diff --git a/.gitea/workflows/post.yml b/.gitea/workflows/post.yml index ac470037..fa9aaeb6 100644 --- a/.gitea/workflows/post.yml +++ b/.gitea/workflows/post.yml @@ -9,8 +9,9 @@ jobs: - run: echo "Start action" - name: Check out repository code uses: actions/checkout@v4 - - run: echo "Installing ruby and jekyll" - - run: apt install ruby-full build-essential zlib1g-dev + - run: echo "Linking Ruby binaries" + - run: export GEM_HOME="bin/gems" + - run: export PATH="bin/gems/bin:$PATH" - run: gem install jekyll bundler - name: List files in the repository run: | diff --git a/bin/bin/ascii85 b/bin/bin/ascii85 new file mode 100755 index 00000000..956dcd41 --- /dev/null +++ b/bin/bin/ascii85 @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'Ascii85' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('Ascii85', 'ascii85', version) +else +gem "Ascii85", version +load Gem.bin_path("Ascii85", "ascii85", version) +end diff --git a/bin/bin/bump b/bin/bin/bump new file mode 100755 index 00000000..699c8b26 --- /dev/null +++ b/bin/bin/bump @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'bump' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('bump', 'bump', version) +else +gem "bump", version +load Gem.bin_path("bump", "bump", version) +end diff --git a/bin/bin/bundle b/bin/bin/bundle new file mode 100755 index 00000000..659f7a77 --- /dev/null +++ b/bin/bin/bundle @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'bundler' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ENV['BUNDLER_VERSION'] = str + + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('bundler', 'bundle', version) +else +gem "bundler", version +load Gem.bin_path("bundler", "bundle", version) +end diff --git a/bin/bin/bundler b/bin/bin/bundler new file mode 100755 index 00000000..65e2b301 --- /dev/null +++ b/bin/bin/bundler @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'bundler' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ENV['BUNDLER_VERSION'] = str + + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('bundler', 'bundler', version) +else +gem "bundler", version +load Gem.bin_path("bundler", "bundler", version) +end diff --git a/bin/bin/coderay b/bin/bin/coderay new file mode 100755 index 00000000..df37887f --- /dev/null +++ b/bin/bin/coderay @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'coderay' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('coderay', 'coderay', version) +else +gem "coderay", version +load Gem.bin_path("coderay", "coderay", version) +end diff --git a/bin/bin/htmlproofer b/bin/bin/htmlproofer new file mode 100755 index 00000000..1055ae8b --- /dev/null +++ b/bin/bin/htmlproofer @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'html-proofer' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('html-proofer', 'htmlproofer', version) +else +gem "html-proofer", version +load Gem.bin_path("html-proofer", "htmlproofer", version) +end diff --git a/bin/bin/jekyll b/bin/bin/jekyll new file mode 100755 index 00000000..73eb8e96 --- /dev/null +++ b/bin/bin/jekyll @@ -0,0 +1,29 @@ +#!/usr/bin/ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'jekyll' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('jekyll', 'jekyll', version) +else +gem "jekyll", version +load Gem.bin_path("jekyll", "jekyll", version) +end diff --git a/bin/bin/just-the-docs b/bin/bin/just-the-docs new file mode 100755 index 00000000..b99d70c4 --- /dev/null +++ b/bin/bin/just-the-docs @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'just-the-docs' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('just-the-docs', 'just-the-docs', version) +else +gem "just-the-docs", version +load Gem.bin_path("just-the-docs", "just-the-docs", version) +end diff --git a/bin/bin/kramdown b/bin/bin/kramdown new file mode 100755 index 00000000..dbc4960e --- /dev/null +++ b/bin/bin/kramdown @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'kramdown' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('kramdown', 'kramdown', version) +else +gem "kramdown", version +load Gem.bin_path("kramdown", "kramdown", version) +end diff --git a/bin/bin/listen b/bin/bin/listen new file mode 100755 index 00000000..c538deca --- /dev/null +++ b/bin/bin/listen @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'listen' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('listen', 'listen', version) +else +gem "listen", version +load Gem.bin_path("listen", "listen", version) +end diff --git a/bin/bin/nokogiri b/bin/bin/nokogiri new file mode 100755 index 00000000..28de80d7 --- /dev/null +++ b/bin/bin/nokogiri @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'nokogiri' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('nokogiri', 'nokogiri', version) +else +gem "nokogiri", version +load Gem.bin_path("nokogiri", "nokogiri", version) +end diff --git a/bin/bin/pdf_callbacks b/bin/bin/pdf_callbacks new file mode 100755 index 00000000..294191f7 --- /dev/null +++ b/bin/bin/pdf_callbacks @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'pdf-reader' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('pdf-reader', 'pdf_callbacks', version) +else +gem "pdf-reader", version +load Gem.bin_path("pdf-reader", "pdf_callbacks", version) +end diff --git a/bin/bin/pdf_object b/bin/bin/pdf_object new file mode 100755 index 00000000..b461c534 --- /dev/null +++ b/bin/bin/pdf_object @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'pdf-reader' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('pdf-reader', 'pdf_object', version) +else +gem "pdf-reader", version +load Gem.bin_path("pdf-reader", "pdf_object", version) +end diff --git a/bin/bin/pdf_text b/bin/bin/pdf_text new file mode 100755 index 00000000..f4067539 --- /dev/null +++ b/bin/bin/pdf_text @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'pdf-reader' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('pdf-reader', 'pdf_text', version) +else +gem "pdf-reader", version +load Gem.bin_path("pdf-reader", "pdf_text", version) +end diff --git a/bin/bin/pry b/bin/bin/pry new file mode 100755 index 00000000..93581fb7 --- /dev/null +++ b/bin/bin/pry @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'pry' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('pry', 'pry', version) +else +gem "pry", version +load Gem.bin_path("pry", "pry", version) +end diff --git a/bin/bin/racc b/bin/bin/racc new file mode 100755 index 00000000..9d74320b --- /dev/null +++ b/bin/bin/racc @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'racc' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('racc', 'racc', version) +else +gem "racc", version +load Gem.bin_path("racc", "racc", version) +end diff --git a/bin/bin/rake b/bin/bin/rake new file mode 100755 index 00000000..6b572b3e --- /dev/null +++ b/bin/bin/rake @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('rake', 'rake', version) +else +gem "rake", version +load Gem.bin_path("rake", "rake", version) +end diff --git a/bin/bin/rougify b/bin/bin/rougify new file mode 100755 index 00000000..a5d14f36 --- /dev/null +++ b/bin/bin/rougify @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'rouge' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('rouge', 'rougify', version) +else +gem "rouge", version +load Gem.bin_path("rouge", "rougify", version) +end diff --git a/bin/bin/safe_yaml b/bin/bin/safe_yaml new file mode 100755 index 00000000..066aeb14 --- /dev/null +++ b/bin/bin/safe_yaml @@ -0,0 +1,29 @@ +#!/usr/bin/ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'safe_yaml' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('safe_yaml', 'safe_yaml', version) +else +gem "safe_yaml", version +load Gem.bin_path("safe_yaml", "safe_yaml", version) +end diff --git a/bin/bin/sass b/bin/bin/sass new file mode 100755 index 00000000..151ac7da --- /dev/null +++ b/bin/bin/sass @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby3.2 +# +# This file was generated by RubyGems. +# +# The application 'sass-embedded' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'rubygems' + +Gem.use_gemdeps + +version = ">= 0.a" + +str = ARGV.first +if str + str = str.b[/\A_(.*)_\z/, 1] + if str and Gem::Version.correct?(str) + version = str + ARGV.shift + end +end + +if Gem.respond_to?(:activate_bin_path) +load Gem.activate_bin_path('sass-embedded', 'sass', version) +else +gem "sass-embedded", version +load Gem.bin_path("sass-embedded", "sass", version) +end diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri new file mode 100644 index 00000000..ce15eb4b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBadInput/cdesc-PunycodeBadInput.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBigOutput/cdesc-PunycodeBigOutput.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBigOutput/cdesc-PunycodeBigOutput.ri new file mode 100644 index 00000000..5bcc1658 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeBigOutput/cdesc-PunycodeBigOutput.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri new file mode 100644 index 00000000..84bf7c0e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/PunycodeOverflow/cdesc-PunycodeOverflow.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/cdesc-IDNA.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/cdesc-IDNA.ri new file mode 100644 index 00000000..41d7901a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/cdesc-IDNA.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri new file mode 100644 index 00000000..5ec77e23 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/lookup_unicode_lowercase-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_adapt-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_adapt-c.ri new file mode 100644 index 00000000..d883f395 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_adapt-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_basic%3f-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_basic%3f-c.ri new file mode 100644 index 00000000..1d4ec293 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_basic%3f-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode-c.ri new file mode 100644 index 00000000..a4d9e8b7 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode_digit-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode_digit-c.ri new file mode 100644 index 00000000..a1f67555 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_decode_digit-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri new file mode 100644 index 00000000..d24c8f5b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_delimiter%3f-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode-c.ri new file mode 100644 index 00000000..faeae6bb Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode_digit-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode_digit-c.ri new file mode 100644 index 00000000..d72d6298 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/punycode_encode_digit-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_ascii-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_ascii-c.ri new file mode 100644 index 00000000..04c08060 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_ascii-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_unicode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_unicode-c.ri new file mode 100644 index 00000000..cf8bd9ad Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/to_unicode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_downcase-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_downcase-c.ri new file mode 100644 index 00000000..fc3baacf Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_downcase-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_normalize_kc-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_normalize_kc-c.ri new file mode 100644 index 00000000..7ca0bf8e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/IDNA/unicode_normalize_kc-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/%3d%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/%3d%3d-i.ri new file mode 100644 index 00000000..6d76c3fe Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/%3d%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri new file mode 100644 index 00000000..bf9a8d9a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateOperatorError/cdesc-InvalidTemplateOperatorError.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri new file mode 100644 index 00000000..05b32daf Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/InvalidTemplateValueError/cdesc-InvalidTemplateValueError.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/%5b%5d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/%5b%5d-i.ri new file mode 100644 index 00000000..33093695 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/%5b%5d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/captures-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/captures-i.ri new file mode 100644 index 00000000..fe88ff96 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/captures-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/cdesc-MatchData.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/cdesc-MatchData.ri new file mode 100644 index 00000000..48ea6b92 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/cdesc-MatchData.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/inspect-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/inspect-i.ri new file mode 100644 index 00000000..cd2b3c6c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/inspect-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/keys-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/keys-i.ri new file mode 100644 index 00000000..71f43c23 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/keys-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/mapping-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/mapping-i.ri new file mode 100644 index 00000000..7d5dee07 --- /dev/null +++ b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/mapping-i.ri @@ -0,0 +1,5 @@ +U:RDoc::Attr[iI" mapping:ETI"-Addressable::Template::MatchData#mapping;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Hash];To:RDoc::Markup::Verbatim; [ I"/The mapping that resulted from the match. +;TI"@Note that this mapping does not include keys or values for +;TI"@variables that appear in the Template, but are not present +;TI"in the URI.;T: @format0: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Addressable::Template::MatchData;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/names-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/names-i.ri new file mode 100644 index 00000000..a62aa28c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/names-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/new-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/new-c.ri new file mode 100644 index 00000000..07635634 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/new-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/post_match-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/post_match-i.ri new file mode 100644 index 00000000..acf076fa Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/post_match-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/pre_match-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/pre_match-i.ri new file mode 100644 index 00000000..ef5aa29e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/pre_match-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/string-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/string-i.ri new file mode 100644 index 00000000..0452274c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/string-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/template-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/template-i.ri new file mode 100644 index 00000000..3936eb5a --- /dev/null +++ b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/template-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" template:ETI".Addressable::Template::MatchData#template;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"$@return [Addressable::Template];To:RDoc::Markup::Verbatim; [I"%The Template used for the match.;T: @format0: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Addressable::Template::MatchData;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_a-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_a-i.ri new file mode 100644 index 00000000..560e4d72 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_a-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_s-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_s-i.ri new file mode 100644 index 00000000..11577c2d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/to_s-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/uri-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/uri-i.ri new file mode 100644 index 00000000..aa228e56 --- /dev/null +++ b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/uri-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"uri:ETI")Addressable::Template::MatchData#uri;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Addressable::URI];To:RDoc::Markup::Verbatim; [I"3The URI that the Template was matched against.;T: @format0: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Addressable::Template::MatchData;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values-i.ri new file mode 100644 index 00000000..57443041 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values_at-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values_at-i.ri new file mode 100644 index 00000000..c8183316 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/values_at-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/variables-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/variables-i.ri new file mode 100644 index 00000000..34e09e89 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/MatchData/variables-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/TemplateOperatorAbortedError/cdesc-TemplateOperatorAbortedError.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/TemplateOperatorAbortedError/cdesc-TemplateOperatorAbortedError.ri new file mode 100644 index 00000000..dae2b729 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/TemplateOperatorAbortedError/cdesc-TemplateOperatorAbortedError.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/cdesc-Template.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/cdesc-Template.ri new file mode 100644 index 00000000..f86346f3 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/cdesc-Template.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/eql%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/eql%3f-i.ri new file mode 100644 index 00000000..9c93795e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/eql%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/expand-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/expand-i.ri new file mode 100644 index 00000000..a8863b51 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/expand-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/extract-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/extract-i.ri new file mode 100644 index 00000000..094710a0 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/extract-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/freeze-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/freeze-i.ri new file mode 100644 index 00000000..b22cc7f2 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/freeze-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/inspect-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/inspect-i.ri new file mode 100644 index 00000000..8c599ddd Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/inspect-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/join_values-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/join_values-i.ri new file mode 100644 index 00000000..0a762d19 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/join_values-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/keys-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/keys-i.ri new file mode 100644 index 00000000..9e9098b1 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/keys-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/match-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/match-i.ri new file mode 100644 index 00000000..a394fed4 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/match-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/named_captures-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/named_captures-i.ri new file mode 100644 index 00000000..cb2d4591 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/named_captures-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/names-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/names-i.ri new file mode 100644 index 00000000..5421b9e4 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/names-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/new-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/new-c.ri new file mode 100644 index 00000000..4021cf5e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/new-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_keys-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_keys-i.ri new file mode 100644 index 00000000..b2ab02bc Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_keys-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_value-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_value-i.ri new file mode 100644 index 00000000..193aa6e4 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/normalize_value-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/ordered_variable_defaults-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/ordered_variable_defaults-i.ri new file mode 100644 index 00000000..58bcbe1e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/ordered_variable_defaults-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_new_template_pattern-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_new_template_pattern-i.ri new file mode 100644 index 00000000..a74a9523 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_new_template_pattern-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_template_pattern-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_template_pattern-i.ri new file mode 100644 index 00000000..3f7a6490 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/parse_template_pattern-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/partial_expand-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/partial_expand-i.ri new file mode 100644 index 00000000..409c54d6 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/partial_expand-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/pattern-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/pattern-i.ri new file mode 100644 index 00000000..6f7c805a --- /dev/null +++ b/bin/doc/addressable-2.9.0/ri/Addressable/Template/pattern-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" pattern:ETI""Addressable::Template#pattern;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"4@return [String] The Template object's pattern.;T: +@fileI" lib/addressable/template.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Addressable::Template;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/source-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/source-i.ri new file mode 100644 index 00000000..54bd57fa Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/source-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/to_regexp-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/to_regexp-i.ri new file mode 100644 index 00000000..b3ac41ec Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/to_regexp-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_capture-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_capture-i.ri new file mode 100644 index 00000000..02c586b4 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_capture-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_partial_capture-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_partial_capture-i.ri new file mode 100644 index 00000000..f196ca84 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/transform_partial_capture-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/variable_defaults-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/variable_defaults-i.ri new file mode 100644 index 00000000..7c103218 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/variable_defaults-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/Template/variables-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/Template/variables-i.ri new file mode 100644 index 00000000..9e2dd024 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/Template/variables-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/%2b-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%2b-i.ri new file mode 100644 index 00000000..6adfd8f9 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%2b-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d%3d-i.ri new file mode 100644 index 00000000..45bf336b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d-i.ri new file mode 100644 index 00000000..425ca859 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/%3d%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri new file mode 100644 index 00000000..63890e57 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClasses/cdesc-CharacterClasses.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClassesRegexps/cdesc-CharacterClassesRegexps.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClassesRegexps/cdesc-CharacterClassesRegexps.ri new file mode 100644 index 00000000..319018ac Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/CharacterClassesRegexps/cdesc-CharacterClassesRegexps.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri new file mode 100644 index 00000000..a7c27a1b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/InvalidURIError/cdesc-InvalidURIError.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/NormalizeCharacterClasses/cdesc-NormalizeCharacterClasses.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/NormalizeCharacterClasses/cdesc-NormalizeCharacterClasses.ri new file mode 100644 index 00000000..a8181e5d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/NormalizeCharacterClasses/cdesc-NormalizeCharacterClasses.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/absolute%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/absolute%3f-i.ri new file mode 100644 index 00000000..4431a395 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/absolute%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority%3d-i.ri new file mode 100644 index 00000000..f8efd58e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority-i.ri new file mode 100644 index 00000000..9c1fb7ab Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/authority-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/basename-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/basename-i.ri new file mode 100644 index 00000000..4e9cfb9b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/basename-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/cdesc-URI.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/cdesc-URI.ri new file mode 100644 index 00000000..ba82118a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/cdesc-URI.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/convert_path-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/convert_path-c.ri new file mode 100644 index 00000000..7b50fe1f Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/convert_path-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/default_port-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/default_port-i.ri new file mode 100644 index 00000000..48126433 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/default_port-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/defer_validation-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/defer_validation-i.ri new file mode 100644 index 00000000..fef4c30e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/defer_validation-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/display_uri-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/display_uri-i.ri new file mode 100644 index 00000000..66f3bc7b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/display_uri-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/domain-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/domain-i.ri new file mode 100644 index 00000000..e4f4a20e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/domain-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/dup-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/dup-i.ri new file mode 100644 index 00000000..50404d67 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/dup-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/empty%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/empty%3f-i.ri new file mode 100644 index 00000000..db5f5de5 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/empty%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode-c.ri new file mode 100644 index 00000000..0840c70c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_component-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_component-c.ri new file mode 100644 index 00000000..8b0d892d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_component-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_with-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_with-i.ri new file mode 100644 index 00000000..fd837a5a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/encode_with-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/eql%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/eql%3f-i.ri new file mode 100644 index 00000000..c18e31c9 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/eql%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape-c.ri new file mode 100644 index 00000000..a600231c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape_component-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape_component-c.ri new file mode 100644 index 00000000..e3756c3c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/escape_component-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/extname-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/extname-i.ri new file mode 100644 index 00000000..4d3673d9 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/extname-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/force_utf8_encoding_if_needed-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/force_utf8_encoding_if_needed-i.ri new file mode 100644 index 00000000..d31c636c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/force_utf8_encoding_if_needed-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_encode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_encode-c.ri new file mode 100644 index 00000000..a1d8ada1 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_encode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_unencode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_unencode-c.ri new file mode 100644 index 00000000..e695c920 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/form_unencode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment%3d-i.ri new file mode 100644 index 00000000..cd6c394e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment-i.ri new file mode 100644 index 00000000..aecc6220 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/fragment-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/freeze-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/freeze-i.ri new file mode 100644 index 00000000..1f08748e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/freeze-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/hash-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hash-i.ri new file mode 100644 index 00000000..8e424667 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hash-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/heuristic_parse-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/heuristic_parse-c.ri new file mode 100644 index 00000000..d21ca6c0 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/heuristic_parse-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/host%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/host%3d-i.ri new file mode 100644 index 00000000..ab2bbac2 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/host%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/host-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/host-i.ri new file mode 100644 index 00000000..96403695 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/host-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname%3d-i.ri new file mode 100644 index 00000000..c9f0fcbb Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname-i.ri new file mode 100644 index 00000000..b55ee28d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/hostname-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/inferred_port-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/inferred_port-i.ri new file mode 100644 index 00000000..71a4b20d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/inferred_port-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/init_with-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/init_with-i.ri new file mode 100644 index 00000000..816eae66 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/init_with-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/inspect-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/inspect-i.ri new file mode 100644 index 00000000..2b179850 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/inspect-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based%3f-i.ri new file mode 100644 index 00000000..7e202211 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based_schemes-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based_schemes-c.ri new file mode 100644 index 00000000..dfa2adf6 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/ip_based_schemes-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/join%21-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join%21-i.ri new file mode 100644 index 00000000..be6c2623 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join%21-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-c.ri new file mode 100644 index 00000000..e350b2de Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-i.ri new file mode 100644 index 00000000..5bc1d4b0 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/join-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge%21-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge%21-i.ri new file mode 100644 index 00000000..4ba6c413 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge%21-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge-i.ri new file mode 100644 index 00000000..275a4049 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/merge-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/new-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/new-c.ri new file mode 100644 index 00000000..a921e797 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/new-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize%21-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize%21-i.ri new file mode 100644 index 00000000..77f80b41 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize%21-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize-i.ri new file mode 100644 index 00000000..70e72b6c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_component-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_component-c.ri new file mode 100644 index 00000000..20b6ece8 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_component-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_path-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_path-c.ri new file mode 100644 index 00000000..f08ac895 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalize_path-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_authority-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_authority-i.ri new file mode 100644 index 00000000..3ca947bd Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_authority-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_encode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_encode-c.ri new file mode 100644 index 00000000..bd19bd65 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_encode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_fragment-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_fragment-i.ri new file mode 100644 index 00000000..45e00e4a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_fragment-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_host-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_host-i.ri new file mode 100644 index 00000000..fca53907 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_host-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_password-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_password-i.ri new file mode 100644 index 00000000..17eb6977 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_password-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_path-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_path-i.ri new file mode 100644 index 00000000..89c9897d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_path-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_port-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_port-i.ri new file mode 100644 index 00000000..7f1e9f1e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_port-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_query-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_query-i.ri new file mode 100644 index 00000000..05230edb Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_query-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_scheme-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_scheme-i.ri new file mode 100644 index 00000000..a31fb03d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_scheme-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_site-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_site-i.ri new file mode 100644 index 00000000..51840472 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_site-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_user-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_user-i.ri new file mode 100644 index 00000000..13895239 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_user-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_userinfo-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_userinfo-i.ri new file mode 100644 index 00000000..eeba8367 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/normalized_userinfo-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit%21-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit%21-i.ri new file mode 100644 index 00000000..5213c177 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit%21-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit-i.ri new file mode 100644 index 00000000..13e66e77 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/omit-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin%3d-i.ri new file mode 100644 index 00000000..087ca14e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin-i.ri new file mode 100644 index 00000000..96e824eb Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/origin-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/parse-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/parse-c.ri new file mode 100644 index 00000000..54c239be Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/parse-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/password%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/password%3d-i.ri new file mode 100644 index 00000000..63d35394 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/password%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/password-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/password-i.ri new file mode 100644 index 00000000..4e5e9bd7 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/password-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/path%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/path%3d-i.ri new file mode 100644 index 00000000..ef698b3e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/path%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/path-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/path-i.ri new file mode 100644 index 00000000..cdab1319 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/path-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/port%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port%3d-i.ri new file mode 100644 index 00000000..30c96c05 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/port-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port-i.ri new file mode 100644 index 00000000..17dec26d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/port_mapping-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port_mapping-c.ri new file mode 100644 index 00000000..b085af85 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/port_mapping-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/query%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query%3d-i.ri new file mode 100644 index 00000000..f6dbec93 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/query-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query-i.ri new file mode 100644 index 00000000..ea2f8a1b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values%3d-i.ri new file mode 100644 index 00000000..597d2ab5 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values-i.ri new file mode 100644 index 00000000..a5947979 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/query_values-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/relative%3f-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/relative%3f-i.ri new file mode 100644 index 00000000..ac9255db Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/relative%3f-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/remove_composite_values-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/remove_composite_values-i.ri new file mode 100644 index 00000000..553bac07 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/remove_composite_values-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/replace_self-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/replace_self-i.ri new file mode 100644 index 00000000..cb65599f Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/replace_self-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri%3d-i.ri new file mode 100644 index 00000000..04551d0c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri-i.ri new file mode 100644 index 00000000..7b185826 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/request_uri-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/reset_ivs-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/reset_ivs-i.ri new file mode 100644 index 00000000..a239707e Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/reset_ivs-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_from-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_from-i.ri new file mode 100644 index 00000000..da47fc3d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_from-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_to-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_to-i.ri new file mode 100644 index 00000000..8accfd09 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/route_to-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme%3d-i.ri new file mode 100644 index 00000000..d6209821 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme-i.ri new file mode 100644 index 00000000..011b88c7 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/scheme-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/site%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/site%3d-i.ri new file mode 100644 index 00000000..4b10dc73 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/site%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/site-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/site-i.ri new file mode 100644 index 00000000..04660e10 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/site-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/split_path-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/split_path-i.ri new file mode 100644 index 00000000..6e0e2dab Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/split_path-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld%3d-i.ri new file mode 100644 index 00000000..c7c26d37 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld-i.ri new file mode 100644 index 00000000..4cd07bf0 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/tld-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_hash-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_hash-i.ri new file mode 100644 index 00000000..903b21c7 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_hash-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_s-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_s-i.ri new file mode 100644 index 00000000..7bf66a91 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_s-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_str-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_str-i.ri new file mode 100644 index 00000000..7fda0c2a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/to_str-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode-c.ri new file mode 100644 index 00000000..610bd2ac Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode_component-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode_component-c.ri new file mode 100644 index 00000000..2ab6648d Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unencode_component-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape-c.ri new file mode 100644 index 00000000..3752d256 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape_component-c.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape_component-c.ri new file mode 100644 index 00000000..1ec681ba Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/unescape_component-c.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/user%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/user%3d-i.ri new file mode 100644 index 00000000..e7d70ae7 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/user%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/user-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/user-i.ri new file mode 100644 index 00000000..798fa33a Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/user-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo%3d-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo%3d-i.ri new file mode 100644 index 00000000..ed617ceb Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo%3d-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo-i.ri new file mode 100644 index 00000000..b759b3f6 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/userinfo-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/URI/validate-i.ri b/bin/doc/addressable-2.9.0/ri/Addressable/URI/validate-i.ri new file mode 100644 index 00000000..288b1626 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/URI/validate-i.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/VERSION/cdesc-VERSION.ri b/bin/doc/addressable-2.9.0/ri/Addressable/VERSION/cdesc-VERSION.ri new file mode 100644 index 00000000..8ed2602c Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/VERSION/cdesc-VERSION.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/Addressable/cdesc-Addressable.ri b/bin/doc/addressable-2.9.0/ri/Addressable/cdesc-Addressable.ri new file mode 100644 index 00000000..199b3746 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/Addressable/cdesc-Addressable.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/cache.ri b/bin/doc/addressable-2.9.0/ri/cache.ri new file mode 100644 index 00000000..3dcd2d5b Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/cache.ri differ diff --git a/bin/doc/addressable-2.9.0/ri/page-README_md.ri b/bin/doc/addressable-2.9.0/ri/page-README_md.ri new file mode 100644 index 00000000..a45887c1 Binary files /dev/null and b/bin/doc/addressable-2.9.0/ri/page-README_md.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/cdesc-Base64.ri b/bin/doc/base64-0.3.0/ri/Base64/cdesc-Base64.ri new file mode 100644 index 00000000..c60080ef Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/cdesc-Base64.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/decode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/decode64-i.ri new file mode 100644 index 00000000..2ec92bec Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/decode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/encode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/encode64-i.ri new file mode 100644 index 00000000..6dd84457 Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/encode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/strict_decode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/strict_decode64-i.ri new file mode 100644 index 00000000..9b95405d Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/strict_decode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/strict_encode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/strict_encode64-i.ri new file mode 100644 index 00000000..a06ea7f3 Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/strict_encode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/urlsafe_decode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/urlsafe_decode64-i.ri new file mode 100644 index 00000000..b5a6628e Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/urlsafe_decode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/Base64/urlsafe_encode64-i.ri b/bin/doc/base64-0.3.0/ri/Base64/urlsafe_encode64-i.ri new file mode 100644 index 00000000..a86e9211 Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/Base64/urlsafe_encode64-i.ri differ diff --git a/bin/doc/base64-0.3.0/ri/cache.ri b/bin/doc/base64-0.3.0/ri/cache.ri new file mode 100644 index 00000000..6bfa8fcc Binary files /dev/null and b/bin/doc/base64-0.3.0/ri/cache.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/app_cache-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/app_cache-c.ri new file mode 100644 index 00000000..85fea148 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/app_cache-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/app_config_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/app_config_path-c.ri new file mode 100644 index 00000000..c419e482 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/app_config_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/auto_install-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/auto_install-c.ri new file mode 100644 index 00000000..401f4a12 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/auto_install-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/auto_switch-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/auto_switch-c.ri new file mode 100644 index 00000000..c6ef2d07 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/auto_switch-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/bin_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/bin_path-c.ri new file mode 100644 index 00000000..72c42f3c Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/bin_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/bundle_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/bundle_path-c.ri new file mode 100644 index 00000000..8f91dcf0 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/bundle_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/cdesc-Bundler.ri b/bin/doc/bundler-4.0.21/ri/Bundler/cdesc-Bundler.ri new file mode 100644 index 00000000..555b51c8 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/cdesc-Bundler.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/clean_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/clean_env-c.ri new file mode 100644 index 00000000..a896bf79 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/clean_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/clean_exec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/clean_exec-c.ri new file mode 100644 index 00000000..c31c8705 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/clean_exec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/clean_system-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/clean_system-c.ri new file mode 100644 index 00000000..bd018f8d Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/clean_system-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/clear_gemspec_cache-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/clear_gemspec_cache-c.ri new file mode 100644 index 00000000..dccd0f9f Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/clear_gemspec_cache-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configure-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configure-c.ri new file mode 100644 index 00000000..18df28ae Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configure-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configure_custom_gemfile-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configure_custom_gemfile-c.ri new file mode 100644 index 00000000..976e3570 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configure_custom_gemfile-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home-c.ri new file mode 100644 index 00000000..bf1322d2 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home_and_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home_and_path-c.ri new file mode 100644 index 00000000..10689cd0 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_home_and_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_path-c.ri new file mode 100644 index 00000000..5b419821 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configure_gem_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/configured_bundle_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/configured_bundle_path-c.ri new file mode 100644 index 00000000..4e54796a Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/configured_bundle_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/create_bundle_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/create_bundle_path-c.ri new file mode 100644 index 00000000..0dcc077f Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/create_bundle_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/default_bundle_dir-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/default_bundle_dir-c.ri new file mode 100644 index 00000000..6ec79397 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/default_bundle_dir-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/default_gemfile-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/default_gemfile-c.ri new file mode 100644 index 00000000..a3be971b Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/default_gemfile-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/default_lockfile-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/default_lockfile-c.ri new file mode 100644 index 00000000..0e8c6110 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/default_lockfile-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/definition-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/definition-c.ri new file mode 100644 index 00000000..3a2a36d1 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/definition-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/environment-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/environment-c.ri new file mode 100644 index 00000000..05bc2693 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/environment-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/eval_gemspec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/eval_gemspec-c.ri new file mode 100644 index 00000000..441c564a Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/eval_gemspec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/eval_yaml_gemspec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/eval_yaml_gemspec-c.ri new file mode 100644 index 00000000..3537d6db Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/eval_yaml_gemspec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/feature_flag-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/feature_flag-c.ri new file mode 100644 index 00000000..fafeea1f Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/feature_flag-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/find_executable-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/find_executable-c.ri new file mode 100644 index 00000000..5f2b7bce Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/find_executable-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/frozen_bundle%3f-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/frozen_bundle%3f-c.ri new file mode 100644 index 00000000..01f8b0cc Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/frozen_bundle%3f-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/generic_local_platform-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/generic_local_platform-c.ri new file mode 100644 index 00000000..0215802b Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/generic_local_platform-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/git_present%3f-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/git_present%3f-c.ri new file mode 100644 index 00000000..4fd22789 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/git_present%3f-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/home-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/home-c.ri new file mode 100644 index 00000000..bb036b9e Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/home-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/install_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/install_path-c.ri new file mode 100644 index 00000000..f66371f6 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/install_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/load-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/load-c.ri new file mode 100644 index 00000000..db3dc8c2 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/load-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec-c.ri new file mode 100644 index 00000000..9eee8829 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec_uncached-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec_uncached-c.ri new file mode 100644 index 00000000..455c81bf Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/load_gemspec_uncached-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/load_marshal-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/load_marshal-c.ri new file mode 100644 index 00000000..2c97f219 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/load_marshal-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/local_platform-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/local_platform-c.ri new file mode 100644 index 00000000..6cfa8d14 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/local_platform-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/locked_gems-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/locked_gems-c.ri new file mode 100644 index 00000000..7d42c28c Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/locked_gems-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/mkdir_p-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/mkdir_p-c.ri new file mode 100644 index 00000000..1179be05 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/mkdir_p-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/original_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/original_env-c.ri new file mode 100644 index 00000000..f400c335 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/original_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/original_exec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/original_exec-c.ri new file mode 100644 index 00000000..c9c6badb Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/original_exec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/original_system-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/original_system-c.ri new file mode 100644 index 00000000..8c54ccc2 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/original_system-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/preferred_gemfile_name-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/preferred_gemfile_name-c.ri new file mode 100644 index 00000000..140acc4c Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/preferred_gemfile_name-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/read_file-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/read_file-c.ri new file mode 100644 index 00000000..462274c2 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/read_file-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/require-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/require-c.ri new file mode 100644 index 00000000..3b6e89eb Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/require-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/reset%21-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/reset%21-c.ri new file mode 100644 index 00000000..40713b3b Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/reset%21-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/reset_paths%21-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/reset_paths%21-c.ri new file mode 100644 index 00000000..22818e0c Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/reset_paths%21-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/reset_rubygems%21-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/reset_rubygems%21-c.ri new file mode 100644 index 00000000..f1962614 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/reset_rubygems%21-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/reset_settings_and_root%21-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/reset_settings_and_root%21-c.ri new file mode 100644 index 00000000..2aa7e96c Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/reset_settings_and_root%21-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/rm_rf-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/rm_rf-c.ri new file mode 100644 index 00000000..dc32ca99 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/rm_rf-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/root-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/root-c.ri new file mode 100644 index 00000000..428723a8 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/root-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/ruby_scope-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/ruby_scope-c.ri new file mode 100644 index 00000000..4a1614ea Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/ruby_scope-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/safe_load_marshal-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/safe_load_marshal-c.ri new file mode 100644 index 00000000..7e6c88df Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/safe_load_marshal-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/self_manager-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/self_manager-c.ri new file mode 100644 index 00000000..2048399e Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/self_manager-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/settings-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/settings-c.ri new file mode 100644 index 00000000..fb85e15e Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/settings-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/setup-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/setup-c.ri new file mode 100644 index 00000000..40226bbc Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/setup-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/specs_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/specs_path-c.ri new file mode 100644 index 00000000..a9d1bb5f Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/specs_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/system_bindir-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/system_bindir-c.ri new file mode 100644 index 00000000..8d8d13c5 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/system_bindir-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/tmp-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/tmp-c.ri new file mode 100644 index 00000000..74670fb6 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/tmp-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/tmp_home_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/tmp_home_path-c.ri new file mode 100644 index 00000000..c2e452c0 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/tmp_home_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/ui%3d-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/ui%3d-c.ri new file mode 100644 index 00000000..41a22bcb Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/ui%3d-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/ui-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/ui-c.ri new file mode 100644 index 00000000..6839574d Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/ui-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env%21-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env%21-c.ri new file mode 100644 index 00000000..263336f7 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env%21-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env-c.ri new file mode 100644 index 00000000..b5969a44 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/unbundle_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_env-c.ri new file mode 100644 index 00000000..54584c87 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_exec-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_exec-c.ri new file mode 100644 index 00000000..9fbf597e Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_exec-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_system-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_system-c.ri new file mode 100644 index 00000000..f037c95a Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/unbundled_system-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/use_system_gems%3f-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/use_system_gems%3f-c.ri new file mode 100644 index 00000000..c9ea5191 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/use_system_gems%3f-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/user_bundle_path-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/user_bundle_path-c.ri new file mode 100644 index 00000000..f1247af0 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/user_bundle_path-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/user_cache-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/user_cache-c.ri new file mode 100644 index 00000000..5d48fefa Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/user_cache-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/user_home-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/user_home-c.ri new file mode 100644 index 00000000..02ea17ec Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/user_home-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/which-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/which-c.ri new file mode 100644 index 00000000..9e26ba90 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/which-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/with_clean_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/with_clean_env-c.ri new file mode 100644 index 00000000..80a70b75 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/with_clean_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/with_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/with_env-c.ri new file mode 100644 index 00000000..93b406ed Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/with_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/with_original_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/with_original_env-c.ri new file mode 100644 index 00000000..8e19f1be Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/with_original_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/Bundler/with_unbundled_env-c.ri b/bin/doc/bundler-4.0.21/ri/Bundler/with_unbundled_env-c.ri new file mode 100644 index 00000000..50b6a2dd Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/Bundler/with_unbundled_env-c.ri differ diff --git a/bin/doc/bundler-4.0.21/ri/cache.ri b/bin/doc/bundler-4.0.21/ri/cache.ri new file mode 100644 index 00000000..5d26ede9 Binary files /dev/null and b/bin/doc/bundler-4.0.21/ri/cache.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/ansi_jump-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/ansi_jump-i.ri new file mode 100644 index 00000000..5b8082db Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/ansi_jump-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/cdesc-Colorator.ri b/bin/doc/colorator-1.1.0/ri/Colorator/cdesc-Colorator.ri new file mode 100644 index 00000000..094935d5 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/cdesc-Colorator.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/clear_line-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/clear_line-i.ri new file mode 100644 index 00000000..983a7593 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/clear_line-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/clear_screen-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/clear_screen-i.ri new file mode 100644 index 00000000..2f40d37e Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/clear_screen-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/colorize-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/colorize-i.ri new file mode 100644 index 00000000..f18bb66c Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/colorize-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/has_ansi%3f-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/has_ansi%3f-i.ri new file mode 100644 index 00000000..dcff50d7 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/has_ansi%3f-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/reset_ansi-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/reset_ansi-i.ri new file mode 100644 index 00000000..231b0b66 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/reset_ansi-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/Colorator/strip_ansi-i.ri b/bin/doc/colorator-1.1.0/ri/Colorator/strip_ansi-i.ri new file mode 100644 index 00000000..b00505fd Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/Colorator/strip_ansi-i.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/String/cdesc-String.ri b/bin/doc/colorator-1.1.0/ri/String/cdesc-String.ri new file mode 100644 index 00000000..17a498b8 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/String/cdesc-String.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/cache.ri b/bin/doc/colorator-1.1.0/ri/cache.ri new file mode 100644 index 00000000..ba55cb17 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/cache.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/page-LICENSE.ri b/bin/doc/colorator-1.1.0/ri/page-LICENSE.ri new file mode 100644 index 00000000..960bc5b5 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/page-LICENSE.ri differ diff --git a/bin/doc/colorator-1.1.0/ri/page-README_markdown.ri b/bin/doc/colorator-1.1.0/ri/page-README_markdown.ri new file mode 100644 index 00000000..cacfc8b0 Binary files /dev/null and b/bin/doc/colorator-1.1.0/ri/page-README_markdown.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Array/cdesc-Array.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Array/cdesc-Array.ri new file mode 100644 index 00000000..fa5b83e5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Array/cdesc-Array.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/cdesc-AtomicReference.ri b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/cdesc-AtomicReference.ri new file mode 100644 index 00000000..0ef4f834 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/cdesc-AtomicReference.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/inspect-i.ri new file mode 100644 index 00000000..cf103fa3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/to_s-i.ri new file mode 100644 index 00000000..4261ea43 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/AtomicReference/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/cdesc-AbstractExchanger.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/cdesc-AbstractExchanger.ri new file mode 100644 index 00000000..03cdde52 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/cdesc-AbstractExchanger.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/do_exchange-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/do_exchange-i.ri new file mode 100644 index 00000000..42bf4c3f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/do_exchange-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange%21-i.ri new file mode 100644 index 00000000..d41ec2c1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange-i.ri new file mode 100644 index 00000000..0375e81e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/exchange-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/new-c.ri new file mode 100644 index 00000000..57d7fb1a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/try_exchange-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/try_exchange-i.ri new file mode 100644 index 00000000..c29b971d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExchanger/try_exchange-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3d-i.ri new file mode 100644 index 00000000..d92f6b4e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3f-i.ri new file mode 100644 index 00000000..7cfed30c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/auto_terminate%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/cdesc-AbstractExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/cdesc-AbstractExecutorService.ri new file mode 100644 index 00000000..265c744f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/cdesc-AbstractExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_action-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_action-i.ri new file mode 100644 index 00000000..f81825de Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_action-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_policy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_policy-i.ri new file mode 100644 index 00000000..43cd7f07 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/fallback_policy-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"fallback_policy:ETI"8Concurrent::AbstractExecutorService#fallback_policy;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"9@!macro executor_service_attr_reader_fallback_policy;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb;T:0@omit_headings_from_table_of_contents_below0F@I"(Concurrent::AbstractExecutorService;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/kill-i.ri new file mode 100644 index 00000000..9fa8dd39 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/name-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/name-i.ri new file mode 100644 index 00000000..a449bf7d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/name-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/new-c.ri new file mode 100644 index 00000000..449c8417 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_auto_terminate%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_auto_terminate%3f-i.ri new file mode 100644 index 00000000..cffb38d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_auto_terminate%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_execute-i.ri new file mode 100644 index 00000000..09b8f646 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_kill_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_kill_execution-i.ri new file mode 100644 index 00000000..150d204e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_kill_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_shutdown_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_shutdown_execution-i.ri new file mode 100644 index 00000000..9ffb8894 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/ns_shutdown_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/running%3f-i.ri new file mode 100644 index 00000000..7fd95c7a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown%3f-i.ri new file mode 100644 index 00000000..a5432471 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown-i.ri new file mode 100644 index 00000000..b34778cc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shutdown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shuttingdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shuttingdown%3f-i.ri new file mode 100644 index 00000000..b618c4fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/shuttingdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/to_s-i.ri new file mode 100644 index 00000000..b5a1a984 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/wait_for_termination-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/wait_for_termination-i.ri new file mode 100644 index 00000000..866cda6e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractExecutorService/wait_for_termination-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/cdesc-AbstractLocals.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/cdesc-AbstractLocals.ri new file mode 100644 index 00000000..dc7fe170 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/cdesc-AbstractLocals.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/fetch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/fetch-i.ri new file mode 100644 index 00000000..15cea844 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/fetch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/free_index-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/free_index-i.ri new file mode 100644 index 00000000..54669ab3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/free_index-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/local_finalizer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/local_finalizer-i.ri new file mode 100644 index 00000000..7c4ebbd2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/local_finalizer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals%21-i.ri new file mode 100644 index 00000000..c194e78b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals-i.ri new file mode 100644 index 00000000..53399c2a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/locals-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/new-c.ri new file mode 100644 index 00000000..a800a3ae Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/next_index-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/next_index-i.ri new file mode 100644 index 00000000..a8c5c562 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/next_index-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/set-i.ri new file mode 100644 index 00000000..0599c4fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/synchronize-i.ri new file mode 100644 index 00000000..9b2ae899 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/thread_fiber_finalizer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/thread_fiber_finalizer-i.ri new file mode 100644 index 00000000..7eef7397 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/thread_fiber_finalizer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/weak_synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/weak_synchronize-i.ri new file mode 100644 index 00000000..080fc742 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AbstractLocals/weak_synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/%3c%3c-i.ri new file mode 100644 index 00000000..e85b61a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/cdesc-Error.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/cdesc-Error.ri new file mode 100644 index 00000000..d4446e73 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/cdesc-Error.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/new-c.ri new file mode 100644 index 00000000..b1028c69 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/Error/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/cdesc-ValidationError.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/cdesc-ValidationError.ri new file mode 100644 index 00000000..dfef1a8f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/cdesc-ValidationError.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/new-c.ri new file mode 100644 index 00000000..80e87151 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ValidationError/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-c.ri new file mode 100644 index 00000000..625ee392 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-i.ri new file mode 100644 index 00000000..207d3ceb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-c.ri new file mode 100644 index 00000000..f1e5a0b5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-i.ri new file mode 100644 index 00000000..0173a2e7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-c.ri new file mode 100644 index 00000000..58fe7935 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-i.ri new file mode 100644 index 00000000..a01b928d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/await_for-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/cdesc-Agent.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/cdesc-Agent.ri new file mode 100644 index 00000000..e717e4e3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/cdesc-Agent.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/deref-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/deref-i.ri new file mode 100644 index 00000000..d412005b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/deref-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_action_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_action_job-i.ri new file mode 100644 index 00000000..f0ebaade Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_action_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_await_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_await_job-i.ri new file mode 100644 index 00000000..d2395a33 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/enqueue_await_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error-i.ri new file mode 100644 index 00000000..7b028abd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error_mode-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error_mode-i.ri new file mode 100644 index 00000000..dcd5e149 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/error_mode-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"error_mode:ETI"!Concurrent::Agent#error_mode;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"NThe error mode this Agent is operating in. See {#initialize} for details.;T: +@fileI",lib/concurrent-ruby/concurrent/agent.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Agent;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/execute_next_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/execute_next_job-i.ri new file mode 100644 index 00000000..b4714137 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/execute_next_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/failed%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/failed%3f-i.ri new file mode 100644 index 00000000..3b8cb78c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/failed%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/handle_error-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/handle_error-i.ri new file mode 100644 index 00000000..33d13005 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/handle_error-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/new-c.ri new file mode 100644 index 00000000..d2bc7553 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_enqueue_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_enqueue_job-i.ri new file mode 100644 index 00000000..36b70585 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_enqueue_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_find_last_job_for_thread-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_find_last_job_for_thread-i.ri new file mode 100644 index 00000000..9c013f3a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_find_last_job_for_thread-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_initialize-i.ri new file mode 100644 index 00000000..13b5083a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_post_next_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_post_next_job-i.ri new file mode 100644 index 00000000..40d996d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_post_next_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_validate-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_validate-i.ri new file mode 100644 index 00000000..75c0c59d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/ns_validate-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/post-i.ri new file mode 100644 index 00000000..8b454fd5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/reason-i.ri new file mode 100644 index 00000000..d3a2baf9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/restart-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/restart-i.ri new file mode 100644 index 00000000..b548e6de Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/restart-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send%21-i.ri new file mode 100644 index 00000000..23d56f2e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send-i.ri new file mode 100644 index 00000000..da3c3994 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off%21-i.ri new file mode 100644 index 00000000..03ec2bac Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off-i.ri new file mode 100644 index 00000000..8266ebb6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_off-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via%21-i.ri new file mode 100644 index 00000000..5a954427 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via-i.ri new file mode 100644 index 00000000..8aec61dc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/send_via-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/stopped%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/stopped%3f-i.ri new file mode 100644 index 00000000..faef1b88 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/stopped%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/value-i.ri new file mode 100644 index 00000000..e0115603 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/wait-i.ri new file mode 100644 index 00000000..b6d16b2f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Agent/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/cdesc-AsyncDelegator.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/cdesc-AsyncDelegator.ri new file mode 100644 index 00000000..9e8b4b35 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/cdesc-AsyncDelegator.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/method_missing-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/method_missing-i.ri new file mode 100644 index 00000000..1052278b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/method_missing-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/new-c.ri new file mode 100644 index 00000000..a3ce6a49 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/perform-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/perform-i.ri new file mode 100644 index 00000000..a150f8ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/perform-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/reset_if_forked-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/reset_if_forked-i.ri new file mode 100644 index 00000000..5e7f4ae0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/reset_if_forked-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/respond_to_missing%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/respond_to_missing%3f-i.ri new file mode 100644 index 00000000..252c6c67 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AsyncDelegator/respond_to_missing%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/cdesc-AwaitDelegator.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/cdesc-AwaitDelegator.ri new file mode 100644 index 00000000..598f3bd8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/cdesc-AwaitDelegator.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/method_missing-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/method_missing-i.ri new file mode 100644 index 00000000..fe77e3f9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/method_missing-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/new-c.ri new file mode 100644 index 00000000..d3502d6f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/respond_to_missing%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/respond_to_missing%3f-i.ri new file mode 100644 index 00000000..72a82178 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/AwaitDelegator/respond_to_missing%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/cdesc-ClassMethods.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/cdesc-ClassMethods.ri new file mode 100644 index 00000000..d7b97e2a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/cdesc-ClassMethods.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/new-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/new-i.ri new file mode 100644 index 00000000..62963c82 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/ClassMethods/new-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/async-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/async-i.ri new file mode 100644 index 00000000..bfb7c14a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/async-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/await-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/await-i.ri new file mode 100644 index 00000000..f7393cfa Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/await-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/call-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/call-i.ri new file mode 100644 index 00000000..848accd6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/call-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cast-i.ri new file mode 100644 index 00000000..5fbb2cb0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cdesc-Async.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cdesc-Async.ri new file mode 100644 index 00000000..af538a83 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/cdesc-Async.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/included-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/included-c.ri new file mode 100644 index 00000000..ff261f71 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/included-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/init_synchronization-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/init_synchronization-i.ri new file mode 100644 index 00000000..d990ae26 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/init_synchronization-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/validate_argc-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/validate_argc-c.ri new file mode 100644 index 00000000..c088f8e4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Async/validate_argc-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/cdesc-Atom.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/cdesc-Atom.ri new file mode 100644 index 00000000..a6bd1034 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/cdesc-Atom.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/compare_and_set-i.ri new file mode 100644 index 00000000..f51b3301 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/new-c.ri new file mode 100644 index 00000000..bb74d49c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/reset-i.ri new file mode 100644 index 00000000..12c8a466 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/swap-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/swap-i.ri new file mode 100644 index 00000000..4038076f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/swap-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/valid%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/valid%3f-i.ri new file mode 100644 index 00000000..98598ce0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Atom/valid%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/cdesc-AtomicBoolean.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/cdesc-AtomicBoolean.ri new file mode 100644 index 00000000..8f2bf536 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/cdesc-AtomicBoolean.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/inspect-i.ri new file mode 100644 index 00000000..3fb29584 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/to_s-i.ri new file mode 100644 index 00000000..d10cdce8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicBoolean/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/cdesc-AtomicDirectUpdate.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/cdesc-AtomicDirectUpdate.ri new file mode 100644 index 00000000..953ac6b0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/cdesc-AtomicDirectUpdate.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update%21-i.ri new file mode 100644 index 00000000..b00dbc26 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update-i.ri new file mode 100644 index 00000000..3fd96c5f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/try_update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/update-i.ri new file mode 100644 index 00000000..22956e6e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicDirectUpdate/update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/cdesc-AtomicFixnum.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/cdesc-AtomicFixnum.ri new file mode 100644 index 00000000..cb3f24b9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/cdesc-AtomicFixnum.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/inspect-i.ri new file mode 100644 index 00000000..bbe4de0d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/to_s-i.ri new file mode 100644 index 00000000..bb439956 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicFixnum/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/cdesc-AtomicMarkableReference.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/cdesc-AtomicMarkableReference.ri new file mode 100644 index 00000000..cf239146 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/cdesc-AtomicMarkableReference.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_set-i.ri new file mode 100644 index 00000000..a3496086 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_swap-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_swap-i.ri new file mode 100644 index 00000000..f0890ad5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/compare_and_swap-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/get-i.ri new file mode 100644 index 00000000..269b3390 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/immutable_array-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/immutable_array-i.ri new file mode 100644 index 00000000..0d567bda Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/immutable_array-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/mark-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/mark-i.ri new file mode 100644 index 00000000..dd5910bc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/mark-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/marked%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/marked%3f-i.ri new file mode 100644 index 00000000..82b4da14 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/marked%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/new-c.ri new file mode 100644 index 00000000..37455d3f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/set-i.ri new file mode 100644 index 00000000..aef83fb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update%21-i.ri new file mode 100644 index 00000000..a5d84a0f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update-i.ri new file mode 100644 index 00000000..05fba8f7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/try_update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/update-i.ri new file mode 100644 index 00000000..aec9349b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/value-i.ri new file mode 100644 index 00000000..de50bef8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicMarkableReference/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/cdesc-AtomicNumericCompareAndSetWrapper.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/cdesc-AtomicNumericCompareAndSetWrapper.ri new file mode 100644 index 00000000..ac758e19 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/cdesc-AtomicNumericCompareAndSetWrapper.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_set-i.ri new file mode 100644 index 00000000..c1121e3b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_swap-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_swap-i.ri new file mode 100644 index 00000000..943a2a9a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/AtomicNumericCompareAndSetWrapper/compare_and_swap-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/cdesc-CachedThreadPool.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/cdesc-CachedThreadPool.ri new file mode 100644 index 00000000..8c9ecab9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/cdesc-CachedThreadPool.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/new-c.ri new file mode 100644 index 00000000..3ba3b727 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/ns_initialize-i.ri new file mode 100644 index 00000000..bfd0d1af Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CachedThreadPool/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/add_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/add_observer-i.ri new file mode 100644 index 00000000..281b0a54 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/add_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/cdesc-CopyOnNotifyObserverSet.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/cdesc-CopyOnNotifyObserverSet.ri new file mode 100644 index 00000000..1d57f55b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/cdesc-CopyOnNotifyObserverSet.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/count_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/count_observers-i.ri new file mode 100644 index 00000000..f2bdbf5a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/count_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observer-i.ri new file mode 100644 index 00000000..7059a1d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observers-i.ri new file mode 100644 index 00000000..8027fdae Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/delete_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_and_clear_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_and_clear_observers-i.ri new file mode 100644 index 00000000..280cc857 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_and_clear_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_observers-i.ri new file mode 100644 index 00000000..5d3ad193 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/duplicate_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/new-c.ri new file mode 100644 index 00000000..658e7bc3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_and_delete_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_and_delete_observers-i.ri new file mode 100644 index 00000000..dcc12ca6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_and_delete_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_observers-i.ri new file mode 100644 index 00000000..be17a01e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_to-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_to-i.ri new file mode 100644 index 00000000..03b70eaa Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/notify_to-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/ns_initialize-i.ri new file mode 100644 index 00000000..cdb26418 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnNotifyObserverSet/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/add_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/add_observer-i.ri new file mode 100644 index 00000000..7015afe0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/add_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/cdesc-CopyOnWriteObserverSet.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/cdesc-CopyOnWriteObserverSet.ri new file mode 100644 index 00000000..5124c36a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/cdesc-CopyOnWriteObserverSet.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/clear_observers_and_return_old-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/clear_observers_and_return_old-i.ri new file mode 100644 index 00000000..1f556c59 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/clear_observers_and_return_old-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/count_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/count_observers-i.ri new file mode 100644 index 00000000..a20df955 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/count_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observer-i.ri new file mode 100644 index 00000000..06fd7457 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observers-i.ri new file mode 100644 index 00000000..842710cf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/delete_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/new-c.ri new file mode 100644 index 00000000..4036200a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_and_delete_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_and_delete_observers-i.ri new file mode 100644 index 00000000..78e3484b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_and_delete_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_observers-i.ri new file mode 100644 index 00000000..ec4d4194 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_to-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_to-i.ri new file mode 100644 index 00000000..fd877622 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/notify_to-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/ns_initialize-i.ri new file mode 100644 index 00000000..c29f3559 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers%3d-i.ri new file mode 100644 index 00000000..a8210139 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers-i.ri new file mode 100644 index 00000000..5d381a5e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/CopyOnWriteObserverSet/observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/%3c%3c-i.ri new file mode 100644 index 00000000..b28b0bd5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/cdesc-JavaNonConcurrentPriorityQueue.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/cdesc-JavaNonConcurrentPriorityQueue.ri new file mode 100644 index 00000000..c1a8dd69 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/cdesc-JavaNonConcurrentPriorityQueue.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/clear-i.ri new file mode 100644 index 00000000..94833880 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/delete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/delete-i.ri new file mode 100644 index 00000000..f401d186 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/delete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/deq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/deq-i.ri new file mode 100644 index 00000000..f00c64d6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/deq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/empty%3f-i.ri new file mode 100644 index 00000000..bd007f8f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/enq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/enq-i.ri new file mode 100644 index 00000000..a474adae Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/enq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/from_list-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/from_list-c.ri new file mode 100644 index 00000000..9c899b04 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/from_list-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/has_priority%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/has_priority%3f-i.ri new file mode 100644 index 00000000..95a6c4b8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/has_priority%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/include%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/include%3f-i.ri new file mode 100644 index 00000000..7735f8b9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/include%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/length-i.ri new file mode 100644 index 00000000..1ebce744 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/new-c.ri new file mode 100644 index 00000000..d0e14f99 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/peek-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/peek-i.ri new file mode 100644 index 00000000..93e50085 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/peek-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/pop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/pop-i.ri new file mode 100644 index 00000000..7ff3f3e4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/pop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/push-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/push-i.ri new file mode 100644 index 00000000..3c7bfd92 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/push-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/shift-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/shift-i.ri new file mode 100644 index 00000000..4ddee0ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/shift-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/size-i.ri new file mode 100644 index 00000000..7053f3af Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/JavaNonConcurrentPriorityQueue/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/%5b%5d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/%5b%5d%3d-i.ri new file mode 100644 index 00000000..9398d6d4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/%5b%5d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/cdesc-MriMapBackend.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/cdesc-MriMapBackend.ri new file mode 100644 index 00000000..83c6df73 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/cdesc-MriMapBackend.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/clear-i.ri new file mode 100644 index 00000000..d1b7a7fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute-i.ri new file mode 100644 index 00000000..c807ae45 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_absent-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_absent-i.ri new file mode 100644 index 00000000..bf7b032e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_absent-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_present-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_present-i.ri new file mode 100644 index 00000000..49994642 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/compute_if_present-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete-i.ri new file mode 100644 index 00000000..bc4bc724 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete_pair-i.ri new file mode 100644 index 00000000..1dc7f244 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/delete_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/get_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/get_and_set-i.ri new file mode 100644 index 00000000..93a807cc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/get_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/merge_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/merge_pair-i.ri new file mode 100644 index 00000000..a368a08b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/merge_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/new-c.ri new file mode 100644 index 00000000..1f53c46b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_if_exists-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_if_exists-i.ri new file mode 100644 index 00000000..0cc977c9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_if_exists-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_pair-i.ri new file mode 100644 index 00000000..c967ce8e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/MriMapBackend/replace_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d%3d-i.ri new file mode 100644 index 00000000..183f6a39 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d-i.ri new file mode 100644 index 00000000..61516415 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/cdesc-NonConcurrentMapBackend.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/cdesc-NonConcurrentMapBackend.ri new file mode 100644 index 00000000..f0270020 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/cdesc-NonConcurrentMapBackend.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/clear-i.ri new file mode 100644 index 00000000..4992c540 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute-i.ri new file mode 100644 index 00000000..b330783b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_absent-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_absent-i.ri new file mode 100644 index 00000000..0ac1e74e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_absent-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_present-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_present-i.ri new file mode 100644 index 00000000..799fd69c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/compute_if_present-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete-i.ri new file mode 100644 index 00000000..c053722f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete_pair-i.ri new file mode 100644 index 00000000..23d96c3b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/delete_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/dupped_backend-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/dupped_backend-i.ri new file mode 100644 index 00000000..eb1fda29 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/dupped_backend-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/each_pair-i.ri new file mode 100644 index 00000000..cda4a8f7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_and_set-i.ri new file mode 100644 index 00000000..94876c0f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_or_default-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_or_default-i.ri new file mode 100644 index 00000000..f5a76fe9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/get_or_default-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/initialize_copy-i.ri new file mode 100644 index 00000000..c69abcac Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/key%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/key%3f-i.ri new file mode 100644 index 00000000..ad8d8650 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/key%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/merge_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/merge_pair-i.ri new file mode 100644 index 00000000..597bfa08 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/merge_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/new-c.ri new file mode 100644 index 00000000..dac2fcb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/pair%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/pair%3f-i.ri new file mode 100644 index 00000000..91bf469f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/pair%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_if_exists-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_if_exists-i.ri new file mode 100644 index 00000000..bb405531 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_if_exists-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_pair-i.ri new file mode 100644 index 00000000..0f076d41 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/replace_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/set_backend-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/set_backend-i.ri new file mode 100644 index 00000000..f2ed2a7a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/set_backend-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/size-i.ri new file mode 100644 index 00000000..6a8e1be2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/store_computed_value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/store_computed_value-i.ri new file mode 100644 index 00000000..1f75958f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentMapBackend/store_computed_value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentPriorityQueue/cdesc-NonConcurrentPriorityQueue.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentPriorityQueue/cdesc-NonConcurrentPriorityQueue.ri new file mode 100644 index 00000000..a91afffc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/NonConcurrentPriorityQueue/cdesc-NonConcurrentPriorityQueue.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/%3c%3c-i.ri new file mode 100644 index 00000000..0a629d66 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/cdesc-RubyNonConcurrentPriorityQueue.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/cdesc-RubyNonConcurrentPriorityQueue.ri new file mode 100644 index 00000000..09080426 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/cdesc-RubyNonConcurrentPriorityQueue.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/clear-i.ri new file mode 100644 index 00000000..4973c04f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/delete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/delete-i.ri new file mode 100644 index 00000000..1ffcde38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/delete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/deq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/deq-i.ri new file mode 100644 index 00000000..c53bfeb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/deq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/empty%3f-i.ri new file mode 100644 index 00000000..4a6ada4e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/enq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/enq-i.ri new file mode 100644 index 00000000..18f0fe9e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/enq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/from_list-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/from_list-c.ri new file mode 100644 index 00000000..63794529 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/from_list-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/has_priority%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/has_priority%3f-i.ri new file mode 100644 index 00000000..e1b00f0c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/has_priority%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/include%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/include%3f-i.ri new file mode 100644 index 00000000..42a5011a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/include%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/length-i.ri new file mode 100644 index 00000000..73005e18 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/new-c.ri new file mode 100644 index 00000000..d561c909 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/ordered%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/ordered%3f-i.ri new file mode 100644 index 00000000..6e9dbdca Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/ordered%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/peek-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/peek-i.ri new file mode 100644 index 00000000..e78f0ab7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/peek-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/pop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/pop-i.ri new file mode 100644 index 00000000..bfdc0437 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/pop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/push-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/push-i.ri new file mode 100644 index 00000000..79fba273 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/push-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/shift-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/shift-i.ri new file mode 100644 index 00000000..3107808d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/shift-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/sink-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/sink-i.ri new file mode 100644 index 00000000..def5d12f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/sink-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/size-i.ri new file mode 100644 index 00000000..18a74815 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swap-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swap-i.ri new file mode 100644 index 00000000..4665636b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swap-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swim-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swim-i.ri new file mode 100644 index 00000000..c166d341 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyNonConcurrentPriorityQueue/swim-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/%3c%3c-i.ri new file mode 100644 index 00000000..73f63e8b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/cdesc-RubyTimeoutQueue.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/cdesc-RubyTimeoutQueue.ri new file mode 100644 index 00000000..09c190a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/cdesc-RubyTimeoutQueue.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/deq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/deq-i.ri new file mode 100644 index 00000000..3e667d93 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/deq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/enq-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/enq-i.ri new file mode 100644 index 00000000..87369cbb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/enq-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/new-c.ri new file mode 100644 index 00000000..86ec1060 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/pop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/pop-i.ri new file mode 100644 index 00000000..47214374 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/pop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/push-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/push-i.ri new file mode 100644 index 00000000..bb973ccf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/push-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/shift-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/shift-i.ri new file mode 100644 index 00000000..e4d87a8f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/RubyTimeoutQueue/shift-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d%3d-i.ri new file mode 100644 index 00000000..8ac518d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d-i.ri new file mode 100644 index 00000000..61c9b3c9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/cdesc-SynchronizedMapBackend.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/cdesc-SynchronizedMapBackend.ri new file mode 100644 index 00000000..94f248cf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/cdesc-SynchronizedMapBackend.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/clear-i.ri new file mode 100644 index 00000000..ae7687fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute-i.ri new file mode 100644 index 00000000..ee1411b6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_absent-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_absent-i.ri new file mode 100644 index 00000000..13c0a8d1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_absent-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_present-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_present-i.ri new file mode 100644 index 00000000..b4a3a369 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/compute_if_present-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete-i.ri new file mode 100644 index 00000000..bbac6a3c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete_pair-i.ri new file mode 100644 index 00000000..974133c7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/delete_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/dupped_backend-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/dupped_backend-i.ri new file mode 100644 index 00000000..7b7c4124 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/dupped_backend-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_and_set-i.ri new file mode 100644 index 00000000..ef1fdb6c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_or_default-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_or_default-i.ri new file mode 100644 index 00000000..90de7ce6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/get_or_default-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/key%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/key%3f-i.ri new file mode 100644 index 00000000..22b618a8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/key%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/merge_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/merge_pair-i.ri new file mode 100644 index 00000000..d373ce95 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/merge_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/new-c.ri new file mode 100644 index 00000000..563f5265 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_if_exists-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_if_exists-i.ri new file mode 100644 index 00000000..e633d505 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_if_exists-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_pair-i.ri new file mode 100644 index 00000000..7f65a08d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/replace_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/size-i.ri new file mode 100644 index 00000000..67ea4557 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/SynchronizedMapBackend/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TimeoutQueue/cdesc-TimeoutQueue.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TimeoutQueue/cdesc-TimeoutQueue.ri new file mode 100644 index 00000000..5cb573fb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TimeoutQueue/cdesc-TimeoutQueue.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/cdesc-TruffleRubyMapBackend.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/cdesc-TruffleRubyMapBackend.ri new file mode 100644 index 00000000..7a9daa20 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/cdesc-TruffleRubyMapBackend.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/new-c.ri new file mode 100644 index 00000000..d105870d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/TruffleRubyMapBackend/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/cdesc-Collection.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/cdesc-Collection.ri new file mode 100644 index 00000000..8ccea17b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Collection/cdesc-Collection.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/cdesc-Deprecation.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/cdesc-Deprecation.ri new file mode 100644 index 00000000..7361fe9b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/cdesc-Deprecation.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated-i.ri new file mode 100644 index 00000000..f1567f93 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated_method-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated_method-i.ri new file mode 100644 index 00000000..4cff1bbd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Deprecation/deprecated_method-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/apply_deref_options-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/apply_deref_options-i.ri new file mode 100644 index 00000000..763404d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/apply_deref_options-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/cdesc-Dereferenceable.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/cdesc-Dereferenceable.ri new file mode 100644 index 00000000..45dea458 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/cdesc-Dereferenceable.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/deref-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/deref-i.ri new file mode 100644 index 00000000..97362637 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/deref-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/ns_set_deref_options-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/ns_set_deref_options-i.ri new file mode 100644 index 00000000..12583471 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/ns_set_deref_options-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/set_deref_options-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/set_deref_options-i.ri new file mode 100644 index 00000000..3b6f5eca Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/set_deref_options-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value%3d-i.ri new file mode 100644 index 00000000..1abac314 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value-i.ri new file mode 100644 index 00000000..fb26ee88 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Dereferenceable/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/cdesc-Logging.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/cdesc-Logging.ri new file mode 100644 index 00000000..fbcd0a29 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/cdesc-Logging.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/log-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/log-i.ri new file mode 100644 index 00000000..ef34b9c7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Logging/log-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/cdesc-Obligation.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/cdesc-Obligation.ri new file mode 100644 index 00000000..8d01b103 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/cdesc-Obligation.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/compare_and_set_state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/compare_and_set_state-i.ri new file mode 100644 index 00000000..505a3a27 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/compare_and_set_state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/complete%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/complete%3f-i.ri new file mode 100644 index 00000000..380f31d0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/complete%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/event-i.ri new file mode 100644 index 00000000..b09dabb8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/exception-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/exception-i.ri new file mode 100644 index 00000000..5a2fb948 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/exception-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/fulfilled%3f-i.ri new file mode 100644 index 00000000..4a964daf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/get_arguments_from-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/get_arguments_from-i.ri new file mode 100644 index 00000000..74ec21e1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/get_arguments_from-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/if_state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/if_state-i.ri new file mode 100644 index 00000000..d5c096c3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/if_state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/incomplete%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/incomplete%3f-i.ri new file mode 100644 index 00000000..0ffca3e2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/incomplete%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/init_obligation-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/init_obligation-i.ri new file mode 100644 index 00000000..66f80fa2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/init_obligation-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/no_error%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/no_error%21-i.ri new file mode 100644 index 00000000..f09d6e5d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/no_error%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_check_state%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_check_state%3f-i.ri new file mode 100644 index 00000000..94280c73 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_check_state%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_set_state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_set_state-i.ri new file mode 100644 index 00000000..8ec71f30 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/ns_set_state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/pending%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/pending%3f-i.ri new file mode 100644 index 00000000..cd529f34 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/pending%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/realized%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/realized%3f-i.ri new file mode 100644 index 00000000..2df8800b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/realized%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/reason-i.ri new file mode 100644 index 00000000..16df3191 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/rejected%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/rejected%3f-i.ri new file mode 100644 index 00000000..69e5068f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/rejected%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/set_state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/set_state-i.ri new file mode 100644 index 00000000..aa135632 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/set_state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state%3d-i.ri new file mode 100644 index 00000000..9050be78 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state-i.ri new file mode 100644 index 00000000..d8b1a30e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/unscheduled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/unscheduled%3f-i.ri new file mode 100644 index 00000000..35d120d2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/unscheduled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value%21-i.ri new file mode 100644 index 00000000..065958c5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value-i.ri new file mode 100644 index 00000000..5b46511a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait%21-i.ri new file mode 100644 index 00000000..72d0fdce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait-i.ri new file mode 100644 index 00000000..e6610e81 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Obligation/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/add_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/add_observer-i.ri new file mode 100644 index 00000000..770b031e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/add_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/cdesc-Observable.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/cdesc-Observable.ri new file mode 100644 index 00000000..86c35c92 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/cdesc-Observable.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/count_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/count_observers-i.ri new file mode 100644 index 00000000..e4590c66 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/count_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observer-i.ri new file mode 100644 index 00000000..fd0744b2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observers-i.ri new file mode 100644 index 00000000..93847799 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/delete_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/observers-i.ri new file mode 100644 index 00000000..f8d2162c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/with_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/with_observer-i.ri new file mode 100644 index 00000000..557d7e4f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/Observable/with_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/cdesc-Concern.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/cdesc-Concern.ri new file mode 100644 index 00000000..81df09ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Concern/cdesc-Concern.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ConcurrentUpdateError/cdesc-ConcurrentUpdateError.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ConcurrentUpdateError/cdesc-ConcurrentUpdateError.ri new file mode 100644 index 00000000..7304aa12 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ConcurrentUpdateError/cdesc-ConcurrentUpdateError.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CountDownLatch/cdesc-CountDownLatch.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CountDownLatch/cdesc-CountDownLatch.ri new file mode 100644 index 00000000..04ab6e79 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CountDownLatch/cdesc-CountDownLatch.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/broken%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/broken%3f-i.ri new file mode 100644 index 00000000..d901673d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/broken%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/cdesc-CyclicBarrier.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/cdesc-CyclicBarrier.ri new file mode 100644 index 00000000..6463e7a2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/cdesc-CyclicBarrier.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/new-c.ri new file mode 100644 index 00000000..31de8b9d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_generation_done-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_generation_done-i.ri new file mode 100644 index 00000000..e5ef2e46 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_generation_done-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_initialize-i.ri new file mode 100644 index 00000000..0ee8c72e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_next_generation-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_next_generation-i.ri new file mode 100644 index 00000000..3c03ad74 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/ns_next_generation-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/number_waiting-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/number_waiting-i.ri new file mode 100644 index 00000000..c343cf64 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/number_waiting-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/parties-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/parties-i.ri new file mode 100644 index 00000000..72fa1f99 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/parties-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/reset-i.ri new file mode 100644 index 00000000..ba48e60d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/wait-i.ri new file mode 100644 index 00000000..71ddf541 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/CyclicBarrier/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/cdesc-DaemonThreadFactory.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/cdesc-DaemonThreadFactory.ri new file mode 100644 index 00000000..0d856a22 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/cdesc-DaemonThreadFactory.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/new-c.ri new file mode 100644 index 00000000..486c36c6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/newThread-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/newThread-i.ri new file mode 100644 index 00000000..b0838bef Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DaemonThreadFactory/newThread-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/cdesc-Delay.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/cdesc-Delay.ri new file mode 100644 index 00000000..29aa8f38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/cdesc-Delay.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/new-c.ri new file mode 100644 index 00000000..89901710 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/ns_initialize-i.ri new file mode 100644 index 00000000..f1e7077c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/reconfigure-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/reconfigure-i.ri new file mode 100644 index 00000000..946fb741 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/reconfigure-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value%21-i.ri new file mode 100644 index 00000000..11d5f435 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value-i.ri new file mode 100644 index 00000000..c32395ea Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/wait-i.ri new file mode 100644 index 00000000..40316445 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Delay/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DependencyCounter/cdesc-DependencyCounter.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DependencyCounter/cdesc-DependencyCounter.ri new file mode 100644 index 00000000..f5ff10f6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/DependencyCounter/cdesc-DependencyCounter.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/cdesc-Event.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/cdesc-Event.ri new file mode 100644 index 00000000..dc1f4bc2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/cdesc-Event.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/new-c.ri new file mode 100644 index 00000000..034cd78e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_initialize-i.ri new file mode 100644 index 00000000..d5b51e2f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_set-i.ri new file mode 100644 index 00000000..2cc0f536 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/ns_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/reset-i.ri new file mode 100644 index 00000000..49ad42fb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set%3f-i.ri new file mode 100644 index 00000000..688e1c7d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set-i.ri new file mode 100644 index 00000000..8e98a0f4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/try%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/try%3f-i.ri new file mode 100644 index 00000000..5d261df4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/try%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/wait-i.ri new file mode 100644 index 00000000..b8b65ba1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Event/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Exchanger/cdesc-Exchanger.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Exchanger/cdesc-Exchanger.ri new file mode 100644 index 00000000..42ed3ade Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Exchanger/cdesc-Exchanger.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/%3c%3c-i.ri new file mode 100644 index 00000000..3fd5c93a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/can_overflow%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/can_overflow%3f-i.ri new file mode 100644 index 00000000..a6b25078 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/can_overflow%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/cdesc-ExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/cdesc-ExecutorService.ri new file mode 100644 index 00000000..24babd58 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/cdesc-ExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/post-i.ri new file mode 100644 index 00000000..a6ba2bbc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/serialized%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/serialized%3f-i.ri new file mode 100644 index 00000000..472bfda9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ExecutorService/serialized%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/bind-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/bind-i.ri new file mode 100644 index 00000000..ba7ed6e4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/bind-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/cdesc-FiberLocalVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/cdesc-FiberLocalVar.ri new file mode 100644 index 00000000..cf5a353d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/cdesc-FiberLocalVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/default-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/default-i.ri new file mode 100644 index 00000000..fed4818d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/default-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/new-c.ri new file mode 100644 index 00000000..72f51fb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value%3d-i.ri new file mode 100644 index 00000000..f8b9205e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value-i.ri new file mode 100644 index 00000000..854a2b6d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocalVar/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/cdesc-FiberLocals.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/cdesc-FiberLocals.ri new file mode 100644 index 00000000..4b8cd964 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/cdesc-FiberLocals.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals%21-i.ri new file mode 100644 index 00000000..42b4ea0c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals-i.ri new file mode 100644 index 00000000..dee65791 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FiberLocals/locals-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/cdesc-FixedThreadPool.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/cdesc-FixedThreadPool.ri new file mode 100644 index 00000000..1952755b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/cdesc-FixedThreadPool.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/new-c.ri new file mode 100644 index 00000000..f0ab657f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/FixedThreadPool/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancel-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancel-i.ri new file mode 100644 index 00000000..657d713b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancel-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancelled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancelled%3f-i.ri new file mode 100644 index 00000000..49653ccb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cancelled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cdesc-Future.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cdesc-Future.ri new file mode 100644 index 00000000..5226679c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/cdesc-Future.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-c.ri new file mode 100644 index 00000000..91e301f0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-i.ri new file mode 100644 index 00000000..189c796b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/new-c.ri new file mode 100644 index 00000000..d4303a34 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/ns_initialize-i.ri new file mode 100644 index 00000000..820940eb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/set-i.ri new file mode 100644 index 00000000..405e0e3f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/wait_or_cancel-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/wait_or_cancel-i.ri new file mode 100644 index 00000000..da1a24fa Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Future/wait_or_cancel-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/add_observer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/add_observer-i.ri new file mode 100644 index 00000000..82c5c439 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/add_observer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/cdesc-IVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/cdesc-IVar.ri new file mode 100644 index 00000000..65a9ca5a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/cdesc-IVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete-i.ri new file mode 100644 index 00000000..39063362 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete_without_notification-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete_without_notification-i.ri new file mode 100644 index 00000000..8c4cf639 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/complete_without_notification-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/fail-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/fail-i.ri new file mode 100644 index 00000000..9fbe6e02 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/fail-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/new-c.ri new file mode 100644 index 00000000..7d750427 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/notify_observers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/notify_observers-i.ri new file mode 100644 index 00000000..b575c636 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/notify_observers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_complete_without_notification-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_complete_without_notification-i.ri new file mode 100644 index 00000000..ca6d6f88 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_complete_without_notification-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_initialize-i.ri new file mode 100644 index 00000000..42f2ee2c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/safe_execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/safe_execute-i.ri new file mode 100644 index 00000000..537a4317 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/safe_execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/set-i.ri new file mode 100644 index 00000000..6eea7557 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/try_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/try_set-i.ri new file mode 100644 index 00000000..71ef3ebf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IVar/try_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/%3c%3c-i.ri new file mode 100644 index 00000000..e1b957c5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/cdesc-ImmediateExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/cdesc-ImmediateExecutor.ri new file mode 100644 index 00000000..fc31243c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/cdesc-ImmediateExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/kill-i.ri new file mode 100644 index 00000000..75916ba3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/new-c.ri new file mode 100644 index 00000000..5041f0b9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/post-i.ri new file mode 100644 index 00000000..d9dc7cf3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/running%3f-i.ri new file mode 100644 index 00000000..606fc563 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown%3f-i.ri new file mode 100644 index 00000000..ec504326 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown-i.ri new file mode 100644 index 00000000..3db73e97 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shutdown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shuttingdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shuttingdown%3f-i.ri new file mode 100644 index 00000000..630abb16 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/shuttingdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/wait_for_termination-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/wait_for_termination-i.ri new file mode 100644 index 00000000..f1a9ebb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmediateExecutor/wait_for_termination-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%3d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%3d%3d-i.ri new file mode 100644 index 00000000..96aebd4b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%3d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%5b%5d-i.ri new file mode 100644 index 00000000..fb82bc40 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/cdesc-ImmutableStruct.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/cdesc-ImmutableStruct.ri new file mode 100644 index 00000000..4d05f441 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/cdesc-ImmutableStruct.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each-i.ri new file mode 100644 index 00000000..e24682d3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each_pair-i.ri new file mode 100644 index 00000000..94a652ee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/included-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/included-c.ri new file mode 100644 index 00000000..d9fcffb9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/included-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/initialize_copy-i.ri new file mode 100644 index 00000000..b15e5bc3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/inspect-i.ri new file mode 100644 index 00000000..38a18117 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/merge-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/merge-i.ri new file mode 100644 index 00000000..79185ca7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/merge-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/new-c.ri new file mode 100644 index 00000000..5e812d4f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/select-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/select-i.ri new file mode 100644 index 00000000..525012c1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/select-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_a-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_a-i.ri new file mode 100644 index 00000000..8775c323 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_a-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_h-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_h-i.ri new file mode 100644 index 00000000..260ffa81 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_h-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_s-i.ri new file mode 100644 index 00000000..492fa1d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values-i.ri new file mode 100644 index 00000000..7f8ea895 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values_at-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values_at-i.ri new file mode 100644 index 00000000..fc64fe6f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ImmutableStruct/values_at-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/cdesc-IndirectImmediateExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/cdesc-IndirectImmediateExecutor.ri new file mode 100644 index 00000000..703fc574 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/cdesc-IndirectImmediateExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/new-c.ri new file mode 100644 index 00000000..bc675027 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/post-i.ri new file mode 100644 index 00000000..992566a8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/IndirectImmediateExecutor/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JRubySet/cdesc-JRubySet.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JRubySet/cdesc-JRubySet.ri new file mode 100644 index 00000000..91854ad5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JRubySet/cdesc-JRubySet.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaAtomicReference/cdesc-JavaAtomicReference.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaAtomicReference/cdesc-JavaAtomicReference.ri new file mode 100644 index 00000000..3ea56bad Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaAtomicReference/cdesc-JavaAtomicReference.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/cdesc-JavaCountDownLatch.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/cdesc-JavaCountDownLatch.ri new file mode 100644 index 00000000..1c59af22 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/cdesc-JavaCountDownLatch.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count-i.ri new file mode 100644 index 00000000..c17f1acf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count_down-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count_down-i.ri new file mode 100644 index 00000000..c959af3c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/count_down-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/new-c.ri new file mode 100644 index 00000000..fc291c3a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/wait-i.ri new file mode 100644 index 00000000..f2c4d42b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaCountDownLatch/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/cdesc-JavaExchanger.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/cdesc-JavaExchanger.ri new file mode 100644 index 00000000..6b988c6f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/cdesc-JavaExchanger.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/do_exchange-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/do_exchange-i.ri new file mode 100644 index 00000000..46b7601b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/do_exchange-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/new-c.ri new file mode 100644 index 00000000..f55e6456 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExchanger/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/cdesc-Job.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/cdesc-Job.ri new file mode 100644 index 00000000..ec9afacd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/cdesc-Job.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/new-c.ri new file mode 100644 index 00000000..1929ae09 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/run-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/run-i.ri new file mode 100644 index 00000000..545dd5b5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/Job/run-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/cdesc-JavaExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/cdesc-JavaExecutorService.ri new file mode 100644 index 00000000..1ed2fdb8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/cdesc-JavaExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/kill-i.ri new file mode 100644 index 00000000..b7c055f3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_running%3f-i.ri new file mode 100644 index 00000000..a454a146 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shutdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shutdown%3f-i.ri new file mode 100644 index 00000000..c6a867ec Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shutdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shuttingdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shuttingdown%3f-i.ri new file mode 100644 index 00000000..12e6fa89 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/ns_shuttingdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/post-i.ri new file mode 100644 index 00000000..958b9e9b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/shutdown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/shutdown-i.ri new file mode 100644 index 00000000..278ff300 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/shutdown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/wait_for_termination-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/wait_for_termination-i.ri new file mode 100644 index 00000000..f49443ba Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaExecutorService/wait_for_termination-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/cdesc-JavaSingleThreadExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/cdesc-JavaSingleThreadExecutor.ri new file mode 100644 index 00000000..e5806585 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/cdesc-JavaSingleThreadExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/new-c.ri new file mode 100644 index 00000000..a3cd9b88 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/ns_initialize-i.ri new file mode 100644 index 00000000..abdc5892 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaSingleThreadExecutor/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/active_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/active_count-i.ri new file mode 100644 index 00000000..69952d1f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/active_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/can_overflow%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/can_overflow%3f-i.ri new file mode 100644 index 00000000..7a0c2747 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/can_overflow%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/cdesc-JavaThreadPoolExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/cdesc-JavaThreadPoolExecutor.ri new file mode 100644 index 00000000..c67b96d3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/cdesc-JavaThreadPoolExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/completed_task_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/completed_task_count-i.ri new file mode 100644 index 00000000..06bf8f86 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/completed_task_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/idletime-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/idletime-i.ri new file mode 100644 index 00000000..aa026818 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/idletime-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/largest_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/largest_length-i.ri new file mode 100644 index 00000000..7add702c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/largest_length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/length-i.ri new file mode 100644 index 00000000..6f5fe575 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_length-i.ri new file mode 100644 index 00000000..5f2423a4 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_length-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"max_length:ETI"2Concurrent::JavaThreadPoolExecutor#max_length;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"8@!macro thread_pool_executor_attr_reader_max_length;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::JavaThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_queue-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_queue-i.ri new file mode 100644 index 00000000..c95a6c66 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/max_queue-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"max_queue:ETI"1Concurrent::JavaThreadPoolExecutor#max_queue;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"7@!macro thread_pool_executor_attr_reader_max_queue;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::JavaThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/min_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/min_length-i.ri new file mode 100644 index 00000000..b5a34bf1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/min_length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/new-c.ri new file mode 100644 index 00000000..682ac0db Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/ns_initialize-i.ri new file mode 100644 index 00000000..89a81a24 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/prune_pool-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/prune_pool-i.ri new file mode 100644 index 00000000..a481fcd1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/prune_pool-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/queue_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/queue_length-i.ri new file mode 100644 index 00000000..e75ce431 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/queue_length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/remaining_capacity-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/remaining_capacity-i.ri new file mode 100644 index 00000000..e1d553e8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/remaining_capacity-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/running%3f-i.ri new file mode 100644 index 00000000..3015974b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/scheduled_task_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/scheduled_task_count-i.ri new file mode 100644 index 00000000..3e8feb12 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/scheduled_task_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/synchronous-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/synchronous-i.ri new file mode 100644 index 00000000..22c7f5b4 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/JavaThreadPoolExecutor/synchronous-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"synchronous:ETI"3Concurrent::JavaThreadPoolExecutor#synchronous;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"9@!macro thread_pool_executor_attr_reader_synchronous;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::JavaThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/cdesc-Node.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/cdesc-Node.ri new file mode 100644 index 00000000..5cdfb2d3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/cdesc-Node.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/new-c.ri new file mode 100644 index 00000000..1c674265 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/next_node-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/next_node-i.ri new file mode 100644 index 00000000..2cb3323c --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/next_node-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"next_node:ETI".Concurrent::LockFreeStack::Node#next_node;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Node];T: +@fileI"Alib/concurrent-ruby/concurrent/collection/lock_free_stack.rb;T:0@omit_headings_from_table_of_contents_below0F@I"$Concurrent::LockFreeStack::Node;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/value-i.ri new file mode 100644 index 00000000..94577d75 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/Node/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"*Concurrent::LockFreeStack::Node#value;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Object];T: +@fileI"Alib/concurrent-ruby/concurrent/collection/lock_free_stack.rb;T:0@omit_headings_from_table_of_contents_below0F@I"$Concurrent::LockFreeStack::Node;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/cdesc-LockFreeStack.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/cdesc-LockFreeStack.ri new file mode 100644 index 00000000..e40c3f77 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/cdesc-LockFreeStack.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear-i.ri new file mode 100644 index 00000000..182cd959 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_each-i.ri new file mode 100644 index 00000000..bfed226f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_if-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_if-i.ri new file mode 100644 index 00000000..aacd076b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/clear_if-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_clear-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_clear-i.ri new file mode 100644 index 00000000..e60c6269 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_clear-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_pop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_pop-i.ri new file mode 100644 index 00000000..079ed5e1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_pop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_push-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_push-i.ri new file mode 100644 index 00000000..af772707 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/compare_and_push-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/each-i.ri new file mode 100644 index 00000000..7e3d8cba Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/empty%3f-i.ri new file mode 100644 index 00000000..9bca97a1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/inspect-i.ri new file mode 100644 index 00000000..5d3db731 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/new-c.ri new file mode 100644 index 00000000..631809d7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of1-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of1-c.ri new file mode 100644 index 00000000..7f70b72a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of1-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of2-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of2-c.ri new file mode 100644 index 00000000..4f7e20ef Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/of2-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/peek-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/peek-i.ri new file mode 100644 index 00000000..858c0d36 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/peek-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/pop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/pop-i.ri new file mode 100644 index 00000000..82408eca Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/pop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/push-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/push-i.ri new file mode 100644 index 00000000..822d982e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/push-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/replace_if-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/replace_if-i.ri new file mode 100644 index 00000000..2aa056d0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/replace_if-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/to_s-i.ri new file mode 100644 index 00000000..76924525 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockFreeStack/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/bind-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/bind-i.ri new file mode 100644 index 00000000..ba7ed6e4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/bind-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/cdesc-LockLocalVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/cdesc-LockLocalVar.ri new file mode 100644 index 00000000..6835475c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/cdesc-LockLocalVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/default-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/default-i.ri new file mode 100644 index 00000000..fed4818d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/default-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/new-c.ri new file mode 100644 index 00000000..72f51fb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value%3d-i.ri new file mode 100644 index 00000000..f8b9205e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value-i.ri new file mode 100644 index 00000000..854a2b6d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/LockLocalVar/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/borrow-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/borrow-i.ri new file mode 100644 index 00000000..53772dda Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/borrow-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/cdesc-MVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/cdesc-MVar.ri new file mode 100644 index 00000000..41f45a71 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/cdesc-MVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/empty%3f-i.ri new file mode 100644 index 00000000..a69c3fe5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/full%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/full%3f-i.ri new file mode 100644 index 00000000..93158c9e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/full%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify%21-i.ri new file mode 100644 index 00000000..4abc223f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify-i.ri new file mode 100644 index 00000000..894f05fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/modify-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/new-c.ri new file mode 100644 index 00000000..ba219858 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/put-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/put-i.ri new file mode 100644 index 00000000..efe59118 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/put-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/set%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/set%21-i.ri new file mode 100644 index 00000000..952c15cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/set%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/synchronize-i.ri new file mode 100644 index 00000000..2ce4fd59 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/take-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/take-i.ri new file mode 100644 index 00000000..5bc73330 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/take-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_put%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_put%21-i.ri new file mode 100644 index 00000000..dd61331c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_put%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_take%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_take%21-i.ri new file mode 100644 index 00000000..f653d10e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/try_take%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_empty%3f-i.ri new file mode 100644 index 00000000..07c4648b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_full%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_full%3f-i.ri new file mode 100644 index 00000000..f170b7b2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/unlocked_full%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_empty-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_empty-i.ri new file mode 100644 index 00000000..6939952e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_empty-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_full-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_full-i.ri new file mode 100644 index 00000000..0d50d70b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_for_full-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_while-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_while-i.ri new file mode 100644 index 00000000..7d63bc81 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MVar/wait_while-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/%5b%5d-i.ri new file mode 100644 index 00000000..c6486fa5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/cdesc-Map.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/cdesc-Map.ri new file mode 100644 index 00000000..a91430ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/cdesc-Map.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each-i.ri new file mode 100644 index 00000000..915c9bee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_key-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_key-i.ri new file mode 100644 index 00000000..baab5940 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_key-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_pair-i.ri new file mode 100644 index 00000000..e9aabd01 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_value-i.ri new file mode 100644 index 00000000..750ceb74 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/each_value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/empty%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/empty%3f-i.ri new file mode 100644 index 00000000..586a000b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/empty%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch-i.ri new file mode 100644 index 00000000..550a56c3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch_or_store-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch_or_store-i.ri new file mode 100644 index 00000000..86ee3971 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/fetch_or_store-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/get-i.ri new file mode 100644 index 00000000..e29eeb47 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/initialize_copy-i.ri new file mode 100644 index 00000000..1f6e7ed1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/inspect-i.ri new file mode 100644 index 00000000..a380fba2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/key-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/key-i.ri new file mode 100644 index 00000000..0f065396 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/key-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/keys-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/keys-i.ri new file mode 100644 index 00000000..040c2c51 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/keys-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_dump-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_dump-i.ri new file mode 100644 index 00000000..9ad3431a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_dump-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_load-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_load-i.ri new file mode 100644 index 00000000..506ae224 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/marshal_load-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/new-c.ri new file mode 100644 index 00000000..a3ea7e0b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/populate_from-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/populate_from-i.ri new file mode 100644 index 00000000..fe4a9c37 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/populate_from-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/put_if_absent-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/put_if_absent-i.ri new file mode 100644 index 00000000..44db8620 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/put_if_absent-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/raise_fetch_no_key-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/raise_fetch_no_key-i.ri new file mode 100644 index 00000000..0857f80a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/raise_fetch_no_key-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/size-i.ri new file mode 100644 index 00000000..11a098b1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/validate_options_hash%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/validate_options_hash%21-i.ri new file mode 100644 index 00000000..48e8cb0e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/validate_options_hash%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/value%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/value%3f-i.ri new file mode 100644 index 00000000..a5a7a5cd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/value%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/values-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/values-i.ri new file mode 100644 index 00000000..85076853 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Map/values-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/%3c%3d%3e-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/%3c%3d%3e-i.ri new file mode 100644 index 00000000..9e0e554e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/%3c%3d%3e-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/cdesc-Maybe.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/cdesc-Maybe.ri new file mode 100644 index 00000000..ce50cb90 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/cdesc-Maybe.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/from-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/from-c.ri new file mode 100644 index 00000000..e4084269 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/from-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/fulfilled%3f-i.ri new file mode 100644 index 00000000..20a5fcf4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just%3f-i.ri new file mode 100644 index 00000000..42bc164a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-c.ri new file mode 100644 index 00000000..5142a5f3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-i.ri new file mode 100644 index 00000000..3d204760 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/just-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" just:ETI"Concurrent::Maybe#just;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"GThe value of a `Maybe` when `Just`. Will be `NONE` when `Nothing`.;T: +@fileI",lib/concurrent-ruby/concurrent/maybe.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Maybe;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/new-c.ri new file mode 100644 index 00000000..2edc7d2d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing%3f-i.ri new file mode 100644 index 00000000..47a97eb4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-c.ri new file mode 100644 index 00000000..0be886d3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-i.ri new file mode 100644 index 00000000..8d454658 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/nothing-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" nothing:ETI"Concurrent::Maybe#nothing;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"KThe reason for the `Maybe` when `Nothing`. Will be `NONE` when `Just`.;T: +@fileI",lib/concurrent-ruby/concurrent/maybe.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Maybe;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/or-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/or-i.ri new file mode 100644 index 00000000..f1b9c18c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/or-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/reason-i.ri new file mode 100644 index 00000000..8c0d2588 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/reason-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" reason:ETI"Concurrent::Maybe#reason;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"KThe reason for the `Maybe` when `Nothing`. Will be `NONE` when `Just`.;T: +@fileI",lib/concurrent-ruby/concurrent/maybe.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Maybe;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/rejected%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/rejected%3f-i.ri new file mode 100644 index 00000000..b4a7a853 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/rejected%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/value-i.ri new file mode 100644 index 00000000..a2121001 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Maybe/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"Concurrent::Maybe#value;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"GThe value of a `Maybe` when `Just`. Will be `NONE` when `Nothing`.;T: +@fileI",lib/concurrent-ruby/concurrent/maybe.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Maybe;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/cdesc-MultipleAssignmentError.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/cdesc-MultipleAssignmentError.ri new file mode 100644 index 00000000..9f2f3d4c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/cdesc-MultipleAssignmentError.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspect-i.ri new file mode 100644 index 00000000..4fdcd705 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspection_data-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspection_data-i.ri new file mode 100644 index 00000000..c474d3f2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/inspection_data-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/new-c.ri new file mode 100644 index 00000000..dfdebc6e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleAssignmentError/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/cdesc-MultipleErrors.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/cdesc-MultipleErrors.ri new file mode 100644 index 00000000..3c718485 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/cdesc-MultipleErrors.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/errors-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/errors-i.ri new file mode 100644 index 00000000..8cb8d2b2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/errors-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/new-c.ri new file mode 100644 index 00000000..221b653e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MultipleErrors/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%3d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%3d%3d-i.ri new file mode 100644 index 00000000..1728f3bf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%3d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d%3d-i.ri new file mode 100644 index 00000000..840447ac Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d-i.ri new file mode 100644 index 00000000..0c1d5cee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/cdesc-MutableStruct.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/cdesc-MutableStruct.ri new file mode 100644 index 00000000..3450f429 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/cdesc-MutableStruct.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each-i.ri new file mode 100644 index 00000000..d6907b65 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each_pair-i.ri new file mode 100644 index 00000000..18aadb3f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/initialize_copy-i.ri new file mode 100644 index 00000000..56713696 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/inspect-i.ri new file mode 100644 index 00000000..10ee83ed Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/merge-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/merge-i.ri new file mode 100644 index 00000000..419a164e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/merge-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/new-c.ri new file mode 100644 index 00000000..c5647098 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/select-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/select-i.ri new file mode 100644 index 00000000..a9eed200 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/select-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_a-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_a-i.ri new file mode 100644 index 00000000..c421afbc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_a-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_h-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_h-i.ri new file mode 100644 index 00000000..c3687928 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_h-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_s-i.ri new file mode 100644 index 00000000..917ffe6a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values-i.ri new file mode 100644 index 00000000..009b07fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values_at-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values_at-i.ri new file mode 100644 index 00000000..e60c50ab Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutableStruct/values_at-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/cdesc-MutexAtomicBoolean.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/cdesc-MutexAtomicBoolean.ri new file mode 100644 index 00000000..63e29d75 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/cdesc-MutexAtomicBoolean.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/false%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/false%3f-i.ri new file mode 100644 index 00000000..e59a286e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/false%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_false-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_false-i.ri new file mode 100644 index 00000000..d88264d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_false-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_true-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_true-i.ri new file mode 100644 index 00000000..98dda1a0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/make_true-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/new-c.ri new file mode 100644 index 00000000..3424ab08 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/ns_make_value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/ns_make_value-i.ri new file mode 100644 index 00000000..956da67b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/ns_make_value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/synchronize-i.ri new file mode 100644 index 00000000..3d3050a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/true%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/true%3f-i.ri new file mode 100644 index 00000000..34e1924d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/true%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value%3d-i.ri new file mode 100644 index 00000000..5a30c14d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value-i.ri new file mode 100644 index 00000000..3c924ae7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicBoolean/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/cdesc-MutexAtomicFixnum.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/cdesc-MutexAtomicFixnum.ri new file mode 100644 index 00000000..78782621 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/cdesc-MutexAtomicFixnum.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/compare_and_set-i.ri new file mode 100644 index 00000000..8c9abdd0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/decrement-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/decrement-i.ri new file mode 100644 index 00000000..792dabb3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/decrement-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/down-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/down-i.ri new file mode 100644 index 00000000..c5be2242 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/down-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/increment-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/increment-i.ri new file mode 100644 index 00000000..f27fd2c2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/increment-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/new-c.ri new file mode 100644 index 00000000..75dae1be Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/ns_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/ns_set-i.ri new file mode 100644 index 00000000..d633671d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/ns_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/synchronize-i.ri new file mode 100644 index 00000000..1d8e5b22 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/up-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/up-i.ri new file mode 100644 index 00000000..405d4ce3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/up-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/update-i.ri new file mode 100644 index 00000000..b54fa895 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value%3d-i.ri new file mode 100644 index 00000000..acc378f4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value-i.ri new file mode 100644 index 00000000..94cccf35 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicFixnum/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/_compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/_compare_and_set-i.ri new file mode 100644 index 00000000..17859977 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/_compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/cdesc-MutexAtomicReference.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/cdesc-MutexAtomicReference.ri new file mode 100644 index 00000000..3d3f7f87 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/cdesc-MutexAtomicReference.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get-i.ri new file mode 100644 index 00000000..6a7e7bb4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get_and_set-i.ri new file mode 100644 index 00000000..08066c1c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/get_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/new-c.ri new file mode 100644 index 00000000..064632c5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/set-i.ri new file mode 100644 index 00000000..d67d3fb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/swap-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/swap-i.ri new file mode 100644 index 00000000..d58fdf1b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/swap-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/synchronize-i.ri new file mode 100644 index 00000000..c7addd77 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value%3d-i.ri new file mode 100644 index 00000000..b28e2f66 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value-i.ri new file mode 100644 index 00000000..d8a93cea Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexAtomicReference/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/cdesc-MutexCountDownLatch.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/cdesc-MutexCountDownLatch.ri new file mode 100644 index 00000000..b3140925 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/cdesc-MutexCountDownLatch.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count-i.ri new file mode 100644 index 00000000..d47a64e6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count_down-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count_down-i.ri new file mode 100644 index 00000000..408f37ee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/count_down-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/new-c.ri new file mode 100644 index 00000000..12425b0f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/ns_initialize-i.ri new file mode 100644 index 00000000..2a5b7fcd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/wait-i.ri new file mode 100644 index 00000000..60c7d0ed Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexCountDownLatch/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/acquire-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/acquire-i.ri new file mode 100644 index 00000000..e90f1ab0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/acquire-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/available_permits-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/available_permits-i.ri new file mode 100644 index 00000000..98d380f4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/available_permits-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/cdesc-MutexSemaphore.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/cdesc-MutexSemaphore.ri new file mode 100644 index 00000000..ef8254c6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/cdesc-MutexSemaphore.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/drain_permits-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/drain_permits-i.ri new file mode 100644 index 00000000..9618a736 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/drain_permits-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/new-c.ri new file mode 100644 index 00000000..de5225c4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/ns_initialize-i.ri new file mode 100644 index 00000000..7ce8d8a5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/reduce_permits-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/reduce_permits-i.ri new file mode 100644 index 00000000..3c70bda5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/reduce_permits-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/release-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/release-i.ri new file mode 100644 index 00000000..18a6ee9e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/release-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire-i.ri new file mode 100644 index 00000000..76a7b4d1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_now-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_now-i.ri new file mode 100644 index 00000000..a1d5feab Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_now-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_timed-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_timed-i.ri new file mode 100644 index 00000000..bbdad1d6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/MutexSemaphore/try_acquire_timed-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/cdesc-Options.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/cdesc-Options.ri new file mode 100644 index 00000000..29a68862 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/cdesc-Options.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/executor-c.ri new file mode 100644 index 00000000..6cab21b4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Options/executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/aggregate-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/aggregate-c.ri new file mode 100644 index 00000000..a03f3967 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/aggregate-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/all%3f-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/all%3f-c.ri new file mode 100644 index 00000000..63c890ee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/all%3f-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/any%3f-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/any%3f-c.ri new file mode 100644 index 00000000..bb14e0ad Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/any%3f-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/catch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/catch-i.ri new file mode 100644 index 00000000..094d52af Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/catch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/cdesc-Promise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/cdesc-Promise.ri new file mode 100644 index 00000000..9ec4f79a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/cdesc-Promise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/complete-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/complete-i.ri new file mode 100644 index 00000000..0fd91cdf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/complete-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-c.ri new file mode 100644 index 00000000..664f78fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-i.ri new file mode 100644 index 00000000..bfae07c0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fail-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fail-i.ri new file mode 100644 index 00000000..cb8a1b09 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fail-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/flat_map-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/flat_map-i.ri new file mode 100644 index 00000000..01e71a54 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/flat_map-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fulfill-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fulfill-c.ri new file mode 100644 index 00000000..6bda6d64 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/fulfill-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/new-c.ri new file mode 100644 index 00000000..40fe5c1a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/notify_child-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/notify_child-i.ri new file mode 100644 index 00000000..85baaa23 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/notify_child-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/ns_initialize-i.ri new file mode 100644 index 00000000..8fe52752 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_error-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_error-i.ri new file mode 100644 index 00000000..f6b7be63 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_error-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_fulfill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_fulfill-i.ri new file mode 100644 index 00000000..c2165083 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_fulfill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_reject-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_reject-i.ri new file mode 100644 index 00000000..271b6b30 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_reject-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_success-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_success-i.ri new file mode 100644 index 00000000..cf24a8ae Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/on_success-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/realize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/realize-i.ri new file mode 100644 index 00000000..0a03497b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/realize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/reject-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/reject-c.ri new file mode 100644 index 00000000..2e944b19 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/reject-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/rescue-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/rescue-i.ri new file mode 100644 index 00000000..dd67f8e1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/rescue-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set-i.ri new file mode 100644 index 00000000..d2765e15 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_pending-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_pending-i.ri new file mode 100644 index 00000000..5a0eba38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_pending-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_state%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_state%21-i.ri new file mode 100644 index 00000000..e212f437 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/set_state%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/synchronized_set_state%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/synchronized_set_state%21-i.ri new file mode 100644 index 00000000..0e6345ea Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/synchronized_set_state%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/then-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/then-i.ri new file mode 100644 index 00000000..ae2c334b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/then-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-c.ri new file mode 100644 index 00000000..aff97039 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-i.ri new file mode 100644 index 00000000..95ad8f95 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promise/zip-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractAnyPromise/cdesc-AbstractAnyPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractAnyPromise/cdesc-AbstractAnyPromise.ri new file mode 100644 index 00000000..c2bfe28f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractAnyPromise/cdesc-AbstractAnyPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback-i.ri new file mode 100644 index 00000000..c5d36135 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_clear_delayed_node-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_clear_delayed_node-i.ri new file mode 100644 index 00000000..10b2d3fb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_clear_delayed_node-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_notify_blocked-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_notify_blocked-i.ri new file mode 100644 index 00000000..5e36463a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/add_callback_notify_blocked-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/async_callback_on_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/async_callback_on_resolution-i.ri new file mode 100644 index 00000000..3bbf27fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/async_callback_on_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/blocks-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/blocks-i.ri new file mode 100644 index 00000000..455d2ef8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/blocks-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callback-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callback-i.ri new file mode 100644 index 00000000..c5588897 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callback-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callbacks-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callbacks-i.ri new file mode 100644 index 00000000..bf66aff4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/call_callbacks-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_clear_delayed_node-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_clear_delayed_node-i.ri new file mode 100644 index 00000000..36c9c7fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_clear_delayed_node-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_notify_blocked-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_notify_blocked-i.ri new file mode 100644 index 00000000..fd8d2bd8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callback_notify_blocked-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callbacks-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callbacks-i.ri new file mode 100644 index 00000000..3ce8eb7f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/callbacks-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/cdesc-AbstractEventFuture.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/cdesc-AbstractEventFuture.ri new file mode 100644 index 00000000..9d6d194b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/cdesc-AbstractEventFuture.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain-i.ri new file mode 100644 index 00000000..eaf0e93f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_on-i.ri new file mode 100644 index 00000000..b2276009 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_resolvable-i.ri new file mode 100644 index 00000000..6d56a26c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/chain_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/default_executor-i.ri new file mode 100644 index 00000000..509ffaa6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/inspect-i.ri new file mode 100644 index 00000000..a8b4e89e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/new-c.ri new file mode 100644 index 00000000..69e93b9e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution%21-i.ri new file mode 100644 index 00000000..3ef474ec Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution-i.ri new file mode 100644 index 00000000..bc0699ed Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution_using-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution_using-i.ri new file mode 100644 index 00000000..31be0993 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/on_resolution_using-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/pending%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/pending%3f-i.ri new file mode 100644 index 00000000..92034e2b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/pending%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/promise-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/promise-i.ri new file mode 100644 index 00000000..08eac4fc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/promise-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolve_with-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolve_with-i.ri new file mode 100644 index 00000000..ef4c03b4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolve_with-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolved%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolved%3f-i.ri new file mode 100644 index 00000000..63075f40 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/resolved%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/state-i.ri new file mode 100644 index 00000000..29753db0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/tangle-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/tangle-i.ri new file mode 100644 index 00000000..12b5b162 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/tangle-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/to_s-i.ri new file mode 100644 index 00000000..bf1446f5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touch-i.ri new file mode 100644 index 00000000..d6e344a9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touched%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touched%3f-i.ri new file mode 100644 index 00000000..b5962568 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/touched%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait-i.ri new file mode 100644 index 00000000..dd2c4a1f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait_until_resolved-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait_until_resolved-i.ri new file mode 100644 index 00000000..b3808c0e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/wait_until_resolved-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/waiting_threads-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/waiting_threads-i.ri new file mode 100644 index 00000000..8a95a766 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/waiting_threads-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_async-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_async-i.ri new file mode 100644 index 00000000..7279d961 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_async-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_default_executor-i.ri new file mode 100644 index 00000000..47c70ebd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_hidden_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_hidden_resolvable-i.ri new file mode 100644 index 00000000..118b6fb8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractEventFuture/with_hidden_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/add_delayed_of-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/add_delayed_of-i.ri new file mode 100644 index 00000000..5800a467 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/add_delayed_of-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/cdesc-AbstractFlatPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/cdesc-AbstractFlatPromise.ri new file mode 100644 index 00000000..2f7ad84f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/cdesc-AbstractFlatPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/new-c.ri new file mode 100644 index 00000000..8eecbe92 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/on_resolvable-i.ri new file mode 100644 index 00000000..6c6a945e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/resolvable%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/resolvable%3f-i.ri new file mode 100644 index 00000000..f5fba4a0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/resolvable%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touch-i.ri new file mode 100644 index 00000000..f4859baa Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touched%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touched%3f-i.ri new file mode 100644 index 00000000..4c28e8c4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractFlatPromise/touched%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/cdesc-AbstractPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/cdesc-AbstractPromise.ri new file mode 100644 index 00000000..3c721330 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/cdesc-AbstractPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/default_executor-i.ri new file mode 100644 index 00000000..878b6eb1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/delayed_because-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/delayed_because-i.ri new file mode 100644 index 00000000..0a67a857 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/delayed_because-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/evaluate_to-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/evaluate_to-i.ri new file mode 100644 index 00000000..d7be0a91 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/evaluate_to-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/event-i.ri new file mode 100644 index 00000000..1955ccb7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/future-i.ri new file mode 100644 index 00000000..3e0ff8e2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/inspect-i.ri new file mode 100644 index 00000000..f8dfb875 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/new-c.ri new file mode 100644 index 00000000..b17a5e1f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/resolve_with-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/resolve_with-i.ri new file mode 100644 index 00000000..28a19d16 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/resolve_with-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/state-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/state-i.ri new file mode 100644 index 00000000..cd2792f1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/state-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/to_s-i.ri new file mode 100644 index 00000000..9ca5edd1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/touch-i.ri new file mode 100644 index 00000000..452e11ff Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AbstractPromise/touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/cdesc-AnyFulfilledFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/cdesc-AnyFulfilledFuturePromise.ri new file mode 100644 index 00000000..e03741ef Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/cdesc-AnyFulfilledFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/resolvable%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/resolvable%3f-i.ri new file mode 100644 index 00000000..2139884a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyFulfilledFuturePromise/resolvable%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/cdesc-AnyResolvedEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/cdesc-AnyResolvedEventPromise.ri new file mode 100644 index 00000000..32900875 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/cdesc-AnyResolvedEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/new-c.ri new file mode 100644 index 00000000..ea4f530e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/on_resolvable-i.ri new file mode 100644 index 00000000..a9dc7834 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/resolvable%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/resolvable%3f-i.ri new file mode 100644 index 00000000..6d0ac1c2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedEventPromise/resolvable%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/cdesc-AnyResolvedFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/cdesc-AnyResolvedFuturePromise.ri new file mode 100644 index 00000000..56057015 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/cdesc-AnyResolvedFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/new-c.ri new file mode 100644 index 00000000..583aa3c7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/on_resolvable-i.ri new file mode 100644 index 00000000..e708f6d0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/resolvable%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/resolvable%3f-i.ri new file mode 100644 index 00000000..b51e3881 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/AnyResolvedFuturePromise/resolvable%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/add_delayed-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/add_delayed-c.ri new file mode 100644 index 00000000..69f6d4ef Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/add_delayed-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/blocked_by-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/blocked_by-i.ri new file mode 100644 index 00000000..0eb03eb8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/blocked_by-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/cdesc-BlockedPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/cdesc-BlockedPromise.ri new file mode 100644 index 00000000..12d0435c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/cdesc-BlockedPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/clear_and_propagate_touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/clear_and_propagate_touch-i.ri new file mode 100644 index 00000000..984db7d9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/clear_and_propagate_touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/delayed_because-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/delayed_because-i.ri new file mode 100644 index 00000000..a16f0dee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/delayed_because-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new-c.ri new file mode 100644 index 00000000..b510e6ca Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by-c.ri new file mode 100644 index 00000000..50db8b86 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by1-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by1-c.ri new file mode 100644 index 00000000..22bb0853 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by1-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by2-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by2-c.ri new file mode 100644 index 00000000..53a5eb18 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/new_blocked_by2-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_blocker_resolution-i.ri new file mode 100644 index 00000000..a3d012cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_resolvable-i.ri new file mode 100644 index 00000000..456abc84 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..3a4a5da4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/resolvable%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/resolvable%3f-i.ri new file mode 100644 index 00000000..1708445b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/resolvable%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/touch-i.ri new file mode 100644 index 00000000..430c6514 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedPromise/touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/cdesc-BlockedTaskPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/cdesc-BlockedTaskPromise.ri new file mode 100644 index 00000000..2c0f28a5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/cdesc-BlockedTaskPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/executor-i.ri new file mode 100644 index 00000000..2e0011d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/new-c.ri new file mode 100644 index 00000000..7ba38c43 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/BlockedTaskPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/cdesc-ChainPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/cdesc-ChainPromise.ri new file mode 100644 index 00000000..bbeb1122 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/cdesc-ChainPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/on_resolvable-i.ri new file mode 100644 index 00000000..ee26be49 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ChainPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/cdesc-DelayPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/cdesc-DelayPromise.ri new file mode 100644 index 00000000..a744b9e0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/cdesc-DelayPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/delayed_because-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/delayed_because-i.ri new file mode 100644 index 00000000..67c37617 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/delayed_because-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/new-c.ri new file mode 100644 index 00000000..91fad184 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/touch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/touch-i.ri new file mode 100644 index 00000000..fdea4d94 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/DelayPromise/touch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%26-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%26-i.ri new file mode 100644 index 00000000..b6c7dbb0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%26-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%7c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%7c-i.ri new file mode 100644 index 00000000..0e675b1d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/%7c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/any-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/any-i.ri new file mode 100644 index 00000000..cac9e9a0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/any-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/callback_on_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/callback_on_resolution-i.ri new file mode 100644 index 00000000..2d7f925f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/callback_on_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/cdesc-Event.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/cdesc-Event.ri new file mode 100644 index 00000000..d1c9782c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/cdesc-Event.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/delay-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/delay-i.ri new file mode 100644 index 00000000..0b6998d9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/delay-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/rejected_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/rejected_resolution-i.ri new file mode 100644 index 00000000..8e9e5771 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/rejected_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/schedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/schedule-i.ri new file mode 100644 index 00000000..e699bead Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/schedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_event-i.ri new file mode 100644 index 00000000..b0e49c96 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_future-i.ri new file mode 100644 index 00000000..5fdd06f8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/to_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/with_default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/with_default_executor-i.ri new file mode 100644 index 00000000..1f49a055 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/with_default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/zip-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/zip-i.ri new file mode 100644 index 00000000..42e39ff4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Event/zip-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/cdesc-EventWrapperPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/cdesc-EventWrapperPromise.ri new file mode 100644 index 00000000..d4b101f2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/cdesc-EventWrapperPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/new-c.ri new file mode 100644 index 00000000..3ce21eda Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/on_resolvable-i.ri new file mode 100644 index 00000000..18ab67fb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/EventWrapperPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/cdesc-Configuration.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/cdesc-Configuration.ri new file mode 100644 index 00000000..1c745d8a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/cdesc-Configuration.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/default_executor-i.ri new file mode 100644 index 00000000..86ee7d92 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/Configuration/default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any-i.ri new file mode 100644 index 00000000..c4575e34 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event-i.ri new file mode 100644 index 00000000..77a5acbd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event_on-i.ri new file mode 100644 index 00000000..fc85c555 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_event_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future-i.ri new file mode 100644 index 00000000..9dd6118a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future_on-i.ri new file mode 100644 index 00000000..bf01f122 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_fulfilled_future_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future-i.ri new file mode 100644 index 00000000..c39930c6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future_on-i.ri new file mode 100644 index 00000000..89faf897 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/any_resolved_future_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/cdesc-FactoryMethods.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/cdesc-FactoryMethods.ri new file mode 100644 index 00000000..99aed007 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/cdesc-FactoryMethods.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay-i.ri new file mode 100644 index 00000000..18320450 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay_on-i.ri new file mode 100644 index 00000000..af693815 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/delay_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/fulfilled_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/fulfilled_future-i.ri new file mode 100644 index 00000000..94a3f68e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/fulfilled_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future-i.ri new file mode 100644 index 00000000..1fff0ec0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future_on-i.ri new file mode 100644 index 00000000..456084b3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/future_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/make_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/make_future-i.ri new file mode 100644 index 00000000..eff9e189 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/make_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/rejected_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/rejected_future-i.ri new file mode 100644 index 00000000..eecd9849 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/rejected_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event-i.ri new file mode 100644 index 00000000..3a09fdf7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event_on-i.ri new file mode 100644 index 00000000..757076cf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_event_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future-i.ri new file mode 100644 index 00000000..e41181cf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future_on-i.ri new file mode 100644 index 00000000..012e9032 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolvable_future_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_event-i.ri new file mode 100644 index 00000000..2624f5ea Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_future-i.ri new file mode 100644 index 00000000..859faed2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/resolved_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule-i.ri new file mode 100644 index 00000000..ed6915ab Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule_on-i.ri new file mode 100644 index 00000000..1e032bb4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/schedule_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip-i.ri new file mode 100644 index 00000000..dbccc314 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events-i.ri new file mode 100644 index 00000000..2a795e6b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events_on-i.ri new file mode 100644 index 00000000..5021242e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_events_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures-i.ri new file mode 100644 index 00000000..5f5de68b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures_on-i.ri new file mode 100644 index 00000000..63706556 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FactoryMethods/zip_futures_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/cdesc-FlatEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/cdesc-FlatEventPromise.ri new file mode 100644 index 00000000..6c89f6ad Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/cdesc-FlatEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/new-c.ri new file mode 100644 index 00000000..3bdc2350 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..4d91e50a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatEventPromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/cdesc-FlatFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/cdesc-FlatFuturePromise.ri new file mode 100644 index 00000000..4f53e09c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/cdesc-FlatFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/new-c.ri new file mode 100644 index 00000000..437b6076 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..e4e5c2a9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FlatFuturePromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%26-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%26-i.ri new file mode 100644 index 00000000..4420c826 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%26-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%7c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%7c-i.ri new file mode 100644 index 00000000..e3f060f4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/%7c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/any-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/any-i.ri new file mode 100644 index 00000000..ad34e672 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/any-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/apply-i.ri new file mode 100644 index 00000000..b1a51120 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_fulfillment-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_fulfillment-i.ri new file mode 100644 index 00000000..739502f3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_fulfillment-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_rejection-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_rejection-i.ri new file mode 100644 index 00000000..326974d6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/async_callback_on_rejection-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_fulfillment-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_fulfillment-i.ri new file mode 100644 index 00000000..f1fe9787 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_fulfillment-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_rejection-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_rejection-i.ri new file mode 100644 index 00000000..30197f44 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_rejection-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_resolution-i.ri new file mode 100644 index 00000000..232733c0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/callback_on_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/cdesc-Future.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/cdesc-Future.ri new file mode 100644 index 00000000..9f8f2d38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/cdesc-Future.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/delay-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/delay-i.ri new file mode 100644 index 00000000..00588993 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/delay-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/exception-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/exception-i.ri new file mode 100644 index 00000000..34227168 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/exception-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat-i.ri new file mode 100644 index 00000000..848e60be Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_event-i.ri new file mode 100644 index 00000000..df38196e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_future-i.ri new file mode 100644 index 00000000..9e372bf6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/flat_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/fulfilled%3f-i.ri new file mode 100644 index 00000000..c24c7e48 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/inspect-i.ri new file mode 100644 index 00000000..240bc076 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment%21-i.ri new file mode 100644 index 00000000..63f700dd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment-i.ri new file mode 100644 index 00000000..3927ee57 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment_using-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment_using-i.ri new file mode 100644 index 00000000..0fc2b44a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_fulfillment_using-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection%21-i.ri new file mode 100644 index 00000000..0a955fbe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection-i.ri new file mode 100644 index 00000000..cee73c99 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection_using-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection_using-i.ri new file mode 100644 index 00000000..14284495 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/on_rejection_using-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/reason-i.ri new file mode 100644 index 00000000..b9daba7d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected%3f-i.ri new file mode 100644 index 00000000..81587155 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected_resolution-i.ri new file mode 100644 index 00000000..eb28d056 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rejected_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue-i.ri new file mode 100644 index 00000000..8983d8bb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue_on-i.ri new file mode 100644 index 00000000..12f2c5e8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/rescue_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/result-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/result-i.ri new file mode 100644 index 00000000..614b1f95 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/result-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run-i.ri new file mode 100644 index 00000000..2ccedba3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run_test-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run_test-i.ri new file mode 100644 index 00000000..e08c6b81 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/run_test-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/schedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/schedule-i.ri new file mode 100644 index 00000000..290934f2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/schedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then-i.ri new file mode 100644 index 00000000..ca4b801d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then_on-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then_on-i.ri new file mode 100644 index 00000000..e33c3c19 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/then_on-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_event-i.ri new file mode 100644 index 00000000..248786cf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_future-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_future-i.ri new file mode 100644 index 00000000..8b7b438e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_future-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_s-i.ri new file mode 100644 index 00000000..560cc55d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value%21-i.ri new file mode 100644 index 00000000..92f2b0a8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value-i.ri new file mode 100644 index 00000000..5edbc966 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait%21-i.ri new file mode 100644 index 00000000..73595337 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait_until_resolved%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait_until_resolved%21-i.ri new file mode 100644 index 00000000..cd0e3dc7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/wait_until_resolved%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/with_default_executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/with_default_executor-i.ri new file mode 100644 index 00000000..4ade100a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/with_default_executor-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/zip-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/zip-i.ri new file mode 100644 index 00000000..5ec4c36e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Future/zip-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/cdesc-FutureWrapperPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/cdesc-FutureWrapperPromise.ri new file mode 100644 index 00000000..03899d10 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/cdesc-FutureWrapperPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/new-c.ri new file mode 100644 index 00000000..e49a79f0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/on_resolvable-i.ri new file mode 100644 index 00000000..de9f9576 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/FutureWrapperPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/cdesc-ImmediateEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/cdesc-ImmediateEventPromise.ri new file mode 100644 index 00000000..a9a92d29 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/cdesc-ImmediateEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/new-c.ri new file mode 100644 index 00000000..f8b12cdc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/cdesc-ImmediateFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/cdesc-ImmediateFuturePromise.ri new file mode 100644 index 00000000..9d7db651 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/cdesc-ImmediateFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/new-c.ri new file mode 100644 index 00000000..5ddd34d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ImmediateFuturePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InnerPromise/cdesc-InnerPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InnerPromise/cdesc-InnerPromise.ri new file mode 100644 index 00000000..8cc92f67 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InnerPromise/cdesc-InnerPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/apply-i.ri new file mode 100644 index 00000000..53148170 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/cdesc-Fulfilled.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/cdesc-Fulfilled.ri new file mode 100644 index 00000000..c8212b16 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/cdesc-Fulfilled.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/fulfilled%3f-i.ri new file mode 100644 index 00000000..23ae0d65 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/new-c.ri new file mode 100644 index 00000000..be76846d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/reason-i.ri new file mode 100644 index 00000000..54ed1c1e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/to_sym-i.ri new file mode 100644 index 00000000..9bc5843e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/value-i.ri new file mode 100644 index 00000000..3187ea6d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Fulfilled/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/apply-i.ri new file mode 100644 index 00000000..e3f119df Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/cdesc-FulfilledArray.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/cdesc-FulfilledArray.ri new file mode 100644 index 00000000..396682a1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/FulfilledArray/cdesc-FulfilledArray.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/apply-i.ri new file mode 100644 index 00000000..52421d61 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/cdesc-PartiallyRejected.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/cdesc-PartiallyRejected.ri new file mode 100644 index 00000000..21b1a8f8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/cdesc-PartiallyRejected.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/fulfilled%3f-i.ri new file mode 100644 index 00000000..fac9dfc6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/new-c.ri new file mode 100644 index 00000000..dff7fd99 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/reason-i.ri new file mode 100644 index 00000000..f0cdec80 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/to_sym-i.ri new file mode 100644 index 00000000..864b8bdc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/value-i.ri new file mode 100644 index 00000000..bb1a2507 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/PartiallyRejected/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/cdesc-Pending.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/cdesc-Pending.ri new file mode 100644 index 00000000..490820d4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/cdesc-Pending.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/resolved%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/resolved%3f-i.ri new file mode 100644 index 00000000..16533112 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/resolved%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/to_sym-i.ri new file mode 100644 index 00000000..3f0c4041 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Pending/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/apply-i.ri new file mode 100644 index 00000000..4f8923af Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/cdesc-Rejected.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/cdesc-Rejected.ri new file mode 100644 index 00000000..e3296b0e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/cdesc-Rejected.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/fulfilled%3f-i.ri new file mode 100644 index 00000000..a875e106 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/new-c.ri new file mode 100644 index 00000000..7939032d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/reason-i.ri new file mode 100644 index 00000000..ba29925d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/to_sym-i.ri new file mode 100644 index 00000000..75eb083d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/value-i.ri new file mode 100644 index 00000000..548a0469 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Rejected/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Reserved/cdesc-Reserved.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Reserved/cdesc-Reserved.ri new file mode 100644 index 00000000..038713cc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/Reserved/cdesc-Reserved.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/apply-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/apply-i.ri new file mode 100644 index 00000000..c2a120fb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/apply-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/cdesc-ResolvedWithResult.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/cdesc-ResolvedWithResult.ri new file mode 100644 index 00000000..7cc87960 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/cdesc-ResolvedWithResult.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/fulfilled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/fulfilled%3f-i.ri new file mode 100644 index 00000000..01aa1f2b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/fulfilled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/reason-i.ri new file mode 100644 index 00000000..884a9d0d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/resolved%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/resolved%3f-i.ri new file mode 100644 index 00000000..7e40f279 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/resolved%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/result-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/result-i.ri new file mode 100644 index 00000000..af245857 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/result-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/to_sym-i.ri new file mode 100644 index 00000000..2e1b0d57 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/value-i.ri new file mode 100644 index 00000000..f8339393 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/ResolvedWithResult/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/cdesc-State.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/cdesc-State.ri new file mode 100644 index 00000000..8827254c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/cdesc-State.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/resolved%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/resolved%3f-i.ri new file mode 100644 index 00000000..3a3c9099 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/resolved%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/to_sym-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/to_sym-i.ri new file mode 100644 index 00000000..8ecb4551 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/State/to_sym-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/cdesc-InternalStates.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/cdesc-InternalStates.ri new file mode 100644 index 00000000..5e215db4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/InternalStates/cdesc-InternalStates.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/cdesc-RescuePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/cdesc-RescuePromise.ri new file mode 100644 index 00000000..1e587e72 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/cdesc-RescuePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/new-c.ri new file mode 100644 index 00000000..d836beca Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/on_resolvable-i.ri new file mode 100644 index 00000000..5da8290f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RescuePromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Resolvable/cdesc-Resolvable.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Resolvable/cdesc-Resolvable.ri new file mode 100644 index 00000000..3b9b7065 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/Resolvable/cdesc-Resolvable.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/cdesc-ResolvableEvent.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/cdesc-ResolvableEvent.ri new file mode 100644 index 00000000..c7e623bd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/cdesc-ResolvableEvent.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/resolve-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/resolve-i.ri new file mode 100644 index 00000000..8ae27765 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/resolve-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/wait-i.ri new file mode 100644 index 00000000..16e4d3b0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/with_hidden_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/with_hidden_resolvable-i.ri new file mode 100644 index 00000000..3e411124 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEvent/with_hidden_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/cdesc-ResolvableEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/cdesc-ResolvableEventPromise.ri new file mode 100644 index 00000000..95ad740b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/cdesc-ResolvableEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/new-c.ri new file mode 100644 index 00000000..64258fa5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/cdesc-ResolvableFuture.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/cdesc-ResolvableFuture.ri new file mode 100644 index 00000000..7315b2ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/cdesc-ResolvableFuture.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to%21-i.ri new file mode 100644 index 00000000..d7f41b60 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to-i.ri new file mode 100644 index 00000000..f28e75fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/evaluate_to-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/fulfill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/fulfill-i.ri new file mode 100644 index 00000000..990961f3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/fulfill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reason-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reason-i.ri new file mode 100644 index 00000000..1b0368b9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reason-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reject-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reject-i.ri new file mode 100644 index 00000000..fcad611d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/reject-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/resolve-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/resolve-i.ri new file mode 100644 index 00000000..e8ef646d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/resolve-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/result-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/result-i.ri new file mode 100644 index 00000000..3116d65c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/result-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value%21-i.ri new file mode 100644 index 00000000..74051898 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value-i.ri new file mode 100644 index 00000000..c9bc96f9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait%21-i.ri new file mode 100644 index 00000000..30a85590 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait-i.ri new file mode 100644 index 00000000..8ca4e83c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/with_hidden_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/with_hidden_resolvable-i.ri new file mode 100644 index 00000000..1726e4c3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuture/with_hidden_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/cdesc-ResolvableFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/cdesc-ResolvableFuturePromise.ri new file mode 100644 index 00000000..6b677ea3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/cdesc-ResolvableFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/new-c.ri new file mode 100644 index 00000000..21a838d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ResolvableFuturePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/cdesc-RunFuturePromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/cdesc-RunFuturePromise.ri new file mode 100644 index 00000000..692c85eb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/cdesc-RunFuturePromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/new-c.ri new file mode 100644 index 00000000..3d705f35 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..3547dd72 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/RunFuturePromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/cdesc-ScheduledPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/cdesc-ScheduledPromise.ri new file mode 100644 index 00000000..948d962f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/cdesc-ScheduledPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/inspect-i.ri new file mode 100644 index 00000000..8934a284 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/intended_time-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/intended_time-i.ri new file mode 100644 index 00000000..fc67a22a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/intended_time-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/new-c.ri new file mode 100644 index 00000000..e0641990 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ScheduledPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/cdesc-ThenPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/cdesc-ThenPromise.ri new file mode 100644 index 00000000..7cfe0797 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/cdesc-ThenPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/new-c.ri new file mode 100644 index 00000000..0b4ae842 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/on_resolvable-i.ri new file mode 100644 index 00000000..4516ad1f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ThenPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/cdesc-ZipEventEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/cdesc-ZipEventEventPromise.ri new file mode 100644 index 00000000..4ea0de1f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/cdesc-ZipEventEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/new-c.ri new file mode 100644 index 00000000..8bbed38a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/on_resolvable-i.ri new file mode 100644 index 00000000..0e5f7cdd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventEventPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/cdesc-ZipEventsPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/cdesc-ZipEventsPromise.ri new file mode 100644 index 00000000..a912dd34 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/cdesc-ZipEventsPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/new-c.ri new file mode 100644 index 00000000..7a62e178 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/on_resolvable-i.ri new file mode 100644 index 00000000..cda61d2e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipEventsPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/cdesc-ZipFutureEventPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/cdesc-ZipFutureEventPromise.ri new file mode 100644 index 00000000..f6f2f7f7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/cdesc-ZipFutureEventPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/new-c.ri new file mode 100644 index 00000000..d9a81838 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/on_resolvable-i.ri new file mode 100644 index 00000000..d71f4b05 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..339855d9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFutureEventPromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/cdesc-ZipFuturesPromise.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/cdesc-ZipFuturesPromise.ri new file mode 100644 index 00000000..826f8b8f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/cdesc-ZipFuturesPromise.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/new-c.ri new file mode 100644 index 00000000..eb05f675 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/on_resolvable-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/on_resolvable-i.ri new file mode 100644 index 00000000..ba316d52 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/on_resolvable-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/process_on_blocker_resolution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/process_on_blocker_resolution-i.ri new file mode 100644 index 00000000..f089c795 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/ZipFuturesPromise/process_on_blocker_resolution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/cdesc-Promises.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/cdesc-Promises.ri new file mode 100644 index 00000000..1a92cfce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Promises/cdesc-Promises.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/cdesc-ReInclude.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/cdesc-ReInclude.ri new file mode 100644 index 00000000..f3184637 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/cdesc-ReInclude.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/extended-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/extended-i.ri new file mode 100644 index 00000000..04b48442 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/extended-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/include-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/include-i.ri new file mode 100644 index 00000000..c77a6f3a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/include-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/included-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/included-i.ri new file mode 100644 index 00000000..c10743b2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReInclude/included-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_read_lock-i.ri new file mode 100644 index 00000000..21cc35c4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_write_lock-i.ri new file mode 100644 index 00000000..6f7b4085 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/acquire_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/cdesc-ReadWriteLock.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/cdesc-ReadWriteLock.ri new file mode 100644 index 00000000..06c92697 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/cdesc-ReadWriteLock.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/has_waiters%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/has_waiters%3f-i.ri new file mode 100644 index 00000000..47942919 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/has_waiters%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_readers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_readers%3f-i.ri new file mode 100644 index 00000000..f5f208db Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_readers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_writers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_writers%3f-i.ri new file mode 100644 index 00000000..0f4ba15a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/max_writers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/new-c.ri new file mode 100644 index 00000000..1b03eebe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_read_lock-i.ri new file mode 100644 index 00000000..ac9d0e27 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_write_lock-i.ri new file mode 100644 index 00000000..397c0e78 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/release_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers%3f-i.ri new file mode 100644 index 00000000..5014e5b5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers-i.ri new file mode 100644 index 00000000..9f22a2dd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_readers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_writer%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_writer%3f-i.ri new file mode 100644 index 00000000..f91a93df Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/running_writer%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writer%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writer%3f-i.ri new file mode 100644 index 00000000..703a77d5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writer%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writers-i.ri new file mode 100644 index 00000000..d6f8ec39 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/waiting_writers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_read_lock-i.ri new file mode 100644 index 00000000..4dd3089e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_write_lock-i.ri new file mode 100644 index 00000000..b07ed8c0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/with_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/write_locked%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/write_locked%3f-i.ri new file mode 100644 index 00000000..923dd935 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReadWriteLock/write_locked%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_read_lock-i.ri new file mode 100644 index 00000000..15533406 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_write_lock-i.ri new file mode 100644 index 00000000..ac6c66ad Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/acquire_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/cdesc-ReentrantReadWriteLock.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/cdesc-ReentrantReadWriteLock.ri new file mode 100644 index 00000000..0ea2f40d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/cdesc-ReentrantReadWriteLock.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_readers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_readers%3f-i.ri new file mode 100644 index 00000000..e8bcdbe9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_readers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_writers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_writers%3f-i.ri new file mode 100644 index 00000000..a1caa1bc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/max_writers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/new-c.ri new file mode 100644 index 00000000..4e106685 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_read_lock-i.ri new file mode 100644 index 00000000..59c7808d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_write_lock-i.ri new file mode 100644 index 00000000..de58aa0e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/release_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers%3f-i.ri new file mode 100644 index 00000000..a2a35f3e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers-i.ri new file mode 100644 index 00000000..874918d0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_readers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_writer%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_writer%3f-i.ri new file mode 100644 index 00000000..72d75047 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/running_writer%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_read_lock-i.ri new file mode 100644 index 00000000..7b47e13a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_write_lock-i.ri new file mode 100644 index 00000000..9af7f367 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/try_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_or_running_writer%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_or_running_writer%3f-i.ri new file mode 100644 index 00000000..dc1052e2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_or_running_writer%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_writers-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_writers-i.ri new file mode 100644 index 00000000..f112031f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/waiting_writers-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_read_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_read_lock-i.ri new file mode 100644 index 00000000..ad972d3b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_read_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_write_lock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_write_lock-i.ri new file mode 100644 index 00000000..f53fa7a6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ReentrantReadWriteLock/with_write_lock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/cdesc-Node.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/cdesc-Node.ri new file mode 100644 index 00000000..d42b23be Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/cdesc-Node.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/item-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/item-i.ri new file mode 100644 index 00000000..e2f550e8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/item-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/latch-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/latch-i.ri new file mode 100644 index 00000000..c4918ba8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/latch-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/new-c.ri new file mode 100644 index 00000000..f7a7330a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/Node/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/cdesc-RubyExchanger.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/cdesc-RubyExchanger.ri new file mode 100644 index 00000000..19b47860 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/cdesc-RubyExchanger.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/do_exchange-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/do_exchange-i.ri new file mode 100644 index 00000000..31f875b8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/do_exchange-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/new-c.ri new file mode 100644 index 00000000..6017edbd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExchanger/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/cdesc-RubyExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/cdesc-RubyExecutorService.ri new file mode 100644 index 00000000..808d3951 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/cdesc-RubyExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/kill-i.ri new file mode 100644 index 00000000..ccfcc04d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/new-c.ri new file mode 100644 index 00000000..1b5cf668 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_running%3f-i.ri new file mode 100644 index 00000000..3f7715df Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown%3f-i.ri new file mode 100644 index 00000000..185bddad Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown_execution-i.ri new file mode 100644 index 00000000..66e827c6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shutdown_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shuttingdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shuttingdown%3f-i.ri new file mode 100644 index 00000000..c6113dcc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/ns_shuttingdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/post-i.ri new file mode 100644 index 00000000..27adc001 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/shutdown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/shutdown-i.ri new file mode 100644 index 00000000..6b1406e3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/shutdown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stop_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stop_event-i.ri new file mode 100644 index 00000000..ee204e24 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stop_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stopped_event-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stopped_event-i.ri new file mode 100644 index 00000000..18be30d7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/stopped_event-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/wait_for_termination-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/wait_for_termination-i.ri new file mode 100644 index 00000000..1bcf5b94 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyExecutorService/wait_for_termination-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/cdesc-RubySingleThreadExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/cdesc-RubySingleThreadExecutor.ri new file mode 100644 index 00000000..bb18ed75 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/cdesc-RubySingleThreadExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/new-c.ri new file mode 100644 index 00000000..391ef4e0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubySingleThreadExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/%3c%3c-i.ri new file mode 100644 index 00000000..c662688f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/cdesc-Worker.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/cdesc-Worker.ri new file mode 100644 index 00000000..9d358ed7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/cdesc-Worker.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/create_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/create_worker-i.ri new file mode 100644 index 00000000..8db076cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/create_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/kill-i.ri new file mode 100644 index 00000000..803c02c5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/new-c.ri new file mode 100644 index 00000000..1ba9e40b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/run_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/run_task-i.ri new file mode 100644 index 00000000..4b946f2d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/run_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/stop-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/stop-i.ri new file mode 100644 index 00000000..b1a95380 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/Worker/stop-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/active_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/active_count-i.ri new file mode 100644 index 00000000..2c271958 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/active_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/can_overflow%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/can_overflow%3f-i.ri new file mode 100644 index 00000000..b48ede39 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/can_overflow%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/cdesc-RubyThreadPoolExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/cdesc-RubyThreadPoolExecutor.ri new file mode 100644 index 00000000..b4cc5807 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/cdesc-RubyThreadPoolExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/completed_task_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/completed_task_count-i.ri new file mode 100644 index 00000000..b37530e9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/completed_task_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/idletime-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/idletime-i.ri new file mode 100644 index 00000000..10251964 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/idletime-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" idletime:ETI"0Concurrent::RubyThreadPoolExecutor#idletime;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"6@!macro thread_pool_executor_attr_reader_idletime;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::RubyThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/largest_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/largest_length-i.ri new file mode 100644 index 00000000..4835afb5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/largest_length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/length-i.ri new file mode 100644 index 00000000..c0777fe2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_length-i.ri new file mode 100644 index 00000000..10e6b85b --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_length-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"max_length:ETI"2Concurrent::RubyThreadPoolExecutor#max_length;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"8@!macro thread_pool_executor_attr_reader_max_length;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::RubyThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_queue-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_queue-i.ri new file mode 100644 index 00000000..6f02c340 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/max_queue-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"max_queue:ETI"1Concurrent::RubyThreadPoolExecutor#max_queue;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"7@!macro thread_pool_executor_attr_reader_max_queue;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::RubyThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/min_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/min_length-i.ri new file mode 100644 index 00000000..b0c9bc1e --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/min_length-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"min_length:ETI"2Concurrent::RubyThreadPoolExecutor#min_length;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"8@!macro thread_pool_executor_attr_reader_min_length;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::RubyThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/new-c.ri new file mode 100644 index 00000000..b0e50cc6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_add_busy_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_add_busy_worker-i.ri new file mode 100644 index 00000000..81d5a8e2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_add_busy_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_assign_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_assign_worker-i.ri new file mode 100644 index 00000000..058d3501 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_assign_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_enqueue-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_enqueue-i.ri new file mode 100644 index 00000000..ab80c4f8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_enqueue-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_execute-i.ri new file mode 100644 index 00000000..4bf13141 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_initialize-i.ri new file mode 100644 index 00000000..1bed7d92 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_kill_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_kill_execution-i.ri new file mode 100644 index 00000000..7789139f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_kill_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_limited_queue%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_limited_queue%3f-i.ri new file mode 100644 index 00000000..e627815a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_limited_queue%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_prunable_capacity-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_prunable_capacity-i.ri new file mode 100644 index 00000000..a8f5d8ff Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_prunable_capacity-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_ready_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_ready_worker-i.ri new file mode 100644 index 00000000..a99c1d4f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_ready_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_busy_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_busy_worker-i.ri new file mode 100644 index 00000000..bc7c6f3f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_busy_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_ready_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_ready_worker-i.ri new file mode 100644 index 00000000..fb67f40e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_remove_ready_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_reset_if_forked-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_reset_if_forked-i.ri new file mode 100644 index 00000000..2db697cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_reset_if_forked-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_shutdown_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_shutdown_execution-i.ri new file mode 100644 index 00000000..eecb74df Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_shutdown_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_worker_died-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_worker_died-i.ri new file mode 100644 index 00000000..88d0db65 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ns_worker_died-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_pool-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_pool-i.ri new file mode 100644 index 00000000..288275f6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_pool-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_worker-i.ri new file mode 100644 index 00000000..9eae406e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/prune_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/queue_length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/queue_length-i.ri new file mode 100644 index 00000000..c3b09577 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/queue_length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ready_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ready_worker-i.ri new file mode 100644 index 00000000..bf8254fc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/ready_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remaining_capacity-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remaining_capacity-i.ri new file mode 100644 index 00000000..ded1cd91 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remaining_capacity-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remove_worker-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remove_worker-i.ri new file mode 100644 index 00000000..5a23400d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/remove_worker-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/scheduled_task_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/scheduled_task_count-i.ri new file mode 100644 index 00000000..0604ed82 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/scheduled_task_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/synchronous-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/synchronous-i.ri new file mode 100644 index 00000000..68e99a43 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/synchronous-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"synchronous:ETI"3Concurrent::RubyThreadPoolExecutor#synchronous;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"9@!macro thread_pool_executor_attr_reader_synchronous;T: +@fileI"Ilib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Concurrent::RubyThreadPoolExecutor;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_died-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_died-i.ri new file mode 100644 index 00000000..25ac8d59 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_died-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_task_completed-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_task_completed-i.ri new file mode 100644 index 00000000..011e0cbb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/RubyThreadPoolExecutor/worker_task_completed-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/cdesc-SafeTaskExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/cdesc-SafeTaskExecutor.ri new file mode 100644 index 00000000..18cf2e39 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/cdesc-SafeTaskExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/execute-i.ri new file mode 100644 index 00000000..d4a1f802 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/new-c.ri new file mode 100644 index 00000000..d16a3c62 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SafeTaskExecutor/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/%3c%3d%3e-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/%3c%3d%3e-i.ri new file mode 100644 index 00000000..621dba28 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/%3c%3d%3e-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancel-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancel-i.ri new file mode 100644 index 00000000..0f8b152e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancel-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancelled%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancelled%3f-i.ri new file mode 100644 index 00000000..001a81a0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cancelled%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cdesc-ScheduledTask.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cdesc-ScheduledTask.ri new file mode 100644 index 00000000..6100fb9c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/cdesc-ScheduledTask.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-c.ri new file mode 100644 index 00000000..f55e9d50 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-i.ri new file mode 100644 index 00000000..9f7cafd1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/executor-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/executor-i.ri new file mode 100644 index 00000000..5939d3a0 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/executor-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" executor:ETI"'Concurrent::ScheduledTask#executor;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"0The executor on which to execute the task. ;TI"@!visibility private;T: +@fileI"5lib/concurrent-ruby/concurrent/scheduled_task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::ScheduledTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/initial_delay-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/initial_delay-i.ri new file mode 100644 index 00000000..92eb24bf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/initial_delay-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/new-c.ri new file mode 100644 index 00000000..5f1d561c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_reschedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_reschedule-i.ri new file mode 100644 index 00000000..52bd3302 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_reschedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_schedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_schedule-i.ri new file mode 100644 index 00000000..1e7431b3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/ns_schedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/process_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/process_task-i.ri new file mode 100644 index 00000000..725f352d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/process_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/processing%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/processing%3f-i.ri new file mode 100644 index 00000000..7793b4f1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/processing%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reschedule-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reschedule-i.ri new file mode 100644 index 00000000..35369d3e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reschedule-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reset-i.ri new file mode 100644 index 00000000..61889ebb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/schedule_time-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/schedule_time-i.ri new file mode 100644 index 00000000..5a703e0e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ScheduledTask/schedule_time-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Semaphore/cdesc-Semaphore.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Semaphore/cdesc-Semaphore.ri new file mode 100644 index 00000000..44c98178 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Semaphore/cdesc-Semaphore.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/cdesc-SerialExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/cdesc-SerialExecutorService.ri new file mode 100644 index 00000000..bf2a4cce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/cdesc-SerialExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/serialized%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/serialized%3f-i.ri new file mode 100644 index 00000000..32adcd5b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerialExecutorService/serialized%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/call_job-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/call_job-i.ri new file mode 100644 index 00000000..2c8e2f7d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/call_job-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/cdesc-SerializedExecution.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/cdesc-SerializedExecution.ri new file mode 100644 index 00000000..bb87407e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/cdesc-SerializedExecution.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/new-c.ri new file mode 100644 index 00000000..234018eb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/ns_initialize-i.ri new file mode 100644 index 00000000..eadb39d0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/post-i.ri new file mode 100644 index 00000000..3324cef0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/posts-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/posts-i.ri new file mode 100644 index 00000000..39ced527 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/posts-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/work-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/work-i.ri new file mode 100644 index 00000000..2cfdc1b5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecution/work-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/cdesc-SerializedExecutionDelegator.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/cdesc-SerializedExecutionDelegator.ri new file mode 100644 index 00000000..7c3d6413 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/cdesc-SerializedExecutionDelegator.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/new-c.ri new file mode 100644 index 00000000..1d4edcd5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/post-i.ri new file mode 100644 index 00000000..94424671 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SerializedExecutionDelegator/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%3d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%3d%3d-i.ri new file mode 100644 index 00000000..f3576623 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%3d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d%3d-i.ri new file mode 100644 index 00000000..546efab8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d-i.ri new file mode 100644 index 00000000..137b564d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/%5b%5d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/cdesc-SettableStruct.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/cdesc-SettableStruct.ri new file mode 100644 index 00000000..a74887ab Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/cdesc-SettableStruct.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each-i.ri new file mode 100644 index 00000000..838483e8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each_pair-i.ri new file mode 100644 index 00000000..87cf78ac Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/initialize_copy-i.ri new file mode 100644 index 00000000..e16a9f01 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/inspect-i.ri new file mode 100644 index 00000000..7f5b596e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/merge-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/merge-i.ri new file mode 100644 index 00000000..bd7006cd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/merge-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/new-c.ri new file mode 100644 index 00000000..db99d85a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/select-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/select-i.ri new file mode 100644 index 00000000..0093774f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/select-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_a-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_a-i.ri new file mode 100644 index 00000000..66ca05c5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_a-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_h-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_h-i.ri new file mode 100644 index 00000000..0863828a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_h-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_s-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_s-i.ri new file mode 100644 index 00000000..3537f611 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/to_s-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values-i.ri new file mode 100644 index 00000000..6407b850 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values_at-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values_at-i.ri new file mode 100644 index 00000000..c9ad273f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SettableStruct/values_at-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-c.ri new file mode 100644 index 00000000..0fdecdd9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-i.ri new file mode 100644 index 00000000..056527dc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/%3c%3c-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/cdesc-SimpleExecutorService.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/cdesc-SimpleExecutorService.ri new file mode 100644 index 00000000..610f86e7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/cdesc-SimpleExecutorService.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/kill-i.ri new file mode 100644 index 00000000..59f97fe5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/ns_initialize-i.ri new file mode 100644 index 00000000..585c126e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-c.ri new file mode 100644 index 00000000..8a51718a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-i.ri new file mode 100644 index 00000000..6507bff7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/running%3f-i.ri new file mode 100644 index 00000000..b1df723a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown%3f-i.ri new file mode 100644 index 00000000..c16825b3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown-i.ri new file mode 100644 index 00000000..f4a051a5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shutdown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shuttingdown%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shuttingdown%3f-i.ri new file mode 100644 index 00000000..338b23d2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/shuttingdown%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/wait_for_termination-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/wait_for_termination-i.ri new file mode 100644 index 00000000..609325ab Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SimpleExecutorService/wait_for_termination-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SingleThreadExecutor/cdesc-SingleThreadExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SingleThreadExecutor/cdesc-SingleThreadExecutor.ri new file mode 100644 index 00000000..af05328f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SingleThreadExecutor/cdesc-SingleThreadExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/cdesc-AbstractLockableObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/cdesc-AbstractLockableObject.ri new file mode 100644 index 00000000..aa0fc8f8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/cdesc-AbstractLockableObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_broadcast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_broadcast-i.ri new file mode 100644 index 00000000..f282b52f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_broadcast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_signal-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_signal-i.ri new file mode 100644 index 00000000..d197cabb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_signal-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait-i.ri new file mode 100644 index 00000000..0dfedef4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait_until-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait_until-i.ri new file mode 100644 index 00000000..405da7a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/ns_wait_until-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/synchronize-i.ri new file mode 100644 index 00000000..61a1b056 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractLockableObject/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/attr_volatile-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/attr_volatile-c.ri new file mode 100644 index 00000000..c62dc323 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/attr_volatile-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/cdesc-AbstractObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/cdesc-AbstractObject.ri new file mode 100644 index 00000000..92bb4923 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/cdesc-AbstractObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/full_memory_barrier-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/full_memory_barrier-i.ri new file mode 100644 index 00000000..f14bfb7b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/full_memory_barrier-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/new-c.ri new file mode 100644 index 00000000..b342e1d3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractObject/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/cdesc-AbstractStruct.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/cdesc-AbstractStruct.ri new file mode 100644 index 00000000..a78a664e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/cdesc-AbstractStruct.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/define_struct_class-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/define_struct_class-c.ri new file mode 100644 index 00000000..c96f47d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/define_struct_class-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/length-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/length-i.ri new file mode 100644 index 00000000..73d3c597 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/length-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/members-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/members-i.ri new file mode 100644 index 00000000..efdf3a98 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/members-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/new-c.ri new file mode 100644 index 00000000..edd852fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each-i.ri new file mode 100644 index 00000000..dd69ca2a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each_pair-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each_pair-i.ri new file mode 100644 index 00000000..e4c7ded9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_each_pair-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_equality-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_equality-i.ri new file mode 100644 index 00000000..dfce1b04 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_equality-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_get-i.ri new file mode 100644 index 00000000..ee2978fd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize-i.ri new file mode 100644 index 00000000..84913d18 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize_copy-i.ri new file mode 100644 index 00000000..d93ac5bb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_inspect-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_inspect-i.ri new file mode 100644 index 00000000..a2a773c2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_inspect-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_merge-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_merge-i.ri new file mode 100644 index 00000000..e1b24ab9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_merge-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_select-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_select-i.ri new file mode 100644 index 00000000..df088b4f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_select-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_to_h-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_to_h-i.ri new file mode 100644 index 00000000..129f3de1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_to_h-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values-i.ri new file mode 100644 index 00000000..186a973c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values_at-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values_at-i.ri new file mode 100644 index 00000000..3819aa9b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/ns_values_at-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/pr_underscore-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/pr_underscore-i.ri new file mode 100644 index 00000000..f92659a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/pr_underscore-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/size-i.ri new file mode 100644 index 00000000..859360a3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/AbstractStruct/size-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/broadcast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/broadcast-i.ri new file mode 100644 index 00000000..297a1a84 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/broadcast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/cdesc-Condition.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/cdesc-Condition.ri new file mode 100644 index 00000000..15e7f2d9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/cdesc-Condition.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/new-c.ri new file mode 100644 index 00000000..5f3b5648 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_broadcast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_broadcast-i.ri new file mode 100644 index 00000000..45ef406f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_broadcast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_signal-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_signal-i.ri new file mode 100644 index 00000000..29e587b4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_signal-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait-i.ri new file mode 100644 index 00000000..f92ba74f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait_until-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait_until-i.ri new file mode 100644 index 00000000..68160b54 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/ns_wait_until-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/signal-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/signal-i.ri new file mode 100644 index 00000000..348d69e7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/signal-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait-i.ri new file mode 100644 index 00000000..bdfc260f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait_until-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait_until-i.ri new file mode 100644 index 00000000..01f31060 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Condition/wait_until-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/cdesc-ConditionSignalling.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/cdesc-ConditionSignalling.ri new file mode 100644 index 00000000..477feeda Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/cdesc-ConditionSignalling.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_broadcast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_broadcast-i.ri new file mode 100644 index 00000000..ca9ac082 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_broadcast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_signal-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_signal-i.ri new file mode 100644 index 00000000..16188820 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/ConditionSignalling/ns_signal-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/JRubyLockableObject/cdesc-JRubyLockableObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/JRubyLockableObject/cdesc-JRubyLockableObject.ri new file mode 100644 index 00000000..3fd068b8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/JRubyLockableObject/cdesc-JRubyLockableObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/broadcast-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/broadcast-i.ri new file mode 100644 index 00000000..014b0a91 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/broadcast-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/cdesc-Lock.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/cdesc-Lock.ri new file mode 100644 index 00000000..e43cbf6a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/cdesc-Lock.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/signal-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/signal-i.ri new file mode 100644 index 00000000..fa3a0990 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/signal-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait-i.ri new file mode 100644 index 00000000..e5d5eac8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait_until-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait_until-i.ri new file mode 100644 index 00000000..e43f13dd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Lock/wait_until-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/cdesc-LockableObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/cdesc-LockableObject.ri new file mode 100644 index 00000000..e4eeb2e0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/cdesc-LockableObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/new_condition-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/new_condition-i.ri new file mode 100644 index 00000000..af51c43b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/LockableObject/new_condition-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/cdesc-MonitorLockableObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/cdesc-MonitorLockableObject.ri new file mode 100644 index 00000000..13f2f767 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/cdesc-MonitorLockableObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/initialize_copy-i.ri new file mode 100644 index 00000000..0dbea712 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/new-c.ri new file mode 100644 index 00000000..b3d43b12 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/ns_wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/ns_wait-i.ri new file mode 100644 index 00000000..90cd4d20 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/ns_wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/synchronize-i.ri new file mode 100644 index 00000000..a30a4097 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MonitorLockableObject/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/cdesc-MutexLockableObject.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/cdesc-MutexLockableObject.ri new file mode 100644 index 00000000..023d2064 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/cdesc-MutexLockableObject.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/initialize_copy-i.ri new file mode 100644 index 00000000..4bbd91a1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/new-c.ri new file mode 100644 index 00000000..9e0d58b1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/ns_wait-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/ns_wait-i.ri new file mode 100644 index 00000000..db3e6419 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/ns_wait-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/synchronize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/synchronize-i.ri new file mode 100644 index 00000000..07d76fd5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/MutexLockableObject/synchronize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/__initialize_atomic_fields__-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/__initialize_atomic_fields__-i.ri new file mode 100644 index 00000000..fa7ef035 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/__initialize_atomic_fields__-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attribute%3f-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attribute%3f-c.ri new file mode 100644 index 00000000..4fe665c1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attribute%3f-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attributes-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attributes-c.ri new file mode 100644 index 00000000..e67e7a6f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/atomic_attributes-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/attr_atomic-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/attr_atomic-c.ri new file mode 100644 index 00000000..04344f29 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/attr_atomic-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/cdesc-Object.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/cdesc-Object.ri new file mode 100644 index 00000000..aa3c7d20 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/cdesc-Object.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/define_initialize_atomic_fields-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/define_initialize_atomic_fields-c.ri new file mode 100644 index 00000000..9417faaf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/define_initialize_atomic_fields-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/ensure_safe_initialization_when_final_fields_are_present-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/ensure_safe_initialization_when_final_fields_are_present-c.ri new file mode 100644 index 00000000..e698bb23 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/ensure_safe_initialization_when_final_fields_are_present-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/new-c.ri new file mode 100644 index 00000000..f3509df3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%21-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%21-c.ri new file mode 100644 index 00000000..7c873797 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%21-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%3f-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%3f-c.ri new file mode 100644 index 00000000..bf49f8f0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Object/safe_initialization%3f-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/cdesc-SafeInitialization.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/cdesc-SafeInitialization.ri new file mode 100644 index 00000000..2b1ba4df Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/cdesc-SafeInitialization.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/new-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/new-i.ri new file mode 100644 index 00000000..346f31dd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/SafeInitialization/new-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/attr_volatile-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/attr_volatile-i.ri new file mode 100644 index 00000000..fed8160e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/attr_volatile-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/cdesc-ClassMethods.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/cdesc-ClassMethods.ri new file mode 100644 index 00000000..3644df38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/ClassMethods/cdesc-ClassMethods.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/cdesc-Volatile.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/cdesc-Volatile.ri new file mode 100644 index 00000000..0a81a21b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/cdesc-Volatile.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/full_memory_barrier-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/full_memory_barrier-i.ri new file mode 100644 index 00000000..5d692cd0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/full_memory_barrier-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/included-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/included-c.ri new file mode 100644 index 00000000..b46481c3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/Volatile/included-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/cdesc-Synchronization.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/cdesc-Synchronization.ri new file mode 100644 index 00000000..75753d7a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/cdesc-Synchronization.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/full_memory_barrier-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/full_memory_barrier-c.ri new file mode 100644 index 00000000..bd55ca8e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Synchronization/full_memory_barrier-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/cdesc-SynchronizedDelegator.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/cdesc-SynchronizedDelegator.ri new file mode 100644 index 00000000..4b9a5390 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/cdesc-SynchronizedDelegator.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/method_missing-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/method_missing-i.ri new file mode 100644 index 00000000..b61a1d9d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/method_missing-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/new-c.ri new file mode 100644 index 00000000..e962de74 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/setup-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/setup-i.ri new file mode 100644 index 00000000..20e1e599 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/setup-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/teardown-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/teardown-i.ri new file mode 100644 index 00000000..1d551d0c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/SynchronizedDelegator/teardown-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/cdesc-TVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/cdesc-TVar.ri new file mode 100644 index 00000000..8809f158 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/cdesc-TVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/new-c.ri new file mode 100644 index 00000000..7a39a817 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value%3d-i.ri new file mode 100644 index 00000000..1ceb625f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value-i.ri new file mode 100644 index 00000000..75605485 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TVar/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/bind-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/bind-i.ri new file mode 100644 index 00000000..6dfe8b25 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/bind-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/cdesc-ThreadLocalVar.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/cdesc-ThreadLocalVar.ri new file mode 100644 index 00000000..c0e0c850 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/cdesc-ThreadLocalVar.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/default-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/default-i.ri new file mode 100644 index 00000000..68ff4863 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/default-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/new-c.ri new file mode 100644 index 00000000..6ad8abf8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value%3d-i.ri new file mode 100644 index 00000000..3d97ef41 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value-i.ri new file mode 100644 index 00000000..a6b46bc7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocalVar/value-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/cdesc-ThreadLocals.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/cdesc-ThreadLocals.ri new file mode 100644 index 00000000..65c6ee02 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/cdesc-ThreadLocals.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals%21-i.ri new file mode 100644 index 00000000..26a2710b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals-i.ri new file mode 100644 index 00000000..de4293a6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadLocals/locals-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadPoolExecutor/cdesc-ThreadPoolExecutor.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadPoolExecutor/cdesc-ThreadPoolExecutor.ri new file mode 100644 index 00000000..a287edac Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadPoolExecutor/cdesc-ThreadPoolExecutor.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/add-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/add-i.ri new file mode 100644 index 00000000..491a18da Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/add-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/cdesc-Adder.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/cdesc-Adder.ri new file mode 100644 index 00000000..81f712c7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/cdesc-Adder.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/decrement-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/decrement-i.ri new file mode 100644 index 00000000..1075998b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/decrement-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/increment-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/increment-i.ri new file mode 100644 index 00000000..d828af5a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/increment-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/reset-i.ri new file mode 100644 index 00000000..a2ce10a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/sum-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/sum-i.ri new file mode 100644 index 00000000..56815a96 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Adder/sum-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri new file mode 100644 index 00000000..e8e4abff Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/cdesc-PowerOfTwoTuple.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri new file mode 100644 index 00000000..b4fc4a30 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/hash_to_index-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/new-c.ri new file mode 100644 index 00000000..4ed61915 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/next_in_size_table-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/next_in_size_table-i.ri new file mode 100644 index 00000000..adea2fba Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/next_in_size_table-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri new file mode 100644 index 00000000..7b0a7cb3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_get_by_hash-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_set_by_hash-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_set_by_hash-i.ri new file mode 100644 index 00000000..b5020ce0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/PowerOfTwoTuple/volatile_set_by_hash-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri new file mode 100644 index 00000000..0f7332cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cas_computed-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri new file mode 100644 index 00000000..60eed3e6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/cdesc-Cell.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/padding-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/padding-c.ri new file mode 100644 index 00000000..a94bbb46 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/Cell/padding-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cas_base_computed-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cas_base_computed-i.ri new file mode 100644 index 00000000..1f500dbb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cas_base_computed-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cdesc-Striped64.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cdesc-Striped64.ri new file mode 100644 index 00000000..19105c3a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/cdesc-Striped64.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri new file mode 100644 index 00000000..678a069b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/expand_table_unless_stale-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/free%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/free%3f-i.ri new file mode 100644 index 00000000..cf307976 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/free%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code%3d-i.ri new file mode 100644 index 00000000..8a88a2d8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code-i.ri new file mode 100644 index 00000000..73ead2e0 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/hash_code-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/internal_reset-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/internal_reset-i.ri new file mode 100644 index 00000000..59e7ac72 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/internal_reset-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/new-c.ri new file mode 100644 index 00000000..b0768ba9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/retry_update-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/retry_update-i.ri new file mode 100644 index 00000000..bf18f825 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/retry_update-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_in_busy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_in_busy-i.ri new file mode 100644 index 00000000..68406c5b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_in_busy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri new file mode 100644 index 00000000..01c1923a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_initialize_cells-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri new file mode 100644 index 00000000..7e04dba3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Striped64/try_to_install_new_cell-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/attr_volatile-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/attr_volatile-i.ri new file mode 100644 index 00000000..aed2ecbf Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/attr_volatile-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/cdesc-Volatile.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/cdesc-Volatile.ri new file mode 100644 index 00000000..13fd0815 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/Volatile/cdesc-Volatile.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri new file mode 100644 index 00000000..cb9cabb2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/cdesc-XorShiftRandom.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/get-i.ri new file mode 100644 index 00000000..64fb8520 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri new file mode 100644 index 00000000..917ce336 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/XorShiftRandom/xorshift-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/cdesc-Util.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/cdesc-Util.ri new file mode 100644 index 00000000..f3326789 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/cdesc-Util.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/initialize_copy-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/initialize_copy-i.ri new file mode 100644 index 00000000..18fa2205 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/initialize_copy-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_cruby-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_cruby-c.ri new file mode 100644 index 00000000..0533122a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_cruby-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_truffleruby-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_truffleruby-c.ri new file mode 100644 index 00000000..d721082a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/make_synchronized_on_truffleruby-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/new-c.ri new file mode 100644 index 00000000..0a4bf8a2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/Util/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/cdesc-ThreadSafe.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/cdesc-ThreadSafe.ri new file mode 100644 index 00000000..17ed5259 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/ThreadSafe/cdesc-ThreadSafe.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/cdesc-TimerSet.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/cdesc-TimerSet.ri new file mode 100644 index 00000000..736b96ec Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/cdesc-TimerSet.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/kill-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/kill-i.ri new file mode 100644 index 00000000..a4d5c102 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/kill-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/new-c.ri new file mode 100644 index 00000000..70b745be Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_initialize-i.ri new file mode 100644 index 00000000..de550799 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_post_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_post_task-i.ri new file mode 100644 index 00000000..c1418418 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_post_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_reset_if_forked-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_reset_if_forked-i.ri new file mode 100644 index 00000000..1df07836 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_reset_if_forked-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_shutdown_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_shutdown_execution-i.ri new file mode 100644 index 00000000..42e896fe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/ns_shutdown_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post-i.ri new file mode 100644 index 00000000..26fcbae5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post_task-i.ri new file mode 100644 index 00000000..b51cfc65 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/post_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/process_tasks-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/process_tasks-i.ri new file mode 100644 index 00000000..883ccc4a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/process_tasks-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/remove_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/remove_task-i.ri new file mode 100644 index 00000000..977eb162 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerSet/remove_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/calculate_next_interval-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/calculate_next_interval-i.ri new file mode 100644 index 00000000..6e5e9e64 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/calculate_next_interval-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/cdesc-TimerTask.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/cdesc-TimerTask.ri new file mode 100644 index 00000000..b45400f8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/cdesc-TimerTask.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-c.ri new file mode 100644 index 00000000..0c4c4bfc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-i.ri new file mode 100644 index 00000000..e447be40 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute_task-i.ri new file mode 100644 index 00000000..c47f04a3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execute_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval%3d-i.ri new file mode 100644 index 00000000..c2b1e5f4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval-i.ri new file mode 100644 index 00000000..2c36cd46 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/execution_interval-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/interval_type-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/interval_type-i.ri new file mode 100644 index 00000000..87434a99 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/interval_type-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"interval_type:ETI"(Concurrent::TimerTask#interval_type;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"#@!attribute [r] interval_type ;TI"I@return [Symbol] method to calculate the interval between executions;T: +@fileI"1lib/concurrent-ruby/concurrent/timer_task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::TimerTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/new-c.ri new file mode 100644 index 00000000..1ce2d586 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_initialize-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_initialize-i.ri new file mode 100644 index 00000000..069e5516 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_initialize-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_kill_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_kill_execution-i.ri new file mode 100644 index 00000000..ac9a691f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_kill_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_shutdown_execution-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_shutdown_execution-i.ri new file mode 100644 index 00000000..56e571a7 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/ns_shutdown_execution-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/running%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/running%3f-i.ri new file mode 100644 index 00000000..79e69b53 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/running%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/schedule_next_task-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/schedule_next_task-i.ri new file mode 100644 index 00000000..0a6860bc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/schedule_next_task-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval%3d-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval%3d-i.ri new file mode 100644 index 00000000..a6382cc1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval%3d-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval-i.ri new file mode 100644 index 00000000..6f58b63a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TimerTask/timeout_interval-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/abort-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/abort-i.ri new file mode 100644 index 00000000..83db79be Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/abort-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/cdesc-Transaction.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/cdesc-Transaction.ri new file mode 100644 index 00000000..4f2a3960 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/cdesc-Transaction.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/commit-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/commit-i.ri new file mode 100644 index 00000000..4c94b047 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/commit-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current%3d-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current%3d-c.ri new file mode 100644 index 00000000..51627c8c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current%3d-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current-c.ri new file mode 100644 index 00000000..bdc0c202 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/current-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/new-c.ri new file mode 100644 index 00000000..b6c76c2f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/open-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/open-i.ri new file mode 100644 index 00000000..47f84cfe Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/open-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/read-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/read-i.ri new file mode 100644 index 00000000..5e1e2b2e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/read-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/unlock-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/unlock-i.ri new file mode 100644 index 00000000..5bb99413 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/unlock-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/write-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/write-i.ri new file mode 100644 index 00000000..6aff3242 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Transaction/write-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyArray/cdesc-TruffleRubyArray.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyArray/cdesc-TruffleRubyArray.ri new file mode 100644 index 00000000..62a644b9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyArray/cdesc-TruffleRubyArray.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyAtomicReference/cdesc-TruffleRubyAtomicReference.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyAtomicReference/cdesc-TruffleRubyAtomicReference.ri new file mode 100644 index 00000000..d43be388 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyAtomicReference/cdesc-TruffleRubyAtomicReference.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyHash/cdesc-TruffleRubyHash.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyHash/cdesc-TruffleRubyHash.ri new file mode 100644 index 00000000..13a6eebd Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubyHash/cdesc-TruffleRubyHash.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubySet/cdesc-TruffleRubySet.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubySet/cdesc-TruffleRubySet.ri new file mode 100644 index 00000000..0773fc69 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/TruffleRubySet/cdesc-TruffleRubySet.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cas-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cas-i.ri new file mode 100644 index 00000000..bdf52f83 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cas-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cdesc-Tuple.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cdesc-Tuple.ri new file mode 100644 index 00000000..645cced8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/cdesc-Tuple.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/compare_and_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/compare_and_set-i.ri new file mode 100644 index 00000000..96fc0dfb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/compare_and_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/each-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/each-i.ri new file mode 100644 index 00000000..1fe57a06 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/each-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/get-i.ri new file mode 100644 index 00000000..004fed6f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/new-c.ri new file mode 100644 index 00000000..6870ca81 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/set-i.ri new file mode 100644 index 00000000..e42aaa34 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/size-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/size-i.ri new file mode 100644 index 00000000..e5b76f23 --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/size-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" size:ETI"Concurrent::Tuple#size;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"#The (fixed) size of the tuple.;T: +@fileI",lib/concurrent-ruby/concurrent/tuple.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Concurrent::Tuple;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_get-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_get-i.ri new file mode 100644 index 00000000..a1b35410 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_get-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_set-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_set-i.ri new file mode 100644 index 00000000..afaaadda Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Tuple/volatile_set-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/cdesc-EngineDetector.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/cdesc-EngineDetector.ri new file mode 100644 index 00000000..6f2527d2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/cdesc-EngineDetector.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_cruby%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_cruby%3f-i.ri new file mode 100644 index 00000000..c0e94d70 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_cruby%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_jruby%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_jruby%3f-i.ri new file mode 100644 index 00000000..04eb9ccb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_jruby%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_linux%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_linux%3f-i.ri new file mode 100644 index 00000000..27be55a5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_linux%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_osx%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_osx%3f-i.ri new file mode 100644 index 00000000..4eadc080 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_osx%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_truffleruby%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_truffleruby%3f-i.ri new file mode 100644 index 00000000..5e8db93d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_truffleruby%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_windows%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_windows%3f-i.ri new file mode 100644 index 00000000..6f314137 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/on_windows%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/ruby_version-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/ruby_version-i.ri new file mode 100644 index 00000000..64f30a61 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/EngineDetector/ruby_version-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/allow_c_extensions%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/allow_c_extensions%3f-i.ri new file mode 100644 index 00000000..a45bbcee Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/allow_c_extensions%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/c_extensions_loaded%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/c_extensions_loaded%3f-i.ri new file mode 100644 index 00000000..f4168500 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/c_extensions_loaded%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/cdesc-NativeExtensionLoader.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/cdesc-NativeExtensionLoader.ri new file mode 100644 index 00000000..54dd6eff Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/cdesc-NativeExtensionLoader.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/java_extensions_loaded%3f-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/java_extensions_loaded%3f-i.ri new file mode 100644 index 00000000..9464861b Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/java_extensions_loaded%3f-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_error_path-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_error_path-i.ri new file mode 100644 index 00000000..ff8cf2bb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_error_path-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_native_extensions-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_native_extensions-i.ri new file mode 100644 index 00000000..a100d946 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/load_native_extensions-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_c_extensions_loaded-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_c_extensions_loaded-i.ri new file mode 100644 index 00000000..566f4f85 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_c_extensions_loaded-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_java_extensions_loaded-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_java_extensions_loaded-i.ri new file mode 100644 index 00000000..b4ecbcc2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/set_java_extensions_loaded-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/try_load_c_extension-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/try_load_c_extension-i.ri new file mode 100644 index 00000000..3b6ca028 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeExtensionLoader/try_load_c_extension-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/cdesc-NativeInteger.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/cdesc-NativeInteger.ri new file mode 100644 index 00000000..c25b40c6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/cdesc-NativeInteger.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer-i.ri new file mode 100644 index 00000000..a863adce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer_and_bounds-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer_and_bounds-i.ri new file mode 100644 index 00000000..4307fae3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_integer_and_bounds-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_lower_bound-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_lower_bound-i.ri new file mode 100644 index 00000000..472ced2e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_lower_bound-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive-i.ri new file mode 100644 index 00000000..a944f12e Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive_and_no_zero-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive_and_no_zero-i.ri new file mode 100644 index 00000000..d8499fb1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_positive_and_no_zero-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_upper_bound-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_upper_bound-i.ri new file mode 100644 index 00000000..487632e4 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/NativeInteger/ensure_upper_bound-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/available_processor_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/available_processor_count-i.ri new file mode 100644 index 00000000..fa51e96a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/available_processor_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cdesc-ProcessorCounter.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cdesc-ProcessorCounter.ri new file mode 100644 index 00000000..fd4df747 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cdesc-ProcessorCounter.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_quota-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_quota-i.ri new file mode 100644 index 00000000..159ea6f1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_quota-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_shares-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_shares-i.ri new file mode 100644 index 00000000..0671bc85 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_cpu_shares-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_physical_processor_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_physical_processor_count-i.ri new file mode 100644 index 00000000..c2c0e5cb Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_physical_processor_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_processor_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_processor_count-i.ri new file mode 100644 index 00000000..f147a335 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/compute_processor_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_quota-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_quota-i.ri new file mode 100644 index 00000000..3603da10 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_quota-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_shares-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_shares-i.ri new file mode 100644 index 00000000..c82ab62f Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/cpu_shares-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/new-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/new-c.ri new file mode 100644 index 00000000..f1eab009 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/new-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/physical_processor_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/physical_processor_count-i.ri new file mode 100644 index 00000000..52c5ba46 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/physical_processor_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/processor_count-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/processor_count-i.ri new file mode 100644 index 00000000..c0af6b0c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/processor_count-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/run-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/run-i.ri new file mode 100644 index 00000000..c69a2d28 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/ProcessorCounter/run-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/cdesc-Utility.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/cdesc-Utility.ri new file mode 100644 index 00000000..e7b07b38 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/Utility/cdesc-Utility.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-c.ri new file mode 100644 index 00000000..29676c19 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-i.ri new file mode 100644 index 00000000..56f66c83 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/abort_transaction-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-c.ri new file mode 100644 index 00000000..b98081f3 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-i.ri new file mode 100644 index 00000000..6e35ff48 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/atomically-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/available_processor_count-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/available_processor_count-c.ri new file mode 100644 index 00000000..ad33d814 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/available_processor_count-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-c.ri new file mode 100644 index 00000000..f1034bed Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-i.ri new file mode 100644 index 00000000..5ae2ba52 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/call_dataflow-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cdesc-Concurrent.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cdesc-Concurrent.ri new file mode 100644 index 00000000..81a8321d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cdesc-Concurrent.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_quota-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_quota-c.ri new file mode 100644 index 00000000..d242b8c8 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_quota-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_shares-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_shares-c.ri new file mode 100644 index 00000000..a9abecf1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/cpu_shares-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_simple_logger-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_simple_logger-c.ri new file mode 100644 index 00000000..cb419664 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_simple_logger-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_stdlib_logger-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_stdlib_logger-c.ri new file mode 100644 index 00000000..c8d3f89a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/create_stdlib_logger-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-c.ri new file mode 100644 index 00000000..8b3bb803 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-i.ri new file mode 100644 index 00000000..2387a3cc Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-c.ri new file mode 100644 index 00000000..3d2a1109 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-i.ri new file mode 100644 index 00000000..3b5237a6 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-c.ri new file mode 100644 index 00000000..119f6a2a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-i.ri new file mode 100644 index 00000000..245249d2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with%21-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-c.ri new file mode 100644 index 00000000..b35a216c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-i.ri new file mode 100644 index 00000000..493e6eb1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/dataflow_with-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/disable_at_exit_handlers%21-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/disable_at_exit_handlers%21-c.ri new file mode 100644 index 00000000..58acc0d9 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/disable_at_exit_handlers%21-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/executor-c.ri new file mode 100644 index 00000000..ef2dceb2 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_fast_executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_fast_executor-c.ri new file mode 100644 index 00000000..0c077db1 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_fast_executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_immediate_executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_immediate_executor-c.ri new file mode 100644 index 00000000..a6ea1b77 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_immediate_executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_io_executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_io_executor-c.ri new file mode 100644 index 00000000..96d22c7d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_io_executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger%3d-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger%3d-c.ri new file mode 100644 index 00000000..41610cde Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger%3d-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger-c.ri new file mode 100644 index 00000000..630701ce Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_logger-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_timer_set-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_timer_set-c.ri new file mode 100644 index 00000000..f4ae3fde Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/global_timer_set-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-c.ri new file mode 100644 index 00000000..bb43b1ef Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-i.ri new file mode 100644 index 00000000..7678a631 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/leave_transaction-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-c.ri new file mode 100644 index 00000000..96ee46a5 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-i.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-i.ri new file mode 100644 index 00000000..a9972984 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/monotonic_time-i.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/mutex_owned_per_thread%3f-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/mutex_owned_per_thread%3f-c.ri new file mode 100644 index 00000000..ae1d865c Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/mutex_owned_per_thread%3f-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_fast_executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_fast_executor-c.ri new file mode 100644 index 00000000..b2da9a97 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_fast_executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_io_executor-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_io_executor-c.ri new file mode 100644 index 00000000..afa4f801 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/new_io_executor-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/physical_processor_count-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/physical_processor_count-c.ri new file mode 100644 index 00000000..9b7d954a Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/physical_processor_count-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/processor_count-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/processor_count-c.ri new file mode 100644 index 00000000..41f14431 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/processor_count-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_simple_logger-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_simple_logger-c.ri new file mode 100644 index 00000000..b3e0bd65 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_simple_logger-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_stdlib_logger-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_stdlib_logger-c.ri new file mode 100644 index 00000000..d8098005 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Concurrent/use_stdlib_logger-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Hash/cdesc-Hash.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Hash/cdesc-Hash.ri new file mode 100644 index 00000000..5d80463d Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Hash/cdesc-Hash.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/Set/cdesc-Set.ri b/bin/doc/concurrent-ruby-1.3.8/ri/Set/cdesc-Set.ri new file mode 100644 index 00000000..2cddc146 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/Set/cdesc-Set.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/cdesc-TruffleRuby.ri b/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/cdesc-TruffleRuby.ri new file mode 100644 index 00000000..24055904 Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/cdesc-TruffleRuby.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/synchronized-c.ri b/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/synchronized-c.ri new file mode 100644 index 00000000..083578ed Binary files /dev/null and b/bin/doc/concurrent-ruby-1.3.8/ri/TruffleRuby/synchronized-c.ri differ diff --git a/bin/doc/concurrent-ruby-1.3.8/ri/cache.ri b/bin/doc/concurrent-ruby-1.3.8/ri/cache.ri new file mode 100644 index 00000000..4e5622ac --- /dev/null +++ b/bin/doc/concurrent-ruby-1.3.8/ri/cache.ri @@ -0,0 +1,104 @@ +{:ancestors{œI"Concurrent::Agent:ET[I"$Concurrent::Concern::Observable;TI"$Synchronization::LockableObject;TI"Concurrent::Agent::Error;T[I"StandardError;TI"'Concurrent::Agent::ValidationError;T[I"Concurrent::Agent::Error;TI"!Concurrent::TruffleRubyArray;T[I" +Array;TI" +Array;T[I"ArrayImplementation;TI"&Concurrent::Async::AsyncDelegator;T[I"$Synchronization::LockableObject;TI"&Concurrent::Async::AwaitDelegator;T[I" Object;TI"Concurrent::Atom;T[@ I"Synchronization::Object;TI"Concurrent::AtomicBoolean;T[I" AtomicBooleanImplementation;TI"Concurrent::AtomicFixnum;T[I"AtomicFixnumImplementation;TI"(Concurrent::AtomicMarkableReference;T[I"(Concurrent::Synchronization::Object;TI"$Concurrent::JavaAtomicReference;T[I"#Concurrent::AtomicDirectUpdate;TI"2Concurrent::AtomicNumericCompareAndSetWrapper;TI" Object;TI"+Concurrent::TruffleRubyAtomicReference;T[@+@,I"!TruffleRuby::AtomicReference;TI"AtomicReference;T[I""AtomicReferenceImplementation;TI"Concurrent::CountDownLatch;T[I"!CountDownLatchImplementation;TI"Concurrent::CyclicBarrier;T[I"$Synchronization::LockableObject;TI"Concurrent::Event;T[I"$Synchronization::LockableObject;TI"Concurrent::FiberLocalVar;T[I" Object;TI"#Concurrent::JavaCountDownLatch;T[I" Object;TI"Concurrent::AbstractLocals;T[I" Object;TI"Concurrent::ThreadLocals;T[I"Concurrent::AbstractLocals;TI"Concurrent::FiberLocals;T[@HI"Concurrent::LockLocalVar;T[@?I"#Concurrent::MutexAtomicBoolean;T[I" Object;TI""Concurrent::MutexAtomicFixnum;T[I" Object;TI"$Concurrent::MutexCountDownLatch;T[I"$Synchronization::LockableObject;TI"Concurrent::MutexSemaphore;T[I"$Synchronization::LockableObject;TI"Concurrent::ReadWriteLock;T[I"Synchronization::Object;TI"'Concurrent::ReentrantReadWriteLock;T[I"Synchronization::Object;TI"Concurrent::Semaphore;T[I"SemaphoreImplementation;TI"Concurrent::ThreadLocalVar;T[I" Object;TI"%Concurrent::MutexAtomicReference;T[@+@,I" Object;TI"4Concurrent::Collection::CopyOnNotifyObserverSet;T[I"$Synchronization::LockableObject;TI"3Concurrent::Collection::CopyOnWriteObserverSet;T[I"$Synchronization::LockableObject;TI";Concurrent::Collection::JavaNonConcurrentPriorityQueue;T[I" Object;TI"Concurrent::LockFreeStack;T[I"Enumerable;TI"Synchronization::Object;TI"$Concurrent::LockFreeStack::Node;T[I" Object;TI"*Concurrent::Collection::MriMapBackend;T[I"NonConcurrentMapBackend;TI"4Concurrent::Collection::NonConcurrentMapBackend;T[I" Object;TI"3Concurrent::Collection::SynchronizedMapBackend;T[I"4Concurrent::Collection::NonConcurrentMapBackend;TI"2Concurrent::Collection::TruffleRubyMapBackend;T[I"TruffleRuby::ConcurrentMap;TI"7Concurrent::Collection::NonConcurrentPriorityQueue;T[I"-NonConcurrentPriorityQueueImplementation;TI";Concurrent::Collection::RubyNonConcurrentPriorityQueue;T[I" Object;TI"-Concurrent::Collection::RubyTimeoutQueue;T[I" +Queue;TI")Concurrent::Collection::TimeoutQueue;T[I"TimeoutQueueImplementation;TI""Concurrent::DependencyCounter;T[I" Object;TI"Concurrent::Delay;T[I"$Concurrent::Concern::Obligation;TI"$Synchronization::LockableObject;TI"(Concurrent::MultipleAssignmentError;T[I" +Error;TI"Concurrent::MultipleErrors;T[I" +Error;TI"&Concurrent::ConcurrentUpdateError;T[I"ThreadError;TI""Concurrent::AbstractExchanger;T[I"Synchronization::Object;TI"Concurrent::RubyExchanger;T[I""Concurrent::AbstractExchanger;TI"$Concurrent::RubyExchanger::Node;T[@(I"Concurrent::JavaExchanger;T[@ I"Concurrent::Exchanger;T[I"ExchangerImplementation;TI"(Concurrent::AbstractExecutorService;T[I"%Concurrent::Concern::Deprecation;TI" Concurrent::ExecutorService;TI"$Synchronization::LockableObject;TI"!Concurrent::CachedThreadPool;T[I"ThreadPoolExecutor;TI" Concurrent::FixedThreadPool;T[I"ThreadPoolExecutor;TI""Concurrent::ImmediateExecutor;T[I"(Concurrent::AbstractExecutorService;TI"&Concurrent::SerialExecutorService;TI"*Concurrent::IndirectImmediateExecutor;T[I""Concurrent::ImmediateExecutor;TI"$Concurrent::JavaExecutorService;T[@µI")Concurrent::JavaExecutorService::Job;T[I" Object;TI" Runnable;TI"$Concurrent::DaemonThreadFactory;T[I" Object;TI")Concurrent::JavaSingleThreadExecutor;T[I"$Concurrent::JavaExecutorService;T@¶I"'Concurrent::JavaThreadPoolExecutor;T[@ª@ÅI"$Concurrent::RubyExecutorService;T[@µI")Concurrent::RubySingleThreadExecutor;T[@¶I"RubyThreadPoolExecutor;TI"'Concurrent::RubyThreadPoolExecutor;T[@ªI"$Concurrent::RubyExecutorService;TI"/Concurrent::RubyThreadPoolExecutor::Worker;T[I"!Concurrent::Concern::Logging;TI" Object;TI"!Concurrent::SafeTaskExecutor;T[I"$Synchronization::LockableObject;TI"$Concurrent::SerializedExecution;T[@ÒI"$Synchronization::LockableObject;TI"-Concurrent::SerializedExecutionDelegator;T[@¶I"SimpleDelegator;TI"&Concurrent::SimpleExecutorService;T[@ÏI"%Concurrent::SingleThreadExecutor;T[I"'SingleThreadExecutorImplementation;TI"#Concurrent::ThreadPoolExecutor;T[I"%ThreadPoolExecutorImplementation;TI"Concurrent::TimerSet;T[@ÏI"Concurrent::Future;T[I" IVar;TI" Concurrent::TruffleRubyHash;T[I" Hash;TI" Hash;T[I"HashImplementation;TI"Concurrent::IVar;T[@�@ I"$Synchronization::LockableObject;TI"Concurrent::Map;T[I".Concurrent::Collection::MapImplementation;TI"Concurrent::Maybe;T[I"Comparable;TI"Synchronization::Object;TI"Concurrent::MVar;T[I")Concurrent::Concern::Dereferenceable;TI"Synchronization::Object;TI"Concurrent::Promise;T[I"Concurrent::IVar;TI"0Concurrent::Promises::InternalStates::State;T[I" Object;TI"2Concurrent::Promises::InternalStates::Pending;T[I"0Concurrent::Promises::InternalStates::State;TI"3Concurrent::Promises::InternalStates::Reserved;T[I"2Concurrent::Promises::InternalStates::Pending;TI"=Concurrent::Promises::InternalStates::ResolvedWithResult;T[@I"4Concurrent::Promises::InternalStates::Fulfilled;T[I"=Concurrent::Promises::InternalStates::ResolvedWithResult;TI"9Concurrent::Promises::InternalStates::FulfilledArray;T[I"4Concurrent::Promises::InternalStates::Fulfilled;TI"3Concurrent::Promises::InternalStates::Rejected;T[@I";TI"fulfilled?;TI" just;TI" +just?;TI" nothing;TI" nothing?;TI"or;TI" reason;TI"rejected?;TI" +value;T@ú[I" borrow;TI" empty?;TI" +full?;TI" modify;TI" modify!;TI"put;TI" set!;TI"synchronize;TI" take;TI" try_put!;TI"try_take!;TI"unlocked_empty?;TI"unlocked_full?;TI"wait_for_empty;TI"wait_for_full;TI"wait_while;T@þ[I" +catch;TI" complete;TI" execute;TI" fail;TI" flat_map;TI"notify_child;TI"ns_initialize;TI" on_error;TI"on_fulfill;TI"on_reject;TI"on_success;TI" realize;TI" rescue;TI"set;TI"set_pending;TI"set_state!;TI"synchronized_set_state!;TI" then;TI"zip;T@[I"resolved?;TI" to_sym;T@[I"resolved?;TI" to_sym;T@ +[ I" +apply;TI"fulfilled?;TI" reason;TI"resolved?;TI" result;TI" to_sym;TI" +value;T@ [ +I" +apply;TI"fulfilled?;TI" reason;TI" to_sym;TI" +value;T@[I" +apply;T@[ +I" +apply;TI"fulfilled?;TI" reason;TI" to_sym;TI" +value;T@[ +I" +apply;TI"fulfilled?;TI" reason;TI" to_sym;TI" +value;T@[&I"add_callback;TI"$add_callback_clear_delayed_node;TI" add_callback_notify_blocked;TI"!async_callback_on_resolution;TI" blocks;TI"call_callback;TI"call_callbacks;TI" callback_clear_delayed_node;TI"callback_notify_blocked;TI"callbacks;TI" +chain;TI" chain_on;TI"chain_resolvable;TI"default_executor;TI" inspect;TI"on_resolution;TI"on_resolution!;TI"on_resolution_using;TI" pending?;TI" promise;TI"resolve_with;TI"resolved?;TI" +state;TI" tangle;TI" to_s;TI" +touch;TI" touched?;TI" wait;TI"wait_until_resolved;TI"waiting_threads;TI"with_async;TI"with_default_executor;TI"with_hidden_resolvable;T@[I"&;TI"any;TI"callback_on_resolution;TI" +delay;TI"rejected_resolution;TI" schedule;TI" to_event;TI"to_future;TI"with_default_executor;TI"zip;TI"|;T@[/I"&;TI"any;TI" +apply;TI""async_callback_on_fulfillment;TI" async_callback_on_rejection;TI"callback_on_fulfillment;TI"callback_on_rejection;TI"callback_on_resolution;TI" +delay;TI"exception;TI" flat;TI"flat_event;TI"flat_future;TI"fulfilled?;TI" inspect;TI"on_fulfillment;TI"on_fulfillment!;TI"on_fulfillment_using;TI"on_rejection;TI"on_rejection!;TI"on_rejection_using;TI" reason;TI"rejected?;TI"rejected_resolution;TI" rescue;TI"rescue_on;TI" result;TI"run;TI" run_test;TI" schedule;TI" then;TI" then_on;TI" to_event;TI"to_future;TI" to_s;TI" +value;TI" value!;TI" +wait!;TI"wait_until_resolved!;TI"with_default_executor;TI"zip;TI"|;T@[I" resolve;TI" wait;TI"with_hidden_resolvable;T@#[I"evaluate_to;TI"evaluate_to!;TI" fulfill;TI" reason;TI" reject;TI" resolve;TI" result;TI" +value;TI" value!;TI" wait;TI" +wait!;TI"with_hidden_resolvable;T@&[I"default_executor;TI"delayed_because;TI"evaluate_to;TI" +event;TI" future;TI" inspect;TI"resolve_with;TI" +state;TI" to_s;TI" +touch;T@0[ I"blocked_by;TI"clear_and_propagate_touch;TI"delayed_because;TI"on_blocker_resolution;TI"on_resolvable;TI""process_on_blocker_resolution;TI"resolvable?;TI" +touch;T@3[I" executor;T@6[I"on_resolvable;T@9[I"on_resolvable;T@;[I"on_resolvable;T@A[ +I"add_delayed_of;TI"on_resolvable;TI"resolvable?;TI" +touch;TI" touched?;T@C[I""process_on_blocker_resolution;T@F[I""process_on_blocker_resolution;T@H[I""process_on_blocker_resolution;T@J[I"on_resolvable;T@L[I"on_resolvable;TI""process_on_blocker_resolution;T@N[I"on_resolvable;T@P[I"on_resolvable;T@R[I"on_resolvable;TI""process_on_blocker_resolution;T@T[I"on_resolvable;T@X[I"on_resolvable;TI"resolvable?;T@[[I"on_resolvable;TI"resolvable?;T@][I"resolvable?;T@`[I"delayed_because;TI" +touch;T@b[I" inspect;TI"intended_time;T@d[I"<=>;TI" cancel;TI"cancelled?;TI" execute;TI" executor;TI"initial_delay;TI"ns_reschedule;TI"ns_schedule;TI"process_task;TI"processing?;TI"reschedule;TI" +reset;TI"schedule_time;T@p[ +I"ns_broadcast;TI"ns_signal;TI" ns_wait;TI"ns_wait_until;TI"synchronize;T@r[I"full_memory_barrier;T@u[ I"broadcast;TI"ns_broadcast;TI"ns_signal;TI" ns_wait;TI"ns_wait_until;TI" signal;TI" wait;TI"wait_until;T@x[I"new_condition;T@~[ I"broadcast;TI" signal;TI" wait;TI"wait_until;T@�[I"initialize_copy;TI" ns_wait;TI"synchronize;T@„[I"initialize_copy;TI" ns_wait;TI"synchronize;T@†[I"!__initialize_atomic_fields__;T@Š[I"method_missing;TI" +setup;TI" teardown;T@�[ +I"add;TI"decrement;TI"increment;TI" +reset;TI"sum;T@�[ I"hash_to_index;TI"next_in_size_table;TI"volatile_get_by_hash;TI"volatile_set_by_hash;T@“[I"cas_base_computed;TI"expand_table_unless_stale;TI" +free?;TI"hash_code;TI"hash_code=;TI"internal_reset;TI"retry_update;TI"try_in_busy;TI"try_initialize_cells;TI"try_to_install_new_cell;T@–[I"cas_computed;T@™[I"calculate_next_interval;TI" execute;TI"execute_task;TI"execution_interval;TI"execution_interval=;TI"interval_type;TI"ns_initialize;TI"ns_kill_execution;TI"ns_shutdown_execution;TI" running?;TI"schedule_next_task;TI"timeout_interval;TI"timeout_interval=;T@›[ I"cas;TI"compare_and_set;TI" each;TI"get;TI"set;TI" size;TI"volatile_get;TI"volatile_set;T@Ÿ[I" +value;TI" value=;T@¡[ I" +abort;TI" commit;TI" open;TI" read;TI" unlock;TI" +write;T@¤[I"available_processor_count;TI"compute_cpu_quota;TI"compute_cpu_shares;TI"%compute_physical_processor_count;TI"compute_processor_count;TI"cpu_quota;TI"cpu_shares;TI"physical_processor_count;TI"processor_count;TI"run;T@p[@r@s@u@z@{@|@}@†@‡@�[ +I" +async;TI" +await;TI" call;TI" cast;TI"init_synchronization;TI"$Concurrent::Async::ClassMethods;T[I"new;TI"#Concurrent::AtomicDirectUpdate;T[I"try_update;TI"try_update!;TI" update;TI"2Concurrent::AtomicNumericCompareAndSetWrapper;T[I"compare_and_set;TI"compare_and_swap;T@§[I"deprecated;TI"deprecated_method;TI")Concurrent::Concern::Dereferenceable;T[ I"apply_deref_options;TI" +deref;TI"ns_set_deref_options;TI"set_deref_options;TI" +value;TI" value=;TI"!Concurrent::Concern::Logging;T[I"log;T@©[I"compare_and_set_state;TI"complete?;TI" +event;TI"exception;TI"fulfilled?;TI"get_arguments_from;TI" if_state;TI"incomplete?;TI"init_obligation;TI"no_error!;TI"ns_check_state?;TI"ns_set_state;TI" pending?;TI"realized?;TI" reason;TI"rejected?;TI"set_state;TI" +state;TI" state=;TI"unscheduled?;TI" +value;TI" value!;TI" wait;TI" +wait!;T@Ý[ I"add_observer;TI"count_observers;TI"delete_observer;TI"delete_observers;TI"observers;TI"with_observer;T@«[ I"<<;TI"can_overflow?;TI" post;TI"serialized?;T@­[I"serialized?;T@¯[I"==;TI"[];TI" each;TI"each_pair;TI"initialize_copy;TI" inspect;TI" +merge;TI" select;TI" to_a;TI" to_h;TI" to_s;TI" values;TI"values_at;T@²[I"==;TI"[];TI"[]=;TI" each;TI"each_pair;TI"initialize_copy;TI" inspect;TI" +merge;TI" select;TI" to_a;TI" to_h;TI" to_s;TI" values;TI"values_at;T@´[ I"any;TI"any_event;TI"any_event_on;TI"any_fulfilled_future;TI"any_fulfilled_future_on;TI"any_resolved_future;TI"any_resolved_future_on;TI" +delay;TI" delay_on;TI"fulfilled_future;TI" future;TI"future_on;TI"make_future;TI"rejected_future;TI"resolvable_event;TI"resolvable_event_on;TI"resolvable_future;TI"resolvable_future_on;TI"resolved_event;TI"resolved_future;TI" schedule;TI"schedule_on;TI"zip;TI"zip_events;TI"zip_events_on;TI"zip_futures;TI"zip_futures_on;TI"8Concurrent::Promises::FactoryMethods::Configuration;T[I"default_executor;TI"Concurrent::ReInclude;T[I" extended;TI" include;TI" included;T@¹[I"==;TI"[];TI"[]=;TI" each;TI"each_pair;TI"initialize_copy;TI" inspect;TI" +merge;TI" select;TI" to_a;TI" to_h;TI" to_s;TI" values;TI"values_at;T@£[I" length;TI" members;TI" ns_each;TI"ns_each_pair;TI"ns_equality;TI" ns_get;TI"ns_initialize;TI"ns_initialize_copy;TI"ns_inspect;TI" ns_merge;TI"ns_select;TI" ns_to_h;TI"ns_values;TI"ns_values_at;TI"pr_underscore;TI" size;TI"5Concurrent::Synchronization::ConditionSignalling;T[I"ns_broadcast;TI"ns_signal;TI"4Concurrent::Synchronization::SafeInitialization;T[I"new;T@¦[I"full_memory_barrier;TI"8Concurrent::Synchronization::Volatile::ClassMethods;T[I"attr_volatile;T@©[I"initialize_copy;TI"+Concurrent::ThreadSafe::Util::Volatile;T[I"attr_volatile;TI"1Concurrent::ThreadSafe::Util::XorShiftRandom;T[I"get;TI" xorshift;TI"(Concurrent::Utility::EngineDetector;T[ I"on_cruby?;TI"on_jruby?;TI"on_linux?;TI" on_osx?;TI"on_truffleruby?;TI"on_windows?;TI"ruby_version;TI"/Concurrent::Utility::NativeExtensionLoader;T[ I"allow_c_extensions?;TI"c_extensions_loaded?;TI"java_extensions_loaded?;TI"load_error_path;TI"load_native_extensions;TI"set_c_extensions_loaded;TI"set_java_extensions_loaded;TI"try_load_c_extension;TI"'Concurrent::Utility::NativeInteger;T[ I"ensure_integer;TI"ensure_integer_and_bounds;TI"ensure_lower_bound;TI"ensure_positive;TI" ensure_positive_and_no_zero;TI"ensure_upper_bound;T: main0: modules[º@I"AtomicReference;TI"Concurrent;T@ @µ@HI"Concurrent::Agent;T@I"'Concurrent::Agent::ValidationError;TI"Concurrent::Async;TI"&Concurrent::Async::AsyncDelegator;TI"&Concurrent::Async::AwaitDelegator;TI"$Concurrent::Async::ClassMethods;TI"Concurrent::Atom;TI"Concurrent::AtomicBoolean;T@+I"Concurrent::AtomicFixnum;TI"(Concurrent::AtomicMarkableReference;T@,I"!Concurrent::CachedThreadPool;TI"Concurrent::Collection;TI"4Concurrent::Collection::CopyOnNotifyObserverSet;TI"3Concurrent::Collection::CopyOnWriteObserverSet;TI";Concurrent::Collection::JavaNonConcurrentPriorityQueue;TI"*Concurrent::Collection::MriMapBackend;T@{I"7Concurrent::Collection::NonConcurrentPriorityQueue;TI";Concurrent::Collection::RubyNonConcurrentPriorityQueue;TI"-Concurrent::Collection::RubyTimeoutQueue;TI"3Concurrent::Collection::SynchronizedMapBackend;TI")Concurrent::Collection::TimeoutQueue;TI"2Concurrent::Collection::TruffleRubyMapBackend;TI"Concurrent::Concern;T@ª@ü@Ò@�@ I"&Concurrent::ConcurrentUpdateError;TI"Concurrent::CountDownLatch;TI"Concurrent::CyclicBarrier;TI"$Concurrent::DaemonThreadFactory;TI"Concurrent::Delay;TI""Concurrent::DependencyCounter;TI"Concurrent::Event;TI"Concurrent::Exchanger;T@«I"Concurrent::FiberLocalVar;TI"Concurrent::FiberLocals;TI" Concurrent::FixedThreadPool;TI"Concurrent::Future;T@@¹I" Concurrent::ImmutableStruct;TI"*Concurrent::IndirectImmediateExecutor;TI"Concurrent::JRubySet;TI"$Concurrent::JavaAtomicReference;TI"#Concurrent::JavaCountDownLatch;TI"Concurrent::JavaExchanger;T@ÅI")Concurrent::JavaExecutorService::Job;TI")Concurrent::JavaSingleThreadExecutor;TI"'Concurrent::JavaThreadPoolExecutor;TI"Concurrent::LockFreeStack;TI"$Concurrent::LockFreeStack::Node;TI"Concurrent::LockLocalVar;TI"Concurrent::MVar;TI"Concurrent::Map;TI"Concurrent::Maybe;TI"(Concurrent::MultipleAssignmentError;TI"Concurrent::MultipleErrors;TI"Concurrent::MutableStruct;TI"#Concurrent::MutexAtomicBoolean;TI""Concurrent::MutexAtomicFixnum;TI"%Concurrent::MutexAtomicReference;TI"$Concurrent::MutexCountDownLatch;TI"Concurrent::MutexSemaphore;TI"Concurrent::Options;TI"Concurrent::Promise;TI"Concurrent::Promises;T@Z@@E@+I"4Concurrent::Promises::AnyFulfilledFuturePromise;TI"2Concurrent::Promises::AnyResolvedEventPromise;T@_@5@8I"'Concurrent::Promises::ChainPromise;TI"'Concurrent::Promises::DelayPromise;T@!I".Concurrent::Promises::EventWrapperPromise;TI")Concurrent::Promises::FactoryMethods;T@¶I"+Concurrent::Promises::FlatEventPromise;TI",Concurrent::Promises::FlatFuturePromise;T@%I"/Concurrent::Promises::FutureWrapperPromise;TI"0Concurrent::Promises::ImmediateEventPromise;TI"1Concurrent::Promises::ImmediateFuturePromise;T@2@@I"9Concurrent::Promises::InternalStates::FulfilledArray;TI";TI"catch_inheritance;TI"descendants;TI"inherited;T@{I" priority;TI" safe;T@[I"gemfile_exists?;T@{I"require_from_bundler;T@|[@{I" tabulate;T@~[@{@€[@{@‚[@{@„[@{@†[@{@ˆ[@{@Š[@{@Œ[@{@Ž[@{@�[@{@’[I"lsi;T@{@”[@{@–[@{@˜[I" mtimes;T@{I"reset_cache;T@š[@{@�[@{@¡[@{@©[@{I" tag_name;T@­[@{@¯[@{@²[@{@´[@{@¶[@{@¸[I"escape_path;T@{I"unescape_path;T@º[@{I" Jekyll;T[ I"configuration;TI"env;TI" logger;TI" logger=;TI"sanitized_path;TI"set_timezone;TI" +sites;TI"Jekyll::External;T[ I"blessed_gems;TI"require_if_present;TI"require_with_graceful_fail;TI"version_constraint;TI"Jekyll::Hooks;T[ +I"insert_hook;TI"priority_value;TI" register;TI"register_one;TI" trigger;T:c_class_variables{: c_singleton_class_variables{: encodingIu: Encoding +UTF-8;F:instance_methods{X@[I"require_all;T@ +[I"[];TI"[]=;TI" +clear;TI" delete;TI"delete_cache_files;TI"disk_cache_enabled?;TI" dump;TI" getset;TI" hash;TI" key?;TI" load;TI" path_to;T@ [I" cleanup!;TI"existing_files;TI"keep_dirs;TI"keep_file_regex;TI"metadata_file;TI" new_dirs;TI"new_files;TI"obsolete_files;TI"parent_dirs;TI"replaced_files;TI" site;T@["I"collection_dir;TI"container;TI"determine_sort_order;TI"directory;TI" docs;TI" entries;TI"entry_filter;TI" exists?;TI"extract_metadata;TI" +files;TI"filtered_entries;TI" inspect;TI" +label;TI" metadata;TI"method_missing;TI"order_with_warning;TI" read;TI"read_document;TI"read_static_file;TI"rearrange_docs!;TI"relative_directory;TI"respond_to_missing?;TI"sanitize_label;TI" site;TI"sort_docs!;TI"sort_docs_by_key!;TI"to_liquid;TI"url_template;TI" write?;T@![I" connect;TI"disconnect;TI"handle_websockets_event;TI"log_error;TI"print_message;TI" reload;TI" running?;TI" +start;TI"started_event;TI" stop;TI"stopped_event;TI" thread;T@#[ +I"bad_browser?;TI" chunked?;TI" +html?;TI" inline?;TI"skip_processing?;T@%[ I"content_length;TI"livereload_added;TI"livereload_args;TI" new_body;TI" process!;TI"processed?;TI" template;T@'[ +I"!conditionally_inject_charset;TI" do_GET;TI"search_file;TI"search_index_file;TI"set_defaults;T@*[I" dispatch;TI"reload_body;TI"reload_size;T@-[I"add_default_collections;TI"add_default_excludes;TI"check_include_exclude;TI"check_plugins;TI"config_files;TI"csv_to_array;TI"#get_config_value_with_override;TI" +quiet;TI" quiet?;TI"read_config_file;TI"read_config_files;TI"safe_load_file;TI" source;TI"stringify_keys;TI"style_to_permalink;TI" validate;TI" verbose;TI" verbose?;T@0[I"highlighter_prefix;TI"highlighter_suffix;T@3[I" convert;TI" matches;TI"output_ext;T@6[I" convert;TI"custom_class_allowed?;TI"custom_processor;TI"extname_list;TI"get_processor;TI" matches;TI"output_ext;TI" +setup;TI"third_party_processors;TI"valid_processors;T@8[I" to_html;T@;[ I" convert;TI"highlighter;TI"load_dependencies;TI"modernize_coderay_config;TI" +setup;TI"strip_coderay_prefix;T@=[I"parse_content;T@@[I" convert;TI" matches;TI"output_ext;T@B[AI"<=>;TI"[];TI"asset_file?;TI" basename;TI"basename_without_ext;TI"categories_from_path;TI"cleaned_relative_path;TI"coffeescript_file?;TI"collection;TI" content;TI" data;TI" date;TI"destination;TI" draft?;TI"excerpt_separator;TI" extname;TI"generate_excerpt;TI"generate_excerpt?;TI"handle_read_error;TI"id;TI" inspect;TI"merge_categories!;TI"merge_data!;TI"merge_date!;TI"merge_defaults;TI"method_missing;TI"modify_date;TI" next_doc;TI"no_layout?;TI" output;TI"output_ext;TI" path;TI"permalink;TI"place_in_layout?;TI"populate_categories;TI"populate_tags;TI"populate_title;TI"previous_doc;TI"published?;TI" read;TI"read_content;TI"read_post_data;TI"related_posts;TI"relative_path;TI"render_with_liquid?;TI" renderer;TI"respond_to_missing?;TI"sass_file?;TI" site;TI"source_file_mtime;TI"to_liquid;TI" to_s;TI"trigger_hooks;TI" type;TI"url;TI"url_placeholders;TI"url_template;TI" +write;TI" write?;TI"yaml_file?;T@E[I" to_s;T@H[ I"<=>;TI"collapse_document;TI"collection;TI" excerpt;TI"hash_for_json;TI" name;TI" next;TI" previous;T@K[I"[];TI"[]=;TI"content_methods;TI" each;TI" each_key;TI" +fetch;TI"hash_for_json;TI" inspect;TI"invoke_drop;TI" key?;TI" keys;TI" +merge;TI" merge!;TI"mutations;TI" to_h;TI" to_hash;TI" to_json;T@O[ I" date;TI" excerpt;TI" layout;TI" name;T@R[ I"environment;TI" to_h;TI" to_json;TI" version;T@U[I"[];TI"collections;TI" config;TI"current_document;TI"documents;TI"html_pages;TI" key?;TI" +posts;TI"related_posts;T@Z[ I" authors;TI"description;TI"fallback_data;TI" gemspec;TI" metadata;TI" root;TI" version;T@\[I" content;TI"fallback_data;TI"highlighter_prefix;TI"highlighter_suffix;TI" jekyll;TI" layout;TI" page;TI"paginator;TI" site;TI" +theme;T@^[I"categories;TI"collection;TI"day;TI"fallback_data;TI" hour;TI" +i_day;TI" i_month;TI" long_day;TI"long_month;TI" minute;TI" +month;TI" name;TI" second;TI"short_day;TI"short_month;TI"short_year;TI" slug;TI"slugified_categories;TI" +title;TI" +w_day;TI" w_year;TI" week;TI" +y_day;TI" year;T@`[I" backup?;TI"base_directory;TI"derive_base_directory;TI"excluded?;TI" filter;TI"included?;TI"relative_to_source;TI" site;TI" special?;T@b[I" content;TI" data;TI"doc;TI"endtag_regex_stash;TI"ext;TI"extract_excerpt;TI"0extract_markdown_link_reference_definitions;TI"id;TI" include?;TI" inspect;TI"liquid_block?;TI" output;TI" path;TI"place_in_layout?;TI"print_build_warning;TI"relative_path;TI"render_with_liquid?;TI"sanctify_liquid_tags;TI"to_liquid;TI" to_s;TI"trigger_hooks;T@d[I"all;TI" applies?;TI"applies_path?;TI"applies_type?;TI"ensure_time!;TI" find;TI"glob_cache;TI"glob_scope;TI"has_precedence?;TI"matching_sets;TI"path_is_subpath?;TI" +reset;TI"sanitize_path;TI"strip_collections_dir;TI"update_deprecated_types;TI" valid?;TI"valid_sets;T@f[ I" content;TI" inspect;TI" name;TI" path;TI" render;TI" site;TI" to_s;T@h[I" content;TI" data;TI"ext;TI" inspect;TI" name;TI" path;TI" process;TI"relative_path;TI" site;T@k[I" +cache;TI" file;TI"increment_bytes;TI"increment_count;TI"increment_time;TI"measure_time;TI"new_profile_hash;TI"normalize_path;TI" +reset;TI"stats_table;T@m[ I"measure_bytes;TI"measure_counts;TI" +parse;TI" render;TI" render!;TI"reset_template_assigns;TI" warnings;T@o[ I"data_for_table;TI"format_bytes;TI"header_labels;TI" to_s;T@q[I"abort_with;TI"adjust_verbosity;TI" +debug;TI" +error;TI"formatted_topic;TI" info;TI" +level;TI"log_level=;TI" message;TI" messages;TI" warn;TI" +write;TI"write_message?;TI" writer;T@s["I" basename;TI" content;TI" data;TI"destination;TI"dir;TI" excerpt;TI"excerpt_separator;TI"ext;TI" extname;TI"generate_excerpt;TI"generate_excerpt?;TI" +html?;TI" index?;TI" inspect;TI" name;TI" output;TI" +pager;TI" path;TI"permalink;TI" process;TI"relative_path;TI" render;TI" site;TI" template;TI"trigger_hooks;TI"url;TI" url_dir;TI"url_placeholders;TI" write?;T@u[ I"doc;TI" inspect;TI"render_with_liquid?;TI"to_liquid;T@x[I"read_yaml;T@}[I"<=>;T@[I"conscientious_require;TI"deprecation_checks;TI"plugin_allowed?;TI"plugins_path;TI"require_gems;TI"require_plugin_files;TI"require_theme_deps;TI" site;TI"whitelist;T@|[I"profile_process;T@~[I"can_be_published?;TI"hidden_in_the_future?;TI" publish?;T@€[I"!conditionally_generate_entry;TI"filter_entries;TI"get_entries;TI""outside_configured_directory?;TI"post_reader;TI" read;TI"read_data;TI"read_directories;TI"read_included_excludes;TI"read_included_file;TI"retrieve_dirs;TI"retrieve_pages;TI"retrieve_posts;TI"retrieve_static_files;TI" site;TI"sort_files!;T@‚[I" content;TI" read;TI" site;T@„[I" config;TI" content;TI"convert_row;TI"csv_config;TI" read;TI"read_config;TI"read_data_file;TI"read_data_to;TI"sanitize_filename;TI" site;TI"tsv_config;T@†[I"entries_in;TI"layout_directory;TI"layout_entries;TI"layout_name;TI" read;TI" site;TI"theme_layout_directory;TI"theme_layout_entries;TI" within;T@ˆ[ I"dir;TI" read;TI" site;TI"unfiltered_content;T@Š[ I"processable?;TI"publishable?;TI"read_content;TI"read_drafts;TI"read_posts;TI"read_publishable;TI" site;TI"unfiltered_content;T@Œ[ I"dir;TI" read;TI" site;TI"unfiltered_content;T@Ž[ I"append_unless_exists;TI" read;TI"read_theme_asset;TI" site;T@�[I"add;TI"add_dependency;TI" +cache;TI" +clear;TI"clear_cache;TI" disabled;TI"disabled?;TI"existing_file_modified?;TI" +force;TI" metadata;TI"metadata_file;TI"modified?;TI"read_metadata;TI"regenerate?;TI"regenerate_document?;TI"regenerate_page?;TI" site;TI"%source_modified_or_dest_missing?;TI"write_metadata;T@’[ I" +build;TI"build_index;TI"lsi_related_posts;TI"most_recent_posts;TI" post;TI" site;T@”[I"!add_regenerator_dependencies;TI"assign_current_document!;TI" assign_highlighter_options!;TI"assign_layout_data!;TI"assign_pages!;TI" convert;TI"converter_output_ext;TI"converters;TI" document;TI"invalid_layout?;TI" layouts;TI"liquid_options;TI"output_ext;TI"output_exts;TI" payload;TI"permalink_ext;TI"place_in_layouts;TI"render_document;TI"render_layout;TI"render_liquid;TI"run;TI" site;TI"validate_layout;T@–[YI" baseurl;TI"cache_dir;TI"categories;TI" cleanup;TI"collection_names;TI"collections;TI"collections_path;TI" config;TI" config=;TI"configure_cache;TI"configure_file_read_opts;TI"configure_include_paths;TI"configure_plugins;TI"configure_theme;TI"converters;TI" data;TI" dest;TI"docs_to_write;TI"documents;TI" drafts;TI"each_site_file;TI"ensure_not_in_dest;TI" exclude;TI"file_read_opts;TI"filter_cache;TI"find_converter_instance;TI"frontmatter_defaults;TI" future;TI" gems;TI" generate;TI"generators;TI"hide_cache_dir_from_git;TI"highlighter;TI"in_cache_dir;TI"in_dest_dir;TI"in_source_dir;TI"in_theme_dir;TI" include;TI"includes_load_paths;TI"inclusions;TI"incremental?;TI" inspect;TI"instantiate_subclasses;TI"keep_files;TI" layouts;TI"limit_posts;TI"limit_posts!;TI"liquid_renderer;TI"load_theme_configuration;TI"lsi;TI" +pages;TI"permalink_style;TI"plugin_manager;TI" plugins;TI"post_attr_hash;TI" +posts;TI"print_stats;TI" process;TI" profiler;TI"publisher;TI" read;TI" reader;TI"regenerator;TI"'relative_permalinks_are_deprecated;TI" render;TI"render_docs;TI"render_pages;TI"render_regenerated;TI" +reset;TI" safe;TI" +setup;TI"show_drafts;TI"site_cleaner;TI"site_data;TI"site_payload;TI" source;TI"static_files;TI"static_files_to_write;TI" tags;TI" +theme;TI" time;TI"to_liquid;TI"unpublished;TI" +write;T@˜[I" basename;TI"cleaned_relative_path;TI"copy_file;TI" data;TI" defaults;TI"destination;TI"destination_rel_dir;TI" extname;TI" inspect;TI"modified?;TI"modified_time;TI" +mtime;TI" name;TI" path;TI"placeholders;TI"relative_path;TI"to_liquid;TI" type;TI"url;TI" +write;TI" write?;T@š[ +I"add;TI" +close;TI" +error;TI"logdevice;TI" warn;T@�[I"add_code_tag;TI"line_highlighter_formatter;TI"mark_lines;TI"parse_options;TI" render;TI"render_codehighlighter;TI"render_pygments;TI"render_rouge;TI"table_formatter;T@¡[I"add_include_to_dependency;TI"could_not_locate_message;TI"file_read_opts;TI"load_cached_partial;TI"locate_include_file;TI"outside_site_source?;TI"parse_params;TI"read_file;TI"realpath_prefixed_with?;TI" render;TI"render_variable;TI"syntax_example;TI"tag_includes_dirs;TI"valid_include_file?;TI"validate_file_name;TI"validate_params;T@¤[ I"add_include_to_dependency;TI"locate_include_file;TI"outside_scope?;TI"realpath_prefixed_with?;TI" render;TI"valid_include_file?;T@§[I"page_path;TI"resource_path;TI"tag_includes_dirs;T@©[I" render;T@­[ I"==;TI" date;TI"deprecated_equality;TI" name;TI" path;TI"post_date;TI"post_slug;TI" slug;T@¯[I" render;T@²[I"assets_path;TI" basename;TI"data_path;TI" gemspec;TI"includes_path;TI"layouts_path;TI"log_realpath_exception;TI" name;TI" path_for;TI"realpath_for;TI" root;TI"runtime_dependencies;TI"sass_path;T@´[I"code_of_conduct;TI" create!;TI"create_accessories;TI"create_directories;TI"create_gemspec;TI"create_starter_files;TI"erb;TI"initialize_git_repo;TI" mkdir_p;TI" name;TI" path;TI" root;TI" template;TI"template_file;TI"user_email;TI"user_name;TI"write_file;T@¶[I"jekyll_version_with_minor;TI" render;TI"theme_directories;T@¸[ I"generate_url;TI"generate_url_from_drop;TI"generate_url_from_hash;TI"generated_permalink;TI"generated_url;TI"possible_keys;TI"sanitize_url;TI" to_s;T@º[I" flag;TI"set;TI" wait;T@*[I"glob_include?;TI" symlink?;TI"!symlink_outside_site_source?;TI"Jekyll::Convertible;T[I"[];TI"asset_file?;TI"coffeescript_file?;TI"converters;TI" defaults;TI"do_layout;TI"hook_owner;TI"invalid_layout?;TI"no_layout?;TI"output_ext;TI"place_in_layout?;TI"published?;TI"read_yaml;TI"render_all_layouts;TI"render_liquid;TI"render_with_liquid?;TI" renderer;TI"sass_file?;TI"to_liquid;TI" to_s;TI"transform;TI" type;TI"validate_data!;TI"validate_permalink!;TI" +write;TI"Jekyll::Deprecator;T[ +I"arg_is_present?;TI"defaults_deprecate_type;TI"deprecation_message;TI"no_subcommand;TI" process;T@¼[&I"array_to_sentence_string;TI"as_liquid;TI"cgi_escape;TI"compare_property_vs_target;TI" find;TI" find_exp;TI" inspect;TI"item_property;TI" jsonify;TI"markdownify;TI"normalize_whitespace;TI"number_of_words;TI"parse_binary_comparison;TI"parse_comparison;TI"parse_condition;TI"parse_sort_input;TI"pop;TI" push;TI"read_liquid_attribute;TI" sample;TI" sassify;TI" scssify;TI" +shift;TI" slugify;TI" smartify;TI" sort;TI"sort_input;TI"to_integer;TI" unshift;TI"uri_escape;TI" +where;TI"where_exp;TI"xml_escape;TI"!Jekyll::Filters::DateFilters;T[ I"date_to_long_string;TI"date_to_rfc822;TI"date_to_string;TI"date_to_xmlschema;TI" ordinal;TI"stringify_date;TI" time;TI"%Jekyll::Filters::GroupingFilters;T[ +I" group_by;TI"group_by_exp;TI"groupable?;TI"grouped_array;TI"parse_expression;TI" Jekyll::Filters::URLFilters;T[ I"absolute_url;TI"compute_absolute_url;TI"compute_relative_url;TI"ensure_leading_slash;TI"relative_url;TI"sanitized_baseurl;TI"strip_index;TI"Jekyll::LiquidExtensions;T[I"lookup_variable;TI"Jekyll::Utils;T[I"add_permalink_suffix;TI"deep_merge_hashes;TI"deep_merge_hashes!;TI"duplicable?;TI"duplicate_frozen_values;TI"has_liquid_construct?;TI"has_yaml_header?;TI"mergable?;TI"merge_default_proc;TI"merge_values;TI"merged_file_read_opts;TI"parse_date;TI"pluralized_array_from_hash;TI"+replace_character_sequence_with_hyphen;TI"safe_glob;TI" slugify;TI"stringify_hash_keys;TI"symbolize_hash_keys;TI"titleize_slug;TI"transform_keys;TI"value_from_plural_key;TI"value_from_singular_key;TI"Jekyll::Utils::Ansi;T[I" has?;TI" +reset;TI" +strip;TI"Jekyll::Utils::Exec;T[I"run;TI"Jekyll::Utils::Internet;T[I"connected?;TI"dns;TI"Jekyll::Utils::Platforms;T[I"bash_on_windows?;TI" jruby?;TI" linux?;TI"linux_os?;TI"microsoft_proc_version?;TI" mri?;TI" osx?;TI"proc_version;TI"rbconfig_host;TI"really_windows?;TI" +unix?;TI"vanilla_windows?;TI" windows?;TI"Jekyll::Utils::WinTZ;T[I"calculate;T: main0: modules[lI" Jekyll;TI"Jekyll::Cache;TI"Jekyll::Cleaner;TI"Jekyll::Collection;TI"Jekyll::CollectionReader;T@I"Jekyll::Commands;TI"Jekyll::Commands::Build;TI"Jekyll::Commands::Clean;TI"Jekyll::Commands::Doctor;TI"Jekyll::Commands::Help;TI"Jekyll::Commands::New;TI"Jekyll::Commands::NewTheme;TI"Jekyll::Commands::Serve;TI"+Jekyll::Commands::Serve::BodyProcessor;TI"1Jekyll::Commands::Serve::HttpAwareConnection;TI"/Jekyll::Commands::Serve::LiveReloadReactor;TI"%Jekyll::Commands::Serve::Servlet;TI"*Jekyll::Commands::Serve::SkipAnalyzer;TI"Jekyll::Configuration;T@5I"Jekyll::Converters;TI"!Jekyll::Converters::Identity;TI"!Jekyll::Converters::Markdown;TI"1Jekyll::Converters::Markdown::KramdownParser;TI"$Jekyll::Converters::SmartyPants;T@jI"Jekyll::DataReader;TI"Jekyll::Deprecator;TI"Jekyll::Document;TI"Jekyll::Drops;TI""Jekyll::Drops::CollectionDrop;T@Q@WI"Jekyll::Drops::ExcerptDrop;TI"Jekyll::Drops::JekyllDrop;TI"Jekyll::Drops::SiteDrop;TI""Jekyll::Drops::StaticFileDrop;TI"Jekyll::Drops::ThemeDrop;TI"&Jekyll::Drops::UnifiedPayloadDrop;TI"Jekyll::Drops::UrlDrop;TI"Jekyll::EntryFilter;TI"Jekyll::Errors;T@wI"Jekyll::External;TI"Jekyll::Filters;T@¾@¿@«I" Jekyll::FrontmatterDefaults;TI"Jekyll::Hooks;TI"Jekyll::Inclusion;TI"Jekyll::Layout;TI"Jekyll::LayoutReader;TI"Jekyll::LiquidExtensions;TI"Jekyll::LiquidRenderer;TI"!Jekyll::LiquidRenderer::File;TI""Jekyll::LiquidRenderer::Table;TI"Jekyll::LogAdapter;T@zI"Jekyll::PageExcerpt;TI"Jekyll::PageReader;TI"Jekyll::PageWithoutAFile;TI"Jekyll::PathManager;TI"Jekyll::Plugin;TI"Jekyll::PluginManager;TI"Jekyll::PostReader;TI"Jekyll::Profiler;TI"Jekyll::Publisher;TI"Jekyll::Reader;TI"Jekyll::Regenerator;TI"Jekyll::RelatedPosts;TI"Jekyll::Renderer;TI"Jekyll::Site;TI"Jekyll::StaticFile;TI"Jekyll::StaticFileReader;TI"Jekyll::Stevenson;TI"Jekyll::Tags;TI"!Jekyll::Tags::HighlightBlock;TI"%Jekyll::Tags::IncludeRelativeTag;T@¦I"Jekyll::Tags::Link;TI"&Jekyll::Tags::OptimizedIncludeTag;TI"Jekyll::Tags::PostComparer;TI"Jekyll::Tags::PostUrl;TI"Jekyll::Theme;TI"Jekyll::ThemeAssetsReader;TI"Jekyll::ThemeBuilder;TI"&Jekyll::ThemeBuilder::ERBRenderer;TI"Jekyll::URL;TI"Jekyll::Utils;TI"Jekyll::Utils::Ansi;TI"Jekyll::Utils::Exec;TI"Jekyll::Utils::Internet;TI"Jekyll::Utils::Platforms;TI"Jekyll::Utils::ThreadEvent;TI"Jekyll::Utils::WinTZ;TI" Kramdown;TI"Kramdown::JekyllDocument;TI"Kramdown::Parser;TI""Kramdown::Parser::SmartyPants;T@I" SafeYAML;T: +pages[I" LICENSE;TI"README.markdown;TI"-lib/blank_template/_layouts/default.html;TI"'lib/blank_template/_sass/base.scss;TI",lib/blank_template/assets/css/main.scss;TI" lib/blank_template/index.md;TI">lib/jekyll/commands/serve/livereload_assets/livereload.js;TI"6lib/jekyll/commands/serve/mime_types_charset.json;TI"lib/jekyll/mime.types;TI"lib/site_template/404.html;TI"%lib/site_template/about.markdown;TI"%lib/site_template/index.markdown;TI"lib/theme_template/Gemfile;TI"-lib/theme_template/_layouts/default.html;TI"*lib/theme_template/_layouts/page.html;TI"*lib/theme_template/_layouts/post.html;TI"(lib/theme_template/example/_post.md;TI"*lib/theme_template/example/index.html;TI"*lib/theme_template/example/style.scss;T: +titleI"jekyll-4.4.1 Documentation;T \ No newline at end of file diff --git a/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_layouts/page-default_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_layouts/page-default_html.ri new file mode 100644 index 00000000..76833fef Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_layouts/page-default_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_sass/page-base_scss.ri b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_sass/page-base_scss.ri new file mode 100644 index 00000000..dc0a67b7 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/_sass/page-base_scss.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/blank_template/assets/css/page-main_scss.ri b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/assets/css/page-main_scss.ri new file mode 100644 index 00000000..445ca533 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/assets/css/page-main_scss.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/blank_template/page-index_md.ri b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/page-index_md.ri new file mode 100644 index 00000000..8ffe0a76 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/blank_template/page-index_md.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/livereload_assets/page-livereload_js.ri b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/livereload_assets/page-livereload_js.ri new file mode 100644 index 00000000..e22878bf Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/livereload_assets/page-livereload_js.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/page-mime_types_charset_json.ri b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/page-mime_types_charset_json.ri new file mode 100644 index 00000000..7ccb23f0 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/commands/serve/page-mime_types_charset_json.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/jekyll/page-mime_types.ri b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/page-mime_types.ri new file mode 100644 index 00000000..ed0fdd99 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/jekyll/page-mime_types.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-404_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-404_html.ri new file mode 100644 index 00000000..f8029644 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-404_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-about_markdown.ri b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-about_markdown.ri new file mode 100644 index 00000000..5ad1877e Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-about_markdown.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-index_markdown.ri b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-index_markdown.ri new file mode 100644 index 00000000..402fe9c2 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/site_template/page-index_markdown.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-default_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-default_html.ri new file mode 100644 index 00000000..d0506011 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-default_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-page_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-page_html.ri new file mode 100644 index 00000000..a9d14435 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-page_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-post_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-post_html.ri new file mode 100644 index 00000000..baa245d9 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/_layouts/page-post_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-_post_md.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-_post_md.ri new file mode 100644 index 00000000..66d657b4 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-_post_md.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-index_html.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-index_html.ri new file mode 100644 index 00000000..5c113fe5 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-index_html.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-style_scss.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-style_scss.ri new file mode 100644 index 00000000..48daafbb Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/example/page-style_scss.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/lib/theme_template/page-Gemfile.ri b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/page-Gemfile.ri new file mode 100644 index 00000000..d66bdf34 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/lib/theme_template/page-Gemfile.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/page-LICENSE.ri b/bin/doc/jekyll-4.4.1/ri/page-LICENSE.ri new file mode 100644 index 00000000..c97d5b15 Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/page-LICENSE.ri differ diff --git a/bin/doc/jekyll-4.4.1/ri/page-README_markdown.ri b/bin/doc/jekyll-4.4.1/ri/page-README_markdown.ri new file mode 100644 index 00000000..60ea35ca Binary files /dev/null and b/bin/doc/jekyll-4.4.1/ri/page-README_markdown.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/cdesc-Sass.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/cdesc-Sass.ri new file mode 100644 index 00000000..f0c8e75c Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/cdesc-Sass.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/syntax-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/syntax-i.ri new file mode 100644 index 00000000..c7fa3a6f Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Sass/syntax-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page-i.ri new file mode 100644 index 00000000..d8f79375 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page_failed%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page_failed%3f-i.ri new file mode 100644 index 00000000..13097e13 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/associate_page_failed%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/cdesc-Scss.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/cdesc-Scss.ri new file mode 100644 index 00000000..3fc9eb17 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/cdesc-Scss.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/convert-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/convert-i.ri new file mode 100644 index 00000000..2e44b698 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/convert-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/dissociate_page-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/dissociate_page-i.ri new file mode 100644 index 00000000..3f4cc765 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/dissociate_page-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/fatal_deprecations-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/fatal_deprecations-i.ri new file mode 100644 index 00000000..235d7090 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/fatal_deprecations-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/file_url_from_path-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/file_url_from_path-i.ri new file mode 100644 index 00000000..6a5b27d2 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/file_url_from_path-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/future_deprecations-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/future_deprecations-i.ri new file mode 100644 index 00000000..4d196b5e Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/future_deprecations-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/generate_source_map_page-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/generate_source_map_page-i.ri new file mode 100644 index 00000000..85844d40 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/generate_source_map_page-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/jekyll_sass_configuration-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/jekyll_sass_configuration-i.ri new file mode 100644 index 00000000..bde95497 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/jekyll_sass_configuration-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/livereload%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/livereload%3f-i.ri new file mode 100644 index 00000000..7100f47c Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/livereload%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/matches-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/matches-i.ri new file mode 100644 index 00000000..8ee26266 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/matches-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/output_ext-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/output_ext-i.ri new file mode 100644 index 00000000..01f6d9d5 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/output_ext-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/process_source_map-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/process_source_map-i.ri new file mode 100644 index 00000000..862e3033 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/process_source_map-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/quiet_deps_option-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/quiet_deps_option-i.ri new file mode 100644 index 00000000..d3dce9d1 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/quiet_deps_option-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/safe%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/safe%3f-i.ri new file mode 100644 index 00000000..0936bbe8 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/safe%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_configs-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_configs-i.ri new file mode 100644 index 00000000..e7a1604e Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_configs-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir-i.ri new file mode 100644 index 00000000..878f7e24 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir_relative_to_site_source-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir_relative_to_site_source-i.ri new file mode 100644 index 00000000..c68e3a02 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_dir_relative_to_site_source-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_file_url-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_file_url-i.ri new file mode 100644 index 00000000..4e7967ec Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_file_url-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_load_paths-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_load_paths-i.ri new file mode 100644 index 00000000..4d6f9971 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_load_paths-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_page-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_page-i.ri new file mode 100644 index 00000000..143f2550 --- /dev/null +++ b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_page-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"sass_page:ETI"'Jekyll::Converters::Scss#sass_page;TI"R;T: privateo:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"AThe Page instance for which this object acts as a converter.;T: +@fileI""lib/jekyll/converters/scss.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Jekyll::Converters::Scss;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_source_root-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_source_root-i.ri new file mode 100644 index 00000000..e847b8e4 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_source_root-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_style-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_style-i.ri new file mode 100644 index 00000000..98cd6d0d Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sass_style-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/silence_deprecations-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/silence_deprecations-i.ri new file mode 100644 index 00000000..827a3166 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/silence_deprecations-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site-i.ri new file mode 100644 index 00000000..0ffa4763 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site_source-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site_source-i.ri new file mode 100644 index 00000000..00bdb38a Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/site_source-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_map_page-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_map_page-i.ri new file mode 100644 index 00000000..43c2f569 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_map_page-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_mapping_url-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_mapping_url-i.ri new file mode 100644 index 00000000..91082db0 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/source_mapping_url-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_option-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_option-i.ri new file mode 100644 index 00000000..b06e2f25 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_option-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_required%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_required%3f-i.ri new file mode 100644 index 00000000..cbdf81c0 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/sourcemap_required%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/syntax-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/syntax-i.ri new file mode 100644 index 00000000..fd215a7e Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/syntax-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/user_sass_load_paths-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/user_sass_load_paths-i.ri new file mode 100644 index 00000000..eb64faa1 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/user_sass_load_paths-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/verbose_option-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/verbose_option-i.ri new file mode 100644 index 00000000..98158357 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/Scss/verbose_option-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/cdesc-Converters.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/cdesc-Converters.ri new file mode 100644 index 00000000..7d04d617 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/Converters/cdesc-Converters.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/asset_file%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/asset_file%3f-i.ri new file mode 100644 index 00000000..7649e096 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/asset_file%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/cdesc-SourceMapPage.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/cdesc-SourceMapPage.ri new file mode 100644 index 00000000..40ee584a Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/cdesc-SourceMapPage.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/ext-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/ext-i.ri new file mode 100644 index 00000000..22e81f2b Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/ext-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/inspect-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/inspect-i.ri new file mode 100644 index 00000000..f74453e4 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/inspect-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/new-c.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/new-c.ri new file mode 100644 index 00000000..2cd5b1e8 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/new-c.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/render_with_liquid%3f-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/render_with_liquid%3f-i.ri new file mode 100644 index 00000000..726bb58d Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/render_with_liquid%3f-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/source_map-i.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/source_map-i.ri new file mode 100644 index 00000000..304c7649 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/SourceMapPage/source_map-i.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/cdesc-Jekyll.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/cdesc-Jekyll.ri new file mode 100644 index 00000000..778f046d Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/Jekyll/cdesc-Jekyll.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/JekyllSassConverter/cdesc-JekyllSassConverter.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/JekyllSassConverter/cdesc-JekyllSassConverter.ri new file mode 100644 index 00000000..e79f1711 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/JekyllSassConverter/cdesc-JekyllSassConverter.ri differ diff --git a/bin/doc/jekyll-sass-converter-3.1.0/ri/cache.ri b/bin/doc/jekyll-sass-converter-3.1.0/ri/cache.ri new file mode 100644 index 00000000..ea7b1802 Binary files /dev/null and b/bin/doc/jekyll-sass-converter-3.1.0/ri/cache.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/cdesc-Watch.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/cdesc-Watch.ri new file mode 100644 index 00000000..b390644b Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/cdesc-Watch.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/init_with_program-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/init_with_program-i.ri new file mode 100644 index 00000000..078f6979 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/init_with_program-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/process-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/process-i.ri new file mode 100644 index 00000000..60d375d2 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/Watch/process-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/cdesc-Commands.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/cdesc-Commands.ri new file mode 100644 index 00000000..0dd8b071 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Commands/cdesc-Commands.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watch/cdesc-Watch.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watch/cdesc-Watch.ri new file mode 100644 index 00000000..e0acc032 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watch/cdesc-Watch.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/build_listener-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/build_listener-i.ri new file mode 100644 index 00000000..4523251f Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/build_listener-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/cdesc-Watcher.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/cdesc-Watcher.ri new file mode 100644 index 00000000..bd9b7f30 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/cdesc-Watcher.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/config_files-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/config_files-i.ri new file mode 100644 index 00000000..c8f79bfb Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/config_files-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/custom_excludes-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/custom_excludes-i.ri new file mode 100644 index 00000000..4cf7f606 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/custom_excludes-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_handler-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_handler-i.ri new file mode 100644 index 00000000..39e73797 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_handler-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_ignore_paths-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_ignore_paths-i.ri new file mode 100644 index 00000000..6f8d3860 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/listen_ignore_paths-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/normalize_encoding-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/normalize_encoding-i.ri new file mode 100644 index 00000000..ad6c02c4 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/normalize_encoding-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/process-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/process-i.ri new file mode 100644 index 00000000..e60ca82e Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/process-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/sleep_forever-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/sleep_forever-i.ri new file mode 100644 index 00000000..f80ee2c0 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/sleep_forever-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/to_exclude-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/to_exclude-i.ri new file mode 100644 index 00000000..f767553a Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/to_exclude-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/watch-i.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/watch-i.ri new file mode 100644 index 00000000..12727f71 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/Watcher/watch-i.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/cdesc-Jekyll.ri b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/cdesc-Jekyll.ri new file mode 100644 index 00000000..51b3ec3a Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/Jekyll/cdesc-Jekyll.ri differ diff --git a/bin/doc/jekyll-watch-2.2.1/ri/cache.ri b/bin/doc/jekyll-watch-2.2.1/ri/cache.ri new file mode 100644 index 00000000..b92cd835 Binary files /dev/null and b/bin/doc/jekyll-watch-2.2.1/ri/cache.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_after%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_after%3f-i.ri new file mode 100644 index 00000000..c31edd27 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_after%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_before%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_before%3f-i.ri new file mode 100644 index 00000000..36671565 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/apply_template_before%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/basic_generate_id-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/basic_generate_id-i.ri new file mode 100644 index 00000000..bcdbc012 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/basic_generate_id-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/cdesc-Base.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/cdesc-Base.ri new file mode 100644 index 00000000..14ae40cb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/cdesc-Base.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-c.ri new file mode 100644 index 00000000..d9056d94 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-i.ri new file mode 100644 index 00000000..b3302fe5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/data-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/data-i.ri new file mode 100644 index 00000000..9709c741 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/data-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" data:ETI"#Kramdown::Converter::Base#data;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"`Can be used by a converter for storing arbitrary information during the conversion process.;T: +@fileI"#lib/kramdown/converter/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Converter::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language%21-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language%21-i.ri new file mode 100644 index 00000000..256731b6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language%21-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language-i.ri new file mode 100644 index 00000000..93ad5b22 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/extract_code_language-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/format_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/format_math-i.ri new file mode 100644 index 00000000..dc10e1bc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/format_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/generate_id-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/generate_id-i.ri new file mode 100644 index 00000000..7d74e513 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/generate_id-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/highlight_code-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/highlight_code-i.ri new file mode 100644 index 00000000..09ffbb7b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/highlight_code-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/in_toc%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/in_toc%3f-i.ri new file mode 100644 index 00000000..b504098b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/in_toc%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/new-c.ri new file mode 100644 index 00000000..bb6b656b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/options-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/options-i.ri new file mode 100644 index 00000000..cc9f6a9e --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/options-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" options:ETI"&Kramdown::Converter::Base#options;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"*The hash with the conversion options.;T: +@fileI"#lib/kramdown/converter/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Converter::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/output_header_level-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/output_header_level-i.ri new file mode 100644 index 00000000..38666a08 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/output_header_level-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/root-i.ri new file mode 100644 index 00000000..a9ae9b27 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/root-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" root:ETI"#Kramdown::Converter::Base#root;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"(The root element that is converted.;T: +@fileI"#lib/kramdown/converter/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Converter::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/smart_quote_entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/smart_quote_entity-i.ri new file mode 100644 index 00000000..57ebcdc6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/smart_quote_entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warning-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warning-i.ri new file mode 100644 index 00000000..57444576 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warning-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warnings-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warnings-i.ri new file mode 100644 index 00000000..904826ab --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Base/warnings-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" warnings:ETI"'Kramdown::Converter::Base#warnings;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"The warnings array.;T: +@fileI"#lib/kramdown/converter/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Converter::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/cdesc-HashAST.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/cdesc-HashAST.ri new file mode 100644 index 00000000..8b05217d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/cdesc-HashAST.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/convert-i.ri new file mode 100644 index 00000000..f7549a49 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAST/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/cdesc-HashAst.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/cdesc-HashAst.ri new file mode 100644 index 00000000..d0174789 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/cdesc-HashAst.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/convert-i.ri new file mode 100644 index 00000000..f7549a49 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/HashAst/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/add_syntax_highlighter_to_class_attr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/add_syntax_highlighter_to_class_attr-i.ri new file mode 100644 index 00000000..d1584d6d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/add_syntax_highlighter_to_class_attr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/cdesc-Html.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/cdesc-Html.ri new file mode 100644 index 00000000..912a41e8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/cdesc-Html.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert-i.ri new file mode 100644 index 00000000..199ded54 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_a-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_a-i.ri new file mode 100644 index 00000000..4f155c9f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_a-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_abbreviation-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_abbreviation-i.ri new file mode 100644 index 00000000..7f5d098d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_abbreviation-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blank-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blank-i.ri new file mode 100644 index 00000000..ea2adf25 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blank-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blockquote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blockquote-i.ri new file mode 100644 index 00000000..d1db578a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_blockquote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_br-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_br-i.ri new file mode 100644 index 00000000..07aa732c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_br-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codeblock-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codeblock-i.ri new file mode 100644 index 00000000..024a01ed Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codeblock-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codespan-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codespan-i.ri new file mode 100644 index 00000000..f249103b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_codespan-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_comment-i.ri new file mode 100644 index 00000000..246ff6b6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dd-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dd-i.ri new file mode 100644 index 00000000..eea1860f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dd-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dl-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dl-i.ri new file mode 100644 index 00000000..59d837d6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dl-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dt-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dt-i.ri new file mode 100644 index 00000000..2388e7aa Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_dt-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_em-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_em-i.ri new file mode 100644 index 00000000..5d62dd29 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_em-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_entity-i.ri new file mode 100644 index 00000000..3eaefc06 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_footnote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_footnote-i.ri new file mode 100644 index 00000000..8853d680 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_footnote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_header-i.ri new file mode 100644 index 00000000..790633f6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_hr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_hr-i.ri new file mode 100644 index 00000000..ea204a6d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_hr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_html_element-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_html_element-i.ri new file mode 100644 index 00000000..11498477 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_html_element-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_img-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_img-i.ri new file mode 100644 index 00000000..a7350eb1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_img-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_li-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_li-i.ri new file mode 100644 index 00000000..06622689 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_li-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_math-i.ri new file mode 100644 index 00000000..36cbe906 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ol-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ol-i.ri new file mode 100644 index 00000000..9ca27ba2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ol-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_p-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_p-i.ri new file mode 100644 index 00000000..9ebcc64b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_p-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_raw-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_raw-i.ri new file mode 100644 index 00000000..83fd9b33 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_raw-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_root-i.ri new file mode 100644 index 00000000..742a2506 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_root-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_smart_quote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_smart_quote-i.ri new file mode 100644 index 00000000..c7bd76df Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_smart_quote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_standalone_image-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_standalone_image-i.ri new file mode 100644 index 00000000..9676327d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_standalone_image-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_strong-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_strong-i.ri new file mode 100644 index 00000000..5f7b4bc9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_strong-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_table-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_table-i.ri new file mode 100644 index 00000000..8234fedb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_table-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tbody-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tbody-i.ri new file mode 100644 index 00000000..7dd5242d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tbody-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_td-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_td-i.ri new file mode 100644 index 00000000..11236db8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_td-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_text-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_text-i.ri new file mode 100644 index 00000000..e3919074 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_text-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tfoot-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tfoot-i.ri new file mode 100644 index 00000000..15b9ae47 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tfoot-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_thead-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_thead-i.ri new file mode 100644 index 00000000..3e976aad Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_thead-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tr-i.ri new file mode 100644 index 00000000..47bc1a49 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_tr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_typographic_sym-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_typographic_sym-i.ri new file mode 100644 index 00000000..f4d9ec55 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_typographic_sym-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ul-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ul-i.ri new file mode 100644 index 00000000..037fcb09 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_ul-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_comment-i.ri new file mode 100644 index 00000000..896becfe Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_pi-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_pi-i.ri new file mode 100644 index 00000000..2b7c4ae2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/convert_xml_pi-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/fix_for_toc_entry-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/fix_for_toc_entry-i.ri new file mode 100644 index 00000000..86174ce3 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/fix_for_toc_entry-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/footnote_content-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/footnote_content-i.ri new file mode 100644 index 00000000..171ede19 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/footnote_content-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_block_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_block_html-i.ri new file mode 100644 index 00000000..7e7b3d7e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_block_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_indented_block_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_indented_block_html-i.ri new file mode 100644 index 00000000..c749efd1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_indented_block_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_span_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_span_html-i.ri new file mode 100644 index 00000000..50a10fed Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/format_as_span_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/generate_toc_tree-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/generate_toc_tree-i.ri new file mode 100644 index 00000000..347a3048 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/generate_toc_tree-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/indent-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/indent-i.ri new file mode 100644 index 00000000..56cebd3d --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/indent-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" indent:ETI"%Kramdown::Converter::Html#indent;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I";The amount of indentation used when nesting HTML tags.;T: +@fileI"#lib/kramdown/converter/html.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Converter::Html;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/inner-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/inner-i.ri new file mode 100644 index 00000000..e589e2e0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/inner-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/new-c.ri new file mode 100644 index 00000000..eb3a899a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/obfuscate-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/obfuscate-i.ri new file mode 100644 index 00000000..a6866bf9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/obfuscate-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/remove_footnotes-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/remove_footnotes-i.ri new file mode 100644 index 00000000..32e70d2c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/remove_footnotes-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/unwrap_links-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/unwrap_links-i.ri new file mode 100644 index 00000000..fe7643cc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Html/unwrap_links-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Kramdown/cdesc-Kramdown.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Kramdown/cdesc-Kramdown.ri new file mode 100644 index 00000000..6377316d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Kramdown/cdesc-Kramdown.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/attribute_list-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/attribute_list-i.ri new file mode 100644 index 00000000..c2ba2a6e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/attribute_list-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/cdesc-Latex.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/cdesc-Latex.ri new file mode 100644 index 00000000..0cf85d19 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/cdesc-Latex.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert-i.ri new file mode 100644 index 00000000..2c54986a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_a-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_a-i.ri new file mode 100644 index 00000000..befda0ec Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_a-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_abbreviation-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_abbreviation-i.ri new file mode 100644 index 00000000..9dccd37e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_abbreviation-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blank-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blank-i.ri new file mode 100644 index 00000000..b142e9f4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blank-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blockquote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blockquote-i.ri new file mode 100644 index 00000000..fde81649 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_blockquote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_br-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_br-i.ri new file mode 100644 index 00000000..2790d0aa Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_br-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codeblock-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codeblock-i.ri new file mode 100644 index 00000000..56f9eb25 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codeblock-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codespan-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codespan-i.ri new file mode 100644 index 00000000..13a63915 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_codespan-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_comment-i.ri new file mode 100644 index 00000000..e68f4edb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dd-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dd-i.ri new file mode 100644 index 00000000..3ecb9c57 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dd-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dl-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dl-i.ri new file mode 100644 index 00000000..5295e137 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dl-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dt-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dt-i.ri new file mode 100644 index 00000000..2544db9e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_dt-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_em-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_em-i.ri new file mode 100644 index 00000000..7d052a36 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_em-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_entity-i.ri new file mode 100644 index 00000000..0a0afc28 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_footnote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_footnote-i.ri new file mode 100644 index 00000000..5cbc728e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_footnote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_header-i.ri new file mode 100644 index 00000000..1b43df9f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_hr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_hr-i.ri new file mode 100644 index 00000000..e1cd37ff Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_hr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_html_element-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_html_element-i.ri new file mode 100644 index 00000000..f9b831bb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_html_element-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_img-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_img-i.ri new file mode 100644 index 00000000..5003c337 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_img-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_li-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_li-i.ri new file mode 100644 index 00000000..55e06efb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_li-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_math-i.ri new file mode 100644 index 00000000..91cfab87 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ol-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ol-i.ri new file mode 100644 index 00000000..f9ad2c3f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ol-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_p-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_p-i.ri new file mode 100644 index 00000000..a4994a83 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_p-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_raw-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_raw-i.ri new file mode 100644 index 00000000..6644bbdf Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_raw-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_root-i.ri new file mode 100644 index 00000000..8802cd10 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_root-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_smart_quote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_smart_quote-i.ri new file mode 100644 index 00000000..51964cc8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_smart_quote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_standalone_image-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_standalone_image-i.ri new file mode 100644 index 00000000..48558cf7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_standalone_image-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_strong-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_strong-i.ri new file mode 100644 index 00000000..ca4a9073 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_strong-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_table-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_table-i.ri new file mode 100644 index 00000000..5e4c0eda Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_table-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tbody-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tbody-i.ri new file mode 100644 index 00000000..f174df43 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tbody-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_td-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_td-i.ri new file mode 100644 index 00000000..67c9089d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_td-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_text-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_text-i.ri new file mode 100644 index 00000000..991c4198 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_text-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tfoot-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tfoot-i.ri new file mode 100644 index 00000000..fb8fea29 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tfoot-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_thead-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_thead-i.ri new file mode 100644 index 00000000..fd26c3a2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_thead-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tr-i.ri new file mode 100644 index 00000000..7552bb3d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_tr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_typographic_sym-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_typographic_sym-i.ri new file mode 100644 index 00000000..e9ae53ca Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_typographic_sym-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ul-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ul-i.ri new file mode 100644 index 00000000..92bf7eb0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_ul-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_comment-i.ri new file mode 100644 index 00000000..01df58dc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_pi-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_pi-i.ri new file mode 100644 index 00000000..af2ab0de Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/convert_xml_pi-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/entity_to_latex-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/entity_to_latex-i.ri new file mode 100644 index 00000000..4accc49f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/entity_to_latex-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/escape-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/escape-i.ri new file mode 100644 index 00000000..d37cc2b1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/escape-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/inner-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/inner-i.ri new file mode 100644 index 00000000..31778ccb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/inner-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_environment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_environment-i.ri new file mode 100644 index 00000000..6abccc2b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_environment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_link_target-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_link_target-i.ri new file mode 100644 index 00000000..e7bcc198 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/latex_link_target-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/new-c.ri new file mode 100644 index 00000000..4f849bc4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/normalize_abbreviation_key-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/normalize_abbreviation_key-i.ri new file mode 100644 index 00000000..a863a5bf Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Latex/normalize_abbreviation_key-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/cdesc-Man.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/cdesc-Man.ri new file mode 100644 index 00000000..fb0114c4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/cdesc-Man.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_a-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_a-i.ri new file mode 100644 index 00000000..feb970b7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_a-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_abbreviation-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_abbreviation-i.ri new file mode 100644 index 00000000..6ea6413e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_abbreviation-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blank-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blank-i.ri new file mode 100644 index 00000000..b949e91f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blank-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blockquote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blockquote-i.ri new file mode 100644 index 00000000..41efc305 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_blockquote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_br-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_br-i.ri new file mode 100644 index 00000000..fbdce661 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_br-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codeblock-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codeblock-i.ri new file mode 100644 index 00000000..386f8717 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codeblock-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codespan-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codespan-i.ri new file mode 100644 index 00000000..e35dc8cc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_codespan-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_comment-i.ri new file mode 100644 index 00000000..9096cf9c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dd-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dd-i.ri new file mode 100644 index 00000000..73221742 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dd-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dl-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dl-i.ri new file mode 100644 index 00000000..4ef5b778 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dl-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dt-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dt-i.ri new file mode 100644 index 00000000..be411e4a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_dt-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_em-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_em-i.ri new file mode 100644 index 00000000..d959051e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_em-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_entity-i.ri new file mode 100644 index 00000000..155a3d96 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_footnote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_footnote-i.ri new file mode 100644 index 00000000..d05456bf Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_footnote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_header-i.ri new file mode 100644 index 00000000..4d59a56c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_hr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_hr-i.ri new file mode 100644 index 00000000..482366b0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_hr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_html_element-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_html_element-i.ri new file mode 100644 index 00000000..2ab0b1a3 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_html_element-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_img-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_img-i.ri new file mode 100644 index 00000000..9951c2f9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_img-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_li-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_li-i.ri new file mode 100644 index 00000000..f6e3db3d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_li-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_math-i.ri new file mode 100644 index 00000000..7cc0ab4d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ol-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ol-i.ri new file mode 100644 index 00000000..cfe9f6d0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ol-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_p-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_p-i.ri new file mode 100644 index 00000000..e16c3e94 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_p-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_raw-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_raw-i.ri new file mode 100644 index 00000000..33f7258f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_raw-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_root-i.ri new file mode 100644 index 00000000..b33507b5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_root-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_smart_quote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_smart_quote-i.ri new file mode 100644 index 00000000..248807c0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_smart_quote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_strong-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_strong-i.ri new file mode 100644 index 00000000..d86e268a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_strong-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_table-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_table-i.ri new file mode 100644 index 00000000..c48f9825 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_table-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tbody-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tbody-i.ri new file mode 100644 index 00000000..c7a44ff1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tbody-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_td-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_td-i.ri new file mode 100644 index 00000000..2ae8aa62 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_td-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_text-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_text-i.ri new file mode 100644 index 00000000..8845bc1b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_text-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tfoot-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tfoot-i.ri new file mode 100644 index 00000000..0fc60fb8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tfoot-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_thead-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_thead-i.ri new file mode 100644 index 00000000..ac2b9b84 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_thead-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tr-i.ri new file mode 100644 index 00000000..78032f27 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_tr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_typographic_sym-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_typographic_sym-i.ri new file mode 100644 index 00000000..99419c74 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_typographic_sym-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ul-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ul-i.ri new file mode 100644 index 00000000..be268733 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_ul-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_comment-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_comment-i.ri new file mode 100644 index 00000000..45bbbb80 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_comment-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_pi-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_pi-i.ri new file mode 100644 index 00000000..46ca8177 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/convert_xml_pi-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/escape-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/escape-i.ri new file mode 100644 index 00000000..c8c2cedb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/escape-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/inner-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/inner-i.ri new file mode 100644 index 00000000..209b7d49 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/inner-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/macro-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/macro-i.ri new file mode 100644 index 00000000..81d80e7e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/macro-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/newline-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/newline-i.ri new file mode 100644 index 00000000..012a738d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/newline-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/quote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/quote-i.ri new file mode 100644 index 00000000..35c16a69 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/quote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/unicode_char-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/unicode_char-i.ri new file mode 100644 index 00000000..3ea13196 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Man/unicode_char-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/call-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/call-c.ri new file mode 100644 index 00000000..55af4d58 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/call-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/cdesc-Mathjax.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/cdesc-Mathjax.ri new file mode 100644 index 00000000..0120caa3 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/Mathjax/cdesc-Mathjax.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/cdesc-MathEngine.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/cdesc-MathEngine.ri new file mode 100644 index 00000000..e3415fc0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/MathEngine/cdesc-MathEngine.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/cdesc-RemoveHtmlTags.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/cdesc-RemoveHtmlTags.ri new file mode 100644 index 00000000..37368471 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/cdesc-RemoveHtmlTags.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/convert-i.ri new file mode 100644 index 00000000..dd6088b0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/new-c.ri new file mode 100644 index 00000000..a1b05424 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/RemoveHtmlTags/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/call-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/call-c.ri new file mode 100644 index 00000000..13913b23 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/call-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/cdesc-Minted.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/cdesc-Minted.ri new file mode 100644 index 00000000..f98109b1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Minted/cdesc-Minted.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/call-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/call-c.ri new file mode 100644 index 00000000..837cd457 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/call-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/cdesc-Rouge.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/cdesc-Rouge.ri new file mode 100644 index 00000000..d5489285 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/cdesc-Rouge.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/formatter_class-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/formatter_class-c.ri new file mode 100644 index 00000000..71cc3dee Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/formatter_class-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/normalize_keys-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/normalize_keys-c.ri new file mode 100644 index 00000000..78fae723 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/normalize_keys-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/options-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/options-c.ri new file mode 100644 index 00000000..67f89c68 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/options-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/prepare_options-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/prepare_options-c.ri new file mode 100644 index 00000000..0c7922a6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/Rouge/prepare_options-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/cdesc-SyntaxHighlighter.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/cdesc-SyntaxHighlighter.ri new file mode 100644 index 00000000..1c2025e1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/SyntaxHighlighter/cdesc-SyntaxHighlighter.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/add_to_toc-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/add_to_toc-i.ri new file mode 100644 index 00000000..ebbc3316 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/add_to_toc-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/cdesc-Toc.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/cdesc-Toc.ri new file mode 100644 index 00000000..a52313d5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/cdesc-Toc.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/convert-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/convert-i.ri new file mode 100644 index 00000000..4dd25d9c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/convert-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/new-c.ri new file mode 100644 index 00000000..b984637b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/Toc/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/cdesc-Converter.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/cdesc-Converter.ri new file mode 100644 index 00000000..abdcbf93 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Converter/cdesc-Converter.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/cdesc-Document.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/cdesc-Document.ri new file mode 100644 index 00000000..a19f7405 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/cdesc-Document.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/method_missing-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/method_missing-i.ri new file mode 100644 index 00000000..f9c5837d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/method_missing-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/new-c.ri new file mode 100644 index 00000000..503f1c82 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/options-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/options-i.ri new file mode 100644 index 00000000..824f77d8 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/options-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" options:ETI"Kramdown::Document#options;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"[The options hash which holds the options for parsing/converting the Kramdown document.;T: +@fileI"lib/kramdown/document.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Document;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/root-i.ri new file mode 100644 index 00000000..5909bf71 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/root-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" root:ETI"Kramdown::Document#root;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"bThe root Element of the element tree. It is immediately available after the ::new method has ;TI"been called.;T: +@fileI"lib/kramdown/document.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Document;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/try_require-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/try_require-i.ri new file mode 100644 index 00000000..698ef87c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/try_require-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/warnings-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/warnings-i.ri new file mode 100644 index 00000000..3176c037 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Document/warnings-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" warnings:ETI" Kramdown::Document#warnings;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"`An array of warning messages. It is filled with warnings during the parsing phase (i.e. in ;TI"%::new) and the conversion phase.;T: +@fileI"lib/kramdown/document.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Document;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/attr-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/attr-i.ri new file mode 100644 index 00000000..81bbcd7b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/attr-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/block%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/block%3f-i.ri new file mode 100644 index 00000000..2cc9d544 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/block%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/category-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/category-c.ri new file mode 100644 index 00000000..a1a7d9db Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/category-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/cdesc-Element.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/cdesc-Element.ri new file mode 100644 index 00000000..a5533d97 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/cdesc-Element.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/children-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/children-i.ri new file mode 100644 index 00000000..c2b7d966 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/children-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" children:ETI"Kramdown::Element#children;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"(The child elements of this element.;T: +@fileI"lib/kramdown/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/new-c.ri new file mode 100644 index 00000000..271c783a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/options-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/options-i.ri new file mode 100644 index 00000000..591057b7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/options-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/span%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/span%3f-i.ri new file mode 100644 index 00000000..eefd543b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/span%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/type-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/type-i.ri new file mode 100644 index 00000000..3dd4eb10 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/type-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" type:ETI"Kramdown::Element#type;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"LA symbol representing the element type. For example, :p or :blockquote.;T: +@fileI"lib/kramdown/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/value-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/value-i.ri new file mode 100644 index 00000000..3848a30f --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Element/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"Kramdown::Element#value;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"dThe value of the element. The interpretation of this field depends on the type of the element. ;TI"(Many elements don't use this field.;T: +@fileI"lib/kramdown/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Error/cdesc-Error.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Error/cdesc-Error.ri new file mode 100644 index 00000000..ccbd3ea7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Error/cdesc-Error.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/%3d%3d%3d-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/%3d%3d%3d-c.ri new file mode 100644 index 00000000..afc3ec18 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/%3d%3d%3d-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/cdesc-Boolean.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/cdesc-Boolean.ri new file mode 100644 index 00000000..069f5564 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/Boolean/cdesc-Boolean.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/cdesc-Options.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/cdesc-Options.ri new file mode 100644 index 00000000..61b80bd2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/cdesc-Options.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defaults-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defaults-c.ri new file mode 100644 index 00000000..0f2dab8f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defaults-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/define-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/define-c.ri new file mode 100644 index 00000000..45fe2441 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/define-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defined%3f-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defined%3f-c.ri new file mode 100644 index 00000000..68dcad86 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/defined%3f-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/definitions-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/definitions-c.ri new file mode 100644 index 00000000..b46861ff Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/definitions-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/merge-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/merge-c.ri new file mode 100644 index 00000000..87ab16eb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/merge-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/parse-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/parse-c.ri new file mode 100644 index 00000000..446fee5e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/parse-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_array_validator-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_array_validator-c.ri new file mode 100644 index 00000000..a6efbaff Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_array_validator-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_hash_validator-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_hash_validator-c.ri new file mode 100644 index 00000000..e4ccae09 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/simple_hash_validator-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/str_to_sym-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/str_to_sym-c.ri new file mode 100644 index 00000000..c084b146 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Options/str_to_sym-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/adapt_source-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/adapt_source-i.ri new file mode 100644 index 00000000..fd34ad02 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/adapt_source-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/add_text-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/add_text-i.ri new file mode 100644 index 00000000..672e9ce8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/add_text-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/cdesc-Base.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/cdesc-Base.ri new file mode 100644 index 00000000..913167cd Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/cdesc-Base.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/extract_string-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/extract_string-i.ri new file mode 100644 index 00000000..0a89de11 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/extract_string-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/new-c.ri new file mode 100644 index 00000000..288c8e1c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/options-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/options-i.ri new file mode 100644 index 00000000..ae8b6295 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/options-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" options:ETI"#Kramdown::Parser::Base#options;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"'The hash with the parsing options.;T: +@fileI" lib/kramdown/parser/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Parser::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-c.ri new file mode 100644 index 00000000..d2a3ca86 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-i.ri new file mode 100644 index 00000000..58158c38 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/parse-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/root-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/root-i.ri new file mode 100644 index 00000000..34ac85cc --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/root-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" root:ETI" Kramdown::Parser::Base#root;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"MThe root element of element tree that is created from the source string.;T: +@fileI" lib/kramdown/parser/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Parser::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/source-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/source-i.ri new file mode 100644 index 00000000..2c3a8dc2 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/source-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" source:ETI""Kramdown::Parser::Base#source;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I" The original source string.;T: +@fileI" lib/kramdown/parser/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Parser::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warning-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warning-i.ri new file mode 100644 index 00000000..bc4b9a4e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warning-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warnings-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warnings-i.ri new file mode 100644 index 00000000..9f02dfdc --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Base/warnings-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" warnings:ETI"$Kramdown::Parser::Base#warnings;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"(The array with the parser warnings.;T: +@fileI" lib/kramdown/parser/base.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Kramdown::Parser::Base;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Constants/cdesc-Constants.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Constants/cdesc-Constants.ri new file mode 100644 index 00000000..9c867280 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Constants/cdesc-Constants.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/ElementConverter/cdesc-ElementConverter.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/ElementConverter/cdesc-ElementConverter.ri new file mode 100644 index 00000000..fc6a6dc8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/ElementConverter/cdesc-ElementConverter.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/cdesc-Parser.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/cdesc-Parser.ri new file mode 100644 index 00000000..8659e65c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/cdesc-Parser.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_html_start_tag-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_html_start_tag-i.ri new file mode 100644 index 00000000..b8d9326a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_html_start_tag-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_raw_html_tag-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_raw_html_tag-i.ri new file mode 100644 index 00000000..9a279b48 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/handle_raw_html_tag-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_html_attributes-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_html_attributes-i.ri new file mode 100644 index 00000000..1a214fc2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_html_attributes-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_raw_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_raw_html-i.ri new file mode 100644 index 00000000..1350ace5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/Parser/parse_raw_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/cdesc-Html.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/cdesc-Html.ri new file mode 100644 index 00000000..c3d172dc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/cdesc-Html.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/parse-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/parse-i.ri new file mode 100644 index 00000000..7312daa1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Html/parse-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_header-i.ri new file mode 100644 index 00000000..ba3afc7c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_link-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_link-i.ri new file mode 100644 index 00000000..52db42bf Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/add_link-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/after_block_boundary%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/after_block_boundary%3f-i.ri new file mode 100644 index 00000000..5f7db647 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/after_block_boundary%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/before_block_boundary%3f-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/before_block_boundary%3f-i.ri new file mode 100644 index 00000000..fefec8c6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/before_block_boundary%3f-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/cdesc-Kramdown.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/cdesc-Kramdown.ri new file mode 100644 index 00000000..133a4b52 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/cdesc-Kramdown.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/configure_parser-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/configure_parser-i.ri new file mode 100644 index 00000000..cccf58e4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/configure_parser-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/correct_abbreviations_attributes-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/correct_abbreviations_attributes-i.ri new file mode 100644 index 00000000..89884b04 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/correct_abbreviations_attributes-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/define_parser-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/define_parser-c.ri new file mode 100644 index 00000000..b9cf6261 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/define_parser-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/fetch_pattern-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/fetch_pattern-i.ri new file mode 100644 index 00000000..1f57a1d5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/fetch_pattern-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_extension-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_extension-i.ri new file mode 100644 index 00000000..4e0003c1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_extension-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_kramdown_html_tag-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_kramdown_html_tag-i.ri new file mode 100644 index 00000000..530d431a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/handle_kramdown_html_tag-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/has_parser%3f-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/has_parser%3f-c.ri new file mode 100644 index 00000000..4e3a4252 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/has_parser%3f-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new-c.ri new file mode 100644 index 00000000..fef8600d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new_block_el-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new_block_el-i.ri new file mode 100644 index 00000000..1d9eca29 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/new_block_el-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/normalize_link_id-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/normalize_link_id-i.ri new file mode 100644 index 00000000..deeb4394 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/normalize_link_id-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/paragraph_end-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/paragraph_end-i.ri new file mode 100644 index 00000000..1dd6b56c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/paragraph_end-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse-i.ri new file mode 100644 index 00000000..8c16b06e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_abbrev_definition-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_abbrev_definition-i.ri new file mode 100644 index 00000000..646b1420 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_abbrev_definition-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_attribute_list-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_attribute_list-i.ri new file mode 100644 index 00000000..a768e4cb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_attribute_list-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_atx_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_atx_header-i.ri new file mode 100644 index 00000000..ada13f81 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_atx_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_autolink-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_autolink-i.ri new file mode 100644 index 00000000..7c177c2a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_autolink-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blank_line-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blank_line-i.ri new file mode 100644 index 00000000..08788034 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blank_line-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_extensions-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_extensions-i.ri new file mode 100644 index 00000000..75f57249 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_extensions-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_html-i.ri new file mode 100644 index 00000000..b6736961 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_math-i.ri new file mode 100644 index 00000000..b9f85d18 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_block_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blockquote-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blockquote-i.ri new file mode 100644 index 00000000..aaccfbfb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blockquote-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blocks-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blocks-i.ri new file mode 100644 index 00000000..a3a014d7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_blocks-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock-i.ri new file mode 100644 index 00000000..1539aa51 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock_fenced-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock_fenced-i.ri new file mode 100644 index 00000000..10d8b9b4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codeblock_fenced-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codespan-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codespan-i.ri new file mode 100644 index 00000000..91520313 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_codespan-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_definition_list-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_definition_list-i.ri new file mode 100644 index 00000000..56bf60f7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_definition_list-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_emphasis-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_emphasis-i.ri new file mode 100644 index 00000000..3f957268 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_emphasis-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_eob_marker-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_eob_marker-i.ri new file mode 100644 index 00000000..3e2447c8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_eob_marker-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_escaped_chars-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_escaped_chars-i.ri new file mode 100644 index 00000000..7970feed Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_escaped_chars-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_extension_start_tag-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_extension_start_tag-i.ri new file mode 100644 index 00000000..c4f2570a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_extension_start_tag-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_first_list_line-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_first_list_line-i.ri new file mode 100644 index 00000000..34a45c91 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_first_list_line-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_definition-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_definition-i.ri new file mode 100644 index 00000000..8b083d45 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_definition-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_marker-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_marker-i.ri new file mode 100644 index 00000000..e0e47e7d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_footnote_marker-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_header_contents-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_header_contents-i.ri new file mode 100644 index 00000000..40ead7c7 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_header_contents-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_horizontal_rule-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_horizontal_rule-i.ri new file mode 100644 index 00000000..7e664efc Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_horizontal_rule-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_html_entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_html_entity-i.ri new file mode 100644 index 00000000..39011180 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_html_entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_inline_math-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_inline_math-i.ri new file mode 100644 index 00000000..e53ff7d9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_inline_math-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_line_break-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_line_break-i.ri new file mode 100644 index 00000000..8a2eb96d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_line_break-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link-i.ri new file mode 100644 index 00000000..eb222ba1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link_definition-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link_definition-i.ri new file mode 100644 index 00000000..c74d9f26 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_link_definition-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_list-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_list-i.ri new file mode 100644 index 00000000..a6752dd0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_list-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_paragraph-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_paragraph-i.ri new file mode 100644 index 00000000..3d3d1e41 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_paragraph-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_setext_header-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_setext_header-i.ri new file mode 100644 index 00000000..8ba23338 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_setext_header-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_smart_quotes-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_smart_quotes-i.ri new file mode 100644 index 00000000..2eac7cd2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_smart_quotes-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_extensions-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_extensions-i.ri new file mode 100644 index 00000000..bb43bf3a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_extensions-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_html-i.ri new file mode 100644 index 00000000..5881f4b4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_span_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_spans-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_spans-i.ri new file mode 100644 index 00000000..10eba173 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_spans-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_table-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_table-i.ri new file mode 100644 index 00000000..f783fe07 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_table-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_typographic_syms-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_typographic_syms-i.ri new file mode 100644 index 00000000..30d90d8f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parse_typographic_syms-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parser-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parser-c.ri new file mode 100644 index 00000000..ed3d1e0b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/parser-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/replace_abbreviations-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/replace_abbreviations-i.ri new file mode 100644 index 00000000..de92fc46 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/replace_abbreviations-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/reset_env-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/reset_env-i.ri new file mode 100644 index 00000000..e8558b7d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/reset_env-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/restore_env-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/restore_env-i.ri new file mode 100644 index 00000000..0878159d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/restore_env-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/save_env-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/save_env-i.ri new file mode 100644 index 00000000..aa9df0a9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/save_env-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_parser_regexps-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_parser_regexps-i.ri new file mode 100644 index 00000000..1e7b0bb0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_parser_regexps-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_pattern_cache-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_pattern_cache-i.ri new file mode 100644 index 00000000..d879e180 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/span_pattern_cache-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_attr_with_ial-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_attr_with_ial-i.ri new file mode 100644 index 00000000..96dc24a0 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_attr_with_ial-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_ial_with_ial-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_ial_with_ial-i.ri new file mode 100644 index 00000000..11807e7e Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_ial_with_ial-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_link_definitions-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_link_definitions-i.ri new file mode 100644 index 00000000..3142c215 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_link_definitions-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_raw_text-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_raw_text-i.ri new file mode 100644 index 00000000..a73fb0e4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_raw_text-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_tree-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_tree-i.ri new file mode 100644 index 00000000..28f8d124 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Kramdown/update_tree-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Markdown/cdesc-Markdown.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Markdown/cdesc-Markdown.ri new file mode 100644 index 00000000..b79356c2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/Markdown/cdesc-Markdown.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/cdesc-Parser.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/cdesc-Parser.ri new file mode 100644 index 00000000..0e0155a4 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Parser/cdesc-Parser.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/cdesc-Configurable.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/cdesc-Configurable.ri new file mode 100644 index 00000000..1b7583f6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/cdesc-Configurable.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/configurable-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/configurable-i.ri new file mode 100644 index 00000000..033208f5 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Configurable/configurable-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/cdesc-Entities.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/cdesc-Entities.ri new file mode 100644 index 00000000..4f233472 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/cdesc-Entities.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-c.ri new file mode 100644 index 00000000..b28adf24 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-i.ri new file mode 100644 index 00000000..b9eb2849 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Entities/entity-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/cdesc-Html.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/cdesc-Html.ri new file mode 100644 index 00000000..0f2fbfb8 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/cdesc-Html.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/entity_to_str-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/entity_to_str-i.ri new file mode 100644 index 00000000..7c6f67e1 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/entity_to_str-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/escape_html-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/escape_html-i.ri new file mode 100644 index 00000000..f5d99f2c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/escape_html-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/fix_cjk_line_break-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/fix_cjk_line_break-i.ri new file mode 100644 index 00000000..58e3877b Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/fix_cjk_line_break-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/html_attributes-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/html_attributes-i.ri new file mode 100644 index 00000000..26d0c79a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Html/html_attributes-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d%3d-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d%3d-i.ri new file mode 100644 index 00000000..5368f8c6 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d%3d-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d-i.ri new file mode 100644 index 00000000..40e6ebc9 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/%5b%5d-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/cdesc-LRUCache.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/cdesc-LRUCache.ri new file mode 100644 index 00000000..a2d4d6f3 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/cdesc-LRUCache.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/new-c.ri new file mode 100644 index 00000000..5dfbc81c Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/LRUCache/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/cdesc-StringScanner.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/cdesc-StringScanner.ri new file mode 100644 index 00000000..ec796397 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/cdesc-StringScanner.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/current_line_number-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/current_line_number-i.ri new file mode 100644 index 00000000..eb56e75d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/current_line_number-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/new-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/new-c.ri new file mode 100644 index 00000000..c517a932 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/new-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/pos%3d-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/pos%3d-i.ri new file mode 100644 index 00000000..98d09425 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/pos%3d-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/revert_pos-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/revert_pos-i.ri new file mode 100644 index 00000000..cf29bd8d Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/revert_pos-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/save_pos-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/save_pos-i.ri new file mode 100644 index 00000000..e396040f Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/save_pos-i.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/start_line_number-i.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/start_line_number-i.ri new file mode 100644 index 00000000..a98c15e5 --- /dev/null +++ b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/StringScanner/start_line_number-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"start_line_number:ETI"5Kramdown::Utils::StringScanner#start_line_number;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"`The start line number. Used for nested StringScanners that scan a sub-string of the source ;TI"Kdocument. The kramdown parser uses this, e.g., for span level parsers.;T: +@fileI")lib/kramdown/utils/string_scanner.rb;T:0@omit_headings_from_table_of_contents_below0F@I"#Kramdown::Utils::StringScanner;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/cdesc-Unidecoder.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/cdesc-Unidecoder.ri new file mode 100644 index 00000000..f1b3c1e2 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/cdesc-Unidecoder.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/decode-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/decode-c.ri new file mode 100644 index 00000000..d7173a15 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/Unidecoder/decode-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/camelize-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/camelize-c.ri new file mode 100644 index 00000000..73f4ef50 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/camelize-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/cdesc-Utils.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/cdesc-Utils.ri new file mode 100644 index 00000000..2cba42eb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/cdesc-Utils.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/deep_const_get-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/deep_const_get-c.ri new file mode 100644 index 00000000..24e847ad Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/deep_const_get-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/snake_case-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/snake_case-c.ri new file mode 100644 index 00000000..6a87e13a Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/Utils/snake_case-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/cdesc-Kramdown.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/cdesc-Kramdown.ri new file mode 100644 index 00000000..191049fb Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/cdesc-Kramdown.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/Kramdown/data_dir-c.ri b/bin/doc/kramdown-2.5.2/ri/Kramdown/data_dir-c.ri new file mode 100644 index 00000000..f3dfe910 Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/Kramdown/data_dir-c.ri differ diff --git a/bin/doc/kramdown-2.5.2/ri/cache.ri b/bin/doc/kramdown-2.5.2/ri/cache.ri new file mode 100644 index 00000000..710d37ab Binary files /dev/null and b/bin/doc/kramdown-2.5.2/ri/cache.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Options/cdesc-Options.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Options/cdesc-Options.ri new file mode 100644 index 00000000..65835516 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Options/cdesc-Options.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/cdesc-GFM.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/cdesc-GFM.ri new file mode 100644 index 00000000..502fe7b8 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/cdesc-GFM.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/generate_gfm_header_id-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/generate_gfm_header_id-i.ri new file mode 100644 index 00000000..1fd94f7e Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/generate_gfm_header_id-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/new-c.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/new-c.ri new file mode 100644 index 00000000..1761078e Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/new-c.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/paragraph_end-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/paragraph_end-i.ri new file mode 100644 index 00000000..dedb7809 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/paragraph_end-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse-i.ri new file mode 100644 index 00000000..3a89cdb6 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_atx_header_gfm_quirk-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_atx_header_gfm_quirk-i.ri new file mode 100644 index 00000000..7ffcd8fb Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_atx_header_gfm_quirk-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_list-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_list-i.ri new file mode 100644 index 00000000..bf1593df Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_list-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_strikethrough_gfm-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_strikethrough_gfm-i.ri new file mode 100644 index 00000000..821c306b Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/parse_strikethrough_gfm-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_elements-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_elements-i.ri new file mode 100644 index 00000000..d12b5bc7 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_elements-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_raw_text-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_raw_text-i.ri new file mode 100644 index 00000000..4a5cacf1 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_raw_text-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_text_type-i.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_text_type-i.ri new file mode 100644 index 00000000..691873d1 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/GFM/update_text_type-i.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/cdesc-Parser.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/cdesc-Parser.ri new file mode 100644 index 00000000..2535a5f5 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/Parser/cdesc-Parser.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/cdesc-Kramdown.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/cdesc-Kramdown.ri new file mode 100644 index 00000000..5ec7c180 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/Kramdown/cdesc-Kramdown.ri differ diff --git a/bin/doc/kramdown-parser-gfm-1.1.0/ri/cache.ri b/bin/doc/kramdown-parser-gfm-1.1.0/ri/cache.ri new file mode 100644 index 00000000..40fcfd81 Binary files /dev/null and b/bin/doc/kramdown-parser-gfm-1.1.0/ri/cache.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Array/cdesc-Array.ri b/bin/doc/liquid-4.0.4/ri/Array/cdesc-Array.ri new file mode 100644 index 00000000..6fc85ce2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Array/cdesc-Array.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Date/cdesc-Date.ri b/bin/doc/liquid-4.0.4/ri/Date/cdesc-Date.ri new file mode 100644 index 00000000..93812628 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Date/cdesc-Date.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/DateTime/cdesc-DateTime.ri b/bin/doc/liquid-4.0.4/ri/DateTime/cdesc-DateTime.ri new file mode 100644 index 00000000..ac03cb31 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/DateTime/cdesc-DateTime.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/FalseClass/cdesc-FalseClass.ri b/bin/doc/liquid-4.0.4/ri/FalseClass/cdesc-FalseClass.ri new file mode 100644 index 00000000..b3a192ae Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/FalseClass/cdesc-FalseClass.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Hash/cdesc-Hash.ri b/bin/doc/liquid-4.0.4/ri/Hash/cdesc-Hash.ri new file mode 100644 index 00000000..cac36477 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Hash/cdesc-Hash.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..2123f5e5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..52b54e21 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/assign_score_of-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/assign_score_of-i.ri new file mode 100644 index 00000000..2f672167 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/assign_score_of-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/blank%3f-i.ri new file mode 100644 index 00000000..dcd49734 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/cdesc-Assign.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/cdesc-Assign.ri new file mode 100644 index 00000000..4cdb77c3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/cdesc-Assign.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/from-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/from-i.ri new file mode 100644 index 00000000..3465723e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/from-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/new-c.ri new file mode 100644 index 00000000..d9714c0d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/render-i.ri new file mode 100644 index 00000000..9409848e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Assign/to-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/to-i.ri new file mode 100644 index 00000000..6d537d26 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Assign/to-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/cdesc-BlankFileSystem.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/cdesc-BlankFileSystem.ri new file mode 100644 index 00000000..394d495c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/cdesc-BlankFileSystem.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/read_template_file-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/read_template_file-i.ri new file mode 100644 index 00000000..8ef1992f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlankFileSystem/read_template_file-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/blank%3f-i.ri new file mode 100644 index 00000000..9347bde5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_delimiter-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_delimiter-i.ri new file mode 100644 index 00000000..4010df0f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_delimiter-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_name-i.ri new file mode 100644 index 00000000..e6fd0238 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/block_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/cdesc-Block.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/cdesc-Block.ri new file mode 100644 index 00000000..3108f1c6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/cdesc-Block.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/new-c.ri new file mode 100644 index 00000000..242afb95 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/nodelist-i.ri new file mode 100644 index 00000000..07cc7000 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse-i.ri new file mode 100644 index 00000000..ff6c3c62 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse_body-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse_body-i.ri new file mode 100644 index 00000000..23967f1c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/parse_body-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/render-i.ri new file mode 100644 index 00000000..4351f285 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Block/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Block/unknown_tag-i.ri new file mode 100644 index 00000000..be71fd9b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Block/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/blank%3f-i.ri new file mode 100644 index 00000000..8e90c211 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/cdesc-BlockBody.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/cdesc-BlockBody.ri new file mode 100644 index 00000000..de4a0144 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/cdesc-BlockBody.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/check_resources-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/check_resources-i.ri new file mode 100644 index 00000000..c49150b1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/check_resources-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/create_variable-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/create_variable-i.ri new file mode 100644 index 00000000..b24f9702 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/create_variable-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/new-c.ri new file mode 100644 index 00000000..0b6c330f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/nodelist-i.ri new file mode 100644 index 00000000..4b965087 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/parse-i.ri new file mode 100644 index 00000000..e1d313e4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_tag_terminator-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_tag_terminator-i.ri new file mode 100644 index 00000000..5d482a00 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_tag_terminator-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_variable_terminator-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_variable_terminator-i.ri new file mode 100644 index 00000000..600aa9eb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/raise_missing_variable_terminator-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/registered_tags-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/registered_tags-i.ri new file mode 100644 index 00000000..0660509d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/registered_tags-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render-i.ri new file mode 100644 index 00000000..8bf03d28 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_to_output-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_to_output-i.ri new file mode 100644 index 00000000..1a88305f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_to_output-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_with_profiling-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_with_profiling-i.ri new file mode 100644 index 00000000..2a8149bc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_with_profiling-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_without_profiling-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_without_profiling-i.ri new file mode 100644 index 00000000..31c642b8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/render_node_without_profiling-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/whitespace_handler-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/whitespace_handler-i.ri new file mode 100644 index 00000000..31fc79be Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BlockBody/whitespace_handler-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Break/cdesc-Break.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Break/cdesc-Break.ri new file mode 100644 index 00000000..017d087c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Break/cdesc-Break.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Break/interrupt-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Break/interrupt-i.ri new file mode 100644 index 00000000..460585ab Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Break/interrupt-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/BreakInterrupt/cdesc-BreakInterrupt.ri b/bin/doc/liquid-4.0.4/ri/Liquid/BreakInterrupt/cdesc-BreakInterrupt.ri new file mode 100644 index 00000000..00145c5f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/BreakInterrupt/cdesc-BreakInterrupt.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Capture/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/blank%3f-i.ri new file mode 100644 index 00000000..de2844a5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Capture/cdesc-Capture.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/cdesc-Capture.ri new file mode 100644 index 00000000..2d275f50 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/cdesc-Capture.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Capture/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/new-c.ri new file mode 100644 index 00000000..ef7075d8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Capture/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/render-i.ri new file mode 100644 index 00000000..16ead3d8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Capture/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..d3ec3724 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..178c3865 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/blocks-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/blocks-i.ri new file mode 100644 index 00000000..016931bb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/blocks-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/cdesc-Case.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/cdesc-Case.ri new file mode 100644 index 00000000..ad52300e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/cdesc-Case.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/left-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/left-i.ri new file mode 100644 index 00000000..527f5dc6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/left-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/new-c.ri new file mode 100644 index 00000000..6714cdbf Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/nodelist-i.ri new file mode 100644 index 00000000..5ed5123c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/parse-i.ri new file mode 100644 index 00000000..2852414a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_else_condition-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_else_condition-i.ri new file mode 100644 index 00000000..03488f03 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_else_condition-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_when_condition-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_when_condition-i.ri new file mode 100644 index 00000000..0d07bff7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/record_when_condition-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/render-i.ri new file mode 100644 index 00000000..af7530e9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Case/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Case/unknown_tag-i.ri new file mode 100644 index 00000000..0e62ce89 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Case/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Comment/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/blank%3f-i.ri new file mode 100644 index 00000000..f66dae67 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Comment/cdesc-Comment.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/cdesc-Comment.ri new file mode 100644 index 00000000..48a787df Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/cdesc-Comment.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Comment/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/render-i.ri new file mode 100644 index 00000000..9a4b1eaf Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Comment/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/unknown_tag-i.ri new file mode 100644 index 00000000..a6af945d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Comment/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..fd1549dc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..de30265b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Condition/cdesc-Condition.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/cdesc-Condition.ri new file mode 100644 index 00000000..2ffc1d6a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Condition/cdesc-Condition.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d%3d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d%3d-i.ri new file mode 100644 index 00000000..b52b0a37 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d%3d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d-i.ri new file mode 100644 index 00000000..d5102a3d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/%5b%5d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/add_filters-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/add_filters-i.ri new file mode 100644 index 00000000..444b743a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/add_filters-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/apply_global_filter-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/apply_global_filter-i.ri new file mode 100644 index 00000000..b2831238 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/apply_global_filter-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/cdesc-Context.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/cdesc-Context.ri new file mode 100644 index 00000000..0e788067 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/cdesc-Context.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/clear_instance_assigns-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/clear_instance_assigns-i.ri new file mode 100644 index 00000000..3a5776c1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/clear_instance_assigns-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/environments-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/environments-i.ri new file mode 100644 index 00000000..1d6d3603 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/environments-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/errors-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/errors-i.ri new file mode 100644 index 00000000..bf68906a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/errors-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/evaluate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/evaluate-i.ri new file mode 100644 index 00000000..9ca272d3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/evaluate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/exception_renderer-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/exception_renderer-i.ri new file mode 100644 index 00000000..fc8495eb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/exception_renderer-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/find_variable-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/find_variable-i.ri new file mode 100644 index 00000000..9fc9101d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/find_variable-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/global_filter-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/global_filter-i.ri new file mode 100644 index 00000000..bcca0900 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/global_filter-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/handle_error-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/handle_error-i.ri new file mode 100644 index 00000000..01def84a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/handle_error-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/internal_error-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/internal_error-i.ri new file mode 100644 index 00000000..c8cb2649 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/internal_error-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/interrupt%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/interrupt%3f-i.ri new file mode 100644 index 00000000..a7ac8aa5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/interrupt%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/invoke-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/invoke-i.ri new file mode 100644 index 00000000..4337caa9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/invoke-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/key%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/key%3f-i.ri new file mode 100644 index 00000000..fdb62f97 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/key%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/lookup_and_evaluate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/lookup_and_evaluate-i.ri new file mode 100644 index 00000000..fd6b6bd7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/lookup_and_evaluate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/merge-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/merge-i.ri new file mode 100644 index 00000000..5739a7f6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/merge-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/new-c.ri new file mode 100644 index 00000000..8c48de2f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/partial-i.ri new file mode 100644 index 00000000..a2ad05f7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop-i.ri new file mode 100644 index 00000000..e37d36c0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop_interrupt-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop_interrupt-i.ri new file mode 100644 index 00000000..b7530cb1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/pop_interrupt-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/push-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/push-i.ri new file mode 100644 index 00000000..21886caa Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/push-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/push_interrupt-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/push_interrupt-i.ri new file mode 100644 index 00000000..02b9252c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/push_interrupt-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/registers-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/registers-i.ri new file mode 100644 index 00000000..8b8ec427 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/registers-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/resource_limits-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/resource_limits-i.ri new file mode 100644 index 00000000..aba4c26b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/resource_limits-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/scopes-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/scopes-i.ri new file mode 100644 index 00000000..8bcd8e51 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/scopes-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/squash_instance_assigns_with_environments-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/squash_instance_assigns_with_environments-i.ri new file mode 100644 index 00000000..da337431 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/squash_instance_assigns_with_environments-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/stack-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/stack-i.ri new file mode 100644 index 00000000..95f66827 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/stack-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/strainer-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strainer-i.ri new file mode 100644 index 00000000..5802a3c0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strainer-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_filters-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_filters-i.ri new file mode 100644 index 00000000..b1a6c202 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_filters-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_variables-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_variables-i.ri new file mode 100644 index 00000000..458250fb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/strict_variables-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/template_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/template_name-i.ri new file mode 100644 index 00000000..f9a05df6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/template_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Context/warnings-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Context/warnings-i.ri new file mode 100644 index 00000000..6169c293 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Context/warnings-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Continue/cdesc-Continue.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Continue/cdesc-Continue.ri new file mode 100644 index 00000000..5f3d405b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Continue/cdesc-Continue.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Continue/interrupt-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Continue/interrupt-i.ri new file mode 100644 index 00000000..3b16434f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Continue/interrupt-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ContinueInterrupt/cdesc-ContinueInterrupt.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ContinueInterrupt/cdesc-ContinueInterrupt.ri new file mode 100644 index 00000000..73071775 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ContinueInterrupt/cdesc-ContinueInterrupt.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..2e368809 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..4554329f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/cdesc-Cycle.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/cdesc-Cycle.ri new file mode 100644 index 00000000..d6f69dc9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/cdesc-Cycle.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/new-c.ri new file mode 100644 index 00000000..01dc7e87 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/render-i.ri new file mode 100644 index 00000000..8370267b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables-i.ri new file mode 100644 index 00000000..1be4ed41 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables_from_string-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables_from_string-i.ri new file mode 100644 index 00000000..980db4af Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Cycle/variables_from_string-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/cdesc-Decrement.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/cdesc-Decrement.ri new file mode 100644 index 00000000..d17d2f46 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/cdesc-Decrement.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/new-c.ri new file mode 100644 index 00000000..e9eb2785 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/render-i.ri new file mode 100644 index 00000000..a7a225d2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Decrement/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Document/cdesc-Document.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Document/cdesc-Document.ri new file mode 100644 index 00000000..b1d2e251 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Document/cdesc-Document.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-c.ri new file mode 100644 index 00000000..3901e3e7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-i.ri new file mode 100644 index 00000000..9da1778f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Document/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Document/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Document/unknown_tag-i.ri new file mode 100644 index 00000000..1f628a62 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Document/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/%5b%5d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/%5b%5d-i.ri new file mode 100644 index 00000000..d4a7da82 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/%5b%5d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/cdesc-Drop.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/cdesc-Drop.ri new file mode 100644 index 00000000..c383a84d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/cdesc-Drop.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/context-i.ri new file mode 100644 index 00000000..a3c86625 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/inspect-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/inspect-i.ri new file mode 100644 index 00000000..7fbb24f1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/inspect-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable%3f-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable%3f-c.ri new file mode 100644 index 00000000..c2c688f0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable%3f-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable_methods-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable_methods-c.ri new file mode 100644 index 00000000..0d34bb75 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invokable_methods-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invoke_drop-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invoke_drop-i.ri new file mode 100644 index 00000000..5c7b1ad7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/invoke_drop-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/key%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/key%3f-i.ri new file mode 100644 index 00000000..85edbf8c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/key%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/liquid_method_missing-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/liquid_method_missing-i.ri new file mode 100644 index 00000000..72fb7f58 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/liquid_method_missing-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_liquid-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_liquid-i.ri new file mode 100644 index 00000000..55b3f667 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_liquid-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_s-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_s-i.ri new file mode 100644 index 00000000..bd4d3dd5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Drop/to_s-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/cdesc-ElseCondition.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/cdesc-ElseCondition.ri new file mode 100644 index 00000000..c3256c66 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/cdesc-ElseCondition.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/else%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/else%3f-i.ri new file mode 100644 index 00000000..d03dfd5c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/else%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/evaluate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/evaluate-i.ri new file mode 100644 index 00000000..b042f9ce Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ElseCondition/evaluate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/cdesc-Error.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/cdesc-Error.ri new file mode 100644 index 00000000..185c0cf3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/cdesc-Error.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/line_number-i.ri new file mode 100644 index 00000000..9a38e28c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/markup_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/markup_context-i.ri new file mode 100644 index 00000000..8cb360ab Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/markup_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/message_prefix-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/message_prefix-i.ri new file mode 100644 index 00000000..f97b1067 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/message_prefix-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/template_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/template_name-i.ri new file mode 100644 index 00000000..5357c058 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/template_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Error/to_s-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Error/to_s-i.ri new file mode 100644 index 00000000..f0a9d14c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Error/to_s-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/cdesc-MethodLiteral.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/cdesc-MethodLiteral.ri new file mode 100644 index 00000000..c7196f1a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/cdesc-MethodLiteral.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/method_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/method_name-i.ri new file mode 100644 index 00000000..091818d9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/method_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/new-c.ri new file mode 100644 index 00000000..b0b86df9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_liquid-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_liquid-i.ri new file mode 100644 index 00000000..42460e27 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_liquid-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_s-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_s-i.ri new file mode 100644 index 00000000..19f9281c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/MethodLiteral/to_s-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/cdesc-Expression.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/cdesc-Expression.ri new file mode 100644 index 00000000..d9d7d9bd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/cdesc-Expression.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Expression/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/parse-c.ri new file mode 100644 index 00000000..ad07ff07 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Expression/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..e98df871 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..f3d3e8de Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/cdesc-For.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/cdesc-For.ri new file mode 100644 index 00000000..cce1e53b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/cdesc-For.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_name-i.ri new file mode 100644 index 00000000..9d01baaa Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_segment-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_segment-i.ri new file mode 100644 index 00000000..d71fcc4a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/collection_segment-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/from-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/from-i.ri new file mode 100644 index 00000000..19df6ced Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/from-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/lax_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/lax_parse-i.ri new file mode 100644 index 00000000..bf6d9862 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/lax_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/limit-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/limit-i.ri new file mode 100644 index 00000000..1cd91edf Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/limit-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/new-c.ri new file mode 100644 index 00000000..66536daa Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/nodelist-i.ri new file mode 100644 index 00000000..4e974fa7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/parse-i.ri new file mode 100644 index 00000000..e2976be1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/render-i.ri new file mode 100644 index 00000000..1e7b110d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/render_else-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/render_else-i.ri new file mode 100644 index 00000000..273d5742 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/render_else-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/render_segment-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/render_segment-i.ri new file mode 100644 index 00000000..08332a2e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/render_segment-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/set_attribute-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/set_attribute-i.ri new file mode 100644 index 00000000..d04257b2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/set_attribute-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/strict_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/strict_parse-i.ri new file mode 100644 index 00000000..656e5145 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/strict_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/unknown_tag-i.ri new file mode 100644 index 00000000..2ff4d683 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/For/variable_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/For/variable_name-i.ri new file mode 100644 index 00000000..b5437148 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/For/variable_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/cdesc-ForloopDrop.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/cdesc-ForloopDrop.ri new file mode 100644 index 00000000..b041372f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/cdesc-ForloopDrop.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/first-i.ri new file mode 100644 index 00000000..c3e279a1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/increment%21-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/increment%21-i.ri new file mode 100644 index 00000000..543f5cbd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/increment%21-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index-i.ri new file mode 100644 index 00000000..9a1cf140 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index0-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index0-i.ri new file mode 100644 index 00000000..fc831159 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/index0-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/last-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/last-i.ri new file mode 100644 index 00000000..e9c70e37 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/last-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/length-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/length-i.ri new file mode 100644 index 00000000..a639fc34 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/length-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/name-i.ri new file mode 100644 index 00000000..18870ddb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/new-c.ri new file mode 100644 index 00000000..f6e31b50 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/parentloop-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/parentloop-i.ri new file mode 100644 index 00000000..baad0e59 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/parentloop-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex-i.ri new file mode 100644 index 00000000..d0f834fb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex0-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex0-i.ri new file mode 100644 index 00000000..548d5b91 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ForloopDrop/rindex0-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/cdesc-I18n.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/cdesc-I18n.ri new file mode 100644 index 00000000..70209b69 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/cdesc-I18n.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/deep_fetch_translation-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/deep_fetch_translation-i.ri new file mode 100644 index 00000000..49ea6780 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/deep_fetch_translation-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/interpolate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/interpolate-i.ri new file mode 100644 index 00000000..070a69d5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/interpolate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/locale-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/locale-i.ri new file mode 100644 index 00000000..588497fe Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/locale-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/new-c.ri new file mode 100644 index 00000000..6a7fe36b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/path-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/path-i.ri new file mode 100644 index 00000000..75ea94a8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/path-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/t-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/t-i.ri new file mode 100644 index 00000000..2215edf6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/t-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/I18n/translate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/translate-i.ri new file mode 100644 index 00000000..6de0b5d2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/I18n/translate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..78bab9f4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..d8ce8378 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/blocks-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/blocks-i.ri new file mode 100644 index 00000000..ca26506c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/blocks-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/cdesc-If.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/cdesc-If.ri new file mode 100644 index 00000000..da0b877f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/cdesc-If.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/lax_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/lax_parse-i.ri new file mode 100644 index 00000000..ed156885 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/lax_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/new-c.ri new file mode 100644 index 00000000..c5b0b4f4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/nodelist-i.ri new file mode 100644 index 00000000..455a7f18 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse-i.ri new file mode 100644 index 00000000..1f745acc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_binary_comparisons-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_binary_comparisons-i.ri new file mode 100644 index 00000000..5c12cbbc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_binary_comparisons-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_comparison-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_comparison-i.ri new file mode 100644 index 00000000..741fc39e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/parse_comparison-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/push_block-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/push_block-i.ri new file mode 100644 index 00000000..06eeeb0e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/push_block-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/render-i.ri new file mode 100644 index 00000000..0251940a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/strict_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/strict_parse-i.ri new file mode 100644 index 00000000..30cd64d9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/strict_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/If/unknown_tag-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/If/unknown_tag-i.ri new file mode 100644 index 00000000..4e855518 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/If/unknown_tag-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/cdesc-Ifchanged.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/cdesc-Ifchanged.ri new file mode 100644 index 00000000..7e190b8e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/cdesc-Ifchanged.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/render-i.ri new file mode 100644 index 00000000..f1871334 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Ifchanged/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..e41b9245 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..22fa9841 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/attributes-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/attributes-i.ri new file mode 100644 index 00000000..c3e9264a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/attributes-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/cdesc-Include.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/cdesc-Include.ri new file mode 100644 index 00000000..eee804a4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/cdesc-Include.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/load_cached_partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/load_cached_partial-i.ri new file mode 100644 index 00000000..d6d5f92e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/load_cached_partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/new-c.ri new file mode 100644 index 00000000..df4319c0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/parse-i.ri new file mode 100644 index 00000000..9f9c21b3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/read_template_from_file_system-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/read_template_from_file_system-i.ri new file mode 100644 index 00000000..d42869b5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/read_template_from_file_system-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render-i.ri new file mode 100644 index 00000000..4cf5b5ed Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_with_profiling-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_with_profiling-i.ri new file mode 100644 index 00000000..d03a55a8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_with_profiling-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_without_profiling-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_without_profiling-i.ri new file mode 100644 index 00000000..37778963 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/render_without_profiling-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/template_name_expr-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/template_name_expr-i.ri new file mode 100644 index 00000000..341340b5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/template_name_expr-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Include/variable_name_expr-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Include/variable_name_expr-i.ri new file mode 100644 index 00000000..0f596472 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Include/variable_name_expr-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Increment/cdesc-Increment.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/cdesc-Increment.ri new file mode 100644 index 00000000..3e731f3c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/cdesc-Increment.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Increment/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/new-c.ri new file mode 100644 index 00000000..3abc8f51 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Increment/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/render-i.ri new file mode 100644 index 00000000..69b3fa5a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Increment/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/cdesc-Interrupt.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/cdesc-Interrupt.ri new file mode 100644 index 00000000..20629281 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/cdesc-Interrupt.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/message-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/message-i.ri new file mode 100644 index 00000000..36a548ed Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/message-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/new-c.ri new file mode 100644 index 00000000..7892ca08 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Interrupt/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/cdesc-Lexer.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/cdesc-Lexer.ri new file mode 100644 index 00000000..e06d3415 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/cdesc-Lexer.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/new-c.ri new file mode 100644 index 00000000..e66294bf Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/tokenize-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/tokenize-i.ri new file mode 100644 index 00000000..173dc691 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Lexer/tokenize-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/cdesc-LocalFileSystem.ri b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/cdesc-LocalFileSystem.ri new file mode 100644 index 00000000..ccdf3091 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/cdesc-LocalFileSystem.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/full_path-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/full_path-i.ri new file mode 100644 index 00000000..ad57f745 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/full_path-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/new-c.ri new file mode 100644 index 00000000..8d5c8743 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/read_template_file-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/read_template_file-i.ri new file mode 100644 index 00000000..131e487f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/read_template_file-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/root-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/root-i.ri new file mode 100644 index 00000000..a9d7fa2e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/LocalFileSystem/root-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/%5b%5d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/%5b%5d-i.ri new file mode 100644 index 00000000..a43909e2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/%5b%5d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/cdesc-ParseContext.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/cdesc-ParseContext.ri new file mode 100644 index 00000000..4f55b79b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/cdesc-ParseContext.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/depth-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/depth-i.ri new file mode 100644 index 00000000..281aa9ae Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/depth-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/error_mode-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/error_mode-i.ri new file mode 100644 index 00000000..a4a28776 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/error_mode-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/line_number-i.ri new file mode 100644 index 00000000..d91a9f31 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/locale-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/locale-i.ri new file mode 100644 index 00000000..6dead23d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/locale-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/new-c.ri new file mode 100644 index 00000000..1aee0993 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial%3d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial%3d-i.ri new file mode 100644 index 00000000..9a950924 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial%3d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial-i.ri new file mode 100644 index 00000000..0950858f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial_options-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial_options-i.ri new file mode 100644 index 00000000..2d7b7cb2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/partial_options-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/trim_whitespace-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/trim_whitespace-i.ri new file mode 100644 index 00000000..de9d72e5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/trim_whitespace-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/warnings-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/warnings-i.ri new file mode 100644 index 00000000..0b79e3ee Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseContext/warnings-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/add_callback_for-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/add_callback_for-i.ri new file mode 100644 index 00000000..4211d842 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/add_callback_for-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..2b55a1ac Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..e2653ce6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/for-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/for-c.ri new file mode 100644 index 00000000..5d2ff06b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/for-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/new-c.ri new file mode 100644 index 00000000..a09b815e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/visit-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/visit-i.ri new file mode 100644 index 00000000..55082033 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParseTreeVisitor/visit-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/argument-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/argument-i.ri new file mode 100644 index 00000000..5234aa68 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/argument-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/cdesc-Parser.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/cdesc-Parser.ri new file mode 100644 index 00000000..33decb35 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/cdesc-Parser.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume%3f-i.ri new file mode 100644 index 00000000..23493986 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume-i.ri new file mode 100644 index 00000000..3f4dbff5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/consume-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/expression-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/expression-i.ri new file mode 100644 index 00000000..32ecf020 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/expression-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/id%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/id%3f-i.ri new file mode 100644 index 00000000..8028fddb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/id%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/jump-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/jump-i.ri new file mode 100644 index 00000000..383231ab Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/jump-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/look-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/look-i.ri new file mode 100644 index 00000000..b74f52c3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/look-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/new-c.ri new file mode 100644 index 00000000..0d868e4c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Parser/variable_signature-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/variable_signature-i.ri new file mode 100644 index 00000000..8c2c1724 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Parser/variable_signature-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/cdesc-ParserSwitching.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/cdesc-ParserSwitching.ri new file mode 100644 index 00000000..9c005e38 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/cdesc-ParserSwitching.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/markup_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/markup_context-i.ri new file mode 100644 index 00000000..32871342 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/markup_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/parse_with_selected_parser-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/parse_with_selected_parser-i.ri new file mode 100644 index 00000000..c2e70ce1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/parse_with_selected_parser-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/strict_parse_with_error_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/strict_parse_with_error_context-i.ri new file mode 100644 index 00000000..4075e6ba Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ParserSwitching/strict_parse_with_error_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/%5b%5d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/%5b%5d-i.ri new file mode 100644 index 00000000..09898be6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/%5b%5d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/cdesc-Timing.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/cdesc-Timing.ri new file mode 100644 index 00000000..57d28133 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/cdesc-Timing.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/children-i.ri new file mode 100644 index 00000000..d19a783c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/code-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/code-i.ri new file mode 100644 index 00000000..6d989f2c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/code-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/finish-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/finish-i.ri new file mode 100644 index 00000000..fb206208 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/finish-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/line_number-i.ri new file mode 100644 index 00000000..9dd6f2ee Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/new-c.ri new file mode 100644 index 00000000..cc06ecbf Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/partial-i.ri new file mode 100644 index 00000000..a7ebf65c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/render_time-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/render_time-i.ri new file mode 100644 index 00000000..f45e9754 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/render_time-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-c.ri new file mode 100644 index 00000000..14d6de0b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-i.ri new file mode 100644 index 00000000..2995c9a5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/Timing/start-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/cdesc-Profiler.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/cdesc-Profiler.ri new file mode 100644 index 00000000..3eea233b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/cdesc-Profiler.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_partial-i.ri new file mode 100644 index 00000000..74977a46 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_profile-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_profile-c.ri new file mode 100644 index 00000000..14721e85 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/current_profile-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/each-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/each-i.ri new file mode 100644 index 00000000..40863d33 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/each-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/end_node-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/end_node-i.ri new file mode 100644 index 00000000..b13fee72 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/end_node-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/length-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/length-i.ri new file mode 100644 index 00000000..1ad9e537 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/length-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/new-c.ri new file mode 100644 index 00000000..2b9a8df0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/pop_partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/pop_partial-i.ri new file mode 100644 index 00000000..53b4a407 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/pop_partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_children-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_children-c.ri new file mode 100644 index 00000000..562a2559 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_children-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_node_render-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_node_render-c.ri new file mode 100644 index 00000000..54cc5366 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/profile_node_render-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/push_partial-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/push_partial-i.ri new file mode 100644 index 00000000..05892685 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/push_partial-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start-i.ri new file mode 100644 index 00000000..e4343aa4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start_node-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start_node-i.ri new file mode 100644 index 00000000..a39ba7e1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/start_node-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/stop-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/stop-i.ri new file mode 100644 index 00000000..87bc0a52 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/stop-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/total_render_time-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/total_render_time-i.ri new file mode 100644 index 00000000..5a6aedd9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Profiler/total_render_time-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/cdesc-RangeLookup.ri b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/cdesc-RangeLookup.ri new file mode 100644 index 00000000..d1d598b6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/cdesc-RangeLookup.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/evaluate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/evaluate-i.ri new file mode 100644 index 00000000..7ebad1ec Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/evaluate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/new-c.ri new file mode 100644 index 00000000..a01a1cb4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/parse-c.ri new file mode 100644 index 00000000..c8707bf8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/to_integer-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/to_integer-i.ri new file mode 100644 index 00000000..698b73a5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/RangeLookup/to_integer-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/blank%3f-i.ri new file mode 100644 index 00000000..164ec112 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/cdesc-Raw.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/cdesc-Raw.ri new file mode 100644 index 00000000..7b843c4c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/cdesc-Raw.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/ensure_valid_markup-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/ensure_valid_markup-i.ri new file mode 100644 index 00000000..b5f1a310 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/ensure_valid_markup-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/new-c.ri new file mode 100644 index 00000000..d91c1a1e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/nodelist-i.ri new file mode 100644 index 00000000..1d4a754c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/parse-i.ri new file mode 100644 index 00000000..d3b9f87f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Raw/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/render-i.ri new file mode 100644 index 00000000..f145fb81 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Raw/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score-i.ri new file mode 100644 index 00000000..cbe0e8c5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score_limit-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score_limit-i.ri new file mode 100644 index 00000000..8c3baa71 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/assign_score_limit-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/cdesc-ResourceLimits.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/cdesc-ResourceLimits.ri new file mode 100644 index 00000000..a2e8b511 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/cdesc-ResourceLimits.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/new-c.ri new file mode 100644 index 00000000..c59606c2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reached%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reached%3f-i.ri new file mode 100644 index 00000000..25e8dce6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reached%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length-i.ri new file mode 100644 index 00000000..a5780f56 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length_limit-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length_limit-i.ri new file mode 100644 index 00000000..c54f7e50 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_length_limit-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score-i.ri new file mode 100644 index 00000000..cdd71a20 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score_limit-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score_limit-i.ri new file mode 100644 index 00000000..2c95f8d1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/render_score_limit-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reset-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reset-i.ri new file mode 100644 index 00000000..8eb42fc6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/ResourceLimits/reset-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/cdesc-InputIterator.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/cdesc-InputIterator.ri new file mode 100644 index 00000000..5755bfc8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/cdesc-InputIterator.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/compact-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/compact-i.ri new file mode 100644 index 00000000..f71ede5b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/compact-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/concat-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/concat-i.ri new file mode 100644 index 00000000..9cb13b6a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/concat-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/each-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/each-i.ri new file mode 100644 index 00000000..e7c7d9c4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/each-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/empty%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/empty%3f-i.ri new file mode 100644 index 00000000..8aade31e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/empty%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/join-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/join-i.ri new file mode 100644 index 00000000..c40e8500 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/join-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/new-c.ri new file mode 100644 index 00000000..e4f406e2 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/reverse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/reverse-i.ri new file mode 100644 index 00000000..b77db2f1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/reverse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/uniq-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/uniq-i.ri new file mode 100644 index 00000000..9cb488f7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/InputIterator/uniq-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/abs-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/abs-i.ri new file mode 100644 index 00000000..2cd1bf0e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/abs-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/append-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/append-i.ri new file mode 100644 index 00000000..5e272156 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/append-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/apply_operation-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/apply_operation-i.ri new file mode 100644 index 00000000..7bfa0f1a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/apply_operation-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_least-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_least-i.ri new file mode 100644 index 00000000..21488966 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_least-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_most-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_most-i.ri new file mode 100644 index 00000000..36977f6b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/at_most-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/capitalize-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/capitalize-i.ri new file mode 100644 index 00000000..0b5b7da3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/capitalize-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/cdesc-StandardFilters.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/cdesc-StandardFilters.ri new file mode 100644 index 00000000..14243e15 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/cdesc-StandardFilters.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/ceil-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/ceil-i.ri new file mode 100644 index 00000000..a55e73cd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/ceil-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/compact-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/compact-i.ri new file mode 100644 index 00000000..439abf64 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/compact-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/concat-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/concat-i.ri new file mode 100644 index 00000000..747060f3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/concat-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/date-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/date-i.ri new file mode 100644 index 00000000..f3323300 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/date-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/default-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/default-i.ri new file mode 100644 index 00000000..c6dd2c1a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/default-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/divided_by-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/divided_by-i.ri new file mode 100644 index 00000000..3b40b4d3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/divided_by-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/downcase-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/downcase-i.ri new file mode 100644 index 00000000..f5dd6017 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/downcase-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape-i.ri new file mode 100644 index 00000000..e95c65c8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape_once-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape_once-i.ri new file mode 100644 index 00000000..b498d0ba Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/escape_once-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/first-i.ri new file mode 100644 index 00000000..c578f550 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/floor-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/floor-i.ri new file mode 100644 index 00000000..80b12d1a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/floor-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/h-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/h-i.ri new file mode 100644 index 00000000..467d1f71 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/h-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/join-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/join-i.ri new file mode 100644 index 00000000..7867ee5c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/join-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/last-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/last-i.ri new file mode 100644 index 00000000..09654bd4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/last-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/lstrip-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/lstrip-i.ri new file mode 100644 index 00000000..996d15b9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/lstrip-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/map-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/map-i.ri new file mode 100644 index 00000000..388a322d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/map-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/minus-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/minus-i.ri new file mode 100644 index 00000000..3ab496b6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/minus-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/modulo-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/modulo-i.ri new file mode 100644 index 00000000..1e59c155 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/modulo-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/newline_to_br-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/newline_to_br-i.ri new file mode 100644 index 00000000..519e01f5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/newline_to_br-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_casecmp-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_casecmp-i.ri new file mode 100644 index 00000000..36724a79 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_casecmp-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_compare-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_compare-i.ri new file mode 100644 index 00000000..9dc04a63 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/nil_safe_compare-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/plus-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/plus-i.ri new file mode 100644 index 00000000..4a335b47 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/plus-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/prepend-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/prepend-i.ri new file mode 100644 index 00000000..301929c6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/prepend-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/raise_property_error-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/raise_property_error-i.ri new file mode 100644 index 00000000..62878279 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/raise_property_error-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove-i.ri new file mode 100644 index 00000000..f849e249 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove_first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove_first-i.ri new file mode 100644 index 00000000..6379a3bd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/remove_first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace-i.ri new file mode 100644 index 00000000..4f364ada Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace_first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace_first-i.ri new file mode 100644 index 00000000..241c3468 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/replace_first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/reverse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/reverse-i.ri new file mode 100644 index 00000000..ad3e0469 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/reverse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/round-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/round-i.ri new file mode 100644 index 00000000..2b3ee66d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/round-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/rstrip-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/rstrip-i.ri new file mode 100644 index 00000000..636b2eb8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/rstrip-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/size-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/size-i.ri new file mode 100644 index 00000000..30dc8009 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/size-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/slice-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/slice-i.ri new file mode 100644 index 00000000..7a0be4a7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/slice-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort-i.ri new file mode 100644 index 00000000..ba361080 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort_natural-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort_natural-i.ri new file mode 100644 index 00000000..a7d89662 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/sort_natural-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/split-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/split-i.ri new file mode 100644 index 00000000..7d2ba16d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/split-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip-i.ri new file mode 100644 index 00000000..da6e8240 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_html-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_html-i.ri new file mode 100644 index 00000000..eed4ff7d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_html-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_newlines-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_newlines-i.ri new file mode 100644 index 00000000..7559fd02 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/strip_newlines-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/times-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/times-i.ri new file mode 100644 index 00000000..6125acb6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/times-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncate-i.ri new file mode 100644 index 00000000..d75200d3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncatewords-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncatewords-i.ri new file mode 100644 index 00000000..3e1c17e9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/truncatewords-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/uniq-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/uniq-i.ri new file mode 100644 index 00000000..7a909bba Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/uniq-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/upcase-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/upcase-i.ri new file mode 100644 index 00000000..9e12c03d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/upcase-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_decode-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_decode-i.ri new file mode 100644 index 00000000..74924477 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_decode-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_encode-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_encode-i.ri new file mode 100644 index 00000000..1f4361bd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/url_encode-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/where-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/where-i.ri new file mode 100644 index 00000000..b42cb13a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/StandardFilters/where-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Strainer/cdesc-Strainer.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Strainer/cdesc-Strainer.ri new file mode 100644 index 00000000..8f129543 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Strainer/cdesc-Strainer.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..d86083d4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..922d816d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/attributes-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/attributes-i.ri new file mode 100644 index 00000000..74a909b0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/attributes-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/cdesc-TableRow.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/cdesc-TableRow.ri new file mode 100644 index 00000000..b65614b5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/cdesc-TableRow.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/collection_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/collection_name-i.ri new file mode 100644 index 00000000..00c4b5d1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/collection_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/new-c.ri new file mode 100644 index 00000000..b518cca9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/render-i.ri new file mode 100644 index 00000000..cdb7e0cc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/variable_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/variable_name-i.ri new file mode 100644 index 00000000..0380fd66 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TableRow/variable_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/cdesc-TablerowloopDrop.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/cdesc-TablerowloopDrop.ri new file mode 100644 index 00000000..c66500e3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/cdesc-TablerowloopDrop.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col-i.ri new file mode 100644 index 00000000..33194edd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col0-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col0-i.ri new file mode 100644 index 00000000..3d839088 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col0-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_first-i.ri new file mode 100644 index 00000000..ffae693f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_last-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_last-i.ri new file mode 100644 index 00000000..ed12221f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/col_last-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/first-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/first-i.ri new file mode 100644 index 00000000..6833cbdb Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/first-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/increment%21-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/increment%21-i.ri new file mode 100644 index 00000000..ca939bf3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/increment%21-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index-i.ri new file mode 100644 index 00000000..fa24156c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index0-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index0-i.ri new file mode 100644 index 00000000..aa69629c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/index0-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/last-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/last-i.ri new file mode 100644 index 00000000..c035fb15 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/last-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/length-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/length-i.ri new file mode 100644 index 00000000..444ca183 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/length-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/new-c.ri new file mode 100644 index 00000000..064f9eb4 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex-i.ri new file mode 100644 index 00000000..4be50802 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex0-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex0-i.ri new file mode 100644 index 00000000..b759b373 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/rindex0-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/row-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/row-i.ri new file mode 100644 index 00000000..0db49f35 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/TablerowloopDrop/row-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/blank%3f-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/blank%3f-i.ri new file mode 100644 index 00000000..e6e030df Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/blank%3f-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/cdesc-Tag.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/cdesc-Tag.ri new file mode 100644 index 00000000..d9d806d6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/cdesc-Tag.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/line_number-i.ri new file mode 100644 index 00000000..1903678e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/name-i.ri new file mode 100644 index 00000000..d59ec27b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/new-c.ri new file mode 100644 index 00000000..563d2fe1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/nodelist-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/nodelist-i.ri new file mode 100644 index 00000000..95abd33c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/nodelist-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/options-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/options-i.ri new file mode 100644 index 00000000..fcb29f4e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/options-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-c.ri new file mode 100644 index 00000000..3346305f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-i.ri new file mode 100644 index 00000000..88f27240 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse_context-i.ri new file mode 100644 index 00000000..b01505db Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/parse_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/raw-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/raw-i.ri new file mode 100644 index 00000000..662b492b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/raw-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/render-i.ri new file mode 100644 index 00000000..71a7f24e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tag/tag_name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/tag_name-i.ri new file mode 100644 index 00000000..baf1a622 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tag/tag_name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d%3d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d%3d-i.ri new file mode 100644 index 00000000..905b8694 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d%3d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d-i.ri new file mode 100644 index 00000000..0c7522d7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/%5b%5d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/cdesc-TagRegistry.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/cdesc-TagRegistry.ri new file mode 100644 index 00000000..aebb0bc7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/cdesc-TagRegistry.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/delete-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/delete-i.ri new file mode 100644 index 00000000..69848b90 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/delete-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/each-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/each-i.ri new file mode 100644 index 00000000..de1473d5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/each-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/lookup_class-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/lookup_class-i.ri new file mode 100644 index 00000000..101e5e7d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/lookup_class-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/new-c.ri new file mode 100644 index 00000000..bad23f7c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/TagRegistry/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/apply_options_to_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/apply_options_to_context-i.ri new file mode 100644 index 00000000..c54545bd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/apply_options_to_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/assigns-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/assigns-i.ri new file mode 100644 index 00000000..02184f16 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/assigns-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/cdesc-Template.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/cdesc-Template.ri new file mode 100644 index 00000000..4e9bb826 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/cdesc-Template.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_exception_renderer-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_exception_renderer-c.ri new file mode 100644 index 00000000..3240dc9f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_exception_renderer-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_resource_limits-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_resource_limits-c.ri new file mode 100644 index 00000000..39f696fd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/default_resource_limits-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/error_mode-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/error_mode-c.ri new file mode 100644 index 00000000..00d70775 --- /dev/null +++ b/bin/doc/liquid-4.0.4/ri/Liquid/Template/error_mode-c.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"error_mode:ETI"!Liquid::Template::error_mode;TI"W;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [ I"+Sets how strict the parser should be. ;TI"R:lax acts like liquid 2.5 and silently ignores malformed tags in most cases. ;TI"Z:warn is the default and will give deprecation warnings when invalid syntax is used. ;TI"):strict will enforce correct syntax.;T: +@fileI"lib/liquid/template.rb;T:0@omit_headings_from_table_of_contents_below0T@I"Liquid::Template;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/errors-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/errors-i.ri new file mode 100644 index 00000000..600f4320 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/errors-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system%3d-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system%3d-c.ri new file mode 100644 index 00000000..50540a4a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system%3d-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system-c.ri new file mode 100644 index 00000000..b30a3265 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/file_system-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/instance_assigns-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/instance_assigns-i.ri new file mode 100644 index 00000000..dde5739e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/instance_assigns-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/new-c.ri new file mode 100644 index 00000000..489605c7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-c.ri new file mode 100644 index 00000000..6db28170 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-i.ri new file mode 100644 index 00000000..0dcac654 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/profiler-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/profiler-i.ri new file mode 100644 index 00000000..e7e13c0a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/profiler-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_filter-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_filter-c.ri new file mode 100644 index 00000000..6becde12 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_filter-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_tag-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_tag-c.ri new file mode 100644 index 00000000..b16ffdea Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/register_tag-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/registers-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/registers-i.ri new file mode 100644 index 00000000..0143f05f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/registers-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/render%21-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/render%21-i.ri new file mode 100644 index 00000000..f0e6c039 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/render%21-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/render-i.ri new file mode 100644 index 00000000..695f77bc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/resource_limits-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/resource_limits-i.ri new file mode 100644 index 00000000..2e631e74 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/resource_limits-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/root-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/root-i.ri new file mode 100644 index 00000000..08d87fe7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/root-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/tags-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/tags-c.ri new file mode 100644 index 00000000..d7d75909 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/tags-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/taint_mode-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/taint_mode-c.ri new file mode 100644 index 00000000..a608e609 --- /dev/null +++ b/bin/doc/liquid-4.0.4/ri/Liquid/Template/taint_mode-c.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"taint_mode:ETI"!Liquid::Template::taint_mode;TI"W;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"5Deprecated. No longer used. Removed in version 5;T: +@fileI"lib/liquid/template.rb;T:0@omit_headings_from_table_of_contents_below0T@I"Liquid::Template;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/tokenize-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/tokenize-i.ri new file mode 100644 index 00000000..4c71c111 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/tokenize-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/warnings-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/warnings-i.ri new file mode 100644 index 00000000..1833342f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/warnings-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Template/with_profiling-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Template/with_profiling-i.ri new file mode 100644 index 00000000..ef375ebc Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Template/with_profiling-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/cdesc-Tokenizer.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/cdesc-Tokenizer.ri new file mode 100644 index 00000000..7cdfed87 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/cdesc-Tokenizer.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/line_number-i.ri new file mode 100644 index 00000000..1e014553 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/new-c.ri new file mode 100644 index 00000000..5603ad9c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/shift-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/shift-i.ri new file mode 100644 index 00000000..f46276f8 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/shift-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/tokenize-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/tokenize-i.ri new file mode 100644 index 00000000..55b61e95 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Tokenizer/tokenize-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Unless/cdesc-Unless.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Unless/cdesc-Unless.ri new file mode 100644 index 00000000..03245179 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Unless/cdesc-Unless.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Unless/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Unless/render-i.ri new file mode 100644 index 00000000..d0698cf7 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Unless/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/cdesc-Utils.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/cdesc-Utils.ri new file mode 100644 index 00000000..e1e9c0ab Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/cdesc-Utils.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection-c.ri new file mode 100644 index 00000000..34cef8f1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection_using_each-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection_using_each-c.ri new file mode 100644 index 00000000..efa2c805 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/slice_collection_using_each-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_date-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_date-c.ri new file mode 100644 index 00000000..9511a13d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_date-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_integer-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_integer-c.ri new file mode 100644 index 00000000..e1ca4f10 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_integer-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_number-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_number-c.ri new file mode 100644 index 00000000..ad98704d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Utils/to_number-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..2c1dcacd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..35c6d72b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/cdesc-Variable.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/cdesc-Variable.ri new file mode 100644 index 00000000..f6bd4940 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/cdesc-Variable.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/evaluate_filter_expressions-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/evaluate_filter_expressions-i.ri new file mode 100644 index 00000000..7fb7eb6c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/evaluate_filter_expressions-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/filters-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/filters-i.ri new file mode 100644 index 00000000..f4f02795 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/filters-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/lax_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/lax_parse-i.ri new file mode 100644 index 00000000..7b67b39f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/lax_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/line_number-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/line_number-i.ri new file mode 100644 index 00000000..12ed00d0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/line_number-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/markup_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/markup_context-i.ri new file mode 100644 index 00000000..ea7bc3de Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/markup_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/name-i.ri new file mode 100644 index 00000000..7adea49e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/new-c.ri new file mode 100644 index 00000000..9bc38959 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/options-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/options-i.ri new file mode 100644 index 00000000..95247cf1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/options-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_context-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_context-i.ri new file mode 100644 index 00000000..9e1e641f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_context-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filter_expressions-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filter_expressions-i.ri new file mode 100644 index 00000000..7500944b Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filter_expressions-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filterargs-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filterargs-i.ri new file mode 100644 index 00000000..140d588f Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/parse_filterargs-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/raw-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/raw-i.ri new file mode 100644 index 00000000..f0366188 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/raw-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/render-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/render-i.ri new file mode 100644 index 00000000..354069c3 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/render-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/Variable/strict_parse-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/strict_parse-i.ri new file mode 100644 index 00000000..90065bd0 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/Variable/strict_parse-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/%3d%3d-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/%3d%3d-i.ri new file mode 100644 index 00000000..2980831a Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/%3d%3d-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri new file mode 100644 index 00000000..501fabea Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/cdesc-ParseTreeVisitor.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/children-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/children-i.ri new file mode 100644 index 00000000..fb03a9f1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/ParseTreeVisitor/children-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/cdesc-VariableLookup.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/cdesc-VariableLookup.ri new file mode 100644 index 00000000..12baa4a6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/cdesc-VariableLookup.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/evaluate-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/evaluate-i.ri new file mode 100644 index 00000000..a65d5d0d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/evaluate-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/lookups-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/lookups-i.ri new file mode 100644 index 00000000..74611149 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/lookups-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/name-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/name-i.ri new file mode 100644 index 00000000..36e080c9 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/name-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/new-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/new-c.ri new file mode 100644 index 00000000..110db33d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/new-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/parse-c.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/parse-c.ri new file mode 100644 index 00000000..a5dde690 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/parse-c.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/state-i.ri b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/state-i.ri new file mode 100644 index 00000000..acd6ccdd Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/VariableLookup/state-i.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Liquid/cdesc-Liquid.ri b/bin/doc/liquid-4.0.4/ri/Liquid/cdesc-Liquid.ri new file mode 100644 index 00000000..106f58a6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Liquid/cdesc-Liquid.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/NilClass/cdesc-NilClass.ri b/bin/doc/liquid-4.0.4/ri/NilClass/cdesc-NilClass.ri new file mode 100644 index 00000000..cc7e4932 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/NilClass/cdesc-NilClass.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Numeric/cdesc-Numeric.ri b/bin/doc/liquid-4.0.4/ri/Numeric/cdesc-Numeric.ri new file mode 100644 index 00000000..bd5fb51d Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Numeric/cdesc-Numeric.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Range/cdesc-Range.ri b/bin/doc/liquid-4.0.4/ri/Range/cdesc-Range.ri new file mode 100644 index 00000000..ce496ef5 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Range/cdesc-Range.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/String/cdesc-String.ri b/bin/doc/liquid-4.0.4/ri/String/cdesc-String.ri new file mode 100644 index 00000000..d0369c8e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/String/cdesc-String.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Symbol/cdesc-Symbol.ri b/bin/doc/liquid-4.0.4/ri/Symbol/cdesc-Symbol.ri new file mode 100644 index 00000000..b9ec7a1e Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Symbol/cdesc-Symbol.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/Time/cdesc-Time.ri b/bin/doc/liquid-4.0.4/ri/Time/cdesc-Time.ri new file mode 100644 index 00000000..d7375460 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/Time/cdesc-Time.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/TrueClass/cdesc-TrueClass.ri b/bin/doc/liquid-4.0.4/ri/TrueClass/cdesc-TrueClass.ri new file mode 100644 index 00000000..df67dc5c Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/TrueClass/cdesc-TrueClass.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/cache.ri b/bin/doc/liquid-4.0.4/ri/cache.ri new file mode 100644 index 00000000..70d07a49 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/cache.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/page-History_md.ri b/bin/doc/liquid-4.0.4/ri/page-History_md.ri new file mode 100644 index 00000000..d067a7c6 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/page-History_md.ri differ diff --git a/bin/doc/liquid-4.0.4/ri/page-README_md.ri b/bin/doc/liquid-4.0.4/ri/page-README_md.ri new file mode 100644 index 00000000..b0a5cab1 Binary files /dev/null and b/bin/doc/liquid-4.0.4/ri/page-README_md.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_change-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_change-i.ri new file mode 100644 index 00000000..a55f8414 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_change-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_configure-i.ri new file mode 100644 index 00000000..cdc8caa8 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_event_path-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_event_path-i.ri new file mode 100644 index 00000000..70f6cb82 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_event_path-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_find-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_find-i.ri new file mode 100644 index 00000000..c5beec62 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_find-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_process_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_process_event-i.ri new file mode 100644 index 00000000..b8b61ab5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_process_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_run-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_run-i.ri new file mode 100644 index 00000000..fee073cc Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_run-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_file-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_file-i.ri new file mode 100644 index 00000000..abf76a04 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_file-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_for_new_file-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_for_new_file-i.ri new file mode 100644 index 00000000..7b1c6ad7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/_watch_for_new_file-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/cdesc-BSD.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/cdesc-BSD.ri new file mode 100644 index 00000000..0209b570 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/cdesc-BSD.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/usable%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/usable%3f-c.ri new file mode 100644 index 00000000..8f7ad016 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/BSD/usable%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_log_exception-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_log_exception-i.ri new file mode 100644 index 00000000..f489d463 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_log_exception-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_queue_change-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_queue_change-i.ri new file mode 100644 index 00000000..44953764 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_queue_change-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_stop-i.ri new file mode 100644 index 00000000..c961e821 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_timed-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_timed-i.ri new file mode 100644 index 00000000..1e99eb61 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/_timed-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/cdesc-Base.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/cdesc-Base.ri new file mode 100644 index 00000000..73ccbaeb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/cdesc-Base.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/config-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/config-i.ri new file mode 100644 index 00000000..52832b4c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/config-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/configure-i.ri new file mode 100644 index 00000000..b1dab761 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/new-c.ri new file mode 100644 index 00000000..33f1b48c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/options-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/options-i.ri new file mode 100644 index 00000000..345a3081 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/options-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/start-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/start-i.ri new file mode 100644 index 00000000..61e002f8 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/start-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/started%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/started%3f-i.ri new file mode 100644 index 00000000..b07603a6 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/started%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/stop-i.ri new file mode 100644 index 00000000..d73f7acb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/usable%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/usable%3f-c.ri new file mode 100644 index 00000000..32a621d9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Base/usable%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/adapter_options-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/adapter_options-i.ri new file mode 100644 index 00000000..4ec6ba5a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/adapter_options-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/cdesc-Config.ri new file mode 100644 index 00000000..59ee89d5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/directories-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/directories-i.ri new file mode 100644 index 00000000..19994e7c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/directories-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/new-c.ri new file mode 100644 index 00000000..f1a169dd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/queue-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/queue-i.ri new file mode 100644 index 00000000..8e1c532a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/queue-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/silencer-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/silencer-i.ri new file mode 100644 index 00000000..ef993170 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Config/silencer-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_configure-i.ri new file mode 100644 index 00000000..e332f2be Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_changes-i.ri new file mode 100644 index 00000000..1b1e30e6 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_event-i.ri new file mode 100644 index 00000000..a9e5aa7c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_process_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_run-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_run-i.ri new file mode 100644 index 00000000..97f30637 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_run-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_stop-i.ri new file mode 100644 index 00000000..6e1b7d7e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/_stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/cdesc-Darwin.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/cdesc-Darwin.ri new file mode 100644 index 00000000..115dc368 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/cdesc-Darwin.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/usable%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/usable%3f-c.ri new file mode 100644 index 00000000..4edf214e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Darwin/usable%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_change-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_change-i.ri new file mode 100644 index 00000000..7caf7948 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_change-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_configure-i.ri new file mode 100644 index 00000000..245c367e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_dir_event%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_dir_event%3f-i.ri new file mode 100644 index 00000000..b1ef70b6 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_dir_event%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_process_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_process_event-i.ri new file mode 100644 index 00000000..1b08eae4 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_process_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_run-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_run-i.ri new file mode 100644 index 00000000..df12891d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_run-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_skip_event%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_skip_event%3f-i.ri new file mode 100644 index 00000000..b778dc0b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_skip_event%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_stop-i.ri new file mode 100644 index 00000000..586a1604 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/_stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/cdesc-Linux.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/cdesc-Linux.ri new file mode 100644 index 00000000..3fd23e89 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Linux/cdesc-Linux.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_configure-i.ri new file mode 100644 index 00000000..0a9a3f0d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_process_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_process_event-i.ri new file mode 100644 index 00000000..7298d7aa Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_process_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_run-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_run-i.ri new file mode 100644 index 00000000..8983403e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/_run-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/cdesc-Polling.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/cdesc-Polling.ri new file mode 100644 index 00000000..2c6840f0 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Polling/cdesc-Polling.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_change-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_change-i.ri new file mode 100644 index 00000000..14399669 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_change-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_configure-i.ri new file mode 100644 index 00000000..0f3a2a50 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_process_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_process_event-i.ri new file mode 100644 index 00000000..86834fad Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_process_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_run-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_run-i.ri new file mode 100644 index 00000000..c98a340e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/_run-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/cdesc-Windows.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/cdesc-Windows.ri new file mode 100644 index 00000000..80c5887b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/cdesc-Windows.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/usable%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/usable%3f-c.ri new file mode 100644 index 00000000..b6f94614 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/Windows/usable%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/_usable_adapter_class-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/_usable_adapter_class-c.ri new file mode 100644 index 00000000..67e26314 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/_usable_adapter_class-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/_warn_polling_fallback-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/_warn_polling_fallback-c.ri new file mode 100644 index 00000000..f3f127e2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/_warn_polling_fallback-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/cdesc-Adapter.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/cdesc-Adapter.ri new file mode 100644 index 00000000..79f8ed05 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/cdesc-Adapter.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Adapter/select-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Adapter/select-c.ri new file mode 100644 index 00000000..67fbc0b5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Adapter/select-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Backend/adapter-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Backend/adapter-i.ri new file mode 100644 index 00000000..685f25cb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Backend/adapter-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Backend/cdesc-Backend.ri b/bin/doc/listen-3.10.0/ri/Listen/Backend/cdesc-Backend.ri new file mode 100644 index 00000000..ffdc3910 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Backend/cdesc-Backend.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Backend/min_delay_between_events-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Backend/min_delay_between_events-i.ri new file mode 100644 index 00000000..9cc68479 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Backend/min_delay_between_events-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Backend/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Backend/new-c.ri new file mode 100644 index 00000000..57f9a508 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Backend/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/CLI/cdesc-CLI.ri b/bin/doc/listen-3.10.0/ri/Listen/CLI/cdesc-CLI.ri new file mode 100644 index 00000000..fd2bd404 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/CLI/cdesc-CLI.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/CLI/start-i.ri b/bin/doc/listen-3.10.0/ri/Listen/CLI/start-i.ri new file mode 100644 index 00000000..c2e68144 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/CLI/start-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/cdesc-Config.ri new file mode 100644 index 00000000..7cbe2e58 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/new-c.ri new file mode 100644 index 00000000..b0d9b606 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/Config/queue-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/queue-i.ri new file mode 100644 index 00000000..521b2dd7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/queue-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/Config/silenced%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/silenced%3f-i.ri new file mode 100644 index 00000000..f09ed2da Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/Config/silenced%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/cdesc-Change.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/cdesc-Change.ri new file mode 100644 index 00000000..7855fa50 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/cdesc-Change.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/invalidate-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/invalidate-i.ri new file mode 100644 index 00000000..4142f369 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/invalidate-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/new-c.ri new file mode 100644 index 00000000..3e019f8b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Change/record-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Change/record-i.ri new file mode 100644 index 00000000..b19732fd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Change/record-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/_async_changes-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/_async_changes-c.ri new file mode 100644 index 00000000..031b9924 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/_async_changes-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/_change-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/_change-c.ri new file mode 100644 index 00000000..eee45fd4 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/_change-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/_children-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/_children-c.ri new file mode 100644 index 00000000..cefd1d8a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/_children-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/ascendant_of%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/ascendant_of%3f-c.ri new file mode 100644 index 00000000..0e0436f5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/ascendant_of%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/cdesc-Directory.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/cdesc-Directory.ri new file mode 100644 index 00000000..ac64161c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/cdesc-Directory.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Directory/scan-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Directory/scan-c.ri new file mode 100644 index 00000000..40d20a3a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Directory/scan-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Error/INotifyMaxWatchesExceeded/cdesc-INotifyMaxWatchesExceeded.ri b/bin/doc/listen-3.10.0/ri/Listen/Error/INotifyMaxWatchesExceeded/cdesc-INotifyMaxWatchesExceeded.ri new file mode 100644 index 00000000..4f4c5e17 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Error/INotifyMaxWatchesExceeded/cdesc-INotifyMaxWatchesExceeded.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Error/NotStarted/cdesc-NotStarted.ri b/bin/doc/listen-3.10.0/ri/Listen/Error/NotStarted/cdesc-NotStarted.ri new file mode 100644 index 00000000..62cac21b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Error/NotStarted/cdesc-NotStarted.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Error/SymlinkLoop/cdesc-SymlinkLoop.ri b/bin/doc/listen-3.10.0/ri/Listen/Error/SymlinkLoop/cdesc-SymlinkLoop.ri new file mode 100644 index 00000000..8944e31a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Error/SymlinkLoop/cdesc-SymlinkLoop.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Error/cdesc-Error.ri b/bin/doc/listen-3.10.0/ri/Listen/Error/cdesc-Error.ri new file mode 100644 index 00000000..6aff9b10 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Error/cdesc-Error.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/call-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/call-i.ri new file mode 100644 index 00000000..ec42b661 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/call-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/callable%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/callable%3f-i.ri new file mode 100644 index 00000000..602fa1ab Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/callable%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/cdesc-Config.ri new file mode 100644 index 00000000..59aa00e9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/event_queue-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/event_queue-i.ri new file mode 100644 index 00000000..c5fd1d58 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/event_queue-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/listener-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/listener-i.ri new file mode 100644 index 00000000..4dc9fedb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/listener-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/min_delay_between_events-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/min_delay_between_events-i.ri new file mode 100644 index 00000000..c075fcfc Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/min_delay_between_events-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/new-c.ri new file mode 100644 index 00000000..23c0aa4f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/optimize_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/optimize_changes-i.ri new file mode 100644 index 00000000..2b314332 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/optimize_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Config/sleep-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/sleep-i.ri new file mode 100644 index 00000000..bfbeca62 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Config/sleep-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_process_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_process_changes-i.ri new file mode 100644 index 00000000..826aa4a7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_process_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_wakeup-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_wakeup-i.ri new file mode 100644 index 00000000..86e87194 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/_wakeup-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/cdesc-Loop.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/cdesc-Loop.ri new file mode 100644 index 00000000..651baa12 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/cdesc-Loop.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/new-c.ri new file mode 100644 index 00000000..ff01bb5b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/pause-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/pause-i.ri new file mode 100644 index 00000000..f20289c0 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/pause-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/start-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/start-i.ri new file mode 100644 index 00000000..db6f5630 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/start-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/started%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/started%3f-i.ri new file mode 100644 index 00000000..343a762e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/started%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stop-i.ri new file mode 100644 index 00000000..f3a5c2dd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stopped%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stopped%3f-i.ri new file mode 100644 index 00000000..eccc6f34 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/stopped%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/wakeup_on_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/wakeup_on_event-i.ri new file mode 100644 index 00000000..ea7f96d7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Loop/wakeup_on_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/Stopped/cdesc-Stopped.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/Stopped/cdesc-Stopped.ri new file mode 100644 index 00000000..d9c336e9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/Stopped/cdesc-Stopped.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_check_stopped-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_check_stopped-i.ri new file mode 100644 index 00000000..350fa204 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_check_stopped-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_deadline-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_deadline-i.ri new file mode 100644 index 00000000..57f4e24b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_deadline-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_flush_wakeup_reasons-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_flush_wakeup_reasons-i.ri new file mode 100644 index 00000000..cb54599e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_flush_wakeup_reasons-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_process_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_process_changes-i.ri new file mode 100644 index 00000000..6fef74c2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_process_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_remember_time_of_first_unprocessed_event-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_remember_time_of_first_unprocessed_event-i.ri new file mode 100644 index 00000000..f98c9054 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_remember_time_of_first_unprocessed_event-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_reset_no_unprocessed_events-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_reset_no_unprocessed_events-i.ri new file mode 100644 index 00000000..16e715e1 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_reset_no_unprocessed_events-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_sleep-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_sleep-i.ri new file mode 100644 index 00000000..0ff550bc Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_sleep-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events-i.ri new file mode 100644 index 00000000..cddb6433 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events_calm_down-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events_calm_down-i.ri new file mode 100644 index 00000000..5b6d9d25 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_events_calm_down-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_no_longer_paused-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_no_longer_paused-i.ri new file mode 100644 index 00000000..27a10b2f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/_wait_until_no_longer_paused-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/cdesc-Processor.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/cdesc-Processor.ri new file mode 100644 index 00000000..c2f0cf31 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/cdesc-Processor.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/config-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/config-i.ri new file mode 100644 index 00000000..9fe94f5c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/config-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/loop_for-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/loop_for-i.ri new file mode 100644 index 00000000..397b39b4 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/loop_for-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/new-c.ri new file mode 100644 index 00000000..ecb342ec Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Processor/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/%3c%3c-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/%3c%3c-i.ri new file mode 100644 index 00000000..db5d4f5b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/%3c%3c-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/cdesc-Config.ri new file mode 100644 index 00000000..8db0b13e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/new-c.ri new file mode 100644 index 00000000..87edf470 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/relative%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/relative%3f-i.ri new file mode 100644 index 00000000..b4406cc3 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/Config/relative%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/_safe_relative_from_cwd-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/_safe_relative_from_cwd-i.ri new file mode 100644 index 00000000..2715db59 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/_safe_relative_from_cwd-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/cdesc-Queue.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/cdesc-Queue.ri new file mode 100644 index 00000000..a876764a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/cdesc-Queue.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/new-c.ri new file mode 100644 index 00000000..a7482ece Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/Queue/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Event/cdesc-Event.ri b/bin/doc/listen-3.10.0/ri/Listen/Event/cdesc-Event.ri new file mode 100644 index 00000000..384d9a19 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Event/cdesc-Event.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/cdesc-ClassMethods.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/cdesc-ClassMethods.ri new file mode 100644 index 00000000..453d386a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/cdesc-ClassMethods.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/start_state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/start_state-i.ri new file mode 100644 index 00000000..3d44ee2e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/start_state-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/state-i.ri new file mode 100644 index 00000000..6bfaacc7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/state-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/states-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/states-i.ri new file mode 100644 index 00000000..a614d86b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/ClassMethods/states-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/call-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/call-i.ri new file mode 100644 index 00000000..fff8516c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/call-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/cdesc-State.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/cdesc-State.ri new file mode 100644 index 00000000..8cdf3733 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/cdesc-State.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/name-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/name-i.ri new file mode 100644 index 00000000..30e4f35c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/name-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/new-c.ri new file mode 100644 index 00000000..0aa185dd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/transitions-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/transitions-i.ri new file mode 100644 index 00000000..e3249c14 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/transitions-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/State/valid_transition%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/valid_transition%3f-i.ri new file mode 100644 index 00000000..801f2caf Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/State/valid_transition%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/cdesc-FSM.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/cdesc-FSM.ri new file mode 100644 index 00000000..39f985d9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/cdesc-FSM.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/current_state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/current_state-i.ri new file mode 100644 index 00000000..b1b556a3 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/current_state-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/included-c.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/included-c.ri new file mode 100644 index 00000000..4c90a57d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/included-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/initialize_fsm-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/initialize_fsm-i.ri new file mode 100644 index 00000000..163958b2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/initialize_fsm-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/state-i.ri new file mode 100644 index 00000000..3f5c286e --- /dev/null +++ b/bin/doc/listen-3.10.0/ri/Listen/FSM/state-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +state:ETI"Listen::FSM#state;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"1Current state of the FSM, stored as a symbol;T: +@fileI"lib/listen/fsm.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Listen::FSM;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/transition%21-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition%21-i.ri new file mode 100644 index 00000000..990c2090 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition%21-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/transition-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition-i.ri new file mode 100644 index 00000000..b6250db5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/transition_with_callbacks%21-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition_with_callbacks%21-i.ri new file mode 100644 index 00000000..2b6d490b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/transition_with_callbacks%21-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/validate_and_sanitize_new_state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/validate_and_sanitize_new_state-i.ri new file mode 100644 index 00000000..b8debded Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/validate_and_sanitize_new_state-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/FSM/wait_for_state-i.ri b/bin/doc/listen-3.10.0/ri/Listen/FSM/wait_for_state-i.ri new file mode 100644 index 00000000..adb1256d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/FSM/wait_for_state-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/File/cdesc-File.ri b/bin/doc/listen-3.10.0/ri/Listen/File/cdesc-File.ri new file mode 100644 index 00000000..cd900271 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/File/cdesc-File.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/File/change-c.ri b/bin/doc/listen-3.10.0/ri/Listen/File/change-c.ri new file mode 100644 index 00000000..b8e885bb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/File/change-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/File/inaccurate_mac_time%3f-c.ri b/bin/doc/listen-3.10.0/ri/Listen/File/inaccurate_mac_time%3f-c.ri new file mode 100644 index 00000000..d7d1daf6 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/File/inaccurate_mac_time%3f-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Forwarder/cdesc-Forwarder.ri b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/cdesc-Forwarder.ri new file mode 100644 index 00000000..00eb0159 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/cdesc-Forwarder.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Forwarder/logger-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/logger-i.ri new file mode 100644 index 00000000..72a89529 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/logger-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Forwarder/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/new-c.ri new file mode 100644 index 00000000..8b243d01 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Forwarder/start-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/start-i.ri new file mode 100644 index 00000000..773e3415 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Forwarder/start-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_instance_options-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_instance_options-i.ri new file mode 100644 index 00000000..4e7d2ee7 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_instance_options-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_select_options-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_select_options-i.ri new file mode 100644 index 00000000..caaa1b5d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/adapter_select_options-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/cdesc-Config.ri new file mode 100644 index 00000000..6ae16df2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/min_delay_between_events-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/min_delay_between_events-i.ri new file mode 100644 index 00000000..fbdb1624 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/min_delay_between_events-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/new-c.ri new file mode 100644 index 00000000..ccc9edf9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/relative%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/relative%3f-i.ri new file mode 100644 index 00000000..5ffaf9fe Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/relative%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/silencer_rules-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/silencer_rules-i.ri new file mode 100644 index 00000000..40cbc785 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/Config/silencer_rules-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/cdesc-Listener.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/cdesc-Listener.ri new file mode 100644 index 00000000..833667f1 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/cdesc-Listener.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore%21-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore%21-i.ri new file mode 100644 index 00000000..903254e5 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore%21-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore-i.ri new file mode 100644 index 00000000..210a2066 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/ignore-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/new-c.ri new file mode 100644 index 00000000..e9bcd804 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/only-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/only-i.ri new file mode 100644 index 00000000..647449fc Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/only-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/pause-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/pause-i.ri new file mode 100644 index 00000000..59b53595 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/pause-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/paused%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/paused%3f-i.ri new file mode 100644 index 00000000..e3908a0a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/paused%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/processing%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/processing%3f-i.ri new file mode 100644 index 00000000..333a7ee0 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/processing%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/start-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/start-i.ri new file mode 100644 index 00000000..adc6c0be Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/start-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/stop-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/stop-i.ri new file mode 100644 index 00000000..f9b7d286 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/stop-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Listener/stopped%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Listener/stopped%3f-i.ri new file mode 100644 index 00000000..cba44aa0 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Listener/stopped%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/cdesc-MonotonicTime.ri b/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/cdesc-MonotonicTime.ri new file mode 100644 index 00000000..8b50c231 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/cdesc-MonotonicTime.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/now-c.ri b/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/now-c.ri new file mode 100644 index 00000000..9638700b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/MonotonicTime/now-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Options/cdesc-Options.ri b/bin/doc/listen-3.10.0/ri/Listen/Options/cdesc-Options.ri new file mode 100644 index 00000000..6f939fdf Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Options/cdesc-Options.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Options/method_missing-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Options/method_missing-i.ri new file mode 100644 index 00000000..b8459f1f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Options/method_missing-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Options/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Options/new-c.ri new file mode 100644 index 00000000..124d3ada Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Options/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Options/respond_to_missing%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Options/respond_to_missing%3f-i.ri new file mode 100644 index 00000000..a0c5e01a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Options/respond_to_missing%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/cdesc-Config.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/cdesc-Config.ri new file mode 100644 index 00000000..1a112f1a Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/cdesc-Config.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/debug-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/debug-i.ri new file mode 100644 index 00000000..58a98013 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/debug-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/exist%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/exist%3f-i.ri new file mode 100644 index 00000000..2a67d6df Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/exist%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/new-c.ri new file mode 100644 index 00000000..9a6b6238 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/silenced%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/silenced%3f-i.ri new file mode 100644 index 00000000..226f10ff Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/Config/silenced%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_calculate_add_remove_difference-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_calculate_add_remove_difference-i.ri new file mode 100644 index 00000000..9e61f2fb Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_calculate_add_remove_difference-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_logical_action_for-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_logical_action_for-i.ri new file mode 100644 index 00000000..0733b6bd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_logical_action_for-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_reinterpret_related_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_reinterpret_related_changes-i.ri new file mode 100644 index 00000000..c2890871 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_reinterpret_related_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_squash_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_squash_changes-i.ri new file mode 100644 index 00000000..6a4c4684 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/_squash_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/cdesc-QueueOptimizer.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/cdesc-QueueOptimizer.ri new file mode 100644 index 00000000..83b10693 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/cdesc-QueueOptimizer.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/config-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/config-i.ri new file mode 100644 index 00000000..9880d015 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/config-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/editor_modified%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/editor_modified%3f-i.ri new file mode 100644 index 00000000..248aebd4 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/editor_modified%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/new-c.ri new file mode 100644 index 00000000..ed9919e2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/smoosh_changes-i.ri b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/smoosh_changes-i.ri new file mode 100644 index 00000000..d9323a47 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/QueueOptimizer/smoosh_changes-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_entries-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_entries-i.ri new file mode 100644 index 00000000..678169ab Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_entries-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_join-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_join-i.ri new file mode 100644 index 00000000..d26e67b8 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/_join-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/cdesc-Entry.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/cdesc-Entry.ri new file mode 100644 index 00000000..a967bf02 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/cdesc-Entry.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/children-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/children-i.ri new file mode 100644 index 00000000..b09a5474 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/children-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/meta-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/meta-i.ri new file mode 100644 index 00000000..0c7610df Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/meta-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/name-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/name-i.ri new file mode 100644 index 00000000..7d658818 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/name-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/new-c.ri new file mode 100644 index 00000000..40faadcc Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/real_path-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/real_path-i.ri new file mode 100644 index 00000000..6944c0c9 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/real_path-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/record_dir_key-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/record_dir_key-i.ri new file mode 100644 index 00000000..3d48bf2b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/record_dir_key-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/relative-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/relative-i.ri new file mode 100644 index 00000000..3215723f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/relative-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/root-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/root-i.ri new file mode 100644 index 00000000..d36e22cd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/root-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/sys_path-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/sys_path-i.ri new file mode 100644 index 00000000..e502e16b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/Entry/sys_path-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/_fail-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/_fail-i.ri new file mode 100644 index 00000000..7ff33af1 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/_fail-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/cdesc-SymlinkDetector.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/cdesc-SymlinkDetector.ri new file mode 100644 index 00000000..f024b90d Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/cdesc-SymlinkDetector.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/new-c.ri new file mode 100644 index 00000000..6012f44f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/verify_unwatched%21-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/verify_unwatched%21-i.ri new file mode 100644 index 00000000..81ff732c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/verify_unwatched%21-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/warn-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/warn-i.ri new file mode 100644 index 00000000..9c687b08 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/SymlinkDetector/warn-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_build_dir-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_build_dir-i.ri new file mode 100644 index 00000000..18323ecf Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_build_dir-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_try_file-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_try_file-i.ri new file mode 100644 index 00000000..8e1682da Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_try_file-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_unset_path-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_unset_path-i.ri new file mode 100644 index 00000000..d6819183 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_unset_path-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_update_file-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_update_file-i.ri new file mode 100644 index 00000000..dcbfffbd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/_fast_update_file-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/add_dir-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/add_dir-i.ri new file mode 100644 index 00000000..8bcfd725 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/add_dir-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/build-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/build-i.ri new file mode 100644 index 00000000..c2c0cf77 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/build-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/cdesc-Record.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/cdesc-Record.ri new file mode 100644 index 00000000..713ac20c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/cdesc-Record.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/dir_entries-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/dir_entries-i.ri new file mode 100644 index 00000000..665d32a2 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/dir_entries-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/empty_dirname%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/empty_dirname%3f-i.ri new file mode 100644 index 00000000..37bea419 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/empty_dirname%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/file_data-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/file_data-i.ri new file mode 100644 index 00000000..c37b984e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/file_data-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/new-c.ri new file mode 100644 index 00000000..cb0fb8ec Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/reset_tree-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/reset_tree-i.ri new file mode 100644 index 00000000..14bbb1a3 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/reset_tree-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/root-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/root-i.ri new file mode 100644 index 00000000..8b2e30d0 --- /dev/null +++ b/bin/doc/listen-3.10.0/ri/Listen/Record/root-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" root:ETI"Listen::Record#root;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"4TODO: one Record object per watched directory? ;TI"TODO: deprecate;T: +@fileI"lib/listen/record.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Listen::Record;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/unset_path-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/unset_path-i.ri new file mode 100644 index 00000000..f0b46db4 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/unset_path-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Record/update_file-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Record/update_file-i.ri new file mode 100644 index 00000000..350c58a0 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Record/update_file-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/_reconfigure_silencer-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/_reconfigure_silencer-i.ri new file mode 100644 index 00000000..4b17587c Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/_reconfigure_silencer-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/append_ignores-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/append_ignores-i.ri new file mode 100644 index 00000000..7f5f1252 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/append_ignores-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/cdesc-Controller.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/cdesc-Controller.ri new file mode 100644 index 00000000..6fa3b6cd Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/cdesc-Controller.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/new-c.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/new-c.ri new file mode 100644 index 00000000..fa98971f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/new-c.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_bang_ignores-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_bang_ignores-i.ri new file mode 100644 index 00000000..169965ab Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_bang_ignores-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_only-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_only-i.ri new file mode 100644 index 00000000..00965d60 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/Controller/replace_with_only-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/_ignore%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_ignore%3f-i.ri new file mode 100644 index 00000000..d017ff8e Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_ignore%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/_init_ignores-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_init_ignores-i.ri new file mode 100644 index 00000000..50d8021b Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_init_ignores-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/_only%3f-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_only%3f-i.ri new file mode 100644 index 00000000..2b2bc4ee Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/_only%3f-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/cdesc-Silencer.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/cdesc-Silencer.ri new file mode 100644 index 00000000..e2de736f Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/cdesc-Silencer.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/configure-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/configure-i.ri new file mode 100644 index 00000000..91f9ca39 Binary files /dev/null and b/bin/doc/listen-3.10.0/ri/Listen/Silencer/configure-i.ri differ diff --git a/bin/doc/listen-3.10.0/ri/Listen/Silencer/ignore_patterns-i.ri b/bin/doc/listen-3.10.0/ri/Listen/Silencer/ignore_patterns-i.ri new file mode 100644 index 00000000..4256ef93 --- /dev/null +++ b/bin/doc/listen-3.10.0/ri/Listen/Silencer/ignore_patterns-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"ignore_patterns:ETI"%Listen::Silencer#ignore_patterns;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"task (only valid if the task was defined with the detect ;TI"location option set).;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/name-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/name-i.ri new file mode 100644 index 00000000..2d690239 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/name-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/needed%3f-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/needed%3f-i.ri new file mode 100644 index 00000000..77e57ce9 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/needed%3f-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/new-c.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/new-c.ri new file mode 100644 index 00000000..2c13636f Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/new-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/order_only_prerequisites-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/order_only_prerequisites-i.ri new file mode 100644 index 00000000..63738101 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/Task/order_only_prerequisites-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"order_only_prerequisites:ETI"(Rake::Task#order_only_prerequisites;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"1List of order only prerequisites for a task.;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/prereqs-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/prereqs-i.ri new file mode 100644 index 00000000..bc88d1c0 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/Task/prereqs-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" prereqs:ETI"Rake::Task#prereqs;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"&List of prerequisites for a task.;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisite_tasks-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisite_tasks-i.ri new file mode 100644 index 00000000..52bbe5ac Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisite_tasks-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisites-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisites-i.ri new file mode 100644 index 00000000..5eba38b3 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/Task/prerequisites-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"prerequisites:ETI"Rake::Task#prerequisites;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"&List of prerequisites for a task.;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/reenable-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/reenable-i.ri new file mode 100644 index 00000000..13b84c8e Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/reenable-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/scope-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/scope-i.ri new file mode 100644 index 00000000..a23e184f --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/Task/scope-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +scope:ETI"Rake::Task#scope;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"HArray of nested namespaces names used for task lookup by this task.;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/scope_name-c.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/scope_name-c.ri new file mode 100644 index 00000000..44e1d1b6 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/scope_name-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/set_arg_names-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/set_arg_names-i.ri new file mode 100644 index 00000000..2e579ffe Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/set_arg_names-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/source-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/source-i.ri new file mode 100644 index 00000000..4d146a25 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/source-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/sources-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/sources-i.ri new file mode 100644 index 00000000..f0839f89 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/Task/sources-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" sources:ETI"Rake::Task#sources;TI"W;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"List of sources for task.;T: +@fileI"lib/rake/task.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::Task;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/task_defined%3f-c.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/task_defined%3f-c.ri new file mode 100644 index 00000000..17cf5d82 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/task_defined%3f-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/tasks-c.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/tasks-c.ri new file mode 100644 index 00000000..bef4497c Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/tasks-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/timestamp-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/timestamp-i.ri new file mode 100644 index 00000000..485b30f8 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/timestamp-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/to_s-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/to_s-i.ri new file mode 100644 index 00000000..9f379731 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/to_s-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Task/transform_comments-i.ri b/bin/doc/rake-13.4.2/ri/Rake/Task/transform_comments-i.ri new file mode 100644 index 00000000..42beb7d3 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Task/transform_comments-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArgumentError/cdesc-TaskArgumentError.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArgumentError/cdesc-TaskArgumentError.ri new file mode 100644 index 00000000..d6dd9d45 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArgumentError/cdesc-TaskArgumentError.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/%5b%5d-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/%5b%5d-i.ri new file mode 100644 index 00000000..163c9202 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/%5b%5d-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/cdesc-TaskArguments.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/cdesc-TaskArguments.ri new file mode 100644 index 00000000..9a20b6e8 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/cdesc-TaskArguments.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/deconstruct_keys-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/deconstruct_keys-i.ri new file mode 100644 index 00000000..d109faca Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/deconstruct_keys-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/each-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/each-i.ri new file mode 100644 index 00000000..4fe37107 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/each-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/extras-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/extras-i.ri new file mode 100644 index 00000000..4f76b9d7 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/extras-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/fetch-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/fetch-i.ri new file mode 100644 index 00000000..e02c45f1 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/fetch-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/has_key%3f-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/has_key%3f-i.ri new file mode 100644 index 00000000..46f8e35f Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/has_key%3f-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/key%3f-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/key%3f-i.ri new file mode 100644 index 00000000..4a30263d Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/key%3f-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/method_missing-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/method_missing-i.ri new file mode 100644 index 00000000..a68801fd Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/method_missing-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/names-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/names-i.ri new file mode 100644 index 00000000..d17b925a --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/names-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +names:ETI"Rake::TaskArguments#names;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Argument names;T: +@fileI"lib/rake/task_arguments.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TaskArguments;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new-c.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new-c.ri new file mode 100644 index 00000000..cb9a3fc1 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new_scope-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new_scope-i.ri new file mode 100644 index 00000000..56c0e19c Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/new_scope-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_a-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_a-i.ri new file mode 100644 index 00000000..8d2c48c4 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_a-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_hash-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_hash-i.ri new file mode 100644 index 00000000..515016e7 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/to_hash-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/values_at-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/values_at-i.ri new file mode 100644 index 00000000..6fa95876 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/values_at-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/with_defaults-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/with_defaults-i.ri new file mode 100644 index 00000000..ae89ecfa Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskArguments/with_defaults-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskLib/cdesc-TaskLib.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskLib/cdesc-TaskLib.ri new file mode 100644 index 00000000..83a86786 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskLib/cdesc-TaskLib.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/%5b%5d-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/%5b%5d-i.ri new file mode 100644 index 00000000..2ab26acb Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/%5b%5d-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/add_location-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/add_location-i.ri new file mode 100644 index 00000000..88546318 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/add_location-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/attempt_rule-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/attempt_rule-i.ri new file mode 100644 index 00000000..6ee72e5b Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/attempt_rule-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/cdesc-TaskManager.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/cdesc-TaskManager.ri new file mode 100644 index 00000000..36ca64d7 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/cdesc-TaskManager.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/clear-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/clear-i.ri new file mode 100644 index 00000000..a4a6ab25 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/clear-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/current_scope-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/current_scope-i.ri new file mode 100644 index 00000000..5fa0a932 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/current_scope-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/enhance_with_matching_rule-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/enhance_with_matching_rule-i.ri new file mode 100644 index 00000000..143ef85b Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/enhance_with_matching_rule-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/find_location-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/find_location-i.ri new file mode 100644 index 00000000..bd3dae0d Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/find_location-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_did_you_mean_suggestions-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_did_you_mean_suggestions-i.ri new file mode 100644 index 00000000..d135cbde Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_did_you_mean_suggestions-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_message_for_undefined_task-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_message_for_undefined_task-i.ri new file mode 100644 index 00000000..81978f38 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_message_for_undefined_task-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_name-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_name-i.ri new file mode 100644 index 00000000..24f3ae46 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/generate_name-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/get_description-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/get_description-i.ri new file mode 100644 index 00000000..d1d7e239 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/get_description-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/in_namespace-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/in_namespace-i.ri new file mode 100644 index 00000000..746a48f7 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/in_namespace-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/intern-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/intern-i.ri new file mode 100644 index 00000000..0f726bdd Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/intern-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/last_description-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/last_description-i.ri new file mode 100644 index 00000000..60aba15b --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/last_description-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"last_description:ETI"'Rake::TaskManager#last_description;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"1Track the last comment made in the Rakefile.;T: +@fileI"lib/rake/task_manager.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TaskManager;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup-i.ri new file mode 100644 index 00000000..b9c61737 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup_in_scope-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup_in_scope-i.ri new file mode 100644 index 00000000..25cc7a42 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/lookup_in_scope-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/make_sources-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/make_sources-i.ri new file mode 100644 index 00000000..62d9191d Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/make_sources-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args-i.ri new file mode 100644 index 00000000..ec4a7e53 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args_without_dependencies-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args_without_dependencies-i.ri new file mode 100644 index 00000000..c8830aee Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/resolve_args_without_dependencies-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks-i.ri new file mode 100644 index 00000000..5cc892bf Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks_in_scope-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks_in_scope-i.ri new file mode 100644 index 00000000..d46be8dc Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TaskManager/tasks_in_scope-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/cdesc-TestTask.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/cdesc-TestTask.ri new file mode 100644 index 00000000..794d15db Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TestTask/cdesc-TestTask.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/define-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/define-i.ri new file mode 100644 index 00000000..86cdce59 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TestTask/define-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/deps-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/deps-i.ri new file mode 100644 index 00000000..72a0258f --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/deps-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" deps:ETI"Rake::TestTask#deps;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Task prerequisites.;T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/description-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/description-i.ri new file mode 100644 index 00000000..04848c30 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/description-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"description:ETI"Rake::TestTask#description;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I";Description of the test task. (default is 'Run tests');T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/libs-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/libs-i.ri new file mode 100644 index 00000000..843cec19 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/libs-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" libs:ETI"Rake::TestTask#libs;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@List of directories added to $LOAD_PATH before running the ;TI"tests. (default is 'lib');T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/loader-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/loader-i.ri new file mode 100644 index 00000000..6d2e8d66 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TestTask/loader-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/name-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/name-i.ri new file mode 100644 index 00000000..072d5eb6 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI"Rake::TestTask#name;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"*Name of test task. (default is :test);T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/new-c.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/new-c.ri new file mode 100644 index 00000000..6b61a9de Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TestTask/new-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/options-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/options-i.ri new file mode 100644 index 00000000..441489eb --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/options-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" options:ETI"Rake::TestTask#options;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"9Test options passed to the test suite. An explicit ;TI"DTESTOPTS=opts on the command line will override this. (default ;TI" is NONE);T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/pattern-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/pattern-i.ri new file mode 100644 index 00000000..a1a94cf8 --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/pattern-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" pattern:ETI"Rake::TestTask#pattern;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"CGlob pattern to match test files. (default is 'test/test*.rb');T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/ruby_opts-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/ruby_opts-i.ri new file mode 100644 index 00000000..8927650e --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/ruby_opts-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"ruby_opts:ETI"Rake::TestTask#ruby_opts;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"LArray of command line options to pass to ruby when running test loader.;T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/test_files%3d-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/test_files%3d-i.ri new file mode 100644 index 00000000..a7811648 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TestTask/test_files%3d-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TestTask/verbose-i.ri b/bin/doc/rake-13.4.2/ri/Rake/TestTask/verbose-i.ri new file mode 100644 index 00000000..87bdd91e --- /dev/null +++ b/bin/doc/rake-13.4.2/ri/Rake/TestTask/verbose-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" verbose:ETI"Rake::TestTask#verbose;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Request that the tests be run with the warning flag set. ;TI"@E.g. warning=true implies "ruby -w" used to run the tests. ;TI"(default is true);T: +@fileI"lib/rake/testtask.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rake::TestTask;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rake-13.4.2/ri/Rake/ThreadHistoryDisplay/cdesc-ThreadHistoryDisplay.ri b/bin/doc/rake-13.4.2/ri/Rake/ThreadHistoryDisplay/cdesc-ThreadHistoryDisplay.ri new file mode 100644 index 00000000..3c2670d8 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/ThreadHistoryDisplay/cdesc-ThreadHistoryDisplay.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/ThreadPool/cdesc-ThreadPool.ri b/bin/doc/rake-13.4.2/ri/Rake/ThreadPool/cdesc-ThreadPool.ri new file mode 100644 index 00000000..7583f7bc Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/ThreadPool/cdesc-ThreadPool.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/TraceOutput/cdesc-TraceOutput.ri b/bin/doc/rake-13.4.2/ri/Rake/TraceOutput/cdesc-TraceOutput.ri new file mode 100644 index 00000000..a50f3999 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/TraceOutput/cdesc-TraceOutput.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Version/cdesc-Version.ri b/bin/doc/rake-13.4.2/ri/Rake/Version/cdesc-Version.ri new file mode 100644 index 00000000..4864f2c0 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Version/cdesc-Version.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/Win32/cdesc-Win32.ri b/bin/doc/rake-13.4.2/ri/Rake/Win32/cdesc-Win32.ri new file mode 100644 index 00000000..8633fb2d Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/Win32/cdesc-Win32.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/add_rakelib-c.ri b/bin/doc/rake-13.4.2/ri/Rake/add_rakelib-c.ri new file mode 100644 index 00000000..16d17197 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/add_rakelib-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/application%3d-c.ri b/bin/doc/rake-13.4.2/ri/Rake/application%3d-c.ri new file mode 100644 index 00000000..ba50b493 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/application%3d-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/application-c.ri b/bin/doc/rake-13.4.2/ri/Rake/application-c.ri new file mode 100644 index 00000000..a56afb0a Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/application-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/cdesc-Rake.ri b/bin/doc/rake-13.4.2/ri/Rake/cdesc-Rake.ri new file mode 100644 index 00000000..718859a6 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/cdesc-Rake.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/load_rakefile-c.ri b/bin/doc/rake-13.4.2/ri/Rake/load_rakefile-c.ri new file mode 100644 index 00000000..630a317c Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/load_rakefile-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/original_dir-c.ri b/bin/doc/rake-13.4.2/ri/Rake/original_dir-c.ri new file mode 100644 index 00000000..42285c8d Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/original_dir-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/Rake/with_application-c.ri b/bin/doc/rake-13.4.2/ri/Rake/with_application-c.ri new file mode 100644 index 00000000..2c89c198 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/Rake/with_application-c.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/cdesc-String.ri b/bin/doc/rake-13.4.2/ri/String/cdesc-String.ri new file mode 100644 index 00000000..ccf45bc6 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/cdesc-String.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/ext-i.ri b/bin/doc/rake-13.4.2/ri/String/ext-i.ri new file mode 100644 index 00000000..dc88c9d9 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/ext-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/pathmap-i.ri b/bin/doc/rake-13.4.2/ri/String/pathmap-i.ri new file mode 100644 index 00000000..d7cd7301 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/pathmap-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/pathmap_explode-i.ri b/bin/doc/rake-13.4.2/ri/String/pathmap_explode-i.ri new file mode 100644 index 00000000..ba9de404 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/pathmap_explode-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/pathmap_partial-i.ri b/bin/doc/rake-13.4.2/ri/String/pathmap_partial-i.ri new file mode 100644 index 00000000..96a709cc Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/pathmap_partial-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/String/pathmap_replace-i.ri b/bin/doc/rake-13.4.2/ri/String/pathmap_replace-i.ri new file mode 100644 index 00000000..5208ddf3 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/String/pathmap_replace-i.ri differ diff --git a/bin/doc/rake-13.4.2/ri/cache.ri b/bin/doc/rake-13.4.2/ri/cache.ri new file mode 100644 index 00000000..0df6fa06 Binary files /dev/null and b/bin/doc/rake-13.4.2/ri/cache.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/callback-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/callback-i.ri new file mode 100644 index 00000000..e6d1aa87 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/callback-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/cdesc-FSEvent.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/cdesc-FSEvent.ri new file mode 100644 index 00000000..853611d6 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/cdesc-FSEvent.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/new-c.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/new-c.ri new file mode 100644 index 00000000..e1ee6231 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/new-c.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/open_pipe-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/open_pipe-i.ri new file mode 100644 index 00000000..c31009e9 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/open_pipe-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/options_string-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/options_string-i.ri new file mode 100644 index 00000000..9d795f9c Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/options_string-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/parse_options-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/parse_options-i.ri new file mode 100644 index 00000000..9dce176f Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/parse_options-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/paths-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/paths-i.ri new file mode 100644 index 00000000..2571f8ef Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/paths-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/process_running%3f-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/process_running%3f-i.ri new file mode 100644 index 00000000..4e2a6417 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/process_running%3f-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/run-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/run-i.ri new file mode 100644 index 00000000..26d1fcb0 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/run-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescape-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescape-i.ri new file mode 100644 index 00000000..d17adc40 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescape-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescaped_paths-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescaped_paths-i.ri new file mode 100644 index 00000000..c1407957 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/shellescaped_paths-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/stop-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/stop-i.ri new file mode 100644 index 00000000..83c5f76b Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/stop-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/watch-i.ri b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/watch-i.ri new file mode 100644 index 00000000..0cdc435f Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/FSEvent/watch-i.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/Error/cdesc-Error.ri b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/Error/cdesc-Error.ri new file mode 100644 index 00000000..7c0b7ad7 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/Error/cdesc-Error.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/cdesc-OTNetstring.ri b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/cdesc-OTNetstring.ri new file mode 100644 index 00000000..b4aef8e2 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/cdesc-OTNetstring.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/encode-c.ri b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/encode-c.ri new file mode 100644 index 00000000..6beb0e67 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/encode-c.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/parse-c.ri b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/parse-c.ri new file mode 100644 index 00000000..150b3dd1 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/parse-c.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/with_encoding-c.ri b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/with_encoding-c.ri new file mode 100644 index 00000000..caebe336 Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/OTNetstring/with_encoding-c.ri differ diff --git a/bin/doc/rb-fsevent-0.11.2/ri/cache.ri b/bin/doc/rb-fsevent-0.11.2/ri/cache.ri new file mode 100644 index 00000000..44727d4c Binary files /dev/null and b/bin/doc/rb-fsevent-0.11.2/ri/cache.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/absolute_name-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/absolute_name-i.ri new file mode 100644 index 00000000..9304196e Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/absolute_name-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/callback%21-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/callback%21-i.ri new file mode 100644 index 00000000..c9be3d06 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/callback%21-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cdesc-Event.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cdesc-Event.ri new file mode 100644 index 00000000..2e58dcf0 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cdesc-Event.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/consume-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/consume-c.ri new file mode 100644 index 00000000..51661c93 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/consume-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cookie-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cookie-i.ri new file mode 100644 index 00000000..0f73a73e Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/cookie-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/fix_encoding-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/fix_encoding-i.ri new file mode 100644 index 00000000..35e9709f Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/fix_encoding-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/flags-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/flags-i.ri new file mode 100644 index 00000000..5a376434 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/flags-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/name-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/name-i.ri new file mode 100644 index 00000000..7dced210 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/name-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/new-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/new-c.ri new file mode 100644 index 00000000..1bc59b18 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/new-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/notifier-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/notifier-i.ri new file mode 100644 index 00000000..cdc75a0a Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/notifier-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/related-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/related-i.ri new file mode 100644 index 00000000..2e0b8fc9 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/related-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/size-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/size-i.ri new file mode 100644 index 00000000..5ef20fd6 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/size-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher-i.ri new file mode 100644 index 00000000..00ce3451 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher_id-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher_id-i.ri new file mode 100644 index 00000000..248f9f2e Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Event/watcher_id-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Event/cdesc-Event.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Event/cdesc-Event.ri new file mode 100644 index 00000000..e5c9c886 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Event/cdesc-Event.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/cdesc-Flags.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/cdesc-Flags.ri new file mode 100644 index 00000000..2d4a2420 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/cdesc-Flags.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/from_mask-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/from_mask-c.ri new file mode 100644 index 00000000..401b1897 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/from_mask-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/to_mask-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/to_mask-c.ri new file mode 100644 index 00000000..4262003c Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/Flags/to_mask-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/cdesc-Native.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/cdesc-Native.ri new file mode 100644 index 00000000..9ba61158 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Native/cdesc-Native.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/cdesc-Notifier.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/cdesc-Notifier.ri new file mode 100644 index 00000000..bc820112 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/cdesc-Notifier.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/close-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/close-i.ri new file mode 100644 index 00000000..22367195 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/close-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/fd-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/fd-i.ri new file mode 100644 index 00000000..b7a0145a Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/fd-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/new-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/new-c.ri new file mode 100644 index 00000000..2d72c04a Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/new-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/process-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/process-i.ri new file mode 100644 index 00000000..2b0bafcd Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/process-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/read_events-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/read_events-i.ri new file mode 100644 index 00000000..56b4995d Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/read_events-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/readpartial-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/readpartial-i.ri new file mode 100644 index 00000000..6e702630 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/readpartial-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/run-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/run-i.ri new file mode 100644 index 00000000..666ed009 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/run-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/stop-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/stop-i.ri new file mode 100644 index 00000000..baaabbbe Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/stop-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/to_io-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/to_io-i.ri new file mode 100644 index 00000000..b5514a36 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/to_io-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watch-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watch-i.ri new file mode 100644 index 00000000..3fd9fc9d Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watch-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watchers-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watchers-i.ri new file mode 100644 index 00000000..daddf428 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Notifier/watchers-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/QueueOverflowError/cdesc-QueueOverflowError.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/QueueOverflowError/cdesc-QueueOverflowError.ri new file mode 100644 index 00000000..892af281 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/QueueOverflowError/cdesc-QueueOverflowError.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/callback%21-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/callback%21-i.ri new file mode 100644 index 00000000..b08bfd98 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/callback%21-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/cdesc-Watcher.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/cdesc-Watcher.ri new file mode 100644 index 00000000..03af9422 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/cdesc-Watcher.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/close-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/close-i.ri new file mode 100644 index 00000000..a3e02c05 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/close-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/flags-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/flags-i.ri new file mode 100644 index 00000000..b3255094 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/flags-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/id-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/id-i.ri new file mode 100644 index 00000000..187179a2 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/id-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/new-c.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/new-c.ri new file mode 100644 index 00000000..de160b7a Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/new-c.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/notifier-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/notifier-i.ri new file mode 100644 index 00000000..feb05953 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/notifier-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/path-i.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/path-i.ri new file mode 100644 index 00000000..77c2ba15 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/Watcher/path-i.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/INotify/cdesc-INotify.ri b/bin/doc/rb-inotify-0.11.1/ri/INotify/cdesc-INotify.ri new file mode 100644 index 00000000..daa53b89 Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/INotify/cdesc-INotify.ri differ diff --git a/bin/doc/rb-inotify-0.11.1/ri/cache.ri b/bin/doc/rb-inotify-0.11.1/ri/cache.ri new file mode 100644 index 00000000..31ef031b Binary files /dev/null and b/bin/doc/rb-inotify-0.11.1/ri/cache.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/%5b%5d-i.ri new file mode 100644 index 00000000..21a1c4fb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/cdesc-AttlistDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/cdesc-AttlistDecl.ri new file mode 100644 index 00000000..a3e678e1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/cdesc-AttlistDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/each-i.ri new file mode 100644 index 00000000..ec89274c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/element_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/element_name-i.ri new file mode 100644 index 00000000..4d28bb62 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/element_name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"element_name:ETI"$REXML::AttlistDecl#element_name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"What is this? Got me.;T: +@fileI"lib/rexml/attlistdecl.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::AttlistDecl;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/include%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/include%3f-i.ri new file mode 100644 index 00000000..f555d219 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/include%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/new-c.ri new file mode 100644 index 00000000..dfef09e2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/node_type-i.ri new file mode 100644 index 00000000..a5484c1b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/write-i.ri new file mode 100644 index 00000000..d95f77fc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/AttlistDecl/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/%3d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/%3d%3d-i.ri new file mode 100644 index 00000000..69f818cd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/%3d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/cdesc-Attribute.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/cdesc-Attribute.ri new file mode 100644 index 00000000..f9a88e7b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/cdesc-Attribute.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/clone-i.ri new file mode 100644 index 00000000..c5546416 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/doctype-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/doctype-i.ri new file mode 100644 index 00000000..777ec478 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/doctype-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/document-i.ri new file mode 100644 index 00000000..c768ec0c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element%3d-i.ri new file mode 100644 index 00000000..151a9408 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element-i.ri new file mode 100644 index 00000000..4a874b62 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/element-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" element:ETI"REXML::Attribute#element;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"0The element to which this attribute belongs;T: +@fileI"lib/rexml/attribute.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Attribute;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/hash-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/hash-i.ri new file mode 100644 index 00000000..e42fc9be Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/hash-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/inspect-i.ri new file mode 100644 index 00000000..7e05ea95 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/namespace-i.ri new file mode 100644 index 00000000..822ddcd4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/new-c.ri new file mode 100644 index 00000000..7d5e94ce Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/node_type-i.ri new file mode 100644 index 00000000..d416ca95 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/normalized%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/normalized%3d-i.ri new file mode 100644 index 00000000..b006466d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/normalized%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/prefix-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/prefix-i.ri new file mode 100644 index 00000000..66490b8b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/prefix-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/remove-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/remove-i.ri new file mode 100644 index 00000000..9edb8863 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/remove-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_s-i.ri new file mode 100644 index 00000000..847b3f71 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_string-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_string-i.ri new file mode 100644 index 00000000..ed6c0a65 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/to_string-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/value-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/value-i.ri new file mode 100644 index 00000000..dac76a76 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/value-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/write-i.ri new file mode 100644 index 00000000..7b4ea5a7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attribute/xpath-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/xpath-i.ri new file mode 100644 index 00000000..546c5abc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attribute/xpath-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%3c%3c-i.ri new file mode 100644 index 00000000..8aa98736 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d%3d-i.ri new file mode 100644 index 00000000..abdc2d47 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d-i.ri new file mode 100644 index 00000000..06da2528 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/add-i.ri new file mode 100644 index 00000000..97960fd0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/cdesc-Attributes.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/cdesc-Attributes.ri new file mode 100644 index 00000000..2a4cf412 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/cdesc-Attributes.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete-i.ri new file mode 100644 index 00000000..b2bef9be Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete_all-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete_all-i.ri new file mode 100644 index 00000000..afe874fc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/delete_all-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each-i.ri new file mode 100644 index 00000000..2e3ee0d8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each_attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each_attribute-i.ri new file mode 100644 index 00000000..a29af439 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/each_attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute-i.ri new file mode 100644 index 00000000..0e84cf64 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute_ns-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute_ns-i.ri new file mode 100644 index 00000000..f167d2ce Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/get_attribute_ns-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/length-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/length-i.ri new file mode 100644 index 00000000..3b48b1e4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/length-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/namespaces-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/namespaces-i.ri new file mode 100644 index 00000000..ce608618 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/namespaces-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/new-c.ri new file mode 100644 index 00000000..dd499f27 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/prefixes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/prefixes-i.ri new file mode 100644 index 00000000..a693d9f3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/prefixes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/size-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/size-i.ri new file mode 100644 index 00000000..ebde80f7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/size-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Attributes/to_a-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/to_a-i.ri new file mode 100644 index 00000000..181482fb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Attributes/to_a-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/cdesc-CData.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/cdesc-CData.ri new file mode 100644 index 00000000..6bf1631f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/cdesc-CData.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/clone-i.ri new file mode 100644 index 00000000..e7cee1f2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/new-c.ri new file mode 100644 index 00000000..04a61758 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/to_s-i.ri new file mode 100644 index 00000000..82e6a41a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/value-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/value-i.ri new file mode 100644 index 00000000..43a61712 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/value-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/CData/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/CData/write-i.ri new file mode 100644 index 00000000..4f1ada66 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/CData/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/bytes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/bytes-i.ri new file mode 100644 index 00000000..7e24f1be Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/bytes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/cdesc-Child.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/cdesc-Child.ri new file mode 100644 index 00000000..f0e8c0e4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/cdesc-Child.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/document-i.ri new file mode 100644 index 00000000..878ecba5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/new-c.ri new file mode 100644 index 00000000..161301fc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/next_sibling%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/next_sibling%3d-i.ri new file mode 100644 index 00000000..00435fa4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/next_sibling%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/parent%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/parent%3d-i.ri new file mode 100644 index 00000000..ef1c487c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/parent%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/parent-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/parent-i.ri new file mode 100644 index 00000000..d46625e3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/parent-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/previous_sibling%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/previous_sibling%3d-i.ri new file mode 100644 index 00000000..80329be0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/previous_sibling%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/remove-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/remove-i.ri new file mode 100644 index 00000000..182b0b00 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/remove-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Child/replace_with-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Child/replace_with-i.ri new file mode 100644 index 00000000..3669f5bf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Child/replace_with-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3c%3d%3e-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3c%3d%3e-i.ri new file mode 100644 index 00000000..95d3adb5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3c%3d%3e-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3d%3d-i.ri new file mode 100644 index 00000000..47b4ab79 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/%3d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/cdesc-Comment.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/cdesc-Comment.ri new file mode 100644 index 00000000..22d807c9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/cdesc-Comment.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/clone-i.ri new file mode 100644 index 00000000..f7406af7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/new-c.ri new file mode 100644 index 00000000..88214bb3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/node_type-i.ri new file mode 100644 index 00000000..977e2bca Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/string-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/string-i.ri new file mode 100644 index 00000000..7f5b4b3b --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Comment/string-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" string:ETI"REXML::Comment#string;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"The content text;T: +@fileI"lib/rexml/comment.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Comment;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/to_s-i.ri new file mode 100644 index 00000000..096eda48 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Comment/to_s-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" to_s:ETI"REXML::Comment#to_s;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"The content text;T: +@fileI"lib/rexml/comment.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Comment;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Comment/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Comment/write-i.ri new file mode 100644 index 00000000..89c0a16d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Comment/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DClonable/cdesc-DClonable.ri b/bin/doc/rexml-3.4.4/ri/REXML/DClonable/cdesc-DClonable.ri new file mode 100644 index 00000000..2d2d03fd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DClonable/cdesc-DClonable.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DClonable/dclone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DClonable/dclone-i.ri new file mode 100644 index 00000000..38cbcd07 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DClonable/dclone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/AttlistDecl/cdesc-AttlistDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/AttlistDecl/cdesc-AttlistDecl.ri new file mode 100644 index 00000000..1ac3222d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/AttlistDecl/cdesc-AttlistDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/cdesc-ElementDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/cdesc-ElementDecl.ri new file mode 100644 index 00000000..67565cc7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/cdesc-ElementDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/new-c.ri new file mode 100644 index 00000000..030a7f70 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/ElementDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/cdesc-EntityDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/cdesc-EntityDecl.ri new file mode 100644 index 00000000..1761d09f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/cdesc-EntityDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/new-c.ri new file mode 100644 index 00000000..aa18bba2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/parse_source-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/parse_source-c.ri new file mode 100644 index 00000000..592f531a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/parse_source-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/to_s-i.ri new file mode 100644 index 00000000..a2a3e059 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/write-i.ri new file mode 100644 index 00000000..57d6c90c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/EntityDecl/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/cdesc-NotationDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/cdesc-NotationDecl.ri new file mode 100644 index 00000000..47bb2879 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/cdesc-NotationDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/new-c.ri new file mode 100644 index 00000000..20dde045 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/parse_source-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/parse_source-c.ri new file mode 100644 index 00000000..004db826 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/parse_source-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/to_s-i.ri new file mode 100644 index 00000000..8f61e6fe Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/write-i.ri new file mode 100644 index 00000000..32d7890a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/NotationDecl/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/cdesc-Parser.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/cdesc-Parser.ri new file mode 100644 index 00000000..441e84c0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/cdesc-Parser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse-c.ri new file mode 100644 index 00000000..0a50522b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse_helper-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse_helper-c.ri new file mode 100644 index 00000000..64080b07 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/Parser/parse_helper-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DTD/cdesc-DTD.ri b/bin/doc/rexml-3.4.4/ri/REXML/DTD/cdesc-DTD.ri new file mode 100644 index 00000000..d28e2ce7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DTD/cdesc-DTD.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Declaration/cdesc-Declaration.ri b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/cdesc-Declaration.ri new file mode 100644 index 00000000..a73cf430 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/cdesc-Declaration.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Declaration/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/new-c.ri new file mode 100644 index 00000000..8c1c024f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Declaration/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/to_s-i.ri new file mode 100644 index 00000000..3296cc8e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Declaration/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/write-i.ri new file mode 100644 index 00000000..d456acc0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Declaration/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/add-i.ri new file mode 100644 index 00000000..1c3f90ee Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/attribute_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/attribute_of-i.ri new file mode 100644 index 00000000..74a9f88a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/attribute_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/attributes_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/attributes_of-i.ri new file mode 100644 index 00000000..adb56e31 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/attributes_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/cdesc-DocType.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/cdesc-DocType.ri new file mode 100644 index 00000000..d9c17e06 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/cdesc-DocType.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/clone-i.ri new file mode 100644 index 00000000..336a6646 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/context-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/context-i.ri new file mode 100644 index 00000000..49bbc9a2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/context-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/entities-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/entities-i.ri new file mode 100644 index 00000000..0c35469c --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/DocType/entities-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" entities:ETI"REXML::DocType#entities;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"%name is the name of the doctype ;TI"0external_id is the referenced DTD, if given;T: +@fileI"lib/rexml/doctype.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::DocType;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/entity-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/entity-i.ri new file mode 100644 index 00000000..ca973d00 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/entity-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/external_id-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/external_id-i.ri new file mode 100644 index 00000000..6b83161a --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/DocType/external_id-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"external_id:ETI"REXML::DocType#external_id;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"%name is the name of the doctype ;TI"0external_id is the referenced DTD, if given;T: +@fileI"lib/rexml/doctype.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::DocType;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/name-i.ri new file mode 100644 index 00000000..42f5900a --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/DocType/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI"REXML::DocType#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"%name is the name of the doctype ;TI"0external_id is the referenced DTD, if given;T: +@fileI"lib/rexml/doctype.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::DocType;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/namespaces-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/namespaces-i.ri new file mode 100644 index 00000000..f72eb86b --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/DocType/namespaces-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"namespaces:ETI"REXML::DocType#namespaces;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"%name is the name of the doctype ;TI"0external_id is the referenced DTD, if given;T: +@fileI"lib/rexml/doctype.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::DocType;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/new-c.ri new file mode 100644 index 00000000..8c3bc6b5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/node_type-i.ri new file mode 100644 index 00000000..771e604b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/notation-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/notation-i.ri new file mode 100644 index 00000000..84fd1d15 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/notation-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/notations-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/notations-i.ri new file mode 100644 index 00000000..cc572665 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/notations-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/public-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/public-i.ri new file mode 100644 index 00000000..411ca2b9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/public-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/system-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/system-i.ri new file mode 100644 index 00000000..9db7efaa Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/system-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/DocType/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/DocType/write-i.ri new file mode 100644 index 00000000..e6cab911 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/DocType/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/%3c%3c-i.ri new file mode 100644 index 00000000..e66e2a73 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/add-i.ri new file mode 100644 index 00000000..2bb1b4ae Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/add_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/add_element-i.ri new file mode 100644 index 00000000..df61d65e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/add_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/build-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/build-i.ri new file mode 100644 index 00000000..62bdf97f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/build-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/cdesc-Document.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/cdesc-Document.ri new file mode 100644 index 00000000..5020db39 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/cdesc-Document.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/clone-i.ri new file mode 100644 index 00000000..630ec7f9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/doctype-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/doctype-i.ri new file mode 100644 index 00000000..7f392515 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/doctype-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/document-i.ri new file mode 100644 index 00000000..ec955bfa Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/enable_cache-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/enable_cache-i.ri new file mode 100644 index 00000000..4b100abc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/enable_cache-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/encoding-i.ri new file mode 100644 index 00000000..0f4d4433 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_count-i.ri new file mode 100644 index 00000000..22d98f36 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit%3d-c.ri new file mode 100644 index 00000000..3a33e7d1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-c.ri new file mode 100644 index 00000000..4e9e82c0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-i.ri new file mode 100644 index 00000000..7c76d5f8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_limit-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit%3d-c.ri new file mode 100644 index 00000000..8b658005 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-c.ri new file mode 100644 index 00000000..398fd45f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-i.ri new file mode 100644 index 00000000..70585cbf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/entity_expansion_text_limit-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/expanded_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/expanded_name-i.ri new file mode 100644 index 00000000..b5eb989e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/expanded_name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/name-i.ri new file mode 100644 index 00000000..0da01ccd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/namespaces_cache-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/namespaces_cache-i.ri new file mode 100644 index 00000000..b7fdfa63 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/namespaces_cache-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/new-c.ri new file mode 100644 index 00000000..11f16eba Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/node_type-i.ri new file mode 100644 index 00000000..120b1987 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/parse_stream-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/parse_stream-c.ri new file mode 100644 index 00000000..750b67a5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/parse_stream-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/record_entity_expansion-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/record_entity_expansion-i.ri new file mode 100644 index 00000000..cb5814c7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/record_entity_expansion-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/root-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/root-i.ri new file mode 100644 index 00000000..e8e4950d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/root-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/stand_alone%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/stand_alone%3f-i.ri new file mode 100644 index 00000000..efdb65b3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/stand_alone%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/version-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/version-i.ri new file mode 100644 index 00000000..db635782 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/version-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/write-i.ri new file mode 100644 index 00000000..95810df8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Document/xml_decl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Document/xml_decl-i.ri new file mode 100644 index 00000000..b984ac26 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Document/xml_decl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/%5b%5d-i.ri new file mode 100644 index 00000000..181c0912 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/__to_xpath_helper-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/__to_xpath_helper-i.ri new file mode 100644 index 00000000..f543f6d9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/__to_xpath_helper-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attribute-i.ri new file mode 100644 index 00000000..b10ec4bf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attributes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attributes-i.ri new file mode 100644 index 00000000..0ffb774e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_attributes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/add_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_element-i.ri new file mode 100644 index 00000000..2e61c4fc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/add_namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_namespace-i.ri new file mode 100644 index 00000000..4c42f1e2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/add_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_text-i.ri new file mode 100644 index 00000000..7e6b4b6b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/add_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/attribute-i.ri new file mode 100644 index 00000000..47460e68 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/attributes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/attributes-i.ri new file mode 100644 index 00000000..c569f186 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Element/attributes-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"attributes:ETI"REXML::Element#attributes;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"DMechanisms for accessing attributes and child elements of this ;TI" element.;T: +@fileI"lib/rexml/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/calculate_namespaces-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/calculate_namespaces-i.ri new file mode 100644 index 00000000..cee076da Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/calculate_namespaces-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/cdatas-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/cdatas-i.ri new file mode 100644 index 00000000..9b713436 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/cdatas-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/cdesc-Element.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/cdesc-Element.ri new file mode 100644 index 00000000..b7a4b6c7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/cdesc-Element.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/clone-i.ri new file mode 100644 index 00000000..2a12b7f2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/comments-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/comments-i.ri new file mode 100644 index 00000000..365276e5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/comments-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/context-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/context-i.ri new file mode 100644 index 00000000..f8d3c0f2 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Element/context-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" context:ETI"REXML::Element#context;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"MThe context holds information about the processing environment, such as ;TI"whitespace handling.;T: +@fileI"lib/rexml/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_attribute-i.ri new file mode 100644 index 00000000..a91eecfa Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_element-i.ri new file mode 100644 index 00000000..efcbb9e0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_namespace-i.ri new file mode 100644 index 00000000..cd5470b8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/delete_namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/document-i.ri new file mode 100644 index 00000000..c61d96aa Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element-i.ri new file mode 100644 index 00000000..4fc7b250 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_attribute-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_attribute-i.ri new file mode 100644 index 00000000..b36adc00 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_attribute-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_text-i.ri new file mode 100644 index 00000000..7cc99bec Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_element_with_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/each_with_something-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_with_something-i.ri new file mode 100644 index 00000000..e94e4830 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/each_with_something-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/elements-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/elements-i.ri new file mode 100644 index 00000000..edd1215a --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Element/elements-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" elements:ETI"REXML::Element#elements;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"DMechanisms for accessing attributes and child elements of this ;TI" element.;T: +@fileI"lib/rexml/element.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Element;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/get_elements-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/get_elements-i.ri new file mode 100644 index 00000000..690f941b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/get_elements-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/get_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/get_text-i.ri new file mode 100644 index 00000000..54a53cf0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/get_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/has_attributes%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_attributes%3f-i.ri new file mode 100644 index 00000000..5bf32111 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_attributes%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/has_elements%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_elements%3f-i.ri new file mode 100644 index 00000000..3496f4b6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_elements%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/has_text%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_text%3f-i.ri new file mode 100644 index 00000000..12897e64 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/has_text%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/ignore_whitespace_nodes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/ignore_whitespace_nodes-i.ri new file mode 100644 index 00000000..aaeb5bdf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/ignore_whitespace_nodes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/inspect-i.ri new file mode 100644 index 00000000..022dc00b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/instructions-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/instructions-i.ri new file mode 100644 index 00000000..14285f34 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/instructions-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/namespace-i.ri new file mode 100644 index 00000000..2a374559 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/namespaces-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/namespaces-i.ri new file mode 100644 index 00000000..6118f043 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/namespaces-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/new-c.ri new file mode 100644 index 00000000..6fd9a056 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/next_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/next_element-i.ri new file mode 100644 index 00000000..96b32ff2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/next_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/node_type-i.ri new file mode 100644 index 00000000..9043a33d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/prefixes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/prefixes-i.ri new file mode 100644 index 00000000..5ba745d2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/prefixes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/previous_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/previous_element-i.ri new file mode 100644 index 00000000..1b4742cc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/previous_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/raw-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/raw-i.ri new file mode 100644 index 00000000..b3b2cb46 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/raw-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/root-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/root-i.ri new file mode 100644 index 00000000..4f91cf41 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/root-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/root_node-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/root_node-i.ri new file mode 100644 index 00000000..640ba7db Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/root_node-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/text%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/text%3d-i.ri new file mode 100644 index 00000000..776d5a2d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/text%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/text-i.ri new file mode 100644 index 00000000..18d7ec0c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/texts-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/texts-i.ri new file mode 100644 index 00000000..aece6113 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/texts-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/whitespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/whitespace-i.ri new file mode 100644 index 00000000..ab71a916 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/whitespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/write-i.ri new file mode 100644 index 00000000..9caa25c1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Element/xpath-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Element/xpath-i.ri new file mode 100644 index 00000000..88f16e25 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Element/xpath-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/cdesc-ElementDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/cdesc-ElementDecl.ri new file mode 100644 index 00000000..b1b84378 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/cdesc-ElementDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/new-c.ri new file mode 100644 index 00000000..2cf0330d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ElementDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%3c%3c-i.ri new file mode 100644 index 00000000..2dd3ed38 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d%3d-i.ri new file mode 100644 index 00000000..ca04038d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d-i.ri new file mode 100644 index 00000000..d0fc4482 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/add-i.ri new file mode 100644 index 00000000..2a93d258 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/cdesc-Elements.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/cdesc-Elements.ri new file mode 100644 index 00000000..53a0b258 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/cdesc-Elements.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/collect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/collect-i.ri new file mode 100644 index 00000000..54bbc2df Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/collect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete-i.ri new file mode 100644 index 00000000..38032a18 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete_all-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete_all-i.ri new file mode 100644 index 00000000..e0f76110 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/delete_all-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/each-i.ri new file mode 100644 index 00000000..65abd33e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/empty%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/empty%3f-i.ri new file mode 100644 index 00000000..433d7bd5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/empty%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/index-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/index-i.ri new file mode 100644 index 00000000..c73d2676 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/index-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/inject-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/inject-i.ri new file mode 100644 index 00000000..58e83145 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/inject-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/literalize-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/literalize-i.ri new file mode 100644 index 00000000..43f96d0d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/literalize-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/new-c.ri new file mode 100644 index 00000000..d7b28383 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/parent-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/parent-i.ri new file mode 100644 index 00000000..f4c2beb5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/parent-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/size-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/size-i.ri new file mode 100644 index 00000000..ab19bb84 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/size-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Elements/to_a-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Elements/to_a-i.ri new file mode 100644 index 00000000..f3f9a4fb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Elements/to_a-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/cdesc-Encoding.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/cdesc-Encoding.ri new file mode 100644 index 00000000..d4fbf093 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/cdesc-Encoding.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/decode-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/decode-i.ri new file mode 100644 index 00000000..e0bd50c3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/decode-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encode-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encode-i.ri new file mode 100644 index 00000000..019cd172 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encode-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding%3d-i.ri new file mode 100644 index 00000000..2be17105 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding-i.ri new file mode 100644 index 00000000..f3da3491 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/encoding-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" encoding:ETI"REXML::Encoding#encoding;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"ID ---> Encoding name;T: +@fileI"lib/rexml/encoding.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Encoding;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Encoding/find_encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/find_encoding-i.ri new file mode 100644 index 00000000..95b1c66a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Encoding/find_encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/cdesc-Entity.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/cdesc-Entity.ri new file mode 100644 index 00000000..844d82a8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/cdesc-Entity.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/external-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/external-i.ri new file mode 100644 index 00000000..669af7b6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/external-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/matches%3f-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/matches%3f-c.ri new file mode 100644 index 00000000..7e84950e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/matches%3f-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/name-i.ri new file mode 100644 index 00000000..c648b778 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/ndata-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/ndata-i.ri new file mode 100644 index 00000000..c6710cf0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/ndata-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/new-c.ri new file mode 100644 index 00000000..7c91f747 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/normalized-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/normalized-i.ri new file mode 100644 index 00000000..810fbbd9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/normalized-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/pubid-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/pubid-i.ri new file mode 100644 index 00000000..1ce9dc52 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/pubid-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/ref-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/ref-i.ri new file mode 100644 index 00000000..817c22f3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/ref-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/to_s-i.ri new file mode 100644 index 00000000..61d2d8a4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/unnormalized-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/unnormalized-i.ri new file mode 100644 index 00000000..d971b814 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/unnormalized-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/value-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/value-i.ri new file mode 100644 index 00000000..e9aa0a32 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/value-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Entity/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Entity/write-i.ri new file mode 100644 index 00000000..ac6c154f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Entity/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/EntityConst/cdesc-EntityConst.ri b/bin/doc/rexml-3.4.4/ri/REXML/EntityConst/cdesc-EntityConst.ri new file mode 100644 index 00000000..ca918641 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/EntityConst/cdesc-EntityConst.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/cdesc-ExternalEntity.ri b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/cdesc-ExternalEntity.ri new file mode 100644 index 00000000..9267fd60 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/cdesc-ExternalEntity.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/new-c.ri new file mode 100644 index 00000000..7791af5c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/to_s-i.ri new file mode 100644 index 00000000..33afb914 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/write-i.ri new file mode 100644 index 00000000..c200508e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ExternalEntity/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/cdesc-Default.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/cdesc-Default.ri new file mode 100644 index 00000000..bc08c4c1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/cdesc-Default.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/new-c.ri new file mode 100644 index 00000000..33833af7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write-i.ri new file mode 100644 index 00000000..de9ffd93 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_cdata-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_cdata-i.ri new file mode 100644 index 00000000..968dd70e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_cdata-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_comment-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_comment-i.ri new file mode 100644 index 00000000..0702de76 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_comment-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_document-i.ri new file mode 100644 index 00000000..d516bf3f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_element-i.ri new file mode 100644 index 00000000..82251aa4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_instruction-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_instruction-i.ri new file mode 100644 index 00000000..4710cafe Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_instruction-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_text-i.ri new file mode 100644 index 00000000..5f35fd5f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Default/write_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/cdesc-Pretty.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/cdesc-Pretty.ri new file mode 100644 index 00000000..197033fb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/cdesc-Pretty.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/compact-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/compact-i.ri new file mode 100644 index 00000000..88d45b75 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/compact-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" compact:ETI"&REXML::Formatters::Pretty#compact;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"JIf compact is set to true, then the formatter will attempt to use as ;TI"little space as possible;T: +@fileI"#lib/rexml/formatters/pretty.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Formatters::Pretty;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/indent_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/indent_text-i.ri new file mode 100644 index 00000000..f636aab7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/indent_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/new-c.ri new file mode 100644 index 00000000..1396c7c0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/width-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/width-i.ri new file mode 100644 index 00000000..2da9565f --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/width-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +width:ETI"$REXML::Formatters::Pretty#width;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"3The width of a page. Used for formatting text;T: +@fileI"#lib/rexml/formatters/pretty.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Formatters::Pretty;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/wrap-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/wrap-i.ri new file mode 100644 index 00000000..68ab341d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/wrap-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_cdata-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_cdata-i.ri new file mode 100644 index 00000000..6571713e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_cdata-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_comment-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_comment-i.ri new file mode 100644 index 00000000..f0d11794 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_comment-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_document-i.ri new file mode 100644 index 00000000..bc1bb33f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_element-i.ri new file mode 100644 index 00000000..85020e32 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_text-i.ri new file mode 100644 index 00000000..0367855e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Pretty/write_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/cdesc-Transitive.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/cdesc-Transitive.ri new file mode 100644 index 00000000..227d8ad1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/cdesc-Transitive.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/new-c.ri new file mode 100644 index 00000000..0e49878e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_element-i.ri new file mode 100644 index 00000000..b5bb61b5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_text-i.ri new file mode 100644 index 00000000..b37b8fa4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/Transitive/write_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Formatters/cdesc-Formatters.ri b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/cdesc-Formatters.ri new file mode 100644 index 00000000..410e79ac Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Formatters/cdesc-Formatters.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/boolean-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/boolean-c.ri new file mode 100644 index 00000000..f80effc2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/boolean-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/cdesc-Functions.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/cdesc-Functions.ri new file mode 100644 index 00000000..c25164d3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/cdesc-Functions.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/ceiling-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/ceiling-c.ri new file mode 100644 index 00000000..68d44f7d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/ceiling-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/compare_language-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/compare_language-c.ri new file mode 100644 index 00000000..249de325 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/compare_language-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/concat-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/concat-c.ri new file mode 100644 index 00000000..587efc24 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/concat-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/contains-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/contains-c.ri new file mode 100644 index 00000000..9779dfee Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/contains-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/context%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/context%3d-c.ri new file mode 100644 index 00000000..270d518c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/context%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/count-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/count-c.ri new file mode 100644 index 00000000..2c7bee13 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/count-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/false-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/false-c.ri new file mode 100644 index 00000000..b907569d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/false-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/floor-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/floor-c.ri new file mode 100644 index 00000000..b8d166ed Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/floor-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/get_namespace-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/get_namespace-c.ri new file mode 100644 index 00000000..03beb249 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/get_namespace-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/id-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/id-c.ri new file mode 100644 index 00000000..123d1478 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/id-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/lang-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/lang-c.ri new file mode 100644 index 00000000..9ef5adbe Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/lang-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/last-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/last-c.ri new file mode 100644 index 00000000..16df259c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/last-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/local_name-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/local_name-c.ri new file mode 100644 index 00000000..3794a965 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/local_name-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/name-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/name-c.ri new file mode 100644 index 00000000..c7a3a8f9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/name-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context%3d-c.ri new file mode 100644 index 00000000..b081c267 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context-c.ri new file mode 100644 index 00000000..16a00855 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_context-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_uri-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_uri-c.ri new file mode 100644 index 00000000..ad47ce74 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/namespace_uri-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/normalize_space-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/normalize_space-c.ri new file mode 100644 index 00000000..5e65316f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/normalize_space-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/not-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/not-c.ri new file mode 100644 index 00000000..9613a42b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/not-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/number-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/number-c.ri new file mode 100644 index 00000000..a18a2f64 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/number-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/position-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/position-c.ri new file mode 100644 index 00000000..8ff1e42d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/position-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/processing_instruction-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/processing_instruction-c.ri new file mode 100644 index 00000000..0f0d1f44 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/processing_instruction-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/round-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/round-c.ri new file mode 100644 index 00000000..36e60420 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/round-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/send-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/send-c.ri new file mode 100644 index 00000000..a7cfad6b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/send-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/singleton_method_added-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/singleton_method_added-c.ri new file mode 100644 index 00000000..7f2d83d3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/singleton_method_added-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/starts_with-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/starts_with-c.ri new file mode 100644 index 00000000..cf47705b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/starts_with-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/string-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string-c.ri new file mode 100644 index 00000000..814d8cc5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_length-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_length-c.ri new file mode 100644 index 00000000..bf8077b0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_length-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_value-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_value-c.ri new file mode 100644 index 00000000..9846644c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/string_value-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring-c.ri new file mode 100644 index 00000000..57b8d14d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_after-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_after-c.ri new file mode 100644 index 00000000..2c6a759f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_after-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_before-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_before-c.ri new file mode 100644 index 00000000..cbb6ce6f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/substring_before-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/sum-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/sum-c.ri new file mode 100644 index 00000000..acbe8c55 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/sum-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/text-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/text-c.ri new file mode 100644 index 00000000..b825c8f3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/text-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/translate-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/translate-c.ri new file mode 100644 index 00000000..5d3d7552 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/translate-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/true-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/true-c.ri new file mode 100644 index 00000000..126f8268 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/true-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables%3d-c.ri new file mode 100644 index 00000000..f0d43ffa Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables-c.ri new file mode 100644 index 00000000..eb006142 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Functions/variables-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/cdesc-IOSource.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/cdesc-IOSource.ri new file mode 100644 index 00000000..0f9e6356 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/cdesc-IOSource.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/current_line-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/current_line-i.ri new file mode 100644 index 00000000..145e9764 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/current_line-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/empty%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/empty%3f-i.ri new file mode 100644 index 00000000..5765fc15 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/empty%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/encoding_updated-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/encoding_updated-i.ri new file mode 100644 index 00000000..30d76842 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/encoding_updated-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/ensure_buffer-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/ensure_buffer-i.ri new file mode 100644 index 00000000..e957efdf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/ensure_buffer-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match%3f-i.ri new file mode 100644 index 00000000..c9449e45 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match-i.ri new file mode 100644 index 00000000..fda38152 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/match-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/new-c.ri new file mode 100644 index 00000000..845a0893 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read-i.ri new file mode 100644 index 00000000..c75b69ce Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read_until-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read_until-i.ri new file mode 100644 index 00000000..b7648591 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/read_until-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/IOSource/readline-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/readline-i.ri new file mode 100644 index 00000000..2d0f5092 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/IOSource/readline-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/%3d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/%3d%3d-i.ri new file mode 100644 index 00000000..64ca1ab1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/%3d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/cdesc-Instruction.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/cdesc-Instruction.ri new file mode 100644 index 00000000..c11ba38f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/cdesc-Instruction.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/clone-i.ri new file mode 100644 index 00000000..40b56592 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/content-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/content-i.ri new file mode 100644 index 00000000..03380edf --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/content-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" content:ETI"REXML::Instruction#content;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Ktarget is the "name" of the Instruction; IE, the "tag" in ;TI" content is everything else.;T: +@fileI"lib/rexml/instruction.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Instruction;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/inspect-i.ri new file mode 100644 index 00000000..66e534b7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/new-c.ri new file mode 100644 index 00000000..d017b32b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/node_type-i.ri new file mode 100644 index 00000000..c2fa448b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/target-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/target-i.ri new file mode 100644 index 00000000..d3d97a2e --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/target-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" target:ETI"REXML::Instruction#target;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Ktarget is the "name" of the Instruction; IE, the "tag" in ;TI" content is everything else.;T: +@fileI"lib/rexml/instruction.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Instruction;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Instruction/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/write-i.ri new file mode 100644 index 00000000..58068271 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Instruction/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3c%3c-i.ri new file mode 100644 index 00000000..0ce49ca9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3d%7e-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3d%7e-i.ri new file mode 100644 index 00000000..7f6c49d4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%3d%7e-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d%3d-i.ri new file mode 100644 index 00000000..404e17ad Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d-i.ri new file mode 100644 index 00000000..cdb96e9b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/cdesc-Node.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/cdesc-Node.ri new file mode 100644 index 00000000..f0af9b4b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/cdesc-Node.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/children-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/children-i.ri new file mode 100644 index 00000000..5f96778f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/children-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/each-i.ri new file mode 100644 index 00000000..318432e8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/has_name%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/has_name%3f-i.ri new file mode 100644 index 00000000..4c010c94 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/has_name%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name%3d-i.ri new file mode 100644 index 00000000..b130d2da Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name-i.ri new file mode 100644 index 00000000..e46e7751 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/local_name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name%3d-i.ri new file mode 100644 index 00000000..2c4b677c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name-i.ri new file mode 100644 index 00000000..c52973c4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace%3d-i.ri new file mode 100644 index 00000000..6b0f92c9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace-i.ri new file mode 100644 index 00000000..6c25778f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace_of-i.ri new file mode 100644 index 00000000..2bd74d02 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namespace_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namesplit-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namesplit-i.ri new file mode 100644 index 00000000..46d87e99 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/namesplit-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/new-c.ri new file mode 100644 index 00000000..ea81bfd7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/node_type-i.ri new file mode 100644 index 00000000..74f8f742 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent%3d-i.ri new file mode 100644 index 00000000..3ebfca62 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent-i.ri new file mode 100644 index 00000000..fccd82be Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/parent-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix-i.ri new file mode 100644 index 00000000..91f1b108 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix_of-i.ri new file mode 100644 index 00000000..ea6e0f5c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/prefix_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/root-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/root-i.ri new file mode 100644 index 00000000..6f012ea4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/root-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/size-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/size-i.ri new file mode 100644 index 00000000..2db66718 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/size-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/text%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/text%3d-i.ri new file mode 100644 index 00000000..0ebbefc5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/text%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/to_s-i.ri new file mode 100644 index 00000000..7b2a51cf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/Node/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Light/cdesc-Light.ri b/bin/doc/rexml-3.4.4/ri/REXML/Light/cdesc-Light.ri new file mode 100644 index 00000000..7ef421eb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Light/cdesc-Light.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/cdesc-Namespace.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/cdesc-Namespace.ri new file mode 100644 index 00000000..f7349659 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/cdesc-Namespace.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/expanded_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/expanded_name-i.ri new file mode 100644 index 00000000..3652f462 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/expanded_name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"expanded_name:ETI"#REXML::Namespace#expanded_name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I")The name of the object, valid if set;T: +@fileI"lib/rexml/namespace.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Namespace;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/fully_expanded_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/fully_expanded_name-i.ri new file mode 100644 index 00000000..5c8076da Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/fully_expanded_name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/has_name%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/has_name%3f-i.ri new file mode 100644 index 00000000..94605621 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/has_name%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/local_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/local_name-i.ri new file mode 100644 index 00000000..136f5064 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/local_name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"local_name:ETI" REXML::Namespace#local_name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I")The name of the object, valid if set;T: +@fileI"lib/rexml/namespace.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Namespace;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name%3d-i.ri new file mode 100644 index 00000000..3f949e1d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name-i.ri new file mode 100644 index 00000000..72e119e1 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI"REXML::Namespace#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I")The name of the object, valid if set;T: +@fileI"lib/rexml/namespace.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Namespace;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Namespace/prefix-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/prefix-i.ri new file mode 100644 index 00000000..c3c988bd --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Namespace/prefix-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" prefix:ETI"REXML::Namespace#prefix;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I":The expanded name of the object, valid if name is set;T: +@fileI"lib/rexml/namespace.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Namespace;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/cdesc-Node.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/cdesc-Node.ri new file mode 100644 index 00000000..3aeaa6e1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/cdesc-Node.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/each_recursive-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/each_recursive-i.ri new file mode 100644 index 00000000..1b193311 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/each_recursive-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/find_first_recursive-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/find_first_recursive-i.ri new file mode 100644 index 00000000..d36be7ed Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/find_first_recursive-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/indent-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/indent-i.ri new file mode 100644 index 00000000..7769f31c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/indent-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/index_in_parent-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/index_in_parent-i.ri new file mode 100644 index 00000000..37ecaba1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/index_in_parent-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/next_sibling_node-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/next_sibling_node-i.ri new file mode 100644 index 00000000..bef59b32 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/next_sibling_node-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/parent%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/parent%3f-i.ri new file mode 100644 index 00000000..6e876475 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/parent%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/previous_sibling_node-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/previous_sibling_node-i.ri new file mode 100644 index 00000000..093d52b3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/previous_sibling_node-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Node/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Node/to_s-i.ri new file mode 100644 index 00000000..60be43c3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Node/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/cdesc-NotationDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/cdesc-NotationDecl.ri new file mode 100644 index 00000000..0c7825fd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/cdesc-NotationDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/name-i.ri new file mode 100644 index 00000000..31bf0e2c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/new-c.ri new file mode 100644 index 00000000..db5c8b5d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/public-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/public-i.ri new file mode 100644 index 00000000..8fec55fc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/public-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/system-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/system-i.ri new file mode 100644 index 00000000..c0a329cd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/system-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/to_s-i.ri new file mode 100644 index 00000000..f28e92da Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/write-i.ri new file mode 100644 index 00000000..f45024f6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/NotationDecl/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Output/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Output/%3c%3c-i.ri new file mode 100644 index 00000000..0baef791 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Output/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Output/cdesc-Output.ri b/bin/doc/rexml-3.4.4/ri/REXML/Output/cdesc-Output.ri new file mode 100644 index 00000000..4c9c8a76 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Output/cdesc-Output.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Output/encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Output/encoding-i.ri new file mode 100644 index 00000000..9c36ec07 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Output/encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Output/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Output/new-c.ri new file mode 100644 index 00000000..40c20f6f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Output/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Output/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Output/to_s-i.ri new file mode 100644 index 00000000..e6f53566 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Output/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%3c%3c-i.ri new file mode 100644 index 00000000..73924c23 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d%3d-i.ri new file mode 100644 index 00000000..a6f18606 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d-i.ri new file mode 100644 index 00000000..98b9eae7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/add-i.ri new file mode 100644 index 00000000..ba2f23e6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/cdesc-Parent.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/cdesc-Parent.ri new file mode 100644 index 00000000..50c6e9cd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/cdesc-Parent.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/children-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/children-i.ri new file mode 100644 index 00000000..5d24a9e2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/children-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/deep_clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/deep_clone-i.ri new file mode 100644 index 00000000..084caf97 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/deep_clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete-i.ri new file mode 100644 index 00000000..cc5ff3d7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_at-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_at-i.ri new file mode 100644 index 00000000..ebad36f9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_at-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_if-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_if-i.ri new file mode 100644 index 00000000..003b8209 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/delete_if-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each-i.ri new file mode 100644 index 00000000..762b827b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_child-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_child-i.ri new file mode 100644 index 00000000..bcbe0047 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_child-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_index-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_index-i.ri new file mode 100644 index 00000000..28f2309f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/each_index-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/index-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/index-i.ri new file mode 100644 index 00000000..5fbd202b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/index-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_after-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_after-i.ri new file mode 100644 index 00000000..bb077db3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_after-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_before-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_before-i.ri new file mode 100644 index 00000000..51e116ac Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/insert_before-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/length-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/length-i.ri new file mode 100644 index 00000000..bad96f5e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/length-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/new-c.ri new file mode 100644 index 00000000..a25eff48 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/parent%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/parent%3f-i.ri new file mode 100644 index 00000000..ef88d857 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/parent%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/push-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/push-i.ri new file mode 100644 index 00000000..a7925d0e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/push-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/replace_child-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/replace_child-i.ri new file mode 100644 index 00000000..a7e2df89 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/replace_child-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/size-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/size-i.ri new file mode 100644 index 00000000..66392759 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/size-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/to_a-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/to_a-i.ri new file mode 100644 index 00000000..15e0db77 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/to_a-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parent/unshift-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parent/unshift-i.ri new file mode 100644 index 00000000..2ea6b151 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parent/unshift-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/cdesc-ParseException.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/cdesc-ParseException.ri new file mode 100644 index 00000000..e8198ff6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/cdesc-ParseException.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/context-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/context-i.ri new file mode 100644 index 00000000..f7d99b29 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/context-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/continued_exception-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/continued_exception-i.ri new file mode 100644 index 00000000..df0b75a9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/continued_exception-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/line-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/line-i.ri new file mode 100644 index 00000000..2cbc9371 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/line-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/new-c.ri new file mode 100644 index 00000000..77a09564 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/parser-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/parser-i.ri new file mode 100644 index 00000000..ad992c29 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/parser-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/position-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/position-i.ri new file mode 100644 index 00000000..2978957c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/position-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/source-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/source-i.ri new file mode 100644 index 00000000..16cf42de Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/source-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ParseException/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/to_s-i.ri new file mode 100644 index 00000000..ea48bf31 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ParseException/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/Private/cdesc-Private.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/Private/cdesc-Private.ri new file mode 100644 index 00000000..e35ea6eb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/Private/cdesc-Private.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_listener-i.ri new file mode 100644 index 00000000..cba5a992 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_namespace-i.ri new file mode 100644 index 00000000..edf6b335 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/add_namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/cdesc-BaseParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/cdesc-BaseParser.ri new file mode 100644 index 00000000..6355e90d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/cdesc-BaseParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/empty%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/empty%3f-i.ri new file mode 100644 index 00000000..58ebc00f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/empty%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity-i.ri new file mode 100644 index 00000000..7ef6d5f4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_count-i.ri new file mode 100644 index 00000000..481b87df Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_limit-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_limit-i.ri new file mode 100644 index 00000000..b4ec2e70 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_limit-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_text_limit-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_text_limit-i.ri new file mode 100644 index 00000000..1d7ac964 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/entity_expansion_text_limit-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/has_next%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/has_next%3f-i.ri new file mode 100644 index 00000000..065e60dc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/has_next%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/need_source_encoding_update%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/need_source_encoding_update%3f-i.ri new file mode 100644 index 00000000..fad3433d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/need_source_encoding_update%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/new-c.ri new file mode 100644 index 00000000..adb66a4d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize-i.ri new file mode 100644 index 00000000..0aab8c02 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize_xml_declaration_encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize_xml_declaration_encoding-i.ri new file mode 100644 index 00000000..ec6ae4c8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/normalize_xml_declaration_encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attribute_value_with_equal-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attribute_value_with_equal-i.ri new file mode 100644 index 00000000..9beb489b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attribute_value_with_equal-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attributes-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attributes-i.ri new file mode 100644 index 00000000..f0a6228c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_attributes-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id-i.ri new file mode 100644 index 00000000..468d621d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id_invalid_details-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id_invalid_details-i.ri new file mode 100644 index 00000000..1426d174 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_id_invalid_details-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_name-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_name-i.ri new file mode 100644 index 00000000..627b3f38 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/parse_name-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/peek-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/peek-i.ri new file mode 100644 index 00000000..f6c9ca88 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/peek-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pop_namespaces_restore-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pop_namespaces_restore-i.ri new file mode 100644 index 00000000..49977fc5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pop_namespaces_restore-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/position-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/position-i.ri new file mode 100644 index 00000000..6ff19c54 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/position-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_comment-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_comment-i.ri new file mode 100644 index 00000000..712e780f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_comment-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_instruction-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_instruction-i.ri new file mode 100644 index 00000000..400b3d99 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/process_instruction-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull-i.ri new file mode 100644 index 00000000..16ae6cb3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull_event-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull_event-i.ri new file mode 100644 index 00000000..7da03a32 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/pull_event-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/push_namespaces_restore-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/push_namespaces_restore-i.ri new file mode 100644 index 00000000..df2a9ea5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/push_namespaces_restore-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/record_entity_expansion-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/record_entity_expansion-i.ri new file mode 100644 index 00000000..6ce88805 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/record_entity_expansion-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/reset-i.ri new file mode 100644 index 00000000..a9c33590 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/scan_quote-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/scan_quote-i.ri new file mode 100644 index 00000000..dc56139f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/scan_quote-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/source-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/source-i.ri new file mode 100644 index 00000000..49e564cc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/source-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/stream%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/stream%3d-i.ri new file mode 100644 index 00000000..004bee3e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/stream%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unnormalize-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unnormalize-i.ri new file mode 100644 index 00000000..390b74df Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unnormalize-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unshift-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unshift-i.ri new file mode 100644 index 00000000..b8773385 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/unshift-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/xml_declaration-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/xml_declaration-i.ri new file mode 100644 index 00000000..d3193068 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/BaseParser/xml_declaration-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/cdesc-EnumerableTally.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/cdesc-EnumerableTally.ri new file mode 100644 index 00000000..46ecb6dc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/cdesc-EnumerableTally.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/tally-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/tally-i.ri new file mode 100644 index 00000000..82574e7a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/EnumerableTally/tally-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/add_listener-i.ri new file mode 100644 index 00000000..923a862f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/cdesc-LightParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/cdesc-LightParser.ri new file mode 100644 index 00000000..b8606dd7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/cdesc-LightParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/new-c.ri new file mode 100644 index 00000000..28c10d84 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/parse-i.ri new file mode 100644 index 00000000..d63fff62 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/rewind-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/rewind-i.ri new file mode 100644 index 00000000..e81c75d9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/LightParser/rewind-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/%5b%5d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/%5b%5d-i.ri new file mode 100644 index 00000000..c6a6d2de Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/%5b%5d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/attlistdecl%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/attlistdecl%3f-i.ri new file mode 100644 index 00000000..7754cb13 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/attlistdecl%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdata%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdata%3f-i.ri new file mode 100644 index 00000000..2d9ad48e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdata%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdesc-PullEvent.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdesc-PullEvent.ri new file mode 100644 index 00000000..02ec3e24 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/cdesc-PullEvent.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/comment%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/comment%3f-i.ri new file mode 100644 index 00000000..f33c95c2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/comment%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/doctype%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/doctype%3f-i.ri new file mode 100644 index 00000000..6f4968b0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/doctype%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/elementdecl%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/elementdecl%3f-i.ri new file mode 100644 index 00000000..55d06950 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/elementdecl%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/end_element%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/end_element%3f-i.ri new file mode 100644 index 00000000..5c67034b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/end_element%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entity%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entity%3f-i.ri new file mode 100644 index 00000000..b13eaa18 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entity%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entitydecl%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entitydecl%3f-i.ri new file mode 100644 index 00000000..beb9c8b6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/entitydecl%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/error%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/error%3f-i.ri new file mode 100644 index 00000000..752da76a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/error%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/event_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/event_type-i.ri new file mode 100644 index 00000000..69e30797 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/event_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/inspect-i.ri new file mode 100644 index 00000000..edffd3b8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/instruction%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/instruction%3f-i.ri new file mode 100644 index 00000000..ade9cd17 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/instruction%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/new-c.ri new file mode 100644 index 00000000..57fc2d66 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/notationdecl%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/notationdecl%3f-i.ri new file mode 100644 index 00000000..491738af Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/notationdecl%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/start_element%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/start_element%3f-i.ri new file mode 100644 index 00000000..b781315c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/start_element%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/text%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/text%3f-i.ri new file mode 100644 index 00000000..64686183 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/text%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/xmldecl%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/xmldecl%3f-i.ri new file mode 100644 index 00000000..c4bf402a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullEvent/xmldecl%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/add_listener-i.ri new file mode 100644 index 00000000..d8db9679 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/cdesc-PullParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/cdesc-PullParser.ri new file mode 100644 index 00000000..701e46e5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/cdesc-PullParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/each-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/each-i.ri new file mode 100644 index 00000000..0c110567 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/each-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_count-i.ri new file mode 100644 index 00000000..96f50c5f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_limit%3d-i.ri new file mode 100644 index 00000000..82bf6022 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_text_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_text_limit%3d-i.ri new file mode 100644 index 00000000..4e90bfb3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/entity_expansion_text_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/new-c.ri new file mode 100644 index 00000000..413ad643 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/peek-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/peek-i.ri new file mode 100644 index 00000000..05249c15 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/peek-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/pull-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/pull-i.ri new file mode 100644 index 00000000..79f4ddfc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/pull-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/reset-i.ri new file mode 100644 index 00000000..786e07fe Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/unshift-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/unshift-i.ri new file mode 100644 index 00000000..3d0f9c00 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/PullParser/unshift-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add-i.ri new file mode 100644 index 00000000..4926f544 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add_listener-i.ri new file mode 100644 index 00000000..18ec65a4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/cdesc-SAX2Parser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/cdesc-SAX2Parser.ri new file mode 100644 index 00000000..50e11825 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/cdesc-SAX2Parser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/deafen-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/deafen-i.ri new file mode 100644 index 00000000..20e517a3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/deafen-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_count-i.ri new file mode 100644 index 00000000..0a3aeaa5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_limit%3d-i.ri new file mode 100644 index 00000000..8c6301dd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_text_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_text_limit%3d-i.ri new file mode 100644 index 00000000..2952f546 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/entity_expansion_text_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_listeners-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_listeners-i.ri new file mode 100644 index 00000000..b3440aa4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_listeners-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_namespace-i.ri new file mode 100644 index 00000000..12c41650 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_procs-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_procs-i.ri new file mode 100644 index 00000000..cee6453c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/get_procs-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle-i.ri new file mode 100644 index 00000000..b3611dee Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle_entitydecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle_entitydecl-i.ri new file mode 100644 index 00000000..111ff545 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/handle_entitydecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/listen-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/listen-i.ri new file mode 100644 index 00000000..fc1387d9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/listen-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/new-c.ri new file mode 100644 index 00000000..39f444a9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/parse-i.ri new file mode 100644 index 00000000..979dc117 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/source-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/source-i.ri new file mode 100644 index 00000000..e9bb723d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/SAX2Parser/source-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/add_listener-i.ri new file mode 100644 index 00000000..591a77d2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/cdesc-StreamParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/cdesc-StreamParser.ri new file mode 100644 index 00000000..281a1c7b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/cdesc-StreamParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_count-i.ri new file mode 100644 index 00000000..d3856928 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_limit%3d-i.ri new file mode 100644 index 00000000..793ef84f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_text_limit%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_text_limit%3d-i.ri new file mode 100644 index 00000000..6b9a5099 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/entity_expansion_text_limit%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/new-c.ri new file mode 100644 index 00000000..4e5b9427 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/parse-i.ri new file mode 100644 index 00000000..5c7473ad Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StreamParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/captures-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/captures-i.ri new file mode 100644 index 00000000..f0791363 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/captures-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/cdesc-StringScannerCaptures.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/cdesc-StringScannerCaptures.ri new file mode 100644 index 00000000..1f6349dd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/StringScannerCaptures/cdesc-StringScannerCaptures.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/add_listener-i.ri new file mode 100644 index 00000000..98ea8801 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/cdesc-TreeParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/cdesc-TreeParser.ri new file mode 100644 index 00000000..d09d4c46 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/cdesc-TreeParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/new-c.ri new file mode 100644 index 00000000..0634c062 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/parse-i.ri new file mode 100644 index 00000000..10df5edb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/TreeParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/add_listener-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/add_listener-i.ri new file mode 100644 index 00000000..174f2a29 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/add_listener-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/cdesc-UltraLightParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/cdesc-UltraLightParser.ri new file mode 100644 index 00000000..6bc5dd9b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/cdesc-UltraLightParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/new-c.ri new file mode 100644 index 00000000..1301a7d8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/parse-i.ri new file mode 100644 index 00000000..780c2c6c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/rewind-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/rewind-i.ri new file mode 100644 index 00000000..cb0bc27b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/UltraLightParser/rewind-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AdditiveExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AdditiveExpr-i.ri new file mode 100644 index 00000000..ec01c3e4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AdditiveExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AndExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AndExpr-i.ri new file mode 100644 index 00000000..b2ff5155 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/AndExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/EqualityExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/EqualityExpr-i.ri new file mode 100644 index 00000000..5a5e8eac Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/EqualityExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FilterExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FilterExpr-i.ri new file mode 100644 index 00000000..f51fda71 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FilterExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FunctionCall-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FunctionCall-i.ri new file mode 100644 index 00000000..b25d0ec7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/FunctionCall-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/LocationPath-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/LocationPath-i.ri new file mode 100644 index 00000000..53a16050 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/LocationPath-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/MultiplicativeExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/MultiplicativeExpr-i.ri new file mode 100644 index 00000000..bde79219 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/MultiplicativeExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/NodeTest-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/NodeTest-i.ri new file mode 100644 index 00000000..a61a8d93 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/NodeTest-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/OrExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/OrExpr-i.ri new file mode 100644 index 00000000..fe71a579 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/OrExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PathExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PathExpr-i.ri new file mode 100644 index 00000000..8f18e09c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PathExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/Predicate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/Predicate-i.ri new file mode 100644 index 00000000..6c0c86f2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/Predicate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PrimaryExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PrimaryExpr-i.ri new file mode 100644 index 00000000..3a40d39b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/PrimaryExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelationalExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelationalExpr-i.ri new file mode 100644 index 00000000..b70cd133 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelationalExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelativeLocationPath-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelativeLocationPath-i.ri new file mode 100644 index 00000000..0b78f26f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/RelativeLocationPath-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnaryExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnaryExpr-i.ri new file mode 100644 index 00000000..28d8f502 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnaryExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnionExpr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnionExpr-i.ri new file mode 100644 index 00000000..7c54d307 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/UnionExpr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/abbreviate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/abbreviate-i.ri new file mode 100644 index 00000000..7da765a0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/abbreviate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/cdesc-XPathParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/cdesc-XPathParser.ri new file mode 100644 index 00000000..392eead8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/cdesc-XPathParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/expand-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/expand-i.ri new file mode 100644 index 00000000..dd200508 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/expand-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/get_group-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/get_group-i.ri new file mode 100644 index 00000000..7b1e539d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/get_group-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/namespaces%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/namespaces%3d-i.ri new file mode 100644 index 00000000..869fa0de Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/namespaces%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse-i.ri new file mode 100644 index 00000000..76da7953 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse_args-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse_args-i.ri new file mode 100644 index 00000000..a5c40bca Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/parse_args-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/preciate_to_string-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/preciate_to_string-i.ri new file mode 100644 index 00000000..0aa6b82a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/preciate_to_string-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate-i.ri new file mode 100644 index 00000000..9fdc0c6d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate_to_path-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate_to_path-i.ri new file mode 100644 index 00000000..fe47194b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/predicate_to_path-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/quote_literal-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/quote_literal-i.ri new file mode 100644 index 00000000..bad8cb12 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/XPathParser/quote_literal-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Parsers/cdesc-Parsers.ri b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/cdesc-Parsers.ri new file mode 100644 index 00000000..73dac2f9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Parsers/cdesc-Parsers.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/attribute-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/attribute-c.ri new file mode 100644 index 00000000..d39a0153 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/attribute-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/axe-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/axe-c.ri new file mode 100644 index 00000000..76f12127 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/axe-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/cdesc-QuickPath.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/cdesc-QuickPath.ri new file mode 100644 index 00000000..e4364a32 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/cdesc-QuickPath.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/each-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/each-c.ri new file mode 100644 index 00000000..9c465b8f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/each-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/filter-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/filter-c.ri new file mode 100644 index 00000000..40d86365 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/filter-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/first-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/first-c.ri new file mode 100644 index 00000000..1cd886ef Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/first-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/function-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/function-c.ri new file mode 100644 index 00000000..9ec7947d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/function-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/match-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/match-c.ri new file mode 100644 index 00000000..fcb35795 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/match-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/method_missing-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/method_missing-c.ri new file mode 100644 index 00000000..9438fbe3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/method_missing-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/name-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/name-c.ri new file mode 100644 index 00000000..945e27d1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/name-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/parse_args-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/parse_args-c.ri new file mode 100644 index 00000000..7aad2dc4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/parse_args-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/predicate-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/predicate-c.ri new file mode 100644 index 00000000..f1e9f48a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/QuickPath/predicate-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/cdesc-ReferenceWriter.ri b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/cdesc-ReferenceWriter.ri new file mode 100644 index 00000000..5884bb84 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/cdesc-ReferenceWriter.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/new-c.ri new file mode 100644 index 00000000..ebbc7815 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/write-i.ri new file mode 100644 index 00000000..837edee1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/ReferenceWriter/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/attlistdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/attlistdecl-i.ri new file mode 100644 index 00000000..46f862b8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/attlistdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdata-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdata-i.ri new file mode 100644 index 00000000..b7019278 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdata-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdesc-SAX2Listener.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdesc-SAX2Listener.ri new file mode 100644 index 00000000..5cb58baf Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/cdesc-SAX2Listener.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/characters-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/characters-i.ri new file mode 100644 index 00000000..379effa9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/characters-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/comment-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/comment-i.ri new file mode 100644 index 00000000..f8adc6f5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/comment-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/doctype-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/doctype-i.ri new file mode 100644 index 00000000..5bc1441c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/doctype-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/elementdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/elementdecl-i.ri new file mode 100644 index 00000000..22bfc65f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/elementdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_document-i.ri new file mode 100644 index 00000000..0e9de0de Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_element-i.ri new file mode 100644 index 00000000..caa2bb59 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_prefix_mapping-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_prefix_mapping-i.ri new file mode 100644 index 00000000..2ae500d4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/end_prefix_mapping-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/entitydecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/entitydecl-i.ri new file mode 100644 index 00000000..15c45ca4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/entitydecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/notationdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/notationdecl-i.ri new file mode 100644 index 00000000..dc1fa21a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/notationdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/processing_instruction-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/processing_instruction-i.ri new file mode 100644 index 00000000..36423882 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/processing_instruction-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/progress-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/progress-i.ri new file mode 100644 index 00000000..7568b39a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/progress-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_document-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_document-i.ri new file mode 100644 index 00000000..e75e6743 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_document-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_element-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_element-i.ri new file mode 100644 index 00000000..ba12cd9c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_element-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_prefix_mapping-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_prefix_mapping-i.ri new file mode 100644 index 00000000..f970d475 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/start_prefix_mapping-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/xmldecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/xmldecl-i.ri new file mode 100644 index 00000000..abda91df Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SAX2Listener/xmldecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Security/cdesc-Security.ri b/bin/doc/rexml-3.4.4/ri/REXML/Security/cdesc-Security.ri new file mode 100644 index 00000000..8210f02f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Security/cdesc-Security.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit%3d-c.ri new file mode 100644 index 00000000..3848333a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit-c.ri new file mode 100644 index 00000000..9a4f55be Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_limit-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit%3d-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit%3d-c.ri new file mode 100644 index 00000000..24445102 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit%3d-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit-c.ri new file mode 100644 index 00000000..f16960ab Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Security/entity_expansion_text_limit-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/Private/cdesc-Private.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/Private/cdesc-Private.ri new file mode 100644 index 00000000..485e4aa6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/Private/cdesc-Private.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer-i.ri new file mode 100644 index 00000000..6f1e9fa0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer_encoding%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer_encoding%3d-i.ri new file mode 100644 index 00000000..aaad8924 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/buffer_encoding%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/cdesc-Source.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/cdesc-Source.ri new file mode 100644 index 00000000..4dd46fd4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/cdesc-Source.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/current_line-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/current_line-i.ri new file mode 100644 index 00000000..c02da751 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/current_line-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/detect_encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/detect_encoding-i.ri new file mode 100644 index 00000000..cbc044c9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/detect_encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/drop_parsed_content-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/drop_parsed_content-i.ri new file mode 100644 index 00000000..0c38f341 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/drop_parsed_content-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/empty%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/empty%3f-i.ri new file mode 100644 index 00000000..ac15302f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/empty%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding%3d-i.ri new file mode 100644 index 00000000..9e938b8f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding-i.ri new file mode 100644 index 00000000..247a4270 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding_updated-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding_updated-i.ri new file mode 100644 index 00000000..c855c4c3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/encoding_updated-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/ensure_buffer-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/ensure_buffer-i.ri new file mode 100644 index 00000000..befd23f7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/ensure_buffer-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/line-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/line-i.ri new file mode 100644 index 00000000..d659c719 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Source/line-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" line:ETI"REXML::Source#line;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I".The line number of the last consumed text;T: +@fileI"lib/rexml/source.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Source;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/match%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/match%3f-i.ri new file mode 100644 index 00000000..6a5e7bab Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/match%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/match-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/match-i.ri new file mode 100644 index 00000000..83cc1d01 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/match-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/new-c.ri new file mode 100644 index 00000000..8cd9037e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/peek_byte-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/peek_byte-i.ri new file mode 100644 index 00000000..0a6a7ce3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/peek_byte-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/position%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/position%3d-i.ri new file mode 100644 index 00000000..5a57d746 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/position%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/position-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/position-i.ri new file mode 100644 index 00000000..916089fb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/position-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/read-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/read-i.ri new file mode 100644 index 00000000..62f78ef6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/read-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/read_until-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/read_until-i.ri new file mode 100644 index 00000000..5ffef1a0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/read_until-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/scan_byte-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/scan_byte-i.ri new file mode 100644 index 00000000..e691dd1b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/scan_byte-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Source/skip_spaces-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Source/skip_spaces-i.ri new file mode 100644 index 00000000..f67ce133 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Source/skip_spaces-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/cdesc-SourceFactory.ri b/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/cdesc-SourceFactory.ri new file mode 100644 index 00000000..f183a070 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/cdesc-SourceFactory.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/create_from-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/create_from-c.ri new file mode 100644 index 00000000..3ccbb803 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/SourceFactory/create_from-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/attlistdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/attlistdecl-i.ri new file mode 100644 index 00000000..fb2db7f6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/attlistdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdata-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdata-i.ri new file mode 100644 index 00000000..29e381d5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdata-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdesc-StreamListener.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdesc-StreamListener.ri new file mode 100644 index 00000000..6154cce2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/cdesc-StreamListener.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/comment-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/comment-i.ri new file mode 100644 index 00000000..956e29d1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/comment-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype-i.ri new file mode 100644 index 00000000..2d456177 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype_end-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype_end-i.ri new file mode 100644 index 00000000..7a258ab6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/doctype_end-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/elementdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/elementdecl-i.ri new file mode 100644 index 00000000..cb3a03b3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/elementdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entity-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entity-i.ri new file mode 100644 index 00000000..82b16386 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entity-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entitydecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entitydecl-i.ri new file mode 100644 index 00000000..107882f6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/entitydecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/instruction-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/instruction-i.ri new file mode 100644 index 00000000..4dff9120 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/instruction-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/notationdecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/notationdecl-i.ri new file mode 100644 index 00000000..5ee9be9b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/notationdecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_end-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_end-i.ri new file mode 100644 index 00000000..f0ab20a1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_end-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_start-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_start-i.ri new file mode 100644 index 00000000..5b0706da Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/tag_start-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/text-i.ri new file mode 100644 index 00000000..90cdad2d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/xmldecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/xmldecl-i.ri new file mode 100644 index 00000000..331a3bc6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StreamListener/xmldecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/cdesc-StringScannerCheckScanString.ri b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/cdesc-StringScannerCheckScanString.ri new file mode 100644 index 00000000..4b97b3ff Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/cdesc-StringScannerCheckScanString.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/check-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/check-i.ri new file mode 100644 index 00000000..337c036b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/check-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/match%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/match%3f-i.ri new file mode 100644 index 00000000..f1f02abc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/match%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/scan-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/scan-i.ri new file mode 100644 index 00000000..30276411 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/scan-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/skip-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/skip-i.ri new file mode 100644 index 00000000..a8777dae Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/StringScannerCheckScanString/skip-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3c-i.ri new file mode 100644 index 00000000..689e927f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3d%3e-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3d%3e-i.ri new file mode 100644 index 00000000..b64f4a65 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/%3c%3d%3e-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/cdesc-Text.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/cdesc-Text.ri new file mode 100644 index 00000000..13e0cdd1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/cdesc-Text.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/check-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/check-c.ri new file mode 100644 index 00000000..e38abca6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/check-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/clear_cache-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/clear_cache-i.ri new file mode 100644 index 00000000..49d3faac Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/clear_cache-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/clone-i.ri new file mode 100644 index 00000000..588d6044 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/doctype-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/doctype-i.ri new file mode 100644 index 00000000..b8354902 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/doctype-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/empty%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/empty%3f-i.ri new file mode 100644 index 00000000..c9bb702d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/empty%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/expand-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/expand-c.ri new file mode 100644 index 00000000..9386aee9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/expand-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/indent_text-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/indent_text-i.ri new file mode 100644 index 00000000..fc24604f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/indent_text-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/inspect-i.ri new file mode 100644 index 00000000..e532eda5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/new-c.ri new file mode 100644 index 00000000..57228774 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/node_type-i.ri new file mode 100644 index 00000000..6f50eabc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/normalize-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/normalize-c.ri new file mode 100644 index 00000000..51e21b60 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/normalize-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/parent%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/parent%3d-i.ri new file mode 100644 index 00000000..6c75cc41 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/parent%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/raw-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/raw-i.ri new file mode 100644 index 00000000..a6194284 --- /dev/null +++ b/bin/doc/rexml-3.4.4/ri/REXML/Text/raw-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"raw:ETI"REXML::Text#raw;TI"RW;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"8If +raw+ is true, then REXML leaves the value alone;T: +@fileI"lib/rexml/text.rb;T:0@omit_headings_from_table_of_contents_below0F@I"REXML::Text;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/read_with_substitution-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/read_with_substitution-c.ri new file mode 100644 index 00000000..8508a3b6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/read_with_substitution-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/to_s-i.ri new file mode 100644 index 00000000..69e3fee0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/unnormalize-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/unnormalize-c.ri new file mode 100644 index 00000000..e269aba6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/unnormalize-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/value%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/value%3d-i.ri new file mode 100644 index 00000000..ebe876af Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/value%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/value-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/value-i.ri new file mode 100644 index 00000000..2b92ba8d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/value-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/wrap-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/wrap-i.ri new file mode 100644 index 00000000..494b4943 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/wrap-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/write-i.ri new file mode 100644 index 00000000..c5b7039e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/write_with_substitution-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/write_with_substitution-i.ri new file mode 100644 index 00000000..91659b42 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/write_with_substitution-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Text/xpath-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Text/xpath-i.ri new file mode 100644 index 00000000..0996d0f1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Text/xpath-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/cdesc-UndefinedNamespaceException.ri b/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/cdesc-UndefinedNamespaceException.ri new file mode 100644 index 00000000..ecc7a6d0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/cdesc-UndefinedNamespaceException.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/new-c.ri new file mode 100644 index 00000000..bf428528 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/UndefinedNamespaceException/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/%3c%3c-i.ri new file mode 100644 index 00000000..d8b54728 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/add_event_to_arry-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/add_event_to_arry-i.ri new file mode 100644 index 00000000..1b2691df Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/add_event_to_arry-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/cdesc-Choice.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/cdesc-Choice.ri new file mode 100644 index 00000000..3ac06932 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/cdesc-Choice.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/expected-i.ri new file mode 100644 index 00000000..a2971ab2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/inspect-i.ri new file mode 100644 index 00000000..71469fb0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/matches%3f-i.ri new file mode 100644 index 00000000..4f650e9d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/new-c.ri new file mode 100644 index 00000000..38d380dc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/next-i.ri new file mode 100644 index 00000000..f239e168 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/reset-i.ri new file mode 100644 index 00000000..3cd89c1d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Choice/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/%3d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/%3d%3d-i.ri new file mode 100644 index 00000000..cd906117 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/%3d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/cdesc-Event.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/cdesc-Event.ri new file mode 100644 index 00000000..971272b1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/cdesc-Event.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/done%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/done%3f-i.ri new file mode 100644 index 00000000..40ab108c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/done%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_arg-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_arg-i.ri new file mode 100644 index 00000000..5018cdc5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_arg-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_type-i.ri new file mode 100644 index 00000000..7959236a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/event_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/inspect-i.ri new file mode 100644 index 00000000..960ca6eb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/matches%3f-i.ri new file mode 100644 index 00000000..2176a9a1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/new-c.ri new file mode 100644 index 00000000..7ba9c41b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/single%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/single%3f-i.ri new file mode 100644 index 00000000..8e205e57 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/single%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/to_s-i.ri new file mode 100644 index 00000000..e3f620b8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Event/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/cdesc-Interleave.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/cdesc-Interleave.ri new file mode 100644 index 00000000..e32cb224 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/cdesc-Interleave.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/expected-i.ri new file mode 100644 index 00000000..8ba4e16d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/inspect-i.ri new file mode 100644 index 00000000..158453ad Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/matches%3f-i.ri new file mode 100644 index 00000000..44593106 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/new-c.ri new file mode 100644 index 00000000..b89a0c79 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next-i.ri new file mode 100644 index 00000000..f5938827 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next_current-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next_current-i.ri new file mode 100644 index 00000000..1f8cdc66 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/next_current-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/reset-i.ri new file mode 100644 index 00000000..34c3332f Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Interleave/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/cdesc-OneOrMore.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/cdesc-OneOrMore.ri new file mode 100644 index 00000000..259d7ca8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/cdesc-OneOrMore.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/expected-i.ri new file mode 100644 index 00000000..7f5dfaa0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/matches%3f-i.ri new file mode 100644 index 00000000..e7b3da9d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/new-c.ri new file mode 100644 index 00000000..dbbe9e8b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/next-i.ri new file mode 100644 index 00000000..42ff2454 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/reset-i.ri new file mode 100644 index 00000000..557d464c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/OneOrMore/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/cdesc-Optional.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/cdesc-Optional.ri new file mode 100644 index 00000000..af9a7e03 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/cdesc-Optional.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/expected-i.ri new file mode 100644 index 00000000..dcca478e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/matches%3f-i.ri new file mode 100644 index 00000000..d9873199 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/next-i.ri new file mode 100644 index 00000000..65f78d12 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Optional/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/cdesc-Ref.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/cdesc-Ref.ri new file mode 100644 index 00000000..53486164 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/cdesc-Ref.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/inspect-i.ri new file mode 100644 index 00000000..1fa6a86b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/new-c.ri new file mode 100644 index 00000000..1ac7b1ca Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/to_s-i.ri new file mode 100644 index 00000000..fdd5c48d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Ref/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/cdesc-RelaxNG.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/cdesc-RelaxNG.ri new file mode 100644 index 00000000..1cf6063b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/cdesc-RelaxNG.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/count-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/count-i.ri new file mode 100644 index 00000000..1a428751 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/count-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/current-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/current-i.ri new file mode 100644 index 00000000..ab73e4d4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/current-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/new-c.ri new file mode 100644 index 00000000..d4abf206 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/receive-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/receive-i.ri new file mode 100644 index 00000000..b4b3efa8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/receive-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/references-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/references-i.ri new file mode 100644 index 00000000..9a51487d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/RelaxNG/references-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/cdesc-Sequence.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/cdesc-Sequence.ri new file mode 100644 index 00000000..dcb45c53 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/cdesc-Sequence.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/matches%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/matches%3f-i.ri new file mode 100644 index 00000000..3d4018e5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Sequence/matches%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/%3c%3c-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/%3c%3c-i.ri new file mode 100644 index 00000000..7e81409d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/%3c%3c-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/add_event_to_arry-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/add_event_to_arry-i.ri new file mode 100644 index 00000000..a2e2987d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/add_event_to_arry-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/cdesc-State.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/cdesc-State.ri new file mode 100644 index 00000000..d1b77947 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/cdesc-State.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expand_ref_in-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expand_ref_in-i.ri new file mode 100644 index 00000000..21d10b30 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expand_ref_in-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expected-i.ri new file mode 100644 index 00000000..f3d196b8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/generate_event-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/generate_event-i.ri new file mode 100644 index 00000000..a4581a26 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/generate_event-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/inspect-i.ri new file mode 100644 index 00000000..cd3789a2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/new-c.ri new file mode 100644 index 00000000..3c5d31a3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/next-i.ri new file mode 100644 index 00000000..9777fca2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/previous%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/previous%3d-i.ri new file mode 100644 index 00000000..3f7d7d7c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/previous%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/reset-i.ri new file mode 100644 index 00000000..d073d145 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/to_s-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/to_s-i.ri new file mode 100644 index 00000000..c588862e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/State/to_s-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/cdesc-ValidationException.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/cdesc-ValidationException.ri new file mode 100644 index 00000000..1b50d856 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/cdesc-ValidationException.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/new-c.ri new file mode 100644 index 00000000..dd8fc850 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ValidationException/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/cdesc-Validator.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/cdesc-Validator.ri new file mode 100644 index 00000000..f23d627c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/cdesc-Validator.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/dump-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/dump-i.ri new file mode 100644 index 00000000..4e088d3a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/dump-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/reset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/reset-i.ri new file mode 100644 index 00000000..ee6047f9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/reset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/validate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/validate-i.ri new file mode 100644 index 00000000..db30a2a6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/Validator/validate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/cdesc-ZeroOrMore.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/cdesc-ZeroOrMore.ri new file mode 100644 index 00000000..757d0d3e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/cdesc-ZeroOrMore.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/expected-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/expected-i.ri new file mode 100644 index 00000000..01f2a852 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/expected-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/next-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/next-i.ri new file mode 100644 index 00000000..e0f8c305 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/ZeroOrMore/next-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/Validation/cdesc-Validation.ri b/bin/doc/rexml-3.4.4/ri/REXML/Validation/cdesc-Validation.ri new file mode 100644 index 00000000..412f7676 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/Validation/cdesc-Validation.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/%3d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/%3d%3d-i.ri new file mode 100644 index 00000000..681755db Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/%3d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/cdesc-XMLDecl.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/cdesc-XMLDecl.ri new file mode 100644 index 00000000..be5b8d00 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/cdesc-XMLDecl.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/clone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/clone-i.ri new file mode 100644 index 00000000..95eddd03 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/clone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/content-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/content-i.ri new file mode 100644 index 00000000..8eda90d2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/content-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/default-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/default-c.ri new file mode 100644 index 00000000..94ec63f2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/default-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/dowrite-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/dowrite-i.ri new file mode 100644 index 00000000..c2fb1e7d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/dowrite-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/encoding%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/encoding%3d-i.ri new file mode 100644 index 00000000..8b3e5163 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/encoding%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/inspect-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/inspect-i.ri new file mode 100644 index 00000000..06616e83 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/inspect-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/new-c.ri new file mode 100644 index 00000000..76871ac3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/node_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/node_type-i.ri new file mode 100644 index 00000000..ce043416 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/node_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/nowrite-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/nowrite-i.ri new file mode 100644 index 00000000..8582eea1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/nowrite-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/old_enc%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/old_enc%3d-i.ri new file mode 100644 index 00000000..0577fed2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/old_enc%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/stand_alone%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/stand_alone%3f-i.ri new file mode 100644 index 00000000..f8128aff Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/stand_alone%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/standalone-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/standalone-i.ri new file mode 100644 index 00000000..ed296f14 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/standalone-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/version-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/version-i.ri new file mode 100644 index 00000000..04d64393 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/version-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/write-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/write-i.ri new file mode 100644 index 00000000..578d8521 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/write-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writeencoding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writeencoding-i.ri new file mode 100644 index 00000000..c26a1cc3 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writeencoding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writethis-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writethis-i.ri new file mode 100644 index 00000000..2a187319 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/writethis-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/xmldecl-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/xmldecl-i.ri new file mode 100644 index 00000000..c21942d9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLDecl/xmldecl-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XMLTokens/cdesc-XMLTokens.ri b/bin/doc/rexml-3.4.4/ri/REXML/XMLTokens/cdesc-XMLTokens.ri new file mode 100644 index 00000000..78c68752 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XMLTokens/cdesc-XMLTokens.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPath/cdesc-XPath.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPath/cdesc-XPath.ri new file mode 100644 index 00000000..8b1e4e31 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPath/cdesc-XPath.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPath/each-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPath/each-c.ri new file mode 100644 index 00000000..80cab053 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPath/each-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPath/first-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPath/first-c.ri new file mode 100644 index 00000000..26cef678 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPath/first-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPath/match-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPath/match-c.ri new file mode 100644 index 00000000..3880c036 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPath/match-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/cdesc-XPathNode.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/cdesc-XPathNode.ri new file mode 100644 index 00000000..6e2c93ac Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/cdesc-XPathNode.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/context-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/context-i.ri new file mode 100644 index 00000000..e6abe48b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/context-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/new-c.ri new file mode 100644 index 00000000..aadcdef2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/position-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/position-i.ri new file mode 100644 index 00000000..0d504b42 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/position-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/raw_node-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/raw_node-i.ri new file mode 100644 index 00000000..977248f6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathNode/raw_node-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/%5b%5d%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/%5b%5d%3d-i.ri new file mode 100644 index 00000000..5d1e5e25 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/%5b%5d%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/cdesc-XPathParser.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/cdesc-XPathParser.ri new file mode 100644 index 00000000..6ccffe41 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/cdesc-XPathParser.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/child-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/child-i.ri new file mode 100644 index 00000000..b6bad3c5 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/child-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/compare-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/compare-i.ri new file mode 100644 index 00000000..27d4f4f0 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/compare-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant-i.ri new file mode 100644 index 00000000..5249bd3b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant_recursive-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant_recursive-i.ri new file mode 100644 index 00000000..95ff1c13 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/descendant_recursive-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/each_unnode-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/each_unnode-i.ri new file mode 100644 index 00000000..9ecb612c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/each_unnode-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/enter-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/enter-i.ri new file mode 100644 index 00000000..b00532f4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/enter-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/equality_relational_compare-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/equality_relational_compare-i.ri new file mode 100644 index 00000000..6cd5944e Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/equality_relational_compare-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/evaluate_predicate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/evaluate_predicate-i.ri new file mode 100644 index 00000000..825508d7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/evaluate_predicate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/expr-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/expr-i.ri new file mode 100644 index 00000000..3a10c854 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/expr-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/filter_nodeset-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/filter_nodeset-i.ri new file mode 100644 index 00000000..90c3d994 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/filter_nodeset-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/first-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/first-i.ri new file mode 100644 index 00000000..7cb77e16 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/first-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following-i.ri new file mode 100644 index 00000000..d55eb740 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following_node_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following_node_of-i.ri new file mode 100644 index 00000000..91ed07dd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/following_node_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_first-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_first-i.ri new file mode 100644 index 00000000..b7af8fbd Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_first-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_namespace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_namespace-i.ri new file mode 100644 index 00000000..ff628653 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/get_namespace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/leave-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/leave-i.ri new file mode 100644 index 00000000..4f9a1693 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/leave-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/match-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/match-i.ri new file mode 100644 index 00000000..cfe1e051 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/match-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/namespaces%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/namespaces%3d-i.ri new file mode 100644 index 00000000..bea9fe48 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/namespaces%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/new-c.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/new-c.ri new file mode 100644 index 00000000..a625151a Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/new-c.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/next_sibling_node-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/next_sibling_node-i.ri new file mode 100644 index 00000000..cf9fdd5d Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/next_sibling_node-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/node_test-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/node_test-i.ri new file mode 100644 index 00000000..44b89cb1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/node_test-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/norm-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/norm-i.ri new file mode 100644 index 00000000..43d06a5c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/norm-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/normalize_compare_values-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/normalize_compare_values-i.ri new file mode 100644 index 00000000..4c0b74f4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/normalize_compare_values-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/parse-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/parse-i.ri new file mode 100644 index 00000000..2e649533 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/parse-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding-i.ri new file mode 100644 index 00000000..ce158097 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding_node_of-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding_node_of-i.ri new file mode 100644 index 00000000..a4c26746 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/preceding_node_of-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/predicate-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/predicate-i.ri new file mode 100644 index 00000000..81f9b763 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/predicate-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/sort-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/sort-i.ri new file mode 100644 index 00000000..bd8f9176 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/sort-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/step-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/step-i.ri new file mode 100644 index 00000000..89f7b96c Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/step-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/strict%3f-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/strict%3f-i.ri new file mode 100644 index 00000000..9fcf8592 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/strict%3f-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/trace-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/trace-i.ri new file mode 100644 index 00000000..57b24bf7 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/trace-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/unnode-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/unnode-i.ri new file mode 100644 index 00000000..3895f3cc Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/unnode-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/value_type-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/value_type-i.ri new file mode 100644 index 00000000..b4e284e8 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/value_type-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/variables%3d-i.ri b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/variables%3d-i.ri new file mode 100644 index 00000000..88a81616 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/XPathParser/variables%3d-i.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/REXML/cdesc-REXML.ri b/bin/doc/rexml-3.4.4/ri/REXML/cdesc-REXML.ri new file mode 100644 index 00000000..f1218ed2 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/REXML/cdesc-REXML.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/cache.ri b/bin/doc/rexml-3.4.4/ri/cache.ri new file mode 100644 index 00000000..96e9a710 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/cache.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/page-context_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/page-context_rdoc.ri new file mode 100644 index 00000000..d7929d48 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/page-context_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/page-tutorial_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/page-tutorial_rdoc.ri new file mode 100644 index 00000000..acbd7a82 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/page-tutorial_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-child_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-child_rdoc.ri new file mode 100644 index 00000000..60412ea4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-child_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-document_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-document_rdoc.ri new file mode 100644 index 00000000..7eea8877 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-document_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-element_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-element_rdoc.ri new file mode 100644 index 00000000..247aedb6 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-element_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-node_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-node_rdoc.ri new file mode 100644 index 00000000..2952e1cb Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-node_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-parent_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-parent_rdoc.ri new file mode 100644 index 00000000..0f74d408 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/rdoc/page-parent_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-child_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-child_toc_rdoc.ri new file mode 100644 index 00000000..3f254137 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-child_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-document_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-document_toc_rdoc.ri new file mode 100644 index 00000000..45483842 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-document_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-element_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-element_toc_rdoc.ri new file mode 100644 index 00000000..622bdb88 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-element_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-master_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-master_toc_rdoc.ri new file mode 100644 index 00000000..4a81fc84 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-master_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-node_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-node_toc_rdoc.ri new file mode 100644 index 00000000..08e59af9 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-node_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-parent_toc_rdoc.ri b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-parent_toc_rdoc.ri new file mode 100644 index 00000000..bfb799d4 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/doc/rexml/tasks/tocs/page-parent_toc_rdoc.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/page-LICENSE_txt.ri b/bin/doc/rexml-3.4.4/ri/page-LICENSE_txt.ri new file mode 100644 index 00000000..c31a9f27 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/page-LICENSE_txt.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/page-NEWS_md.ri b/bin/doc/rexml-3.4.4/ri/page-NEWS_md.ri new file mode 100644 index 00000000..022d85c1 Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/page-NEWS_md.ri differ diff --git a/bin/doc/rexml-3.4.4/ri/page-README_md.ri b/bin/doc/rexml-3.4.4/ri/page-README_md.ri new file mode 100644 index 00000000..6a1efa8b Binary files /dev/null and b/bin/doc/rexml-3.4.4/ri/page-README_md.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/cdesc-Debug.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/cdesc-Debug.ri new file mode 100644 index 00000000..e681d32b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/cdesc-Debug.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/desc-c.ri new file mode 100644 index 00000000..875a5c81 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/doc-c.ri new file mode 100644 index 00000000..3c56647a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/parse_opts-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/parse_opts-c.ri new file mode 100644 index 00000000..ab1a5aa3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Debug/parse_opts-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/cdesc-Error.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/cdesc-Error.ri new file mode 100644 index 00000000..2b794b8f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/cdesc-Error.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/message-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/message-i.ri new file mode 100644 index 00000000..6c341321 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/message-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/new-c.ri new file mode 100644 index 00000000..eacfc1ce Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/status-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/status-i.ri new file mode 100644 index 00000000..1b954416 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Error/status-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/cdesc-Guess.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/cdesc-Guess.ri new file mode 100644 index 00000000..53b433f8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/cdesc-Guess.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/desc-c.ri new file mode 100644 index 00000000..b1949e0f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_file-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_file-i.ri new file mode 100644 index 00000000..41c8d20f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_file-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_source-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_source-i.ri new file mode 100644 index 00000000..254059c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/input_source-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/lexers-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/lexers-i.ri new file mode 100644 index 00000000..ad28f2d9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/lexers-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/new-c.ri new file mode 100644 index 00000000..6fb512a2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/parse-c.ri new file mode 100644 index 00000000..c6da2ef0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/run-i.ri new file mode 100644 index 00000000..1f3114af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Guess/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/cdesc-Help.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/cdesc-Help.ri new file mode 100644 index 00000000..f26c55b4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/cdesc-Help.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/desc-c.ri new file mode 100644 index 00000000..cfb1de6c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/doc-c.ri new file mode 100644 index 00000000..0887c8ca Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/new-c.ri new file mode 100644 index 00000000..b6e0c06d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/parse-c.ri new file mode 100644 index 00000000..28361e38 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/run-i.ri new file mode 100644 index 00000000..3dd26c1b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Help/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/cdesc-Highlight.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/cdesc-Highlight.ri new file mode 100644 index 00000000..9b68339e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/cdesc-Highlight.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/desc-c.ri new file mode 100644 index 00000000..d842a288 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/doc-c.ri new file mode 100644 index 00000000..964c3ac9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape-i.ri new file mode 100644 index 00000000..f07f5838 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape_lexer-i.ri new file mode 100644 index 00000000..b72cf571 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/escape_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/formatter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/formatter-i.ri new file mode 100644 index 00000000..d2b0f0d7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/formatter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input-i.ri new file mode 100644 index 00000000..f3abddc1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_file-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_file-i.ri new file mode 100644 index 00000000..af9666ec Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_file-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_stream-i.ri new file mode 100644 index 00000000..557715c7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/input_stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer-i.ri new file mode 100644 index 00000000..745363b1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_class-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_class-i.ri new file mode 100644 index 00000000..02d5041d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_class-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_name-i.ri new file mode 100644 index 00000000..e6db97db Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/lexer_name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/mimetype-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/mimetype-i.ri new file mode 100644 index 00000000..2188b454 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/mimetype-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/new-c.ri new file mode 100644 index 00000000..7b5b5ac9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse-c.ri new file mode 100644 index 00000000..ce0dd45c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_cgi-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_cgi-c.ri new file mode 100644 index 00000000..dbd46ea9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_cgi-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_opts-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_opts-c.ri new file mode 100644 index 00000000..1e577111 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/parse_opts-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/raw_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/raw_lexer-i.ri new file mode 100644 index 00000000..998e29ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/raw_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/run-i.ri new file mode 100644 index 00000000..d34550d4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/supports_truecolor%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/supports_truecolor%3f-c.ri new file mode 100644 index 00000000..8c6eb044 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Highlight/supports_truecolor%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/cdesc-List.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/cdesc-List.ri new file mode 100644 index 00000000..ee474c54 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/cdesc-List.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/desc-c.ri new file mode 100644 index 00000000..d67ff650 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/doc-c.ri new file mode 100644 index 00000000..5e383802 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/parse-c.ri new file mode 100644 index 00000000..3cdb8d17 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/run-i.ri new file mode 100644 index 00000000..836348c7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/List/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/cdesc-Style.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/cdesc-Style.ri new file mode 100644 index 00000000..0bbbec98 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/cdesc-Style.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/desc-c.ri new file mode 100644 index 00000000..7a680c0d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/doc-c.ri new file mode 100644 index 00000000..d4b830c0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/new-c.ri new file mode 100644 index 00000000..47a7b560 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/parse-c.ri new file mode 100644 index 00000000..b1d62a30 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/run-i.ri new file mode 100644 index 00000000..007ae657 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Style/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/cdesc-Version.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/cdesc-Version.ri new file mode 100644 index 00000000..d3d3540c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/cdesc-Version.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/desc-c.ri new file mode 100644 index 00000000..bd4ad1a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/parse-c.ri new file mode 100644 index 00000000..60e360bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/run-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/run-i.ri new file mode 100644 index 00000000..9501f7c1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/Version/run-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/cdesc-CLI.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/cdesc-CLI.ri new file mode 100644 index 00000000..d187f2f3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/cdesc-CLI.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/class_from_arg-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/class_from_arg-c.ri new file mode 100644 index 00000000..73fff1fe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/class_from_arg-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/doc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/doc-c.ri new file mode 100644 index 00000000..a2e602f2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/doc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-c.ri new file mode 100644 index 00000000..caa78891 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-i.ri new file mode 100644 index 00000000..9168f872 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/error%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/new-c.ri new file mode 100644 index 00000000..91f9652b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/normalize_syntax-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/normalize_syntax-c.ri new file mode 100644 index 00000000..a55ee08f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/normalize_syntax-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CLI/parse-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/parse-c.ri new file mode 100644 index 00000000..ffef1a97 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CLI/parse-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/cdesc-CSSTheme.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/cdesc-CSSTheme.ri new file mode 100644 index 00000000..00e267e5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/cdesc-CSSTheme.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/css_selector-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/css_selector-i.ri new file mode 100644 index 00000000..62e610cc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/css_selector-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/inflate_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/inflate_token-i.ri new file mode 100644 index 00000000..d0cd31cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/inflate_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/new-c.ri new file mode 100644 index 00000000..da5e2a7f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render-i.ri new file mode 100644 index 00000000..c7dbb23a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render_base-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render_base-i.ri new file mode 100644 index 00000000..fb171eee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/render_base-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/single_css_selector-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/single_css_selector-i.ri new file mode 100644 index 00000000..4f41b272 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/single_css_selector-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/style_for-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/style_for-i.ri new file mode 100644 index 00000000..79589afd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/CSSTheme/style_for-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/cdesc-FileReader.ri b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/cdesc-FileReader.ri new file mode 100644 index 00000000..73421b46 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/cdesc-FileReader.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/file-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/file-i.ri new file mode 100644 index 00000000..6236db79 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/file-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/input-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/input-i.ri new file mode 100644 index 00000000..4ec386ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/input-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/new-c.ri new file mode 100644 index 00000000..93821cc9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/read-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/read-i.ri new file mode 100644 index 00000000..19948c53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/FileReader/read-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/cdesc-Formatter.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/cdesc-Formatter.ri new file mode 100644 index 00000000..aebf9064 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/cdesc-Formatter.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/disable_escape%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/disable_escape%21-c.ri new file mode 100644 index 00000000..894b8921 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/disable_escape%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/enable_escape%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/enable_escape%21-c.ri new file mode 100644 index 00000000..874b06e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/enable_escape%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape%3f-i.ri new file mode 100644 index 00000000..e589516e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape_enabled%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape_enabled%3f-c.ri new file mode 100644 index 00000000..9477fcc7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/escape_enabled%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/filter_escapes-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/filter_escapes-i.ri new file mode 100644 index 00000000..fa8410af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/filter_escapes-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/find-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/find-c.ri new file mode 100644 index 00000000..2e1d2a0e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/find-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-c.ri new file mode 100644 index 00000000..6d464afd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-i.ri new file mode 100644 index 00000000..6182b13d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/format-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/new-c.ri new file mode 100644 index 00000000..366ed7f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/render-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/render-i.ri new file mode 100644 index 00000000..80811263 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/render-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/stream-i.ri new file mode 100644 index 00000000..229f72e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/tag-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/tag-c.ri new file mode 100644 index 00000000..9d51b728 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/tag-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/token_lines-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/token_lines-i.ri new file mode 100644 index 00000000..2e55455a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/token_lines-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/with_escape-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/with_escape-c.ri new file mode 100644 index 00000000..2e817349 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatter/with_escape-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/cdesc-HTML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/cdesc-HTML.ri new file mode 100644 index 00000000..065177ab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/cdesc-HTML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/escape_special_html_chars-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/escape_special_html_chars-i.ri new file mode 100644 index 00000000..74f10296 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/escape_special_html_chars-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/safe_span-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/safe_span-i.ri new file mode 100644 index 00000000..1c509aab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/safe_span-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/span-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/span-i.ri new file mode 100644 index 00000000..c7fbe96b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/span-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/stream-i.ri new file mode 100644 index 00000000..773ac88b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTML/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/cdesc-HTMLInline.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/cdesc-HTMLInline.ri new file mode 100644 index 00000000..f1866543 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/cdesc-HTMLInline.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/new-c.ri new file mode 100644 index 00000000..aa249e5d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/safe_span-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/safe_span-i.ri new file mode 100644 index 00000000..c52eec80 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLInline/safe_span-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/cdesc-HTMLLegacy.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/cdesc-HTMLLegacy.ri new file mode 100644 index 00000000..192492de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/cdesc-HTMLLegacy.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/new-c.ri new file mode 100644 index 00000000..63eacd50 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/stream-i.ri new file mode 100644 index 00000000..1ecfee51 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLegacy/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/cdesc-HTMLLineHighlighter.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/cdesc-HTMLLineHighlighter.ri new file mode 100644 index 00000000..1e8538fb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/cdesc-HTMLLineHighlighter.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/new-c.ri new file mode 100644 index 00000000..dfa154bc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/stream-i.ri new file mode 100644 index 00000000..b0f70faa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineHighlighter/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/cdesc-HTMLLineTable.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/cdesc-HTMLLineTable.ri new file mode 100644 index 00000000..be64d38b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/cdesc-HTMLLineTable.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/new-c.ri new file mode 100644 index 00000000..e3d434f2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/stream-i.ri new file mode 100644 index 00000000..295a7ca1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLineTable/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/cdesc-HTMLLinewise.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/cdesc-HTMLLinewise.ri new file mode 100644 index 00000000..69409d32 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/cdesc-HTMLLinewise.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/new-c.ri new file mode 100644 index 00000000..9b00fa0a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/stream-i.ri new file mode 100644 index 00000000..ea4d33c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLLinewise/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/cdesc-HTMLPygments.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/cdesc-HTMLPygments.ri new file mode 100644 index 00000000..5b8ff123 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/cdesc-HTMLPygments.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/new-c.ri new file mode 100644 index 00000000..e9beae64 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/stream-i.ri new file mode 100644 index 00000000..6114b9ee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLPygments/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/cdesc-HTMLTable.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/cdesc-HTMLTable.ri new file mode 100644 index 00000000..671a82a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/cdesc-HTMLTable.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/new-c.ri new file mode 100644 index 00000000..89230c7a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/stream-i.ri new file mode 100644 index 00000000..88c68e01 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/style-i.ri new file mode 100644 index 00000000..159064f4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/HTMLTable/style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/cdesc-Null.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/cdesc-Null.ri new file mode 100644 index 00000000..052efa9d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/cdesc-Null.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/new-c.ri new file mode 100644 index 00000000..7cb3c61d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/stream-i.ri new file mode 100644 index 00000000..7f62eaab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Null/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/bg-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/bg-i.ri new file mode 100644 index 00000000..a947ca0d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/bg-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/cdesc-EscapeSequence.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/cdesc-EscapeSequence.ri new file mode 100644 index 00000000..8f920d41 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/cdesc-EscapeSequence.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/closest_color-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/closest_color-c.ri new file mode 100644 index 00000000..bd26efdc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/closest_color-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/color_index-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/color_index-c.ri new file mode 100644 index 00000000..36603b52 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/color_index-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/escape-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/escape-i.ri new file mode 100644 index 00000000..74fca566 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/escape-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/fg-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/fg-i.ri new file mode 100644 index 00000000..1db6ef2e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/fg-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/get_rgb-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/get_rgb-c.ri new file mode 100644 index 00000000..a9c0ecae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/get_rgb-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/new-c.ri new file mode 100644 index 00000000..50e27b45 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/reset_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/reset_string-i.ri new file mode 100644 index 00000000..52b046c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/reset_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/stream_value-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/stream_value-i.ri new file mode 100644 index 00000000..57354da5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/stream_value-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style-i.ri new file mode 100644 index 00000000..b4bce891 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style_string-i.ri new file mode 100644 index 00000000..a3a843d2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/style_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/xterm_colors-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/xterm_colors-c.ri new file mode 100644 index 00000000..477e12f4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/EscapeSequence/xterm_colors-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/cdesc-Unescape.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/cdesc-Unescape.ri new file mode 100644 index 00000000..a7b5943d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/cdesc-Unescape.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/escape_sequence-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/escape_sequence-i.ri new file mode 100644 index 00000000..e5b2562f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/escape_sequence-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/get_style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/get_style-i.ri new file mode 100644 index 00000000..a423ae53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/get_style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/make_escape_sequence-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/make_escape_sequence-i.ri new file mode 100644 index 00000000..0ca6aac3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/make_escape_sequence-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/new-c.ri new file mode 100644 index 00000000..0ea9775f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/reset_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/reset_string-i.ri new file mode 100644 index 00000000..83be5a09 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/reset_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/stream_value-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/stream_value-i.ri new file mode 100644 index 00000000..a0a3067e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/stream_value-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/style_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/style_string-i.ri new file mode 100644 index 00000000..b404d824 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/style_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/text_style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/text_style-i.ri new file mode 100644 index 00000000..522f81b6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/Unescape/text_style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/cdesc-Terminal256.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/cdesc-Terminal256.ri new file mode 100644 index 00000000..ba9db1f6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/cdesc-Terminal256.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/new-c.ri new file mode 100644 index 00000000..87ae8b9e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/stream-i.ri new file mode 100644 index 00000000..eca864f3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/theme-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/theme-i.ri new file mode 100644 index 00000000..84214026 --- /dev/null +++ b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Terminal256/theme-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +theme:ETI")Rouge::Formatters::Terminal256#theme;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I" @private;T: +@fileI"(lib/rouge/formatters/terminal256.rb;T:0@omit_headings_from_table_of_contents_below0F@I"#Rouge::Formatters::Terminal256;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/cdesc-TruecolorEscapeSequence.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/cdesc-TruecolorEscapeSequence.ri new file mode 100644 index 00000000..e39aa172 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/cdesc-TruecolorEscapeSequence.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/get_rgb-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/get_rgb-i.ri new file mode 100644 index 00000000..683badf3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/get_rgb-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/style_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/style_string-i.ri new file mode 100644 index 00000000..4daf5aa4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/TruecolorEscapeSequence/style_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/cdesc-TerminalTruecolor.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/cdesc-TerminalTruecolor.ri new file mode 100644 index 00000000..01a836e5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/cdesc-TerminalTruecolor.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/make_escape_sequence-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/make_escape_sequence-i.ri new file mode 100644 index 00000000..0c8c870c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/TerminalTruecolor/make_escape_sequence-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/cdesc-Tex.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/cdesc-Tex.ri new file mode 100644 index 00000000..957ede35 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/cdesc-Tex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/escape_tex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/escape_tex-i.ri new file mode 100644 index 00000000..1529dfcc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/escape_tex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/hphantom_tag-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/hphantom_tag-i.ri new file mode 100644 index 00000000..174672b7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/hphantom_tag-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/new-c.ri new file mode 100644 index 00000000..b7a76a00 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/render_line-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/render_line-i.ri new file mode 100644 index 00000000..6f5864b5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/render_line-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/stream-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/stream-i.ri new file mode 100644 index 00000000..9342524d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/stream-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/tag-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/tag-i.ri new file mode 100644 index 00000000..f988761c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/Tex/tag-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/cdesc-Formatters.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/cdesc-Formatters.ri new file mode 100644 index 00000000..1ef9540d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Formatters/cdesc-Formatters.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/alternatives-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/alternatives-i.ri new file mode 100644 index 00000000..b5ea5209 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/alternatives-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/cdesc-Ambiguous.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/cdesc-Ambiguous.ri new file mode 100644 index 00000000..fa22ff14 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/cdesc-Ambiguous.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/message-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/message-i.ri new file mode 100644 index 00000000..0afb610c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/message-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/new-c.ri new file mode 100644 index 00000000..b9b8204c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/Ambiguous/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/cdesc-Guesser.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/cdesc-Guesser.ri new file mode 100644 index 00000000..e2746187 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/cdesc-Guesser.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/collect_best-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/collect_best-i.ri new file mode 100644 index 00000000..e3ecbd70 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/collect_best-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/filter-i.ri new file mode 100644 index 00000000..fc68693d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/guess-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/guess-c.ri new file mode 100644 index 00000000..a6bd46be Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guesser/guess-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/cdesc-Disambiguator.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/cdesc-Disambiguator.ri new file mode 100644 index 00000000..81539e54 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/cdesc-Disambiguator.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/decide%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/decide%21-i.ri new file mode 100644 index 00000000..e1f1a903 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/decide%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/match%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/match%3f-i.ri new file mode 100644 index 00000000..5006ef43 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/match%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/new-c.ri new file mode 100644 index 00000000..846068bb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/Disambiguator/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/cdesc-Disambiguation.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/cdesc-Disambiguation.ri new file mode 100644 index 00000000..af359669 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/cdesc-Disambiguation.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/contains%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/contains%3f-i.ri new file mode 100644 index 00000000..2e477e90 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/contains%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguate-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguate-c.ri new file mode 100644 index 00000000..8ed5997d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguate-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguators-c.ri new file mode 100644 index 00000000..966ad65a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/disambiguators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/filter-i.ri new file mode 100644 index 00000000..4b2e5014 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/matches%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/matches%3f-i.ri new file mode 100644 index 00000000..3892404f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/matches%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/new-c.ri new file mode 100644 index 00000000..f2a72a93 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Disambiguation/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/cdesc-Filename.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/cdesc-Filename.ri new file mode 100644 index 00000000..05e09475 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/cdesc-Filename.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/filter-i.ri new file mode 100644 index 00000000..5f93a9c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/fname-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/fname-i.ri new file mode 100644 index 00000000..5f152b27 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/fname-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/new-c.ri new file mode 100644 index 00000000..054c4027 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Filename/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/by_pairs-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/by_pairs-c.ri new file mode 100644 index 00000000..882c59af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/by_pairs-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/cdesc-GlobMapping.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/cdesc-GlobMapping.ri new file mode 100644 index 00000000..823ceb3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/cdesc-GlobMapping.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filename-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filename-i.ri new file mode 100644 index 00000000..e0bfb7f7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filename-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filter-i.ri new file mode 100644 index 00000000..8278def0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/glob_map-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/glob_map-i.ri new file mode 100644 index 00000000..96b23e47 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/glob_map-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/new-c.ri new file mode 100644 index 00000000..935c973e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/GlobMapping/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/cdesc-Mimetype.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/cdesc-Mimetype.ri new file mode 100644 index 00000000..e968c782 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/cdesc-Mimetype.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/filter-i.ri new file mode 100644 index 00000000..7d7b4d20 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/mimetype-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/mimetype-i.ri new file mode 100644 index 00000000..dbdb2501 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/mimetype-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/new-c.ri new file mode 100644 index 00000000..42d7d98a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Mimetype/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/cdesc-Modeline.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/cdesc-Modeline.ri new file mode 100644 index 00000000..22e7a860 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/cdesc-Modeline.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/filter-i.ri new file mode 100644 index 00000000..6ddca180 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/new-c.ri new file mode 100644 index 00000000..adfcc9a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Modeline/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/cdesc-Source.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/cdesc-Source.ri new file mode 100644 index 00000000..9ce998c5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/cdesc-Source.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/filter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/filter-i.ri new file mode 100644 index 00000000..2f10ba55 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/filter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/new-c.ri new file mode 100644 index 00000000..adb9d909 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/source-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/source-i.ri new file mode 100644 index 00000000..8b97cb21 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Source/source-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/cdesc-SourceNormalizer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/cdesc-SourceNormalizer.ri new file mode 100644 index 00000000..e9bc8ae1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/cdesc-SourceNormalizer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/normalize-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/normalize-c.ri new file mode 100644 index 00000000..9925ae5d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/SourceNormalizer/normalize-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/cdesc-Util.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/cdesc-Util.ri new file mode 100644 index 00000000..ed33addf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/cdesc-Util.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/get_source-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/get_source-i.ri new file mode 100644 index 00000000..4dfe49fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/get_source-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/test_glob-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/test_glob-i.ri new file mode 100644 index 00000000..10c62135 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/Util/test_glob-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/cdesc-Guessers.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/cdesc-Guessers.ri new file mode 100644 index 00000000..33db8a3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Guessers/cdesc-Guessers.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/cdesc-HasModes.ri b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/cdesc-HasModes.ri new file mode 100644 index 00000000..32126d46 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/cdesc-HasModes.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/get_mode-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/get_mode-i.ri new file mode 100644 index 00000000..abbcb544 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/get_mode-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode%21-i.ri new file mode 100644 index 00000000..68512518 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode-i.ri new file mode 100644 index 00000000..8db488d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/mode-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/set_mode%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/set_mode%21-i.ri new file mode 100644 index 00000000..a49691e2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/HasModes/set_mode%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/cdesc-Indentation.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/cdesc-Indentation.ri new file mode 100644 index 00000000..da031d90 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/cdesc-Indentation.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/indentation-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/indentation-i.ri new file mode 100644 index 00000000..b83df189 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/indentation-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/reset%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/reset%21-i.ri new file mode 100644 index 00000000..af317ece Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/reset%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/starts_block-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/starts_block-i.ri new file mode 100644 index 00000000..b5944dc6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Indentation/starts_block-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/%5b%5d-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/%5b%5d-i.ri new file mode 100644 index 00000000..eab25d8f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/%5b%5d-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/cdesc-InheritableHash.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/cdesc-InheritableHash.ri new file mode 100644 index 00000000..966467af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/cdesc-InheritableHash.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/each-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/each-i.ri new file mode 100644 index 00000000..01d4a38a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/each-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/include%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/include%3f-i.ri new file mode 100644 index 00000000..dedecec2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/include%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/keys-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/keys-i.ri new file mode 100644 index 00000000..59fe6e55 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/keys-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/new-c.ri new file mode 100644 index 00000000..936692b9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/own_keys-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/own_keys-i.ri new file mode 100644 index 00000000..b7c3792c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/own_keys-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/parent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/parent-i.ri new file mode 100644 index 00000000..74ef0d41 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableHash/parent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/%3c%3c-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/%3c%3c-i.ri new file mode 100644 index 00000000..48db5c07 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/%3c%3c-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/cdesc-InheritableList.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/cdesc-InheritableList.ri new file mode 100644 index 00000000..4ce6d171 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/cdesc-InheritableList.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/each-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/each-i.ri new file mode 100644 index 00000000..fda05058 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/each-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/new-c.ri new file mode 100644 index 00000000..06e0dba2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/own_entries-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/own_entries-i.ri new file mode 100644 index 00000000..773f4f8e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/own_entries-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/parent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/parent-i.ri new file mode 100644 index 00000000..86776164 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/parent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/push-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/push-i.ri new file mode 100644 index 00000000..f33c4928 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/InheritableList/push-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/aliases-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/aliases-c.ri new file mode 100644 index 00000000..9bab0bda Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/aliases-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/all-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/all-c.ri new file mode 100644 index 00000000..4b499494 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/all-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_bool-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_bool-i.ri new file mode 100644 index 00000000..1e231a28 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_bool-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_lexer-i.ri new file mode 100644 index 00000000..dadca296 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_list-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_list-i.ri new file mode 100644 index 00000000..227080cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_list-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_string-i.ri new file mode 100644 index 00000000..ab959d09 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_token-i.ri new file mode 100644 index 00000000..cfd26edd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/as_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/assert_utf8%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/assert_utf8%21-c.ri new file mode 100644 index 00000000..e1a868f5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/assert_utf8%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/bool_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/bool_option-i.ri new file mode 100644 index 00000000..fffcc857 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/bool_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/cdesc-Lexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/cdesc-Lexer.ri new file mode 100644 index 00000000..eacb0fec Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/cdesc-Lexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-c.ri new file mode 100644 index 00000000..6d0af05d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-i.ri new file mode 100644 index 00000000..fd18c054 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/continue_lex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/debug_enabled%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/debug_enabled%3f-c.ri new file mode 100644 index 00000000..9e2ee8a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/debug_enabled%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo-c.ri new file mode 100644 index 00000000..703d1b1d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo_file-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo_file-c.ri new file mode 100644 index 00000000..37d145ee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/demo_file-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/desc-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/desc-c.ri new file mode 100644 index 00000000..659e84cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/desc-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detect%3f-c.ri new file mode 100644 index 00000000..80cddd3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detectable%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detectable%3f-c.ri new file mode 100644 index 00000000..38975e58 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/detectable%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/disable_debug%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/disable_debug%21-c.ri new file mode 100644 index 00000000..5c577eb6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/disable_debug%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/enable_debug%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/enable_debug%21-c.ri new file mode 100644 index 00000000..278c6fb5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/enable_debug%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/filenames-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/filenames-c.ri new file mode 100644 index 00000000..ce6aa383 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/filenames-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find-c.ri new file mode 100644 index 00000000..7213fa1b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find_fancy-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find_fancy-c.ri new file mode 100644 index 00000000..524a20d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/find_fancy-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess-c.ri new file mode 100644 index 00000000..ae6d96e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_filename-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_filename-c.ri new file mode 100644 index 00000000..d0856556 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_filename-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_mimetype-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_mimetype-c.ri new file mode 100644 index 00000000..e1a1c6be Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_mimetype-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_source-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_source-c.ri new file mode 100644 index 00000000..92fbadc5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guess_by_source-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guesses-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guesses-c.ri new file mode 100644 index 00000000..b1bae0e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/guesses-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/hash_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/hash_option-i.ri new file mode 100644 index 00000000..02f5d4dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/hash_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-c.ri new file mode 100644 index 00000000..6fa9712c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-i.ri new file mode 100644 index 00000000..fed3eba8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lexer_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lexer_option-i.ri new file mode 100644 index 00000000..4d2c46c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lexer_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/list_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/list_option-i.ri new file mode 100644 index 00000000..265d88ab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/list_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lookup_fancy-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lookup_fancy-c.ri new file mode 100644 index 00000000..d24e1ca3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/lookup_fancy-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/mimetypes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/mimetypes-c.ri new file mode 100644 index 00000000..4a857b58 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/mimetypes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/new-c.ri new file mode 100644 index 00000000..580cc8b0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option-c.ri new file mode 100644 index 00000000..894b32c1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option_docs-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option_docs-c.ri new file mode 100644 index 00000000..98761200 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/option_docs-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/options-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/options-i.ri new file mode 100644 index 00000000..e723e523 --- /dev/null +++ b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/options-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" options:ETI"Rouge::Lexer#options;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"-*- instance methods -*- #;T: +@fileI"lib/rouge/lexer.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Rouge::Lexer;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/register-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/register-c.ri new file mode 100644 index 00000000..d37ec4e4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/register-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/registry-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/registry-c.ri new file mode 100644 index 00000000..6a6928df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/registry-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/reset%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/reset%21-i.ri new file mode 100644 index 00000000..b16a2b39 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/reset%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/stream_tokens-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/stream_tokens-i.ri new file mode 100644 index 00000000..f87240d2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/stream_tokens-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/string_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/string_option-i.ri new file mode 100644 index 00000000..3bc3c4e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/string_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-c.ri new file mode 100644 index 00000000..88a95d82 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-i.ri new file mode 100644 index 00000000..b6b1ab42 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/tag-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/title-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/title-c.ri new file mode 100644 index 00000000..6e067901 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/title-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/token_option-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/token_option-i.ri new file mode 100644 index 00000000..089e124a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/token_option-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/with-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/with-i.ri new file mode 100644 index 00000000..3fb8cabf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexer/with-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/builtins-c.ri new file mode 100644 index 00000000..fe29851a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/cdesc-ABAP.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/cdesc-ABAP.ri new file mode 100644 index 00000000..5da7ae9a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/cdesc-ABAP.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/keywords-c.ri new file mode 100644 index 00000000..deaab86c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/new_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/new_keywords-c.ri new file mode 100644 index 00000000..784a917e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/new_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/types-c.ri new file mode 100644 index 00000000..0a5f9e8d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ABAP/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/APIBlueprint/cdesc-APIBlueprint.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/APIBlueprint/cdesc-APIBlueprint.ri new file mode 100644 index 00000000..3fc1d0b9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/APIBlueprint/cdesc-APIBlueprint.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/builtins-c.ri new file mode 100644 index 00000000..381a3192 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/cdesc-Actionscript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/cdesc-Actionscript.ri new file mode 100644 index 00000000..a6893fad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/cdesc-Actionscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/constants-c.ri new file mode 100644 index 00000000..1dff3034 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/declarations-c.ri new file mode 100644 index 00000000..13974aae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/keywords-c.ri new file mode 100644 index 00000000..c8f0792f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/reserved-c.ri new file mode 100644 index 00000000..a2f6c106 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Actionscript/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/cdesc-Ada.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/cdesc-Ada.ri new file mode 100644 index 00000000..524b62aa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/cdesc-Ada.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/idents-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/idents-c.ri new file mode 100644 index 00000000..ea1c91d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ada/idents-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/cdesc-Apache.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/cdesc-Apache.ri new file mode 100644 index 00000000..51c83ff0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/cdesc-Apache.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/directives-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/directives-c.ri new file mode 100644 index 00000000..db0c160e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/directives-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/name_for_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/name_for_token-i.ri new file mode 100644 index 00000000..86dfbd6f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/name_for_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/sections-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/sections-c.ri new file mode 100644 index 00000000..0a9d32e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/sections-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/values-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/values-c.ri new file mode 100644 index 00000000..5dac3ee9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apache/values-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/cdesc-Apex.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/cdesc-Apex.ri new file mode 100644 index 00000000..bca5f19d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/cdesc-Apex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/constants-c.ri new file mode 100644 index 00000000..c128a0af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/declarations-c.ri new file mode 100644 index 00000000..b9202bdf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/keywords-c.ri new file mode 100644 index 00000000..247ad49c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/soql-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/soql-c.ri new file mode 100644 index 00000000..dcdecfe5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/soql-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/types-c.ri new file mode 100644 index 00000000..969f363b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Apex/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/builtins-c.ri new file mode 100644 index 00000000..5d449a62 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/cdesc-AppleScript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/cdesc-AppleScript.ri new file mode 100644 index 00000000..0e5850b8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/cdesc-AppleScript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/classes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/classes-c.ri new file mode 100644 index 00000000..5d61709e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/classes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/commands-c.ri new file mode 100644 index 00000000..924f425e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/controls-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/controls-c.ri new file mode 100644 index 00000000..1a0f4c41 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/controls-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/declarations-c.ri new file mode 100644 index 00000000..379fac83 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/handler_params-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/handler_params-c.ri new file mode 100644 index 00000000..5533b47a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/handler_params-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/literals-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/literals-c.ri new file mode 100644 index 00000000..ae84bfed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/literals-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/operators-c.ri new file mode 100644 index 00000000..29b1d13e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/references-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/references-c.ri new file mode 100644 index 00000000..4f260fa7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/references-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/reserved-c.ri new file mode 100644 index 00000000..1bed6b05 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_classes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_classes-c.ri new file mode 100644 index 00000000..ff13b7d9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_classes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_commands-c.ri new file mode 100644 index 00000000..71a3bfee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_events-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_events-c.ri new file mode 100644 index 00000000..260e000b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_events-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_properties-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_properties-c.ri new file mode 100644 index 00000000..db7add32 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/AppleScript/studio_properties-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/builtin-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/builtin-c.ri new file mode 100644 index 00000000..381da2ce Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/builtin-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/cdesc-ArmAsm.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/cdesc-ArmAsm.ri new file mode 100644 index 00000000..d94a5eaa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/cdesc-ArmAsm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/file_directive-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/file_directive-c.ri new file mode 100644 index 00000000..6c1934cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/file_directive-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/general_directive-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/general_directive-c.ri new file mode 100644 index 00000000..2d6f4b18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/general_directive-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/operator-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/operator-c.ri new file mode 100644 index 00000000..3439f3cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/operator-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/preproc_keyword-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/preproc_keyword-c.ri new file mode 100644 index 00000000..a72bd196 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/preproc_keyword-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/shift_or_condition-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/shift_or_condition-c.ri new file mode 100644 index 00000000..c280e3fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ArmAsm/shift_or_condition-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/cdesc-Augeas.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/cdesc-Augeas.ri new file mode 100644 index 00000000..1b4676c0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/cdesc-Augeas.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/reserved-c.ri new file mode 100644 index 00000000..b279875e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Augeas/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/builtins-c.ri new file mode 100644 index 00000000..697bcfa9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/cdesc-Awk.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/cdesc-Awk.ri new file mode 100644 index 00000000..3c666a11 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/cdesc-Awk.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/constants-c.ri new file mode 100644 index 00000000..d3fde80b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/declarations-c.ri new file mode 100644 index 00000000..38aafcb4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/detect%3f-c.ri new file mode 100644 index 00000000..a939c5bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/keywords-c.ri new file mode 100644 index 00000000..68711860 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/reserved-c.ri new file mode 100644 index 00000000..ea842154 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Awk/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/cdesc-BBCBASIC.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/cdesc-BBCBASIC.ri new file mode 100644 index 00000000..223b3dcc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/cdesc-BBCBASIC.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/constant-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/constant-c.ri new file mode 100644 index 00000000..c918a404 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/constant-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/function-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/function-c.ri new file mode 100644 index 00000000..3e1df642 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/function-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/operator-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/operator-c.ri new file mode 100644 index 00000000..5d993344 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/operator-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/punctuation-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/punctuation-c.ri new file mode 100644 index 00000000..63a45324 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/punctuation-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/statement-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/statement-c.ri new file mode 100644 index 00000000..c90b9e7a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BBCBASIC/statement-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/cdesc-BIML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/cdesc-BIML.ri new file mode 100644 index 00000000..786e64de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/cdesc-BIML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/detect%3f-c.ri new file mode 100644 index 00000000..b407b525 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BIML/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BPF/cdesc-BPF.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BPF/cdesc-BPF.ri new file mode 100644 index 00000000..a37f3dea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BPF/cdesc-BPF.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/attributes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/attributes-c.ri new file mode 100644 index 00000000..7ba56626 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/attributes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/builtin_commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/builtin_commands-c.ri new file mode 100644 index 00000000..37d61a50 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/builtin_commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/cdesc-Batchfile.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/cdesc-Batchfile.ri new file mode 100644 index 00000000..281bd190 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/cdesc-Batchfile.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/devices-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/devices-c.ri new file mode 100644 index 00000000..95c800aa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/devices-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/keywords-c.ri new file mode 100644 index 00000000..0506ac12 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/operator_words-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/operator_words-c.ri new file mode 100644 index 00000000..5a1920e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/operator_words-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/other_commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/other_commands-c.ri new file mode 100644 index 00000000..ee59fdc4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Batchfile/other_commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BibTeX/cdesc-BibTeX.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BibTeX/cdesc-BibTeX.ri new file mode 100644 index 00000000..bea7f214 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/BibTeX/cdesc-BibTeX.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/cdesc-Bicep.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/cdesc-Bicep.ri new file mode 100644 index 00000000..e7837c6a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/cdesc-Bicep.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/datatypes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/datatypes-c.ri new file mode 100644 index 00000000..50c48d44 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/datatypes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/functions-c.ri new file mode 100644 index 00000000..fcbb61ac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/keywords-c.ri new file mode 100644 index 00000000..ddb814cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bicep/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brainfuck/cdesc-Brainfuck.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brainfuck/cdesc-Brainfuck.ri new file mode 100644 index 00000000..6e4b7d54 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brainfuck/cdesc-Brainfuck.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/builtins-c.ri new file mode 100644 index 00000000..e4e1ac18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/cdesc-Brightscript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/cdesc-Brightscript.ri new file mode 100644 index 00000000..c48862ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/cdesc-Brightscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved-c.ri new file mode 100644 index 00000000..112a97c9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved_unsupported-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved_unsupported-c.ri new file mode 100644 index 00000000..30b4a2ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_reserved_unsupported-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_type-c.ri new file mode 100644 index 00000000..d7d80d88 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/keyword_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/name_builtin-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/name_builtin-c.ri new file mode 100644 index 00000000..bf87b947 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/name_builtin-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/operator_word-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/operator_word-c.ri new file mode 100644 index 00000000..9979dd2f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Brightscript/operator_word-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bsl/cdesc-Bsl.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bsl/cdesc-Bsl.ri new file mode 100644 index 00000000..e9cdec41 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Bsl/cdesc-Bsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/builtins-c.ri new file mode 100644 index 00000000..9f0af0df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/cdesc-C.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/cdesc-C.ri new file mode 100644 index 00000000..b40fdf63 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/cdesc-C.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords-c.ri new file mode 100644 index 00000000..c9ba6faa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords_type-c.ri new file mode 100644 index 00000000..ae3378a6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/reserved-c.ri new file mode 100644 index 00000000..52b65b18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/C/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/cdesc-CMHG.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/cdesc-CMHG.ri new file mode 100644 index 00000000..2e1cc624 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/cdesc-CMHG.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/preproc_keyword-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/preproc_keyword-c.ri new file mode 100644 index 00000000..cbeead87 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMHG/preproc_keyword-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMake/cdesc-CMake.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMake/cdesc-CMake.ri new file mode 100644 index 00000000..81f71112 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CMake/cdesc-CMake.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/cdesc-COBOL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/cdesc-COBOL.ri new file mode 100644 index 00000000..8014cc24 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/cdesc-COBOL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/divisions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/divisions-c.ri new file mode 100644 index 00000000..baf2adf7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/divisions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/keywords-c.ri new file mode 100644 index 00000000..beeab393 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/sections-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/sections-c.ri new file mode 100644 index 00000000..737adf49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/COBOL/sections-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/builtins-c.ri new file mode 100644 index 00000000..2bf5d88f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/cdesc-CSS.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/cdesc-CSS.ri new file mode 100644 index 00000000..2c9d6dfd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/cdesc-CSS.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/colors-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/colors-c.ri new file mode 100644 index 00000000..a826d543 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/colors-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/functions-c.ri new file mode 100644 index 00000000..a656e9b5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/properties-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/properties-c.ri new file mode 100644 index 00000000..c73d649c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/properties-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/vendor_prefixes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/vendor_prefixes-c.ri new file mode 100644 index 00000000..f3722fe9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSS/vendor_prefixes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSVS/cdesc-CSVS.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSVS/cdesc-CSVS.ri new file mode 100644 index 00000000..a46da46e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSVS/cdesc-CSVS.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cdesc-CSharp.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cdesc-CSharp.ri new file mode 100644 index 00000000..4cf6ccc9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cdesc-CSharp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cpp_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cpp_keywords-c.ri new file mode 100644 index 00000000..3a1ad54b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/cpp_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords-c.ri new file mode 100644 index 00000000..793cc801 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords_type-c.ri new file mode 100644 index 00000000..d7742509 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CSharp/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/cdesc-CUDA.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/cdesc-CUDA.ri new file mode 100644 index 00000000..ce1ffa68 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/cdesc-CUDA.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords-c.ri new file mode 100644 index 00000000..d1510090 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords_type-c.ri new file mode 100644 index 00000000..59617e35 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CUDA/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ceylon/cdesc-Ceylon.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ceylon/cdesc-Ceylon.ri new file mode 100644 index 00000000..f14e84cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ceylon/cdesc-Ceylon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/cdesc-Cfscript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/cdesc-Cfscript.ri new file mode 100644 index 00000000..5ff47bf6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/cdesc-Cfscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/declarations-c.ri new file mode 100644 index 00000000..b243160d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/keywords-c.ri new file mode 100644 index 00000000..dc9058df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/types-c.ri new file mode 100644 index 00000000..a4a679a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cfscript/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CiscoIos/cdesc-CiscoIos.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CiscoIos/cdesc-CiscoIos.ri new file mode 100644 index 00000000..ecdfda18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CiscoIos/cdesc-CiscoIos.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/cdesc-Clean.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/cdesc-Clean.ri new file mode 100644 index 00000000..f461e77f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/cdesc-Clean.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/keywords-c.ri new file mode 100644 index 00000000..94e38ee7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clean/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/builtins-c.ri new file mode 100644 index 00000000..e0e1af17 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/cdesc-Clojure.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/cdesc-Clojure.ri new file mode 100644 index 00000000..419d463b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/cdesc-Clojure.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/keywords-c.ri new file mode 100644 index 00000000..87b6d584 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/name_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/name_token-i.ri new file mode 100644 index 00000000..273c2951 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Clojure/name_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Codeowners/cdesc-Codeowners.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Codeowners/cdesc-Codeowners.ri new file mode 100644 index 00000000..4558c1e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Codeowners/cdesc-Codeowners.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/builtins-c.ri new file mode 100644 index 00000000..c51b35ca Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/cdesc-Coffeescript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/cdesc-Coffeescript.ri new file mode 100644 index 00000000..67047c47 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/cdesc-Coffeescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/constants-c.ri new file mode 100644 index 00000000..7f512d18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/detect%3f-c.ri new file mode 100644 index 00000000..81634b47 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/keywords-c.ri new file mode 100644 index 00000000..763d94fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/reserved-c.ri new file mode 100644 index 00000000..bc5a3d46 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coffeescript/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CommonLisp/cdesc-CommonLisp.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CommonLisp/cdesc-CommonLisp.ri new file mode 100644 index 00000000..9ea6d4e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/CommonLisp/cdesc-CommonLisp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Conf/cdesc-Conf.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Conf/cdesc-Conf.ri new file mode 100644 index 00000000..8fecebe5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Conf/cdesc-Conf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/allow_comments%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/allow_comments%3f-i.ri new file mode 100644 index 00000000..0170c227 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/allow_comments%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/cdesc-ConsoleLexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/cdesc-ConsoleLexer.ri new file mode 100644 index 00000000..bfea0ef2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/cdesc-ConsoleLexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/comment_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/comment_regex-i.ri new file mode 100644 index 00000000..df2278aa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/comment_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/end_chars-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/end_chars-i.ri new file mode 100644 index 00000000..41ff72fe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/end_chars-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/error_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/error_regex-i.ri new file mode 100644 index 00000000..d22062db Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/error_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/lang_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/lang_lexer-i.ri new file mode 100644 index 00000000..00995107 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/lang_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/line_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/line_regex-i.ri new file mode 100644 index 00000000..dd13e6f6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/line_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/new-c.ri new file mode 100644 index 00000000..66a17846 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/output_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/output_lexer-i.ri new file mode 100644 index 00000000..46bbef40 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/output_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/process_line-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/process_line-i.ri new file mode 100644 index 00000000..4823cb3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/process_line-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_prefix_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_prefix_regex-i.ri new file mode 100644 index 00000000..75afee64 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_prefix_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_regex-i.ri new file mode 100644 index 00000000..9aa191d5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/prompt_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/stream_tokens-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/stream_tokens-i.ri new file mode 100644 index 00000000..b7bcce8e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ConsoleLexer/stream_tokens-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/cdesc-Coq.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/cdesc-Coq.ri new file mode 100644 index 00000000..19038a3b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/cdesc-Coq.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/classify-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/classify-c.ri new file mode 100644 index 00000000..fb69446e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/classify-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/coq-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/coq-c.ri new file mode 100644 index 00000000..fa53ffe7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/coq-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/gallina-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/gallina-c.ri new file mode 100644 index 00000000..1356a629 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/gallina-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/ltac-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/ltac-c.ri new file mode 100644 index 00000000..76075cc2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/ltac-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/tacticals-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/tacticals-c.ri new file mode 100644 index 00000000..6bb75cd2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/tacticals-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/terminators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/terminators-c.ri new file mode 100644 index 00000000..389250fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Coq/terminators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/cdesc-Cpp.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/cdesc-Cpp.ri new file mode 100644 index 00000000..49d13252 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/cdesc-Cpp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords-c.ri new file mode 100644 index 00000000..07d9e5e6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords_type-c.ri new file mode 100644 index 00000000..d226bbbd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/reserved-c.ri new file mode 100644 index 00000000..6e657216 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cpp/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/cdesc-Crystal.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/cdesc-Crystal.ri new file mode 100644 index 00000000..7e79d570 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/cdesc-Crystal.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/detect%3f-c.ri new file mode 100644 index 00000000..09d74ed3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Crystal/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/cdesc-Cypher.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/cdesc-Cypher.ri new file mode 100644 index 00000000..e028a773 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/cdesc-Cypher.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/functions-c.ri new file mode 100644 index 00000000..42b9b13d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/keywords-c.ri new file mode 100644 index 00000000..5a0e5e98 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/predicates-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/predicates-c.ri new file mode 100644 index 00000000..ad9f2ce0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cypher/predicates-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/c_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/c_keywords-c.ri new file mode 100644 index 00000000..6f8ba32c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/c_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/cdesc-Cython.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/cdesc-Cython.ri new file mode 100644 index 00000000..47332811 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/cdesc-Cython.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/keywords-c.ri new file mode 100644 index 00000000..5ec398f3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/new-c.ri new file mode 100644 index 00000000..43d3af04 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Cython/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/D/cdesc-D.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/D/cdesc-D.ri new file mode 100644 index 00000000..3c04c529 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/D/cdesc-D.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dafny/cdesc-Dafny.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dafny/cdesc-Dafny.ri new file mode 100644 index 00000000..f6014fc2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dafny/cdesc-Dafny.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dart/cdesc-Dart.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dart/cdesc-Dart.ri new file mode 100644 index 00000000..fe0871d2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dart/cdesc-Dart.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/cdesc-Datastudio.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/cdesc-Datastudio.ri new file mode 100644 index 00000000..e443080d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/cdesc-Datastudio.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/sql_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/sql_keywords-c.ri new file mode 100644 index 00000000..0b60e1ec Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Datastudio/sql_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/cdesc-Diff.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/cdesc-Diff.ri new file mode 100644 index 00000000..6131270e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/cdesc-Diff.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/detect%3f-c.ri new file mode 100644 index 00000000..938797ee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Diff/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Digdag/cdesc-Digdag.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Digdag/cdesc-Digdag.ri new file mode 100644 index 00000000..84f872cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Digdag/cdesc-Digdag.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Docker/cdesc-Docker.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Docker/cdesc-Docker.ri new file mode 100644 index 00000000..26aaf749 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Docker/cdesc-Docker.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dot/cdesc-Dot.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dot/cdesc-Dot.ri new file mode 100644 index 00000000..f608e9f0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Dot/cdesc-Dot.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/cdesc-ECL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/cdesc-ECL.ri new file mode 100644 index 00000000..6217efab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/cdesc-ECL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_first-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_first-c.ri new file mode 100644 index 00000000..287db8c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_first-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_second-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_second-c.ri new file mode 100644 index 00000000..8347c401 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/class_second-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/functions-c.ri new file mode 100644 index 00000000..c3864785 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/keywords-c.ri new file mode 100644 index 00000000..df699e1d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/template-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/template-c.ri new file mode 100644 index 00000000..56acfee1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/template-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/type-c.ri new file mode 100644 index 00000000..efb2d8a8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/typed-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/typed-c.ri new file mode 100644 index 00000000..0a436340 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ECL/typed-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/cdesc-EEX.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/cdesc-EEX.ri new file mode 100644 index 00000000..90c07541 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/cdesc-EEX.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/new-c.ri new file mode 100644 index 00000000..254a311e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EEX/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/cdesc-EPP.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/cdesc-EPP.ri new file mode 100644 index 00000000..1df35e53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/cdesc-EPP.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/new-c.ri new file mode 100644 index 00000000..a2b14d42 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/EPP/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/cdesc-ERB.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/cdesc-ERB.ri new file mode 100644 index 00000000..bdec098e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/cdesc-ERB.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/new-c.ri new file mode 100644 index 00000000..8651b233 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ERB/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Eiffel/cdesc-Eiffel.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Eiffel/cdesc-Eiffel.ri new file mode 100644 index 00000000..3ee71313 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Eiffel/cdesc-Eiffel.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/cdesc-Elixir.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/cdesc-Elixir.ri new file mode 100644 index 00000000..d759e216 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/cdesc-Elixir.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/detect%3f-c.ri new file mode 100644 index 00000000..037564c9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elixir/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elm/cdesc-Elm.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elm/cdesc-Elm.ri new file mode 100644 index 00000000..6cc7fd5f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Elm/cdesc-Elm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Email/cdesc-Email.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Email/cdesc-Email.ri new file mode 100644 index 00000000..912e9ca3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Email/cdesc-Email.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Erlang/cdesc-Erlang.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Erlang/cdesc-Erlang.ri new file mode 100644 index 00000000..273cec9a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Erlang/cdesc-Erlang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/cdesc-Escape.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/cdesc-Escape.ri new file mode 100644 index 00000000..4ab268f9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/cdesc-Escape.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/end-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/end-i.ri new file mode 100644 index 00000000..8acc709e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/end-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/lang-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/lang-i.ri new file mode 100644 index 00000000..ade908fa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/lang-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/new-c.ri new file mode 100644 index 00000000..42cf2939 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/start-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/start-i.ri new file mode 100644 index 00000000..cc48b511 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/start-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/stream_tokens-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/stream_tokens-i.ri new file mode 100644 index 00000000..c241515d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/stream_tokens-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_end_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_end_regex-i.ri new file mode 100644 index 00000000..a609afd0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_end_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_start_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_start_regex-i.ri new file mode 100644 index 00000000..f3a60201 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Escape/to_start_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/cdesc-FSharp.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/cdesc-FSharp.ri new file mode 100644 index 00000000..1657feda Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/cdesc-FSharp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keyopts-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keyopts-c.ri new file mode 100644 index 00000000..9dc62a63 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keyopts-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keywords-c.ri new file mode 100644 index 00000000..247b9165 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/primitives-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/primitives-c.ri new file mode 100644 index 00000000..5e0da7de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/primitives-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/word_operators-c.ri new file mode 100644 index 00000000..933de49f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FSharp/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/builtins-c.ri new file mode 100644 index 00000000..c4dc7f71 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/cdesc-Factor.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/cdesc-Factor.ri new file mode 100644 index 00000000..d5035108 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/cdesc-Factor.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/detect%3f-c.ri new file mode 100644 index 00000000..a71bdd90 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Factor/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fluent/cdesc-Fluent.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fluent/cdesc-Fluent.ri new file mode 100644 index 00000000..debdabbb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fluent/cdesc-Fluent.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/cdesc-Fortran.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/cdesc-Fortran.ri new file mode 100644 index 00000000..ce6fe6ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/cdesc-Fortran.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/intrinsics-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/intrinsics-c.ri new file mode 100644 index 00000000..ed708904 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/intrinsics-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/keywords-c.ri new file mode 100644 index 00000000..9183d0fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/types-c.ri new file mode 100644 index 00000000..70720e93 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Fortran/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/attributes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/attributes-c.ri new file mode 100644 index 00000000..72c88ef2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/attributes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/builtins-c.ri new file mode 100644 index 00000000..315d62e4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/cdesc-FreeFEM.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/cdesc-FreeFEM.ri new file mode 100644 index 00000000..a2160c22 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/cdesc-FreeFEM.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords-c.ri new file mode 100644 index 00000000..de2ec0e4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords_type-c.ri new file mode 100644 index 00000000..8523d0f9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/reserved-c.ri new file mode 100644 index 00000000..9ec8a04f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/FreeFEM/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins-c.ri new file mode 100644 index 00000000..00d8f3c3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins_type-c.ri new file mode 100644 index 00000000..301b5d81 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/builtins_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/cdesc-GDScript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/cdesc-GDScript.ri new file mode 100644 index 00000000..90c977c2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/cdesc-GDScript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords-c.ri new file mode 100644 index 00000000..b291a46e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords_reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords_reserved-c.ri new file mode 100644 index 00000000..7b4f5657 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GDScript/keywords_reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCmm/cdesc-GHCCmm.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCmm/cdesc-GHCCmm.ri new file mode 100644 index 00000000..78518da0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCmm/cdesc-GHCCmm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCore/cdesc-GHCCore.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCore/cdesc-GHCCore.ri new file mode 100644 index 00000000..8822b91e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GHCCore/cdesc-GHCCore.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/cdesc-Gherkin.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/cdesc-Gherkin.ri new file mode 100644 index 00000000..187a6f23 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/cdesc-Gherkin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/detect%3f-c.ri new file mode 100644 index 00000000..d850c421 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/keywords-c.ri new file mode 100644 index 00000000..9a5b7a34 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/step_regex-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/step_regex-c.ri new file mode 100644 index 00000000..624000cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gherkin/step_regex-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/cdesc-Gjs.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/cdesc-Gjs.ri new file mode 100644 index 00000000..13da9d5a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/cdesc-Gjs.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/new-c.ri new file mode 100644 index 00000000..04f140a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gjs/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/builtins-c.ri new file mode 100644 index 00000000..45074c11 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/cdesc-Glsl.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/cdesc-Glsl.ri new file mode 100644 index 00000000..68cd7512 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/cdesc-Glsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords-c.ri new file mode 100644 index 00000000..bf3834f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords_type-c.ri new file mode 100644 index 00000000..59edeb87 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/reserved-c.ri new file mode 100644 index 00000000..52e1c874 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Glsl/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Go/cdesc-Go.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Go/cdesc-Go.ri new file mode 100644 index 00000000..511cbb51 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Go/cdesc-Go.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/cdesc-Gradle.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/cdesc-Gradle.ri new file mode 100644 index 00000000..0f6b9d8b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/cdesc-Gradle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/keywords-c.ri new file mode 100644 index 00000000..f8ee75b1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/types-c.ri new file mode 100644 index 00000000..15a929cc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gradle/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GraphQL/cdesc-GraphQL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GraphQL/cdesc-GraphQL.ri new file mode 100644 index 00000000..22924590 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/GraphQL/cdesc-GraphQL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/cdesc-Groovy.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/cdesc-Groovy.ri new file mode 100644 index 00000000..b83ebba4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/cdesc-Groovy.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/constants-c.ri new file mode 100644 index 00000000..797b0b19 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/declarations-c.ri new file mode 100644 index 00000000..dce8f26c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/detect%3f-c.ri new file mode 100644 index 00000000..3e198447 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/keywords-c.ri new file mode 100644 index 00000000..0ce600ae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/types-c.ri new file mode 100644 index 00000000..bd88e842 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Groovy/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/cdesc-Gts.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/cdesc-Gts.ri new file mode 100644 index 00000000..47f2112c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/cdesc-Gts.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/new-c.ri new file mode 100644 index 00000000..d79fb567 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Gts/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/builtins-c.ri new file mode 100644 index 00000000..b4b395b5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/cdesc-HLSL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/cdesc-HLSL.ri new file mode 100644 index 00000000..03b7f68e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/cdesc-HLSL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords-c.ri new file mode 100644 index 00000000..7441c6a1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords_type-c.ri new file mode 100644 index 00000000..eee24c75 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/reserved-c.ri new file mode 100644 index 00000000..065d834b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HLSL/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HOCON/cdesc-HOCON.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HOCON/cdesc-HOCON.ri new file mode 100644 index 00000000..156e884d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HOCON/cdesc-HOCON.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/cdesc-HQL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/cdesc-HQL.ri new file mode 100644 index 00000000..8fbc44cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/cdesc-HQL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords-c.ri new file mode 100644 index 00000000..fa5c79f4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords_type-c.ri new file mode 100644 index 00000000..00f9482e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HQL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/cdesc-HTML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/cdesc-HTML.ri new file mode 100644 index 00000000..157dbc05 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/cdesc-HTML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/detect%3f-c.ri new file mode 100644 index 00000000..f5ae8c5c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTML/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/cdesc-HTTP.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/cdesc-HTTP.ri new file mode 100644 index 00000000..53dbb5de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/cdesc-HTTP.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/content_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/content_lexer-i.ri new file mode 100644 index 00000000..8de9103b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/content_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/guess_content_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/guess_content_lexer-i.ri new file mode 100644 index 00000000..30e441fe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/guess_content_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/http_methods-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/http_methods-c.ri new file mode 100644 index 00000000..8629d4ce Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HTTP/http_methods-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/cdesc-Hack.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/cdesc-Hack.ri new file mode 100644 index 00000000..dea943db Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/cdesc-Hack.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/detect%3f-c.ri new file mode 100644 index 00000000..6640046a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/keywords-c.ri new file mode 100644 index 00000000..aed44f43 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hack/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/cdesc-Haml.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/cdesc-Haml.ri new file mode 100644 index 00000000..a9c90988 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/cdesc-Haml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/filters-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/filters-i.ri new file mode 100644 index 00000000..93c3ce64 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/filters-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/html-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/html-i.ri new file mode 100644 index 00000000..8c4bcd06 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/html-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/new-c.ri new file mode 100644 index 00000000..41d81b48 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby%21-i.ri new file mode 100644 index 00000000..598824e9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby-i.ri new file mode 100644 index 00000000..f5ba7e39 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haml/ruby-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Handlebars/cdesc-Handlebars.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Handlebars/cdesc-Handlebars.ri new file mode 100644 index 00000000..f1d9c9dc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Handlebars/cdesc-Handlebars.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/cdesc-Haskell.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/cdesc-Haskell.ri new file mode 100644 index 00000000..58497a5a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/cdesc-Haskell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/detect%3f-c.ri new file mode 100644 index 00000000..11225975 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haskell/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/builtins-c.ri new file mode 100644 index 00000000..c1fb9ade Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/cdesc-Haxe.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/cdesc-Haxe.ri new file mode 100644 index 00000000..398b0d38 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/cdesc-Haxe.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/constants-c.ri new file mode 100644 index 00000000..0a261494 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/declarations-c.ri new file mode 100644 index 00000000..0144908b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/detect%3f-c.ri new file mode 100644 index 00000000..6d4d338a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/imports-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/imports-c.ri new file mode 100644 index 00000000..2c700e22 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/imports-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/keywords-c.ri new file mode 100644 index 00000000..dfc8aaba Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/reserved-c.ri new file mode 100644 index 00000000..64637fa1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Haxe/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/builtins-c.ri new file mode 100644 index 00000000..b5ca9224 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/cdesc-Hcl.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/cdesc-Hcl.ri new file mode 100644 index 00000000..339d4761 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/cdesc-Hcl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/constants-c.ri new file mode 100644 index 00000000..58b2102a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/declarations-c.ri new file mode 100644 index 00000000..89fa47d0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/keywords-c.ri new file mode 100644 index 00000000..eaed46a1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/reserved-c.ri new file mode 100644 index 00000000..176d1f99 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Hcl/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/builtins-c.ri new file mode 100644 index 00000000..5d1aeebb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/cdesc-HyLang.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/cdesc-HyLang.ri new file mode 100644 index 00000000..0a09368c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/cdesc-HyLang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/keywords-c.ri new file mode 100644 index 00000000..d019cb56 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/name_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/name_token-i.ri new file mode 100644 index 00000000..d516cea2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/HyLang/name_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/cdesc-IDLang.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/cdesc-IDLang.ri new file mode 100644 index 00000000..66ffedcc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/cdesc-IDLang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/conditionals-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/conditionals-c.ri new file mode 100644 index 00000000..e8879543 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/conditionals-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/decorators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/decorators-c.ri new file mode 100644 index 00000000..9088a8ce Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/decorators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/exec_unit-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/exec_unit-c.ri new file mode 100644 index 00000000..6be1e183 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/exec_unit-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/keywords-c.ri new file mode 100644 index 00000000..471dff76 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/operators-c.ri new file mode 100644 index 00000000..97d9ffa0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/routines-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/routines-c.ri new file mode 100644 index 00000000..8ba8348d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/routines-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/standalone_statements-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/standalone_statements-c.ri new file mode 100644 index 00000000..d3ab9753 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IDLang/standalone_statements-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/INI/cdesc-INI.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/INI/cdesc-INI.ri new file mode 100644 index 00000000..9f54b96b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/INI/cdesc-INI.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/builtins-c.ri new file mode 100644 index 00000000..30f59c5c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/cdesc-IO.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/cdesc-IO.ri new file mode 100644 index 00000000..32532262 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/cdesc-IO.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/constants-c.ri new file mode 100644 index 00000000..6e3ae495 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/detect%3f-c.ri new file mode 100644 index 00000000..e28db5b5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IO/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/allow_comments%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/allow_comments%3f-i.ri new file mode 100644 index 00000000..fa40fd70 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/allow_comments%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/cdesc-IRBLexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/cdesc-IRBLexer.ri new file mode 100644 index 00000000..e61511c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/cdesc-IRBLexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/lang_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/lang_lexer-i.ri new file mode 100644 index 00000000..a767a1f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/lang_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/output_lexer-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/output_lexer-i.ri new file mode 100644 index 00000000..104634f2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/output_lexer-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/prompt_regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/prompt_regex-i.ri new file mode 100644 index 00000000..a366c3a4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBLexer/prompt_regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBOutputLexer/cdesc-IRBOutputLexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBOutputLexer/cdesc-IRBOutputLexer.ri new file mode 100644 index 00000000..48d9e3c4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IRBOutputLexer/cdesc-IRBOutputLexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/builtins-c.ri new file mode 100644 index 00000000..203a8654 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/cdesc-ISBL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/cdesc-ISBL.ri new file mode 100644 index 00000000..92737bf8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/cdesc-ISBL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/constants-c.ri new file mode 100644 index 00000000..80675d2a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/globals-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/globals-c.ri new file mode 100644 index 00000000..dfac19e3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/globals-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/interfaces-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/interfaces-c.ri new file mode 100644 index 00000000..5ea028db Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/interfaces-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/keywords-c.ri new file mode 100644 index 00000000..f6c554f9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ISBL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/ascii-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/ascii-c.ri new file mode 100644 index 00000000..2c1180c4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/ascii-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/cdesc-Idris.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/cdesc-Idris.ri new file mode 100644 index 00000000..77f2644e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/cdesc-Idris.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/prelude_functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/prelude_functions-c.ri new file mode 100644 index 00000000..4872a07b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/prelude_functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/reserved_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/reserved_keywords-c.ri new file mode 100644 index 00000000..65055ec7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Idris/reserved_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/cdesc-IecST.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/cdesc-IecST.ri new file mode 100644 index 00000000..1df64781 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/cdesc-IecST.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/keywords-c.ri new file mode 100644 index 00000000..8eb1e5a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/literals-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/literals-c.ri new file mode 100644 index 00000000..7141b964 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/literals-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/operators-c.ri new file mode 100644 index 00000000..3226edfe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/types-c.ri new file mode 100644 index 00000000..ecd3f174 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IecST/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/cdesc-IgorPro.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/cdesc-IgorPro.ri new file mode 100644 index 00000000..d79fd00b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/cdesc-IgorPro.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorConstants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorConstants-c.ri new file mode 100644 index 00000000..6a04a91c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorConstants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorDeclarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorDeclarations-c.ri new file mode 100644 index 00000000..2a7b527a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorDeclarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorFunction-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorFunction-c.ri new file mode 100644 index 00000000..197667b8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorFunction-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorOperation-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorOperation-c.ri new file mode 100644 index 00000000..a601be7f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/igorOperation-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/keywords-c.ri new file mode 100644 index 00000000..fcdfdd8e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/object_name-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/object_name-c.ri new file mode 100644 index 00000000..57621713 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/object_name-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/preprocessor-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/preprocessor-c.ri new file mode 100644 index 00000000..48e82406 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/IgorPro/preprocessor-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/cdesc-Isabelle.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/cdesc-Isabelle.ri new file mode 100644 index 00000000..8f995db9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/cdesc-Isabelle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_abandon_proof-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_abandon_proof-c.ri new file mode 100644 index 00000000..593340c4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_abandon_proof-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_diag-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_diag-c.ri new file mode 100644 index 00000000..5b11aabd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_diag-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_minor-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_minor-c.ri new file mode 100644 index 00000000..bdebd7a3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_minor-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm-c.ri new file mode 100644 index 00000000..4dfc95d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm_goal-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm_goal-c.ri new file mode 100644 index 00000000..58dcc211 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_asm_goal-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_block-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_block-c.ri new file mode 100644 index 00000000..4d906247 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_block-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_chain-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_chain-c.ri new file mode 100644 index 00000000..7bd9e402 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_chain-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_decl-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_decl-c.ri new file mode 100644 index 00000000..cf50756b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_decl-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_goal-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_goal-c.ri new file mode 100644 index 00000000..cff94586 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_goal-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_script-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_script-c.ri new file mode 100644 index 00000000..23baeada Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_proof_script-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_qed-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_qed-c.ri new file mode 100644 index 00000000..ad39b4fb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_qed-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_section-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_section-c.ri new file mode 100644 index 00000000..6f041488 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_section-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_subsection-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_subsection-c.ri new file mode 100644 index 00000000..906f0ceb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_subsection-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_decl-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_decl-c.ri new file mode 100644 index 00000000..f9503144 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_decl-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_goal-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_goal-c.ri new file mode 100644 index 00000000..073cdf3f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_goal-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_script-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_script-c.ri new file mode 100644 index 00000000..0a352fac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_theory_script-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_thy-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_thy-c.ri new file mode 100644 index 00000000..52b0ef8f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/keyword_thy-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/word-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/word-i.ri new file mode 100644 index 00000000..bb1cb4b3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Isabelle/word-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/cdesc-J.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/cdesc-J.ri new file mode 100644 index 00000000..dac445d5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/cdesc-J.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words-c.ri new file mode 100644 index 00000000..b2cae95e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words_id-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words_id-c.ri new file mode 100644 index 00000000..1915b074 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/control_words_id-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/inflection_list-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/inflection_list-c.ri new file mode 100644 index 00000000..4c192d33 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/inflection_list-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive-c.ri new file mode 100644 index 00000000..dd3d1171 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive_table-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive_table-c.ri new file mode 100644 index 00000000..67ad1274 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/primitive_table-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/token_map-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/token_map-c.ri new file mode 100644 index 00000000..e54b16c9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/J/token_map-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSL/cdesc-JSL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSL/cdesc-JSL.ri new file mode 100644 index 00000000..ec359a31 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSL/cdesc-JSL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON/cdesc-JSON.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON/cdesc-JSON.ri new file mode 100644 index 00000000..2e96c022 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON/cdesc-JSON.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON5/cdesc-JSON5.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON5/cdesc-JSON5.ri new file mode 100644 index 00000000..ac78e076 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSON5/cdesc-JSON5.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSONDOC/cdesc-JSONDOC.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSONDOC/cdesc-JSONDOC.ri new file mode 100644 index 00000000..bab3fe8e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSONDOC/cdesc-JSONDOC.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/cdesc-JSP.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/cdesc-JSP.ri new file mode 100644 index 00000000..44a2fbcf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/cdesc-JSP.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/new-c.ri new file mode 100644 index 00000000..6cdfb7dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSP/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSX/cdesc-JSX.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSX/cdesc-JSX.ri new file mode 100644 index 00000000..6198bdcb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/JSX/cdesc-JSX.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/bundled-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/bundled-c.ri new file mode 100644 index 00000000..017b2cdd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/bundled-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/cdesc-Janet.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/cdesc-Janet.ri new file mode 100644 index 00000000..98089695 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/cdesc-Janet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/name_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/name_token-i.ri new file mode 100644 index 00000000..7e4dfc3f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/name_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/specials-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/specials-c.ri new file mode 100644 index 00000000..c21e2ab8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Janet/specials-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Java/cdesc-Java.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Java/cdesc-Java.ri new file mode 100644 index 00000000..49365b40 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Java/cdesc-Java.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/builtins-c.ri new file mode 100644 index 00000000..e7c5aeac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/cdesc-Javascript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/cdesc-Javascript.ri new file mode 100644 index 00000000..aaad648d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/cdesc-Javascript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/constants-c.ri new file mode 100644 index 00000000..3dcaf1a4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/declarations-c.ri new file mode 100644 index 00000000..4e190468 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/detect%3f-c.ri new file mode 100644 index 00000000..cc8ba539 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/id_regex-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/id_regex-c.ri new file mode 100644 index 00000000..f95a9999 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/id_regex-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/keywords-c.ri new file mode 100644 index 00000000..72e6adf6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/reserved-c.ri new file mode 100644 index 00000000..77e8dc54 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Javascript/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/cdesc-Jinja.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/cdesc-Jinja.ri new file mode 100644 index 00000000..30e12f15 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/cdesc-Jinja.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/keywords-c.ri new file mode 100644 index 00000000..5953469f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/pseudo_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/pseudo_keywords-c.ri new file mode 100644 index 00000000..538572a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/pseudo_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/tests-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/tests-c.ri new file mode 100644 index 00000000..f8d5d632 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/tests-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/word_operators-c.ri new file mode 100644 index 00000000..9cb89ade Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jinja/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/builtins-c.ri new file mode 100644 index 00000000..0d9a2540 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/cdesc-Jsonnet.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/cdesc-Jsonnet.ri new file mode 100644 index 00000000..d6885cc2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/cdesc-Jsonnet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/constants-c.ri new file mode 100644 index 00000000..45dfe642 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/declarations-c.ri new file mode 100644 index 00000000..2f5c8d55 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/keywords-c.ri new file mode 100644 index 00000000..396bebc1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Jsonnet/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/cdesc-Julia.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/cdesc-Julia.ri new file mode 100644 index 00000000..bb594a31 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/cdesc-Julia.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/detect%3f-c.ri new file mode 100644 index 00000000..98506b67 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Julia/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Kotlin/cdesc-Kotlin.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Kotlin/cdesc-Kotlin.ri new file mode 100644 index 00000000..c45bac8c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Kotlin/cdesc-Kotlin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/cdesc-LLVM.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/cdesc-LLVM.ri new file mode 100644 index 00000000..b7f24c39 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/cdesc-LLVM.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/instructions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/instructions-c.ri new file mode 100644 index 00000000..89693ce4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/instructions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/keywords-c.ri new file mode 100644 index 00000000..170b36e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/types-c.ri new file mode 100644 index 00000000..c721afa9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LLVM/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/cdesc-Lasso.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/cdesc-Lasso.ri new file mode 100644 index 00000000..1fdeced4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/cdesc-Lasso.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/detect%3f-c.ri new file mode 100644 index 00000000..fd5c854c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/keywords-c.ri new file mode 100644 index 00000000..ad3e01e1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/new-c.ri new file mode 100644 index 00000000..341f0bc5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/start_inline%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/start_inline%3f-i.ri new file mode 100644 index 00000000..e318dea2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lasso/start_inline%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/cdesc-Lean.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/cdesc-Lean.ri new file mode 100644 index 00000000..a2f3ed39 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/cdesc-Lean.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/keywords-c.ri new file mode 100644 index 00000000..6ddbd1cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/operators-c.ri new file mode 100644 index 00000000..f028eff0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/types-c.ri new file mode 100644 index 00000000..f9e36525 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lean/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Liquid/cdesc-Liquid.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Liquid/cdesc-Liquid.ri new file mode 100644 index 00000000..c43a9b70 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Liquid/cdesc-Liquid.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/cdesc-LiterateCoffeescript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/cdesc-LiterateCoffeescript.ri new file mode 100644 index 00000000..363189bf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/cdesc-LiterateCoffeescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/coffee-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/coffee-i.ri new file mode 100644 index 00000000..756962dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/coffee-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/markdown-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/markdown-i.ri new file mode 100644 index 00000000..c26b6bc2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateCoffeescript/markdown-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/cdesc-LiterateHaskell.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/cdesc-LiterateHaskell.ri new file mode 100644 index 00000000..15de423b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/cdesc-LiterateHaskell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/haskell-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/haskell-i.ri new file mode 100644 index 00000000..e35491ab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/LiterateHaskell/haskell-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/builtins-c.ri new file mode 100644 index 00000000..d19a911d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/cdesc-Livescript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/cdesc-Livescript.ri new file mode 100644 index 00000000..639d6aae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/cdesc-Livescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/constants-c.ri new file mode 100644 index 00000000..7d13f43c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/declarations-c.ri new file mode 100644 index 00000000..5eb99788 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/detect%3f-c.ri new file mode 100644 index 00000000..62580e3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/keywords-c.ri new file mode 100644 index 00000000..f1287e87 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/loop_control_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/loop_control_keywords-c.ri new file mode 100644 index 00000000..4068eb1d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Livescript/loop_control_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-c.ri new file mode 100644 index 00000000..a165bb6f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-i.ri new file mode 100644 index 00000000..dc492be7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/cdesc-Lua.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/cdesc-Lua.ri new file mode 100644 index 00000000..d86142da Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/cdesc-Lua.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/detect%3f-c.ri new file mode 100644 index 00000000..8a2172c1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/new-c.ri new file mode 100644 index 00000000..d2de36d2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lua/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/cdesc-Lustre.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/cdesc-Lustre.ri new file mode 100644 index 00000000..7bc82492 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/cdesc-Lustre.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/keywords-c.ri new file mode 100644 index 00000000..25a6ecc4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/primitives-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/primitives-c.ri new file mode 100644 index 00000000..c30d0ace Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/primitives-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/word_operators-c.ri new file mode 100644 index 00000000..3f24d8e9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lustre/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/cdesc-Lutin.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/cdesc-Lutin.ri new file mode 100644 index 00000000..f911847a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/cdesc-Lutin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/keywords-c.ri new file mode 100644 index 00000000..f81ea2bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/primitives-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/primitives-c.ri new file mode 100644 index 00000000..a583e562 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/primitives-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/word_operators-c.ri new file mode 100644 index 00000000..3c62af4c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Lutin/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/builtins-c.ri new file mode 100644 index 00000000..e776accd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/cdesc-M68k.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/cdesc-M68k.ri new file mode 100644 index 00000000..28ba057e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/cdesc-M68k.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords-c.ri new file mode 100644 index 00000000..04f4c844 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords_type-c.ri new file mode 100644 index 00000000..14752b04 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/reserved-c.ri new file mode 100644 index 00000000..af080d04 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/M68k/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MXML/cdesc-MXML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MXML/cdesc-MXML.ri new file mode 100644 index 00000000..8fa0bdce Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MXML/cdesc-MXML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/cdesc-Magik.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/cdesc-Magik.ri new file mode 100644 index 00000000..d7c7c626 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/cdesc-Magik.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/character-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/character-c.ri new file mode 100644 index 00000000..b78611e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/character-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/decimal-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/decimal-c.ri new file mode 100644 index 00000000..fc3db296 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/decimal-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/digits-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/digits-c.ri new file mode 100644 index 00000000..cd89783c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/digits-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/exponent-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/exponent-c.ri new file mode 100644 index 00000000..5b290b62 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/exponent-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/global_ref-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/global_ref-c.ri new file mode 100644 index 00000000..e4b2778e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/global_ref-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/identifier-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/identifier-c.ri new file mode 100644 index 00000000..4a41eeef Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/identifier-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/keywords-c.ri new file mode 100644 index 00000000..98b30aa7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/label-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/label-c.ri new file mode 100644 index 00000000..4bf82174 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/label-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/number-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/number-c.ri new file mode 100644 index 00000000..92c2b12d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/number-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/package_identifier-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/package_identifier-c.ri new file mode 100644 index 00000000..4b25ff06 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/package_identifier-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/piped_identifier-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/piped_identifier-c.ri new file mode 100644 index 00000000..cb6ab24e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/piped_identifier-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/radix-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/radix-c.ri new file mode 100644 index 00000000..e9ac26fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/radix-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/simple_identifier-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/simple_identifier-c.ri new file mode 100644 index 00000000..3ceb960f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/simple_identifier-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_double-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_double-c.ri new file mode 100644 index 00000000..5cf1b1d9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_double-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_single-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_single-c.ri new file mode 100644 index 00000000..abbad9bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/string_single-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/symbol-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/symbol-c.ri new file mode 100644 index 00000000..dd2881fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Magik/symbol-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/cdesc-Make.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/cdesc-Make.ri new file mode 100644 index 00000000..e6f618a6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/cdesc-Make.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/functions-c.ri new file mode 100644 index 00000000..1233ad13 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/new-c.ri new file mode 100644 index 00000000..ba3f8ac4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Make/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/cdesc-Markdown.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/cdesc-Markdown.ri new file mode 100644 index 00000000..6253e79e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/cdesc-Markdown.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/html-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/html-i.ri new file mode 100644 index 00000000..c5f36eff Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Markdown/html-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/cdesc-Mason.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/cdesc-Mason.ri new file mode 100644 index 00000000..f221a288 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/cdesc-Mason.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/new-c.ri new file mode 100644 index 00000000..17ade3e3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mason/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/builtins-c.ri new file mode 100644 index 00000000..b2882bbf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/cdesc-Mathematica.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/cdesc-Mathematica.ri new file mode 100644 index 00000000..03534007 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/cdesc-Mathematica.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/keywords-c.ri new file mode 100644 index 00000000..09f00d89 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mathematica/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/builtins-c.ri new file mode 100644 index 00000000..5dabc8d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/cdesc-Matlab.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/cdesc-Matlab.ri new file mode 100644 index 00000000..d025a034 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/cdesc-Matlab.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/keywords-c.ri new file mode 100644 index 00000000..33ade0f9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Matlab/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/cdesc-StringRegister.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/cdesc-StringRegister.ri new file mode 100644 index 00000000..df8dc0ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/cdesc-StringRegister.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/delim%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/delim%3f-i.ri new file mode 100644 index 00000000..27975f17 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/delim%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/register-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/register-i.ri new file mode 100644 index 00000000..be9e02e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/register-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/remove-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/remove-i.ri new file mode 100644 index 00000000..f98b1bd8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/remove-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/type%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/type%3f-i.ri new file mode 100644 index 00000000..0ce9a1da Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/StringRegister/type%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_functions-c.ri new file mode 100644 index 00000000..37679d49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_variables-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_variables-c.ri new file mode 100644 index 00000000..9e006bc7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/builtin_variables-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/cdesc-Meson.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/cdesc-Meson.ri new file mode 100644 index 00000000..024d7cbc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/cdesc-Meson.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/current_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/current_string-i.ri new file mode 100644 index 00000000..dedeaf65 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/current_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/keywords-c.ri new file mode 100644 index 00000000..2991533f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Meson/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/builtins-c.ri new file mode 100644 index 00000000..b580e448 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/cdesc-MiniZinc.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/cdesc-MiniZinc.ri new file mode 100644 index 00000000..af7d3371 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/cdesc-MiniZinc.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords-c.ri new file mode 100644 index 00000000..dc178ef2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords_type-c.ri new file mode 100644 index 00000000..9aec8a7d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/operators-c.ri new file mode 100644 index 00000000..52029240 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MiniZinc/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/builtins-c.ri new file mode 100644 index 00000000..21ef1993 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/cdesc-Mojo.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/cdesc-Mojo.ri new file mode 100644 index 00000000..23b5695a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/cdesc-Mojo.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/detect%3f-c.ri new file mode 100644 index 00000000..d17a4ec3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/keywords-c.ri new file mode 100644 index 00000000..0a6cb5a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mojo/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/builtins-i.ri new file mode 100644 index 00000000..e4a98184 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/cdesc-Moonscript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/cdesc-Moonscript.ri new file mode 100644 index 00000000..3bfd1ce1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/cdesc-Moonscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/detect%3f-c.ri new file mode 100644 index 00000000..acc3f479 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/new-c.ri new file mode 100644 index 00000000..94308002 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Moonscript/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mosel/cdesc-Mosel.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mosel/cdesc-Mosel.ri new file mode 100644 index 00000000..8e64698a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Mosel/cdesc-Mosel.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MsgTrans/cdesc-MsgTrans.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MsgTrans/cdesc-MsgTrans.ri new file mode 100644 index 00000000..eb268c4a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/MsgTrans/cdesc-MsgTrans.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nasm/cdesc-Nasm.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nasm/cdesc-Nasm.ri new file mode 100644 index 00000000..5b073106 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nasm/cdesc-Nasm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/cdesc-NesAsm.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/cdesc-NesAsm.ri new file mode 100644 index 00000000..92aee17e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/cdesc-NesAsm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords-c.ri new file mode 100644 index 00000000..b208f021 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_reserved-c.ri new file mode 100644 index 00000000..6260a0e4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_type-c.ri new file mode 100644 index 00000000..6fa3b79d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/NesAsm/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nginx/cdesc-Nginx.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nginx/cdesc-Nginx.ri new file mode 100644 index 00000000..0892cdbe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nginx/cdesc-Nginx.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/cdesc-Nial.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/cdesc-Nial.ri new file mode 100644 index 00000000..30de777e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/cdesc-Nial.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/consts-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/consts-c.ri new file mode 100644 index 00000000..e3025f1a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/consts-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/funcs-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/funcs-c.ri new file mode 100644 index 00000000..25d9688b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/funcs-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/keywords-c.ri new file mode 100644 index 00000000..28d643e5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/operators-c.ri new file mode 100644 index 00000000..05f87c84 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/punctuations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/punctuations-c.ri new file mode 100644 index 00000000..09999413 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/punctuations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/transformers-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/transformers-c.ri new file mode 100644 index 00000000..54213fb1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nial/transformers-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/cdesc-Nim.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/cdesc-Nim.ri new file mode 100644 index 00000000..16da73d0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/cdesc-Nim.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/underscorize-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/underscorize-c.ri new file mode 100644 index 00000000..746ae2db Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nim/underscorize-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nix/cdesc-Nix.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nix/cdesc-Nix.ri new file mode 100644 index 00000000..aa3e5c98 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Nix/cdesc-Nix.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/builtins-c.ri new file mode 100644 index 00000000..2f892d90 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/cdesc-OCL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/cdesc-OCL.ri new file mode 100644 index 00000000..d4ca5a10 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/cdesc-OCL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/functions-c.ri new file mode 100644 index 00000000..eeec851c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords-c.ri new file mode 100644 index 00000000..ff0b47cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords_type-c.ri new file mode 100644 index 00000000..a56ecbf0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/operators-c.ri new file mode 100644 index 00000000..04f06d2c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCL/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/cdesc-OCaml.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/cdesc-OCaml.ri new file mode 100644 index 00000000..f2cd79a9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/cdesc-OCaml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/keywords-c.ri new file mode 100644 index 00000000..5f7e92e5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCaml/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/cdesc-OCamlCommon.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/cdesc-OCamlCommon.ri new file mode 100644 index 00000000..6bacdeaa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/cdesc-OCamlCommon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/keywords-c.ri new file mode 100644 index 00000000..a363cfef Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/primitives-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/primitives-c.ri new file mode 100644 index 00000000..2e410e0e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/primitives-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/word_operators-c.ri new file mode 100644 index 00000000..38be9de1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OCamlCommon/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveC/cdesc-ObjectiveC.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveC/cdesc-ObjectiveC.ri new file mode 100644 index 00000000..62e7d0c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveC/cdesc-ObjectiveC.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_builtins-i.ri new file mode 100644 index 00000000..b3877de5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_keywords-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_keywords-i.ri new file mode 100644 index 00000000..119cb663 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/at_keywords-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/builtins-i.ri new file mode 100644 index 00000000..7a38eb49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/cdesc-ObjectiveCCommon.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/cdesc-ObjectiveCCommon.ri new file mode 100644 index 00000000..33ca18bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/cdesc-ObjectiveCCommon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/extended-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/extended-c.ri new file mode 100644 index 00000000..b0c9b6f7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCCommon/extended-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCpp/cdesc-ObjectiveCpp.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCpp/cdesc-ObjectiveCpp.ri new file mode 100644 index 00000000..5708d002 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ObjectiveCpp/cdesc-ObjectiveCpp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/cdesc-OpenEdge.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/cdesc-OpenEdge.ri new file mode 100644 index 00000000..fb0ec253 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/cdesc-OpenEdge.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords-c.ri new file mode 100644 index 00000000..c970e05f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_prepro-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_prepro-c.ri new file mode 100644 index 00000000..341ab060 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_prepro-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_type-c.ri new file mode 100644 index 00000000..f3cd6972 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenEdge/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/cdesc-OpenTypeFeatureFile.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/cdesc-OpenTypeFeatureFile.ri new file mode 100644 index 00000000..f5fcfa3a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/cdesc-OpenTypeFeatureFile.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/keywords-c.ri new file mode 100644 index 00000000..de6e692d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/OpenTypeFeatureFile/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/builtins-c.ri new file mode 100644 index 00000000..6d35fff2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/cdesc-P4.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/cdesc-P4.ri new file mode 100644 index 00000000..6036a5fa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/cdesc-P4.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/decls-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/decls-c.ri new file mode 100644 index 00000000..97b24d9b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/decls-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/keywords-c.ri new file mode 100644 index 00000000..aaec055d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/operators-c.ri new file mode 100644 index 00000000..1185d24c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/P4/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-c.ri new file mode 100644 index 00000000..0cd0ba02 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-i.ri new file mode 100644 index 00000000..eb8d5d0d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/cdesc-PHP.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/cdesc-PHP.ri new file mode 100644 index 00000000..68e42daa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/cdesc-PHP.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/detect%3f-c.ri new file mode 100644 index 00000000..2d7b6876 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/keywords-c.ri new file mode 100644 index 00000000..9081be62 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/new-c.ri new file mode 100644 index 00000000..d06abed1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PHP/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/cdesc-PLSQL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/cdesc-PLSQL.ri new file mode 100644 index 00000000..fd4c9a6f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/cdesc-PLSQL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords-c.ri new file mode 100644 index 00000000..8e201c99 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_func-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_func-c.ri new file mode 100644 index 00000000..dcda9523 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_func-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_reserved-c.ri new file mode 100644 index 00000000..7191875a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_type-c.ri new file mode 100644 index 00000000..dffad27e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PLSQL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pascal/cdesc-Pascal.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pascal/cdesc-Pascal.ri new file mode 100644 index 00000000..0db7123b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pascal/cdesc-Pascal.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/cdesc-Perl.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/cdesc-Perl.ri new file mode 100644 index 00000000..5946354a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/cdesc-Perl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/detect%3f-c.ri new file mode 100644 index 00000000..4991dc98 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Perl/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/cdesc-PlainText.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/cdesc-PlainText.ri new file mode 100644 index 00000000..a78e5e4c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/cdesc-PlainText.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/new-c.ri new file mode 100644 index 00000000..39d225a7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/stream_tokens-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/stream_tokens-i.ri new file mode 100644 index 00000000..833ead23 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/stream_tokens-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/token-i.ri new file mode 100644 index 00000000..53974c65 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PlainText/token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Plist/cdesc-Plist.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Plist/cdesc-Plist.ri new file mode 100644 index 00000000..fd6969fa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Plist/cdesc-Plist.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pony/cdesc-Pony.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pony/cdesc-Pony.ri new file mode 100644 index 00000000..cfd51146 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Pony/cdesc-Pony.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/cdesc-PostScript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/cdesc-PostScript.ri new file mode 100644 index 00000000..45fc9416 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/cdesc-PostScript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/detect%3f-c.ri new file mode 100644 index 00000000..cfc3dfac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/PostScript/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Powershell/cdesc-Powershell.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Powershell/cdesc-Powershell.ri new file mode 100644 index 00000000..85d7f3d5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Powershell/cdesc-Powershell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/cdesc-Praat.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/cdesc-Praat.ri new file mode 100644 index 00000000..415b4bf9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/cdesc-Praat.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/detect%3f-c.ri new file mode 100644 index 00000000..d273a6c4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_array-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_array-c.ri new file mode 100644 index 00000000..87a4f8e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_array-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_builtin-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_builtin-c.ri new file mode 100644 index 00000000..34c06d4b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_builtin-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_matrix-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_matrix-c.ri new file mode 100644 index 00000000..94d074ed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_matrix-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_numeric-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_numeric-c.ri new file mode 100644 index 00000000..59bd0b3e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_numeric-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string-c.ri new file mode 100644 index 00000000..22a560c1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string_vector-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string_vector-c.ri new file mode 100644 index 00000000..473b83ba Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/functions_string_vector-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/keywords-c.ri new file mode 100644 index 00000000..00143d58 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/object_attributes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/object_attributes-c.ri new file mode 100644 index 00000000..3f5ce15d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/object_attributes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/objects-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/objects-c.ri new file mode 100644 index 00000000..a5ad1f82 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/objects-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_numeric-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_numeric-c.ri new file mode 100644 index 00000000..600c54bb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_numeric-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_string-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_string-c.ri new file mode 100644 index 00000000..16077ca9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Praat/variables_string-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prolog/cdesc-Prolog.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prolog/cdesc-Prolog.ri new file mode 100644 index 00000000..387df11c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prolog/cdesc-Prolog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/cdesc-Prometheus.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/cdesc-Prometheus.ri new file mode 100644 index 00000000..fd226134 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/cdesc-Prometheus.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/functions-c.ri new file mode 100644 index 00000000..272a6bc0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Prometheus/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Properties/cdesc-Properties.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Properties/cdesc-Properties.ri new file mode 100644 index 00000000..6ff9d107 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Properties/cdesc-Properties.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Protobuf/cdesc-Protobuf.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Protobuf/cdesc-Protobuf.ri new file mode 100644 index 00000000..594dad7e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Protobuf/cdesc-Protobuf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/cdesc-Puppet.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/cdesc-Puppet.ri new file mode 100644 index 00000000..3ec41479 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/cdesc-Puppet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/constants-c.ri new file mode 100644 index 00000000..feb21032 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/detect%3f-c.ri new file mode 100644 index 00000000..01c1bf03 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/keywords-c.ri new file mode 100644 index 00000000..58fc6ddd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/metaparameters-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/metaparameters-c.ri new file mode 100644 index 00000000..5a5aaa76 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Puppet/metaparameters-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/cdesc-StringRegister.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/cdesc-StringRegister.ri new file mode 100644 index 00000000..d8efc64c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/cdesc-StringRegister.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/delim%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/delim%3f-i.ri new file mode 100644 index 00000000..9d75c7f5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/delim%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/register-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/register-i.ri new file mode 100644 index 00000000..cf6c9063 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/register-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/remove-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/remove-i.ri new file mode 100644 index 00000000..41b675a9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/remove-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/type%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/type%3f-i.ri new file mode 100644 index 00000000..932a422a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/StringRegister/type%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins-c.ri new file mode 100644 index 00000000..e15136a8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins_pseudo-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins_pseudo-c.ri new file mode 100644 index 00000000..c01b2fe4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/builtins_pseudo-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/cdesc-Python.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/cdesc-Python.ri new file mode 100644 index 00000000..77cac519 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/cdesc-Python.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/current_string-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/current_string-i.ri new file mode 100644 index 00000000..edff95ea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/current_string-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/detect%3f-c.ri new file mode 100644 index 00000000..1a920f8c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/exceptions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/exceptions-c.ri new file mode 100644 index 00000000..7b39dc1a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/exceptions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/keywords-c.ri new file mode 100644 index 00000000..b87f52d0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Python/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/builtins-c.ri new file mode 100644 index 00000000..2dc4b095 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/cdesc-Q.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/cdesc-Q.ri new file mode 100644 index 00000000..66021595 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/cdesc-Q.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/keywords-c.ri new file mode 100644 index 00000000..71aa424f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/word_operators-c.ri new file mode 100644 index 00000000..7345d3ef Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Q/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Qml/cdesc-Qml.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Qml/cdesc-Qml.ri new file mode 100644 index 00000000..1311f766 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Qml/cdesc-Qml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/cdesc-R.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/cdesc-R.ri new file mode 100644 index 00000000..adab7f36 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/cdesc-R.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/detect%3f-c.ri new file mode 100644 index 00000000..4c0817a2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/R/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/arithmetic_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/arithmetic_keywords-c.ri new file mode 100644 index 00000000..d02dbc88 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/arithmetic_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/cdesc-RML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/cdesc-RML.ri new file mode 100644 index 00000000..5c286754 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/cdesc-RML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/keywords-c.ri new file mode 100644 index 00000000..4ffea83a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RML/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/builtins-c.ri new file mode 100644 index 00000000..e5d34187 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/cdesc-Racket.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/cdesc-Racket.ri new file mode 100644 index 00000000..ca5d5562 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/cdesc-Racket.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/detect%3f-c.ri new file mode 100644 index 00000000..b9af3ccd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/keywords-c.ri new file mode 100644 index 00000000..2e0931e6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Racket/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/cdesc-ReScript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/cdesc-ReScript.ri new file mode 100644 index 00000000..cad9097e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/cdesc-ReScript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/keywords-c.ri new file mode 100644 index 00000000..ae390832 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/types-c.ri new file mode 100644 index 00000000..20532909 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/word_operators-c.ri new file mode 100644 index 00000000..dbdfc691 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReScript/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/cdesc-ReasonML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/cdesc-ReasonML.ri new file mode 100644 index 00000000..f155516d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/cdesc-ReasonML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/keywords-c.ri new file mode 100644 index 00000000..272f1643 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/ReasonML/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/cdesc-Rego.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/cdesc-Rego.ri new file mode 100644 index 00000000..267bf498 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/cdesc-Rego.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/constants-c.ri new file mode 100644 index 00000000..1d9ab07e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/operators-c.ri new file mode 100644 index 00000000..45fd042e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rego/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/cdesc-RobotFramework.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/cdesc-RobotFramework.ri new file mode 100644 index 00000000..c6beff33 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/cdesc-RobotFramework.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/new-c.ri new file mode 100644 index 00000000..db2e32b1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_args-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_args-c.ri new file mode 100644 index 00000000..10f58574 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_args-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_keywords-c.ri new file mode 100644 index 00000000..20a9de60 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/RobotFramework/settings_with_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/cdesc-Ruby.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/cdesc-Ruby.ri new file mode 100644 index 00000000..61a213a9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/cdesc-Ruby.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/detect%3f-c.ri new file mode 100644 index 00000000..133023f0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Ruby/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/builtins-c.ri new file mode 100644 index 00000000..e9e9319e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/cdesc-Rust.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/cdesc-Rust.ri new file mode 100644 index 00000000..b88f4446 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/cdesc-Rust.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/detect%3f-c.ri new file mode 100644 index 00000000..87deafa3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/keywords-c.ri new file mode 100644 index 00000000..54956ce5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/macro_closed%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/macro_closed%3f-i.ri new file mode 100644 index 00000000..bb89a23b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Rust/macro_closed%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/cdesc-SAS.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/cdesc-SAS.ri new file mode 100644 index 00000000..e7314bf0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/cdesc-SAS.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/data_step_statements-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/data_step_statements-c.ri new file mode 100644 index 00000000..168b5286 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/data_step_statements-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/proc_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/proc_keywords-c.ri new file mode 100644 index 00000000..9426d336 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/proc_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_auto_macro_vars-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_auto_macro_vars-c.ri new file mode 100644 index 00000000..66921e2b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_auto_macro_vars-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_functions-c.ri new file mode 100644 index 00000000..83fbcc14 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_functions-c.ri new file mode 100644 index 00000000..031c1a8a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_statements-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_statements-c.ri new file mode 100644 index 00000000..a46cc743 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_macro_statements-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_proc_names-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_proc_names-c.ri new file mode 100644 index 00000000..d3f56707 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SAS/sas_proc_names-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/cdesc-SML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/cdesc-SML.ri new file mode 100644 index 00000000..4faa036c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/cdesc-SML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/keywords-c.ri new file mode 100644 index 00000000..09cc81bf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/symbolic_reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/symbolic_reserved-c.ri new file mode 100644 index 00000000..b68605df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/symbolic_reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_final_id-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_final_id-i.ri new file mode 100644 index 00000000..b264334a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_final_id-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id-i.ri new file mode 100644 index 00000000..0143ace2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id_with_dot-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id_with_dot-i.ri new file mode 100644 index 00000000..dcb432cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SML/token_for_id_with_dot-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/builtins-c.ri new file mode 100644 index 00000000..f45e92ee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/cdesc-SPARQL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/cdesc-SPARQL.ri new file mode 100644 index 00000000..182ac4e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/cdesc-SPARQL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/keywords-c.ri new file mode 100644 index 00000000..f35b18e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SPARQL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/cdesc-SQF.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/cdesc-SQF.ri new file mode 100644 index 00000000..61b3a8f0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/cdesc-SQF.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/commands-c.ri new file mode 100644 index 00000000..2e94d580 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/constants-c.ri new file mode 100644 index 00000000..6168d6a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/controlflow-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/controlflow-c.ri new file mode 100644 index 00000000..b0955e03 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/controlflow-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/diag_commands-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/diag_commands-c.ri new file mode 100644 index 00000000..c444c40c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/diag_commands-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/initializers-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/initializers-c.ri new file mode 100644 index 00000000..1bb0db11 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/initializers-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/namespaces-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/namespaces-c.ri new file mode 100644 index 00000000..dbb87cbe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/namespaces-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/wordoperators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/wordoperators-c.ri new file mode 100644 index 00000000..c74f9b5d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQF/wordoperators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/cdesc-SQL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/cdesc-SQL.ri new file mode 100644 index 00000000..977f49dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/cdesc-SQL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords-c.ri new file mode 100644 index 00000000..3844b488 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords_type-c.ri new file mode 100644 index 00000000..28e6d9fa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SQL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SSH/cdesc-SSH.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SSH/cdesc-SSH.ri new file mode 100644 index 00000000..0e109c43 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SSH/cdesc-SSH.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sass/cdesc-Sass.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sass/cdesc-Sass.ri new file mode 100644 index 00000000..ca248071 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sass/cdesc-Sass.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SassCommon/cdesc-SassCommon.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SassCommon/cdesc-SassCommon.ri new file mode 100644 index 00000000..11a9004d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SassCommon/cdesc-SassCommon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scala/cdesc-Scala.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scala/cdesc-Scala.ri new file mode 100644 index 00000000..1a12e525 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scala/cdesc-Scala.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/builtins-c.ri new file mode 100644 index 00000000..b3f0f2cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/cdesc-Scheme.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/cdesc-Scheme.ri new file mode 100644 index 00000000..5ae4c9cc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/cdesc-Scheme.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/keywords-c.ri new file mode 100644 index 00000000..7f7859c0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scheme/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scss/cdesc-Scss.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scss/cdesc-Scss.ri new file mode 100644 index 00000000..b5764223 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Scss/cdesc-Scss.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Regex/cdesc-Regex.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Regex/cdesc-Regex.ri new file mode 100644 index 00000000..e8bd91bf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Regex/cdesc-Regex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Replacement/cdesc-Replacement.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Replacement/cdesc-Replacement.ri new file mode 100644 index 00000000..1c3dbeff Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/Replacement/cdesc-Replacement.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/cdesc-Sed.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/cdesc-Sed.ri new file mode 100644 index 00000000..6311e12c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/cdesc-Sed.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/detect%3f-c.ri new file mode 100644 index 00000000..72fa2d9d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/regex-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/regex-i.ri new file mode 100644 index 00000000..536985de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/regex-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/replacement-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/replacement-i.ri new file mode 100644 index 00000000..7adfc5fb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sed/replacement-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/cdesc-Shell.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/cdesc-Shell.ri new file mode 100644 index 00000000..19aa70f7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/cdesc-Shell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/detect%3f-c.ri new file mode 100644 index 00000000..e4939316 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Shell/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/actions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/actions-c.ri new file mode 100644 index 00000000..2f8586dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/actions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/cdesc-Sieve.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/cdesc-Sieve.ri new file mode 100644 index 00000000..e5c63240 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/cdesc-Sieve.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/controls-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/controls-c.ri new file mode 100644 index 00000000..a7eb5463 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/controls-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/tests-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/tests-c.ri new file mode 100644 index 00000000..1d3da0df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Sieve/tests-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/cdesc-Slice.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/cdesc-Slice.ri new file mode 100644 index 00000000..acbeb447 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/cdesc-Slice.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords-c.ri new file mode 100644 index 00000000..a79f9ae2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords_type-c.ri new file mode 100644 index 00000000..8205c19c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slice/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/cdesc-Slim.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/cdesc-Slim.ri new file mode 100644 index 00000000..21a14c86 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/cdesc-Slim.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/filters-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/filters-i.ri new file mode 100644 index 00000000..9fbbc0ff Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/filters-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/html-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/html-i.ri new file mode 100644 index 00000000..3f3e7257 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/html-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/ruby-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/ruby-i.ri new file mode 100644 index 00000000..57f330df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Slim/ruby-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smalltalk/cdesc-Smalltalk.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smalltalk/cdesc-Smalltalk.ri new file mode 100644 index 00000000..ff438e90 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smalltalk/cdesc-Smalltalk.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/builtins-c.ri new file mode 100644 index 00000000..3ecb5b80 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/cdesc-Smarty.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/cdesc-Smarty.ri new file mode 100644 index 00000000..053b93d4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Smarty/cdesc-Smarty.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/builtin_functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/builtin_functions-c.ri new file mode 100644 index 00000000..7ade1542 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/builtin_functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/cdesc-Stan.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/cdesc-Stan.ri new file mode 100644 index 00000000..59cd787f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/cdesc-Stan.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/constants-c.ri new file mode 100644 index 00000000..250a346e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/distributions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/distributions-c.ri new file mode 100644 index 00000000..07a28e96 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/distributions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/keywords-c.ri new file mode 100644 index 00000000..f52f7ad9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/reserved-c.ri new file mode 100644 index 00000000..01dcf1f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/types-c.ri new file mode 100644 index 00000000..9e70ccd9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stan/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/cdesc-Stata.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/cdesc-Stata.ri new file mode 100644 index 00000000..71b3867f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/cdesc-Stata.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/reserved_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/reserved_keywords-c.ri new file mode 100644 index 00000000..05da48ad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/reserved_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/type_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/type_keywords-c.ri new file mode 100644 index 00000000..bb6927d4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Stata/type_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/cdesc-SuperCollider.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/cdesc-SuperCollider.ri new file mode 100644 index 00000000..33b1a3d5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/cdesc-SuperCollider.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/constants-c.ri new file mode 100644 index 00000000..1eff0f8a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/keywords-c.ri new file mode 100644 index 00000000..37add58a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/reserved-c.ri new file mode 100644 index 00000000..ae283209 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SuperCollider/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/cdesc-Svelte.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/cdesc-Svelte.ri new file mode 100644 index 00000000..bc4e7e75 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/cdesc-Svelte.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/new-c.ri new file mode 100644 index 00000000..c656d869 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Svelte/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Swift/cdesc-Swift.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Swift/cdesc-Swift.ri new file mode 100644 index 00000000..7319541c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Swift/cdesc-Swift.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SystemD/cdesc-SystemD.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SystemD/cdesc-SystemD.ri new file mode 100644 index 00000000..bdd6d0eb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/SystemD/cdesc-SystemD.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/cdesc-Syzlang.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/cdesc-Syzlang.ri new file mode 100644 index 00000000..78abdffa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/cdesc-Syzlang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords-c.ri new file mode 100644 index 00000000..abbdfaea Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords_type-c.ri new file mode 100644 index 00000000..64dba628 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzlang/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/cdesc-Syzprog.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/cdesc-Syzprog.ri new file mode 100644 index 00000000..4544f21d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/cdesc-Syzprog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/keywords-c.ri new file mode 100644 index 00000000..ffa40643 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Syzprog/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/cdesc-TCL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/cdesc-TCL.ri new file mode 100644 index 00000000..1dbea9df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/cdesc-TCL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/detect%3f-c.ri new file mode 100644 index 00000000..501d4891 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_command_state-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_command_state-c.ri new file mode 100644 index 00000000..1c297d7d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_command_state-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_delimiter_states-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_delimiter_states-c.ri new file mode 100644 index 00000000..04080dad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TCL/gen_delimiter_states-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TOML/cdesc-TOML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TOML/cdesc-TOML.ri new file mode 100644 index 00000000..0d4291bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TOML/cdesc-TOML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TSX/cdesc-TSX.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TSX/cdesc-TSX.ri new file mode 100644 index 00000000..687b92b0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TSX/cdesc-TSX.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/cdesc-TTCN3.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/cdesc-TTCN3.ri new file mode 100644 index 00000000..a3809575 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/cdesc-TTCN3.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/keywords-c.ri new file mode 100644 index 00000000..43902ed4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/reserved-c.ri new file mode 100644 index 00000000..56545596 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/types-c.ri new file mode 100644 index 00000000..4d6044b2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TTCN3/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tap/cdesc-Tap.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tap/cdesc-Tap.ri new file mode 100644 index 00000000..63325984 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tap/cdesc-Tap.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/cdesc-TeX.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/cdesc-TeX.ri new file mode 100644 index 00000000..b9daf3b6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/cdesc-TeX.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/detect%3f-c.ri new file mode 100644 index 00000000..9085727f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TeX/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/builtins-c.ri new file mode 100644 index 00000000..17d7cac7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/cdesc-Terraform.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/cdesc-Terraform.ri new file mode 100644 index 00000000..b82e2a6b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/cdesc-Terraform.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/constants-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/constants-c.ri new file mode 100644 index 00000000..55a3733f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/constants-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/declarations-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/declarations-c.ri new file mode 100644 index 00000000..a8c66607 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/declarations-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/keywords-c.ri new file mode 100644 index 00000000..c1c2e0a1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/reserved-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/reserved-c.ri new file mode 100644 index 00000000..14feb028 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Terraform/reserved-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/cdesc-Tulip.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/cdesc-Tulip.ri new file mode 100644 index 00000000..b781878d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/cdesc-Tulip.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/detect%3f-c.ri new file mode 100644 index 00000000..a617cf5c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Tulip/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Turtle/cdesc-Turtle.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Turtle/cdesc-Turtle.ri new file mode 100644 index 00000000..0ae56e2b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Turtle/cdesc-Turtle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/cdesc-Twig.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/cdesc-Twig.ri new file mode 100644 index 00000000..667de3ed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/cdesc-Twig.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/keywords-c.ri new file mode 100644 index 00000000..be32f95c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/pseudo_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/pseudo_keywords-c.ri new file mode 100644 index 00000000..996de160 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/pseudo_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/tests-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/tests-c.ri new file mode 100644 index 00000000..e43fab86 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/tests-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/word_operators-c.ri new file mode 100644 index 00000000..ec708c5f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Twig/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Typescript/cdesc-Typescript.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Typescript/cdesc-Typescript.ri new file mode 100644 index 00000000..4abc9824 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Typescript/cdesc-Typescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/builtins-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/builtins-i.ri new file mode 100644 index 00000000..4f622d1c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/builtins-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/cdesc-TypescriptCommon.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/cdesc-TypescriptCommon.ri new file mode 100644 index 00000000..02c12f2e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/cdesc-TypescriptCommon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/declarations-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/declarations-i.ri new file mode 100644 index 00000000..98543621 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/declarations-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/extended-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/extended-c.ri new file mode 100644 index 00000000..2303a0ae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/extended-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/keywords-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/keywords-i.ri new file mode 100644 index 00000000..d806d940 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/keywords-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/reserved-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/reserved-i.ri new file mode 100644 index 00000000..846c7b3b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/TypescriptCommon/reserved-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/cdesc-VHDL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/cdesc-VHDL.ri new file mode 100644 index 00000000..135b28f5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/cdesc-VHDL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords-c.ri new file mode 100644 index 00000000..7cb92186 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords_type-c.ri new file mode 100644 index 00000000..3b0d184b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/operator_words-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/operator_words-c.ri new file mode 100644 index 00000000..4235e787 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VHDL/operator_words-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vala/cdesc-Vala.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vala/cdesc-Vala.ri new file mode 100644 index 00000000..d6d13320 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vala/cdesc-Vala.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/cdesc-Varnish.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/cdesc-Varnish.ri new file mode 100644 index 00000000..3bcf3800 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/cdesc-Varnish.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/functions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/functions-c.ri new file mode 100644 index 00000000..9cb2a885 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/functions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/keywords-c.ri new file mode 100644 index 00000000..d7accfa9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/variables-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/variables-c.ri new file mode 100644 index 00000000..336a60e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Varnish/variables-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Velocity/cdesc-Velocity.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Velocity/cdesc-Velocity.ri new file mode 100644 index 00000000..fd88cc0b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Velocity/cdesc-Velocity.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/cdesc-Verilog.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/cdesc-Verilog.ri new file mode 100644 index 00000000..c7703d08 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/cdesc-Verilog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords-c.ri new file mode 100644 index 00000000..86826734 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_system_task-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_system_task-c.ri new file mode 100644 index 00000000..20c643e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_system_task-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_type-c.ri new file mode 100644 index 00000000..65552574 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Verilog/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/cdesc-VimL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/cdesc-VimL.ri new file mode 100644 index 00000000..59f8d487 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/cdesc-VimL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/keywords-c.ri new file mode 100644 index 00000000..4c6ff4a4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VimL/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/builtins-c.ri new file mode 100644 index 00000000..bcc38fbd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/cdesc-VisualBasic.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/cdesc-VisualBasic.ri new file mode 100644 index 00000000..34ebaeb4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/cdesc-VisualBasic.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords-c.ri new file mode 100644 index 00000000..df73e51e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords_type-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords_type-c.ri new file mode 100644 index 00000000..d564bf00 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/keywords_type-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/operator_words-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/operator_words-c.ri new file mode 100644 index 00000000..bb22e476 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/VisualBasic/operator_words-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/cdesc-Vue.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/cdesc-Vue.ri new file mode 100644 index 00000000..42b2e5e2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/cdesc-Vue.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/lookup_lang-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/lookup_lang-i.ri new file mode 100644 index 00000000..67d6d5a8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/lookup_lang-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/new-c.ri new file mode 100644 index 00000000..ab8b92cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Vue/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/any-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/any-i.ri new file mode 100644 index 00000000..e78a939a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/any-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/cdesc-Wollok.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/cdesc-Wollok.ri new file mode 100644 index 00000000..e472b2cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/cdesc-Wollok.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/entities-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/entities-i.ri new file mode 100644 index 00000000..8e26cf46 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Wollok/entities-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/cdesc-XML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/cdesc-XML.ri new file mode 100644 index 00000000..e76ee9e7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/cdesc-XML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/detect%3f-c.ri new file mode 100644 index 00000000..ced3d013 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XML/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/axes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/axes-c.ri new file mode 100644 index 00000000..237f5145 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/axes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/cdesc-XPath.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/cdesc-XPath.ri new file mode 100644 index 00000000..f24541c0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/cdesc-XPath.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/commentStart-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/commentStart-c.ri new file mode 100644 index 00000000..08b360da Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/commentStart-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/constructorTypes-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/constructorTypes-c.ri new file mode 100644 index 00000000..57c9fe15 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/constructorTypes-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/decimalLiteral-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/decimalLiteral-c.ri new file mode 100644 index 00000000..19a51a0a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/decimalLiteral-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/digits-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/digits-c.ri new file mode 100644 index 00000000..0099be53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/digits-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/doubleLiteral-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/doubleLiteral-c.ri new file mode 100644 index 00000000..0ccd0da3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/doubleLiteral-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/eqName-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/eqName-c.ri new file mode 100644 index 00000000..18ffe1a2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/eqName-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/keywords-c.ri new file mode 100644 index 00000000..3cdc1ad0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTest-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTest-c.ri new file mode 100644 index 00000000..be636057 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTest-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTestForPI-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTestForPI-c.ri new file mode 100644 index 00000000..4e9c4dc9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/kindTestForPI-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/ncName-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/ncName-c.ri new file mode 100644 index 00000000..c5a4247d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/ncName-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/openParen-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/openParen-c.ri new file mode 100644 index 00000000..8395f74c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/openParen-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/operators-c.ri new file mode 100644 index 00000000..1d37e59a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/qName-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/qName-c.ri new file mode 100644 index 00000000..640cec4a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/qName-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/stringLiteral-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/stringLiteral-c.ri new file mode 100644 index 00000000..43dba506 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/stringLiteral-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/uriQName-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/uriQName-c.ri new file mode 100644 index 00000000..52f1b757 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/uriQName-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/word_operators-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/word_operators-c.ri new file mode 100644 index 00000000..91b7fd23 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XPath/word_operators-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/cdesc-XQuery.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/cdesc-XQuery.ri new file mode 100644 index 00000000..2842c69c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/cdesc-XQuery.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/keywords-c.ri new file mode 100644 index 00000000..d18d8c23 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/XQuery/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Xojo/cdesc-Xojo.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Xojo/cdesc-Xojo.ri new file mode 100644 index 00000000..af73fbbb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Xojo/cdesc-Xojo.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/cdesc-YAML.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/cdesc-YAML.ri new file mode 100644 index 00000000..98a9cc47 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/cdesc-YAML.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/continue_indent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/continue_indent-i.ri new file mode 100644 index 00000000..d8a833f0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/continue_indent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/dedent%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/dedent%3f-i.ri new file mode 100644 index 00000000..f8a75b63 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/dedent%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/detect%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/detect%3f-c.ri new file mode 100644 index 00000000..42606fbd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/detect%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent%3f-i.ri new file mode 100644 index 00000000..f51f5b6e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent-i.ri new file mode 100644 index 00000000..b45a15bb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/indent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/reset_indent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/reset_indent-i.ri new file mode 100644 index 00000000..3153225f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/reset_indent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/save_indent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/save_indent-i.ri new file mode 100644 index 00000000..2c569f83 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/save_indent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/set_indent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/set_indent-i.ri new file mode 100644 index 00000000..64261c24 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YAML/set_indent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/body_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/body_stmts_keywords-c.ri new file mode 100644 index 00000000..22107a22 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/body_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/cdesc-YANG.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/cdesc-YANG.ri new file mode 100644 index 00000000..deb79c1b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/cdesc-YANG.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/constants_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/constants_keywords-c.ri new file mode 100644 index 00000000..e2de5a53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/constants_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/data_def_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/data_def_stmts_keywords-c.ri new file mode 100644 index 00000000..ccd073ba Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/data_def_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/linkage_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/linkage_stmts_keywords-c.ri new file mode 100644 index 00000000..a90f2ff6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/linkage_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/list_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/list_stmts_keywords-c.ri new file mode 100644 index 00000000..ae58375b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/list_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/meta_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/meta_stmts_keywords-c.ri new file mode 100644 index 00000000..a66ff778 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/meta_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/module_header_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/module_header_stmts_keywords-c.ri new file mode 100644 index 00000000..da97b6e1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/module_header_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/top_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/top_stmts_keywords-c.ri new file mode 100644 index 00000000..1ef666b3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/top_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/type_stmts_keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/type_stmts_keywords-c.ri new file mode 100644 index 00000000..80eaefc9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/type_stmts_keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/types-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/types-c.ri new file mode 100644 index 00000000..f6a88557 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/YANG/types-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/builtins-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/builtins-c.ri new file mode 100644 index 00000000..40707c8d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/builtins-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/cdesc-Zig.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/cdesc-Zig.ri new file mode 100644 index 00000000..c03067fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/cdesc-Zig.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/keywords-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/keywords-c.ri new file mode 100644 index 00000000..07662eb5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/Zig/keywords-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/cdesc-Lexers.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/cdesc-Lexers.ri new file mode 100644 index 00000000..74547008 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/cdesc-Lexers.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/load_lexer-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/load_lexer-c.ri new file mode 100644 index 00000000..c6b518a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Lexers/load_lexer-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/block_code-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/block_code-i.ri new file mode 100644 index 00000000..1ecc5458 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/block_code-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/cdesc-Redcarpet.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/cdesc-Redcarpet.ri new file mode 100644 index 00000000..7fa400cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/cdesc-Redcarpet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/rouge_formatter-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/rouge_formatter-i.ri new file mode 100644 index 00000000..29010536 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/Redcarpet/rouge_formatter-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/cdesc-Plugins.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/cdesc-Plugins.ri new file mode 100644 index 00000000..f575d283 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Plugins/cdesc-Plugins.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/cdesc-ClosedState.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/cdesc-ClosedState.ri new file mode 100644 index 00000000..670c0926 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/cdesc-ClosedState.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/new-c.ri new file mode 100644 index 00000000..a07f3508 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/rule-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/rule-i.ri new file mode 100644 index 00000000..ea28d35b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/rule-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/state-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/state-i.ri new file mode 100644 index 00000000..04729976 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/state-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/to_s-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/to_s-i.ri new file mode 100644 index 00000000..067beaa2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/ClosedState/to_s-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/cdesc-InvalidRegex.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/cdesc-InvalidRegex.ri new file mode 100644 index 00000000..d4a862fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/cdesc-InvalidRegex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/new-c.ri new file mode 100644 index 00000000..f83f7701 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/to_s-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/to_s-i.ri new file mode 100644 index 00000000..00a285fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/InvalidRegex/to_s-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/beginning_of_line-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/beginning_of_line-i.ri new file mode 100644 index 00000000..6f50248d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/beginning_of_line-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/callback-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/callback-i.ri new file mode 100644 index 00000000..2ad23edf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/callback-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/cdesc-Rule.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/cdesc-Rule.ri new file mode 100644 index 00000000..f0e563be Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/cdesc-Rule.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/inspect-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/inspect-i.ri new file mode 100644 index 00000000..a5dd0b26 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/inspect-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/new-c.ri new file mode 100644 index 00000000..20de046c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/re-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/re-i.ri new file mode 100644 index 00000000..a5ca88cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/Rule/re-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/cdesc-State.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/cdesc-State.ri new file mode 100644 index 00000000..eab898d9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/cdesc-State.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/inspect-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/inspect-i.ri new file mode 100644 index 00000000..f7981d9c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/inspect-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/name-i.ri new file mode 100644 index 00000000..441d0f58 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/new-c.ri new file mode 100644 index 00000000..c3846754 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/rules-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/rules-i.ri new file mode 100644 index 00000000..78bb683d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/State/rules-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/appended-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/appended-i.ri new file mode 100644 index 00000000..5be8f995 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/appended-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/cdesc-StateDSL.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/cdesc-StateDSL.ri new file mode 100644 index 00000000..8ec7c419 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/cdesc-StateDSL.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/close%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/close%21-i.ri new file mode 100644 index 00000000..8860619d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/close%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/context_sensitive%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/context_sensitive%3f-i.ri new file mode 100644 index 00000000..8972ed5b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/context_sensitive%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/load%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/load%21-i.ri new file mode 100644 index 00000000..ef7bf5a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/load%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/mixin-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/mixin-i.ri new file mode 100644 index 00000000..09199018 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/mixin-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/name-i.ri new file mode 100644 index 00000000..1d3de4aa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/new-c.ri new file mode 100644 index 00000000..f6211716 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/prepended-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/prepended-i.ri new file mode 100644 index 00000000..453be7c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/prepended-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rule-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rule-i.ri new file mode 100644 index 00000000..0a958e05 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rule-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rules-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rules-i.ri new file mode 100644 index 00000000..65134395 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/rules-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/to_state-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/to_state-i.ri new file mode 100644 index 00000000..504867da Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/StateDSL/to_state-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/append-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/append-c.ri new file mode 100644 index 00000000..bab65aad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/append-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/cdesc-RegexLexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/cdesc-RegexLexer.ri new file mode 100644 index 00000000..f1de1e78 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/cdesc-RegexLexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/delegate-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/delegate-i.ri new file mode 100644 index 00000000..e80f992f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/delegate-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-c.ri new file mode 100644 index 00000000..36207c2f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-i.ri new file mode 100644 index 00000000..fba35c5c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/get_state-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/goto-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/goto-i.ri new file mode 100644 index 00000000..99582030 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/goto-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/group-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/group-i.ri new file mode 100644 index 00000000..fefc62d8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/group-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/groups-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/groups-i.ri new file mode 100644 index 00000000..5789c8f8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/groups-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/in_state%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/in_state%3f-i.ri new file mode 100644 index 00000000..9f139ac1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/in_state%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/pop%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/pop%21-i.ri new file mode 100644 index 00000000..94774d6f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/pop%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/prepend-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/prepend-c.ri new file mode 100644 index 00000000..c9791e1d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/prepend-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/push-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/push-i.ri new file mode 100644 index 00000000..dc982a13 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/push-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/recurse-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/recurse-i.ri new file mode 100644 index 00000000..022fb620 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/recurse-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/replace_state-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/replace_state-c.ri new file mode 100644 index 00000000..1f325d0b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/replace_state-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset%21-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset%21-i.ri new file mode 100644 index 00000000..9de1c082 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset%21-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset_stack-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset_stack-i.ri new file mode 100644 index 00000000..7c83e51f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/reset_stack-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stack-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stack-i.ri new file mode 100644 index 00000000..2656c9b0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stack-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start-c.ri new file mode 100644 index 00000000..28657af4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start_procs-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start_procs-c.ri new file mode 100644 index 00000000..88a6bef6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/start_procs-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state%3f-i.ri new file mode 100644 index 00000000..98bbbb50 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-c.ri new file mode 100644 index 00000000..46fb61fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-i.ri new file mode 100644 index 00000000..015e2d97 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state_definitions-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state_definitions-c.ri new file mode 100644 index 00000000..2ee775a1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/state_definitions-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/states-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/states-c.ri new file mode 100644 index 00000000..bc317958 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/states-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/step-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/step-i.ri new file mode 100644 index 00000000..7e29121d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/step-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stream_tokens-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stream_tokens-i.ri new file mode 100644 index 00000000..7a43b908 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/stream_tokens-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/token-i.ri new file mode 100644 index 00000000..4a9e3b65 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/yield_token-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/yield_token-i.ri new file mode 100644 index 00000000..72d3740f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/RegexLexer/yield_token-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/cdesc-TemplateLexer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/cdesc-TemplateLexer.ri new file mode 100644 index 00000000..bb4903a7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/cdesc-TemplateLexer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/parent-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/parent-i.ri new file mode 100644 index 00000000..4f7849f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TemplateLexer/parent-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/camelize-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/camelize-i.ri new file mode 100644 index 00000000..d3eba64a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/camelize-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/cdesc-TexThemeRenderer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/cdesc-TexThemeRenderer.ri new file mode 100644 index 00000000..378dd1d2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/cdesc-TexThemeRenderer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/gen_inline-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/gen_inline-i.ri new file mode 100644 index 00000000..24557c22 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/gen_inline-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/inline_name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/inline_name-i.ri new file mode 100644 index 00000000..55b58774 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/inline_name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/new-c.ri new file mode 100644 index 00000000..9532f7af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/palette_name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/palette_name-i.ri new file mode 100644 index 00000000..07189955 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/palette_name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render-i.ri new file mode 100644 index 00000000..3501b8ac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_blank-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_blank-i.ri new file mode 100644 index 00000000..f41451c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_blank-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_inline_pallete-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_inline_pallete-i.ri new file mode 100644 index 00000000..02a81ddf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_inline_pallete-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_palette-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_palette-i.ri new file mode 100644 index 00000000..cfb3629a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_palette-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_style-i.ri new file mode 100644 index 00000000..13238f7d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/render_style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/token_name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/token_name-i.ri new file mode 100644 index 00000000..841ab409 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TexThemeRenderer/token_name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/cdesc-TextAnalyzer.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/cdesc-TextAnalyzer.ri new file mode 100644 index 00000000..1a1b27fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/cdesc-TextAnalyzer.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype%3f-i.ri new file mode 100644 index 00000000..f3f4e355 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype-i.ri new file mode 100644 index 00000000..ea9a4548 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/doctype-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/lexes_cleanly%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/lexes_cleanly%3f-i.ri new file mode 100644 index 00000000..aa4fd9e6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/lexes_cleanly%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang%3f-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang%3f-i.ri new file mode 100644 index 00000000..7c9446d6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang%3f-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang-i.ri new file mode 100644 index 00000000..7e9927d8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/TextAnalyzer/shebang-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/cdesc-Style.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/cdesc-Style.ri new file mode 100644 index 00000000..2a4721b2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/cdesc-Style.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/new-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/new-c.ri new file mode 100644 index 00000000..0933e16f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/new-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/render-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/render-i.ri new file mode 100644 index 00000000..86fcd8e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/render-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/rendered_rules-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/rendered_rules-i.ri new file mode 100644 index 00000000..1e18584d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/Style/rendered_rules-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/base_style-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/base_style-c.ri new file mode 100644 index 00000000..10406760 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/base_style-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/cdesc-Theme.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/cdesc-Theme.ri new file mode 100644 index 00000000..2af96816 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/cdesc-Theme.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/find-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/find-c.ri new file mode 100644 index 00000000..ff3afee7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/find-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-c.ri new file mode 100644 index 00000000..c8b0f6ff Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-i.ri new file mode 100644 index 00000000..74fe97b3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_own_style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-c.ri new file mode 100644 index 00000000..04aae0f7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-i.ri new file mode 100644 index 00000000..e66efea9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/get_style-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-c.ri new file mode 100644 index 00000000..fddf0ebd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-i.ri new file mode 100644 index 00000000..24b3cafc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/name-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-c.ri new file mode 100644 index 00000000..7953a17e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-i.ri new file mode 100644 index 00000000..274191bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/palette-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/register-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/register-c.ri new file mode 100644 index 00000000..a2a2150c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/register-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/registry-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/registry-c.ri new file mode 100644 index 00000000..ca64d9f8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/registry-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/render-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/render-c.ri new file mode 100644 index 00000000..99e63cb8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/render-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/style-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/style-c.ri new file mode 100644 index 00000000..6f4e2665 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/style-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-c.ri new file mode 100644 index 00000000..ec768264 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-i.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-i.ri new file mode 100644 index 00000000..96142602 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Theme/styles-i.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Monokai/cdesc-Monokai.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Monokai/cdesc-Monokai.ri new file mode 100644 index 00000000..4dc24829 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Monokai/cdesc-Monokai.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Solarized/cdesc-Solarized.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Solarized/cdesc-Solarized.ri new file mode 100644 index 00000000..1898dba9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/Solarized/cdesc-Solarized.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/cdesc-Base16.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/cdesc-Base16.ri new file mode 100644 index 00000000..a584090f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/cdesc-Base16.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/dark%21-c.ri new file mode 100644 index 00000000..49916e87 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/light%21-c.ri new file mode 100644 index 00000000..93e6ae04 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_dark%21-c.ri new file mode 100644 index 00000000..ed90d07a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_light%21-c.ri new file mode 100644 index 00000000..4e5423c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Base16/make_light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/BlackWhiteTheme/cdesc-BlackWhiteTheme.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/BlackWhiteTheme/cdesc-BlackWhiteTheme.ri new file mode 100644 index 00000000..2bfcb774 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/BlackWhiteTheme/cdesc-BlackWhiteTheme.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Colorful/cdesc-Colorful.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Colorful/cdesc-Colorful.ri new file mode 100644 index 00000000..af211cd4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Colorful/cdesc-Colorful.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/cdesc-Github.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/cdesc-Github.ri new file mode 100644 index 00000000..9604d0fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/cdesc-Github.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/dark%21-c.ri new file mode 100644 index 00000000..2f27d772 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/light%21-c.ri new file mode 100644 index 00000000..72248c51 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_dark%21-c.ri new file mode 100644 index 00000000..832953ae Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_light%21-c.ri new file mode 100644 index 00000000..6a503802 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Github/make_light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/cdesc-Gruvbox.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/cdesc-Gruvbox.ri new file mode 100644 index 00000000..d5b24033 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/cdesc-Gruvbox.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/dark%21-c.ri new file mode 100644 index 00000000..92288667 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/light%21-c.ri new file mode 100644 index 00000000..8bae65a3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_dark%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_dark%21-c.ri new file mode 100644 index 00000000..d3c7dac4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_dark%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_light%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_light%21-c.ri new file mode 100644 index 00000000..b69d43a7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Gruvbox/make_light%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/IgorPro/cdesc-IgorPro.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/IgorPro/cdesc-IgorPro.ri new file mode 100644 index 00000000..61484421 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/IgorPro/cdesc-IgorPro.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Magritte/cdesc-Magritte.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Magritte/cdesc-Magritte.ri new file mode 100644 index 00000000..163824cb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Magritte/cdesc-Magritte.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Molokai/cdesc-Molokai.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Molokai/cdesc-Molokai.ri new file mode 100644 index 00000000..3531bf79 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Molokai/cdesc-Molokai.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Monokai/cdesc-Monokai.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Monokai/cdesc-Monokai.ri new file mode 100644 index 00000000..ca10f948 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Monokai/cdesc-Monokai.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/MonokaiSublime/cdesc-MonokaiSublime.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/MonokaiSublime/cdesc-MonokaiSublime.ri new file mode 100644 index 00000000..0b67893c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/MonokaiSublime/cdesc-MonokaiSublime.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Pastie/cdesc-Pastie.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Pastie/cdesc-Pastie.ri new file mode 100644 index 00000000..a15b05ca Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Pastie/cdesc-Pastie.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/ThankfulEyes/cdesc-ThankfulEyes.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/ThankfulEyes/cdesc-ThankfulEyes.ri new file mode 100644 index 00000000..196434f2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/ThankfulEyes/cdesc-ThankfulEyes.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Tulip/cdesc-Tulip.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Tulip/cdesc-Tulip.ri new file mode 100644 index 00000000..a31e21ab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/Tulip/cdesc-Tulip.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Themes/cdesc-Themes.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/cdesc-Themes.ri new file mode 100644 index 00000000..afee6ead Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Themes/cdesc-Themes.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/%5b%5d-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/%5b%5d-c.ri new file mode 100644 index 00000000..03835bfd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/%5b%5d-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/cdesc-Tokens.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/cdesc-Tokens.ri new file mode 100644 index 00000000..eb21d68e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/cdesc-Tokens.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/token-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/token-c.ri new file mode 100644 index 00000000..f5b65eeb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/Tokens/token-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/cache-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/cache-c.ri new file mode 100644 index 00000000..2152d8e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/cache-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/cdesc-Token.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/cdesc-Token.ri new file mode 100644 index 00000000..90c5e868 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/cdesc-Token.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/each_token-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/each_token-c.ri new file mode 100644 index 00000000..6a083ecf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/each_token-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/inspect-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/inspect-c.ri new file mode 100644 index 00000000..713be68c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/inspect-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/make_token-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/make_token-c.ri new file mode 100644 index 00000000..fb43afc1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/make_token-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/matches%3f-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/matches%3f-c.ri new file mode 100644 index 00000000..5a5a3cd3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/matches%3f-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/name-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/name-c.ri new file mode 100644 index 00000000..fe9a98ac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/name-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/parent-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/parent-c.ri new file mode 100644 index 00000000..fb005560 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/parent-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/qualname-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/qualname-c.ri new file mode 100644 index 00000000..7e5cd8e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/qualname-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/register%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/register%21-c.ri new file mode 100644 index 00000000..c3825845 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/register%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/shortname-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/shortname-c.ri new file mode 100644 index 00000000..e0a704e8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/shortname-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/sub_tokens-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/sub_tokens-c.ri new file mode 100644 index 00000000..0d284d3b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/sub_tokens-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/token-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/token-c.ri new file mode 100644 index 00000000..54491988 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/token-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/Token/token_chain-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/Token/token_chain-c.ri new file mode 100644 index 00000000..36bc23b9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/Token/token_chain-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/cdesc-Rouge.ri b/bin/doc/rouge-4.7.0/ri/Rouge/cdesc-Rouge.ri new file mode 100644 index 00000000..3f78352d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/cdesc-Rouge.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/highlight-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/highlight-c.ri new file mode 100644 index 00000000..a978e902 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/highlight-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/load_file-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/load_file-c.ri new file mode 100644 index 00000000..793c7bfb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/load_file-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/load_lexers-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/load_lexers-c.ri new file mode 100644 index 00000000..bfed7843 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/load_lexers-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/reload%21-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/reload%21-c.ri new file mode 100644 index 00000000..4736814c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/reload%21-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/Rouge/version-c.ri b/bin/doc/rouge-4.7.0/ri/Rouge/version-c.ri new file mode 100644 index 00000000..1e5323ee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/Rouge/version-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/cache.ri b/bin/doc/rouge-4.7.0/ri/cache.ri new file mode 100644 index 00000000..18483bad --- /dev/null +++ b/bin/doc/rouge-4.7.0/ri/cache.ri @@ -0,0 +1,95 @@ +{:ancestors{,I"Rouge::FileReader:ET[I" Object;TI"Rouge::CLI;T[I" Object;TI"Rouge::CLI::Error;T[I"StandardError;TI"Rouge::CLI::Version;T[I"Rouge::CLI;TI"Rouge::CLI::Help;T[@I"Rouge::CLI::Highlight;T[@I"Rouge::CLI::Debug;T[I"Rouge::CLI::Highlight;TI"Rouge::CLI::Style;T[@I"Rouge::CLI::List;T[@I"Rouge::CLI::Guess;T[@I"Rouge::Formatter;T[I" Object;TI"Rouge::Formatters::HTML;T[I"Rouge::Formatter;TI""Rouge::Formatters::HTMLInline;T[I"Rouge::Formatters::HTML;TI""Rouge::Formatters::HTMLLegacy;T[@%I"+Rouge::Formatters::HTMLLineHighlighter;T[@%I"%Rouge::Formatters::HTMLLineTable;T[@%I"$Rouge::Formatters::HTMLLinewise;T[@%I"$Rouge::Formatters::HTMLPygments;T[@%I"!Rouge::Formatters::HTMLTable;T[@%I"Rouge::Formatters::Null;T[@%I"#Rouge::Formatters::Terminal256;T[@%I"3Rouge::Formatters::Terminal256::EscapeSequence;T[I" Object;TI"-Rouge::Formatters::Terminal256::Unescape;T[I"3Rouge::Formatters::Terminal256::EscapeSequence;TI")Rouge::Formatters::TerminalTruecolor;T[I"#Rouge::Formatters::Terminal256;TI"BRouge::Formatters::TerminalTruecolor::TruecolorEscapeSequence;T[@>I"Rouge::Formatters::Tex;T[@%I"Rouge::Guesser;T[I" Object;TI"Rouge::Guesser::Ambiguous;T[I"StandardError;TI"$Rouge::Guessers::Disambiguation;T[I"Rouge::Guesser;TI"Rouge::Guessers::Util;TI"Rouge::Lexers;TI"3Rouge::Guessers::Disambiguation::Disambiguator;T[I" Object;T@OI"Rouge::Guessers::Filename;T[@NI"!Rouge::Guessers::GlobMapping;T[@N@OI"Rouge::Guessers::Mimetype;T[@NI"Rouge::Guessers::Modeline;T[@N@OI"Rouge::Guessers::Source;T[@N@OI"Rouge::Lexer;T[I" Object;TI"Rouge::Token::Tokens;TI"Rouge::Lexers::ABAP;T[I"RegexLexer;TI" Rouge::Lexers::Actionscript;T[I"RegexLexer;TI"Rouge::Lexers::Ada;T[I"RegexLexer;TI"Rouge::Lexers::Apache;T[I"RegexLexer;TI"Rouge::Lexers::Apex;T[I"RegexLexer;TI" Rouge::Lexers::APIBlueprint;T[I" Markdown;TI"Rouge::Lexers::AppleScript;T[I"RegexLexer;TI"Rouge::Lexers::ArmAsm;T[I"RegexLexer;TI"Rouge::Lexers::Augeas;T[I"RegexLexer;TI"Rouge::Lexers::Awk;T[I"RegexLexer;TI"Rouge::Lexers::Batchfile;T[I"RegexLexer;TI"Rouge::Lexers::BBCBASIC;T[I"RegexLexer;TI"Rouge::Lexers::BibTeX;T[I"RegexLexer;TI"Rouge::Lexers::Bicep;T[I"Rouge::RegexLexer;TI"Rouge::Lexers::BIML;T[I"XML;TI"Rouge::Lexers::BPF;T[I"RegexLexer;TI"Rouge::Lexers::Brainfuck;T[I"RegexLexer;TI" Rouge::Lexers::Brightscript;T[I"RegexLexer;TI"Rouge::Lexers::Bsl;T[I"RegexLexer;TI"Rouge::Lexers::C;T[I"RegexLexer;TI"Rouge::Lexers::Ceylon;T[I"RegexLexer;TI"Rouge::Lexers::Cfscript;T[I"RegexLexer;TI"Rouge::Lexers::CiscoIos;T[I"RegexLexer;TI"Rouge::Lexers::Clean;T[I"RegexLexer;TI"Rouge::Lexers::Clojure;T[I"RegexLexer;TI"Rouge::Lexers::CMake;T[I"RegexLexer;TI"Rouge::Lexers::CMHG;T[I"RegexLexer;TI"Rouge::Lexers::COBOL;T[I"RegexLexer;TI"Rouge::Lexers::Codeowners;T[I"RegexLexer;TI" Rouge::Lexers::Coffeescript;T[I"RegexLexer;TI"Rouge::Lexers::CommonLisp;T[I"RegexLexer;TI"Rouge::Lexers::Conf;T[I"RegexLexer;TI" Rouge::Lexers::ConsoleLexer;T[I"Rouge::Lexer;TI"Rouge::Lexers::Coq;T[I"RegexLexer;TI"Rouge::Lexers::Cpp;T[I"Rouge::Lexers::C;TI"Rouge::Lexers::Crystal;T[I"RegexLexer;TI"Rouge::Lexers::CSharp;T[I"RegexLexer;TI"Rouge::Lexers::CSS;T[I"RegexLexer;TI"Rouge::Lexers::CSVS;T[I"RegexLexer;TI"Rouge::Lexers::CUDA;T[I"Rouge::Lexers::Cpp;TI"Rouge::Lexers::Cypher;T[I"RegexLexer;TI"Rouge::Lexers::Cython;T[I" Python;TI"Rouge::Lexers::D;T[I"RegexLexer;TI"Rouge::Lexers::Dafny;T[I"RegexLexer;TI"Rouge::Lexers::Dart;T[I"RegexLexer;TI"Rouge::Lexers::Datastudio;T[I"RegexLexer;TI"Rouge::Lexers::Diff;T[I"RegexLexer;TI"Rouge::Lexers::Digdag;T[I" YAML;TI"Rouge::Lexers::Docker;T[I"RegexLexer;TI"Rouge::Lexers::Dot;T[I"RegexLexer;TI"Rouge::Lexers::ECL;T[I"RegexLexer;TI"Rouge::Lexers::EEX;T[I"TemplateLexer;TI"Rouge::Lexers::Eiffel;T[I"RegexLexer;TI"Rouge::Lexers::Elixir;T[I"RegexLexer;TI"Rouge::Lexers::Elm;T[I"RegexLexer;TI"Rouge::Lexers::Email;T[I"RegexLexer;TI"Rouge::Lexers::EPP;T[I"TemplateLexer;TI"Rouge::Lexers::ERB;T[I"TemplateLexer;TI"Rouge::Lexers::Erlang;T[I"RegexLexer;TI"Rouge::Lexers::Escape;T[@¿I"Rouge::Lexers::Factor;T[I"RegexLexer;TI"Rouge::Lexers::Fluent;T[I"RegexLexer;TI"Rouge::Lexers::Fortran;T[I"RegexLexer;TI"Rouge::Lexers::FreeFEM;T[@ÔI"Rouge::Lexers::FSharp;T[I"RegexLexer;TI"Rouge::Lexers::GDScript;T[I"RegexLexer;TI"Rouge::Lexers::GHCCmm;T[I"RegexLexer;TI"Rouge::Lexers::GHCCore;T[I"RegexLexer;TI"Rouge::Lexers::Gherkin;T[I"RegexLexer;TI"Rouge::Lexers::Gjs;T[I"Javascript;TI"Rouge::Lexers::Glsl;T[@ÅI"Rouge::Lexers::Go;T[I"RegexLexer;TI"Rouge::Lexers::Gradle;T[I" Groovy;TI"Rouge::Lexers::GraphQL;T[I"RegexLexer;TI"Rouge::Lexers::Groovy;T[I"RegexLexer;TI"Rouge::Lexers::Gts;T[I"Typescript;TI"Rouge::Lexers::Hack;T[I"PHP;TI"Rouge::Lexers::Haml;T[I"RegexLexer;TI"Rouge::Indentation;TI"Rouge::Lexers::Handlebars;T[I"TemplateLexer;TI"Rouge::Lexers::Haskell;T[I"RegexLexer;TI"Rouge::Lexers::Haxe;T[I"RegexLexer;TI"Rouge::Lexers::Hcl;T[I"RegexLexer;TI"Rouge::Lexers::HLSL;T[@ÅI"Rouge::Lexers::HOCON;T[I" JSON;TI"Rouge::Lexers::HQL;T[I"SQL;TI"Rouge::Lexers::HTML;T[I"RegexLexer;TI"Rouge::Lexers::HTTP;T[I"RegexLexer;TI"Rouge::Lexers::HyLang;T[I"RegexLexer;TI"Rouge::Lexers::IDLang;T[I"RegexLexer;TI"Rouge::Lexers::Idris;T[I"RegexLexer;TI"Rouge::Lexers::IecST;T[I"RegexLexer;TI"Rouge::Lexers::IgorPro;T[I"RegexLexer;TI"Rouge::Lexers::INI;T[I"RegexLexer;TI"Rouge::Lexers::IO;T[I"RegexLexer;TI"Rouge::Lexers::IRBLexer;T[I" Rouge::Lexers::ConsoleLexer;TI""Rouge::Lexers::IRBOutputLexer;T[I" Ruby;TI"Rouge::Lexers::Isabelle;T[I"RegexLexer;TI"Rouge::Lexers::ISBL;T[I"RegexLexer;TI"Rouge::Lexers::J;T[I"RegexLexer;TI"Rouge::Lexers::Janet;T[I"RegexLexer;TI"Rouge::Lexers::Java;T[I"RegexLexer;TI"Rouge::Lexers::Javascript;T[I"RegexLexer;TI"Rouge::Lexers::Jinja;T[I"TemplateLexer;TI"Rouge::Lexers::JSL;T[I"RegexLexer;TI"Rouge::Lexers::JSON;T[I"RegexLexer;TI"Rouge::Lexers::JSON5;T[I"Rouge::Lexers::JSON;TI"Rouge::Lexers::JSONDOC;T[@—I"Rouge::Lexers::Jsonnet;T[I"RegexLexer;TI"Rouge::Lexers::JSP;T[I"TemplateLexer;TI"Rouge::Lexers::JSX;T[I"Rouge::Lexers::Javascript;TI"Rouge::Lexers::Julia;T[I"RegexLexer;TI"Rouge::Lexers::Kotlin;T[I"RegexLexer;TI"Rouge::Lexers::Lasso;T[I"TemplateLexer;TI"Rouge::Lexers::Lean;T[I"RegexLexer;TI"Rouge::Lexers::Liquid;T[I"RegexLexer;TI"(Rouge::Lexers::LiterateCoffeescript;T[I"RegexLexer;TI"#Rouge::Lexers::LiterateHaskell;T[I"RegexLexer;TI"Rouge::Lexers::Livescript;T[I"RegexLexer;TI"Rouge::Lexers::LLVM;T[I"RegexLexer;TI"Rouge::Lexers::Lua;T[I"RegexLexer;TI"Rouge::Lexers::Lustre;T[I"RegexLexer;TI"Rouge::Lexers::Lutin;T[I"Rouge::Lexers::Lustre;TI"Rouge::Lexers::M68k;T[I"RegexLexer;TI"Rouge::Lexers::Magik;T[I"RegexLexer;TI"Rouge::Lexers::Make;T[I"RegexLexer;TI"Rouge::Lexers::Markdown;T[I"RegexLexer;TI"Rouge::Lexers::Mason;T[I"TemplateLexer;TI"Rouge::Lexers::Mathematica;T[I"RegexLexer;TI"Rouge::Lexers::Matlab;T[I"RegexLexer;TI"Rouge::Lexers::Meson;T[I"RegexLexer;TI")Rouge::Lexers::Meson::StringRegister;T[I" +Array;TI"Rouge::Lexers::MiniZinc;T[I"RegexLexer;TI"Rouge::Lexers::Mojo;T[I" Python;TI"Rouge::Lexers::Moonscript;T[I"RegexLexer;TI"Rouge::Lexers::Mosel;T[I"RegexLexer;TI"Rouge::Lexers::MsgTrans;T[I"RegexLexer;TI"Rouge::Lexers::MXML;T[I"RegexLexer;TI"Rouge::Lexers::Nasm;T[I"RegexLexer;TI"Rouge::Lexers::NesAsm;T[I"RegexLexer;TI"Rouge::Lexers::Nginx;T[I"RegexLexer;TI"Rouge::Lexers::Nial;T[I"RegexLexer;TI"Rouge::Lexers::Nim;T[I"RegexLexer;TI"Rouge::Lexers::Nix;T[I"RegexLexer;TI"Rouge::Lexers::ObjectiveC;T[@ÅI" Rouge::Lexers::ObjectiveCpp;T[@ÔI"Rouge::Lexers::OCaml;T[I"OCamlCommon;TI"Rouge::Lexers::OCamlCommon;T[I"RegexLexer;TI"Rouge::Lexers::OCL;T[I"RegexLexer;TI"Rouge::Lexers::OpenEdge;T[I"RegexLexer;TI"'Rouge::Lexers::OpenTypeFeatureFile;T[I"RegexLexer;TI"Rouge::Lexers::P4;T[I"RegexLexer;TI"Rouge::Lexers::Pascal;T[I"RegexLexer;TI"Rouge::Lexers::Perl;T[I"RegexLexer;TI"Rouge::Lexers::PHP;T[I"TemplateLexer;TI"Rouge::Lexers::PlainText;T[@¿I"Rouge::Lexers::Plist;T[I"RegexLexer;TI"Rouge::Lexers::PLSQL;T[I"RegexLexer;TI"Rouge::Lexers::Pony;T[I"RegexLexer;TI"Rouge::Lexers::PostScript;T[I"RegexLexer;TI"Rouge::Lexers::Powershell;T[I"RegexLexer;TI"Rouge::Lexers::Praat;T[I"RegexLexer;TI"Rouge::Lexers::Prolog;T[I"RegexLexer;TI"Rouge::Lexers::Prometheus;T[I"RegexLexer;TI"Rouge::Lexers::Properties;T[I"RegexLexer;TI"Rouge::Lexers::Protobuf;T[I"RegexLexer;TI"Rouge::Lexers::Puppet;T[I"RegexLexer;TI"Rouge::Lexers::Python;T[I"RegexLexer;TI"*Rouge::Lexers::Python::StringRegister;T[I" +Array;TI"Rouge::Lexers::Q;T[I"RegexLexer;TI"Rouge::Lexers::Qml;T[@¢I"Rouge::Lexers::R;T[I"RegexLexer;TI"Rouge::Lexers::Racket;T[I"RegexLexer;TI"Rouge::Lexers::ReasonML;T[I"Rouge::Lexers::OCamlCommon;TI"Rouge::Lexers::Rego;T[I"RegexLexer;TI"Rouge::Lexers::ReScript;T[@[I"Rouge::Lexers::RML;T[I"RegexLexer;TI""Rouge::Lexers::RobotFramework;T[I"RegexLexer;TI"Rouge::Lexers::Ruby;T[I"RegexLexer;TI"Rouge::Lexers::Rust;T[I"RegexLexer;TI"Rouge::Lexers::SAS;T[I"RegexLexer;TI"Rouge::Lexers::Sass;T[@DI"SassCommon;TI"Rouge::Lexers::SassCommon;T[I"RegexLexer;TI"Rouge::Lexers::Scala;T[I"RegexLexer;TI"Rouge::Lexers::Scheme;T[I"RegexLexer;TI"Rouge::Lexers::Scss;T[I"Rouge::Lexers::SassCommon;TI"Rouge::Lexers::Sed;T[I"RegexLexer;TI"Rouge::Lexers::Sed::Regex;T[I"RegexLexer;TI"$Rouge::Lexers::Sed::Replacement;T[I"RegexLexer;TI"Rouge::Lexers::Shell;T[I"RegexLexer;TI"Rouge::Lexers::Sieve;T[I"RegexLexer;TI"Rouge::Lexers::Slice;T[@ÅI"Rouge::Lexers::Slim;T[I"RegexLexer;T@DI"Rouge::Lexers::Smalltalk;T[I"RegexLexer;TI"Rouge::Lexers::Smarty;T[I"TemplateLexer;TI"Rouge::Lexers::SML;T[I"RegexLexer;TI"Rouge::Lexers::SPARQL;T[I"RegexLexer;TI"Rouge::Lexers::SQF;T[I"RegexLexer;TI"Rouge::Lexers::SQL;T[I"RegexLexer;TI"Rouge::Lexers::SSH;T[I"RegexLexer;TI"Rouge::Lexers::Stan;T[I"RegexLexer;TI"Rouge::Lexers::Stata;T[I"RegexLexer;TI"!Rouge::Lexers::SuperCollider;T[I"RegexLexer;TI"Rouge::Lexers::Svelte;T[I"Rouge::Lexers::HTML;TI"Rouge::Lexers::Swift;T[I"RegexLexer;TI"Rouge::Lexers::SystemD;T[I"RegexLexer;TI"Rouge::Lexers::Syzlang;T[I"RegexLexer;TI"Rouge::Lexers::Syzprog;T[I"RegexLexer;TI"Rouge::Lexers::Tap;T[I"RegexLexer;TI"Rouge::Lexers::TCL;T[I"RegexLexer;TI"Rouge::Lexers::Terraform;T[I"Rouge::Lexers::Hcl;TI"Rouge::Lexers::TeX;T[I"RegexLexer;TI"Rouge::Lexers::TOML;T[I"RegexLexer;TI"Rouge::Lexers::TSX;T[I"Rouge::Lexers::JSX;TI"Rouge::Lexers::TTCN3;T[I"RegexLexer;TI"Rouge::Lexers::Tulip;T[I"RegexLexer;TI"Rouge::Lexers::Turtle;T[I"RegexLexer;TI"Rouge::Lexers::Twig;T[I"Rouge::Lexers::Jinja;TI"Rouge::Lexers::Typescript;T[@¢I"Rouge::Lexers::Vala;T[I"RegexLexer;TI"Rouge::Lexers::Varnish;T[I"RegexLexer;TI"Rouge::Lexers::VisualBasic;T[I"RegexLexer;TI"Rouge::Lexers::Velocity;T[I"TemplateLexer;TI"Rouge::Lexers::Verilog;T[I"RegexLexer;TI"Rouge::Lexers::VHDL;T[I"RegexLexer;TI"Rouge::Lexers::VimL;T[I"RegexLexer;TI"Rouge::Lexers::Vue;T[@³I"Rouge::Lexers::Wollok;T[I"RegexLexer;TI"Rouge::Lexers::XML;T[I"RegexLexer;TI"Rouge::Lexers::Xojo;T[I"RegexLexer;TI"Rouge::Lexers::XPath;T[I"RegexLexer;TI"Rouge::Lexers::XQuery;T[I"Rouge::Lexers::XPath;TI"Rouge::Lexers::YAML;T[I"RegexLexer;TI"Rouge::Lexers::YANG;T[I"RegexLexer;TI"Rouge::Lexers::Zig;T[I"RegexLexer;TI"Rouge::RegexLexer;T[@¿I"$Rouge::RegexLexer::InvalidRegex;T[I"StandardError;TI"#Rouge::RegexLexer::ClosedState;T[I"StandardError;TI"Rouge::RegexLexer::Rule;T[I" Object;TI"Rouge::RegexLexer::State;T[I" Object;TI" Rouge::RegexLexer::StateDSL;T[I" Object;TI"Rouge::TemplateLexer;T[@†I"Rouge::TexThemeRenderer;T[I" Object;TI"Rouge::TextAnalyzer;T[I" String;TI"Rouge::Theme;T[I" Object;T@aI"Rouge::Theme::Style;T[I" Hash;TI"Rouge::CSSTheme;T[I"Rouge::Theme;TI"Rouge::Themes::Base16;T[I"Rouge::CSSTheme;TI"%Rouge::Themes::Base16::Solarized;T[I"Rouge::Themes::Base16;TI"#Rouge::Themes::Base16::Monokai;T[@6I"#Rouge::Themes::BlackWhiteTheme;T[@3I"Rouge::Themes::Colorful;T[@3I"Rouge::Themes::Github;T[@3I"Rouge::Themes::Gruvbox;T[@3I"Rouge::Themes::IgorPro;T[@3I"Rouge::Themes::Magritte;T[@3I"Rouge::Themes::Molokai;T[@3I"Rouge::Themes::Monokai;T[@3I""Rouge::Themes::MonokaiSublime;T[@3I"Rouge::Themes::Pastie;T[@3I" Rouge::Themes::ThankfulEyes;T[@3I"Rouge::Themes::Tulip;T[@3I"Rouge::Token;T[I" Object;TI"Rouge::InheritableHash;T[I" Hash;TI"Rouge::InheritableList;T[I"Enumerable;TI" Object;T:attributes{@[I"attr_reader input;T@ [I"attr_reader message;TI"attr_reader status;T@[ +I"attr_reader escape;TI"attr_reader formatter;TI"attr_reader input_file;TI"attr_reader lexer_name;TI"attr_reader mimetype;T@[I"attr_reader input_file;TI"attr_reader input_source;T@7[I"attr_reader theme;T@9[I"attr_reader style;T@I[I"attr_reader alternatives;T@T[I"attr_reader fname;T@V[I"attr_reader filename;TI"attr_reader glob_map;T@X[I"attr_reader mimetype;T@\[I"attr_reader source;T@^[I"attr_reader options;T@[I"attr_reader end;TI"attr_reader lang;TI"attr_reader start;T@A[I"attr_reader filters;T@%[I"attr_reader token;T@[I"attr_reader state;T@[I""attr_reader beginning_of_line;TI"attr_reader callback;TI"attr_reader re;T@[I"attr_reader name;TI"attr_reader rules;T@[I"attr_reader name;TI"attr_reader rules;T@Q[I"attr_reader name;TI"attr_reader parent;TI"attr_reader shortname;T:class_methods{Ð@[I"new;T@ +[ I"class_from_arg;TI"doc;TI" error!;T@•I"normalize_syntax;TI" +parse;T@ [@•@[I" desc;TI" +parse;T@[ I" desc;TI"doc;T@•I" +parse;T@[ I" desc;TI"doc;T@•I" +parse;TI"parse_cgi;TI"parse_opts;TI"supports_truecolor?;T@[I" desc;TI"doc;TI"parse_opts;T@[ I" desc;TI"doc;T@•I" +parse;T@[I" desc;TI"doc;TI" +parse;T@[I" desc;T@•I" +parse;T@ [ I"disable_escape!;TI"enable_escape!;TI"escape_enabled?;TI" find;TI" format;T@•I"tag;TI"with_escape;T@&[@•@)[@•@+[@•@-[@•@/[@•@1[@•@3[@•@5[@•@7[@•@9[ +I"closest_color;TI"color_index;TI" get_rgb;T@•I"xterm_colors;T@<[@•@D[@•@F[I" +guess;T@I[@•@L[I"disambiguate;TI"disambiguators;T@•@Q[@•@T[@•@V[I" by_pairs;T@•@X[@•@Z[@•@\[@•@^[#I" aliases;TI"all;TI"assert_utf8!;TI"continue_lex;TI"debug_enabled?;TI" demo;TI"demo_file;TI" desc;TI" detect?;TI"detectable?;TI"disable_debug!;TI"enable_debug!;TI"filenames;TI" find;TI"find_fancy;TI" +guess;TI"guess_by_filename;TI"guess_by_mimetype;TI"guess_by_source;TI" guesses;TI"lex;TI"lookup_fancy;TI"mimetypes;T@•I" option;TI"option_docs;TI" register;TI" registry;TI"tag;TI" +title;T@b[ I" builtins;TI" keywords;TI"new_keywords;TI" +types;T@e[ +I" builtins;TI"constants;TI"declarations;TI" keywords;TI" reserved;T@h[I" idents;T@k[I"directives;TI" sections;TI" values;T@n[ +I"constants;TI"declarations;TI" keywords;TI" soql;TI" +types;T@t[I" builtins;TI" classes;TI" commands;TI" controls;TI"declarations;TI"handler_params;TI" literals;TI"operators;TI"references;TI" reserved;TI"studio_classes;TI"studio_commands;TI"studio_events;TI"studio_properties;T@w[ I" builtin;TI"file_directive;TI"general_directive;TI" operator;TI"preproc_keyword;TI"shift_or_condition;T@z[I" reserved;T@}[ I" builtins;TI"constants;TI"declarations;TI" detect?;TI" keywords;TI" reserved;T@{[ I"attributes;TI"builtin_commands;TI" devices;TI" keywords;TI"operator_words;TI"other_commands;T@~[ +I" constant;TI" function;TI" operator;TI"punctuation;TI"statement;T@„[I"datatypes;TI"functions;TI" keywords;T@‡[I" detect?;T@�[ I" builtins;TI"keyword_reserved;TI"!keyword_reserved_unsupported;TI"keyword_type;TI"name_builtin;TI"operator_word;T@–[ I" builtins;TI" keywords;TI"keywords_type;TI" reserved;T@œ[I"declarations;TI" keywords;TI" +types;T@¢[I" keywords;T@¥[I" builtins;TI" keywords;T@«[I"preproc_keyword;T@®[I"divisions;TI" keywords;TI" sections;T@´[ +I" builtins;TI"constants;TI" detect?;TI" keywords;TI" reserved;T@½[@•@À[ I" classify;TI"coq;TI" gallina;TI" ltac;TI"tacticals;TI"terminators;T@Ã[I" keywords;TI"keywords_type;TI" reserved;T@Æ[I" detect?;T@É[I"cpp_keywords;TI" keywords;TI"keywords_type;T@Ì[ +I" builtins;TI" colors;TI"functions;TI"properties;TI"vendor_prefixes;T@Ò[I" keywords;TI"keywords_type;T@Õ[I"functions;TI" keywords;TI"predicates;T@Ø[I"c_keywords;TI" keywords;T@•@ä[I"sql_keywords;T@ç[I" detect?;T@ó[ I"class_first;TI"class_second;TI"functions;TI" keywords;TI" template;TI" type;TI" +typed;T@ö[@•@ü[I" detect?;T@[@•@[@•@[@•@[I" builtins;TI" detect?;T@[I"intrinsics;TI" keywords;TI" +types;T@[ +I"attributes;TI" builtins;TI" keywords;TI"keywords_type;TI" reserved;T@[ I" keyopts;TI" keywords;TI"primitives;TI"word_operators;T@[ I" builtins;TI"builtins_type;TI" keywords;TI"keywords_reserved;T@'[I" detect?;TI" keywords;TI"step_regex;T@*[@•@-[ I" builtins;TI" keywords;TI"keywords_type;TI" reserved;T@2[I" keywords;TI" +types;T@8[ +I"constants;TI"declarations;TI" detect?;TI" keywords;TI" +types;T@;[@•@>[I" detect?;TI" keywords;T@A[@•@H[I" detect?;T@K[ I" builtins;TI"constants;TI"declarations;TI" detect?;TI" imports;TI" keywords;TI" reserved;T@N[ +I" builtins;TI"constants;TI"declarations;TI" keywords;TI" reserved;T@Q[ I" builtins;TI" keywords;TI"keywords_type;TI" reserved;T@V[I" keywords;TI"keywords_type;T@Y[I" detect?;T@\[I"http_methods;T@_[I" builtins;TI" keywords;T@b[ I"conditionals;TI"decorators;TI"exec_unit;TI" keywords;TI"operators;TI" routines;TI"standalone_statements;T@e[I" +ascii;TI"prelude_functions;TI"reserved_keywords;T@h[ I" keywords;TI" literals;TI"operators;TI" +types;T@k[ I"igorConstants;TI"igorDeclarations;TI"igorFunction;TI"igorOperation;TI" keywords;TI"object_name;TI"preprocessor;T@q[I" builtins;TI"constants;TI" detect?;T@z[I"keyword_abandon_proof;TI"keyword_diag;TI"keyword_minor;TI"keyword_proof_asm;TI"keyword_proof_asm_goal;TI"keyword_proof_block;TI"keyword_proof_chain;TI"keyword_proof_decl;TI"keyword_proof_goal;TI"keyword_proof_script;TI"keyword_qed;TI"keyword_section;TI"keyword_subsection;TI"keyword_theory_decl;TI"keyword_theory_goal;TI"keyword_theory_script;TI"keyword_thy;T@}[ +I" builtins;TI"constants;TI" globals;TI"interfaces;TI" keywords;T@€[ I"control_words;TI"control_words_id;TI"inflection_list;TI"primitive;TI"primitive_table;TI"token_map;T@ƒ[I" bundled;TI" specials;T@‰[ I" builtins;TI"constants;TI"declarations;TI" detect?;TI" id_regex;TI" keywords;TI" reserved;T@Œ[ I" keywords;TI"pseudo_keywords;TI" +tests;TI"word_operators;T@š[ I" builtins;TI"constants;TI"declarations;TI" keywords;T@�[@•@£[I" detect?;T@©[I" detect?;TI" keywords;T@•@¬[I" keywords;TI"operators;TI" +types;T@¸[ I" builtins;TI"constants;TI"declarations;TI" detect?;TI" keywords;TI"loop_control_keywords;T@»[I"instructions;TI" keywords;TI" +types;T@¾[I" builtins;TI" detect?;T@•@Á[I" keywords;TI"primitives;TI"word_operators;T@Ä[I" keywords;TI"primitives;TI"word_operators;T@Ç[ I" builtins;TI" keywords;TI"keywords_type;TI" reserved;T@Ê[I"character;TI" decimal;TI" digits;TI" exponent;TI"global_ref;TI"identifier;TI" keywords;TI" +label;TI" number;TI"package_identifier;TI"piped_identifier;TI" +radix;TI"simple_identifier;TI"string_double;TI"string_single;TI" symbol;T@Í[I"functions;T@•@Ó[@•@Ö[I" builtins;TI" keywords;T@Ù[I" builtins;TI" keywords;T@Ü[I"builtin_functions;TI"builtin_variables;TI" keywords;T@â[ I" builtins;TI" keywords;TI"keywords_type;TI"operators;T@å[I" builtins;TI" detect?;TI" keywords;T@è[I" detect?;T@•@÷[I" keywords;TI"keywords_reserved;TI"keywords_type;T@ý[ I" consts;TI" +funcs;TI" keywords;TI"operators;TI"punctuations;TI"transformers;T@[I"underscorize;T@ +[I" keywords;T@ [I" keywords;TI"primitives;TI"word_operators;T@[ +I" builtins;TI"functions;TI" keywords;TI"keywords_type;TI"operators;T@[I" keywords;TI"keywords_prepro;TI"keywords_type;T@[I" keywords;T@[ I" builtins;TI" +decls;TI" keywords;TI"operators;T@[I" detect?;T@"[ I" builtins;TI" detect?;TI" keywords;T@•@%[@•@*[ I" keywords;TI"keywords_func;TI"keywords_reserved;TI"keywords_type;T@0[I" detect?;T@6[I" detect?;TI"functions_array;TI"functions_builtin;TI"functions_matrix;TI"functions_numeric;TI"functions_string;TI"functions_string_vector;TI" keywords;TI"object_attributes;TI" objects;TI"variables_numeric;TI"variables_string;T@<[I"functions;T@E[ I"constants;TI" detect?;TI" keywords;TI"metaparameters;T@H[ +I" builtins;TI"builtins_pseudo;TI" detect?;TI"exceptions;TI" keywords;T@N[I" builtins;TI" keywords;TI"word_operators;T@S[I" detect?;T@V[I" builtins;TI" detect?;TI" keywords;T@Y[I" keywords;T@\[I"constants;TI"operators;T@_[I" keywords;TI" +types;TI"word_operators;T@a[I"arithmetic_keywords;TI" keywords;T@d[@•I"settings_with_args;TI"settings_with_keywords;T@g[I" detect?;T@j[I" builtins;TI" detect?;TI" keywords;T@m[ I"data_step_statements;TI"proc_keywords;TI"sas_auto_macro_vars;TI"sas_functions;TI"sas_macro_functions;TI"sas_macro_statements;TI"sas_proc_names;T@y[I" builtins;TI" keywords;T@[I" detect?;T@ˆ[I" detect?;T@‹[I" actions;TI" controls;TI" +tests;T@Ž[I" keywords;TI"keywords_type;T@–[I" builtins;T@™[I" keywords;TI"symbolic_reserved;T@œ[I" builtins;TI" keywords;T@Ÿ[ I" commands;TI"constants;TI"controlflow;TI"diag_commands;TI"initializers;TI"namespaces;TI"wordoperators;T@¢[I" keywords;TI"keywords_type;T@¨[ I"builtin_functions;TI"constants;TI"distributions;TI" keywords;TI" reserved;TI" +types;T@«[I"reserved_keywords;TI"type_keywords;T@®[I"constants;TI" keywords;TI" reserved;T@±[@•@º[I" keywords;TI"keywords_type;T@½[I" keywords;T@Ã[I" detect?;TI"gen_command_state;TI"gen_delimiter_states;T@Æ[ +I" builtins;TI"constants;TI"declarations;TI" keywords;TI" reserved;T@É[I" detect?;T@Ò[I" keywords;TI" reserved;TI" +types;T@Õ[I" detect?;T@Û[ I" keywords;TI"pseudo_keywords;TI" +tests;TI"word_operators;T@ã[I"functions;TI" keywords;TI"variables;T@æ[ I" builtins;TI" keywords;TI"keywords_type;TI"operator_words;T@ì[I" keywords;TI"keywords_system_task;TI"keywords_type;T@ï[I" keywords;TI"keywords_type;TI"operator_words;T@ò[I" keywords;T@õ[@•@ú[I" detect?;T@[I" axes;TI"commentStart;TI"constructorTypes;TI"decimalLiteral;TI" digits;TI"doubleLiteral;TI" eqName;TI" keywords;TI" kindTest;TI"kindTestForPI;TI" ncName;TI"openParen;TI"operators;TI" +qName;TI"stringLiteral;TI" uriQName;TI"word_operators;T@[I" keywords;T@[I" detect?;T@ [I"body_stmts_keywords;TI"constants_keywords;TI"data_def_stmts_keywords;TI"linkage_stmts_keywords;TI"list_stmts_keywords;TI"meta_stmts_keywords;TI"!module_header_stmts_keywords;TI"top_stmts_keywords;TI"type_stmts_keywords;TI" +types;T@ [I" builtins;TI" keywords;T@[I" append;TI"get_state;TI" prepend;TI"replace_state;TI" +start;TI"start_procs;TI" +state;TI"state_definitions;TI" states;T@[@•@[@•@[@•@[@•@[@•@"[@•@([I"base_style;TI" find;TI"get_own_style;TI"get_style;TI" name;TI" palette;TI" register;TI" registry;TI" render;TI" +style;TI" styles;T@+[@•@.[@•@1[ I" +dark!;TI" light!;TI"make_dark!;TI"make_light!;T@=[ I" +dark!;TI" light!;TI"make_dark!;TI"make_light!;T@?[ I" +dark!;TI" light!;TI"make_dark!;TI"make_light!;T@Q[I"[];TI" +cache;TI"each_token;TI" inspect;TI"make_token;TI" matches?;TI" name;TI" parent;TI" qualname;TI"register!;TI"shortname;TI"sub_tokens;TI" +token;TI"token_chain;T@T[@•@W[@•I" +Rouge;T[ +I"highlight;TI"load_file;TI"load_lexers;TI" reload!;TI" version;TI",Rouge::Guessers::Util::SourceNormalizer;T[I"normalize;TI"Rouge::Lexers;T[I"load_lexer;TI"$Rouge::Lexers::ObjectiveCCommon;T[I" extended;TI"$Rouge::Lexers::TypescriptCommon;T[I" extended;TI"Rouge::Token::Tokens;T[I" +token;T:c_class_variables{: c_singleton_class_variables{: encodingIu: Encoding +UTF-8;F:instance_methods{Y@[I" file;TI" +input;TI" read;T@ +[I" error!;T@ [I" message;TI" status;T@[I"run;T@[I"run;T@[I" escape;TI"escape_lexer;TI"formatter;TI" +input;TI"input_file;TI"input_stream;TI" +lexer;TI"lexer_class;TI"lexer_name;TI" mimetype;TI"raw_lexer;TI"run;T@[I"run;T@[I"run;T@[ I"input_file;TI"input_source;TI" lexers;TI"run;T@ [ I" escape?;TI"filter_escapes;TI" format;TI" render;TI" stream;TI"token_lines;T@#[ I"escape_special_html_chars;TI"safe_span;TI" span;TI" stream;T@&[I"safe_span;T@)[I" stream;T@+[I" stream;T@-[I" stream;T@/[I" stream;T@1[I" stream;T@3[I" stream;TI" +style;T@5[I" stream;T@7[I" stream;TI" +theme;T@9[ I"bg;TI" escape;TI"fg;TI"reset_string;TI"stream_value;TI" +style;TI"style_string;T@<[ I"escape_sequence;TI"get_style;TI"make_escape_sequence;TI"reset_string;TI"stream_value;TI"style_string;TI"text_style;T@?[I"make_escape_sequence;T@B[I" get_rgb;TI"style_string;T@D[ +I"escape_tex;TI"hphantom_tag;TI"render_line;TI" stream;TI"tag;T@F[I"collect_best;TI" filter;T@I[I"alternatives;TI" message;T@L[I"contains?;TI" filter;TI" matches?;T@Q[I" decide!;TI" match?;T@T[I" filter;TI" +fname;T@V[I" filename;TI" filter;TI" glob_map;T@X[I" filter;TI" mimetype;T@Z[I" filter;T@\[I" filter;TI" source;T@^[I" as_bool;TI" as_lexer;TI" as_list;TI"as_string;TI" as_token;TI"bool_option;TI"continue_lex;TI"hash_option;TI"lex;TI"lexer_option;TI"list_option;TI" options;TI" reset!;TI"stream_tokens;TI"string_option;TI"tag;TI"token_option;TI" with;T@k[I"name_for_token;T@¥[I"name_token;T@½[I"allow_comments?;TI"comment_regex;TI"end_chars;TI"error_regex;TI"lang_lexer;TI"line_regex;TI"output_lexer;TI"process_line;TI"prompt_prefix_regex;TI"prompt_regex;TI"stream_tokens;T@[ I"end;TI" lang;TI" +start;TI"stream_tokens;TI"to_end_regex;TI"to_start_regex;T@A[ I" filters;TI" html;TI" ruby;TI" +ruby!;T@\[I"content_lexer;TI"guess_content_lexer;T@_[I"name_token;T@t[ I"allow_comments?;TI"lang_lexer;TI"output_lexer;TI"prompt_regex;T@z[I" word;T@ƒ[I"name_token;T@©[I"start_inline?;T@²[I" coffee;TI" markdown;T@µ[I" haskell;T@¾[I" builtins;T@Ð[I" html;T@Ü[I"current_string;T@ß[ I" delim?;TI" register;TI" remove;TI" +type?;T@è[I" builtins;T@"[I" builtins;T@%[I"stream_tokens;TI" +token;T@H[I"current_string;T@K[ I" delim?;TI" register;TI" remove;TI" +type?;T@j[I"macro_closed?;T@[I" +regex;TI"replacement;T@�[I" filters;TI" html;TI" ruby;T@™[I"token_for_final_id;TI"token_for_id;TI"token_for_id_with_dot;T@õ[I"lookup_lang;T@÷[I"any;TI" entities;T@[ I"continue_indent;TI" dedent?;TI" indent;TI" indent?;TI"reset_indent;TI"save_indent;TI"set_indent;T@[I" delegate;TI"get_state;TI" goto;TI" +group;TI" groups;TI"in_state?;TI" pop!;TI" push;TI" recurse;TI" reset!;TI"reset_stack;TI" +stack;TI" +state;TI" state?;TI" step;TI"stream_tokens;TI" +token;TI"yield_token;T@[I" to_s;T@[I" rule;TI" +state;TI" to_s;T@[ I"beginning_of_line;TI" callback;TI" inspect;TI"re;T@[I" inspect;TI" name;TI" +rules;T@[I" appended;TI" close!;TI"context_sensitive?;TI" +load!;TI" +mixin;TI" name;TI"prepended;TI" rule;TI" +rules;TI" to_state;T@ [I" parent;T@"[I" camelize;TI"gen_inline;TI"inline_name;TI"palette_name;TI" render;TI"render_blank;TI"render_inline_pallete;TI"render_palette;TI"render_style;TI"token_name;T@%[ +I" doctype;TI" doctype?;TI"lexes_cleanly?;TI" shebang;TI" shebang?;T@([ +I"get_own_style;TI"get_style;TI" name;TI" palette;TI" styles;T@+[I" render;TI"rendered_rules;T@.[ I"css_selector;TI"inflate_token;TI" render;TI"render_base;TI"single_css_selector;TI"style_for;T@T[ I"[];TI" each;TI" include?;TI" keys;TI" own_keys;TI" parent;T@W[ +I"<<;TI" each;TI"own_entries;TI" parent;TI" push;TI"Rouge::Guessers::Util;T[I"get_source;TI"test_glob;T@Ì[I"at_builtins;TI"at_keywords;TI" builtins;T@Ï[ I" builtins;TI"declarations;TI" keywords;TI" reserved;TI"Rouge::Plugins::Redcarpet;T[I"block_code;TI"rouge_formatter;TI"Rouge::HasModes;T[ I" get_mode;TI" mode;TI" +mode!;TI"set_mode!;TI"Rouge::Indentation;T[I"indentation;TI" reset!;TI"starts_block;T: main0: modules[:I" +Rouge;T@I"Rouge::CLI::Debug;TI"Rouge::CLI::Error;TI"Rouge::CLI::Guess;TI"Rouge::CLI::Help;T@I"Rouge::CLI::List;TI"Rouge::CLI::Style;TI"Rouge::CLI::Version;T@3I"Rouge::FileReader;T@%I"Rouge::Formatters;T@(I""Rouge::Formatters::HTMLInline;TI""Rouge::Formatters::HTMLLegacy;TI"+Rouge::Formatters::HTMLLineHighlighter;TI"%Rouge::Formatters::HTMLLineTable;TI"$Rouge::Formatters::HTMLLinewise;TI"$Rouge::Formatters::HTMLPygments;TI"!Rouge::Formatters::HTMLTable;TI"Rouge::Formatters::Null;T@A@>I"-Rouge::Formatters::Terminal256::Unescape;TI")Rouge::Formatters::TerminalTruecolor;TI"BRouge::Formatters::TerminalTruecolor::TruecolorEscapeSequence;TI"Rouge::Formatters::Tex;T@NI"Rouge::Guesser::Ambiguous;TI"Rouge::Guessers;TI"$Rouge::Guessers::Disambiguation;TI"3Rouge::Guessers::Disambiguation::Disambiguator;TI"Rouge::Guessers::Filename;TI"!Rouge::Guessers::GlobMapping;TI"Rouge::Guessers::Mimetype;TI"Rouge::Guessers::Modeline;TI"Rouge::Guessers::Source;T@OI",Rouge::Guessers::Util::SourceNormalizer;TI"Rouge::HasModes;T@DI"Rouge::InheritableHash;TI"Rouge::InheritableList;T@¿@PI"Rouge::Lexers::ABAP;TI" Rouge::Lexers::APIBlueprint;TI" Rouge::Lexers::Actionscript;TI"Rouge::Lexers::Ada;TI"Rouge::Lexers::Apache;TI"Rouge::Lexers::Apex;TI"Rouge::Lexers::AppleScript;TI"Rouge::Lexers::ArmAsm;TI"Rouge::Lexers::Augeas;TI"Rouge::Lexers::Awk;TI"Rouge::Lexers::BBCBASIC;TI"Rouge::Lexers::BIML;TI"Rouge::Lexers::BPF;TI"Rouge::Lexers::Batchfile;TI"Rouge::Lexers::BibTeX;TI"Rouge::Lexers::Bicep;TI"Rouge::Lexers::Brainfuck;TI" Rouge::Lexers::Brightscript;TI"Rouge::Lexers::Bsl;T@ÅI"Rouge::Lexers::CMHG;TI"Rouge::Lexers::CMake;TI"Rouge::Lexers::COBOL;TI"Rouge::Lexers::CSS;TI"Rouge::Lexers::CSVS;TI"Rouge::Lexers::CSharp;TI"Rouge::Lexers::CUDA;TI"Rouge::Lexers::Ceylon;TI"Rouge::Lexers::Cfscript;TI"Rouge::Lexers::CiscoIos;TI"Rouge::Lexers::Clean;TI"Rouge::Lexers::Clojure;TI"Rouge::Lexers::Codeowners;TI" Rouge::Lexers::Coffeescript;TI"Rouge::Lexers::CommonLisp;TI"Rouge::Lexers::Conf;T@vI"Rouge::Lexers::Coq;T@ÔI"Rouge::Lexers::Crystal;TI"Rouge::Lexers::Cypher;TI"Rouge::Lexers::Cython;TI"Rouge::Lexers::D;TI"Rouge::Lexers::Dafny;TI"Rouge::Lexers::Dart;TI"Rouge::Lexers::Datastudio;TI"Rouge::Lexers::Diff;TI"Rouge::Lexers::Digdag;TI"Rouge::Lexers::Docker;TI"Rouge::Lexers::Dot;TI"Rouge::Lexers::ECL;TI"Rouge::Lexers::EEX;TI"Rouge::Lexers::EPP;TI"Rouge::Lexers::ERB;TI"Rouge::Lexers::Eiffel;TI"Rouge::Lexers::Elixir;TI"Rouge::Lexers::Elm;TI"Rouge::Lexers::Email;TI"Rouge::Lexers::Erlang;TI"Rouge::Lexers::Escape;TI"Rouge::Lexers::FSharp;TI"Rouge::Lexers::Factor;TI"Rouge::Lexers::Fluent;TI"Rouge::Lexers::Fortran;TI"Rouge::Lexers::FreeFEM;TI"Rouge::Lexers::GDScript;TI"Rouge::Lexers::GHCCmm;TI"Rouge::Lexers::GHCCore;TI"Rouge::Lexers::Gherkin;TI"Rouge::Lexers::Gjs;TI"Rouge::Lexers::Glsl;TI"Rouge::Lexers::Go;TI"Rouge::Lexers::Gradle;TI"Rouge::Lexers::GraphQL;TI"Rouge::Lexers::Groovy;TI"Rouge::Lexers::Gts;TI"Rouge::Lexers::HLSL;TI"Rouge::Lexers::HOCON;TI"Rouge::Lexers::HQL;T@³I"Rouge::Lexers::HTTP;TI"Rouge::Lexers::Hack;TI"Rouge::Lexers::Haml;TI"Rouge::Lexers::Handlebars;TI"Rouge::Lexers::Haskell;TI"Rouge::Lexers::Haxe;T@ÈI"Rouge::Lexers::HyLang;TI"Rouge::Lexers::IDLang;TI"Rouge::Lexers::INI;TI"Rouge::Lexers::IO;TI"Rouge::Lexers::IRBLexer;TI""Rouge::Lexers::IRBOutputLexer;TI"Rouge::Lexers::ISBL;TI"Rouge::Lexers::Idris;TI"Rouge::Lexers::IecST;TI"Rouge::Lexers::IgorPro;TI"Rouge::Lexers::Isabelle;TI"Rouge::Lexers::J;TI"Rouge::Lexers::JSL;T@—I"Rouge::Lexers::JSON5;TI"Rouge::Lexers::JSONDOC;TI"Rouge::Lexers::JSP;T@ÑI"Rouge::Lexers::Janet;TI"Rouge::Lexers::Java;T@¢@ÝI"Rouge::Lexers::Jsonnet;TI"Rouge::Lexers::Julia;TI"Rouge::Lexers::Kotlin;TI"Rouge::Lexers::LLVM;TI"Rouge::Lexers::Lasso;TI"Rouge::Lexers::Lean;TI"Rouge::Lexers::Liquid;TI"(Rouge::Lexers::LiterateCoffeescript;TI"#Rouge::Lexers::LiterateHaskell;TI"Rouge::Lexers::Livescript;TI"Rouge::Lexers::Lua;T@ÆI"Rouge::Lexers::Lutin;TI"Rouge::Lexers::M68k;TI"Rouge::Lexers::MXML;TI"Rouge::Lexers::Magik;TI"Rouge::Lexers::Make;TI"Rouge::Lexers::Markdown;TI"Rouge::Lexers::Mason;TI"Rouge::Lexers::Mathematica;TI"Rouge::Lexers::Matlab;TI"Rouge::Lexers::Meson;TI")Rouge::Lexers::Meson::StringRegister;TI"Rouge::Lexers::MiniZinc;TI"Rouge::Lexers::Mojo;TI"Rouge::Lexers::Moonscript;TI"Rouge::Lexers::Mosel;TI"Rouge::Lexers::MsgTrans;TI"Rouge::Lexers::Nasm;TI"Rouge::Lexers::NesAsm;TI"Rouge::Lexers::Nginx;TI"Rouge::Lexers::Nial;TI"Rouge::Lexers::Nim;TI"Rouge::Lexers::Nix;TI"Rouge::Lexers::OCL;TI"Rouge::Lexers::OCaml;T@[I"Rouge::Lexers::ObjectiveC;TI"$Rouge::Lexers::ObjectiveCCommon;TI" Rouge::Lexers::ObjectiveCpp;TI"Rouge::Lexers::OpenEdge;TI"'Rouge::Lexers::OpenTypeFeatureFile;TI"Rouge::Lexers::P4;TI"Rouge::Lexers::PHP;TI"Rouge::Lexers::PLSQL;TI"Rouge::Lexers::Pascal;TI"Rouge::Lexers::Perl;TI"Rouge::Lexers::PlainText;TI"Rouge::Lexers::Plist;TI"Rouge::Lexers::Pony;TI"Rouge::Lexers::PostScript;TI"Rouge::Lexers::Powershell;TI"Rouge::Lexers::Praat;TI"Rouge::Lexers::Prolog;TI"Rouge::Lexers::Prometheus;TI"Rouge::Lexers::Properties;TI"Rouge::Lexers::Protobuf;TI"Rouge::Lexers::Puppet;TI"Rouge::Lexers::Python;TI"*Rouge::Lexers::Python::StringRegister;TI"Rouge::Lexers::Q;TI"Rouge::Lexers::Qml;TI"Rouge::Lexers::R;TI"Rouge::Lexers::RML;TI"Rouge::Lexers::Racket;TI"Rouge::Lexers::ReScript;TI"Rouge::Lexers::ReasonML;TI"Rouge::Lexers::Rego;TI""Rouge::Lexers::RobotFramework;TI"Rouge::Lexers::Ruby;TI"Rouge::Lexers::Rust;TI"Rouge::Lexers::SAS;TI"Rouge::Lexers::SML;TI"Rouge::Lexers::SPARQL;TI"Rouge::Lexers::SQF;TI"Rouge::Lexers::SQL;TI"Rouge::Lexers::SSH;TI"Rouge::Lexers::Sass;T@~I"Rouge::Lexers::Scala;TI"Rouge::Lexers::Scheme;TI"Rouge::Lexers::Scss;TI"Rouge::Lexers::Sed;TI"Rouge::Lexers::Sed::Regex;TI"$Rouge::Lexers::Sed::Replacement;TI"Rouge::Lexers::Shell;TI"Rouge::Lexers::Sieve;TI"Rouge::Lexers::Slice;TI"Rouge::Lexers::Slim;TI"Rouge::Lexers::Smalltalk;TI"Rouge::Lexers::Smarty;TI"Rouge::Lexers::Stan;TI"Rouge::Lexers::Stata;TI"!Rouge::Lexers::SuperCollider;TI"Rouge::Lexers::Svelte;TI"Rouge::Lexers::Swift;TI"Rouge::Lexers::SystemD;TI"Rouge::Lexers::Syzlang;TI"Rouge::Lexers::Syzprog;TI"Rouge::Lexers::TCL;TI"Rouge::Lexers::TOML;TI"Rouge::Lexers::TSX;TI"Rouge::Lexers::TTCN3;TI"Rouge::Lexers::Tap;TI"Rouge::Lexers::TeX;TI"Rouge::Lexers::Terraform;TI"Rouge::Lexers::Tulip;TI"Rouge::Lexers::Turtle;TI"Rouge::Lexers::Twig;TI"Rouge::Lexers::Typescript;TI"$Rouge::Lexers::TypescriptCommon;TI"Rouge::Lexers::VHDL;TI"Rouge::Lexers::Vala;TI"Rouge::Lexers::Varnish;TI"Rouge::Lexers::Velocity;TI"Rouge::Lexers::Verilog;TI"Rouge::Lexers::VimL;TI"Rouge::Lexers::VisualBasic;TI"Rouge::Lexers::Vue;TI"Rouge::Lexers::Wollok;TI"Rouge::Lexers::XML;T@I"Rouge::Lexers::XQuery;TI"Rouge::Lexers::Xojo;TI"Rouge::Lexers::YAML;TI"Rouge::Lexers::YANG;TI"Rouge::Lexers::Zig;TI"Rouge::Plugins;TI"Rouge::Plugins::Redcarpet;T@†I"#Rouge::RegexLexer::ClosedState;TI"$Rouge::RegexLexer::InvalidRegex;TI"Rouge::RegexLexer::Rule;TI"Rouge::RegexLexer::State;TI" Rouge::RegexLexer::StateDSL;TI"Rouge::TemplateLexer;TI"Rouge::TexThemeRenderer;TI"Rouge::TextAnalyzer;T@0I"Rouge::Theme::Style;TI"Rouge::Themes;T@6I"#Rouge::Themes::Base16::Monokai;TI"%Rouge::Themes::Base16::Solarized;TI"#Rouge::Themes::BlackWhiteTheme;TI"Rouge::Themes::Colorful;TI"Rouge::Themes::Github;TI"Rouge::Themes::Gruvbox;TI"Rouge::Themes::IgorPro;TI"Rouge::Themes::Magritte;TI"Rouge::Themes::Molokai;TI"Rouge::Themes::Monokai;TI""Rouge::Themes::MonokaiSublime;TI"Rouge::Themes::Pastie;TI" Rouge::Themes::ThankfulEyes;TI"Rouge::Themes::Tulip;TI"Rouge::Token;T@a: +pages[äI"lib/rouge/demos/abap;TI"!lib/rouge/demos/actionscript;TI"lib/rouge/demos/ada;TI"lib/rouge/demos/apache;TI"lib/rouge/demos/apex;TI"!lib/rouge/demos/apiblueprint;TI" lib/rouge/demos/applescript;TI"lib/rouge/demos/armasm;TI"lib/rouge/demos/augeas;TI"lib/rouge/demos/awk;TI"lib/rouge/demos/batchfile;TI"lib/rouge/demos/bbcbasic;TI"lib/rouge/demos/bibtex;TI"lib/rouge/demos/bicep;TI"lib/rouge/demos/biml;TI"lib/rouge/demos/bpf;TI"lib/rouge/demos/brainfuck;TI"!lib/rouge/demos/brightscript;TI"lib/rouge/demos/bsl;TI"lib/rouge/demos/c;TI"lib/rouge/demos/ceylon;TI"lib/rouge/demos/cfscript;TI"lib/rouge/demos/cisco_ios;TI"lib/rouge/demos/clean;TI"lib/rouge/demos/clojure;TI"lib/rouge/demos/cmake;TI"lib/rouge/demos/cmhg;TI"lib/rouge/demos/cobol;TI"lib/rouge/demos/codeowners;TI"!lib/rouge/demos/coffeescript;TI" lib/rouge/demos/common_lisp;TI"lib/rouge/demos/conf;TI"lib/rouge/demos/console;TI"lib/rouge/demos/coq;TI"lib/rouge/demos/cpp;TI"lib/rouge/demos/crystal;TI"lib/rouge/demos/csharp;TI"lib/rouge/demos/css;TI"lib/rouge/demos/csvs;TI"lib/rouge/demos/cuda;TI"lib/rouge/demos/cypher;TI"lib/rouge/demos/cython;TI"lib/rouge/demos/d;TI"lib/rouge/demos/dafny;TI"lib/rouge/demos/dart;TI"lib/rouge/demos/datastudio;TI"lib/rouge/demos/diff;TI"lib/rouge/demos/digdag;TI"lib/rouge/demos/docker;TI"lib/rouge/demos/dot;TI"lib/rouge/demos/ecl;TI"lib/rouge/demos/eex;TI"lib/rouge/demos/eiffel;TI"lib/rouge/demos/elixir;TI"lib/rouge/demos/elm;TI"lib/rouge/demos/email;TI"lib/rouge/demos/epp;TI"lib/rouge/demos/erb;TI"lib/rouge/demos/erlang;TI"lib/rouge/demos/escape;TI"lib/rouge/demos/factor;TI"lib/rouge/demos/fluent;TI"lib/rouge/demos/fortran;TI"lib/rouge/demos/freefem;TI"lib/rouge/demos/fsharp;TI"lib/rouge/demos/gdscript;TI"lib/rouge/demos/ghc-cmm;TI"lib/rouge/demos/ghc-core;TI"lib/rouge/demos/gherkin;TI"lib/rouge/demos/gjs;TI"lib/rouge/demos/glsl;TI"lib/rouge/demos/go;TI"lib/rouge/demos/gradle;TI"lib/rouge/demos/graphql;TI"lib/rouge/demos/groovy;TI"lib/rouge/demos/gts;TI"lib/rouge/demos/hack;TI"lib/rouge/demos/haml;TI"lib/rouge/demos/handlebars;TI"lib/rouge/demos/haskell;TI"lib/rouge/demos/haxe;TI"lib/rouge/demos/hcl;TI"lib/rouge/demos/hlsl;TI"lib/rouge/demos/hocon;TI"lib/rouge/demos/hql;TI"lib/rouge/demos/html;TI"lib/rouge/demos/http;TI"lib/rouge/demos/hylang;TI"lib/rouge/demos/idlang;TI"lib/rouge/demos/idris;TI"lib/rouge/demos/iecst;TI"lib/rouge/demos/igorpro;TI"lib/rouge/demos/ini;TI"lib/rouge/demos/io;TI"lib/rouge/demos/irb;TI"lib/rouge/demos/irb_output;TI"lib/rouge/demos/isabelle;TI"lib/rouge/demos/isbl;TI"lib/rouge/demos/j;TI"lib/rouge/demos/janet;TI"lib/rouge/demos/java;TI"lib/rouge/demos/javascript;TI"lib/rouge/demos/jinja;TI"lib/rouge/demos/jsl;TI"lib/rouge/demos/json;TI"lib/rouge/demos/json-doc;TI"lib/rouge/demos/json5;TI"lib/rouge/demos/jsonnet;TI"lib/rouge/demos/jsp;TI"lib/rouge/demos/jsx;TI"lib/rouge/demos/julia;TI"lib/rouge/demos/kotlin;TI"lib/rouge/demos/lasso;TI"lib/rouge/demos/lean;TI"lib/rouge/demos/liquid;TI"*lib/rouge/demos/literate_coffeescript;TI"%lib/rouge/demos/literate_haskell;TI"lib/rouge/demos/livescript;TI"lib/rouge/demos/llvm;TI"lib/rouge/demos/lua;TI"lib/rouge/demos/lustre;TI"lib/rouge/demos/lutin;TI"lib/rouge/demos/m68k;TI"lib/rouge/demos/magik;TI"lib/rouge/demos/make;TI"lib/rouge/demos/markdown;TI"lib/rouge/demos/mason;TI" lib/rouge/demos/mathematica;TI"lib/rouge/demos/matlab;TI"lib/rouge/demos/meson;TI"lib/rouge/demos/minizinc;TI"lib/rouge/demos/mojo;TI"lib/rouge/demos/moonscript;TI"lib/rouge/demos/mosel;TI"lib/rouge/demos/msgtrans;TI"lib/rouge/demos/mxml;TI"lib/rouge/demos/nasm;TI"lib/rouge/demos/nesasm;TI"lib/rouge/demos/nginx;TI"lib/rouge/demos/nial;TI"lib/rouge/demos/nim;TI"lib/rouge/demos/nix;TI" lib/rouge/demos/objective_c;TI""lib/rouge/demos/objective_cpp;TI"lib/rouge/demos/ocaml;TI"lib/rouge/demos/ocl;TI"lib/rouge/demos/openedge;TI"*lib/rouge/demos/opentype_feature_file;TI"lib/rouge/demos/p4;TI"lib/rouge/demos/pascal;TI"lib/rouge/demos/perl;TI"lib/rouge/demos/php;TI"lib/rouge/demos/plaintext;TI"lib/rouge/demos/plist;TI"lib/rouge/demos/plsql;TI"lib/rouge/demos/pony;TI"lib/rouge/demos/postscript;TI"lib/rouge/demos/powershell;TI"lib/rouge/demos/praat;TI"lib/rouge/demos/prolog;TI"lib/rouge/demos/prometheus;TI"lib/rouge/demos/properties;TI"lib/rouge/demos/protobuf;TI"lib/rouge/demos/puppet;TI"lib/rouge/demos/python;TI"lib/rouge/demos/q;TI"lib/rouge/demos/qml;TI"lib/rouge/demos/r;TI"lib/rouge/demos/racket;TI"lib/rouge/demos/reasonml;TI"lib/rouge/demos/rego;TI"lib/rouge/demos/rescript;TI"lib/rouge/demos/rml;TI"$lib/rouge/demos/robot_framework;TI"lib/rouge/demos/ruby;TI"lib/rouge/demos/rust;TI"lib/rouge/demos/sas;TI"lib/rouge/demos/sass;TI"lib/rouge/demos/scala;TI"lib/rouge/demos/scheme;TI"lib/rouge/demos/scss;TI"lib/rouge/demos/sed;TI"lib/rouge/demos/shell;TI"lib/rouge/demos/sieve;TI"lib/rouge/demos/slice;TI"lib/rouge/demos/slim;TI"lib/rouge/demos/smalltalk;TI"lib/rouge/demos/smarty;TI"lib/rouge/demos/sml;TI"lib/rouge/demos/sparql;TI"lib/rouge/demos/sqf;TI"lib/rouge/demos/sql;TI"lib/rouge/demos/ssh;TI"lib/rouge/demos/stan;TI"lib/rouge/demos/stata;TI""lib/rouge/demos/supercollider;TI"lib/rouge/demos/svelte;TI"lib/rouge/demos/swift;TI"lib/rouge/demos/systemd;TI"lib/rouge/demos/syzlang;TI"lib/rouge/demos/syzprog;TI"lib/rouge/demos/tap;TI"lib/rouge/demos/tcl;TI"lib/rouge/demos/terraform;TI"lib/rouge/demos/tex;TI"lib/rouge/demos/toml;TI"lib/rouge/demos/tsx;TI"lib/rouge/demos/ttcn3;TI"lib/rouge/demos/tulip;TI"lib/rouge/demos/turtle;TI"lib/rouge/demos/twig;TI"lib/rouge/demos/typescript;TI"lib/rouge/demos/vala;TI"lib/rouge/demos/vb;TI"lib/rouge/demos/vcl;TI"lib/rouge/demos/velocity;TI"lib/rouge/demos/verilog;TI"lib/rouge/demos/vhdl;TI"lib/rouge/demos/viml;TI"lib/rouge/demos/vue;TI"lib/rouge/demos/wollok;TI"lib/rouge/demos/xml;TI"lib/rouge/demos/xojo;TI"lib/rouge/demos/xpath;TI"lib/rouge/demos/xquery;TI"lib/rouge/demos/yaml;TI"lib/rouge/demos/yang;TI"lib/rouge/demos/zig;T: +titleI"rouge-4.7.0 Documentation;T \ No newline at end of file diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-abap.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-abap.ri new file mode 100644 index 00000000..412a53d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-abap.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-actionscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-actionscript.ri new file mode 100644 index 00000000..8dd3eb7d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-actionscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ada.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ada.ri new file mode 100644 index 00000000..4890cda8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ada.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apache.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apache.ri new file mode 100644 index 00000000..1b1bc841 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apache.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apex.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apex.ri new file mode 100644 index 00000000..526685dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apiblueprint.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apiblueprint.ri new file mode 100644 index 00000000..9e1a2325 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-apiblueprint.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-applescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-applescript.ri new file mode 100644 index 00000000..421c4a4f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-applescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-armasm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-armasm.ri new file mode 100644 index 00000000..9a7db110 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-armasm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-augeas.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-augeas.ri new file mode 100644 index 00000000..138c27de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-augeas.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-awk.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-awk.ri new file mode 100644 index 00000000..c016b13a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-awk.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-batchfile.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-batchfile.ri new file mode 100644 index 00000000..f9bf518c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-batchfile.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bbcbasic.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bbcbasic.ri new file mode 100644 index 00000000..62eb3894 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bbcbasic.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bibtex.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bibtex.ri new file mode 100644 index 00000000..e29ba1ef Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bibtex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bicep.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bicep.ri new file mode 100644 index 00000000..9e8a37de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bicep.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-biml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-biml.ri new file mode 100644 index 00000000..6c3edde5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-biml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bpf.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bpf.ri new file mode 100644 index 00000000..2b4a6e9a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bpf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brainfuck.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brainfuck.ri new file mode 100644 index 00000000..3a80579e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brainfuck.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brightscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brightscript.ri new file mode 100644 index 00000000..068b183f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-brightscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bsl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bsl.ri new file mode 100644 index 00000000..e6a657c5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-bsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-c.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-c.ri new file mode 100644 index 00000000..c9b64c3d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ceylon.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ceylon.ri new file mode 100644 index 00000000..b4951bd9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ceylon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cfscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cfscript.ri new file mode 100644 index 00000000..9f480a97 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cfscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cisco_ios.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cisco_ios.ri new file mode 100644 index 00000000..82a2b91b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cisco_ios.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clean.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clean.ri new file mode 100644 index 00000000..28076005 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clean.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clojure.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clojure.ri new file mode 100644 index 00000000..6224ebf1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-clojure.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmake.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmake.ri new file mode 100644 index 00000000..12990ee7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmake.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmhg.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmhg.ri new file mode 100644 index 00000000..0c981580 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cmhg.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cobol.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cobol.ri new file mode 100644 index 00000000..449a55d4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cobol.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-codeowners.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-codeowners.ri new file mode 100644 index 00000000..135c6267 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-codeowners.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coffeescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coffeescript.ri new file mode 100644 index 00000000..bf824f56 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coffeescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-common_lisp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-common_lisp.ri new file mode 100644 index 00000000..7570caed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-common_lisp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-conf.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-conf.ri new file mode 100644 index 00000000..f1138e18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-conf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-console.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-console.ri new file mode 100644 index 00000000..5c4c37f5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-console.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coq.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coq.ri new file mode 100644 index 00000000..19f4ebc8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-coq.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cpp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cpp.ri new file mode 100644 index 00000000..0a5d663f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cpp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-crystal.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-crystal.ri new file mode 100644 index 00000000..0d303d2a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-crystal.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csharp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csharp.ri new file mode 100644 index 00000000..9e3af5a4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csharp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-css.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-css.ri new file mode 100644 index 00000000..3ac9dd68 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-css.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csvs.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csvs.ri new file mode 100644 index 00000000..2b3e5f71 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-csvs.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cuda.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cuda.ri new file mode 100644 index 00000000..0f2cf89e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cuda.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cypher.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cypher.ri new file mode 100644 index 00000000..bbe3f4bb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cypher.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cython.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cython.ri new file mode 100644 index 00000000..5a93de3a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-cython.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-d.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-d.ri new file mode 100644 index 00000000..a613fd84 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-d.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dafny.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dafny.ri new file mode 100644 index 00000000..65314967 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dafny.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dart.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dart.ri new file mode 100644 index 00000000..6bbd2c1d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dart.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-datastudio.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-datastudio.ri new file mode 100644 index 00000000..52c76618 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-datastudio.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-diff.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-diff.ri new file mode 100644 index 00000000..f5dd3b49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-diff.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-digdag.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-digdag.ri new file mode 100644 index 00000000..c2d416df Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-digdag.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-docker.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-docker.ri new file mode 100644 index 00000000..469fa08e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-docker.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dot.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dot.ri new file mode 100644 index 00000000..22c1170e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-dot.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ecl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ecl.ri new file mode 100644 index 00000000..1259bdf0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ecl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eex.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eex.ri new file mode 100644 index 00000000..7604b51b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eiffel.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eiffel.ri new file mode 100644 index 00000000..b3811eb0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-eiffel.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elixir.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elixir.ri new file mode 100644 index 00000000..8f9ef022 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elixir.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elm.ri new file mode 100644 index 00000000..727ba1f4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-elm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-email.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-email.ri new file mode 100644 index 00000000..fb2d2c66 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-email.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-epp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-epp.ri new file mode 100644 index 00000000..098f637f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-epp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erb.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erb.ri new file mode 100644 index 00000000..d6600f59 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erb.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erlang.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erlang.ri new file mode 100644 index 00000000..5e7ad8e3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-erlang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-escape.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-escape.ri new file mode 100644 index 00000000..92d2f832 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-escape.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-factor.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-factor.ri new file mode 100644 index 00000000..0a60e5d6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-factor.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fluent.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fluent.ri new file mode 100644 index 00000000..b77b39c3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fluent.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fortran.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fortran.ri new file mode 100644 index 00000000..f8193a89 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fortran.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-freefem.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-freefem.ri new file mode 100644 index 00000000..d4882cfc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-freefem.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fsharp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fsharp.ri new file mode 100644 index 00000000..ee1ee4c0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-fsharp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gdscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gdscript.ri new file mode 100644 index 00000000..0f90b4e0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gdscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-cmm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-cmm.ri new file mode 100644 index 00000000..a6d143a5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-cmm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-core.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-core.ri new file mode 100644 index 00000000..4f467102 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ghc-core.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gherkin.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gherkin.ri new file mode 100644 index 00000000..dc65a53f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gherkin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gjs.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gjs.ri new file mode 100644 index 00000000..377fc016 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gjs.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-glsl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-glsl.ri new file mode 100644 index 00000000..e95cb0f9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-glsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-go.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-go.ri new file mode 100644 index 00000000..5b33c916 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-go.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gradle.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gradle.ri new file mode 100644 index 00000000..0c21de7f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gradle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-graphql.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-graphql.ri new file mode 100644 index 00000000..ca69f5f3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-graphql.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-groovy.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-groovy.ri new file mode 100644 index 00000000..bff8503f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-groovy.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gts.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gts.ri new file mode 100644 index 00000000..d794d2c6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-gts.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hack.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hack.ri new file mode 100644 index 00000000..17262a9d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hack.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haml.ri new file mode 100644 index 00000000..51a85e18 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-handlebars.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-handlebars.ri new file mode 100644 index 00000000..806d26cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-handlebars.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haskell.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haskell.ri new file mode 100644 index 00000000..b4997dc9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haskell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haxe.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haxe.ri new file mode 100644 index 00000000..b75fbf96 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-haxe.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hcl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hcl.ri new file mode 100644 index 00000000..69365357 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hcl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hlsl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hlsl.ri new file mode 100644 index 00000000..ab4260ec Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hlsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hocon.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hocon.ri new file mode 100644 index 00000000..a4e04e49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hocon.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hql.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hql.ri new file mode 100644 index 00000000..029b25c8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hql.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-html.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-html.ri new file mode 100644 index 00000000..3cbb1b0c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-html.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-http.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-http.ri new file mode 100644 index 00000000..f9d5ea24 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-http.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hylang.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hylang.ri new file mode 100644 index 00000000..ae2166af Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-hylang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idlang.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idlang.ri new file mode 100644 index 00000000..433a4803 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idlang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idris.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idris.ri new file mode 100644 index 00000000..3b9a11cf Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-idris.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-iecst.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-iecst.ri new file mode 100644 index 00000000..ba2760ed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-iecst.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-igorpro.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-igorpro.ri new file mode 100644 index 00000000..9d5b8f38 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-igorpro.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ini.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ini.ri new file mode 100644 index 00000000..16e87855 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ini.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-io.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-io.ri new file mode 100644 index 00000000..47e90cb6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-io.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb.ri new file mode 100644 index 00000000..da68713e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb_output.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb_output.ri new file mode 100644 index 00000000..ff7a7525 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-irb_output.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isabelle.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isabelle.ri new file mode 100644 index 00000000..201ea0a0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isabelle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isbl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isbl.ri new file mode 100644 index 00000000..28c7a603 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-isbl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-j.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-j.ri new file mode 100644 index 00000000..d0920771 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-j.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-janet.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-janet.ri new file mode 100644 index 00000000..13588543 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-janet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-java.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-java.ri new file mode 100644 index 00000000..028bc3c5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-java.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-javascript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-javascript.ri new file mode 100644 index 00000000..0a42c3f1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-javascript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jinja.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jinja.ri new file mode 100644 index 00000000..f706f234 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jinja.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsl.ri new file mode 100644 index 00000000..7812c93b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json-doc.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json-doc.ri new file mode 100644 index 00000000..a512f1b7 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json-doc.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json.ri new file mode 100644 index 00000000..4d539cc4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json5.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json5.ri new file mode 100644 index 00000000..e19c7c5e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-json5.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsonnet.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsonnet.ri new file mode 100644 index 00000000..8d94b36b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsonnet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsp.ri new file mode 100644 index 00000000..2b3d44c2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsx.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsx.ri new file mode 100644 index 00000000..441e869f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-jsx.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-julia.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-julia.ri new file mode 100644 index 00000000..4b7a944a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-julia.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-kotlin.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-kotlin.ri new file mode 100644 index 00000000..df99720b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-kotlin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lasso.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lasso.ri new file mode 100644 index 00000000..78ca552e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lasso.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lean.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lean.ri new file mode 100644 index 00000000..0fc0c840 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lean.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-liquid.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-liquid.ri new file mode 100644 index 00000000..20bda8bc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-liquid.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_coffeescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_coffeescript.ri new file mode 100644 index 00000000..80325e6b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_coffeescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_haskell.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_haskell.ri new file mode 100644 index 00000000..8b5b4964 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-literate_haskell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-livescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-livescript.ri new file mode 100644 index 00000000..53b8a1cc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-livescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-llvm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-llvm.ri new file mode 100644 index 00000000..02bc75ad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-llvm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lua.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lua.ri new file mode 100644 index 00000000..c5fadf56 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lua.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lustre.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lustre.ri new file mode 100644 index 00000000..a05fc6b8 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lustre.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lutin.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lutin.ri new file mode 100644 index 00000000..1cbfa43a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-lutin.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-m68k.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-m68k.ri new file mode 100644 index 00000000..8113b68d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-m68k.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-magik.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-magik.ri new file mode 100644 index 00000000..b069f372 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-magik.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-make.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-make.ri new file mode 100644 index 00000000..650cf527 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-make.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-markdown.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-markdown.ri new file mode 100644 index 00000000..e045da1a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-markdown.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mason.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mason.ri new file mode 100644 index 00000000..fd18501b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mason.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mathematica.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mathematica.ri new file mode 100644 index 00000000..5cd53c01 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mathematica.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-matlab.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-matlab.ri new file mode 100644 index 00000000..267d666e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-matlab.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-meson.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-meson.ri new file mode 100644 index 00000000..85b638f6 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-meson.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-minizinc.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-minizinc.ri new file mode 100644 index 00000000..f0e5a825 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-minizinc.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mojo.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mojo.ri new file mode 100644 index 00000000..e33447e1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mojo.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-moonscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-moonscript.ri new file mode 100644 index 00000000..ccbe5dde Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-moonscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mosel.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mosel.ri new file mode 100644 index 00000000..6836828b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mosel.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-msgtrans.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-msgtrans.ri new file mode 100644 index 00000000..623d4887 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-msgtrans.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mxml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mxml.ri new file mode 100644 index 00000000..92c52af0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-mxml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nasm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nasm.ri new file mode 100644 index 00000000..b35e2611 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nasm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nesasm.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nesasm.ri new file mode 100644 index 00000000..52e028bd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nesasm.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nginx.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nginx.ri new file mode 100644 index 00000000..844c5bad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nginx.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nial.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nial.ri new file mode 100644 index 00000000..2a293aa2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nial.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nim.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nim.ri new file mode 100644 index 00000000..6478e094 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nim.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nix.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nix.ri new file mode 100644 index 00000000..865f3dd5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-nix.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_c.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_c.ri new file mode 100644 index 00000000..9bfdb97f Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_c.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_cpp.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_cpp.ri new file mode 100644 index 00000000..59b3374c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-objective_cpp.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocaml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocaml.ri new file mode 100644 index 00000000..21e15f35 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocaml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocl.ri new file mode 100644 index 00000000..6c563b79 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ocl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-openedge.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-openedge.ri new file mode 100644 index 00000000..43734eaa Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-openedge.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-opentype_feature_file.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-opentype_feature_file.ri new file mode 100644 index 00000000..2a20b194 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-opentype_feature_file.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-p4.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-p4.ri new file mode 100644 index 00000000..4b15ae6a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-p4.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pascal.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pascal.ri new file mode 100644 index 00000000..a8ba8d97 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pascal.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-perl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-perl.ri new file mode 100644 index 00000000..111cebdc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-perl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-php.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-php.ri new file mode 100644 index 00000000..79f0ce43 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-php.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plaintext.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plaintext.ri new file mode 100644 index 00000000..ab158996 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plaintext.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plist.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plist.ri new file mode 100644 index 00000000..c090af92 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plist.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plsql.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plsql.ri new file mode 100644 index 00000000..df6cea86 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-plsql.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pony.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pony.ri new file mode 100644 index 00000000..16cb9052 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-pony.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-postscript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-postscript.ri new file mode 100644 index 00000000..6a9fb7eb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-postscript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-powershell.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-powershell.ri new file mode 100644 index 00000000..dd6d8da9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-powershell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-praat.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-praat.ri new file mode 100644 index 00000000..089902de Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-praat.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prolog.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prolog.ri new file mode 100644 index 00000000..93321804 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prolog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prometheus.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prometheus.ri new file mode 100644 index 00000000..8eba7787 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-prometheus.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-properties.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-properties.ri new file mode 100644 index 00000000..873d0a12 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-properties.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-protobuf.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-protobuf.ri new file mode 100644 index 00000000..731a2816 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-protobuf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-puppet.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-puppet.ri new file mode 100644 index 00000000..0798c1fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-puppet.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-python.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-python.ri new file mode 100644 index 00000000..90cea8a9 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-python.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-q.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-q.ri new file mode 100644 index 00000000..3f458241 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-q.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-qml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-qml.ri new file mode 100644 index 00000000..884ef85a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-qml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-r.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-r.ri new file mode 100644 index 00000000..9951b833 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-r.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-racket.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-racket.ri new file mode 100644 index 00000000..e4a5f80a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-racket.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-reasonml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-reasonml.ri new file mode 100644 index 00000000..c492451b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-reasonml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rego.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rego.ri new file mode 100644 index 00000000..8d2e8598 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rego.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rescript.ri new file mode 100644 index 00000000..e0fa16fe Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rml.ri new file mode 100644 index 00000000..f509ee48 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-robot_framework.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-robot_framework.ri new file mode 100644 index 00000000..c7b3ac55 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-robot_framework.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ruby.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ruby.ri new file mode 100644 index 00000000..45171af4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ruby.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rust.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rust.ri new file mode 100644 index 00000000..f33c1dee Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-rust.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sas.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sas.ri new file mode 100644 index 00000000..2f7f4b0d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sas.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sass.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sass.ri new file mode 100644 index 00000000..1647f0f0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sass.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scala.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scala.ri new file mode 100644 index 00000000..89456e15 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scala.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scheme.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scheme.ri new file mode 100644 index 00000000..36db35ad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scheme.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scss.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scss.ri new file mode 100644 index 00000000..71682263 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-scss.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sed.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sed.ri new file mode 100644 index 00000000..8efc6499 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sed.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-shell.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-shell.ri new file mode 100644 index 00000000..d4aeeb4d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-shell.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sieve.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sieve.ri new file mode 100644 index 00000000..1327abf1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sieve.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slice.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slice.ri new file mode 100644 index 00000000..29c1aa49 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slice.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slim.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slim.ri new file mode 100644 index 00000000..24f94851 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-slim.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smalltalk.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smalltalk.ri new file mode 100644 index 00000000..e6cb3fcd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smalltalk.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smarty.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smarty.ri new file mode 100644 index 00000000..dd56131e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-smarty.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sml.ri new file mode 100644 index 00000000..9a6cb1cd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sparql.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sparql.ri new file mode 100644 index 00000000..314baeac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sparql.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sqf.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sqf.ri new file mode 100644 index 00000000..dd24c6bb Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sqf.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sql.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sql.ri new file mode 100644 index 00000000..d383351c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-sql.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ssh.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ssh.ri new file mode 100644 index 00000000..91f5267c Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ssh.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stan.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stan.ri new file mode 100644 index 00000000..7715bc69 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stan.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stata.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stata.ri new file mode 100644 index 00000000..ce35adac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-stata.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-supercollider.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-supercollider.ri new file mode 100644 index 00000000..cb242a53 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-supercollider.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-svelte.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-svelte.ri new file mode 100644 index 00000000..8d9ef53d Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-svelte.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-swift.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-swift.ri new file mode 100644 index 00000000..538d0b2b Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-swift.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-systemd.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-systemd.ri new file mode 100644 index 00000000..e1535872 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-systemd.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzlang.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzlang.ri new file mode 100644 index 00000000..1dcd2f68 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzlang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzprog.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzprog.ri new file mode 100644 index 00000000..99922de3 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-syzprog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tap.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tap.ri new file mode 100644 index 00000000..5c36f40e Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tap.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tcl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tcl.ri new file mode 100644 index 00000000..daa1c273 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tcl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-terraform.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-terraform.ri new file mode 100644 index 00000000..d631ddde Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-terraform.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tex.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tex.ri new file mode 100644 index 00000000..6c34c9dd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tex.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-toml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-toml.ri new file mode 100644 index 00000000..fc0bca89 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-toml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tsx.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tsx.ri new file mode 100644 index 00000000..6e5f6c10 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tsx.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ttcn3.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ttcn3.ri new file mode 100644 index 00000000..b1f484b0 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-ttcn3.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tulip.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tulip.ri new file mode 100644 index 00000000..a84756d1 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-tulip.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-turtle.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-turtle.ri new file mode 100644 index 00000000..6741ded4 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-turtle.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-twig.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-twig.ri new file mode 100644 index 00000000..28535853 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-twig.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-typescript.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-typescript.ri new file mode 100644 index 00000000..2e33f9ac Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-typescript.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vala.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vala.ri new file mode 100644 index 00000000..4dc0e6ad Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vala.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vb.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vb.ri new file mode 100644 index 00000000..6d7f2d7a Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vb.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vcl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vcl.ri new file mode 100644 index 00000000..72a8bbe2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vcl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-velocity.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-velocity.ri new file mode 100644 index 00000000..2a1a8813 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-velocity.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-verilog.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-verilog.ri new file mode 100644 index 00000000..3ea37df5 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-verilog.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vhdl.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vhdl.ri new file mode 100644 index 00000000..221dd6fd Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vhdl.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-viml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-viml.ri new file mode 100644 index 00000000..2a769074 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-viml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vue.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vue.ri new file mode 100644 index 00000000..acdf4f86 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-vue.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-wollok.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-wollok.ri new file mode 100644 index 00000000..d8a71208 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-wollok.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xml.ri new file mode 100644 index 00000000..5f912cc2 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xojo.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xojo.ri new file mode 100644 index 00000000..c8fc98ab Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xojo.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xpath.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xpath.ri new file mode 100644 index 00000000..7b664816 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xpath.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xquery.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xquery.ri new file mode 100644 index 00000000..91188f22 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-xquery.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yaml.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yaml.ri new file mode 100644 index 00000000..b37cffed Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yaml.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yang.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yang.ri new file mode 100644 index 00000000..af3e2592 Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-yang.ri differ diff --git a/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-zig.ri b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-zig.ri new file mode 100644 index 00000000..d507d1fc Binary files /dev/null and b/bin/doc/rouge-4.7.0/ri/lib/rouge/demos/page-zig.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/Object/cdesc-Object.ri b/bin/doc/safe_yaml-1.0.5/ri/Object/cdesc-Object.ri new file mode 100644 index 00000000..63b7b5de Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/Object/cdesc-Object.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/cdesc-Deep.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/cdesc-Deep.ri new file mode 100644 index 00000000..4f855aa4 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/cdesc-Deep.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/copy-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/copy-c.ri new file mode 100644 index 00000000..d0f6b5a4 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/copy-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/freeze-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/freeze-c.ri new file mode 100644 index 00000000..8a7e7d9f Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Deep/freeze-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/cdesc-LibyamlChecker.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/cdesc-LibyamlChecker.ri new file mode 100644 index 00000000..ab8587f7 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/cdesc-LibyamlChecker.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_patched%3f-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_patched%3f-c.ri new file mode 100644 index 00000000..4857fe68 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_patched%3f-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_version_ok%3f-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_version_ok%3f-c.ri new file mode 100644 index 00000000..33a8357d Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/LibyamlChecker/libyaml_version_ok%3f-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/cdesc-Date.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/cdesc-Date.ri new file mode 100644 index 00000000..272fd71b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/cdesc-Date.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/value-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/value-c.ri new file mode 100644 index 00000000..fe32e40e Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Date/value-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/cdesc-Hexadecimal.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/cdesc-Hexadecimal.ri new file mode 100644 index 00000000..5d5c2a69 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/cdesc-Hexadecimal.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/value-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/value-c.ri new file mode 100644 index 00000000..8f62358e Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Hexadecimal/value-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/cdesc-Sexagesimal.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/cdesc-Sexagesimal.ri new file mode 100644 index 00000000..9474845c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/cdesc-Sexagesimal.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/value-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/value-c.ri new file mode 100644 index 00000000..bae7837f Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/Sexagesimal/value-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/cdesc-Parse.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/cdesc-Parse.ri new file mode 100644 index 00000000..7b3979b1 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Parse/cdesc-Parse.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/add_to_current_structure-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/add_to_current_structure-i.ri new file mode 100644 index 00000000..e993b21e Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/add_to_current_structure-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/alias-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/alias-i.ri new file mode 100644 index 00000000..c319b611 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/alias-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/cdesc-PsychHandler.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/cdesc-PsychHandler.ri new file mode 100644 index 00000000..a39a52bc Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/cdesc-PsychHandler.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_current_structure-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_current_structure-i.ri new file mode 100644 index 00000000..0dc854bd Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_current_structure-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_document-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_document-i.ri new file mode 100644 index 00000000..bedc92b8 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_document-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_mapping-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_mapping-i.ri new file mode 100644 index 00000000..5a22c9ed Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_mapping-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_sequence-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_sequence-i.ri new file mode 100644 index 00000000..f47ea06c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/end_sequence-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/new-c.ri new file mode 100644 index 00000000..b8f8cf1d Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/result-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/result-i.ri new file mode 100644 index 00000000..eb41220a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/result-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/scalar-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/scalar-i.ri new file mode 100644 index 00000000..4634b2fc Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/scalar-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_mapping-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_mapping-i.ri new file mode 100644 index 00000000..8439010a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_mapping-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_sequence-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_sequence-i.ri new file mode 100644 index 00000000..55820f49 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/start_sequence-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/streaming%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/streaming%3f-i.ri new file mode 100644 index 00000000..57a4c7fb Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychHandler/streaming%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/cdesc-PsychResolver.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/cdesc-PsychResolver.ri new file mode 100644 index 00000000..1fb687c4 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/cdesc-PsychResolver.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_tag-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_tag-i.ri new file mode 100644 index 00000000..e4d70a02 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_tag-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_type-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_type-i.ri new file mode 100644 index 00000000..0f1acf2a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_type-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_value-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_value-i.ri new file mode 100644 index 00000000..c98bd7a8 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/get_node_value-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/native_resolve-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/native_resolve-i.ri new file mode 100644 index 00000000..49d6600f Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/native_resolve-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/new-c.ri new file mode 100644 index 00000000..3d27335e Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_alias-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_alias-i.ri new file mode 100644 index 00000000..b1dca553 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_alias-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_root-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_root-i.ri new file mode 100644 index 00000000..5f068bc8 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/resolve_root-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/value_is_quoted%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/value_is_quoted%3f-i.ri new file mode 100644 index 00000000..f3141be4 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/PsychResolver/value_is_quoted%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/cdesc-Resolver.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/cdesc-Resolver.ri new file mode 100644 index 00000000..d0916a31 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/cdesc-Resolver.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/get_and_check_node_tag-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/get_and_check_node_tag-i.ri new file mode 100644 index 00000000..0f597208 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/get_and_check_node_tag-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/merge_into_hash-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/merge_into_hash-i.ri new file mode 100644 index 00000000..1b9d989d Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/merge_into_hash-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/new-c.ri new file mode 100644 index 00000000..63839029 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/normalize_map-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/normalize_map-i.ri new file mode 100644 index 00000000..70f557c6 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/normalize_map-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/options-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/options-i.ri new file mode 100644 index 00000000..02cf8588 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/options-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_map-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_map-i.ri new file mode 100644 index 00000000..cf1483e3 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_map-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_node-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_node-i.ri new file mode 100644 index 00000000..88f1ce76 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_node-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_scalar-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_scalar-i.ri new file mode 100644 index 00000000..fb63e1ba Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_scalar-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_seq-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_seq-i.ri new file mode 100644 index 00000000..72e046a9 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/resolve_seq-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/tag_is_whitelisted%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/tag_is_whitelisted%3f-i.ri new file mode 100644 index 00000000..23fb4d8d Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Resolver/tag_is_whitelisted%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/accept-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/accept-i.ri new file mode 100644 index 00000000..e69c0883 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/accept-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/cdesc-SafeToRubyVisitor.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/cdesc-SafeToRubyVisitor.ri new file mode 100644 index 00000000..8165528c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/cdesc-SafeToRubyVisitor.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/new-c.ri new file mode 100644 index 00000000..b146c487 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SafeToRubyVisitor/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/cdesc-Store.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/cdesc-Store.ri new file mode 100644 index 00000000..f2314bc1 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/cdesc-Store.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/load-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/load-i.ri new file mode 100644 index 00000000..a1c49091 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/load-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/new-c.ri new file mode 100644 index 00000000..a39f2c7c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/safe_yaml_load-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/safe_yaml_load-i.ri new file mode 100644 index 00000000..7f0ca9e7 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Store/safe_yaml_load-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/cdesc-SyckResolver.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/cdesc-SyckResolver.ri new file mode 100644 index 00000000..e7aaff77 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/cdesc-SyckResolver.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_tag-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_tag-i.ri new file mode 100644 index 00000000..a9190cba Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_tag-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_type-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_type-i.ri new file mode 100644 index 00000000..0eedaf5a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_type-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_value-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_value-i.ri new file mode 100644 index 00000000..d0dc084c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/get_node_value-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/native_resolve-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/native_resolve-i.ri new file mode 100644 index 00000000..acd2cc2c Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/native_resolve-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/new-c.ri new file mode 100644 index 00000000..cb2707eb Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/value_is_quoted%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/value_is_quoted%3f-i.ri new file mode 100644 index 00000000..10c3498b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/SyckResolver/value_is_quoted%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/cdesc-ToBoolean.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/cdesc-ToBoolean.ri new file mode 100644 index 00000000..6ad8bdf5 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/cdesc-ToBoolean.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/transform%3f-i.ri new file mode 100644 index 00000000..d319ba2f Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToBoolean/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/cdesc-ToDate.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/cdesc-ToDate.ri new file mode 100644 index 00000000..0b302df0 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/cdesc-ToDate.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/transform%3f-i.ri new file mode 100644 index 00000000..6240e8ee Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToDate/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/cdesc-ToFloat.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/cdesc-ToFloat.ri new file mode 100644 index 00000000..44ac4dec Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/cdesc-ToFloat.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/transform%3f-i.ri new file mode 100644 index 00000000..7345ce1b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/try_edge_cases%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/try_edge_cases%3f-i.ri new file mode 100644 index 00000000..8930ec90 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToFloat/try_edge_cases%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/cdesc-ToInteger.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/cdesc-ToInteger.ri new file mode 100644 index 00000000..b561e3a0 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/cdesc-ToInteger.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/transform%3f-i.ri new file mode 100644 index 00000000..b81780b7 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/try_edge_cases%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/try_edge_cases%3f-i.ri new file mode 100644 index 00000000..d01fadee Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToInteger/try_edge_cases%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/cdesc-ToNil.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/cdesc-ToNil.ri new file mode 100644 index 00000000..cebb7183 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/cdesc-ToNil.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/transform%3f-i.ri new file mode 100644 index 00000000..a0c7fbf5 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToNil/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/cdesc-ToSymbol.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/cdesc-ToSymbol.ri new file mode 100644 index 00000000..0fd3efa3 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/cdesc-ToSymbol.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/transform%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/transform%3f-i.ri new file mode 100644 index 00000000..f9defb95 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/ToSymbol/transform%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/%5b%5d-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/%5b%5d-i.ri new file mode 100644 index 00000000..147ffc4e Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/%5b%5d-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/cdesc-CaseAgnosticMap.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/cdesc-CaseAgnosticMap.ri new file mode 100644 index 00000000..2354c4a5 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/cdesc-CaseAgnosticMap.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/freeze-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/freeze-i.ri new file mode 100644 index 00000000..0224958b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/freeze-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/include%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/include%3f-i.ri new file mode 100644 index 00000000..53076af9 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/include%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/new-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/new-c.ri new file mode 100644 index 00000000..09953467 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/CaseAgnosticMap/new-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/cdesc-ClassMethods.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/cdesc-ClassMethods.ri new file mode 100644 index 00000000..20fa2799 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/cdesc-ClassMethods.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/set_predefined_values-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/set_predefined_values-i.ri new file mode 100644 index 00000000..dc5f0851 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/ClassMethods/set_predefined_values-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/cdesc-TransformationMap.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/cdesc-TransformationMap.ri new file mode 100644 index 00000000..9be95579 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/cdesc-TransformationMap.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/included-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/included-c.ri new file mode 100644 index 00000000..10c32d6b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/TransformationMap/included-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/cdesc-Transform.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/cdesc-Transform.ri new file mode 100644 index 00000000..cc7fa44a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/cdesc-Transform.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_guessed_type-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_guessed_type-c.ri new file mode 100644 index 00000000..10472ac5 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_guessed_type-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_proper_type-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_proper_type-c.ri new file mode 100644 index 00000000..bd15a977 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/Transform/to_proper_type-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/cdesc-SafeYAML.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/cdesc-SafeYAML.ri new file mode 100644 index 00000000..c7edc7ce Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/cdesc-SafeYAML.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load-c.ri new file mode 100644 index 00000000..1f0fc9be Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load_file-c.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load_file-c.ri new file mode 100644 index 00000000..b4b2914d Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/load_file-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/restore_defaults%21-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/restore_defaults%21-i.ri new file mode 100644 index 00000000..74dff12b Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/restore_defaults%21-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_is_explicitly_trusted%3f-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_is_explicitly_trusted%3f-i.ri new file mode 100644 index 00000000..6530530a Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_is_explicitly_trusted%3f-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_safety_check%21-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_safety_check%21-i.ri new file mode 100644 index 00000000..04ade0cd Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/tag_safety_check%21-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist%21-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist%21-i.ri new file mode 100644 index 00000000..3087d6e9 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist%21-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist_class%21-i.ri b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist_class%21-i.ri new file mode 100644 index 00000000..0acb9ef1 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/SafeYAML/whitelist_class%21-i.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/cdesc-YAML.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/cdesc-YAML.ri new file mode 100644 index 00000000..b7c013d9 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/cdesc-YAML.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/filename_and_options_from_arguments-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/filename_and_options_from_arguments-c.ri new file mode 100644 index 00000000..09f46629 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/filename_and_options_from_arguments-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/load-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/load-c.ri new file mode 100644 index 00000000..e3ae1fc5 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/load-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file-c.ri new file mode 100644 index 00000000..90418ee6 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file_with_options-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file_with_options-c.ri new file mode 100644 index 00000000..65697b96 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_file_with_options-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/load_with_options-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_with_options-c.ri new file mode 100644 index 00000000..42a31be4 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/load_with_options-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/options_for_safe_load-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/options_for_safe_load-c.ri new file mode 100644 index 00000000..94182c3f Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/options_for_safe_load-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load-c.ri new file mode 100644 index 00000000..ef66df63 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load_file-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load_file-c.ri new file mode 100644 index 00000000..210fa522 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_load_file-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_mode_from_options-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_mode_from_options-c.ri new file mode 100644 index 00000000..d6875755 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/safe_mode_from_options-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load-c.ri new file mode 100644 index 00000000..4e610a47 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load_file-c.ri b/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load_file-c.ri new file mode 100644 index 00000000..796cced6 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/YAML/unsafe_load_file-c.ri differ diff --git a/bin/doc/safe_yaml-1.0.5/ri/cache.ri b/bin/doc/safe_yaml-1.0.5/ri/cache.ri new file mode 100644 index 00000000..96b4cbe2 Binary files /dev/null and b/bin/doc/safe_yaml-1.0.5/ri/cache.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CLI/cdesc-CLI.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CLI/cdesc-CLI.ri new file mode 100644 index 00000000..add42846 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CLI/cdesc-CLI.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/%3d%3d-i.ri new file mode 100644 index 00000000..8af1fa44 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/cdesc-CalculationOperation.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/cdesc-CalculationOperation.ri new file mode 100644 index 00000000..58e88715 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/cdesc-CalculationOperation.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/hash-i.ri new file mode 100644 index 00000000..7209c780 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/left-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/left-i.ri new file mode 100644 index 00000000..036ee325 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/left-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" left:ETI"6Sass::CalculationValue::CalculationOperation#left;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [CalculationValue];T: +@fileI"8lib/sass/calculation_value/calculation_operation.rb;T:0@omit_headings_from_table_of_contents_below0F@I"1Sass::CalculationValue::CalculationOperation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/new-c.ri new file mode 100644 index 00000000..cde00232 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/operator-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/operator-i.ri new file mode 100644 index 00000000..8559b81a --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/operator-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" operator:ETI":Sass::CalculationValue::CalculationOperation#operator;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI"8lib/sass/calculation_value/calculation_operation.rb;T:0@omit_headings_from_table_of_contents_below0F@I"1Sass::CalculationValue::CalculationOperation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/right-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/right-i.ri new file mode 100644 index 00000000..91d5ae98 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/CalculationOperation/right-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +right:ETI"7Sass::CalculationValue::CalculationOperation#right;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [CalculationValue];T: +@fileI"8lib/sass/calculation_value/calculation_operation.rb;T:0@omit_headings_from_table_of_contents_below0F@I"1Sass::CalculationValue::CalculationOperation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/assert_calculation_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/assert_calculation_value-i.ri new file mode 100644 index 00000000..a62380ef Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/assert_calculation_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/cdesc-CalculationValue.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/cdesc-CalculationValue.ri new file mode 100644 index 00000000..60c05435 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CalculationValue/cdesc-CalculationValue.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/cdesc-CanonicalizeContext.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/cdesc-CanonicalizeContext.ri new file mode 100644 index 00000000..67351ae9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/cdesc-CanonicalizeContext.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/containing_url-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/containing_url-i.ri new file mode 100644 index 00000000..5443670a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/containing_url-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/from_import-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/from_import-i.ri new file mode 100644 index 00000000..a58d06e4 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/from_import-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"from_import:ETI"*Sass::CanonicalizeContext#from_import;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Boolean];T: +@fileI"%lib/sass/canonicalize_context.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CanonicalizeContext;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/new-c.ri new file mode 100644 index 00000000..312b4311 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CanonicalizeContext/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/cdesc-CompileError.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/cdesc-CompileError.ri new file mode 100644 index 00000000..db9dfa66 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/cdesc-CompileError.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/detailed_message-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/detailed_message-i.ri new file mode 100644 index 00000000..dfeb1304 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/detailed_message-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/loaded_urls-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/loaded_urls-i.ri new file mode 100644 index 00000000..dc3e75ce --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/loaded_urls-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"loaded_urls:ETI"#Sass::CompileError#loaded_urls;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Array];T: +@fileI"lib/sass/exception.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileError;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/new-c.ri new file mode 100644 index 00000000..af223fd5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/sass_stack-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/sass_stack-i.ri new file mode 100644 index 00000000..98dc93af --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/sass_stack-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"sass_stack:ETI""Sass::CompileError#sass_stack;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String, nil];T: +@fileI"lib/sass/exception.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileError;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/span-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/span-i.ri new file mode 100644 index 00000000..f9e267aa --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/span-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" span:ETI"Sass::CompileError#span;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"&@return [Logger::SourceSpan, nil];T: +@fileI"lib/sass/exception.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileError;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/to_css-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/to_css-i.ri new file mode 100644 index 00000000..201399d6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileError/to_css-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/cdesc-CompileResult.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/cdesc-CompileResult.ri new file mode 100644 index 00000000..a122a43b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/cdesc-CompileResult.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/css-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/css-i.ri new file mode 100644 index 00000000..1ae50a56 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/css-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"css:ETI"Sass::CompileResult#css;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String];T: +@fileI"lib/sass/compile_result.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileResult;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/loaded_urls-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/loaded_urls-i.ri new file mode 100644 index 00000000..4beaca86 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/loaded_urls-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"loaded_urls:ETI"$Sass::CompileResult#loaded_urls;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Array];T: +@fileI"lib/sass/compile_result.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileResult;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/new-c.ri new file mode 100644 index 00000000..5ff9d39a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/source_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/source_map-i.ri new file mode 100644 index 00000000..0332cf80 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/CompileResult/source_map-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"source_map:ETI"#Sass::CompileResult#source_map;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String, nil];T: +@fileI"lib/sass/compile_result.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::CompileResult;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/cdesc-Stream.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/cdesc-Stream.ri new file mode 100644 index 00000000..bad0d363 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/cdesc-Stream.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/close-i.ri new file mode 100644 index 00000000..1f4004b7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/error-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/error-i.ri new file mode 100644 index 00000000..7749a2b1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/error-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/id-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/id-i.ri new file mode 100644 index 00000000..f19c6ee0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/id-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/new-c.ri new file mode 100644 index 00000000..ce459556 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/send_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/send_proto-i.ri new file mode 100644 index 00000000..8ab2f3f4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/Stream/send_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/cdesc-Channel.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/cdesc-Channel.ri new file mode 100644 index 00000000..5f924ad6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/cdesc-Channel.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/close-i.ri new file mode 100644 index 00000000..b3120ede Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/closed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/closed%3f-i.ri new file mode 100644 index 00000000..5aa56850 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/closed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/new-c.ri new file mode 100644 index 00000000..ffad9d5d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/stream-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/stream-i.ri new file mode 100644 index 00000000..af7cd4b5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Channel/stream-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/cdesc-Connection.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/cdesc-Connection.ri new file mode 100644 index 00000000..dbd3c71b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/cdesc-Connection.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/close-i.ri new file mode 100644 index 00000000..b950a12c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/closed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/closed%3f-i.ri new file mode 100644 index 00000000..16d51682 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/closed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/id-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/id-i.ri new file mode 100644 index 00000000..279f7be3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/id-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/listen-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/listen-i.ri new file mode 100644 index 00000000..5fefe1a6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/listen-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/new-c.ri new file mode 100644 index 00000000..f671dff4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/write-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/write-i.ri new file mode 100644 index 00000000..0030592c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Connection/write-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_close-i.ri new file mode 100644 index 00000000..ba2b62d2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_closed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_closed%3f-i.ri new file mode 100644 index 00000000..007a843c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_closed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle%3f-i.ri new file mode 100644 index 00000000..79eadd5e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle-i.ri new file mode 100644 index 00000000..093d39bf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/_idle-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/cdesc-Dispatcher.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/cdesc-Dispatcher.ri new file mode 100644 index 00000000..e7828e35 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/cdesc-Dispatcher.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/close-i.ri new file mode 100644 index 00000000..1589fae8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/closed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/closed%3f-i.ri new file mode 100644 index 00000000..79ceba0e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/closed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/current_time-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/current_time-i.ri new file mode 100644 index 00000000..283a9b7e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/current_time-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/error-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/error-i.ri new file mode 100644 index 00000000..ef2642fa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/error-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/new-c.ri new file mode 100644 index 00000000..1395f3a3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/receive_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/receive_proto-i.ri new file mode 100644 index 00000000..51d6f31b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/receive_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/send_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/send_proto-i.ri new file mode 100644 index 00000000..71fc772b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/send_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/subscribe-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/subscribe-i.ri new file mode 100644 index 00000000..0f2c032a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/subscribe-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/unsubscribe-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/unsubscribe-i.ri new file mode 100644 index 00000000..e107a384 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Dispatcher/unsubscribe-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/cdesc-FunctionRegistry.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/cdesc-FunctionRegistry.ri new file mode 100644 index 00000000..9e851ca3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/cdesc-FunctionRegistry.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/compile_context-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/compile_context-i.ri new file mode 100644 index 00000000..458621b9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/compile_context-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/function_call-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/function_call-i.ri new file mode 100644 index 00000000..985b45c2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/function_call-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/global_functions-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/global_functions-i.ri new file mode 100644 index 00000000..1f659533 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/global_functions-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/new-c.ri new file mode 100644 index 00000000..ba00d5bb Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/protofier-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/protofier-i.ri new file mode 100644 index 00000000..8ff1641e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/protofier-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/register-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/register-i.ri new file mode 100644 index 00000000..d8c5ec56 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/FunctionRegistry/register-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/canonicalize-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/canonicalize-i.ri new file mode 100644 index 00000000..0c179c41 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/canonicalize-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/cdesc-ImporterRegistry.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/cdesc-ImporterRegistry.ri new file mode 100644 index 00000000..6e3e3a10 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/cdesc-ImporterRegistry.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/file_import-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/file_import-i.ri new file mode 100644 index 00000000..0b7bde0f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/file_import-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/import-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/import-i.ri new file mode 100644 index 00000000..7a5d6902 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/import-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/importers-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/importers-i.ri new file mode 100644 index 00000000..74dcef24 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/importers-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/new-c.ri new file mode 100644 index 00000000..b007298e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/register-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/register-i.ri new file mode 100644 index 00000000..54865c90 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/register-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/syntax_to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/syntax_to_proto-i.ri new file mode 100644 index 00000000..395818a3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/ImporterRegistry/syntax_to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/cdesc-DebugContext.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/cdesc-DebugContext.ri new file mode 100644 index 00000000..b45fa15e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/cdesc-DebugContext.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/new-c.ri new file mode 100644 index 00000000..04c8a3fc Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/span-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/span-i.ri new file mode 100644 index 00000000..b52fab11 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/DebugContext/span-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" span:ETI"?Sass::Compiler::Session::LoggerRegistry::DebugContext#span;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"&@return [Logger::SourceSpan, nil];T: +@fileI"1lib/sass/compiler/session/logger_registry.rb;T:0@omit_headings_from_table_of_contents_below0F@I":Sass::Compiler::Session::LoggerRegistry::DebugContext;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/cdesc-WarnContext.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/cdesc-WarnContext.ri new file mode 100644 index 00000000..6c3e2bf2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/cdesc-WarnContext.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation-i.ri new file mode 100644 index 00000000..18cfe3f2 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"deprecation:ETI"ESass::Compiler::Session::LoggerRegistry::WarnContext#deprecation;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Boolean];T: +@fileI"1lib/sass/compiler/session/logger_registry.rb;T:0@omit_headings_from_table_of_contents_below0F@I"9Sass::Compiler::Session::LoggerRegistry::WarnContext;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation_type-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation_type-i.ri new file mode 100644 index 00000000..d227fccd --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/deprecation_type-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"deprecation_type:ETI"JSass::Compiler::Session::LoggerRegistry::WarnContext#deprecation_type;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String, nil];T: +@fileI"1lib/sass/compiler/session/logger_registry.rb;T:0@omit_headings_from_table_of_contents_below0F@I"9Sass::Compiler::Session::LoggerRegistry::WarnContext;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/new-c.ri new file mode 100644 index 00000000..b77b071c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/stack-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/stack-i.ri new file mode 100644 index 00000000..fc910c84 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/WarnContext/stack-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +stack:ETI"?Sass::Compiler::Session::LoggerRegistry::WarnContext#stack;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String];T: +@fileI"1lib/sass/compiler/session/logger_registry.rb;T:0@omit_headings_from_table_of_contents_below0F@I"9Sass::Compiler::Session::LoggerRegistry::WarnContext;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/cdesc-LoggerRegistry.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/cdesc-LoggerRegistry.ri new file mode 100644 index 00000000..48518cde Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/cdesc-LoggerRegistry.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/log-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/log-i.ri new file mode 100644 index 00000000..bc237e91 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/log-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/new-c.ri new file mode 100644 index 00000000..bf890f74 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/LoggerRegistry/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/cdesc-Path.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/cdesc-Path.ri new file mode 100644 index 00000000..c0caf0bd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/cdesc-Path.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_formatted%21-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_formatted%21-i.ri new file mode 100644 index 00000000..991e3029 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_formatted%21-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_uri-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_uri-i.ri new file mode 100644 index 00000000..571be39f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Path/pretty_uri-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/cdesc-Calculation.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/cdesc-Calculation.ri new file mode 100644 index 00000000..3e661085 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/cdesc-Calculation.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/from_proto-i.ri new file mode 100644 index 00000000..720bb9a6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/to_proto-i.ri new file mode 100644 index 00000000..24d1f2a9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Calculation/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/cdesc-CalculationOperator.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/cdesc-CalculationOperator.ri new file mode 100644 index 00000000..6543083a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/cdesc-CalculationOperator.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/from_proto-i.ri new file mode 100644 index 00000000..831881af Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/to_proto-i.ri new file mode 100644 index 00000000..53a7018b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationOperator/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/cdesc-CalculationValue.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/cdesc-CalculationValue.ri new file mode 100644 index 00000000..ba9b7f0d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/cdesc-CalculationValue.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/from_proto-i.ri new file mode 100644 index 00000000..6309027d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/to_proto-i.ri new file mode 100644 index 00000000..26d29396 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/CalculationValue/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/cdesc-ListSeparator.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/cdesc-ListSeparator.ri new file mode 100644 index 00000000..467fcc30 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/cdesc-ListSeparator.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/from_proto-i.ri new file mode 100644 index 00000000..4cc1e15f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/to_proto-i.ri new file mode 100644 index 00000000..786d9f46 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/ListSeparator/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/cdesc-Number.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/cdesc-Number.ri new file mode 100644 index 00000000..914faaff Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/cdesc-Number.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/from_proto-i.ri new file mode 100644 index 00000000..7a91cf34 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/to_proto-i.ri new file mode 100644 index 00000000..8cbd3e53 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/Number/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/assert_compiler_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/assert_compiler_value-i.ri new file mode 100644 index 00000000..155c67a8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/assert_compiler_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/cdesc-Protofier.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/cdesc-Protofier.ri new file mode 100644 index 00000000..f47e03df Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/cdesc-Protofier.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/compiler_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/compiler_value-i.ri new file mode 100644 index 00000000..070ef192 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/compiler_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/from_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/from_proto-i.ri new file mode 100644 index 00000000..2763d539 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/from_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/new-c.ri new file mode 100644 index 00000000..771d7018 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/to_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/to_proto-i.ri new file mode 100644 index 00000000..59303bef Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Protofier/to_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/cdesc-StackTrace.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/cdesc-StackTrace.ri new file mode 100644 index 00000000..d9a36fb1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/cdesc-StackTrace.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/pretty_formatted%21-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/pretty_formatted%21-i.ri new file mode 100644 index 00000000..849cf823 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/StackTrace/pretty_formatted%21-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/cdesc-Struct.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/cdesc-Struct.ri new file mode 100644 index 00000000..7e5c78cd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/cdesc-Struct.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/method_missing-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/method_missing-i.ri new file mode 100644 index 00000000..d6d8d4b1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/method_missing-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/new-c.ri new file mode 100644 index 00000000..259aa581 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/respond_to_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/respond_to_missing%3f-i.ri new file mode 100644 index 00000000..8fd208b3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/Struct/respond_to_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await-i.ri new file mode 100644 index 00000000..23418df6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await0-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await0-i.ri new file mode 100644 index 00000000..6d5c4fcb Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/await0-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/backtrace-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/backtrace-i.ri new file mode 100644 index 00000000..cab84b98 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/backtrace-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/canonicalize_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/canonicalize_request-i.ri new file mode 100644 index 00000000..4f8d9709 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/canonicalize_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/cdesc-Session.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/cdesc-Session.ri new file mode 100644 index 00000000..34fb2298 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/cdesc-Session.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_request-i.ri new file mode 100644 index 00000000..3df78bb7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_response-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_response-i.ri new file mode 100644 index 00000000..af7d6a24 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/compile_response-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/error-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/error-i.ri new file mode 100644 index 00000000..d3026d3b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/error-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/file_import_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/file_import_request-i.ri new file mode 100644 index 00000000..6090e8e0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/file_import_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/function_call_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/function_call_request-i.ri new file mode 100644 index 00000000..e08f72c0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/function_call_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/id-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/id-i.ri new file mode 100644 index 00000000..e003df3e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/id-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/import_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/import_request-i.ri new file mode 100644 index 00000000..9c4fb9c6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/import_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/listen-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/listen-i.ri new file mode 100644 index 00000000..28ee12d5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/listen-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/log_event-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/log_event-i.ri new file mode 100644 index 00000000..65a14080 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/log_event-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/new-c.ri new file mode 100644 index 00000000..0af15e3b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/receive_proto-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/receive_proto-i.ri new file mode 100644 index 00000000..0fae6e80 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/receive_proto-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message-i.ri new file mode 100644 index 00000000..37815eec Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message0-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message0-i.ri new file mode 100644 index 00000000..9867cca7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/send_message0-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_request-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_request-i.ri new file mode 100644 index 00000000..d97a87f8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_request-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_response-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_response-i.ri new file mode 100644 index 00000000..a517887b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Session/version_response-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/cdesc-Varint.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/cdesc-Varint.ri new file mode 100644 index 00000000..1ec3b59d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/cdesc-Varint.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/length-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/length-i.ri new file mode 100644 index 00000000..d2be9241 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/length-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/read-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/read-i.ri new file mode 100644 index 00000000..7416c5c1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/read-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/write-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/write-i.ri new file mode 100644 index 00000000..4f88747b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/Varint/write-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/cdesc-Compiler.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/cdesc-Compiler.ri new file mode 100644 index 00000000..757af8ed Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/cdesc-Compiler.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/close-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/close-i.ri new file mode 100644 index 00000000..75f8f714 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/close-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/closed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/closed%3f-i.ri new file mode 100644 index 00000000..c8ba9cc5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/closed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile-i.ri new file mode 100644 index 00000000..9918662d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile_string-i.ri new file mode 100644 index 00000000..41d61d23 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/compile_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/info-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/info-i.ri new file mode 100644 index 00000000..8a60b8e5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/info-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/new-c.ri new file mode 100644 index 00000000..255c0e9e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Compiler/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/cdesc-PackInfo.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/cdesc-PackInfo.ri new file mode 100644 index 00000000..56f65682 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/cdesc-PackInfo.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/format-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/format-i.ri new file mode 100644 index 00000000..035008aa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/format-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/new-c.ri new file mode 100644 index 00000000..9a62e0d8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/pack-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/pack-i.ri new file mode 100644 index 00000000..60a3cfbf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/pack-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/sizeof-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/sizeof-i.ri new file mode 100644 index 00000000..cb1cd191 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/sizeof-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/unpack-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/unpack-i.ri new file mode 100644 index 00000000..0b56e467 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/PackInfo/unpack-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/cdesc-ELF.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/cdesc-ELF.ri new file mode 100644 index 00000000..9c715fbf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/cdesc-ELF.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/core%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/core%3f-i.ri new file mode 100644 index 00000000..23be7899 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/core%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/dump-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/dump-i.ri new file mode 100644 index 00000000..9bfc236d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/dump-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/executable%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/executable%3f-i.ri new file mode 100644 index 00000000..4861916b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/executable%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/interpreter-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/interpreter-i.ri new file mode 100644 index 00000000..e1dd4f43 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/interpreter-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/new-c.ri new file mode 100644 index 00000000..539cf017 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/relocatable%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/relocatable%3f-i.ri new file mode 100644 index 00000000..1743f2bb Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/relocatable%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/shared_object%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/shared_object%3f-i.ri new file mode 100644 index 00000000..d55dca4b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ELF/shared_object%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Embedded/cdesc-Embedded.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Embedded/cdesc-Embedded.ri new file mode 100644 index 00000000..5ece8054 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Embedded/cdesc-Embedded.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/CompileRequest/cdesc-CompileRequest.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/CompileRequest/cdesc-CompileRequest.ri new file mode 100644 index 00000000..dc9a2616 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/CompileRequest/cdesc-CompileRequest.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/ImportResponse/cdesc-ImportResponse.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/ImportResponse/cdesc-ImportResponse.ri new file mode 100644 index 00000000..d55eb95a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/ImportResponse/cdesc-ImportResponse.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/cdesc-InboundMessage.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/cdesc-InboundMessage.ri new file mode 100644 index 00000000..5e0d3fd5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/InboundMessage/cdesc-InboundMessage.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/CompileResponse/cdesc-CompileResponse.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/CompileResponse/cdesc-CompileResponse.ri new file mode 100644 index 00000000..90f9935a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/CompileResponse/cdesc-CompileResponse.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/cdesc-OutboundMessage.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/cdesc-OutboundMessage.ri new file mode 100644 index 00000000..1bd4f4e1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/OutboundMessage/cdesc-OutboundMessage.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/SourceSpan/cdesc-SourceSpan.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/SourceSpan/cdesc-SourceSpan.ri new file mode 100644 index 00000000..179ca005 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/SourceSpan/cdesc-SourceSpan.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Calculation/cdesc-Calculation.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Calculation/cdesc-Calculation.ri new file mode 100644 index 00000000..6fe1b489 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Calculation/cdesc-Calculation.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Map/cdesc-Map.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Map/cdesc-Map.ri new file mode 100644 index 00000000..c701128c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/Map/cdesc-Map.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/cdesc-Value.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/cdesc-Value.ri new file mode 100644 index 00000000..01429a89 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/Value/cdesc-Value.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/cdesc-EmbeddedProtocol.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/cdesc-EmbeddedProtocol.ri new file mode 100644 index 00000000..c212e096 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/EmbeddedProtocol/cdesc-EmbeddedProtocol.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/_fork-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/_fork-i.ri new file mode 100644 index 00000000..654e8cd3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/_fork-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/cdesc-CoreExt.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/cdesc-CoreExt.ri new file mode 100644 index 00000000..7a632bd1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/CoreExt/cdesc-CoreExt.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/add-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/add-i.ri new file mode 100644 index 00000000..c201885d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/add-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/cdesc-ForkTracker.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/cdesc-ForkTracker.ri new file mode 100644 index 00000000..b2039996 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/cdesc-ForkTracker.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/delete-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/delete-i.ri new file mode 100644 index 00000000..f5fefac8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/delete-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/each-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/each-i.ri new file mode 100644 index 00000000..9a672294 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ForkTracker/each-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/cdesc-GemPackageImporter.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/cdesc-GemPackageImporter.ri new file mode 100644 index 00000000..4adf1a79 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/cdesc-GemPackageImporter.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/find_file_url-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/find_file_url-i.ri new file mode 100644 index 00000000..72071877 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/GemPackageImporter/find_file_url-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/cdesc-Silent.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/cdesc-Silent.ri new file mode 100644 index 00000000..6927c42e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/cdesc-Silent.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/debug-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/debug-i.ri new file mode 100644 index 00000000..a39b8b51 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/debug-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/warn-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/warn-i.ri new file mode 100644 index 00000000..86817b3e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/Silent/warn-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/cdesc-SourceLocation.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/cdesc-SourceLocation.ri new file mode 100644 index 00000000..1e3e116d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/cdesc-SourceLocation.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/column-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/column-i.ri new file mode 100644 index 00000000..bb021308 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/column-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" column:ETI"(Sass::Logger::SourceLocation#column;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Integer];T: +@fileI"'lib/sass/logger/source_location.rb;T:0@omit_headings_from_table_of_contents_below0F@I"!Sass::Logger::SourceLocation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/line-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/line-i.ri new file mode 100644 index 00000000..4abaf18f --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/line-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" line:ETI"&Sass::Logger::SourceLocation#line;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Integer];T: +@fileI"'lib/sass/logger/source_location.rb;T:0@omit_headings_from_table_of_contents_below0F@I"!Sass::Logger::SourceLocation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/new-c.ri new file mode 100644 index 00000000..97b778aa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/offset-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/offset-i.ri new file mode 100644 index 00000000..eb0f23ea --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceLocation/offset-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" offset:ETI"(Sass::Logger::SourceLocation#offset;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Integer];T: +@fileI"'lib/sass/logger/source_location.rb;T:0@omit_headings_from_table_of_contents_below0F@I"!Sass::Logger::SourceLocation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/cdesc-SourceSpan.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/cdesc-SourceSpan.ri new file mode 100644 index 00000000..bc2c42f0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/cdesc-SourceSpan.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/context-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/context-i.ri new file mode 100644 index 00000000..e42e6306 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/context-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" context:ETI"%Sass::Logger::SourceSpan#context;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String, nil];T: +@fileI"#lib/sass/logger/source_span.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Logger::SourceSpan;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/end-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/end-i.ri new file mode 100644 index 00000000..85215892 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/end-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"end:ETI"!Sass::Logger::SourceSpan#end;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [SourceLocation];T: +@fileI"#lib/sass/logger/source_span.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Logger::SourceSpan;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/new-c.ri new file mode 100644 index 00000000..4ef68033 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/start-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/start-i.ri new file mode 100644 index 00000000..220a16fa --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/start-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +start:ETI"#Sass::Logger::SourceSpan#start;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [SourceLocation];T: +@fileI"#lib/sass/logger/source_span.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Logger::SourceSpan;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/text-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/text-i.ri new file mode 100644 index 00000000..18220ccc --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/text-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" text:ETI""Sass::Logger::SourceSpan#text;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String];T: +@fileI"#lib/sass/logger/source_span.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Logger::SourceSpan;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/url-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/url-i.ri new file mode 100644 index 00000000..50bef9ab --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/SourceSpan/url-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"url:ETI"!Sass::Logger::SourceSpan#url;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [String, nil];T: +@fileI"#lib/sass/logger/source_span.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Logger::SourceSpan;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/cdesc-Logger.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/cdesc-Logger.ri new file mode 100644 index 00000000..ee43019e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/cdesc-Logger.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/silent-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/silent-i.ri new file mode 100644 index 00000000..49a75605 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Logger/silent-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/cdesc-NodePackageImporter.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/cdesc-NodePackageImporter.ri new file mode 100644 index 00000000..f199c19b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/cdesc-NodePackageImporter.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/new-c.ri new file mode 100644 index 00000000..d990807b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/NodePackageImporter/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/cdesc-ScriptError.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/cdesc-ScriptError.ri new file mode 100644 index 00000000..b99b7d30 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/cdesc-ScriptError.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/new-c.ri new file mode 100644 index 00000000..45944982 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/ScriptError/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/cdesc-Serializer.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/cdesc-Serializer.ri new file mode 100644 index 00000000..1299a898 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/cdesc-Serializer.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_quoted_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_quoted_string-i.ri new file mode 100644 index 00000000..4a90bd81 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_quoted_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_unquoted_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_unquoted_string-i.ri new file mode 100644 index 00000000..ea9ce1e6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Serializer/serialize_unquoted_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/cdesc-Uri.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/cdesc-Uri.ri new file mode 100644 index 00000000..6a75262a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/cdesc-Uri.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/decode_uri_component-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/decode_uri_component-i.ri new file mode 100644 index 00000000..60c1825e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/decode_uri_component-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_component-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_component-i.ri new file mode 100644 index 00000000..15cca4c2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_component-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_path_component-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_path_component-i.ri new file mode 100644 index 00000000..8a5d656a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_path_component-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_query_component-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_query_component-i.ri new file mode 100644 index 00000000..b79ddd46 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/encode_uri_query_component-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/file_uri_to_path-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/file_uri_to_path-i.ri new file mode 100644 index 00000000..7be6f79a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/file_uri_to_path-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/path_to_file_uri-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/path_to_file_uri-i.ri new file mode 100644 index 00000000..5fa4e7bd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/path_to_file_uri-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/pwd-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/pwd-i.ri new file mode 100644 index 00000000..12cafa3c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/pwd-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/relative-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/relative-i.ri new file mode 100644 index 00000000..3402dc72 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Uri/relative-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/%5b%5d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/%5b%5d-i.ri new file mode 100644 index 00000000..054e734f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/%5b%5d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/cdesc-ArgumentList.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/cdesc-ArgumentList.ri new file mode 100644 index 00000000..d99688ad Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/cdesc-ArgumentList.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/keywords-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/keywords-i.ri new file mode 100644 index 00000000..74a28513 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/keywords-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/new-c.ri new file mode 100644 index 00000000..36c58ddb Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/ArgumentList/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%21-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%21-i.ri new file mode 100644 index 00000000..c03240ca Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%21-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%3d%3d-i.ri new file mode 100644 index 00000000..a9f7c16d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/assert_boolean-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/assert_boolean-i.ri new file mode 100644 index 00000000..3e294c83 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/assert_boolean-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/cdesc-Boolean.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/cdesc-Boolean.ri new file mode 100644 index 00000000..fc4ac5d0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/cdesc-Boolean.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/hash-i.ri new file mode 100644 index 00000000..6dd30ffd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/new-c.ri new file mode 100644 index 00000000..4eedee11 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/to_bool-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/to_bool-i.ri new file mode 100644 index 00000000..c665cc63 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/to_bool-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" to_bool:ETI"!Sass::Value::Boolean#to_bool;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::Boolean];T: +@fileI"lib/sass/value/boolean.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Boolean;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/value-i.ri new file mode 100644 index 00000000..c9f48da0 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Boolean/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"Sass::Value::Boolean#value;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::Boolean];T: +@fileI"lib/sass/value/boolean.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Boolean;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/%3d%3d-i.ri new file mode 100644 index 00000000..bf5d2e10 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/arguments-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/arguments-i.ri new file mode 100644 index 00000000..6613cfd1 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/arguments-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"arguments:ETI"'Sass::Value::Calculation#arguments;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"&@return [Array];T: +@fileI""lib/sass/value/calculation.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Calculation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/assert_calculation-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/assert_calculation-i.ri new file mode 100644 index 00000000..d7995dd9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/assert_calculation-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/calc-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/calc-c.ri new file mode 100644 index 00000000..31180fe6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/calc-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/cdesc-Calculation.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/cdesc-Calculation.ri new file mode 100644 index 00000000..5dcf7d02 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/cdesc-Calculation.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/clamp-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/clamp-c.ri new file mode 100644 index 00000000..7eb69680 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/clamp-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/hash-i.ri new file mode 100644 index 00000000..7269387e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/max-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/max-c.ri new file mode 100644 index 00000000..70300c84 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/max-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/min-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/min-c.ri new file mode 100644 index 00000000..cb0111be Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/min-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/name-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/name-i.ri new file mode 100644 index 00000000..b7509db9 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI""Sass::Value::Calculation#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI""lib/sass/value/calculation.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Calculation;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/new-c.ri new file mode 100644 index 00000000..6a40cb52 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/valid_clamp_arg%3f-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/valid_clamp_arg%3f-c.ri new file mode 100644 index 00000000..7f26437a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Calculation/valid_clamp_arg%3f-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/%3d%3d-i.ri new file mode 100644 index 00000000..d96e6329 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/analogous%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/analogous%3f-i.ri new file mode 100644 index 00000000..42ffaea5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/analogous%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/associated_unit-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/associated_unit-i.ri new file mode 100644 index 00000000..25998619 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/associated_unit-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"associated_unit:ETI"5Sass::Value::Color::ColorChannel#associated_unit;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String, nil];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Sass::Value::Color::ColorChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/cdesc-ColorChannel.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/cdesc-ColorChannel.ri new file mode 100644 index 00000000..626f69ac Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/cdesc-ColorChannel.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/name-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/name-i.ri new file mode 100644 index 00000000..771d006e --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI"*Sass::Value::Color::ColorChannel#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"%Sass::Value::Color::ColorChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/new-c.ri new file mode 100644 index 00000000..2d6fbb41 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/polar_angle%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/polar_angle%3f-i.ri new file mode 100644 index 00000000..0a814800 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/ColorChannel/polar_angle%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Conversions/cdesc-Conversions.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Conversions/cdesc-Conversions.ri new file mode 100644 index 00000000..21536e86 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Conversions/cdesc-Conversions.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/_clamp_channel-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/_clamp_channel-i.ri new file mode 100644 index 00000000..9b7188d3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/_clamp_channel-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/cdesc-Clip.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/cdesc-Clip.ri new file mode 100644 index 00000000..fde80062 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/cdesc-Clip.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/map-i.ri new file mode 100644 index 00000000..3c8afc09 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/new-c.ri new file mode 100644 index 00000000..61b79065 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/Clip/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/_delta_eok-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/_delta_eok-i.ri new file mode 100644 index 00000000..a0647988 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/_delta_eok-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/cdesc-LocalMinde.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/cdesc-LocalMinde.ri new file mode 100644 index 00000000..8133c044 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/cdesc-LocalMinde.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/map-i.ri new file mode 100644 index 00000000..9182a1fa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/new-c.ri new file mode 100644 index 00000000..ae10e887 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/LocalMinde/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/cdesc-GamutMapMethod.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/cdesc-GamutMapMethod.ri new file mode 100644 index 00000000..aae22f63 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/cdesc-GamutMapMethod.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/from_name-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/from_name-c.ri new file mode 100644 index 00000000..5d7d6410 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/from_name-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/map-i.ri new file mode 100644 index 00000000..91ff2442 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/name-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/name-i.ri new file mode 100644 index 00000000..7bbdbd68 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI",Sass::Value::Color::GamutMapMethod#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI"-lib/sass/value/color/gamut_map_method.rb;T:0@omit_headings_from_table_of_contents_below0F@I"'Sass::Value::Color::GamutMapMethod;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/new-c.ri new file mode 100644 index 00000000..f70eb3f2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/GamutMapMethod/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/cdesc-HueInterpolationMethod.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/cdesc-HueInterpolationMethod.ri new file mode 100644 index 00000000..6a347bca Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/cdesc-HueInterpolationMethod.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/from_name-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/from_name-c.ri new file mode 100644 index 00000000..47686b36 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/HueInterpolationMethod/from_name-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/cdesc-InterpolationMethod.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/cdesc-InterpolationMethod.ri new file mode 100644 index 00000000..07827af5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/cdesc-InterpolationMethod.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/hue-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/hue-i.ri new file mode 100644 index 00000000..f175ceac --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/hue-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"hue:ETI"0Sass::Value::Color::InterpolationMethod#hue;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Symbol, nil];T: +@fileI"1lib/sass/value/color/interpolation_method.rb;T:0@omit_headings_from_table_of_contents_below0F@I",Sass::Value::Color::InterpolationMethod;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/new-c.ri new file mode 100644 index 00000000..aeb4335b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/space-i.ri new file mode 100644 index 00000000..142c8c0d --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/InterpolationMethod/space-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +space:ETI"2Sass::Value::Color::InterpolationMethod#space;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Space];T: +@fileI"1lib/sass/value/color/interpolation_method.rb;T:0@omit_headings_from_table_of_contents_below0F@I",Sass::Value::Color::InterpolationMethod;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/cdesc-LinearChannel.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/cdesc-LinearChannel.ri new file mode 100644 index 00000000..0d013924 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/cdesc-LinearChannel.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/lower_clamped-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/lower_clamped-i.ri new file mode 100644 index 00000000..beec922b --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/lower_clamped-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"lower_clamped:ETI"4Sass::Value::Color::LinearChannel#lower_clamped;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::Boolean];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"&Sass::Value::Color::LinearChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/max-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/max-i.ri new file mode 100644 index 00000000..68c40c26 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/max-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"max:ETI"*Sass::Value::Color::LinearChannel#max;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Numeric];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"&Sass::Value::Color::LinearChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/min-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/min-i.ri new file mode 100644 index 00000000..a5cb7ec0 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/min-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"min:ETI"*Sass::Value::Color::LinearChannel#min;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Numeric];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"&Sass::Value::Color::LinearChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/new-c.ri new file mode 100644 index 00000000..5c39c652 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/requires_percent-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/requires_percent-i.ri new file mode 100644 index 00000000..9be97bac --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/requires_percent-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"requires_percent:ETI"7Sass::Value::Color::LinearChannel#requires_percent;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::Boolean];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"&Sass::Value::Color::LinearChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/upper_clamped-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/upper_clamped-i.ri new file mode 100644 index 00000000..eccc1682 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/LinearChannel/upper_clamped-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"upper_clamped:ETI"4Sass::Value::Color::LinearChannel#upper_clamped;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::Boolean];T: +@fileI"$lib/sass/value/color/channel.rb;T:0@omit_headings_from_table_of_contents_below0F@I"&Sass::Value::Color::LinearChannel;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/bounded%3f-i.ri new file mode 100644 index 00000000..7c5fad7e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/cdesc-A98Rgb.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/cdesc-A98Rgb.ri new file mode 100644 index 00000000..86d81a6c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/cdesc-A98Rgb.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/from_linear-i.ri new file mode 100644 index 00000000..8f3871d9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/new-c.ri new file mode 100644 index 00000000..280d8628 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/to_linear-i.ri new file mode 100644 index 00000000..cc06901c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/transformation_matrix-i.ri new file mode 100644 index 00000000..0d26d43e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/A98Rgb/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/bounded%3f-i.ri new file mode 100644 index 00000000..144892e4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/cdesc-DisplayP3.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/cdesc-DisplayP3.ri new file mode 100644 index 00000000..783e7a42 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/cdesc-DisplayP3.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/convert-i.ri new file mode 100644 index 00000000..0ccd973f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/from_linear-i.ri new file mode 100644 index 00000000..2f18182e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/new-c.ri new file mode 100644 index 00000000..41b4f2c1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/to_linear-i.ri new file mode 100644 index 00000000..93b58199 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/transformation_matrix-i.ri new file mode 100644 index 00000000..97a444b2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/bounded%3f-i.ri new file mode 100644 index 00000000..c6ba7274 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/cdesc-DisplayP3Linear.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/cdesc-DisplayP3Linear.ri new file mode 100644 index 00000000..6f27ca64 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/cdesc-DisplayP3Linear.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/convert-i.ri new file mode 100644 index 00000000..68fd5267 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/from_linear-i.ri new file mode 100644 index 00000000..e9950be7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/new-c.ri new file mode 100644 index 00000000..f31d1738 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/to_linear-i.ri new file mode 100644 index 00000000..783ec352 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/transformation_matrix-i.ri new file mode 100644 index 00000000..d004a006 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/DisplayP3Linear/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/bounded%3f-i.ri new file mode 100644 index 00000000..865d56cd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/cdesc-Hsl.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/cdesc-Hsl.ri new file mode 100644 index 00000000..09dc5b84 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/cdesc-Hsl.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/convert-i.ri new file mode 100644 index 00000000..c47da9a6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/legacy%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/legacy%3f-i.ri new file mode 100644 index 00000000..1b0dc113 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/legacy%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/new-c.ri new file mode 100644 index 00000000..285198f8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/polar%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/polar%3f-i.ri new file mode 100644 index 00000000..46cdfe85 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hsl/polar%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/bounded%3f-i.ri new file mode 100644 index 00000000..0401f88c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/cdesc-Hwb.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/cdesc-Hwb.ri new file mode 100644 index 00000000..3110d53f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/cdesc-Hwb.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/convert-i.ri new file mode 100644 index 00000000..f14d8b00 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/legacy%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/legacy%3f-i.ri new file mode 100644 index 00000000..de76857f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/legacy%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/new-c.ri new file mode 100644 index 00000000..33904fd3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/polar%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/polar%3f-i.ri new file mode 100644 index 00000000..11892ff0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Hwb/polar%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/_convert_f_to_x_or_z-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/_convert_f_to_x_or_z-i.ri new file mode 100644 index 00000000..b76d4a67 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/_convert_f_to_x_or_z-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/bounded%3f-i.ri new file mode 100644 index 00000000..25797d0f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/cdesc-Lab.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/cdesc-Lab.ri new file mode 100644 index 00000000..996b504d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/cdesc-Lab.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/convert-i.ri new file mode 100644 index 00000000..a71285ce Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/new-c.ri new file mode 100644 index 00000000..58a6e1be Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lab/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/bounded%3f-i.ri new file mode 100644 index 00000000..c48ab3d5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/cdesc-Lch.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/cdesc-Lch.ri new file mode 100644 index 00000000..0e3b9126 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/cdesc-Lch.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/convert-i.ri new file mode 100644 index 00000000..f420e122 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/new-c.ri new file mode 100644 index 00000000..77ab4e43 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/polar%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/polar%3f-i.ri new file mode 100644 index 00000000..3de8ee3c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lch/polar%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/bounded%3f-i.ri new file mode 100644 index 00000000..1aeae40a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/cdesc-Lms.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/cdesc-Lms.ri new file mode 100644 index 00000000..5b601513 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/cdesc-Lms.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/convert-i.ri new file mode 100644 index 00000000..05324fd4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/from_linear-i.ri new file mode 100644 index 00000000..32c54a21 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/new-c.ri new file mode 100644 index 00000000..3b15f953 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/to_linear-i.ri new file mode 100644 index 00000000..659dd5bd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/transformation_matrix-i.ri new file mode 100644 index 00000000..979a4fc1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Lms/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/bounded%3f-i.ri new file mode 100644 index 00000000..814bde3d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/cdesc-Oklab.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/cdesc-Oklab.ri new file mode 100644 index 00000000..42b22808 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/cdesc-Oklab.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/convert-i.ri new file mode 100644 index 00000000..729b250e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/new-c.ri new file mode 100644 index 00000000..a09e68b2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklab/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/bounded%3f-i.ri new file mode 100644 index 00000000..f003c9df Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/cdesc-Oklch.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/cdesc-Oklch.ri new file mode 100644 index 00000000..d3a1e4d9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/cdesc-Oklch.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/convert-i.ri new file mode 100644 index 00000000..e7d63bb1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/new-c.ri new file mode 100644 index 00000000..e6fcd39b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/polar%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/polar%3f-i.ri new file mode 100644 index 00000000..003400e2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Oklch/polar%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/bounded%3f-i.ri new file mode 100644 index 00000000..0fd7feab Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/cdesc-ProphotoRgb.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/cdesc-ProphotoRgb.ri new file mode 100644 index 00000000..48501ef3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/cdesc-ProphotoRgb.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/from_linear-i.ri new file mode 100644 index 00000000..5427b803 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/new-c.ri new file mode 100644 index 00000000..9b407f72 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/to_linear-i.ri new file mode 100644 index 00000000..f8e1c80e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/transformation_matrix-i.ri new file mode 100644 index 00000000..f3b0f7de Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/ProphotoRgb/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/bounded%3f-i.ri new file mode 100644 index 00000000..e4d3b712 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/cdesc-Rec2020.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/cdesc-Rec2020.ri new file mode 100644 index 00000000..21519ccd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/cdesc-Rec2020.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/from_linear-i.ri new file mode 100644 index 00000000..bf8b8322 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/new-c.ri new file mode 100644 index 00000000..de1aa98f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/to_linear-i.ri new file mode 100644 index 00000000..8424270a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/transformation_matrix-i.ri new file mode 100644 index 00000000..58ddaf6c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rec2020/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/bounded%3f-i.ri new file mode 100644 index 00000000..8f604b04 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/cdesc-Rgb.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/cdesc-Rgb.ri new file mode 100644 index 00000000..31a4ec38 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/cdesc-Rgb.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/convert-i.ri new file mode 100644 index 00000000..13330479 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/from_linear-i.ri new file mode 100644 index 00000000..45e36f8b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/legacy%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/legacy%3f-i.ri new file mode 100644 index 00000000..02e9406d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/legacy%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/new-c.ri new file mode 100644 index 00000000..9860196a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/to_linear-i.ri new file mode 100644 index 00000000..d500cd65 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Rgb/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/bounded%3f-i.ri new file mode 100644 index 00000000..f8fa3479 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/cdesc-Srgb.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/cdesc-Srgb.ri new file mode 100644 index 00000000..010ffb3f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/cdesc-Srgb.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/convert-i.ri new file mode 100644 index 00000000..b1ece1d9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/from_linear-i.ri new file mode 100644 index 00000000..c6a3cd99 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/new-c.ri new file mode 100644 index 00000000..aa245301 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/to_linear-i.ri new file mode 100644 index 00000000..2ad5da11 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/transformation_matrix-i.ri new file mode 100644 index 00000000..460253e2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Srgb/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/bounded%3f-i.ri new file mode 100644 index 00000000..32a478aa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/cdesc-SrgbLinear.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/cdesc-SrgbLinear.ri new file mode 100644 index 00000000..80cf31e4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/cdesc-SrgbLinear.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/convert-i.ri new file mode 100644 index 00000000..215f730a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/from_linear-i.ri new file mode 100644 index 00000000..72ff8e94 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/new-c.ri new file mode 100644 index 00000000..0c518ce5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/to_linear-i.ri new file mode 100644 index 00000000..52233c28 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/transformation_matrix-i.ri new file mode 100644 index 00000000..df681e4e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/SrgbLinear/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/cdesc-Utils.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/cdesc-Utils.ri new file mode 100644 index 00000000..a99fd5ce Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/cdesc-Utils.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/lab_to_lch-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/lab_to_lch-i.ri new file mode 100644 index 00000000..64bb9c3e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/lab_to_lch-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_from_linear-i.ri new file mode 100644 index 00000000..54f546cf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_to_linear-i.ri new file mode 100644 index 00000000..4edf4a7f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/Utils/srgb_and_display_p3_to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/_convert_component_to_lab_f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/_convert_component_to_lab_f-i.ri new file mode 100644 index 00000000..f3114677 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/_convert_component_to_lab_f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/bounded%3f-i.ri new file mode 100644 index 00000000..09afd163 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/cdesc-XyzD50.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/cdesc-XyzD50.ri new file mode 100644 index 00000000..37986dad Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/cdesc-XyzD50.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/convert-i.ri new file mode 100644 index 00000000..dd1cdf39 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/from_linear-i.ri new file mode 100644 index 00000000..924302d7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/new-c.ri new file mode 100644 index 00000000..9252bc0f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/to_linear-i.ri new file mode 100644 index 00000000..ce60ff9e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/transformation_matrix-i.ri new file mode 100644 index 00000000..caf3313d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD50/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/bounded%3f-i.ri new file mode 100644 index 00000000..b7125bb4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/cdesc-XyzD65.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/cdesc-XyzD65.ri new file mode 100644 index 00000000..b4c7e2be Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/cdesc-XyzD65.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/from_linear-i.ri new file mode 100644 index 00000000..07cb8852 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/new-c.ri new file mode 100644 index 00000000..f223342c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/to_linear-i.ri new file mode 100644 index 00000000..cd40249f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/transformation_matrix-i.ri new file mode 100644 index 00000000..8c8342da Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/XyzD65/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/bounded%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/bounded%3f-i.ri new file mode 100644 index 00000000..e9fadece Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/bounded%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/cdesc-Space.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/cdesc-Space.ri new file mode 100644 index 00000000..23f40a1f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/cdesc-Space.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/channels-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/channels-i.ri new file mode 100644 index 00000000..b2c997f7 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/channels-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" channels:ETI"'Sass::Value::Color::Space#channels;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I""@return [Array];T: +@fileI""lib/sass/value/color/space.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Color::Space;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert-i.ri new file mode 100644 index 00000000..a5363365 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert_linear-i.ri new file mode 100644 index 00000000..a6d290e0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/convert_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_linear-i.ri new file mode 100644 index 00000000..95be0d24 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_name-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_name-c.ri new file mode 100644 index 00000000..b8d4d1c1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/from_name-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/legacy%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/legacy%3f-i.ri new file mode 100644 index 00000000..6a9be575 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/legacy%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/name-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/name-i.ri new file mode 100644 index 00000000..78a71151 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/name-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" name:ETI"#Sass::Value::Color::Space#name;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI""lib/sass/value/color/space.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Color::Space;TcRDoc::NormalModule0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/new-c.ri new file mode 100644 index 00000000..d200dd21 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/polar%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/polar%3f-i.ri new file mode 100644 index 00000000..0a2e93b4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/polar%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/to_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/to_linear-i.ri new file mode 100644 index 00000000..203773e6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/to_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/transformation_matrix-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/transformation_matrix-i.ri new file mode 100644 index 00000000..aa5da2bf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/Space/transformation_matrix-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_assert_options-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_assert_options-i.ri new file mode 100644 index 00000000..87bf3577 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_assert_options-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_for_space-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_for_space-c.ri new file mode 100644 index 00000000..881fcd64 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_for_space-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_in_gamut%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_in_gamut%3f-i.ri new file mode 100644 index 00000000..01a1e57a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_in_gamut%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space-i.ri new file mode 100644 index 00000000..e34f8e34 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space_internal-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space_internal-i.ri new file mode 100644 index 00000000..87a1f69a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_initialize_for_space_internal-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate-i.ri new file mode 100644 index 00000000..27ce68a6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate_hues-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate_hues-i.ri new file mode 100644 index 00000000..878072ac Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_interpolate_hues-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_is_channel_in_gamut%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_is_channel_in_gamut%3f-i.ri new file mode 100644 index 00000000..10dca3ac Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_is_channel_in_gamut%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_hue-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_hue-i.ri new file mode 100644 index 00000000..b2458875 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_hue-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_linear-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_linear-i.ri new file mode 100644 index 00000000..60726b5d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_normalize_linear-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_space-i.ri new file mode 100644 index 00000000..32b0c319 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_space-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_gamut-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_gamut-i.ri new file mode 100644 index 00000000..5191c9ff Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_gamut-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_space-i.ri new file mode 100644 index 00000000..4c1d147a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/_to_space-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha-i.ri new file mode 100644 index 00000000..ea1bc29b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_missing%3f-i.ri new file mode 100644 index 00000000..941cfb3d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_or_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_or_nil-i.ri new file mode 100644 index 00000000..4c19e5ef Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/alpha_or_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/assert_color-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/assert_color-i.ri new file mode 100644 index 00000000..bce557c2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/assert_color-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blackness-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blackness-i.ri new file mode 100644 index 00000000..a592bff7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blackness-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blue-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blue-i.ri new file mode 100644 index 00000000..06c67317 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/blue-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/cdesc-Color.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/cdesc-Color.ri new file mode 100644 index 00000000..77ff9b55 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/cdesc-Color.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/change-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/change-i.ri new file mode 100644 index 00000000..c5971852 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/change-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel-i.ri new file mode 100644 index 00000000..ca5072a1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0-i.ri new file mode 100644 index 00000000..de1672a5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_missing%3f-i.ri new file mode 100644 index 00000000..d688e56a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_or_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_or_nil-i.ri new file mode 100644 index 00000000..daf4bdb2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_or_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_powerless%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_powerless%3f-i.ri new file mode 100644 index 00000000..116a39db Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel0_powerless%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1-i.ri new file mode 100644 index 00000000..c06b6434 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_missing%3f-i.ri new file mode 100644 index 00000000..989ed200 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_or_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_or_nil-i.ri new file mode 100644 index 00000000..1f7610e6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_or_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_powerless%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_powerless%3f-i.ri new file mode 100644 index 00000000..b977b57a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel1_powerless%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2-i.ri new file mode 100644 index 00000000..ebd711f9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_missing%3f-i.ri new file mode 100644 index 00000000..26bab5a7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_or_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_or_nil-i.ri new file mode 100644 index 00000000..0190d70a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_or_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_powerless%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_powerless%3f-i.ri new file mode 100644 index 00000000..14f7018b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel2_powerless%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_missing%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_missing%3f-i.ri new file mode 100644 index 00000000..010f472c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_missing%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_powerless%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_powerless%3f-i.ri new file mode 100644 index 00000000..1f1c22d6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channel_powerless%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels-i.ri new file mode 100644 index 00000000..702a3eaa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels_or_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels_or_nil-i.ri new file mode 100644 index 00000000..c4717c7f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/channels_or_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space-c.ri new file mode 100644 index 00000000..9a0bd3b3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space_internal-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space_internal-c.ri new file mode 100644 index 00000000..1c326231 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/for_space_internal-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/green-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/green-i.ri new file mode 100644 index 00000000..aab54ad7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/green-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hash-i.ri new file mode 100644 index 00000000..86ece3a3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hue-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hue-i.ri new file mode 100644 index 00000000..4e88040c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/hue-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/in_gamut%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/in_gamut%3f-i.ri new file mode 100644 index 00000000..37c8cc4a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/in_gamut%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/interpolate-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/interpolate-i.ri new file mode 100644 index 00000000..d624f0f7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/interpolate-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/legacy%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/legacy%3f-i.ri new file mode 100644 index 00000000..b848b1fd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/legacy%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/lightness-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/lightness-i.ri new file mode 100644 index 00000000..d0e196f2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/lightness-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/new-c.ri new file mode 100644 index 00000000..69c013a4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/red-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/red-i.ri new file mode 100644 index 00000000..f911208d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/red-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/saturation-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/saturation-i.ri new file mode 100644 index 00000000..f6154d26 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/saturation-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/space-i.ri new file mode 100644 index 00000000..f7dd59db Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/space-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_gamut-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_gamut-i.ri new file mode 100644 index 00000000..22e8be59 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_gamut-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_space-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_space-i.ri new file mode 100644 index 00000000..62323a13 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/to_space-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/whiteness-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/whiteness-i.ri new file mode 100644 index 00000000..7fb3ac91 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Color/whiteness-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/%3d%3d-i.ri new file mode 100644 index 00000000..df344e22 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/assert_function-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/assert_function-i.ri new file mode 100644 index 00000000..a6772511 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/assert_function-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/callback-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/callback-i.ri new file mode 100644 index 00000000..fdf78957 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/callback-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" callback:ETI"#Sass::Value::Function#callback;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Proc, nil];T: +@fileI"lib/sass/value/function.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Function;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/cdesc-Function.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/cdesc-Function.ri new file mode 100644 index 00000000..8d58099e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/cdesc-Function.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/hash-i.ri new file mode 100644 index 00000000..6fc5551a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/new-c.ri new file mode 100644 index 00000000..80af39a2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/signature-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/signature-i.ri new file mode 100644 index 00000000..fcf386d1 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Function/signature-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"signature:ETI"$Sass::Value::Function#signature;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String, nil];T: +@fileI"lib/sass/value/function.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Function;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_clamp_like_css-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_clamp_like_css-i.ri new file mode 100644 index 00000000..bea193b2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_clamp_like_css-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_hash-i.ri new file mode 100644 index 00000000..cfdad98a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/_hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/assert_between-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/assert_between-i.ri new file mode 100644 index 00000000..36b5671a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/assert_between-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/between-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/between-i.ri new file mode 100644 index 00000000..67a41ab0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/between-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/cdesc-FuzzyMath.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/cdesc-FuzzyMath.ri new file mode 100644 index 00000000..fa42067f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/cdesc-FuzzyMath.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals%3f-i.ri new file mode 100644 index 00000000..45a070e7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals_nilable%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals_nilable%3f-i.ri new file mode 100644 index 00000000..f560f740 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/equals_nilable%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than%3f-i.ri new file mode 100644 index 00000000..0bcc6912 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than_or_equals%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than_or_equals%3f-i.ri new file mode 100644 index 00000000..57a71654 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/greater_than_or_equals%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/integer%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/integer%3f-i.ri new file mode 100644 index 00000000..d3f53e40 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/integer%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than%3f-i.ri new file mode 100644 index 00000000..bd2b1ac4 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than_or_equals%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than_or_equals%3f-i.ri new file mode 100644 index 00000000..04529762 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/less_than_or_equals%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/to_i-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/to_i-i.ri new file mode 100644 index 00000000..012f76b0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/FuzzyMath/to_i-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/%3d%3d-i.ri new file mode 100644 index 00000000..fb1653d3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/assert_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/assert_map-i.ri new file mode 100644 index 00000000..ac3094f7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/assert_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/at-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/at-i.ri new file mode 100644 index 00000000..2e413f9a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/at-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/bracketed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/bracketed%3f-i.ri new file mode 100644 index 00000000..11a728dd Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/bracketed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/cdesc-List.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/cdesc-List.ri new file mode 100644 index 00000000..31fc3406 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/cdesc-List.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/hash-i.ri new file mode 100644 index 00000000..35d664ba Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/new-c.ri new file mode 100644 index 00000000..2dbc3672 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/separator-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/separator-i.ri new file mode 100644 index 00000000..42875ecf --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/separator-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"separator:ETI" Sass::Value::List#separator;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String, nil];T: +@fileI"lib/sass/value/list.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::List;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a-i.ri new file mode 100644 index 00000000..d7e430bf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a_length-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a_length-i.ri new file mode 100644 index 00000000..9bc2846e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_a_length-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_map-i.ri new file mode 100644 index 00000000..3742aeb6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/List/to_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/%3d%3d-i.ri new file mode 100644 index 00000000..78c73d58 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/assert_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/assert_map-i.ri new file mode 100644 index 00000000..bde8de7f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/assert_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/at-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/at-i.ri new file mode 100644 index 00000000..c5574bd7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/at-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/cdesc-Map.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/cdesc-Map.ri new file mode 100644 index 00000000..88838f1a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/cdesc-Map.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/contents-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/contents-i.ri new file mode 100644 index 00000000..9cf395a5 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/contents-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" contents:ETI"Sass::Value::Map#contents;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"!@return [Hash];T: +@fileI"lib/sass/value/map.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Map;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/hash-i.ri new file mode 100644 index 00000000..3305949a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/new-c.ri new file mode 100644 index 00000000..6105f8f1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/separator-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/separator-i.ri new file mode 100644 index 00000000..08833d3a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/separator-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a-i.ri new file mode 100644 index 00000000..b71f65f6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a_length-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a_length-i.ri new file mode 100644 index 00000000..a8e653b0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_a_length-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_map-i.ri new file mode 100644 index 00000000..de197385 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Map/to_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/%3d%3d-i.ri new file mode 100644 index 00000000..0a220421 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/assert_mixin-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/assert_mixin-i.ri new file mode 100644 index 00000000..f664a261 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/assert_mixin-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/cdesc-Mixin.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/cdesc-Mixin.ri new file mode 100644 index 00000000..a6f3b02d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/cdesc-Mixin.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/hash-i.ri new file mode 100644 index 00000000..fbb0953b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Mixin/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%21-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%21-i.ri new file mode 100644 index 00000000..24f781ef Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%21-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%3d%3d-i.ri new file mode 100644 index 00000000..4da152df Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/cdesc-Null.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/cdesc-Null.ri new file mode 100644 index 00000000..d00b2e3c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/cdesc-Null.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/hash-i.ri new file mode 100644 index 00000000..0317926b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/new-c.ri new file mode 100644 index 00000000..6b78fd42 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_bool-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_bool-i.ri new file mode 100644 index 00000000..0a34f8e6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_bool-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_nil-i.ri new file mode 100644 index 00000000..599ad821 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/to_nil-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" to_nil:ETI"Sass::Value::Null#to_nil;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [nil];T: +@fileI"lib/sass/value/null.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Null;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/value-i.ri new file mode 100644 index 00000000..bf20eb77 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Null/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"Sass::Value::Null#value;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [nil];T: +@fileI"lib/sass/value/null.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Null;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/%3d%3d-i.ri new file mode 100644 index 00000000..d2b1a1f8 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier-i.ri new file mode 100644 index 00000000..957c92f9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier_for_unit-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier_for_unit-i.ri new file mode 100644 index 00000000..153408fa Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonical_multiplier_for_unit-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonicalize_units-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonicalize_units-i.ri new file mode 100644 index 00000000..f5194c47 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/canonicalize_units-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/cdesc-Unit.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/cdesc-Unit.ri new file mode 100644 index 00000000..1426e673 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/cdesc-Unit.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/conversion_factor-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/conversion_factor-i.ri new file mode 100644 index 00000000..994d7f26 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/Unit/conversion_factor-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_between-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_between-i.ri new file mode 100644 index 00000000..27ccf77f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_between-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_integer-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_integer-i.ri new file mode 100644 index 00000000..d3218cbe Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_integer-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_number-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_number-i.ri new file mode 100644 index 00000000..d4819d86 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_number-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unit-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unit-i.ri new file mode 100644 index 00000000..252315f1 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unit-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unitless-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unitless-i.ri new file mode 100644 index 00000000..c625a7f5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/assert_unitless-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/canonical_units_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/canonical_units_value-i.ri new file mode 100644 index 00000000..21f51b92 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/canonical_units_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/cdesc-Number.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/cdesc-Number.ri new file mode 100644 index 00000000..51d74ca2 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/cdesc-Number.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce-i.ri new file mode 100644 index 00000000..5e082d57 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_or_convert_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_or_convert_value-i.ri new file mode 100644 index 00000000..95d0dcdc Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_or_convert_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_to_match-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_to_match-i.ri new file mode 100644 index 00000000..a5248a81 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_to_match-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value-i.ri new file mode 100644 index 00000000..c2c5625d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_match-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_match-i.ri new file mode 100644 index 00000000..37c27e5a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_match-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_unit-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_unit-i.ri new file mode 100644 index 00000000..632dc6ec Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/coerce_value_to_unit-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/compatible_with_unit%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/compatible_with_unit%3f-i.ri new file mode 100644 index 00000000..ce6a2644 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/compatible_with_unit%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert-i.ri new file mode 100644 index 00000000..15eb881e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_to_match-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_to_match-i.ri new file mode 100644 index 00000000..5faf6045 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_to_match-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value-i.ri new file mode 100644 index 00000000..981da90c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value_to_match-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value_to_match-i.ri new file mode 100644 index 00000000..6f93efd3 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/convert_value_to_match-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/denominator_units-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/denominator_units-i.ri new file mode 100644 index 00000000..b05e575b --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/denominator_units-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"denominator_units:ETI"*Sass::Value::Number#denominator_units;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Array<::String>];T: +@fileI"lib/sass/value/number.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Number;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/hash-i.ri new file mode 100644 index 00000000..fcbc141b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/integer%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/integer%3f-i.ri new file mode 100644 index 00000000..16096cf6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/integer%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/new-c.ri new file mode 100644 index 00000000..4f80d2e9 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/numerator_units-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/numerator_units-i.ri new file mode 100644 index 00000000..60d67fd3 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/numerator_units-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI"numerator_units:ETI"(Sass::Value::Number#numerator_units;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Array<::String>];T: +@fileI"lib/sass/value/number.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Number;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/single_unit%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/single_unit%3f-i.ri new file mode 100644 index 00000000..5981dbbf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/single_unit%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/to_i-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/to_i-i.ri new file mode 100644 index 00000000..ed55da0b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/to_i-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit%3f-i.ri new file mode 100644 index 00000000..be86e1f5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit_string-i.ri new file mode 100644 index 00000000..7f80b225 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unit_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unitless%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unitless%3f-i.ri new file mode 100644 index 00000000..0e79a2a6 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/unitless%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/units%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/units%3f-i.ri new file mode 100644 index 00000000..1815aa9c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/units%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/value-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/value-i.ri new file mode 100644 index 00000000..a450ea1f --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/Number/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI"Sass::Value::Number#value;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [Numeric];T: +@fileI"lib/sass/value/number.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::Number;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/%3d%3d-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/%3d%3d-i.ri new file mode 100644 index 00000000..7169a21b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/%3d%3d-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/assert_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/assert_string-i.ri new file mode 100644 index 00000000..f8e7ab50 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/assert_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/cdesc-String.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/cdesc-String.ri new file mode 100644 index 00000000..dda82872 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/cdesc-String.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/hash-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/hash-i.ri new file mode 100644 index 00000000..bf7da24a Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/hash-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/new-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/new-c.ri new file mode 100644 index 00000000..983d7f7c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/new-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/quoted%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/quoted%3f-i.ri new file mode 100644 index 00000000..a3f34b08 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/quoted%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/sass_index_to_string_index-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/sass_index_to_string_index-i.ri new file mode 100644 index 00000000..7f55a698 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/sass_index_to_string_index-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/text-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/text-i.ri new file mode 100644 index 00000000..336296c7 --- /dev/null +++ b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/text-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" text:ETI"Sass::Value::String#text;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"@return [::String];T: +@fileI"lib/sass/value/string.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Sass::Value::String;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/to_s-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/to_s-i.ri new file mode 100644 index 00000000..1d66470c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/String/to_s-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_boolean-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_boolean-i.ri new file mode 100644 index 00000000..30aad225 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_boolean-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_calculation-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_calculation-i.ri new file mode 100644 index 00000000..e732c4c7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_calculation-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_color-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_color-i.ri new file mode 100644 index 00000000..262bf00f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_color-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_function-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_function-i.ri new file mode 100644 index 00000000..1e35f55b Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_function-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_map-i.ri new file mode 100644 index 00000000..f9520ee7 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_mixin-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_mixin-i.ri new file mode 100644 index 00000000..611188cf Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_mixin-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_number-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_number-i.ri new file mode 100644 index 00000000..2faa839d Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_number-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_string-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_string-i.ri new file mode 100644 index 00000000..fc349e55 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/assert_string-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/at-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/at-i.ri new file mode 100644 index 00000000..aaa5d4ca Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/at-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/bracketed%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/bracketed%3f-i.ri new file mode 100644 index 00000000..241eb444 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/bracketed%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/cdesc-Value.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/cdesc-Value.ri new file mode 100644 index 00000000..532b7f90 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/cdesc-Value.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/eql%3f-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/eql%3f-i.ri new file mode 100644 index 00000000..a3bfff45 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/eql%3f-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/sass_index_to_array_index-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/sass_index_to_array_index-i.ri new file mode 100644 index 00000000..b5ea84d5 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/sass_index_to_array_index-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/separator-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/separator-i.ri new file mode 100644 index 00000000..e9f0533e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/separator-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a-i.ri new file mode 100644 index 00000000..b24dd9ab Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a_length-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a_length-i.ri new file mode 100644 index 00000000..3f5abe59 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_a_length-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_bool-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_bool-i.ri new file mode 100644 index 00000000..05938aa0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_bool-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_map-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_map-i.ri new file mode 100644 index 00000000..b9f12128 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_map-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_nil-i.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_nil-i.ri new file mode 100644 index 00000000..dd30d54f Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/Value/to_nil-i.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/cdesc-Sass.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/cdesc-Sass.ri new file mode 100644 index 00000000..ab61d172 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/cdesc-Sass.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile-c.ri new file mode 100644 index 00000000..33d3f94e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile_string-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile_string-c.ri new file mode 100644 index 00000000..9b7e57de Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compile_string-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compiler-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compiler-c.ri new file mode 100644 index 00000000..e38e3f7c Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/compiler-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/info-c.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/info-c.ri new file mode 100644 index 00000000..1e04397e Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/Sass/info-c.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/cache.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/cache.ri new file mode 100644 index 00000000..675bdb18 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/cache.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/page-sass.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/page-sass.ri new file mode 100644 index 00000000..50848fd0 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/page-sass.ri differ diff --git a/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/src/page-LICENSE.ri b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/src/page-LICENSE.ri new file mode 100644 index 00000000..95940810 Binary files /dev/null and b/bin/doc/sass-embedded-1.104.1-x86_64-linux-gnu/ri/lib/sass/dart-sass/src/page-LICENSE.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Object/cdesc-Object.ri b/bin/doc/terminal-table-3.0.2/ri/Object/cdesc-Object.ri new file mode 100644 index 00000000..ab3492da Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Object/cdesc-Object.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3c%3c-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3c%3c-i.ri new file mode 100644 index 00000000..6c0fd6ed Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3c%3c-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3d%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3d%3d-i.ri new file mode 100644 index 00000000..5c979c24 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/%3d%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/cdesc-AsciiBorder.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/cdesc-AsciiBorder.ri new file mode 100644 index 00000000..4d901177 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/cdesc-AsciiBorder.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/horizontal-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/horizontal-i.ri new file mode 100644 index 00000000..47cd905c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/horizontal-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/new-c.ri new file mode 100644 index 00000000..fb8412f4 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/vertical-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/vertical-i.ri new file mode 100644 index 00000000..233a8d6b Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/AsciiBorder/vertical-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d%3d-i.ri new file mode 100644 index 00000000..9652995c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d-i.ri new file mode 100644 index 00000000..835cc2c4 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/%5b%5d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/bottom-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/bottom-i.ri new file mode 100644 index 00000000..c3b147ee Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/bottom-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/cdesc-Border.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/cdesc-Border.ri new file mode 100644 index 00000000..91e46cd9 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/cdesc-Border.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/data-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/data-i.ri new file mode 100644 index 00000000..109a3540 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/data-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/initialize_dup-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/initialize_dup-i.ri new file mode 100644 index 00000000..fc40a9c4 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/initialize_dup-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/left-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/left-i.ri new file mode 100644 index 00000000..e067376f Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/left-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/maybeleft-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/maybeleft-i.ri new file mode 100644 index 00000000..fea39165 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/maybeleft-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/mayberight-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/mayberight-i.ri new file mode 100644 index 00000000..290d1ffa Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/mayberight-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/new-c.ri new file mode 100644 index 00000000..fbad05d2 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_horizontals-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_horizontals-i.ri new file mode 100644 index 00000000..74e04526 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_horizontals-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_verticals-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_verticals-i.ri new file mode 100644 index 00000000..b714fe80 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/remove_verticals-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/right-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/right-i.ri new file mode 100644 index 00000000..ae274d83 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/right-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/top-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/top-i.ri new file mode 100644 index 00000000..7fa74b97 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Border/top-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/align-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/align-i.ri new file mode 100644 index 00000000..cced7dbb Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/align-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3d-i.ri new file mode 100644 index 00000000..25f72eb5 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3f-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3f-i.ri new file mode 100644 index 00000000..cd23bc90 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment%3f-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment-i.ri new file mode 100644 index 00000000..35e6cba2 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/alignment-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/cdesc-Cell.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/cdesc-Cell.ri new file mode 100644 index 00000000..4b6a0723 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/cdesc-Cell.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/colspan-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/colspan-i.ri new file mode 100644 index 00000000..cabce7da --- /dev/null +++ b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/colspan-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" colspan:ETI""Terminal::Table::Cell#colspan;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Column span.;T: +@fileI"lib/terminal-table/cell.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Terminal::Table::Cell;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/inspect-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/inspect-i.ri new file mode 100644 index 00000000..6f12f2f3 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/inspect-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/lines-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/lines-i.ri new file mode 100644 index 00000000..ed4617bb Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/lines-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/new-c.ri new file mode 100644 index 00000000..9c82780d Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/render-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/render-i.ri new file mode 100644 index 00000000..d773bedd Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/render-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/to_s-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/to_s-i.ri new file mode 100644 index 00000000..c123f990 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/to_s-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value-i.ri new file mode 100644 index 00000000..a04ddb1a --- /dev/null +++ b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +value:ETI" Terminal::Table::Cell#value;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Cell value.;T: +@fileI"lib/terminal-table/cell.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Terminal::Table::Cell;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value_for_column_width_recalc-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value_for_column_width_recalc-i.ri new file mode 100644 index 00000000..a60b2602 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/value_for_column_width_recalc-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/width-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/width-i.ri new file mode 100644 index 00000000..6db86913 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Cell/width-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/cdesc-MarkdownBorder.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/cdesc-MarkdownBorder.ri new file mode 100644 index 00000000..313a6a25 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/cdesc-MarkdownBorder.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/new-c.ri new file mode 100644 index 00000000..df69a71f Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/MarkdownBorder/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%3c%3c-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%3c%3c-i.ri new file mode 100644 index 00000000..a9351b61 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%3c%3c-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%5b%5d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%5b%5d-i.ri new file mode 100644 index 00000000..809ca297 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/%5b%5d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/add_cell-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/add_cell-i.ri new file mode 100644 index 00000000..f56fb41f Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/add_cell-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cdesc-Row.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cdesc-Row.ri new file mode 100644 index 00000000..b6127f5e Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cdesc-Row.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cells-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cells-i.ri new file mode 100644 index 00000000..7dcbf42e --- /dev/null +++ b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/cells-i.ri @@ -0,0 +1,3 @@ +U:RDoc::Attr[iI" +cells:ETI"Terminal::Table::Row#cells;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"Row cells;T: +@fileI"lib/terminal-table/row.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Terminal::Table::Row;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/crossings-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/crossings-i.ri new file mode 100644 index 00000000..0ebeb336 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/crossings-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/height-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/height-i.ri new file mode 100644 index 00000000..97d47896 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/height-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/new-c.ri new file mode 100644 index 00000000..7825fe35 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/number_of_columns-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/number_of_columns-i.ri new file mode 100644 index 00000000..8577fa0e Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/number_of_columns-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/render-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/render-i.ri new file mode 100644 index 00000000..1eaa9cbb Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/render-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/table-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/table-i.ri new file mode 100644 index 00000000..79eff993 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Row/table-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/border_type-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/border_type-i.ri new file mode 100644 index 00000000..c7c57202 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/border_type-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/cdesc-Separator.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/cdesc-Separator.ri new file mode 100644 index 00000000..ee7da52b Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/cdesc-Separator.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/implicit-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/implicit-i.ri new file mode 100644 index 00000000..84e24b41 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/implicit-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/new-c.ri new file mode 100644 index 00000000..486cfa13 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/render-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/render-i.ri new file mode 100644 index 00000000..ec201406 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/render-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/save_adjacent_rows-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/save_adjacent_rows-i.ri new file mode 100644 index 00000000..ca8702f5 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Separator/save_adjacent_rows-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/alignment-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/alignment-i.ri new file mode 100644 index 00000000..4daabf64 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/alignment-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/all_separators-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/all_separators-i.ri new file mode 100644 index 00000000..81041408 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/all_separators-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/apply-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/apply-i.ri new file mode 100644 index 00000000..ac140db8 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/apply-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border%3d-i.ri new file mode 100644 index 00000000..36a076e9 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border-i.ri new file mode 100644 index 00000000..9327c920 --- /dev/null +++ b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border-i.ri @@ -0,0 +1,2 @@ +U:RDoc::Attr[iI" border:ETI""Terminal::Table::Style#border;TI"R;T: publico:RDoc::Markup::Document: @parts[o:RDoc::Markup::Paragraph; [I"$Accessor for instance of Border;T: +@fileI" lib/terminal-table/style.rb;T:0@omit_headings_from_table_of_contents_below0F@I"Terminal::Table::Style;TcRDoc::NormalClass0 \ No newline at end of file diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom%3d-i.ri new file mode 100644 index 00000000..92a1f17c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom-i.ri new file mode 100644 index 00000000..b7440a4d Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_bottom-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_i%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_i%3d-i.ri new file mode 100644 index 00000000..eec4d5d7 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_i%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left%3d-i.ri new file mode 100644 index 00000000..5343ec7a Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left-i.ri new file mode 100644 index 00000000..117e4bbf Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_left-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right%3d-i.ri new file mode 100644 index 00000000..8193221c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right-i.ri new file mode 100644 index 00000000..6b6c3981 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_right-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top%3d-i.ri new file mode 100644 index 00000000..f8684895 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top-i.ri new file mode 100644 index 00000000..d5422e51 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_top-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_x%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_x%3d-i.ri new file mode 100644 index 00000000..6159a039 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_x%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y%3d-i.ri new file mode 100644 index 00000000..25992d0b Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y-i.ri new file mode 100644 index 00000000..021337dc Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y_width-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y_width-i.ri new file mode 100644 index 00000000..9b4c1782 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/border_y_width-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/cdesc-Style.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/cdesc-Style.ri new file mode 100644 index 00000000..05d82882 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/cdesc-Style.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults%3d-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults%3d-c.ri new file mode 100644 index 00000000..39d05ac6 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults%3d-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults-c.ri new file mode 100644 index 00000000..54bc4841 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/defaults-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/margin_left-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/margin_left-i.ri new file mode 100644 index 00000000..07bb1d6f Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/margin_left-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/new-c.ri new file mode 100644 index 00000000..3c2a16dd Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/on_change-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/on_change-i.ri new file mode 100644 index 00000000..8fa3cefe Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/on_change-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_left-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_left-i.ri new file mode 100644 index 00000000..3f972ab9 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_left-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_right-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_right-i.ri new file mode 100644 index 00000000..0a1f121e Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/padding_right-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/width-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/width-i.ri new file mode 100644 index 00000000..8c06b1b9 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Style/width-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/cdesc-TableHelper.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/cdesc-TableHelper.ri new file mode 100644 index 00000000..997947d3 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/cdesc-TableHelper.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/table-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/table-i.ri new file mode 100644 index 00000000..2f2ae885 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/TableHelper/table-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/cdesc-UnicodeBorder.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/cdesc-UnicodeBorder.ri new file mode 100644 index 00000000..367d7770 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/cdesc-UnicodeBorder.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/horizontal-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/horizontal-i.ri new file mode 100644 index 00000000..2bb8af21 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/horizontal-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/new-c.ri new file mode 100644 index 00000000..b316b463 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/vertical-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/vertical-i.ri new file mode 100644 index 00000000..ed0cde73 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeBorder/vertical-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/cdesc-UnicodeRoundBorder.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/cdesc-UnicodeRoundBorder.ri new file mode 100644 index 00000000..3f94b013 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/cdesc-UnicodeRoundBorder.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/new-c.ri new file mode 100644 index 00000000..fdb130d3 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeRoundBorder/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/cdesc-UnicodeThickEdgeBorder.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/cdesc-UnicodeThickEdgeBorder.ri new file mode 100644 index 00000000..869d970e Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/cdesc-UnicodeThickEdgeBorder.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/new-c.ri new file mode 100644 index 00000000..e95077d0 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/UnicodeThickEdgeBorder/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-c.ri new file mode 100644 index 00000000..944af6ba Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-i.ri new file mode 100644 index 00000000..6e31cc50 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/ansi_escape-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/cdesc-Util.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/cdesc-Util.ri new file mode 100644 index 00000000..cff23f74 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/Util/cdesc-Util.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_row-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_row-i.ri new file mode 100644 index 00000000..3a33fd05 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_row-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_separator-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_separator-i.ri new file mode 100644 index 00000000..6ff2826c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/add_separator-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/align_column-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/align_column-i.ri new file mode 100644 index 00000000..36657af0 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/align_column-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cdesc-Table.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cdesc-Table.ri new file mode 100644 index 00000000..53acae3a Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cdesc-Table.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_padding-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_padding-i.ri new file mode 100644 index 00000000..bf007cd3 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_padding-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_spacing-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_spacing-i.ri new file mode 100644 index 00000000..f8f8b637 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/cell_spacing-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column-i.ri new file mode 100644 index 00000000..1c4ae2d9 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_width-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_width-i.ri new file mode 100644 index 00000000..d37f8a75 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_width-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_widths-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_widths-i.ri new file mode 100644 index 00000000..1622d17a Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_widths-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_with_headings-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_with_headings-i.ri new file mode 100644 index 00000000..a49b5aee Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/column_with_headings-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns-i.ri new file mode 100644 index 00000000..0b2d9f79 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns_width-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns_width-i.ri new file mode 100644 index 00000000..2cc02597 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/columns_width-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/elaborate_rows-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/elaborate_rows-i.ri new file mode 100644 index 00000000..29b9c657 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/elaborate_rows-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings%3d-i.ri new file mode 100644 index 00000000..279bb0c7 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings-i.ri new file mode 100644 index 00000000..df600dcc Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings_with_rows-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings_with_rows-i.ri new file mode 100644 index 00000000..86395ac3 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/headings_with_rows-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/length_of_column-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/length_of_column-i.ri new file mode 100644 index 00000000..79f1d98c Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/length_of_column-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/new-c.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/new-c.ri new file mode 100644 index 00000000..75feddcb Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/new-c.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/number_of_columns-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/number_of_columns-i.ri new file mode 100644 index 00000000..67e42924 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/number_of_columns-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/recalc_column_widths-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/recalc_column_widths-i.ri new file mode 100644 index 00000000..41e20373 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/recalc_column_widths-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/render-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/render-i.ri new file mode 100644 index 00000000..1a1516d2 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/render-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/require_column_widths_recalc-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/require_column_widths_recalc-i.ri new file mode 100644 index 00000000..ab2994c8 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/require_column_widths_recalc-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows%3d-i.ri new file mode 100644 index 00000000..10be9404 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows-i.ri new file mode 100644 index 00000000..dce29a23 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/rows-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style%3d-i.ri new file mode 100644 index 00000000..e08896da Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style-i.ri new file mode 100644 index 00000000..12d61df2 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/style-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title%3d-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title%3d-i.ri new file mode 100644 index 00000000..16ba8527 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title%3d-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title-i.ri new file mode 100644 index 00000000..fa34c475 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title_cell_options-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title_cell_options-i.ri new file mode 100644 index 00000000..95605b5d Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/title_cell_options-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/to_s-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/to_s-i.ri new file mode 100644 index 00000000..278a2731 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/to_s-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/yield_or_eval-i.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/yield_or_eval-i.ri new file mode 100644 index 00000000..a89930fe Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/Table/yield_or_eval-i.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/Terminal/cdesc-Terminal.ri b/bin/doc/terminal-table-3.0.2/ri/Terminal/cdesc-Terminal.ri new file mode 100644 index 00000000..b1c9e623 Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/Terminal/cdesc-Terminal.ri differ diff --git a/bin/doc/terminal-table-3.0.2/ri/cache.ri b/bin/doc/terminal-table-3.0.2/ri/cache.ri new file mode 100644 index 00000000..d5bc697f Binary files /dev/null and b/bin/doc/terminal-table-3.0.2/ri/cache.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/String/cdesc-String.ri b/bin/doc/unicode-display_width-2.6.0/ri/String/cdesc-String.ri new file mode 100644 index 00000000..5ff514f1 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/String/cdesc-String.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/String/display_width-i.ri b/bin/doc/unicode-display_width-2.6.0/ri/String/display_width-i.ri new file mode 100644 index 00000000..c9bd160f Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/String/display_width-i.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/cdesc-DisplayWidth.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/cdesc-DisplayWidth.ri new file mode 100644 index 00000000..bd99ef88 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/cdesc-DisplayWidth.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/decompress_index-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/decompress_index-c.ri new file mode 100644 index 00000000..5f180f84 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/decompress_index-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/emoji_extra_width_of-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/emoji_extra_width_of-c.ri new file mode 100644 index 00000000..ed717c8a Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/emoji_extra_width_of-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/get_config-i.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/get_config-i.ri new file mode 100644 index 00000000..8ee64658 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/get_config-i.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/new-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/new-c.ri new file mode 100644 index 00000000..b3d4b699 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/new-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-c.ri new file mode 100644 index 00000000..6a6fed33 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-i.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-i.ri new file mode 100644 index 00000000..39c4149e Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/of-i.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_all_features-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_all_features-c.ri new file mode 100644 index 00000000..44bd0395 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_all_features-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_no_overwrite-c.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_no_overwrite-c.ri new file mode 100644 index 00000000..976e33bd Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/DisplayWidth/width_no_overwrite-c.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/Unicode/cdesc-Unicode.ri b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/cdesc-Unicode.ri new file mode 100644 index 00000000..6ba7c4e4 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/Unicode/cdesc-Unicode.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/cache.ri b/bin/doc/unicode-display_width-2.6.0/ri/cache.ri new file mode 100644 index 00000000..6b97726d Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/cache.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/page-CHANGELOG_md.ri b/bin/doc/unicode-display_width-2.6.0/ri/page-CHANGELOG_md.ri new file mode 100644 index 00000000..ac90445a Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/page-CHANGELOG_md.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/page-MIT-LICENSE_txt.ri b/bin/doc/unicode-display_width-2.6.0/ri/page-MIT-LICENSE_txt.ri new file mode 100644 index 00000000..fccbbd2f Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/page-MIT-LICENSE_txt.ri differ diff --git a/bin/doc/unicode-display_width-2.6.0/ri/page-README_md.ri b/bin/doc/unicode-display_width-2.6.0/ri/page-README_md.ri new file mode 100644 index 00000000..4a886330 Binary files /dev/null and b/bin/doc/unicode-display_width-2.6.0/ri/page-README_md.ri differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/bigdecimal.so b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/bigdecimal.so new file mode 100755 index 00000000..79cc5e0f Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/bigdecimal.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/gem_make.out new file mode 100644 index 00000000..0d826eae --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/gem_make.out @@ -0,0 +1,44 @@ +current directory: /home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +checking for __builtin_clz()... yes +checking for __builtin_clzl()... yes +checking for __builtin_clzll()... yes +checking for float.h... yes +checking for math.h... yes +checking for stdbool.h... yes +checking for stdlib.h... yes +checking for x86intrin.h... yes +checking for _lzcnt_u32() in x86intrin.h... no +checking for _lzcnt_u64() in x86intrin.h... no +checking for intrin.h... no +checking for labs() in stdlib.h... yes +checking for llabs() in stdlib.h... yes +checking for finite() in math.h... yes +checking for isfinite() in math.h... no +checking for ruby/atomic.h... yes +checking for ruby/internal/has/builtin.h... yes +checking for ruby/internal/static_assert.h... yes +checking for rb_rational_num() in ruby.h... yes +checking for rb_rational_den() in ruby.h... yes +checking for rb_complex_real() in ruby.h... yes +checking for rb_complex_imag() in ruby.h... yes +checking for rb_opts_exception_p() in ruby.h... yes +checking for rb_category_warn() in ruby.h... yes +checking for RB_WARN_CATEGORY_DEPRECATED in ruby.h... yes +creating Makefile + +current directory: /home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-nitl0v sitelibdir\=./.gem.20260916-3763582-nitl0v clean + +current directory: /home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-nitl0v sitelibdir\=./.gem.20260916-3763582-nitl0v +compiling bigdecimal.c +compiling missing.c +linking shared-object bigdecimal.so + +current directory: /home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-nitl0v sitelibdir\=./.gem.20260916-3763582-nitl0v install +/usr/bin/install -c -m 0755 bigdecimal.so ./.gem.20260916-3763582-nitl0v + +current directory: /home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-nitl0v sitelibdir\=./.gem.20260916-3763582-nitl0v clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/mkmf.log b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/mkmf.log new file mode 100644 index 00000000..dd1af57f --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/bigdecimal-3.1.9/mkmf.log @@ -0,0 +1,605 @@ +have_builtin_func: checking for __builtin_clz()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int foo; +4: int main() { __builtin_clz(0); return 0; } +/* end */ + +-------------------- + +have_builtin_func: checking for __builtin_clzl()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int foo; +4: int main() { __builtin_clzl(0); return 0; } +/* end */ + +-------------------- + +have_builtin_func: checking for __builtin_clzll()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int foo; +4: int main() { __builtin_clzll(0); return 0; } +/* end */ + +-------------------- + +have_header: checking for float.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for math.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for stdbool.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for stdlib.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for x86intrin.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for _lzcnt_u32() in x86intrin.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccqQcDRW.o: in function `t': +/home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal/conftest.c:16:(.text+0xb): undefined reference to `_lzcnt_u32' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))_lzcnt_u32; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c:16:13: error: conflicting types for ‘_lzcnt_u32’; have ‘void()’ + 16 | extern void _lzcnt_u32(); + | ^~~~~~~~~~ +In file included from /usr/lib/gcc/x86_64-linux-gnu/13/include/x86gprintrin.h:61, + from /usr/lib/gcc/x86_64-linux-gnu/13/include/x86intrin.h:27, + from conftest.c:3: +/usr/lib/gcc/x86_64-linux-gnu/13/include/lzcntintrin.h:51:1: note: previous definition of ‘_lzcnt_u32’ with type ‘unsigned int(unsigned int)’ + 51 | _lzcnt_u32 (unsigned int __X) + | ^~~~~~~~~~ +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void _lzcnt_u32(); +17: int t(void) { _lzcnt_u32(); return 0; } +/* end */ + +-------------------- + +have_func: checking for _lzcnt_u64() in x86intrin.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccCTKY3u.o: in function `t': +/home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal/conftest.c:16:(.text+0xb): undefined reference to `_lzcnt_u64' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))_lzcnt_u64; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c:16:13: error: conflicting types for ‘_lzcnt_u64’; have ‘void()’ + 16 | extern void _lzcnt_u64(); + | ^~~~~~~~~~ +In file included from /usr/lib/gcc/x86_64-linux-gnu/13/include/x86gprintrin.h:61, + from /usr/lib/gcc/x86_64-linux-gnu/13/include/x86intrin.h:27, + from conftest.c:3: +/usr/lib/gcc/x86_64-linux-gnu/13/include/lzcntintrin.h:64:1: note: previous definition of ‘_lzcnt_u64’ with type ‘long long unsigned int(long long unsigned int)’ + 64 | _lzcnt_u64 (unsigned long long __X) + | ^~~~~~~~~~ +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void _lzcnt_u64(); +17: int t(void) { _lzcnt_u64(); return 0; } +/* end */ + +-------------------- + +have_header: checking for intrin.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +conftest.c:3:10: fatal error: intrin.h: No such file or directory + 3 | #include + | ^~~~~~~~~~ +compilation terminated. +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for labs() in stdlib.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))labs; return !p; } +/* end */ + +-------------------- + +have_func: checking for llabs() in stdlib.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))llabs; return !p; } +/* end */ + +-------------------- + +have_func: checking for finite() in math.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))finite; return !p; } +/* end */ + +-------------------- + +have_func: checking for isfinite() in math.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:16:57: error: ‘isfinite’ undeclared (first use in this function); did you mean ‘finite’? + 16 | int t(void) { void ((*volatile p)()); p = (void ((*)()))isfinite; return !p; } + | ^~~~~~~~ + | finite +conftest.c:16:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))isfinite; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccyjbqcO.o: in function `t': +/home/pizza2d1/gems/gems/bigdecimal-3.1.9/ext/bigdecimal/conftest.c:17:(.text+0xb): undefined reference to `__builtin_isfinite' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void isfinite(); +17: int t(void) { isfinite(); return 0; } +/* end */ + +-------------------- + +have_header: checking for ruby/atomic.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for ruby/internal/has/builtin.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for ruby/internal/static_assert.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for rb_rational_num() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_rational_num; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_rational_den() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_rational_den; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_complex_real() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_complex_real; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_complex_imag() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_complex_imag; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_opts_exception_p() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:16:57: error: ‘rb_opts_exception_p’ undeclared (first use in this function); did you mean ‘rb_make_exception’? + 16 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_opts_exception_p; return !p; } + | ^~~~~~~~~~~~~~~~~~~ + | rb_make_exception +conftest.c:16:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_opts_exception_p; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void rb_opts_exception_p(); +17: int t(void) { rb_opts_exception_p(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_category_warn() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_category_warn; return !p; } +/* end */ + +-------------------- + +have_const: checking for RB_WARN_CATEGORY_DEPRECATED in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: +5: /*top*/ +6: typedef int conftest_type; +7: conftest_type conftestval = (int)RB_WARN_CATEGORY_DEPRECATED; +/* end */ + +-------------------- + diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/fastfilereaderext.so b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/fastfilereaderext.so new file mode 100755 index 00000000..cd6e6f8e Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/fastfilereaderext.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/gem_make.out new file mode 100644 index 00000000..9ad64a9d --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/gem_make.out @@ -0,0 +1,19 @@ +current directory: /home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/fastfilereader +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +creating Makefile + +current directory: /home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/fastfilereader +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-lft3pb sitelibdir\=./.gem.20260916-3762757-lft3pb clean + +current directory: /home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/fastfilereader +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-lft3pb sitelibdir\=./.gem.20260916-3762757-lft3pb +compiling mapper.cpp +compiling rubymain.cpp +linking shared-object fastfilereaderext.so + +current directory: /home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/fastfilereader +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-lft3pb sitelibdir\=./.gem.20260916-3762757-lft3pb install +/usr/bin/install -c -m 0755 fastfilereaderext.so ./.gem.20260916-3762757-lft3pb + +current directory: /home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/fastfilereader +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-lft3pb sitelibdir\=./.gem.20260916-3762757-lft3pb clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/mkmf.log b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/mkmf.log new file mode 100644 index 00000000..94c6159e --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/mkmf.log @@ -0,0 +1,647 @@ +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu x86_64-linux-gnu-pkg-config --exists openssl +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu x86_64-linux-gnu-pkg-config --libs openssl | +=> "-lssl -lcrypto \n" +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lssl -lcrypto -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu x86_64-linux-gnu-pkg-config --cflags-only-I openssl | +=> "\n" +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu x86_64-linux-gnu-pkg-config --cflags-only-other openssl | +=> "\n" +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu x86_64-linux-gnu-pkg-config --libs-only-l openssl | +=> "-lssl -lcrypto \n" +package configuration for openssl +incflags: +cflags: +ldflags: +libs: -lssl -lcrypto + +have_library: checking for -lcrypto... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lruby-3.2 -lssl -lcrypto -lcrypto -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: +15: int t(void) { ; return 0; } +/* end */ + +-------------------- + +have_library: checking for -lssl... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: +15: int t(void) { ; return 0; } +/* end */ + +-------------------- + +have_header: checking for openssl/ssl.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for openssl/err.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_var: checking for rb_trap_immediate in ruby.h,rubysig.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +conftest.c:4:10: fatal error: rubysig.h: No such file or directory + 4 | #include + | ^~~~~~~~~~~ +compilation terminated. +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: #include + 5: + 6: /*top*/ + 7: extern int t(void); + 8: int main(int argc, char **argv) + 9: { +10: if (argc > 1000000) { +11: int (* volatile tp)(void)=(int (*)(void))&t; +12: printf("%d", (*tp)()); +13: } +14: +15: return !!argv[argc]; +16: } +17: int t(void) { const volatile void *volatile p; p = &(&rb_trap_immediate)[0]; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_thread_blocking_region()... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:57: error: ‘rb_thread_blocking_region’ undeclared (first use in this function) + 14 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_thread_blocking_region; return !p; } + | ^~~~~~~~~~~~~~~~~~~~~~~~~ +conftest.c:14:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_thread_blocking_region; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccJzlOiU.o: in function `t': +/home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/conftest.c:15:(.text+0xb): undefined reference to `rb_thread_blocking_region' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: extern void rb_thread_blocking_region(); +15: int t(void) { rb_thread_blocking_region(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_thread_call_without_gvl() in ruby/thread.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_thread_call_without_gvl; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_thread_fd_select()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_thread_fd_select; return !p; } +/* end */ + +-------------------- + +have_type: checking for rb_fdset_t in ruby/intern.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: +5: /*top*/ +6: typedef rb_fdset_t conftest_type; +7: int conftestval[sizeof(conftest_type)?1:-1]; +/* end */ + +-------------------- + +have_func: checking for rb_wait_for_single_fd()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:57: error: ‘rb_wait_for_single_fd’ undeclared (first use in this function) + 14 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_wait_for_single_fd; return !p; } + | ^~~~~~~~~~~~~~~~~~~~~ +conftest.c:14:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_wait_for_single_fd; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: extern void rb_wait_for_single_fd(); +15: int t(void) { rb_wait_for_single_fd(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_enable_interrupt()... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:57: error: ‘rb_enable_interrupt’ undeclared (first use in this function); did you mean ‘rb_eInterrupt’? + 14 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_enable_interrupt; return !p; } + | ^~~~~~~~~~~~~~~~~~~ + | rb_eInterrupt +conftest.c:14:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_enable_interrupt; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccQNGadi.o: in function `t': +/home/pizza2d1/gems/gems/eventmachine-1.2.7/ext/conftest.c:15:(.text+0xb): undefined reference to `rb_enable_interrupt' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: extern void rb_enable_interrupt(); +15: int t(void) { rb_enable_interrupt(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_time_new()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_time_new; return !p; } +/* end */ + +-------------------- + +have_func: checking for inotify_init() in sys/inotify.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))inotify_init; return !p; } +/* end */ + +-------------------- + +have_func: checking for writev() in sys/uio.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))writev; return !p; } +/* end */ + +-------------------- + +have_func: checking for pipe2() in unistd.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))pipe2; return !p; } +/* end */ + +-------------------- + +have_func: checking for accept4() in sys/socket.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))accept4; return !p; } +/* end */ + +-------------------- + +have_const: checking for SOCK_CLOEXEC in sys/socket.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: +5: /*top*/ +6: typedef int conftest_type; +7: conftest_type conftestval = (int)SOCK_CLOEXEC; +/* end */ + +-------------------- + +have_header: checking for sys/event.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +conftest.c:3:10: fatal error: sys/event.h: No such file or directory + 3 | #include + | ^~~~~~~~~~~~~ +compilation terminated. +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for epoll_create() in sys/epoll.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))epoll_create; return !p; } +/* end */ + +-------------------- + +have_func: checking for clock_gettime()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))clock_gettime; return !p; } +/* end */ + +-------------------- + +have_const: checking for CLOCK_MONOTONIC_RAW in time.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: +5: /*top*/ +6: typedef int conftest_type; +7: conftest_type conftestval = (int)CLOCK_MONOTONIC_RAW; +/* end */ + +-------------------- + +have_const: checking for CLOCK_MONOTONIC in time.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: +5: /*top*/ +6: typedef int conftest_type; +7: conftest_type conftestval = (int)CLOCK_MONOTONIC; +/* end */ + +-------------------- + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wall -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wextra -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wno-deprecated-declarations -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wno-ignored-qualifiers -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wno-unused-result -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -Wno-address -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main() {return 0;} +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-g++ -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lssl -lcrypto -lcrypto -lssl -lruby-3.2 -lstdc++ -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +4: using namespace std; +5: int main(){ pair tuple = make_pair(1,2); } +/* end */ + diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/rubyeventmachine.so b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/rubyeventmachine.so new file mode 100755 index 00000000..62a89c50 Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/eventmachine-1.2.7/rubyeventmachine.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/gem_make.out new file mode 100644 index 00000000..806f5d19 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/gem_make.out @@ -0,0 +1,19 @@ +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.0/ext/ruby_http_parser +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +creating Makefile + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.0/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-v02v67 sitelibdir\=./.gem.20260916-3763582-v02v67 clean + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.0/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-v02v67 sitelibdir\=./.gem.20260916-3763582-v02v67 +compiling ruby_http_parser.c +compiling ryah_http_parser.c +linking shared-object ruby_http_parser.so + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.0/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-v02v67 sitelibdir\=./.gem.20260916-3763582-v02v67 install +/usr/bin/install -c -m 0755 ruby_http_parser.so ./.gem.20260916-3763582-v02v67 + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.0/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-v02v67 sitelibdir\=./.gem.20260916-3763582-v02v67 clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/ruby_http_parser.so b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/ruby_http_parser.so new file mode 100755 index 00000000..8e1b0327 Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.0/ruby_http_parser.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/gem_make.out new file mode 100644 index 00000000..6d78cf35 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/gem_make.out @@ -0,0 +1,19 @@ +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.1/ext/ruby_http_parser +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +creating Makefile + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.1/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-5aydch sitelibdir\=./.gem.20260916-3762757-5aydch clean + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.1/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-5aydch sitelibdir\=./.gem.20260916-3762757-5aydch +compiling ruby_http_parser.c +compiling ryah_http_parser.c +linking shared-object ruby_http_parser.so + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.1/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-5aydch sitelibdir\=./.gem.20260916-3762757-5aydch install +/usr/bin/install -c -m 0755 ruby_http_parser.so ./.gem.20260916-3762757-5aydch + +current directory: /home/pizza2d1/gems/gems/http_parser.rb-0.8.1/ext/ruby_http_parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3762757-5aydch sitelibdir\=./.gem.20260916-3762757-5aydch clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/ruby_http_parser.so b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/ruby_http_parser.so new file mode 100755 index 00000000..1b9df9b1 Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/http_parser.rb-0.8.1/ruby_http_parser.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/IO_Event.so b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/IO_Event.so new file mode 100755 index 00000000..f8cb626e Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/IO_Event.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/gem_make.out new file mode 100644 index 00000000..02906716 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/gem_make.out @@ -0,0 +1,38 @@ +current directory: /home/pizza2d1/gems/gems/io-event-1.9.0/ext +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +checking for rb_ext_ractor_safe()... yes +checking for &rb_fiber_transfer()... yes +checking for -luring... no +checking for sys/epoll.h... yes +checking for sys/event.h... no +checking for sys/wait.h... yes +checking for sys/eventfd.h... yes +checking for rb_io_descriptor()... yes +checking for &rb_process_status_wait()... no +checking for rb_fiber_current()... yes +checking for &rb_fiber_raise()... yes +checking for epoll_pwait2()... yes +checking for ruby/io/buffer.h... yes +creating extconf.h +creating Makefile + +current directory: /home/pizza2d1/gems/gems/io-event-1.9.0/ext +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-uef7b1 sitelibdir\=./.gem.20260916-3763582-uef7b1 clean + +current directory: /home/pizza2d1/gems/gems/io-event-1.9.0/ext +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-uef7b1 sitelibdir\=./.gem.20260916-3763582-uef7b1 +compiling ./io/event/selector/epoll.c +compiling ./io/event/event.c +compiling ./io/event/fiber.c +compiling ./io/event/interrupt.c +compiling ./io/event/profiler.c +compiling ./io/event/selector/selector.c +compiling ./io/event/time.c +linking shared-object IO_Event.so + +current directory: /home/pizza2d1/gems/gems/io-event-1.9.0/ext +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-uef7b1 sitelibdir\=./.gem.20260916-3763582-uef7b1 install +/usr/bin/install -c -m 0755 IO_Event.so ./.gem.20260916-3763582-uef7b1 + +current directory: /home/pizza2d1/gems/gems/io-event-1.9.0/ext +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-uef7b1 sitelibdir\=./.gem.20260916-3763582-uef7b1 clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/mkmf.log b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/mkmf.log new file mode 100644 index 00000000..084a3529 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/io-event-1.9.0/mkmf.log @@ -0,0 +1,334 @@ +have_func: checking for rb_ext_ractor_safe()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_ext_ractor_safe; return !p; } +/* end */ + +-------------------- + +have_func: checking for &rb_fiber_transfer()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { const volatile void *volatile p; p = (const volatile void *)&rb_fiber_transfer; return !p; } +/* end */ + +-------------------- + +have_library: checking for -luring... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -luring -lm -lpthread -lc" +/usr/bin/ld: cannot find -luring: No such file or directory +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: +15: int t(void) { ; return 0; } +/* end */ + +-------------------- + +have_header: checking for sys/epoll.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for sys/event.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 -c conftest.c" +conftest.c:3:10: fatal error: sys/event.h: No such file or directory + 3 | #include + | ^~~~~~~~~~~~~ +compilation terminated. +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for sys/wait.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_header: checking for sys/eventfd.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for rb_io_descriptor()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:57: error: ‘rb_io_descriptor’ undeclared (first use in this function) + 14 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_io_descriptor; return !p; } + | ^~~~~~~~~~~~~~~~ +conftest.c:14:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_io_descriptor; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: extern void rb_io_descriptor(); +15: int t(void) { rb_io_descriptor(); return 0; } +/* end */ + +-------------------- + +have_func: checking for &rb_process_status_wait()... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:76: error: ‘rb_process_status_wait’ undeclared (first use in this function) + 14 | int t(void) { const volatile void *volatile p; p = (const volatile void *)&rb_process_status_wait; return !p; } + | ^~~~~~~~~~~~~~~~~~~~~~ +conftest.c:14:76: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { const volatile void *volatile p; p = (const volatile void *)&rb_process_status_wait; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_fiber_current()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_fiber_current; return !p; } +/* end */ + +-------------------- + +have_func: checking for &rb_fiber_raise()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { const volatile void *volatile p; p = (const volatile void *)&rb_fiber_raise; return !p; } +/* end */ + +-------------------- + +have_func: checking for epoll_pwait2()... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:14:57: error: ‘epoll_pwait2’ undeclared (first use in this function) + 14 | int t(void) { void ((*volatile p)()); p = (void ((*)()))epoll_pwait2; return !p; } + | ^~~~~~~~~~~~ +conftest.c:14:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: int t(void) { void ((*volatile p)()); p = (void ((*)()))epoll_pwait2; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: /*top*/ + 4: extern int t(void); + 5: int main(int argc, char **argv) + 6: { + 7: if (argc > 1000000) { + 8: int (* volatile tp)(void)=(int (*)(void))&t; + 9: printf("%d", (*tp)()); +10: } +11: +12: return !!argv[argc]; +13: } +14: extern void epoll_pwait2(); +15: int t(void) { epoll_pwait2(); return 0; } +/* end */ + +-------------------- + +have_header: checking for ruby/io/buffer.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -Wall -Wno-unknown-pragmas -std=c99 -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +extconf.h is: +/* begin */ + 1: #ifndef EXTCONF_H + 2: #define EXTCONF_H + 3: #define HAVE_RB_EXT_RACTOR_SAFE 1 + 4: #define HAVE__RB_FIBER_TRANSFER 1 + 5: #define HAVE_SYS_EPOLL_H 1 + 6: #define HAVE_SYS_WAIT_H 1 + 7: #define HAVE_SYS_EVENTFD_H 1 + 8: #define HAVE_RB_IO_DESCRIPTOR 1 + 9: #define HAVE_RB_FIBER_CURRENT 1 +10: #define HAVE__RB_FIBER_RAISE 1 +11: #define HAVE_EPOLL_PWAIT2 1 +12: #define HAVE_RUBY_IO_BUFFER_H 1 +13: #endif +/* end */ + diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/gem_make.out new file mode 100644 index 00000000..18de51d4 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/gem_make.out @@ -0,0 +1,24 @@ +current directory: /home/pizza2d1/gems/gems/json-2.10.2/ext/json/ext/parser +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +checking for rb_enc_interned_str() in ruby.h... yes +checking for rb_hash_new_capa() in ruby.h... yes +checking for rb_hash_bulk_insert() in ruby.h... yes +checking for rb_category_warn() in ruby.h... yes +checking for strnlen() in string.h... yes +checking for whether -std=c99 is accepted as CFLAGS... yes +creating Makefile + +current directory: /home/pizza2d1/gems/gems/json-2.10.2/ext/json/ext/parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-up5u9y sitelibdir\=./.gem.20260916-3763582-up5u9y clean + +current directory: /home/pizza2d1/gems/gems/json-2.10.2/ext/json/ext/parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-up5u9y sitelibdir\=./.gem.20260916-3763582-up5u9y +compiling parser.c +linking shared-object json/ext/parser.so + +current directory: /home/pizza2d1/gems/gems/json-2.10.2/ext/json/ext/parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-up5u9y sitelibdir\=./.gem.20260916-3763582-up5u9y install +/usr/bin/install -c -m 0755 parser.so ./.gem.20260916-3763582-up5u9y/json/ext + +current directory: /home/pizza2d1/gems/gems/json-2.10.2/ext/json/ext/parser +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-up5u9y sitelibdir\=./.gem.20260916-3763582-up5u9y clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/generator.so b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/generator.so new file mode 100755 index 00000000..ca348658 Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/generator.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/parser.so b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/parser.so new file mode 100755 index 00000000..79f1247f Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/json/ext/parser.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/mkmf.log b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/mkmf.log new file mode 100644 index 00000000..1bb400d9 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/json-2.10.2/mkmf.log @@ -0,0 +1,179 @@ +have_func: checking for rb_enc_interned_str() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:16:57: error: ‘rb_enc_interned_str’ undeclared (first use in this function); did you mean ‘rb_interned_str’? + 16 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_enc_interned_str; return !p; } + | ^~~~~~~~~~~~~~~~~~~ + | rb_interned_str +conftest.c:16:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_enc_interned_str; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void rb_enc_interned_str(); +17: int t(void) { rb_enc_interned_str(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_hash_new_capa() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_hash_new_capa; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_hash_bulk_insert() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_hash_bulk_insert; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_category_warn() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_category_warn; return !p; } +/* end */ + +-------------------- + +have_func: checking for strnlen() in string.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))strnlen; return !p; } +/* end */ + +-------------------- + +block in append_cflags: checking for whether -std=c99 is accepted as CFLAGS... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -std=c99 -Werror -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +-------------------- + diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/gem_make.out new file mode 100644 index 00000000..552c60fa --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/gem_make.out @@ -0,0 +1,18 @@ +current directory: /home/pizza2d1/gems/gems/racc-1.8.1/ext/racc/cparse +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +creating Makefile + +current directory: /home/pizza2d1/gems/gems/racc-1.8.1/ext/racc/cparse +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-rzd82i sitelibdir\=./.gem.20260916-3763582-rzd82i clean + +current directory: /home/pizza2d1/gems/gems/racc-1.8.1/ext/racc/cparse +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-rzd82i sitelibdir\=./.gem.20260916-3763582-rzd82i +compiling cparse.c +linking shared-object racc/cparse.so + +current directory: /home/pizza2d1/gems/gems/racc-1.8.1/ext/racc/cparse +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-rzd82i sitelibdir\=./.gem.20260916-3763582-rzd82i install +/usr/bin/install -c -m 0755 cparse.so ./.gem.20260916-3763582-rzd82i/racc + +current directory: /home/pizza2d1/gems/gems/racc-1.8.1/ext/racc/cparse +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-rzd82i sitelibdir\=./.gem.20260916-3763582-rzd82i clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/racc/cparse.so b/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/racc/cparse.so new file mode 100755 index 00000000..b988830f Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/racc-1.8.1/racc/cparse.so differ diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/gem.build_complete b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/gem.build_complete new file mode 100644 index 00000000..e69de29b diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/gem_make.out b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/gem_make.out new file mode 100644 index 00000000..c54caf95 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/gem_make.out @@ -0,0 +1,27 @@ +current directory: /home/pizza2d1/gems/gems/rbtree-0.4.6 +/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb +checking for ruby/version.h... yes +checking for rb_exec_recursive() in ruby.h... yes +checking for rb_exec_recursive_paired() in ruby.h... yes +checking for rb_proc_lambda_p() in ruby.h... yes +checking for rb_ary_resize() in ruby.h... yes +checking for rb_obj_hide() in ruby.h... yes +checking for rb_safe_level() in ruby.h... no +checking for rb_cData() in ruby.h... no +creating Makefile + +current directory: /home/pizza2d1/gems/gems/rbtree-0.4.6 +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-hpa6si sitelibdir\=./.gem.20260916-3763582-hpa6si clean + +current directory: /home/pizza2d1/gems/gems/rbtree-0.4.6 +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-hpa6si sitelibdir\=./.gem.20260916-3763582-hpa6si +compiling dict.c +compiling rbtree.c +linking shared-object rbtree.so + +current directory: /home/pizza2d1/gems/gems/rbtree-0.4.6 +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-hpa6si sitelibdir\=./.gem.20260916-3763582-hpa6si install +/usr/bin/install -c -m 0755 rbtree.so ./.gem.20260916-3763582-hpa6si + +current directory: /home/pizza2d1/gems/gems/rbtree-0.4.6 +make DESTDIR\= sitearchdir\=./.gem.20260916-3763582-hpa6si sitelibdir\=./.gem.20260916-3763582-hpa6si clean diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/mkmf.log b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/mkmf.log new file mode 100644 index 00000000..f9ecf681 --- /dev/null +++ b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/mkmf.log @@ -0,0 +1,258 @@ +have_header: checking for ruby/version.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: int main(int argc, char **argv) +4: { +5: return !!argv[argc]; +6: } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -c conftest.c" +checked program was: +/* begin */ +1: #include "ruby.h" +2: +3: #include +/* end */ + +-------------------- + +have_func: checking for rb_exec_recursive() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_exec_recursive; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_exec_recursive_paired() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_exec_recursive_paired; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_proc_lambda_p() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_proc_lambda_p; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_ary_resize() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_ary_resize; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_obj_hide() in ruby.h... -------------------- yes + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_obj_hide; return !p; } +/* end */ + +-------------------- + +have_func: checking for rb_safe_level() in ruby.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:16:57: error: ‘rb_safe_level’ undeclared (first use in this function) + 16 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_safe_level; return !p; } + | ^~~~~~~~~~~~~ +conftest.c:16:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_safe_level; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +/usr/bin/ld: /tmp/ccQkdDaT.o: in function `t': +/home/pizza2d1/gems/gems/rbtree-0.4.6/conftest.c:17:(.text+0xb): undefined reference to `rb_safe_level' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void rb_safe_level(); +17: int t(void) { rb_safe_level(); return 0; } +/* end */ + +-------------------- + +have_func: checking for rb_cData() in ruby.h... -------------------- no + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +conftest.c: In function ‘t’: +conftest.c:16:57: error: ‘rb_cData’ undeclared (first use in this function) + 16 | int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_cData; return !p; } + | ^~~~~~~~ +conftest.c:16:57: note: each undeclared identifier is reported only once for each function it appears in +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: int t(void) { void ((*volatile p)()); p = (void ((*)()))rb_cData; return !p; } +/* end */ + +LD_LIBRARY_PATH=.:/usr/lib/x86_64-linux-gnu "x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-3.2.0 -I/usr/include/ruby-3.2.0/ruby/backward -I/usr/include/ruby-3.2.0 -I. -Wdate-time -D_FORTIFY_SOURCE=3 -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -lruby-3.2 -lm -lpthread -lc" +/usr/bin/ld: /tmp/cctRFeD8.o: in function `t': +/home/pizza2d1/gems/gems/rbtree-0.4.6/conftest.c:17:(.text+0xb): undefined reference to `rb_cData' +collect2: error: ld returned 1 exit status +checked program was: +/* begin */ + 1: #include "ruby.h" + 2: + 3: #include + 4: + 5: /*top*/ + 6: extern int t(void); + 7: int main(int argc, char **argv) + 8: { + 9: if (argc > 1000000) { +10: int (* volatile tp)(void)=(int (*)(void))&t; +11: printf("%d", (*tp)()); +12: } +13: +14: return !!argv[argc]; +15: } +16: extern void rb_cData(); +17: int t(void) { rb_cData(); return 0; } +/* end */ + +-------------------- + diff --git a/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/rbtree.so b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/rbtree.so new file mode 100755 index 00000000..ff93cab4 Binary files /dev/null and b/bin/extensions/x86_64-linux-gnu/3.2.0/rbtree-0.4.6/rbtree.so differ diff --git a/bin/gems/Ascii85-2.0.1/Ascii85.gemspec b/bin/gems/Ascii85-2.0.1/Ascii85.gemspec new file mode 100644 index 00000000..71b93bb4 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/Ascii85.gemspec @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require_relative 'lib/Ascii85/version' + +Gem::Specification.new do |s| + s.name = 'Ascii85' + s.version = Ascii85::VERSION + s.platform = Gem::Platform::RUBY + s.author = 'Johannes Holzfuß' + s.email = 'johannes@holzfuss.name' + s.license = 'MIT' + s.homepage = 'https://github.com/DataWraith/ascii85gem/' + s.summary = 'Ascii85 encoder/decoder' + s.description = "Ascii85 provides methods to encode/decode Adobe's binary-to-text encoding of the same name." + + s.required_ruby_version = '>= 2.7.0' + + s.add_development_dependency 'minitest', '~> 5', '>= 5.12.0' + s.add_development_dependency 'rake', '~> 13' + + s.files = `git ls-files`.split("\n") - ['.gitignore', '.github/workflows/ruby.yml'] + s.test_files = `git ls-files -- spec/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } + s.require_paths = ['lib'] + s.extra_rdoc_files = ['README.md', 'LICENSE'] +end diff --git a/bin/gems/Ascii85-2.0.1/CHANGELOG.md b/bin/gems/Ascii85-2.0.1/CHANGELOG.md new file mode 100644 index 00000000..6942feaf --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/CHANGELOG.md @@ -0,0 +1,70 @@ +# Ascii85 Changelog + +## [2.0.1] - 2024-09-15 + +### Fixed + +- Decoding binary data could lead to Encoding errors (Issue #8) + +## [2.0.0] - 2024-08-20 + +### BREAKING CHANGES + +- The minimum required Ruby version has been raised to 2.7.0. + +### Added + +- `Ascii85.decode_raw` method that doesn't expect the input to be wrapped in `<~` and `~>` delimiters. +- `Ascii85.extract` method to extract encoded text from between `<~` and `~>` for feeding to `#decode_raw`. +- Option to pass an IO-object as input to `#encode` and `#decode_raw` instead of a String. +- Option to pass an IO-object to `#encode` and `#decode_raw` for output. Output is written to the object instead of being returned as a String. +- Streaming capability for `#encode` and `#decode_raw` when both input and output are IO objects, using constant memory. + +## [1.1.1] - 2024-05-09 + +### Fixed + +- Make `bin/ascii85` Ruby 3.2-compatible (thanks @tylerwillingham) +- Slightly improved error handling of `bin/ascii85` + +## [1.1.0] - 2020-11-11 + +### Added + +- Make use of frozen_string_literal (thanks @aliismayilov) + +### Changed + +- Updated tests to use newer minitest syntax + +## [1.0.3] - 2018-01-25 + +### Changed + +- Updated the gem's metadata + +## [1.0.2] - 2012-09-16 + +### Changed + +- Changed test runner from RSpec to MiniSpec +- Added support for rubygems-test +- Minor changes to make packaging easier + +## [1.0.1] - 2011-05-05 + +### Changed + +- Removed `hoe` dependency in favor of `bundler` +- Minor corrections in the documentation + +## [1.0.0] - 2009-12-25 + +### Added + +- Ruby 1.9 compatibility +- Command-line en- and decoder + +## [0.9.0] - 2009-02-17 + +- Initial release diff --git a/bin/gems/Ascii85-2.0.1/Gemfile b/bin/gems/Ascii85-2.0.1/Gemfile new file mode 100644 index 00000000..9e6a10ed --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source 'http://rubygems.org' + +# Specify your gem's dependencies in Ascii85.gemspec +gemspec diff --git a/bin/gems/Ascii85-2.0.1/LICENSE b/bin/gems/Ascii85-2.0.1/LICENSE new file mode 100644 index 00000000..5d68e1d8 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009 Johannes Holzfuß + +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/bin/gems/Ascii85-2.0.1/README.md b/bin/gems/Ascii85-2.0.1/README.md new file mode 100644 index 00000000..2292a4a0 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/README.md @@ -0,0 +1,78 @@ +**Status**: This project is feature-complete. With the exception of fixes to reported bugs, no further development will take place. + +# Ascii85 + +## Description + +Ascii85 is a Ruby gem that provides methods for encoding/decoding Adobe's +binary-to-text encoding of the same name. + +See the Adobe PostScript Language Reference ([archived version][PLRM]) page 131 +and [Wikipedia](https://en.wikipedia.org/wiki/Ascii85) for more information +about the format. + +[PLRM]: https://web.archive.org/web/20161222092741/https://www.adobe.com/products/postscript/pdfs/PLRM.pdf + + +## Installation + +`$ gem install Ascii85` + +> [!IMPORTANT] +> Note that the gem name is capitalized. + + +## Usage + +```ruby +require 'ascii85' + +Ascii85.encode("Ruby") +=> "<~;KZGo~>" + +Ascii85.decode("<~;KZGo~>") +=> "Ruby" + +Ascii85.extract("Foo<~;KZGo~>Bar") +=> ";KZGo" + +Ascii85.decode_raw(";KZGo") +=> "Ruby" +``` + +In addition, `Ascii85.encode` can take a second parameter that specifies the +length of the returned lines. The default is 80; use `false` for unlimited. + +`Ascii85.decode` expects the input to be enclosed in `<~` and `~>` — it +ignores everything outside of these, while `Ascii85.decode_raw` assumes that +the entire String passed in is encoded in Ascii85. If you need to, you can use +`Ascii85.extract` to find and extract the first substring of the input that is +enclosed by the `<~` and `~>` delimiters. + +The output of `Ascii85.decode` and `Ascii85.decode_raw` will be a String that +has the `ASCII-8BIT` encoding, so you may have to use `String#force_encoding` to +convert it to the desired encoding. + +For further options, see the [Documentation](https://www.rubydoc.info/gems/Ascii85/). + + +## Command-line utility + +This gem includes `ascii85`, a command-line utility modeled after `base64` from +the GNU coreutils. It can be used to encode/decode Ascii85 directly from the +command-line: + +``` +Usage: ascii85 [OPTIONS] [FILE] +Encodes or decodes FILE or STDIN using Ascii85 and writes to STDOUT. + -w, --wrap COLUMN Wrap lines at COLUMN. Default is 80, use 0 for no wrapping + -d, --decode Decode the input + -h, --help Display this help and exit + -V, --version Output version information +``` + + +## License + +Ascii85 is distributed under the MIT License. See the accompanying LICENSE file +for details. diff --git a/bin/gems/Ascii85-2.0.1/Rakefile b/bin/gems/Ascii85-2.0.1/Rakefile new file mode 100644 index 00000000..8183fc22 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/Rakefile @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'bundler' +Bundler::GemHelper.install_tasks + +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.test_files = FileList['spec/**/*_spec.rb'] +end + +task specs: :test +task tests: :test +task default: :test diff --git a/bin/gems/Ascii85-2.0.1/bin/ascii85 b/bin/gems/Ascii85-2.0.1/bin/ascii85 new file mode 100755 index 00000000..0bd24bd6 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/bin/ascii85 @@ -0,0 +1,112 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# A simple command-line tool to de- and encode Ascii85, modeled after `base64` +# from the GNU Coreutils. +# + +require 'optparse' +require File.join(File.dirname(__FILE__), '..', 'lib', 'ascii85') +require File.join(File.dirname(__FILE__), '..', 'lib', 'Ascii85', 'version') + +class CLI + attr_reader :options + + def initialize(argv, stdin: $stdin, stdout: $stdout) + @in = stdin + @out = stdout + + @options = { + wrap: 80, + action: :encode + } + + parse_options(argv) + end + + def parse_options(argv) + @parser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] [FILE]\n" \ + 'Encodes or decodes FILE or STDIN using Ascii85 and writes to STDOUT.' + + opts.on('-w', '--wrap COLUMN', Integer, + 'Wrap lines at COLUMN. Default is 80, use 0 for no wrapping') do |opt| + @options[:wrap] = opt.abs + @options[:wrap] = false if opt.zero? + end + + opts.on('-d', '--decode', 'Decode the input') do + @options[:action] = :decode + end + + opts.on('-h', '--help', 'Display this help and exit') do + @options[:action] = :help + end + + opts.on('-V', '--version', 'Output version information') do |_opt| + @options[:action] = :version + end + + end + + remaining_args = @parser.parse!(argv) + + case remaining_args.size + when 0 + @options[:file] = '-' + when 1 + @options[:file] = remaining_args.first + else + raise(OptionParser::ParseError, "Superfluous operand(s): \"#{remaining_args[1..].join('", "')}\"") + end + end + + def input + fn = @options[:file] + + return @in.binmode if fn == '-' + + raise(StandardError, "File not found: \"#{fn}\"") unless File.exist?(fn) + raise(StandardError, "File is not readable: \"#{fn}\"") unless File.readable_real?(fn) + + File.new(fn, 'rb') + end + + def decode + Ascii85.decode(input.read, out: @out) + end + + def encode + Ascii85.encode(input, @options[:wrap], out: @out) + end + + def version + "Ascii85 v#{Ascii85::VERSION},\nwritten by Johannes Holzfuß" + end + + def help + @parser + end + + def call + case @options[:action] + when :help then @out.puts help + when :version then @out.puts version + when :encode then encode + when :decode then decode + end + end +end + +if File.basename($PROGRAM_NAME) == "ascii85" + begin + CLI.new(ARGV).call + rescue OptionParser::ParseError => e + abort e.message + rescue Ascii85::DecodingError => e + abort "Decoding Error: #{e.message}" + rescue StandardError => e + abort "Error: #{e.message}" + end +end diff --git a/bin/gems/Ascii85-2.0.1/lib/Ascii85/version.rb b/bin/gems/Ascii85-2.0.1/lib/Ascii85/version.rb new file mode 100644 index 00000000..4bf5cd53 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/lib/Ascii85/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Ascii85 + VERSION = '2.0.1' +end diff --git a/bin/gems/Ascii85-2.0.1/lib/ascii85.rb b/bin/gems/Ascii85-2.0.1/lib/ascii85.rb new file mode 100644 index 00000000..433a68ff --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/lib/ascii85.rb @@ -0,0 +1,469 @@ +# frozen_string_literal: true + +require 'stringio' + +# +# Ascii85 is an implementation of Adobe's binary-to-text encoding of the +# same name in pure Ruby. +# +# See http://en.wikipedia.org/wiki/Ascii85 for more information about the +# format. +# +# Author:: Johannes Holzfuß (johannes@holzfuss.name) +# License:: Distributed under the MIT License (see LICENSE file) +# +module Ascii85 + class << self + EMPTY_STRING = ''.dup.force_encoding(Encoding::ASCII_8BIT) + START_MARKER = '<~'.dup.force_encoding(Encoding::ASCII_8BIT) + ENDING_MARKER = '~>'.dup.force_encoding(Encoding::ASCII_8BIT) + LINE_BREAK = "\n".dup.force_encoding(Encoding::ASCII_8BIT) + + # + # Encodes the bytes of the given String or IO-like object as Ascii85. + # + # @param str_or_io [String, IO] The input to encode + # @param wrap_lines [Integer, false] The line length for wrapping, or +false+ for no wrapping + # @param out [IO, nil] An optional IO-like object to write the output to + # + # @return [String, IO] The encoded String or the output IO object that was passed in + # + # @example Encoding a simple String + # Ascii85.encode("Ruby") + # # => <~;KZGo~> + # + # @example Encoding with line wrapping + # Ascii85.encode("Supercalifragilisticexpialidocious", 15) + # # => <~;g!%jEarNoBkD + # # BoB5)0rF*),+AU& + # # 0.@;KXgDe!L"F`R + # # ~> + # + # @example Encoding without line wrapping + # Ascii85.encode("Supercalifragilisticexpialidocious", false) + # # => <~;g!%jEarNoBkDBoB5)0rF*),+AU&0.@;KXgDe!L"F`R~> + # + # @example Encoding from an IO-like object + # input = StringIO.new("Ruby") + # Ascii85.encode(input) + # # => "<~;KZGo~>" + # + # @example Encoding to an IO object + # output = StringIO.new + # Ascii85.encode("Ruby", out: output) + # # => output (with "<~;KZGo~>" written to it) + # + def encode(str_or_io, wrap_lines = 80, out: nil) + reader = if io_like?(str_or_io) + str_or_io + else + StringIO.new(str_or_io.to_s, 'rb') + end + + return EMPTY_STRING.dup if reader.eof? + + # Setup buffered Reader and Writers + bufreader = BufferedReader.new(reader, unencoded_chunk_size) + bufwriter = BufferedWriter.new(out || StringIO.new(String.new, 'wb'), encoded_chunk_size) + writer = wrap_lines ? Wrapper.new(bufwriter, wrap_lines) : DummyWrapper.new(bufwriter) + + padding = unfrozen_binary_copy("\0\0\0\0") + tuplebuf = unfrozen_binary_copy('!!!!!') + exclamations = unfrozen_binary_copy('!!!!!') + z = unfrozen_binary_copy('z') + + bufreader.each_chunk do |chunk| + chunk.unpack('N*').each do |word| + # Encode each big-endian 32-bit word into a 5-character tuple (except + # for 0, which encodes to 'z') + if word.zero? + writer.write(z) + else + word, b0 = word.divmod(85) + word, b1 = word.divmod(85) + word, b2 = word.divmod(85) + word, b3 = word.divmod(85) + b4 = word + + tuplebuf.setbyte(0, b4 + 33) + tuplebuf.setbyte(1, b3 + 33) + tuplebuf.setbyte(2, b2 + 33) + tuplebuf.setbyte(3, b1 + 33) + tuplebuf.setbyte(4, b0 + 33) + + writer.write(tuplebuf) + end + end + + next if (chunk.bytesize & 0b11).zero? + + # If we have leftover bytes, we need to zero-pad to a multiple of four + # before converting to a 32-bit word. + padding_length = (-chunk.bytesize) % 4 + trailing = chunk[-(4 - padding_length)..] + word = (trailing + padding[0...padding_length]).unpack1('N') + + # Encode the last word and cut off any padding + if word.zero? + writer.write(exclamations[0..(4 - padding_length)]) + else + word, b0 = word.divmod(85) + word, b1 = word.divmod(85) + word, b2 = word.divmod(85) + word, b3 = word.divmod(85) + b4 = word + + tuplebuf.setbyte(0, b4 + 33) + tuplebuf.setbyte(1, b3 + 33) + tuplebuf.setbyte(2, b2 + 33) + tuplebuf.setbyte(3, b1 + 33) + tuplebuf.setbyte(4, b0 + 33) + + writer.write(tuplebuf[0..(4 - padding_length)]) + end + end + + # If no output IO-object was provided, extract the encoded String from the + # default StringIO writer. We force the encoding to 'ASCII-8BIT' to work + # around a TruffleRuby bug. + return writer.finish.io.string.force_encoding(Encoding::ASCII_8BIT) if out.nil? + + # Otherwise we make sure to flush the output writer, and then return it. + writer.finish.io + end + + # Searches through a String and extracts the first substring enclosed by '<~' and '~>'. + # + # @param str [String] The String to search through + # + # @return [String] The extracted substring, or an empty String if no valid delimiters are found + # + # @example Extracting Ascii85 content + # Ascii85.extract("Foo<~;KZGo~>Bar<~z~>Baz") + # # => ";KZGo" + # + # @example When no delimiters are found + # Ascii85.extract("No delimiters") + # # => "" + # + # @note This method only accepts a String, not an IO-like object, as the entire input + # needs to be available to ensure validity. + # + def extract(str) + input = str.to_s + + # Make sure the delimiter Strings have the correct encoding. + opening_delim = '<~'.encode(input.encoding) + closing_delim = '~>'.encode(input.encoding) + + # Get the positions of the opening/closing delimiters. If there is no pair + # of opening/closing delimiters, return an unfrozen empty String. + (start_pos = input.index(opening_delim)) or return EMPTY_STRING.dup + (end_pos = input.index(closing_delim, start_pos + 2)) or return EMPTY_STRING.dup + + # Get the String inside the delimiter-pair + input[(start_pos + 2)...end_pos] + end + + # + # Searches through a String and decodes the first substring enclosed by '<~' and '~>'. + # + # @param str [String] The String containing Ascii85-encoded content + # @param out [IO, nil] An optional IO-like object to write the output to + # + # @return [String, IO] The decoded String (in ASCII-8BIT encoding) or the output IO object (if it was provided) + # + # @raise [Ascii85::DecodingError] When malformed input is encountered + # + # @example Decoding Ascii85 content + # Ascii85.decode("<~;KZGo~>") + # # => "Ruby" + # + # @example Decoding with multiple Ascii85 blocks present (ignores all but the first) + # Ascii85.decode("Foo<~;KZGo~>Bar<~87cURDZ~>Baz") + # # => "Ruby" + # + # @example When no delimiters are found + # Ascii85.decode("No delimiters") + # # => "" + # + # @example Decoding to an IO object + # output = StringIO.new + # Ascii85.decode("<~;KZGo~>", out: output) + # # => output (with "Ruby" written to it) + # + # @note This method only accepts a String, not an IO-like object, as the entire input + # needs to be available to ensure validity. + # + def decode(str, out: nil) + decode_raw(extract(str), out: out) + end + + # + # Decodes the given raw Ascii85-encoded String or IO-like object. + # + # @param str_or_io [String, IO] The Ascii85-encoded input to decode + # @param out [IO, nil] An optional IO-like object to write the output to + # + # @return [String, IO] The decoded String (in ASCII-8BIT encoding) or the output IO object (if it was provided) + # + # @raise [Ascii85::DecodingError] When malformed input is encountered + # + # @example Decoding a raw Ascii85 String + # Ascii85.decode_raw(";KZGo") + # # => "Ruby" + # + # @example Decoding from an IO-like object + # input = StringIO.new(";KZGo") + # Ascii85.decode_raw(input) + # # => "Ruby" + # + # @example Decoding to an IO object + # output = StringIO.new + # Ascii85.decode_raw(";KZGo", out: output) + # # => output (with "Ruby" written to it) + # + # @note The input must not be enclosed in '<~' and '~>' delimiters. + # + def decode_raw(str_or_io, out: nil) + reader = if io_like?(str_or_io) + str_or_io + else + StringIO.new(str_or_io.to_s, 'rb') + end + + # Return an unfrozen String on empty input + return EMPTY_STRING.dup if reader.eof? + + # Setup buffered Reader and Writers + bufreader = BufferedReader.new(reader, encoded_chunk_size) + bufwriter = BufferedWriter.new(out || StringIO.new(String.new, 'wb'), unencoded_chunk_size) + + # Populate the lookup table (caches the exponentiation) + lut = (0..4).map { |count| 85**(4 - count) } + + # Decode + word = 0 + count = 0 + zeroes = unfrozen_binary_copy("\0\0\0\0") + wordbuf = zeroes.dup + + bufreader.each_chunk do |chunk| + chunk.each_byte do |c| + case c.chr + when ' ', "\t", "\r", "\n", "\f", "\0" + # Ignore whitespace + next + + when 'z' + raise(Ascii85::DecodingError, "Found 'z' inside Ascii85 5-tuple") unless count.zero? + + # Expand z to 0-word + bufwriter.write(zeroes) + + when '!'..'u' + # Decode 5 characters into a 4-byte word + word += (c - 33) * lut[count] + count += 1 + + if count == 5 && word > 0xffffffff + raise(Ascii85::DecodingError, "Invalid Ascii85 5-tuple (#{word} >= 2**32)") + elsif count == 5 + b3 = word & 0xff; word >>= 8 + b2 = word & 0xff; word >>= 8 + b1 = word & 0xff; word >>= 8 + b0 = word + + wordbuf.setbyte(0, b0) + wordbuf.setbyte(1, b1) + wordbuf.setbyte(2, b2) + wordbuf.setbyte(3, b3) + + bufwriter.write(wordbuf) + + word = 0 + count = 0 + end + + else + raise(Ascii85::DecodingError, "Illegal character inside Ascii85: #{c.chr.dump}") + end + end + end + + # We're done if all 5-tuples have been consumed + if count.zero? + bufwriter.flush + return out || bufwriter.io.string.force_encoding(Encoding::ASCII_8BIT) + end + + raise(Ascii85::DecodingError, 'Last 5-tuple consists of single character') if count == 1 + + # Finish last, partially decoded 32-bit word + count -= 1 + word += lut[count] + + bufwriter.write((word >> 24).chr) if count >= 1 + bufwriter.write(((word >> 16) & 0xff).chr) if count >= 2 + bufwriter.write(((word >> 8) & 0xff).chr) if count == 3 + bufwriter.flush + + out || bufwriter.io.string.force_encoding(Encoding::ASCII_8BIT) + end + + private + + # Copies the given String and forces the encoding of the returned copy to + # be Encoding::ASCII_8BIT. + def unfrozen_binary_copy(str) + str.dup.force_encoding(Encoding::ASCII_8BIT) + end + + # Buffers an underlying IO object to increase efficiency. You do not need + # to use this directly. + # + # @private + # + class BufferedReader + def initialize(io, buffer_size) + @io = io + @buffer_size = buffer_size + end + + def each_chunk + return enum_for(:each_chunk) unless block_given? + + until @io.eof? + chunk = @io.read(@buffer_size) + yield chunk if chunk + end + end + end + + # Buffers an underlying IO object to increase efficiency. You do not need + # to use this directly. + # + # @private + # + class BufferedWriter + attr_accessor :io + + def initialize(io, buffer_size) + @io = io + @buffer_size = buffer_size + @buffer = String.new(capacity: buffer_size, encoding: Encoding::ASCII_8BIT) + end + + def write(tuple) + flush if @buffer.bytesize + tuple.bytesize > @buffer_size + @buffer << tuple + end + + def flush + @io.write(@buffer) + @buffer.clear + end + end + + # Wraps the input in '<~' and '~>' delimiters and passes it through + # unmodified to the underlying IO object otherwise. You do not need to + # use this directly. + # + # @private + # + class DummyWrapper + def initialize(out) + @out = out + @out.write(START_MARKER) + end + + def write(buffer) + @out.write(buffer) + end + + def finish + @out.write(ENDING_MARKER) + @out.flush + + @out + end + end + + # Wraps the input in '<~' and '~>' delimiters and ensures that no line is + # longer than the specified length. You do not need to use this directly. + # + # @private + # + class Wrapper + def initialize(out, wrap_lines) + @line_length = [2, wrap_lines.to_i].max + + @out = out + @out.write(START_MARKER) + + @cur_len = 2 + end + + def write(buffer) + loop do + s = buffer.bytesize + + if @cur_len + s < @line_length + @out.write(buffer) + @cur_len += s + return + end + + remaining = @line_length - @cur_len + @out.write(buffer[0...remaining]) + @out.write(LINE_BREAK) + @cur_len = 0 + buffer = buffer[remaining..] + return if buffer.empty? + end + end + + def finish + # Add the closing delimiter (may need to be pushed to the next line) + @out.write(LINE_BREAK) if @cur_len + 2 > @line_length + @out.write(ENDING_MARKER) + + @out.flush + @out + end + end + + # Check if an object is IO-like + # + # @private + # + def io_like?(obj) + obj.respond_to?(:read) && + obj.respond_to?(:eof?) + end + + # @return [Integer] Buffer size for to-be-encoded input + # + def unencoded_chunk_size + 4 * 2048 + end + + # @return [Integer] Buffer size for encoded output + # + def encoded_chunk_size + 5 * 2048 + end + end + + # + # Error raised when Ascii85 encounters problems while decoding the input. + # + # This error is raised for the following issues: + # * An invalid character (valid characters are '!'..'u' and 'z') + # * A 'z' character inside a 5-tuple ('z' is only valid on its own) + # * An invalid 5-tuple that decodes to >= 2**32 + # * The last tuple consisting of a single character. Valid tuples always have + # at least two characters. + # + class DecodingError < StandardError; end +end diff --git a/bin/gems/Ascii85-2.0.1/spec/bin/cli_spec.rb b/bin/gems/Ascii85-2.0.1/spec/bin/cli_spec.rb new file mode 100644 index 00000000..93fb62a8 --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/spec/bin/cli_spec.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +require 'stringio' +require 'tempfile' + +require 'minitest/autorun' + +# We can't require the executable file because it doesn't +# have the '.rb' extension, so we have to load it. +unless defined?(CLI) + load File.join(__dir__, '..','..', 'bin', 'ascii85') +end + +describe 'CLI' do + it 'should recognize the -h and --help options' do + [%w[-h], %w[--help]].each do |args| + cli = CLI.new(args) + assert_equal :help, cli.options[:action] + end + end + + it 'should recognize the -V and --version options' do + [%w[-V], %w[--version]].each do |args| + cli = CLI.new(args) + assert_equal :version, cli.options[:action] + end + end + + it 'should complain about superfluous arguments' do + assert_raises(OptionParser::ParseError) do + CLI.new(%w[foo bar]) + end + end + + describe 'wrap' do + it 'should default to wrapping at 80 characters' do + cli = CLI.new([]) + assert_equal 80, cli.options[:wrap] + end + + it 'should recognize the -w and --wrap options' do + [%w[-w 17], %w[--wrap 17]].each do |args| + cli = CLI.new(args) + assert_equal 17, cli.options[:wrap] + end + end + + it 'should recognize the no-wrapping setting' do + cli = CLI.new(%w[-w 0]) + assert_equal false, cli.options[:wrap] + end + + it 'should raise an error if the wrap option is not an integer' do + assert_raises(OptionParser::ParseError) do + CLI.new(%w[-w foo]) + end + end + end + + describe 'encoding' do + it 'should encode from STDIN' do + stdin = StringIO.new('Ruby') + stdout = StringIO.new + + CLI.new([], stdin: stdin, stdout: stdout).call + + assert_equal '<~;KZGo~>', stdout.string + end + + it 'should accept "-" as a file name' do + stdin = StringIO.new('Ruby') + stdout = StringIO.new + + CLI.new(['-'], stdin: stdin, stdout: stdout).call + + assert_equal '<~;KZGo~>', stdout.string + end + + it 'should encode a file' do + begin + f = Tempfile.create('ascii85_encode') + f.write('Ruby') + f.close + + stdout = StringIO.new + CLI.new([f.path], stdout: stdout).call + + assert_equal '<~;KZGo~>', stdout.string + ensure + File.unlink(f.path) + end + end + + it 'should wrap lines' do + begin + f = Tempfile.create('ascii85_wrap') + f.write('a' * 20) + f.close + + stdout = StringIO.new + CLI.new([f.path, '-w2'], stdout: stdout).call + + assert stdout.string.lines.all? { |l| l.chomp.length <= 2 } + ensure + File.unlink(f.path) + end + end + + it 'should fail when the input file is not found' do + assert_raises(StandardError) do + CLI.new(['./foo/bar/baz']).call + end + end + + it 'should fail when the input file is not readable' do + begin + f = Tempfile.create('ascii85_encode') + f.chmod(0o000) + + assert_raises(StandardError) do + CLI.new([f.path]).call + end + ensure + File.unlink(f.path) + end + end + end + + describe 'decoding' do + it 'should decode from STDIN' do + stdin = StringIO.new('<~;KZGo~>') + stdout = StringIO.new + + CLI.new(['-d'], stdin: stdin, stdout: stdout).call + + assert_equal 'Ruby', stdout.string + end + + it 'should accept "-" as a file name' do + stdin = StringIO.new('<~;KZGo~>') + stdout = StringIO.new + + CLI.new(['-d','-'], stdin: stdin, stdout: stdout).call + + assert_equal 'Ruby', stdout.string + end + + it 'should decode a file' do + begin + f = Tempfile.create('ascii85_decode') + f.write('<~;KZGo~>') + f.close + + stdout = StringIO.new + CLI.new(['-d', f.path], stdout: stdout).call + + assert_equal 'Ruby', stdout.string + ensure + File.unlink(f.path) + end + end + + it 'should fail when the input file is not found' do + assert_raises(StandardError) do + CLI.new(['-d', './foo/bar/baz']).call + end + end + + it 'should fail when the input file is not readable' do + begin + f = Tempfile.create('ascii85_decode') + f.chmod(0o000) + + assert_raises(StandardError) do + CLI.new(['-d', f.path]).call + end + ensure + File.unlink(f.path) + end + end + + describe 'invalid input' do + it 'should return the empty string when the input does not have delimiters' do + stdin = StringIO.new('No delimiters') + stdout = StringIO.new + + CLI.new(['-d'], stdin: stdin, stdout: stdout).call + + assert_equal '', stdout.string + end + + ERROR_CASES = [ + '<~!!y!!~>', + '<~!!z!!~>', + '<~s8W-#~>', + '<~!~>', + ] + + it 'should raise an error when invalid input is encountered' do + ERROR_CASES.each do |input| + stdin = StringIO.new(input) + stdout = StringIO.new + + assert_raises(Ascii85::DecodingError) do + CLI.new(['-d'], stdin: stdin, stdout: stdout).call + end + end + end + end + end +end \ No newline at end of file diff --git a/bin/gems/Ascii85-2.0.1/spec/lib/ascii85_spec.rb b/bin/gems/Ascii85-2.0.1/spec/lib/ascii85_spec.rb new file mode 100644 index 00000000..415fbace --- /dev/null +++ b/bin/gems/Ascii85-2.0.1/spec/lib/ascii85_spec.rb @@ -0,0 +1,263 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require 'stringio' + +# Require implementation +require File.expand_path('../../lib/ascii85', __dir__) + +TEST_CASES = { + '' => '', + ' ' => '<~+9~>', + + "\0" * 1 => '<~!!~>', + "\0" * 2 => '<~!!!~>', + "\0" * 3 => '<~!!!!~>', + "\0" * 4 => '<~z~>', + "\0" * 5 => '<~z!!~>', + "A\0\0\0\0" => '<~5l^lb!!~>', # No z-abbreviation! + + 'A' => '<~5l~>', + 'AB' => '<~5sb~>', + 'ABC' => '<~5sdp~>', + 'ABCD' => '<~5sdq,~>', + 'ABCDE' => '<~5sdq,70~>', + 'ABCDEF' => '<~5sdq,77I~>', + 'ABCDEFG' => '<~5sdq,77Kc~>', + 'ABCDEFGH' => '<~5sdq,77Kd<~>', + 'ABCDEFGHI' => '<~5sdq,77Kd<8H~>', + 'Ascii85' => '<~6$$OMBfIs~>', + + 'Antidisestablishmentarianism' => '<~6#LdYA8-*rF*(i"Ch[s(D.RU,@<-\'jDJ=0/~>', + + # Dōmo arigatō, Mr. Roboto (according to Wikipedia) + 'どうもありがとうミスターロボット' => + '<~j+42iJVN3:K&_E6j+<0KJW/W?W8iG`j+EuaK"9on^Z0sZj+FJoK:LtSKB%T?~>', + + [Math::PI].pack('G') => '<~5RAV2<(&;T~>', + [Math::E].pack('G') => '<~5R"n0M\\K6,~>', + + # Minified example from Github issue 8. + # Note that OT and OU as the trailing characters are equivalent. + "\x9B\xB6\xB9+\x91" => '<~S$ojXOT~>' +}.freeze + +describe Ascii85 do + it '#decode should be the inverse of #encode' do + # Generate a test string that contains all possible bytes + test_str = String.new + (0..255).each do |c| + test_str << c.chr + end + + encoded = Ascii85.encode(test_str) + decoded = Ascii85.decode(encoded) + + assert_equal test_str, decoded + end + + describe '#encode' do + it 'should encode all specified test-cases correctly' do + TEST_CASES.each_pair do |input, encoded| + assert_equal encoded, Ascii85.encode(input) + end + end + + it 'should always return unfrozen Strings' do + TEST_CASES.each_pair do |input, encoded| + assert_equal false, Ascii85.encode(input).frozen? + end + end + + it 'should encode Strings in different encodings correctly' do + input_euc_jp = 'どうもありがとうミスターロボット'.encode('EUC-JP') + input_binary = input_euc_jp.force_encoding('ASCII-8BIT') + + assert_equal Ascii85.encode(input_binary), Ascii85.encode(input_euc_jp) + end + + it 'should produce output lines no longer than specified' do + test_str = '0123456789' * 30 + + # + # No wrap + # + assert_equal 0, Ascii85.encode(test_str, false).count("\n") + + # + # x characters per line, except for the last one + # + (2..12).each do |x| + encoded = Ascii85.encode(test_str, x) + + # Determine the length of all lines + count_arr = [] + encoded.each_line do |line| + count_arr << line.chomp.length + end + + # The last line is allowed to be shorter than x, so remove it + count_arr.pop if count_arr.last <= x + + # If the end-marker is on a line of its own, the next-to-last line is + # allowed to be shorter than specified by exactly one character + count_arr.pop if (encoded[-3].chr =~ /[\r\n]/) && (count_arr.last == x - 1) + + # Remove all line-lengths that are of length x from count_arr + count_arr.delete_if { |len| len == x } + + # Now count_arr should be empty + assert_empty count_arr + end + end + + it 'should not split the end-marker to achieve correct line length' do + assert_equal "<~z\n~>", Ascii85.encode("\0" * 4, 4) + end + + it 'should encode to an IO object when provided' do + output = StringIO.new + result = Ascii85.encode('Ruby', out: output) + assert_equal output, result + assert_equal '<~;KZGo~>', output.string + end + + it 'should encode from an IO object' do + input = StringIO.new('Ruby') + result = Ascii85.encode(input) + assert_equal '<~;KZGo~>', result + end + end + + describe '#extract' do + it 'should extract data within delimiters only' do + assert_empty Ascii85.extract('<~~>') + assert_empty Ascii85.extract("Doesn't contain delimiters") + assert_empty Ascii85.extract('Mismatched ~> delimiters 1') + assert_empty Ascii85.extract('Mismatched <~ delimiters 2') + assert_empty Ascii85.extract('Mismatched ~><~ delimiters 3') + + assert_equal ';KZGo', Ascii85.extract('<~;KZGo~><~z~>') + assert_equal 'z', Ascii85.extract('FooBar<~z~>BazQux') + end + end + + describe '#decode' do + it 'should decode all specified test-cases correctly' do + TEST_CASES.each_pair do |decoded, input| + assert_equal decoded.dup.force_encoding('ASCII-8BIT'), Ascii85.decode(input) + end + end + + it 'should always return unfrozen Strings' do + TEST_CASES.each_pair do |input, encoded| + assert_equal false, Ascii85.decode(encoded).frozen? + end + end + + it 'should accept valid input in encodings other than the default' do + input = 'Ragnarök τέχνη русский язык I ♥ Ruby' + input_ascii85 = Ascii85.encode(input) + + # Try to encode input_ascii85 in all possible encodings and see if we + # do the right thing in #decode. + Encoding.list.each do |encoding| + next if encoding.dummy? + next unless encoding.ascii_compatible? + + # CP949 is a Microsoft Codepage for Korean, which apparently does not + # include a backslash, even though #ascii_compatible? returns true. This + # leads to an Ascii85::DecodingError, so we simply skip the encoding. + next if encoding.name == 'CP949' + + begin + to_test = input_ascii85.encode(encoding) + assert_equal input, Ascii85.decode(to_test).force_encoding('UTF-8') + rescue Encoding::ConverterNotFoundError + # Ignore this encoding + end + end + end + + it 'should only process data within delimiters' do + assert_empty Ascii85.decode('<~~>') + assert_empty Ascii85.decode("Doesn't contain delimiters") + assert_empty Ascii85.decode('Mismatched ~> delimiters 1') + assert_empty Ascii85.decode('Mismatched <~ delimiters 2') + assert_empty Ascii85.decode('Mismatched ~><~ delimiters 3') + + assert_equal 'Ruby', Ascii85.decode('<~;KZGo~><~z~>') + assert_equal "\0\0\0\0", Ascii85.decode('FooBar<~z~>BazQux') + end + + it 'should ignore whitespace' do + decoded = Ascii85.decode("<~6 #LdYA\r\08\n \n\n- *rF*(i\"Ch[s \t(D.RU,@ <-\'jDJ=0\f/~>") + assert_equal 'Antidisestablishmentarianism', decoded + end + + it 'should return ASCII-8BIT encoded strings' do + assert_equal 'ASCII-8BIT', Ascii85.decode('<~;KZGo~>').encoding.name + end + + it 'should decode to an IO object when provided' do + output = StringIO.new + result = Ascii85.decode('<~;KZGo~>', out: output) + assert_equal output, result + assert_equal 'Ruby', output.string + end + + describe 'Error conditions' do + it 'should raise DecodingError if it encounters a word >= 2**32' do + assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~s8W-#~>') } + end + + it 'should raise DecodingError if it encounters an invalid character' do + assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!!y!!~>') } + end + + it 'should raise DecodingError if the last tuple consists of a single character' do + assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!~>') } + end + + it 'should raise DecodingError if a z is found inside a 5-tuple' do + assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!!z!!~>') } + end + end + end + + describe '#decode_raw' do + it 'should decode raw Ascii85 without delimiters' do + TEST_CASES.each_pair do |decoded, input| + raw_input = input[2...-2] # Remove '<~' and '~>' + assert_equal decoded.dup.force_encoding('ASCII-8BIT'), Ascii85.decode_raw(raw_input) + end + end + + it 'should always return unfrozen Strings' do + TEST_CASES.each_pair do |decoded, input| + raw_input = input[2...-2] # Remove '<~' and '~>' + assert_equal false, Ascii85.decode_raw(raw_input).frozen? + end + end + + it 'should decode from an IO object' do + input = StringIO.new(';KZGo') + result = Ascii85.decode_raw(input) + assert_equal 'Ruby', result + end + + it 'should decode to an IO object when provided' do + output = StringIO.new + result = Ascii85.decode_raw(';KZGo', out: output) + assert_equal output, result + assert_equal 'Ruby', output.string + end + + it 'should raise DecodingError for invalid input' do + assert_raises(Ascii85::DecodingError) { Ascii85.decode_raw('s8W-#') } + assert_raises(Ascii85::DecodingError) { Ascii85.decode_raw('!!y!!') } + assert_raises(Ascii85::DecodingError) { Ascii85.decode_raw('!') } + assert_raises(Ascii85::DecodingError) { Ascii85.decode_raw('!!z!!') } + end + end +end diff --git a/bin/gems/addressable-2.8.7/CHANGELOG.md b/bin/gems/addressable-2.8.7/CHANGELOG.md new file mode 100644 index 00000000..bf21002e --- /dev/null +++ b/bin/gems/addressable-2.8.7/CHANGELOG.md @@ -0,0 +1,301 @@ +# Addressable 2.8.7 +- Allow `public_suffix` 6 ([#535]) + +[#535]: https://github.com/sporkmonger/addressable/pull/535 + +# Addressable 2.8.6 +- Memoize regexps for common character classes ([#524]) + +[#524]: https://github.com/sporkmonger/addressable/pull/524 + +# Addressable 2.8.5 +- Fix thread safety issue with encoding tables ([#515]) +- Define URI::NONE as a module to avoid serialization issues ([#509]) +- Fix YAML serialization ([#508]) + +[#508]: https://github.com/sporkmonger/addressable/pull/508 +[#509]: https://github.com/sporkmonger/addressable/pull/509 +[#515]: https://github.com/sporkmonger/addressable/pull/515 + +# Addressable 2.8.4 +- Restore `Addressable::IDNA.unicode_normalize_kc` as a deprecated method ([#504]) + +[#504]: https://github.com/sporkmonger/addressable/pull/504 + +# Addressable 2.8.3 +- Fix template expand level 2 hash support for non-string objects ([#499], [#498]) + +[#499]: https://github.com/sporkmonger/addressable/pull/499 +[#498]: https://github.com/sporkmonger/addressable/pull/498 + +# Addressable 2.8.2 +- Improve cache hits and JIT friendliness ([#486](https://github.com/sporkmonger/addressable/pull/486)) +- Improve code style and test coverage ([#482](https://github.com/sporkmonger/addressable/pull/482)) +- Ensure reset of deferred validation ([#481](https://github.com/sporkmonger/addressable/pull/481)) +- Resolve normalization differences between `IDNA::Native` and `IDNA::Pure` ([#408](https://github.com/sporkmonger/addressable/issues/408), [#492]) +- Remove redundant colon in `Addressable::URI::CharacterClasses::AUTHORITY` regex ([#438](https://github.com/sporkmonger/addressable/pull/438)) (accidentally reverted by [#449] merge but [added back](https://github.com/sporkmonger/addressable/pull/492#discussion_r1105125280) in [#492]) + +[#492]: https://github.com/sporkmonger/addressable/pull/492 + +# Addressable 2.8.1 +- refactor `Addressable::URI.normalize_path` to address linter offenses ([#430](https://github.com/sporkmonger/addressable/pull/430)) +- update gemspec to reflect supported Ruby versions ([#466], [#464], [#463]) +- compatibility w/ public_suffix 5.x ([#466], [#465], [#460]) +- fixes "invalid byte sequence in UTF-8" exception when unencoding URLs containing non UTF-8 characters ([#459](https://github.com/sporkmonger/addressable/pull/459)) +- `Ractor` compatibility ([#449]) +- use the whole string instead of a single line for template match ([#431](https://github.com/sporkmonger/addressable/pull/431)) +- force UTF-8 encoding only if needed ([#341](https://github.com/sporkmonger/addressable/pull/341)) + +[#449]: https://github.com/sporkmonger/addressable/pull/449 +[#460]: https://github.com/sporkmonger/addressable/pull/460 +[#463]: https://github.com/sporkmonger/addressable/pull/463 +[#464]: https://github.com/sporkmonger/addressable/pull/464 +[#465]: https://github.com/sporkmonger/addressable/pull/465 +[#466]: https://github.com/sporkmonger/addressable/pull/466 + +# Addressable 2.8.0 +- fixes ReDoS vulnerability in Addressable::Template#match +- no longer replaces `+` with spaces in queries for non-http(s) schemes +- fixed encoding ipv6 literals +- the `:compacted` flag for `normalized_query` now dedupes parameters +- fix broken `escape_component` alias +- dropping support for Ruby 2.0 and 2.1 +- adding Ruby 3.0 compatibility for development tasks +- drop support for `rack-mount` and remove Addressable::Template#generate +- performance improvements +- switch CI/CD to GitHub Actions + +# Addressable 2.7.0 +- added `:compacted` flag to `normalized_query` +- `heuristic_parse` handles `mailto:` more intuitively +- dropped explicit support for JRuby 9.0.5.0 +- compatibility w/ public_suffix 4.x +- performance improvements + +# Addressable 2.6.0 +- added `tld=` method to allow assignment to the public suffix +- most `heuristic_parse` patterns are now case-insensitive +- `heuristic_parse` handles more `file://` URI variations +- fixes bug in `heuristic_parse` when uri starts with digit +- fixes bug in `request_uri=` with query strings +- fixes template issues with `nil` and `?` operator +- `frozen_string_literal` pragmas added +- minor performance improvements in regexps +- fixes to eliminate warnings + +# Addressable 2.5.2 +- better support for frozen string literals +- fixed bug w/ uppercase characters in scheme +- IDNA errors w/ emoji URLs +- compatibility w/ public_suffix 3.x + +# Addressable 2.5.1 +- allow unicode normalization to be disabled for URI Template expansion +- removed duplicate test + +# Addressable 2.5.0 +- dropping support for Ruby 1.9 +- adding support for Ruby 2.4 preview +- add support for public suffixes and tld; first runtime dependency +- hostname escaping should match RFC; underscores in hostnames no longer escaped +- paths beginning with // and missing an authority are now considered invalid +- validation now also takes place after setting a path +- handle backslashes in authority more like a browser for `heuristic_parse` +- unescaped backslashes in host now raise an `InvalidURIError` +- `merge!`, `join!`, `omit!` and `normalize!` don't disable deferred validation +- `heuristic_parse` now trims whitespace before parsing +- host parts longer than 63 bytes will be ignored and not passed to libidn +- normalized values always encoded as UTF-8 + +# Addressable 2.4.0 +- support for 1.8.x dropped +- double quotes in a host now raises an error +- newlines in host will no longer get unescaped during normalization +- stricter handling of bogus scheme values +- stricter handling of encoded port values +- calling `require 'addressable'` will now load both the URI and Template files +- assigning to the `hostname` component with an `IPAddr` object is now supported +- assigning to the `origin` component is now supported +- fixed minor bug where an exception would be thrown for a missing ACE suffix +- better partial expansion of URI templates + +# Addressable 2.3.8 +- fix warnings +- update dependency gems +- support for 1.8.x officially deprecated + +# Addressable 2.3.7 +- fix scenario in which invalid URIs don't get an exception until inspected +- handle hostnames with two adjacent periods correctly +- upgrade of RSpec + +# Addressable 2.3.6 +- normalization drops empty query string +- better handling in template extract for missing values +- template modifier for `'?'` now treated as optional +- fixed issue where character class parameters were modified +- templates can now be tested for equality +- added `:sorted` option to normalization of query strings +- fixed issue with normalization of hosts given in `'example.com.'` form + +# Addressable 2.3.5 +- added Addressable::URI#empty? method +- Addressable::URI#hostname methods now strip square brackets from IPv6 hosts +- compatibility with Net::HTTP in Ruby 2.0.0 +- Addressable::URI#route_from should always give relative URIs + +# Addressable 2.3.4 +- fixed issue with encoding altering its inputs +- query string normalization now leaves ';' characters alone +- FakeFS is detected before attempting to load unicode tables +- additional testing to ensure frozen objects don't cause problems + +# Addressable 2.3.3 +- fixed issue with converting common primitives during template expansion +- fixed port encoding issue +- removed a few warnings +- normalize should now ignore %2B in query strings +- the IDNA logic should now be handled by libidn in Ruby 1.9 +- no template match should now result in nil instead of an empty MatchData +- added license information to gemspec + +# Addressable 2.3.2 +- added Addressable::URI#default_port method +- fixed issue with Marshalling Unicode data on Windows +- improved heuristic parsing to better handle IPv4 addresses + +# Addressable 2.3.1 +- fixed missing unicode data file + +# Addressable 2.3.0 +- updated Addressable::Template to use RFC 6570, level 4 +- fixed compatibility problems with some versions of Ruby +- moved unicode tables into a data file for performance reasons +- removing support for multiple query value notations + +# Addressable 2.2.8 +- fixed issues with dot segment removal code +- form encoding can now handle multiple values per key +- updated development environment + +# Addressable 2.2.7 +- fixed issues related to Addressable::URI#query_values= +- the Addressable::URI.parse method is now polymorphic + +# Addressable 2.2.6 +- changed the way ambiguous paths are handled +- fixed bug with frozen URIs +- https supported in heuristic parsing + +# Addressable 2.2.5 +- 'parsing' a pre-parsed URI object is now a dup operation +- introduced conditional support for libidn +- fixed normalization issue on ampersands in query strings +- added additional tests around handling of query strings + +# Addressable 2.2.4 +- added origin support from draft-ietf-websec-origin-00 +- resolved issue with attempting to navigate below root +- fixed bug with string splitting in query strings + +# Addressable 2.2.3 +- added :flat_array notation for query strings + +# Addressable 2.2.2 +- fixed issue with percent escaping of '+' character in query strings + +# Addressable 2.2.1 +- added support for application/x-www-form-urlencoded. + +# Addressable 2.2.0 +- added site methods +- improved documentation + +# Addressable 2.1.2 +- added HTTP request URI methods +- better handling of Windows file paths +- validation_deferred boolean replaced with defer_validation block +- normalization of percent-encoded paths should now be correct +- fixed issue with constructing URIs with relative paths +- fixed warnings + +# Addressable 2.1.1 +- more type checking changes +- fixed issue with unicode normalization +- added method to find template defaults +- symbolic keys are now allowed in template mappings +- numeric values and symbolic values are now allowed in template mappings + +# Addressable 2.1.0 +- refactored URI template support out into its own class +- removed extract method due to being useless and unreliable +- removed Addressable::URI.expand_template +- removed Addressable::URI#extract_mapping +- added partial template expansion +- fixed minor bugs in the parse and heuristic_parse methods +- fixed incompatibility with Ruby 1.9.1 +- fixed bottleneck in Addressable::URI#hash and Addressable::URI#to_s +- fixed unicode normalization exception +- updated query_values methods to better handle subscript notation +- worked around issue with freezing URIs +- improved specs + +# Addressable 2.0.2 +- fixed issue with URI template expansion +- fixed issue with percent escaping characters 0-15 + +# Addressable 2.0.1 +- fixed issue with query string assignment +- fixed issue with improperly encoded components + +# Addressable 2.0.0 +- the initialize method now takes an options hash as its only parameter +- added query_values method to URI class +- completely replaced IDNA implementation with pure Ruby +- renamed Addressable::ADDRESSABLE_VERSION to Addressable::VERSION +- completely reworked the Rakefile +- changed the behavior of the port method significantly +- Addressable::URI.encode_segment, Addressable::URI.unencode_segment renamed +- documentation is now in YARD format +- more rigorous type checking +- to_str method implemented, implicit conversion to Strings now allowed +- Addressable::URI#omit method added, Addressable::URI#merge method replaced +- updated URI Template code to match v 03 of the draft spec +- added a bunch of new specifications + +# Addressable 1.0.4 +- switched to using RSpec's pending system for specs that rely on IDN +- fixed issue with creating URIs with paths that are not prefixed with '/' + +# Addressable 1.0.3 +- implemented a hash method + +# Addressable 1.0.2 +- fixed minor bug with the extract_mapping method + +# Addressable 1.0.1 +- fixed minor bug with the extract_mapping method + +# Addressable 1.0.0 +- heuristic parse method added +- parsing is slightly more strict +- replaced to_h with to_hash +- fixed routing methods +- improved specifications +- improved heckle rake task +- no surviving heckle mutations + +# Addressable 0.1.2 +- improved normalization +- fixed bug in joining algorithm +- updated specifications + +# Addressable 0.1.1 +- updated documentation +- added URI Template variable extraction + +# Addressable 0.1.0 +- initial release +- implementation based on RFC 3986, 3987 +- support for IRIs via libidn +- support for the URI Template draft spec diff --git a/bin/gems/addressable-2.8.7/Gemfile b/bin/gems/addressable-2.8.7/Gemfile new file mode 100644 index 00000000..87cf7719 --- /dev/null +++ b/bin/gems/addressable-2.8.7/Gemfile @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gemspec + +group :test do + gem 'bigdecimal' if RUBY_VERSION > '2.4' + gem 'rspec', '~> 3.8' + gem 'rspec-its', '~> 1.3' +end + +group :coverage do + gem "coveralls", "> 0.7", require: false, platforms: :mri + gem "simplecov", require: false +end + +group :development do + gem 'launchy', '~> 2.4', '>= 2.4.3' + gem 'redcarpet', :platform => :mri_19 + gem 'yard' +end + +group :test, :development do + gem 'memory_profiler' + gem "rake", ">= 12.3.3" +end + +unless ENV["IDNA_MODE"] == "pure" + gem "idn-ruby", platform: :mri +end diff --git a/bin/gems/addressable-2.8.7/LICENSE.txt b/bin/gems/addressable-2.8.7/LICENSE.txt new file mode 100644 index 00000000..ef51da2b --- /dev/null +++ b/bin/gems/addressable-2.8.7/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bin/gems/addressable-2.8.7/README.md b/bin/gems/addressable-2.8.7/README.md new file mode 100644 index 00000000..9892f615 --- /dev/null +++ b/bin/gems/addressable-2.8.7/README.md @@ -0,0 +1,121 @@ +# Addressable + +
+
Homepage
github.com/sporkmonger/addressable
+
Author
Bob Aman
+
Copyright
Copyright © Bob Aman
+
License
Apache 2.0
+
+ +[![Gem Version](https://img.shields.io/gem/dt/addressable.svg)][gem] +[![Build Status](https://github.com/sporkmonger/addressable/workflows/CI/badge.svg)][actions] +[![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls] +[![Documentation Coverage Status](https://inch-ci.org/github/sporkmonger/addressable.svg?branch=master)][inch] + +[gem]: https://rubygems.org/gems/addressable +[actions]: https://github.com/sporkmonger/addressable/actions +[coveralls]: https://coveralls.io/r/sporkmonger/addressable +[inch]: https://inch-ci.org/github/sporkmonger/addressable + +# Description + +Addressable is an alternative implementation to the URI implementation +that is part of Ruby's standard library. It is flexible, offers heuristic +parsing, and additionally provides extensive support for IRIs and URI templates. + +Addressable closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4). + +# Reference + +- {Addressable::URI} +- {Addressable::Template} + +# Example usage + +```ruby +require "addressable/uri" + +uri = Addressable::URI.parse("http://example.com/path/to/resource/") +uri.scheme +#=> "http" +uri.host +#=> "example.com" +uri.path +#=> "/path/to/resource/" + +uri = Addressable::URI.parse("http://www.詹姆斯.com/") +uri.normalize +#=> # +``` + + +# URI Templates + +For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt). + + +```ruby + +require "addressable/template" + +template = Addressable::Template.new("http://example.com/{?query*}") +template.expand({ + "query" => { + 'foo' => 'bar', + 'color' => 'red' + } +}) +#=> # + +template = Addressable::Template.new("http://example.com/{?one,two,three}") +template.partial_expand({"one" => "1", "three" => 3}).pattern +#=> "http://example.com/?one=1{&two}&three=3" + +template = Addressable::Template.new( + "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" +) +uri = Addressable::URI.parse( + "http://example.com/a/b/c/?one=1&two=2#foo" +) +template.extract(uri) +#=> +# { +# "host" => "example.com", +# "segments" => ["a", "b", "c"], +# "one" => "1", +# "two" => "2", +# "fragment" => "foo" +# } +``` + +# Install + +```console +$ gem install addressable +``` + +You may optionally turn on native IDN support by installing libidn and the +idn gem: + +```console +$ sudo apt-get install libidn11-dev # Debian/Ubuntu +$ brew install libidn # OS X +$ gem install idn-ruby +``` + +# Semantic Versioning + +This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your +dependency using a pessimistic version constraint covering the major and minor +values: + +```ruby +spec.add_dependency 'addressable', '~> 2.7' +``` + +If you need a specific bug fix, you can also specify minimum tiny versions +without preventing updates to the latest minor release: + +```ruby +spec.add_dependency 'addressable', '~> 2.3', '>= 2.3.7' +``` diff --git a/bin/gems/addressable-2.8.7/Rakefile b/bin/gems/addressable-2.8.7/Rakefile new file mode 100644 index 00000000..46fbbd0a --- /dev/null +++ b/bin/gems/addressable-2.8.7/Rakefile @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rubygems' +require 'rake' + +require File.join(File.dirname(__FILE__), 'lib', 'addressable', 'version') + +PKG_DISPLAY_NAME = 'Addressable' +PKG_NAME = PKG_DISPLAY_NAME.downcase +PKG_VERSION = Addressable::VERSION::STRING +PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" + +RELEASE_NAME = "REL #{PKG_VERSION}" + +PKG_SUMMARY = "URI Implementation" +PKG_DESCRIPTION = <<-TEXT +Addressable is an alternative implementation to the URI implementation that is +part of Ruby's standard library. It is flexible, offers heuristic parsing, and +additionally provides extensive support for IRIs and URI templates. +TEXT + +PKG_FILES = FileList[ + "data/**/*", + "lib/**/*.rb", + "spec/**/*.rb", + "tasks/**/*.rake", + "addressable.gemspec", + "CHANGELOG.md", + "Gemfile", + "LICENSE.txt", + "README.md", + "Rakefile", +] + +task :default => "spec" + +Dir['tasks/**/*.rake'].each { |rake| load rake } diff --git a/bin/gems/addressable-2.8.7/addressable.gemspec b/bin/gems/addressable-2.8.7/addressable.gemspec new file mode 100644 index 00000000..bb1f2fa7 --- /dev/null +++ b/bin/gems/addressable-2.8.7/addressable.gemspec @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +# stub: addressable 2.8.7 ruby lib + +Gem::Specification.new do |s| + s.name = "addressable".freeze + s.version = "2.8.7".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.metadata = { "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md#v2.8.7" } if s.respond_to? :metadata= + s.require_paths = ["lib".freeze] + s.authors = ["Bob Aman".freeze] + s.date = "2024-06-21" + s.description = "Addressable is an alternative implementation to the URI implementation that is\npart of Ruby's standard library. It is flexible, offers heuristic parsing, and\nadditionally provides extensive support for IRIs and URI templates.\n".freeze + s.email = "bob@sporkmonger.com".freeze + s.extra_rdoc_files = ["README.md".freeze] + s.files = ["CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "addressable.gemspec".freeze, "data/unicode.data".freeze, "lib/addressable.rb".freeze, "lib/addressable/idna.rb".freeze, "lib/addressable/idna/native.rb".freeze, "lib/addressable/idna/pure.rb".freeze, "lib/addressable/template.rb".freeze, "lib/addressable/uri.rb".freeze, "lib/addressable/version.rb".freeze, "spec/addressable/idna_spec.rb".freeze, "spec/addressable/net_http_compat_spec.rb".freeze, "spec/addressable/security_spec.rb".freeze, "spec/addressable/template_spec.rb".freeze, "spec/addressable/uri_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tasks/clobber.rake".freeze, "tasks/gem.rake".freeze, "tasks/git.rake".freeze, "tasks/metrics.rake".freeze, "tasks/profile.rake".freeze, "tasks/rspec.rake".freeze, "tasks/yard.rake".freeze] + s.homepage = "https://github.com/sporkmonger/addressable".freeze + s.licenses = ["Apache-2.0".freeze] + s.rdoc_options = ["--main".freeze, "README.md".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) + s.rubygems_version = "3.5.11".freeze + s.summary = "URI Implementation".freeze + + s.specification_version = 4 + + s.add_runtime_dependency(%q.freeze, [">= 2.0.2".freeze, "< 7.0".freeze]) + s.add_development_dependency(%q.freeze, [">= 1.0".freeze, "< 3.0".freeze]) +end diff --git a/bin/gems/addressable-2.8.7/data/unicode.data b/bin/gems/addressable-2.8.7/data/unicode.data new file mode 100644 index 00000000..cdfc2241 Binary files /dev/null and b/bin/gems/addressable-2.8.7/data/unicode.data differ diff --git a/bin/gems/addressable-2.8.7/lib/addressable.rb b/bin/gems/addressable-2.8.7/lib/addressable.rb new file mode 100644 index 00000000..b4e98b69 --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require 'addressable/uri' +require 'addressable/template' diff --git a/bin/gems/addressable-2.8.7/lib/addressable/idna.rb b/bin/gems/addressable-2.8.7/lib/addressable/idna.rb new file mode 100644 index 00000000..2dbd3934 --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/idna.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +begin + require "addressable/idna/native" +rescue LoadError + # libidn or the idn gem was not available, fall back on a pure-Ruby + # implementation... + require "addressable/idna/pure" +end diff --git a/bin/gems/addressable-2.8.7/lib/addressable/idna/native.rb b/bin/gems/addressable-2.8.7/lib/addressable/idna/native.rb new file mode 100644 index 00000000..a718364f --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/idna/native.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "idn" + +module Addressable + module IDNA + def self.punycode_encode(value) + IDN::Punycode.encode(value.to_s) + end + + def self.punycode_decode(value) + IDN::Punycode.decode(value.to_s) + end + + class << self + # @deprecated Use {String#unicode_normalize(:nfkc)} instead + def unicode_normalize_kc(value) + value.to_s.unicode_normalize(:nfkc) + end + + extend Gem::Deprecate + deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 + end + + def self.to_ascii(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + + def self.to_unicode(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + end +end diff --git a/bin/gems/addressable-2.8.7/lib/addressable/idna/pure.rb b/bin/gems/addressable-2.8.7/lib/addressable/idna/pure.rb new file mode 100644 index 00000000..3d6ffbad --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/idna/pure.rb @@ -0,0 +1,505 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +module Addressable + module IDNA + # This module is loosely based on idn_actionmailer by Mick Staugaard, + # the unicode library by Yoshida Masato, and the punycode implementation + # by Kazuhiro Nishiyama. Most of the code was copied verbatim, but + # some reformatting was done, and some translation from C was done. + # + # Without their code to work from as a base, we'd all still be relying + # on the presence of libidn. Which nobody ever seems to have installed. + # + # Original sources: + # http://github.com/staugaard/idn_actionmailer + # http://www.yoshidam.net/Ruby.html#unicode + # http://rubyforge.org/frs/?group_id=2550 + + + UNICODE_TABLE = File.expand_path( + File.join(File.dirname(__FILE__), '../../..', 'data/unicode.data') + ) + + ACE_PREFIX = "xn--" + + UTF8_REGEX = /\A(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*\z/mnx + + UTF8_REGEX_MULTIBYTE = /(?: + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )/mnx + + # :startdoc: + + # Converts from a Unicode internationalized domain name to an ASCII + # domain name as described in RFC 3490. + def self.to_ascii(input) + input = input.to_s unless input.is_a?(String) + input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc) + if input.respond_to?(:force_encoding) + input.force_encoding(Encoding::ASCII_8BIT) + end + if input =~ UTF8_REGEX && input =~ UTF8_REGEX_MULTIBYTE + parts = unicode_downcase(input).split('.') + parts.map! do |part| + if part.respond_to?(:force_encoding) + part.force_encoding(Encoding::ASCII_8BIT) + end + if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE + ACE_PREFIX + punycode_encode(part) + else + part + end + end + parts.join('.') + else + input + end + end + + # Converts from an ASCII domain name to a Unicode internationalized + # domain name as described in RFC 3490. + def self.to_unicode(input) + input = input.to_s unless input.is_a?(String) + parts = input.split('.') + parts.map! do |part| + if part =~ /^#{ACE_PREFIX}(.+)/ + begin + punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1]) + rescue Addressable::IDNA::PunycodeBadInput + # toUnicode is explicitly defined as never-fails by the spec + part + end + else + part + end + end + output = parts.join('.') + if output.respond_to?(:force_encoding) + output.force_encoding(Encoding::UTF_8) + end + output + end + + class << self + # @deprecated Use {String#unicode_normalize(:nfkc)} instead + def unicode_normalize_kc(value) + value.to_s.unicode_normalize(:nfkc) + end + + extend Gem::Deprecate + deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 + end + + ## + # Unicode aware downcase method. + # + # @api private + # @param [String] input + # The input string. + # @return [String] The downcased result. + def self.unicode_downcase(input) + input = input.to_s unless input.is_a?(String) + unpacked = input.unpack("U*") + unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) } + return unpacked.pack("U*") + end + private_class_method :unicode_downcase + + def self.lookup_unicode_lowercase(codepoint) + codepoint_data = UNICODE_DATA[codepoint] + (codepoint_data ? + (codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) : + codepoint) + end + private_class_method :lookup_unicode_lowercase + + UNICODE_DATA_COMBINING_CLASS = 0 + UNICODE_DATA_EXCLUSION = 1 + UNICODE_DATA_CANONICAL = 2 + UNICODE_DATA_COMPATIBILITY = 3 + UNICODE_DATA_UPPERCASE = 4 + UNICODE_DATA_LOWERCASE = 5 + UNICODE_DATA_TITLECASE = 6 + + begin + if defined?(FakeFS) + fakefs_state = FakeFS.activated? + FakeFS.deactivate! + end + # This is a sparse Unicode table. Codepoints without entries are + # assumed to have the value: [0, 0, nil, nil, nil, nil, nil] + UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file| + Marshal.load(file.read) + end + ensure + if defined?(FakeFS) + FakeFS.activate! if fakefs_state + end + end + + COMPOSITION_TABLE = {} + UNICODE_DATA.each do |codepoint, data| + canonical = data[UNICODE_DATA_CANONICAL] + exclusion = data[UNICODE_DATA_EXCLUSION] + + if canonical && exclusion == 0 + COMPOSITION_TABLE[canonical.unpack("C*")] = codepoint + end + end + + UNICODE_MAX_LENGTH = 256 + ACE_MAX_LENGTH = 256 + + PUNYCODE_BASE = 36 + PUNYCODE_TMIN = 1 + PUNYCODE_TMAX = 26 + PUNYCODE_SKEW = 38 + PUNYCODE_DAMP = 700 + PUNYCODE_INITIAL_BIAS = 72 + PUNYCODE_INITIAL_N = 0x80 + PUNYCODE_DELIMITER = 0x2D + + PUNYCODE_MAXINT = 1 << 64 + + PUNYCODE_PRINT_ASCII = + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + " !\"\#$%&'()*+,-./" + + "0123456789:;<=>?" + + "@ABCDEFGHIJKLMNO" + + "PQRSTUVWXYZ[\\]^_" + + "`abcdefghijklmno" + + "pqrstuvwxyz{|}~\n" + + # Input is invalid. + class PunycodeBadInput < StandardError; end + # Output would exceed the space provided. + class PunycodeBigOutput < StandardError; end + # Input needs wider integers to process. + class PunycodeOverflow < StandardError; end + + def self.punycode_encode(unicode) + unicode = unicode.to_s unless unicode.is_a?(String) + input = unicode.unpack("U*") + output = [0] * (ACE_MAX_LENGTH + 1) + input_length = input.size + output_length = [ACE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + delta = out = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: + input_length.times do |j| + if punycode_basic?(input[j]) + if max_out - out < 2 + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + output[out] = input[j] + out += 1 + end + end + + h = b = out + + # h is the number of code points that have been handled, b is the + # number of basic code points, and out is the number of characters + # that have been output. + + if b > 0 + output[out] = PUNYCODE_DELIMITER + out += 1 + end + + # Main encoding loop: + + while h < input_length + # All non-basic code points < n have been + # handled already. Find the next larger one: + + m = PUNYCODE_MAXINT + input_length.times do |j| + m = input[j] if (n...m) === input[j] + end + + # Increase delta enough to advance the decoder's + # state to , but guard against overflow: + + if m - n > (PUNYCODE_MAXINT - delta) / (h + 1) + raise PunycodeOverflow, "Input needs wider integers to process." + end + delta += (m - n) * (h + 1) + n = m + + input_length.times do |j| + # Punycode does not need to check whether input[j] is basic: + if input[j] < n + delta += 1 + if delta == 0 + raise PunycodeOverflow, + "Input needs wider integers to process." + end + end + + if input[j] == n + # Represent delta as a generalized variable-length integer: + + q = delta; k = PUNYCODE_BASE + while true + if out >= max_out + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if q < t + output[out] = + punycode_encode_digit(t + (q - t) % (PUNYCODE_BASE - t)) + out += 1 + q = (q - t) / (PUNYCODE_BASE - t) + k += PUNYCODE_BASE + end + + output[out] = punycode_encode_digit(q) + out += 1 + bias = punycode_adapt(delta, h + 1, h == b) + delta = 0 + h += 1 + end + end + + delta += 1 + n += 1 + end + + output_length[0] = out + + outlen = out + outlen.times do |j| + c = output[j] + unless c >= 0 && c <= 127 + raise StandardError, "Invalid output char." + end + unless PUNYCODE_PRINT_ASCII[c] + raise PunycodeBadInput, "Input is invalid." + end + end + + output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "") + end + private_class_method :punycode_encode + + def self.punycode_decode(punycode) + input = [] + output = [] + + if ACE_MAX_LENGTH * 2 < punycode.size + raise PunycodeBigOutput, "Output would exceed the space provided." + end + punycode.each_byte do |c| + unless c >= 0 && c <= 127 + raise PunycodeBadInput, "Input is invalid." + end + input.push(c) + end + + input_length = input.length + output_length = [UNICODE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + + out = i = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: Let b be the number of input code + # points before the last delimiter, or 0 if there is none, then + # copy the first b code points to the output. + + b = 0 + input_length.times do |j| + b = j if punycode_delimiter?(input[j]) + end + if b > max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + b.times do |j| + unless punycode_basic?(input[j]) + raise PunycodeBadInput, "Input is invalid." + end + output[out] = input[j] + out+=1 + end + + # Main decoding loop: Start just after the last delimiter if any + # basic code points were copied; start at the beginning otherwise. + + in_ = b > 0 ? b + 1 : 0 + while in_ < input_length + + # in_ is the index of the next character to be consumed, and + # out is the number of code points in the output array. + + # Decode a generalized variable-length integer into delta, + # which gets added to i. The overflow checking is easier + # if we increase i as we go, then subtract off its starting + # value at the end to obtain delta. + + oldi = i; w = 1; k = PUNYCODE_BASE + while true + if in_ >= input_length + raise PunycodeBadInput, "Input is invalid." + end + digit = punycode_decode_digit(input[in_]) + in_+=1 + if digit >= PUNYCODE_BASE + raise PunycodeBadInput, "Input is invalid." + end + if digit > (PUNYCODE_MAXINT - i) / w + raise PunycodeOverflow, "Input needs wider integers to process." + end + i += digit * w + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if digit < t + if w > PUNYCODE_MAXINT / (PUNYCODE_BASE - t) + raise PunycodeOverflow, "Input needs wider integers to process." + end + w *= PUNYCODE_BASE - t + k += PUNYCODE_BASE + end + + bias = punycode_adapt(i - oldi, out + 1, oldi == 0) + + # I was supposed to wrap around from out + 1 to 0, + # incrementing n each time, so we'll fix that now: + + if i / (out + 1) > PUNYCODE_MAXINT - n + raise PunycodeOverflow, "Input needs wider integers to process." + end + n += i / (out + 1) + i %= out + 1 + + # Insert n at position i of the output: + + # not needed for Punycode: + # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base + if out >= max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + #memmove(output + i + 1, output + i, (out - i) * sizeof *output) + output[i + 1, out - i] = output[i, out - i] + output[i] = n + i += 1 + + out += 1 + end + + output_length[0] = out + + output.pack("U*") + end + private_class_method :punycode_decode + + def self.punycode_basic?(codepoint) + codepoint < 0x80 + end + private_class_method :punycode_basic? + + def self.punycode_delimiter?(codepoint) + codepoint == PUNYCODE_DELIMITER + end + private_class_method :punycode_delimiter? + + def self.punycode_encode_digit(d) + d + 22 + 75 * ((d < 26) ? 1 : 0) + end + private_class_method :punycode_encode_digit + + # Returns the numeric value of a basic codepoint + # (for use in representing integers) in the range 0 to + # base - 1, or PUNYCODE_BASE if codepoint does not represent a value. + def self.punycode_decode_digit(codepoint) + if codepoint - 48 < 10 + codepoint - 22 + elsif codepoint - 65 < 26 + codepoint - 65 + elsif codepoint - 97 < 26 + codepoint - 97 + else + PUNYCODE_BASE + end + end + private_class_method :punycode_decode_digit + + # Bias adaptation method + def self.punycode_adapt(delta, numpoints, firsttime) + delta = firsttime ? delta / PUNYCODE_DAMP : delta >> 1 + # delta >> 1 is a faster way of doing delta / 2 + delta += delta / numpoints + difference = PUNYCODE_BASE - PUNYCODE_TMIN + + k = 0 + while delta > (difference * PUNYCODE_TMAX) / 2 + delta /= difference + k += PUNYCODE_BASE + end + + k + (difference + 1) * delta / (delta + PUNYCODE_SKEW) + end + private_class_method :punycode_adapt + end + # :startdoc: +end diff --git a/bin/gems/addressable-2.8.7/lib/addressable/template.rb b/bin/gems/addressable-2.8.7/lib/addressable/template.rb new file mode 100644 index 00000000..08556d9e --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/template.rb @@ -0,0 +1,1029 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/uri" + +module Addressable + ## + # This is an implementation of a URI template based on + # RFC 6570 (http://tools.ietf.org/html/rfc6570). + class Template + # Constants used throughout the template code. + anything = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + + + variable_char_class = + Addressable::URI::CharacterClasses::ALPHA + + Addressable::URI::CharacterClasses::DIGIT + '_' + + var_char = + "(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)" + RESERVED = + "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])" + UNRESERVED = + "(?:[#{ + Addressable::URI::CharacterClasses::UNRESERVED + }]|%[a-fA-F0-9][a-fA-F0-9])" + variable = + "(?:#{var_char}(?:\\.?#{var_char})*)" + varspec = + "(?:(#{variable})(\\*|:\\d+)?)" + VARNAME = + /^#{variable}$/ + VARSPEC = + /^#{varspec}$/ + VARIABLE_LIST = + /^#{varspec}(?:,#{varspec})*$/ + operator = + "+#./;?&=,!@|" + EXPRESSION = + /\{([#{operator}])?(#{varspec}(?:,#{varspec})*)\}/ + + + LEADERS = { + '?' => '?', + '/' => '/', + '#' => '#', + '.' => '.', + ';' => ';', + '&' => '&' + } + JOINERS = { + '?' => '&', + '.' => '.', + ';' => ';', + '&' => '&', + '/' => '/' + } + + ## + # Raised if an invalid template value is supplied. + class InvalidTemplateValueError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class InvalidTemplateOperatorError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class TemplateOperatorAbortedError < StandardError + end + + ## + # This class represents the data that is extracted when a Template + # is matched against a URI. + class MatchData + ## + # Creates a new MatchData object. + # MatchData objects should never be instantiated directly. + # + # @param [Addressable::URI] uri + # The URI that the template was matched against. + def initialize(uri, template, mapping) + @uri = uri.dup.freeze + @template = template + @mapping = mapping.dup.freeze + end + + ## + # @return [Addressable::URI] + # The URI that the Template was matched against. + attr_reader :uri + + ## + # @return [Addressable::Template] + # The Template used for the match. + attr_reader :template + + ## + # @return [Hash] + # The mapping that resulted from the match. + # Note that this mapping does not include keys or values for + # variables that appear in the Template, but are not present + # in the URI. + attr_reader :mapping + + ## + # @return [Array] + # The list of variables that were present in the Template. + # Note that this list will include variables which do not appear + # in the mapping because they were not present in URI. + def variables + self.template.variables + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # @return [Array] + # The list of values that were captured by the Template. + # Note that this list will include nils for any variables which + # were in the Template, but did not appear in the URI. + def values + @values ||= self.variables.inject([]) do |accu, key| + accu << self.mapping[key] + accu + end + end + alias_method :captures, :values + + ## + # Accesses captured values by name or by index. + # + # @param [String, Symbol, Fixnum] key + # Capture index or name. Note that when accessing by with index + # of 0, the full URI will be returned. The intention is to mimic + # the ::MatchData#[] behavior. + # + # @param [#to_int, nil] len + # If provided, an array of values will be returned with the given + # parameter used as length. + # + # @return [Array, String, nil] + # The captured value corresponding to the index or name. If the + # value was not provided or the key is unknown, nil will be + # returned. + # + # If the second parameter is provided, an array of that length will + # be returned instead. + def [](key, len = nil) + if len + to_a[key, len] + elsif String === key or Symbol === key + mapping[key.to_s] + else + to_a[key] + end + end + + ## + # @return [Array] + # Array with the matched URI as first element followed by the captured + # values. + def to_a + [to_s, *values] + end + + ## + # @return [String] + # The matched URI as String. + def to_s + uri.to_s + end + alias_method :string, :to_s + + # Returns multiple captured values at once. + # + # @param [String, Symbol, Fixnum] *indexes + # Indices of the captures to be returned + # + # @return [Array] + # Values corresponding to given indices. + # + # @see Addressable::Template::MatchData#[] + def values_at(*indexes) + indexes.map { |i| self[i] } + end + + ## + # Returns a String representation of the MatchData's state. + # + # @return [String] The MatchData's state, as a String. + def inspect + sprintf("#<%s:%#0x RESULT:%s>", + self.class.to_s, self.object_id, self.mapping.inspect) + end + + ## + # Dummy method for code expecting a ::MatchData instance + # + # @return [String] An empty string. + def pre_match + "" + end + alias_method :post_match, :pre_match + end + + ## + # Creates a new Addressable::Template object. + # + # @param [#to_str] pattern The URI Template pattern. + # + # @return [Addressable::Template] The initialized Template object. + def initialize(pattern) + if !pattern.respond_to?(:to_str) + raise TypeError, "Can't convert #{pattern.class} into String." + end + @pattern = pattern.to_str.dup.freeze + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.variables + self.variable_defaults + self.named_captures + super + end + + ## + # @return [String] The Template object's pattern. + attr_reader :pattern + + ## + # Returns a String representation of the Template object's state. + # + # @return [String] The Template object's state, as a String. + def inspect + sprintf("#<%s:%#0x PATTERN:%s>", + self.class.to_s, self.object_id, self.pattern) + end + + ## + # Returns true if the Template objects are equal. This method + # does NOT normalize either Template before doing the comparison. + # + # @param [Object] template The Template to compare. + # + # @return [TrueClass, FalseClass] + # true if the Templates are equivalent, false + # otherwise. + def ==(template) + return false unless template.kind_of?(Template) + return self.pattern == template.pattern + end + + ## + # Addressable::Template makes no distinction between `==` and `eql?`. + # + # @see #== + alias_method :eql?, :== + + ## + # Extracts a mapping from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).extract(uri, ExampleProcessor) + # #=> {"query" => "an example search query"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{second}/" + # ).extract(uri, ExampleProcessor) + # #=> {"first" => "a", "second" => "b/c"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{-list|/|second}/" + # ).extract(uri) + # #=> {"first" => "a", "second" => ["b", "c"]} + def extract(uri, processor=nil) + match_data = self.match(uri, processor) + return (match_data ? match_data.mapping : nil) + end + + ## + # Extracts match data from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # match = Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["query"] + # match.captures + # #=> ["an example search query"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}/{+second}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", "b/c"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}{/second*}/" + # ).match(uri) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", ["b", "c"]] + def match(uri, processor=nil) + uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI) + mapping = {} + + # First, we need to process the pattern, and extract the values. + expansions, expansion_regexp = + parse_template_pattern(pattern, processor) + + return nil unless uri.to_str.match(expansion_regexp) + unparsed_values = uri.to_str.scan(expansion_regexp).flatten + + if uri.to_str == pattern + return Addressable::Template::MatchData.new(uri, self, mapping) + elsif expansions.size > 0 + index = 0 + expansions.each do |expansion| + _, operator, varlist = *expansion.match(EXPRESSION) + varlist.split(',').each do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + mapping[name] ||= nil + case operator + when nil, '+', '#', '/', '.' + unparsed_value = unparsed_values[index] + name = varspec[VARSPEC, 1] + value = unparsed_value + value = value.split(JOINERS[operator]) if value && modifier == '*' + when ';', '?', '&' + if modifier == '*' + if unparsed_values[index] + value = unparsed_values[index].split(JOINERS[operator]) + value = value.inject({}) do |acc, v| + key, val = v.split('=') + val = "" if val.nil? + acc[key] = val + acc + end + end + else + if (unparsed_values[index]) + name, value = unparsed_values[index].split('=') + value = "" if value.nil? + end + end + end + if processor != nil && processor.respond_to?(:restore) + value = processor.restore(name, value) + end + if processor == nil + if value.is_a?(Hash) + value = value.inject({}){|acc, (k, v)| + acc[Addressable::URI.unencode_component(k)] = + Addressable::URI.unencode_component(v) + acc + } + elsif value.is_a?(Array) + value = value.map{|v| Addressable::URI.unencode_component(v) } + else + value = Addressable::URI.unencode_component(value) + end + end + if !mapping.has_key?(name) || mapping[name].nil? + # Doesn't exist, set to value (even if value is nil) + mapping[name] = value + end + index = index + 1 + end + end + return Addressable::Template::MatchData.new(uri, self, mapping) + else + return nil + end + end + + ## + # Expands a URI template into another URI template. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::Template] The partially expanded URI template. + # + # @example + # Addressable::Template.new( + # "http://example.com/{one}/{two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/1/{two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/?one=1{&two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two,three}/" + # ).partial_expand({"one" => "1", "three" => 3}).pattern + # #=> "http://example.com/?one=1{&two}&three=3" + def partial_expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_partial_capture(mapping, capture, processor, normalize_values) + end + return Addressable::Template.new(result) + end + + ## + # Expands a URI template into a full URI. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::URI] The expanded URI template. + # + # @example + # class ExampleProcessor + # def self.validate(name, value) + # return !!(value =~ /^[\w ]+$/) if name == "query" + # return true + # end + # + # def self.transform(name, value) + # return value.gsub(/ /, "+") if name == "query" + # return value + # end + # end + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"}, + # ExampleProcessor + # ).to_str + # #=> "http://example.com/search/an+example+search+query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"} + # ).to_str + # #=> "http://example.com/search/an%20example%20search%20query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "bogus!"}, + # ExampleProcessor + # ).to_str + # #=> Addressable::Template::InvalidTemplateValueError + def expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_capture(mapping, capture, processor, normalize_values) + end + return Addressable::URI.parse(result) + end + + ## + # Returns an Array of variables used within the template pattern. + # The variables are listed in the Array in the order they appear within + # the pattern. Multiple occurrences of a variable within a pattern are + # not represented in this Array. + # + # @return [Array] The variables present in the template's pattern. + def variables + @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # Returns a mapping of variables to their default values specified + # in the template. Variables without defaults are not returned. + # + # @return [Hash] Mapping of template variables to their defaults + def variable_defaults + @variable_defaults ||= + Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] + end + + ## + # Coerces a template into a `Regexp` object. This regular expression will + # behave very similarly to the actual template, and should match the same + # URI values, but it cannot fully handle, for example, values that would + # extract to an `Array`. + # + # @return [Regexp] A regular expression which should match the template. + def to_regexp + _, source = parse_template_pattern(pattern) + Regexp.new(source) + end + + ## + # Returns the source of the coerced `Regexp`. + # + # @return [String] The source of the `Regexp` given by {#to_regexp}. + # + # @api private + def source + self.to_regexp.source + end + + ## + # Returns the named captures of the coerced `Regexp`. + # + # @return [Hash] The named captures of the `Regexp` given by {#to_regexp}. + # + # @api private + def named_captures + self.to_regexp.named_captures + end + + private + def ordered_variable_defaults + @ordered_variable_defaults ||= begin + expansions, _ = parse_template_pattern(pattern) + expansions.flat_map do |capture| + _, _, varlist = *capture.match(EXPRESSION) + varlist.split(',').map do |varspec| + varspec[VARSPEC, 1] + end + end + end + end + + + ## + # Loops through each capture and expands any values available in mapping + # + # @param [Hash] mapping + # Set of keys to expand + # @param [String] capture + # The expression to expand + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_partial_capture(mapping, capture, processor = nil, + normalize_values = true) + _, operator, varlist = *capture.match(EXPRESSION) + + vars = varlist.split(",") + + if operator == "?" + # partial expansion of form style query variables sometimes requires a + # slight reordering of the variables to produce a valid url. + first_to_expand = vars.find { |varspec| + _, name, _ = *varspec.match(VARSPEC) + mapping.key?(name) && !mapping[name].nil? + } + + vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand + end + + vars. + inject("".dup) do |acc, varspec| + _, name, _ = *varspec.match(VARSPEC) + next_val = if mapping.key? name + transform_capture(mapping, "{#{operator}#{varspec}}", + processor, normalize_values) + else + "{#{operator}#{varspec}}" + end + # If we've already expanded at least one '?' operator with non-empty + # value, change to '&' + operator = "&" if (operator == "?") && (next_val != "") + acc << next_val + end + end + + ## + # Transforms a mapped value so that values can be substituted into the + # template. + # + # @param [Hash] mapping The mapping to replace captures + # @param [String] capture + # The expression to replace + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_capture(mapping, capture, processor=nil, + normalize_values=true) + _, operator, varlist = *capture.match(EXPRESSION) + return_value = varlist.split(',').inject([]) do |acc, varspec| + _, name, modifier = *varspec.match(VARSPEC) + value = mapping[name] + unless value == nil || value == {} + allow_reserved = %w(+ #).include?(operator) + # Common primitives where the .to_s output is well-defined + if Numeric === value || Symbol === value || + value == true || value == false + value = value.to_s + end + length = modifier.gsub(':', '').to_i if modifier =~ /^:\d+/ + + unless (Hash === value) || + value.respond_to?(:to_ary) || value.respond_to?(:to_str) + raise TypeError, + "Can't convert #{value.class} into String or Array." + end + + value = normalize_value(value) if normalize_values + + if processor == nil || !processor.respond_to?(:transform) + # Handle percent escaping + if allow_reserved + encode_map = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + else + encode_map = Addressable::URI::CharacterClasses::UNRESERVED + end + if value.kind_of?(Array) + transformed_value = value.map do |val| + if length + Addressable::URI.encode_component(val[0...length], encode_map) + else + Addressable::URI.encode_component(val, encode_map) + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + elsif value.kind_of?(Hash) + transformed_value = value.map do |key, val| + if modifier == "*" + "#{ + Addressable::URI.encode_component( key, encode_map) + }=#{ + Addressable::URI.encode_component( val, encode_map) + }" + else + "#{ + Addressable::URI.encode_component( key, encode_map) + },#{ + Addressable::URI.encode_component( val, encode_map) + }" + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + else + if length + transformed_value = Addressable::URI.encode_component( + value[0...length], encode_map) + else + transformed_value = Addressable::URI.encode_component( + value, encode_map) + end + end + end + + # Process, if we've got a processor + if processor != nil + if processor.respond_to?(:validate) + if !processor.validate(name, value) + display_value = value.kind_of?(Array) ? value.inspect : value + raise InvalidTemplateValueError, + "#{name}=#{display_value} is an invalid template value." + end + end + if processor.respond_to?(:transform) + transformed_value = processor.transform(name, value) + if normalize_values + transformed_value = normalize_value(transformed_value) + end + end + end + acc << [name, transformed_value] + end + acc + end + return "" if return_value.empty? + join_values(operator, return_value) + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [String, Nil] operator One of the operators from the set + # (?,&,+,#,;,/,.), or nil if there wasn't one. + # @param [Array] return_value + # The set of return values (as [variable_name, value] tuples) that will + # be joined together. + # + # @return [String] The transformed mapped value + def join_values(operator, return_value) + leader = LEADERS.fetch(operator, '') + joiner = JOINERS.fetch(operator, ',') + case operator + when '&', '?' + leader + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + v.join(joiner) + elsif v.is_a?(Array) + v.map{|inner_value| "#{k}=#{inner_value}"}.join(joiner) + else + "#{k}=#{v}" + end + }.join(joiner) + when ';' + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + ';' + v.join(";") + elsif v.is_a?(Array) + ';' + v.map{|inner_value| "#{k}=#{inner_value}"}.join(";") + else + v && v != '' ? ";#{k}=#{v}" : ";#{k}" + end + }.join + else + leader + return_value.map{|k,v| v}.join(joiner) + end + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [Hash, Array, String] value + # Normalizes unicode keys and values with String#unicode_normalize (NFC) + # + # @return [Hash, Array, String] The normalized values + def normalize_value(value) + # Handle unicode normalization + if value.respond_to?(:to_ary) + value.to_ary.map! { |val| normalize_value(val) } + elsif value.kind_of?(Hash) + value = value.inject({}) { |acc, (k, v)| + acc[normalize_value(k)] = normalize_value(v) + acc + } + else + value = value.to_s if !value.kind_of?(String) + if value.encoding != Encoding::UTF_8 + value = value.dup.force_encoding(Encoding::UTF_8) + end + value = value.unicode_normalize(:nfc) + end + value + end + + ## + # Generates a hash with string keys + # + # @param [Hash] mapping A mapping hash to normalize + # + # @return [Hash] + # A hash with stringified keys + def normalize_keys(mapping) + return mapping.inject({}) do |accu, pair| + name, value = pair + if Symbol === name + name = name.to_s + elsif name.respond_to?(:to_str) + name = name.to_str + else + raise TypeError, + "Can't convert #{name.class} into String." + end + accu[name] = value + accu + end + end + + ## + # Generates the Regexp that parses a template pattern. Memoizes the + # value if template processor not set (processors may not be deterministic) + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Array, Regexp] + # An array of expansion variables nad a regular expression which may be + # used to parse a template pattern + def parse_template_pattern(pattern, processor = nil) + if processor.nil? && pattern == @pattern + @cached_template_parse ||= + parse_new_template_pattern(pattern, processor) + else + parse_new_template_pattern(pattern, processor) + end + end + + ## + # Generates the Regexp that parses a template pattern. + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Array, Regexp] + # An array of expansion variables nad a regular expression which may be + # used to parse a template pattern + def parse_new_template_pattern(pattern, processor = nil) + # Escape the pattern. The two gsubs restore the escaped curly braces + # back to their original form. Basically, escape everything that isn't + # within an expansion. + escaped_pattern = Regexp.escape( + pattern + ).gsub(/\\\{(.*?)\\\}/) do |escaped| + escaped.gsub(/\\(.)/, "\\1") + end + + expansions = [] + + # Create a regular expression that captures the values of the + # variables in the URI. + regexp_string = escaped_pattern.gsub( EXPRESSION ) do |expansion| + + expansions << expansion + _, operator, varlist = *expansion.match(EXPRESSION) + leader = Regexp.escape(LEADERS.fetch(operator, '')) + joiner = Regexp.escape(JOINERS.fetch(operator, ',')) + combined = varlist.split(',').map do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + + result = processor && processor.respond_to?(:match) ? processor.match(name) : nil + if result + "(?<#{name}>#{ result })" + else + group = case operator + when '+' + "#{ RESERVED }*?" + when '#' + "#{ RESERVED }*?" + when '/' + "#{ UNRESERVED }*?" + when '.' + "#{ UNRESERVED.gsub('\.', '') }*?" + when ';' + "#{ UNRESERVED }*=?#{ UNRESERVED }*?" + when '?' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + when '&' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + else + "#{ UNRESERVED }*?" + end + if modifier == '*' + "(?<#{name}>#{group}(?:#{joiner}?#{group})*)?" + else + "(?<#{name}>#{group})?" + end + end + end.join("#{joiner}?") + "(?:|#{leader}#{combined})" + end + + # Ensure that the regular expression matches the whole URI. + regexp_string = "\\A#{regexp_string}\\z" + return expansions, Regexp.new(regexp_string) + end + + end +end diff --git a/bin/gems/addressable-2.8.7/lib/addressable/uri.rb b/bin/gems/addressable-2.8.7/lib/addressable/uri.rb new file mode 100644 index 00000000..40b80cf0 --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/uri.rb @@ -0,0 +1,2602 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/idna" +require "public_suffix" + +## +# Addressable is a library for processing links and URIs. +module Addressable + ## + # This is an implementation of a URI parser based on + # RFC 3986, + # RFC 3987. + class URI + ## + # Raised if something other than a uri is supplied. + class InvalidURIError < StandardError + end + + ## + # Container for the character classes specified in + # RFC 3986. + # + # Note: Concatenated and interpolated `String`s are not affected by the + # `frozen_string_literal` directive and must be frozen explicitly. + # + # Interpolated `String`s *were* frozen this way before Ruby 3.0: + # https://bugs.ruby-lang.org/issues/17104 + module CharacterClasses + ALPHA = "a-zA-Z" + DIGIT = "0-9" + GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@" + SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=" + RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze + UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze + RESERVED_AND_UNRESERVED = RESERVED + UNRESERVED + PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze + SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze + HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze + AUTHORITY = (PCHAR + "\\[\\]").freeze + PATH = (PCHAR + "\\/").freeze + QUERY = (PCHAR + "\\/\\?").freeze + FRAGMENT = (PCHAR + "\\/\\?").freeze + end + + module NormalizeCharacterClasses + HOST = /[^#{CharacterClasses::HOST}]/ + UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ + PCHAR = /[^#{CharacterClasses::PCHAR}]/ + SCHEME = /[^#{CharacterClasses::SCHEME}]/ + FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ + QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)} + end + + module CharacterClassesRegexps + AUTHORITY = /[^#{CharacterClasses::AUTHORITY}]/ + FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ + HOST = /[^#{CharacterClasses::HOST}]/ + PATH = /[^#{CharacterClasses::PATH}]/ + QUERY = /[^#{CharacterClasses::QUERY}]/ + RESERVED = /[^#{CharacterClasses::RESERVED}]/ + RESERVED_AND_UNRESERVED = /[^#{CharacterClasses::RESERVED_AND_UNRESERVED}]/ + SCHEME = /[^#{CharacterClasses::SCHEME}]/ + UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ + end + + SLASH = '/' + EMPTY_STR = '' + + URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ + + PORT_MAPPING = { + "http" => 80, + "https" => 443, + "ftp" => 21, + "tftp" => 69, + "sftp" => 22, + "ssh" => 22, + "svn+ssh" => 22, + "telnet" => 23, + "nntp" => 119, + "gopher" => 70, + "wais" => 210, + "ldap" => 389, + "prospero" => 1525 + }.freeze + + ## + # Returns a URI object based on the parsed string. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # + # @return [Addressable::URI] The parsed URI. + def self.parse(uri) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + # Otherwise, convert to a String + begin + uri = uri.to_str + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{uri.class} into String." + end unless uri.is_a?(String) + + # This Regexp supplied as an example in RFC 3986, and it works great. + scan = uri.scan(URIREGEX) + fragments = scan[0] + scheme = fragments[1] + authority = fragments[3] + path = fragments[4] + query = fragments[6] + fragment = fragments[8] + user = nil + password = nil + host = nil + port = nil + if authority != nil + # The Regexp above doesn't split apart the authority. + userinfo = authority[/^([^\[\]]*)@/, 1] + if userinfo != nil + user = userinfo.strip[/^([^:]*):?/, 1] + password = userinfo.strip[/:(.*)$/, 1] + end + + host = authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + + port = authority[/:([^:@\[\]]*?)$/, 1] + port = nil if port == EMPTY_STR + end + + return new( + :scheme => scheme, + :user => user, + :password => password, + :host => host, + :port => port, + :path => path, + :query => query, + :fragment => fragment + ) + end + + ## + # Converts an input to a URI. The input does not have to be a valid + # URI — the method will use heuristics to guess what URI was intended. + # This is not standards-compliant, merely user-friendly. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # @param [Hash] hints + # A Hash of hints to the heuristic parser. + # Defaults to {:scheme => "http"}. + # + # @return [Addressable::URI] The parsed URI. + def self.heuristic_parse(uri, hints={}) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + unless uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + # Otherwise, convert to a String + uri = uri.to_str.dup.strip + hints = { + :scheme => "http" + }.merge(hints) + case uri + when /^http:\//i + uri.sub!(/^http:\/+/i, "http://") + when /^https:\//i + uri.sub!(/^https:\/+/i, "https://") + when /^feed:\/+http:\//i + uri.sub!(/^feed:\/+http:\/+/i, "feed:http://") + when /^feed:\//i + uri.sub!(/^feed:\/+/i, "feed://") + when %r[^file:/{4}]i + uri.sub!(%r[^file:/+]i, "file:////") + when %r[^file://localhost/]i + uri.sub!(%r[^file://localhost/+]i, "file:///") + when %r[^file:/+]i + uri.sub!(%r[^file:/+]i, "file:///") + when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ + uri.sub!(/^/, hints[:scheme] + "://") + when /\A\d+\..*:\d+\z/ + uri = "#{hints[:scheme]}://#{uri}" + end + match = uri.match(URIREGEX) + fragments = match.captures + authority = fragments[3] + if authority && authority.length > 0 + new_authority = authority.tr("\\", "/").gsub(" ", "%20") + # NOTE: We want offset 4, not 3! + offset = match.offset(4) + uri = uri.dup + uri[offset[0]...offset[1]] = new_authority + end + parsed = self.parse(uri) + if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ + parsed = self.parse(hints[:scheme] + "://" + uri) + end + if parsed.path.include?(".") + if parsed.path[/\b@\b/] + parsed.scheme = "mailto" unless parsed.scheme + elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] + parsed.defer_validation do + new_path = parsed.path.sub( + Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR) + parsed.host = new_host + parsed.path = new_path + parsed.scheme = hints[:scheme] unless parsed.scheme + end + end + end + return parsed + end + + ## + # Converts a path to a file scheme URI. If the path supplied is + # relative, it will be returned as a relative URI. If the path supplied + # is actually a non-file URI, it will parse the URI as if it had been + # parsed with Addressable::URI.parse. Handles all of the + # various Microsoft-specific formats for specifying paths. + # + # @param [String, Addressable::URI, #to_str] path + # Typically a String path to a file or directory, but + # will return a sensible return value if an absolute URI is supplied + # instead. + # + # @return [Addressable::URI] + # The parsed file scheme URI or the original URI if some other URI + # scheme was provided. + # + # @example + # base = Addressable::URI.convert_path("/absolute/path/") + # uri = Addressable::URI.convert_path("relative/path") + # (base + uri).to_s + # #=> "file:///absolute/path/relative/path" + # + # Addressable::URI.convert_path( + # "c:\\windows\\My Documents 100%20\\foo.txt" + # ).to_s + # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" + # + # Addressable::URI.convert_path("http://example.com/").to_s + # #=> "http://example.com/" + def self.convert_path(path) + # If we were given nil, return nil. + return nil unless path + # If a URI object is passed, just return itself. + return path if path.kind_of?(self) + unless path.respond_to?(:to_str) + raise TypeError, "Can't convert #{path.class} into String." + end + # Otherwise, convert to a String + path = path.to_str.strip + + path.sub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/ + path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/ + uri = self.parse(path) + + if uri.scheme == nil + # Adjust windows-style uris + uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do + "/#{$1.downcase}:/" + end + uri.path.tr!("\\", SLASH) + if File.exist?(uri.path) && + File.stat(uri.path).directory? + uri.path.chomp!(SLASH) + uri.path = uri.path + '/' + end + + # If the path is absolute, set the scheme and host. + if uri.path.start_with?(SLASH) + uri.scheme = "file" + uri.host = EMPTY_STR + end + uri.normalize! + end + + return uri + end + + ## + # Joins several URIs together. + # + # @param [String, Addressable::URI, #to_str] *uris + # The URIs to join. + # + # @return [Addressable::URI] The joined URI. + # + # @example + # base = "http://example.com/" + # uri = Addressable::URI.parse("relative/path") + # Addressable::URI.join(base, uri) + # #=> # + def self.join(*uris) + uri_objects = uris.collect do |uri| + unless uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + uri.kind_of?(self) ? uri : self.parse(uri.to_str) + end + result = uri_objects.shift.dup + uri_objects.each do |uri| + result.join!(uri) + end + return result + end + + ## + # Tables used to optimize encoding operations in `self.encode_component` + # and `self.normalize_component` + SEQUENCE_ENCODING_TABLE = (0..255).map do |byte| + format("%02x", byte).freeze + end.freeze + + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte| + format("%%%02X", byte).freeze + end.freeze + + ## + # Percent encodes a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' through + # '9' to be percent encoded. If a Regexp is passed, the + # value /[^b-zB-Z0-9]/ would have the same effect. A set of + # useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [Regexp] upcase_encoded + # A string of characters that may already be percent encoded, and whose + # encodings should be upcased. This allows normalization of percent + # encodings for characters not included in the + # character_class. + # + # @return [String] The encoded component. + # + # @example + # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component( + # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + def self.encode_component(component, character_class=CharacterClassesRegexps::RESERVED_AND_UNRESERVED, upcase_encoded='') + return nil if component.nil? + + begin + if component.kind_of?(Symbol) || + component.kind_of?(Numeric) || + component.kind_of?(TrueClass) || + component.kind_of?(FalseClass) + component = component.to_s + else + component = component.to_str + end + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + character_class = /[^#{character_class}]/ + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + # Avoiding gsub! because there are edge cases with frozen strings + component = component.gsub(character_class) do |char| + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord] + end + if upcase_encoded.length > 0 + upcase_encoded_chars = upcase_encoded.bytes.map do |byte| + SEQUENCE_ENCODING_TABLE[byte] + end + component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/, + &:upcase) + end + + return component + end + + class << self + alias_method :escape_component, :encode_component + end + + ## + # Unencodes any percent encoded characters within a URI component. + # This method may be used for unencoding either components or full URIs, + # however, it is recommended to use the unencode_component + # alias when unencoding components. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI or component to unencode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @param [String] leave_encoded + # A string of characters to leave encoded. If a percent encoded character + # in this list is encountered then it will remain percent encoded. + # + # @return [String, Addressable::URI] + # The unencoded component or URI. + # The return type is determined by the return_type + # parameter. + def self.unencode(uri, return_type=String, leave_encoded='') + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + + result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence| + c = sequence[1..3].to_i(16).chr + c.force_encoding(sequence.encoding) + leave_encoded.include?(c) ? sequence : c + end + + result.force_encoding(Encoding::UTF_8) + if return_type == String + return result + elsif return_type == ::Addressable::URI + return ::Addressable::URI.parse(result) + end + end + + class << self + alias_method :unescape, :unencode + alias_method :unencode_component, :unencode + alias_method :unescape_component, :unencode + end + + + ## + # Normalizes the encoding of a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' + # through '9' to be percent encoded. If a Regexp is passed, + # the value /[^b-zB-Z0-9]/ would have the same effect. A + # set of useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [String] leave_encoded + # When character_class is a String then + # leave_encoded is a string of characters that should remain + # percent encoded while normalizing the component; if they appear percent + # encoded in the original component, then they will be upcased ("%2f" + # normalized to "%2F") but otherwise left alone. + # + # @return [String] The normalized component. + # + # @example + # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", /[^b-zB-Z]/ + # ) + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", + # Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + # Addressable::URI.normalize_component( + # "one%20two%2fthree%26four", + # "0-9a-zA-Z &/", + # "/" + # ) + # => "one two%2Fthree&four" + def self.normalize_component(component, character_class= + CharacterClassesRegexps::RESERVED_AND_UNRESERVED, + leave_encoded='') + return nil if component.nil? + + begin + component = component.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + leave_re = if leave_encoded.length > 0 + character_class = "#{character_class}%" unless character_class.include?('%') + + bytes = leave_encoded.bytes + leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|') + "|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})" + end + + character_class = if leave_re + /[^#{character_class}]#{leave_re}/ + else + /[^#{character_class}]/ + end + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + unencoded = self.unencode_component(component, String, leave_encoded) + begin + encoded = self.encode_component( + unencoded.unicode_normalize(:nfc), + character_class, + leave_encoded + ) + rescue ArgumentError + encoded = self.encode_component(unencoded) + end + encoded.force_encoding(Encoding::UTF_8) + return encoded + end + + ## + # Percent encodes any special characters in the URI. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.encode(uri, return_type=String) + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(uri_object.scheme, + Addressable::URI::CharacterClassesRegexps::SCHEME), + :authority => self.encode_component(uri_object.authority, + Addressable::URI::CharacterClassesRegexps::AUTHORITY), + :path => self.encode_component(uri_object.path, + Addressable::URI::CharacterClassesRegexps::PATH), + :query => self.encode_component(uri_object.query, + Addressable::URI::CharacterClassesRegexps::QUERY), + :fragment => self.encode_component(uri_object.fragment, + Addressable::URI::CharacterClassesRegexps::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + class << self + alias_method :escape, :encode + end + + ## + # Normalizes the encoding of a URI. Characters within a hostname are + # not percent encoded to allow for internationalized domain names. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.normalized_encode(uri, return_type=String) + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + components = { + :scheme => self.unencode_component(uri_object.scheme), + :user => self.unencode_component(uri_object.user), + :password => self.unencode_component(uri_object.password), + :host => self.unencode_component(uri_object.host), + :port => (uri_object.port.nil? ? nil : uri_object.port.to_s), + :path => self.unencode_component(uri_object.path), + :query => self.unencode_component(uri_object.query), + :fragment => self.unencode_component(uri_object.fragment) + } + components.each do |key, value| + if value != nil + begin + components[key] = value.to_str.unicode_normalize(:nfc) + rescue ArgumentError + # Likely a malformed UTF-8 character, skip unicode normalization + components[key] = value.to_str + end + end + end + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(components[:scheme], + Addressable::URI::CharacterClassesRegexps::SCHEME), + :user => self.encode_component(components[:user], + Addressable::URI::CharacterClassesRegexps::UNRESERVED), + :password => self.encode_component(components[:password], + Addressable::URI::CharacterClassesRegexps::UNRESERVED), + :host => components[:host], + :port => components[:port], + :path => self.encode_component(components[:path], + Addressable::URI::CharacterClassesRegexps::PATH), + :query => self.encode_component(components[:query], + Addressable::URI::CharacterClassesRegexps::QUERY), + :fragment => self.encode_component(components[:fragment], + Addressable::URI::CharacterClassesRegexps::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + ## + # Encodes a set of key/value pairs according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [#to_hash, #to_ary] form_values + # The form values to encode. + # + # @param [TrueClass, FalseClass] sort + # Sort the key/value pairs prior to encoding. + # Defaults to false. + # + # @return [String] + # The encoded value. + def self.form_encode(form_values, sort=false) + if form_values.respond_to?(:to_hash) + form_values = form_values.to_hash.to_a + elsif form_values.respond_to?(:to_ary) + form_values = form_values.to_ary + else + raise TypeError, "Can't convert #{form_values.class} into Array." + end + + form_values = form_values.inject([]) do |accu, (key, value)| + if value.kind_of?(Array) + value.each do |v| + accu << [key.to_s, v.to_s] + end + else + accu << [key.to_s, value.to_s] + end + accu + end + + if sort + # Useful for OAuth and optimizing caching systems + form_values = form_values.sort + end + escaped_form_values = form_values.map do |(key, value)| + # Line breaks are CRLF pairs + [ + self.encode_component( + key.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClassesRegexps::UNRESERVED + ).gsub("%20", "+"), + self.encode_component( + value.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClassesRegexps::UNRESERVED + ).gsub("%20", "+") + ] + end + return escaped_form_values.map do |(key, value)| + "#{key}=#{value}" + end.join("&") + end + + ## + # Decodes a String according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [String, #to_str] encoded_value + # The form values to decode. + # + # @return [Array] + # The decoded values. + # This is not a Hash because of the possibility for + # duplicate keys. + def self.form_unencode(encoded_value) + if !encoded_value.respond_to?(:to_str) + raise TypeError, "Can't convert #{encoded_value.class} into String." + end + encoded_value = encoded_value.to_str + split_values = encoded_value.split("&").map do |pair| + pair.split("=", 2) + end + return split_values.map do |(key, value)| + [ + key ? self.unencode_component( + key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil, + value ? (self.unencode_component( + value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil + ] + end + end + + ## + # Creates a new uri object from component parts. + # + # @option [String, #to_str] scheme The scheme component. + # @option [String, #to_str] user The user component. + # @option [String, #to_str] password The password component. + # @option [String, #to_str] userinfo + # The userinfo component. If this is supplied, the user and password + # components must be omitted. + # @option [String, #to_str] host The host component. + # @option [String, #to_str] port The port component. + # @option [String, #to_str] authority + # The authority component. If this is supplied, the user, password, + # userinfo, host, and port components must be omitted. + # @option [String, #to_str] path The path component. + # @option [String, #to_str] query The query component. + # @option [String, #to_str] fragment The fragment component. + # + # @return [Addressable::URI] The constructed URI object. + def initialize(options={}) + if options.has_key?(:authority) + if (options.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if options.has_key?(:userinfo) + if (options.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + reset_ivs + + defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + self.scheme = options[:scheme] if options[:scheme] + self.user = options[:user] if options[:user] + self.password = options[:password] if options[:password] + self.userinfo = options[:userinfo] if options[:userinfo] + self.host = options[:host] if options[:host] + self.port = options[:port] if options[:port] + self.authority = options[:authority] if options[:authority] + self.path = options[:path] if options[:path] + self.query = options[:query] if options[:query] + self.query_values = options[:query_values] if options[:query_values] + self.fragment = options[:fragment] if options[:fragment] + end + + to_s # force path validation + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.normalized_scheme + self.normalized_user + self.normalized_password + self.normalized_userinfo + self.normalized_host + self.normalized_port + self.normalized_authority + self.normalized_site + self.normalized_path + self.normalized_query + self.normalized_fragment + self.hash + super + end + + ## + # The scheme component for this URI. + # + # @return [String] The scheme component. + attr_reader :scheme + + ## + # The scheme component for this URI, normalized. + # + # @return [String] The scheme component, normalized. + def normalized_scheme + return nil unless self.scheme + if @normalized_scheme == NONE + @normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i + "svn+ssh".dup + else + Addressable::URI.normalize_component( + self.scheme.strip.downcase, + Addressable::URI::NormalizeCharacterClasses::SCHEME + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_scheme) + @normalized_scheme + end + + ## + # Sets the scheme component for this URI. + # + # @param [String, #to_str] new_scheme The new scheme component. + def scheme=(new_scheme) + if new_scheme && !new_scheme.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_scheme.class} into String." + elsif new_scheme + new_scheme = new_scheme.to_str + end + if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i + raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'" + end + @scheme = new_scheme + @scheme = nil if @scheme.to_s.strip.empty? + + # Reset dependent values + @normalized_scheme = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The user component for this URI. + # + # @return [String] The user component. + attr_reader :user + + ## + # The user component for this URI, normalized. + # + # @return [String] The user component, normalized. + def normalized_user + return nil unless self.user + return @normalized_user unless @normalized_user == NONE + @normalized_user = begin + if normalized_scheme =~ /https?/ && self.user.strip.empty? && + (!self.password || self.password.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.user.strip, + Addressable::URI::NormalizeCharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_user) + @normalized_user + end + + ## + # Sets the user component for this URI. + # + # @param [String, #to_str] new_user The new user component. + def user=(new_user) + if new_user && !new_user.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_user.class} into String." + end + @user = new_user ? new_user.to_str : nil + + # You can't have a nil user with a non-nil password + if password != nil + @user = EMPTY_STR unless user + end + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_user = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The password component for this URI. + # + # @return [String] The password component. + attr_reader :password + + ## + # The password component for this URI, normalized. + # + # @return [String] The password component, normalized. + def normalized_password + return nil unless self.password + return @normalized_password unless @normalized_password == NONE + @normalized_password = begin + if self.normalized_scheme =~ /https?/ && self.password.strip.empty? && + (!self.user || self.user.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.password.strip, + Addressable::URI::NormalizeCharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_password) + @normalized_password + end + + ## + # Sets the password component for this URI. + # + # @param [String, #to_str] new_password The new password component. + def password=(new_password) + if new_password && !new_password.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_password.class} into String." + end + @password = new_password ? new_password.to_str : nil + + # You can't have a nil user with a non-nil password + if @password != nil + self.user = EMPTY_STR if user.nil? + end + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_password = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The userinfo component for this URI. + # Combines the user and password components. + # + # @return [String] The userinfo component. + def userinfo + current_user = self.user + current_password = self.password + (current_user || current_password) && @userinfo ||= begin + if current_user && current_password + "#{current_user}:#{current_password}" + elsif current_user && !current_password + "#{current_user}" + end + end + end + + ## + # The userinfo component for this URI, normalized. + # + # @return [String] The userinfo component, normalized. + def normalized_userinfo + return nil unless self.userinfo + return @normalized_userinfo unless @normalized_userinfo == NONE + @normalized_userinfo = begin + current_user = self.normalized_user + current_password = self.normalized_password + if !current_user && !current_password + nil + elsif current_user && current_password + "#{current_user}:#{current_password}".dup + elsif current_user && !current_password + "#{current_user}".dup + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_userinfo) + @normalized_userinfo + end + + ## + # Sets the userinfo component for this URI. + # + # @param [String, #to_str] new_userinfo The new userinfo component. + def userinfo=(new_userinfo) + if new_userinfo && !new_userinfo.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_userinfo.class} into String." + end + new_user, new_password = if new_userinfo + [ + new_userinfo.to_str.strip[/^(.*):/, 1], + new_userinfo.to_str.strip[/:(.*)$/, 1] + ] + else + [nil, nil] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + + # Reset dependent values + @authority = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The host component for this URI. + # + # @return [String] The host component. + attr_reader :host + + ## + # The host component for this URI, normalized. + # + # @return [String] The host component, normalized. + def normalized_host + return nil unless self.host + + @normalized_host ||= begin + if !self.host.strip.empty? + result = ::Addressable::IDNA.to_ascii( + URI.unencode_component(self.host.strip.downcase) + ) + if result =~ /[^\.]\.$/ + # Single trailing dots are unnecessary. + result = result[0...-1] + end + result = Addressable::URI.normalize_component( + result, + NormalizeCharacterClasses::HOST + ) + result + else + EMPTY_STR.dup + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_host) + @normalized_host + end + + ## + # Sets the host component for this URI. + # + # @param [String, #to_str] new_host The new host component. + def host=(new_host) + if new_host && !new_host.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_host.class} into String." + end + @host = new_host ? new_host.to_str : nil + + # Reset dependent values + @authority = nil + @normalized_host = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # This method is same as URI::Generic#host except + # brackets for IPv6 (and 'IPvFuture') addresses are removed. + # + # @see Addressable::URI#host + # + # @return [String] The hostname for this URI. + def hostname + v = self.host + /\A\[(.*)\]\z/ =~ v ? $1 : v + end + + ## + # This method is same as URI::Generic#host= except + # the argument can be a bare IPv6 address (or 'IPvFuture'). + # + # @see Addressable::URI#host= + # + # @param [String, #to_str] new_hostname The new hostname for this URI. + def hostname=(new_hostname) + if new_hostname && + (new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?)) + new_hostname = new_hostname.to_s + elsif new_hostname && !new_hostname.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_hostname.class} into String." + end + v = new_hostname ? new_hostname.to_str : nil + v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v + self.host = v + end + + ## + # Returns the top-level domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk" + def tld + PublicSuffix.parse(self.host, ignore_private: true).tld + end + + ## + # Sets the top-level domain for this URI. + # + # @param [String, #to_str] new_tld The new top-level domain. + def tld=(new_tld) + replaced_tld = host.sub(/#{tld}\z/, new_tld) + self.host = PublicSuffix::Domain.new(replaced_tld).to_s + end + + ## + # Returns the public suffix domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk" + def domain + PublicSuffix.domain(self.host, ignore_private: true) + end + + ## + # The authority component for this URI. + # Combines the user, password, host, and port components. + # + # @return [String] The authority component. + def authority + self.host && @authority ||= begin + authority = String.new + if self.userinfo != nil + authority << "#{self.userinfo}@" + end + authority << self.host + if self.port != nil + authority << ":#{self.port}" + end + authority + end + end + + ## + # The authority component for this URI, normalized. + # + # @return [String] The authority component, normalized. + def normalized_authority + return nil unless self.authority + @normalized_authority ||= begin + authority = String.new + if self.normalized_userinfo != nil + authority << "#{self.normalized_userinfo}@" + end + authority << self.normalized_host + if self.normalized_port != nil + authority << ":#{self.normalized_port}" + end + authority + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_authority) + @normalized_authority + end + + ## + # Sets the authority component for this URI. + # + # @param [String, #to_str] new_authority The new authority component. + def authority=(new_authority) + if new_authority + if !new_authority.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_authority.class} into String." + end + new_authority = new_authority.to_str + new_userinfo = new_authority[/^([^\[\]]*)@/, 1] + if new_userinfo + new_user = new_userinfo.strip[/^([^:]*):?/, 1] + new_password = new_userinfo.strip[/:(.*)$/, 1] + end + new_host = new_authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + new_port = + new_authority[/:([^:@\[\]]*?)$/, 1] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + self.host = new_host + self.port = new_port + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. + # + # @return [String] The serialized origin. + def origin + if self.scheme && self.authority + if self.normalized_port + "#{self.normalized_scheme}://#{self.normalized_host}" + + ":#{self.normalized_port}" + else + "#{self.normalized_scheme}://#{self.normalized_host}" + end + else + "null" + end + end + + ## + # Sets the origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. This assignment will reset the `userinfo` + # component. + # + # @param [String, #to_str] new_origin The new origin component. + def origin=(new_origin) + if new_origin + if !new_origin.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_origin.class} into String." + end + new_origin = new_origin.to_str + new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1] + unless new_scheme + raise InvalidURIError, 'An origin cannot omit the scheme.' + end + new_host = new_origin[/:\/\/([^\/?#:]+)/, 1] + unless new_host + raise InvalidURIError, 'An origin cannot omit the host.' + end + new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1] + end + + self.scheme = new_scheme + self.host = new_host + self.port = new_port + self.userinfo = nil + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_authority = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + # Returns an array of known ip-based schemes. These schemes typically + # use a similar URI form: + # //:@:/ + def self.ip_based_schemes + return self.port_mapping.keys + end + + # Returns a hash of common IP-based schemes and their default port + # numbers. Adding new schemes to this hash, as necessary, will allow + # for better URI normalization. + def self.port_mapping + PORT_MAPPING + end + + ## + # The port component for this URI. + # This is the port number actually given in the URI. This does not + # infer port numbers from default values. + # + # @return [Integer] The port component. + attr_reader :port + + ## + # The port component for this URI, normalized. + # + # @return [Integer] The port component, normalized. + def normalized_port + return nil unless self.port + return @normalized_port unless @normalized_port == NONE + @normalized_port = begin + if URI.port_mapping[self.normalized_scheme] == self.port + nil + else + self.port + end + end + end + + ## + # Sets the port component for this URI. + # + # @param [String, Integer, #to_s] new_port The new port component. + def port=(new_port) + if new_port != nil && new_port.respond_to?(:to_str) + new_port = Addressable::URI.unencode_component(new_port.to_str) + end + + if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding? + raise InvalidURIError, "Invalid encoding in port" + end + + if new_port != nil && !(new_port.to_s =~ /^\d+$/) + raise InvalidURIError, + "Invalid port number: #{new_port.inspect}" + end + + @port = new_port.to_s.to_i + @port = nil if @port == 0 + + # Reset dependent values + @authority = nil + @normalized_port = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The inferred port component for this URI. + # This method will normalize to the default port for the URI's scheme if + # the port isn't explicitly specified in the URI. + # + # @return [Integer] The inferred port component. + def inferred_port + if self.port.to_i == 0 + self.default_port + else + self.port.to_i + end + end + + ## + # The default port for this URI's scheme. + # This method will always returns the default port for the URI's scheme + # regardless of the presence of an explicit port in the URI. + # + # @return [Integer] The default port. + def default_port + URI.port_mapping[self.scheme.strip.downcase] if self.scheme + end + + ## + # The combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The components that identify a site. + def site + (self.scheme || self.authority) && @site ||= begin + site_string = "".dup + site_string << "#{self.scheme}:" if self.scheme != nil + site_string << "//#{self.authority}" if self.authority != nil + site_string + end + end + + ## + # The normalized combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The normalized components that identify a site. + def normalized_site + return nil unless self.site + @normalized_site ||= begin + site_string = "".dup + if self.normalized_scheme != nil + site_string << "#{self.normalized_scheme}:" + end + if self.normalized_authority != nil + site_string << "//#{self.normalized_authority}" + end + site_string + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_site) + @normalized_site + end + + ## + # Sets the site value for this URI. + # + # @param [String, #to_str] new_site The new site value. + def site=(new_site) + if new_site + if !new_site.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_site.class} into String." + end + new_site = new_site.to_str + # These two regular expressions derived from the primary parsing + # expression + self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1] + self.authority = new_site[ + /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1 + ] + else + self.scheme = nil + self.authority = nil + end + end + + ## + # The path component for this URI. + # + # @return [String] The path component. + attr_reader :path + + NORMPATH = /^(?!\/)[^\/:]*:.*$/ + ## + # The path component for this URI, normalized. + # + # @return [String] The path component, normalized. + def normalized_path + @normalized_path ||= begin + path = self.path.to_s + if self.scheme == nil && path =~ NORMPATH + # Relative paths with colons in the first segment are ambiguous. + path = path.sub(":", "%2F") + end + # String#split(delimiter, -1) uses the more strict splitting behavior + # found by default in Python. + result = path.strip.split(SLASH, -1).map do |segment| + Addressable::URI.normalize_component( + segment, + Addressable::URI::NormalizeCharacterClasses::PCHAR + ) + end.join(SLASH) + + result = URI.normalize_path(result) + if result.empty? && + ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) + result = SLASH.dup + end + result + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_path) + @normalized_path + end + + ## + # Sets the path component for this URI. + # + # @param [String, #to_str] new_path The new path component. + def path=(new_path) + if new_path && !new_path.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_path.class} into String." + end + @path = (new_path || EMPTY_STR).to_str + if !@path.empty? && @path[0..0] != SLASH && host != nil + @path = "/#{@path}" + end + + # Reset dependent values + @normalized_path = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The basename, if any, of the file in the path component. + # + # @return [String] The path's basename. + def basename + # Path cannot be nil + return File.basename(self.path).sub(/;[^\/]*$/, EMPTY_STR) + end + + ## + # The extname, if any, of the file in the path component. + # Empty string if there is no extension. + # + # @return [String] The path's extname. + def extname + return nil unless self.path + return File.extname(self.basename) + end + + ## + # The query component for this URI. + # + # @return [String] The query component. + attr_reader :query + + ## + # The query component for this URI, normalized. + # + # @return [String] The query component, normalized. + def normalized_query(*flags) + return nil unless self.query + return @normalized_query unless @normalized_query == NONE + @normalized_query = begin + modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup + # Make sure possible key-value pair delimiters are escaped. + modified_query_class.sub!("\\&", "").sub!("\\;", "") + pairs = (query || "").split("&", -1) + pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted) + pairs.sort! if flags.include?(:sorted) + component = pairs.map do |pair| + Addressable::URI.normalize_component( + pair, + Addressable::URI::NormalizeCharacterClasses::QUERY, + "+" + ) + end.join("&") + component == "" ? nil : component + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_query) + @normalized_query + end + + ## + # Sets the query component for this URI. + # + # @param [String, #to_str] new_query The new query component. + def query=(new_query) + if new_query && !new_query.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_query.class} into String." + end + @query = new_query ? new_query.to_str : nil + + # Reset dependent values + @normalized_query = NONE + remove_composite_values + end + + ## + # Converts the query component to a Hash value. + # + # @param [Class] return_type The return type desired. Value must be either + # `Hash` or `Array`. + # + # @return [Hash, Array, nil] The query string parsed as a Hash or Array + # or nil if the query string is blank. + # + # @example + # Addressable::URI.parse("?one=1&two=2&three=3").query_values + # #=> {"one" => "1", "two" => "2", "three" => "3"} + # Addressable::URI.parse("?one=two&one=three").query_values(Array) + # #=> [["one", "two"], ["one", "three"]] + # Addressable::URI.parse("?one=two&one=three").query_values(Hash) + # #=> {"one" => "three"} + # Addressable::URI.parse("?").query_values + # #=> {} + # Addressable::URI.parse("").query_values + # #=> nil + def query_values(return_type=Hash) + empty_accumulator = Array == return_type ? [] : {} + if return_type != Hash && return_type != Array + raise ArgumentError, "Invalid return type. Must be Hash or Array." + end + return nil if self.query == nil + split_query = self.query.split("&").map do |pair| + pair.split("=", 2) if pair && !pair.empty? + end.compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + # I'd rather use key/value identifiers instead of array lookups, + # but in this case I really want to maintain the exact pair structure, + # so it's best to make all changes in-place. + pair[0] = URI.unencode_component(pair[0]) + if pair[1].respond_to?(:to_str) + value = pair[1].to_str + # I loathe the fact that I have to do this. Stupid HTML 4.01. + # Treating '+' as a space was just an unbelievably bad idea. + # There was nothing wrong with '%20'! + # If it ain't broke, don't fix it! + value = value.tr("+", " ") if ["http", "https", nil].include?(scheme) + pair[1] = URI.unencode_component(value) + end + if return_type == Hash + accu[pair[0]] = pair[1] + else + accu << pair + end + accu + end + end + + ## + # Sets the query component for this URI from a Hash object. + # An empty Hash or Array will result in an empty query string. + # + # @param [Hash, #to_hash, Array] new_query_values The new query values. + # + # @example + # uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['flag'], ['key', 'value']] + # uri.query + # # => "flag&key=value" + def query_values=(new_query_values) + if new_query_values == nil + self.query = nil + return nil + end + + if !new_query_values.is_a?(Array) + if !new_query_values.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{new_query_values.class} into Hash." + end + new_query_values = new_query_values.to_hash + new_query_values = new_query_values.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + new_query_values.sort! + end + + # new_query_values have form [['key1', 'value1'], ['key2', 'value2']] + buffer = "".dup + new_query_values.each do |key, value| + encoded_key = URI.encode_component( + key, CharacterClassesRegexps::UNRESERVED + ) + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = URI.encode_component( + sub_value, CharacterClassesRegexps::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = URI.encode_component( + value, CharacterClassesRegexps::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + self.query = buffer.chop + end + + ## + # The HTTP request URI for this URI. This is the path and the + # query string. + # + # @return [String] The request URI required for an HTTP request. + def request_uri + return nil if self.absolute? && self.scheme !~ /^https?$/i + return ( + (!self.path.empty? ? self.path : SLASH) + + (self.query ? "?#{self.query}" : EMPTY_STR) + ) + end + + ## + # Sets the HTTP request URI for this URI. + # + # @param [String, #to_str] new_request_uri The new HTTP request URI. + def request_uri=(new_request_uri) + if !new_request_uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_request_uri.class} into String." + end + if self.absolute? && self.scheme !~ /^https?$/i + raise InvalidURIError, + "Cannot set an HTTP request URI for a non-HTTP URI." + end + new_request_uri = new_request_uri.to_str + path_component = new_request_uri[/^([^\?]*)\??(?:.*)$/, 1] + query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] + path_component = path_component.to_s + path_component = (!path_component.empty? ? path_component : SLASH) + self.path = path_component + self.query = query_component + + # Reset dependent values + remove_composite_values + end + + ## + # The fragment component for this URI. + # + # @return [String] The fragment component. + attr_reader :fragment + + ## + # The fragment component for this URI, normalized. + # + # @return [String] The fragment component, normalized. + def normalized_fragment + return nil unless self.fragment + return @normalized_fragment unless @normalized_fragment == NONE + @normalized_fragment = begin + component = Addressable::URI.normalize_component( + self.fragment, + Addressable::URI::NormalizeCharacterClasses::FRAGMENT + ) + component == "" ? nil : component + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_fragment) + @normalized_fragment + end + + ## + # Sets the fragment component for this URI. + # + # @param [String, #to_str] new_fragment The new fragment component. + def fragment=(new_fragment) + if new_fragment && !new_fragment.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_fragment.class} into String." + end + @fragment = new_fragment ? new_fragment.to_str : nil + + # Reset dependent values + @normalized_fragment = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # Determines if the scheme indicates an IP-based protocol. + # + # @return [TrueClass, FalseClass] + # true if the scheme indicates an IP-based protocol. + # false otherwise. + def ip_based? + if self.scheme + return URI.ip_based_schemes.include?( + self.scheme.strip.downcase) + end + return false + end + + ## + # Determines if the URI is relative. + # + # @return [TrueClass, FalseClass] + # true if the URI is relative. false + # otherwise. + def relative? + return self.scheme.nil? + end + + ## + # Determines if the URI is absolute. + # + # @return [TrueClass, FalseClass] + # true if the URI is absolute. false + # otherwise. + def absolute? + return !relative? + end + + ## + # Joins two URIs together. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + def join(uri) + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + if !uri.kind_of?(URI) + # Otherwise, convert to a String, then parse. + uri = URI.parse(uri.to_str) + end + if uri.to_s.empty? + return self.dup + end + + joined_scheme = nil + joined_user = nil + joined_password = nil + joined_host = nil + joined_port = nil + joined_path = nil + joined_query = nil + joined_fragment = nil + + # Section 5.2.2 of RFC 3986 + if uri.scheme != nil + joined_scheme = uri.scheme + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.authority != nil + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.path == nil || uri.path.empty? + joined_path = self.path + if uri.query != nil + joined_query = uri.query + else + joined_query = self.query + end + else + if uri.path[0..0] == SLASH + joined_path = URI.normalize_path(uri.path) + else + base_path = self.path.dup + base_path = EMPTY_STR if base_path == nil + base_path = URI.normalize_path(base_path) + + # Section 5.2.3 of RFC 3986 + # + # Removes the right-most path segment from the base path. + if base_path.include?(SLASH) + base_path.sub!(/\/[^\/]+$/, SLASH) + else + base_path = EMPTY_STR + end + + # If the base path is empty and an authority segment has been + # defined, use a base path of SLASH + if base_path.empty? && self.authority != nil + base_path = SLASH + end + + joined_path = URI.normalize_path(base_path + uri.path) + end + joined_query = uri.query + end + joined_user = self.user + joined_password = self.password + joined_host = self.host + joined_port = self.port + end + joined_scheme = self.scheme + end + joined_fragment = uri.fragment + + return self.class.new( + :scheme => joined_scheme, + :user => joined_user, + :password => joined_password, + :host => joined_host, + :port => joined_port, + :path => joined_path, + :query => joined_query, + :fragment => joined_fragment + ) + end + alias_method :+, :join + + ## + # Destructive form of join. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + # + # @see Addressable::URI#join + def join!(uri) + replace_self(self.join(uri)) + end + + ## + # Merges a URI with a Hash of components. + # This method has different behavior from join. Any + # components present in the hash parameter will override the + # original components. The path component is not treated specially. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Hash#merge + def merge(hash) + unless hash.respond_to?(:to_hash) + raise TypeError, "Can't convert #{hash.class} into Hash." + end + hash = hash.to_hash + + if hash.has_key?(:authority) + if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if hash.has_key?(:userinfo) + if (hash.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + uri = self.class.new + uri.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + uri.scheme = + hash.has_key?(:scheme) ? hash[:scheme] : self.scheme + if hash.has_key?(:authority) + uri.authority = + hash.has_key?(:authority) ? hash[:authority] : self.authority + end + if hash.has_key?(:userinfo) + uri.userinfo = + hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo + end + if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) + uri.user = + hash.has_key?(:user) ? hash[:user] : self.user + uri.password = + hash.has_key?(:password) ? hash[:password] : self.password + end + if !hash.has_key?(:authority) + uri.host = + hash.has_key?(:host) ? hash[:host] : self.host + uri.port = + hash.has_key?(:port) ? hash[:port] : self.port + end + uri.path = + hash.has_key?(:path) ? hash[:path] : self.path + uri.query = + hash.has_key?(:query) ? hash[:query] : self.query + uri.fragment = + hash.has_key?(:fragment) ? hash[:fragment] : self.fragment + end + + return uri + end + + ## + # Destructive form of merge. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Addressable::URI#merge + def merge!(uri) + replace_self(self.merge(uri)) + end + + ## + # Returns the shortest normalized relative form of this URI that uses the + # supplied URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_to. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route from. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the original URI. + def route_from(uri) + uri = URI.parse(uri).normalize + normalized_self = self.normalize + if normalized_self.relative? + raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" + end + if uri.relative? + raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" + end + if normalized_self == uri + return Addressable::URI.parse("##{normalized_self.fragment}") + end + components = normalized_self.to_hash + if normalized_self.scheme == uri.scheme + components[:scheme] = nil + if normalized_self.authority == uri.authority + components[:user] = nil + components[:password] = nil + components[:host] = nil + components[:port] = nil + if normalized_self.path == uri.path + components[:path] = nil + if normalized_self.query == uri.query + components[:query] = nil + end + else + if uri.path != SLASH and components[:path] + self_splitted_path = split_path(components[:path]) + uri_splitted_path = split_path(uri.path) + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + end + components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH) + end + end + end + end + # Avoid network-path references. + if components[:host] != nil + components[:scheme] = normalized_self.scheme + end + return Addressable::URI.new( + :scheme => components[:scheme], + :user => components[:user], + :password => components[:password], + :host => components[:host], + :port => components[:port], + :path => components[:path], + :query => components[:query], + :fragment => components[:fragment] + ) + end + + ## + # Returns the shortest normalized relative form of the supplied URI that + # uses this URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_from. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route to. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the supplied URI. + def route_to(uri) + return URI.parse(uri).route_from(self) + end + + ## + # Returns a normalized URI object. + # + # NOTE: This method does not attempt to fully conform to specifications. + # It exists largely to correct other people's failures to read the + # specifications, and also to deal with caching issues since several + # different URIs may represent the same resource and should not be + # cached multiple times. + # + # @return [Addressable::URI] The normalized URI. + def normalize + # This is a special exception for the frequently misused feed + # URI scheme. + if normalized_scheme == "feed" + if self.to_s =~ /^feed:\/*http:\/*/ + return URI.parse( + self.to_s[/^feed:\/*(http:\/*.*)/, 1] + ).normalize + end + end + + return self.class.new( + :scheme => normalized_scheme, + :authority => normalized_authority, + :path => normalized_path, + :query => normalized_query, + :fragment => normalized_fragment + ) + end + + ## + # Destructively normalizes this URI object. + # + # @return [Addressable::URI] The normalized URI. + # + # @see Addressable::URI#normalize + def normalize! + replace_self(self.normalize) + end + + ## + # Creates a URI suitable for display to users. If semantic attacks are + # likely, the application should try to detect these and warn the user. + # See RFC 3986, + # section 7.6 for more information. + # + # @return [Addressable::URI] A URI suitable for display purposes. + def display_uri + display_uri = self.normalize + display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) + return display_uri + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison, and allows comparison + # against Strings. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ===(uri) + if uri.respond_to?(:normalize) + uri_string = uri.normalize.to_s + else + begin + uri_string = ::Addressable::URI.parse(uri).normalize.to_s + rescue InvalidURIError, TypeError + return false + end + end + return self.normalize.to_s == uri_string + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ==(uri) + return false unless uri.kind_of?(URI) + return self.normalize.to_s == uri.normalize.to_s + end + + ## + # Returns true if the URI objects are equal. This method + # does NOT normalize either URI before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def eql?(uri) + return false unless uri.kind_of?(URI) + return self.to_s == uri.to_s + end + + ## + # A hash value that will make a URI equivalent to its normalized + # form. + # + # @return [Integer] A hash of the URI. + def hash + @hash ||= self.to_s.hash * -1 + end + + ## + # Clones the URI object. + # + # @return [Addressable::URI] The cloned URI. + def dup + duplicated_uri = self.class.new( + :scheme => self.scheme ? self.scheme.dup : nil, + :user => self.user ? self.user.dup : nil, + :password => self.password ? self.password.dup : nil, + :host => self.host ? self.host.dup : nil, + :port => self.port, + :path => self.path ? self.path.dup : nil, + :query => self.query ? self.query.dup : nil, + :fragment => self.fragment ? self.fragment.dup : nil + ) + return duplicated_uri + end + + ## + # Omits components from a URI. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @example + # uri = Addressable::URI.parse("http://example.com/path?query") + # #=> # + # uri.omit(:scheme, :authority) + # #=> # + def omit(*components) + invalid_components = components - [ + :scheme, :user, :password, :userinfo, :host, :port, :authority, + :path, :query, :fragment + ] + unless invalid_components.empty? + raise ArgumentError, + "Invalid component names: #{invalid_components.inspect}." + end + duplicated_uri = self.dup + duplicated_uri.defer_validation do + components.each do |component| + duplicated_uri.send((component.to_s + "=").to_sym, nil) + end + duplicated_uri.user = duplicated_uri.normalized_user + end + duplicated_uri + end + + ## + # Destructive form of omit. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @see Addressable::URI#omit + def omit!(*components) + replace_self(self.omit(*components)) + end + + ## + # Determines if the URI is an empty string. + # + # @return [TrueClass, FalseClass] + # Returns true if empty, false otherwise. + def empty? + return self.to_s.empty? + end + + ## + # Converts the URI to a String. + # + # @return [String] The URI's String representation. + def to_s + if self.scheme == nil && self.path != nil && !self.path.empty? && + self.path =~ NORMPATH + raise InvalidURIError, + "Cannot assemble URI string with ambiguous path: '#{self.path}'" + end + @uri_string ||= begin + uri_string = String.new + uri_string << "#{self.scheme}:" if self.scheme != nil + uri_string << "//#{self.authority}" if self.authority != nil + uri_string << self.path.to_s + uri_string << "?#{self.query}" if self.query != nil + uri_string << "##{self.fragment}" if self.fragment != nil + uri_string.force_encoding(Encoding::UTF_8) + uri_string + end + end + + ## + # URI's are glorified Strings. Allow implicit conversion. + alias_method :to_str, :to_s + + ## + # Returns a Hash of the URI components. + # + # @return [Hash] The URI as a Hash of components. + def to_hash + return { + :scheme => self.scheme, + :user => self.user, + :password => self.password, + :host => self.host, + :port => self.port, + :path => self.path, + :query => self.query, + :fragment => self.fragment + } + end + + ## + # Returns a String representation of the URI object's state. + # + # @return [String] The URI object's state, as a String. + def inspect + sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s) + end + + ## + # This method allows you to make several changes to a URI simultaneously, + # which separately would cause validation errors, but in conjunction, + # are valid. The URI will be revalidated as soon as the entire block has + # been executed. + # + # @param [Proc] block + # A set of operations to perform on a given URI. + def defer_validation + raise LocalJumpError, "No block given." unless block_given? + @validation_deferred = true + yield + @validation_deferred = false + validate + ensure + @validation_deferred = false + end + + def encode_with(coder) + instance_variables.each do |ivar| + value = instance_variable_get(ivar) + if value != NONE + key = ivar.to_s.slice(1..-1) + coder[key] = value + end + end + nil + end + + def init_with(coder) + reset_ivs + coder.map.each do |key, value| + instance_variable_set("@#{key}", value) + end + nil + end + + protected + SELF_REF = '.' + PARENT = '..' + + RULE_2A = /\/\.\/|\/\.$/ + RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/ + RULE_2D = /^\.\.?\/?/ + RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/ + + ## + # Resolves paths to their simplest form. + # + # @param [String] path The path to normalize. + # + # @return [String] The normalized path. + def self.normalize_path(path) + # Section 5.2.4 of RFC 3986 + + return if path.nil? + normalized_path = path.dup + loop do + mod ||= normalized_path.gsub!(RULE_2A, SLASH) + + pair = normalized_path.match(RULE_2B_2C) + if pair + parent = pair[1] + current = pair[2] + else + parent = nil + current = nil + end + + regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|" + regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)" + + if pair && ((parent != SELF_REF && parent != PARENT) || + (current != SELF_REF && current != PARENT)) + mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH) + end + + mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR) + # Non-standard, removes prefixed dotted segments from path. + mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH) + break if mod.nil? + end + + normalized_path + end + + ## + # Ensures that the URI is valid. + def validate + return if !!@validation_deferred + if self.scheme != nil && self.ip_based? && + (self.host == nil || self.host.empty?) && + (self.path == nil || self.path.empty?) + raise InvalidURIError, + "Absolute URI missing hierarchical segment: '#{self.to_s}'" + end + if self.host == nil + if self.port != nil || + self.user != nil || + self.password != nil + raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" + end + end + if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH && + self.authority != nil + raise InvalidURIError, + "Cannot have a relative path with an authority set: '#{self.to_s}'" + end + if self.path != nil && !self.path.empty? && + self.path[0..1] == SLASH + SLASH && self.authority == nil + raise InvalidURIError, + "Cannot have a path with two leading slashes " + + "without an authority set: '#{self.to_s}'" + end + unreserved = CharacterClasses::UNRESERVED + sub_delims = CharacterClasses::SUB_DELIMS + if !self.host.nil? && (self.host =~ /[<>{}\/\\\?\#\@"[[:space:]]]/ || + (self.host[/^\[(.*)\]$/, 1] != nil && self.host[/^\[(.*)\]$/, 1] !~ + Regexp.new("^[#{unreserved}#{sub_delims}:]*$"))) + raise InvalidURIError, "Invalid character in host: '#{self.host.to_s}'" + end + return nil + end + + ## + # Replaces the internal state of self with the specified URI's state. + # Used in destructive operations to avoid massive code repetition. + # + # @param [Addressable::URI] uri The URI to replace self with. + # + # @return [Addressable::URI] self. + def replace_self(uri) + # Reset dependent values + reset_ivs + + @scheme = uri.scheme + @user = uri.user + @password = uri.password + @host = uri.host + @port = uri.port + @path = uri.path + @query = uri.query + @fragment = uri.fragment + return self + end + + ## + # Splits path string with "/" (slash). + # It is considered that there is empty string after last slash when + # path ends with slash. + # + # @param [String] path The path to split. + # + # @return [Array] An array of parts of path. + def split_path(path) + splitted = path.split(SLASH) + splitted << EMPTY_STR if path.end_with? SLASH + splitted + end + + ## + # Resets composite values for the entire URI + # + # @api private + def remove_composite_values + @uri_string = nil + @hash = nil + end + + ## + # Converts the string to be UTF-8 if it is not already UTF-8 + # + # @api private + def force_utf8_encoding_if_needed(str) + if str && str.encoding != Encoding::UTF_8 + str.force_encoding(Encoding::UTF_8) + end + end + + private + + ## + # Resets instance variables + # + # @api private + def reset_ivs + @scheme = nil + @user = nil + @normalized_scheme = NONE + @normalized_user = NONE + @uri_string = nil + @hash = nil + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @password = nil + @normalized_authority = nil + @port = nil + @normalized_password = NONE + @host = nil + @normalized_host = nil + @normalized_port = NONE + @path = EMPTY_STR + @normalized_path = nil + @normalized_query = NONE + @fragment = nil + @normalized_fragment = NONE + @query = nil + end + + NONE = Module.new.freeze + + private_constant :NONE + end +end diff --git a/bin/gems/addressable-2.8.7/lib/addressable/version.rb b/bin/gems/addressable-2.8.7/lib/addressable/version.rb new file mode 100644 index 00000000..2eec3e65 --- /dev/null +++ b/bin/gems/addressable-2.8.7/lib/addressable/version.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +# Used to prevent the class/module from being loaded more than once +if !defined?(Addressable::VERSION) + module Addressable + module VERSION + MAJOR = 2 + MINOR = 8 + TINY = 7 + + STRING = [MAJOR, MINOR, TINY].join('.') + end + end +end diff --git a/bin/gems/addressable-2.8.7/spec/addressable/idna_spec.rb b/bin/gems/addressable-2.8.7/spec/addressable/idna_spec.rb new file mode 100644 index 00000000..428c9ec8 --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/addressable/idna_spec.rb @@ -0,0 +1,302 @@ +# frozen_string_literal: true + +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +# Have to use RubyGems to load the idn gem. +require "rubygems" + +require "addressable/idna" + +shared_examples_for "converting from unicode to ASCII" do + it "should convert 'www.google.com' correctly" do + expect(Addressable::IDNA.to_ascii("www.google.com")).to eq("www.google.com") + end + + long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com' + it "should convert '#{long}' correctly" do + expect(Addressable::IDNA.to_ascii(long)).to eq(long) + end + + it "should convert 'www.詹姆斯.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "www.詹姆斯.com" + )).to eq("www.xn--8ws00zhy3a.com") + end + + it "also accepts unicode strings encoded as ascii-8bit" do + expect(Addressable::IDNA.to_ascii( + "www.詹姆斯.com".b + )).to eq("www.xn--8ws00zhy3a.com") + end + + it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do + "www.Iñtërnâtiônàlizætiøn.com" + expect(Addressable::IDNA.to_ascii( + "www.I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4" + + "n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n.com" + )).to eq("www.xn--itrntinliztin-vdb0a5exd8ewcye.com") + end + + it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "www.In\xCC\x83te\xCC\x88rna\xCC\x82tio\xCC\x82n" + + "a\xCC\x80liz\xC3\xA6ti\xC3\xB8n.com" + )).to eq("www.xn--itrntinliztin-vdb0a5exd8ewcye.com") + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + expect(Addressable::IDNA.to_ascii( + "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + + "\201\252\343\201\214\343\201\204\343\202\217\343\201\221\343\201\256" + + "\343\202\217\343\201\213\343\202\211\343\201\252\343\201\204\343\201" + + "\251\343\202\201\343\201\204\343\202\223\343\202\201\343\201\204\343" + + "\201\256\343\202\211\343\201\271\343\202\213\343\201\276\343\201\240" + + "\343\201\252\343\201\214\343\201\217\343\201\227\343\201\252\343\201" + + "\204\343\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + + "w3.mag.keio.ac.jp" + )).to eq( + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + ) + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + expect(Addressable::IDNA.to_ascii( + "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + + "\201\252\343\201\213\343\202\231\343\201\204\343\202\217\343\201\221" + + "\343\201\256\343\202\217\343\201\213\343\202\211\343\201\252\343\201" + + "\204\343\201\250\343\202\231\343\202\201\343\201\204\343\202\223\343" + + "\202\201\343\201\204\343\201\256\343\202\211\343\201\270\343\202\231" + + "\343\202\213\343\201\276\343\201\237\343\202\231\343\201\252\343\201" + + "\213\343\202\231\343\201\217\343\201\227\343\201\252\343\201\204\343" + + "\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + + "w3.mag.keio.ac.jp" + )).to eq( + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + ) + end + + it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do + expect(Addressable::IDNA.to_ascii( + "点心和烤鸭.w3.mag.keio.ac.jp" + )).to eq("xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp") + end + + it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "가각갂갃간갅갆갇갈갉힢힣.com" + )).to eq("xn--o39acdefghijk5883jma.com") + end + + it "should convert " + + "'\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com" + )).to eq("xn--9cs565brid46mda086o.com") + end + + it "should convert 'リ宠퐱〹.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "\357\276\230\345\256\240\355\220\261\343\200\271.com" + )).to eq("xn--eek174hoxfpr4k.com") + end + + it "should convert 'リ宠퐱卄.com' correctly" do + expect(Addressable::IDNA.to_ascii( + "\343\203\252\345\256\240\355\220\261\345\215\204.com" + )).to eq("xn--eek174hoxfpr4k.com") + end + + it "should convert 'ᆵ' correctly" do + expect(Addressable::IDNA.to_ascii( + "\341\206\265" + )).to eq("xn--4ud") + end + + it "should convert 'ᆵ' correctly" do + expect(Addressable::IDNA.to_ascii( + "\357\276\257" + )).to eq("xn--4ud") + end + + it "should convert '🌹🌹🌹.ws' correctly" do + expect(Addressable::IDNA.to_ascii( + "\360\237\214\271\360\237\214\271\360\237\214\271.ws" + )).to eq("xn--2h8haa.ws") + end + + it "should handle two adjacent '.'s correctly" do + expect(Addressable::IDNA.to_ascii( + "example..host" + )).to eq("example..host") + end +end + +shared_examples_for "converting from ASCII to unicode" do + long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com' + it "should convert '#{long}' correctly" do + expect(Addressable::IDNA.to_unicode(long)).to eq(long) + end + + it "should return the identity conversion when punycode decode fails" do + expect(Addressable::IDNA.to_unicode("xn--zckp1cyg1.sblo.jp")).to eq( + "xn--zckp1cyg1.sblo.jp") + end + + it "should return the identity conversion when the ACE prefix has no suffix" do + expect(Addressable::IDNA.to_unicode("xn--...-")).to eq("xn--...-") + end + + it "should convert 'www.google.com' correctly" do + expect(Addressable::IDNA.to_unicode("www.google.com")).to eq( + "www.google.com") + end + + it "should convert 'www.詹姆斯.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "www.xn--8ws00zhy3a.com" + )).to eq("www.詹姆斯.com") + end + + it "should convert '詹姆斯.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--8ws00zhy3a.com" + )).to eq("詹姆斯.com") + end + + it "should convert 'www.iñtërnâtiônàlizætiøn.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "www.xn--itrntinliztin-vdb0a5exd8ewcye.com" + )).to eq("www.iñtërnâtiônàlizætiøn.com") + end + + it "should convert 'iñtërnâtiônàlizætiøn.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--itrntinliztin-vdb0a5exd8ewcye.com" + )).to eq("iñtërnâtiônàlizætiøn.com") + end + + it "should convert " + + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + + "correctly" do + expect(Addressable::IDNA.to_unicode( + "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + )).to eq( + "www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp" + ) + end + + it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp" + )).to eq("点心和烤鸭.w3.mag.keio.ac.jp") + end + + it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--o39acdefghijk5883jma.com" + )).to eq("가각갂갃간갅갆갇갈갉힢힣.com") + end + + it "should convert " + + "'\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--9cs565brid46mda086o.com" + )).to eq( + "\347\242\274\346\250\231\346\272\226\350" + + "\220\254\345\234\213\347\242\274.com" + ) + end + + it "should convert 'リ宠퐱卄.com' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--eek174hoxfpr4k.com" + )).to eq("\343\203\252\345\256\240\355\220\261\345\215\204.com") + end + + it "should convert 'ᆵ' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--4ud" + )).to eq("\341\206\265") + end + + it "should convert '🌹🌹🌹.ws' correctly" do + expect(Addressable::IDNA.to_unicode( + "xn--2h8haa.ws" + )).to eq("\360\237\214\271\360\237\214\271\360\237\214\271.ws") + end + + it "should handle two adjacent '.'s correctly" do + expect(Addressable::IDNA.to_unicode( + "example..host" + )).to eq("example..host") + end +end + +describe Addressable::IDNA, "when using the pure-Ruby implementation" do + before do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/pure.rb" + end + + it_should_behave_like "converting from unicode to ASCII" + it_should_behave_like "converting from ASCII to unicode" + + begin + require "fiber" + + it "should not blow up inside fibers" do + f = Fiber.new do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/pure.rb" + end + f.resume + end + rescue LoadError + # Fibers aren't supported in this version of Ruby, skip this test. + warn('Fibers unsupported.') + end +end + +begin + require "idn" + + describe Addressable::IDNA, "when using the native-code implementation" do + before do + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/native.rb" + end + + it_should_behave_like "converting from unicode to ASCII" + it_should_behave_like "converting from ASCII to unicode" + end +rescue LoadError => error + raise error if ENV["CI"] && TestHelper.native_supported? + + # Cannot test the native implementation without libidn support. + warn('Could not load native IDN implementation.') +end diff --git a/bin/gems/addressable-2.8.7/spec/addressable/net_http_compat_spec.rb b/bin/gems/addressable-2.8.7/spec/addressable/net_http_compat_spec.rb new file mode 100644 index 00000000..d07a43e5 --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/addressable/net_http_compat_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/uri" +require "net/http" + +describe Net::HTTP do + it "should be compatible with Addressable" do + response_body = + Net::HTTP.get(Addressable::URI.parse('http://www.google.com/')) + expect(response_body).not_to be_nil + end +end diff --git a/bin/gems/addressable-2.8.7/spec/addressable/security_spec.rb b/bin/gems/addressable-2.8.7/spec/addressable/security_spec.rb new file mode 100644 index 00000000..3bf90a20 --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/addressable/security_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/uri" + +describe Addressable::URI, "when created with a URI known to cause crashes " + + "in certain browsers" do + it "should parse correctly" do + uri = Addressable::URI.parse('%%30%30') + expect(uri.path).to eq('%%30%30') + expect(uri.normalize.path).to eq('%2500') + end + + it "should parse correctly as a full URI" do + uri = Addressable::URI.parse('http://www.example.com/%%30%30') + expect(uri.path).to eq('/%%30%30') + expect(uri.normalize.path).to eq('/%2500') + end +end + +describe Addressable::URI, "when created with a URI known to cause crashes " + + "in certain browsers" do + it "should parse correctly" do + uri = Addressable::URI.parse('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') + expect(uri.path).to eq('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') + expect(uri.normalize.path).to eq( + '%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' + + '%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' + + '%A3%20%E0%A5%A3%20%E5%86%97' + ) + end + + it "should parse correctly as a full URI" do + uri = Addressable::URI.parse('http://www.example.com/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') + expect(uri.path).to eq('/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') + expect(uri.normalize.path).to eq( + '/%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' + + '%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' + + '%A3%20%E0%A5%A3%20%E5%86%97' + ) + end +end diff --git a/bin/gems/addressable-2.8.7/spec/addressable/template_spec.rb b/bin/gems/addressable-2.8.7/spec/addressable/template_spec.rb new file mode 100644 index 00000000..24616c23 --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/addressable/template_spec.rb @@ -0,0 +1,1264 @@ +# frozen_string_literal: true + +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "bigdecimal" +require "timeout" +require "addressable/template" + +shared_examples_for 'expands' do |tests| + tests.each do |template, expansion| + exp = expansion.is_a?(Array) ? expansion.first : expansion + it "#{template} to #{exp}" do + tmpl = Addressable::Template.new(template).expand(subject) + expect(tmpl.to_str).to eq(expansion) + end + end +end + +describe "eql?" do + let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } + it 'is equal when the pattern matches' do + other_template = Addressable::Template.new('https://www.example.com/{foo}') + expect(template).to be_eql(other_template) + expect(other_template).to be_eql(template) + end + it 'is not equal when the pattern differs' do + other_template = Addressable::Template.new('https://www.example.com/{bar}') + expect(template).to_not be_eql(other_template) + expect(other_template).to_not be_eql(template) + end + it 'is not equal to non-templates' do + uri = 'https://www.example.com/foo/bar' + addressable_template = Addressable::Template.new uri + addressable_uri = Addressable::URI.parse uri + expect(addressable_template).to_not be_eql(addressable_uri) + expect(addressable_uri).to_not be_eql(addressable_template) + end +end + +describe "==" do + let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } + it 'is equal when the pattern matches' do + other_template = Addressable::Template.new('https://www.example.com/{foo}') + expect(template).to eq other_template + expect(other_template).to eq template + end + it 'is not equal when the pattern differs' do + other_template = Addressable::Template.new('https://www.example.com/{bar}') + expect(template).not_to eq other_template + expect(other_template).not_to eq template + end + it 'is not equal to non-templates' do + uri = 'https://www.example.com/foo/bar' + addressable_template = Addressable::Template.new uri + addressable_uri = Addressable::URI.parse uri + expect(addressable_template).not_to eq addressable_uri + expect(addressable_uri).not_to eq addressable_template + end +end + +describe "#to_regexp" do + it "does not match the first line of multiline strings" do + uri = "https://www.example.com/bar" + template = Addressable::Template.new(uri) + expect(template.match(uri)).not_to be_nil + expect(template.match("#{uri}\ngarbage")).to be_nil + end +end + +describe "Type conversion" do + subject { + { + :var => true, + :hello => 1234, + :nothing => nil, + :sym => :symbolic, + :decimal => BigDecimal('1') + } + } + + it_behaves_like 'expands', { + '{var}' => 'true', + '{hello}' => '1234', + '{nothing}' => '', + '{sym}' => 'symbolic', + '{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1' + } +end + +describe "Level 1:" do + subject { + {:var => "value", :hello => "Hello World!"} + } + it_behaves_like 'expands', { + '{var}' => 'value', + '{hello}' => 'Hello%20World%21' + } +end + +describe "Level 2" do + subject { + { + :var => "value", + :hello => "Hello World!", + :path => "/foo/bar" + } + } + context "Operator +:" do + it_behaves_like 'expands', { + '{+var}' => 'value', + '{+hello}' => 'Hello%20World!', + '{+path}/here' => '/foo/bar/here', + 'here?ref={+path}' => 'here?ref=/foo/bar' + } + end + context "Operator #:" do + it_behaves_like 'expands', { + 'X{#var}' => 'X#value', + 'X{#hello}' => 'X#Hello%20World!' + } + end +end + +describe "Level 3" do + subject { + { + :var => "value", + :hello => "Hello World!", + :empty => "", + :path => "/foo/bar", + :x => "1024", + :y => "768" + } + } + context "Operator nil (multiple vars):" do + it_behaves_like 'expands', { + 'map?{x,y}' => 'map?1024,768', + '{x,hello,y}' => '1024,Hello%20World%21,768' + } + end + context "Operator + (multiple vars):" do + it_behaves_like 'expands', { + '{+x,hello,y}' => '1024,Hello%20World!,768', + '{+path,x}/here' => '/foo/bar,1024/here' + } + end + context "Operator # (multiple vars):" do + it_behaves_like 'expands', { + '{#x,hello,y}' => '#1024,Hello%20World!,768', + '{#path,x}/here' => '#/foo/bar,1024/here' + } + end + context "Operator ." do + it_behaves_like 'expands', { + 'X{.var}' => 'X.value', + 'X{.x,y}' => 'X.1024.768' + } + end + context "Operator /" do + it_behaves_like 'expands', { + '{/var}' => '/value', + '{/var,x}/here' => '/value/1024/here' + } + end + context "Operator ;" do + it_behaves_like 'expands', { + '{;x,y}' => ';x=1024;y=768', + '{;x,y,empty}' => ';x=1024;y=768;empty' + } + end + context "Operator ?" do + it_behaves_like 'expands', { + '{?x,y}' => '?x=1024&y=768', + '{?x,y,empty}' => '?x=1024&y=768&empty=' + } + end + context "Operator &" do + it_behaves_like 'expands', { + '?fixed=yes{&x}' => '?fixed=yes&x=1024', + '{&x,y,empty}' => '&x=1024&y=768&empty=' + } + end +end + +describe "Level 4" do + subject { + { + :var => "value", + :hello => "Hello World!", + :path => "/foo/bar", + :semi => ";", + :list => %w(red green blue), + :keys => {"semi" => ';', "dot" => '.', :comma => ','} + } + } + context "Expansion with value modifiers" do + it_behaves_like 'expands', { + '{var:3}' => 'val', + '{var:30}' => 'value', + '{list}' => 'red,green,blue', + '{list*}' => 'red,green,blue', + '{keys}' => 'semi,%3B,dot,.,comma,%2C', + '{keys*}' => 'semi=%3B,dot=.,comma=%2C', + } + end + context "Operator + with value modifiers" do + it_behaves_like 'expands', { + '{+path:6}/here' => '/foo/b/here', + '{+list}' => 'red,green,blue', + '{+list*}' => 'red,green,blue', + '{+keys}' => 'semi,;,dot,.,comma,,', + '{+keys*}' => 'semi=;,dot=.,comma=,', + } + end + context "Operator # with value modifiers" do + it_behaves_like 'expands', { + '{#path:6}/here' => '#/foo/b/here', + '{#list}' => '#red,green,blue', + '{#list*}' => '#red,green,blue', + '{#keys}' => '#semi,;,dot,.,comma,,', + '{#keys*}' => '#semi=;,dot=.,comma=,', + } + end + context "Operator . with value modifiers" do + it_behaves_like 'expands', { + 'X{.var:3}' => 'X.val', + 'X{.list}' => 'X.red,green,blue', + 'X{.list*}' => 'X.red.green.blue', + 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C', + 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C', + } + end + context "Operator / with value modifiers" do + it_behaves_like 'expands', { + '{/var:1,var}' => '/v/value', + '{/list}' => '/red,green,blue', + '{/list*}' => '/red/green/blue', + '{/list*,path:4}' => '/red/green/blue/%2Ffoo', + '{/keys}' => '/semi,%3B,dot,.,comma,%2C', + '{/keys*}' => '/semi=%3B/dot=./comma=%2C', + } + end + context "Operator ; with value modifiers" do + it_behaves_like 'expands', { + '{;hello:5}' => ';hello=Hello', + '{;list}' => ';list=red,green,blue', + '{;list*}' => ';list=red;list=green;list=blue', + '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C', + '{;keys*}' => ';semi=%3B;dot=.;comma=%2C', + } + end + context "Operator ? with value modifiers" do + it_behaves_like 'expands', { + '{?var:3}' => '?var=val', + '{?list}' => '?list=red,green,blue', + '{?list*}' => '?list=red&list=green&list=blue', + '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C', + '{?keys*}' => '?semi=%3B&dot=.&comma=%2C', + } + end + context "Operator & with value modifiers" do + it_behaves_like 'expands', { + '{&var:3}' => '&var=val', + '{&list}' => '&list=red,green,blue', + '{&list*}' => '&list=red&list=green&list=blue', + '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C', + '{&keys*}' => '&semi=%3B&dot=.&comma=%2C', + } + end +end +describe "Modifiers" do + subject { + { + :var => "value", + :semi => ";", + :year => [1965, 2000, 2012], + :dom => %w(example com) + } + } + context "length" do + it_behaves_like 'expands', { + '{var:3}' => 'val', + '{var:30}' => 'value', + '{var}' => 'value', + '{semi}' => '%3B', + '{semi:2}' => '%3B' + } + end + context "explode" do + it_behaves_like 'expands', { + 'find{?year*}' => 'find?year=1965&year=2000&year=2012', + 'www{.dom*}' => 'www.example.com', + } + end +end +describe "Expansion" do + subject { + { + :count => ["one", "two", "three"], + :dom => ["example", "com"], + :dub => "me/too", + :hello => "Hello World!", + :half => "50%", + :var => "value", + :who => "fred", + :base => "http://example.com/home/", + :path => "/foo/bar", + :list => ["red", "green", "blue"], + :keys => {"semi" => ";","dot" => ".",:comma => ","}, + :v => "6", + :x => "1024", + :y => "768", + :empty => "", + :empty_keys => {}, + :undef => nil + } + } + context "concatenation" do + it_behaves_like 'expands', { + '{count}' => 'one,two,three', + '{count*}' => 'one,two,three', + '{/count}' => '/one,two,three', + '{/count*}' => '/one/two/three', + '{;count}' => ';count=one,two,three', + '{;count*}' => ';count=one;count=two;count=three', + '{?count}' => '?count=one,two,three', + '{?count*}' => '?count=one&count=two&count=three', + '{&count*}' => '&count=one&count=two&count=three' + } + end + context "simple expansion" do + it_behaves_like 'expands', { + '{var}' => 'value', + '{hello}' => 'Hello%20World%21', + '{half}' => '50%25', + 'O{empty}X' => 'OX', + 'O{undef}X' => 'OX', + '{x,y}' => '1024,768', + '{x,hello,y}' => '1024,Hello%20World%21,768', + '?{x,empty}' => '?1024,', + '?{x,undef}' => '?1024', + '?{undef,y}' => '?768', + '{var:3}' => 'val', + '{var:30}' => 'value', + '{list}' => 'red,green,blue', + '{list*}' => 'red,green,blue', + '{keys}' => 'semi,%3B,dot,.,comma,%2C', + '{keys*}' => 'semi=%3B,dot=.,comma=%2C', + } + end + context "reserved expansion (+)" do + it_behaves_like 'expands', { + '{+var}' => 'value', + '{+hello}' => 'Hello%20World!', + '{+half}' => '50%25', + '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex', + '{+base}index' => 'http://example.com/home/index', + 'O{+empty}X' => 'OX', + 'O{+undef}X' => 'OX', + '{+path}/here' => '/foo/bar/here', + 'here?ref={+path}' => 'here?ref=/foo/bar', + 'up{+path}{var}/here' => 'up/foo/barvalue/here', + '{+x,hello,y}' => '1024,Hello%20World!,768', + '{+path,x}/here' => '/foo/bar,1024/here', + '{+path:6}/here' => '/foo/b/here', + '{+list}' => 'red,green,blue', + '{+list*}' => 'red,green,blue', + '{+keys}' => 'semi,;,dot,.,comma,,', + '{+keys*}' => 'semi=;,dot=.,comma=,', + } + end + context "fragment expansion (#)" do + it_behaves_like 'expands', { + '{#var}' => '#value', + '{#hello}' => '#Hello%20World!', + '{#half}' => '#50%25', + 'foo{#empty}' => 'foo#', + 'foo{#undef}' => 'foo', + '{#x,hello,y}' => '#1024,Hello%20World!,768', + '{#path,x}/here' => '#/foo/bar,1024/here', + '{#path:6}/here' => '#/foo/b/here', + '{#list}' => '#red,green,blue', + '{#list*}' => '#red,green,blue', + '{#keys}' => '#semi,;,dot,.,comma,,', + '{#keys*}' => '#semi=;,dot=.,comma=,', + } + end + context "label expansion (.)" do + it_behaves_like 'expands', { + '{.who}' => '.fred', + '{.who,who}' => '.fred.fred', + '{.half,who}' => '.50%25.fred', + 'www{.dom*}' => 'www.example.com', + 'X{.var}' => 'X.value', + 'X{.empty}' => 'X.', + 'X{.undef}' => 'X', + 'X{.var:3}' => 'X.val', + 'X{.list}' => 'X.red,green,blue', + 'X{.list*}' => 'X.red.green.blue', + 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C', + 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C', + 'X{.empty_keys}' => 'X', + 'X{.empty_keys*}' => 'X' + } + end + context "path expansion (/)" do + it_behaves_like 'expands', { + '{/who}' => '/fred', + '{/who,who}' => '/fred/fred', + '{/half,who}' => '/50%25/fred', + '{/who,dub}' => '/fred/me%2Ftoo', + '{/var}' => '/value', + '{/var,empty}' => '/value/', + '{/var,undef}' => '/value', + '{/var,x}/here' => '/value/1024/here', + '{/var:1,var}' => '/v/value', + '{/list}' => '/red,green,blue', + '{/list*}' => '/red/green/blue', + '{/list*,path:4}' => '/red/green/blue/%2Ffoo', + '{/keys}' => '/semi,%3B,dot,.,comma,%2C', + '{/keys*}' => '/semi=%3B/dot=./comma=%2C', + } + end + context "path-style expansion (;)" do + it_behaves_like 'expands', { + '{;who}' => ';who=fred', + '{;half}' => ';half=50%25', + '{;empty}' => ';empty', + '{;v,empty,who}' => ';v=6;empty;who=fred', + '{;v,bar,who}' => ';v=6;who=fred', + '{;x,y}' => ';x=1024;y=768', + '{;x,y,empty}' => ';x=1024;y=768;empty', + '{;x,y,undef}' => ';x=1024;y=768', + '{;hello:5}' => ';hello=Hello', + '{;list}' => ';list=red,green,blue', + '{;list*}' => ';list=red;list=green;list=blue', + '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C', + '{;keys*}' => ';semi=%3B;dot=.;comma=%2C', + } + end + context "form query expansion (?)" do + it_behaves_like 'expands', { + '{?who}' => '?who=fred', + '{?half}' => '?half=50%25', + '{?x,y}' => '?x=1024&y=768', + '{?x,y,empty}' => '?x=1024&y=768&empty=', + '{?x,y,undef}' => '?x=1024&y=768', + '{?var:3}' => '?var=val', + '{?list}' => '?list=red,green,blue', + '{?list*}' => '?list=red&list=green&list=blue', + '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C', + '{?keys*}' => '?semi=%3B&dot=.&comma=%2C', + } + end + context "form query expansion (&)" do + it_behaves_like 'expands', { + '{&who}' => '&who=fred', + '{&half}' => '&half=50%25', + '?fixed=yes{&x}' => '?fixed=yes&x=1024', + '{&x,y,empty}' => '&x=1024&y=768&empty=', + '{&x,y,undef}' => '&x=1024&y=768', + '{&var:3}' => '&var=val', + '{&list}' => '&list=red,green,blue', + '{&list*}' => '&list=red&list=green&list=blue', + '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C', + '{&keys*}' => '&semi=%3B&dot=.&comma=%2C', + } + end + context "non-string key in match data" do + subject {Addressable::Template.new("http://example.com/{one}")} + + it "raises TypeError" do + expect { subject.expand(Object.new => "1") }.to raise_error TypeError + end + end +end + +class ExampleTwoProcessor + def self.restore(name, value) + return value.gsub(/-/, " ") if name == "query" + return value + end + + def self.match(name) + return ".*?" if name == "first" + return ".*" + end + def self.validate(name, value) + return !!(value =~ /^[\w ]+$/) if name == "query" + return true + end + + def self.transform(name, value) + return value.gsub(/ /, "+") if name == "query" + return value + end +end + +class DumbProcessor + def self.match(name) + return ".*?" if name == "first" + end +end + +describe Addressable::Template do + describe 'initialize' do + context 'with a non-string' do + it 'raises a TypeError' do + expect { Addressable::Template.new(nil) }.to raise_error(TypeError) + end + end + end + + describe 'freeze' do + subject { Addressable::Template.new("http://example.com/{first}/{+second}/") } + it 'freezes the template' do + expect(subject.freeze).to be_frozen + end + end + + describe "Matching" do + let(:uri){ + Addressable::URI.parse( + "http://example.com/search/an-example-search-query/" + ) + } + let(:uri2){ + Addressable::URI.parse("http://example.com/a/b/c/") + } + let(:uri3){ + Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo") + } + let(:uri4){ + Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo") + } + let(:uri5){ + "http://example.com/foo" + } + context "first uri with ExampleTwoProcessor" do + subject { + Addressable::Template.new( + "http://example.com/search/{query}/" + ).match(uri, ExampleTwoProcessor) + } + its(:variables){ should == ["query"] } + its(:captures){ should == ["an example search query"] } + end + + context "second uri with ExampleTwoProcessor" do + subject { + Addressable::Template.new( + "http://example.com/{first}/{+second}/" + ).match(uri2, ExampleTwoProcessor) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", "b/c"] } + end + + context "second uri with DumbProcessor" do + subject { + Addressable::Template.new( + "http://example.com/{first}/{+second}/" + ).match(uri2, DumbProcessor) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", "b/c"] } + end + + context "second uri" do + subject { + Addressable::Template.new( + "http://example.com/{first}{/second*}/" + ).match(uri2) + } + its(:variables){ should == ["first", "second"] } + its(:captures){ should == ["a", ["b","c"]] } + end + context "third uri" do + subject { + Addressable::Template.new( + "http://example.com/{;hash*,first}" + ).match(uri3) + } + its(:variables){ should == ["hash", "first"] } + its(:captures){ should == [ + {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] } + end + # Note that this expansion is impossible to revert deterministically - the + # * operator means first could have been a key of hash or a separate key. + # Semantically, a separate key is more likely, but both are possible. + context "fourth uri" do + subject { + Addressable::Template.new( + "http://example.com/{?hash*,first}" + ).match(uri4) + } + its(:variables){ should == ["hash", "first"] } + its(:captures){ should == [ + {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] } + end + context "fifth uri" do + subject { + Addressable::Template.new( + "http://example.com/{path}{?hash*,first}" + ).match(uri5) + } + its(:variables){ should == ["path", "hash", "first"] } + its(:captures){ should == ["foo", nil, nil] } + end + end + + describe 'match' do + subject { Addressable::Template.new('http://example.com/first/second/') } + context 'when the URI is the same as the template' do + it 'returns the match data itself with an empty mapping' do + uri = Addressable::URI.parse('http://example.com/first/second/') + match_data = subject.match(uri) + expect(match_data).to be_an Addressable::Template::MatchData + expect(match_data.uri).to eq(uri) + expect(match_data.template).to eq(subject) + expect(match_data.mapping).to be_empty + expect(match_data.inspect).to be_an String + end + end + end + + describe "extract" do + let(:template) { + Addressable::Template.new( + "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" + ) + } + let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" } + let(:uri2){ "http://example.com/a/b/c/#foo" } + it "should be able to extract with queries" do + expect(template.extract(uri)).to eq({ + "host" => "example.com", + "segments" => %w(a b c), + "one" => "1", + "bogus" => nil, + "two" => "2", + "fragment" => "foo" + }) + end + it "should be able to extract without queries" do + expect(template.extract(uri2)).to eq({ + "host" => "example.com", + "segments" => %w(a b c), + "one" => nil, + "bogus" => nil, + "two" => nil, + "fragment" => "foo" + }) + end + + context "issue #137" do + subject { Addressable::Template.new('/path{?page,per_page}') } + + it "can match empty" do + data = subject.extract("/path") + expect(data["page"]).to eq(nil) + expect(data["per_page"]).to eq(nil) + expect(data.keys.sort).to eq(['page', 'per_page']) + end + + it "can match first var" do + data = subject.extract("/path?page=1") + expect(data["page"]).to eq("1") + expect(data["per_page"]).to eq(nil) + expect(data.keys.sort).to eq(['page', 'per_page']) + end + + it "can match second var" do + data = subject.extract("/path?per_page=1") + expect(data["page"]).to eq(nil) + expect(data["per_page"]).to eq("1") + expect(data.keys.sort).to eq(['page', 'per_page']) + end + + it "can match both vars" do + data = subject.extract("/path?page=2&per_page=1") + expect(data["page"]).to eq("2") + expect(data["per_page"]).to eq("1") + expect(data.keys.sort).to eq(['page', 'per_page']) + end + end + end + + describe "Partial expand with symbols" do + context "partial_expand with two simple values" do + subject { + Addressable::Template.new("http://example.com/{one}/{two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand(:one => "1").pattern).to eq( + "http://example.com/1/{two}/" + ) + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq( + "http://example.com/?one=1{&two}&three=3/" + ) + end + end + context "partial_expand form style query with missing param at beginning" do + subject { + Addressable::Template.new("http://example.com/{?one,two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand(:two => "2").pattern).to eq( + "http://example.com/?two=2{&one}/" + ) + end + end + context "issue #307 - partial_expand form query with nil params" do + subject do + Addressable::Template.new("http://example.com/{?one,two,three}/") + end + it "builds a new pattern with two=nil" do + expect(subject.partial_expand(two: nil).pattern).to eq( + "http://example.com/{?one}{&three}/" + ) + end + it "builds a new pattern with one=nil and two=nil" do + expect(subject.partial_expand(one: nil, two: nil).pattern).to eq( + "http://example.com/{?three}/" + ) + end + it "builds a new pattern with one=1 and two=nil" do + expect(subject.partial_expand(one: 1, two: nil).pattern).to eq( + "http://example.com/?one=1{&three}/" + ) + end + it "builds a new pattern with one=nil and two=2" do + expect(subject.partial_expand(one: nil, two: 2).pattern).to eq( + "http://example.com/?two=2{&three}/" + ) + end + it "builds a new pattern with one=nil" do + expect(subject.partial_expand(one: nil).pattern).to eq( + "http://example.com/{?two}{&three}/" + ) + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + expect(subject.partial_expand(:one => "1").pattern).to eq( + "http://example.com/?one=1{&two}/" + ) + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand(:one => "1").pattern).to eq( + "http://example.com/1{/two}/" + ) + end + end + context "partial expand with unicode values" do + subject do + Addressable::Template.new("http://example.com/{resource}/{query}/") + end + it "normalizes unicode by default" do + template = subject.partial_expand("query" => "Cafe\u0301") + expect(template.pattern).to eq( + "http://example.com/{resource}/Caf%C3%A9/" + ) + end + + it "normalizes as unicode even with wrong encoding specified" do + template = subject.partial_expand("query" => "Cafe\u0301".b) + expect(template.pattern).to eq( + "http://example.com/{resource}/Caf%C3%A9/" + ) + end + + it "raises on invalid unicode input" do + expect { + subject.partial_expand("query" => "M\xE9thode".b) + }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8") + end + + it "does not normalize unicode when byte semantics requested" do + template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false) + expect(template.pattern).to eq( + "http://example.com/{resource}/Cafe%CC%81/" + ) + end + end + end + describe "Partial expand with strings" do + context "partial_expand with two simple values" do + subject { + Addressable::Template.new("http://example.com/{one}/{two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1").pattern).to eq( + "http://example.com/1/{two}/" + ) + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq( + "http://example.com/?one=1{&two}&three=3/" + ) + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1").pattern).to eq( + "http://example.com/?one=1{&two}/" + ) + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1").pattern).to eq( + "http://example.com/1{/two}/" + ) + end + end + end + describe "Expand" do + context "expand with unicode values" do + subject do + Addressable::Template.new("http://example.com/search/{query}/") + end + it "normalizes unicode by default" do + uri = subject.expand("query" => "Cafe\u0301").to_str + expect(uri).to eq("http://example.com/search/Caf%C3%A9/") + end + + it "normalizes as unicode even with wrong encoding specified" do + uri = subject.expand("query" => "Cafe\u0301".b).to_str + expect(uri).to eq("http://example.com/search/Caf%C3%A9/") + end + + it "raises on invalid unicode input" do + expect { + subject.expand("query" => "M\xE9thode".b).to_str + }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8") + end + + it "does not normalize unicode when byte semantics requested" do + uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str + expect(uri).to eq("http://example.com/search/Cafe%CC%81/") + end + end + context "expand with a processor" do + subject { + Addressable::Template.new("http://example.com/search/{query}/") + } + it "processes spaces" do + expect(subject.expand({"query" => "an example search query"}, + ExampleTwoProcessor).to_str).to eq( + "http://example.com/search/an+example+search+query/" + ) + end + it "validates" do + expect{ + subject.expand({"query" => "Bogus!"}, + ExampleTwoProcessor).to_str + }.to raise_error(Addressable::Template::InvalidTemplateValueError) + end + end + context "partial_expand query with missing param in middle" do + subject { + Addressable::Template.new("http://example.com/{?one,two,three}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq( + "http://example.com/?one=1{&two}&three=3/" + ) + end + end + context "partial_expand with query string" do + subject { + Addressable::Template.new("http://example.com/{?two,one}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1").pattern).to eq( + "http://example.com/?one=1{&two}/" + ) + end + end + context "partial_expand with path operator" do + subject { + Addressable::Template.new("http://example.com{/one,two}/") + } + it "builds a new pattern" do + expect(subject.partial_expand("one" => "1").pattern).to eq( + "http://example.com/1{/two}/" + ) + end + end + end + context "Matching with operators" do + describe "Level 1:" do + subject { Addressable::Template.new("foo{foo}/{bar}baz") } + it "can match" do + data = subject.match("foofoo/bananabaz") + expect(data.mapping["foo"]).to eq("foo") + expect(data.mapping["bar"]).to eq("banana") + end + it "can fail" do + expect(subject.match("bar/foo")).to be_nil + expect(subject.match("foobaz")).to be_nil + end + it "can match empty" do + data = subject.match("foo/baz") + expect(data.mapping["foo"]).to eq(nil) + expect(data.mapping["bar"]).to eq(nil) + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + + describe "Level 2:" do + subject { Addressable::Template.new("foo{+foo}{#bar}baz") } + it "can match" do + data = subject.match("foo/test/banana#bazbaz") + expect(data.mapping["foo"]).to eq("/test/banana") + expect(data.mapping["bar"]).to eq("baz") + end + it "can match empty level 2 #" do + data = subject.match("foo/test/bananabaz") + expect(data.mapping["foo"]).to eq("/test/banana") + expect(data.mapping["bar"]).to eq(nil) + data = subject.match("foo/test/banana#baz") + expect(data.mapping["foo"]).to eq("/test/banana") + expect(data.mapping["bar"]).to eq("") + end + it "can match empty level 2 +" do + data = subject.match("foobaz") + expect(data.mapping["foo"]).to eq(nil) + expect(data.mapping["bar"]).to eq(nil) + data = subject.match("foo#barbaz") + expect(data.mapping["foo"]).to eq(nil) + expect(data.mapping["bar"]).to eq("bar") + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + + describe "Level 3:" do + context "no operator" do + subject { Addressable::Template.new("foo{foo,bar}baz") } + it "can match" do + data = subject.match("foofoo,barbaz") + expect(data.mapping["foo"]).to eq("foo") + expect(data.mapping["bar"]).to eq("bar") + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + context "+ operator" do + subject { Addressable::Template.new("foo{+foo,bar}baz") } + it "can match" do + data = subject.match("foofoo/bar,barbaz") + expect(data.mapping["bar"]).to eq("foo/bar,bar") + expect(data.mapping["foo"]).to eq("") + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + context ". operator" do + subject { Addressable::Template.new("foo{.foo,bar}baz") } + it "can match" do + data = subject.match("foo.foo.barbaz") + expect(data.mapping["foo"]).to eq("foo") + expect(data.mapping["bar"]).to eq("bar") + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + context "/ operator" do + subject { Addressable::Template.new("foo{/foo,bar}baz") } + it "can match" do + data = subject.match("foo/foo/barbaz") + expect(data.mapping["foo"]).to eq("foo") + expect(data.mapping["bar"]).to eq("bar") + end + it "lists vars" do + expect(subject.variables).to eq(["foo", "bar"]) + end + end + context "; operator" do + subject { Addressable::Template.new("foo{;foo,bar,baz}baz") } + it "can match" do + data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz") + expect(data.mapping["foo"]).to eq("bar baz") + expect(data.mapping["bar"]).to eq("foo") + expect(data.mapping["baz"]).to eq("") + end + it "lists vars" do + expect(subject.variables).to eq(%w(foo bar baz)) + end + end + context "? operator" do + context "test" do + subject { Addressable::Template.new("foo{?foo,bar}baz") } + it "can match" do + data = subject.match("foo?foo=bar%20baz&bar=foobaz") + expect(data.mapping["foo"]).to eq("bar baz") + expect(data.mapping["bar"]).to eq("foo") + end + it "lists vars" do + expect(subject.variables).to eq(%w(foo bar)) + end + end + + context "issue #137" do + subject { Addressable::Template.new('/path{?page,per_page}') } + + it "can match empty" do + data = subject.match("/path") + expect(data.mapping["page"]).to eq(nil) + expect(data.mapping["per_page"]).to eq(nil) + expect(data.mapping.keys.sort).to eq(['page', 'per_page']) + end + + it "can match first var" do + data = subject.match("/path?page=1") + expect(data.mapping["page"]).to eq("1") + expect(data.mapping["per_page"]).to eq(nil) + expect(data.mapping.keys.sort).to eq(['page', 'per_page']) + end + + it "can match second var" do + data = subject.match("/path?per_page=1") + expect(data.mapping["page"]).to eq(nil) + expect(data.mapping["per_page"]).to eq("1") + expect(data.mapping.keys.sort).to eq(['page', 'per_page']) + end + + it "can match both vars" do + data = subject.match("/path?page=2&per_page=1") + expect(data.mapping["page"]).to eq("2") + expect(data.mapping["per_page"]).to eq("1") + expect(data.mapping.keys.sort).to eq(['page', 'per_page']) + end + end + + context "issue #71" do + subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") } + it "can match" do + data = subject.match("http://cyberscore.dev/api/users?username=foobaz") + expect(data.mapping["username"]).to eq("foobaz") + end + it "lists vars" do + expect(subject.variables).to eq(%w(username)) + expect(subject.keys).to eq(%w(username)) + end + end + end + context "& operator" do + subject { Addressable::Template.new("foo{&foo,bar}baz") } + it "can match" do + data = subject.match("foo&foo=bar%20baz&bar=foobaz") + expect(data.mapping["foo"]).to eq("bar baz") + expect(data.mapping["bar"]).to eq("foo") + end + it "lists vars" do + expect(subject.variables).to eq(%w(foo bar)) + end + end + end + end + + context "support regexes:" do + context "EXPRESSION" do + subject { Addressable::Template::EXPRESSION } + it "should be able to match an expression" do + expect(subject).to match("{foo}") + expect(subject).to match("{foo,9}") + expect(subject).to match("{foo.bar,baz}") + expect(subject).to match("{+foo.bar,baz}") + expect(subject).to match("{foo,foo%20bar}") + expect(subject).to match("{#foo:20,baz*}") + expect(subject).to match("stuff{#foo:20,baz*}things") + end + it "should fail on non vars" do + expect(subject).not_to match("!{foo") + expect(subject).not_to match("{foo.bar.}") + expect(subject).not_to match("!{}") + end + end + context "VARNAME" do + subject { Addressable::Template::VARNAME } + it "should be able to match a variable" do + expect(subject).to match("foo") + expect(subject).to match("9") + expect(subject).to match("foo.bar") + expect(subject).to match("foo_bar") + expect(subject).to match("foo_bar.baz") + expect(subject).to match("foo%20bar") + expect(subject).to match("foo%20bar.baz") + end + it "should fail on non vars" do + expect(subject).not_to match("!foo") + expect(subject).not_to match("foo.bar.") + expect(subject).not_to match("foo%2%00bar") + expect(subject).not_to match("foo_ba%r") + expect(subject).not_to match("foo_bar*") + expect(subject).not_to match("foo_bar:20") + end + + it 'should parse in a reasonable time' do + expect do + Timeout.timeout(0.1) do + expect(subject).not_to match("0"*25 + "!") + end + end.not_to raise_error + end + end + context "VARIABLE_LIST" do + subject { Addressable::Template::VARIABLE_LIST } + it "should be able to match a variable list" do + expect(subject).to match("foo,bar") + expect(subject).to match("foo") + expect(subject).to match("foo,bar*,baz") + expect(subject).to match("foo.bar,bar_baz*,baz:12") + end + it "should fail on non vars" do + expect(subject).not_to match(",foo,bar*,baz") + expect(subject).not_to match("foo,*bar,baz") + expect(subject).not_to match("foo,,bar*,baz") + end + end + context "VARSPEC" do + subject { Addressable::Template::VARSPEC } + it "should be able to match a variable with modifier" do + expect(subject).to match("9:8") + expect(subject).to match("foo.bar*") + expect(subject).to match("foo_bar:12") + expect(subject).to match("foo_bar.baz*") + expect(subject).to match("foo%20bar:12") + expect(subject).to match("foo%20bar.baz*") + end + it "should fail on non vars" do + expect(subject).not_to match("!foo") + expect(subject).not_to match("*foo") + expect(subject).not_to match("fo*o") + expect(subject).not_to match("fo:o") + expect(subject).not_to match("foo:") + end + end + end +end + +describe Addressable::Template::MatchData do + let(:template) { Addressable::Template.new('{foo}/{bar}') } + subject(:its) { template.match('ab/cd') } + its(:uri) { should == Addressable::URI.parse('ab/cd') } + its(:template) { should == template } + its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } } + its(:variables) { should == ['foo', 'bar'] } + its(:keys) { should == ['foo', 'bar'] } + its(:names) { should == ['foo', 'bar'] } + its(:values) { should == ['ab', 'cd'] } + its(:captures) { should == ['ab', 'cd'] } + its(:to_a) { should == ['ab/cd', 'ab', 'cd'] } + its(:to_s) { should == 'ab/cd' } + its(:string) { should == its.to_s } + its(:pre_match) { should == "" } + its(:post_match) { should == "" } + + describe 'values_at' do + it 'returns an array with the values' do + expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd']) + end + it 'allows mixing integer an string keys' do + expect(its.values_at('foo', 1)).to eq(['ab', 'ab']) + end + it 'accepts unknown keys' do + expect(its.values_at('baz', 'foo')).to eq([nil, 'ab']) + end + end + + describe '[]' do + context 'string key' do + it 'returns the corresponding capture' do + expect(its['foo']).to eq('ab') + expect(its['bar']).to eq('cd') + end + it 'returns nil for unknown keys' do + expect(its['baz']).to be_nil + end + end + context 'symbol key' do + it 'returns the corresponding capture' do + expect(its[:foo]).to eq('ab') + expect(its[:bar]).to eq('cd') + end + it 'returns nil for unknown keys' do + expect(its[:baz]).to be_nil + end + end + context 'integer key' do + it 'returns the full URI for index 0' do + expect(its[0]).to eq('ab/cd') + end + it 'returns the corresponding capture' do + expect(its[1]).to eq('ab') + expect(its[2]).to eq('cd') + end + it 'returns nil for unknown keys' do + expect(its[3]).to be_nil + end + end + context 'other key' do + it 'raises an exception' do + expect { its[Object.new] }.to raise_error(TypeError) + end + end + context 'with length' do + it 'returns an array starting at index with given length' do + expect(its[0, 2]).to eq(['ab/cd', 'ab']) + expect(its[2, 1]).to eq(['cd']) + end + end + end +end diff --git a/bin/gems/addressable-2.8.7/spec/addressable/uri_spec.rb b/bin/gems/addressable-2.8.7/spec/addressable/uri_spec.rb new file mode 100644 index 00000000..26ee923d --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/addressable/uri_spec.rb @@ -0,0 +1,6840 @@ +# frozen_string_literal: true + +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "spec_helper" + +require "addressable/uri" +require "uri" +require "ipaddr" +require "yaml" + +if !"".respond_to?("force_encoding") + class String + def force_encoding(encoding) + @encoding = encoding + end + + def encoding + @encoding ||= Encoding::ASCII_8BIT + end + end + + class Encoding + def initialize(name) + @name = name + end + + def to_s + return @name + end + + UTF_8 = Encoding.new("UTF-8") + ASCII_8BIT = Encoding.new("US-ASCII") + end +end + +module Fake + module URI + class HTTP + def initialize(uri) + @uri = uri + end + + def to_s + return @uri.to_s + end + + alias :to_str :to_s + end + end +end + +describe Addressable::URI, "when created with a non-numeric port number" do + it "should raise an error" do + expect do + Addressable::URI.new(:port => "bogus") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a invalid encoded port number" do + it "should raise an error" do + expect do + Addressable::URI.new(:port => "%eb") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a non-string scheme" do + it "should raise an error" do + expect do + Addressable::URI.new(:scheme => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string user" do + it "should raise an error" do + expect do + Addressable::URI.new(:user => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string password" do + it "should raise an error" do + expect do + Addressable::URI.new(:password => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string userinfo" do + it "should raise an error" do + expect do + Addressable::URI.new(:userinfo => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string host" do + it "should raise an error" do + expect do + Addressable::URI.new(:host => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string authority" do + it "should raise an error" do + expect do + Addressable::URI.new(:authority => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string path" do + it "should raise an error" do + expect do + Addressable::URI.new(:path => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string query" do + it "should raise an error" do + expect do + Addressable::URI.new(:query => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a non-string fragment" do + it "should raise an error" do + expect do + Addressable::URI.new(:fragment => :bogus) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when created with a scheme but no hierarchical " + + "segment" do + it "should raise an error" do + expect do + Addressable::URI.parse("http:") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "quote handling" do + describe 'in host name' do + it "should raise an error for single quote" do + expect do + Addressable::URI.parse("http://local\"host/") + end.to raise_error(Addressable::URI::InvalidURIError) + end + end +end + +describe Addressable::URI, "newline normalization" do + it "should not accept newlines in scheme" do + expect do + Addressable::URI.parse("ht%0atp://localhost/") + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should not unescape newline in path" do + uri = Addressable::URI.parse("http://localhost/%0a").normalize + expect(uri.to_s).to eq("http://localhost/%0A") + end + + it "should not unescape newline in hostname" do + uri = Addressable::URI.parse("http://local%0ahost/").normalize + expect(uri.to_s).to eq("http://local%0Ahost/") + end + + it "should not unescape newline in username" do + uri = Addressable::URI.parse("http://foo%0abar@localhost/").normalize + expect(uri.to_s).to eq("http://foo%0Abar@localhost/") + end + + it "should not unescape newline in username" do + uri = Addressable::URI.parse("http://example:foo%0abar@example/").normalize + expect(uri.to_s).to eq("http://example:foo%0Abar@example/") + end + + it "should not accept newline in hostname" do + uri = Addressable::URI.parse("http://localhost/") + expect do + uri.host = "local\nhost" + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with ambiguous path" do + it "should raise an error" do + expect do + Addressable::URI.parse("::http") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with an invalid host" do + it "should raise an error" do + expect do + Addressable::URI.new(:host => "") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a host consisting of " + + "sub-delims characters" do + it "should not raise an error" do + expect do + Addressable::URI.new( + :host => Addressable::URI::CharacterClasses::SUB_DELIMS.gsub(/\\/, '') + ) + end.not_to raise_error + end +end + +describe Addressable::URI, "when created with a host consisting of " + + "unreserved characters" do + it "should not raise an error" do + expect do + Addressable::URI.new( + :host => Addressable::URI::CharacterClasses::UNRESERVED.gsub(/\\/, '') + ) + end.not_to raise_error + end +end + +describe Addressable::URI, "when created from nil components" do + before do + @uri = Addressable::URI.new + end + + it "should have a nil site value" do + expect(@uri.site).to eq(nil) + end + + it "should have an empty path" do + expect(@uri.path).to eq("") + end + + it "should be an empty uri" do + expect(@uri.to_s).to eq("") + end + + it "should have a nil default port" do + expect(@uri.default_port).to eq(nil) + end + + it "should be empty" do + expect(@uri).to be_empty + end + + it "should raise an error if the scheme is set to whitespace" do + expect do + @uri.scheme = "\t \n" + end.to raise_error(Addressable::URI::InvalidURIError, /'\t \n'/) + end + + it "should raise an error if the scheme is set to all digits" do + expect do + @uri.scheme = "123" + end.to raise_error(Addressable::URI::InvalidURIError, /'123'/) + end + + it "should raise an error if the scheme begins with a digit" do + expect do + @uri.scheme = "1scheme" + end.to raise_error(Addressable::URI::InvalidURIError, /'1scheme'/) + end + + it "should raise an error if the scheme begins with a plus" do + expect do + @uri.scheme = "+scheme" + end.to raise_error(Addressable::URI::InvalidURIError, /'\+scheme'/) + end + + it "should raise an error if the scheme begins with a dot" do + expect do + @uri.scheme = ".scheme" + end.to raise_error(Addressable::URI::InvalidURIError, /'\.scheme'/) + end + + it "should raise an error if the scheme begins with a dash" do + expect do + @uri.scheme = "-scheme" + end.to raise_error(Addressable::URI::InvalidURIError, /'-scheme'/) + end + + it "should raise an error if the scheme contains an illegal character" do + expect do + @uri.scheme = "scheme!" + end.to raise_error(Addressable::URI::InvalidURIError, /'scheme!'/) + end + + it "should raise an error if the scheme contains whitespace" do + expect do + @uri.scheme = "sch eme" + end.to raise_error(Addressable::URI::InvalidURIError, /'sch eme'/) + end + + it "should raise an error if the scheme contains a newline" do + expect do + @uri.scheme = "sch\neme" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + expect do + @uri.user = "user" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + expect do + @uri.password = "pass" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + expect do + @uri.scheme = "http" + @uri.fragment = "fragment" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should raise an error if set into an invalid state" do + expect do + @uri.fragment = "fragment" + @uri.scheme = "http" + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when initialized from individual components" do + before do + @uri = Addressable::URI.new( + :scheme => "http", + :user => "user", + :password => "password", + :host => "example.com", + :port => 8080, + :path => "/path", + :query => "query=value", + :fragment => "fragment" + ) + end + + it "returns 'http' for #scheme" do + expect(@uri.scheme).to eq("http") + end + + it "returns 'http' for #normalized_scheme" do + expect(@uri.normalized_scheme).to eq("http") + end + + it "returns 'user' for #user" do + expect(@uri.user).to eq("user") + end + + it "returns 'user' for #normalized_user" do + expect(@uri.normalized_user).to eq("user") + end + + it "returns 'password' for #password" do + expect(@uri.password).to eq("password") + end + + it "returns 'password' for #normalized_password" do + expect(@uri.normalized_password).to eq("password") + end + + it "returns 'user:password' for #userinfo" do + expect(@uri.userinfo).to eq("user:password") + end + + it "returns 'user:password' for #normalized_userinfo" do + expect(@uri.normalized_userinfo).to eq("user:password") + end + + it "returns 'example.com' for #host" do + expect(@uri.host).to eq("example.com") + end + + it "returns 'example.com' for #normalized_host" do + expect(@uri.normalized_host).to eq("example.com") + end + + it "returns 'com' for #tld" do + expect(@uri.tld).to eq("com") + end + + it "returns 'user:password@example.com:8080' for #authority" do + expect(@uri.authority).to eq("user:password@example.com:8080") + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + expect(@uri.normalized_authority).to eq("user:password@example.com:8080") + end + + it "returns 8080 for #port" do + expect(@uri.port).to eq(8080) + end + + it "returns 8080 for #normalized_port" do + expect(@uri.normalized_port).to eq(8080) + end + + it "returns 80 for #default_port" do + expect(@uri.default_port).to eq(80) + end + + it "returns 'http://user:password@example.com:8080' for #site" do + expect(@uri.site).to eq("http://user:password@example.com:8080") + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") + end + + it "returns '/path' for #path" do + expect(@uri.path).to eq("/path") + end + + it "returns '/path' for #normalized_path" do + expect(@uri.normalized_path).to eq("/path") + end + + it "returns 'query=value' for #query" do + expect(@uri.query).to eq("query=value") + end + + it "returns 'query=value' for #normalized_query" do + expect(@uri.normalized_query).to eq("query=value") + end + + it "returns 'fragment' for #fragment" do + expect(@uri.fragment).to eq("fragment") + end + + it "returns 'fragment' for #normalized_fragment" do + expect(@uri.normalized_fragment).to eq("fragment") + end + + it "returns #hash" do + expect(@uri.hash).not_to be nil + end + + it "returns #to_s" do + expect(@uri.to_s).to eq( + "http://user:password@example.com:8080/path?query=value#fragment" + ) + end + + it "should not be empty" do + expect(@uri).not_to be_empty + end + + it "should not be frozen" do + expect(@uri).not_to be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when initialized from " + + "frozen individual components" do + before do + @uri = Addressable::URI.new( + :scheme => "http".freeze, + :user => "user".freeze, + :password => "password".freeze, + :host => "example.com".freeze, + :port => "8080".freeze, + :path => "/path".freeze, + :query => "query=value".freeze, + :fragment => "fragment".freeze + ) + end + + it "returns 'http' for #scheme" do + expect(@uri.scheme).to eq("http") + end + + it "returns 'http' for #normalized_scheme" do + expect(@uri.normalized_scheme).to eq("http") + end + + it "returns 'user' for #user" do + expect(@uri.user).to eq("user") + end + + it "returns 'user' for #normalized_user" do + expect(@uri.normalized_user).to eq("user") + end + + it "returns 'password' for #password" do + expect(@uri.password).to eq("password") + end + + it "returns 'password' for #normalized_password" do + expect(@uri.normalized_password).to eq("password") + end + + it "returns 'user:password' for #userinfo" do + expect(@uri.userinfo).to eq("user:password") + end + + it "returns 'user:password' for #normalized_userinfo" do + expect(@uri.normalized_userinfo).to eq("user:password") + end + + it "returns 'example.com' for #host" do + expect(@uri.host).to eq("example.com") + end + + it "returns 'example.com' for #normalized_host" do + expect(@uri.normalized_host).to eq("example.com") + end + + it "returns 'user:password@example.com:8080' for #authority" do + expect(@uri.authority).to eq("user:password@example.com:8080") + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + expect(@uri.normalized_authority).to eq("user:password@example.com:8080") + end + + it "returns 8080 for #port" do + expect(@uri.port).to eq(8080) + end + + it "returns 8080 for #normalized_port" do + expect(@uri.normalized_port).to eq(8080) + end + + it "returns 80 for #default_port" do + expect(@uri.default_port).to eq(80) + end + + it "returns 'http://user:password@example.com:8080' for #site" do + expect(@uri.site).to eq("http://user:password@example.com:8080") + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") + end + + it "returns '/path' for #path" do + expect(@uri.path).to eq("/path") + end + + it "returns '/path' for #normalized_path" do + expect(@uri.normalized_path).to eq("/path") + end + + it "returns 'query=value' for #query" do + expect(@uri.query).to eq("query=value") + end + + it "returns 'query=value' for #normalized_query" do + expect(@uri.normalized_query).to eq("query=value") + end + + it "returns 'fragment' for #fragment" do + expect(@uri.fragment).to eq("fragment") + end + + it "returns 'fragment' for #normalized_fragment" do + expect(@uri.normalized_fragment).to eq("fragment") + end + + it "returns #hash" do + expect(@uri.hash).not_to be nil + end + + it "returns #to_s" do + expect(@uri.to_s).to eq( + "http://user:password@example.com:8080/path?query=value#fragment" + ) + end + + it "should not be empty" do + expect(@uri).not_to be_empty + end + + it "should not be frozen" do + expect(@uri).not_to be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when parsed from a frozen string" do + before do + @uri = Addressable::URI.parse( + "http://user:password@example.com:8080/path?query=value#fragment".freeze + ) + end + + it "returns 'http' for #scheme" do + expect(@uri.scheme).to eq("http") + end + + it "returns 'http' for #normalized_scheme" do + expect(@uri.normalized_scheme).to eq("http") + end + + it "returns 'user' for #user" do + expect(@uri.user).to eq("user") + end + + it "returns 'user' for #normalized_user" do + expect(@uri.normalized_user).to eq("user") + end + + it "returns 'password' for #password" do + expect(@uri.password).to eq("password") + end + + it "returns 'password' for #normalized_password" do + expect(@uri.normalized_password).to eq("password") + end + + it "returns 'user:password' for #userinfo" do + expect(@uri.userinfo).to eq("user:password") + end + + it "returns 'user:password' for #normalized_userinfo" do + expect(@uri.normalized_userinfo).to eq("user:password") + end + + it "returns 'example.com' for #host" do + expect(@uri.host).to eq("example.com") + end + + it "returns 'example.com' for #normalized_host" do + expect(@uri.normalized_host).to eq("example.com") + end + + it "returns 'user:password@example.com:8080' for #authority" do + expect(@uri.authority).to eq("user:password@example.com:8080") + end + + it "returns 'user:password@example.com:8080' for #normalized_authority" do + expect(@uri.normalized_authority).to eq("user:password@example.com:8080") + end + + it "returns 8080 for #port" do + expect(@uri.port).to eq(8080) + end + + it "returns 8080 for #normalized_port" do + expect(@uri.normalized_port).to eq(8080) + end + + it "returns 80 for #default_port" do + expect(@uri.default_port).to eq(80) + end + + it "returns 'http://user:password@example.com:8080' for #site" do + expect(@uri.site).to eq("http://user:password@example.com:8080") + end + + it "returns 'http://user:password@example.com:8080' for #normalized_site" do + expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") + end + + it "returns '/path' for #path" do + expect(@uri.path).to eq("/path") + end + + it "returns '/path' for #normalized_path" do + expect(@uri.normalized_path).to eq("/path") + end + + it "returns 'query=value' for #query" do + expect(@uri.query).to eq("query=value") + end + + it "returns 'query=value' for #normalized_query" do + expect(@uri.normalized_query).to eq("query=value") + end + + it "returns 'fragment' for #fragment" do + expect(@uri.fragment).to eq("fragment") + end + + it "returns 'fragment' for #normalized_fragment" do + expect(@uri.normalized_fragment).to eq("fragment") + end + + it "returns #hash" do + expect(@uri.hash).not_to be nil + end + + it "returns #to_s" do + expect(@uri.to_s).to eq( + "http://user:password@example.com:8080/path?query=value#fragment" + ) + end + + it "should not be empty" do + expect(@uri).not_to be_empty + end + + it "should not be frozen" do + expect(@uri).not_to be_frozen + end + + it "should allow destructive operations" do + expect { @uri.normalize! }.not_to raise_error + end +end + +describe Addressable::URI, "when frozen" do + before do + @uri = Addressable::URI.new.freeze + end + + it "returns nil for #scheme" do + expect(@uri.scheme).to eq(nil) + end + + it "returns nil for #normalized_scheme" do + expect(@uri.normalized_scheme).to eq(nil) + end + + it "returns nil for #user" do + expect(@uri.user).to eq(nil) + end + + it "returns nil for #normalized_user" do + expect(@uri.normalized_user).to eq(nil) + end + + it "returns nil for #password" do + expect(@uri.password).to eq(nil) + end + + it "returns nil for #normalized_password" do + expect(@uri.normalized_password).to eq(nil) + end + + it "returns nil for #userinfo" do + expect(@uri.userinfo).to eq(nil) + end + + it "returns nil for #normalized_userinfo" do + expect(@uri.normalized_userinfo).to eq(nil) + end + + it "returns nil for #host" do + expect(@uri.host).to eq(nil) + end + + it "returns nil for #normalized_host" do + expect(@uri.normalized_host).to eq(nil) + end + + it "returns nil for #authority" do + expect(@uri.authority).to eq(nil) + end + + it "returns nil for #normalized_authority" do + expect(@uri.normalized_authority).to eq(nil) + end + + it "returns nil for #port" do + expect(@uri.port).to eq(nil) + end + + it "returns nil for #normalized_port" do + expect(@uri.normalized_port).to eq(nil) + end + + it "returns nil for #default_port" do + expect(@uri.default_port).to eq(nil) + end + + it "returns nil for #site" do + expect(@uri.site).to eq(nil) + end + + it "returns nil for #normalized_site" do + expect(@uri.normalized_site).to eq(nil) + end + + it "returns '' for #path" do + expect(@uri.path).to eq('') + end + + it "returns '' for #normalized_path" do + expect(@uri.normalized_path).to eq('') + end + + it "returns nil for #query" do + expect(@uri.query).to eq(nil) + end + + it "returns nil for #normalized_query" do + expect(@uri.normalized_query).to eq(nil) + end + + it "returns nil for #fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "returns nil for #normalized_fragment" do + expect(@uri.normalized_fragment).to eq(nil) + end + + it "returns #hash" do + expect(@uri.hash).not_to be nil + end + + it "returns #to_s" do + expect(@uri.to_s).to eq('') + end + + it "should be empty" do + expect(@uri).to be_empty + end + + it "should be frozen" do + expect(@uri).to be_frozen + end + + it "should not be frozen after duping" do + expect(@uri.dup).not_to be_frozen + end + + it "should not allow destructive operations" do + expect { @uri.normalize! }.to raise_error { |error| + expect(error.message).to match(/can't modify frozen/) + expect(error).to satisfy { |e| RuntimeError === e || TypeError === e } + } + end +end + +describe Addressable::URI, "when frozen" do + before do + @uri = Addressable::URI.parse( + "HTTP://example.com.:%38%30/%70a%74%68?a=%31#1%323" + ).freeze + end + + it "returns 'HTTP' for #scheme" do + expect(@uri.scheme).to eq("HTTP") + end + + it "returns 'http' for #normalized_scheme" do + expect(@uri.normalized_scheme).to eq("http") + expect(@uri.normalize.scheme).to eq("http") + end + + it "returns nil for #user" do + expect(@uri.user).to eq(nil) + end + + it "returns nil for #normalized_user" do + expect(@uri.normalized_user).to eq(nil) + end + + it "returns nil for #password" do + expect(@uri.password).to eq(nil) + end + + it "returns nil for #normalized_password" do + expect(@uri.normalized_password).to eq(nil) + end + + it "returns nil for #userinfo" do + expect(@uri.userinfo).to eq(nil) + end + + it "returns nil for #normalized_userinfo" do + expect(@uri.normalized_userinfo).to eq(nil) + end + + it "returns 'example.com.' for #host" do + expect(@uri.host).to eq("example.com.") + end + + it "returns nil for #normalized_host" do + expect(@uri.normalized_host).to eq("example.com") + expect(@uri.normalize.host).to eq("example.com") + end + + it "returns 'example.com.:80' for #authority" do + expect(@uri.authority).to eq("example.com.:80") + end + + it "returns 'example.com:80' for #normalized_authority" do + expect(@uri.normalized_authority).to eq("example.com") + expect(@uri.normalize.authority).to eq("example.com") + end + + it "returns 80 for #port" do + expect(@uri.port).to eq(80) + end + + it "returns nil for #normalized_port" do + expect(@uri.normalized_port).to eq(nil) + expect(@uri.normalize.port).to eq(nil) + end + + it "returns 80 for #default_port" do + expect(@uri.default_port).to eq(80) + end + + it "returns 'HTTP://example.com.:80' for #site" do + expect(@uri.site).to eq("HTTP://example.com.:80") + end + + it "returns 'http://example.com' for #normalized_site" do + expect(@uri.normalized_site).to eq("http://example.com") + expect(@uri.normalize.site).to eq("http://example.com") + end + + it "returns '/%70a%74%68' for #path" do + expect(@uri.path).to eq("/%70a%74%68") + end + + it "returns '/path' for #normalized_path" do + expect(@uri.normalized_path).to eq("/path") + expect(@uri.normalize.path).to eq("/path") + end + + it "returns 'a=%31' for #query" do + expect(@uri.query).to eq("a=%31") + end + + it "returns 'a=1' for #normalized_query" do + expect(@uri.normalized_query).to eq("a=1") + expect(@uri.normalize.query).to eq("a=1") + end + + it "returns '/%70a%74%68?a=%31' for #request_uri" do + expect(@uri.request_uri).to eq("/%70a%74%68?a=%31") + end + + it "returns '1%323' for #fragment" do + expect(@uri.fragment).to eq("1%323") + end + + it "returns '123' for #normalized_fragment" do + expect(@uri.normalized_fragment).to eq("123") + expect(@uri.normalize.fragment).to eq("123") + end + + it "returns #hash" do + expect(@uri.hash).not_to be nil + end + + it "returns #to_s" do + expect(@uri.to_s).to eq('HTTP://example.com.:80/%70a%74%68?a=%31#1%323') + expect(@uri.normalize.to_s).to eq('http://example.com/path?a=1#123') + end + + it "should not be empty" do + expect(@uri).not_to be_empty + end + + it "should be frozen" do + expect(@uri).to be_frozen + end + + it "should not be frozen after duping" do + expect(@uri.dup).not_to be_frozen + end + + it "should not allow destructive operations" do + expect { @uri.normalize! }.to raise_error { |error| + expect(error.message).to match(/can't modify frozen/) + expect(error).to satisfy { |e| RuntimeError === e || TypeError === e } + } + end +end + +describe Addressable::URI, "when normalized and then deeply frozen" do + before do + @uri = Addressable::URI.parse( + "http://user:password@example.com:8080/path?query=value#fragment" + ).normalize! + + @uri.instance_variables.each do |var| + @uri.instance_variable_set(var, @uri.instance_variable_get(var).freeze) + end + + @uri.freeze + end + + it "#normalized_scheme should not error" do + expect { @uri.normalized_scheme }.not_to raise_error + end + + it "#normalized_user should not error" do + expect { @uri.normalized_user }.not_to raise_error + end + + it "#normalized_password should not error" do + expect { @uri.normalized_password }.not_to raise_error + end + + it "#normalized_userinfo should not error" do + expect { @uri.normalized_userinfo }.not_to raise_error + end + + it "#normalized_host should not error" do + expect { @uri.normalized_host }.not_to raise_error + end + + it "#normalized_authority should not error" do + expect { @uri.normalized_authority }.not_to raise_error + end + + it "#normalized_port should not error" do + expect { @uri.normalized_port }.not_to raise_error + end + + it "#normalized_site should not error" do + expect { @uri.normalized_site }.not_to raise_error + end + + it "#normalized_path should not error" do + expect { @uri.normalized_path }.not_to raise_error + end + + it "#normalized_query should not error" do + expect { @uri.normalized_query }.not_to raise_error + end + + it "#normalized_fragment should not error" do + expect { @uri.normalized_fragment }.not_to raise_error + end + + it "should be frozen" do + expect(@uri).to be_frozen + end + + it "should not allow destructive operations" do + expect { @uri.normalize! }.to raise_error(RuntimeError) + end +end + +describe Addressable::URI, "when created from string components" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :host => "example.com" + ) + end + + it "should have a site value of 'http://example.com'" do + expect(@uri.site).to eq("http://example.com") + end + + it "should be equal to the equivalent parsed URI" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + it "should raise an error if invalid components omitted" do + expect do + @uri.omit(:bogus) + end.to raise_error(ArgumentError) + expect do + @uri.omit(:scheme, :bogus, :path) + end.to raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with a nil host but " + + "non-nil authority components" do + it "should raise an error" do + expect do + Addressable::URI.new(:user => "user", :password => "pass", :port => 80) + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with both an authority and a user" do + it "should raise an error" do + expect do + Addressable::URI.new( + :user => "user", :authority => "user@example.com:80" + ) + end.to raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with an authority and no port" do + before do + @uri = Addressable::URI.new(:authority => "user@example.com") + end + + it "should not infer a port" do + expect(@uri.port).to eq(nil) + expect(@uri.default_port).to eq(nil) + expect(@uri.inferred_port).to eq(nil) + end + + it "should have a site value of '//user@example.com'" do + expect(@uri.site).to eq("//user@example.com") + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when created with a host with trailing dots" do + before do + @uri = Addressable::URI.new(:authority => "example...") + end + + it "should have a stable normalized form" do + expect(@uri.normalize.normalize.normalize.host).to eq( + @uri.normalize.host + ) + end +end + +describe Addressable::URI, "when created with a host with a backslash" do + it "should raise an error" do + expect do + Addressable::URI.new(:authority => "example\\example") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a host with a slash" do + it "should raise an error" do + expect do + Addressable::URI.new(:authority => "example/example") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with a host with a space" do + it "should raise an error" do + expect do + Addressable::URI.new(:authority => "example example") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when created with both a userinfo and a user" do + it "should raise an error" do + expect do + Addressable::URI.new(:user => "user", :userinfo => "user:pass") + end.to raise_error(ArgumentError) + end +end + +describe Addressable::URI, "when created with a path that hasn't been " + + "prefixed with a '/' but a host specified" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :host => "example.com", :path => "path" + ) + end + + it "should prefix a '/' to the path" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/path")) + end + + it "should have a site value of 'http://example.com'" do + expect(@uri.site).to eq("http://example.com") + end + + it "should have an origin of 'http://example.com" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when created with a path that hasn't been " + + "prefixed with a '/' but no host specified" do + before do + @uri = Addressable::URI.new( + :scheme => "http", :path => "path" + ) + end + + it "should not prefix a '/' to the path" do + expect(@uri).to eq(Addressable::URI.parse("http:path")) + end + + it "should have a site value of 'http:'" do + expect(@uri.site).to eq("http:") + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from an Addressable::URI object" do + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.parse(original_uri) + new_uri.host = 'www.example.com' + expect(new_uri.host).to eq('www.example.com') + expect(new_uri.to_s).to eq('http://www.example.com/') + expect(original_uri.host).to eq('example.com') + expect(original_uri.to_s).to eq('http://example.com/') + end + + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.heuristic_parse(original_uri) + new_uri.host = 'www.example.com' + expect(new_uri.host).to eq('www.example.com') + expect(new_uri.to_s).to eq('http://www.example.com/') + expect(original_uri.host).to eq('example.com') + expect(original_uri.to_s).to eq('http://example.com/') + end + + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.parse(original_uri) + new_uri.origin = 'https://www.example.com:8080' + expect(new_uri.host).to eq('www.example.com') + expect(new_uri.to_s).to eq('https://www.example.com:8080/') + expect(original_uri.host).to eq('example.com') + expect(original_uri.to_s).to eq('http://example.com/') + end + + it "should not have unexpected side-effects" do + original_uri = Addressable::URI.parse("http://example.com/") + new_uri = Addressable::URI.heuristic_parse(original_uri) + new_uri.origin = 'https://www.example.com:8080' + expect(new_uri.host).to eq('www.example.com') + expect(new_uri.to_s).to eq('https://www.example.com:8080/') + expect(original_uri.host).to eq('example.com') + expect(original_uri.to_s).to eq('http://example.com/') + end +end + +describe Addressable::URI, "when parsed from something that looks " + + "like a URI object" do + it "should parse without error" do + uri = Addressable::URI.parse(Fake::URI::HTTP.new("http://example.com/")) + expect do + Addressable::URI.parse(uri) + end.not_to raise_error + end +end + +describe Addressable::URI, "when parsed from a standard library URI object" do + it "should parse without error" do + uri = Addressable::URI.parse(URI.parse("http://example.com/")) + expect do + Addressable::URI.parse(uri) + end.not_to raise_error + end +end + +describe Addressable::URI, "when parsed from ''" do + before do + @uri = Addressable::URI.parse("") + end + + it "should have no scheme" do + expect(@uri.scheme).to eq(nil) + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of ''" do + expect(@uri.path).to eq("") + end + + it "should have a request URI of '/'" do + expect(@uri.request_uri).to eq("/") + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'ftp://ftp.is.co.za/rfc/rfc1808.txt'" do + before do + @uri = Addressable::URI.parse("ftp://ftp.is.co.za/rfc/rfc1808.txt") + end + + it "should use the 'ftp' scheme" do + expect(@uri.scheme).to eq("ftp") + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a host of 'ftp.is.co.za'" do + expect(@uri.host).to eq("ftp.is.co.za") + end + + it "should have inferred_port of 21" do + expect(@uri.inferred_port).to eq(21) + end + + it "should have a path of '/rfc/rfc1808.txt'" do + expect(@uri.path).to eq("/rfc/rfc1808.txt") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have an origin of 'ftp://ftp.is.co.za'" do + expect(@uri.origin).to eq('ftp://ftp.is.co.za') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'http://www.ietf.org/rfc/rfc2396.txt'" do + before do + @uri = Addressable::URI.parse("http://www.ietf.org/rfc/rfc2396.txt") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a host of 'www.ietf.org'" do + expect(@uri.host).to eq("www.ietf.org") + end + + it "should have inferred_port of 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/rfc/rfc2396.txt'" do + expect(@uri.path).to eq("/rfc/rfc2396.txt") + end + + it "should have a request URI of '/rfc/rfc2396.txt'" do + expect(@uri.request_uri).to eq("/rfc/rfc2396.txt") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should correctly omit components" do + expect(@uri.omit(:scheme).to_s).to eq("//www.ietf.org/rfc/rfc2396.txt") + expect(@uri.omit(:path).to_s).to eq("http://www.ietf.org") + end + + it "should correctly omit components destructively" do + @uri.omit!(:scheme) + expect(@uri.to_s).to eq("//www.ietf.org/rfc/rfc2396.txt") + end + + it "should have an origin of 'http://www.ietf.org'" do + expect(@uri.origin).to eq('http://www.ietf.org') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'ldap://[2001:db8::7]/c=GB?objectClass?one'" do + before do + @uri = Addressable::URI.parse("ldap://[2001:db8::7]/c=GB?objectClass?one") + end + + it "should use the 'ldap' scheme" do + expect(@uri.scheme).to eq("ldap") + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a host of '[2001:db8::7]'" do + expect(@uri.host).to eq("[2001:db8::7]") + end + + it "should have inferred_port of 389" do + expect(@uri.inferred_port).to eq(389) + end + + it "should have a path of '/c=GB'" do + expect(@uri.path).to eq("/c=GB") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should not allow request URI assignment" do + expect do + @uri.request_uri = "/" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should have a query of 'objectClass?one'" do + expect(@uri.query).to eq("objectClass?one") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should correctly omit components" do + expect(@uri.omit(:scheme, :authority).to_s).to eq("/c=GB?objectClass?one") + expect(@uri.omit(:path).to_s).to eq("ldap://[2001:db8::7]?objectClass?one") + end + + it "should correctly omit components destructively" do + @uri.omit!(:scheme, :authority) + expect(@uri.to_s).to eq("/c=GB?objectClass?one") + end + + it "should raise an error if omission would create an invalid URI" do + expect do + @uri.omit(:authority, :path) + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should have an origin of 'ldap://[2001:db8::7]'" do + expect(@uri.origin).to eq('ldap://[2001:db8::7]') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'mailto:John.Doe@example.com'" do + before do + @uri = Addressable::URI.parse("mailto:John.Doe@example.com") + end + + it "should use the 'mailto' scheme" do + expect(@uri.scheme).to eq("mailto") + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should not have an inferred_port" do + expect(@uri.inferred_port).to eq(nil) + end + + it "should have a path of 'John.Doe@example.com'" do + expect(@uri.path).to eq("John.Doe@example.com") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +# Section 2 of RFC 6068 +describe Addressable::URI, "when parsed from " + + "'mailto:?to=addr1@an.example,addr2@an.example'" do + before do + @uri = Addressable::URI.parse( + "mailto:?to=addr1@an.example,addr2@an.example" + ) + end + + it "should use the 'mailto' scheme" do + expect(@uri.scheme).to eq("mailto") + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should not have an inferred_port" do + expect(@uri.inferred_port).to eq(nil) + end + + it "should have a path of ''" do + expect(@uri.path).to eq("") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should have the To: field value parameterized" do + expect(@uri.query_values(Hash)["to"]).to eq( + "addr1@an.example,addr2@an.example" + ) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'news:comp.infosystems.www.servers.unix'" do + before do + @uri = Addressable::URI.parse("news:comp.infosystems.www.servers.unix") + end + + it "should use the 'news' scheme" do + expect(@uri.scheme).to eq("news") + end + + it "should not have an inferred_port" do + expect(@uri.inferred_port).to eq(nil) + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of 'comp.infosystems.www.servers.unix'" do + expect(@uri.path).to eq("comp.infosystems.www.servers.unix") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'tel:+1-816-555-1212'" do + before do + @uri = Addressable::URI.parse("tel:+1-816-555-1212") + end + + it "should use the 'tel' scheme" do + expect(@uri.scheme).to eq("tel") + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should not have an inferred_port" do + expect(@uri.inferred_port).to eq(nil) + end + + it "should have a path of '+1-816-555-1212'" do + expect(@uri.path).to eq("+1-816-555-1212") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'telnet://192.0.2.16:80/'" do + before do + @uri = Addressable::URI.parse("telnet://192.0.2.16:80/") + end + + it "should use the 'telnet' scheme" do + expect(@uri.scheme).to eq("telnet") + end + + it "should have a host of '192.0.2.16'" do + expect(@uri.host).to eq("192.0.2.16") + end + + it "should have a port of 80" do + expect(@uri.port).to eq(80) + end + + it "should have a inferred_port of 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a default_port of 23" do + expect(@uri.default_port).to eq(23) + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a path of '/'" do + expect(@uri.path).to eq("/") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have an origin of 'telnet://192.0.2.16:80'" do + expect(@uri.origin).to eq('telnet://192.0.2.16:80') + end +end + +# Section 1.1.2 of RFC 3986 +describe Addressable::URI, "when parsed from " + + "'urn:oasis:names:specification:docbook:dtd:xml:4.1.2'" do + before do + @uri = Addressable::URI.parse( + "urn:oasis:names:specification:docbook:dtd:xml:4.1.2") + end + + it "should use the 'urn' scheme" do + expect(@uri.scheme).to eq("urn") + end + + it "should not have an inferred_port" do + expect(@uri.inferred_port).to eq(nil) + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of " + + "'oasis:names:specification:docbook:dtd:xml:4.1.2'" do + expect(@uri.path).to eq("oasis:names:specification:docbook:dtd:xml:4.1.2") + end + + it "should not have a request URI" do + expect(@uri.request_uri).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when heuristically parsed from " + + "'192.0.2.16:8000/path'" do + before do + @uri = Addressable::URI.heuristic_parse("192.0.2.16:8000/path") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a host of '192.0.2.16'" do + expect(@uri.host).to eq("192.0.2.16") + end + + it "should have a port of '8000'" do + expect(@uri.port).to eq(8000) + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a path of '/path'" do + expect(@uri.path).to eq("/path") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have an origin of 'http://192.0.2.16:8000'" do + expect(@uri.origin).to eq('http://192.0.2.16:8000') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com'" do + before do + @uri = Addressable::URI.parse("http://example.com") + end + + it "when inspected, should have the correct URI" do + expect(@uri.inspect).to include("http://example.com") + end + + it "when inspected, should have the correct class name" do + expect(@uri.inspect).to include("Addressable::URI") + end + + it "when inspected, should have the correct object id" do + expect(@uri.inspect).to include("%#0x" % @uri.object_id) + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should be considered ip-based" do + expect(@uri).to be_ip_based + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not have a specified port" do + expect(@uri.port).to eq(nil) + end + + it "should have an empty path" do + expect(@uri.path).to eq("") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + expect(@uri.query_values).to eq(nil) + end + + it "should have a request URI of '/'" do + expect(@uri.request_uri).to eq("/") + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should not be considered relative" do + expect(@uri).not_to be_relative + end + + it "should not be exactly equal to 42" do + expect(@uri.eql?(42)).to eq(false) + end + + it "should not be equal to 42" do + expect(@uri == 42).to eq(false) + end + + it "should not be roughly equal to 42" do + expect(@uri === 42).to eq(false) + end + + it "should be exactly equal to http://example.com" do + expect(@uri.eql?(Addressable::URI.parse("http://example.com"))).to eq(true) + end + + it "should be roughly equal to http://example.com/" do + expect(@uri === Addressable::URI.parse("http://example.com/")).to eq(true) + end + + it "should be roughly equal to the string 'http://example.com/'" do + expect(@uri === "http://example.com/").to eq(true) + end + + it "should not be roughly equal to the string " + + "'http://example.com:bogus/'" do + expect do + expect(@uri === "http://example.com:bogus/").to eq(false) + end.not_to raise_error + end + + it "should result in itself when joined with itself" do + expect(@uri.join(@uri).to_s).to eq("http://example.com") + expect(@uri.join!(@uri).to_s).to eq("http://example.com") + end + + it "should be equivalent to http://EXAMPLE.com" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com")) + end + + it "should be equivalent to http://EXAMPLE.com:80/" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com:80/")) + end + + it "should have the same hash as http://example.com" do + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com").hash) + end + + it "should have the same hash as http://EXAMPLE.com after assignment" do + @uri.origin = "http://EXAMPLE.com" + expect(@uri.hash).to eq(Addressable::URI.parse("http://EXAMPLE.com").hash) + end + + it "should have a different hash from http://EXAMPLE.com" do + expect(@uri.hash).not_to eq(Addressable::URI.parse("http://EXAMPLE.com").hash) + end + + it "should not allow origin assignment without scheme" do + expect do + @uri.origin = "example.com" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow origin assignment without host" do + expect do + @uri.origin = "http://" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow origin assignment with bogus type" do + expect do + @uri.origin = :bogus + end.to raise_error(TypeError) + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/")) + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com:/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) + end + + # Section 6.2.3 of RFC 3986 + it "should be equivalent to http://example.com:80/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) + end + + # Section 6.2.2.1 of RFC 3986 + it "should be equivalent to http://EXAMPLE.COM/" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.COM/")) + end + + it "should have a route of '/path/' to 'http://example.com/path/'" do + expect(@uri.route_to("http://example.com/path/")).to eq( + Addressable::URI.parse("/path/") + ) + end + + it "should have a route of '..' from 'http://example.com/path/'" do + expect(@uri.route_from("http://example.com/path/")).to eq( + Addressable::URI.parse("..") + ) + end + + it "should have a route of '#' to 'http://example.com/'" do + expect(@uri.route_to("http://example.com/")).to eq( + Addressable::URI.parse("#") + ) + end + + it "should have a route of 'http://elsewhere.com/' to " + + "'http://elsewhere.com/'" do + expect(@uri.route_to("http://elsewhere.com/")).to eq( + Addressable::URI.parse("http://elsewhere.com/") + ) + end + + it "when joined with 'relative/path' should be " + + "'http://example.com/relative/path'" do + expect(@uri.join('relative/path')).to eq( + Addressable::URI.parse("http://example.com/relative/path") + ) + end + + it "when joined with a bogus object a TypeError should be raised" do + expect do + @uri.join(42) + end.to raise_error(TypeError) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq(nil) + expect(@uri.to_s).to eq("http://newuser@example.com") + end + + it "should have the correct username after assignment" do + @uri.user = "user@123!" + expect(@uri.user).to eq("user@123!") + expect(@uri.normalized_user).to eq("user%40123%21") + expect(@uri.password).to eq(nil) + expect(@uri.normalize.to_s).to eq("http://user%40123%21@example.com/") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.user).to eq("") + expect(@uri.to_s).to eq("http://:newpass@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "#secret@123!" + expect(@uri.password).to eq("#secret@123!") + expect(@uri.normalized_password).to eq("%23secret%40123%21") + expect(@uri.user).to eq("") + expect(@uri.normalize.to_s).to eq("http://:%23secret%40123%21@example.com/") + expect(@uri.omit(:password).to_s).to eq("http://example.com") + end + + it "should have the correct user/pass after repeated assignment" do + @uri.user = nil + expect(@uri.user).to eq(nil) + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + # Username cannot be nil if the password is set + expect(@uri.user).to eq("") + expect(@uri.to_s).to eq("http://:newpass@example.com") + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + @uri.password = nil + expect(@uri.password).to eq(nil) + expect(@uri.to_s).to eq("http://newuser@example.com") + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + @uri.password = "" + expect(@uri.password).to eq("") + expect(@uri.to_s).to eq("http://newuser:@example.com") + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + @uri.user = nil + # Username cannot be nil if the password is set + expect(@uri.user).to eq("") + expect(@uri.to_s).to eq("http://:newpass@example.com") + end + + it "should have the correct user/pass after userinfo assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + @uri.userinfo = nil + expect(@uri.userinfo).to eq(nil) + expect(@uri.user).to eq(nil) + expect(@uri.password).to eq(nil) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +# Section 5.1.2 of RFC 2616 +describe Addressable::URI, "when parsed from " + + "'HTTP://www.w3.org/pub/WWW/TheProject.html'" do + before do + @uri = Addressable::URI.parse("HTTP://www.w3.org/pub/WWW/TheProject.html") + end + + it "should have the correct request URI" do + expect(@uri.request_uri).to eq("/pub/WWW/TheProject.html") + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "/pub/WWW/TheProject.html?" + expect(@uri.request_uri).to eq("/pub/WWW/TheProject.html?") + expect(@uri.path).to eq("/pub/WWW/TheProject.html") + expect(@uri.query).to eq("") + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "/some/where/else.html" + expect(@uri.request_uri).to eq("/some/where/else.html") + expect(@uri.path).to eq("/some/where/else.html") + expect(@uri.query).to eq(nil) + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "/some/where/else.html?query?string" + expect(@uri.request_uri).to eq("/some/where/else.html?query?string") + expect(@uri.path).to eq("/some/where/else.html") + expect(@uri.query).to eq("query?string") + end + + it "should have the correct request URI after assignment" do + @uri.request_uri = "?x=y" + expect(@uri.request_uri).to eq("/?x=y") + expect(@uri.path).to eq("/") + expect(@uri.query).to eq("x=y") + end + + it "should raise an error if the site value is set to something bogus" do + expect do + @uri.site = 42 + end.to raise_error(TypeError) + end + + it "should raise an error if the request URI is set to something bogus" do + expect do + @uri.request_uri = 42 + end.to raise_error(TypeError) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "HTTP", + :user => nil, + :password => nil, + :host => "www.w3.org", + :port => nil, + :path => "/pub/WWW/TheProject.html", + :query => nil, + :fragment => nil + }) + end + + it "should have an origin of 'http://www.w3.org'" do + expect(@uri.origin).to eq('http://www.w3.org') + end +end + +describe Addressable::URI, "when parsing IPv6 addresses" do + it "should not raise an error for " + + "'http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[fe80:0:0:0:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[fe80:0:0:0:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[fe80::200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[fe80::200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[::1]/'" do + Addressable::URI.parse("http://[::1]/") + end + + it "should not raise an error for " + + "'http://[fe80::1]/'" do + Addressable::URI.parse("http://[fe80::1]/") + end + + it "should raise an error for " + + "'http://[]/'" do + expect do + Addressable::URI.parse("http://[]/") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsing IPv6 address" do + subject { Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") } + its(:host) { should == '[3ffe:1900:4545:3:200:f8ff:fe21:67cf]' } + its(:hostname) { should == '3ffe:1900:4545:3:200:f8ff:fe21:67cf' } +end + +describe Addressable::URI, "when assigning IPv6 address" do + it "should allow to set bare IPv6 address as hostname" do + uri = Addressable::URI.parse("http://[::1]/") + uri.hostname = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' + expect(uri.to_s).to eq('http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/') + end + + it "should allow to set bare IPv6 address as hostname with IPAddr object" do + uri = Addressable::URI.parse("http://[::1]/") + uri.hostname = IPAddr.new('3ffe:1900:4545:3:200:f8ff:fe21:67cf') + expect(uri.to_s).to eq('http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/') + end + + it "should not allow to set bare IPv6 address as host" do + uri = Addressable::URI.parse("http://[::1]/") + skip "not checked" + expect do + uri.host = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsing IPvFuture addresses" do + it "should not raise an error for " + + "'http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[v12.fe80::200:f8ff:fe21:67cf]/'" do + Addressable::URI.parse("http://[v12.fe80::200:f8ff:fe21:67cf]/") + end + + it "should not raise an error for " + + "'http://[va0.::1]/'" do + Addressable::URI.parse("http://[va0.::1]/") + end + + it "should not raise an error for " + + "'http://[v255.fe80::1]/'" do + Addressable::URI.parse("http://[v255.fe80::1]/") + end + + it "should raise an error for " + + "'http://[v0.]/'" do + expect do + Addressable::URI.parse("http://[v0.]/") + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/'" do + before do + @uri = Addressable::URI.parse("http://example.com/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to HTTP://example.com/" do + expect(@uri).to eq(Addressable::URI.parse("HTTP://example.com/")) + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com:/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com:80/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://Example.com/" do + expect(@uri).to eq(Addressable::URI.parse("http://Example.com/")) + end + + it "should have the correct username after assignment" do + @uri.user = nil + expect(@uri.user).to eq(nil) + expect(@uri.password).to eq(nil) + expect(@uri.to_s).to eq("http://example.com/") + end + + it "should have the correct password after assignment" do + @uri.password = nil + expect(@uri.password).to eq(nil) + expect(@uri.user).to eq(nil) + expect(@uri.to_s).to eq("http://example.com/") + end + + it "should have a request URI of '/'" do + expect(@uri.request_uri).to eq("/") + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have the same hash as its duplicate" do + expect(@uri.hash).to eq(@uri.dup.hash) + end + + it "should have a different hash from its equivalent String value" do + expect(@uri.hash).not_to eq(@uri.to_s.hash) + end + + it "should have the same hash as an equal URI" do + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/").hash) + end + + it "should be equivalent to http://EXAMPLE.com" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com")) + end + + it "should be equivalent to http://EXAMPLE.com:80/" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com:80/")) + end + + it "should have the same hash as http://example.com/" do + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/").hash) + end + + it "should have the same hash as http://example.com after assignment" do + @uri.path = "" + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com").hash) + end + + it "should have the same hash as http://example.com/? after assignment" do + @uri.query = "" + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/?").hash) + end + + it "should have the same hash as http://example.com/? after assignment" do + @uri.query_values = {} + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/?").hash) + end + + it "should have the same hash as http://example.com/# after assignment" do + @uri.fragment = "" + expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/#").hash) + end + + it "should have a different hash from http://example.com" do + expect(@uri.hash).not_to eq(Addressable::URI.parse("http://example.com").hash) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com?#'" do + before do + @uri = Addressable::URI.parse("http://example.com?#") + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "", + :query => "", + :fragment => "" + }) + end + + it "should have a request URI of '/?'" do + expect(@uri.request_uri).to eq("/?") + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq("http://example.com") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://@example.com/'" do + before do + @uri = Addressable::URI.parse("http://@example.com/") + end + + it "should be equivalent to http://example.com" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => "", + :password => nil, + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com./'" do + before do + @uri = Addressable::URI.parse("http://example.com./") + end + + it "should be equivalent to http://example.com" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:@example.com/'" do + before do + @uri = Addressable::URI.parse("http://:@example.com/") + end + + it "should be equivalent to http://example.com" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => "", + :password => "", + :host => "example.com", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'HTTP://EXAMPLE.COM/'" do + before do + @uri = Addressable::URI.parse("HTTP://EXAMPLE.COM/") + end + + it "should be equivalent to http://example.com" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com")) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "HTTP", + :user => nil, + :password => nil, + :host => "EXAMPLE.COM", + :port => nil, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end + + it "should have a tld of 'com'" do + expect(@uri.tld).to eq('com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.example.co.uk/'" do + before do + @uri = Addressable::URI.parse("http://www.example.co.uk/") + end + + it "should have an origin of 'http://www.example.co.uk'" do + expect(@uri.origin).to eq('http://www.example.co.uk') + end + + it "should have a tld of 'co.uk'" do + expect(@uri.tld).to eq('co.uk') + end + + it "should have a domain of 'example.co.uk'" do + expect(@uri.domain).to eq('example.co.uk') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://sub_domain.blogspot.com/'" do + before do + @uri = Addressable::URI.parse("http://sub_domain.blogspot.com/") + end + + it "should have an origin of 'http://sub_domain.blogspot.com'" do + expect(@uri.origin).to eq('http://sub_domain.blogspot.com') + end + + it "should have a tld of 'com'" do + expect(@uri.tld).to eq('com') + end + + it "should have a domain of 'blogspot.com'" do + expect(@uri.domain).to eq('blogspot.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/~smith/'" do + before do + @uri = Addressable::URI.parse("http://example.com/~smith/") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com/%7Esmith/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/%7Esmith/")) + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to http://example.com/%7esmith/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/%7esmith/")) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%E8'" do + before do + @uri = Addressable::URI.parse("http://example.com/%E8") + end + + it "should not raise an exception when normalized" do + expect do + @uri.normalize + end.not_to raise_error + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com/%E8" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com/%E8" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path%2Fsegment/'" do + before do + @uri = Addressable::URI.parse("http://example.com/path%2Fsegment/") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should be equal to 'http://example.com/path%2Fsegment/'" do + expect(@uri.normalize).to be_eql( + Addressable::URI.parse("http://example.com/path%2Fsegment/") + ) + end + + it "should not be equal to 'http://example.com/path/segment/'" do + expect(@uri).not_to eq( + Addressable::URI.parse("http://example.com/path/segment/") + ) + end + + it "should not be equal to 'http://example.com/path/segment/'" do + expect(@uri.normalize).not_to be_eql( + Addressable::URI.parse("http://example.com/path/segment/") + ) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?%F6'" do + before do + @uri = Addressable::URI.parse("http://example.com/?%F6") + end + + it "should not raise an exception when normalized" do + expect do + @uri.normalize + end.not_to raise_error + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com/?%F6" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com/?%F6" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/#%F6'" do + before do + @uri = Addressable::URI.parse("http://example.com/#%F6") + end + + it "should not raise an exception when normalized" do + expect do + @uri.normalize + end.not_to raise_error + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com/#%F6" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com/#%F6" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%C3%87'" do + before do + @uri = Addressable::URI.parse("http://example.com/%C3%87") + end + + # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence + it "should be equivalent to 'http://example.com/C%CC%A7'" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/C%CC%A7")) + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com/%C3%87" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com/%C3%87" + end + + it "should raise an error if encoding with an unexpected return type" do + expect do + Addressable::URI.normalized_encode(@uri, Integer) + end.to raise_error(TypeError) + end + + it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do + expect(Addressable::URI.encode(@uri).to_s).to eq( + "http://example.com/%25C3%2587" + ) + end + + it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do + expect(Addressable::URI.encode(@uri, Addressable::URI)).to eq( + Addressable::URI.parse("http://example.com/%25C3%2587") + ) + end + + it "should raise an error if encoding with an unexpected return type" do + expect do + Addressable::URI.encode(@uri, Integer) + end.to raise_error(TypeError) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=string'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=string") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/'" do + expect(@uri.path).to eq("/") + end + + it "should have a query string of 'q=string'" do + expect(@uri.query).to eq("q=string") + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should not be considered relative" do + expect(@uri).not_to be_relative + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:80/'" do + before do + @uri = Addressable::URI.parse("http://example.com:80/") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com:80'" do + expect(@uri.authority).to eq("example.com:80") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have explicit port 80" do + expect(@uri.port).to eq(80) + end + + it "should have a path of '/'" do + expect(@uri.path).to eq("/") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should not be considered relative" do + expect(@uri).not_to be_relative + end + + it "should be exactly equal to http://example.com:80/" do + expect(@uri.eql?(Addressable::URI.parse("http://example.com:80/"))).to eq(true) + end + + it "should be roughly equal to http://example.com/" do + expect(@uri === Addressable::URI.parse("http://example.com/")).to eq(true) + end + + it "should be roughly equal to the string 'http://example.com/'" do + expect(@uri === "http://example.com/").to eq(true) + end + + it "should not be roughly equal to the string " + + "'http://example.com:bogus/'" do + expect do + expect(@uri === "http://example.com:bogus/").to eq(false) + end.not_to raise_error + end + + it "should result in itself when joined with itself" do + expect(@uri.join(@uri).to_s).to eq("http://example.com:80/") + expect(@uri.join!(@uri).to_s).to eq("http://example.com:80/") + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com/")) + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com:/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) + end + + # Section 6.2.3 of RFC 3986 + it "should be equal to http://example.com:80/" do + expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) + end + + # Section 6.2.2.1 of RFC 3986 + it "should be equal to http://EXAMPLE.COM/" do + expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.COM/")) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => 80, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com:80/" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com:80/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:8080/'" do + before do + @uri = Addressable::URI.parse("http://example.com:8080/") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com:8080'" do + expect(@uri.authority).to eq("example.com:8080") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 8080" do + expect(@uri.inferred_port).to eq(8080) + end + + it "should have explicit port 8080" do + expect(@uri.port).to eq(8080) + end + + it "should have default port 80" do + expect(@uri.default_port).to eq(80) + end + + it "should have a path of '/'" do + expect(@uri.path).to eq("/") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should not be considered relative" do + expect(@uri).not_to be_relative + end + + it "should be exactly equal to http://example.com:8080/" do + expect(@uri.eql?(Addressable::URI.parse( + "http://example.com:8080/"))).to eq(true) + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://example.com/path/to/'" do + expect(@uri.route_from("http://example.com/path/to/")).to eq( + Addressable::URI.parse("http://example.com:8080/") + ) + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://example.com:80/path/to/'" do + expect(@uri.route_from("http://example.com:80/path/to/")).to eq( + Addressable::URI.parse("http://example.com:8080/") + ) + end + + it "should have a route of '../../' from " + + "'http://example.com:8080/path/to/'" do + expect(@uri.route_from("http://example.com:8080/path/to/")).to eq( + Addressable::URI.parse("../../") + ) + end + + it "should have a route of 'http://example.com:8080/' from " + + "'http://user:pass@example.com/path/to/'" do + expect(@uri.route_from("http://user:pass@example.com/path/to/")).to eq( + Addressable::URI.parse("http://example.com:8080/") + ) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => 8080, + :path => "/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com:8080'" do + expect(@uri.origin).to eq('http://example.com:8080') + end + + it "should not change if encoded with the normalizing algorithm" do + expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( + "http://example.com:8080/" + ) + expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === + "http://example.com:8080/" + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com:%38%30/'" do + before do + @uri = Addressable::URI.parse("http://example.com:%38%30/") + end + + it "should have the correct port" do + expect(@uri.port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed with empty port" do + subject(:uri) do + Addressable::URI.parse("//example.com:") + end + + it "should not infer a port" do + expect(uri.port).to be(nil) + end + + it "should have a site value of '//example.com'" do + expect(uri.site).to eq("//example.com") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/%2E/'" do + before do + @uri = Addressable::URI.parse("http://example.com/%2E/") + end + + it "should be considered to be in normal form" do + skip( + 'path segment normalization should happen before ' + + 'percent escaping normalization' + ) + @uri.normalize.should be_eql(@uri) + end + + it "should normalize to 'http://example.com/%2E/'" do + skip( + 'path segment normalization should happen before ' + + 'percent escaping normalization' + ) + expect(@uri.normalize).to eq("http://example.com/%2E/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/..") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/../..'" do + before do + @uri = Addressable::URI.parse("http://example.com/../..") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path(/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/path(/..") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/(path)/..'" do + before do + @uri = Addressable::URI.parse("http://example.com/(path)/..") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path(/../'" do + before do + @uri = Addressable::URI.parse("http://example.com/path(/../") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/(path)/../'" do + before do + @uri = Addressable::URI.parse("http://example.com/(path)/../") + end + + it "should have the correct port" do + expect(@uri.inferred_port).to eq(80) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'/..//example.com'" do + before do + @uri = Addressable::URI.parse("/..//example.com") + end + + it "should become invalid when normalized" do + expect do + @uri.normalize + end.to raise_error(Addressable::URI::InvalidURIError, /authority/) + end + + it "should have a path of '/..//example.com'" do + expect(@uri.path).to eq("/..//example.com") + end +end + +describe Addressable::URI, "when parsed from '/a/b/c/./../../g'" do + before do + @uri = Addressable::URI.parse("/a/b/c/./../../g") + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + # Section 5.2.4 of RFC 3986 + it "should normalize to '/a/g'" do + expect(@uri.normalize.to_s).to eq("/a/g") + end +end + +describe Addressable::URI, "when parsed from 'mid/content=5/../6'" do + before do + @uri = Addressable::URI.parse("mid/content=5/../6") + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + # Section 5.2.4 of RFC 3986 + it "should normalize to 'mid/6'" do + expect(@uri.normalize.to_s).to eq("mid/6") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.example.com///../'" do + before do + @uri = Addressable::URI.parse('http://www.example.com///../') + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end + + it "should normalize to 'http://www.example.com//'" do + expect(@uri.normalize.to_s).to eq("http://www.example.com//") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/path/to/resource/'" do + before do + @uri = Addressable::URI.parse("http://example.com/path/to/resource/") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/path/to/resource/'" do + expect(@uri.path).to eq("/path/to/resource/") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should not be considered relative" do + expect(@uri).not_to be_relative + end + + it "should be exactly equal to http://example.com:8080/" do + expect(@uri.eql?(Addressable::URI.parse( + "http://example.com/path/to/resource/"))).to eq(true) + end + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/'" do + expect(@uri.route_from("http://example.com/path/to/")).to eq( + Addressable::URI.parse("resource/") + ) + end + + it "should have a route of '../' from " + + "'http://example.com/path/to/resource/sub'" do + expect(@uri.route_from("http://example.com/path/to/resource/sub")).to eq( + Addressable::URI.parse("../") + ) + end + + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/another'" do + expect(@uri.route_from("http://example.com/path/to/another")).to eq( + Addressable::URI.parse("resource/") + ) + end + + it "should have a route of 'resource/' from " + + "'http://example.com/path/to/res'" do + expect(@uri.route_from("http://example.com/path/to/res")).to eq( + Addressable::URI.parse("resource/") + ) + end + + it "should have a route of 'resource/' from " + + "'http://example.com:80/path/to/'" do + expect(@uri.route_from("http://example.com:80/path/to/")).to eq( + Addressable::URI.parse("resource/") + ) + end + + it "should have a route of 'http://example.com/path/to/' from " + + "'http://example.com:8080/path/to/'" do + expect(@uri.route_from("http://example.com:8080/path/to/")).to eq( + Addressable::URI.parse("http://example.com/path/to/resource/") + ) + end + + it "should have a route of 'http://example.com/path/to/' from " + + "'http://user:pass@example.com/path/to/'" do + expect(@uri.route_from("http://user:pass@example.com/path/to/")).to eq( + Addressable::URI.parse("http://example.com/path/to/resource/") + ) + end + + it "should have a route of '../../path/to/resource/' from " + + "'http://example.com/to/resource/'" do + expect(@uri.route_from("http://example.com/to/resource/")).to eq( + Addressable::URI.parse("../../path/to/resource/") + ) + end + + it "should correctly convert to a hash" do + expect(@uri.to_hash).to eq({ + :scheme => "http", + :user => nil, + :password => nil, + :host => "example.com", + :port => nil, + :path => "/path/to/resource/", + :query => nil, + :fragment => nil + }) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end +end + +describe Addressable::URI, "when parsed from " + + "'relative/path/to/resource'" do + before do + @uri = Addressable::URI.parse("relative/path/to/resource") + end + + it "should not have a scheme" do + expect(@uri.scheme).to eq(nil) + end + + it "should not be considered ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should not have an authority segment" do + expect(@uri.authority).to eq(nil) + end + + it "should not have a host" do + expect(@uri.host).to eq(nil) + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should not have a port" do + expect(@uri.port).to eq(nil) + end + + it "should have a path of 'relative/path/to/resource'" do + expect(@uri.path).to eq("relative/path/to/resource") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should not be considered absolute" do + expect(@uri).not_to be_absolute + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "should raise an error if routing is attempted" do + expect do + @uri.route_to("http://example.com/") + end.to raise_error(ArgumentError, /relative\/path\/to\/resource/) + expect do + @uri.route_from("http://example.com/") + end.to raise_error(ArgumentError, /relative\/path\/to\/resource/) + end + + it "when joined with 'another/relative/path' should be " + + "'relative/path/to/another/relative/path'" do + expect(@uri.join('another/relative/path')).to eq( + Addressable::URI.parse("relative/path/to/another/relative/path") + ) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end +end + +describe Addressable::URI, "when parsed from " + + "'relative_path_with_no_slashes'" do + before do + @uri = Addressable::URI.parse("relative_path_with_no_slashes") + end + + it "should not have a scheme" do + expect(@uri.scheme).to eq(nil) + end + + it "should not be considered ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should not have an authority segment" do + expect(@uri.authority).to eq(nil) + end + + it "should not have a host" do + expect(@uri.host).to eq(nil) + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should not have a port" do + expect(@uri.port).to eq(nil) + end + + it "should have a path of 'relative_path_with_no_slashes'" do + expect(@uri.path).to eq("relative_path_with_no_slashes") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should not be considered absolute" do + expect(@uri).not_to be_absolute + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "when joined with 'another_relative_path' should be " + + "'another_relative_path'" do + expect(@uri.join('another_relative_path')).to eq( + Addressable::URI.parse("another_relative_path") + ) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt") + end + + it "should have a scheme of 'http'" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/file.txt'" do + expect(@uri.path).to eq("/file.txt") + end + + it "should have a basename of 'file.txt'" do + expect(@uri.basename).to eq("file.txt") + end + + it "should have an extname of '.txt'" do + expect(@uri.extname).to eq(".txt") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt;parameter'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt;parameter") + end + + it "should have a scheme of 'http'" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/file.txt;parameter'" do + expect(@uri.path).to eq("/file.txt;parameter") + end + + it "should have a basename of 'file.txt'" do + expect(@uri.basename).to eq("file.txt") + end + + it "should have an extname of '.txt'" do + expect(@uri.extname).to eq(".txt") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/file.txt;x=y'" do + before do + @uri = Addressable::URI.parse("http://example.com/file.txt;x=y") + end + + it "should have a scheme of 'http'" do + expect(@uri.scheme).to eq("http") + end + + it "should have a scheme of 'http'" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'example.com'" do + expect(@uri.authority).to eq("example.com") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have no username" do + expect(@uri.user).to eq(nil) + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/file.txt;x=y'" do + expect(@uri.path).to eq("/file.txt;x=y") + end + + it "should have an extname of '.txt'" do + expect(@uri.extname).to eq(".txt") + end + + it "should have no query string" do + expect(@uri.query).to eq(nil) + end + + it "should have no fragment" do + expect(@uri.fragment).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'svn+ssh://developername@rubyforge.org/var/svn/project'" do + before do + @uri = Addressable::URI.parse( + "svn+ssh://developername@rubyforge.org/var/svn/project" + ) + end + + it "should have a scheme of 'svn+ssh'" do + expect(@uri.scheme).to eq("svn+ssh") + end + + it "should be considered to be ip-based" do + expect(@uri).to be_ip_based + end + + it "should have a path of '/var/svn/project'" do + expect(@uri.path).to eq("/var/svn/project") + end + + it "should have a username of 'developername'" do + expect(@uri.user).to eq("developername") + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'ssh+svn://developername@RUBYFORGE.ORG/var/svn/project'" do + before do + @uri = Addressable::URI.parse( + "ssh+svn://developername@RUBYFORGE.ORG/var/svn/project" + ) + end + + it "should have a scheme of 'ssh+svn'" do + expect(@uri.scheme).to eq("ssh+svn") + end + + it "should have a normalized scheme of 'svn+ssh'" do + expect(@uri.normalized_scheme).to eq("svn+ssh") + end + + it "should have a normalized site of 'svn+ssh'" do + expect(@uri.normalized_site).to eq("svn+ssh://developername@rubyforge.org") + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of '/var/svn/project'" do + expect(@uri.path).to eq("/var/svn/project") + end + + it "should have a username of 'developername'" do + expect(@uri.user).to eq("developername") + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should not be considered to be in normal form" do + expect(@uri.normalize).not_to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'mailto:user@example.com'" do + before do + @uri = Addressable::URI.parse("mailto:user@example.com") + end + + it "should have a scheme of 'mailto'" do + expect(@uri.scheme).to eq("mailto") + end + + it "should not be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of 'user@example.com'" do + expect(@uri.path).to eq("user@example.com") + end + + it "should have no user" do + expect(@uri.user).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'tag:example.com,2006-08-18:/path/to/something'" do + before do + @uri = Addressable::URI.parse( + "tag:example.com,2006-08-18:/path/to/something") + end + + it "should have a scheme of 'tag'" do + expect(@uri.scheme).to eq("tag") + end + + it "should be considered to be ip-based" do + expect(@uri).not_to be_ip_based + end + + it "should have a path of " + + "'example.com,2006-08-18:/path/to/something'" do + expect(@uri.path).to eq("example.com,2006-08-18:/path/to/something") + end + + it "should have no user" do + expect(@uri.user).to eq(nil) + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/x;y/'" do + before do + @uri = Addressable::URI.parse("http://example.com/x;y/") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?x=1&y=2'" do + before do + @uri = Addressable::URI.parse("http://example.com/?x=1&y=2") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end +end + +describe Addressable::URI, "when parsed from " + + "'view-source:http://example.com/'" do + before do + @uri = Addressable::URI.parse("view-source:http://example.com/") + end + + it "should have a scheme of 'view-source'" do + expect(@uri.scheme).to eq("view-source") + end + + it "should have a path of 'http://example.com/'" do + expect(@uri.path).to eq("http://example.com/") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do + before do + @uri = Addressable::URI.parse( + "http://user:pass@example.com/path/to/resource?query=x#fragment") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have an authority segment of 'user:pass@example.com'" do + expect(@uri.authority).to eq("user:pass@example.com") + end + + it "should have a username of 'user'" do + expect(@uri.user).to eq("user") + end + + it "should have a password of 'pass'" do + expect(@uri.password).to eq("pass") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/path/to/resource'" do + expect(@uri.path).to eq("/path/to/resource") + end + + it "should have a query string of 'query=x'" do + expect(@uri.query).to eq("query=x") + end + + it "should have a fragment of 'fragment'" do + expect(@uri.fragment).to eq("fragment") + end + + it "should be considered to be in normal form" do + expect(@uri.normalize).to be_eql(@uri) + end + + it "should have a route of '../../' to " + + "'http://user:pass@example.com/path/'" do + expect(@uri.route_to("http://user:pass@example.com/path/")).to eq( + Addressable::URI.parse("../../") + ) + end + + it "should have a route of 'to/resource?query=x#fragment' " + + "from 'http://user:pass@example.com/path/'" do + expect(@uri.route_from("http://user:pass@example.com/path/")).to eq( + Addressable::URI.parse("to/resource?query=x#fragment") + ) + end + + it "should have a route of '?query=x#fragment' " + + "from 'http://user:pass@example.com/path/to/resource'" do + expect(@uri.route_from("http://user:pass@example.com/path/to/resource")).to eq( + Addressable::URI.parse("?query=x#fragment") + ) + end + + it "should have a route of '#fragment' " + + "from 'http://user:pass@example.com/path/to/resource?query=x'" do + expect(@uri.route_from( + "http://user:pass@example.com/path/to/resource?query=x")).to eq( + Addressable::URI.parse("#fragment") + ) + end + + it "should have a route of '#fragment' from " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do + expect(@uri.route_from( + "http://user:pass@example.com/path/to/resource?query=x#fragment" + )).to eq(Addressable::URI.parse("#fragment")) + end + + it "should have a route of 'http://elsewhere.com/' to " + + "'http://elsewhere.com/'" do + expect(@uri.route_to("http://elsewhere.com/")).to eq( + Addressable::URI.parse("http://elsewhere.com/") + ) + end + + it "should have a route of " + + "'http://user:pass@example.com/path/to/resource?query=x#fragment' " + + "from 'http://example.com/path/to/'" do + expect(@uri.route_from("http://elsewhere.com/path/to/")).to eq( + Addressable::URI.parse( + "http://user:pass@example.com/path/to/resource?query=x#fragment") + ) + end + + it "should have the correct scheme after assignment" do + @uri.scheme = "ftp" + expect(@uri.scheme).to eq("ftp") + expect(@uri.to_s).to eq( + "ftp://user:pass@example.com/path/to/resource?query=x#fragment" + ) + expect(@uri.to_str).to eq( + "ftp://user:pass@example.com/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct site segment after assignment" do + @uri.site = "https://newuser:newpass@example.com:443" + expect(@uri.scheme).to eq("https") + expect(@uri.authority).to eq("newuser:newpass@example.com:443") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("newpass") + expect(@uri.userinfo).to eq("newuser:newpass") + expect(@uri.normalized_userinfo).to eq("newuser:newpass") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(443) + expect(@uri.inferred_port).to eq(443) + expect(@uri.to_s).to eq( + "https://newuser:newpass@example.com:443" + + "/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser:newpass@example.com:80" + expect(@uri.authority).to eq("newuser:newpass@example.com:80") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("newpass") + expect(@uri.userinfo).to eq("newuser:newpass") + expect(@uri.normalized_userinfo).to eq("newuser:newpass") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(80) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq( + "http://newuser:newpass@example.com:80" + + "/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct userinfo segment after assignment" do + @uri.userinfo = "newuser:newpass" + expect(@uri.userinfo).to eq("newuser:newpass") + expect(@uri.authority).to eq("newuser:newpass@example.com") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("newpass") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq( + "http://newuser:newpass@example.com" + + "/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.authority).to eq("newuser:pass@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.authority).to eq("user:newpass@example.com") + end + + it "should have the correct host after assignment" do + @uri.host = "newexample.com" + expect(@uri.host).to eq("newexample.com") + expect(@uri.authority).to eq("user:pass@newexample.com") + end + + it "should have the correct host after assignment" do + @uri.hostname = "newexample.com" + expect(@uri.host).to eq("newexample.com") + expect(@uri.hostname).to eq("newexample.com") + expect(@uri.authority).to eq("user:pass@newexample.com") + end + + it "should raise an error if assigning a bogus object to the hostname" do + expect do + @uri.hostname = Object.new + end.to raise_error(TypeError) + end + + it "should have the correct port after assignment" do + @uri.port = 8080 + expect(@uri.port).to eq(8080) + expect(@uri.authority).to eq("user:pass@example.com:8080") + end + + it "should have the correct origin after assignment" do + @uri.origin = "http://newexample.com" + expect(@uri.host).to eq("newexample.com") + expect(@uri.authority).to eq("newexample.com") + end + + it "should have the correct path after assignment" do + @uri.path = "/newpath/to/resource" + expect(@uri.path).to eq("/newpath/to/resource") + expect(@uri.to_s).to eq( + "http://user:pass@example.com/newpath/to/resource?query=x#fragment" + ) + end + + it "should have the correct scheme and authority after nil assignment" do + @uri.site = nil + expect(@uri.scheme).to eq(nil) + expect(@uri.authority).to eq(nil) + expect(@uri.to_s).to eq("/path/to/resource?query=x#fragment") + end + + it "should have the correct scheme and authority after assignment" do + @uri.site = "file://" + expect(@uri.scheme).to eq("file") + expect(@uri.authority).to eq("") + expect(@uri.to_s).to eq("file:///path/to/resource?query=x#fragment") + end + + it "should have the correct path after nil assignment" do + @uri.path = nil + expect(@uri.path).to eq("") + expect(@uri.to_s).to eq( + "http://user:pass@example.com?query=x#fragment" + ) + end + + it "should have the correct query string after assignment" do + @uri.query = "newquery=x" + expect(@uri.query).to eq("newquery=x") + expect(@uri.to_s).to eq( + "http://user:pass@example.com/path/to/resource?newquery=x#fragment" + ) + @uri.query = nil + expect(@uri.query).to eq(nil) + expect(@uri.to_s).to eq( + "http://user:pass@example.com/path/to/resource#fragment" + ) + end + + it "should have the correct query string after hash assignment" do + @uri.query_values = {"?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther"} + expect(@uri.query.split("&")).to include("%3Fuestion%20mark=%3Dsign") + expect(@uri.query.split("&")).to include("hello=g%C3%BCnther") + expect(@uri.query_values).to eq({ + "?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther" + }) + end + + it "should have the correct query string after flag hash assignment" do + @uri.query_values = {'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil} + expect(@uri.query.split("&")).to include("flag%3F1") + expect(@uri.query.split("&")).to include("fl%3Dag2") + expect(@uri.query.split("&")).to include("flag3") + expect(@uri.query_values(Array).sort).to eq([["fl=ag2"], ["flag3"], ["flag?1"]]) + expect(@uri.query_values(Hash)).to eq({ + 'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil + }) + end + + it "should raise an error if query values are set to a bogus type" do + expect do + @uri.query_values = "bogus" + end.to raise_error(TypeError) + end + + it "should have the correct fragment after assignment" do + @uri.fragment = "newfragment" + expect(@uri.fragment).to eq("newfragment") + expect(@uri.to_s).to eq( + "http://user:pass@example.com/path/to/resource?query=x#newfragment" + ) + + @uri.fragment = nil + expect(@uri.fragment).to eq(nil) + expect(@uri.to_s).to eq( + "http://user:pass@example.com/path/to/resource?query=x" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:fragment => "newfragment").to_s).to eq( + "http://user:pass@example.com/path/to/resource?query=x#newfragment" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:fragment => nil).to_s).to eq( + "http://user:pass@example.com/path/to/resource?query=x" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:userinfo => "newuser:newpass").to_s).to eq( + "http://newuser:newpass@example.com/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:userinfo => nil).to_s).to eq( + "http://example.com/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:path => "newpath").to_s).to eq( + "http://user:pass@example.com/newpath?query=x#fragment" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:port => "42", :path => "newpath", :query => "").to_s).to eq( + "http://user:pass@example.com:42/newpath?#fragment" + ) + end + + it "should have the correct values after a merge" do + expect(@uri.merge(:authority => "foo:bar@baz:42").to_s).to eq( + "http://foo:bar@baz:42/path/to/resource?query=x#fragment" + ) + # Ensure the operation was not destructive + expect(@uri.to_s).to eq( + "http://user:pass@example.com/path/to/resource?query=x#fragment" + ) + end + + it "should have the correct values after a destructive merge" do + @uri.merge!(:authority => "foo:bar@baz:42") + # Ensure the operation was destructive + expect(@uri.to_s).to eq( + "http://foo:bar@baz:42/path/to/resource?query=x#fragment" + ) + end + + it "should fail to merge with bogus values" do + expect do + @uri.merge(:port => "bogus") + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should fail to merge with bogus values" do + expect do + @uri.merge(:authority => "bar@baz:bogus") + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should fail to merge with bogus parameters" do + expect do + @uri.merge(42) + end.to raise_error(TypeError) + end + + it "should fail to merge with bogus parameters" do + expect do + @uri.merge("http://example.com/") + end.to raise_error(TypeError) + end + + it "should fail to merge with both authority and subcomponents" do + expect do + @uri.merge(:authority => "foo:bar@baz:42", :port => "42") + end.to raise_error(ArgumentError) + end + + it "should fail to merge with both userinfo and subcomponents" do + expect do + @uri.merge(:userinfo => "foo:bar", :user => "foo") + end.to raise_error(ArgumentError) + end + + it "should be identical to its duplicate" do + expect(@uri).to eq(@uri.dup) + end + + it "should have an origin of 'http://example.com'" do + expect(@uri.origin).to eq('http://example.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/search?q=Q%26A'" do + + before do + @uri = Addressable::URI.parse("http://example.com/search?q=Q%26A") + end + + it "should have a query of 'q=Q%26A'" do + expect(@uri.query).to eq("q=Q%26A") + end + + it "should have query_values of {'q' => 'Q&A'}" do + expect(@uri.query_values).to eq({ 'q' => 'Q&A' }) + end + + it "should normalize to the original uri " + + "(with the ampersand properly percent-encoded)" do + expect(@uri.normalize.to_s).to eq("http://example.com/search?q=Q%26A") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?&x=b") + end + + it "should have a query of '&x=b'" do + expect(@uri.query).to eq("&x=b") + end + + it "should have query_values of {'x' => 'b'}" do + expect(@uri.query_values).to eq({'x' => 'b'}) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q='one;two'&x=1'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q='one;two'&x=1") + end + + it "should have a query of 'q='one;two'&x=1'" do + expect(@uri.query).to eq("q='one;two'&x=1") + end + + it "should have query_values of {\"q\" => \"'one;two'\", \"x\" => \"1\"}" do + expect(@uri.query_values).to eq({"q" => "'one;two'", "x" => "1"}) + end + + it "should escape the ';' character when normalizing to avoid ambiguity " + + "with the W3C HTML 4.01 specification" do + # HTML 4.01 Section B.2.2 + expect(@uri.normalize.query).to eq("q='one%3Btwo'&x=1") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?&&x=b") + end + + it "should have a query of '&&x=b'" do + expect(@uri.query).to eq("&&x=b") + end + + it "should have query_values of {'x' => 'b'}" do + expect(@uri.query_values).to eq({'x' => 'b'}) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a&&x=b") + end + + it "should have a query of 'q=a&&x=b'" do + expect(@uri.query).to eq("q=a&&x=b") + end + + it "should have query_values of {'q' => 'a, 'x' => 'b'}" do + expect(@uri.query_values).to eq({'q' => 'a', 'x' => 'b'}) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q&&x=b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q&&x=b") + end + + it "should have a query of 'q&&x=b'" do + expect(@uri.query).to eq("q&&x=b") + end + + it "should have query_values of {'q' => true, 'x' => 'b'}" do + expect(@uri.query_values).to eq({'q' => nil, 'x' => 'b'}) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a+b'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a+b") + end + + it "should have a query of 'q=a+b'" do + expect(@uri.query).to eq("q=a+b") + end + + it "should have query_values of {'q' => 'a b'}" do + expect(@uri.query_values).to eq({'q' => 'a b'}) + end + + it "should have a normalized query of 'q=a+b'" do + expect(@uri.normalized_query).to eq("q=a+b") + end +end + +describe Addressable::URI, "when parsed from 'https://example.com/?q=a+b'" do + before do + @uri = Addressable::URI.parse("https://example.com/?q=a+b") + end + + it "should have query_values of {'q' => 'a b'}" do + expect(@uri.query_values).to eq("q" => "a b") + end +end + +describe Addressable::URI, "when parsed from 'example.com?q=a+b'" do + before do + @uri = Addressable::URI.parse("example.com?q=a+b") + end + + it "should have query_values of {'q' => 'a b'}" do + expect(@uri.query_values).to eq("q" => "a b") + end +end + +describe Addressable::URI, "when parsed from 'mailto:?q=a+b'" do + before do + @uri = Addressable::URI.parse("mailto:?q=a+b") + end + + it "should have query_values of {'q' => 'a+b'}" do + expect(@uri.query_values).to eq("q" => "a+b") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q=a%2bb'" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=a%2bb") + end + + it "should have a query of 'q=a+b'" do + expect(@uri.query).to eq("q=a%2bb") + end + + it "should have query_values of {'q' => 'a+b'}" do + expect(@uri.query_values).to eq({'q' => 'a+b'}) + end + + it "should have a normalized query of 'q=a%2Bb'" do + expect(@uri.normalized_query).to eq("q=a%2Bb") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7'" do + before do + @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7") + end + + it "should have a normalized query of 'v=~&w=%25&x=%25&y=%2B&z=%C3%87'" do + expect(@uri.normalized_query).to eq("v=~&w=%25&x=%25&y=%2B&z=%C3%87") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7'" do + before do + @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7") + end + + it "should have a normalized query of 'v=~&w=%25&x=%25&y=+&z=%C3%87'" do + expect(@uri.normalized_query).to eq("v=~&w=%25&x=%25&y=+&z=%C3%87") + end +end + +describe Addressable::URI, "when parsed from 'http://example/?b=1&a=2&c=3'" do + before do + @uri = Addressable::URI.parse("http://example/?b=1&a=2&c=3") + end + + it "should have a sorted normalized query of 'a=2&b=1&c=3'" do + expect(@uri.normalized_query(:sorted)).to eq("a=2&b=1&c=3") + end +end + +describe Addressable::URI, "when parsed from 'http://example/?&a&&c&'" do + before do + @uri = Addressable::URI.parse("http://example/?&a&&c&") + end + + it "should have a compacted normalized query of 'a&c'" do + expect(@uri.normalized_query(:compacted)).to eq("a&c") + end +end + +describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=1'" do + before do + @uri = Addressable::URI.parse("http://example.com/?a=1&a=1") + end + + it "should have a compacted normalized query of 'a=1'" do + expect(@uri.normalized_query(:compacted)).to eq("a=1") + end +end + +describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=2'" do + before do + @uri = Addressable::URI.parse("http://example.com/?a=1&a=2") + end + + it "should have a compacted normalized query of 'a=1&a=2'" do + expect(@uri.normalized_query(:compacted)).to eq("a=1&a=2") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/sound%2bvision'" do + before do + @uri = Addressable::URI.parse("http://example.com/sound%2bvision") + end + + it "should have a normalized path of '/sound+vision'" do + expect(@uri.normalized_path).to eq('/sound+vision') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/?q='" do + before do + @uri = Addressable::URI.parse("http://example.com/?q=") + end + + it "should have a query of 'q='" do + expect(@uri.query).to eq("q=") + end + + it "should have query_values of {'q' => ''}" do + expect(@uri.query_values).to eq({'q' => ''}) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user@example.com'" do + before do + @uri = Addressable::URI.parse("http://user@example.com") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a username of 'user'" do + expect(@uri.user).to eq("user") + end + + it "should have no password" do + expect(@uri.password).to eq(nil) + end + + it "should have a userinfo of 'user'" do + expect(@uri.userinfo).to eq("user") + end + + it "should have a normalized userinfo of 'user'" do + expect(@uri.normalized_userinfo).to eq("user") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have default_port 80" do + expect(@uri.default_port).to eq(80) + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq(nil) + expect(@uri.to_s).to eq("http://newuser@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.to_s).to eq("http://user:newpass@example.com") + end + + it "should have the correct userinfo segment after assignment" do + @uri.userinfo = "newuser:newpass" + expect(@uri.userinfo).to eq("newuser:newpass") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("newpass") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://newuser:newpass@example.com") + end + + it "should have the correct userinfo segment after nil assignment" do + @uri.userinfo = nil + expect(@uri.userinfo).to eq(nil) + expect(@uri.user).to eq(nil) + expect(@uri.password).to eq(nil) + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://example.com") + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser@example.com" + expect(@uri.authority).to eq("newuser@example.com") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq(nil) + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://newuser@example.com") + end + + it "should raise an error after nil assignment of authority segment" do + expect do + # This would create an invalid URI + @uri.authority = nil + end.to raise_error(Addressable::URI::InvalidURIError) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://user:@example.com'" do + before do + @uri = Addressable::URI.parse("http://user:@example.com") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a username of 'user'" do + expect(@uri.user).to eq("user") + end + + it "should have a password of ''" do + expect(@uri.password).to eq("") + end + + it "should have a normalized userinfo of 'user:'" do + expect(@uri.normalized_userinfo).to eq("user:") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("") + expect(@uri.to_s).to eq("http://newuser:@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.to_s).to eq("http://user:newpass@example.com") + end + + it "should have the correct authority segment after assignment" do + @uri.authority = "newuser:@example.com" + expect(@uri.authority).to eq("newuser:@example.com") + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://newuser:@example.com") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:pass@example.com'" do + before do + @uri = Addressable::URI.parse("http://:pass@example.com") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a username of ''" do + expect(@uri.user).to eq("") + end + + it "should have a password of 'pass'" do + expect(@uri.password).to eq("pass") + end + + it "should have a userinfo of ':pass'" do + expect(@uri.userinfo).to eq(":pass") + end + + it "should have a normalized userinfo of ':pass'" do + expect(@uri.normalized_userinfo).to eq(":pass") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("pass") + expect(@uri.to_s).to eq("http://newuser:pass@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.user).to eq("") + expect(@uri.to_s).to eq("http://:newpass@example.com") + end + + it "should have the correct authority segment after assignment" do + @uri.authority = ":newpass@example.com" + expect(@uri.authority).to eq(":newpass@example.com") + expect(@uri.user).to eq("") + expect(@uri.password).to eq("newpass") + expect(@uri.host).to eq("example.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://:newpass@example.com") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://:@example.com'" do + before do + @uri = Addressable::URI.parse("http://:@example.com") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a username of ''" do + expect(@uri.user).to eq("") + end + + it "should have a password of ''" do + expect(@uri.password).to eq("") + end + + it "should have a normalized userinfo of nil" do + expect(@uri.normalized_userinfo).to eq(nil) + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have the correct username after assignment" do + @uri.user = "newuser" + expect(@uri.user).to eq("newuser") + expect(@uri.password).to eq("") + expect(@uri.to_s).to eq("http://newuser:@example.com") + end + + it "should have the correct password after assignment" do + @uri.password = "newpass" + expect(@uri.password).to eq("newpass") + expect(@uri.user).to eq("") + expect(@uri.to_s).to eq("http://:newpass@example.com") + end + + it "should have the correct authority segment after assignment" do + @uri.authority = ":@newexample.com" + expect(@uri.authority).to eq(":@newexample.com") + expect(@uri.user).to eq("") + expect(@uri.password).to eq("") + expect(@uri.host).to eq("newexample.com") + expect(@uri.port).to eq(nil) + expect(@uri.inferred_port).to eq(80) + expect(@uri.to_s).to eq("http://:@newexample.com") + end +end + +describe Addressable::URI, "when parsed from " + + "'#example'" do + before do + @uri = Addressable::URI.parse("#example") + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "should have a host of nil" do + expect(@uri.host).to eq(nil) + end + + it "should have a site of nil" do + expect(@uri.site).to eq(nil) + end + + it "should have a normalized_site of nil" do + expect(@uri.normalized_site).to eq(nil) + end + + it "should have a path of ''" do + expect(@uri.path).to eq("") + end + + it "should have a query string of nil" do + expect(@uri.query).to eq(nil) + end + + it "should have a fragment of 'example'" do + expect(@uri.fragment).to eq("example") + end +end + +describe Addressable::URI, "when parsed from " + + "the network-path reference '//example.com/'" do + before do + @uri = Addressable::URI.parse("//example.com/") + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should have a path of '/'" do + expect(@uri.path).to eq("/") + end + + it "should raise an error if routing is attempted" do + expect do + @uri.route_to("http://example.com/") + end.to raise_error(ArgumentError, /\/\/example.com\//) + expect do + @uri.route_from("http://example.com/") + end.to raise_error(ArgumentError, /\/\/example.com\//) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from " + + "'feed://http://example.com/'" do + before do + @uri = Addressable::URI.parse("feed://http://example.com/") + end + + it "should have a host of 'http'" do + expect(@uri.host).to eq("http") + end + + it "should have a path of '//example.com/'" do + expect(@uri.path).to eq("//example.com/") + end +end + +describe Addressable::URI, "when parsed from " + + "'feed:http://example.com/'" do + before do + @uri = Addressable::URI.parse("feed:http://example.com/") + end + + it "should have a path of 'http://example.com/'" do + expect(@uri.path).to eq("http://example.com/") + end + + it "should normalize to 'http://example.com/'" do + expect(@uri.normalize.to_s).to eq("http://example.com/") + expect(@uri.normalize!.to_s).to eq("http://example.com/") + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from " + + "'example://a/b/c/%7Bfoo%7D'" do + before do + @uri = Addressable::URI.parse("example://a/b/c/%7Bfoo%7D") + end + + # Section 6.2.2 of RFC 3986 + it "should be equivalent to eXAMPLE://a/./b/../b/%63/%7bfoo%7d" do + expect(@uri).to eq( + Addressable::URI.parse("eXAMPLE://a/./b/../b/%63/%7bfoo%7d") + ) + end + + it "should have an origin of 'example://a'" do + expect(@uri.origin).to eq('example://a') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://example.com/indirect/path/./to/../resource/'" do + before do + @uri = Addressable::URI.parse( + "http://example.com/indirect/path/./to/../resource/") + end + + it "should use the 'http' scheme" do + expect(@uri.scheme).to eq("http") + end + + it "should have a host of 'example.com'" do + expect(@uri.host).to eq("example.com") + end + + it "should use port 80" do + expect(@uri.inferred_port).to eq(80) + end + + it "should have a path of '/indirect/path/./to/../resource/'" do + expect(@uri.path).to eq("/indirect/path/./to/../resource/") + end + + # Section 6.2.2.3 of RFC 3986 + it "should have a normalized path of '/indirect/path/resource/'" do + expect(@uri.normalize.path).to eq("/indirect/path/resource/") + expect(@uri.normalize!.path).to eq("/indirect/path/resource/") + end +end + +describe Addressable::URI, "when parsed from " + + "'http://under_score.example.com/'" do + it "should not cause an error" do + expect do + Addressable::URI.parse("http://under_score.example.com/") + end.not_to raise_error + end +end + +describe Addressable::URI, "when parsed from " + + "'./this:that'" do + before do + @uri = Addressable::URI.parse("./this:that") + end + + it "should be considered relative" do + expect(@uri).to be_relative + end + + it "should have no scheme" do + expect(@uri.scheme).to eq(nil) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from " + + "'this:that'" do + before do + @uri = Addressable::URI.parse("this:that") + end + + it "should be considered absolute" do + expect(@uri).to be_absolute + end + + it "should have a scheme of 'this'" do + expect(@uri.scheme).to eq("this") + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from '?'" do + before do + @uri = Addressable::URI.parse("?") + end + + it "should normalize to ''" do + expect(@uri.normalize.to_s).to eq("") + end + + it "should have the correct return type" do + expect(@uri.query_values).to eq({}) + expect(@uri.query_values(Hash)).to eq({}) + expect(@uri.query_values(Array)).to eq([]) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from '?one=1&two=2&three=3'" do + before do + @uri = Addressable::URI.parse("?one=1&two=2&three=3") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({"one" => "1", "two" => "2", "three" => "3"}) + end + + it "should raise an error for invalid return type values" do + expect do + @uri.query_values(Integer) + end.to raise_error(ArgumentError) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one", "1"], ["two", "2"], ["three", "3"] + ]) + end + + it "should have a 'null' origin" do + expect(@uri.origin).to eq('null') + end +end + +describe Addressable::URI, "when parsed from '?one=1=uno&two=2=dos'" do + before do + @uri = Addressable::URI.parse("?one=1=uno&two=2=dos") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({"one" => "1=uno", "two" => "2=dos"}) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one", "1=uno"], ["two", "2=dos"] + ]) + end +end + +describe Addressable::URI, "when parsed from '?one[two][three]=four'" do + before do + @uri = Addressable::URI.parse("?one[two][three]=four") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({"one[two][three]" => "four"}) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one[two][three]", "four"] + ]) + end +end + +describe Addressable::URI, "when parsed from '?one.two.three=four'" do + before do + @uri = Addressable::URI.parse("?one.two.three=four") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one.two.three" => "four" + }) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one.two.three", "four"] + ]) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three]=four&one[two][five]=six'" do + before do + @uri = Addressable::URI.parse("?one[two][three]=four&one[two][five]=six") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one[two][three]" => "four", "one[two][five]" => "six" + }) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one[two][three]", "four"], ["one[two][five]", "six"] + ]) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one.two.three=four&one.two.five=six'" do + before do + @uri = Addressable::URI.parse("?one.two.three=four&one.two.five=six") + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one.two.three" => "four", "one.two.five" => "six" + }) + end + + it "should have the correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one.two.three", "four"], ["one.two.five", "six"] + ]) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one=two&one=three'" do + before do + @uri = Addressable::URI.parse( + "?one=two&one=three&one=four" + ) + end + + it "should have correct array query values" do + expect(@uri.query_values(Array)).to eq( + [['one', 'two'], ['one', 'three'], ['one', 'four']] + ) + end + + it "should have correct hash query values" do + skip("This is probably more desirable behavior.") + expect(@uri.query_values(Hash)).to eq( + {'one' => ['two', 'three', 'four']} + ) + end + + it "should handle assignment with keys of mixed type" do + @uri.query_values = @uri.query_values(Hash).merge({:one => 'three'}) + expect(@uri.query_values(Hash)).to eq({'one' => 'three'}) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][]=four&one[two][three][]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][]=four&one[two][three][]=five" + ) + end + + it "should have correct query values" do + expect(@uri.query_values(Hash)).to eq({"one[two][three][]" => "five"}) + end + + it "should have correct array query values" do + expect(@uri.query_values(Array)).to eq([ + ["one[two][three][]", "four"], ["one[two][three][]", "five"] + ]) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][0]=four&one[two][three][1]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][0]=four&one[two][three][1]=five" + ) + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one[two][three][0]" => "four", "one[two][three][1]" => "five" + }) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][1]=four&one[two][three][0]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][1]=four&one[two][three][0]=five" + ) + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one[two][three][1]" => "four", "one[two][three][0]" => "five" + }) + end +end + +describe Addressable::URI, "when parsed from " + + "'?one[two][three][2]=four&one[two][three][1]=five'" do + before do + @uri = Addressable::URI.parse( + "?one[two][three][2]=four&one[two][three][1]=five" + ) + end + + it "should have the correct query values" do + expect(@uri.query_values).to eq({ + "one[two][three][2]" => "four", "one[two][three][1]" => "five" + }) + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/") + end + + it "should be equivalent to 'http://www.xn--8ws00zhy3a.com/'" do + expect(@uri).to eq( + Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") + ) + end + + it "should not have domain name encoded during normalization" do + expect(Addressable::URI.normalized_encode(@uri.to_s)).to eq( + "http://www.詹姆斯.com/" + ) + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/ some spaces /'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/ some spaces /") + end + + it "should be equivalent to " + + "'http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/'" do + expect(@uri).to eq( + Addressable::URI.parse( + "http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/") + ) + end + + it "should not have domain name encoded during normalization" do + expect(Addressable::URI.normalized_encode(@uri.to_s)).to eq( + "http://www.詹姆斯.com/%20some%20spaces%20/" + ) + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.xn--8ws00zhy3a.com/'" do + before do + @uri = Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") + end + + it "should be displayed as http://www.詹姆斯.com/" do + expect(@uri.display_uri.to_s).to eq("http://www.詹姆斯.com/") + end + + it "should properly force the encoding" do + display_string = @uri.display_uri.to_str + expect(display_string).to eq("http://www.詹姆斯.com/") + if display_string.respond_to?(:encoding) + expect(display_string.encoding.to_s).to eq(Encoding::UTF_8.to_s) + end + end + + it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do + expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') + end +end + +describe Addressable::URI, "when parsed from " + + "'http://www.詹姆斯.com/atomtests/iri/詹.html'" do + before do + @uri = Addressable::URI.parse("http://www.詹姆斯.com/atomtests/iri/詹.html") + end + + it "should normalize to " + + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" do + expect(@uri.normalize.to_s).to eq( + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" + ) + expect(@uri.normalize!.to_s).to eq( + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" + ) + end +end + +describe Addressable::URI, "when parsed from a percent-encoded IRI" do + before do + @uri = Addressable::URI.parse( + "http://www.%E3%81%BB%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA" + + "%E3%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3" + + "%82%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82" + + "%81%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0" + + "%E3%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3" + + "%81%9F%E3%82%8A%E3%81%AA%E3%81%84.w3.mag.keio.ac.jp" + ) + end + + it "should normalize to something sane" do + expect(@uri.normalize.to_s).to eq( + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" + ) + expect(@uri.normalize!.to_s).to eq( + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" + ) + end + + it "should have the correct origin" do + expect(@uri.origin).to eq( + "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" + ) + end +end + +describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do + before do + @uri = Addressable::URI.parse("http://a/b/c/d;p?q") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g:h' should resolve to g:h" do + expect((@uri + "g:h").to_s).to eq("g:h") + expect(Addressable::URI.join(@uri, "g:h").to_s).to eq("g:h") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g' should resolve to http://a/b/c/g" do + expect((@uri + "g").to_s).to eq("http://a/b/c/g") + expect(Addressable::URI.join(@uri.to_s, "g").to_s).to eq("http://a/b/c/g") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with './g' should resolve to http://a/b/c/g" do + expect((@uri + "./g").to_s).to eq("http://a/b/c/g") + expect(Addressable::URI.join(@uri.to_s, "./g").to_s).to eq("http://a/b/c/g") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g/' should resolve to http://a/b/c/g/" do + expect((@uri + "g/").to_s).to eq("http://a/b/c/g/") + expect(Addressable::URI.join(@uri.to_s, "g/").to_s).to eq("http://a/b/c/g/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '/g' should resolve to http://a/g" do + expect((@uri + "/g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "/g").to_s).to eq("http://a/g") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '//g' should resolve to http://g" do + expect((@uri + "//g").to_s).to eq("http://g") + expect(Addressable::URI.join(@uri.to_s, "//g").to_s).to eq("http://g") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '?y' should resolve to http://a/b/c/d;p?y" do + expect((@uri + "?y").to_s).to eq("http://a/b/c/d;p?y") + expect(Addressable::URI.join(@uri.to_s, "?y").to_s).to eq("http://a/b/c/d;p?y") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g?y' should resolve to http://a/b/c/g?y" do + expect((@uri + "g?y").to_s).to eq("http://a/b/c/g?y") + expect(Addressable::URI.join(@uri.to_s, "g?y").to_s).to eq("http://a/b/c/g?y") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '#s' should resolve to http://a/b/c/d;p?q#s" do + expect((@uri + "#s").to_s).to eq("http://a/b/c/d;p?q#s") + expect(Addressable::URI.join(@uri.to_s, "#s").to_s).to eq( + "http://a/b/c/d;p?q#s" + ) + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g#s' should resolve to http://a/b/c/g#s" do + expect((@uri + "g#s").to_s).to eq("http://a/b/c/g#s") + expect(Addressable::URI.join(@uri.to_s, "g#s").to_s).to eq("http://a/b/c/g#s") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g?y#s' should resolve to http://a/b/c/g?y#s" do + expect((@uri + "g?y#s").to_s).to eq("http://a/b/c/g?y#s") + expect(Addressable::URI.join( + @uri.to_s, "g?y#s").to_s).to eq("http://a/b/c/g?y#s") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with ';x' should resolve to http://a/b/c/;x" do + expect((@uri + ";x").to_s).to eq("http://a/b/c/;x") + expect(Addressable::URI.join(@uri.to_s, ";x").to_s).to eq("http://a/b/c/;x") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g;x' should resolve to http://a/b/c/g;x" do + expect((@uri + "g;x").to_s).to eq("http://a/b/c/g;x") + expect(Addressable::URI.join(@uri.to_s, "g;x").to_s).to eq("http://a/b/c/g;x") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with 'g;x?y#s' should resolve to http://a/b/c/g;x?y#s" do + expect((@uri + "g;x?y#s").to_s).to eq("http://a/b/c/g;x?y#s") + expect(Addressable::URI.join( + @uri.to_s, "g;x?y#s").to_s).to eq("http://a/b/c/g;x?y#s") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '' should resolve to http://a/b/c/d;p?q" do + expect((@uri + "").to_s).to eq("http://a/b/c/d;p?q") + expect(Addressable::URI.join(@uri.to_s, "").to_s).to eq("http://a/b/c/d;p?q") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '.' should resolve to http://a/b/c/" do + expect((@uri + ".").to_s).to eq("http://a/b/c/") + expect(Addressable::URI.join(@uri.to_s, ".").to_s).to eq("http://a/b/c/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with './' should resolve to http://a/b/c/" do + expect((@uri + "./").to_s).to eq("http://a/b/c/") + expect(Addressable::URI.join(@uri.to_s, "./").to_s).to eq("http://a/b/c/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '..' should resolve to http://a/b/" do + expect((@uri + "..").to_s).to eq("http://a/b/") + expect(Addressable::URI.join(@uri.to_s, "..").to_s).to eq("http://a/b/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../' should resolve to http://a/b/" do + expect((@uri + "../").to_s).to eq("http://a/b/") + expect(Addressable::URI.join(@uri.to_s, "../").to_s).to eq("http://a/b/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../g' should resolve to http://a/b/g" do + expect((@uri + "../g").to_s).to eq("http://a/b/g") + expect(Addressable::URI.join(@uri.to_s, "../g").to_s).to eq("http://a/b/g") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../..' should resolve to http://a/" do + expect((@uri + "../..").to_s).to eq("http://a/") + expect(Addressable::URI.join(@uri.to_s, "../..").to_s).to eq("http://a/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../../' should resolve to http://a/" do + expect((@uri + "../../").to_s).to eq("http://a/") + expect(Addressable::URI.join(@uri.to_s, "../../").to_s).to eq("http://a/") + end + + # Section 5.4.1 of RFC 3986 + it "when joined with '../../g' should resolve to http://a/g" do + expect((@uri + "../../g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "../../g").to_s).to eq("http://a/g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '../../../g' should resolve to http://a/g" do + expect((@uri + "../../../g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "../../../g").to_s).to eq("http://a/g") + end + + it "when joined with '../.././../g' should resolve to http://a/g" do + expect((@uri + "../.././../g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "../.././../g").to_s).to eq( + "http://a/g" + ) + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '../../../../g' should resolve to http://a/g" do + expect((@uri + "../../../../g").to_s).to eq("http://a/g") + expect(Addressable::URI.join( + @uri.to_s, "../../../../g").to_s).to eq("http://a/g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '/./g' should resolve to http://a/g" do + expect((@uri + "/./g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "/./g").to_s).to eq("http://a/g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '/../g' should resolve to http://a/g" do + expect((@uri + "/../g").to_s).to eq("http://a/g") + expect(Addressable::URI.join(@uri.to_s, "/../g").to_s).to eq("http://a/g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g.' should resolve to http://a/b/c/g." do + expect((@uri + "g.").to_s).to eq("http://a/b/c/g.") + expect(Addressable::URI.join(@uri.to_s, "g.").to_s).to eq("http://a/b/c/g.") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '.g' should resolve to http://a/b/c/.g" do + expect((@uri + ".g").to_s).to eq("http://a/b/c/.g") + expect(Addressable::URI.join(@uri.to_s, ".g").to_s).to eq("http://a/b/c/.g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g..' should resolve to http://a/b/c/g.." do + expect((@uri + "g..").to_s).to eq("http://a/b/c/g..") + expect(Addressable::URI.join(@uri.to_s, "g..").to_s).to eq("http://a/b/c/g..") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with '..g' should resolve to http://a/b/c/..g" do + expect((@uri + "..g").to_s).to eq("http://a/b/c/..g") + expect(Addressable::URI.join(@uri.to_s, "..g").to_s).to eq("http://a/b/c/..g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with './../g' should resolve to http://a/b/g" do + expect((@uri + "./../g").to_s).to eq("http://a/b/g") + expect(Addressable::URI.join(@uri.to_s, "./../g").to_s).to eq("http://a/b/g") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with './g/.' should resolve to http://a/b/c/g/" do + expect((@uri + "./g/.").to_s).to eq("http://a/b/c/g/") + expect(Addressable::URI.join(@uri.to_s, "./g/.").to_s).to eq("http://a/b/c/g/") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g/./h' should resolve to http://a/b/c/g/h" do + expect((@uri + "g/./h").to_s).to eq("http://a/b/c/g/h") + expect(Addressable::URI.join(@uri.to_s, "g/./h").to_s).to eq("http://a/b/c/g/h") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g/../h' should resolve to http://a/b/c/h" do + expect((@uri + "g/../h").to_s).to eq("http://a/b/c/h") + expect(Addressable::URI.join(@uri.to_s, "g/../h").to_s).to eq("http://a/b/c/h") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g;x=1/./y' " + + "should resolve to http://a/b/c/g;x=1/y" do + expect((@uri + "g;x=1/./y").to_s).to eq("http://a/b/c/g;x=1/y") + expect(Addressable::URI.join( + @uri.to_s, "g;x=1/./y").to_s).to eq("http://a/b/c/g;x=1/y") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g;x=1/../y' should resolve to http://a/b/c/y" do + expect((@uri + "g;x=1/../y").to_s).to eq("http://a/b/c/y") + expect(Addressable::URI.join( + @uri.to_s, "g;x=1/../y").to_s).to eq("http://a/b/c/y") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g?y/./x' " + + "should resolve to http://a/b/c/g?y/./x" do + expect((@uri + "g?y/./x").to_s).to eq("http://a/b/c/g?y/./x") + expect(Addressable::URI.join( + @uri.to_s, "g?y/./x").to_s).to eq("http://a/b/c/g?y/./x") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g?y/../x' " + + "should resolve to http://a/b/c/g?y/../x" do + expect((@uri + "g?y/../x").to_s).to eq("http://a/b/c/g?y/../x") + expect(Addressable::URI.join( + @uri.to_s, "g?y/../x").to_s).to eq("http://a/b/c/g?y/../x") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g#s/./x' " + + "should resolve to http://a/b/c/g#s/./x" do + expect((@uri + "g#s/./x").to_s).to eq("http://a/b/c/g#s/./x") + expect(Addressable::URI.join( + @uri.to_s, "g#s/./x").to_s).to eq("http://a/b/c/g#s/./x") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'g#s/../x' " + + "should resolve to http://a/b/c/g#s/../x" do + expect((@uri + "g#s/../x").to_s).to eq("http://a/b/c/g#s/../x") + expect(Addressable::URI.join( + @uri.to_s, "g#s/../x").to_s).to eq("http://a/b/c/g#s/../x") + end + + # Section 5.4.2 of RFC 3986 + it "when joined with 'http:g' should resolve to http:g" do + expect((@uri + "http:g").to_s).to eq("http:g") + expect(Addressable::URI.join(@uri.to_s, "http:g").to_s).to eq("http:g") + end + + # Edge case to be sure + it "when joined with '//example.com/' should " + + "resolve to http://example.com/" do + expect((@uri + "//example.com/").to_s).to eq("http://example.com/") + expect(Addressable::URI.join( + @uri.to_s, "//example.com/").to_s).to eq("http://example.com/") + end + + it "when joined with a bogus object a TypeError should be raised" do + expect do + Addressable::URI.join(@uri, 42) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when converting the path " + + "'relative/path/to/something'" do + before do + @path = 'relative/path/to/something' + end + + it "should convert to " + + "\'relative/path/to/something\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("relative/path/to/something") + end + + it "should join with an absolute file path correctly" do + @base = Addressable::URI.convert_path("/absolute/path/") + @uri = Addressable::URI.convert_path(@path) + expect((@base + @uri).to_str).to eq( + "file:///absolute/path/relative/path/to/something" + ) + end +end + +describe Addressable::URI, "when converting a bogus path" do + it "should raise a TypeError" do + expect do + Addressable::URI.convert_path(42) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when given a UNIX root directory" do + before do + @path = "/" + end + + it "should convert to \'file:///\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given a Windows root directory" do + before do + @path = "C:\\" + end + + it "should convert to \'file:///c:/\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the path '/one/two/'" do + before do + @path = '/one/two/' + end + + it "should convert to " + + "\'file:///one/two/\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///one/two/") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the tld " do + it "'uk' should have a tld of 'uk'" do + uri = Addressable::URI.parse("http://example.com") + uri.tld = "uk" + + expect(uri.tld).to eq("uk") + end + + context "which " do + let (:uri) { Addressable::URI.parse("http://www.comrade.net/path/to/source/") } + + it "contains a subdomain" do + uri.tld = "co.uk" + + expect(uri.to_s).to eq("http://www.comrade.co.uk/path/to/source/") + end + + it "is part of the domain" do + uri.tld = "com" + + expect(uri.to_s).to eq("http://www.comrade.com/path/to/source/") + end + end +end + +describe Addressable::URI, "when given the path " + + "'c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the path " + + "'file://c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file://c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the path " + + "'file:c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file:c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the path " + + "'file:/c:\\windows\\My Documents 100%20\\foo.txt'" do + before do + @path = "file:/c:\\windows\\My Documents 100%20\\foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given the path " + + "'file:///c|/windows/My%20Documents%20100%20/foo.txt'" do + before do + @path = "file:///c|/windows/My%20Documents%20100%20/foo.txt" + end + + it "should convert to " + + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") + end + + it "should have an origin of 'file://'" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.origin).to eq('file://') + end +end + +describe Addressable::URI, "when given an http protocol URI" do + before do + @path = "http://example.com/" + end + + it "should not do any conversion at all" do + @uri = Addressable::URI.convert_path(@path) + expect(@uri.to_str).to eq("http://example.com/") + end +end + +class SuperString + def initialize(string) + @string = string.to_s + end + + def to_str + return @string + end +end + +describe Addressable::URI, "when parsing a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.parse(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.parse(42) + end.to raise_error(TypeError) + end + + it "should correctly parse heuristically anything with a 'to_str' method" do + Addressable::URI.heuristic_parse(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.heuristic_parse(42) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when form encoding a hash" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.form_encode( + [["&one", "/1"], ["=two", "?2"], [":three", "#3"]] + )).to eq("%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.form_encode( + {"q" => "one two three"} + )).to eq("q=one+two+three") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.form_encode( + {"key" => nil} + )).to eq("key=") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.form_encode( + {"q" => ["one", "two", "three"]} + )).to eq("q=one&q=two&q=three") + end + + it "should result in correctly encoded newlines" do + expect(Addressable::URI.form_encode( + {"text" => "one\ntwo\rthree\r\nfour\n\r"} + )).to eq("text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A") + end + + it "should result in a sorted percent encoded sequence" do + expect(Addressable::URI.form_encode( + [["a", "1"], ["dup", "3"], ["dup", "2"]], true + )).to eq("a=1&dup=2&dup=3") + end +end + +describe Addressable::URI, "when form encoding a non-Array object" do + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.form_encode(42) + end.to raise_error(TypeError) + end +end + +# See https://tools.ietf.org/html/rfc6749#appendix-B +describe Addressable::URI, "when form encoding the example value from OAuth 2" do + it "should result in correct values" do + expect(Addressable::URI.form_encode( + {"value" => " %&+£€"} + )).to eq("value=+%25%26%2B%C2%A3%E2%82%AC") + end +end + +# See https://tools.ietf.org/html/rfc6749#appendix-B +describe Addressable::URI, "when form unencoding the example value from OAuth 2" do + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "value=+%25%26%2B%C2%A3%E2%82%AC" + )).to eq([["value", " %&+£€"]]) + end +end + +describe Addressable::URI, "when form unencoding a string" do + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233" + )).to eq([["&one", "/1"], ["=two", "?2"], [":three", "#3"]]) + end + + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "q=one+two+three" + )).to eq([["q", "one two three"]]) + end + + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A" + )).to eq([["text", "one\ntwo\nthree\nfour\n\n"]]) + end + + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "a=1&dup=2&dup=3" + )).to eq([["a", "1"], ["dup", "2"], ["dup", "3"]]) + end + + it "should result in correct values" do + expect(Addressable::URI.form_unencode( + "key" + )).to eq([["key", nil]]) + end + + it "should result in correct values" do + expect(Addressable::URI.form_unencode("GivenName=Ren%C3%A9")).to eq( + [["GivenName", "René"]] + ) + end +end + +describe Addressable::URI, "when form unencoding a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.form_unencode(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.form_unencode(42) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when normalizing a non-String object" do + it "should correctly parse anything with a 'to_str' method" do + Addressable::URI.normalize_component(SuperString.new(42)) + end + + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.normalize_component(42) + end.to raise_error(TypeError) + end + + it "should raise a TypeError for objects than cannot be converted" do + expect do + Addressable::URI.normalize_component("component", 42) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when normalizing a path with an encoded slash" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.parse("/path%2Fsegment/").normalize.path).to eq( + "/path%2Fsegment/" + ) + end +end + +describe Addressable::URI, "when normalizing a path with special unicode" do + it "does not stop at or ignore null bytes" do + expect(Addressable::URI.parse("/path%00segment/").normalize.path).to eq( + "/path%00segment/" + ) + end + + it "does apply NFC unicode normalization" do + expect(Addressable::URI.parse("/%E2%84%A6").normalize.path).to eq( + "/%CE%A9" + ) + end + + it "does not apply NFKC unicode normalization" do + expect(Addressable::URI.parse("/%C2%AF%C2%A0").normalize.path).to eq( + "/%C2%AF%C2%A0" + ) + end +end + +describe Addressable::URI, "when normalizing a partially encoded string" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component( + "partially % encoded%21" + )).to eq("partially%20%25%20encoded!") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component( + "partially %25 encoded!" + )).to eq("partially%20%25%20encoded!") + end +end + +describe Addressable::URI, "when normalizing a unicode sequence" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component( + "/C%CC%A7" + )).to eq("/%C3%87") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component( + "/%C3%87" + )).to eq("/%C3%87") + end +end + +describe Addressable::URI, "when normalizing a multibyte string" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component("günther")).to eq( + "g%C3%BCnther" + ) + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component("g%C3%BCnther")).to eq( + "g%C3%BCnther" + ) + end +end + +describe Addressable::URI, "when normalizing a string but leaving some characters encoded" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.normalize_component("%58X%59Y%5AZ", "0-9a-zXY", "Y")).to eq( + "XX%59Y%5A%5A" + ) + end + + it "should not modify the character class" do + character_class = "0-9a-zXY" + + character_class_copy = character_class.dup + + Addressable::URI.normalize_component("%58X%59Y%5AZ", character_class, "Y") + + expect(character_class).to eq(character_class_copy) + end +end + +describe Addressable::URI, "when encoding IP literals" do + it "should work for IPv4" do + input = "http://127.0.0.1/" + expect(Addressable::URI.encode(input)).to eq(input) + end + + it "should work for IPv6" do + input = "http://[fe80::200:f8ff:fe21:67cf]/" + expect(Addressable::URI.encode(input)).to eq(input) + end +end + +describe Addressable::URI, "when encoding a string with existing encodings to upcase" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.encode_component("JK%4c", "0-9A-IKM-Za-z%", "L")).to eq("%4AK%4C") + end +end + +describe Addressable::URI, "when encoding a multibyte string" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.encode_component("günther")).to eq("g%C3%BCnther") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.encode_component( + "günther", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ + )).to eq("g%C3%BCnther") + end +end + +describe Addressable::URI, "when form encoding a multibyte string" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.form_encode({"GivenName" => "René"})).to eq( + "GivenName=Ren%C3%A9" + ) + end +end + +describe Addressable::URI, "when encoding a string with ASCII chars 0-15" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.encode_component("one\ntwo")).to eq("one%0Atwo") + end + + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.encode_component( + "one\ntwo", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ + )).to eq("one%0Atwo") + end +end + +describe Addressable::URI, "when unencoding a multibyte string" do + it "should result in correct percent encoded sequence" do + expect(Addressable::URI.unencode_component("g%C3%BCnther")).to eq("günther") + end + + it "should consistently use UTF-8 internally" do + expect(Addressable::URI.unencode_component("ski=%BA%DAɫ")).to eq("ski=\xBA\xDAɫ") + end + + it "should not fail with UTF-8 incompatible string" do + url = "/M%E9/\xE9?p=\xFC".b + expect(Addressable::URI.unencode_component(url)).to eq("/M\xE9/\xE9?p=\xFC") + end + + it "should result in correct percent encoded sequence as a URI" do + expect(Addressable::URI.unencode( + "/path?g%C3%BCnther", ::Addressable::URI + )).to eq(Addressable::URI.new( + :path => "/path", :query => "günther" + )) + end +end + +describe Addressable::URI, "when partially unencoding a string" do + it "should unencode all characters by default" do + expect(Addressable::URI.unencode('%%25~%7e+%2b', String)).to eq('%%~~++') + end + + it "should unencode characters not in leave_encoded" do + expect(Addressable::URI.unencode('%%25~%7e+%2b', String, '~')).to eq('%%~%7e++') + end + + it "should leave characters in leave_encoded alone" do + expect(Addressable::URI.unencode('%%25~%7e+%2b', String, '%~+')).to eq('%%25~%7e+%2b') + end +end + +describe Addressable::URI, "when unencoding a bogus object" do + it "should raise a TypeError" do + expect do + Addressable::URI.unencode_component(42) + end.to raise_error(TypeError) + end + + it "should raise a TypeError" do + expect do + Addressable::URI.unencode("/path?g%C3%BCnther", Integer) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when encoding a bogus object" do + it "should raise a TypeError" do + expect do + Addressable::URI.encode(Object.new) + end.to raise_error(TypeError) + end + + it "should raise a TypeError" do + expect do + Addressable::URI.normalized_encode(Object.new) + end.to raise_error(TypeError) + end + + it "should raise a TypeError" do + expect do + Addressable::URI.encode_component("günther", Object.new) + end.to raise_error(TypeError) + end + + it "should raise a TypeError" do + expect do + Addressable::URI.encode_component(Object.new) + end.to raise_error(TypeError) + end +end + +describe Addressable::URI, "when given the input " + + "'http://example.com/'" do + before do + @input = "http://example.com/" + end + + it "should heuristically parse to 'http://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com/") + end + + it "should not raise error when frozen" do + expect do + Addressable::URI.heuristic_parse(@input).freeze.to_s + end.not_to raise_error + end +end + +describe Addressable::URI, "when given the input " + + "'https://example.com/'" do + before do + @input = "https://example.com/" + end + + it "should heuristically parse to 'https://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("https://example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'http:example.com/'" do + before do + @input = "http:example.com/" + end + + it "should heuristically parse to 'http://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com/") + end + + it "should heuristically parse to 'http://example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'https:example.com/'" do + before do + @input = "https:example.com/" + end + + it "should heuristically parse to 'https://example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("https://example.com/") + end + + it "should heuristically parse to 'https://example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("https://example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'http://example.com/example.com/'" do + before do + @input = "http://example.com/example.com/" + end + + it "should heuristically parse to 'http://example.com/example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com/example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'http://prefix\\.example.com/'" do + before do + @input = "http://prefix\\.example.com/" + end + + it "should heuristically parse to 'http://prefix/.example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("prefix") + expect(@uri.to_s).to eq("http://prefix/.example.com/") + end + + it "should heuristically parse to 'http://prefix/.example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://prefix/.example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'http://p:\\/'" do + before do + @input = "http://p:\\/" + end + + it "should heuristically parse to 'http://p//'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("p") + expect(@uri.to_s).to eq("http://p//") + end + + it "should heuristically parse to 'http://p//' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://p//") + end +end + +describe Addressable::URI, "when given the input " + + "'http://p://'" do + before do + @input = "http://p://" + end + + it "should heuristically parse to 'http://p//'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("p") + expect(@uri.to_s).to eq("http://p//") + end + + it "should heuristically parse to 'http://p//' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://p//") + end +end + +describe Addressable::URI, "when given the input " + + "'http://p://p'" do + before do + @input = "http://p://p" + end + + it "should heuristically parse to 'http://p//p'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("p") + expect(@uri.to_s).to eq("http://p//p") + end + + it "should heuristically parse to 'http://p//p' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://p//p") + end +end + +describe Addressable::URI, "when given the input " + + "'http://prefix .example.com/'" do + before do + @input = "http://prefix .example.com/" + end + + # Justification here being that no browser actually tries to resolve this. + # They all treat this as a web search. + it "should heuristically parse to 'http://prefix%20.example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("prefix%20.example.com") + expect(@uri.to_s).to eq("http://prefix%20.example.com/") + end + + it "should heuristically parse to 'http://prefix%20.example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://prefix%20.example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "' http://www.example.com/ '" do + before do + @input = " http://www.example.com/ " + end + + it "should heuristically parse to 'http://prefix%20.example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.scheme).to eq("http") + expect(@uri.path).to eq("/") + expect(@uri.to_s).to eq("http://www.example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'http://prefix%2F.example.com/'" do + before do + @input = "http://prefix%2F.example.com/" + end + + it "should heuristically parse to 'http://prefix%2F.example.com/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.authority).to eq("prefix%2F.example.com") + expect(@uri.to_s).to eq("http://prefix%2F.example.com/") + end + + it "should heuristically parse to 'http://prefix%2F.example.com/' " + + "even with a scheme hint of 'ftp'" do + @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) + expect(@uri.to_s).to eq("http://prefix%2F.example.com/") + end +end + +describe Addressable::URI, "when given the input " + + "'/path/to/resource'" do + before do + @input = "/path/to/resource" + end + + it "should heuristically parse to '/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("/path/to/resource") + end +end + +describe Addressable::URI, "when given the input " + + "'relative/path/to/resource'" do + before do + @input = "relative/path/to/resource" + end + + it "should heuristically parse to 'relative/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("relative/path/to/resource") + end +end + +describe Addressable::URI, "when given the input " + + "'example.com'" do + before do + @input = "example.com" + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com") + end +end + +describe Addressable::URI, "when given the input " + + "'example.com' and a scheme hint of 'ftp'" do + before do + @input = "example.com" + @hints = {:scheme => 'ftp'} + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input, @hints) + expect(@uri.to_s).to eq("ftp://example.com") + end +end + +describe Addressable::URI, "when given the input " + + "'example.com:21' and a scheme hint of 'ftp'" do + before do + @input = "example.com:21" + @hints = {:scheme => 'ftp'} + end + + it "should heuristically parse to 'http://example.com:21'" do + @uri = Addressable::URI.heuristic_parse(@input, @hints) + expect(@uri.to_s).to eq("ftp://example.com:21") + end +end + +describe Addressable::URI, "when given the input " + + "'example.com/path/to/resource'" do + before do + @input = "example.com/path/to/resource" + end + + it "should heuristically parse to 'http://example.com/path/to/resource'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com/path/to/resource") + end +end + +describe Addressable::URI, "when given the input " + + "'http:///example.com'" do + before do + @input = "http:///example.com" + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com") + end +end + +describe Addressable::URI, "when given the input which "\ + "start with digits and has specified port" do + before do + @input = "7777.example.org:8089" + end + + it "should heuristically parse to 'http://7777.example.org:8089'" do + uri = Addressable::URI.heuristic_parse(@input) + expect(uri.to_s).to eq("http://7777.example.org:8089") + end +end + +describe Addressable::URI, "when given the input " + + "'feed:///example.com'" do + before do + @input = "feed:///example.com" + end + + it "should heuristically parse to 'feed://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("feed://example.com") + end +end + +describe Addressable::URI, "when given the input " + + "'file://localhost/path/to/resource/'" do + before do + @input = "file://localhost/path/to/resource/" + end + + it "should heuristically parse to 'file:///path/to/resource/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("file:///path/to/resource/") + end +end + +describe Addressable::URI, "when given the input " + + "'file://path/to/resource/'" do + before do + @input = "file://path/to/resource/" + end + + it "should heuristically parse to 'file:///path/to/resource/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("file:///path/to/resource/") + end +end + +describe Addressable::URI, "when given the input " + + "'file://///path/to/resource/'" do + before do + @input = "file:///////path/to/resource/" + end + + it "should heuristically parse to 'file:////path/to/resource/'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("file:////path/to/resource/") + end +end + +describe Addressable::URI, "when given the input " + + "'feed://http://example.com'" do + before do + @input = "feed://http://example.com" + end + + it "should heuristically parse to 'feed:http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("feed:http://example.com") + end +end + +describe Addressable::URI, "when given the input " + + "::URI.parse('http://example.com')" do + before do + @input = ::URI.parse('http://example.com') + end + + it "should heuristically parse to 'http://example.com'" do + @uri = Addressable::URI.heuristic_parse(@input) + expect(@uri.to_s).to eq("http://example.com") + end +end + +describe Addressable::URI, "when given the input: 'user@domain.com'" do + before do + @input = "user@domain.com" + end + + context "for heuristic parse" do + it "should remain 'mailto:user@domain.com'" do + uri = Addressable::URI.heuristic_parse("mailto:#{@input}") + expect(uri.to_s).to eq("mailto:user@domain.com") + end + + it "should have a scheme of 'mailto'" do + uri = Addressable::URI.heuristic_parse(@input) + expect(uri.to_s).to eq("mailto:user@domain.com") + expect(uri.scheme).to eq("mailto") + end + + it "should remain 'acct:user@domain.com'" do + uri = Addressable::URI.heuristic_parse("acct:#{@input}") + expect(uri.to_s).to eq("acct:user@domain.com") + end + + context "HTTP" do + before do + @uri = Addressable::URI.heuristic_parse("http://#{@input}/") + end + + it "should remain 'http://user@domain.com/'" do + expect(@uri.to_s).to eq("http://user@domain.com/") + end + + it "should have the username 'user' for HTTP basic authentication" do + expect(@uri.user).to eq("user") + end + end + end +end + +describe Addressable::URI, "when assigning query values" do + before do + @uri = Addressable::URI.new + end + + it "should correctly assign {:a => 'a', :b => ['c', 'd', 'e']}" do + @uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + expect(@uri.query).to eq("a=a&b=c&b=d&b=e") + end + + it "should raise an error attempting to assign {'a' => {'b' => ['c']}}" do + expect do + @uri.query_values = { 'a' => {'b' => ['c'] } } + end.to raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:b => '2', :a => {:c => '1'}}" do + expect do + @uri.query_values = {:b => '2', :a => {:c => '1'}} + end.to raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => [{:c => 'c', :d => 'd'}, " + + "{:e => 'e', :f => 'f'}]}" do + expect do + @uri.query_values = { + :a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}] + } + end.to raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => [{:c => true, :d => 'd'}, " + + "{:e => 'e', :f => 'f'}]}" do + expect do + @uri.query_values = { + :a => 'a', :b => [{:c => true, :d => 'd'}, {:e => 'e', :f => 'f'}] + } + end.to raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do + expect do + @uri.query_values = { + :a => 'a', :b => {:c => true, :d => 'd'} + } + end.to raise_error(TypeError) + end + + it "should raise an error attempting to assign " + + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do + expect do + @uri.query_values = { + :a => 'a', :b => {:c => true, :d => 'd'} + } + end.to raise_error(TypeError) + end + + it "should correctly assign {:a => 1, :b => 1.5}" do + @uri.query_values = { :a => 1, :b => 1.5 } + expect(@uri.query).to eq("a=1&b=1.5") + end + + it "should raise an error attempting to assign " + + "{:z => 1, :f => [2, {999.1 => [3,'4']}, ['h', 'i']], " + + ":a => {:b => ['c', 'd'], :e => true, :y => 0.5}}" do + expect do + @uri.query_values = { + :z => 1, + :f => [ 2, {999.1 => [3,'4']}, ['h', 'i'] ], + :a => { :b => ['c', 'd'], :e => true, :y => 0.5 } + } + end.to raise_error(TypeError) + end + + it "should correctly assign {}" do + @uri.query_values = {} + expect(@uri.query).to eq('') + end + + it "should correctly assign nil" do + @uri.query_values = nil + expect(@uri.query).to eq(nil) + end + + it "should correctly sort {'ab' => 'c', :ab => 'a', :a => 'x'}" do + @uri.query_values = {'ab' => 'c', :ab => 'a', :a => 'x'} + expect(@uri.query).to eq("a=x&ab=a&ab=c") + end + + it "should correctly assign " + + "[['b', 'c'], ['b', 'a'], ['a', 'a']]" do + # Order can be guaranteed in this format, so preserve it. + @uri.query_values = [['b', 'c'], ['b', 'a'], ['a', 'a']] + expect(@uri.query).to eq("b=c&b=a&a=a") + end + + it "should preserve query string order" do + query_string = (('a'..'z').to_a.reverse.map { |e| "#{e}=#{e}" }).join("&") + @uri.query = query_string + original_uri = @uri.to_s + @uri.query_values = @uri.query_values(Array) + expect(@uri.to_s).to eq(original_uri) + end + + describe 'when a hash with mixed types is assigned to query_values' do + it 'should not raise an error' do + skip 'Issue #94' + expect { subject.query_values = { "page" => "1", :page => 2 } }.to_not raise_error + end + end +end + +describe Addressable::URI, "when assigning path values" do + before do + @uri = Addressable::URI.new + end + + it "should correctly assign paths containing colons" do + @uri.path = "acct:bob@sporkmonger.com" + expect(@uri.path).to eq("acct:bob@sporkmonger.com") + expect(@uri.normalize.to_str).to eq("acct%2Fbob@sporkmonger.com") + expect { @uri.to_s }.to raise_error( + Addressable::URI::InvalidURIError + ) + end + + it "should correctly assign paths containing colons" do + @uri.path = "/acct:bob@sporkmonger.com" + @uri.authority = "example.com" + expect(@uri.normalize.to_str).to eq("//example.com/acct:bob@sporkmonger.com") + end + + it "should correctly assign paths containing colons" do + @uri.path = "acct:bob@sporkmonger.com" + @uri.scheme = "something" + expect(@uri.normalize.to_str).to eq("something:acct:bob@sporkmonger.com") + end + + it "should not allow relative paths to be assigned on absolute URIs" do + expect do + @uri.scheme = "http" + @uri.host = "example.com" + @uri.path = "acct:bob@sporkmonger.com" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow relative paths to be assigned on absolute URIs" do + expect do + @uri.path = "acct:bob@sporkmonger.com" + @uri.scheme = "http" + @uri.host = "example.com" + end.to raise_error(Addressable::URI::InvalidURIError) + end + + it "should not allow relative paths to be assigned on absolute URIs" do + expect do + @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12" + @uri.scheme = "urn" + end.not_to raise_error + end +end + +describe Addressable::URI, "when initializing a subclass of Addressable::URI" do + before do + @uri = Class.new(Addressable::URI).new + end + + it "should have the same class after being parsed" do + expect(@uri.class).to eq(Addressable::URI.parse(@uri).class) + end + + it "should have the same class as its duplicate" do + expect(@uri.class).to eq(@uri.dup.class) + end + + it "should have the same class after being normalized" do + expect(@uri.class).to eq(@uri.normalize.class) + end + + it "should have the same class after being merged" do + expect(@uri.class).to eq(@uri.merge(:path => 'path').class) + end + + it "should have the same class after being joined" do + expect(@uri.class).to eq(@uri.join('path').class) + end +end + +describe Addressable::URI, "support serialization roundtrip" do + before do + @uri = Addressable::URI.new( + :scheme => "http", + :user => "user", + :password => "password", + :host => "example.com", + :port => 80, + :path => "/path", + :query => "query=value", + :fragment => "fragment" + ) + end + + it "is in a working state after being serialized with Marshal" do + @uri = Addressable::URI.parse("http://example.com") + cloned_uri = Marshal.load(Marshal.dump(@uri)) + expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme + end + + it "is in a working state after being serialized with YAML" do + @uri = Addressable::URI.parse("http://example.com") + cloned_uri = if YAML.respond_to?(:unsafe_load) + YAML.unsafe_load(YAML.dump(@uri)) + else + YAML.load(YAML.dump(@uri)) + end + expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme + end +end + +describe Addressable::URI, "when initialized in a non-main `Ractor`" do + it "should have the same value as if used in the main `Ractor`" do + pending("Ruby 3.0+ for `Ractor` support") unless defined?(Ractor) + main = Addressable::URI.parse("http://example.com") + expect( + Ractor.new { Addressable::URI.parse("http://example.com") }.take + ).to eq(main) + end +end + +describe Addressable::URI, "when deferring validation" do + subject(:deferred) { uri.instance_variable_get(:@validation_deferred) } + + let(:uri) { Addressable::URI.parse("http://example.com") } + + it "defers validation within the block" do + uri.defer_validation do + expect(deferred).to be true + end + end + + it "always resets deferral afterward" do + expect { uri.defer_validation { raise "boom" } }.to raise_error("boom") + expect(deferred).to be false + end + + it "returns nil" do + res = uri.defer_validation {} + expect(res).to be nil + end +end + +describe Addressable::URI, "YAML safe loading" do + it "doesn't serialize anonymous objects" do + url = Addressable::URI.parse("http://example.com/") + expect(YAML.dump(url)).to_not include("!ruby/object {}") + end +end diff --git a/bin/gems/addressable-2.8.7/spec/spec_helper.rb b/bin/gems/addressable-2.8.7/spec/spec_helper.rb new file mode 100644 index 00000000..bd8e3958 --- /dev/null +++ b/bin/gems/addressable-2.8.7/spec/spec_helper.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'bundler/setup' +require 'rspec/its' + +begin + require 'coveralls' + Coveralls.wear! do + add_filter "spec/" + add_filter "vendor/" + end +rescue LoadError + warn "warning: coveralls gem not found; skipping Coveralls" + require 'simplecov' + SimpleCov.start do + add_filter "spec/" + add_filter "vendor/" + end +end if Gem.loaded_specs.key?("simplecov") + +class TestHelper + def self.native_supported? + mri = RUBY_ENGINE == "ruby" + windows = RUBY_PLATFORM.include?("mingw") + + mri && !windows + end +end + +RSpec.configure do |config| + config.warnings = true + config.filter_run_when_matching :focus +end diff --git a/bin/gems/addressable-2.8.7/tasks/clobber.rake b/bin/gems/addressable-2.8.7/tasks/clobber.rake new file mode 100644 index 00000000..a9e32b34 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/clobber.rake @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +desc "Remove all build products" +task "clobber" diff --git a/bin/gems/addressable-2.8.7/tasks/gem.rake b/bin/gems/addressable-2.8.7/tasks/gem.rake new file mode 100644 index 00000000..70b1f97d --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/gem.rake @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require "rubygems/package_task" + +namespace :gem do + GEM_SPEC = Gem::Specification.new do |s| + s.name = PKG_NAME + s.version = PKG_VERSION + s.summary = PKG_SUMMARY + s.description = PKG_DESCRIPTION + + s.files = PKG_FILES.to_a + + s.extra_rdoc_files = %w( README.md ) + s.rdoc_options.concat ["--main", "README.md"] + + if !s.respond_to?(:add_development_dependency) + puts "Cannot build Gem with this version of RubyGems." + exit(1) + end + + s.required_ruby_version = ">= 2.2" + + s.add_runtime_dependency "public_suffix", ">= 2.0.2", "< 7.0" + s.add_development_dependency "bundler", ">= 1.0", "< 3.0" + + s.require_path = "lib" + + s.author = "Bob Aman" + s.email = "bob@sporkmonger.com" + s.homepage = "https://github.com/sporkmonger/addressable" + s.license = "Apache-2.0" + s.metadata = { + "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md#v#{PKG_VERSION}" + } + end + + Gem::PackageTask.new(GEM_SPEC) do |p| + p.gem_spec = GEM_SPEC + p.need_tar = true + p.need_zip = true + end + + desc "Generates .gemspec file" + task :gemspec do + spec_string = GEM_SPEC.to_ruby + File.open("#{GEM_SPEC.name}.gemspec", "w") do |file| + file.write spec_string + end + end + + desc "Show information about the gem" + task :debug do + puts GEM_SPEC.to_ruby + end + + desc "Install the gem" + task :install => ["clobber", "gem:package"] do + sh "gem install --local ./pkg/#{GEM_SPEC.full_name}.gem" + end + + desc "Uninstall the gem" + task :uninstall do + installed_list = Gem.source_index.find_name(PKG_NAME) + if installed_list && + (installed_list.collect { |s| s.version.to_s}.include?(PKG_VERSION)) + sh( + "gem uninstall --version '#{PKG_VERSION}' " + + "--ignore-dependencies --executables #{PKG_NAME}" + ) + end + end + + desc "Reinstall the gem" + task :reinstall => [:uninstall, :install] + + desc "Package for release" + task :release => ["gem:package", "gem:gemspec"] do |t| + v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z" + abort "Versions don't match #{v} vs #{PROJ.version}" if v != PKG_VERSION + pkg = "pkg/#{GEM_SPEC.full_name}" + + changelog = File.open("CHANGELOG.md") { |file| file.read } + + puts "Releasing #{PKG_NAME} v. #{PKG_VERSION}" + Rake::Task["git:tag:create"].invoke + end +end + +desc "Alias to gem:package" +task "gem" => "gem:package" + +task "gem:release" => "gem:gemspec" + +task "clobber" => ["gem:clobber_package"] diff --git a/bin/gems/addressable-2.8.7/tasks/git.rake b/bin/gems/addressable-2.8.7/tasks/git.rake new file mode 100644 index 00000000..1238c8d2 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/git.rake @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +namespace :git do + namespace :tag do + desc "List tags from the Git repository" + task :list do + tags = `git tag -l` + tags.gsub!("\r", "") + tags = tags.split("\n").sort {|a, b| b <=> a } + puts tags.join("\n") + end + + desc "Create a new tag in the Git repository" + task :create do + changelog = File.open("CHANGELOG.md", "r") { |file| file.read } + puts "-" * 80 + puts changelog + puts "-" * 80 + puts + + v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z" + abort "Versions don't match #{v} vs #{PKG_VERSION}" if v != PKG_VERSION + + git_status = `git status` + if git_status !~ /^nothing to commit/ + abort "Working directory isn't clean." + end + + tag = "#{PKG_NAME}-#{PKG_VERSION}" + msg = "Release #{PKG_NAME}-#{PKG_VERSION}" + + existing_tags = `git tag -l #{PKG_NAME}-*`.split('\n') + if existing_tags.include?(tag) + warn("Tag already exists, deleting...") + unless system "git tag -d #{tag}" + abort "Tag deletion failed." + end + end + puts "Creating git tag '#{tag}'..." + unless system "git tag -a -m \"#{msg}\" #{tag}" + abort "Tag creation failed." + end + end + end +end + +task "gem:release" => "git:tag:create" diff --git a/bin/gems/addressable-2.8.7/tasks/metrics.rake b/bin/gems/addressable-2.8.7/tasks/metrics.rake new file mode 100644 index 00000000..107cc244 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/metrics.rake @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +namespace :metrics do + task :lines do + lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 + for file_name in FileList["lib/**/*.rb"] + f = File.open(file_name) + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end + puts "L: #{sprintf("%4d", lines)}, " + + "LOC #{sprintf("%4d", codelines)} | #{file_name}" + total_lines += lines + total_codelines += codelines + + lines, codelines = 0, 0 + end + + puts "Total: Lines #{total_lines}, LOC #{total_codelines}" + end +end diff --git a/bin/gems/addressable-2.8.7/tasks/profile.rake b/bin/gems/addressable-2.8.7/tasks/profile.rake new file mode 100644 index 00000000..b697d489 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/profile.rake @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +namespace :profile do + desc "Profile Template match memory allocations" + task :template_match_memory do + require "memory_profiler" + require "addressable/template" + + start_at = Time.now.to_f + template = Addressable::Template.new("http://example.com/{?one,two,three}") + report = MemoryProfiler.report do + 30_000.times do + template.match( + "http://example.com/?one=one&two=floo&three=me" + ) + end + end + end_at = Time.now.to_f + print_options = { scale_bytes: true, normalize_paths: true } + puts "\n\n" + + if ENV["CI"] + report.pretty_print(print_options) + else + t_allocated = report.scale_bytes(report.total_allocated_memsize) + t_retained = report.scale_bytes(report.total_retained_memsize) + + puts "Total allocated: #{t_allocated} (#{report.total_allocated} objects)" + puts "Total retained: #{t_retained} (#{report.total_retained} objects)" + puts "Took #{end_at - start_at} seconds" + + FileUtils.mkdir_p("tmp") + report.pretty_print(to_file: "tmp/memprof.txt", **print_options) + end + end + + desc "Profile URI parse memory allocations" + task :memory do + require "memory_profiler" + require "addressable/uri" + if ENV["IDNA_MODE"] == "pure" + Addressable.send(:remove_const, :IDNA) + load "addressable/idna/pure.rb" + end + + start_at = Time.now.to_f + report = MemoryProfiler.report do + 30_000.times do + Addressable::URI.parse( + "http://google.com/stuff/../?with_lots=of¶ms=asdff#!stuff" + ).normalize + end + end + end_at = Time.now.to_f + print_options = { scale_bytes: true, normalize_paths: true } + puts "\n\n" + + if ENV["CI"] + report.pretty_print(**print_options) + else + t_allocated = report.scale_bytes(report.total_allocated_memsize) + t_retained = report.scale_bytes(report.total_retained_memsize) + + puts "Total allocated: #{t_allocated} (#{report.total_allocated} objects)" + puts "Total retained: #{t_retained} (#{report.total_retained} objects)" + puts "Took #{end_at - start_at} seconds" + + FileUtils.mkdir_p("tmp") + report.pretty_print(to_file: "tmp/memprof.txt", **print_options) + end + end +end diff --git a/bin/gems/addressable-2.8.7/tasks/rspec.rake b/bin/gems/addressable-2.8.7/tasks/rspec.rake new file mode 100644 index 00000000..e3d9f014 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/rspec.rake @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "rspec/core/rake_task" + +namespace :spec do + RSpec::Core::RakeTask.new(:simplecov) do |t| + t.pattern = FileList['spec/**/*_spec.rb'] + t.rspec_opts = %w[--color --format documentation] unless ENV["CI"] + end + + namespace :simplecov do + desc "Browse the code coverage report." + task :browse => "spec:simplecov" do + require "launchy" + Launchy.open("coverage/index.html") + end + end +end + +desc "Alias to spec:simplecov" +task "spec" => "spec:simplecov" + +task "clobber" => ["spec:clobber_simplecov"] diff --git a/bin/gems/addressable-2.8.7/tasks/yard.rake b/bin/gems/addressable-2.8.7/tasks/yard.rake new file mode 100644 index 00000000..515f9603 --- /dev/null +++ b/bin/gems/addressable-2.8.7/tasks/yard.rake @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "rake" + +begin + require "yard" + require "yard/rake/yardoc_task" + + namespace :doc do + desc "Generate Yardoc documentation" + YARD::Rake::YardocTask.new do |yardoc| + yardoc.name = "yard" + yardoc.options = ["--verbose", "--markup", "markdown"] + yardoc.files = FileList[ + "lib/**/*.rb", "ext/**/*.c", + "README.md", "CHANGELOG.md", "LICENSE.txt" + ].exclude(/idna/) + end + end + + task "clobber" => ["doc:clobber_yard"] + + desc "Alias to doc:yard" + task "doc" => "doc:yard" +rescue LoadError + # If yard isn't available, it's not the end of the world + desc "Alias to doc:rdoc" + task "doc" => "doc:rdoc" +end diff --git a/bin/gems/addressable-2.9.0/CHANGELOG.md b/bin/gems/addressable-2.9.0/CHANGELOG.md new file mode 100644 index 00000000..76708d4d --- /dev/null +++ b/bin/gems/addressable-2.9.0/CHANGELOG.md @@ -0,0 +1,326 @@ +# Changelog + +## Addressable 2.9.0 +- fixes ReDoS vulnerability in Addressable::Template#match (fixes incomplete + remediation in 2.8.10) + +## Addressable 2.8.10 +- fixes ReDoS vulnerability in Addressable::Template#match + +## Addressable 2.8.9 +- Reduce gem size by excluding test files ([#569]) +- No need for bundler as development dependency ([#571], [5fc1d93](https://github.com/sporkmonger/addressable/commit/5fc1d93)) +- idna/pure: stop building the useless `COMPOSITION_TABLE` (removes the `Addressable::IDNA::COMPOSITION_TABLE` constant) ([#564]) + +[#569]: https://github.com/sporkmonger/addressable/pull/569 +[#571]: https://github.com/sporkmonger/addressable/pull/571 +[#564]: https://github.com/sporkmonger/addressable/pull/564 + +## Addressable 2.8.8 +- Replace the `unicode.data` blob by a ruby constant ([#561]) +- Allow `public_suffix` 7 ([#558]) + +[#561]: https://github.com/sporkmonger/addressable/pull/561 +[#558]: https://github.com/sporkmonger/addressable/pull/558 + +## Addressable 2.8.7 +- Allow `public_suffix` 6 ([#535]) + +[#535]: https://github.com/sporkmonger/addressable/pull/535 + +## Addressable 2.8.6 +- Memoize regexps for common character classes ([#524]) + +[#524]: https://github.com/sporkmonger/addressable/pull/524 + +## Addressable 2.8.5 +- Fix thread safety issue with encoding tables ([#515]) +- Define URI::NONE as a module to avoid serialization issues ([#509]) +- Fix YAML serialization ([#508]) + +[#508]: https://github.com/sporkmonger/addressable/pull/508 +[#509]: https://github.com/sporkmonger/addressable/pull/509 +[#515]: https://github.com/sporkmonger/addressable/pull/515 + +## Addressable 2.8.4 +- Restore `Addressable::IDNA.unicode_normalize_kc` as a deprecated method ([#504]) + +[#504]: https://github.com/sporkmonger/addressable/pull/504 + +## Addressable 2.8.3 +- Fix template expand level 2 hash support for non-string objects ([#499], [#498]) + +[#499]: https://github.com/sporkmonger/addressable/pull/499 +[#498]: https://github.com/sporkmonger/addressable/pull/498 + +## Addressable 2.8.2 +- Improve cache hits and JIT friendliness ([#486](https://github.com/sporkmonger/addressable/pull/486)) +- Improve code style and test coverage ([#482](https://github.com/sporkmonger/addressable/pull/482)) +- Ensure reset of deferred validation ([#481](https://github.com/sporkmonger/addressable/pull/481)) +- Resolve normalization differences between `IDNA::Native` and `IDNA::Pure` ([#408](https://github.com/sporkmonger/addressable/issues/408), [#492]) +- Remove redundant colon in `Addressable::URI::CharacterClasses::AUTHORITY` regex ([#438](https://github.com/sporkmonger/addressable/pull/438)) (accidentally reverted by [#449] merge but [added back](https://github.com/sporkmonger/addressable/pull/492#discussion_r1105125280) in [#492]) + +[#492]: https://github.com/sporkmonger/addressable/pull/492 + +## Addressable 2.8.1 +- refactor `Addressable::URI.normalize_path` to address linter offenses ([#430](https://github.com/sporkmonger/addressable/pull/430)) +- update gemspec to reflect supported Ruby versions ([#466], [#464], [#463]) +- compatibility w/ public_suffix 5.x ([#466], [#465], [#460]) +- fixes "invalid byte sequence in UTF-8" exception when unencoding URLs containing non UTF-8 characters ([#459](https://github.com/sporkmonger/addressable/pull/459)) +- `Ractor` compatibility ([#449]) +- use the whole string instead of a single line for template match ([#431](https://github.com/sporkmonger/addressable/pull/431)) +- force UTF-8 encoding only if needed ([#341](https://github.com/sporkmonger/addressable/pull/341)) + +[#449]: https://github.com/sporkmonger/addressable/pull/449 +[#460]: https://github.com/sporkmonger/addressable/pull/460 +[#463]: https://github.com/sporkmonger/addressable/pull/463 +[#464]: https://github.com/sporkmonger/addressable/pull/464 +[#465]: https://github.com/sporkmonger/addressable/pull/465 +[#466]: https://github.com/sporkmonger/addressable/pull/466 + +## Addressable 2.8.0 +- fixes ReDoS vulnerability in Addressable::Template#match +- no longer replaces `+` with spaces in queries for non-http(s) schemes +- fixed encoding ipv6 literals +- the `:compacted` flag for `normalized_query` now dedupes parameters +- fix broken `escape_component` alias +- dropping support for Ruby 2.0 and 2.1 +- adding Ruby 3.0 compatibility for development tasks +- drop support for `rack-mount` and remove Addressable::Template#generate +- performance improvements +- switch CI/CD to GitHub Actions + +## Addressable 2.7.0 +- added `:compacted` flag to `normalized_query` +- `heuristic_parse` handles `mailto:` more intuitively +- dropped explicit support for JRuby 9.0.5.0 +- compatibility w/ public_suffix 4.x +- performance improvements + +## Addressable 2.6.0 +- added `tld=` method to allow assignment to the public suffix +- most `heuristic_parse` patterns are now case-insensitive +- `heuristic_parse` handles more `file://` URI variations +- fixes bug in `heuristic_parse` when uri starts with digit +- fixes bug in `request_uri=` with query strings +- fixes template issues with `nil` and `?` operator +- `frozen_string_literal` pragmas added +- minor performance improvements in regexps +- fixes to eliminate warnings + +## Addressable 2.5.2 +- better support for frozen string literals +- fixed bug w/ uppercase characters in scheme +- IDNA errors w/ emoji URLs +- compatibility w/ public_suffix 3.x + +## Addressable 2.5.1 +- allow unicode normalization to be disabled for URI Template expansion +- removed duplicate test + +## Addressable 2.5.0 +- dropping support for Ruby 1.9 +- adding support for Ruby 2.4 preview +- add support for public suffixes and tld; first runtime dependency +- hostname escaping should match RFC; underscores in hostnames no longer escaped +- paths beginning with // and missing an authority are now considered invalid +- validation now also takes place after setting a path +- handle backslashes in authority more like a browser for `heuristic_parse` +- unescaped backslashes in host now raise an `InvalidURIError` +- `merge!`, `join!`, `omit!` and `normalize!` don't disable deferred validation +- `heuristic_parse` now trims whitespace before parsing +- host parts longer than 63 bytes will be ignored and not passed to libidn +- normalized values always encoded as UTF-8 + +## Addressable 2.4.0 +- support for 1.8.x dropped +- double quotes in a host now raises an error +- newlines in host will no longer get unescaped during normalization +- stricter handling of bogus scheme values +- stricter handling of encoded port values +- calling `require 'addressable'` will now load both the URI and Template files +- assigning to the `hostname` component with an `IPAddr` object is now supported +- assigning to the `origin` component is now supported +- fixed minor bug where an exception would be thrown for a missing ACE suffix +- better partial expansion of URI templates + +## Addressable 2.3.8 +- fix warnings +- update dependency gems +- support for 1.8.x officially deprecated + +## Addressable 2.3.7 +- fix scenario in which invalid URIs don't get an exception until inspected +- handle hostnames with two adjacent periods correctly +- upgrade of RSpec + +## Addressable 2.3.6 +- normalization drops empty query string +- better handling in template extract for missing values +- template modifier for `'?'` now treated as optional +- fixed issue where character class parameters were modified +- templates can now be tested for equality +- added `:sorted` option to normalization of query strings +- fixed issue with normalization of hosts given in `'example.com.'` form + +## Addressable 2.3.5 +- added Addressable::URI#empty? method +- Addressable::URI#hostname methods now strip square brackets from IPv6 hosts +- compatibility with Net::HTTP in Ruby 2.0.0 +- Addressable::URI#route_from should always give relative URIs + +## Addressable 2.3.4 +- fixed issue with encoding altering its inputs +- query string normalization now leaves ';' characters alone +- FakeFS is detected before attempting to load unicode tables +- additional testing to ensure frozen objects don't cause problems + +## Addressable 2.3.3 +- fixed issue with converting common primitives during template expansion +- fixed port encoding issue +- removed a few warnings +- normalize should now ignore %2B in query strings +- the IDNA logic should now be handled by libidn in Ruby 1.9 +- no template match should now result in nil instead of an empty MatchData +- added license information to gemspec + +## Addressable 2.3.2 +- added Addressable::URI#default_port method +- fixed issue with Marshalling Unicode data on Windows +- improved heuristic parsing to better handle IPv4 addresses + +## Addressable 2.3.1 +- fixed missing unicode data file + +## Addressable 2.3.0 +- updated Addressable::Template to use RFC 6570, level 4 +- fixed compatibility problems with some versions of Ruby +- moved unicode tables into a data file for performance reasons +- removing support for multiple query value notations + +## Addressable 2.2.8 +- fixed issues with dot segment removal code +- form encoding can now handle multiple values per key +- updated development environment + +## Addressable 2.2.7 +- fixed issues related to Addressable::URI#query_values= +- the Addressable::URI.parse method is now polymorphic + +## Addressable 2.2.6 +- changed the way ambiguous paths are handled +- fixed bug with frozen URIs +- https supported in heuristic parsing + +## Addressable 2.2.5 +- 'parsing' a pre-parsed URI object is now a dup operation +- introduced conditional support for libidn +- fixed normalization issue on ampersands in query strings +- added additional tests around handling of query strings + +## Addressable 2.2.4 +- added origin support from draft-ietf-websec-origin-00 +- resolved issue with attempting to navigate below root +- fixed bug with string splitting in query strings + +## Addressable 2.2.3 +- added :flat_array notation for query strings + +## Addressable 2.2.2 +- fixed issue with percent escaping of '+' character in query strings + +## Addressable 2.2.1 +- added support for application/x-www-form-urlencoded. + +## Addressable 2.2.0 +- added site methods +- improved documentation + +## Addressable 2.1.2 +- added HTTP request URI methods +- better handling of Windows file paths +- validation_deferred boolean replaced with defer_validation block +- normalization of percent-encoded paths should now be correct +- fixed issue with constructing URIs with relative paths +- fixed warnings + +## Addressable 2.1.1 +- more type checking changes +- fixed issue with unicode normalization +- added method to find template defaults +- symbolic keys are now allowed in template mappings +- numeric values and symbolic values are now allowed in template mappings + +## Addressable 2.1.0 +- refactored URI template support out into its own class +- removed extract method due to being useless and unreliable +- removed Addressable::URI.expand_template +- removed Addressable::URI#extract_mapping +- added partial template expansion +- fixed minor bugs in the parse and heuristic_parse methods +- fixed incompatibility with Ruby 1.9.1 +- fixed bottleneck in Addressable::URI#hash and Addressable::URI#to_s +- fixed unicode normalization exception +- updated query_values methods to better handle subscript notation +- worked around issue with freezing URIs +- improved specs + +## Addressable 2.0.2 +- fixed issue with URI template expansion +- fixed issue with percent escaping characters 0-15 + +## Addressable 2.0.1 +- fixed issue with query string assignment +- fixed issue with improperly encoded components + +## Addressable 2.0.0 +- the initialize method now takes an options hash as its only parameter +- added query_values method to URI class +- completely replaced IDNA implementation with pure Ruby +- renamed Addressable::ADDRESSABLE_VERSION to Addressable::VERSION +- completely reworked the Rakefile +- changed the behavior of the port method significantly +- Addressable::URI.encode_segment, Addressable::URI.unencode_segment renamed +- documentation is now in YARD format +- more rigorous type checking +- to_str method implemented, implicit conversion to Strings now allowed +- Addressable::URI#omit method added, Addressable::URI#merge method replaced +- updated URI Template code to match v 03 of the draft spec +- added a bunch of new specifications + +## Addressable 1.0.4 +- switched to using RSpec's pending system for specs that rely on IDN +- fixed issue with creating URIs with paths that are not prefixed with '/' + +## Addressable 1.0.3 +- implemented a hash method + +## Addressable 1.0.2 +- fixed minor bug with the extract_mapping method + +## Addressable 1.0.1 +- fixed minor bug with the extract_mapping method + +## Addressable 1.0.0 +- heuristic parse method added +- parsing is slightly more strict +- replaced to_h with to_hash +- fixed routing methods +- improved specifications +- improved heckle rake task +- no surviving heckle mutations + +## Addressable 0.1.2 +- improved normalization +- fixed bug in joining algorithm +- updated specifications + +## Addressable 0.1.1 +- updated documentation +- added URI Template variable extraction + +## Addressable 0.1.0 +- initial release +- implementation based on RFC 3986, 3987 +- support for IRIs via libidn +- support for the URI Template draft spec diff --git a/bin/gems/addressable-2.9.0/LICENSE.txt b/bin/gems/addressable-2.9.0/LICENSE.txt new file mode 100644 index 00000000..ef51da2b --- /dev/null +++ b/bin/gems/addressable-2.9.0/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bin/gems/addressable-2.9.0/README.md b/bin/gems/addressable-2.9.0/README.md new file mode 100644 index 00000000..d9fa04f2 --- /dev/null +++ b/bin/gems/addressable-2.9.0/README.md @@ -0,0 +1,121 @@ +# Addressable + +
+
Homepage
github.com/sporkmonger/addressable
+
Author
Bob Aman
+
Copyright
Copyright © Bob Aman
+
License
Apache 2.0
+
+ +[![Gem Version](https://img.shields.io/gem/dt/addressable.svg)][gem] +[![Build Status](https://github.com/sporkmonger/addressable/workflows/CI/badge.svg)][actions] +[![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls] +[![Documentation Coverage Status](https://inch-ci.org/github/sporkmonger/addressable.svg?branch=master)][inch] + +[gem]: https://rubygems.org/gems/addressable +[actions]: https://github.com/sporkmonger/addressable/actions +[coveralls]: https://coveralls.io/r/sporkmonger/addressable +[inch]: https://inch-ci.org/github/sporkmonger/addressable + +## Description + +Addressable is an alternative implementation to the URI implementation +that is part of Ruby's standard library. It is flexible, offers heuristic +parsing, and additionally provides extensive support for IRIs and URI templates. + +Addressable closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4). + +## Reference + +- {Addressable::URI} +- {Addressable::Template} + +## Example usage + +```ruby +require "addressable/uri" + +uri = Addressable::URI.parse("http://example.com/path/to/resource/") +uri.scheme +#=> "http" +uri.host +#=> "example.com" +uri.path +#=> "/path/to/resource/" + +uri = Addressable::URI.parse("http://www.詹姆斯.com/") +uri.normalize +#=> # +``` + + +## URI Templates + +For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt). + + +```ruby + +require "addressable/template" + +template = Addressable::Template.new("http://example.com/{?query*}") +template.expand({ + "query" => { + 'foo' => 'bar', + 'color' => 'red' + } +}) +#=> # + +template = Addressable::Template.new("http://example.com/{?one,two,three}") +template.partial_expand({"one" => "1", "three" => 3}).pattern +#=> "http://example.com/?one=1{&two}&three=3" + +template = Addressable::Template.new( + "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" +) +uri = Addressable::URI.parse( + "http://example.com/a/b/c/?one=1&two=2#foo" +) +template.extract(uri) +#=> +# { +# "host" => "example.com", +# "segments" => ["a", "b", "c"], +# "one" => "1", +# "two" => "2", +# "fragment" => "foo" +# } +``` + +## Install + +```console +$ gem install addressable +``` + +You may optionally turn on native IDN support by installing libidn and the +idn gem: + +```console +$ sudo apt-get install libidn11-dev # Debian/Ubuntu +$ brew install libidn # OS X +$ gem install idn-ruby +``` + +## Semantic Versioning + +This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your +dependency using a pessimistic version constraint covering the major and minor +values: + +```ruby +spec.add_dependency 'addressable', '~> 2.7' +``` + +If you need a specific bug fix, you can also specify minimum tiny versions +without preventing updates to the latest minor release: + +```ruby +spec.add_dependency 'addressable', '~> 2.3', '>= 2.3.7' +``` diff --git a/bin/gems/addressable-2.9.0/lib/addressable.rb b/bin/gems/addressable-2.9.0/lib/addressable.rb new file mode 100644 index 00000000..b4e98b69 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require 'addressable/uri' +require 'addressable/template' diff --git a/bin/gems/addressable-2.9.0/lib/addressable/idna.rb b/bin/gems/addressable-2.9.0/lib/addressable/idna.rb new file mode 100644 index 00000000..2dbd3934 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/idna.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +begin + require "addressable/idna/native" +rescue LoadError + # libidn or the idn gem was not available, fall back on a pure-Ruby + # implementation... + require "addressable/idna/pure" +end diff --git a/bin/gems/addressable-2.9.0/lib/addressable/idna/native.rb b/bin/gems/addressable-2.9.0/lib/addressable/idna/native.rb new file mode 100644 index 00000000..a718364f --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/idna/native.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "idn" + +module Addressable + module IDNA + def self.punycode_encode(value) + IDN::Punycode.encode(value.to_s) + end + + def self.punycode_decode(value) + IDN::Punycode.decode(value.to_s) + end + + class << self + # @deprecated Use {String#unicode_normalize(:nfkc)} instead + def unicode_normalize_kc(value) + value.to_s.unicode_normalize(:nfkc) + end + + extend Gem::Deprecate + deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 + end + + def self.to_ascii(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + + def self.to_unicode(value) + value.to_s.split('.', -1).map do |segment| + if segment.size > 0 && segment.size < 64 + IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED) + elsif segment.size >= 64 + segment + else + '' + end + end.join('.') + end + end +end diff --git a/bin/gems/addressable-2.9.0/lib/addressable/idna/pure.rb b/bin/gems/addressable-2.9.0/lib/addressable/idna/pure.rb new file mode 100644 index 00000000..6572e641 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/idna/pure.rb @@ -0,0 +1,4710 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +module Addressable + module IDNA + # This module is loosely based on idn_actionmailer by Mick Staugaard, + # the unicode library by Yoshida Masato, and the punycode implementation + # by Kazuhiro Nishiyama. Most of the code was copied verbatim, but + # some reformatting was done, and some translation from C was done. + # + # Without their code to work from as a base, we'd all still be relying + # on the presence of libidn. Which nobody ever seems to have installed. + # + # Original sources: + # http://github.com/staugaard/idn_actionmailer + # http://www.yoshidam.net/Ruby.html#unicode + # http://rubyforge.org/frs/?group_id=2550 + + ACE_PREFIX = "xn--" + + UTF8_REGEX = /\A(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*\z/mnx + + UTF8_REGEX_MULTIBYTE = /(?: + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )/mnx + + # :startdoc: + + # Converts from a Unicode internationalized domain name to an ASCII + # domain name as described in RFC 3490. + def self.to_ascii(input) + input = input.to_s unless input.is_a?(String) + input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc) + if input.respond_to?(:force_encoding) + input.force_encoding(Encoding::ASCII_8BIT) + end + if input =~ UTF8_REGEX && input =~ UTF8_REGEX_MULTIBYTE + parts = unicode_downcase(input).split('.') + parts.map! do |part| + if part.respond_to?(:force_encoding) + part.force_encoding(Encoding::ASCII_8BIT) + end + if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE + ACE_PREFIX + punycode_encode(part) + else + part + end + end + parts.join('.') + else + input + end + end + + # Converts from an ASCII domain name to a Unicode internationalized + # domain name as described in RFC 3490. + def self.to_unicode(input) + input = input.to_s unless input.is_a?(String) + parts = input.split('.') + parts.map! do |part| + if part =~ /^#{ACE_PREFIX}(.+)/ + begin + punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1]) + rescue Addressable::IDNA::PunycodeBadInput + # toUnicode is explicitly defined as never-fails by the spec + part + end + else + part + end + end + output = parts.join('.') + if output.respond_to?(:force_encoding) + output.force_encoding(Encoding::UTF_8) + end + output + end + + class << self + # @deprecated Use {String#unicode_normalize(:nfkc)} instead + def unicode_normalize_kc(value) + value.to_s.unicode_normalize(:nfkc) + end + + extend Gem::Deprecate + deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 + end + + ## + # Unicode aware downcase method. + # + # @api private + # @param [String] input + # The input string. + # @return [String] The downcased result. + def self.unicode_downcase(input) + input = input.to_s unless input.is_a?(String) + unpacked = input.unpack("U*") + unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) } + return unpacked.pack("U*") + end + private_class_method :unicode_downcase + + def self.lookup_unicode_lowercase(codepoint) + codepoint_data = UNICODE_DATA[codepoint] + (codepoint_data ? + (codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) : + codepoint) + end + private_class_method :lookup_unicode_lowercase + + UNICODE_DATA_COMBINING_CLASS = 0 + UNICODE_DATA_EXCLUSION = 1 + UNICODE_DATA_CANONICAL = 2 + UNICODE_DATA_COMPATIBILITY = 3 + UNICODE_DATA_UPPERCASE = 4 + UNICODE_DATA_LOWERCASE = 5 + UNICODE_DATA_TITLECASE = 6 + + UNICODE_DATA = { + 65 => [0, 0, nil, nil, nil, 97, nil], + 66 => [0, 0, nil, nil, nil, 98, nil], + 67 => [0, 0, nil, nil, nil, 99, nil], + 68 => [0, 0, nil, nil, nil, 100, nil], + 69 => [0, 0, nil, nil, nil, 101, nil], + 70 => [0, 0, nil, nil, nil, 102, nil], + 71 => [0, 0, nil, nil, nil, 103, nil], + 72 => [0, 0, nil, nil, nil, 104, nil], + 73 => [0, 0, nil, nil, nil, 105, nil], + 74 => [0, 0, nil, nil, nil, 106, nil], + 75 => [0, 0, nil, nil, nil, 107, nil], + 76 => [0, 0, nil, nil, nil, 108, nil], + 77 => [0, 0, nil, nil, nil, 109, nil], + 78 => [0, 0, nil, nil, nil, 110, nil], + 79 => [0, 0, nil, nil, nil, 111, nil], + 80 => [0, 0, nil, nil, nil, 112, nil], + 81 => [0, 0, nil, nil, nil, 113, nil], + 82 => [0, 0, nil, nil, nil, 114, nil], + 83 => [0, 0, nil, nil, nil, 115, nil], + 84 => [0, 0, nil, nil, nil, 116, nil], + 85 => [0, 0, nil, nil, nil, 117, nil], + 86 => [0, 0, nil, nil, nil, 118, nil], + 87 => [0, 0, nil, nil, nil, 119, nil], + 88 => [0, 0, nil, nil, nil, 120, nil], + 89 => [0, 0, nil, nil, nil, 121, nil], + 90 => [0, 0, nil, nil, nil, 122, nil], + 97 => [0, 0, nil, nil, 65, nil, 65], + 98 => [0, 0, nil, nil, 66, nil, 66], + 99 => [0, 0, nil, nil, 67, nil, 67], + 100 => [0, 0, nil, nil, 68, nil, 68], + 101 => [0, 0, nil, nil, 69, nil, 69], + 102 => [0, 0, nil, nil, 70, nil, 70], + 103 => [0, 0, nil, nil, 71, nil, 71], + 104 => [0, 0, nil, nil, 72, nil, 72], + 105 => [0, 0, nil, nil, 73, nil, 73], + 106 => [0, 0, nil, nil, 74, nil, 74], + 107 => [0, 0, nil, nil, 75, nil, 75], + 108 => [0, 0, nil, nil, 76, nil, 76], + 109 => [0, 0, nil, nil, 77, nil, 77], + 110 => [0, 0, nil, nil, 78, nil, 78], + 111 => [0, 0, nil, nil, 79, nil, 79], + 112 => [0, 0, nil, nil, 80, nil, 80], + 113 => [0, 0, nil, nil, 81, nil, 81], + 114 => [0, 0, nil, nil, 82, nil, 82], + 115 => [0, 0, nil, nil, 83, nil, 83], + 116 => [0, 0, nil, nil, 84, nil, 84], + 117 => [0, 0, nil, nil, 85, nil, 85], + 118 => [0, 0, nil, nil, 86, nil, 86], + 119 => [0, 0, nil, nil, 87, nil, 87], + 120 => [0, 0, nil, nil, 88, nil, 88], + 121 => [0, 0, nil, nil, 89, nil, 89], + 122 => [0, 0, nil, nil, 90, nil, 90], + 160 => [0, 0, nil, " ", nil, nil, nil], + 168 => [0, 0, nil, " ̈", nil, nil, nil], + 170 => [0, 0, nil, "a", nil, nil, nil], + 175 => [0, 0, nil, " ̄", nil, nil, nil], + 178 => [0, 0, nil, "2", nil, nil, nil], + 179 => [0, 0, nil, "3", nil, nil, nil], + 180 => [0, 0, nil, " ́", nil, nil, nil], + 181 => [0, 0, nil, "μ", 924, nil, 924], + 184 => [0, 0, nil, " ̧", nil, nil, nil], + 185 => [0, 0, nil, "1", nil, nil, nil], + 186 => [0, 0, nil, "o", nil, nil, nil], + 188 => [0, 0, nil, "1⁄4", nil, nil, nil], + 189 => [0, 0, nil, "1⁄2", nil, nil, nil], + 190 => [0, 0, nil, "3⁄4", nil, nil, nil], + 192 => [0, 0, "À", "À", nil, 224, nil], + 193 => [0, 0, "Á", "Á", nil, 225, nil], + 194 => [0, 0, "Â", "Â", nil, 226, nil], + 195 => [0, 0, "Ã", "Ã", nil, 227, nil], + 196 => [0, 0, "Ä", "Ä", nil, 228, nil], + 197 => [0, 0, "Å", "Å", nil, 229, nil], + 198 => [0, 0, nil, nil, nil, 230, nil], + 199 => [0, 0, "Ç", "Ç", nil, 231, nil], + 200 => [0, 0, "È", "È", nil, 232, nil], + 201 => [0, 0, "É", "É", nil, 233, nil], + 202 => [0, 0, "Ê", "Ê", nil, 234, nil], + 203 => [0, 0, "Ë", "Ë", nil, 235, nil], + 204 => [0, 0, "Ì", "Ì", nil, 236, nil], + 205 => [0, 0, "Í", "Í", nil, 237, nil], + 206 => [0, 0, "Î", "Î", nil, 238, nil], + 207 => [0, 0, "Ï", "Ï", nil, 239, nil], + 208 => [0, 0, nil, nil, nil, 240, nil], + 209 => [0, 0, "Ñ", "Ñ", nil, 241, nil], + 210 => [0, 0, "Ò", "Ò", nil, 242, nil], + 211 => [0, 0, "Ó", "Ó", nil, 243, nil], + 212 => [0, 0, "Ô", "Ô", nil, 244, nil], + 213 => [0, 0, "Õ", "Õ", nil, 245, nil], + 214 => [0, 0, "Ö", "Ö", nil, 246, nil], + 216 => [0, 0, nil, nil, nil, 248, nil], + 217 => [0, 0, "Ù", "Ù", nil, 249, nil], + 218 => [0, 0, "Ú", "Ú", nil, 250, nil], + 219 => [0, 0, "Û", "Û", nil, 251, nil], + 220 => [0, 0, "Ü", "Ü", nil, 252, nil], + 221 => [0, 0, "Ý", "Ý", nil, 253, nil], + 222 => [0, 0, nil, nil, nil, 254, nil], + 224 => [0, 0, "à", "à", 192, nil, 192], + 225 => [0, 0, "á", "á", 193, nil, 193], + 226 => [0, 0, "â", "â", 194, nil, 194], + 227 => [0, 0, "ã", "ã", 195, nil, 195], + 228 => [0, 0, "ä", "ä", 196, nil, 196], + 229 => [0, 0, "å", "å", 197, nil, 197], + 230 => [0, 0, nil, nil, 198, nil, 198], + 231 => [0, 0, "ç", "ç", 199, nil, 199], + 232 => [0, 0, "è", "è", 200, nil, 200], + 233 => [0, 0, "é", "é", 201, nil, 201], + 234 => [0, 0, "ê", "ê", 202, nil, 202], + 235 => [0, 0, "ë", "ë", 203, nil, 203], + 236 => [0, 0, "ì", "ì", 204, nil, 204], + 237 => [0, 0, "í", "í", 205, nil, 205], + 238 => [0, 0, "î", "î", 206, nil, 206], + 239 => [0, 0, "ï", "ï", 207, nil, 207], + 240 => [0, 0, nil, nil, 208, nil, 208], + 241 => [0, 0, "ñ", "ñ", 209, nil, 209], + 242 => [0, 0, "ò", "ò", 210, nil, 210], + 243 => [0, 0, "ó", "ó", 211, nil, 211], + 244 => [0, 0, "ô", "ô", 212, nil, 212], + 245 => [0, 0, "õ", "õ", 213, nil, 213], + 246 => [0, 0, "ö", "ö", 214, nil, 214], + 248 => [0, 0, nil, nil, 216, nil, 216], + 249 => [0, 0, "ù", "ù", 217, nil, 217], + 250 => [0, 0, "ú", "ú", 218, nil, 218], + 251 => [0, 0, "û", "û", 219, nil, 219], + 252 => [0, 0, "ü", "ü", 220, nil, 220], + 253 => [0, 0, "ý", "ý", 221, nil, 221], + 254 => [0, 0, nil, nil, 222, nil, 222], + 255 => [0, 0, "ÿ", "ÿ", 376, nil, 376], + 256 => [0, 0, "Ā", "Ā", nil, 257, nil], + 257 => [0, 0, "ā", "ā", 256, nil, 256], + 258 => [0, 0, "Ă", "Ă", nil, 259, nil], + 259 => [0, 0, "ă", "ă", 258, nil, 258], + 260 => [0, 0, "Ą", "Ą", nil, 261, nil], + 261 => [0, 0, "ą", "ą", 260, nil, 260], + 262 => [0, 0, "Ć", "Ć", nil, 263, nil], + 263 => [0, 0, "ć", "ć", 262, nil, 262], + 264 => [0, 0, "Ĉ", "Ĉ", nil, 265, nil], + 265 => [0, 0, "ĉ", "ĉ", 264, nil, 264], + 266 => [0, 0, "Ċ", "Ċ", nil, 267, nil], + 267 => [0, 0, "ċ", "ċ", 266, nil, 266], + 268 => [0, 0, "Č", "Č", nil, 269, nil], + 269 => [0, 0, "č", "č", 268, nil, 268], + 270 => [0, 0, "Ď", "Ď", nil, 271, nil], + 271 => [0, 0, "ď", "ď", 270, nil, 270], + 272 => [0, 0, nil, nil, nil, 273, nil], + 273 => [0, 0, nil, nil, 272, nil, 272], + 274 => [0, 0, "Ē", "Ē", nil, 275, nil], + 275 => [0, 0, "ē", "ē", 274, nil, 274], + 276 => [0, 0, "Ĕ", "Ĕ", nil, 277, nil], + 277 => [0, 0, "ĕ", "ĕ", 276, nil, 276], + 278 => [0, 0, "Ė", "Ė", nil, 279, nil], + 279 => [0, 0, "ė", "ė", 278, nil, 278], + 280 => [0, 0, "Ę", "Ę", nil, 281, nil], + 281 => [0, 0, "ę", "ę", 280, nil, 280], + 282 => [0, 0, "Ě", "Ě", nil, 283, nil], + 283 => [0, 0, "ě", "ě", 282, nil, 282], + 284 => [0, 0, "Ĝ", "Ĝ", nil, 285, nil], + 285 => [0, 0, "ĝ", "ĝ", 284, nil, 284], + 286 => [0, 0, "Ğ", "Ğ", nil, 287, nil], + 287 => [0, 0, "ğ", "ğ", 286, nil, 286], + 288 => [0, 0, "Ġ", "Ġ", nil, 289, nil], + 289 => [0, 0, "ġ", "ġ", 288, nil, 288], + 290 => [0, 0, "Ģ", "Ģ", nil, 291, nil], + 291 => [0, 0, "ģ", "ģ", 290, nil, 290], + 292 => [0, 0, "Ĥ", "Ĥ", nil, 293, nil], + 293 => [0, 0, "ĥ", "ĥ", 292, nil, 292], + 294 => [0, 0, nil, nil, nil, 295, nil], + 295 => [0, 0, nil, nil, 294, nil, 294], + 296 => [0, 0, "Ĩ", "Ĩ", nil, 297, nil], + 297 => [0, 0, "ĩ", "ĩ", 296, nil, 296], + 298 => [0, 0, "Ī", "Ī", nil, 299, nil], + 299 => [0, 0, "ī", "ī", 298, nil, 298], + 300 => [0, 0, "Ĭ", "Ĭ", nil, 301, nil], + 301 => [0, 0, "ĭ", "ĭ", 300, nil, 300], + 302 => [0, 0, "Į", "Į", nil, 303, nil], + 303 => [0, 0, "į", "į", 302, nil, 302], + 304 => [0, 0, "İ", "İ", nil, 105, nil], + 305 => [0, 0, nil, nil, 73, nil, 73], + 306 => [0, 0, nil, "IJ", nil, 307, nil], + 307 => [0, 0, nil, "ij", 306, nil, 306], + 308 => [0, 0, "Ĵ", "Ĵ", nil, 309, nil], + 309 => [0, 0, "ĵ", "ĵ", 308, nil, 308], + 310 => [0, 0, "Ķ", "Ķ", nil, 311, nil], + 311 => [0, 0, "ķ", "ķ", 310, nil, 310], + 313 => [0, 0, "Ĺ", "Ĺ", nil, 314, nil], + 314 => [0, 0, "ĺ", "ĺ", 313, nil, 313], + 315 => [0, 0, "Ļ", "Ļ", nil, 316, nil], + 316 => [0, 0, "ļ", "ļ", 315, nil, 315], + 317 => [0, 0, "Ľ", "Ľ", nil, 318, nil], + 318 => [0, 0, "ľ", "ľ", 317, nil, 317], + 319 => [0, 0, nil, "L·", nil, 320, nil], + 320 => [0, 0, nil, "l·", 319, nil, 319], + 321 => [0, 0, nil, nil, nil, 322, nil], + 322 => [0, 0, nil, nil, 321, nil, 321], + 323 => [0, 0, "Ń", "Ń", nil, 324, nil], + 324 => [0, 0, "ń", "ń", 323, nil, 323], + 325 => [0, 0, "Ņ", "Ņ", nil, 326, nil], + 326 => [0, 0, "ņ", "ņ", 325, nil, 325], + 327 => [0, 0, "Ň", "Ň", nil, 328, nil], + 328 => [0, 0, "ň", "ň", 327, nil, 327], + 329 => [0, 0, nil, "ʼn", nil, nil, nil], + 330 => [0, 0, nil, nil, nil, 331, nil], + 331 => [0, 0, nil, nil, 330, nil, 330], + 332 => [0, 0, "Ō", "Ō", nil, 333, nil], + 333 => [0, 0, "ō", "ō", 332, nil, 332], + 334 => [0, 0, "Ŏ", "Ŏ", nil, 335, nil], + 335 => [0, 0, "ŏ", "ŏ", 334, nil, 334], + 336 => [0, 0, "Ő", "Ő", nil, 337, nil], + 337 => [0, 0, "ő", "ő", 336, nil, 336], + 338 => [0, 0, nil, nil, nil, 339, nil], + 339 => [0, 0, nil, nil, 338, nil, 338], + 340 => [0, 0, "Ŕ", "Ŕ", nil, 341, nil], + 341 => [0, 0, "ŕ", "ŕ", 340, nil, 340], + 342 => [0, 0, "Ŗ", "Ŗ", nil, 343, nil], + 343 => [0, 0, "ŗ", "ŗ", 342, nil, 342], + 344 => [0, 0, "Ř", "Ř", nil, 345, nil], + 345 => [0, 0, "ř", "ř", 344, nil, 344], + 346 => [0, 0, "Ś", "Ś", nil, 347, nil], + 347 => [0, 0, "ś", "ś", 346, nil, 346], + 348 => [0, 0, "Ŝ", "Ŝ", nil, 349, nil], + 349 => [0, 0, "ŝ", "ŝ", 348, nil, 348], + 350 => [0, 0, "Ş", "Ş", nil, 351, nil], + 351 => [0, 0, "ş", "ş", 350, nil, 350], + 352 => [0, 0, "Š", "Š", nil, 353, nil], + 353 => [0, 0, "š", "š", 352, nil, 352], + 354 => [0, 0, "Ţ", "Ţ", nil, 355, nil], + 355 => [0, 0, "ţ", "ţ", 354, nil, 354], + 356 => [0, 0, "Ť", "Ť", nil, 357, nil], + 357 => [0, 0, "ť", "ť", 356, nil, 356], + 358 => [0, 0, nil, nil, nil, 359, nil], + 359 => [0, 0, nil, nil, 358, nil, 358], + 360 => [0, 0, "Ũ", "Ũ", nil, 361, nil], + 361 => [0, 0, "ũ", "ũ", 360, nil, 360], + 362 => [0, 0, "Ū", "Ū", nil, 363, nil], + 363 => [0, 0, "ū", "ū", 362, nil, 362], + 364 => [0, 0, "Ŭ", "Ŭ", nil, 365, nil], + 365 => [0, 0, "ŭ", "ŭ", 364, nil, 364], + 366 => [0, 0, "Ů", "Ů", nil, 367, nil], + 367 => [0, 0, "ů", "ů", 366, nil, 366], + 368 => [0, 0, "Ű", "Ű", nil, 369, nil], + 369 => [0, 0, "ű", "ű", 368, nil, 368], + 370 => [0, 0, "Ų", "Ų", nil, 371, nil], + 371 => [0, 0, "ų", "ų", 370, nil, 370], + 372 => [0, 0, "Ŵ", "Ŵ", nil, 373, nil], + 373 => [0, 0, "ŵ", "ŵ", 372, nil, 372], + 374 => [0, 0, "Ŷ", "Ŷ", nil, 375, nil], + 375 => [0, 0, "ŷ", "ŷ", 374, nil, 374], + 376 => [0, 0, "Ÿ", "Ÿ", nil, 255, nil], + 377 => [0, 0, "Ź", "Ź", nil, 378, nil], + 378 => [0, 0, "ź", "ź", 377, nil, 377], + 379 => [0, 0, "Ż", "Ż", nil, 380, nil], + 380 => [0, 0, "ż", "ż", 379, nil, 379], + 381 => [0, 0, "Ž", "Ž", nil, 382, nil], + 382 => [0, 0, "ž", "ž", 381, nil, 381], + 383 => [0, 0, nil, "s", 83, nil, 83], + 385 => [0, 0, nil, nil, nil, 595, nil], + 386 => [0, 0, nil, nil, nil, 387, nil], + 387 => [0, 0, nil, nil, 386, nil, 386], + 388 => [0, 0, nil, nil, nil, 389, nil], + 389 => [0, 0, nil, nil, 388, nil, 388], + 390 => [0, 0, nil, nil, nil, 596, nil], + 391 => [0, 0, nil, nil, nil, 392, nil], + 392 => [0, 0, nil, nil, 391, nil, 391], + 393 => [0, 0, nil, nil, nil, 598, nil], + 394 => [0, 0, nil, nil, nil, 599, nil], + 395 => [0, 0, nil, nil, nil, 396, nil], + 396 => [0, 0, nil, nil, 395, nil, 395], + 398 => [0, 0, nil, nil, nil, 477, nil], + 399 => [0, 0, nil, nil, nil, 601, nil], + 400 => [0, 0, nil, nil, nil, 603, nil], + 401 => [0, 0, nil, nil, nil, 402, nil], + 402 => [0, 0, nil, nil, 401, nil, 401], + 403 => [0, 0, nil, nil, nil, 608, nil], + 404 => [0, 0, nil, nil, nil, 611, nil], + 405 => [0, 0, nil, nil, 502, nil, 502], + 406 => [0, 0, nil, nil, nil, 617, nil], + 407 => [0, 0, nil, nil, nil, 616, nil], + 408 => [0, 0, nil, nil, nil, 409, nil], + 409 => [0, 0, nil, nil, 408, nil, 408], + 412 => [0, 0, nil, nil, nil, 623, nil], + 413 => [0, 0, nil, nil, nil, 626, nil], + 415 => [0, 0, nil, nil, nil, 629, nil], + 416 => [0, 0, "Ơ", "Ơ", nil, 417, nil], + 417 => [0, 0, "ơ", "ơ", 416, nil, 416], + 418 => [0, 0, nil, nil, nil, 419, nil], + 419 => [0, 0, nil, nil, 418, nil, 418], + 420 => [0, 0, nil, nil, nil, 421, nil], + 421 => [0, 0, nil, nil, 420, nil, 420], + 422 => [0, 0, nil, nil, nil, 640, nil], + 423 => [0, 0, nil, nil, nil, 424, nil], + 424 => [0, 0, nil, nil, 423, nil, 423], + 425 => [0, 0, nil, nil, nil, 643, nil], + 428 => [0, 0, nil, nil, nil, 429, nil], + 429 => [0, 0, nil, nil, 428, nil, 428], + 430 => [0, 0, nil, nil, nil, 648, nil], + 431 => [0, 0, "Ư", "Ư", nil, 432, nil], + 432 => [0, 0, "ư", "ư", 431, nil, 431], + 433 => [0, 0, nil, nil, nil, 650, nil], + 434 => [0, 0, nil, nil, nil, 651, nil], + 435 => [0, 0, nil, nil, nil, 436, nil], + 436 => [0, 0, nil, nil, 435, nil, 435], + 437 => [0, 0, nil, nil, nil, 438, nil], + 438 => [0, 0, nil, nil, 437, nil, 437], + 439 => [0, 0, nil, nil, nil, 658, nil], + 440 => [0, 0, nil, nil, nil, 441, nil], + 441 => [0, 0, nil, nil, 440, nil, 440], + 444 => [0, 0, nil, nil, nil, 445, nil], + 445 => [0, 0, nil, nil, 444, nil, 444], + 447 => [0, 0, nil, nil, 503, nil, 503], + 452 => [0, 0, nil, "DŽ", nil, 454, 453], + 453 => [0, 0, nil, "Dž", 452, 454, nil], + 454 => [0, 0, nil, "dž", 452, nil, 453], + 455 => [0, 0, nil, "LJ", nil, 457, 456], + 456 => [0, 0, nil, "Lj", 455, 457, nil], + 457 => [0, 0, nil, "lj", 455, nil, 456], + 458 => [0, 0, nil, "NJ", nil, 460, 459], + 459 => [0, 0, nil, "Nj", 458, 460, nil], + 460 => [0, 0, nil, "nj", 458, nil, 459], + 461 => [0, 0, "Ǎ", "Ǎ", nil, 462, nil], + 462 => [0, 0, "ǎ", "ǎ", 461, nil, 461], + 463 => [0, 0, "Ǐ", "Ǐ", nil, 464, nil], + 464 => [0, 0, "ǐ", "ǐ", 463, nil, 463], + 465 => [0, 0, "Ǒ", "Ǒ", nil, 466, nil], + 466 => [0, 0, "ǒ", "ǒ", 465, nil, 465], + 467 => [0, 0, "Ǔ", "Ǔ", nil, 468, nil], + 468 => [0, 0, "ǔ", "ǔ", 467, nil, 467], + 469 => [0, 0, "Ǖ", "Ǖ", nil, 470, nil], + 470 => [0, 0, "ǖ", "ǖ", 469, nil, 469], + 471 => [0, 0, "Ǘ", "Ǘ", nil, 472, nil], + 472 => [0, 0, "ǘ", "ǘ", 471, nil, 471], + 473 => [0, 0, "Ǚ", "Ǚ", nil, 474, nil], + 474 => [0, 0, "ǚ", "ǚ", 473, nil, 473], + 475 => [0, 0, "Ǜ", "Ǜ", nil, 476, nil], + 476 => [0, 0, "ǜ", "ǜ", 475, nil, 475], + 477 => [0, 0, nil, nil, 398, nil, 398], + 478 => [0, 0, "Ǟ", "Ǟ", nil, 479, nil], + 479 => [0, 0, "ǟ", "ǟ", 478, nil, 478], + 480 => [0, 0, "Ǡ", "Ǡ", nil, 481, nil], + 481 => [0, 0, "ǡ", "ǡ", 480, nil, 480], + 482 => [0, 0, "Ǣ", "Ǣ", nil, 483, nil], + 483 => [0, 0, "ǣ", "ǣ", 482, nil, 482], + 484 => [0, 0, nil, nil, nil, 485, nil], + 485 => [0, 0, nil, nil, 484, nil, 484], + 486 => [0, 0, "Ǧ", "Ǧ", nil, 487, nil], + 487 => [0, 0, "ǧ", "ǧ", 486, nil, 486], + 488 => [0, 0, "Ǩ", "Ǩ", nil, 489, nil], + 489 => [0, 0, "ǩ", "ǩ", 488, nil, 488], + 490 => [0, 0, "Ǫ", "Ǫ", nil, 491, nil], + 491 => [0, 0, "ǫ", "ǫ", 490, nil, 490], + 492 => [0, 0, "Ǭ", "Ǭ", nil, 493, nil], + 493 => [0, 0, "ǭ", "ǭ", 492, nil, 492], + 494 => [0, 0, "Ǯ", "Ǯ", nil, 495, nil], + 495 => [0, 0, "ǯ", "ǯ", 494, nil, 494], + 496 => [0, 0, "ǰ", "ǰ", nil, nil, nil], + 497 => [0, 0, nil, "DZ", nil, 499, 498], + 498 => [0, 0, nil, "Dz", 497, 499, nil], + 499 => [0, 0, nil, "dz", 497, nil, 498], + 500 => [0, 0, "Ǵ", "Ǵ", nil, 501, nil], + 501 => [0, 0, "ǵ", "ǵ", 500, nil, 500], + 502 => [0, 0, nil, nil, nil, 405, nil], + 503 => [0, 0, nil, nil, nil, 447, nil], + 504 => [0, 0, "Ǹ", "Ǹ", nil, 505, nil], + 505 => [0, 0, "ǹ", "ǹ", 504, nil, 504], + 506 => [0, 0, "Ǻ", "Ǻ", nil, 507, nil], + 507 => [0, 0, "ǻ", "ǻ", 506, nil, 506], + 508 => [0, 0, "Ǽ", "Ǽ", nil, 509, nil], + 509 => [0, 0, "ǽ", "ǽ", 508, nil, 508], + 510 => [0, 0, "Ǿ", "Ǿ", nil, 511, nil], + 511 => [0, 0, "ǿ", "ǿ", 510, nil, 510], + 512 => [0, 0, "Ȁ", "Ȁ", nil, 513, nil], + 513 => [0, 0, "ȁ", "ȁ", 512, nil, 512], + 514 => [0, 0, "Ȃ", "Ȃ", nil, 515, nil], + 515 => [0, 0, "ȃ", "ȃ", 514, nil, 514], + 516 => [0, 0, "Ȅ", "Ȅ", nil, 517, nil], + 517 => [0, 0, "ȅ", "ȅ", 516, nil, 516], + 518 => [0, 0, "Ȇ", "Ȇ", nil, 519, nil], + 519 => [0, 0, "ȇ", "ȇ", 518, nil, 518], + 520 => [0, 0, "Ȉ", "Ȉ", nil, 521, nil], + 521 => [0, 0, "ȉ", "ȉ", 520, nil, 520], + 522 => [0, 0, "Ȋ", "Ȋ", nil, 523, nil], + 523 => [0, 0, "ȋ", "ȋ", 522, nil, 522], + 524 => [0, 0, "Ȍ", "Ȍ", nil, 525, nil], + 525 => [0, 0, "ȍ", "ȍ", 524, nil, 524], + 526 => [0, 0, "Ȏ", "Ȏ", nil, 527, nil], + 527 => [0, 0, "ȏ", "ȏ", 526, nil, 526], + 528 => [0, 0, "Ȑ", "Ȑ", nil, 529, nil], + 529 => [0, 0, "ȑ", "ȑ", 528, nil, 528], + 530 => [0, 0, "Ȓ", "Ȓ", nil, 531, nil], + 531 => [0, 0, "ȓ", "ȓ", 530, nil, 530], + 532 => [0, 0, "Ȕ", "Ȕ", nil, 533, nil], + 533 => [0, 0, "ȕ", "ȕ", 532, nil, 532], + 534 => [0, 0, "Ȗ", "Ȗ", nil, 535, nil], + 535 => [0, 0, "ȗ", "ȗ", 534, nil, 534], + 536 => [0, 0, "Ș", "Ș", nil, 537, nil], + 537 => [0, 0, "ș", "ș", 536, nil, 536], + 538 => [0, 0, "Ț", "Ț", nil, 539, nil], + 539 => [0, 0, "ț", "ț", 538, nil, 538], + 540 => [0, 0, nil, nil, nil, 541, nil], + 541 => [0, 0, nil, nil, 540, nil, 540], + 542 => [0, 0, "Ȟ", "Ȟ", nil, 543, nil], + 543 => [0, 0, "ȟ", "ȟ", 542, nil, 542], + 546 => [0, 0, nil, nil, nil, 547, nil], + 547 => [0, 0, nil, nil, 546, nil, 546], + 548 => [0, 0, nil, nil, nil, 549, nil], + 549 => [0, 0, nil, nil, 548, nil, 548], + 550 => [0, 0, "Ȧ", "Ȧ", nil, 551, nil], + 551 => [0, 0, "ȧ", "ȧ", 550, nil, 550], + 552 => [0, 0, "Ȩ", "Ȩ", nil, 553, nil], + 553 => [0, 0, "ȩ", "ȩ", 552, nil, 552], + 554 => [0, 0, "Ȫ", "Ȫ", nil, 555, nil], + 555 => [0, 0, "ȫ", "ȫ", 554, nil, 554], + 556 => [0, 0, "Ȭ", "Ȭ", nil, 557, nil], + 557 => [0, 0, "ȭ", "ȭ", 556, nil, 556], + 558 => [0, 0, "Ȯ", "Ȯ", nil, 559, nil], + 559 => [0, 0, "ȯ", "ȯ", 558, nil, 558], + 560 => [0, 0, "Ȱ", "Ȱ", nil, 561, nil], + 561 => [0, 0, "ȱ", "ȱ", 560, nil, 560], + 562 => [0, 0, "Ȳ", "Ȳ", nil, 563, nil], + 563 => [0, 0, "ȳ", "ȳ", 562, nil, 562], + 595 => [0, 0, nil, nil, 385, nil, 385], + 596 => [0, 0, nil, nil, 390, nil, 390], + 598 => [0, 0, nil, nil, 393, nil, 393], + 599 => [0, 0, nil, nil, 394, nil, 394], + 601 => [0, 0, nil, nil, 399, nil, 399], + 603 => [0, 0, nil, nil, 400, nil, 400], + 608 => [0, 0, nil, nil, 403, nil, 403], + 611 => [0, 0, nil, nil, 404, nil, 404], + 616 => [0, 0, nil, nil, 407, nil, 407], + 617 => [0, 0, nil, nil, 406, nil, 406], + 623 => [0, 0, nil, nil, 412, nil, 412], + 626 => [0, 0, nil, nil, 413, nil, 413], + 629 => [0, 0, nil, nil, 415, nil, 415], + 640 => [0, 0, nil, nil, 422, nil, 422], + 643 => [0, 0, nil, nil, 425, nil, 425], + 648 => [0, 0, nil, nil, 430, nil, 430], + 650 => [0, 0, nil, nil, 433, nil, 433], + 651 => [0, 0, nil, nil, 434, nil, 434], + 658 => [0, 0, nil, nil, 439, nil, 439], + 688 => [0, 0, nil, "h", nil, nil, nil], + 689 => [0, 0, nil, "ɦ", nil, nil, nil], + 690 => [0, 0, nil, "j", nil, nil, nil], + 691 => [0, 0, nil, "r", nil, nil, nil], + 692 => [0, 0, nil, "ɹ", nil, nil, nil], + 693 => [0, 0, nil, "ɻ", nil, nil, nil], + 694 => [0, 0, nil, "ʁ", nil, nil, nil], + 695 => [0, 0, nil, "w", nil, nil, nil], + 696 => [0, 0, nil, "y", nil, nil, nil], + 728 => [0, 0, nil, " ̆", nil, nil, nil], + 729 => [0, 0, nil, " ̇", nil, nil, nil], + 730 => [0, 0, nil, " ̊", nil, nil, nil], + 731 => [0, 0, nil, " ̨", nil, nil, nil], + 732 => [0, 0, nil, " ̃", nil, nil, nil], + 733 => [0, 0, nil, " ̋", nil, nil, nil], + 736 => [0, 0, nil, "ɣ", nil, nil, nil], + 737 => [0, 0, nil, "l", nil, nil, nil], + 738 => [0, 0, nil, "s", nil, nil, nil], + 739 => [0, 0, nil, "x", nil, nil, nil], + 740 => [0, 0, nil, "ʕ", nil, nil, nil], + 768 => [230, 0, nil, nil, nil, nil, nil], + 769 => [230, 0, nil, nil, nil, nil, nil], + 770 => [230, 0, nil, nil, nil, nil, nil], + 771 => [230, 0, nil, nil, nil, nil, nil], + 772 => [230, 0, nil, nil, nil, nil, nil], + 773 => [230, 0, nil, nil, nil, nil, nil], + 774 => [230, 0, nil, nil, nil, nil, nil], + 775 => [230, 0, nil, nil, nil, nil, nil], + 776 => [230, 0, nil, nil, nil, nil, nil], + 777 => [230, 0, nil, nil, nil, nil, nil], + 778 => [230, 0, nil, nil, nil, nil, nil], + 779 => [230, 0, nil, nil, nil, nil, nil], + 780 => [230, 0, nil, nil, nil, nil, nil], + 781 => [230, 0, nil, nil, nil, nil, nil], + 782 => [230, 0, nil, nil, nil, nil, nil], + 783 => [230, 0, nil, nil, nil, nil, nil], + 784 => [230, 0, nil, nil, nil, nil, nil], + 785 => [230, 0, nil, nil, nil, nil, nil], + 786 => [230, 0, nil, nil, nil, nil, nil], + 787 => [230, 0, nil, nil, nil, nil, nil], + 788 => [230, 0, nil, nil, nil, nil, nil], + 789 => [232, 0, nil, nil, nil, nil, nil], + 790 => [220, 0, nil, nil, nil, nil, nil], + 791 => [220, 0, nil, nil, nil, nil, nil], + 792 => [220, 0, nil, nil, nil, nil, nil], + 793 => [220, 0, nil, nil, nil, nil, nil], + 794 => [232, 0, nil, nil, nil, nil, nil], + 795 => [216, 0, nil, nil, nil, nil, nil], + 796 => [220, 0, nil, nil, nil, nil, nil], + 797 => [220, 0, nil, nil, nil, nil, nil], + 798 => [220, 0, nil, nil, nil, nil, nil], + 799 => [220, 0, nil, nil, nil, nil, nil], + 800 => [220, 0, nil, nil, nil, nil, nil], + 801 => [202, 0, nil, nil, nil, nil, nil], + 802 => [202, 0, nil, nil, nil, nil, nil], + 803 => [220, 0, nil, nil, nil, nil, nil], + 804 => [220, 0, nil, nil, nil, nil, nil], + 805 => [220, 0, nil, nil, nil, nil, nil], + 806 => [220, 0, nil, nil, nil, nil, nil], + 807 => [202, 0, nil, nil, nil, nil, nil], + 808 => [202, 0, nil, nil, nil, nil, nil], + 809 => [220, 0, nil, nil, nil, nil, nil], + 810 => [220, 0, nil, nil, nil, nil, nil], + 811 => [220, 0, nil, nil, nil, nil, nil], + 812 => [220, 0, nil, nil, nil, nil, nil], + 813 => [220, 0, nil, nil, nil, nil, nil], + 814 => [220, 0, nil, nil, nil, nil, nil], + 815 => [220, 0, nil, nil, nil, nil, nil], + 816 => [220, 0, nil, nil, nil, nil, nil], + 817 => [220, 0, nil, nil, nil, nil, nil], + 818 => [220, 0, nil, nil, nil, nil, nil], + 819 => [220, 0, nil, nil, nil, nil, nil], + 820 => [1, 0, nil, nil, nil, nil, nil], + 821 => [1, 0, nil, nil, nil, nil, nil], + 822 => [1, 0, nil, nil, nil, nil, nil], + 823 => [1, 0, nil, nil, nil, nil, nil], + 824 => [1, 0, nil, nil, nil, nil, nil], + 825 => [220, 0, nil, nil, nil, nil, nil], + 826 => [220, 0, nil, nil, nil, nil, nil], + 827 => [220, 0, nil, nil, nil, nil, nil], + 828 => [220, 0, nil, nil, nil, nil, nil], + 829 => [230, 0, nil, nil, nil, nil, nil], + 830 => [230, 0, nil, nil, nil, nil, nil], + 831 => [230, 0, nil, nil, nil, nil, nil], + 832 => [230, 2, "̀", "̀", nil, nil, nil], + 833 => [230, 2, "́", "́", nil, nil, nil], + 834 => [230, 0, nil, nil, nil, nil, nil], + 835 => [230, 2, "̓", "̓", nil, nil, nil], + 836 => [230, 3, "̈́", "̈́", nil, nil, nil], + 837 => [240, 0, nil, nil, 921, nil, 921], + 838 => [230, 0, nil, nil, nil, nil, nil], + 839 => [220, 0, nil, nil, nil, nil, nil], + 840 => [220, 0, nil, nil, nil, nil, nil], + 841 => [220, 0, nil, nil, nil, nil, nil], + 842 => [230, 0, nil, nil, nil, nil, nil], + 843 => [230, 0, nil, nil, nil, nil, nil], + 844 => [230, 0, nil, nil, nil, nil, nil], + 845 => [220, 0, nil, nil, nil, nil, nil], + 846 => [220, 0, nil, nil, nil, nil, nil], + 864 => [234, 0, nil, nil, nil, nil, nil], + 865 => [234, 0, nil, nil, nil, nil, nil], + 866 => [233, 0, nil, nil, nil, nil, nil], + 884 => [0, 2, "ʹ", "ʹ", nil, nil, nil], + 890 => [0, 0, nil, " ͅ", nil, nil, nil], + 894 => [0, 2, ";", ";", nil, nil, nil], + 900 => [0, 0, nil, " ́", nil, nil, nil], + 901 => [0, 0, "΅", "΅", nil, nil, nil], + 902 => [0, 0, "Ά", "Ά", nil, 940, nil], + 903 => [0, 2, "·", "·", nil, nil, nil], + 904 => [0, 0, "Έ", "Έ", nil, 941, nil], + 905 => [0, 0, "Ή", "Ή", nil, 942, nil], + 906 => [0, 0, "Ί", "Ί", nil, 943, nil], + 908 => [0, 0, "Ό", "Ό", nil, 972, nil], + 910 => [0, 0, "Ύ", "Ύ", nil, 973, nil], + 911 => [0, 0, "Ώ", "Ώ", nil, 974, nil], + 912 => [0, 0, "ΐ", "ΐ", nil, nil, nil], + 913 => [0, 0, nil, nil, nil, 945, nil], + 914 => [0, 0, nil, nil, nil, 946, nil], + 915 => [0, 0, nil, nil, nil, 947, nil], + 916 => [0, 0, nil, nil, nil, 948, nil], + 917 => [0, 0, nil, nil, nil, 949, nil], + 918 => [0, 0, nil, nil, nil, 950, nil], + 919 => [0, 0, nil, nil, nil, 951, nil], + 920 => [0, 0, nil, nil, nil, 952, nil], + 921 => [0, 0, nil, nil, nil, 953, nil], + 922 => [0, 0, nil, nil, nil, 954, nil], + 923 => [0, 0, nil, nil, nil, 955, nil], + 924 => [0, 0, nil, nil, nil, 956, nil], + 925 => [0, 0, nil, nil, nil, 957, nil], + 926 => [0, 0, nil, nil, nil, 958, nil], + 927 => [0, 0, nil, nil, nil, 959, nil], + 928 => [0, 0, nil, nil, nil, 960, nil], + 929 => [0, 0, nil, nil, nil, 961, nil], + 931 => [0, 0, nil, nil, nil, 963, nil], + 932 => [0, 0, nil, nil, nil, 964, nil], + 933 => [0, 0, nil, nil, nil, 965, nil], + 934 => [0, 0, nil, nil, nil, 966, nil], + 935 => [0, 0, nil, nil, nil, 967, nil], + 936 => [0, 0, nil, nil, nil, 968, nil], + 937 => [0, 0, nil, nil, nil, 969, nil], + 938 => [0, 0, "Ϊ", "Ϊ", nil, 970, nil], + 939 => [0, 0, "Ϋ", "Ϋ", nil, 971, nil], + 940 => [0, 0, "ά", "ά", 902, nil, 902], + 941 => [0, 0, "έ", "έ", 904, nil, 904], + 942 => [0, 0, "ή", "ή", 905, nil, 905], + 943 => [0, 0, "ί", "ί", 906, nil, 906], + 944 => [0, 0, "ΰ", "ΰ", nil, nil, nil], + 945 => [0, 0, nil, nil, 913, nil, 913], + 946 => [0, 0, nil, nil, 914, nil, 914], + 947 => [0, 0, nil, nil, 915, nil, 915], + 948 => [0, 0, nil, nil, 916, nil, 916], + 949 => [0, 0, nil, nil, 917, nil, 917], + 950 => [0, 0, nil, nil, 918, nil, 918], + 951 => [0, 0, nil, nil, 919, nil, 919], + 952 => [0, 0, nil, nil, 920, nil, 920], + 953 => [0, 0, nil, nil, 921, nil, 921], + 954 => [0, 0, nil, nil, 922, nil, 922], + 955 => [0, 0, nil, nil, 923, nil, 923], + 956 => [0, 0, nil, nil, 924, nil, 924], + 957 => [0, 0, nil, nil, 925, nil, 925], + 958 => [0, 0, nil, nil, 926, nil, 926], + 959 => [0, 0, nil, nil, 927, nil, 927], + 960 => [0, 0, nil, nil, 928, nil, 928], + 961 => [0, 0, nil, nil, 929, nil, 929], + 962 => [0, 0, nil, nil, 931, nil, 931], + 963 => [0, 0, nil, nil, 931, nil, 931], + 964 => [0, 0, nil, nil, 932, nil, 932], + 965 => [0, 0, nil, nil, 933, nil, 933], + 966 => [0, 0, nil, nil, 934, nil, 934], + 967 => [0, 0, nil, nil, 935, nil, 935], + 968 => [0, 0, nil, nil, 936, nil, 936], + 969 => [0, 0, nil, nil, 937, nil, 937], + 970 => [0, 0, "ϊ", "ϊ", 938, nil, 938], + 971 => [0, 0, "ϋ", "ϋ", 939, nil, 939], + 972 => [0, 0, "ό", "ό", 908, nil, 908], + 973 => [0, 0, "ύ", "ύ", 910, nil, 910], + 974 => [0, 0, "ώ", "ώ", 911, nil, 911], + 976 => [0, 0, nil, "β", 914, nil, 914], + 977 => [0, 0, nil, "θ", 920, nil, 920], + 978 => [0, 0, nil, "Υ", nil, nil, nil], + 979 => [0, 0, "ϓ", "ϓ", nil, nil, nil], + 980 => [0, 0, "ϔ", "ϔ", nil, nil, nil], + 981 => [0, 0, nil, "φ", 934, nil, 934], + 982 => [0, 0, nil, "π", 928, nil, 928], + 986 => [0, 0, nil, nil, nil, 987, nil], + 987 => [0, 0, nil, nil, 986, nil, 986], + 988 => [0, 0, nil, nil, nil, 989, nil], + 989 => [0, 0, nil, nil, 988, nil, 988], + 990 => [0, 0, nil, nil, nil, 991, nil], + 991 => [0, 0, nil, nil, 990, nil, 990], + 992 => [0, 0, nil, nil, nil, 993, nil], + 993 => [0, 0, nil, nil, 992, nil, 992], + 994 => [0, 0, nil, nil, nil, 995, nil], + 995 => [0, 0, nil, nil, 994, nil, 994], + 996 => [0, 0, nil, nil, nil, 997, nil], + 997 => [0, 0, nil, nil, 996, nil, 996], + 998 => [0, 0, nil, nil, nil, 999, nil], + 999 => [0, 0, nil, nil, 998, nil, 998], + 1000 => [0, 0, nil, nil, nil, 1001, nil], + 1001 => [0, 0, nil, nil, 1000, nil, 1000], + 1002 => [0, 0, nil, nil, nil, 1003, nil], + 1003 => [0, 0, nil, nil, 1002, nil, 1002], + 1004 => [0, 0, nil, nil, nil, 1005, nil], + 1005 => [0, 0, nil, nil, 1004, nil, 1004], + 1006 => [0, 0, nil, nil, nil, 1007, nil], + 1007 => [0, 0, nil, nil, 1006, nil, 1006], + 1008 => [0, 0, nil, "κ", 922, nil, 922], + 1009 => [0, 0, nil, "ρ", 929, nil, 929], + 1010 => [0, 0, nil, "ς", 931, nil, 931], + 1024 => [0, 0, "Ѐ", "Ѐ", nil, 1104, nil], + 1025 => [0, 0, "Ё", "Ё", nil, 1105, nil], + 1026 => [0, 0, nil, nil, nil, 1106, nil], + 1027 => [0, 0, "Ѓ", "Ѓ", nil, 1107, nil], + 1028 => [0, 0, nil, nil, nil, 1108, nil], + 1029 => [0, 0, nil, nil, nil, 1109, nil], + 1030 => [0, 0, nil, nil, nil, 1110, nil], + 1031 => [0, 0, "Ї", "Ї", nil, 1111, nil], + 1032 => [0, 0, nil, nil, nil, 1112, nil], + 1033 => [0, 0, nil, nil, nil, 1113, nil], + 1034 => [0, 0, nil, nil, nil, 1114, nil], + 1035 => [0, 0, nil, nil, nil, 1115, nil], + 1036 => [0, 0, "Ќ", "Ќ", nil, 1116, nil], + 1037 => [0, 0, "Ѝ", "Ѝ", nil, 1117, nil], + 1038 => [0, 0, "Ў", "Ў", nil, 1118, nil], + 1039 => [0, 0, nil, nil, nil, 1119, nil], + 1040 => [0, 0, nil, nil, nil, 1072, nil], + 1041 => [0, 0, nil, nil, nil, 1073, nil], + 1042 => [0, 0, nil, nil, nil, 1074, nil], + 1043 => [0, 0, nil, nil, nil, 1075, nil], + 1044 => [0, 0, nil, nil, nil, 1076, nil], + 1045 => [0, 0, nil, nil, nil, 1077, nil], + 1046 => [0, 0, nil, nil, nil, 1078, nil], + 1047 => [0, 0, nil, nil, nil, 1079, nil], + 1048 => [0, 0, nil, nil, nil, 1080, nil], + 1049 => [0, 0, "Й", "Й", nil, 1081, nil], + 1050 => [0, 0, nil, nil, nil, 1082, nil], + 1051 => [0, 0, nil, nil, nil, 1083, nil], + 1052 => [0, 0, nil, nil, nil, 1084, nil], + 1053 => [0, 0, nil, nil, nil, 1085, nil], + 1054 => [0, 0, nil, nil, nil, 1086, nil], + 1055 => [0, 0, nil, nil, nil, 1087, nil], + 1056 => [0, 0, nil, nil, nil, 1088, nil], + 1057 => [0, 0, nil, nil, nil, 1089, nil], + 1058 => [0, 0, nil, nil, nil, 1090, nil], + 1059 => [0, 0, nil, nil, nil, 1091, nil], + 1060 => [0, 0, nil, nil, nil, 1092, nil], + 1061 => [0, 0, nil, nil, nil, 1093, nil], + 1062 => [0, 0, nil, nil, nil, 1094, nil], + 1063 => [0, 0, nil, nil, nil, 1095, nil], + 1064 => [0, 0, nil, nil, nil, 1096, nil], + 1065 => [0, 0, nil, nil, nil, 1097, nil], + 1066 => [0, 0, nil, nil, nil, 1098, nil], + 1067 => [0, 0, nil, nil, nil, 1099, nil], + 1068 => [0, 0, nil, nil, nil, 1100, nil], + 1069 => [0, 0, nil, nil, nil, 1101, nil], + 1070 => [0, 0, nil, nil, nil, 1102, nil], + 1071 => [0, 0, nil, nil, nil, 1103, nil], + 1072 => [0, 0, nil, nil, 1040, nil, 1040], + 1073 => [0, 0, nil, nil, 1041, nil, 1041], + 1074 => [0, 0, nil, nil, 1042, nil, 1042], + 1075 => [0, 0, nil, nil, 1043, nil, 1043], + 1076 => [0, 0, nil, nil, 1044, nil, 1044], + 1077 => [0, 0, nil, nil, 1045, nil, 1045], + 1078 => [0, 0, nil, nil, 1046, nil, 1046], + 1079 => [0, 0, nil, nil, 1047, nil, 1047], + 1080 => [0, 0, nil, nil, 1048, nil, 1048], + 1081 => [0, 0, "й", "й", 1049, nil, 1049], + 1082 => [0, 0, nil, nil, 1050, nil, 1050], + 1083 => [0, 0, nil, nil, 1051, nil, 1051], + 1084 => [0, 0, nil, nil, 1052, nil, 1052], + 1085 => [0, 0, nil, nil, 1053, nil, 1053], + 1086 => [0, 0, nil, nil, 1054, nil, 1054], + 1087 => [0, 0, nil, nil, 1055, nil, 1055], + 1088 => [0, 0, nil, nil, 1056, nil, 1056], + 1089 => [0, 0, nil, nil, 1057, nil, 1057], + 1090 => [0, 0, nil, nil, 1058, nil, 1058], + 1091 => [0, 0, nil, nil, 1059, nil, 1059], + 1092 => [0, 0, nil, nil, 1060, nil, 1060], + 1093 => [0, 0, nil, nil, 1061, nil, 1061], + 1094 => [0, 0, nil, nil, 1062, nil, 1062], + 1095 => [0, 0, nil, nil, 1063, nil, 1063], + 1096 => [0, 0, nil, nil, 1064, nil, 1064], + 1097 => [0, 0, nil, nil, 1065, nil, 1065], + 1098 => [0, 0, nil, nil, 1066, nil, 1066], + 1099 => [0, 0, nil, nil, 1067, nil, 1067], + 1100 => [0, 0, nil, nil, 1068, nil, 1068], + 1101 => [0, 0, nil, nil, 1069, nil, 1069], + 1102 => [0, 0, nil, nil, 1070, nil, 1070], + 1103 => [0, 0, nil, nil, 1071, nil, 1071], + 1104 => [0, 0, "ѐ", "ѐ", 1024, nil, 1024], + 1105 => [0, 0, "ё", "ё", 1025, nil, 1025], + 1106 => [0, 0, nil, nil, 1026, nil, 1026], + 1107 => [0, 0, "ѓ", "ѓ", 1027, nil, 1027], + 1108 => [0, 0, nil, nil, 1028, nil, 1028], + 1109 => [0, 0, nil, nil, 1029, nil, 1029], + 1110 => [0, 0, nil, nil, 1030, nil, 1030], + 1111 => [0, 0, "ї", "ї", 1031, nil, 1031], + 1112 => [0, 0, nil, nil, 1032, nil, 1032], + 1113 => [0, 0, nil, nil, 1033, nil, 1033], + 1114 => [0, 0, nil, nil, 1034, nil, 1034], + 1115 => [0, 0, nil, nil, 1035, nil, 1035], + 1116 => [0, 0, "ќ", "ќ", 1036, nil, 1036], + 1117 => [0, 0, "ѝ", "ѝ", 1037, nil, 1037], + 1118 => [0, 0, "ў", "ў", 1038, nil, 1038], + 1119 => [0, 0, nil, nil, 1039, nil, 1039], + 1120 => [0, 0, nil, nil, nil, 1121, nil], + 1121 => [0, 0, nil, nil, 1120, nil, 1120], + 1122 => [0, 0, nil, nil, nil, 1123, nil], + 1123 => [0, 0, nil, nil, 1122, nil, 1122], + 1124 => [0, 0, nil, nil, nil, 1125, nil], + 1125 => [0, 0, nil, nil, 1124, nil, 1124], + 1126 => [0, 0, nil, nil, nil, 1127, nil], + 1127 => [0, 0, nil, nil, 1126, nil, 1126], + 1128 => [0, 0, nil, nil, nil, 1129, nil], + 1129 => [0, 0, nil, nil, 1128, nil, 1128], + 1130 => [0, 0, nil, nil, nil, 1131, nil], + 1131 => [0, 0, nil, nil, 1130, nil, 1130], + 1132 => [0, 0, nil, nil, nil, 1133, nil], + 1133 => [0, 0, nil, nil, 1132, nil, 1132], + 1134 => [0, 0, nil, nil, nil, 1135, nil], + 1135 => [0, 0, nil, nil, 1134, nil, 1134], + 1136 => [0, 0, nil, nil, nil, 1137, nil], + 1137 => [0, 0, nil, nil, 1136, nil, 1136], + 1138 => [0, 0, nil, nil, nil, 1139, nil], + 1139 => [0, 0, nil, nil, 1138, nil, 1138], + 1140 => [0, 0, nil, nil, nil, 1141, nil], + 1141 => [0, 0, nil, nil, 1140, nil, 1140], + 1142 => [0, 0, "Ѷ", "Ѷ", nil, 1143, nil], + 1143 => [0, 0, "ѷ", "ѷ", 1142, nil, 1142], + 1144 => [0, 0, nil, nil, nil, 1145, nil], + 1145 => [0, 0, nil, nil, 1144, nil, 1144], + 1146 => [0, 0, nil, nil, nil, 1147, nil], + 1147 => [0, 0, nil, nil, 1146, nil, 1146], + 1148 => [0, 0, nil, nil, nil, 1149, nil], + 1149 => [0, 0, nil, nil, 1148, nil, 1148], + 1150 => [0, 0, nil, nil, nil, 1151, nil], + 1151 => [0, 0, nil, nil, 1150, nil, 1150], + 1152 => [0, 0, nil, nil, nil, 1153, nil], + 1153 => [0, 0, nil, nil, 1152, nil, 1152], + 1155 => [230, 0, nil, nil, nil, nil, nil], + 1156 => [230, 0, nil, nil, nil, nil, nil], + 1157 => [230, 0, nil, nil, nil, nil, nil], + 1158 => [230, 0, nil, nil, nil, nil, nil], + 1164 => [0, 0, nil, nil, nil, 1165, nil], + 1165 => [0, 0, nil, nil, 1164, nil, 1164], + 1166 => [0, 0, nil, nil, nil, 1167, nil], + 1167 => [0, 0, nil, nil, 1166, nil, 1166], + 1168 => [0, 0, nil, nil, nil, 1169, nil], + 1169 => [0, 0, nil, nil, 1168, nil, 1168], + 1170 => [0, 0, nil, nil, nil, 1171, nil], + 1171 => [0, 0, nil, nil, 1170, nil, 1170], + 1172 => [0, 0, nil, nil, nil, 1173, nil], + 1173 => [0, 0, nil, nil, 1172, nil, 1172], + 1174 => [0, 0, nil, nil, nil, 1175, nil], + 1175 => [0, 0, nil, nil, 1174, nil, 1174], + 1176 => [0, 0, nil, nil, nil, 1177, nil], + 1177 => [0, 0, nil, nil, 1176, nil, 1176], + 1178 => [0, 0, nil, nil, nil, 1179, nil], + 1179 => [0, 0, nil, nil, 1178, nil, 1178], + 1180 => [0, 0, nil, nil, nil, 1181, nil], + 1181 => [0, 0, nil, nil, 1180, nil, 1180], + 1182 => [0, 0, nil, nil, nil, 1183, nil], + 1183 => [0, 0, nil, nil, 1182, nil, 1182], + 1184 => [0, 0, nil, nil, nil, 1185, nil], + 1185 => [0, 0, nil, nil, 1184, nil, 1184], + 1186 => [0, 0, nil, nil, nil, 1187, nil], + 1187 => [0, 0, nil, nil, 1186, nil, 1186], + 1188 => [0, 0, nil, nil, nil, 1189, nil], + 1189 => [0, 0, nil, nil, 1188, nil, 1188], + 1190 => [0, 0, nil, nil, nil, 1191, nil], + 1191 => [0, 0, nil, nil, 1190, nil, 1190], + 1192 => [0, 0, nil, nil, nil, 1193, nil], + 1193 => [0, 0, nil, nil, 1192, nil, 1192], + 1194 => [0, 0, nil, nil, nil, 1195, nil], + 1195 => [0, 0, nil, nil, 1194, nil, 1194], + 1196 => [0, 0, nil, nil, nil, 1197, nil], + 1197 => [0, 0, nil, nil, 1196, nil, 1196], + 1198 => [0, 0, nil, nil, nil, 1199, nil], + 1199 => [0, 0, nil, nil, 1198, nil, 1198], + 1200 => [0, 0, nil, nil, nil, 1201, nil], + 1201 => [0, 0, nil, nil, 1200, nil, 1200], + 1202 => [0, 0, nil, nil, nil, 1203, nil], + 1203 => [0, 0, nil, nil, 1202, nil, 1202], + 1204 => [0, 0, nil, nil, nil, 1205, nil], + 1205 => [0, 0, nil, nil, 1204, nil, 1204], + 1206 => [0, 0, nil, nil, nil, 1207, nil], + 1207 => [0, 0, nil, nil, 1206, nil, 1206], + 1208 => [0, 0, nil, nil, nil, 1209, nil], + 1209 => [0, 0, nil, nil, 1208, nil, 1208], + 1210 => [0, 0, nil, nil, nil, 1211, nil], + 1211 => [0, 0, nil, nil, 1210, nil, 1210], + 1212 => [0, 0, nil, nil, nil, 1213, nil], + 1213 => [0, 0, nil, nil, 1212, nil, 1212], + 1214 => [0, 0, nil, nil, nil, 1215, nil], + 1215 => [0, 0, nil, nil, 1214, nil, 1214], + 1217 => [0, 0, "Ӂ", "Ӂ", nil, 1218, nil], + 1218 => [0, 0, "ӂ", "ӂ", 1217, nil, 1217], + 1219 => [0, 0, nil, nil, nil, 1220, nil], + 1220 => [0, 0, nil, nil, 1219, nil, 1219], + 1223 => [0, 0, nil, nil, nil, 1224, nil], + 1224 => [0, 0, nil, nil, 1223, nil, 1223], + 1227 => [0, 0, nil, nil, nil, 1228, nil], + 1228 => [0, 0, nil, nil, 1227, nil, 1227], + 1232 => [0, 0, "Ӑ", "Ӑ", nil, 1233, nil], + 1233 => [0, 0, "ӑ", "ӑ", 1232, nil, 1232], + 1234 => [0, 0, "Ӓ", "Ӓ", nil, 1235, nil], + 1235 => [0, 0, "ӓ", "ӓ", 1234, nil, 1234], + 1236 => [0, 0, nil, nil, nil, 1237, nil], + 1237 => [0, 0, nil, nil, 1236, nil, 1236], + 1238 => [0, 0, "Ӗ", "Ӗ", nil, 1239, nil], + 1239 => [0, 0, "ӗ", "ӗ", 1238, nil, 1238], + 1240 => [0, 0, nil, nil, nil, 1241, nil], + 1241 => [0, 0, nil, nil, 1240, nil, 1240], + 1242 => [0, 0, "Ӛ", "Ӛ", nil, 1243, nil], + 1243 => [0, 0, "ӛ", "ӛ", 1242, nil, 1242], + 1244 => [0, 0, "Ӝ", "Ӝ", nil, 1245, nil], + 1245 => [0, 0, "ӝ", "ӝ", 1244, nil, 1244], + 1246 => [0, 0, "Ӟ", "Ӟ", nil, 1247, nil], + 1247 => [0, 0, "ӟ", "ӟ", 1246, nil, 1246], + 1248 => [0, 0, nil, nil, nil, 1249, nil], + 1249 => [0, 0, nil, nil, 1248, nil, 1248], + 1250 => [0, 0, "Ӣ", "Ӣ", nil, 1251, nil], + 1251 => [0, 0, "ӣ", "ӣ", 1250, nil, 1250], + 1252 => [0, 0, "Ӥ", "Ӥ", nil, 1253, nil], + 1253 => [0, 0, "ӥ", "ӥ", 1252, nil, 1252], + 1254 => [0, 0, "Ӧ", "Ӧ", nil, 1255, nil], + 1255 => [0, 0, "ӧ", "ӧ", 1254, nil, 1254], + 1256 => [0, 0, nil, nil, nil, 1257, nil], + 1257 => [0, 0, nil, nil, 1256, nil, 1256], + 1258 => [0, 0, "Ӫ", "Ӫ", nil, 1259, nil], + 1259 => [0, 0, "ӫ", "ӫ", 1258, nil, 1258], + 1260 => [0, 0, "Ӭ", "Ӭ", nil, 1261, nil], + 1261 => [0, 0, "ӭ", "ӭ", 1260, nil, 1260], + 1262 => [0, 0, "Ӯ", "Ӯ", nil, 1263, nil], + 1263 => [0, 0, "ӯ", "ӯ", 1262, nil, 1262], + 1264 => [0, 0, "Ӱ", "Ӱ", nil, 1265, nil], + 1265 => [0, 0, "ӱ", "ӱ", 1264, nil, 1264], + 1266 => [0, 0, "Ӳ", "Ӳ", nil, 1267, nil], + 1267 => [0, 0, "ӳ", "ӳ", 1266, nil, 1266], + 1268 => [0, 0, "Ӵ", "Ӵ", nil, 1269, nil], + 1269 => [0, 0, "ӵ", "ӵ", 1268, nil, 1268], + 1272 => [0, 0, "Ӹ", "Ӹ", nil, 1273, nil], + 1273 => [0, 0, "ӹ", "ӹ", 1272, nil, 1272], + 1329 => [0, 0, nil, nil, nil, 1377, nil], + 1330 => [0, 0, nil, nil, nil, 1378, nil], + 1331 => [0, 0, nil, nil, nil, 1379, nil], + 1332 => [0, 0, nil, nil, nil, 1380, nil], + 1333 => [0, 0, nil, nil, nil, 1381, nil], + 1334 => [0, 0, nil, nil, nil, 1382, nil], + 1335 => [0, 0, nil, nil, nil, 1383, nil], + 1336 => [0, 0, nil, nil, nil, 1384, nil], + 1337 => [0, 0, nil, nil, nil, 1385, nil], + 1338 => [0, 0, nil, nil, nil, 1386, nil], + 1339 => [0, 0, nil, nil, nil, 1387, nil], + 1340 => [0, 0, nil, nil, nil, 1388, nil], + 1341 => [0, 0, nil, nil, nil, 1389, nil], + 1342 => [0, 0, nil, nil, nil, 1390, nil], + 1343 => [0, 0, nil, nil, nil, 1391, nil], + 1344 => [0, 0, nil, nil, nil, 1392, nil], + 1345 => [0, 0, nil, nil, nil, 1393, nil], + 1346 => [0, 0, nil, nil, nil, 1394, nil], + 1347 => [0, 0, nil, nil, nil, 1395, nil], + 1348 => [0, 0, nil, nil, nil, 1396, nil], + 1349 => [0, 0, nil, nil, nil, 1397, nil], + 1350 => [0, 0, nil, nil, nil, 1398, nil], + 1351 => [0, 0, nil, nil, nil, 1399, nil], + 1352 => [0, 0, nil, nil, nil, 1400, nil], + 1353 => [0, 0, nil, nil, nil, 1401, nil], + 1354 => [0, 0, nil, nil, nil, 1402, nil], + 1355 => [0, 0, nil, nil, nil, 1403, nil], + 1356 => [0, 0, nil, nil, nil, 1404, nil], + 1357 => [0, 0, nil, nil, nil, 1405, nil], + 1358 => [0, 0, nil, nil, nil, 1406, nil], + 1359 => [0, 0, nil, nil, nil, 1407, nil], + 1360 => [0, 0, nil, nil, nil, 1408, nil], + 1361 => [0, 0, nil, nil, nil, 1409, nil], + 1362 => [0, 0, nil, nil, nil, 1410, nil], + 1363 => [0, 0, nil, nil, nil, 1411, nil], + 1364 => [0, 0, nil, nil, nil, 1412, nil], + 1365 => [0, 0, nil, nil, nil, 1413, nil], + 1366 => [0, 0, nil, nil, nil, 1414, nil], + 1377 => [0, 0, nil, nil, 1329, nil, 1329], + 1378 => [0, 0, nil, nil, 1330, nil, 1330], + 1379 => [0, 0, nil, nil, 1331, nil, 1331], + 1380 => [0, 0, nil, nil, 1332, nil, 1332], + 1381 => [0, 0, nil, nil, 1333, nil, 1333], + 1382 => [0, 0, nil, nil, 1334, nil, 1334], + 1383 => [0, 0, nil, nil, 1335, nil, 1335], + 1384 => [0, 0, nil, nil, 1336, nil, 1336], + 1385 => [0, 0, nil, nil, 1337, nil, 1337], + 1386 => [0, 0, nil, nil, 1338, nil, 1338], + 1387 => [0, 0, nil, nil, 1339, nil, 1339], + 1388 => [0, 0, nil, nil, 1340, nil, 1340], + 1389 => [0, 0, nil, nil, 1341, nil, 1341], + 1390 => [0, 0, nil, nil, 1342, nil, 1342], + 1391 => [0, 0, nil, nil, 1343, nil, 1343], + 1392 => [0, 0, nil, nil, 1344, nil, 1344], + 1393 => [0, 0, nil, nil, 1345, nil, 1345], + 1394 => [0, 0, nil, nil, 1346, nil, 1346], + 1395 => [0, 0, nil, nil, 1347, nil, 1347], + 1396 => [0, 0, nil, nil, 1348, nil, 1348], + 1397 => [0, 0, nil, nil, 1349, nil, 1349], + 1398 => [0, 0, nil, nil, 1350, nil, 1350], + 1399 => [0, 0, nil, nil, 1351, nil, 1351], + 1400 => [0, 0, nil, nil, 1352, nil, 1352], + 1401 => [0, 0, nil, nil, 1353, nil, 1353], + 1402 => [0, 0, nil, nil, 1354, nil, 1354], + 1403 => [0, 0, nil, nil, 1355, nil, 1355], + 1404 => [0, 0, nil, nil, 1356, nil, 1356], + 1405 => [0, 0, nil, nil, 1357, nil, 1357], + 1406 => [0, 0, nil, nil, 1358, nil, 1358], + 1407 => [0, 0, nil, nil, 1359, nil, 1359], + 1408 => [0, 0, nil, nil, 1360, nil, 1360], + 1409 => [0, 0, nil, nil, 1361, nil, 1361], + 1410 => [0, 0, nil, nil, 1362, nil, 1362], + 1411 => [0, 0, nil, nil, 1363, nil, 1363], + 1412 => [0, 0, nil, nil, 1364, nil, 1364], + 1413 => [0, 0, nil, nil, 1365, nil, 1365], + 1414 => [0, 0, nil, nil, 1366, nil, 1366], + 1415 => [0, 0, nil, "եւ", nil, nil, nil], + 1425 => [220, 0, nil, nil, nil, nil, nil], + 1426 => [230, 0, nil, nil, nil, nil, nil], + 1427 => [230, 0, nil, nil, nil, nil, nil], + 1428 => [230, 0, nil, nil, nil, nil, nil], + 1429 => [230, 0, nil, nil, nil, nil, nil], + 1430 => [220, 0, nil, nil, nil, nil, nil], + 1431 => [230, 0, nil, nil, nil, nil, nil], + 1432 => [230, 0, nil, nil, nil, nil, nil], + 1433 => [230, 0, nil, nil, nil, nil, nil], + 1434 => [222, 0, nil, nil, nil, nil, nil], + 1435 => [220, 0, nil, nil, nil, nil, nil], + 1436 => [230, 0, nil, nil, nil, nil, nil], + 1437 => [230, 0, nil, nil, nil, nil, nil], + 1438 => [230, 0, nil, nil, nil, nil, nil], + 1439 => [230, 0, nil, nil, nil, nil, nil], + 1440 => [230, 0, nil, nil, nil, nil, nil], + 1441 => [230, 0, nil, nil, nil, nil, nil], + 1443 => [220, 0, nil, nil, nil, nil, nil], + 1444 => [220, 0, nil, nil, nil, nil, nil], + 1445 => [220, 0, nil, nil, nil, nil, nil], + 1446 => [220, 0, nil, nil, nil, nil, nil], + 1447 => [220, 0, nil, nil, nil, nil, nil], + 1448 => [230, 0, nil, nil, nil, nil, nil], + 1449 => [230, 0, nil, nil, nil, nil, nil], + 1450 => [220, 0, nil, nil, nil, nil, nil], + 1451 => [230, 0, nil, nil, nil, nil, nil], + 1452 => [230, 0, nil, nil, nil, nil, nil], + 1453 => [222, 0, nil, nil, nil, nil, nil], + 1454 => [228, 0, nil, nil, nil, nil, nil], + 1455 => [230, 0, nil, nil, nil, nil, nil], + 1456 => [10, 0, nil, nil, nil, nil, nil], + 1457 => [11, 0, nil, nil, nil, nil, nil], + 1458 => [12, 0, nil, nil, nil, nil, nil], + 1459 => [13, 0, nil, nil, nil, nil, nil], + 1460 => [14, 0, nil, nil, nil, nil, nil], + 1461 => [15, 0, nil, nil, nil, nil, nil], + 1462 => [16, 0, nil, nil, nil, nil, nil], + 1463 => [17, 0, nil, nil, nil, nil, nil], + 1464 => [18, 0, nil, nil, nil, nil, nil], + 1465 => [19, 0, nil, nil, nil, nil, nil], + 1467 => [20, 0, nil, nil, nil, nil, nil], + 1468 => [21, 0, nil, nil, nil, nil, nil], + 1469 => [22, 0, nil, nil, nil, nil, nil], + 1471 => [23, 0, nil, nil, nil, nil, nil], + 1473 => [24, 0, nil, nil, nil, nil, nil], + 1474 => [25, 0, nil, nil, nil, nil, nil], + 1476 => [230, 0, nil, nil, nil, nil, nil], + 1570 => [0, 0, "آ", "آ", nil, nil, nil], + 1571 => [0, 0, "أ", "أ", nil, nil, nil], + 1572 => [0, 0, "ؤ", "ؤ", nil, nil, nil], + 1573 => [0, 0, "إ", "إ", nil, nil, nil], + 1574 => [0, 0, "ئ", "ئ", nil, nil, nil], + 1611 => [27, 0, nil, nil, nil, nil, nil], + 1612 => [28, 0, nil, nil, nil, nil, nil], + 1613 => [29, 0, nil, nil, nil, nil, nil], + 1614 => [30, 0, nil, nil, nil, nil, nil], + 1615 => [31, 0, nil, nil, nil, nil, nil], + 1616 => [32, 0, nil, nil, nil, nil, nil], + 1617 => [33, 0, nil, nil, nil, nil, nil], + 1618 => [34, 0, nil, nil, nil, nil, nil], + 1619 => [230, 0, nil, nil, nil, nil, nil], + 1620 => [230, 0, nil, nil, nil, nil, nil], + 1621 => [220, 0, nil, nil, nil, nil, nil], + 1648 => [35, 0, nil, nil, nil, nil, nil], + 1653 => [0, 0, nil, "اٴ", nil, nil, nil], + 1654 => [0, 0, nil, "وٴ", nil, nil, nil], + 1655 => [0, 0, nil, "ۇٴ", nil, nil, nil], + 1656 => [0, 0, nil, "يٴ", nil, nil, nil], + 1728 => [0, 0, "ۀ", "ۀ", nil, nil, nil], + 1730 => [0, 0, "ۂ", "ۂ", nil, nil, nil], + 1747 => [0, 0, "ۓ", "ۓ", nil, nil, nil], + 1750 => [230, 0, nil, nil, nil, nil, nil], + 1751 => [230, 0, nil, nil, nil, nil, nil], + 1752 => [230, 0, nil, nil, nil, nil, nil], + 1753 => [230, 0, nil, nil, nil, nil, nil], + 1754 => [230, 0, nil, nil, nil, nil, nil], + 1755 => [230, 0, nil, nil, nil, nil, nil], + 1756 => [230, 0, nil, nil, nil, nil, nil], + 1759 => [230, 0, nil, nil, nil, nil, nil], + 1760 => [230, 0, nil, nil, nil, nil, nil], + 1761 => [230, 0, nil, nil, nil, nil, nil], + 1762 => [230, 0, nil, nil, nil, nil, nil], + 1763 => [220, 0, nil, nil, nil, nil, nil], + 1764 => [230, 0, nil, nil, nil, nil, nil], + 1767 => [230, 0, nil, nil, nil, nil, nil], + 1768 => [230, 0, nil, nil, nil, nil, nil], + 1770 => [220, 0, nil, nil, nil, nil, nil], + 1771 => [230, 0, nil, nil, nil, nil, nil], + 1772 => [230, 0, nil, nil, nil, nil, nil], + 1773 => [220, 0, nil, nil, nil, nil, nil], + 1809 => [36, 0, nil, nil, nil, nil, nil], + 1840 => [230, 0, nil, nil, nil, nil, nil], + 1841 => [220, 0, nil, nil, nil, nil, nil], + 1842 => [230, 0, nil, nil, nil, nil, nil], + 1843 => [230, 0, nil, nil, nil, nil, nil], + 1844 => [220, 0, nil, nil, nil, nil, nil], + 1845 => [230, 0, nil, nil, nil, nil, nil], + 1846 => [230, 0, nil, nil, nil, nil, nil], + 1847 => [220, 0, nil, nil, nil, nil, nil], + 1848 => [220, 0, nil, nil, nil, nil, nil], + 1849 => [220, 0, nil, nil, nil, nil, nil], + 1850 => [230, 0, nil, nil, nil, nil, nil], + 1851 => [220, 0, nil, nil, nil, nil, nil], + 1852 => [220, 0, nil, nil, nil, nil, nil], + 1853 => [230, 0, nil, nil, nil, nil, nil], + 1854 => [220, 0, nil, nil, nil, nil, nil], + 1855 => [230, 0, nil, nil, nil, nil, nil], + 1856 => [230, 0, nil, nil, nil, nil, nil], + 1857 => [230, 0, nil, nil, nil, nil, nil], + 1858 => [220, 0, nil, nil, nil, nil, nil], + 1859 => [230, 0, nil, nil, nil, nil, nil], + 1860 => [220, 0, nil, nil, nil, nil, nil], + 1861 => [230, 0, nil, nil, nil, nil, nil], + 1862 => [220, 0, nil, nil, nil, nil, nil], + 1863 => [230, 0, nil, nil, nil, nil, nil], + 1864 => [220, 0, nil, nil, nil, nil, nil], + 1865 => [230, 0, nil, nil, nil, nil, nil], + 1866 => [230, 0, nil, nil, nil, nil, nil], + 2345 => [0, 0, "ऩ", "ऩ", nil, nil, nil], + 2353 => [0, 0, "ऱ", "ऱ", nil, nil, nil], + 2356 => [0, 0, "ऴ", "ऴ", nil, nil, nil], + 2364 => [7, 0, nil, nil, nil, nil, nil], + 2381 => [9, 0, nil, nil, nil, nil, nil], + 2385 => [230, 0, nil, nil, nil, nil, nil], + 2386 => [220, 0, nil, nil, nil, nil, nil], + 2387 => [230, 0, nil, nil, nil, nil, nil], + 2388 => [230, 0, nil, nil, nil, nil, nil], + 2392 => [0, 1, "क़", "क़", nil, nil, nil], + 2393 => [0, 1, "ख़", "ख़", nil, nil, nil], + 2394 => [0, 1, "ग़", "ग़", nil, nil, nil], + 2395 => [0, 1, "ज़", "ज़", nil, nil, nil], + 2396 => [0, 1, "ड़", "ड़", nil, nil, nil], + 2397 => [0, 1, "ढ़", "ढ़", nil, nil, nil], + 2398 => [0, 1, "फ़", "फ़", nil, nil, nil], + 2399 => [0, 1, "य़", "य़", nil, nil, nil], + 2492 => [7, 0, nil, nil, nil, nil, nil], + 2507 => [0, 0, "ো", "ো", nil, nil, nil], + 2508 => [0, 0, "ৌ", "ৌ", nil, nil, nil], + 2509 => [9, 0, nil, nil, nil, nil, nil], + 2524 => [0, 1, "ড়", "ড়", nil, nil, nil], + 2525 => [0, 1, "ঢ়", "ঢ়", nil, nil, nil], + 2527 => [0, 1, "য়", "য়", nil, nil, nil], + 2611 => [0, 1, "ਲ਼", "ਲ਼", nil, nil, nil], + 2614 => [0, 1, "ਸ਼", "ਸ਼", nil, nil, nil], + 2620 => [7, 0, nil, nil, nil, nil, nil], + 2637 => [9, 0, nil, nil, nil, nil, nil], + 2649 => [0, 1, "ਖ਼", "ਖ਼", nil, nil, nil], + 2650 => [0, 1, "ਗ਼", "ਗ਼", nil, nil, nil], + 2651 => [0, 1, "ਜ਼", "ਜ਼", nil, nil, nil], + 2654 => [0, 1, "ਫ਼", "ਫ਼", nil, nil, nil], + 2748 => [7, 0, nil, nil, nil, nil, nil], + 2765 => [9, 0, nil, nil, nil, nil, nil], + 2876 => [7, 0, nil, nil, nil, nil, nil], + 2888 => [0, 0, "ୈ", "ୈ", nil, nil, nil], + 2891 => [0, 0, "ୋ", "ୋ", nil, nil, nil], + 2892 => [0, 0, "ୌ", "ୌ", nil, nil, nil], + 2893 => [9, 0, nil, nil, nil, nil, nil], + 2908 => [0, 1, "ଡ଼", "ଡ଼", nil, nil, nil], + 2909 => [0, 1, "ଢ଼", "ଢ଼", nil, nil, nil], + 2964 => [0, 0, "ஔ", "ஔ", nil, nil, nil], + 3018 => [0, 0, "ொ", "ொ", nil, nil, nil], + 3019 => [0, 0, "ோ", "ோ", nil, nil, nil], + 3020 => [0, 0, "ௌ", "ௌ", nil, nil, nil], + 3021 => [9, 0, nil, nil, nil, nil, nil], + 3144 => [0, 0, "ై", "ై", nil, nil, nil], + 3149 => [9, 0, nil, nil, nil, nil, nil], + 3157 => [84, 0, nil, nil, nil, nil, nil], + 3158 => [91, 0, nil, nil, nil, nil, nil], + 3264 => [0, 0, "ೀ", "ೀ", nil, nil, nil], + 3271 => [0, 0, "ೇ", "ೇ", nil, nil, nil], + 3272 => [0, 0, "ೈ", "ೈ", nil, nil, nil], + 3274 => [0, 0, "ೊ", "ೊ", nil, nil, nil], + 3275 => [0, 0, "ೋ", "ೋ", nil, nil, nil], + 3277 => [9, 0, nil, nil, nil, nil, nil], + 3402 => [0, 0, "ൊ", "ൊ", nil, nil, nil], + 3403 => [0, 0, "ോ", "ോ", nil, nil, nil], + 3404 => [0, 0, "ൌ", "ൌ", nil, nil, nil], + 3405 => [9, 0, nil, nil, nil, nil, nil], + 3530 => [9, 0, nil, nil, nil, nil, nil], + 3546 => [0, 0, "ේ", "ේ", nil, nil, nil], + 3548 => [0, 0, "ො", "ො", nil, nil, nil], + 3549 => [0, 0, "ෝ", "ෝ", nil, nil, nil], + 3550 => [0, 0, "ෞ", "ෞ", nil, nil, nil], + 3635 => [0, 0, nil, "ํา", nil, nil, nil], + 3640 => [103, 0, nil, nil, nil, nil, nil], + 3641 => [103, 0, nil, nil, nil, nil, nil], + 3642 => [9, 0, nil, nil, nil, nil, nil], + 3656 => [107, 0, nil, nil, nil, nil, nil], + 3657 => [107, 0, nil, nil, nil, nil, nil], + 3658 => [107, 0, nil, nil, nil, nil, nil], + 3659 => [107, 0, nil, nil, nil, nil, nil], + 3763 => [0, 0, nil, "ໍາ", nil, nil, nil], + 3768 => [118, 0, nil, nil, nil, nil, nil], + 3769 => [118, 0, nil, nil, nil, nil, nil], + 3784 => [122, 0, nil, nil, nil, nil, nil], + 3785 => [122, 0, nil, nil, nil, nil, nil], + 3786 => [122, 0, nil, nil, nil, nil, nil], + 3787 => [122, 0, nil, nil, nil, nil, nil], + 3804 => [0, 0, nil, "ຫນ", nil, nil, nil], + 3805 => [0, 0, nil, "ຫມ", nil, nil, nil], + 3852 => [0, 0, nil, "་", nil, nil, nil], + 3864 => [220, 0, nil, nil, nil, nil, nil], + 3865 => [220, 0, nil, nil, nil, nil, nil], + 3893 => [220, 0, nil, nil, nil, nil, nil], + 3895 => [220, 0, nil, nil, nil, nil, nil], + 3897 => [216, 0, nil, nil, nil, nil, nil], + 3907 => [0, 1, "གྷ", "གྷ", nil, nil, nil], + 3917 => [0, 1, "ཌྷ", "ཌྷ", nil, nil, nil], + 3922 => [0, 1, "དྷ", "དྷ", nil, nil, nil], + 3927 => [0, 1, "བྷ", "བྷ", nil, nil, nil], + 3932 => [0, 1, "ཛྷ", "ཛྷ", nil, nil, nil], + 3945 => [0, 1, "ཀྵ", "ཀྵ", nil, nil, nil], + 3953 => [129, 0, nil, nil, nil, nil, nil], + 3954 => [130, 0, nil, nil, nil, nil, nil], + 3955 => [0, 3, "ཱི", "ཱི", nil, nil, nil], + 3956 => [132, 0, nil, nil, nil, nil, nil], + 3957 => [0, 3, "ཱུ", "ཱུ", nil, nil, nil], + 3958 => [0, 1, "ྲྀ", "ྲྀ", nil, nil, nil], + 3959 => [0, 0, nil, "ྲཱྀ", nil, nil, nil], + 3960 => [0, 1, "ླྀ", "ླྀ", nil, nil, nil], + 3961 => [0, 0, nil, "ླཱྀ", nil, nil, nil], + 3962 => [130, 0, nil, nil, nil, nil, nil], + 3963 => [130, 0, nil, nil, nil, nil, nil], + 3964 => [130, 0, nil, nil, nil, nil, nil], + 3965 => [130, 0, nil, nil, nil, nil, nil], + 3968 => [130, 0, nil, nil, nil, nil, nil], + 3969 => [0, 3, "ཱྀ", "ཱྀ", nil, nil, nil], + 3970 => [230, 0, nil, nil, nil, nil, nil], + 3971 => [230, 0, nil, nil, nil, nil, nil], + 3972 => [9, 0, nil, nil, nil, nil, nil], + 3974 => [230, 0, nil, nil, nil, nil, nil], + 3975 => [230, 0, nil, nil, nil, nil, nil], + 3987 => [0, 1, "ྒྷ", "ྒྷ", nil, nil, nil], + 3997 => [0, 1, "ྜྷ", "ྜྷ", nil, nil, nil], + 4002 => [0, 1, "ྡྷ", "ྡྷ", nil, nil, nil], + 4007 => [0, 1, "ྦྷ", "ྦྷ", nil, nil, nil], + 4012 => [0, 1, "ྫྷ", "ྫྷ", nil, nil, nil], + 4025 => [0, 1, "ྐྵ", "ྐྵ", nil, nil, nil], + 4038 => [220, 0, nil, nil, nil, nil, nil], + 4134 => [0, 0, "ဦ", "ဦ", nil, nil, nil], + 4151 => [7, 0, nil, nil, nil, nil, nil], + 4153 => [9, 0, nil, nil, nil, nil, nil], + 6098 => [9, 0, nil, nil, nil, nil, nil], + 6313 => [228, 0, nil, nil, nil, nil, nil], + 7680 => [0, 0, "Ḁ", "Ḁ", nil, 7681, nil], + 7681 => [0, 0, "ḁ", "ḁ", 7680, nil, 7680], + 7682 => [0, 0, "Ḃ", "Ḃ", nil, 7683, nil], + 7683 => [0, 0, "ḃ", "ḃ", 7682, nil, 7682], + 7684 => [0, 0, "Ḅ", "Ḅ", nil, 7685, nil], + 7685 => [0, 0, "ḅ", "ḅ", 7684, nil, 7684], + 7686 => [0, 0, "Ḇ", "Ḇ", nil, 7687, nil], + 7687 => [0, 0, "ḇ", "ḇ", 7686, nil, 7686], + 7688 => [0, 0, "Ḉ", "Ḉ", nil, 7689, nil], + 7689 => [0, 0, "ḉ", "ḉ", 7688, nil, 7688], + 7690 => [0, 0, "Ḋ", "Ḋ", nil, 7691, nil], + 7691 => [0, 0, "ḋ", "ḋ", 7690, nil, 7690], + 7692 => [0, 0, "Ḍ", "Ḍ", nil, 7693, nil], + 7693 => [0, 0, "ḍ", "ḍ", 7692, nil, 7692], + 7694 => [0, 0, "Ḏ", "Ḏ", nil, 7695, nil], + 7695 => [0, 0, "ḏ", "ḏ", 7694, nil, 7694], + 7696 => [0, 0, "Ḑ", "Ḑ", nil, 7697, nil], + 7697 => [0, 0, "ḑ", "ḑ", 7696, nil, 7696], + 7698 => [0, 0, "Ḓ", "Ḓ", nil, 7699, nil], + 7699 => [0, 0, "ḓ", "ḓ", 7698, nil, 7698], + 7700 => [0, 0, "Ḕ", "Ḕ", nil, 7701, nil], + 7701 => [0, 0, "ḕ", "ḕ", 7700, nil, 7700], + 7702 => [0, 0, "Ḗ", "Ḗ", nil, 7703, nil], + 7703 => [0, 0, "ḗ", "ḗ", 7702, nil, 7702], + 7704 => [0, 0, "Ḙ", "Ḙ", nil, 7705, nil], + 7705 => [0, 0, "ḙ", "ḙ", 7704, nil, 7704], + 7706 => [0, 0, "Ḛ", "Ḛ", nil, 7707, nil], + 7707 => [0, 0, "ḛ", "ḛ", 7706, nil, 7706], + 7708 => [0, 0, "Ḝ", "Ḝ", nil, 7709, nil], + 7709 => [0, 0, "ḝ", "ḝ", 7708, nil, 7708], + 7710 => [0, 0, "Ḟ", "Ḟ", nil, 7711, nil], + 7711 => [0, 0, "ḟ", "ḟ", 7710, nil, 7710], + 7712 => [0, 0, "Ḡ", "Ḡ", nil, 7713, nil], + 7713 => [0, 0, "ḡ", "ḡ", 7712, nil, 7712], + 7714 => [0, 0, "Ḣ", "Ḣ", nil, 7715, nil], + 7715 => [0, 0, "ḣ", "ḣ", 7714, nil, 7714], + 7716 => [0, 0, "Ḥ", "Ḥ", nil, 7717, nil], + 7717 => [0, 0, "ḥ", "ḥ", 7716, nil, 7716], + 7718 => [0, 0, "Ḧ", "Ḧ", nil, 7719, nil], + 7719 => [0, 0, "ḧ", "ḧ", 7718, nil, 7718], + 7720 => [0, 0, "Ḩ", "Ḩ", nil, 7721, nil], + 7721 => [0, 0, "ḩ", "ḩ", 7720, nil, 7720], + 7722 => [0, 0, "Ḫ", "Ḫ", nil, 7723, nil], + 7723 => [0, 0, "ḫ", "ḫ", 7722, nil, 7722], + 7724 => [0, 0, "Ḭ", "Ḭ", nil, 7725, nil], + 7725 => [0, 0, "ḭ", "ḭ", 7724, nil, 7724], + 7726 => [0, 0, "Ḯ", "Ḯ", nil, 7727, nil], + 7727 => [0, 0, "ḯ", "ḯ", 7726, nil, 7726], + 7728 => [0, 0, "Ḱ", "Ḱ", nil, 7729, nil], + 7729 => [0, 0, "ḱ", "ḱ", 7728, nil, 7728], + 7730 => [0, 0, "Ḳ", "Ḳ", nil, 7731, nil], + 7731 => [0, 0, "ḳ", "ḳ", 7730, nil, 7730], + 7732 => [0, 0, "Ḵ", "Ḵ", nil, 7733, nil], + 7733 => [0, 0, "ḵ", "ḵ", 7732, nil, 7732], + 7734 => [0, 0, "Ḷ", "Ḷ", nil, 7735, nil], + 7735 => [0, 0, "ḷ", "ḷ", 7734, nil, 7734], + 7736 => [0, 0, "Ḹ", "Ḹ", nil, 7737, nil], + 7737 => [0, 0, "ḹ", "ḹ", 7736, nil, 7736], + 7738 => [0, 0, "Ḻ", "Ḻ", nil, 7739, nil], + 7739 => [0, 0, "ḻ", "ḻ", 7738, nil, 7738], + 7740 => [0, 0, "Ḽ", "Ḽ", nil, 7741, nil], + 7741 => [0, 0, "ḽ", "ḽ", 7740, nil, 7740], + 7742 => [0, 0, "Ḿ", "Ḿ", nil, 7743, nil], + 7743 => [0, 0, "ḿ", "ḿ", 7742, nil, 7742], + 7744 => [0, 0, "Ṁ", "Ṁ", nil, 7745, nil], + 7745 => [0, 0, "ṁ", "ṁ", 7744, nil, 7744], + 7746 => [0, 0, "Ṃ", "Ṃ", nil, 7747, nil], + 7747 => [0, 0, "ṃ", "ṃ", 7746, nil, 7746], + 7748 => [0, 0, "Ṅ", "Ṅ", nil, 7749, nil], + 7749 => [0, 0, "ṅ", "ṅ", 7748, nil, 7748], + 7750 => [0, 0, "Ṇ", "Ṇ", nil, 7751, nil], + 7751 => [0, 0, "ṇ", "ṇ", 7750, nil, 7750], + 7752 => [0, 0, "Ṉ", "Ṉ", nil, 7753, nil], + 7753 => [0, 0, "ṉ", "ṉ", 7752, nil, 7752], + 7754 => [0, 0, "Ṋ", "Ṋ", nil, 7755, nil], + 7755 => [0, 0, "ṋ", "ṋ", 7754, nil, 7754], + 7756 => [0, 0, "Ṍ", "Ṍ", nil, 7757, nil], + 7757 => [0, 0, "ṍ", "ṍ", 7756, nil, 7756], + 7758 => [0, 0, "Ṏ", "Ṏ", nil, 7759, nil], + 7759 => [0, 0, "ṏ", "ṏ", 7758, nil, 7758], + 7760 => [0, 0, "Ṑ", "Ṑ", nil, 7761, nil], + 7761 => [0, 0, "ṑ", "ṑ", 7760, nil, 7760], + 7762 => [0, 0, "Ṓ", "Ṓ", nil, 7763, nil], + 7763 => [0, 0, "ṓ", "ṓ", 7762, nil, 7762], + 7764 => [0, 0, "Ṕ", "Ṕ", nil, 7765, nil], + 7765 => [0, 0, "ṕ", "ṕ", 7764, nil, 7764], + 7766 => [0, 0, "Ṗ", "Ṗ", nil, 7767, nil], + 7767 => [0, 0, "ṗ", "ṗ", 7766, nil, 7766], + 7768 => [0, 0, "Ṙ", "Ṙ", nil, 7769, nil], + 7769 => [0, 0, "ṙ", "ṙ", 7768, nil, 7768], + 7770 => [0, 0, "Ṛ", "Ṛ", nil, 7771, nil], + 7771 => [0, 0, "ṛ", "ṛ", 7770, nil, 7770], + 7772 => [0, 0, "Ṝ", "Ṝ", nil, 7773, nil], + 7773 => [0, 0, "ṝ", "ṝ", 7772, nil, 7772], + 7774 => [0, 0, "Ṟ", "Ṟ", nil, 7775, nil], + 7775 => [0, 0, "ṟ", "ṟ", 7774, nil, 7774], + 7776 => [0, 0, "Ṡ", "Ṡ", nil, 7777, nil], + 7777 => [0, 0, "ṡ", "ṡ", 7776, nil, 7776], + 7778 => [0, 0, "Ṣ", "Ṣ", nil, 7779, nil], + 7779 => [0, 0, "ṣ", "ṣ", 7778, nil, 7778], + 7780 => [0, 0, "Ṥ", "Ṥ", nil, 7781, nil], + 7781 => [0, 0, "ṥ", "ṥ", 7780, nil, 7780], + 7782 => [0, 0, "Ṧ", "Ṧ", nil, 7783, nil], + 7783 => [0, 0, "ṧ", "ṧ", 7782, nil, 7782], + 7784 => [0, 0, "Ṩ", "Ṩ", nil, 7785, nil], + 7785 => [0, 0, "ṩ", "ṩ", 7784, nil, 7784], + 7786 => [0, 0, "Ṫ", "Ṫ", nil, 7787, nil], + 7787 => [0, 0, "ṫ", "ṫ", 7786, nil, 7786], + 7788 => [0, 0, "Ṭ", "Ṭ", nil, 7789, nil], + 7789 => [0, 0, "ṭ", "ṭ", 7788, nil, 7788], + 7790 => [0, 0, "Ṯ", "Ṯ", nil, 7791, nil], + 7791 => [0, 0, "ṯ", "ṯ", 7790, nil, 7790], + 7792 => [0, 0, "Ṱ", "Ṱ", nil, 7793, nil], + 7793 => [0, 0, "ṱ", "ṱ", 7792, nil, 7792], + 7794 => [0, 0, "Ṳ", "Ṳ", nil, 7795, nil], + 7795 => [0, 0, "ṳ", "ṳ", 7794, nil, 7794], + 7796 => [0, 0, "Ṵ", "Ṵ", nil, 7797, nil], + 7797 => [0, 0, "ṵ", "ṵ", 7796, nil, 7796], + 7798 => [0, 0, "Ṷ", "Ṷ", nil, 7799, nil], + 7799 => [0, 0, "ṷ", "ṷ", 7798, nil, 7798], + 7800 => [0, 0, "Ṹ", "Ṹ", nil, 7801, nil], + 7801 => [0, 0, "ṹ", "ṹ", 7800, nil, 7800], + 7802 => [0, 0, "Ṻ", "Ṻ", nil, 7803, nil], + 7803 => [0, 0, "ṻ", "ṻ", 7802, nil, 7802], + 7804 => [0, 0, "Ṽ", "Ṽ", nil, 7805, nil], + 7805 => [0, 0, "ṽ", "ṽ", 7804, nil, 7804], + 7806 => [0, 0, "Ṿ", "Ṿ", nil, 7807, nil], + 7807 => [0, 0, "ṿ", "ṿ", 7806, nil, 7806], + 7808 => [0, 0, "Ẁ", "Ẁ", nil, 7809, nil], + 7809 => [0, 0, "ẁ", "ẁ", 7808, nil, 7808], + 7810 => [0, 0, "Ẃ", "Ẃ", nil, 7811, nil], + 7811 => [0, 0, "ẃ", "ẃ", 7810, nil, 7810], + 7812 => [0, 0, "Ẅ", "Ẅ", nil, 7813, nil], + 7813 => [0, 0, "ẅ", "ẅ", 7812, nil, 7812], + 7814 => [0, 0, "Ẇ", "Ẇ", nil, 7815, nil], + 7815 => [0, 0, "ẇ", "ẇ", 7814, nil, 7814], + 7816 => [0, 0, "Ẉ", "Ẉ", nil, 7817, nil], + 7817 => [0, 0, "ẉ", "ẉ", 7816, nil, 7816], + 7818 => [0, 0, "Ẋ", "Ẋ", nil, 7819, nil], + 7819 => [0, 0, "ẋ", "ẋ", 7818, nil, 7818], + 7820 => [0, 0, "Ẍ", "Ẍ", nil, 7821, nil], + 7821 => [0, 0, "ẍ", "ẍ", 7820, nil, 7820], + 7822 => [0, 0, "Ẏ", "Ẏ", nil, 7823, nil], + 7823 => [0, 0, "ẏ", "ẏ", 7822, nil, 7822], + 7824 => [0, 0, "Ẑ", "Ẑ", nil, 7825, nil], + 7825 => [0, 0, "ẑ", "ẑ", 7824, nil, 7824], + 7826 => [0, 0, "Ẓ", "Ẓ", nil, 7827, nil], + 7827 => [0, 0, "ẓ", "ẓ", 7826, nil, 7826], + 7828 => [0, 0, "Ẕ", "Ẕ", nil, 7829, nil], + 7829 => [0, 0, "ẕ", "ẕ", 7828, nil, 7828], + 7830 => [0, 0, "ẖ", "ẖ", nil, nil, nil], + 7831 => [0, 0, "ẗ", "ẗ", nil, nil, nil], + 7832 => [0, 0, "ẘ", "ẘ", nil, nil, nil], + 7833 => [0, 0, "ẙ", "ẙ", nil, nil, nil], + 7834 => [0, 0, nil, "aʾ", nil, nil, nil], + 7835 => [0, 0, "ẛ", "ẛ", 7776, nil, 7776], + 7840 => [0, 0, "Ạ", "Ạ", nil, 7841, nil], + 7841 => [0, 0, "ạ", "ạ", 7840, nil, 7840], + 7842 => [0, 0, "Ả", "Ả", nil, 7843, nil], + 7843 => [0, 0, "ả", "ả", 7842, nil, 7842], + 7844 => [0, 0, "Ấ", "Ấ", nil, 7845, nil], + 7845 => [0, 0, "ấ", "ấ", 7844, nil, 7844], + 7846 => [0, 0, "Ầ", "Ầ", nil, 7847, nil], + 7847 => [0, 0, "ầ", "ầ", 7846, nil, 7846], + 7848 => [0, 0, "Ẩ", "Ẩ", nil, 7849, nil], + 7849 => [0, 0, "ẩ", "ẩ", 7848, nil, 7848], + 7850 => [0, 0, "Ẫ", "Ẫ", nil, 7851, nil], + 7851 => [0, 0, "ẫ", "ẫ", 7850, nil, 7850], + 7852 => [0, 0, "Ậ", "Ậ", nil, 7853, nil], + 7853 => [0, 0, "ậ", "ậ", 7852, nil, 7852], + 7854 => [0, 0, "Ắ", "Ắ", nil, 7855, nil], + 7855 => [0, 0, "ắ", "ắ", 7854, nil, 7854], + 7856 => [0, 0, "Ằ", "Ằ", nil, 7857, nil], + 7857 => [0, 0, "ằ", "ằ", 7856, nil, 7856], + 7858 => [0, 0, "Ẳ", "Ẳ", nil, 7859, nil], + 7859 => [0, 0, "ẳ", "ẳ", 7858, nil, 7858], + 7860 => [0, 0, "Ẵ", "Ẵ", nil, 7861, nil], + 7861 => [0, 0, "ẵ", "ẵ", 7860, nil, 7860], + 7862 => [0, 0, "Ặ", "Ặ", nil, 7863, nil], + 7863 => [0, 0, "ặ", "ặ", 7862, nil, 7862], + 7864 => [0, 0, "Ẹ", "Ẹ", nil, 7865, nil], + 7865 => [0, 0, "ẹ", "ẹ", 7864, nil, 7864], + 7866 => [0, 0, "Ẻ", "Ẻ", nil, 7867, nil], + 7867 => [0, 0, "ẻ", "ẻ", 7866, nil, 7866], + 7868 => [0, 0, "Ẽ", "Ẽ", nil, 7869, nil], + 7869 => [0, 0, "ẽ", "ẽ", 7868, nil, 7868], + 7870 => [0, 0, "Ế", "Ế", nil, 7871, nil], + 7871 => [0, 0, "ế", "ế", 7870, nil, 7870], + 7872 => [0, 0, "Ề", "Ề", nil, 7873, nil], + 7873 => [0, 0, "ề", "ề", 7872, nil, 7872], + 7874 => [0, 0, "Ể", "Ể", nil, 7875, nil], + 7875 => [0, 0, "ể", "ể", 7874, nil, 7874], + 7876 => [0, 0, "Ễ", "Ễ", nil, 7877, nil], + 7877 => [0, 0, "ễ", "ễ", 7876, nil, 7876], + 7878 => [0, 0, "Ệ", "Ệ", nil, 7879, nil], + 7879 => [0, 0, "ệ", "ệ", 7878, nil, 7878], + 7880 => [0, 0, "Ỉ", "Ỉ", nil, 7881, nil], + 7881 => [0, 0, "ỉ", "ỉ", 7880, nil, 7880], + 7882 => [0, 0, "Ị", "Ị", nil, 7883, nil], + 7883 => [0, 0, "ị", "ị", 7882, nil, 7882], + 7884 => [0, 0, "Ọ", "Ọ", nil, 7885, nil], + 7885 => [0, 0, "ọ", "ọ", 7884, nil, 7884], + 7886 => [0, 0, "Ỏ", "Ỏ", nil, 7887, nil], + 7887 => [0, 0, "ỏ", "ỏ", 7886, nil, 7886], + 7888 => [0, 0, "Ố", "Ố", nil, 7889, nil], + 7889 => [0, 0, "ố", "ố", 7888, nil, 7888], + 7890 => [0, 0, "Ồ", "Ồ", nil, 7891, nil], + 7891 => [0, 0, "ồ", "ồ", 7890, nil, 7890], + 7892 => [0, 0, "Ổ", "Ổ", nil, 7893, nil], + 7893 => [0, 0, "ổ", "ổ", 7892, nil, 7892], + 7894 => [0, 0, "Ỗ", "Ỗ", nil, 7895, nil], + 7895 => [0, 0, "ỗ", "ỗ", 7894, nil, 7894], + 7896 => [0, 0, "Ộ", "Ộ", nil, 7897, nil], + 7897 => [0, 0, "ộ", "ộ", 7896, nil, 7896], + 7898 => [0, 0, "Ớ", "Ớ", nil, 7899, nil], + 7899 => [0, 0, "ớ", "ớ", 7898, nil, 7898], + 7900 => [0, 0, "Ờ", "Ờ", nil, 7901, nil], + 7901 => [0, 0, "ờ", "ờ", 7900, nil, 7900], + 7902 => [0, 0, "Ở", "Ở", nil, 7903, nil], + 7903 => [0, 0, "ở", "ở", 7902, nil, 7902], + 7904 => [0, 0, "Ỡ", "Ỡ", nil, 7905, nil], + 7905 => [0, 0, "ỡ", "ỡ", 7904, nil, 7904], + 7906 => [0, 0, "Ợ", "Ợ", nil, 7907, nil], + 7907 => [0, 0, "ợ", "ợ", 7906, nil, 7906], + 7908 => [0, 0, "Ụ", "Ụ", nil, 7909, nil], + 7909 => [0, 0, "ụ", "ụ", 7908, nil, 7908], + 7910 => [0, 0, "Ủ", "Ủ", nil, 7911, nil], + 7911 => [0, 0, "ủ", "ủ", 7910, nil, 7910], + 7912 => [0, 0, "Ứ", "Ứ", nil, 7913, nil], + 7913 => [0, 0, "ứ", "ứ", 7912, nil, 7912], + 7914 => [0, 0, "Ừ", "Ừ", nil, 7915, nil], + 7915 => [0, 0, "ừ", "ừ", 7914, nil, 7914], + 7916 => [0, 0, "Ử", "Ử", nil, 7917, nil], + 7917 => [0, 0, "ử", "ử", 7916, nil, 7916], + 7918 => [0, 0, "Ữ", "Ữ", nil, 7919, nil], + 7919 => [0, 0, "ữ", "ữ", 7918, nil, 7918], + 7920 => [0, 0, "Ự", "Ự", nil, 7921, nil], + 7921 => [0, 0, "ự", "ự", 7920, nil, 7920], + 7922 => [0, 0, "Ỳ", "Ỳ", nil, 7923, nil], + 7923 => [0, 0, "ỳ", "ỳ", 7922, nil, 7922], + 7924 => [0, 0, "Ỵ", "Ỵ", nil, 7925, nil], + 7925 => [0, 0, "ỵ", "ỵ", 7924, nil, 7924], + 7926 => [0, 0, "Ỷ", "Ỷ", nil, 7927, nil], + 7927 => [0, 0, "ỷ", "ỷ", 7926, nil, 7926], + 7928 => [0, 0, "Ỹ", "Ỹ", nil, 7929, nil], + 7929 => [0, 0, "ỹ", "ỹ", 7928, nil, 7928], + 7936 => [0, 0, "ἀ", "ἀ", 7944, nil, 7944], + 7937 => [0, 0, "ἁ", "ἁ", 7945, nil, 7945], + 7938 => [0, 0, "ἂ", "ἂ", 7946, nil, 7946], + 7939 => [0, 0, "ἃ", "ἃ", 7947, nil, 7947], + 7940 => [0, 0, "ἄ", "ἄ", 7948, nil, 7948], + 7941 => [0, 0, "ἅ", "ἅ", 7949, nil, 7949], + 7942 => [0, 0, "ἆ", "ἆ", 7950, nil, 7950], + 7943 => [0, 0, "ἇ", "ἇ", 7951, nil, 7951], + 7944 => [0, 0, "Ἀ", "Ἀ", nil, 7936, nil], + 7945 => [0, 0, "Ἁ", "Ἁ", nil, 7937, nil], + 7946 => [0, 0, "Ἂ", "Ἂ", nil, 7938, nil], + 7947 => [0, 0, "Ἃ", "Ἃ", nil, 7939, nil], + 7948 => [0, 0, "Ἄ", "Ἄ", nil, 7940, nil], + 7949 => [0, 0, "Ἅ", "Ἅ", nil, 7941, nil], + 7950 => [0, 0, "Ἆ", "Ἆ", nil, 7942, nil], + 7951 => [0, 0, "Ἇ", "Ἇ", nil, 7943, nil], + 7952 => [0, 0, "ἐ", "ἐ", 7960, nil, 7960], + 7953 => [0, 0, "ἑ", "ἑ", 7961, nil, 7961], + 7954 => [0, 0, "ἒ", "ἒ", 7962, nil, 7962], + 7955 => [0, 0, "ἓ", "ἓ", 7963, nil, 7963], + 7956 => [0, 0, "ἔ", "ἔ", 7964, nil, 7964], + 7957 => [0, 0, "ἕ", "ἕ", 7965, nil, 7965], + 7960 => [0, 0, "Ἐ", "Ἐ", nil, 7952, nil], + 7961 => [0, 0, "Ἑ", "Ἑ", nil, 7953, nil], + 7962 => [0, 0, "Ἒ", "Ἒ", nil, 7954, nil], + 7963 => [0, 0, "Ἓ", "Ἓ", nil, 7955, nil], + 7964 => [0, 0, "Ἔ", "Ἔ", nil, 7956, nil], + 7965 => [0, 0, "Ἕ", "Ἕ", nil, 7957, nil], + 7968 => [0, 0, "ἠ", "ἠ", 7976, nil, 7976], + 7969 => [0, 0, "ἡ", "ἡ", 7977, nil, 7977], + 7970 => [0, 0, "ἢ", "ἢ", 7978, nil, 7978], + 7971 => [0, 0, "ἣ", "ἣ", 7979, nil, 7979], + 7972 => [0, 0, "ἤ", "ἤ", 7980, nil, 7980], + 7973 => [0, 0, "ἥ", "ἥ", 7981, nil, 7981], + 7974 => [0, 0, "ἦ", "ἦ", 7982, nil, 7982], + 7975 => [0, 0, "ἧ", "ἧ", 7983, nil, 7983], + 7976 => [0, 0, "Ἠ", "Ἠ", nil, 7968, nil], + 7977 => [0, 0, "Ἡ", "Ἡ", nil, 7969, nil], + 7978 => [0, 0, "Ἢ", "Ἢ", nil, 7970, nil], + 7979 => [0, 0, "Ἣ", "Ἣ", nil, 7971, nil], + 7980 => [0, 0, "Ἤ", "Ἤ", nil, 7972, nil], + 7981 => [0, 0, "Ἥ", "Ἥ", nil, 7973, nil], + 7982 => [0, 0, "Ἦ", "Ἦ", nil, 7974, nil], + 7983 => [0, 0, "Ἧ", "Ἧ", nil, 7975, nil], + 7984 => [0, 0, "ἰ", "ἰ", 7992, nil, 7992], + 7985 => [0, 0, "ἱ", "ἱ", 7993, nil, 7993], + 7986 => [0, 0, "ἲ", "ἲ", 7994, nil, 7994], + 7987 => [0, 0, "ἳ", "ἳ", 7995, nil, 7995], + 7988 => [0, 0, "ἴ", "ἴ", 7996, nil, 7996], + 7989 => [0, 0, "ἵ", "ἵ", 7997, nil, 7997], + 7990 => [0, 0, "ἶ", "ἶ", 7998, nil, 7998], + 7991 => [0, 0, "ἷ", "ἷ", 7999, nil, 7999], + 7992 => [0, 0, "Ἰ", "Ἰ", nil, 7984, nil], + 7993 => [0, 0, "Ἱ", "Ἱ", nil, 7985, nil], + 7994 => [0, 0, "Ἲ", "Ἲ", nil, 7986, nil], + 7995 => [0, 0, "Ἳ", "Ἳ", nil, 7987, nil], + 7996 => [0, 0, "Ἴ", "Ἴ", nil, 7988, nil], + 7997 => [0, 0, "Ἵ", "Ἵ", nil, 7989, nil], + 7998 => [0, 0, "Ἶ", "Ἶ", nil, 7990, nil], + 7999 => [0, 0, "Ἷ", "Ἷ", nil, 7991, nil], + 8000 => [0, 0, "ὀ", "ὀ", 8008, nil, 8008], + 8001 => [0, 0, "ὁ", "ὁ", 8009, nil, 8009], + 8002 => [0, 0, "ὂ", "ὂ", 8010, nil, 8010], + 8003 => [0, 0, "ὃ", "ὃ", 8011, nil, 8011], + 8004 => [0, 0, "ὄ", "ὄ", 8012, nil, 8012], + 8005 => [0, 0, "ὅ", "ὅ", 8013, nil, 8013], + 8008 => [0, 0, "Ὀ", "Ὀ", nil, 8000, nil], + 8009 => [0, 0, "Ὁ", "Ὁ", nil, 8001, nil], + 8010 => [0, 0, "Ὂ", "Ὂ", nil, 8002, nil], + 8011 => [0, 0, "Ὃ", "Ὃ", nil, 8003, nil], + 8012 => [0, 0, "Ὄ", "Ὄ", nil, 8004, nil], + 8013 => [0, 0, "Ὅ", "Ὅ", nil, 8005, nil], + 8016 => [0, 0, "ὐ", "ὐ", nil, nil, nil], + 8017 => [0, 0, "ὑ", "ὑ", 8025, nil, 8025], + 8018 => [0, 0, "ὒ", "ὒ", nil, nil, nil], + 8019 => [0, 0, "ὓ", "ὓ", 8027, nil, 8027], + 8020 => [0, 0, "ὔ", "ὔ", nil, nil, nil], + 8021 => [0, 0, "ὕ", "ὕ", 8029, nil, 8029], + 8022 => [0, 0, "ὖ", "ὖ", nil, nil, nil], + 8023 => [0, 0, "ὗ", "ὗ", 8031, nil, 8031], + 8025 => [0, 0, "Ὑ", "Ὑ", nil, 8017, nil], + 8027 => [0, 0, "Ὓ", "Ὓ", nil, 8019, nil], + 8029 => [0, 0, "Ὕ", "Ὕ", nil, 8021, nil], + 8031 => [0, 0, "Ὗ", "Ὗ", nil, 8023, nil], + 8032 => [0, 0, "ὠ", "ὠ", 8040, nil, 8040], + 8033 => [0, 0, "ὡ", "ὡ", 8041, nil, 8041], + 8034 => [0, 0, "ὢ", "ὢ", 8042, nil, 8042], + 8035 => [0, 0, "ὣ", "ὣ", 8043, nil, 8043], + 8036 => [0, 0, "ὤ", "ὤ", 8044, nil, 8044], + 8037 => [0, 0, "ὥ", "ὥ", 8045, nil, 8045], + 8038 => [0, 0, "ὦ", "ὦ", 8046, nil, 8046], + 8039 => [0, 0, "ὧ", "ὧ", 8047, nil, 8047], + 8040 => [0, 0, "Ὠ", "Ὠ", nil, 8032, nil], + 8041 => [0, 0, "Ὡ", "Ὡ", nil, 8033, nil], + 8042 => [0, 0, "Ὢ", "Ὢ", nil, 8034, nil], + 8043 => [0, 0, "Ὣ", "Ὣ", nil, 8035, nil], + 8044 => [0, 0, "Ὤ", "Ὤ", nil, 8036, nil], + 8045 => [0, 0, "Ὥ", "Ὥ", nil, 8037, nil], + 8046 => [0, 0, "Ὦ", "Ὦ", nil, 8038, nil], + 8047 => [0, 0, "Ὧ", "Ὧ", nil, 8039, nil], + 8048 => [0, 0, "ὰ", "ὰ", 8122, nil, 8122], + 8049 => [0, 2, "ά", "ά", 8123, nil, 8123], + 8050 => [0, 0, "ὲ", "ὲ", 8136, nil, 8136], + 8051 => [0, 2, "έ", "έ", 8137, nil, 8137], + 8052 => [0, 0, "ὴ", "ὴ", 8138, nil, 8138], + 8053 => [0, 2, "ή", "ή", 8139, nil, 8139], + 8054 => [0, 0, "ὶ", "ὶ", 8154, nil, 8154], + 8055 => [0, 2, "ί", "ί", 8155, nil, 8155], + 8056 => [0, 0, "ὸ", "ὸ", 8184, nil, 8184], + 8057 => [0, 2, "ό", "ό", 8185, nil, 8185], + 8058 => [0, 0, "ὺ", "ὺ", 8170, nil, 8170], + 8059 => [0, 2, "ύ", "ύ", 8171, nil, 8171], + 8060 => [0, 0, "ὼ", "ὼ", 8186, nil, 8186], + 8061 => [0, 2, "ώ", "ώ", 8187, nil, 8187], + 8064 => [0, 0, "ᾀ", "ᾀ", 8072, nil, 8072], + 8065 => [0, 0, "ᾁ", "ᾁ", 8073, nil, 8073], + 8066 => [0, 0, "ᾂ", "ᾂ", 8074, nil, 8074], + 8067 => [0, 0, "ᾃ", "ᾃ", 8075, nil, 8075], + 8068 => [0, 0, "ᾄ", "ᾄ", 8076, nil, 8076], + 8069 => [0, 0, "ᾅ", "ᾅ", 8077, nil, 8077], + 8070 => [0, 0, "ᾆ", "ᾆ", 8078, nil, 8078], + 8071 => [0, 0, "ᾇ", "ᾇ", 8079, nil, 8079], + 8072 => [0, 0, "ᾈ", "ᾈ", nil, 8064, nil], + 8073 => [0, 0, "ᾉ", "ᾉ", nil, 8065, nil], + 8074 => [0, 0, "ᾊ", "ᾊ", nil, 8066, nil], + 8075 => [0, 0, "ᾋ", "ᾋ", nil, 8067, nil], + 8076 => [0, 0, "ᾌ", "ᾌ", nil, 8068, nil], + 8077 => [0, 0, "ᾍ", "ᾍ", nil, 8069, nil], + 8078 => [0, 0, "ᾎ", "ᾎ", nil, 8070, nil], + 8079 => [0, 0, "ᾏ", "ᾏ", nil, 8071, nil], + 8080 => [0, 0, "ᾐ", "ᾐ", 8088, nil, 8088], + 8081 => [0, 0, "ᾑ", "ᾑ", 8089, nil, 8089], + 8082 => [0, 0, "ᾒ", "ᾒ", 8090, nil, 8090], + 8083 => [0, 0, "ᾓ", "ᾓ", 8091, nil, 8091], + 8084 => [0, 0, "ᾔ", "ᾔ", 8092, nil, 8092], + 8085 => [0, 0, "ᾕ", "ᾕ", 8093, nil, 8093], + 8086 => [0, 0, "ᾖ", "ᾖ", 8094, nil, 8094], + 8087 => [0, 0, "ᾗ", "ᾗ", 8095, nil, 8095], + 8088 => [0, 0, "ᾘ", "ᾘ", nil, 8080, nil], + 8089 => [0, 0, "ᾙ", "ᾙ", nil, 8081, nil], + 8090 => [0, 0, "ᾚ", "ᾚ", nil, 8082, nil], + 8091 => [0, 0, "ᾛ", "ᾛ", nil, 8083, nil], + 8092 => [0, 0, "ᾜ", "ᾜ", nil, 8084, nil], + 8093 => [0, 0, "ᾝ", "ᾝ", nil, 8085, nil], + 8094 => [0, 0, "ᾞ", "ᾞ", nil, 8086, nil], + 8095 => [0, 0, "ᾟ", "ᾟ", nil, 8087, nil], + 8096 => [0, 0, "ᾠ", "ᾠ", 8104, nil, 8104], + 8097 => [0, 0, "ᾡ", "ᾡ", 8105, nil, 8105], + 8098 => [0, 0, "ᾢ", "ᾢ", 8106, nil, 8106], + 8099 => [0, 0, "ᾣ", "ᾣ", 8107, nil, 8107], + 8100 => [0, 0, "ᾤ", "ᾤ", 8108, nil, 8108], + 8101 => [0, 0, "ᾥ", "ᾥ", 8109, nil, 8109], + 8102 => [0, 0, "ᾦ", "ᾦ", 8110, nil, 8110], + 8103 => [0, 0, "ᾧ", "ᾧ", 8111, nil, 8111], + 8104 => [0, 0, "ᾨ", "ᾨ", nil, 8096, nil], + 8105 => [0, 0, "ᾩ", "ᾩ", nil, 8097, nil], + 8106 => [0, 0, "ᾪ", "ᾪ", nil, 8098, nil], + 8107 => [0, 0, "ᾫ", "ᾫ", nil, 8099, nil], + 8108 => [0, 0, "ᾬ", "ᾬ", nil, 8100, nil], + 8109 => [0, 0, "ᾭ", "ᾭ", nil, 8101, nil], + 8110 => [0, 0, "ᾮ", "ᾮ", nil, 8102, nil], + 8111 => [0, 0, "ᾯ", "ᾯ", nil, 8103, nil], + 8112 => [0, 0, "ᾰ", "ᾰ", 8120, nil, 8120], + 8113 => [0, 0, "ᾱ", "ᾱ", 8121, nil, 8121], + 8114 => [0, 0, "ᾲ", "ᾲ", nil, nil, nil], + 8115 => [0, 0, "ᾳ", "ᾳ", 8124, nil, 8124], + 8116 => [0, 0, "ᾴ", "ᾴ", nil, nil, nil], + 8118 => [0, 0, "ᾶ", "ᾶ", nil, nil, nil], + 8119 => [0, 0, "ᾷ", "ᾷ", nil, nil, nil], + 8120 => [0, 0, "Ᾰ", "Ᾰ", nil, 8112, nil], + 8121 => [0, 0, "Ᾱ", "Ᾱ", nil, 8113, nil], + 8122 => [0, 0, "Ὰ", "Ὰ", nil, 8048, nil], + 8123 => [0, 2, "Ά", "Ά", nil, 8049, nil], + 8124 => [0, 0, "ᾼ", "ᾼ", nil, 8115, nil], + 8125 => [0, 0, nil, " ̓", nil, nil, nil], + 8126 => [0, 2, "ι", "ι", 921, nil, 921], + 8127 => [0, 0, nil, " ̓", nil, nil, nil], + 8128 => [0, 0, nil, " ͂", nil, nil, nil], + 8129 => [0, 0, "῁", "῁", nil, nil, nil], + 8130 => [0, 0, "ῂ", "ῂ", nil, nil, nil], + 8131 => [0, 0, "ῃ", "ῃ", 8140, nil, 8140], + 8132 => [0, 0, "ῄ", "ῄ", nil, nil, nil], + 8134 => [0, 0, "ῆ", "ῆ", nil, nil, nil], + 8135 => [0, 0, "ῇ", "ῇ", nil, nil, nil], + 8136 => [0, 0, "Ὲ", "Ὲ", nil, 8050, nil], + 8137 => [0, 2, "Έ", "Έ", nil, 8051, nil], + 8138 => [0, 0, "Ὴ", "Ὴ", nil, 8052, nil], + 8139 => [0, 2, "Ή", "Ή", nil, 8053, nil], + 8140 => [0, 0, "ῌ", "ῌ", nil, 8131, nil], + 8141 => [0, 0, "῍", "῍", nil, nil, nil], + 8142 => [0, 0, "῎", "῎", nil, nil, nil], + 8143 => [0, 0, "῏", "῏", nil, nil, nil], + 8144 => [0, 0, "ῐ", "ῐ", 8152, nil, 8152], + 8145 => [0, 0, "ῑ", "ῑ", 8153, nil, 8153], + 8146 => [0, 0, "ῒ", "ῒ", nil, nil, nil], + 8147 => [0, 2, "ΐ", "ΐ", nil, nil, nil], + 8150 => [0, 0, "ῖ", "ῖ", nil, nil, nil], + 8151 => [0, 0, "ῗ", "ῗ", nil, nil, nil], + 8152 => [0, 0, "Ῐ", "Ῐ", nil, 8144, nil], + 8153 => [0, 0, "Ῑ", "Ῑ", nil, 8145, nil], + 8154 => [0, 0, "Ὶ", "Ὶ", nil, 8054, nil], + 8155 => [0, 2, "Ί", "Ί", nil, 8055, nil], + 8157 => [0, 0, "῝", "῝", nil, nil, nil], + 8158 => [0, 0, "῞", "῞", nil, nil, nil], + 8159 => [0, 0, "῟", "῟", nil, nil, nil], + 8160 => [0, 0, "ῠ", "ῠ", 8168, nil, 8168], + 8161 => [0, 0, "ῡ", "ῡ", 8169, nil, 8169], + 8162 => [0, 0, "ῢ", "ῢ", nil, nil, nil], + 8163 => [0, 2, "ΰ", "ΰ", nil, nil, nil], + 8164 => [0, 0, "ῤ", "ῤ", nil, nil, nil], + 8165 => [0, 0, "ῥ", "ῥ", 8172, nil, 8172], + 8166 => [0, 0, "ῦ", "ῦ", nil, nil, nil], + 8167 => [0, 0, "ῧ", "ῧ", nil, nil, nil], + 8168 => [0, 0, "Ῠ", "Ῠ", nil, 8160, nil], + 8169 => [0, 0, "Ῡ", "Ῡ", nil, 8161, nil], + 8170 => [0, 0, "Ὺ", "Ὺ", nil, 8058, nil], + 8171 => [0, 2, "Ύ", "Ύ", nil, 8059, nil], + 8172 => [0, 0, "Ῥ", "Ῥ", nil, 8165, nil], + 8173 => [0, 0, "῭", "῭", nil, nil, nil], + 8174 => [0, 2, "΅", "΅", nil, nil, nil], + 8175 => [0, 2, "`", "`", nil, nil, nil], + 8178 => [0, 0, "ῲ", "ῲ", nil, nil, nil], + 8179 => [0, 0, "ῳ", "ῳ", 8188, nil, 8188], + 8180 => [0, 0, "ῴ", "ῴ", nil, nil, nil], + 8182 => [0, 0, "ῶ", "ῶ", nil, nil, nil], + 8183 => [0, 0, "ῷ", "ῷ", nil, nil, nil], + 8184 => [0, 0, "Ὸ", "Ὸ", nil, 8056, nil], + 8185 => [0, 2, "Ό", "Ό", nil, 8057, nil], + 8186 => [0, 0, "Ὼ", "Ὼ", nil, 8060, nil], + 8187 => [0, 2, "Ώ", "Ώ", nil, 8061, nil], + 8188 => [0, 0, "ῼ", "ῼ", nil, 8179, nil], + 8189 => [0, 2, "´", "´", nil, nil, nil], + 8190 => [0, 0, nil, " ̔", nil, nil, nil], + 8192 => [0, 2, " ", " ", nil, nil, nil], + 8193 => [0, 2, " ", " ", nil, nil, nil], + 8194 => [0, 0, nil, " ", nil, nil, nil], + 8195 => [0, 0, nil, " ", nil, nil, nil], + 8196 => [0, 0, nil, " ", nil, nil, nil], + 8197 => [0, 0, nil, " ", nil, nil, nil], + 8198 => [0, 0, nil, " ", nil, nil, nil], + 8199 => [0, 0, nil, " ", nil, nil, nil], + 8200 => [0, 0, nil, " ", nil, nil, nil], + 8201 => [0, 0, nil, " ", nil, nil, nil], + 8202 => [0, 0, nil, " ", nil, nil, nil], + 8209 => [0, 0, nil, "‐", nil, nil, nil], + 8215 => [0, 0, nil, " ̳", nil, nil, nil], + 8228 => [0, 0, nil, ".", nil, nil, nil], + 8229 => [0, 0, nil, "..", nil, nil, nil], + 8230 => [0, 0, nil, "...", nil, nil, nil], + 8239 => [0, 0, nil, " ", nil, nil, nil], + 8243 => [0, 0, nil, "′′", nil, nil, nil], + 8244 => [0, 0, nil, "′′′", nil, nil, nil], + 8246 => [0, 0, nil, "‵‵", nil, nil, nil], + 8247 => [0, 0, nil, "‵‵‵", nil, nil, nil], + 8252 => [0, 0, nil, "!!", nil, nil, nil], + 8254 => [0, 0, nil, " ̅", nil, nil, nil], + 8264 => [0, 0, nil, "?!", nil, nil, nil], + 8265 => [0, 0, nil, "!?", nil, nil, nil], + 8304 => [0, 0, nil, "0", nil, nil, nil], + 8308 => [0, 0, nil, "4", nil, nil, nil], + 8309 => [0, 0, nil, "5", nil, nil, nil], + 8310 => [0, 0, nil, "6", nil, nil, nil], + 8311 => [0, 0, nil, "7", nil, nil, nil], + 8312 => [0, 0, nil, "8", nil, nil, nil], + 8313 => [0, 0, nil, "9", nil, nil, nil], + 8314 => [0, 0, nil, "+", nil, nil, nil], + 8315 => [0, 0, nil, "−", nil, nil, nil], + 8316 => [0, 0, nil, "=", nil, nil, nil], + 8317 => [0, 0, nil, "(", nil, nil, nil], + 8318 => [0, 0, nil, ")", nil, nil, nil], + 8319 => [0, 0, nil, "n", nil, nil, nil], + 8320 => [0, 0, nil, "0", nil, nil, nil], + 8321 => [0, 0, nil, "1", nil, nil, nil], + 8322 => [0, 0, nil, "2", nil, nil, nil], + 8323 => [0, 0, nil, "3", nil, nil, nil], + 8324 => [0, 0, nil, "4", nil, nil, nil], + 8325 => [0, 0, nil, "5", nil, nil, nil], + 8326 => [0, 0, nil, "6", nil, nil, nil], + 8327 => [0, 0, nil, "7", nil, nil, nil], + 8328 => [0, 0, nil, "8", nil, nil, nil], + 8329 => [0, 0, nil, "9", nil, nil, nil], + 8330 => [0, 0, nil, "+", nil, nil, nil], + 8331 => [0, 0, nil, "−", nil, nil, nil], + 8332 => [0, 0, nil, "=", nil, nil, nil], + 8333 => [0, 0, nil, "(", nil, nil, nil], + 8334 => [0, 0, nil, ")", nil, nil, nil], + 8360 => [0, 0, nil, "Rs", nil, nil, nil], + 8400 => [230, 0, nil, nil, nil, nil, nil], + 8401 => [230, 0, nil, nil, nil, nil, nil], + 8402 => [1, 0, nil, nil, nil, nil, nil], + 8403 => [1, 0, nil, nil, nil, nil, nil], + 8404 => [230, 0, nil, nil, nil, nil, nil], + 8405 => [230, 0, nil, nil, nil, nil, nil], + 8406 => [230, 0, nil, nil, nil, nil, nil], + 8407 => [230, 0, nil, nil, nil, nil, nil], + 8408 => [1, 0, nil, nil, nil, nil, nil], + 8409 => [1, 0, nil, nil, nil, nil, nil], + 8410 => [1, 0, nil, nil, nil, nil, nil], + 8411 => [230, 0, nil, nil, nil, nil, nil], + 8412 => [230, 0, nil, nil, nil, nil, nil], + 8417 => [230, 0, nil, nil, nil, nil, nil], + 8448 => [0, 0, nil, "a/c", nil, nil, nil], + 8449 => [0, 0, nil, "a/s", nil, nil, nil], + 8450 => [0, 0, nil, "C", nil, nil, nil], + 8451 => [0, 0, nil, "°C", nil, nil, nil], + 8453 => [0, 0, nil, "c/o", nil, nil, nil], + 8454 => [0, 0, nil, "c/u", nil, nil, nil], + 8455 => [0, 0, nil, "Ɛ", nil, nil, nil], + 8457 => [0, 0, nil, "°F", nil, nil, nil], + 8458 => [0, 0, nil, "g", nil, nil, nil], + 8459 => [0, 0, nil, "H", nil, nil, nil], + 8460 => [0, 0, nil, "H", nil, nil, nil], + 8461 => [0, 0, nil, "H", nil, nil, nil], + 8462 => [0, 0, nil, "h", nil, nil, nil], + 8463 => [0, 0, nil, "ħ", nil, nil, nil], + 8464 => [0, 0, nil, "I", nil, nil, nil], + 8465 => [0, 0, nil, "I", nil, nil, nil], + 8466 => [0, 0, nil, "L", nil, nil, nil], + 8467 => [0, 0, nil, "l", nil, nil, nil], + 8469 => [0, 0, nil, "N", nil, nil, nil], + 8470 => [0, 0, nil, "No", nil, nil, nil], + 8473 => [0, 0, nil, "P", nil, nil, nil], + 8474 => [0, 0, nil, "Q", nil, nil, nil], + 8475 => [0, 0, nil, "R", nil, nil, nil], + 8476 => [0, 0, nil, "R", nil, nil, nil], + 8477 => [0, 0, nil, "R", nil, nil, nil], + 8480 => [0, 0, nil, "SM", nil, nil, nil], + 8481 => [0, 0, nil, "TEL", nil, nil, nil], + 8482 => [0, 0, nil, "TM", nil, nil, nil], + 8484 => [0, 0, nil, "Z", nil, nil, nil], + 8486 => [0, 2, "Ω", "Ω", nil, 969, nil], + 8488 => [0, 0, nil, "Z", nil, nil, nil], + 8490 => [0, 2, "K", "K", nil, 107, nil], + 8491 => [0, 2, "Å", "Å", nil, 229, nil], + 8492 => [0, 0, nil, "B", nil, nil, nil], + 8493 => [0, 0, nil, "C", nil, nil, nil], + 8495 => [0, 0, nil, "e", nil, nil, nil], + 8496 => [0, 0, nil, "E", nil, nil, nil], + 8497 => [0, 0, nil, "F", nil, nil, nil], + 8499 => [0, 0, nil, "M", nil, nil, nil], + 8500 => [0, 0, nil, "o", nil, nil, nil], + 8501 => [0, 0, nil, "א", nil, nil, nil], + 8502 => [0, 0, nil, "ב", nil, nil, nil], + 8503 => [0, 0, nil, "ג", nil, nil, nil], + 8504 => [0, 0, nil, "ד", nil, nil, nil], + 8505 => [0, 0, nil, "i", nil, nil, nil], + 8531 => [0, 0, nil, "1⁄3", nil, nil, nil], + 8532 => [0, 0, nil, "2⁄3", nil, nil, nil], + 8533 => [0, 0, nil, "1⁄5", nil, nil, nil], + 8534 => [0, 0, nil, "2⁄5", nil, nil, nil], + 8535 => [0, 0, nil, "3⁄5", nil, nil, nil], + 8536 => [0, 0, nil, "4⁄5", nil, nil, nil], + 8537 => [0, 0, nil, "1⁄6", nil, nil, nil], + 8538 => [0, 0, nil, "5⁄6", nil, nil, nil], + 8539 => [0, 0, nil, "1⁄8", nil, nil, nil], + 8540 => [0, 0, nil, "3⁄8", nil, nil, nil], + 8541 => [0, 0, nil, "5⁄8", nil, nil, nil], + 8542 => [0, 0, nil, "7⁄8", nil, nil, nil], + 8543 => [0, 0, nil, "1⁄", nil, nil, nil], + 8544 => [0, 0, nil, "I", nil, 8560, nil], + 8545 => [0, 0, nil, "II", nil, 8561, nil], + 8546 => [0, 0, nil, "III", nil, 8562, nil], + 8547 => [0, 0, nil, "IV", nil, 8563, nil], + 8548 => [0, 0, nil, "V", nil, 8564, nil], + 8549 => [0, 0, nil, "VI", nil, 8565, nil], + 8550 => [0, 0, nil, "VII", nil, 8566, nil], + 8551 => [0, 0, nil, "VIII", nil, 8567, nil], + 8552 => [0, 0, nil, "IX", nil, 8568, nil], + 8553 => [0, 0, nil, "X", nil, 8569, nil], + 8554 => [0, 0, nil, "XI", nil, 8570, nil], + 8555 => [0, 0, nil, "XII", nil, 8571, nil], + 8556 => [0, 0, nil, "L", nil, 8572, nil], + 8557 => [0, 0, nil, "C", nil, 8573, nil], + 8558 => [0, 0, nil, "D", nil, 8574, nil], + 8559 => [0, 0, nil, "M", nil, 8575, nil], + 8560 => [0, 0, nil, "i", 8544, nil, 8544], + 8561 => [0, 0, nil, "ii", 8545, nil, 8545], + 8562 => [0, 0, nil, "iii", 8546, nil, 8546], + 8563 => [0, 0, nil, "iv", 8547, nil, 8547], + 8564 => [0, 0, nil, "v", 8548, nil, 8548], + 8565 => [0, 0, nil, "vi", 8549, nil, 8549], + 8566 => [0, 0, nil, "vii", 8550, nil, 8550], + 8567 => [0, 0, nil, "viii", 8551, nil, 8551], + 8568 => [0, 0, nil, "ix", 8552, nil, 8552], + 8569 => [0, 0, nil, "x", 8553, nil, 8553], + 8570 => [0, 0, nil, "xi", 8554, nil, 8554], + 8571 => [0, 0, nil, "xii", 8555, nil, 8555], + 8572 => [0, 0, nil, "l", 8556, nil, 8556], + 8573 => [0, 0, nil, "c", 8557, nil, 8557], + 8574 => [0, 0, nil, "d", 8558, nil, 8558], + 8575 => [0, 0, nil, "m", 8559, nil, 8559], + 8602 => [0, 0, "↚", "↚", nil, nil, nil], + 8603 => [0, 0, "↛", "↛", nil, nil, nil], + 8622 => [0, 0, "↮", "↮", nil, nil, nil], + 8653 => [0, 0, "⇍", "⇍", nil, nil, nil], + 8654 => [0, 0, "⇎", "⇎", nil, nil, nil], + 8655 => [0, 0, "⇏", "⇏", nil, nil, nil], + 8708 => [0, 0, "∄", "∄", nil, nil, nil], + 8713 => [0, 0, "∉", "∉", nil, nil, nil], + 8716 => [0, 0, "∌", "∌", nil, nil, nil], + 8740 => [0, 0, "∤", "∤", nil, nil, nil], + 8742 => [0, 0, "∦", "∦", nil, nil, nil], + 8748 => [0, 0, nil, "∫∫", nil, nil, nil], + 8749 => [0, 0, nil, "∫∫∫", nil, nil, nil], + 8751 => [0, 0, nil, "∮∮", nil, nil, nil], + 8752 => [0, 0, nil, "∮∮∮", nil, nil, nil], + 8769 => [0, 0, "≁", "≁", nil, nil, nil], + 8772 => [0, 0, "≄", "≄", nil, nil, nil], + 8775 => [0, 0, "≇", "≇", nil, nil, nil], + 8777 => [0, 0, "≉", "≉", nil, nil, nil], + 8800 => [0, 0, "≠", "≠", nil, nil, nil], + 8802 => [0, 0, "≢", "≢", nil, nil, nil], + 8813 => [0, 0, "≭", "≭", nil, nil, nil], + 8814 => [0, 0, "≮", "≮", nil, nil, nil], + 8815 => [0, 0, "≯", "≯", nil, nil, nil], + 8816 => [0, 0, "≰", "≰", nil, nil, nil], + 8817 => [0, 0, "≱", "≱", nil, nil, nil], + 8820 => [0, 0, "≴", "≴", nil, nil, nil], + 8821 => [0, 0, "≵", "≵", nil, nil, nil], + 8824 => [0, 0, "≸", "≸", nil, nil, nil], + 8825 => [0, 0, "≹", "≹", nil, nil, nil], + 8832 => [0, 0, "⊀", "⊀", nil, nil, nil], + 8833 => [0, 0, "⊁", "⊁", nil, nil, nil], + 8836 => [0, 0, "⊄", "⊄", nil, nil, nil], + 8837 => [0, 0, "⊅", "⊅", nil, nil, nil], + 8840 => [0, 0, "⊈", "⊈", nil, nil, nil], + 8841 => [0, 0, "⊉", "⊉", nil, nil, nil], + 8876 => [0, 0, "⊬", "⊬", nil, nil, nil], + 8877 => [0, 0, "⊭", "⊭", nil, nil, nil], + 8878 => [0, 0, "⊮", "⊮", nil, nil, nil], + 8879 => [0, 0, "⊯", "⊯", nil, nil, nil], + 8928 => [0, 0, "⋠", "⋠", nil, nil, nil], + 8929 => [0, 0, "⋡", "⋡", nil, nil, nil], + 8930 => [0, 0, "⋢", "⋢", nil, nil, nil], + 8931 => [0, 0, "⋣", "⋣", nil, nil, nil], + 8938 => [0, 0, "⋪", "⋪", nil, nil, nil], + 8939 => [0, 0, "⋫", "⋫", nil, nil, nil], + 8940 => [0, 0, "⋬", "⋬", nil, nil, nil], + 8941 => [0, 0, "⋭", "⋭", nil, nil, nil], + 9001 => [0, 2, "〈", "〈", nil, nil, nil], + 9002 => [0, 2, "〉", "〉", nil, nil, nil], + 9312 => [0, 0, nil, "1", nil, nil, nil], + 9313 => [0, 0, nil, "2", nil, nil, nil], + 9314 => [0, 0, nil, "3", nil, nil, nil], + 9315 => [0, 0, nil, "4", nil, nil, nil], + 9316 => [0, 0, nil, "5", nil, nil, nil], + 9317 => [0, 0, nil, "6", nil, nil, nil], + 9318 => [0, 0, nil, "7", nil, nil, nil], + 9319 => [0, 0, nil, "8", nil, nil, nil], + 9320 => [0, 0, nil, "9", nil, nil, nil], + 9321 => [0, 0, nil, "10", nil, nil, nil], + 9322 => [0, 0, nil, "11", nil, nil, nil], + 9323 => [0, 0, nil, "12", nil, nil, nil], + 9324 => [0, 0, nil, "13", nil, nil, nil], + 9325 => [0, 0, nil, "14", nil, nil, nil], + 9326 => [0, 0, nil, "15", nil, nil, nil], + 9327 => [0, 0, nil, "16", nil, nil, nil], + 9328 => [0, 0, nil, "17", nil, nil, nil], + 9329 => [0, 0, nil, "18", nil, nil, nil], + 9330 => [0, 0, nil, "19", nil, nil, nil], + 9331 => [0, 0, nil, "20", nil, nil, nil], + 9332 => [0, 0, nil, "(1)", nil, nil, nil], + 9333 => [0, 0, nil, "(2)", nil, nil, nil], + 9334 => [0, 0, nil, "(3)", nil, nil, nil], + 9335 => [0, 0, nil, "(4)", nil, nil, nil], + 9336 => [0, 0, nil, "(5)", nil, nil, nil], + 9337 => [0, 0, nil, "(6)", nil, nil, nil], + 9338 => [0, 0, nil, "(7)", nil, nil, nil], + 9339 => [0, 0, nil, "(8)", nil, nil, nil], + 9340 => [0, 0, nil, "(9)", nil, nil, nil], + 9341 => [0, 0, nil, "(10)", nil, nil, nil], + 9342 => [0, 0, nil, "(11)", nil, nil, nil], + 9343 => [0, 0, nil, "(12)", nil, nil, nil], + 9344 => [0, 0, nil, "(13)", nil, nil, nil], + 9345 => [0, 0, nil, "(14)", nil, nil, nil], + 9346 => [0, 0, nil, "(15)", nil, nil, nil], + 9347 => [0, 0, nil, "(16)", nil, nil, nil], + 9348 => [0, 0, nil, "(17)", nil, nil, nil], + 9349 => [0, 0, nil, "(18)", nil, nil, nil], + 9350 => [0, 0, nil, "(19)", nil, nil, nil], + 9351 => [0, 0, nil, "(20)", nil, nil, nil], + 9352 => [0, 0, nil, "1.", nil, nil, nil], + 9353 => [0, 0, nil, "2.", nil, nil, nil], + 9354 => [0, 0, nil, "3.", nil, nil, nil], + 9355 => [0, 0, nil, "4.", nil, nil, nil], + 9356 => [0, 0, nil, "5.", nil, nil, nil], + 9357 => [0, 0, nil, "6.", nil, nil, nil], + 9358 => [0, 0, nil, "7.", nil, nil, nil], + 9359 => [0, 0, nil, "8.", nil, nil, nil], + 9360 => [0, 0, nil, "9.", nil, nil, nil], + 9361 => [0, 0, nil, "10.", nil, nil, nil], + 9362 => [0, 0, nil, "11.", nil, nil, nil], + 9363 => [0, 0, nil, "12.", nil, nil, nil], + 9364 => [0, 0, nil, "13.", nil, nil, nil], + 9365 => [0, 0, nil, "14.", nil, nil, nil], + 9366 => [0, 0, nil, "15.", nil, nil, nil], + 9367 => [0, 0, nil, "16.", nil, nil, nil], + 9368 => [0, 0, nil, "17.", nil, nil, nil], + 9369 => [0, 0, nil, "18.", nil, nil, nil], + 9370 => [0, 0, nil, "19.", nil, nil, nil], + 9371 => [0, 0, nil, "20.", nil, nil, nil], + 9372 => [0, 0, nil, "(a)", nil, nil, nil], + 9373 => [0, 0, nil, "(b)", nil, nil, nil], + 9374 => [0, 0, nil, "(c)", nil, nil, nil], + 9375 => [0, 0, nil, "(d)", nil, nil, nil], + 9376 => [0, 0, nil, "(e)", nil, nil, nil], + 9377 => [0, 0, nil, "(f)", nil, nil, nil], + 9378 => [0, 0, nil, "(g)", nil, nil, nil], + 9379 => [0, 0, nil, "(h)", nil, nil, nil], + 9380 => [0, 0, nil, "(i)", nil, nil, nil], + 9381 => [0, 0, nil, "(j)", nil, nil, nil], + 9382 => [0, 0, nil, "(k)", nil, nil, nil], + 9383 => [0, 0, nil, "(l)", nil, nil, nil], + 9384 => [0, 0, nil, "(m)", nil, nil, nil], + 9385 => [0, 0, nil, "(n)", nil, nil, nil], + 9386 => [0, 0, nil, "(o)", nil, nil, nil], + 9387 => [0, 0, nil, "(p)", nil, nil, nil], + 9388 => [0, 0, nil, "(q)", nil, nil, nil], + 9389 => [0, 0, nil, "(r)", nil, nil, nil], + 9390 => [0, 0, nil, "(s)", nil, nil, nil], + 9391 => [0, 0, nil, "(t)", nil, nil, nil], + 9392 => [0, 0, nil, "(u)", nil, nil, nil], + 9393 => [0, 0, nil, "(v)", nil, nil, nil], + 9394 => [0, 0, nil, "(w)", nil, nil, nil], + 9395 => [0, 0, nil, "(x)", nil, nil, nil], + 9396 => [0, 0, nil, "(y)", nil, nil, nil], + 9397 => [0, 0, nil, "(z)", nil, nil, nil], + 9398 => [0, 0, nil, "A", nil, 9424, nil], + 9399 => [0, 0, nil, "B", nil, 9425, nil], + 9400 => [0, 0, nil, "C", nil, 9426, nil], + 9401 => [0, 0, nil, "D", nil, 9427, nil], + 9402 => [0, 0, nil, "E", nil, 9428, nil], + 9403 => [0, 0, nil, "F", nil, 9429, nil], + 9404 => [0, 0, nil, "G", nil, 9430, nil], + 9405 => [0, 0, nil, "H", nil, 9431, nil], + 9406 => [0, 0, nil, "I", nil, 9432, nil], + 9407 => [0, 0, nil, "J", nil, 9433, nil], + 9408 => [0, 0, nil, "K", nil, 9434, nil], + 9409 => [0, 0, nil, "L", nil, 9435, nil], + 9410 => [0, 0, nil, "M", nil, 9436, nil], + 9411 => [0, 0, nil, "N", nil, 9437, nil], + 9412 => [0, 0, nil, "O", nil, 9438, nil], + 9413 => [0, 0, nil, "P", nil, 9439, nil], + 9414 => [0, 0, nil, "Q", nil, 9440, nil], + 9415 => [0, 0, nil, "R", nil, 9441, nil], + 9416 => [0, 0, nil, "S", nil, 9442, nil], + 9417 => [0, 0, nil, "T", nil, 9443, nil], + 9418 => [0, 0, nil, "U", nil, 9444, nil], + 9419 => [0, 0, nil, "V", nil, 9445, nil], + 9420 => [0, 0, nil, "W", nil, 9446, nil], + 9421 => [0, 0, nil, "X", nil, 9447, nil], + 9422 => [0, 0, nil, "Y", nil, 9448, nil], + 9423 => [0, 0, nil, "Z", nil, 9449, nil], + 9424 => [0, 0, nil, "a", 9398, nil, 9398], + 9425 => [0, 0, nil, "b", 9399, nil, 9399], + 9426 => [0, 0, nil, "c", 9400, nil, 9400], + 9427 => [0, 0, nil, "d", 9401, nil, 9401], + 9428 => [0, 0, nil, "e", 9402, nil, 9402], + 9429 => [0, 0, nil, "f", 9403, nil, 9403], + 9430 => [0, 0, nil, "g", 9404, nil, 9404], + 9431 => [0, 0, nil, "h", 9405, nil, 9405], + 9432 => [0, 0, nil, "i", 9406, nil, 9406], + 9433 => [0, 0, nil, "j", 9407, nil, 9407], + 9434 => [0, 0, nil, "k", 9408, nil, 9408], + 9435 => [0, 0, nil, "l", 9409, nil, 9409], + 9436 => [0, 0, nil, "m", 9410, nil, 9410], + 9437 => [0, 0, nil, "n", 9411, nil, 9411], + 9438 => [0, 0, nil, "o", 9412, nil, 9412], + 9439 => [0, 0, nil, "p", 9413, nil, 9413], + 9440 => [0, 0, nil, "q", 9414, nil, 9414], + 9441 => [0, 0, nil, "r", 9415, nil, 9415], + 9442 => [0, 0, nil, "s", 9416, nil, 9416], + 9443 => [0, 0, nil, "t", 9417, nil, 9417], + 9444 => [0, 0, nil, "u", 9418, nil, 9418], + 9445 => [0, 0, nil, "v", 9419, nil, 9419], + 9446 => [0, 0, nil, "w", 9420, nil, 9420], + 9447 => [0, 0, nil, "x", 9421, nil, 9421], + 9448 => [0, 0, nil, "y", 9422, nil, 9422], + 9449 => [0, 0, nil, "z", 9423, nil, 9423], + 9450 => [0, 0, nil, "0", nil, nil, nil], + 11935 => [0, 0, nil, "母", nil, nil, nil], + 12019 => [0, 0, nil, "龟", nil, nil, nil], + 12032 => [0, 0, nil, "一", nil, nil, nil], + 12033 => [0, 0, nil, "丨", nil, nil, nil], + 12034 => [0, 0, nil, "丶", nil, nil, nil], + 12035 => [0, 0, nil, "丿", nil, nil, nil], + 12036 => [0, 0, nil, "乙", nil, nil, nil], + 12037 => [0, 0, nil, "亅", nil, nil, nil], + 12038 => [0, 0, nil, "二", nil, nil, nil], + 12039 => [0, 0, nil, "亠", nil, nil, nil], + 12040 => [0, 0, nil, "人", nil, nil, nil], + 12041 => [0, 0, nil, "儿", nil, nil, nil], + 12042 => [0, 0, nil, "入", nil, nil, nil], + 12043 => [0, 0, nil, "八", nil, nil, nil], + 12044 => [0, 0, nil, "冂", nil, nil, nil], + 12045 => [0, 0, nil, "冖", nil, nil, nil], + 12046 => [0, 0, nil, "冫", nil, nil, nil], + 12047 => [0, 0, nil, "几", nil, nil, nil], + 12048 => [0, 0, nil, "凵", nil, nil, nil], + 12049 => [0, 0, nil, "刀", nil, nil, nil], + 12050 => [0, 0, nil, "力", nil, nil, nil], + 12051 => [0, 0, nil, "勹", nil, nil, nil], + 12052 => [0, 0, nil, "匕", nil, nil, nil], + 12053 => [0, 0, nil, "匚", nil, nil, nil], + 12054 => [0, 0, nil, "匸", nil, nil, nil], + 12055 => [0, 0, nil, "十", nil, nil, nil], + 12056 => [0, 0, nil, "卜", nil, nil, nil], + 12057 => [0, 0, nil, "卩", nil, nil, nil], + 12058 => [0, 0, nil, "厂", nil, nil, nil], + 12059 => [0, 0, nil, "厶", nil, nil, nil], + 12060 => [0, 0, nil, "又", nil, nil, nil], + 12061 => [0, 0, nil, "口", nil, nil, nil], + 12062 => [0, 0, nil, "囗", nil, nil, nil], + 12063 => [0, 0, nil, "土", nil, nil, nil], + 12064 => [0, 0, nil, "士", nil, nil, nil], + 12065 => [0, 0, nil, "夂", nil, nil, nil], + 12066 => [0, 0, nil, "夊", nil, nil, nil], + 12067 => [0, 0, nil, "夕", nil, nil, nil], + 12068 => [0, 0, nil, "大", nil, nil, nil], + 12069 => [0, 0, nil, "女", nil, nil, nil], + 12070 => [0, 0, nil, "子", nil, nil, nil], + 12071 => [0, 0, nil, "宀", nil, nil, nil], + 12072 => [0, 0, nil, "寸", nil, nil, nil], + 12073 => [0, 0, nil, "小", nil, nil, nil], + 12074 => [0, 0, nil, "尢", nil, nil, nil], + 12075 => [0, 0, nil, "尸", nil, nil, nil], + 12076 => [0, 0, nil, "屮", nil, nil, nil], + 12077 => [0, 0, nil, "山", nil, nil, nil], + 12078 => [0, 0, nil, "巛", nil, nil, nil], + 12079 => [0, 0, nil, "工", nil, nil, nil], + 12080 => [0, 0, nil, "己", nil, nil, nil], + 12081 => [0, 0, nil, "巾", nil, nil, nil], + 12082 => [0, 0, nil, "干", nil, nil, nil], + 12083 => [0, 0, nil, "幺", nil, nil, nil], + 12084 => [0, 0, nil, "广", nil, nil, nil], + 12085 => [0, 0, nil, "廴", nil, nil, nil], + 12086 => [0, 0, nil, "廾", nil, nil, nil], + 12087 => [0, 0, nil, "弋", nil, nil, nil], + 12088 => [0, 0, nil, "弓", nil, nil, nil], + 12089 => [0, 0, nil, "彐", nil, nil, nil], + 12090 => [0, 0, nil, "彡", nil, nil, nil], + 12091 => [0, 0, nil, "彳", nil, nil, nil], + 12092 => [0, 0, nil, "心", nil, nil, nil], + 12093 => [0, 0, nil, "戈", nil, nil, nil], + 12094 => [0, 0, nil, "戶", nil, nil, nil], + 12095 => [0, 0, nil, "手", nil, nil, nil], + 12096 => [0, 0, nil, "支", nil, nil, nil], + 12097 => [0, 0, nil, "攴", nil, nil, nil], + 12098 => [0, 0, nil, "文", nil, nil, nil], + 12099 => [0, 0, nil, "斗", nil, nil, nil], + 12100 => [0, 0, nil, "斤", nil, nil, nil], + 12101 => [0, 0, nil, "方", nil, nil, nil], + 12102 => [0, 0, nil, "无", nil, nil, nil], + 12103 => [0, 0, nil, "日", nil, nil, nil], + 12104 => [0, 0, nil, "曰", nil, nil, nil], + 12105 => [0, 0, nil, "月", nil, nil, nil], + 12106 => [0, 0, nil, "木", nil, nil, nil], + 12107 => [0, 0, nil, "欠", nil, nil, nil], + 12108 => [0, 0, nil, "止", nil, nil, nil], + 12109 => [0, 0, nil, "歹", nil, nil, nil], + 12110 => [0, 0, nil, "殳", nil, nil, nil], + 12111 => [0, 0, nil, "毋", nil, nil, nil], + 12112 => [0, 0, nil, "比", nil, nil, nil], + 12113 => [0, 0, nil, "毛", nil, nil, nil], + 12114 => [0, 0, nil, "氏", nil, nil, nil], + 12115 => [0, 0, nil, "气", nil, nil, nil], + 12116 => [0, 0, nil, "水", nil, nil, nil], + 12117 => [0, 0, nil, "火", nil, nil, nil], + 12118 => [0, 0, nil, "爪", nil, nil, nil], + 12119 => [0, 0, nil, "父", nil, nil, nil], + 12120 => [0, 0, nil, "爻", nil, nil, nil], + 12121 => [0, 0, nil, "爿", nil, nil, nil], + 12122 => [0, 0, nil, "片", nil, nil, nil], + 12123 => [0, 0, nil, "牙", nil, nil, nil], + 12124 => [0, 0, nil, "牛", nil, nil, nil], + 12125 => [0, 0, nil, "犬", nil, nil, nil], + 12126 => [0, 0, nil, "玄", nil, nil, nil], + 12127 => [0, 0, nil, "玉", nil, nil, nil], + 12128 => [0, 0, nil, "瓜", nil, nil, nil], + 12129 => [0, 0, nil, "瓦", nil, nil, nil], + 12130 => [0, 0, nil, "甘", nil, nil, nil], + 12131 => [0, 0, nil, "生", nil, nil, nil], + 12132 => [0, 0, nil, "用", nil, nil, nil], + 12133 => [0, 0, nil, "田", nil, nil, nil], + 12134 => [0, 0, nil, "疋", nil, nil, nil], + 12135 => [0, 0, nil, "疒", nil, nil, nil], + 12136 => [0, 0, nil, "癶", nil, nil, nil], + 12137 => [0, 0, nil, "白", nil, nil, nil], + 12138 => [0, 0, nil, "皮", nil, nil, nil], + 12139 => [0, 0, nil, "皿", nil, nil, nil], + 12140 => [0, 0, nil, "目", nil, nil, nil], + 12141 => [0, 0, nil, "矛", nil, nil, nil], + 12142 => [0, 0, nil, "矢", nil, nil, nil], + 12143 => [0, 0, nil, "石", nil, nil, nil], + 12144 => [0, 0, nil, "示", nil, nil, nil], + 12145 => [0, 0, nil, "禸", nil, nil, nil], + 12146 => [0, 0, nil, "禾", nil, nil, nil], + 12147 => [0, 0, nil, "穴", nil, nil, nil], + 12148 => [0, 0, nil, "立", nil, nil, nil], + 12149 => [0, 0, nil, "竹", nil, nil, nil], + 12150 => [0, 0, nil, "米", nil, nil, nil], + 12151 => [0, 0, nil, "糸", nil, nil, nil], + 12152 => [0, 0, nil, "缶", nil, nil, nil], + 12153 => [0, 0, nil, "网", nil, nil, nil], + 12154 => [0, 0, nil, "羊", nil, nil, nil], + 12155 => [0, 0, nil, "羽", nil, nil, nil], + 12156 => [0, 0, nil, "老", nil, nil, nil], + 12157 => [0, 0, nil, "而", nil, nil, nil], + 12158 => [0, 0, nil, "耒", nil, nil, nil], + 12159 => [0, 0, nil, "耳", nil, nil, nil], + 12160 => [0, 0, nil, "聿", nil, nil, nil], + 12161 => [0, 0, nil, "肉", nil, nil, nil], + 12162 => [0, 0, nil, "臣", nil, nil, nil], + 12163 => [0, 0, nil, "自", nil, nil, nil], + 12164 => [0, 0, nil, "至", nil, nil, nil], + 12165 => [0, 0, nil, "臼", nil, nil, nil], + 12166 => [0, 0, nil, "舌", nil, nil, nil], + 12167 => [0, 0, nil, "舛", nil, nil, nil], + 12168 => [0, 0, nil, "舟", nil, nil, nil], + 12169 => [0, 0, nil, "艮", nil, nil, nil], + 12170 => [0, 0, nil, "色", nil, nil, nil], + 12171 => [0, 0, nil, "艸", nil, nil, nil], + 12172 => [0, 0, nil, "虍", nil, nil, nil], + 12173 => [0, 0, nil, "虫", nil, nil, nil], + 12174 => [0, 0, nil, "血", nil, nil, nil], + 12175 => [0, 0, nil, "行", nil, nil, nil], + 12176 => [0, 0, nil, "衣", nil, nil, nil], + 12177 => [0, 0, nil, "襾", nil, nil, nil], + 12178 => [0, 0, nil, "見", nil, nil, nil], + 12179 => [0, 0, nil, "角", nil, nil, nil], + 12180 => [0, 0, nil, "言", nil, nil, nil], + 12181 => [0, 0, nil, "谷", nil, nil, nil], + 12182 => [0, 0, nil, "豆", nil, nil, nil], + 12183 => [0, 0, nil, "豕", nil, nil, nil], + 12184 => [0, 0, nil, "豸", nil, nil, nil], + 12185 => [0, 0, nil, "貝", nil, nil, nil], + 12186 => [0, 0, nil, "赤", nil, nil, nil], + 12187 => [0, 0, nil, "走", nil, nil, nil], + 12188 => [0, 0, nil, "足", nil, nil, nil], + 12189 => [0, 0, nil, "身", nil, nil, nil], + 12190 => [0, 0, nil, "車", nil, nil, nil], + 12191 => [0, 0, nil, "辛", nil, nil, nil], + 12192 => [0, 0, nil, "辰", nil, nil, nil], + 12193 => [0, 0, nil, "辵", nil, nil, nil], + 12194 => [0, 0, nil, "邑", nil, nil, nil], + 12195 => [0, 0, nil, "酉", nil, nil, nil], + 12196 => [0, 0, nil, "釆", nil, nil, nil], + 12197 => [0, 0, nil, "里", nil, nil, nil], + 12198 => [0, 0, nil, "金", nil, nil, nil], + 12199 => [0, 0, nil, "長", nil, nil, nil], + 12200 => [0, 0, nil, "門", nil, nil, nil], + 12201 => [0, 0, nil, "阜", nil, nil, nil], + 12202 => [0, 0, nil, "隶", nil, nil, nil], + 12203 => [0, 0, nil, "隹", nil, nil, nil], + 12204 => [0, 0, nil, "雨", nil, nil, nil], + 12205 => [0, 0, nil, "靑", nil, nil, nil], + 12206 => [0, 0, nil, "非", nil, nil, nil], + 12207 => [0, 0, nil, "面", nil, nil, nil], + 12208 => [0, 0, nil, "革", nil, nil, nil], + 12209 => [0, 0, nil, "韋", nil, nil, nil], + 12210 => [0, 0, nil, "韭", nil, nil, nil], + 12211 => [0, 0, nil, "音", nil, nil, nil], + 12212 => [0, 0, nil, "頁", nil, nil, nil], + 12213 => [0, 0, nil, "風", nil, nil, nil], + 12214 => [0, 0, nil, "飛", nil, nil, nil], + 12215 => [0, 0, nil, "食", nil, nil, nil], + 12216 => [0, 0, nil, "首", nil, nil, nil], + 12217 => [0, 0, nil, "香", nil, nil, nil], + 12218 => [0, 0, nil, "馬", nil, nil, nil], + 12219 => [0, 0, nil, "骨", nil, nil, nil], + 12220 => [0, 0, nil, "高", nil, nil, nil], + 12221 => [0, 0, nil, "髟", nil, nil, nil], + 12222 => [0, 0, nil, "鬥", nil, nil, nil], + 12223 => [0, 0, nil, "鬯", nil, nil, nil], + 12224 => [0, 0, nil, "鬲", nil, nil, nil], + 12225 => [0, 0, nil, "鬼", nil, nil, nil], + 12226 => [0, 0, nil, "魚", nil, nil, nil], + 12227 => [0, 0, nil, "鳥", nil, nil, nil], + 12228 => [0, 0, nil, "鹵", nil, nil, nil], + 12229 => [0, 0, nil, "鹿", nil, nil, nil], + 12230 => [0, 0, nil, "麥", nil, nil, nil], + 12231 => [0, 0, nil, "麻", nil, nil, nil], + 12232 => [0, 0, nil, "黃", nil, nil, nil], + 12233 => [0, 0, nil, "黍", nil, nil, nil], + 12234 => [0, 0, nil, "黑", nil, nil, nil], + 12235 => [0, 0, nil, "黹", nil, nil, nil], + 12236 => [0, 0, nil, "黽", nil, nil, nil], + 12237 => [0, 0, nil, "鼎", nil, nil, nil], + 12238 => [0, 0, nil, "鼓", nil, nil, nil], + 12239 => [0, 0, nil, "鼠", nil, nil, nil], + 12240 => [0, 0, nil, "鼻", nil, nil, nil], + 12241 => [0, 0, nil, "齊", nil, nil, nil], + 12242 => [0, 0, nil, "齒", nil, nil, nil], + 12243 => [0, 0, nil, "龍", nil, nil, nil], + 12244 => [0, 0, nil, "龜", nil, nil, nil], + 12245 => [0, 0, nil, "龠", nil, nil, nil], + 12288 => [0, 0, nil, " ", nil, nil, nil], + 12330 => [218, 0, nil, nil, nil, nil, nil], + 12331 => [228, 0, nil, nil, nil, nil, nil], + 12332 => [232, 0, nil, nil, nil, nil, nil], + 12333 => [222, 0, nil, nil, nil, nil, nil], + 12334 => [224, 0, nil, nil, nil, nil, nil], + 12335 => [224, 0, nil, nil, nil, nil, nil], + 12342 => [0, 0, nil, "〒", nil, nil, nil], + 12344 => [0, 0, nil, "十", nil, nil, nil], + 12345 => [0, 0, nil, "卄", nil, nil, nil], + 12346 => [0, 0, nil, "卅", nil, nil, nil], + 12364 => [0, 0, "が", "が", nil, nil, nil], + 12366 => [0, 0, "ぎ", "ぎ", nil, nil, nil], + 12368 => [0, 0, "ぐ", "ぐ", nil, nil, nil], + 12370 => [0, 0, "げ", "げ", nil, nil, nil], + 12372 => [0, 0, "ご", "ご", nil, nil, nil], + 12374 => [0, 0, "ざ", "ざ", nil, nil, nil], + 12376 => [0, 0, "じ", "じ", nil, nil, nil], + 12378 => [0, 0, "ず", "ず", nil, nil, nil], + 12380 => [0, 0, "ぜ", "ぜ", nil, nil, nil], + 12382 => [0, 0, "ぞ", "ぞ", nil, nil, nil], + 12384 => [0, 0, "だ", "だ", nil, nil, nil], + 12386 => [0, 0, "ぢ", "ぢ", nil, nil, nil], + 12389 => [0, 0, "づ", "づ", nil, nil, nil], + 12391 => [0, 0, "で", "で", nil, nil, nil], + 12393 => [0, 0, "ど", "ど", nil, nil, nil], + 12400 => [0, 0, "ば", "ば", nil, nil, nil], + 12401 => [0, 0, "ぱ", "ぱ", nil, nil, nil], + 12403 => [0, 0, "び", "び", nil, nil, nil], + 12404 => [0, 0, "ぴ", "ぴ", nil, nil, nil], + 12406 => [0, 0, "ぶ", "ぶ", nil, nil, nil], + 12407 => [0, 0, "ぷ", "ぷ", nil, nil, nil], + 12409 => [0, 0, "べ", "べ", nil, nil, nil], + 12410 => [0, 0, "ぺ", "ぺ", nil, nil, nil], + 12412 => [0, 0, "ぼ", "ぼ", nil, nil, nil], + 12413 => [0, 0, "ぽ", "ぽ", nil, nil, nil], + 12436 => [0, 0, "ゔ", "ゔ", nil, nil, nil], + 12441 => [8, 0, nil, nil, nil, nil, nil], + 12442 => [8, 0, nil, nil, nil, nil, nil], + 12443 => [0, 0, nil, " ゙", nil, nil, nil], + 12444 => [0, 0, nil, " ゚", nil, nil, nil], + 12446 => [0, 0, "ゞ", "ゞ", nil, nil, nil], + 12460 => [0, 0, "ガ", "ガ", nil, nil, nil], + 12462 => [0, 0, "ギ", "ギ", nil, nil, nil], + 12464 => [0, 0, "グ", "グ", nil, nil, nil], + 12466 => [0, 0, "ゲ", "ゲ", nil, nil, nil], + 12468 => [0, 0, "ゴ", "ゴ", nil, nil, nil], + 12470 => [0, 0, "ザ", "ザ", nil, nil, nil], + 12472 => [0, 0, "ジ", "ジ", nil, nil, nil], + 12474 => [0, 0, "ズ", "ズ", nil, nil, nil], + 12476 => [0, 0, "ゼ", "ゼ", nil, nil, nil], + 12478 => [0, 0, "ゾ", "ゾ", nil, nil, nil], + 12480 => [0, 0, "ダ", "ダ", nil, nil, nil], + 12482 => [0, 0, "ヂ", "ヂ", nil, nil, nil], + 12485 => [0, 0, "ヅ", "ヅ", nil, nil, nil], + 12487 => [0, 0, "デ", "デ", nil, nil, nil], + 12489 => [0, 0, "ド", "ド", nil, nil, nil], + 12496 => [0, 0, "バ", "バ", nil, nil, nil], + 12497 => [0, 0, "パ", "パ", nil, nil, nil], + 12499 => [0, 0, "ビ", "ビ", nil, nil, nil], + 12500 => [0, 0, "ピ", "ピ", nil, nil, nil], + 12502 => [0, 0, "ブ", "ブ", nil, nil, nil], + 12503 => [0, 0, "プ", "プ", nil, nil, nil], + 12505 => [0, 0, "ベ", "ベ", nil, nil, nil], + 12506 => [0, 0, "ペ", "ペ", nil, nil, nil], + 12508 => [0, 0, "ボ", "ボ", nil, nil, nil], + 12509 => [0, 0, "ポ", "ポ", nil, nil, nil], + 12532 => [0, 0, "ヴ", "ヴ", nil, nil, nil], + 12535 => [0, 0, "ヷ", "ヷ", nil, nil, nil], + 12536 => [0, 0, "ヸ", "ヸ", nil, nil, nil], + 12537 => [0, 0, "ヹ", "ヹ", nil, nil, nil], + 12538 => [0, 0, "ヺ", "ヺ", nil, nil, nil], + 12542 => [0, 0, "ヾ", "ヾ", nil, nil, nil], + 12593 => [0, 0, nil, "ᄀ", nil, nil, nil], + 12594 => [0, 0, nil, "ᄁ", nil, nil, nil], + 12595 => [0, 0, nil, "ᆪ", nil, nil, nil], + 12596 => [0, 0, nil, "ᄂ", nil, nil, nil], + 12597 => [0, 0, nil, "ᆬ", nil, nil, nil], + 12598 => [0, 0, nil, "ᆭ", nil, nil, nil], + 12599 => [0, 0, nil, "ᄃ", nil, nil, nil], + 12600 => [0, 0, nil, "ᄄ", nil, nil, nil], + 12601 => [0, 0, nil, "ᄅ", nil, nil, nil], + 12602 => [0, 0, nil, "ᆰ", nil, nil, nil], + 12603 => [0, 0, nil, "ᆱ", nil, nil, nil], + 12604 => [0, 0, nil, "ᆲ", nil, nil, nil], + 12605 => [0, 0, nil, "ᆳ", nil, nil, nil], + 12606 => [0, 0, nil, "ᆴ", nil, nil, nil], + 12607 => [0, 0, nil, "ᆵ", nil, nil, nil], + 12608 => [0, 0, nil, "ᄚ", nil, nil, nil], + 12609 => [0, 0, nil, "ᄆ", nil, nil, nil], + 12610 => [0, 0, nil, "ᄇ", nil, nil, nil], + 12611 => [0, 0, nil, "ᄈ", nil, nil, nil], + 12612 => [0, 0, nil, "ᄡ", nil, nil, nil], + 12613 => [0, 0, nil, "ᄉ", nil, nil, nil], + 12614 => [0, 0, nil, "ᄊ", nil, nil, nil], + 12615 => [0, 0, nil, "ᄋ", nil, nil, nil], + 12616 => [0, 0, nil, "ᄌ", nil, nil, nil], + 12617 => [0, 0, nil, "ᄍ", nil, nil, nil], + 12618 => [0, 0, nil, "ᄎ", nil, nil, nil], + 12619 => [0, 0, nil, "ᄏ", nil, nil, nil], + 12620 => [0, 0, nil, "ᄐ", nil, nil, nil], + 12621 => [0, 0, nil, "ᄑ", nil, nil, nil], + 12622 => [0, 0, nil, "ᄒ", nil, nil, nil], + 12623 => [0, 0, nil, "ᅡ", nil, nil, nil], + 12624 => [0, 0, nil, "ᅢ", nil, nil, nil], + 12625 => [0, 0, nil, "ᅣ", nil, nil, nil], + 12626 => [0, 0, nil, "ᅤ", nil, nil, nil], + 12627 => [0, 0, nil, "ᅥ", nil, nil, nil], + 12628 => [0, 0, nil, "ᅦ", nil, nil, nil], + 12629 => [0, 0, nil, "ᅧ", nil, nil, nil], + 12630 => [0, 0, nil, "ᅨ", nil, nil, nil], + 12631 => [0, 0, nil, "ᅩ", nil, nil, nil], + 12632 => [0, 0, nil, "ᅪ", nil, nil, nil], + 12633 => [0, 0, nil, "ᅫ", nil, nil, nil], + 12634 => [0, 0, nil, "ᅬ", nil, nil, nil], + 12635 => [0, 0, nil, "ᅭ", nil, nil, nil], + 12636 => [0, 0, nil, "ᅮ", nil, nil, nil], + 12637 => [0, 0, nil, "ᅯ", nil, nil, nil], + 12638 => [0, 0, nil, "ᅰ", nil, nil, nil], + 12639 => [0, 0, nil, "ᅱ", nil, nil, nil], + 12640 => [0, 0, nil, "ᅲ", nil, nil, nil], + 12641 => [0, 0, nil, "ᅳ", nil, nil, nil], + 12642 => [0, 0, nil, "ᅴ", nil, nil, nil], + 12643 => [0, 0, nil, "ᅵ", nil, nil, nil], + 12644 => [0, 0, nil, "ᅠ", nil, nil, nil], + 12645 => [0, 0, nil, "ᄔ", nil, nil, nil], + 12646 => [0, 0, nil, "ᄕ", nil, nil, nil], + 12647 => [0, 0, nil, "ᇇ", nil, nil, nil], + 12648 => [0, 0, nil, "ᇈ", nil, nil, nil], + 12649 => [0, 0, nil, "ᇌ", nil, nil, nil], + 12650 => [0, 0, nil, "ᇎ", nil, nil, nil], + 12651 => [0, 0, nil, "ᇓ", nil, nil, nil], + 12652 => [0, 0, nil, "ᇗ", nil, nil, nil], + 12653 => [0, 0, nil, "ᇙ", nil, nil, nil], + 12654 => [0, 0, nil, "ᄜ", nil, nil, nil], + 12655 => [0, 0, nil, "ᇝ", nil, nil, nil], + 12656 => [0, 0, nil, "ᇟ", nil, nil, nil], + 12657 => [0, 0, nil, "ᄝ", nil, nil, nil], + 12658 => [0, 0, nil, "ᄞ", nil, nil, nil], + 12659 => [0, 0, nil, "ᄠ", nil, nil, nil], + 12660 => [0, 0, nil, "ᄢ", nil, nil, nil], + 12661 => [0, 0, nil, "ᄣ", nil, nil, nil], + 12662 => [0, 0, nil, "ᄧ", nil, nil, nil], + 12663 => [0, 0, nil, "ᄩ", nil, nil, nil], + 12664 => [0, 0, nil, "ᄫ", nil, nil, nil], + 12665 => [0, 0, nil, "ᄬ", nil, nil, nil], + 12666 => [0, 0, nil, "ᄭ", nil, nil, nil], + 12667 => [0, 0, nil, "ᄮ", nil, nil, nil], + 12668 => [0, 0, nil, "ᄯ", nil, nil, nil], + 12669 => [0, 0, nil, "ᄲ", nil, nil, nil], + 12670 => [0, 0, nil, "ᄶ", nil, nil, nil], + 12671 => [0, 0, nil, "ᅀ", nil, nil, nil], + 12672 => [0, 0, nil, "ᅇ", nil, nil, nil], + 12673 => [0, 0, nil, "ᅌ", nil, nil, nil], + 12674 => [0, 0, nil, "ᇱ", nil, nil, nil], + 12675 => [0, 0, nil, "ᇲ", nil, nil, nil], + 12676 => [0, 0, nil, "ᅗ", nil, nil, nil], + 12677 => [0, 0, nil, "ᅘ", nil, nil, nil], + 12678 => [0, 0, nil, "ᅙ", nil, nil, nil], + 12679 => [0, 0, nil, "ᆄ", nil, nil, nil], + 12680 => [0, 0, nil, "ᆅ", nil, nil, nil], + 12681 => [0, 0, nil, "ᆈ", nil, nil, nil], + 12682 => [0, 0, nil, "ᆑ", nil, nil, nil], + 12683 => [0, 0, nil, "ᆒ", nil, nil, nil], + 12684 => [0, 0, nil, "ᆔ", nil, nil, nil], + 12685 => [0, 0, nil, "ᆞ", nil, nil, nil], + 12686 => [0, 0, nil, "ᆡ", nil, nil, nil], + 12690 => [0, 0, nil, "一", nil, nil, nil], + 12691 => [0, 0, nil, "二", nil, nil, nil], + 12692 => [0, 0, nil, "三", nil, nil, nil], + 12693 => [0, 0, nil, "四", nil, nil, nil], + 12694 => [0, 0, nil, "上", nil, nil, nil], + 12695 => [0, 0, nil, "中", nil, nil, nil], + 12696 => [0, 0, nil, "下", nil, nil, nil], + 12697 => [0, 0, nil, "甲", nil, nil, nil], + 12698 => [0, 0, nil, "乙", nil, nil, nil], + 12699 => [0, 0, nil, "丙", nil, nil, nil], + 12700 => [0, 0, nil, "丁", nil, nil, nil], + 12701 => [0, 0, nil, "天", nil, nil, nil], + 12702 => [0, 0, nil, "地", nil, nil, nil], + 12703 => [0, 0, nil, "人", nil, nil, nil], + 12800 => [0, 0, nil, "(ᄀ)", nil, nil, nil], + 12801 => [0, 0, nil, "(ᄂ)", nil, nil, nil], + 12802 => [0, 0, nil, "(ᄃ)", nil, nil, nil], + 12803 => [0, 0, nil, "(ᄅ)", nil, nil, nil], + 12804 => [0, 0, nil, "(ᄆ)", nil, nil, nil], + 12805 => [0, 0, nil, "(ᄇ)", nil, nil, nil], + 12806 => [0, 0, nil, "(ᄉ)", nil, nil, nil], + 12807 => [0, 0, nil, "(ᄋ)", nil, nil, nil], + 12808 => [0, 0, nil, "(ᄌ)", nil, nil, nil], + 12809 => [0, 0, nil, "(ᄎ)", nil, nil, nil], + 12810 => [0, 0, nil, "(ᄏ)", nil, nil, nil], + 12811 => [0, 0, nil, "(ᄐ)", nil, nil, nil], + 12812 => [0, 0, nil, "(ᄑ)", nil, nil, nil], + 12813 => [0, 0, nil, "(ᄒ)", nil, nil, nil], + 12814 => [0, 0, nil, "(가)", nil, nil, nil], + 12815 => [0, 0, nil, "(나)", nil, nil, nil], + 12816 => [0, 0, nil, "(다)", nil, nil, nil], + 12817 => [0, 0, nil, "(라)", nil, nil, nil], + 12818 => [0, 0, nil, "(마)", nil, nil, nil], + 12819 => [0, 0, nil, "(바)", nil, nil, nil], + 12820 => [0, 0, nil, "(사)", nil, nil, nil], + 12821 => [0, 0, nil, "(아)", nil, nil, nil], + 12822 => [0, 0, nil, "(자)", nil, nil, nil], + 12823 => [0, 0, nil, "(차)", nil, nil, nil], + 12824 => [0, 0, nil, "(카)", nil, nil, nil], + 12825 => [0, 0, nil, "(타)", nil, nil, nil], + 12826 => [0, 0, nil, "(파)", nil, nil, nil], + 12827 => [0, 0, nil, "(하)", nil, nil, nil], + 12828 => [0, 0, nil, "(주)", nil, nil, nil], + 12832 => [0, 0, nil, "(一)", nil, nil, nil], + 12833 => [0, 0, nil, "(二)", nil, nil, nil], + 12834 => [0, 0, nil, "(三)", nil, nil, nil], + 12835 => [0, 0, nil, "(四)", nil, nil, nil], + 12836 => [0, 0, nil, "(五)", nil, nil, nil], + 12837 => [0, 0, nil, "(六)", nil, nil, nil], + 12838 => [0, 0, nil, "(七)", nil, nil, nil], + 12839 => [0, 0, nil, "(八)", nil, nil, nil], + 12840 => [0, 0, nil, "(九)", nil, nil, nil], + 12841 => [0, 0, nil, "(十)", nil, nil, nil], + 12842 => [0, 0, nil, "(月)", nil, nil, nil], + 12843 => [0, 0, nil, "(火)", nil, nil, nil], + 12844 => [0, 0, nil, "(水)", nil, nil, nil], + 12845 => [0, 0, nil, "(木)", nil, nil, nil], + 12846 => [0, 0, nil, "(金)", nil, nil, nil], + 12847 => [0, 0, nil, "(土)", nil, nil, nil], + 12848 => [0, 0, nil, "(日)", nil, nil, nil], + 12849 => [0, 0, nil, "(株)", nil, nil, nil], + 12850 => [0, 0, nil, "(有)", nil, nil, nil], + 12851 => [0, 0, nil, "(社)", nil, nil, nil], + 12852 => [0, 0, nil, "(名)", nil, nil, nil], + 12853 => [0, 0, nil, "(特)", nil, nil, nil], + 12854 => [0, 0, nil, "(財)", nil, nil, nil], + 12855 => [0, 0, nil, "(祝)", nil, nil, nil], + 12856 => [0, 0, nil, "(労)", nil, nil, nil], + 12857 => [0, 0, nil, "(代)", nil, nil, nil], + 12858 => [0, 0, nil, "(呼)", nil, nil, nil], + 12859 => [0, 0, nil, "(学)", nil, nil, nil], + 12860 => [0, 0, nil, "(監)", nil, nil, nil], + 12861 => [0, 0, nil, "(企)", nil, nil, nil], + 12862 => [0, 0, nil, "(資)", nil, nil, nil], + 12863 => [0, 0, nil, "(協)", nil, nil, nil], + 12864 => [0, 0, nil, "(祭)", nil, nil, nil], + 12865 => [0, 0, nil, "(休)", nil, nil, nil], + 12866 => [0, 0, nil, "(自)", nil, nil, nil], + 12867 => [0, 0, nil, "(至)", nil, nil, nil], + 12896 => [0, 0, nil, "ᄀ", nil, nil, nil], + 12897 => [0, 0, nil, "ᄂ", nil, nil, nil], + 12898 => [0, 0, nil, "ᄃ", nil, nil, nil], + 12899 => [0, 0, nil, "ᄅ", nil, nil, nil], + 12900 => [0, 0, nil, "ᄆ", nil, nil, nil], + 12901 => [0, 0, nil, "ᄇ", nil, nil, nil], + 12902 => [0, 0, nil, "ᄉ", nil, nil, nil], + 12903 => [0, 0, nil, "ᄋ", nil, nil, nil], + 12904 => [0, 0, nil, "ᄌ", nil, nil, nil], + 12905 => [0, 0, nil, "ᄎ", nil, nil, nil], + 12906 => [0, 0, nil, "ᄏ", nil, nil, nil], + 12907 => [0, 0, nil, "ᄐ", nil, nil, nil], + 12908 => [0, 0, nil, "ᄑ", nil, nil, nil], + 12909 => [0, 0, nil, "ᄒ", nil, nil, nil], + 12910 => [0, 0, nil, "가", nil, nil, nil], + 12911 => [0, 0, nil, "나", nil, nil, nil], + 12912 => [0, 0, nil, "다", nil, nil, nil], + 12913 => [0, 0, nil, "라", nil, nil, nil], + 12914 => [0, 0, nil, "마", nil, nil, nil], + 12915 => [0, 0, nil, "바", nil, nil, nil], + 12916 => [0, 0, nil, "사", nil, nil, nil], + 12917 => [0, 0, nil, "아", nil, nil, nil], + 12918 => [0, 0, nil, "자", nil, nil, nil], + 12919 => [0, 0, nil, "차", nil, nil, nil], + 12920 => [0, 0, nil, "카", nil, nil, nil], + 12921 => [0, 0, nil, "타", nil, nil, nil], + 12922 => [0, 0, nil, "파", nil, nil, nil], + 12923 => [0, 0, nil, "하", nil, nil, nil], + 12928 => [0, 0, nil, "一", nil, nil, nil], + 12929 => [0, 0, nil, "二", nil, nil, nil], + 12930 => [0, 0, nil, "三", nil, nil, nil], + 12931 => [0, 0, nil, "四", nil, nil, nil], + 12932 => [0, 0, nil, "五", nil, nil, nil], + 12933 => [0, 0, nil, "六", nil, nil, nil], + 12934 => [0, 0, nil, "七", nil, nil, nil], + 12935 => [0, 0, nil, "八", nil, nil, nil], + 12936 => [0, 0, nil, "九", nil, nil, nil], + 12937 => [0, 0, nil, "十", nil, nil, nil], + 12938 => [0, 0, nil, "月", nil, nil, nil], + 12939 => [0, 0, nil, "火", nil, nil, nil], + 12940 => [0, 0, nil, "水", nil, nil, nil], + 12941 => [0, 0, nil, "木", nil, nil, nil], + 12942 => [0, 0, nil, "金", nil, nil, nil], + 12943 => [0, 0, nil, "土", nil, nil, nil], + 12944 => [0, 0, nil, "日", nil, nil, nil], + 12945 => [0, 0, nil, "株", nil, nil, nil], + 12946 => [0, 0, nil, "有", nil, nil, nil], + 12947 => [0, 0, nil, "社", nil, nil, nil], + 12948 => [0, 0, nil, "名", nil, nil, nil], + 12949 => [0, 0, nil, "特", nil, nil, nil], + 12950 => [0, 0, nil, "財", nil, nil, nil], + 12951 => [0, 0, nil, "祝", nil, nil, nil], + 12952 => [0, 0, nil, "労", nil, nil, nil], + 12953 => [0, 0, nil, "秘", nil, nil, nil], + 12954 => [0, 0, nil, "男", nil, nil, nil], + 12955 => [0, 0, nil, "女", nil, nil, nil], + 12956 => [0, 0, nil, "適", nil, nil, nil], + 12957 => [0, 0, nil, "優", nil, nil, nil], + 12958 => [0, 0, nil, "印", nil, nil, nil], + 12959 => [0, 0, nil, "注", nil, nil, nil], + 12960 => [0, 0, nil, "項", nil, nil, nil], + 12961 => [0, 0, nil, "休", nil, nil, nil], + 12962 => [0, 0, nil, "写", nil, nil, nil], + 12963 => [0, 0, nil, "正", nil, nil, nil], + 12964 => [0, 0, nil, "上", nil, nil, nil], + 12965 => [0, 0, nil, "中", nil, nil, nil], + 12966 => [0, 0, nil, "下", nil, nil, nil], + 12967 => [0, 0, nil, "左", nil, nil, nil], + 12968 => [0, 0, nil, "右", nil, nil, nil], + 12969 => [0, 0, nil, "医", nil, nil, nil], + 12970 => [0, 0, nil, "宗", nil, nil, nil], + 12971 => [0, 0, nil, "学", nil, nil, nil], + 12972 => [0, 0, nil, "監", nil, nil, nil], + 12973 => [0, 0, nil, "企", nil, nil, nil], + 12974 => [0, 0, nil, "資", nil, nil, nil], + 12975 => [0, 0, nil, "協", nil, nil, nil], + 12976 => [0, 0, nil, "夜", nil, nil, nil], + 12992 => [0, 0, nil, "1月", nil, nil, nil], + 12993 => [0, 0, nil, "2月", nil, nil, nil], + 12994 => [0, 0, nil, "3月", nil, nil, nil], + 12995 => [0, 0, nil, "4月", nil, nil, nil], + 12996 => [0, 0, nil, "5月", nil, nil, nil], + 12997 => [0, 0, nil, "6月", nil, nil, nil], + 12998 => [0, 0, nil, "7月", nil, nil, nil], + 12999 => [0, 0, nil, "8月", nil, nil, nil], + 13000 => [0, 0, nil, "9月", nil, nil, nil], + 13001 => [0, 0, nil, "10月", nil, nil, nil], + 13002 => [0, 0, nil, "11月", nil, nil, nil], + 13003 => [0, 0, nil, "12月", nil, nil, nil], + 13008 => [0, 0, nil, "ア", nil, nil, nil], + 13009 => [0, 0, nil, "イ", nil, nil, nil], + 13010 => [0, 0, nil, "ウ", nil, nil, nil], + 13011 => [0, 0, nil, "エ", nil, nil, nil], + 13012 => [0, 0, nil, "オ", nil, nil, nil], + 13013 => [0, 0, nil, "カ", nil, nil, nil], + 13014 => [0, 0, nil, "キ", nil, nil, nil], + 13015 => [0, 0, nil, "ク", nil, nil, nil], + 13016 => [0, 0, nil, "ケ", nil, nil, nil], + 13017 => [0, 0, nil, "コ", nil, nil, nil], + 13018 => [0, 0, nil, "サ", nil, nil, nil], + 13019 => [0, 0, nil, "シ", nil, nil, nil], + 13020 => [0, 0, nil, "ス", nil, nil, nil], + 13021 => [0, 0, nil, "セ", nil, nil, nil], + 13022 => [0, 0, nil, "ソ", nil, nil, nil], + 13023 => [0, 0, nil, "タ", nil, nil, nil], + 13024 => [0, 0, nil, "チ", nil, nil, nil], + 13025 => [0, 0, nil, "ツ", nil, nil, nil], + 13026 => [0, 0, nil, "テ", nil, nil, nil], + 13027 => [0, 0, nil, "ト", nil, nil, nil], + 13028 => [0, 0, nil, "ナ", nil, nil, nil], + 13029 => [0, 0, nil, "ニ", nil, nil, nil], + 13030 => [0, 0, nil, "ヌ", nil, nil, nil], + 13031 => [0, 0, nil, "ネ", nil, nil, nil], + 13032 => [0, 0, nil, "ノ", nil, nil, nil], + 13033 => [0, 0, nil, "ハ", nil, nil, nil], + 13034 => [0, 0, nil, "ヒ", nil, nil, nil], + 13035 => [0, 0, nil, "フ", nil, nil, nil], + 13036 => [0, 0, nil, "ヘ", nil, nil, nil], + 13037 => [0, 0, nil, "ホ", nil, nil, nil], + 13038 => [0, 0, nil, "マ", nil, nil, nil], + 13039 => [0, 0, nil, "ミ", nil, nil, nil], + 13040 => [0, 0, nil, "ム", nil, nil, nil], + 13041 => [0, 0, nil, "メ", nil, nil, nil], + 13042 => [0, 0, nil, "モ", nil, nil, nil], + 13043 => [0, 0, nil, "ヤ", nil, nil, nil], + 13044 => [0, 0, nil, "ユ", nil, nil, nil], + 13045 => [0, 0, nil, "ヨ", nil, nil, nil], + 13046 => [0, 0, nil, "ラ", nil, nil, nil], + 13047 => [0, 0, nil, "リ", nil, nil, nil], + 13048 => [0, 0, nil, "ル", nil, nil, nil], + 13049 => [0, 0, nil, "レ", nil, nil, nil], + 13050 => [0, 0, nil, "ロ", nil, nil, nil], + 13051 => [0, 0, nil, "ワ", nil, nil, nil], + 13052 => [0, 0, nil, "ヰ", nil, nil, nil], + 13053 => [0, 0, nil, "ヱ", nil, nil, nil], + 13054 => [0, 0, nil, "ヲ", nil, nil, nil], + 13056 => [0, 0, nil, "アパート", nil, nil, nil], + 13057 => [0, 0, nil, "アルファ", nil, nil, nil], + 13058 => [0, 0, nil, "アンペア", nil, nil, nil], + 13059 => [0, 0, nil, "アール", nil, nil, nil], + 13060 => [0, 0, nil, "イニング", nil, nil, nil], + 13061 => [0, 0, nil, "インチ", nil, nil, nil], + 13062 => [0, 0, nil, "ウォン", nil, nil, nil], + 13063 => [0, 0, nil, "エスクード", nil, nil, nil], + 13064 => [0, 0, nil, "エーカー", nil, nil, nil], + 13065 => [0, 0, nil, "オンス", nil, nil, nil], + 13066 => [0, 0, nil, "オーム", nil, nil, nil], + 13067 => [0, 0, nil, "カイリ", nil, nil, nil], + 13068 => [0, 0, nil, "カラット", nil, nil, nil], + 13069 => [0, 0, nil, "カロリー", nil, nil, nil], + 13070 => [0, 0, nil, "ガロン", nil, nil, nil], + 13071 => [0, 0, nil, "ガンマ", nil, nil, nil], + 13072 => [0, 0, nil, "ギガ", nil, nil, nil], + 13073 => [0, 0, nil, "ギニー", nil, nil, nil], + 13074 => [0, 0, nil, "キュリー", nil, nil, nil], + 13075 => [0, 0, nil, "ギルダー", nil, nil, nil], + 13076 => [0, 0, nil, "キロ", nil, nil, nil], + 13077 => [0, 0, nil, "キログラム", nil, nil, nil], + 13078 => [0, 0, nil, "キロメートル", nil, nil, nil], + 13079 => [0, 0, nil, "キロワット", nil, nil, nil], + 13080 => [0, 0, nil, "グラム", nil, nil, nil], + 13081 => [0, 0, nil, "グラムトン", nil, nil, nil], + 13082 => [0, 0, nil, "クルゼイロ", nil, nil, nil], + 13083 => [0, 0, nil, "クローネ", nil, nil, nil], + 13084 => [0, 0, nil, "ケース", nil, nil, nil], + 13085 => [0, 0, nil, "コルナ", nil, nil, nil], + 13086 => [0, 0, nil, "コーポ", nil, nil, nil], + 13087 => [0, 0, nil, "サイクル", nil, nil, nil], + 13088 => [0, 0, nil, "サンチーム", nil, nil, nil], + 13089 => [0, 0, nil, "シリング", nil, nil, nil], + 13090 => [0, 0, nil, "センチ", nil, nil, nil], + 13091 => [0, 0, nil, "セント", nil, nil, nil], + 13092 => [0, 0, nil, "ダース", nil, nil, nil], + 13093 => [0, 0, nil, "デシ", nil, nil, nil], + 13094 => [0, 0, nil, "ドル", nil, nil, nil], + 13095 => [0, 0, nil, "トン", nil, nil, nil], + 13096 => [0, 0, nil, "ナノ", nil, nil, nil], + 13097 => [0, 0, nil, "ノット", nil, nil, nil], + 13098 => [0, 0, nil, "ハイツ", nil, nil, nil], + 13099 => [0, 0, nil, "パーセント", nil, nil, nil], + 13100 => [0, 0, nil, "パーツ", nil, nil, nil], + 13101 => [0, 0, nil, "バーレル", nil, nil, nil], + 13102 => [0, 0, nil, "ピアストル", nil, nil, nil], + 13103 => [0, 0, nil, "ピクル", nil, nil, nil], + 13104 => [0, 0, nil, "ピコ", nil, nil, nil], + 13105 => [0, 0, nil, "ビル", nil, nil, nil], + 13106 => [0, 0, nil, "ファラッド", nil, nil, nil], + 13107 => [0, 0, nil, "フィート", nil, nil, nil], + 13108 => [0, 0, nil, "ブッシェル", nil, nil, nil], + 13109 => [0, 0, nil, "フラン", nil, nil, nil], + 13110 => [0, 0, nil, "ヘクタール", nil, nil, nil], + 13111 => [0, 0, nil, "ペソ", nil, nil, nil], + 13112 => [0, 0, nil, "ペニヒ", nil, nil, nil], + 13113 => [0, 0, nil, "ヘルツ", nil, nil, nil], + 13114 => [0, 0, nil, "ペンス", nil, nil, nil], + 13115 => [0, 0, nil, "ページ", nil, nil, nil], + 13116 => [0, 0, nil, "ベータ", nil, nil, nil], + 13117 => [0, 0, nil, "ポイント", nil, nil, nil], + 13118 => [0, 0, nil, "ボルト", nil, nil, nil], + 13119 => [0, 0, nil, "ホン", nil, nil, nil], + 13120 => [0, 0, nil, "ポンド", nil, nil, nil], + 13121 => [0, 0, nil, "ホール", nil, nil, nil], + 13122 => [0, 0, nil, "ホーン", nil, nil, nil], + 13123 => [0, 0, nil, "マイクロ", nil, nil, nil], + 13124 => [0, 0, nil, "マイル", nil, nil, nil], + 13125 => [0, 0, nil, "マッハ", nil, nil, nil], + 13126 => [0, 0, nil, "マルク", nil, nil, nil], + 13127 => [0, 0, nil, "マンション", nil, nil, nil], + 13128 => [0, 0, nil, "ミクロン", nil, nil, nil], + 13129 => [0, 0, nil, "ミリ", nil, nil, nil], + 13130 => [0, 0, nil, "ミリバール", nil, nil, nil], + 13131 => [0, 0, nil, "メガ", nil, nil, nil], + 13132 => [0, 0, nil, "メガトン", nil, nil, nil], + 13133 => [0, 0, nil, "メートル", nil, nil, nil], + 13134 => [0, 0, nil, "ヤード", nil, nil, nil], + 13135 => [0, 0, nil, "ヤール", nil, nil, nil], + 13136 => [0, 0, nil, "ユアン", nil, nil, nil], + 13137 => [0, 0, nil, "リットル", nil, nil, nil], + 13138 => [0, 0, nil, "リラ", nil, nil, nil], + 13139 => [0, 0, nil, "ルピー", nil, nil, nil], + 13140 => [0, 0, nil, "ルーブル", nil, nil, nil], + 13141 => [0, 0, nil, "レム", nil, nil, nil], + 13142 => [0, 0, nil, "レントゲン", nil, nil, nil], + 13143 => [0, 0, nil, "ワット", nil, nil, nil], + 13144 => [0, 0, nil, "0点", nil, nil, nil], + 13145 => [0, 0, nil, "1点", nil, nil, nil], + 13146 => [0, 0, nil, "2点", nil, nil, nil], + 13147 => [0, 0, nil, "3点", nil, nil, nil], + 13148 => [0, 0, nil, "4点", nil, nil, nil], + 13149 => [0, 0, nil, "5点", nil, nil, nil], + 13150 => [0, 0, nil, "6点", nil, nil, nil], + 13151 => [0, 0, nil, "7点", nil, nil, nil], + 13152 => [0, 0, nil, "8点", nil, nil, nil], + 13153 => [0, 0, nil, "9点", nil, nil, nil], + 13154 => [0, 0, nil, "10点", nil, nil, nil], + 13155 => [0, 0, nil, "11点", nil, nil, nil], + 13156 => [0, 0, nil, "12点", nil, nil, nil], + 13157 => [0, 0, nil, "13点", nil, nil, nil], + 13158 => [0, 0, nil, "14点", nil, nil, nil], + 13159 => [0, 0, nil, "15点", nil, nil, nil], + 13160 => [0, 0, nil, "16点", nil, nil, nil], + 13161 => [0, 0, nil, "17点", nil, nil, nil], + 13162 => [0, 0, nil, "18点", nil, nil, nil], + 13163 => [0, 0, nil, "19点", nil, nil, nil], + 13164 => [0, 0, nil, "20点", nil, nil, nil], + 13165 => [0, 0, nil, "21点", nil, nil, nil], + 13166 => [0, 0, nil, "22点", nil, nil, nil], + 13167 => [0, 0, nil, "23点", nil, nil, nil], + 13168 => [0, 0, nil, "24点", nil, nil, nil], + 13169 => [0, 0, nil, "hPa", nil, nil, nil], + 13170 => [0, 0, nil, "da", nil, nil, nil], + 13171 => [0, 0, nil, "AU", nil, nil, nil], + 13172 => [0, 0, nil, "bar", nil, nil, nil], + 13173 => [0, 0, nil, "oV", nil, nil, nil], + 13174 => [0, 0, nil, "pc", nil, nil, nil], + 13179 => [0, 0, nil, "平成", nil, nil, nil], + 13180 => [0, 0, nil, "昭和", nil, nil, nil], + 13181 => [0, 0, nil, "大正", nil, nil, nil], + 13182 => [0, 0, nil, "明治", nil, nil, nil], + 13183 => [0, 0, nil, "株式会社", nil, nil, nil], + 13184 => [0, 0, nil, "pA", nil, nil, nil], + 13185 => [0, 0, nil, "nA", nil, nil, nil], + 13186 => [0, 0, nil, "μA", nil, nil, nil], + 13187 => [0, 0, nil, "mA", nil, nil, nil], + 13188 => [0, 0, nil, "kA", nil, nil, nil], + 13189 => [0, 0, nil, "KB", nil, nil, nil], + 13190 => [0, 0, nil, "MB", nil, nil, nil], + 13191 => [0, 0, nil, "GB", nil, nil, nil], + 13192 => [0, 0, nil, "cal", nil, nil, nil], + 13193 => [0, 0, nil, "kcal", nil, nil, nil], + 13194 => [0, 0, nil, "pF", nil, nil, nil], + 13195 => [0, 0, nil, "nF", nil, nil, nil], + 13196 => [0, 0, nil, "μF", nil, nil, nil], + 13197 => [0, 0, nil, "μg", nil, nil, nil], + 13198 => [0, 0, nil, "mg", nil, nil, nil], + 13199 => [0, 0, nil, "kg", nil, nil, nil], + 13200 => [0, 0, nil, "Hz", nil, nil, nil], + 13201 => [0, 0, nil, "kHz", nil, nil, nil], + 13202 => [0, 0, nil, "MHz", nil, nil, nil], + 13203 => [0, 0, nil, "GHz", nil, nil, nil], + 13204 => [0, 0, nil, "THz", nil, nil, nil], + 13205 => [0, 0, nil, "μℓ", nil, nil, nil], + 13206 => [0, 0, nil, "mℓ", nil, nil, nil], + 13207 => [0, 0, nil, "dℓ", nil, nil, nil], + 13208 => [0, 0, nil, "kℓ", nil, nil, nil], + 13209 => [0, 0, nil, "fm", nil, nil, nil], + 13210 => [0, 0, nil, "nm", nil, nil, nil], + 13211 => [0, 0, nil, "μm", nil, nil, nil], + 13212 => [0, 0, nil, "mm", nil, nil, nil], + 13213 => [0, 0, nil, "cm", nil, nil, nil], + 13214 => [0, 0, nil, "km", nil, nil, nil], + 13215 => [0, 0, nil, "mm²", nil, nil, nil], + 13216 => [0, 0, nil, "cm²", nil, nil, nil], + 13217 => [0, 0, nil, "m²", nil, nil, nil], + 13218 => [0, 0, nil, "km²", nil, nil, nil], + 13219 => [0, 0, nil, "mm³", nil, nil, nil], + 13220 => [0, 0, nil, "cm³", nil, nil, nil], + 13221 => [0, 0, nil, "m³", nil, nil, nil], + 13222 => [0, 0, nil, "km³", nil, nil, nil], + 13223 => [0, 0, nil, "m∕s", nil, nil, nil], + 13224 => [0, 0, nil, "m∕s²", nil, nil, nil], + 13225 => [0, 0, nil, "Pa", nil, nil, nil], + 13226 => [0, 0, nil, "kPa", nil, nil, nil], + 13227 => [0, 0, nil, "MPa", nil, nil, nil], + 13228 => [0, 0, nil, "GPa", nil, nil, nil], + 13229 => [0, 0, nil, "rad", nil, nil, nil], + 13230 => [0, 0, nil, "rad∕s", nil, nil, nil], + 13231 => [0, 0, nil, "rad∕s²", nil, nil, nil], + 13232 => [0, 0, nil, "ps", nil, nil, nil], + 13233 => [0, 0, nil, "ns", nil, nil, nil], + 13234 => [0, 0, nil, "μs", nil, nil, nil], + 13235 => [0, 0, nil, "ms", nil, nil, nil], + 13236 => [0, 0, nil, "pV", nil, nil, nil], + 13237 => [0, 0, nil, "nV", nil, nil, nil], + 13238 => [0, 0, nil, "μV", nil, nil, nil], + 13239 => [0, 0, nil, "mV", nil, nil, nil], + 13240 => [0, 0, nil, "kV", nil, nil, nil], + 13241 => [0, 0, nil, "MV", nil, nil, nil], + 13242 => [0, 0, nil, "pW", nil, nil, nil], + 13243 => [0, 0, nil, "nW", nil, nil, nil], + 13244 => [0, 0, nil, "μW", nil, nil, nil], + 13245 => [0, 0, nil, "mW", nil, nil, nil], + 13246 => [0, 0, nil, "kW", nil, nil, nil], + 13247 => [0, 0, nil, "MW", nil, nil, nil], + 13248 => [0, 0, nil, "kΩ", nil, nil, nil], + 13249 => [0, 0, nil, "MΩ", nil, nil, nil], + 13250 => [0, 0, nil, "a.m.", nil, nil, nil], + 13251 => [0, 0, nil, "Bq", nil, nil, nil], + 13252 => [0, 0, nil, "cc", nil, nil, nil], + 13253 => [0, 0, nil, "cd", nil, nil, nil], + 13254 => [0, 0, nil, "C∕kg", nil, nil, nil], + 13255 => [0, 0, nil, "Co.", nil, nil, nil], + 13256 => [0, 0, nil, "dB", nil, nil, nil], + 13257 => [0, 0, nil, "Gy", nil, nil, nil], + 13258 => [0, 0, nil, "ha", nil, nil, nil], + 13259 => [0, 0, nil, "HP", nil, nil, nil], + 13260 => [0, 0, nil, "in", nil, nil, nil], + 13261 => [0, 0, nil, "KK", nil, nil, nil], + 13262 => [0, 0, nil, "KM", nil, nil, nil], + 13263 => [0, 0, nil, "kt", nil, nil, nil], + 13264 => [0, 0, nil, "lm", nil, nil, nil], + 13265 => [0, 0, nil, "ln", nil, nil, nil], + 13266 => [0, 0, nil, "log", nil, nil, nil], + 13267 => [0, 0, nil, "lx", nil, nil, nil], + 13268 => [0, 0, nil, "mb", nil, nil, nil], + 13269 => [0, 0, nil, "mil", nil, nil, nil], + 13270 => [0, 0, nil, "mol", nil, nil, nil], + 13271 => [0, 0, nil, "PH", nil, nil, nil], + 13272 => [0, 0, nil, "p.m.", nil, nil, nil], + 13273 => [0, 0, nil, "PPM", nil, nil, nil], + 13274 => [0, 0, nil, "PR", nil, nil, nil], + 13275 => [0, 0, nil, "sr", nil, nil, nil], + 13276 => [0, 0, nil, "Sv", nil, nil, nil], + 13277 => [0, 0, nil, "Wb", nil, nil, nil], + 13280 => [0, 0, nil, "1日", nil, nil, nil], + 13281 => [0, 0, nil, "2日", nil, nil, nil], + 13282 => [0, 0, nil, "3日", nil, nil, nil], + 13283 => [0, 0, nil, "4日", nil, nil, nil], + 13284 => [0, 0, nil, "5日", nil, nil, nil], + 13285 => [0, 0, nil, "6日", nil, nil, nil], + 13286 => [0, 0, nil, "7日", nil, nil, nil], + 13287 => [0, 0, nil, "8日", nil, nil, nil], + 13288 => [0, 0, nil, "9日", nil, nil, nil], + 13289 => [0, 0, nil, "10日", nil, nil, nil], + 13290 => [0, 0, nil, "11日", nil, nil, nil], + 13291 => [0, 0, nil, "12日", nil, nil, nil], + 13292 => [0, 0, nil, "13日", nil, nil, nil], + 13293 => [0, 0, nil, "14日", nil, nil, nil], + 13294 => [0, 0, nil, "15日", nil, nil, nil], + 13295 => [0, 0, nil, "16日", nil, nil, nil], + 13296 => [0, 0, nil, "17日", nil, nil, nil], + 13297 => [0, 0, nil, "18日", nil, nil, nil], + 13298 => [0, 0, nil, "19日", nil, nil, nil], + 13299 => [0, 0, nil, "20日", nil, nil, nil], + 13300 => [0, 0, nil, "21日", nil, nil, nil], + 13301 => [0, 0, nil, "22日", nil, nil, nil], + 13302 => [0, 0, nil, "23日", nil, nil, nil], + 13303 => [0, 0, nil, "24日", nil, nil, nil], + 13304 => [0, 0, nil, "25日", nil, nil, nil], + 13305 => [0, 0, nil, "26日", nil, nil, nil], + 13306 => [0, 0, nil, "27日", nil, nil, nil], + 13307 => [0, 0, nil, "28日", nil, nil, nil], + 13308 => [0, 0, nil, "29日", nil, nil, nil], + 13309 => [0, 0, nil, "30日", nil, nil, nil], + 13310 => [0, 0, nil, "31日", nil, nil, nil], + 63744 => [0, 2, "豈", "豈", nil, nil, nil], + 63745 => [0, 2, "更", "更", nil, nil, nil], + 63746 => [0, 2, "車", "車", nil, nil, nil], + 63747 => [0, 2, "賈", "賈", nil, nil, nil], + 63748 => [0, 2, "滑", "滑", nil, nil, nil], + 63749 => [0, 2, "串", "串", nil, nil, nil], + 63750 => [0, 2, "句", "句", nil, nil, nil], + 63751 => [0, 2, "龜", "龜", nil, nil, nil], + 63752 => [0, 2, "龜", "龜", nil, nil, nil], + 63753 => [0, 2, "契", "契", nil, nil, nil], + 63754 => [0, 2, "金", "金", nil, nil, nil], + 63755 => [0, 2, "喇", "喇", nil, nil, nil], + 63756 => [0, 2, "奈", "奈", nil, nil, nil], + 63757 => [0, 2, "懶", "懶", nil, nil, nil], + 63758 => [0, 2, "癩", "癩", nil, nil, nil], + 63759 => [0, 2, "羅", "羅", nil, nil, nil], + 63760 => [0, 2, "蘿", "蘿", nil, nil, nil], + 63761 => [0, 2, "螺", "螺", nil, nil, nil], + 63762 => [0, 2, "裸", "裸", nil, nil, nil], + 63763 => [0, 2, "邏", "邏", nil, nil, nil], + 63764 => [0, 2, "樂", "樂", nil, nil, nil], + 63765 => [0, 2, "洛", "洛", nil, nil, nil], + 63766 => [0, 2, "烙", "烙", nil, nil, nil], + 63767 => [0, 2, "珞", "珞", nil, nil, nil], + 63768 => [0, 2, "落", "落", nil, nil, nil], + 63769 => [0, 2, "酪", "酪", nil, nil, nil], + 63770 => [0, 2, "駱", "駱", nil, nil, nil], + 63771 => [0, 2, "亂", "亂", nil, nil, nil], + 63772 => [0, 2, "卵", "卵", nil, nil, nil], + 63773 => [0, 2, "欄", "欄", nil, nil, nil], + 63774 => [0, 2, "爛", "爛", nil, nil, nil], + 63775 => [0, 2, "蘭", "蘭", nil, nil, nil], + 63776 => [0, 2, "鸞", "鸞", nil, nil, nil], + 63777 => [0, 2, "嵐", "嵐", nil, nil, nil], + 63778 => [0, 2, "濫", "濫", nil, nil, nil], + 63779 => [0, 2, "藍", "藍", nil, nil, nil], + 63780 => [0, 2, "襤", "襤", nil, nil, nil], + 63781 => [0, 2, "拉", "拉", nil, nil, nil], + 63782 => [0, 2, "臘", "臘", nil, nil, nil], + 63783 => [0, 2, "蠟", "蠟", nil, nil, nil], + 63784 => [0, 2, "廊", "廊", nil, nil, nil], + 63785 => [0, 2, "朗", "朗", nil, nil, nil], + 63786 => [0, 2, "浪", "浪", nil, nil, nil], + 63787 => [0, 2, "狼", "狼", nil, nil, nil], + 63788 => [0, 2, "郎", "郎", nil, nil, nil], + 63789 => [0, 2, "來", "來", nil, nil, nil], + 63790 => [0, 2, "冷", "冷", nil, nil, nil], + 63791 => [0, 2, "勞", "勞", nil, nil, nil], + 63792 => [0, 2, "擄", "擄", nil, nil, nil], + 63793 => [0, 2, "櫓", "櫓", nil, nil, nil], + 63794 => [0, 2, "爐", "爐", nil, nil, nil], + 63795 => [0, 2, "盧", "盧", nil, nil, nil], + 63796 => [0, 2, "老", "老", nil, nil, nil], + 63797 => [0, 2, "蘆", "蘆", nil, nil, nil], + 63798 => [0, 2, "虜", "虜", nil, nil, nil], + 63799 => [0, 2, "路", "路", nil, nil, nil], + 63800 => [0, 2, "露", "露", nil, nil, nil], + 63801 => [0, 2, "魯", "魯", nil, nil, nil], + 63802 => [0, 2, "鷺", "鷺", nil, nil, nil], + 63803 => [0, 2, "碌", "碌", nil, nil, nil], + 63804 => [0, 2, "祿", "祿", nil, nil, nil], + 63805 => [0, 2, "綠", "綠", nil, nil, nil], + 63806 => [0, 2, "菉", "菉", nil, nil, nil], + 63807 => [0, 2, "錄", "錄", nil, nil, nil], + 63808 => [0, 2, "鹿", "鹿", nil, nil, nil], + 63809 => [0, 2, "論", "論", nil, nil, nil], + 63810 => [0, 2, "壟", "壟", nil, nil, nil], + 63811 => [0, 2, "弄", "弄", nil, nil, nil], + 63812 => [0, 2, "籠", "籠", nil, nil, nil], + 63813 => [0, 2, "聾", "聾", nil, nil, nil], + 63814 => [0, 2, "牢", "牢", nil, nil, nil], + 63815 => [0, 2, "磊", "磊", nil, nil, nil], + 63816 => [0, 2, "賂", "賂", nil, nil, nil], + 63817 => [0, 2, "雷", "雷", nil, nil, nil], + 63818 => [0, 2, "壘", "壘", nil, nil, nil], + 63819 => [0, 2, "屢", "屢", nil, nil, nil], + 63820 => [0, 2, "樓", "樓", nil, nil, nil], + 63821 => [0, 2, "淚", "淚", nil, nil, nil], + 63822 => [0, 2, "漏", "漏", nil, nil, nil], + 63823 => [0, 2, "累", "累", nil, nil, nil], + 63824 => [0, 2, "縷", "縷", nil, nil, nil], + 63825 => [0, 2, "電", "電", nil, nil, nil], + 63826 => [0, 2, "勒", "勒", nil, nil, nil], + 63827 => [0, 2, "肋", "肋", nil, nil, nil], + 63828 => [0, 2, "凜", "凜", nil, nil, nil], + 63829 => [0, 2, "凌", "凌", nil, nil, nil], + 63830 => [0, 2, "稜", "稜", nil, nil, nil], + 63831 => [0, 2, "綾", "綾", nil, nil, nil], + 63832 => [0, 2, "菱", "菱", nil, nil, nil], + 63833 => [0, 2, "陵", "陵", nil, nil, nil], + 63834 => [0, 2, "讀", "讀", nil, nil, nil], + 63835 => [0, 2, "拏", "拏", nil, nil, nil], + 63836 => [0, 2, "樂", "樂", nil, nil, nil], + 63837 => [0, 2, "諾", "諾", nil, nil, nil], + 63838 => [0, 2, "丹", "丹", nil, nil, nil], + 63839 => [0, 2, "寧", "寧", nil, nil, nil], + 63840 => [0, 2, "怒", "怒", nil, nil, nil], + 63841 => [0, 2, "率", "率", nil, nil, nil], + 63842 => [0, 2, "異", "異", nil, nil, nil], + 63843 => [0, 2, "北", "北", nil, nil, nil], + 63844 => [0, 2, "磻", "磻", nil, nil, nil], + 63845 => [0, 2, "便", "便", nil, nil, nil], + 63846 => [0, 2, "復", "復", nil, nil, nil], + 63847 => [0, 2, "不", "不", nil, nil, nil], + 63848 => [0, 2, "泌", "泌", nil, nil, nil], + 63849 => [0, 2, "數", "數", nil, nil, nil], + 63850 => [0, 2, "索", "索", nil, nil, nil], + 63851 => [0, 2, "參", "參", nil, nil, nil], + 63852 => [0, 2, "塞", "塞", nil, nil, nil], + 63853 => [0, 2, "省", "省", nil, nil, nil], + 63854 => [0, 2, "葉", "葉", nil, nil, nil], + 63855 => [0, 2, "說", "說", nil, nil, nil], + 63856 => [0, 2, "殺", "殺", nil, nil, nil], + 63857 => [0, 2, "辰", "辰", nil, nil, nil], + 63858 => [0, 2, "沈", "沈", nil, nil, nil], + 63859 => [0, 2, "拾", "拾", nil, nil, nil], + 63860 => [0, 2, "若", "若", nil, nil, nil], + 63861 => [0, 2, "掠", "掠", nil, nil, nil], + 63862 => [0, 2, "略", "略", nil, nil, nil], + 63863 => [0, 2, "亮", "亮", nil, nil, nil], + 63864 => [0, 2, "兩", "兩", nil, nil, nil], + 63865 => [0, 2, "凉", "凉", nil, nil, nil], + 63866 => [0, 2, "梁", "梁", nil, nil, nil], + 63867 => [0, 2, "糧", "糧", nil, nil, nil], + 63868 => [0, 2, "良", "良", nil, nil, nil], + 63869 => [0, 2, "諒", "諒", nil, nil, nil], + 63870 => [0, 2, "量", "量", nil, nil, nil], + 63871 => [0, 2, "勵", "勵", nil, nil, nil], + 63872 => [0, 2, "呂", "呂", nil, nil, nil], + 63873 => [0, 2, "女", "女", nil, nil, nil], + 63874 => [0, 2, "廬", "廬", nil, nil, nil], + 63875 => [0, 2, "旅", "旅", nil, nil, nil], + 63876 => [0, 2, "濾", "濾", nil, nil, nil], + 63877 => [0, 2, "礪", "礪", nil, nil, nil], + 63878 => [0, 2, "閭", "閭", nil, nil, nil], + 63879 => [0, 2, "驪", "驪", nil, nil, nil], + 63880 => [0, 2, "麗", "麗", nil, nil, nil], + 63881 => [0, 2, "黎", "黎", nil, nil, nil], + 63882 => [0, 2, "力", "力", nil, nil, nil], + 63883 => [0, 2, "曆", "曆", nil, nil, nil], + 63884 => [0, 2, "歷", "歷", nil, nil, nil], + 63885 => [0, 2, "轢", "轢", nil, nil, nil], + 63886 => [0, 2, "年", "年", nil, nil, nil], + 63887 => [0, 2, "憐", "憐", nil, nil, nil], + 63888 => [0, 2, "戀", "戀", nil, nil, nil], + 63889 => [0, 2, "撚", "撚", nil, nil, nil], + 63890 => [0, 2, "漣", "漣", nil, nil, nil], + 63891 => [0, 2, "煉", "煉", nil, nil, nil], + 63892 => [0, 2, "璉", "璉", nil, nil, nil], + 63893 => [0, 2, "秊", "秊", nil, nil, nil], + 63894 => [0, 2, "練", "練", nil, nil, nil], + 63895 => [0, 2, "聯", "聯", nil, nil, nil], + 63896 => [0, 2, "輦", "輦", nil, nil, nil], + 63897 => [0, 2, "蓮", "蓮", nil, nil, nil], + 63898 => [0, 2, "連", "連", nil, nil, nil], + 63899 => [0, 2, "鍊", "鍊", nil, nil, nil], + 63900 => [0, 2, "列", "列", nil, nil, nil], + 63901 => [0, 2, "劣", "劣", nil, nil, nil], + 63902 => [0, 2, "咽", "咽", nil, nil, nil], + 63903 => [0, 2, "烈", "烈", nil, nil, nil], + 63904 => [0, 2, "裂", "裂", nil, nil, nil], + 63905 => [0, 2, "說", "說", nil, nil, nil], + 63906 => [0, 2, "廉", "廉", nil, nil, nil], + 63907 => [0, 2, "念", "念", nil, nil, nil], + 63908 => [0, 2, "捻", "捻", nil, nil, nil], + 63909 => [0, 2, "殮", "殮", nil, nil, nil], + 63910 => [0, 2, "簾", "簾", nil, nil, nil], + 63911 => [0, 2, "獵", "獵", nil, nil, nil], + 63912 => [0, 2, "令", "令", nil, nil, nil], + 63913 => [0, 2, "囹", "囹", nil, nil, nil], + 63914 => [0, 2, "寧", "寧", nil, nil, nil], + 63915 => [0, 2, "嶺", "嶺", nil, nil, nil], + 63916 => [0, 2, "怜", "怜", nil, nil, nil], + 63917 => [0, 2, "玲", "玲", nil, nil, nil], + 63918 => [0, 2, "瑩", "瑩", nil, nil, nil], + 63919 => [0, 2, "羚", "羚", nil, nil, nil], + 63920 => [0, 2, "聆", "聆", nil, nil, nil], + 63921 => [0, 2, "鈴", "鈴", nil, nil, nil], + 63922 => [0, 2, "零", "零", nil, nil, nil], + 63923 => [0, 2, "靈", "靈", nil, nil, nil], + 63924 => [0, 2, "領", "領", nil, nil, nil], + 63925 => [0, 2, "例", "例", nil, nil, nil], + 63926 => [0, 2, "禮", "禮", nil, nil, nil], + 63927 => [0, 2, "醴", "醴", nil, nil, nil], + 63928 => [0, 2, "隸", "隸", nil, nil, nil], + 63929 => [0, 2, "惡", "惡", nil, nil, nil], + 63930 => [0, 2, "了", "了", nil, nil, nil], + 63931 => [0, 2, "僚", "僚", nil, nil, nil], + 63932 => [0, 2, "寮", "寮", nil, nil, nil], + 63933 => [0, 2, "尿", "尿", nil, nil, nil], + 63934 => [0, 2, "料", "料", nil, nil, nil], + 63935 => [0, 2, "樂", "樂", nil, nil, nil], + 63936 => [0, 2, "燎", "燎", nil, nil, nil], + 63937 => [0, 2, "療", "療", nil, nil, nil], + 63938 => [0, 2, "蓼", "蓼", nil, nil, nil], + 63939 => [0, 2, "遼", "遼", nil, nil, nil], + 63940 => [0, 2, "龍", "龍", nil, nil, nil], + 63941 => [0, 2, "暈", "暈", nil, nil, nil], + 63942 => [0, 2, "阮", "阮", nil, nil, nil], + 63943 => [0, 2, "劉", "劉", nil, nil, nil], + 63944 => [0, 2, "杻", "杻", nil, nil, nil], + 63945 => [0, 2, "柳", "柳", nil, nil, nil], + 63946 => [0, 2, "流", "流", nil, nil, nil], + 63947 => [0, 2, "溜", "溜", nil, nil, nil], + 63948 => [0, 2, "琉", "琉", nil, nil, nil], + 63949 => [0, 2, "留", "留", nil, nil, nil], + 63950 => [0, 2, "硫", "硫", nil, nil, nil], + 63951 => [0, 2, "紐", "紐", nil, nil, nil], + 63952 => [0, 2, "類", "類", nil, nil, nil], + 63953 => [0, 2, "六", "六", nil, nil, nil], + 63954 => [0, 2, "戮", "戮", nil, nil, nil], + 63955 => [0, 2, "陸", "陸", nil, nil, nil], + 63956 => [0, 2, "倫", "倫", nil, nil, nil], + 63957 => [0, 2, "崙", "崙", nil, nil, nil], + 63958 => [0, 2, "淪", "淪", nil, nil, nil], + 63959 => [0, 2, "輪", "輪", nil, nil, nil], + 63960 => [0, 2, "律", "律", nil, nil, nil], + 63961 => [0, 2, "慄", "慄", nil, nil, nil], + 63962 => [0, 2, "栗", "栗", nil, nil, nil], + 63963 => [0, 2, "率", "率", nil, nil, nil], + 63964 => [0, 2, "隆", "隆", nil, nil, nil], + 63965 => [0, 2, "利", "利", nil, nil, nil], + 63966 => [0, 2, "吏", "吏", nil, nil, nil], + 63967 => [0, 2, "履", "履", nil, nil, nil], + 63968 => [0, 2, "易", "易", nil, nil, nil], + 63969 => [0, 2, "李", "李", nil, nil, nil], + 63970 => [0, 2, "梨", "梨", nil, nil, nil], + 63971 => [0, 2, "泥", "泥", nil, nil, nil], + 63972 => [0, 2, "理", "理", nil, nil, nil], + 63973 => [0, 2, "痢", "痢", nil, nil, nil], + 63974 => [0, 2, "罹", "罹", nil, nil, nil], + 63975 => [0, 2, "裏", "裏", nil, nil, nil], + 63976 => [0, 2, "裡", "裡", nil, nil, nil], + 63977 => [0, 2, "里", "里", nil, nil, nil], + 63978 => [0, 2, "離", "離", nil, nil, nil], + 63979 => [0, 2, "匿", "匿", nil, nil, nil], + 63980 => [0, 2, "溺", "溺", nil, nil, nil], + 63981 => [0, 2, "吝", "吝", nil, nil, nil], + 63982 => [0, 2, "燐", "燐", nil, nil, nil], + 63983 => [0, 2, "璘", "璘", nil, nil, nil], + 63984 => [0, 2, "藺", "藺", nil, nil, nil], + 63985 => [0, 2, "隣", "隣", nil, nil, nil], + 63986 => [0, 2, "鱗", "鱗", nil, nil, nil], + 63987 => [0, 2, "麟", "麟", nil, nil, nil], + 63988 => [0, 2, "林", "林", nil, nil, nil], + 63989 => [0, 2, "淋", "淋", nil, nil, nil], + 63990 => [0, 2, "臨", "臨", nil, nil, nil], + 63991 => [0, 2, "立", "立", nil, nil, nil], + 63992 => [0, 2, "笠", "笠", nil, nil, nil], + 63993 => [0, 2, "粒", "粒", nil, nil, nil], + 63994 => [0, 2, "狀", "狀", nil, nil, nil], + 63995 => [0, 2, "炙", "炙", nil, nil, nil], + 63996 => [0, 2, "識", "識", nil, nil, nil], + 63997 => [0, 2, "什", "什", nil, nil, nil], + 63998 => [0, 2, "茶", "茶", nil, nil, nil], + 63999 => [0, 2, "刺", "刺", nil, nil, nil], + 64000 => [0, 2, "切", "切", nil, nil, nil], + 64001 => [0, 2, "度", "度", nil, nil, nil], + 64002 => [0, 2, "拓", "拓", nil, nil, nil], + 64003 => [0, 2, "糖", "糖", nil, nil, nil], + 64004 => [0, 2, "宅", "宅", nil, nil, nil], + 64005 => [0, 2, "洞", "洞", nil, nil, nil], + 64006 => [0, 2, "暴", "暴", nil, nil, nil], + 64007 => [0, 2, "輻", "輻", nil, nil, nil], + 64008 => [0, 2, "行", "行", nil, nil, nil], + 64009 => [0, 2, "降", "降", nil, nil, nil], + 64010 => [0, 2, "見", "見", nil, nil, nil], + 64011 => [0, 2, "廓", "廓", nil, nil, nil], + 64012 => [0, 2, "兀", "兀", nil, nil, nil], + 64013 => [0, 2, "嗀", "嗀", nil, nil, nil], + 64016 => [0, 2, "塚", "塚", nil, nil, nil], + 64018 => [0, 2, "晴", "晴", nil, nil, nil], + 64021 => [0, 2, "凞", "凞", nil, nil, nil], + 64022 => [0, 2, "猪", "猪", nil, nil, nil], + 64023 => [0, 2, "益", "益", nil, nil, nil], + 64024 => [0, 2, "礼", "礼", nil, nil, nil], + 64025 => [0, 2, "神", "神", nil, nil, nil], + 64026 => [0, 2, "祥", "祥", nil, nil, nil], + 64027 => [0, 2, "福", "福", nil, nil, nil], + 64028 => [0, 2, "靖", "靖", nil, nil, nil], + 64029 => [0, 2, "精", "精", nil, nil, nil], + 64030 => [0, 2, "羽", "羽", nil, nil, nil], + 64032 => [0, 2, "蘒", "蘒", nil, nil, nil], + 64034 => [0, 2, "諸", "諸", nil, nil, nil], + 64037 => [0, 2, "逸", "逸", nil, nil, nil], + 64038 => [0, 2, "都", "都", nil, nil, nil], + 64042 => [0, 2, "飯", "飯", nil, nil, nil], + 64043 => [0, 2, "飼", "飼", nil, nil, nil], + 64044 => [0, 2, "館", "館", nil, nil, nil], + 64045 => [0, 2, "鶴", "鶴", nil, nil, nil], + 64256 => [0, 0, nil, "ff", nil, nil, nil], + 64257 => [0, 0, nil, "fi", nil, nil, nil], + 64258 => [0, 0, nil, "fl", nil, nil, nil], + 64259 => [0, 0, nil, "ffi", nil, nil, nil], + 64260 => [0, 0, nil, "ffl", nil, nil, nil], + 64261 => [0, 0, nil, "ſt", nil, nil, nil], + 64262 => [0, 0, nil, "st", nil, nil, nil], + 64275 => [0, 0, nil, "մն", nil, nil, nil], + 64276 => [0, 0, nil, "մե", nil, nil, nil], + 64277 => [0, 0, nil, "մի", nil, nil, nil], + 64278 => [0, 0, nil, "վն", nil, nil, nil], + 64279 => [0, 0, nil, "մխ", nil, nil, nil], + 64285 => [0, 0, "יִ", "יִ", nil, nil, nil], + 64286 => [26, 0, nil, nil, nil, nil, nil], + 64287 => [0, 1, "ײַ", "ײַ", nil, nil, nil], + 64288 => [0, 0, nil, "ע", nil, nil, nil], + 64289 => [0, 0, nil, "א", nil, nil, nil], + 64290 => [0, 0, nil, "ד", nil, nil, nil], + 64291 => [0, 0, nil, "ה", nil, nil, nil], + 64292 => [0, 0, nil, "כ", nil, nil, nil], + 64293 => [0, 0, nil, "ל", nil, nil, nil], + 64294 => [0, 0, nil, "ם", nil, nil, nil], + 64295 => [0, 0, nil, "ר", nil, nil, nil], + 64296 => [0, 0, nil, "ת", nil, nil, nil], + 64297 => [0, 0, nil, "+", nil, nil, nil], + 64298 => [0, 1, "שׁ", "שׁ", nil, nil, nil], + 64299 => [0, 1, "שׂ", "שׂ", nil, nil, nil], + 64300 => [0, 1, "שּׁ", "שּׁ", nil, nil, nil], + 64301 => [0, 1, "שּׂ", "שּׂ", nil, nil, nil], + 64302 => [0, 1, "אַ", "אַ", nil, nil, nil], + 64303 => [0, 1, "אָ", "אָ", nil, nil, nil], + 64304 => [0, 1, "אּ", "אּ", nil, nil, nil], + 64305 => [0, 1, "בּ", "בּ", nil, nil, nil], + 64306 => [0, 1, "גּ", "גּ", nil, nil, nil], + 64307 => [0, 1, "דּ", "דּ", nil, nil, nil], + 64308 => [0, 1, "הּ", "הּ", nil, nil, nil], + 64309 => [0, 1, "וּ", "וּ", nil, nil, nil], + 64310 => [0, 1, "זּ", "זּ", nil, nil, nil], + 64312 => [0, 1, "טּ", "טּ", nil, nil, nil], + 64313 => [0, 1, "יּ", "יּ", nil, nil, nil], + 64314 => [0, 1, "ךּ", "ךּ", nil, nil, nil], + 64315 => [0, 1, "כּ", "כּ", nil, nil, nil], + 64316 => [0, 1, "לּ", "לּ", nil, nil, nil], + 64318 => [0, 1, "מּ", "מּ", nil, nil, nil], + 64320 => [0, 1, "נּ", "נּ", nil, nil, nil], + 64321 => [0, 1, "סּ", "סּ", nil, nil, nil], + 64323 => [0, 1, "ףּ", "ףּ", nil, nil, nil], + 64324 => [0, 1, "פּ", "פּ", nil, nil, nil], + 64326 => [0, 1, "צּ", "צּ", nil, nil, nil], + 64327 => [0, 1, "קּ", "קּ", nil, nil, nil], + 64328 => [0, 1, "רּ", "רּ", nil, nil, nil], + 64329 => [0, 1, "שּ", "שּ", nil, nil, nil], + 64330 => [0, 1, "תּ", "תּ", nil, nil, nil], + 64331 => [0, 1, "וֹ", "וֹ", nil, nil, nil], + 64332 => [0, 1, "בֿ", "בֿ", nil, nil, nil], + 64333 => [0, 1, "כֿ", "כֿ", nil, nil, nil], + 64334 => [0, 1, "פֿ", "פֿ", nil, nil, nil], + 64335 => [0, 0, nil, "אל", nil, nil, nil], + 64336 => [0, 0, nil, "ٱ", nil, nil, nil], + 64337 => [0, 0, nil, "ٱ", nil, nil, nil], + 64338 => [0, 0, nil, "ٻ", nil, nil, nil], + 64339 => [0, 0, nil, "ٻ", nil, nil, nil], + 64340 => [0, 0, nil, "ٻ", nil, nil, nil], + 64341 => [0, 0, nil, "ٻ", nil, nil, nil], + 64342 => [0, 0, nil, "پ", nil, nil, nil], + 64343 => [0, 0, nil, "پ", nil, nil, nil], + 64344 => [0, 0, nil, "پ", nil, nil, nil], + 64345 => [0, 0, nil, "پ", nil, nil, nil], + 64346 => [0, 0, nil, "ڀ", nil, nil, nil], + 64347 => [0, 0, nil, "ڀ", nil, nil, nil], + 64348 => [0, 0, nil, "ڀ", nil, nil, nil], + 64349 => [0, 0, nil, "ڀ", nil, nil, nil], + 64350 => [0, 0, nil, "ٺ", nil, nil, nil], + 64351 => [0, 0, nil, "ٺ", nil, nil, nil], + 64352 => [0, 0, nil, "ٺ", nil, nil, nil], + 64353 => [0, 0, nil, "ٺ", nil, nil, nil], + 64354 => [0, 0, nil, "ٿ", nil, nil, nil], + 64355 => [0, 0, nil, "ٿ", nil, nil, nil], + 64356 => [0, 0, nil, "ٿ", nil, nil, nil], + 64357 => [0, 0, nil, "ٿ", nil, nil, nil], + 64358 => [0, 0, nil, "ٹ", nil, nil, nil], + 64359 => [0, 0, nil, "ٹ", nil, nil, nil], + 64360 => [0, 0, nil, "ٹ", nil, nil, nil], + 64361 => [0, 0, nil, "ٹ", nil, nil, nil], + 64362 => [0, 0, nil, "ڤ", nil, nil, nil], + 64363 => [0, 0, nil, "ڤ", nil, nil, nil], + 64364 => [0, 0, nil, "ڤ", nil, nil, nil], + 64365 => [0, 0, nil, "ڤ", nil, nil, nil], + 64366 => [0, 0, nil, "ڦ", nil, nil, nil], + 64367 => [0, 0, nil, "ڦ", nil, nil, nil], + 64368 => [0, 0, nil, "ڦ", nil, nil, nil], + 64369 => [0, 0, nil, "ڦ", nil, nil, nil], + 64370 => [0, 0, nil, "ڄ", nil, nil, nil], + 64371 => [0, 0, nil, "ڄ", nil, nil, nil], + 64372 => [0, 0, nil, "ڄ", nil, nil, nil], + 64373 => [0, 0, nil, "ڄ", nil, nil, nil], + 64374 => [0, 0, nil, "ڃ", nil, nil, nil], + 64375 => [0, 0, nil, "ڃ", nil, nil, nil], + 64376 => [0, 0, nil, "ڃ", nil, nil, nil], + 64377 => [0, 0, nil, "ڃ", nil, nil, nil], + 64378 => [0, 0, nil, "چ", nil, nil, nil], + 64379 => [0, 0, nil, "چ", nil, nil, nil], + 64380 => [0, 0, nil, "چ", nil, nil, nil], + 64381 => [0, 0, nil, "چ", nil, nil, nil], + 64382 => [0, 0, nil, "ڇ", nil, nil, nil], + 64383 => [0, 0, nil, "ڇ", nil, nil, nil], + 64384 => [0, 0, nil, "ڇ", nil, nil, nil], + 64385 => [0, 0, nil, "ڇ", nil, nil, nil], + 64386 => [0, 0, nil, "ڍ", nil, nil, nil], + 64387 => [0, 0, nil, "ڍ", nil, nil, nil], + 64388 => [0, 0, nil, "ڌ", nil, nil, nil], + 64389 => [0, 0, nil, "ڌ", nil, nil, nil], + 64390 => [0, 0, nil, "ڎ", nil, nil, nil], + 64391 => [0, 0, nil, "ڎ", nil, nil, nil], + 64392 => [0, 0, nil, "ڈ", nil, nil, nil], + 64393 => [0, 0, nil, "ڈ", nil, nil, nil], + 64394 => [0, 0, nil, "ژ", nil, nil, nil], + 64395 => [0, 0, nil, "ژ", nil, nil, nil], + 64396 => [0, 0, nil, "ڑ", nil, nil, nil], + 64397 => [0, 0, nil, "ڑ", nil, nil, nil], + 64398 => [0, 0, nil, "ک", nil, nil, nil], + 64399 => [0, 0, nil, "ک", nil, nil, nil], + 64400 => [0, 0, nil, "ک", nil, nil, nil], + 64401 => [0, 0, nil, "ک", nil, nil, nil], + 64402 => [0, 0, nil, "گ", nil, nil, nil], + 64403 => [0, 0, nil, "گ", nil, nil, nil], + 64404 => [0, 0, nil, "گ", nil, nil, nil], + 64405 => [0, 0, nil, "گ", nil, nil, nil], + 64406 => [0, 0, nil, "ڳ", nil, nil, nil], + 64407 => [0, 0, nil, "ڳ", nil, nil, nil], + 64408 => [0, 0, nil, "ڳ", nil, nil, nil], + 64409 => [0, 0, nil, "ڳ", nil, nil, nil], + 64410 => [0, 0, nil, "ڱ", nil, nil, nil], + 64411 => [0, 0, nil, "ڱ", nil, nil, nil], + 64412 => [0, 0, nil, "ڱ", nil, nil, nil], + 64413 => [0, 0, nil, "ڱ", nil, nil, nil], + 64414 => [0, 0, nil, "ں", nil, nil, nil], + 64415 => [0, 0, nil, "ں", nil, nil, nil], + 64416 => [0, 0, nil, "ڻ", nil, nil, nil], + 64417 => [0, 0, nil, "ڻ", nil, nil, nil], + 64418 => [0, 0, nil, "ڻ", nil, nil, nil], + 64419 => [0, 0, nil, "ڻ", nil, nil, nil], + 64420 => [0, 0, nil, "ۀ", nil, nil, nil], + 64421 => [0, 0, nil, "ۀ", nil, nil, nil], + 64422 => [0, 0, nil, "ہ", nil, nil, nil], + 64423 => [0, 0, nil, "ہ", nil, nil, nil], + 64424 => [0, 0, nil, "ہ", nil, nil, nil], + 64425 => [0, 0, nil, "ہ", nil, nil, nil], + 64426 => [0, 0, nil, "ھ", nil, nil, nil], + 64427 => [0, 0, nil, "ھ", nil, nil, nil], + 64428 => [0, 0, nil, "ھ", nil, nil, nil], + 64429 => [0, 0, nil, "ھ", nil, nil, nil], + 64430 => [0, 0, nil, "ے", nil, nil, nil], + 64431 => [0, 0, nil, "ے", nil, nil, nil], + 64432 => [0, 0, nil, "ۓ", nil, nil, nil], + 64433 => [0, 0, nil, "ۓ", nil, nil, nil], + 64467 => [0, 0, nil, "ڭ", nil, nil, nil], + 64468 => [0, 0, nil, "ڭ", nil, nil, nil], + 64469 => [0, 0, nil, "ڭ", nil, nil, nil], + 64470 => [0, 0, nil, "ڭ", nil, nil, nil], + 64471 => [0, 0, nil, "ۇ", nil, nil, nil], + 64472 => [0, 0, nil, "ۇ", nil, nil, nil], + 64473 => [0, 0, nil, "ۆ", nil, nil, nil], + 64474 => [0, 0, nil, "ۆ", nil, nil, nil], + 64475 => [0, 0, nil, "ۈ", nil, nil, nil], + 64476 => [0, 0, nil, "ۈ", nil, nil, nil], + 64477 => [0, 0, nil, "ٷ", nil, nil, nil], + 64478 => [0, 0, nil, "ۋ", nil, nil, nil], + 64479 => [0, 0, nil, "ۋ", nil, nil, nil], + 64480 => [0, 0, nil, "ۅ", nil, nil, nil], + 64481 => [0, 0, nil, "ۅ", nil, nil, nil], + 64482 => [0, 0, nil, "ۉ", nil, nil, nil], + 64483 => [0, 0, nil, "ۉ", nil, nil, nil], + 64484 => [0, 0, nil, "ې", nil, nil, nil], + 64485 => [0, 0, nil, "ې", nil, nil, nil], + 64486 => [0, 0, nil, "ې", nil, nil, nil], + 64487 => [0, 0, nil, "ې", nil, nil, nil], + 64488 => [0, 0, nil, "ى", nil, nil, nil], + 64489 => [0, 0, nil, "ى", nil, nil, nil], + 64490 => [0, 0, nil, "ئا", nil, nil, nil], + 64491 => [0, 0, nil, "ئا", nil, nil, nil], + 64492 => [0, 0, nil, "ئە", nil, nil, nil], + 64493 => [0, 0, nil, "ئە", nil, nil, nil], + 64494 => [0, 0, nil, "ئو", nil, nil, nil], + 64495 => [0, 0, nil, "ئو", nil, nil, nil], + 64496 => [0, 0, nil, "ئۇ", nil, nil, nil], + 64497 => [0, 0, nil, "ئۇ", nil, nil, nil], + 64498 => [0, 0, nil, "ئۆ", nil, nil, nil], + 64499 => [0, 0, nil, "ئۆ", nil, nil, nil], + 64500 => [0, 0, nil, "ئۈ", nil, nil, nil], + 64501 => [0, 0, nil, "ئۈ", nil, nil, nil], + 64502 => [0, 0, nil, "ئې", nil, nil, nil], + 64503 => [0, 0, nil, "ئې", nil, nil, nil], + 64504 => [0, 0, nil, "ئې", nil, nil, nil], + 64505 => [0, 0, nil, "ئى", nil, nil, nil], + 64506 => [0, 0, nil, "ئى", nil, nil, nil], + 64507 => [0, 0, nil, "ئى", nil, nil, nil], + 64508 => [0, 0, nil, "ی", nil, nil, nil], + 64509 => [0, 0, nil, "ی", nil, nil, nil], + 64510 => [0, 0, nil, "ی", nil, nil, nil], + 64511 => [0, 0, nil, "ی", nil, nil, nil], + 64512 => [0, 0, nil, "ئج", nil, nil, nil], + 64513 => [0, 0, nil, "ئح", nil, nil, nil], + 64514 => [0, 0, nil, "ئم", nil, nil, nil], + 64515 => [0, 0, nil, "ئى", nil, nil, nil], + 64516 => [0, 0, nil, "ئي", nil, nil, nil], + 64517 => [0, 0, nil, "بج", nil, nil, nil], + 64518 => [0, 0, nil, "بح", nil, nil, nil], + 64519 => [0, 0, nil, "بخ", nil, nil, nil], + 64520 => [0, 0, nil, "بم", nil, nil, nil], + 64521 => [0, 0, nil, "بى", nil, nil, nil], + 64522 => [0, 0, nil, "بي", nil, nil, nil], + 64523 => [0, 0, nil, "تج", nil, nil, nil], + 64524 => [0, 0, nil, "تح", nil, nil, nil], + 64525 => [0, 0, nil, "تخ", nil, nil, nil], + 64526 => [0, 0, nil, "تم", nil, nil, nil], + 64527 => [0, 0, nil, "تى", nil, nil, nil], + 64528 => [0, 0, nil, "تي", nil, nil, nil], + 64529 => [0, 0, nil, "ثج", nil, nil, nil], + 64530 => [0, 0, nil, "ثم", nil, nil, nil], + 64531 => [0, 0, nil, "ثى", nil, nil, nil], + 64532 => [0, 0, nil, "ثي", nil, nil, nil], + 64533 => [0, 0, nil, "جح", nil, nil, nil], + 64534 => [0, 0, nil, "جم", nil, nil, nil], + 64535 => [0, 0, nil, "حج", nil, nil, nil], + 64536 => [0, 0, nil, "حم", nil, nil, nil], + 64537 => [0, 0, nil, "خج", nil, nil, nil], + 64538 => [0, 0, nil, "خح", nil, nil, nil], + 64539 => [0, 0, nil, "خم", nil, nil, nil], + 64540 => [0, 0, nil, "سج", nil, nil, nil], + 64541 => [0, 0, nil, "سح", nil, nil, nil], + 64542 => [0, 0, nil, "سخ", nil, nil, nil], + 64543 => [0, 0, nil, "سم", nil, nil, nil], + 64544 => [0, 0, nil, "صح", nil, nil, nil], + 64545 => [0, 0, nil, "صم", nil, nil, nil], + 64546 => [0, 0, nil, "ضج", nil, nil, nil], + 64547 => [0, 0, nil, "ضح", nil, nil, nil], + 64548 => [0, 0, nil, "ضخ", nil, nil, nil], + 64549 => [0, 0, nil, "ضم", nil, nil, nil], + 64550 => [0, 0, nil, "طح", nil, nil, nil], + 64551 => [0, 0, nil, "طم", nil, nil, nil], + 64552 => [0, 0, nil, "ظم", nil, nil, nil], + 64553 => [0, 0, nil, "عج", nil, nil, nil], + 64554 => [0, 0, nil, "عم", nil, nil, nil], + 64555 => [0, 0, nil, "غج", nil, nil, nil], + 64556 => [0, 0, nil, "غم", nil, nil, nil], + 64557 => [0, 0, nil, "فج", nil, nil, nil], + 64558 => [0, 0, nil, "فح", nil, nil, nil], + 64559 => [0, 0, nil, "فخ", nil, nil, nil], + 64560 => [0, 0, nil, "فم", nil, nil, nil], + 64561 => [0, 0, nil, "فى", nil, nil, nil], + 64562 => [0, 0, nil, "في", nil, nil, nil], + 64563 => [0, 0, nil, "قح", nil, nil, nil], + 64564 => [0, 0, nil, "قم", nil, nil, nil], + 64565 => [0, 0, nil, "قى", nil, nil, nil], + 64566 => [0, 0, nil, "قي", nil, nil, nil], + 64567 => [0, 0, nil, "كا", nil, nil, nil], + 64568 => [0, 0, nil, "كج", nil, nil, nil], + 64569 => [0, 0, nil, "كح", nil, nil, nil], + 64570 => [0, 0, nil, "كخ", nil, nil, nil], + 64571 => [0, 0, nil, "كل", nil, nil, nil], + 64572 => [0, 0, nil, "كم", nil, nil, nil], + 64573 => [0, 0, nil, "كى", nil, nil, nil], + 64574 => [0, 0, nil, "كي", nil, nil, nil], + 64575 => [0, 0, nil, "لج", nil, nil, nil], + 64576 => [0, 0, nil, "لح", nil, nil, nil], + 64577 => [0, 0, nil, "لخ", nil, nil, nil], + 64578 => [0, 0, nil, "لم", nil, nil, nil], + 64579 => [0, 0, nil, "لى", nil, nil, nil], + 64580 => [0, 0, nil, "لي", nil, nil, nil], + 64581 => [0, 0, nil, "مج", nil, nil, nil], + 64582 => [0, 0, nil, "مح", nil, nil, nil], + 64583 => [0, 0, nil, "مخ", nil, nil, nil], + 64584 => [0, 0, nil, "مم", nil, nil, nil], + 64585 => [0, 0, nil, "مى", nil, nil, nil], + 64586 => [0, 0, nil, "مي", nil, nil, nil], + 64587 => [0, 0, nil, "نج", nil, nil, nil], + 64588 => [0, 0, nil, "نح", nil, nil, nil], + 64589 => [0, 0, nil, "نخ", nil, nil, nil], + 64590 => [0, 0, nil, "نم", nil, nil, nil], + 64591 => [0, 0, nil, "نى", nil, nil, nil], + 64592 => [0, 0, nil, "ني", nil, nil, nil], + 64593 => [0, 0, nil, "هج", nil, nil, nil], + 64594 => [0, 0, nil, "هم", nil, nil, nil], + 64595 => [0, 0, nil, "هى", nil, nil, nil], + 64596 => [0, 0, nil, "هي", nil, nil, nil], + 64597 => [0, 0, nil, "يج", nil, nil, nil], + 64598 => [0, 0, nil, "يح", nil, nil, nil], + 64599 => [0, 0, nil, "يخ", nil, nil, nil], + 64600 => [0, 0, nil, "يم", nil, nil, nil], + 64601 => [0, 0, nil, "يى", nil, nil, nil], + 64602 => [0, 0, nil, "يي", nil, nil, nil], + 64603 => [0, 0, nil, "ذٰ", nil, nil, nil], + 64604 => [0, 0, nil, "رٰ", nil, nil, nil], + 64605 => [0, 0, nil, "ىٰ", nil, nil, nil], + 64606 => [0, 0, nil, " ٌّ", nil, nil, nil], + 64607 => [0, 0, nil, " ٍّ", nil, nil, nil], + 64608 => [0, 0, nil, " َّ", nil, nil, nil], + 64609 => [0, 0, nil, " ُّ", nil, nil, nil], + 64610 => [0, 0, nil, " ِّ", nil, nil, nil], + 64611 => [0, 0, nil, " ّٰ", nil, nil, nil], + 64612 => [0, 0, nil, "ئر", nil, nil, nil], + 64613 => [0, 0, nil, "ئز", nil, nil, nil], + 64614 => [0, 0, nil, "ئم", nil, nil, nil], + 64615 => [0, 0, nil, "ئن", nil, nil, nil], + 64616 => [0, 0, nil, "ئى", nil, nil, nil], + 64617 => [0, 0, nil, "ئي", nil, nil, nil], + 64618 => [0, 0, nil, "بر", nil, nil, nil], + 64619 => [0, 0, nil, "بز", nil, nil, nil], + 64620 => [0, 0, nil, "بم", nil, nil, nil], + 64621 => [0, 0, nil, "بن", nil, nil, nil], + 64622 => [0, 0, nil, "بى", nil, nil, nil], + 64623 => [0, 0, nil, "بي", nil, nil, nil], + 64624 => [0, 0, nil, "تر", nil, nil, nil], + 64625 => [0, 0, nil, "تز", nil, nil, nil], + 64626 => [0, 0, nil, "تم", nil, nil, nil], + 64627 => [0, 0, nil, "تن", nil, nil, nil], + 64628 => [0, 0, nil, "تى", nil, nil, nil], + 64629 => [0, 0, nil, "تي", nil, nil, nil], + 64630 => [0, 0, nil, "ثر", nil, nil, nil], + 64631 => [0, 0, nil, "ثز", nil, nil, nil], + 64632 => [0, 0, nil, "ثم", nil, nil, nil], + 64633 => [0, 0, nil, "ثن", nil, nil, nil], + 64634 => [0, 0, nil, "ثى", nil, nil, nil], + 64635 => [0, 0, nil, "ثي", nil, nil, nil], + 64636 => [0, 0, nil, "فى", nil, nil, nil], + 64637 => [0, 0, nil, "في", nil, nil, nil], + 64638 => [0, 0, nil, "قى", nil, nil, nil], + 64639 => [0, 0, nil, "قي", nil, nil, nil], + 64640 => [0, 0, nil, "كا", nil, nil, nil], + 64641 => [0, 0, nil, "كل", nil, nil, nil], + 64642 => [0, 0, nil, "كم", nil, nil, nil], + 64643 => [0, 0, nil, "كى", nil, nil, nil], + 64644 => [0, 0, nil, "كي", nil, nil, nil], + 64645 => [0, 0, nil, "لم", nil, nil, nil], + 64646 => [0, 0, nil, "لى", nil, nil, nil], + 64647 => [0, 0, nil, "لي", nil, nil, nil], + 64648 => [0, 0, nil, "ما", nil, nil, nil], + 64649 => [0, 0, nil, "مم", nil, nil, nil], + 64650 => [0, 0, nil, "نر", nil, nil, nil], + 64651 => [0, 0, nil, "نز", nil, nil, nil], + 64652 => [0, 0, nil, "نم", nil, nil, nil], + 64653 => [0, 0, nil, "نن", nil, nil, nil], + 64654 => [0, 0, nil, "نى", nil, nil, nil], + 64655 => [0, 0, nil, "ني", nil, nil, nil], + 64656 => [0, 0, nil, "ىٰ", nil, nil, nil], + 64657 => [0, 0, nil, "ير", nil, nil, nil], + 64658 => [0, 0, nil, "يز", nil, nil, nil], + 64659 => [0, 0, nil, "يم", nil, nil, nil], + 64660 => [0, 0, nil, "ين", nil, nil, nil], + 64661 => [0, 0, nil, "يى", nil, nil, nil], + 64662 => [0, 0, nil, "يي", nil, nil, nil], + 64663 => [0, 0, nil, "ئج", nil, nil, nil], + 64664 => [0, 0, nil, "ئح", nil, nil, nil], + 64665 => [0, 0, nil, "ئخ", nil, nil, nil], + 64666 => [0, 0, nil, "ئم", nil, nil, nil], + 64667 => [0, 0, nil, "ئه", nil, nil, nil], + 64668 => [0, 0, nil, "بج", nil, nil, nil], + 64669 => [0, 0, nil, "بح", nil, nil, nil], + 64670 => [0, 0, nil, "بخ", nil, nil, nil], + 64671 => [0, 0, nil, "بم", nil, nil, nil], + 64672 => [0, 0, nil, "به", nil, nil, nil], + 64673 => [0, 0, nil, "تج", nil, nil, nil], + 64674 => [0, 0, nil, "تح", nil, nil, nil], + 64675 => [0, 0, nil, "تخ", nil, nil, nil], + 64676 => [0, 0, nil, "تم", nil, nil, nil], + 64677 => [0, 0, nil, "ته", nil, nil, nil], + 64678 => [0, 0, nil, "ثم", nil, nil, nil], + 64679 => [0, 0, nil, "جح", nil, nil, nil], + 64680 => [0, 0, nil, "جم", nil, nil, nil], + 64681 => [0, 0, nil, "حج", nil, nil, nil], + 64682 => [0, 0, nil, "حم", nil, nil, nil], + 64683 => [0, 0, nil, "خج", nil, nil, nil], + 64684 => [0, 0, nil, "خم", nil, nil, nil], + 64685 => [0, 0, nil, "سج", nil, nil, nil], + 64686 => [0, 0, nil, "سح", nil, nil, nil], + 64687 => [0, 0, nil, "سخ", nil, nil, nil], + 64688 => [0, 0, nil, "سم", nil, nil, nil], + 64689 => [0, 0, nil, "صح", nil, nil, nil], + 64690 => [0, 0, nil, "صخ", nil, nil, nil], + 64691 => [0, 0, nil, "صم", nil, nil, nil], + 64692 => [0, 0, nil, "ضج", nil, nil, nil], + 64693 => [0, 0, nil, "ضح", nil, nil, nil], + 64694 => [0, 0, nil, "ضخ", nil, nil, nil], + 64695 => [0, 0, nil, "ضم", nil, nil, nil], + 64696 => [0, 0, nil, "طح", nil, nil, nil], + 64697 => [0, 0, nil, "ظم", nil, nil, nil], + 64698 => [0, 0, nil, "عج", nil, nil, nil], + 64699 => [0, 0, nil, "عم", nil, nil, nil], + 64700 => [0, 0, nil, "غج", nil, nil, nil], + 64701 => [0, 0, nil, "غم", nil, nil, nil], + 64702 => [0, 0, nil, "فج", nil, nil, nil], + 64703 => [0, 0, nil, "فح", nil, nil, nil], + 64704 => [0, 0, nil, "فخ", nil, nil, nil], + 64705 => [0, 0, nil, "فم", nil, nil, nil], + 64706 => [0, 0, nil, "قح", nil, nil, nil], + 64707 => [0, 0, nil, "قم", nil, nil, nil], + 64708 => [0, 0, nil, "كج", nil, nil, nil], + 64709 => [0, 0, nil, "كح", nil, nil, nil], + 64710 => [0, 0, nil, "كخ", nil, nil, nil], + 64711 => [0, 0, nil, "كل", nil, nil, nil], + 64712 => [0, 0, nil, "كم", nil, nil, nil], + 64713 => [0, 0, nil, "لج", nil, nil, nil], + 64714 => [0, 0, nil, "لح", nil, nil, nil], + 64715 => [0, 0, nil, "لخ", nil, nil, nil], + 64716 => [0, 0, nil, "لم", nil, nil, nil], + 64717 => [0, 0, nil, "له", nil, nil, nil], + 64718 => [0, 0, nil, "مج", nil, nil, nil], + 64719 => [0, 0, nil, "مح", nil, nil, nil], + 64720 => [0, 0, nil, "مخ", nil, nil, nil], + 64721 => [0, 0, nil, "مم", nil, nil, nil], + 64722 => [0, 0, nil, "نج", nil, nil, nil], + 64723 => [0, 0, nil, "نح", nil, nil, nil], + 64724 => [0, 0, nil, "نخ", nil, nil, nil], + 64725 => [0, 0, nil, "نم", nil, nil, nil], + 64726 => [0, 0, nil, "نه", nil, nil, nil], + 64727 => [0, 0, nil, "هج", nil, nil, nil], + 64728 => [0, 0, nil, "هم", nil, nil, nil], + 64729 => [0, 0, nil, "هٰ", nil, nil, nil], + 64730 => [0, 0, nil, "يج", nil, nil, nil], + 64731 => [0, 0, nil, "يح", nil, nil, nil], + 64732 => [0, 0, nil, "يخ", nil, nil, nil], + 64733 => [0, 0, nil, "يم", nil, nil, nil], + 64734 => [0, 0, nil, "يه", nil, nil, nil], + 64735 => [0, 0, nil, "ئم", nil, nil, nil], + 64736 => [0, 0, nil, "ئه", nil, nil, nil], + 64737 => [0, 0, nil, "بم", nil, nil, nil], + 64738 => [0, 0, nil, "به", nil, nil, nil], + 64739 => [0, 0, nil, "تم", nil, nil, nil], + 64740 => [0, 0, nil, "ته", nil, nil, nil], + 64741 => [0, 0, nil, "ثم", nil, nil, nil], + 64742 => [0, 0, nil, "ثه", nil, nil, nil], + 64743 => [0, 0, nil, "سم", nil, nil, nil], + 64744 => [0, 0, nil, "سه", nil, nil, nil], + 64745 => [0, 0, nil, "شم", nil, nil, nil], + 64746 => [0, 0, nil, "شه", nil, nil, nil], + 64747 => [0, 0, nil, "كل", nil, nil, nil], + 64748 => [0, 0, nil, "كم", nil, nil, nil], + 64749 => [0, 0, nil, "لم", nil, nil, nil], + 64750 => [0, 0, nil, "نم", nil, nil, nil], + 64751 => [0, 0, nil, "نه", nil, nil, nil], + 64752 => [0, 0, nil, "يم", nil, nil, nil], + 64753 => [0, 0, nil, "يه", nil, nil, nil], + 64754 => [0, 0, nil, "ـَّ", nil, nil, nil], + 64755 => [0, 0, nil, "ـُّ", nil, nil, nil], + 64756 => [0, 0, nil, "ـِّ", nil, nil, nil], + 64757 => [0, 0, nil, "طى", nil, nil, nil], + 64758 => [0, 0, nil, "طي", nil, nil, nil], + 64759 => [0, 0, nil, "عى", nil, nil, nil], + 64760 => [0, 0, nil, "عي", nil, nil, nil], + 64761 => [0, 0, nil, "غى", nil, nil, nil], + 64762 => [0, 0, nil, "غي", nil, nil, nil], + 64763 => [0, 0, nil, "سى", nil, nil, nil], + 64764 => [0, 0, nil, "سي", nil, nil, nil], + 64765 => [0, 0, nil, "شى", nil, nil, nil], + 64766 => [0, 0, nil, "شي", nil, nil, nil], + 64767 => [0, 0, nil, "حى", nil, nil, nil], + 64768 => [0, 0, nil, "حي", nil, nil, nil], + 64769 => [0, 0, nil, "جى", nil, nil, nil], + 64770 => [0, 0, nil, "جي", nil, nil, nil], + 64771 => [0, 0, nil, "خى", nil, nil, nil], + 64772 => [0, 0, nil, "خي", nil, nil, nil], + 64773 => [0, 0, nil, "صى", nil, nil, nil], + 64774 => [0, 0, nil, "صي", nil, nil, nil], + 64775 => [0, 0, nil, "ضى", nil, nil, nil], + 64776 => [0, 0, nil, "ضي", nil, nil, nil], + 64777 => [0, 0, nil, "شج", nil, nil, nil], + 64778 => [0, 0, nil, "شح", nil, nil, nil], + 64779 => [0, 0, nil, "شخ", nil, nil, nil], + 64780 => [0, 0, nil, "شم", nil, nil, nil], + 64781 => [0, 0, nil, "شر", nil, nil, nil], + 64782 => [0, 0, nil, "سر", nil, nil, nil], + 64783 => [0, 0, nil, "صر", nil, nil, nil], + 64784 => [0, 0, nil, "ضر", nil, nil, nil], + 64785 => [0, 0, nil, "طى", nil, nil, nil], + 64786 => [0, 0, nil, "طي", nil, nil, nil], + 64787 => [0, 0, nil, "عى", nil, nil, nil], + 64788 => [0, 0, nil, "عي", nil, nil, nil], + 64789 => [0, 0, nil, "غى", nil, nil, nil], + 64790 => [0, 0, nil, "غي", nil, nil, nil], + 64791 => [0, 0, nil, "سى", nil, nil, nil], + 64792 => [0, 0, nil, "سي", nil, nil, nil], + 64793 => [0, 0, nil, "شى", nil, nil, nil], + 64794 => [0, 0, nil, "شي", nil, nil, nil], + 64795 => [0, 0, nil, "حى", nil, nil, nil], + 64796 => [0, 0, nil, "حي", nil, nil, nil], + 64797 => [0, 0, nil, "جى", nil, nil, nil], + 64798 => [0, 0, nil, "جي", nil, nil, nil], + 64799 => [0, 0, nil, "خى", nil, nil, nil], + 64800 => [0, 0, nil, "خي", nil, nil, nil], + 64801 => [0, 0, nil, "صى", nil, nil, nil], + 64802 => [0, 0, nil, "صي", nil, nil, nil], + 64803 => [0, 0, nil, "ضى", nil, nil, nil], + 64804 => [0, 0, nil, "ضي", nil, nil, nil], + 64805 => [0, 0, nil, "شج", nil, nil, nil], + 64806 => [0, 0, nil, "شح", nil, nil, nil], + 64807 => [0, 0, nil, "شخ", nil, nil, nil], + 64808 => [0, 0, nil, "شم", nil, nil, nil], + 64809 => [0, 0, nil, "شر", nil, nil, nil], + 64810 => [0, 0, nil, "سر", nil, nil, nil], + 64811 => [0, 0, nil, "صر", nil, nil, nil], + 64812 => [0, 0, nil, "ضر", nil, nil, nil], + 64813 => [0, 0, nil, "شج", nil, nil, nil], + 64814 => [0, 0, nil, "شح", nil, nil, nil], + 64815 => [0, 0, nil, "شخ", nil, nil, nil], + 64816 => [0, 0, nil, "شم", nil, nil, nil], + 64817 => [0, 0, nil, "سه", nil, nil, nil], + 64818 => [0, 0, nil, "شه", nil, nil, nil], + 64819 => [0, 0, nil, "طم", nil, nil, nil], + 64820 => [0, 0, nil, "سج", nil, nil, nil], + 64821 => [0, 0, nil, "سح", nil, nil, nil], + 64822 => [0, 0, nil, "سخ", nil, nil, nil], + 64823 => [0, 0, nil, "شج", nil, nil, nil], + 64824 => [0, 0, nil, "شح", nil, nil, nil], + 64825 => [0, 0, nil, "شخ", nil, nil, nil], + 64826 => [0, 0, nil, "طم", nil, nil, nil], + 64827 => [0, 0, nil, "ظم", nil, nil, nil], + 64828 => [0, 0, nil, "اً", nil, nil, nil], + 64829 => [0, 0, nil, "اً", nil, nil, nil], + 64848 => [0, 0, nil, "تجم", nil, nil, nil], + 64849 => [0, 0, nil, "تحج", nil, nil, nil], + 64850 => [0, 0, nil, "تحج", nil, nil, nil], + 64851 => [0, 0, nil, "تحم", nil, nil, nil], + 64852 => [0, 0, nil, "تخم", nil, nil, nil], + 64853 => [0, 0, nil, "تمج", nil, nil, nil], + 64854 => [0, 0, nil, "تمح", nil, nil, nil], + 64855 => [0, 0, nil, "تمخ", nil, nil, nil], + 64856 => [0, 0, nil, "جمح", nil, nil, nil], + 64857 => [0, 0, nil, "جمح", nil, nil, nil], + 64858 => [0, 0, nil, "حمي", nil, nil, nil], + 64859 => [0, 0, nil, "حمى", nil, nil, nil], + 64860 => [0, 0, nil, "سحج", nil, nil, nil], + 64861 => [0, 0, nil, "سجح", nil, nil, nil], + 64862 => [0, 0, nil, "سجى", nil, nil, nil], + 64863 => [0, 0, nil, "سمح", nil, nil, nil], + 64864 => [0, 0, nil, "سمح", nil, nil, nil], + 64865 => [0, 0, nil, "سمج", nil, nil, nil], + 64866 => [0, 0, nil, "سمم", nil, nil, nil], + 64867 => [0, 0, nil, "سمم", nil, nil, nil], + 64868 => [0, 0, nil, "صحح", nil, nil, nil], + 64869 => [0, 0, nil, "صحح", nil, nil, nil], + 64870 => [0, 0, nil, "صمم", nil, nil, nil], + 64871 => [0, 0, nil, "شحم", nil, nil, nil], + 64872 => [0, 0, nil, "شحم", nil, nil, nil], + 64873 => [0, 0, nil, "شجي", nil, nil, nil], + 64874 => [0, 0, nil, "شمخ", nil, nil, nil], + 64875 => [0, 0, nil, "شمخ", nil, nil, nil], + 64876 => [0, 0, nil, "شمم", nil, nil, nil], + 64877 => [0, 0, nil, "شمم", nil, nil, nil], + 64878 => [0, 0, nil, "ضحى", nil, nil, nil], + 64879 => [0, 0, nil, "ضخم", nil, nil, nil], + 64880 => [0, 0, nil, "ضخم", nil, nil, nil], + 64881 => [0, 0, nil, "طمح", nil, nil, nil], + 64882 => [0, 0, nil, "طمح", nil, nil, nil], + 64883 => [0, 0, nil, "طمم", nil, nil, nil], + 64884 => [0, 0, nil, "طمي", nil, nil, nil], + 64885 => [0, 0, nil, "عجم", nil, nil, nil], + 64886 => [0, 0, nil, "عمم", nil, nil, nil], + 64887 => [0, 0, nil, "عمم", nil, nil, nil], + 64888 => [0, 0, nil, "عمى", nil, nil, nil], + 64889 => [0, 0, nil, "غمم", nil, nil, nil], + 64890 => [0, 0, nil, "غمي", nil, nil, nil], + 64891 => [0, 0, nil, "غمى", nil, nil, nil], + 64892 => [0, 0, nil, "فخم", nil, nil, nil], + 64893 => [0, 0, nil, "فخم", nil, nil, nil], + 64894 => [0, 0, nil, "قمح", nil, nil, nil], + 64895 => [0, 0, nil, "قمم", nil, nil, nil], + 64896 => [0, 0, nil, "لحم", nil, nil, nil], + 64897 => [0, 0, nil, "لحي", nil, nil, nil], + 64898 => [0, 0, nil, "لحى", nil, nil, nil], + 64899 => [0, 0, nil, "لجج", nil, nil, nil], + 64900 => [0, 0, nil, "لجج", nil, nil, nil], + 64901 => [0, 0, nil, "لخم", nil, nil, nil], + 64902 => [0, 0, nil, "لخم", nil, nil, nil], + 64903 => [0, 0, nil, "لمح", nil, nil, nil], + 64904 => [0, 0, nil, "لمح", nil, nil, nil], + 64905 => [0, 0, nil, "محج", nil, nil, nil], + 64906 => [0, 0, nil, "محم", nil, nil, nil], + 64907 => [0, 0, nil, "محي", nil, nil, nil], + 64908 => [0, 0, nil, "مجح", nil, nil, nil], + 64909 => [0, 0, nil, "مجم", nil, nil, nil], + 64910 => [0, 0, nil, "مخج", nil, nil, nil], + 64911 => [0, 0, nil, "مخم", nil, nil, nil], + 64914 => [0, 0, nil, "مجخ", nil, nil, nil], + 64915 => [0, 0, nil, "همج", nil, nil, nil], + 64916 => [0, 0, nil, "همم", nil, nil, nil], + 64917 => [0, 0, nil, "نحم", nil, nil, nil], + 64918 => [0, 0, nil, "نحى", nil, nil, nil], + 64919 => [0, 0, nil, "نجم", nil, nil, nil], + 64920 => [0, 0, nil, "نجم", nil, nil, nil], + 64921 => [0, 0, nil, "نجى", nil, nil, nil], + 64922 => [0, 0, nil, "نمي", nil, nil, nil], + 64923 => [0, 0, nil, "نمى", nil, nil, nil], + 64924 => [0, 0, nil, "يمم", nil, nil, nil], + 64925 => [0, 0, nil, "يمم", nil, nil, nil], + 64926 => [0, 0, nil, "بخي", nil, nil, nil], + 64927 => [0, 0, nil, "تجي", nil, nil, nil], + 64928 => [0, 0, nil, "تجى", nil, nil, nil], + 64929 => [0, 0, nil, "تخي", nil, nil, nil], + 64930 => [0, 0, nil, "تخى", nil, nil, nil], + 64931 => [0, 0, nil, "تمي", nil, nil, nil], + 64932 => [0, 0, nil, "تمى", nil, nil, nil], + 64933 => [0, 0, nil, "جمي", nil, nil, nil], + 64934 => [0, 0, nil, "جحى", nil, nil, nil], + 64935 => [0, 0, nil, "جمى", nil, nil, nil], + 64936 => [0, 0, nil, "سخى", nil, nil, nil], + 64937 => [0, 0, nil, "صحي", nil, nil, nil], + 64938 => [0, 0, nil, "شحي", nil, nil, nil], + 64939 => [0, 0, nil, "ضحي", nil, nil, nil], + 64940 => [0, 0, nil, "لجي", nil, nil, nil], + 64941 => [0, 0, nil, "لمي", nil, nil, nil], + 64942 => [0, 0, nil, "يحي", nil, nil, nil], + 64943 => [0, 0, nil, "يجي", nil, nil, nil], + 64944 => [0, 0, nil, "يمي", nil, nil, nil], + 64945 => [0, 0, nil, "ممي", nil, nil, nil], + 64946 => [0, 0, nil, "قمي", nil, nil, nil], + 64947 => [0, 0, nil, "نحي", nil, nil, nil], + 64948 => [0, 0, nil, "قمح", nil, nil, nil], + 64949 => [0, 0, nil, "لحم", nil, nil, nil], + 64950 => [0, 0, nil, "عمي", nil, nil, nil], + 64951 => [0, 0, nil, "كمي", nil, nil, nil], + 64952 => [0, 0, nil, "نجح", nil, nil, nil], + 64953 => [0, 0, nil, "مخي", nil, nil, nil], + 64954 => [0, 0, nil, "لجم", nil, nil, nil], + 64955 => [0, 0, nil, "كمم", nil, nil, nil], + 64956 => [0, 0, nil, "لجم", nil, nil, nil], + 64957 => [0, 0, nil, "نجح", nil, nil, nil], + 64958 => [0, 0, nil, "جحي", nil, nil, nil], + 64959 => [0, 0, nil, "حجي", nil, nil, nil], + 64960 => [0, 0, nil, "مجي", nil, nil, nil], + 64961 => [0, 0, nil, "فمي", nil, nil, nil], + 64962 => [0, 0, nil, "بحي", nil, nil, nil], + 64963 => [0, 0, nil, "كمم", nil, nil, nil], + 64964 => [0, 0, nil, "عجم", nil, nil, nil], + 64965 => [0, 0, nil, "صمم", nil, nil, nil], + 64966 => [0, 0, nil, "سخي", nil, nil, nil], + 64967 => [0, 0, nil, "نجي", nil, nil, nil], + 65008 => [0, 0, nil, "صلے", nil, nil, nil], + 65009 => [0, 0, nil, "قلے", nil, nil, nil], + 65010 => [0, 0, nil, "الله", nil, nil, nil], + 65011 => [0, 0, nil, "اكبر", nil, nil, nil], + 65012 => [0, 0, nil, "محمد", nil, nil, nil], + 65013 => [0, 0, nil, "صلعم", nil, nil, nil], + 65014 => [0, 0, nil, "رسول", nil, nil, nil], + 65015 => [0, 0, nil, "عليه", nil, nil, nil], + 65016 => [0, 0, nil, "وسلم", nil, nil, nil], + 65017 => [0, 0, nil, "صلى", nil, nil, nil], + 65018 => [0, 0, nil, "صلى الله عليه وسلم", nil, nil, nil], + 65019 => [0, 0, nil, "جل جلاله", nil, nil, nil], + 65056 => [230, 0, nil, nil, nil, nil, nil], + 65057 => [230, 0, nil, nil, nil, nil, nil], + 65058 => [230, 0, nil, nil, nil, nil, nil], + 65059 => [230, 0, nil, nil, nil, nil, nil], + 65072 => [0, 0, nil, "‥", nil, nil, nil], + 65073 => [0, 0, nil, "—", nil, nil, nil], + 65074 => [0, 0, nil, "–", nil, nil, nil], + 65075 => [0, 0, nil, "_", nil, nil, nil], + 65076 => [0, 0, nil, "_", nil, nil, nil], + 65077 => [0, 0, nil, "(", nil, nil, nil], + 65078 => [0, 0, nil, ")", nil, nil, nil], + 65079 => [0, 0, nil, "{", nil, nil, nil], + 65080 => [0, 0, nil, "}", nil, nil, nil], + 65081 => [0, 0, nil, "〔", nil, nil, nil], + 65082 => [0, 0, nil, "〕", nil, nil, nil], + 65083 => [0, 0, nil, "【", nil, nil, nil], + 65084 => [0, 0, nil, "】", nil, nil, nil], + 65085 => [0, 0, nil, "《", nil, nil, nil], + 65086 => [0, 0, nil, "》", nil, nil, nil], + 65087 => [0, 0, nil, "〈", nil, nil, nil], + 65088 => [0, 0, nil, "〉", nil, nil, nil], + 65089 => [0, 0, nil, "「", nil, nil, nil], + 65090 => [0, 0, nil, "」", nil, nil, nil], + 65091 => [0, 0, nil, "『", nil, nil, nil], + 65092 => [0, 0, nil, "』", nil, nil, nil], + 65097 => [0, 0, nil, "‾", nil, nil, nil], + 65098 => [0, 0, nil, "‾", nil, nil, nil], + 65099 => [0, 0, nil, "‾", nil, nil, nil], + 65100 => [0, 0, nil, "‾", nil, nil, nil], + 65101 => [0, 0, nil, "_", nil, nil, nil], + 65102 => [0, 0, nil, "_", nil, nil, nil], + 65103 => [0, 0, nil, "_", nil, nil, nil], + 65104 => [0, 0, nil, ",", nil, nil, nil], + 65105 => [0, 0, nil, "、", nil, nil, nil], + 65106 => [0, 0, nil, ".", nil, nil, nil], + 65108 => [0, 0, nil, ";", nil, nil, nil], + 65109 => [0, 0, nil, ":", nil, nil, nil], + 65110 => [0, 0, nil, "?", nil, nil, nil], + 65111 => [0, 0, nil, "!", nil, nil, nil], + 65112 => [0, 0, nil, "—", nil, nil, nil], + 65113 => [0, 0, nil, "(", nil, nil, nil], + 65114 => [0, 0, nil, ")", nil, nil, nil], + 65115 => [0, 0, nil, "{", nil, nil, nil], + 65116 => [0, 0, nil, "}", nil, nil, nil], + 65117 => [0, 0, nil, "〔", nil, nil, nil], + 65118 => [0, 0, nil, "〕", nil, nil, nil], + 65119 => [0, 0, nil, "#", nil, nil, nil], + 65120 => [0, 0, nil, "&", nil, nil, nil], + 65121 => [0, 0, nil, "*", nil, nil, nil], + 65122 => [0, 0, nil, "+", nil, nil, nil], + 65123 => [0, 0, nil, "-", nil, nil, nil], + 65124 => [0, 0, nil, "<", nil, nil, nil], + 65125 => [0, 0, nil, ">", nil, nil, nil], + 65126 => [0, 0, nil, "=", nil, nil, nil], + 65128 => [0, 0, nil, "\\", nil, nil, nil], + 65129 => [0, 0, nil, "$", nil, nil, nil], + 65130 => [0, 0, nil, "%", nil, nil, nil], + 65131 => [0, 0, nil, "@", nil, nil, nil], + 65136 => [0, 0, nil, " ً", nil, nil, nil], + 65137 => [0, 0, nil, "ـً", nil, nil, nil], + 65138 => [0, 0, nil, " ٌ", nil, nil, nil], + 65140 => [0, 0, nil, " ٍ", nil, nil, nil], + 65142 => [0, 0, nil, " َ", nil, nil, nil], + 65143 => [0, 0, nil, "ـَ", nil, nil, nil], + 65144 => [0, 0, nil, " ُ", nil, nil, nil], + 65145 => [0, 0, nil, "ـُ", nil, nil, nil], + 65146 => [0, 0, nil, " ِ", nil, nil, nil], + 65147 => [0, 0, nil, "ـِ", nil, nil, nil], + 65148 => [0, 0, nil, " ّ", nil, nil, nil], + 65149 => [0, 0, nil, "ـّ", nil, nil, nil], + 65150 => [0, 0, nil, " ْ", nil, nil, nil], + 65151 => [0, 0, nil, "ـْ", nil, nil, nil], + 65152 => [0, 0, nil, "ء", nil, nil, nil], + 65153 => [0, 0, nil, "آ", nil, nil, nil], + 65154 => [0, 0, nil, "آ", nil, nil, nil], + 65155 => [0, 0, nil, "أ", nil, nil, nil], + 65156 => [0, 0, nil, "أ", nil, nil, nil], + 65157 => [0, 0, nil, "ؤ", nil, nil, nil], + 65158 => [0, 0, nil, "ؤ", nil, nil, nil], + 65159 => [0, 0, nil, "إ", nil, nil, nil], + 65160 => [0, 0, nil, "إ", nil, nil, nil], + 65161 => [0, 0, nil, "ئ", nil, nil, nil], + 65162 => [0, 0, nil, "ئ", nil, nil, nil], + 65163 => [0, 0, nil, "ئ", nil, nil, nil], + 65164 => [0, 0, nil, "ئ", nil, nil, nil], + 65165 => [0, 0, nil, "ا", nil, nil, nil], + 65166 => [0, 0, nil, "ا", nil, nil, nil], + 65167 => [0, 0, nil, "ب", nil, nil, nil], + 65168 => [0, 0, nil, "ب", nil, nil, nil], + 65169 => [0, 0, nil, "ب", nil, nil, nil], + 65170 => [0, 0, nil, "ب", nil, nil, nil], + 65171 => [0, 0, nil, "ة", nil, nil, nil], + 65172 => [0, 0, nil, "ة", nil, nil, nil], + 65173 => [0, 0, nil, "ت", nil, nil, nil], + 65174 => [0, 0, nil, "ت", nil, nil, nil], + 65175 => [0, 0, nil, "ت", nil, nil, nil], + 65176 => [0, 0, nil, "ت", nil, nil, nil], + 65177 => [0, 0, nil, "ث", nil, nil, nil], + 65178 => [0, 0, nil, "ث", nil, nil, nil], + 65179 => [0, 0, nil, "ث", nil, nil, nil], + 65180 => [0, 0, nil, "ث", nil, nil, nil], + 65181 => [0, 0, nil, "ج", nil, nil, nil], + 65182 => [0, 0, nil, "ج", nil, nil, nil], + 65183 => [0, 0, nil, "ج", nil, nil, nil], + 65184 => [0, 0, nil, "ج", nil, nil, nil], + 65185 => [0, 0, nil, "ح", nil, nil, nil], + 65186 => [0, 0, nil, "ح", nil, nil, nil], + 65187 => [0, 0, nil, "ح", nil, nil, nil], + 65188 => [0, 0, nil, "ح", nil, nil, nil], + 65189 => [0, 0, nil, "خ", nil, nil, nil], + 65190 => [0, 0, nil, "خ", nil, nil, nil], + 65191 => [0, 0, nil, "خ", nil, nil, nil], + 65192 => [0, 0, nil, "خ", nil, nil, nil], + 65193 => [0, 0, nil, "د", nil, nil, nil], + 65194 => [0, 0, nil, "د", nil, nil, nil], + 65195 => [0, 0, nil, "ذ", nil, nil, nil], + 65196 => [0, 0, nil, "ذ", nil, nil, nil], + 65197 => [0, 0, nil, "ر", nil, nil, nil], + 65198 => [0, 0, nil, "ر", nil, nil, nil], + 65199 => [0, 0, nil, "ز", nil, nil, nil], + 65200 => [0, 0, nil, "ز", nil, nil, nil], + 65201 => [0, 0, nil, "س", nil, nil, nil], + 65202 => [0, 0, nil, "س", nil, nil, nil], + 65203 => [0, 0, nil, "س", nil, nil, nil], + 65204 => [0, 0, nil, "س", nil, nil, nil], + 65205 => [0, 0, nil, "ش", nil, nil, nil], + 65206 => [0, 0, nil, "ش", nil, nil, nil], + 65207 => [0, 0, nil, "ش", nil, nil, nil], + 65208 => [0, 0, nil, "ش", nil, nil, nil], + 65209 => [0, 0, nil, "ص", nil, nil, nil], + 65210 => [0, 0, nil, "ص", nil, nil, nil], + 65211 => [0, 0, nil, "ص", nil, nil, nil], + 65212 => [0, 0, nil, "ص", nil, nil, nil], + 65213 => [0, 0, nil, "ض", nil, nil, nil], + 65214 => [0, 0, nil, "ض", nil, nil, nil], + 65215 => [0, 0, nil, "ض", nil, nil, nil], + 65216 => [0, 0, nil, "ض", nil, nil, nil], + 65217 => [0, 0, nil, "ط", nil, nil, nil], + 65218 => [0, 0, nil, "ط", nil, nil, nil], + 65219 => [0, 0, nil, "ط", nil, nil, nil], + 65220 => [0, 0, nil, "ط", nil, nil, nil], + 65221 => [0, 0, nil, "ظ", nil, nil, nil], + 65222 => [0, 0, nil, "ظ", nil, nil, nil], + 65223 => [0, 0, nil, "ظ", nil, nil, nil], + 65224 => [0, 0, nil, "ظ", nil, nil, nil], + 65225 => [0, 0, nil, "ع", nil, nil, nil], + 65226 => [0, 0, nil, "ع", nil, nil, nil], + 65227 => [0, 0, nil, "ع", nil, nil, nil], + 65228 => [0, 0, nil, "ع", nil, nil, nil], + 65229 => [0, 0, nil, "غ", nil, nil, nil], + 65230 => [0, 0, nil, "غ", nil, nil, nil], + 65231 => [0, 0, nil, "غ", nil, nil, nil], + 65232 => [0, 0, nil, "غ", nil, nil, nil], + 65233 => [0, 0, nil, "ف", nil, nil, nil], + 65234 => [0, 0, nil, "ف", nil, nil, nil], + 65235 => [0, 0, nil, "ف", nil, nil, nil], + 65236 => [0, 0, nil, "ف", nil, nil, nil], + 65237 => [0, 0, nil, "ق", nil, nil, nil], + 65238 => [0, 0, nil, "ق", nil, nil, nil], + 65239 => [0, 0, nil, "ق", nil, nil, nil], + 65240 => [0, 0, nil, "ق", nil, nil, nil], + 65241 => [0, 0, nil, "ك", nil, nil, nil], + 65242 => [0, 0, nil, "ك", nil, nil, nil], + 65243 => [0, 0, nil, "ك", nil, nil, nil], + 65244 => [0, 0, nil, "ك", nil, nil, nil], + 65245 => [0, 0, nil, "ل", nil, nil, nil], + 65246 => [0, 0, nil, "ل", nil, nil, nil], + 65247 => [0, 0, nil, "ل", nil, nil, nil], + 65248 => [0, 0, nil, "ل", nil, nil, nil], + 65249 => [0, 0, nil, "م", nil, nil, nil], + 65250 => [0, 0, nil, "م", nil, nil, nil], + 65251 => [0, 0, nil, "م", nil, nil, nil], + 65252 => [0, 0, nil, "م", nil, nil, nil], + 65253 => [0, 0, nil, "ن", nil, nil, nil], + 65254 => [0, 0, nil, "ن", nil, nil, nil], + 65255 => [0, 0, nil, "ن", nil, nil, nil], + 65256 => [0, 0, nil, "ن", nil, nil, nil], + 65257 => [0, 0, nil, "ه", nil, nil, nil], + 65258 => [0, 0, nil, "ه", nil, nil, nil], + 65259 => [0, 0, nil, "ه", nil, nil, nil], + 65260 => [0, 0, nil, "ه", nil, nil, nil], + 65261 => [0, 0, nil, "و", nil, nil, nil], + 65262 => [0, 0, nil, "و", nil, nil, nil], + 65263 => [0, 0, nil, "ى", nil, nil, nil], + 65264 => [0, 0, nil, "ى", nil, nil, nil], + 65265 => [0, 0, nil, "ي", nil, nil, nil], + 65266 => [0, 0, nil, "ي", nil, nil, nil], + 65267 => [0, 0, nil, "ي", nil, nil, nil], + 65268 => [0, 0, nil, "ي", nil, nil, nil], + 65269 => [0, 0, nil, "لآ", nil, nil, nil], + 65270 => [0, 0, nil, "لآ", nil, nil, nil], + 65271 => [0, 0, nil, "لأ", nil, nil, nil], + 65272 => [0, 0, nil, "لأ", nil, nil, nil], + 65273 => [0, 0, nil, "لإ", nil, nil, nil], + 65274 => [0, 0, nil, "لإ", nil, nil, nil], + 65275 => [0, 0, nil, "لا", nil, nil, nil], + 65276 => [0, 0, nil, "لا", nil, nil, nil], + 65281 => [0, 0, nil, "!", nil, nil, nil], + 65282 => [0, 0, nil, "\"", nil, nil, nil], + 65283 => [0, 0, nil, "#", nil, nil, nil], + 65284 => [0, 0, nil, "$", nil, nil, nil], + 65285 => [0, 0, nil, "%", nil, nil, nil], + 65286 => [0, 0, nil, "&", nil, nil, nil], + 65287 => [0, 0, nil, "'", nil, nil, nil], + 65288 => [0, 0, nil, "(", nil, nil, nil], + 65289 => [0, 0, nil, ")", nil, nil, nil], + 65290 => [0, 0, nil, "*", nil, nil, nil], + 65291 => [0, 0, nil, "+", nil, nil, nil], + 65292 => [0, 0, nil, ",", nil, nil, nil], + 65293 => [0, 0, nil, "-", nil, nil, nil], + 65294 => [0, 0, nil, ".", nil, nil, nil], + 65295 => [0, 0, nil, "/", nil, nil, nil], + 65296 => [0, 0, nil, "0", nil, nil, nil], + 65297 => [0, 0, nil, "1", nil, nil, nil], + 65298 => [0, 0, nil, "2", nil, nil, nil], + 65299 => [0, 0, nil, "3", nil, nil, nil], + 65300 => [0, 0, nil, "4", nil, nil, nil], + 65301 => [0, 0, nil, "5", nil, nil, nil], + 65302 => [0, 0, nil, "6", nil, nil, nil], + 65303 => [0, 0, nil, "7", nil, nil, nil], + 65304 => [0, 0, nil, "8", nil, nil, nil], + 65305 => [0, 0, nil, "9", nil, nil, nil], + 65306 => [0, 0, nil, ":", nil, nil, nil], + 65307 => [0, 0, nil, ";", nil, nil, nil], + 65308 => [0, 0, nil, "<", nil, nil, nil], + 65309 => [0, 0, nil, "=", nil, nil, nil], + 65310 => [0, 0, nil, ">", nil, nil, nil], + 65311 => [0, 0, nil, "?", nil, nil, nil], + 65312 => [0, 0, nil, "@", nil, nil, nil], + 65313 => [0, 0, nil, "A", nil, 65345, nil], + 65314 => [0, 0, nil, "B", nil, 65346, nil], + 65315 => [0, 0, nil, "C", nil, 65347, nil], + 65316 => [0, 0, nil, "D", nil, 65348, nil], + 65317 => [0, 0, nil, "E", nil, 65349, nil], + 65318 => [0, 0, nil, "F", nil, 65350, nil], + 65319 => [0, 0, nil, "G", nil, 65351, nil], + 65320 => [0, 0, nil, "H", nil, 65352, nil], + 65321 => [0, 0, nil, "I", nil, 65353, nil], + 65322 => [0, 0, nil, "J", nil, 65354, nil], + 65323 => [0, 0, nil, "K", nil, 65355, nil], + 65324 => [0, 0, nil, "L", nil, 65356, nil], + 65325 => [0, 0, nil, "M", nil, 65357, nil], + 65326 => [0, 0, nil, "N", nil, 65358, nil], + 65327 => [0, 0, nil, "O", nil, 65359, nil], + 65328 => [0, 0, nil, "P", nil, 65360, nil], + 65329 => [0, 0, nil, "Q", nil, 65361, nil], + 65330 => [0, 0, nil, "R", nil, 65362, nil], + 65331 => [0, 0, nil, "S", nil, 65363, nil], + 65332 => [0, 0, nil, "T", nil, 65364, nil], + 65333 => [0, 0, nil, "U", nil, 65365, nil], + 65334 => [0, 0, nil, "V", nil, 65366, nil], + 65335 => [0, 0, nil, "W", nil, 65367, nil], + 65336 => [0, 0, nil, "X", nil, 65368, nil], + 65337 => [0, 0, nil, "Y", nil, 65369, nil], + 65338 => [0, 0, nil, "Z", nil, 65370, nil], + 65339 => [0, 0, nil, "[", nil, nil, nil], + 65340 => [0, 0, nil, "\\", nil, nil, nil], + 65341 => [0, 0, nil, "]", nil, nil, nil], + 65342 => [0, 0, nil, "^", nil, nil, nil], + 65343 => [0, 0, nil, "_", nil, nil, nil], + 65344 => [0, 0, nil, "`", nil, nil, nil], + 65345 => [0, 0, nil, "a", 65313, nil, 65313], + 65346 => [0, 0, nil, "b", 65314, nil, 65314], + 65347 => [0, 0, nil, "c", 65315, nil, 65315], + 65348 => [0, 0, nil, "d", 65316, nil, 65316], + 65349 => [0, 0, nil, "e", 65317, nil, 65317], + 65350 => [0, 0, nil, "f", 65318, nil, 65318], + 65351 => [0, 0, nil, "g", 65319, nil, 65319], + 65352 => [0, 0, nil, "h", 65320, nil, 65320], + 65353 => [0, 0, nil, "i", 65321, nil, 65321], + 65354 => [0, 0, nil, "j", 65322, nil, 65322], + 65355 => [0, 0, nil, "k", 65323, nil, 65323], + 65356 => [0, 0, nil, "l", 65324, nil, 65324], + 65357 => [0, 0, nil, "m", 65325, nil, 65325], + 65358 => [0, 0, nil, "n", 65326, nil, 65326], + 65359 => [0, 0, nil, "o", 65327, nil, 65327], + 65360 => [0, 0, nil, "p", 65328, nil, 65328], + 65361 => [0, 0, nil, "q", 65329, nil, 65329], + 65362 => [0, 0, nil, "r", 65330, nil, 65330], + 65363 => [0, 0, nil, "s", 65331, nil, 65331], + 65364 => [0, 0, nil, "t", 65332, nil, 65332], + 65365 => [0, 0, nil, "u", 65333, nil, 65333], + 65366 => [0, 0, nil, "v", 65334, nil, 65334], + 65367 => [0, 0, nil, "w", 65335, nil, 65335], + 65368 => [0, 0, nil, "x", 65336, nil, 65336], + 65369 => [0, 0, nil, "y", 65337, nil, 65337], + 65370 => [0, 0, nil, "z", 65338, nil, 65338], + 65371 => [0, 0, nil, "{", nil, nil, nil], + 65372 => [0, 0, nil, "|", nil, nil, nil], + 65373 => [0, 0, nil, "}", nil, nil, nil], + 65374 => [0, 0, nil, "~", nil, nil, nil], + 65377 => [0, 0, nil, "。", nil, nil, nil], + 65378 => [0, 0, nil, "「", nil, nil, nil], + 65379 => [0, 0, nil, "」", nil, nil, nil], + 65380 => [0, 0, nil, "、", nil, nil, nil], + 65381 => [0, 0, nil, "・", nil, nil, nil], + 65382 => [0, 0, nil, "ヲ", nil, nil, nil], + 65383 => [0, 0, nil, "ァ", nil, nil, nil], + 65384 => [0, 0, nil, "ィ", nil, nil, nil], + 65385 => [0, 0, nil, "ゥ", nil, nil, nil], + 65386 => [0, 0, nil, "ェ", nil, nil, nil], + 65387 => [0, 0, nil, "ォ", nil, nil, nil], + 65388 => [0, 0, nil, "ャ", nil, nil, nil], + 65389 => [0, 0, nil, "ュ", nil, nil, nil], + 65390 => [0, 0, nil, "ョ", nil, nil, nil], + 65391 => [0, 0, nil, "ッ", nil, nil, nil], + 65392 => [0, 0, nil, "ー", nil, nil, nil], + 65393 => [0, 0, nil, "ア", nil, nil, nil], + 65394 => [0, 0, nil, "イ", nil, nil, nil], + 65395 => [0, 0, nil, "ウ", nil, nil, nil], + 65396 => [0, 0, nil, "エ", nil, nil, nil], + 65397 => [0, 0, nil, "オ", nil, nil, nil], + 65398 => [0, 0, nil, "カ", nil, nil, nil], + 65399 => [0, 0, nil, "キ", nil, nil, nil], + 65400 => [0, 0, nil, "ク", nil, nil, nil], + 65401 => [0, 0, nil, "ケ", nil, nil, nil], + 65402 => [0, 0, nil, "コ", nil, nil, nil], + 65403 => [0, 0, nil, "サ", nil, nil, nil], + 65404 => [0, 0, nil, "シ", nil, nil, nil], + 65405 => [0, 0, nil, "ス", nil, nil, nil], + 65406 => [0, 0, nil, "セ", nil, nil, nil], + 65407 => [0, 0, nil, "ソ", nil, nil, nil], + 65408 => [0, 0, nil, "タ", nil, nil, nil], + 65409 => [0, 0, nil, "チ", nil, nil, nil], + 65410 => [0, 0, nil, "ツ", nil, nil, nil], + 65411 => [0, 0, nil, "テ", nil, nil, nil], + 65412 => [0, 0, nil, "ト", nil, nil, nil], + 65413 => [0, 0, nil, "ナ", nil, nil, nil], + 65414 => [0, 0, nil, "ニ", nil, nil, nil], + 65415 => [0, 0, nil, "ヌ", nil, nil, nil], + 65416 => [0, 0, nil, "ネ", nil, nil, nil], + 65417 => [0, 0, nil, "ノ", nil, nil, nil], + 65418 => [0, 0, nil, "ハ", nil, nil, nil], + 65419 => [0, 0, nil, "ヒ", nil, nil, nil], + 65420 => [0, 0, nil, "フ", nil, nil, nil], + 65421 => [0, 0, nil, "ヘ", nil, nil, nil], + 65422 => [0, 0, nil, "ホ", nil, nil, nil], + 65423 => [0, 0, nil, "マ", nil, nil, nil], + 65424 => [0, 0, nil, "ミ", nil, nil, nil], + 65425 => [0, 0, nil, "ム", nil, nil, nil], + 65426 => [0, 0, nil, "メ", nil, nil, nil], + 65427 => [0, 0, nil, "モ", nil, nil, nil], + 65428 => [0, 0, nil, "ヤ", nil, nil, nil], + 65429 => [0, 0, nil, "ユ", nil, nil, nil], + 65430 => [0, 0, nil, "ヨ", nil, nil, nil], + 65431 => [0, 0, nil, "ラ", nil, nil, nil], + 65432 => [0, 0, nil, "リ", nil, nil, nil], + 65433 => [0, 0, nil, "ル", nil, nil, nil], + 65434 => [0, 0, nil, "レ", nil, nil, nil], + 65435 => [0, 0, nil, "ロ", nil, nil, nil], + 65436 => [0, 0, nil, "ワ", nil, nil, nil], + 65437 => [0, 0, nil, "ン", nil, nil, nil], + 65438 => [0, 0, nil, "゙", nil, nil, nil], + 65439 => [0, 0, nil, "゚", nil, nil, nil], + 65440 => [0, 0, nil, "ㅤ", nil, nil, nil], + 65441 => [0, 0, nil, "ㄱ", nil, nil, nil], + 65442 => [0, 0, nil, "ㄲ", nil, nil, nil], + 65443 => [0, 0, nil, "ㄳ", nil, nil, nil], + 65444 => [0, 0, nil, "ㄴ", nil, nil, nil], + 65445 => [0, 0, nil, "ㄵ", nil, nil, nil], + 65446 => [0, 0, nil, "ㄶ", nil, nil, nil], + 65447 => [0, 0, nil, "ㄷ", nil, nil, nil], + 65448 => [0, 0, nil, "ㄸ", nil, nil, nil], + 65449 => [0, 0, nil, "ㄹ", nil, nil, nil], + 65450 => [0, 0, nil, "ㄺ", nil, nil, nil], + 65451 => [0, 0, nil, "ㄻ", nil, nil, nil], + 65452 => [0, 0, nil, "ㄼ", nil, nil, nil], + 65453 => [0, 0, nil, "ㄽ", nil, nil, nil], + 65454 => [0, 0, nil, "ㄾ", nil, nil, nil], + 65455 => [0, 0, nil, "ㄿ", nil, nil, nil], + 65456 => [0, 0, nil, "ㅀ", nil, nil, nil], + 65457 => [0, 0, nil, "ㅁ", nil, nil, nil], + 65458 => [0, 0, nil, "ㅂ", nil, nil, nil], + 65459 => [0, 0, nil, "ㅃ", nil, nil, nil], + 65460 => [0, 0, nil, "ㅄ", nil, nil, nil], + 65461 => [0, 0, nil, "ㅅ", nil, nil, nil], + 65462 => [0, 0, nil, "ㅆ", nil, nil, nil], + 65463 => [0, 0, nil, "ㅇ", nil, nil, nil], + 65464 => [0, 0, nil, "ㅈ", nil, nil, nil], + 65465 => [0, 0, nil, "ㅉ", nil, nil, nil], + 65466 => [0, 0, nil, "ㅊ", nil, nil, nil], + 65467 => [0, 0, nil, "ㅋ", nil, nil, nil], + 65468 => [0, 0, nil, "ㅌ", nil, nil, nil], + 65469 => [0, 0, nil, "ㅍ", nil, nil, nil], + 65470 => [0, 0, nil, "ㅎ", nil, nil, nil], + 65474 => [0, 0, nil, "ㅏ", nil, nil, nil], + 65475 => [0, 0, nil, "ㅐ", nil, nil, nil], + 65476 => [0, 0, nil, "ㅑ", nil, nil, nil], + 65477 => [0, 0, nil, "ㅒ", nil, nil, nil], + 65478 => [0, 0, nil, "ㅓ", nil, nil, nil], + 65479 => [0, 0, nil, "ㅔ", nil, nil, nil], + 65482 => [0, 0, nil, "ㅕ", nil, nil, nil], + 65483 => [0, 0, nil, "ㅖ", nil, nil, nil], + 65484 => [0, 0, nil, "ㅗ", nil, nil, nil], + 65485 => [0, 0, nil, "ㅘ", nil, nil, nil], + 65486 => [0, 0, nil, "ㅙ", nil, nil, nil], + 65487 => [0, 0, nil, "ㅚ", nil, nil, nil], + 65490 => [0, 0, nil, "ㅛ", nil, nil, nil], + 65491 => [0, 0, nil, "ㅜ", nil, nil, nil], + 65492 => [0, 0, nil, "ㅝ", nil, nil, nil], + 65493 => [0, 0, nil, "ㅞ", nil, nil, nil], + 65494 => [0, 0, nil, "ㅟ", nil, nil, nil], + 65495 => [0, 0, nil, "ㅠ", nil, nil, nil], + 65498 => [0, 0, nil, "ㅡ", nil, nil, nil], + 65499 => [0, 0, nil, "ㅢ", nil, nil, nil], + 65500 => [0, 0, nil, "ㅣ", nil, nil, nil], + 65504 => [0, 0, nil, "¢", nil, nil, nil], + 65505 => [0, 0, nil, "£", nil, nil, nil], + 65506 => [0, 0, nil, "¬", nil, nil, nil], + 65507 => [0, 0, nil, "¯", nil, nil, nil], + 65508 => [0, 0, nil, "¦", nil, nil, nil], + 65509 => [0, 0, nil, "¥", nil, nil, nil], + 65510 => [0, 0, nil, "₩", nil, nil, nil], + 65512 => [0, 0, nil, "│", nil, nil, nil], + 65513 => [0, 0, nil, "←", nil, nil, nil], + 65514 => [0, 0, nil, "↑", nil, nil, nil], + 65515 => [0, 0, nil, "→", nil, nil, nil], + 65516 => [0, 0, nil, "↓", nil, nil, nil], + 65517 => [0, 0, nil, "■", nil, nil, nil], + 65518 => [0, 0, nil, "○", nil, nil, nil], + } + + UNICODE_MAX_LENGTH = 256 + ACE_MAX_LENGTH = 256 + + PUNYCODE_BASE = 36 + PUNYCODE_TMIN = 1 + PUNYCODE_TMAX = 26 + PUNYCODE_SKEW = 38 + PUNYCODE_DAMP = 700 + PUNYCODE_INITIAL_BIAS = 72 + PUNYCODE_INITIAL_N = 0x80 + PUNYCODE_DELIMITER = 0x2D + + PUNYCODE_MAXINT = 1 << 64 + + PUNYCODE_PRINT_ASCII = + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + + " !\"\#$%&'()*+,-./" + + "0123456789:;<=>?" + + "@ABCDEFGHIJKLMNO" + + "PQRSTUVWXYZ[\\]^_" + + "`abcdefghijklmno" + + "pqrstuvwxyz{|}~\n" + + # Input is invalid. + class PunycodeBadInput < StandardError; end + # Output would exceed the space provided. + class PunycodeBigOutput < StandardError; end + # Input needs wider integers to process. + class PunycodeOverflow < StandardError; end + + def self.punycode_encode(unicode) + unicode = unicode.to_s unless unicode.is_a?(String) + input = unicode.unpack("U*") + output = [0] * (ACE_MAX_LENGTH + 1) + input_length = input.size + output_length = [ACE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + delta = out = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: + input_length.times do |j| + if punycode_basic?(input[j]) + if max_out - out < 2 + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + output[out] = input[j] + out += 1 + end + end + + h = b = out + + # h is the number of code points that have been handled, b is the + # number of basic code points, and out is the number of characters + # that have been output. + + if b > 0 + output[out] = PUNYCODE_DELIMITER + out += 1 + end + + # Main encoding loop: + + while h < input_length + # All non-basic code points < n have been + # handled already. Find the next larger one: + + m = PUNYCODE_MAXINT + input_length.times do |j| + m = input[j] if (n...m) === input[j] + end + + # Increase delta enough to advance the decoder's + # state to , but guard against overflow: + + if m - n > (PUNYCODE_MAXINT - delta) / (h + 1) + raise PunycodeOverflow, "Input needs wider integers to process." + end + delta += (m - n) * (h + 1) + n = m + + input_length.times do |j| + # Punycode does not need to check whether input[j] is basic: + if input[j] < n + delta += 1 + if delta == 0 + raise PunycodeOverflow, + "Input needs wider integers to process." + end + end + + if input[j] == n + # Represent delta as a generalized variable-length integer: + + q = delta; k = PUNYCODE_BASE + while true + if out >= max_out + raise PunycodeBigOutput, + "Output would exceed the space provided." + end + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if q < t + output[out] = + punycode_encode_digit(t + (q - t) % (PUNYCODE_BASE - t)) + out += 1 + q = (q - t) / (PUNYCODE_BASE - t) + k += PUNYCODE_BASE + end + + output[out] = punycode_encode_digit(q) + out += 1 + bias = punycode_adapt(delta, h + 1, h == b) + delta = 0 + h += 1 + end + end + + delta += 1 + n += 1 + end + + output_length[0] = out + + outlen = out + outlen.times do |j| + c = output[j] + unless c >= 0 && c <= 127 + raise StandardError, "Invalid output char." + end + unless PUNYCODE_PRINT_ASCII[c] + raise PunycodeBadInput, "Input is invalid." + end + end + + output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "") + end + private_class_method :punycode_encode + + def self.punycode_decode(punycode) + input = [] + output = [] + + if ACE_MAX_LENGTH * 2 < punycode.size + raise PunycodeBigOutput, "Output would exceed the space provided." + end + punycode.each_byte do |c| + unless c >= 0 && c <= 127 + raise PunycodeBadInput, "Input is invalid." + end + input.push(c) + end + + input_length = input.length + output_length = [UNICODE_MAX_LENGTH] + + # Initialize the state + n = PUNYCODE_INITIAL_N + + out = i = 0 + max_out = output_length[0] + bias = PUNYCODE_INITIAL_BIAS + + # Handle the basic code points: Let b be the number of input code + # points before the last delimiter, or 0 if there is none, then + # copy the first b code points to the output. + + b = 0 + input_length.times do |j| + b = j if punycode_delimiter?(input[j]) + end + if b > max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + b.times do |j| + unless punycode_basic?(input[j]) + raise PunycodeBadInput, "Input is invalid." + end + output[out] = input[j] + out+=1 + end + + # Main decoding loop: Start just after the last delimiter if any + # basic code points were copied; start at the beginning otherwise. + + in_ = b > 0 ? b + 1 : 0 + while in_ < input_length + + # in_ is the index of the next character to be consumed, and + # out is the number of code points in the output array. + + # Decode a generalized variable-length integer into delta, + # which gets added to i. The overflow checking is easier + # if we increase i as we go, then subtract off its starting + # value at the end to obtain delta. + + oldi = i; w = 1; k = PUNYCODE_BASE + while true + if in_ >= input_length + raise PunycodeBadInput, "Input is invalid." + end + digit = punycode_decode_digit(input[in_]) + in_+=1 + if digit >= PUNYCODE_BASE + raise PunycodeBadInput, "Input is invalid." + end + if digit > (PUNYCODE_MAXINT - i) / w + raise PunycodeOverflow, "Input needs wider integers to process." + end + i += digit * w + t = ( + if k <= bias + PUNYCODE_TMIN + elsif k >= bias + PUNYCODE_TMAX + PUNYCODE_TMAX + else + k - bias + end + ) + break if digit < t + if w > PUNYCODE_MAXINT / (PUNYCODE_BASE - t) + raise PunycodeOverflow, "Input needs wider integers to process." + end + w *= PUNYCODE_BASE - t + k += PUNYCODE_BASE + end + + bias = punycode_adapt(i - oldi, out + 1, oldi == 0) + + # I was supposed to wrap around from out + 1 to 0, + # incrementing n each time, so we'll fix that now: + + if i / (out + 1) > PUNYCODE_MAXINT - n + raise PunycodeOverflow, "Input needs wider integers to process." + end + n += i / (out + 1) + i %= out + 1 + + # Insert n at position i of the output: + + # not needed for Punycode: + # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base + if out >= max_out + raise PunycodeBigOutput, "Output would exceed the space provided." + end + + #memmove(output + i + 1, output + i, (out - i) * sizeof *output) + output[i + 1, out - i] = output[i, out - i] + output[i] = n + i += 1 + + out += 1 + end + + output_length[0] = out + + output.pack("U*") + end + private_class_method :punycode_decode + + def self.punycode_basic?(codepoint) + codepoint < 0x80 + end + private_class_method :punycode_basic? + + def self.punycode_delimiter?(codepoint) + codepoint == PUNYCODE_DELIMITER + end + private_class_method :punycode_delimiter? + + def self.punycode_encode_digit(d) + d + 22 + 75 * ((d < 26) ? 1 : 0) + end + private_class_method :punycode_encode_digit + + # Returns the numeric value of a basic codepoint + # (for use in representing integers) in the range 0 to + # base - 1, or PUNYCODE_BASE if codepoint does not represent a value. + def self.punycode_decode_digit(codepoint) + if codepoint - 48 < 10 + codepoint - 22 + elsif codepoint - 65 < 26 + codepoint - 65 + elsif codepoint - 97 < 26 + codepoint - 97 + else + PUNYCODE_BASE + end + end + private_class_method :punycode_decode_digit + + # Bias adaptation method + def self.punycode_adapt(delta, numpoints, firsttime) + delta = firsttime ? delta / PUNYCODE_DAMP : delta >> 1 + # delta >> 1 is a faster way of doing delta / 2 + delta += delta / numpoints + difference = PUNYCODE_BASE - PUNYCODE_TMIN + + k = 0 + while delta > (difference * PUNYCODE_TMAX) / 2 + delta /= difference + k += PUNYCODE_BASE + end + + k + (difference + 1) * delta / (delta + PUNYCODE_SKEW) + end + private_class_method :punycode_adapt + end + # :startdoc: +end diff --git a/bin/gems/addressable-2.9.0/lib/addressable/template.rb b/bin/gems/addressable-2.9.0/lib/addressable/template.rb new file mode 100644 index 00000000..cb390289 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/template.rb @@ -0,0 +1,1040 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/uri" + +module Addressable + ## + # This is an implementation of a URI template based on + # RFC 6570 (http://tools.ietf.org/html/rfc6570). + class Template + # Constants used throughout the template code. + anything = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + + + variable_char_class = + Addressable::URI::CharacterClasses::ALPHA + + Addressable::URI::CharacterClasses::DIGIT + '_' + + var_char = + "(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)" + RESERVED = + "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])" + RESERVED_NO_COMMA = + "(?:[#{anything.delete(',')}]|%[a-fA-F0-9][a-fA-F0-9])" + UNRESERVED = + "(?:[#{ + Addressable::URI::CharacterClasses::UNRESERVED + }]|%[a-fA-F0-9][a-fA-F0-9])" + variable = + "(?:#{var_char}(?:\\.?#{var_char})*)" + varspec = + "(?:(#{variable})(\\*|:\\d+)?)" + VARNAME = + /^#{variable}$/ + VARSPEC = + /^#{varspec}$/ + VARIABLE_LIST = + /^#{varspec}(?:,#{varspec})*$/ + operator = + "+#./;?&=,!@|" + EXPRESSION = + /\{([#{operator}])?(#{varspec}(?:,#{varspec})*)\}/ + + + LEADERS = { + '?' => '?', + '/' => '/', + '#' => '#', + '.' => '.', + ';' => ';', + '&' => '&' + } + JOINERS = { + '?' => '&', + '.' => '.', + ';' => ';', + '&' => '&', + '/' => '/' + } + + ## + # Raised if an invalid template value is supplied. + class InvalidTemplateValueError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class InvalidTemplateOperatorError < StandardError + end + + ## + # Raised if an invalid template operator is used in a pattern. + class TemplateOperatorAbortedError < StandardError + end + + ## + # This class represents the data that is extracted when a Template + # is matched against a URI. + class MatchData + ## + # Creates a new MatchData object. + # MatchData objects should never be instantiated directly. + # + # @param [Addressable::URI] uri + # The URI that the template was matched against. + def initialize(uri, template, mapping) + @uri = uri.dup.freeze + @template = template + @mapping = mapping.dup.freeze + end + + ## + # @return [Addressable::URI] + # The URI that the Template was matched against. + attr_reader :uri + + ## + # @return [Addressable::Template] + # The Template used for the match. + attr_reader :template + + ## + # @return [Hash] + # The mapping that resulted from the match. + # Note that this mapping does not include keys or values for + # variables that appear in the Template, but are not present + # in the URI. + attr_reader :mapping + + ## + # @return [Array] + # The list of variables that were present in the Template. + # Note that this list will include variables which do not appear + # in the mapping because they were not present in URI. + def variables + self.template.variables + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # @return [Array] + # The list of values that were captured by the Template. + # Note that this list will include nils for any variables which + # were in the Template, but did not appear in the URI. + def values + @values ||= self.variables.inject([]) do |accu, key| + accu << self.mapping[key] + accu + end + end + alias_method :captures, :values + + ## + # Accesses captured values by name or by index. + # + # @param [String, Symbol, Fixnum] key + # Capture index or name. Note that when accessing by with index + # of 0, the full URI will be returned. The intention is to mimic + # the ::MatchData#[] behavior. + # + # @param [#to_int, nil] len + # If provided, an array of values will be returned with the given + # parameter used as length. + # + # @return [Array, String, nil] + # The captured value corresponding to the index or name. If the + # value was not provided or the key is unknown, nil will be + # returned. + # + # If the second parameter is provided, an array of that length will + # be returned instead. + def [](key, len = nil) + if len + to_a[key, len] + elsif String === key or Symbol === key + mapping[key.to_s] + else + to_a[key] + end + end + + ## + # @return [Array] + # Array with the matched URI as first element followed by the captured + # values. + def to_a + [to_s, *values] + end + + ## + # @return [String] + # The matched URI as String. + def to_s + uri.to_s + end + alias_method :string, :to_s + + # Returns multiple captured values at once. + # + # @param [String, Symbol, Fixnum] *indexes + # Indices of the captures to be returned + # + # @return [Array] + # Values corresponding to given indices. + # + # @see Addressable::Template::MatchData#[] + def values_at(*indexes) + indexes.map { |i| self[i] } + end + + ## + # Returns a String representation of the MatchData's state. + # + # @return [String] The MatchData's state, as a String. + def inspect + sprintf("#<%s:%#0x RESULT:%s>", + self.class.to_s, self.object_id, self.mapping.inspect) + end + + ## + # Dummy method for code expecting a ::MatchData instance + # + # @return [String] An empty string. + def pre_match + "" + end + alias_method :post_match, :pre_match + end + + ## + # Creates a new Addressable::Template object. + # + # @param [#to_str] pattern The URI Template pattern. + # + # @return [Addressable::Template] The initialized Template object. + def initialize(pattern) + if !pattern.respond_to?(:to_str) + raise TypeError, "Can't convert #{pattern.class} into String." + end + @pattern = pattern.to_str.dup.freeze + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.variables + self.variable_defaults + self.named_captures + super + end + + ## + # @return [String] The Template object's pattern. + attr_reader :pattern + + ## + # Returns a String representation of the Template object's state. + # + # @return [String] The Template object's state, as a String. + def inspect + sprintf("#<%s:%#0x PATTERN:%s>", + self.class.to_s, self.object_id, self.pattern) + end + + ## + # Returns true if the Template objects are equal. This method + # does NOT normalize either Template before doing the comparison. + # + # @param [Object] template The Template to compare. + # + # @return [TrueClass, FalseClass] + # true if the Templates are equivalent, false + # otherwise. + def ==(template) + return false unless template.kind_of?(Template) + return self.pattern == template.pattern + end + + ## + # Addressable::Template makes no distinction between `==` and `eql?`. + # + # @see #== + alias_method :eql?, :== + + ## + # Extracts a mapping from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).extract(uri, ExampleProcessor) + # #=> {"query" => "an example search query"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{second}/" + # ).extract(uri, ExampleProcessor) + # #=> {"first" => "a", "second" => "b/c"} + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # Addressable::Template.new( + # "http://example.com/{first}/{-list|/|second}/" + # ).extract(uri) + # #=> {"first" => "a", "second" => ["b", "c"]} + def extract(uri, processor=nil) + match_data = self.match(uri, processor) + return (match_data ? match_data.mapping : nil) + end + + ## + # Extracts match data from the URI using a URI Template pattern. + # + # @param [Addressable::URI, #to_str] uri + # The URI to extract from. + # + # @param [#restore, #match] processor + # A template processor object may optionally be supplied. + # + # The object should respond to either the restore or + # match messages or both. The restore method should + # take two parameters: `[String] name` and `[String] value`. + # The restore method should reverse any transformations that + # have been performed on the value to ensure a valid URI. + # The match method should take a single + # parameter: `[String] name`. The match method should return + # a String containing a regular expression capture group for + # matching on that particular variable. The default value is `".*?"`. + # The match method has no effect on multivariate operator + # expansions. + # + # @return [Hash, NilClass] + # The Hash mapping that was extracted from the URI, or + # nil if the URI didn't match the template. + # + # @example + # class ExampleProcessor + # def self.restore(name, value) + # return value.gsub(/\+/, " ") if name == "query" + # return value + # end + # + # def self.match(name) + # return ".*?" if name == "first" + # return ".*" + # end + # end + # + # uri = Addressable::URI.parse( + # "http://example.com/search/an+example+search+query/" + # ) + # match = Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["query"] + # match.captures + # #=> ["an example search query"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}/{+second}/" + # ).match(uri, ExampleProcessor) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", "b/c"] + # + # uri = Addressable::URI.parse("http://example.com/a/b/c/") + # match = Addressable::Template.new( + # "http://example.com/{first}{/second*}/" + # ).match(uri) + # match.variables + # #=> ["first", "second"] + # match.captures + # #=> ["a", ["b", "c"]] + def match(uri, processor=nil) + uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI) + mapping = {} + + # First, we need to process the pattern, and extract the values. + expansions, expansion_regexp = + parse_template_pattern(pattern, processor) + + return nil unless uri.to_str.match(expansion_regexp) + unparsed_values = uri.to_str.scan(expansion_regexp).flatten + + if uri.to_str == pattern + return Addressable::Template::MatchData.new(uri, self, mapping) + elsif expansions.size > 0 + index = 0 + expansions.each do |expansion| + _, operator, varlist = *expansion.match(EXPRESSION) + varlist.split(',').each do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + mapping[name] ||= nil + case operator + when nil, '+', '#', '/', '.' + unparsed_value = unparsed_values[index] + name = varspec[VARSPEC, 1] + value = unparsed_value + value = value.split(JOINERS[operator]) if value && modifier == '*' + when ';', '?', '&' + if modifier == '*' + if unparsed_values[index] + value = unparsed_values[index].split(JOINERS[operator]) + value = value.inject({}) do |acc, v| + key, val = v.split('=') + val = "" if val.nil? + acc[key] = val + acc + end + end + else + if (unparsed_values[index]) + name, value = unparsed_values[index].split('=') + value = "" if value.nil? + end + end + end + if processor != nil && processor.respond_to?(:restore) + value = processor.restore(name, value) + end + if processor == nil + if value.is_a?(Hash) + value = value.inject({}){|acc, (k, v)| + acc[Addressable::URI.unencode_component(k)] = + Addressable::URI.unencode_component(v) + acc + } + elsif value.is_a?(Array) + value = value.map{|v| Addressable::URI.unencode_component(v) } + else + value = Addressable::URI.unencode_component(value) + end + end + if !mapping.has_key?(name) || mapping[name].nil? + # Doesn't exist, set to value (even if value is nil) + mapping[name] = value + end + index = index + 1 + end + end + return Addressable::Template::MatchData.new(uri, self, mapping) + else + return nil + end + end + + ## + # Expands a URI template into another URI template. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::Template] The partially expanded URI template. + # + # @example + # Addressable::Template.new( + # "http://example.com/{one}/{two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/1/{two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two}/" + # ).partial_expand({"one" => "1"}).pattern + # #=> "http://example.com/?one=1{&two}/" + # + # Addressable::Template.new( + # "http://example.com/{?one,two,three}/" + # ).partial_expand({"one" => "1", "three" => 3}).pattern + # #=> "http://example.com/?one=1{&two}&three=3" + def partial_expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_partial_capture(mapping, capture, processor, normalize_values) + end + return Addressable::Template.new(result) + end + + ## + # Expands a URI template into a full URI. + # + # @param [Hash] mapping The mapping that corresponds to the pattern. + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError + # exception will be raised if the value is invalid. The transform + # method should return the transformed variable value as a String. + # If a transform method is used, the value will not be percent + # encoded automatically. Unicode normalization will be performed both + # before and after sending the value to the transform method. + # + # @return [Addressable::URI] The expanded URI template. + # + # @example + # class ExampleProcessor + # def self.validate(name, value) + # return !!(value =~ /^[\w ]+$/) if name == "query" + # return true + # end + # + # def self.transform(name, value) + # return value.gsub(/ /, "+") if name == "query" + # return value + # end + # end + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"}, + # ExampleProcessor + # ).to_str + # #=> "http://example.com/search/an+example+search+query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "an example search query"} + # ).to_str + # #=> "http://example.com/search/an%20example%20search%20query/" + # + # Addressable::Template.new( + # "http://example.com/search/{query}/" + # ).expand( + # {"query" => "bogus!"}, + # ExampleProcessor + # ).to_str + # #=> Addressable::Template::InvalidTemplateValueError + def expand(mapping, processor=nil, normalize_values=true) + result = self.pattern.dup + mapping = normalize_keys(mapping) + result.gsub!( EXPRESSION ) do |capture| + transform_capture(mapping, capture, processor, normalize_values) + end + return Addressable::URI.parse(result) + end + + ## + # Returns an Array of variables used within the template pattern. + # The variables are listed in the Array in the order they appear within + # the pattern. Multiple occurrences of a variable within a pattern are + # not represented in this Array. + # + # @return [Array] The variables present in the template's pattern. + def variables + @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq + end + alias_method :keys, :variables + alias_method :names, :variables + + ## + # Returns a mapping of variables to their default values specified + # in the template. Variables without defaults are not returned. + # + # @return [Hash] Mapping of template variables to their defaults + def variable_defaults + @variable_defaults ||= + Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] + end + + ## + # Coerces a template into a `Regexp` object. This regular expression will + # behave very similarly to the actual template, and should match the same + # URI values, but it cannot fully handle, for example, values that would + # extract to an `Array`. + # + # @return [Regexp] A regular expression which should match the template. + def to_regexp + _, source = parse_template_pattern(pattern) + Regexp.new(source) + end + + ## + # Returns the source of the coerced `Regexp`. + # + # @return [String] The source of the `Regexp` given by {#to_regexp}. + # + # @api private + def source + self.to_regexp.source + end + + ## + # Returns the named captures of the coerced `Regexp`. + # + # @return [Hash] The named captures of the `Regexp` given by {#to_regexp}. + # + # @api private + def named_captures + self.to_regexp.named_captures + end + + private + def ordered_variable_defaults + @ordered_variable_defaults ||= begin + expansions, _ = parse_template_pattern(pattern) + expansions.flat_map do |capture| + _, _, varlist = *capture.match(EXPRESSION) + varlist.split(',').map do |varspec| + varspec[VARSPEC, 1] + end + end + end + end + + + ## + # Loops through each capture and expands any values available in mapping + # + # @param [Hash] mapping + # Set of keys to expand + # @param [String] capture + # The expression to expand + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_partial_capture(mapping, capture, processor = nil, + normalize_values = true) + _, operator, varlist = *capture.match(EXPRESSION) + + vars = varlist.split(",") + + if operator == "?" + # partial expansion of form style query variables sometimes requires a + # slight reordering of the variables to produce a valid url. + first_to_expand = vars.find { |varspec| + _, name, _ = *varspec.match(VARSPEC) + mapping.key?(name) && !mapping[name].nil? + } + + vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand + end + + vars. + inject("".dup) do |acc, varspec| + _, name, _ = *varspec.match(VARSPEC) + next_val = if mapping.key? name + transform_capture(mapping, "{#{operator}#{varspec}}", + processor, normalize_values) + else + "{#{operator}#{varspec}}" + end + # If we've already expanded at least one '?' operator with non-empty + # value, change to '&' + operator = "&" if (operator == "?") && (next_val != "") + acc << next_val + end + end + + ## + # Transforms a mapped value so that values can be substituted into the + # template. + # + # @param [Hash] mapping The mapping to replace captures + # @param [String] capture + # The expression to replace + # @param [#validate, #transform] processor + # An optional processor object may be supplied. + # @param [Boolean] normalize_values + # Optional flag to enable/disable unicode normalization. Default: true + # + # + # The object should respond to either the validate or + # transform messages or both. Both the validate and + # transform methods should take two parameters: name and + # value. The validate method should return true + # or false; true if the value of the variable is valid, + # false otherwise. An InvalidTemplateValueError exception + # will be raised if the value is invalid. The transform method + # should return the transformed variable value as a String. If a + # transform method is used, the value will not be percent encoded + # automatically. Unicode normalization will be performed both before and + # after sending the value to the transform method. + # + # @return [String] The expanded expression + def transform_capture(mapping, capture, processor=nil, + normalize_values=true) + _, operator, varlist = *capture.match(EXPRESSION) + return_value = varlist.split(',').inject([]) do |acc, varspec| + _, name, modifier = *varspec.match(VARSPEC) + value = mapping[name] + unless value == nil || value == {} + allow_reserved = %w(+ #).include?(operator) + # Common primitives where the .to_s output is well-defined + if Numeric === value || Symbol === value || + value == true || value == false + value = value.to_s + end + length = modifier.gsub(':', '').to_i if modifier =~ /^:\d+/ + + unless (Hash === value) || + value.respond_to?(:to_ary) || value.respond_to?(:to_str) + raise TypeError, + "Can't convert #{value.class} into String or Array." + end + + value = normalize_value(value) if normalize_values + + if processor == nil || !processor.respond_to?(:transform) + # Handle percent escaping + if allow_reserved + encode_map = + Addressable::URI::CharacterClasses::RESERVED + + Addressable::URI::CharacterClasses::UNRESERVED + else + encode_map = Addressable::URI::CharacterClasses::UNRESERVED + end + if value.kind_of?(Array) + transformed_value = value.map do |val| + if length + Addressable::URI.encode_component(val[0...length], encode_map) + else + Addressable::URI.encode_component(val, encode_map) + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + elsif value.kind_of?(Hash) + transformed_value = value.map do |key, val| + if modifier == "*" + "#{ + Addressable::URI.encode_component( key, encode_map) + }=#{ + Addressable::URI.encode_component( val, encode_map) + }" + else + "#{ + Addressable::URI.encode_component( key, encode_map) + },#{ + Addressable::URI.encode_component( val, encode_map) + }" + end + end + unless modifier == "*" + transformed_value = transformed_value.join(',') + end + else + if length + transformed_value = Addressable::URI.encode_component( + value[0...length], encode_map) + else + transformed_value = Addressable::URI.encode_component( + value, encode_map) + end + end + end + + # Process, if we've got a processor + if processor != nil + if processor.respond_to?(:validate) + if !processor.validate(name, value) + display_value = value.kind_of?(Array) ? value.inspect : value + raise InvalidTemplateValueError, + "#{name}=#{display_value} is an invalid template value." + end + end + if processor.respond_to?(:transform) + transformed_value = processor.transform(name, value) + if normalize_values + transformed_value = normalize_value(transformed_value) + end + end + end + acc << [name, transformed_value] + end + acc + end + return "" if return_value.empty? + join_values(operator, return_value) + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [String, Nil] operator One of the operators from the set + # (?,&,+,#,;,/,.), or nil if there wasn't one. + # @param [Array] return_value + # The set of return values (as [variable_name, value] tuples) that will + # be joined together. + # + # @return [String] The transformed mapped value + def join_values(operator, return_value) + leader = LEADERS.fetch(operator, '') + joiner = JOINERS.fetch(operator, ',') + case operator + when '&', '?' + leader + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + v.join(joiner) + elsif v.is_a?(Array) + v.map{|inner_value| "#{k}=#{inner_value}"}.join(joiner) + else + "#{k}=#{v}" + end + }.join(joiner) + when ';' + return_value.map{|k,v| + if v.is_a?(Array) && v.first =~ /=/ + ';' + v.join(";") + elsif v.is_a?(Array) + ';' + v.map{|inner_value| "#{k}=#{inner_value}"}.join(";") + else + v && v != '' ? ";#{k}=#{v}" : ";#{k}" + end + }.join + else + leader + return_value.map{|k,v| v}.join(joiner) + end + end + + ## + # Takes a set of values, and joins them together based on the + # operator. + # + # @param [Hash, Array, String] value + # Normalizes unicode keys and values with String#unicode_normalize (NFC) + # + # @return [Hash, Array, String] The normalized values + def normalize_value(value) + # Handle unicode normalization + if value.respond_to?(:to_ary) + value.to_ary.map! { |val| normalize_value(val) } + elsif value.kind_of?(Hash) + value = value.inject({}) { |acc, (k, v)| + acc[normalize_value(k)] = normalize_value(v) + acc + } + else + value = value.to_s if !value.kind_of?(String) + if value.encoding != Encoding::UTF_8 + value = value.dup.force_encoding(Encoding::UTF_8) + end + value = value.unicode_normalize(:nfc) + end + value + end + + ## + # Generates a hash with string keys + # + # @param [Hash] mapping A mapping hash to normalize + # + # @return [Hash] + # A hash with stringified keys + def normalize_keys(mapping) + return mapping.inject({}) do |accu, pair| + name, value = pair + if Symbol === name + name = name.to_s + elsif name.respond_to?(:to_str) + name = name.to_str + else + raise TypeError, + "Can't convert #{name.class} into String." + end + accu[name] = value + accu + end + end + + ## + # Generates the Regexp that parses a template pattern. Memoizes the + # value if template processor not set (processors may not be deterministic) + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Array, Regexp] + # An array of expansion variables nad a regular expression which may be + # used to parse a template pattern + def parse_template_pattern(pattern, processor = nil) + if processor.nil? && pattern == @pattern + @cached_template_parse ||= + parse_new_template_pattern(pattern, processor) + else + parse_new_template_pattern(pattern, processor) + end + end + + ## + # Generates the Regexp that parses a template pattern. + # + # @param [String] pattern The URI template pattern. + # @param [#match] processor The template processor to use. + # + # @return [Array, Regexp] + # An array of expansion variables nad a regular expression which may be + # used to parse a template pattern + def parse_new_template_pattern(pattern, processor = nil) + # Escape the pattern. The two gsubs restore the escaped curly braces + # back to their original form. Basically, escape everything that isn't + # within an expansion. + escaped_pattern = Regexp.escape( + pattern + ).gsub(/\\\{(.*?)\\\}/) do |escaped| + escaped.gsub(/\\(.)/, "\\1") + end + + expansions = [] + + # Create a regular expression that captures the values of the + # variables in the URI. + regexp_string = escaped_pattern.gsub( EXPRESSION ) do |expansion| + + expansions << expansion + _, operator, varlist = *expansion.match(EXPRESSION) + leader = Regexp.escape(LEADERS.fetch(operator, '')) + joiner = Regexp.escape(JOINERS.fetch(operator, ',')) + varspecs = varlist.split(',') + combined = varspecs.map do |varspec| + _, name, modifier = *varspec.match(VARSPEC) + + result = processor && processor.respond_to?(:match) ? processor.match(name) : nil + if result + "(?<#{name}>#{ result })" + else + group = case operator + when '+' + "#{ RESERVED }*?" + when '#' + "#{ RESERVED }*?" + when '/' + "#{ UNRESERVED }*?" + when '.' + "#{ UNRESERVED.gsub('\.', '') }*?" + when ';' + "#{ UNRESERVED }*=?#{ UNRESERVED }*?" + when '?' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + when '&' + "#{ UNRESERVED }*=#{ UNRESERVED }*?" + else + "#{ UNRESERVED }*?" + end + if modifier == '*' + seg = case operator + when '+', '#' then "#{RESERVED_NO_COMMA}*+" + else group + end + joiner_pattern = operator.nil? ? joiner : "#{joiner}?" + "(?<#{name}>#{seg}(?:#{joiner_pattern}#{seg})*)?" + elsif varspecs.size > 1 && (operator == '+' || operator == '#') && + varspec != varspecs.last + "(?<#{name}>#{RESERVED_NO_COMMA}*+)?" + else + "(?<#{name}>#{group})?" + end + end + end.join("#{joiner}?") + "(?:|#{leader}#{combined})" + end + + # Ensure that the regular expression matches the whole URI. + regexp_string = "\\A#{regexp_string}\\z" + return expansions, Regexp.new(regexp_string) + end + + end +end diff --git a/bin/gems/addressable-2.9.0/lib/addressable/uri.rb b/bin/gems/addressable-2.9.0/lib/addressable/uri.rb new file mode 100644 index 00000000..07c9aeb5 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/uri.rb @@ -0,0 +1,2602 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +require "addressable/version" +require "addressable/idna" +require "public_suffix" + +## +# Addressable is a library for processing links and URIs. +module Addressable + ## + # This is an implementation of a URI parser based on + # RFC 3986, + # RFC 3987. + class URI + ## + # Raised if something other than a uri is supplied. + class InvalidURIError < StandardError + end + + ## + # Container for the character classes specified in + # RFC 3986. + # + # Note: Concatenated and interpolated `String`s are not affected by the + # `frozen_string_literal` directive and must be frozen explicitly. + # + # Interpolated `String`s *were* frozen this way before Ruby 3.0: + # https://bugs.ruby-lang.org/issues/17104 + module CharacterClasses + ALPHA = "a-zA-Z" + DIGIT = "0-9" + GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@" + SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=" + RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze + UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze + RESERVED_AND_UNRESERVED = RESERVED + UNRESERVED + PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze + SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze + HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze + AUTHORITY = (PCHAR + "\\[\\]").freeze + PATH = (PCHAR + "\\/").freeze + QUERY = (PCHAR + "\\/\\?").freeze + FRAGMENT = (PCHAR + "\\/\\?").freeze + end + + module NormalizeCharacterClasses + HOST = /[^#{CharacterClasses::HOST}]/ + UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ + PCHAR = /[^#{CharacterClasses::PCHAR}]/ + SCHEME = /[^#{CharacterClasses::SCHEME}]/ + FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ + QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)} + end + + module CharacterClassesRegexps + AUTHORITY = /[^#{CharacterClasses::AUTHORITY}]/ + FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ + HOST = /[^#{CharacterClasses::HOST}]/ + PATH = /[^#{CharacterClasses::PATH}]/ + QUERY = /[^#{CharacterClasses::QUERY}]/ + RESERVED = /[^#{CharacterClasses::RESERVED}]/ + RESERVED_AND_UNRESERVED = /[^#{CharacterClasses::RESERVED_AND_UNRESERVED}]/ + SCHEME = /[^#{CharacterClasses::SCHEME}]/ + UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ + end + + SLASH = '/' + EMPTY_STR = '' + + URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ + + PORT_MAPPING = { + "http" => 80, + "https" => 443, + "ftp" => 21, + "tftp" => 69, + "sftp" => 22, + "ssh" => 22, + "svn+ssh" => 22, + "telnet" => 23, + "nntp" => 119, + "gopher" => 70, + "wais" => 210, + "ldap" => 389, + "prospero" => 1525 + }.freeze + + ## + # Returns a URI object based on the parsed string. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # + # @return [Addressable::URI] The parsed URI. + def self.parse(uri) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + # Otherwise, convert to a String + begin + uri = uri.to_str + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{uri.class} into String." + end unless uri.is_a?(String) + + # This Regexp supplied as an example in RFC 3986, and it works great. + scan = uri.scan(URIREGEX) + fragments = scan[0] + scheme = fragments[1] + authority = fragments[3] + path = fragments[4] + query = fragments[6] + fragment = fragments[8] + user = nil + password = nil + host = nil + port = nil + if authority != nil + # The Regexp above doesn't split apart the authority. + userinfo = authority[/^([^\[\]]*)@/, 1] + if userinfo != nil + user = userinfo.strip[/^([^:]*):?/, 1] + password = userinfo.strip[/:(.*)$/, 1] + end + + host = authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + + port = authority[/:([^:@\[\]]*?)$/, 1] + port = nil if port == EMPTY_STR + end + + return new( + :scheme => scheme, + :user => user, + :password => password, + :host => host, + :port => port, + :path => path, + :query => query, + :fragment => fragment + ) + end + + ## + # Converts an input to a URI. The input does not have to be a valid + # URI — the method will use heuristics to guess what URI was intended. + # This is not standards-compliant, merely user-friendly. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI string to parse. + # No parsing is performed if the object is already an + # Addressable::URI. + # @param [Hash] hints + # A Hash of hints to the heuristic parser. + # Defaults to {:scheme => "http"}. + # + # @return [Addressable::URI] The parsed URI. + def self.heuristic_parse(uri, hints={}) + # If we were given nil, return nil. + return nil unless uri + # If a URI object is passed, just return itself. + return uri.dup if uri.kind_of?(self) + + # If a URI object of the Ruby standard library variety is passed, + # convert it to a string, then parse the string. + # We do the check this way because we don't want to accidentally + # cause a missing constant exception to be thrown. + if uri.class.name =~ /^URI\b/ + uri = uri.to_s + end + + unless uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + # Otherwise, convert to a String + uri = uri.to_str.dup.strip + hints = { + :scheme => "http" + }.merge(hints) + case uri + when /^http:\//i + uri.sub!(/^http:\/+/i, "http://") + when /^https:\//i + uri.sub!(/^https:\/+/i, "https://") + when /^feed:\/+http:\//i + uri.sub!(/^feed:\/+http:\/+/i, "feed:http://") + when /^feed:\//i + uri.sub!(/^feed:\/+/i, "feed://") + when %r[^file:/{4}]i + uri.sub!(%r[^file:/+]i, "file:////") + when %r[^file://localhost/]i + uri.sub!(%r[^file://localhost/+]i, "file:///") + when %r[^file:/+]i + uri.sub!(%r[^file:/+]i, "file:///") + when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ + uri.sub!(/^/, hints[:scheme] + "://") + when /\A\d+\..*:\d+\z/ + uri = "#{hints[:scheme]}://#{uri}" + end + match = uri.match(URIREGEX) + fragments = match.captures + authority = fragments[3] + if authority && authority.length > 0 + new_authority = authority.tr("\\", "/").gsub(" ", "%20") + # NOTE: We want offset 4, not 3! + offset = match.offset(4) + uri = uri.dup + uri[offset[0]...offset[1]] = new_authority + end + parsed = self.parse(uri) + if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ + parsed = self.parse(hints[:scheme] + "://" + uri) + end + if parsed.path.include?(".") + if parsed.path[/\b@\b/] + parsed.scheme = "mailto" unless parsed.scheme + elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] + parsed.defer_validation do + new_path = parsed.path.sub( + Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR) + parsed.host = new_host + parsed.path = new_path + parsed.scheme = hints[:scheme] unless parsed.scheme + end + end + end + return parsed + end + + ## + # Converts a path to a file scheme URI. If the path supplied is + # relative, it will be returned as a relative URI. If the path supplied + # is actually a non-file URI, it will parse the URI as if it had been + # parsed with Addressable::URI.parse. Handles all of the + # various Microsoft-specific formats for specifying paths. + # + # @param [String, Addressable::URI, #to_str] path + # Typically a String path to a file or directory, but + # will return a sensible return value if an absolute URI is supplied + # instead. + # + # @return [Addressable::URI] + # The parsed file scheme URI or the original URI if some other URI + # scheme was provided. + # + # @example + # base = Addressable::URI.convert_path("/absolute/path/") + # uri = Addressable::URI.convert_path("relative/path") + # (base + uri).to_s + # #=> "file:///absolute/path/relative/path" + # + # Addressable::URI.convert_path( + # "c:\\windows\\My Documents 100%20\\foo.txt" + # ).to_s + # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" + # + # Addressable::URI.convert_path("http://example.com/").to_s + # #=> "http://example.com/" + def self.convert_path(path) + # If we were given nil, return nil. + return nil unless path + # If a URI object is passed, just return itself. + return path if path.kind_of?(self) + unless path.respond_to?(:to_str) + raise TypeError, "Can't convert #{path.class} into String." + end + # Otherwise, convert to a String + path = path.to_str.strip + + path.sub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/ + path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/ + uri = self.parse(path) + + if uri.scheme == nil + # Adjust windows-style uris + uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do + "/#{$1.downcase}:/" + end + uri.path.tr!("\\", SLASH) + if File.exist?(uri.path) && + File.stat(uri.path).directory? + uri.path.chomp!(SLASH) + uri.path = uri.path + '/' + end + + # If the path is absolute, set the scheme and host. + if uri.path.start_with?(SLASH) + uri.scheme = "file" + uri.host = EMPTY_STR + end + uri.normalize! + end + + return uri + end + + ## + # Joins several URIs together. + # + # @param [String, Addressable::URI, #to_str] *uris + # The URIs to join. + # + # @return [Addressable::URI] The joined URI. + # + # @example + # base = "http://example.com/" + # uri = Addressable::URI.parse("relative/path") + # Addressable::URI.join(base, uri) + # #=> # + def self.join(*uris) + uri_objects = uris.collect do |uri| + unless uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + uri.kind_of?(self) ? uri : self.parse(uri.to_str) + end + result = uri_objects.shift.dup + uri_objects.each do |uri| + result.join!(uri) + end + return result + end + + ## + # Tables used to optimize encoding operations in `self.encode_component` + # and `self.normalize_component` + SEQUENCE_ENCODING_TABLE = (0..255).map do |byte| + format("%02x", byte).freeze + end.freeze + + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte| + format("%%%02X", byte).freeze + end.freeze + + ## + # Percent encodes a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' through + # '9' to be percent encoded. If a Regexp is passed, the + # value /[^b-zB-Z0-9]/ would have the same effect. A set of + # useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [Regexp] upcase_encoded + # A string of characters that may already be percent encoded, and whose + # encodings should be upcased. This allows normalization of percent + # encodings for characters not included in the + # character_class. + # + # @return [String] The encoded component. + # + # @example + # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) + # => "simple%2Fex%61mple" + # Addressable::URI.encode_component( + # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + def self.encode_component(component, character_class=CharacterClassesRegexps::RESERVED_AND_UNRESERVED, upcase_encoded='') + return nil if component.nil? + + begin + if component.kind_of?(Symbol) || + component.kind_of?(Numeric) || + component.kind_of?(TrueClass) || + component.kind_of?(FalseClass) + component = component.to_s + else + component = component.to_str + end + rescue TypeError, NoMethodError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + character_class = /[^#{character_class}]/ + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + # Avoiding gsub! because there are edge cases with frozen strings + component = component.gsub(character_class) do |char| + SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord] + end + if upcase_encoded.length > 0 + upcase_encoded_chars = upcase_encoded.bytes.map do |byte| + SEQUENCE_ENCODING_TABLE[byte] + end + component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/, + &:upcase) + end + + return component + end + + class << self + alias_method :escape_component, :encode_component + end + + ## + # Unencodes any percent encoded characters within a URI component. + # This method may be used for unencoding either components or full URIs, + # however, it is recommended to use the unencode_component + # alias when unencoding components. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI or component to unencode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @param [String] leave_encoded + # A string of characters to leave encoded. If a percent encoded character + # in this list is encountered then it will remain percent encoded. + # + # @return [String, Addressable::URI] + # The unencoded component or URI. + # The return type is determined by the return_type + # parameter. + def self.unencode(uri, return_type=String, leave_encoded='') + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + + result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence| + c = sequence[1..3].to_i(16).chr + c.force_encoding(sequence.encoding) + leave_encoded.include?(c) ? sequence : c + end + + result.force_encoding(Encoding::UTF_8) + if return_type == String + return result + elsif return_type == ::Addressable::URI + return ::Addressable::URI.parse(result) + end + end + + class << self + alias_method :unescape, :unencode + alias_method :unencode_component, :unencode + alias_method :unescape_component, :unencode + end + + + ## + # Normalizes the encoding of a URI component. + # + # @param [String, #to_str] component The URI component to encode. + # + # @param [String, Regexp] character_class + # The characters which are not percent encoded. If a String + # is passed, the String must be formatted as a regular + # expression character class. (Do not include the surrounding square + # brackets.) For example, "b-zB-Z0-9" would cause + # everything but the letters 'b' through 'z' and the numbers '0' + # through '9' to be percent encoded. If a Regexp is passed, + # the value /[^b-zB-Z0-9]/ would have the same effect. A + # set of useful String values may be found in the + # Addressable::URI::CharacterClasses module. The default + # value is the reserved plus unreserved character classes specified in + # RFC 3986. + # + # @param [String] leave_encoded + # When character_class is a String then + # leave_encoded is a string of characters that should remain + # percent encoded while normalizing the component; if they appear percent + # encoded in the original component, then they will be upcased ("%2f" + # normalized to "%2F") but otherwise left alone. + # + # @return [String] The normalized component. + # + # @example + # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", /[^b-zB-Z]/ + # ) + # => "simple%2Fex%61mple" + # Addressable::URI.normalize_component( + # "simpl%65/%65xampl%65", + # Addressable::URI::CharacterClasses::UNRESERVED + # ) + # => "simple%2Fexample" + # Addressable::URI.normalize_component( + # "one%20two%2fthree%26four", + # "0-9a-zA-Z &/", + # "/" + # ) + # => "one two%2Fthree&four" + def self.normalize_component(component, character_class= + CharacterClassesRegexps::RESERVED_AND_UNRESERVED, + leave_encoded='') + return nil if component.nil? + + begin + component = component.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{component.class} into String." + end if !component.is_a? String + + if ![String, Regexp].include?(character_class.class) + raise TypeError, + "Expected String or Regexp, got #{character_class.inspect}" + end + if character_class.kind_of?(String) + leave_re = if leave_encoded.length > 0 + character_class = "#{character_class}%" unless character_class.include?('%') + + bytes = leave_encoded.bytes + leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|') + "|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})" + end + + character_class = if leave_re + /[^#{character_class}]#{leave_re}/ + else + /[^#{character_class}]/ + end + end + # We can't perform regexps on invalid UTF sequences, but + # here we need to, so switch to ASCII. + component = component.dup + component.force_encoding(Encoding::ASCII_8BIT) + unencoded = self.unencode_component(component, String, leave_encoded) + begin + encoded = self.encode_component( + unencoded.unicode_normalize(:nfc), + character_class, + leave_encoded + ) + rescue ArgumentError + encoded = self.encode_component(unencoded) + end + encoded.force_encoding(Encoding::UTF_8) + return encoded + end + + ## + # Percent encodes any special characters in the URI. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.encode(uri, return_type=String) + return nil if uri.nil? + + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(uri_object.scheme, + Addressable::URI::CharacterClassesRegexps::SCHEME), + :authority => self.encode_component(uri_object.authority, + Addressable::URI::CharacterClassesRegexps::AUTHORITY), + :path => self.encode_component(uri_object.path, + Addressable::URI::CharacterClassesRegexps::PATH), + :query => self.encode_component(uri_object.query, + Addressable::URI::CharacterClassesRegexps::QUERY), + :fragment => self.encode_component(uri_object.fragment, + Addressable::URI::CharacterClassesRegexps::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + class << self + alias_method :escape, :encode + end + + ## + # Normalizes the encoding of a URI. Characters within a hostname are + # not percent encoded to allow for internationalized domain names. + # + # @param [String, Addressable::URI, #to_str] uri + # The URI to encode. + # + # @param [Class] return_type + # The type of object to return. + # This value may only be set to String or + # Addressable::URI. All other values are invalid. Defaults + # to String. + # + # @return [String, Addressable::URI] + # The encoded URI. + # The return type is determined by the return_type + # parameter. + def self.normalized_encode(uri, return_type=String) + begin + uri = uri.to_str + rescue NoMethodError, TypeError + raise TypeError, "Can't convert #{uri.class} into String." + end if !uri.is_a? String + + if ![String, ::Addressable::URI].include?(return_type) + raise TypeError, + "Expected Class (String or Addressable::URI), " + + "got #{return_type.inspect}" + end + uri_object = uri.kind_of?(self) ? uri : self.parse(uri) + components = { + :scheme => self.unencode_component(uri_object.scheme), + :user => self.unencode_component(uri_object.user), + :password => self.unencode_component(uri_object.password), + :host => self.unencode_component(uri_object.host), + :port => (uri_object.port.nil? ? nil : uri_object.port.to_s), + :path => self.unencode_component(uri_object.path), + :query => self.unencode_component(uri_object.query), + :fragment => self.unencode_component(uri_object.fragment) + } + components.each do |key, value| + if value != nil + begin + components[key] = value.to_str.unicode_normalize(:nfc) + rescue ArgumentError + # Likely a malformed UTF-8 character, skip unicode normalization + components[key] = value.to_str + end + end + end + encoded_uri = Addressable::URI.new( + :scheme => self.encode_component(components[:scheme], + Addressable::URI::CharacterClassesRegexps::SCHEME), + :user => self.encode_component(components[:user], + Addressable::URI::CharacterClassesRegexps::UNRESERVED), + :password => self.encode_component(components[:password], + Addressable::URI::CharacterClassesRegexps::UNRESERVED), + :host => components[:host], + :port => components[:port], + :path => self.encode_component(components[:path], + Addressable::URI::CharacterClassesRegexps::PATH), + :query => self.encode_component(components[:query], + Addressable::URI::CharacterClassesRegexps::QUERY), + :fragment => self.encode_component(components[:fragment], + Addressable::URI::CharacterClassesRegexps::FRAGMENT) + ) + if return_type == String + return encoded_uri.to_s + elsif return_type == ::Addressable::URI + return encoded_uri + end + end + + ## + # Encodes a set of key/value pairs according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [#to_hash, #to_ary] form_values + # The form values to encode. + # + # @param [TrueClass, FalseClass] sort + # Sort the key/value pairs prior to encoding. + # Defaults to false. + # + # @return [String] + # The encoded value. + def self.form_encode(form_values, sort=false) + if form_values.respond_to?(:to_hash) + form_values = form_values.to_hash.to_a + elsif form_values.respond_to?(:to_ary) + form_values = form_values.to_ary + else + raise TypeError, "Can't convert #{form_values.class} into Array." + end + + form_values = form_values.inject([]) do |accu, (key, value)| + if value.kind_of?(Array) + value.each do |v| + accu << [key.to_s, v.to_s] + end + else + accu << [key.to_s, value.to_s] + end + accu + end + + if sort + # Useful for OAuth and optimizing caching systems + form_values = form_values.sort + end + escaped_form_values = form_values.map do |(key, value)| + # Line breaks are CRLF pairs + [ + self.encode_component( + key.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClassesRegexps::UNRESERVED + ).gsub("%20", "+"), + self.encode_component( + value.gsub(/(\r\n|\n|\r)/, "\r\n"), + CharacterClassesRegexps::UNRESERVED + ).gsub("%20", "+") + ] + end + return escaped_form_values.map do |(key, value)| + "#{key}=#{value}" + end.join("&") + end + + ## + # Decodes a String according to the rules for the + # application/x-www-form-urlencoded MIME type. + # + # @param [String, #to_str] encoded_value + # The form values to decode. + # + # @return [Array] + # The decoded values. + # This is not a Hash because of the possibility for + # duplicate keys. + def self.form_unencode(encoded_value) + if !encoded_value.respond_to?(:to_str) + raise TypeError, "Can't convert #{encoded_value.class} into String." + end + encoded_value = encoded_value.to_str + split_values = encoded_value.split("&").map do |pair| + pair.split("=", 2) + end + return split_values.map do |(key, value)| + [ + key ? self.unencode_component( + key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil, + value ? (self.unencode_component( + value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil + ] + end + end + + ## + # Creates a new uri object from component parts. + # + # @option [String, #to_str] scheme The scheme component. + # @option [String, #to_str] user The user component. + # @option [String, #to_str] password The password component. + # @option [String, #to_str] userinfo + # The userinfo component. If this is supplied, the user and password + # components must be omitted. + # @option [String, #to_str] host The host component. + # @option [String, #to_str] port The port component. + # @option [String, #to_str] authority + # The authority component. If this is supplied, the user, password, + # userinfo, host, and port components must be omitted. + # @option [String, #to_str] path The path component. + # @option [String, #to_str] query The query component. + # @option [String, #to_str] fragment The fragment component. + # + # @return [Addressable::URI] The constructed URI object. + def initialize(options={}) + if options.has_key?(:authority) + if (options.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if options.has_key?(:userinfo) + if (options.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + reset_ivs + + defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + self.scheme = options[:scheme] if options[:scheme] + self.user = options[:user] if options[:user] + self.password = options[:password] if options[:password] + self.userinfo = options[:userinfo] if options[:userinfo] + self.host = options[:host] if options[:host] + self.port = options[:port] if options[:port] + self.authority = options[:authority] if options[:authority] + self.path = options[:path] if options[:path] + self.query = options[:query] if options[:query] + self.query_values = options[:query_values] if options[:query_values] + self.fragment = options[:fragment] if options[:fragment] + end + + to_s # force path validation + end + + ## + # Freeze URI, initializing instance variables. + # + # @return [Addressable::URI] The frozen URI object. + def freeze + self.normalized_scheme + self.normalized_user + self.normalized_password + self.normalized_userinfo + self.normalized_host + self.normalized_port + self.normalized_authority + self.normalized_site + self.normalized_path + self.normalized_query + self.normalized_fragment + self.hash + super + end + + ## + # The scheme component for this URI. + # + # @return [String] The scheme component. + attr_reader :scheme + + ## + # The scheme component for this URI, normalized. + # + # @return [String] The scheme component, normalized. + def normalized_scheme + return nil unless self.scheme + if @normalized_scheme == NONE + @normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i + "svn+ssh".dup + else + Addressable::URI.normalize_component( + self.scheme.strip.downcase, + Addressable::URI::NormalizeCharacterClasses::SCHEME + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_scheme) + @normalized_scheme + end + + ## + # Sets the scheme component for this URI. + # + # @param [String, #to_str] new_scheme The new scheme component. + def scheme=(new_scheme) + if new_scheme && !new_scheme.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_scheme.class} into String." + elsif new_scheme + new_scheme = new_scheme.to_str + end + if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i + raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'" + end + @scheme = new_scheme + @scheme = nil if @scheme.to_s.strip.empty? + + # Reset dependent values + @normalized_scheme = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The user component for this URI. + # + # @return [String] The user component. + attr_reader :user + + ## + # The user component for this URI, normalized. + # + # @return [String] The user component, normalized. + def normalized_user + return nil unless self.user + return @normalized_user unless @normalized_user == NONE + @normalized_user = begin + if normalized_scheme =~ /https?/ && self.user.strip.empty? && + (!self.password || self.password.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.user.strip, + Addressable::URI::NormalizeCharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_user) + @normalized_user + end + + ## + # Sets the user component for this URI. + # + # @param [String, #to_str] new_user The new user component. + def user=(new_user) + if new_user && !new_user.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_user.class} into String." + end + @user = new_user ? new_user.to_str : nil + + # You can't have a nil user with a non-nil password + if password != nil + @user = EMPTY_STR unless user + end + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_user = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The password component for this URI. + # + # @return [String] The password component. + attr_reader :password + + ## + # The password component for this URI, normalized. + # + # @return [String] The password component, normalized. + def normalized_password + return nil unless self.password + return @normalized_password unless @normalized_password == NONE + @normalized_password = begin + if self.normalized_scheme =~ /https?/ && self.password.strip.empty? && + (!self.user || self.user.strip.empty?) + nil + else + Addressable::URI.normalize_component( + self.password.strip, + Addressable::URI::NormalizeCharacterClasses::UNRESERVED + ) + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_password) + @normalized_password + end + + ## + # Sets the password component for this URI. + # + # @param [String, #to_str] new_password The new password component. + def password=(new_password) + if new_password && !new_password.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_password.class} into String." + end + @password = new_password ? new_password.to_str : nil + + # You can't have a nil user with a non-nil password + if @password != nil + self.user = EMPTY_STR if user.nil? + end + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_password = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The userinfo component for this URI. + # Combines the user and password components. + # + # @return [String] The userinfo component. + def userinfo + current_user = self.user + current_password = self.password + (current_user || current_password) && @userinfo ||= begin + if current_user && current_password + "#{current_user}:#{current_password}" + elsif current_user && !current_password + "#{current_user}" + end + end + end + + ## + # The userinfo component for this URI, normalized. + # + # @return [String] The userinfo component, normalized. + def normalized_userinfo + return nil unless self.userinfo + return @normalized_userinfo unless @normalized_userinfo == NONE + @normalized_userinfo = begin + current_user = self.normalized_user + current_password = self.normalized_password + if !current_user && !current_password + nil + elsif current_user && current_password + "#{current_user}:#{current_password}".dup + elsif current_user && !current_password + "#{current_user}".dup + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_userinfo) + @normalized_userinfo + end + + ## + # Sets the userinfo component for this URI. + # + # @param [String, #to_str] new_userinfo The new userinfo component. + def userinfo=(new_userinfo) + if new_userinfo && !new_userinfo.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_userinfo.class} into String." + end + new_user, new_password = if new_userinfo + [ + new_userinfo.to_str.strip[/^(.*):/, 1], + new_userinfo.to_str.strip[/:(.*)$/, 1] + ] + else + [nil, nil] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + + # Reset dependent values + @authority = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The host component for this URI. + # + # @return [String] The host component. + attr_reader :host + + ## + # The host component for this URI, normalized. + # + # @return [String] The host component, normalized. + def normalized_host + return nil unless self.host + + @normalized_host ||= begin + if !self.host.strip.empty? + result = ::Addressable::IDNA.to_ascii( + URI.unencode_component(self.host.strip.downcase) + ) + if result =~ /[^\.]\.$/ + # Single trailing dots are unnecessary. + result = result[0...-1] + end + result = Addressable::URI.normalize_component( + result, + NormalizeCharacterClasses::HOST + ) + result + else + EMPTY_STR.dup + end + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_host) + @normalized_host + end + + ## + # Sets the host component for this URI. + # + # @param [String, #to_str] new_host The new host component. + def host=(new_host) + if new_host && !new_host.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_host.class} into String." + end + @host = new_host ? new_host.to_str : nil + + # Reset dependent values + @authority = nil + @normalized_host = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # This method is same as URI::Generic#host except + # brackets for IPv6 (and 'IPvFuture') addresses are removed. + # + # @see Addressable::URI#host + # + # @return [String] The hostname for this URI. + def hostname + v = self.host + /\A\[(.*)\]\z/ =~ v ? $1 : v + end + + ## + # This method is same as URI::Generic#host= except + # the argument can be a bare IPv6 address (or 'IPvFuture'). + # + # @see Addressable::URI#host= + # + # @param [String, #to_str] new_hostname The new hostname for this URI. + def hostname=(new_hostname) + if new_hostname && + (new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?)) + new_hostname = new_hostname.to_s + elsif new_hostname && !new_hostname.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_hostname.class} into String." + end + v = new_hostname ? new_hostname.to_str : nil + v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v + self.host = v + end + + ## + # Returns the top-level domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk" + def tld + PublicSuffix.parse(self.host, ignore_private: true).tld + end + + ## + # Sets the top-level domain for this URI. + # + # @param [String, #to_str] new_tld The new top-level domain. + def tld=(new_tld) + replaced_tld = host.sub(/#{tld}\z/, new_tld) + self.host = PublicSuffix::Domain.new(replaced_tld).to_s + end + + ## + # Returns the public suffix domain for this host. + # + # @example + # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk" + def domain + PublicSuffix.domain(self.host, ignore_private: true) + end + + ## + # The authority component for this URI. + # Combines the user, password, host, and port components. + # + # @return [String] The authority component. + def authority + self.host && @authority ||= begin + authority = String.new + if self.userinfo != nil + authority << "#{self.userinfo}@" + end + authority << self.host + if self.port != nil + authority << ":#{self.port}" + end + authority + end + end + + ## + # The authority component for this URI, normalized. + # + # @return [String] The authority component, normalized. + def normalized_authority + return nil unless self.authority + @normalized_authority ||= begin + authority = String.new + if self.normalized_userinfo != nil + authority << "#{self.normalized_userinfo}@" + end + authority << self.normalized_host + if self.normalized_port != nil + authority << ":#{self.normalized_port}" + end + authority + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_authority) + @normalized_authority + end + + ## + # Sets the authority component for this URI. + # + # @param [String, #to_str] new_authority The new authority component. + def authority=(new_authority) + if new_authority + if !new_authority.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_authority.class} into String." + end + new_authority = new_authority.to_str + new_userinfo = new_authority[/^([^\[\]]*)@/, 1] + if new_userinfo + new_user = new_userinfo.strip[/^([^:]*):?/, 1] + new_password = new_userinfo.strip[/:(.*)$/, 1] + end + new_host = new_authority.sub( + /^([^\[\]]*)@/, EMPTY_STR + ).sub( + /:([^:@\[\]]*?)$/, EMPTY_STR + ) + new_port = + new_authority[/:([^:@\[\]]*?)$/, 1] + end + + # Password assigned first to ensure validity in case of nil + self.password = new_password + self.user = new_user + self.host = new_host + self.port = new_port + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. + # + # @return [String] The serialized origin. + def origin + if self.scheme && self.authority + if self.normalized_port + "#{self.normalized_scheme}://#{self.normalized_host}" + + ":#{self.normalized_port}" + else + "#{self.normalized_scheme}://#{self.normalized_host}" + end + else + "null" + end + end + + ## + # Sets the origin for this URI, serialized to ASCII, as per + # RFC 6454, section 6.2. This assignment will reset the `userinfo` + # component. + # + # @param [String, #to_str] new_origin The new origin component. + def origin=(new_origin) + if new_origin + if !new_origin.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_origin.class} into String." + end + new_origin = new_origin.to_str + new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1] + unless new_scheme + raise InvalidURIError, 'An origin cannot omit the scheme.' + end + new_host = new_origin[/:\/\/([^\/?#:]+)/, 1] + unless new_host + raise InvalidURIError, 'An origin cannot omit the host.' + end + new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1] + end + + self.scheme = new_scheme + self.host = new_host + self.port = new_port + self.userinfo = nil + + # Reset dependent values + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @normalized_authority = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + # Returns an array of known ip-based schemes. These schemes typically + # use a similar URI form: + # //:@:/ + def self.ip_based_schemes + return self.port_mapping.keys + end + + # Returns a hash of common IP-based schemes and their default port + # numbers. Adding new schemes to this hash, as necessary, will allow + # for better URI normalization. + def self.port_mapping + PORT_MAPPING + end + + ## + # The port component for this URI. + # This is the port number actually given in the URI. This does not + # infer port numbers from default values. + # + # @return [Integer] The port component. + attr_reader :port + + ## + # The port component for this URI, normalized. + # + # @return [Integer] The port component, normalized. + def normalized_port + return nil unless self.port + return @normalized_port unless @normalized_port == NONE + @normalized_port = begin + if URI.port_mapping[self.normalized_scheme] == self.port + nil + else + self.port + end + end + end + + ## + # Sets the port component for this URI. + # + # @param [String, Integer, #to_s] new_port The new port component. + def port=(new_port) + if new_port != nil && new_port.respond_to?(:to_str) + new_port = Addressable::URI.unencode_component(new_port.to_str) + end + + if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding? + raise InvalidURIError, "Invalid encoding in port" + end + + if new_port != nil && !(new_port.to_s =~ /^\d+$/) + raise InvalidURIError, + "Invalid port number: #{new_port.inspect}" + end + + @port = new_port.to_s.to_i + @port = nil if @port == 0 + + # Reset dependent values + @authority = nil + @normalized_port = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The inferred port component for this URI. + # This method will normalize to the default port for the URI's scheme if + # the port isn't explicitly specified in the URI. + # + # @return [Integer] The inferred port component. + def inferred_port + if self.port.to_i == 0 + self.default_port + else + self.port.to_i + end + end + + ## + # The default port for this URI's scheme. + # This method will always returns the default port for the URI's scheme + # regardless of the presence of an explicit port in the URI. + # + # @return [Integer] The default port. + def default_port + URI.port_mapping[self.scheme.strip.downcase] if self.scheme + end + + ## + # The combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The components that identify a site. + def site + (self.scheme || self.authority) && @site ||= begin + site_string = "".dup + site_string << "#{self.scheme}:" if self.scheme != nil + site_string << "//#{self.authority}" if self.authority != nil + site_string + end + end + + ## + # The normalized combination of components that represent a site. + # Combines the scheme, user, password, host, and port components. + # Primarily useful for HTTP and HTTPS. + # + # For example, "http://example.com/path?query" would have a + # site value of "http://example.com". + # + # @return [String] The normalized components that identify a site. + def normalized_site + return nil unless self.site + @normalized_site ||= begin + site_string = "".dup + if self.normalized_scheme != nil + site_string << "#{self.normalized_scheme}:" + end + if self.normalized_authority != nil + site_string << "//#{self.normalized_authority}" + end + site_string + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_site) + @normalized_site + end + + ## + # Sets the site value for this URI. + # + # @param [String, #to_str] new_site The new site value. + def site=(new_site) + if new_site + if !new_site.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_site.class} into String." + end + new_site = new_site.to_str + # These two regular expressions derived from the primary parsing + # expression + self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1] + self.authority = new_site[ + /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1 + ] + else + self.scheme = nil + self.authority = nil + end + end + + ## + # The path component for this URI. + # + # @return [String] The path component. + attr_reader :path + + NORMPATH = /^(?!\/)[^\/:]*:.*$/ + ## + # The path component for this URI, normalized. + # + # @return [String] The path component, normalized. + def normalized_path + @normalized_path ||= begin + path = self.path.to_s + if self.scheme == nil && path =~ NORMPATH + # Relative paths with colons in the first segment are ambiguous. + path = path.sub(":", "%2F") + end + # String#split(delimiter, -1) uses the more strict splitting behavior + # found by default in Python. + result = path.strip.split(SLASH, -1).map do |segment| + Addressable::URI.normalize_component( + segment, + Addressable::URI::NormalizeCharacterClasses::PCHAR + ) + end.join(SLASH) + + result = URI.normalize_path(result) + if result.empty? && + ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) + result = SLASH.dup + end + result + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_path) + @normalized_path + end + + ## + # Sets the path component for this URI. + # + # @param [String, #to_str] new_path The new path component. + def path=(new_path) + if new_path && !new_path.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_path.class} into String." + end + @path = (new_path || EMPTY_STR).to_str + if !@path.empty? && @path[0..0] != SLASH && host != nil + @path = "/#{@path}" + end + + # Reset dependent values + @normalized_path = nil + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # The basename, if any, of the file in the path component. + # + # @return [String] The path's basename. + def basename + # Path cannot be nil + return File.basename(self.path).sub(/;[^\/]*$/, EMPTY_STR) + end + + ## + # The extname, if any, of the file in the path component. + # Empty string if there is no extension. + # + # @return [String] The path's extname. + def extname + return nil unless self.path + return File.extname(self.basename) + end + + ## + # The query component for this URI. + # + # @return [String] The query component. + attr_reader :query + + ## + # The query component for this URI, normalized. + # + # @return [String] The query component, normalized. + def normalized_query(*flags) + return nil unless self.query + return @normalized_query unless @normalized_query == NONE + @normalized_query = begin + modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup + # Make sure possible key-value pair delimiters are escaped. + modified_query_class.sub!("\\&", "").sub!("\\;", "") + pairs = (query || "").split("&", -1) + pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted) + pairs.sort! if flags.include?(:sorted) + component = pairs.map do |pair| + Addressable::URI.normalize_component( + pair, + Addressable::URI::NormalizeCharacterClasses::QUERY, + "+" + ) + end.join("&") + component == "" ? nil : component + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_query) + @normalized_query + end + + ## + # Sets the query component for this URI. + # + # @param [String, #to_str] new_query The new query component. + def query=(new_query) + if new_query && !new_query.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_query.class} into String." + end + @query = new_query ? new_query.to_str : nil + + # Reset dependent values + @normalized_query = NONE + remove_composite_values + end + + ## + # Converts the query component to a Hash value. + # + # @param [Class] return_type The return type desired. Value must be either + # `Hash` or `Array`. + # + # @return [Hash, Array, nil] The query string parsed as a Hash or Array + # or nil if the query string is blank. + # + # @example + # Addressable::URI.parse("?one=1&two=2&three=3").query_values + # #=> {"one" => "1", "two" => "2", "three" => "3"} + # Addressable::URI.parse("?one=two&one=three").query_values(Array) + # #=> [["one", "two"], ["one", "three"]] + # Addressable::URI.parse("?one=two&one=three").query_values(Hash) + # #=> {"one" => "three"} + # Addressable::URI.parse("?").query_values + # #=> {} + # Addressable::URI.parse("").query_values + # #=> nil + def query_values(return_type=Hash) + empty_accumulator = Array == return_type ? [] : {} + if return_type != Hash && return_type != Array + raise ArgumentError, "Invalid return type. Must be Hash or Array." + end + return nil if self.query == nil + split_query = self.query.split("&").map do |pair| + pair.split("=", 2) if pair && !pair.empty? + end.compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + # I'd rather use key/value identifiers instead of array lookups, + # but in this case I really want to maintain the exact pair structure, + # so it's best to make all changes in-place. + pair[0] = URI.unencode_component(pair[0]) + if pair[1].respond_to?(:to_str) + value = pair[1].to_str + # I loathe the fact that I have to do this. Stupid HTML 4.01. + # Treating '+' as a space was just an unbelievably bad idea. + # There was nothing wrong with '%20'! + # If it ain't broke, don't fix it! + value = value.tr("+", " ") if ["http", "https", nil].include?(scheme) + pair[1] = URI.unencode_component(value) + end + if return_type == Hash + accu[pair[0]] = pair[1] + else + accu << pair + end + accu + end + end + + ## + # Sets the query component for this URI from a Hash object. + # An empty Hash or Array will result in an empty query string. + # + # @param [Hash, #to_hash, Array] new_query_values The new query values. + # + # @example + # uri.query_values = {:a => "a", :b => ["c", "d", "e"]} + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]] + # uri.query + # # => "a=a&b=c&b=d&b=e" + # uri.query_values = [['flag'], ['key', 'value']] + # uri.query + # # => "flag&key=value" + def query_values=(new_query_values) + if new_query_values == nil + self.query = nil + return nil + end + + if !new_query_values.is_a?(Array) + if !new_query_values.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{new_query_values.class} into Hash." + end + new_query_values = new_query_values.to_hash + new_query_values = new_query_values.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + new_query_values.sort! + end + + # new_query_values have form [['key1', 'value1'], ['key2', 'value2']] + buffer = "".dup + new_query_values.each do |key, value| + encoded_key = URI.encode_component( + key, CharacterClassesRegexps::UNRESERVED + ) + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = URI.encode_component( + sub_value, CharacterClassesRegexps::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = URI.encode_component( + value, CharacterClassesRegexps::UNRESERVED + ) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + self.query = buffer.chop + end + + ## + # The HTTP request URI for this URI. This is the path and the + # query string. + # + # @return [String] The request URI required for an HTTP request. + def request_uri + return nil if self.absolute? && self.scheme !~ /^https?$/i + return ( + (!self.path.empty? ? self.path : SLASH) + + (self.query ? "?#{self.query}" : EMPTY_STR) + ) + end + + ## + # Sets the HTTP request URI for this URI. + # + # @param [String, #to_str] new_request_uri The new HTTP request URI. + def request_uri=(new_request_uri) + if !new_request_uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_request_uri.class} into String." + end + if self.absolute? && self.scheme !~ /^https?$/i + raise InvalidURIError, + "Cannot set an HTTP request URI for a non-HTTP URI." + end + new_request_uri = new_request_uri.to_str + path_component = new_request_uri[/^([^\?]*)\??(?:.*)$/, 1] + query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] + path_component = path_component.to_s + path_component = (!path_component.empty? ? path_component : SLASH) + self.path = path_component + self.query = query_component + + # Reset dependent values + remove_composite_values + end + + ## + # The fragment component for this URI. + # + # @return [String] The fragment component. + attr_reader :fragment + + ## + # The fragment component for this URI, normalized. + # + # @return [String] The fragment component, normalized. + def normalized_fragment + return nil unless self.fragment + return @normalized_fragment unless @normalized_fragment == NONE + @normalized_fragment = begin + component = Addressable::URI.normalize_component( + self.fragment, + Addressable::URI::NormalizeCharacterClasses::FRAGMENT + ) + component == "" ? nil : component + end + # All normalized values should be UTF-8 + force_utf8_encoding_if_needed(@normalized_fragment) + @normalized_fragment + end + + ## + # Sets the fragment component for this URI. + # + # @param [String, #to_str] new_fragment The new fragment component. + def fragment=(new_fragment) + if new_fragment && !new_fragment.respond_to?(:to_str) + raise TypeError, "Can't convert #{new_fragment.class} into String." + end + @fragment = new_fragment ? new_fragment.to_str : nil + + # Reset dependent values + @normalized_fragment = NONE + remove_composite_values + + # Ensure we haven't created an invalid URI + validate() + end + + ## + # Determines if the scheme indicates an IP-based protocol. + # + # @return [TrueClass, FalseClass] + # true if the scheme indicates an IP-based protocol. + # false otherwise. + def ip_based? + if self.scheme + return URI.ip_based_schemes.include?( + self.scheme.strip.downcase) + end + return false + end + + ## + # Determines if the URI is relative. + # + # @return [TrueClass, FalseClass] + # true if the URI is relative. false + # otherwise. + def relative? + return self.scheme.nil? + end + + ## + # Determines if the URI is absolute. + # + # @return [TrueClass, FalseClass] + # true if the URI is absolute. false + # otherwise. + def absolute? + return !relative? + end + + ## + # Joins two URIs together. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + def join(uri) + if !uri.respond_to?(:to_str) + raise TypeError, "Can't convert #{uri.class} into String." + end + if !uri.kind_of?(URI) + # Otherwise, convert to a String, then parse. + uri = URI.parse(uri.to_str) + end + if uri.to_s.empty? + return self.dup + end + + joined_scheme = nil + joined_user = nil + joined_password = nil + joined_host = nil + joined_port = nil + joined_path = nil + joined_query = nil + joined_fragment = nil + + # Section 5.2.2 of RFC 3986 + if uri.scheme != nil + joined_scheme = uri.scheme + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.authority != nil + joined_user = uri.user + joined_password = uri.password + joined_host = uri.host + joined_port = uri.port + joined_path = URI.normalize_path(uri.path) + joined_query = uri.query + else + if uri.path == nil || uri.path.empty? + joined_path = self.path + if uri.query != nil + joined_query = uri.query + else + joined_query = self.query + end + else + if uri.path[0..0] == SLASH + joined_path = URI.normalize_path(uri.path) + else + base_path = self.path.dup + base_path = EMPTY_STR if base_path == nil + base_path = URI.normalize_path(base_path) + + # Section 5.2.3 of RFC 3986 + # + # Removes the right-most path segment from the base path. + if base_path.include?(SLASH) + base_path.sub!(/\/[^\/]+$/, SLASH) + else + base_path = EMPTY_STR + end + + # If the base path is empty and an authority segment has been + # defined, use a base path of SLASH + if base_path.empty? && self.authority != nil + base_path = SLASH + end + + joined_path = URI.normalize_path(base_path + uri.path) + end + joined_query = uri.query + end + joined_user = self.user + joined_password = self.password + joined_host = self.host + joined_port = self.port + end + joined_scheme = self.scheme + end + joined_fragment = uri.fragment + + return self.class.new( + :scheme => joined_scheme, + :user => joined_user, + :password => joined_password, + :host => joined_host, + :port => joined_port, + :path => joined_path, + :query => joined_query, + :fragment => joined_fragment + ) + end + alias_method :+, :join + + ## + # Destructive form of join. + # + # @param [String, Addressable::URI, #to_str] The URI to join with. + # + # @return [Addressable::URI] The joined URI. + # + # @see Addressable::URI#join + def join!(uri) + replace_self(self.join(uri)) + end + + ## + # Merges a URI with a Hash of components. + # This method has different behavior from join. Any + # components present in the hash parameter will override the + # original components. The path component is not treated specially. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Hash#merge + def merge(hash) + unless hash.respond_to?(:to_hash) + raise TypeError, "Can't convert #{hash.class} into Hash." + end + hash = hash.to_hash + + if hash.has_key?(:authority) + if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? + raise ArgumentError, + "Cannot specify both an authority and any of the components " + + "within the authority." + end + end + if hash.has_key?(:userinfo) + if (hash.keys & [:user, :password]).any? + raise ArgumentError, + "Cannot specify both a userinfo and either the user or password." + end + end + + uri = self.class.new + uri.defer_validation do + # Bunch of crazy logic required because of the composite components + # like userinfo and authority. + uri.scheme = + hash.has_key?(:scheme) ? hash[:scheme] : self.scheme + if hash.has_key?(:authority) + uri.authority = + hash.has_key?(:authority) ? hash[:authority] : self.authority + end + if hash.has_key?(:userinfo) + uri.userinfo = + hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo + end + if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) + uri.user = + hash.has_key?(:user) ? hash[:user] : self.user + uri.password = + hash.has_key?(:password) ? hash[:password] : self.password + end + if !hash.has_key?(:authority) + uri.host = + hash.has_key?(:host) ? hash[:host] : self.host + uri.port = + hash.has_key?(:port) ? hash[:port] : self.port + end + uri.path = + hash.has_key?(:path) ? hash[:path] : self.path + uri.query = + hash.has_key?(:query) ? hash[:query] : self.query + uri.fragment = + hash.has_key?(:fragment) ? hash[:fragment] : self.fragment + end + + return uri + end + + ## + # Destructive form of merge. + # + # @param [Hash, Addressable::URI, #to_hash] The components to merge with. + # + # @return [Addressable::URI] The merged URI. + # + # @see Addressable::URI#merge + def merge!(uri) + replace_self(self.merge(uri)) + end + + ## + # Returns the shortest normalized relative form of this URI that uses the + # supplied URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_to. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route from. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the original URI. + def route_from(uri) + uri = URI.parse(uri).normalize + normalized_self = self.normalize + if normalized_self.relative? + raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" + end + if uri.relative? + raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" + end + if normalized_self == uri + return Addressable::URI.parse("##{normalized_self.fragment}") + end + components = normalized_self.to_hash + if normalized_self.scheme == uri.scheme + components[:scheme] = nil + if normalized_self.authority == uri.authority + components[:user] = nil + components[:password] = nil + components[:host] = nil + components[:port] = nil + if normalized_self.path == uri.path + components[:path] = nil + if normalized_self.query == uri.query + components[:query] = nil + end + else + if uri.path != SLASH and components[:path] + self_splitted_path = split_path(components[:path]) + uri_splitted_path = split_path(uri.path) + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir + self_dir = self_splitted_path.shift + uri_dir = uri_splitted_path.shift + end + components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH) + end + end + end + end + # Avoid network-path references. + if components[:host] != nil + components[:scheme] = normalized_self.scheme + end + return Addressable::URI.new( + :scheme => components[:scheme], + :user => components[:user], + :password => components[:password], + :host => components[:host], + :port => components[:port], + :path => components[:path], + :query => components[:query], + :fragment => components[:fragment] + ) + end + + ## + # Returns the shortest normalized relative form of the supplied URI that + # uses this URI as a base for resolution. Returns an absolute URI if + # necessary. This is effectively the opposite of route_from. + # + # @param [String, Addressable::URI, #to_str] uri The URI to route to. + # + # @return [Addressable::URI] + # The normalized relative URI that is equivalent to the supplied URI. + def route_to(uri) + return URI.parse(uri).route_from(self) + end + + ## + # Returns a normalized URI object. + # + # NOTE: This method does not attempt to fully conform to specifications. + # It exists largely to correct other people's failures to read the + # specifications, and also to deal with caching issues since several + # different URIs may represent the same resource and should not be + # cached multiple times. + # + # @return [Addressable::URI] The normalized URI. + def normalize + # This is a special exception for the frequently misused feed + # URI scheme. + if normalized_scheme == "feed" + if self.to_s =~ /^feed:\/*http:\/*/ + return URI.parse( + self.to_s[/^feed:\/*(http:\/*.*)/, 1] + ).normalize + end + end + + return self.class.new( + :scheme => normalized_scheme, + :authority => normalized_authority, + :path => normalized_path, + :query => normalized_query, + :fragment => normalized_fragment + ) + end + + ## + # Destructively normalizes this URI object. + # + # @return [Addressable::URI] The normalized URI. + # + # @see Addressable::URI#normalize + def normalize! + replace_self(self.normalize) + end + + ## + # Creates a URI suitable for display to users. If semantic attacks are + # likely, the application should try to detect these and warn the user. + # See RFC 3986, + # section 7.6 for more information. + # + # @return [Addressable::URI] A URI suitable for display purposes. + def display_uri + display_uri = self.normalize + display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) + return display_uri + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison, and allows comparison + # against Strings. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ===(uri) + if uri.respond_to?(:normalize) + uri_string = uri.normalize.to_s + else + begin + uri_string = ::Addressable::URI.parse(uri).normalize.to_s + rescue InvalidURIError, TypeError + return false + end + end + return self.normalize.to_s == uri_string + end + + ## + # Returns true if the URI objects are equal. This method + # normalizes both URIs before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def ==(uri) + return false unless uri.kind_of?(URI) + return self.normalize.to_s == uri.normalize.to_s + end + + ## + # Returns true if the URI objects are equal. This method + # does NOT normalize either URI before doing the comparison. + # + # @param [Object] uri The URI to compare. + # + # @return [TrueClass, FalseClass] + # true if the URIs are equivalent, false + # otherwise. + def eql?(uri) + return false unless uri.kind_of?(URI) + return self.to_s == uri.to_s + end + + ## + # A hash value that will make a URI equivalent to its normalized + # form. + # + # @return [Integer] A hash of the URI. + def hash + @hash ||= self.to_s.hash * -1 + end + + ## + # Clones the URI object. + # + # @return [Addressable::URI] The cloned URI. + def dup + duplicated_uri = self.class.new( + :scheme => self.scheme ? self.scheme.dup : nil, + :user => self.user ? self.user.dup : nil, + :password => self.password ? self.password.dup : nil, + :host => self.host ? self.host.dup : nil, + :port => self.port, + :path => self.path ? self.path.dup : nil, + :query => self.query ? self.query.dup : nil, + :fragment => self.fragment ? self.fragment.dup : nil + ) + return duplicated_uri + end + + ## + # Omits components from a URI. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @example + # uri = Addressable::URI.parse("http://example.com/path?query") + # #=> # + # uri.omit(:scheme, :authority) + # #=> # + def omit(*components) + invalid_components = components - [ + :scheme, :user, :password, :userinfo, :host, :port, :authority, + :path, :query, :fragment + ] + unless invalid_components.empty? + raise ArgumentError, + "Invalid component names: #{invalid_components.inspect}." + end + duplicated_uri = self.dup + duplicated_uri.defer_validation do + components.each do |component| + duplicated_uri.send((component.to_s + "=").to_sym, nil) + end + duplicated_uri.user = duplicated_uri.normalized_user + end + duplicated_uri + end + + ## + # Destructive form of omit. + # + # @param [Symbol] *components The components to be omitted. + # + # @return [Addressable::URI] The URI with components omitted. + # + # @see Addressable::URI#omit + def omit!(*components) + replace_self(self.omit(*components)) + end + + ## + # Determines if the URI is an empty string. + # + # @return [TrueClass, FalseClass] + # Returns true if empty, false otherwise. + def empty? + return self.to_s.empty? + end + + ## + # Converts the URI to a String. + # + # @return [String] The URI's String representation. + def to_s + if self.scheme == nil && self.path != nil && !self.path.empty? && + self.path =~ NORMPATH + raise InvalidURIError, + "Cannot assemble URI string with ambiguous path: '#{self.path}'" + end + @uri_string ||= begin + uri_string = String.new + uri_string << "#{self.scheme}:" if self.scheme != nil + uri_string << "//#{self.authority}" if self.authority != nil + uri_string << self.path.to_s + uri_string << "?#{self.query}" if self.query != nil + uri_string << "##{self.fragment}" if self.fragment != nil + uri_string.force_encoding(Encoding::UTF_8) + uri_string + end + end + + ## + # URI's are glorified Strings. Allow implicit conversion. + alias_method :to_str, :to_s + + ## + # Returns a Hash of the URI components. + # + # @return [Hash] The URI as a Hash of components. + def to_hash + return { + :scheme => self.scheme, + :user => self.user, + :password => self.password, + :host => self.host, + :port => self.port, + :path => self.path, + :query => self.query, + :fragment => self.fragment + } + end + + ## + # Returns a String representation of the URI object's state. + # + # @return [String] The URI object's state, as a String. + def inspect + sprintf("#<%s:%#0x URI:%s>", self.class.to_s, self.object_id, self.to_s) + end + + ## + # This method allows you to make several changes to a URI simultaneously, + # which separately would cause validation errors, but in conjunction, + # are valid. The URI will be revalidated as soon as the entire block has + # been executed. + # + # @param [Proc] block + # A set of operations to perform on a given URI. + def defer_validation + raise LocalJumpError, "No block given." unless block_given? + @validation_deferred = true + yield + @validation_deferred = false + validate + ensure + @validation_deferred = false + end + + def encode_with(coder) + instance_variables.each do |ivar| + value = instance_variable_get(ivar) + if value != NONE + key = ivar.to_s.slice(1..-1) + coder[key] = value + end + end + nil + end + + def init_with(coder) + reset_ivs + coder.map.each do |key, value| + instance_variable_set("@#{key}", value) + end + nil + end + + protected + SELF_REF = '.' + PARENT = '..' + + RULE_2A = /\/\.\/|\/\.$/ + RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/ + RULE_2D = /^\.\.?\/?/ + RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/ + + ## + # Resolves paths to their simplest form. + # + # @param [String] path The path to normalize. + # + # @return [String] The normalized path. + def self.normalize_path(path) + # Section 5.2.4 of RFC 3986 + + return if path.nil? + normalized_path = path.dup + loop do + mod ||= normalized_path.gsub!(RULE_2A, SLASH) + + pair = normalized_path.match(RULE_2B_2C) + if pair + parent = pair[1] + current = pair[2] + else + parent = nil + current = nil + end + + regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|" + regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)" + + if pair && ((parent != SELF_REF && parent != PARENT) || + (current != SELF_REF && current != PARENT)) + mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH) + end + + mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR) + # Non-standard, removes prefixed dotted segments from path. + mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH) + break if mod.nil? + end + + normalized_path + end + + ## + # Ensures that the URI is valid. + def validate + return if !!@validation_deferred + if self.scheme != nil && self.ip_based? && + (self.host == nil || self.host.empty?) && + (self.path == nil || self.path.empty?) + raise InvalidURIError, + "Absolute URI missing hierarchical segment: '#{self.to_s}'" + end + if self.host == nil + if self.port != nil || + self.user != nil || + self.password != nil + raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" + end + end + if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH && + self.authority != nil + raise InvalidURIError, + "Cannot have a relative path with an authority set: '#{self.to_s}'" + end + if self.path != nil && !self.path.empty? && + self.path[0..1] == SLASH + SLASH && self.authority == nil + raise InvalidURIError, + "Cannot have a path with two leading slashes " + + "without an authority set: '#{self.to_s}'" + end + unreserved = CharacterClasses::UNRESERVED + sub_delims = CharacterClasses::SUB_DELIMS + if !self.host.nil? && (self.host =~ /[<>{}\/\\\?\#\@"[[:space:]]]/ || + (self.host[/^\[(.*)\]$/, 1] != nil && self.host[/^\[(.*)\]$/, 1] !~ + Regexp.new("^[#{unreserved}#{sub_delims}:]*$"))) + raise InvalidURIError, "Invalid character in host: '#{self.host.to_s}'" + end + return nil + end + + ## + # Replaces the internal state of self with the specified URI's state. + # Used in destructive operations to avoid massive code repetition. + # + # @param [Addressable::URI] uri The URI to replace self with. + # + # @return [Addressable::URI] self. + def replace_self(uri) + # Reset dependent values + reset_ivs + + @scheme = uri.scheme + @user = uri.user + @password = uri.password + @host = uri.host + @port = uri.port + @path = uri.path + @query = uri.query + @fragment = uri.fragment + return self + end + + ## + # Splits path string with "/" (slash). + # It is considered that there is empty string after last slash when + # path ends with slash. + # + # @param [String] path The path to split. + # + # @return [Array] An array of parts of path. + def split_path(path) + splitted = path.split(SLASH) + splitted << EMPTY_STR if path.end_with? SLASH + splitted + end + + ## + # Resets composite values for the entire URI + # + # @api private + def remove_composite_values + @uri_string = nil + @hash = nil + end + + ## + # Converts the string to be UTF-8 if it is not already UTF-8 + # + # @api private + def force_utf8_encoding_if_needed(str) + if str && str.encoding != Encoding::UTF_8 + str.force_encoding(Encoding::UTF_8) + end + end + + private + + ## + # Resets instance variables + # + # @api private + def reset_ivs + @scheme = nil + @user = nil + @normalized_scheme = NONE + @normalized_user = NONE + @uri_string = nil + @hash = nil + @userinfo = nil + @normalized_userinfo = NONE + @authority = nil + @password = nil + @normalized_authority = nil + @port = nil + @normalized_password = NONE + @host = nil + @normalized_host = nil + @normalized_port = NONE + @path = EMPTY_STR + @normalized_path = nil + @normalized_query = NONE + @fragment = nil + @normalized_fragment = NONE + @query = nil + end + + NONE = Module.new.freeze + + private_constant :NONE + end +end diff --git a/bin/gems/addressable-2.9.0/lib/addressable/version.rb b/bin/gems/addressable-2.9.0/lib/addressable/version.rb new file mode 100644 index 00000000..b1254e31 --- /dev/null +++ b/bin/gems/addressable-2.9.0/lib/addressable/version.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +#-- +# Copyright (C) Bob Aman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#++ + + +# Used to prevent the class/module from being loaded more than once +if !defined?(Addressable::VERSION) + module Addressable + module VERSION + MAJOR = 2 + MINOR = 9 + TINY = 0 + + STRING = [MAJOR, MINOR, TINY].join('.') + end + end +end diff --git a/bin/gems/afm-0.2.2/CHANGELOG.md b/bin/gems/afm-0.2.2/CHANGELOG.md new file mode 100644 index 00000000..81e452c5 --- /dev/null +++ b/bin/gems/afm-0.2.2/CHANGELOG.md @@ -0,0 +1,9 @@ +## 0.2.2 + +* The gem was missing + +## 0.2.1 + +* Fixed rdoc tasks, replaced Test::Unit with Minitest (Thanks to @yob, @strzibny for changes) +* Removed jeweler dependency + diff --git a/bin/gems/afm-0.2.2/LICENSE b/bin/gems/afm-0.2.2/LICENSE new file mode 100644 index 00000000..12ea103b --- /dev/null +++ b/bin/gems/afm-0.2.2/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 Jan Krutisch + +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/bin/gems/afm-0.2.2/README.rdoc b/bin/gems/afm-0.2.2/README.rdoc new file mode 100644 index 00000000..c54d7718 --- /dev/null +++ b/bin/gems/afm-0.2.2/README.rdoc @@ -0,0 +1,20 @@ += afm + +A very simple library to read Adobe Font Metrics files (afm). + +Currently simply parses the file and saves it in a few attributes. + + +== Note on Patches/Pull Requests + +* Fork the project. +* Make your feature addition or bug fix. +* Add tests for it. This is important so I don't break it in a + future version unintentionally. +* Commit, do not mess with rakefile, version, or history. + (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) +* Send me a pull request. Bonus points for topic branches. + +== Copyright + +Copyright (c) 2010 Jan Krutisch. See LICENSE for details. diff --git a/bin/gems/afm-0.2.2/Rakefile b/bin/gems/afm-0.2.2/Rakefile new file mode 100644 index 00000000..197264dd --- /dev/null +++ b/bin/gems/afm-0.2.2/Rakefile @@ -0,0 +1,23 @@ +require 'rubygems' +require 'bundler/setup' +require 'rake' + +require 'rake/testtask' +Rake::TestTask.new(:test) do |test| + test.libs << 'lib' << 'test' + test.pattern = 'test/**/test_*.rb' + test.verbose = true +end + +task :default => :test + +require 'rdoc/task' + +RDoc::Task.new do |rdoc| + version = File.exist?('VERSION') ? File.read('VERSION') : "" + + rdoc.rdoc_dir = 'rdoc' + rdoc.title = "afm #{version}" + rdoc.rdoc_files.include('README*') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/bin/gems/afm-0.2.2/VERSION b/bin/gems/afm-0.2.2/VERSION new file mode 100644 index 00000000..f4778493 --- /dev/null +++ b/bin/gems/afm-0.2.2/VERSION @@ -0,0 +1 @@ +0.2.2 \ No newline at end of file diff --git a/bin/gems/afm-0.2.2/lib/afm.rb b/bin/gems/afm-0.2.2/lib/afm.rb new file mode 100644 index 00000000..52ed6bc3 --- /dev/null +++ b/bin/gems/afm-0.2.2/lib/afm.rb @@ -0,0 +1,105 @@ +module AFM + + ISO_LATIN1_ENCODING = %w( + .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef + .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef + .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef + .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef space + exclam quotedbl numbersign dollar percent ampersand quoteright + parenleft parenright asterisk plus comma minus period slash zero one + two three four five six seven eight nine colon semicolon less equal + greater question at A B C D E F G H I J K L M N O P Q R S + T U V W X Y Z bracketleft backslash bracketright asciicircum + underscore quoteleft a b c d e f g h i j k l m n o p q r s + t u v w x y z braceleft bar braceright asciitilde .notdef .notdef + .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef + .notdef .notdef .notdef .notdef .notdef .notdef .notdef dotlessi grave + acute circumflex tilde macron breve dotaccent dieresis .notdef ring + cedilla .notdef hungarumlaut ogonek caron space exclamdown cent + sterling currency yen brokenbar section dieresis copyright ordfeminine + guillemotleft logicalnot hyphen registered macron degree plusminus + twosuperior threesuperior acute mu paragraph periodcentered cedilla + onesuperior ordmasculine guillemotright onequarter onehalf threequarters + questiondown Agrave Aacute Acircumflex Atilde Adieresis Aring AE + Ccedilla Egrave Eacute Ecircumflex Edieresis Igrave Iacute Icircumflex + Idieresis Eth Ntilde Ograve Oacute Ocircumflex Otilde Odieresis + multiply Oslash Ugrave Uacute Ucircumflex Udieresis Yacute Thorn + germandbls agrave aacute acircumflex atilde adieresis aring ae + ccedilla egrave eacute ecircumflex edieresis igrave iacute icircumflex + idieresis eth ntilde ograve oacute ocircumflex otilde odieresis divide + oslash ugrave uacute ucircumflex udieresis yacute thorn ydieresis + ) + + + class Font + attr_reader :metadata, :char_metrics, :char_metrics_by_code, :kern_pairs + + # Loading a Font Metrics file by absolute path (no automatic font path resolution) + def initialize(filename) + @metadata = {} + @char_metrics = {} + @char_metrics_by_code = {} + @kern_pairs = [] + File.open(filename) do |file| + mode = :meta + file.each_line do |line| + case(line) + when /^StartFontMetrics/ ; mode = :meta + when /^StartCharMetrics/ ; mode = :char_metrics + when /^EndCharMetrics/ ; mode = :meta + when /^StartKernData/ ; mode = :kern_data + when /^StartKernPairs/ ; mode = :kern_pairs + when /^EndKernPairs/ ; mode = :kern_data + when /^EndKernData/ ; mode = :meta + else + case(mode) + when :meta + if match = line.match(/^([\w]+) (.*)$/) + @metadata[match[1]] = match[2] + end + when :char_metrics + metrics = {} + metrics[:charcode] = match[1].to_i if match = line.match(/C (-?\d+) *?;/) + metrics[:wx] = match[1].to_i if match = line.match(/WX (-?\d+) *?;/) + metrics[:name] = match[1] if match = line.match(/N ([.\w]+) *?;/) + if match = line.match(/B (-?\d+) (-?\d+) (-?\d+) (-?\d+) *?;/) + metrics[:boundingbox] = [match[1].to_i, match[2].to_i, match[3].to_i, match[4].to_i] + end + @char_metrics[metrics[:name]] = metrics if metrics[:name] + @char_metrics_by_code[metrics[:charcode]] = metrics if metrics[:charcode] && metrics[:charcode] > 0 + when :kern_pairs + if match = line.match(/^KPX ([.\w]+) ([.\w]+) (-?\d+)$/) + @kern_pairs << [match[1], match[2], match[3].to_i] + end + end + end + end + end + end + + # + # alias for new() + def self.from_file(file) + self.new(file) + end + + # + # Get metadata by key + def [](key) + @metadata[key] + end + # + # Get metrics for character. Takes an integer (charcode) or + # a one-char string. currently works only for Latin1 strings, + # since we only have a chartable for the Latin1 charset so far. + # (shamelessly stolen from AFM.pm by Gisle Aas) + def metrics_for(char) + glyph = if (char.kind_of?(Integer)) + ISO_LATIN1_ENCODING[char] + else + ISO_LATIN1_ENCODING[char.unpack("C*").first] + end + @char_metrics[glyph] + end + end +end diff --git a/bin/gems/afm-0.2.2/test/fixtures/Vera.afm b/bin/gems/afm-0.2.2/test/fixtures/Vera.afm new file mode 100644 index 00000000..5c236d99 --- /dev/null +++ b/bin/gems/afm-0.2.2/test/fixtures/Vera.afm @@ -0,0 +1,1783 @@ +StartFontMetrics 2.0 +Comment Converted at Wed Sep 29 22:37:48 2010 by ttf2afm from font file `/Users/jankrutisch/Dropbox/fonts/Vera.ttf' +FontName BitstreamVeraSans-Roman +FullName Bitstream Vera Sans +FamilyName Bitstream Vera Sans +Weight Normal +ItalicAngle 0 +IsFixedPitch false +FontBBox -183 -235 1287 928 +UnderlinePosition -104 +UnderlineThickness 69 +Version Release 1.10 +Notice Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. +EncodingScheme FontSpecific +CapHeight 729 +XHeight 546 +Ascender 928 +Descender -235 +StartCharMetrics 268 +C -1 ; WX 600 ; N .notdef ; B 49 -176 549 705 ; +C -1 ; WX 0 ; N .null ; B 150 0 250 729 ; +C -1 ; WX 317 ; N CR ; B 150 0 250 729 ; +C -1 ; WX 317 ; N space ; B 150 0 250 729 ; +C 33 ; WX 400 ; N exclam ; B 150 0 250 729 ; +C -1 ; WX 459 ; N quotedbl ; B 96 458 363 729 ; +C -1 ; WX 837 ; N numbersign ; B 77 0 761 717 ; +C -1 ; WX 636 ; N dollar ; B 83 -146 553 759 ; +C -1 ; WX 950 ; N percent ; B 55 -14 895 742 ; +C -1 ; WX 779 ; N ampersand ; B 62 -14 749 742 ; +C -1 ; WX 274 ; N quotesingle ; B 96 458 179 729 ; +C 40 ; WX 390 ; N parenleft ; B 85 -131 310 758 ; +C -1 ; WX 390 ; N parenright ; B 80 -131 304 758 ; +C -1 ; WX 500 ; N asterisk ; B 29 286 470 742 ; +C -1 ; WX 837 ; N plus ; B 105 0 731 626 ; +C -1 ; WX 317 ; N comma ; B 77 -116 220 124 ; +C -1 ; WX 360 ; N hyphen ; B 48 233 312 313 ; +C -1 ; WX 317 ; N period ; B 106 0 209 124 ; +C -1 ; WX 336 ; N slash ; B 0 -92 336 729 ; +C -1 ; WX 636 ; N zero ; B 65 -14 569 742 ; +C -1 ; WX 636 ; N one ; B 109 0 543 729 ; +C -1 ; WX 636 ; N two ; B 73 0 536 742 ; +C -1 ; WX 636 ; N three ; B 76 -14 556 742 ; +C -1 ; WX 636 ; N four ; B 48 0 580 729 ; +C -1 ; WX 636 ; N five ; B 77 -14 548 729 ; +C -1 ; WX 636 ; N six ; B 69 -14 573 742 ; +C -1 ; WX 636 ; N seven ; B 82 0 550 729 ; +C -1 ; WX 636 ; N eight ; B 67 -14 567 742 ; +C -1 ; WX 636 ; N nine ; B 62 -14 565 742 ; +C -1 ; WX 336 ; N colon ; B 117 0 220 517 ; +C -1 ; WX 336 ; N semicolon ; B 77 -116 220 517 ; +C -1 ; WX 837 ; N less ; B 105 45 731 581 ; +C -1 ; WX 837 ; N equal ; B 105 171 731 454 ; +C -1 ; WX 837 ; N greater ; B 105 45 731 581 ; +C -1 ; WX 530 ; N question ; B 71 0 460 742 ; +C -1 ; WX 1000 ; N at ; B 65 -173 930 704 ; +C -1 ; WX 684 ; N A ; B 7 0 675 729 ; +C -1 ; WX 686 ; N B ; B 98 0 615 729 ; +C -1 ; WX 698 ; N C ; B 56 -14 644 742 ; +C -1 ; WX 770 ; N D ; B 98 0 710 729 ; +C -1 ; WX 631 ; N E ; B 98 0 567 729 ; +C -1 ; WX 575 ; N F ; B 98 0 517 729 ; +C -1 ; WX 774 ; N G ; B 56 -14 692 742 ; +C -1 ; WX 751 ; N H ; B 98 0 653 729 ; +C -1 ; WX 294 ; N I ; B 98 0 196 729 ; +C -1 ; WX 294 ; N J ; B -51 -200 196 729 ; +C -1 ; WX 655 ; N K ; B 98 0 676 729 ; +C -1 ; WX 557 ; N L ; B 98 0 551 729 ; +C -1 ; WX 862 ; N M ; B 98 0 765 729 ; +C -1 ; WX 748 ; N N ; B 98 0 649 729 ; +C -1 ; WX 787 ; N O ; B 56 -14 730 742 ; +C -1 ; WX 603 ; N P ; B 98 0 568 729 ; +C -1 ; WX 787 ; N Q ; B 56 -128 730 742 ; +C -1 ; WX 694 ; N R ; B 98 0 666 729 ; +C -1 ; WX 634 ; N S ; B 65 -14 579 742 ; +C -1 ; WX 610 ; N T ; B -2 0 613 729 ; +C -1 ; WX 731 ; N U ; B 86 -14 645 729 ; +C -1 ; WX 684 ; N V ; B 7 0 675 729 ; +C -1 ; WX 988 ; N W ; B 33 0 956 729 ; +C -1 ; WX 685 ; N X ; B 29 0 653 729 ; +C -1 ; WX 610 ; N Y ; B -1 0 612 729 ; +C -1 ; WX 685 ; N Z ; B 44 0 640 729 ; +C -1 ; WX 390 ; N bracketleft ; B 85 -131 292 759 ; +C -1 ; WX 336 ; N backslash ; B 0 -92 336 729 ; +C -1 ; WX 390 ; N bracketright ; B 97 -131 304 759 ; +C -1 ; WX 837 ; N asciicircum ; B 105 457 731 729 ; +C -1 ; WX 500 ; N underscore ; B -9 -235 509 -166 ; +C -1 ; WX 500 ; N grave ; B 83 617 316 799 ; +C -1 ; WX 612 ; N a ; B 60 -14 521 560 ; +C -1 ; WX 634 ; N b ; B 90 -14 580 759 ; +C -1 ; WX 549 ; N c ; B 55 -14 487 560 ; +C -1 ; WX 634 ; N d ; B 55 -14 543 759 ; +C -1 ; WX 615 ; N e ; B 55 -14 562 560 ; +C -1 ; WX 352 ; N f ; B 22 0 371 759 ; +C -1 ; WX 634 ; N g ; B 55 -208 543 560 ; +C -1 ; WX 633 ; N h ; B 90 0 548 759 ; +C -1 ; WX 277 ; N i ; B 94 0 184 759 ; +C -1 ; WX 277 ; N j ; B -18 -208 184 759 ; +C -1 ; WX 579 ; N k ; B 90 0 576 759 ; +C -1 ; WX 277 ; N l ; B 94 0 184 759 ; +C -1 ; WX 974 ; N m ; B 90 0 889 560 ; +C -1 ; WX 633 ; N n ; B 90 0 548 560 ; +C -1 ; WX 611 ; N o ; B 55 -14 557 560 ; +C -1 ; WX 634 ; N p ; B 90 -208 580 560 ; +C -1 ; WX 634 ; N q ; B 55 -208 543 560 ; +C -1 ; WX 411 ; N r ; B 90 0 411 560 ; +C -1 ; WX 520 ; N s ; B 54 -14 472 560 ; +C -1 ; WX 392 ; N t ; B 26 0 368 702 ; +C -1 ; WX 633 ; N u ; B 84 -14 542 546 ; +C -1 ; WX 591 ; N v ; B 29 0 562 546 ; +C -1 ; WX 817 ; N w ; B 41 0 775 546 ; +C -1 ; WX 591 ; N x ; B 28 0 559 546 ; +C -1 ; WX 591 ; N y ; B 29 -208 562 546 ; +C -1 ; WX 524 ; N z ; B 42 0 481 546 ; +C -1 ; WX 636 ; N braceleft ; B 125 -163 511 759 ; +C -1 ; WX 336 ; N bar ; B 126 -235 209 764 ; +C -1 ; WX 636 ; N braceright ; B 125 -163 511 759 ; +C -1 ; WX 837 ; N asciitilde ; B 105 228 731 398 ; +C -1 ; WX 684 ; N Adieresis ; B 7 0 675 913 ; +C -1 ; WX 684 ; N Aring ; B 7 0 675 928 ; +C -1 ; WX 698 ; N Ccedilla ; B 56 -192 644 742 ; +C -1 ; WX 631 ; N Eacute ; B 98 0 567 927 ; +C -1 ; WX 748 ; N Ntilde ; B 98 0 649 920 ; +C -1 ; WX 787 ; N Odieresis ; B 56 -14 730 913 ; +C -1 ; WX 731 ; N Udieresis ; B 86 -14 645 913 ; +C -1 ; WX 612 ; N aacute ; B 60 -14 521 799 ; +C -1 ; WX 612 ; N agrave ; B 60 -14 521 799 ; +C -1 ; WX 612 ; N acircumflex ; B 60 -14 521 799 ; +C -1 ; WX 612 ; N adieresis ; B 60 -14 521 757 ; +C -1 ; WX 612 ; N atilde ; B 60 -14 521 776 ; +C -1 ; WX 612 ; N aring ; B 60 -14 521 877 ; +C -1 ; WX 549 ; N ccedilla ; B 55 -192 487 560 ; +C -1 ; WX 615 ; N eacute ; B 55 -14 562 799 ; +C -1 ; WX 615 ; N egrave ; B 55 -14 562 799 ; +C -1 ; WX 615 ; N ecircumflex ; B 55 -14 562 799 ; +C -1 ; WX 615 ; N edieresis ; B 55 -14 562 757 ; +C -1 ; WX 277 ; N iacute ; B 70 0 304 799 ; +C -1 ; WX 277 ; N igrave ; B -27 0 206 799 ; +C -1 ; WX 277 ; N icircumflex ; B -16 0 294 799 ; +C -1 ; WX 277 ; N idieresis ; B -5 0 284 757 ; +C -1 ; WX 633 ; N ntilde ; B 90 0 548 776 ; +C -1 ; WX 611 ; N oacute ; B 55 -14 557 799 ; +C -1 ; WX 611 ; N ograve ; B 55 -14 557 799 ; +C -1 ; WX 611 ; N ocircumflex ; B 55 -14 557 799 ; +C -1 ; WX 611 ; N odieresis ; B 55 -14 557 757 ; +C -1 ; WX 611 ; N otilde ; B 55 -14 557 776 ; +C -1 ; WX 633 ; N uacute ; B 84 -14 542 799 ; +C -1 ; WX 633 ; N ugrave ; B 84 -14 542 799 ; +C -1 ; WX 633 ; N ucircumflex ; B 84 -14 542 799 ; +C -1 ; WX 633 ; N udieresis ; B 84 -14 542 757 ; +C -1 ; WX 500 ; N dagger ; B 27 -96 472 729 ; +C -1 ; WX 500 ; N degree ; B 95 432 404 742 ; +C -1 ; WX 636 ; N cent ; B 83 -152 517 699 ; +C -1 ; WX 636 ; N sterling ; B 62 0 547 742 ; +C -1 ; WX 500 ; N section ; B 44 -95 454 742 ; +C -1 ; WX 589 ; N bullet ; B 149 227 439 516 ; +C -1 ; WX 636 ; N paragraph ; B 77 -96 527 729 ; +C -1 ; WX 629 ; N germandbls ; B 90 -14 583 759 ; +C -1 ; WX 1000 ; N registered ; B 138 0 861 725 ; +C -1 ; WX 1000 ; N copyright ; B 138 0 861 725 ; +C -1 ; WX 1000 ; N trademark ; B 144 446 784 729 ; +C -1 ; WX 500 ; N acute ; B 181 616 415 799 ; +C -1 ; WX 500 ; N dieresis ; B 104 659 395 757 ; +C -1 ; WX 837 ; N notequal ; B 105 19 731 607 ; +C -1 ; WX 974 ; N AE ; B 3 0 910 729 ; +C -1 ; WX 787 ; N Oslash ; B 49 -34 736 761 ; +C -1 ; WX 833 ; N infinity ; B 107 107 726 491 ; +C -1 ; WX 837 ; N plusminus ; B 105 0 731 626 ; +C -1 ; WX 837 ; N lessequal ; B 105 0 731 582 ; +C -1 ; WX 837 ; N greaterequal ; B 105 0 731 582 ; +C -1 ; WX 636 ; N yen ; B 40 0 595 729 ; +C -1 ; WX 636 ; N mu ; B 84 -208 611 546 ; +C -1 ; WX 517 ; N partialdiff ; B 50 -12 469 646 ; +C -1 ; WX 673 ; N Sigma ; B 12 -191 653 719 ; +C -1 ; WX 756 ; N Pi ; B 76 -191 680 719 ; +C -1 ; WX 588 ; N pi ; B -15 -7 583 522 ; +C -1 ; WX 520 ; N integral ; B 22 -181 497 756 ; +C -1 ; WX 471 ; N ordfeminine ; B 56 229 403 742 ; +C -1 ; WX 471 ; N ordmasculine ; B 46 229 423 742 ; +C -1 ; WX 764 ; N Omega ; B 38 0 726 737 ; +C -1 ; WX 981 ; N ae ; B 60 -14 929 560 ; +C -1 ; WX 611 ; N oslash ; B 35 -45 576 591 ; +C -1 ; WX 530 ; N questiondown ; B 69 -14 458 729 ; +C -1 ; WX 400 ; N exclamdown ; B 150 0 250 729 ; +C -1 ; WX 837 ; N logicalnot ; B 105 140 731 420 ; +C -1 ; WX 637 ; N radical ; B 29 -20 637 811 ; +C -1 ; WX 636 ; N florin ; B 15 -208 625 759 ; +C -1 ; WX 837 ; N approxequal ; B 105 132 731 494 ; +C -1 ; WX 668 ; N Delta ; B -2 0 671 719 ; +C -1 ; WX 611 ; N guillemotleft ; B 77 68 518 517 ; +C -1 ; WX 611 ; N guillemotright ; B 94 68 535 517 ; +C -1 ; WX 1000 ; N ellipsis ; B 115 0 884 124 ; +C -1 ; WX 636 ; N nbspace ; B 7 0 675 927 ; +C -1 ; WX 684 ; N Agrave ; B 7 0 675 927 ; +C -1 ; WX 684 ; N Atilde ; B 7 0 675 920 ; +C -1 ; WX 787 ; N Otilde ; B 56 -14 730 920 ; +C -1 ; WX 1069 ; N OE ; B 56 0 1005 729 ; +C -1 ; WX 1022 ; N oe ; B 55 -14 970 560 ; +C -1 ; WX 500 ; N endash ; B 0 238 500 309 ; +C -1 ; WX 1000 ; N emdash ; B 0 238 1000 309 ; +C -1 ; WX 518 ; N quotedblleft ; B 84 488 428 729 ; +C -1 ; WX 518 ; N quotedblright ; B 84 488 428 729 ; +C -1 ; WX 317 ; N quoteleft ; B 84 488 228 729 ; +C -1 ; WX 317 ; N quoteright ; B 86 499 229 729 ; +C -1 ; WX 837 ; N divide ; B 105 73 731 554 ; +C -1 ; WX 494 ; N lozenge ; B 2 -232 491 807 ; +C -1 ; WX 591 ; N ydieresis ; B 29 -208 562 757 ; +C -1 ; WX 610 ; N Ydieresis ; B -1 0 612 913 ; +C -1 ; WX 166 ; N fraction ; B -183 -14 350 742 ; +C -1 ; WX 636 ; N currency ; B 45 40 591 586 ; +C -1 ; WX 399 ; N guilsinglleft ; B 77 68 306 517 ; +C -1 ; WX 399 ; N guilsinglright ; B 94 68 323 517 ; +C -1 ; WX 629 ; N fi ; B 22 0 536 759 ; +C -1 ; WX 629 ; N fl ; B 22 0 536 759 ; +C -1 ; WX 500 ; N daggerdbl ; B 27 -96 472 729 ; +C -1 ; WX 317 ; N periodcentered ; B 106 285 209 409 ; +C -1 ; WX 317 ; N quotesinglbase ; B 84 -116 228 124 ; +C -1 ; WX 518 ; N quotedblbase ; B 84 -116 428 124 ; +C -1 ; WX 1341 ; N perthousand ; B 55 -14 1287 742 ; +C -1 ; WX 684 ; N Acircumflex ; B 7 0 675 928 ; +C -1 ; WX 631 ; N Ecircumflex ; B 98 0 567 928 ; +C -1 ; WX 684 ; N Aacute ; B 7 0 675 927 ; +C -1 ; WX 631 ; N Edieresis ; B 98 0 567 913 ; +C -1 ; WX 631 ; N Egrave ; B 98 0 567 927 ; +C -1 ; WX 294 ; N Iacute ; B 79 0 265 927 ; +C -1 ; WX 294 ; N Icircumflex ; B 0 0 296 928 ; +C -1 ; WX 294 ; N Idieresis ; B 2 0 292 913 ; +C -1 ; WX 294 ; N Igrave ; B 28 0 215 927 ; +C -1 ; WX 787 ; N Oacute ; B 56 -14 730 927 ; +C -1 ; WX 787 ; N Ocircumflex ; B 56 -14 730 928 ; +C -1 ; WX 787 ; N Ograve ; B 56 -14 730 927 ; +C -1 ; WX 731 ; N Uacute ; B 86 -14 645 927 ; +C -1 ; WX 731 ; N Ucircumflex ; B 86 -14 645 928 ; +C -1 ; WX 731 ; N Ugrave ; B 86 -14 645 927 ; +C -1 ; WX 277 ; N dotlessi ; B 94 0 184 546 ; +C -1 ; WX 500 ; N circumflex ; B 94 616 405 799 ; +C -1 ; WX 500 ; N tilde ; B 88 639 411 776 ; +C -1 ; WX 500 ; N macron ; B 104 672 395 745 ; +C -1 ; WX 500 ; N breve ; B 97 645 402 785 ; +C -1 ; WX 500 ; N dotaccent ; B 200 658 299 757 ; +C -1 ; WX 500 ; N ring ; B 116 609 383 877 ; +C -1 ; WX 500 ; N cedilla ; B 142 -192 344 0 ; +C -1 ; WX 500 ; N hungarumlaut ; B 117 616 459 799 ; +C -1 ; WX 500 ; N ogonek ; B 162 -192 344 0 ; +C -1 ; WX 500 ; N caron ; B 94 616 405 799 ; +C -1 ; WX 562 ; N Lslash ; B -6 0 557 729 ; +C -1 ; WX 284 ; N lslash ; B 0 0 285 759 ; +C -1 ; WX 634 ; N Scaron ; B 65 -14 579 928 ; +C -1 ; WX 520 ; N scaron ; B 54 -14 472 799 ; +C -1 ; WX 685 ; N Zcaron ; B 44 0 640 928 ; +C -1 ; WX 524 ; N zcaron ; B 42 0 481 799 ; +C -1 ; WX 336 ; N brokenbar ; B 126 -170 209 699 ; +C -1 ; WX 774 ; N Eth ; B 4 0 715 729 ; +C -1 ; WX 611 ; N eth ; B 55 -14 557 759 ; +C -1 ; WX 610 ; N Yacute ; B -1 0 612 927 ; +C -1 ; WX 591 ; N yacute ; B 29 -208 562 799 ; +C -1 ; WX 604 ; N Thorn ; B 98 0 568 729 ; +C -1 ; WX 634 ; N thorn ; B 90 -208 580 759 ; +C -1 ; WX 837 ; N minus ; B 105 271 731 354 ; +C -1 ; WX 837 ; N multiply ; B 137 30 701 596 ; +C -1 ; WX 400 ; N onesuperior ; B 66 326 346 733 ; +C -1 ; WX 400 ; N twosuperior ; B 45 326 337 742 ; +C -1 ; WX 400 ; N threesuperior ; B 47 318 350 742 ; +C -1 ; WX 969 ; N onequarter ; B 66 -14 937 742 ; +C -1 ; WX 969 ; N onehalf ; B 66 -14 905 742 ; +C -1 ; WX 969 ; N threequarters ; B 47 -14 937 742 ; +C -1 ; WX 774 ; N Gbreve ; B 56 -14 692 928 ; +C -1 ; WX 634 ; N gbreve ; B 55 -208 543 785 ; +C -1 ; WX 294 ; N Idot ; B 98 0 197 914 ; +C -1 ; WX 634 ; N Scedilla ; B 65 -192 579 742 ; +C -1 ; WX 520 ; N scedilla ; B 54 -192 472 560 ; +C -1 ; WX 698 ; N Cacute ; B 56 -14 644 927 ; +C -1 ; WX 549 ; N cacute ; B 55 -14 487 799 ; +C -1 ; WX 698 ; N Ccaron ; B 56 -14 644 928 ; +C -1 ; WX 549 ; N ccaron ; B 55 -14 487 799 ; +C -1 ; WX 634 ; N dmacron ; B 55 -14 619 759 ; +C -1 ; WX 360 ; N sfthyphen ; B 48 233 312 313 ; +C -1 ; WX 317 ; N periodcentered ; B 106 285 209 409 ; +C -1 ; WX 636 ; N Euro ; B 0 -14 569 742 ; +C -1 ; WX 500 ; N c6459 ; B 104 631 395 730 ; +C -1 ; WX 500 ; N c6460 ; B 181 616 367 745 ; +C -1 ; WX 500 ; N c6461 ; B 88 631 411 738 ; +C -1 ; WX 500 ; N c6462 ; B 130 616 317 745 ; +C -1 ; WX 500 ; N c6463 ; B 101 616 398 746 ; +C -1 ; WX 500 ; N c6466 ; B 101 616 398 746 ; +C -1 ; WX 400 ; N c6467 ; B 30 326 369 733 ; +C -1 ; WX 500 ; N c6468 ; B 97 627 402 746 ; +C -1 ; WX 500 ; N c6469 ; B 200 631 299 731 ; +EndCharMetrics +StartKernData +StartKernPairs 1490 +KPX hyphen A -21 +KPX hyphen B -35 +KPX hyphen G 36 +KPX hyphen J 55 +KPX hyphen O 27 +KPX hyphen Q 36 +KPX hyphen T -91 +KPX hyphen V -58 +KPX hyphen W -40 +KPX hyphen X -49 +KPX hyphen Y -118 +KPX hyphen o 18 +KPX hyphen v -26 +KPX hyphen y -17 +KPX hyphen Adieresis -21 +KPX hyphen Odieresis 27 +KPX hyphen oacute 18 +KPX hyphen ograve 18 +KPX hyphen ocircumflex 18 +KPX hyphen odieresis 18 +KPX hyphen otilde 18 +KPX hyphen Agrave -21 +KPX hyphen Atilde -21 +KPX hyphen Otilde 27 +KPX hyphen ydieresis -17 +KPX hyphen Ydieresis -118 +KPX hyphen Acircumflex -21 +KPX hyphen Aacute -21 +KPX hyphen Oacute 27 +KPX hyphen Ocircumflex 27 +KPX hyphen Ograve 27 +KPX hyphen Yacute -118 +KPX hyphen yacute -17 +KPX hyphen Gbreve 36 +KPX A hyphen -21 +KPX A period -17 +KPX A colon -17 +KPX A A 27 +KPX A C -17 +KPX A G -17 +KPX A O -17 +KPX A Q -17 +KPX A T -77 +KPX A V -63 +KPX A W -54 +KPX A Y -77 +KPX A c -17 +KPX A d -17 +KPX A e -17 +KPX A f -35 +KPX A o -17 +KPX A q -17 +KPX A t -17 +KPX A v -58 +KPX A w -40 +KPX A y -67 +KPX A Adieresis 27 +KPX A Ccedilla -17 +KPX A Odieresis -17 +KPX A ccedilla -17 +KPX A eacute -17 +KPX A egrave -17 +KPX A ecircumflex -17 +KPX A edieresis -17 +KPX A oacute -17 +KPX A ograve -17 +KPX A ocircumflex -17 +KPX A odieresis -17 +KPX A otilde -17 +KPX A guillemotleft -35 +KPX A Agrave 27 +KPX A Atilde 27 +KPX A Otilde -17 +KPX A quotedblleft -128 +KPX A quotedblright -123 +KPX A ydieresis -67 +KPX A Ydieresis -77 +KPX A quotedblbase 22 +KPX A Acircumflex 27 +KPX A Aacute 27 +KPX A Oacute -17 +KPX A Ocircumflex -17 +KPX A Ograve -17 +KPX A Yacute -77 +KPX A yacute -67 +KPX A Gbreve -17 +KPX A Cacute -17 +KPX A cacute -17 +KPX A Ccaron -17 +KPX A ccaron -17 +KPX B C -17 +KPX B G -17 +KPX B O -17 +KPX B S -17 +KPX B V -30 +KPX B W -35 +KPX B Y -54 +KPX B Ccedilla -17 +KPX B Odieresis -17 +KPX B guillemotleft -30 +KPX B guillemotright -17 +KPX B Otilde -17 +KPX B quotedblleft -54 +KPX B quotedblright -54 +KPX B Ydieresis -54 +KPX B quotedblbase -40 +KPX B Oacute -17 +KPX B Ocircumflex -17 +KPX B Ograve -17 +KPX B Scaron -17 +KPX B Yacute -54 +KPX B Gbreve -17 +KPX B Scedilla -17 +KPX B Cacute -17 +KPX B Ccaron -17 +KPX C Y -17 +KPX C guillemotleft -17 +KPX C guillemotright -17 +KPX C quotedblright 18 +KPX C Ydieresis -17 +KPX C Yacute -17 +KPX D A -17 +KPX D V -17 +KPX D Y -54 +KPX D Adieresis -17 +KPX D guillemotleft -17 +KPX D guillemotright -17 +KPX D Agrave -17 +KPX D Atilde -17 +KPX D quotedblleft -21 +KPX D quotedblright -26 +KPX D Ydieresis -54 +KPX D quotedblbase -91 +KPX D Acircumflex -17 +KPX D Aacute -17 +KPX D Yacute -54 +KPX F period -160 +KPX F colon -77 +KPX F A -91 +KPX F S -17 +KPX F T -17 +KPX F a -91 +KPX F e -54 +KPX F i -72 +KPX F o -35 +KPX F r -72 +KPX F u -54 +KPX F y -91 +KPX F Adieresis -91 +KPX F aacute -91 +KPX F agrave -91 +KPX F acircumflex -91 +KPX F adieresis -91 +KPX F atilde -91 +KPX F aring -91 +KPX F eacute -54 +KPX F egrave -54 +KPX F ecircumflex -54 +KPX F edieresis -54 +KPX F oacute -35 +KPX F ograve -35 +KPX F ocircumflex -35 +KPX F odieresis -35 +KPX F otilde -35 +KPX F uacute -54 +KPX F ugrave -54 +KPX F ucircumflex -54 +KPX F udieresis -54 +KPX F Agrave -91 +KPX F Atilde -91 +KPX F quotedblleft -21 +KPX F ydieresis -91 +KPX F quotedblbase -183 +KPX F Acircumflex -91 +KPX F Aacute -91 +KPX F Scaron -17 +KPX F yacute -91 +KPX F Scedilla -17 +KPX G T -35 +KPX G Y -49 +KPX G guillemotleft -17 +KPX G guillemotright -17 +KPX G quotedblleft -21 +KPX G quotedblright -21 +KPX G Ydieresis -49 +KPX G quotedblbase -26 +KPX G Yacute -49 +KPX H period -17 +KPX H quotedblleft -35 +KPX H quotedblright -30 +KPX H quotedblbase -35 +KPX J hyphen -35 +KPX J A -17 +KPX J Adieresis -17 +KPX J guillemotleft -17 +KPX J guillemotright -17 +KPX J Agrave -17 +KPX J Atilde -17 +KPX J quotedblleft -35 +KPX J quotedblright -30 +KPX J quotedblbase -54 +KPX J Acircumflex -17 +KPX J Aacute -17 +KPX K hyphen -104 +KPX K A -17 +KPX K C -54 +KPX K O -54 +KPX K T -77 +KPX K U -26 +KPX K W -35 +KPX K Y -35 +KPX K a -17 +KPX K e -49 +KPX K o -49 +KPX K u -49 +KPX K y -72 +KPX K Adieresis -17 +KPX K Ccedilla -54 +KPX K Odieresis -54 +KPX K Udieresis -26 +KPX K aacute -17 +KPX K agrave -17 +KPX K acircumflex -17 +KPX K adieresis -17 +KPX K atilde -17 +KPX K aring -17 +KPX K eacute -49 +KPX K egrave -49 +KPX K ecircumflex -49 +KPX K edieresis -49 +KPX K oacute -49 +KPX K ograve -49 +KPX K ocircumflex -49 +KPX K odieresis -49 +KPX K otilde -49 +KPX K uacute -49 +KPX K ugrave -49 +KPX K ucircumflex -49 +KPX K udieresis -49 +KPX K guillemotleft -63 +KPX K Agrave -17 +KPX K Atilde -17 +KPX K Otilde -54 +KPX K quotedblleft -30 +KPX K quotedblright -30 +KPX K ydieresis -72 +KPX K Ydieresis -35 +KPX K Acircumflex -17 +KPX K Aacute -17 +KPX K Oacute -54 +KPX K Ocircumflex -54 +KPX K Ograve -54 +KPX K Uacute -26 +KPX K Ucircumflex -26 +KPX K Ugrave -26 +KPX K Yacute -35 +KPX K yacute -72 +KPX K Cacute -54 +KPX K Ccaron -54 +KPX L hyphen -17 +KPX L A 22 +KPX L O -35 +KPX L T -137 +KPX L U -49 +KPX L V -109 +KPX L W -91 +KPX L Y -132 +KPX L e -17 +KPX L o -17 +KPX L u -17 +KPX L y -91 +KPX L Adieresis 22 +KPX L Odieresis -35 +KPX L Udieresis -49 +KPX L eacute -17 +KPX L egrave -17 +KPX L ecircumflex -17 +KPX L edieresis -17 +KPX L oacute -17 +KPX L ograve -17 +KPX L ocircumflex -17 +KPX L odieresis -17 +KPX L otilde -17 +KPX L uacute -17 +KPX L ugrave -17 +KPX L ucircumflex -17 +KPX L udieresis -17 +KPX L Agrave 22 +KPX L Atilde 22 +KPX L Otilde -35 +KPX L quotedblleft -202 +KPX L quotedblright -262 +KPX L ydieresis -91 +KPX L Ydieresis -132 +KPX L Acircumflex 22 +KPX L Aacute 22 +KPX L Oacute -35 +KPX L Ocircumflex -35 +KPX L Ograve -35 +KPX L Uacute -49 +KPX L Ucircumflex -49 +KPX L Ugrave -49 +KPX L Yacute -132 +KPX L yacute -91 +KPX O hyphen 27 +KPX O period -40 +KPX O colon -17 +KPX O A -17 +KPX O V -17 +KPX O X -63 +KPX O Y -54 +KPX O Adieresis -17 +KPX O guillemotleft -17 +KPX O Agrave -17 +KPX O Atilde -17 +KPX O quotedblleft -21 +KPX O quotedblright -17 +KPX O Ydieresis -54 +KPX O quotedblbase -91 +KPX O Acircumflex -17 +KPX O Aacute -17 +KPX O Yacute -54 +KPX P hyphen -21 +KPX P period -155 +KPX P A -63 +KPX P Y -21 +KPX P a -44 +KPX P e -35 +KPX P i -21 +KPX P n -17 +KPX P o -35 +KPX P r -17 +KPX P s -17 +KPX P u -17 +KPX P Adieresis -63 +KPX P aacute -44 +KPX P agrave -44 +KPX P acircumflex -44 +KPX P adieresis -44 +KPX P atilde -44 +KPX P aring -44 +KPX P eacute -35 +KPX P egrave -35 +KPX P ecircumflex -35 +KPX P edieresis -35 +KPX P ntilde -17 +KPX P oacute -35 +KPX P ograve -35 +KPX P ocircumflex -35 +KPX P odieresis -35 +KPX P otilde -35 +KPX P uacute -17 +KPX P ugrave -17 +KPX P ucircumflex -17 +KPX P udieresis -17 +KPX P guillemotleft -17 +KPX P Agrave -63 +KPX P Atilde -63 +KPX P quotedblleft 18 +KPX P quotedblright 18 +KPX P Ydieresis -21 +KPX P quotedblbase -160 +KPX P Acircumflex -63 +KPX P Aacute -63 +KPX P scaron -17 +KPX P Yacute -21 +KPX P scedilla -17 +KPX Q hyphen 27 +KPX Q quotedblleft -21 +KPX Q quotedblright -17 +KPX Q quotedblbase -63 +KPX R hyphen -40 +KPX R period -35 +KPX R colon -30 +KPX R A -40 +KPX R C -49 +KPX R T -72 +KPX R V -54 +KPX R W -40 +KPX R Y -63 +KPX R a -21 +KPX R e -44 +KPX R o -44 +KPX R u -44 +KPX R y -54 +KPX R Adieresis -40 +KPX R Ccedilla -49 +KPX R aacute -21 +KPX R agrave -21 +KPX R acircumflex -21 +KPX R adieresis -21 +KPX R atilde -21 +KPX R aring -21 +KPX R eacute -44 +KPX R egrave -44 +KPX R ecircumflex -44 +KPX R edieresis -44 +KPX R oacute -44 +KPX R ograve -44 +KPX R ocircumflex -44 +KPX R odieresis -44 +KPX R otilde -44 +KPX R uacute -44 +KPX R ugrave -44 +KPX R ucircumflex -44 +KPX R udieresis -44 +KPX R guillemotleft -54 +KPX R guillemotright -17 +KPX R Agrave -40 +KPX R Atilde -40 +KPX R quotedblleft -72 +KPX R quotedblright -63 +KPX R ydieresis -54 +KPX R Ydieresis -63 +KPX R quotedblbase -17 +KPX R Acircumflex -40 +KPX R Aacute -40 +KPX R Yacute -63 +KPX R yacute -54 +KPX R Cacute -49 +KPX R Ccaron -49 +KPX S A 18 +KPX S Adieresis 18 +KPX S Agrave 18 +KPX S Atilde 18 +KPX S Acircumflex 18 +KPX S Aacute 18 +KPX T hyphen -91 +KPX T period -118 +KPX T colon -109 +KPX T A -77 +KPX T C -58 +KPX T T -17 +KPX T a -165 +KPX T c -169 +KPX T e -169 +KPX T i -30 +KPX T o -169 +KPX T r -146 +KPX T s -165 +KPX T u -151 +KPX T w -165 +KPX T y -155 +KPX T Adieresis -77 +KPX T Ccedilla -58 +KPX T aacute -165 +KPX T agrave -165 +KPX T acircumflex -165 +KPX T adieresis -165 +KPX T atilde -165 +KPX T aring -165 +KPX T ccedilla -169 +KPX T eacute -169 +KPX T egrave -169 +KPX T ecircumflex -169 +KPX T edieresis -169 +KPX T oacute -169 +KPX T ograve -169 +KPX T ocircumflex -169 +KPX T odieresis -169 +KPX T otilde -169 +KPX T uacute -151 +KPX T ugrave -151 +KPX T ucircumflex -151 +KPX T udieresis -151 +KPX T guillemotleft -91 +KPX T guillemotright -54 +KPX T Agrave -77 +KPX T Atilde -77 +KPX T quotedblright -21 +KPX T ydieresis -155 +KPX T quotedblbase -128 +KPX T Acircumflex -77 +KPX T Aacute -77 +KPX T scaron -165 +KPX T yacute -155 +KPX T scedilla -165 +KPX T Cacute -58 +KPX T cacute -169 +KPX T Ccaron -58 +KPX T ccaron -169 +KPX U Z -17 +KPX U Zcaron -17 +KPX V hyphen -58 +KPX V period -128 +KPX V colon -81 +KPX V A -63 +KPX V O -17 +KPX V a -77 +KPX V e -77 +KPX V i -21 +KPX V o -77 +KPX V u -67 +KPX V y -26 +KPX V Adieresis -63 +KPX V Odieresis -17 +KPX V aacute -77 +KPX V agrave -77 +KPX V acircumflex -77 +KPX V adieresis -77 +KPX V atilde -77 +KPX V aring -77 +KPX V eacute -77 +KPX V egrave -77 +KPX V ecircumflex -77 +KPX V edieresis -77 +KPX V oacute -77 +KPX V ograve -77 +KPX V ocircumflex -77 +KPX V odieresis -77 +KPX V otilde -77 +KPX V uacute -67 +KPX V ugrave -67 +KPX V ucircumflex -67 +KPX V udieresis -67 +KPX V guillemotleft -86 +KPX V guillemotright -54 +KPX V Agrave -63 +KPX V Atilde -63 +KPX V Otilde -17 +KPX V ydieresis -26 +KPX V quotedblbase -137 +KPX V Acircumflex -63 +KPX V Aacute -63 +KPX V Oacute -17 +KPX V Ocircumflex -17 +KPX V Ograve -17 +KPX V yacute -26 +KPX W hyphen -40 +KPX W period -114 +KPX W colon -58 +KPX W A -54 +KPX W a -63 +KPX W e -58 +KPX W i -21 +KPX W o -58 +KPX W r -44 +KPX W u -35 +KPX W y -17 +KPX W Adieresis -54 +KPX W aacute -63 +KPX W agrave -63 +KPX W acircumflex -63 +KPX W adieresis -63 +KPX W atilde -63 +KPX W aring -63 +KPX W eacute -58 +KPX W egrave -58 +KPX W ecircumflex -58 +KPX W edieresis -58 +KPX W oacute -58 +KPX W ograve -58 +KPX W ocircumflex -58 +KPX W odieresis -58 +KPX W otilde -58 +KPX W uacute -35 +KPX W ugrave -35 +KPX W ucircumflex -35 +KPX W udieresis -35 +KPX W guillemotleft -54 +KPX W guillemotright -17 +KPX W Agrave -54 +KPX W Atilde -54 +KPX W quotedblleft -17 +KPX W ydieresis -17 +KPX W quotedblbase -128 +KPX W Acircumflex -54 +KPX W Aacute -54 +KPX W yacute -17 +KPX X hyphen -49 +KPX X C -72 +KPX X O -63 +KPX X T -17 +KPX X e -44 +KPX X Ccedilla -72 +KPX X Odieresis -63 +KPX X eacute -44 +KPX X egrave -44 +KPX X ecircumflex -44 +KPX X edieresis -44 +KPX X guillemotleft -54 +KPX X Otilde -63 +KPX X quotedblleft -77 +KPX X quotedblright -40 +KPX X quotedblbase -21 +KPX X Oacute -63 +KPX X Ocircumflex -63 +KPX X Ograve -63 +KPX X Cacute -72 +KPX X Ccaron -72 +KPX Y hyphen -118 +KPX Y period -202 +KPX Y colon -132 +KPX Y A -77 +KPX Y C -54 +KPX Y O -54 +KPX Y a -137 +KPX Y e -132 +KPX Y i -35 +KPX Y o -132 +KPX Y u -114 +KPX Y Adieresis -77 +KPX Y Ccedilla -54 +KPX Y Odieresis -54 +KPX Y aacute -137 +KPX Y agrave -137 +KPX Y acircumflex -137 +KPX Y adieresis -137 +KPX Y atilde -137 +KPX Y aring -137 +KPX Y eacute -132 +KPX Y egrave -132 +KPX Y ecircumflex -132 +KPX Y edieresis -132 +KPX Y oacute -132 +KPX Y ograve -132 +KPX Y ocircumflex -132 +KPX Y odieresis -132 +KPX Y otilde -132 +KPX Y uacute -114 +KPX Y ugrave -114 +KPX Y ucircumflex -114 +KPX Y udieresis -114 +KPX Y guillemotleft -109 +KPX Y guillemotright -72 +KPX Y Agrave -77 +KPX Y Atilde -77 +KPX Y Otilde -54 +KPX Y quotedblleft -54 +KPX Y quotedblright -17 +KPX Y quotedblbase -128 +KPX Y Acircumflex -77 +KPX Y Aacute -77 +KPX Y Oacute -54 +KPX Y Ocircumflex -54 +KPX Y Ograve -54 +KPX Y Cacute -54 +KPX Y Ccaron -54 +KPX Z hyphen -17 +KPX Z quotedblleft -17 +KPX Z quotedblright -17 +KPX Z quotedblbase -17 +KPX e x -17 +KPX f hyphen -54 +KPX f period -72 +KPX f colon -35 +KPX f t -17 +KPX f w -17 +KPX f y -17 +KPX f guillemotleft -35 +KPX f guillemotright -17 +KPX f quotedblleft 31 +KPX f ydieresis -17 +KPX f quotedblbase -114 +KPX f yacute -17 +KPX k a -17 +KPX k e -35 +KPX k o -35 +KPX k u -30 +KPX k y -35 +KPX k aacute -17 +KPX k agrave -17 +KPX k acircumflex -17 +KPX k adieresis -17 +KPX k atilde -17 +KPX k aring -17 +KPX k eacute -35 +KPX k egrave -35 +KPX k ecircumflex -35 +KPX k edieresis -35 +KPX k oacute -35 +KPX k ograve -35 +KPX k ocircumflex -35 +KPX k odieresis -35 +KPX k otilde -35 +KPX k uacute -30 +KPX k ugrave -30 +KPX k ucircumflex -30 +KPX k udieresis -30 +KPX k ydieresis -35 +KPX k yacute -35 +KPX n quotedblleft -72 +KPX n quotedblright -54 +KPX n quotedblbase -44 +KPX o hyphen 18 +KPX o period -17 +KPX o x -30 +KPX o quotedblleft -72 +KPX o quotedblright -35 +KPX o quotedblbase -63 +KPX r hyphen -63 +KPX r period -91 +KPX r colon -17 +KPX r c -21 +KPX r d -17 +KPX r e -21 +KPX r g -17 +KPX r h -17 +KPX r m -17 +KPX r n -17 +KPX r o -21 +KPX r q -17 +KPX r r -17 +KPX r x -26 +KPX r ccedilla -21 +KPX r eacute -21 +KPX r egrave -21 +KPX r ecircumflex -21 +KPX r edieresis -21 +KPX r ntilde -17 +KPX r oacute -21 +KPX r ograve -21 +KPX r ocircumflex -21 +KPX r odieresis -21 +KPX r otilde -21 +KPX r guillemotleft -35 +KPX r quotedblright 41 +KPX r quotedblbase -151 +KPX r gbreve -17 +KPX r cacute -21 +KPX r ccaron -21 +KPX v hyphen -26 +KPX v period -77 +KPX v colon -54 +KPX v guillemotleft -17 +KPX v guillemotright -17 +KPX v quotedblright -17 +KPX v quotedblbase -132 +KPX w period -91 +KPX w colon -54 +KPX w guillemotleft -17 +KPX w guillemotright -17 +KPX w quotedblbase -104 +KPX x c -17 +KPX x e -30 +KPX x o -30 +KPX x ccedilla -17 +KPX x eacute -30 +KPX x egrave -30 +KPX x ecircumflex -30 +KPX x edieresis -30 +KPX x oacute -30 +KPX x ograve -30 +KPX x ocircumflex -30 +KPX x odieresis -30 +KPX x otilde -30 +KPX x cacute -17 +KPX x ccaron -17 +KPX y hyphen -17 +KPX y period -142 +KPX y colon -72 +KPX y guillemotleft -17 +KPX y guillemotright -17 +KPX y quotedblbase -146 +KPX Adieresis hyphen -21 +KPX Adieresis period -17 +KPX Adieresis colon -17 +KPX Adieresis A 27 +KPX Adieresis C -17 +KPX Adieresis G -17 +KPX Adieresis O -17 +KPX Adieresis Q -17 +KPX Adieresis T -77 +KPX Adieresis V -63 +KPX Adieresis W -54 +KPX Adieresis Y -77 +KPX Adieresis c -17 +KPX Adieresis d -17 +KPX Adieresis e -17 +KPX Adieresis f -35 +KPX Adieresis o -17 +KPX Adieresis q -17 +KPX Adieresis t -17 +KPX Adieresis v -58 +KPX Adieresis w -40 +KPX Adieresis y -67 +KPX Adieresis Adieresis 27 +KPX Adieresis Ccedilla -17 +KPX Adieresis Odieresis -17 +KPX Adieresis ccedilla -17 +KPX Adieresis eacute -17 +KPX Adieresis egrave -17 +KPX Adieresis ecircumflex -17 +KPX Adieresis edieresis -17 +KPX Adieresis oacute -17 +KPX Adieresis ograve -17 +KPX Adieresis ocircumflex -17 +KPX Adieresis odieresis -17 +KPX Adieresis otilde -17 +KPX Adieresis guillemotleft -35 +KPX Adieresis Agrave 27 +KPX Adieresis Atilde 27 +KPX Adieresis Otilde -17 +KPX Adieresis quotedblleft -128 +KPX Adieresis quotedblright -123 +KPX Adieresis ydieresis -67 +KPX Adieresis Ydieresis -77 +KPX Adieresis quotedblbase 22 +KPX Adieresis Acircumflex 27 +KPX Adieresis Aacute 27 +KPX Adieresis Oacute -17 +KPX Adieresis Ocircumflex -17 +KPX Adieresis Ograve -17 +KPX Adieresis Yacute -77 +KPX Adieresis yacute -67 +KPX Adieresis Gbreve -17 +KPX Adieresis Cacute -17 +KPX Adieresis cacute -17 +KPX Adieresis Ccaron -17 +KPX Adieresis ccaron -17 +KPX Ccedilla Y -17 +KPX Ccedilla guillemotleft -17 +KPX Ccedilla guillemotright -17 +KPX Ccedilla quotedblright 18 +KPX Ccedilla Ydieresis -17 +KPX Ccedilla Yacute -17 +KPX Odieresis hyphen 27 +KPX Odieresis period -40 +KPX Odieresis colon -17 +KPX Odieresis A -17 +KPX Odieresis V -17 +KPX Odieresis X -63 +KPX Odieresis Y -54 +KPX Odieresis Adieresis -17 +KPX Odieresis guillemotleft -17 +KPX Odieresis Agrave -17 +KPX Odieresis Atilde -17 +KPX Odieresis quotedblleft -21 +KPX Odieresis quotedblright -17 +KPX Odieresis Ydieresis -54 +KPX Odieresis quotedblbase -91 +KPX Odieresis Acircumflex -17 +KPX Odieresis Aacute -17 +KPX Odieresis Yacute -54 +KPX Udieresis Z -17 +KPX Udieresis Zcaron -17 +KPX eacute x -17 +KPX egrave x -17 +KPX ecircumflex x -17 +KPX edieresis x -17 +KPX ntilde quotedblleft -72 +KPX ntilde quotedblright -54 +KPX ntilde quotedblbase -44 +KPX oacute hyphen 18 +KPX oacute period -17 +KPX oacute x -30 +KPX oacute quotedblleft -72 +KPX oacute quotedblright -35 +KPX oacute quotedblbase -63 +KPX ograve hyphen 18 +KPX ograve period -17 +KPX ograve x -30 +KPX ograve quotedblleft -72 +KPX ograve quotedblright -35 +KPX ograve quotedblbase -63 +KPX ocircumflex hyphen 18 +KPX ocircumflex period -17 +KPX ocircumflex x -30 +KPX ocircumflex quotedblleft -72 +KPX ocircumflex quotedblright -35 +KPX ocircumflex quotedblbase -63 +KPX odieresis hyphen 18 +KPX odieresis period -17 +KPX odieresis x -30 +KPX odieresis quotedblleft -72 +KPX odieresis quotedblright -35 +KPX odieresis quotedblbase -63 +KPX otilde hyphen 18 +KPX otilde period -17 +KPX otilde x -30 +KPX otilde quotedblleft -72 +KPX otilde quotedblright -35 +KPX otilde quotedblbase -63 +KPX germandbls hyphen 18 +KPX germandbls quotedblleft -54 +KPX germandbls quotedblright -54 +KPX germandbls quotedblbase -40 +KPX AE quotedblleft -40 +KPX AE quotedblright -44 +KPX AE quotedblbase -54 +KPX guillemotleft B -17 +KPX guillemotleft C -17 +KPX guillemotleft D -17 +KPX guillemotleft G -17 +KPX guillemotleft J -17 +KPX guillemotleft T -54 +KPX guillemotleft V -54 +KPX guillemotleft W -17 +KPX guillemotleft Y -72 +KPX guillemotleft v -17 +KPX guillemotleft w -17 +KPX guillemotleft y -17 +KPX guillemotleft Ccedilla -17 +KPX guillemotleft AE 73 +KPX guillemotleft ydieresis -17 +KPX guillemotleft Ydieresis -72 +KPX guillemotleft Yacute -72 +KPX guillemotleft yacute -17 +KPX guillemotleft Gbreve -17 +KPX guillemotleft Cacute -17 +KPX guillemotleft Ccaron -17 +KPX guillemotright A -35 +KPX guillemotright B -35 +KPX guillemotright C -17 +KPX guillemotright D -17 +KPX guillemotright J -17 +KPX guillemotright O -17 +KPX guillemotright T -91 +KPX guillemotright V -86 +KPX guillemotright W -54 +KPX guillemotright X -54 +KPX guillemotright Y -109 +KPX guillemotright v -17 +KPX guillemotright w -17 +KPX guillemotright y -17 +KPX guillemotright Adieresis -35 +KPX guillemotright Ccedilla -17 +KPX guillemotright Odieresis -17 +KPX guillemotright Agrave -35 +KPX guillemotright Atilde -35 +KPX guillemotright Otilde -17 +KPX guillemotright ydieresis -17 +KPX guillemotright Ydieresis -109 +KPX guillemotright Acircumflex -35 +KPX guillemotright Aacute -35 +KPX guillemotright Oacute -17 +KPX guillemotright Ocircumflex -17 +KPX guillemotright Ograve -17 +KPX guillemotright Yacute -109 +KPX guillemotright yacute -17 +KPX guillemotright Cacute -17 +KPX guillemotright Ccaron -17 +KPX Agrave hyphen -21 +KPX Agrave period -17 +KPX Agrave colon -17 +KPX Agrave A 27 +KPX Agrave C -17 +KPX Agrave G -17 +KPX Agrave O -17 +KPX Agrave Q -17 +KPX Agrave T -77 +KPX Agrave V -63 +KPX Agrave W -54 +KPX Agrave Y -77 +KPX Agrave c -17 +KPX Agrave d -17 +KPX Agrave e -17 +KPX Agrave f -35 +KPX Agrave o -17 +KPX Agrave q -17 +KPX Agrave t -17 +KPX Agrave v -58 +KPX Agrave w -40 +KPX Agrave y -67 +KPX Agrave Adieresis 27 +KPX Agrave Ccedilla -17 +KPX Agrave Odieresis -17 +KPX Agrave ccedilla -17 +KPX Agrave eacute -17 +KPX Agrave egrave -17 +KPX Agrave ecircumflex -17 +KPX Agrave edieresis -17 +KPX Agrave oacute -17 +KPX Agrave ograve -17 +KPX Agrave ocircumflex -17 +KPX Agrave odieresis -17 +KPX Agrave otilde -17 +KPX Agrave guillemotleft -35 +KPX Agrave Agrave 27 +KPX Agrave Atilde 27 +KPX Agrave Otilde -17 +KPX Agrave quotedblleft -128 +KPX Agrave quotedblright -123 +KPX Agrave ydieresis -67 +KPX Agrave Ydieresis -77 +KPX Agrave quotedblbase 22 +KPX Agrave Acircumflex 27 +KPX Agrave Aacute 27 +KPX Agrave Oacute -17 +KPX Agrave Ocircumflex -17 +KPX Agrave Ograve -17 +KPX Agrave Yacute -77 +KPX Agrave yacute -67 +KPX Agrave Gbreve -17 +KPX Agrave Cacute -17 +KPX Agrave cacute -17 +KPX Agrave Ccaron -17 +KPX Agrave ccaron -17 +KPX Atilde hyphen -21 +KPX Atilde period -17 +KPX Atilde colon -17 +KPX Atilde A 27 +KPX Atilde C -17 +KPX Atilde G -17 +KPX Atilde O -17 +KPX Atilde Q -17 +KPX Atilde T -77 +KPX Atilde V -63 +KPX Atilde W -54 +KPX Atilde Y -77 +KPX Atilde c -17 +KPX Atilde d -17 +KPX Atilde e -17 +KPX Atilde f -35 +KPX Atilde o -17 +KPX Atilde q -17 +KPX Atilde t -17 +KPX Atilde v -58 +KPX Atilde w -40 +KPX Atilde y -67 +KPX Atilde Adieresis 27 +KPX Atilde Ccedilla -17 +KPX Atilde Odieresis -17 +KPX Atilde ccedilla -17 +KPX Atilde eacute -17 +KPX Atilde egrave -17 +KPX Atilde ecircumflex -17 +KPX Atilde edieresis -17 +KPX Atilde oacute -17 +KPX Atilde ograve -17 +KPX Atilde ocircumflex -17 +KPX Atilde odieresis -17 +KPX Atilde otilde -17 +KPX Atilde guillemotleft -35 +KPX Atilde Agrave 27 +KPX Atilde Atilde 27 +KPX Atilde Otilde -17 +KPX Atilde quotedblleft -128 +KPX Atilde quotedblright -123 +KPX Atilde ydieresis -67 +KPX Atilde Ydieresis -77 +KPX Atilde quotedblbase 22 +KPX Atilde Acircumflex 27 +KPX Atilde Aacute 27 +KPX Atilde Oacute -17 +KPX Atilde Ocircumflex -17 +KPX Atilde Ograve -17 +KPX Atilde Yacute -77 +KPX Atilde yacute -67 +KPX Atilde Gbreve -17 +KPX Atilde Cacute -17 +KPX Atilde cacute -17 +KPX Atilde Ccaron -17 +KPX Atilde ccaron -17 +KPX Otilde hyphen 27 +KPX Otilde period -40 +KPX Otilde colon -17 +KPX Otilde A -17 +KPX Otilde V -17 +KPX Otilde X -63 +KPX Otilde Y -54 +KPX Otilde Adieresis -17 +KPX Otilde guillemotleft -17 +KPX Otilde Agrave -17 +KPX Otilde Atilde -17 +KPX Otilde quotedblleft -21 +KPX Otilde quotedblright -17 +KPX Otilde Ydieresis -54 +KPX Otilde quotedblbase -91 +KPX Otilde Acircumflex -17 +KPX Otilde Aacute -17 +KPX Otilde Yacute -54 +KPX quotedblleft A -128 +KPX quotedblleft B -30 +KPX quotedblleft C -35 +KPX quotedblleft D -30 +KPX quotedblleft F -30 +KPX quotedblleft G -35 +KPX quotedblleft H -30 +KPX quotedblleft J -30 +KPX quotedblleft K -30 +KPX quotedblleft L -30 +KPX quotedblleft O -35 +KPX quotedblleft P -30 +KPX quotedblleft Q -35 +KPX quotedblleft R -30 +KPX quotedblleft X -58 +KPX quotedblleft Z -17 +KPX quotedblleft f -35 +KPX quotedblleft n -54 +KPX quotedblleft o -72 +KPX quotedblleft r -54 +KPX quotedblleft v -35 +KPX quotedblleft w -35 +KPX quotedblleft y -35 +KPX quotedblleft Adieresis -128 +KPX quotedblleft Ccedilla -35 +KPX quotedblleft Odieresis -35 +KPX quotedblleft ntilde -54 +KPX quotedblleft oacute -72 +KPX quotedblleft ograve -72 +KPX quotedblleft ocircumflex -72 +KPX quotedblleft odieresis -72 +KPX quotedblleft otilde -72 +KPX quotedblleft germandbls -30 +KPX quotedblleft AE -188 +KPX quotedblleft Agrave -128 +KPX quotedblleft Atilde -128 +KPX quotedblleft Otilde -35 +KPX quotedblleft ydieresis -35 +KPX quotedblleft Acircumflex -128 +KPX quotedblleft Aacute -128 +KPX quotedblleft Oacute -35 +KPX quotedblleft Ocircumflex -35 +KPX quotedblleft Ograve -35 +KPX quotedblleft Zcaron -17 +KPX quotedblleft eth -35 +KPX quotedblleft yacute -35 +KPX quotedblleft Thorn -30 +KPX quotedblleft Gbreve -35 +KPX quotedblleft Cacute -35 +KPX quotedblleft Ccaron -35 +KPX ydieresis hyphen -17 +KPX ydieresis period -142 +KPX ydieresis colon -72 +KPX ydieresis guillemotleft -17 +KPX ydieresis guillemotright -17 +KPX ydieresis quotedblbase -146 +KPX Ydieresis hyphen -118 +KPX Ydieresis period -202 +KPX Ydieresis colon -132 +KPX Ydieresis A -77 +KPX Ydieresis C -54 +KPX Ydieresis O -54 +KPX Ydieresis a -137 +KPX Ydieresis e -132 +KPX Ydieresis i -35 +KPX Ydieresis o -132 +KPX Ydieresis u -114 +KPX Ydieresis Adieresis -77 +KPX Ydieresis Ccedilla -54 +KPX Ydieresis Odieresis -54 +KPX Ydieresis aacute -137 +KPX Ydieresis agrave -137 +KPX Ydieresis acircumflex -137 +KPX Ydieresis adieresis -137 +KPX Ydieresis atilde -137 +KPX Ydieresis aring -137 +KPX Ydieresis eacute -132 +KPX Ydieresis egrave -132 +KPX Ydieresis ecircumflex -132 +KPX Ydieresis edieresis -132 +KPX Ydieresis oacute -132 +KPX Ydieresis ograve -132 +KPX Ydieresis ocircumflex -132 +KPX Ydieresis odieresis -132 +KPX Ydieresis otilde -132 +KPX Ydieresis uacute -114 +KPX Ydieresis ugrave -114 +KPX Ydieresis ucircumflex -114 +KPX Ydieresis udieresis -114 +KPX Ydieresis guillemotleft -109 +KPX Ydieresis guillemotright -72 +KPX Ydieresis Agrave -77 +KPX Ydieresis Atilde -77 +KPX Ydieresis Otilde -54 +KPX Ydieresis quotedblleft -54 +KPX Ydieresis quotedblright -17 +KPX Ydieresis quotedblbase -128 +KPX Ydieresis Acircumflex -77 +KPX Ydieresis Aacute -77 +KPX Ydieresis Oacute -54 +KPX Ydieresis Ocircumflex -54 +KPX Ydieresis Ograve -54 +KPX Ydieresis Cacute -54 +KPX Ydieresis Ccaron -54 +KPX quotedblbase A 18 +KPX quotedblbase B -35 +KPX quotedblbase C -54 +KPX quotedblbase D -35 +KPX quotedblbase F -35 +KPX quotedblbase G -35 +KPX quotedblbase H -35 +KPX quotedblbase J 22 +KPX quotedblbase K -35 +KPX quotedblbase L -35 +KPX quotedblbase O -54 +KPX quotedblbase P -35 +KPX quotedblbase Q -54 +KPX quotedblbase R -35 +KPX quotedblbase T -137 +KPX quotedblbase V -183 +KPX quotedblbase W -123 +KPX quotedblbase X -35 +KPX quotedblbase Y -183 +KPX quotedblbase f -17 +KPX quotedblbase n -35 +KPX quotedblbase o -35 +KPX quotedblbase r -35 +KPX quotedblbase v -114 +KPX quotedblbase w -95 +KPX quotedblbase y -54 +KPX quotedblbase Adieresis 18 +KPX quotedblbase Ccedilla -54 +KPX quotedblbase Odieresis -54 +KPX quotedblbase ntilde -35 +KPX quotedblbase oacute -35 +KPX quotedblbase ograve -35 +KPX quotedblbase ocircumflex -35 +KPX quotedblbase odieresis -35 +KPX quotedblbase otilde -35 +KPX quotedblbase germandbls -35 +KPX quotedblbase AE 18 +KPX quotedblbase Agrave 18 +KPX quotedblbase Atilde 18 +KPX quotedblbase Otilde -54 +KPX quotedblbase ydieresis -54 +KPX quotedblbase Ydieresis -183 +KPX quotedblbase Acircumflex 18 +KPX quotedblbase Aacute 18 +KPX quotedblbase Oacute -54 +KPX quotedblbase Ocircumflex -54 +KPX quotedblbase Ograve -54 +KPX quotedblbase eth -35 +KPX quotedblbase Yacute -183 +KPX quotedblbase yacute -54 +KPX quotedblbase Thorn -35 +KPX quotedblbase Gbreve -35 +KPX quotedblbase Cacute -54 +KPX quotedblbase Ccaron -54 +KPX Acircumflex hyphen -21 +KPX Acircumflex period -17 +KPX Acircumflex colon -17 +KPX Acircumflex A 27 +KPX Acircumflex C -17 +KPX Acircumflex G -17 +KPX Acircumflex O -17 +KPX Acircumflex Q -17 +KPX Acircumflex T -77 +KPX Acircumflex V -63 +KPX Acircumflex W -54 +KPX Acircumflex Y -77 +KPX Acircumflex c -17 +KPX Acircumflex d -17 +KPX Acircumflex e -17 +KPX Acircumflex f -35 +KPX Acircumflex o -17 +KPX Acircumflex q -17 +KPX Acircumflex t -17 +KPX Acircumflex v -58 +KPX Acircumflex w -40 +KPX Acircumflex y -67 +KPX Acircumflex Adieresis 27 +KPX Acircumflex Ccedilla -17 +KPX Acircumflex Odieresis -17 +KPX Acircumflex ccedilla -17 +KPX Acircumflex eacute -17 +KPX Acircumflex egrave -17 +KPX Acircumflex ecircumflex -17 +KPX Acircumflex edieresis -17 +KPX Acircumflex oacute -17 +KPX Acircumflex ograve -17 +KPX Acircumflex ocircumflex -17 +KPX Acircumflex odieresis -17 +KPX Acircumflex otilde -17 +KPX Acircumflex guillemotleft -35 +KPX Acircumflex Agrave 27 +KPX Acircumflex Atilde 27 +KPX Acircumflex Otilde -17 +KPX Acircumflex quotedblleft -128 +KPX Acircumflex quotedblright -123 +KPX Acircumflex ydieresis -67 +KPX Acircumflex Ydieresis -77 +KPX Acircumflex quotedblbase 22 +KPX Acircumflex Acircumflex 27 +KPX Acircumflex Aacute 27 +KPX Acircumflex Oacute -17 +KPX Acircumflex Ocircumflex -17 +KPX Acircumflex Ograve -17 +KPX Acircumflex Yacute -77 +KPX Acircumflex yacute -67 +KPX Acircumflex Gbreve -17 +KPX Acircumflex Cacute -17 +KPX Acircumflex cacute -17 +KPX Acircumflex Ccaron -17 +KPX Acircumflex ccaron -17 +KPX Aacute hyphen -21 +KPX Aacute period -17 +KPX Aacute colon -17 +KPX Aacute A 27 +KPX Aacute C -17 +KPX Aacute G -17 +KPX Aacute O -17 +KPX Aacute Q -17 +KPX Aacute T -77 +KPX Aacute V -63 +KPX Aacute W -54 +KPX Aacute Y -77 +KPX Aacute c -17 +KPX Aacute d -17 +KPX Aacute e -17 +KPX Aacute f -35 +KPX Aacute o -17 +KPX Aacute q -17 +KPX Aacute t -17 +KPX Aacute v -58 +KPX Aacute w -40 +KPX Aacute y -67 +KPX Aacute Adieresis 27 +KPX Aacute Ccedilla -17 +KPX Aacute Odieresis -17 +KPX Aacute ccedilla -17 +KPX Aacute eacute -17 +KPX Aacute egrave -17 +KPX Aacute ecircumflex -17 +KPX Aacute edieresis -17 +KPX Aacute oacute -17 +KPX Aacute ograve -17 +KPX Aacute ocircumflex -17 +KPX Aacute odieresis -17 +KPX Aacute otilde -17 +KPX Aacute guillemotleft -35 +KPX Aacute Agrave 27 +KPX Aacute Atilde 27 +KPX Aacute Otilde -17 +KPX Aacute quotedblleft -128 +KPX Aacute quotedblright -123 +KPX Aacute ydieresis -67 +KPX Aacute Ydieresis -77 +KPX Aacute quotedblbase 22 +KPX Aacute Acircumflex 27 +KPX Aacute Aacute 27 +KPX Aacute Oacute -17 +KPX Aacute Ocircumflex -17 +KPX Aacute Ograve -17 +KPX Aacute Yacute -77 +KPX Aacute yacute -67 +KPX Aacute Gbreve -17 +KPX Aacute Cacute -17 +KPX Aacute cacute -17 +KPX Aacute Ccaron -17 +KPX Aacute ccaron -17 +KPX Oacute hyphen 27 +KPX Oacute period -40 +KPX Oacute colon -17 +KPX Oacute A -17 +KPX Oacute V -17 +KPX Oacute X -63 +KPX Oacute Y -54 +KPX Oacute Adieresis -17 +KPX Oacute guillemotleft -17 +KPX Oacute Agrave -17 +KPX Oacute Atilde -17 +KPX Oacute quotedblleft -21 +KPX Oacute quotedblright -17 +KPX Oacute Ydieresis -54 +KPX Oacute quotedblbase -91 +KPX Oacute Acircumflex -17 +KPX Oacute Aacute -17 +KPX Oacute Yacute -54 +KPX Ocircumflex hyphen 27 +KPX Ocircumflex period -40 +KPX Ocircumflex colon -17 +KPX Ocircumflex A -17 +KPX Ocircumflex V -17 +KPX Ocircumflex X -63 +KPX Ocircumflex Y -54 +KPX Ocircumflex Adieresis -17 +KPX Ocircumflex guillemotleft -17 +KPX Ocircumflex Agrave -17 +KPX Ocircumflex Atilde -17 +KPX Ocircumflex quotedblleft -21 +KPX Ocircumflex quotedblright -17 +KPX Ocircumflex Ydieresis -54 +KPX Ocircumflex quotedblbase -91 +KPX Ocircumflex Acircumflex -17 +KPX Ocircumflex Aacute -17 +KPX Ocircumflex Yacute -54 +KPX Ograve hyphen 27 +KPX Ograve period -40 +KPX Ograve colon -17 +KPX Ograve A -17 +KPX Ograve V -17 +KPX Ograve X -63 +KPX Ograve Y -54 +KPX Ograve Adieresis -17 +KPX Ograve guillemotleft -17 +KPX Ograve Agrave -17 +KPX Ograve Atilde -17 +KPX Ograve quotedblleft -21 +KPX Ograve quotedblright -17 +KPX Ograve Ydieresis -54 +KPX Ograve quotedblbase -91 +KPX Ograve Acircumflex -17 +KPX Ograve Aacute -17 +KPX Ograve Yacute -54 +KPX Uacute Z -17 +KPX Uacute Zcaron -17 +KPX Ucircumflex Z -17 +KPX Ucircumflex Zcaron -17 +KPX Ugrave Z -17 +KPX Ugrave Zcaron -17 +KPX Scaron A 18 +KPX Scaron Adieresis 18 +KPX Scaron Agrave 18 +KPX Scaron Atilde 18 +KPX Scaron Acircumflex 18 +KPX Scaron Aacute 18 +KPX Zcaron hyphen -17 +KPX Zcaron quotedblleft -17 +KPX Zcaron quotedblright -17 +KPX Zcaron quotedblbase -17 +KPX eth quotedblleft -44 +KPX eth quotedblright -54 +KPX eth quotedblbase -35 +KPX Yacute hyphen -118 +KPX Yacute period -202 +KPX Yacute colon -132 +KPX Yacute A -77 +KPX Yacute C -54 +KPX Yacute O -54 +KPX Yacute a -137 +KPX Yacute e -132 +KPX Yacute i -35 +KPX Yacute o -132 +KPX Yacute u -114 +KPX Yacute Adieresis -77 +KPX Yacute Ccedilla -54 +KPX Yacute Odieresis -54 +KPX Yacute aacute -137 +KPX Yacute agrave -137 +KPX Yacute acircumflex -137 +KPX Yacute adieresis -137 +KPX Yacute atilde -137 +KPX Yacute aring -137 +KPX Yacute eacute -132 +KPX Yacute egrave -132 +KPX Yacute ecircumflex -132 +KPX Yacute edieresis -132 +KPX Yacute oacute -132 +KPX Yacute ograve -132 +KPX Yacute ocircumflex -132 +KPX Yacute odieresis -132 +KPX Yacute otilde -132 +KPX Yacute uacute -114 +KPX Yacute ugrave -114 +KPX Yacute ucircumflex -114 +KPX Yacute udieresis -114 +KPX Yacute guillemotleft -109 +KPX Yacute guillemotright -72 +KPX Yacute Agrave -77 +KPX Yacute Atilde -77 +KPX Yacute Otilde -54 +KPX Yacute quotedblleft -54 +KPX Yacute quotedblright -17 +KPX Yacute quotedblbase -128 +KPX Yacute Acircumflex -77 +KPX Yacute Aacute -77 +KPX Yacute Oacute -54 +KPX Yacute Ocircumflex -54 +KPX Yacute Ograve -54 +KPX Yacute Cacute -54 +KPX Yacute Ccaron -54 +KPX yacute hyphen -17 +KPX yacute period -142 +KPX yacute colon -72 +KPX yacute guillemotleft -17 +KPX yacute guillemotright -17 +KPX yacute quotedblbase -146 +KPX Thorn period -72 +KPX Thorn colon -35 +KPX Thorn quotedblleft -17 +KPX Thorn quotedblbase -91 +KPX Gbreve T -35 +KPX Gbreve Y -49 +KPX Gbreve guillemotleft -17 +KPX Gbreve guillemotright -17 +KPX Gbreve quotedblleft -21 +KPX Gbreve quotedblright -21 +KPX Gbreve Ydieresis -49 +KPX Gbreve quotedblbase -26 +KPX Gbreve Yacute -49 +KPX Scedilla A 18 +KPX Scedilla Adieresis 18 +KPX Scedilla Agrave 18 +KPX Scedilla Atilde 18 +KPX Scedilla Acircumflex 18 +KPX Scedilla Aacute 18 +KPX Cacute Y -17 +KPX Cacute guillemotleft -17 +KPX Cacute guillemotright -17 +KPX Cacute quotedblright 18 +KPX Cacute Ydieresis -17 +KPX Cacute Yacute -17 +KPX Ccaron Y -17 +KPX Ccaron guillemotleft -17 +KPX Ccaron guillemotright -17 +KPX Ccaron quotedblright 18 +KPX Ccaron Ydieresis -17 +KPX Ccaron Yacute -17 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/bin/gems/afm-0.2.2/test/helper.rb b/bin/gems/afm-0.2.2/test/helper.rb new file mode 100644 index 00000000..4361aa1c --- /dev/null +++ b/bin/gems/afm-0.2.2/test/helper.rb @@ -0,0 +1,4 @@ +require 'rubygems' +require 'bundler/setup' +require 'minitest/autorun' +require 'afm' diff --git a/bin/gems/afm-0.2.2/test/test_afm.rb b/bin/gems/afm-0.2.2/test/test_afm.rb new file mode 100644 index 00000000..d02376e0 --- /dev/null +++ b/bin/gems/afm-0.2.2/test/test_afm.rb @@ -0,0 +1,32 @@ +require 'helper' + +class TestAfm < Minitest::Test + + def setup + @font = AFM::Font.new(File.join(File.dirname(__FILE__), 'fixtures', 'Vera.afm')) + end + + def test_should_set_metadata + assert_equal "BitstreamVeraSans-Roman", @font.metadata['FontName'] + assert_equal "BitstreamVeraSans-Roman", @font['FontName'] + end + + def test_should_set_char_metrics + assert_equal 400, @font.char_metrics['exclam'][:wx] + assert_equal [85, -131, 310, 758], @font.char_metrics['parenleft'][:boundingbox] + end + + def test_should_set_char_metrics_by_code + assert_equal 400, @font.char_metrics_by_code[33][:wx] + assert_equal [85, -131, 310, 758], @font.char_metrics_by_code[40][:boundingbox] + end + + def test_should_get_char_metrics_by_char + assert_equal 400, @font.metrics_for("!")[:wx] + end + + def test_open_font_with_alternative_method + assert !AFM::Font.from_file(File.join(File.dirname(__FILE__), 'fixtures', 'Vera.afm')).nil? + end + +end diff --git a/bin/gems/async-2.23.0/lib/async.rb b/bin/gems/async-2.23.0/lib/async.rb new file mode 100644 index 00000000..dfbb7dbc --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2020, by Salim Semaoune. + +require_relative "async/version" +require_relative "async/reactor" + +require_relative "kernel/async" +require_relative "kernel/sync" + +# Asynchronous programming framework. +module Async +end diff --git a/bin/gems/async-2.23.0/lib/async/barrier.md b/bin/gems/async-2.23.0/lib/async/barrier.md new file mode 100644 index 00000000..03cdfa52 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/barrier.md @@ -0,0 +1,42 @@ +A synchronization primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore}. + + +## Example + +~~~ ruby +require 'async' +require 'async/barrier' + +barrier = Async::Barrier.new +Sync do + Console.info("Barrier Example: sleep sort.") + + # Generate an array of 10 numbers: + numbers = 10.times.map{rand(10)} + sorted = [] + + # Sleep sort the numbers: + numbers.each do |number| + barrier.async do |task| + sleep(number) + sorted << number + end + end + + # Wait for all the numbers to be sorted: + barrier.wait + + Console.info("Sorted", sorted) +ensure + # Ensure all the tasks are stopped when we exit: + barrier.stop +end +~~~ + +### Output + +~~~ +0.0s info: Barrier Example: sleep sort. +9.0s info: Sorted + | [3, 3, 3, 4, 4, 5, 5, 5, 8, 9] +~~~ diff --git a/bin/gems/async-2.23.0/lib/async/barrier.rb b/bin/gems/async-2.23.0/lib/async/barrier.rb new file mode 100644 index 00000000..274a2c75 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/barrier.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "list" +require_relative "task" + +module Async + # A general purpose synchronisation primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore}. + # + # @public Since *Async v1*. + class Barrier + # Initialize the barrier. + # @parameter parent [Task | Semaphore | Nil] The parent for holding any children tasks. + # @public Since *Async v1*. + def initialize(parent: nil) + @tasks = List.new + + @parent = parent + end + + class TaskNode < List::Node + def initialize(task) + @task = task + end + + attr :task + end + + private_constant :TaskNode + + # Number of tasks being held by the barrier. + def size + @tasks.size + end + + # All tasks which have been invoked into the barrier. + attr :tasks + + # Execute a child task and add it to the barrier. + # @asynchronous Executes the given block concurrently. + def async(*arguments, parent: (@parent or Task.current), **options, &block) + task = parent.async(*arguments, **options, &block) + + @tasks.append(TaskNode.new(task)) + + return task + end + + # Whether there are any tasks being held by the barrier. + # @returns [Boolean] + def empty? + @tasks.empty? + end + + # Wait for all tasks to complete by invoking {Task#wait} on each waiting task, which may raise an error. As long as the task has completed, it will be removed from the barrier. + # @asynchronous Will wait for tasks to finish executing. + def wait + @tasks.each do |waiting| + task = waiting.task + begin + task.wait + ensure + @tasks.remove?(waiting) unless task.alive? + end + end + end + + # Stop all tasks held by the barrier. + # @asynchronous May wait for tasks to finish executing. + def stop + @tasks.each do |waiting| + waiting.task.stop + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/clock.rb b/bin/gems/async-2.23.0/lib/async/clock.rb new file mode 100644 index 00000000..f1d6ebc8 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/clock.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2022, by Samuel Williams. + +module Async + # A convenient wrapper around the internal monotonic clock. + # @public Since *Async v1*. + class Clock + # Get the current elapsed monotonic time. + def self.now + ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + end + + # Measure the execution of a block of code. + # @yields {...} The block to execute. + # @returns [Numeric] The total execution time. + def self.measure + start_time = self.now + + yield + + return self.now - start_time + end + + # Start measuring elapsed time from now. + # @returns [Clock] + def self.start + self.new.tap(&:start!) + end + + # Create a new clock with the initial total time. + # @parameter total [Numeric] The initial clock duration. + def initialize(total = 0) + @total = total + @started = nil + end + + # Start measuring a duration. + def start! + @started ||= Clock.now + end + + # Stop measuring a duration and append the duration to the current total. + def stop! + if @started + @total += (Clock.now - @started) + @started = nil + end + + return @total + end + + # The total elapsed time including any current duration. + def total + total = @total + + if @started + total += (Clock.now - @started) + end + + return total + end + + # Reset the total elapsed time. If the clock is currently running, reset the start time to now. + def reset! + @total = 0 + + if @started + @started = Clock.now + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/condition.md b/bin/gems/async-2.23.0/lib/async/condition.md new file mode 100644 index 00000000..ef1d44f7 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/condition.md @@ -0,0 +1,31 @@ +A synchronization primitive, which allows fibers to wait until a particular condition is (edge) triggered. Zero or more fibers can wait on a condition. When the condition is signalled, the fibers will be resumed in order. + +## Example + +~~~ ruby +require 'async' + +Sync do + condition = Async::Condition.new + + Async do + Console.info "Waiting for condition..." + value = condition.wait + Console.info "Condition was signalled: #{value}" + end + + Async do |task| + sleep(1) + Console.info "Signalling condition..." + condition.signal("Hello World") + end +end +~~~ + +### Output + +~~~ +0.0s info: Waiting for condition... +1.0s info: Signalling condition... +1.0s info: Condition was signalled: Hello World +~~~ diff --git a/bin/gems/async-2.23.0/lib/async/condition.rb b/bin/gems/async-2.23.0/lib/async/condition.rb new file mode 100644 index 00000000..373e8a3e --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/condition.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2017, by Kent Gruber. + +require "fiber" +require_relative "list" + +module Async + # A synchronization primitive, which allows fibers to wait until a particular condition is (edge) triggered. + # @public Since *Async v1*. + class Condition + # Create a new condition. + def initialize + @waiting = List.new + end + + class FiberNode < List::Node + def initialize(fiber) + @fiber = fiber + end + + def transfer(*arguments) + @fiber.transfer(*arguments) + end + + def alive? + @fiber.alive? + end + end + + private_constant :FiberNode + + # Queue up the current fiber and wait on yielding the task. + # @returns [Object] + def wait + @waiting.stack(FiberNode.new(Fiber.current)) do + Fiber.scheduler.transfer + end + end + + # @deprecated Replaced by {#waiting?} + def empty? + @waiting.empty? + end + + # @returns [Boolean] Is any fiber waiting on this notification? + def waiting? + @waiting.size > 0 + end + + # Signal to a given task that it should resume operations. + # @parameter value [Object | Nil] The value to return to the waiting fibers. + def signal(value = nil) + return if @waiting.empty? + + waiting = self.exchange + + waiting.each do |fiber| + Fiber.scheduler.resume(fiber, value) if fiber.alive? + end + + return nil + end + + protected + + def exchange + waiting = @waiting + @waiting = List.new + return waiting + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/console.rb b/bin/gems/async-2.23.0/lib/async/console.rb new file mode 100644 index 00000000..301595f6 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/console.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +module Async + # Shims for the console gem, redirecting warnings and above to `Kernel#warn`. + # + # If you require this file, the `async` library will not depend on the `console` gem. + # + # That includes any gems that sit within the `Async` namespace. + # + # This is an experimental feature. + module Console + # Log a message at the debug level. The shim is silent. + def self.debug(...) + end + + # Log a message at the info level. The shim is silent. + def self.info(...) + end + + # Log a message at the warn level. The shim redirects to `Kernel#warn`. + def self.warn(*arguments, exception: nil, **options) + if exception + super(*arguments, exception.full_message, **options) + else + super(*arguments, **options) + end + end + + # Log a message at the error level. The shim redirects to `Kernel#warn`. + def self.error(...) + self.warn(...) + end + + # Log a message at the fatal level. The shim redirects to `Kernel#warn`. + def self.fatal(...) + self.warn(...) + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/idler.rb b/bin/gems/async-2.23.0/lib/async/idler.rb new file mode 100644 index 00000000..c221969c --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/idler.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +module Async + # A load balancing mechanism that can be used process work when the system is idle. + class Idler + # Create a new idler. + # + # @public Since *Async v2*. + # + # @parameter maximum_load [Numeric] The maximum load before we start shedding work. + # @parameter backoff [Numeric] The initial backoff time, used for delaying work. + # @parameter parent [Interface(:async) | Nil] The parent task to use for async operations. + def initialize(maximum_load = 0.8, backoff: 0.01, parent: nil) + @maximum_load = maximum_load + @backoff = backoff + @parent = parent + end + + # Wait until the system is idle, then execute the given block in a new task. + # + # @asynchronous Executes the given block concurrently. + # + # @parameter arguments [Array] The arguments to pass to the block. + # @parameter parent [Interface(:async) | Nil] The parent task to use for async operations. + # @parameter options [Hash] The options to pass to the task. + # @yields {|task| ...} When the system is idle, the block will be executed in a new task. + def async(*arguments, parent: (@parent or Task.current), **options, &block) + wait + + # It is crucial that we optimistically execute the child task, so that we prevent a tight loop invoking this method from consuming all available resources. + parent.async(*arguments, **options, &block) + end + + # Wait until the system is idle, according to the maximum load specified. + # + # If the scheduler is overloaded, this method will sleep for an exponentially increasing amount of time. + def wait + scheduler = Fiber.scheduler + backoff = nil + + while true + load = scheduler.load + + break if load < @maximum_load + + if backoff + sleep(backoff) + backoff *= 2.0 + else + scheduler.yield + backoff = @backoff + end + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/limited_queue.rb b/bin/gems/async-2.23.0/lib/async/limited_queue.rb new file mode 100644 index 00000000..10511a1d --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/limited_queue.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +# The implementation lives in `queue.rb` but later we may move it here for better autoload/inference. +require_relative "queue" diff --git a/bin/gems/async-2.23.0/lib/async/list.rb b/bin/gems/async-2.23.0/lib/async/list.rb new file mode 100644 index 00000000..11e66164 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/list.rb @@ -0,0 +1,311 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. + +module Async + # A general doublely linked list. This is used internally by {Async::Barrier} and {Async::Condition} to manage child tasks. + class List + # Initialize a new, empty, list. + def initialize + @head = self + @tail = self + @size = 0 + end + + # @returns [String] A short summary of the list. + def to_s + sprintf("#<%s:0x%x size=%d>", self.class.name, object_id, @size) + end + + alias inspect to_s + + # Fast, safe, unbounded accumulation of children. + def to_a + items = [] + current = self + + while current.tail != self + unless current.tail.is_a?(Iterator) + items << current.tail + end + + current = current.tail + end + + return items + end + + # @attribute [Node | Nil] Points at the end of the list. + attr_accessor :head + + # @attribute [Node | Nil] Points at the start of the list. + attr_accessor :tail + + # @attribute [Integer] The number of nodes in the list. + attr :size + + # A callback that is invoked when an item is added to the list. + def added(node) + @size += 1 + return node + end + + # Append a node to the end of the list. + def append(node) + if node.head + raise ArgumentError, "Node is already in a list!" + end + + node.tail = self + @head.tail = node + node.head = @head + @head = node + + return added(node) + end + + # Prepend a node to the start of the list. + def prepend(node) + if node.head + raise ArgumentError, "Node is already in a list!" + end + + node.head = self + @tail.head = node + node.tail = @tail + @tail = node + + return added(node) + end + + # Add the node, yield, and the remove the node. + # @yields {|node| ...} Yields the node. + # @returns [Object] Returns the result of the block. + def stack(node, &block) + append(node) + return yield(node) + ensure + remove!(node) + end + + # A callback that is invoked when an item is removed from the list. + def removed(node) + @size -= 1 + return node + end + + # Remove the node if it is in a list. + # + # You should be careful to only remove nodes that are part of this list. + # + # @returns [Node] Returns the node if it was removed, otherwise nil. + def remove?(node) + if node.head + return remove!(node) + end + + return nil + end + + # Remove the node. If it was already removed, this will raise an error. + # + # You should be careful to only remove nodes that are part of this list. + # + # @raises [ArgumentError] If the node is not part of this list. + # @returns [Node] Returns the node if it was removed, otherwise nil. + def remove(node) + # One downside of this interface is we don't actually check if the node is part of the list defined by `self`. This means that there is a potential for a node to be removed from a different list using this method, which in can throw off book-keeping when lists track size, etc. + unless node.head + raise ArgumentError, "Node is not in a list!" + end + + remove!(node) + end + + private def remove!(node) + node.head.tail = node.tail + node.tail.head = node.head + + # This marks the node as being removed, and causes remove to fail if called a 2nd time. + node.head = nil + # node.tail = nil + + return removed(node) + end + + # @returns [Boolean] Returns true if the list is empty. + def empty? + @size == 0 + end + + # def validate!(node = nil) + # previous = self + # current = @tail + # found = node.equal?(self) + + # while true + # break if current.equal?(self) + + # if current.head != previous + # raise "Invalid previous linked list node!" + # end + + # if current.is_a?(List) and !current.equal?(self) + # raise "Invalid list in list node!" + # end + + # if node + # found ||= current.equal?(node) + # end + + # previous = current + # current = current.tail + # end + + # if node and !found + # raise "Node not found in list!" + # end + # end + + # Iterate over each node in the linked list. It is generally safe to remove the current node, any previous node or any future node during iteration. + # + # @yields {|node| ...} Yields each node in the list. + # @returns [List] Returns self. + def each(&block) + return to_enum unless block_given? + + Iterator.each(self, &block) + + return self + end + + # Determine whether the given node is included in the list. + # + # @parameter needle [Node] The node to search for. + # @returns [Boolean] Returns true if the node is in the list. + def include?(needle) + self.each do |item| + return true if needle.equal?(item) + end + + return false + end + + # @returns [Node] Returns the first node in the list, if it is not empty. + def first + # validate! + + current = @tail + + while !current.equal?(self) + if current.is_a?(Iterator) + current = current.tail + else + return current + end + end + + return nil + end + + # @returns [Node] Returns the last node in the list, if it is not empty. + def last + # validate! + + current = @head + + while !current.equal?(self) + if current.is_a?(Iterator) + current = current.head + else + return current + end + end + + return nil + end + + # Shift the first node off the list, if it is not empty. + def shift + if node = first + remove!(node) + end + end + + # A linked list Node. + class Node + attr_accessor :head + attr_accessor :tail + + alias inspect to_s + end + + class Iterator < Node + def initialize(list) + @list = list + + # Insert the iterator as the first item in the list: + @tail = list.tail + @tail.head = self + list.tail = self + @head = list + end + + def remove! + @head.tail = @tail + @tail.head = @head + @head = nil + @tail = nil + @list = nil + end + + def move_next + # Move to the next item (which could be an iterator or the end): + @tail.head = @head + @head.tail = @tail + @head = @tail + @tail = @tail.tail + @head.tail = self + @tail.head = self + end + + def move_current + while true + # Are we at the end of the list? + if @tail.equal?(@list) + return nil + end + + if @tail.is_a?(Iterator) + move_next + else + return @tail + end + end + end + + def each + while current = move_current + yield current + + if current.equal?(@tail) + move_next + end + end + end + + def self.each(list, &block) + return if list.empty? + + iterator = Iterator.new(list) + + iterator.each(&block) + ensure + iterator&.remove! + end + end + + private_constant :Iterator + end +end diff --git a/bin/gems/async-2.23.0/lib/async/node.rb b/bin/gems/async-2.23.0/lib/async/node.rb new file mode 100644 index 00000000..e4042508 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/node.rb @@ -0,0 +1,324 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2017, by Kent Gruber. +# Copyright, 2022, by Shannon Skipper. + +require "fiber/annotation" + +require_relative "list" + +module Async + # A list of children tasks. + class Children < List + # Create an empty list of children tasks. + def initialize + super + @transient_count = 0 + end + + # Some children may be marked as transient. Transient children do not prevent the parent from finishing. + # @returns [Boolean] Whether the node has transient children. + def transients? + @transient_count > 0 + end + + # Whether all children are considered finished. Ignores transient children. + def finished? + @size == @transient_count + end + + # Whether the children is empty, preserved for compatibility. + def nil? + empty? + end + + # Adjust the number of transient children, assuming it has changed. + # + # Despite being public, this is not intended to be called directly. It is used internally by {Node#transient=}. + # + # @parameter transient [Boolean] Whether to increment or decrement the transient count. + def adjust_transient_count(transient) + if transient + @transient_count += 1 + else + @transient_count -= 1 + end + end + + private + + def added(node) + if node.transient? + @transient_count += 1 + end + + return super + end + + def removed(node) + if node.transient? + @transient_count -= 1 + end + + return super + end + end + + # A node in a tree, used for implementing the task hierarchy. + class Node + # Create a new node in the tree. + # @parameter parent [Node | Nil] This node will attach to the given parent. + def initialize(parent = nil, annotation: nil, transient: false) + @parent = nil + @children = nil + + @annotation = annotation + @object_name = nil + + @transient = transient + + @head = nil + @tail = nil + + if parent + parent.add_child(self) + end + end + + # @returns [Node] The root node in the hierarchy. + def root + @parent&.root || self + end + + # @private + attr_accessor :head + + # @private + attr_accessor :tail + + # @attribute [Node] The parent node. + attr :parent + + # @attribute [Children | Nil] Optional list of children. + attr :children + + # @attribute [String | Nil] A useful identifier for the current node. + attr :annotation + + # Whether this node has any children. + # @returns [Boolean] + def children? + @children && !@children.empty? + end + + # Represents whether a node is transient. Transient nodes are not considered + # when determining if a node is finished. This is useful for tasks which are + # internal to an object rather than explicit user concurrency. For example, + # a child task which is pruning a connection pool is transient, because it + # is not directly related to the parent task, and should not prevent the + # parent task from finishing. + def transient? + @transient + end + + # Change the transient state of the node. + # + # A transient node is not considered when determining if a node is finished, and propagates up if the parent is consumed. + # + # @parameter value [Boolean] Whether the node is transient. + def transient=(value) + if @transient != value + @transient = value + + @parent&.children&.adjust_transient_count(value) + end + end + + # Annotate the node with a description. + # + # @parameter annotation [String] The description to annotate the node with. + def annotate(annotation) + if block_given? + begin + current_annotation = @annotation + @annotation = annotation + return yield + ensure + @annotation = current_annotation + end + else + @annotation = annotation + end + end + + # A description of the node, including the annotation and object name. + # + # @returns [String] The description of the node. + def description + @object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}" + + if annotation = self.annotation + "#{@object_name} #{annotation}" + elsif line = self.backtrace(0, 1)&.first + "#{@object_name} #{line}" + else + @object_name + end + end + + # Provides a backtrace for nodes that have an active execution context. + # + # @returns [Array(Thread::Backtrace::Locations) | Nil] The backtrace of the node, if available. + def backtrace(*arguments) + nil + end + + # @returns [String] A description of the node. + def to_s + "\#<#{self.description}>" + end + + alias inspect to_s + + # Change the parent of this node. + # + # @parameter parent [Node | Nil] The parent to attach to, or nil to detach. + # @returns [Node] Itself. + def parent=(parent) + return if @parent.equal?(parent) + + if @parent + @parent.remove_child(self) + @parent = nil + end + + if parent + parent.add_child(self) + end + + return self + end + + protected def set_parent(parent) + @parent = parent + end + + protected def add_child(child) + @children ||= Children.new + @children.append(child) + child.set_parent(self) + end + + protected def remove_child(child) + @children.remove(child) + child.set_parent(nil) + end + + # Whether the node can be consumed (deleted) safely. By default, checks if the children set is empty. + # + # @returns [Boolean] + def finished? + @children.nil? || @children.finished? + end + + # If the node has a parent, and is {finished?}, then remove this node from + # the parent. + def consume + if parent = @parent and finished? + parent.remove_child(self) + + # If we have children, then we need to move them to our the parent if they are not finished: + if @children + while child = @children.shift + if child.finished? + child.set_parent(nil) + else + parent.add_child(child) + end + end + + @children = nil + end + + parent.consume + end + end + + # Traverse the task tree. + # + # @returns [Enumerator] An enumerator which will traverse the tree if no block is given. + # @yields {|node, level| ...} The node and the level relative to the given root. + def traverse(&block) + return enum_for(:traverse) unless block_given? + + self.traverse_recurse(&block) + end + + protected def traverse_recurse(level = 0, &block) + yield self, level + + @children&.each do |child| + child.traverse_recurse(level + 1, &block) + end + end + + # Immediately terminate all children tasks, including transient tasks. Internally invokes `stop(false)` on all children. This should be considered a last ditch effort and is used when closing the scheduler. + def terminate + # Attempt to stop the current task immediately, and all children: + stop(false) + + # If that doesn't work, take more serious action: + @children&.each do |child| + child.terminate + end + + return @children.nil? + end + + # Attempt to stop the current node immediately, including all non-transient children. Invokes {#stop_children} to stop all children. + # + # @parameter later [Boolean] Whether to defer stopping until some point in the future. + def stop(later = false) + # The implementation of this method may defer calling `stop_children`. + stop_children(later) + end + + # Attempt to stop all non-transient children. + private def stop_children(later = false) + @children&.each do |child| + child.stop(later) unless child.transient? + end + end + + # Whether the node has been stopped. + def stopped? + @children.nil? + end + + # Print the hierarchy of the task tree from the given node. + # + # @parameter out [IO] The output stream to write to. + # @parameter backtrace [Boolean] Whether to print the backtrace of each node. + def print_hierarchy(out = $stdout, backtrace: true) + self.traverse do |node, level| + indent = "\t" * level + + out.puts "#{indent}#{node}" + + print_backtrace(out, indent, node) if backtrace + end + end + + private + + def print_backtrace(out, indent, node) + if backtrace = node.backtrace + backtrace.each_with_index do |line, index| + out.puts "#{indent}#{index.zero? ? "→ " : " "}#{line}" + end + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/notification.rb b/bin/gems/async-2.23.0/lib/async/notification.rb new file mode 100644 index 00000000..f7ac780f --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/notification.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2024, by Samuel Williams. + +require_relative "condition" + +module Async + # A synchronization primitive, which allows fibers to wait until a notification is received. Does not block the task which signals the notification. Waiting tasks are resumed on next iteration of the reactor. + # @public Since *Async v1*. + class Notification < Condition + # Signal to a given task that it should resume operations. + def signal(value = nil, task: Task.current) + return if @waiting.empty? + + Fiber.scheduler.push Signal.new(self.exchange, value) + + return nil + end + + Signal = Struct.new(:waiting, :value) do + def alive? + true + end + + def transfer + waiting.each do |fiber| + fiber.transfer(value) if fiber.alive? + end + end + end + + private_constant :Signal + end +end diff --git a/bin/gems/async-2.23.0/lib/async/queue.rb b/bin/gems/async-2.23.0/lib/async/queue.rb new file mode 100644 index 00000000..429b5868 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/queue.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2024, by Samuel Williams. +# Copyright, 2019, by Ryan Musgrave. +# Copyright, 2020-2022, by Bruno Sutic. + +require_relative "notification" + +module Async + # A queue which allows items to be processed in order. + # + # It has a compatible interface with {Notification} and {Condition}, except that it's multi-value. + # + # @public Since *Async v1*. + class Queue + # Create a new queue. + # + # @parameter parent [Interface(:async) | Nil] The parent task to use for async operations. + # @parameter available [Notification] The notification to use for signaling when items are available. + def initialize(parent: nil, available: Notification.new) + @items = [] + @parent = parent + @available = available + end + + # @attribute [Array] The items in the queue. + attr :items + + # @returns [Integer] The number of items in the queue. + def size + @items.size + end + + # @returns [Boolean] Whether the queue is empty. + def empty? + @items.empty? + end + + # Add an item to the queue. + def push(item) + @items << item + + @available.signal unless self.empty? + end + + # Compatibility with {::Queue#push}. + def <<(item) + self.push(item) + end + + # Add multiple items to the queue. + def enqueue(*items) + @items.concat(items) + + @available.signal unless self.empty? + end + + # Remove and return the next item from the queue. + def dequeue + while @items.empty? + @available.wait + end + + @items.shift + end + + # Compatibility with {::Queue#pop}. + def pop + self.dequeue + end + + # Process each item in the queue. + # + # @asynchronous Executes the given block concurrently for each item. + # + # @parameter arguments [Array] The arguments to pass to the block. + # @parameter parent [Interface(:async) | Nil] The parent task to use for async operations. + # @parameter options [Hash] The options to pass to the task. + # @yields {|task| ...} When the system is idle, the block will be executed in a new task. + def async(parent: (@parent or Task.current), **options, &block) + while item = self.dequeue + parent.async(item, **options, &block) + end + end + + # Enumerate each item in the queue. + def each + while item = self.dequeue + yield item + end + end + + # Signal the queue with a value, the same as {#enqueue}. + def signal(value = nil) + self.enqueue(value) + end + + # Wait for an item to be available, the same as {#dequeue}. + def wait + self.dequeue + end + end + + # A queue which limits the number of items that can be enqueued. + # @public Since *Async v1*. + class LimitedQueue < Queue + # Create a new limited queue. + # + # @parameter limit [Integer] The maximum number of items that can be enqueued. + # @parameter full [Notification] The notification to use for signaling when the queue is full. + def initialize(limit = 1, full: Notification.new, **options) + super(**options) + + @limit = limit + @full = full + end + + # @attribute [Integer] The maximum number of items that can be enqueued. + attr :limit + + # @returns [Boolean] Whether trying to enqueue an item would block. + def limited? + @items.size >= @limit + end + + # Add an item to the queue. + # + # If the queue is full, this method will block until there is space available. + # + # @parameter item [Object] The item to add to the queue. + def push(item) + while limited? + @full.wait + end + + super + end + + # Add multiple items to the queue. + # + # If the queue is full, this method will block until there is space available. + # + # @parameter items [Array] The items to add to the queue. + def enqueue(*items) + while !items.empty? + while limited? + @full.wait + end + + available = @limit - @items.size + @items.concat(items.shift(available)) + + @available.signal unless self.empty? + end + end + + # Remove and return the next item from the queue. + # + # If the queue is empty, this method will block until an item is available. + # + # @returns [Object] The next item in the queue. + def dequeue + item = super + + @full.signal + + return item + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/reactor.rb b/bin/gems/async-2.23.0/lib/async/reactor.rb new file mode 100644 index 00000000..bab99827 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/reactor.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2017, by Kent Gruber. +# Copyright, 2018, by Sokolov Yura. + +require_relative "scheduler" + +module Async + # A wrapper around the the scheduler which binds it to the current thread automatically. + class Reactor < Scheduler + # @deprecated Replaced by {Kernel::Async}. + def self.run(...) + Async(...) + end + + # Initialize the reactor and assign it to the current Fiber scheduler. + def initialize(...) + super + + Fiber.set_scheduler(self) + end + + # Close the reactor and remove it from the current Fiber scheduler. + def scheduler_close + self.close + end + + public :sleep + end +end diff --git a/bin/gems/async-2.23.0/lib/async/scheduler.rb b/bin/gems/async-2.23.0/lib/async/scheduler.rb new file mode 100644 index 00000000..ccea68e7 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/scheduler.rb @@ -0,0 +1,582 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. +# Copyright, 2020, by Jun Jiang. +# Copyright, 2021, by Julien Portalier. + +require_relative "clock" +require_relative "task" +require_relative "worker_pool" + +require "io/event" + +require "console" +require "resolv" + +module Async + begin + require "fiber/profiler" + Profiler = Fiber::Profiler + rescue LoadError + # Fiber::Profiler is not available. + Profiler = nil + end + + # Handles scheduling of fibers. Implements the fiber scheduler interface. + class Scheduler < Node + WORKER_POOL = ENV.fetch("ASYNC_SCHEDULER_WORKER_POOL", nil).then do |value| + value == "true" ? true : nil + end + + # Raised when an operation is attempted on a closed scheduler. + class ClosedError < RuntimeError + # Create a new error. + # + # @parameter message [String] The error message. + def initialize(message = "Scheduler is closed!") + super + end + end + + # Whether the fiber scheduler is supported. + # @public Since *Async v1*. + def self.supported? + true + end + + # Create a new scheduler. + # + # @public Since *Async v1*. + # @parameter parent [Node | Nil] The parent node to use for task hierarchy. + # @parameter selector [IO::Event::Selector] The selector to use for event handling. + def initialize(parent = nil, selector: nil, profiler: Profiler&.default, worker_pool: WORKER_POOL) + super(parent) + + @selector = selector || ::IO::Event::Selector.new(Fiber.current) + @profiler = profiler + + @interrupted = false + + @blocked = 0 + + @busy_time = 0.0 + @idle_time = 0.0 + + @timers = ::IO::Event::Timers.new + if worker_pool == true + @worker_pool = WorkerPool.new + else + @worker_pool = worker_pool + end + + if @worker_pool + self.singleton_class.prepend(WorkerPool::BlockingOperationWait) + end + end + + # Compute the scheduler load according to the busy and idle times that are updated by the run loop. + # + # @returns [Float] The load of the scheduler. 0.0 means no load, 1.0 means fully loaded or over-loaded. + def load + total_time = @busy_time + @idle_time + + # If the total time is zero, then the load is zero: + return 0.0 if total_time.zero? + + # We normalize to a 1 second window: + if total_time > 1.0 + ratio = 1.0 / total_time + @busy_time *= ratio + @idle_time *= ratio + + # We don't need to divide here as we've already normalised it to a 1s window: + return @busy_time + else + return @busy_time / total_time + end + end + + # Invoked when the fiber scheduler is being closed. + # + # Executes the run loop until all tasks are finished, then closes the scheduler. + def scheduler_close(error = $!) + # If the execution context (thread) was handling an exception, we want to exit as quickly as possible: + unless error + self.run + end + ensure + self.close + end + + # Terminate all child tasks. + def terminate + # If that doesn't work, take more serious action: + @children&.each do |child| + child.terminate + end + + return @children.nil? + end + + # Terminate all child tasks and close the scheduler. + # @public Since *Async v1*. + def close + self.run_loop do + until self.terminate + self.run_once! + end + end + + Kernel.raise "Closing scheduler with blocked operations!" if @blocked > 0 + ensure + # We want `@selector = nil` to be a visible side effect from this point forward, specifically in `#interrupt` and `#unblock`. If the selector is closed, then we don't want to push any fibers to it. + selector = @selector + @selector = nil + + selector&.close + + worker_pool = @worker_pool + @worker_pool = nil + + worker_pool&.close + + consume + end + + # @returns [Boolean] Whether the scheduler has been closed. + # @public Since *Async v1*. + def closed? + @selector.nil? + end + + # @returns [String] A description of the scheduler. + def to_s + "\#<#{self.description} #{@children&.size || 0} children (#{stopped? ? 'stopped' : 'running'})>" + end + + # Interrupt the event loop and cause it to exit. + # @asynchronous May be called from any thread. + def interrupt + @interrupted = true + @selector&.wakeup + end + + # Transfer from the calling fiber to the event loop. + def transfer + @selector.transfer + end + + # Yield the current fiber and resume it on the next iteration of the event loop. + def yield + @selector.yield + end + + # Schedule a fiber (or equivalent object) to be resumed on the next loop through the reactor. + # @parameter fiber [Fiber | Object] The object to be resumed on the next iteration of the run-loop. + def push(fiber) + @selector.push(fiber) + end + + # Raise an exception on a specified fiber with the given arguments. + # + # This internally schedules the current fiber to be ready, before raising the exception, so that it will later resume execution. + # + # @parameter fiber [Fiber] The fiber to raise the exception on. + # @parameter *arguments [Array] The arguments to pass to the fiber. + def raise(...) + @selector.raise(...) + end + + # Resume execution of the specified fiber. + # + # @parameter fiber [Fiber] The fiber to resume. + # @parameter arguments [Array] The arguments to pass to the fiber. + def resume(fiber, *arguments) + @selector.resume(fiber, *arguments) + end + + # Invoked when a fiber tries to perform a blocking operation which cannot continue. A corresponding call {unblock} must be performed to allow this fiber to continue. + # + # @public Since *Async v2*. + # @asynchronous May only be called on same thread as fiber scheduler. + # + # @parameter blocker [Object] The object that is blocking the fiber. + # @parameter timeout [Float | Nil] The maximum time to block, or if nil, indefinitely. + def block(blocker, timeout) + # $stderr.puts "block(#{blocker}, #{Fiber.current}, #{timeout})" + fiber = Fiber.current + + if timeout + timer = @timers.after(timeout) do + if fiber.alive? + fiber.transfer(false) + end + end + end + + begin + @blocked += 1 + @selector.transfer + ensure + @blocked -= 1 + end + ensure + timer&.cancel! + end + + # Unblock a fiber that was previously blocked. + # + # @public Since *Async v2* and *Ruby v3.1*. + # @asynchronous May be called from any thread. + # + # @parameter blocker [Object] The object that was blocking the fiber. + # @parameter fiber [Fiber] The fiber to unblock. + def unblock(blocker, fiber) + # $stderr.puts "unblock(#{blocker}, #{fiber})" + + # This operation is protected by the GVL: + if selector = @selector + selector.push(fiber) + selector.wakeup + end + end + + # Sleep for the specified duration. + # + # @public Since *Async v2* and *Ruby v3.1*. + # @asynchronous May be non-blocking. + # + # @parameter duration [Numeric | Nil] The time in seconds to sleep, or if nil, indefinitely. + def kernel_sleep(duration = nil) + if duration + self.block(nil, duration) + else + self.transfer + end + end + + # Resolve the address of the given hostname. + # + # @public Since *Async v2*. + # @asynchronous May be non-blocking. + # + # @parameter hostname [String] The hostname to resolve. + def address_resolve(hostname) + # On some platforms, hostnames may contain a device-specific suffix (e.g. %en0). We need to strip this before resolving. + # See for more details. + hostname = hostname.split("%", 2).first + ::Resolv.getaddresses(hostname) + end + + if IO.method_defined?(:timeout) + private def get_timeout(io) + io.timeout + end + else + private def get_timeout(io) + nil + end + end + + # Wait for the specified IO to become ready for the specified events. + # + # @public Since *Async v2*. + # @asynchronous May be non-blocking. + # + # @parameter io [IO] The IO object to wait on. + # @parameter events [Integer] The events to wait for, e.g. `IO::READABLE`, `IO::WRITABLE`, etc. + # @parameter timeout [Float | Nil] The maximum time to wait, or if nil, indefinitely. + def io_wait(io, events, timeout = nil) + fiber = Fiber.current + + if timeout + # If an explicit timeout is specified, we expect that the user will handle it themselves: + timer = @timers.after(timeout) do + fiber.transfer + end + elsif timeout = get_timeout(io) + # Otherwise, if we default to the io's timeout, we raise an exception: + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become ready!") + end + end + + return @selector.io_wait(fiber, io, events) + ensure + timer&.cancel! + end + + if ::IO::Event::Support.buffer? + # Read from the specified IO into the buffer. + # + # @public Since *Async v2* and Ruby with `IO::Buffer` support. + # @asynchronous May be non-blocking. + # + # @parameter io [IO] The IO object to read from. + # @parameter buffer [IO::Buffer] The buffer to read into. + # @parameter length [Integer] The minimum number of bytes to read. + # @parameter offset [Integer] The offset within the buffer to read into. + def io_read(io, buffer, length, offset = 0) + fiber = Fiber.current + + if timeout = get_timeout(io) + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become readable!") + end + end + + @selector.io_read(fiber, io, buffer, length, offset) + ensure + timer&.cancel! + end + + if RUBY_ENGINE != "ruby" || RUBY_VERSION >= "3.3.1" + # Write the specified buffer to the IO. + # + # @public Since *Async v2* and *Ruby v3.3.1* with `IO::Buffer` support. + # @asynchronous May be non-blocking. + # + # @parameter io [IO] The IO object to write to. + # @parameter buffer [IO::Buffer] The buffer to write from. + # @parameter length [Integer] The minimum number of bytes to write. + # @parameter offset [Integer] The offset within the buffer to write from. + def io_write(io, buffer, length, offset = 0) + fiber = Fiber.current + + if timeout = get_timeout(io) + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become writable!") + end + end + + @selector.io_write(fiber, io, buffer, length, offset) + ensure + timer&.cancel! + end + end + end + + # Wait for the specified process ID to exit. + # + # @public Since *Async v2*. + # @asynchronous May be non-blocking. + # + # @parameter pid [Integer] The process ID to wait for. + # @parameter flags [Integer] A bit-mask of flags suitable for `Process::Status.wait`. + # @returns [Process::Status] A process status instance. + # @asynchronous May be non-blocking.. + def process_wait(pid, flags) + return @selector.process_wait(Fiber.current, pid, flags) + end + + # Run one iteration of the event loop. + # + # When terminating the event loop, we already know we are finished. So we don't need to check the task tree. This is a logical requirement because `run_once` ignores transient tasks. For example, a single top level transient task is not enough to keep the reactor running, but during termination we must still process it in order to terminate child tasks. + # + # @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite. + # @returns [Boolean] Whether there is more work to do. + private def run_once!(timeout = nil) + start_time = Async::Clock.now + + interval = @timers.wait_interval + + # If there is no interval to wait (thus no timers), and no tasks, we could be done: + if interval.nil? + # Allow the user to specify a maximum interval if we would otherwise be sleeping indefinitely: + interval = timeout + elsif interval < 0 + # We have timers ready to fire, don't sleep in the selctor: + interval = 0 + elsif timeout and interval > timeout + interval = timeout + end + + begin + @selector.select(interval) + rescue Errno::EINTR + # Ignore. + end + + @timers.fire + + # Compute load: + end_time = Async::Clock.now + total_duration = end_time - start_time + idle_duration = @selector.idle_duration + busy_duration = total_duration - idle_duration + + @busy_time += busy_duration + @idle_time += idle_duration + + # The reactor still has work to do: + return true + end + + # Run one iteration of the event loop. + # + # @public Since *Async v1*. + # @asynchronous Must be invoked from blocking (root) fiber. + # + # @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite. + # @returns [Boolean] Whether there is more work to do. + def run_once(timeout = nil) + Kernel.raise "Running scheduler on non-blocking fiber!" unless Fiber.blocking? + + if self.finished? + self.stop + end + + # If we are finished, we stop the task tree and exit: + if @children.nil? + return false + end + + return run_once!(timeout) + end + + # Checks and clears the interrupted state of the scheduler. + # + # @returns [Boolean] Whether the reactor has been interrupted. + private def interrupted? + if @interrupted + @interrupted = false + return true + end + + if Thread.pending_interrupt? + return true + end + + return false + end + + # Stop all children, including transient children. + # + # @public Since *Async v1*. + def stop + @children&.each do |child| + child.stop + end + end + + private def run_loop(&block) + interrupt = nil + + begin + # In theory, we could use Exception here to be a little bit safer, but we've only shown the case for SignalException to be a problem, so let's not over-engineer this. + Thread.handle_interrupt(::SignalException => :never) do + until self.interrupted? + # If we are finished, we need to exit: + break unless yield + end + end + rescue Interrupt => interrupt + # If an interrupt did occur during an iteration of the event loop, we need to handle it. More specifically, `self.stop` is not safe to interrupt without potentially corrupting the task tree. + Thread.handle_interrupt(::SignalException => :never) do + Console.debug(self) do |buffer| + buffer.puts "Scheduler interrupted: #{interrupt.inspect}" + self.print_hierarchy(buffer) + end + + self.stop + end + + retry + end + + # If the event loop was interrupted, and we finished exiting normally (due to the interrupt), we need to re-raise the interrupt so that the caller can handle it too. + if interrupt + Kernel.raise(interrupt) + end + end + + # Run the reactor until all tasks are finished. Proxies arguments to {#async} immediately before entering the loop, if a block is provided. + # + # Forwards all parameters to {#async} if a block is given. + # + # @public Since *Async v1*. + # + # @yields {|task| ...} The top level task, if a block is given. + # @returns [Task] The initial task that was scheduled into the reactor. + def run(...) + Kernel.raise ClosedError if @selector.nil? + + begin + @profiler&.start + + initial_task = self.async(...) if block_given? + + self.run_loop do + run_once + end + + return initial_task + ensure + @profiler&.stop + end + end + + # Start an asynchronous task within the specified reactor. The task will be executed until the first blocking call, at which point it will yield and and this method will return. + # + # @public Since *Async v1*. + # @asynchronous May context switch immediately to new task. + # @deprecated Use {#run} or {Task#async} instead. + # + # @yields {|task| ...} Executed within the task. + # @returns [Task] The task that was scheduled into the reactor. + def async(*arguments, **options, &block) + # warn "Async::Scheduler#async is deprecated. Use `run` or `Task#async` instead.", uplevel: 1, category: :deprecated + + Kernel.raise ClosedError if @selector.nil? + + task = Task.new(Task.current? || self, **options, &block) + + task.run(*arguments) + + return task + end + + def fiber(...) + return async(...).fiber + end + + # Invoke the block, but after the specified timeout, raise {TimeoutError} in any currenly blocking operation. If the block runs to completion before the timeout occurs or there are no non-blocking operations after the timeout expires, the code will complete without any exception. + # + # @public Since *Async v1*. + # @asynchronous May raise an exception at any interruption point (e.g. blocking operations). + # + # @parameter duration [Numeric] The time in seconds, in which the task should complete. + # @parameter exception [Class] The exception class to raise. + # @parameter message [String] The message to pass to the exception. + # @yields {|duration| ...} The block to execute with a timeout. + def with_timeout(duration, exception = TimeoutError, message = "execution expired", &block) + fiber = Fiber.current + + timer = @timers.after(duration) do + if fiber.alive? + fiber.raise(exception, message) + end + end + + yield timer + ensure + timer&.cancel! + end + + # Invoke the block, but after the specified timeout, raise the specified exception with the given message. If the block runs to completion before the timeout occurs or there are no non-blocking operations after the timeout expires, the code will complete without any exception. + # + # @public Since *Async v1* and *Ruby v3.1*. May be invoked from `Timeout.timeout`. + # @asynchronous May raise an exception at any interruption point (e.g. blocking operations). + # + # @parameter duration [Numeric] The time in seconds, in which the task should complete. + # @parameter exception [Class] The exception class to raise. + # @parameter message [String] The message to pass to the exception. + # @yields {|duration| ...} The block to execute with a timeout. + def timeout_after(duration, exception, message, &block) + with_timeout(duration, exception, message) do |timer| + yield duration + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/semaphore.md b/bin/gems/async-2.23.0/lib/async/semaphore.md new file mode 100644 index 00000000..2524693d --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/semaphore.md @@ -0,0 +1,41 @@ +A synchronization primitive, which limits access to a given resource, such as a limited number of database connections, open files, or network connections. + +## Example + +~~~ ruby +require 'async' +require 'async/semaphore' +require 'net/http' + +Sync do + # Only allow two concurrent tasks at a time: + semaphore = Async::Semaphore.new(2) + + # Generate an array of 10 numbers: + terms = ['ruby', 'python', 'go', 'java', 'c++'] + + # Search for the terms: + terms.each do |term| + semaphore.async do |task| + Console.info("Searching for #{term}...") + response = Net::HTTP.get(URI "https://www.google.com/search?q=#{term}") + Console.info("Got response #{response.size} bytes.") + end + end +end +~~~ + +### Output + +~~~ +0.0s info: Searching for ruby... [ec=0x3c] [pid=50523] +0.04s info: Searching for python... [ec=0x21c] [pid=50523] +1.7s info: Got response 182435 bytes. [ec=0x3c] [pid=50523] +1.71s info: Searching for go... [ec=0x834] [pid=50523] +3.0s info: Got response 204854 bytes. [ec=0x21c] [pid=50523] +3.0s info: Searching for java... [ec=0xf64] [pid=50523] +4.32s info: Got response 103235 bytes. [ec=0x834] [pid=50523] +4.32s info: Searching for c++... [ec=0x12d4] [pid=50523] +4.65s info: Got response 109697 bytes. [ec=0xf64] [pid=50523] +6.64s info: Got response 87249 bytes. [ec=0x12d4] [pid=50523] +~~~ diff --git a/bin/gems/async-2.23.0/lib/async/semaphore.rb b/bin/gems/async-2.23.0/lib/async/semaphore.rb new file mode 100644 index 00000000..cf307ab8 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/semaphore.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2024, by Samuel Williams. + +require_relative "list" + +module Async + # A synchronization primitive, which limits access to a given resource. + # @public Since *Async v1*. + class Semaphore + # @parameter limit [Integer] The maximum number of times the semaphore can be acquired before it blocks. + # @parameter parent [Task | Semaphore | Nil] The parent for holding any children tasks. + def initialize(limit = 1, parent: nil) + @count = 0 + @limit = limit + @waiting = List.new + + @parent = parent + end + + # The current number of tasks that have acquired the semaphore. + attr :count + + # The maximum number of tasks that can acquire the semaphore. + attr :limit + + # The tasks waiting on this semaphore. + attr :waiting + + # Allow setting the limit. This is useful for cases where the semaphore is used to limit the number of concurrent tasks, but the number of tasks is not known in advance or needs to be modified. + # + # On increasing the limit, some tasks may be immediately resumed. On decreasing the limit, some tasks may execute until the count is < than the limit. + # + # @parameter limit [Integer] The new limit. + def limit= limit + difference = limit - @limit + @limit = limit + + # We can't suspend + if difference > 0 + difference.times do + break unless node = @waiting.first + + node.resume + end + end + end + + # Is the semaphore currently acquired? + def empty? + @count.zero? + end + + # Whether trying to acquire this semaphore would block. + def blocking? + @count >= @limit + end + + # Run an async task. Will wait until the semaphore is ready until spawning and running the task. + def async(*arguments, parent: (@parent or Task.current), **options) + wait + + parent.async(**options) do |task| + @count += 1 + + begin + yield task, *arguments + ensure + self.release + end + end + end + + # Acquire the semaphore, block if we are at the limit. + # If no block is provided, you must call release manually. + # @yields {...} When the semaphore can be acquired. + # @returns The result of the block if invoked. + def acquire + wait + + @count += 1 + + return unless block_given? + + begin + return yield + ensure + self.release + end + end + + # Release the semaphore. Must match up with a corresponding call to `acquire`. Will release waiting fibers in FIFO order. + def release + @count -= 1 + + while (@limit - @count) > 0 and node = @waiting.first + node.resume + end + end + + private + + class FiberNode < List::Node + def initialize(fiber) + @fiber = fiber + end + + def resume + if @fiber.alive? + Fiber.scheduler.resume(@fiber) + end + end + end + + private_constant :FiberNode + + # Wait until the semaphore becomes available. + def wait + return unless blocking? + + @waiting.stack(FiberNode.new(Fiber.current)) do + Fiber.scheduler.transfer while blocking? + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/task.md b/bin/gems/async-2.23.0/lib/async/task.md new file mode 100644 index 00000000..43893725 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/task.md @@ -0,0 +1,30 @@ +A sequence of instructions, defined by a block, which is executed sequentially and managed by the scheduler. A task can be in one of the following states: `initialized`, `running`, `completed`, `failed`, `cancelled` or `stopped`. + +```mermaid +stateDiagram-v2 +[*] --> Initialized +Initialized --> Running : Run + +Running --> Completed : Return Value +Running --> Failed : Exception + +Completed --> [*] +Failed --> [*] + +Running --> Stopped : Stop +Stopped --> [*] +Completed --> Stopped : Stop +Failed --> Stopped : Stop +Initialized --> Stopped : Stop +``` + +## Example + +```ruby +require 'async' + +# Create an asynchronous task that sleeps for 1 second: +Async do |task| + sleep(1) +end +``` diff --git a/bin/gems/async-2.23.0/lib/async/task.rb b/bin/gems/async-2.23.0/lib/async/task.rb new file mode 100644 index 00000000..e8162238 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/task.rb @@ -0,0 +1,459 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2017, by Kent Gruber. +# Copyright, 2017, by Devin Christensen. +# Copyright, 2020, by Patrik Wenger. +# Copyright, 2023, by Math Ieu. + +require "fiber" +require "console" + +require_relative "node" +require_relative "condition" + +Fiber.attr_accessor :async_task + +module Async + # Raised when a task is explicitly stopped. + class Stop < Exception + # Used to defer stopping the current task until later. + class Later + # Create a new stop later operation. + # + # @parameter task [Task] The task to stop later. + def initialize(task) + @task = task + end + + # @returns [Boolean] Whether the task is alive. + def alive? + true + end + + # Transfer control to the operation - this will stop the task. + def transfer + @task.stop + end + end + end + + # Raised if a timeout occurs on a specific Fiber. Handled gracefully by `Task`. + # @public Since *Async v1*. + class TimeoutError < StandardError + # Create a new timeout error. + # + # @parameter message [String] The error message. + def initialize(message = "execution expired") + super + end + end + + # @public Since *Async v1*. + class Task < Node + # Raised when a child task is created within a task that has finished execution. + class FinishedError < RuntimeError + # Create a new finished error. + # + # @parameter message [String] The error message. + def initialize(message = "Cannot create child task within a task that has finished execution!") + super + end + end + + # @deprecated With no replacement. + def self.yield + Fiber.scheduler.transfer + end + + # Run the given block of code in a task, asynchronously, in the given scheduler. + def self.run(scheduler, *arguments, **options, &block) + self.new(scheduler, **options, &block).tap do |task| + task.run(*arguments) + end + end + + # Create a new task. + # @parameter reactor [Reactor] the reactor this task will run within. + # @parameter parent [Task] the parent task. + def initialize(parent = Task.current?, finished: nil, **options, &block) + super(parent, **options) + + # These instance variables are critical to the state of the task. + # In the initialized state, the @block should be set, but the @fiber should be nil. + # In the running state, the @fiber should be set. + # In a finished state, the @block should be nil, and the @fiber should be nil. + @block = block + @fiber = nil + + @status = :initialized + @result = nil + @finished = finished + + @defer_stop = nil + end + + # @returns [Scheduler] The scheduler for this task. + def reactor + self.root + end + + # @returns [Array(Thread::Backtrace::Location) | Nil] The backtrace of the task, if available. + def backtrace(*arguments) + @fiber&.backtrace(*arguments) + end + + # Annotate the task with a description. + # + # This will internally try to annotate the fiber if it is running, otherwise it will annotate the task itself. + # + # @parameter annotation [String] The description to annotate the task with. + def annotate(annotation, &block) + if @fiber + @fiber.annotate(annotation, &block) + else + super + end + end + + # @returns [Object] The annotation of the task. + def annotation + if @fiber + @fiber.annotation + else + super + end + end + + # @returns [String] A description of the task and it's current status. + def to_s + "\#<#{self.description} (#{@status})>" + end + + # @deprecated Prefer {Kernel#sleep} except when compatibility with `stable-v1` is required. + def sleep(duration = nil) + super + end + + # Execute the given block of code, raising the specified exception if it exceeds the given duration during a non-blocking operation. + def with_timeout(duration, exception = TimeoutError, message = "execution expired", &block) + Fiber.scheduler.with_timeout(duration, exception, message, &block) + end + + # Yield back to the reactor and allow other fibers to execute. + def yield + Fiber.scheduler.yield + end + + # @attribute [Fiber] The fiber which is being used for the execution of this task. + attr :fiber + + # @returns [Boolean] Whether the internal fiber is alive, i.e. it is actively executing. + def alive? + @fiber&.alive? + end + + # Whether we can remove this node from the reactor graph. + # @returns [Boolean] + def finished? + # If the block is nil and the fiber is nil, it means the task has finished execution. This becomes true after `finish!` is called. + super && @block.nil? && @fiber.nil? + end + + # @returns [Boolean] Whether the task is running. + def running? + @status == :running + end + + # @returns [Boolean] Whether the task failed with an exception. + def failed? + @status == :failed + end + + # @returns [Boolean] Whether the task has been stopped. + def stopped? + @status == :stopped + end + + # @returns [Boolean] Whether the task has completed execution and generated a result. + def completed? + @status == :completed + end + + # Alias for {#completed?}. + def complete? + self.completed? + end + + # @attribute [Symbol] The status of the execution of the task, one of `:initialized`, `:running`, `:complete`, `:stopped` or `:failed`. + attr :status + + # Begin the execution of the task. + # + # @raises [RuntimeError] If the task is already running. + def run(*arguments) + if @status == :initialized + @status = :running + + schedule do + @block.call(self, *arguments) + rescue => error + # I'm not completely happy with this overhead, but the alternative is to not log anything which makes debugging extremely difficult. Maybe we can introduce a debug wrapper which adds extra logging. + if @finished.nil? + warn(self, "Task may have ended with unhandled exception.", exception: error) + end + + raise + end + else + raise RuntimeError, "Task already running!" + end + end + + # Run an asynchronous task as a child of the current task. + # + # @public Since *Async v1*. + # @asynchronous May context switch immediately to the new task. + # + # @yields {|task| ...} in the context of the new task. + # @raises [FinishedError] If the task has already finished. + # @returns [Task] The child task. + def async(*arguments, **options, &block) + raise FinishedError if self.finished? + + task = Task.new(self, **options, &block) + + # When calling an async block, we deterministically execute it until the first blocking operation. We don't *have* to do this - we could schedule it for later execution, but it's useful to: + # + # - Fail at the point of the method call where possible. + # - Execute determinstically where possible. + # - Avoid scheduler overhead if no blocking operation is performed. + # + # There are different strategies (greedy vs non-greedy). We are currently using a greedy strategy. + task.run(*arguments) + + return task + end + + # Retrieve the current result of the task. Will cause the caller to wait until result is available. If the task resulted in an unhandled error (derived from `StandardError`), this will be raised. If the task was stopped, this will return `nil`. + # + # Conceptually speaking, waiting on a task should return a result, and if it throws an exception, this is certainly an exceptional case that should represent a failure in your program, not an expected outcome. In other words, you should not design your programs to expect exceptions from `#wait` as a normal flow control, and prefer to catch known exceptions within the task itself and return a result that captures the intention of the failure, e.g. a `TimeoutError` might simply return `nil` or `false` to indicate that the operation did not generate a valid result (as a timeout was an expected outcome of the internal operation in this case). + # + # @raises [RuntimeError] If the task's fiber is the current fiber. + # @returns [Object] The final expression/result of the task's block. + def wait + raise "Cannot wait on own fiber!" if Fiber.current.equal?(@fiber) + + # `finish!` will set both of these to nil before signaling the condition: + if @block || @fiber + @finished ||= Condition.new + @finished.wait + end + + if @status == :failed + raise @result + else + return @result + end + end + + # Access the result of the task without waiting. May be nil if the task is not completed. Does not raise exceptions. + attr :result + + # Stop the task and all of its children. + # + # If `later` is false, it means that `stop` has been invoked directly. When `later` is true, it means that `stop` is invoked by `stop_children` or some other indirect mechanism. In that case, if we encounter the "current" fiber, we can't stop it right away, as it's currently performing `#stop`. Stopping it immediately would interrupt the current stop traversal, so we need to schedule the stop to occur later. + # + # @parameter later [Boolean] Whether to stop the task later, or immediately. + def stop(later = false) + if self.stopped? + # If the task is already stopped, a `stop` state transition re-enters the same state which is a no-op. However, we will also attempt to stop any running children too. This can happen if the children did not stop correctly the first time around. Doing this should probably be considered a bug, but it's better to be safe than sorry. + return stopped! + end + + # If the fiber is alive, we need to stop it: + if @fiber&.alive? + # As the task is now exiting, we want to ensure the event loop continues to execute until the task finishes. + self.transient = false + + # If we are deferring stop... + if @defer_stop == false + # Don't stop now... but update the state so we know we need to stop later. + @defer_stop = true + return false + end + + if self.current? + # If the fiber is current, and later is `true`, we need to schedule the fiber to be stopped later, as it's currently invoking `stop`: + if later + # If the fiber is the current fiber and we want to stop it later, schedule it: + Fiber.scheduler.push(Stop::Later.new(self)) + else + # Otherwise, raise the exception directly: + raise Stop, "Stopping current task!" + end + else + # If the fiber is not curent, we can raise the exception directly: + begin + # There is a chance that this will stop the fiber that originally called stop. If that happens, the exception handling in `#stopped` will rescue the exception and re-raise it later. + Fiber.scheduler.raise(@fiber, Stop) + rescue FiberError => error + # In some cases, this can cause a FiberError (it might be resumed already), so we schedule it to be stopped later: + Fiber.scheduler.push(Stop::Later.new(self)) + end + end + else + # We are not running, but children might be, so transition directly into stopped state: + stop! + end + end + + # Defer the handling of stop. During the execution of the given block, if a stop is requested, it will be deferred until the block exits. This is useful for ensuring graceful shutdown of servers and other long-running tasks. You should wrap the response handling code in a defer_stop block to ensure that the task is stopped when the response is complete but not before. + # + # You can nest calls to defer_stop, but the stop will only be deferred until the outermost block exits. + # + # If stop is invoked a second time, it will be immediately executed. + # + # @yields {} The block of code to execute. + # @public Since *Async v1*. + def defer_stop + # Tri-state variable for controlling stop: + # - nil: defer_stop has not been called. + # - false: defer_stop has been called and we are not stopping. + # - true: defer_stop has been called and we will stop when exiting the block. + if @defer_stop.nil? + begin + # If we are not deferring stop already, we can defer it now: + @defer_stop = false + + yield + rescue Stop + # If we are exiting due to a stop, we shouldn't try to invoke stop again: + @defer_stop = nil + raise + ensure + defer_stop = @defer_stop + + # We need to ensure the state is reset before we exit the block: + @defer_stop = nil + + # If we were asked to stop, we should do so now: + if defer_stop + raise Stop, "Stopping current task (was deferred)!" + end + end + else + # If we are deferring stop already, entering it again is a no-op. + yield + end + end + + # @returns [Boolean] Whether stop has been deferred. + def stop_deferred? + @defer_stop + end + + # Lookup the {Task} for the current fiber. Raise `RuntimeError` if none is available. + # @returns [Task] + # @raises[RuntimeError] If task was not {set!} for the current fiber. + def self.current + Fiber.current.async_task or raise RuntimeError, "No async task available!" + end + + # Check if there is a task defined for the current fiber. + # @returns [Interface(:async) | Nil] + def self.current? + Fiber.current.async_task + end + + # @returns [Boolean] Whether this task is the currently executing task. + def current? + Fiber.current.equal?(@fiber) + end + + private + + def warn(...) + Console.warn(...) + end + + # Finish the current task, moving any children to the parent. + def finish! + # Don't hold references to the fiber or block after the task has finished: + @fiber = nil + @block = nil # If some how we went directly from initialized to finished. + + # Attempt to remove this node from the task tree. + consume + + # If this task was being used as a future, signal completion here: + if @finished + @finished.signal(self) + @finished = nil + end + end + + # State transition into the completed state. + def completed!(result) + @result = result + @status = :completed + end + + # State transition into the failed state. + def failed!(exception = false) + @result = exception + @status = :failed + end + + def stopped! + # Console.info(self, status:) {"Task #{self} was stopped with #{@children&.size.inspect} children!"} + @status = :stopped + + stopped = false + + begin + # We are not running, but children might be so we should stop them: + stop_children(true) + rescue Stop + stopped = true + # If we are stopping children, and one of them tries to stop the current task, we should ignore it. We will be stopped later. + retry + end + + if stopped + raise Stop, "Stopping current task!" + end + end + + def stop! + stopped! + + finish! + end + + def schedule(&block) + @fiber = Fiber.new(annotation: self.annotation) do + begin + completed!(yield) + rescue Stop + stopped! + rescue StandardError => error + failed!(error) + rescue Exception => exception + failed!(exception) + + # This is a critical failure, we should stop the reactor: + raise + ensure + # Console.info(self) {"Task ensure $! = #{$!} with #{@children&.size.inspect} children!"} + finish! + end + end + + @fiber.async_task = self + + self.root.resume(@fiber) + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/variable.rb b/bin/gems/async-2.23.0/lib/async/variable.rb new file mode 100644 index 00000000..9dffc550 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/variable.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +require_relative "condition" + +module Async + # A synchronization primitive that allows one task to wait for another task to resolve a value. + class Variable + # Create a new variable. + # + # @parameter condition [Condition] The condition to use for synchronization. + def initialize(condition = Condition.new) + @condition = condition + @value = nil + end + + # Resolve the value. + # + # Signals all waiting tasks. + # + # @parameter value [Object] The value to resolve. + def resolve(value = true) + @value = value + condition = @condition + @condition = nil + + self.freeze + + condition.signal(value) + end + + # Alias for {#resolve}. + def value=(value) + self.resolve(value) + end + + # Whether the value has been resolved. + # + # @returns [Boolean] Whether the value has been resolved. + def resolved? + @condition.nil? + end + + # Wait for the value to be resolved. + # + # @returns [Object] The resolved value. + def wait + @condition&.wait + return @value + end + + # Alias for {#wait}. + def value + self.wait + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/version.rb b/bin/gems/async-2.23.0/lib/async/version.rb new file mode 100644 index 00000000..13e9fc5e --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/version.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. + +module Async + VERSION = "2.23.0" +end diff --git a/bin/gems/async-2.23.0/lib/async/waiter.md b/bin/gems/async-2.23.0/lib/async/waiter.md new file mode 100644 index 00000000..3a1270cb --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/waiter.md @@ -0,0 +1,50 @@ +A synchronization primitive, which allows you to wait for tasks to complete in order of completion. This is useful for implementing a task pool, where you want to wait for the first task to complete, and then cancel the rest. + +If you try to wait for more things than you have added, you will deadlock. + +## Example + +~~~ ruby +require 'async' +require 'async/semaphore' +require 'async/barrier' +require 'async/waiter' + +Sync do + barrier = Async::Barrier.new + waiter = Async::Waiter.new(parent: barrier) + semaphore = Async::Semaphore.new(2, parent: waiter) + + # Sleep sort the numbers: + generator = Async do + while true + semaphore.async do |task| + number = rand(1..10) + sleep(number) + end + end + end + + numbers = [] + + 4.times do + # Wait for all the numbers to be sorted: + numbers << waiter.wait + end + + # Don't generate any more numbers: + generator.stop + + # Stop all tasks which we don't care about: + barrier.stop + + Console.info("Smallest", numbers) +end +~~~ + +### Output + +~~~ +0.0s info: Smallest + | [3, 3, 1, 2] +~~~ diff --git a/bin/gems/async-2.23.0/lib/async/waiter.rb b/bin/gems/async-2.23.0/lib/async/waiter.rb new file mode 100644 index 00000000..7f1608aa --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/waiter.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. +# Copyright, 2024, by Patrik Wenger. + +module Async + # A composable synchronization primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore} and/or {Barrier}. + class Waiter + # Create a waiter instance. + # + # @parameter parent [Interface(:async) | Nil] The parent task to use for asynchronous operations. + # @parameter finished [Async::Condition] The condition to signal when a task completes. + def initialize(parent: nil, finished: Async::Condition.new) + @finished = finished + @done = [] + + @parent = parent + end + + # Execute a child task and add it to the waiter. + # @asynchronous Executes the given block concurrently. + def async(parent: (@parent or Task.current), **options, &block) + parent.async(**options) do |task| + yield(task) + ensure + @done << task + @finished.signal + end + end + + # Wait for the first `count` tasks to complete. + # @parameter count [Integer | Nil] The number of tasks to wait for. + # @returns [Array(Async::Task)] If an integer is given, the tasks which have completed. + # @returns [Async::Task] Otherwise, the first task to complete. + def first(count = nil) + minimum = count || 1 + + while @done.size < minimum + @finished.wait + end + + return @done.shift(*count) + end + + # Wait for the first `count` tasks to complete. + # @parameter count [Integer | Nil] The number of tasks to wait for. + def wait(count = nil) + if count + first(count).map(&:wait) + else + first.wait + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/worker_pool.rb b/bin/gems/async-2.23.0/lib/async/worker_pool.rb new file mode 100644 index 00000000..36df724c --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/worker_pool.rb @@ -0,0 +1,182 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require "etc" + +module Async + # A simple work pool that offloads work to a background thread. + # + # @private + class WorkerPool + # Used to augment the scheduler to add support for blocking operations. + module BlockingOperationWait + # Wait for the given work to be executed. + # + # @public Since *Async v2.19* and *Ruby v3.4*. + # @asynchronous May be non-blocking. + # + # @parameter work [Proc] The work to execute on a background thread. + # @returns [Object] The result of the work. + def blocking_operation_wait(work) + @worker_pool.call(work) + end + end + + # Execute the given work in a background thread. + class Promise + # Create a new promise. + # + # @parameter work [Proc] The work to be done. + def initialize(work) + @work = work + @state = :pending + @value = nil + @guard = ::Mutex.new + @condition = ::ConditionVariable.new + @thread = nil + end + + # Execute the work and resolve the promise. + def call + work = nil + + @guard.synchronize do + @thread = ::Thread.current + + return unless work = @work + end + + resolve(work.call) + rescue Exception => error + reject(error) + end + + private def resolve(value) + @guard.synchronize do + @work = nil + @thread = nil + @value = value + @state = :resolved + @condition.broadcast + end + end + + private def reject(error) + @guard.synchronize do + @work = nil + @thread = nil + @value = error + @state = :failed + @condition.broadcast + end + end + + # Cancel the work and raise an exception in the background thread. + def cancel + return unless @work + + @guard.synchronize do + @work = nil + @state = :cancelled + @thread&.raise(Interrupt) + end + end + + # Wait for the work to be done. + # + # @returns [Object] The result of the work. + def wait + @guard.synchronize do + while @state == :pending + @condition.wait(@guard) + end + + if @state == :failed + raise @value + else + return @value + end + end + end + end + + # A background worker thread. + class Worker + # Create a new worker. + def initialize + @work = ::Thread::Queue.new + @thread = ::Thread.new(&method(:run)) + end + + # Execute work until the queue is closed. + def run + while work = @work.pop + work.call + end + end + + # Close the worker thread. + def close + if thread = @thread + @thread = nil + thread.kill + end + end + + # Call the work and notify the scheduler when it is done. + def call(work) + promise = Promise.new(work) + + @work.push(promise) + + begin + return promise.wait + ensure + promise.cancel + end + end + end + + # Create a new work pool. + # + # @parameter size [Integer] The number of threads to use. + def initialize(size: Etc.nprocessors) + @ready = ::Thread::Queue.new + + size.times do + @ready.push(Worker.new) + end + end + + # Close the work pool. Kills all outstanding work. + def close + if ready = @ready + @ready = nil + ready.close + + while worker = ready.pop + worker.close + end + end + end + + # Offload work to a thread. + # + # @parameter work [Proc] The work to be done. + def call(work) + if ready = @ready + worker = ready.pop + + begin + worker.call(work) + ensure + ready.push(worker) + end + else + raise RuntimeError, "No worker available!" + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/async/wrapper.rb b/bin/gems/async-2.23.0/lib/async/wrapper.rb new file mode 100644 index 00000000..8d6a4864 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/async/wrapper.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2017-2024, by Samuel Williams. +# Copyright, 2017, by Kent Gruber. + +warn "Async::Wrapper is deprecated and will be removed on 2025-03-31. Please use native interfaces instead.", uplevel: 1, category: :deprecated + +module Async + # Represents an asynchronous IO within a reactor. + # @deprecated With no replacement. Prefer native interfaces. + class Wrapper + # An exception that occurs when the asynchronous operation was cancelled. + class Cancelled < StandardError + end + + # @parameter io the native object to wrap. + # @parameter reactor [Reactor] the reactor that is managing this wrapper, or not specified, it's looked up by way of {Task.current}. + def initialize(io, reactor = nil) + @io = io + @reactor = reactor + + @timeout = nil + end + + attr_accessor :reactor + + # Dup the underlying IO. + def dup + self.class.new(@io.dup) + end + + # The underlying native `io`. + attr :io + + # Wait for the io to become readable. + def wait_readable(timeout = @timeout) + @io.to_io.wait_readable(timeout) or raise TimeoutError + end + + # Wait for the io to become writable. + def wait_priority(timeout = @timeout) + @io.to_io.wait_priority(timeout) or raise TimeoutError + end + + # Wait for the io to become writable. + def wait_writable(timeout = @timeout) + @io.to_io.wait_writable(timeout) or raise TimeoutError + end + + # Wait fo the io to become either readable or writable. + # @parameter duration [Float] timeout after the given duration if not `nil`. + def wait_any(timeout = @timeout) + @io.to_io.wait(::IO::READABLE|::IO::WRITABLE|::IO::PRIORITY, timeout) or raise TimeoutError + end + + # Close the underlying IO. + def close + @io.close + end + + # Whether the underlying IO is closed. + def closed? + @io.closed? + end + end +end diff --git a/bin/gems/async-2.23.0/lib/kernel/async.rb b/bin/gems/async-2.23.0/lib/kernel/async.rb new file mode 100644 index 00000000..46c41c96 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/kernel/async.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "../async/reactor" + +module Kernel + # Run the given block of code in a task, asynchronously, creating a reactor if necessary. + # + # The preferred method to invoke asynchronous behavior at the top level. + # + # - When invoked within an existing reactor task, it will run the given block + # asynchronously. Will return the task once it has been scheduled. + # - When invoked at the top level, will create and run a reactor, and invoke + # the block as an asynchronous task. Will block until the reactor finishes + # running. + # + # @yields {|task| ...} The block that will execute asynchronously. + # @parameter task [Async::Task] The task that is executing the given block. + # + # @public Since *Async v1*. + # @asynchronous May block until given block completes executing. + def Async(...) + if current = ::Async::Task.current? + return current.async(...) + elsif scheduler = Fiber.scheduler + ::Async::Task.run(scheduler, ...) + else + # This calls Fiber.set_scheduler(self): + reactor = ::Async::Reactor.new + + begin + return reactor.run(...) + ensure + Fiber.set_scheduler(nil) + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/kernel/sync.rb b/bin/gems/async-2.23.0/lib/kernel/sync.rb new file mode 100644 index 00000000..ee38fe44 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/kernel/sync.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2020, by Brian Morearty. +# Copyright, 2024, by Patrik Wenger. + +require_relative "../async/reactor" + +# Extensions to all Ruby objects. +module Kernel + # Run the given block of code synchronously, but within a reactor if not already in one. + # + # @yields {|task| ...} The block that will execute asynchronously. + # @parameter task [Async::Task] The task that is executing the given block. + # + # @public Since *Async v1*. + # @asynchronous Will block until given block completes executing. + def Sync(annotation: nil, &block) + if task = ::Async::Task.current? + if annotation + task.annotate(annotation) {yield task} + else + yield task + end + elsif scheduler = Fiber.scheduler + ::Async::Task.run(scheduler, &block).wait + else + # This calls Fiber.set_scheduler(self): + reactor = Async::Reactor.new + + begin + return reactor.run(annotation: annotation, finished: ::Async::Condition.new, &block).wait + ensure + Fiber.set_scheduler(nil) + end + end + end +end diff --git a/bin/gems/async-2.23.0/lib/metrics/provider/async.rb b/bin/gems/async-2.23.0/lib/metrics/provider/async.rb new file mode 100644 index 00000000..a4252d48 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/metrics/provider/async.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "async/task" diff --git a/bin/gems/async-2.23.0/lib/metrics/provider/async/task.rb b/bin/gems/async-2.23.0/lib/metrics/provider/async/task.rb new file mode 100644 index 00000000..29b3e8a7 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/metrics/provider/async/task.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "../../../async/task" +require "metrics/provider" + +Metrics::Provider(Async::Task) do + ASYNC_TASK_SCHEDULED = Metrics.metric("async.task.scheduled", :counter, description: "The number of tasks scheduled.") + ASYNC_TASK_FINISHED = Metrics.metric("async.task.finished", :counter, description: "The number of tasks finished.") + + def schedule(&block) + ASYNC_TASK_SCHEDULED.emit(1) + + super(&block) + ensure + ASYNC_TASK_FINISHED.emit(1) + end +end diff --git a/bin/gems/async-2.23.0/lib/traces/provider/async.rb b/bin/gems/async-2.23.0/lib/traces/provider/async.rb new file mode 100644 index 00000000..ba4de707 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/traces/provider/async.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "async/task" +require_relative "async/barrier" diff --git a/bin/gems/async-2.23.0/lib/traces/provider/async/barrier.rb b/bin/gems/async-2.23.0/lib/traces/provider/async/barrier.rb new file mode 100644 index 00000000..ffa6721a --- /dev/null +++ b/bin/gems/async-2.23.0/lib/traces/provider/async/barrier.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022, by Samuel Williams. + +require_relative "../../../async/barrier" +require "traces/provider" + +Traces::Provider(Async::Barrier) do + def wait + attributes = { + "size" => self.size + } + + Traces.trace("async.barrier.wait", attributes: attributes) {super} + end +end diff --git a/bin/gems/async-2.23.0/lib/traces/provider/async/task.rb b/bin/gems/async-2.23.0/lib/traces/provider/async/task.rb new file mode 100644 index 00000000..c7c5fd55 --- /dev/null +++ b/bin/gems/async-2.23.0/lib/traces/provider/async/task.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022, by Samuel Williams. + +require_relative "../../../async/task" +require "traces/provider" + +Traces::Provider(Async::Task) do + def schedule(&block) + # If we are not actively tracing anything, then we can skip this: + unless Traces.active? + return super(&block) + end + + unless self.transient? + trace_context = Traces.trace_context + end + + attributes = { + # We use the instance variable as it corresponds to the user-provided block. + "block" => @block, + "transient" => self.transient?, + } + + # Run the trace in the context of the child task: + super do + Traces.trace_context = trace_context + + if annotation = self.annotation + attributes["annotation"] = annotation + end + + Traces.trace("async.task", attributes: attributes) do + # Yes, this is correct, we already called super above: + yield + end + end + end +end diff --git a/bin/gems/async-2.23.0/license.md b/bin/gems/async-2.23.0/license.md new file mode 100644 index 00000000..7e747023 --- /dev/null +++ b/bin/gems/async-2.23.0/license.md @@ -0,0 +1,47 @@ +# MIT License + +Copyright, 2017-2024, by Samuel Williams. +Copyright, 2017, by Kent Gruber. +Copyright, 2017, by Devin Christensen. +Copyright, 2018, by Sokolov Yura. +Copyright, 2018, by Jiang Jinyang. +Copyright, 2019, by Jeremy Jung. +Copyright, 2019, by Ryan Musgrave. +Copyright, 2020-2023, by Olle Jonsson. +Copyright, 2020, by Salim Semaoune. +Copyright, 2020, by Brian Morearty. +Copyright, 2020, by Stefan Wrobel. +Copyright, 2020-2024, by Patrik Wenger. +Copyright, 2020, by Ken Muryoi. +Copyright, 2020, by Jun Jiang. +Copyright, 2020-2022, by Bruno Sutic. +Copyright, 2021, by Julien Portalier. +Copyright, 2022, by Shannon Skipper. +Copyright, 2022, by Masafumi Okura. +Copyright, 2022, by Trevor Turk. +Copyright, 2022, by Masayuki Yamamoto. +Copyright, 2023, by Leon Löchner. +Copyright, 2023, by Colin Kelley. +Copyright, 2023, by Math Ieu. +Copyright, 2023, by Emil Tin. +Copyright, 2023, by Gert Goet. +Copyright, 2024, by Dimitar Peychinov. +Copyright, 2024, by Jamie McCarthy. + +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/bin/gems/async-2.23.0/readme.md b/bin/gems/async-2.23.0/readme.md new file mode 100644 index 00000000..aab76423 --- /dev/null +++ b/bin/gems/async-2.23.0/readme.md @@ -0,0 +1,94 @@ +# ![Async](assets/logo.webp) + +Async is a composable asynchronous I/O framework for Ruby based on [io-event](https://github.com/socketry/io-event). + +> "Lately I've been looking into `async`, as one of my projects – +> [tus-ruby-server](https://github.com/janko/tus-ruby-server) – would really benefit from non-blocking I/O. It's really +> beautifully designed." *– [janko](https://github.com/janko)* + +[![Development Status](https://github.com/socketry/async/workflows/Test/badge.svg)](https://github.com/socketry/async/actions?workflow=Test) +[](https://api.gitsponsors.com/api/badge/link?p=U4gCxvzG7eUksiJSe0MSlPHWWhBYryqj6i48tx5L7/r/2NgkAToKb6dEm31bAftU3H+7BVwk3VhUBtE4GHqHJTPfWPR6xo2BQVoT15rFAGAsLFgdT2kKopIfCGV/QDOm7BrkodS2//R7NUMksAdaCQ==) + +## Features + + - Scalable event-driven I/O for Ruby. Thousands of clients per process\! + - Light weight fiber-based concurrency. No need for callbacks\! + - Multi-thread/process containers for parallelism. + - Growing eco-system of event-driven components. + +## Usage + +Please see the [project documentation](https://socketry.github.io/async/) for more details. + + - [Getting Started](https://socketry.github.io/async/guides/getting-started/index) - This guide shows how to add async to your project and run code asynchronously. + + - [Asynchronous Tasks](https://socketry.github.io/async/guides/asynchronous-tasks/index) - This guide explains how asynchronous tasks work and how to use them. + + - [Scheduler](https://socketry.github.io/async/guides/scheduler/index) - This guide gives an overview of how the scheduler is implemented. + + - [Compatibility](https://socketry.github.io/async/guides/compatibility/index) - This guide gives an overview of the compatibility of Async with Ruby and other frameworks. + + - [Best Practices](https://socketry.github.io/async/guides/best-practices/index) - This guide gives an overview of best practices for using Async. + + - [Debugging](https://socketry.github.io/async/guides/debugging/index) - This guide explains how to debug issues with programs that use Async. + +## Releases + +Please see the [project releases](https://socketry.github.io/async/releases/index) for all releases. + +### v2.23.0 + + - Rename `ASYNC_SCHEDULER_DEFAULT_WORKER_POOL` to `ASYNC_SCHEDULER_WORKER_POOL`. + - [Fiber Stall Profiler](https://socketry.github.io/async/releases/index#fiber-stall-profiler) + +### v2.21.1 + + - [Worker Pool](https://socketry.github.io/async/releases/index#worker-pool) + +### v2.20.0 + + - [Traces and Metrics Providers](https://socketry.github.io/async/releases/index#traces-and-metrics-providers) + +### v2.19.0 + + - [Async::Scheduler Debugging](https://socketry.github.io/async/releases/index#async::scheduler-debugging) + - [Console Shims](https://socketry.github.io/async/releases/index#console-shims) + +### v2.18.0 + + - Add support for `Sync(annotation:)`, so that you can annotate the block with a description of what it does, even if it doesn't create a new task. + +### v2.17.0 + + - Introduce `Async::Queue#push` and `Async::Queue#pop` for compatibility with `::Queue`. + +### v2.16.0 + + - [Better Handling of Async and Sync in Nested Fibers](https://socketry.github.io/async/releases/index#better-handling-of-async-and-sync-in-nested-fibers) + +## See Also + + - [async-http](https://github.com/socketry/async-http) — Asynchronous HTTP client/server. + - [async-websocket](https://github.com/socketry/async-websocket) — Asynchronous client and server websockets. + - [async-dns](https://github.com/socketry/async-dns) — Asynchronous DNS resolver and server. + - [falcon](https://github.com/socketry/falcon) — A rack compatible server built on top of `async-http`. + - [rubydns](https://github.com/ioquatix/rubydns) — An easy to use Ruby DNS server. + - [slack-ruby-bot](https://github.com/slack-ruby/slack-ruby-bot) — A client for making slack bots. + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +### Developer Certificate of Origin + +In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. + +### Community Guidelines + +This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers. diff --git a/bin/gems/async-2.23.0/releases.md b/bin/gems/async-2.23.0/releases.md new file mode 100644 index 00000000..2d40c6de --- /dev/null +++ b/bin/gems/async-2.23.0/releases.md @@ -0,0 +1,121 @@ +# Releases + +## v2.23.0 + + - Rename `ASYNC_SCHEDULER_DEFAULT_WORKER_POOL` to `ASYNC_SCHEDULER_WORKER_POOL`. + +### Fiber Stall Profiler + +After several iterations of experimentation, we are officially introducing the fiber stall profiler, implemented using the optional `fiber-profiler` gem. This gem is not included by default, but can be added to your project: + +``` bash +$ bundle add fiber-profiler +``` + +After adding the gem, you can enable the fiber stall profiler by setting the `FIBER_PROFILER_CAPTURE=true` environment variable: + +``` bash +$ FIBER_PROFILER_CAPTURE=true bundle exec ruby -rasync -e 'Async{Fiber.blocking{sleep 0.1}}' +Fiber stalled for 0.105 seconds +-e:1 in c-call '##blocking' (0.105s) + -e:1 in c-call 'Kernel#sleep' (0.105s) +Skipped 1 calls that were too short to be meaningful. +``` + +The fiber profiler will help you find problems with your code that cause the event loop to stall, which can be a common source of performance issues in asynchronous code. + +## v2.21.1 + +### Worker Pool + +Ruby 3.4 will feature a new fiber scheduler hook, `blocking_operation_wait` which allows the scheduler to redirect the work given to `rb_nogvl` to a worker pool. + +The Async scheduler optionally supports this feature using a worker pool, by using the following environment variable: + + ASYNC_SCHEDULER_WORKER_POOL=true + +This will cause the scheduler to use a worker pool for general blocking operations, rather than blocking the event loop. + +It should be noted that this isn't a net win, as the overhead of using a worker pool can be significant compared to the `rb_nogvl` work. As such, it is recommended to benchmark your application with and without the worker pool to determine if it is beneficial. + +## v2.20.0 + +### Traces and Metrics Providers + +Async now has [traces](https://github.com/socketry/traces) and [metrics](https://github.com/socketry/metrics) providers for various core classes. This allows you to emit traces and metrics to a suitable backend (including DataDog, New Relic, OpenTelemetry, etc.) for monitoring and debugging purposes. + +To take advantage of this feature, you will need to introduce your own `config/traces.rb` and `config/metrics.rb`. Async's own repository includes these files for testing purposes, you could copy them into your own project and modify them as needed. + +## v2.19.0 + +### Async::Scheduler Debugging + +Occasionally on issues, I encounter people asking for help and I need more information. Pressing Ctrl-C to exit a hung program is common, but it usually doesn't provide enough information to diagnose the problem. Setting the `CONSOLE_LEVEL=debug` environment variable will now print additional information about the scheduler when you interrupt it, including a backtrace of the current tasks. + + > CONSOLE_LEVEL=debug bundle exec ruby ./test.rb + ^C 0.0s debug: Async::Reactor [oid=0x974] [ec=0x988] [pid=9116] [2024-11-08 14:12:03 +1300] + | Scheduler interrupted: Interrupt + | # + | # + | → /Users/samuel/Developer/socketry/async/lib/async/scheduler.rb:185:in `transfer' + | /Users/samuel/Developer/socketry/async/lib/async/scheduler.rb:185:in `block' + | /Users/samuel/Developer/socketry/async/lib/async/scheduler.rb:207:in `kernel_sleep' + | /Users/samuel/Developer/socketry/async/test.rb:7:in `sleep' + | /Users/samuel/Developer/socketry/async/test.rb:7:in `sleepy' + | /Users/samuel/Developer/socketry/async/test.rb:12:in `block in ' + | /Users/samuel/Developer/socketry/async/lib/async/task.rb:197:in `block in run' + | /Users/samuel/Developer/socketry/async/lib/async/task.rb:420:in `block in schedule' + /Users/samuel/Developer/socketry/async/lib/async/scheduler.rb:317:in `select': Interrupt + ... (backtrace continues) ... + +This gives better visibility into what the scheduler is doing, and should help diagnose issues. + +### Console Shims + +The `async` gem depends on `console` gem, because my goal was to have good logging by default without thinking about it too much. However, some users prefer to avoid using the `console` gem for logging, so I've added an experimental set of shims which should allow you to bypass the `console` gem entirely. + +``` ruby +require 'async/console' +require 'async' + +Async{raise "Boom"} +``` + +Will now use `Kernel#warn` to print the task failure warning: + + # + Task may have ended with unhandled exception. + (irb):4:in `block in ': Boom (RuntimeError) + from /home/samuel/Developer/socketry/async/lib/async/task.rb:197:in `block in run' + from /home/samuel/Developer/socketry/async/lib/async/task.rb:420:in `block in schedule' + +## v2.18.0 + + - Add support for `Sync(annotation:)`, so that you can annotate the block with a description of what it does, even if it doesn't create a new task. + +## v2.17.0 + + - Introduce `Async::Queue#push` and `Async::Queue#pop` for compatibility with `::Queue`. + +## v2.16.0 + +### Better Handling of Async and Sync in Nested Fibers + +Interleaving bare fibers within `Async` and `Sync` blocks should not cause problems, but it presents a number of issues in the current implementation. Tracking the parent-child relationship between tasks, when they are interleaved with bare fibers, is difficult. The current implementation assumes that if there is no parent task, then it should create a new reactor. This is not always the case, as the parent task might not be visible due to nested Fibers. As a result, `Async` will create a new reactor, trying to stop the existing one, causing major internal consistency issues. + +I encountered this issue when trying to use `Async` within a streaming response in Rails. The `protocol-rack` [uses a normal fiber to wrap streaming responses](https://github.com/socketry/protocol-rack/blob/cb1ca44e9deadb9369bdb2ea03416556aa927c5c/lib/protocol/rack/body/streaming.rb#L24-L28), and if you try to use `Async` within it, it will create a new reactor, causing the server to lock up. + +Ideally, `Async` and `Sync` helpers should work when any `Fiber.scheduler` is defined. Right now, it's unrealistic to expect `Async::Task` to work in any scheduler, but at the very least, the following should work: + +``` ruby +reactor = Async::Reactor.new # internally calls Fiber.set_scheduler + +# This should run in the above reactor, rather than creating a new one. +Async do + puts "Hello World" +end +``` + +In order to do this, bare `Async` and `Sync` blocks should use `Fiber.scheduler` as a parent if possible. + +See for more details. diff --git a/bin/gems/base64-0.2.0/LICENSE.txt b/bin/gems/base64-0.2.0/LICENSE.txt new file mode 100644 index 00000000..a009caef --- /dev/null +++ b/bin/gems/base64-0.2.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/bin/gems/base64-0.2.0/README.md b/bin/gems/base64-0.2.0/README.md new file mode 100644 index 00000000..a29c58e7 --- /dev/null +++ b/bin/gems/base64-0.2.0/README.md @@ -0,0 +1,48 @@ +# Base64 + +The Base64 module provides for the encoding (`#encode64`, `#strict_encode64`, +`#urlsafe_encode64`) and decoding (`#decode64`, `#strict_decode64`, +`#urlsafe_decode64`) of binary data using a Base64 representation. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'base64' +``` + +And then execute: + + $ bundle install + +Or install it yourself as: + + $ gem install base64 + +## Usage + +A simple encoding and decoding. + +```ruby +require "base64" + +enc = Base64.encode64('Send reinforcements') + # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" +plain = Base64.decode64(enc) + # -> "Send reinforcements" +``` + +The purpose of using base64 to encode data is that it translates any +binary data into purely printable characters. + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/base64. + diff --git a/bin/gems/base64-0.2.0/lib/base64.rb b/bin/gems/base64-0.2.0/lib/base64.rb new file mode 100644 index 00000000..cd2ecc18 --- /dev/null +++ b/bin/gems/base64-0.2.0/lib/base64.rb @@ -0,0 +1,363 @@ +# frozen_string_literal: true +# +# \Module \Base64 provides methods for: +# +# - Encoding a binary string (containing non-ASCII characters) +# as a string of printable ASCII characters. +# - Decoding such an encoded string. +# +# \Base64 is commonly used in contexts where binary data +# is not allowed or supported: +# +# - Images in HTML or CSS files, or in URLs. +# - Email attachments. +# +# A \Base64-encoded string is about one-third larger that its source. +# See the {Wikipedia article}[https://en.wikipedia.org/wiki/Base64] +# for more information. +# +# This module provides three pairs of encode/decode methods. +# Your choices among these methods should depend on: +# +# - Which character set is to be used for encoding and decoding. +# - Whether "padding" is to be used. +# - Whether encoded strings are to contain newlines. +# +# Note: Examples on this page assume that the including program has executed: +# +# require 'base64' +# +# == Encoding Character Sets +# +# A \Base64-encoded string consists only of characters from a 64-character set: +# +# - ('A'..'Z'). +# - ('a'..'z'). +# - ('0'..'9'). +# - =, the 'padding' character. +# - Either: +# - %w[+ /]: +# {RFC-2045-compliant}[https://datatracker.ietf.org/doc/html/rfc2045]; +# _not_ safe for URLs. +# - %w[- _]: +# {RFC-4648-compliant}[https://datatracker.ietf.org/doc/html/rfc4648]; +# safe for URLs. +# +# If you are working with \Base64-encoded strings that will come from +# or be put into URLs, you should choose this encoder-decoder pair +# of RFC-4648-compliant methods: +# +# - Base64.urlsafe_encode64 and Base64.urlsafe_decode64. +# +# Otherwise, you may choose any of the pairs in this module, +# including the pair above, or the RFC-2045-compliant pairs: +# +# - Base64.encode64 and Base64.decode64. +# - Base64.strict_encode64 and Base64.strict_decode64. +# +# == Padding +# +# \Base64-encoding changes a triplet of input bytes +# into a quartet of output characters. +# +# Padding in Encode Methods +# +# Padding -- extending an encoded string with zero, one, or two trailing +# = characters -- is performed by methods Base64.encode64, +# Base64.strict_encode64, and, by default, Base64.urlsafe_encode64: +# +# Base64.encode64('s') # => "cw==\n" +# Base64.strict_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s', padding: false) # => "cw" +# +# When padding is performed, the encoded string is always of length 4n, +# where +n+ is a non-negative integer: +# +# - Input bytes of length 3n generate unpadded output characters +# of length 4n: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.strict_encode64('123') # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.strict_encode64('123456') # => "MDEyMzQ1" +# +# - Input bytes of length 3n+1 generate padded output characters +# of length 4(n+1), with two padding characters at the end: +# +# # n = 1: 4 bytes => 8 characters. +# Base64.strict_encode64('1234') # => "MDEyMw==" +# # n = 2: 7 bytes => 12 characters. +# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" +# +# - Input bytes of length 3n+2 generate padded output characters +# of length 4(n+1), with one padding character at the end: +# +# # n = 1: 5 bytes => 8 characters. +# Base64.strict_encode64('12345') # => "MDEyMzQ=" +# # n = 2: 8 bytes => 12 characters. +# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" +# +# When padding is suppressed, for a positive integer n: +# +# - Input bytes of length 3n generate unpadded output characters +# of length 4n: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.urlsafe_encode64('123', padding: false) # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1" +# +# - Input bytes of length 3n+1 generate unpadded output characters +# of length 4n+2, with two padding characters at the end: +# +# # n = 1: 4 bytes => 6 characters. +# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" +# # n = 2: 7 bytes => 10 characters. +# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" +# +# - Input bytes of length 3n+2 generate unpadded output characters +# of length 4n+3, with one padding character at the end: +# +# # n = 1: 5 bytes => 7 characters. +# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" +# # m = 2: 8 bytes => 11 characters. +# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" +# +# Padding in Decode Methods +# +# All of the \Base64 decode methods support (but do not require) padding. +# +# \Method Base64.decode64 does not check the size of the padding: +# +# Base64.decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc==") # => "01234567" +# +# \Method Base64.strict_decode64 strictly enforces padding size: +# +# Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError +# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError +# +# \Method Base64.urlsafe_decode64 allows padding in +str+, +# which if present, must be correct: +# see {Padding}[Base64.html#module-Base64-label-Padding], above: +# +# Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. +# +# == Newlines +# +# An encoded string returned by Base64.encode64 or Base64.urlsafe_encode64 +# has an embedded newline character +# after each 60-character sequence, and, if non-empty, at the end: +# +# # No newline if empty. +# encoded = Base64.encode64("\x00" * 0) +# encoded.index("\n") # => nil +# +# # Newline at end of short output. +# encoded = Base64.encode64("\x00" * 1) +# encoded.size # => 4 +# encoded.index("\n") # => 4 +# +# # Newline at end of longer output. +# encoded = Base64.encode64("\x00" * 45) +# encoded.size # => 60 +# encoded.index("\n") # => 60 +# +# # Newlines embedded and at end of still longer output. +# encoded = Base64.encode64("\x00" * 46) +# encoded.size # => 65 +# encoded.rindex("\n") # => 65 +# encoded.split("\n").map {|s| s.size } # => [60, 4] +# +# The string to be encoded may itself contain newlines, +# which are encoded as \Base64: +# +# # Base64.encode64("\n\n\n") # => "CgoK\n" +# s = "This is line 1\nThis is line 2\n" +# Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" +# +module Base64 + + VERSION = "0.2.0" + + module_function + + # Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters + # + or /; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; + # see {Padding}[Base64.html#module-Base64-label-Padding] above. + # + # Base64.encode64('*') # => "Kg==\n" + # + # The returned string ends with a newline character, and if sufficiently long + # will have one or more embedded newline characters; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.encode64('*') # => "Kg==\n" + # Base64.encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n" + # + # The string to be encoded may itself contain newlines, + # which will be encoded as ordinary \Base64: + # + # Base64.encode64("\n\n\n") # => "CgoK\n" + # s = "This is line 1\nThis is line 2\n" + # Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # + def encode64(bin) + [bin].pack("m") + end + + # Returns a string containing the decoding of an RFC-2045-compliant + # \Base64-encoded string +str+: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # Base64.decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-\Base64 characters in +str+ are ignored; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # these include newline characters and characters - and /: + # + # Base64.decode64("\x00\n-_") # => "" + # + # Padding in +str+ (even if incorrect) is ignored: + # + # Base64.decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc==") # => "01234567" + # + def decode64(str) + str.unpack1("m") + end + + # Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters + # + or /; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.strict_encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.strict_encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; + # see {Padding}[Base64.html#module-Base64-label-Padding] above. + # + # Base64.strict_encode64('*') # => "Kg==\n" + # + # The returned string will have no newline characters, regardless of its length; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.strict_encode64('*') # => "Kg==" + # Base64.strict_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + # The string to be encoded may itself contain newlines, + # which will be encoded as ordinary \Base64: + # + # Base64.strict_encode64("\n\n\n") # => "CgoK" + # s = "This is line 1\nThis is line 2\n" + # Base64.strict_encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # + def strict_encode64(bin) + [bin].pack("m0") + end + + # Returns a string containing the decoding of an RFC-2045-compliant + # \Base64-encoded string +str+: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-\Base64 characters in +str+ not allowed; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # these include newline characters and characters - and /: + # + # Base64.strict_decode64("\n") # Raises ArgumentError + # Base64.strict_decode64('-') # Raises ArgumentError + # Base64.strict_decode64('_') # Raises ArgumentError + # + # Padding in +str+, if present, must be correct: + # + # Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError + # Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError + # + def strict_decode64(str) + str.unpack1("m0") + end + + # Returns the RFC-4648-compliant \Base64-encoding of +bin+. + # + # Per RFC 4648, the returned string will not contain the URL-unsafe characters + # + or /, + # but instead may contain the URL-safe characters + # - and _; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.urlsafe_encode64("\xFB\xEF\xBE") # => "----" + # Base64.urlsafe_encode64("\xFF\xFF\xFF") # => "____" + # + # By default, the returned string may have padding; + # see {Padding}[Base64.html#module-Base64-label-Padding], above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # + # Optionally, you can suppress padding: + # + # Base64.urlsafe_encode64('*', padding: false) # => "Kg" + # + # The returned string will have no newline characters, regardless of its length; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # Base64.urlsafe_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + def urlsafe_encode64(bin, padding: true) + str = strict_encode64(bin) + str.chomp!("==") or str.chomp!("=") unless padding + str.tr!("+/", "-_") + str + end + + # Returns the decoding of an RFC-4648-compliant \Base64-encoded string +str+: + # + # +str+ may not contain non-Base64 characters; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.urlsafe_decode64('+') # Raises ArgumentError. + # Base64.urlsafe_decode64('/') # Raises ArgumentError. + # Base64.urlsafe_decode64("\n") # Raises ArgumentError. + # + # Padding in +str+, if present, must be correct: + # see {Padding}[Base64.html#module-Base64-label-Padding], above: + # + # Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. + # + def urlsafe_decode64(str) + # NOTE: RFC 4648 does say nothing about unpadded input, but says that + # "the excess pad characters MAY also be ignored", so it is inferred that + # unpadded input is also acceptable. + if !str.end_with?("=") && str.length % 4 != 0 + str = str.ljust((str.length + 3) & ~3, "=") + str.tr!("-_", "+/") + else + str = str.tr("-_", "+/") + end + strict_decode64(str) + end +end diff --git a/bin/gems/base64-0.3.0/BSDL b/bin/gems/base64-0.3.0/BSDL new file mode 100644 index 00000000..66d93598 --- /dev/null +++ b/bin/gems/base64-0.3.0/BSDL @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/bin/gems/base64-0.3.0/COPYING b/bin/gems/base64-0.3.0/COPYING new file mode 100644 index 00000000..48e5a96d --- /dev/null +++ b/bin/gems/base64-0.3.0/COPYING @@ -0,0 +1,56 @@ +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + +1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + +2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a. place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b. use the modified software only within your corporation or + organization. + + c. give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d. make other distribution arrangements with the author. + +3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a. distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b. accompany the distribution with the machine-readable source of + the software. + + c. give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d. make other distribution arrangements with the author. + +4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + +5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + +6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. diff --git a/bin/gems/base64-0.3.0/LEGAL b/bin/gems/base64-0.3.0/LEGAL new file mode 100644 index 00000000..f2d80147 --- /dev/null +++ b/bin/gems/base64-0.3.0/LEGAL @@ -0,0 +1,60 @@ +# -*- rdoc -*- + += LEGAL NOTICE INFORMATION +-------------------------- + +All the files in this distribution are covered under either the Ruby's +license (see the file COPYING) or public-domain except some files +mentioned below. + +== MIT License +>>> + 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. + +== Old-style BSD license +>>> + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + IMPORTANT NOTE:: + + From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change + paragraph 3 above is now null and void. diff --git a/bin/gems/base64-0.3.0/README.md b/bin/gems/base64-0.3.0/README.md new file mode 100644 index 00000000..a29c58e7 --- /dev/null +++ b/bin/gems/base64-0.3.0/README.md @@ -0,0 +1,48 @@ +# Base64 + +The Base64 module provides for the encoding (`#encode64`, `#strict_encode64`, +`#urlsafe_encode64`) and decoding (`#decode64`, `#strict_decode64`, +`#urlsafe_decode64`) of binary data using a Base64 representation. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'base64' +``` + +And then execute: + + $ bundle install + +Or install it yourself as: + + $ gem install base64 + +## Usage + +A simple encoding and decoding. + +```ruby +require "base64" + +enc = Base64.encode64('Send reinforcements') + # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" +plain = Base64.decode64(enc) + # -> "Send reinforcements" +``` + +The purpose of using base64 to encode data is that it translates any +binary data into purely printable characters. + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/base64. + diff --git a/bin/gems/base64-0.3.0/lib/base64.rb b/bin/gems/base64-0.3.0/lib/base64.rb new file mode 100644 index 00000000..8c0145d2 --- /dev/null +++ b/bin/gems/base64-0.3.0/lib/base64.rb @@ -0,0 +1,381 @@ +# frozen_string_literal: true +# +# \Module \Base64 provides methods for: +# +# - \Encoding a binary string (containing non-ASCII characters) +# as a string of printable ASCII characters. +# - Decoding such an encoded string. +# +# \Base64 is commonly used in contexts where binary data +# is not allowed or supported: +# +# - Images in HTML or CSS files, or in URLs. +# - Email attachments. +# +# A \Base64-encoded string is about one-third larger that its source. +# See the {Wikipedia article}[https://en.wikipedia.org/wiki/Base64] +# for more information. +# +# This module provides three pairs of encode/decode methods. +# Your choices among these methods should depend on: +# +# - Which character set is to be used for encoding and decoding. +# - Whether "padding" is to be used. +# - Whether encoded strings are to contain newlines. +# +# Note: Examples on this page assume that the including program has executed: +# +# require 'base64' +# +# == \Encoding Character Sets +# +# A \Base64-encoded string consists only of characters from a 64-character set: +# +# - ('A'..'Z'). +# - ('a'..'z'). +# - ('0'..'9'). +# - =, the 'padding' character. +# - Either: +# - %w[+ /]: +# {RFC-2045-compliant}[https://datatracker.ietf.org/doc/html/rfc2045]; +# _not_ safe for URLs. +# - %w[- _]: +# {RFC-4648-compliant}[https://datatracker.ietf.org/doc/html/rfc4648]; +# safe for URLs. +# +# If you are working with \Base64-encoded strings that will come from +# or be put into URLs, you should choose this encoder-decoder pair +# of RFC-4648-compliant methods: +# +# - Base64.urlsafe_encode64 and Base64.urlsafe_decode64. +# +# Otherwise, you may choose any of the pairs in this module, +# including the pair above, or the RFC-2045-compliant pairs: +# +# - Base64.encode64 and Base64.decode64. +# - Base64.strict_encode64 and Base64.strict_decode64. +# +# == Padding +# +# \Base64-encoding changes a triplet of input bytes +# into a quartet of output characters. +# +# Padding in Encode Methods +# +# Padding -- extending an encoded string with zero, one, or two trailing +# = characters -- is performed by methods Base64.encode64, +# Base64.strict_encode64, and, by default, Base64.urlsafe_encode64: +# +# Base64.encode64('s') # => "cw==\n" +# Base64.strict_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s', padding: false) # => "cw" +# +# When padding is performed, the encoded string is always of length 4n, +# where +n+ is a non-negative integer: +# +# - Input bytes of length 3n generate unpadded output characters +# of length 4n: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.strict_encode64('123') # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.strict_encode64('123456') # => "MDEyMzQ1" +# +# - Input bytes of length 3n+1 generate padded output characters +# of length 4(n+1), with two padding characters at the end: +# +# # n = 1: 4 bytes => 8 characters. +# Base64.strict_encode64('1234') # => "MDEyMw==" +# # n = 2: 7 bytes => 12 characters. +# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" +# +# - Input bytes of length 3n+2 generate padded output characters +# of length 4(n+1), with one padding character at the end: +# +# # n = 1: 5 bytes => 8 characters. +# Base64.strict_encode64('12345') # => "MDEyMzQ=" +# # n = 2: 8 bytes => 12 characters. +# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" +# +# When padding is suppressed, for a positive integer n: +# +# - Input bytes of length 3n generate unpadded output characters +# of length 4n: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.urlsafe_encode64('123', padding: false) # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1" +# +# - Input bytes of length 3n+1 generate unpadded output characters +# of length 4n+2, with two padding characters at the end: +# +# # n = 1: 4 bytes => 6 characters. +# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" +# # n = 2: 7 bytes => 10 characters. +# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" +# +# - Input bytes of length 3n+2 generate unpadded output characters +# of length 4n+3, with one padding character at the end: +# +# # n = 1: 5 bytes => 7 characters. +# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" +# # m = 2: 8 bytes => 11 characters. +# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" +# +# Padding in Decode Methods +# +# All of the \Base64 decode methods support (but do not require) padding. +# +# \Method Base64.decode64 does not check the size of the padding: +# +# Base64.decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc==") # => "01234567" +# +# \Method Base64.strict_decode64 strictly enforces padding size: +# +# Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError +# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError +# +# \Method Base64.urlsafe_decode64 allows padding in the encoded string, +# which if present, must be correct: +# see {Padding}[Base64.html#module-Base64-label-Padding], above: +# +# Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. +# +# == Newlines +# +# An encoded string returned by Base64.encode64 or Base64.urlsafe_encode64 +# has an embedded newline character +# after each 60-character sequence, and, if non-empty, at the end: +# +# # No newline if empty. +# encoded = Base64.encode64("\x00" * 0) +# encoded.index("\n") # => nil +# +# # Newline at end of short output. +# encoded = Base64.encode64("\x00" * 1) +# encoded.size # => 4 +# encoded.index("\n") # => 4 +# +# # Newline at end of longer output. +# encoded = Base64.encode64("\x00" * 45) +# encoded.size # => 60 +# encoded.index("\n") # => 60 +# +# # Newlines embedded and at end of still longer output. +# encoded = Base64.encode64("\x00" * 46) +# encoded.size # => 65 +# encoded.rindex("\n") # => 65 +# encoded.split("\n").map {|s| s.size } # => [60, 4] +# +# The string to be encoded may itself contain newlines, +# which are encoded as \Base64: +# +# # Base64.encode64("\n\n\n") # => "CgoK\n" +# s = "This is line 1\nThis is line 2\n" +# Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" +# +module Base64 + + VERSION = "0.3.0" + + module_function + + # :call-seq: + # Base64.encode64(string) -> encoded_string + # + # Returns a string containing the RFC-2045-compliant \Base64-encoding of +string+. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters + # + or /; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; + # see {Padding}[Base64.html#module-Base64-label-Padding] above. + # + # Base64.encode64('*') # => "Kg==\n" + # + # The returned string ends with a newline character, and if sufficiently long + # will have one or more embedded newline characters; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.encode64('*') # => "Kg==\n" + # Base64.encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n" + # + # The string to be encoded may itself contain newlines, + # which will be encoded as ordinary \Base64: + # + # Base64.encode64("\n\n\n") # => "CgoK\n" + # s = "This is line 1\nThis is line 2\n" + # Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # + def encode64(bin) + [bin].pack("m") + end + + # :call-seq: + # Base64.decode(encoded_string) -> decoded_string + # + # Returns a string containing the decoding of an RFC-2045-compliant + # \Base64-encoded string +encoded_string+: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # Base64.decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-\Base64 characters in +encoded_string+ are ignored; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # these include newline characters and characters - and /: + # + # Base64.decode64("\x00\n-_") # => "" + # + # Padding in +encoded_string+ (even if incorrect) is ignored: + # + # Base64.decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc==") # => "01234567" + # + def decode64(str) + str.unpack1("m") + end + + # :call-seq: + # Base64.strict_encode64(string) -> encoded_string + # + # Returns a string containing the RFC-2045-compliant \Base64-encoding of +string+. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters + # + or /; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.strict_encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.strict_encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; + # see {Padding}[Base64.html#module-Base64-label-Padding] above. + # + # Base64.strict_encode64('*') # => "Kg==\n" + # + # The returned string will have no newline characters, regardless of its length; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.strict_encode64('*') # => "Kg==" + # Base64.strict_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + # The string to be encoded may itself contain newlines, + # which will be encoded as ordinary \Base64: + # + # Base64.strict_encode64("\n\n\n") # => "CgoK" + # s = "This is line 1\nThis is line 2\n" + # Base64.strict_encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # + def strict_encode64(bin) + [bin].pack("m0") + end + + # :call-seq: + # Base64.strict_decode64(encoded_string) -> decoded_string + # + # Returns a string containing the decoding of an RFC-2045-compliant + # \Base64-encoded string +encoded_string+: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-\Base64 characters in +encoded_string+ are not allowed; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # these include newline characters and characters - and /: + # + # Base64.strict_decode64("\n") # Raises ArgumentError + # Base64.strict_decode64('-') # Raises ArgumentError + # Base64.strict_decode64('_') # Raises ArgumentError + # + # Padding in +encoded_string+, if present, must be correct: + # + # Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError + # Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError + # + def strict_decode64(str) + str.unpack1("m0") + end + + # :call-seq: + # Base64.urlsafe_encode64(string) -> encoded_string + # + # Returns the RFC-4648-compliant \Base64-encoding of +string+. + # + # Per RFC 4648, the returned string will not contain the URL-unsafe characters + # + or /, + # but instead may contain the URL-safe characters + # - and _; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.urlsafe_encode64("\xFB\xEF\xBE") # => "----" + # Base64.urlsafe_encode64("\xFF\xFF\xFF") # => "____" + # + # By default, the returned string may have padding; + # see {Padding}[Base64.html#module-Base64-label-Padding], above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # + # Optionally, you can suppress padding: + # + # Base64.urlsafe_encode64('*', padding: false) # => "Kg" + # + # The returned string will have no newline characters, regardless of its length; + # see {Newlines}[Base64.html#module-Base64-label-Newlines] above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # Base64.urlsafe_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + def urlsafe_encode64(bin, padding: true) + str = strict_encode64(bin) + str.chomp!("==") or str.chomp!("=") unless padding + str.tr!("+/", "-_") + str + end + + # :call-seq: + # Base64.urlsafe_decode64(encoded_string) -> decoded_string + # + # Returns the decoding of an RFC-4648-compliant \Base64-encoded string +encoded_string+: + # + # +encoded_string+ may not contain non-Base64 characters; + # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # + # Base64.urlsafe_decode64('+') # Raises ArgumentError. + # Base64.urlsafe_decode64('/') # Raises ArgumentError. + # Base64.urlsafe_decode64("\n") # Raises ArgumentError. + # + # Padding in +encoded_string+, if present, must be correct: + # see {Padding}[Base64.html#module-Base64-label-Padding], above: + # + # Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. + # + def urlsafe_decode64(str) + # NOTE: RFC 4648 does say nothing about unpadded input, but says that + # "the excess pad characters MAY also be ignored", so it is inferred that + # unpadded input is also acceptable. + if !str.end_with?("=") && str.length % 4 != 0 + str = str.ljust((str.length + 3) & ~3, "=") + str.tr!("-_", "+/") + else + str = str.tr("-_", "+/") + end + strict_decode64(str) + end +end diff --git a/bin/gems/base64-0.3.0/sig/base64.rbs b/bin/gems/base64-0.3.0/sig/base64.rbs new file mode 100644 index 00000000..147e874c --- /dev/null +++ b/bin/gems/base64-0.3.0/sig/base64.rbs @@ -0,0 +1,355 @@ +# +# Module Base64 provides methods for: +# +# * Encoding a binary string (containing non-ASCII characters) as a string of +# printable ASCII characters. +# * Decoding such an encoded string. +# +# Base64 is commonly used in contexts where binary data is not allowed or +# supported: +# +# * Images in HTML or CSS files, or in URLs. +# * Email attachments. +# +# A Base64-encoded string is about one-third larger that its source. See the +# [Wikipedia article](https://en.wikipedia.org/wiki/Base64) for more +# information. +# +# This module provides three pairs of encode/decode methods. Your choices among +# these methods should depend on: +# +# * Which character set is to be used for encoding and decoding. +# * Whether "padding" is to be used. +# * Whether encoded strings are to contain newlines. +# +# Note: Examples on this page assume that the including program has executed: +# +# require 'base64' +# +# ## Encoding Character Sets +# +# A Base64-encoded string consists only of characters from a 64-character set: +# +# * `('A'..'Z')`. +# * `('a'..'z')`. +# * `('0'..'9')`. +# * `=`, the 'padding' character. +# * Either: +# * `%w[+ /]`: +# [RFC-2045-compliant](https://datatracker.ietf.org/doc/html/rfc2045); +# *not* safe for URLs. +# * `%w[- _]`: +# [RFC-4648-compliant](https://datatracker.ietf.org/doc/html/rfc4648); +# safe for URLs. +# +# If you are working with Base64-encoded strings that will come from or be put +# into URLs, you should choose this encoder-decoder pair of RFC-4648-compliant +# methods: +# +# * Base64.urlsafe_encode64 and Base64.urlsafe_decode64. +# +# Otherwise, you may choose any of the pairs in this module, including the pair +# above, or the RFC-2045-compliant pairs: +# +# * Base64.encode64 and Base64.decode64. +# * Base64.strict_encode64 and Base64.strict_decode64. +# +# ## Padding +# +# Base64-encoding changes a triplet of input bytes into a quartet of output +# characters. +# +# **Padding in Encode Methods** +# +# Padding -- extending an encoded string with zero, one, or two trailing `=` +# characters -- is performed by methods Base64.encode64, Base64.strict_encode64, +# and, by default, Base64.urlsafe_encode64: +# +# Base64.encode64('s') # => "cw==\n" +# Base64.strict_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s') # => "cw==" +# Base64.urlsafe_encode64('s', padding: false) # => "cw" +# +# When padding is performed, the encoded string is always of length *4n*, where +# `n` is a non-negative integer: +# +# * Input bytes of length *3n* generate unpadded output characters of length +# *4n*: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.strict_encode64('123') # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.strict_encode64('123456') # => "MDEyMzQ1" +# +# * Input bytes of length *3n+1* generate padded output characters of length +# *4(n+1)*, with two padding characters at the end: +# +# # n = 1: 4 bytes => 8 characters. +# Base64.strict_encode64('1234') # => "MDEyMw==" +# # n = 2: 7 bytes => 12 characters. +# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" +# +# * Input bytes of length *3n+2* generate padded output characters of length +# *4(n+1)*, with one padding character at the end: +# +# # n = 1: 5 bytes => 8 characters. +# Base64.strict_encode64('12345') # => "MDEyMzQ=" +# # n = 2: 8 bytes => 12 characters. +# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" +# +# When padding is suppressed, for a positive integer *n*: +# +# * Input bytes of length *3n* generate unpadded output characters of length +# *4n*: +# +# # n = 1: 3 bytes => 4 characters. +# Base64.urlsafe_encode64('123', padding: false) # => "MDEy" +# # n = 2: 6 bytes => 8 characters. +# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1" +# +# * Input bytes of length *3n+1* generate unpadded output characters of length +# *4n+2*, with two padding characters at the end: +# +# # n = 1: 4 bytes => 6 characters. +# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" +# # n = 2: 7 bytes => 10 characters. +# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" +# +# * Input bytes of length *3n+2* generate unpadded output characters of length +# *4n+3*, with one padding character at the end: +# +# # n = 1: 5 bytes => 7 characters. +# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" +# # m = 2: 8 bytes => 11 characters. +# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" +# +# **Padding in Decode Methods** +# +# All of the Base64 decode methods support (but do not require) padding. +# +# Method Base64.decode64 does not check the size of the padding: +# +# Base64.decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.decode64("MDEyMzQ1Njc==") # => "01234567" +# +# Method Base64.strict_decode64 strictly enforces padding size: +# +# Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError +# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError +# +# Method Base64.urlsafe_decode64 allows padding in `str`, which if present, must +# be correct: see [Padding](Base64.html#module-Base64-label-Padding), above: +# +# Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" +# Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. +# +# ## Newlines +# +# An encoded string returned by Base64.encode64 or Base64.urlsafe_encode64 has +# an embedded newline character after each 60-character sequence, and, if +# non-empty, at the end: +# +# # No newline if empty. +# encoded = Base64.encode64("\x00" * 0) +# encoded.index("\n") # => nil +# +# # Newline at end of short output. +# encoded = Base64.encode64("\x00" * 1) +# encoded.size # => 4 +# encoded.index("\n") # => 4 +# +# # Newline at end of longer output. +# encoded = Base64.encode64("\x00" * 45) +# encoded.size # => 60 +# encoded.index("\n") # => 60 +# +# # Newlines embedded and at end of still longer output. +# encoded = Base64.encode64("\x00" * 46) +# encoded.size # => 65 +# encoded.rindex("\n") # => 65 +# encoded.split("\n").map {|s| s.size } # => [60, 4] +# +# The string to be encoded may itself contain newlines, which are encoded as +# Base64: +# +# # Base64.encode64("\n\n\n") # => "CgoK\n" +# s = "This is line 1\nThis is line 2\n" +# Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" +# +module Base64 + # + # Returns a string containing the decoding of an RFC-2045-compliant + # Base64-encoded string `str`: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # Base64.decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-Base64 characters in `str` are ignored; see [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: these + # include newline characters and characters `-` and `/`: + # + # Base64.decode64("\x00\n-_") # => "" + # + # Padding in `str` (even if incorrect) is ignored: + # + # Base64.decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.decode64("MDEyMzQ1Njc==") # => "01234567" + # + def self?.decode64: (String str) -> String + + # + # Returns a string containing the RFC-2045-compliant Base64-encoding of `bin`. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters `+` or + # `/`; see [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: + # + # Base64.encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; see + # [Padding](Base64.html#module-Base64-label-Padding) above. + # + # Base64.encode64('*') # => "Kg==\n" + # + # The returned string ends with a newline character, and if sufficiently long + # will have one or more embedded newline characters; see + # [Newlines](Base64.html#module-Base64-label-Newlines) above: + # + # Base64.encode64('*') # => "Kg==\n" + # Base64.encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n" + # + # The string to be encoded may itself contain newlines, which will be encoded as + # ordinary Base64: + # + # Base64.encode64("\n\n\n") # => "CgoK\n" + # s = "This is line 1\nThis is line 2\n" + # Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n" + # + def self?.encode64: (String bin) -> String + + # + # Returns a string containing the decoding of an RFC-2045-compliant + # Base64-encoded string `str`: + # + # s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n" + # + # Non-Base64 characters in `str` not allowed; see [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: these + # include newline characters and characters `-` and `/`: + # + # Base64.strict_decode64("\n") # Raises ArgumentError + # Base64.strict_decode64('-') # Raises ArgumentError + # Base64.strict_decode64('_') # Raises ArgumentError + # + # Padding in `str`, if present, must be correct: + # + # Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError + # Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError + # + def self?.strict_decode64: (String str) -> String + + # + # Returns a string containing the RFC-2045-compliant Base64-encoding of `bin`. + # + # Per RFC 2045, the returned string may contain the URL-unsafe characters `+` or + # `/`; see [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: + # + # Base64.strict_encode64("\xFB\xEF\xBE") # => "++++\n" + # Base64.strict_encode64("\xFF\xFF\xFF") # => "////\n" + # + # The returned string may include padding; see + # [Padding](Base64.html#module-Base64-label-Padding) above. + # + # Base64.strict_encode64('*') # => "Kg==\n" + # + # The returned string will have no newline characters, regardless of its length; + # see [Newlines](Base64.html#module-Base64-label-Newlines) above: + # + # Base64.strict_encode64('*') # => "Kg==" + # Base64.strict_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + # The string to be encoded may itself contain newlines, which will be encoded as + # ordinary Base64: + # + # Base64.strict_encode64("\n\n\n") # => "CgoK" + # s = "This is line 1\nThis is line 2\n" + # Base64.strict_encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK" + # + def self?.strict_encode64: (String bin) -> String + + # + # Returns the decoding of an RFC-4648-compliant Base64-encoded string `str`: + # + # `str` may not contain non-Base64 characters; see [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: + # + # Base64.urlsafe_decode64('+') # Raises ArgumentError. + # Base64.urlsafe_decode64('/') # Raises ArgumentError. + # Base64.urlsafe_decode64("\n") # Raises ArgumentError. + # + # Padding in `str`, if present, must be correct: see + # [Padding](Base64.html#module-Base64-label-Padding), above: + # + # Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567" + # Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError. + # + def self?.urlsafe_decode64: (String str) -> String + + # + # Returns the RFC-4648-compliant Base64-encoding of `bin`. + # + # Per RFC 4648, the returned string will not contain the URL-unsafe characters + # `+` or `/`, but instead may contain the URL-safe characters `-` and `_`; see + # [Encoding Character + # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: + # + # Base64.urlsafe_encode64("\xFB\xEF\xBE") # => "----" + # Base64.urlsafe_encode64("\xFF\xFF\xFF") # => "____" + # + # By default, the returned string may have padding; see + # [Padding](Base64.html#module-Base64-label-Padding), above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # + # Optionally, you can suppress padding: + # + # Base64.urlsafe_encode64('*', padding: false) # => "Kg" + # + # The returned string will have no newline characters, regardless of its length; + # see [Newlines](Base64.html#module-Base64-label-Newlines) above: + # + # Base64.urlsafe_encode64('*') # => "Kg==" + # Base64.urlsafe_encode64('*' * 46) + # # => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg==" + # + def self?.urlsafe_encode64: (String bin, ?padding: boolish) -> String +end diff --git a/bin/gems/bigdecimal-3.1.9/LICENSE b/bin/gems/bigdecimal-3.1.9/LICENSE new file mode 100644 index 00000000..a1f19ff9 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/LICENSE @@ -0,0 +1,56 @@ +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. diff --git a/bin/gems/bigdecimal-3.1.9/bigdecimal.gemspec b/bin/gems/bigdecimal-3.1.9/bigdecimal.gemspec new file mode 100644 index 00000000..b6ef8fd9 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/bigdecimal.gemspec @@ -0,0 +1,57 @@ +# coding: utf-8 + +name = File.basename(__FILE__, '.*') +source_version = ["", "ext/#{name}/"].find do |dir| + begin + break File.foreach(File.join(__dir__, "#{dir}#{name}.c")) {|line| + break $1.sub("-", ".") if /^#define\s+#{name.upcase}_VERSION\s+"(.+)"/o =~ line + } + rescue Errno::ENOENT + end +end or raise "can't find #{name.upcase}_VERSION" + +Gem::Specification.new do |s| + s.name = name + s.version = source_version + s.authors = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"] + s.email = ["mrkn@mrkn.jp"] + + s.summary = "Arbitrary-precision decimal floating-point number library." + s.description = "This library provides arbitrary-precision decimal floating-point number class." + s.homepage = "https://github.com/ruby/bigdecimal" + s.licenses = ["Ruby", "BSD-2-Clause"] + + s.require_paths = %w[lib] + s.files = %w[ + LICENSE + bigdecimal.gemspec + lib/bigdecimal.rb + lib/bigdecimal/jacobian.rb + lib/bigdecimal/ludcmp.rb + lib/bigdecimal/math.rb + lib/bigdecimal/newton.rb + lib/bigdecimal/util.rb + sample/linear.rb + sample/nlsolve.rb + sample/pi.rb + ] + if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby' + s.platform = 'java' + else + s.extensions = %w[ext/bigdecimal/extconf.rb] + s.files += %w[ + ext/bigdecimal/bigdecimal.c + ext/bigdecimal/bigdecimal.h + ext/bigdecimal/bits.h + ext/bigdecimal/feature.h + ext/bigdecimal/missing.c + ext/bigdecimal/missing.h + ext/bigdecimal/missing/dtoa.c + ext/bigdecimal/static_assert.h + ] + end + + s.required_ruby_version = Gem::Requirement.new(">= 2.5.0") + + s.metadata["changelog_uri"] = s.homepage + "/blob/master/CHANGES.md" +end diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/Makefile b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/Makefile new file mode 100644 index 00000000..b4ae762a --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/Makefile @@ -0,0 +1,270 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = . +topdir = /usr/include/ruby-3.2.0 +hdrdir = $(topdir) +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR)/etc +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ +LIBRUBY = $(LIBRUBY_SO) +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = -fPIC +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = +CPPFLAGS = -DHAVE_BUILTIN___BUILTIN_CLZ -DHAVE_BUILTIN___BUILTIN_CLZL -DHAVE_BUILTIN___BUILTIN_CLZLL -DHAVE_FLOAT_H -DHAVE_MATH_H -DHAVE_STDBOOL_H -DHAVE_STDLIB_H -DHAVE_X86INTRIN_H -DHAVE_LABS -DHAVE_LLABS -DHAVE_FINITE -DHAVE_RUBY_ATOMIC_H -DHAVE_RUBY_INTERNAL_HAS_BUILTIN_H -DHAVE_RUBY_INTERNAL_STATIC_ASSERT_H -DHAVE_RB_RATIONAL_NUM -DHAVE_RB_RATIONAL_DEN -DHAVE_RB_COMPLEX_REAL -DHAVE_RB_COMPLEX_IMAG -DHAVE_RB_OPTS_EXCEPTION_P -DHAVE_RB_CATEGORY_WARN -DHAVE_CONST_RB_WARN_CATEGORY_DEPRECATED -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CC) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-linux-gnu-gcc-ar +EXEEXT = + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 +RUBYW_INSTALL_NAME = +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x86_64-linux-gnu +sitearch = $(arch) +ruby_version = 3.2.0 +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 +RUBY = $(ruby) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h + +RM = rm -f +RM_RF = rm -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) +DEFFILE = + +CLEANFILES = mkmf.log +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc +ORIG_SRCS = bigdecimal.c missing.c +SRCS = $(ORIG_SRCS) +OBJS = bigdecimal.o missing.o +HDRS = $(srcdir)/bigdecimal.h $(srcdir)/bits.h $(srcdir)/feature.h $(srcdir)/missing.h $(srcdir)/static_assert.h +LOCAL_HDRS = +TARGET = bigdecimal +TARGET_NAME = bigdecimal +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = $(OBJS) *.bak +TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time +BIGDECIMAL_RB = $(srcdir)/../../lib/bigdecimal.rb + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP) + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + -$(Q)$(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TARGET_SO_DIR_TIMESTAMP): + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(OBJS) Makefile + $(ECHO) linking shared-object $(DLLIB) + -$(Q)$(RM) $(@) + $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) + + + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.c b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.c new file mode 100644 index 00000000..a707295e --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.c @@ -0,0 +1,7790 @@ +/* + * + * Ruby BigDecimal(Variable decimal precision) extension library. + * + * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp) + * + */ + +/* #define BIGDECIMAL_DEBUG 1 */ + +#include "bigdecimal.h" +#include "ruby/util.h" + +#ifndef BIGDECIMAL_DEBUG +# undef NDEBUG +# define NDEBUG +#endif +#include + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_IEEEFP_H +#include +#endif + +#include "bits.h" +#include "static_assert.h" + +#define BIGDECIMAL_VERSION "3.1.9" + +/* #define ENABLE_NUMERIC_STRING */ + +#define SIGNED_VALUE_MAX INTPTR_MAX +#define SIGNED_VALUE_MIN INTPTR_MIN +#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX) + +VALUE rb_cBigDecimal; +VALUE rb_mBigMath; + +static ID id_BigDecimal_exception_mode; +static ID id_BigDecimal_rounding_mode; +static ID id_BigDecimal_precision_limit; + +static ID id_up; +static ID id_down; +static ID id_truncate; +static ID id_half_up; +static ID id_default; +static ID id_half_down; +static ID id_half_even; +static ID id_banker; +static ID id_ceiling; +static ID id_ceil; +static ID id_floor; +static ID id_to_r; +static ID id_eq; +static ID id_half; + +#define RBD_NUM_ROUNDING_MODES 11 + +static struct { + ID id; + uint8_t mode; +} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES]; + +/* MACRO's to guard objects from GC by keeping them in stack */ +#ifdef RBIMPL_ATTR_MAYBE_UNUSED +#define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0 +#else +#define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0 +#endif +#define PUSH(x) (vStack[iStack++] = (VALUE)(x)) +#define SAVE(p) PUSH((p)->obj) +#define GUARD_OBJ(p,y) ((p)=(y), SAVE(p)) + +#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES +#define BASE BIGDECIMAL_BASE + +#define HALF_BASE (BASE/2) +#define BASE1 (BASE/10) + +#define LOG10_2 0.3010299956639812 + +#ifndef RRATIONAL_ZERO_P +# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \ + FIX2LONG(rb_rational_num(x)) == 0) +#endif + +#ifndef RRATIONAL_NEGATIVE_P +# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0))) +#endif + +#ifndef DECIMAL_SIZE_OF_BITS +#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999) +/* an approximation of ceil(n * log10(2)), upto 65536 at least */ +#endif + +#ifdef PRIsVALUE +# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj) +# define RB_OBJ_STRING(obj) (obj) +#else +# define PRIsVALUE "s" +# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj) +# define RB_OBJ_STRING(obj) StringValueCStr(obj) +#endif + +#ifndef MAYBE_UNUSED +# define MAYBE_UNUSED(x) x +#endif + +#define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0) +#define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0) + +/* + * ================== Memory allocation ============================ + */ + +#ifdef BIGDECIMAL_DEBUG +static size_t rbd_allocation_count = 0; /* Memory allocation counter */ +static inline void +atomic_allocation_count_inc(void) +{ + RUBY_ATOMIC_SIZE_INC(rbd_allocation_count); +} +static inline void +atomic_allocation_count_dec_nounderflow(void) +{ + if (rbd_allocation_count == 0) return; + RUBY_ATOMIC_SIZE_DEC(rbd_allocation_count); +} +static void +check_allocation_count_nonzero(void) +{ + if (rbd_allocation_count != 0) return; + rb_bug("[bigdecimal][rbd_free_struct] Too many memory free calls"); +} +#else +# define atomic_allocation_count_inc() /* nothing */ +# define atomic_allocation_count_dec_nounderflow() /* nothing */ +# define check_allocation_count_nonzero() /* nothing */ +#endif /* BIGDECIMAL_DEBUG */ + +PUREFUNC(static inline size_t rbd_struct_size(size_t const)); + +static inline size_t +rbd_struct_size(size_t const internal_digits) +{ + size_t const frac_len = (internal_digits == 0) ? 1 : internal_digits; + return offsetof(Real, frac) + frac_len * sizeof(DECDIG); +} + +static inline Real * +rbd_allocate_struct(size_t const internal_digits) +{ + size_t const size = rbd_struct_size(internal_digits); + Real *real = ruby_xcalloc(1, size); + atomic_allocation_count_inc(); + real->MaxPrec = internal_digits; + return real; +} + +static size_t +rbd_calculate_internal_digits(size_t const digits, bool limit_precision) +{ + size_t const len = roomof(digits, BASE_FIG); + if (limit_precision) { + size_t const prec_limit = VpGetPrecLimit(); + if (prec_limit > 0) { + /* NOTE: 2 more digits for rounding and division */ + size_t const max_len = roomof(prec_limit, BASE_FIG) + 2; + if (len > max_len) + return max_len; + } + } + + return len; +} + +static inline Real * +rbd_allocate_struct_decimal_digits(size_t const decimal_digits, bool limit_precision) +{ + size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision); + return rbd_allocate_struct(internal_digits); +} + +static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp); + +static Real * +rbd_reallocate_struct(Real *real, size_t const internal_digits) +{ + size_t const size = rbd_struct_size(internal_digits); + VALUE obj = real ? real->obj : 0; + Real *new_real = (Real *)ruby_xrealloc(real, size); + new_real->MaxPrec = internal_digits; + if (obj) { + new_real->obj = 0; + BigDecimal_wrap_struct(obj, new_real); + } + return new_real; +} + +static void +rbd_free_struct(Real *real) +{ + if (real != NULL) { + check_allocation_count_nonzero(); + ruby_xfree(real); + atomic_allocation_count_dec_nounderflow(); + } +} + +#define NewZero rbd_allocate_struct_zero +static Real * +rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision) +{ + Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision); + VpSetZero(real, sign); + return real; +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits)); +#define NewZeroLimited rbd_allocate_struct_zero_limited +static inline Real * +rbd_allocate_struct_zero_limited(int sign, size_t const digits) +{ + return rbd_allocate_struct_zero(sign, digits, true); +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits)); +#define NewZeroNolimit rbd_allocate_struct_zero_nolimit +static inline Real * +rbd_allocate_struct_zero_nolimit(int sign, size_t const digits) +{ + return rbd_allocate_struct_zero(sign, digits, false); +} + +#define NewOne rbd_allocate_struct_one +static Real * +rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision) +{ + Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision); + VpSetOne(real); + if (sign < 0) + VpSetSign(real, VP_SIGN_NEGATIVE_FINITE); + return real; +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits)); +#define NewOneLimited rbd_allocate_struct_one_limited +static inline Real * +rbd_allocate_struct_one_limited(int sign, size_t const digits) +{ + return rbd_allocate_struct_one(sign, digits, true); +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits)); +#define NewOneNolimit rbd_allocate_struct_one_nolimit +static inline Real * +rbd_allocate_struct_one_nolimit(int sign, size_t const digits) +{ + return rbd_allocate_struct_one(sign, digits, false); +} + +/* + * ================== Ruby Interface part ========================== + */ +#define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f) + +/* + * VP routines used in BigDecimal part + */ +static unsigned short VpGetException(void); +static void VpSetException(unsigned short f); +static void VpCheckException(Real *p, bool always); +static VALUE VpCheckGetValue(Real *p); +static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v); +static int VpLimitRound(Real *c, size_t ixDigit); +static Real *VpCopy(Real *pv, Real const* const x); +static int VPrint(FILE *fp,const char *cntl_chr,Real *a); + +/* + * **** BigDecimal part **** + */ + +static VALUE BigDecimal_nan(void); +static VALUE BigDecimal_positive_infinity(void); +static VALUE BigDecimal_negative_infinity(void); +static VALUE BigDecimal_positive_zero(void); +static VALUE BigDecimal_negative_zero(void); + +static void +BigDecimal_delete(void *pv) +{ + rbd_free_struct(pv); +} + +static size_t +BigDecimal_memsize(const void *ptr) +{ + const Real *pv = ptr; + return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG)); +} + +#ifndef HAVE_RB_EXT_RACTOR_SAFE +# undef RUBY_TYPED_FROZEN_SHAREABLE +# define RUBY_TYPED_FROZEN_SHAREABLE 0 +#endif + +static const rb_data_type_t BigDecimal_data_type = { + "BigDecimal", + { 0, BigDecimal_delete, BigDecimal_memsize, }, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED +#endif +}; + +static Real * +rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision) +{ + Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision); + if (real != NULL) { + VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); + BigDecimal_wrap_struct(obj, real); + } + return real; +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)); +#define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap +static inline Real * +rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits) +{ + return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true); +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)); +#define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap +static inline Real * +rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits) +{ + return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false); +} + +static Real * +rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision) +{ + Real *real = rbd_allocate_struct_one(sign, digits, limit_precision); + if (real != NULL) { + VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); + BigDecimal_wrap_struct(obj, real); + } + return real; +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)); +#define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap +static inline Real * +rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits) +{ + return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true); +} + +MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)); +#define NewOneWrapNolimit rbd_allocate_struct_one_nolimit_wrap +static inline Real * +rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits) +{ + return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false); +} + +static inline int +is_kind_of_BigDecimal(VALUE const v) +{ + return rb_typeddata_is_kind_of(v, &BigDecimal_data_type); +} + +NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE)); + +static void +cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v) +{ + VALUE str; + + if (rb_special_const_p(v)) { + str = rb_inspect(v); + } + else { + str = rb_class_name(rb_obj_class(v)); + } + + str = rb_str_cat2(rb_str_dup(str), " can't be coerced into BigDecimal"); + rb_exc_raise(rb_exc_new3(exc_class, str)); +} + +static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE); +static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception); +static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception); +static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception); +static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception); +static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception); + +static Real* +GetVpValueWithPrec(VALUE v, long prec, int must) +{ + const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec; + + switch(TYPE(v)) { + case T_FLOAT: + v = rb_float_convert_to_BigDecimal(v, digs, must); + break; + + case T_RATIONAL: + v = rb_rational_convert_to_BigDecimal(v, digs, must); + break; + + case T_DATA: + if (!is_kind_of_BigDecimal(v)) { + goto SomeOneMayDoIt; + } + break; + + case T_FIXNUM: { + char szD[128]; + snprintf(szD, 128, "%ld", FIX2LONG(v)); + v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must); + break; + } + +#ifdef ENABLE_NUMERIC_STRING + case T_STRING: { + const char *c_str = StringValueCStr(v); + v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must); + break; + } +#endif /* ENABLE_NUMERIC_STRING */ + + case T_BIGNUM: { + VALUE bg = rb_big2str(v, 10); + v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must); + RB_GC_GUARD(bg); + break; + } + + default: + goto SomeOneMayDoIt; + } + + Real *vp; + TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp); + return vp; + +SomeOneMayDoIt: + if (must) { + cannot_be_coerced_into_BigDecimal(rb_eTypeError, v); + } + return NULL; /* NULL means to coerce */ +} + +static inline Real* +GetVpValue(VALUE v, int must) +{ + return GetVpValueWithPrec(v, -1, must); +} + +/* call-seq: + * BigDecimal.double_fig -> integer + * + * Returns the number of digits a Float object is allowed to have; + * the result is system-dependent: + * + * BigDecimal.double_fig # => 16 + * + */ +static inline VALUE +BigDecimal_double_fig(VALUE self) +{ + return INT2FIX(VpDblFig()); +} + +/* call-seq: + * precs -> array + * + * Returns an Array of two Integer values that represent platform-dependent + * internal storage properties. + * + * This method is deprecated and will be removed in the future. + * Instead, use BigDecimal#n_significant_digits for obtaining the number of + * significant digits in scientific notation, and BigDecimal#precision for + * obtaining the number of digits in decimal notation. + * + */ + +static VALUE +BigDecimal_prec(VALUE self) +{ + ENTER(1); + Real *p; + VALUE obj; + + rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, + "BigDecimal#precs is deprecated and will be removed in the future; " + "use BigDecimal#precision instead."); + + GUARD_OBJ(p, GetVpValue(self, 1)); + obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()), + SIZET2NUM(p->MaxPrec*VpBaseFig())); + return obj; +} + +static void +BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale) +{ + ENTER(1); + + if (out_precision == NULL && out_scale == NULL) + return; + + Real *p; + GUARD_OBJ(p, GetVpValue(self, 1)); + if (VpIsZero(p) || !VpIsDef(p)) { + zero: + if (out_precision) *out_precision = 0; + if (out_scale) *out_scale = 0; + return; + } + + DECDIG x; + + ssize_t n = p->Prec; /* The length of frac without zeros. */ + while (n > 0 && p->frac[n-1] == 0) --n; + if (n == 0) goto zero; + + int nlz = BASE_FIG; + for (x = p->frac[0]; x > 0; x /= 10) --nlz; + + int ntz = 0; + for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz; + + /* + * Calculate the precision and the scale + * ------------------------------------- + * + * The most significant digit is frac[0], and the least significant digit + * is frac[Prec-1]. When the exponent is zero, the decimal point is + * located just before frac[0]. + * + * When the exponent is negative, the decimal point moves to leftward. + * In this case, the precision can be calculated by + * + * precision = BASE_FIG * (-exponent + n) - ntz, + * + * and the scale is the same as precision. + * + * 0 . 0000 0000 | frac[0] ... frac[n-1] | + * |<----------| exponent == -2 | + * |---------------------------------->| precision + * |---------------------------------->| scale + * + * + * Conversely, when the exponent is positive, the decimal point moves to + * rightward. In this case, the scale equals to + * + * BASE_FIG * (n - exponent) - ntz. + * + * the precision equals to + * + * scale + BASE_FIG * exponent - nlz. + * + * | frac[0] frac[1] . frac[2] ... frac[n-1] | + * |---------------->| exponent == 2 | + * | |---------------------->| scale + * |---------------------------------------->| precision + */ + + ssize_t ex = p->exponent; + + /* Count the number of decimal digits before frac[1]. */ + ssize_t n_digits_head = BASE_FIG; + if (ex < 0) { + n_digits_head += (-ex) * BASE_FIG; /* The number of leading zeros before frac[0]. */ + ex = 0; + } + else if (ex > 0) { + /* Count the number of decimal digits without the leading zeros in + * the most significant digit in the integral part. + */ + n_digits_head -= nlz; /* Make the number of digits */ + } + + if (out_precision) { + ssize_t precision = n_digits_head; + + /* Count the number of decimal digits after frac[0]. */ + if (ex > (ssize_t)n) { + /* In this case the number is an integer with some trailing zeros. */ + precision += (ex - 1) * BASE_FIG; + } + else if (n > 0) { + precision += (n - 1) * BASE_FIG; + + if (ex < (ssize_t)n) { + precision -= ntz; + } + } + + *out_precision = precision; + } + + if (out_scale) { + ssize_t scale = 0; + + if (p->exponent < 0) { + scale = n_digits_head + (n - 1) * BASE_FIG - ntz; + } + else if (n > p->exponent) { + scale = (n - p->exponent) * BASE_FIG - ntz; + } + + *out_scale = scale; + } +} + +/* + * call-seq: + * precision -> integer + * + * Returns the number of decimal digits in +self+: + * + * BigDecimal("0").precision # => 0 + * BigDecimal("1").precision # => 1 + * BigDecimal("1.1").precision # => 2 + * BigDecimal("3.1415").precision # => 5 + * BigDecimal("-1e20").precision # => 21 + * BigDecimal("1e-20").precision # => 20 + * BigDecimal("Infinity").precision # => 0 + * BigDecimal("-Infinity").precision # => 0 + * BigDecimal("NaN").precision # => 0 + * + */ +static VALUE +BigDecimal_precision(VALUE self) +{ + ssize_t precision; + BigDecimal_count_precision_and_scale(self, &precision, NULL); + return SSIZET2NUM(precision); +} + +/* + * call-seq: + * scale -> integer + * + * Returns the number of decimal digits following the decimal digits in +self+. + * + * BigDecimal("0").scale # => 0 + * BigDecimal("1").scale # => 0 + * BigDecimal("1.1").scale # => 1 + * BigDecimal("3.1415").scale # => 4 + * BigDecimal("-1e20").precision # => 0 + * BigDecimal("1e-20").precision # => 20 + * BigDecimal("Infinity").scale # => 0 + * BigDecimal("-Infinity").scale # => 0 + * BigDecimal("NaN").scale # => 0 + */ +static VALUE +BigDecimal_scale(VALUE self) +{ + ssize_t scale; + BigDecimal_count_precision_and_scale(self, NULL, &scale); + return SSIZET2NUM(scale); +} + +/* + * call-seq: + * precision_scale -> [integer, integer] + * + * Returns a 2-length array; the first item is the result of + * BigDecimal#precision and the second one is of BigDecimal#scale. + * + * See BigDecimal#precision. + * See BigDecimal#scale. + */ +static VALUE +BigDecimal_precision_scale(VALUE self) +{ + ssize_t precision, scale; + BigDecimal_count_precision_and_scale(self, &precision, &scale); + return rb_assoc_new(SSIZET2NUM(precision), SSIZET2NUM(scale)); +} + +/* + * call-seq: + * n_significant_digits -> integer + * + * Returns the number of decimal significant digits in +self+. + * + * BigDecimal("0").n_significant_digits # => 0 + * BigDecimal("1").n_significant_digits # => 1 + * BigDecimal("1.1").n_significant_digits # => 2 + * BigDecimal("3.1415").n_significant_digits # => 5 + * BigDecimal("-1e20").n_significant_digits # => 1 + * BigDecimal("1e-20").n_significant_digits # => 1 + * BigDecimal("Infinity").n_significant_digits # => 0 + * BigDecimal("-Infinity").n_significant_digits # => 0 + * BigDecimal("NaN").n_significant_digits # => 0 + */ +static VALUE +BigDecimal_n_significant_digits(VALUE self) +{ + ENTER(1); + + Real *p; + GUARD_OBJ(p, GetVpValue(self, 1)); + if (VpIsZero(p) || !VpIsDef(p)) { + return INT2FIX(0); + } + + ssize_t n = p->Prec; /* The length of frac without trailing zeros. */ + for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n); + if (n == 0) return INT2FIX(0); + + DECDIG x; + int nlz = BASE_FIG; + for (x = p->frac[0]; x > 0; x /= 10) --nlz; + + int ntz = 0; + for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz; + + ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz; + return SSIZET2NUM(n_significant_digits); +} + +/* + * call-seq: + * hash -> integer + * + * Returns the integer hash value for +self+. + * + * Two instances of \BigDecimal have the same hash value if and only if + * they have equal: + * + * - Sign. + * - Fractional part. + * - Exponent. + * + */ +static VALUE +BigDecimal_hash(VALUE self) +{ + ENTER(1); + Real *p; + st_index_t hash; + + GUARD_OBJ(p, GetVpValue(self, 1)); + hash = (st_index_t)p->sign; + /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */ + if(hash == 2 || hash == (st_index_t)-2) { + hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec); + hash += p->exponent; + } + return ST2FIX(hash); +} + +/* + * call-seq: + * _dump -> string + * + * Returns a string representing the marshalling of +self+. + * See module Marshal. + * + * inf = BigDecimal('Infinity') # => Infinity + * dumped = inf._dump # => "9:Infinity" + * BigDecimal._load(dumped) # => Infinity + * + */ +static VALUE +BigDecimal_dump(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + Real *vp; + char *psz; + VALUE dummy; + volatile VALUE dump; + size_t len; + + rb_scan_args(argc, argv, "01", &dummy); + GUARD_OBJ(vp,GetVpValue(self, 1)); + dump = rb_str_new(0, VpNumOfChars(vp, "E")+50); + psz = RSTRING_PTR(dump); + snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig()); + len = strlen(psz); + VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0); + rb_str_resize(dump, strlen(psz)); + return dump; +} + +/* + * Internal method used to provide marshalling support. See the Marshal module. + */ +static VALUE +BigDecimal_load(VALUE self, VALUE str) +{ + ENTER(2); + Real *pv; + unsigned char *pch; + unsigned char ch; + unsigned long m=0; + + pch = (unsigned char *)StringValueCStr(str); + /* First get max prec */ + while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') { + if(!ISDIGIT(ch)) { + rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string"); + } + m = m*10 + (unsigned long)(ch-'0'); + } + if (m > VpBaseFig()) m -= VpBaseFig(); + GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true)); + m /= VpBaseFig(); + if (m && pv->MaxPrec > m) { + pv->MaxPrec = m+1; + } + return VpCheckGetValue(pv); +} + +static unsigned short +check_rounding_mode_option(VALUE const opts) +{ + VALUE mode; + char const *s; + long l; + + assert(RB_TYPE_P(opts, T_HASH)); + + if (NIL_P(opts)) + goto no_opt; + + mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef); + if (mode == Qundef || NIL_P(mode)) + goto no_opt; + + if (SYMBOL_P(mode)) + mode = rb_sym2str(mode); + else if (!RB_TYPE_P(mode, T_STRING)) { + VALUE str_mode = rb_check_string_type(mode); + if (NIL_P(str_mode)) + goto invalid; + mode = str_mode; + } + s = RSTRING_PTR(mode); + l = RSTRING_LEN(mode); + switch (l) { + case 2: + if (strncasecmp(s, "up", 2) == 0) + return VP_ROUND_HALF_UP; + break; + case 4: + if (strncasecmp(s, "even", 4) == 0) + return VP_ROUND_HALF_EVEN; + else if (strncasecmp(s, "down", 4) == 0) + return VP_ROUND_HALF_DOWN; + break; + default: + break; + } + + invalid: + rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", mode); + + no_opt: + return VpGetRoundMode(); +} + +static unsigned short +check_rounding_mode(VALUE const v) +{ + unsigned short sw; + ID id; + if (RB_TYPE_P(v, T_SYMBOL)) { + int i; + id = SYM2ID(v); + for (i = 0; i < RBD_NUM_ROUNDING_MODES; ++i) { + if (rbd_rounding_modes[i].id == id) { + return rbd_rounding_modes[i].mode; + } + } + rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v); + } + else { + sw = NUM2USHORT(v); + if (!VpIsRoundMode(sw)) { + rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v); + } + return sw; + } +} + +/* call-seq: + * BigDecimal.mode(mode, setting = nil) -> integer + * + * Returns an integer representing the mode settings + * for exception handling and rounding. + * + * These modes control exception handling: + * + * - \BigDecimal::EXCEPTION_NaN. + * - \BigDecimal::EXCEPTION_INFINITY. + * - \BigDecimal::EXCEPTION_UNDERFLOW. + * - \BigDecimal::EXCEPTION_OVERFLOW. + * - \BigDecimal::EXCEPTION_ZERODIVIDE. + * - \BigDecimal::EXCEPTION_ALL. + * + * Values for +setting+ for exception handling: + * + * - +true+: sets the given +mode+ to +true+. + * - +false+: sets the given +mode+ to +false+. + * - +nil+: does not modify the mode settings. + * + * You can use method BigDecimal.save_exception_mode + * to temporarily change, and then automatically restore, exception modes. + * + * For clarity, some examples below begin by setting all + * exception modes to +false+. + * + * This mode controls the way rounding is to be performed: + * + * - \BigDecimal::ROUND_MODE + * + * You can use method BigDecimal.save_rounding_mode + * to temporarily change, and then automatically restore, the rounding mode. + * + * NaNs + * + * Mode \BigDecimal::EXCEPTION_NaN controls behavior + * when a \BigDecimal NaN is created. + * + * Settings: + * + * - +false+ (default): Returns BigDecimal('NaN'). + * - +true+: Raises FloatDomainError. + * + * Examples: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * BigDecimal('NaN') # => NaN + * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true) # => 2 + * BigDecimal('NaN') # Raises FloatDomainError + * + * Infinities + * + * Mode \BigDecimal::EXCEPTION_INFINITY controls behavior + * when a \BigDecimal Infinity or -Infinity is created. + * Settings: + * + * - +false+ (default): Returns BigDecimal('Infinity') + * or BigDecimal('-Infinity'). + * - +true+: Raises FloatDomainError. + * + * Examples: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * BigDecimal('Infinity') # => Infinity + * BigDecimal('-Infinity') # => -Infinity + * BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true) # => 1 + * BigDecimal('Infinity') # Raises FloatDomainError + * BigDecimal('-Infinity') # Raises FloatDomainError + * + * Underflow + * + * Mode \BigDecimal::EXCEPTION_UNDERFLOW controls behavior + * when a \BigDecimal underflow occurs. + * Settings: + * + * - +false+ (default): Returns BigDecimal('0') + * or BigDecimal('-Infinity'). + * - +true+: Raises FloatDomainError. + * + * Examples: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * def flow_under + * x = BigDecimal('0.1') + * 100.times { x *= x } + * end + * flow_under # => 100 + * BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) # => 4 + * flow_under # Raises FloatDomainError + * + * Overflow + * + * Mode \BigDecimal::EXCEPTION_OVERFLOW controls behavior + * when a \BigDecimal overflow occurs. + * Settings: + * + * - +false+ (default): Returns BigDecimal('Infinity') + * or BigDecimal('-Infinity'). + * - +true+: Raises FloatDomainError. + * + * Examples: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * def flow_over + * x = BigDecimal('10') + * 100.times { x *= x } + * end + * flow_over # => 100 + * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) # => 1 + * flow_over # Raises FloatDomainError + * + * Zero Division + * + * Mode \BigDecimal::EXCEPTION_ZERODIVIDE controls behavior + * when a zero-division occurs. + * Settings: + * + * - +false+ (default): Returns BigDecimal('Infinity') + * or BigDecimal('-Infinity'). + * - +true+: Raises FloatDomainError. + * + * Examples: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * one = BigDecimal('1') + * zero = BigDecimal('0') + * one / zero # => Infinity + * BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true) # => 16 + * one / zero # Raises FloatDomainError + * + * All Exceptions + * + * Mode \BigDecimal::EXCEPTION_ALL controls all of the above: + * + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0 + * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true) # => 23 + * + * Rounding + * + * Mode \BigDecimal::ROUND_MODE controls the way rounding is to be performed; + * its +setting+ values are: + * + * - +ROUND_UP+: Round away from zero. + * Aliased as +:up+. + * - +ROUND_DOWN+: Round toward zero. + * Aliased as +:down+ and +:truncate+. + * - +ROUND_HALF_UP+: Round toward the nearest neighbor; + * if the neighbors are equidistant, round away from zero. + * Aliased as +:half_up+ and +:default+. + * - +ROUND_HALF_DOWN+: Round toward the nearest neighbor; + * if the neighbors are equidistant, round toward zero. + * Aliased as +:half_down+. + * - +ROUND_HALF_EVEN+ (Banker's rounding): Round toward the nearest neighbor; + * if the neighbors are equidistant, round toward the even neighbor. + * Aliased as +:half_even+ and +:banker+. + * - +ROUND_CEILING+: Round toward positive infinity. + * Aliased as +:ceiling+ and +:ceil+. + * - +ROUND_FLOOR+: Round toward negative infinity. + * Aliased as +:floor:+. + * + */ +static VALUE +BigDecimal_mode(int argc, VALUE *argv, VALUE self) +{ + VALUE which; + VALUE val; + unsigned long f,fo; + + rb_scan_args(argc, argv, "11", &which, &val); + f = (unsigned long)NUM2INT(which); + + if (f & VP_EXCEPTION_ALL) { + /* Exception mode setting */ + fo = VpGetException(); + if (val == Qnil) return INT2FIX(fo); + if (val != Qfalse && val!=Qtrue) { + rb_raise(rb_eArgError, "second argument must be true or false"); + return Qnil; /* Not reached */ + } + if (f & VP_EXCEPTION_INFINITY) { + VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) : + (fo & (~VP_EXCEPTION_INFINITY)))); + } + fo = VpGetException(); + if (f & VP_EXCEPTION_NaN) { + VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) : + (fo & (~VP_EXCEPTION_NaN)))); + } + fo = VpGetException(); + if (f & VP_EXCEPTION_UNDERFLOW) { + VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) : + (fo & (~VP_EXCEPTION_UNDERFLOW)))); + } + fo = VpGetException(); + if(f & VP_EXCEPTION_ZERODIVIDE) { + VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) : + (fo & (~VP_EXCEPTION_ZERODIVIDE)))); + } + fo = VpGetException(); + return INT2FIX(fo); + } + if (VP_ROUND_MODE == f) { + /* Rounding mode setting */ + unsigned short sw; + fo = VpGetRoundMode(); + if (NIL_P(val)) return INT2FIX(fo); + sw = check_rounding_mode(val); + fo = VpSetRoundMode(sw); + return INT2FIX(fo); + } + rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid"); + return Qnil; +} + +static size_t +GetAddSubPrec(Real *a, Real *b) +{ + size_t mxs; + size_t mx = a->Prec; + SIGNED_VALUE d; + + if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L; + if (mx < b->Prec) mx = b->Prec; + if (a->exponent != b->exponent) { + mxs = mx; + d = a->exponent - b->exponent; + if (d < 0) d = -d; + mx = mx + (size_t)d; + if (mx < mxs) { + return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0); + } + } + return mx; +} + +static inline SIGNED_VALUE +check_int_precision(VALUE v) +{ + SIGNED_VALUE n; +#if SIZEOF_VALUE <= SIZEOF_LONG + n = (SIGNED_VALUE)NUM2LONG(v); +#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG + n = (SIGNED_VALUE)NUM2LL(v); +#else +# error SIZEOF_VALUE is too large +#endif + if (n < 0) { + rb_raise(rb_eArgError, "negative precision"); + } + return n; +} + +static VALUE +BigDecimal_wrap_struct(VALUE obj, Real *vp) +{ + assert(is_kind_of_BigDecimal(obj)); + assert(vp != NULL); + + if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp) + return obj; + + assert(RTYPEDDATA_DATA(obj) == NULL); + assert(vp->obj == 0); + + RTYPEDDATA_DATA(obj) = vp; + vp->obj = obj; + RB_OBJ_FREEZE(obj); + return obj; +} + +VP_EXPORT Real * +VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception) +{ + VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); + Real *pv = VpAlloc(mx, str, strict_p, raise_exception); + if (!pv) + return NULL; + BigDecimal_wrap_struct(obj, pv); + return pv; +} + +VP_EXPORT Real * +VpCreateRbObject(size_t mx, const char *str, bool raise_exception) +{ + return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception); +} + +static Real * +VpCopy(Real *pv, Real const* const x) +{ + assert(x != NULL); + + pv = rbd_reallocate_struct(pv, x->MaxPrec); + pv->MaxPrec = x->MaxPrec; + pv->Prec = x->Prec; + pv->exponent = x->exponent; + pv->sign = x->sign; + pv->flag = x->flag; + MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec); + + return pv; +} + +/* Returns True if the value is Not a Number. */ +static VALUE +BigDecimal_IsNaN(VALUE self) +{ + Real *p = GetVpValue(self, 1); + if (VpIsNaN(p)) return Qtrue; + return Qfalse; +} + +/* Returns nil, -1, or +1 depending on whether the value is finite, + * -Infinity, or +Infinity. + */ +static VALUE +BigDecimal_IsInfinite(VALUE self) +{ + Real *p = GetVpValue(self, 1); + if (VpIsPosInf(p)) return INT2FIX(1); + if (VpIsNegInf(p)) return INT2FIX(-1); + return Qnil; +} + +/* Returns True if the value is finite (not NaN or infinite). */ +static VALUE +BigDecimal_IsFinite(VALUE self) +{ + Real *p = GetVpValue(self, 1); + if (VpIsNaN(p)) return Qfalse; + if (VpIsInf(p)) return Qfalse; + return Qtrue; +} + +static void +BigDecimal_check_num(Real *p) +{ + VpCheckException(p, true); +} + +static VALUE BigDecimal_split(VALUE self); + +/* Returns the value as an Integer. + * + * If the BigDecimal is infinity or NaN, raises FloatDomainError. + */ +static VALUE +BigDecimal_to_i(VALUE self) +{ + ENTER(5); + ssize_t e, nf; + Real *p; + + GUARD_OBJ(p, GetVpValue(self, 1)); + BigDecimal_check_num(p); + + e = VpExponent10(p); + if (e <= 0) return INT2FIX(0); + nf = VpBaseFig(); + if (e <= nf) { + return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0])); + } + else { + VALUE a = BigDecimal_split(self); + VALUE digits = RARRAY_AREF(a, 1); + VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0); + VALUE ret; + ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits); + + if (BIGDECIMAL_NEGATIVE_P(p)) { + numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1)); + } + if (dpower < 0) { + ret = rb_funcall(numerator, rb_intern("div"), 1, + rb_funcall(INT2FIX(10), rb_intern("**"), 1, + INT2FIX(-dpower))); + } + else { + ret = rb_funcall(numerator, '*', 1, + rb_funcall(INT2FIX(10), rb_intern("**"), 1, + INT2FIX(dpower))); + } + if (RB_TYPE_P(ret, T_FLOAT)) { + rb_raise(rb_eFloatDomainError, "Infinity"); + } + return ret; + } +} + +/* Returns a new Float object having approximately the same value as the + * BigDecimal number. Normal accuracy limits and built-in errors of binary + * Float arithmetic apply. + */ +static VALUE +BigDecimal_to_f(VALUE self) +{ + ENTER(1); + Real *p; + double d; + SIGNED_VALUE e; + char *buf; + volatile VALUE str; + + GUARD_OBJ(p, GetVpValue(self, 1)); + if (VpVtoD(&d, &e, p) != 1) + return rb_float_new(d); + if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG)) + goto overflow; + if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG)) + goto underflow; + + str = rb_str_new(0, VpNumOfChars(p, "E")); + buf = RSTRING_PTR(str); + VpToString(p, buf, RSTRING_LEN(str), 0, 0); + errno = 0; + d = strtod(buf, 0); + if (errno == ERANGE) { + if (d == 0.0) goto underflow; + if (fabs(d) >= HUGE_VAL) goto overflow; + } + return rb_float_new(d); + +overflow: + VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0); + if (BIGDECIMAL_NEGATIVE_P(p)) + return rb_float_new(VpGetDoubleNegInf()); + else + return rb_float_new(VpGetDoublePosInf()); + +underflow: + VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0); + if (BIGDECIMAL_NEGATIVE_P(p)) + return rb_float_new(-0.0); + else + return rb_float_new(0.0); +} + + +/* Converts a BigDecimal to a Rational. + */ +static VALUE +BigDecimal_to_r(VALUE self) +{ + Real *p; + ssize_t sign, power, denomi_power; + VALUE a, digits, numerator; + + p = GetVpValue(self, 1); + BigDecimal_check_num(p); + + sign = VpGetSign(p); + power = VpExponent10(p); + a = BigDecimal_split(self); + digits = RARRAY_AREF(a, 1); + denomi_power = power - RSTRING_LEN(digits); + numerator = rb_funcall(digits, rb_intern("to_i"), 0); + + if (sign < 0) { + numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1)); + } + if (denomi_power < 0) { + return rb_Rational(numerator, + rb_funcall(INT2FIX(10), rb_intern("**"), 1, + INT2FIX(-denomi_power))); + } + else { + return rb_Rational1(rb_funcall(numerator, '*', 1, + rb_funcall(INT2FIX(10), rb_intern("**"), 1, + INT2FIX(denomi_power)))); + } +} + +/* The coerce method provides support for Ruby type coercion. It is not + * enabled by default. + * + * This means that binary operations like + * / or - can often be performed + * on a BigDecimal and an object of another type, if the other object can + * be coerced into a BigDecimal value. + * + * e.g. + * a = BigDecimal("1.0") + * b = a / 2.0 #=> 0.5 + * + * Note that coercing a String to a BigDecimal is not supported by default; + * it requires a special compile-time option when building Ruby. + */ +static VALUE +BigDecimal_coerce(VALUE self, VALUE other) +{ + ENTER(2); + VALUE obj; + Real *b; + + if (RB_TYPE_P(other, T_FLOAT)) { + GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1)); + obj = rb_assoc_new(VpCheckGetValue(b), self); + } + else { + if (RB_TYPE_P(other, T_RATIONAL)) { + Real* pv = DATA_PTR(self); + GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1)); + } + else { + GUARD_OBJ(b, GetVpValue(other, 1)); + } + obj = rb_assoc_new(b->obj, self); + } + + return obj; +} + +/* + * call-seq: + * +big_decimal -> self + * + * Returns +self+: + * + * +BigDecimal(5) # => 0.5e1 + * +BigDecimal(-5) # => -0.5e1 + * + */ + +static VALUE +BigDecimal_uplus(VALUE self) +{ + return self; +} + + /* + * call-seq: + * self + value -> bigdecimal + * + * Returns the \BigDecimal sum of +self+ and +value+: + * + * b = BigDecimal('111111.111') # => 0.111111111e6 + * b + 2 # => 0.111113111e6 + * b + 2.0 # => 0.111113111e6 + * b + Rational(2, 1) # => 0.111113111e6 + * b + Complex(2, 0) # => (0.111113111e6+0i) + * + * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision]. + * + */ + +static VALUE +BigDecimal_add(VALUE self, VALUE r) +{ + ENTER(5); + Real *c, *a, *b; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self, 1)); + if (RB_TYPE_P(r, T_FLOAT)) { + b = GetVpValueWithPrec(r, 0, 1); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + } + else { + b = GetVpValue(r, 0); + } + + if (!b) return DoSomeOne(self,r,'+'); + SAVE(b); + + if (VpIsNaN(b)) return b->obj; + if (VpIsNaN(a)) return a->obj; + + mx = GetAddSubPrec(a, b); + if (mx == (size_t)-1L) { + GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1)); + VpAddSub(c, a, b, 1); + } + else { + GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1))); + if (!mx) { + VpSetInf(c, VpGetSign(a)); + } + else { + VpAddSub(c, a, b, 1); + } + } + return VpCheckGetValue(c); +} + + /* call-seq: + * self - value -> bigdecimal + * + * Returns the \BigDecimal difference of +self+ and +value+: + * + * b = BigDecimal('333333.333') # => 0.333333333e6 + * b - 2 # => 0.333331333e6 + * b - 2.0 # => 0.333331333e6 + * b - Rational(2, 1) # => 0.333331333e6 + * b - Complex(2, 0) # => (0.333331333e6+0i) + * + * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision]. + * + */ +static VALUE +BigDecimal_sub(VALUE self, VALUE r) +{ + ENTER(5); + Real *c, *a, *b; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self,1)); + if (RB_TYPE_P(r, T_FLOAT)) { + b = GetVpValueWithPrec(r, 0, 1); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + } + else { + b = GetVpValue(r,0); + } + + if (!b) return DoSomeOne(self,r,'-'); + SAVE(b); + + if (VpIsNaN(b)) return b->obj; + if (VpIsNaN(a)) return a->obj; + + mx = GetAddSubPrec(a,b); + if (mx == (size_t)-1L) { + GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1)); + VpAddSub(c, a, b, -1); + } + else { + GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1))); + if (!mx) { + VpSetInf(c,VpGetSign(a)); + } + else { + VpAddSub(c, a, b, -1); + } + } + return VpCheckGetValue(c); +} + +static VALUE +BigDecimalCmp(VALUE self, VALUE r,char op) +{ + ENTER(5); + SIGNED_VALUE e; + Real *a, *b=0; + GUARD_OBJ(a, GetVpValue(self, 1)); + switch (TYPE(r)) { + case T_DATA: + if (!is_kind_of_BigDecimal(r)) break; + /* fall through */ + case T_FIXNUM: + /* fall through */ + case T_BIGNUM: + GUARD_OBJ(b, GetVpValue(r, 0)); + break; + + case T_FLOAT: + GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0)); + break; + + case T_RATIONAL: + GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0)); + break; + + default: + break; + } + if (b == NULL) { + ID f = 0; + + switch (op) { + case '*': + return rb_num_coerce_cmp(self, r, rb_intern("<=>")); + + case '=': + return RTEST(rb_num_coerce_cmp(self, r, rb_intern("=="))) ? Qtrue : Qfalse; + + case 'G': + f = rb_intern(">="); + break; + + case 'L': + f = rb_intern("<="); + break; + + case '>': + /* fall through */ + case '<': + f = (ID)op; + break; + + default: + break; + } + return rb_num_coerce_relop(self, r, f); + } + SAVE(b); + e = VpComp(a, b); + if (e == 999) + return (op == '*') ? Qnil : Qfalse; + switch (op) { + case '*': + return INT2FIX(e); /* any op */ + + case '=': + if (e == 0) return Qtrue; + return Qfalse; + + case 'G': + if (e >= 0) return Qtrue; + return Qfalse; + + case '>': + if (e > 0) return Qtrue; + return Qfalse; + + case 'L': + if (e <= 0) return Qtrue; + return Qfalse; + + case '<': + if (e < 0) return Qtrue; + return Qfalse; + + default: + break; + } + + rb_bug("Undefined operation in BigDecimalCmp()"); + + UNREACHABLE; +} + +/* Returns True if the value is zero. */ +static VALUE +BigDecimal_zero(VALUE self) +{ + Real *a = GetVpValue(self, 1); + return VpIsZero(a) ? Qtrue : Qfalse; +} + +/* Returns self if the value is non-zero, nil otherwise. */ +static VALUE +BigDecimal_nonzero(VALUE self) +{ + Real *a = GetVpValue(self, 1); + return VpIsZero(a) ? Qnil : self; +} + +/* The comparison operator. + * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b. + */ +static VALUE +BigDecimal_comp(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, '*'); +} + +/* + * Tests for value equality; returns true if the values are equal. + * + * The == and === operators and the eql? method have the same implementation + * for BigDecimal. + * + * Values may be coerced to perform the comparison: + * + * BigDecimal('1.0') == 1.0 #=> true + */ +static VALUE +BigDecimal_eq(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, '='); +} + +/* call-seq: + * self < other -> true or false + * + * Returns +true+ if +self+ is less than +other+, +false+ otherwise: + * + * b = BigDecimal('1.5') # => 0.15e1 + * b < 2 # => true + * b < 2.0 # => true + * b < Rational(2, 1) # => true + * b < 1.5 # => false + * + * Raises an exception if the comparison cannot be made. + * + */ +static VALUE +BigDecimal_lt(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, '<'); +} + +/* call-seq: + * self <= other -> true or false + * + * Returns +true+ if +self+ is less or equal to than +other+, +false+ otherwise: + * + * b = BigDecimal('1.5') # => 0.15e1 + * b <= 2 # => true + * b <= 2.0 # => true + * b <= Rational(2, 1) # => true + * b <= 1.5 # => true + * b < 1 # => false + * + * Raises an exception if the comparison cannot be made. + * + */ +static VALUE +BigDecimal_le(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, 'L'); +} + +/* call-seq: + * self > other -> true or false + * + * Returns +true+ if +self+ is greater than +other+, +false+ otherwise: + * + * b = BigDecimal('1.5') + * b > 1 # => true + * b > 1.0 # => true + * b > Rational(1, 1) # => true + * b > 2 # => false + * + * Raises an exception if the comparison cannot be made. + * + */ +static VALUE +BigDecimal_gt(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, '>'); +} + +/* call-seq: + * self >= other -> true or false + * + * Returns +true+ if +self+ is greater than or equal to +other+, +false+ otherwise: + * + * b = BigDecimal('1.5') + * b >= 1 # => true + * b >= 1.0 # => true + * b >= Rational(1, 1) # => true + * b >= 1.5 # => true + * b > 2 # => false + * + * Raises an exception if the comparison cannot be made. + * + */ +static VALUE +BigDecimal_ge(VALUE self, VALUE r) +{ + return BigDecimalCmp(self, r, 'G'); +} + +/* + * call-seq: + * -self -> bigdecimal + * + * Returns the \BigDecimal negation of self: + * + * b0 = BigDecimal('1.5') + * b1 = -b0 # => -0.15e1 + * b2 = -b1 # => 0.15e1 + * + */ + +static VALUE +BigDecimal_neg(VALUE self) +{ + ENTER(5); + Real *c, *a; + GUARD_OBJ(a, GetVpValue(self, 1)); + GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1))); + VpAsgn(c, a, -1); + return VpCheckGetValue(c); +} + +/* + * call-seq: + * a * b -> bigdecimal + * + * Multiply by the specified value. + * + * The result precision will be the precision of the sum of each precision. + * + * See BigDecimal#mult. + */ + +static VALUE +BigDecimal_mult(VALUE self, VALUE r) +{ + ENTER(5); + Real *c, *a, *b; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self, 1)); + if (RB_TYPE_P(r, T_FLOAT)) { + b = GetVpValueWithPrec(r, 0, 1); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + } + else { + b = GetVpValue(r,0); + } + + if (!b) return DoSomeOne(self, r, '*'); + SAVE(b); + + mx = a->Prec + b->Prec; + GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1))); + VpMult(c, a, b); + return VpCheckGetValue(c); +} + +static VALUE +BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div) +/* For c = self.div(r): with round operation */ +{ + ENTER(5); + Real *a, *b; + ssize_t a_prec, b_prec; + size_t mx; + + TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a); + SAVE(a); + + VALUE rr = r; + if (is_kind_of_BigDecimal(rr)) { + /* do nothing */ + } + else if (RB_INTEGER_TYPE_P(r)) { + rr = rb_inum_convert_to_BigDecimal(r, 0, true); + } + else if (RB_TYPE_P(r, T_FLOAT)) { + rr = rb_float_convert_to_BigDecimal(r, 0, true); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true); + } + + if (!is_kind_of_BigDecimal(rr)) { + return DoSomeOne(self, r, '/'); + } + + TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b); + SAVE(b); + *div = b; + + BigDecimal_count_precision_and_scale(self, &a_prec, NULL); + BigDecimal_count_precision_and_scale(rr, &b_prec, NULL); + mx = (a_prec > b_prec) ? a_prec : b_prec; + mx *= 2; + + if (2*BIGDECIMAL_DOUBLE_FIGURES > mx) + mx = 2*BIGDECIMAL_DOUBLE_FIGURES; + + GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG)); + GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG)); + VpDivd(*c, *res, a, b); + + return Qnil; +} + +static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod); + +/* call-seq: + * a / b -> bigdecimal + * + * Divide by the specified value. + * + * The result precision will be the precision of the larger operand, + * but its minimum is 2*Float::DIG. + * + * See BigDecimal#div. + * See BigDecimal#quo. + */ +static VALUE +BigDecimal_div(VALUE self, VALUE r) +/* For c = self/r: with round operation */ +{ + ENTER(5); + Real *c=NULL, *res=NULL, *div = NULL; + r = BigDecimal_divide(self, r, &c, &res, &div); + if (!NIL_P(r)) return r; /* coerced by other */ + SAVE(c); SAVE(res); SAVE(div); + /* a/b = c + r/b */ + /* c xxxxx + r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE + */ + /* Round */ + if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */ + VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0])); + } + return VpCheckGetValue(c); +} + +static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self); + +/* call-seq: + * quo(value) -> bigdecimal + * quo(value, digits) -> bigdecimal + * + * Divide by the specified value. + * + * digits:: If specified and less than the number of significant digits of + * the result, the result is rounded to the given number of digits, + * according to the rounding mode indicated by BigDecimal.mode. + * + * If digits is 0 or omitted, the result is the same as for the + * / operator. + * + * See BigDecimal#/. + * See BigDecimal#div. + */ +static VALUE +BigDecimal_quo(int argc, VALUE *argv, VALUE self) +{ + VALUE value, digits, result; + SIGNED_VALUE n = -1; + + argc = rb_scan_args(argc, argv, "11", &value, &digits); + if (argc > 1) { + n = check_int_precision(digits); + } + + if (n > 0) { + result = BigDecimal_div2(self, value, digits); + } + else { + result = BigDecimal_div(self, value); + } + + return result; +} + +/* + * %: mod = a%b = a - (a.to_f/b).floor * b + * div = (a.to_f/b).floor + */ +static VALUE +BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) +{ + ENTER(8); + Real *c=NULL, *d=NULL, *res=NULL; + Real *a, *b; + ssize_t a_prec, b_prec; + size_t mx; + + TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a); + SAVE(a); + + VALUE rr = r; + if (is_kind_of_BigDecimal(rr)) { + /* do nothing */ + } + else if (RB_INTEGER_TYPE_P(r)) { + rr = rb_inum_convert_to_BigDecimal(r, 0, true); + } + else if (RB_TYPE_P(r, T_FLOAT)) { + rr = rb_float_convert_to_BigDecimal(r, 0, true); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true); + } + + if (!is_kind_of_BigDecimal(rr)) { + return Qfalse; + } + + TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b); + SAVE(b); + + if (VpIsNaN(a) || VpIsNaN(b)) goto NaN; + if (VpIsInf(a) && VpIsInf(b)) goto NaN; + if (VpIsZero(b)) { + rb_raise(rb_eZeroDivError, "divided by 0"); + } + if (VpIsInf(a)) { + if (VpGetSign(a) == VpGetSign(b)) { + VALUE inf = BigDecimal_positive_infinity(); + TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div); + } + else { + VALUE inf = BigDecimal_negative_infinity(); + TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div); + } + VALUE nan = BigDecimal_nan(); + TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod); + return Qtrue; + } + if (VpIsInf(b)) { + VALUE zero = BigDecimal_positive_zero(); + TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div); + *mod = a; + return Qtrue; + } + if (VpIsZero(a)) { + VALUE zero = BigDecimal_positive_zero(); + TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div); + TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod); + return Qtrue; + } + + BigDecimal_count_precision_and_scale(self, &a_prec, NULL); + BigDecimal_count_precision_and_scale(rr, &b_prec, NULL); + + mx = (a_prec > b_prec) ? a_prec : b_prec; + mx *= 2; + + if (2*BIGDECIMAL_DOUBLE_FIGURES > mx) + mx = 2*BIGDECIMAL_DOUBLE_FIGURES; + + GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG)); + GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG)); + VpDivd(c, res, a, b); + + mx = c->Prec * BASE_FIG; + GUARD_OBJ(d, NewZeroWrapLimited(1, mx)); + VpActiveRound(d, c, VP_ROUND_DOWN, 0); + + VpMult(res, d, b); + VpAddSub(c, a, res, -1); + + if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) { + /* result adjustment for negative case */ + res = rbd_reallocate_struct(res, d->MaxPrec); + res->MaxPrec = d->MaxPrec; + VpAddSub(res, d, VpOne(), -1); + GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG)); + VpAddSub(d, c, b, 1); + *div = res; + *mod = d; + } + else { + *div = d; + *mod = c; + } + return Qtrue; + + NaN: + { + VALUE nan = BigDecimal_nan(); + TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div); + TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod); + } + return Qtrue; +} + +/* call-seq: + * a % b + * a.modulo(b) + * + * Returns the modulus from dividing by b. + * + * See BigDecimal#divmod. + */ +static VALUE +BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */ +{ + ENTER(3); + Real *div = NULL, *mod = NULL; + + if (BigDecimal_DoDivmod(self, r, &div, &mod)) { + SAVE(div); SAVE(mod); + return VpCheckGetValue(mod); + } + return DoSomeOne(self, r, '%'); +} + +static VALUE +BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv) +{ + ENTER(10); + size_t mx; + Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL; + Real *f = NULL; + + GUARD_OBJ(a, GetVpValue(self, 1)); + if (RB_TYPE_P(r, T_FLOAT)) { + b = GetVpValueWithPrec(r, 0, 1); + } + else if (RB_TYPE_P(r, T_RATIONAL)) { + b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1); + } + else { + b = GetVpValue(r, 0); + } + + if (!b) return DoSomeOne(self, r, rb_intern("remainder")); + SAVE(b); + + if (VpIsPosInf(b) || VpIsNegInf(b)) { + GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1)); + VpSetZero(*dv, 1); + *rv = a; + return Qnil; + } + + mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig(); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1))); + GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1))); + GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1))); + + VpDivd(c, res, a, b); + + mx = c->Prec *(VpBaseFig() + 1); + + GUARD_OBJ(d, NewZeroWrapLimited(1, mx)); + GUARD_OBJ(f, NewZeroWrapLimited(1, mx)); + + VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */ + + VpFrac(f, c); + VpMult(rr, f, b); + VpAddSub(ff, res, rr, 1); + + *dv = d; + *rv = ff; + return Qnil; +} + +/* call-seq: + * remainder(value) + * + * Returns the remainder from dividing by the value. + * + * x.remainder(y) means x-y*(x/y).truncate + */ +static VALUE +BigDecimal_remainder(VALUE self, VALUE r) /* remainder */ +{ + VALUE f; + Real *d, *rv = 0; + f = BigDecimal_divremain(self, r, &d, &rv); + if (!NIL_P(f)) return f; + return VpCheckGetValue(rv); +} + +/* call-seq: + * divmod(value) + * + * Divides by the specified value, and returns the quotient and modulus + * as BigDecimal numbers. The quotient is rounded towards negative infinity. + * + * For example: + * + * require 'bigdecimal' + * + * a = BigDecimal("42") + * b = BigDecimal("9") + * + * q, m = a.divmod(b) + * + * c = q * b + m + * + * a == c #=> true + * + * The quotient q is (a/b).floor, and the modulus is the amount that must be + * added to q * b to get a. + */ +static VALUE +BigDecimal_divmod(VALUE self, VALUE r) +{ + ENTER(5); + Real *div = NULL, *mod = NULL; + + if (BigDecimal_DoDivmod(self, r, &div, &mod)) { + SAVE(div); SAVE(mod); + return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod)); + } + return DoSomeOne(self,r,rb_intern("divmod")); +} + +/* + * Do the same manner as Float#div when n is nil. + * Do the same manner as BigDecimal#quo when n is 0. + */ +static inline VALUE +BigDecimal_div2(VALUE self, VALUE b, VALUE n) +{ + ENTER(5); + SIGNED_VALUE ix; + + if (NIL_P(n)) { /* div in Float sense */ + Real *div = NULL; + Real *mod; + if (BigDecimal_DoDivmod(self, b, &div, &mod)) { + return BigDecimal_to_i(VpCheckGetValue(div)); + } + return DoSomeOne(self, b, rb_intern("div")); + } + + /* div in BigDecimal sense */ + ix = check_int_precision(n); + if (ix == 0) { + return BigDecimal_div(self, b); + } + else { + Real *res = NULL; + Real *av = NULL, *bv = NULL, *cv = NULL; + size_t mx = ix + VpBaseFig()*2; + size_t b_prec = ix; + size_t pl = VpSetPrecLimit(0); + + GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig())); + GUARD_OBJ(av, GetVpValue(self, 1)); + /* TODO: I want to refactor this precision control for a float value later + * by introducing an implicit conversion function instead of + * GetVpValueWithPrec. */ + if (RB_FLOAT_TYPE_P(b) && b_prec > BIGDECIMAL_DOUBLE_FIGURES) { + b_prec = BIGDECIMAL_DOUBLE_FIGURES; + } + GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1)); + mx = av->Prec + bv->Prec + 2; + if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1; + GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig())); + VpDivd(cv, res, av, bv); + VpSetPrecLimit(pl); + VpLeftRound(cv, VpGetRoundMode(), ix); + return VpCheckGetValue(cv); + } +} + + /* + * Document-method: BigDecimal#div + * + * call-seq: + * div(value) -> integer + * div(value, digits) -> bigdecimal or integer + * + * Divide by the specified value. + * + * digits:: If specified and less than the number of significant digits of the + * result, the result is rounded to that number of digits, according + * to BigDecimal.mode. + * + * If digits is 0, the result is the same as for the / operator + * or #quo. + * + * If digits is not specified, the result is an integer, + * by analogy with Float#div; see also BigDecimal#divmod. + * + * See BigDecimal#/. + * See BigDecimal#quo. + * + * Examples: + * + * a = BigDecimal("4") + * b = BigDecimal("3") + * + * a.div(b, 3) # => 0.133e1 + * + * a.div(b, 0) # => 0.1333333333333333333e1 + * a / b # => 0.1333333333333333333e1 + * a.quo(b) # => 0.1333333333333333333e1 + * + * a.div(b) # => 1 + */ +static VALUE +BigDecimal_div3(int argc, VALUE *argv, VALUE self) +{ + VALUE b,n; + + rb_scan_args(argc, argv, "11", &b, &n); + + return BigDecimal_div2(self, b, n); +} + + /* + * call-seq: + * add(value, ndigits) -> new_bigdecimal + * + * Returns the \BigDecimal sum of +self+ and +value+ + * with a precision of +ndigits+ decimal digits. + * + * When +ndigits+ is less than the number of significant digits + * in the sum, the sum is rounded to that number of digits, + * according to the current rounding mode; see BigDecimal.mode. + * + * Examples: + * + * # Set the rounding mode. + * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up) + * b = BigDecimal('111111.111') + * b.add(1, 0) # => 0.111112111e6 + * b.add(1, 3) # => 0.111e6 + * b.add(1, 6) # => 0.111112e6 + * b.add(1, 15) # => 0.111112111e6 + * b.add(1.0, 15) # => 0.111112111e6 + * b.add(Rational(1, 1), 15) # => 0.111112111e6 + * + */ + +static VALUE +BigDecimal_add2(VALUE self, VALUE b, VALUE n) +{ + ENTER(2); + Real *cv; + SIGNED_VALUE mx = check_int_precision(n); + if (mx == 0) return BigDecimal_add(self, b); + else { + size_t pl = VpSetPrecLimit(0); + VALUE c = BigDecimal_add(self, b); + VpSetPrecLimit(pl); + GUARD_OBJ(cv, GetVpValue(c, 1)); + VpLeftRound(cv, VpGetRoundMode(), mx); + return VpCheckGetValue(cv); + } +} + +/* call-seq: + * sub(value, digits) -> bigdecimal + * + * Subtract the specified value. + * + * e.g. + * c = a.sub(b,n) + * + * digits:: If specified and less than the number of significant digits of the + * result, the result is rounded to that number of digits, according + * to BigDecimal.mode. + * + */ +static VALUE +BigDecimal_sub2(VALUE self, VALUE b, VALUE n) +{ + ENTER(2); + Real *cv; + SIGNED_VALUE mx = check_int_precision(n); + if (mx == 0) return BigDecimal_sub(self, b); + else { + size_t pl = VpSetPrecLimit(0); + VALUE c = BigDecimal_sub(self, b); + VpSetPrecLimit(pl); + GUARD_OBJ(cv, GetVpValue(c, 1)); + VpLeftRound(cv, VpGetRoundMode(), mx); + return VpCheckGetValue(cv); + } +} + + /* + * call-seq: + * mult(other, ndigits) -> bigdecimal + * + * Returns the \BigDecimal product of +self+ and +value+ + * with a precision of +ndigits+ decimal digits. + * + * When +ndigits+ is less than the number of significant digits + * in the sum, the sum is rounded to that number of digits, + * according to the current rounding mode; see BigDecimal.mode. + * + * Examples: + * + * # Set the rounding mode. + * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up) + * b = BigDecimal('555555.555') + * b.mult(3, 0) # => 0.1666666665e7 + * b.mult(3, 3) # => 0.167e7 + * b.mult(3, 6) # => 0.166667e7 + * b.mult(3, 15) # => 0.1666666665e7 + * b.mult(3.0, 0) # => 0.1666666665e7 + * b.mult(Rational(3, 1), 0) # => 0.1666666665e7 + * b.mult(Complex(3, 0), 0) # => (0.1666666665e7+0.0i) + * + */ + +static VALUE +BigDecimal_mult2(VALUE self, VALUE b, VALUE n) +{ + ENTER(2); + Real *cv; + SIGNED_VALUE mx = check_int_precision(n); + if (mx == 0) return BigDecimal_mult(self, b); + else { + size_t pl = VpSetPrecLimit(0); + VALUE c = BigDecimal_mult(self, b); + VpSetPrecLimit(pl); + GUARD_OBJ(cv, GetVpValue(c, 1)); + VpLeftRound(cv, VpGetRoundMode(), mx); + return VpCheckGetValue(cv); + } +} + +/* + * call-seq: + * abs -> bigdecimal + * + * Returns the \BigDecimal absolute value of +self+: + * + * BigDecimal('5').abs # => 0.5e1 + * BigDecimal('-3').abs # => 0.3e1 + * + */ + +static VALUE +BigDecimal_abs(VALUE self) +{ + ENTER(5); + Real *c, *a; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec *(VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpAsgn(c, a, 1); + VpChangeSign(c, 1); + return VpCheckGetValue(c); +} + +/* call-seq: + * sqrt(n) + * + * Returns the square root of the value. + * + * Result has at least n significant digits. + */ +static VALUE +BigDecimal_sqrt(VALUE self, VALUE nFig) +{ + ENTER(5); + Real *c, *a; + size_t mx, n; + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + + n = check_int_precision(nFig); + n += VpDblFig() + VpBaseFig(); + if (mx <= n) mx = n; + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpSqrt(c, a); + return VpCheckGetValue(c); +} + +/* Return the integer part of the number, as a BigDecimal. + */ +static VALUE +BigDecimal_fix(VALUE self) +{ + ENTER(5); + Real *c, *a; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec *(VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */ + return VpCheckGetValue(c); +} + +/* call-seq: + * round(n, mode) + * + * Round to the nearest integer (by default), returning the result as a + * BigDecimal if n is specified and positive, or as an Integer if it isn't. + * + * BigDecimal('3.14159').round #=> 3 + * BigDecimal('8.7').round #=> 9 + * BigDecimal('-9.9').round #=> -10 + * + * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal" + * BigDecimal('3.14159').round.class.name #=> "Integer" + * BigDecimal('3.14159').round(0).class.name #=> "Integer" + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that many digits to the left of the + * decimal point will be 0 in the result, and return value will be an Integer. + * + * BigDecimal('3.14159').round(3) #=> 3.142 + * BigDecimal('13345.234').round(-2) #=> 13300 + * + * The value of the optional mode argument can be used to determine how + * rounding is performed; see BigDecimal.mode. + */ +static VALUE +BigDecimal_round(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + Real *c, *a; + int iLoc = 0; + VALUE vLoc; + VALUE vRound; + int round_to_int = 0; + size_t mx, pl; + + unsigned short sw = VpGetRoundMode(); + + switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) { + case 0: + iLoc = 0; + round_to_int = 1; + break; + case 1: + if (RB_TYPE_P(vLoc, T_HASH)) { + sw = check_rounding_mode_option(vLoc); + } + else { + iLoc = NUM2INT(vLoc); + if (iLoc < 1) round_to_int = 1; + } + break; + case 2: + iLoc = NUM2INT(vLoc); + if (RB_TYPE_P(vRound, T_HASH)) { + sw = check_rounding_mode_option(vRound); + } + else { + sw = check_rounding_mode(vRound); + } + break; + default: + break; + } + + pl = VpSetPrecLimit(0); + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpSetPrecLimit(pl); + VpActiveRound(c, a, sw, iLoc); + if (round_to_int) { + return BigDecimal_to_i(VpCheckGetValue(c)); + } + return VpCheckGetValue(c); +} + +/* call-seq: + * truncate(n) + * + * Truncate to the nearest integer (by default), returning the result as a + * BigDecimal. + * + * BigDecimal('3.14159').truncate #=> 3 + * BigDecimal('8.7').truncate #=> 8 + * BigDecimal('-9.9').truncate #=> -9 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that many digits to the left of the + * decimal point will be 0 in the result. + * + * BigDecimal('3.14159').truncate(3) #=> 3.141 + * BigDecimal('13345.234').truncate(-2) #=> 13300.0 + */ +static VALUE +BigDecimal_truncate(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + Real *c, *a; + int iLoc; + VALUE vLoc; + size_t mx, pl = VpSetPrecLimit(0); + + if (rb_scan_args(argc, argv, "01", &vLoc) == 0) { + iLoc = 0; + } + else { + iLoc = NUM2INT(vLoc); + } + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpSetPrecLimit(pl); + VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */ + if (argc == 0) { + return BigDecimal_to_i(VpCheckGetValue(c)); + } + return VpCheckGetValue(c); +} + +/* Return the fractional part of the number, as a BigDecimal. + */ +static VALUE +BigDecimal_frac(VALUE self) +{ + ENTER(5); + Real *c, *a; + size_t mx; + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpFrac(c, a); + return VpCheckGetValue(c); +} + +/* call-seq: + * floor(n) + * + * Return the largest integer less than or equal to the value, as a BigDecimal. + * + * BigDecimal('3.14159').floor #=> 3 + * BigDecimal('-9.1').floor #=> -10 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that + * many digits to the left of the decimal point will be 0 in the result. + * + * BigDecimal('3.14159').floor(3) #=> 3.141 + * BigDecimal('13345.234').floor(-2) #=> 13300.0 + */ +static VALUE +BigDecimal_floor(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + Real *c, *a; + int iLoc; + VALUE vLoc; + size_t mx, pl = VpSetPrecLimit(0); + + if (rb_scan_args(argc, argv, "01", &vLoc)==0) { + iLoc = 0; + } + else { + iLoc = NUM2INT(vLoc); + } + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpSetPrecLimit(pl); + VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc); +#ifdef BIGDECIMAL_DEBUG + VPrint(stderr, "floor: c=%\n", c); +#endif + if (argc == 0) { + return BigDecimal_to_i(VpCheckGetValue(c)); + } + return VpCheckGetValue(c); +} + +/* call-seq: + * ceil(n) + * + * Return the smallest integer greater than or equal to the value, as a BigDecimal. + * + * BigDecimal('3.14159').ceil #=> 4 + * BigDecimal('-9.1').ceil #=> -9 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that + * many digits to the left of the decimal point will be 0 in the result. + * + * BigDecimal('3.14159').ceil(3) #=> 3.142 + * BigDecimal('13345.234').ceil(-2) #=> 13400.0 + */ +static VALUE +BigDecimal_ceil(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + Real *c, *a; + int iLoc; + VALUE vLoc; + size_t mx, pl = VpSetPrecLimit(0); + + if (rb_scan_args(argc, argv, "01", &vLoc) == 0) { + iLoc = 0; + } else { + iLoc = NUM2INT(vLoc); + } + + GUARD_OBJ(a, GetVpValue(self, 1)); + mx = a->Prec * (VpBaseFig() + 1); + GUARD_OBJ(c, NewZeroWrapLimited(1, mx)); + VpSetPrecLimit(pl); + VpActiveRound(c, a, VP_ROUND_CEIL, iLoc); + if (argc == 0) { + return BigDecimal_to_i(VpCheckGetValue(c)); + } + return VpCheckGetValue(c); +} + +/* call-seq: + * to_s(s) + * + * Converts the value to a string. + * + * The default format looks like 0.xxxxEnn. + * + * The optional parameter s consists of either an integer; or an optional '+' + * or ' ', followed by an optional number, followed by an optional 'E' or 'F'. + * + * If there is a '+' at the start of s, positive values are returned with + * a leading '+'. + * + * A space at the start of s returns positive values with a leading space. + * + * If s contains a number, a space is inserted after each group of that many + * digits, starting from '.' and counting outwards. + * + * If s ends with an 'E', engineering notation (0.xxxxEnn) is used. + * + * If s ends with an 'F', conventional floating point notation is used. + * + * Examples: + * + * BigDecimal('-1234567890123.45678901234567890').to_s('5F') + * #=> '-123 45678 90123.45678 90123 45678 9' + * + * BigDecimal('1234567890123.45678901234567890').to_s('+8F') + * #=> '+12345 67890123.45678901 23456789' + * + * BigDecimal('1234567890123.45678901234567890').to_s(' F') + * #=> ' 1234567890123.4567890123456789' + */ +static VALUE +BigDecimal_to_s(int argc, VALUE *argv, VALUE self) +{ + ENTER(5); + int fmt = 0; /* 0: E format, 1: F format */ + int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */ + Real *vp; + volatile VALUE str; + char *psz; + char ch; + size_t nc, mc = 0; + SIGNED_VALUE m; + VALUE f; + + GUARD_OBJ(vp, GetVpValue(self, 1)); + + if (rb_scan_args(argc, argv, "01", &f) == 1) { + if (RB_TYPE_P(f, T_STRING)) { + psz = StringValueCStr(f); + if (*psz == ' ') { + fPlus = 1; + psz++; + } + else if (*psz == '+') { + fPlus = 2; + psz++; + } + while ((ch = *psz++) != 0) { + if (ISSPACE(ch)) { + continue; + } + if (!ISDIGIT(ch)) { + if (ch == 'F' || ch == 'f') { + fmt = 1; /* F format */ + } + break; + } + mc = mc*10 + ch - '0'; + } + } + else { + m = NUM2INT(f); + if (m <= 0) { + rb_raise(rb_eArgError, "argument must be positive"); + } + mc = (size_t)m; + } + } + if (fmt) { + nc = VpNumOfChars(vp, "F"); + } + else { + nc = VpNumOfChars(vp, "E"); + } + if (mc > 0) { + nc += (nc + mc - 1) / mc + 1; + } + + str = rb_usascii_str_new(0, nc); + psz = RSTRING_PTR(str); + + if (fmt) { + VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus); + } + else { + VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus); + } + rb_str_resize(str, strlen(psz)); + return str; +} + +/* Splits a BigDecimal number into four parts, returned as an array of values. + * + * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0 + * if the BigDecimal is Not a Number. + * + * The second value is a string representing the significant digits of the + * BigDecimal, with no leading zeros. + * + * The third value is the base used for arithmetic (currently always 10) as an + * Integer. + * + * The fourth value is an Integer exponent. + * + * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the + * string of significant digits with no leading zeros, and n is the exponent. + * + * From these values, you can translate a BigDecimal to a float as follows: + * + * sign, significant_digits, base, exponent = a.split + * f = sign * "0.#{significant_digits}".to_f * (base ** exponent) + * + * (Note that the to_f method is provided as a more convenient way to translate + * a BigDecimal to a Float.) + */ +static VALUE +BigDecimal_split(VALUE self) +{ + ENTER(5); + Real *vp; + VALUE obj,str; + ssize_t e, s; + char *psz1; + + GUARD_OBJ(vp, GetVpValue(self, 1)); + str = rb_str_new(0, VpNumOfChars(vp, "E")); + psz1 = RSTRING_PTR(str); + VpSzMantissa(vp, psz1, RSTRING_LEN(str)); + s = 1; + if(psz1[0] == '-') { + size_t len = strlen(psz1 + 1); + + memmove(psz1, psz1 + 1, len); + psz1[len] = '\0'; + s = -1; + } + if (psz1[0] == 'N') s = 0; /* NaN */ + e = VpExponent10(vp); + obj = rb_ary_new2(4); + rb_ary_push(obj, INT2FIX(s)); + rb_ary_push(obj, str); + rb_str_resize(str, strlen(psz1)); + rb_ary_push(obj, INT2FIX(10)); + rb_ary_push(obj, SSIZET2NUM(e)); + return obj; +} + +/* Returns the exponent of the BigDecimal number, as an Integer. + * + * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string + * of digits with no leading zeros, then n is the exponent. + */ +static VALUE +BigDecimal_exponent(VALUE self) +{ + ssize_t e = VpExponent10(GetVpValue(self, 1)); + return SSIZET2NUM(e); +} + +/* Returns a string representation of self. + * + * BigDecimal("1234.5678").inspect + * #=> "0.12345678e4" + */ +static VALUE +BigDecimal_inspect(VALUE self) +{ + ENTER(5); + Real *vp; + volatile VALUE str; + size_t nc; + + GUARD_OBJ(vp, GetVpValue(self, 1)); + nc = VpNumOfChars(vp, "E"); + + str = rb_str_new(0, nc); + VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0); + rb_str_resize(str, strlen(RSTRING_PTR(str))); + return str; +} + +static VALUE BigMath_s_exp(VALUE, VALUE, VALUE); +static VALUE BigMath_s_log(VALUE, VALUE, VALUE); + +#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n)) +#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n)) + +inline static int +is_integer(VALUE x) +{ + return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM)); +} + +inline static int +is_negative(VALUE x) +{ + if (FIXNUM_P(x)) { + return FIX2LONG(x) < 0; + } + else if (RB_TYPE_P(x, T_BIGNUM)) { + return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0; + } + else if (RB_TYPE_P(x, T_FLOAT)) { + return RFLOAT_VALUE(x) < 0.0; + } + return RTEST(rb_funcall(x, '<', 1, INT2FIX(0))); +} + +#define is_positive(x) (!is_negative(x)) + +inline static int +is_zero(VALUE x) +{ + VALUE num; + + switch (TYPE(x)) { + case T_FIXNUM: + return FIX2LONG(x) == 0; + + case T_BIGNUM: + return Qfalse; + + case T_RATIONAL: + num = rb_rational_num(x); + return FIXNUM_P(num) && FIX2LONG(num) == 0; + + default: + break; + } + + return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0))); +} + +inline static int +is_one(VALUE x) +{ + VALUE num, den; + + switch (TYPE(x)) { + case T_FIXNUM: + return FIX2LONG(x) == 1; + + case T_BIGNUM: + return Qfalse; + + case T_RATIONAL: + num = rb_rational_num(x); + den = rb_rational_den(x); + return FIXNUM_P(den) && FIX2LONG(den) == 1 && + FIXNUM_P(num) && FIX2LONG(num) == 1; + + default: + break; + } + + return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1))); +} + +inline static int +is_even(VALUE x) +{ + switch (TYPE(x)) { + case T_FIXNUM: + return (FIX2LONG(x) % 2) == 0; + + case T_BIGNUM: + { + unsigned long l; + rb_big_pack(x, &l, 1); + return l % 2 == 0; + } + + default: + break; + } + + return 0; +} + +static VALUE +bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n) +{ + VALUE log_x, multiplied, y; + volatile VALUE obj = exp->obj; + + if (VpIsZero(exp)) { + return VpCheckGetValue(NewOneWrapLimited(1, n)); + } + + log_x = BigMath_log(x->obj, SSIZET2NUM(n+1)); + multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1)); + y = BigMath_exp(multiplied, SSIZET2NUM(n)); + RB_GC_GUARD(obj); + + return y; +} + +/* call-seq: + * power(n) + * power(n, prec) + * + * Returns the value raised to the power of n. + * + * Note that n must be an Integer. + * + * Also available as the operator **. + */ +static VALUE +BigDecimal_power(int argc, VALUE*argv, VALUE self) +{ + ENTER(5); + VALUE vexp, prec; + Real* exp = NULL; + Real *x, *y; + ssize_t mp, ma, n; + SIGNED_VALUE int_exp; + double d; + + rb_scan_args(argc, argv, "11", &vexp, &prec); + + GUARD_OBJ(x, GetVpValue(self, 1)); + n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec); + + if (VpIsNaN(x)) { + y = NewZeroWrapLimited(1, n); + VpSetNaN(y); + RB_GC_GUARD(y->obj); + return VpCheckGetValue(y); + } + + retry: + switch (TYPE(vexp)) { + case T_FIXNUM: + break; + + case T_BIGNUM: + break; + + case T_FLOAT: + d = RFLOAT_VALUE(vexp); + if (d == round(d)) { + if (FIXABLE(d)) { + vexp = LONG2FIX((long)d); + } + else { + vexp = rb_dbl2big(d); + } + goto retry; + } + if (NIL_P(prec)) { + n += BIGDECIMAL_DOUBLE_FIGURES; + } + exp = GetVpValueWithPrec(vexp, 0, 1); + break; + + case T_RATIONAL: + if (is_zero(rb_rational_num(vexp))) { + if (is_positive(vexp)) { + vexp = INT2FIX(0); + goto retry; + } + } + else if (is_one(rb_rational_den(vexp))) { + vexp = rb_rational_num(vexp); + goto retry; + } + exp = GetVpValueWithPrec(vexp, n, 1); + if (NIL_P(prec)) { + n += n; + } + break; + + case T_DATA: + if (is_kind_of_BigDecimal(vexp)) { + VALUE zero = INT2FIX(0); + VALUE rounded = BigDecimal_round(1, &zero, vexp); + if (RTEST(BigDecimal_eq(vexp, rounded))) { + vexp = BigDecimal_to_i(vexp); + goto retry; + } + if (NIL_P(prec)) { + GUARD_OBJ(y, GetVpValue(vexp, 1)); + n += y->Prec*VpBaseFig(); + } + exp = DATA_PTR(vexp); + break; + } + /* fall through */ + default: + rb_raise(rb_eTypeError, + "wrong argument type %"PRIsVALUE" (expected scalar Numeric)", + RB_OBJ_CLASSNAME(vexp)); + } + + if (VpIsZero(x)) { + if (is_negative(vexp)) { + y = NewZeroWrapNolimit(1, n); + if (BIGDECIMAL_NEGATIVE_P(x)) { + if (is_integer(vexp)) { + if (is_even(vexp)) { + /* (-0) ** (-even_integer) -> Infinity */ + VpSetPosInf(y); + } + else { + /* (-0) ** (-odd_integer) -> -Infinity */ + VpSetNegInf(y); + } + } + else { + /* (-0) ** (-non_integer) -> Infinity */ + VpSetPosInf(y); + } + } + else { + /* (+0) ** (-num) -> Infinity */ + VpSetPosInf(y); + } + RB_GC_GUARD(y->obj); + return VpCheckGetValue(y); + } + else if (is_zero(vexp)) { + return VpCheckGetValue(NewOneWrapLimited(1, n)); + } + else { + return VpCheckGetValue(NewZeroWrapLimited(1, n)); + } + } + + if (is_zero(vexp)) { + return VpCheckGetValue(NewOneWrapLimited(1, n)); + } + else if (is_one(vexp)) { + return self; + } + + if (VpIsInf(x)) { + if (is_negative(vexp)) { + if (BIGDECIMAL_NEGATIVE_P(x)) { + if (is_integer(vexp)) { + if (is_even(vexp)) { + /* (-Infinity) ** (-even_integer) -> +0 */ + return VpCheckGetValue(NewZeroWrapLimited(1, n)); + } + else { + /* (-Infinity) ** (-odd_integer) -> -0 */ + return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + } + } + else { + /* (-Infinity) ** (-non_integer) -> -0 */ + return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + } + } + else { + return VpCheckGetValue(NewZeroWrapLimited(1, n)); + } + } + else { + y = NewZeroWrapLimited(1, n); + if (BIGDECIMAL_NEGATIVE_P(x)) { + if (is_integer(vexp)) { + if (is_even(vexp)) { + VpSetPosInf(y); + } + else { + VpSetNegInf(y); + } + } + else { + /* TODO: support complex */ + rb_raise(rb_eMathDomainError, + "a non-integral exponent for a negative base"); + } + } + else { + VpSetPosInf(y); + } + return VpCheckGetValue(y); + } + } + + if (exp != NULL) { + return bigdecimal_power_by_bigdecimal(x, exp, n); + } + else if (RB_TYPE_P(vexp, T_BIGNUM)) { + VALUE abs_value = BigDecimal_abs(self); + if (is_one(abs_value)) { + return VpCheckGetValue(NewOneWrapLimited(1, n)); + } + else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) { + if (is_negative(vexp)) { + y = NewZeroWrapLimited(1, n); + VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x)); + return VpCheckGetValue(y); + } + else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) { + return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + } + else { + return VpCheckGetValue(NewZeroWrapLimited(1, n)); + } + } + else { + if (is_positive(vexp)) { + y = NewZeroWrapLimited(1, n); + VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x)); + return VpCheckGetValue(y); + } + else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) { + return VpCheckGetValue(NewZeroWrapLimited(-1, n)); + } + else { + return VpCheckGetValue(NewZeroWrapLimited(1, n)); + } + } + } + + int_exp = FIX2LONG(vexp); + ma = int_exp; + if (ma < 0) ma = -ma; + if (ma == 0) ma = 1; + + if (VpIsDef(x)) { + mp = x->Prec * (VpBaseFig() + 1); + GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1))); + } + else { + GUARD_OBJ(y, NewZeroWrapLimited(1, 1)); + } + VpPowerByInt(y, x, int_exp); + if (!NIL_P(prec) && VpIsDef(y)) { + VpMidRound(y, VpGetRoundMode(), n); + } + return VpCheckGetValue(y); +} + +/* call-seq: + * self ** other -> bigdecimal + * + * Returns the \BigDecimal value of +self+ raised to power +other+: + * + * b = BigDecimal('3.14') + * b ** 2 # => 0.98596e1 + * b ** 2.0 # => 0.98596e1 + * b ** Rational(2, 1) # => 0.98596e1 + * + * Related: BigDecimal#power. + * + */ +static VALUE +BigDecimal_power_op(VALUE self, VALUE exp) +{ + return BigDecimal_power(1, &exp, self); +} + +/* :nodoc: + * + * private method for dup and clone the provided BigDecimal +other+ + */ +static VALUE +BigDecimal_initialize_copy(VALUE self, VALUE other) +{ + Real *pv = rb_check_typeddata(self, &BigDecimal_data_type); + Real *x = rb_check_typeddata(other, &BigDecimal_data_type); + + if (self != other) { + DATA_PTR(self) = VpCopy(pv, x); + } + return self; +} + +/* :nodoc: */ +static VALUE +BigDecimal_clone(VALUE self) +{ + return self; +} + +#ifdef HAVE_RB_OPTS_EXCEPTION_P +int rb_opts_exception_p(VALUE opts, int default_value); +#define opts_exception_p(opts) rb_opts_exception_p((opts), 1) +#else +static int +opts_exception_p(VALUE opts) +{ + static ID kwds[1]; + VALUE exception; + if (!kwds[0]) { + kwds[0] = rb_intern_const("exception"); + } + if (!rb_get_kwargs(opts, kwds, 0, 1, &exception)) return 1; + switch (exception) { + case Qtrue: case Qfalse: + break; + default: + rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE, + exception); + } + return exception != Qfalse; +} +#endif + +static VALUE +check_exception(VALUE bd) +{ + assert(is_kind_of_BigDecimal(bd)); + + Real *vp; + TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp); + VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */ + + return bd; +} + +static VALUE +rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception) +{ + VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0); + + Real *vp; + if (uval == 0) { + vp = rbd_allocate_struct(1); + vp->MaxPrec = 1; + vp->Prec = 1; + vp->exponent = 1; + VpSetZero(vp, 1); + vp->frac[0] = 0; + } + else if (uval < BASE) { + vp = rbd_allocate_struct(1); + vp->MaxPrec = 1; + vp->Prec = 1; + vp->exponent = 1; + VpSetSign(vp, 1); + vp->frac[0] = (DECDIG)uval; + } + else { + DECDIG buf[BIGDECIMAL_INT64_MAX_LENGTH] = {0,}; + DECDIG r = uval % BASE; + size_t len = 0, ntz = 0; + if (r == 0) { + // Count and skip trailing zeros + for (; r == 0 && uval > 0; ++ntz) { + uval /= BASE; + r = uval % BASE; + } + } + for (; uval > 0; ++len) { + // Store digits + buf[BIGDECIMAL_INT64_MAX_LENGTH - len - 1] = r; + uval /= BASE; + r = uval % BASE; + } + + const size_t exp = len + ntz; + vp = rbd_allocate_struct(len); + vp->MaxPrec = len; + vp->Prec = len; + vp->exponent = exp; + VpSetSign(vp, 1); + MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len); + } + + return BigDecimal_wrap_struct(obj, vp); +} + +static VALUE +rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception) +{ + const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival; + VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception); + if (ival < 0) { + Real *vp; + TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp); + VpSetSign(vp, -1); + } + return bd; +} + +static VALUE +rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception) +{ + assert(RB_TYPE_P(val, T_BIGNUM)); + + int leading_zeros; + size_t size = rb_absint_size(val, &leading_zeros); + int sign = FIX2INT(rb_big_cmp(val, INT2FIX(0))); + if (sign < 0 && leading_zeros == 0) { + size += 1; + } + if (size <= sizeof(long)) { + if (sign < 0) { + return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception); + } + else { + return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception); + } + } +#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG + else if (size <= sizeof(LONG_LONG)) { + if (sign < 0) { + return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception); + } + else { + return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception); + } + } +#endif + else { + VALUE str = rb_big2str(val, 10); + Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1, + RSTRING_PTR(str), true); + RB_GC_GUARD(str); + return check_exception(vp->obj); + } +} + +static VALUE +rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception) +{ + assert(RB_INTEGER_TYPE_P(val)); + if (FIXNUM_P(val)) { + return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception); + } + else { + return rb_big_convert_to_BigDecimal(val, digs, raise_exception); + } +} + +static VALUE +rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) +{ + assert(RB_FLOAT_TYPE_P(val)); + + double d = RFLOAT_VALUE(val); + + if (isnan(d)) { + VALUE obj = BigDecimal_nan(); + return check_exception(obj); + } + else if (isinf(d)) { + VALUE obj; + if (d > 0) { + obj = BigDecimal_positive_infinity(); + } + else { + obj = BigDecimal_negative_infinity(); + } + return check_exception(obj); + } + else if (d == 0.0) { + if (1/d < 0.0) { + return BigDecimal_negative_zero(); + } + else { + return BigDecimal_positive_zero(); + } + } + + if (digs == SIZE_MAX) { + if (!raise_exception) + return Qnil; + rb_raise(rb_eArgError, + "can't omit precision for a %"PRIsVALUE".", + CLASS_OF(val)); + } + else if (digs > BIGDECIMAL_DOUBLE_FIGURES) { + if (!raise_exception) + return Qnil; + rb_raise(rb_eArgError, "precision too large."); + } + + /* Use the same logic in flo_to_s to convert a float to a decimal string */ + char buf[BIGDECIMAL_DOUBLE_FIGURES + BASE_FIG + 2 + 1]; /* sizeof(buf) == 28 in the typical case */ + int decpt, negative_p; + char *e; + const int mode = digs == 0 ? 0 : 2; + char *p = BigDecimal_dtoa(d, mode, (int)digs, &decpt, &negative_p, &e); + int len10 = (int)(e - p); + if (len10 > BIGDECIMAL_DOUBLE_FIGURES) { + /* TODO: Presumably, rounding should be done here. */ + len10 = BIGDECIMAL_DOUBLE_FIGURES; + } + memcpy(buf, p, len10); + xfree(p); + + VALUE inum; + size_t RB_UNUSED_VAR(prec) = 0; + SIGNED_VALUE exp = 0; + if (decpt > 0) { + if (decpt < len10) { + /* + * len10 |---------------| + * : |-------| frac_len10 = len10 - decpt + * decpt |-------| |--| ntz10 = BASE_FIG - frac_len10 % BASE_FIG + * : : : + * 00 dd dddd.dddd dd 00 + * prec |-----.----.----.-----| prec = exp + roomof(frac_len, BASE_FIG) + * exp |-----.----| exp = roomof(decpt, BASE_FIG) + */ + const size_t frac_len10 = len10 - decpt; + const size_t ntz10 = BASE_FIG - frac_len10 % BASE_FIG; + memset(buf + len10, '0', ntz10); + buf[len10 + ntz10] = '\0'; + inum = rb_cstr_to_inum(buf, 10, false); + + exp = roomof(decpt, BASE_FIG); + prec = exp + roomof(frac_len10, BASE_FIG); + } + else { + /* + * decpt |-----------------------| + * len10 |----------| : + * : |------------| exp10 + * : : : + * 00 dd dddd dd 00 0000 0000.0 + * : : : : + * : |--| ntz10 = exp10 % BASE_FIG + * prec |-----.----.-----| : + * : |----.----| exp10 / BASE_FIG + * exp |-----.----.-----.----.----| + */ + const size_t exp10 = decpt - len10; + const size_t ntz10 = exp10 % BASE_FIG; + + memset(buf + len10, '0', ntz10); + buf[len10 + ntz10] = '\0'; + inum = rb_cstr_to_inum(buf, 10, false); + + prec = roomof(len10 + ntz10, BASE_FIG); + exp = prec + exp10 / BASE_FIG; + } + } + else if (decpt == 0) { + /* + * len10 |------------| + * : : + * 0.dddd dddd dd 00 + * : : : + * : |--| ntz10 = prec * BASE_FIG - len10 + * prec |----.----.-----| roomof(len10, BASE_FIG) + */ + prec = roomof(len10, BASE_FIG); + const size_t ntz10 = prec * BASE_FIG - len10; + + memset(buf + len10, '0', ntz10); + buf[len10 + ntz10] = '\0'; + inum = rb_cstr_to_inum(buf, 10, false); + } + else { + /* + * len10 |---------------| + * : : + * decpt |-------| |--| ntz10 = prec * BASE_FIG - nlz10 - len10 + * : : : + * 0.0000 00 dd dddd dddd dd 00 + * : : : + * nlz10 |--| : decpt % BASE_FIG + * prec |-----.----.----.-----| roomof(decpt + len10, BASE_FIG) - exp + * exp |----| decpt / BASE_FIG + */ + decpt = -decpt; + + const size_t nlz10 = decpt % BASE_FIG; + exp = decpt / BASE_FIG; + prec = roomof(decpt + len10, BASE_FIG) - exp; + const size_t ntz10 = prec * BASE_FIG - nlz10 - len10; + + if (nlz10 > 0) { + memmove(buf + nlz10, buf, len10); + memset(buf, '0', nlz10); + } + memset(buf + nlz10 + len10, '0', ntz10); + buf[nlz10 + len10 + ntz10] = '\0'; + inum = rb_cstr_to_inum(buf, 10, false); + + exp = -exp; + } + + VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception); + Real *vp; + TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp); + assert(vp->Prec == prec); + vp->exponent = exp; + + if (negative_p) VpSetSign(vp, -1); + return bd; +} + +static VALUE +rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) +{ + assert(RB_TYPE_P(val, T_RATIONAL)); + + if (digs == SIZE_MAX) { + if (!raise_exception) + return Qnil; + rb_raise(rb_eArgError, + "can't omit precision for a %"PRIsVALUE".", + CLASS_OF(val)); + } + + VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception); + VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs)); + return d; +} + +static VALUE +rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception) +{ + if (digs == SIZE_MAX) + digs = 0; + + Real *vp = VpCreateRbObject(digs, c_str, raise_exception); + if (!vp) + return Qnil; + return VpCheckGetValue(vp); +} + +static inline VALUE +rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) +{ + const char *c_str = StringValueCStr(val); + return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception); +} + +static VALUE +rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) +{ + switch (val) { + case Qnil: + case Qtrue: + case Qfalse: + if (raise_exception) { + const char *cname = NIL_P(val) ? "nil" : + val == Qtrue ? "true" : + val == Qfalse ? "false" : + NULL; + rb_raise(rb_eTypeError, + "can't convert %s into BigDecimal", cname); + } + return Qnil; + + default: + break; + } + + if (is_kind_of_BigDecimal(val)) { + if (digs == SIZE_MAX) + return check_exception(val); + + Real *vp; + TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp); + + VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0); + vp = VpCopy(NULL, vp); + /* TODO: rounding */ + BigDecimal_wrap_struct(copy, vp); + return VpCheckGetValue(vp); + } + else if (RB_INTEGER_TYPE_P(val)) { + return rb_inum_convert_to_BigDecimal(val, digs, raise_exception); + } + else if (RB_FLOAT_TYPE_P(val)) { + return rb_float_convert_to_BigDecimal(val, digs, raise_exception); + } + else if (RB_TYPE_P(val, T_RATIONAL)) { + return rb_rational_convert_to_BigDecimal(val, digs, raise_exception); + } + else if (RB_TYPE_P(val, T_COMPLEX)) { + VALUE im = rb_complex_imag(val); + if (!is_zero(im)) { + /* TODO: handle raise_exception */ + rb_raise(rb_eArgError, + "Unable to make a BigDecimal from non-zero imaginary number"); + } + return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception); + } + else if (RB_TYPE_P(val, T_STRING)) { + return rb_str_convert_to_BigDecimal(val, digs, raise_exception); + } + + /* TODO: chheck to_d */ + /* TODO: chheck to_int */ + + VALUE str = rb_check_convert_type(val, T_STRING, "String", "to_str"); + if (!RB_TYPE_P(str, T_STRING)) { + if (raise_exception) { + rb_raise(rb_eTypeError, + "can't convert %"PRIsVALUE" into BigDecimal", rb_obj_class(val)); + } + return Qnil; + } + return rb_str_convert_to_BigDecimal(str, digs, raise_exception); +} + +/* call-seq: + * BigDecimal(value, exception: true) -> bigdecimal + * BigDecimal(value, ndigits, exception: true) -> bigdecimal + * + * Returns the \BigDecimal converted from +value+ + * with a precision of +ndigits+ decimal digits. + * + * When +ndigits+ is less than the number of significant digits + * in the value, the result is rounded to that number of digits, + * according to the current rounding mode; see BigDecimal.mode. + * + * When +ndigits+ is 0, the number of digits to correctly represent a float number + * is determined automatically. + * + * Returns +value+ converted to a \BigDecimal, depending on the type of +value+: + * + * - Integer, Float, Rational, Complex, or BigDecimal: converted directly: + * + * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given. + * BigDecimal(2) # => 0.2e1 + * BigDecimal(Complex(2, 0)) # => 0.2e1 + * BigDecimal(BigDecimal(2)) # => 0.2e1 + * # Float or Rational value requires ndigits. + * BigDecimal(2.0, 0) # => 0.2e1 + * BigDecimal(Rational(2, 1), 0) # => 0.2e1 + * + * - String: converted by parsing if it contains an integer or floating-point literal; + * leading and trailing whitespace is ignored: + * + * # String does not require ndigits; ignored if given. + * BigDecimal('2') # => 0.2e1 + * BigDecimal('2.0') # => 0.2e1 + * BigDecimal('0.2e1') # => 0.2e1 + * BigDecimal(' 2.0 ') # => 0.2e1 + * + * - Other type that responds to method :to_str: + * first converted to a string, then converted to a \BigDecimal, as above. + * + * - Other type: + * + * - Raises an exception if keyword argument +exception+ is +true+. + * - Returns +nil+ if keyword argument +exception+ is +false+. + * + * Raises an exception if +value+ evaluates to a Float + * and +digits+ is larger than Float::DIG + 1. + * + */ +static VALUE +f_BigDecimal(int argc, VALUE *argv, VALUE self) +{ + VALUE val, digs_v, opts = Qnil; + argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts); + int exception = opts_exception_p(opts); + + size_t digs = SIZE_MAX; /* this means digs is omitted */ + if (argc > 1) { + digs_v = rb_to_int(digs_v); + if (FIXNUM_P(digs_v)) { + long n = FIX2LONG(digs_v); + if (n < 0) + goto negative_digs; + digs = (size_t)n; + } + else { + if (RBIGNUM_NEGATIVE_P(digs_v)) { + negative_digs: + if (!exception) + return Qnil; + rb_raise(rb_eArgError, "negative precision"); + } + digs = NUM2SIZET(digs_v); + } + } + + return rb_convert_to_BigDecimal(val, digs, exception); +} + +/* call-seq: + * BigDecimal.interpret_loosely(string) -> bigdecimal + * + * Returns the +BigDecimal+ converted loosely from +string+. + */ + +static VALUE +BigDecimal_s_interpret_loosely(VALUE klass, VALUE str) +{ + char const *c_str = StringValueCStr(str); + Real *vp = VpNewRbClass(0, c_str, klass, false, true); + if (!vp) + return Qnil; + else + return VpCheckGetValue(vp); +} + + /* call-seq: + * BigDecimal.limit(digits) + * + * Limit the number of significant digits in newly created BigDecimal + * numbers to the specified value. Rounding is performed as necessary, + * as specified by BigDecimal.mode. + * + * A limit of 0, the default, means no upper limit. + * + * The limit specified by this method takes less priority over any limit + * specified to instance methods such as ceil, floor, truncate, or round. + */ +static VALUE +BigDecimal_limit(int argc, VALUE *argv, VALUE self) +{ + VALUE nFig; + VALUE nCur = SIZET2NUM(VpGetPrecLimit()); + + if (rb_scan_args(argc, argv, "01", &nFig) == 1) { + int nf; + if (NIL_P(nFig)) return nCur; + nf = NUM2INT(nFig); + if (nf < 0) { + rb_raise(rb_eArgError, "argument must be positive"); + } + VpSetPrecLimit(nf); + } + return nCur; +} + +/* Returns the sign of the value. + * + * Returns a positive value if > 0, a negative value if < 0. + * It behaves the same with zeros - + * it returns a positive value for a positive zero (BigDecimal('0')) and + * a negative value for a negative zero (BigDecimal('-0')). + * + * The specific value returned indicates the type and sign of the BigDecimal, + * as follows: + * + * BigDecimal::SIGN_NaN:: value is Not a Number + * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0 + * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0 + * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +Infinity + * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -Infinity + * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive + * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative + */ +static VALUE +BigDecimal_sign(VALUE self) +{ /* sign */ + int s = GetVpValue(self, 1)->sign; + return INT2FIX(s); +} + +/* + * call-seq: BigDecimal.save_exception_mode { ... } + * + * Execute the provided block, but preserve the exception mode + * + * BigDecimal.save_exception_mode do + * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + * + * BigDecimal(BigDecimal('Infinity')) + * BigDecimal(BigDecimal('-Infinity')) + * BigDecimal(BigDecimal('NaN')) + * end + * + * For use with the BigDecimal::EXCEPTION_* + * + * See BigDecimal.mode + */ +static VALUE +BigDecimal_save_exception_mode(VALUE self) +{ + unsigned short const exception_mode = VpGetException(); + int state; + VALUE ret = rb_protect(rb_yield, Qnil, &state); + VpSetException(exception_mode); + if (state) rb_jump_tag(state); + return ret; +} + +/* + * call-seq: BigDecimal.save_rounding_mode { ... } + * + * Execute the provided block, but preserve the rounding mode + * + * BigDecimal.save_rounding_mode do + * BigDecimal.mode(BigDecimal::ROUND_MODE, :up) + * puts BigDecimal.mode(BigDecimal::ROUND_MODE) + * end + * + * For use with the BigDecimal::ROUND_* + * + * See BigDecimal.mode + */ +static VALUE +BigDecimal_save_rounding_mode(VALUE self) +{ + unsigned short const round_mode = VpGetRoundMode(); + int state; + VALUE ret = rb_protect(rb_yield, Qnil, &state); + VpSetRoundMode(round_mode); + if (state) rb_jump_tag(state); + return ret; +} + +/* + * call-seq: BigDecimal.save_limit { ... } + * + * Execute the provided block, but preserve the precision limit + * + * BigDecimal.limit(100) + * puts BigDecimal.limit + * BigDecimal.save_limit do + * BigDecimal.limit(200) + * puts BigDecimal.limit + * end + * puts BigDecimal.limit + * + */ +static VALUE +BigDecimal_save_limit(VALUE self) +{ + size_t const limit = VpGetPrecLimit(); + int state; + VALUE ret = rb_protect(rb_yield, Qnil, &state); + VpSetPrecLimit(limit); + if (state) rb_jump_tag(state); + return ret; +} + +/* call-seq: + * BigMath.exp(decimal, numeric) -> BigDecimal + * + * Computes the value of e (the base of natural logarithms) raised to the + * power of +decimal+, to the specified number of digits of precision. + * + * If +decimal+ is infinity, returns Infinity. + * + * If +decimal+ is NaN, returns NaN. + */ +static VALUE +BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec) +{ + ssize_t prec, n, i; + Real* vx = NULL; + VALUE one, d, y; + int negative = 0; + int infinite = 0; + int nan = 0; + double flo; + + prec = NUM2SSIZET(vprec); + if (prec <= 0) { + rb_raise(rb_eArgError, "Zero or negative precision for exp"); + } + + /* TODO: the following switch statement is almost same as one in the + * BigDecimalCmp function. */ + switch (TYPE(x)) { + case T_DATA: + if (!is_kind_of_BigDecimal(x)) break; + vx = DATA_PTR(x); + negative = BIGDECIMAL_NEGATIVE_P(vx); + infinite = VpIsPosInf(vx) || VpIsNegInf(vx); + nan = VpIsNaN(vx); + break; + + case T_FIXNUM: + /* fall through */ + case T_BIGNUM: + vx = GetVpValue(x, 0); + break; + + case T_FLOAT: + flo = RFLOAT_VALUE(x); + negative = flo < 0; + infinite = isinf(flo); + nan = isnan(flo); + if (!infinite && !nan) { + vx = GetVpValueWithPrec(x, 0, 0); + } + break; + + case T_RATIONAL: + vx = GetVpValueWithPrec(x, prec, 0); + break; + + default: + break; + } + if (infinite) { + if (negative) { + return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1)); + } + else { + Real* vy = NewZeroWrapNolimit(1, prec); + VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE); + RB_GC_GUARD(vy->obj); + return VpCheckGetValue(vy); + } + } + else if (nan) { + Real* vy = NewZeroWrapNolimit(1, prec); + VpSetNaN(vy); + RB_GC_GUARD(vy->obj); + return VpCheckGetValue(vy); + } + else if (vx == NULL) { + cannot_be_coerced_into_BigDecimal(rb_eArgError, x); + } + x = vx->obj; + + n = prec + BIGDECIMAL_DOUBLE_FIGURES; + negative = BIGDECIMAL_NEGATIVE_P(vx); + if (negative) { + VALUE x_zero = INT2NUM(1); + VALUE x_copy = f_BigDecimal(1, &x_zero, klass); + x = BigDecimal_initialize_copy(x_copy, x); + vx = DATA_PTR(x); + VpSetSign(vx, 1); + } + + one = VpCheckGetValue(NewOneWrapLimited(1, 1)); + y = one; + d = y; + i = 1; + + while (!VpIsZero((Real*)DATA_PTR(d))) { + SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y)); + SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d)); + ssize_t m = n - vabs(ey - ed); + + rb_thread_check_ints(); + + if (m <= 0) { + break; + } + else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) { + m = BIGDECIMAL_DOUBLE_FIGURES; + } + + d = BigDecimal_mult(d, x); /* d <- d * x */ + d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */ + y = BigDecimal_add(y, d); /* y <- y + d */ + ++i; /* i <- i + 1 */ + } + + if (negative) { + return BigDecimal_div2(one, y, vprec); + } + else { + vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y))); + return BigDecimal_round(1, &vprec, y); + } + + RB_GC_GUARD(one); + RB_GC_GUARD(x); + RB_GC_GUARD(y); + RB_GC_GUARD(d); +} + +/* call-seq: + * BigMath.log(decimal, numeric) -> BigDecimal + * + * Computes the natural logarithm of +decimal+ to the specified number of + * digits of precision, +numeric+. + * + * If +decimal+ is zero or negative, raises Math::DomainError. + * + * If +decimal+ is positive infinity, returns Infinity. + * + * If +decimal+ is NaN, returns NaN. + */ +static VALUE +BigMath_s_log(VALUE klass, VALUE x, VALUE vprec) +{ + ssize_t prec, n, i; + SIGNED_VALUE expo; + Real* vx = NULL; + VALUE vn, one, two, w, x2, y, d; + int zero = 0; + int negative = 0; + int infinite = 0; + int nan = 0; + double flo; + long fix; + + if (!is_integer(vprec)) { + rb_raise(rb_eArgError, "precision must be an Integer"); + } + + prec = NUM2SSIZET(vprec); + if (prec <= 0) { + rb_raise(rb_eArgError, "Zero or negative precision for exp"); + } + + /* TODO: the following switch statement is almost same as one in the + * BigDecimalCmp function. */ + switch (TYPE(x)) { + case T_DATA: + if (!is_kind_of_BigDecimal(x)) break; + vx = DATA_PTR(x); + zero = VpIsZero(vx); + negative = BIGDECIMAL_NEGATIVE_P(vx); + infinite = VpIsPosInf(vx) || VpIsNegInf(vx); + nan = VpIsNaN(vx); + break; + + case T_FIXNUM: + fix = FIX2LONG(x); + zero = fix == 0; + negative = fix < 0; + goto get_vp_value; + + case T_BIGNUM: + i = FIX2INT(rb_big_cmp(x, INT2FIX(0))); + zero = i == 0; + negative = i < 0; +get_vp_value: + if (zero || negative) break; + vx = GetVpValue(x, 0); + break; + + case T_FLOAT: + flo = RFLOAT_VALUE(x); + zero = flo == 0; + negative = flo < 0; + infinite = isinf(flo); + nan = isnan(flo); + if (!zero && !negative && !infinite && !nan) { + vx = GetVpValueWithPrec(x, 0, 1); + } + break; + + case T_RATIONAL: + zero = RRATIONAL_ZERO_P(x); + negative = RRATIONAL_NEGATIVE_P(x); + if (zero || negative) break; + vx = GetVpValueWithPrec(x, prec, 1); + break; + + case T_COMPLEX: + rb_raise(rb_eMathDomainError, + "Complex argument for BigMath.log"); + + default: + break; + } + if (infinite && !negative) { + Real *vy = NewZeroWrapNolimit(1, prec); + RB_GC_GUARD(vy->obj); + VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE); + return VpCheckGetValue(vy); + } + else if (nan) { + Real* vy = NewZeroWrapNolimit(1, prec); + RB_GC_GUARD(vy->obj); + VpSetNaN(vy); + return VpCheckGetValue(vy); + } + else if (zero || negative) { + rb_raise(rb_eMathDomainError, + "Zero or negative argument for log"); + } + else if (vx == NULL) { + cannot_be_coerced_into_BigDecimal(rb_eArgError, x); + } + x = VpCheckGetValue(vx); + + one = VpCheckGetValue(NewOneWrapLimited(1, 1)); + two = VpCheckGetValue(VpCreateRbObject(1, "2", true)); + + n = prec + BIGDECIMAL_DOUBLE_FIGURES; + vn = SSIZET2NUM(n); + expo = VpExponent10(vx); + if (expo < 0 || expo >= 3) { + char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4]; + snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo); + x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn); + } + else { + expo = 0; + } + w = BigDecimal_sub(x, one); + x = BigDecimal_div2(w, BigDecimal_add(x, one), vn); + x2 = BigDecimal_mult2(x, x, vn); + y = x; + d = y; + i = 1; + while (!VpIsZero((Real*)DATA_PTR(d))) { + SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y)); + SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d)); + ssize_t m = n - vabs(ey - ed); + if (m <= 0) { + break; + } + else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) { + m = BIGDECIMAL_DOUBLE_FIGURES; + } + + x = BigDecimal_mult2(x2, x, vn); + i += 2; + d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m)); + y = BigDecimal_add(y, d); + } + + y = BigDecimal_mult(y, two); + if (expo != 0) { + VALUE log10, vexpo, dy; + log10 = BigMath_s_log(klass, INT2FIX(10), vprec); + vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1)); + dy = BigDecimal_mult(log10, vexpo); + y = BigDecimal_add(y, dy); + } + + RB_GC_GUARD(one); + RB_GC_GUARD(two); + RB_GC_GUARD(vn); + RB_GC_GUARD(x2); + RB_GC_GUARD(y); + RB_GC_GUARD(d); + + return y; +} + +static VALUE BIGDECIMAL_NAN = Qnil; + +static VALUE +BigDecimal_nan(void) +{ + return BIGDECIMAL_NAN; +} + +static VALUE BIGDECIMAL_POSITIVE_INFINITY = Qnil; + +static VALUE +BigDecimal_positive_infinity(void) +{ + return BIGDECIMAL_POSITIVE_INFINITY; +} + +static VALUE BIGDECIMAL_NEGATIVE_INFINITY = Qnil; + +static VALUE +BigDecimal_negative_infinity(void) +{ + return BIGDECIMAL_NEGATIVE_INFINITY; +} + +static VALUE BIGDECIMAL_POSITIVE_ZERO = Qnil; + +static VALUE +BigDecimal_positive_zero(void) +{ + return BIGDECIMAL_POSITIVE_ZERO; +} + +static VALUE BIGDECIMAL_NEGATIVE_ZERO = Qnil; + +static VALUE +BigDecimal_negative_zero(void) +{ + return BIGDECIMAL_NEGATIVE_ZERO; +} + +static inline VALUE +BigDecimal_literal(const char *str) +{ + VALUE arg = rb_str_new_cstr(str); + VALUE val = f_BigDecimal(1, &arg, rb_cBigDecimal); + rb_gc_register_mark_object(val); + return val; +} + +#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val)) + +/* Document-class: BigDecimal + * BigDecimal provides arbitrary-precision floating point decimal arithmetic. + * + * == Introduction + * + * Ruby provides built-in support for arbitrary precision integer arithmetic. + * + * For example: + * + * 42**13 #=> 1265437718438866624512 + * + * BigDecimal provides similar support for very large or very accurate floating + * point numbers. + * + * Decimal arithmetic is also useful for general calculation, because it + * provides the correct answers people expect--whereas normal binary floating + * point arithmetic often introduces subtle errors because of the conversion + * between base 10 and base 2. + * + * For example, try: + * + * sum = 0 + * 10_000.times do + * sum = sum + 0.0001 + * end + * print sum #=> 0.9999999999999062 + * + * and contrast with the output from: + * + * require 'bigdecimal' + * + * sum = BigDecimal("0") + * 10_000.times do + * sum = sum + BigDecimal("0.0001") + * end + * print sum #=> 0.1E1 + * + * Similarly: + * + * (BigDecimal("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true + * + * (1.2 - 1.0) == 0.2 #=> false + * + * == A Note About Precision + * + * For a calculation using a \BigDecimal and another +value+, + * the precision of the result depends on the type of +value+: + * + * - If +value+ is a \Float, + * the precision is Float::DIG + 1. + * - If +value+ is a \Rational, the precision is larger than Float::DIG + 1. + * - If +value+ is a \BigDecimal, the precision is +value+'s precision in the + * internal representation, which is platform-dependent. + * - If +value+ is other object, the precision is determined by the result of +BigDecimal(value)+. + * + * == Special features of accurate decimal arithmetic + * + * Because BigDecimal is more accurate than normal binary floating point + * arithmetic, it requires some special values. + * + * === Infinity + * + * BigDecimal sometimes needs to return infinity, for example if you divide + * a value by zero. + * + * BigDecimal("1.0") / BigDecimal("0.0") #=> Infinity + * BigDecimal("-1.0") / BigDecimal("0.0") #=> -Infinity + * + * You can represent infinite numbers to BigDecimal using the strings + * 'Infinity', '+Infinity' and + * '-Infinity' (case-sensitive) + * + * === Not a Number + * + * When a computation results in an undefined value, the special value +NaN+ + * (for 'not a number') is returned. + * + * Example: + * + * BigDecimal("0.0") / BigDecimal("0.0") #=> NaN + * + * You can also create undefined values. + * + * NaN is never considered to be the same as any other value, even NaN itself: + * + * n = BigDecimal('NaN') + * n == 0.0 #=> false + * n == n #=> false + * + * === Positive and negative zero + * + * If a computation results in a value which is too small to be represented as + * a BigDecimal within the currently specified limits of precision, zero must + * be returned. + * + * If the value which is too small to be represented is negative, a BigDecimal + * value of negative zero is returned. + * + * BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0 + * + * If the value is positive, a value of positive zero is returned. + * + * BigDecimal("1.0") / BigDecimal("Infinity") #=> 0.0 + * + * (See BigDecimal.mode for how to specify limits of precision.) + * + * Note that +-0.0+ and +0.0+ are considered to be the same for the purposes of + * comparison. + * + * Note also that in mathematics, there is no particular concept of negative + * or positive zero; true mathematical zero has no sign. + * + * == bigdecimal/util + * + * When you require +bigdecimal/util+, the #to_d method will be + * available on BigDecimal and the native Integer, Float, Rational, + * and String classes: + * + * require 'bigdecimal/util' + * + * 42.to_d # => 0.42e2 + * 0.5.to_d # => 0.5e0 + * (2/3r).to_d(3) # => 0.667e0 + * "0.5".to_d # => 0.5e0 + * + * == Methods for Working with \JSON + * + * - {::json_create}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-c-json_create]: + * Returns a new \BigDecimal object constructed from the given object. + * - {#as_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-as_json]: + * Returns a 2-element hash representing +self+. + * - {#to_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-to_json]: + * Returns a \JSON string representing +self+. + * + * These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available: + * + * require 'json/add/bigdecimal' + * + * * == License + * + * Copyright (C) 2002 by Shigeo Kobayashi . + * + * BigDecimal is released under the Ruby and 2-clause BSD licenses. + * See LICENSE.txt for details. + * + * Maintained by mrkn and ruby-core members. + * + * Documented by zzak , mathew , and + * many other contributors. + */ +void +Init_bigdecimal(void) +{ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + + id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode"); + id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode"); + id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit"); + + /* Initialize VP routines */ + VpInit(0UL); + + /* Class and method registration */ + rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric); + + /* Global function */ + rb_define_global_function("BigDecimal", f_BigDecimal, -1); + + /* Class methods */ + rb_undef_alloc_func(rb_cBigDecimal); + rb_undef_method(CLASS_OF(rb_cBigDecimal), "new"); + rb_define_singleton_method(rb_cBigDecimal, "interpret_loosely", BigDecimal_s_interpret_loosely, 1); + rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1); + rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1); + rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0); + rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1); + + rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0); + rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0); + rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0); + + /* Constants definition */ + + /* + * The version of bigdecimal library + */ + rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION)); + + /* + * Base value used in internal calculations. On a 32 bit system, BASE + * is 10000, indicating that calculation is done in groups of 4 digits. + * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't + * guarantee that two groups could always be multiplied together without + * overflow.) + */ + rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal())); + + /* Exceptions */ + + /* + * 0xff: Determines whether overflow, underflow or zero divide result in + * an exception being thrown. See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL", INT2FIX(VP_EXCEPTION_ALL)); + + /* + * 0x02: Determines what happens when the result of a computation is not a + * number (NaN). See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN", INT2FIX(VP_EXCEPTION_NaN)); + + /* + * 0x01: Determines what happens when the result of a computation is + * infinity. See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY", INT2FIX(VP_EXCEPTION_INFINITY)); + + /* + * 0x04: Determines what happens when the result of a computation is an + * underflow (a result too small to be represented). See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW", INT2FIX(VP_EXCEPTION_UNDERFLOW)); + + /* + * 0x01: Determines what happens when the result of a computation is an + * overflow (a result too large to be represented). See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW", INT2FIX(VP_EXCEPTION_OVERFLOW)); + + /* + * 0x10: Determines what happens when a division by zero is performed. + * See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE", INT2FIX(VP_EXCEPTION_ZERODIVIDE)); + + /* + * 0x100: Determines what happens when a result must be rounded in order to + * fit in the appropriate number of significant digits. See + * BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "ROUND_MODE", INT2FIX(VP_ROUND_MODE)); + + /* 1: Indicates that values should be rounded away from zero. See + * BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "ROUND_UP", INT2FIX(VP_ROUND_UP)); + + /* 2: Indicates that values should be rounded towards zero. See + * BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "ROUND_DOWN", INT2FIX(VP_ROUND_DOWN)); + + /* 3: Indicates that digits >= 5 should be rounded up, others rounded down. + * See BigDecimal.mode. */ + rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP", INT2FIX(VP_ROUND_HALF_UP)); + + /* 4: Indicates that digits >= 6 should be rounded up, others rounded down. + * See BigDecimal.mode. + */ + rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN", INT2FIX(VP_ROUND_HALF_DOWN)); + /* 5: Round towards +Infinity. See BigDecimal.mode. */ + rb_define_const(rb_cBigDecimal, "ROUND_CEILING", INT2FIX(VP_ROUND_CEIL)); + + /* 6: Round towards -Infinity. See BigDecimal.mode. */ + rb_define_const(rb_cBigDecimal, "ROUND_FLOOR", INT2FIX(VP_ROUND_FLOOR)); + + /* 7: Round towards the even neighbor. See BigDecimal.mode. */ + rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN", INT2FIX(VP_ROUND_HALF_EVEN)); + + /* 0: Indicates that a value is not a number. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_NaN", INT2FIX(VP_SIGN_NaN)); + + /* 1: Indicates that a value is +0. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO", INT2FIX(VP_SIGN_POSITIVE_ZERO)); + + /* -1: Indicates that a value is -0. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO", INT2FIX(VP_SIGN_NEGATIVE_ZERO)); + + /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE", INT2FIX(VP_SIGN_POSITIVE_FINITE)); + + /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE", INT2FIX(VP_SIGN_NEGATIVE_FINITE)); + + /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE", INT2FIX(VP_SIGN_POSITIVE_INFINITE)); + + /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */ + rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE", INT2FIX(VP_SIGN_NEGATIVE_INFINITE)); + + /* Positive zero value. */ + BIGDECIMAL_LITERAL(POSITIVE_ZERO, +0); + + /* Negative zero value. */ + BIGDECIMAL_LITERAL(NEGATIVE_ZERO, -0); + + /* Positive infinity[rdoc-ref:BigDecimal@Infinity] value. */ + rb_define_const(rb_cBigDecimal, "INFINITY", BIGDECIMAL_LITERAL(POSITIVE_INFINITY, +Infinity)); + + /* Negative infinity value. */ + BIGDECIMAL_LITERAL(NEGATIVE_INFINITY, -Infinity); + + /* '{Not a Number}[rdoc-ref:BigDecimal@Not+a+Number]' value. */ + rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN)); + + /* instance methods */ + rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0); + rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0); + rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0); + rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0); + rb_define_method(rb_cBigDecimal, "n_significant_digits", BigDecimal_n_significant_digits, 0); + + rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2); + rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2); + rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2); + rb_define_method(rb_cBigDecimal, "div", BigDecimal_div3, -1); + rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0); + rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1); + rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0); + rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0); + rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0); + rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0); + rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1); + rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1); + rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0); + rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0); + rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1); + rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1); + rb_define_method(rb_cBigDecimal, "quo", BigDecimal_quo, -1); + rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1); + rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1); + rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1); + rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1); + rb_define_method(rb_cBigDecimal, "clone", BigDecimal_clone, 0); + rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0); + rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0); + rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0); + rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1); + rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0); + rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1); + rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0); + rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1); + rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1); + rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1); + rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1); + rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1); + rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1); + rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1); + rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1); + rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1); + rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1); + rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1); + rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1); + rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0); + rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0); + rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1); + rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0); + rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0); + rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0); + rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0); + rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0); + rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0); + rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1); + rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1); + + rb_mBigMath = rb_define_module("BigMath"); + rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2); + rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2); + +#define ROUNDING_MODE(i, name, value) \ + id_##name = rb_intern_const(#name); \ + rbd_rounding_modes[i].id = id_##name; \ + rbd_rounding_modes[i].mode = value; + + ROUNDING_MODE(0, up, RBD_ROUND_UP); + ROUNDING_MODE(1, down, RBD_ROUND_DOWN); + ROUNDING_MODE(2, half_up, RBD_ROUND_HALF_UP); + ROUNDING_MODE(3, half_down, RBD_ROUND_HALF_DOWN); + ROUNDING_MODE(4, ceil, RBD_ROUND_CEIL); + ROUNDING_MODE(5, floor, RBD_ROUND_FLOOR); + ROUNDING_MODE(6, half_even, RBD_ROUND_HALF_EVEN); + + ROUNDING_MODE(7, default, RBD_ROUND_DEFAULT); + ROUNDING_MODE(8, truncate, RBD_ROUND_TRUNCATE); + ROUNDING_MODE(9, banker, RBD_ROUND_BANKER); + ROUNDING_MODE(10, ceiling, RBD_ROUND_CEILING); + +#undef ROUNDING_MODE + + id_to_r = rb_intern_const("to_r"); + id_eq = rb_intern_const("=="); + id_half = rb_intern_const("half"); + + (void)VPrint; /* suppress unused warning */ +} + +/* + * + * ============================================================================ + * + * vp_ routines begin from here. + * + * ============================================================================ + * + */ +#ifdef BIGDECIMAL_DEBUG +static int gfDebug = 1; /* Debug switch */ +#if 0 +static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */ +#endif +#endif /* BIGDECIMAL_DEBUG */ + +static Real *VpConstOne; /* constant 1.0 */ +static Real *VpConstPt5; /* constant 0.5 */ +#define maxnr 100UL /* Maximum iterations for calculating sqrt. */ + /* used in VpSqrt() */ + +/* ETC */ +#define MemCmp(x,y,z) memcmp(x,y,z) +#define StrCmp(x,y) strcmp(x,y) + +enum op_sw { + OP_SW_ADD = 1, /* + */ + OP_SW_SUB, /* - */ + OP_SW_MULT, /* * */ + OP_SW_DIV /* / */ +}; + +static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw); +static int AddExponent(Real *a, SIGNED_VALUE n); +static DECDIG VpAddAbs(Real *a,Real *b,Real *c); +static DECDIG VpSubAbs(Real *a,Real *b,Real *c); +static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv); +static int VpNmlz(Real *a); +static void VpFormatSt(char *psz, size_t fFmt); +static int VpRdup(Real *m, size_t ind_m); + +#ifdef BIGDECIMAL_DEBUG +# ifdef HAVE_RB_EXT_RACTOR_SAFE +# error Need to make rewiting gnAlloc atomic +# endif +static int gnAlloc = 0; /* Memory allocation counter */ +#endif /* BIGDECIMAL_DEBUG */ + +/* + * EXCEPTION Handling. + */ + +#define bigdecimal_set_thread_local_exception_mode(mode) \ + rb_thread_local_aset( \ + rb_thread_current(), \ + id_BigDecimal_exception_mode, \ + INT2FIX((int)(mode)) \ + ) + +static unsigned short +VpGetException (void) +{ + VALUE const vmode = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_exception_mode + ); + + if (NIL_P(vmode)) { + bigdecimal_set_thread_local_exception_mode(BIGDECIMAL_EXCEPTION_MODE_DEFAULT); + return BIGDECIMAL_EXCEPTION_MODE_DEFAULT; + } + + return NUM2USHORT(vmode); +} + +static void +VpSetException(unsigned short f) +{ + bigdecimal_set_thread_local_exception_mode(f); +} + +static void +VpCheckException(Real *p, bool always) +{ + if (VpIsNaN(p)) { + VpException(VP_EXCEPTION_NaN, "Computation results in 'NaN' (Not a Number)", always); + } + else if (VpIsPosInf(p)) { + VpException(VP_EXCEPTION_INFINITY, "Computation results in 'Infinity'", always); + } + else if (VpIsNegInf(p)) { + VpException(VP_EXCEPTION_INFINITY, "Computation results in '-Infinity'", always); + } +} + +static VALUE +VpCheckGetValue(Real *p) +{ + VpCheckException(p, false); + return p->obj; +} + +/* + * Precision limit. + */ + +#define bigdecimal_set_thread_local_precision_limit(limit) \ + rb_thread_local_aset( \ + rb_thread_current(), \ + id_BigDecimal_precision_limit, \ + SIZET2NUM(limit) \ + ) +#define BIGDECIMAL_PRECISION_LIMIT_DEFAULT ((size_t)0) + +/* These 2 functions added at v1.1.7 */ +VP_EXPORT size_t +VpGetPrecLimit(void) +{ + VALUE const vlimit = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_precision_limit + ); + + if (NIL_P(vlimit)) { + bigdecimal_set_thread_local_precision_limit(BIGDECIMAL_PRECISION_LIMIT_DEFAULT); + return BIGDECIMAL_PRECISION_LIMIT_DEFAULT; + } + + return NUM2SIZET(vlimit); +} + +VP_EXPORT size_t +VpSetPrecLimit(size_t n) +{ + size_t const s = VpGetPrecLimit(); + bigdecimal_set_thread_local_precision_limit(n); + return s; +} + +/* + * Rounding mode. + */ + +#define bigdecimal_set_thread_local_rounding_mode(mode) \ + rb_thread_local_aset( \ + rb_thread_current(), \ + id_BigDecimal_rounding_mode, \ + INT2FIX((int)(mode)) \ + ) + +VP_EXPORT unsigned short +VpGetRoundMode(void) +{ + VALUE const vmode = rb_thread_local_aref( + rb_thread_current(), + id_BigDecimal_rounding_mode + ); + + if (NIL_P(vmode)) { + bigdecimal_set_thread_local_rounding_mode(BIGDECIMAL_ROUNDING_MODE_DEFAULT); + return BIGDECIMAL_ROUNDING_MODE_DEFAULT; + } + + return NUM2USHORT(vmode); +} + +VP_EXPORT int +VpIsRoundMode(unsigned short n) +{ + switch (n) { + case VP_ROUND_UP: + case VP_ROUND_DOWN: + case VP_ROUND_HALF_UP: + case VP_ROUND_HALF_DOWN: + case VP_ROUND_CEIL: + case VP_ROUND_FLOOR: + case VP_ROUND_HALF_EVEN: + return 1; + + default: + return 0; + } +} + +VP_EXPORT unsigned short +VpSetRoundMode(unsigned short n) +{ + if (VpIsRoundMode(n)) { + bigdecimal_set_thread_local_rounding_mode(n); + return n; + } + + return VpGetRoundMode(); +} + +/* + * 0.0 & 1.0 generator + * These gZero_..... and gOne_..... can be any name + * referenced from nowhere except Zero() and One(). + * gZero_..... and gOne_..... must have global scope + * (to let the compiler know they may be changed in outside + * (... but not actually..)). + */ +volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0; + +static double +One(void) +{ + return gOne_ABCED9B4_CE73__00400511F31D; +} + +/* + ---------------------------------------------------------------- + Value of sign in Real structure is reserved for future use. + short sign; + ==0 : NaN + 1 : Positive zero + -1 : Negative zero + 2 : Positive number + -2 : Negative number + 3 : Positive infinite number + -3 : Negative infinite number + ---------------------------------------------------------------- +*/ + +VP_EXPORT double +VpGetDoubleNaN(void) /* Returns the value of NaN */ +{ + return nan(""); +} + +VP_EXPORT double +VpGetDoublePosInf(void) /* Returns the value of +Infinity */ +{ + return HUGE_VAL; +} + +VP_EXPORT double +VpGetDoubleNegInf(void) /* Returns the value of -Infinity */ +{ + return -HUGE_VAL; +} + +VP_EXPORT double +VpGetDoubleNegZero(void) /* Returns the value of -0 */ +{ + static double nzero = 1000.0; + if (nzero != 0.0) nzero = (One()/VpGetDoubleNegInf()); + return nzero; +} + +#if 0 /* unused */ +VP_EXPORT int +VpIsNegDoubleZero(double v) +{ + double z = VpGetDoubleNegZero(); + return MemCmp(&v,&z,sizeof(v))==0; +} +#endif + +VP_EXPORT int +VpException(unsigned short f, const char *str,int always) +{ + unsigned short const exception_mode = VpGetException(); + + if (f == VP_EXCEPTION_OP) always = 1; + + if (always || (exception_mode & f)) { + switch(f) { + /* case VP_EXCEPTION_OVERFLOW: */ + case VP_EXCEPTION_ZERODIVIDE: + case VP_EXCEPTION_INFINITY: + case VP_EXCEPTION_NaN: + case VP_EXCEPTION_UNDERFLOW: + case VP_EXCEPTION_OP: + rb_raise(rb_eFloatDomainError, "%s", str); + break; + default: + rb_fatal("%s", str); + } + } + return 0; /* 0 Means VpException() raised no exception */ +} + +/* Throw exception or returns 0,when resulting c is Inf or NaN */ +/* sw=1:+ 2:- 3:* 4:/ */ +static int +VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw) +{ + if (VpIsNaN(a) || VpIsNaN(b)) { + /* at least a or b is NaN */ + VpSetNaN(c); + goto NaN; + } + + if (VpIsInf(a)) { + if (VpIsInf(b)) { + switch(sw) { + case OP_SW_ADD: /* + */ + if (VpGetSign(a) == VpGetSign(b)) { + VpSetInf(c, VpGetSign(a)); + goto Inf; + } + else { + VpSetNaN(c); + goto NaN; + } + case OP_SW_SUB: /* - */ + if (VpGetSign(a) != VpGetSign(b)) { + VpSetInf(c, VpGetSign(a)); + goto Inf; + } + else { + VpSetNaN(c); + goto NaN; + } + case OP_SW_MULT: /* * */ + VpSetInf(c, VpGetSign(a)*VpGetSign(b)); + goto Inf; + case OP_SW_DIV: /* / */ + VpSetNaN(c); + goto NaN; + } + VpSetNaN(c); + goto NaN; + } + /* Inf op Finite */ + switch(sw) { + case OP_SW_ADD: /* + */ + case OP_SW_SUB: /* - */ + VpSetInf(c, VpGetSign(a)); + break; + case OP_SW_MULT: /* * */ + if (VpIsZero(b)) { + VpSetNaN(c); + goto NaN; + } + VpSetInf(c, VpGetSign(a)*VpGetSign(b)); + break; + case OP_SW_DIV: /* / */ + VpSetInf(c, VpGetSign(a)*VpGetSign(b)); + } + goto Inf; + } + + if (VpIsInf(b)) { + switch(sw) { + case OP_SW_ADD: /* + */ + VpSetInf(c, VpGetSign(b)); + break; + case OP_SW_SUB: /* - */ + VpSetInf(c, -VpGetSign(b)); + break; + case OP_SW_MULT: /* * */ + if (VpIsZero(a)) { + VpSetNaN(c); + goto NaN; + } + VpSetInf(c, VpGetSign(a)*VpGetSign(b)); + break; + case OP_SW_DIV: /* / */ + VpSetZero(c, VpGetSign(a)*VpGetSign(b)); + } + goto Inf; + } + return 1; /* Results OK */ + +Inf: + if (VpIsPosInf(c)) { + return VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 0); + } + else { + return VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 0); + } + +NaN: + return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0); +} + +/* + ---------------------------------------------------------------- +*/ + +/* + * returns number of chars needed to represent vp in specified format. + */ +VP_EXPORT size_t +VpNumOfChars(Real *vp,const char *pszFmt) +{ + SIGNED_VALUE ex; + size_t nc; + + if (vp == NULL) return BASE_FIG*2+6; + if (!VpIsDef(vp)) return 32; /* not sure,may be OK */ + + switch(*pszFmt) { + case 'F': + nc = BASE_FIG*(vp->Prec + 1)+2; + ex = vp->exponent; + if (ex < 0) { + nc += BASE_FIG*(size_t)(-ex); + } + else { + if ((size_t)ex > vp->Prec) { + nc += BASE_FIG*((size_t)ex - vp->Prec); + } + } + break; + case 'E': + /* fall through */ + default: + nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */ + } + return nc; +} + +/* + * Initializer for Vp routines and constants used. + * [Input] + * BaseVal: Base value(assigned to BASE) for Vp calculation. + * It must be the form BaseVal=10**n.(n=1,2,3,...) + * If Base <= 0L,then the BASE will be calculated so + * that BASE is as large as possible satisfying the + * relation MaxVal <= BASE*(BASE+1). Where the value + * MaxVal is the largest value which can be represented + * by one DECDIG word in the computer used. + * + * [Returns] + * BIGDECIMAL_DOUBLE_FIGURES ... OK + */ +VP_EXPORT size_t +VpInit(DECDIG BaseVal) +{ + /* Setup +/- Inf NaN -0 */ + VpGetDoubleNegZero(); + + /* Const 1.0 */ + VpConstOne = NewOneNolimit(1, 1); + + /* Const 0.5 */ + VpConstPt5 = NewOneNolimit(1, 1); + VpConstPt5->exponent = 0; + VpConstPt5->frac[0] = 5*BASE1; + +#ifdef BIGDECIMAL_DEBUG + gnAlloc = 0; +#endif /* BIGDECIMAL_DEBUG */ + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal); + printf("\tBASE = %"PRIuDECDIG"\n", BASE); + printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE); + printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1); + printf("\tBASE_FIG = %u\n", BASE_FIG); + printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES); + } +#endif /* BIGDECIMAL_DEBUG */ + + return BIGDECIMAL_DOUBLE_FIGURES; +} + +VP_EXPORT Real * +VpOne(void) +{ + return VpConstOne; +} + +/* If exponent overflows,then raise exception or returns 0 */ +static int +AddExponent(Real *a, SIGNED_VALUE n) +{ + SIGNED_VALUE e = a->exponent; + SIGNED_VALUE m = e+n; + SIGNED_VALUE eb, mb; + if (e > 0) { + if (n > 0) { + if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) || + MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) + goto overflow; + mb = m*(SIGNED_VALUE)BASE_FIG; + eb = e*(SIGNED_VALUE)BASE_FIG; + if (eb - mb > 0) goto overflow; + } + } + else if (n < 0) { + if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) || + MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) + goto underflow; + mb = m*(SIGNED_VALUE)BASE_FIG; + eb = e*(SIGNED_VALUE)BASE_FIG; + if (mb - eb > 0) goto underflow; + } + a->exponent = m; + return 1; + +/* Overflow/Underflow ==> Raise exception or returns 0 */ +underflow: + VpSetZero(a, VpGetSign(a)); + return VpException(VP_EXCEPTION_UNDERFLOW, "Exponent underflow", 0); + +overflow: + VpSetInf(a, VpGetSign(a)); + return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0); +} + +Real * +bigdecimal_parse_special_string(const char *str) +{ + static const struct { + const char *str; + size_t len; + int sign; + } table[] = { + { SZ_INF, sizeof(SZ_INF) - 1, VP_SIGN_POSITIVE_INFINITE }, + { SZ_PINF, sizeof(SZ_PINF) - 1, VP_SIGN_POSITIVE_INFINITE }, + { SZ_NINF, sizeof(SZ_NINF) - 1, VP_SIGN_NEGATIVE_INFINITE }, + { SZ_NaN, sizeof(SZ_NaN) - 1, VP_SIGN_NaN } + }; + static const size_t table_length = sizeof(table) / sizeof(table[0]); + size_t i; + + for (i = 0; i < table_length; ++i) { + const char *p; + if (strncmp(str, table[i].str, table[i].len) != 0) { + continue; + } + + p = str + table[i].len; + while (*p && ISSPACE(*p)) ++p; + if (*p == '\0') { + Real *vp = rbd_allocate_struct(1); + vp->MaxPrec = 1; + switch (table[i].sign) { + default: + UNREACHABLE; break; + case VP_SIGN_POSITIVE_INFINITE: + VpSetPosInf(vp); + return vp; + case VP_SIGN_NEGATIVE_INFINITE: + VpSetNegInf(vp); + return vp; + case VP_SIGN_NaN: + VpSetNaN(vp); + return vp; + } + } + } + + return NULL; +} + +struct VpCtoV_args { + Real *a; + const char *int_chr; + size_t ni; + const char *frac; + size_t nf; + const char *exp_chr; + size_t ne; +}; + +static VALUE +call_VpCtoV(VALUE arg) +{ + struct VpCtoV_args *x = (struct VpCtoV_args *)arg; + return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne); +} + +static int +protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne, int free_on_error) +{ + struct VpCtoV_args args; + int state = 0; + + args.a = a; + args.int_chr = int_chr; + args.ni = ni; + args.frac = frac; + args.nf = nf; + args.exp_chr = exp_chr; + args.ne = ne; + + VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state); + if (state) { + if (free_on_error) { + rbd_free_struct(a); + } + rb_jump_tag(state); + } + + return (int)result; +} + +/* + * Allocates variable. + * [Input] + * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal. + * The mx will be the number of significant digits can to be stored. + * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed. + * If szVal[0]=='#' then MaxPrec is not affected by the precision limit + * so that the full precision specified by szVal is allocated. + * + * [Returns] + * Pointer to the newly allocated variable, or + * NULL be returned if memory allocation is failed,or any error. + */ +VP_EXPORT Real * +VpAlloc(size_t mx, const char *szVal, int strict_p, int exc) +{ + const char *orig_szVal = szVal; + size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc; + size_t len; + char v, *psz; + int sign=1; + Real *vp = NULL; + VALUE buf; + + if (szVal == NULL) { + return_zero: + /* necessary to be able to store */ + /* at least mx digits. */ + /* szVal==NULL ==> allocate zero value. */ + vp = rbd_allocate_struct(mx); + vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */ + VpSetZero(vp, 1); /* initialize vp to zero. */ + return vp; + } + + /* Skipping leading spaces */ + while (ISSPACE(*szVal)) szVal++; + + /* Check on Inf & NaN */ + if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) { + return vp; + } + + /* Processing the leading one `#` */ + if (*szVal != '#') { + len = rbd_calculate_internal_digits(mx, true); + } + else { + len = rbd_calculate_internal_digits(mx, false); + ++szVal; + } + + /* Scanning digits */ + + /* A buffer for keeping scanned digits */ + buf = rb_str_tmp_new(strlen(szVal) + 1); + psz = RSTRING_PTR(buf); + + /* cursor: i for psz, and j for szVal */ + i = j = 0; + + /* Scanning: sign part */ + v = psz[i] = szVal[j]; + if ((v == '-') || (v == '+')) { + sign = -(v == '-'); + ++i; + ++j; + } + + /* Scanning: integer part */ + ni = 0; /* number of digits in the integer part */ + while ((v = psz[i] = szVal[j]) != '\0') { + if (!strict_p && ISSPACE(v)) { + v = psz[i] = '\0'; + break; + } + if (v == '_') { + if (ni > 0) { + v = szVal[j+1]; + if (v == '\0' || ISSPACE(v) || ISDIGIT(v)) { + ++j; + continue; + } + if (!strict_p) { + v = psz[i] = '\0'; + break; + } + } + goto invalid_value; + } + if (!ISDIGIT(v)) { + break; + } + ++ni; + ++i; + ++j; + } + + /* Scanning: fractional part */ + nf = 0; /* number of digits in the fractional part */ + ne = 0; /* number of digits in the exponential part */ + ipf = 0; /* index of the beginning of the fractional part */ + ipe = 0; /* index of the beginning of the exponential part */ + exp_seen = 0; + + if (v != '\0') { + /* Scanning fractional part */ + if ((psz[i] = szVal[j]) == '.') { + ++i; + ++j; + ipf = i; + while ((v = psz[i] = szVal[j]) != '\0') { + if (!strict_p && ISSPACE(v)) { + v = psz[i] = '\0'; + break; + } + if (v == '_') { + if (nf > 0 && ISDIGIT(szVal[j+1])) { + ++j; + continue; + } + if (!strict_p) { + v = psz[i] = '\0'; + break; + } + goto invalid_value; + } + if (!ISDIGIT(v)) break; + ++i; + ++j; + ++nf; + } + } + + /* Scanning exponential part */ + if (v != '\0') { + switch ((psz[i] = szVal[j])) { + case '\0': + break; + case 'e': case 'E': + case 'd': case 'D': + exp_seen = 1; + ++i; + ++j; + ipe = i; + v = psz[i] = szVal[j]; + if ((v == '-') || (v == '+')) { + ++i; + ++j; + } + while ((v = psz[i] = szVal[j]) != '\0') { + if (!strict_p && ISSPACE(v)) { + v = psz[i] = '\0'; + break; + } + if (v == '_') { + if (ne > 0 && ISDIGIT(szVal[j+1])) { + ++j; + continue; + } + if (!strict_p) { + v = psz[i] = '\0'; + if (ne == 0) { + exp_seen = 0; + } + break; + } + goto invalid_value; + } + if (!ISDIGIT(v)) break; + ++i; + ++j; + ++ne; + } + break; + default: + break; + } + } + + if (v != '\0') { + /* Scanning trailing spaces */ + while (ISSPACE(szVal[j])) ++j; + + /* Invalid character */ + if (szVal[j] && strict_p) { + goto invalid_value; + } + } + } + + psz[i] = '\0'; + + if (strict_p && ((ni == 0 && nf == 0) || (exp_seen && ne == 0))) { + VALUE str; + invalid_value: + if (!strict_p) { + goto return_zero; + } + if (!exc) { + return NULL; + } + str = rb_str_new2(orig_szVal); + rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str); + } + + nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */ + /* units for szVal[] */ + if (len == 0) len = 1; + nalloc = Max(nalloc, len); + len = nalloc; + vp = rbd_allocate_struct(len); + vp->MaxPrec = len; /* set max precision */ + VpSetZero(vp, sign); + protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true); + rb_str_resize(buf, 0); + return vp; +} + +/* + * Assignment(c=a). + * [Input] + * a ... RHSV + * isw ... switch for assignment. + * c = a when isw > 0 + * c = -a when isw < 0 + * if c->MaxPrec < a->Prec,then round operation + * will be performed. + * [Output] + * c ... LHSV + */ +VP_EXPORT size_t +VpAsgn(Real *c, Real *a, int isw) +{ + size_t n; + if (VpIsNaN(a)) { + VpSetNaN(c); + return 0; + } + if (VpIsInf(a)) { + VpSetInf(c, isw * VpGetSign(a)); + return 0; + } + + /* check if the RHS is zero */ + if (!VpIsZero(a)) { + c->exponent = a->exponent; /* store exponent */ + VpSetSign(c, isw * VpGetSign(a)); /* set sign */ + n = (a->Prec < c->MaxPrec) ? (a->Prec) : (c->MaxPrec); + c->Prec = n; + memcpy(c->frac, a->frac, n * sizeof(DECDIG)); + /* Needs round ? */ + if (isw != 10) { + /* Not in ActiveRound */ + if(c->Prec < a->Prec) { + VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]); + } + else { + VpLimitRound(c,0); + } + } + } + else { + /* The value of 'a' is zero. */ + VpSetZero(c, isw * VpGetSign(a)); + return 1; + } + return c->Prec * BASE_FIG; +} + +/* + * c = a + b when operation = 1 or 2 + * c = a - b when operation = -1 or -2. + * Returns number of significant digits of c + */ +VP_EXPORT size_t +VpAddSub(Real *c, Real *a, Real *b, int operation) +{ + short sw, isw; + Real *a_ptr, *b_ptr; + size_t n, na, nb, i; + DECDIG mrv; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpAddSub(enter) a=% \n", a); + VPrint(stdout, " b=% \n", b); + printf(" operation=%d\n", operation); + } +#endif /* BIGDECIMAL_DEBUG */ + + if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */ + + /* check if a or b is zero */ + if (VpIsZero(a)) { + /* a is zero,then assign b to c */ + if (!VpIsZero(b)) { + VpAsgn(c, b, operation); + } + else { + /* Both a and b are zero. */ + if (VpGetSign(a) < 0 && operation * VpGetSign(b) < 0) { + /* -0 -0 */ + VpSetZero(c, -1); + } + else { + VpSetZero(c, 1); + } + return 1; /* 0: 1 significant digits */ + } + return c->Prec * BASE_FIG; + } + if (VpIsZero(b)) { + /* b is zero,then assign a to c. */ + VpAsgn(c, a, 1); + return c->Prec*BASE_FIG; + } + + if (operation < 0) sw = -1; + else sw = 1; + + /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */ + if (a->exponent > b->exponent) { + a_ptr = a; + b_ptr = b; + } /* |a|>|b| */ + else if (a->exponent < b->exponent) { + a_ptr = b; + b_ptr = a; + } /* |a|<|b| */ + else { + /* Exponent part of a and b is the same,then compare fraction */ + /* part */ + na = a->Prec; + nb = b->Prec; + n = Min(na, nb); + for (i=0; i < n; ++i) { + if (a->frac[i] > b->frac[i]) { + a_ptr = a; + b_ptr = b; + goto end_if; + } + else if (a->frac[i] < b->frac[i]) { + a_ptr = b; + b_ptr = a; + goto end_if; + } + } + if (na > nb) { + a_ptr = a; + b_ptr = b; + goto end_if; + } + else if (na < nb) { + a_ptr = b; + b_ptr = a; + goto end_if; + } + /* |a| == |b| */ + if (VpGetSign(a) + sw *VpGetSign(b) == 0) { + VpSetZero(c, 1); /* abs(a)=abs(b) and operation = '-' */ + return c->Prec * BASE_FIG; + } + a_ptr = a; + b_ptr = b; + } + +end_if: + isw = VpGetSign(a) + sw *VpGetSign(b); + /* + * isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1) + * = 2 ...( 1)+( 1),( 1)-(-1) + * =-2 ...(-1)+(-1),(-1)-( 1) + * If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|) + * else c =(Sign ofisw)(|a_ptr|+|b_ptr|) + */ + if (isw) { /* addition */ + VpSetSign(c, 1); + mrv = VpAddAbs(a_ptr, b_ptr, c); + VpSetSign(c, isw / 2); + } + else { /* subtraction */ + VpSetSign(c, 1); + mrv = VpSubAbs(a_ptr, b_ptr, c); + if (a_ptr == a) { + VpSetSign(c,VpGetSign(a)); + } + else { + VpSetSign(c, VpGetSign(a_ptr) * sw); + } + } + VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv); + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpAddSub(result) c=% \n", c); + VPrint(stdout, " a=% \n", a); + VPrint(stdout, " b=% \n", b); + printf(" operation=%d\n", operation); + } +#endif /* BIGDECIMAL_DEBUG */ + return c->Prec * BASE_FIG; +} + +/* + * Addition of two values with variable precision + * a and b assuming abs(a)>abs(b). + * c = abs(a) + abs(b) ; where |a|>=|b| + */ +static DECDIG +VpAddAbs(Real *a, Real *b, Real *c) +{ + size_t word_shift; + size_t ap; + size_t bp; + size_t cp; + size_t a_pos; + size_t b_pos, b_pos_with_word_shift; + size_t c_pos; + DECDIG av, bv, carry, mrv; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpAddAbs called: a = %\n", a); + VPrint(stdout, " b = %\n", b); + } +#endif /* BIGDECIMAL_DEBUG */ + + word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv); + a_pos = ap; + b_pos = bp; + c_pos = cp; + + if (word_shift == (size_t)-1L) return 0; /* Overflow */ + if (b_pos == (size_t)-1L) goto Assign_a; + + mrv = av + bv; /* Most right val. Used for round. */ + + /* Just assign the last few digits of b to c because a has no */ + /* corresponding digits to be added. */ + if (b_pos > 0) { + while (b_pos > 0 && b_pos + word_shift > a_pos) { + c->frac[--c_pos] = b->frac[--b_pos]; + } + } + if (b_pos == 0 && word_shift > a_pos) { + while (word_shift-- > a_pos) { + c->frac[--c_pos] = 0; + } + } + + /* Just assign the last few digits of a to c because b has no */ + /* corresponding digits to be added. */ + b_pos_with_word_shift = b_pos + word_shift; + while (a_pos > b_pos_with_word_shift) { + c->frac[--c_pos] = a->frac[--a_pos]; + } + carry = 0; /* set first carry be zero */ + + /* Now perform addition until every digits of b will be */ + /* exhausted. */ + while (b_pos > 0) { + c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry; + if (c->frac[c_pos] >= BASE) { + c->frac[c_pos] -= BASE; + carry = 1; + } + else { + carry = 0; + } + } + + /* Just assign the first few digits of a with considering */ + /* the carry obtained so far because b has been exhausted. */ + while (a_pos > 0) { + c->frac[--c_pos] = a->frac[--a_pos] + carry; + if (c->frac[c_pos] >= BASE) { + c->frac[c_pos] -= BASE; + carry = 1; + } + else { + carry = 0; + } + } + if (c_pos) c->frac[c_pos - 1] += carry; + goto Exit; + +Assign_a: + VpAsgn(c, a, 1); + mrv = 0; + +Exit: + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpAddAbs exit: c=% \n", c); + } +#endif /* BIGDECIMAL_DEBUG */ + return mrv; +} + +/* + * c = abs(a) - abs(b) + */ +static DECDIG +VpSubAbs(Real *a, Real *b, Real *c) +{ + size_t word_shift; + size_t ap; + size_t bp; + size_t cp; + size_t a_pos; + size_t b_pos, b_pos_with_word_shift; + size_t c_pos; + DECDIG av, bv, borrow, mrv; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpSubAbs called: a = %\n", a); + VPrint(stdout, " b = %\n", b); + } +#endif /* BIGDECIMAL_DEBUG */ + + word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv); + a_pos = ap; + b_pos = bp; + c_pos = cp; + if (word_shift == (size_t)-1L) return 0; /* Overflow */ + if (b_pos == (size_t)-1L) goto Assign_a; + + if (av >= bv) { + mrv = av - bv; + borrow = 0; + } + else { + mrv = 0; + borrow = 1; + } + + /* Just assign the values which are the BASE subtracted by */ + /* each of the last few digits of the b because the a has no */ + /* corresponding digits to be subtracted. */ + if (b_pos + word_shift > a_pos) { + while (b_pos > 0 && b_pos + word_shift > a_pos) { + c->frac[--c_pos] = BASE - b->frac[--b_pos] - borrow; + borrow = 1; + } + if (b_pos == 0) { + while (word_shift > a_pos) { + --word_shift; + c->frac[--c_pos] = BASE - borrow; + borrow = 1; + } + } + } + /* Just assign the last few digits of a to c because b has no */ + /* corresponding digits to subtract. */ + + b_pos_with_word_shift = b_pos + word_shift; + while (a_pos > b_pos_with_word_shift) { + c->frac[--c_pos] = a->frac[--a_pos]; + } + + /* Now perform subtraction until every digits of b will be */ + /* exhausted. */ + while (b_pos > 0) { + --c_pos; + if (a->frac[--a_pos] < b->frac[--b_pos] + borrow) { + c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow; + borrow = 1; + } + else { + c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow; + borrow = 0; + } + } + + /* Just assign the first few digits of a with considering */ + /* the borrow obtained so far because b has been exhausted. */ + while (a_pos > 0) { + --c_pos; + if (a->frac[--a_pos] < borrow) { + c->frac[c_pos] = BASE + a->frac[a_pos] - borrow; + borrow = 1; + } + else { + c->frac[c_pos] = a->frac[a_pos] - borrow; + borrow = 0; + } + } + if (c_pos) c->frac[c_pos - 1] -= borrow; + goto Exit; + +Assign_a: + VpAsgn(c, a, 1); + mrv = 0; + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpSubAbs exit: c=% \n", c); + } +#endif /* BIGDECIMAL_DEBUG */ + return mrv; +} + +/* + * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant + * digit of c(In case of addition). + * ------------------------- figure of output ----------------------------------- + * a = xxxxxxxxxxx + * b = xxxxxxxxxx + * c =xxxxxxxxxxxxxxx + * word_shift = | | + * right_word = | | (Total digits in RHSV) + * left_word = | | (Total digits in LHSV) + * a_pos = | + * b_pos = | + * c_pos = | + */ +static size_t +VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv) +{ + size_t left_word, right_word, word_shift; + + size_t const round_limit = (VpGetPrecLimit() + BASE_FIG - 1) / BASE_FIG; + + assert(a->exponent >= b->exponent); + + c->frac[0] = 0; + *av = *bv = 0; + + word_shift = (a->exponent - b->exponent); + left_word = b->Prec + word_shift; + right_word = Max(a->Prec, left_word); + left_word = c->MaxPrec - 1; /* -1 ... prepare for round up */ + + /* + * check if 'round' is needed. + */ + if (right_word > left_word) { /* round ? */ + /*--------------------------------- + * Actual size of a = xxxxxxAxx + * Actual size of b = xxxBxxxxx + * Max. size of c = xxxxxx + * Round off = |-----| + * c_pos = | + * right_word = | + * a_pos = | + */ + *c_pos = right_word = left_word + 1; /* Set resulting precision */ + /* be equal to that of c */ + if (a->Prec >= c->MaxPrec) { + /* + * a = xxxxxxAxxx + * c = xxxxxx + * a_pos = | + */ + *a_pos = left_word; + if (*a_pos <= round_limit) { + *av = a->frac[*a_pos]; /* av is 'A' shown in above. */ + } + } + else { + /* + * a = xxxxxxx + * c = xxxxxxxxxx + * a_pos = | + */ + *a_pos = a->Prec; + } + if (b->Prec + word_shift >= c->MaxPrec) { + /* + * a = xxxxxxxxx + * b = xxxxxxxBxxx + * c = xxxxxxxxxxx + * b_pos = | + */ + if (c->MaxPrec >= word_shift + 1) { + *b_pos = c->MaxPrec - word_shift - 1; + if (*b_pos + word_shift <= round_limit) { + *bv = b->frac[*b_pos]; + } + } + else { + *b_pos = -1L; + } + } + else { + /* + * a = xxxxxxxxxxxxxxxx + * b = xxxxxx + * c = xxxxxxxxxxxxx + * b_pos = | + */ + *b_pos = b->Prec; + } + } + else { /* The MaxPrec of c - 1 > The Prec of a + b */ + /* + * a = xxxxxxx + * b = xxxxxx + * c = xxxxxxxxxxx + * c_pos = | + */ + *b_pos = b->Prec; + *a_pos = a->Prec; + *c_pos = right_word + 1; + } + c->Prec = *c_pos; + c->exponent = a->exponent; + if (!AddExponent(c, 1)) return (size_t)-1L; + return word_shift; +} + +/* + * Return number of significant digits + * c = a * b , Where a = a0a1a2 ... an + * b = b0b1b2 ... bm + * c = c0c1c2 ... cl + * a0 a1 ... an * bm + * a0 a1 ... an * bm-1 + * . . . + * . . . + * a0 a1 .... an * b0 + * +_____________________________ + * c0 c1 c2 ...... cl + * nc <---| + * MaxAB |--------------------| + */ +VP_EXPORT size_t +VpMult(Real *c, Real *a, Real *b) +{ + size_t MxIndA, MxIndB, MxIndAB, MxIndC; + size_t ind_c, i, ii, nc; + size_t ind_as, ind_ae, ind_bs; + DECDIG carry; + DECDIG_DBL s; + Real *w; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpMult(Enter): a=% \n", a); + VPrint(stdout, " b=% \n", b); + } +#endif /* BIGDECIMAL_DEBUG */ + + if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */ + + if (VpIsZero(a) || VpIsZero(b)) { + /* at least a or b is zero */ + VpSetZero(c, VpGetSign(a) * VpGetSign(b)); + return 1; /* 0: 1 significant digit */ + } + + if (VpIsOne(a)) { + VpAsgn(c, b, VpGetSign(a)); + goto Exit; + } + if (VpIsOne(b)) { + VpAsgn(c, a, VpGetSign(b)); + goto Exit; + } + if (b->Prec > a->Prec) { + /* Adjust so that digits(a)>digits(b) */ + w = a; + a = b; + b = w; + } + w = NULL; + MxIndA = a->Prec - 1; + MxIndB = b->Prec - 1; + MxIndC = c->MaxPrec - 1; + MxIndAB = a->Prec + b->Prec - 1; + + if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */ + w = c; + c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG)); + MxIndC = MxIndAB; + } + + /* set LHSV c info */ + + c->exponent = a->exponent; /* set exponent */ + if (!AddExponent(c, b->exponent)) { + if (w) rbd_free_struct(c); + return 0; + } + VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */ + carry = 0; + nc = ind_c = MxIndAB; + memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */ + c->Prec = nc + 1; /* set precision */ + for (nc = 0; nc < MxIndAB; ++nc, --ind_c) { + if (nc < MxIndB) { /* The left triangle of the Fig. */ + ind_as = MxIndA - nc; + ind_ae = MxIndA; + ind_bs = MxIndB; + } + else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */ + ind_as = MxIndA - nc; + ind_ae = MxIndA - (nc - MxIndB); + ind_bs = MxIndB; + } + else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */ + ind_as = 0; + ind_ae = MxIndAB - nc - 1; + ind_bs = MxIndB - (nc - MxIndA); + } + + for (i = ind_as; i <= ind_ae; ++i) { + s = (DECDIG_DBL)a->frac[i] * b->frac[ind_bs--]; + carry = (DECDIG)(s / BASE); + s -= (DECDIG_DBL)carry * BASE; + c->frac[ind_c] += (DECDIG)s; + if (c->frac[ind_c] >= BASE) { + s = c->frac[ind_c] / BASE; + carry += (DECDIG)s; + c->frac[ind_c] -= (DECDIG)(s * BASE); + } + if (carry) { + ii = ind_c; + while (ii-- > 0) { + c->frac[ii] += carry; + if (c->frac[ii] >= BASE) { + carry = c->frac[ii] / BASE; + c->frac[ii] -= (carry * BASE); + } + else { + break; + } + } + } + } + } + if (w != NULL) { /* free work variable */ + VpNmlz(c); + VpAsgn(w, c, 1); + rbd_free_struct(c); + c = w; + } + else { + VpLimitRound(c,0); + } + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpMult(c=a*b): c=% \n", c); + VPrint(stdout, " a=% \n", a); + VPrint(stdout, " b=% \n", b); + } +#endif /*BIGDECIMAL_DEBUG */ + return c->Prec*BASE_FIG; +} + +/* + * c = a / b, remainder = r + */ +VP_EXPORT size_t +VpDivd(Real *c, Real *r, Real *a, Real *b) +{ + size_t word_a, word_b, word_c, word_r; + size_t i, n, ind_a, ind_b, ind_c, ind_r; + size_t nLoop; + DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2; + DECDIG borrow, borrow1, borrow2; + DECDIG_DBL qb; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, " VpDivd(c=a/b) a=% \n", a); + VPrint(stdout, " b=% \n", b); + } +#endif /*BIGDECIMAL_DEBUG */ + + VpSetNaN(r); + if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit; + if (VpIsZero(a) && VpIsZero(b)) { + VpSetNaN(c); + return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0); + } + if (VpIsZero(b)) { + VpSetInf(c, VpGetSign(a) * VpGetSign(b)); + return VpException(VP_EXCEPTION_ZERODIVIDE, "Divide by zero", 0); + } + if (VpIsZero(a)) { + /* numerator a is zero */ + VpSetZero(c, VpGetSign(a) * VpGetSign(b)); + VpSetZero(r, VpGetSign(a) * VpGetSign(b)); + goto Exit; + } + if (VpIsOne(b)) { + /* divide by one */ + VpAsgn(c, a, VpGetSign(b)); + VpSetZero(r, VpGetSign(a)); + goto Exit; + } + + word_a = a->Prec; + word_b = b->Prec; + word_c = c->MaxPrec; + word_r = r->MaxPrec; + + if (word_a >= word_r) goto space_error; + + ind_r = 1; + r->frac[0] = 0; + while (ind_r <= word_a) { + r->frac[ind_r] = a->frac[ind_r - 1]; + ++ind_r; + } + while (ind_r < word_r) r->frac[ind_r++] = 0; + + ind_c = 0; + while (ind_c < word_c) c->frac[ind_c++] = 0; + + /* initial procedure */ + b1 = b1p1 = b->frac[0]; + if (b->Prec <= 1) { + b1b2p1 = b1b2 = b1p1 * BASE; + } + else { + b1p1 = b1 + 1; + b1b2p1 = b1b2 = b1 * BASE + b->frac[1]; + if (b->Prec > 2) ++b1b2p1; + } + + /* */ + /* loop start */ + ind_c = word_r - 1; + nLoop = Min(word_c,ind_c); + ind_c = 1; + while (ind_c < nLoop) { + if (r->frac[ind_c] == 0) { + ++ind_c; + continue; + } + r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1]; + if (r1r2 == b1b2) { + /* The first two word digits is the same */ + ind_b = 2; + ind_a = ind_c + 2; + while (ind_b < word_b) { + if (r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1; + if (r->frac[ind_a] > b->frac[ind_b]) break; + ++ind_a; + ++ind_b; + } + /* The first few word digits of r and b is the same and */ + /* the first different word digit of w is greater than that */ + /* of b, so quotient is 1 and just subtract b from r. */ + borrow = 0; /* quotient=1, then just r-b */ + ind_b = b->Prec - 1; + ind_r = ind_c + ind_b; + if (ind_r >= word_r) goto space_error; + n = ind_b; + for (i = 0; i <= n; ++i) { + if (r->frac[ind_r] < b->frac[ind_b] + borrow) { + r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow)); + borrow = 1; + } + else { + r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow; + borrow = 0; + } + --ind_r; + --ind_b; + } + ++c->frac[ind_c]; + goto carry; + } + /* The first two word digits is not the same, */ + /* then compare magnitude, and divide actually. */ + if (r1r2 >= b1b2p1) { + q = r1r2 / b1b2p1; /* q == (DECDIG)q */ + c->frac[ind_c] += (DECDIG)q; + ind_r = b->Prec + ind_c - 1; + goto sub_mult; + } + +div_b1p1: + if (ind_c + 1 >= word_c) goto out_side; + q = r1r2 / b1p1; /* q == (DECDIG)q */ + c->frac[ind_c + 1] += (DECDIG)q; + ind_r = b->Prec + ind_c; + +sub_mult: + borrow1 = borrow2 = 0; + ind_b = word_b - 1; + if (ind_r >= word_r) goto space_error; + n = ind_b; + for (i = 0; i <= n; ++i) { + /* now, perform r = r - q * b */ + qb = q * b->frac[ind_b]; + if (qb < BASE) borrow1 = 0; + else { + borrow1 = (DECDIG)(qb / BASE); + qb -= (DECDIG_DBL)borrow1 * BASE; /* get qb < BASE */ + } + if(r->frac[ind_r] < qb) { + r->frac[ind_r] += (DECDIG)(BASE - qb); + borrow2 = borrow2 + borrow1 + 1; + } + else { + r->frac[ind_r] -= (DECDIG)qb; + borrow2 += borrow1; + } + if (borrow2) { + if(r->frac[ind_r - 1] < borrow2) { + r->frac[ind_r - 1] += (BASE - borrow2); + borrow2 = 1; + } + else { + r->frac[ind_r - 1] -= borrow2; + borrow2 = 0; + } + } + --ind_r; + --ind_b; + } + + r->frac[ind_r] -= borrow2; +carry: + ind_r = ind_c; + while (c->frac[ind_r] >= BASE) { + c->frac[ind_r] -= BASE; + --ind_r; + ++c->frac[ind_r]; + } + } + /* End of operation, now final arrangement */ +out_side: + c->Prec = word_c; + c->exponent = a->exponent; + if (!AddExponent(c, 2)) return 0; + if (!AddExponent(c, -(b->exponent))) return 0; + + VpSetSign(c, VpGetSign(a) * VpGetSign(b)); + VpNmlz(c); /* normalize c */ + r->Prec = word_r; + r->exponent = a->exponent; + if (!AddExponent(r, 1)) return 0; + VpSetSign(r, VpGetSign(a)); + VpNmlz(r); /* normalize r(remainder) */ + goto Exit; + +space_error: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + printf(" word_a=%"PRIuSIZE"\n", word_a); + printf(" word_b=%"PRIuSIZE"\n", word_b); + printf(" word_c=%"PRIuSIZE"\n", word_c); + printf(" word_r=%"PRIuSIZE"\n", word_r); + printf(" ind_r =%"PRIuSIZE"\n", ind_r); + } +#endif /* BIGDECIMAL_DEBUG */ + rb_bug("ERROR(VpDivd): space for remainder too small."); + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, " VpDivd(c=a/b), c=% \n", c); + VPrint(stdout, " r=% \n", r); + } +#endif /* BIGDECIMAL_DEBUG */ + return c->Prec * BASE_FIG; +} + +/* + * Input a = 00000xxxxxxxx En(5 preceding zeros) + * Output a = xxxxxxxx En-5 + */ +static int +VpNmlz(Real *a) +{ + size_t ind_a, i; + + if (!VpIsDef(a)) goto NoVal; + if (VpIsZero(a)) goto NoVal; + + ind_a = a->Prec; + while (ind_a--) { + if (a->frac[ind_a]) { + a->Prec = ind_a + 1; + i = 0; + while (a->frac[i] == 0) ++i; /* skip the first few zeros */ + if (i) { + a->Prec -= i; + if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0; + memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(DECDIG)); + } + return 1; + } + } + /* a is zero(no non-zero digit) */ + VpSetZero(a, VpGetSign(a)); + return 0; + +NoVal: + a->frac[0] = 0; + a->Prec = 1; + return 0; +} + +/* + * VpComp = 0 ... if a=b, + * Pos ... a>b, + * Neg ... asign - b->sign; + else e = a->sign; + + if (e > 0) return 1; + else if (e < 0) return -1; + else return 0; + } + if (!VpIsDef(b)) { + e = -b->sign; + if (e > 0) return 1; + else return -1; + } + /* Zero check */ + if (VpIsZero(a)) { + if (VpIsZero(b)) return 0; /* both zero */ + val = -VpGetSign(b); + goto Exit; + } + if (VpIsZero(b)) { + val = VpGetSign(a); + goto Exit; + } + + /* compare sign */ + if (VpGetSign(a) > VpGetSign(b)) { + val = 1; /* a>b */ + goto Exit; + } + if (VpGetSign(a) < VpGetSign(b)) { + val = -1; /* aexponent > b->exponent) { + val = VpGetSign(a); + goto Exit; + } + if (a->exponent < b->exponent) { + val = -VpGetSign(b); + goto Exit; + } + + /* a and b have same exponent, then compare their significand. */ + mx = (a->Prec < b->Prec) ? a->Prec : b->Prec; + ind = 0; + while (ind < mx) { + if (a->frac[ind] > b->frac[ind]) { + val = VpGetSign(a); + goto Exit; + } + if (a->frac[ind] < b->frac[ind]) { + val = -VpGetSign(b); + goto Exit; + } + ++ind; + } + if (a->Prec > b->Prec) { + val = VpGetSign(a); + } + else if (a->Prec < b->Prec) { + val = -VpGetSign(b); + } + +Exit: + if (val > 1) val = 1; + else if (val < -1) val = -1; + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, " VpComp a=%\n", a); + VPrint(stdout, " b=%\n", b); + printf(" ans=%d\n", val); + } +#endif /* BIGDECIMAL_DEBUG */ + return (int)val; +} + +/* + * cntl_chr ... ASCIIZ Character, print control characters + * Available control codes: + * % ... VP variable. To print '%', use '%%'. + * \n ... new line + * \b ... backspace + * \t ... tab + * Note: % must not appear more than once + * a ... VP variable to be printed + */ +static int +VPrint(FILE *fp, const char *cntl_chr, Real *a) +{ + size_t i, j, nc, nd, ZeroSup, sep = 10; + DECDIG m, e, nn; + + j = 0; + nd = nc = 0; /* nd : number of digits in fraction part(every 10 digits, */ + /* nd<=10). */ + /* nc : number of characters printed */ + ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */ + while (*(cntl_chr + j)) { + if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') { + nc = 0; + if (VpIsNaN(a)) { + fprintf(fp, SZ_NaN); + nc += 8; + } + else if (VpIsPosInf(a)) { + fprintf(fp, SZ_INF); + nc += 8; + } + else if (VpIsNegInf(a)) { + fprintf(fp, SZ_NINF); + nc += 9; + } + else if (!VpIsZero(a)) { + if (BIGDECIMAL_NEGATIVE_P(a)) { + fprintf(fp, "-"); + ++nc; + } + nc += fprintf(fp, "0."); + switch (*(cntl_chr + j + 1)) { + default: + break; + + case '0': case 'z': + ZeroSup = 0; + ++j; + sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10; + break; + } + for (i = 0; i < a->Prec; ++i) { + m = BASE1; + e = a->frac[i]; + while (m) { + nn = e / m; + if (!ZeroSup || nn) { + nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */ + /* as 0.00xx will not */ + /* be printed. */ + ++nd; + ZeroSup = 0; /* Set to print succeeding zeros */ + } + if (nd >= sep) { /* print ' ' after every 10 digits */ + nd = 0; + nc += fprintf(fp, " "); + } + e = e - nn * m; + m /= 10; + } + } + nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a)); + nc += fprintf(fp, " (%"PRIdVALUE", %"PRIuSIZE", %"PRIuSIZE")", a->exponent, a->Prec, a->MaxPrec); + } + else { + nc += fprintf(fp, "0.0"); + } + } + else { + ++nc; + if (*(cntl_chr + j) == '\\') { + switch (*(cntl_chr + j + 1)) { + case 'n': + fprintf(fp, "\n"); + ++j; + break; + case 't': + fprintf(fp, "\t"); + ++j; + break; + case 'b': + fprintf(fp, "\n"); + ++j; + break; + default: + fprintf(fp, "%c", *(cntl_chr + j)); + break; + } + } + else { + fprintf(fp, "%c", *(cntl_chr + j)); + if (*(cntl_chr + j) == '%') ++j; + } + } + j++; + } + + return (int)nc; +} + +static void +VpFormatSt(char *psz, size_t fFmt) +{ + size_t ie, i, nf = 0; + char ch; + + if (fFmt == 0) return; + + ie = strlen(psz); + for (i = 0; i < ie; ++i) { + ch = psz[i]; + if (!ch) break; + if (ISSPACE(ch) || ch=='-' || ch=='+') continue; + if (ch == '.') { nf = 0; continue; } + if (ch == 'E' || ch == 'e') break; + + if (++nf > fFmt) { + memmove(psz + i + 1, psz + i, ie - i + 1); + ++ie; + nf = 0; + psz[i] = ' '; + } + } +} + +VP_EXPORT ssize_t +VpExponent10(Real *a) +{ + ssize_t ex; + size_t n; + + if (!VpHasVal(a)) return 0; + + ex = a->exponent * (ssize_t)BASE_FIG; + n = BASE1; + while ((a->frac[0] / n) == 0) { + --ex; + n /= 10; + } + return ex; +} + +VP_EXPORT void +VpSzMantissa(Real *a, char *buf, size_t buflen) +{ + size_t i, n, ZeroSup; + DECDIG_DBL m, e, nn; + + if (VpIsNaN(a)) { + snprintf(buf, buflen, SZ_NaN); + return; + } + if (VpIsPosInf(a)) { + snprintf(buf, buflen, SZ_INF); + return; + } + if (VpIsNegInf(a)) { + snprintf(buf, buflen, SZ_NINF); + return; + } + + ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */ + if (!VpIsZero(a)) { + if (BIGDECIMAL_NEGATIVE_P(a)) *buf++ = '-'; + n = a->Prec; + for (i = 0; i < n; ++i) { + m = BASE1; + e = a->frac[i]; + while (m) { + nn = e / m; + if (!ZeroSup || nn) { + snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */ + buf += strlen(buf); + /* as 0.00xx will be ignored. */ + ZeroSup = 0; /* Set to print succeeding zeros */ + } + e = e - nn * m; + m /= 10; + } + } + *buf = 0; + while (buf[-1] == '0') *(--buf) = 0; + } + else { + if (VpIsPosZero(a)) snprintf(buf, buflen, "0"); + else snprintf(buf, buflen, "-0"); + } +} + +VP_EXPORT int +VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus) +/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */ +{ + if (VpIsNaN(a)) { + snprintf(buf, buflen, SZ_NaN); + return 1; + } + + if (VpIsPosInf(a)) { + if (fPlus == 1) { + *buf++ = ' '; + } + else if (fPlus == 2) { + *buf++ = '+'; + } + snprintf(buf, buflen, SZ_INF); + return 1; + } + if (VpIsNegInf(a)) { + snprintf(buf, buflen, SZ_NINF); + return 1; + } + if (VpIsZero(a)) { + if (VpIsPosZero(a)) { + if (fPlus == 1) snprintf(buf, buflen, " 0.0"); + else if (fPlus == 2) snprintf(buf, buflen, "+0.0"); + else snprintf(buf, buflen, "0.0"); + } + else snprintf(buf, buflen, "-0.0"); + return 1; + } + return 0; +} + +VP_EXPORT void +VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus) +/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */ +{ + size_t i, n, ZeroSup; + DECDIG shift, m, e, nn; + char *p = buf; + size_t plen = buflen; + ssize_t ex; + + if (VpToSpecialString(a, buf, buflen, fPlus)) return; + + ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */ + +#define ADVANCE(n) do { \ + if (plen < n) goto overflow; \ + p += n; \ + plen -= n; \ +} while (0) + + if (BIGDECIMAL_NEGATIVE_P(a)) { + *p = '-'; + ADVANCE(1); + } + else if (fPlus == 1) { + *p = ' '; + ADVANCE(1); + } + else if (fPlus == 2) { + *p = '+'; + ADVANCE(1); + } + + *p = '0'; ADVANCE(1); + *p = '.'; ADVANCE(1); + + n = a->Prec; + for (i = 0; i < n; ++i) { + m = BASE1; + e = a->frac[i]; + while (m) { + nn = e / m; + if (!ZeroSup || nn) { + /* The reading zero(s) */ + size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn); + if (n > plen) goto overflow; + ADVANCE(n); + /* as 0.00xx will be ignored. */ + ZeroSup = 0; /* Set to print succeeding zeros */ + } + e = e - nn * m; + m /= 10; + } + } + + ex = a->exponent * (ssize_t)BASE_FIG; + shift = BASE1; + while (a->frac[0] / shift == 0) { + --ex; + shift /= 10; + } + while (p - 1 > buf && p[-1] == '0') { + *(--p) = '\0'; + ++plen; + } + snprintf(p, plen, "e%"PRIdSIZE, ex); + if (fFmt) VpFormatSt(buf, fFmt); + + overflow: + return; +#undef ADVANCE +} + +VP_EXPORT void +VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus) +/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */ +{ + size_t i, n; + DECDIG m, e; + char *p = buf; + size_t plen = buflen, delim = fFmt; + ssize_t ex; + + if (VpToSpecialString(a, buf, buflen, fPlus)) return; + +#define APPEND(c, group) do { \ + if (plen < 1) goto overflow; \ + if (group && delim == 0) { \ + *p = ' '; \ + p += 1; \ + plen -= 1; \ + } \ + if (plen < 1) goto overflow; \ + *p = c; \ + p += 1; \ + plen -= 1; \ + if (group) delim = (delim + 1) % fFmt; \ +} while (0) + + + if (BIGDECIMAL_NEGATIVE_P(a)) { + APPEND('-', false); + } + else if (fPlus == 1) { + APPEND(' ', false); + } + else if (fPlus == 2) { + APPEND('+', false); + } + + n = a->Prec; + ex = a->exponent; + if (ex <= 0) { + APPEND('0', false); + APPEND('.', false); + } + while (ex < 0) { + for (i=0; i < BASE_FIG; ++i) { + APPEND('0', fFmt > 0); + } + ++ex; + } + + for (i = 0; i < n; ++i) { + m = BASE1; + e = a->frac[i]; + if (i == 0 && ex > 0) { + for (delim = 0; e / m == 0; delim++) { + m /= 10; + } + if (fFmt > 0) { + delim = 2*fFmt - (ex * BASE_FIG - delim) % fFmt; + } + } + while (m && (e || (i < n - 1) || ex > 0)) { + APPEND((char)(e / m + '0'), fFmt > 0); + e %= m; + m /= 10; + } + if (--ex == 0) { + APPEND('.', false); + delim = fFmt; + } + } + + while (ex > 0) { + for (i=0; i < BASE_FIG; ++i) { + APPEND('0', fFmt > 0); + } + if (--ex == 0) { + APPEND('.', false); + } + } + + *p = '\0'; + if (p - 1 > buf && p[-1] == '.') { + snprintf(p, plen, "0"); + } + + overflow: + return; +#undef APPEND +} + +/* + * [Output] + * a[] ... variable to be assigned the value. + * [Input] + * int_chr[] ... integer part(may include '+/-'). + * ni ... number of characters in int_chr[],not including '+/-'. + * frac[] ... fraction part. + * nf ... number of characters in frac[]. + * exp_chr[] ... exponent part(including '+/-'). + * ne ... number of characters in exp_chr[],not including '+/-'. + */ +VP_EXPORT int +VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne) +{ + size_t i, j, ind_a, ma, mi, me; + SIGNED_VALUE e, es, eb, ef; + int sign, signe, exponent_overflow; + + /* get exponent part */ + e = 0; + ma = a->MaxPrec; + mi = ni; + me = ne; + signe = 1; + exponent_overflow = 0; + memset(a->frac, 0, ma * sizeof(DECDIG)); + if (ne > 0) { + i = 0; + if (exp_chr[0] == '-') { + signe = -1; + ++i; + ++me; + } + else if (exp_chr[0] == '+') { + ++i; + ++me; + } + while (i < me) { + if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) { + es = e; + goto exp_overflow; + } + es = e * (SIGNED_VALUE)BASE_FIG; + if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) || + SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10) + goto exp_overflow; + e = e * 10 + exp_chr[i] - '0'; + if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) + goto exp_overflow; + if (es > (SIGNED_VALUE)(e * BASE_FIG)) { + exp_overflow: + exponent_overflow = 1; + e = es; /* keep sign */ + break; + } + ++i; + } + } + + /* get integer part */ + i = 0; + sign = 1; + if (1 /*ni >= 0*/) { + if (int_chr[0] == '-') { + sign = -1; + ++i; + ++mi; + } + else if (int_chr[0] == '+') { + ++i; + ++mi; + } + } + + e = signe * e; /* e: The value of exponent part. */ + e = e + ni; /* set actual exponent size. */ + + if (e > 0) signe = 1; + else signe = -1; + + /* Adjust the exponent so that it is the multiple of BASE_FIG. */ + j = 0; + ef = 1; + while (ef) { + if (e >= 0) eb = e; + else eb = -e; + ef = eb / (SIGNED_VALUE)BASE_FIG; + ef = eb - ef * (SIGNED_VALUE)BASE_FIG; + if (ef) { + ++j; /* Means to add one more preceding zero */ + ++e; + } + } + + eb = e / (SIGNED_VALUE)BASE_FIG; + + if (exponent_overflow) { + int zero = 1; + for ( ; i < mi && zero; i++) zero = int_chr[i] == '0'; + for (i = 0; i < nf && zero; i++) zero = frac[i] == '0'; + if (!zero && signe > 0) { + VpSetInf(a, sign); + VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0); + } + else VpSetZero(a, sign); + return 1; + } + + ind_a = 0; + while (i < mi) { + a->frac[ind_a] = 0; + while (j < BASE_FIG && i < mi) { + a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0'; + ++j; + ++i; + } + if (i < mi) { + ++ind_a; + if (ind_a >= ma) goto over_flow; + j = 0; + } + } + + /* get fraction part */ + + i = 0; + while (i < nf) { + while (j < BASE_FIG && i < nf) { + a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0'; + ++j; + ++i; + } + if (i < nf) { + ++ind_a; + if (ind_a >= ma) goto over_flow; + j = 0; + } + } + goto Final; + +over_flow: + rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded)."); + +Final: + if (ind_a >= ma) ind_a = ma - 1; + while (j < BASE_FIG) { + a->frac[ind_a] = a->frac[ind_a] * 10; + ++j; + } + a->Prec = ind_a + 1; + a->exponent = eb; + VpSetSign(a, sign); + VpNmlz(a); + return 1; +} + +/* + * [Input] + * *m ... Real + * [Output] + * *d ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig. + * *e ... exponent of m. + * BIGDECIMAL_DOUBLE_FIGURES ... Number of digits in a double variable. + * + * m -> d*10**e, 0Prec); + *d = 0.0; + div = 1.; + while (ind_m < mm) { + div /= (double)BASE; + *d = *d + (double)m->frac[ind_m++] * div; + } + *e = m->exponent * (SIGNED_VALUE)BASE_FIG; + *d *= VpGetSign(m); + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, " VpVtoD: m=%\n", m); + printf(" d=%e * 10 **%ld\n", *d, *e); + printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES); + } +#endif /*BIGDECIMAL_DEBUG */ + return f; +} + +/* + * m <- d + */ +VP_EXPORT void +VpDtoV(Real *m, double d) +{ + size_t ind_m, mm; + SIGNED_VALUE ne; + DECDIG i; + double val, val2; + + if (isnan(d)) { + VpSetNaN(m); + goto Exit; + } + if (isinf(d)) { + if (d > 0.0) VpSetPosInf(m); + else VpSetNegInf(m); + goto Exit; + } + + if (d == 0.0) { + VpSetZero(m, 1); + goto Exit; + } + val = (d > 0.) ? d : -d; + ne = 0; + if (val >= 1.0) { + while (val >= 1.0) { + val /= (double)BASE; + ++ne; + } + } + else { + val2 = 1.0 / (double)BASE; + while (val < val2) { + val *= (double)BASE; + --ne; + } + } + /* Now val = 0.xxxxx*BASE**ne */ + + mm = m->MaxPrec; + memset(m->frac, 0, mm * sizeof(DECDIG)); + for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) { + val *= (double)BASE; + i = (DECDIG)val; + val -= (double)i; + m->frac[ind_m] = i; + } + if (ind_m >= mm) ind_m = mm - 1; + VpSetSign(m, (d > 0.0) ? 1 : -1); + m->Prec = ind_m + 1; + m->exponent = ne; + + VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0, + (DECDIG)(val*(double)BASE)); + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + printf("VpDtoV d=%30.30e\n", d); + VPrint(stdout, " m=%\n", m); + } +#endif /* BIGDECIMAL_DEBUG */ + return; +} + +/* + * m <- ival + */ +#if 0 /* unused */ +VP_EXPORT void +VpItoV(Real *m, SIGNED_VALUE ival) +{ + size_t mm, ind_m; + size_t val, v1, v2, v; + int isign; + SIGNED_VALUE ne; + + if (ival == 0) { + VpSetZero(m, 1); + goto Exit; + } + isign = 1; + val = ival; + if (ival < 0) { + isign = -1; + val =(size_t)(-ival); + } + ne = 0; + ind_m = 0; + mm = m->MaxPrec; + while (ind_m < mm) { + m->frac[ind_m] = 0; + ++ind_m; + } + ind_m = 0; + while (val > 0) { + if (val) { + v1 = val; + v2 = 1; + while (v1 >= BASE) { + v1 /= BASE; + v2 *= BASE; + } + val = val - v2 * v1; + v = v1; + } + else { + v = 0; + } + m->frac[ind_m] = v; + ++ind_m; + ++ne; + } + m->Prec = ind_m - 1; + m->exponent = ne; + VpSetSign(m, isign); + VpNmlz(m); + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + printf(" VpItoV i=%d\n", ival); + VPrint(stdout, " m=%\n", m); + } +#endif /* BIGDECIMAL_DEBUG */ + return; +} +#endif + +/* + * y = SQRT(x), y*y - x =>0 + */ +VP_EXPORT int +VpSqrt(Real *y, Real *x) +{ + Real *f = NULL; + Real *r = NULL; + size_t y_prec; + SIGNED_VALUE n, e; + ssize_t nr; + double val; + + /* Zero or +Infinity ? */ + if (VpIsZero(x) || VpIsPosInf(x)) { + VpAsgn(y,x,1); + goto Exit; + } + + /* Negative ? */ + if (BIGDECIMAL_NEGATIVE_P(x)) { + VpSetNaN(y); + return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0); + } + + /* NaN ? */ + if (VpIsNaN(x)) { + VpSetNaN(y); + return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0); + } + + /* One ? */ + if (VpIsOne(x)) { + VpSetOne(y); + goto Exit; + } + + n = (SIGNED_VALUE)y->MaxPrec; + if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec; + + /* allocate temporally variables */ + /* TODO: reconsider MaxPrec of f and r */ + f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2)); + r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2)); + + nr = 0; + y_prec = y->MaxPrec; + + VpVtoD(&val, &e, x); /* val <- x */ + e /= (SIGNED_VALUE)BASE_FIG; + n = e / 2; + if (e - n * 2 != 0) { + val /= BASE; + n = (e + 1) / 2; + } + VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */ + y->exponent += n; + n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG); + y->MaxPrec = Min((size_t)n , y_prec); + f->MaxPrec = y->MaxPrec + 1; + n = (SIGNED_VALUE)(y_prec * BASE_FIG); + if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr; + + /* + * Perform: y_{n+1} = (y_n - x/y_n) / 2 + */ + do { + y->MaxPrec *= 2; + if (y->MaxPrec > y_prec) y->MaxPrec = y_prec; + f->MaxPrec = y->MaxPrec; + VpDivd(f, r, x, y); /* f = x/y */ + VpAddSub(r, f, y, -1); /* r = f - y */ + VpMult(f, VpConstPt5, r); /* f = 0.5*r */ + if (VpIsZero(f)) + goto converge; + VpAddSub(r, f, y, 1); /* r = y + f */ + VpAsgn(y, r, 1); /* y = r */ + } while (++nr < n); + +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr); + } +#endif /* BIGDECIMAL_DEBUG */ + y->MaxPrec = y_prec; + +converge: + VpChangeSign(y, 1); +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VpMult(r, y, y); + VpAddSub(f, x, r, -1); + printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr); + VPrint(stdout, " y =% \n", y); + VPrint(stdout, " x =% \n", x); + VPrint(stdout, " x-y*y = % \n", f); + } +#endif /* BIGDECIMAL_DEBUG */ + y->MaxPrec = y_prec; + +Exit: + rbd_free_struct(f); + rbd_free_struct(r); + return 1; +} + +/* + * Round relatively from the decimal point. + * f: rounding mode + * nf: digit location to round from the decimal point. + */ +VP_EXPORT int +VpMidRound(Real *y, unsigned short f, ssize_t nf) +{ + /* fracf: any positive digit under rounding position? */ + /* fracf_1further: any positive digits under one further than the rounding position? */ + /* exptoadd: number of digits needed to compensate negative nf */ + int fracf, fracf_1further; + ssize_t n,i,ix,ioffset, exptoadd; + DECDIG v, shifter; + DECDIG div; + + nf += y->exponent * (ssize_t)BASE_FIG; + exptoadd=0; + if (nf < 0) { + /* rounding position too left(large). */ + if (f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) { + VpSetZero(y, VpGetSign(y)); /* truncate everything */ + return 0; + } + exptoadd = -nf; + nf = 0; + } + + ix = nf / (ssize_t)BASE_FIG; + if ((size_t)ix >= y->Prec) return 0; /* rounding position too right(small). */ + v = y->frac[ix]; + + ioffset = nf - ix*(ssize_t)BASE_FIG; + n = (ssize_t)BASE_FIG - ioffset - 1; + for (shifter = 1, i = 0; i < n; ++i) shifter *= 10; + + /* so the representation used (in y->frac) is an array of DECDIG, where + each DECDIG contains a value between 0 and BASE-1, consisting of BASE_FIG + decimal places. + + (that numbers of decimal places are typed as ssize_t is somewhat confusing) + + nf is now position (in decimal places) of the digit from the start of + the array. + + ix is the position (in DECDIGs) of the DECDIG containing the decimal digit, + from the start of the array. + + v is the value of this DECDIG + + ioffset is the number of extra decimal places along of this decimal digit + within v. + + n is the number of decimal digits remaining within v after this decimal digit + shifter is 10**n, + + v % shifter are the remaining digits within v + v % (shifter * 10) are the digit together with the remaining digits within v + v / shifter are the digit's predecessors together with the digit + div = v / shifter / 10 is just the digit's precessors + (v / shifter) - div*10 is just the digit, which is what v ends up being reassigned to. + */ + + fracf = (v % (shifter * 10) > 0); + fracf_1further = ((v % shifter) > 0); + + v /= shifter; + div = v / 10; + v = v - div*10; + /* now v is just the digit required. + now fracf is whether the digit or any of the remaining digits within v are non-zero + now fracf_1further is whether any of the remaining digits within v are non-zero + */ + + /* now check all the remaining DECDIGs for zero-ness a whole DECDIG at a time. + if we spot any non-zeroness, that means that we found a positive digit under + rounding position, and we also found a positive digit under one further than + the rounding position, so both searches (to see if any such non-zero digit exists) + can stop */ + + for (i = ix + 1; (size_t)i < y->Prec; i++) { + if (y->frac[i] % BASE) { + fracf = fracf_1further = 1; + break; + } + } + + /* now fracf = does any positive digit exist under the rounding position? + now fracf_1further = does any positive digit exist under one further than the + rounding position? + now v = the first digit under the rounding position */ + + /* drop digits after pointed digit */ + memset(y->frac + ix + 1, 0, (y->Prec - (ix + 1)) * sizeof(DECDIG)); + + switch (f) { + case VP_ROUND_DOWN: /* Truncate */ + break; + case VP_ROUND_UP: /* Roundup */ + if (fracf) ++div; + break; + case VP_ROUND_HALF_UP: + if (v>=5) ++div; + break; + case VP_ROUND_HALF_DOWN: + if (v > 5 || (v == 5 && fracf_1further)) ++div; + break; + case VP_ROUND_CEIL: + if (fracf && BIGDECIMAL_POSITIVE_P(y)) ++div; + break; + case VP_ROUND_FLOOR: + if (fracf && BIGDECIMAL_NEGATIVE_P(y)) ++div; + break; + case VP_ROUND_HALF_EVEN: /* Banker's rounding */ + if (v > 5) ++div; + else if (v == 5) { + if (fracf_1further) { + ++div; + } + else { + if (ioffset == 0) { + /* v is the first decimal digit of its DECDIG; + need to grab the previous DECDIG if present + to check for evenness of the previous decimal + digit (which is same as that of the DECDIG since + base 10 has a factor of 2) */ + if (ix && (y->frac[ix-1] % 2)) ++div; + } + else { + if (div % 2) ++div; + } + } + } + break; + } + for (i = 0; i <= n; ++i) div *= 10; + if (div >= BASE) { + if (ix) { + y->frac[ix] = 0; + VpRdup(y, ix); + } + else { + short s = VpGetSign(y); + SIGNED_VALUE e = y->exponent; + VpSetOne(y); + VpSetSign(y, s); + y->exponent = e + 1; + } + } + else { + y->frac[ix] = div; + VpNmlz(y); + } + if (exptoadd > 0) { + y->exponent += (SIGNED_VALUE)(exptoadd / BASE_FIG); + exptoadd %= (ssize_t)BASE_FIG; + for (i = 0; i < exptoadd; i++) { + y->frac[0] *= 10; + if (y->frac[0] >= BASE) { + y->frac[0] /= BASE; + y->exponent++; + } + } + } + return 1; +} + +VP_EXPORT int +VpLeftRound(Real *y, unsigned short f, ssize_t nf) +/* + * Round from the left hand side of the digits. + */ +{ + DECDIG v; + if (!VpHasVal(y)) return 0; /* Unable to round */ + v = y->frac[0]; + nf -= VpExponent(y) * (ssize_t)BASE_FIG; + while ((v /= 10) != 0) nf--; + nf += (ssize_t)BASE_FIG-1; + return VpMidRound(y, f, nf); +} + +VP_EXPORT int +VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf) +{ + /* First,assign whole value in truncation mode */ + if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */ + return VpMidRound(y, f, nf); +} + +static int +VpLimitRound(Real *c, size_t ixDigit) +{ + size_t ix = VpGetPrecLimit(); + if (!VpNmlz(c)) return -1; + if (!ix) return 0; + if (!ixDigit) ixDigit = c->Prec-1; + if ((ix + BASE_FIG - 1) / BASE_FIG > ixDigit + 1) return 0; + return VpLeftRound(c, VpGetRoundMode(), (ssize_t)ix); +} + +/* If I understand correctly, this is only ever used to round off the final decimal + digit of precision */ +static void +VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v) +{ + int f = 0; + + unsigned short const rounding_mode = VpGetRoundMode(); + + if (VpLimitRound(c, ixDigit)) return; + if (!v) return; + + v /= BASE1; + switch (rounding_mode) { + case VP_ROUND_DOWN: + break; + case VP_ROUND_UP: + if (v) f = 1; + break; + case VP_ROUND_HALF_UP: + if (v >= 5) f = 1; + break; + case VP_ROUND_HALF_DOWN: + /* this is ok - because this is the last digit of precision, + the case where v == 5 and some further digits are nonzero + will never occur */ + if (v >= 6) f = 1; + break; + case VP_ROUND_CEIL: + if (v && BIGDECIMAL_POSITIVE_P(c)) f = 1; + break; + case VP_ROUND_FLOOR: + if (v && BIGDECIMAL_NEGATIVE_P(c)) f = 1; + break; + case VP_ROUND_HALF_EVEN: /* Banker's rounding */ + /* as per VP_ROUND_HALF_DOWN, because this is the last digit of precision, + there is no case to worry about where v == 5 and some further digits are nonzero */ + if (v > 5) f = 1; + else if (v == 5 && vPrev % 2) f = 1; + break; + } + if (f) { + VpRdup(c, ixDigit); + VpNmlz(c); + } +} + +/* + * Rounds up m(plus one to final digit of m). + */ +static int +VpRdup(Real *m, size_t ind_m) +{ + DECDIG carry; + + if (!ind_m) ind_m = m->Prec; + + carry = 1; + while (carry > 0 && ind_m--) { + m->frac[ind_m] += carry; + if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE; + else carry = 0; + } + if (carry > 0) { /* Overflow,count exponent and set fraction part be 1 */ + if (!AddExponent(m, 1)) return 0; + m->Prec = m->frac[0] = 1; + } + else { + VpNmlz(m); + } + return 1; +} + +/* + * y = x - fix(x) + */ +VP_EXPORT void +VpFrac(Real *y, Real *x) +{ + size_t my, ind_y, ind_x; + + if (!VpHasVal(x)) { + VpAsgn(y, x, 1); + goto Exit; + } + + if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) { + VpSetZero(y, VpGetSign(x)); + goto Exit; + } + else if (x->exponent <= 0) { + VpAsgn(y, x, 1); + goto Exit; + } + + /* satisfy: x->exponent > 0 */ + + y->Prec = x->Prec - (size_t)x->exponent; + y->Prec = Min(y->Prec, y->MaxPrec); + y->exponent = 0; + VpSetSign(y, VpGetSign(x)); + ind_y = 0; + my = y->Prec; + ind_x = x->exponent; + while (ind_y < my) { + y->frac[ind_y] = x->frac[ind_x]; + ++ind_y; + ++ind_x; + } + VpNmlz(y); + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpFrac y=%\n", y); + VPrint(stdout, " x=%\n", x); + } +#endif /* BIGDECIMAL_DEBUG */ + return; +} + +/* + * y = x ** n + */ +VP_EXPORT int +VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n) +{ + size_t s, ss; + ssize_t sign; + Real *w1 = NULL; + Real *w2 = NULL; + + if (VpIsZero(x)) { + if (n == 0) { + VpSetOne(y); + goto Exit; + } + sign = VpGetSign(x); + if (n < 0) { + n = -n; + if (sign < 0) sign = (n % 2) ? -1 : 1; + VpSetInf(y, sign); + } + else { + if (sign < 0) sign = (n % 2) ? -1 : 1; + VpSetZero(y,sign); + } + goto Exit; + } + if (VpIsNaN(x)) { + VpSetNaN(y); + goto Exit; + } + if (VpIsInf(x)) { + if (n == 0) { + VpSetOne(y); + goto Exit; + } + if (n > 0) { + VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1); + goto Exit; + } + VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1); + goto Exit; + } + + if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) { + /* abs(x) = 1 */ + VpSetOne(y); + if (BIGDECIMAL_POSITIVE_P(x)) goto Exit; + if ((n % 2) == 0) goto Exit; + VpSetSign(y, -1); + goto Exit; + } + + if (n > 0) sign = 1; + else if (n < 0) { + sign = -1; + n = -n; + } + else { + VpSetOne(y); + goto Exit; + } + + /* Allocate working variables */ + /* TODO: reconsider MaxPrec of w1 and w2 */ + w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG); + w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG); + + /* calculation start */ + + VpAsgn(y, x, 1); + --n; + while (n > 0) { + VpAsgn(w1, x, 1); + s = 1; + while (ss = s, (s += s) <= (size_t)n) { + VpMult(w2, w1, w1); + VpAsgn(w1, w2, 1); + } + n -= (SIGNED_VALUE)ss; + VpMult(w2, y, w1); + VpAsgn(y, w2, 1); + } + if (sign < 0) { + VpDivd(w1, w2, VpConstOne, y); + VpAsgn(y, w1, 1); + } + +Exit: +#ifdef BIGDECIMAL_DEBUG + if (gfDebug) { + VPrint(stdout, "VpPowerByInt y=%\n", y); + VPrint(stdout, "VpPowerByInt x=%\n", x); + printf(" n=%"PRIdVALUE"\n", n); + } +#endif /* BIGDECIMAL_DEBUG */ + rbd_free_struct(w2); + rbd_free_struct(w1); + return 1; +} + +#ifdef BIGDECIMAL_DEBUG +int +VpVarCheck(Real * v) +/* + * Checks the validity of the Real variable v. + * [Input] + * v ... Real *, variable to be checked. + * [Returns] + * 0 ... correct v. + * other ... error + */ +{ + size_t i; + + if (v->MaxPrec == 0) { + printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n", + v->MaxPrec); + return 1; + } + if (v->Prec == 0 || v->Prec > v->MaxPrec) { + printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec); + printf(" Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec); + return 2; + } + for (i = 0; i < v->Prec; ++i) { + if (v->frac[i] >= BASE) { + printf("ERROR(VpVarCheck): Illegal fraction\n"); + printf(" Frac[%"PRIuSIZE"]=%"PRIuDECDIG"\n", i, v->frac[i]); + printf(" Prec. =%"PRIuSIZE"\n", v->Prec); + printf(" Exp. =%"PRIdVALUE"\n", v->exponent); + printf(" BASE =%"PRIuDECDIG"\n", BASE); + return 3; + } + } + return 0; +} +#endif /* BIGDECIMAL_DEBUG */ diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.h b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.h new file mode 100644 index 00000000..54fed811 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bigdecimal.h @@ -0,0 +1,313 @@ +/* + * + * Ruby BigDecimal(Variable decimal precision) extension library. + * + * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp) + * + */ + +#ifndef RUBY_BIG_DECIMAL_H +#define RUBY_BIG_DECIMAL_H 1 + +#define RUBY_NO_OLD_COMPATIBILITY +#include "ruby/ruby.h" +#include "missing.h" + +#ifdef HAVE_FLOAT_H +# include +#endif + +#ifdef HAVE_INT64_T +# define DECDIG uint32_t +# define DECDIG_DBL uint64_t +# define DECDIG_DBL_SIGNED int64_t +# define SIZEOF_DECDIG 4 +# define PRI_DECDIG_PREFIX "" +# ifdef PRI_LL_PREFIX +# define PRI_DECDIG_DBL_PREFIX PRI_LL_PREFIX +# else +# define PRI_DECDIG_DBL_PREFIX "l" +# endif +#else +# define DECDIG uint16_t +# define DECDIG_DBL uint32_t +# define DECDIG_DBL_SIGNED int32_t +# define SIZEOF_DECDIG 2 +# define PRI_DECDIG_PREFIX "h" +# define PRI_DECDIG_DBL_PREFIX "" +#endif + +#define PRIdDECDIG PRI_DECDIG_PREFIX"d" +#define PRIiDECDIG PRI_DECDIG_PREFIX"i" +#define PRIoDECDIG PRI_DECDIG_PREFIX"o" +#define PRIuDECDIG PRI_DECDIG_PREFIX"u" +#define PRIxDECDIG PRI_DECDIG_PREFIX"x" +#define PRIXDECDIG PRI_DECDIG_PREFIX"X" + +#define PRIdDECDIG_DBL PRI_DECDIG_DBL_PREFIX"d" +#define PRIiDECDIG_DBL PRI_DECDIG_DBL_PREFIX"i" +#define PRIoDECDIG_DBL PRI_DECDIG_DBL_PREFIX"o" +#define PRIuDECDIG_DBL PRI_DECDIG_DBL_PREFIX"u" +#define PRIxDECDIG_DBL PRI_DECDIG_DBL_PREFIX"x" +#define PRIXDECDIG_DBL PRI_DECDIG_DBL_PREFIX"X" + +#if SIZEOF_DECDIG == 4 +# define BIGDECIMAL_BASE ((DECDIG)1000000000U) +# define BIGDECIMAL_COMPONENT_FIGURES 9 +/* + * The number of components required for a 64-bit integer. + * + * INT64_MAX: 9_223372036_854775807 + * UINT64_MAX: 18_446744073_709551615 + */ +# define BIGDECIMAL_INT64_MAX_LENGTH 3 + +#elif SIZEOF_DECDIG == 2 +# define BIGDECIMAL_BASE ((DECDIG)10000U) +# define BIGDECIMAL_COMPONENT_FIGURES 4 +/* + * The number of components required for a 64-bit integer. + * + * INT64_MAX: 922_3372_0368_5477_5807 + * UINT64_MAX: 1844_6744_0737_0955_1615 + */ +# define BIGDECIMAL_INT64_MAX_LENGTH 5 + +#else +# error Unknown size of DECDIG +#endif + +#define BIGDECIMAL_DOUBLE_FIGURES (1+DBL_DIG) + +#if defined(__cplusplus) +extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif +#endif + +extern VALUE rb_cBigDecimal; + +/* + * NaN & Infinity + */ +#define SZ_NaN "NaN" +#define SZ_INF "Infinity" +#define SZ_PINF "+Infinity" +#define SZ_NINF "-Infinity" + +/* + * #define VP_EXPORT other than static to let VP_ routines + * be called from outside of this module. + */ +#define VP_EXPORT static + +/* Exception mode */ +#define VP_EXCEPTION_ALL ((unsigned short)0x00FF) +#define VP_EXCEPTION_INFINITY ((unsigned short)0x0001) +#define VP_EXCEPTION_NaN ((unsigned short)0x0002) +#define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004) +#define VP_EXCEPTION_OVERFLOW ((unsigned short)0x0001) /* 0x0008) */ +#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0010) + +/* Following 2 exceptions can't controlled by user */ +#define VP_EXCEPTION_OP ((unsigned short)0x0020) + +#define BIGDECIMAL_EXCEPTION_MODE_DEFAULT 0U + +/* This is used in BigDecimal#mode */ +#define VP_ROUND_MODE ((unsigned short)0x0100) + +/* Rounding mode */ +#define VP_ROUND_UP RBD_ROUND_UP +#define VP_ROUND_DOWN RBD_ROUND_DOWN +#define VP_ROUND_HALF_UP RBD_ROUND_HALF_UP +#define VP_ROUND_HALF_DOWN RBD_ROUND_HALF_DOWN +#define VP_ROUND_CEIL RBD_ROUND_CEIL +#define VP_ROUND_FLOOR RBD_ROUND_FLOOR +#define VP_ROUND_HALF_EVEN RBD_ROUND_HALF_EVEN + +enum rbd_rounding_mode { + RBD_ROUND_UP = 1, + RBD_ROUND_DOWN = 2, + RBD_ROUND_HALF_UP = 3, + RBD_ROUND_HALF_DOWN = 4, + RBD_ROUND_CEIL = 5, + RBD_ROUND_FLOOR = 6, + RBD_ROUND_HALF_EVEN = 7, + + RBD_ROUND_DEFAULT = RBD_ROUND_HALF_UP, + RBD_ROUND_TRUNCATE = RBD_ROUND_DOWN, + RBD_ROUND_BANKER = RBD_ROUND_HALF_EVEN, + RBD_ROUND_CEILING = RBD_ROUND_CEIL +}; + +#define BIGDECIMAL_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP + +/* Sign flag */ +#define VP_SIGN_NaN 0 /* NaN */ +#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */ +#define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */ +#define VP_SIGN_POSITIVE_FINITE 2 /* Positive finite number */ +#define VP_SIGN_NEGATIVE_FINITE -2 /* Negative finite number */ +#define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */ +#define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */ + +/* The size of fraction part array */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define FLEXIBLE_ARRAY_SIZE /* */ +#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define FLEXIBLE_ARRAY_SIZE 0 +#else +#define FLEXIBLE_ARRAY_SIZE 1 +#endif + +/* + * VP representation + * r = 0.xxxxxxxxx *BASE**exponent + */ +typedef struct { + VALUE obj; /* Back pointer(VALUE) for Ruby object. */ + size_t MaxPrec; /* Maximum precision size */ + /* This is the actual size of frac[] */ + /*(frac[0] to frac[MaxPrec] are available). */ + size_t Prec; /* Current precision size. */ + /* This indicates how much the */ + /* array frac[] is actually used. */ + SIGNED_VALUE exponent; /* Exponent part. */ + short sign; /* Attributes of the value. */ + /* + * ==0 : NaN + * 1 : Positive zero + * -1 : Negative zero + * 2 : Positive number + * -2 : Negative number + * 3 : Positive infinite number + * -3 : Negative infinite number + */ + short flag; /* Not used in vp_routines,space for user. */ + DECDIG frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */ +} Real; + +/* + * ------------------ + * EXPORTables. + * ------------------ + */ + +VP_EXPORT Real *VpNewRbClass(size_t mx, char const *str, VALUE klass, bool strict_p, bool raise_exception); + +VP_EXPORT Real *VpCreateRbObject(size_t mx, const char *str, bool raise_exception); + +#define VpBaseFig() BIGDECIMAL_COMPONENT_FIGURES +#define VpDblFig() BIGDECIMAL_DOUBLE_FIGURES +#define VpBaseVal() BIGDECIMAL_BASE + +/* Zero,Inf,NaN (isinf(),isnan() used to check) */ +VP_EXPORT double VpGetDoubleNaN(void); +VP_EXPORT double VpGetDoublePosInf(void); +VP_EXPORT double VpGetDoubleNegInf(void); +VP_EXPORT double VpGetDoubleNegZero(void); + +/* These 2 functions added at v1.1.7 */ +VP_EXPORT size_t VpGetPrecLimit(void); +VP_EXPORT size_t VpSetPrecLimit(size_t n); + +/* Round mode */ +VP_EXPORT int VpIsRoundMode(unsigned short n); +VP_EXPORT unsigned short VpGetRoundMode(void); +VP_EXPORT unsigned short VpSetRoundMode(unsigned short n); + +VP_EXPORT int VpException(unsigned short f,const char *str,int always); +#if 0 /* unused */ +VP_EXPORT int VpIsNegDoubleZero(double v); +#endif +VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt); +VP_EXPORT size_t VpInit(DECDIG BaseVal); +VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p, int exc); +VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw); +VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation); +VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b); +VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b); +VP_EXPORT int VpComp(Real *a,Real *b); +VP_EXPORT ssize_t VpExponent10(Real *a); +VP_EXPORT void VpSzMantissa(Real *a, char *buf, size_t bufsize); +VP_EXPORT int VpToSpecialString(Real *a, char *buf, size_t bufsize, int fPlus); +VP_EXPORT void VpToString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus); +VP_EXPORT void VpToFString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus); +VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne); +VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m); +VP_EXPORT void VpDtoV(Real *m,double d); +#if 0 /* unused */ +VP_EXPORT void VpItoV(Real *m,S_INT ival); +#endif +VP_EXPORT int VpSqrt(Real *y,Real *x); +VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il); +VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf); +VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf); +VP_EXPORT void VpFrac(Real *y, Real *x); +VP_EXPORT int VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n); +#define VpPower VpPowerByInt + +/* VP constants */ +VP_EXPORT Real *VpOne(void); + +/* + * ------------------ + * MACRO definitions. + * ------------------ + */ +#define Abs(a) (((a)>= 0)?(a):(-(a))) +#define Max(a, b) (((a)>(b))?(a):(b)) +#define Min(a, b) (((a)>(b))?(b):(a)) + +#define VpMaxPrec(a) ((a)->MaxPrec) +#define VpPrec(a) ((a)->Prec) +#define VpGetFlag(a) ((a)->flag) + +/* Sign */ + +/* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */ +#define VpGetSign(a) (((a)->sign>0)?1:(-1)) +/* Change sign of a to a>0,a<0 if s = 1,-1 respectively */ +#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((ssize_t)(a)->sign);else (a)->sign=-(short)Abs((ssize_t)(a)->sign);} +/* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */ +#define VpSetSign(a,s) {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;} + +/* 1 */ +#define VpSetOne(a) {(a)->Prec=(a)->exponent=(a)->frac[0]=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;} + +/* ZEROs */ +#define VpIsPosZero(a) ((a)->sign==VP_SIGN_POSITIVE_ZERO) +#define VpIsNegZero(a) ((a)->sign==VP_SIGN_NEGATIVE_ZERO) +#define VpIsZero(a) (VpIsPosZero(a) || VpIsNegZero(a)) +#define VpSetPosZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_ZERO) +#define VpSetNegZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_ZERO) +#define VpSetZero(a,s) (void)(((s)>0)?VpSetPosZero(a):VpSetNegZero(a)) + +/* NaN */ +#define VpIsNaN(a) ((a)->sign==VP_SIGN_NaN) +#define VpSetNaN(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NaN) + +/* Infinity */ +#define VpIsPosInf(a) ((a)->sign==VP_SIGN_POSITIVE_INFINITE) +#define VpIsNegInf(a) ((a)->sign==VP_SIGN_NEGATIVE_INFINITE) +#define VpIsInf(a) (VpIsPosInf(a) || VpIsNegInf(a)) +#define VpIsDef(a) ( !(VpIsNaN(a)||VpIsInf(a)) ) +#define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE) +#define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE) +#define VpSetInf(a,s) (void)(((s)>0)?VpSetPosInf(a):VpSetNegInf(a)) +#define VpHasVal(a) (a->frac[0]) +#define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1)) +#define VpExponent(a) (a->exponent) +#ifdef BIGDECIMAL_DEBUG +int VpVarCheck(Real * v); +#endif /* BIGDECIMAL_DEBUG */ + +#if defined(__cplusplus) +#if 0 +{ /* satisfy cc-mode */ +#endif +} /* extern "C" { */ +#endif +#endif /* RUBY_BIG_DECIMAL_H */ diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bits.h b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bits.h new file mode 100644 index 00000000..6e1e4776 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/bits.h @@ -0,0 +1,141 @@ +#ifndef BIGDECIMAL_BITS_H +#define BIGDECIMAL_BITS_H + +#include "feature.h" +#include "static_assert.h" + +#if defined(__x86_64__) && defined(HAVE_X86INTRIN_H) +# include /* for _lzcnt_u64, etc. */ +#elif defined(_MSC_VER) && defined(HAVE_INTRIN_H) +# include /* for the following intrinsics */ +#endif + +#if defined(_MSC_VER) && defined(__AVX2__) +# pragma intrinsic(__lzcnt) +# pragma intrinsic(__lzcnt64) +#endif + +#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0]))) +#define roomof(x, y) (((x) + (y) - 1) / (y)) +#define type_roomof(x, y) roomof(sizeof(x), sizeof(y)) + +#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \ + (a) == 0 ? 0 : \ + (a) == -1 ? (b) < -(max) : \ + (a) > 0 ? \ + ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \ + ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b))) + +#ifdef HAVE_UINT128_T +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \ + 128 - nlz_int128((uint128_t)(x))) +#else +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + 64 - nlz_int64((uint64_t)(x))) +#endif + +static inline unsigned nlz_int32(uint32_t x); +static inline unsigned nlz_int64(uint64_t x); +#ifdef HAVE_UINT128_T +static inline unsigned nlz_int128(uint128_t x); +#endif + +static inline unsigned int +nlz_int32(uint32_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT) + /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC. + * AMD CPUs have had this instruction for decades (since K10) but for + * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum + * safety. */ + return (unsigned int)__lzcnt(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U32) + return (unsigned int)_lzcnt_u32(x); + +#elif defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE) + unsigned long r; + return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; + +#elif __has_builtin(__builtin_clz) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32); + return x ? (unsigned int)__builtin_clz(x) : 32; + +#else + uint32_t y; + unsigned n = 32; + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); +#endif +} + +static inline unsigned int +nlz_int64(uint64_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT64) + return (unsigned int)__lzcnt64(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U64) + return (unsigned int)_lzcnt_u64(x); + +#elif defined(_WIN64) && defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE64) + unsigned long r; + return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; + +#elif __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) && !(defined(__sun) && defined(__sparc)) + if (x == 0) { + return 64; + } + else if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + __builtin_unreachable(); + } + +#else + uint64_t y; + unsigned int n = 64; + y = x >> 32; if (y) {n -= 32; x = y;} + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); + +#endif +} + +#ifdef HAVE_UINT128_T +static inline unsigned int +nlz_int128(uint128_t x) +{ + uint64_t y = (uint64_t)(x >> 64); + + if (x == 0) { + return 128; + } + else if (y == 0) { + return (unsigned int)nlz_int64(x) + 64; + } + else { + return (unsigned int)nlz_int64(y); + } +} +#endif + +#endif /* BIGDECIMAL_BITS_H */ diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/extconf.rb b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/extconf.rb new file mode 100644 index 00000000..cf4290f5 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/extconf.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: false +require 'mkmf' + +def have_builtin_func(name, check_expr, opt = "", &b) + checking_for checking_message(name.funcall_style, nil, opt) do + if try_compile(< +#endif + +#ifdef RBIMPL_HAS_BUILTIN +# define BIGDECIMAL_HAS_BUILTIN(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__) + +#else +# /* The following section is copied from CRuby's builtin.h */ +# +# ifdef __has_builtin +# if defined(__INTEL_COMPILER) +# /* :TODO: Intel C Compiler has __has_builtin (since 19.1 maybe?), and is +# * reportedly broken. We have to skip them. However the situation can +# * change. They might improve someday. We need to revisit here later. */ +# elif defined(__GNUC__) && ! __has_builtin(__builtin_alloca) +# /* FreeBSD's defines its own *broken* version of +# * __has_builtin. Cygwin copied that content to be a victim of the +# * broken-ness. We don't take them into account. */ +# else +# define HAVE___HAS_BUILTIN 1 +# endif +# endif +# +# if defined(HAVE___HAS_BUILTIN) +# define BIGDECIMAL_HAS_BUILTIN(_) __has_builtin(_) +# +# elif defined(__GNUC__) +# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _ +# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 6)) +# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 1 +# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 1 +# else +# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 0 +# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 0 +# endif +# elif defined(_MSC_VER) +# define BIGDECIMAL_HAS_BUILTIN(_) 0 +# +# else +# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _ +# define BIGDECIMAL_HAS_BUILTIN___builtin_clz HAVE_BUILTIN___BUILTIN_CLZ +# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl HAVE_BUILTIN___BUILTIN_CLZL +# endif +#endif /* RBIMPL_HAS_BUILTIN */ + +#ifndef __has_builtin +# define __has_builtin(...) BIGDECIMAL_HAS_BUILTIN(__VA_ARGS__) +#endif + +#endif /* BIGDECIMAL_HAS_FEATURE_H */ diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.c b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.c new file mode 100644 index 00000000..1454c281 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.c @@ -0,0 +1,28 @@ +#include + +#ifdef HAVE_RUBY_ATOMIC_H +# include +#endif + +#ifdef RUBY_ATOMIC_PTR_CAS +# define ATOMIC_PTR_CAS(var, old, new) RUBY_ATOMIC_PTR_CAS(var, old, new) +#endif + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +/* GCC warns about unknown sanitizer, which is annoying. */ +# undef NO_SANITIZE +# define NO_SANITIZE(x, y) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wattributes\"") \ + __attribute__((__no_sanitize__(x))) y; \ + _Pragma("GCC diagnostic pop") \ + y +#endif + +#undef strtod +#define strtod BigDecimal_strtod +#undef dtoa +#define dtoa BigDecimal_dtoa +#undef hdtoa +#define hdtoa BigDecimal_hdtoa +#include "missing/dtoa.c" diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.h b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.h new file mode 100644 index 00000000..325554b5 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing.h @@ -0,0 +1,196 @@ +#ifndef MISSING_H +#define MISSING_H 1 + +#if defined(__cplusplus) +extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +#ifndef RB_UNUSED_VAR +# if defined(_MSC_VER) && _MSC_VER >= 1911 +# define RB_UNUSED_VAR(x) x [[maybe_unused]] + +# elif defined(__has_cpp_attribute) && __has_cpp_attribute(maybe_unused) +# define RB_UNUSED_VAR(x) x [[maybe_unused]] + +# elif defined(__has_c_attribute) && __has_c_attribute(maybe_unused) +# define RB_UNUSED_VAR(x) x [[maybe_unused]] + +# elif defined(__GNUC__) +# define RB_UNUSED_VAR(x) x __attribute__ ((unused)) + +# else +# define RB_UNUSED_VAR(x) x +# endif +#endif /* RB_UNUSED_VAR */ + +#if defined(_MSC_VER) && _MSC_VER >= 1310 +# define HAVE___ASSUME 1 + +#elif defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300 +# define HAVE___ASSUME 1 +#endif + +#ifndef UNREACHABLE +# if __has_builtin(__builtin_unreachable) +# define UNREACHABLE __builtin_unreachable() + +# elif defined(HAVE___ASSUME) +# define UNREACHABLE __assume(0) + +# else +# define UNREACHABLE /* unreachable */ +# endif +#endif /* UNREACHABLE */ + +/* bool */ + +#if defined(__bool_true_false_are_defined) +# /* Take that. */ + +#elif defined(HAVE_STDBOOL_H) +# include + +#else +typedef unsigned char _Bool; +# define bool _Bool +# define true ((_Bool)+1) +# define false ((_Bool)-1) +# define __bool_true_false_are_defined +#endif + +/* abs */ + +#ifndef HAVE_LABS +static inline long +labs(long const x) +{ + if (x < 0) return -x; + return x; +} +#endif + +#ifndef HAVE_LLABS +static inline LONG_LONG +llabs(LONG_LONG const x) +{ + if (x < 0) return -x; + return x; +} +#endif + +#ifdef vabs +# undef vabs +#endif +#if SIZEOF_VALUE <= SIZEOF_INT +# define vabs abs +#elif SIZEOF_VALUE <= SIZEOF_LONG +# define vabs labs +#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG +# define vabs llabs +#endif + +/* finite */ + +#ifndef HAVE_FINITE +static int +finite(double) +{ + return !isnan(n) && !isinf(n); +} +#endif + +#ifndef isfinite +# ifndef HAVE_ISFINITE +# define HAVE_ISFINITE 1 +# define isfinite(x) finite(x) +# endif +#endif + +/* dtoa */ +char *BigDecimal_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve); + +/* rational */ + +#ifndef HAVE_RB_RATIONAL_NUM +static inline VALUE +rb_rational_num(VALUE rat) +{ +#ifdef RRATIONAL + return RRATIONAL(rat)->num; +#else + return rb_funcall(rat, rb_intern("numerator"), 0); +#endif +} +#endif + +#ifndef HAVE_RB_RATIONAL_DEN +static inline VALUE +rb_rational_den(VALUE rat) +{ +#ifdef RRATIONAL + return RRATIONAL(rat)->den; +#else + return rb_funcall(rat, rb_intern("denominator"), 0); +#endif +} +#endif + +/* complex */ + +#ifndef HAVE_RB_COMPLEX_REAL +static inline VALUE +rb_complex_real(VALUE cmp) +{ +#ifdef RCOMPLEX + return RCOMPLEX(cmp)->real; +#else + return rb_funcall(cmp, rb_intern("real"), 0); +#endif +} +#endif + +#ifndef HAVE_RB_COMPLEX_IMAG +static inline VALUE +rb_complex_imag(VALUE cmp) +{ +# ifdef RCOMPLEX + return RCOMPLEX(cmp)->imag; +# else + return rb_funcall(cmp, rb_intern("imag"), 0); +# endif +} +#endif + +/* st */ + +#ifndef ST2FIX +# undef RB_ST2FIX +# define RB_ST2FIX(h) LONG2FIX((long)(h)) +# define ST2FIX(h) RB_ST2FIX(h) +#endif + +/* warning */ + +#if !defined(HAVE_RB_CATEGORY_WARN) || !defined(HAVE_CONST_RB_WARN_CATEGORY_DEPRECATED) +# define rb_category_warn(category, ...) rb_warn(__VA_ARGS__) +#endif + +#if defined(__cplusplus) +#if 0 +{ /* satisfy cc-mode */ +#endif +} /* extern "C" { */ +#endif + +#endif /* MISSING_H */ diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing/dtoa.c b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing/dtoa.c new file mode 100644 index 00000000..41b0a221 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/missing/dtoa.c @@ -0,0 +1,3462 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define INFNAN_CHECK on IEEE systems to cause strtod to check for + * Infinity and NaN (case insensitively). On some systems (e.g., + * some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define YES_ALIAS to permit aliasing certain double values with + * arrays of ULongs. This leads to slightly better code with + * some compilers and was always used prior to 19990916, but it + * is not strictly legal and can cause trouble with aggressively + * optimizing compilers (e.g., gcc 2.95.1 under -O2). + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + */ + +#ifdef WORDS_BIGENDIAN +#define IEEE_BIG_ENDIAN +#else +#define IEEE_LITTLE_ENDIAN +#endif + +#ifdef __vax__ +#define VAX +#undef IEEE_BIG_ENDIAN +#undef IEEE_LITTLE_ENDIAN +#endif + +#if defined(__arm__) && !defined(__VFP_FP__) +#define IEEE_BIG_ENDIAN +#undef IEEE_LITTLE_ENDIAN +#endif + +#undef Long +#undef ULong + +#include + +#if (INT_MAX >> 30) && !(INT_MAX >> 31) +#define Long int +#define ULong unsigned int +#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31) +#define Long long int +#define ULong unsigned long int +#else +#error No 32bit integer +#endif + +#if HAVE_LONG_LONG +#define Llong LONG_LONG +#else +#define NO_LONG_LONG +#endif + +#ifdef DEBUG +#include +#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);} +#endif + +#ifndef ISDIGIT +#include +#define ISDIGIT(c) isdigit(c) +#endif +#include +#include +#include + +#ifdef USE_LOCALE +#include +#endif + +#ifdef MALLOC +extern void *MALLOC(size_t); +#else +#define MALLOC xmalloc +#endif +#ifdef FREE +extern void FREE(void*); +#else +#define FREE xfree +#endif +#ifndef NO_SANITIZE +#define NO_SANITIZE(x, y) y +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_BIG_ENDIAN +#define IEEE_Arith +#endif +#ifdef IEEE_LITTLE_ENDIAN +#define IEEE_Arith +#endif + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include +#endif /* Bad_float_h */ + +#include + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif +#endif + +#ifndef hexdigit +static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; +#endif + +#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef YES_ALIAS +typedef double double_u; +# define dval(x) (x) +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) (((ULong *)&(x))[1]) +# define word1(x) (((ULong *)&(x))[0]) +# else +# define word0(x) (((ULong *)&(x))[0]) +# define word1(x) (((ULong *)&(x))[1]) +# endif +#else +typedef U double_u; +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) ((x).L[1]) +# define word1(x) ((x).L[0]) +# else +# define word0(x) ((x).L[0]) +# define word1(x) ((x).L[1]) +# endif +# define dval(x) ((x).d) +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__) +#define Storeinc(a,b,c) (((unsigned short *)(a))[1] = (unsigned short)(b), \ +((unsigned short *)(a))[0] = (unsigned short)(c), (a)++) +#else +#define Storeinc(a,b,c) (((unsigned short *)(a))[0] = (unsigned short)(b), \ +((unsigned short *)(a))[1] = (unsigned short)(c), (a)++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) ((a) = rnd_prod((a), (b))) +#define rounded_quotient(a,b) ((a) = rnd_quot((a), (b))) +extern double rnd_prod(double, double), rnd_quot(double, double); +#else +#define rounded_product(a,b) ((a) *= (b)) +#define rounded_quotient(a,b) ((a) /= (b)) +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#define FFFFFFFF 0xffffffffUL + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#define MULTIPLE_THREADS 1 + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#else +#define ACQUIRE_DTOA_LOCK(n) /*unused right now*/ +#define FREE_DTOA_LOCK(n) /*unused right now*/ +#endif + +#ifndef ATOMIC_PTR_CAS +#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old)) +#endif +#ifndef LIKELY +#define LIKELY(x) (x) +#endif +#ifndef UNLIKELY +#define UNLIKELY(x) (x) +#endif +#ifndef ASSUME +#define ASSUME(x) (void)(x) +#endif + +#define Kmax 15 + +struct Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; +}; + +typedef struct Bigint Bigint; + +static Bigint *freelist[Kmax+1]; + +static Bigint * +Balloc(int k) +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + size_t len; +#endif + + rv = 0; + ACQUIRE_DTOA_LOCK(0); + if (k <= Kmax) { + rv = freelist[k]; + while (rv) { + Bigint *rvn = rv; + rv = ATOMIC_PTR_CAS(freelist[k], rv, rv->next); + if (LIKELY(rvn == rv)) { + ASSUME(rv); + break; + } + } + } + if (!rv) { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax) { + double *pnext = pmem_next; + while (pnext - private_mem + len <= PRIVATE_mem) { + double *p = pnext; + pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len); + if (LIKELY(p == pnext)) { + rv = (Bigint*)pnext; + ASSUME(rv); + break; + } + } + } + if (!rv) + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; +} + +static void +Bfree(Bigint *v) +{ + Bigint *vn; + if (v) { + if (v->k > Kmax) { + FREE(v); + return; + } + ACQUIRE_DTOA_LOCK(0); + do { + vn = v->next = freelist[v->k]; + } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn)); + FREE_DTOA_LOCK(0); + } +} + +#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \ +(y)->wds*sizeof(Long) + 2*sizeof(int)) + +static Bigint * +multadd(Bigint *b, int m, int a) /* multiply by m and add a */ +{ + int i, wds; + ULong *x; +#ifdef ULLong + ULLong carry, y; +#else + ULong carry, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } while (++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = (ULong)carry; + b->wds = wds; + } + return b; +} + +static Bigint * +s2b(const char *s, int nd0, int nd, ULong y9) +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for (k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do { + b = multadd(b, 10, *s++ - '0'); + } while (++i < nd0); + s++; + } + else + s += 10; + for (; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; +} + +static int +hi0bits(register ULong x) +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; +} + +static int +lo0bits(ULong *y) +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; +} + +static Bigint * +i2b(int i) +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; +} + +static Bigint * +mult(Bigint *a, Bigint *b) +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for (x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for (; xb < xbe; xc0++) { + if ((y = *xb++) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = (ULong)(z & FFFFFFFF); + } while (x < xae); + *xc = (ULong)carry; + } + } +#else +#ifdef Pack_32 + for (; xb < xbe; xb++, xc0++) { + if ((y = *xb & 0xffff) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } while (x < xae); + *xc = (ULong)carry; + } + if ((y = *xb >> 16) != 0) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } while (x < xae); + *xc = z2; + } + } +#else + for (; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } while (x < xae); + *xc = (ULong)carry; + } + } +#endif +#endif + for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; +} + +static Bigint *p5s; + +static Bigint * +pow5mult(Bigint *b, int k) +{ + Bigint *b1, *p5, *p51; + Bigint *p5tmp; + int i; + static const int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3) != 0) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = i2b(625); + p5->next = 0; + p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5); + if (UNLIKELY(p5tmp)) { + Bfree(p5); + p5 = p5tmp; + } + } + FREE_DTOA_LOCK(1); + } + for (;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = mult(p5,p5); + p51->next = 0; + p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51); + if (UNLIKELY(p5tmp)) { + Bfree(p51); + p51 = p5tmp; + } + } + FREE_DTOA_LOCK(1); + } + p5 = p51; + } + return b; +} + +static Bigint * +lshift(Bigint *b, int k) +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for (i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for (i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } while (x < xe); + if ((*x1 = z) != 0) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } while (x < xe); + if (*x1 = z) + ++n1; + } +#endif + else + do { + *x1++ = *x++; + } while (x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; +} + +static int +cmp(Bigint *a, Bigint *b) +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for (;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; +} + +NO_SANITIZE("unsigned-integer-overflow", static Bigint * diff(Bigint *a, Bigint *b)); +static Bigint * +diff(Bigint *a, Bigint *b) +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } while (xb < xbe); + while (xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } while (xb < xbe); + while (xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } while (xb < xbe); + while (xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while (!*--xc) + wa--; + c->wds = wa; + return c; +} + +static double +ulp(double x_) +{ + register Long L; + double_u x, a; + dval(x) = x_; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); +} + +static double +b2d(Bigint *a, int *e) +{ + ULong *xa, *xa0, w, y, z; + int k; + double_u d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif +ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); +} + +static Bigint * +d2b(double d_, int *e, int *bits) +{ + double_u d; + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; +#endif + dval(d) = d_; +#ifdef VAX + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift)) != 0) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1) != 0) { + if ((k = lo0bits(&y)) != 0) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while (!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; +} +#undef d0 +#undef d1 + +static double +ratio(Bigint *a, Bigint *b) +{ + double_u da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); +} + +static const double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif +}; + +static const double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif +}; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static const double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#ifndef IEEE_Arith +#undef INFNAN_CHECK +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + +static int +match(const char **sp, char *t) +{ + int c, d; + const char *s = *sp; + + while (d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; +} + +#ifndef No_Hex_NaN +static void +hexnan(double *rvp, const char **sp) +{ + ULong c, x[2]; + const char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + while (c = *(const unsigned char*)++s) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } +} +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + +NO_SANITIZE("unsigned-integer-overflow", double strtod(const char *s00, char **se)); +double +strtod(const char *s00, char **se) +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + const char *s, *s0, *s1; + double aadj, adj; + double_u aadj1, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + const char *s2; +#endif + + errno = 0; + sign = nz0 = nz = 0; + dval(rv) = 0.; + for (s = s00;;s++) + switch (*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } +break2: + if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s0 = ++s; + adj = 0; + aadj = 1.0; + nd0 = -4; + + if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (*s == '0') { + while (*++s == '0'); + s1 = strchr(hexdigit, *s); + } + if (s1 != NULL) { + do { + adj += aadj * ((s1 - hexdigit) & 15); + nd0 += 4; + aadj /= 16; + } while (*++s && (s1 = strchr(hexdigit, *s))); + } + + if (*s == '.') { + dsign = 1; + if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (nd0 < 0) { + while (*s == '0') { + s++; + nd0 -= 4; + } + } + for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { + adj += aadj * ((s1 - hexdigit) & 15); + if ((aadj /= 16) == 0.0) { + while (strchr(hexdigit, *++s)); + break; + } + } + } + else { + dsign = 0; + } + + if (*s == 'P' || *s == 'p') { + dsign = 0x2C - *++s; /* +: 2B, -: 2D */ + if (abs(dsign) == 1) s++; + else dsign = 1; + + nd = 0; + c = *s; + if (c < '0' || '9' < c) goto ret0; + do { + nd *= 10; + nd += c; + nd -= '0'; + c = *++s; + /* Float("0x0."+("0"*267)+"1fp2095") */ + if (nd + dsign * nd0 > 2095) { + while ('0' <= c && c <= '9') c = *++s; + break; + } + } while ('0' <= c && c <= '9'); + nd0 += nd * dsign; + } + else { + if (dsign) goto ret0; + } + dval(rv) = ldexp(adj, nd0); + goto ret; + } + nz0 = 1; + while (*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < DBL_DIG + 2) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for (;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + if (!ISDIGIT(s[1])) + goto dig_done; + c = *++s; + if (!nd) { + for (; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for (; c >= '0' && c <= '9'; c = *++s) { +have_dig: + nz++; + if (nd > DBL_DIG * 4) { + continue; + } + if (c -= '0') { + nf += nz; + for (i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 2) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 2) + z = 10*z + c; + nz = 0; + } + } + } +dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch (c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while (c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while ((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch (c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ +ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = bb = bd = bs = delta = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ +vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15) != 0) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { +ovfl: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch (rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15) != 0) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for (j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << (j-32); + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { +undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for (;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } +apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(dval(rv)); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(dval(rv)); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { +drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(dval(rv)); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(dval(rv)); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = dval(aadj1) = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + dval(aadj1) = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + dval(aadj1) = -aadj; + } + } + else { + aadj *= 0.5; + dval(aadj1) = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch (Rounding) { + case 2: /* towards +infinity */ + dval(aadj1) -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + dval(aadj1) += 0.5; + } +#else + if (Flt_Rounds == 0) + dval(aadj1) += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (int)aadj) <= 0) + z = 1; + aadj = z; + dval(aadj1) = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + dval(aadj1) = (double)(int)(aadj + 0.5); + if (!dsign) + dval(aadj1) = -dval(aadj1); + } + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif +cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif +retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); +ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); +} + +NO_SANITIZE("unsigned-integer-overflow", static int quorem(Bigint *b, Bigint *S)); +static int +quorem(Bigint *b, Bigint *S) +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } while (sx <= sxe); + if (!*bxe) { + bx = b->x; + while (--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } while (sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while (--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; +} + +#ifndef MULTIPLE_THREADS +static char *dtoa_result; +#endif + +#ifndef MULTIPLE_THREADS +static char * +rv_alloc(int i) +{ + return dtoa_result = MALLOC(i); +} +#else +#define rv_alloc(i) MALLOC(i) +#endif + +static char * +nrv_alloc(const char *s, char **rve, size_t n) +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while ((*t = *s++) != 0) t++; + if (rve) + *rve = t; + return rv; +} + +#define rv_strdup(s, rve) nrv_alloc((s), (rve), strlen(s)+1) + +#ifndef MULTIPLE_THREADS +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + +static void +freedtoa(char *s) +{ + FREE(s); +} +#endif + +static const char INFSTR[] = "Infinity"; +static const char NANSTR[] = "NaN"; +static const char ZEROSTR[] = "0"; + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + +char * +dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick, half = 0; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S; + double ds; + double_u d, d2, eps; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + + dval(d) = d_; + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return rv_strdup(INFSTR, rve); +#endif + return rv_strdup(NANSTR, rve); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return rv_strdup(ZEROSTR, rve); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(dval(d), &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) + : word1(d) << (32 - i); + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; + switch (mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i+1); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for (; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if ((j1 = -k) != 0) { + dval(d) *= tens[j1 & 0xf]; + for (j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for (i = 0;;) { + L = (int)dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for (i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while (*--s == '0') ; + s++; + goto ret1; + } + half = 1; + if ((*(s-1) - '0') & 1) { + goto bump_up; + } + break; + } + } +#ifndef No_leftright + } +#endif +fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) <= 5*ds) + goto no_digits; + goto one_digit; + } + for (i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch (rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || (dval(d) == ds && (L & 1))) { +bump_up: + while (*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if ((j = b5 - m5) != 0) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) + i = 32 - i; +#else + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) != 0) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ +no_digits: + k = -1 - ndigits; + goto ret; + } +one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for (i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch (rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') + goto round_9_up; + } +accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ +round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS +keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for (i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch (rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || (j == 0 && (dig & 1))) { + roundoff: + while (*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + if (!half || (*s - '0') & 1) + ++*s; + } + else { + while (*--s == '0') ; + } + s++; +ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } +ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; +} + +/*- + * Copyright (c) 2004-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define DBL_MANH_SIZE 20 +#define DBL_MANL_SIZE 32 +#define DBL_ADJ (DBL_MAX_EXP - 2) +#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1) +#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1) +#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | ((v) << Exp_shift))) +#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask)) +#define dmanl_get(u) ((uint32_t)word1(u)) + + +/* + * This procedure converts a double-precision number in IEEE format + * into a string of hexadecimal digits and an exponent of 2. Its + * behavior is bug-for-bug compatible with dtoa() in mode 2, with the + * following exceptions: + * + * - An ndigits < 0 causes it to use as many digits as necessary to + * represent the number exactly. + * - The additional xdigs argument should point to either the string + * "0123456789ABCDEF" or the string "0123456789abcdef", depending on + * which case is desired. + * - This routine does not repeat dtoa's mistake of setting decpt + * to 9999 in the case of an infinity or NaN. INT_MAX is used + * for this purpose instead. + * + * Note that the C99 standard does not specify what the leading digit + * should be for non-zero numbers. For instance, 0x1.3p3 is the same + * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes + * the leading digit a 1. This ensures that the exponent printed is the + * actual base-2 exponent, i.e., ilogb(d). + * + * Inputs: d, xdigs, ndigits + * Outputs: decpt, sign, rve + */ +char * +hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve) +{ + U u; + char *s, *s0; + int bufsize; + uint32_t manh, manl; + + u.d = d; + if (word0(u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + + if (isinf(d)) { /* FP_INFINITE */ + *decpt = INT_MAX; + return rv_strdup(INFSTR, rve); + } + else if (isnan(d)) { /* FP_NAN */ + *decpt = INT_MAX; + return rv_strdup(NANSTR, rve); + } + else if (d == 0.0) { /* FP_ZERO */ + *decpt = 1; + return rv_strdup(ZEROSTR, rve); + } + else if (dexp_get(u)) { /* FP_NORMAL */ + *decpt = dexp_get(u) - DBL_ADJ; + } + else { /* FP_SUBNORMAL */ + u.d *= 5.363123171977039e+154 /* 0x1p514 */; + *decpt = dexp_get(u) - (514 + DBL_ADJ); + } + + if (ndigits == 0) /* dtoa() compatibility */ + ndigits = 1; + + /* + * If ndigits < 0, we are expected to auto-size, so we allocate + * enough space for all the digits. + */ + bufsize = (ndigits > 0) ? ndigits : SIGFIGS; + s0 = rv_alloc(bufsize+1); + + /* Round to the desired number of digits. */ + if (SIGFIGS > ndigits && ndigits > 0) { + float redux = 1.0f; + int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG; + dexp_set(u, offset); + u.d += redux; + u.d -= redux; + *decpt += dexp_get(u) - offset; + } + + manh = dmanh_get(u); + manl = dmanl_get(u); + *s0 = '1'; + for (s = s0 + 1; s < s0 + bufsize; s++) { + *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf]; + manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4)); + manl <<= 4; + } + + /* If ndigits < 0, we are expected to auto-size the precision. */ + if (ndigits < 0) { + for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--) + ; + } + + s = s0 + ndigits; + *s = '\0'; + if (rve != NULL) + *rve = s; + return (s0); +} + +#ifdef __cplusplus +#if 0 +{ /* satisfy cc-mode */ +#endif +} +#endif diff --git a/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/static_assert.h b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/static_assert.h new file mode 100644 index 00000000..9295729b --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/ext/bigdecimal/static_assert.h @@ -0,0 +1,54 @@ +#ifndef BIGDECIMAL_STATIC_ASSERT_H +#define BIGDECIMAL_STATIC_ASSERT_H + +#include "feature.h" + +#ifdef HAVE_RUBY_INTERNAL_STATIC_ASSERT_H +# include +#endif + +#ifdef RBIMPL_STATIC_ASSERT +# define STATIC_ASSERT RBIMPL_STATIC_ASSERT +#endif + +#ifndef STATIC_ASSERT +# /* The following section is copied from CRuby's static_assert.h */ + +# if defined(__cplusplus) && defined(__cpp_static_assert) +# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */ +# define BIGDECIMAL_STATIC_ASSERT0 static_assert + +# elif defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER >= 1600 +# define BIGDECIMAL_STATIC_ASSERT0 static_assert + +# elif defined(__INTEL_CXX11_MODE__) +# define BIGDECIMAL_STATIC_ASSERT0 static_assert + +# elif defined(__cplusplus) && __cplusplus >= 201103L +# define BIGDECIMAL_STATIC_ASSERT0 static_assert + +# elif defined(__cplusplus) && __has_extension(cxx_static_assert) +# define BIGDECIMAL_STATIC_ASSERT0 __extension__ static_assert + +# elif defined(__STDC_VERSION__) && __has_extension(c_static_assert) +# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert + +# elif defined(__STDC_VERSION__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert +#endif + +# if defined(__DOXYGEN__) +# define STATIC_ASSERT static_assert + +# elif defined(BIGDECIMAL_STATIC_ASSERT0) +# define STATIC_ASSERT(name, expr) \ + BIGDECIMAL_STATIC_ASSERT0(expr, #name ": " #expr) + +# else +# define STATIC_ASSERT(name, expr) \ + typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)] +# endif +#endif /* STATIC_ASSERT */ + + +#endif /* BIGDECIMAL_STATIC_ASSERT_H */ diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.rb new file mode 100644 index 00000000..82b3e1b7 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.rb @@ -0,0 +1,5 @@ +if RUBY_ENGINE == 'jruby' + JRuby::Util.load_ext("org.jruby.ext.bigdecimal.BigDecimalLibrary") +else + require 'bigdecimal.so' +end diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.so b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.so new file mode 100755 index 00000000..79cc5e0f Binary files /dev/null and b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal.so differ diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/jacobian.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/jacobian.rb new file mode 100644 index 00000000..4448024c --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/jacobian.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: false + +require 'bigdecimal' + +# require 'bigdecimal/jacobian' +# +# Provides methods to compute the Jacobian matrix of a set of equations at a +# point x. In the methods below: +# +# f is an Object which is used to compute the Jacobian matrix of the equations. +# It must provide the following methods: +# +# f.values(x):: returns the values of all functions at x +# +# f.zero:: returns 0.0 +# f.one:: returns 1.0 +# f.two:: returns 2.0 +# f.ten:: returns 10.0 +# +# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. +# +# x is the point at which to compute the Jacobian. +# +# fx is f.values(x). +# +module Jacobian + module_function + + # Determines the equality of two numbers by comparing to zero, or using the epsilon value + def isEqual(a,b,zero=0.0,e=1.0e-8) + aa = a.abs + bb = b.abs + if aa == zero && bb == zero then + true + else + if ((a-b)/(aa+bb)).abs < e then + true + else + false + end + end + end + + + # Computes the derivative of +f[i]+ at +x[i]+. + # +fx+ is the value of +f+ at +x+. + def dfdxi(f,fx,x,i) + nRetry = 0 + n = x.size + xSave = x[i] + ok = 0 + ratio = f.ten*f.ten*f.ten + dx = x[i].abs/ratio + dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps) + dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps) + until ok>0 do + deriv = [] + nRetry += 1 + if nRetry > 100 + raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]" + end + dx = dx*f.two + x[i] += dx + fxNew = f.values(x) + for j in 0...n do + if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then + ok += 1 + deriv <<= (fxNew[j]-fx[j])/dx + else + deriv <<= f.zero + end + end + x[i] = xSave + end + deriv + end + + # Computes the Jacobian of +f+ at +x+. +fx+ is the value of +f+ at +x+. + def jacobian(f,fx,x) + n = x.size + dfdx = Array.new(n*n) + for i in 0...n do + df = dfdxi(f,fx,x,i) + for j in 0...n do + dfdx[j*n+i] = df[j] + end + end + dfdx + end +end diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/ludcmp.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/ludcmp.rb new file mode 100644 index 00000000..dd265e48 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/ludcmp.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: false +require 'bigdecimal' + +# +# Solves a*x = b for x, using LU decomposition. +# +module LUSolve + module_function + + # Performs LU decomposition of the n by n matrix a. + def ludecomp(a,n,zero=0,one=1) + prec = BigDecimal.limit(nil) + ps = [] + scales = [] + for i in 0...n do # pick up largest(abs. val.) element in each row. + ps <<= i + nrmrow = zero + ixn = i*n + for j in 0...n do + biggst = a[ixn+j].abs + nrmrow = biggst if biggst>nrmrow + end + if nrmrow>zero then + scales <<= one.div(nrmrow,prec) + else + raise "Singular matrix" + end + end + n1 = n - 1 + for k in 0...n1 do # Gaussian elimination with partial pivoting. + biggst = zero; + for i in k...n do + size = a[ps[i]*n+k].abs*scales[ps[i]] + if size>biggst then + biggst = size + pividx = i + end + end + raise "Singular matrix" if biggst<=zero + if pividx!=k then + j = ps[k] + ps[k] = ps[pividx] + ps[pividx] = j + end + pivot = a[ps[k]*n+k] + for i in (k+1)...n do + psin = ps[i]*n + a[psin+k] = mult = a[psin+k].div(pivot,prec) + if mult!=zero then + pskn = ps[k]*n + for j in (k+1)...n do + a[psin+j] -= mult.mult(a[pskn+j],prec) + end + end + end + end + raise "Singular matrix" if a[ps[n1]*n+n1] == zero + ps + end + + # Solves a*x = b for x, using LU decomposition. + # + # a is a matrix, b is a constant vector, x is the solution vector. + # + # ps is the pivot, a vector which indicates the permutation of rows performed + # during LU decomposition. + def lusolve(a,b,ps,zero=0.0) + prec = BigDecimal.limit(nil) + n = ps.size + x = [] + for i in 0...n do + dot = zero + psin = ps[i]*n + for j in 0...i do + dot = a[psin+j].mult(x[j],prec) + dot + end + x <<= b[ps[i]] - dot + end + (n-1).downto(0) do |i| + dot = zero + psin = ps[i]*n + for j in (i+1)...n do + dot = a[psin+j].mult(x[j],prec) + dot + end + x[i] = (x[i]-dot).div(a[psin+i],prec) + end + x + end +end diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/math.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/math.rb new file mode 100644 index 00000000..0b9d0648 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/math.rb @@ -0,0 +1,232 @@ +# frozen_string_literal: false +require 'bigdecimal' + +# +#-- +# Contents: +# sqrt(x, prec) +# sin (x, prec) +# cos (x, prec) +# atan(x, prec) Note: |x|<1, x=0.9999 may not converge. +# PI (prec) +# E (prec) == exp(1.0,prec) +# +# where: +# x ... BigDecimal number to be computed. +# |x| must be small enough to get convergence. +# prec ... Number of digits to be obtained. +#++ +# +# Provides mathematical functions. +# +# Example: +# +# require "bigdecimal/math" +# +# include BigMath +# +# a = BigDecimal((PI(100)/2).to_s) +# puts sin(a,100) # => 0.99999999999999999999......e0 +# +module BigMath + module_function + + # call-seq: + # sqrt(decimal, numeric) -> BigDecimal + # + # Computes the square root of +decimal+ to the specified number of digits of + # precision, +numeric+. + # + # BigMath.sqrt(BigDecimal('2'), 16).to_s + # #=> "0.1414213562373095048801688724e1" + # + def sqrt(x, prec) + x.sqrt(prec) + end + + # call-seq: + # sin(decimal, numeric) -> BigDecimal + # + # Computes the sine of +decimal+ to the specified number of digits of + # precision, +numeric+. + # + # If +decimal+ is Infinity or NaN, returns NaN. + # + # BigMath.sin(BigMath.PI(5)/4, 5).to_s + # #=> "0.70710678118654752440082036563292800375e0" + # + def sin(x, prec) + raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 + return BigDecimal("NaN") if x.infinite? || x.nan? + n = prec + BigDecimal.double_fig + one = BigDecimal("1") + two = BigDecimal("2") + x = -x if neg = x < 0 + if x > (twopi = two * BigMath.PI(prec)) + if x > 30 + x %= twopi + else + x -= twopi while x > twopi + end + end + x1 = x + x2 = x.mult(x,n) + sign = 1 + y = x + d = y + i = one + z = one + while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) + m = BigDecimal.double_fig if m < BigDecimal.double_fig + sign = -sign + x1 = x2.mult(x1,n) + i += two + z *= (i-one) * i + d = sign * x1.div(z,m) + y += d + end + neg ? -y : y + end + + # call-seq: + # cos(decimal, numeric) -> BigDecimal + # + # Computes the cosine of +decimal+ to the specified number of digits of + # precision, +numeric+. + # + # If +decimal+ is Infinity or NaN, returns NaN. + # + # BigMath.cos(BigMath.PI(4), 16).to_s + # #=> "-0.999999999999999999999999999999856613163740061349e0" + # + def cos(x, prec) + raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 + return BigDecimal("NaN") if x.infinite? || x.nan? + n = prec + BigDecimal.double_fig + one = BigDecimal("1") + two = BigDecimal("2") + x = -x if x < 0 + if x > (twopi = two * BigMath.PI(prec)) + if x > 30 + x %= twopi + else + x -= twopi while x > twopi + end + end + x1 = one + x2 = x.mult(x,n) + sign = 1 + y = one + d = y + i = BigDecimal("0") + z = one + while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) + m = BigDecimal.double_fig if m < BigDecimal.double_fig + sign = -sign + x1 = x2.mult(x1,n) + i += two + z *= (i-one) * i + d = sign * x1.div(z,m) + y += d + end + y + end + + # call-seq: + # atan(decimal, numeric) -> BigDecimal + # + # Computes the arctangent of +decimal+ to the specified number of digits of + # precision, +numeric+. + # + # If +decimal+ is NaN, returns NaN. + # + # BigMath.atan(BigDecimal('-1'), 16).to_s + # #=> "-0.785398163397448309615660845819878471907514682065e0" + # + def atan(x, prec) + raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 + return BigDecimal("NaN") if x.nan? + pi = PI(prec) + x = -x if neg = x < 0 + return pi.div(neg ? -2 : 2, prec) if x.infinite? + return pi / (neg ? -4 : 4) if x.round(prec) == 1 + x = BigDecimal("1").div(x, prec) if inv = x > 1 + x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5 + n = prec + BigDecimal.double_fig + y = x + d = y + t = x + r = BigDecimal("3") + x2 = x.mult(x,n) + while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0) + m = BigDecimal.double_fig if m < BigDecimal.double_fig + t = -t.mult(x2,n) + d = t.div(r,m) + y += d + r += 2 + end + y *= 2 if dbl + y = pi / 2 - y if inv + y = -y if neg + y + end + + # call-seq: + # PI(numeric) -> BigDecimal + # + # Computes the value of pi to the specified number of digits of precision, + # +numeric+. + # + # BigMath.PI(10).to_s + # #=> "0.3141592653589793238462643388813853786957412e1" + # + def PI(prec) + raise ArgumentError, "Zero or negative precision for PI" if prec <= 0 + n = prec + BigDecimal.double_fig + zero = BigDecimal("0") + one = BigDecimal("1") + two = BigDecimal("2") + + m25 = BigDecimal("-0.04") + m57121 = BigDecimal("-57121") + + pi = zero + + d = one + k = one + t = BigDecimal("-80") + while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) + m = BigDecimal.double_fig if m < BigDecimal.double_fig + t = t*m25 + d = t.div(k,m) + k = k+two + pi = pi + d + end + + d = one + k = one + t = BigDecimal("956") + while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0) + m = BigDecimal.double_fig if m < BigDecimal.double_fig + t = t.div(m57121,n) + d = t.div(k,m) + pi = pi + d + k = k+two + end + pi + end + + # call-seq: + # E(numeric) -> BigDecimal + # + # Computes e (the base of natural logarithms) to the specified number of + # digits of precision, +numeric+. + # + # BigMath.E(10).to_s + # #=> "0.271828182845904523536028752390026306410273e1" + # + def E(prec) + raise ArgumentError, "Zero or negative precision for E" if prec <= 0 + BigMath.exp(1, prec) + end +end diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/newton.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/newton.rb new file mode 100644 index 00000000..85bacb7f --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/newton.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: false +require "bigdecimal/ludcmp" +require "bigdecimal/jacobian" + +# +# newton.rb +# +# Solves the nonlinear algebraic equation system f = 0 by Newton's method. +# This program is not dependent on BigDecimal. +# +# To call: +# n = nlsolve(f,x) +# where n is the number of iterations required, +# x is the initial value vector +# f is an Object which is used to compute the values of the equations to be solved. +# It must provide the following methods: +# +# f.values(x):: returns the values of all functions at x +# +# f.zero:: returns 0.0 +# f.one:: returns 1.0 +# f.two:: returns 2.0 +# f.ten:: returns 10.0 +# +# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. +# +# On exit, x is the solution vector. +# +module Newton + include LUSolve + include Jacobian + module_function + + def norm(fv,zero=0.0) # :nodoc: + s = zero + n = fv.size + for i in 0...n do + s += fv[i]*fv[i] + end + s + end + + # See also Newton + def nlsolve(f,x) + nRetry = 0 + n = x.size + + f0 = f.values(x) + zero = f.zero + one = f.one + two = f.two + p5 = one/two + d = norm(f0,zero) + minfact = f.ten*f.ten*f.ten + minfact = one/minfact + e = f.eps + while d >= e do + nRetry += 1 + # Not yet converged. => Compute Jacobian matrix + dfdx = jacobian(f,f0,x) + # Solve dfdx*dx = -f0 to estimate dx + dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero) + fact = two + xs = x.dup + begin + fact *= p5 + if fact < minfact then + raise "Failed to reduce function values." + end + for i in 0...n do + x[i] = xs[i] - dx[i]*fact + end + f0 = f.values(x) + dn = norm(f0,zero) + end while(dn>=d) + d = dn + end + nRetry + end +end diff --git a/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/util.rb b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/util.rb new file mode 100644 index 00000000..cb514435 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/lib/bigdecimal/util.rb @@ -0,0 +1,185 @@ +# frozen_string_literal: false +# +#-- +# bigdecimal/util extends various native classes to provide the #to_d method, +# and provides BigDecimal#to_d and BigDecimal#to_digits. +#++ + +require 'bigdecimal' + +class Integer < Numeric + # call-seq: + # int.to_d -> bigdecimal + # + # Returns the value of +int+ as a BigDecimal. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # 42.to_d # => 0.42e2 + # + # See also Kernel.BigDecimal. + # + def to_d + BigDecimal(self) + end +end + + +class Float < Numeric + # call-seq: + # float.to_d -> bigdecimal + # float.to_d(precision) -> bigdecimal + # + # Returns the value of +float+ as a BigDecimal. + # The +precision+ parameter is used to determine the number of + # significant digits for the result. When +precision+ is set to +0+, + # the number of digits to represent the float being converted is determined + # automatically. + # The default +precision+ is +0+. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # 0.5.to_d # => 0.5e0 + # 1.234.to_d # => 0.1234e1 + # 1.234.to_d(2) # => 0.12e1 + # + # See also Kernel.BigDecimal. + # + def to_d(precision=0) + BigDecimal(self, precision) + end +end + + +class String + # call-seq: + # str.to_d -> bigdecimal + # + # Returns the result of interpreting leading characters in +str+ + # as a BigDecimal. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # "0.5".to_d # => 0.5e0 + # "123.45e1".to_d # => 0.12345e4 + # "45.67 degrees".to_d # => 0.4567e2 + # + # See also Kernel.BigDecimal. + # + def to_d + BigDecimal.interpret_loosely(self) + end +end + + +class BigDecimal < Numeric + # call-seq: + # a.to_digits -> string + # + # Converts a BigDecimal to a String of the form "nnnnnn.mmm". + # This method is deprecated; use BigDecimal#to_s("F") instead. + # + # require 'bigdecimal/util' + # + # d = BigDecimal("3.14") + # d.to_digits # => "3.14" + # + def to_digits + if self.nan? || self.infinite? || self.zero? + self.to_s + else + i = self.to_i.to_s + _,f,_,z = self.frac.split + i + "." + ("0"*(-z)) + f + end + end + + # call-seq: + # a.to_d -> bigdecimal + # + # Returns self. + # + # require 'bigdecimal/util' + # + # d = BigDecimal("3.14") + # d.to_d # => 0.314e1 + # + def to_d + self + end +end + + +class Rational < Numeric + # call-seq: + # rat.to_d(precision) -> bigdecimal + # + # Returns the value as a BigDecimal. + # + # The required +precision+ parameter is used to determine the number of + # significant digits for the result. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # Rational(22, 7).to_d(3) # => 0.314e1 + # + # See also Kernel.BigDecimal. + # + def to_d(precision) + BigDecimal(self, precision) + end +end + + +class Complex < Numeric + # call-seq: + # cmp.to_d -> bigdecimal + # cmp.to_d(precision) -> bigdecimal + # + # Returns the value as a BigDecimal. + # + # The +precision+ parameter is required for a rational complex number. + # This parameter is used to determine the number of significant digits + # for the result. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # Complex(0.1234567, 0).to_d(4) # => 0.1235e0 + # Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1 + # + # See also Kernel.BigDecimal. + # + def to_d(*args) + BigDecimal(self) unless self.imag.zero? # to raise error + + if args.length == 0 + case self.real + when Rational + BigDecimal(self.real) # to raise error + end + end + self.real.to_d(*args) + end +end + + +class NilClass + # call-seq: + # nil.to_d -> bigdecimal + # + # Returns nil represented as a BigDecimal. + # + # require 'bigdecimal' + # require 'bigdecimal/util' + # + # nil.to_d # => 0.0 + # + def to_d + BigDecimal(0) + end +end diff --git a/bin/gems/bigdecimal-3.1.9/sample/linear.rb b/bin/gems/bigdecimal-3.1.9/sample/linear.rb new file mode 100644 index 00000000..516c2473 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/sample/linear.rb @@ -0,0 +1,74 @@ +#!/usr/local/bin/ruby +# frozen_string_literal: false + +# +# linear.rb +# +# Solves linear equation system(A*x = b) by LU decomposition method. +# where A is a coefficient matrix,x is an answer vector,b is a constant vector. +# +# USAGE: +# ruby linear.rb [input file solved] +# + +# :stopdoc: +require "bigdecimal" +require "bigdecimal/ludcmp" + +# +# NOTE: +# Change following BigDecimal.limit() if needed. +BigDecimal.limit(100) +# + +include LUSolve +def rd_order(na) + printf("Number of equations ?") if(na <= 0) + n = ARGF.gets().to_i +end + +na = ARGV.size +zero = BigDecimal("0.0") +one = BigDecimal("1.0") + +while (n=rd_order(na))>0 + a = [] + as= [] + b = [] + if na <= 0 + # Read data from console. + printf("\nEnter coefficient matrix element A[i,j]\n") + for i in 0...n do + for j in 0...n do + printf("A[%d,%d]? ",i,j); s = ARGF.gets + a << BigDecimal(s) + as << BigDecimal(s) + end + printf("Contatant vector element b[%d] ? ",i) + b << BigDecimal(ARGF.gets) + end + else + # Read data from specified file. + printf("Coefficient matrix and constant vector.\n") + for i in 0...n do + s = ARGF.gets + printf("%d) %s",i,s) + s = s.split + for j in 0...n do + a << BigDecimal(s[j]) + as << BigDecimal(s[j]) + end + b << BigDecimal(s[n]) + end + end + x = lusolve(a,b,ludecomp(a,n,zero,one),zero) + printf("Answer(x[i] & (A*x-b)[i]) follows\n") + for i in 0...n do + printf("x[%d]=%s ",i,x[i].to_s) + s = zero + for j in 0...n do + s = s + as[i*n+j]*x[j] + end + printf(" & %s\n",(s-b[i]).to_s) + end +end diff --git a/bin/gems/bigdecimal-3.1.9/sample/nlsolve.rb b/bin/gems/bigdecimal-3.1.9/sample/nlsolve.rb new file mode 100644 index 00000000..c2227dac --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/sample/nlsolve.rb @@ -0,0 +1,40 @@ +#!/usr/local/bin/ruby +# frozen_string_literal: false + +# +# nlsolve.rb +# An example for solving nonlinear algebraic equation system. +# + +require "bigdecimal" +require "bigdecimal/newton" +include Newton + +class Function # :nodoc: all + def initialize() + @zero = BigDecimal("0.0") + @one = BigDecimal("1.0") + @two = BigDecimal("2.0") + @ten = BigDecimal("10.0") + @eps = BigDecimal("1.0e-16") + end + def zero;@zero;end + def one ;@one ;end + def two ;@two ;end + def ten ;@ten ;end + def eps ;@eps ;end + def values(x) # <= defines functions solved + f = [] + f1 = x[0]*x[0] + x[1]*x[1] - @two # f1 = x**2 + y**2 - 2 => 0 + f2 = x[0] - x[1] # f2 = x - y => 0 + f <<= f1 + f <<= f2 + f + end +end + +f = BigDecimal.limit(100) +f = Function.new +x = [f.zero,f.zero] # Initial values +n = nlsolve(f,x) +p x diff --git a/bin/gems/bigdecimal-3.1.9/sample/pi.rb b/bin/gems/bigdecimal-3.1.9/sample/pi.rb new file mode 100644 index 00000000..ea966389 --- /dev/null +++ b/bin/gems/bigdecimal-3.1.9/sample/pi.rb @@ -0,0 +1,21 @@ +#!/usr/local/bin/ruby +# frozen_string_literal: false + +# +# pi.rb +# +# Calculates 3.1415.... (the number of times that a circle's diameter +# will fit around the circle) using J. Machin's formula. +# + +require "bigdecimal" +require "bigdecimal/math.rb" + +include BigMath + +if ARGV.size == 1 + print "PI("+ARGV[0]+"):\n" + p PI(ARGV[0].to_i) +else + print "TRY: ruby pi.rb 1000 \n" +end diff --git a/bin/gems/bump-0.10.0/README.md b/bin/gems/bump-0.10.0/README.md new file mode 100644 index 00000000..778acc83 --- /dev/null +++ b/bin/gems/bump-0.10.0/README.md @@ -0,0 +1,163 @@ +[![Build Status](https://travis-ci.org/gregorym/bump.svg)](https://travis-ci.org/gregorym/bump) +[![Gem Version](https://badge.fury.io/rb/bump.svg)](http://badge.fury.io/rb/bump) + +A gem to bump versions of gems and chef-cookbooks. + + - bumps version major / minor / patch / pre + - bundles + - commits changes + +# Installation + + gem install bump + +# Usage + +### Show current version + + bump current + +> 0.1.2 + +### Bump (major, minor, patch, pre) + + bump patch + +> Bump version 0.1.2 to 0.1.3 + +### Show next version + + bump show-next patch + +> 0.1.3 + +### Show version file path + + bump file + +> lib/foo/version.rb + +## Options + +### `--no-commit` + +Do not commit after bumping. + + bump patch --no-commit + +### `--tag` + +Will add a git tag like `v1.2.3` (if the current project is a git repository and `--no-commit` has not been given). + + bump patch --tag + +The `--tag-prefix` option can change the tag prefix: + + bump patch --tag --tag-prefix v- # tag as v-1.2.3 + bump patch --tag --tag-prefix "" # tag as 1.2.3 + +### `--no-bundle` + +Do not run `bundle` command after bumping. + + bump patch --no-bundle + +### `--replace-in` + +Bump the version in additional files. + + bump patch --replace-in Readme.md + +### `--commit-message [MSG], -m [MSG]` + +Append additional information to the commit message. + + bump patch --commit-message "Something extra" + +or + + bump patch -m "Something extra" + +### `--changelog` + +Updates `CHANGELOG.md` when bumping. +This requires a heading (starting with `##`) that includes the previous version and a heading above that, for example: + +```markdown +### Next +- Added bar + +### v0.0.0 - 2019-12-24 +- Added foo +``` + +### `--edit-changelog` + +Updates CHANGELOG.md when bumping (see above), and +opens the changelog in an editor specified in `$EDITOR` (or `vi`), +then waits for the editor to be closed and continues. + +```bash +EDITOR="subl -n -w" bump patch --edit-changelog +``` + +## Rake + +```ruby +# Rakefile +require "bump/tasks" + +# +# do not always tag the version +# Bump.tag_by_default = false +# +# bump the version in additional files +# Bump.replace_in_default = ["Readme.md"] +# +# Maintain changelog: +# Bump.changelog = true +# Opens the changelog in an editor when bumping +# Bump.changelog = :editor +``` + + rake bump:current # display current version + rake bump:show-next INCREMENT=minor # display next minor version + rake bump:file # display version file path + + # bumping using defaults for `COMMIT`, `TAG`, and `BUNDLE` + rake bump:major + rake bump:patch + rake bump:minor + rake bump:pre + + # bumping with option(s) + rake bump:patch TAG=false BUNDLE=false # commit, but don't tag or run `bundle` + rake bump:patch TAG=true TAG_PREFIX=v- # tag with a prefix 'v-' ex. the tag will look like v-0.0.1 + rake bump:patch COMMIT=false TAG=false # don't commit, don't tag + rake bump:minor BUNDLE=false # don't run `bundle` + +## Ruby + +```ruby +require "bump" +Bump::Bump.current # -> "1.2.3" +Bump::Bump.next_version("patch") # -> "1.2.4" +Bump::Bump.file # -> "lib/foo/version.rb" +Bump::Bump.run("patch") # -> version changed +Bump::Bump.run("patch", tag: true, tag_prefix: 'v-') # -> version changed with tagging with '-v' as prefix +Bump::Bump.run("patch", commit: false, bundle:false, tag:false) # -> version changed with options +Bump::Bump.run("patch", commit_message: '[no ci]') # -> creates a commit message with 'v1.2.3 [no ci]' instead of default: 'v1.2.3' +``` + +# Supported locations + +- `VERSION` file with `1.2.3` +- `gemspec` with `gem.version = "1.2.3"` or `Gem:Specification.new "gem-name", "1.2.3" do` +- `lib/**/version.rb` file with `VERSION = "1.2.3"` +- `metadata.rb` with `version "1.2.3"` +- `VERSION = "1.2.3"` in `lib/**/*.rb` + +# Author + +Gregory
+License: MIT diff --git a/bin/gems/bump-0.10.0/bin/bump b/bin/gems/bump-0.10.0/bin/bump new file mode 100755 index 00000000..9d401842 --- /dev/null +++ b/bin/gems/bump-0.10.0/bin/bump @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'optparse' +require 'shellwords' + +options = {} +OptionParser.new do |opts| + opts.banner = <<-BANNER.gsub(/^ /, "") + Bump your gem version. + + Usage: + bump current # show current version + bump show-next INCREMENT # show next (pre|patch|minor|major) version of your gem + bump file # show version file path + bump pre # increase prerelease version of your gem (1.0.0-X) [alpha, beta, rc, ] + bump patch # increase patch version of your gem (1.0.X) + bump minor # increase minor version of your gem (1.X.0) + bump major # increase major version of your gem (X.0.0) + bump set 1.2.3 # set the version number to the given value + + Options: + BANNER + opts.on("--no-commit", "Do not make a commit.") { options[:commit] = false } + opts.on("-m", "--commit-message MSG", String, "Append MSG to the commit message.") { |msg| options[:commit_message] = msg } + opts.on("--no-bundle", "Do not bundle.") { options[:bundle] = false } + opts.on("--tag", "Create git tag from version (only if commit is true).") { options[:tag] = true } + opts.on("--tag-prefix TAG_PREFIX", "Prefix the tag with this string, ex. 'v'") { |tag_prefix| options[:tag_prefix] = tag_prefix } + opts.on("--replace-in FILE", String, "Replace old version with the new version additionally in this file") { |f| (options[:replace_in] ||= []) << f } + opts.on("--changelog", "Update CHANGELOG.md") { options[:changelog] = true } + opts.on("--edit-changelog", "Use $EDITOR to open changelog before committing, e.g. 'subl -n -w' or 'nano'.") { options[:changelog] = :editor } + opts.on("--value-only", "Do not prefix the output with any descriptive text") { options[:value_only] = true } + opts.on("-h", "--help", "Show this.") { puts opts; exit } +end.parse! + +valid_argv = ["set", "show-next"].include?(ARGV.first) ? 2 : 1 +abort "Usage instructions: bump --help" unless ARGV.size == valid_argv + +options[:version] = ARGV[1] if ARGV[0] == "set" +options[:increment] = ARGV[1] if ARGV[0] == "show-next" + +require File.dirname(__FILE__) + '/../lib/bump' +output, status = Bump::Bump.run(ARGV.first, options) +puts output +exit status diff --git a/bin/gems/bump-0.10.0/lib/bump.rb b/bin/gems/bump-0.10.0/lib/bump.rb new file mode 100644 index 00000000..35e22c51 --- /dev/null +++ b/bin/gems/bump-0.10.0/lib/bump.rb @@ -0,0 +1,312 @@ +# frozen_string_literal: true + +module Bump + class InvalidIncrementError < StandardError; end + class InvalidOptionError < StandardError; end + class InvalidVersionError < StandardError; end + class UnfoundVersionError < StandardError; end + class TooManyVersionFilesError < StandardError; end + class UnfoundVersionFileError < StandardError; end + class RakeArgumentsDeprecatedError < StandardError; end + + class <` edge case [#6992](https://github.com/rubygems/rubygems/pull/6992) + - Stop bundler eagerly loading all specs with exts [#6945](https://github.com/rubygems/rubygems/pull/6945) + +## Performance: + + - Reduce allocations when parsing lockfile [#6976](https://github.com/rubygems/rubygems/pull/6976) + - Stop allocating the same settings keys repeatedly [#6963](https://github.com/rubygems/rubygems/pull/6963) + +## Documentation: + + - Improve formatting and global source information in `bundle plugin` man page [#7045](https://github.com/rubygems/rubygems/pull/7045) + - Update man page of `bundle exec` to reflect default true of flag `--keep-file-descriptors` [#7033](https://github.com/rubygems/rubygems/pull/7033) + +# 2.4.20 (September 27, 2023) + +## Enhancements: + + - Bump actions/checkout to v4 in bundler gem template [#6966](https://github.com/rubygems/rubygems/pull/6966) + - Add support for the `ruby-3.2.2` format in the `ruby file:` Gemfile directive, and explicitly test the `3.2.2@gemset` format as rejected [#6954](https://github.com/rubygems/rubygems/pull/6954) + - Support `ruby file: ".tool-versions"` in Gemfile [#6898](https://github.com/rubygems/rubygems/pull/6898) + - Unify LockfileParser loading of SPECS section [#6933](https://github.com/rubygems/rubygems/pull/6933) + - Only check circular deps when dependency api is available, not on full index sources [#6919](https://github.com/rubygems/rubygems/pull/6919) + +## Bug fixes: + + - Allow standalone mode to work on a Windows edge case [#6989](https://github.com/rubygems/rubygems/pull/6989) + - Fix `bundle outdated` crashing when both `ref` and `branch` specified for a git gem in Gemfile [#6959](https://github.com/rubygems/rubygems/pull/6959) + - Fix `bundle update --redownload` [#6924](https://github.com/rubygems/rubygems/pull/6924) + - Fixed malformed bundler version in lockfile making Bundler crash [#6920](https://github.com/rubygems/rubygems/pull/6920) + - Fix standalone install crashing when using legacy gemfiles with multiple global sources [#6918](https://github.com/rubygems/rubygems/pull/6918) + - Resolve ruby version file relative to bundle root [#6892](https://github.com/rubygems/rubygems/pull/6892) + +## Performance: + + - Lazily construct fetcher debug messages [#6973](https://github.com/rubygems/rubygems/pull/6973) + - Avoid allocating empty hashes in Index [#6962](https://github.com/rubygems/rubygems/pull/6962) + - Improve `Bundler::Index` efficiency by removing unnecessary creation and dups [#6931](https://github.com/rubygems/rubygems/pull/6931) + - (Further) Improve Bundler::Settings#[] performance and memory usage [#6923](https://github.com/rubygems/rubygems/pull/6923) + - Don't use full indexes unnecessarily on legacy Gemfiles [#6916](https://github.com/rubygems/rubygems/pull/6916) + - Improve memory usage in Bundler::Settings, and thus improve boot time [#6884](https://github.com/rubygems/rubygems/pull/6884) + +# 2.4.19 (August 17, 2023) + +## Enhancements: + + - Add `file` option to `ruby` method in Gemfile [#6876](https://github.com/rubygems/rubygems/pull/6876) + - Show better error when PAT can't authenticate to a private server [#6871](https://github.com/rubygems/rubygems/pull/6871) + - Don't fallback to old dependency API when bad credentials are configured [#6869](https://github.com/rubygems/rubygems/pull/6869) + +## Bug fixes: + + - Fix git source conservativeness [#6850](https://github.com/rubygems/rubygems/pull/6850) + +## Documentation: + + - Clarify that `bundle info` takes a gem name [#6875](https://github.com/rubygems/rubygems/pull/6875) + +# 2.4.18 (August 2, 2023) + +## Security: + + - Merge URI-0.12.2 for Bundler [#6779](https://github.com/rubygems/rubygems/pull/6779) + +## Enhancements: + + - Update Magnus version in Rust extension gem template [#6843](https://github.com/rubygems/rubygems/pull/6843) + +## Documentation: + + - Update bundle-outdated(1) man to use table output [#6833](https://github.com/rubygems/rubygems/pull/6833) + +# 2.4.17 (July 14, 2023) + +## Enhancements: + + - Avoid printing "Using ..." messages when version has not changed [#6804](https://github.com/rubygems/rubygems/pull/6804) + +## Bug fixes: + + - Fix `bundler/setup` unintendedly writing to the filesystem [#6814](https://github.com/rubygems/rubygems/pull/6814) + +# 2.4.16 (July 10, 2023) + +## Bug fixes: + + - Exclude Bundler from missing locked dependencies check [#6792](https://github.com/rubygems/rubygems/pull/6792) + - Fix another incorrect removal of "ruby" platform from lockfile when changing path sources [#6784](https://github.com/rubygems/rubygems/pull/6784) + - Fix git source lockfile instability [#6786](https://github.com/rubygems/rubygems/pull/6786) + +## Documentation: + + - `gemfile.5`: Code format the default glob to escape Markdown [#6790](https://github.com/rubygems/rubygems/pull/6790) + +# 2.4.15 (June 29, 2023) + +## Enhancements: + + - Improve edge case error message [#6733](https://github.com/rubygems/rubygems/pull/6733) + +## Bug fixes: + + - Fix `bundle lock --update --bundler` [#6213](https://github.com/rubygems/rubygems/pull/6213) + +# 2.4.14 (June 12, 2023) + +## Enhancements: + + - Stop publishing Gemfile in default gem template [#6723](https://github.com/rubygems/rubygems/pull/6723) + - Avoid infinite loops when hitting resolution bugs [#6722](https://github.com/rubygems/rubygems/pull/6722) + - Make `LockfileParser` usable with just a lockfile [#6694](https://github.com/rubygems/rubygems/pull/6694) + - Always rely on `$LOAD_PATH` when jumping from `exe/` to `lib/` [#6702](https://github.com/rubygems/rubygems/pull/6702) + - Make `frozen` setting take precedence over `deployment` setting [#6685](https://github.com/rubygems/rubygems/pull/6685) + - Show an error when trying to update bundler in frozen mode [#6684](https://github.com/rubygems/rubygems/pull/6684) + +## Bug fixes: + + - Fix `deployment` vs `path` precedence [#6703](https://github.com/rubygems/rubygems/pull/6703) + - Fix inline mode with multiple sources [#6699](https://github.com/rubygems/rubygems/pull/6699) + +# 2.4.13 (May 9, 2023) + +## Bug fixes: + + - Fix unexpected fallbacks to full index by adding FalseClass and Time to the SafeMarshal list [#6655](https://github.com/rubygems/rubygems/pull/6655) + +## Documentation: + + - Fix broken hyperlinks in bundle cache documentation [#6606](https://github.com/rubygems/rubygems/pull/6606) + +# 2.4.12 (April 11, 2023) + +## Enhancements: + + - Remove reference to `pry` gem from generated `bin/console` file [#6515](https://github.com/rubygems/rubygems/pull/6515) + +# 2.4.11 (April 10, 2023) + +## Security: + + - Use URI-0.12.1 (safe against CVE-2023-28755 ReDoS vulnerability) [#6558](https://github.com/rubygems/rubygems/pull/6558) + +## Enhancements: + + - Remove one fallback to full indexes on big gemfiles [#6578](https://github.com/rubygems/rubygems/pull/6578) + - Generate native gems with `-fvisibility=hidden` [#6541](https://github.com/rubygems/rubygems/pull/6541) + +## Bug fixes: + + - Fix resolver hangs when dealing with an incomplete lockfile [#6552](https://github.com/rubygems/rubygems/pull/6552) + - Fix prereleases not being considered by gem version promoter when there's no lockfile [#6537](https://github.com/rubygems/rubygems/pull/6537) + +# 2.4.10 (March 27, 2023) + +## Bug fixes: + + - Fix some unnecessary top level dependency downgrades [#6535](https://github.com/rubygems/rubygems/pull/6535) + - Fix incorrect ruby platform removal from lockfile when adding Gemfile dependencies [#6540](https://github.com/rubygems/rubygems/pull/6540) + - Fix installing plugins in frozen mode [#6543](https://github.com/rubygems/rubygems/pull/6543) + - Restore "enumerability" of `SpecSet` [#6532](https://github.com/rubygems/rubygems/pull/6532) + +# 2.4.9 (March 20, 2023) + +## Security: + + - Don't recommend `--full-index` on errors [#6493](https://github.com/rubygems/rubygems/pull/6493) + +## Enhancements: + + - Fix duplicated specs in some error messages [#6475](https://github.com/rubygems/rubygems/pull/6475) + - When running `bundle lock --update `, checkout locked revision of unrelated git sources directly [#6459](https://github.com/rubygems/rubygems/pull/6459) + - Avoid expiring git sources when unnecessary [#6458](https://github.com/rubygems/rubygems/pull/6458) + - Use `RbSys::ExtensionTask` when creating new rust gems [#6352](https://github.com/rubygems/rubygems/pull/6352) + - Don't ignore pre-releases when there's only one candidate [#6441](https://github.com/rubygems/rubygems/pull/6441) + +## Bug fixes: + + - Fix incorrect removal of ruby platform when auto-healing corrupted lockfiles [#6495](https://github.com/rubygems/rubygems/pull/6495) + - Don't consider platform specific candidates when `force_ruby_platform` set [#6442](https://github.com/rubygems/rubygems/pull/6442) + - Better deal with circular dependencies [#6330](https://github.com/rubygems/rubygems/pull/6330) + +## Documentation: + + - Add debugging docs [#6387](https://github.com/rubygems/rubygems/pull/6387) + - Document our current release policy [#6450](https://github.com/rubygems/rubygems/pull/6450) + +# 2.4.8 (March 8, 2023) + +## Security: + + - Safe load all marshaled data [#6384](https://github.com/rubygems/rubygems/pull/6384) + +## Enhancements: + + - Better suggestion when `bundler/setup` fails due to missing gems and Gemfile is not the default [#6428](https://github.com/rubygems/rubygems/pull/6428) + - Simplify the gem package file filter in the gemspec template [#6344](https://github.com/rubygems/rubygems/pull/6344) + - Auto-heal corrupted `Gemfile.lock` with no specs [#6423](https://github.com/rubygems/rubygems/pull/6423) + - Auto-heal on corrupted lockfile with missing deps [#6400](https://github.com/rubygems/rubygems/pull/6400) + - Give a better message when Gemfile branch does not exist [#6383](https://github.com/rubygems/rubygems/pull/6383) + +## Bug fixes: + + - Respect --no-install option for git: sources [#6088](https://github.com/rubygems/rubygems/pull/6088) + - Fix `gems.rb` lockfile for bundler version lookup in template [#6413](https://github.com/rubygems/rubygems/pull/6413) + +## Documentation: + + - Switch supporting explanations to all Ruby Central [#6419](https://github.com/rubygems/rubygems/pull/6419) + +# 2.4.7 (February 15, 2023) + +## Enhancements: + + - Add `--gemfile` flag to `bundle init` to configure gemfile name to generate [#6046](https://github.com/rubygems/rubygems/pull/6046) + - Improve solve failure explanations by using better wording [#6366](https://github.com/rubygems/rubygems/pull/6366) + - Restore better error message when locked ref does not exist [#6356](https://github.com/rubygems/rubygems/pull/6356) + - Avoid crashing when installing from a corrupted lockfile [#6355](https://github.com/rubygems/rubygems/pull/6355) + - Improve wording of unmet dependencies warning [#6357](https://github.com/rubygems/rubygems/pull/6357) + - Add Ruby 3.2 and 3.3 platforms to Gemfile DSL [#6346](https://github.com/rubygems/rubygems/pull/6346) + +## Bug fixes: + + - Fix crash in pub grub involving empty ranges [#6365](https://github.com/rubygems/rubygems/pull/6365) + - Make gemspec file generated by `bundle gem` properly exclude itself from packaged gem [#6339](https://github.com/rubygems/rubygems/pull/6339) + - Preserve relative path sources in standalone setup [#6327](https://github.com/rubygems/rubygems/pull/6327) + +# 2.4.6 (January 31, 2023) + +## Enhancements: + + - Don't warn on `bundle binstubs --standalone --all` [#6312](https://github.com/rubygems/rubygems/pull/6312) + +## Bug fixes: + + - Don't undo require decorations made by other gems [#6308](https://github.com/rubygems/rubygems/pull/6308) + - Fix `bundler/inline` not properly installing gems with extensions when used more than once [#6306](https://github.com/rubygems/rubygems/pull/6306) + - Fix `bundler/inline` not skipping installation when gems already there, when used more than once [#6305](https://github.com/rubygems/rubygems/pull/6305) + +# 2.4.5 (January 21, 2023) + +## Bug fixes: + + - Fix `bundler/inline` not resolving properly if gems not preinstalled [#6282](https://github.com/rubygems/rubygems/pull/6282) + - Fix packages for external platforms being introduced in lockfile when Bundler retries resolution [#6285](https://github.com/rubygems/rubygems/pull/6285) + +## Documentation: + + - Update bundle-exec man page to not use deprecated `Bundler.with_clean_env` [#6284](https://github.com/rubygems/rubygems/pull/6284) + +# 2.4.4 (January 16, 2023) + +## Bug fixes: + + - Fix platform specific gems removed from the lockfile [#6266](https://github.com/rubygems/rubygems/pull/6266) + - Properly handle incompatibilities on platform specific gems [#6270](https://github.com/rubygems/rubygems/pull/6270) + - Optimistically exclude prereleases from initial resolution [#6246](https://github.com/rubygems/rubygems/pull/6246) + - Fix another case of not properly falling back to ruby variant when materializing [#6261](https://github.com/rubygems/rubygems/pull/6261) + - Skip setting `BUNDLER_SETUP` on Ruby 2.6 [#6252](https://github.com/rubygems/rubygems/pull/6252) + - Let resolver deal with legacy gems with equivalent version and different dependencies [#6219](https://github.com/rubygems/rubygems/pull/6219) + +# 2.4.3 (January 6, 2023) + +## Enhancements: + + - Enhance `bundle open` command to allow opening subdir/file of gem [#6146](https://github.com/rubygems/rubygems/pull/6146) + +## Bug fixes: + + - Fix pointing GitHub sources to PRs [#6241](https://github.com/rubygems/rubygems/pull/6241) + - Fix version ranges incorrectly handling platforms [#6240](https://github.com/rubygems/rubygems/pull/6240) + - Cleanup unnecessary gems when removing lockfile platforms [#6234](https://github.com/rubygems/rubygems/pull/6234) + - When auto-removing RUBY platform don't add specific platform if not needed [#6233](https://github.com/rubygems/rubygems/pull/6233) + - Fallback to selecting installable candidates if possible when materializing specs [#6225](https://github.com/rubygems/rubygems/pull/6225) + +## Documentation: + + - Fix several typos [#6224](https://github.com/rubygems/rubygems/pull/6224) + +# 2.4.2 (January 1, 2023) + +## Performance: + + - Speed up resolution by properly merging incompatibility ranges [#6215](https://github.com/rubygems/rubygems/pull/6215) + +## Documentation: + + - Remove stray word in `bundle config` man page [#6220](https://github.com/rubygems/rubygems/pull/6220) + +# 2.4.1 (December 24, 2022) + +## Enhancements: + + - Allow Bundler to run on old RubyGems + Ruby 2.7 without warnings [#6187](https://github.com/rubygems/rubygems/pull/6187) + +## Bug fixes: + + - Fix dependencies scoped to other platforms making resolver fail [#6189](https://github.com/rubygems/rubygems/pull/6189) + - Restore annotated git tag support [#6186](https://github.com/rubygems/rubygems/pull/6186) + +# 2.4.0 (December 24, 2022) + +## Security: + + - In README generated by `bundle gem`, do not fill rubygems.org install commands with the gem name automatically [#6093](https://github.com/rubygems/rubygems/pull/6093) + - Use safe Marshal deserialization for dependency API response [#6141](https://github.com/rubygems/rubygems/pull/6141) + +## Breaking changes: + + - Remove Travis CI from gem skeleton [#6150](https://github.com/rubygems/rubygems/pull/6150) + - Drop support for Ruby 2.3, 2.4, 2.5 and RubyGems 2.5, 2.6, 2.7 [#6107](https://github.com/rubygems/rubygems/pull/6107) + - Completely remove "auto-sudo" feature [#5888](https://github.com/rubygems/rubygems/pull/5888) + +## Deprecations: + + - Turn `--ext` option of `bundle gem` into string. Deprecate usage without explicit value [#6144](https://github.com/rubygems/rubygems/pull/6144) + +## Features: + + - Add `--ext=rust` support to `bundle gem` for creating simple gems with Rust extensions [#6149](https://github.com/rubygems/rubygems/pull/6149) + - Migrate our resolver engine to PubGrub [#5960](https://github.com/rubygems/rubygems/pull/5960) + +## Performance: + + - Make cloning git repos faster [#4475](https://github.com/rubygems/rubygems/pull/4475) + +## Enhancements: + + - Add `bundle lock --update --bundler` [#6134](https://github.com/rubygems/rubygems/pull/6134) + - Support for pre flag in `bundle update`/`bundle lock` [#5258](https://github.com/rubygems/rubygems/pull/5258) + - Improve error message when changing Gemfile to a mistyped git ref [#6130](https://github.com/rubygems/rubygems/pull/6130) + - Remove special handling of some `LoadError` and `NoMethodError` [#6115](https://github.com/rubygems/rubygems/pull/6115) + +## Bug fixes: + + - Don't unlock dependencies of a gemspec when its version changes [#6184](https://github.com/rubygems/rubygems/pull/6184) + - Fix platform specific version for libv8-node and other allowlisted gems not being chosen in Truffleruby [#6169](https://github.com/rubygems/rubygems/pull/6169) + - Fix `bundle outdated` with both `--groups` and `--parseable` flags [#6148](https://github.com/rubygems/rubygems/pull/6148) + - Auto-heal lockfile when it's missing specs [#6132](https://github.com/rubygems/rubygems/pull/6132) + - Fix unintentional downgrades when gemspec DSL is used [#6131](https://github.com/rubygems/rubygems/pull/6131) + - Fix display of previous gem version when previously downloaded already [#6110](https://github.com/rubygems/rubygems/pull/6110) + - Fix hang when a lockfile gem does not resolve on the current platform [#6070](https://github.com/rubygems/rubygems/pull/6070) + +## Documentation: + + - Improve Bundler setup docs for development [#6154](https://github.com/rubygems/rubygems/pull/6154) + - Fx link in bundle-platform man page [#6071](https://github.com/rubygems/rubygems/pull/6071) + +# 2.3.26 (November 16, 2022) + +## Enhancements: + + - Map 'universal' to the real arch in Bundler for prebuilt gem selection [#5978](https://github.com/rubygems/rubygems/pull/5978) + +## Documentation: + + - Fix '--force' option documentation of 'bundle clean' [#6050](https://github.com/rubygems/rubygems/pull/6050) + +# 2.3.25 (November 2, 2022) + +## Bug fixes: + + - Properly sort specs when materializing [#6015](https://github.com/rubygems/rubygems/pull/6015) + - Fix bad unfreeze recommendation [#6013](https://github.com/rubygems/rubygems/pull/6013) + +## Documentation: + + - Bring docs for gemfile(5) manpage up to date [#6007](https://github.com/rubygems/rubygems/pull/6007) + - Fix `github` DSL docs to mention they use https protocol over git under the hood [#5993](https://github.com/rubygems/rubygems/pull/5993) + +# 2.3.24 (October 17, 2022) + +## Enhancements: + + - Only add extra resolver spec group for Ruby platform when needed [#5698](https://github.com/rubygems/rubygems/pull/5698) + - Fix little UI issue when bundler shows duplicated gems in a list [#5965](https://github.com/rubygems/rubygems/pull/5965) + +## Bug fixes: + + - Fix incorrect materialization on Windows [#5975](https://github.com/rubygems/rubygems/pull/5975) + +# 2.3.23 (October 5, 2022) + +## Enhancements: + + - Update GitLab CI template with new one [#5944](https://github.com/rubygems/rubygems/pull/5944) + +## Bug fixes: + + - Fix `bundle init` not respecting umask in generated gem's Gemfile [#5947](https://github.com/rubygems/rubygems/pull/5947) + +## Performance: + + - Further speed up Bundler by not sorting specs unnecessarily [#5868](https://github.com/rubygems/rubygems/pull/5868) + +## Documentation: + + - Update Bundler new feature instructions [#5912](https://github.com/rubygems/rubygems/pull/5912) + +# 2.3.22 (September 7, 2022) + +## Enhancements: + + - Use a more accurate source code uri in gemspec [#5896](https://github.com/rubygems/rubygems/pull/5896) + - Support `--path` option in `bundle add` [#5897](https://github.com/rubygems/rubygems/pull/5897) + - Improve lockfile dependency unlocking [#5881](https://github.com/rubygems/rubygems/pull/5881) + - Add platform alias `:windows` to Gemfile DSL [#5650](https://github.com/rubygems/rubygems/pull/5650) + - Make `#to_lock` consistent between `Gem::Dependency` and `Bundler::Dependency` [#5872](https://github.com/rubygems/rubygems/pull/5872) + - Support marshaled index specifications with `nil` required ruby version [#5824](https://github.com/rubygems/rubygems/pull/5824) + +## Bug fixes: + + - Fix resolution hanging on musl platforms [#5875](https://github.com/rubygems/rubygems/pull/5875) + - Fix another regression affecting the sorbet family of gems [#5874](https://github.com/rubygems/rubygems/pull/5874) + +## Documentation: + + - Introduce bundle-console(1) man [#5901](https://github.com/rubygems/rubygems/pull/5901) + - Introduce bundle-version(1) man [#5895](https://github.com/rubygems/rubygems/pull/5895) + - Introduce bundle-help(1) man [#5886](https://github.com/rubygems/rubygems/pull/5886) + +# 2.3.21 (August 24, 2022) + +## Enhancements: + + - Backport non gnu libc linux support from RubyGems [#4488](https://github.com/rubygems/rubygems/pull/4488) + - Improve `Bundler.rm_rf` error message [#5861](https://github.com/rubygems/rubygems/pull/5861) + - Disallow both `--branch` and `--ref` at the same time in bundle-plugin [#5855](https://github.com/rubygems/rubygems/pull/5855) + - Restore previous performance of private RubyGems servers [#5826](https://github.com/rubygems/rubygems/pull/5826) + +## Bug fixes: + + - Fix conservative update downgrading top level gems [#5847](https://github.com/rubygems/rubygems/pull/5847) + - Fix edge case where `bundler/inline` unintentionally skips install [#5848](https://github.com/rubygems/rubygems/pull/5848) + - Fix `bundle platform` crash when there's a lockfile with no Ruby locked [#5850](https://github.com/rubygems/rubygems/pull/5850) + - Fix crash when incomplete locked specifications are found in transitive dependencies [#5840](https://github.com/rubygems/rubygems/pull/5840) + - Fix Ruby platform incorrectly removed on `bundle update` [#5832](https://github.com/rubygems/rubygems/pull/5832) + +## Documentation: + + - Explain cancelled CLI deprecations clearly [#5864](https://github.com/rubygems/rubygems/pull/5864) + - Improve `bundle config` command synopsis [#5854](https://github.com/rubygems/rubygems/pull/5854) + - Introduce bundle-plugin(1) man [#5853](https://github.com/rubygems/rubygems/pull/5853) + +# 2.3.20 (August 10, 2022) + +## Enhancements: + + - Consistently ignore patchlevel when reporting `bundle platform --ruby` [#5793](https://github.com/rubygems/rubygems/pull/5793) + - Make `--standalone` play nice with `--local` [#5762](https://github.com/rubygems/rubygems/pull/5762) + - Implement `bundle install --prefer-local` [#5761](https://github.com/rubygems/rubygems/pull/5761) + +## Bug fixes: + + - Fix regression where yanked gems are now unintentionally updated when other gems are unlocked [#5812](https://github.com/rubygems/rubygems/pull/5812) + - Automatically remove "ruby" from lockfile if incomplete [#5807](https://github.com/rubygems/rubygems/pull/5807) + - Fix `bundle outdated --strict` showing too many outdated gems [#5798](https://github.com/rubygems/rubygems/pull/5798) + - Don't discard candidates matching Ruby metadata [#5784](https://github.com/rubygems/rubygems/pull/5784) + - Fix `bundle outdated` crash in debug mode [#5796](https://github.com/rubygems/rubygems/pull/5796) + - Fix `ruby` DSL requirement matching for head and prerelease rubies [#5766](https://github.com/rubygems/rubygems/pull/5766) + +## Documentation: + + - Update Bundler support policies to match what we do these days [#5813](https://github.com/rubygems/rubygems/pull/5813) + - Fix arguments for bundle-config(1) docs [#5804](https://github.com/rubygems/rubygems/pull/5804) + - Improve `bundle platform` man page [#5788](https://github.com/rubygems/rubygems/pull/5788) + - Remove `bundle cache` from deprecated commands list, and consistently link to `bundle cache` in man pages [#5783](https://github.com/rubygems/rubygems/pull/5783) + - Add package/pack aliases to man pages for cache [#5785](https://github.com/rubygems/rubygems/pull/5785) + - Add deprecation notice of bundle console [#5775](https://github.com/rubygems/rubygems/pull/5775) + +# 2.3.19 (July 27, 2022) + +## Enhancements: + + - Add `Bundler.settings[:only]` to install gems of the specified groups [#5759](https://github.com/rubygems/rubygems/pull/5759) + - Add `ignore_funding_requests` config flag [#5767](https://github.com/rubygems/rubygems/pull/5767) + - Prevent random crash when autoloading `Pathname` [#5769](https://github.com/rubygems/rubygems/pull/5769) + - Don't corrupt lockfile when user moves a gem that's already in the lockfile to an incorrect source by mistake [#5070](https://github.com/rubygems/rubygems/pull/5070) + - Reconcile error/warning message for multiple global sources with documentation [#5741](https://github.com/rubygems/rubygems/pull/5741) + - Improve error message when gems cannot be found to include the source for each gem [#5729](https://github.com/rubygems/rubygems/pull/5729) + +## Bug fixes: + + - Fix yet another TruffleRuby platform selection regression [#5746](https://github.com/rubygems/rubygems/pull/5746) + - Show a proper error if extension dir is not writable [#5726](https://github.com/rubygems/rubygems/pull/5726) + +## Performance: + + - Lazily check incomplete lockfile to improve performance [#5546](https://github.com/rubygems/rubygems/pull/5546) + +## Documentation: + + - Add deprecation notice of bundle inject [#5776](https://github.com/rubygems/rubygems/pull/5776) + - Add deprecation notice of `bundle viz` to man pages [#5765](https://github.com/rubygems/rubygems/pull/5765) + - Update command example in `bundle exec` man page [#5754](https://github.com/rubygems/rubygems/pull/5754) + - Remove bundle show from obsolete commands [#5753](https://github.com/rubygems/rubygems/pull/5753) + - Improve global source(s) documentation [#5732](https://github.com/rubygems/rubygems/pull/5732) + - Use https protocol for URLs for config mirror in bundler man [#5722](https://github.com/rubygems/rubygems/pull/5722) + +# 2.3.18 (July 14, 2022) + +## Enhancements: + + - Extend `gem` DSL with a `force_ruby_platform` option [#4049](https://github.com/rubygems/rubygems/pull/4049) + +## Bug fixes: + + - Fix misleading error if compact index cannot be copied [#5709](https://github.com/rubygems/rubygems/pull/5709) + - Fix TruffleRuby no longer able to install lockfiles generated with other implementations [#5711](https://github.com/rubygems/rubygems/pull/5711) + - Fix TruffleRuby no longer installing lockfiles using "ruby" platform correctly [#5694](https://github.com/rubygems/rubygems/pull/5694) + - Fix crash when updating vendor cache of default gems [#5679](https://github.com/rubygems/rubygems/pull/5679) + +## Performance: + + - Speed up `bundler/setup` by using the raw `Gemfile.lock` information without extra processing whenever possible [#5695](https://github.com/rubygems/rubygems/pull/5695) + +## Documentation: + + - Use modern style hashes in Gemfile DSL docs [#5674](https://github.com/rubygems/rubygems/pull/5674) + +# 2.3.17 (June 29, 2022) + +## Enhancements: + + - Add support for platform `:x64_mingw` to correctly lookup "x64-mingw-ucrt" [#5649](https://github.com/rubygems/rubygems/pull/5649) + - Fix some errors being printed twice in `--verbose` mode [#5654](https://github.com/rubygems/rubygems/pull/5654) + - Fix extension paths in generated standalone script [#5632](https://github.com/rubygems/rubygems/pull/5632) + +## Bug fixes: + + - Raise if ruby platform is forced and there are no ruby variants [#5495](https://github.com/rubygems/rubygems/pull/5495) + - Fix `bundle package --no-install` no longer skipping install [#5639](https://github.com/rubygems/rubygems/pull/5639) + +## Performance: + + - Improve performance of `Bundler::SpecSet#for` by using hash lookup of handled deps [#5537](https://github.com/rubygems/rubygems/pull/5537) + +## Documentation: + + - Fix formatting issue in `bundle add` man page [#5642](https://github.com/rubygems/rubygems/pull/5642) + +# 2.3.16 (June 15, 2022) + +## Performance: + + - Improve performance of installing gems from gem server sources [#5614](https://github.com/rubygems/rubygems/pull/5614) + +# 2.3.15 (June 1, 2022) + +## Enhancements: + + - Show better error when previous installation fails to be removed [#5564](https://github.com/rubygems/rubygems/pull/5564) + - Show exception cause in bug report template [#5563](https://github.com/rubygems/rubygems/pull/5563) + +## Bug fixes: + + - Fix `bundle remove` by invalidating cached `Bundle.definition` [#5443](https://github.com/rubygems/rubygems/pull/5443) + - Fix generated standalone script when it includes default gems [#5586](https://github.com/rubygems/rubygems/pull/5586) + - Skip duplicated dependency warning for gemspec dev deps [#5587](https://github.com/rubygems/rubygems/pull/5587) + - Give better conflict resolution advice [#5581](https://github.com/rubygems/rubygems/pull/5581) + - Fix crash when commenting out a mirror in configuration [#5576](https://github.com/rubygems/rubygems/pull/5576) + - Fix crash when installing gems with symlinks [#5570](https://github.com/rubygems/rubygems/pull/5570) + - Ignore `Errno::EROFS` errors when creating `bundler.lock` [#5580](https://github.com/rubygems/rubygems/pull/5580) + - Ignore `Errno::EPERM` errors when creating `bundler.lock` [#5579](https://github.com/rubygems/rubygems/pull/5579) + - Fix crash when printing resolution conflicts on metadata requirements [#5562](https://github.com/rubygems/rubygems/pull/5562) + +# 2.3.14 (May 18, 2022) + +## Bug fixes: + + - Fix confusing inline mode install output [#5530](https://github.com/rubygems/rubygems/pull/5530) + - Fix error message when locked version of a gem does not support running Ruby [#5525](https://github.com/rubygems/rubygems/pull/5525) + +## Performance: + + - Improve `bundler/setup` performance again by not deduplicating intermediate results [#5533](https://github.com/rubygems/rubygems/pull/5533) + +## Documentation: + + - Fix typo in documentation [#5514](https://github.com/rubygems/rubygems/pull/5514) + - Update man page for `require` option in `bundle add` command [#5513](https://github.com/rubygems/rubygems/pull/5513) + +# 2.3.13 (May 4, 2022) + +## Bug fixes: + + - Fix missing required rubygems version when using old APIs [#5496](https://github.com/rubygems/rubygems/pull/5496) + - Fix crash when gem used twice in Gemfile under different platforms [#5187](https://github.com/rubygems/rubygems/pull/5187) + +## Performance: + + - Speed up `bundler/setup` time [#5503](https://github.com/rubygems/rubygems/pull/5503) + +# 2.3.12 (April 20, 2022) + +## Enhancements: + + - Improve Ruby version resolution conflicts [#5474](https://github.com/rubygems/rubygems/pull/5474) + - Stop considering `RUBY_PATCHLEVEL` for resolution [#5472](https://github.com/rubygems/rubygems/pull/5472) + - Add modern rubies as valid platform values in Gemfile DSL [#5469](https://github.com/rubygems/rubygems/pull/5469) + +# 2.3.11 (April 7, 2022) + +## Enhancements: + + - Bump actions/checkout to 3 in bundler gem template [#5445](https://github.com/rubygems/rubygems/pull/5445) + - Prefer `__dir__` to `__FILE__` [#5444](https://github.com/rubygems/rubygems/pull/5444) + +## Documentation: + + - Update bundler documentation to reflect bundle config scope changes [#5441](https://github.com/rubygems/rubygems/pull/5441) + +# 2.3.10 (March 23, 2022) + +## Enhancements: + + - More helpful reporting of marshal loading issues [#5416](https://github.com/rubygems/rubygems/pull/5416) + - Report Github Actions CI provider within user agent string [#5400](https://github.com/rubygems/rubygems/pull/5400) + - Remove extra closing bracket in version warning [#5397](https://github.com/rubygems/rubygems/pull/5397) + +# 2.3.9 (March 9, 2022) + +## Enhancements: + + - Add newline to validate_platforms! message when platform is missing [#5353](https://github.com/rubygems/rubygems/pull/5353) + - Suggest quicker `bundle add` for installation in `README.md` generated by `bundle gem` [#5337](https://github.com/rubygems/rubygems/pull/5337) + - Make `--strict` flag of `update` and `outdated` commands consistent [#5379](https://github.com/rubygems/rubygems/pull/5379) + +## Bug fixes: + + - Fix regression when activating gem executables caused by Bundler monkey patches to RubyGems [#5386](https://github.com/rubygems/rubygems/pull/5386) + +# 2.3.8 (February 23, 2022) + +## Bug fixes: + + - Fix corrupted lockfile when running `bundle check` and having to re-resolve locally [#5344](https://github.com/rubygems/rubygems/pull/5344) + - Fix typo in multiple gemfiles warning [#5342](https://github.com/rubygems/rubygems/pull/5342) + +## Documentation: + + - Add clarification for bundle-config "with" option [#5346](https://github.com/rubygems/rubygems/pull/5346) + +# 2.3.7 (February 9, 2022) + +## Enhancements: + + - Don't activate `yaml` gem from Bundler [#5277](https://github.com/rubygems/rubygems/pull/5277) + - Add Reverse Dependencies section to info command [#3966](https://github.com/rubygems/rubygems/pull/3966) + +## Bug fixes: + + - Don't silently persist `BUNDLE_WITH` and `BUNDLE_WITHOUT` envs locally [#5335](https://github.com/rubygems/rubygems/pull/5335) + - Fix `bundle config` inside an application saving configuration globally [#4152](https://github.com/rubygems/rubygems/pull/4152) + +# 2.3.6 (January 26, 2022) + +## Enhancements: + + - Use `Gem::Platform.local` instead of `RUBY_PLATFORM` when displaying local platform [#5306](https://github.com/rubygems/rubygems/pull/5306) + - Lock standard.yml to the required ruby version [#5284](https://github.com/rubygems/rubygems/pull/5284) + - Use `Fiddle` in `bundle doctor` to check for dynamic library presence [#5173](https://github.com/rubygems/rubygems/pull/5173) + +## Bug fixes: + + - Fix edge case where gems were incorrectly removed from the lockfile [#5302](https://github.com/rubygems/rubygems/pull/5302) + - Fix `force_ruby_platform` ignored when lockfile includes current specific platform [#5304](https://github.com/rubygems/rubygems/pull/5304) + - Create minitest file to underscored path in "bundle gem" command with dashed gem name [#5273](https://github.com/rubygems/rubygems/pull/5273) + - Fix regression with old marshaled specs having null `required_rubygems_version` [#5291](https://github.com/rubygems/rubygems/pull/5291) + +# 2.3.5 (January 12, 2022) + +## Enhancements: + + - Make `bundle update --bundler` actually lock to the latest bundler version (even if not yet installed) [#5182](https://github.com/rubygems/rubygems/pull/5182) + - Use thor-1.2.1 [#5260](https://github.com/rubygems/rubygems/pull/5260) + - Exclude bin directory for newgem template [#5259](https://github.com/rubygems/rubygems/pull/5259) + +## Bug fixes: + + - Fix metadata requirements being bypassed when custom gem servers are used [#5256](https://github.com/rubygems/rubygems/pull/5256) + - Fix `rake build:checksum` writing checksum of package path, not package contents [#5250](https://github.com/rubygems/rubygems/pull/5250) + +# 2.3.4 (December 29, 2021) + +## Enhancements: + + - Improve error message when `BUNDLED WITH` version does not exist [#5205](https://github.com/rubygems/rubygems/pull/5205) + +## Bug fixes: + + - Fix `bundle update --bundler` no longer updating lockfile [#5224](https://github.com/rubygems/rubygems/pull/5224) + +# 2.3.3 (December 24, 2021) + +## Bug fixes: + + - Fix locked bundler not installed to the right path when `deployment` is set [#5217](https://github.com/rubygems/rubygems/pull/5217) + +# 2.3.2 (December 23, 2021) + +## Enhancements: + + - Remove unnecessary lockfile upgrade warning [#5209](https://github.com/rubygems/rubygems/pull/5209) + +# 2.3.1 (December 22, 2021) + +## Enhancements: + + - Vendor latest `thor` with fixes for latest `did_you_mean` deprecations [#5202](https://github.com/rubygems/rubygems/pull/5202) + - Avoid unnecessary `shellwords` require on newer rubygems [#5195](https://github.com/rubygems/rubygems/pull/5195) + - Re-exec prepending command with `Gem.ruby` if `$PROGRAM_NAME` is not executable [#5193](https://github.com/rubygems/rubygems/pull/5193) + +# 2.3.0 (December 21, 2021) + +## Features: + + - Change `bundle install` with a lockfile to respect the `BUNDLED WITH` bundler version [#4076](https://github.com/rubygems/rubygems/pull/4076) + +## Enhancements: + + - Cancel deprecation of custom git sources [#5147](https://github.com/rubygems/rubygems/pull/5147) + - Print warning when running Bundler on potentially problematic RubyGems & Ruby combinations [#5177](https://github.com/rubygems/rubygems/pull/5177) + - Error tracing should be printed to stderr [#5179](https://github.com/rubygems/rubygems/pull/5179) + - Add `github` and `ref` options to `bundle add` [#5159](https://github.com/rubygems/rubygems/pull/5159) + - Add require parameter to `bundle add` [#5021](https://github.com/rubygems/rubygems/pull/5021) + - Enable parallel installation on Windows by default [#4822](https://github.com/rubygems/rubygems/pull/4822) + - More logging when compact index is not used and we fallback to other APIs [#4546](https://github.com/rubygems/rubygems/pull/4546) + - `bundle gem` generated MiniTest file and class now start with 'test' [#3893](https://github.com/rubygems/rubygems/pull/3893) + - Add `Bundler::Definition.no_lock` accessor for skipping lock file creation/update [#3401](https://github.com/rubygems/rubygems/pull/3401) + +## Bug fixes: + + - Fix crash when when no platform specific matches exist and show a proper error [#5168](https://github.com/rubygems/rubygems/pull/5168) + - Ignore dependencies not actually locked from frozen check [#5152](https://github.com/rubygems/rubygems/pull/5152) + - Fix `bundle cache --all-platforms` on Windows [#4552](https://github.com/rubygems/rubygems/pull/4552) + +## Documentation: + + - Fix gemspec template typo [#4545](https://github.com/rubygems/rubygems/pull/4545) + +# 2.2.33 (December 7, 2021) + +## Security fixes: + + - Pass "--" to git commands to separate positional and optional args [#5142](https://github.com/rubygems/rubygems/pull/5142) + +## Enhancements: + + - Accept pull request URLs as github source [#5126](https://github.com/rubygems/rubygems/pull/5126) + - Add `--version` parameter to `bundle info` command [#5137](https://github.com/rubygems/rubygems/pull/5137) + - Let original `Errno::EACCES` error be raised in compact index updater [#5110](https://github.com/rubygems/rubygems/pull/5110) + - Improve gemfile-lockfile source equivalence errors [#5120](https://github.com/rubygems/rubygems/pull/5120) + - Avoid float-to-string loss of characters in GitHub Actions configuration labels in new gem template [#5089](https://github.com/rubygems/rubygems/pull/5089) + - Add an initial rbs template to `bundle gem` skeleton [#5041](https://github.com/rubygems/rubygems/pull/5041) + - Avoid shared libraries not getting environment passed right after argv in memory when `bundle exec` is used [#4815](https://github.com/rubygems/rubygems/pull/4815) + +## Bug fixes: + + - Don't cleanup paths from gems already activated from `$LOAD_PATH` [#5111](https://github.com/rubygems/rubygems/pull/5111) + - Fix handling prereleases of 0 versions, like 0.0.0.dev or 0.0.0.SNAPSHOT [#5116](https://github.com/rubygems/rubygems/pull/5116) + - Fix escape of filenames in `bundle doctor` [#5102](https://github.com/rubygems/rubygems/pull/5102) + - Don't unlock dependencies when running `bundle install` after changing global source [#5090](https://github.com/rubygems/rubygems/pull/5090) + - Fix missing locked specs when depended on another platform [#5092](https://github.com/rubygems/rubygems/pull/5092) + - Fix `bundle info` sometimes claiming that bundler has been deleted [#5097](https://github.com/rubygems/rubygems/pull/5097) + +## Documentation: + + - Ignore to generate the documentation from vendored libraries [#5118](https://github.com/rubygems/rubygems/pull/5118) + +# 2.2.32 (November 23, 2021) + +## Enhancements: + + - Clarify `bundle viz` deprecation [#5083](https://github.com/rubygems/rubygems/pull/5083) + - Unlock dependencies that no longer match lockfile [#5068](https://github.com/rubygems/rubygems/pull/5068) + - Use `shellsplit` instead of array of strings for git push [#5062](https://github.com/rubygems/rubygems/pull/5062) + - Re-enable `default_ignores` option for standard [#5003](https://github.com/rubygems/rubygems/pull/5003) + +## Bug fixes: + + - Fix downgrading dependencies by changing the `Gemfile` and running `bundle update` [#5078](https://github.com/rubygems/rubygems/pull/5078) + +# 2.2.31 (November 8, 2021) + +## Enhancements: + + - Link to working `bundler-graph` plugin in `bundle viz` deprecation message [#5061](https://github.com/rubygems/rubygems/pull/5061) + - Memoize materialized specs when requiring `bundler/setup` [#5033](https://github.com/rubygems/rubygems/pull/5033) + - Allow custom LicenseRef [#5013](https://github.com/rubygems/rubygems/pull/5013) + - Better error when installing a lockfile with git sources and git is not installed [#5036](https://github.com/rubygems/rubygems/pull/5036) + - Only delete cached gem when it's corrupted [#5031](https://github.com/rubygems/rubygems/pull/5031) + - Support gemified `tsort` [#5032](https://github.com/rubygems/rubygems/pull/5032) + - Add standard option alongside rubocop to `bundle gem` [#4411](https://github.com/rubygems/rubygems/pull/4411) + +## Bug fixes: + + - Fix system man pages no longer working after bundler overrides `MANPATH` [#5039](https://github.com/rubygems/rubygems/pull/5039) + - Don't warn when a lockfile is locked to a dev version [#5018](https://github.com/rubygems/rubygems/pull/5018) + +# 2.2.30 (October 26, 2021) + +## Enhancements: + + - Add a custom SHA1 digest implementation to no longer depend on the digest gem before we know which version to activate [#4989](https://github.com/rubygems/rubygems/pull/4989) + - Ensure vendored gems have licenses [#4998](https://github.com/rubygems/rubygems/pull/4998) + - Update broken link in Bundler::Fetcher::CertificateFailureError [#4987](https://github.com/rubygems/rubygems/pull/4987) + - Give better errors for some permission issues [#4965](https://github.com/rubygems/rubygems/pull/4965) + - Print better errors when `bundler/gem_tasks` fail [#4872](https://github.com/rubygems/rubygems/pull/4872) + - Fix `bundle install` to reinstall deleted gems [#4974](https://github.com/rubygems/rubygems/pull/4974) + - Unify issue template and ISSUES.md document [#4980](https://github.com/rubygems/rubygems/pull/4980) + - Bump vendored connection_pool to 2.2.5 [#4738](https://github.com/rubygems/rubygems/pull/4738) + +## Bug fixes: + + - Fix error message pointing to non existing file when using a global gem cache [#4999](https://github.com/rubygems/rubygems/pull/4999) + - Fix install crash when lockfile has missing dependencies for the current platform [#4941](https://github.com/rubygems/rubygems/pull/4941) + - Make `bundle info` show a proper warning every time it finds a deleted gem [#4971](https://github.com/rubygems/rubygems/pull/4971) + +# 2.2.29 (October 8, 2021) + +## Enhancements: + + - Require at least Ruby 2.6.0 for gems created with recent rubies [#4920](https://github.com/rubygems/rubygems/pull/4920) + - Include glob information in string representation of git sources to make generated lockfiles deterministic [#4947](https://github.com/rubygems/rubygems/pull/4947) + - Add missing `rubygem_push` prerequisite [#4930](https://github.com/rubygems/rubygems/pull/4930) + +# 2.2.28 (September 23, 2021) + +## Enhancements: + + - Use example.com in new gem template, since it will never have a potentially dangerous backing website [#4918](https://github.com/rubygems/rubygems/pull/4918) + - Deprecate `--install` flag to `bundle remove` and trigger install by default [#4891](https://github.com/rubygems/rubygems/pull/4891) + +# 2.2.27 (September 3, 2021) + +## Enhancements: + + - Optimize some requires [#4887](https://github.com/rubygems/rubygems/pull/4887) + - Correctly redact credentials when using x-oauth-basic [#4866](https://github.com/rubygems/rubygems/pull/4866) + +## Bug fixes: + + - Add missing key `branches:` to template for GitHub Actions [#4883](https://github.com/rubygems/rubygems/pull/4883) + - Fix `bundle plugin install` detection of already installed plugins [#4869](https://github.com/rubygems/rubygems/pull/4869) + - Make plugin installation idempotent [#4864](https://github.com/rubygems/rubygems/pull/4864) + - Fix `bundle check` showing duplicated gems when multiple platforms are locked [#4854](https://github.com/rubygems/rubygems/pull/4854) + - Fix `bundle check` incorrectly considering cached gems [#4853](https://github.com/rubygems/rubygems/pull/4853) + +# 2.2.26 (August 17, 2021) + +## Enhancements: + + - Remove `RUBYGEMS_GEMDEPS` warning [#4827](https://github.com/rubygems/rubygems/pull/4827) + - Better defaults for GitHub Actions template generated by `bundle gem` [#4619](https://github.com/rubygems/rubygems/pull/4619) + - Make `bundle exec` keep file descriptors by default [#4812](https://github.com/rubygems/rubygems/pull/4812) + - Exclude gemspec file itself from file list of gems generated by `bundle gem` [#4650](https://github.com/rubygems/rubygems/pull/4650) + - Fix a couple small typos in deprecation / error messages [#4806](https://github.com/rubygems/rubygems/pull/4806) + - Make script generated by `bundle install --standalone` resilient to moving the application to a differently nested folder when `path` sources are used [#4792](https://github.com/rubygems/rubygems/pull/4792) + - Exclude CI files and issue templates from file list of gems generated by `bundle gem` [#4033](https://github.com/rubygems/rubygems/pull/4033) + +## Bug fixes: + + - Respect `BUNDLE_USER_HOME` env when choosing config location [#4828](https://github.com/rubygems/rubygems/pull/4828) + - Fix `bundle gem` on path with spaces [#4816](https://github.com/rubygems/rubygems/pull/4816) + - Fix bundler hitting the network in some cases where not allowed [#4805](https://github.com/rubygems/rubygems/pull/4805) + +# 2.2.25 (July 30, 2021) + +## Deprecations: + + - Deprecate Gemfile without an explicit global source [#4779](https://github.com/rubygems/rubygems/pull/4779) + - Deprecate `bundle cache --path` [#4496](https://github.com/rubygems/rubygems/pull/4496) + +## Enhancements: + + - Give better errors when materialization fails [#4788](https://github.com/rubygems/rubygems/pull/4788) + - Lazily load `shellwords` library [#4786](https://github.com/rubygems/rubygems/pull/4786) + - Show original error and backtrace directly on `bundle install` errors instead of a more brittle `gem install` hint [#4778](https://github.com/rubygems/rubygems/pull/4778) + - Remove LoadError message in regards to requiring a relative file [#4772](https://github.com/rubygems/rubygems/pull/4772) + +## Bug fixes: + + - Fix `BUNDLE_USER_CONFIG` no longer respected as config location [#4797](https://github.com/rubygems/rubygems/pull/4797) + - Fix `--standalone` installation of default gems [#4782](https://github.com/rubygems/rubygems/pull/4782) + - Fix `--quiet` flag not printing warnings [#4781](https://github.com/rubygems/rubygems/pull/4781) + - Fix bundler binstub version selection [#4775](https://github.com/rubygems/rubygems/pull/4775) + - Fix interrupt handling in Bundler workers [#4767](https://github.com/rubygems/rubygems/pull/4767) + +# 2.2.24 (July 15, 2021) + +## Bug fixes: + + - Fix development gem unintentionally removed on an edge case [#4751](https://github.com/rubygems/rubygems/pull/4751) + - Fix dangling empty plugin hooks [#4755](https://github.com/rubygems/rubygems/pull/4755) + - Fix `bundle plugin install --help` showing `bundle install`'s help [#4756](https://github.com/rubygems/rubygems/pull/4756) + - Make sure `bundle check` shows uniq missing gems [#4749](https://github.com/rubygems/rubygems/pull/4749) + +## Performance: + + - Slightly speed up `bundler/setup` [#4750](https://github.com/rubygems/rubygems/pull/4750) + +# 2.2.23 (July 9, 2021) + +## Enhancements: + + - Fix `bundle install` on truffleruby selecting incorrect variant for `sorbet-static` gem [#4625](https://github.com/rubygems/rubygems/pull/4625) + - Spare meaningless warning on read-only bundle invocations [#4724](https://github.com/rubygems/rubygems/pull/4724) + +## Bug fixes: + + - Fix incorrect warning about duplicated gems in the Gemfile [#4732](https://github.com/rubygems/rubygems/pull/4732) + - Fix `bundle plugin install foo` crashing [#4734](https://github.com/rubygems/rubygems/pull/4734) + +# 2.2.22 (July 6, 2021) + +## Enhancements: + + - Never downgrade indirect dependencies when running `bundle update` [#4713](https://github.com/rubygems/rubygems/pull/4713) + - Fix `getaddrinfo` errors not treated as fatal on non darwin platforms [#4703](https://github.com/rubygems/rubygems/pull/4703) + +## Bug fixes: + + - Fix `bundle update ` sometimes hanging and `bundle lock --update` not being able to update an insecure lockfile to the new format if it requires downgrades [#4652](https://github.com/rubygems/rubygems/pull/4652) + - Fix edge case combination of DSL methods and duplicated sources causing gems to not be found [#4711](https://github.com/rubygems/rubygems/pull/4711) + - Fix `bundle doctor` crashing when finding a broken symlink [#4707](https://github.com/rubygems/rubygems/pull/4707) + - Fix incorrect re-resolve edge case [#4700](https://github.com/rubygems/rubygems/pull/4700) + - Fix some gems being unintentionally locked under multiple lockfile sections [#4701](https://github.com/rubygems/rubygems/pull/4701) + - Fix `--conservative` flag unexpectedly updating indirect dependencies. NOTE: As part of this bug fix, some undocumented, unintentional code causing `bundle update --source ` to update conservatively was fixed. Use the documented `bundle update --conservative ` instead [#4692](https://github.com/rubygems/rubygems/pull/4692) + +# 2.2.21 (June 23, 2021) + +## Security fixes: + + - Auto-update insecure lockfile to split GEM source sections whenever possible [#4647](https://github.com/rubygems/rubygems/pull/4647) + +## Enhancements: + + - Use a more limited number of threads when fetching in parallel from the Compact Index API [#4670](https://github.com/rubygems/rubygems/pull/4670) + - Update TODO link in bundle gem template to https [#4671](https://github.com/rubygems/rubygems/pull/4671) + +## Bug fixes: + + - Fix `bundle install --local` hitting the network when `cache_all_platforms` configured [#4677](https://github.com/rubygems/rubygems/pull/4677) + +# 2.2.20 (June 11, 2021) + +## Enhancements: + + - Don't print bug report template on server side errors [#4663](https://github.com/rubygems/rubygems/pull/4663) + - Don't load `resolv` unnecessarily [#4640](https://github.com/rubygems/rubygems/pull/4640) + +## Bug fixes: + + - Fix `bundle outdated` edge case [#4648](https://github.com/rubygems/rubygems/pull/4648) + - Fix `bundle check` with scoped rubygems sources [#4639](https://github.com/rubygems/rubygems/pull/4639) + +## Performance: + + - Don't use `extra_rdoc_files` with md files in gemspec to make installing bundler with docs faster [#4628](https://github.com/rubygems/rubygems/pull/4628) + +# 2.2.19 (May 31, 2021) + +## Bug fixes: + + - Restore support for configuration keys with dashes [#4582](https://github.com/rubygems/rubygems/pull/4582) + - Fix some cached gems being unintentionally ignored when using rubygems 3.2.18 [#4623](https://github.com/rubygems/rubygems/pull/4623) + +# 2.2.18 (May 25, 2021) + +## Security fixes: + + - Fix dependency confusion issues with implicit dependencies [#4609](https://github.com/rubygems/rubygems/pull/4609) + +## Enhancements: + + - Use simpler notation for generated `required_ruby_version` [#4598](https://github.com/rubygems/rubygems/pull/4598) + - Undeprecate bundle show [#4586](https://github.com/rubygems/rubygems/pull/4586) + - Make sure link to new issue uses the proper template [#4592](https://github.com/rubygems/rubygems/pull/4592) + +## Bug fixes: + + - Fix platform specific gems being removed from the lockfile [#4580](https://github.com/rubygems/rubygems/pull/4580) + +# 2.2.17 (May 5, 2021) + +## Enhancements: + + - Improve authentication required error message to include an alternative using `ENV` [#4565](https://github.com/rubygems/rubygems/pull/4565) + - Discard partial range responses without etag [#4563](https://github.com/rubygems/rubygems/pull/4563) + - Fix configuring ENV for a gem server with a name including dashes [#4571](https://github.com/rubygems/rubygems/pull/4571) + - Redact credentials from `bundle env` and `bundle config` [#4566](https://github.com/rubygems/rubygems/pull/4566) + - Redact all sources in verbose mode [#4564](https://github.com/rubygems/rubygems/pull/4564) + - Improve `bundle pristine` error if `BUNDLE_GEMFILE` does not exist [#4536](https://github.com/rubygems/rubygems/pull/4536) + - [CurrentRuby] Add 3.0 as a known minor [#4535](https://github.com/rubygems/rubygems/pull/4535) + - Prefer File.read instead of IO.read [#4530](https://github.com/rubygems/rubygems/pull/4530) + - Add space after open curly bracket in Gemfile and gems.rb template [#4518](https://github.com/rubygems/rubygems/pull/4518) + +## Bug fixes: + + - Make sure specs are fetched from the right source when materializing [#4562](https://github.com/rubygems/rubygems/pull/4562) + - Fix `bundle cache` with an up-to-date lockfile and specs not already installed [#4554](https://github.com/rubygems/rubygems/pull/4554) + - Ignore `deployment` setting in inline mode [#4523](https://github.com/rubygems/rubygems/pull/4523) + +## Performance: + + - Don't materialize resolutions when not necessary [#4556](https://github.com/rubygems/rubygems/pull/4556) + +# 2.2.16 (April 8, 2021) + +## Enhancements: + + - Add `--github-username` option and config to `bundle gem` [#3687](https://github.com/rubygems/rubygems/pull/3687) + - Bump vendored `tmpdir` library copy [#4506](https://github.com/rubygems/rubygems/pull/4506) + - Add `rake build:checksum` task to build checksums for a gem package [#4156](https://github.com/rubygems/rubygems/pull/4156) + - Enable bundler-cache for GitHub Actions template [#4498](https://github.com/rubygems/rubygems/pull/4498) + - Improve `bundle info` error when gem is on a "disabled" group [#4492](https://github.com/rubygems/rubygems/pull/4492) + - Small tweak to yank message [#4494](https://github.com/rubygems/rubygems/pull/4494) + - Don't show duplicate entries in `bundle outdated` output [#4474](https://github.com/rubygems/rubygems/pull/4474) + - Never downgrade top level gems when running `bundle update` [#4473](https://github.com/rubygems/rubygems/pull/4473) + +## Bug fixes: + + - Fix incorrect logic for filtering metadata matching candidates [#4497](https://github.com/rubygems/rubygems/pull/4497) + +# 2.2.15 (March 19, 2021) + +## Enhancements: + + - Add a hint about bundler installing executables for path gems [#4461](https://github.com/rubygems/rubygems/pull/4461) + - Warn lockfiles with incorrect resolutions [#4459](https://github.com/rubygems/rubygems/pull/4459) + - Don't generate duplicate redundant sources in the lockfile [#4456](https://github.com/rubygems/rubygems/pull/4456) + +## Bug fixes: + + - Respect running ruby when resolving platforms [#4449](https://github.com/rubygems/rubygems/pull/4449) + +# 2.2.14 (March 8, 2021) + +## Security fixes: + + - Lock GEM sources separately and fix locally installed specs confusing bundler [#4381](https://github.com/rubygems/rubygems/pull/4381) + +## Bug fixes: + + - Make `rake` available to other gems' installers right after it's installed [#4428](https://github.com/rubygems/rubygems/pull/4428) + - Fix encoding issue on compact index updater [#4362](https://github.com/rubygems/rubygems/pull/4362) + +# 2.2.13 (March 3, 2021) + +## Enhancements: + + - Respect user configured default branch in README links in new generated gems [#4303](https://github.com/rubygems/rubygems/pull/4303) + +## Bug fixes: + + - Fix gems sometimes being pulled from irrelevant sources [#4418](https://github.com/rubygems/rubygems/pull/4418) + +# 2.2.12 (March 1, 2021) + +## Bug fixes: + + - Fix sporadic warnings about `nil` gemspec on install/update and make those faster [#4409](https://github.com/rubygems/rubygems/pull/4409) + - Fix deployment install with duplicate path gems added to Gemfile [#4410](https://github.com/rubygems/rubygems/pull/4410) + +# 2.2.11 (February 17, 2021) + +## Bug fixes: + + - Revert disable_multisource changes [#4385](https://github.com/rubygems/rubygems/pull/4385) + +# 2.2.10 (February 15, 2021) + +## Security fixes: + + - Fix source priority for transitive dependencies and split lockfile rubygems source sections [#3655](https://github.com/rubygems/rubygems/pull/3655) + +## Bug fixes: + + - Fix adding platforms to lockfile sometimes conflicting on ruby requirements [#4371](https://github.com/rubygems/rubygems/pull/4371) + - Fix bundler sometimes choosing ruby variants over java ones [#4367](https://github.com/rubygems/rubygems/pull/4367) + +## Documentation: + + - Update man pages to reflect to new default for bundle install jobs [#4188](https://github.com/rubygems/rubygems/pull/4188) + +# 2.2.9 (February 8, 2021) + +## Enhancements: + + - Stop removing existing platforms when force_ruby_platform is true [#4336](https://github.com/rubygems/rubygems/pull/4336) + +## Bug fixes: + + - Don't install platform specific gems on truffleruby [#4333](https://github.com/rubygems/rubygems/pull/4333) + +# 2.2.8 (February 2, 2021) + +## Enhancements: + + - Add a CHANGELOG.md file to gems generated by `bundle gem` [#4093](https://github.com/rubygems/rubygems/pull/4093) + - Support gemified `set` [#4297](https://github.com/rubygems/rubygems/pull/4297) + +## Bug fixes: + + - Fix standalone Kernel.require visibility [#4337](https://github.com/rubygems/rubygems/pull/4337) + +## Performance: + + - Fix resolver edge cases and speed up bundler [#4277](https://github.com/rubygems/rubygems/pull/4277) + +# 2.2.7 (January 26, 2021) + +## Enhancements: + + - Improve error messages when dependency on bundler conflicts with running version [#4308](https://github.com/rubygems/rubygems/pull/4308) + - Avoid showing platforms with requirements in error messages [#4310](https://github.com/rubygems/rubygems/pull/4310) + - Introduce disable_local_revision_check config [#4237](https://github.com/rubygems/rubygems/pull/4237) + - Reverse rubygems require mixin with bundler standalone [#4299](https://github.com/rubygems/rubygems/pull/4299) + +## Bug fixes: + + - Fix releasing from a not yet pushed branch [#4309](https://github.com/rubygems/rubygems/pull/4309) + - Install cache only once if it already exists [#4304](https://github.com/rubygems/rubygems/pull/4304) + - Fix `force_ruby_platform` no longer being respected [#4302](https://github.com/rubygems/rubygems/pull/4302) + +## Performance: + + - Fix resolver dependency comparison [#4289](https://github.com/rubygems/rubygems/pull/4289) + +# 2.2.6 (January 18, 2021) + +## Enhancements: + + - Improve resolver debugging [#4288](https://github.com/rubygems/rubygems/pull/4288) + +## Bug fixes: + + - Fix dependency locking for path source [#4293](https://github.com/rubygems/rubygems/pull/4293) + +## Performance: + + - Speed up complex dependency resolves by creating DepProxy factory and cache [#4216](https://github.com/rubygems/rubygems/pull/4216) + +# 2.2.5 (January 11, 2021) + +## Enhancements: + + - Improve rubocop setup in the new gem template [#4220](https://github.com/rubygems/rubygems/pull/4220) + - Support repositories with default branch not named master [#4224](https://github.com/rubygems/rubygems/pull/4224) + +## Bug fixes: + + - Let Net::HTTP decompress the index instead of doing it manually [#4081](https://github.com/rubygems/rubygems/pull/4081) + - Workaround for another jruby crash when autoloading a constant [#4252](https://github.com/rubygems/rubygems/pull/4252) + - Fix another performance regression in the resolver [#4243](https://github.com/rubygems/rubygems/pull/4243) + - Restore support for old git versions [#4233](https://github.com/rubygems/rubygems/pull/4233) + - Give a proper error if cache path does not have write access [#4215](https://github.com/rubygems/rubygems/pull/4215) + - Fix running `rake release` from an ambiguous ref [#4219](https://github.com/rubygems/rubygems/pull/4219) + +# 2.2.4 (December 31, 2020) + +## Bug fixes: + + - Fix bundle man pages display on truffleruby [#4209](https://github.com/rubygems/rubygems/pull/4209) + - Fix Windows + JRuby no longer being able to install git sources [#4196](https://github.com/rubygems/rubygems/pull/4196) + +# 2.2.3 (December 22, 2020) + +## Bug fixes: + + - Restore full compatibility with previous lockfiles [#4179](https://github.com/rubygems/rubygems/pull/4179) + - Add all matching variants with the same platform specificity to the lockfile [#4180](https://github.com/rubygems/rubygems/pull/4180) + - Fix bundler installing gems for a different platform when running in frozen mode and current platform not in the lockfile [#4172](https://github.com/rubygems/rubygems/pull/4172) + - Fix crash when `bundle exec`'ing to bundler [#4175](https://github.com/rubygems/rubygems/pull/4175) + +# 2.2.2 (December 17, 2020) + +## Bug fixes: + + - Fix resolver crash when a candidate has 0 matching platforms [#4163](https://github.com/rubygems/rubygems/pull/4163) + - Restore change to copy global with/without config locally upon `bundle install` [#4154](https://github.com/rubygems/rubygems/pull/4154) + +# 2.2.1 (December 14, 2020) + +## Bug fixes: + + - Ad-hoc fix for platform regression [#4127](https://github.com/rubygems/rubygems/pull/4127) + - Workaround JRuby + Windows issue with net-http-persistent vendored code [#4138](https://github.com/rubygems/rubygems/pull/4138) + - Reset also root when in a nested invocation [#4140](https://github.com/rubygems/rubygems/pull/4140) + - Restore 2.1.4 resolution times [#4134](https://github.com/rubygems/rubygems/pull/4134) + - Fix `bundle outdated --strict` crash [#4133](https://github.com/rubygems/rubygems/pull/4133) + - Autoload `Bundler::RemoteSpecification` to workaround crash on jruby [#4114](https://github.com/rubygems/rubygems/pull/4114) + +# 2.2.0 (December 7, 2020) + +## Enhancements: + + - New gem template: prefer `require_relative` to `require` [#4066](https://github.com/rubygems/rubygems/pull/4066) + - Always show underlying error when fetching specs fails [#4061](https://github.com/rubygems/rubygems/pull/4061) + - Add `--all-platforms` flag to `bundle binstubs` to generate binstubs for all platforms [#3886](https://github.com/rubygems/rubygems/pull/3886) + - Improve gem not found in source error messages [#4019](https://github.com/rubygems/rubygems/pull/4019) + - Revert resolving all Gemfile platforms automatically [#4052](https://github.com/rubygems/rubygems/pull/4052) + - Remove extra empty line from README template [#4041](https://github.com/rubygems/rubygems/pull/4041) + - Lazily load `erb` [#4011](https://github.com/rubygems/rubygems/pull/4011) + +## Bug fixes: + + - Fix `Bundler::Plugin::API::Source#to_s` having empty source type [#4084](https://github.com/rubygems/rubygems/pull/4084) + - Raise consistent errors with or without `bundle exec` [#4063](https://github.com/rubygems/rubygems/pull/4063) + - Fix edge case resulting in a crash when using `zeitwerk` inside a nested `bundle exec` invocation [#4062](https://github.com/rubygems/rubygems/pull/4062) + - Enable `specific_platform` by default [#4015](https://github.com/rubygems/rubygems/pull/4015) + - Prevent remove command from deleting gemfile lines that are comments [#4045](https://github.com/rubygems/rubygems/pull/4045) + - Fix issue with `cache_all_platforms` and `specific_platform` configured [#4042](https://github.com/rubygems/rubygems/pull/4042) + - Fix incorrect error message on Windows [#4039](https://github.com/rubygems/rubygems/pull/4039) + - Make printed drive letters consistent on Windows [#4038](https://github.com/rubygems/rubygems/pull/4038) + - Load rubygems plugins from RUBYLIB during `bundle install` and `bundle update` [#3534](https://github.com/rubygems/rubygems/pull/3534) + - Fix `specific_platform` and `cache_all` with `bundle cache --all-platforms` [#4022](https://github.com/rubygems/rubygems/pull/4022) + - Bring back the possibility to install a plugin from path [#4020](https://github.com/rubygems/rubygems/pull/4020) + - Move ronn pages to lib [#3997](https://github.com/rubygems/rubygems/pull/3997) + - Fix fileutils double load when using `bundler/inline` [#3991](https://github.com/rubygems/rubygems/pull/3991) + - Accept responses with no etag header [#3865](https://github.com/rubygems/rubygems/pull/3865) + +## Documentation: + + - Fix typo of `bundle-install.1` (v2.1) [#4079](https://github.com/rubygems/rubygems/pull/4079) + - Add commented out example and more information link to generated gemspec [#4034](https://github.com/rubygems/rubygems/pull/4034) + +# 2.2.0.rc.2 (October 6, 2020) + +## Features: + + - Add `bundle fund` command [#3390](https://github.com/rubygems/rubygems/pull/3390) + +## Enhancements: + + - Fix ls-files matching regexp [#3845](https://github.com/rubygems/rubygems/pull/3845) + - Remove redundant `bundler/setup` require from `spec_helper.rb` generated by `bundle gem` [#3791](https://github.com/rubygems/rubygems/pull/3791) + +## Bug fixes: + + - Deduplicate spec groups [#3965](https://github.com/rubygems/rubygems/pull/3965) + - Fix some cases of running `bundler` on a path including brackets [#3854](https://github.com/rubygems/rubygems/pull/3854) + - Don't warn when deinit'ing submodules [#3969](https://github.com/rubygems/rubygems/pull/3969) + - Make `bundle clean --force` leave default gem executables untouched [#3907](https://github.com/rubygems/rubygems/pull/3907) + - Prioritize `path.system` over `path` when it makes sense [#3933](https://github.com/rubygems/rubygems/pull/3933) + - Sort requirements in Gem::Requirement to succeed comparison with different order [#3889](https://github.com/rubygems/rubygems/pull/3889) + - Print bug report template to standard error [#3924](https://github.com/rubygems/rubygems/pull/3924) + - Restore `bundle cache --all` in all cases [#3914](https://github.com/rubygems/rubygems/pull/3914) + - Move shebang to the top of `bin/console` template [#3927](https://github.com/rubygems/rubygems/pull/3927) + - Fix platform issues when running under a frozen bundle [#3909](https://github.com/rubygems/rubygems/pull/3909) + - Fix deprecation messages for `bundle install` flags, the config should be --local as before [#3917](https://github.com/rubygems/rubygems/pull/3917) + - Look for absolute path when removing bundler/setup from RUBYOPT in Bundler.unbundled_env method [#3877](https://github.com/rubygems/rubygems/pull/3877) + - Fix incorrect re-resolution when path gem excluded and not available [#3902](https://github.com/rubygems/rubygems/pull/3902) + - Fix error when building error message in `bundler/inline` [#3901](https://github.com/rubygems/rubygems/pull/3901) + - Fix regression related to locked ruby [#3900](https://github.com/rubygems/rubygems/pull/3900) + - Expand load paths in standalone setup.rb file [#3522](https://github.com/rubygems/rubygems/pull/3522) + - Fix broken exception recovery code when installing plugins [#3487](https://github.com/rubygems/rubygems/pull/3487) + - Fix incorrect build info on development versions of bundler, and on bundler versions installed as a default gem [#3778](https://github.com/rubygems/rubygems/pull/3778) + - Avoid autoloading `openssl` to try help with jruby load service issues [#3809](https://github.com/rubygems/rubygems/pull/3809) + - Fix `rake release` pushing all local tags instead of only the release tag [#3785](https://github.com/rubygems/rubygems/pull/3785) + - Fix `rake release` aborting when credentials file is missing, even if properly configured through XDG [#3783](https://github.com/rubygems/rubygems/pull/3783) + +## Deprecations: + + - Deprecate `bundle cache --all` flag [#3932](https://github.com/rubygems/rubygems/pull/3932) + +## Documentation: + + - Correct grammar in Gemfile docs [#3990](https://github.com/rubygems/rubygems/pull/3990) + - Fix typo in `bundle pristine` warning message [#3959](https://github.com/rubygems/rubygems/pull/3959) + - Improve human readable fallback version of CLI help messages [#3921](https://github.com/rubygems/rubygems/pull/3921) + - Note CLI flag deprecations in documentation [#3915](https://github.com/rubygems/rubygems/pull/3915) + - Update man page and deprecation warning for binstubs --all [#3872](https://github.com/rubygems/rubygems/pull/3872) + +# 2.2.0.rc.1 (July 2, 2020) + +## Features: + + - Windows support. There's still gotchas and unimplemented features, but a Windows CI is now enforced. + - Full multiplatform support. Bundler should now seamlessly handle multiplatform `Gemfile` or `gems.rb` files. + +## Enhancements: + + - `bundle info` now includes gem metadata [#7376](https://github.com/rubygems/bundler/pull/7376) + - `bundle list --without-group` and `bundle list --only-group` now support space separated list of groups in addition to single groups [#7404](https://github.com/rubygems/bundler/pull/7404) + - `bundle gem` now supports a `--rubocop` flag that adds the `rubocop` gem to the new gem layout [#6455](https://github.com/rubygems/bundler/pull/6455) + - `bundle gem` now supports `--test-unit` in addition to `rspec` and `minitest` as a value for its `--test` option [#5521](https://github.com/rubygems/bundler/pull/5521) + - `bundle install` now uses the available number of processors automatically for concurrent gem install, except for Windows where it still uses a single thread by default [#3393](https://github.com/rubygems/rubygems/pull/3393) and [#3718](https://github.com/rubygems/rubygems/pull/3718) + - Report Gitlab CI within bundler user-agent string [#3432](https://github.com/rubygems/rubygems/pull/3432) + - Add `bundle plugin uninstall` [#3482](https://github.com/rubygems/rubygems/pull/3482) + - `bundle gem` now supports a `--ci` flag and a `gem.ci` configuration that adds CI config files for the main CI providers to the generated gem skeleton [#3667](https://github.com/rubygems/rubygems/pull/3667) + - Allow setting a tag prefix to be used by release tasks [#3766](https://github.com/rubygems/rubygems/pull/3766) + - `bundle outdated` now prints output in columns for better readability [#4474](https://github.com/rubygems/bundler/pull/4474) + - bundler's `release` rake task now prints a better message when not being logged in and trying to push a gem [#7513](https://github.com/rubygems/bundler/pull/7513) + - `BUNDLE_APP_CONFIG` environment variable is now documented [#7563](https://github.com/rubygems/bundler/pull/7563) + - Original exception is now reported when bundler fails to load OpenSSL [#7527](https://github.com/rubygems/bundler/pull/7527) + - RVM specific instructions for recompiling ruby is no longer recommended when bundler fails to load OpenSSL [#7597](https://github.com/rubygems/bundler/pull/7597) + - Improve resolver debugging out from resolver [#7589](https://github.com/rubygems/bundler/pull/7589) and [#7590](https://github.com/rubygems/bundler/pull/7590) + - Clarify `bundle config --local` docs [#3408](https://github.com/rubygems/rubygems/pull/3408) + - Make sure to not "leak" to a different bundler install under any circumstances [#3595](https://github.com/rubygems/rubygems/pull/3595) + - Make sure users messing with `$;` doesn't affect us [#3602](https://github.com/rubygems/rubygems/pull/3602) + - Remove explicit psych activation which could potentially lead to packaging-specific issues [#3638](https://github.com/rubygems/rubygems/pull/3638) + - Deprecate `--no-deployment` flag and never recommend it [#3657](https://github.com/rubygems/rubygems/pull/3657) + - `bundle gem` test framework defaults to the `gem.test` setting and asks for a value without overwriting configuration if `-t` without a value is passed explicitly [#3544](https://github.com/rubygems/rubygems/pull/3544) + - `bundle gem` now ships with a default `.rubocop.yml` file and an offense free initial gem skeleton [#3731](https://github.com/rubygems/rubygems/pull/3731), [#3740](https://github.com/rubygems/rubygems/pull/3740), [#3765](https://github.com/rubygems/rubygems/pull/3765) + - Remove some requires that might workaround some autoloading issues on jruby [#3771](https://github.com/rubygems/rubygems/pull/3771) + - Unswallow an error that should make some random crashes on jruby easier to troubleshoot [#3774](https://github.com/rubygems/rubygems/pull/3774) + +## Bug fixes: + + - Fix `bundle pristine` removing gems with local overrides. Be conservative by printing a warning and skipping the removal [#7423](https://github.com/rubygems/bundler/pull/7423) + - Fix multiplaform resolution edge cases [#7522](https://github.com/rubygems/bundler/pull/7522) and [#7578](https://github.com/rubygems/bundler/pull/7578) + - Fix ruby version conflicts not displaying the current ruby version [7559](https://github.com/rubygems/bundler/pull/7559) + - Fix `Gemfile` or `gems.rb` files containing `:path` gems using relative paths not working when the app is packaged as a `jar` with `warbler` [#7614](https://github.com/rubygems/bundler/pull/7614) + - Fix config location edge case where if `BUNDLE_APP_CONFIG` is set to an absolute path like in official ruby docker images, and there's no Gemfile up in the directory hierarchy, bundler would end up using the default config location instead of the customized one [#7622](https://github.com/rubygems/bundler/pull/7622) + - Fix error message about missing permissions recommending a deprecated command [#7633](https://github.com/rubygems/bundler/pull/7633) + - Fix `init_gems_rb` setting being ignored by `bundle gem` [#7629](https://github.com/rubygems/bundler/pull/7629) + - Fix "unresolvable warning" being printed on `bundle install` of multipliplatform `Gemfile` or `gems.rb` files without lockfiles, multiplatform is now managed automatically [#7580](https://github.com/rubygems/bundler/pull/7580) + - Fix setting the number of `--jobs` to be one unit less than specified to the CLI [#3393](https://github.com/rubygems/rubygems/pull/3393) + - Fix extension building when the same git source specifies several gems with extensions [#3475](https://github.com/rubygems/rubygems/pull/3475) + - Fix uninitialized instance variable warning under ruby-head (2.8-dev) [#3477](https://github.com/rubygems/rubygems/pull/3477) + - Fix double chdir warning while installing a git gem with extensions [#3479](https://github.com/rubygems/rubygems/pull/3479) + - Fix some deprecations not showing up when CLI flags passed as `--flag=value` [#3561](https://github.com/rubygems/rubygems/pull/3561) + - Fix man pages display when bundler installed as a default gem [#3562](https://github.com/rubygems/rubygems/pull/3562) + - Fix bundler gem tasks not handling relative paths [#3586](https://github.com/rubygems/rubygems/pull/3586) + - Fix deprecation warnings when options the dashed names are used, such as `--no-prune` [#3623](https://github.com/rubygems/rubygems/pull/3623) + - Fix crash related to bundler gem activation under old rubygems version (2.6.1 or older) [#3626](https://github.com/rubygems/rubygems/pull/3626) + - Avoid stack overflow inside `StubSpecification` on some edge cases [#3635](https://github.com/rubygems/rubygems/pull/3635) + - Fix `bundle remove` with multiline gem specifications [#3400](https://github.com/rubygems/rubygems/pull/3400) + - Fix `bundle info` not informing about deleted gems as opposed to old `bundle show` [#3509](https://github.com/rubygems/rubygems/pull/3509) + - The `--no-deployment` flag to `bundle install` was deprecated just like the other flags that rely on their value being remembered [#3657](https://github.com/rubygems/rubygems/pull/3657) + - Fix `bundle install` unintentionally copying `with` and `without` global config to local configuration [#3666](https://github.com/rubygems/rubygems/pull/3666). This PR also address the `BUNDLE_WITH` environment variable unintentionally being persisted to configuration in a similar way ([#3708](https://github.com/rubygems/rubygems/issues/3708)) + - Fix race condition in `bundle install` that could "empty" exceptions to be raised [#3669](https://github.com/rubygems/rubygems/pull/3669) + - Fix `--no-cache` to `bundle install` being unintentionally deprecated [#3688](https://github.com/rubygems/rubygems/pull/3688) + - Avoid calling `LoadError#message` to fix performance regression in future ruby 3.0 [#3762](https://github.com/rubygems/rubygems/pull/3762) + +# 2.1.4 (January 5, 2020) + +## Bug fixes: + + - Fix `net-http-pipeline` no longer being allowed in Gemfiles if already installed in the system due to our vendored version of `net-http-persistent` optionally requiring it [#7529](https://github.com/bundler/bundler/pull/7529) + - Fix inline gems no longer being requirable if no Gemfile is present in the directory hierarchy [#7537](https://github.com/bundler/bundler/pull/7537) + +# 2.1.3 (January 2, 2020) + +## Bug fixes: + + - Fix `rake build` when path has spaces on it [#7514](https://github.com/bundler/bundler/pull/7514) + - Fix `rake release` git push tasks when the running shell has `git` as an alias of another command (like `hub`) [#7510](https://github.com/bundler/bundler/pull/7510) + - Fix some circular require warnings [#7520](https://github.com/bundler/bundler/pull/7520) + - Fix `bundle config set deployment true` recommended alternative to `bundle config --deployment` to behave in the same way as the `--deployment` flag [#7519](https://github.com/bundler/bundler/pull/7519) + +# 2.1.2 (December 20, 2019) + +## Bug fixes: + + - Restore an explicit `require "rubygems"` on top `rubygems_integration.rb` to avoid some missing constant errors under some convoluted setups [#7505](https://github.com/rubygems/bundler/pull/7505) + +# 2.1.1 (December 17, 2019) + +## Bug fixes: + + - Fix some cases of shelling out to `rubygems` still being silent [#7493](https://github.com/rubygems/bundler/pull/7493) + - Restore compatibility with `rubygems-bundler` so that binstubs work under `RVM` [#7498](https://github.com/rubygems/bundler/pull/7498) + +# 2.1.0 (December 15, 2019) + +## Features: + + - Add support for new default gems. In particular, + + * `open3` [#7455](https://github.com/rubygems/bundler/pull/7455) + * `cgi`: [#7456](https://github.com/rubygems/bundler/pull/7456) + * `uri` [#7460](https://github.com/rubygems/bundler/pull/7460) + + plus other PRs removing or lazily loading usages of these gems from other places to not interfere with user's choice, such as [#7471](https://github.com/rubygems/bundler/pull/7471) or [#7473](https://github.com/bundler/bundler/pull/7473) + +## Bug fixes: + + - Fix `bundle exec rake install` failing [#7474](https://github.com/rubygems/bundler/pull/7474) + - Fix `bundle exec`'ing to rubygems being silent [#7442](https://github.com/rubygems/bundler/pull/7442) + - Restore previous `BUNDLE_GEMFILE` in `bundler/inline` [#7418](https://github.com/rubygems/bundler/pull/7418) + - Fix error when using `gem` DSL's `:glob` option for selecting gemspecs from a specific source [#7419](https://github.com/rubygems/bundler/pull/7419) + +## Enhancements: + + - `bundle config` no longer warns when using "old interface" (might be deprecated again in the future) [#7475](https://github.com/rubygems/bundler/pull/7475) + - `bundle update` no longer warns when used without arguments (might be deprecated again in the future) [#7475](https://github.com/rubygems/bundler/pull/7475) + +# 2.1.0.pre.3 (November 12, 2019) + +## Features: + + - Add caller information to some deprecation messages to make them easier to fix [#7361](https://github.com/rubygems/bundler/pull/7361) + - Reconcile `bundle cache` vs `bundle package` everywhere. Now in docs, CLI help and everywhere else `bundle cache` is the preferred version and `bundle package` remains as an alias [#7389](https://github.com/rubygems/bundler/pull/7389) + - Display some basic `bundler` documentation together with ruby's RDoc based documentation [#7394](https://github.com/rubygems/bundler/pull/7394) + +## Bug fixes: + + - Fix typos deprecation message and upgrading docs [#7374](https://github.com/rubygems/bundler/pull/7374) + - Deprecation warnings about `taint` usage on ruby 2.7 [#7385](https://github.com/rubygems/bundler/pull/7385) + - Fix `--help` flag not correctly delegating to `man` when used with command aliases [#7388](https://github.com/rubygems/bundler/pull/7388) + - `bundle add` should cache newly added gems if an application cache exists [#7393](https://github.com/rubygems/bundler/pull/7393) + - Stop using an insecure folder as a "fallback home" when user home is not defined [#7416](https://github.com/rubygems/bundler/pull/7416) + - Fix `bundler/inline` warning about `Bundler.root` redefinition [#7417](https://github.com/rubygems/bundler/pull/7417) + +# 2.1.0.pre.2 (September 15, 2019) + +## Bug fixes: + + - Fix `bundle clean` trying to delete non-existent directory ([#7340](https://github.com/rubygems/bundler/pull/7340)) + - Fix warnings about keyword argument separation on ruby 2.7 ([#7337](https://github.com/rubygems/bundler/pull/7337)) + +# 2.1.0.pre.1 (August 28, 2019) + + One of the biggest changes in bundler 2.1.0 is that deprecations for upcoming + breaking changes in bundler 3 will be turned on by default. We do this to grab + feedback and communicate early to our users the kind of changes we're intending + to ship with bundler 3. See + [#6965](https://github.com/rubygems/bundler/pull/6965). + + Another important improvement is a better coexistence between bundler + installations and the default copy of bundler that comes with ruby installed as + a default gem. Since bundler is shipped as a default gem with ruby, a number of + users have been affected by issues where bundler ends up failing due to version + mismatches, because at some point of the execution, bundler switches to run the + default copy instead of the expected version. A number of PRs have been focused + on minimizing (hopefully eliminating) this, such as + [#7100](https://github.com/rubygems/bundler/pull/7100), + [#7137](https://github.com/rubygems/bundler/pull/7137), + [#6996](https://github.com/rubygems/bundler/pull/6996), + [#7056](https://github.com/rubygems/bundler/pull/7056), + [#7062](https://github.com/rubygems/bundler/pull/7062), + [#7193](https://github.com/rubygems/bundler/pull/7193), + [#7216](https://github.com/rubygems/bundler/pull/7216), + [#7274](https://github.com/rubygems/bundler/pull/7274) + +## Deprecations: + + * See the [the upgrading document](UPGRADING.md) for a detailed explanation of + the deprecations that are getting enabled in bundler 2.1, and the future + breaking changes in bundler 3. + +## Features: + + - Reimplement `config` command using subcommands ([#5981](https://github.com/rubygems/bundler/pull/5981)) + - Add `bundle plugin list` command ([#6120](https://github.com/rubygems/bundler/pull/6120)) + - Introduce a `bundle lock --gemfile` flag ([#6748](https://github.com/rubygems/bundler/pull/6748)) + - Add local git repository source option (`--local_git`) to plugin installation ([#6749](https://github.com/rubygems/bundler/pull/6749)) + - Add `quiet` flag to inline bundler ([#6828](https://github.com/rubygems/bundler/pull/6828)) + - Introduce a `prefer_patch` configuration that makes `bundle update` behave like `bundle update --patch` ([#6931](https://github.com/rubygems/bundler/pull/6931)) + - Introduce `Bundler.original_system` and `Bundler.original_exec` to shell out or exec to external programs using the original environment before bundler was loaded ([#7052](https://github.com/rubygems/bundler/pull/7052)) + - Add feature parity to `bundle info GEM` with respect to the old deprecated command `bundle show GEM` [#7026](https://github.com/rubygems/bundler/pull/7026) + - Introduce `bundle list` to list groups of gems in your Gemfile. This command was actually documented, but was working as an alias to `bundle show` so this could also be considered a bug fix :) [#7072](https://github.com/rubygems/bundler/pull/7072) + - Introduce `bundle outdated --filter-strict` as an alias to `bundle outdated --strict` [#6030](https://github.com/rubygems/bundler/pull/6030) + - Add `:git` and `:branch` options to `bundle add` ([#7127](https://github.com/rubygems/bundler/pull/7127)) + - Add `:ruby_26` as a valid value to the `:platform(s)` dsl ([#7155](https://github.com/rubygems/bundler/pull/7155)) + - Let the `bundle cache` command include all features currently provided by `bundle package` ([#7249](https://github.com/rubygems/bundler/pull/7249)) + - Several improvements on new gem templates ([#6924](https://github.com/rubygems/bundler/pull/6924), [#6968](https://github.com/bundler/bundler/pull/6968), [#7209](https://github.com/bundler/bundler/pull/7209), [#7222](https://github.com/bundler/bundler/pull/7222), [#7238](https://github.com/bundler/bundler/pull/7238)) + - Add `--[no-]git` option to `bundle gem` to generate non source control gems. Useful for monorepos, for example ([#7263](https://github.com/rubygems/bundler/pull/7263)) + +## Bug fixes: + + - Raise when the same gem is available in multiple sources, and show a suggestion to solve it ([#5985](https://github.com/rubygems/bundler/pull/5985)) + - Validate that bundler has permissions to write to the tmp directory, and raise with a meaningful error otherwise ([#5954](https://github.com/rubygems/bundler/pull/5954)) + - Remove downloaded `.gem` file from the cache if it's corrupted ([#6010](https://github.com/rubygems/bundler/pull/6010)) + - Fix generated README in new gems to explicitly suggest running `bundle install`, so that the outcome is independent from the major version of bundler being run ([#6068](https://github.com/rubygems/bundler/pull/6068)) + - Fix `bundle outdated --group NAME` when the group is listed second in the Gemfile ([#6116](https://github.com/rubygems/bundler/pull/6116)) + - Improve conflict resolution messages by not calling "ruby" a gem when conflict happens in the `required_ruby_version`, and by filtering out requirements that didn't contribute to the conflict ([#6647](https://github.com/rubygems/bundler/pull/6647)) + - Avoid fetching and rebuilding git gems whenever any gem is changed in the Gemfile ([#6711](https://github.com/rubygems/bundler/pull/6711)) + - Include the exact bundler version in the lock file in the suggested command when bundler warns about version mismatches of itself [#6971](https://github.com/rubygems/bundler/pull/6971) + - Fix plugins being installed every time a command is run #[#6978](https://github.com/rubygems/bundler/pull/6978) + - Fallback to sequentially fetching specs on 429s [#6728](https://github.com/rubygems/bundler/pull/6728) + - Make `bundle clean` also clean native extensions for gems with a git source [#7058](https://github.com/rubygems/bundler/pull/7058) + - Fix `bundle info bundler` to show the correct path to the bundler gem [#7026](https://github.com/rubygems/bundler/pull/7026) + - Fix `bundle config build.` not sending multiple parameters to `extconf.rb` correctly [#7023](https://github.com/rubygems/bundler/pull/7023) + - Fix bad error message on Gemfile errors under ruby 2.7 (still unreleased, but it's a bugfix for beta testers after all) [#7038](https://github.com/rubygems/bundler/pull/7038) + - Warn about situations where multiple gems provide the same executable ([#7075](https://github.com/rubygems/bundler/pull/7075)) + - Ignore `frozen` setting in inline mode ([#7125](https://github.com/rubygems/bundler/pull/7125)) + - Fix incorrect "bundler attempted to update GEM but version stayed the same" message when updating git sourced gems ([#6325](https://github.com/rubygems/bundler/pull/6325)) + - Don't check for existence of a writable home directory if `BUNDLE_USER_HOME` is set ([#6885](https://github.com/rubygems/bundler/pull/6885)) + - Fix error message when server would respond to a bad username/password request with a 401 ([#6928](https://github.com/rubygems/bundler/pull/6928)) + - Fix `bundle outdated` pluralization when multiple groups are requested ([#7063](https://github.com/rubygems/bundler/pull/7063)) + - Fix `bundle install` not updating conservatively when gemspec is changed ([#7143](https://github.com/rubygems/bundler/pull/7143)) + - Fix `bundle exec` not respecting custom process titles inside scripts ([#7140](https://github.com/rubygems/bundler/pull/7140)) + - Fix `bundle update` message about exclude groups saying "installed" instead of "updated" ([#7150](https://github.com/rubygems/bundler/pull/7150)) + - Fix `bundle licenses` not showing correct information about bundler itself ([#7147](https://github.com/rubygems/bundler/pull/7147)) + - Fix installation path not including ruby scope when `BUNDLE_PATH` was set ([#7163](https://github.com/rubygems/bundler/pull/7163)) + - Fix `bundle clean` incorrectly removing git dependencies present in the Gemfile when rubygems 3.0+ was used and path involved a symlink ([#7211](https://github.com/rubygems/bundler/pull/7211)) + - Fix platform specific gems always being re-resolved when bundler was not running under that platform ([#7212](https://github.com/rubygems/bundler/pull/7212)) + - Fix `bundle package --all-platforms` causing `bundle install` to ignore `--with` and `--without` ([#6113](https://github.com/rubygems/bundler/pull/6113)) + - Fix `MissingRevision` git errors to include the specific `git` command that failed under the hood ([#7225](https://github.com/rubygems/bundler/pull/7225)) + - Fix using gemspec & `force_ruby_platform` on Windows ([#6809](https://github.com/rubygems/bundler/pull/6809)) + - Make bundler's binstub checks on bundler version consistent with rubygems `BundlerVersionFinder` ([#7259](https://github.com/rubygems/bundler/pull/7259)) + - Fix `bundle install` and `bundle update` generating different lockfiles when `path:` gems with relative paths starting with "./" were used ([#7264](https://github.com/rubygems/bundler/pull/7264)) + - Give a proper error when user tries to `bundle open` a default gem ([#7288](https://github.com/rubygems/bundler/pull/7288)) + - Fix `bundle doctor` command ([#7309](https://github.com/rubygems/bundler/pull/7309)) + - Fix bundler giving an unclear recommendation when duplicated gems are found in the Gemfile ([#7302](https://github.com/rubygems/bundler/pull/7302)) + +## Documentation: + + - Fix typo on a file extension in `bundle.ronn` [#7146](https://github.com/rubygems/bundler/pull/7146) + - Fix incorrect default value for `cache_path` configuration ([#7229](https://github.com/rubygems/bundler/pull/7229)) + - Binstubs documentation has been improved ([#5889](https://github.com/rubygems/bundler/pull/5889)) + - Fix incorrect sections when explaining `:git`, `:branch`, and `:ref` options ([#7265](https://github.com/rubygems/bundler/pull/7265)) + - Fix mentions to remembered options in docs to explain the current state ([#7242](https://github.com/rubygems/bundler/pull/7242)) + + Internally, there's also been a bunch of improvements in our development + environment, test suite, policies, contributing docs, and a bunch of cleanups of + old compatibility code. + +# 2.0.2 (June 13, 2019) + +## Enhancements: + + - Fixes for Bundler integration with ruby-src ([#6941](https://github.com/rubygems/bundler/pull/6941), [#6973](https://github.com/bundler/bundler/pull/6973), [#6977](https://github.com/bundler/bundler/pull/6977), [#6315](https://github.com/bundler/bundler/pull/6315), [#7061](https://github.com/bundler/bundler/pull/7061)) + - Use `__dir__` instead of `__FILE__` when generating a gem with `bundle gem` ([#6503](https://github.com/rubygems/bundler/pull/6503)) + - Use `https` on externals links in the Bundler gemspec ([#6721](https://github.com/rubygems/bundler/pull/6721)) + - Removed duplicate gem names from the suggested `did you mean` list for gem typos ([#6739](https://github.com/rubygems/bundler/pull/6739)) + - Removed Ruby 1.x compatibility code ([#6764](https://github.com/rubygems/bundler/pull/6764), [#6806](https://github.com/bundler/bundler/pull/6806)) + - Fixed an issue where `bundle remove` would crash with certain Gemfiles ([#6768](https://github.com/rubygems/bundler/pull/6769)) + - Fixed indentation in the Bundler executable template ([#6773](https://github.com/rubygems/bundler/pull/6773)) + - Fixed an issue where plugins could register for the same Bundler hook multiple times ([#6775](https://github.com/rubygems/bundler/pull/6775)) + - Changed the "multiple sources" message in `bundle install` to be a warning instead of an error ([#6790](https://github.com/rubygems/bundler/pull/6790)) + - Fixed a bug where path gems would break when using `only_update_to_newer_versions` ([#6774](https://github.com/rubygems/bundler/pull/6774)) + - Fixed a bug where installing plugins with the `--deployment` setting would fail ([#6805](https://github.com/rubygems/bundler/pull/6805)) + - Fixed an issue where `bundle update` couldn't update & install a gem when `no_install` was set (a `bundle package` config) ([#7078](https://github.com/rubygems/bundler/pull/7078)) + - Fixed an issue where users could not run `bundle exec` on default gems ([#6963](https://github.com/rubygems/bundler/pull/6963)) + - Updated vendor libraries to their latest version ([#7076](https://github.com/rubygems/bundler/pull/7067), [#7068](https://github.com/bundler/bundler/pull/7068)) + - Fixed an issue where the `github` source was not using `https` by default that we mentioned in the 2.0 release ([#7182](https://github.com/rubygems/bundler/pull/7182)) + - Fixed an issue where `rake release` was not outputting the message to users asking for a 2fa token ([#7199](https://github.com/rubygems/bundler/pull/7199)) + +## Documentation: + + - Fix incorrect documented `BUNDLE_PATH_RELATIVE_TO_CWD` env var ([#6751](https://github.com/rubygems/bundler/pull/6751)) + - Update URLs in Bundler's documentation to use `https` ([#6935](https://github.com/rubygems/bundler/pull/6935)) + +# 2.0.1 (January 4, 2019) + +## Bug fixes: + + - Relaxed RubyGems requirement to `>= 2.5.0` ([#6867](https://github.com/rubygems/bundler/pull/6867)) + +# 2.0.0 (January 3, 2019) + + No changes. + +# 2.0.0.pre.3 (December 30, 2018) + +## Breaking changes: + + - Bundler 2 now requires RubyGems 3.0.0 at minimum + +## Bug fixes: + + - Ruby 2.6 compatibility fixes (@segiddins) + +## Enhancements: + + - Import changes from Bundler 1.17.3 release + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +# 2.0.0.pre.2 (November 27, 2018) + +## Breaking changes: + + - `:github` source in the Gemfile now defaults to using HTTPS + +Changes + + - Add compatibility for Bundler merge into ruby-src + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +# 2.0.0.pre.1 (November 9, 2018) + +## Breaking changes: + + - Dropped support for versions of Ruby under 2.3 + - Dropped support for version of RubyGems under 2.5 + - Moved error messages from STDOUT to STDERR + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +# 1.17.3 (December 27, 2018) + +## Bug fixes: + + - Fix a Bundler error when installing gems on old versions of RubyGems ([#6839](https://github.com/rubygems/bundler/issues/6839), @colby-swandale) + - Fix a rare issue where Bundler was removing itself after a `bundle clean` ([#6829](https://github.com/rubygems/bundler/issues/6829), @colby-swandale) + +## Documentation: + + - Add entry for the `bundle remove` command to the main Bundler manual page + +# 1.17.2 (December 11, 2018) + + - Add compatibility for bundler merge with Ruby 2.6 + +# 1.17.1 (October 25, 2018) + + - Convert `Pathname`s to `String`s before sorting them, fixing #6760 and #6758 ([#6761](https://github.com/rubygems/bundler/pull/6761), @alexggordon) + +# 1.17.0 (October 25, 2018) + + No changes. + +# 1.17.0.pre.2 (October 13, 2018) + +## Features: + + - Configure Bundler home, cache, config and plugin directories with `BUNDLE_USER_HOME`, `BUNDLE_USER_CACHE`, `BUNDLE_USER_CONFIG` and `BUNDLE_USER_PLUGIN` env vars ([#4333](https://github.com/rubygems/bundler/issues/4333), @gwerbin) + - Add `--all` option to `bundle binstubs` that will generate an executable file for all gems with commands in the bundle + - Add `bundle remove` command to remove gems from the Gemfile via the CLI + - Improve checking file permissions and asking for `sudo` in Bundler when it doesn't need to + - Add error message to `bundle add` to check adding duplicate gems to the Gemfile + - When asking for `sudo`, Bundler will show a list of folders/files that require elevated permissions to write to. + + The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Improve deprecation warning message for `bundle show` command + - Improve deprecation warning message for the `--force` option in `bundle install` + +# 1.17.0.pre.1 (September 24, 2018) + +## Features: + + - Check folder/file permissions of the Bundle home directory in the `bundle doctor` command ([#5786](https://github.com/rubygems/bundler/issues/5786), @ajwann) + - Remove compiled gem extensions when running `bundle clean` ([#5596](https://github.com/rubygems/bundler/issues/5596), @akhramov) + - Add `--paths` option to `bundle list` command ([#6172](https://github.com/rubygems/bundler/issues/6172), @colby-swandale) + - Add base error class to gems generated from `bundle gem` ([#6260](https://github.com/rubygems/bundler/issues/6260), @christhekeele) + - Correctly re-install gem extensions with a git source when running `bundle pristine` ([#6294](https://github.com/rubygems/bundler/issues/6294), @wagenet) + - Add config option to disable platform warnings ([#6124](https://github.com/rubygems/bundler/issues/6124), @agrim123) + - Add `--skip-install` option to `bundle add` command to add gems to the Gemfile without installation ([#6511](https://github.com/rubygems/bundler/issues/6511), @agrim123) + - Add `--only-explicit` option to `bundle outdated` to list only outdated gems in the Gemfile ([#5366](https://github.com/rubygems/bundler/issues/5366), @peret) + - Support adding multiple gems to the Gemfile with `bundle add` ([#6543](https://github.com/rubygems/bundler/issues/6543), @agrim123) + - Make registered plugin events easier to manage in the Plugin API (@jules2689) + - Add new gem install hooks to the Plugin API (@jules2689) + - Add `--optimistic` and `--strict` options to `bundle add` ([#6553](https://github.com/rubygems/bundler/issues/6553), @agrim123) + - Add `--without-group` and `--only-group` options to `bundle list` ([#6564](https://github.com/rubygems/bundler/issues/6564), @agrim123) + - Add `--gemfile` option to the `bundle exec` command ([#5924](https://github.com/rubygems/bundler/issues/5924), @ankitkataria) + + The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Make `install --path` relative to the current working directory ([#2048](https://github.com/rubygems/bundler/issues/2048), @igorbozato) + - Auto-configure job count ([#5808](https://github.com/rubygems/bundler/issues/5808), @segiddins) + - Use the Gem Version Promoter for major gem updates ([#5993](https://github.com/rubygems/bundler/issues/5993), @segiddins) + - Add config option to add the Ruby scope to `bundle config path` when configured globally (@segiddins) + +# 1.16.6 (October 5, 2018) + +## Enhancements: + + - Add an error message when adding a gem with `bundle add` that's already in the bundle ([#6341](https://github.com/rubygems/bundler/issues/6341), @agrim123) + - Add Homepage, Source Code and Changelog URI metadata fields to the `bundle gem` gemspec template (@walf443) + +## Bug fixes: + + - Fix issue where updating a gem resulted in the gem's version being downgraded when `BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS` was set ([#6529](https://github.com/rubygems/bundler/issues/6529), @theflow) + - Fix some rescue calls that don't specify error type (@utilum) + - Fix an issue when the Lockfile would contain platform-specific gems that it didn't need ([#6491](https://github.com/rubygems/bundler/issues/6491), @segiddins) + - Improve handling of adding new gems with only a single group to the Gemfile in `bundle add` (@agrim123) + - Refactor check for OpenSSL in `bundle env` (@voxik) + - Remove an unnecessary assignment in Metadata (@voxik) + +## Documentation: + + - Update docs to reflect revised guidance to check in Gemfile.lock into version control for gems ([#5879](https://github.com/rubygems/bundler/issues/5879), @arbonap) + - Add documentation for the `--all` flag in `bundle update` (@agrim123) + - Update README to use `bundle add` in usage examples (@hdf1986) + +# 1.16.5 (September 18, 2018) + +## Enhancements: + + - Add support for TruffleRuby (@eregon) + +## Bug fixes: + + - Avoid printing git errors when checking the version on incorrectly packaged versions of Bundler ([#6453](https://github.com/rubygems/bundler/issues/6453), @greysteil) + - Fix issue where Bundler does not check the given class when comparing equality in DepProxy (@ChrisBr) + - Handle `RangeNotSatisfiable` error in Compact Index (@MaxLap) + - Check for initialized `search` variable in `LazySpecification` (@voxik) + - Fix LoadError occurring in nested bundle exec calls ([#6537](https://github.com/rubygems/bundler/issues/6537), @colby-swandale) + - Check that Bundler::Deprecate is not an autoload constant ([#6163](https://github.com/rubygems/bundler/issues/6163), @eregon) + - Prefer non-pre-release versions when performing a `bundle update --patch` ([#6684](https://github.com/rubygems/bundler/issues/6684), @segiddins) + +# 1.16.4 (August 17, 2018) + +## Enhancements: + + - Welcome new members to the Bundler core team (@indirect) + - Don't mutate original error trees when determining version_conflict_message (@greysteil) + - Update vendored Molinillo to 0.6.6 (@segiddins) + +## Bug fixes: + + - Reword bundle update regression message to be more clear to the user when a gem's version is downgraded ([#6584](https://github.com/rubygems/bundler/issues/6584), @ralphbolo) + - Respect --conservative flag when updating a dependency group ([#6560](https://github.com/rubygems/bundler/issues/6560), @greysteil) + - Fix issue where a pre-release version was not being selected when it's specified in the Gemfile ([#6449](https://github.com/rubygems/bundler/issues/6449), @akihiro17) + - Fix issue where `Etc` was not loaded when getting the user's home dir ([#6640](https://github.com/rubygems/bundler/issues/6640), @colby-swandale) + - Use UTF-8 for reading files including Gemfile ([#6660](https://github.com/rubygems/bundler/issues/6660), @eregon) + - Remove unnecessary `while` loop in path resolver helper (@ojab) + +## Documentation: + + - Document that `bundle show [--paths]` sorts results by name (@kemitchell) + +# 1.16.3 (July 17, 2018) + +## Features: + + - Support URI::File of Ruby 2.6 (@hsbt) + +## Bug fixes: + + - Expand symlinks during setup to allow Bundler to load correctly when using symlinks in $GEM_HOME ([#6465](https://github.com/rubygems/bundler/issues/6465), @ojab, @indirect) + - Dont let Bundler create temporary folders for gem installs which are owned by root ([#6258](https://github.com/rubygems/bundler/issues/6258), @colby-swandale) + - Don't fallback to using temporary directories when needed directories already exist ([#6546](https://github.com/rubygems/bundler/issues/6546), @brodock) + - Use SharedHelpers.filesystem_access when reading a Gemfile so friendly error messages can be given to the user ([#6541](https://github.com/rubygems/bundler/issues/6541), @segiddins) + - Check if source responds to `#remotes` before printing gem install error message ([#6211](https://github.com/rubygems/bundler/issues/6211), @colby-swandale) + - Handle Errno::ENOTSUP in the Bundler Process Lock to prevent exceptions when using NFS mounts ([#6566](https://github.com/rubygems/bundler/issues/6566), @colby-swandale) + - Respect encodings when reading gemspecs ([#6598](https://github.com/rubygems/bundler/issues/6598), @deivid-rodriguez) + +## Documentation: + + - Fix links between manual pages (@BanzaiMan) + - Add warning to Gemfile documentation for the use of the `source` option when declaring gems ([#6280](https://github.com/rubygems/bundler/issues/6280), @forestgagnon) + +# 1.16.2 (April 20, 2018) + +## Enhancements: + + - Include the gem's source in the gem install error message when available (@papanikge) + - Remove unnecessary executable bit from gem template (@voxik) + - Dont add the timestamp comment with gems added to the Gemfile via `bundle add` ([#6193](https://github.com/rubygems/bundler/issues/6193), @cpgo) + - Improve yanked gem error message (@alyssais) + - Use `Bundler.rubygems.inflate` instead of the Gem::Util method directly (@segiddins) + - Remove unused instance variable (@segiddins) + +## Bug fixes: + + - Only trap INT signal and have Ruby's signal default handler be invoked (@shayonj) + - Fix warning about the use of `__FILE__` in RubyGems integration testing (@MSP-Greg) + - Skip the outdated bundler check when MD5 is not available ([#6032](https://github.com/rubygems/bundler/issues/6032), @segiddins) + - Fallback to the original error if the friendly message raises (@segiddins) + - Rename Bundler.frozen? to avoid Object method conflict ([#6252](https://github.com/rubygems/bundler/issues/6252), @segiddins) + - Ensure the bindir exists before installing gems (@segiddins) + - Handle gzip corruption errors in the compact index client ([#6261](https://github.com/rubygems/bundler/issues/6261), @colby-swandale) + - Check if the current directory is writeable when writing files in `bundle gem` ([#6219](https://github.com/rubygems/bundler/issues/6219), @nilsding) + - Fix hang when gemspec has incompatible encoding (@deivid-rodriguez) + - Gracefully handle when the lockfile is missing spec entries for the current platform ([#6079](https://github.com/rubygems/bundler/issues/6079), @segiddins) + - Use Gem::Util.inflate instead of Gem.inflate (@hsbt) + - Update binstub generator to use new ERB.new arity in Ruby 2.6 (@koic) + - Fix `source_location` call in rubygems integration (@MSP-Greg) + - Use `filesystem_access` when copying files in Compact Index Updater ([#6289](https://github.com/rubygems/bundler/issues/6289), @segiddins) + - Fail gracefully when resetting git gems to the given revision fails ([#6324](https://github.com/rubygems/bundler/issues/6324), @segiddins) + - Handle exceptions that do not have a backtrace ([#6342](https://github.com/rubygems/bundler/issues/6342), @nesaulov) + - Check if stderr was closed before writing to it (@shime) + - Handle updating a specific gem for a non-local platform ([#6350](https://github.com/rubygems/bundler/issues/6350), @greysteil) + - Bump the `bundle_binstub` check-length to 300 characters (@tduffield) + - Fix specifying alterntive Lockfile with `bundle lock` when default gemfile is present ([#6460](https://github.com/rubygems/bundler/issues/6460), @agrim123) + - Allow installing dependencies when the path is set to `.` ([#6475](https://github.com/rubygems/bundler/issues/6475), @segiddins) + - Support Bundler installing on a readonly filesystem without a home directory ([#6461](https://github.com/rubygems/bundler/issues/6461), @grosser) + - Filter git uri credentials in source description (@segiddins) + +## Documentation: + + - Correct typos in `bundle binstubs` man page (@erikj, @samueloph) + - Update links in `bundle gem` command documentation to use https (@KrauseFx) + - Fix broken links between bundler man pages (@segiddins) + - Add man page for the `bundle doctor` command ([#6243](https://github.com/rubygems/bundler/issues/6243), @nholden) + - Document `# frozen_string_literal` in `bundle init` Gemfile (@315tky) + - Explain the gemspec files attribute in `bundle gem` template and print a link to bundler.io guides when running `bundle gem` ([#6246](https://github.com/rubygems/bundler/issues/6246), @nesaulov) + - Small copy tweaks & removed redundant phrasing in the bundler man page (@rubymorillo) + - Improve the documentation of the settings load order in Bundler (@rubymorillo) + - Added license info to main README (@rubymorillo) + - Document parameters and return value of Injector#inject (@tobias-grasse) + +# 1.16.1 (December 12, 2017) + +## Bug fixes: + + - avoid hanging on complex resolver errors ([#6114](https://github.com/rubygems/bundler/issues/6114), @halfbyte) + - avoid an error when running `bundle update --group` ([#6156](https://github.com/rubygems/bundler/issues/6156), @mattbrictson) + - ensure the resolver prefers non-pre-release gems when possible ([#6181](https://github.com/rubygems/bundler/issues/6181), @greysteil) + - include bundler's gemspec in the built gem ([#6165](https://github.com/rubygems/bundler/issues/6165), @dr-itz) + - ensure locally installed specs are not overridden by those in remote sources during dependency resolution ([#6072](https://github.com/rubygems/bundler/issues/6072), @indirect) + - ensure custom gemfiles are respected in generated binstubs (@pftg) + - fail gracefully when loading a bundler-generated binstub when `bin/bundle` was not generated by bundler ([#6149](https://github.com/rubygems/bundler/issues/6149), @hsbt) + - allow `bundle init` to be run even when a parent directory contains a gemfile ([#6205](https://github.com/rubygems/bundler/issues/6205), @colby-swandale) + +# 1.16.0 (October 31, 2017) + +## Bug fixes: + + - avoid new RubyGems warning about unsafe YAML loading (to keep output consistent) (@segiddins) + - load digest subclasses in a thread-safe manner (@segiddins, @colby-swandale) + - avoid unused variable warnings under ruby 2.5 (@amatsuda) + - fix printing the same message twice in verbose mode ([#6028](https://github.com/rubygems/bundler/issues/6028), @akhramov) + - allow `SignalException`s to bubble up to the interpreter during `bundle exec` ([#6090](https://github.com/rubygems/bundler/issues/6090), @dekellum) + - avoid activating stdlib digest under Ruby 2.5 (@segiddins) + - prioritise explicitly requested gems in dependency resolution sort order (@segiddins) + - reduce memory usage during dependency resolution ([#6114](https://github.com/rubygems/bundler/issues/6114), @greysteil) + - ensure that the default bundler gem is not accidentally activated on ruby 2.5 when using local git overrides (@segiddins) + +# 1.16.0.pre.3 (October 4, 2017) + +## Features: + + - the output from `bundle env` includes more information, particularly both the compiled & loaded versions of OpenSSL (@indirect) + +## Bug fixes: + + - fix a bug where installing on FreeBSD would accidentally raise an error ([#6013](https://github.com/rubygems/bundler/issues/6013), @olleolleolle) + - fix a regression in 1.16 where pre-release gems could accidentally be resolved even when the gemfile contained no pre-release requirements (@greysteil) + - bundler will avoid making unnecessary network requests to fetch dependency data, fixing a regression introduced in 1.16 (@segiddins) + - the outdated bundler version message is disabled by default until the message has been fine-tuned ([#6004](https://github.com/rubygems/bundler/issues/6004), @segiddins) + +# 1.16.0.pre.2 (September 6, 2017) + +## Bug fixes: + + - handle when a connection is missing a socket when warning about OpenSSL version (@greysteil) + - the description for the `rake release` task now reflects `$RUBYGEMS_HOST` (@wadetandy) + - fix a bug where `bundle update` would regress transitive dependencies (@greysteil) + +# 1.16.0.pre.1 (September 4, 2017) + +## Features: + + - allow using non-branch symbolic refs in a git source ([#4845](https://github.com/rubygems/bundler/issues/4845), @segiddins) + - allow absolute paths in the `cache path` setting ([#5627](https://github.com/rubygems/bundler/issues/5627), @mal) + - gems created via `bundle gem` with rspec have `--require spec_helper` in their `.rspec` file (@koic) + - `bundle env` includes `Gem.ruby` and the `bundle` binstub shebang when they don't match ([#5616](https://github.com/rubygems/bundler/issues/5616), @segiddins) + - allow passing gem names to `bundle pristine` (@segiddins) + - `bundle version` and `bundle env` include the commit and build date for the bundler gem ([#5049](https://github.com/rubygems/bundler/issues/5049), @segiddins) + - add the `--shebang` option to `bundle binstubs` ([#4070](https://github.com/rubygems/bundler/issues/4070), @segiddins, @Zorbash) + - gemfiles are `eval`ed one fewer time when running `bundle install` ([#4952](https://github.com/rubygems/bundler/issues/4952), [#3096](https://github.com/bundler/bundler/issues/3096), [#4417](https://github.com/bundler/bundler/issues/4417), @segiddins) + - the `fileutils` gem is now vendored so different versions of the gem can be activated (@segiddins) + - speed up no-op installations ([#5842](https://github.com/rubygems/bundler/issues/5842), @segiddins) + - default to keeping the lockfile in the default gem template (@deivid-rodriguez) + - add a special bundler binstub that ensures the correct version of bundler is activated ([#5876](https://github.com/rubygems/bundler/issues/5876), @segiddins) + - speed up dependency resolution and ensure that all resolvable gemfiles can be installed (@segiddins, @greysteil) + - add a `bundle list` command that prints the gems in use ([#4754](https://github.com/rubygems/bundler/issues/4754), @colby-swandale) + - allow adding credentials to a gem source during deployment when `allow_deployment_source_credential_changes` is set (@adrian-gomez) + - making an outdated (and insecure) TLS connection to rubygems.org will print a warning (@segiddins) + +## Bug fixes: + + - allow configuring a mirror fallback timeout without a trailing slash ([#4830](https://github.com/rubygems/bundler/issues/4830), @segiddins) + - fix handling of mirrors for file: urls that contain upper-case characters (@segiddins) + - list the correct gem host for `rake release` when `allowed_push_host` has been set (@mdeering) + - ensure `Bundler.original_env` preserves all env keys that bundler sets ([#5700](https://github.com/rubygems/bundler/issues/5700), @segiddins) + - ensure `bundle pristine` removes files added to a git gem (@segiddins) + - load plugin files from path gems before gem installation ([#5429](https://github.com/rubygems/bundler/issues/5429), @segiddins) + - ensure gems containing manpages are properly set up ([#5730](https://github.com/rubygems/bundler/issues/5730), @segiddins) + - avoid fetching remote specs when all effected gems are in groups that are not being installed (@segiddins) + - allow `BUNDLE_GEMFILE` to be a relative path ([#5712](https://github.com/rubygems/bundler/issues/5712), @gxespino) + - show a more helpful error message when a gem fails to install due to a corrupted lockfile ([#5846](https://github.com/rubygems/bundler/issues/5846), @segiddins) + - add a process lock to allow multiple concurrent `bundle install`s ([#5851](https://github.com/rubygems/bundler/issues/5851), @stefansedich) + - ensure that specifications always return an array for `#extensions` (@greysteil) + - print a helpful error message when using a gem in the Gemfile with an empty name (@colby-swandale) + - ensure that all gemfiles are included in `bundle env` (@segiddins) + - use ssl client cert and ca cert settings from gem configuration as fallbacks (@stan3) + - avoid global namespace pollution when loading gems ([#5958](https://github.com/rubygems/bundler/issues/5958), @shyouhei) + - avoid running a complete re-resolve on `bundle update --bundler` (@segiddins) + - allow `bundle binstubs --standalone` to work without `path` being set (@colby-swandale) + - fix support for bundle paths that include jars or wars on jruby ([#5975](https://github.com/rubygems/bundler/issues/5975), @torcido) + +# 1.15.4 (August 19, 2017) + +## Bug fixes: + + - handle file conflicts gracefully in `bundle gem` (@rafaelfranca, @segiddins) + - bundler will fail gracefully when the bundle path contains the system path separator ([#5485](https://github.com/rubygems/bundler/issues/5485), ajwann) + - failed gem downloads will be retried consistently across different RubyGems versions (@shayonj) + - `bundle pristine` will respect build options while re-building native extensions (@NickLaMuro) + +# 1.15.3 (July 21, 2017) + +## Bug fixes: + + - ensure that empty strings passed to `bundle config` are serialized & parsed properly ([#5881](https://github.com/rubygems/bundler/issues/5881), @segiddins) + - avoid printing an outdated version warning when running a parseable command (@segiddins) + +# 1.15.2 (July 17, 2017) + +## Features: + + - new gemfiles created by bundler will include an explicit `github` git source that uses `https` (@segiddins) + +## Bug fixes: + + - inline gemfiles work when `BUNDLE_BIN` is set ([#5847](https://github.com/rubygems/bundler/issues/5847), @segiddins) + - avoid using the old dependency API when there are no changes to the compact index files ([#5373](https://github.com/rubygems/bundler/issues/5373), @greysteil) + - fail gracefully when the full index serves gemspecs with invalid dependencies ([#5797](https://github.com/rubygems/bundler/issues/5797), @segiddins) + - support installing gemfiles that use `eval_gemfile`, `:path` gems with relative paths, and `--deployment` simultaneously (@NickLaMuro) + - `bundle config` will print settings as the type they are interpreted as (@segiddins) + - respect the `no_proxy` environment variable when making network requests ([#5781](https://github.com/rubygems/bundler/issues/5781), @jakauppila) + - commands invoked with `--verbose` will not have default flags printed (@segiddins) + - allow `bundle viz` to work when another gem has a requirable `grapviz` file ([#5707](https://github.com/rubygems/bundler/issues/5707), @segiddins) + - ensure bundler puts activated gems on the `$LOAD_PATH` in a consistent order ([#5696](https://github.com/rubygems/bundler/issues/5696), @segiddins) + +# 1.15.1 (June 2, 2017) + +## Bug fixes: + + - `bundle lock --update GEM` will fail gracefully when the gem is not in the lockfile ([#5693](https://github.com/rubygems/bundler/issues/5693), @segiddins) + - `bundle init --gemspec` will fail gracefully when the gemspec is invalid (@colby-swandale) + - `bundle install --force` works when the gemfile contains git gems ([#5678](https://github.com/rubygems/bundler/issues/5678), @segiddins) + - `bundle env` will print well-formed markdown when there are no settings ([#5677](https://github.com/rubygems/bundler/issues/5677), @segiddins) + +# 1.15.0 (May 19, 2017) + + No changes. + +# 1.15.0.pre.4 (May 10, 2017) + +## Bug fixes: + + - avoid conflicts when `Gem.finish_resolve` is called after the bundle has been set up (@segiddins) + - ensure that `Gem::Specification.find_by_name` always returns an object that can have `#to_spec` called on it ([#5592](https://github.com/rubygems/bundler/issues/5592), @jules2689) + +# 1.15.0.pre.3 (April 30, 2017) + +## Bug fixes: + + - avoid redundant blank lines in the readme generated by `bundle gem` (@koic) + - ensure that `open-uri` is not loaded after `bundle exec` (@segiddins) + - print a helpful error message when an activated default gem conflicts with + a gem in the gemfile (@segiddins) + - only shorten `ref` option for git gems when it is a SHA ([#5620](https://github.com/rubygems/bundler/issues/5620), @segiddins) + +# 1.15.0.pre.2 (April 23, 2017) + +## Bug fixes: + + - ensure pre-existing fit caches are updated from remote sources ([#5423](https://github.com/rubygems/bundler/issues/5423), @alextaylor000) + - avoid duplicating specs in the lockfile after updating with the gem uninstalled ([#5599](https://github.com/rubygems/bundler/issues/5599), @segiddins) + - ensure git gems have their extensions available at runtime ([#5594](https://github.com/rubygems/bundler/issues/5594), @jules2689, @segiddins) + +# 1.15.0.pre.1 (April 16, 2017) + +## Features: + + - print a notification when a newer version of bundler is available ([#4683](https://github.com/rubygems/bundler/issues/4683), @segiddins) + - add man pages for all bundler commands ([#4988](https://github.com/rubygems/bundler/issues/4988), @feministy) + - add the `bundle info` command (@fredrb, @colby-swandale) + - all files created with `bundle gem` comply with the bundler style guide (@zachahn) + - if installing a gem fails, print out the reason the gem needed to be installed ([#5078](https://github.com/rubygems/bundler/issues/5078), @segiddins) + - allow setting `gem.push_key` to set the key used when running `rake release` (@DTrierweiler) + - print gem versions that are regressing during `bundle update` in yellow ([#5506](https://github.com/rubygems/bundler/issues/5506), @brchristian) + - avoid printing extraneous dependencies when the resolver encounters a conflict (@segiddins) + - add the `bundle issue` command that prints instructions for reporting issues ([#4871](https://github.com/rubygems/bundler/issues/4871), @jonathanpike) + - add `--source` and `--group` options to the `bundle inject` command ([#5452](https://github.com/rubygems/bundler/issues/5452), @Shekharrajak) + - add the `bundle add` command to add a gem to the gemfile (@denniss) + - add the `bundle pristine` command to re-install gems from cached `.gem` files ([#4509](https://github.com/rubygems/bundler/issues/4509), @denniss) + - add a `--parseable` option for `bundle config` (@JuanitoFatas, @colby-swandale) + +## Performance: + + - speed up gemfile initialization by storing locked dependencies as a hash (@jules2689) + - speed up gemfile initialization by making locked dependency comparison lazy, avoiding object allocation (@jules2689) + - only validate git gems when they are downloaded, instead of every time `Bundler.setup` is run (@segiddins) + - avoid regenerating the lockfile when nothing has changed (@segiddins) + - avoid diffing large arrays when no sources in the gemfile have changed (@segiddins) + - avoid evaluating full gemspecs when running with RubyGems 2.5+ (@segiddins) + +## Bug fixes: + + - fix cases where `bundle update` would print a resolver conflict instead of updating the selected gems ([#5031](https://github.com/rubygems/bundler/issues/5031), [#5095](https://github.com/bundler/bundler/issues/5095), @segiddins) + - print out a stack trace after an interrupt when running in debug mode (@segiddins) + - print out when bundler starts fetching a gem from a remote server (@segiddins) + - fix `bundle gem` failing when `git` is unavailable ([#5458](https://github.com/rubygems/bundler/issues/5458), @Shekharrajak, @colby-swandale) + - suggest the appropriate command to unfreeze a bundle ([#5009](https://github.com/rubygems/bundler/issues/5009), @denniss) + - ensure nested calls to `bundle exec` resolve default gems correctly ([#5500](https://github.com/rubygems/bundler/issues/5500), @segiddins) + - ensure that a plugin failing to install doesn't uninstall other plugins (@kerrizor, @roseaboveit) + - ensure `socket` is required before being referenced ([#5533](https://github.com/rubygems/bundler/issues/5533), @rafaelfranca) + - allow running `bundle outdated` when gems aren't installed locally ([#5553](https://github.com/rubygems/bundler/issues/5553), @segiddins) + - print a helpful error when `bundle exec`ing to a gem that isn't included in the bundle ([#5487](https://github.com/rubygems/bundler/issues/5487), @segiddins) + - print an error message when a non-git gem is given a `branch` option ([#5530](https://github.com/rubygems/bundler/issues/5530), @colby-swandale) + - allow interrupts to exit the process after gems have been installed (@segiddins) + - print the underlying error when downloading gem metadata fails ([#5579](https://github.com/rubygems/bundler/issues/5579), @segiddins) + - avoid deadlocking when installing with a lockfile that is missing dependencies ([#5378](https://github.com/rubygems/bundler/issues/5378), [#5480](https://github.com/bundler/bundler/issues/5480), [#5519](https://github.com/bundler/bundler/issues/5519), [#5526](https://github.com/bundler/bundler/issues/5526), [#5529](https://github.com/bundler/bundler/issues/5529), [#5549](https://github.com/bundler/bundler/issues/5549), [#5572](https://github.com/bundler/bundler/issues/5572), @segiddins) + +# 1.14.6 (March 3, 2017) + +## Bug fixes: + + - avoid undefined constant `Bundler::Plugin::API::Source` exception ([#5409](https://github.com/rubygems/bundler/issues/5409), @segiddins) + - avoid incorrect warnings about needing to enable `specific_platform` (@segiddins) + - fail gracefully when the compact index does not send an ETag ([#5463](https://github.com/rubygems/bundler/issues/5463), @olleolleolle) + - ensure `bundle outdated --local` shows all outdated gems ([#5430](https://github.com/rubygems/bundler/issues/5430), @denniss) + - fix a case where ruby version requirements could lead to incorrect resolver conflicts ([#5425](https://github.com/rubygems/bundler/issues/5425), @segiddins) + +# 1.14.5 (February 22, 2017) + +## Bug fixes: + + - avoid loading all unused gemspecs during `bundle exec` on RubyGems 2.3+ (@segiddins) + - improve resolver performance when dependencies have zero or one total possibilities ignoring requirements ([#5444](https://github.com/rubygems/bundler/issues/5444), [#5457](https://github.com/bundler/bundler/issues/5457), @segiddins) + - enable compact index when OpenSSL FIPS mode is enabled but not active ([#5433](https://github.com/rubygems/bundler/issues/5433), @wjordan) + - use github username instead of git name for the github url in `bundle gem` ([#5438](https://github.com/rubygems/bundler/issues/5438), @danielpclark) + - avoid a TypeError on RubyGems 2.6.8 when no build settings are set for native extensions (@okkez) + - fail gracefully when the dependency api is missing runtime dependencies for a gem (@segiddins) + - handle when a platform-specific gem has more dependencies than the ruby platform version ([#5339](https://github.com/rubygems/bundler/issues/5339), [#5426](https://github.com/bundler/bundler/issues/5426), @segiddins) + - allow running bundler on a machine with no home directory where the temporary directory is not writable ([#5371](https://github.com/rubygems/bundler/issues/5371), @segiddins) + - avoid gem version conflicts on openssl using Ruby 2.5 ([#5235](https://github.com/rubygems/bundler/issues/5235), @rhenium) + - fail when installing in frozen mode and the dependencies for `gemspec` gems have changed without the lockfile being updated ([#5264](https://github.com/rubygems/bundler/issues/5264), @segiddins) + +# 1.14.4 (February 12, 2017) + +## Bug fixes: + + - fail gracefully when attempting to overwrite an existing directory with `bundle gem` ([#5358](https://github.com/rubygems/bundler/issues/5358), @nodo) + - fix a resolver bug that would cause bundler to report conflicts that it could resolve ([#5359](https://github.com/rubygems/bundler/issues/5359), [#5362](https://github.com/bundler/bundler/issues/5362), @segiddins) + - set native extension build arguments for git gems ([#5401](https://github.com/rubygems/bundler/issues/5401), @segiddins) + - fix the suggested `bundle lock` command printed when a dependency is unused on any platform (@5t111111) + - ensure the version passed to `ruby` in the Gemfile is valid during Gemfile parsing ([#5380](https://github.com/rubygems/bundler/issues/5380), @segiddins) + - show `bundle inject` usage when too many arguments are passed ([#5384](https://github.com/rubygems/bundler/issues/5384), @Shekharrajak) + - stop `bundle show --outdated` from implicitly running `bundle update` ([#5375](https://github.com/rubygems/bundler/issues/5375), @colby-swandale) + - allow the temporary home directory fallback to work for multiple users (@svoop) + +# 1.14.3 (January 24, 2017) + +## Bug fixes: + + - fix the resolver attempting to activate ruby-platform gems when the bundle is only for other platforms ([#5349](https://github.com/rubygems/bundler/issues/5349), [#5356](https://github.com/bundler/bundler/issues/5356), @segiddins) + - avoid re-resolving a locked gemfile that uses `gemspec` and includes development dependencies ([#5349](https://github.com/rubygems/bundler/issues/5349), @segiddins) + +# 1.14.2 (January 22, 2017) + +## Bug fixes: + + - fix using `force_ruby_platform` on windows ([#5344](https://github.com/rubygems/bundler/issues/5344), @segiddins) + - fix an incorrect version conflict error when using `gemspec` on multiple platforms ([#5340](https://github.com/rubygems/bundler/issues/5340), @segiddins) + +# 1.14.1 (January 21, 2017) + +## Bug fixes: + + - work around a ruby 2.2.2 bug that caused a stack consistency error during installation ([#5342](https://github.com/rubygems/bundler/issues/5342), @segiddins) + +# 1.14.0 (January 20, 2017) + +## Bug fixes: + + - ensure `Settings::Mirror` is autoloaded under the `Settings` namespace + ([#5238](https://github.com/rubygems/bundler/issues/5238), @segiddins) + - fix `bundler/inline` when `BUNDLE_GEMFILE=""` ([#5079](https://github.com/rubygems/bundler/issues/5079), @segiddins) + +# 1.14.0.pre.2 (January 11, 2017) + +## Bug fixes: + + - allow not selecting a gem when running `bundle open` ([#5301](https://github.com/rubygems/bundler/issues/5301), @segiddins) + - support installing gems from git branches that contain shell metacharacters ([#5295](https://github.com/rubygems/bundler/issues/5295), @segiddins) + - fix a resolver error that could leave dependencies unresolved ([#5294](https://github.com/rubygems/bundler/issues/5294), @segiddins) + - fix a stack overflow error when invoking commands ([#5296](https://github.com/rubygems/bundler/issues/5296), @segiddins) + +# 1.14.0.pre.1 (December 29, 2016) + +## Features: + + - `bundle doctor` first runs `bundle check` (@segiddins) + - the bundler trampoline is automatically enabled when the target version is greater than bundler 2 (@segiddins) + - gem checksums returned by rubygems.org are validated when installing gems ([#4464](https://github.com/rubygems/bundler/issues/4464), @segiddins) + - use the git username as a github username when running `bundle gem` (@JuanitoFatas) + - show more context when the resolver conflicts on required ruby and rubygems versions (@segiddins) + - improve platform support by allowing bundler to pick the best platform match during dependency resolution, enabled with the `specific_platform` setting ([#4295](https://github.com/rubygems/bundler/issues/4295), [#4896](https://github.com/bundler/bundler/issues/4896), @segiddins) + - always prompt the user for a password when using `sudo` ([#3006](https://github.com/rubygems/bundler/issues/3006), @segiddins) + - support running without a home directory ([#4778](https://github.com/rubygems/bundler/issues/4778), @segiddins) + - print a warning when the gemfile uses a platform conditional that will exclude the gem from all lockfile platforms (@segiddins) + - add the `force_ruby_platform` setting to force bundler to install ruby-platform gems, even on other platforms ([#4813](https://github.com/rubygems/bundler/issues/4813), @segiddins) + - add conservative update options to `bundle lock` ([#4912](https://github.com/rubygems/bundler/issues/4912), @chrismo) + - improve `bundle outdated` output to group gems by group (@ryanfox1985) + - add conservative update options to `bundle update` ([#5065](https://github.com/rubygems/bundler/issues/5065), [#5076](https://github.com/bundler/bundler/issues/5076), @chrismo) + - print the output of `bundle env` as github-flavored markdown, making it easier to preserve formatting when copy-pasting into a new issue (@segiddins) + - configure the persistence file when using `bundle gem` with `rspec` (@segiddins) + - add support for the `ruby_25` gemfile filter (@amatsuda) + - when installing with a lockfile that is missing dependencies, allow installation to proceed (but without parallelism) (@segiddins) + +## Performance: + + - improve `require "bundler"` performance by ~5x (@segiddins) + - allow install gems in parallel when running on rubygems 2+ + +## Bug fixes: + + - config files with CRLF line endings can be read ([#4435](https://github.com/rubygems/bundler/issues/4435), @segiddins) + - `bundle lock` activates gems for the current platform even if they were activated under a different platform for a separate dependency ([#4896](https://github.com/rubygems/bundler/issues/4896), @segiddins) + - running `bundle env` in a directory without a gemfile no longer crashes (@segiddins) + - fail gracefully when attempting to use a source with an unknown URI scheme ([#4953](https://github.com/rubygems/bundler/issues/4953), @segiddins) + - store paths in the lockfile relative to the root gemfile directory when using `eval_gemfile` ([#4966](https://github.com/rubygems/bundler/issues/4966), @segiddins) + - `bundle lock` will not update without the `--update` flag ([#4957](https://github.com/rubygems/bundler/issues/4957), @segiddins) + - the `console` binstub generated by `bundle gem` will load `.irbrc` files (@mattbrictson) + - print friendly filesystem access errors in the new index (@segiddins) + - print a helpful error when running out of memory on jruby ([#4673](https://github.com/rubygems/bundler/issues/4673), @segiddins) + - load all rubygems plugins when installing gems ([#2824](https://github.com/rubygems/bundler/issues/2824), @segiddins) + - `bundle clean --dry-run` prints the list of gems without the `--force` option when no path is set ([#5027](https://github.com/rubygems/bundler/issues/5027), @hmistry) + - local installs no longer print "this gem may have been yanked" ([#5022](https://github.com/rubygems/bundler/issues/5022), @hmistry) + - avoid leaking `which` output when running `bundle doctor` (@colby-swandale) + - print a warning when attempting to `bundle exec` an empty program ([#5084](https://github.com/rubygems/bundler/issues/5084), @bronzdoc) + - ensure `bundle outdated` lists all outdated gems ([#4979](https://github.com/rubygems/bundler/issues/4979), @chrismo) + - fail gracefully when attempting to `bundle gem` with an invalid constant name ([#5185](https://github.com/rubygems/bundler/issues/5185), @segiddins) + - allow `bundler/inline` to work in a directory that contains a gemfile ([#5117](https://github.com/rubygems/bundler/issues/5117), @colby-swandale) + - ensure that the new index is thread-safe, allowing installation on rbx ([#5142](https://github.com/rubygems/bundler/issues/5142), @segiddins) + - remove deprecated `rspec` syntax in `bundle gem` output (@gearnode) + - fail gracefully when any system error is encountered when touching the filesystem ([#5134](https://github.com/rubygems/bundler/issues/5134), @segiddins) + - fix compatibility with a machine running with FIPS mode enabled ([#4989](https://github.com/rubygems/bundler/issues/4989), @segiddins) + - fix `bundle lock --add-platform ruby` ([#5230](https://github.com/rubygems/bundler/issues/5230), @segiddins) + - print gem post-install messages when running `bundle update` (@smathy) + - ensure errors due to a retries are all separated by a newline (@segiddins) + - print out the bundle path in gem not found errors ([#4854](https://github.com/rubygems/bundler/issues/4854), @diegosteiner) + - fail gracefully when creating threads fails (@segiddins) + - avoid downloading metadata for gems that are only development dependencies (@Paxa) + +# 1.13.7 (December 25, 2016) + +## Features: + + - add support for the `ruby_24` gemfile filter ([#5281](https://github.com/rubygems/bundler/issues/5281), @amatsuda) + +# 1.13.6 (October 22, 2016) + +## Bug fixes: + + - make the `gem` method public again, fixing a regression in 1.13.4 ([#5102](https://github.com/rubygems/bundler/issues/5102), @segiddins) + +# 1.13.5 (October 15, 2016) + +## Bug fixes: + + - Ensure a locked pre-release spec can always be re-resolved ([#5089](https://github.com/rubygems/bundler/issues/5089), @segiddins) + +# 1.13.4 (October 11, 2016) + +## Bug fixes: + + - stop printing warning when compact index versions file is rewritten ([#5064](https://github.com/rubygems/bundler/issues/5064), @indirect) + - fix `parent directory is world writable but not sticky` error on install ([#5043](https://github.com/rubygems/bundler/issues/5043), @indirect) + - fix for `uninitialized constant Bundler::Plugin::API::Source` error ([#5010](https://github.com/rubygems/bundler/issues/5010), @hsbt, @aycabta) + - make `update` options for major, minor, and patch updates consistent ([#4934](https://github.com/rubygems/bundler/issues/4934), @chrismo) + +# 1.13.3 (October 10, 2016) + +## Bug fixes: + + - add support for weak etags to the new index (@segiddins) + +# 1.13.2 (September 30, 2016) + +## Bug fixes: + + - allow `Settings` to be initialized without a root directory (@m1k3) + - allow specifying ruby engines in the gemfile as a symbol ([#4919](https://github.com/rubygems/bundler/issues/4919), @JuanitoFatas) + - avoid an exception when using `bundler/deployment` with Vlad (@srbaker) + - ensure redefined methods have the same visibility as the one they're replacing, fixing `Kernel.require` failing on JRuby ([#4975](https://github.com/rubygems/bundler/issues/4975), @segiddins) + - ensure that Bundler won't complain about a corrupt lockfile when no lockfile exists when using `gemspec` in the Gemfile ([#5006](https://github.com/rubygems/bundler/issues/5006), @segiddins) + - fail gracefully when parsing the metadata for a gemspec from the compact index fails (@segiddins) + - fix system gems not being copied to --path on bundle install (e.g. --deployment) ([#4974](https://github.com/rubygems/bundler/issues/4974), @chrismo) + +## Performance: + + - avoid parsing the lockfile twice when evaluating gemfiles (@segiddins) + +# 1.13.1 (September 13, 2016) + +## Bug fixes: + + - ensure that `Gem::Source` is available, fixing several exceptions ([#4944](https://github.com/rubygems/bundler/issues/4944), @dekellum) + - ensure that dependency resolution works when multiple gems have the same dependency ([#4961](https://github.com/rubygems/bundler/issues/4961), @segiddins) + +# 1.13.0 (September 5, 2016) + + No changes. + +# 1.13.0.rc.2 (August 21, 2016) + +## Features: + + - add setting `exec_disable_load` to force `exec` to spawn a new Ruby process (@segiddins) + - add `doctor` command to help with issues like unlinked compiled gems ([#4765](https://github.com/rubygems/bundler/issues/4765), @mistydemeo) + - rework the `update` command, providing fine-grained control via flags ([#4676](https://github.com/rubygems/bundler/issues/4676), @chrismo) + - add URI to http response output in debug mode ([#4808](https://github.com/rubygems/bundler/issues/4808), @NickLaMuro) + - add manpage for `binstubs` command ([#4847](https://github.com/rubygems/bundler/issues/4847), @Zorbash) + - support `mirror` settings for sources by hostname, not only full URL (@opiethehokie) + - print gem installation errors after other install output ([#4834](https://github.com/rubygems/bundler/issues/4834), @segiddins) + - add `lock --remove-platform` flag to remove platforms from the lock ([#4877](https://github.com/rubygems/bundler/issues/4877), @segiddins) + - add `only_update_to_newer_versions` setting to prevent downgrades during `update` (@segiddins) + - expanded experimental plugin support to include hooks and sources (@asutoshpalai) + +## Bug fixes: + + - retry gem downloads ([#4846](https://github.com/rubygems/bundler/issues/4846), @jkeiser) + - improve the CompactIndex to handle capitalized legacy gems ([#4867](https://github.com/rubygems/bundler/issues/4867), @segiddins) + - reuse persistent HTTP connections for CompactIndex (@NickLaMuro) + - respect `required_ruby_version` when Gemfile contains `ruby` version (@indirect) + - allow `rake release` to sign git tags ([#4743](https://github.com/rubygems/bundler/issues/4743), @eagletmt) + - set process titles when using `#load` during `exec` (@yob) + - recognize JRuby shebangs for using `#load` during `exec` (@ojab) + - handle world-writable home directories ([#4726](https://github.com/rubygems/bundler/issues/4726), @allenzhao) + - support multi-platform gems via the `gemspec` Gemfile method ([#4798](https://github.com/rubygems/bundler/issues/4798), @segiddins) + - print dots correctly for CompactIndex fetcher (@NickLaMuro) + - set an `open_timeout` when requesting gem data via HTTP (@NickLaMuro) + - rename the BUNDLE\_ORIG\_ENV variable so it no longer shows up in `config` (@indirect) + - show help only when `-h` or `--help` is passed to Bundler, not to `exec` ([#4801](https://github.com/rubygems/bundler/issues/4801), @segiddins) + - handle symlinks to binstubs created by `--standalone` ([#4782](https://github.com/rubygems/bundler/issues/4782), @terinjokes) + +# 1.13.0.rc.1 (June 27, 2016) + +## Features: + + - when `bundle config major_deprecations` or `BUNDLE_MAJOR_DEPRECATIONS` is set, deprecation warnings for bundler 2 will be printed (@segiddins) + - when running with `--verbose`, bundler will print the reason it is re-resolving a gemfile (@segiddins) + +## Bug fixes: + + - fix support for running RubyGems 1.x on Ruby 2.3 ([#4698](https://github.com/rubygems/bundler/issues/4698), @segiddins) + - fix bundle exec'ing to a ruby file when gems are installed into a path ([#4592](https://github.com/rubygems/bundler/issues/4592), @chrismo) + - when multiple specs in a bundle have the same executable, prefer activating the one from the requested gem ([#4705](https://github.com/rubygems/bundler/issues/4705), @segiddins) + - stop changing the load path to require the vendored postit when trampolining (@segiddins) + - ensure relative paths are properly printed after completing an installation (@jenseng) + - fix re-resolving when there are multiple unchanged path sources (@segiddins) + - de-init submodules when running git 2.9 and requesting a git gem without submodules (@segiddins) + +# 1.13.0.pre.1 (June 20, 2016) + +## Performance: + + - speed up gemfile resolution during `bundle install` by between 4x-100x ([#4376](https://github.com/rubygems/bundler/issues/4376), @segiddins) + - generally reduce object allocations when using bundler (@segiddins) + - speed up bin generation for path gems with many files ([#2846](https://github.com/rubygems/bundler/issues/2846), @segiddins) + - fix detecting path spec changes to avoid re-resolving unnecessarily (@jrafanie) + +## Features: + + - automatically trampoline to the bundler version locked in the lockfile, only updating to the running version on `bundle update --bundler` (@segiddins) + - laying the groundwork for plugin support, which is currently unsuppported, undocumented, disabled by default, and liable to change without notice (@asutoshpalai) + - allow `bundle viz --without` to accept multiple `:`-delimited groups (@mobilutz) + - support for RubyGems 2.6.4 ([#4368](https://github.com/rubygems/bundler/issues/4368), @segiddins, @RochesterinNYC) + - colorize updated gem versions ([#4334](https://github.com/rubygems/bundler/issues/4334), @bronzdoc) + - add the `--standalone` flag to `bundle binstubs` ([#4594](https://github.com/rubygems/bundler/issues/4594), @b-ggs) + - update the `bundle gem` CoC to contributor covenant v1.4 (@cllns) + - use a custom YAML serializer to make config file consistent (@segiddins) + - filter credentials from error messages (bundler/bundler-features[#111](https://github.com/rubygems/bundler/issues/111), @RochesterinNYC, @sandlerr) + - support relative paths used inside a nested invocation of `eval_gemfile` ([#4584](https://github.com/rubygems/bundler/issues/4584), @RochesterinNYC) + - fail gracefully when attempting to install a yanked gem ([#4344](https://github.com/rubygems/bundler/issues/4344), @allenzhao) + - automatically install an inline gemfile when gems are missing locally (@segiddins) + - allow conflicts for gems resolved via `gemspec` (@segiddins) + - add `--add-platform` option to `bundle lock` (@segiddins) + - fail gracefully when a resolved spec's `required_ruby_version` or `required_rubygems_version` is incompatible (@segiddins) + +## Bug fixes: + + - implicitly unlock the resolved ruby version when the declared requirements in the gemfile are incompatible with the locked version ([#4595](https://github.com/rubygems/bundler/issues/4595), [#4627](https://github.com/bundler/bundler/issues/4627), @segiddins) + - add support for quoted paths in `$PATH` ([#4323](https://github.com/rubygems/bundler/issues/4323), @segiddins) + - check out missing git repos that are not being installed ([#3981](https://github.com/rubygems/bundler/issues/3981), @asutoshpalai) + - write `bundler/setup.rb` to a consistent path (@glennpratt) + - open editor in `bundle open` with a clean environment (@sj26) + - resolve infinitely recursive copy when running `bundle package --all` with a `gemspec` in the gemfile ([#4392](https://github.com/rubygems/bundler/issues/4392), [#4430](https://github.com/bundler/bundler/issues/4430), @RochesterinNYC) + - fail gracefully when encountering an `Errno::ENOTSUP` ([#4394](https://github.com/rubygems/bundler/issues/4394), @segiddins) + - fail gracefully when encountering an `Errno::EHOSTUNREACH` ([#4642](https://github.com/rubygems/bundler/issues/4642), @allenzhao) + - fix loading config files with very long values ([#4370](https://github.com/rubygems/bundler/issues/4370), @segiddins) + - only show potential updates for gemfile platforms in `bundle outdated` ([#4450](https://github.com/rubygems/bundler/issues/4450), @RochesterinNYC) + - allow running `bundle install --deployment` after `bundle package --all` with path gems ([#2175](https://github.com/rubygems/bundler/issues/2175), @allenzhao) + - add support for patchlevels in ruby versions in the gemfile and gemspecs ([#4593](https://github.com/rubygems/bundler/issues/4593), @chalkos) + +# 1.12.6 (October 10, 2016) + +## Bug fixes: + - add support for weak etags to the new index (@segiddins) + +# 1.12.5 (May 25, 2016) + +## Bug fixes: + - only take over `--help` on `bundle exec` when the first two arguments are `exec` and `--help` ([#4596](https://github.com/rubygems/bundler/issues/4596), @segiddins) + - don't require `require: true` dependencies that are excluded via `env` or `install_if` (@BrianHawley) + - reduce the number of threads used simultaneously by bundler ([#4367](https://github.com/rubygems/bundler/issues/4367), @will-in-wi) + +# 1.12.4 (May 16, 2016) + +## Bug fixes: + - ensure concurrent use of the new index can't corrupt the cache ([#4519](https://github.com/rubygems/bundler/issues/4519), @domcleal) + - allow missing rubygems credentials when pushing a gem with a custom host ([#4437](https://github.com/rubygems/bundler/issues/4437), @Cohen-Carlisle) + - fix installing built-in specs with `--standalone` ([#4557](https://github.com/rubygems/bundler/issues/4557), @segiddins) + - fix `bundle show` when a gem has a prerelease version that includes a `-` ([#4385](https://github.com/rubygems/bundler/issues/4385), @segiddins) + +# 1.12.3 (May 6, 2016) + +## Bug fixes: + - fix uncoditionally writing `.bundle/config` when running `bundle install` (@segiddins) + - fall back to the dependency API and the full index when the home directory is not writable (@segiddins) + +# 1.12.2 (May 4, 2016) + +## Bug fixes: + - fix modifying a frozen string when the resolver conflicts on dependencies with requirements ([#4520](https://github.com/rubygems/bundler/issues/4520), @grzuy) + - fix `bundle exec foo --help` not showing the invoked command's help ([#4480](https://github.com/rubygems/bundler/issues/4480), @b-ggs) + +# 1.12.1 (April 30, 2016) + +## Bug fixes: + - automatically fallback when the new index has a checksum mismatch instead of erroring (@segiddins) + - fix computation of new index file local checksums on Windows ([#4472](https://github.com/rubygems/bundler/issues/4472), @mwrock) + - properly handle certain resolver backtracking cases without erroring (@segiddins, [#4484](https://github.com/rubygems/bundler/issues/4484)) + - ensure the `$LOAD_PATH` contains specs' load paths in the correct order (@segiddins, [#4482](https://github.com/rubygems/bundler/issues/4482)) + +# 1.12.0 (April 28, 2016) + + No changes. + +# 1.12.0.rc.4 (April 21, 2016) + +## Bug fixes: + + - don't fail when `bundle outdated` is run with flags and the lockfile contains non-semver versions ([#4438](https://github.com/rubygems/bundler/issues/4438), @RochesterinNYC) + +# 1.12.0.rc.3 (April 19, 2016) + +## Bug fixes: + + - don't allow new attributes to dirty a lockfile when running `bundle exec`, `-rbundler/setup`, or `bundle check` (@segiddins) + +# 1.12.0.rc.2 (April 15, 2016) + +## Features: + + - `bundle outdated` handles all combinations of `--major`, `--minor`, and `--patch` ([#4396](https://github.com/rubygems/bundler/issues/4396), @RochesterinNYC) + +## Bug fixes: + + - prevent endless recursive copy for `bundle package --all` ([#4392](https://github.com/rubygems/bundler/issues/4392), @RochesterinNYC) + - allow executables that are `load`ed to exit non-0 via an `at_exit` hook when invoked by `bundle exec` (@segiddins) + - nested invocations of `bundle exec` properly preserve the `$PATH` and `$GEM_PATH` environment variables (@segiddins) + +# 1.12.0.rc (March 13, 2016) + +## Performance: + + - Download gem metadata from globally distributed CDN endpoints ([#4358](https://github.com/rubygems/bundler/issues/4358), @segiddins) + +## Bug fixes: + + - handle Ruby pre-releases built from source ([#4324](https://github.com/rubygems/bundler/issues/4324), @RochesterinNYC) + - support binstubs from RubyGems 2.6 ([#4341](https://github.com/rubygems/bundler/issues/4341), @segiddins) + - handle quotes present in in PATH ([#4326](https://github.com/rubygems/bundler/issues/4326), @segiddins) + +# 1.12.0.pre.2 (February 26, 2016) + +## Performance: + + - speed up `bundle exec` by `load`ing the executable whenever possible, saving roughly .2 seconds per invocation (@segiddins) + +## Features: + + - add a `--patch` flag for `bundle outdated` (@RochesterinNYC) + - add `Bundler.clean_env` and `Bundler.original_env` ([#4232](https://github.com/rubygems/bundler/issues/4232), @njam) + - add `--frozen` support to `bundle package` ([#3356](https://github.com/rubygems/bundler/issues/3356), @RochesterinNYC) + +## Bug fixes: + + - place bundler loaded gems after `-I` and `RUBYLIB` (@Elffers) + - give a better error message when filesystem access raises an `EPROTO` error ([#3581](https://github.com/rubygems/bundler/issues/3581), [#3932](https://github.com/bundler/bundler/issues/3932), [#4163](https://github.com/bundler/bundler/issues/4163), @RochesterinNYC) + - give a better error message when both `--deployment` and `--system` are used together (@RochesterinNYC) + - fix `$PATH` being preserved for use in `Bundler.with_clean_env` ([#4251](https://github.com/rubygems/bundler/issues/4251), @segiddins, @njam) + - give a better error message when running `bundle outdated` in frozen mode ([#4287](https://github.com/rubygems/bundler/issues/4287), @RochesterinNYC) + - handle when `http_proxy` is set to `:no_proxy` in the rubygems configuration ([#4294](https://github.com/rubygems/bundler/issues/4294), @segiddins) + - give a better error message when authentication details aren't properly escaped ([#4288](https://github.com/rubygems/bundler/issues/4288), @RochesterinNYC) + - fix `bundle outdated --minor` to only report updates that match the current minor version (@RochesterinNYC) + - fix extra dependencies being resolved unnecessarily ([#4276](https://github.com/rubygems/bundler/issues/4276), @segiddins) + - give a better error message when missing specs due to platform mis-matches ([#4259](https://github.com/rubygems/bundler/issues/4259), @RochesterinNYC) + - skip rebuilding extensions for git gems if they are already built ([#4082](https://github.com/rubygems/bundler/issues/4082), @csfrancis, @indirect, @segiddins) + - fix `bundle install` not installing when the `no_install` setting is set ([#3966](https://github.com/rubygems/bundler/issues/3966), @chulkilee, @segiddins) + +# 1.12.0.pre.1 (February 9, 2016) + +## Performance: + + - speed up `bundle install` and `bundle update` by using the new compact gem index (@segiddins, @fotanus, @indirect) + - speed up `bundle exec` by avoiding loading the gemfile twice ([#2951](https://github.com/rubygems/bundler/issues/2951), [#2952](https://github.com/bundler/bundler/issues/2952), @segiddins) + +## Features: + + - add support for using version operators to specify ruby versions in the Gemfile (@jtarchie) + - redirect `--help` flag for plugins to that plugin's man page (@RochesterinNYC) + - support probing a mirror with a fallback timeout ([#4128](https://github.com/rubygems/bundler/issues/4128), @pcarranza) + - add `--full-index` option to `bundle lock` (@segiddins) + - support running with frozen string literals (@deepj, @segiddins) + - add `--major` and `--minor` options to `bundle outdated` ([#3805](https://github.com/rubygems/bundler/issues/3805), @cirdes) + - allow passing a custom `ui` to `bundler/inline` (@lamont-granquist) + - add support for ruby 2.4 ([#4266](https://github.com/rubygems/bundler/issues/4266), @segiddins) + - add `bundle outdated --parseable` for machine-readable output (@RochesterinNYC) + +## Bug fixes: + + - fix `bundle package --all` recursing endlessly ([#4158](https://github.com/rubygems/bundler/issues/4158), @RochesterinNYC) + - fail fast on more errors when fetching remote resources ([#4154](https://github.com/rubygems/bundler/issues/4154), @RochesterinNYC) + - give a better error message when a given git commit can't be found ([#4140](https://github.com/rubygems/bundler/issues/4140), @doy) + - give a better error message when `bundle clean` doesn't have sufficient permissions ([#4170](https://github.com/rubygems/bundler/issues/4170), @RochesterinNYC) + - give a better error message when reading a bundler config file fails (@segiddins) + - restrict platforms when referencing a `gemspec` in the `Gemfile` to those defined in the gemspec ([#4102](https://github.com/rubygems/bundler/issues/4102), [#4150](https://github.com/bundler/bundler/issues/4150), @smellsblue) + - fix `bundle gem` with minitest to use the correct rake task (@kotoshenya) + - give a better error message when ssl isn't available ([#4054](https://github.com/rubygems/bundler/issues/4054), @RochesterinNYC) + - print the original `require` error when `Bundler.require` fails ([#4182](https://github.com/rubygems/bundler/issues/4182), @RochesterinNYC) + - give a better error message when certain resources are temporarily unavailable ([#4183](https://github.com/rubygems/bundler/issues/4183), @RochesterinNYC) + - fix returning case-sensitive gem mirror URIs on ruby 2.3 (@segiddins) + - ignore colorized output from `git` when determining the current branch ([#4056](https://github.com/rubygems/bundler/issues/4056), @agis-) + - fix storing the shared gems config option as a boolean (@vassilevsky) + - add support for running `bundle gem --exe` instead of using the `--bin` option (@christhekeele) + - fix `exec`-ing with 0 args in a directory with spaces ([#4230](https://github.com/rubygems/bundler/issues/4230), @segiddins) + - avoid installing extraneous gems when resolving to an older version of a spec ([#4101](https://github.com/rubygems/bundler/issues/4101), [#4198](https://github.com/bundler/bundler/issues/4198), @segiddins) + - ensure paths resolved when parsing a gemfile are relative to that file ([#3349](https://github.com/rubygems/bundler/issues/3349), @dtognazzini) + - give a better error message when encountering an invalid gemspec ([#4248](https://github.com/rubygems/bundler/issues/4248), [#4275](https://github.com/bundler/bundler/issues/4275), @RochesterinNYC) + - preserve the original `PATH` in `Bundler.with_clean_env` ([#4251](https://github.com/rubygems/bundler/issues/4251), @segiddins) + - ensure standalone file paths are relative to the project root ([#4144](https://github.com/rubygems/bundler/issues/4144), @glennpratt) + +# 1.11.2 (December 15, 2015) + +## Bug fixes: + + - _really_ stop calling `required_ruby_version` on nil @specifications ([#4147](https://github.com/rubygems/bundler/issues/4147), @indirect) + +# 1.11.1 (December 15, 2015) + +## Bug fixes: + + - lazy-load Psych, again ([#4149](https://github.com/rubygems/bundler/issues/4149), @indirect) + - allow gemspec gems on other platforms ([#4150](https://github.com/rubygems/bundler/issues/4150), @indirect) + - fix --no-coc and --no-mit flags on `gem` ([#4148](https://github.com/rubygems/bundler/issues/4148), @RochesterinNYC) + - stop calling `required_ruby_version` on nil @specifications ([#4147](https://github.com/rubygems/bundler/issues/4147), @indirect) + +# 1.11.0 (December 12, 2015) + + No changes. + +# 1.11.0.pre.2 (December 6, 2015) + +## Bug fixes: + + - fail gracefully when trying to execute a non-executable file ([#4081](https://github.com/rubygems/bundler/issues/4081), @fotanus) + - fix a crash when pushing a gem via `rake release` (@segiddins) + +# 1.11.0.pre.1 (November 29, 2015) + +## Features: + + - actual Gemfile and lockfile filenames are used in messages ([#3672](https://github.com/rubygems/bundler/issues/3672), @segiddins) + - the git remote for `rake release` is now customizable (@skateman) + - file access permissions errors are now much more friendly ([#3703](https://github.com/rubygems/bundler/issues/3703), [#3735](https://github.com/bundler/bundler/issues/3735), [#3858](https://github.com/bundler/bundler/issues/3858), [#3988](https://github.com/bundler/bundler/issues/3988), [#4009](https://github.com/bundler/bundler/issues/4009) @repinel, @Elffers, @segiddins, @agis-) + - add support for showing help for plugin commands (@tf) + - send `X-Gemfile-Source` header to source mirrors (@agis-) + - show what version upstream dependencies were resolved to in conflict messages (@segiddins) + - add support for using bundler setting to add private access credentials for git sources (@frsyuki) + - take into consideration HTTP proxy settings in `.gemrc` (@PG-kura) + - allow specifying a gem host to push to in the `GEM_HOST` environment variable (@pmenglund) + - when gempec `required_ruby_version` is available and the Gemfile specifies a ruby version, resolve for the given ruby version (@segiddins) + - allow setting a `silence_root_warning` setting to silence the warning when `bundle install` is run as root (@blackxored) + - update the `bundle gem` code of conduct template to Contributor Covenant v1.3.0 (@CoralineAda) + - add support for specifying gems to update when running `bundle lock` via `--update gem1 gem2` (@JuanitoFatas) + - added support for MRI 2.3 (@amatsuda) + - show a helpful message when requiring a file in `bundler require` fails ([#3960](https://github.com/rubygems/bundler/issues/3960), @agis-) + - include git revision hash when printing a git source ([#3433](https://github.com/rubygems/bundler/issues/3433), @agis-) + - improve hint when a resolution conflict occurs (@seanlinsley) + - show a friendly error when a git ref is not found ([#3879](https://github.com/rubygems/bundler/issues/3879), @agis-) + - improve error message when sources are not absolute URIs ([#3925](https://github.com/rubygems/bundler/issues/3925), @agis-) + - add `pkg` to rake's clobber list ([#3676](https://github.com/rubygems/bundler/issues/3676), @jasonkarns) + - retry fetching specs when fetching version metadata fails (@jingweno) + +## Bug fixes: + + - avoid showing bundler version warning messages twice (@fotanus) + - fix running `bundle check` with `--path` when the gems are only installed globally (@akihiro17) + - fix `bin/setup` from `bundle gem` assuming `bash` is in `/bin` + - fail more gracefully when an HTTP remote is unreachable ([#3765](https://github.com/rubygems/bundler/issues/3765), @steverob) + - fix a warning running `bundle exec` on jruby 9.0.0.0 (@deivid-rodriguez, @mastfish) + - fix the `bundle gem` readme when no tests are generated (@roseweixel) + - the dependencies on test gems in `bundle gem` are now locked to major versions ([#3811](https://github.com/rubygems/bundler/issues/3811), @indirect) + - fix the paths for native extensions generated by `--standalone` ([#3813](https://github.com/rubygems/bundler/issues/3813), @AlexanderPavlenko) + - fix trying to cache a gem that has no source (@EduardoBautista) + - fix `--source` option to `bundle update` causing incorrect gem unlocking ([#3759](https://github.com/rubygems/bundler/issues/3759), [#3761](https://github.com/bundler/bundler/issues/3761), @neoeno) + - fix handling an empty `BUNDLE_GEMFILE` environment variables ([#3678](https://github.com/rubygems/bundler/issues/3678), @agis-) + - avoid cleaning up gem extension directory in `bundle clean` (@Sirupsen) + - fix the `ssl_verify_mode` setting not being treated as a number (@goughy000) + - fix not retrying on zlib errors ([#4047](https://github.com/rubygems/bundler/issues/4047), @andremedeiros) + - fix a warning being shown for using `URI.encode` (@EduardoBautista) + - fix handling of fatal HTTP errors ([#3830](https://github.com/rubygems/bundler/issues/3830), @indirect) + - ensure all `sudo` access is done in a thread-safe manner ([#3910](https://github.com/rubygems/bundler/issues/3910), @agis-) + - fix caching gems with a path with the same prefix as the bundled application (@indirect) + - fix showing gemspec validation errors on `bundle exec` ([#3895](https://github.com/rubygems/bundler/issues/3895), @agis-) + - distinguish Gemfile syntax and evaluation errors ([#3783](https://github.com/rubygems/bundler/issues/3783), @agis-) + - fix nested Gemfile sources not restoring the previous source ([#3974](https://github.com/rubygems/bundler/issues/3974), @agis-) + - fix the `RUBYLIB` environment variable not being cleaned ([#3982](https://github.com/rubygems/bundler/issues/3982), @agis-) + - fix handling a dependency missing from `Gemfile.lock` so parallel installation does not deadlock ([#4012](https://github.com/rubygems/bundler/issues/4012), @lukaso) + - also print gemspecs in `bundle env` output (@agis-) + - fix handling when a `path` source does not have a gemspec but a lockfile says there is ([#4004](https://github.com/rubygems/bundler/issues/4004), @segiddins) + - show a warning when the `RUBYGEMS_GEMDEPS` environment variable is set ([#3656](https://github.com/rubygems/bundler/issues/3656), @agis-) + - fix handling invalid RubyGems configuration files ([#4042](https://github.com/rubygems/bundler/issues/4042), @agis-) + - fix `bundle console` falling back to `irb` when the preferred console is unavailable (@felixbuenemann) + - restrict platforms when referencing a `gemspec` in the `Gemfile` to those defined in the gemspec ([#4102](https://github.com/rubygems/bundler/issues/4102), @smellsblue) + +## Performance: + + - speed up dependency resolution in pathological cases by 25x ([#3803](https://github.com/rubygems/bundler/issues/3803), @segiddins) + - drop string allocations when searching for gems (@jrafanie) + +# 1.10.6 (July 22, 2015) + +## Bug fixes: + + - only warn on invalid gemspecs (@indirect) + - fix installing dependencies in the correct order ([#3799](https://github.com/rubygems/bundler/issues/3799), @pducks32) + - fix sorting of mixed DependencyLists ([#3762](https://github.com/rubygems/bundler/issues/3762), @tony-spataro-rs) + - fix `install_if` conditionals when using the block form (@danieltdt) + +# 1.10.5 (June 24, 2015) + +## Bug fixes: + + - don't add or update BUNDLED WITH during `install` with no changes (@segiddins) + - fix sorting of mixed DependencyLists with RubyGems >= 2.23 ([#3762](https://github.com/rubygems/bundler/issues/3762), @tony-spataro-rs) + - speed up resolver for path and git gems (@segiddins) + - fix `install --force` to not reinstall Bundler ([#3743](https://github.com/rubygems/bundler/issues/3743), @karlo57) + +# 1.10.4 (June 16, 2015) + +## Bug fixes: + + - don't add BUNDLED WITH to the lock when Spring runs `check` over and over (@indirect) + - display "with native extensions" log output correctly (@ivantsepp) + - alias `i` to `install`, `c` to `check`, and `e` to `exec` (@indirect) + +# 1.10.3 (June 3, 2015) + +## Bug fixes: + + - allow missing gemspec files when validating path and git gems ([#3686](https://github.com/rubygems/bundler/issues/3686), [#3698](https://github.com/bundler/bundler/issues/3698), @segiddins) + - fix regression in `rake install` ([#3701](https://github.com/rubygems/bundler/issues/3701), [#3705](https://github.com/bundler/bundler/issues/3705), @segiddins) + - fix regression when calling `gem` with `bundle exec` or `-rbundler/setup` ([#3699](https://github.com/rubygems/bundler/issues/3699), @segiddins) + - fix `bundler/inline` requiring a newly-installed gem ([#3693](https://github.com/rubygems/bundler/issues/3693), @indirect, @segiddins) + +# 1.10.2 (May 29, 2015) + +## Bug fixes: + + - fix regression in `bundle update GEM` performance introduced in 1.10.0 ([#3687](https://github.com/rubygems/bundler/issues/3687), @segiddins) + +# 1.10.1 (May 28, 2015) + +## Bug fixes: + + - silence ruby warning when running CLI commands (@segiddins) + - validate gemspecs in non-packaging mode ([#3681](https://github.com/rubygems/bundler/issues/3681), @segiddins) + - ensure the same chdir mutex as RubyGems is used ([#3680](https://github.com/rubygems/bundler/issues/3680), @segiddins) + +# 1.10.0 (May 28, 2015) + + No changes. + +# 1.10.0.rc (May 16, 2015) + +## Features: + + - dramatically speed up resolving some slow Gemfiles ([#3635](https://github.com/rubygems/bundler/issues/3635), @segiddins) + - track CI platforms running Bundler ([#3646](https://github.com/rubygems/bundler/issues/3646), @fotanus) + +## Bug fixes: + + - allow `viz` to work with prereleases ([#3621](https://github.com/rubygems/bundler/issues/3621), [#3217](https://github.com/bundler/bundler/issues/3217), @aprescott) + - validate gemspecs used in path and git gems ([#3639](https://github.com/rubygems/bundler/issues/3639), @segiddins, @indirect) + - stop printing config warnings when config is unchanged ([#3649](https://github.com/rubygems/bundler/issues/3649), @fotanus, @indirect) + - Without groups saved via `config` are no longer ignored when the `--without` flag is used + +# 1.10.0.pre.2 (May 7, 2015) + +## Bug fixes: + + - make BUNDLED WITH backwards compatible ([#3623](https://github.com/rubygems/bundler/issues/3623), @segiddins) + +# 1.10.0.pre.1 (May 5, 2015) + +## Bug fixes: + + - always clean up tmp dirs ([#3277](https://github.com/rubygems/bundler/issues/3277), @hone, @indirect, @segiddins) + +# 1.10.0.pre (May 3, 2015) + +## Features: + + - support gem extensions built into any directory on RubyGems 2.2+ ([#3582](https://github.com/rubygems/bundler/issues/3582), @voxik) + - add 'bundler/inline' which provides a `gemfile` method ([#3440](https://github.com/rubygems/bundler/issues/3440), @segiddins) + - improved error reports for Gemfile errors ([#3480](https://github.com/rubygems/bundler/issues/3480), @segiddins) + - `lock` command ([#3437](https://github.com/rubygems/bundler/issues/3437), @segiddins) + - add `ignore_messages` config to suppress post-install text ([#3510](https://github.com/rubygems/bundler/issues/3510), @pducks32) + - improve `gem` minitest template ([#3513](https://github.com/rubygems/bundler/issues/3513), [#3515](https://github.com/bundler/bundler/issues/3515), @arthurnn) + - add `install --force` to re-install installed gems ([#3519](https://github.com/rubygems/bundler/issues/3519), @segiddins) + - show more `outdated` information, including groups (@smlance, @indirect) + - add optional groups to the Gemfile ([#3531](https://github.com/rubygems/bundler/issues/3531), @jhass) + - accept glob argument to `gemspec` in Gemfile ([#3464](https://github.com/rubygems/bundler/issues/3464), @pjump) + - make timeouts and retries configurable via `config` ([#3601](https://github.com/rubygems/bundler/issues/3601), @pducks32) + - add `install_if` Gemfile method for conditional installs ([#3611](https://github.com/rubygems/bundler/issues/3611), @segiddins) + +## Bug fixes: + + - standalone mode now uses builtin gems correctly ([#3610](https://github.com/rubygems/bundler/issues/3610), @segiddins) + - fix `rake spec:deps` on MinGW Ruby 2.0+ ([#3487](https://github.com/rubygems/bundler/issues/3487), @marutosi) + - remember all y/n answers when generating gems ([#3579](https://github.com/rubygems/bundler/issues/3579), @pducks32) + +## Performance: + + - use RubyGems stub specifications when possible ([#3580](https://github.com/rubygems/bundler/issues/3580), @segiddins) + +## Deprecations: + + - deprecated the (never enabled) `bundle_ruby` binary (@smlance) + +# 1.9.10 (June 22, 2015) + +## Features: + + - the `BUNDLED WITH` section of lockfiles generated by 1.10+ will be preserved (@segiddins) + +# 1.9.9 (May 16, 2015) + +## Bug fixes: + + - read mirror and credential settings from older versions ([#3557](https://github.com/rubygems/bundler/issues/3557), @Strech) + +# 1.9.8 (May 12, 2015) + +## Bug fixes: + + - fix regression in sudo mode introduced by 1.9.7 ([#3642](https://github.com/rubygems/bundler/issues/3642), @segiddins) + +# 1.9.7 (May 11, 2015) + +## Bug fixes: + + - always clean up tmp dirs ([#3277](https://github.com/rubygems/bundler/issues/3277), @hone, @indirect, @segiddins) + +# 1.9.6 (May 2, 2015) + +## Bug fixes: + + - use RubyGems spec stubs if available (@segiddins) + - allow creating gems with names containing two dashes ([#3483](https://github.com/rubygems/bundler/issues/3483), @janlelis) + - allow creating gems with names extending constants ([#3603](https://github.com/rubygems/bundler/issues/3603), @amatsuda) + +# 1.9.5 (April 29, 2015) + +## Bug fixes: + + - respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +# 1.9.4 (April 13, 2015) + +## Bug fixes: + + - fix regression in installing x86 and universal gems ([#3565](https://github.com/rubygems/bundler/issues/3565), @jdmundrawala) + - improve error when gems are missing ([#3564](https://github.com/rubygems/bundler/issues/3564), @sealocal) + +# 1.9.3 (April 12, 2015) + +## Bug fixes: + + - handle removal of `specs` from rubygems/rubygems@620910 ([#3558](https://github.com/rubygems/bundler/issues/3558), @indirect) + - install 'universal' gems on Windows ([#3066](https://github.com/rubygems/bundler/issues/3066), @jdmundrawala) + - stop passing --local during `rake install` task ([#3236](https://github.com/rubygems/bundler/issues/3236), @indirect) + - guard against all possible accidental public gem pushes ([#3533](https://github.com/rubygems/bundler/issues/3533), @indirect) + +# 1.9.2 (March 30, 2015) + +## Bug fixes: + + - ensure gem executables are executable ([#3517](https://github.com/rubygems/bundler/issues/3517), [#3511](https://github.com/bundler/bundler/issues/3511), @indirect) + - fix warnings in Molinillo ([#3516](https://github.com/rubygems/bundler/issues/3516), @segiddins) + - ensure duplicate dependencies do not propagate ([#3522](https://github.com/rubygems/bundler/issues/3522), @segiddins) + - keep gems locked when updating another gem from the same source ([#3520](https://github.com/rubygems/bundler/issues/3520), @indirect) + - resolve race that could build gems without saved arguments ([#3404](https://github.com/rubygems/bundler/issues/3404), @indirect) + +# 1.9.1 (March 21, 2015) + +## Bug fixes: + + - avoid exception in 'bundler/gem_tasks' ([#3492](https://github.com/rubygems/bundler/issues/3492), @segiddins) + +# 1.9.0 (March 20, 2015) + +# 1.9.0.rc (March 13, 2015) + +## Bug fixes: + + - make Bundler.which stop finding directories (@nohoho) + - handle Bundler prereleases correctly ([#3470](https://github.com/rubygems/bundler/issues/3470), @segiddins) + - add before_install to .travis.yml template for new gems (@kodnin) + +# 1.9.0.pre.1 (March 11, 2015) + +## Bug fixes: + + - make `gem` command work again (@arthurnn) + +# 1.9.0.pre (March 11, 2015) + +## Features: + + - prefer gemspecs closest to the directory root ([#3428](https://github.com/rubygems/bundler/issues/3428), @segiddins) + - debug log for API request limits ([#3452](https://github.com/rubygems/bundler/issues/3452), @neerfri) + +## Enhancements: + + - Molinillo resolver, shared with CocoaPods (@segiddins) + - updated Thor to v0.19.1 (@segiddins) + +# 1.8.9 (May 2, 2015) + +## Bug fixes: + + - Use RubyGems spec stubs if available (@segiddins) + +# 1.8.8 (April 29, 2015) + +## Bug fixes: + + - Respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +# 1.8.7 (April 7, 2015) + +## Bug fixes: + + - stop suppressing errors inside gems that get required ([#3549](https://github.com/rubygems/bundler/issues/3549), @indirect) + +# 1.8.6 (March 30, 2015) + +## Bug fixes: + + - keep gems locked when updating another gem from the same source ([#3250](https://github.com/rubygems/bundler/issues/3250), @indirect) + - resolve race that could build gems without saved arguments ([#3404](https://github.com/rubygems/bundler/issues/3404), @indirect) + +# 1.8.5 (March 11, 2015) + +## Bug fixes: + + - remove MIT license from gemspec when removing license file (@indirect) + - respect 'no' immediately as well as saving it in `gem` config (@kirs) + +# 1.8.4 (March 5, 2015) + +## Bug fixes: + + - document --all-platforms option ([#3449](https://github.com/rubygems/bundler/issues/3449), @moeffju) + - find gems from all sources on exec after install ([#3450](https://github.com/rubygems/bundler/issues/3450), @TimMoore) + +# 1.8.3 (February 24, 2015) + +## Bug fixes: + + - handle boolean values for gem settings (@EduardoBautista) + - stop always looking for updated `path` gems ([#3414](https://github.com/rubygems/bundler/issues/3414), [#3417](https://github.com/bundler/bundler/issues/3417), [#3429](https://github.com/bundler/bundler/issues/3429), @TimMoore) + +# 1.8.2 (February 14, 2015) + +## Bug fixes: + + - allow config settings for gems with 'http' in the name again ([#3398](https://github.com/rubygems/bundler/issues/3398), @TimMoore) + +# 1.8.1 (February 13, 2015) + +## Bug fixes: + + - synchronize building git gem native extensions ([#3385](https://github.com/rubygems/bundler/issues/3385), @antifuchs & @indirect) + - set gemspec bindir correctly ([#3392](https://github.com/rubygems/bundler/issues/3392), @TimMoore) + - request lockfile deletion when it is malformed ([#3396](https://github.com/rubygems/bundler/issues/3396), @indirect) + - explain problem when mirror config is missing ([#3386](https://github.com/rubygems/bundler/issues/3386), @indirect) + - explain problem when caching causes permission error ([#3390](https://github.com/rubygems/bundler/issues/3390), @indirect) + - normalize URLs in config keys ([#3391](https://github.com/rubygems/bundler/issues/3391), @indirect) + +# 1.8.0 (February 10, 2015) + +## Bug fixes: + + - gemfile `github` blocks now work ([#3379](https://github.com/rubygems/bundler/issues/3379), @indirect) + - look up installed gems in remote sources ([#3300](https://github.com/rubygems/bundler/issues/3300), [#3368](https://github.com/bundler/bundler/issues/3368), [#3377](https://github.com/bundler/bundler/issues/3377), [#3380](https://github.com/bundler/bundler/issues/3380), [#3381](https://github.com/bundler/bundler/issues/3381), @indirect) + - look up gems across all sources to satisfy dependencies ([#3365](https://github.com/rubygems/bundler/issues/3365), @keiths-osc) + - request dependencies for no more than 100 gems at a time ([#3367](https://github.com/rubygems/bundler/issues/3367), @segiddins) + +# 1.8.0.rc (January 26, 2015) + +## Features: + + - add `config disable_multisource` option to ensure sources can't compete (@indirect) + +## Bug fixes: + + - don't add extra quotes around long, quoted config values (@aroben, [#3338](https://github.com/rubygems/bundler/issues/3338)) + +## Security fixes: + + - warn when more than one top-level source is present (@indirect) + +# 1.8.0.pre (January 26, 2015) + +## Features: + + - add metadata allowed_push_host to new gem template ([#3002](https://github.com/rubygems/bundler/issues/3002), @juanitofatas) + - adds a `--no-install` flag to `bundle package` (@d-reinhold) + - add `bundle config auto_install true` to install automatically (@smashwilson) + - add `bundle viz --without` to exclude gem groups from resulting graph (@fnichol) + - prevent whitespace in gem declarations with clear messaging (@benlakey) + - tries to find a `bundler-` executable on your path for non-bundler commands (@andremedeiros) + - tries to find `gems.rb` and it's new counterpart, `gems.locked` (@andremedeiros) + - change the initial version of new gems from `0.0.1` to `0.1.0` (@petedmarsh) + - add `package --all-platforms` to cache gems for each known platform (@ccutrer) + - speed up `exec` when running commands on the $PATH (@kirs) + - add gem code of conduct file and option (@kirs) + - add config settings for gem license and tests (@kirs) + - add `bin/setup` and `bin/console` to new gems (@indirect) + - include configured user-agent in network requests (@indirect) + - support `github`, `gist`, and `bitbucket` options on git gems (@indirect) + - add `package --cache-path` and `config cache_path` for cache location (@jnraine) + - allow `config` to work even when a Gemfile is not present (@dholdren) + - add `config gemfile /path` for other Gemfile locations (@dholdren) + - add `github` method alonside the `git` method (@BenMorganIO) + +## Bug fixes: + + - reduce memory usage with threaded parallel workers (@Who828) + - support read-only git gems (@pmahoney) + - various resolver performance improvements (@dubek) + - untaint git gem paths for Rubygems compatibility (@tdtds) + +## Documentation: + + - add missing Gemfile global `path` explanation (@agenteo) + +# 1.7.15 (April 29, 2015) + +## Bug fixes: + + - Respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +# 1.7.14 (March 30, 2015) + +## Bug fixes: + + - Keep gems locked when updating another gem from the same source ([#3250](https://github.com/rubygems/bundler/issues/3250), @indirect) + - Don't add extra quotes around long, quoted config values (@aroben, [#3338](https://github.com/rubygems/bundler/issues/3338)) + +# 1.7.13 (February 7, 2015) + +## Bug fixes: + + - Look up installed gems in remote sources ([#3300](https://github.com/rubygems/bundler/issues/3300), [#3368](https://github.com/bundler/bundler/issues/3368), [#3377](https://github.com/bundler/bundler/issues/3377), [#3380](https://github.com/bundler/bundler/issues/3380), [#3381](https://github.com/bundler/bundler/issues/3381), @indirect) + - Look up gems across all sources to satisfy dependencies ([#3365](https://github.com/rubygems/bundler/issues/3365), @keiths-osc) + - Request dependencies for no more than 100 gems at a time ([#3367](https://github.com/rubygems/bundler/issues/3367), @segiddins) + +# 1.7.12 (January 8, 2015) + +## Bug fixes: + + - Always send credentials for sources, fixing private Gemfury gems ([#3342](https://github.com/rubygems/bundler/issues/3342), @TimMoore) + +# 1.7.11 (January 4, 2015) + +## Bug fixes: + + - Recognize `:mri_22` and `:mingw_22`, rather than just `:ruby_22` ([#3328](https://github.com/rubygems/bundler/issues/3328), @myabc) + +# 1.7.10 (December 29, 2014) + +## Bug fixes: + + - Fix source blocks sometimes causing deployment mode to fail wrongly ([#3298](https://github.com/rubygems/bundler/issues/3298), @TimMoore) + +## Features: + + - Support `platform :mri_22` and related version bits ([#3309](https://github.com/rubygems/bundler/issues/3309), @thomasfedb) + +# 1.7.9 (December 9, 2014) + +## Bug fixes: + + - Fix an issue where bundler sometime spams one gem in Gemfile.lock ([#3216](https://github.com/rubygems/bundler/issues/3216), @Who828) + - Ensure bundle update installs the newer version of the gem ([#3089](https://github.com/rubygems/bundler/issues/3089), @Who828) + - Fix an regression which stopped Bundler from resolving some Gemfiles ([#3059](https://github.com/rubygems/bundler/issues/3059), [#3248](https://github.com/bundler/bundler/issues/3248), @Who828) + +# 1.7.8 (December 6, 2014) + +## Bug fixes: + + - Hide credentials while warning about gems with ambiguous sources ([#3256](https://github.com/rubygems/bundler/issues/3256), @TimMoore) + +# 1.7.7 (November 19, 2014) + +## Bug fixes: + + - Ensure server credentials stored in config or ENV will be used ([#3180](https://github.com/rubygems/bundler/issues/3180), @arronmabrey) + - Fix race condition causing errors while installing git-based gems ([#3174](https://github.com/rubygems/bundler/issues/3174), @Who828) + - Use single quotes in config so YAML won't add more quotes ([#3261](https://github.com/rubygems/bundler/issues/3261), @indirect) + +# 1.7.6 (November 11, 2014) + +## Bug fixes: + + - CA certificates that work with all OpenSSLs (@luislavena, @indirect) + +# 1.7.5 (November 10, 2014) + +## Bug fixes: + + - Fix --deployment with source blocks and non-alphabetical gems ([#3224](https://github.com/rubygems/bundler/issues/3224), @TimMoore) + - Vendor CA chain to validate new rubygems.org HTTPS certificate (@indirect) + +# 1.7.4 (October 19, 2014) + +## Bug fixes: + + - Allow --deployment after `pack` while using source blocks ([#3167](https://github.com/rubygems/bundler/issues/3167), @TimMoore) + - Use dependency API even when HTTP credentials are in ENV ([#3191](https://github.com/rubygems/bundler/issues/3191), @fvaleur) + - Silence warnings (including root warning) in --quiet mode ([#3186](https://github.com/rubygems/bundler/issues/3186), @indirect) + - Stop asking gem servers for gems already found locally ([#2909](https://github.com/rubygems/bundler/issues/2909), @dubek) + +# 1.7.3 (September 14, 2014) + +## Bug fixes: + + - `extconf.rb` is now generated with the right path for `create_makefile` (@andremedeiros) + - Fix various Ruby warnings (@piotrsanarki, @indirect) + +# 1.7.2 (August 23, 2014) + +## Bug fixes: + + - Revert gem source sorting in lock files (@indirect) + +# 1.7.1 (August 20, 2014) + +## Bug fixes: + + - Install gems from one source needed by gems in another source (@indirect) + - Install the same gem versions even after some are installed (@TimMoore) + - Download specs only when installing from servers (@indirect) + +# 1.7.0 (August 13, 2014) + +## Security fixes: + + - Fix for CVE-2013-0334, installing gems from an unexpected source (@TimMoore) + +## Features: + + - Gemfile `source` calls now take a block containing gems from that source (@TimMoore) + - Added the `:source` option to `gem` to specify a source (@TimMoore) + +## Bug fixes: + + - Warn on ambiguous gems available from more than one source (@TimMoore) + +# 1.6.7 (October 19, 2014) + +## Features: + + - warn to upgrade when using useless source blocks (@danfinnie) + +## Documentation: + + - explain how to use gem server credentials via ENV (@hwartig) + +# 1.6.6 (August 23, 2014) + +## Bug fixes: + + - restore Gemfile credentials to Gemfile.lock (@indirect) + +# 1.6.5 (July 23, 2014) + +## Bug fixes: + + - require openssl explicitly to fix rare HTTPS request failures (@indirect, [#3107](https://github.com/rubygems/bundler/issues/3107)) + +# 1.6.4 (July 17, 2014) + +## Bug fixes: + + - fix undefined constant error when can't find gem during binstubs ([#3095](https://github.com/rubygems/bundler/issues/3095), @jetaggart) + - work when installed git gems are not writable ([#3092](https://github.com/rubygems/bundler/issues/3092), @pmahoney) + - don't store configured source credentials in Gemfile.lock ([#3045](https://github.com/rubygems/bundler/issues/3045), @lhz) + - don't include config source credentials in the lockfile (Lars Haugseth) + - use threads for jobs on Rubinius (@YorickPeterse) + - skip dependencies from other platforms (@mvz) + - work when Rubygems was built without SSL (@andremedeiros) + +# 1.6.3 (June 16, 2014) + +## Bug fixes: + + - fix regression when resolving many conflicts ([#2994](https://github.com/rubygems/bundler/issues/2994), @Who828) + - use local gemspec for builtin gems during install --local ([#3041](https://github.com/rubygems/bundler/issues/3041), @Who828) + - don't warn about sudo when installing on Windows ([#2984](https://github.com/rubygems/bundler/issues/2984), @indirect) + - shell escape `bundle open` arguments (@indirect) + +# 1.6.2 (April 13, 2014) + +## Bug fixes: + + - fix an exception when using builtin gems ([#2915](https://github.com/rubygems/bundler/issues/2915), [#2963](https://github.com/bundler/bundler/issues/2963), @gnufied) + - cache gems that are built in to the running ruby ([#2975](https://github.com/rubygems/bundler/issues/2975), @indirect) + - re-allow deploying cached git gems without git installed ([#2968](https://github.com/rubygems/bundler/issues/2968), @aughr) + - keep standalone working even with builtin gems (@indirect) + - don't update vendor/cache in deployment mode ([#2921](https://github.com/rubygems/bundler/issues/2921), @indirect) + +## Features: + + - warn informatively when `bundle install` is run as root ([#2936](https://github.com/rubygems/bundler/issues/2936), @1337807) + +# 1.6.1 (April 2, 2014) + +## Bug fixes: + + - update C extensions when git gem versions change ([#2948](https://github.com/rubygems/bundler/issues/2948), @dylanahsmith) + +## Features: + + - add support for C extensions in sudo mode on Rubygems 2.2 + +# 1.6.0 (March 28, 2014) + +## Bug fixes: + + - many Gemfiles that caused incorrect errors now resolve correctly (@Who828) + - redirects across hosts now work on rubies without OpenSSL ([#2686](https://github.com/rubygems/bundler/issues/2686), @grddev) + - gemspecs now handle filenames with newlines ([#2634](https://github.com/rubygems/bundler/issues/2634), @jasonmp85) + - support escaped characters in usernames and passwords (@punkie) + - no more exception on `update GEM` without lock file (@simi) + - allow long config values ([#2823](https://github.com/rubygems/bundler/issues/2823), @kgrz) + - cache successfully even locked to gems shipped with Ruby ([#2869](https://github.com/rubygems/bundler/issues/2869), @aughr) + - respect NO_PROXY even if a proxy is configured ([#2878](https://github.com/rubygems/bundler/issues/2878), @stlay) + - only retry git commands that hit the network ([#2899](https://github.com/rubygems/bundler/issues/2899), @timmoore) + - fix NameError regression when OpenSSL is not available ([#2898](https://github.com/rubygems/bundler/issues/2898), @timmoore) + - handle exception installing when build_info owned by root (@Who828) + - skip HTTP redirects from rubygems.org, huge speed boost (@Who828) + +## Features: + + - resolver rewritten to avoid recursion (@Who828) + - add `git_source` for custom options like :github and :gist (@strzalek) + - HTTP auth may now be stored in `bundle config` (@smashwilson) + - some complex Gemfiles are resolved up to 10x faster (@Who828) + - add support for IRB alternatives such as Pry and Ripl (@joallard, @postmodern) + - highlight installed or updated gems ([#2722](https://github.com/rubygems/bundler/issues/2722), [#2741](https://github.com/bundler/bundler/issues/2741), @yaotti, @simi) + - display the `post_install_message` for gems installed via :git (@phallstrom) + - `bundle outdated --strict` now only reports allowed updates (@davidblondeau) + - `bundle show --verbose` Add gem summary to the output (@lardcanoe) + - `bundle gem GEM --ext` now generates a skeleton for a C extension (@superdealloc) + - Avoid using threequals operator where possible (@as-cii) + - Add `bundle update --group` to update specific group ([#2731](https://github.com/rubygems/bundler/issues/2731) @banyan) + +## Documentation: + + - Add missing switches for bundle-install(1) and bundle-update(1) (@as-cii) + +# 1.5.3 (February 6, 2014) + +## Bug fixes: + + - find "missing" gems that are actually present ([#2780](https://github.com/rubygems/bundler/issues/2780), [#2818](https://github.com/bundler/bundler/issues/2818), [#2854](https://github.com/bundler/bundler/issues/2854)) + - use n-1 cores when given n jobs for parallel install (@jdickey) + +# 1.5.2 (January 10, 2014) + +## Bug fixes: + + - fix integration with Rubygems 1.8.0-1.8.19 + - handle ENETDOWN exception during network requests + - gracefully shut down after interrupt during parallel install (@Who828) + - allow Rails to run Thor without debug mode (@rafaelfranca) + - set git binstub permissions by umask (@v-yarotsky) + - remove parallel install debug log + +# 1.5.1 (December 28, 2013) + +## Bug fixes: + + - correctly find gems installed with Ruby by default + +# 1.5.0 (December 26, 2013) + +## Features: + + - install missing gems if their specs are present (@hone) + +## Bug fixes: + + - use print for "Installing…" so messages are thread-safe (@TimMoore) + +# 1.5.0.rc.2 (December 18, 2013) + +## Features: + + - Support threaded installation on Rubygems 2.0.7+ + - Debug installation logs in .bundle/install.log + +## Bug fixes: + + - Try to catch gem installation race conditions + +# 1.5.0.rc.1 (November 9, 2013) + +## Features: + + - bundle update also accepts --jobs ([#2692](https://github.com/rubygems/bundler/issues/2692), @mrkn) + - add fork URL to README for new `bundle gem` ([#2665](https://github.com/rubygems/bundler/issues/2665), @zzak) + - add `bundle outdated --strict` ([#2685](https://github.com/rubygems/bundler/issues/2685), @davidblondeau) + - warn if same gem/version is added twice ([#2679](https://github.com/rubygems/bundler/issues/2679), @jendiamond) + - don't redownload installed specs for `bundle install` ([#2680](https://github.com/rubygems/bundler/issues/2680), @cainlevy) + - override gem sources with mirrors ([#2650](https://github.com/rubygems/bundler/issues/2650), @danielsdeleo, @mkristian) + +## Bug fixes: + + - fix sharing same SSL socket when forking workers for parallel install ([#2632](https://github.com/rubygems/bundler/issues/2632)) + - fix msg typo in GitNotAllowedError ([#2654](https://github.com/rubygems/bundler/issues/2654), @joyicecloud) + - fix Bundler.which for directories ([#2697](https://github.com/rubygems/bundler/issues/2697), @rhysd) + - properly require `Capistrano::Version` ([#2690](https://github.com/rubygems/bundler/issues/2690), @steveklabnik) + - search for git.exe and git + - fix the bug that downloads every spec when API fetcher encounters an error + - only retry network requests + +# 1.4.0.rc.1 (September 29, 2013) + +## Features: + + - add support for the x64-mingw32 platform ([#2356](https://github.com/rubygems/bundler/issues/2356), [#2590](https://github.com/bundler/bundler/issues/2590), @larskanis) + - add :patchlevel option to ruby DSL + - add `bundler` bin ([#2598](https://github.com/rubygems/bundler/issues/2598), @kirs) + - friendly ambiguous error messages ([#2581](https://github.com/rubygems/bundler/issues/2581), [#2550](https://github.com/bundler/bundler/issues/2550), @jlsuttles, @jendiamond, @joyicecloud) + - add `:jruby_18` and `:jruby_19` platform options (@mcfiredrill) + - add X.509 client certificates for auth without passwords (@snackbandit) + - add `exec --keep-file-descriptors` for Ruby 1.9-like behavior on 2.0 (@steved555) + - print a better error when git is not installed (@joyicecloud) + - exit non-zero when `outdated` is run with an unknown gem (@joyicecloud) + - add `:ruby_21` platform option (@brandonblack) + - add `--retry` to retry failed network and git commands (@schneems) + - include command and versions in User-Agent (@indirect, @joyicecloud) + +## Bug fixes: + + - allow passwordless Basic Auth ([#2606](https://github.com/rubygems/bundler/issues/2606), @rykov) + - don't suggest `gem install foo` when `foo` is a git gem that fails (@kirs) + - revert [#2569](https://github.com/rubygems/bundler/issues/2569), staying compatible with git: instead of https: for :github gems + - handle exceptions while installing gems in parallel (@gnufied) + +# 1.4.0.pre.1 (August 4, 2013) + +## Features: + + - retry network requests while installing gems ([#2561](https://github.com/rubygems/bundler/issues/2561), @ascherger) + - faster installs using gemspecs from the local system cache ([#2497](https://github.com/rubygems/bundler/issues/2497), @mipearson) + - add `bundle install -jN` for N parallel gem installations ([#2481](https://github.com/rubygems/bundler/issues/2481), @eagletmt) + - add `ENV['DEBUG_RESOLVER_TREE']` outputs resolver tree (@dblock) + - set $MANPATH so `bundle exec man name` works ([#1624](https://github.com/rubygems/bundler/issues/1624), @sunaku) + - use `man` instead of `groff` ([#2579](https://github.com/rubygems/bundler/issues/2579), @ixti, @simi) + - add Gemfile dependency info to bundle outdated output ([#2487](https://github.com/rubygems/bundler/issues/2487), @rahearn) + - allow `require: true` as an alias for `require: ` ([#2538](https://github.com/rubygems/bundler/issues/2538), @ndbroadbent) + - rescue and report Thor errors ([#2478](https://github.com/rubygems/bundler/issues/2478), @pjvds) + - detect cyclic dependencies ([#2564](https://github.com/rubygems/bundler/issues/2564), @gnufied) + - support multiple gems in `binstubs` ([#2576](https://github.com/rubygems/bundler/issues/2576), @lucasmazza) + - use https instead of git for :github gems ([#2569](https://github.com/rubygems/bundler/issues/2569), @fuadsaud) + - add quiet option to `bundle package` ([#2573](https://github.com/rubygems/bundler/issues/2573), @shtirlic) + - use RUBYLIB instead of RUBYOPT for better Windows support ([#2536](https://github.com/rubygems/bundler/issues/2536), @equinux) + +## Bug fixes: + + - reduce stack size while resolving to fix JRuby overflow ([#2510](https://github.com/rubygems/bundler/issues/2510), @headius) + - display GitErrors while loading specs in --verbose mode ([#2461](https://github.com/rubygems/bundler/issues/2461)) + - allow the same options hash to be passed to multiple gems ([#2447](https://github.com/rubygems/bundler/issues/2447)) + - handle missing binaries without an exception ([#2019](https://github.com/rubygems/bundler/issues/2019), @luismreis) + +# 1.3.6 (January 8, 2014) + +## Bug fixes: + + - make gemspec path option preserve relative paths in lock file (@bwillis) + - use umask when creating binstubs ([#1618](https://github.com/rubygems/bundler/issues/1618), @v-yarotsky) + - warn if graphviz is not installed ([#2435](https://github.com/rubygems/bundler/issues/2435), @Agis-) + - show git errors while loading gemspecs + - don't mutate gem method options hash ([#2447](https://github.com/rubygems/bundler/issues/2447)) + - print Thor errors ([#2478](https://github.com/rubygems/bundler/issues/2478), @pjvds) + - print Rubygems system exit errors (James Cook) + - more Pathnames into Strings for MacRuby (@kml) + - preserve original gemspec path (@bwillis) + - remove warning about deps with :git ([#1651](https://github.com/rubygems/bundler/issues/1651), @ixti) + - split git files on null ([#2634](https://github.com/rubygems/bundler/issues/2634), @jasonmp85) + - handle cross-host redirects without SSL ([#2686](https://github.com/rubygems/bundler/issues/2686), @grddev) + - handle Rubygems 2 security exception (@zzak) + - reinstall gems if they are missing with spec present + - set binstub permissions using umask ([#1618](https://github.com/rubygems/bundler/issues/1618), @v-yarotsky) + +# 1.3.5 (April 3, 2013) + +## Features: + + - progress indicator while resolver is running (@chief) + +## Bug fixes: + + - update local overrides with orphaned revisions (@jamesferguson) + - revert to working quoting of RUBYOPT on Windows (@ogra) + - use basic auth even when SSL is not available (@jayniz) + - installing git gems without dependencies in deployment now works + +# 1.3.4 (March 15, 2013) + +## Bug fixes: + + - load YAML on Rubygems versions that define module YAML + - fix regression that broke --without on ruby 1.8.7 + +# 1.3.3 (March 13, 2013) + +## Features: + + - compatible with Rubygems 2.0.2 (higher and lower already work) + - mention skipped groups in bundle install and bundle update output (@simi) + - `gem` creates rake tasks for minitest (@coop) and rspec + +## Bug fixes: + + - require rbconfig for standalone mode + +# 1.3.2 (March 7, 2013) + +## Features: + + - include rubygems.org CA chain + +## Bug fixes: + + - don't store --dry-run as a Bundler setting + +# 1.3.1 (March 3, 2013) + +## Bug fixes: + + - include manpages in gem, restoring many help pages + - handle more SSL certificate verification failures + - check for the full version of SSL, which we need (@alup) + - gem rake task 'install' now depends on task 'build' (@sunaku) + +# 1.3.0 (February 24, 2013) + +## Features: + + - raise a useful error when the lockfile contains a merge conflict (@zofrex) + - ensure `rake release` checks for uncommitted as well as unstaged (@benmoss) + - allow environment variables to be negated with 'false' and '0' (@brettporter) + - set $MANPATH inside `exec` for gems with man pages (@sunaku) + - partial gem names for `open` and `update` now return a list (@takkanm) + +## Bug fixes: + + - `update` now (again) finds gems that aren't listed in the Gemfile + - `install` now (again) updates cached gems that aren't in the Gemfile + - install Gemfiles with HTTP sources even without OpenSSL present + - display CerficateFailureError message in full + +# 1.3.0.pre.8 (February 12, 2013) + +## Security fixes: + + - validate SSL certificate chain during HTTPS network requests + - don't send HTTP Basic Auth creds when redirected to other hosts (@perplexes) + - add `--trust-policy` to `install`, like `gem install -P` (@CosmicCat, [#2293](https://github.com/rubygems/bundler/issues/2293)) + +## Features: + + - optimize resolver when too new of a gem is already activated (@rykov, [#2248](https://github.com/rubygems/bundler/issues/2248)) + - update Net::HTTP::Persistent for SSL cert validation and no_proxy ENV + - explain SSL cert validation failures + - generate gemspecs when installing git repos, removing shellouts + - add pager selection (@csgui) + - add `licenses` command (@bryanwoods, [#1898](https://github.com/rubygems/bundler/issues/1898)) + - sort output from `outdated` (@richardkmichael, [#1896](https://github.com/rubygems/bundler/issues/1896)) + - add a .travis.yml to `gem -t` (@ndbroadbent, [#2143](https://github.com/rubygems/bundler/issues/2143)) + - inform users when the resolver starts + - disable reverse DNS to speed up API requests (@raggi) + +## Bug fixes: + + - raise errors while requiring dashed gems ([#1807](https://github.com/rubygems/bundler/issues/1807)) + - quote the Bundler path on Windows (@jgeiger, [#1862](https://github.com/rubygems/bundler/issues/1862), [#1856](https://github.com/bundler/bundler/issues/1856)) + - load gemspecs containing unicode (@gaffneyc, [#2301](https://github.com/rubygems/bundler/issues/2301)) + - support any ruby version in --standalone + - resolve some ruby -w warnings (@chastell, [#2193](https://github.com/rubygems/bundler/issues/2193)) + - don't scare users with an error message during API fallback + - `install --binstubs` is back to overwriting. thanks, SemVer. + +# 1.3.0.pre.7 (January 22, 2013) + +## Bug fixes: + + - stubs for gems with dev deps no longer cause exceptions ([#2272](https://github.com/rubygems/bundler/issues/2272)) + - don't suggest binstubs to --binstubs users + +# 1.3.0.pre.6 (January 22, 2013) + +## Features: + + - `binstubs` lists child gem bins if a gem has no binstubs + - `bundle gem --edit` will open the new gemspec (@ndbroadbent) + - `bundle gem --test rspec` now makes working tests (@tricknotes) + - `bundle env` prints info about bundler's environment (@peeja) + - add `BUNDLE_IGNORE_CONFIG` environment variable support (@richo) + +## Bug fixes: + + - don't overwrite custom binstubs during `install --binstubs` + - don't throw an exception if `binstubs` gem doesn't exist + - `bundle config` now works in directories without a Gemfile + +# 1.3.0.pre.5 (January 9, 2013) + +## Features: + + - make `--standalone` require lines ruby engine/version agnostic + - add `--dry-run` to `bundle clean` (@wfarr, [#2237](https://github.com/rubygems/bundler/issues/2237)) + +## Bug fixes: + + - don't skip writing binstubs when doing `bundle install` + - distinguish between ruby 1.9/2.0 when using :platforms (@spastorino) + +# 1.3.0.pre.4 (January 3, 2013) + +## Features: + + - `bundle binstubs ` to setup individual binstubs + - `bundle install --binstubs ""` will remove binstubs option + - `bundle clean --dry-run` will print out gems instead of removing them + +## Bug fixes: + + - Avoid stack traces when Ctrl+C during bundle command (@mitchellh) + - fix YAML parsing in in ruby-preview2 + +# 1.3.0.pre.3 (December 21, 2012) + +## Features: + + - pushing gems during `rake release` can be disabled (@trans) + - installing gems with `rake install` is much faster (@utkarshkukreti) + - added platforms :ruby_20 and :mri_20, since the ABI has changed + - added '--edit' option to open generated gemspec in editor + +## Bug fixes: + + - :git gems with extensions now work with Rubygems >= 2.0 (@jeremy) + - revert SemVer breaking change to :github + - `outdated` exits non-zero if outdated gems found (@rohit, [#2021](https://github.com/rubygems/bundler/issues/2021)) + - https Gist URLs for compatibility with Gist 2.0 (@NARKOZ) + - namespaced gems no longer generate a superfluous directory (@banyan) + +# 1.3.0.pre.2 (December 9, 2012) + +## Features: + + - `config` expands local overrides like `local.rack .` (@gkop, [#2205](https://github.com/rubygems/bundler/issues/2205)) + - `gem` generates files correctly for names like `jquery-rails` (@banyan, [#2201](https://github.com/rubygems/bundler/issues/2201)) + - use gems from gists with the :gist option in the Gemfile (@jgaskins) + +## Bug fixes: + + - Gemfile sources other than rubygems.org work even when .gemrc contains sources + - caching git gems now caches specs, fixing e.g. git ls-files (@bison, [#2039](https://github.com/rubygems/bundler/issues/2039)) + - `show GEM` now warns if the directory has been deleted (@rohit, [#2070](https://github.com/rubygems/bundler/issues/2070)) + - git output hidden when running in --quiet mode (@rohit) + +# 1.3.0.pre (November 29, 2012) + +## Features: + + - compatible with Ruby 2.0.0-preview2 + - compatible with Rubygems 2.0.0.preview2 (@drbrain, @evanphx) + - ruby 2.0 added to the `:ruby19` ABI-compatible platform + - lazy load YAML, allowing Psych to be specified in the Gemfile + - significant performance improvements (@cheald, [#2181](https://github.com/rubygems/bundler/issues/2181)) + - `inject` command for scripted Gemfile additions (Engine Yard) + - :github option uses slashless arguments as repo owner (@rking) + - `open` suggests gem names for typos (@jdelStrother) + - `update` reports non-existent gems (@jdelStrother) + - `gem` option --test can generate rspec stubs (@MafcoCinco) + - `gem` option --test can generate minitest stubs (@kcurtin) + - `gem` command generates MIT license (@BrentWheeldon) + - gem rake task 'release' reuses existing tags (@shtirlic) + +## Bug fixes: + + - JRuby new works with HTTPS gem sources (@davidcelis) + - `install` installs both rake rake-built gems at once (@crowbot, [#2107](https://github.com/rubygems/bundler/issues/2107)) + - handle Errno::ETIMEDOUT errors (@jmoses) + - handle Errno::EAGAIN errors on JRuby + - disable ANSI coloring when output is redirected (@tomykaira) + - raise LoadErrors correctly during Bundler.require (@Empact) + - do not swallow --verbose on `bundle exec` (@sol, [#2102](https://github.com/rubygems/bundler/issues/2102)) + - `gem` generates gemspecs that block double-requires + - `gem` generates gemspecs that admit they depend on rake + +# 1.2.5 (February 24, 2013) + +## Bug fixes: + + - install Gemfiles with HTTP sources even without OpenSSL present + - display CerficateFailureError message in full + +# 1.2.4 (February 12, 2013) + +## Features: + + - warn about Ruby 2.0 and Rubygems 2.0 + - inform users when the resolver starts + - disable reverse DNS to speed up API requests (@raggi) + +## Bug fixes: + + - don't send user/pass when redirected to another host (@perplexes) + - load gemspecs containing unicode (@gaffneyc, [#2301](https://github.com/rubygems/bundler/issues/2301)) + - support any ruby version in --standalone + - resolve some ruby -w warnings (@chastell, [#2193](https://github.com/rubygems/bundler/issues/2193)) + - don't scare users with an error message during API fallback + +# 1.2.3 (November 29, 2012) + +## Bug fixes: + + - fix exceptions while loading some gemspecs + +# 1.2.2 (November 14, 2012) + +## Bug fixes: + + - support new Psych::SyntaxError for Ruby 2.0.0 (@tenderlove, @sol) + - `bundle viz` works with git gems again (@hirochachacha) + - recognize more cases when OpenSSL is not present + +# 1.2.1 (September 19, 2012) + +## Bug fixes: + + - `bundle clean` now works with BUNDLE_WITHOUT groups again + - have a net/http read timeout around the Gemcutter API Endpoint + +# 1.2.0 (August 30, 2012) + +## Bug fixes: + + - raise original error message from LoadError's + +## Documentation: + + - `platform` man pages + +# 1.2.0.rc.2 (August 8, 2012) + +## Bug fixes: + + - `clean` doesn't remove gems that are included in the lockfile + +# 1.2.0.rc (July 17, 2012) + +## Features: + + - `check` now has a `--dry-run` option (@svenfuchs, [#1811](https://github.com/rubygems/bundler/issues/1811)) + - loosen ruby directive for engines + - prune git/path directories inside vendor/cache (@josevalim, [#1988](https://github.com/rubygems/bundler/issues/1988)) + - update vendored thor to 0.15.2 (@sferik) + - add .txt to LICENSE (@postmodern, [#2001](https://github.com/rubygems/bundler/issues/2001)) + - add `config disable_local_branch_check` (@josevalim, [#1985](https://github.com/rubygems/bundler/issues/1985)) + - fall back on the full index when experiencing syck errors ([#1419](https://github.com/rubygems/bundler/issues/1419)) + - handle syntax errors in Ruby gemspecs ([#1974](https://github.com/rubygems/bundler/issues/1974)) + +## Bug fixes: + + - fix `pack`/`cache` with `--all` (@josevalim, [#1989](https://github.com/rubygems/bundler/issues/1989)) + - don't display warning message when `cache_all` is set + - check for `nil` PATH ([#2006](https://github.com/rubygems/bundler/issues/2006)) + - Always try to keep original GEM_PATH (@drogus, [#1920](https://github.com/rubygems/bundler/issues/1920)) + +# 1.2.0.pre.1 (May 27, 2012) + +## Features: + + - Git gems import submodules of submodules recursively (@nwwatson, [#1935](https://github.com/rubygems/bundler/issues/1935)) + +## Bug fixes: + + - Exit from `check` with a non-zero status when frozen with no lock + - Use `latest_release` in Capistrano and Vlad integration ([#1264](https://github.com/rubygems/bundler/issues/1264)) + - Work around a Ruby 1.9.3p194 bug in Psych when config files are empty + +## Documentation: + + - Add instructions for local git repos to the `config` manpage + - Update the `Gemfile` manpage to include ruby versions (@stevenh512) + - When OpenSSL is missing, provide instructions for fixing ([#1776](https://github.com/rubygems/bundler/issues/1776) etc.) + - Unknown exceptions now link to ISSUES for help instead of a new ticket + - Correct inline help for `clean --force` (@dougbarth, [#1911](https://github.com/rubygems/bundler/issues/1911)) + +# 1.2.0.pre (May 4, 2012) + +## Features: + + - bundle package now accepts --all to package git and path dependencies + - bundle config now accepts --local, --global and --delete options + - It is possible to override a git repository via configuration. + For instance, if you have a git dependency on rack, you can force + it to use a local repo with `bundle config local.rack ~/path/to/rack` + - Cache gemspec loads for performance (@dekellum, [#1635](https://github.com/rubygems/bundler/issues/1635)) + - add --full-index flag to `bundle update` (@fluxx, [#1829](https://github.com/rubygems/bundler/issues/1829)) + - add --quiet flag to `bundle update` (@nashby, [#1654](https://github.com/rubygems/bundler/issues/1654)) + - Add Bundler::GemHelper.gemspec (@knu, [#1637](https://github.com/rubygems/bundler/issues/1637)) + - Graceful handling of Gemfile syntax errors (@koraktor, [#1661](https://github.com/rubygems/bundler/issues/1661)) + - `bundle platform` command + - add ruby to DSL, to specify version of ruby + - error out if the ruby version doesn't match + +## Performance: + + - bundle exec shouldn't run Bundler.setup just setting the right rubyopts options is enough (@spastorino, [#1598](https://github.com/rubygems/bundler/issues/1598)) + +## Bug fixes: + + - Avoid passing RUBYOPT changes in with_clean_env block (@eric1234, [#1604](https://github.com/rubygems/bundler/issues/1604)) + - Use the same ruby to run subprocesses as is running rake (@brixen) + +## Documentation: + + - Add :github documentation in DSL (@zofrex, [#1848](https://github.com/rubygems/bundler/issues/1848), [#1851](https://github.com/bundler/bundler/issues/1851), [#1852](https://github.com/bundler/bundler/issues/1852)) + - Add docs for the --no-cache option (@fluxx, [#1796](https://github.com/rubygems/bundler/issues/1796)) + - Add basic documentation for bin_path and bundle_path (@radar) + - Add documentation for the run method in Bundler::Installer + +# 1.1.5 (July 17, 2012) + +## Features: + + - Special case `ruby` directive from 1.2.0, so you can install Gemfiles that use it + +# 1.1.4 (May 27, 2012) + +## Bug fixes: + + - Use `latest_release` in Capistrano and Vlad integration ([#1264](https://github.com/rubygems/bundler/issues/1264)) + - Unknown exceptions now link to ISSUES for help instead of a new ticket + - When OpenSSL is missing, provide instructions for fixing ([#1776](https://github.com/rubygems/bundler/issues/1776) etc.) + - Correct inline help for `clean --force` (@dougbarth, [#1911](https://github.com/rubygems/bundler/issues/1911)) + - Work around a Ruby 1.9.3p194 bug in Psych when config files are empty + +# 1.1.3 (March 23, 2012) + +## Bug fixes: + + - escape the bundler root path (@tenderlove, [#1789](https://github.com/rubygems/bundler/issues/1789)) + +# 1.1.2 (March 20, 2012) + +## Bug fixes: + + - Fix --deployment for multiple PATH sections of the same source ([#1782](https://github.com/rubygems/bundler/issues/1782)) + +# 1.1.1 (March 14, 2012) + +## Bug fixes: + + - Rescue EAGAIN so the fetcher works on JRuby on Windows + - Stop asking users to report gem installation errors + - Clarify "no sources" message + - Use $\ so `bundle gem` gemspecs work on Windows (@postmodern) + - URI-encode gem names for dependency API (@rohit, [#1672](https://github.com/rubygems/bundler/issues/1672)) + - Fix `cache` edge case in rubygems 1.3.7 ([#1202](https://github.com/rubygems/bundler/issues/1202)) + +## Performance: + + - Reduce invocation of git ls-files in `bundle gem` gemspecs (@knu) + +# 1.1.0 (March 7, 2012) + +## Bug fixes: + + - Clean up corrupted lockfiles on bundle installs + - Prevent duplicate GIT sources + - Fix post_install_message when uing the endpoint API + +# 1.1.rc.8 (March 3, 2012) + +## Performance: + + - don't resolve if the Gemfile.lock and Gemfile haven't changed + +## Bug fixes: + + - Load gemspecs from git even when a released gem has the same version ([#1609](https://github.com/rubygems/bundler/issues/1609)) + - Declare an accurate Ruby version requirement of 1.8.7 or newer ([#1619](https://github.com/rubygems/bundler/issues/1619)) + - handle gemspec development dependencies correctly (@raggi, [#1639](https://github.com/rubygems/bundler/issues/1639)) + - Avoid passing RUBYOPT changes in with_clean_env block. (eric1234, [#1604](https://github.com/rubygems/bundler/issues/1604)) + +# 1.1.rc.7 (December 29, 2011) + +## Bug fixes: + + - Fix bug where `clean` would break when using :path with no gemspec + +# 1.1.rc.6 (December 22, 2011) + +## Bug fixes: + + - Fix performance regression from 1.0 (@spastorino, [#1511](https://github.com/rubygems/bundler/issues/1511), [#1591](https://github.com/bundler/bundler/issues/1591), [#1592](https://github.com/bundler/bundler/issues/1592)) + - Load gems correctly when GEM_HOME is blank + - Refresh gems so Bundler works from inside a bundle + - Handle empty .bundle/config files without an error + +# 1.1.rc.5 (December 14, 2011) + +## Bug fixes: + + - Fix ASCII encoding errors with gem (rerelease with ruby 1.8) + +# 1.1.rc.4 (December 14, 2011) + +## Features: + + - `bundle viz` has the option to output a DOT file instead of a PNG (@hirochachacha, [#683](https://github.com/rubygems/bundler/issues/683)) + +## Bug fixes: + + - Ensure binstubs generated when using --standalone point to the standalonde bundle (@cowboyd, [#1588](https://github.com/rubygems/bundler/issues/1588)) + - fix `bundle viz` (@hirochachacha, [#1586](https://github.com/rubygems/bundler/issues/1586)) + +# 1.1.rc.3 (December 8, 2011) + +## Bug fixes: + + - fix relative_path so it checks Bundler.root is actually in the beginning of the path ([#1582](https://github.com/rubygems/bundler/issues/1582)) + - fix bundle outdated doesn't list all gems (@joelmoss, [#1521](https://github.com/rubygems/bundler/issues/1521)) + +# 1.1.rc.2 (December 6, 2011) + +## Features: + + - Added README.md to `newgem` (@ognevsky, [#1574](https://github.com/rubygems/bundler/issues/1574)) + - Added LICENSE (MIT) to newgem (@ognevsky, [#1571](https://github.com/rubygems/bundler/issues/1571)) + +## Bug fixes: + + - only auto-namespace requires for implied requires ([#1531](https://github.com/rubygems/bundler/issues/1531)) + - fix bundle clean output for git repos ([#1473](https://github.com/rubygems/bundler/issues/1473)) + - use Gem.bindir for bundle clean ([#1544](https://github.com/rubygems/bundler/issues/1544), [#1532](https://github.com/bundler/bundler/issues/1532)) + - use `Gem.load_env_plugins` instead of `Gem.load_env_plugins` ([#1500](https://github.com/rubygems/bundler/issues/1500), [#1543](https://github.com/bundler/bundler/issues/1543)) + - differentiate Ruby 2.0 (trunk) from Ruby 1.9 (@tenderlove, [#1539](https://github.com/rubygems/bundler/issues/1539)) + - `bundle clean` handles 7 length git hash for bundle clean ([#1490](https://github.com/rubygems/bundler/issues/1490), [#1491](https://github.com/bundler/bundler/issues/1491)) + - fix Psych loading issues + - Search $PATH for a binary rather than shelling out to `which` (@tenderlove, [#1573](https://github.com/rubygems/bundler/issues/1573)) + - do not clear RG cache unless we actually modify GEM_PATH and GEM_HOME- use `Gem.load_env_plugins` instead of `Gem.load_env_plugins` ([#1500](https://github.com/rubygems/bundler/issues/1500), [#1543](https://github.com/bundler/bundler/issues/1543)) + - `newgem` now uses https://rubygems.org ([#1562](https://github.com/rubygems/bundler/issues/1562)) + - `bundle init` now uses https://rubygems.org (@jjb, [#1522](https://github.com/rubygems/bundler/issues/1522)) + - `bundle install/update` does not autoclean when using --path for semver + +## Documentation: + + - added documentation for --shebang option for `bundle install` (@lunks, [#1475](https://github.com/rubygems/bundler/issues/1475), [#1558](https://github.com/bundler/bundler/issues/1558)) + +# 1.1.rc (October 3, 2011) + +## Features: + + - add `--shebang` option to bundle install (@bensie, [#1467](https://github.com/rubygems/bundler/issues/1467)) + - build passes on ruby 1.9.3rc1 ([#1458](https://github.com/rubygems/bundler/issues/1458), [#1469](https://github.com/bundler/bundler/issues/1469)) + - hide basic auth credentials for custom sources ([#1440](https://github.com/rubygems/bundler/issues/1440), [#1463](https://github.com/bundler/bundler/issues/1463)) + +## Bug fixes: + + - fix index search result caching ([#1446](https://github.com/rubygems/bundler/issues/1446), [#1466](https://github.com/bundler/bundler/issues/1466)) + - fix fetcher prints multiple times during install ([#1445](https://github.com/rubygems/bundler/issues/1445), [#1462](https://github.com/bundler/bundler/issues/1462)) + - don't mention API errors from non-rubygems.org sources + - fix autoclean so it doesn't remove bins that are used ([#1459](https://github.com/rubygems/bundler/issues/1459), [#1460](https://github.com/bundler/bundler/issues/1460)) + +## Documentation: + + - add :require => [...] to the gemfile(5) manpage (@nono, [#1468](https://github.com/rubygems/bundler/issues/1468)) + +# 1.1.pre.10 (September 27, 2011) + +## Features: + + - `config system_bindir foo` added, works like "-n foo" in your .gemrc file + +# 1.1.pre.9 (September 18, 2011) + +## Features: + + - `clean` will now clean up all old .gem and .gemspec files, cleaning up older pres + - `clean` will be automatically run after bundle install and update when using `--path` ([#1420](https://github.com/rubygems/bundler/issues/1420), [#1425](https://github.com/bundler/bundler/issues/1425)) + - `clean` now takes a `--force` option ([#1247](https://github.com/rubygems/bundler/issues/1247), [#1426](https://github.com/bundler/bundler/issues/1426)) + - `clean` will clean up cached git dirs in bundle clean ([#1390](https://github.com/rubygems/bundler/issues/1390)) + - remove deprecations from DSL ([#1119](https://github.com/rubygems/bundler/issues/1119)) + - autorequire tries directories for gems with dashed names ([#1205](https://github.com/rubygems/bundler/issues/1205)) + - adds a `--paths` flag to `bundle show` to list all the paths of bundled gems (@tiegz, [#1360](https://github.com/rubygems/bundler/issues/1360)) + - load rubygems plugins in the bundle binary (@tpope, [#1364](https://github.com/rubygems/bundler/issues/1364)) + - make `--standalone` respect `--path` (@cowboyd, [#1361](https://github.com/rubygems/bundler/issues/1361)) + +## Bug fixes: + + - Fix `clean` to handle nested gems in a git repo ([#1329](https://github.com/rubygems/bundler/issues/1329)) + - Fix conflict from revert of benchmark tool (@boffbowsh, [#1355](https://github.com/rubygems/bundler/issues/1355)) + - Fix fatal error when unable to connect to gem source ([#1269](https://github.com/rubygems/bundler/issues/1269)) + - Fix `outdated` to find pre-release gems that are installed. ([#1359](https://github.com/rubygems/bundler/issues/1359)) + - Fix color for ui. ([#1374](https://github.com/rubygems/bundler/issues/1374)) + - Fix installing to user-owned system gems on OS X + - Fix caching issue in the resolver ([#1353](https://github.com/rubygems/bundler/issues/1353), [#1421](https://github.com/bundler/bundler/issues/1421)) + - Fix :github DSL option + +# 1.1.pre.8 (August 13, 2011) + +## Bug fixes: + + - Fix `bundle check` to not print fatal error message (@cldwalker, [#1347](https://github.com/rubygems/bundler/issues/1347)) + - Fix require_sudo when Gem.bindir isn't writeable ([#1352](https://github.com/rubygems/bundler/issues/1352)) + - Fix not asking Gemcutter API for dependency chain of git gems in --deployment ([#1254](https://github.com/rubygems/bundler/issues/1254)) + - Fix `install --binstubs` when using --path ([#1332](https://github.com/rubygems/bundler/issues/1332)) + +# 1.1.pre.7 (August 8, 2011) + +## Bug fixes: + + - Fixed invalid byte sequence error while installing gem on Ruby 1.9 ([#1341](https://github.com/rubygems/bundler/issues/1341)) + - Fixed exception when sudo was needed to install gems (@spastorino) + +# 1.1.pre.6 (August 8, 2011) + +## Bug fixes: + + - Fix cross repository dependencies ([#1138](https://github.com/rubygems/bundler/issues/1138)) + - Fix git dependency fetching from API endpoint ([#1254](https://github.com/rubygems/bundler/issues/1254)) + - Fixes for bundle outdated (@joelmoss, [#1238](https://github.com/rubygems/bundler/issues/1238)) + - Fix bundle standalone when using the endpoint ([#1240](https://github.com/rubygems/bundler/issues/1240)) + +## Features: + + - Implement `to_ary` to avoid calls to method_missing (@tenderlove, [#1274](https://github.com/rubygems/bundler/issues/1274)) + - bundle clean removes old .gem files (@cldwalker, [#1293](https://github.com/rubygems/bundler/issues/1293)) + - Correctly identify missing child dependency in error message + - Run pre-install, post-build, and post-install gem hooks for git gems (@warhammerkid, [#1120](https://github.com/rubygems/bundler/issues/1120)) + - create Gemfile.lock for empty Gemfile ([#1218](https://github.com/rubygems/bundler/issues/1218)) + +# 1.1.pre.5 (June 11, 2011) + +## Bug fixes: + + - Fix LazySpecification on Ruby 1.9 (@dpiddy, [#1232](https://github.com/rubygems/bundler/issues/1232)) + - Fix HTTP proxy support (@leobessa, [#878](https://github.com/rubygems/bundler/issues/878)) + +## Features: + + - Speed up `install --deployment` by using the API endpoint + - Support Basic HTTP Auth for the API endpoint (@dpiddy, [#1229](https://github.com/rubygems/bundler/issues/1229)) + - Add `install --full-index` to disable the API endpoint, just in case + - Significantly speed up install by removing unneeded gemspec fetches + - `outdated` command shows outdated gems (@joelmoss, [#1130](https://github.com/rubygems/bundler/issues/1130)) + - Print gem post install messages (@csquared, [#1155](https://github.com/rubygems/bundler/issues/1155)) + - Reduce memory use by removing Specification.new inside method_missing (@tenderlove, [#1222](https://github.com/rubygems/bundler/issues/1222)) + - Allow `check --path` + +# 1.1.pre.4 (May 5, 2011) + +## Bug fixes: + + - Fix bug that could prevent installing new gems + +# 1.1.pre.3 (May 4, 2011) + +## Features: + + - Add `bundle outdated` to show outdated gems (@joelmoss) + - Remove BUNDLE_* from `Bundler.with_clean_env` (@wuputah) + - Add Bundler.clean_system, and clean_exec (@wuputah) + - Use git config for gem author name and email (@krekoten) + +## Bug fixes: + + - Fix error calling Bundler.rubygems.gem_path + - Fix error when Gem.path returns Gem::FS instead of String + +# 1.1.pre.2 (April 28, 2011) + +## Features: + + - Add :github option to Gemfile DSL for easy git repos + - Merge all fixes from 1.0.12 and 1.0.13 + +# 1.1.pre.1 (February 2, 2011) + +## Bug fixes: + + - Compatibility with changes made by Rubygems 1.5 + +# 1.1.pre (January 21, 2011) + +## Features: + + - Add bundle clean. Removes unused gems from --path directory + - Initial Gemcutter Endpoint API work, BAI Fetching source index + - Added bundle install --standalone + - Ignore Gemfile.lock when building new gems + - Make it possible to override a .gemspec dependency's source in the + Gemfile + +## Breaking changes: + + - Removed bundle lock + - Removed bundle install + - Removed bundle install --production + - Removed bundle install --disable-shared-gems + +# 1.0.21 (September 30, 2011) + + No changes. + +# 1.0.21.rc (September 29, 2011) + +## Bug fixes: + + - Load Psych unless Syck is defined, because 1.9.2 defines YAML + +# 1.0.20 (September 27, 2011) + +## Features: + + - Add platform :maglev (@timfel, [#1444](https://github.com/rubygems/bundler/issues/1444)) + +## Bug fixes: + + - Ensure YAML is required even if Psych is found + - Handle directory names that contain invalid regex characters + +# 1.0.20.rc (September 18, 2011) + +## Features: + + - Rescue interrupts to `bundle` while loading bundler.rb ([#1395](https://github.com/rubygems/bundler/issues/1395)) + - Allow clearing without groups by passing `--without ''` ([#1259](https://github.com/rubygems/bundler/issues/1259)) + +## Bug fixes: + + - Manually sort requirements in the lockfile ([#1375](https://github.com/rubygems/bundler/issues/1375)) + - Remove several warnings generated by ruby -w (@stephencelis) + - Handle trailing slashes on names passed to `gem` ([#1372](https://github.com/rubygems/bundler/issues/1372)) + - Name modules for gems like 'test-foo_bar' correctly ([#1303](https://github.com/rubygems/bundler/issues/1303)) + - Don't require Psych if Syck is already loaded ([#1239](https://github.com/rubygems/bundler/issues/1239)) + +# 1.0.19.rc (September 13, 2011) + +## Features: + + - Compatibility with Rubygems 1.8.10 installer changes + - Report gem installation failures clearly (@rwilcox, [#1380](https://github.com/rubygems/bundler/issues/1380)) + - Useful error for cap and vlad on first deploy (@nexmat, @kirs) + +## Bug fixes: + + - `exec` now works when the command contains 'exec' + - Only touch lock after changes on Windows (@robertwahler, [#1358](https://github.com/rubygems/bundler/issues/1358)) + - Keep load paths when #setup is called multiple times (@radsaq, [#1379](https://github.com/rubygems/bundler/issues/1379)) + +# 1.0.18 (August 16, 2011) + +## Bug fixes: + + - Fix typo in DEBUG_RESOLVER (@geemus) + - Fixes rake 0.9.x warning (@mtylty, [#1333](https://github.com/rubygems/bundler/issues/1333)) + - Fix `bundle cache` again for rubygems 1.3.x + +## Features: + + - Run the bundle install earlier in a Capistrano deployment (@cgriego, [#1300](https://github.com/rubygems/bundler/issues/1300)) + - Support hidden gemspec (@trans, @cldwalker, [#827](https://github.com/rubygems/bundler/issues/827)) + - Make fetch_specs faster (@zeha, [#1294](https://github.com/rubygems/bundler/issues/1294)) + - Allow overriding development deps loaded by #gemspec (@lgierth, [#1245](https://github.com/rubygems/bundler/issues/1245)) + +# 1.0.17 (August 8, 2011) + +## Bug fixes: + + - Fix rake issues with rubygems 1.3.x ([#1342](https://github.com/rubygems/bundler/issues/1342)) + - Fixed invalid byte sequence error while installing gem on Ruby 1.9 ([#1341](https://github.com/rubygems/bundler/issues/1341)) + +# 1.0.16 (August 8, 2011) + +## Features: + + - Performance fix for MRI 1.9 (@efficientcloud, [#1288](https://github.com/rubygems/bundler/issues/1288)) + - Shortcuts (like `bundle i`) for all commands (@amatsuda) + - Correctly identify missing child dependency in error message + +## Bug fixes: + + - Allow Windows network share paths with forward slashes (@mtscout6, [#1253](https://github.com/rubygems/bundler/issues/1253)) + - Check for rubygems.org credentials so `rake release` doesn't hang ([#980](https://github.com/rubygems/bundler/issues/980)) + - Find cached prerelease gems on rubygems 1.3.x (@dburt, [#1202](https://github.com/rubygems/bundler/issues/1202)) + - Fix `bundle install --without` on kiji (@tmm1, [#1287](https://github.com/rubygems/bundler/issues/1287)) + - Get rid of warning in ruby 1.9.3 (@smartinez87, [#1231](https://github.com/rubygems/bundler/issues/1231)) + +## Documentation: + + - Documentation for `gem ..., :require => false` (@kmayer, [#1292](https://github.com/rubygems/bundler/issues/1292)) + - Gems provide "executables", they are rarely also binaries (@fxn, [#1242](https://github.com/rubygems/bundler/issues/1242)) + +# 1.0.15 (June 9, 2011) + +## Features: + + - Improved Rubygems integration, removed many deprecation notices + +## Bug fixes: + + - Escape URL arguments to git correctly on Windows (1.0.14 regression) + +# 1.0.14 (May 27, 2011) + +## Features: + + - Rubinius platform :rbx (@rkbodenner) + - Include gem rake tasks with "require 'bundler/gem_tasks" (@indirect) + - Include user name and email from git config in new gemspec (@ognevsky) + +## Bug fixes: + + - Set file permissions after checking out git repos (@tissak) + - Remove deprecated call to Gem::SourceIndex#all_gems (@mpj) + - Require the version file in new gemspecs (@rubiii) + - Allow relative paths from the Gemfile in gems with no gemspec (@mbirk) + - Install gems that contain 'bundler', e.g. guard-bundler (@hone) + - Display installed path correctly on Windows (@tadman) + - Escape quotes in git URIs (@mheffner) + - Improve Rake 0.9 support (@quix) + - Handle certain directories already existing (@raggi) + - Escape filenames containing regex characters (@indirect) + +# 1.0.13 (May 4, 2011) + +## Features: + + - Compatibility with Rubygems master (soon to be v1.8) (@evanphx) + - Informative error when --path points to a broken symlink + - Support Rake 0.9 and greater (@e2) + - Output full errors for non-TTYs e.g. pow (@josh) + +## Bug fixes: + + - Allow spaces in gem path names for gem tasks (@rslifka) + - Have cap run bundle install from release_path (@martinjagusch) + - Quote git refspec so zsh doesn't expand it (@goneflyin) + +# 1.0.12 (April 8, 2011) + +## Features: + + - Add --no-deployment option to `install` for disabling it on dev machines + - Better error message when git fails and cache is present (@parndt) + - Honor :bundle_cmd in cap `rake` command (@voidlock, @cgriego) + +## Bug fixes: + + - Compatibility with Rubygems 1.7 and Rails 2.3 and vendored gems (@evanphx) + - Fix changing gem order in lock (@gucki) + - Remove color escape sequences when displaying man pages (@bgreenlee) + - Fix creating GEM_HOME on both JRuby 1.5 and 1.6 (@nickseiger) + - Fix gems without a gemspec and directories in bin/ (@epall) + - Fix --no-prune option for `bundle install` (@cmeiklejohn) + +# 1.0.11 (April 1, 2011) + +## Features: + + - Compatibility with Rubygems 1.6 and 1.7 + - Better error messages when a git command fails + +## Bug fixes: + + - Don't always update gemspec gems (@carllerche) + - Remove ivar warnings (@jackdempsey) + - Fix occasional git failures in zsh (@jonah-carbonfive) + - Consistent lock for gems with double deps like Cap (@akahn) + +# 1.0.10 (February 1, 2011) + +## Bug fixes: + + - Fix a regression loading YAML gemspecs from :git and :path gems + - Requires, namespaces, etc. to work with changes in Rubygems 1.5 + +# 1.0.9 (January 19, 2011) + +## Bug fixes: + + - Fix a bug where Bundler.require could remove gems from the load + path. In Rails apps with a default application.rb, this removed + all gems in groups other than :default and Rails.env + +# 1.0.8 (January 18, 2011) + +## Features: + + - Allow overriding gemspec() deps with :git deps + - Add --local option to `bundle update` + - Ignore Gemfile.lock in newly generated gems + - Use `less` as help pager instead of `more` + - Run `bundle exec rake` instead of `rake` in Capistrano tasks + +## Bug fixes: + + - Fix --no-cache option for `bundle install` + - Allow Vlad deploys to work without Capistrano gem installed + - Fix group arguments to `bundle console` + - Allow groups to be loaded even if other groups were loaded + - Evaluate gemspec() gemspecs in their directory not the cwd + - Count on Rake to chdir to the right place in GemHelper + - Change Pathnames to Strings for MacRuby + - Check git process exit status correctly + - Fix some warnings in 1.9.3-trunk (thanks tenderlove) + +# 1.0.7 (November 17, 2010) + +## Bug fixes: + + - Remove Bundler version from the lockfile because it broke + backwards compatibility with 1.0.0-1.0.5. Sorry. :( + +# 1.0.6 (November 16, 2010) + +## Bug fixes: + + - Fix regression in `update` that caused long/wrong results + - Allow git gems on other platforms while installing ([#579](https://github.com/rubygems/bundler/issues/579)) + +## Features: + + - Speed up `install` command using various optimizations + - Significantly increase performance of resolver + - Use upcoming Rubygems performance improvements (@tmm1) + - Warn if the lockfile was generated by a newer version + - Set generated gems' homepage to "", so Rubygems will warn + +# 1.0.5 (November 13, 2010) + +## Bug fixes: + + - Fix regression disabling all operations that employ sudo + +# 1.0.4 (November 12, 2010) + +## Bug fixes: + + - Expand relative :paths from Bundler.root (eg ./foogem) + - Allow git gems in --without groups while --frozen + - Allow gem :ref to be a symbol as well as a string + - Fix exception when Gemfile needs a newer Bundler version + - Explanation when the current Bundler version conflicts + - Explicit error message if Gemfile needs newer Bundler + - Ignore an empty string BUNDLE_GEMFILE + - Skeleton gemspec now works with older versions of git + - Fix shell quoting and ref fetching in GemHelper + - Disable colored output in --deployment + - Preserve line endings in lock file + +## Features: + + - Add support for 'mingw32' platform (aka RubyInstaller) + - Large speed increase when Gemfile.lock is already present + - Huge speed increase when many (100+) system gems are present + - Significant expansion of ISSUES, man pages, and docs site + - Remove Open3 from GemHelper (now it works on Windows™®©) + - Allow setting roles in built-in cap and vlad tasks + +# 1.0.3 (October 15, 2010) + +## Bug fixes: + + - Use bitwise or in #hash to reduce the chance of overflow + - `bundle update` now works with :git + :tag updates + - Record relative :path options in the Gemfile.lock + - :groups option on gem method in Gemfile now works + - Add #platform method and :platform option to Gemfile DSL + - --without now accepts a quoted, space-separated list + - Installing after --deployment with no lock is now possible + - Binstubs can now be symlinked + - Print warning if cache for --local install is missing gems + - Improve output when installing to a path + - The tests all pass! Yay! + +# 1.0.2 (October 2, 2010) + +## Bug fixes: + + - Actually include the man pages in the gem, so help works + +# 1.0.1 (October 1, 2010) + +## Features: + + - Vlad deployment recipe, `require 'bundler/vlad'` + - Prettier bundle graphs + - Improved gem skeleton for `bundle gem` + - Prompt on file clashes when generating a gem + - Option to generate binary with gem skeleton + - Allow subclassing of GemHelper for custom tasks + - Chdir to gem directory during `bundle open` + +## Bug fixes: + + - Allow gemspec requirements with a list of versions + - Accept lockfiles with windows line endings + - Respect BUNDLE_WITHOUT env var + - Allow `gem "foo", :platform => :jruby` + - Specify loaded_from path in fake gemspec + - Flesh out gem_helper tasks, raise errors correctly + - Respect RBConfig::CONFIG['ruby_install_name'] in binstubs + +# 1.0.0 (August 29, 2010) + +## Features: + + - You can now define `:bundle_cmd` in the capistrano task + +## Bug fixes: + + - Various bugfixes to the built-in rake helpers + - Fix a bug where shortrefs weren't unique enough and were + therefore colliding + - Fix a small bug involving checking whether a local git + clone is up to date + - Correctly handle explicit '=' dependencies with gems + pinned to a git source + - Fix an issue with Windows-generated lockfiles by reading + and writing the lockfile in binary mode + - Fix an issue with shelling out to git in Windows by + using double quotes around paths + - Detect new Rubygems sources in the Gemfile and update + the lockfile + +# 1.0.0.rc.6 (August 23, 2010) + +## Features: + + - Much better documentation for most of the commands and Gemfile + format + +## Bug fixes: + + - Don't attempt to create directories if they already exist + - Fix the capistrano task so that it actually runs + - Update the Gemfile template to reference rubygems.org instead + of :gemcutter + - bundle exec should exit with a non zero exit code when the gem + binary does not exist or the file is not executable. + - Expand paths in Gemfile relative to the Gemfile and not the current + working directory. + +# 1.0.0.rc.5 (August 10, 2010) + +## Features: + + - Make the Capistrano task more concise. + +## Bug fixes: + + - Fix a regression with determining whether or not to use sudo + - Allow using the --gemfile flag with the --deployment flag + +# 1.0.0.rc.4 (August 9, 2010) + +## Features: + + - `bundle gem NAME` command to generate a new gem with Gemfile + - Bundle config file location can be specified by BUNDLE_APP_CONFIG + - Add --frozen to disable updating the Gemfile.lock at runtime + (default with --deployment) + - Basic Capistrano task now added as 'bundler/capistrano' + +## Bug fixes: + + - Multiple bundler process no longer share a tmp directory + - `bundle update GEM` always updates dependencies of GEM as well + - Deleting the cache directory no longer causes errors + - Moving the bundle after installation no longer causes git errors + - Bundle path is now correctly remembered on a read-only filesystem + - Gem binaries are installed to Gem.bindir, not #{Gem.dir}/bin + - Fetch gems from vendor/cache, even without --local + - Sort lockfile by platform as well as spec + +# 1.0.0.rc.3 (August 3, 2010) + +## Features: + + - Deprecate --production flag for --deployment, since the former + was causing confusion with the :production group + - Add --gemfile option to `bundle check` + - Reduce memory usage of `bundle install` by 2-4x + - Improve message from `bundle check` under various conditions + - Better error when a changed Gemfile conflicts with Gemfile.lock + +## Bug fixes: + + - Create bin/ directory if it is missing, then install binstubs + - Error nicely on the edge case of a pinned gem with no spec + - Do not require gems for other platforms + - Update git sources along with the gems they contain + +# 1.0.0.rc.2 (July 29, 2010) + + - `bundle install path` was causing confusion, so we now print + a clarifying warning. The preferred way to install to a path + (which will not print the warning) is + `bundle install --path path/to/install`. + - `bundle install --system` installs to the default system + location ($BUNDLE_PATH or $GEM_HOME) even if you previously + used `bundle install --path` + - completely remove `--disable-shared-gems`. If you install to + system, you will not be isolated, while if you install to + another path, you will be isolated from gems installed to + the system. This was mostly an internal option whose naming + and semantics were extremely confusing. + - Add a `--production` option to `bundle install`: + - by default, installs to `vendor/bundle`. This can be + overridden with the `--path` option + - uses `--local` if `vendor/cache` is found. This will + guarantee that Bundler does not attempt to connect to + Rubygems and will use the gems cached in `vendor/cache` + instead + - Raises an exception if a Gemfile.lock is not found + - Raises an exception if you modify your Gemfile in development + but do not check in an updated Gemfile.lock + - Fixes a bug where switching a source from Rubygems to git + would always say "the git source is not checked out" when + running `bundle install` + + NOTE: We received several reports of "the git source has not + been checked out. Please run bundle install". As far as we + can tell, these problems have two possible causes: + + 1. `bundle install ~/.bundle` in one user, but actually running + the application as another user. Never install gems to a + directory scoped to a user (`~` or `$HOME`) in deployment. + 2. A bug that happened when changing a gem to a git source. + + To mitigate several common causes of `(1)`, please use the + new `--production` flag. This flag is simply a roll-up of + the best practices we have been encouraging people to use + for deployment. + + If you want to share gems across deployments, and you use + Capistrano, symlink release_path/current/vendor/bundle to + release_path/shared/bundle. This will keep deployments + snappy while maintaining the benefits of clean, deploy-time + isolation. + +# 1.0.0.rc.1 (July 26, 2010) + + - Fixed a bug with `bundle install` on multiple machines and git + +# 1.0.0.beta.10 (July 25, 2010) + + - Last release before 1.0.0.rc.1 + - Added :mri as a valid platform (platforms :mri { gem "ruby-debug" }) + - Fix `bundle install` immediately after modifying the :submodule option + - Don't write to Gemfile.lock if nothing has changed, fixing situations + where bundle install was run with a different user than the app + itself + - Fix a bug where other platforms were being wiped on `bundle update` + - Don't ask for root password on `bundle install` if not needed + - Avoid setting `$GEM_HOME` where not needed + - First solid pass of `bundle config` + - Add build options + - `bundle config build.mysql --with-mysql-config=/path/to/config` + +# 1.0.0.beta.9 (July 21, 2010) + + - Fix install failure when switching from a path to git source + - Fix `bundle exec bundle *` in a bundle with --disable-shared-gems + - Fix `bundle *` from inside a bundle with --disable-shared-gem + - Shim Gem.refresh. This is used by Unicorn + - Fix install failure when a path's dependencies changed + +# 1.0.0.beta.8 (July 20, 2010) + + - Fix a Beta 7 bug involving Ruby 1.9 + +# 1.0.0.beta.7 (July 20, 2010, yanked) + + - Running `bundle install` twice in a row with a git source always crashed + +# 1.0.0.beta.6 (July 20, 2010, yanked) + + - Create executables with bundle install --binstubs + - You can customize the location (default is app/bin) with --binstubs other/location + - Fix a bug where the Gemfile.lock would be deleted even if the update was exited + - Fix a bug where cached gems for other platforms were sometimes deleted + - Clean up output when nothing was deleted from cache (it previously said + "Removing outdated gems ...") + - Improve performance of bundle install if the git gem was already checked out, + and the revision being used already exists locally + - Fix bundle show bundler in some cases + - Fix bugs with bundle update + - Don't ever run git commands at runtime (fixes a number of common passenger issues) + - Fixes an obscure bug where switching the source of a gem could fail to correctly + change the source of its dependencies + - Support multiple version dependencies in the Gemfile + (`gem "rails", ">= 3.0.0.beta1", "<= 3.0.0"`) + - Raise an exception for ambiguous uses of multiple declarations of the same gem + (for instance, with different versions or sources). + - Fix cases where the same dependency appeared several times in the Gemfile.lock + - Fix a bug where require errors were being swallowed during Bundler.require + +# 1.0.0.beta.1 + + - No `bundle lock` command. Locking happens automatically on install or update + - No .bundle/environment.rb. Require 'bundler/setup' instead. + - $BUNDLE_HOME defaults to $GEM_HOME instead of ~/.bundle + - Remove lockfiles generated by 0.9 + +# 0.9.26 + +## Features: + + - error nicely on incompatible 0.10 lockfiles + +# 0.9.25 (May 3, 2010) + +## Bug fixes: + + - explicitly coerce Pathname objects to Strings for Ruby 1.9 + - fix some newline weirdness in output from install command + +# 0.9.24 (April 22, 2010) + +## Features: + + - fetch submodules for git sources + - limit the bundled version of bundler to the same as the one installing + - force relative paths in git gemspecs to avoid raising Gem::NameTooLong + - serialize GemCache sources correctly, so locking works + - raise Bundler::GemNotFound instead of calling exit! inside library code + - Rubygems 1.3.5 compatibility for the adventurous, not supported by me :) + +## Bug fixes: + + - don't try to regenerate environment.rb if it is read-only + - prune outdated gems with the platform "ruby" + - prune cache without errors when there are directories or non-gem files + - don't re-write environment.rb if running after it has been loaded + - do not monkeypatch Specification#load_paths twice when inside a bundle + +# 0.9.23 (April 20, 2010) + +## Bug fixes: + + - cache command no longer prunes gems created by an older rubygems version + - cache command no longer prunes gems that are for other platforms + +# 0.9.22 (April 20, 2010) + +## Features: + + - cache command now prunes stale .gem files from vendor/cache + - init --gemspec command now generates development dependencies + - handle Polyglot's changes to Kernel#require with Bundler::ENV_LOADED ([#287](https://github.com/rubygems/bundler/issues/287)) + - remove .gem files generated after installing a gem from a :path ([#286](https://github.com/rubygems/bundler/issues/286)) + - improve install/lock messaging ([#284](https://github.com/rubygems/bundler/issues/284)) + +## Bug fixes: + + - ignore cached gems that are for another platform ([#288](https://github.com/rubygems/bundler/issues/288)) + - install Windows gems that have no architecture set, like rcov ([#277](https://github.com/rubygems/bundler/issues/277)) + - exec command while locked now includes the bundler lib in $LOAD_PATH ([#293](https://github.com/rubygems/bundler/issues/293)) + - fix the `rake install` task + - add GemspecError so it can be raised without (further) error ([#292](https://github.com/rubygems/bundler/issues/292)) + - create a parent directory before cloning for git 1.5 compatibility ([#285](https://github.com/rubygems/bundler/issues/285)) + +# 0.9.21 (April 16, 2010) + +## Bug fixes: + + - don't raise 'omg wtf' when lockfile is outdated + +# 0.9.20 (April 15, 2010) + +## Features: + + - load YAML format gemspecs + - no backtraces when calling Bundler.setup if gems are missing + - no backtraces when trying to exec a file without the executable bit + +## Bug fixes: + + - fix infinite recursion in Bundler.setup after loading a bundled Bundler gem + - request install instead of lock when env.rb is out of sync with Gemfile.lock + +# 0.9.19 (April 12, 2010) + +## Features: + + - suggest `bundle install --relock` when the Gemfile has changed ([#272](https://github.com/rubygems/bundler/issues/272)) + - source support for Rubygems servers without prerelease gem indexes ([#262](https://github.com/rubygems/bundler/issues/262)) + +## Bug fixes: + + - don't set up all groups every time Bundler.setup is called while locked ([#263](https://github.com/rubygems/bundler/issues/263)) + - fix #full_gem_path for git gems while locked ([#268](https://github.com/rubygems/bundler/issues/268)) + - eval gemspecs at the top level, not inside the Bundler class ([#269](https://github.com/rubygems/bundler/issues/269)) + + +# 0.9.18 (April 8, 2010) + +## Features: + + - console command that runs irb with bundle (and optional group) already loaded + +## Bug fixes: + + - Bundler.setup now fully disables system gems, even when unlocked ([#266](https://github.com/rubygems/bundler/issues/266), [#246](https://github.com/bundler/bundler/issues/246)) + - fixes Yard, which found plugins in Gem.source_index that it could not load + - makes behaviour of `Bundler.require` consistent between locked and unlocked loads + +# 0.9.17 (April 7, 2010) + +## Features: + + - Bundler.require now calls Bundler.setup automatically + - Gem::Specification#add_bundler_dependencies added for gemspecs + +## Bug fixes: + + - Gem paths are not longer duplicated while loading bundler + - exec no longer duplicates RUBYOPT if it is already set correctly + +# 0.9.16 (April 3, 2010) + +## Features: + + - exit gracefully on INT signal + - resolver output now indicates whether remote sources were checked + - print error instead of backtrace when exec cannot find a binary ([#241](https://github.com/rubygems/bundler/issues/241)) + +## Bug fixes: + + - show, check, and open commands work again while locked (oops) + - show command for git gems + - outputs branch names other than master + - gets the correct sha from the checkout + - doesn't print sha twice if :ref is set + - report errors from bundler/setup.rb without backtraces ([#243](https://github.com/rubygems/bundler/issues/243)) + - fix Gem::Spec#git_version to not error on unloaded specs + - improve deprecation, Gemfile, and command error messages ([#242](https://github.com/rubygems/bundler/issues/242)) + +# 0.9.15 (April 1, 2010) + +## Features: + + - use the env_file if possible instead of doing a runtime resolve + - huge speedup when calling Bundler.setup while locked + - ensures bundle exec is fast while locked + - regenerates env_file if it was generated by an older version + - update cached/packed gems when you update gems via bundle install + +## Bug fixes: + + - prep for Rubygems 1.3.7 changes + - install command now pulls git branches correctly ([#211](https://github.com/rubygems/bundler/issues/211)) + - raise errors on invalid options in the Gemfile + +# 0.9.14 (March 30, 2010) + +## Features: + + - install command output vastly improved + - installation message now accurate, with 'using' and 'installing' + - bundler gems no longer listed as 'system gems' + - show command output now includes sha and branch name for git gems + - init command now takes --gemspec option for bootstrapping gem Gemfiles + - Bundler.with_clean_env for shelling out to ruby scripts + - show command now aliased as 'list' + - VISUAL env var respected for GUI editors + +## Bug fixes: + + - exec command now finds binaries from gems with no gemspec + - note source of Gemfile resolver errors + - don't blow up if git urls are changed + +# 0.9.13 (March 23, 2010) + +## Bug fixes: + + - exec command now finds binaries from gems installed via :path + - gem dependencies are pulled in even if their type is nil + - paths with spaces have double-quotes to work on Windows + - set GEM_PATH in environment.rb so generators work with Rails 2 + +# 0.9.12 (March 17, 2010) + + - refactoring, internal cleanup, more solid specs + +## Features: + + - check command takes a --without option + - check command exits 1 if the check fails + +## Bug fixes: + + - perform a topological sort on resolved gems ([#191](https://github.com/rubygems/bundler/issues/191)) + - gems from git work even when paths or repos have spaces ([#196](https://github.com/rubygems/bundler/issues/196)) + - Specification#loaded_from returns a String, like Gem::Specification ([#197](https://github.com/rubygems/bundler/issues/197)) + - specs eval from inside the gem directory, even when locked + - virtual gemspecs are now saved in environment.rb for use when loading + - unify the Installer's local index and the runtime index ([#204](https://github.com/rubygems/bundler/issues/204)) + +# 0.9.11 (March 9, 2010) + + - added roadmap with future development plans + +## Features: + + - install command can take the path to the gemfile with --gemfile ([#125](https://github.com/rubygems/bundler/issues/125)) + - unknown command line options are now rejected ([#163](https://github.com/rubygems/bundler/issues/163)) + - exec command hugely sped up while locked ([#177](https://github.com/rubygems/bundler/issues/177)) + - show command prints the install path if you pass it a gem name ([#148](https://github.com/rubygems/bundler/issues/148)) + - open command edits an installed gem with $EDITOR ([#148](https://github.com/rubygems/bundler/issues/148)) + - Gemfile allows assigning an array of groups to a gem ([#114](https://github.com/rubygems/bundler/issues/114)) + - Gemfile allows :tag option on :git sources + - improve backtraces when a gemspec is invalid + - improve performance by installing gems from the cache if present + +## Bug fixes: + + - normalize parameters to Bundler.require ([#153](https://github.com/rubygems/bundler/issues/153)) + - check now checks installed gems rather than cached gems ([#162](https://github.com/rubygems/bundler/issues/162)) + - don't update the gem index when installing after locking ([#169](https://github.com/rubygems/bundler/issues/169)) + - bundle parenthesises arguments for 1.8.6 ([#179](https://github.com/rubygems/bundler/issues/179)) + - gems can now be assigned to multiple groups without problems ([#135](https://github.com/rubygems/bundler/issues/135)) + - fix the warning when building extensions for a gem from git with Rubygems 1.3.6 + - fix a Dependency.to_yaml error due to accidentally including sources and groups + - don't reinstall packed gems + - fix gems with git sources that are private repositories + +# 0.9.10 (March 1, 2010) + + - depends on Rubygems 1.3.6 + +## Bug fixes: + + - support locking after install --without + - don't reinstall gems from the cache if they're already in the bundle + - fixes for Ruby 1.8.7 and 1.9 + +# 0.9.9 (February 25, 2010) + +## Bug fixes: + + - don't die if GEM_HOME is an empty string + - fixes for Ruby 1.8.6 and 1.9 + +# 0.9.8 (February 23, 2010) + +## Features: + + - pack command which both caches and locks + - descriptive error if a cached gem is missing + - remember the --without option after installing + - expand paths given in the Gemfile via the :path option + - add block syntax to the git and group options in the Gemfile + - support gems with extensions that don't admit they depend on rake + - generate gems using gem build gemspec so git gems can have native extensions + - print a useful warning if building a gem fails + - allow manual configuration via BUNDLE_PATH + +## Bug fixes: + + - eval gemspecs in the gem directory so relative paths work + - make default spec for git sources valid + - don't reinstall gems that are already packed + +# 0.9.7 (February 17, 2010) + +## Bug fixes: + + - don't say that a gem from an excluded group is "installing" + - improve crippling rubygems in locked scenarios + +# 0.9.6 (February 16, 2010) + +## Features: + + - allow String group names + - a number of improvements in the documentation and error messages + +## Bug fixes: + + - set SourceIndex#spec_dirs to solve a problem involving Rails 2.3 in unlocked mode + - ensure Rubygems is fully loaded in Ruby 1.9 before patching it + - fix `bundle install` for a locked app without a .bundle directory + - require gems in the order that the resolver determines + - make the tests platform agnostic so we can confirm that they're green on JRuby + - fixes for Ruby 1.9 + +# 0.9.5 (February 12, 2010) + +## Features: + + - added support for :path => "relative/path" + - added support for older versions of git + - added `bundle install --disable-shared-gems` + - Bundler.require fails silently if a library does not have a file on the load path with its name + - Basic support for multiple rubies by namespacing the default bundle path using the version and engine + +## Bug fixes: + + - if the bundle is locked and .bundle/environment.rb is not present when Bundler.setup is called, generate it + - same if it's not present with `bundle check` + - same if it's not present with `bundle install` diff --git a/bin/gems/bundler-2.5.9/LICENSE.md b/bin/gems/bundler-2.5.9/LICENSE.md new file mode 100644 index 00000000..52b5c213 --- /dev/null +++ b/bin/gems/bundler-2.5.9/LICENSE.md @@ -0,0 +1,22 @@ +The MIT License + +Portions copyright (c) 2010-2019 André Arko +Portions copyright (c) 2009 Engine Yard + +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/bin/gems/bundler-2.5.9/README.md b/bin/gems/bundler-2.5.9/README.md new file mode 100644 index 00000000..18e956e1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/README.md @@ -0,0 +1,58 @@ +[![Version ](https://img.shields.io/gem/v/bundler.svg?style=flat)](https://rubygems.org/gems/bundler) + +# Bundler: a gem to bundle gems + +Bundler makes sure Ruby applications run the same code on every machine. + +It does this by managing the gems that the application depends on. Given a list of gems, it can automatically download and install those gems, as well as any other gems needed by the gems that are listed. Before installing gems, it checks the versions of every gem to make sure that they are compatible, and can all be loaded at the same time. After the gems have been installed, Bundler can help you update some or all of them when new versions become available. Finally, it records the exact versions that have been installed, so that others can install the exact same gems. + +### Installation and usage + +To install (or update to the latest version): + +``` +gem install bundler +``` + +To install a prerelease version (if one is available), run `gem install bundler --pre`. To uninstall Bundler, run `gem uninstall bundler`. + +Bundler is most commonly used to manage your application's dependencies. For example, these commands will allow you to use Bundler to manage the `rspec` gem for your application: + +``` +bundle init +bundle add rspec +bundle install +bundle exec rspec +``` + +See [bundler.io](https://bundler.io) for the full documentation. + +### Troubleshooting + +For help with common problems, see [TROUBLESHOOTING](doc/TROUBLESHOOTING.md). + +Still stuck? Try [filing an issue](https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md). + +### Other questions + +To see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANGELOG.md). + +To get in touch with the Bundler core team and other Bundler users, please join [the Bundler slack](https://join.slack.com/t/bundler/shared_invite/zt-1rrsuuv3m-OmXKWQf8K6iSla4~F1DBjQ). + +### Contributing + +If you'd like to contribute to Bundler, that's awesome, and we <3 you. We've put together [the Bundler contributor guide](https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/README.md) with all of the information you need to get started. + +If you'd like to request a substantial change to Bundler or its documentation, refer to the [Bundler RFC process](https://github.com/rubygems/rfcs) for more information. + +### Supporting + +RubyGems is managed by [Ruby Central](https://rubycentral.org), a non-profit organization that supports the Ruby community through projects like this one, as well as [RubyConf](https://rubyconf.org), [RailsConf](https://railsconf.org), and [RubyGems.org](https://rubygems.org). You can support Ruby Central by attending or [sponsoring](sponsors@rubycentral.org) a conference, or by [joining as a supporting member](https://rubycentral.org/#/portal/signup). + +### Code of Conduct + +Everyone interacting in the Bundler project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [Bundler code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md). + +### License + +Bundler is available under an [MIT License](https://github.com/rubygems/rubygems/blob/master/bundler/LICENSE.md). diff --git a/bin/gems/bundler-2.5.9/bundler.gemspec b/bin/gems/bundler-2.5.9/bundler.gemspec new file mode 100644 index 00000000..0a05d7de --- /dev/null +++ b/bin/gems/bundler-2.5.9/bundler.gemspec @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +begin + require_relative "lib/bundler/version" +rescue LoadError + # for Ruby core repository + require_relative "version" +end + +Gem::Specification.new do |s| + s.name = "bundler" + s.version = Bundler::VERSION + s.license = "MIT" + s.authors = [ + "André Arko", "Samuel Giddins", "Colby Swandale", "Hiroshi Shibata", + "David Rodríguez", "Grey Baker", "Stephanie Morillo", "Chris Morris", "James Wen", "Tim Moore", + "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", + "Yehuda Katz" + ] + s.email = ["team@bundler.io"] + s.homepage = "https://bundler.io" + s.summary = "The best way to manage your application's dependencies" + s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably" + + s.metadata = { + "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler", + "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md", + "homepage_uri" => "https://bundler.io/", + "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler", + } + + s.required_ruby_version = ">= 3.0.0" + + # It should match the RubyGems version shipped with `required_ruby_version` above + s.required_rubygems_version = ">= 3.2.3" + + s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + + # include the gemspec itself because warbler breaks w/o it + s.files += %w[bundler.gemspec] + + s.files += %w[CHANGELOG.md LICENSE.md README.md] + s.bindir = "exe" + s.executables = %w[bundle bundler] + s.require_paths = ["lib"] +end diff --git a/bin/gems/bundler-2.5.9/exe/bundle b/bin/gems/bundler-2.5.9/exe/bundle new file mode 100755 index 00000000..92387bc2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/exe/bundle @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Exit cleanly from an early interrupt +Signal.trap("INT") do + Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) + exit 1 +end + +base_path = File.expand_path("../lib", __dir__) + +if File.exist?(base_path) + $LOAD_PATH.unshift(base_path) +end + +require "bundler" + +require "bundler/friendly_errors" + +Bundler.with_friendly_errors do + require "bundler/cli" + + # Allow any command to use --help flag to show help for that command + help_flags = %w[--help -h] + help_flag_used = ARGV.any? {|a| help_flags.include? a } + args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV + + Bundler::CLI.start(args, debug: true) +end diff --git a/bin/gems/bundler-2.5.9/exe/bundler b/bin/gems/bundler-2.5.9/exe/bundler new file mode 100755 index 00000000..a6826a8c --- /dev/null +++ b/bin/gems/bundler-2.5.9/exe/bundler @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +load File.expand_path("bundle", __dir__) diff --git a/bin/gems/bundler-2.5.9/lib/bundler.rb b/bin/gems/bundler-2.5.9/lib/bundler.rb new file mode 100644 index 00000000..59a1107b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler.rb @@ -0,0 +1,664 @@ +# frozen_string_literal: true + +require_relative "bundler/vendored_fileutils" +require "pathname" +require "rbconfig" + +require_relative "bundler/errors" +require_relative "bundler/environment_preserver" +require_relative "bundler/plugin" +require_relative "bundler/rubygems_ext" +require_relative "bundler/rubygems_integration" +require_relative "bundler/version" +require_relative "bundler/constants" +require_relative "bundler/current_ruby" +require_relative "bundler/build_metadata" + +# Bundler provides a consistent environment for Ruby projects by +# tracking and installing the exact gems and versions that are needed. +# +# Bundler is a part of Ruby's standard library. +# +# Bundler is used by creating _gemfiles_ listing all the project dependencies +# and (optionally) their versions and then using +# +# require 'bundler/setup' +# +# or Bundler.setup to setup environment where only specified gems and their +# specified versions could be used. +# +# See {Bundler website}[https://bundler.io/docs.html] for extensive documentation +# on gemfiles creation and Bundler usage. +# +# As a standard library inside project, Bundler could be used for introspection +# of loaded and required modules. +# +module Bundler + environment_preserver = EnvironmentPreserver.from_env + ORIGINAL_ENV = environment_preserver.restore + environment_preserver.replace_with_backup + SUDO_MUTEX = Thread::Mutex.new + + autoload :Checksum, File.expand_path("bundler/checksum", __dir__) + autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__) + autoload :Definition, File.expand_path("bundler/definition", __dir__) + autoload :Dependency, File.expand_path("bundler/dependency", __dir__) + autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__) + autoload :Digest, File.expand_path("bundler/digest", __dir__) + autoload :Dsl, File.expand_path("bundler/dsl", __dir__) + autoload :EndpointSpecification, File.expand_path("bundler/endpoint_specification", __dir__) + autoload :Env, File.expand_path("bundler/env", __dir__) + autoload :Fetcher, File.expand_path("bundler/fetcher", __dir__) + autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__) + autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__) + autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__) + autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__) + autoload :Graph, File.expand_path("bundler/graph", __dir__) + autoload :Index, File.expand_path("bundler/index", __dir__) + autoload :Injector, File.expand_path("bundler/injector", __dir__) + autoload :Installer, File.expand_path("bundler/installer", __dir__) + autoload :LazySpecification, File.expand_path("bundler/lazy_specification", __dir__) + autoload :LockfileParser, File.expand_path("bundler/lockfile_parser", __dir__) + autoload :MatchRemoteMetadata, File.expand_path("bundler/match_remote_metadata", __dir__) + autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__) + autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__) + autoload :Resolver, File.expand_path("bundler/resolver", __dir__) + autoload :Retry, File.expand_path("bundler/retry", __dir__) + autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__) + autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__) + autoload :Runtime, File.expand_path("bundler/runtime", __dir__) + autoload :SelfManager, File.expand_path("bundler/self_manager", __dir__) + autoload :Settings, File.expand_path("bundler/settings", __dir__) + autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) + autoload :Source, File.expand_path("bundler/source", __dir__) + autoload :SourceList, File.expand_path("bundler/source_list", __dir__) + autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) + autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) + autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) + autoload :UI, File.expand_path("bundler/ui", __dir__) + autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__) + autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__) + autoload :SafeMarshal, File.expand_path("bundler/safe_marshal", __dir__) + + class << self + def configure + @configure ||= configure_gem_home_and_path + end + + def ui + (defined?(@ui) && @ui) || (self.ui = UI::Shell.new) + end + + def ui=(ui) + Bundler.rubygems.ui = UI::RGProxy.new(ui) + @ui = ui + end + + # Returns absolute path of where gems are installed on the filesystem. + def bundle_path + @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) + end + + def create_bundle_path + mkdir_p(bundle_path) unless bundle_path.exist? + + @bundle_path = bundle_path.realpath + rescue Errno::EEXIST + raise PathError, "Could not install to path `#{bundle_path}` " \ + "because a file already exists at that path. Either remove or rename the file so the directory can be created." + end + + def configured_bundle_path + @configured_bundle_path ||= settings.path.tap(&:validate!) + end + + # Returns absolute location of where binstubs are installed to. + def bin_path + @bin_path ||= begin + path = settings[:bin] || "bin" + path = Pathname.new(path).expand_path(root).expand_path + mkdir_p(path) + path + end + end + + # Turns on the Bundler runtime. After +Bundler.setup+ call, all +load+ or + # +require+ of the gems would be allowed only if they are part of + # the Gemfile or Ruby's standard library. If the versions specified + # in Gemfile, only those versions would be loaded. + # + # Assuming Gemfile + # + # gem 'first_gem', '= 1.0' + # group :test do + # gem 'second_gem', '= 1.0' + # end + # + # The code using Bundler.setup works as follows: + # + # require 'third_gem' # allowed, required from global gems + # require 'first_gem' # allowed, loads the last installed version + # Bundler.setup + # require 'fourth_gem' # fails with LoadError + # require 'second_gem' # loads exactly version 1.0 + # + # +Bundler.setup+ can be called only once, all subsequent calls are no-op. + # + # If _groups_ list is provided, only gems from specified groups would + # be allowed (gems specified outside groups belong to special +:default+ group). + # + # To require all gems from Gemfile (or only some groups), see Bundler.require. + # + def setup(*groups) + # Return if all groups are already loaded + return @setup if defined?(@setup) && @setup + + definition.validate_runtime! + + SharedHelpers.print_major_deprecations! + + if groups.empty? + # Load all groups, but only once + @setup = load.setup + else + load.setup(*groups) + end + end + + # Setups Bundler environment (see Bundler.setup) if it is not already set, + # and loads all gems from groups specified. Unlike ::setup, can be called + # multiple times with different groups (if they were allowed by setup). + # + # Assuming Gemfile + # + # gem 'first_gem', '= 1.0' + # group :test do + # gem 'second_gem', '= 1.0' + # end + # + # The code will work as follows: + # + # Bundler.setup # allow all groups + # Bundler.require(:default) # requires only first_gem + # # ...later + # Bundler.require(:test) # requires second_gem + # + def require(*groups) + setup(*groups).require(*groups) + end + + def load + @load ||= Runtime.new(root, definition) + end + + def environment + SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", print_caller_location: true + load + end + + # Returns an instance of Bundler::Definition for given Gemfile and lockfile + # + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @param lockfile [Pathname] Path to Gemfile.lock + # @return [Bundler::Definition] + def definition(unlock = nil, lockfile = default_lockfile) + @definition = nil if unlock + @definition ||= begin + configure + Definition.build(default_gemfile, lockfile, unlock) + end + end + + def frozen_bundle? + frozen = settings[:frozen] + return frozen unless frozen.nil? + + settings[:deployment] + end + + def locked_gems + @locked_gems ||= + if defined?(@definition) && @definition + definition.locked_gems + elsif Bundler.default_lockfile.file? + lock = Bundler.read_file(Bundler.default_lockfile) + LockfileParser.new(lock) + end + end + + def most_specific_locked_platform?(platform) + return false unless defined?(@definition) && @definition + + definition.most_specific_locked_platform == platform + end + + def ruby_scope + "#{Bundler.rubygems.ruby_engine}/#{RbConfig::CONFIG["ruby_version"]}" + end + + def user_home + @user_home ||= begin + home = Bundler.rubygems.user_home + bundle_home = home ? File.join(home, ".bundle") : nil + + warning = if home.nil? + "Your home directory is not set." + elsif !File.directory?(home) + "`#{home}` is not a directory." + elsif !File.writable?(home) && (!File.directory?(bundle_home) || !File.writable?(bundle_home)) + "`#{home}` is not writable." + end + + if warning + Bundler.ui.warn "#{warning}\n" + user_home = tmp_home_path + Bundler.ui.warn "Bundler will use `#{user_home}' as your home directory temporarily.\n" + user_home + else + Pathname.new(home) + end + end + end + + def user_bundle_path(dir = "home") + env_var, fallback = case dir + when "home" + ["BUNDLE_USER_HOME", proc { Pathname.new(user_home).join(".bundle") }] + when "cache" + ["BUNDLE_USER_CACHE", proc { user_bundle_path.join("cache") }] + when "config" + ["BUNDLE_USER_CONFIG", proc { user_bundle_path.join("config") }] + when "plugin" + ["BUNDLE_USER_PLUGIN", proc { user_bundle_path.join("plugin") }] + else + raise BundlerError, "Unknown user path requested: #{dir}" + end + # `fallback` will already be a Pathname, but Pathname.new() is + # idempotent so it's OK + Pathname.new(ENV.fetch(env_var, &fallback)) + end + + def user_cache + user_bundle_path("cache") + end + + def home + bundle_path.join("bundler") + end + + def install_path + home.join("gems") + end + + def specs_path + bundle_path.join("specifications") + end + + def root + @root ||= begin + SharedHelpers.root + rescue GemfileNotFound + bundle_dir = default_bundle_dir + raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir + Pathname.new(File.expand_path("..", bundle_dir)) + end + end + + def app_config_path + if app_config = ENV["BUNDLE_APP_CONFIG"] + app_config_pathname = Pathname.new(app_config) + + if app_config_pathname.absolute? + app_config_pathname + else + app_config_pathname.expand_path(root) + end + else + root.join(".bundle") + end + end + + def app_cache(custom_path = nil) + path = custom_path || root + Pathname.new(path).join(settings.app_cache_path) + end + + def tmp(name = Process.pid.to_s) + Kernel.send(:require, "tmpdir") + Pathname.new(Dir.mktmpdir(["bundler", name])) + end + + def rm_rf(path) + FileUtils.remove_entry_secure(path) if path && File.exist?(path) + end + + def settings + @settings ||= Settings.new(app_config_path) + rescue GemfileNotFound + @settings = Settings.new(Pathname.new(".bundle").expand_path) + end + + # @return [Hash] Environment present before Bundler was activated + def original_env + ORIGINAL_ENV.clone + end + + # @deprecated Use `unbundled_env` instead + def clean_env + message = + "`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + removed_message = + "`Bundler.clean_env` has been removed in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true) + unbundled_env + end + + # @return [Hash] Environment with all bundler-related variables removed + def unbundled_env + env = original_env + + if env.key?("BUNDLER_ORIG_MANPATH") + env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"] + end + + env.delete_if {|k, _| k[0, 7] == "BUNDLE_" } + + if env.key?("RUBYOPT") + rubyopt = env["RUBYOPT"].split(" ") + rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}") + rubyopt.delete("-rbundler/setup") + env["RUBYOPT"] = rubyopt.join(" ") + end + + if env.key?("RUBYLIB") + rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR) + rubylib.delete(__dir__) + env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR) + end + + env + end + + # Run block with environment present before Bundler was activated + def with_original_env + with_env(original_env) { yield } + end + + # @deprecated Use `with_unbundled_env` instead + def with_clean_env + message = + "`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + removed_message = + "`Bundler.with_clean_env` has been removed in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true) + with_env(unbundled_env) { yield } + end + + # Run block with all bundler-related variables removed + def with_unbundled_env + with_env(unbundled_env) { yield } + end + + # Run subcommand with the environment present before Bundler was activated + def original_system(*args) + with_original_env { Kernel.system(*args) } + end + + # @deprecated Use `unbundled_system` instead + def clean_system(*args) + message = + "`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \ + "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`" + removed_message = + "`Bundler.clean_system` has been removed in favor of `Bundler.unbundled_system`. " \ + "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`" + Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true) + with_env(unbundled_env) { Kernel.system(*args) } + end + + # Run subcommand in an environment with all bundler related variables removed + def unbundled_system(*args) + with_unbundled_env { Kernel.system(*args) } + end + + # Run a `Kernel.exec` to a subcommand with the environment present before Bundler was activated + def original_exec(*args) + with_original_env { Kernel.exec(*args) } + end + + # @deprecated Use `unbundled_exec` instead + def clean_exec(*args) + message = + "`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \ + "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`" + removed_message = + "`Bundler.clean_exec` has been removed in favor of `Bundler.unbundled_exec`. " \ + "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`" + Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true) + with_env(unbundled_env) { Kernel.exec(*args) } + end + + # Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed + def unbundled_exec(*args) + with_env(unbundled_env) { Kernel.exec(*args) } + end + + def local_platform + return Gem::Platform::RUBY if settings[:force_ruby_platform] + Gem::Platform.local + end + + def default_gemfile + SharedHelpers.default_gemfile + end + + def default_lockfile + SharedHelpers.default_lockfile + end + + def default_bundle_dir + SharedHelpers.default_bundle_dir + end + + def system_bindir + # Gem.bindir doesn't always return the location that RubyGems will install + # system binaries. If you put '-n foo' in your .gemrc, RubyGems will + # install binstubs there instead. Unfortunately, RubyGems doesn't expose + # that directory at all, so rather than parse .gemrc ourselves, we allow + # the directory to be set as well, via `bundle config set --local bindir foo`. + Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir + end + + def preferred_gemfile_name + Bundler.settings[:init_gems_rb] ? "gems.rb" : "Gemfile" + end + + def use_system_gems? + configured_bundle_path.use_system_gems? + end + + def mkdir_p(path) + SharedHelpers.filesystem_access(path, :write) do |p| + FileUtils.mkdir_p(p) + end + end + + def which(executable) + if File.file?(executable) && File.executable?(executable) + executable + elsif paths = ENV["PATH"] + quote = '"' + paths.split(File::PATH_SEPARATOR).find do |path| + path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) + executable_path = File.expand_path(executable, path) + return executable_path if File.file?(executable_path) && File.executable?(executable_path) + end + end + end + + def read_file(file) + SharedHelpers.filesystem_access(file, :read) do + File.open(file, "r:UTF-8", &:read) + end + end + + def safe_load_marshal(data) + if Gem.respond_to?(:load_safe_marshal) + Gem.load_safe_marshal + begin + Gem::SafeMarshal.safe_load(data) + rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e + raise MarshalError, "#{e.class}: #{e.message}" + end + else + load_marshal(data, marshal_proc: SafeMarshal.proc) + end + end + + def load_gemspec(file, validate = false) + @gemspec_cache ||= {} + key = File.expand_path(file) + @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) + # Protect against caching side-effected gemspecs by returning a + # new instance each time. + @gemspec_cache[key]&.dup + end + + def load_gemspec_uncached(file, validate = false) + path = Pathname.new(file) + contents = read_file(file) + spec = if contents.start_with?("---") # YAML header + eval_yaml_gemspec(path, contents) + else + # Eval the gemspec from its parent directory, because some gemspecs + # depend on "./" relative paths. + SharedHelpers.chdir(path.dirname.to_s) do + eval_gemspec(path, contents) + end + end + return unless spec + spec.loaded_from = path.expand_path.to_s + Bundler.rubygems.validate(spec) if validate + spec + end + + def clear_gemspec_cache + @gemspec_cache = {} + end + + def git_present? + return @git_present if defined?(@git_present) + @git_present = Bundler.which("git#{RbConfig::CONFIG["EXEEXT"]}") + end + + def feature_flag + @feature_flag ||= FeatureFlag.new(VERSION) + end + + def reset! + reset_paths! + Plugin.reset! + reset_rubygems! + end + + def reset_settings_and_root! + @settings = nil + @root = nil + end + + def reset_paths! + @bin_path = nil + @bundler_major_version = nil + @bundle_path = nil + @configure = nil + @configured_bundle_path = nil + @definition = nil + @load = nil + @locked_gems = nil + @root = nil + @settings = nil + @setup = nil + @user_home = nil + end + + def reset_rubygems! + return unless defined?(@rubygems) && @rubygems + rubygems.undo_replacements + rubygems.reset + @rubygems = nil + end + + def configure_gem_home_and_path(path = bundle_path) + configure_gem_path + configure_gem_home(path) + Bundler.rubygems.clear_paths + end + + def self_manager + @self_manager ||= begin + require_relative "bundler/self_manager" + Bundler::SelfManager.new + end + end + + private + + def load_marshal(data, marshal_proc: nil) + Marshal.load(data, marshal_proc) + rescue TypeError => e + raise MarshalError, "#{e.class}: #{e.message}" + end + + def eval_yaml_gemspec(path, contents) + Kernel.require "psych" + + Gem::Specification.from_yaml(contents) + rescue ::Psych::SyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception + eval_gemspec(path, contents) + end + + def eval_gemspec(path, contents) + eval(contents, TOPLEVEL_BINDING.dup, path.expand_path.to_s) + rescue ScriptError, StandardError => e + msg = "There was an error while loading `#{path.basename}`: #{e.message}" + + raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents) + end + + def configure_gem_path + unless use_system_gems? + # this needs to be empty string to cause + # PathSupport.split_gem_path to only load up the + # Bundler --path setting as the GEM_PATH. + Bundler::SharedHelpers.set_env "GEM_PATH", "" + end + end + + def configure_gem_home(path) + Bundler::SharedHelpers.set_env "GEM_HOME", path.to_s + end + + def tmp_home_path + Kernel.send(:require, "tmpdir") + SharedHelpers.filesystem_access(Dir.tmpdir) do + path = Bundler.tmp + at_exit { Bundler.rm_rf(path) } + path + end + end + + # @param env [Hash] + def with_env(env) + backup = ENV.to_hash + ENV.replace(env) + yield + ensure + ENV.replace(backup) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/.document b/bin/gems/bundler-2.5.9/lib/bundler/.document new file mode 100644 index 00000000..238bbd87 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/.document @@ -0,0 +1 @@ +# not in RDoc diff --git a/bin/gems/bundler-2.5.9/lib/bundler/build_metadata.rb b/bin/gems/bundler-2.5.9/lib/bundler/build_metadata.rb new file mode 100644 index 00000000..6358d343 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/build_metadata.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Bundler + # Represents metadata from when the Bundler gem was built. + module BuildMetadata + # begin ivars + @built_at = "2024-04-12".freeze + @git_commit_sha = "4304697e0c".freeze + @release = true + # end ivars + + # A hash representation of the build metadata. + def self.to_h + { + "Built At" => built_at, + "Git SHA" => git_commit_sha, + "Released Version" => release?, + } + end + + # A string representing the date the bundler gem was built. + def self.built_at + @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze + end + + # The SHA for the git commit the bundler gem was built from. + def self.git_commit_sha + return @git_commit_sha if instance_variable_defined? :@git_commit_sha + + # If Bundler has been installed without its .git directory and without a + # commit instance variable then we can't determine its commits SHA. + git_dir = File.expand_path("../../../.git", __dir__) + if File.directory?(git_dir) + return @git_commit_sha = IO.popen(%w[git rev-parse --short HEAD], { chdir: git_dir }, &:read).strip.freeze + end + + @git_commit_sha ||= "unknown" + end + + # Whether this is an official release build of Bundler. + def self.release? + @release + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/capistrano.rb b/bin/gems/bundler-2.5.9/lib/bundler/capistrano.rb new file mode 100644 index 00000000..70584014 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/capistrano.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.major_deprecation 2, + "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler" + +# Capistrano task for Bundler. +# +# Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and +# Bundler will be activated after each new deployment. +require_relative "deployment" +require "capistrano/version" + +if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") + raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler" +end + +Capistrano::Configuration.instance(:must_exist).load do + before "deploy:finalize_update", "bundle:install" + Bundler::Deployment.define_task(self, :task, except: { no_release: true }) + set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/checksum.rb b/bin/gems/bundler-2.5.9/lib/bundler/checksum.rb new file mode 100644 index 00000000..60ba9341 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/checksum.rb @@ -0,0 +1,254 @@ +# frozen_string_literal: true + +module Bundler + class Checksum + ALGO_SEPARATOR = "=" + DEFAULT_ALGORITHM = "sha256" + private_constant :DEFAULT_ALGORITHM + DEFAULT_BLOCK_SIZE = 16_384 + private_constant :DEFAULT_BLOCK_SIZE + + class << self + def from_gem_package(gem_package, algo = DEFAULT_ALGORITHM) + return if Bundler.settings[:disable_checksum_validation] + return unless source = gem_package.instance_variable_get(:@gem) + return unless source.respond_to?(:with_read_io) + + source.with_read_io do |io| + from_gem(io, source.path) + ensure + io.rewind + end + end + + def from_gem(io, pathname, algo = DEFAULT_ALGORITHM) + digest = Bundler::SharedHelpers.digest(algo.upcase).new + buf = String.new(capacity: DEFAULT_BLOCK_SIZE) + digest << io.readpartial(DEFAULT_BLOCK_SIZE, buf) until io.eof? + Checksum.new(algo, digest.hexdigest!, Source.new(:gem, pathname)) + end + + def from_api(digest, source_uri, algo = DEFAULT_ALGORITHM) + return if Bundler.settings[:disable_checksum_validation] + + Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:api, source_uri)) + end + + def from_lock(lock_checksum, lockfile_location) + algo, digest = lock_checksum.strip.split(ALGO_SEPARATOR, 2) + Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:lock, lockfile_location)) + end + + def to_hexdigest(digest, algo = DEFAULT_ALGORITHM) + return digest unless algo == DEFAULT_ALGORITHM + return digest if digest.match?(/\A[0-9a-f]{64}\z/i) + + if digest.match?(%r{\A[-0-9a-z_+/]{43}={0,2}\z}i) + digest = digest.tr("-_", "+/") # fix urlsafe base64 + digest.unpack1("m0").unpack1("H*") + else + raise ArgumentError, "#{digest.inspect} is not a valid SHA256 hex or base64 digest" + end + end + end + + attr_reader :algo, :digest, :sources + + def initialize(algo, digest, source) + @algo = algo + @digest = digest + @sources = [source] + end + + def ==(other) + match?(other) && other.sources == sources + end + + alias_method :eql?, :== + + def same_source?(other) + sources.include?(other.sources.first) + end + + def match?(other) + other.is_a?(self.class) && other.digest == digest && other.algo == algo + end + + def hash + digest.hash + end + + def to_s + "#{to_lock} (from #{sources.first}#{", ..." if sources.size > 1})" + end + + def to_lock + "#{algo}#{ALGO_SEPARATOR}#{digest}" + end + + def merge!(other) + return nil unless match?(other) + + @sources.concat(other.sources).uniq! + self + end + + def formatted_sources + sources.join("\n and ").concat("\n") + end + + def removable? + sources.all?(&:removable?) + end + + def removal_instructions + msg = +"" + i = 1 + sources.each do |source| + msg << " #{i}. #{source.removal}\n" + i += 1 + end + msg << " #{i}. run `bundle install`\n" + end + + def inspect + abbr = "#{algo}#{ALGO_SEPARATOR}#{digest[0, 8]}" + from = "from #{sources.join(" and ")}" + "#<#{self.class}:#{object_id} #{abbr} #{from}>" + end + + class Source + attr_reader :type, :location + + def initialize(type, location) + @type = type + @location = location + end + + def removable? + type == :lock || type == :gem + end + + def ==(other) + other.is_a?(self.class) && other.type == type && other.location == location + end + + # phrased so that the usual string format is grammatically correct + # rake (10.3.2) sha256=abc123 from #{to_s} + def to_s + case type + when :lock + "the lockfile CHECKSUMS at #{location}" + when :gem + "the gem at #{location}" + when :api + "the API at #{location}" + else + "#{location} (#{type})" + end + end + + # A full sentence describing how to remove the checksum + def removal + case type + when :lock + "remove the matching checksum in #{location}" + when :gem + "remove the gem at #{location}" + when :api + "checksums from #{location} cannot be locally modified, you may need to update your sources" + else + "remove #{location} (#{type})" + end + end + end + + class Store + attr_reader :store + protected :store + + def initialize + @store = {} + @store_mutex = Mutex.new + end + + def inspect + "#<#{self.class}:#{object_id} size=#{store.size}>" + end + + # Replace when the new checksum is from the same source. + # The primary purpose is registering checksums from gems where there are + # duplicates of the same gem (according to full_name) in the index. + # + # In particular, this is when 2 gems have two similar platforms, e.g. + # "darwin20" and "darwin-20", both of which resolve to darwin-20. + # In the Index, the later gem replaces the former, so we do that here. + # + # However, if the new checksum is from a different source, we register like normal. + # This ensures a mismatch error where there are multiple top level sources + # that contain the same gem with different checksums. + def replace(spec, checksum) + return unless checksum + + lock_name = spec.name_tuple.lock_name + @store_mutex.synchronize do + existing = fetch_checksum(lock_name, checksum.algo) + if !existing || existing.same_source?(checksum) + store_checksum(lock_name, checksum) + else + merge_checksum(lock_name, checksum, existing) + end + end + end + + def register(spec, checksum) + return unless checksum + + register_checksum(spec.name_tuple.lock_name, checksum) + end + + def merge!(other) + other.store.each do |lock_name, checksums| + checksums.each do |_algo, checksum| + register_checksum(lock_name, checksum) + end + end + end + + def to_lock(spec) + lock_name = spec.name_tuple.lock_name + checksums = @store[lock_name] + if checksums + "#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}" + else + lock_name + end + end + + private + + def register_checksum(lock_name, checksum) + @store_mutex.synchronize do + existing = fetch_checksum(lock_name, checksum.algo) + if existing + merge_checksum(lock_name, checksum, existing) + else + store_checksum(lock_name, checksum) + end + end + end + + def merge_checksum(lock_name, checksum, existing) + existing.merge!(checksum) || raise(ChecksumMismatchError.new(lock_name, existing, checksum)) + end + + def store_checksum(lock_name, checksum) + (@store[lock_name] ||= {})[checksum.algo] = checksum + end + + def fetch_checksum(lock_name, algo) + @store[lock_name]&.fetch(algo, nil) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ci_detector.rb b/bin/gems/bundler-2.5.9/lib/bundler/ci_detector.rb new file mode 100644 index 00000000..e5fedbdea --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ci_detector.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Bundler + module CIDetector + # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and + # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates). + # TODO: Drop that duplication once bundler drops support for RubyGems 3.4 + # + # ## Recognized CI providers, their signifiers, and the relevant docs ## + # + # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables + # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables + # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables + # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/ + # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/ + # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables + # dsari - CI, DSARI https://github.com/rfinnie/dsari#running + # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables + # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters + # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments + # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars + # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/ + # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables + # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html + # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables + # + # ### Some "standard" ENVs that multiple providers may set ### + # + # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard. + # * CI_NAME - Not as frequently used, but some providers set this to specify their own name + + # Any of these being set is a reasonably reliable indicator that we are + # executing in a CI environment. + ENV_INDICATORS = [ + "CI", + "CI_NAME", + "CONTINUOUS_INTEGRATION", + "BUILD_NUMBER", + "CI_APP_ID", + "CI_BUILD_ID", + "CI_BUILD_NUMBER", + "RUN_ID", + "TASKCLUSTER_ROOT_URL", + ].freeze + + # For each CI, this env suffices to indicate that we're on _that_ CI's + # containers. (A few of them only supply a CI_NAME variable, which is also + # nice). And if they set "CI" but we can't tell which one they are, we also + # want to know that - a bare "ci" without another token tells us as much. + ENV_DESCRIPTORS = { + "TRAVIS" => "travis", + "CIRCLECI" => "circle", + "CIRRUS_CI" => "cirrus", + "DSARI" => "dsari", + "SEMAPHORE" => "semaphore", + "JENKINS_URL" => "jenkins", + "BUILDKITE" => "buildkite", + "GO_SERVER_URL" => "go", + "GITLAB_CI" => "gitlab", + "GITHUB_ACTIONS" => "github", + "TASKCLUSTER_ROOT_URL" => "taskcluster", + "CI" => "ci", + }.freeze + + def self.ci? + ENV_INDICATORS.any? {|var| ENV.include?(var) } + end + + def self.ci_strings + matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values + matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"] + matching_names.reject(&:empty?).sort.uniq + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli.rb new file mode 100644 index 00000000..36405367 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli.rb @@ -0,0 +1,846 @@ +# frozen_string_literal: true + +require_relative "vendored_thor" + +module Bundler + class CLI < Thor + require_relative "cli/common" + + package_name "Bundler" + + AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze + PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze + EXTENSIONS = ["c", "rust"].freeze + + COMMAND_ALIASES = { + "check" => "c", + "install" => "i", + "plugin" => "", + "list" => "ls", + "exec" => ["e", "ex", "exe"], + "cache" => ["package", "pack"], + "version" => ["-v", "--version"], + }.freeze + + def self.start(*) + check_deprecated_ext_option(ARGV) if ARGV.include?("--ext") + + super + ensure + Bundler::SharedHelpers.print_major_deprecations! + end + + def self.dispatch(*) + super do |i| + i.send(:print_command) + i.send(:warn_on_outdated_bundler) + end + end + + def self.all_aliases + @all_aliases ||= begin + command_aliases = {} + + COMMAND_ALIASES.each do |name, aliases| + Array(aliases).each do |one_alias| + command_aliases[one_alias] = name + end + end + + command_aliases + end + end + + def self.aliases_for(command_name) + COMMAND_ALIASES.select {|k, _| k == command_name }.invert + end + + def initialize(*args) + super + + custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] + if custom_gemfile && !custom_gemfile.empty? + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) + Bundler.reset_settings_and_root! + end + + Bundler.self_manager.restart_with_locked_bundler_if_needed + + Bundler.settings.set_command_option_if_given :retry, options[:retry] + + current_cmd = args.last[:current_command].name + auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) + rescue UnknownArgumentError => e + raise InvalidOption, e.message + ensure + self.options ||= {} + unprinted_warnings = Bundler.ui.unprinted_warnings + Bundler.ui = UI::Shell.new(options) + Bundler.ui.level = "debug" if options["verbose"] + unprinted_warnings.each {|w| Bundler.ui.warn(w) } + end + + check_unknown_options!(except: [:config, :exec]) + stop_on_unknown_option! :exec + + desc "cli_help", "Prints a summary of bundler commands", hide: true + def cli_help + version + Bundler.ui.info "\n" + + primary_commands = ["install", "update", "cache", "exec", "config", "help"] + + list = self.class.printable_commands(true) + by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] } + utilities = by_name.keys.sort - primary_commands + primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first } + utilities.map! {|name| by_name[name].first } + + shell.say "Bundler commands:\n\n" + + shell.say " Primary commands:\n" + shell.print_table(primary_commands, indent: 4, truncate: true) + shell.say + shell.say " Utilities:\n" + shell.print_table(utilities, indent: 4, truncate: true) + shell.say + self.class.send(:class_options_help, shell) + end + default_task(Bundler.feature_flag.default_cli_command) + + class_option "no-color", type: :boolean, desc: "Disable colorization in output" + class_option "retry", type: :numeric, aliases: "-r", banner: "NUM", + desc: "Specify the number of times you wish to attempt network commands" + class_option "verbose", type: :boolean, desc: "Enable verbose output mode", aliases: "-V" + + def help(cli = nil) + case cli + when "gemfile" then command = "gemfile" + when nil then command = "bundle" + else command = "bundle-#{cli}" + end + + man_path = File.expand_path("man", __dir__) + man_pages = Hash[Dir.glob(File.join(man_path, "**", "*")).grep(/.*\.\d*\Z/).collect do |f| + [File.basename(f, ".*"), f] + end] + + if man_pages.include?(command) + man_page = man_pages[command] + if Bundler.which("man") && !man_path.match?(%r{^file:/.+!/META-INF/jruby.home/.+}) + Kernel.exec("man", man_page) + else + puts File.read("#{man_path}/#{File.basename(man_page)}.ronn") + end + elsif command_path = Bundler.which("bundler-#{cli}") + Kernel.exec(command_path, "--help") + else + super + end + end + + def self.handle_no_command_error(command, has_namespace = $thor_runner) + if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command) + return Bundler::Plugin.exec_command(command, ARGV[1..-1]) + end + + return super unless command_path = Bundler.which("bundler-#{command}") + + Kernel.exec(command_path, *ARGV[1..-1]) + end + + desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" + long_desc <<-D + Init generates a default Gemfile in the current working directory. When adding a + Gemfile to a gem with a gemspec, the --gemspec option will automatically add each + dependency listed in the gemspec file to the newly created Gemfile. + D + method_option "gemspec", type: :string, banner: "Use the specified .gemspec to create the Gemfile" + method_option "gemfile", type: :string, banner: "Use the specified name for the gemfile instead of 'Gemfile'" + def init + require_relative "cli/init" + Init.new(options.dup).run + end + + desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" + long_desc <<-D + Check searches the local machine for each of the gems requested in the Gemfile. If + all gems are found, Bundler prints a success message and exits with a status of 0. + If not, the first missing gem is listed and Bundler exits status 1. + D + method_option "dry-run", type: :boolean, default: false, banner: "Lock the Gemfile" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" + def check + remembered_flag_deprecation("path") + + require_relative "cli/check" + Check.new(options).run + end + + map aliases_for("check") + + desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile" + long_desc <<-D + Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning. + D + method_option "install", type: :boolean, banner: "Runs 'bundle install' after removing the gems from the Gemfile" + def remove(*gems) + if ARGV.include?("--install") + message = "The `--install` flag has been deprecated. `bundle install` is triggered by default." + removed_message = "The `--install` flag has been removed. `bundle install` is triggered by default." + SharedHelpers.major_deprecation(2, message, removed_message: removed_message) + end + + require_relative "cli/remove" + Remove.new(gems, options).run + end + + desc "install [OPTIONS]", "Install the current environment to the system" + long_desc <<-D + Install will install all of the gems in the current bundle, making them available + for use. In a freshly checked out repository, this command will give you the same + gem versions as the last person who updated the Gemfile and ran `bundle update`. + + Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed + into the [DIR] directory rather than into system gems. + + If the bundle has already been installed, bundler will tell you so and then exit. + D + method_option "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin" + method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install" + method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments" + method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install" + method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "prefer-local", type: :boolean, banner: "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely" + method_option "no-cache", type: :boolean, banner: "Don't update the existing gem cache." + method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem." + method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache." + method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')" + method_option "standalone", type: :array, lazy_default: [], banner: "Make a bundle that can work without the Bundler runtime" + method_option "system", type: :boolean, banner: "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" + method_option "trust-policy", alias: "P", type: :string, banner: "Gem trust policy (like gem install -P). Must be one of " + + Bundler.rubygems.security_policy_keys.join("|") + method_option "without", type: :array, banner: "Exclude gems that are part of the specified named group." + method_option "with", type: :array, banner: "Include gems that are part of the specified named group." + def install + SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") + + %w[clean deployment frozen no-prune path shebang without with].each do |option| + remembered_flag_deprecation(option) + end + + print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system") + + remembered_negative_flag_deprecation("no-deployment") + + require_relative "cli/install" + Bundler.settings.temporary(no_install: false) do + Install.new(options.dup).run + end + end + + map aliases_for("install") + + desc "update [OPTIONS]", "Update the current environment" + long_desc <<-D + Update will install the newest versions of the gems listed in the Gemfile. Use + update when you have changed the Gemfile, or if you want to get the newest + possible versions of the gems in the bundle. + D + method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "group", aliases: "-g", type: :array, banner: "Update a specific group" + method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "source", type: :array, banner: "Update a specific source (and all gems associated with it)" + method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem." + method_option "ruby", type: :boolean, banner: "Update ruby specified in Gemfile.lock" + method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler" + method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version" + method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)" + method_option "pre", type: :boolean, banner: "Always choose the highest allowed version when updating gems, regardless of prerelease status" + method_option "strict", type: :boolean, banner: "Do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "conservative", type: :boolean, banner: "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." + method_option "all", type: :boolean, banner: "Update everything." + def update(*gems) + SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force") + require_relative "cli/update" + Bundler.settings.temporary(no_install: false) do + Update.new(options, gems).run + end + end + + desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" + long_desc <<-D + Show lists the names and versions of all gems that are required by your Gemfile. + Calling show with [GEM] will list the exact location of that gem on your machine. + D + method_option "paths", type: :boolean, + banner: "List the paths of all gems that are required by your Gemfile." + method_option "outdated", type: :boolean, + banner: "Show verbose output including whether gems are outdated." + def show(gem_name = nil) + if ARGV.include?("--outdated") + message = "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement" + removed_message = "the `--outdated` flag to `bundle show` was undocumented and has been removed without replacement" + SharedHelpers.major_deprecation(2, message, removed_message: removed_message) + end + require_relative "cli/show" + Show.new(options, gem_name).run + end + + desc "list", "List all gems in the bundle" + method_option "name-only", type: :boolean, banner: "print only the gem names" + method_option "only-group", type: :array, default: [], banner: "print gems from a given set of groups" + method_option "without-group", type: :array, default: [], banner: "print all gems except from a given set of groups" + method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle" + def list + require_relative "cli/list" + List.new(options).run + end + + map aliases_for("list") + + desc "info GEM [OPTIONS]", "Show information for the given gem" + method_option "path", type: :boolean, banner: "Print full path to gem" + method_option "version", type: :boolean, banner: "Print gem version" + def info(gem_name) + require_relative "cli/info" + Info.new(options, gem_name).run + end + + desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" + long_desc <<-D + Generate binstubs for executables in [GEM]. Binstubs are put into bin, + or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] + will create binstubs for all given gems. + D + method_option "force", type: :boolean, default: false, banner: "Overwrite existing binstubs if they exist" + method_option "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory (default bin)" + method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')" + method_option "standalone", type: :boolean, banner: "Make binstubs that can work without the Bundler runtime" + method_option "all", type: :boolean, banner: "Install binstubs for all gems" + method_option "all-platforms", type: :boolean, default: false, banner: "Install binstubs for all platforms" + def binstubs(*gems) + require_relative "cli/binstubs" + Binstubs.new(options, gems).run + end + + desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" + long_desc <<-D + Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. + D + method_option "version", aliases: "-v", type: :string + method_option "group", aliases: "-g", type: :string + method_option "source", aliases: "-s", type: :string + method_option "require", aliases: "-r", type: :string, banner: "Adds require path to gem. Provide false, or a path as a string." + method_option "path", type: :string + method_option "git", type: :string + method_option "github", type: :string + method_option "branch", type: :string + method_option "ref", type: :string + method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it" + method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem" + method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem" + def add(*gems) + require_relative "cli/add" + Add.new(options.dup, gems).run + end + + desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" + long_desc <<-D + Outdated lists the names and versions of gems that have a newer version available + in the given source. Calling outdated with [GEM [GEM]] will only check for newer + versions of the given gems. Prerelease gems are ignored by default. If your gems + are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. + + For more information on patch level options (--major, --minor, --patch, + --strict) see documentation on the same options on the update command. + D + method_option "group", type: :string, banner: "List gems from a specific group" + method_option "groups", type: :boolean, banner: "List gems organized by groups" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "pre", type: :boolean, banner: "Check for newer pre-release gems" + method_option "source", type: :array, banner: "Check against a specific source" + method_option "filter-strict", type: :boolean, aliases: "--strict", banner: "Only list newer versions allowed by your Gemfile requirements" + method_option "update-strict", type: :boolean, banner: "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)" + method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version" + method_option "filter-major", type: :boolean, banner: "Only list major newer versions" + method_option "filter-minor", type: :boolean, banner: "Only list minor newer versions" + method_option "filter-patch", type: :boolean, banner: "Only list patch newer versions" + method_option "parseable", aliases: "--porcelain", type: :boolean, banner: "Use minimal formatting for more parseable output" + method_option "only-explicit", type: :boolean, banner: "Only list gems specified in your Gemfile, not their dependencies" + def outdated(*gems) + require_relative "cli/outdated" + Outdated.new(options, gems).run + end + + desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance" + method_option "group", aliases: "-g", type: :array, banner: "Fetch funding information for a specific group" + def fund + require_relative "cli/fund" + Fund.new(options).run + end + + desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" + method_option "all", type: :boolean, + default: Bundler.feature_flag.cache_all?, + banner: "Include all sources (including path and git)." + method_option "all-platforms", type: :boolean, banner: "Include gems for all platforms present in the lockfile, not only the current one" + method_option "cache-path", type: :string, banner: "Specify a different cache path than the default (vendor/cache)." + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "no-install", type: :boolean, banner: "Don't install the gems, only update the cache." + method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache." + method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install" + long_desc <<-D + The cache command will copy the .gem files for every gem in the bundle into the + directory ./vendor/cache. If you then check that directory into your source + control repository, others who check out your source will be able to install the + bundle without having to download any additional gems. + D + def cache + print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all") + + if ARGV.include?("--path") + message = + "The `--path` flag is deprecated because its semantics are unclear. " \ + "Use `bundle config cache_path` to configure the path of your cache of gems, " \ + "and `bundle config path` to configure the path where your gems are installed, " \ + "and stop using this flag" + removed_message = + "The `--path` flag has been removed because its semantics were unclear. " \ + "Use `bundle config cache_path` to configure the path of your cache of gems, " \ + "and `bundle config path` to configure the path where your gems are installed." + SharedHelpers.major_deprecation 2, message, removed_message: removed_message + end + + require_relative "cli/cache" + Cache.new(options).run + end + + map aliases_for("cache") + + desc "exec [OPTIONS]", "Run the command in context of the bundle" + method_option :keep_file_descriptors, type: :boolean, default: true + method_option :gemfile, type: :string, required: false + long_desc <<-D + Exec runs a command, providing it access to the gems in the bundle. While using + bundle exec you can require and call the bundled gems as if they were installed + into the system wide RubyGems repository. + D + def exec(*args) + if ARGV.include?("--no-keep-file-descriptors") + message = "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to" + removed_message = "The `--no-keep-file-descriptors` has been removed. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to" + SharedHelpers.major_deprecation(2, message, removed_message: removed_message) + end + + require_relative "cli/exec" + Exec.new(options, args).run + end + + map aliases_for("exec") + + desc "config NAME [VALUE]", "Retrieve or set a configuration value" + long_desc <<-D + Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the + existing value with the newly provided one. + + By default, setting a configuration value sets it for all projects + on the machine. + + If a global setting is superseded by local configuration, this command + will show the current value, as well as any superseded values and + where they were specified. + D + require_relative "cli/config" + subcommand "config", Config + + desc "open GEM", "Opens the source directory of the given bundled gem" + method_option "path", type: :string, lazy_default: "", banner: "Open relative path of the gem source." + def open(name) + require_relative "cli/open" + Open.new(options, name).run + end + + unless Bundler.feature_flag.bundler_3_mode? + desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" + def console(group = nil) + require_relative "cli/console" + Console.new(options, group).run + end + end + + desc "version", "Prints Bundler version information" + def version + cli_help = current_command.name == "cli_help" + if cli_help || ARGV.include?("version") + build_info = " (#{BuildMetadata.built_at} commit #{BuildMetadata.git_commit_sha})" + end + + if !cli_help && Bundler.feature_flag.print_only_version_number? + Bundler.ui.info "#{Bundler::VERSION}#{build_info}" + else + Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}" + end + end + + map aliases_for("version") + + desc "licenses", "Prints the license of all gems in the bundle" + def licenses + Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| + gem_name = s.name + license = s.license || s.licenses + + if license.empty? + Bundler.ui.warn "#{gem_name}: Unknown" + else + Bundler.ui.info "#{gem_name}: #{license}" + end + end + end + + unless Bundler.feature_flag.bundler_3_mode? + desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true + long_desc <<-D + Viz generates a PNG file of the current Gemfile as a dependency graph. + Viz requires the ruby-graphviz gem (and its dependencies). + The associated gems must also be installed via 'bundle install'. + D + method_option :file, type: :string, default: "gem_graph", aliases: "-f", desc: "The name to use for the generated file. see format option" + method_option :format, type: :string, default: "png", aliases: "-F", desc: "This is output format option. Supported format is png, jpg, svg, dot ..." + method_option :requirements, type: :boolean, default: false, aliases: "-R", desc: "Set to show the version of each required dependency." + method_option :version, type: :boolean, default: false, aliases: "-v", desc: "Set to show each gem version." + method_option :without, type: :array, default: [], aliases: "-W", banner: "GROUP[ GROUP...]", desc: "Exclude gems that are part of the specified named group." + def viz + SharedHelpers.major_deprecation 2, "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph" + require_relative "cli/viz" + Viz.new(options.dup).run + end + end + + old_gem = instance_method(:gem) + + desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" + method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], desc: "Generate a binary executable for your library." + method_option :coc, type: :boolean, desc: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." + method_option :edit, type: :string, aliases: "-e", required: false, banner: "EDITOR", + lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, + desc: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" + method_option :ext, type: :string, desc: "Generate the boilerplate for C extension code.", enum: EXTENSIONS + method_option :git, type: :boolean, default: true, desc: "Initialize a git repo inside your library." + method_option :mit, type: :boolean, desc: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." + method_option :rubocop, type: :boolean, desc: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." + method_option :changelog, type: :boolean, desc: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." + method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library", + desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." + method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", + desc: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`" + method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "", + desc: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`" + method_option :github_username, type: :string, default: Bundler.settings["gem.github_username"], banner: "Set your username on GitHub", desc: "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username `." + + def gem(name) + end + + commands["gem"].tap do |gem_command| + def gem_command.run(instance, args = []) + arity = 1 # name + + require_relative "cli/gem" + cmd_args = args + [instance] + cmd_args.unshift(instance.options) + + cmd = begin + Gem.new(*cmd_args) + rescue ArgumentError => e + instance.class.handle_argument_error(self, e, args, arity) + end + + cmd.run + end + end + + undef_method(:gem) + define_method(:gem, old_gem) + private :gem + + def self.source_root + File.expand_path("templates", __dir__) + end + + desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", hide: true + method_option "dry-run", type: :boolean, default: false, banner: "Only print out changes, do not clean gems" + method_option "force", type: :boolean, default: false, banner: "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application." + def clean + require_relative "cli/clean" + Clean.new(options.dup).run + end + + desc "platform [OPTIONS]", "Displays platform compatibility information" + method_option "ruby", type: :boolean, default: false, banner: "only display ruby related platform information" + def platform + require_relative "cli/platform" + Platform.new(options).run + end + + desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", hide: true + method_option "source", type: :string, banner: "Install gem from the given source" + method_option "group", type: :string, banner: "Install gem into a bundler group" + def inject(name, version) + SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command" + require_relative "cli/inject" + Inject.new(options.dup, name, version).run + end + + desc "lock", "Creates a lockfile without installing" + method_option "update", type: :array, lazy_default: true, banner: "ignore the existing lockfile, update all gems by default, or update list of given gems" + method_option "local", type: :boolean, default: false, banner: "do not attempt to fetch remote gemspecs and use the local gem cache only" + method_option "print", type: :boolean, default: false, banner: "print the lockfile to STDOUT instead of writing to the file system" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "lockfile", type: :string, default: nil, banner: "the path the lockfile should be written to" + method_option "full-index", type: :boolean, default: false, banner: "Fall back to using the single-file index of all gems" + method_option "add-platform", type: :array, default: [], banner: "Add a new platform to the lockfile" + method_option "remove-platform", type: :array, default: [], banner: "Remove a platform from the lockfile" + method_option "patch", type: :boolean, banner: "If updating, prefer updating only to next patch version" + method_option "minor", type: :boolean, banner: "If updating, prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "If updating, prefer updating to next major version (default)" + method_option "pre", type: :boolean, banner: "If updating, always choose the highest allowed version, regardless of prerelease status" + method_option "strict", type: :boolean, banner: "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "conservative", type: :boolean, banner: "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" + method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler" + def lock + require_relative "cli/lock" + Lock.new(options).run + end + + desc "env", "Print information about the environment Bundler is running under" + def env + Env.write($stdout) + end + + desc "doctor [OPTIONS]", "Checks the bundle for common problems" + long_desc <<-D + Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If + missing dependencies are detected, Bundler prints them and exits status 1. + Otherwise, Bundler prints a success message and exits with a status of 0. + D + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + def doctor + require_relative "cli/doctor" + Doctor.new(options).run + end + + desc "issue", "Learn how to report an issue in Bundler" + def issue + require_relative "cli/issue" + Issue.new.run + end + + desc "pristine [GEMS...]", "Restores installed gems to pristine condition" + long_desc <<-D + Restores installed gems to pristine condition from files located in the + gem cache. Gems installed from a git repository will be issued `git + checkout --force`. + D + def pristine(*gems) + require_relative "cli/pristine" + Bundler.settings.temporary(no_install: false) do + Pristine.new(gems).run + end + end + + if Bundler.feature_flag.plugins? + require_relative "cli/plugin" + desc "plugin", "Manage the bundler plugins" + subcommand "plugin", Plugin + end + + # Reformat the arguments passed to bundle that include a --help flag + # into the corresponding `bundle help #{command}` call + def self.reformatted_help_args(args) + bundler_commands = (COMMAND_ALIASES.keys + COMMAND_ALIASES.values).flatten + + help_flags = %w[--help -h] + exec_commands = ["exec"] + COMMAND_ALIASES["exec"] + + help_used = args.index {|a| help_flags.include? a } + exec_used = args.index {|a| exec_commands.include? a } + + command = args.find {|a| bundler_commands.include? a } + command = all_aliases[command] if all_aliases[command] + + if exec_used && help_used + if exec_used + help_used == 1 + %w[help exec] + else + args + end + elsif help_used + args = args.dup + args.delete_at(help_used) + ["help", command || args].flatten.compact + else + args + end + end + + def self.check_deprecated_ext_option(arguments) + # when deprecated version of `--ext` is called + # print out deprecation warning and pretend `--ext=c` was provided + if deprecated_ext_value?(arguments) + message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used." + removed_message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been removed. Please select a language, e.g. `--ext=rust` to generate a Rust extension." + SharedHelpers.major_deprecation 2, message, removed_message: removed_message + arguments[arguments.index("--ext")] = "--ext=c" + end + end + + def self.deprecated_ext_value?(arguments) + index = arguments.index("--ext") + next_argument = arguments[index + 1] + + # it is ok when --ext is followed with valid extension value + # for example `bundle gem hello --ext c` + return false if EXTENSIONS.include?(next_argument) + + # deprecated call when --ext is called with no value in last position + # for example `bundle gem hello_gem --ext` + return true if next_argument.nil? + + # deprecated call when --ext is followed by other parameter + # for example `bundle gem --ext --no-ci hello_gem` + return true if next_argument.start_with?("-") + + # deprecated call when --ext is followed by gem name + # for example `bundle gem --ext hello_gem` + return true if next_argument + + false + end + + private + + # Automatically invoke `bundle install` and resume if + # Bundler.settings[:auto_install] exists. This is set through config cmd + # `bundle config set --global auto_install 1`. + # + # Note that this method `nil`s out the global Definition object, so it + # should be called first, before you instantiate anything like an + # `Installer` that'll keep a reference to the old one instead. + def auto_install + return unless Bundler.settings[:auto_install] + + begin + Bundler.definition.specs + rescue GemNotFound, GitError + Bundler.ui.info "Automatically installing missing gems." + Bundler.reset! + invoke :install, [] + Bundler.reset! + end + end + + def current_command + _, _, config = @_initializer + config[:current_command] + end + + def print_command + return unless Bundler.ui.debug? + cmd = current_command + command_name = cmd.name + return if PARSEABLE_COMMANDS.include?(command_name) + command = ["bundle", command_name] + args + options_to_print = options.dup + options_to_print.delete_if do |k, v| + next unless o = cmd.options[k] + o.default == v + end + command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip + command.reject!(&:empty?) + Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}" + end + + def warn_on_outdated_bundler + return if Bundler.settings[:disable_version_check] + + command_name = current_command.name + return if PARSEABLE_COMMANDS.include?(command_name) + + return unless SharedHelpers.md5_available? + + latest = Fetcher::CompactIndex. + new(nil, Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org")), nil, nil). + send(:compact_index_client). + instance_variable_get(:@cache). + dependencies("bundler"). + map {|d| Gem::Version.new(d.first) }. + max + return unless latest + + current = Gem::Version.new(VERSION) + return if current >= latest + + Bundler.ui.warn \ + "The latest bundler is #{latest}, but you are currently running #{current}.\n" \ + "To update to the most recent version, run `bundle update --bundler`" + rescue RuntimeError + nil + end + + def remembered_negative_flag_deprecation(name) + positive_name = name.gsub(/\Ano-/, "") + option = current_command.options[positive_name] + flag_name = "--no-" + option.switch_name.gsub(/\A--/, "") + + flag_deprecation(positive_name, flag_name, option) + end + + def remembered_flag_deprecation(name) + option = current_command.options[name] + flag_name = option.switch_name + + flag_deprecation(name, flag_name, option) + end + + def flag_deprecation(name, flag_name, option) + name_index = ARGV.find {|arg| flag_name == arg.split("=")[0] } + return unless name_index + + value = options[name] + value = value.join(" ").to_s if option.type == :array + value = "'#{value}'" unless option.type == :boolean + + print_remembered_flag_deprecation(flag_name, name.tr("-", "_"), value) + end + + def print_remembered_flag_deprecation(flag_name, option_name, option_value) + message = + "The `#{flag_name}` flag is deprecated because it relies on being " \ + "remembered across bundler invocations, which bundler will no longer " \ + "do in future versions. Instead please use `bundle config set #{option_name} " \ + "#{option_value}`, and stop using this flag" + removed_message = + "The `#{flag_name}` flag has been removed because it relied on being " \ + "remembered across bundler invocations, which bundler will no longer " \ + "do. Instead please use `bundle config set #{option_name} " \ + "#{option_value}`, and stop using this flag" + Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/add.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/add.rb new file mode 100644 index 00000000..002d9e1d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/add.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Add + attr_reader :gems, :options, :version + + def initialize(options, gems) + @gems = gems + @options = options + @options[:group] = options[:group].split(",").map(&:strip) unless options[:group].nil? + @version = options[:version].split(",").map(&:strip) unless options[:version].nil? + end + + def run + validate_options! + inject_dependencies + perform_bundle_install unless options["skip-install"] + end + + private + + def perform_bundle_install + Installer.install(Bundler.root, Bundler.definition) + Bundler.load.cache if Bundler.app_cache.exist? + end + + def inject_dependencies + dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) } + + Injector.inject(dependencies, + conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified + optimistic: options[:optimistic], + strict: options[:strict]) + end + + def validate_options! + raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic] + + # raise error when no gems are specified + raise InvalidOption, "Please specify gems to add." if gems.empty? + + version.to_a.each do |v| + raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN.match?(v.to_s) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/binstubs.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/binstubs.rb new file mode 100644 index 00000000..8ce138df --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/binstubs.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Binstubs + attr_reader :options, :gems + def initialize(options, gems) + @options = options + @gems = gems + end + + def run + Bundler.definition.validate_runtime! + path_option = options["path"] + path_option = nil if path_option&.empty? + Bundler.settings.set_command_option :bin, path_option if options["path"] + Bundler.settings.set_command_option_if_given :shebang, options["shebang"] + installer = Installer.new(Bundler.root, Bundler.definition) + + installer_opts = { + force: options[:force], + binstubs_cmd: true, + all_platforms: options["all-platforms"], + } + + if options[:all] + raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? + @gems = Bundler.definition.specs.map(&:name) + installer_opts.delete(:binstubs_cmd) + elsif gems.empty? + Bundler.ui.error "`bundle binstubs` needs at least one gem to run." + exit 1 + end + + gems.each do |gem_name| + spec = Bundler.definition.specs.find {|s| s.name == gem_name } + unless spec + raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( + gem_name, Bundler.definition.specs + ) + end + + if options[:standalone] + if gem_name == "bundler" + Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") unless options[:all] + next + end + + Bundler.settings.temporary(path: Bundler.settings[:path] || Bundler.root) do + installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) + end + else + installer.generate_bundler_executable_stubs(spec, installer_opts) + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/cache.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/cache.rb new file mode 100644 index 00000000..2e63a16e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/cache.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Cache + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + Bundler.settings.set_command_option_if_given :path, options[:path] + Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] + + setup_cache_all + install + + # TODO: move cache contents here now that all bundles are locked + custom_path = Bundler.settings[:path] if options[:path] + + Bundler.settings.temporary(cache_all_platforms: options["all-platforms"]) do + Bundler.load.cache(custom_path) + end + end + + private + + def install + require_relative "install" + options = self.options.dup + options["local"] = false if Bundler.settings[:cache_all_platforms] + options["no-cache"] = true + Bundler::CLI::Install.new(options).run + end + + def setup_cache_all + all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil) + + Bundler.settings.set_command_option_if_given :cache_all, all + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/check.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/check.rb new file mode 100644 index 00000000..33d31cdd --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/check.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Check + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.settings.set_command_option_if_given :path, options[:path] + + definition = Bundler.definition + definition.validate_runtime! + + begin + definition.resolve_only_locally! + not_installed = definition.missing_specs + rescue GemNotFound, SolveFailure + Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." + Bundler.ui.warn "Install missing gems with `bundle install`." + exit 1 + end + + if not_installed.any? + Bundler.ui.error "The following gems are missing" + not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } + Bundler.ui.warn "Install missing gems with `bundle install`" + exit 1 + elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? + Bundler.ui.error "This bundle has been frozen, but there is no #{SharedHelpers.relative_lockfile_path} present" + exit 1 + else + Bundler.load.lock(preserve_unknown_sections: true) unless options[:"dry-run"] + Bundler.ui.info "The Gemfile's dependencies are satisfied" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/clean.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/clean.rb new file mode 100644 index 00000000..c6b0968e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/clean.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Clean + attr_reader :options + + def initialize(options) + @options = options + end + + def run + require_path_or_force unless options[:"dry-run"] + Bundler.load.clean(options[:"dry-run"]) + end + + protected + + def require_path_or_force + return unless Bundler.use_system_gems? && !options[:force] + raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ + "If you're sure you want to remove every system gem not in this " \ + "bundle, run `bundle clean --force`." + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/common.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/common.rb new file mode 100644 index 00000000..7ef6deb2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/common.rb @@ -0,0 +1,138 @@ +# frozen_string_literal: true + +module Bundler + module CLI::Common + def self.output_post_install_messages(messages) + return if Bundler.settings["ignore_messages"] + messages.to_a.each do |name, msg| + print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] + end + end + + def self.print_post_install_message(name, msg) + Bundler.ui.confirm "Post-install message from #{name}:" + Bundler.ui.info msg + end + + def self.output_fund_metadata_summary + return if Bundler.settings["ignore_funding_requests"] + definition = Bundler.definition + current_dependencies = definition.requested_dependencies + current_specs = definition.specs + + count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") } + + return if count.zero? + + intro = count > 1 ? "#{count} installed gems you directly depend on are" : "#{count} installed gem you directly depend on is" + message = "#{intro} looking for funding.\n Run `bundle fund` for details" + Bundler.ui.info message + end + + def self.output_without_groups_message(command) + return if Bundler.settings[:without].empty? + Bundler.ui.confirm without_groups_message(command) + end + + def self.without_groups_message(command) + command_in_past_tense = command == :install ? "installed" : "updated" + groups = Bundler.settings[:without] + "Gems in the #{verbalize_groups(groups)} were not #{command_in_past_tense}." + end + + def self.verbalize_groups(groups) + groups.map! {|g| "'#{g}'" } + group_list = [groups[0...-1].join(", "), groups[-1..-1]]. + reject {|s| s.to_s.empty? }.join(" and ") + group_str = groups.size == 1 ? "group" : "groups" + "#{group_str} #{group_list}" + end + + def self.select_spec(name, regex_match = nil) + specs = [] + regexp = Regexp.new(name) if regex_match + + Bundler.definition.specs.each do |spec| + return spec if spec.name == name + specs << spec if regexp && spec.name.match?(regexp) + end + + default_spec = default_gem_spec(name) + specs << default_spec if default_spec + + case specs.count + when 0 + dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name } + + if dep_in_other_group + raise GemNotFound, "Could not find gem '#{name}', because it's in the #{verbalize_groups(dep_in_other_group.groups)}, configured to be ignored." + else + raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) + end + when 1 + specs.first + else + ask_for_spec_from(specs) + end + rescue RegexpError + raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) + end + + def self.default_gem_spec(name) + gem_spec = Gem::Specification.find_all_by_name(name).last + gem_spec if gem_spec&.default_gem? + end + + def self.ask_for_spec_from(specs) + specs.each_with_index do |spec, index| + Bundler.ui.info "#{index.succ} : #{spec.name}", true + end + Bundler.ui.info "0 : - exit -", true + + num = Bundler.ui.ask("> ").to_i + num > 0 ? specs[num - 1] : nil + end + + def self.gem_not_found_message(missing_gem_name, alternatives) + require_relative "../similarity_detector" + message = "Could not find gem '#{missing_gem_name}'." + alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } + suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) + message += "\nDid you mean #{suggestions}?" if suggestions + message + end + + def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) + return unless locked_gems + + locked_names = locked_gems.specs.map(&:name).uniq + names.-(locked_names).each do |g| + raise GemNotFound, gem_not_found_message(g, locked_names) + end + end + + def self.configure_gem_version_promoter(definition, options) + patch_level = patch_level_options(options) + patch_level << :patch if patch_level.empty? && Bundler.settings[:prefer_patch] + raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 + + definition.gem_version_promoter.tap do |gvp| + gvp.level = patch_level.first || :major + gvp.strict = options[:strict] || options["filter-strict"] + gvp.pre = options[:pre] + end + end + + def self.patch_level_options(options) + [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } + end + + def self.clean_after_install? + clean = Bundler.settings[:clean] + return clean unless clean.nil? + clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil? + clean &&= !Bundler.use_system_gems? + clean + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/config.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/config.rb new file mode 100644 index 00000000..77b502fe --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/config.rb @@ -0,0 +1,204 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Config < Thor + class_option :parseable, type: :boolean, banner: "Use minimal formatting for more parseable output" + + def self.scope_options + method_option :global, type: :boolean, banner: "Only change the global config" + method_option :local, type: :boolean, banner: "Only change the local config" + end + private_class_method :scope_options + + desc "base NAME [VALUE]", "The Bundler 1 config interface", hide: true + scope_options + method_option :delete, type: :boolean, banner: "delete" + def base(name = nil, *value) + new_args = + if ARGV.size == 1 + ["config", "list"] + elsif ARGV.include?("--delete") + ARGV.map {|arg| arg == "--delete" ? "unset" : arg } + elsif ARGV.include?("--global") || ARGV.include?("--local") || ARGV.size == 3 + ["config", "set", *ARGV[1..-1]] + else + ["config", "get", ARGV[1]] + end + + message = "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead." + removed_message = "Using the `config` command without a subcommand [list, get, set, unset] is has been removed. Use `bundle #{new_args.join(" ")}` instead." + SharedHelpers.major_deprecation 3, message, removed_message: removed_message + + Base.new(options, name, value, self).run + end + + desc "list", "List out all configured settings" + def list + Base.new(options, nil, nil, self).run + end + + desc "get NAME", "Returns the value for the given key" + def get(name) + Base.new(options, name, nil, self).run + end + + desc "set NAME VALUE", "Sets the given value for the given key" + scope_options + def set(name, value, *value_) + Base.new(options, name, value_.unshift(value), self).run + end + + desc "unset NAME", "Unsets the value for the given key" + scope_options + def unset(name) + options[:delete] = true + Base.new(options, name, nil, self).run + end + + default_task :base + + class Base + attr_reader :name, :value, :options, :scope, :thor + + def initialize(options, name, value, thor) + @options = options + @name = name + value = Array(value) + @value = value.empty? ? nil : value.join(" ") + @thor = thor + validate_scope! + end + + def run + unless name + warn_unused_scope "Ignoring --#{scope}" + confirm_all + return + end + + if options[:delete] + if !explicit_scope? || scope != "global" + Bundler.settings.set_local(name, nil) + end + if !explicit_scope? || scope != "local" + Bundler.settings.set_global(name, nil) + end + return + end + + if value.nil? + warn_unused_scope "Ignoring --#{scope} since no value to set was given" + + if options[:parseable] + if value = Bundler.settings[name] + Bundler.ui.info("#{name}=#{value}") + end + return + end + + confirm(name) + return + end + + Bundler.ui.info(message) if message + Bundler.settings.send("set_#{scope}", name, new_value) + end + + def confirm_all + if @options[:parseable] + thor.with_padding do + Bundler.settings.all.each do |setting| + val = Bundler.settings[setting] + Bundler.ui.info "#{setting}=#{val}" + end + end + else + Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" + Bundler.settings.all.each do |setting| + Bundler.ui.confirm setting + show_pretty_values_for(setting) + Bundler.ui.confirm "" + end + end + end + + def confirm(name) + Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" + show_pretty_values_for(name) + end + + def new_value + pathname = Pathname.new(value) + if name.start_with?("local.") && pathname.directory? + pathname.expand_path.to_s + else + value + end + end + + def message + locations = Bundler.settings.locations(name) + if @options[:parseable] + "#{name}=#{new_value}" if new_value + elsif scope == "global" + if !locations[:local].nil? + "Your application has set #{name} to #{locations[:local].inspect}. " \ + "This will override the global value you are currently setting" + elsif locations[:env] + "You have a bundler environment variable for #{name} set to " \ + "#{locations[:env].inspect}. This will take precedence over the global value you are setting" + elsif !locations[:global].nil? && locations[:global] != value + "You are replacing the current global value of #{name}, which is currently " \ + "#{locations[:global].inspect}" + end + elsif scope == "local" && !locations[:local].nil? && locations[:local] != value + "You are replacing the current local value of #{name}, which is currently " \ + "#{locations[:local].inspect}" + end + end + + def show_pretty_values_for(setting) + thor.with_padding do + Bundler.settings.pretty_values_for(setting).each do |line| + Bundler.ui.info line + end + end + end + + def explicit_scope? + @explicit_scope + end + + def warn_unused_scope(msg) + return unless explicit_scope? + return if options[:parseable] + + Bundler.ui.warn(msg) + end + + def validate_scope! + @explicit_scope = true + scopes = %w[global local].select {|s| options[s] } + case scopes.size + when 0 + @scope = inside_app? ? "local" : "global" + @explicit_scope = false + when 1 + @scope = scopes.first + else + raise InvalidOption, + "The options #{scopes.join " and "} were specified. Please only use one of the switches at a time." + end + end + + private + + def inside_app? + Bundler.root + true + rescue GemfileNotFound + false + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/console.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/console.rb new file mode 100644 index 00000000..840cf14f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/console.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Console + attr_reader :options, :group + def initialize(options, group) + @options = options + @group = group + end + + def run + message = "bundle console will be replaced by `bin/console` generated by `bundle gem `" + removed_message = "bundle console has been replaced by `bin/console` generated by `bundle gem `" + Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message + + group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require + ARGV.clear + + console = get_console(Bundler.settings[:console] || "irb") + console.start + end + + def get_console(name) + require name + get_constant(name) + rescue LoadError + Bundler.ui.error "Couldn't load console #{name}, falling back to irb" + require "irb" + get_constant("irb") + end + + def get_constant(name) + const_name = { + "pry" => :Pry, + "ripl" => :Ripl, + "irb" => :IRB, + }[name] + Object.const_get(const_name) + rescue NameError + Bundler.ui.error "Could not find constant #{const_name}" + exit 1 + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/doctor.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/doctor.rb new file mode 100644 index 00000000..1f6fc93c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/doctor.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true + +require "rbconfig" +require "shellwords" +require "fiddle" + +module Bundler + class CLI::Doctor + DARWIN_REGEX = /\s+(.+) \(compatibility / + LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/ + + attr_reader :options + + def initialize(options) + @options = options + end + + def otool_available? + Bundler.which("otool") + end + + def ldd_available? + Bundler.which("ldd") + end + + def dylibs_darwin(path) + output = `/usr/bin/otool -L #{path.shellescape}`.chomp + dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq + # ignore @rpath and friends + dylibs.reject {|dylib| dylib.start_with? "@" } + end + + def dylibs_ldd(path) + output = `/usr/bin/ldd #{path.shellescape}`.chomp + output.split("\n").map do |l| + match = l.match(LDD_REGEX) + next if match.nil? + match.captures[0] + end.compact + end + + def dylibs(path) + case RbConfig::CONFIG["host_os"] + when /darwin/ + return [] unless otool_available? + dylibs_darwin(path) + when /(linux|solaris|bsd)/ + return [] unless ldd_available? + dylibs_ldd(path) + else # Windows, etc. + Bundler.ui.warn("Dynamic library check not supported on this platform.") + [] + end + end + + def bundles_for_gem(spec) + Dir.glob("#{spec.full_gem_path}/**/*.bundle") + end + + def check! + require_relative "check" + Bundler::CLI::Check.new({}).run + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + Bundler.settings.validate! + check! + + definition = Bundler.definition + broken_links = {} + + definition.specs.each do |spec| + bundles_for_gem(spec).each do |bundle| + bad_paths = dylibs(bundle).select do |f| + Fiddle.dlopen(f) + false + rescue Fiddle::DLError + true + end + if bad_paths.any? + broken_links[spec] ||= [] + broken_links[spec].concat(bad_paths) + end + end + end + + permissions_valid = check_home_permissions + + if broken_links.any? + message = "The following gems are missing OS dependencies:" + broken_links.map do |spec, paths| + paths.uniq.map do |path| + "\n * #{spec.name}: #{path}" + end + end.flatten.sort.each {|m| message += m } + raise ProductionError, message + elsif !permissions_valid + Bundler.ui.info "No issues found with the installed bundle" + end + end + + private + + def check_home_permissions + require "find" + files_not_readable_or_writable = [] + files_not_rw_and_owned_by_different_user = [] + files_not_owned_by_current_user_but_still_rw = [] + broken_symlinks = [] + Find.find(Bundler.bundle_path.to_s).each do |f| + if !File.exist?(f) + broken_symlinks << f + elsif !File.writable?(f) || !File.readable?(f) + if File.stat(f).uid != Process.uid + files_not_rw_and_owned_by_different_user << f + else + files_not_readable_or_writable << f + end + elsif File.stat(f).uid != Process.uid + files_not_owned_by_current_user_but_still_rw << f + end + end + + ok = true + + if broken_symlinks.any? + Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" + + ok = false + end + + if files_not_owned_by_current_user_but_still_rw.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" + + ok = false + end + + if files_not_rw_and_owned_by_different_user.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" + + ok = false + end + + if files_not_readable_or_writable.any? + Bundler.ui.warn "Files exist in the Bundler home that are not " \ + "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" + + ok = false + end + + ok + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/exec.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/exec.rb new file mode 100644 index 00000000..f81cd5d2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/exec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require_relative "../current_ruby" + +module Bundler + class CLI::Exec + attr_reader :options, :args, :cmd + + TRAPPED_SIGNALS = %w[INT].freeze + + def initialize(options, args) + @options = options + @cmd = args.shift + @args = args + @args << { close_others: !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby? + end + + def run + validate_cmd! + SharedHelpers.set_bundle_environment + if bin_path = Bundler.which(cmd) + if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) + return kernel_load(bin_path, *args) + end + kernel_exec(bin_path, *args) + else + # exec using the given command + kernel_exec(cmd, *args) + end + end + + private + + def validate_cmd! + return unless cmd.nil? + Bundler.ui.error "bundler: exec needs a command to run" + exit 128 + end + + def kernel_exec(*args) + Kernel.exec(*args) + rescue Errno::EACCES, Errno::ENOEXEC + Bundler.ui.error "bundler: not executable: #{cmd}" + exit 126 + rescue Errno::ENOENT + Bundler.ui.error "bundler: command not found: #{cmd}" + Bundler.ui.warn "Install missing gem executables with `bundle install`" + exit 127 + end + + def kernel_load(file, *args) + args.pop if args.last.is_a?(Hash) + ARGV.replace(args) + $0 = file + Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) + require_relative "../setup" + TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } + Kernel.load(file) + rescue SystemExit, SignalException + raise + rescue Exception # rubocop:disable Lint/RescueException + Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" + Bundler::FriendlyErrors.disable! + raise + end + + def process_title(file, args) + "#{file} #{args.join(" ")}".strip + end + + def ruby_shebang?(file) + possibilities = [ + "#!/usr/bin/env ruby\n", + "#!/usr/bin/env jruby\n", + "#!/usr/bin/env truffleruby\n", + "#!#{Gem.ruby}\n", + ] + + if File.zero?(file) + Bundler.ui.warn "#{file} is empty" + return false + end + + first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } + possibilities.any? {|shebang| first_line.start_with?(shebang) } + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/fund.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/fund.rb new file mode 100644 index 00000000..52db5aef --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/fund.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Fund + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.definition.validate_runtime! + + groups = Array(options[:group]).map(&:to_sym) + + deps = if groups.any? + Bundler.definition.dependencies_for(groups) + else + Bundler.definition.current_dependencies + end + + fund_info = deps.each_with_object([]) do |dep, arr| + spec = Bundler.definition.specs[dep.name].first + if spec.metadata.key?("funding_uri") + arr << "* #{spec.name} (#{spec.version})\n Funding: #{spec.metadata["funding_uri"]}" + end + end + + if fund_info.empty? + Bundler.ui.info "None of the installed gems you directly depend on are looking for funding." + else + Bundler.ui.info fund_info.join("\n") + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/gem.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/gem.rb new file mode 100644 index 00000000..f0bb3aab --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/gem.rb @@ -0,0 +1,471 @@ +# frozen_string_literal: true + +require "pathname" + +module Bundler + class CLI + Bundler.require_thor_actions + include Thor::Actions + end + + class CLI::Gem + TEST_FRAMEWORK_VERSIONS = { + "rspec" => "3.0", + "minitest" => "5.16", + "test-unit" => "3.0", + }.freeze + + attr_reader :options, :gem_name, :thor, :name, :target, :extension + + def initialize(options, gem_name, thor) + @options = options + @gem_name = resolve_name(gem_name) + + @thor = thor + thor.behavior = :invoke + thor.destination_root = nil + + @name = @gem_name + @target = SharedHelpers.pwd.join(gem_name) + + @extension = options[:ext] + + validate_ext_name if @extension + validate_rust_builder_rubygems_version if @extension == "rust" + travis_removal_info + end + + def run + Bundler.ui.confirm "Creating gem '#{name}'..." + + underscored_name = name.tr("-", "_") + namespaced_path = name.tr("-", "/") + constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } + constant_array = constant_name.split("::") + minitest_constant_name = constant_array.clone.tap {|a| a[-1] = "Test#{a[-1]}" }.join("::") # Foo::Bar => Foo::TestBar + + use_git = Bundler.git_present? && options[:git] + + git_author_name = use_git ? `git config user.name`.chomp : "" + git_username = use_git ? `git config github.user`.chomp : "" + git_user_email = use_git ? `git config user.email`.chomp : "" + + github_username = if options[:github_username].nil? + git_username + elsif options[:github_username] == false + "" + else + options[:github_username] + end + + config = { + name: name, + underscored_name: underscored_name, + namespaced_path: namespaced_path, + makefile_path: "#{underscored_name}/#{underscored_name}", + constant_name: constant_name, + constant_array: constant_array, + author: git_author_name.empty? ? "TODO: Write your name" : git_author_name, + email: git_user_email.empty? ? "TODO: Write your email address" : git_user_email, + test: options[:test], + ext: extension, + exe: options[:exe], + bundler_version: bundler_dependency_version, + git: use_git, + github_username: github_username.empty? ? "[USERNAME]" : github_username, + required_ruby_version: required_ruby_version, + rust_builder_required_rubygems_version: rust_builder_required_rubygems_version, + minitest_constant_name: minitest_constant_name, + } + ensure_safe_gem_name(name, constant_array) + + templates = { + "#{Bundler.preferred_gemfile_name}.tt" => Bundler.preferred_gemfile_name, + "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", + "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", + "sig/newgem.rbs.tt" => "sig/#{namespaced_path}.rbs", + "newgem.gemspec.tt" => "#{name}.gemspec", + "Rakefile.tt" => "Rakefile", + "README.md.tt" => "README.md", + "bin/console.tt" => "bin/console", + "bin/setup.tt" => "bin/setup", + } + + executables = %w[ + bin/console + bin/setup + ] + + templates.merge!("gitignore.tt" => ".gitignore") if use_git + + if test_framework = ask_and_set_test_framework + config[:test] = test_framework + config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] + + case test_framework + when "rspec" + templates.merge!( + "rspec.tt" => ".rspec", + "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", + "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" + ) + config[:test_task] = :spec + when "minitest" + # Generate path for minitest target file (FileList["test/**/test_*.rb"]) + # foo => test/test_foo.rb + # foo-bar => test/foo/test_bar.rb + # foo_bar => test/test_foo_bar.rb + paths = namespaced_path.rpartition("/") + paths[2] = "test_#{paths[2]}" + minitest_namespaced_path = paths.join("") + + templates.merge!( + "test/minitest/test_helper.rb.tt" => "test/test_helper.rb", + "test/minitest/test_newgem.rb.tt" => "test/#{minitest_namespaced_path}.rb" + ) + config[:test_task] = :test + when "test-unit" + templates.merge!( + "test/test-unit/test_helper.rb.tt" => "test/test_helper.rb", + "test/test-unit/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" + ) + config[:test_task] = :test + end + end + + config[:ci] = ask_and_set_ci + case config[:ci] + when "github" + templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml") + config[:ci_config_path] = ".github " + when "gitlab" + templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml") + config[:ci_config_path] = ".gitlab-ci.yml " + when "circle" + templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml") + config[:ci_config_path] = ".circleci " + end + + if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", + "This means that any other developer or company will be legally allowed to use your code " \ + "for free as long as they admit you created it. You can read more about the MIT license " \ + "at https://choosealicense.com/licenses/mit.") + config[:mit] = true + Bundler.ui.info "MIT License enabled in config" + templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") + end + + if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", + "Codes of conduct can increase contributions to your project by contributors who " \ + "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ + "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ + "of enforcing it, so be sure that you are prepared to do that. Be sure that your email " \ + "address is specified as a contact in the generated code of conduct so that people know " \ + "who to contact in case of a violation. For suggestions about " \ + "how to enforce codes of conduct, see https://bit.ly/coc-enforcement.") + config[:coc] = true + Bundler.ui.info "Code of conduct enabled in config" + templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") + end + + if ask_and_set(:changelog, "Do you want to include a changelog?", + "A changelog is a file which contains a curated, chronologically ordered list of notable " \ + "changes for each version of a project. To make it easier for users and contributors to" \ + " see precisely what notable changes have been made between each release (or version) of" \ + " the project. Whether consumers or developers, the end users of software are" \ + " human beings who care about what's in the software. When the software changes, people " \ + "want to know why and how. see https://keepachangelog.com") + config[:changelog] = true + Bundler.ui.info "Changelog enabled in config" + templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md") + end + + config[:linter] = ask_and_set_linter + case config[:linter] + when "rubocop" + config[:linter_version] = rubocop_version + Bundler.ui.info "RuboCop enabled in config" + templates.merge!("rubocop.yml.tt" => ".rubocop.yml") + when "standard" + config[:linter_version] = standard_version + Bundler.ui.info "Standard enabled in config" + templates.merge!("standard.yml.tt" => ".standard.yml") + end + + templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] + + if extension == "c" + templates.merge!( + "ext/newgem/extconf-c.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", + "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" + ) + end + + if extension == "rust" + templates.merge!( + "Cargo.toml.tt" => "Cargo.toml", + "ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml", + "ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs", + ) + end + + if target.exist? && !target.directory? + Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." + exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] + end + + if use_git + Bundler.ui.info "Initializing git repo in #{target}" + require "shellwords" + `git init #{target.to_s.shellescape}` + + config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp + end + + templates.each do |src, dst| + destination = target.join(dst) + thor.template("newgem/#{src}", destination, config) + end + + executables.each do |file| + path = target.join(file) + executable = (path.stat.mode | 0o111) + path.chmod(executable) + end + + if use_git + IO.popen(%w[git add .], { chdir: target }, &:read) + end + + # Open gemspec in editor + open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] + + Bundler.ui.info "Gem '#{name}' was successfully created. " \ + "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" + end + + private + + def resolve_name(name) + SharedHelpers.pwd.join(name).basename.to_s + end + + def ask_and_set(key, header, message) + choice = options[key] + choice = Bundler.settings["gem.#{key}"] if choice.nil? + + if choice.nil? + Bundler.ui.confirm header + choice = Bundler.ui.yes? "#{message} y/(n):" + Bundler.settings.set_global("gem.#{key}", choice) + end + + choice + end + + def validate_ext_name + return unless gem_name.index("-") + + Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ + "naming guidelines for C extensions. For more information, \n" \ + "see the 'Extension Naming' section at the following URL:\n" \ + "https://guides.rubygems.org/gems-with-extensions/\n" + exit 1 + end + + def ask_and_set_test_framework + test_framework = options[:test] || Bundler.settings["gem.test"] + + if test_framework.to_s.empty? + Bundler.ui.confirm "Do you want to generate tests with your gem?" + Bundler.ui.info hint_text("test") + + result = Bundler.ui.ask "Enter a test framework. rspec/minitest/test-unit/(none):" + if /rspec|minitest|test-unit/.match?(result) + test_framework = result + else + test_framework = false + end + end + + if Bundler.settings["gem.test"].nil? + Bundler.settings.set_global("gem.test", test_framework) + end + + if options[:test] == Bundler.settings["gem.test"] + Bundler.ui.info "#{options[:test]} is already configured, ignoring --test flag." + end + + test_framework + end + + def hint_text(setting) + if Bundler.settings["gem.#{setting}"] == false + "Your choice will only be applied to this gem." + else + "Future `bundle gem` calls will use your choice. " \ + "This setting can be changed anytime with `bundle config gem.#{setting}`." + end + end + + def ask_and_set_ci + ci_template = options[:ci] || Bundler.settings["gem.ci"] + + if ci_template.to_s.empty? + Bundler.ui.confirm "Do you want to set up continuous integration for your gem? " \ + "Supported services:\n" \ + "* CircleCI: https://circleci.com/\n" \ + "* GitHub Actions: https://github.com/features/actions\n" \ + "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \ + "\n" + Bundler.ui.info hint_text("ci") + + result = Bundler.ui.ask "Enter a CI service. github/gitlab/circle/(none):" + if /github|gitlab|circle/.match?(result) + ci_template = result + else + ci_template = false + end + end + + if Bundler.settings["gem.ci"].nil? + Bundler.settings.set_global("gem.ci", ci_template) + end + + if options[:ci] == Bundler.settings["gem.ci"] + Bundler.ui.info "#{options[:ci]} is already configured, ignoring --ci flag." + end + + ci_template + end + + def ask_and_set_linter + linter_template = options[:linter] || Bundler.settings["gem.linter"] + linter_template = deprecated_rubocop_option if linter_template.nil? + + if linter_template.to_s.empty? + Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \ + "Supported Linters:\n" \ + "* RuboCop: https://rubocop.org\n" \ + "* Standard: https://github.com/standardrb/standard\n" \ + "\n" + Bundler.ui.info hint_text("linter") + + result = Bundler.ui.ask "Enter a linter. rubocop/standard/(none):" + if /rubocop|standard/.match?(result) + linter_template = result + else + linter_template = false + end + end + + if Bundler.settings["gem.linter"].nil? + Bundler.settings.set_global("gem.linter", linter_template) + end + + # Once gem.linter safely set, unset the deprecated gem.rubocop + unless Bundler.settings["gem.rubocop"].nil? + Bundler.settings.set_global("gem.rubocop", nil) + end + + if options[:linter] == Bundler.settings["gem.linter"] + Bundler.ui.info "#{options[:linter]} is already configured, ignoring --linter flag." + end + + linter_template + end + + def deprecated_rubocop_option + if !options[:rubocop].nil? + if options[:rubocop] + Bundler::SharedHelpers.major_deprecation 2, + "--rubocop is deprecated, use --linter=rubocop", + removed_message: "--rubocop has been removed, use --linter=rubocop" + "rubocop" + else + Bundler::SharedHelpers.major_deprecation 2, + "--no-rubocop is deprecated, use --linter", + removed_message: "--no-rubocop has been removed, use --linter" + false + end + elsif !Bundler.settings["gem.rubocop"].nil? + Bundler::SharedHelpers.major_deprecation 2, + "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead", + removed_message: "config gem.rubocop has been removed; we've updated your config to use gem.linter instead" + Bundler.settings["gem.rubocop"] ? "rubocop" : false + end + end + + def bundler_dependency_version + v = Gem::Version.new(Bundler::VERSION) + req = v.segments[0..1] + req << "a" if v.prerelease? + req.join(".") + end + + def ensure_safe_gem_name(name, constant_array) + if /^\d/.match?(name) + Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." + exit 1 + end + + constant_name = constant_array.join("::") + + existing_constant = constant_array.inject(Object) do |c, s| + defined = begin + c.const_defined?(s) + rescue NameError + Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" + exit 1 + end + (defined && c.const_get(s)) || break + end + + return unless existing_constant + Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." + exit 1 + end + + def open_editor(editor, file) + thor.run(%(#{editor} "#{file}")) + end + + def rust_builder_required_rubygems_version + "3.3.11" + end + + def required_ruby_version + "3.0.0" + end + + def rubocop_version + "1.21" + end + + def standard_version + "1.3" + end + + # TODO: remove at next minor release + def travis_removal_info + if options[:ci] == "travis" + Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator." + exit 1 + end + + if Bundler.settings["gem.ci"] == "travis" + Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator, but it is present in bundle config. Please configure another provider using `bundle config set gem.ci SERVICE` (where SERVICE is one of github/gitlab/circle) or unset configuration using `bundle config unset gem.ci`." + exit 1 + end + end + + def validate_rust_builder_rubygems_version + if Gem::Version.new(rust_builder_required_rubygems_version) > Gem.rubygems_version + Bundler.ui.error "Your RubyGems version (#{Gem.rubygems_version}) is too old to build Rust extension. Please update your RubyGems using `gem update --system` or any other way and try again." + exit 1 + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/info.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/info.rb new file mode 100644 index 00000000..8f34956a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/info.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Info + attr_reader :gem_name, :options + def initialize(options, gem_name) + @options = options + @gem_name = gem_name + end + + def run + Bundler.ui.silence do + Bundler.definition.validate_runtime! + Bundler.load.lock + end + + spec = spec_for_gem(gem_name) + + if spec + return print_gem_path(spec) if @options[:path] + return print_gem_version(spec) if @options[:version] + print_gem_info(spec) + end + end + + private + + def spec_for_gem(name) + Bundler::CLI::Common.select_spec(name, :regex_match) + end + + def print_gem_version(spec) + Bundler.ui.info spec.version.to_s + end + + def print_gem_path(spec) + name = spec.name + if name == "bundler" + path = File.expand_path("../../..", __dir__) + else + path = spec.full_gem_path + if spec.deleted_gem? + return Bundler.ui.warn "The gem #{name} has been deleted. It was installed at: #{path}" + end + end + + Bundler.ui.info path + end + + def print_gem_info(spec) + metadata = spec.metadata + name = spec.name + gem_info = String.new + gem_info << " * #{name} (#{spec.version}#{spec.git_version})\n" + gem_info << "\tSummary: #{spec.summary}\n" if spec.summary + gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage + gem_info << "\tDocumentation: #{metadata["documentation_uri"]}\n" if metadata.key?("documentation_uri") + gem_info << "\tSource Code: #{metadata["source_code_uri"]}\n" if metadata.key?("source_code_uri") + gem_info << "\tFunding: #{metadata["funding_uri"]}\n" if metadata.key?("funding_uri") + gem_info << "\tWiki: #{metadata["wiki_uri"]}\n" if metadata.key?("wiki_uri") + gem_info << "\tChangelog: #{metadata["changelog_uri"]}\n" if metadata.key?("changelog_uri") + gem_info << "\tBug Tracker: #{metadata["bug_tracker_uri"]}\n" if metadata.key?("bug_tracker_uri") + gem_info << "\tMailing List: #{metadata["mailing_list_uri"]}\n" if metadata.key?("mailing_list_uri") + gem_info << "\tPath: #{spec.full_gem_path}\n" + gem_info << "\tDefault Gem: yes\n" if spec.respond_to?(:default_gem?) && spec.default_gem? + gem_info << "\tReverse Dependencies: \n\t\t#{gem_dependencies.join("\n\t\t")}" if gem_dependencies.any? + + if name != "bundler" && spec.deleted_gem? + return Bundler.ui.warn "The gem #{name} has been deleted. Gemspec information is still available though:\n#{gem_info}" + end + + Bundler.ui.info gem_info + end + + def gem_dependencies + @gem_dependencies ||= Bundler.definition.specs.map do |spec| + dependency = spec.dependencies.find {|dep| dep.name == gem_name } + next unless dependency + "#{spec.name} (#{spec.version}) depends on #{gem_name} (#{dependency.requirements_list.join(", ")})" + end.compact.sort + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/init.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/init.rb new file mode 100644 index 00000000..246b9d64 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/init.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Init + attr_reader :options + def initialize(options) + @options = options + end + + def run + if File.exist?(gemfile) + Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" + exit 1 + end + + unless File.writable?(Dir.pwd) + Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." + exit 1 + end + + if options[:gemspec] + gemspec = File.expand_path(options[:gemspec]) + unless File.exist?(gemspec) + Bundler.ui.error "Gem specification #{gemspec} doesn't exist" + exit 1 + end + + spec = Bundler.load_gemspec_uncached(gemspec) + + File.open(gemfile, "wb") do |file| + file << "# Generated from #{gemspec}\n" + file << spec.to_gemfile + end + else + File.open(File.expand_path("../templates/Gemfile", __dir__), "r") do |template| + File.open(gemfile, "wb") do |destination| + IO.copy_stream(template, destination) + end + end + end + + puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" + end + + private + + def gemfile + @gemfile ||= options[:gemfile] || Bundler.preferred_gemfile_name + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/inject.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/inject.rb new file mode 100644 index 00000000..8093a852 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/inject.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Inject + attr_reader :options, :name, :version, :group, :source, :gems + def initialize(options, name, version) + @options = options + @name = name + @version = version || last_version_number + @group = options[:group].split(",") unless options[:group].nil? + @source = options[:source] + @gems = [] + end + + def run + # The required arguments allow Thor to give useful feedback when the arguments + # are incorrect. This adds those first two arguments onto the list as a whole. + gems.unshift(source).unshift(group).unshift(version).unshift(name) + + # Build an array of Dependency objects out of the arguments + deps = [] + # when `inject` support addition of more than one gem, then this loop will + # help. Currently this loop is running once. + gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| + ops = Gem::Requirement::OPS.map {|key, _val| key } + has_op = ops.any? {|op| gem_version.start_with? op } + gem_version = "~> #{gem_version}" unless has_op + deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) + end + + added = Injector.inject(deps, options) + + if added.any? + Bundler.ui.confirm "Added to Gemfile:" + Bundler.ui.confirm(added.map do |d| + name = "'#{d.name}'" + requirement = ", '#{d.requirement}'" + group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) + source = ", :source => '#{d.source}'" unless d.source.nil? + %(gem #{name}#{requirement}#{group}#{source}) + end.join("\n")) + else + Bundler.ui.confirm "All gems were already present in the Gemfile" + end + end + + private + + def last_version_number + definition = Bundler.definition(true) + definition.resolve_remotely! + specs = definition.index[name].sort_by(&:version) + unless options[:pre] + specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } + end + spec = specs.last + spec.version.to_s + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/install.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/install.rb new file mode 100644 index 00000000..6c102d53 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/install.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Install + attr_reader :options + def initialize(options) + @options = options + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + + warn_if_root + + Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed + + Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD + + # Disable color in deployment mode + Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] + + check_for_options_conflicts + + check_trust_policy + + if options[:deployment] || options[:frozen] || Bundler.frozen_bundle? + unless Bundler.default_lockfile.exist? + flag = "--deployment flag" if options[:deployment] + flag ||= "--frozen flag" if options[:frozen] + flag ||= "deployment setting" + raise ProductionError, "The #{flag} requires a lockfile. Please make " \ + "sure you have checked your #{SharedHelpers.relative_lockfile_path} into version control " \ + "before deploying." + end + + options[:local] = true if Bundler.app_cache.exist? + + Bundler.settings.set_command_option :deployment, true if options[:deployment] + Bundler.settings.set_command_option :frozen, true if options[:frozen] + end + + # When install is called with --no-deployment, disable deployment mode + if options[:deployment] == false + Bundler.settings.set_command_option :frozen, nil + options[:system] = true + end + + normalize_settings + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + if options["binstubs"] + Bundler::SharedHelpers.major_deprecation 2, + "The --binstubs option will be removed in favor of `bundle binstubs --all`", + removed_message: "The --binstubs option have been removed in favor of `bundle binstubs --all`" + end + + Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? + + definition = Bundler.definition + definition.validate_runtime! + + installer = Installer.install(Bundler.root, definition, options) + + Bundler.settings.temporary(cache_all_platforms: options[:local] ? false : Bundler.settings[:cache_all_platforms]) do + Bundler.load.cache(nil, options[:local]) if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? + end + + Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." + Bundler::CLI::Common.output_without_groups_message(:install) + + if Bundler.use_system_gems? + Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." + else + relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd + Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" + end + + Bundler::CLI::Common.output_post_install_messages installer.post_install_messages + + warn_ambiguous_gems + + if CLI::Common.clean_after_install? + require_relative "clean" + Bundler::CLI::Clean.new(options).run + end + + Bundler::CLI::Common.output_fund_metadata_summary + rescue Gem::InvalidSpecificationException + Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." + raise + end + + private + + def warn_if_root + return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? + Bundler.ui.warn "Don't run Bundler as root. Installing your bundle as root " \ + "will break this application for all non-root users on this machine.", wrap: true + end + + def dependencies_count_for(definition) + count = definition.dependencies.count + "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" + end + + def gems_installed_for(definition) + count = definition.specs.count + "#{count} #{count == 1 ? "gem" : "gems"} now installed" + end + + def check_for_group_conflicts_in_cli_options + conflicting_groups = Array(options[:without]) & Array(options[:with]) + return if conflicting_groups.empty? + raise InvalidOption, "You can't list a group in both with and without." \ + " The offending groups are: #{conflicting_groups.join(", ")}." + end + + def check_for_options_conflicts + if (options[:path] || options[:deployment]) && options[:system] + error_message = String.new + error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] + error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] + raise InvalidOption.new(error_message) + end + end + + def check_trust_policy + trust_policy = options["trust-policy"] + unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) + raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ + "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." + end + Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy + end + + def normalize_groups + check_for_group_conflicts_in_cli_options + + # need to nil them out first to get around validation for backwards compatibility + Bundler.settings.set_command_option :without, nil + Bundler.settings.set_command_option :with, nil + Bundler.settings.set_command_option :without, options[:without] + Bundler.settings.set_command_option :with, options[:with] + end + + def normalize_settings + Bundler.settings.set_command_option :path, nil if options[:system] + Bundler.settings.set_command_option_if_given :path, options[:path] + + if options["standalone"] && Bundler.settings[:path].nil? && !options["local"] + Bundler.settings.temporary(path_relative_to_cwd: false) do + Bundler.settings.set_command_option :path, "bundle" + end + end + + bin_option = options["binstubs"] + bin_option = nil if bin_option&.empty? + Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] + + Bundler.settings.set_command_option_if_given :shebang, options["shebang"] + + Bundler.settings.set_command_option_if_given :jobs, options["jobs"] + + Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] + + Bundler.settings.set_command_option_if_given :no_install, options["no-install"] + + Bundler.settings.set_command_option_if_given :clean, options["clean"] + + normalize_groups if options[:without] || options[:with] + + options[:force] = options[:redownload] + end + + def warn_ambiguous_gems + # TODO: remove this when we drop Bundler 1.x support + Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| + Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." + Bundler.ui.warn "Installed from: #{installed_from_uri}" + Bundler.ui.warn "Also found in:" + also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } + Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." + Bundler.ui.warn "For example:" + Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" + Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/issue.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/issue.rb new file mode 100644 index 00000000..5f2924c4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/issue.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "rbconfig" + +module Bundler + class CLI::Issue + def run + Bundler.ui.info <<~EOS + Did you find an issue with Bundler? Before filing a new issue, + be sure to check out these resources: + + 1. Check out our troubleshooting guide for quick fixes to common issues: + https://github.com/rubygems/rubygems/blob/master/bundler/doc/TROUBLESHOOTING.md + + 2. Instructions for common Bundler uses can be found on the documentation + site: https://bundler.io/ + + 3. Information about each Bundler command can be found in the Bundler + man pages: https://bundler.io/man/bundle.1.html + + Hopefully the troubleshooting steps above resolved your problem! If things + still aren't working the way you expect them to, please let us know so + that we can diagnose and help fix the problem you're having, by filling + in the new issue form located at + https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md, + and copy and pasting the information below. + + EOS + + Bundler.ui.info Bundler::Env.report + + Bundler.ui.info "\n## Bundle Doctor" + doctor + end + + def doctor + require_relative "doctor" + Bundler::CLI::Doctor.new({}).run + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/list.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/list.rb new file mode 100644 index 00000000..f56bf5b8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/list.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Bundler + class CLI::List + def initialize(options) + @options = options + @without_group = options["without-group"].map(&:to_sym) + @only_group = options["only-group"].map(&:to_sym) + end + + def run + raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @only_group.any? && @without_group.any? + + raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] + + specs = if @only_group.any? || @without_group.any? + filtered_specs_by_groups + else + begin + Bundler.load.specs + rescue GemNotFound => e + Bundler.ui.error e.message + Bundler.ui.warn "Install missing gems with `bundle install`." + exit 1 + end + end.reject {|s| s.name == "bundler" }.sort_by(&:name) + + return Bundler.ui.info "No gems in the Gemfile" if specs.empty? + + return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] + return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] + + Bundler.ui.info "Gems included by the bundle:" + + specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } + + Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" + end + + private + + def verify_group_exists(groups) + (@without_group + @only_group).each do |group| + raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) + end + end + + def filtered_specs_by_groups + definition = Bundler.definition + groups = definition.groups + + verify_group_exists(groups) + + show_groups = + if @without_group.any? + groups.reject {|g| @without_group.include?(g) } + elsif @only_group.any? + groups.select {|g| @only_group.include?(g) } + else + groups + end.map(&:to_sym) + + definition.specs_for(show_groups) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/lock.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/lock.rb new file mode 100644 index 00000000..dac3d2a0 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/lock.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Lock + attr_reader :options + + def initialize(options) + @options = options + end + + def run + unless Bundler.default_gemfile + Bundler.ui.error "Unable to find a Gemfile to lock" + exit 1 + end + + print = options[:print] + previous_ui_level = Bundler.ui.level + Bundler.ui.level = "silent" if print + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + update = options[:update] + conservative = options[:conservative] + bundler = options[:bundler] + + if update.is_a?(Array) # unlocking specific gems + Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) + update = { gems: update, conservative: conservative } + elsif update && conservative + update = { conservative: conservative } + elsif update && bundler + update = { bundler: bundler } + end + + file = options[:lockfile] + file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile + + Bundler.settings.temporary(frozen: false) do + definition = Bundler.definition(update, file) + + Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update] + + options["remove-platform"].each do |platform| + definition.remove_platform(platform) + end + + options["add-platform"].each do |platform_string| + platform = Gem::Platform.new(platform_string) + if platform.to_s == "unknown" + Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ + "and adding it will likely lead to resolution errors" + end + definition.add_platform(platform) + end + + if definition.platforms.empty? + raise InvalidOption, "Removing all platforms from the bundle is not allowed" + end + + definition.resolve_remotely! unless options[:local] + + if print + puts definition.to_lock + else + puts "Writing lockfile to #{file}" + definition.lock + end + end + + Bundler.ui.level = previous_ui_level + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/open.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/open.rb new file mode 100644 index 00000000..f24693b8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/open.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Open + attr_reader :options, :name, :path + def initialize(options, name) + @options = options + @name = name + @path = options[:path] unless options[:path].nil? + end + + def run + raise InvalidOption, "Cannot specify `--path` option without a value" if !@path.nil? && @path.empty? + editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } + return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor + return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) + if spec.default_gem? + Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist." + else + root_path = spec.full_gem_path + require "shellwords" + command = Shellwords.split(editor) << File.join([root_path, path].compact) + Bundler.with_original_env do + system(*command, { chdir: root_path }) + end || Bundler.ui.info("Could not run '#{command.join(" ")}'") + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/outdated.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/outdated.rb new file mode 100644 index 00000000..ec42e631 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/outdated.rb @@ -0,0 +1,297 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Outdated + attr_reader :options, :gems, :options_include_groups, :filter_options_patch, :sources, :strict + attr_accessor :outdated_gems + + def initialize(options, gems) + @options = options + @gems = gems + @sources = Array(options[:source]) + + @filter_options_patch = options.keys & %w[filter-major filter-minor filter-patch] + + @outdated_gems = [] + + @options_include_groups = [:group, :groups].any? do |v| + options.keys.include?(v.to_s) + end + + # the patch level options imply strict is also true. It wouldn't make + # sense otherwise. + @strict = options["filter-strict"] || Bundler::CLI::Common.patch_level_options(options).any? + end + + def run + check_for_deployment_mode! + + gems.each do |gem_name| + Bundler::CLI::Common.select_spec(gem_name) + end + + Bundler.definition.validate_runtime! + current_specs = Bundler.ui.silence { Bundler.definition.resolve } + + current_dependencies = Bundler.ui.silence do + Bundler.load.dependencies.map {|dep| [dep.name, dep] }.to_h + end + + definition = if gems.empty? && sources.empty? + # We're doing a full update + Bundler.definition(true) + else + Bundler.definition(gems: gems, sources: sources) + end + + Bundler::CLI::Common.configure_gem_version_promoter( + Bundler.definition, + options.merge(strict: @strict) + ) + + definition_resolution = proc do + options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! + end + + if options[:parseable] + Bundler.ui.silence(&definition_resolution) + else + definition_resolution.call + end + + Bundler.ui.info "" + + # Loop through the current specs + gemfile_specs, dependency_specs = current_specs.partition do |spec| + current_dependencies.key? spec.name + end + + specs = if options["only-explicit"] + gemfile_specs + else + gemfile_specs + dependency_specs + end + + specs.sort_by(&:name).uniq(&:name).each do |current_spec| + next unless gems.empty? || gems.include?(current_spec.name) + + active_spec = retrieve_active_spec(definition, current_spec) + next unless active_spec + + next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) + + gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) + next unless gem_outdated || (current_spec.git_version != active_spec.git_version) + + dependency = current_dependencies[current_spec.name] + groups = "" + if dependency && !options[:parseable] + groups = dependency.groups.join(", ") + end + + outdated_gems << { + active_spec: active_spec, + current_spec: current_spec, + dependency: dependency, + groups: groups, + } + end + + if outdated_gems.empty? + unless options[:parseable] + Bundler.ui.info(nothing_outdated_message) + end + else + if options_include_groups + relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| + contains_group = groups.split(", ").include?(options[:group]) + next unless options[:groups] || contains_group + + gems + end.compact + + if options[:parseable] + print_gems(relevant_outdated_gems) + else + print_gems_table(relevant_outdated_gems) + end + elsif options[:parseable] + print_gems(outdated_gems) + else + print_gems_table(outdated_gems) + end + + exit 1 + end + end + + private + + def loaded_from_for(spec) + return unless spec.respond_to?(:loaded_from) + + spec.loaded_from + end + + def groups_text(group_text, groups) + "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" + end + + def nothing_outdated_message + if filter_options_patch.any? + display = filter_options_patch.map do |o| + o.sub("filter-", "") + end.join(" or ") + + "No #{display} updates to display.\n" + else + "Bundle up to date!\n" + end + end + + def retrieve_active_spec(definition, current_spec) + active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) + return unless active_spec + + return active_spec if strict + + active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) + if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 + active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } + end + active_specs.last + end + + def print_gems(gems_list) + gems_list.each do |gem| + print_gem( + gem[:current_spec], + gem[:active_spec], + gem[:dependency], + gem[:groups], + ) + end + end + + def print_gems_table(gems_list) + data = gems_list.map do |gem| + gem_column_for( + gem[:current_spec], + gem[:active_spec], + gem[:dependency], + gem[:groups], + ) + end + + print_indented([table_header] + data) + end + + def print_gem(current_spec, active_spec, dependency, groups) + spec_version = "#{active_spec.version}#{active_spec.git_version}" + if Bundler.ui.debug? + loaded_from = loaded_from_for(active_spec) + spec_version += " (from #{loaded_from})" if loaded_from + end + current_version = "#{current_spec.version}#{current_spec.git_version}" + + if dependency&.specific? + dependency_version = %(, requested #{dependency.requirement}) + end + + spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ + "installed #{current_version}#{dependency_version})" + + output_message = if options[:parseable] + spec_outdated_info.to_s + elsif options_include_groups || groups.empty? + " * #{spec_outdated_info}" + else + " * #{spec_outdated_info} in #{groups_text("group", groups)}" + end + + Bundler.ui.info output_message.rstrip + end + + def gem_column_for(current_spec, active_spec, dependency, groups) + current_version = "#{current_spec.version}#{current_spec.git_version}" + spec_version = "#{active_spec.version}#{active_spec.git_version}" + dependency = dependency.requirement if dependency + + ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] + ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug? + ret_val + end + + def check_for_deployment_mode! + return unless Bundler.frozen_bundle? + suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? + "bundle config unset frozen" + elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? + "bundle config unset deployment" + end + raise ProductionError, "You are trying to check outdated gems in " \ + "deployment mode. Run `bundle outdated` elsewhere.\n" \ + "\nIf this is a development machine, remove the " \ + "#{Bundler.default_gemfile} freeze" \ + "\nby running `#{suggested_command}`." + end + + def update_present_via_semver_portions(current_spec, active_spec, options) + current_major = current_spec.version.segments.first + active_major = active_spec.version.segments.first + + update_present = false + update_present = active_major > current_major if options["filter-major"] + + if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major + current_minor = get_version_semver_portion_value(current_spec, 1) + active_minor = get_version_semver_portion_value(active_spec, 1) + + update_present = active_minor > current_minor if options["filter-minor"] + + if !update_present && options["filter-patch"] && current_minor == active_minor + current_patch = get_version_semver_portion_value(current_spec, 2) + active_patch = get_version_semver_portion_value(active_spec, 2) + + update_present = active_patch > current_patch + end + end + + update_present + end + + def get_version_semver_portion_value(spec, version_portion_index) + version_section = spec.version.segments[version_portion_index, 1] + version_section.to_a[0].to_i + end + + def print_indented(matrix) + header = matrix[0] + data = matrix[1..-1] + + column_sizes = Array.new(header.size) do |index| + matrix.max_by {|row| row[index].length }[index].length + end + + Bundler.ui.info justify(header, column_sizes) + + data.sort_by! {|row| row[0] } + + data.each do |row| + Bundler.ui.info justify(row, column_sizes) + end + end + + def table_header + header = ["Gem", "Current", "Latest", "Requested", "Groups"] + header << "Path" if Bundler.ui.debug? + header + end + + def justify(row, sizes) + row.each_with_index.map do |element, index| + element.ljust(sizes[index]) + end.join(" ").strip + "\n" + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/platform.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/platform.rb new file mode 100644 index 00000000..32d68abb --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/platform.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Platform + attr_reader :options + def initialize(options) + @options = options + end + + def run + ruby_version = if Bundler.locked_gems + Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "") + else + Bundler.definition.ruby_version&.single_version_string + end + + output = [] + + if options[:ruby] + if ruby_version + output << ruby_version + else + output << "No ruby version specified" + end + else + platforms = Bundler.definition.platforms.map {|p| "* #{p}" } + + output << "Your platform is: #{Gem::Platform.local}" + output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" + + if ruby_version + output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" + + begin + Bundler.definition.validate_runtime! + output << "Your current platform satisfies the Ruby version requirement." + rescue RubyVersionMismatch => e + output << e.message + end + else + output << "Your Gemfile does not specify a Ruby version requirement." + end + end + + Bundler.ui.info output.join("\n\n") + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/plugin.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/plugin.rb new file mode 100644 index 00000000..fd61ef0d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/plugin.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require_relative "../vendored_thor" +module Bundler + class CLI::Plugin < Thor + desc "install PLUGINS", "Install the plugin from the source" + long_desc <<-D + Install plugins either from the rubygems source provided (with --source option), from a git source provided with --git, or a local path provided with --path. If no sources are provided, it uses Gem.sources + D + method_option "source", type: :string, default: nil, banner: "URL of the RubyGems source to fetch the plugin from" + method_option "version", type: :string, default: nil, banner: "The version of the plugin to fetch" + method_option "git", type: :string, default: nil, banner: "URL of the git repo to fetch from" + method_option "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (deprecated)" + method_option "branch", type: :string, default: nil, banner: "The git branch to checkout" + method_option "ref", type: :string, default: nil, banner: "The git revision to check out" + method_option "path", type: :string, default: nil, banner: "Path of a local gem to directly use" + def install(*plugins) + Bundler::Plugin.install(plugins, options) + end + + desc "uninstall PLUGINS", "Uninstall the plugins" + long_desc <<-D + Uninstall given list of plugins. To uninstall all the plugins, use -all option. + D + method_option "all", type: :boolean, default: nil, banner: "Uninstall all the installed plugins. If no plugin is installed, then it does nothing." + def uninstall(*plugins) + Bundler::Plugin.uninstall(plugins, options) + end + + desc "list", "List the installed plugins and available commands" + def list + Bundler::Plugin.list + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/pristine.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/pristine.rb new file mode 100644 index 00000000..e0d7452c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/pristine.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Pristine + def initialize(gems) + @gems = gems + end + + def run + CLI::Common.ensure_all_gems_in_lockfile!(@gems) + definition = Bundler.definition + definition.validate_runtime! + installer = Bundler::Installer.new(Bundler.root, definition) + + ProcessLock.lock do + installed_specs = definition.specs.reject do |spec| + next if spec.name == "bundler" # Source::Rubygems doesn't install bundler + next if !@gems.empty? && !@gems.include?(spec.name) + + gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" + gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY + + case source = spec.source + when Source::Rubygems + cached_gem = spec.cache_file + unless File.exist?(cached_gem) + Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") + next + end + + FileUtils.rm_rf spec.full_gem_path + when Source::Git + if source.local? + Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.") + next + end + + source.remote! + if extension_cache_path = source.extension_cache_path(spec) + FileUtils.rm_rf extension_cache_path + end + FileUtils.rm_rf spec.extension_dir + FileUtils.rm_rf spec.full_gem_path + else + Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") + next + end + + true + end.map(&:name) + + jobs = installer.send(:installation_parallelization, {}) + pristine_count = definition.specs.count - installed_specs.count + # allow a pristining a single gem to skip the parallel worker + jobs = [jobs, pristine_count].min + ParallelInstaller.call(installer, definition.specs, jobs, false, true, skip: installed_specs) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/remove.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/remove.rb new file mode 100644 index 00000000..44a4d891 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/remove.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Remove + def initialize(gems, options) + @gems = gems + @options = options + end + + def run + raise InvalidOption, "Please specify gems to remove." if @gems.empty? + + Injector.remove(@gems, {}) + Installer.install(Bundler.root, Bundler.definition) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/show.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/show.rb new file mode 100644 index 00000000..59b0af42 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/show.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Show + attr_reader :options, :gem_name, :latest_specs + def initialize(options, gem_name) + @options = options + @gem_name = gem_name + @verbose = options[:verbose] || options[:outdated] + @latest_specs = fetch_latest_specs if @verbose + end + + def run + Bundler.ui.silence do + Bundler.definition.validate_runtime! + Bundler.load.lock + end + + if gem_name + if gem_name == "bundler" + path = File.expand_path("../../..", __dir__) + else + spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) + return unless spec + path = spec.full_gem_path + unless File.directory?(path) + return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" + end + end + return Bundler.ui.info(path) + end + + if options[:paths] + Bundler.load.specs.sort_by(&:name).map do |s| + Bundler.ui.info s.full_gem_path + end + else + Bundler.ui.info "Gems included by the bundle:" + Bundler.load.specs.sort_by(&:name).each do |s| + desc = " * #{s.name} (#{s.version}#{s.git_version})" + if @verbose + latest = latest_specs.find {|l| l.name == s.name } + Bundler.ui.info <<~END + #{desc.lstrip} + \tSummary: #{s.summary || "No description available."} + \tHomepage: #{s.homepage || "No website available."} + \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} + END + else + Bundler.ui.info desc + end + end + end + end + + private + + def fetch_latest_specs + definition = Bundler.definition(true) + if options[:outdated] + Bundler.ui.info "Fetching remote specs for outdated check...\n\n" + Bundler.ui.silence { definition.resolve_remotely! } + else + definition.resolve_with_cache! + end + Bundler.reset! + definition.specs + end + + def outdated?(current, latest) + return false unless latest + Gem::Version.new(current.version) < Gem::Version.new(latest.version) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/update.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/update.rb new file mode 100644 index 00000000..985e8db0 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/update.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Update + attr_reader :options, :gems + def initialize(options, gems) + @options = options + @gems = gems + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + + update_bundler = options[:bundler] + + Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler + + Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? + + sources = Array(options[:source]) + groups = Array(options[:group]).map(&:to_sym) + + full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler + + if full_update && !options[:all] + if Bundler.feature_flag.update_requires_all_flag? + raise InvalidOption, "To update everything, pass the `--all` flag." + end + SharedHelpers.major_deprecation 3, "Pass --all to `bundle update` to update everything" + elsif !full_update && options[:all] + raise InvalidOption, "Cannot specify --all along with specific options." + end + + conservative = options[:conservative] + + if full_update + if conservative + Bundler.definition(conservative: conservative) + else + Bundler.definition(true) + end + else + unless Bundler.default_lockfile.exist? + raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ + "Run `bundle install` to update and install the bundled gems." + end + Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) + + if groups.any? + deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } + gems.concat(deps.map(&:name)) + end + + Bundler.definition(gems: gems, sources: sources, ruby: options[:ruby], + conservative: conservative, + bundler: update_bundler) + end + + Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + opts = options.dup + opts["update"] = true + opts["local"] = options[:local] + opts["force"] = options[:redownload] + + Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] + + Bundler.definition.validate_runtime! + + if locked_gems = Bundler.definition.locked_gems + previous_locked_info = locked_gems.specs.reduce({}) do |h, s| + h[s.name] = { spec: s, version: s.version, source: s.source.identifier } + h + end + end + + installer = Installer.install Bundler.root, Bundler.definition, opts + Bundler.load.cache if Bundler.app_cache.exist? + + if CLI::Common.clean_after_install? + require_relative "clean" + Bundler::CLI::Clean.new(options).run + end + + if locked_gems + gems.each do |name| + locked_info = previous_locked_info[name] + next unless locked_info + + locked_spec = locked_info[:spec] + new_spec = Bundler.definition.specs[name].first + unless new_spec + unless locked_spec.match_platform(Bundler.local_platform) + Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one" + end + + next + end + + locked_source = locked_info[:source] + new_source = new_spec.source.identifier + next if locked_source != new_source + + new_version = new_spec.version + locked_version = locked_info[:version] + if new_version < locked_version + Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" + elsif new_version == locked_version + Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" + end + end + end + + Bundler.ui.confirm "Bundle updated!" + Bundler::CLI::Common.output_without_groups_message(:update) + Bundler::CLI::Common.output_post_install_messages installer.post_install_messages + + Bundler::CLI::Common.output_fund_metadata_summary + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/cli/viz.rb b/bin/gems/bundler-2.5.9/lib/bundler/cli/viz.rb new file mode 100644 index 00000000..5c09e009 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/cli/viz.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Viz + attr_reader :options, :gem_name + def initialize(options) + @options = options + end + + def run + # make sure we get the right `graphviz`. There is also a `graphviz` + # gem we're not built to support + gem "ruby-graphviz" + require "graphviz" + + options[:without] = options[:without].join(":").tr(" ", ":").split(":") + output_file = File.expand_path(options[:file]) + + graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) + graph.viz + rescue LoadError => e + Bundler.ui.error e.inspect + Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" + Bundler.ui.warn "`gem install ruby-graphviz`" + rescue StandardError => e + raise unless e.message.to_s.include?("GraphViz not installed or dot not in PATH") + Bundler.ui.error e.message + Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client.rb b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client.rb new file mode 100644 index 00000000..68e0d7e0 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require "pathname" +require "set" + +module Bundler + class CompactIndexClient + # NOTE: MD5 is here not because we expect a server to respond with it, but + # because we use it to generate the etag on first request during the upgrade + # to the compact index client that uses opaque etags saved to files. + # Remove once 2.5.0 has been out for a while. + SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze + DEBUG_MUTEX = Thread::Mutex.new + + def self.debug + return unless ENV["DEBUG_COMPACT_INDEX"] + DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } + end + + class Error < StandardError; end + + require_relative "compact_index_client/cache" + require_relative "compact_index_client/cache_file" + require_relative "compact_index_client/updater" + + attr_reader :directory + + def initialize(directory, fetcher) + @directory = Pathname.new(directory) + @updater = Updater.new(fetcher) + @cache = Cache.new(@directory) + @endpoints = Set.new + @info_checksums_by_name = {} + @parsed_checksums = false + @mutex = Thread::Mutex.new + end + + def execution_mode=(block) + Bundler::CompactIndexClient.debug { "execution_mode=" } + @endpoints = Set.new + + @execution_mode = block + end + + # @return [Lambda] A lambda that takes an array of inputs and a block, and + # maps the inputs with the block in parallel. + # + def execution_mode + @execution_mode || sequentially + end + + def sequential_execution_mode! + self.execution_mode = sequentially + end + + def sequentially + @sequentially ||= lambda do |inputs, &blk| + inputs.map(&blk) + end + end + + def names + Bundler::CompactIndexClient.debug { "/names" } + update("names", @cache.names_path, @cache.names_etag_path) + @cache.names + end + + def versions + Bundler::CompactIndexClient.debug { "/versions" } + update("versions", @cache.versions_path, @cache.versions_etag_path) + versions, @info_checksums_by_name = @cache.versions + versions + end + + def dependencies(names) + Bundler::CompactIndexClient.debug { "dependencies(#{names})" } + execution_mode.call(names) do |name| + update_info(name) + @cache.dependencies(name).map {|d| d.unshift(name) } + end.flatten(1) + end + + def update_and_parse_checksums! + Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } + return @info_checksums_by_name if @parsed_checksums + update("versions", @cache.versions_path, @cache.versions_etag_path) + @info_checksums_by_name = @cache.checksums + @parsed_checksums = true + end + + private + + def update(remote_path, local_path, local_etag_path) + Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } + unless synchronize { @endpoints.add?(remote_path) } + Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } + return + end + @updater.update(url(remote_path), local_path, local_etag_path) + end + + def update_info(name) + Bundler::CompactIndexClient.debug { "update_info(#{name})" } + path = @cache.info_path(name) + unless existing = @info_checksums_by_name[name] + Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } + return + end + checksum = SharedHelpers.checksum_for_file(path, :MD5) + if checksum == existing + Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } + return + end + Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } + update("info/#{name}", path, @cache.info_etag_path(name)) + end + + def url(path) + path + end + + def synchronize + @mutex.synchronize { yield } + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache.rb b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache.rb new file mode 100644 index 00000000..55911fde --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require_relative "gem_parser" + +module Bundler + class CompactIndexClient + class Cache + attr_reader :directory + + def initialize(directory) + @directory = Pathname.new(directory).expand_path + info_roots.each {|dir| mkdir(dir) } + mkdir(info_etag_root) + end + + def names + lines(names_path) + end + + def names_path + directory.join("names") + end + + def names_etag_path + directory.join("names.etag") + end + + def versions + versions_by_name = Hash.new {|hash, key| hash[key] = [] } + info_checksums_by_name = {} + + lines(versions_path).each do |line| + name, versions_string, info_checksum = line.split(" ", 3) + info_checksums_by_name[name] = info_checksum || "" + versions_string.split(",") do |version| + delete = version.delete_prefix!("-") + version = version.split("-", 2).unshift(name) + if delete + versions_by_name[name].delete(version) + else + versions_by_name[name] << version + end + end + end + + [versions_by_name, info_checksums_by_name] + end + + def versions_path + directory.join("versions") + end + + def versions_etag_path + directory.join("versions.etag") + end + + def checksums + checksums = {} + + lines(versions_path).each do |line| + name, _, checksum = line.split(" ", 3) + checksums[name] = checksum + end + + checksums + end + + def dependencies(name) + lines(info_path(name)).map do |line| + parse_gem(line) + end + end + + def info_path(name) + name = name.to_s + if /[^a-z0-9_-]/.match?(name) + name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" + info_roots.last.join(name) + else + info_roots.first.join(name) + end + end + + def info_etag_path(name) + name = name.to_s + info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}") + end + + private + + def mkdir(dir) + SharedHelpers.filesystem_access(dir) do + FileUtils.mkdir_p(dir) + end + end + + def lines(path) + return [] unless path.file? + lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") + header = lines.index("---") + header ? lines[header + 1..-1] : lines + end + + def parse_gem(line) + @dependency_parser ||= GemParser.new + @dependency_parser.parse(line) + end + + def info_roots + [ + directory.join("info"), + directory.join("info-special-characters"), + ] + end + + def info_etag_root + directory.join("info-etags") + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache_file.rb b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache_file.rb new file mode 100644 index 00000000..5988bc91 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/cache_file.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +require_relative "../vendored_fileutils" +require "rubygems/package" + +module Bundler + class CompactIndexClient + # write cache files in a way that is robust to concurrent modifications + # if digests are given, the checksums will be verified + class CacheFile + DEFAULT_FILE_MODE = 0o644 + private_constant :DEFAULT_FILE_MODE + + class Error < RuntimeError; end + class ClosedError < Error; end + + class DigestMismatchError < Error + def initialize(digests, expected_digests) + super "Calculated checksums #{digests.inspect} did not match expected #{expected_digests.inspect}." + end + end + + # Initialize with a copy of the original file, then yield the instance. + def self.copy(path, &block) + new(path) do |file| + file.initialize_digests + + SharedHelpers.filesystem_access(path, :read) do + path.open("rb") do |s| + file.open {|f| IO.copy_stream(s, f) } + end + end + + yield file + end + end + + # Write data to a temp file, then replace the original file with it verifying the digests if given. + def self.write(path, data, digests = nil) + return unless data + new(path) do |file| + file.digests = digests + file.write(data) + end + end + + attr_reader :original_path, :path + + def initialize(original_path, &block) + @original_path = original_path + @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE + @path = original_path.sub(/$/, ".#{$$}.tmp") + return unless block_given? + begin + yield self + ensure + close + end + end + + def size + path.size + end + + # initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys. + def initialize_digests(keys = nil) + @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup + @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new } + end + + # reset the digests so they don't contain any previously read data + def reset_digests + @digests&.each_value(&:reset) + end + + # set the digests that will be verified at the end + def digests=(expected_digests) + @expected_digests = expected_digests + + if @expected_digests.nil? + @digests = nil + elsif @digests + @digests = @digests.slice(*@expected_digests.keys) + else + initialize_digests(@expected_digests.keys) + end + end + + # remove this method when we stop generating md5 digests for legacy etags + def md5 + @digests && @digests["md5"] + end + + def digests? + @digests&.any? + end + + # Open the temp file for writing, reusing original permissions, yielding the IO object. + def open(write_mode = "wb", perm = @perm, &block) + raise ClosedError, "Cannot reopen closed file" if @closed + SharedHelpers.filesystem_access(path, :write) do + path.open(write_mode, perm) do |f| + yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f + end + end + end + + # Returns false without appending when no digests since appending is too error prone to do without digests. + def append(data) + return false unless digests? + open("a") {|f| f.write data } + verify && commit + end + + def write(data) + reset_digests + open {|f| f.write data } + commit! + end + + def commit! + verify || raise(DigestMismatchError.new(@base64digests, @expected_digests)) + commit + end + + # Verify the digests, returning true on match, false on mismatch. + def verify + return true unless @expected_digests && digests? + @base64digests = @digests.transform_values!(&:base64digest) + @digests = nil + @base64digests.all? {|algo, digest| @expected_digests[algo] == digest } + end + + # Replace the original file with the temp file without verifying digests. + # The file is permanently closed. + def commit + raise ClosedError, "Cannot commit closed file" if @closed + SharedHelpers.filesystem_access(original_path, :write) do + FileUtils.mv(path, original_path) + end + @closed = true + end + + # Remove the temp file without replacing the original file. + # The file is permanently closed. + def close + return if @closed + FileUtils.remove_file(path) if @path&.file? + @closed = true + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/gem_parser.rb b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/gem_parser.rb new file mode 100644 index 00000000..60a18176 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/gem_parser.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Bundler + class CompactIndexClient + if defined?(Gem::Resolver::APISet::GemParser) + GemParser = Gem::Resolver::APISet::GemParser + else + class GemParser + EMPTY_ARRAY = [].freeze + private_constant :EMPTY_ARRAY + + def parse(line) + version_and_platform, rest = line.split(" ", 2) + version, platform = version_and_platform.split("-", 2) + dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest + dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY + requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY + [version, platform, dependencies, requirements] + end + + private + + def parse_dependency(string) + dependency = string.split(":") + dependency[-1] = dependency[-1].split("&") if dependency.size > 1 + dependency[0] = -dependency[0] + dependency + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/updater.rb b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/updater.rb new file mode 100644 index 00000000..36f6b81d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/compact_index_client/updater.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +module Bundler + class CompactIndexClient + class Updater + class MismatchedChecksumError < Error + def initialize(path, message) + super "The checksum of /#{path} does not match the checksum provided by the server! Something is wrong. #{message}" + end + end + + def initialize(fetcher) + @fetcher = fetcher + end + + def update(remote_path, local_path, etag_path) + append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path) + rescue CacheFile::DigestMismatchError => e + raise MismatchedChecksumError.new(remote_path, e.message) + rescue Zlib::GzipFile::Error + raise Bundler::HTTPError + end + + private + + def append(remote_path, local_path, etag_path) + return false unless local_path.file? && local_path.size.nonzero? + + CacheFile.copy(local_path) do |file| + etag = etag_path.read.tap(&:chomp!) if etag_path.file? + etag ||= generate_etag(etag_path, file) # Remove this after 2.5.0 has been out for a while. + + # Subtract a byte to ensure the range won't be empty. + # Avoids 416 (Range Not Satisfiable) responses. + response = @fetcher.call(remote_path, request_headers(etag, file.size - 1)) + break true if response.is_a?(Gem::Net::HTTPNotModified) + + file.digests = parse_digests(response) + # server may ignore Range and return the full response + if response.is_a?(Gem::Net::HTTPPartialContent) + break false unless file.append(response.body.byteslice(1..-1)) + else + file.write(response.body) + end + CacheFile.write(etag_path, etag_from_response(response)) + true + end + end + + # request without range header to get the full file or a 304 Not Modified + def replace(remote_path, local_path, etag_path) + etag = etag_path.read.tap(&:chomp!) if etag_path.file? + response = @fetcher.call(remote_path, request_headers(etag)) + return true if response.is_a?(Gem::Net::HTTPNotModified) + CacheFile.write(local_path, response.body, parse_digests(response)) + CacheFile.write(etag_path, etag_from_response(response)) + end + + def request_headers(etag, range_start = nil) + headers = {} + headers["Range"] = "bytes=#{range_start}-" if range_start + headers["If-None-Match"] = %("#{etag}") if etag + headers + end + + def etag_for_request(etag_path) + etag_path.read.tap(&:chomp!) if etag_path.file? + end + + # When first releasing this opaque etag feature, we want to generate the old MD5 etag + # based on the content of the file. After that it will always use the saved opaque etag. + # This transparently saves existing users with good caches from updating a bunch of files. + # Remove this behavior after 2.5.0 has been out for a while. + def generate_etag(etag_path, file) + etag = file.md5.hexdigest + CacheFile.write(etag_path, etag) + etag + end + + def etag_from_response(response) + return unless response["ETag"] + etag = response["ETag"].delete_prefix("W/") + return if etag.delete_prefix!('"') && !etag.delete_suffix!('"') + etag + end + + # Unwraps and returns a Hash of digest algorithms and base64 values + # according to RFC 8941 Structured Field Values for HTTP. + # https://www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence + # Ignores unsupported algorithms. + def parse_digests(response) + return unless header = response["Repr-Digest"] || response["Digest"] + digests = {} + header.split(",") do |param| + algorithm, value = param.split("=", 2) + algorithm.strip! + algorithm.downcase! + next unless SUPPORTED_DIGESTS.key?(algorithm) + next unless value = byte_sequence(value) + digests[algorithm] = value + end + digests.empty? ? nil : digests + end + + # Unwrap surrounding colons (byte sequence) + # The wrapping characters must be matched or we return nil. + # Also handles quotes because right now rubygems.org sends them. + def byte_sequence(value) + return if value.delete_prefix!(":") && !value.delete_suffix!(":") + return if value.delete_prefix!('"') && !value.delete_suffix!('"') + value + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/constants.rb b/bin/gems/bundler-2.5.9/lib/bundler/constants.rb new file mode 100644 index 00000000..de9698b5 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/constants.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Bundler + WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ + FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd") + NULL = File::NULL +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/current_ruby.rb b/bin/gems/bundler-2.5.9/lib/bundler/current_ruby.rb new file mode 100644 index 00000000..93e0c401 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/current_ruby.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module Bundler + # Returns current version of Ruby + # + # @return [CurrentRuby] Current version of Ruby + def self.current_ruby + @current_ruby ||= CurrentRuby.new + end + + class CurrentRuby + KNOWN_MINOR_VERSIONS = %w[ + 1.8 + 1.9 + 2.0 + 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 3.0 + 3.1 + 3.2 + 3.3 + ].freeze + + KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze + + KNOWN_PLATFORMS = %w[ + jruby + maglev + mingw + mri + mswin + mswin64 + rbx + ruby + truffleruby + windows + x64_mingw + ].freeze + + def ruby? + return true if Bundler::GemHelpers.generic_local_platform_is_ruby? + + !windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby") + end + + def mri? + !windows? && RUBY_ENGINE == "ruby" + end + + def rbx? + ruby? && RUBY_ENGINE == "rbx" + end + + def jruby? + RUBY_ENGINE == "jruby" + end + + def maglev? + RUBY_ENGINE == "maglev" + end + + def truffleruby? + RUBY_ENGINE == "truffleruby" + end + + def windows? + Gem.win_platform? + end + alias_method :mswin?, :windows? + alias_method :mswin64?, :windows? + alias_method :mingw?, :windows? + alias_method :x64_mingw?, :windows? + + (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| + trimmed_version = version.tr(".", "") + define_method(:"on_#{trimmed_version}?") do + RUBY_VERSION.start_with?("#{version}.") + end + + KNOWN_PLATFORMS.each do |platform| + define_method(:"#{platform}_#{trimmed_version}?") do + send(:"#{platform}?") && send(:"on_#{trimmed_version}?") + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/definition.rb b/bin/gems/bundler-2.5.9/lib/bundler/definition.rb new file mode 100644 index 00000000..c8faf77b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/definition.rb @@ -0,0 +1,1041 @@ +# frozen_string_literal: true + +require_relative "lockfile_parser" + +module Bundler + class Definition + include GemHelpers + + class << self + # Do not create or modify a lockfile (Makes #lock a noop) + attr_accessor :no_lock + end + + attr_reader( + :dependencies, + :locked_deps, + :locked_gems, + :platforms, + :ruby_version, + :lockfile, + :gemfiles, + :locked_checksums + ) + + # Given a gemfile and lockfile creates a Bundler definition + # + # @param gemfile [Pathname] Path to Gemfile + # @param lockfile [Pathname,nil] Path to Gemfile.lock + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @return [Bundler::Definition] + def self.build(gemfile, lockfile, unlock) + unlock ||= {} + gemfile = Pathname.new(gemfile).expand_path + + raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? + + Dsl.evaluate(gemfile, lockfile, unlock) + end + + # + # How does the new system work? + # + # * Load information from Gemfile and Lockfile + # * Invalidate stale locked specs + # * All specs from stale source are stale + # * All specs that are reachable only through a stale + # dependency are stale. + # * If all fresh dependencies are satisfied by the locked + # specs, then we can try to resolve locally. + # + # @param lockfile [Pathname] Path to Gemfile.lock + # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile + # @param sources [Bundler::SourceList] + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version + # @param optional_groups [Array(String)] A list of optional groups + def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) + if [true, false].include?(unlock) + @unlocking_bundler = false + @unlocking = unlock + else + @unlocking_bundler = unlock.delete(:bundler) + @unlocking = unlock.any? {|_k, v| !Array(v).empty? } + end + + @dependencies = dependencies + @sources = sources + @unlock = unlock + @optional_groups = optional_groups + @remote = false + @prefer_local = false + @specs = nil + @ruby_version = ruby_version + @gemfiles = gemfiles + + @lockfile = lockfile + @lockfile_contents = String.new + + @locked_bundler_version = nil + @resolved_bundler_version = nil + + @locked_ruby_version = nil + @new_platform = nil + @removed_platform = nil + + if lockfile_exists? + @lockfile_contents = Bundler.read_file(lockfile) + @locked_gems = LockfileParser.new(@lockfile_contents) + @locked_platforms = @locked_gems.platforms + @platforms = @locked_platforms.dup + @locked_bundler_version = @locked_gems.bundler_version + @locked_ruby_version = @locked_gems.ruby_version + @originally_locked_specs = SpecSet.new(@locked_gems.specs) + @locked_checksums = @locked_gems.checksums + + if unlock != true + @locked_deps = @locked_gems.dependencies + @locked_specs = @originally_locked_specs + @locked_sources = @locked_gems.sources + else + @unlock = {} + @locked_deps = {} + @locked_specs = SpecSet.new([]) + @locked_sources = [] + end + else + @unlock = {} + @platforms = [] + @locked_gems = nil + @locked_deps = {} + @locked_specs = SpecSet.new([]) + @originally_locked_specs = @locked_specs + @locked_sources = [] + @locked_platforms = [] + @locked_checksums = nil + end + + locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } + @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? + + if @multisource_allowed + unless sources.aggregate_global_source? + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." + + Bundler::SharedHelpers.major_deprecation 2, msg + end + + @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) + end + + @unlock[:sources] ||= [] + @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object + @ruby_version.diff(locked_ruby_version_object) + end + @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) + + add_current_platform unless Bundler.frozen_bundle? + + converge_path_sources_to_gemspec_sources + @path_changes = converge_paths + @source_changes = converge_sources + + if @unlock[:conservative] + @unlock[:gems] ||= @dependencies.map(&:name) + else + eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") } + @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq + end + + @dependency_changes = converge_dependencies + @local_changes = converge_locals + + check_lockfile + end + + def gem_version_promoter + @gem_version_promoter ||= GemVersionPromoter.new + end + + def resolve_only_locally! + @remote = false + sources.local_only! + resolve + end + + def resolve_with_cache! + sources.cached! + resolve + end + + def resolve_remotely! + @remote = true + sources.remote! + resolve + end + + def resolution_mode=(options) + if options["local"] + @remote = false + else + @remote = true + @prefer_local = options["prefer-local"] + end + end + + def setup_sources_for_resolve + if @remote == false + sources.cached! + else + sources.remote! + end + end + + # For given dependency list returns a SpecSet with Gemspec of all the required + # dependencies. + # 1. The method first resolves the dependencies specified in Gemfile + # 2. After that it tries and fetches gemspec of resolved dependencies + # + # @return [Bundler::SpecSet] + def specs + @specs ||= materialize(requested_dependencies) + end + + def new_specs + specs - @locked_specs + end + + def removed_specs + @locked_specs - specs + end + + def missing_specs + resolve.materialize(requested_dependencies).missing_specs + end + + def missing_specs? + missing = missing_specs + return false if missing.empty? + Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" + true + rescue BundlerError => e + @resolve = nil + @resolver = nil + @resolution_packages = nil + @specs = nil + @gem_version_promoter = nil + + Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" + true + end + + def requested_specs + specs_for(requested_groups) + end + + def requested_dependencies + dependencies_for(requested_groups) + end + + def current_dependencies + filter_relevant(dependencies) + end + + def current_locked_dependencies + filter_relevant(locked_dependencies) + end + + def filter_relevant(dependencies) + platforms_array = [generic_local_platform].freeze + dependencies.select do |d| + d.should_include? && !d.gem_platforms(platforms_array).empty? + end + end + + def locked_dependencies + @locked_deps.values + end + + def new_deps + @new_deps ||= @dependencies - locked_dependencies + end + + def deleted_deps + @deleted_deps ||= locked_dependencies - @dependencies + end + + def specs_for(groups) + return specs if groups.empty? + deps = dependencies_for(groups) + materialize(deps) + end + + def dependencies_for(groups) + groups.map!(&:to_sym) + deps = current_dependencies # always returns a new array + deps.select! do |d| + if RUBY_VERSION >= "3.1" + d.groups.intersect?(groups) + else + !(d.groups & groups).empty? + end + end + deps + end + + # Resolve all the dependencies specified in Gemfile. It ensures that + # dependencies that have been already resolved via locked file and are fresh + # are reused when resolving dependencies + # + # @return [SpecSet] resolved dependencies + def resolve + @resolve ||= if Bundler.frozen_bundle? + Bundler.ui.debug "Frozen, using resolution from the lockfile" + @locked_specs + elsif no_resolve_needed? + if deleted_deps.any? + Bundler.ui.debug "Some dependencies were deleted, using a subset of the resolution from the lockfile" + SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) + else + Bundler.ui.debug "Found no changes, using resolution from the lockfile" + if @removed_platform || @locked_gems.may_include_redundant_platform_specific_gems? + SpecSet.new(filter_specs(@locked_specs, @dependencies)) + else + @locked_specs + end + end + else + Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}" + start_resolution + end + end + + def spec_git_paths + sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact + end + + def groups + dependencies.map(&:groups).flatten.uniq + end + + def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false) + if [true, false, nil].include?(file_or_preserve_unknown_sections) + target_lockfile = lockfile || Bundler.default_lockfile + preserve_unknown_sections = file_or_preserve_unknown_sections + else + target_lockfile = file_or_preserve_unknown_sections + preserve_unknown_sections = preserve_unknown_sections_or_unused + + suggestion = if target_lockfile == lockfile + "To fix this warning, remove it from the `Definition#lock` call." + else + "Instead, instantiate a new definition passing `#{target_lockfile}`, and call `lock` without a file argument on that definition" + end + + msg = "`Definition#lock` was passed a target file argument. #{suggestion}" + + Bundler::SharedHelpers.major_deprecation 2, msg + end + + write_lock(target_lockfile, preserve_unknown_sections) + end + + def locked_ruby_version + return unless ruby_version + if @unlock[:ruby] || !@locked_ruby_version + Bundler::RubyVersion.system + else + @locked_ruby_version + end + end + + def locked_ruby_version_object + return unless @locked_ruby_version + @locked_ruby_version_object ||= begin + unless version = RubyVersion.from_string(@locked_ruby_version) + raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ + "#{@lockfile} could not be parsed. " \ + "Try running bundle update --ruby to resolve this." + end + version + end + end + + def bundler_version_to_lock + @resolved_bundler_version || Bundler.gem_version + end + + def to_lock + require_relative "lockfile_generator" + LockfileGenerator.generate(self) + end + + def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) + added = [] + deleted = [] + changed = [] + + new_platforms = @platforms - @locked_platforms + deleted_platforms = @locked_platforms - @platforms + added.concat new_platforms.map {|p| "* platform: #{p}" } + deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } + + added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? + deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any? + + both_sources = Hash.new {|h, k| h[k] = [] } + current_dependencies.each {|d| both_sources[d.name][0] = d } + current_locked_dependencies.each {|d| both_sources[d.name][1] = d } + + both_sources.each do |name, (dep, lock_dep)| + next if dep.nil? || lock_dep.nil? + + gemfile_source = dep.source || default_source + lock_source = lock_dep.source || default_source + next if lock_source.include?(gemfile_source) + + gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source" + lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source" + changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`" + end + + reason = change_reason + msg = String.new + msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set" + msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? + msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? + msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? + msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n" + + unless explicit_flag + suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env) + "bundle config set frozen false" + end + msg << "If this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \ + "freeze by running `#{suggested_command}`." if suggested_command + end + + raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed? + end + + def validate_runtime! + validate_ruby! + validate_platforms! + end + + def validate_ruby! + return unless ruby_version + + if diff = ruby_version.diff(Bundler::RubyVersion.system) + problem, expected, actual = diff + + msg = case problem + when :engine + "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" + when :version + "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" + when :engine_version + "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" + when :patchlevel + if !expected.is_a?(String) + "The Ruby patchlevel in your Gemfile must be a string" + else + "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" + end + end + + raise RubyVersionMismatch, msg + end + end + + def validate_platforms! + return if current_platform_locked? + + raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ + "but your local platform is #{local_platform}. " \ + "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again." + end + + def add_platform(platform) + @new_platform ||= !@platforms.include?(platform) + @platforms |= [platform] + end + + def remove_platform(platform) + removed_platform = @platforms.delete(Gem::Platform.new(platform)) + @removed_platform ||= removed_platform + return if removed_platform + raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" + end + + def most_specific_locked_platform + @platforms.min_by do |bundle_platform| + platform_specificity_match(bundle_platform, local_platform) + end + end + + attr_reader :sources + private :sources + + def nothing_changed? + !@source_changes && + !@dependency_changes && + !@new_platform && + !@path_changes && + !@local_changes && + !@missing_lockfile_dep && + !@unlocking_bundler && + !@locked_spec_with_missing_deps && + !@locked_spec_with_invalid_deps + end + + def no_resolve_needed? + !unlocking? && nothing_changed? + end + + def unlocking? + @unlocking + end + + private + + def should_add_extra_platforms? + !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform] + end + + def lockfile_exists? + file_exists?(lockfile) + end + + def file_exists?(file) + file && File.exist?(file) + end + + def write_lock(file, preserve_unknown_sections) + return if Definition.no_lock + + contents = to_lock + + # Convert to \r\n if the existing lock has them + # i.e., Windows with `git config core.autocrlf=true` + contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n") + + if @locked_bundler_version + locked_major = @locked_bundler_version.segments.first + current_major = bundler_version_to_lock.segments.first + + updating_major = locked_major < current_major + end + + preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) + + if file_exists?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) + return if Bundler.frozen_bundle? + SharedHelpers.filesystem_access(file) { FileUtils.touch(file) } + return + end + + if Bundler.frozen_bundle? + Bundler.ui.error "Cannot write a changed lockfile while frozen." + return + end + + SharedHelpers.filesystem_access(file) do |p| + File.open(p, "wb") {|f| f.puts(contents) } + end + end + + def resolver + @resolver ||= Resolver.new(resolution_packages, gem_version_promoter) + end + + def expanded_dependencies + dependencies_with_bundler + metadata_dependencies + end + + def dependencies_with_bundler + return dependencies unless @unlocking_bundler + return dependencies if dependencies.map(&:name).include?("bundler") + + [Dependency.new("bundler", @unlocking_bundler)] + dependencies + end + + def resolution_packages + @resolution_packages ||= begin + last_resolve = converge_locked_specs + remove_invalid_platforms!(current_dependencies) + packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlock[:gems], prerelease: gem_version_promoter.pre?) + additional_base_requirements_for_resolve(packages, last_resolve) + end + end + + def filter_specs(specs, deps) + SpecSet.new(specs).for(deps, false, platforms) + end + + def materialize(dependencies) + specs = resolve.materialize(dependencies) + missing_specs = specs.missing_specs + + if missing_specs.any? + missing_specs.each do |s| + locked_gem = @locked_specs[s.name].last + next if locked_gem.nil? || locked_gem.version != s.version || !@remote + raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ + "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ + "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ + "removed in order to install." + end + + missing_specs_list = missing_specs.group_by(&:source).map do |source, missing_specs_for_source| + "#{missing_specs_for_source.map(&:full_name).join(", ")} in #{source}" + end + + raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}" + end + + incomplete_specs = specs.incomplete_specs + loop do + break if incomplete_specs.empty? + + Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies") + setup_sources_for_resolve + resolution_packages.delete(incomplete_specs) + @resolve = start_resolution + specs = resolve.materialize(dependencies) + + still_incomplete_specs = specs.incomplete_specs + + if still_incomplete_specs == incomplete_specs + package = resolution_packages.get_package(incomplete_specs.first.name) + resolver.raise_not_found! package + end + + incomplete_specs = still_incomplete_specs + end + + bundler = sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last + specs["bundler"] = bundler + + specs + end + + def start_resolution + result = SpecSet.new(resolver.start) + + @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version + @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms? + + result.complete_platforms!(platforms) + + SpecSet.new(result.for(dependencies, false, @platforms)) + end + + def precompute_source_requirements_for_indirect_dependencies? + sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? + end + + def pin_locally_available_names(source_requirements) + source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements| + local_source = original_source.dup + local_source.local_only! + + new_source_requirements[name] = if local_source.specs.search(name).any? + local_source + else + original_source + end + end + end + + def current_ruby_platform_locked? + return false unless generic_local_platform_is_ruby? + return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY) + + current_platform_locked? + end + + def current_platform_locked? + @platforms.any? do |bundle_platform| + MatchPlatform.platforms_match?(bundle_platform, local_platform) + end + end + + def add_current_platform + return if current_ruby_platform_locked? + + add_platform(local_platform) + end + + def change_reason + if unlocking? + unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v| + if v == true + k.to_s + else + v = Array(v) + "#{k}: (#{v.join(", ")})" + end + end.join(", ") + return "bundler is unlocking #{unlock_reason}" + end + [ + [@source_changes, "the list of sources changed"], + [@dependency_changes, "the dependencies in your gemfile changed"], + [@new_platform, "you added a new platform to your gemfile"], + [@path_changes, "the gemspecs for path gems changed"], + [@local_changes, "the gemspecs for git local gems changed"], + [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""], + [@unlocking_bundler, "an update to the version of Bundler itself was requested"], + [@locked_spec_with_missing_deps, "your lock file includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"], + [@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""], + ].select(&:first).map(&:last).join(", ") + end + + def pretty_dep(dep) + SharedHelpers.pretty_dependency(dep) + end + + # Check if the specs of the given source changed + # according to the locked source. + def specs_changed?(source) + locked = @locked_sources.find {|s| s == source } + + !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) + end + + def dependencies_for_source_changed?(source, locked_source = source) + deps_for_source = @dependencies.select {|s| s.source == source } + locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source } + + deps_for_source.uniq.sort != locked_deps_for_source.sort + end + + def specs_for_source_changed?(source) + locked_index = Index.new + locked_index.use(@locked_specs.select {|s| source.can_lock?(s) }) + + !locked_index.subset?(source.specs) + rescue PathError, GitError => e + Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" + false + end + + # Get all locals and override their matching sources. + # Return true if any of the locals changed (for example, + # they point to a new revision) or depend on new specs. + def converge_locals + locals = [] + + Bundler.settings.local_overrides.map do |k, v| + spec = @dependencies.find {|s| s.name == k } + source = spec&.source + if source&.respond_to?(:local_override!) + source.unlock! if @unlock[:gems].include?(spec.name) + locals << [source, source.local_override!(v)] + end + end + + sources_with_changes = locals.select do |source, changed| + changed || specs_changed?(source) + end.map(&:first) + !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty? + end + + def check_lockfile + @missing_lockfile_dep = nil + + @locked_spec_with_invalid_deps = nil + @locked_spec_with_missing_deps = nil + + missing = [] + invalid = [] + + @locked_specs.each do |s| + validation = @locked_specs.validate_deps(s) + + missing << s if validation == :missing + invalid << s if validation == :invalid + end + + if missing.any? + @locked_specs.delete(missing) + + @locked_spec_with_missing_deps = missing.first.name + elsif !@dependency_changes + @missing_lockfile_dep = current_dependencies.find do |d| + @locked_specs[d.name].empty? && d.name != "bundler" + end&.name + end + + if invalid.any? + @locked_specs.delete(invalid) + + @locked_spec_with_invalid_deps = invalid.first.name + end + end + + def converge_paths + sources.path_sources.any? do |source| + specs_changed?(source) + end + end + + def converge_path_source_to_gemspec_source(source) + return source unless source.instance_of?(Source::Path) + gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source } + gemspec_source || source + end + + def converge_path_sources_to_gemspec_sources + @locked_sources.map! do |source| + converge_path_source_to_gemspec_source(source) + end + @locked_specs.each do |spec| + spec.source &&= converge_path_source_to_gemspec_source(spec.source) + end + @locked_deps.each do |_, dep| + dep.source &&= converge_path_source_to_gemspec_source(dep.source) + end + end + + def converge_sources + # Replace the sources from the Gemfile with the sources from the Gemfile.lock, + # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent + # source in the Gemfile.lock, use the one from the Gemfile. + changes = sources.replace_sources!(@locked_sources) + + sources.all_sources.each do |source| + # has to be done separately, because we want to keep the locked checksum + # store for a source, even when doing a full update + if @locked_checksums && @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source && !s.equal?(source) } + source.checksum_store.merge!(locked_source.checksum_store) + end + # If the source is unlockable and the current command allows an unlock of + # the source (for example, you are doing a `bundle update ` of a git-pinned + # gem), unlock it. For git sources, this means to unlock the revision, which + # will cause the `ref` used to be the most recent for the branch (or master) if + # an explicit `ref` is not used. + if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name) + source.unlock! + changes = true + end + end + + changes + end + + def converge_dependencies + changes = false + + @dependencies.each do |dep| + if dep.source + dep.source = sources.get(dep.source) + end + + next if unlocking? + + unless locked_dep = @locked_deps[dep.name] + changes = true + next + end + + # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile + # doesn't carry a notion of the dependency type, if you use + # add_development_dependency in a gemspec that's loaded with the gemspec + # directive, the lockfile dependencies and resolved dependencies end up + # with a mismatch on #type. Work around that by setting the type on the + # dep from the lockfile. + locked_dep.instance_variable_set(:@type, dep.type) + + # We already know the name matches from the hash lookup + # so we only need to check the requirement now + changes ||= dep.requirement != locked_dep.requirement + end + + changes + end + + # Remove elements from the locked specs that are expired. This will most + # commonly happen if the Gemfile has changed since the lockfile was last + # generated + def converge_locked_specs + converged = converge_specs(@locked_specs) + + resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) }) + + diff = nil + + # Now, we unlock any sources that do not have anymore gems pinned to it + sources.all_sources.each do |source| + next unless source.respond_to?(:unlock!) + + unless resolve.any? {|s| s.source == source } + diff ||= @locked_specs.to_a - resolve.to_a + source.unlock! if diff.any? {|s| s.source == source } + end + end + + resolve + end + + def converge_specs(specs) + converged = [] + deps = [] + + @specs_that_changed_sources = [] + + specs.each do |s| + name = s.name + dep = @dependencies.find {|d| s.satisfies?(d) } + lockfile_source = s.source + + if dep + gemfile_source = dep.source || default_source + + @specs_that_changed_sources << s if gemfile_source != lockfile_source + deps << dep if !dep.source || lockfile_source.include?(dep.source) + @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source + + # Replace the locked dependency's source with the equivalent source from the Gemfile + s.source = gemfile_source + else + # Replace the locked dependency's source with the default source, if the locked source is no longer in the Gemfile + s.source = default_source unless sources.get(lockfile_source) + end + + next if @unlock[:sources].include?(s.source.name) + + # Path sources have special logic + if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) + new_specs = begin + s.source.specs + rescue PathError + # if we won't need the source (according to the lockfile), + # don't error if the path source isn't available + next if specs. + for(requested_dependencies, false). + none? {|locked_spec| locked_spec.source == s.source } + + raise + end + + new_spec = new_specs[s].first + if new_spec + s.dependencies.replace(new_spec.dependencies) + else + # If the spec is no longer in the path source, unlock it. This + # commonly happens if the version changed in the gemspec + @unlock[:gems] << name + end + end + + if dep.nil? && requested_dependencies.find {|d| name == d.name } + @unlock[:gems] << s.name + else + converged << s + end + end + + filter_specs(converged, deps) + end + + def metadata_dependencies + @metadata_dependencies ||= [ + Dependency.new("Ruby\0", Bundler::RubyVersion.system.gem_version), + Dependency.new("RubyGems\0", Gem::VERSION), + ] + end + + def source_requirements + # Record the specs available in each gem's source, so that those + # specs will be available later when the resolver knows where to + # look for that gemspec (or its dependencies) + source_requirements = if precompute_source_requirements_for_indirect_dependencies? + all_requirements = source_map.all_requirements + all_requirements = pin_locally_available_names(all_requirements) if @prefer_local + { default: default_source }.merge(all_requirements) + else + { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) + end + source_requirements.merge!(source_map.locked_requirements) unless @remote + metadata_dependencies.each do |dep| + source_requirements[dep.name] = sources.metadata_source + end + + default_bundler_source = source_requirements["bundler"] || default_source + + if @unlocking_bundler + default_bundler_source.add_dependency_names("bundler") + else + source_requirements[:default_bundler] = default_bundler_source + source_requirements["bundler"] = sources.metadata_source # needs to come last to override + end + + verify_changed_sources! + source_requirements + end + + def default_source + sources.default_source + end + + def verify_changed_sources! + @specs_that_changed_sources.each do |s| + if s.source.specs.search(s.name).empty? + raise GemNotFound, "Could not find gem '#{s.name}' in #{s.source}" + end + end + end + + def requested_groups + values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] + values &= Bundler.settings[:only] unless Bundler.settings[:only].empty? + values + end + + def lockfiles_equal?(current, proposed, preserve_unknown_sections) + if preserve_unknown_sections + sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) + sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) + sections_to_ignore << LockfileParser::RUBY + sections_to_ignore << LockfileParser::BUNDLED unless @unlocking_bundler + pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ + whitespace_cleanup = /\n{2,}/ + current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip + proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip + end + current == proposed + end + + def additional_base_requirements_for_resolve(resolution_packages, last_resolve) + return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources) + converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec| + next if locked_spec.source.is_a?(Source::Path) + resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}") + end + resolution_packages + end + + def remove_invalid_platforms!(dependencies) + return if Bundler.frozen_bundle? + + platforms.reverse_each do |platform| + next if local_platform == platform || + (@new_platform && platforms.last == platform) || + @path_changes || + @dependency_changes || + !@originally_locked_specs.incomplete_for_platform?(dependencies, platform) + + remove_platform(platform) + add_current_platform if platform == Gem::Platform::RUBY + end + end + + def source_map + @source_map ||= SourceMap.new(sources, dependencies, @locked_specs) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/dependency.rb b/bin/gems/bundler-2.5.9/lib/bundler/dependency.rb new file mode 100644 index 00000000..77d7a003 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/dependency.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +require "rubygems/dependency" +require_relative "shared_helpers" +require_relative "rubygems_ext" + +module Bundler + class Dependency < Gem::Dependency + attr_reader :autorequire + attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref + + ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze + PLATFORM_MAP = { + ruby: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS], + mri: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS], + rbx: [Gem::Platform::RUBY], + truffleruby: [Gem::Platform::RUBY], + jruby: [Gem::Platform::JAVA, [18, 19]], + windows: [Gem::Platform::WINDOWS, ALL_RUBY_VERSIONS], + # deprecated + mswin: [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS], + mswin64: [Gem::Platform::MSWIN64, ALL_RUBY_VERSIONS - [18]], + mingw: [Gem::Platform::MINGW, ALL_RUBY_VERSIONS], + x64_mingw: [Gem::Platform::X64_MINGW, ALL_RUBY_VERSIONS - [18, 19]], + }.each_with_object({}) do |(platform, spec), hash| + hash[platform] = spec[0] + spec[1]&.each {|version| hash[:"#{platform}_#{version}"] = spec[0] } + end.freeze + + def initialize(name, version, options = {}, &blk) + type = options["type"] || :runtime + super(name, version, type) + + @autorequire = nil + @groups = Array(options["group"] || :default).map(&:to_sym) + @source = options["source"] + @path = options["path"] + @git = options["git"] + @github = options["github"] + @branch = options["branch"] + @ref = options["ref"] + @platforms = Array(options["platforms"]) + @env = options["env"] + @should_include = options.fetch("should_include", true) + @gemfile = options["gemfile"] + @force_ruby_platform = options["force_ruby_platform"] if options.key?("force_ruby_platform") + + @autorequire = Array(options["require"] || []) if options.key?("require") + end + + RUBY_PLATFORM_ARRAY = [Gem::Platform::RUBY].freeze + private_constant :RUBY_PLATFORM_ARRAY + + # Returns the platforms this dependency is valid for, in the same order as + # passed in the `valid_platforms` parameter + def gem_platforms(valid_platforms) + return RUBY_PLATFORM_ARRAY if force_ruby_platform + return valid_platforms if @platforms.empty? + + valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) } + end + + def expanded_platforms + @expanded_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.flatten.uniq + end + + def should_include? + @should_include && current_env? && current_platform? + end + + def gemspec_dev_dep? + type == :development + end + + def current_env? + return true unless @env + if @env.is_a?(Hash) + @env.all? do |key, val| + ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) + end + else + ENV[@env.to_s] + end + end + + def current_platform? + return true if @platforms.empty? + @platforms.any? do |p| + Bundler.current_ruby.send("#{p}?") + end + end + + def to_lock + out = super + out << "!" if source + out + end + + def specific? + super + rescue NoMethodError + requirement != ">= 0" + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/deployment.rb b/bin/gems/bundler-2.5.9/lib/bundler/deployment.rb new file mode 100644 index 00000000..b432ae6a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/deployment.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.major_deprecation 2, "Bundler no longer integrates with " \ + "Capistrano, but Capistrano provides its own integration with " \ + "Bundler via the capistrano-bundler gem. Use it instead." + +module Bundler + class Deployment + def self.define_task(context, task_method = :task, opts = {}) + if defined?(Capistrano) && context.is_a?(Capistrano::Configuration) + context_name = "capistrano" + role_default = "{:except => {:no_release => true}}" + error_type = ::Capistrano::CommandError + else + context_name = "vlad" + role_default = "[:app]" + error_type = ::Rake::CommandFailedError + end + + roles = context.fetch(:bundle_roles, false) + opts[:roles] = roles if roles + + context.send :namespace, :bundle do + send :desc, <<-DESC + Install the current Bundler environment. By default, gems will be \ + installed to the shared/bundle path. Gems in the development and \ + test group will not be installed. The install command is executed \ + with the --deployment and --quiet flags. If the bundle cmd cannot \ + be found then you can override the bundle_cmd variable to specify \ + which one it should use. The base path to the app is fetched from \ + the :latest_release variable. Set it for custom deploy layouts. + + You can override any of these defaults by setting the variables shown below. + + N.B. bundle_roles must be defined before you require 'bundler/#{context_name}' \ + in your deploy.rb file. + + set :bundle_gemfile, "Gemfile" + set :bundle_dir, File.join(fetch(:shared_path), 'bundle') + set :bundle_flags, "--deployment --quiet" + set :bundle_without, [:development, :test] + set :bundle_with, [:mysql] + set :bundle_cmd, "bundle" # e.g. "/opt/ruby/bin/bundle" + set :bundle_roles, #{role_default} # e.g. [:app, :batch] + DESC + send task_method, :install, opts do + bundle_cmd = context.fetch(:bundle_cmd, "bundle") + bundle_flags = context.fetch(:bundle_flags, "--deployment --quiet") + bundle_dir = context.fetch(:bundle_dir, File.join(context.fetch(:shared_path), "bundle")) + bundle_gemfile = context.fetch(:bundle_gemfile, "Gemfile") + bundle_without = [*context.fetch(:bundle_without, [:development, :test])].compact + bundle_with = [*context.fetch(:bundle_with, [])].compact + app_path = context.fetch(:latest_release) + if app_path.to_s.empty? + raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.") + end + args = ["--gemfile #{File.join(app_path, bundle_gemfile)}"] + args << "--path #{bundle_dir}" unless bundle_dir.to_s.empty? + args << bundle_flags.to_s + args << "--without #{bundle_without.join(" ")}" unless bundle_without.empty? + args << "--with #{bundle_with.join(" ")}" unless bundle_with.empty? + + run "cd #{app_path} && #{bundle_cmd} install #{args.join(" ")}" + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/deprecate.rb b/bin/gems/bundler-2.5.9/lib/bundler/deprecate.rb new file mode 100644 index 00000000..f5953363 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/deprecate.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +begin + require "rubygems/deprecate" +rescue LoadError + # it's fine if it doesn't exist on the current RubyGems... + nil +end + +module Bundler + # If Bundler::Deprecate is an autoload constant, we need to define it + if defined?(Bundler::Deprecate) && !autoload?(:Deprecate) + # nothing to do! + elsif defined? ::Deprecate + Deprecate = ::Deprecate + elsif defined? Gem::Deprecate + Deprecate = Gem::Deprecate + else + class Deprecate + end + end + + unless Deprecate.respond_to?(:skip_during) + def Deprecate.skip_during + original = skip + self.skip = true + yield + ensure + self.skip = original + end + end + + unless Deprecate.respond_to?(:skip) + def Deprecate.skip + @skip ||= false + end + end + + unless Deprecate.respond_to?(:skip=) + def Deprecate.skip=(skip) + @skip = skip + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/digest.rb b/bin/gems/bundler-2.5.9/lib/bundler/digest.rb new file mode 100644 index 00000000..2c6d971f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/digest.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# This code was extracted from https://github.com/Solistra/ruby-digest which is under public domain +module Bundler + module Digest + # The initial constant values for the 32-bit constant words A, B, C, D, and + # E, respectively. + SHA1_WORDS = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0].freeze + + # The 8-bit field used for bitwise `AND` masking. Defaults to `0xFFFFFFFF`. + SHA1_MASK = 0xFFFFFFFF + + class << self + def sha1(string) + unless string.is_a?(String) + raise TypeError, "can't convert #{string.class.inspect} into String" + end + + buffer = string.b + + words = SHA1_WORDS.dup + generate_split_buffer(buffer) do |chunk| + w = [] + chunk.each_slice(4) do |a, b, c, d| + w << (((a << 8 | b) << 8 | c) << 8 | d) + end + a, b, c, d, e = *words + (16..79).each do |i| + w[i] = SHA1_MASK & rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1) + end + 0.upto(79) do |i| + case i + when 0..19 + f = ((b & c) | (~b & d)) + k = 0x5A827999 + when 20..39 + f = (b ^ c ^ d) + k = 0x6ED9EBA1 + when 40..59 + f = ((b & c) | (b & d) | (c & d)) + k = 0x8F1BBCDC + when 60..79 + f = (b ^ c ^ d) + k = 0xCA62C1D6 + end + t = SHA1_MASK & rotate(a, 5) + f + e + k + w[i] + a, b, c, d, e = t, a, SHA1_MASK & rotate(b, 30), c, d # rubocop:disable Style/ParallelAssignment + end + mutated = [a, b, c, d, e] + words.map!.with_index {|word, index| SHA1_MASK & (word + mutated[index]) } + end + + words.pack("N*").unpack1("H*") + end + + private + + def generate_split_buffer(string, &block) + size = string.bytesize * 8 + buffer = string.bytes << 128 + buffer << 0 while buffer.size % 64 != 56 + buffer.concat([size].pack("Q>").bytes) + buffer.each_slice(64, &block) + end + + def rotate(value, spaces) + value << spaces | value >> (32 - spaces) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/dsl.rb b/bin/gems/bundler-2.5.9/lib/bundler/dsl.rb new file mode 100644 index 00000000..6af80fb3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/dsl.rb @@ -0,0 +1,619 @@ +# frozen_string_literal: true + +require_relative "dependency" +require_relative "ruby_dsl" + +module Bundler + class Dsl + include RubyDsl + + def self.evaluate(gemfile, lockfile, unlock) + builder = new + builder.eval_gemfile(gemfile) + builder.to_definition(lockfile, unlock) + end + + VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze + + VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules + platform platforms type source install_if gemfile force_ruby_platform].freeze + + GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z} + GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z} + + attr_reader :gemspecs, :gemfile + attr_accessor :dependencies + + def initialize + @source = nil + @sources = SourceList.new + @git_sources = {} + @dependencies = [] + @groups = [] + @install_conditionals = [] + @optional_groups = [] + @platforms = [] + @env = nil + @ruby_version = nil + @gemspecs = [] + @gemfile = nil + @gemfiles = [] + add_git_sources + end + + def eval_gemfile(gemfile, contents = nil) + expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent) + original_gemfile = @gemfile + @gemfile = expanded_gemfile_path + @gemfiles << expanded_gemfile_path + contents ||= Bundler.read_file(@gemfile.to_s) + instance_eval(contents, @gemfile.to_s, 1) + rescue Exception => e # rubocop:disable Lint/RescueException + message = "There was an error " \ + "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ + "`#{File.basename gemfile.to_s}`: #{e.message}" + + raise DSLError.new(message, gemfile, e.backtrace, contents) + ensure + @gemfile = original_gemfile + end + + def gemspec(opts = nil) + opts ||= {} + path = opts[:path] || "." + glob = opts[:glob] + name = opts[:name] + development_group = opts[:development_group] || :development + expanded_path = gemfile_root.join(path) + + gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact + gemspecs.reject! {|s| s.name != name } if name + specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } + + case specs_by_name_and_version.size + when 1 + specs = specs_by_name_and_version.values.first + spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first + + @gemspecs << spec + + gem spec.name, name: spec.name, path: path, glob: glob + + group(development_group) do + spec.development_dependencies.each do |dep| + gem dep.name, *(dep.requirement.as_list + [type: :development]) + end + end + when 0 + raise InvalidOption, "There are no gemspecs at #{expanded_path}" + else + raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ + "Please use the :name option to specify which one should be used" + end + end + + def gem(name, *args) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + options["gemfile"] = @gemfile + version = args || [">= 0"] + + normalize_options(name, version, options) + + dep = Dependency.new(name, version, options) + + # if there's already a dependency with this name we try to prefer one + if current = @dependencies.find {|d| d.name == dep.name } + if current.requirement != dep.requirement + current_requirement_open = current.requirements_list.include?(">= 0") + + gemspec_dep = [dep, current].find(&:gemspec_dev_dep?) + if gemspec_dep + gemfile_dep = [dep, current].find(&:runtime?) + + unless current_requirement_open + Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \ + "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n" + end + else + update_prompt = "" + + if File.basename(@gemfile) == Injector::INJECTED_GEMS + if dep.requirements_list.include?(">= 0") && !current_requirement_open + update_prompt = ". Gem already added" + else + update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`" + + update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current_requirement_open + end + end + + raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ + "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \ + "#{update_prompt}" + end + end + + # Always prefer the dependency from the Gemfile + if current.gemspec_dev_dep? + @dependencies.delete(current) + elsif dep.gemspec_dev_dep? + return + elsif current.source != dep.source + raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ + "You specified that #{dep.name} (#{dep.requirement}) should come from " \ + "#{current.source || "an unspecified source"} and #{dep.source}\n" + else + Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ + "You should probably keep only one of them.\n" \ + "Remove any duplicate entries and specify the gem only once.\n" \ + "While it's not a problem now, it could cause errors if you change the version of one of them later." + end + end + + @dependencies << dep + end + + def source(source, *args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + options = normalize_hash(options) + source = normalize_source(source) + + if options.key?("type") + options["type"] = options["type"].to_s + unless Plugin.source?(options["type"]) + raise InvalidOption, "No plugin sources available for #{options["type"]}" + end + + unless block_given? + raise InvalidOption, "You need to pass a block to #source with :type option" + end + + source_opts = options.merge("uri" => source) + with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) + elsif block_given? + with_source(@sources.add_rubygems_source("remotes" => source), &blk) + else + @sources.add_global_rubygems_remote(source) + end + end + + def git_source(name, &block) + unless block_given? + raise InvalidOption, "You need to pass a block to #git_source" + end + + if valid_keys.include?(name.to_s) + raise InvalidOption, "You cannot use #{name} as a git source. It " \ + "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" + end + + @git_sources[name.to_s] = block + end + + def path(path, options = {}, &blk) + source_options = normalize_hash(options).merge( + "path" => Pathname.new(path), + "root_path" => gemfile_root, + "gemspec" => gemspecs.find {|g| g.name == options["name"] } + ) + + source_options["global"] = true unless block_given? + + source = @sources.add_path_source(source_options) + with_source(source, &blk) + end + + def git(uri, options = {}, &blk) + unless block_given? + msg = "You can no longer specify a git source by itself. Instead, \n" \ + "either use the :git option on a gem, or specify the gems that \n" \ + "bundler should find in the git source by passing a block to \n" \ + "the git method, like: \n\n" \ + " git 'git://github.com/rails/rails.git' do\n" \ + " gem 'rails'\n" \ + " end" + raise DeprecatedError, msg + end + + with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) + end + + def github(repo, options = {}) + raise ArgumentError, "GitHub sources require a block" unless block_given? + github_uri = @git_sources["github"].call(repo) + git_options = normalize_hash(options).merge("uri" => github_uri) + git_source = @sources.add_git_source(git_options) + with_source(git_source) { yield } + end + + def to_definition(lockfile, unlock) + check_primary_source_safety + Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) + end + + def group(*args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + normalize_group_options(options, args) + + @groups.concat args + + if options["optional"] + optional_groups = args - @optional_groups + @optional_groups.concat optional_groups + end + + yield + ensure + args.each { @groups.pop } + end + + def install_if(*args) + @install_conditionals.concat args + yield + ensure + args.each { @install_conditionals.pop } + end + + def platforms(*platforms) + @platforms.concat platforms + yield + ensure + platforms.each { @platforms.pop } + end + alias_method :platform, :platforms + + def env(name) + old = @env + @env = name + yield + ensure + @env = old + end + + def plugin(*args) + # Pass on + end + + def method_missing(name, *args) + raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" + end + + def check_primary_source_safety + check_path_source_safety + check_rubygems_source_safety + end + + private + + def add_git_sources + git_source(:github) do |repo_name| + if repo_name =~ GITHUB_PULL_REQUEST_URL + { + "git" => "https://github.com/#{$1}.git", + "branch" => nil, + "ref" => "refs/pull/#{$2}/head", + "tag" => nil, + } + else + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://github.com/#{repo_name}.git" + end + end + + git_source(:gist) do |repo_name| + "https://gist.github.com/#{repo_name}.git" + end + + git_source(:bitbucket) do |repo_name| + user_name, repo_name = repo_name.split("/") + repo_name ||= user_name + "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" + end + + git_source(:gitlab) do |repo_name| + if repo_name =~ GITLAB_MERGE_REQUEST_URL + { + "git" => "https://gitlab.com/#{$1}.git", + "branch" => nil, + "ref" => "refs/merge-requests/#{$2}/head", + "tag" => nil, + } + else + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://gitlab.com/#{repo_name}.git" + end + end + end + + def with_source(source) + old_source = @source + if block_given? + @source = source + yield + end + source + ensure + @source = old_source + end + + def normalize_hash(opts) + opts.keys.each do |k| + opts[k.to_s] = opts.delete(k) unless k.is_a?(String) + end + opts + end + + def valid_keys + @valid_keys ||= VALID_KEYS + end + + def normalize_options(name, version, opts) + if name.is_a?(Symbol) + raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) + end + if /\s/.match?(name) + raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) + end + raise GemfileError, %(an empty gem name is not valid) if name.empty? + + normalize_hash(opts) + + git_names = @git_sources.keys.map(&:to_s) + validate_keys("gem '#{name}'", opts, valid_keys + git_names) + + groups = @groups.dup + opts["group"] = opts.delete("groups") || opts["group"] + groups.concat Array(opts.delete("group")) + groups = [:default] if groups.empty? + + install_if = @install_conditionals.dup + install_if.concat Array(opts.delete("install_if")) + install_if = install_if.reduce(true) do |memo, val| + memo && (val.respond_to?(:call) ? val.call : val) + end + + platforms = @platforms.dup + opts["platforms"] = opts["platform"] || opts["platforms"] + platforms.concat Array(opts.delete("platforms")) + platforms.map!(&:to_sym) + platforms.each do |p| + next if VALID_PLATFORMS.include?(p) + raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" + end + + # Save sources passed in a key + if opts.key?("source") + source = normalize_source(opts["source"]) + opts["source"] = @sources.add_rubygems_source("remotes" => source) + end + + git_name = (git_names & opts.keys).last + if @git_sources[git_name] + git_opts = @git_sources[git_name].call(opts[git_name]) + git_opts = { "git" => git_opts } if git_opts.is_a?(String) + opts.merge!(git_opts) do |key, _gemfile_value, _git_source_value| + raise GemfileError, %(The :#{key} option can't be used with `#{git_name}: #{opts[git_name].inspect}`) + end + end + + %w[git path].each do |type| + next unless param = opts[type] + if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ + options = opts.merge("name" => name, "version" => $1) + else + options = opts.dup + end + source = send(type, param, options) {} + opts["source"] = source + end + + opts["source"] ||= @source + opts["env"] ||= @env + opts["platforms"] = platforms.dup + opts["group"] = groups + opts["should_include"] = install_if + end + + def normalize_group_options(opts, groups) + normalize_hash(opts) + + groups = groups.map {|group| ":#{group}" }.join(", ") + validate_keys("group #{groups}", opts, %w[optional]) + + opts["optional"] ||= false + end + + def validate_keys(command, opts, valid_keys) + if opts["branch"] && !(opts["git"] || opts["github"] || (opts.keys & @git_sources.keys.map(&:to_s)).any?) + raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) + end + + invalid_keys = opts.keys - valid_keys + return true unless invalid_keys.any? + + message = String.new + message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " + message << if invalid_keys.size > 1 + "as options for #{command}, but they are invalid." + else + "as an option for #{command}, but it is invalid." + end + + message << " Valid options are: #{valid_keys.join(", ")}." + message << " You may be able to resolve this by upgrading Bundler to the newest version." + raise InvalidOption, message + end + + def normalize_source(source) + case source + when :gemcutter, :rubygems, :rubyforge + message = + "The source :#{source} is deprecated because HTTP requests are insecure.\n" \ + "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not." + removed_message = + "The source :#{source} is disallowed because HTTP requests are insecure.\n" \ + "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not." + Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message + "http://rubygems.org" + when String + source + else + raise GemfileError, "Unknown source '#{source}'" + end + end + + def check_path_source_safety + return if @sources.global_path_source.nil? + + msg = "You can no longer specify a path source by itself. Instead, \n" \ + "either use the :path option on a gem, or specify the gems that \n" \ + "bundler should find in the path source by passing a block to \n" \ + "the path method, like: \n\n" \ + " path 'dir/containing/rails' do\n" \ + " gem 'rails'\n" \ + " end\n\n" + + SharedHelpers.major_deprecation(2, msg.strip) + end + + def check_rubygems_source_safety + if @sources.implicit_global_source? + implicit_global_source_warning + elsif @sources.aggregate_global_source? + multiple_global_source_warning + end + end + + def implicit_global_source_warning + Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \ + "Not using an explicit global source may result in a different lockfile being generated depending on " \ + "the gems you have installed locally before bundler is run. " \ + "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"." + end + + def multiple_global_source_warning + if Bundler.feature_flag.bundler_3_mode? + msg = "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" + raise GemfileEvalError, msg + else + message = + "Your Gemfile contains multiple global sources. " \ + "Using `source` more than once without a block is a security risk, and " \ + "may result in installing unexpected gems. To resolve this warning, use " \ + "a block to indicate which gems should come from the secondary source." + removed_message = + "Your Gemfile contains multiple global sources. " \ + "Using `source` more than once without a block is a security risk, and " \ + "may result in installing unexpected gems. To resolve this error, use " \ + "a block to indicate which gems should come from the secondary source." + Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message + end + end + + class DSLError < GemfileError + # @return [String] the description that should be presented to the user. + # + attr_reader :description + + # @return [String] the path of the dsl file that raised the exception. + # + attr_reader :dsl_path + + # @return [Exception] the backtrace of the exception raised by the + # evaluation of the dsl file. + # + attr_reader :backtrace + + # @param [Exception] backtrace @see backtrace + # @param [String] dsl_path @see dsl_path + # + def initialize(description, dsl_path, backtrace, contents = nil) + @status_code = $!.respond_to?(:status_code) && $!.status_code + + @description = description + @dsl_path = dsl_path + @backtrace = backtrace + @contents = contents + end + + def status_code + @status_code || super + end + + # @return [String] the contents of the DSL that cause the exception to + # be raised. + # + def contents + @contents ||= dsl_path && File.exist?(dsl_path) && File.read(dsl_path) + end + + # The message of the exception reports the content of podspec for the + # line that generated the original exception. + # + # @example Output + # + # Invalid podspec at `RestKit.podspec` - undefined method + # `exclude_header_search_paths=' for # + # + # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 + # ------------------------------------------- + # # because it would break: #import + # > ns.exclude_header_search_paths = 'Code/RestKit.h' + # end + # ------------------------------------------- + # + # @return [String] the message of the exception. + # + def to_s + @to_s ||= begin + trace_line, description = parse_line_number_from_description + + m = String.new("\n[!] ") + m << description + m << ". Bundler cannot continue.\n" + + return m unless backtrace && dsl_path && contents + + trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line + return m unless trace_line + line_numer = trace_line.split(":")[1].to_i - 1 + return m unless line_numer + + lines = contents.lines.to_a + indent = " # " + indicator = indent.tr("#", ">") + first_line = line_numer.zero? + last_line = (line_numer == (lines.count - 1)) + + m << "\n" + m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" + m << "#{indent}-------------------------------------------\n" + m << "#{indent}#{lines[line_numer - 1]}" unless first_line + m << "#{indicator}#{lines[line_numer]}" + m << "#{indent}#{lines[line_numer + 1]}" unless last_line + m << "\n" unless m.end_with?("\n") + m << "#{indent}-------------------------------------------\n" + end + end + + private + + def parse_line_number_from_description + description = self.description + if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/ + trace_line = Regexp.last_match[1] + description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") + end + [trace_line, description] + end + end + + def gemfile_root + @gemfile ||= Bundler.default_gemfile + @gemfile.dirname + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/endpoint_specification.rb b/bin/gems/bundler-2.5.9/lib/bundler/endpoint_specification.rb new file mode 100644 index 00000000..87cb352e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/endpoint_specification.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +module Bundler + # used for Creating Specifications from the Gemcutter Endpoint + class EndpointSpecification < Gem::Specification + include MatchRemoteMetadata + + attr_reader :name, :version, :platform, :checksum + attr_accessor :source, :remote, :dependencies + + def initialize(name, version, platform, spec_fetcher, dependencies, metadata = nil) + super() + @name = name + @version = Gem::Version.create version + @platform = Gem::Platform.new(platform) + @spec_fetcher = spec_fetcher + @dependencies = dependencies.map {|dep, reqs| build_dependency(dep, reqs) } + + @loaded_from = nil + @remote_specification = nil + + parse_metadata(metadata) + end + + def fetch_platform + @platform + end + + # needed for standalone, load required_paths from local gemspec + # after the gem is installed + def require_paths + if @remote_specification + @remote_specification.require_paths + elsif _local_specification + _local_specification.require_paths + else + super + end + end + + # needed for inline + def load_paths + # remote specs aren't installed, and can't have load_paths + if _local_specification + _local_specification.load_paths + else + super + end + end + + # needed for binstubs + def executables + if @remote_specification + @remote_specification.executables + elsif _local_specification + _local_specification.executables + else + super + end + end + + # needed for bundle clean + def bindir + if @remote_specification + @remote_specification.bindir + elsif _local_specification + _local_specification.bindir + else + super + end + end + + # needed for post_install_messages during install + def post_install_message + if @remote_specification + @remote_specification.post_install_message + elsif _local_specification + _local_specification.post_install_message + else + super + end + end + + # needed for "with native extensions" during install + def extensions + if @remote_specification + @remote_specification.extensions + elsif _local_specification + _local_specification.extensions + else + super + end + end + + def _local_specification + return unless @loaded_from && File.exist?(local_specification_path) + eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec| + spec.loaded_from = @loaded_from + end + end + + def __swap__(spec) + SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) + @remote_specification = spec + end + + private + + def _remote_specification + @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) + end + + def local_specification_path + "#{base_dir}/specifications/#{full_name}.gemspec" + end + + def parse_metadata(data) + unless data + @required_ruby_version = nil + @required_rubygems_version = nil + return + end + + data.each do |k, v| + next unless v + case k.to_s + when "checksum" + begin + @checksum = Checksum.from_api(v.last, @spec_fetcher.uri) + rescue ArgumentError => e + raise ArgumentError, "Invalid checksum for #{full_name}: #{e.message}" + end + when "rubygems" + @required_rubygems_version = Gem::Requirement.new(v) + when "ruby" + @required_ruby_version = Gem::Requirement.new(v) + end + end + rescue StandardError => e + raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" + end + + def build_dependency(name, requirements) + Gem::Dependency.new(name, requirements) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/env.rb b/bin/gems/bundler-2.5.9/lib/bundler/env.rb new file mode 100644 index 00000000..f6cb198e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/env.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require_relative "rubygems_integration" +require_relative "source/git/git_proxy" + +module Bundler + class Env + def self.write(io) + io.write report + end + + def self.report(options = {}) + print_gemfile = options.delete(:print_gemfile) { true } + print_gemspecs = options.delete(:print_gemspecs) { true } + + out = String.new + append_formatted_table("Environment", environment, out) + append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) + + unless Bundler.settings.all.empty? + out << "\n## Bundler settings\n\n```\n" + Bundler.settings.all.each do |setting| + out << setting << "\n" + Bundler.settings.pretty_values_for(setting).each do |line| + out << " " << line << "\n" + end + end + out << "```\n" + end + + return out unless SharedHelpers.in_bundle? + + if print_gemfile + gemfiles = [Bundler.default_gemfile] + begin + gemfiles = Bundler.definition.gemfiles + rescue GemfileNotFound + nil + end + + out << "\n## Gemfile\n" + gemfiles.each do |gemfile| + out << "\n### #{SharedHelpers.relative_path_to(gemfile)}\n\n" + out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" + end + + out << "\n### #{SharedHelpers.relative_path_to(Bundler.default_lockfile)}\n\n" + out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" + end + + if print_gemspecs + dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } + out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? + dsl.gemspecs.each do |gs| + out << "\n### #{File.basename(gs.loaded_from)}" + out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" + end + end + + out + end + + def self.read_file(filename) + Bundler.read_file(filename.to_s).strip + rescue Errno::ENOENT + "" + rescue RuntimeError => e + "#{e.class}: #{e.message}" + end + + def self.ruby_version + "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]" + end + + def self.git_version + Bundler::Source::Git::GitProxy.new(nil, nil).full_version + rescue Bundler::Source::Git::GitNotInstalledError + "not installed" + end + + def self.version_of(script) + return "not installed" unless Bundler.which(script) + `#{script} --version`.chomp + end + + def self.chruby_version + return "not installed" unless Bundler.which("chruby-exec") + `chruby-exec -- chruby --version`. + sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1') + end + + def self.environment + out = [] + + out << ["Bundler", Bundler::VERSION] + out << [" Platforms", Gem.platforms.join(", ")] + out << ["Ruby", ruby_version] + out << [" Full Path", Gem.ruby] + out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname] + out << ["RubyGems", Gem::VERSION] + out << [" Gem Home", Gem.dir] + out << [" Gem Path", Gem.path.join(File::PATH_SEPARATOR)] + out << [" User Home", Gem.user_home] + out << [" User Path", Gem.user_dir] + out << [" Bin Dir", Gem.bindir] + if defined?(OpenSSL::SSL) + out << ["OpenSSL"] + out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) + out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) + out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE) + out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR) + end + out << ["Tools"] + out << [" Git", git_version] + out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }] + out << [" rbenv", version_of("rbenv")] + out << [" chruby", chruby_version] + + %w[rubygems-bundler open_gem].each do |name| + specs = Bundler.rubygems.find_name(name) + out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty? + end + if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z} + shebang = File.read(exe).lines.first + shebang.sub!(/^#!\s*/, "") + unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby") + out << ["Gem.ruby", Gem.ruby] + out << ["bundle #!", shebang] + end + end + + out + end + + def self.append_formatted_table(title, pairs, out) + return if pairs.empty? + out << "\n" unless out.empty? + out << "## #{title}\n\n```\n" + ljust = pairs.map {|k, _v| k.to_s.length }.max + pairs.each do |k, v| + out << "#{k.to_s.ljust(ljust)} #{v}\n" + end + out << "```\n" + end + + private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/environment_preserver.rb b/bin/gems/bundler-2.5.9/lib/bundler/environment_preserver.rb new file mode 100644 index 00000000..c4c1b53f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/environment_preserver.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +module Bundler + class EnvironmentPreserver + INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL" + BUNDLER_KEYS = %w[ + BUNDLE_BIN_PATH + BUNDLE_GEMFILE + BUNDLER_VERSION + BUNDLER_SETUP + GEM_HOME + GEM_PATH + MANPATH + PATH + RB_USER_INSTALL + RUBYLIB + RUBYOPT + ].map(&:freeze).freeze + BUNDLER_PREFIX = "BUNDLER_ORIG_" + + def self.from_env + new(env_to_hash(ENV), BUNDLER_KEYS) + end + + def self.env_to_hash(env) + to_hash = env.to_hash + return to_hash unless Gem.win_platform? + + to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v } + end + + # @param env [Hash] + # @param keys [Array] + def initialize(env, keys) + @original = env + @keys = keys + @prefix = BUNDLER_PREFIX + end + + # Replaces `ENV` with the bundler environment variables backed up + def replace_with_backup + unless Gem.win_platform? + ENV.replace(backup) + return + end + + # Fallback logic for Windows below to workaround + # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all + # supported rubies include the fix for that. + + ENV.clear + + backup.each {|k, v| ENV[k] = v } + end + + # @return [Hash] + def backup + env = @original.clone + @keys.each do |key| + value = env[key] + if !value.nil? + env[@prefix + key] ||= value + else + env[@prefix + key] ||= INTENTIONALLY_NIL + end + end + env + end + + # @return [Hash] + def restore + env = @original.clone + @keys.each do |key| + value_original = env[@prefix + key] + next if value_original.nil? + if value_original == INTENTIONALLY_NIL + env.delete(key) + else + env[key] = value_original + end + env.delete(@prefix + key) + end + env + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/errors.rb b/bin/gems/bundler-2.5.9/lib/bundler/errors.rb new file mode 100644 index 00000000..b6a11cc7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/errors.rb @@ -0,0 +1,233 @@ +# frozen_string_literal: true + +module Bundler + class BundlerError < StandardError + def self.status_code(code) + define_method(:status_code) { code } + if match = BundlerError.all_errors.find {|_k, v| v == code } + error, _ = match + raise ArgumentError, + "Trying to register #{self} for status code #{code} but #{error} is already registered" + end + BundlerError.all_errors[self] = code + end + + def self.all_errors + @all_errors ||= {} + end + end + + class GemfileError < BundlerError; status_code(4); end + class InstallError < BundlerError; status_code(5); end + + # Internal error, should be rescued + class SolveFailure < BundlerError; status_code(6); end + + class GemNotFound < BundlerError; status_code(7); end + class InstallHookError < BundlerError; status_code(8); end + class GemfileNotFound < BundlerError; status_code(10); end + class GitError < BundlerError; status_code(11); end + class DeprecatedError < BundlerError; status_code(12); end + class PathError < BundlerError; status_code(13); end + class GemspecError < BundlerError; status_code(14); end + class InvalidOption < BundlerError; status_code(15); end + class ProductionError < BundlerError; status_code(16); end + + class HTTPError < BundlerError + status_code(17) + def filter_uri(uri) + URICredentialsFilter.credential_filtered_uri(uri) + end + end + + class RubyVersionMismatch < BundlerError; status_code(18); end + class SecurityError < BundlerError; status_code(19); end + class LockfileError < BundlerError; status_code(20); end + class CyclicDependencyError < BundlerError; status_code(21); end + class GemfileLockNotFound < BundlerError; status_code(22); end + class PluginError < BundlerError; status_code(29); end + class ThreadCreationError < BundlerError; status_code(33); end + class APIResponseMismatchError < BundlerError; status_code(34); end + class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end + class GemfileEvalError < GemfileError; end + class MarshalError < StandardError; end + + class ChecksumMismatchError < SecurityError + def initialize(lock_name, existing, checksum) + @lock_name = lock_name + @existing = existing + @checksum = checksum + end + + def message + <<~MESSAGE + Bundler found mismatched checksums. This is a potential security risk. + #{@lock_name} #{@existing.to_lock} + from #{@existing.sources.join("\n and ")} + #{@lock_name} #{@checksum.to_lock} + from #{@checksum.sources.join("\n and ")} + + #{mismatch_resolution_instructions} + To ignore checksum security warnings, disable checksum validation with + `bundle config set --local disable_checksum_validation true` + MESSAGE + end + + def mismatch_resolution_instructions + removable, remote = [@existing, @checksum].partition(&:removable?) + case removable.size + when 0 + msg = +"Mismatched checksums each have an authoritative source:\n" + msg << " 1. #{@existing.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n" + msg << " 2. #{@checksum.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n" + msg << "You may need to alter your Gemfile sources to resolve this issue.\n" + when 1 + msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n" + msg << removable.first.removal_instructions + when 2 + msg = +"To resolve this issue you can either:\n" + msg << @checksum.removal_instructions + msg << "or if you are sure that the new checksum from #{@checksum.sources.first} is correct:\n" + msg << @existing.removal_instructions + end + end + + status_code(37) + end + + class PermissionError < BundlerError + def initialize(path, permission_type = :write) + @path = path + @permission_type = permission_type + end + + def action + case @permission_type + when :read then "read from" + when :write then "write to" + when :executable, :exec then "execute" + else @permission_type.to_s + end + end + + def permission_type + case @permission_type + when :create + "executable permissions for all parent directories and write permissions for `#{parent_folder}`" + else + "#{@permission_type} permissions for that path" + end + end + + def parent_folder + File.dirname(@path) + end + + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "It is likely that you need to grant #{permission_type}." + end + + status_code(23) + end + + class GemRequireError < BundlerError + attr_reader :orig_exception + + def initialize(orig_exception, msg) + full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ + "Backtrace for gem load error is:\n"\ + "#{orig_exception.backtrace.join("\n")}\n"\ + "Bundler Error Backtrace:\n" + super(full_message) + @orig_exception = orig_exception + end + + status_code(24) + end + + class YamlSyntaxError < BundlerError + attr_reader :orig_exception + + def initialize(orig_exception, msg) + super(msg) + @orig_exception = orig_exception + end + + status_code(25) + end + + class TemporaryResourceError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "Some resource was temporarily unavailable. It's suggested that you try" \ + "the operation again." + end + + status_code(26) + end + + class VirtualProtocolError < BundlerError + def message + "There was an error relating to virtualization and file access. " \ + "It is likely that you need to grant access to or mount some file system correctly." + end + + status_code(27) + end + + class OperationNotSupportedError < PermissionError + def message + "Attempting to #{action} `#{@path}` is unsupported by your OS." + end + + status_code(28) + end + + class NoSpaceOnDeviceError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "There was insufficient space remaining on the device." + end + + status_code(31) + end + + class GenericSystemCallError < BundlerError + attr_reader :underlying_error + + def initialize(underlying_error, message) + @underlying_error = underlying_error + super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") + end + + status_code(32) + end + + class DirectoryRemovalError < BundlerError + def initialize(orig_exception, msg) + full_message = "#{msg}.\n" \ + "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \ + " #{orig_exception.backtrace.join("\n ")}\n\n" \ + "Bundler Error Backtrace:" + super(full_message) + end + + status_code(36) + end + + class InsecureInstallPathError < BundlerError + def initialize(path) + @path = path + end + + def message + "The installation path is insecure. Bundler cannot continue.\n" \ + "#{@path} is world-writable (without sticky bit).\n" \ + "Bundler cannot safely replace gems in world-writeable directories due to potential vulnerabilities.\n" \ + "Please change the permissions of this directory or choose a different install path." + end + + status_code(38) + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/feature_flag.rb b/bin/gems/bundler-2.5.9/lib/bundler/feature_flag.rb new file mode 100644 index 00000000..ab2189f7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/feature_flag.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Bundler + class FeatureFlag + def self.settings_flag(flag, &default) + unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s) + raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key" + end + + settings_method("#{flag}?", flag, &default) + end + private_class_method :settings_flag + + def self.settings_option(key, &default) + settings_method(key, key, &default) + end + private_class_method :settings_option + + def self.settings_method(name, key, &default) + define_method(name) do + value = Bundler.settings[key] + value = instance_eval(&default) if value.nil? + value + end + end + private_class_method :settings_method + + (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } + + settings_flag(:allow_offline_install) { bundler_3_mode? } + settings_flag(:auto_clean_without_path) { bundler_3_mode? } + settings_flag(:cache_all) { bundler_3_mode? } + settings_flag(:default_install_uses_path) { bundler_3_mode? } + settings_flag(:forget_cli_options) { bundler_3_mode? } + settings_flag(:global_gem_cache) { bundler_3_mode? } + settings_flag(:path_relative_to_cwd) { bundler_3_mode? } + settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } + settings_flag(:print_only_version_number) { bundler_3_mode? } + settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } + settings_flag(:update_requires_all_flag) { bundler_4_mode? } + + settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install } + + def initialize(bundler_version) + @bundler_version = Gem::Version.create(bundler_version) + end + + def major_version + @bundler_version.segments.first + end + private :major_version + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher.rb new file mode 100644 index 00000000..6288b22d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher.rb @@ -0,0 +1,324 @@ +# frozen_string_literal: true + +require_relative "vendored_persistent" +require_relative "vendored_timeout" +require "cgi" +require "securerandom" +require "zlib" + +module Bundler + # Handles all the fetching with the rubygems server + class Fetcher + autoload :Base, File.expand_path("fetcher/base", __dir__) + autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__) + autoload :Downloader, File.expand_path("fetcher/downloader", __dir__) + autoload :Dependency, File.expand_path("fetcher/dependency", __dir__) + autoload :Index, File.expand_path("fetcher/index", __dir__) + + # This error is raised when it looks like the network is down + class NetworkDownError < HTTPError; end + # This error is raised if we should rate limit our requests to the API + class TooManyRequestsError < HTTPError; end + # This error is raised if the API returns a 413 (only printed in verbose) + class FallbackError < HTTPError; end + + # This is the error raised if OpenSSL fails the cert verification + class CertificateFailureError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ + " is a chance you are experiencing a man-in-the-middle attack, but" \ + " most likely your system doesn't have the CA certificates needed" \ + " for verification. For information about OpenSSL certificates, see" \ + " https://railsapps.github.io/openssl-certificate-verify-failed.html." + end + end + + # This is the error raised when a source is HTTPS and OpenSSL didn't load + class SSLError < HTTPError + def initialize(msg = nil) + super msg || "Could not load OpenSSL.\n" \ + "You must recompile Ruby with OpenSSL support." + end + end + + # This error is raised if HTTP authentication is required, but not provided. + class AuthenticationRequiredError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Authentication is required for #{remote_uri}.\n" \ + "Please supply credentials for this source. You can do this by running:\n" \ + "`bundle config set --global #{remote_uri} username:password`\n" \ + "or by storing the credentials in the `#{Settings.key_for(remote_uri)}` environment variable" + end + end + + # This error is raised if HTTP authentication is provided, but incorrect. + class BadAuthenticationError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Bad username or password for #{remote_uri}.\n" \ + "Please double-check your credentials and correct them." + end + end + + # This error is raised if HTTP authentication is correct, but lacks + # necessary permissions. + class AuthenticationForbiddenError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Access token could not be authenticated for #{remote_uri}.\n" \ + "Make sure it's valid and has the necessary scopes configured." + end + end + + # Exceptions classes that should bypass retry attempts. If your password didn't work the + # first time, it's not going to the third time. + NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency, + :HTTPForbidden, :HTTPInsufficientStorage, :HTTPMethodNotAllowed, + :HTTPMovedPermanently, :HTTPNoContent, :HTTPNotFound, + :HTTPNotImplemented, :HTTPPreconditionFailed, :HTTPRequestEntityTooLarge, + :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, + :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze + FAIL_ERRORS = begin + fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError] + fail_errors << Gem::Requirement::BadRequirementError + fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) }) + end.freeze + + class << self + attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries + end + + self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request + self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call + self.max_retries = Bundler.settings[:retry] # How many retries for the API call + + def initialize(remote) + @cis = nil + @remote = remote + + Socket.do_not_reverse_lookup = true + connection # create persistent connection + end + + def uri + @remote.anonymized_uri + end + + # fetch a gem specification + def fetch_spec(spec) + spec -= [nil, "ruby", ""] + spec_file_name = "#{spec.join "-"}.gemspec" + + uri = Gem::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") + spec = if uri.scheme == "file" + path = Gem::Util.correct_for_windows_path(uri.path) + Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) + elsif cached_spec_path = gemspec_cached_path(spec_file_name) + Bundler.load_gemspec(cached_spec_path) + else + Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) + end + raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification) + spec + rescue MarshalError + raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ + "Your network or your gem server is probably having issues right now." + end + + # return the specs in the bundler format as an index with retries + def specs_with_retry(gem_names, source) + Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do + specs(gem_names, source) + end + end + + # return the specs in the bundler format as an index + def specs(gem_names, source) + index = Bundler::Index.new + + fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata| + spec = if dependencies + EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es| + source.checksum_store.replace(es, es.checksum) + end + else + RemoteSpecification.new(name, version, platform, self) + end + spec.source = source + spec.remote = @remote + index << spec + end + + index + rescue CertificateFailureError + Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots + raise + end + + def user_agent + @user_agent ||= begin + ruby = Bundler::RubyVersion.system + + agent = String.new("bundler/#{Bundler::VERSION}") + agent << " rubygems/#{Gem::VERSION}" + agent << " ruby/#{ruby.versions_string(ruby.versions)}" + agent << " (#{ruby.host})" + agent << " command/#{ARGV.first}" + + if ruby.engine != "ruby" + # engine_version raises on unknown engines + engine_version = begin + ruby.engine_versions + rescue RuntimeError + "???" + end + agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" + end + + agent << " options/#{Bundler.settings.all.join(",")}" + + agent << " ci/#{cis.join(",")}" if cis.any? + + # add a random ID so we can consolidate runs server-side + agent << " " << SecureRandom.hex(8) + + # add any user agent strings set in the config + extra_ua = Bundler.settings[:user_agent] + agent << " " << extra_ua if extra_ua + + agent + end + end + + def http_proxy + return unless uri = connection.proxy_uri + uri.to_s + end + + def inspect + "#<#{self.class}:0x#{object_id} uri=#{uri}>" + end + + def api_fetcher? + fetchers.first.api_fetcher? + end + + def gem_remote_fetcher + @gem_remote_fetcher ||= begin + require_relative "fetcher/gem_remote_fetcher" + fetcher = GemRemoteFetcher.new Gem.configuration[:http_proxy] + fetcher.headers["User-Agent"] = user_agent + fetcher.headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri + fetcher + end + end + + private + + def available_fetchers + if Bundler::Fetcher.disable_endpoint + [Index] + elsif remote_uri.scheme == "file" + Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API") + [Index] + else + [CompactIndex, Dependency, Index] + end + end + + def fetchers + @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri, gem_remote_fetcher) }.drop_while {|f| !f.available? } + end + + def fetch_specs(gem_names) + fetchers.reject!(&:api_fetcher?) unless gem_names + fetchers.reject! do |f| + specs = f.specs(gem_names) + return specs if specs + true + end + [] + end + + def cis + @cis ||= Bundler::CIDetector.ci_strings + end + + def connection + @connection ||= begin + needs_ssl = remote_uri.scheme == "https" || + Bundler.settings[:ssl_verify_mode] || + Bundler.settings[:ssl_client_cert] + raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) + + con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV + if gem_proxy = Gem.configuration[:http_proxy] + con.proxy = Gem::URI.parse(gem_proxy) if gem_proxy != :no_proxy + end + + if remote_uri.scheme == "https" + con.verify_mode = (Bundler.settings[:ssl_verify_mode] || + OpenSSL::SSL::VERIFY_PEER) + con.cert_store = bundler_cert_store + end + + ssl_client_cert = Bundler.settings[:ssl_client_cert] || + (Gem.configuration.ssl_client_cert if + Gem.configuration.respond_to?(:ssl_client_cert)) + if ssl_client_cert + pem = File.read(ssl_client_cert) + con.cert = OpenSSL::X509::Certificate.new(pem) + con.key = OpenSSL::PKey::RSA.new(pem) + end + + con.read_timeout = Fetcher.api_timeout + con.open_timeout = Fetcher.api_timeout + con.override_headers["User-Agent"] = user_agent + con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri + con + end + end + + # cached gem specification path, if one exists + def gemspec_cached_path(spec_file_name) + paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } + paths.find {|path| File.file? path } + end + + HTTP_ERRORS = [ + Gem::Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, + Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, + Gem::Net::HTTPBadResponse, Gem::Net::HTTPHeaderSyntaxError, Gem::Net::ProtocolError, + Gem::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH + ].freeze + + def bundler_cert_store + store = OpenSSL::X509::Store.new + ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || + (Gem.configuration.ssl_ca_cert if + Gem.configuration.respond_to?(:ssl_ca_cert)) + if ssl_ca_cert + if File.directory? ssl_ca_cert + store.add_path ssl_ca_cert + else + store.add_file ssl_ca_cert + end + else + store.set_default_paths + require "rubygems/request" + Gem::Request.get_cert_files.each {|c| store.add_file c } + end + store + end + + def remote_uri + @remote.uri + end + + def downloader + @downloader ||= Downloader.new(connection, self.class.redirect_limit) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/base.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/base.rb new file mode 100644 index 00000000..cfec2f8e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/base.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Bundler + class Fetcher + class Base + attr_reader :downloader + attr_reader :display_uri + attr_reader :remote + attr_reader :gem_remote_fetcher + + def initialize(downloader, remote, display_uri, gem_remote_fetcher) + raise "Abstract class" if self.class == Base + @downloader = downloader + @remote = remote + @display_uri = display_uri + @gem_remote_fetcher = gem_remote_fetcher + end + + def remote_uri + @remote.uri + end + + def fetch_uri + @fetch_uri ||= if remote_uri.host == "rubygems.org" + uri = remote_uri.dup + uri.host = "index.rubygems.org" + uri + else + remote_uri + end + end + + def available? + true + end + + def api_fetcher? + false + end + + private + + def log_specs(&block) + if Bundler.ui.debug? + Bundler.ui.debug yield + else + Bundler.ui.info ".", false + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/compact_index.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/compact_index.rb new file mode 100644 index 00000000..db914839 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/compact_index.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require_relative "base" +require_relative "../worker" + +module Bundler + autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__) + + class Fetcher + class CompactIndex < Base + def self.compact_index_request(method_name) + method = instance_method(method_name) + undef_method(method_name) + define_method(method_name) do |*args, &blk| + method.bind(self).call(*args, &blk) + rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e + raise HTTPError, e.message + rescue AuthenticationRequiredError, BadAuthenticationError + # Fail since we got a 401 from the server. + raise + rescue HTTPError => e + Bundler.ui.trace(e) + nil + end + end + + def specs(gem_names) + specs_for_names(gem_names) + end + compact_index_request :specs + + def specs_for_names(gem_names) + gem_info = [] + complete_gems = [] + remaining_gems = gem_names.dup + + until remaining_gems.empty? + log_specs { "Looking up gems #{remaining_gems.inspect}" } + + deps = begin + parallel_compact_index_client.dependencies(remaining_gems) + rescue TooManyRequestsError + @bundle_worker&.stop + @bundle_worker = nil # reset it. Not sure if necessary + serial_compact_index_client.dependencies(remaining_gems) + end + next_gems = deps.flat_map {|d| d[3].flat_map(&:first) }.uniq + deps.each {|dep| gem_info << dep } + complete_gems.concat(deps.map(&:first)).uniq! + remaining_gems = next_gems - complete_gems + end + @bundle_worker&.stop + @bundle_worker = nil # reset it. Not sure if necessary + + gem_info + end + + def available? + unless SharedHelpers.md5_available? + Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API") + return nil + end + # Read info file checksums out of /versions, so we can know if gems are up to date + compact_index_client.update_and_parse_checksums! + rescue CompactIndexClient::Updater::MismatchedChecksumError => e + Bundler.ui.debug(e.message) + nil + end + compact_index_request :available? + + def api_fetcher? + true + end + + private + + def compact_index_client + @compact_index_client ||= + SharedHelpers.filesystem_access(cache_path) do + CompactIndexClient.new(cache_path, client_fetcher) + end + end + + def parallel_compact_index_client + compact_index_client.execution_mode = lambda do |inputs, &blk| + func = lambda {|object, _index| blk.call(object) } + worker = bundle_worker(func) + inputs.each {|input| worker.enq(input) } + inputs.map { worker.deq } + end + + compact_index_client + end + + def serial_compact_index_client + compact_index_client.sequential_execution_mode! + compact_index_client + end + + def bundle_worker(func = nil) + @bundle_worker ||= begin + worker_name = "Compact Index (#{display_uri.host})" + Bundler::Worker.new(Bundler.settings.processor_count, worker_name, func) + end + @bundle_worker.tap do |worker| + worker.instance_variable_set(:@func, func) if func + end + end + + def cache_path + Bundler.user_cache.join("compact_index", remote.cache_slug) + end + + def client_fetcher + ClientFetcher.new(self, Bundler.ui) + end + + ClientFetcher = Struct.new(:fetcher, :ui) do + def call(path, headers) + fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) + rescue NetworkDownError => e + raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] + ui.warn "Using the cached data for the new index because of a network error: #{e}" + Gem::Net::HTTPNotModified.new(nil, nil, nil) + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/dependency.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/dependency.rb new file mode 100644 index 00000000..0b807c9a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/dependency.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require_relative "base" +require "cgi" + +module Bundler + class Fetcher + class Dependency < Base + def available? + @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) + rescue NetworkDownError => e + raise HTTPError, e.message + rescue AuthenticationRequiredError + # Fail since we got a 401 from the server. + raise + rescue HTTPError + false + end + + def api_fetcher? + true + end + + def specs(gem_names, full_dependency_list = [], last_spec_list = []) + query_list = gem_names.uniq - full_dependency_list + + log_specs { "Query List: #{query_list.inspect}" } + + return last_spec_list if query_list.empty? + + spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do + dependency_specs(query_list) + end + + returned_gems = spec_list.map(&:first).uniq + specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) + rescue MarshalError, HTTPError, GemspecError + Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over + Bundler.ui.debug "could not fetch from the dependency API, trying the full index" + nil + end + + def dependency_specs(gem_names) + Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" + + gem_list = unmarshalled_dep_gems(gem_names) + get_formatted_specs_and_deps(gem_list) + end + + def unmarshalled_dep_gems(gem_names) + gem_list = [] + gem_names.each_slice(Source::Rubygems::API_REQUEST_SIZE) do |names| + marshalled_deps = downloader.fetch(dependency_api_uri(names)).body + gem_list.concat(Bundler.safe_load_marshal(marshalled_deps)) + end + gem_list + end + + def get_formatted_specs_and_deps(gem_list) + deps_list = [] + spec_list = [] + + gem_list.each do |s| + deps_list.concat(s[:dependencies].map(&:first)) + deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } + spec_list.push([s[:name], s[:number], s[:platform], deps]) + end + [spec_list, deps_list] + end + + def dependency_api_uri(gem_names = []) + uri = fetch_uri + "api/v1/dependencies" + uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? + uri + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/downloader.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/downloader.rb new file mode 100644 index 00000000..868b39b9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/downloader.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +module Bundler + class Fetcher + class Downloader + attr_reader :connection + attr_reader :redirect_limit + + def initialize(connection, redirect_limit) + @connection = connection + @redirect_limit = redirect_limit + end + + def fetch(uri, headers = {}, counter = 0) + raise HTTPError, "Too many redirects" if counter >= redirect_limit + + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + + response = request(uri, headers) + Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") + + case response + when Gem::Net::HTTPSuccess, Gem::Net::HTTPNotModified + response + when Gem::Net::HTTPRedirection + new_uri = Gem::URI.parse(response["location"]) + if new_uri.host == uri.host + new_uri.user = uri.user + new_uri.password = uri.password + end + fetch(new_uri, headers, counter + 1) + when Gem::Net::HTTPRequestedRangeNotSatisfiable + new_headers = headers.dup + new_headers.delete("Range") + new_headers["Accept-Encoding"] = "gzip" + fetch(uri, new_headers) + when Gem::Net::HTTPRequestEntityTooLarge + raise FallbackError, response.body + when Gem::Net::HTTPTooManyRequests + raise TooManyRequestsError, response.body + when Gem::Net::HTTPUnauthorized + raise BadAuthenticationError, uri.host if uri.userinfo + raise AuthenticationRequiredError, uri.host + when Gem::Net::HTTPForbidden + raise AuthenticationForbiddenError, uri.host + when Gem::Net::HTTPNotFound + raise FallbackError, "Gem::Net::HTTPNotFound: #{filtered_uri}" + else + message = "Gem::#{response.class.name.gsub(/\AGem::/, "")}" + message += ": #{response.body}" unless response.body.empty? + raise HTTPError, message + end + end + + def request(uri, headers) + validate_uri_scheme!(uri) + + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + + Bundler.ui.debug "HTTP GET #{filtered_uri}" + req = Gem::Net::HTTP::Get.new uri.request_uri, headers + if uri.user + user = CGI.unescape(uri.user) + password = uri.password ? CGI.unescape(uri.password) : nil + req.basic_auth(user, password) + end + connection.request(uri, req) + rescue OpenSSL::SSL::SSLError + raise CertificateFailureError.new(uri) + rescue *HTTP_ERRORS => e + Bundler.ui.trace e + if e.is_a?(SocketError) || e.message.to_s.include?("host down:") + raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ + "connection and try again." + else + raise HTTPError, "Network error while fetching #{filtered_uri}" \ + " (#{e})" + end + end + + private + + def validate_uri_scheme!(uri) + return if /\Ahttps?\z/.match?(uri.scheme) + raise InvalidOption, + "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ + "Did you mean `http` or `https`?" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/gem_remote_fetcher.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/gem_remote_fetcher.rb new file mode 100644 index 00000000..3fc7b682 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/gem_remote_fetcher.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require "rubygems/remote_fetcher" + +module Bundler + class Fetcher + class GemRemoteFetcher < Gem::RemoteFetcher + def request(*args) + super do |req| + req.delete("User-Agent") if headers["User-Agent"] + yield req if block_given? + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/fetcher/index.rb b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/index.rb new file mode 100644 index 00000000..6e37e1e5 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/fetcher/index.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "base" + +module Bundler + class Fetcher + class Index < Base + def specs(_gem_names) + Bundler.rubygems.fetch_all_remote_specs(remote, gem_remote_fetcher) + rescue Gem::RemoteFetcher::FetchError => e + case e.message + when /certificate verify failed/ + raise CertificateFailureError.new(display_uri) + when /401/ + raise BadAuthenticationError, remote_uri if remote_uri.userinfo + raise AuthenticationRequiredError, remote_uri + when /403/ + raise AuthenticationForbiddenError, remote_uri + else + raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>" + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/force_platform.rb b/bin/gems/bundler-2.5.9/lib/bundler/force_platform.rb new file mode 100644 index 00000000..249a24ec --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/force_platform.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Bundler + module ForcePlatform + private + + # The `:force_ruby_platform` value used by dependencies for resolution, and + # by locked specifications for materialization is `false` by default, except + # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform + # variant unless the name is explicitly allowlisted. + + def default_force_ruby_platform + return false unless RUBY_ENGINE == "truffleruby" + + !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/friendly_errors.rb b/bin/gems/bundler-2.5.9/lib/bundler/friendly_errors.rb new file mode 100644 index 00000000..e61ed644 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/friendly_errors.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require_relative "vendored_thor" + +module Bundler + module FriendlyErrors + module_function + + def enable! + @disabled = false + end + + def disabled? + @disabled + end + + def disable! + @disabled = true + end + + def log_error(error) + case error + when YamlSyntaxError + Bundler.ui.error error.message + Bundler.ui.trace error.orig_exception + when Dsl::DSLError, GemspecError + Bundler.ui.error error.message + when GemRequireError + Bundler.ui.error error.message + Bundler.ui.trace error.orig_exception + when BundlerError + if Bundler.ui.debug? + Bundler.ui.trace error + else + Bundler.ui.error error.message, wrap: true + end + when Thor::Error + Bundler.ui.error error.message + when Interrupt + Bundler.ui.error "\nQuitting..." + Bundler.ui.trace error + when Gem::InvalidSpecificationException + Bundler.ui.error error.message, wrap: true + when SystemExit + when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact + Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ + "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ + "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ + "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." + else request_issue_report_for(error) + end + end + + def exit_status(error) + case error + when BundlerError then error.status_code + when Thor::Error then 15 + when SystemExit then error.status + else 1 + end + end + + def request_issue_report_for(e) + Bundler.ui.error <<~EOS, nil, nil + --- ERROR REPORT TEMPLATE ------------------------------------------------------- + + ``` + #{exception_message(e)} + ``` + + #{Bundler::Env.report} + --- TEMPLATE END ---------------------------------------------------------------- + + EOS + + Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." + + Bundler.ui.error <<~EOS, nil, :yellow + + First, try this link to see if there are any existing issue reports for this error: + #{issues_url(e)} + + If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}, and copy and paste the report template above in there. + EOS + end + + def exception_message(error) + message = serialized_exception_for(error) + cause = error.cause + return message unless cause + + message + serialized_exception_for(cause) + end + + def serialized_exception_for(e) + <<~EOS + #{e.class}: #{e.message} + #{e.backtrace&.join("\n ")&.chomp} + EOS + end + + def issues_url(exception) + message = exception.message.lines.first.tr(":", " ").chomp + message = message.split("-").first if exception.is_a?(Errno) + require "cgi" + "https://github.com/rubygems/rubygems/search?q=" \ + "#{CGI.escape(message)}&type=Issues" + end + + def new_issue_url + "https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md" + end + end + + def self.with_friendly_errors + FriendlyErrors.enable! + yield + rescue SignalException + raise + rescue Exception => e # rubocop:disable Lint/RescueException + raise if FriendlyErrors.disabled? + + FriendlyErrors.log_error(e) + exit FriendlyErrors.exit_status(e) + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/gem_helper.rb b/bin/gems/bundler-2.5.9/lib/bundler/gem_helper.rb new file mode 100644 index 00000000..d535d54f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/gem_helper.rb @@ -0,0 +1,237 @@ +# frozen_string_literal: true + +require_relative "../bundler" +require "shellwords" + +module Bundler + class GemHelper + include Rake::DSL if defined? Rake::DSL + + class << self + # set when install'd. + attr_accessor :instance + + def install_tasks(opts = {}) + new(opts[:dir], opts[:name]).install + end + + def tag_prefix=(prefix) + instance.tag_prefix = prefix + end + + def gemspec(&block) + gemspec = instance.gemspec + block&.call(gemspec) + gemspec + end + end + + attr_reader :spec_path, :base, :gemspec + + attr_writer :tag_prefix + + def initialize(base = nil, name = nil) + @base = File.expand_path(base || SharedHelpers.pwd) + gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base) + raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 + @spec_path = gemspecs.first + @gemspec = Bundler.load_gemspec(@spec_path) + @tag_prefix = "" + end + + def install + built_gem_path = nil + + desc "Build #{name}-#{version}.gem into the pkg directory." + task "build" do + built_gem_path = build_gem + end + + desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory." + task "build:checksum" => "build" do + build_checksum(built_gem_path) + end + + desc "Build and install #{name}-#{version}.gem into system gems." + task "install" => "build" do + install_gem(built_gem_path) + end + + desc "Build and install #{name}-#{version}.gem into system gems without network access." + task "install:local" => "build" do + install_gem(built_gem_path, :local) + end + + desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \ + "To prevent publishing in RubyGems use `gem_push=no rake release`" + task "release", [:remote] => ["build", "release:guard_clean", + "release:source_control_push", "release:rubygem_push"] do + end + + task "release:guard_clean" do + guard_clean + end + + task "release:source_control_push", [:remote] do |_, args| + tag_version { git_push(args[:remote]) } unless already_tagged? + end + + task "release:rubygem_push" => "build" do + rubygem_push(built_gem_path) if gem_push? + end + + GemHelper.instance = self + end + + def build_gem + file_name = nil + sh([*gem_command, "build", "-V", spec_path]) do + file_name = File.basename(built_gem_path) + SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } + FileUtils.mv(built_gem_path, "pkg") + Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." + end + File.join(base, "pkg", file_name) + end + + def install_gem(built_gem_path = nil, local = false) + built_gem_path ||= build_gem + cmd = [*gem_command, "install", built_gem_path.to_s] + cmd << "--local" if local + sh(cmd) + Bundler.ui.confirm "#{name} (#{version}) installed." + end + + def build_checksum(built_gem_path = nil) + built_gem_path ||= build_gem + SharedHelpers.filesystem_access(File.join(base, "checksums")) {|p| FileUtils.mkdir_p(p) } + file_name = "#{File.basename(built_gem_path)}.sha512" + require "digest/sha2" + checksum = ::Digest::SHA512.file(built_gem_path).hexdigest + target = File.join(base, "checksums", file_name) + File.write(target, checksum + "\n") + Bundler.ui.confirm "#{name} #{version} checksum written to checksums/#{file_name}." + end + + protected + + def rubygem_push(path) + cmd = [*gem_command, "push", path] + cmd << "--key" << gem_key if gem_key + cmd << "--host" << allowed_push_host if allowed_push_host + sh_with_input(cmd) + Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" + end + + def built_gem_path + Gem::Util.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last + end + + def git_push(remote = nil) + remote ||= default_remote + sh("git push #{remote} refs/heads/#{current_branch}".shellsplit) + sh("git push #{remote} refs/tags/#{version_tag}".shellsplit) + Bundler.ui.confirm "Pushed git commits and release tag." + end + + def default_remote + remote_for_branch, status = sh_with_status(%W[git config --get branch.#{current_branch}.remote]) + return "origin" unless status.success? + + remote_for_branch.strip + end + + def current_branch + # We can replace this with `git branch --show-current` once we drop support for git < 2.22.0 + sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip + end + + def allowed_push_host + @gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata) + end + + def gem_push_host + env_rubygems_host = ENV["RUBYGEMS_HOST"] + env_rubygems_host = nil if env_rubygems_host&.empty? + + allowed_push_host || env_rubygems_host || "rubygems.org" + end + + def already_tagged? + return false unless sh(%w[git tag]).split(/\n/).include?(version_tag) + Bundler.ui.confirm "Tag #{version_tag} has already been created." + true + end + + def guard_clean + clean? && committed? || raise("There are files that need to be committed first.") + end + + def clean? + sh_with_status(%w[git diff --exit-code])[1].success? + end + + def committed? + sh_with_status(%w[git diff-index --quiet --cached HEAD])[1].success? + end + + def tag_version + sh %W[git tag -m Version\ #{version} #{version_tag}] + Bundler.ui.confirm "Tagged #{version_tag}." + yield if block_given? + rescue RuntimeError + Bundler.ui.error "Untagging #{version_tag} due to error." + sh_with_status %W[git tag -d #{version_tag}] + raise + end + + def version + gemspec.version + end + + def version_tag + "#{@tag_prefix}v#{version}" + end + + def name + gemspec.name + end + + def sh_with_input(cmd) + Bundler.ui.debug(cmd) + SharedHelpers.chdir(base) do + abort unless Kernel.system(*cmd) + end + end + + def sh(cmd, &block) + out, status = sh_with_status(cmd, &block) + unless status.success? + raise("Running `#{cmd.shelljoin}` failed with the following output:\n\n#{out}\n") + end + out + end + + def sh_with_status(cmd, &block) + Bundler.ui.debug(cmd) + SharedHelpers.chdir(base) do + outbuf = IO.popen(cmd, err: [:child, :out], &:read) + status = $? + block&.call(outbuf) if status.success? + [outbuf, status] + end + end + + def gem_key + Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] + end + + def gem_push? + !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) + end + + def gem_command + ENV["GEM_COMMAND"]&.shellsplit || ["gem"] + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/gem_helpers.rb b/bin/gems/bundler-2.5.9/lib/bundler/gem_helpers.rb new file mode 100644 index 00000000..de007523 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/gem_helpers.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +module Bundler + module GemHelpers + GENERIC_CACHE = { Gem::Platform::RUBY => Gem::Platform::RUBY } # rubocop:disable Style/MutableConstant + GENERICS = [ + [Gem::Platform.new("java"), Gem::Platform.new("java")], + [Gem::Platform.new("mswin32"), Gem::Platform.new("mswin32")], + [Gem::Platform.new("mswin64"), Gem::Platform.new("mswin64")], + [Gem::Platform.new("universal-mingw32"), Gem::Platform.new("universal-mingw32")], + [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw32")], + [Gem::Platform.new("x86_64-mingw32"), Gem::Platform.new("x64-mingw32")], + [Gem::Platform.new("x64-mingw-ucrt"), Gem::Platform.new("x64-mingw-ucrt")], + [Gem::Platform.new("mingw32"), Gem::Platform.new("x86-mingw32")], + ].freeze + + def generic(p) + GENERIC_CACHE[p] ||= begin + _, found = GENERICS.find do |match, _generic| + p.os == match.os && (!match.cpu || p.cpu == match.cpu) + end + found || Gem::Platform::RUBY + end + end + module_function :generic + + def generic_local_platform + generic(local_platform) + end + module_function :generic_local_platform + + def local_platform + Bundler.local_platform + end + module_function :local_platform + + def generic_local_platform_is_ruby? + generic_local_platform == Gem::Platform::RUBY + end + module_function :generic_local_platform_is_ruby? + + def platform_specificity_match(spec_platform, user_platform) + spec_platform = Gem::Platform.new(spec_platform) + + PlatformMatch.specificity_score(spec_platform, user_platform) + end + module_function :platform_specificity_match + + def select_best_platform_match(specs, platform) + matching = specs.select {|spec| spec.match_platform(platform) } + + sort_best_platform_match(matching, platform) + end + module_function :select_best_platform_match + + def force_ruby_platform(specs) + matching = specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! } + + sort_best_platform_match(matching, Gem::Platform::RUBY) + end + module_function :force_ruby_platform + + def sort_best_platform_match(matching, platform) + exact = matching.select {|spec| spec.platform == platform } + return exact if exact.any? + + sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) } + exemplary_spec = sorted_matching.first + + sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) } + end + module_function :sort_best_platform_match + + class PlatformMatch + def self.specificity_score(spec_platform, user_platform) + return -1 if spec_platform == user_platform + return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY + + os_match(spec_platform, user_platform) + + cpu_match(spec_platform, user_platform) * 10 + + platform_version_match(spec_platform, user_platform) * 100 + end + + def self.os_match(spec_platform, user_platform) + if spec_platform.os == user_platform.os + 0 + else + 1 + end + end + + def self.cpu_match(spec_platform, user_platform) + if spec_platform.cpu == user_platform.cpu + 0 + elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") + 0 + elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" + 1 + else + 2 + end + end + + def self.platform_version_match(spec_platform, user_platform) + if spec_platform.version == user_platform.version + 0 + elsif spec_platform.version.nil? + 1 + else + 2 + end + end + end + + def same_specificity(platform, spec, exemplary_spec) + platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform) + end + module_function :same_specificity + + def same_deps(spec, exemplary_spec) + same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort + same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version + same_runtime_deps && same_metadata_deps + end + module_function :same_deps + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/gem_tasks.rb b/bin/gems/bundler-2.5.9/lib/bundler/gem_tasks.rb new file mode 100644 index 00000000..bc725d36 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/gem_tasks.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "rake/clean" +CLOBBER.include "pkg" + +require_relative "gem_helper" +Bundler::GemHelper.install_tasks diff --git a/bin/gems/bundler-2.5.9/lib/bundler/gem_version_promoter.rb b/bin/gems/bundler-2.5.9/lib/bundler/gem_version_promoter.rb new file mode 100644 index 00000000..ecc65b49 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/gem_version_promoter.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +module Bundler + # This class contains all of the logic for determining the next version of a + # Gem to update to based on the requested level (patch, minor, major). + # Primarily designed to work with Resolver which will provide it the list of + # available dependency versions as found in its index, before returning it to + # to the resolution engine to select the best version. + class GemVersionPromoter + attr_reader :level + attr_accessor :pre + + # By default, strict is false, meaning every available version of a gem + # is returned from sort_versions. The order gives preference to the + # requested level (:patch, :minor, :major) but in complicated requirement + # cases some gems will by necessity be promoted past the requested level, + # or even reverted to older versions. + # + # If strict is set to true, the results from sort_versions will be + # truncated, eliminating any version outside the current level scope. + # This can lead to unexpected outcomes or even VersionConflict exceptions + # that report a version of a gem not existing for versions that indeed do + # existing in the referenced source. + attr_accessor :strict + + # Creates a GemVersionPromoter instance. + # + # @return [GemVersionPromoter] + def initialize + @level = :major + @strict = false + @pre = false + end + + # @param value [Symbol] One of three Symbols: :major, :minor or :patch. + def level=(value) + v = case value + when String, Symbol + value.to_sym + end + + raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) + @level = v + end + + # Given a Resolver::Package and an Array of Specifications of available + # versions for a gem, this method will return the Array of Specifications + # sorted in an order to give preference to the current level (:major, :minor + # or :patch) when resolution is deciding what versions best resolve all + # dependencies in the bundle. + # @param package [Resolver::Package] The package being resolved. + # @param specs [Specification] An array of Specifications for the package. + # @return [Specification] A new instance of the Specification Array sorted. + def sort_versions(package, specs) + locked_version = package.locked_version + + result = specs.sort do |a, b| + unless package.prerelease_specified? || pre? + a_pre = a.prerelease? + b_pre = b.prerelease? + + next 1 if a_pre && !b_pre + next -1 if b_pre && !a_pre + end + + if major? || locked_version.nil? + b <=> a + elsif either_version_older_than_locked?(a, b, locked_version) + b <=> a + elsif segments_do_not_match?(a, b, :major) + a <=> b + elsif !minor? && segments_do_not_match?(a, b, :minor) + a <=> b + else + b <=> a + end + end + post_sort(result, package.unlock?, locked_version) + end + + # @return [bool] Convenience method for testing value of level variable. + def major? + level == :major + end + + # @return [bool] Convenience method for testing value of level variable. + def minor? + level == :minor + end + + # @return [bool] Convenience method for testing value of pre variable. + def pre? + pre == true + end + + # Given a Resolver::Package and an Array of Specifications of available + # versions for a gem, this method will truncate the Array if strict + # is true. That means filtering out downgrades from the version currently + # locked, and filtering out upgrades that go past the selected level (major, + # minor, or patch). + # @param package [Resolver::Package] The package being resolved. + # @param specs [Specification] An array of Specifications for the package. + # @return [Specification] A new instance of the Specification Array + # truncated. + def filter_versions(package, specs) + return specs unless strict + + locked_version = package.locked_version + return specs if locked_version.nil? || major? + + specs.select do |spec| + gsv = spec.version + + must_match = minor? ? [0] : [0, 1] + + all_match = must_match.all? {|idx| gsv.segments[idx] == locked_version.segments[idx] } + all_match && gsv >= locked_version + end + end + + private + + def either_version_older_than_locked?(a, b, locked_version) + a.version < locked_version || b.version < locked_version + end + + def segments_do_not_match?(a, b, level) + index = [:major, :minor].index(level) + a.segments[index] != b.segments[index] + end + + # Specific version moves can't always reliably be done during sorting + # as not all elements are compared against each other. + def post_sort(result, unlock, locked_version) + # default :major behavior in Bundler does not do this + return result if major? + if unlock || locked_version.nil? + result + else + move_version_to_beginning(result, locked_version) + end + end + + def move_version_to_beginning(result, version) + move, keep = result.partition {|s| s.version.to_s == version.to_s } + move.concat(keep) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/graph.rb b/bin/gems/bundler-2.5.9/lib/bundler/graph.rb new file mode 100644 index 00000000..b22b17a4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/graph.rb @@ -0,0 +1,152 @@ +# frozen_string_literal: true + +require "set" +module Bundler + class Graph + GRAPH_NAME = :Gemfile + + def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = []) + @env = env + @output_file = output_file + @show_version = show_version + @show_requirements = show_requirements + @output_format = output_format + @without_groups = without.map(&:to_sym) + + @groups = [] + @relations = Hash.new {|h, k| h[k] = Set.new } + @node_options = {} + @edge_options = {} + + _populate_relations + end + + attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format + + def viz + GraphVizClient.new(self).run + end + + private + + def _populate_relations + parent_dependencies = _groups.values.to_set.flatten + loop do + break if parent_dependencies.empty? + + tmp = Set.new + parent_dependencies.each do |dependency| + child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set + @relations[dependency.name] += child_dependencies.map(&:name).to_set + tmp += child_dependencies + + @node_options[dependency.name] = _make_label(dependency, :node) + child_dependencies.each do |c_dependency| + @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge) + end + end + parent_dependencies = tmp + end + end + + def _groups + relations = Hash.new {|h, k| h[k] = Set.new } + @env.current_dependencies.each do |dependency| + dependency.groups.each do |group| + next if @without_groups.include?(group) + + relations[group.to_s].add(dependency) + @relations[group.to_s].add(dependency.name) + + @node_options[group.to_s] ||= _make_label(group, :node) + @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge) + end + end + @groups = relations.keys + relations + end + + def _make_label(symbol_or_string_or_dependency, element_type) + case element_type.to_sym + when :node + if symbol_or_string_or_dependency.is_a?(Gem::Dependency) + label = symbol_or_string_or_dependency.name.dup + label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version + else + label = symbol_or_string_or_dependency.to_s + end + when :edge + label = nil + if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements + tmp = symbol_or_string_or_dependency.requirements_list.join(", ") + label = tmp if tmp != ">= 0" + end + else + raise ArgumentError, "2nd argument is invalid" + end + label.nil? ? {} : { label: label } + end + + def spec_for_dependency(dependency) + @env.requested_specs.find {|s| s.name == dependency.name } + end + + class GraphVizClient + def initialize(graph_instance) + @graph_name = graph_instance.class::GRAPH_NAME + @groups = graph_instance.groups + @relations = graph_instance.relations + @node_options = graph_instance.node_options + @edge_options = graph_instance.edge_options + @output_file = graph_instance.output_file + @output_format = graph_instance.output_format + end + + def g + @g ||= ::GraphViz.digraph(@graph_name, concentrate: true, normalize: true, nodesep: 0.55) do |g| + g.edge[:weight] = 2 + g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif" + g.edge[:fontsize] = 12 + end + end + + def run + @groups.each do |group| + g.add_nodes( + group, { + style: "filled", + fillcolor: "#B9B9D5", + shape: "box3d", + fontsize: 16, + }.merge(@node_options[group]) + ) + end + + @relations.each do |parent, children| + children.each do |child| + if @groups.include?(parent) + g.add_nodes(child, { style: "filled", fillcolor: "#B9B9D5" }.merge(@node_options[child])) + g.add_edges(parent, child, { constraint: false }.merge(@edge_options["#{parent}_#{child}"])) + else + g.add_nodes(child, @node_options[child]) + g.add_edges(parent, child, @edge_options["#{parent}_#{child}"]) + end + end + end + + if @output_format.to_s == "debug" + $stdout.puts g.output none: String + Bundler.ui.info "debugging bundle viz..." + else + begin + g.output @output_format.to_sym => "#{@output_file}.#{@output_format}" + Bundler.ui.info "#{@output_file}.#{@output_format}" + rescue ArgumentError => e + warn "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb" + raise e + end + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/index.rb b/bin/gems/bundler-2.5.9/lib/bundler/index.rb new file mode 100644 index 00000000..df46facc --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/index.rb @@ -0,0 +1,205 @@ +# frozen_string_literal: true + +module Bundler + class Index + include Enumerable + + def self.build + i = new + yield i + i + end + + attr_reader :specs, :duplicates, :sources + protected :specs, :duplicates + + RUBY = "ruby" + NULL = "\0" + + def initialize + @sources = [] + @cache = {} + @specs = {} + @duplicates = {} + end + + def initialize_copy(o) + @sources = o.sources.dup + @cache = {} + @specs = {} + @duplicates = {} + + o.specs.each do |name, hash| + @specs[name] = hash.dup + end + o.duplicates.each do |name, array| + @duplicates[name] = array.dup + end + end + + def inspect + "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" + end + + def empty? + each { return false } + true + end + + def search_all(name, &blk) + return enum_for(:search_all, name) unless blk + specs_by_name(name).each(&blk) + @duplicates[name]&.each(&blk) + @sources.each {|source| source.search_all(name, &blk) } + end + + # Search this index's specs, and any source indexes that this index knows + # about, returning all of the results. + def search(query) + results = local_search(query) + return results unless @sources.any? + + @sources.each do |source| + results = safe_concat(results, source.search(query)) + end + results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH + results + end + + alias_method :[], :search + + def local_search(query) + case query + when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) + when String then specs_by_name(query) + when Array then specs_by_name_and_version(*query) + else + raise "You can't search for a #{query.inspect}." + end + end + + def add(spec) + (@specs[spec.name] ||= {}).store(spec.full_name, spec) + end + alias_method :<<, :add + + def each(&blk) + return enum_for(:each) unless blk + specs.values.each do |spec_sets| + spec_sets.values.each(&blk) + end + sources.each {|s| s.each(&blk) } + self + end + + def spec_names + names = specs.keys + sources.map(&:spec_names) + names.uniq! + names + end + + def unmet_dependency_names + dependency_names.select do |name| + search(name).empty? + end + end + + def dependency_names + names = [] + each do |spec| + spec.dependencies.each do |dep| + next if dep.type == :development + names << dep.name + end + end + names.uniq + end + + # Combines indexes proritizing existing specs, like `Hash#reverse_merge!` + # Duplicate specs found in `other` are stored in `@duplicates`. + def use(other) + return unless other + other.each do |spec| + exist?(spec) ? add_duplicate(spec) : add(spec) + end + self + end + + # Combines indexes proritizing specs from `other`, like `Hash#merge!` + # Duplicate specs found in `self` are saved in `@duplicates`. + def merge!(other) + return unless other + other.each do |spec| + if existing = find_by_spec(spec) + add_duplicate(existing) + end + add spec + end + self + end + + def size + @sources.inject(@specs.size) do |size, source| + size += source.size + end + end + + # Whether all the specs in self are in other + def subset?(other) + all? do |spec| + other_spec = other[spec].first + other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source + end + end + + def dependencies_eql?(spec, other_spec) + deps = spec.dependencies.select {|d| d.type != :development } + other_deps = other_spec.dependencies.select {|d| d.type != :development } + deps.sort == other_deps.sort + end + + def add_source(index) + raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) + @sources << index + @sources.uniq! # need to use uniq! here instead of checking for the item before adding + end + + private + + def safe_concat(a, b) + return a if b.empty? + return b if a.empty? + a.concat(b) + end + + def add_duplicate(spec) + (@duplicates[spec.name] ||= []) << spec + end + + def specs_by_name_and_version(name, version) + results = @specs[name]&.values + return EMPTY_SEARCH unless results + results.select! {|spec| spec.version == version } + results + end + + def specs_by_name(name) + @specs[name]&.values || EMPTY_SEARCH + end + + EMPTY_SEARCH = [].freeze + + def search_by_spec(spec) + spec = find_by_spec(spec) + spec ? [spec] : EMPTY_SEARCH + end + + def find_by_spec(spec) + @specs[spec.name]&.fetch(spec.full_name, nil) + end + + def exist?(spec) + @specs[spec.name]&.key?(spec.full_name) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/injector.rb b/bin/gems/bundler-2.5.9/lib/bundler/injector.rb new file mode 100644 index 00000000..cf561c2e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/injector.rb @@ -0,0 +1,287 @@ +# frozen_string_literal: true + +module Bundler + class Injector + INJECTED_GEMS = "injected gems" + + def self.inject(new_deps, options = {}) + injector = new(new_deps, options) + injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) + end + + def self.remove(gems, options = {}) + injector = new(gems, options) + injector.remove(Bundler.default_gemfile, Bundler.default_lockfile) + end + + def initialize(deps, options = {}) + @deps = deps + @options = options + end + + # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency. + # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency. + # @return [Array] + def inject(gemfile_path, lockfile_path) + if Bundler.frozen_bundle? + # ensure the lock and Gemfile are synced + Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) + end + + # temporarily unfreeze + Bundler.settings.temporary(deployment: false, frozen: false) do + # evaluate the Gemfile we have now + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + # don't inject any gems that are already in the Gemfile + @deps -= builder.dependencies + + # add new deps to the end of the in-memory Gemfile + # Set conservative versioning to false because + # we want to let the resolver resolve the version first + builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any? + + # resolve to see if the new deps broke anything + @definition = builder.to_definition(lockfile_path, {}) + @definition.resolve_remotely! + + # since nothing broke, we can add those gems to the gemfile + append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any? + + # since we resolved successfully, write out the lockfile + @definition.lock + + # invalidate the cached Bundler.definition + Bundler.reset_paths! + + # return an array of the deps that we added + @deps + end + end + + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + # @param [Pathname] lockfile_path The lockfile from which to remove dependencies. + # @return [Array] + def remove(gemfile_path, lockfile_path) + # remove gems from each gemfiles we have + Bundler.definition.gemfiles.each do |path| + deps = remove_deps(path) + + show_warning("No gems were removed from the gemfile.") if deps.empty? + + deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep)} was removed." } + end + + # Invalidate the cached Bundler.definition. + # This prevents e.g. `bundle remove ...` from using outdated information. + Bundler.reset_paths! + end + + private + + def conservative_version(spec) + version = spec.version + return ">= 0" if version.nil? + segments = version.segments + seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 + + prerelease_suffix = version.to_s.delete_prefix(version.release.to_s) if version.prerelease? + "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}" + end + + def version_prefix + if @options[:strict] + "= " + elsif @options[:optimistic] + ">= " + else + "~> " + end + end + + def build_gem_lines(conservative_versioning) + @deps.map do |d| + name = d.name.dump + + requirement = if conservative_versioning + ", \"#{conservative_version(@definition.specs[d.name][0])}\"" + else + ", #{d.requirement.as_list.map(&:dump).join(", ")}" + end + + if d.groups != Array(:default) + group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}" + end + + source = ", :source => \"#{d.source}\"" unless d.source.nil? + path = ", :path => \"#{d.path}\"" unless d.path.nil? + git = ", :git => \"#{d.git}\"" unless d.git.nil? + github = ", :github => \"#{d.github}\"" unless d.github.nil? + branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil? + ref = ", :ref => \"#{d.ref}\"" unless d.ref.nil? + require_path = ", :require => #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil? + + %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{require_path}) + end.join("\n") + end + + def append_to(gemfile_path, new_gem_lines) + gemfile_path.open("a") do |f| + f.puts + f.puts new_gem_lines + end + end + + # evaluates a gemfile to remove the specified gem + # from it. + def remove_deps(gemfile_path) + initial_gemfile = File.readlines(gemfile_path) + + Bundler.ui.info "Removing gems from #{gemfile_path}" + + # evaluate the Gemfile we have + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) + + # abort the operation if no gems were removed + # no need to operate on gemfile further + return [] if removed_deps.empty? + + cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) + + SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile) + + # check for errors + # including extra gems being removed + # or some gems not being removed + # and return the actual removed deps + cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile) + end + + # @param [Dsl] builder Dsl object of current Gemfile. + # @param [Array] gems Array of names of gems to be removed. + # @param [Pathname] gemfile_path Path of the Gemfile. + # @return [Array] Array of removed dependencies. + def remove_gems_from_dependencies(builder, gems, gemfile_path) + removed_deps = [] + + gems.each do |gem_name| + deleted_dep = builder.dependencies.find {|d| d.name == gem_name } + + if deleted_dep.nil? + raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed." + end + + builder.dependencies.delete(deleted_dep) + + removed_deps << deleted_dep + end + + removed_deps + end + + # @param [Array] gems Array of names of gems to be removed. + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + def remove_gems_from_gemfile(gems, gemfile_path) + patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/ + new_gemfile = [] + multiline_removal = false + File.readlines(gemfile_path).each do |line| + match_data = line.match(patterns) + if match_data && is_not_within_comment?(line, match_data) + multiline_removal = line.rstrip.end_with?(",") + # skip lines which match the regex + next + end + + # skip followup lines until line does not end with ',' + new_gemfile << line unless multiline_removal + multiline_removal = line.rstrip.end_with?(",") if multiline_removal + end + + # remove line \n and append them with other strings + new_gemfile.each_with_index do |_line, index| + if new_gemfile[index + 1] == "\n" + new_gemfile[index] += new_gemfile[index + 1] + new_gemfile.delete_at(index + 1) + end + end + + %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) } + + new_gemfile.join.chomp + end + + # @param [String] line Individual line of gemfile content. + # @param [MatchData] match_data Data about Regex match. + def is_not_within_comment?(line, match_data) + match_start_index = match_data.offset(0).first + !line[0..match_start_index].include?("#") + end + + # @param [Array] gemfile Array of gemfile contents. + # @param [String] block_name Name of block name to look for. + def remove_nested_blocks(gemfile, block_name) + nested_blocks = 0 + + # count number of nested blocks + gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) } + + while nested_blocks >= 0 + nested_blocks -= 1 + + gemfile.each_with_index do |line, index| + next unless !line.nil? && line.strip.start_with?(block_name) + if /^\s*end\s*$/.match?(gemfile[index + 1]) + gemfile[index] = nil + gemfile[index + 1] = nil + end + end + + gemfile.compact! + end + end + + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + # @param [Array] original_deps Array of original dependencies. + # @param [Array] removed_deps Array of removed dependencies. + # @param [Array] initial_gemfile Contents of original Gemfile before any operation. + def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) + # evaluate the new gemfile to look for any failure cases + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + # record gems which were removed but not requested + extra_removed_gems = original_deps - builder.dependencies + + # if some extra gems were removed then raise error + # and revert Gemfile to original + unless extra_removed_gems.empty? + SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join) + + raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue." + end + + # record gems which could not be removed due to some reasons + errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path } + + show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty? + + # return actual removed dependencies + removed_deps - errored_deps + end + + def show_warning(message) + Bundler.ui.info Bundler.ui.add_color(message, :yellow) + end + + def convert_autorequire(autorequire) + autorequire = autorequire.first + return autorequire if autorequire == "false" + autorequire.inspect + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/inline.rb b/bin/gems/bundler-2.5.9/lib/bundler/inline.rb new file mode 100644 index 00000000..ae4ccf21 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/inline.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Allows for declaring a Gemfile inline in a ruby script, optionally installing +# any gems that aren't already installed on the user's system. +# +# @note Every gem that is specified in this 'Gemfile' will be `require`d, as if +# the user had manually called `Bundler.require`. To avoid a requested gem +# being automatically required, add the `:require => false` option to the +# `gem` dependency declaration. +# +# @param install [Boolean] whether gems that aren't already installed on the +# user's system should be installed. +# Defaults to `false`. +# +# @param gemfile [Proc] a block that is evaluated as a `Gemfile`. +# +# @example Using an inline Gemfile +# +# #!/usr/bin/env ruby +# +# require 'bundler/inline' +# +# gemfile do +# source 'https://rubygems.org' +# gem 'json', require: false +# gem 'nap', require: 'rest' +# gem 'cocoapods', '~> 0.34.1' +# end +# +# puts Pod::VERSION # => "0.34.4" +# +def gemfile(install = false, options = {}, &gemfile) + require_relative "../bundler" + Bundler.reset! + + opts = options.dup + ui = opts.delete(:ui) { Bundler::UI::Shell.new } + ui.level = "silent" if opts.delete(:quiet) || !install + Bundler.ui = ui + raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? + + Bundler.with_unbundled_env do + Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir)) + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" + + Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? + builder = Bundler::Dsl.new + builder.instance_eval(&gemfile) + builder.check_primary_source_safety + + Bundler.settings.temporary(deployment: false, frozen: false) do + definition = builder.to_definition(nil, true) + def definition.lock(*); end + definition.validate_runtime! + + if install || definition.missing_specs? + Bundler.settings.temporary(inline: true, no_install: false) do + installer = Bundler::Installer.install(Bundler.root, definition, system: true) + installer.post_install_messages.each do |name, message| + Bundler.ui.info "Post-install message from #{name}:\n#{message}" + end + end + end + + runtime = Bundler::Runtime.new(nil, definition) + runtime.setup.require + end + end + + if ENV["BUNDLE_GEMFILE"].nil? + ENV["BUNDLE_GEMFILE"] = "" + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/installer.rb new file mode 100644 index 00000000..018324f8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/installer.rb @@ -0,0 +1,267 @@ +# frozen_string_literal: true + +require_relative "worker" +require_relative "installer/parallel_installer" +require_relative "installer/standalone" +require_relative "installer/gem_installer" + +module Bundler + class Installer + class << self + attr_accessor :ambiguous_gems + + Installer.ambiguous_gems = [] + end + + attr_reader :post_install_messages, :definition + + # Begins the installation process for Bundler. + # For more information see the #run method on this class. + def self.install(root, definition, options = {}) + installer = new(root, definition) + Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) + installer.run(options) + Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) + installer + end + + def initialize(root, definition) + @root = root + @definition = definition + @post_install_messages = {} + end + + # Runs the install procedures for a specific Gemfile. + # + # Firstly, this method will check to see if `Bundler.bundle_path` exists + # and if not then Bundler will create the directory. This is usually the same + # location as RubyGems which typically is the `~/.gem` directory + # unless other specified. + # + # Secondly, it checks if Bundler has been configured to be "frozen". + # Frozen ensures that the Gemfile and the Gemfile.lock file are matching. + # This stops a situation where a developer may update the Gemfile but may not run + # `bundle install`, which leads to the Gemfile.lock file not being correctly updated. + # If this file is not correctly updated then any other developer running + # `bundle install` will potentially not install the correct gems. + # + # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. + # If there are no dependencies specified then Bundler returns a warning message stating + # so and this method returns. + # + # Fourthly, Bundler checks if the Gemfile.lock exists, and if so + # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. + # During this step Bundler will also download information about any new gems + # that are not in the Gemfile.lock and resolve any dependencies if needed. + # + # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. + # This then leads into the gems being installed, along with stubs for their executables, + # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set + # earlier. + # + # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time + # that a user runs `bundle install` they will receive any updates from this process. + # + # Finally, if the user has specified the standalone flag, Bundler will generate the needed + # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more + # information. + def run(options) + Bundler.create_bundle_path + + ProcessLock.lock do + if Bundler.frozen_bundle? + @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) + end + + if @definition.dependencies.empty? + Bundler.ui.warn "The Gemfile specifies no dependencies" + lock + return + end + + if resolve_if_needed(options) + ensure_specs_are_compatible! + load_plugins + options.delete(:jobs) + else + options[:jobs] = 1 # to avoid the overhead of Bundler::Worker + end + install(options) + + Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available + + lock + Standalone.new(options[:standalone], @definition).generate if options[:standalone] + end + end + + def generate_bundler_executable_stubs(spec, options = {}) + if options[:binstubs_cmd] && spec.executables.empty? + options = {} + spec.runtime_dependencies.each do |dep| + bins = @definition.specs[dep].first.executables + options[dep.name] = bins unless bins.empty? + end + if options.any? + Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ + "one from a gem it depends on." + options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } + else + Bundler.ui.warn "There are no executables for the gem #{spec.name}." + end + return + end + + # double-assignment to avoid warnings about variables that will be used by ERB + bin_path = Bundler.bin_path + bin_path = bin_path + relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) + relative_gemfile_path = relative_gemfile_path + ruby_command = Thor::Util.ruby_command + ruby_command = ruby_command + template_path = File.expand_path("templates/Executable", __dir__) + if spec.name == "bundler" + template_path += ".bundler" + spec.executables = %(bundle) + end + template = File.read(template_path) + + exists = [] + spec.executables.each do |executable| + binstub_path = "#{bin_path}/#{executable}" + if File.exist?(binstub_path) && !options[:force] + exists << executable + next + end + + mode = Gem.win_platform? ? "wb:UTF-8" : "w" + require "erb" + content = ERB.new(template, trim_mode: "-").result(binding) + + File.write(binstub_path, content, mode: mode, perm: 0o777 & ~File.umask) + if Gem.win_platform? || options[:all_platforms] + prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" + File.write("#{binstub_path}.cmd", prefix + content, mode: mode) + end + end + + if options[:binstubs_cmd] && exists.any? + case exists.size + when 1 + Bundler.ui.warn "Skipped #{exists[0]} since it already exists." + when 2 + Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." + else + items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") + skipped = [items, exists[-1]].compact.join(" and ") + Bundler.ui.warn "Skipped #{skipped} since they already exist." + end + Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." + end + end + + def generate_standalone_bundler_executable_stubs(spec, options = {}) + # double-assignment to avoid warnings about variables that will be used by ERB + bin_path = Bundler.bin_path + unless path = Bundler.settings[:path] + raise "Can't standalone without an explicit path set" + end + standalone_path = Bundler.root.join(path).relative_path_from(bin_path) + standalone_path = standalone_path + template = File.read(File.expand_path("templates/Executable.standalone", __dir__)) + ruby_command = Thor::Util.ruby_command + ruby_command = ruby_command + + spec.executables.each do |executable| + next if executable == "bundle" + executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) + executable_path = executable_path + + mode = Gem.win_platform? ? "wb:UTF-8" : "w" + require "erb" + content = ERB.new(template, trim_mode: "-").result(binding) + + File.write("#{bin_path}/#{executable}", content, mode: mode, perm: 0o755) + if Gem.win_platform? || options[:all_platforms] + prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" + File.write("#{bin_path}/#{executable}.cmd", prefix + content, mode: mode) + end + end + end + + private + + # the order that the resolver provides is significant, since + # dependencies might affect the installation of a gem. + # that said, it's a rare situation (other than rake), and parallel + # installation is SO MUCH FASTER. so we let people opt in. + def install(options) + force = options["force"] + jobs = installation_parallelization(options) + install_in_parallel jobs, options[:standalone], force + end + + def installation_parallelization(options) + if jobs = options.delete(:jobs) + return jobs + end + + if jobs = Bundler.settings[:jobs] + return jobs + end + + Bundler.settings.processor_count + end + + def load_plugins + Gem.load_plugins + + requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) } + path_plugin_files = requested_path_gems.map do |spec| + Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}") + rescue TypeError + error_message = "#{spec.name} #{spec.version} has an invalid gemspec" + raise Gem::InvalidSpecificationException, error_message + end.flatten + Gem.load_plugin_files(path_plugin_files) + Gem.load_env_plugins + end + + def ensure_specs_are_compatible! + @definition.specs.each do |spec| + unless spec.matches_current_ruby? + raise InstallError, "#{spec.full_name} requires ruby version #{spec.required_ruby_version}, " \ + "which is incompatible with the current version, #{Gem.ruby_version}" + end + unless spec.matches_current_rubygems? + raise InstallError, "#{spec.full_name} requires rubygems version #{spec.required_rubygems_version}, " \ + "which is incompatible with the current version, #{Gem.rubygems_version}" + end + end + end + + def install_in_parallel(size, standalone, force = false) + spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force) + spec_installations.each do |installation| + post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? + end + end + + # returns whether or not a re-resolve was needed + def resolve_if_needed(options) + @definition.resolution_mode = options + + if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? + return false if @definition.nothing_changed? && !@definition.missing_specs? + end + + @definition.setup_sources_for_resolve + + true + end + + def lock + @definition.lock + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/installer/gem_installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/installer/gem_installer.rb new file mode 100644 index 00000000..d3bbcc90 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/installer/gem_installer.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module Bundler + class GemInstaller + attr_reader :spec, :standalone, :worker, :force, :installer + + def initialize(spec, installer, standalone = false, worker = 0, force = false) + @spec = spec + @installer = installer + @standalone = standalone + @worker = worker + @force = force + end + + def install_from_spec + post_install_message = install + Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}" + generate_executable_stubs + [true, post_install_message] + rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError, Bundler::InsecureInstallPathError + raise + rescue Errno::ENOSPC + [false, out_of_space_message] + rescue Bundler::BundlerError, Gem::InstallError => e + [false, specific_failure_message(e)] + end + + private + + def specific_failure_message(e) + message = "#{e.class}: #{e.message}\n" + message += " " + e.backtrace.join("\n ") + "\n\n" + message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear) + message + Bundler.ui.add_color(failure_message, :red) + end + + def failure_message + install_error_message + end + + def install_error_message + "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue." + end + + def spec_settings + # Fetch the build settings, if there are any + if settings = Bundler.settings["build.#{spec.name}"] + require "shellwords" + Shellwords.shellsplit(settings) + end + end + + def install + spec.source.install( + spec, + force: force, + ensure_builtin_gems_cached: standalone, + build_args: Array(spec_settings), + previous_spec: previous_spec, + ) + end + + def previous_spec + locked_gems = installer.definition.locked_gems + return unless locked_gems + + locked_gems.specs.find {|s| s.name == spec.name } + end + + def out_of_space_message + "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle." + end + + def generate_executable_stubs + return if Bundler.feature_flag.forget_cli_options? + return if Bundler.settings[:inline] + if Bundler.settings[:bin] && standalone + installer.generate_standalone_bundler_executable_stubs(spec) + elsif Bundler.settings[:bin] + installer.generate_bundler_executable_stubs(spec, force: true) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/installer/parallel_installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/installer/parallel_installer.rb new file mode 100644 index 00000000..e745088f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/installer/parallel_installer.rb @@ -0,0 +1,202 @@ +# frozen_string_literal: true + +require_relative "../worker" +require_relative "gem_installer" + +module Bundler + class ParallelInstaller + class SpecInstallation + attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error + def initialize(spec) + @spec = spec + @name = spec.name + @full_name = spec.full_name + @state = :none + @post_install_message = "" + @error = nil + end + + def installed? + state == :installed + end + + def enqueued? + state == :enqueued + end + + def failed? + state == :failed + end + + def ready_to_enqueue? + state == :none + end + + def has_post_install_message? + !post_install_message.empty? + end + + def ignorable_dependency?(dep) + dep.type == :development || dep.name == @name + end + + # Checks installed dependencies against spec's dependencies to make + # sure needed dependencies have been installed. + def dependencies_installed?(installed_specs) + dependencies.all? {|d| installed_specs.include? d.name } + end + + # Represents only the non-development dependencies, the ones that are + # itself and are in the total list. + def dependencies + @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep } + end + + # Represents all dependencies + def all_dependencies + @spec.dependencies + end + + def to_s + "#<#{self.class} #{full_name} (#{state})>" + end + end + + def self.call(*args, **kwargs) + new(*args, **kwargs).call + end + + attr_reader :size + + def initialize(installer, all_specs, size, standalone, force, skip: nil) + @installer = installer + @size = size + @standalone = standalone + @force = force + @specs = all_specs.map {|s| SpecInstallation.new(s) } + @specs.each do |spec_install| + spec_install.state = :installed if skip.include?(spec_install.name) + end if skip + @spec_set = all_specs + @rake = @specs.find {|s| s.name == "rake" unless s.installed? } + end + + def call + if @rake + do_install(@rake, 0) + Gem::Specification.reset + end + + if @size > 1 + install_with_worker + else + install_serially + end + + handle_error if failed_specs.any? + @specs + ensure + worker_pool&.stop + end + + private + + def failed_specs + @specs.select(&:failed?) + end + + def install_with_worker + enqueue_specs + process_specs until finished_installing? + end + + def install_serially + until finished_installing? + raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?) + spec_install.state = :enqueued + do_install(spec_install, 0) + end + end + + def worker_pool + @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num| + do_install(spec_install, worker_num) + } + end + + def do_install(spec_install, worker_num) + Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install) + gem_installer = Bundler::GemInstaller.new( + spec_install.spec, @installer, @standalone, worker_num, @force + ) + success, message = gem_installer.install_from_spec + if success + spec_install.state = :installed + spec_install.post_install_message = message unless message.nil? + else + spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" + spec_install.state = :failed + end + Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL, spec_install) + spec_install + end + + # Dequeue a spec and save its post-install message and then enqueue the + # remaining specs. + # Some specs might've had to wait til this spec was installed to be + # processed so the call to `enqueue_specs` is important after every + # dequeue. + def process_specs + worker_pool.deq + enqueue_specs + end + + def finished_installing? + @specs.all? do |spec| + return true if spec.failed? + spec.installed? + end + end + + def handle_error + errors = failed_specs.map(&:error) + if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) } + raise exception + end + raise Bundler::InstallError, errors.join("\n\n") + end + + def require_tree_for_spec(spec) + tree = @spec_set.what_required(spec) + t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n") + tree.each_with_index do |s, depth| + t << " " * depth.succ << s.name + unless tree.last == s + t << %( was resolved to #{s.version}, which depends on) + end + t << %(\n) + end + t + end + + # Keys in the remains hash represent uninstalled gems specs. + # We enqueue all gem specs that do not have any dependencies. + # Later we call this lambda again to install specs that depended on + # previously installed specifications. We continue until all specs + # are installed. + def enqueue_specs + installed_specs = {} + @specs.each do |spec| + next unless spec.installed? + installed_specs[spec.name] = true + end + + @specs.each do |spec| + if spec.ready_to_enqueue? && spec.dependencies_installed?(installed_specs) + spec.state = :enqueued + worker_pool.enq spec + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/installer/standalone.rb b/bin/gems/bundler-2.5.9/lib/bundler/installer/standalone.rb new file mode 100644 index 00000000..5331df2e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/installer/standalone.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module Bundler + class Standalone + def initialize(groups, definition) + @specs = definition.specs_for(groups) + end + + def generate + SharedHelpers.filesystem_access(bundler_path) do |p| + FileUtils.mkdir_p(p) + end + File.open File.join(bundler_path, "setup.rb"), "w" do |file| + file.puts "require 'rbconfig'" + file.puts prevent_gem_activation + file.puts define_path_helpers + file.puts reverse_rubygems_kernel_mixin + paths.each do |path| + if Pathname.new(path).absolute? + file.puts %($:.unshift "#{path}") + else + file.puts %($:.unshift File.expand_path("\#{__dir__}/#{path}")) + end + end + end + end + + private + + def paths + @specs.map do |spec| + next if spec.name == "bundler" + Array(spec.require_paths).map do |path| + gem_path(path, spec). + sub(version_dir, '#{RUBY_ENGINE}/#{Gem.ruby_api_version}'). + sub(extensions_dir, 'extensions/\k/#{Gem.extension_api_version}') + # This is a static string intentionally. It's interpolated at a later time. + end + end.flatten.compact + end + + def version_dir + "#{RUBY_ENGINE}/#{Gem.ruby_api_version}" + end + + def extensions_dir + %r{extensions/(?[^/]+)/#{Regexp.escape(Gem.extension_api_version)}} + end + + def bundler_path + Bundler.root.join(Bundler.settings[:path].to_s, "bundler") + end + + def gem_path(path, spec) + full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) + if spec.source.instance_of?(Source::Path) && spec.source.path.absolute? + full_path + else + SharedHelpers.relative_path_to(full_path, from: Bundler.root.join(bundler_path)) + end + rescue TypeError + error_message = "#{spec.name} #{spec.version} has an invalid gemspec" + raise Gem::InvalidSpecificationException.new(error_message) + end + + def prevent_gem_activation + <<~'END' + module Kernel + remove_method(:gem) if private_method_defined?(:gem) + + def gem(*) + end + + private :gem + end + END + end + + def define_path_helpers + <<~'END' + unless defined?(Gem) + module Gem + def self.ruby_api_version + RbConfig::CONFIG["ruby_version"] + end + + def self.extension_api_version + if 'no' == RbConfig::CONFIG['ENABLE_SHARED'] + "#{ruby_api_version}-static" + else + ruby_api_version + end + end + end + end + END + end + + def reverse_rubygems_kernel_mixin + <<~END + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + [::Kernel.singleton_class, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + private_require = k.private_method_defined?(:require) + k.send(:remove_method, :require) + k.send(:define_method, :require, k.instance_method(:gem_original_require)) + k.send(:private, :require) if private_require + end + end + end + END + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/lazy_specification.rb b/bin/gems/bundler-2.5.9/lib/bundler/lazy_specification.rb new file mode 100644 index 00000000..38aea2a4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/lazy_specification.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +require_relative "force_platform" + +module Bundler + class LazySpecification + include MatchPlatform + include ForcePlatform + + attr_reader :name, :version, :platform + attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version + + alias_method :runtime_dependencies, :dependencies + + def self.from_spec(s) + lazy_spec = new(s.name, s.version, s.platform, s.source) + lazy_spec.dependencies = s.dependencies + lazy_spec.required_ruby_version = s.required_ruby_version + lazy_spec.required_rubygems_version = s.required_rubygems_version + lazy_spec + end + + def initialize(name, version, platform, source = nil) + @name = name + @version = version + @dependencies = [] + @required_ruby_version = Gem::Requirement.default + @required_rubygems_version = Gem::Requirement.default + @platform = platform || Gem::Platform::RUBY + @source = source + @force_ruby_platform = default_force_ruby_platform + end + + def full_name + @full_name ||= if platform == Gem::Platform::RUBY + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{platform}" + end + end + + def lock_name + @lock_name ||= name_tuple.lock_name + end + + def name_tuple + Gem::NameTuple.new(@name, @version, @platform) + end + + def ==(other) + full_name == other.full_name + end + + def eql?(other) + full_name.eql?(other.full_name) + end + + def hash + full_name.hash + end + + ## + # Does this locked specification satisfy +dependency+? + # + # NOTE: Rubygems default requirement is ">= 0", which doesn't match + # prereleases of 0 versions, like "0.0.0.dev" or "0.0.0.SNAPSHOT". However, + # bundler users expect those to work. We need to make sure that Gemfile + # dependencies without explicit requirements (which use ">= 0" under the + # hood by default) are still valid for locked specs using this kind of + # versions. The method implements an ad-hoc fix for that. A better solution + # might be to change default rubygems requirement of dependencies to be ">= + # 0.A" but that's a major refactoring likely to break things. Hopefully we + # can attempt it in the future. + # + + def satisfies?(dependency) + effective_requirement = dependency.requirement == Gem::Requirement.default ? Gem::Requirement.new(">= 0.A") : dependency.requirement + + @name == dependency.name && effective_requirement.satisfied_by?(Gem::Version.new(@version)) + end + + def to_lock + out = String.new + out << " #{lock_name}\n" + + dependencies.sort_by(&:to_s).uniq.each do |dep| + next if dep.type == :development + out << " #{dep.to_lock}\n" + end + + out + end + + def materialize_for_installation + source.local! + + matching_specs = source.specs.search(use_exact_resolved_specifications? ? self : [name, version]) + return self if matching_specs.empty? + + candidates = if use_exact_resolved_specifications? + matching_specs + else + target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform + + installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform) + + specification = __materialize__(installable_candidates, fallback_to_non_installable: false) + return specification unless specification.nil? + + if target_platform != platform + installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform) + end + + installable_candidates + end + + __materialize__(candidates) + end + + # If in frozen mode, we fallback to a non-installable candidate because by + # doing this we avoid re-resolving and potentially end up changing the + # lock file, which is not allowed. In that case, we will give a proper error + # about the mismatch higher up the stack, right before trying to install the + # bad gem. + def __materialize__(candidates, fallback_to_non_installable: Bundler.frozen_bundle?) + search = candidates.reverse.find do |spec| + spec.is_a?(StubSpecification) || spec.matches_current_metadata? + end + if search.nil? && fallback_to_non_installable + search = candidates.last + else + search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) + end + search + end + + def to_s + lock_name + end + + def git_version + return unless source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + def force_ruby_platform! + @force_ruby_platform = true + end + + private + + def use_exact_resolved_specifications? + @use_exact_resolved_specifications ||= !source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform? + end + + # + # For backwards compatibility with existing lockfiles, if the most specific + # locked platform is not a specific platform like x86_64-linux or + # universal-java-11, then we keep the previous behaviour of resolving the + # best platform variant at materiliazation time. For previous bundler + # versions (before 2.2.0) this was always the case (except when the lockfile + # only included non-ruby platforms), but we're also keeping this behaviour + # on newer bundlers unless users generate the lockfile from scratch or + # explicitly add a more specific platform. + # + def ruby_platform_materializes_to_ruby_platform? + generic_platform = generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY + + !Bundler.most_specific_locked_platform?(generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform] + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/lockfile_generator.rb b/bin/gems/bundler-2.5.9/lib/bundler/lockfile_generator.rb new file mode 100644 index 00000000..a646d00e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/lockfile_generator.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module Bundler + class LockfileGenerator + attr_reader :definition + attr_reader :out + + # @private + def initialize(definition) + @definition = definition + @out = String.new + end + + def self.generate(definition) + new(definition).generate! + end + + def generate! + add_sources + add_platforms + add_dependencies + add_checksums + add_locked_ruby_version + add_bundled_with + + out + end + + private + + def add_sources + definition.send(:sources).lock_sources.each_with_index do |source, idx| + out << "\n" unless idx.zero? + + # Add the source header + out << source.to_lock + + # Find all specs for this source + specs = definition.resolve.select {|s| source.can_lock?(s) } + add_specs(specs) + end + end + + def add_specs(specs) + # This needs to be sorted by full name so that + # gems with the same name, but different platform + # are ordered consistently + specs.sort_by(&:full_name).each do |spec| + next if spec.name == "bundler" + out << spec.to_lock + end + end + + def add_platforms + add_section("PLATFORMS", definition.platforms) + end + + def add_dependencies + out << "\nDEPENDENCIES\n" + + handled = [] + definition.dependencies.sort_by(&:to_s).each do |dep| + next if handled.include?(dep.name) + out << dep.to_lock << "\n" + handled << dep.name + end + end + + def add_checksums + return unless definition.locked_checksums + checksums = definition.resolve.map do |spec| + spec.source.checksum_store.to_lock(spec) + end + add_section("CHECKSUMS", checksums) + end + + def add_locked_ruby_version + return unless locked_ruby_version = definition.locked_ruby_version + add_section("RUBY VERSION", locked_ruby_version.to_s) + end + + def add_bundled_with + add_section("BUNDLED WITH", definition.bundler_version_to_lock.to_s) + end + + def add_section(name, value) + out << "\n#{name}\n" + case value + when Array + value.map(&:to_s).sort.each do |val| + out << " #{val}\n" + end + when Hash + value.to_a.sort_by {|k, _| k.to_s }.each do |key, val| + out << " #{key}: #{val}\n" + end + when String + out << " #{value}\n" + else + raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/lockfile_parser.rb b/bin/gems/bundler-2.5.9/lib/bundler/lockfile_parser.rb new file mode 100644 index 00000000..1e11621e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/lockfile_parser.rb @@ -0,0 +1,289 @@ +# frozen_string_literal: true + +module Bundler + class LockfileParser + class Position + attr_reader :line, :column + def initialize(line, column) + @line = line + @column = column + end + + def advance!(string) + lines = string.count("\n") + if lines > 0 + @line += lines + @column = string.length - string.rindex("\n") + else + @column += string.length + end + end + + def to_s + "#{line}:#{column}" + end + end + + attr_reader( + :sources, + :dependencies, + :specs, + :platforms, + :bundler_version, + :ruby_version, + :checksums, + ) + + BUNDLED = "BUNDLED WITH" + DEPENDENCIES = "DEPENDENCIES" + CHECKSUMS = "CHECKSUMS" + PLATFORMS = "PLATFORMS" + RUBY = "RUBY VERSION" + GIT = "GIT" + GEM = "GEM" + PATH = "PATH" + PLUGIN = "PLUGIN SOURCE" + SPECS = " specs:" + OPTIONS = /^ ([a-z]+): (.*)$/i + SOURCE = [GIT, GEM, PATH, PLUGIN].freeze + + SECTIONS_BY_VERSION_INTRODUCED = { + Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, + Gem::Version.create("1.10") => [BUNDLED].freeze, + Gem::Version.create("1.12") => [RUBY].freeze, + Gem::Version.create("1.13") => [PLUGIN].freeze, + Gem::Version.create("2.5.0") => [CHECKSUMS].freeze, + }.freeze + + KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze + + ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze + deprecate_constant(:ENVIRONMENT_VERSION_SECTIONS) + + def self.sections_in_lockfile(lockfile_contents) + sections = lockfile_contents.scan(/^\w[\w ]*$/) + sections.uniq! + sections + end + + def self.unknown_sections_in_lockfile(lockfile_contents) + sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS + end + + def self.sections_to_ignore(base_version = nil) + base_version &&= base_version.release + base_version ||= Gem::Version.create("1.0") + attributes = [] + SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced| + next if version <= base_version + attributes += introduced + end + attributes + end + + def self.bundled_with + lockfile = Bundler.default_lockfile + return unless lockfile.file? + + lockfile_contents = Bundler.read_file(lockfile) + return unless lockfile_contents.include?(BUNDLED) + + lockfile_contents.split(BUNDLED).last.strip + end + + def initialize(lockfile) + @platforms = [] + @sources = [] + @dependencies = {} + @parse_method = nil + @specs = {} + @lockfile_path = begin + SharedHelpers.relative_lockfile_path + rescue GemfileNotFound + "Gemfile.lock" + end + @pos = Position.new(1, 1) + + if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) + raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \ + "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock." + end + + lockfile.split(/((?:\r?\n)+)/) do |line| + # split alternates between the line and the following whitespace + next @pos.advance!(line) if line.match?(/^\s*$/) + + if SOURCE.include?(line) + @parse_method = :parse_source + parse_source(line) + elsif line == DEPENDENCIES + @parse_method = :parse_dependency + elsif line == CHECKSUMS + # This is a temporary solution to make this feature disabled by default + # for all gemfiles that don't already explicitly include the feature. + @checksums = true + @parse_method = :parse_checksum + elsif line == PLATFORMS + @parse_method = :parse_platform + elsif line == RUBY + @parse_method = :parse_ruby + elsif line == BUNDLED + @parse_method = :parse_bundled_with + elsif /^[^\s]/.match?(line) + @parse_method = nil + elsif @parse_method + send(@parse_method, line) + end + @pos.advance!(line) + end + @specs = @specs.values.sort_by!(&:full_name) + rescue ArgumentError => e + Bundler.ui.debug(e) + raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \ + "and then `bundle install` to generate a new lockfile. The error occurred while " \ + "evaluating #{@lockfile_path}:#{@pos}" + end + + def may_include_redundant_platform_specific_gems? + bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2") + end + + private + + TYPES = { + GIT => Bundler::Source::Git, + GEM => Bundler::Source::Rubygems, + PATH => Bundler::Source::Path, + PLUGIN => Bundler::Plugin, + }.freeze + + def parse_source(line) + case line + when SPECS + return unless TYPES.key?(@type) + @current_source = TYPES[@type].from_lock(@opts) + @sources << @current_source + when OPTIONS + value = $2 + value = true if value == "true" + value = false if value == "false" + + key = $1 + + if @opts[key] + @opts[key] = Array(@opts[key]) + @opts[key] << value + else + @opts[key] = value + end + when *SOURCE + @current_source = nil + @opts = {} + @type = line + else + parse_spec(line) + end + end + + space = / / + NAME_VERSION = / + ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line + (.*?) # Name + (?:#{space}\(([^-]*) # Space, followed by version + (?:-(.*))?\))? # Optional platform + (!)? # Optional pinned marker + (?:#{space}([^ ]+))? # Optional checksum + $ # Line end + /xo + + def parse_dependency(line) + return unless line =~ NAME_VERSION + spaces = $1 + return unless spaces.size == 2 + name = -$2 + version = $3 + pinned = $5 + + version = version.split(",").each(&:strip!) if version + + dep = Bundler::Dependency.new(name, version) + + if pinned && dep.name != "bundler" + spec = @specs.find {|_, v| v.name == dep.name } + dep.source = spec.last.source if spec + + # Path sources need to know what the default name / version + # to use in the case that there are no gemspecs present. A fake + # gemspec is created based on the version set on the dependency + # TODO: Use the version from the spec instead of from the dependency + if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) + dep.source.name = name + dep.source.version = $1 + end + end + + @dependencies[dep.name] = dep + end + + def parse_checksum(line) + return unless line =~ NAME_VERSION + + spaces = $1 + return unless spaces.size == 2 + checksums = $6 + return unless checksums + name = $2 + version = $3 + platform = $4 + + version = Gem::Version.new(version) + platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + full_name = Gem::NameTuple.new(name, version, platform).full_name + return unless spec = @specs[full_name] + + checksums.split(",") do |lock_checksum| + column = line.index(lock_checksum) + 1 + checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}") + spec.source.checksum_store.register(spec, checksum) + end + end + + def parse_spec(line) + return unless line =~ NAME_VERSION + spaces = $1 + name = -$2 + version = $3 + + if spaces.size == 4 + # only load platform for non-dependency (spec) line + platform = $4 + + version = Gem::Version.new(version) + platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + @current_spec = LazySpecification.new(name, version, platform, @current_source) + @current_source.add_dependency_names(name) + + @specs[@current_spec.full_name] = @current_spec + elsif spaces.size == 6 + version = version.split(",").each(&:strip!) if version + dep = Gem::Dependency.new(name, version) + @current_spec.dependencies << dep + end + end + + def parse_platform(line) + @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/ + end + + def parse_bundled_with(line) + line.strip! + return unless Gem::Version.correct?(line) + @bundler_version = Gem::Version.create(line) + end + + def parse_ruby(line) + line.strip! + @ruby_version = line + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/.document b/bin/gems/bundler-2.5.9/lib/bundler/man/.document new file mode 100644 index 00000000..fb66f13c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/.document @@ -0,0 +1 @@ +# Ignore all files in this directory diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1 new file mode 100644 index 00000000..a6cbc88f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1 @@ -0,0 +1,59 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-ADD" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install +.SH "SYNOPSIS" +\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT] [\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-skip\-install] [\-\-strict] [\-\-optimistic] +.SH "DESCRIPTION" +Adds the named gem to the Gemfile and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\. +.P +Example: +.P +bundle add rails +.P +bundle add rails \-\-version "< 3\.0, > 1\.1" +.P +bundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development" +.P +bundle add rails \-\-skip\-install +.P +bundle add rails \-\-group "development, test" +.SH "OPTIONS" +.TP +\fB\-\-version\fR, \fB\-v\fR +Specify version requirements(s) for the added gem\. +.TP +\fB\-\-group\fR, \fB\-g\fR +Specify the group(s) for the added gem\. Multiple groups should be separated by commas\. +.TP +\fB\-\-source\fR, \fB\-s\fR +Specify the source for the added gem\. +.TP +\fB\-\-require\fR, \fB\-r\fR +Adds require path to gem\. Provide false, or a path as a string\. +.TP +\fB\-\-path\fR +Specify the file system path for the added gem\. +.TP +\fB\-\-git\fR +Specify the git source for the added gem\. +.TP +\fB\-\-github\fR +Specify the github source for the added gem\. +.TP +\fB\-\-branch\fR +Specify the git branch for the added gem\. +.TP +\fB\-\-ref\fR +Specify the git ref for the added gem\. +.TP +\fB\-\-skip\-install\fR +Adds the gem to the Gemfile but does not install it\. +.TP +\fB\-\-optimistic\fR +Adds optimistic declaration of version\. +.TP +\fB\-\-strict\fR +Adds strict declaration of version\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1.ronn new file mode 100644 index 00000000..37c92e5f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-add.1.ronn @@ -0,0 +1,58 @@ +bundle-add(1) -- Add gem to the Gemfile and run bundle install +================================================================ + +## SYNOPSIS + +`bundle add` [--group=GROUP] [--version=VERSION] [--source=SOURCE] [--path=PATH] [--git=GIT] [--github=GITHUB] [--branch=BRANCH] [--ref=REF] [--skip-install] [--strict] [--optimistic] + +## DESCRIPTION +Adds the named gem to the Gemfile and run `bundle install`. `bundle install` can be avoided by using the flag `--skip-install`. + +Example: + +bundle add rails + +bundle add rails --version "< 3.0, > 1.1" + +bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development" + +bundle add rails --skip-install + +bundle add rails --group "development, test" + +## OPTIONS +* `--version`, `-v`: + Specify version requirements(s) for the added gem. + +* `--group`, `-g`: + Specify the group(s) for the added gem. Multiple groups should be separated by commas. + +* `--source`, `-s`: + Specify the source for the added gem. + +* `--require`, `-r`: + Adds require path to gem. Provide false, or a path as a string. + +* `--path`: + Specify the file system path for the added gem. + +* `--git`: + Specify the git source for the added gem. + +* `--github`: + Specify the github source for the added gem. + +* `--branch`: + Specify the git branch for the added gem. + +* `--ref`: + Specify the git ref for the added gem. + +* `--skip-install`: + Adds the gem to the Gemfile but does not install it. + +* `--optimistic`: + Adds optimistic declaration of version. + +* `--strict`: + Adds strict declaration of version. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1 new file mode 100644 index 00000000..2b35bc95 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1 @@ -0,0 +1,30 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-BINSTUBS" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems +.SH "SYNOPSIS" +\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone] +.SH "DESCRIPTION" +Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\. +.P +For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\. +.P +This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\. +.SH "OPTIONS" +.TP +\fB\-\-force\fR +Overwrite existing binstubs if they exist\. +.TP +\fB\-\-path\fR +The location to install the specified binstubs to\. This defaults to \fBbin\fR\. +.TP +\fB\-\-standalone\fR +Makes binstubs that can work without depending on Rubygems or Bundler at runtime\. +.TP +\fB\-\-shebang\fR +Specify a different shebang executable name than the default (default 'ruby') +.TP +\fB\-\-all\fR +Create binstubs for all gems in the bundle\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1.ronn new file mode 100644 index 00000000..a9618692 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-binstubs.1.ronn @@ -0,0 +1,41 @@ +bundle-binstubs(1) -- Install the binstubs of the listed gems +============================================================= + +## SYNOPSIS + +`bundle binstubs` [--force] [--path PATH] [--standalone] + +## DESCRIPTION + +Binstubs are scripts that wrap around executables. Bundler creates a +small Ruby file (a binstub) that loads Bundler, runs the command, +and puts it into `bin/`. Binstubs are a shortcut-or alternative- +to always using `bundle exec`. This gives you a file that can be run +directly, and one that will always run the correct gem version +used by the application. + +For example, if you run `bundle binstubs rspec-core`, Bundler will create +the file `bin/rspec`. That file will contain enough code to load Bundler, +tell it to load the bundled gems, and then run rspec. + +This command generates binstubs for executables in `GEM_NAME`. +Binstubs are put into `bin`, or the `--path` directory if one has been set. +Calling binstubs with [GEM [GEM]] will create binstubs for all given gems. + +## OPTIONS + +* `--force`: + Overwrite existing binstubs if they exist. + +* `--path`: + The location to install the specified binstubs to. This defaults to `bin`. + +* `--standalone`: + Makes binstubs that can work without depending on Rubygems or Bundler at + runtime. + +* `--shebang`: + Specify a different shebang executable name than the default (default 'ruby') + +* `--all`: + Create binstubs for all gems in the bundle. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1 new file mode 100644 index 00000000..3b86b995 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1 @@ -0,0 +1,40 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-CACHE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application +.SH "SYNOPSIS" +\fBbundle cache\fR +.P +alias: \fBpackage\fR, \fBpack\fR +.SH "DESCRIPTION" +Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. +.SH "GIT AND PATH GEMS" +The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\. +.SH "SUPPORT FOR MULTIPLE PLATFORMS" +When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\. +.SH "REMOTE FETCHING" +By default, if you run \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\. +.P +For instance, consider this Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "nokogiri" +.fi +.IP "" 0 +.P +If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\. +.P +Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\. +.P +This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\. +.P +If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\. +.P +One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\. +.P +By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. +.SH "HISTORY" +In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1.ronn new file mode 100644 index 00000000..8112c2c5 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-cache.1.ronn @@ -0,0 +1,79 @@ +bundle-cache(1) -- Package your needed `.gem` files into your application +=========================================================================== + +## SYNOPSIS + +`bundle cache` + +alias: `package`, `pack` + +## DESCRIPTION + +Copy all of the `.gem` files needed to run the application into the +`vendor/cache` directory. In the future, when running [`bundle install(1)`](bundle-install.1.html), +use the gems in the cache in preference to the ones on `rubygems.org`. + +## GIT AND PATH GEMS + +The `bundle cache` command can also package `:git` and `:path` dependencies +besides .gem files. This needs to be explicitly enabled via the `--all` option. +Once used, the `--all` option will be remembered. + +## SUPPORT FOR MULTIPLE PLATFORMS + +When using gems that have different packages for different platforms, Bundler +supports caching of gems for other platforms where the Gemfile has been resolved +(i.e. present in the lockfile) in `vendor/cache`. This needs to be enabled via +the `--all-platforms` option. This setting will be remembered in your local +bundler configuration. + +## REMOTE FETCHING + +By default, if you run [`bundle install(1)`](bundle-install.1.html) after running +[bundle cache(1)](bundle-cache.1.html), bundler will still connect to `rubygems.org` +to check whether a platform-specific gem exists for any of the gems +in `vendor/cache`. + +For instance, consider this Gemfile(5): + + source "https://rubygems.org" + + gem "nokogiri" + +If you run `bundle cache` under C Ruby, bundler will retrieve +the version of `nokogiri` for the `"ruby"` platform. If you deploy +to JRuby and run `bundle install`, bundler is forced to check to +see whether a `"java"` platformed `nokogiri` exists. + +Even though the `nokogiri` gem for the Ruby platform is +_technically_ acceptable on JRuby, it has a C extension +that does not run on JRuby. As a result, bundler will, by default, +still connect to `rubygems.org` to check whether it has a version +of one of your gems more specific to your platform. + +This problem is also not limited to the `"java"` platform. +A similar (common) problem can happen when developing on Windows +and deploying to Linux, or even when developing on OSX and +deploying to Linux. + +If you know for sure that the gems packaged in `vendor/cache` +are appropriate for the platform you are on, you can run +`bundle install --local` to skip checking for more appropriate +gems, and use the ones in `vendor/cache`. + +One way to be sure that you have the right platformed versions +of all your gems is to run `bundle cache` on an identical +machine and check in the gems. For instance, you can run +`bundle cache` on an identical staging box during your +staging process, and check in the `vendor/cache` before +deploying to production. + +By default, [bundle cache(1)](bundle-cache.1.html) fetches and also +installs the gems to the default location. To package the +dependencies to `vendor/cache` without installing them to the +local install location, you can run `bundle cache --no-install`. + +## HISTORY + +In Bundler 2.1, `cache` took in the functionalities of `package` and now +`package` and `pack` are aliases of `cache`. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1 new file mode 100644 index 00000000..7f18e265 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1 @@ -0,0 +1,22 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-CHECK" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems +.SH "SYNOPSIS" +\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH] +.SH "DESCRIPTION" +\fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\. +.P +If not, the first missing gem is listed and Bundler exits status 1\. +.SH "OPTIONS" +.TP +\fB\-\-dry\-run\fR +Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\. +.TP +\fB\-\-gemfile\fR +Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\. +.TP +\fB\-\-path\fR +Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1.ronn new file mode 100644 index 00000000..f2846b8f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-check.1.ronn @@ -0,0 +1,26 @@ +bundle-check(1) -- Verifies if dependencies are satisfied by installed gems +=========================================================================== + +## SYNOPSIS + +`bundle check` [--dry-run] + [--gemfile=FILE] + [--path=PATH] + +## DESCRIPTION + +`check` searches the local machine for each of the gems requested in the +Gemfile. If all gems are found, Bundler prints a success message and exits with +a status of 0. + +If not, the first missing gem is listed and Bundler exits status 1. + +## OPTIONS + +* `--dry-run`: + Locks the [`Gemfile(5)`][Gemfile(5)] before running the command. +* `--gemfile`: + Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)]. +* `--path`: + Specify a different path than the system default (`$BUNDLE_PATH` or `$GEM_HOME`). + Bundler will remember this value for future installs on this machine. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1 new file mode 100644 index 00000000..0180eb38 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1 @@ -0,0 +1,17 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-CLEAN" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory +.SH "SYNOPSIS" +\fBbundle clean\fR [\-\-dry\-run] [\-\-force] +.SH "DESCRIPTION" +This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\. +.SH "OPTIONS" +.TP +\fB\-\-dry\-run\fR +Print the changes, but do not clean the unused gems\. +.TP +\fB\-\-force\fR +Forces cleaning up unused gems even if Bundler is configured to use globally installed gems\. As a consequence, removes all system gems except for the ones in the current application\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1.ronn new file mode 100644 index 00000000..dae27c21 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-clean.1.ronn @@ -0,0 +1,18 @@ +bundle-clean(1) -- Cleans up unused gems in your bundler directory +================================================================== + +## SYNOPSIS + +`bundle clean` [--dry-run] [--force] + +## DESCRIPTION + +This command will remove all unused gems in your bundler directory. This is +useful when you have made many changes to your gem dependencies. + +## OPTIONS + +* `--dry-run`: + Print the changes, but do not clean the unused gems. +* `--force`: + Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1 new file mode 100644 index 00000000..b768f1e3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1 @@ -0,0 +1,321 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-CONFIG" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-config\fR \- Set bundler configuration options +.SH "SYNOPSIS" +\fBbundle config\fR list +.br +\fBbundle config\fR [get] NAME +.br +\fBbundle config\fR [set] NAME VALUE +.br +\fBbundle config\fR unset NAME +.SH "DESCRIPTION" +This command allows you to interact with Bundler's configuration system\. +.P +Bundler loads configuration settings in this order: +.IP "1." 4 +Local config (\fB/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR) +.IP "2." 4 +Environmental variables (\fBENV\fR) +.IP "3." 4 +Global config (\fB~/\.bundle/config\fR) +.IP "4." 4 +Bundler default config +.IP "" 0 +.P +Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\. +.P +Executing \fBbundle config get \fR will print the value of that configuration setting, and where it was set\. +.P +Executing \fBbundle config set \fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. See \fB\-\-local\fR and \fB\-\-global\fR options below\. +.P +Executing \fBbundle config set \-\-local \fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\. +.P +Executing \fBbundle config set \-\-global \fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\. +.P +Executing \fBbundle config unset \fR will delete the configuration in both local and global sources\. +.P +Executing \fBbundle config unset \-\-global \fR will delete the configuration only from the user configuration\. +.P +Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. +.P +Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. +.SH "REMEMBERING OPTIONS" +Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application's configuration (normally, \fB\./\.bundle/config\fR)\. +.P +However, this will be changed in bundler 3, so it's better not to rely on this behavior\. If these options must be remembered, it's better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\. +.P +The options that can be configured are: +.TP +\fBbin\fR +Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. +.TP +\fBdeployment\fR +In deployment mode, Bundler will 'roll\-out' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\. +.TP +\fBonly\fR +A space\-separated list of groups to install only gems of the specified groups\. +.TP +\fBpath\fR +The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. +.TP +\fBwithout\fR +A space\-separated list of groups referencing gems to skip during installation\. +.TP +\fBwith\fR +A space\-separated list of \fBoptional\fR groups referencing gems to include during installation\. +.SH "BUILD OPTIONS" +You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\. +.P +A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\. +.IP "" 4 +.nf +gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config +.fi +.IP "" 0 +.P +Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\. +.IP "" 4 +.nf +bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config +.fi +.IP "" 0 +.P +After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\. +.SH "CONFIGURATION KEYS" +Configuration keys in bundler have two forms: the canonical form and the environment variable form\. +.P +For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn't install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\. +.P +The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\. +.P +Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\. +.SH "LIST OF AVAILABLE KEYS" +The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. +.IP "\(bu" 4 +\fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem's source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR +.IP "\(bu" 4 +\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\. +.IP "\(bu" 4 +\fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\. +.IP "\(bu" 4 +\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\. +.IP "\(bu" 4 +\fBbin\fR (\fBBUNDLE_BIN\fR): Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\. +.IP "\(bu" 4 +\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3\. +.IP "\(bu" 4 +\fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\. +.IP "\(bu" 4 +\fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\. +.IP "\(bu" 4 +\fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. +.IP "\(bu" 4 +\fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\. +.IP "\(bu" 4 +\fBdefault_install_uses_path\fR (\fBBUNDLE_DEFAULT_INSTALL_USES_PATH\fR): Whether a \fBbundle install\fR without an explicit \fB\-\-path\fR argument defaults to installing gems in \fB\.bundle\fR\. +.IP "\(bu" 4 +\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. +.IP "\(bu" 4 +\fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\. +.IP "\(bu" 4 +\fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\. +.IP "\(bu" 4 +\fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\. +.IP "\(bu" 4 +\fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. +.IP "\(bu" 4 +\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems' normal location\. +.IP "\(bu" 4 +\fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\. +.IP "\(bu" 4 +\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine's platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\. +.IP "\(bu" 4 +\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\. +.IP "\(bu" 4 +\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. +.IP "\(bu" 4 +\fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\. +.IP "\(bu" 4 +\fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\. +.IP "\(bu" 4 +\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\. +.IP "\(bu" 4 +\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\. +.IP "\(bu" 4 +\fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. +.IP "\(bu" 4 +\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. +.IP "\(bu" 4 +\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to the number of available processors\. +.IP "\(bu" 4 +\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\. +.IP "\(bu" 4 +\fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\. +.IP "\(bu" 4 +\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\. +.IP "\(bu" 4 +\fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\. +.IP "\(bu" 4 +\fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\. +.IP "\(bu" 4 +\fBpath_relative_to_cwd\fR (\fBBUNDLE_PATH_RELATIVE_TO_CWD\fR) Makes \fB\-\-path\fR relative to the CWD instead of the \fBGemfile\fR\. +.IP "\(bu" 4 +\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler's experimental plugin system\. +.IP "\(bu" 4 +\fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\. +.IP "\(bu" 4 +\fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\. +.IP "\(bu" 4 +\fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\. +.IP "\(bu" 4 +\fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\. +.IP "\(bu" 4 +\fBsetup_makes_kernel_gem_public\fR (\fBBUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC\fR): Have \fBBundler\.setup\fR make the \fBKernel#gem\fR method public, even though RubyGems declares it as private\. +.IP "\(bu" 4 +\fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\. +.IP "\(bu" 4 +\fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\. +.IP "\(bu" 4 +\fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\. +.IP "\(bu" 4 +\fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\. +.IP "\(bu" 4 +\fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\. +.IP "\(bu" 4 +\fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\. +.IP "\(bu" 4 +\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\. +.IP "\(bu" 4 +\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. +.IP "\(bu" 4 +\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. +.IP "\(bu" 4 +\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. +.IP "\(bu" 4 +\fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlockfile\fR\. You can also specify \fBsystem\fR or \fBx\.y\.z\fR\. \fBlockfile\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBsystem\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\. +.IP "\(bu" 4 +\fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\. +.IP "\(bu" 4 +\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\. +.IP "" 0 +.P +In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle cache(1) \fIbundle\-cache\.1\.html\fR command\. +.P +You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\. +.SH "LOCAL GIT REPOS" +Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override: +.IP "" 4 +.nf +bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository +.fi +.IP "" 0 +.P +For example, in order to use a local Rack repository, a developer could call: +.IP "" 4 +.nf +bundle config set \-\-local local\.rack ~/Work/git/rack +.fi +.IP "" 0 +.P +Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You'll also need to CGI escape your usernames and passwords as well\. +.P +Bundler does many checks to ensure a developer won't work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\. +.P +Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\. +.SH "MIRRORS OF GEM SOURCES" +Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\. +.IP "" 4 +.nf +bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL +.fi +.IP "" 0 +.P +For example, to use a mirror of https://rubygems\.org hosted at https://example\.org: +.IP "" 4 +.nf +bundle config set \-\-global mirror\.https://rubygems\.org https://example\.org +.fi +.IP "" 0 +.P +Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\. +.IP "" 4 +.nf +bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT +.fi +.IP "" 0 +.P +For example, to fall back to rubygems\.org after 3 seconds: +.IP "" 4 +.nf +bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3 +.fi +.IP "" 0 +.P +The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\. +.SH "CREDENTIALS FOR GEM SOURCES" +Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\. +.IP "" 4 +.nf +bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD +.fi +.IP "" 0 +.P +For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run: +.IP "" 4 +.nf +bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit +.fi +.IP "" 0 +.P +Or you can set the credentials as an environment variable like this: +.IP "" 4 +.nf +export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" +.fi +.IP "" 0 +.P +For gems with a git source with HTTP(S) URL you can specify credentials like so: +.IP "" 4 +.nf +bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password +.fi +.IP "" 0 +.P +Or you can set the credentials as an environment variable like so: +.IP "" 4 +.nf +export BUNDLE_GITHUB__COM=username:password +.fi +.IP "" 0 +.P +This is especially useful for private repositories on hosts such as GitHub, where you can use personal OAuth tokens: +.IP "" 4 +.nf +export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic +.fi +.IP "" 0 +.P +Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentionally leaking credentials when copy\-pasting bundler output\. +.P +Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: +.IP "\(bu" 4 +Any \fB\-\fR characters in a host name are mapped to a triple underscore (\fB___\fR) in the corresponding environment variable\. +.IP "\(bu" 4 +Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\fR) in the corresponding environment variable\. +.IP "" 0 +.P +This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\. +.SH "CONFIGURE BUNDLER DIRECTORIES" +Bundler's home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values +.IP "" 4 +.nf +BUNDLE_USER_HOME : $HOME/\.bundle +BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache +BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config +BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin +.fi +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1.ronn new file mode 100644 index 00000000..587d31db --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-config.1.ronn @@ -0,0 +1,411 @@ +bundle-config(1) -- Set bundler configuration options +===================================================== + +## SYNOPSIS + +`bundle config` list
+`bundle config` [get] NAME
+`bundle config` [set] NAME VALUE
+`bundle config` unset NAME + +## DESCRIPTION + +This command allows you to interact with Bundler's configuration system. + +Bundler loads configuration settings in this order: + +1. Local config (`/.bundle/config` or `$BUNDLE_APP_CONFIG/config`) +2. Environmental variables (`ENV`) +3. Global config (`~/.bundle/config`) +4. Bundler default config + +Executing `bundle config list` will print a list of all bundler +configuration for the current bundle, and where that configuration +was set. + +Executing `bundle config get ` will print the value of that configuration +setting, and where it was set. + +Executing `bundle config set ` defaults to setting `local` +configuration if executing from within a local application, otherwise it will +set `global` configuration. See `--local` and `--global` options below. + +Executing `bundle config set --local ` will set that configuration +in the directory for the local application. The configuration will be stored in +`/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration +will be stored in `$BUNDLE_APP_CONFIG/config`. + +Executing `bundle config set --global ` will set that +configuration to the value specified for all bundles executed as the current +user. The configuration will be stored in `~/.bundle/config`. If already +is set, will be overridden and user will be warned. + +Executing `bundle config unset ` will delete the configuration in both +local and global sources. + +Executing `bundle config unset --global ` will delete the configuration +only from the user configuration. + +Executing `bundle config unset --local ` will delete the configuration +only from the local application. + +Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will +cause it to ignore all configuration. + +## REMEMBERING OPTIONS + +Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or +`--without production`, are remembered between commands and saved to your local +application's configuration (normally, `./.bundle/config`). + +However, this will be changed in bundler 3, so it's better not to rely on this +behavior. If these options must be remembered, it's better to set them using +`bundle config` (e.g., `bundle config set --local path foo`). + +The options that can be configured are: + +* `bin`: + Creates a directory (defaults to `~/bin`) and place any executables from the + gem there. These executables run in Bundler's context. If used, you might add + this directory to your environment's `PATH` variable. For instance, if the + `rails` gem comes with a `rails` executable, this flag will create a + `bin/rails` executable that ensures that all referred dependencies will be + resolved using the bundled gems. + +* `deployment`: + In deployment mode, Bundler will 'roll-out' the bundle for + `production` use. Please check carefully if you want to have this option + enabled in `development` or `test` environments. + +* `only`: + A space-separated list of groups to install only gems of the specified groups. + +* `path`: + The location to install the specified gems to. This defaults to Rubygems' + setting. Bundler shares this location with Rubygems, `gem install ...` will + have gem installed there, too. Therefore, gems installed without a + `--path ...` setting will show up by calling `gem list`. Accordingly, gems + installed to other locations will not get listed. + +* `without`: + A space-separated list of groups referencing gems to skip during installation. + +* `with`: + A space-separated list of **optional** groups referencing gems to include during installation. + +## BUILD OPTIONS + +You can use `bundle config` to give Bundler the flags to pass to the gem +installer every time bundler tries to install a particular gem. + +A very common example, the `mysql` gem, requires Snow Leopard users to +pass configuration flags to `gem install` to specify where to find the +`mysql_config` executable. + + gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config + +Since the specific location of that executable can change from machine +to machine, you can specify these flags on a per-machine basis. + + bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config + +After running this command, every time bundler needs to install the +`mysql` gem, it will pass along the flags you specified. + +## CONFIGURATION KEYS + +Configuration keys in bundler have two forms: the canonical form and the +environment variable form. + +For instance, passing the `--without` flag to [bundle install(1)](bundle-install.1.html) +prevents Bundler from installing certain groups specified in the Gemfile(5). Bundler +persists this value in `app/.bundle/config` so that calls to `Bundler.setup` +do not try to find gems from the `Gemfile` that you didn't install. Additionally, +subsequent calls to [bundle install(1)](bundle-install.1.html) remember this setting +and skip those groups. + +The canonical form of this configuration is `"without"`. To convert the canonical +form to the environment variable form, capitalize it, and prepend `BUNDLE_`. The +environment variable form of `"without"` is `BUNDLE_WITHOUT`. + +Any periods in the configuration keys must be replaced with two underscores when +setting it via environment variables. The configuration key `local.rack` becomes +the environment variable `BUNDLE_LOCAL__RACK`. + +## LIST OF AVAILABLE KEYS + +The following is a list of all configuration keys and their purpose. You can +learn more about their operation in [bundle install(1)](bundle-install.1.html). + +* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`): + When in deployment mode, allow changing the credentials to a gem's source. + Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path` +* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`): + Allow Bundler to use cached data when installing without network access. +* `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`): + Automatically run `bundle clean` after installing when an explicit `path` + has not been set and Bundler is not installing into the system gems. +* `auto_install` (`BUNDLE_AUTO_INSTALL`): + Automatically run `bundle install` when gems are missing. +* `bin` (`BUNDLE_BIN`): + Install executables from gems in the bundle to the specified directory. + Defaults to `false`. +* `cache_all` (`BUNDLE_CACHE_ALL`): + Cache all gems, including path and git gems. This needs to be explicitly + configured on bundler 1 and bundler 2, but will be the default on bundler 3. +* `cache_all_platforms` (`BUNDLE_CACHE_ALL_PLATFORMS`): + Cache gems for all platforms. +* `cache_path` (`BUNDLE_CACHE_PATH`): + The directory that bundler will place cached gems in when running + bundle package, and that bundler will look in when installing gems. + Defaults to `vendor/cache`. +* `clean` (`BUNDLE_CLEAN`): + Whether Bundler should run `bundle clean` automatically after + `bundle install`. +* `console` (`BUNDLE_CONSOLE`): + The console that `bundle console` starts. Defaults to `irb`. +* `default_install_uses_path` (`BUNDLE_DEFAULT_INSTALL_USES_PATH`): + Whether a `bundle install` without an explicit `--path` argument defaults + to installing gems in `.bundle`. +* `deployment` (`BUNDLE_DEPLOYMENT`): + Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the + lockfile has not been updated, running Bundler commands will be blocked. +* `disable_checksum_validation` (`BUNDLE_DISABLE_CHECKSUM_VALIDATION`): + Allow installing gems even if they do not match the checksum provided by + RubyGems. +* `disable_exec_load` (`BUNDLE_DISABLE_EXEC_LOAD`): + Stop Bundler from using `load` to launch an executable in-process in + `bundle exec`. +* `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`): + Allow Bundler to use a local git override without a branch specified in the + Gemfile. +* `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): + Allow Bundler to use a local git override without checking if the revision + present in the lockfile is present in the repository. +* `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): + Stop Bundler from accessing gems installed to RubyGems' normal location. +* `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): + Stop Bundler from checking if a newer Bundler version is available on + rubygems.org. +* `force_ruby_platform` (`BUNDLE_FORCE_RUBY_PLATFORM`): + Ignore the current machine's platform and install only `ruby` platform gems. + As a result, gems with native extensions will be compiled from source. +* `frozen` (`BUNDLE_FROZEN`): + Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the + lockfile has not been updated, running Bundler commands will be blocked. + Defaults to `true` when `--deployment` is used. +* `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`): + Sets a GitHub username or organization to be used in `README` file when you + create a new gem via `bundle gem` command. It can be overridden by passing an + explicit `--github-username` flag to `bundle gem`. +* `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`): + Sets the `--key` parameter for `gem push` when using the `rake release` + command with a private gemstash server. +* `gemfile` (`BUNDLE_GEMFILE`): + The name of the file that bundler should use as the `Gemfile`. This location + of this file also sets the root of the project, which is used to resolve + relative paths in the `Gemfile`, among other things. By default, bundler + will search up from the current working directory until it finds a + `Gemfile`. +* `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): + Whether Bundler should cache all gems globally, rather than locally to the + installing Ruby installation. +* `ignore_funding_requests` (`BUNDLE_IGNORE_FUNDING_REQUESTS`): + When set, no funding requests will be printed. +* `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): + When set, no post install messages will be printed. To silence a single gem, + use dot notation like `ignore_messages.httparty true`. +* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`): + Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`. +* `jobs` (`BUNDLE_JOBS`): + The number of gems Bundler can install in parallel. Defaults to the number of + available processors. +* `no_install` (`BUNDLE_NO_INSTALL`): + Whether `bundle package` should skip installing gems. +* `no_prune` (`BUNDLE_NO_PRUNE`): + Whether Bundler should leave outdated gems unpruned when caching. +* `only` (`BUNDLE_ONLY`): + A space-separated list of groups to install only gems of the specified groups. +* `path` (`BUNDLE_PATH`): + The location on disk where all gems in your bundle will be located regardless + of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location + will be installed by `bundle install`. Defaults to `Gem.dir`. When --deployment + is used, defaults to vendor/bundle. +* `path.system` (`BUNDLE_PATH__SYSTEM`): + Whether Bundler will install gems into the default system path (`Gem.dir`). +* `path_relative_to_cwd` (`BUNDLE_PATH_RELATIVE_TO_CWD`) + Makes `--path` relative to the CWD instead of the `Gemfile`. +* `plugins` (`BUNDLE_PLUGINS`): + Enable Bundler's experimental plugin system. +* `prefer_patch` (BUNDLE_PREFER_PATCH): + Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`. +* `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`): + Print only version number from `bundler --version`. +* `redirect` (`BUNDLE_REDIRECT`): + The number of redirects allowed for network requests. Defaults to `5`. +* `retry` (`BUNDLE_RETRY`): + The number of times to retry failed network requests. Defaults to `3`. +* `setup_makes_kernel_gem_public` (`BUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC`): + Have `Bundler.setup` make the `Kernel#gem` method public, even though + RubyGems declares it as private. +* `shebang` (`BUNDLE_SHEBANG`): + The program name that should be invoked for generated binstubs. Defaults to + the ruby install name used to generate the binstub. +* `silence_deprecations` (`BUNDLE_SILENCE_DEPRECATIONS`): + Whether Bundler should silence deprecation warnings for behavior that will + be changed in the next major version. +* `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`): + Silence the warning Bundler prints when installing gems as root. +* `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`): + Path to a designated CA certificate file or folder containing multiple + certificates for trusted CAs in PEM format. +* `ssl_client_cert` (`BUNDLE_SSL_CLIENT_CERT`): + Path to a designated file containing a X.509 client certificate + and key in PEM format. +* `ssl_verify_mode` (`BUNDLE_SSL_VERIFY_MODE`): + The SSL verification mode Bundler uses when making HTTPS requests. + Defaults to verify peer. +* `system_bindir` (`BUNDLE_SYSTEM_BINDIR`): + The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. +* `timeout` (`BUNDLE_TIMEOUT`): + The seconds allowed before timing out for network requests. Defaults to `10`. +* `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): + Require passing `--all` to `bundle update` when everything should be updated, + and disallow passing no options to `bundle update`. +* `user_agent` (`BUNDLE_USER_AGENT`): + The custom user agent fragment Bundler includes in API requests. +* `version` (`BUNDLE_VERSION`): + The version of Bundler to use when running under Bundler environment. + Defaults to `lockfile`. You can also specify `system` or `x.y.z`. + `lockfile` will use the Bundler version specified in the `Gemfile.lock`, + `system` will use the system version of Bundler, and `x.y.z` will use + the specified version of Bundler. +* `with` (`BUNDLE_WITH`): + A `:`-separated list of groups whose gems bundler should install. +* `without` (`BUNDLE_WITHOUT`): + A `:`-separated list of groups whose gems bundler should not install. + +In general, you should set these settings per-application by using the applicable +flag to the [bundle install(1)](bundle-install.1.html) or [bundle cache(1)](bundle-cache.1.html) command. + +You can set them globally either via environment variables or `bundle config`, +whichever is preferable for your setup. If you use both, environment variables +will take preference over global settings. + +## LOCAL GIT REPOS + +Bundler also allows you to work against a git repository locally +instead of using the remote version. This can be achieved by setting +up a local override: + + bundle config set --local local.GEM_NAME /path/to/local/git/repository + +For example, in order to use a local Rack repository, a developer could call: + + bundle config set --local local.rack ~/Work/git/rack + +Now instead of checking out the remote git repository, the local +override will be used. Similar to a path source, every time the local +git repository change, changes will be automatically picked up by +Bundler. This means a commit in the local git repo will update the +revision in the `Gemfile.lock` to the local git repo revision. This +requires the same attention as git submodules. Before pushing to +the remote, you need to ensure the local override was pushed, otherwise +you may point to a commit that only exists in your local machine. +You'll also need to CGI escape your usernames and passwords as well. + +Bundler does many checks to ensure a developer won't work with +invalid references. Particularly, we force a developer to specify +a branch in the `Gemfile` in order to use this feature. If the branch +specified in the `Gemfile` and the current branch in the local git +repository do not match, Bundler will abort. This ensures that +a developer is always working against the correct branches, and prevents +accidental locking to a different branch. + +Finally, Bundler also ensures that the current revision in the +`Gemfile.lock` exists in the local git repository. By doing this, Bundler +forces you to fetch the latest changes in the remotes. + +## MIRRORS OF GEM SOURCES + +Bundler supports overriding gem sources with mirrors. This allows you to +configure rubygems.org as the gem source in your Gemfile while still using your +mirror to fetch gems. + + bundle config set --global mirror.SOURCE_URL MIRROR_URL + +For example, to use a mirror of https://rubygems.org hosted at https://example.org: + + bundle config set --global mirror.https://rubygems.org https://example.org + +Each mirror also provides a fallback timeout setting. If the mirror does not +respond within the fallback timeout, Bundler will try to use the original +server instead of the mirror. + + bundle config set --global mirror.SOURCE_URL.fallback_timeout TIMEOUT + +For example, to fall back to rubygems.org after 3 seconds: + + bundle config set --global mirror.https://rubygems.org.fallback_timeout 3 + +The default fallback timeout is 0.1 seconds, but the setting can currently +only accept whole seconds (for example, 1, 15, or 30). + +## CREDENTIALS FOR GEM SOURCES + +Bundler allows you to configure credentials for any gem source, which allows +you to avoid putting secrets into your Gemfile. + + bundle config set --global SOURCE_HOSTNAME USERNAME:PASSWORD + +For example, to save the credentials of user `claudette` for the gem source at +`gems.longerous.com`, you would run: + + bundle config set --global gems.longerous.com claudette:s00pers3krit + +Or you can set the credentials as an environment variable like this: + + export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" + +For gems with a git source with HTTP(S) URL you can specify credentials like so: + + bundle config set --global https://github.com/rubygems/rubygems.git username:password + +Or you can set the credentials as an environment variable like so: + + export BUNDLE_GITHUB__COM=username:password + +This is especially useful for private repositories on hosts such as GitHub, +where you can use personal OAuth tokens: + + export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic + +Note that any configured credentials will be redacted by informative commands +such as `bundle config list` or `bundle config get`, unless you use the +`--parseable` flag. This is to avoid unintentionally leaking credentials when +copy-pasting bundler output. + +Also note that to guarantee a sane mapping between valid environment variable +names and valid host names, bundler makes the following transformations: + +* Any `-` characters in a host name are mapped to a triple underscore (`___`) in the + corresponding environment variable. + +* Any `.` characters in a host name are mapped to a double underscore (`__`) in the + corresponding environment variable. + +This means that if you have a gem server named `my.gem-host.com`, you'll need to +use the `BUNDLE_MY__GEM___HOST__COM` variable to configure credentials for it +through ENV. + +## CONFIGURE BUNDLER DIRECTORIES + +Bundler's home, config, cache and plugin directories are able to be configured +through environment variables. The default location for Bundler's home directory is +`~/.bundle`, which all directories inherit from by default. The following +outlines the available environment variables and their default values + + BUNDLE_USER_HOME : $HOME/.bundle + BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache + BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config + BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1 new file mode 100644 index 00000000..1368a50e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1 @@ -0,0 +1,35 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-CONSOLE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded +.SH "SYNOPSIS" +\fBbundle console\fR [GROUP] +.SH "DESCRIPTION" +Starts an interactive Ruby console session in the context of the current bundle\. +.P +If no \fBGROUP\fR is specified, all gems in the \fBdefault\fR group in the Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR are preliminarily loaded\. +.P +If \fBGROUP\fR is specified, all gems in the given group in the Gemfile in addition to the gems in \fBdefault\fR group are loaded\. Even if the given group does not exist in the Gemfile, IRB console starts without any warning or error\. +.P +The environment variable \fBBUNDLE_CONSOLE\fR or \fBbundle config set console\fR can be used to change the shell from the following: +.IP "\(bu" 4 +\fBirb\fR (default) +.IP "\(bu" 4 +\fBpry\fR (https://github\.com/pry/pry) +.IP "\(bu" 4 +\fBripl\fR (https://github\.com/cldwalker/ripl) +.IP "" 0 +.P +\fBbundle console\fR uses irb by default\. An alternative Pry or Ripl can be used with \fBbundle console\fR by adjusting the \fBconsole\fR Bundler setting\. Also make sure that \fBpry\fR or \fBripl\fR is in your Gemfile\. +.SH "EXAMPLE" +.nf +$ bundle config set console pry +$ bundle console +Resolving dependencies\|\.\|\.\|\. +[1] pry(main)> +.fi +.SH "NOTES" +This command was deprecated in Bundler 2\.1 and will be removed in 3\.0\. Use \fBbin/console\fR script, which can be generated by \fBbundle gem \fR\. +.SH "SEE ALSO" +Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1.ronn new file mode 100644 index 00000000..f9096d38 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-console.1.ronn @@ -0,0 +1,44 @@ +bundle-console(1) -- Deprecated way to open an IRB session with the bundle pre-loaded +===================================================================================== + +## SYNOPSIS + +`bundle console` [GROUP] + +## DESCRIPTION + +Starts an interactive Ruby console session in the context of the current bundle. + +If no `GROUP` is specified, all gems in the `default` group in the [Gemfile(5)](https://bundler.io/man/gemfile.5.html) are +preliminarily loaded. + +If `GROUP` is specified, all gems in the given group in the Gemfile in addition +to the gems in `default` group are loaded. Even if the given group does not +exist in the Gemfile, IRB console starts without any warning or error. + +The environment variable `BUNDLE_CONSOLE` or `bundle config set console` can be used to change +the shell from the following: + +* `irb` (default) +* `pry` (https://github.com/pry/pry) +* `ripl` (https://github.com/cldwalker/ripl) + +`bundle console` uses irb by default. An alternative Pry or Ripl can be used with +`bundle console` by adjusting the `console` Bundler setting. Also make sure that +`pry` or `ripl` is in your Gemfile. + +## EXAMPLE + + $ bundle config set console pry + $ bundle console + Resolving dependencies... + [1] pry(main)> + +## NOTES + +This command was deprecated in Bundler 2.1 and will be removed in 3.0. +Use `bin/console` script, which can be generated by `bundle gem `. + +## SEE ALSO + +[Gemfile(5)](https://bundler.io/man/gemfile.5.html) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1 new file mode 100644 index 00000000..80eaf2a8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1 @@ -0,0 +1,30 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-DOCTOR" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-doctor\fR \- Checks the bundle for common problems +.SH "SYNOPSIS" +\fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE] +.SH "DESCRIPTION" +Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\. +.P +Examples of common problems caught by bundle\-doctor include: +.IP "\(bu" 4 +Invalid Bundler settings +.IP "\(bu" 4 +Mismatched Ruby versions +.IP "\(bu" 4 +Mismatched platforms +.IP "\(bu" 4 +Uninstalled gems +.IP "\(bu" 4 +Missing dependencies +.IP "" 0 +.SH "OPTIONS" +.TP +\fB\-\-quiet\fR +Only output warnings and errors\. +.TP +\fB\-\-gemfile=\fR +The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1.ronn new file mode 100644 index 00000000..271ee800 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-doctor.1.ronn @@ -0,0 +1,33 @@ +bundle-doctor(1) -- Checks the bundle for common problems +========================================================= + +## SYNOPSIS + +`bundle doctor` [--quiet] + [--gemfile=GEMFILE] + +## DESCRIPTION + +Checks your Gemfile and gem environment for common problems. If issues +are detected, Bundler prints them and exits status 1. Otherwise, +Bundler prints a success message and exits status 0. + +Examples of common problems caught by bundle-doctor include: + +* Invalid Bundler settings +* Mismatched Ruby versions +* Mismatched platforms +* Uninstalled gems +* Missing dependencies + +## OPTIONS + +* `--quiet`: + Only output warnings and errors. + +* `--gemfile=`: + The location of the Gemfile(5) which Bundler should use. This defaults + to a Gemfile(5) in the current working directory. In general, Bundler + will assume that the location of the Gemfile(5) is also the project's + root and will try to find `Gemfile.lock` and `vendor/cache` relative + to this location. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1 new file mode 100644 index 00000000..191863c0 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1 @@ -0,0 +1,104 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-EXEC" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-exec\fR \- Execute a command in the context of the bundle +.SH "SYNOPSIS" +\fBbundle exec\fR [\-\-keep\-file\-descriptors] \fIcommand\fR +.SH "DESCRIPTION" +This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\. +.P +Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\. +.P +Note that \fBbundle exec\fR does not require that an executable is available on your shell's \fB$PATH\fR\. +.SH "OPTIONS" +.TP +\fB\-\-keep\-file\-descriptors\fR +Passes all file descriptors to the new processes\. Default is true from bundler version 2\.2\.26\. Setting it to false is now deprecated\. +.SH "BUNDLE INSTALL \-\-BINSTUBS" +If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\. +.P +After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\. +.SH "ENVIRONMENT MODIFICATIONS" +\fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\. +.IP "\(bu" 4 +make sure that it's still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR) +.IP "\(bu" 4 +put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR +.IP "\(bu" 4 +make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR) +.IP "\(bu" 4 +add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle +.IP "" 0 +.P +It also modifies Rubygems: +.IP "\(bu" 4 +disallow loading additional gems not in the bundle +.IP "\(bu" 4 +modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it's not +.IP "\(bu" 4 +Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment +.IP "\(bu" 4 +Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work +.IP "\(bu" 4 +Add all gems in the bundle into Gem\.loaded_specs +.IP "" 0 +.P +Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem's groups, \fBautorequire\fR, and platforms, etc\., and that information isn't stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\. +.SS "Loading" +By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\. +.SS "Shelling out" +Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don't work inside a bundle: +.IP "" 4 +.nf +Bundler\.with_unbundled_env do + `brew install wget` +end +.fi +.IP "" 0 +.P +Using \fBwith_unbundled_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_unbundled_env\fR\. +.IP "" 4 +.nf +Bundler\.with_unbundled_env do + Dir\.chdir "/other/bundler/project" do + `bundle exec \./script` + end +end +.fi +.IP "" 0 +.P +Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this: +.IP "" 4 +.nf +Bundler\.clean_system('brew install wget') +Bundler\.clean_exec('brew install wget') +.fi +.IP "" 0 +.SH "RUBYGEMS PLUGINS" +At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\. +.P +Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\. +.P +For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure \fR\. +.P +If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\. +.P +If this happens, bundler will say: +.IP "" 4 +.nf +You have already activated json_pure 1\.4\.6 but your Gemfile +requires json_pure 1\.4\.3\. Consider using bundle exec\. +.fi +.IP "" 0 +.P +In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\. +.P +You can find a list of all the gems containing gem plugins by running +.IP "" 4 +.nf +ruby \-e "puts Gem\.find_files('rubygems_plugin\.rb')" +.fi +.IP "" 0 +.P +At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (\fBgem uninstall gem_name\fR)\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1.ronn new file mode 100644 index 00000000..9d5b559f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-exec.1.ronn @@ -0,0 +1,151 @@ +bundle-exec(1) -- Execute a command in the context of the bundle +================================================================ + +## SYNOPSIS + +`bundle exec` [--keep-file-descriptors] + +## DESCRIPTION + +This command executes the command, making all gems specified in the +[`Gemfile(5)`][Gemfile(5)] available to `require` in Ruby programs. + +Essentially, if you would normally have run something like +`rspec spec/my_spec.rb`, and you want to use the gems specified +in the [`Gemfile(5)`][Gemfile(5)] and installed via [bundle install(1)](bundle-install.1.html), you +should run `bundle exec rspec spec/my_spec.rb`. + +Note that `bundle exec` does not require that an executable is +available on your shell's `$PATH`. + +## OPTIONS + +* `--keep-file-descriptors`: + Passes all file descriptors to the new processes. Default is true from + bundler version 2.2.26. Setting it to false is now deprecated. + +## BUNDLE INSTALL --BINSTUBS + +If you use the `--binstubs` flag in [bundle install(1)](bundle-install.1.html), Bundler will +automatically create a directory (which defaults to `app_root/bin`) +containing all of the executables available from gems in the bundle. + +After using `--binstubs`, `bin/rspec spec/my_spec.rb` is identical +to `bundle exec rspec spec/my_spec.rb`. + +## ENVIRONMENT MODIFICATIONS + +`bundle exec` makes a number of changes to the shell environment, +then executes the command you specify in full. + +* make sure that it's still possible to shell out to `bundle` + from inside a command invoked by `bundle exec` (using + `$BUNDLE_BIN_PATH`) +* put the directory containing executables (like `rails`, `rspec`, + `rackup`) for your bundle on `$PATH` +* make sure that if bundler is invoked in the subshell, it uses + the same `Gemfile` (by setting `BUNDLE_GEMFILE`) +* add `-rbundler/setup` to `$RUBYOPT`, which makes sure that + Ruby programs invoked in the subshell can see the gems in + the bundle + +It also modifies Rubygems: + +* disallow loading additional gems not in the bundle +* modify the `gem` method to be a no-op if a gem matching + the requirements is in the bundle, and to raise a + `Gem::LoadError` if it's not +* Define `Gem.refresh` to be a no-op, since the source + index is always frozen when using bundler, and to + prevent gems from the system leaking into the environment +* Override `Gem.bin_path` to use the gems in the bundle, + making system executables work +* Add all gems in the bundle into Gem.loaded_specs + +Finally, `bundle exec` also implicitly modifies `Gemfile.lock` if the lockfile +and the Gemfile do not match. Bundler needs the Gemfile to determine things +such as a gem's groups, `autorequire`, and platforms, etc., and that +information isn't stored in the lockfile. The Gemfile and lockfile must be +synced in order to `bundle exec` successfully, so `bundle exec` +updates the lockfile beforehand. + +### Loading + +By default, when attempting to `bundle exec` to a file with a ruby shebang, +Bundler will `Kernel.load` that file instead of using `Kernel.exec`. For the +vast majority of cases, this is a performance improvement. In a rare few cases, +this could cause some subtle side-effects (such as dependence on the exact +contents of `$0` or `__FILE__`) and the optimization can be disabled by enabling +the `disable_exec_load` setting. + +### Shelling out + +Any Ruby code that opens a subshell (like `system`, backticks, or `%x{}`) will +automatically use the current Bundler environment. If you need to shell out to +a Ruby command that is not part of your current bundle, use the +`with_unbundled_env` method with a block. Any subshells created inside the block +will be given the environment present before Bundler was activated. For +example, Homebrew commands run Ruby, but don't work inside a bundle: + + Bundler.with_unbundled_env do + `brew install wget` + end + +Using `with_unbundled_env` is also necessary if you are shelling out to a different +bundle. Any Bundler commands run in a subshell will inherit the current +Gemfile, so commands that need to run in the context of a different bundle also +need to use `with_unbundled_env`. + + Bundler.with_unbundled_env do + Dir.chdir "/other/bundler/project" do + `bundle exec ./script` + end + end + +Bundler provides convenience helpers that wrap `system` and `exec`, and they +can be used like this: + + Bundler.clean_system('brew install wget') + Bundler.clean_exec('brew install wget') + + +## RUBYGEMS PLUGINS + +At present, the Rubygems plugin system requires all files +named `rubygems_plugin.rb` on the load path of _any_ installed +gem when any Ruby code requires `rubygems.rb`. This includes +executables installed into the system, like `rails`, `rackup`, +and `rspec`. + +Since Rubygems plugins can contain arbitrary Ruby code, they +commonly end up activating themselves or their dependencies. + +For instance, the `gemcutter 0.5` gem depended on `json_pure`. +If you had that version of gemcutter installed (even if +you _also_ had a newer version without this problem), Rubygems +would activate `gemcutter 0.5` and `json_pure `. + +If your Gemfile(5) also contained `json_pure` (or a gem +with a dependency on `json_pure`), the latest version on +your system might conflict with the version in your +Gemfile(5), or the snapshot version in your `Gemfile.lock`. + +If this happens, bundler will say: + + You have already activated json_pure 1.4.6 but your Gemfile + requires json_pure 1.4.3. Consider using bundle exec. + +In this situation, you almost certainly want to remove the +underlying gem with the problematic gem plugin. In general, +the authors of these plugins (in this case, the `gemcutter` +gem) have released newer versions that are more careful in +their plugins. + +You can find a list of all the gems containing gem plugins +by running + + ruby -e "puts Gem.find_files('rubygems_plugin.rb')" + +At the very least, you should remove all but the newest +version of each gem plugin, and also remove all gem plugins +that you aren't using (`gem uninstall gem_name`). diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1 new file mode 100644 index 00000000..464d8d11 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1 @@ -0,0 +1,69 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-GEM" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem +.SH "SYNOPSIS" +\fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR +.SH "DESCRIPTION" +Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\. +.P +Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\. +.P +The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler's global configuration file using the following names: +.IP "\(bu" 4 +\fBgem\.coc\fR +.IP "\(bu" 4 +\fBgem\.mit\fR +.IP "\(bu" 4 +\fBgem\.test\fR +.IP "" 0 +.SH "OPTIONS" +.IP "\(bu" 4 +\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR: Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-no\-exe\fR: Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-no\-coc\fR: Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-ext=c\fR, \fB\-\-ext=rust\fR Add boilerplate for C or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-no\-ext\fR: Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-no\-mit\fR: Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR: Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: +.IP +When Bundler is configured to generate tests, this defaults to Bundler's global config setting \fBgem\.test\fR\. +.IP +When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP +When Bundler is configured to generate CI files, this defaults to Bundler's global config setting \fBgem\.ci\fR\. +.IP +When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project's development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP +When Bundler is configured to add a linter, this defaults to Bundler's global config setting \fBgem\.linter\fR\. +.IP +When Bundler is configured not to add a linter, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR: Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +.IP "" 0 +.SH "SEE ALSO" +.IP "\(bu" 4 +bundle config(1) \fIbundle\-config\.1\.html\fR +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1.ronn new file mode 100644 index 00000000..46fa2f17 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-gem.1.ronn @@ -0,0 +1,117 @@ +bundle-gem(1) -- Generate a project skeleton for creating a rubygem +==================================================================== + +## SYNOPSIS + +`bundle gem` [OPTIONS] + +## DESCRIPTION + +Generates a directory named `GEM_NAME` with a `Rakefile`, `GEM_NAME.gemspec`, +and other supporting files and directories that can be used to develop a +rubygem with that name. + +Run `rake -T` in the resulting project for a list of Rake tasks that can be used +to test and publish the gem to rubygems.org. + +The generated project skeleton can be customized with OPTIONS, as explained +below. Note that these options can also be specified via Bundler's global +configuration file using the following names: + +* `gem.coc` +* `gem.mit` +* `gem.test` + +## OPTIONS + +* `--exe` or `-b` or `--bin`: + Specify that Bundler should create a binary executable (as `exe/GEM_NAME`) + in the generated rubygem project. This binary will also be added to the + `GEM_NAME.gemspec` manifest. This behavior is disabled by default. + +* `--no-exe`: + Do not create a binary (overrides `--exe` specified in the global config). + +* `--coc`: + Add a `CODE_OF_CONDUCT.md` file to the root of the generated project. If + this option is unspecified, an interactive prompt will be displayed and the + answer will be saved in Bundler's global config for future `bundle gem` use. + +* `--no-coc`: + Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the + global config). + +* `--ext=c`, `--ext=rust` + Add boilerplate for C or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior + is disabled by default. + +* `--no-ext`: + Do not add extension code (overrides `--ext` specified in the global + config). + +* `--mit`: + Add an MIT license to a `LICENSE.txt` file in the root of the generated + project. Your name from the global git config is used for the copyright + statement. If this option is unspecified, an interactive prompt will be + displayed and the answer will be saved in Bundler's global config for future + `bundle gem` use. + +* `--no-mit`: + Do not create a `LICENSE.txt` (overrides `--mit` specified in the global + config). + +* `-t`, `--test=minitest`, `--test=rspec`, `--test=test-unit`: + Specify the test framework that Bundler should use when generating the + project. Acceptable values are `minitest`, `rspec` and `test-unit`. The + `GEM_NAME.gemspec` will be configured and a skeleton test/spec directory will + be created based on this option. Given no option is specified: + + When Bundler is configured to generate tests, this defaults to Bundler's + global config setting `gem.test`. + + When Bundler is configured to not generate tests, an interactive prompt will + be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `--ci`, `--ci=github`, `--ci=gitlab`, `--ci=circle`: + Specify the continuous integration service that Bundler should use when + generating the project. Acceptable values are `github`, `gitlab` + and `circle`. A configuration file will be generated in the project directory. + Given no option is specified: + + When Bundler is configured to generate CI files, this defaults to Bundler's + global config setting `gem.ci`. + + When Bundler is configured to not generate CI files, an interactive prompt + will be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `--linter`, `--linter=rubocop`, `--linter=standard`: + Specify the linter and code formatter that Bundler should add to the + project's development dependencies. Acceptable values are `rubocop` and + `standard`. A configuration file will be generated in the project directory. + Given no option is specified: + + When Bundler is configured to add a linter, this defaults to Bundler's + global config setting `gem.linter`. + + When Bundler is configured not to add a linter, an interactive prompt + will be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `-e`, `--edit[=EDITOR]`: + Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not + specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`. + +## SEE ALSO + +* [bundle config(1)](bundle-config.1.html) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1 new file mode 100644 index 00000000..3604ad61 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1 @@ -0,0 +1,9 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-HELP" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-help\fR \- Displays detailed help for each subcommand +.SH "SYNOPSIS" +\fBbundle help\fR [COMMAND] +.SH "DESCRIPTION" +Displays detailed help for the given subcommand\. You can specify a single \fBCOMMAND\fR at the same time\. When \fBCOMMAND\fR is omitted, help for \fBhelp\fR command will be displayed\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1.ronn new file mode 100644 index 00000000..0e144aea --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-help.1.ronn @@ -0,0 +1,12 @@ +bundle-help(1) -- Displays detailed help for each subcommand +============================================================ + +## SYNOPSIS + +`bundle help` [COMMAND] + +## DESCRIPTION + +Displays detailed help for the given subcommand. +You can specify a single `COMMAND` at the same time. +When `COMMAND` is omitted, help for `help` command will be displayed. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1 new file mode 100644 index 00000000..647f5987 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1 @@ -0,0 +1,14 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-INFO" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-info\fR \- Show information for the given gem in your bundle +.SH "SYNOPSIS" +\fBbundle info\fR [GEM_NAME] [\-\-path] +.SH "DESCRIPTION" +Given a gem name present in your bundle, print the basic information about it such as homepage, version, path and summary\. +.SH "OPTIONS" +.TP +\fB\-\-path\fR +Print the path of the given gem + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1.ronn new file mode 100644 index 00000000..cecdeb56 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-info.1.ronn @@ -0,0 +1,17 @@ +bundle-info(1) -- Show information for the given gem in your bundle +========================================================================= + +## SYNOPSIS + +`bundle info` [GEM_NAME] + [--path] + +## DESCRIPTION + +Given a gem name present in your bundle, print the basic information about it + such as homepage, version, path and summary. + +## OPTIONS + +* `--path`: +Print the path of the given gem diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1 new file mode 100644 index 00000000..2c41a3c7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1 @@ -0,0 +1,20 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-INIT" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-init\fR \- Generates a Gemfile into the current working directory +.SH "SYNOPSIS" +\fBbundle init\fR [\-\-gemspec=FILE] +.SH "DESCRIPTION" +Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\. +.SH "OPTIONS" +.TP +\fB\-\-gemspec\fR +Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)] +.TP +\fB\-\-gemfile\fR +Use the specified name for the gemfile instead of \fBGemfile\fR +.SH "FILES" +Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\. +.SH "SEE ALSO" +Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1.ronn new file mode 100644 index 00000000..7d3cede1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-init.1.ronn @@ -0,0 +1,31 @@ +bundle-init(1) -- Generates a Gemfile into the current working directory +======================================================================== + +## SYNOPSIS + +`bundle init` [--gemspec=FILE] + +## DESCRIPTION + +Init generates a default [`Gemfile(5)`][Gemfile(5)] in the current working directory. When +adding a [`Gemfile(5)`][Gemfile(5)] to a gem with a gemspec, the `--gemspec` option will +automatically add each dependency listed in the gemspec file to the newly +created [`Gemfile(5)`][Gemfile(5)]. + +## OPTIONS + +* `--gemspec`: + Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)] +* `--gemfile`: + Use the specified name for the gemfile instead of `Gemfile` + +## FILES + +Included in the default [`Gemfile(5)`][Gemfile(5)] +generated is the line `# frozen_string_literal: true`. This is a magic comment +supported for the first time in Ruby 2.3. The presence of this line +results in all string literals in the file being implicitly frozen. + +## SEE ALSO + +[Gemfile(5)](https://bundler.io/man/gemfile.5.html) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1 new file mode 100644 index 00000000..c7269db3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1 @@ -0,0 +1,23 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-INJECT" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile +.SH "SYNOPSIS" +\fBbundle inject\fR [GEM] [VERSION] +.SH "DESCRIPTION" +Adds the named gem(s) with their version requirements to the resolved [\fBGemfile(5)\fR][Gemfile(5)]\. +.P +This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn't listed yet\. +.P +Example: +.IP "" 4 +.nf +bundle install +bundle inject 'rack' '> 0' +.fi +.IP "" 0 +.P +This will inject the 'rack' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\. +.P +The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 3\.0\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1.ronn new file mode 100644 index 00000000..95704edd --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-inject.1.ronn @@ -0,0 +1,24 @@ +bundle-inject(1) -- Add named gem(s) with version requirements to Gemfile +========================================================================= + +## SYNOPSIS + +`bundle inject` [GEM] [VERSION] + +## DESCRIPTION + +Adds the named gem(s) with their version requirements to the resolved +[`Gemfile(5)`][Gemfile(5)]. + +This command will add the gem to both your [`Gemfile(5)`][Gemfile(5)] and Gemfile.lock if it +isn't listed yet. + +Example: + + bundle install + bundle inject 'rack' '> 0' + +This will inject the 'rack' gem with a version greater than 0 in your +[`Gemfile(5)`][Gemfile(5)] and Gemfile.lock. + +The `bundle inject` command was deprecated in Bundler 2.1 and will be removed in Bundler 3.0. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1 new file mode 100644 index 00000000..3fa1a467 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1 @@ -0,0 +1,215 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-INSTALL" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile +.SH "SYNOPSIS" +\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-prefer\-local] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-without=GROUP[ GROUP\|\.\|\.\|\.]] +.SH "DESCRIPTION" +Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\. +.P +If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\. +.P +If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\. +.SH "OPTIONS" +The \fB\-\-clean\fR, \fB\-\-deployment\fR, \fB\-\-frozen\fR, \fB\-\-no\-prune\fR, \fB\-\-path\fR, \fB\-\-shebang\fR, \fB\-\-system\fR, \fB\-\-without\fR and \fB\-\-with\fR options are deprecated because they only make sense if they are applied to every subsequent \fBbundle install\fR run automatically and that requires \fBbundler\fR to silently remember them\. Since \fBbundler\fR will no longer remember CLI flags in future versions, \fBbundle config\fR (see bundle\-config(1)) should be used to apply them permanently\. +.TP +\fB\-\-binstubs[=]\fR +Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in \fBbin/\fR\. This lets you link the binstub inside of an application to the exact gem version the application needs\. +.IP +Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. +.TP +\fB\-\-clean\fR +On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don't worry, gems currently in use will not be removed\. +.IP +This option is deprecated in favor of the \fBclean\fR setting\. +.TP +\fB\-\-deployment\fR +In \fIdeployment mode\fR, Bundler will 'roll\-out' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\. +.IP +This option is deprecated in favor of the \fBdeployment\fR setting\. +.TP +\fB\-\-redownload\fR +Force download every gem, even if the required versions are already available locally\. +.TP +\fB\-\-frozen\fR +Do not allow the Gemfile\.lock to be updated after this install\. Exits non\-zero if there are going to be changes to the Gemfile\.lock\. +.IP +This option is deprecated in favor of the \fBfrozen\fR setting\. +.TP +\fB\-\-full\-index\fR +Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\. +.TP +\fB\-\-gemfile=\fR +The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. +.TP +\fB\-\-jobs=[]\fR, \fB\-j[]\fR +The maximum number of parallel download and install jobs\. The default is the number of available processors\. +.TP +\fB\-\-local\fR +Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. +.TP +\fB\-\-prefer\-local\fR +Force using locally installed gems, or gems already present in Rubygems' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\. +.TP +\fB\-\-no\-cache\fR +Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. +.TP +\fB\-\-no\-prune\fR +Don't remove stale gems from the cache when the installation finishes\. +.IP +This option is deprecated in favor of the \fBno_prune\fR setting\. +.TP +\fB\-\-path=\fR +The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. +.IP +This option is deprecated in favor of the \fBpath\fR setting\. +.TP +\fB\-\-quiet\fR +Do not print progress information to the standard output\. Instead, Bundler will exit using a status code (\fB$?\fR)\. +.TP +\fB\-\-retry=[]\fR +Retry failed network or git requests for \fInumber\fR times\. +.TP +\fB\-\-shebang=\fR +Uses the specified ruby executable (usually \fBruby\fR) to execute the scripts created with \fB\-\-binstubs\fR\. In addition, if you use \fB\-\-binstubs\fR together with \fB\-\-shebang jruby\fR these executables will be changed to execute \fBjruby\fR instead\. +.IP +This option is deprecated in favor of the \fBshebang\fR setting\. +.TP +\fB\-\-standalone[=]\fR +Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler's own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\. +.TP +\fB\-\-system\fR +Installs the gems specified in the bundle to the system's Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\. +.IP +This option is deprecated in favor of the \fBsystem\fR setting\. +.TP +\fB\-\-trust\-policy=[]\fR +Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\. +.TP +\fB\-\-with=\fR +A space\-separated list of groups referencing gems to install\. If an optional group is given it is installed\. If a group is given that is in the remembered list of groups given to \-\-without, it is removed from that list\. +.IP +This option is deprecated in favor of the \fBwith\fR setting\. +.TP +\fB\-\-without=\fR +A space\-separated list of groups referencing gems to skip during installation\. If a group is given that is in the remembered list of groups given to \-\-with, it is removed from that list\. +.IP +This option is deprecated in favor of the \fBwithout\fR setting\. +.SH "DEPLOYMENT MODE" +Bundler's defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\. +.IP "1." 4 +A \fBGemfile\.lock\fR is required\. +.IP +To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\. +.IP +This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\. +.IP "2." 4 +The \fBGemfile\.lock\fR must be up to date +.IP +In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\. +.IP +In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\. +.IP "3." 4 +Gems are installed to \fBvendor/bundle\fR not your default system location +.IP +In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system\. +.IP +In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\. +.IP +As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fB\-\-path\fR option\. +.IP "" 0 +.SH "INSTALLING GROUPS" +By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\. +.P +However, you can explicitly tell Bundler to skip installing certain groups with the \fB\-\-without\fR option\. This option takes a space\-separated list of groups\. +.P +While the \fB\-\-without\fR option will skip \fIinstalling\fR the gems in the specified groups, it will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\. +.P +This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\. +.P +\fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR +.P +For a simple illustration, consider the following Gemfile(5): +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'sinatra' + +group :production do + gem 'rack\-perftools\-profiler' +end +.fi +.IP "" 0 +.P +In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\. +.P +When you run \fBbundle install \-\-without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\. +.P +This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\. +.P +This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\. +.SH "THE GEMFILE\.LOCK" +When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\. +.P +Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\. +.P +Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\. +.P +As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\. +.P +When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\. +.SH "CONSERVATIVE UPDATING" +When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\. +.P +In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\. +.P +Let's take a look at an example\. Here's your original Gemfile(5): +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'actionpack', '2\.3\.8' +gem 'activemerchant' +.fi +.IP "" 0 +.P +In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\. +.P +When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\. +.P +Next, you modify your Gemfile(5) to: +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'actionpack', '3\.0\.0\.rc' +gem 'activemerchant' +.fi +.IP "" 0 +.P +The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\. +.P +When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements: +.TP +\fBactivesupport 2\.3\.8\fR +also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated +.TP +\fBrack ~> 1\.1\.0\fR +not currently being used to satisfy another dependency +.P +Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\. +.P +Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\. +.P +To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\. +.P +\fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\. +.SH "SEE ALSO" +.IP "\(bu" 4 +Gem install docs \fIhttps://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR +.IP "\(bu" 4 +Rubygems signing docs \fIhttps://guides\.rubygems\.org/security/\fR +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1.ronn new file mode 100644 index 00000000..ed8169de --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-install.1.ronn @@ -0,0 +1,383 @@ +bundle-install(1) -- Install the dependencies specified in your Gemfile +======================================================================= + +## SYNOPSIS + +`bundle install` [--binstubs[=DIRECTORY]] + [--clean] + [--deployment] + [--frozen] + [--full-index] + [--gemfile=GEMFILE] + [--jobs=NUMBER] + [--local] + [--no-cache] + [--no-prune] + [--path PATH] + [--prefer-local] + [--quiet] + [--redownload] + [--retry=NUMBER] + [--shebang] + [--standalone[=GROUP[ GROUP...]]] + [--system] + [--trust-policy=POLICY] + [--with=GROUP[ GROUP...]] + [--without=GROUP[ GROUP...]] + +## DESCRIPTION + +Install the gems specified in your Gemfile(5). If this is the first +time you run bundle install (and a `Gemfile.lock` does not exist), +Bundler will fetch all remote sources, resolve dependencies and +install all needed gems. + +If a `Gemfile.lock` does exist, and you have not updated your Gemfile(5), +Bundler will fetch all remote sources, but use the dependencies +specified in the `Gemfile.lock` instead of resolving dependencies. + +If a `Gemfile.lock` does exist, and you have updated your Gemfile(5), +Bundler will use the dependencies in the `Gemfile.lock` for all gems +that you did not update, but will re-resolve the dependencies of +gems that you did update. You can find more information about this +update process below under [CONSERVATIVE UPDATING][]. + +## OPTIONS + +The `--clean`, `--deployment`, `--frozen`, `--no-prune`, `--path`, `--shebang`, +`--system`, `--without` and `--with` options are deprecated because they only +make sense if they are applied to every subsequent `bundle install` run +automatically and that requires `bundler` to silently remember them. Since +`bundler` will no longer remember CLI flags in future versions, `bundle config` +(see bundle-config(1)) should be used to apply them permanently. + +* `--binstubs[=]`: + Binstubs are scripts that wrap around executables. Bundler creates a small Ruby + file (a binstub) that loads Bundler, runs the command, and puts it in `bin/`. + This lets you link the binstub inside of an application to the exact gem + version the application needs. + + Creates a directory (defaults to `~/bin`) and places any executables from the + gem there. These executables run in Bundler's context. If used, you might add + this directory to your environment's `PATH` variable. For instance, if the + `rails` gem comes with a `rails` executable, this flag will create a + `bin/rails` executable that ensures that all referred dependencies will be + resolved using the bundled gems. + +* `--clean`: + On finishing the installation Bundler is going to remove any gems not present + in the current Gemfile(5). Don't worry, gems currently in use will not be + removed. + + This option is deprecated in favor of the `clean` setting. + +* `--deployment`: + In [deployment mode][DEPLOYMENT MODE], Bundler will 'roll-out' the bundle for + production or CI use. Please check carefully if you want to have this option + enabled in your development environment. + + This option is deprecated in favor of the `deployment` setting. + +* `--redownload`: + Force download every gem, even if the required versions are already available + locally. + +* `--frozen`: + Do not allow the Gemfile.lock to be updated after this install. Exits + non-zero if there are going to be changes to the Gemfile.lock. + + This option is deprecated in favor of the `frozen` setting. + +* `--full-index`: + Bundler will not call Rubygems' API endpoint (default) but download and cache + a (currently big) index file of all gems. Performance can be improved for + large bundles that seldom change by enabling this option. + +* `--gemfile=`: + The location of the Gemfile(5) which Bundler should use. This defaults + to a Gemfile(5) in the current working directory. In general, Bundler + will assume that the location of the Gemfile(5) is also the project's + root and will try to find `Gemfile.lock` and `vendor/cache` relative + to this location. + +* `--jobs=[]`, `-j[]`: + The maximum number of parallel download and install jobs. The default is the + number of available processors. + +* `--local`: + Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the + gems already present in Rubygems' cache or in `vendor/cache`. Note that if an + appropriate platform-specific gem exists on `rubygems.org` it will not be + found. + +* `--prefer-local`: + Force using locally installed gems, or gems already present in Rubygems' cache + or in `vendor/cache`, when resolving, even if newer versions are available + remotely. Only attempt to connect to `rubygems.org` for gems that are not + present locally. + +* `--no-cache`: + Do not update the cache in `vendor/cache` with the newly bundled gems. This + does not remove any gems in the cache but keeps the newly bundled gems from + being cached during the install. + +* `--no-prune`: + Don't remove stale gems from the cache when the installation finishes. + + This option is deprecated in favor of the `no_prune` setting. + +* `--path=`: + The location to install the specified gems to. This defaults to Rubygems' + setting. Bundler shares this location with Rubygems, `gem install ...` will + have gem installed there, too. Therefore, gems installed without a + `--path ...` setting will show up by calling `gem list`. Accordingly, gems + installed to other locations will not get listed. + + This option is deprecated in favor of the `path` setting. + +* `--quiet`: + Do not print progress information to the standard output. Instead, Bundler + will exit using a status code (`$?`). + +* `--retry=[]`: + Retry failed network or git requests for times. + +* `--shebang=`: + Uses the specified ruby executable (usually `ruby`) to execute the scripts + created with `--binstubs`. In addition, if you use `--binstubs` together with + `--shebang jruby` these executables will be changed to execute `jruby` + instead. + + This option is deprecated in favor of the `shebang` setting. + +* `--standalone[=]`: + Makes a bundle that can work without depending on Rubygems or Bundler at + runtime. A space separated list of groups to install has to be specified. + Bundler creates a directory named `bundle` and installs the bundle there. It + also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup + in the manner required. Using this option implicitly sets `path`, which is a + [remembered option][REMEMBERED OPTIONS]. + +* `--system`: + Installs the gems specified in the bundle to the system's Rubygems location. + This overrides any previous configuration of `--path`. + + This option is deprecated in favor of the `system` setting. + +* `--trust-policy=[]`: + Apply the Rubygems security policy , where policy is one of + `HighSecurity`, `MediumSecurity`, `LowSecurity`, `AlmostNoSecurity`, or + `NoSecurity`. For more details, please see the Rubygems signing documentation + linked below in [SEE ALSO][]. + +* `--with=`: + A space-separated list of groups referencing gems to install. If an + optional group is given it is installed. If a group is given that is + in the remembered list of groups given to --without, it is removed + from that list. + + This option is deprecated in favor of the `with` setting. + +* `--without=`: + A space-separated list of groups referencing gems to skip during installation. + If a group is given that is in the remembered list of groups given + to --with, it is removed from that list. + + This option is deprecated in favor of the `without` setting. + +## DEPLOYMENT MODE + +Bundler's defaults are optimized for development. To switch to +defaults optimized for deployment and for CI, use the `--deployment` +flag. Do not activate deployment mode on development machines, as it +will cause an error when the Gemfile(5) is modified. + +1. A `Gemfile.lock` is required. + + To ensure that the same versions of the gems you developed with + and tested with are also used in deployments, a `Gemfile.lock` + is required. + + This is mainly to ensure that you remember to check your + `Gemfile.lock` into version control. + +2. The `Gemfile.lock` must be up to date + + In development, you can modify your Gemfile(5) and re-run + `bundle install` to [conservatively update][CONSERVATIVE UPDATING] + your `Gemfile.lock` snapshot. + + In deployment, your `Gemfile.lock` should be up-to-date with + changes made in your Gemfile(5). + +3. Gems are installed to `vendor/bundle` not your default system location + + In development, it's convenient to share the gems used in your + application with other applications and other scripts that run on + the system. + + In deployment, isolation is a more important default. In addition, + the user deploying the application may not have permission to install + gems to the system, or the web server may not have permission to + read them. + + As a result, `bundle install --deployment` installs gems to + the `vendor/bundle` directory in the application. This may be + overridden using the `--path` option. + +## INSTALLING GROUPS + +By default, `bundle install` will install all gems in all groups +in your Gemfile(5), except those declared for a different platform. + +However, you can explicitly tell Bundler to skip installing +certain groups with the `--without` option. This option takes +a space-separated list of groups. + +While the `--without` option will skip _installing_ the gems in the +specified groups, it will still _download_ those gems and use them to +resolve the dependencies of every gem in your Gemfile(5). + +This is so that installing a different set of groups on another + machine (such as a production server) will not change the +gems and versions that you have already developed and tested against. + +`Bundler offers a rock-solid guarantee that the third-party +code you are running in development and testing is also the +third-party code you are running in production. You can choose +to exclude some of that code in different environments, but you +will never be caught flat-footed by different versions of +third-party code being used in different environments.` + +For a simple illustration, consider the following Gemfile(5): + + source 'https://rubygems.org' + + gem 'sinatra' + + group :production do + gem 'rack-perftools-profiler' + end + +In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while +`rack-perftools-profiler` depends on 1.x (`~> 1.0`). + +When you run `bundle install --without production` in development, we +look at the dependencies of `rack-perftools-profiler` as well. That way, +you do not spend all your time developing against Rack 2.0, using new +APIs unavailable in Rack 1.x, only to have Bundler switch to Rack 1.2 +when the `production` group _is_ used. + +This should not cause any problems in practice, because we do not +attempt to `install` the gems in the excluded groups, and only evaluate +as part of the dependency resolution process. + +This also means that you cannot include different versions of the same +gem in different groups, because doing so would result in different +sets of dependencies used in development and production. Because of +the vagaries of the dependency resolution process, this usually +affects more than the gems you list in your Gemfile(5), and can +(surprisingly) radically change the gems you are using. + +## THE GEMFILE.LOCK + +When you run `bundle install`, Bundler will persist the full names +and versions of all gems that you used (including dependencies of +the gems specified in the Gemfile(5)) into a file called `Gemfile.lock`. + +Bundler uses this file in all subsequent calls to `bundle install`, +which guarantees that you always use the same exact code, even +as your application moves across machines. + +Because of the way dependency resolution works, even a +seemingly small change (for instance, an update to a point-release +of a dependency of a gem in your Gemfile(5)) can result in radically +different gems being needed to satisfy all dependencies. + +As a result, you `SHOULD` check your `Gemfile.lock` into version +control, in both applications and gems. If you do not, every machine that +checks out your repository (including your production server) will resolve all +dependencies again, which will result in different versions of +third-party code being used if `any` of the gems in the Gemfile(5) +or any of their dependencies have been updated. + +When Bundler first shipped, the `Gemfile.lock` was included in the `.gitignore` +file included with generated gems. Over time, however, it became clear that +this practice forces the pain of broken dependencies onto new contributors, +while leaving existing contributors potentially unaware of the problem. Since +`bundle install` is usually the first step towards a contribution, the pain of +broken dependencies would discourage new contributors from contributing. As a +result, we have revised our guidance for gem authors to now recommend checking +in the lock for gems. + +## CONSERVATIVE UPDATING + +When you make a change to the Gemfile(5) and then run `bundle install`, +Bundler will update only the gems that you modified. + +In other words, if a gem that you `did not modify` worked before +you called `bundle install`, it will continue to use the exact +same versions of all dependencies as it used before the update. + +Let's take a look at an example. Here's your original Gemfile(5): + + source 'https://rubygems.org' + + gem 'actionpack', '2.3.8' + gem 'activemerchant' + +In this case, both `actionpack` and `activemerchant` depend on +`activesupport`. The `actionpack` gem depends on `activesupport 2.3.8` +and `rack ~> 1.1.0`, while the `activemerchant` gem depends on +`activesupport >= 2.3.2`, `braintree >= 2.0.0`, and `builder >= 2.0.0`. + +When the dependencies are first resolved, Bundler will select +`activesupport 2.3.8`, which satisfies the requirements of both +gems in your Gemfile(5). + +Next, you modify your Gemfile(5) to: + + source 'https://rubygems.org' + + gem 'actionpack', '3.0.0.rc' + gem 'activemerchant' + +The `actionpack 3.0.0.rc` gem has a number of new dependencies, +and updates the `activesupport` dependency to `= 3.0.0.rc` and +the `rack` dependency to `~> 1.2.1`. + +When you run `bundle install`, Bundler notices that you changed +the `actionpack` gem, but not the `activemerchant` gem. It +evaluates the gems currently being used to satisfy its requirements: + + * `activesupport 2.3.8`: + also used to satisfy a dependency in `activemerchant`, + which is not being updated + * `rack ~> 1.1.0`: + not currently being used to satisfy another dependency + +Because you did not explicitly ask to update `activemerchant`, +you would not expect it to suddenly stop working after updating +`actionpack`. However, satisfying the new `activesupport 3.0.0.rc` +dependency of actionpack requires updating one of its dependencies. + +Even though `activemerchant` declares a very loose dependency +that theoretically matches `activesupport 3.0.0.rc`, Bundler treats +gems in your Gemfile(5) that have not changed as an atomic unit +together with their dependencies. In this case, the `activemerchant` +dependency is treated as `activemerchant 1.7.1 + activesupport 2.3.8`, +so `bundle install` will report that it cannot update `actionpack`. + +To explicitly update `actionpack`, including its dependencies +which other gems in the Gemfile(5) still depend on, run +`bundle update actionpack` (see `bundle update(1)`). + +`Summary`: In general, after making a change to the Gemfile(5) , you +should first try to run `bundle install`, which will guarantee that no +other gem in the Gemfile(5) is impacted by the change. If that +does not work, run [bundle update(1)](bundle-update.1.html). + +## SEE ALSO + +* [Gem install docs](https://guides.rubygems.org/rubygems-basics/#installing-gems) +* [Rubygems signing docs](https://guides.rubygems.org/security/) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1 new file mode 100644 index 00000000..f91fd957 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1 @@ -0,0 +1,35 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-LIST" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-list\fR \- List all the gems in the bundle +.SH "SYNOPSIS" +\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-only\-group=GROUP[ GROUP\|\.\|\.\|\.]] +.SH "DESCRIPTION" +Prints a list of all the gems in the bundle including their version\. +.P +Example: +.P +bundle list \-\-name\-only +.P +bundle list \-\-paths +.P +bundle list \-\-without\-group test +.P +bundle list \-\-only\-group dev +.P +bundle list \-\-only\-group dev test \-\-paths +.SH "OPTIONS" +.TP +\fB\-\-name\-only\fR +Print only the name of each gem\. +.TP +\fB\-\-paths\fR +Print the path to each gem in the bundle\. +.TP +\fB\-\-without\-group=\fR +A space\-separated list of groups of gems to skip during printing\. +.TP +\fB\-\-only\-group=\fR +A space\-separated list of groups of gems to print\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1.ronn new file mode 100644 index 00000000..dc058ecd --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-list.1.ronn @@ -0,0 +1,33 @@ +bundle-list(1) -- List all the gems in the bundle +========================================================================= + +## SYNOPSIS + +`bundle list` [--name-only] [--paths] [--without-group=GROUP[ GROUP...]] [--only-group=GROUP[ GROUP...]] + +## DESCRIPTION + +Prints a list of all the gems in the bundle including their version. + +Example: + +bundle list --name-only + +bundle list --paths + +bundle list --without-group test + +bundle list --only-group dev + +bundle list --only-group dev test --paths + +## OPTIONS + +* `--name-only`: + Print only the name of each gem. +* `--paths`: + Print the path to each gem in the bundle. +* `--without-group=`: + A space-separated list of groups of gems to skip during printing. +* `--only-group=`: + A space-separated list of groups of gems to print. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1 new file mode 100644 index 00000000..f992f5ee --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1 @@ -0,0 +1,60 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-LOCK" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing +.SH "SYNOPSIS" +\fBbundle lock\fR [\-\-update] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-add\-platform] [\-\-remove\-platform] [\-\-patch] [\-\-minor] [\-\-major] [\-\-strict] [\-\-conservative] +.SH "DESCRIPTION" +Lock the gems specified in Gemfile\. +.SH "OPTIONS" +.TP +\fB\-\-update=<*gems>\fR +Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\. +.TP +\fB\-\-local\fR +Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. +.TP +\fB\-\-print\fR +Prints the lockfile to STDOUT instead of writing to the file system\. +.TP +\fB\-\-lockfile=\fR +The path where the lockfile should be written to\. +.TP +\fB\-\-full\-index\fR +Fall back to using the single\-file index of all gems\. +.TP +\fB\-\-add\-platform\fR +Add a new platform to the lockfile, re\-resolving for the addition of that platform\. +.TP +\fB\-\-remove\-platform\fR +Remove a platform from the lockfile\. +.TP +\fB\-\-patch\fR +If updating, prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +If updating, prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +If updating, prefer updating to next major version (default)\. +.TP +\fB\-\-strict\fR +If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\. +.TP +\fB\-\-conservative\fR +If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\. +.SH "UPDATING ALL GEMS" +If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. +.SH "UPDATING A LIST OF GEMS" +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.P +For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\. +.P +Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.SH "SUPPORTING OTHER PLATFORMS" +If you want your bundle to support platforms other than the one you're running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\. +.P +For a full explanation of gem platforms, see \fBgem help platform\fR\. +.SH "PATCH LEVEL OPTIONS" +See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1.ronn new file mode 100644 index 00000000..3aa5920f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-lock.1.ronn @@ -0,0 +1,94 @@ +bundle-lock(1) -- Creates / Updates a lockfile without installing +================================================================= + +## SYNOPSIS + +`bundle lock` [--update] + [--local] + [--print] + [--lockfile=PATH] + [--full-index] + [--add-platform] + [--remove-platform] + [--patch] + [--minor] + [--major] + [--strict] + [--conservative] + +## DESCRIPTION + +Lock the gems specified in Gemfile. + +## OPTIONS + +* `--update=<*gems>`: + Ignores the existing lockfile. Resolve then updates lockfile. Taking a list + of gems or updating all gems if no list is given. + +* `--local`: + Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the + gems already present in Rubygems' cache or in `vendor/cache`. Note that if a + appropriate platform-specific gem exists on `rubygems.org` it will not be + found. + +* `--print`: + Prints the lockfile to STDOUT instead of writing to the file system. + +* `--lockfile=`: + The path where the lockfile should be written to. + +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--add-platform`: + Add a new platform to the lockfile, re-resolving for the addition of that + platform. + +* `--remove-platform`: + Remove a platform from the lockfile. + +* `--patch`: + If updating, prefer updating only to next patch version. + +* `--minor`: + If updating, prefer updating only to next minor version. + +* `--major`: + If updating, prefer updating to next major version (default). + +* `--strict`: + If updating, do not allow any gem to be updated past latest --patch | --minor | --major. + +* `--conservative`: + If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated. + +## UPDATING ALL GEMS + +If you run `bundle lock` with `--update` option without list of gems, bundler will +ignore any previously installed gems and resolve all dependencies again based +on the latest versions of all gems available in the sources. + +## UPDATING A LIST OF GEMS + +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of +the gems that you specified locked to the versions in the `Gemfile.lock`. + +For instance, you only want to update `nokogiri`, run `bundle lock --update nokogiri`. + +Bundler will update `nokogiri` and any of its dependencies, but leave the rest of the +gems that you specified locked to the versions in the `Gemfile.lock`. + +## SUPPORTING OTHER PLATFORMS + +If you want your bundle to support platforms other than the one you're running +locally, you can run `bundle lock --add-platform PLATFORM` to add PLATFORM to +the lockfile, force bundler to re-resolve and consider the new platform when +picking gems, all without needing to have a machine that matches PLATFORM handy +to install those platform-specific gems on. + +For a full explanation of gem platforms, see `gem help platform`. + +## PATCH LEVEL OPTIONS + +See [bundle update(1)](bundle-update.1.html) for details. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1 new file mode 100644 index 00000000..53d35415 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1 @@ -0,0 +1,32 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-OPEN" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle +.SH "SYNOPSIS" +\fBbundle open\fR [GEM] [\-\-path=PATH] +.SH "DESCRIPTION" +Opens the source directory of the provided GEM in your editor\. +.P +For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\. +.P +Example: +.IP "" 4 +.nf +bundle open 'rack' +.fi +.IP "" 0 +.P +Will open the source directory for the 'rack' gem in your bundle\. +.IP "" 4 +.nf +bundle open 'rack' \-\-path 'README\.md' +.fi +.IP "" 0 +.P +Will open the README\.md file of the 'rack' gem source in your bundle\. +.SH "OPTIONS" +.TP +\fB\-\-path\fR +Specify GEM source relative path to open\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1.ronn new file mode 100644 index 00000000..a857f3a9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-open.1.ronn @@ -0,0 +1,27 @@ +bundle-open(1) -- Opens the source directory for a gem in your bundle +===================================================================== + +## SYNOPSIS + +`bundle open` [GEM] [--path=PATH] + +## DESCRIPTION + +Opens the source directory of the provided GEM in your editor. + +For this to work the `EDITOR` or `BUNDLER_EDITOR` environment variable has to +be set. + +Example: + + bundle open 'rack' + +Will open the source directory for the 'rack' gem in your bundle. + + bundle open 'rack' --path 'README.md' + +Will open the README.md file of the 'rack' gem source in your bundle. + +## OPTIONS +* `--path`: + Specify GEM source relative path to open. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1 new file mode 100644 index 00000000..f79eff5a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1 @@ -0,0 +1,100 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-OUTDATED" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-outdated\fR \- List installed gems with newer versions available +.SH "SYNOPSIS" +\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] +.SH "DESCRIPTION" +Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\. +.SH "OPTIONS" +.TP +\fB\-\-local\fR +Do not attempt to fetch gems remotely and use the gem cache instead\. +.TP +\fB\-\-pre\fR +Check for newer pre\-release gems\. +.TP +\fB\-\-source\fR +Check against a specific source\. +.TP +\fB\-\-strict\fR +Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (\-\-patch, \-\-minor, \-\-major)\. +.TP +\fB\-\-parseable\fR, \fB\-\-porcelain\fR +Use minimal formatting for more parseable output\. +.TP +\fB\-\-group\fR +List gems from a specific group\. +.TP +\fB\-\-groups\fR +List gems organized by groups\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-filter\-major\fR +Only list major newer versions\. +.TP +\fB\-\-filter\-minor\fR +Only list minor newer versions\. +.TP +\fB\-\-filter\-patch\fR +Only list patch newer versions\. +.TP +\fB\-\-only\-explicit\fR +Only list gems specified in your Gemfile, not their dependencies\. +.SH "PATCH LEVEL OPTIONS" +See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. +.SH "FILTERING OUTPUT" +The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\. +.P +If the regular output shows the following: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test +* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default +* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test +.fi +.IP "" 0 +.P +\fB\-\-filter\-major\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups +* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default +.fi +.IP "" 0 +.P +\fB\-\-filter\-minor\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups +* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test +.fi +.IP "" 0 +.P +\fB\-\-filter\-patch\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test +.fi +.IP "" 0 +.P +Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test +.fi +.IP "" 0 +.P +Combining all three \fBfilter\fR options would be the same result as providing none of them\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1.ronn new file mode 100644 index 00000000..4ac65d05 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-outdated.1.ronn @@ -0,0 +1,106 @@ +bundle-outdated(1) -- List installed gems with newer versions available +======================================================================= + +## SYNOPSIS + +`bundle outdated` [GEM] [--local] + [--pre] + [--source] + [--strict] + [--parseable | --porcelain] + [--group=GROUP] + [--groups] + [--patch|--minor|--major] + [--filter-major] + [--filter-minor] + [--filter-patch] + [--only-explicit] + +## DESCRIPTION + +Outdated lists the names and versions of gems that have a newer version available +in the given source. Calling outdated with [GEM [GEM]] will only check for newer +versions of the given gems. Prerelease gems are ignored by default. If your gems +are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. + +## OPTIONS + +* `--local`: + Do not attempt to fetch gems remotely and use the gem cache instead. + +* `--pre`: + Check for newer pre-release gems. + +* `--source`: + Check against a specific source. + +* `--strict`: + Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (--patch, --minor, --major). + +* `--parseable`, `--porcelain`: + Use minimal formatting for more parseable output. + +* `--group`: + List gems from a specific group. + +* `--groups`: + List gems organized by groups. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--patch`: + Prefer updating only to next patch version. + +* `--filter-major`: + Only list major newer versions. + +* `--filter-minor`: + Only list minor newer versions. + +* `--filter-patch`: + Only list patch newer versions. + +* `--only-explicit`: + Only list gems specified in your Gemfile, not their dependencies. + +## PATCH LEVEL OPTIONS + +See [bundle update(1)](bundle-update.1.html) for details. + +## FILTERING OUTPUT + +The 3 filtering options do not affect the resolution of versions, merely what versions are shown +in the output. + +If the regular output shows the following: + + * Gem Current Latest Requested Groups + * faker 1.6.5 1.6.6 ~> 1.4 development, test + * hashie 1.2.0 3.4.6 = 1.2.0 default + * headless 2.2.3 2.3.1 = 2.2.3 test + +`--filter-major` would only show: + + * Gem Current Latest Requested Groups + * hashie 1.2.0 3.4.6 = 1.2.0 default + +`--filter-minor` would only show: + + * Gem Current Latest Requested Groups + * headless 2.2.3 2.3.1 = 2.2.3 test + +`--filter-patch` would only show: + + * Gem Current Latest Requested Groups + * faker 1.6.5 1.6.6 ~> 1.4 development, test + +Filter options can be combined. `--filter-minor` and `--filter-patch` would show: + + * Gem Current Latest Requested Groups + * faker 1.6.5 1.6.6 ~> 1.4 development, test + +Combining all three `filter` options would be the same result as providing none of them. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1 new file mode 100644 index 00000000..d2133ec4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1 @@ -0,0 +1,49 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-PLATFORM" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-platform\fR \- Displays platform compatibility information +.SH "SYNOPSIS" +\fBbundle platform\fR [\-\-ruby] +.SH "DESCRIPTION" +\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. +.P +For instance, using this Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +ruby "3\.1\.2" + +gem "rack" +.fi +.IP "" 0 +.P +If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output: +.IP "" 4 +.nf +Your platform is: x86_64\-linux + +Your app has gems that work on these platforms: +* arm64\-darwin\-21 +* ruby +* x64\-mingw\-ucrt +* x86_64\-linux + +Your Gemfile specifies a Ruby version requirement: +* ruby 3\.1\.2 + +Your current platform satisfies the Ruby version requirement\. +.fi +.IP "" 0 +.P +\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn't match the running Ruby VM, it tells you what part does not\. +.SH "OPTIONS" +.TP +\fB\-\-ruby\fR +It will display the ruby directive information, so you don't have to parse it from the Gemfile(5)\. +.SH "SEE ALSO" +.IP "\(bu" 4 +bundle\-lock(1) \fIbundle\-lock\.1\.html\fR +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1.ronn new file mode 100644 index 00000000..744acd1b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-platform.1.ronn @@ -0,0 +1,49 @@ +bundle-platform(1) -- Displays platform compatibility information +================================================================= + +## SYNOPSIS + +`bundle platform` [--ruby] + +## DESCRIPTION + +`platform` displays information from your Gemfile, Gemfile.lock, and Ruby +VM about your platform. + +For instance, using this Gemfile(5): + + source "https://rubygems.org" + + ruby "3.1.2" + + gem "rack" + +If you run `bundle platform` on Ruby 3.1.2, it displays the following output: + + Your platform is: x86_64-linux + + Your app has gems that work on these platforms: + * arm64-darwin-21 + * ruby + * x64-mingw-ucrt + * x86_64-linux + + Your Gemfile specifies a Ruby version requirement: + * ruby 3.1.2 + + Your current platform satisfies the Ruby version requirement. + +`platform` lists all the platforms in your `Gemfile.lock` as well as the +`ruby` directive if applicable from your Gemfile(5). It also lets you know +if the `ruby` directive requirement has been met. If `ruby` directive doesn't +match the running Ruby VM, it tells you what part does not. + +## OPTIONS + +* `--ruby`: + It will display the ruby directive information, so you don't have to + parse it from the Gemfile(5). + +## SEE ALSO + +* [bundle-lock(1)](bundle-lock.1.html) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1 new file mode 100644 index 00000000..cbdfac11 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1 @@ -0,0 +1,58 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-PLUGIN" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-plugin\fR \- Manage Bundler plugins +.SH "SYNOPSIS" +\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR] [\-\-path=\fIpath\fR] +.br +\fBbundle plugin\fR uninstall PLUGINS +.br +\fBbundle plugin\fR list +.br +\fBbundle plugin\fR help [COMMAND] +.SH "DESCRIPTION" +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler\. +.SH "SUB\-COMMANDS" +.SS "install" +Install the given plugin(s)\. +.TP +\fBbundle plugin install bundler\-graph\fR +Install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. The global source, specified in source in Gemfile is ignored\. +.TP +\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR +Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\. +.TP +\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR +You can specify the version of the gem via \fB\-\-version\fR\. +.TP +\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR +Install bundler\-graph gem from Git repository\. You can use standard Git URLs like: +.IP +\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR +.br +\fBhttp[s]://host\.xz[:port]/path/to/repo\.git\fR +.br +\fB/path/to/repo\fR +.br +\fBfile:///path/to/repo\fR +.IP +When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\. +.TP +\fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR +Install bundler\-graph gem from a local path\. +.SS "uninstall" +Uninstall the plugin(s) specified in PLUGINS\. +.SS "list" +List the installed plugins and available commands\. +.P +No options\. +.SS "help" +Describe subcommands or one specific subcommand\. +.P +No options\. +.SH "SEE ALSO" +.IP "\(bu" 4 +How to write a Bundler plugin \fIhttps://bundler\.io/guides/bundler_plugins\.html\fR +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1.ronn new file mode 100644 index 00000000..b0a34660 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-plugin.1.ronn @@ -0,0 +1,63 @@ +bundle-plugin(1) -- Manage Bundler plugins +========================================== + +## SYNOPSIS + +`bundle plugin` install PLUGINS [--source=] [--version=] + [--git=] [--branch=|--ref=] + [--path=]
+`bundle plugin` uninstall PLUGINS
+`bundle plugin` list
+`bundle plugin` help [COMMAND] + +## DESCRIPTION + +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler. + +## SUB-COMMANDS + +### install + +Install the given plugin(s). + +* `bundle plugin install bundler-graph`: + Install bundler-graph gem from globally configured sources (defaults to RubyGems.org). The global source, specified in source in Gemfile is ignored. + +* `bundle plugin install bundler-graph --source https://example.com`: + Install bundler-graph gem from example.com. The global source, specified in source in Gemfile is not considered. + +* `bundle plugin install bundler-graph --version 0.2.1`: + You can specify the version of the gem via `--version`. + +* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`: + Install bundler-graph gem from Git repository. You can use standard Git URLs like: + + `ssh://[user@]host.xz[:port]/path/to/repo.git`
+ `http[s]://host.xz[:port]/path/to/repo.git`
+ `/path/to/repo`
+ `file:///path/to/repo` + + When you specify `--git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use. + +* `bundle plugin install bundler-graph --path ../bundler-graph`: + Install bundler-graph gem from a local path. + +### uninstall + +Uninstall the plugin(s) specified in PLUGINS. + +### list + +List the installed plugins and available commands. + +No options. + +### help + +Describe subcommands or one specific subcommand. + +No options. + +## SEE ALSO + +* [How to write a Bundler plugin](https://bundler.io/guides/bundler_plugins.html) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1 new file mode 100644 index 00000000..faa04d76 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1 @@ -0,0 +1,23 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-PRISTINE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition +.SH "SYNOPSIS" +\fBbundle pristine\fR +.SH "DESCRIPTION" +\fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\. +.P +For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem's git repository as if one were installing from scratch\. +.P +Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from\. +.P +When is it practical to use \fBbundle pristine\fR? +.P +It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\. +.P +Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR? +.P +Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\. +.P +If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1.ronn new file mode 100644 index 00000000..e2d6b6a3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-pristine.1.ronn @@ -0,0 +1,34 @@ +bundle-pristine(1) -- Restores installed gems to their pristine condition +=========================================================================== + +## SYNOPSIS + +`bundle pristine` + +## DESCRIPTION + +`pristine` restores the installed gems in the bundle to their pristine condition +using the local gem cache from RubyGems. For git gems, a forced checkout will be performed. + +For further explanation, `bundle pristine` ignores unpacked files on disk. In other +words, this command utilizes the local `.gem` cache or the gem's git repository +as if one were installing from scratch. + +Note: the Bundler gem cannot be restored to its original state with `pristine`. +One also cannot use `bundle pristine` on gems with a 'path' option in the Gemfile, +because bundler has no original copy it can restore from. + +When is it practical to use `bundle pristine`? + +It comes in handy when a developer is debugging a gem. `bundle pristine` is a +great way to get rid of experimental changes to a gem that one may not want. + +Why use `bundle pristine` over `gem pristine --all`? + +Both commands are very similar. +For context: `bundle pristine`, without arguments, cleans all gems from the lockfile. +Meanwhile, `gem pristine --all` cleans all installed gems for that Ruby version. + +If a developer forgets which gems in their project they might +have been debugging, the Rubygems `gem pristine [GEMNAME]` command may be inconvenient. +One can avoid waiting for `gem pristine --all`, and instead run `bundle pristine`. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1 new file mode 100644 index 00000000..3f8cbbd9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1 @@ -0,0 +1,21 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-REMOVE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-remove\fR \- Removes gems from the Gemfile +.SH "SYNOPSIS" +\fBbundle remove [GEM [GEM \|\.\|\.\|\.]] [\-\-install]\fR +.SH "DESCRIPTION" +Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\. +.SH "OPTIONS" +.TP +\fB\-\-install\fR +Runs \fBbundle install\fR after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s)\. +.P +Example: +.P +bundle remove rails +.P +bundle remove rails rack +.P +bundle remove rails rack \-\-install diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1.ronn new file mode 100644 index 00000000..40a239b4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-remove.1.ronn @@ -0,0 +1,23 @@ +bundle-remove(1) -- Removes gems from the Gemfile +=========================================================================== + +## SYNOPSIS + +`bundle remove [GEM [GEM ...]] [--install]` + +## DESCRIPTION + +Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If a gem cannot be removed, a warning is printed. If a gem is already absent from the Gemfile, and error is raised. + +## OPTIONS + +* `--install`: + Runs `bundle install` after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s). + +Example: + +bundle remove rails + +bundle remove rails rack + +bundle remove rails rack --install diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1 new file mode 100644 index 00000000..bc72c6e3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1 @@ -0,0 +1,16 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-SHOW" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem +.SH "SYNOPSIS" +\fBbundle show\fR [GEM] [\-\-paths] +.SH "DESCRIPTION" +Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\. +.P +Calling show with [GEM] will list the exact location of that gem on your machine\. +.SH "OPTIONS" +.TP +\fB\-\-paths\fR +List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1.ronn new file mode 100644 index 00000000..a6a59a14 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-show.1.ronn @@ -0,0 +1,21 @@ +bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem +========================================================================= + +## SYNOPSIS + +`bundle show` [GEM] + [--paths] + +## DESCRIPTION + +Without the [GEM] option, `show` will print a list of the names and versions of +all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by name. + +Calling show with [GEM] will list the exact location of that gem on your +machine. + +## OPTIONS + +* `--paths`: + List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], + sorted by gem name. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1 new file mode 100644 index 00000000..d1284c2e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1 @@ -0,0 +1,275 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-UPDATE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-update\fR \- Update your gems to the latest available versions +.SH "SYNOPSIS" +\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-full\-index] [\-\-jobs=JOBS] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-redownload] [\-\-strict] [\-\-conservative] +.SH "DESCRIPTION" +Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\. +.P +You would use \fBbundle update\fR to explicitly update the version of a gem\. +.SH "OPTIONS" +.TP +\fB\-\-all\fR +Update all gems specified in Gemfile\. +.TP +\fB\-\-group=\fR, \fB\-g=[]\fR +Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\. +.TP +\fB\-\-source=\fR +The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR +.TP +\fB\-\-local\fR +Do not attempt to fetch gems remotely and use the gem cache instead\. +.TP +\fB\-\-ruby\fR +Update the locked version of Ruby to the current version of Ruby\. +.TP +\fB\-\-bundler\fR +Update the locked version of bundler to the invoked bundler version\. +.TP +\fB\-\-full\-index\fR +Fall back to using the single\-file index of all gems\. +.TP +\fB\-\-jobs=[]\fR, \fB\-j[]\fR +Specify the number of jobs to run in parallel\. The default is the number of available processors\. +.TP +\fB\-\-retry=[]\fR +Retry failed network or git requests for \fInumber\fR times\. +.TP +\fB\-\-quiet\fR +Only output warnings and errors\. +.TP +\fB\-\-redownload\fR +Force downloading every gem\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-strict\fR +Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. +.TP +\fB\-\-conservative\fR +Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. +.SH "UPDATING ALL GEMS" +If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. +.P +Consider the following Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "rails", "3\.0\.0\.rc" +gem "nokogiri" +.fi +.IP "" 0 +.P +When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: +.IP "" 4 +.nf +Fetching gem metadata from https://rubygems\.org/\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\. +Resolving dependencies\|\.\|\.\|\. +Installing builder 2\.1\.2 +Installing abstract 1\.0\.0 +Installing rack 1\.2\.8 +Using bundler 1\.7\.6 +Installing rake 10\.4\.0 +Installing polyglot 0\.3\.5 +Installing mime\-types 1\.25\.1 +Installing i18n 0\.4\.2 +Installing mini_portile 0\.6\.1 +Installing tzinfo 0\.3\.42 +Installing rack\-mount 0\.6\.14 +Installing rack\-test 0\.5\.7 +Installing treetop 1\.4\.15 +Installing thor 0\.14\.6 +Installing activesupport 3\.0\.0\.rc +Installing erubis 2\.6\.6 +Installing activemodel 3\.0\.0\.rc +Installing arel 0\.4\.0 +Installing mail 2\.2\.20 +Installing activeresource 3\.0\.0\.rc +Installing actionpack 3\.0\.0\.rc +Installing activerecord 3\.0\.0\.rc +Installing actionmailer 3\.0\.0\.rc +Installing railties 3\.0\.0\.rc +Installing rails 3\.0\.0\.rc +Installing nokogiri 1\.6\.5 + +Bundle complete! 2 Gemfile dependencies, 26 gems total\. +Use `bundle show [gemname]` to see where a bundled gem is installed\. +.fi +.IP "" 0 +.P +As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\. +.P +After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don't need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\. +.P +However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\. +.P +To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\. +.SH "UPDATING A LIST OF GEMS" +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.P +For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\. +.P +Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\. +.SH "OVERLAPPING DEPENDENCIES" +Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\. +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "thin" +gem "rack\-perftools\-profiler" +.fi +.IP "" 0 +.P +The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get: +.IP "" 4 +.nf +Fetching source index for https://rubygems\.org/ +Installing daemons (1\.1\.0) +Installing eventmachine (0\.12\.10) with native extensions +Installing open4 (1\.0\.1) +Installing perftools\.rb (0\.4\.7) with native extensions +Installing rack (1\.2\.1) +Installing rack\-perftools_profiler (0\.0\.2) +Installing thin (1\.2\.7) with native extensions +Using bundler (1\.0\.0\.rc\.3) +.fi +.IP "" 0 +.P +In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it's \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\. +.P +In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. +.P +To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: +.P +In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. +.P +Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. +.SH "PATCH LEVEL OPTIONS" +Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-strict\fR +Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. +.P +When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\. +.P +Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\. +.P +For example, if gem 'foo' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. +.P +If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\. +.P +If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\. +.P +Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\. +.P +To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. +.P +Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is '~> 1\.0', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\. +.SH "PATCH LEVEL EXAMPLES" +Given the following gem specifications: +.IP "" 4 +.nf +foo 1\.4\.3, requires: ~> bar 2\.0 +foo 1\.4\.4, requires: ~> bar 2\.0 +foo 1\.4\.5, requires: ~> bar 2\.1 +foo 1\.5\.0, requires: ~> bar 2\.1 +foo 1\.5\.1, requires: ~> bar 3\.0 +bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0 +.fi +.IP "" 0 +.P +Gemfile: +.IP "" 4 +.nf +gem 'foo' +.fi +.IP "" 0 +.P +Gemfile\.lock: +.IP "" 4 +.nf +foo (1\.4\.3) + bar (~> 2\.0) +bar (2\.0\.3) +.fi +.IP "" 0 +.P +Cases: +.IP "" 4 +.nf +# Command Line Result +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +1 bundle update \-\-patch 'foo 1\.4\.5', 'bar 2\.1\.1' +2 bundle update \-\-patch foo 'foo 1\.4\.5', 'bar 2\.1\.1' +3 bundle update \-\-minor 'foo 1\.5\.1', 'bar 3\.0\.0' +4 bundle update \-\-minor \-\-strict 'foo 1\.5\.0', 'bar 2\.1\.1' +5 bundle update \-\-patch \-\-strict 'foo 1\.4\.4', 'bar 2\.0\.4' +.fi +.IP "" 0 +.P +In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\. +.P +In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile\. +.P +In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\. +.P +In case 4, foo is preferred up to a minor version, but 1\.5\.1 won't work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it's a major increment\. +.P +In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\. +.SH "RECOMMENDED WORKFLOW" +In general, when working with an application managed with bundler, you should use the following workflow: +.IP "\(bu" 4 +After you create your Gemfile(5) for the first time, run +.IP +$ bundle install +.IP "\(bu" 4 +Check the resulting \fBGemfile\.lock\fR into version control +.IP +$ git add Gemfile\.lock +.IP "\(bu" 4 +When checking out this repository on another development machine, run +.IP +$ bundle install +.IP "\(bu" 4 +When checking out this repository on a deployment machine, run +.IP +$ bundle install \-\-deployment +.IP "\(bu" 4 +After changing the Gemfile(5) to reflect a new or update dependency, run +.IP +$ bundle install +.IP "\(bu" 4 +Make sure to check the updated \fBGemfile\.lock\fR into version control +.IP +$ git add Gemfile\.lock +.IP "\(bu" 4 +If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5) +.IP +$ bundle update rails thin +.IP "\(bu" 4 +If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run +.IP +$ bundle update \-\-all +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1.ronn new file mode 100644 index 00000000..fe500cdc --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-update.1.ronn @@ -0,0 +1,351 @@ +bundle-update(1) -- Update your gems to the latest available versions +===================================================================== + +## SYNOPSIS + +`bundle update` <*gems> [--all] + [--group=NAME] + [--source=NAME] + [--local] + [--ruby] + [--bundler[=VERSION]] + [--full-index] + [--jobs=JOBS] + [--quiet] + [--patch|--minor|--major] + [--redownload] + [--strict] + [--conservative] + +## DESCRIPTION + +Update the gems specified (all gems, if `--all` flag is used), ignoring +the previously installed gems specified in the `Gemfile.lock`. In +general, you should use [bundle install(1)](bundle-install.1.html) to install the same exact +gems and versions across machines. + +You would use `bundle update` to explicitly update the version of a +gem. + +## OPTIONS + +* `--all`: + Update all gems specified in Gemfile. + +* `--group=`, `-g=[]`: + Only update the gems in the specified group. For instance, you can update all gems + in the development group with `bundle update --group development`. You can also + call `bundle update rails --group test` to update the rails gem and all gems in + the test group, for example. + +* `--source=`: + The name of a `:git` or `:path` source used in the Gemfile(5). For + instance, with a `:git` source of `http://github.com/rails/rails.git`, + you would call `bundle update --source rails` + +* `--local`: + Do not attempt to fetch gems remotely and use the gem cache instead. + +* `--ruby`: + Update the locked version of Ruby to the current version of Ruby. + +* `--bundler`: + Update the locked version of bundler to the invoked bundler version. + +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--jobs=[]`, `-j[]`: + Specify the number of jobs to run in parallel. The default is the number of + available processors. + +* `--retry=[]`: + Retry failed network or git requests for times. + +* `--quiet`: + Only output warnings and errors. + +* `--redownload`: + Force downloading every gem. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +* `--conservative`: + Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. + +## UPDATING ALL GEMS + +If you run `bundle update --all`, bundler will ignore +any previously installed gems and resolve all dependencies again +based on the latest versions of all gems available in the sources. + +Consider the following Gemfile(5): + + source "https://rubygems.org" + + gem "rails", "3.0.0.rc" + gem "nokogiri" + +When you run [bundle install(1)](bundle-install.1.html) the first time, bundler will resolve +all of the dependencies, all the way down, and install what you need: + + Fetching gem metadata from https://rubygems.org/......... + Resolving dependencies... + Installing builder 2.1.2 + Installing abstract 1.0.0 + Installing rack 1.2.8 + Using bundler 1.7.6 + Installing rake 10.4.0 + Installing polyglot 0.3.5 + Installing mime-types 1.25.1 + Installing i18n 0.4.2 + Installing mini_portile 0.6.1 + Installing tzinfo 0.3.42 + Installing rack-mount 0.6.14 + Installing rack-test 0.5.7 + Installing treetop 1.4.15 + Installing thor 0.14.6 + Installing activesupport 3.0.0.rc + Installing erubis 2.6.6 + Installing activemodel 3.0.0.rc + Installing arel 0.4.0 + Installing mail 2.2.20 + Installing activeresource 3.0.0.rc + Installing actionpack 3.0.0.rc + Installing activerecord 3.0.0.rc + Installing actionmailer 3.0.0.rc + Installing railties 3.0.0.rc + Installing rails 3.0.0.rc + Installing nokogiri 1.6.5 + + Bundle complete! 2 Gemfile dependencies, 26 gems total. + Use `bundle show [gemname]` to see where a bundled gem is installed. + +As you can see, even though you have two gems in the Gemfile(5), your application +needs 26 different gems in order to run. Bundler remembers the exact versions +it installed in `Gemfile.lock`. The next time you run [bundle install(1)](bundle-install.1.html), bundler skips +the dependency resolution and installs the same gems as it installed last time. + +After checking in the `Gemfile.lock` into version control and cloning it on another +machine, running [bundle install(1)](bundle-install.1.html) will _still_ install the gems that you installed +last time. You don't need to worry that a new release of `erubis` or `mail` changes +the gems you use. + +However, from time to time, you might want to update the gems you are using to the +newest versions that still match the gems in your Gemfile(5). + +To do this, run `bundle update --all`, which will ignore the `Gemfile.lock`, and resolve +all the dependencies again. Keep in mind that this process can result in a significantly +different set of the 25 gems, based on the requirements of new gems that the gem +authors released since the last time you ran `bundle update --all`. + +## UPDATING A LIST OF GEMS + +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the +gems that you specified locked to the versions in the `Gemfile.lock`. + +For instance, in the scenario above, imagine that `nokogiri` releases version `1.4.4`, and +you want to update it _without_ updating Rails and all of its dependencies. To do this, +run `bundle update nokogiri`. + +Bundler will update `nokogiri` and any of its dependencies, but leave alone Rails and +its dependencies. + +## OVERLAPPING DEPENDENCIES + +Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same +second-level dependency. For instance, consider the case of `thin` and +`rack-perftools-profiler`. + + source "https://rubygems.org" + + gem "thin" + gem "rack-perftools-profiler" + +The `thin` gem depends on `rack >= 1.0`, while `rack-perftools-profiler` depends +on `rack ~> 1.0`. If you run bundle install, you get: + + Fetching source index for https://rubygems.org/ + Installing daemons (1.1.0) + Installing eventmachine (0.12.10) with native extensions + Installing open4 (1.0.1) + Installing perftools.rb (0.4.7) with native extensions + Installing rack (1.2.1) + Installing rack-perftools_profiler (0.0.2) + Installing thin (1.2.7) with native extensions + Using bundler (1.0.0.rc.3) + +In this case, the two gems have their own set of dependencies, but they share +`rack` in common. If you run `bundle update thin`, bundler will update `daemons`, +`eventmachine` and `rack`, which are dependencies of `thin`, but not `open4` or +`perftools.rb`, which are dependencies of `rack-perftools_profiler`. Note that +`bundle update thin` will update `rack` even though it's _also_ a dependency of +`rack-perftools_profiler`. + +In short, by default, when you update a gem using `bundle update`, bundler will +update all dependencies of that gem, including those that are also dependencies +of another gem. + +To prevent updating indirect dependencies, prior to version 1.14 the only option +was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): + +In this scenario, updating the `thin` version manually in the Gemfile(5), +and then running [bundle install(1)](bundle-install.1.html) will only update `daemons` and `eventmachine`, +but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section +of [bundle install(1)](bundle-install.1.html). + +Starting with 1.14, specifying the `--conservative` option will also prevent indirect +dependencies from being updated. + +## PATCH LEVEL OPTIONS + +Version 1.14 introduced 4 patch-level options that will influence how gem +versions are resolved. One of the following options can be used: `--patch`, +`--minor` or `--major`. `--strict` can be added to further influence resolution. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +When Bundler is resolving what versions to use to satisfy declared +requirements in the Gemfile or in parent gems, it looks up all +available versions, filters out any versions that don't satisfy +the requirement, and then, by default, sorts them from newest to +oldest, considering them in that order. + +Providing one of the patch level options (e.g. `--patch`) changes the +sort order of the satisfying versions, causing Bundler to consider the +latest `--patch` or `--minor` version available before other versions. +Note that versions outside the stated patch level could still be +resolved to if necessary to find a suitable dependency graph. + +For example, if gem 'foo' is locked at 1.0.2, with no gem requirement +defined in the Gemfile, and versions 1.0.3, 1.0.4, 1.1.0, 1.1.1, 2.0.0 +all exist, the default order of preference by default (`--major`) will +be "2.0.0, 1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +If the `--patch` option is used, the order of preference will change to +"1.0.4, 1.0.3, 1.0.2, 1.1.1, 1.1.0, 2.0.0". + +If the `--minor` option is used, the order of preference will change to +"1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2, 2.0.0". + +Combining the `--strict` option with any of the patch level options +will remove any versions beyond the scope of the patch level option, +to ensure that no gem is updated that far. + +To continue the previous example, if both `--patch` and `--strict` +options are used, the available versions for resolution would be +"1.0.4, 1.0.3, 1.0.2". If `--minor` and `--strict` are used, it would +be "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +Gem requirements as defined in the Gemfile will still be the first +determining factor for what versions are available. If the gem +requirement for `foo` in the Gemfile is '~> 1.0', that will accomplish +the same thing as providing the `--minor` and `--strict` options. + +## PATCH LEVEL EXAMPLES + +Given the following gem specifications: + + foo 1.4.3, requires: ~> bar 2.0 + foo 1.4.4, requires: ~> bar 2.0 + foo 1.4.5, requires: ~> bar 2.1 + foo 1.5.0, requires: ~> bar 2.1 + foo 1.5.1, requires: ~> bar 3.0 + bar with versions 2.0.3, 2.0.4, 2.1.0, 2.1.1, 3.0.0 + +Gemfile: + + gem 'foo' + +Gemfile.lock: + + foo (1.4.3) + bar (~> 2.0) + bar (2.0.3) + +Cases: + + # Command Line Result + ------------------------------------------------------------ + 1 bundle update --patch 'foo 1.4.5', 'bar 2.1.1' + 2 bundle update --patch foo 'foo 1.4.5', 'bar 2.1.1' + 3 bundle update --minor 'foo 1.5.1', 'bar 3.0.0' + 4 bundle update --minor --strict 'foo 1.5.0', 'bar 2.1.1' + 5 bundle update --patch --strict 'foo 1.4.4', 'bar 2.0.4' + +In case 1, bar is upgraded to 2.1.1, a minor version increase, because +the dependency from foo 1.4.5 required it. + +In case 2, only foo is requested to be unlocked, but bar is also +allowed to move because it's not a declared dependency in the Gemfile. + +In case 3, bar goes up a whole major release, because a minor increase +is preferred now for foo, and when it goes to 1.5.1, it requires 3.0.0 +of bar. + +In case 4, foo is preferred up to a minor version, but 1.5.1 won't work +because the --strict flag removes bar 3.0.0 from consideration since +it's a major increment. + +In case 5, both foo and bar have any minor or major increments removed +from consideration because of the --strict flag, so the most they can +move is up to 1.4.4 and 2.0.4. + +## RECOMMENDED WORKFLOW + +In general, when working with an application managed with bundler, you should +use the following workflow: + +* After you create your Gemfile(5) for the first time, run + + $ bundle install + +* Check the resulting `Gemfile.lock` into version control + + $ git add Gemfile.lock + +* When checking out this repository on another development machine, run + + $ bundle install + +* When checking out this repository on a deployment machine, run + + $ bundle install --deployment + +* After changing the Gemfile(5) to reflect a new or update dependency, run + + $ bundle install + +* Make sure to check the updated `Gemfile.lock` into version control + + $ git add Gemfile.lock + +* If [bundle install(1)](bundle-install.1.html) reports a conflict, manually update the specific + gems that you changed in the Gemfile(5) + + $ bundle update rails thin + +* If you want to update all the gems to the latest possible versions that + still match the gems listed in the Gemfile(5), run + + $ bundle update --all diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1 new file mode 100644 index 00000000..05905e13 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1 @@ -0,0 +1,22 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-VERSION" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-version\fR \- Prints Bundler version information +.SH "SYNOPSIS" +\fBbundle version\fR +.SH "DESCRIPTION" +Prints Bundler version information\. +.SH "OPTIONS" +No options\. +.SH "EXAMPLE" +Print the version of Bundler with build date and commit hash of the in the Git source\. +.IP "" 4 +.nf +bundle version +.fi +.IP "" 0 +.P +shows \fBBundler version 2\.3\.21 (2022\-08\-24 commit d54be5fdd8)\fR for example\. +.P +cf\. \fBbundle \-\-version\fR shows \fBBundler version 2\.3\.21\fR\. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1.ronn new file mode 100644 index 00000000..46c6f0b3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-version.1.ronn @@ -0,0 +1,24 @@ +bundle-version(1) -- Prints Bundler version information +======================================================= + +## SYNOPSIS + +`bundle version` + +## DESCRIPTION + +Prints Bundler version information. + +## OPTIONS + +No options. + +## EXAMPLE + +Print the version of Bundler with build date and commit hash of the in the Git source. + + bundle version + +shows `Bundler version 2.3.21 (2022-08-24 commit d54be5fdd8)` for example. + +cf. `bundle --version` shows `Bundler version 2.3.21`. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1 new file mode 100644 index 00000000..681563cd --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1 @@ -0,0 +1,30 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE\-VIZ" "1" "March 2024" "" +.SH "NAME" +\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile +.SH "SYNOPSIS" +\fBbundle viz\fR [\-\-file=FILE] [\-\-format=FORMAT] [\-\-requirements] [\-\-version] [\-\-without=GROUP GROUP] +.SH "DESCRIPTION" +\fBviz\fR generates a PNG file of the current \fBGemfile(5)\fR as a dependency graph\. \fBviz\fR requires the ruby\-graphviz gem (and its dependencies)\. +.P +The associated gems must also be installed via \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR\. +.P +\fBviz\fR command was deprecated in Bundler 2\.2\. Use bundler\-graph plugin \fIhttps://github\.com/rubygems/bundler\-graph\fR instead\. +.SH "OPTIONS" +.TP +\fB\-\-file\fR, \fB\-f\fR +The name to use for the generated file\. See \fB\-\-format\fR option +.TP +\fB\-\-format\fR, \fB\-F\fR +This is output format option\. Supported format is png, jpg, svg, dot \|\.\|\.\|\. +.TP +\fB\-\-requirements\fR, \fB\-R\fR +Set to show the version of each required dependency\. +.TP +\fB\-\-version\fR, \fB\-v\fR +Set to show each gem version\. +.TP +\fB\-\-without\fR, \fB\-W\fR +Exclude gems that are part of the specified named group\. + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1.ronn new file mode 100644 index 00000000..f2202569 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle-viz.1.ronn @@ -0,0 +1,32 @@ +bundle-viz(1) -- Generates a visual dependency graph for your Gemfile +===================================================================== + +## SYNOPSIS + +`bundle viz` [--file=FILE] + [--format=FORMAT] + [--requirements] + [--version] + [--without=GROUP GROUP] + +## DESCRIPTION + +`viz` generates a PNG file of the current `Gemfile(5)` as a dependency graph. +`viz` requires the ruby-graphviz gem (and its dependencies). + +The associated gems must also be installed via [`bundle install(1)`](bundle-install.1.html). + +`viz` command was deprecated in Bundler 2.2. Use [bundler-graph plugin](https://github.com/rubygems/bundler-graph) instead. + +## OPTIONS + +* `--file`, `-f`: + The name to use for the generated file. See `--format` option +* `--format`, `-F`: + This is output format option. Supported format is png, jpg, svg, dot ... +* `--requirements`, `-R`: + Set to show the version of each required dependency. +* `--version`, `-v`: + Set to show each gem version. +* `--without`, `-W`: + Exclude gems that are part of the specified named group. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1 b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1 new file mode 100644 index 00000000..1d2c7800 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1 @@ -0,0 +1,102 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "BUNDLE" "1" "March 2024" "" +.SH "NAME" +\fBbundle\fR \- Ruby Dependency Management +.SH "SYNOPSIS" +\fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS] +.SH "DESCRIPTION" +Bundler manages an \fBapplication's dependencies\fR through its entire life across many machines systematically and repeatably\. +.P +See the bundler website \fIhttps://bundler\.io\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\. +.SH "OPTIONS" +.TP +\fB\-\-no\-color\fR +Print all output without color +.TP +\fB\-\-retry\fR, \fB\-r\fR +Specify the number of times you wish to attempt network commands +.TP +\fB\-\-verbose\fR, \fB\-V\fR +Print out additional logging information +.SH "BUNDLE COMMANDS" +We divide \fBbundle\fR subcommands into primary commands and utilities: +.SH "PRIMARY COMMANDS" +.TP +\fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR +Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR +.TP +\fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR +Update dependencies to their latest versions +.TP +\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR +Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR) +.TP +\fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR +Execute a script in the current bundle +.TP +\fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR +Specify and read configuration options for Bundler +.TP +\fBbundle help(1)\fR \fIbundle\-help\.1\.html\fR +Display detailed help for each subcommand +.SH "UTILITIES" +.TP +\fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR +Add the named gem to the Gemfile and run \fBbundle install\fR +.TP +\fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR +Generate binstubs for executables in a gem +.TP +\fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR +Determine whether the requirements for your application are installed and available to Bundler +.TP +\fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR +Show the source location of a particular gem in the bundle +.TP +\fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR +Show all of the outdated gems in the current bundle +.TP +\fBbundle console(1)\fR (deprecated) +Start an IRB session in the current bundle +.TP +\fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR +Open an installed gem in the editor +.TP +\fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR +Generate a lockfile for your dependencies +.TP +\fBbundle viz(1)\fR \fIbundle\-viz\.1\.html\fR (deprecated) +Generate a visual representation of your dependencies +.TP +\fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR +Generate a simple \fBGemfile\fR, placed in the current directory +.TP +\fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR +Create a simple gem, suitable for development with Bundler +.TP +\fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR +Display platform compatibility information +.TP +\fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR +Clean up unused gems in your Bundler directory +.TP +\fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR +Display warnings about common problems +.TP +\fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR +Removes gems from the Gemfile +.TP +\fBbundle plugin(1)\fR \fIbundle\-plugin\.1\.html\fR +Manage Bundler plugins +.TP +\fBbundle version(1)\fR \fIbundle\-version\.1\.html\fR +Prints Bundler version information +.SH "PLUGINS" +When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-\fR and execute it, passing down any extra arguments to it\. +.SH "OBSOLETE" +These commands are obsolete and should no longer be used: +.IP "\(bu" 4 +\fBbundle inject(1)\fR +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1.ronn new file mode 100644 index 00000000..8245effa --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/bundle.1.ronn @@ -0,0 +1,116 @@ +bundle(1) -- Ruby Dependency Management +======================================= + +## SYNOPSIS + +`bundle` COMMAND [--no-color] [--verbose] [ARGS] + +## DESCRIPTION + +Bundler manages an `application's dependencies` through its entire life +across many machines systematically and repeatably. + +See [the bundler website](https://bundler.io) for information on getting +started, and Gemfile(5) for more information on the `Gemfile` format. + +## OPTIONS + +* `--no-color`: + Print all output without color + +* `--retry`, `-r`: + Specify the number of times you wish to attempt network commands + +* `--verbose`, `-V`: + Print out additional logging information + +## BUNDLE COMMANDS + +We divide `bundle` subcommands into primary commands and utilities: + +## PRIMARY COMMANDS + +* [`bundle install(1)`](bundle-install.1.html): + Install the gems specified by the `Gemfile` or `Gemfile.lock` + +* [`bundle update(1)`](bundle-update.1.html): + Update dependencies to their latest versions + +* [`bundle cache(1)`](bundle-cache.1.html): + Package the .gem files required by your application into the + `vendor/cache` directory (aliases: `bundle package`, `bundle pack`) + +* [`bundle exec(1)`](bundle-exec.1.html): + Execute a script in the current bundle + +* [`bundle config(1)`](bundle-config.1.html): + Specify and read configuration options for Bundler + +* [`bundle help(1)`](bundle-help.1.html): + Display detailed help for each subcommand + +## UTILITIES + +* [`bundle add(1)`](bundle-add.1.html): + Add the named gem to the Gemfile and run `bundle install` + +* [`bundle binstubs(1)`](bundle-binstubs.1.html): + Generate binstubs for executables in a gem + +* [`bundle check(1)`](bundle-check.1.html): + Determine whether the requirements for your application are installed + and available to Bundler + +* [`bundle show(1)`](bundle-show.1.html): + Show the source location of a particular gem in the bundle + +* [`bundle outdated(1)`](bundle-outdated.1.html): + Show all of the outdated gems in the current bundle + +* `bundle console(1)` (deprecated): + Start an IRB session in the current bundle + +* [`bundle open(1)`](bundle-open.1.html): + Open an installed gem in the editor + +* [`bundle lock(1)`](bundle-lock.1.html): + Generate a lockfile for your dependencies + +* [`bundle viz(1)`](bundle-viz.1.html) (deprecated): + Generate a visual representation of your dependencies + +* [`bundle init(1)`](bundle-init.1.html): + Generate a simple `Gemfile`, placed in the current directory + +* [`bundle gem(1)`](bundle-gem.1.html): + Create a simple gem, suitable for development with Bundler + +* [`bundle platform(1)`](bundle-platform.1.html): + Display platform compatibility information + +* [`bundle clean(1)`](bundle-clean.1.html): + Clean up unused gems in your Bundler directory + +* [`bundle doctor(1)`](bundle-doctor.1.html): + Display warnings about common problems + +* [`bundle remove(1)`](bundle-remove.1.html): + Removes gems from the Gemfile + +* [`bundle plugin(1)`](bundle-plugin.1.html): + Manage Bundler plugins + +* [`bundle version(1)`](bundle-version.1.html): + Prints Bundler version information + +## PLUGINS + +When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, +Bundler will try to find an executable on your path named `bundler-` +and execute it, passing down any extra arguments to it. + +## OBSOLETE + +These commands are obsolete and should no longer be used: + +* `bundle inject(1)` diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5 b/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5 new file mode 100644 index 00000000..39503f22 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5 @@ -0,0 +1,470 @@ +.\" generated with nRonn/v0.11.1 +.\" https://github.com/n-ronn/nronn/tree/0.11.1 +.TH "GEMFILE" "5" "March 2024" "" +.SH "NAME" +\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs +.SH "SYNOPSIS" +A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\. +.P +Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\. +.SH "SYNTAX" +A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\. +.SH "GLOBAL SOURCE" +At the top of the \fBGemfile\fR, add a single line for the \fBRubyGems\fR source that contains the gems listed in the \fBGemfile\fR\. +.IP "" 4 +.nf +source "https://rubygems\.org" +.fi +.IP "" 0 +.P +You can add only one global source\. In Bundler 1\.13, adding multiple global sources was deprecated\. The \fBsource\fR \fBMUST\fR be a valid RubyGems repository\. +.P +To use more than one source of RubyGems, you should use \fI\fBsource\fR block\fR\. +.P +A source is checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\. +.P +\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or \fBsource\fR block\. +.SS "CREDENTIALS" +Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\. +.IP "" 4 +.nf +bundle config gems\.example\.com user:password +.fi +.IP "" 0 +.P +For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\. +.IP "" 4 +.nf +source "https://user:password@gems\.example\.com" +.fi +.IP "" 0 +.P +Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\. +.SH "RUBY" +If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. +.SS "VERSION (required)" +The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc\., this should be the Ruby version that the engine is compatible with\. +.IP "" 4 +.nf +ruby "3\.1\.2" +.fi +.IP "" 0 +.P +If you wish to derive your Ruby version from a version file (ie \.ruby\-version), you can use the \fBfile\fR option instead\. +.IP "" 4 +.nf +ruby file: "\.ruby\-version" +.fi +.IP "" 0 +.P +The version file should conform to any of the following formats: +.IP "\(bu" 4 +\fB3\.1\.2\fR (\.ruby\-version) +.IP "\(bu" 4 +\fBruby 3\.1\.2\fR (\.tool\-versions, read: https://asdf\-vm\.com/manage/configuration\.html#tool\-versions) +.IP "" 0 +.SS "ENGINE" +Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\. +.P +What exactly is an Engine? +.IP "\(bu" 4 +A Ruby engine is an implementation of the Ruby language\. +.IP "\(bu" 4 +For background: the reference or original implementation of the Ruby programming language is called Matz's Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\. +.IP "\(bu" 4 +Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttps://www\.jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\. +.IP "" 0 +.SS "ENGINE VERSION" +Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\. +.IP "" 4 +.nf +ruby "2\.6\.8", engine: "jruby", engine_version: "9\.3\.8\.0" +.fi +.IP "" 0 +.SS "PATCHLEVEL" +Each application \fImay\fR specify a Ruby patchlevel\. Specifying the patchlevel has been meaningless since Ruby 2\.1\.0 was released as the patchlevel is now uniquely determined by a combination of major, minor, and teeny version numbers\. +.P +This option was implemented in Bundler 1\.4\.0 for Ruby 2\.0 or earlier\. +.IP "" 4 +.nf +ruby "3\.1\.2", patchlevel: "20" +.fi +.IP "" 0 +.SH "GEMS" +Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. +.SS "NAME (required)" +For each gem requirement, list a single \fIgem\fR line\. +.IP "" 4 +.nf +gem "nokogiri" +.fi +.IP "" 0 +.SS "VERSION" +Each \fIgem\fR \fBMAY\fR have one or more version specifiers\. +.IP "" 4 +.nf +gem "nokogiri", ">= 1\.4\.2" +gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0" +.fi +.IP "" 0 +.SS "REQUIRE AS" +Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\. +.IP "" 4 +.nf +gem "redis", require: ["redis/connection/hiredis", "redis"] +gem "webmock", require: false +gem "byebug", require: true +.fi +.IP "" 0 +.P +The argument defaults to the name of the gem\. For example, these are identical: +.IP "" 4 +.nf +gem "nokogiri" +gem "nokogiri", require: "nokogiri" +gem "nokogiri", require: true +.fi +.IP "" 0 +.SS "GROUPS" +Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\. +.IP "" 4 +.nf +gem "rspec", group: :test +gem "wirble", groups: [:development, :test] +.fi +.IP "" 0 +.P +The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\. +.IP "" 4 +.nf +# setup adds gems to Ruby's load path +Bundler\.setup # defaults to all groups +require "bundler/setup" # same as Bundler\.setup +Bundler\.setup(:default) # only set up the _default_ group +Bundler\.setup(:test) # only set up the _test_ group (but `not` _default_) +Bundler\.setup(:default, :test) # set up the _default_ and _test_ groups, but no others + +# require requires all of the gems in the specified groups +Bundler\.require # defaults to the _default_ group +Bundler\.require(:default) # identical +Bundler\.require(:default, :test) # requires the _default_ and _test_ groups +Bundler\.require(:test) # requires the _test_ group +.fi +.IP "" 0 +.P +The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\. +.P +To specify multiple groups to ignore, specify a list of groups separated by spaces\. +.IP "" 4 +.nf +bundle config set \-\-local without test +bundle config set \-\-local without development test +.fi +.IP "" 0 +.P +Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\. +.P +Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Understanding Bundler \fIhttps://bundler\.io/rationale\.html\fR\. +.SS "PLATFORMS" +If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\. +.P +There are a number of \fBGemfile\fR platforms: +.TP +\fBruby\fR +C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows +.TP +\fBmri\fR +C Ruby (MRI) only, but not Windows +.TP +\fBwindows\fR +Windows C Ruby (MRI), including RubyInstaller 32\-bit and 64\-bit versions +.TP +\fBmswin\fR +Windows C Ruby (MRI), including RubyInstaller 32\-bit versions +.TP +\fBmswin64\fR +Windows C Ruby (MRI), including RubyInstaller 64\-bit versions +.TP +\fBrbx\fR +Rubinius +.TP +\fBjruby\fR +JRuby +.TP +\fBtruffleruby\fR +TruffleRuby +.P +On platforms \fBruby\fR, \fBmri\fR, \fBmswin\fR, \fBmswin64\fR, and \fBwindows\fR, you may additionally specify a version by appending the major and minor version numbers without a delimiter\. For example, to specify that a gem should only be used on platform \fBruby\fR version 3\.1, use: +.IP "" 4 +.nf +ruby_31 +.fi +.IP "" 0 +.P +As with groups (above), you may specify one or more platforms: +.IP "" 4 +.nf +gem "weakling", platforms: :jruby +gem "ruby\-debug", platforms: :mri_31 +gem "nokogiri", platforms: [:windows_31, :jruby] +.fi +.IP "" 0 +.P +All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\. +.P +The following platform values are deprecated and should be replaced with \fBwindows\fR: +.IP "\(bu" 4 +\fBmswin\fR, \fBmswin64\fR, \fBmingw32\fR, \fBx64_mingw\fR +.IP "" 0 +.SS "FORCE_RUBY_PLATFORM" +If you always want the pure ruby variant of a gem to be chosen over platform specific variants, you can use the \fBforce_ruby_platform\fR option: +.IP "" 4 +.nf +gem "ffi", force_ruby_platform: true +.fi +.IP "" 0 +.P +This can be handy (assuming the pure ruby variant works fine) when: +.IP "\(bu" 4 +You're having issues with the platform specific variant\. +.IP "\(bu" 4 +The platform specific variant does not yet support a newer ruby (and thus has a \fBrequired_ruby_version\fR upper bound), but you still want your Gemfile{\.lock} files to resolve under that ruby\. +.IP "" 0 +.SS "SOURCE" +You can select an alternate RubyGems repository for a gem using the ':source' option\. +.IP "" 4 +.nf +gem "some_internal_gem", source: "https://gems\.example\.com" +.fi +.IP "" 0 +.P +This forces the gem to be loaded from this source and ignores the global source declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\. +.P +Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on the global source\. +.P +\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCE\fR\. +.P +Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\. +.SS "GIT" +If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols: +.TP +\fBHTTP(S)\fR +gem "rails", git: "https://github\.com/rails/rails\.git" +.TP +\fBSSH\fR +gem "rails", git: "git@github\.com:rails/rails\.git" +.TP +\fBgit\fR +gem "rails", git: "git://github\.com/rails/rails\.git" +.P +If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\. +.P +\fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\. +.P +The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\. +.P +A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\. +.P +If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\. +.P +If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\. +.IP "" 4 +.nf +gem "rails", "2\.3\.8", git: "https://github\.com/rails/rails\.git" +# bundle install will fail, because the \.gemspec in the rails +# repository's master branch specifies version 3\.0\.0 +.fi +.IP "" 0 +.P +If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\. +.P +Git repositories support a number of additional options\. +.TP +\fBbranch\fR, \fBtag\fR, and \fBref\fR +You \fBMUST\fR only specify at most one of these options\. The default is \fBbranch: "master"\fR\. For example: +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", branch: "5\-0\-stable" +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", tag: "v5\.0\.0" +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", ref: "4aded" +.TP +\fBsubmodules\fR +For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fBsubmodules: true\fR to cause bundler to expand any submodules included in the git repository +.P +If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\. +.IP "" 4 +.nf +|~rails [git root] +| |\-rails\.gemspec [rails gem located here] +|~actionpack +| |\-actionpack\.gemspec [actionpack gem located here] +|~activesupport +| |\-activesupport\.gemspec [activesupport gem located here] +|\|\.\|\.\|\. +.fi +.IP "" 0 +.P +To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\. +.SS "GIT SOURCE" +A custom git source can be defined via the \fBgit_source\fR method\. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: +.IP "" 4 +.nf +git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" } +gem 'rails', stash: 'forks/rails' +.fi +.IP "" 0 +.P +In addition, if you wish to choose a specific branch: +.IP "" 4 +.nf +gem "rails", stash: "forks/rails", branch: "branch_name" +.fi +.IP "" 0 +.SS "GITHUB" +\fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\. +.P +If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. +.IP "" 4 +.nf +gem "rails", github: "rails/rails" +gem "rails", github: "rails" +.fi +.IP "" 0 +.P +Are both equivalent to +.IP "" 4 +.nf +gem "rails", git: "https://github\.com/rails/rails\.git" +.fi +.IP "" 0 +.P +Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.P +You can also directly pass a pull request URL: +.IP "" 4 +.nf +gem "rails", github: "https://github\.com/rails/rails/pull/43753" +.fi +.IP "" 0 +.P +Which is equivalent to: +.IP "" 4 +.nf +gem "rails", github: "rails/rails", branch: "refs/pull/43753/head" +.fi +.IP "" 0 +.SS "GIST" +If the git repository you want to use is hosted as a GitHub Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\. +.IP "" 4 +.nf +gem "the_hatch", gist: "4815162342" +.fi +.IP "" 0 +.P +Is equivalent to: +.IP "" 4 +.nf +gem "the_hatch", git: "https://gist\.github\.com/4815162342\.git" +.fi +.IP "" 0 +.P +Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.SS "BITBUCKET" +If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. +.IP "" 4 +.nf +gem "rails", bitbucket: "rails/rails" +gem "rails", bitbucket: "rails" +.fi +.IP "" 0 +.P +Are both equivalent to +.IP "" 4 +.nf +gem "rails", git: "https://rails@bitbucket\.org/rails/rails\.git" +.fi +.IP "" 0 +.P +Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.SS "PATH" +You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\. +.P +Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\. +.P +Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\. +.IP "" 4 +.nf +gem "rails", path: "vendor/rails" +.fi +.IP "" 0 +.P +If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem's files\. This will automatically load gemspec files from subdirectories\. +.IP "" 4 +.nf +path 'components' do + gem 'admin_ui' + gem 'public_ui' +end +.fi +.IP "" 0 +.SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS" +The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\. +.IP "" 4 +.nf +source "https://gems\.example\.com" do + gem "some_internal_gem" + gem "another_internal_gem" +end + +git "https://github\.com/rails/rails\.git" do + gem "activesupport" + gem "actionpack" +end + +platforms :ruby do + gem "ruby\-debug" + gem "sqlite3" +end + +group :development, optional: true do + gem "wirble" + gem "faker" +end +.fi +.IP "" 0 +.P +In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\. +.P +In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\. +.P +The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\. +.SH "INSTALL_IF" +The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\. +.IP "" 4 +.nf +install_if \-> { RUBY_PLATFORM =~ /darwin/ } do + gem "pasteboard" +end +.fi +.IP "" 0 +.SH "GEMSPEC" +The \fB\.gemspec\fR \fIhttps://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\. +.P +If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\. +.P +The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: '\.'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\. +.P +The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: \fB{,*,*/*}\.gemspec\fR), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\. +.P +When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\. +.SH "SOURCE PRIORITY" +When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: +.IP "1." 4 +The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR) +.IP "2." 4 +For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR +.IP "3." 4 +If neither of the above conditions are met, the global source will be used\. If multiple global sources are specified, they will be prioritized from last to first, but this is deprecated since Bundler 1\.13, so Bundler prints a warning and will abort with an error in the future\. +.IP "" 0 + diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5.ronn b/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5.ronn new file mode 100644 index 00000000..7c1e00d1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/gemfile.5.ronn @@ -0,0 +1,552 @@ +Gemfile(5) -- A format for describing gem dependencies for Ruby programs +======================================================================== + +## SYNOPSIS + +A `Gemfile` describes the gem dependencies required to execute associated +Ruby code. + +Place the `Gemfile` in the root of the directory containing the associated +code. For instance, in a Rails application, place the `Gemfile` in the same +directory as the `Rakefile`. + +## SYNTAX + +A `Gemfile` is evaluated as Ruby code, in a context which makes available +a number of methods used to describe the gem requirements. + +## GLOBAL SOURCE + +At the top of the `Gemfile`, add a single line for the `RubyGems` source that +contains the gems listed in the `Gemfile`. + + source "https://rubygems.org" + +You can add only one global source. In Bundler 1.13, adding multiple global +sources was deprecated. The `source` `MUST` be a valid RubyGems repository. + +To use more than one source of RubyGems, you should use [`source` block +](#BLOCK-FORM-OF-SOURCE-GIT-PATH-GROUP-and-PLATFORMS). + +A source is checked for gems following the heuristics described in +[SOURCE PRIORITY][]. + +**Note about a behavior of the feature deprecated in Bundler 1.13**: +If a gem is found in more than one global source, Bundler +will print a warning after installing the gem indicating which source was used, +and listing the other sources where the gem is available. A specific source can +be selected for gems that need to use a non-standard repository, suppressing +this warning, by using the [`:source` option](#SOURCE) or `source` block. + +### CREDENTIALS + +Some gem sources require a username and password. Use [bundle config(1)](bundle-config.1.html) to set +the username and password for any of the sources that need it. The command must +be run once on each computer that will install the Gemfile, but this keeps the +credentials from being stored in plain text in version control. + + bundle config gems.example.com user:password + +For some sources, like a company Gemfury account, it may be easier to +include the credentials in the Gemfile as part of the source URL. + + source "https://user:password@gems.example.com" + +Credentials in the source URL will take precedence over credentials set using +`config`. + +## RUBY + +If your application requires a specific Ruby version or engine, specify your +requirements using the `ruby` method, with the following arguments. +All parameters are `OPTIONAL` unless otherwise specified. + +### VERSION (required) + +The version of Ruby that your application requires. If your application +requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc., this +should be the Ruby version that the engine is compatible with. + + ruby "3.1.2" + +If you wish to derive your Ruby version from a version file (ie .ruby-version), +you can use the `file` option instead. + + ruby file: ".ruby-version" + +The version file should conform to any of the following formats: + + - `3.1.2` (.ruby-version) + - `ruby 3.1.2` (.tool-versions, read: https://asdf-vm.com/manage/configuration.html#tool-versions) + +### ENGINE + +Each application _may_ specify a Ruby engine. If an engine is specified, an +engine version _must_ also be specified. + +What exactly is an Engine? + - A Ruby engine is an implementation of the Ruby language. + + - For background: the reference or original implementation of the Ruby + programming language is called + [Matz's Ruby Interpreter](https://en.wikipedia.org/wiki/Ruby_MRI), or MRI + for short. This is named after Ruby creator Yukihiro Matsumoto, + also known as Matz. MRI is also known as CRuby, because it is written in C. + MRI is the most widely used Ruby engine. + + - [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist. + Some of the more well-known implementations include + [JRuby](https://www.jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/). + Rubinius is an alternative implementation of Ruby written in Ruby. + JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine. + TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM. + +### ENGINE VERSION + +Each application _may_ specify a Ruby engine version. If an engine version is +specified, an engine _must_ also be specified. If the engine is "ruby" the +engine version specified _must_ match the Ruby version. + + ruby "2.6.8", engine: "jruby", engine_version: "9.3.8.0" + +### PATCHLEVEL + +Each application _may_ specify a Ruby patchlevel. Specifying the patchlevel has +been meaningless since Ruby 2.1.0 was released as the patchlevel is now +uniquely determined by a combination of major, minor, and teeny version numbers. + +This option was implemented in Bundler 1.4.0 for Ruby 2.0 or earlier. + + ruby "3.1.2", patchlevel: "20" + +## GEMS + +Specify gem requirements using the `gem` method, with the following arguments. +All parameters are `OPTIONAL` unless otherwise specified. + +### NAME (required) + +For each gem requirement, list a single _gem_ line. + + gem "nokogiri" + +### VERSION + +Each _gem_ `MAY` have one or more version specifiers. + + gem "nokogiri", ">= 1.4.2" + gem "RedCloth", ">= 4.1.0", "< 4.2.0" + +### REQUIRE AS + +Each _gem_ `MAY` specify files that should be used when autorequiring via +`Bundler.require`. You may pass an array with multiple files or `true` if the file +you want `required` has the same name as _gem_ or `false` to +prevent any file from being autorequired. + + gem "redis", require: ["redis/connection/hiredis", "redis"] + gem "webmock", require: false + gem "byebug", require: true + +The argument defaults to the name of the gem. For example, these are identical: + + gem "nokogiri" + gem "nokogiri", require: "nokogiri" + gem "nokogiri", require: true + +### GROUPS + +Each _gem_ `MAY` specify membership in one or more groups. Any _gem_ that does +not specify membership in any group is placed in the `default` group. + + gem "rspec", group: :test + gem "wirble", groups: [:development, :test] + +The Bundler runtime allows its two main methods, `Bundler.setup` and +`Bundler.require`, to limit their impact to particular groups. + + # setup adds gems to Ruby's load path + Bundler.setup # defaults to all groups + require "bundler/setup" # same as Bundler.setup + Bundler.setup(:default) # only set up the _default_ group + Bundler.setup(:test) # only set up the _test_ group (but `not` _default_) + Bundler.setup(:default, :test) # set up the _default_ and _test_ groups, but no others + + # require requires all of the gems in the specified groups + Bundler.require # defaults to the _default_ group + Bundler.require(:default) # identical + Bundler.require(:default, :test) # requires the _default_ and _test_ groups + Bundler.require(:test) # requires the _test_ group + +The Bundler CLI allows you to specify a list of groups whose gems `bundle install` should +not install with the `without` configuration. + +To specify multiple groups to ignore, specify a list of groups separated by spaces. + + bundle config set --local without test + bundle config set --local without development test + +Also, calling `Bundler.setup` with no parameters, or calling `require "bundler/setup"` +will setup all groups except for the ones you excluded via `--without` (since they +are not available). + +Note that on `bundle install`, bundler downloads and evaluates all gems, in order to +create a single canonical list of all of the required gems and their dependencies. +This means that you cannot list different versions of the same gems in different +groups. For more details, see [Understanding Bundler](https://bundler.io/rationale.html). + +### PLATFORMS + +If a gem should only be used in a particular platform or set of platforms, you can +specify them. Platforms are essentially identical to groups, except that you do not +need to use the `--without` install-time flag to exclude groups of gems for other +platforms. + +There are a number of `Gemfile` platforms: + + * `ruby`: + C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows + * `mri`: + C Ruby (MRI) only, but not Windows + * `windows`: + Windows C Ruby (MRI), including RubyInstaller 32-bit and 64-bit versions + * `mswin`: + Windows C Ruby (MRI), including RubyInstaller 32-bit versions + * `mswin64`: + Windows C Ruby (MRI), including RubyInstaller 64-bit versions + * `rbx`: + Rubinius + * `jruby`: + JRuby + * `truffleruby`: + TruffleRuby + +On platforms `ruby`, `mri`, `mswin`, `mswin64`, and `windows`, you may +additionally specify a version by appending the major and minor version numbers +without a delimiter. For example, to specify that a gem should only be used on +platform `ruby` version 3.1, use: + + ruby_31 + +As with groups (above), you may specify one or more platforms: + + gem "weakling", platforms: :jruby + gem "ruby-debug", platforms: :mri_31 + gem "nokogiri", platforms: [:windows_31, :jruby] + +All operations involving groups ([`bundle install`](bundle-install.1.html), `Bundler.setup`, +`Bundler.require`) behave exactly the same as if any groups not +matching the current platform were explicitly excluded. + +The following platform values are deprecated and should be replaced with `windows`: + + * `mswin`, `mswin64`, `mingw32`, `x64_mingw` + +### FORCE_RUBY_PLATFORM + +If you always want the pure ruby variant of a gem to be chosen over platform +specific variants, you can use the `force_ruby_platform` option: + + gem "ffi", force_ruby_platform: true + +This can be handy (assuming the pure ruby variant works fine) when: + +* You're having issues with the platform specific variant. +* The platform specific variant does not yet support a newer ruby (and thus has + a `required_ruby_version` upper bound), but you still want your Gemfile{.lock} + files to resolve under that ruby. + +### SOURCE + +You can select an alternate RubyGems repository for a gem using the ':source' +option. + + gem "some_internal_gem", source: "https://gems.example.com" + +This forces the gem to be loaded from this source and ignores the global source +declared at the top level of the file. If the gem does not exist in this source, +it will not be installed. + +Bundler will search for child dependencies of this gem by first looking in the +source selected for the parent, but if they are not found there, it will fall +back on the global source. + +**Note about a behavior of the feature deprecated in Bundler 1.13**: +Selecting a specific source repository this way also suppresses the ambiguous +gem warning described above in [GLOBAL SOURCE](#GLOBAL-SOURCE). + +Using the `:source` option for an individual gem will also make that source +available as a possible global source for any other gems which do not specify +explicit sources. Thus, when adding gems with explicit sources, it is +recommended that you also ensure all other gems in the Gemfile are using +explicit sources. + +### GIT + +If necessary, you can specify that a gem is located at a particular +git repository using the `:git` parameter. The repository can be accessed via +several protocols: + + * `HTTP(S)`: + gem "rails", git: "https://github.com/rails/rails.git" + * `SSH`: + gem "rails", git: "git@github.com:rails/rails.git" + * `git`: + gem "rails", git: "git://github.com/rails/rails.git" + +If using SSH, the user that you use to run `bundle install` `MUST` have the +appropriate keys available in their `$HOME/.ssh`. + +`NOTE`: `http://` and `git://` URLs should be avoided if at all possible. These +protocols are unauthenticated, so a man-in-the-middle attacker can deliver +malicious code and compromise your system. HTTPS and SSH are strongly +preferred. + +The `group`, `platforms`, and `require` options are available and behave +exactly the same as they would for a normal gem. + +A git repository `SHOULD` have at least one file, at the root of the +directory containing the gem, with the extension `.gemspec`. This file +`MUST` contain a valid gem specification, as expected by the `gem build` +command. + +If a git repository does not have a `.gemspec`, bundler will attempt to +create one, but it will not contain any dependencies, executables, or +C extension compilation instructions. As a result, it may fail to properly +integrate into your application. + +If a git repository does have a `.gemspec` for the gem you attached it +to, a version specifier, if provided, means that the git repository is +only valid if the `.gemspec` specifies a version matching the version +specifier. If not, bundler will print a warning. + + gem "rails", "2.3.8", git: "https://github.com/rails/rails.git" + # bundle install will fail, because the .gemspec in the rails + # repository's master branch specifies version 3.0.0 + +If a git repository does `not` have a `.gemspec` for the gem you attached +it to, a version specifier `MUST` be provided. Bundler will use this +version in the simple `.gemspec` it creates. + +Git repositories support a number of additional options. + + * `branch`, `tag`, and `ref`: + You `MUST` only specify at most one of these options. The default + is `branch: "master"`. For example: + + gem "rails", git: "https://github.com/rails/rails.git", branch: "5-0-stable" + + gem "rails", git: "https://github.com/rails/rails.git", tag: "v5.0.0" + + gem "rails", git: "https://github.com/rails/rails.git", ref: "4aded" + + * `submodules`: + For reference, a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) + lets you have another git repository within a subfolder of your repository. + Specify `submodules: true` to cause bundler to expand any + submodules included in the git repository + +If a git repository contains multiple `.gemspecs`, each `.gemspec` +represents a gem located at the same place in the file system as +the `.gemspec`. + + |~rails [git root] + | |-rails.gemspec [rails gem located here] + |~actionpack + | |-actionpack.gemspec [actionpack gem located here] + |~activesupport + | |-activesupport.gemspec [activesupport gem located here] + |... + +To install a gem located in a git repository, bundler changes to +the directory containing the gemspec, runs `gem build name.gemspec` +and then installs the resulting gem. The `gem build` command, +which comes standard with Rubygems, evaluates the `.gemspec` in +the context of the directory in which it is located. + +### GIT SOURCE + +A custom git source can be defined via the `git_source` method. Provide the source's name +as an argument, and a block which receives a single argument and interpolates it into a +string to return the full repo address: + + git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" } + gem 'rails', stash: 'forks/rails' + +In addition, if you wish to choose a specific branch: + + gem "rails", stash: "forks/rails", branch: "branch_name" + +### GITHUB + +`NOTE`: This shorthand should be avoided until Bundler 2.0, since it +currently expands to an insecure `git://` URL. This allows a +man-in-the-middle attacker to compromise your system. + +If the git repository you want to use is hosted on GitHub and is public, you can use the +:github shorthand to specify the github username and repository name (without the +trailing ".git"), separated by a slash. If both the username and repository name are the +same, you can omit one. + + gem "rails", github: "rails/rails" + gem "rails", github: "rails" + +Are both equivalent to + + gem "rails", git: "https://github.com/rails/rails.git" + +Since the `github` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +You can also directly pass a pull request URL: + + gem "rails", github: "https://github.com/rails/rails/pull/43753" + +Which is equivalent to: + + gem "rails", github: "rails/rails", branch: "refs/pull/43753/head" + +### GIST + +If the git repository you want to use is hosted as a GitHub Gist and is public, you can use +the :gist shorthand to specify the gist identifier (without the trailing ".git"). + + gem "the_hatch", gist: "4815162342" + +Is equivalent to: + + gem "the_hatch", git: "https://gist.github.com/4815162342.git" + +Since the `gist` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +### BITBUCKET + +If the git repository you want to use is hosted on Bitbucket and is public, you can use the +:bitbucket shorthand to specify the bitbucket username and repository name (without the +trailing ".git"), separated by a slash. If both the username and repository name are the +same, you can omit one. + + gem "rails", bitbucket: "rails/rails" + gem "rails", bitbucket: "rails" + +Are both equivalent to + + gem "rails", git: "https://rails@bitbucket.org/rails/rails.git" + +Since the `bitbucket` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +### PATH + +You can specify that a gem is located in a particular location +on the file system. Relative paths are resolved relative to the +directory containing the `Gemfile`. + +Similar to the semantics of the `:git` option, the `:path` +option requires that the directory in question either contains +a `.gemspec` for the gem, or that you specify an explicit +version that bundler should use. + +Unlike `:git`, bundler does not compile C extensions for +gems specified as paths. + + gem "rails", path: "vendor/rails" + +If you would like to use multiple local gems directly from the filesystem, you can set a global `path` option to the path containing the gem's files. This will automatically load gemspec files from subdirectories. + + path 'components' do + gem 'admin_ui' + gem 'public_ui' + end + +## BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS + +The `:source`, `:git`, `:path`, `:group`, and `:platforms` options may be +applied to a group of gems by using block form. + + source "https://gems.example.com" do + gem "some_internal_gem" + gem "another_internal_gem" + end + + git "https://github.com/rails/rails.git" do + gem "activesupport" + gem "actionpack" + end + + platforms :ruby do + gem "ruby-debug" + gem "sqlite3" + end + + group :development, optional: true do + gem "wirble" + gem "faker" + end + +In the case of the group block form the :optional option can be given +to prevent a group from being installed unless listed in the `--with` +option given to the `bundle install` command. + +In the case of the `git` block form, the `:ref`, `:branch`, `:tag`, +and `:submodules` options may be passed to the `git` method, and +all gems in the block will inherit those options. + +The presence of a `source` block in a Gemfile also makes that source +available as a possible global source for any other gems which do not specify +explicit sources. Thus, when defining source blocks, it is +recommended that you also ensure all other gems in the Gemfile are using +explicit sources, either via source blocks or `:source` directives on +individual gems. + +## INSTALL_IF + +The `install_if` method allows gems to be installed based on a proc or lambda. +This is especially useful for optional gems that can only be used if certain +software is installed or some other conditions are met. + + install_if -> { RUBY_PLATFORM =~ /darwin/ } do + gem "pasteboard" + end + +## GEMSPEC + +The [`.gemspec`](https://guides.rubygems.org/specification-reference/) file is where + you provide metadata about your gem to Rubygems. Some required Gemspec + attributes include the name, description, and homepage of your gem. This is + also where you specify the dependencies your gem needs to run. + +If you wish to use Bundler to help install dependencies for a gem while it is +being developed, use the `gemspec` method to pull in the dependencies listed in +the `.gemspec` file. + +The `gemspec` method adds any runtime dependencies as gem requirements in the +default group. It also adds development dependencies as gem requirements in the +`development` group. Finally, it adds a gem requirement on your project (`path: +'.'`). In conjunction with `Bundler.setup`, this allows you to require project +files in your test code as you would if the project were installed as a gem; you +need not manipulate the load path manually or require project files via relative +paths. + +The `gemspec` method supports optional `:path`, `:glob`, `:name`, and `:development_group` +options, which control where bundler looks for the `.gemspec`, the glob it uses to look +for the gemspec (defaults to: `{,*,*/*}.gemspec`), what named `.gemspec` it uses +(if more than one is present), and which group development dependencies are included in. + +When a `gemspec` dependency encounters version conflicts during resolution, the +local version under development will always be selected -- even if there are +remote versions that better match other requirements for the `gemspec` gem. + +## SOURCE PRIORITY + +When attempting to locate a gem to satisfy a gem requirement, +bundler uses the following priority order: + + 1. The source explicitly attached to the gem (using `:source`, `:path`, or + `:git`) + 2. For implicit gems (dependencies of explicit gems), any source, git, or path + repository declared on the parent. This results in bundler prioritizing the + ActiveSupport gem from the Rails git repository over ones from + `rubygems.org` + 3. If neither of the above conditions are met, the global source will be used. + If multiple global sources are specified, they will be prioritized from + last to first, but this is deprecated since Bundler 1.13, so Bundler prints + a warning and will abort with an error in the future. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/man/index.txt b/bin/gems/bundler-2.5.9/lib/bundler/man/index.txt new file mode 100644 index 00000000..24f7633e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/man/index.txt @@ -0,0 +1,29 @@ +Gemfile(5) gemfile.5 +bundle(1) bundle.1 +bundle-add(1) bundle-add.1 +bundle-binstubs(1) bundle-binstubs.1 +bundle-cache(1) bundle-cache.1 +bundle-check(1) bundle-check.1 +bundle-clean(1) bundle-clean.1 +bundle-config(1) bundle-config.1 +bundle-console(1) bundle-console.1 +bundle-doctor(1) bundle-doctor.1 +bundle-exec(1) bundle-exec.1 +bundle-gem(1) bundle-gem.1 +bundle-help(1) bundle-help.1 +bundle-info(1) bundle-info.1 +bundle-init(1) bundle-init.1 +bundle-inject(1) bundle-inject.1 +bundle-install(1) bundle-install.1 +bundle-list(1) bundle-list.1 +bundle-lock(1) bundle-lock.1 +bundle-open(1) bundle-open.1 +bundle-outdated(1) bundle-outdated.1 +bundle-platform(1) bundle-platform.1 +bundle-plugin(1) bundle-plugin.1 +bundle-pristine(1) bundle-pristine.1 +bundle-remove(1) bundle-remove.1 +bundle-show(1) bundle-show.1 +bundle-update(1) bundle-update.1 +bundle-version(1) bundle-version.1 +bundle-viz(1) bundle-viz.1 diff --git a/bin/gems/bundler-2.5.9/lib/bundler/match_metadata.rb b/bin/gems/bundler-2.5.9/lib/bundler/match_metadata.rb new file mode 100644 index 00000000..f6cc27df --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/match_metadata.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Bundler + module MatchMetadata + def matches_current_metadata? + matches_current_ruby? && matches_current_rubygems? + end + + def matches_current_ruby? + @required_ruby_version.satisfied_by?(Gem.ruby_version) + end + + def matches_current_rubygems? + @required_rubygems_version.satisfied_by?(Gem.rubygems_version) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/match_platform.rb b/bin/gems/bundler-2.5.9/lib/bundler/match_platform.rb new file mode 100644 index 00000000..ece9fb86 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/match_platform.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require_relative "gem_helpers" + +module Bundler + module MatchPlatform + include GemHelpers + + def match_platform(p) + MatchPlatform.platforms_match?(platform, p) + end + + def self.platforms_match?(gemspec_platform, local_platform) + return true if gemspec_platform.nil? + return true if gemspec_platform == Gem::Platform::RUBY + return true if local_platform == gemspec_platform + gemspec_platform = Gem::Platform.new(gemspec_platform) + return true if gemspec_platform === local_platform + + false + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/match_remote_metadata.rb b/bin/gems/bundler-2.5.9/lib/bundler/match_remote_metadata.rb new file mode 100644 index 00000000..5e46d524 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/match_remote_metadata.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Bundler + module FetchMetadata + # A fallback is included because the original version of the specification + # API didn't include that field, so some marshalled specs in the index have it + # set to +nil+. + def matches_current_ruby? + @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default + + super + end + + def matches_current_rubygems? + # A fallback is included because the original version of the specification + # API didn't include that field, so some marshalled specs in the index have it + # set to +nil+. + @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default + + super + end + end + + module MatchRemoteMetadata + include MatchMetadata + + prepend FetchMetadata + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/mirror.rb b/bin/gems/bundler-2.5.9/lib/bundler/mirror.rb new file mode 100644 index 00000000..494a6d6a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/mirror.rb @@ -0,0 +1,221 @@ +# frozen_string_literal: true + +require "socket" + +module Bundler + class Settings + # Class used to build the mirror set and then find a mirror for a given URI + # + # @param prober [Prober object, nil] by default a TCPSocketProbe, this object + # will be used to probe the mirror address to validate that the mirror replies. + class Mirrors + def initialize(prober = nil) + @all = Mirror.new + @prober = prober || TCPSocketProbe.new + @mirrors = {} + end + + # Returns a mirror for the given uri. + # + # Depending on the uri having a valid mirror or not, it may be a + # mirror that points to the provided uri + def for(uri) + if @all.validate!(@prober).valid? + @all + else + fetch_valid_mirror_for(Settings.normalize_uri(uri)) + end + end + + def each + @mirrors.each do |k, v| + yield k, v.uri.to_s + end + end + + def parse(key, value) + config = MirrorConfig.new(key, value) + mirror = if config.all? + @all + else + @mirrors[config.uri] ||= Mirror.new + end + config.update_mirror(mirror) + end + + private + + def fetch_valid_mirror_for(uri) + downcased = uri.to_s.downcase + mirror = @mirrors[downcased] || @mirrors[Gem::URI(downcased).host] || Mirror.new(uri) + mirror.validate!(@prober) + mirror = Mirror.new(uri) unless mirror.valid? + mirror + end + end + + # A mirror + # + # Contains both the uri that should be used as a mirror and the + # fallback timeout which will be used for probing if the mirror + # replies on time or not. + class Mirror + DEFAULT_FALLBACK_TIMEOUT = 0.1 + + attr_reader :uri, :fallback_timeout + + def initialize(uri = nil, fallback_timeout = 0) + self.uri = uri + self.fallback_timeout = fallback_timeout + @valid = nil + end + + def uri=(uri) + @uri = if uri.nil? + nil + else + Gem::URI(uri.to_s) + end + @valid = nil + end + + def fallback_timeout=(timeout) + case timeout + when true, "true" + @fallback_timeout = DEFAULT_FALLBACK_TIMEOUT + when false, "false" + @fallback_timeout = 0 + else + @fallback_timeout = timeout.to_i + end + @valid = nil + end + + def ==(other) + !other.nil? && uri == other.uri && fallback_timeout == other.fallback_timeout + end + + def valid? + return false if @uri.nil? + return @valid unless @valid.nil? + false + end + + def validate!(probe = nil) + @valid = false if uri.nil? + if @valid.nil? + @valid = fallback_timeout == 0 || (probe || TCPSocketProbe.new).replies?(self) + end + self + end + end + + # Class used to parse one configuration line + # + # Gets the configuration line and the value. + # This object provides a `update_mirror` method + # used to setup the given mirror value. + class MirrorConfig + attr_accessor :uri, :value + + def initialize(config_line, value) + uri, fallback = + config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures + @fallback = !fallback.nil? + @all = false + if uri == "all" + @all = true + else + @uri = Gem::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri + end + @value = value + end + + def all? + @all + end + + def update_mirror(mirror) + if @fallback + mirror.fallback_timeout = @value + else + mirror.uri = Settings.normalize_uri(@value) + end + end + end + + # Class used for probing TCP availability for a given mirror. + class TCPSocketProbe + def replies?(mirror) + MirrorSockets.new(mirror).any? do |socket, address, timeout| + socket.connect_nonblock(address) + rescue Errno::EINPROGRESS + wait_for_writtable_socket(socket, address, timeout) + rescue RuntimeError # Connection failed somehow, again + false + end + end + + private + + def wait_for_writtable_socket(socket, address, timeout) + if IO.select(nil, [socket], nil, timeout) + probe_writtable_socket(socket, address) + else # TCP Handshake timed out, or there is something dropping packets + false + end + end + + def probe_writtable_socket(socket, address) + socket.connect_nonblock(address) + rescue Errno::EISCONN + true + rescue StandardError # Connection failed + false + end + end + end + + # Class used to build the list of sockets that correspond to + # a given mirror. + # + # One mirror may correspond to many different addresses, both + # because of it having many dns entries or because + # the network interface is both ipv4 and ipv5 + class MirrorSockets + def initialize(mirror) + @timeout = mirror.fallback_timeout + @addresses = Socket.getaddrinfo(mirror.uri.host, mirror.uri.port).map do |address| + SocketAddress.new(address[0], address[3], address[1]) + end + end + + def any? + @addresses.any? do |address| + socket = Socket.new(Socket.const_get(address.type), Socket::SOCK_STREAM, 0) + socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) + value = yield socket, address.to_socket_address, @timeout + socket.close unless socket.closed? + value + end + end + end + + # Socket address builder. + # + # Given a socket type, a host and a port, + # provides a method to build sockaddr string + class SocketAddress + attr_reader :type, :host, :port + + def initialize(type, host, port) + @type = type + @host = host + @port = port + end + + def to_socket_address + Socket.pack_sockaddr_in(@port, @host) + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin.rb new file mode 100644 index 00000000..588fa79b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin.rb @@ -0,0 +1,359 @@ +# frozen_string_literal: true + +require_relative "plugin/api" + +module Bundler + module Plugin + autoload :DSL, File.expand_path("plugin/dsl", __dir__) + autoload :Events, File.expand_path("plugin/events", __dir__) + autoload :Index, File.expand_path("plugin/index", __dir__) + autoload :Installer, File.expand_path("plugin/installer", __dir__) + autoload :SourceList, File.expand_path("plugin/source_list", __dir__) + + class MalformattedPlugin < PluginError; end + class UndefinedCommandError < PluginError; end + class UnknownSourceError < PluginError; end + class PluginInstallError < PluginError; end + + PLUGIN_FILE_NAME = "plugins.rb" + + module_function + + def reset! + instance_variables.each {|i| remove_instance_variable(i) } + + @sources = {} + @commands = {} + @hooks_by_event = Hash.new {|h, k| h[k] = [] } + @loaded_plugin_names = [] + end + + reset! + + # Installs a new plugin by the given name + # + # @param [Array] names the name of plugin to be installed + # @param [Hash] options various parameters as described in description. + # Refer to cli/plugin for available options + def install(names, options) + raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"] + + specs = Installer.new.install(names, options) + + save_plugins names, specs + rescue PluginError + specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) } + specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) } + + raise + end + + # Uninstalls plugins by the given names + # + # @param [Array] names the names of plugins to be uninstalled + def uninstall(names, options) + if names.empty? && !options[:all] + Bundler.ui.error "No plugins to uninstall. Specify at least 1 plugin to uninstall.\n"\ + "Use --all option to uninstall all the installed plugins." + return + end + + names = index.installed_plugins if options[:all] + if names.any? + names.each do |name| + if index.installed?(name) + path = index.plugin_path(name).to_s + Bundler.rm_rf(path) if index.installed_in_plugin_root?(name) + index.unregister_plugin(name) + Bundler.ui.info "Uninstalled plugin #{name}" + else + Bundler.ui.error "Plugin #{name} is not installed \n" + end + end + else + Bundler.ui.info "No plugins installed" + end + end + + # List installed plugins and commands + # + def list + installed_plugins = index.installed_plugins + if installed_plugins.any? + output = String.new + installed_plugins.each do |plugin| + output << "#{plugin}\n" + output << "-----\n" + index.plugin_commands(plugin).each do |command| + output << " #{command}\n" + end + output << "\n" + end + else + output = "No plugins installed" + end + Bundler.ui.info output + end + + # Evaluates the Gemfile with a limited DSL and installs the plugins + # specified by plugin method + # + # @param [Pathname] gemfile path + # @param [Proc] block that can be evaluated for (inline) Gemfile + def gemfile_install(gemfile = nil, &inline) + Bundler.settings.temporary(frozen: false, deployment: false) do + builder = DSL.new + if block_given? + builder.instance_eval(&inline) + else + builder.eval_gemfile(gemfile) + end + builder.check_primary_source_safety + definition = builder.to_definition(nil, true) + + return if definition.dependencies.empty? + + plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } + installed_specs = Installer.new.install_definition(definition) + + save_plugins plugins, installed_specs, builder.inferred_plugins + end + rescue RuntimeError => e + unless e.is_a?(GemfileError) + Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" + end + raise + end + + # The index object used to store the details about the plugin + def index + @index ||= Index.new + end + + # The directory root for all plugin related data + # + # If run in an app, points to local root, in app_config_path + # Otherwise, points to global root, in Bundler.user_bundle_path("plugin") + def root + @root ||= if SharedHelpers.in_bundle? + local_root + else + global_root + end + end + + def local_root + Bundler.app_config_path.join("plugin") + end + + # The global directory root for all plugin related data + def global_root + Bundler.user_bundle_path("plugin") + end + + # The cache directory for plugin stuffs + def cache + @cache ||= root.join("cache") + end + + # To be called via the API to register to handle a command + def add_command(command, cls) + @commands[command] = cls + end + + # Checks if any plugin handles the command + def command?(command) + !index.command_plugin(command).nil? + end + + # To be called from Cli class to pass the command and argument to + # appropriate plugin class + def exec_command(command, args) + raise UndefinedCommandError, "Command `#{command}` not found" unless command? command + + load_plugin index.command_plugin(command) unless @commands.key? command + + @commands[command].new.exec(command, args) + end + + # To be called via the API to register to handle a source plugin + def add_source(source, cls) + @sources[source] = cls + end + + # Checks if any plugin declares the source + def source?(name) + !index.source_plugin(name.to_s).nil? + end + + # @return [Class] that handles the source. The class includes API::Source + def source(name) + raise UnknownSourceError, "Source #{name} not found" unless source? name + + load_plugin(index.source_plugin(name)) unless @sources.key? name + + @sources[name] + end + + # @param [Hash] The options that are present in the lock file + # @return [API::Source] the instance of the class that handles the source + # type passed in locked_opts + def from_lock(locked_opts) + src = source(locked_opts["type"]) + + src.new(locked_opts.merge("uri" => locked_opts["remote"])) + end + + # To be called via the API to register a hooks and corresponding block that + # will be called to handle the hook + def add_hook(event, &block) + unless Events.defined_event?(event) + raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" + end + @hooks_by_event[event.to_s] << block + end + + # Runs all the hooks that are registered for the passed event + # + # It passes the passed arguments and block to the block registered with + # the api. + # + # @param [String] event + def hook(event, *args, &arg_blk) + return unless Bundler.feature_flag.plugins? + unless Events.defined_event?(event) + raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" + end + + plugins = index.hook_plugins(event) + return unless plugins.any? + + plugins.each {|name| load_plugin(name) } + + @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) } + end + + # currently only intended for specs + # + # @return [String, nil] installed path + def installed?(plugin) + Index.new.installed?(plugin) + end + + # @return [true, false] whether the plugin is loaded + def loaded?(plugin) + @loaded_plugin_names.include?(plugin) + end + + # Post installation processing and registering with index + # + # @param [Array] plugins list to be installed + # @param [Hash] specs of plugins mapped to installation path (currently they + # contain all the installed specs, including plugins) + # @param [Array] names of inferred source plugins that can be ignored + def save_plugins(plugins, specs, optional_plugins = []) + plugins.each do |name| + next if index.installed?(name) + + spec = specs[name] + + save_plugin(name, spec, optional_plugins.include?(name)) + end + end + + # Checks if the gem is good to be a plugin + # + # At present it only checks whether it contains plugins.rb file + # + # @param [Pathname] plugin_path the path plugin is installed at + # @raise [MalformattedPlugin] if plugins.rb file is not found + def validate_plugin!(plugin_path) + plugin_file = plugin_path.join(PLUGIN_FILE_NAME) + raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file? + end + + # Validates and registers a plugin. + # + # @param [String] name the name of the plugin + # @param [Specification] spec of installed plugin + # @param [Boolean] optional_plugin, removed if there is conflict with any + # other plugin (used for default source plugins) + # + # @raise [PluginInstallError] if validation or registration raises any error + def save_plugin(name, spec, optional_plugin = false) + validate_plugin! Pathname.new(spec.full_gem_path) + installed = register_plugin(name, spec, optional_plugin) + Bundler.ui.info "Installed plugin #{name}" if installed + rescue PluginError => e + raise PluginInstallError, "Failed to install plugin `#{spec.name}`, due to #{e.class} (#{e.message})" + end + + # Runs the plugins.rb file in an isolated namespace, records the plugin + # actions it registers for and then passes the data to index to be stored. + # + # @param [String] name the name of the plugin + # @param [Specification] spec of installed plugin + # @param [Boolean] optional_plugin, removed if there is conflict with any + # other plugin (used for default source plugins) + # + # @raise [MalformattedPlugin] if plugins.rb raises any error + def register_plugin(name, spec, optional_plugin = false) + commands = @commands + sources = @sources + hooks = @hooks_by_event + + @commands = {} + @sources = {} + @hooks_by_event = Hash.new {|h, k| h[k] = [] } + + load_paths = spec.load_paths + Gem.add_to_load_path(*load_paths) + path = Pathname.new spec.full_gem_path + + begin + load path.join(PLUGIN_FILE_NAME), true + rescue StandardError => e + raise MalformattedPlugin, "#{e.class}: #{e.message}" + end + + if optional_plugin && @sources.keys.any? {|s| source? s } + Bundler.rm_rf(path) + false + else + index.register_plugin(name, path.to_s, load_paths, @commands.keys, + @sources.keys, @hooks_by_event.keys) + true + end + ensure + @commands = commands + @sources = sources + @hooks_by_event = hooks + end + + # Executes the plugins.rb file + # + # @param [String] name of the plugin + def load_plugin(name) + return unless name && !name.empty? + return if loaded?(name) + + # Need to ensure before this that plugin root where the rest of gems + # are installed to be on load path to support plugin deps. Currently not + # done to avoid conflicts + path = index.plugin_path(name) + + Gem.add_to_load_path(*index.load_paths(name)) + + load path.join(PLUGIN_FILE_NAME) + + @loaded_plugin_names << name + rescue RuntimeError => e + Bundler.ui.error "Failed loading plugin #{name}: #{e.message}" + raise + end + + class << self + private :load_plugin, :register_plugin, :save_plugins, :validate_plugin! + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/api.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/api.rb new file mode 100644 index 00000000..ee2bffe3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/api.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module Bundler + # This is the interfacing class represents the API that we intend to provide + # the plugins to use. + # + # For plugins to be independent of the Bundler internals they shall limit their + # interactions to methods of this class only. This will save them from breaking + # when some internal change. + # + # Currently we are delegating the methods defined in Bundler class to + # itself. So, this class acts as a buffer. + # + # If there is some change in the Bundler class that is incompatible to its + # previous behavior or if otherwise desired, we can reimplement(or implement) + # the method to preserve compatibility. + # + # To use this, either the class can inherit this class or use it directly. + # For example of both types of use, refer the file `spec/plugins/command.rb` + # + # To use it without inheriting, you will have to create an object of this + # to use the functions (except for declaration functions like command, source, + # and hooks). + module Plugin + class API + autoload :Source, File.expand_path("api/source", __dir__) + + # The plugins should declare that they handle a command through this helper. + # + # @param [String] command being handled by them + # @param [Class] (optional) class that handles the command. If not + # provided, the `self` class will be used. + def self.command(command, cls = self) + Plugin.add_command command, cls + end + + # The plugins should declare that they provide a installation source + # through this helper. + # + # @param [String] the source type they provide + # @param [Class] (optional) class that handles the source. If not + # provided, the `self` class will be used. + def self.source(source, cls = self) + cls.send :include, Bundler::Plugin::API::Source + Plugin.add_source source, cls + end + + def self.hook(event, &block) + Plugin.add_hook(event, &block) + end + + # The cache dir to be used by the plugins for storage + # + # @return [Pathname] path of the cache dir + def cache_dir + Plugin.cache.join("plugins") + end + + # A tmp dir to be used by plugins + # Accepts names that get concatenated as suffix + # + # @return [Pathname] object for the new directory created + def tmp(*names) + Bundler.tmp(["plugin", *names].join("-")) + end + + def method_missing(name, *args, &blk) + return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name) + + return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name) + + super + end + + def respond_to_missing?(name, include_private = false) + SharedHelpers.respond_to?(name, include_private) || + Bundler.respond_to?(name, include_private) || super + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/api/source.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/api/source.rb new file mode 100644 index 00000000..8563ee35 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/api/source.rb @@ -0,0 +1,321 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class API + # This class provides the base to build source plugins + # All the method here are required to build a source plugin (except + # `uri_hash`, `gem_install_dir`; they are helpers). + # + # Defaults for methods, where ever possible are provided which is + # expected to work. But, all source plugins have to override + # `fetch_gemspec_files` and `install`. Defaults are also not provided for + # `remote!`, `cache!` and `unlock!`. + # + # The defaults shall work for most situations but nevertheless they can + # be (preferably should be) overridden as per the plugins' needs safely + # (as long as they behave as expected). + # On overriding `initialize` you should call super first. + # + # If required plugin should override `hash`, `==` and `eql?` methods to be + # able to match objects representing same sources, but may be created in + # different situation (like form gemfile and lockfile). The default ones + # checks only for class and uri, but elaborate source plugins may need + # more comparisons (e.g. git checking on branch or tag). + # + # @!attribute [r] uri + # @return [String] the remote specified with `source` block in Gemfile + # + # @!attribute [r] options + # @return [String] options passed during initialization (either from + # lockfile or Gemfile) + # + # @!attribute [r] name + # @return [String] name that can be used to uniquely identify a source + # + # @!attribute [rw] dependency_names + # @return [Array] Names of dependencies that the source should + # try to resolve. It is not necessary to use this list internally. This + # is present to be compatible with `Definition` and is used by + # rubygems source. + module Source + attr_reader :uri, :options, :name, :checksum_store + attr_accessor :dependency_names + + def initialize(opts) + @options = opts + @dependency_names = [] + @uri = opts["uri"] + @type = opts["type"] + @name = opts["name"] || "#{@type} at #{@uri}" + @checksum_store = Checksum::Store.new + end + + # This is used by the default `spec` method to constructs the + # Specification objects for the gems and versions that can be installed + # by this source plugin. + # + # Note: If the spec method is overridden, this function is not necessary + # + # @return [Array] paths of the gemspec files for gems that can + # be installed + def fetch_gemspec_files + [] + end + + # Options to be saved in the lockfile so that the source plugin is able + # to check out same version of gem later. + # + # There options are passed when the source plugin is created from the + # lock file. + # + # @return [Hash] + def options_to_lock + {} + end + + # Install the gem specified by the spec at appropriate path. + # `install_path` provides a sufficient default, if the source can only + # satisfy one gem, but is not binding. + # + # @return [String] post installation message (if any) + def install(spec, opts) + raise MalformattedPlugin, "Source plugins need to override the install method." + end + + # It builds extensions, generates bins and installs them for the spec + # provided. + # + # It depends on `spec.loaded_from` to get full_gem_path. The source + # plugins should set that. + # + # It should be called in `install` after the plugin is done placing the + # gem at correct install location. + # + # It also runs Gem hooks `pre_install`, `post_build` and `post_install` + # + # Note: Do not override if you don't know what you are doing. + def post_install(spec, disable_exts = false) + opts = { env_shebang: false, disable_extensions: disable_exts } + installer = Bundler::Source::Path::Installer.new(spec, opts) + installer.post_install + end + + # A default installation path to install a single gem. If the source + # servers multiple gems, it's not of much use and the source should one + # of its own. + def install_path + @install_path ||= + begin + base_name = File.basename(Gem::URI.parse(uri).normalize.path) + + gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") + end + end + + # Parses the gemspec files to find the specs for the gems that can be + # satisfied by the source. + # + # Few important points to keep in mind: + # - If the gems are not installed then it shall return specs for all + # the gems it can satisfy + # - If gem is installed (that is to be detected by the plugin itself) + # then it shall return at least the specs that are installed. + # - The `loaded_from` for each of the specs shall be correct (it is + # used to find the load path) + # + # @return [Bundler::Index] index containing the specs + def specs + files = fetch_gemspec_files + + Bundler::Index.build do |index| + files.each do |file| + next unless spec = Bundler.load_gemspec(file) + Bundler.rubygems.set_installed_by_version(spec) + + spec.source = self + Bundler.rubygems.validate(spec) + + index << spec + end + end + end + + # Set internal representation to fetch the gems/specs locally. + # + # When this is called, the source should try to fetch the specs and + # install from the local system. + def local! + end + + # Set internal representation to fetch the gems/specs from remote. + # + # When this is called, the source should try to fetch the specs and + # install from remote path. + def remote! + end + + # Set internal representation to fetch the gems/specs from app cache. + # + # When this is called, the source should try to fetch the specs and + # install from the path provided by `app_cache_path`. + def cached! + end + + # This is called to update the spec and installation. + # + # If the source plugin is loaded from lockfile or otherwise, it shall + # refresh the cache/specs (e.g. git sources can make a fresh clone). + def unlock! + end + + # Name of directory where plugin the is expected to cache the gems when + # #cache is called. + # + # Also this name is matched against the directories in cache for pruning + # + # This is used by `app_cache_path` + def app_cache_dirname + base_name = File.basename(Gem::URI.parse(uri).normalize.path) + "#{base_name}-#{uri_hash}" + end + + # This method is called while caching to save copy of the gems that the + # source can resolve to path provided by `app_cache_app`so that they can + # be reinstalled from the cache without querying the remote (i.e. an + # alternative to remote) + # + # This is stored with the app and source plugins should try to provide + # specs and install only from this cache when `cached!` is called. + # + # This cache is different from the internal caching that can be done + # at sub paths of `cache_path` (from API). This can be though as caching + # by bundler. + def cache(spec, custom_path = nil) + new_cache_path = app_cache_path(custom_path) + + FileUtils.rm_rf(new_cache_path) + FileUtils.cp_r(install_path, new_cache_path) + FileUtils.touch(app_cache_path.join(".bundlecache")) + end + + # This shall check if two source object represent the same source. + # + # The comparison shall take place only on the attribute that can be + # inferred from the options passed from Gemfile and not on attributes + # that are used to pin down the gem to specific version (e.g. Git + # sources should compare on branch and tag but not on commit hash) + # + # The sources objects are constructed from Gemfile as well as from + # lockfile. To converge the sources, it is necessary that they match. + # + # The same applies for `eql?` and `hash` + def ==(other) + other.is_a?(self.class) && uri == other.uri + end + + # When overriding `eql?` please preserve the behaviour as mentioned in + # docstring for `==` method. + alias_method :eql?, :== + + # When overriding `hash` please preserve the behaviour as mentioned in + # docstring for `==` method, i.e. two methods equal by above comparison + # should have same hash. + def hash + [self.class, uri].hash + end + + # A helper method, not necessary if not used internally. + def installed? + File.directory?(install_path) + end + + # The full path where the plugin should cache the gem so that it can be + # installed latter. + # + # Note: Do not override if you don't know what you are doing. + def app_cache_path(custom_path = nil) + @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def unmet_deps + specs.unmet_dependency_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def spec_names + specs.spec_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def add_dependency_names(names) + @dependencies |= Array(names) + end + + # NOTE: Do not override if you don't know what you are doing. + def can_lock?(spec) + spec.source == self + end + + # Generates the content to be entered into the lockfile. + # Saves type and remote and also calls to `options_to_lock`. + # + # Plugin should use `options_to_lock` to save information in lockfile + # and not override this. + # + # Note: Do not override if you don't know what you are doing. + def to_lock + out = String.new("#{LockfileParser::PLUGIN}\n") + out << " remote: #{@uri}\n" + out << " type: #{@type}\n" + options_to_lock.each do |opt, value| + out << " #{opt}: #{value}\n" + end + out << " specs:\n" + end + + def to_s + "plugin source for #{@type} with uri #{@uri}" + end + alias_method :identifier, :to_s + + # NOTE: Do not override if you don't know what you are doing. + def include?(other) + other == self + end + + def uri_hash + SharedHelpers.digest(:SHA1).hexdigest(uri) + end + + # NOTE: Do not override if you don't know what you are doing. + def gem_install_dir + Bundler.install_path + end + + # It is used to obtain the full_gem_path. + # + # spec's loaded_from path is expanded against this to get full_gem_path + # + # Note: Do not override if you don't know what you are doing. + def root + Bundler.root + end + + # @private + # This API on source might not be stable, and for now we expect plugins + # to download all specs in `#specs`, so we implement the method for + # compatibility purposes and leave it undocumented (and don't support) + # overriding it) + def double_check_for(*); end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/dsl.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/dsl.rb new file mode 100644 index 00000000..da751d17 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/dsl.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + # Dsl to parse the Gemfile looking for plugins to install + class DSL < Bundler::Dsl + class PluginGemfileError < PluginError; end + alias_method :_gem, :gem # To use for plugin installation as gem + + # So that we don't have to override all there methods to dummy ones + # explicitly. + # They will be handled by method_missing + [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m } + + # This lists the plugins that was added automatically and not specified by + # the user. + # + # When we encounter :type attribute with a source block, we add a plugin + # by name bundler-source- to list of plugins to be installed. + # + # These plugins are optional and are not installed when there is conflict + # with any other plugin. + attr_reader :inferred_plugins + + def initialize + super + @sources = Plugin::SourceList.new + @inferred_plugins = [] # The source plugins inferred from :type + end + + def plugin(name, *args) + _gem(name, *args) + end + + def method_missing(name, *args) + raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name + end + + def source(source, *args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + options = normalize_hash(options) + return super unless options.key?("type") + + plugin_name = "bundler-source-#{options["type"]}" + + return if @dependencies.any? {|d| d.name == plugin_name } + + plugin(plugin_name) + @inferred_plugins << plugin_name + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/events.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/events.rb new file mode 100644 index 00000000..bc037d1a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/events.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + module Events + def self.define(const, event) + const = const.to_sym.freeze + if const_defined?(const) && const_get(const) != event + raise ArgumentError, "Attempting to reassign #{const} to a different value" + end + const_set(const, event) unless const_defined?(const) + @events ||= {} + @events[event] = const + end + private_class_method :define + + def self.reset + @events.each_value do |const| + remove_const(const) + end + @events = nil + end + private_class_method :reset + + # Check if an event has been defined + # @param event [String] An event to check + # @return [Boolean] A boolean indicating if the event has been defined + def self.defined_event?(event) + @events ||= {} + @events.key?(event) + end + + # @!parse + # A hook called before each individual gem is installed + # Includes a Bundler::ParallelInstaller::SpecInstallation. + # No state, error, post_install_message will be present as nothing has installed yet + # GEM_BEFORE_INSTALL = "before-install" + define :GEM_BEFORE_INSTALL, "before-install" + + # @!parse + # A hook called after each individual gem is installed + # Includes a Bundler::ParallelInstaller::SpecInstallation. + # - If state is failed, an error will be present. + # - If state is success, a post_install_message may be present. + # GEM_AFTER_INSTALL = "after-install" + define :GEM_AFTER_INSTALL, "after-install" + + # @!parse + # A hook called before any gems install + # Includes an Array of Bundler::Dependency objects + # GEM_BEFORE_INSTALL_ALL = "before-install-all" + define :GEM_BEFORE_INSTALL_ALL, "before-install-all" + + # @!parse + # A hook called after any gems install + # Includes an Array of Bundler::Dependency objects + # GEM_AFTER_INSTALL_ALL = "after-install-all" + define :GEM_AFTER_INSTALL_ALL, "after-install-all" + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/index.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/index.rb new file mode 100644 index 00000000..c2ab8f90 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/index.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true + +module Bundler + # Manages which plugins are installed and their sources. This also is supposed to map + # which plugin does what (currently the features are not implemented so this class is + # now a stub class). + module Plugin + class Index + class CommandConflict < PluginError + def initialize(plugin, commands) + msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered." + super msg + end + end + + class SourceConflict < PluginError + def initialize(plugin, sources) + msg = "Source(s) `#{sources.join("`, `")}` declared by #{plugin} are already registered." + super msg + end + end + + attr_reader :commands + + def initialize + @plugin_paths = {} + @commands = {} + @sources = {} + @hooks = {} + @load_paths = {} + + begin + load_index(global_index_file, true) + rescue GenericSystemCallError + # no need to fail when on a read-only FS, for example + nil + end + load_index(local_index_file) if SharedHelpers.in_bundle? + end + + # This function is to be called when a new plugin is installed. This + # function shall add the functions of the plugin to existing maps and also + # the name to source location. + # + # @param [String] name of the plugin to be registered + # @param [String] path where the plugin is installed + # @param [Array] load_paths for the plugin + # @param [Array] commands that are handled by the plugin + # @param [Array] sources that are handled by the plugin + def register_plugin(name, path, load_paths, commands, sources, hooks) + old_commands = @commands.dup + + common = commands & @commands.keys + raise CommandConflict.new(name, common) unless common.empty? + commands.each {|c| @commands[c] = name } + + common = sources & @sources.keys + raise SourceConflict.new(name, common) unless common.empty? + sources.each {|k| @sources[k] = name } + + hooks.each do |event| + event_hooks = (@hooks[event] ||= []) << name + event_hooks.uniq! + end + + @plugin_paths[name] = path + @load_paths[name] = load_paths + save_index + rescue StandardError + @commands = old_commands + raise + end + + def unregister_plugin(name) + @commands.delete_if {|_, v| v == name } + @sources.delete_if {|_, v| v == name } + @hooks.each do |hook, names| + names.delete(name) + @hooks.delete(hook) if names.empty? + end + @plugin_paths.delete(name) + @load_paths.delete(name) + save_index + end + + # Path of default index file + def index_file + Plugin.root.join("index") + end + + # Path where the global index file is stored + def global_index_file + Plugin.global_root.join("index") + end + + # Path where the local index file is stored + def local_index_file + Plugin.local_root.join("index") + end + + def plugin_path(name) + Pathname.new @plugin_paths[name] + end + + def load_paths(name) + @load_paths[name] + end + + # Fetch the name of plugin handling the command + def command_plugin(command) + @commands[command] + end + + def installed?(name) + @plugin_paths[name] + end + + def installed_plugins + @plugin_paths.keys + end + + def plugin_commands(plugin) + @commands.find_all {|_, n| n == plugin }.map(&:first) + end + + def source?(source) + @sources.key? source + end + + def source_plugin(name) + @sources[name] + end + + # Returns the list of plugin names handling the passed event + def hook_plugins(event) + @hooks[event] || [] + end + + # This plugin is installed inside the .bundle/plugin directory, + # and thus is managed solely by Bundler + def installed_in_plugin_root?(name) + return false unless (path = installed?(name)) + + path.start_with?("#{Plugin.root}/") + end + + private + + # Reads the index file from the directory and initializes the instance + # variables. + # + # It skips the sources if the second param is true + # @param [Pathname] index file path + # @param [Boolean] is the index file global index + def load_index(index_file, global = false) + SharedHelpers.filesystem_access(index_file, :read) do |index_f| + valid_file = index_f&.exist? && !index_f.size.zero? + break unless valid_file + + data = index_f.read + + require_relative "../yaml_serializer" + index = YAMLSerializer.load(data) + + @commands.merge!(index["commands"]) + @hooks.merge!(index["hooks"]) + @load_paths.merge!(index["load_paths"]) + @plugin_paths.merge!(index["plugin_paths"]) + @sources.merge!(index["sources"]) unless global + end + end + + # Should be called when any of the instance variables change. Stores the + # instance variables in YAML format. (The instance variables are supposed + # to be only String key value pairs) + def save_index + index = { + "commands" => @commands, + "hooks" => @hooks, + "load_paths" => @load_paths, + "plugin_paths" => @plugin_paths, + "sources" => @sources, + } + + require_relative "../yaml_serializer" + SharedHelpers.filesystem_access(index_file) do |index_f| + FileUtils.mkdir_p(index_f.dirname) + File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer.rb new file mode 100644 index 00000000..4f60862b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +module Bundler + # Handles the installation of plugin in appropriate directories. + # + # This class is supposed to be wrapper over the existing gem installation infra + # but currently it itself handles everything as the Source's subclasses (e.g. Source::RubyGems) + # are heavily dependent on the Gemfile. + module Plugin + class Installer + autoload :Rubygems, File.expand_path("installer/rubygems", __dir__) + autoload :Git, File.expand_path("installer/git", __dir__) + autoload :Path, File.expand_path("installer/path", __dir__) + + def install(names, options) + check_sources_consistency!(options) + + version = options[:version] || [">= 0"] + + if options[:git] + install_git(names, version, options) + elsif options[:path] + install_path(names, version, options[:path]) + else + sources = options[:source] || Gem.sources + install_rubygems(names, version, sources) + end + end + + # Installs the plugin from Definition object created by limited parsing of + # Gemfile searching for plugins to be installed + # + # @param [Definition] definition object + # @return [Hash] map of names to their specs they are installed with + def install_definition(definition) + def definition.lock(*); end + definition.resolve_remotely! + specs = definition.specs + + install_from_specs specs + end + + private + + def check_sources_consistency!(options) + if options.key?(:git) && options.key?(:local_git) + raise InvalidOption, "Remote and local plugin git sources can't be both specified" + end + + # back-compat; local_git is an alias for git + if options.key?(:local_git) + Bundler::SharedHelpers.major_deprecation(2, "--local_git is deprecated, use --git") + options[:git] = options.delete(:local_git) + end + + if (options.keys & [:source, :git, :path]).length > 1 + raise InvalidOption, "Only one of --source, --git, or --path may be specified" + end + + if (options.key?(:branch) || options.key?(:ref)) && !options.key?(:git) + raise InvalidOption, "--#{options.key?(:branch) ? "branch" : "ref"} can only be used with git sources" + end + + if options.key?(:branch) && options.key?(:ref) + raise InvalidOption, "--branch and --ref can't be both specified" + end + end + + def install_git(names, version, options) + source_list = SourceList.new + source = source_list.add_git_source({ "uri" => options[:git], + "branch" => options[:branch], + "ref" => options[:ref] }) + + install_all_sources(names, version, source_list, source) + end + + def install_path(names, version, path) + source_list = SourceList.new + source = source_list.add_path_source({ "path" => path, "root_path" => SharedHelpers.pwd }) + + install_all_sources(names, version, source_list, source) + end + + # Installs the plugin from rubygems source and returns the path where the + # plugin was installed + # + # @param [String] name of the plugin gem to search in the source + # @param [Array] version of the gem to install + # @param [String, Array] source(s) to resolve the gem + # + # @return [Hash] map of names to the specs of plugins installed + def install_rubygems(names, version, sources) + source_list = SourceList.new + + Array(sources).each {|remote| source_list.add_global_rubygems_remote(remote) } + + install_all_sources(names, version, source_list) + end + + def install_all_sources(names, version, source_list, source = nil) + deps = names.map {|name| Dependency.new(name, version, { "source" => source }) } + + Bundler.configure_gem_home_and_path(Plugin.root) + + Bundler.settings.temporary(deployment: false, frozen: false) do + definition = Definition.new(nil, deps, source_list, true) + + install_definition(definition) + end + end + + # Installs the plugins and deps from the provided specs and returns map of + # gems to their paths + # + # @param specs to install + # + # @return [Hash] map of names to the specs + def install_from_specs(specs) + paths = {} + + specs.each do |spec| + spec.source.install spec + + paths[spec.name] = spec + end + + paths + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/git.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/git.rb new file mode 100644 index 00000000..deec5e99 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/git.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Git < Bundler::Source::Git + def cache_path + @cache_path ||= begin + git_scope = "#{base_name}-#{uri_hash}" + + Plugin.cache.join("bundler", "git", git_scope) + end + end + + def install_path + @install_path ||= begin + git_scope = "#{base_name}-#{shortref_for_path(revision)}" + + Plugin.root.join("bundler", "gems", git_scope) + end + end + + def root + Plugin.root + end + + def generate_bin(spec, disable_extensions = false) + # Need to find a way without code duplication + # For now, we can ignore this + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/path.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/path.rb new file mode 100644 index 00000000..58a8fa74 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/path.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Path < Bundler::Source::Path + def root + SharedHelpers.in_bundle? ? Bundler.root : Plugin.root + end + + def generate_bin(spec, disable_extensions = false) + # Need to find a way without code duplication + # For now, we can ignore this + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/rubygems.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/rubygems.rb new file mode 100644 index 00000000..cb5db9c3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/installer/rubygems.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Rubygems < Bundler::Source::Rubygems + private + + def rubygems_dir + Plugin.root + end + + def cache_path + Plugin.cache + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/plugin/source_list.rb b/bin/gems/bundler-2.5.9/lib/bundler/plugin/source_list.rb new file mode 100644 index 00000000..746996de --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/plugin/source_list.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + # SourceList object to be used while parsing the Gemfile, setting the + # approptiate options to be used with Source classes for plugin installation + module Plugin + class SourceList < Bundler::SourceList + def add_git_source(options = {}) + add_source_to_list Plugin::Installer::Git.new(options), git_sources + end + + def add_path_source(options = {}) + add_source_to_list Plugin::Installer::Path.new(options), path_sources + end + + def add_rubygems_source(options = {}) + add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources + end + + def all_sources + path_sources + git_sources + rubygems_sources + [metadata_source] + end + + private + + def rubygems_aggregate_class + Plugin::Installer::Rubygems + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/process_lock.rb b/bin/gems/bundler-2.5.9/lib/bundler/process_lock.rb new file mode 100644 index 00000000..0297f80e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/process_lock.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Bundler + class ProcessLock + def self.lock(bundle_path = Bundler.bundle_path) + lock_file_path = File.join(bundle_path, "bundler.lock") + has_lock = false + + File.open(lock_file_path, "w") do |f| + f.flock(File::LOCK_EX) + has_lock = true + yield + f.flock(File::LOCK_UN) + end + rescue Errno::EACCES, Errno::ENOLCK, Errno::ENOTSUP, Errno::EPERM, Errno::EROFS + # In the case the user does not have access to + # create the lock file or is using NFS where + # locks are not available we skip locking. + yield + ensure + FileUtils.rm_f(lock_file_path) if has_lock + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/remote_specification.rb b/bin/gems/bundler-2.5.9/lib/bundler/remote_specification.rb new file mode 100644 index 00000000..9d237f3f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/remote_specification.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +module Bundler + # Represents a lazily loaded gem specification, where the full specification + # is on the source server in rubygems' "quick" index. The proxy object is to + # be seeded with what we're given from the source's abbreviated index - the + # full specification will only be fetched when necessary. + class RemoteSpecification + include MatchRemoteMetadata + include MatchPlatform + include Comparable + + attr_reader :name, :version, :platform + attr_writer :dependencies + attr_accessor :source, :remote + + def initialize(name, version, platform, spec_fetcher) + @name = name + @version = Gem::Version.create version + @original_platform = platform || Gem::Platform::RUBY + @platform = Gem::Platform.new(platform) + @spec_fetcher = spec_fetcher + @dependencies = nil + end + + # Needed before installs, since the arch matters then and quick + # specs don't bother to include the arch in the platform string + def fetch_platform + @platform = _remote_specification.platform + end + + def full_name + @full_name ||= if @platform == Gem::Platform::RUBY + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{@platform}" + end + end + + # Compare this specification against another object. Using sort_obj + # is compatible with Gem::Specification and other Bundler or RubyGems + # objects. Otherwise, use the default Object comparison. + def <=>(other) + if other.respond_to?(:sort_obj) + sort_obj <=> other.sort_obj + else + super + end + end + + # Because Rubyforge cannot be trusted to provide valid specifications + # once the remote gem is downloaded, the backend specification will + # be swapped out. + def __swap__(spec) + raise APIResponseInvalidDependenciesError unless spec.dependencies.all? {|d| d.is_a?(Gem::Dependency) } + + SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) + @_remote_specification = spec + end + + # Create a delegate used for sorting. This strategy is copied from + # RubyGems 2.23 and ensures that Bundler's specifications can be + # compared and sorted with RubyGems' own specifications. + # + # @see #<=> + # @see Gem::Specification#sort_obj + # + # @return [Array] an object you can use to compare and sort this + # specification against other specifications + def sort_obj + [@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] + end + + def to_s + "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>" + end + + def dependencies + @dependencies ||= begin + deps = method_missing(:dependencies) + + # allow us to handle when the specs dependencies are an array of array of string + # in order to delay the crash to `#__swap__` where it results in a friendlier error + # see https://github.com/rubygems/bundler/issues/5797 + deps = deps.map {|d| d.is_a?(Gem::Dependency) ? d : Gem::Dependency.new(*d) } + + deps + end + end + + def runtime_dependencies + dependencies.select(&:runtime?) + end + + def git_version + return unless loaded_from && source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + private + + def to_ary + nil + end + + def _remote_specification + @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) + @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ + " missing from the server!") + end + + def method_missing(method, *args, &blk) + _remote_specification.send(method, *args, &blk) + end + + def respond_to?(method, include_all = false) + super || _remote_specification.respond_to?(method, include_all) + end + public :respond_to? + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver.rb new file mode 100644 index 00000000..1a6711ea --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver.rb @@ -0,0 +1,492 @@ +# frozen_string_literal: true + +module Bundler + # + # This class implements the interface needed by PubGrub for resolution. It is + # equivalent to the `PubGrub::BasicPackageSource` class provided by PubGrub by + # default and used by the most simple PubGrub consumers. + # + class Resolver + require_relative "vendored_pub_grub" + require_relative "resolver/base" + require_relative "resolver/candidate" + require_relative "resolver/incompatibility" + require_relative "resolver/root" + + include GemHelpers + + def initialize(base, gem_version_promoter) + @source_requirements = base.source_requirements + @base = base + @gem_version_promoter = gem_version_promoter + end + + def start + @requirements = @base.requirements + @packages = @base.packages + + root, logger = setup_solver + + Bundler.ui.info "Resolving dependencies...", true + + solve_versions(root: root, logger: logger) + end + + def setup_solver + root = Resolver::Root.new(name_for_explicit_dependency_source) + root_version = Resolver::Candidate.new(0) + + @all_specs = Hash.new do |specs, name| + source = source_for(name) + matches = source.specs.search(name) + + # Don't bother to check for circular deps when no dependency API are + # available, since it's too slow to be usable. That edge case won't work + # but resolution other than that should work fine and reasonably fast. + if source.respond_to?(:dependency_api_available?) && source.dependency_api_available? + matches = filter_invalid_self_dependencies(matches, name) + end + + specs[name] = matches.sort_by {|s| [s.version, s.platform.to_s] } + end + + @all_versions = Hash.new do |candidates, package| + candidates[package] = all_versions_for(package) + end + + @sorted_versions = Hash.new do |candidates, package| + candidates[package] = filtered_versions_for(package).sort + end + + @sorted_versions[root] = [root_version] + + root_dependencies = prepare_dependencies(@requirements, @packages) + + @cached_dependencies = Hash.new do |dependencies, package| + dependencies[package] = Hash.new do |versions, version| + versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages) + end + end + + @cached_dependencies[root] = { root_version => root_dependencies } + + logger = Bundler::UI::Shell.new + logger.level = debug? ? "debug" : "warn" + + [root, logger] + end + + def solve_versions(root:, logger:) + solver = PubGrub::VersionSolver.new(source: self, root: root, logger: logger) + result = solver.solve + result.map {|package, version| version.to_specs(package) }.flatten.uniq + rescue PubGrub::SolveFailure => e + incompatibility = e.incompatibility + + names_to_unlock, names_to_allow_prereleases_for, extended_explanation = find_names_to_relax(incompatibility) + + names_to_relax = names_to_unlock + names_to_allow_prereleases_for + + if names_to_relax.any? + if names_to_unlock.any? + Bundler.ui.debug "Found conflicts with locked dependencies. Will retry with #{names_to_unlock.join(", ")} unlocked...", true + + @base.unlock_names(names_to_unlock) + end + + if names_to_allow_prereleases_for.any? + Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retrying considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true + + @base.include_prereleases(names_to_allow_prereleases_for) + end + + root, logger = setup_solver + + Bundler.ui.debug "Retrying resolution...", true + retry + end + + explanation = e.message + + if extended_explanation + explanation << "\n\n" + explanation << extended_explanation + end + + raise SolveFailure.new(explanation) + end + + def find_names_to_relax(incompatibility) + names_to_unlock = [] + names_to_allow_prereleases_for = [] + extended_explanation = nil + + while incompatibility.conflict? + cause = incompatibility.cause + incompatibility = cause.incompatibility + + incompatibility.terms.each do |term| + package = term.package + name = package.name + + if base_requirements[name] + names_to_unlock << name + elsif package.ignores_prereleases? && @all_specs[name].any? {|s| s.version.prerelease? } + names_to_allow_prereleases_for << name + end + + no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) } + next unless no_versions_incompat + + extended_explanation = no_versions_incompat.extended_explanation + end + end + + [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, extended_explanation] + end + + def parse_dependency(package, dependency) + range = if repository_for(package).is_a?(Source::Gemspec) + PubGrub::VersionRange.any + else + requirement_to_range(dependency) + end + + PubGrub::VersionConstraint.new(package, range: range) + end + + def versions_for(package, range=VersionRange.any) + versions = select_sorted_versions(package, range) + + # Conditional avoids (among other things) calling + # sort_versions_by_preferred with the root package + if versions.size > 1 + sort_versions_by_preferred(package, versions) + else + versions + end + end + + def no_versions_incompatibility_for(package, unsatisfied_term) + cause = PubGrub::Incompatibility::NoVersions.new(unsatisfied_term) + name = package.name + constraint = unsatisfied_term.constraint + constraint_string = constraint.constraint_string + requirements = constraint_string.split(" OR ").map {|req| Gem::Requirement.new(req.split(",")) } + + if name == "bundler" && bundler_pinned_to_current_version? + custom_explanation = "the current Bundler version (#{Bundler::VERSION}) does not satisfy #{constraint}" + extended_explanation = bundler_not_found_message(requirements) + else + specs_matching_other_platforms = filter_matching_specs(@all_specs[name], requirements) + + platforms_explanation = specs_matching_other_platforms.any? ? " for any resolution platforms (#{package.platforms.join(", ")})" : "" + custom_explanation = "#{constraint} could not be found in #{repository_for(package)}#{platforms_explanation}" + + label = "#{name} (#{constraint_string})" + extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any? + end + + Incompatibility.new([unsatisfied_term], cause: cause, custom_explanation: custom_explanation, extended_explanation: extended_explanation) + end + + def debug? + ENV["BUNDLER_DEBUG_RESOLVER"] || + ENV["BUNDLER_DEBUG_RESOLVER_TREE"] || + ENV["DEBUG_RESOLVER"] || + ENV["DEBUG_RESOLVER_TREE"] || + false + end + + def incompatibilities_for(package, version) + package_deps = @cached_dependencies[package] + sorted_versions = @sorted_versions[package] + package_deps[version].map do |dep_package, dep_constraint| + low = high = sorted_versions.index(version) + + # find version low such that all >= low share the same dep + while low > 0 && package_deps[sorted_versions[low - 1]][dep_package] == dep_constraint + low -= 1 + end + low = + if low == 0 + nil + else + sorted_versions[low] + end + + # find version high such that all < high share the same dep + while high < sorted_versions.length && package_deps[sorted_versions[high]][dep_package] == dep_constraint + high += 1 + end + high = + if high == sorted_versions.length + nil + else + sorted_versions[high] + end + + range = PubGrub::VersionRange.new(min: low, max: high, include_min: true) + + self_constraint = PubGrub::VersionConstraint.new(package, range: range) + + dep_term = PubGrub::Term.new(dep_constraint, false) + self_term = PubGrub::Term.new(self_constraint, true) + + custom_explanation = if dep_package.meta? && package.root? + "current #{dep_package} version is #{dep_constraint.constraint_string}" + end + + PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation) + end + end + + def all_versions_for(package) + name = package.name + results = (@base[name] + filter_prereleases(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] } + + if name == "bundler" && !bundler_pinned_to_current_version? + bundler_spec = Gem.loaded_specs["bundler"] + results << bundler_spec if bundler_spec + end + + locked_requirement = base_requirements[name] + results = filter_matching_specs(results, locked_requirement) if locked_requirement + + results.group_by(&:version).reduce([]) do |groups, (version, specs)| + platform_specs = package.platforms.map {|platform| select_best_platform_match(specs, platform) } + + # If package is a top-level dependency, + # candidate is only valid if there are matching versions for all resolution platforms. + # + # If package is not a top-level deependency, + # then it's not necessary that it has matching versions for all platforms, since it may have been introduced only as + # a dependency for a platform specific variant, so it will only need to have a valid version for that platform. + # + if package.top_level? + next groups if platform_specs.any?(&:empty?) + else + next groups if platform_specs.all?(&:empty?) + end + + platform_specs.flatten! + + ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY) + groups << Resolver::Candidate.new(version, specs: ruby_specs) if ruby_specs.any? + + next groups if platform_specs == ruby_specs || package.force_ruby_platform? + + groups << Resolver::Candidate.new(version, specs: platform_specs) + + groups + end + end + + def source_for(name) + @source_requirements[name] || @source_requirements[:default] + end + + def default_bundler_source + @source_requirements[:default_bundler] + end + + def bundler_pinned_to_current_version? + !default_bundler_source.nil? + end + + def name_for_explicit_dependency_source + Bundler.default_gemfile.basename.to_s + rescue StandardError + "Gemfile" + end + + def raise_not_found!(package) + name = package.name + source = source_for(name) + specs = @all_specs[name] + matching_part = name + requirement_label = SharedHelpers.pretty_dependency(package.dependency) + cache_message = begin + " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? + rescue GemfileNotFound + nil + end + specs_matching_requirement = filter_matching_specs(specs, package.dependency.requirement) + + not_found_message = if specs_matching_requirement.any? + specs = specs_matching_requirement + matching_part = requirement_label + platforms = package.platforms + + if platforms.size == 1 + "Could not find gem '#{requirement_label}' with platform '#{platforms.first}'" + else + "Could not find gems matching '#{requirement_label}' valid for all resolution platforms (#{platforms.join(", ")})" + end + else + "Could not find gem '#{requirement_label}'" + end + + message = String.new("#{not_found_message} in #{source}#{cache_message}.\n") + + if specs.any? + message << "\n#{other_specs_matching_message(specs, matching_part)}" + end + + raise GemNotFound, message + end + + private + + def filtered_versions_for(package) + @gem_version_promoter.filter_versions(package, @all_versions[package]) + end + + def raise_all_versions_filtered_out!(package) + level = @gem_version_promoter.level + name = package.name + locked_version = package.locked_version + requirement = package.dependency + + raise GemNotFound, + "#{name} is locked to #{locked_version}, while Gemfile is requesting #{requirement}. " \ + "--strict --#{level} was specified, but there are no #{level} level upgrades from #{locked_version} satisfying #{requirement}, so version solving has failed" + end + + def filter_matching_specs(specs, requirements) + Array(requirements).flat_map do |requirement| + specs.select {| spec| requirement_satisfied_by?(requirement, spec) } + end + end + + def filter_prereleases(specs, package) + return specs unless package.ignores_prereleases? && specs.size > 1 + + specs.reject {|s| s.version.prerelease? } + end + + # Ignore versions that depend on themselves incorrectly + def filter_invalid_self_dependencies(specs, name) + specs.reject do |s| + s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } + end + end + + def requirement_satisfied_by?(requirement, spec) + requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec) + end + + def sort_versions_by_preferred(package, versions) + @gem_version_promoter.sort_versions(package, versions) + end + + def repository_for(package) + source_for(package.name) + end + + def base_requirements + @base.base_requirements + end + + def prepare_dependencies(requirements, packages) + to_dependency_hash(requirements, packages).map do |dep_package, dep_constraint| + name = dep_package.name + + next [dep_package, dep_constraint] if name == "bundler" + + dep_range = dep_constraint.range + versions = select_sorted_versions(dep_package, dep_range) + if versions.empty? && dep_package.ignores_prereleases? + @all_versions.delete(dep_package) + @sorted_versions.delete(dep_package) + dep_package.consider_prereleases! + versions = select_sorted_versions(dep_package, dep_range) + end + + if versions.empty? && select_all_versions(dep_package, dep_range).any? + raise_all_versions_filtered_out!(dep_package) + end + + next [dep_package, dep_constraint] unless versions.empty? + + next unless dep_package.current_platform? + + raise_not_found!(dep_package) + end.compact.to_h + end + + def select_sorted_versions(package, range) + range.select_versions(@sorted_versions[package]) + end + + def select_all_versions(package, range) + range.select_versions(@all_versions[package]) + end + + def other_specs_matching_message(specs, requirement) + message = String.new("The source contains the following gems matching '#{requirement}':\n") + message << specs.map {|s| " * #{s.full_name}" }.join("\n") + message + end + + def requirement_to_range(requirement) + ranges = requirement.requirements.map do |(op, version)| + ver = Resolver::Candidate.new(version).generic! + platform_ver = Resolver::Candidate.new(version).platform_specific! + + case op + when "~>" + name = "~> #{ver}" + bump = Resolver::Candidate.new(version.bump.to_s + ".A") + PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true) + when ">" + PubGrub::VersionRange.new(min: platform_ver) + when ">=" + PubGrub::VersionRange.new(min: ver, include_min: true) + when "<" + PubGrub::VersionRange.new(max: ver) + when "<=" + PubGrub::VersionRange.new(max: platform_ver, include_max: true) + when "=" + PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true) + when "!=" + PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert + else + raise "bad version specifier: #{op}" + end + end + + ranges.inject(&:intersect) + end + + def to_dependency_hash(dependencies, packages) + dependencies.inject({}) do |deps, dep| + package = packages[dep.name] + + current_req = deps[package] + new_req = parse_dependency(package, dep.requirement) + + deps[package] = if current_req + current_req.intersect(new_req) + else + new_req + end + + deps + end + end + + def bundler_not_found_message(conflict_dependencies) + candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies) + + if candidate_specs.any? + target_version = candidate_specs.last.version + new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") + "Your bundle requires a different version of Bundler than the one you're running.\n" \ + "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n" + else + "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/base.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/base.rb new file mode 100644 index 00000000..ad19eeb3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/base.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require_relative "package" + +module Bundler + class Resolver + class Base + attr_reader :packages, :requirements, :source_requirements + + def initialize(source_requirements, dependencies, base, platforms, options) + @source_requirements = source_requirements + + @base = base + + @packages = Hash.new do |hash, name| + hash[name] = Package.new(name, platforms, **options) + end + + @requirements = dependencies.map do |dep| + dep_platforms = dep.gem_platforms(platforms) + + # Dependencies scoped to external platforms are ignored + next if dep_platforms.empty? + + name = dep.name + + @packages[name] = Package.new(name, dep_platforms, **options.merge(dependency: dep)) + + dep + end.compact + end + + def [](name) + @base[name] + end + + def delete(specs) + @base.delete(specs) + end + + def get_package(name) + @packages[name] + end + + def base_requirements + @base_requirements ||= build_base_requirements + end + + def unlock_names(names) + indirect_pins = indirect_pins(names) + + if indirect_pins.any? + loosen_names(indirect_pins) + else + pins = pins(names) + + if pins.any? + loosen_names(pins) + else + unrestrict_names(names) + end + end + end + + def include_prereleases(names) + names.each do |name| + get_package(name).consider_prereleases! + end + end + + private + + def indirect_pins(names) + names.select {|name| @base_requirements[name].exact? && @requirements.none? {|dep| dep.name == name } } + end + + def pins(names) + names.select {|name| @base_requirements[name].exact? } + end + + def loosen_names(names) + names.each do |name| + version = @base_requirements[name].requirements.first[1] + + @base_requirements[name] = Gem::Requirement.new(">= #{version}") + + @base.delete_by_name(name) + end + end + + def unrestrict_names(names) + names.each do |name| + @base_requirements.delete(name) + end + end + + def build_base_requirements + base_requirements = {} + @base.each do |ls| + req = Gem::Requirement.new(ls.version) + base_requirements[ls.name] = req + end + base_requirements + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/candidate.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/candidate.rb new file mode 100644 index 00000000..9e8b9133 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/candidate.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require_relative "spec_group" + +module Bundler + class Resolver + # + # This class is a PubGrub compatible "Version" class that takes Bundler + # resolution complexities into account. + # + # Each Resolver::Candidate has a underlying `Gem::Version` plus a set of + # platforms. For example, 1.1.0-x86_64-linux is a different resolution candidate + # from 1.1.0 (generic). This is because different platform variants of the + # same gem version can bring different dependencies, so they need to be + # considered separately. + # + # Some candidates may also keep some information explicitly about the + # package they refer to. These candidates are referred to as "canonical" and + # are used when materializing resolution results back into RubyGems + # specifications that can be installed, written to lock files, and so on. + # + class Candidate + include Comparable + + attr_reader :version + + def initialize(version, specs: []) + @spec_group = Resolver::SpecGroup.new(specs) + @version = Gem::Version.new(version) + @ruby_only = specs.map(&:platform).uniq == [Gem::Platform::RUBY] + end + + def dependencies + @spec_group.dependencies + end + + def to_specs(package) + return [] if package.meta? + + @spec_group.to_specs(package.force_ruby_platform?) + end + + def generic! + @ruby_only = true + + self + end + + def platform_specific! + @ruby_only = false + + self + end + + def prerelease? + @version.prerelease? + end + + def segments + @version.segments + end + + def sort_obj + [@version, @ruby_only ? -1 : 1] + end + + def <=>(other) + return unless other.is_a?(self.class) + + sort_obj <=> other.sort_obj + end + + def ==(other) + return unless other.is_a?(self.class) + + sort_obj == other.sort_obj + end + + def eql?(other) + return unless other.is_a?(self.class) + + sort_obj.eql?(other.sort_obj) + end + + def hash + sort_obj.hash + end + + def to_s + @version.to_s + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/incompatibility.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/incompatibility.rb new file mode 100644 index 00000000..4ac1b2e1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/incompatibility.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class Incompatibility < PubGrub::Incompatibility + attr_reader :extended_explanation + + def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil) + @extended_explanation = extended_explanation + + super(terms, cause: cause, custom_explanation: custom_explanation) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/package.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/package.rb new file mode 100644 index 00000000..04613286 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/package.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + # + # Represents a gem being resolved, in a format PubGrub likes. + # + # The class holds the following information: + # + # * Platforms this gem will be resolved on. + # * The locked version of this gem resolution should favor (if any). + # * Whether the gem should be unlocked to its latest version. + # * The dependency explicit set in the Gemfile for this gem (if any). + # + class Package + attr_reader :name, :platforms, :dependency, :locked_version + + def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, dependency: nil) + @name = name + @platforms = platforms + @locked_version = locked_specs[name].first&.version + @unlock = unlock + @dependency = dependency || Dependency.new(name, @locked_version) + @top_level = !dependency.nil? + @prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore + end + + def to_s + @name.delete("\0") + end + + def root? + false + end + + def top_level? + @top_level + end + + def meta? + @name.end_with?("\0") + end + + def ==(other) + self.class == other.class && @name == other.name + end + + def hash + @name.hash + end + + def unlock? + @unlock.empty? || @unlock.include?(name) + end + + def ignores_prereleases? + @prerelease == :ignore + end + + def prerelease_specified? + @prerelease == :consider_first + end + + def consider_prereleases! + @prerelease = :consider_last + end + + def force_ruby_platform? + @dependency.force_ruby_platform + end + + def current_platform? + @dependency.current_platform? + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/root.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/root.rb new file mode 100644 index 00000000..e5eb634f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/root.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "package" + +module Bundler + class Resolver + # + # Represents the Gemfile from the resolver's perspective. It's the root + # package and Gemfile entries depend on it. + # + class Root < Package + def initialize(name) + @name = name + end + + def meta? + true + end + + def root? + true + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/resolver/spec_group.rb b/bin/gems/bundler-2.5.9/lib/bundler/resolver/spec_group.rb new file mode 100644 index 00000000..5cee444e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/resolver/spec_group.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class SpecGroup + def initialize(specs) + @specs = specs + end + + def empty? + @specs.empty? + end + + def name + @name ||= exemplary_spec.name + end + + def version + @version ||= exemplary_spec.version + end + + def source + @source ||= exemplary_spec.source + end + + def to_specs(force_ruby_platform) + @specs.map do |s| + lazy_spec = LazySpecification.from_spec(s) + lazy_spec.force_ruby_platform = force_ruby_platform + lazy_spec + end + end + + def to_s + sorted_spec_names.join(", ") + end + + def dependencies + @dependencies ||= @specs.map do |spec| + __dependencies(spec) + metadata_dependencies(spec) + end.flatten.uniq + end + + protected + + def sorted_spec_names + @sorted_spec_names ||= @specs.map(&:full_name).sort + end + + private + + def exemplary_spec + @specs.first + end + + def __dependencies(spec) + dependencies = [] + spec.dependencies.each do |dep| + next if dep.type == :development + dependencies << Dependency.new(dep.name, dep.requirement) + end + dependencies + end + + def metadata_dependencies(spec) + [ + metadata_dependency("Ruby", spec.required_ruby_version), + metadata_dependency("RubyGems", spec.required_rubygems_version), + ].compact + end + + def metadata_dependency(name, requirement) + return if requirement.nil? || requirement.none? + + Dependency.new("#{name}\0", requirement) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/retry.rb b/bin/gems/bundler-2.5.9/lib/bundler/retry.rb new file mode 100644 index 00000000..b95c42c3 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/retry.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Bundler + # General purpose class for retrying code that may fail + class Retry + attr_accessor :name, :total_runs, :current_run + + class << self + def default_attempts + default_retries + 1 + end + alias_method :attempts, :default_attempts + + def default_retries + Bundler.settings[:retry] + end + end + + def initialize(name, exceptions = nil, retries = self.class.default_retries) + @name = name + @retries = retries + @exceptions = Array(exceptions) || [] + @total_runs = @retries + 1 # will run once, then upto attempts.times + end + + def attempt(&block) + @current_run = 0 + @failed = false + @error = nil + run(&block) while keep_trying? + @result + end + alias_method :attempts, :attempt + + private + + def run(&block) + @failed = false + @current_run += 1 + @result = block.call + rescue StandardError => e + fail_attempt(e) + end + + def fail_attempt(e) + @failed = true + if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } + Bundler.ui.info "" unless Bundler.ui.debug? + raise e + end + return true unless name + Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this + Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? + end + + def keep_trying? + return true if current_run.zero? + return false if last_attempt? + true if @failed + end + + def last_attempt? + current_run >= total_runs + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ruby_dsl.rb b/bin/gems/bundler-2.5.9/lib/bundler/ruby_dsl.rb new file mode 100644 index 00000000..fb4b79c4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ruby_dsl.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Bundler + module RubyDsl + def ruby(*ruby_version) + options = ruby_version.pop if ruby_version.last.is_a?(Hash) + ruby_version.flatten! + + if options + patchlevel = options[:patchlevel] + engine = options[:engine] + engine_version = options[:engine_version] + + raise GemfileError, "Please define :engine_version" if engine && engine_version.nil? + raise GemfileError, "Please define :engine" if engine_version && engine.nil? + + if options[:file] + raise GemfileError, "Do not pass version argument when using :file option" unless ruby_version.empty? + ruby_version << normalize_ruby_file(options[:file]) + end + + if engine == "ruby" && engine_version && ruby_version != Array(engine_version) + raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" + end + end + + @ruby_version = RubyVersion.new(ruby_version, patchlevel, engine, engine_version) + end + + # Support the various file formats found in .ruby-version files. + # + # 3.2.2 + # ruby-3.2.2 + # + # Also supports .tool-versions files for asdf. Lines not starting with "ruby" are ignored. + # + # ruby 2.5.1 # comment is ignored + # ruby 2.5.1# close comment and extra spaces doesn't confuse + # + # Intentionally does not support `3.2.1@gemset` since rvm recommends using .ruby-gemset instead + # + # Loads the file relative to the dirname of the Gemfile itself. + def normalize_ruby_file(filename) + file_content = Bundler.read_file(gemfile.dirname.join(filename)) + # match "ruby-3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment + if /^ruby(-|\s+)([^\s#]+)/.match(file_content) + $2 + else + file_content.strip + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ruby_version.rb b/bin/gems/bundler-2.5.9/lib/bundler/ruby_version.rb new file mode 100644 index 00000000..7e9e072b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ruby_version.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +module Bundler + class RubyVersion + attr_reader :versions, + :patchlevel, + :engine, + :engine_versions, + :gem_version, + :engine_gem_version + + def initialize(versions, patchlevel, engine, engine_version) + # The parameters to this method must satisfy the + # following constraints, which are verified in + # the DSL: + # + # * If an engine is specified, an engine version + # must also be specified + # * If an engine version is specified, an engine + # must also be specified + # * If the engine is "ruby", the engine version + # must not be specified, or the engine version + # specified must match the version. + + @versions = Array(versions).map do |v| + op, v = Gem::Requirement.parse(normalize_version(v)) + op == "=" ? v.to_s : "#{op} #{v}" + end + + @gem_version = Gem::Requirement.create(@versions.first).requirements.first.last + @input_engine = engine&.to_s + @engine = engine&.to_s || "ruby" + @engine_versions = (engine_version && Array(engine_version)) || @versions + @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last + @patchlevel = patchlevel || (@gem_version.prerelease? ? "-1" : nil) + end + + def to_s(versions = self.versions) + output = String.new("ruby #{versions_string(versions)}") + output << "p#{patchlevel}" if patchlevel && patchlevel != "-1" + output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" + + output + end + + # @private + PATTERN = / + ruby\s + (\d+\.\d+\.\d+(?:\.\S+)?) # ruby version + (?:p(-?\d+))? # optional patchlevel + (?:\s\((\S+)\s(.+)\))? # optional engine info + /xo + + # Returns a RubyVersion from the given string. + # @param [String] the version string to match. + # @return [RubyVersion,Nil] The version if the string is a valid RubyVersion + # description, and nil otherwise. + def self.from_string(string) + new($1, $2, $3, $4) if string =~ PATTERN + end + + def single_version_string + to_s(gem_version) + end + + def ==(other) + versions == other.versions && + engine == other.engine && + engine_versions == other.engine_versions && + patchlevel == other.patchlevel + end + + def host + @host ||= [ + RbConfig::CONFIG["host_cpu"], + RbConfig::CONFIG["host_vendor"], + RbConfig::CONFIG["host_os"], + ].join("-") + end + + # Returns a tuple of these things: + # [diff, this, other] + # The priority of attributes are + # 1. engine + # 2. ruby_version + # 3. engine_version + def diff(other) + raise ArgumentError, "Can only diff with a RubyVersion, not a #{other.class}" unless other.is_a?(RubyVersion) + if engine != other.engine && @input_engine + [:engine, engine, other.engine] + elsif versions.empty? || !matches?(versions, other.gem_version) + [:version, versions_string(versions), versions_string(other.versions)] + elsif @input_engine && !matches?(engine_versions, other.engine_gem_version) + [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)] + elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) + [:patchlevel, patchlevel, other.patchlevel] + end + end + + def versions_string(versions) + Array(versions).join(", ") + end + + def self.system + ruby_engine = RUBY_ENGINE.dup + ruby_version = Gem.ruby_version.to_s + ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup + patchlevel = RUBY_PATCHLEVEL.to_s + + @system ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) + end + + private + + # Ruby's official preview version format uses a `-`: Example: 3.3.0-preview2 + # However, RubyGems recognizes preview version format with a `.`: Example: 3.3.0.preview2 + # Returns version string after replacing `-` with `.` + def normalize_version(version) + version.tr("-", ".") + end + + def matches?(requirements, version) + # Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head + return requirements == version if requirements.to_s == "-1" || version.to_s == "-1" + + Array(requirements).all? do |requirement| + Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.create(version)) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/rubygems_ext.rb b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_ext.rb new file mode 100644 index 00000000..e0582beb --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_ext.rb @@ -0,0 +1,328 @@ +# frozen_string_literal: true + +require "pathname" + +require "rubygems" unless defined?(Gem) + +require "rubygems/specification" + +# We can't let `Gem::Source` be autoloaded in the `Gem::Specification#source` +# redefinition below, so we need to load it upfront. The reason is that if +# Bundler monkeypatches are loaded before RubyGems activates an executable (for +# example, through `ruby -rbundler -S irb`), gem activation might end up calling +# the redefined `Gem::Specification#source` and triggering the `Gem::Source` +# autoload. That would result in requiring "rubygems/source" inside another +# require, which would trigger a monitor error and cause the `autoload` to +# eventually fail. A better solution is probably to completely avoid autoloading +# `Gem::Source` from the redefined `Gem::Specification#source`. +require "rubygems/source" + +require_relative "match_metadata" +require_relative "force_platform" +require_relative "match_platform" + +# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler +# versions and ignore patchlevels +# (https://github.com/rubygems/rubygems/pull/5472, +# https://github.com/rubygems/rubygems/pull/5486). May be removed once RubyGems +# 3.3.12 support is dropped. +unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1 + Gem.instance_variable_set(:@ruby_version, Gem::Version.new(RUBY_VERSION)) +end + +module Gem + class Specification + include ::Bundler::MatchMetadata + include ::Bundler::MatchPlatform + + attr_accessor :remote, :location, :relative_loaded_from + + remove_method :source + attr_writer :source + def source + (defined?(@source) && @source) || Gem::Source::Installed.new + end + + alias_method :rg_full_gem_path, :full_gem_path + alias_method :rg_loaded_from, :loaded_from + + def full_gem_path + if source.respond_to?(:root) + Pathname.new(loaded_from).dirname.expand_path(source.root).to_s + else + rg_full_gem_path + end + end + + def loaded_from + if relative_loaded_from + source.path.join(relative_loaded_from).to_s + else + rg_loaded_from + end + end + + def load_paths + full_require_paths + end + + alias_method :rg_extension_dir, :extension_dir + def extension_dir + # following instance variable is already used in original method + # and that is the reason to prefix it with bundler_ and add rubocop exception + @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) # rubocop:disable Naming/MemoizedInstanceVariableName + unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") + File.expand_path(File.join(extensions_dir, unique_extension_dir)) + else + rg_extension_dir + end + end + + remove_method :gem_dir + def gem_dir + full_gem_path + end + + unless const_defined?(:LATEST_RUBY_WITHOUT_PATCH_VERSIONS) + LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1") + + alias_method :rg_required_ruby_version=, :required_ruby_version= + def required_ruby_version=(req) + self.rg_required_ruby_version = req + + @required_ruby_version.requirements.map! do |op, v| + if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4 + [op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))] + else + [op, v] + end + end + end + end + + def groups + @groups ||= [] + end + + def git_version + return unless loaded_from && source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + def to_gemfile(path = nil) + gemfile = String.new("source 'https://rubygems.org'\n") + gemfile << dependencies_to_gemfile(nondevelopment_dependencies) + unless development_dependencies.empty? + gemfile << "\n" + gemfile << dependencies_to_gemfile(development_dependencies, :development) + end + gemfile + end + + def nondevelopment_dependencies + dependencies - development_dependencies + end + + def deleted_gem? + !default_gem? && !File.directory?(full_gem_path) + end + + private + + def dependencies_to_gemfile(dependencies, group = nil) + gemfile = String.new + if dependencies.any? + gemfile << "group :#{group} do\n" if group + dependencies.each do |dependency| + gemfile << " " if group + gemfile << %(gem "#{dependency.name}") + req = dependency.requirements_list.first + gemfile << %(, "#{req}") if req + gemfile << "\n" + end + gemfile << "end\n" if group + end + gemfile + end + end + + class Dependency + include ::Bundler::ForcePlatform + + attr_accessor :source, :groups + + alias_method :eql?, :== + + def force_ruby_platform + return @force_ruby_platform if defined?(@force_ruby_platform) && !@force_ruby_platform.nil? + + @force_ruby_platform = default_force_ruby_platform + end + + def encode_with(coder) + to_yaml_properties.each do |ivar| + coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) + end + end + + def to_yaml_properties + instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } + end + + def to_lock + out = String.new(" #{name}") + unless requirement.none? + reqs = requirement.requirements.map {|o, v| "#{o} #{v}" }.sort.reverse + out << " (#{reqs.join(", ")})" + end + out + end + end + + # Requirements using lambda operator differentiate trailing zeros since rubygems 3.2.6 + if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash + class Requirement + module CorrectHashForLambdaOperator + def hash + if requirements.any? {|r| r.first == "~>" } + requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash + else + super + end + end + end + + prepend CorrectHashForLambdaOperator + end + end + + require "rubygems/platform" + + class Platform + JAVA = Gem::Platform.new("java") + MSWIN = Gem::Platform.new("mswin32") + MSWIN64 = Gem::Platform.new("mswin64") + MINGW = Gem::Platform.new("x86-mingw32") + X64_MINGW = [Gem::Platform.new("x64-mingw32"), + Gem::Platform.new("x64-mingw-ucrt")].freeze + WINDOWS = [MSWIN, MSWIN64, MINGW, X64_MINGW].flatten.freeze + X64_LINUX = Gem::Platform.new("x86_64-linux") + X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl") + + if X64_LINUX === X64_LINUX_MUSL + remove_method :=== + + def ===(other) + return nil unless Gem::Platform === other + + # universal-mingw32 matches x64-mingw-ucrt + return true if (@cpu == "universal" || other.cpu == "universal") && + @os.start_with?("mingw") && other.os.start_with?("mingw") + + # cpu + ([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu || + (@cpu == "arm" && other.cpu.start_with?("arm"))) && + + # os + @os == other.os && + + # version + ( + (@os != "linux" && (@version.nil? || other.version.nil?)) || + (@os == "linux" && (normalized_linux_version_ext == other.normalized_linux_version_ext || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) || + @version == other.version + ) + end + + # This is a copy of RubyGems 3.3.23 or higher `normalized_linux_method`. + # Once only 3.3.23 is supported, we can use the method in RubyGems. + def normalized_linux_version_ext + return nil unless @version + + without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "") + return nil if without_gnu_nor_abi_modifiers.empty? + + without_gnu_nor_abi_modifiers + end + end + + if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY) + REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 libv8-node sorbet-static].freeze + end + end + + Platform.singleton_class.module_eval do + unless Platform.singleton_methods.include?(:match_spec?) + def match_spec?(spec) + match_gem?(spec.platform, spec.name) + end + + def match_gem?(platform, gem_name) + match_platforms?(platform, Gem.platforms) + end + end + + match_platforms_defined = Gem::Platform.respond_to?(:match_platforms?, true) + + if !match_platforms_defined || Gem::Platform.send(:match_platforms?, Gem::Platform::X64_LINUX_MUSL, [Gem::Platform::X64_LINUX]) + + private + + remove_method :match_platforms? if match_platforms_defined + + def match_platforms?(platform, platforms) + platforms.any? do |local_platform| + platform.nil? || + local_platform == platform || + (local_platform != Gem::Platform::RUBY && platform =~ local_platform) + end + end + end + end + + # On universal Rubies, resolve the "universal" arch to the real CPU arch, without changing the extension directory. + class BasicSpecification + if /^universal\.(?.*?)-/ =~ (CROSS_COMPILING || RUBY_PLATFORM) + local_platform = Platform.local + if local_platform.cpu == "universal" + ORIGINAL_LOCAL_PLATFORM = local_platform.to_s.freeze + + local_platform.cpu = if arch == "arm64e" # arm64e is only permitted for Apple system binaries + "arm64" + else + arch + end + + def extensions_dir + @extensions_dir ||= + Gem.default_ext_dir_for(base_dir) || File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM, Gem.extension_api_version) + end + end + end + end + + require "rubygems/name_tuple" + + class NameTuple + # Versions of RubyGems before about 3.5.0 don't to_s the platform. + unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String) + alias_method :initialize_with_platform, :initialize + + def initialize(name, version, platform=Gem::Platform::RUBY) + if Gem::Platform === platform + initialize_with_platform(name, version, platform.to_s) + else + initialize_with_platform(name, version, platform) + end + end + end + + def lock_name + if platform == Gem::Platform::RUBY + "#{name} (#{version})" + else + "#{name} (#{version}-#{platform})" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/rubygems_gem_installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_gem_installer.rb new file mode 100644 index 00000000..d563868c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_gem_installer.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require "rubygems/installer" + +module Bundler + class RubyGemsGemInstaller < Gem::Installer + def check_executable_overwrite(filename) + # Bundler needs to install gems regardless of binstub overwriting + end + + def install + pre_install_checks + + run_pre_install_hooks + + spec.loaded_from = spec_file + + # Completely remove any previous gem files + strict_rm_rf gem_dir + strict_rm_rf spec.extension_dir + + SharedHelpers.filesystem_access(gem_dir, :create) do + FileUtils.mkdir_p gem_dir, mode: 0o755 + end + + extract_files + + build_extensions if spec.extensions.any? + write_build_info_file + run_post_build_hooks + + generate_bin + generate_plugins + + write_spec + + SharedHelpers.filesystem_access("#{gem_home}/cache", :write) do + write_cache_file + end + + say spec.post_install_message unless spec.post_install_message.nil? + + run_post_install_hooks + + spec + end + + def pre_install_checks + super + rescue Gem::FilePermissionError + # Ignore permission checks in RubyGems. Instead, go on, and try to write + # for real. We properly handle permission errors when they happen. + nil + end + + def generate_plugins + return unless Gem::Installer.instance_methods(false).include?(:generate_plugins) + + latest = Gem::Specification.stubs_for(spec.name).first + return if latest && latest.version > spec.version + + ensure_writable_dir @plugins_dir + + if spec.plugins.empty? + remove_plugins_for(spec, @plugins_dir) + else + regenerate_plugins_for(spec, @plugins_dir) + end + end + + def build_extensions + extension_cache_path = options[:bundler_extension_cache_path] + extension_dir = spec.extension_dir + unless extension_cache_path && extension_dir + prepare_extension_build(extension_dir) + return super + end + + build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) + if build_complete && !options[:force] + SharedHelpers.filesystem_access(File.dirname(extension_dir)) do |p| + FileUtils.mkpath p + end + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_cache_path, extension_dir + end + else + prepare_extension_build(extension_dir) + super + SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_dir, extension_cache_path + end + end + end + + def spec + if Bundler.rubygems.provides?("< 3.3.12") # RubyGems implementation rescues and re-raises errors before 3.3.12 and we don't want that + @package.spec + else + super + end + end + + def gem_checksum + Checksum.from_gem_package(@package) + end + + private + + def prepare_extension_build(extension_dir) + SharedHelpers.filesystem_access(extension_dir, :create) do + FileUtils.mkdir_p extension_dir + end + require "shellwords" unless Bundler.rubygems.provides?(">= 3.2.25") + end + + def strict_rm_rf(dir) + return unless File.exist?(dir) + + parent = File.dirname(dir) + parent_st = File.stat(parent) + + if parent_st.world_writable? && !parent_st.sticky? + raise InsecureInstallPathError.new(parent) + end + + begin + FileUtils.remove_entry_secure(dir) + rescue StandardError => e + raise unless File.exist?(dir) + + raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`") + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/rubygems_integration.rb b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_integration.rb new file mode 100644 index 00000000..da555681 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/rubygems_integration.rb @@ -0,0 +1,493 @@ +# frozen_string_literal: true + +require "rubygems" unless defined?(Gem) + +module Bundler + class RubygemsIntegration + require "monitor" + + EXT_LOCK = Monitor.new + + def initialize + @replaced_methods = {} + end + + def version + @version ||= Gem.rubygems_version + end + + def provides?(req_str) + Gem::Requirement.new(req_str).satisfied_by?(version) + end + + def supports_bundler_trampolining? + provides?(">= 3.3.0.a") + end + + def build_args + require "rubygems/command" + Gem::Command.build_args + end + + def build_args=(args) + require "rubygems/command" + Gem::Command.build_args = args + end + + def loaded_specs(name) + Gem.loaded_specs[name] + end + + def mark_loaded(spec) + if spec.respond_to?(:activated=) + current = Gem.loaded_specs[spec.name] + current.activated = false if current + spec.activated = true + end + Gem.loaded_specs[spec.name] = spec + end + + def validate(spec) + Bundler.ui.silence { spec.validate(false) } + rescue Gem::InvalidSpecificationException => e + error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \ + "The validation error was '#{e.message}'\n" + raise Gem::InvalidSpecificationException.new(error_message) + rescue Errno::ENOENT + nil + end + + def set_installed_by_version(spec, installed_by_version = Gem::VERSION) + return unless spec.respond_to?(:installed_by_version=) + spec.installed_by_version = Gem::Version.create(installed_by_version) + end + + def spec_missing_extensions?(spec, default = true) + return spec.missing_extensions? if spec.respond_to?(:missing_extensions?) + + return false if spec.default_gem? + return false if spec.extensions.empty? + + default + end + + def spec_matches_for_glob(spec, glob) + return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob) + + spec.load_paths.flat_map do |lp| + Dir["#{lp}/#{glob}#{suffix_pattern}"] + end + end + + def stub_set_spec(stub, spec) + stub.instance_variable_set(:@spec, spec) + end + + def path(obj) + obj.to_s + end + + def ruby_engine + Gem.ruby_engine + end + + def read_binary(path) + Gem.read_binary(path) + end + + def inflate(obj) + Gem::Util.inflate(obj) + end + + def gem_dir + Gem.dir + end + + def gem_bindir + Gem.bindir + end + + def user_home + Gem.user_home + end + + def gem_path + Gem.path + end + + def reset + Gem::Specification.reset + end + + def post_reset_hooks + Gem.post_reset_hooks + end + + def suffix_pattern + Gem.suffix_pattern + end + + def gem_cache + gem_path.map {|p| File.expand_path("cache", p) } + end + + def spec_cache_dirs + @spec_cache_dirs ||= begin + dirs = gem_path.map {|dir| File.join(dir, "specifications") } + dirs << Gem.spec_cache_dir + dirs.uniq.select {|dir| File.directory? dir } + end + end + + def marshal_spec_dir + Gem::MARSHAL_SPEC_DIR + end + + def clear_paths + Gem.clear_paths + end + + def bin_path(gem, bin, ver) + Gem.bin_path(gem, bin, ver) + end + + def loaded_gem_paths + loaded_gem_paths = Gem.loaded_specs.map {|_, s| s.full_require_paths } + loaded_gem_paths.flatten + end + + def ui=(obj) + Gem::DefaultUserInteraction.ui = obj + end + + def ext_lock + EXT_LOCK + end + + def spec_from_gem(path) + require "rubygems/package" + Gem::Package.new(path).spec + end + + def build_gem(gem_dir, spec) + build(spec) + end + + def security_policy_keys + %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" } + end + + def security_policies + @security_policies ||= begin + require "rubygems/security" + Gem::Security::Policies + rescue LoadError, NameError + {} + end + end + + def reverse_rubygems_kernel_mixin + # Disable rubygems' gem activation system + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + [::Kernel.singleton_class, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + redefine_method(k, :require, k.instance_method(:gem_original_require)) + end + end + end + end + + def replace_gem(specs, specs_by_name) + executables = nil + + [::Kernel.singleton_class, ::Kernel].each do |kernel_class| + redefine_method(kernel_class, :gem) do |dep, *reqs| + if executables&.include?(File.basename(caller.first.split(":").first)) + break + end + + reqs.pop if reqs.last.is_a?(Hash) + + unless dep.respond_to?(:name) && dep.respond_to?(:requirement) + dep = Gem::Dependency.new(dep, reqs) + end + + if spec = specs_by_name[dep.name] + return true if dep.matches_spec?(spec) + end + + message = if spec.nil? + target_file = begin + Bundler.default_gemfile.basename + rescue GemfileNotFound + "inline Gemfile" + end + "#{dep.name} is not part of the bundle." \ + " Add it to your #{target_file}." + else + "can't activate #{dep}, already activated #{spec.full_name}. " \ + "Make sure all dependencies are added to Gemfile." + end + + e = Gem::LoadError.new(message) + e.name = dep.name + e.requirement = dep.requirement + raise e + end + + # backwards compatibility shim, see https://github.com/rubygems/bundler/issues/5102 + kernel_class.send(:public, :gem) if Bundler.feature_flag.setup_makes_kernel_gem_public? + end + end + + # Used to make bin stubs that are not created by bundler work + # under bundler. The new Gem.bin_path only considers gems in + # +specs+ + def replace_bin_path(specs_by_name) + gem_class = (class << Gem; self; end) + + redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args| + exec_name = args.first + raise ArgumentError, "you must supply exec_name" unless exec_name + + spec_with_name = specs_by_name[gem_name] + matching_specs_by_exec_name = specs_by_name.values.select {|s| s.executables.include?(exec_name) } + spec = matching_specs_by_exec_name.delete(spec_with_name) + + unless spec || !matching_specs_by_exec_name.empty? + message = "can't find executable #{exec_name} for gem #{gem_name}" + if spec_with_name.nil? + message += ". #{gem_name} is not currently included in the bundle, " \ + "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?" + end + raise Gem::Exception, message + end + + unless spec + spec = matching_specs_by_exec_name.shift + warn \ + "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \ + "You should run `bundle binstub #{gem_name}` " \ + "to work around a system/bundle conflict." + end + + unless matching_specs_by_exec_name.empty? + conflicting_names = matching_specs_by_exec_name.map(&:name).join(", ") + warn \ + "The `#{exec_name}` executable in the `#{spec.name}` gem is being loaded, but it's also present in other gems (#{conflicting_names}).\n" \ + "If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub `).\n" \ + "If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names." + end + + spec + end + + redefine_method(gem_class, :activate_bin_path) do |name, *args| + exec_name = args.first + return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" + + # Copy of Rubygems activate_bin_path impl + requirement = args.last + spec = find_spec_for_exe name, exec_name, [requirement] + + gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) + gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) + File.exist?(gem_bin) ? gem_bin : gem_from_path_bin + end + + redefine_method(gem_class, :bin_path) do |name, *args| + exec_name = args.first + return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle" + + spec = find_spec_for_exe(name, *args) + exec_name ||= spec.default_executable + + gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name) + gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name) + File.exist?(gem_bin) ? gem_bin : gem_from_path_bin + end + end + + # Replace or hook into RubyGems to provide a bundlerized view + # of the world. + def replace_entrypoints(specs) + specs_by_name = add_default_gems_to(specs) + + reverse_rubygems_kernel_mixin + begin + # bundled_gems only provide with Ruby 3.3 or later + require "bundled_gems" + rescue LoadError + else + Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require) + end + replace_gem(specs, specs_by_name) + stub_rubygems(specs) + replace_bin_path(specs_by_name) + + Gem.clear_paths + end + + # Add default gems not already present in specs, and return them as a hash. + def add_default_gems_to(specs) + specs_by_name = specs.reduce({}) do |h, s| + h[s.name] = s + h + end + + Bundler.rubygems.default_stubs.each do |stub| + default_spec = stub.to_spec + default_spec_name = default_spec.name + next if specs_by_name.key?(default_spec_name) + + specs << default_spec + specs_by_name[default_spec_name] = default_spec + end + + specs_by_name + end + + def undo_replacements + @replaced_methods.each do |(sym, klass), method| + redefine_method(klass, sym, method) + end + if Binding.public_method_defined?(:source_location) + post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ } + else + post_reset_hooks.reject! {|proc| proc.binding.eval("__FILE__") == __FILE__ } + end + @replaced_methods.clear + end + + def redefine_method(klass, method, unbound_method = nil, &block) + visibility = method_visibility(klass, method) + begin + if (instance_method = klass.instance_method(method)) && method != :initialize + # doing this to ensure we also get private methods + klass.send(:remove_method, method) + end + rescue NameError + # method isn't defined + nil + end + @replaced_methods[[method, klass]] = instance_method + if unbound_method + klass.send(:define_method, method, unbound_method) + klass.send(visibility, method) + elsif block + klass.send(:define_method, method, &block) + klass.send(visibility, method) + end + end + + def method_visibility(klass, method) + if klass.private_method_defined?(method) + :private + elsif klass.protected_method_defined?(method) + :protected + else + :public + end + end + + def stub_rubygems(specs) + Gem::Specification.all = specs + + Gem.post_reset do + Gem::Specification.all = specs + end + + redefine_method((class << Gem; self; end), :finish_resolve) do |*| + [] + end + end + + def plain_specs + Gem::Specification._all + end + + def plain_specs=(specs) + Gem::Specification.all = specs + end + + def fetch_specs(remote, name, fetcher) + require "rubygems/remote_fetcher" + path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz" + string = fetcher.fetch_path(path) + specs = Bundler.safe_load_marshal(string) + raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array) + specs + rescue Gem::RemoteFetcher::FetchError + # it's okay for prerelease to fail + raise unless name == "prerelease_specs" + end + + def fetch_all_remote_specs(remote, gem_remote_fetcher) + specs = fetch_specs(remote, "specs", gem_remote_fetcher) + pres = fetch_specs(remote, "prerelease_specs", gem_remote_fetcher) || [] + + specs.concat(pres) + end + + def download_gem(spec, uri, cache_dir, fetcher) + require "rubygems/remote_fetcher" + uri = Bundler.settings.mirror_for(uri) + Bundler::Retry.new("download gem from #{uri}").attempts do + gem_file_name = spec.file_name + local_gem_path = File.join cache_dir, gem_file_name + return if File.exist? local_gem_path + + begin + remote_gem_path = uri + "gems/#{gem_file_name}" + + SharedHelpers.filesystem_access(local_gem_path) do + fetcher.cache_update_path remote_gem_path, local_gem_path + end + rescue Gem::RemoteFetcher::FetchError + raise if spec.original_platform == spec.platform + + original_gem_file_name = "#{spec.original_name}.gem" + raise if gem_file_name == original_gem_file_name + + gem_file_name = original_gem_file_name + retry + end + end + rescue Gem::RemoteFetcher::FetchError => e + raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>" + end + + def build(spec, skip_validation = false) + require "rubygems/package" + Gem::Package.build(spec, skip_validation) + end + + def path_separator + Gem.path_separator + end + + def all_specs + Gem::Specification.stubs.map do |stub| + StubSpecification.from_stub(stub) + end + end + + def find_bundler(version) + find_name("bundler").find {|s| s.version.to_s == version } + end + + def find_name(name) + Gem::Specification.stubs_for(name).map(&:to_spec) + end + + def default_stubs + Gem::Specification.default_stubs("*.gemspec") + end + end + + def self.rubygems + @rubygems ||= RubygemsIntegration.new + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/runtime.rb b/bin/gems/bundler-2.5.9/lib/bundler/runtime.rb new file mode 100644 index 00000000..ec772cfe --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/runtime.rb @@ -0,0 +1,307 @@ +# frozen_string_literal: true + +module Bundler + class Runtime + include SharedHelpers + + def initialize(root, definition) + @root = root + @definition = definition + end + + def setup(*groups) + @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle? + + # Has to happen first + clean_load_path + + specs = @definition.specs_for(groups) + + SharedHelpers.set_bundle_environment + Bundler.rubygems.replace_entrypoints(specs) + + # Activate the specs + load_paths = specs.map do |spec| + check_for_activated_spec!(spec) + + Bundler.rubygems.mark_loaded(spec) + spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } + end.reverse.flatten + + Gem.add_to_load_path(*load_paths) + + setup_manpath + + lock(preserve_unknown_sections: true) + + self + end + + def require(*groups) + groups.map!(&:to_sym) + groups = [:default] if groups.empty? + + @definition.dependencies.each do |dep| + # Skip the dependency if it is not in any of the requested groups, or + # not for the current platform, or doesn't match the gem constraints. + next unless (dep.groups & groups).any? && dep.should_include? + + required_file = nil + + begin + # Loop through all the specified autorequires for the + # dependency. If there are none, use the dependency's name + # as the autorequire. + Array(dep.autorequire || dep.name).each do |file| + # Allow `require: true` as an alias for `require: ` + file = dep.name if file == true + required_file = file + begin + Kernel.require file + rescue RuntimeError => e + raise e if e.is_a?(LoadError) # we handle this a little later + raise Bundler::GemRequireError.new e, + "There was an error while trying to load the gem '#{file}'." + end + end + rescue LoadError => e + raise if dep.autorequire || e.path != required_file + + if dep.autorequire.nil? && dep.name.include?("-") + begin + namespaced_file = dep.name.tr("-", "/") + Kernel.require namespaced_file + rescue LoadError => e + raise if e.path != namespaced_file + end + end + end + end + end + + def self.definition_method(meth) + define_method(meth) do + raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition + @definition.send(meth) + end + end + private_class_method :definition_method + + definition_method :requested_specs + definition_method :specs + definition_method :dependencies + definition_method :current_dependencies + definition_method :requires + + def lock(opts = {}) + return if @definition.no_resolve_needed? + @definition.lock(opts[:preserve_unknown_sections]) + end + + alias_method :gems, :specs + + def cache(custom_path = nil, local = false) + cache_path = Bundler.app_cache(custom_path) + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end unless File.exist?(cache_path) + + Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" + + specs_to_cache = if Bundler.settings[:cache_all_platforms] + @definition.resolve.materialized_for_all_platforms + else + begin + specs + rescue GemNotFound + if local + Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." + end + + raise + end + end + + specs_to_cache.each do |spec| + next if spec.name == "bundler" + next if spec.source.is_a?(Source::Gemspec) + spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) + end + + Dir[cache_path.join("*/.git")].each do |git_dir| + FileUtils.rm_rf(git_dir) + FileUtils.touch(File.expand_path("../.bundlecache", git_dir)) + end + + prune_cache(cache_path) unless Bundler.settings[:no_prune] + end + + def prune_cache(cache_path) + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end unless File.exist?(cache_path) + resolve = @definition.resolve + prune_gem_cache(resolve, cache_path) + prune_git_and_path_cache(resolve, cache_path) + end + + def clean(dry_run = false) + gem_bins = Dir["#{Gem.dir}/bin/*"] + git_dirs = Dir["#{Gem.dir}/bundler/gems/*"] + git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"] + gem_dirs = Dir["#{Gem.dir}/gems/*"] + gem_files = Dir["#{Gem.dir}/cache/*.gem"] + gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"] + extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] + Dir["#{Gem.dir}/bundler/gems/extensions/*/*/*"] + spec_gem_paths = [] + # need to keep git sources around + spec_git_paths = @definition.spec_git_paths + spec_git_cache_dirs = [] + spec_gem_executables = [] + spec_cache_paths = [] + spec_gemspec_paths = [] + spec_extension_paths = [] + Bundler.rubygems.add_default_gems_to(specs).values.each do |spec| + spec_gem_paths << spec.full_gem_path + # need to check here in case gems are nested like for the rails git repo + md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) + spec_git_paths << md[1] if md + spec_gem_executables << spec.executables.collect do |executable| + e = "#{Bundler.rubygems.gem_bindir}/#{executable}" + [e, "#{e}.bat"] + end + spec_cache_paths << spec.cache_file + spec_gemspec_paths << spec.spec_file + spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) + spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) + end + spec_gem_paths.uniq! + spec_gem_executables.flatten! + + stale_gem_bins = gem_bins - spec_gem_executables + stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"] + stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs + stale_gem_dirs = gem_dirs - spec_gem_paths + stale_gem_files = gem_files - spec_cache_paths + stale_gemspec_files = gemspec_files - spec_gemspec_paths + stale_extension_dirs = extension_dirs - spec_extension_paths + + removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } + removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } + output = removed_stale_gem_dirs + removed_stale_git_dirs + + unless dry_run + stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files + stale_files.each do |file| + SharedHelpers.filesystem_access(File.dirname(file)) do |_p| + FileUtils.rm(file) if File.exist?(file) + end + end + + stale_dirs = stale_git_cache_dirs + stale_extension_dirs + stale_dirs.each do |stale_dir| + SharedHelpers.filesystem_access(stale_dir) do |dir| + FileUtils.rm_rf(dir) if File.exist?(dir) + end + end + end + + output + end + + private + + def prune_gem_cache(resolve, cache_path) + cached = Dir["#{cache_path}/*.gem"] + + cached = cached.delete_if do |path| + spec = Bundler.rubygems.spec_from_gem path + + resolve.any? do |s| + s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) + end + end + + if cached.any? + Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}" + + cached.each do |path| + Bundler.ui.info " * #{File.basename(path)}" + File.delete(path) + end + end + end + + def prune_git_and_path_cache(resolve, cache_path) + cached = Dir["#{cache_path}/*/.bundlecache"] + + cached = cached.delete_if do |path| + name = File.basename(File.dirname(path)) + + resolve.any? do |s| + source = s.source + source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name + end + end + + if cached.any? + Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}" + + cached.each do |path| + path = File.dirname(path) + Bundler.ui.info " * #{File.basename(path)}" + FileUtils.rm_rf(path) + end + end + end + + def setup_manpath + # Add man/ subdirectories from activated bundles to MANPATH for man(1) + manuals = $LOAD_PATH.map do |path| + man_subdir = path.sub(/lib$/, "man") + man_subdir unless Dir[man_subdir + "/man?/"].empty? + end.compact + + return if manuals.empty? + Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( + ENV["MANPATH"] ? ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) : [""] + ).uniq.join(File::PATH_SEPARATOR) + end + + def remove_dir(dir, dry_run) + full_name = Pathname.new(dir).basename.to_s + + parts = full_name.split("-") + name = parts[0..-2].join("-") + version = parts.last + output = "#{name} (#{version})" + + if dry_run + Bundler.ui.info "Would have removed #{output}" + else + Bundler.ui.info "Removing #{output}" + FileUtils.rm_rf(dir) + end + + output + end + + def check_for_activated_spec!(spec) + return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) + return if activated_spec.version == spec.version + + suggestion = if activated_spec.default_gem? + "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ + " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." + else + "Prepending `bundle exec` to your command may solve this." + end + + e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ + "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" + e.name = spec.name + e.requirement = Gem::Requirement.new(spec.version.to_s) + raise e + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/safe_marshal.rb b/bin/gems/bundler-2.5.9/lib/bundler/safe_marshal.rb new file mode 100644 index 00000000..50aa0f60 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/safe_marshal.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + module SafeMarshal + ALLOWED_CLASSES = [ + Array, + FalseClass, + Gem::Specification, + Gem::Version, + Hash, + String, + Symbol, + Time, + TrueClass, + ].freeze + + ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed." + + PROC = proc do |object| + object.tap do + unless ALLOWED_CLASSES.include?(object.class) + raise TypeError, format(ERROR, object.class, ALLOWED_CLASSES.join(", ")) + end + end + end + + def self.proc + PROC + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/self_manager.rb b/bin/gems/bundler-2.5.9/lib/bundler/self_manager.rb new file mode 100644 index 00000000..bfd000b1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/self_manager.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +module Bundler + # + # This class handles installing and switching to the version of bundler needed + # by an application. + # + class SelfManager + def restart_with_locked_bundler_if_needed + return unless needs_switching? && installed? + + restart_with(restart_version) + end + + def install_locked_bundler_and_restart_with_it_if_needed + return unless needs_switching? + + if restart_version == lockfile_version + Bundler.ui.info \ + "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \ + "Installing Bundler #{lockfile_version} and restarting using that version." + else + Bundler.ui.info \ + "Bundler #{current_version} is running, but your configuration was #{restart_version}. " \ + "Installing Bundler #{restart_version} and restarting using that version." + end + + install_and_restart_with(restart_version) + end + + def update_bundler_and_restart_with_it_if_needed(target) + return unless autoswitching_applies? + + spec = resolve_update_version_from(target) + return unless spec + + version = spec.version + + Bundler.ui.info "Updating bundler to #{version}." + + install(spec) + + restart_with(version) + end + + private + + def install_and_restart_with(version) + requirement = Gem::Requirement.new(version) + spec = find_latest_matching_spec(requirement) + + if spec.nil? + Bundler.ui.warn "Your lockfile is locked to a version of bundler (#{lockfile_version}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}" + return + end + + install(spec) + rescue StandardError => e + Bundler.ui.trace e + Bundler.ui.warn "There was an error installing the locked bundler version (#{lockfile_version}), rerun with the `--verbose` flag for more details. Going on using bundler #{current_version}." + else + restart_with(version) + end + + def install(spec) + spec.source.install(spec) + end + + def restart_with(version) + configured_gem_home = ENV["GEM_HOME"] + configured_gem_path = ENV["GEM_PATH"] + + cmd = [$PROGRAM_NAME, *ARGV] + cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME) + + Bundler.with_original_env do + Kernel.exec( + { "GEM_HOME" => configured_gem_home, "GEM_PATH" => configured_gem_path, "BUNDLER_VERSION" => version.to_s }, + *cmd + ) + end + end + + def needs_switching? + autoswitching_applies? && + released?(lockfile_version) && + !running?(lockfile_version) && + !updating? && + Bundler.settings[:version] != "system" + end + + def autoswitching_applies? + ENV["BUNDLER_VERSION"].nil? && + Bundler.rubygems.supports_bundler_trampolining? && + SharedHelpers.in_bundle? && + lockfile_version + end + + def resolve_update_version_from(target) + requirement = Gem::Requirement.new(target) + update_candidate = find_latest_matching_spec(requirement) + + if update_candidate.nil? + raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist" + end + + resolved_version = update_candidate.version + needs_update = requirement.specific? ? !running?(resolved_version) : running_older_than?(resolved_version) + + return unless needs_update + + update_candidate + end + + def local_specs + @local_specs ||= Bundler::Source::Rubygems.new("allow_local" => true, "allow_cached" => true).specs.select {|spec| spec.name == "bundler" } + end + + def remote_specs + @remote_specs ||= begin + source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org") + source.remote! + source.add_dependency_names("bundler") + source.specs.select(&:matches_current_metadata?) + end + end + + def find_latest_matching_spec(requirement) + local_result = find_latest_matching_spec_from_collection(local_specs, requirement) + return local_result if local_result && requirement.specific? + + remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement) + return remote_result if local_result.nil? + + [local_result, remote_result].max + end + + def find_latest_matching_spec_from_collection(specs, requirement) + specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) } + end + + def running?(version) + version == current_version + end + + def running_older_than?(version) + current_version < version + end + + def released?(version) + !version.to_s.end_with?(".dev") + end + + def updating? + "update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") } + end + + def installed? + Bundler.configure + + Bundler.rubygems.find_bundler(restart_version.to_s) + end + + def current_version + @current_version ||= Gem::Version.new(Bundler::VERSION) + end + + def lockfile_version + return @lockfile_version if defined?(@lockfile_version) + + parsed_version = Bundler::LockfileParser.bundled_with + @lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil + rescue ArgumentError + @lockfile_version = nil + end + + def restart_version + return @restart_version if defined?(@restart_version) + # BUNDLE_VERSION=x.y.z + @restart_version = Gem::Version.new(Bundler.settings[:version]) + rescue ArgumentError + # BUNDLE_VERSION=lockfile + @restart_version = lockfile_version + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/settings.rb b/bin/gems/bundler-2.5.9/lib/bundler/settings.rb new file mode 100644 index 00000000..379abfb2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/settings.rb @@ -0,0 +1,591 @@ +# frozen_string_literal: true + +module Bundler + class Settings + autoload :Mirror, File.expand_path("mirror", __dir__) + autoload :Mirrors, File.expand_path("mirror", __dir__) + autoload :Validator, File.expand_path("settings/validator", __dir__) + + BOOL_KEYS = %w[ + allow_deployment_source_credential_changes + allow_offline_install + auto_clean_without_path + auto_install + cache_all + cache_all_platforms + clean + default_install_uses_path + deployment + disable_checksum_validation + disable_exec_load + disable_local_branch_check + disable_local_revision_check + disable_shared_gems + disable_version_check + force_ruby_platform + forget_cli_options + frozen + gem.changelog + gem.coc + gem.mit + git.allow_insecure + global_gem_cache + ignore_messages + init_gems_rb + inline + no_install + no_prune + path_relative_to_cwd + path.system + plugins + prefer_patch + print_only_version_number + setup_makes_kernel_gem_public + silence_deprecations + silence_root_warning + update_requires_all_flag + ].freeze + + REMEMBERED_KEYS = %w[ + bin + cache_all + clean + deployment + frozen + no_prune + path + shebang + path.system + without + with + ].freeze + + NUMBER_KEYS = %w[ + jobs + redirect + retry + ssl_verify_mode + timeout + ].freeze + + ARRAY_KEYS = %w[ + only + with + without + ].freeze + + STRING_KEYS = %w[ + bin + cache_path + console + gem.ci + gem.github_username + gem.linter + gem.rubocop + gem.test + gemfile + path + shebang + system_bindir + trust-policy + version + ].freeze + + DEFAULT_CONFIG = { + "BUNDLE_SILENCE_DEPRECATIONS" => false, + "BUNDLE_DISABLE_VERSION_CHECK" => true, + "BUNDLE_PREFER_PATCH" => false, + "BUNDLE_REDIRECT" => 5, + "BUNDLE_RETRY" => 3, + "BUNDLE_TIMEOUT" => 10, + "BUNDLE_VERSION" => "lockfile", + }.freeze + + def initialize(root = nil) + @root = root + @local_config = load_config(local_config_file) + + @env_config = ENV.to_h + @env_config.select! {|key, _value| key.start_with?("BUNDLE_") } + @env_config.delete("BUNDLE_") + + @global_config = load_config(global_config_file) + @temporary = {} + + @key_cache = {} + end + + def [](name) + key = key_for(name) + + value = nil + configs.each do |_, config| + value = config[key] + next if value.nil? + break + end + + converted_value(value, name) + end + + def set_command_option(key, value) + if !is_remembered(key) || Bundler.feature_flag.forget_cli_options? + temporary(key => value) + value + else + set_local(key, value) + end + end + + def set_command_option_if_given(key, value) + return if value.nil? + set_command_option(key, value) + end + + def set_local(key, value) + local_config_file || raise(GemfileNotFound, "Could not locate Gemfile") + + set_key(key, value, @local_config, local_config_file) + end + + def temporary(update) + existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }] + update.each do |k, v| + set_key(k, v, @temporary, nil) + end + return unless block_given? + begin + yield + ensure + existing.each {|k, v| set_key(k, v, @temporary, nil) } + end + end + + def set_global(key, value) + set_key(key, value, @global_config, global_config_file) + end + + def all + keys = @temporary.keys.union(@global_config.keys, @local_config.keys, @env_config.keys) + + keys.map! do |key| + key = key.delete_prefix("BUNDLE_") + key.gsub!("___", "-") + key.gsub!("__", ".") + key.downcase! + key + end.sort! + keys + end + + def local_overrides + repos = {} + all.each do |k| + repos[k.delete_prefix("local.")] = self[k] if k.start_with?("local.") + end + repos + end + + def mirror_for(uri) + if uri.is_a?(String) + require_relative "vendored_uri" + uri = Gem::URI(uri) + end + + gem_mirrors.for(uri.to_s).uri + end + + def credentials_for(uri) + self[uri.to_s] || self[uri.host] + end + + def gem_mirrors + all.inject(Mirrors.new) do |mirrors, k| + mirrors.parse(k, self[k]) if k.start_with?("mirror.") + mirrors + end + end + + def locations(key) + key = key_for(key) + configs.keys.inject({}) do |partial_locations, level| + value_on_level = configs[level][key] + partial_locations[level] = value_on_level unless value_on_level.nil? + partial_locations + end + end + + def pretty_values_for(exposed_key) + key = key_for(exposed_key) + + locations = [] + + if value = @temporary[key] + locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}" + end + + if value = @local_config[key] + locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}" + end + + if value = @env_config[key] + locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}" + end + + if value = @global_config[key] + locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}" + end + + return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? + locations + end + + def processor_count + require "etc" + Etc.nprocessors + rescue StandardError + 1 + end + + # for legacy reasons, in Bundler 2, we do not respect :disable_shared_gems + def path + configs.each do |_level, settings| + path = value_for("path", settings) + path_system = value_for("path.system", settings) + disabled_shared_gems = value_for("disable_shared_gems", settings) + next if path.nil? && path_system.nil? && disabled_shared_gems.nil? + system_path = path_system || (disabled_shared_gems == false) + return Path.new(path, system_path) + end + + path = "vendor/bundle" if self[:deployment] + + Path.new(path, false) + end + + Path = Struct.new(:explicit_path, :system_path) do + def path + path = base_path + path = File.join(path, Bundler.ruby_scope) unless use_system_gems? + path + end + + def use_system_gems? + return true if system_path + return false if explicit_path + !Bundler.feature_flag.default_install_uses_path? + end + + def base_path + path = explicit_path + path ||= ".bundle" unless use_system_gems? + path ||= Bundler.rubygems.gem_dir + path + end + + def base_path_relative_to_pwd + base_path = Pathname.new(self.base_path) + expanded_base_path = base_path.expand_path(Bundler.root) + relative_path = expanded_base_path.relative_path_from(Pathname.pwd) + if relative_path.to_s.start_with?("..") + relative_path = base_path if base_path.absolute? + else + relative_path = Pathname.new(File.join(".", relative_path)) + end + relative_path + rescue ArgumentError + expanded_base_path + end + + def validate! + return unless explicit_path && system_path + path = Bundler.settings.pretty_values_for(:path) + path.unshift(nil, "path:") unless path.empty? + system_path = Bundler.settings.pretty_values_for("path.system") + system_path.unshift(nil, "path.system:") unless system_path.empty? + disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems) + disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty? + raise InvalidOption, + "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}" + end + end + + def ignore_config? + ENV["BUNDLE_IGNORE_CONFIG"] + end + + def app_cache_path + @app_cache_path ||= self[:cache_path] || "vendor/cache" + end + + def validate! + all.each do |raw_key| + [@local_config, @env_config, @global_config].each do |settings| + value = value_for(raw_key, settings) + Validator.validate!(raw_key, value, settings.dup) + end + end + end + + def key_for(key) + @key_cache[key] ||= self.class.key_for(key) + end + + private + + def configs + @configs ||= { + temporary: @temporary, + local: @local_config, + env: @env_config, + global: @global_config, + default: DEFAULT_CONFIG, + } + end + + def value_for(name, config) + converted_value(config[key_for(name)], name) + end + + def parent_setting_for(name) + split_specific_setting_for(name)[0] + end + + def specific_gem_for(name) + split_specific_setting_for(name)[1] + end + + def split_specific_setting_for(name) + name.split(".") + end + + def is_bool(name) + name = self.class.key_to_s(name) + BOOL_KEYS.include?(name) || BOOL_KEYS.include?(parent_setting_for(name)) + end + + def is_string(name) + name = self.class.key_to_s(name) + STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.") + end + + def to_bool(value) + case value + when String + value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true + when nil, false + false + else + true + end + end + + def is_num(key) + NUMBER_KEYS.include?(self.class.key_to_s(key)) + end + + def is_array(key) + ARRAY_KEYS.include?(self.class.key_to_s(key)) + end + + def is_remembered(key) + REMEMBERED_KEYS.include?(self.class.key_to_s(key)) + end + + def is_credential(key) + key == "gem.push_key" + end + + def is_userinfo(value) + value.include?(":") + end + + def to_array(value) + return [] unless value + value.tr(" ", ":").split(":").map(&:to_sym) + end + + def array_to_s(array) + array = Array(array) + return nil if array.empty? + array.join(":").tr(" ", ":") + end + + def set_key(raw_key, value, hash, file) + raw_key = self.class.key_to_s(raw_key) + value = array_to_s(value) if is_array(raw_key) + + key = key_for(raw_key) + + return if hash[key] == value + + hash[key] = value + hash.delete(key) if value.nil? + + Validator.validate!(raw_key, converted_value(value, raw_key), hash) + + return unless file + SharedHelpers.filesystem_access(file) do |p| + FileUtils.mkdir_p(p.dirname) + p.open("w") {|f| f.write(serializer_class.dump(hash)) } + end + end + + def converted_value(value, key) + key = self.class.key_to_s(key) + + if is_array(key) + to_array(value) + elsif value.nil? + nil + elsif is_bool(key) || value == "false" + to_bool(value) + elsif is_num(key) + value.to_i + else + value.to_s + end + end + + def printable_value(value, key) + converted = converted_value(value, key) + return converted unless converted.is_a?(String) + + if is_string(key) + converted + elsif is_credential(key) + "[REDACTED]" + elsif is_userinfo(converted) + username, pass = converted.split(":", 2) + + if pass == "x-oauth-basic" + username = "[REDACTED]" + else + pass = "[REDACTED]" + end + + [username, pass].join(":") + else + converted + end + end + + def global_config_file + if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? + Pathname.new(ENV["BUNDLE_CONFIG"]) + elsif ENV["BUNDLE_USER_CONFIG"] && !ENV["BUNDLE_USER_CONFIG"].empty? + Pathname.new(ENV["BUNDLE_USER_CONFIG"]) + elsif ENV["BUNDLE_USER_HOME"] && !ENV["BUNDLE_USER_HOME"].empty? + Pathname.new(ENV["BUNDLE_USER_HOME"]).join("config") + elsif Bundler.rubygems.user_home && !Bundler.rubygems.user_home.empty? + Pathname.new(Bundler.rubygems.user_home).join(".bundle/config") + end + end + + def local_config_file + Pathname.new(@root).join("config") if @root + end + + def load_config(config_file) + return {} if !config_file || ignore_config? + SharedHelpers.filesystem_access(config_file, :read) do |file| + valid_file = file.exist? && !file.size.zero? + return {} unless valid_file + serializer_class.load(file.read).inject({}) do |config, (k, v)| + unless k.start_with?("#") + if k.include?("-") + Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \ + "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \ + "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)." + + # string hash keys are frozen + k = k.gsub("-", "___") + end + + config[k] = v + end + + config + end + end + end + + def serializer_class + require "rubygems/yaml_serializer" + Gem::YAMLSerializer + rescue LoadError + # TODO: Remove this when RubyGems 3.4 is EOL + require_relative "yaml_serializer" + YAMLSerializer + end + + PER_URI_OPTIONS = %w[ + fallback_timeout + ].freeze + + NORMALIZE_URI_OPTIONS_PATTERN = + / + \A + (\w+\.)? # optional prefix key + (https?.*?) # URI + (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key + \z + /ix + + def self.key_for(key) + key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http") + key = key_to_s(key).gsub(".", "__") + key.gsub!("-", "___") + key.upcase! + + key.prepend("BUNDLE_") + end + + # TODO: duplicates Rubygems#normalize_uri + # TODO: is this the correct place to validate mirror URIs? + def self.normalize_uri(uri) + uri = uri.to_s + if uri =~ NORMALIZE_URI_OPTIONS_PATTERN + prefix = $1 + uri = $2 + suffix = $3 + end + uri = URINormalizer.normalize_suffix(uri) + require_relative "vendored_uri" + uri = Gem::URI(uri) + unless uri.absolute? + raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) + end + "#{prefix}#{uri}#{suffix}" + end + + # This is a hot method, so avoid respond_to? checks on every invocation + if :read.respond_to?(:name) + def self.key_to_s(key) + case key + when String + key + when Symbol + key.name + when Gem::URI::HTTP + key.to_s + else + raise ArgumentError, "Invalid key: #{key.inspect}" + end + end + else + def self.key_to_s(key) + case key + when String + key + when Symbol + key.to_s + when Gem::URI::HTTP + key.to_s + else + raise ArgumentError, "Invalid key: #{key.inspect}" + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/settings/validator.rb b/bin/gems/bundler-2.5.9/lib/bundler/settings/validator.rb new file mode 100644 index 00000000..0a57ea7f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/settings/validator.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module Bundler + class Settings + class Validator + class Rule + attr_reader :description + + def initialize(keys, description, &validate) + @keys = keys + @description = description + @validate = validate + end + + def validate!(key, value, settings) + instance_exec(key, value, settings, &@validate) + end + + def fail!(key, value, *reasons) + reasons.unshift @description + raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}" + end + + def set(settings, key, value, *reasons) + hash_key = k(key) + return if settings[hash_key] == value + reasons.unshift @description + Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}" + if value.nil? + settings.delete(hash_key) + else + settings[hash_key] = value + end + end + + def k(key) + Bundler.settings.key_for(key) + end + end + + def self.rules + @rules ||= Hash.new {|h, k| h[k] = [] } + end + private_class_method :rules + + def self.rule(keys, description, &blk) + rule = Rule.new(keys, description, &blk) + keys.each {|k| rules[k] << rule } + end + private_class_method :rule + + def self.validate!(key, value, settings) + rules_to_validate = rules[key] + rules_to_validate.each {|rule| rule.validate!(key, value, settings) } + end + + rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings| + if key == "path" && value + set(settings, "path.system", nil) + elsif key == "path.system" && value + set(settings, :path, nil) + end + end + + rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings| + with = settings.fetch(k(:with), "").split(":").map(&:to_sym) + without = settings.fetch(k(:without), "").split(":").map(&:to_sym) + + other_key = key == "with" ? :without : :with + other_setting = key == "with" ? without : with + + conflicting = with & without + if conflicting.any? + fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict") + end + end + + rule %w[path], "relative paths are expanded relative to the current working directory" do |key, value, settings| + next if value.nil? + + path = Pathname.new(value) + next if !path.relative? || !Bundler.feature_flag.path_relative_to_cwd? + + path = path.expand_path + + root = begin + Bundler.root + rescue GemfileNotFound + Pathname.pwd.expand_path + end + + path = begin + path.relative_path_from(root) + rescue ArgumentError + path + end + + set(settings, key, path.to_s) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/setup.rb b/bin/gems/bundler-2.5.9/lib/bundler/setup.rb new file mode 100644 index 00000000..7131d150 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/setup.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" + +if Bundler::SharedHelpers.in_bundle? + require_relative "../bundler" + + if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] + begin + Bundler.ui.silence { Bundler.setup } + rescue Bundler::BundlerError => e + Bundler.ui.error e.message + Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"] + if e.is_a?(Bundler::GemNotFound) + default_bundle = Gem.bin_path("bundler", "bundle") + current_bundle = Bundler::SharedHelpers.bundle_bin_path + suggested_bundle = default_bundle == current_bundle ? "bundle" : current_bundle + suggested_cmd = "#{suggested_bundle} install" + original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"] + suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile + Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems." + end + exit e.status_code + end + else + Bundler.ui.silence { Bundler.setup } + end + + # We might be in the middle of shelling out to rubygems + # (RUBYOPT=-rbundler/setup), so we need to give rubygems the opportunity of + # not being silent. + Gem::DefaultUserInteraction.ui = nil +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/shared_helpers.rb b/bin/gems/bundler-2.5.9/lib/bundler/shared_helpers.rb new file mode 100644 index 00000000..78760e6f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/shared_helpers.rb @@ -0,0 +1,380 @@ +# frozen_string_literal: true + +require "pathname" +require "rbconfig" + +require_relative "version" +require_relative "constants" +require_relative "rubygems_integration" +require_relative "current_ruby" + +module Bundler + module SharedHelpers + def root + gemfile = find_gemfile + raise GemfileNotFound, "Could not locate Gemfile" unless gemfile + Pathname.new(gemfile).expand_path.parent + end + + def default_gemfile + gemfile = find_gemfile + raise GemfileNotFound, "Could not locate Gemfile" unless gemfile + Pathname.new(gemfile).expand_path + end + + def default_lockfile + gemfile = default_gemfile + + case gemfile.basename.to_s + when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) + else Pathname.new("#{gemfile}.lock") + end + end + + def default_bundle_dir + bundle_dir = find_directory(".bundle") + return nil unless bundle_dir + + bundle_dir = Pathname.new(bundle_dir) + + global_bundle_dir = Bundler.user_home.join(".bundle") + return nil if bundle_dir == global_bundle_dir + + bundle_dir + end + + def in_bundle? + find_gemfile + end + + def chdir(dir, &blk) + Bundler.rubygems.ext_lock.synchronize do + Dir.chdir dir, &blk + end + end + + def pwd + Bundler.rubygems.ext_lock.synchronize do + Pathname.pwd + end + end + + def with_clean_git_env(&block) + keys = %w[GIT_DIR GIT_WORK_TREE] + old_env = keys.inject({}) do |h, k| + h.update(k => ENV[k]) + end + + keys.each {|key| ENV.delete(key) } + + block.call + ensure + keys.each {|key| ENV[key] = old_env[key] } + end + + def set_bundle_environment + set_bundle_variables + set_path + set_rubyopt + set_rubylib + end + + # Rescues permissions errors raised by file system operations + # (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead. + # + # @param path [String] the path that the action will be attempted to + # @param action [Symbol, #to_s] the type of operation that will be + # performed. For example: :write, :read, :exec + # + # @yield path + # + # @raise [Bundler::PermissionError] if Errno:EACCES is raised in the + # given block + # @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the + # given block + # + # @example + # filesystem_access("vendor/cache", :write) do + # FileUtils.mkdir_p("vendor/cache") + # end + # + # @see {Bundler::PermissionError} + def filesystem_access(path, action = :write, &block) + yield(path.dup) + rescue Errno::EACCES + raise PermissionError.new(path, action) + rescue Errno::EAGAIN + raise TemporaryResourceError.new(path, action) + rescue Errno::EPROTO + raise VirtualProtocolError.new + rescue Errno::ENOSPC + raise NoSpaceOnDeviceError.new(path, action) + rescue Errno::ENOTSUP + raise OperationNotSupportedError.new(path, action) + rescue Errno::EEXIST, Errno::ENOENT + raise + rescue SystemCallError => e + raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.") + end + + def major_deprecation(major_version, message, removed_message: nil, print_caller_location: false) + if print_caller_location + caller_location = caller_locations(2, 2).first + suffix = " (called at #{caller_location.path}:#{caller_location.lineno})" + message += suffix + removed_message += suffix if removed_message + end + + bundler_major_version = Bundler.bundler_major_version + if bundler_major_version > major_version + require_relative "errors" + raise DeprecatedError, "[REMOVED] #{removed_message || message}" + end + + return unless bundler_major_version >= major_version && prints_major_deprecations? + Bundler.ui.warn("[DEPRECATED] #{message}") + end + + def print_major_deprecations! + multiple_gemfiles = search_up(".") do |dir| + gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) } + next if gemfiles.empty? + break gemfiles.size != 1 + end + return unless multiple_gemfiles + message = "Multiple gemfiles (gems.rb and Gemfile) detected. " \ + "Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.locked." + Bundler.ui.warn message + end + + def ensure_same_dependencies(spec, old_deps, new_deps) + new_deps = new_deps.reject {|d| d.type == :development } + old_deps = old_deps.reject {|d| d.type == :development } + + without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } + new_deps.map!(&without_type) + old_deps.map!(&without_type) + + extra_deps = new_deps - old_deps + return if extra_deps.empty? + + Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has either corrupted API or lockfile dependencies" \ + " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" + raise APIResponseMismatchError, + "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \ + "\nRunning `bundle update #{spec.name}` should fix the problem." + end + + def pretty_dependency(dep) + msg = String.new(dep.name) + msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default + + if dep.is_a?(Bundler::Dependency) + platform_string = dep.platforms.join(", ") + msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY + end + + msg + end + + def md5_available? + return @md5_available if defined?(@md5_available) + @md5_available = begin + require "openssl" + ::OpenSSL::Digest.digest("MD5", "") + true + rescue LoadError + true + rescue ::OpenSSL::Digest::DigestError + false + end + end + + def digest(name) + require "digest" + Digest(name) + end + + def checksum_for_file(path, digest) + return unless path.file? + # This must use File.read instead of Digest.file().hexdigest + # because we need to preserve \n line endings on windows when calculating + # the checksum + SharedHelpers.filesystem_access(path, :read) do + File.open(path, "rb") do |f| + digest = SharedHelpers.digest(digest).new + buf = String.new(capacity: 16_384, encoding: Encoding::BINARY) + digest << buf while f.read(16_384, buf) + digest.hexdigest + end + end + end + + def write_to_gemfile(gemfile_path, contents) + filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } } + end + + def relative_gemfile_path + relative_path_to(Bundler.default_gemfile) + end + + def relative_lockfile_path + relative_path_to(Bundler.default_lockfile) + end + + def relative_path_to(destination, from: pwd) + Pathname.new(destination).relative_path_from(from).to_s + rescue ArgumentError + # on Windows, if source and destination are on different drivers, there's no relative path from one to the other + destination + end + + private + + def validate_bundle_path + path_separator = Bundler.rubygems.path_separator + return unless Bundler.bundle_path.to_s.split(path_separator).size > 1 + message = "Your bundle path contains text matching #{path_separator.inspect}, " \ + "which is the path separator for your system. Bundler cannot " \ + "function correctly when the Bundle path contains the " \ + "system's PATH separator. Please change your " \ + "bundle path to not match #{path_separator.inspect}." \ + "\nYour current bundle path is '#{Bundler.bundle_path}'." + raise Bundler::PathError, message + end + + def find_gemfile + given = ENV["BUNDLE_GEMFILE"] + return given if given && !given.empty? + find_file(*gemfile_names) + end + + def gemfile_names + ["gems.rb", "Gemfile"] + end + + def find_file(*names) + search_up(*names) do |filename| + return filename if File.file?(filename) + end + end + + def find_directory(*names) + search_up(*names) do |dirname| + return dirname if File.directory?(dirname) + end + end + + def search_up(*names) + previous = nil + current = File.expand_path(SharedHelpers.pwd) + + until !File.directory?(current) || current == previous + if ENV["BUNDLER_SPEC_RUN"] + # avoid stepping above the tmp directory when testing + gemspec = if ENV["GEM_COMMAND"] + # for Ruby Core + "lib/bundler/bundler.gemspec" + else + "bundler.gemspec" + end + + # avoid stepping above the tmp directory when testing + return nil if File.file?(File.join(current, gemspec)) + end + + names.each do |name| + filename = File.join(current, name) + yield filename + end + previous = current + current = File.expand_path("..", current) + end + end + + def set_env(key, value) + raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key) + orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}" + orig = ENV[key] + orig ||= EnvironmentPreserver::INTENTIONALLY_NIL + ENV[orig_key] ||= orig + + ENV[key] = value + end + public :set_env + + def set_bundle_variables + Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", bundle_bin_path + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s + Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION + Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) + end + + def bundle_bin_path + # bundler exe & lib folders have same root folder, typical gem installation + exe_file = File.expand_path("../../exe/bundle", __dir__) + + # for Ruby core repository testing + exe_file = File.expand_path("../../libexec/bundle", __dir__) unless File.exist?(exe_file) + + # bundler is a default gem, exe path is separate + exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file) + + exe_file + end + public :bundle_bin_path + + def set_path + validate_bundle_path + paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) + paths.unshift "#{Bundler.bundle_path}/bin" + Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR) + end + + def set_rubyopt + rubyopt = [ENV["RUBYOPT"]].compact + setup_require = "-r#{File.expand_path("setup", __dir__)}" + return if !rubyopt.empty? && rubyopt.first.include?(setup_require) + rubyopt.unshift setup_require + Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ") + end + + def set_rubylib + rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) + rubylib.unshift bundler_ruby_lib unless RbConfig::CONFIG["rubylibdir"] == bundler_ruby_lib + Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR) + end + + def bundler_ruby_lib + File.expand_path("..", __dir__) + end + + def clean_load_path + loaded_gem_paths = Bundler.rubygems.loaded_gem_paths + + $LOAD_PATH.reject! do |p| + resolved_path = resolve_path(p) + next if $LOADED_FEATURES.any? {|lf| lf.start_with?(resolved_path) } + loaded_gem_paths.delete(p) + end + $LOAD_PATH.uniq! + end + + def resolve_path(path) + expanded = File.expand_path(path) + return expanded unless File.exist?(expanded) + + File.realpath(expanded) + end + + def prints_major_deprecations? + require_relative "../bundler" + return false if Bundler.settings[:silence_deprecations] + require_relative "deprecate" + return false if Bundler::Deprecate.skip + true + end + + extend self + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/similarity_detector.rb b/bin/gems/bundler-2.5.9/lib/bundler/similarity_detector.rb new file mode 100644 index 00000000..50e66b9c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/similarity_detector.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module Bundler + class SimilarityDetector + SimilarityScore = Struct.new(:string, :distance) + + # initialize with an array of words to be matched against + def initialize(corpus) + @corpus = corpus + end + + # return an array of words similar to 'word' from the corpus + def similar_words(word, limit = 3) + words_by_similarity = @corpus.map {|w| SimilarityScore.new(w, levenshtein_distance(word, w)) } + words_by_similarity.select {|s| s.distance <= limit }.sort_by(&:distance).map(&:string) + end + + # return the result of 'similar_words', concatenated into a list + # (eg "a, b, or c") + def similar_word_list(word, limit = 3) + words = similar_words(word, limit) + if words.length == 1 + words[0] + elsif words.length > 1 + [words[0..-2].join(", "), words[-1]].join(" or ") + end + end + + protected + + # https://www.informit.com/articles/article.aspx?p=683059&seqNum=36 + def levenshtein_distance(this, that, ins = 2, del = 2, sub = 1) + # ins, del, sub are weighted costs + return nil if this.nil? + return nil if that.nil? + dm = [] # distance matrix + + # Initialize first row values + dm[0] = (0..this.length).collect {|i| i * ins } + fill = [0] * (this.length - 1) + + # Initialize first column values + (1..that.length).each do |i| + dm[i] = [i * del, fill.flatten] + end + + # populate matrix + (1..that.length).each do |i| + (1..this.length).each do |j| + # critical comparison + dm[i][j] = [ + dm[i - 1][j - 1] + (this[j - 1] == that[i - 1] ? 0 : sub), + dm[i][j - 1] + ins, + dm[i - 1][j] + del, + ].min + end + end + + # The last value in matrix is the Levenshtein distance between the strings + dm[that.length][this.length] + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source.rb b/bin/gems/bundler-2.5.9/lib/bundler/source.rb new file mode 100644 index 00000000..115dbd13 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module Bundler + class Source + autoload :Gemspec, File.expand_path("source/gemspec", __dir__) + autoload :Git, File.expand_path("source/git", __dir__) + autoload :Metadata, File.expand_path("source/metadata", __dir__) + autoload :Path, File.expand_path("source/path", __dir__) + autoload :Rubygems, File.expand_path("source/rubygems", __dir__) + autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) + + attr_accessor :dependency_names + + attr_reader :checksum_store + + def unmet_deps + specs.unmet_dependency_names + end + + def version_message(spec, locked_spec = nil) + message = "#{spec.name} #{spec.version}" + message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? + + if locked_spec + locked_spec_version = locked_spec.version + if locked_spec_version && spec.version != locked_spec_version + message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) + end + end + + message + end + + def can_lock?(spec) + spec.source == self + end + + def local!; end + + def local_only!; end + + def cached!; end + + def remote!; end + + def add_dependency_names(names) + @dependency_names = Array(dependency_names) | Array(names) + end + + # it's possible that gems from one source depend on gems from some + # other source, so now we download gemspecs and iterate over those + # dependencies, looking for gems we don't have info on yet. + def double_check_for(*); end + + def dependency_names_to_double_check + specs.dependency_names + end + + def spec_names + specs.spec_names + end + + def include?(other) + other == self + end + + def inspect + "#<#{self.class}:0x#{object_id} #{self}>" + end + + def identifier + to_s + end + + def path? + instance_of?(Bundler::Source::Path) + end + + def extension_cache_path(spec) + return unless Bundler.feature_flag.global_gem_cache? + return unless source_slug = extension_cache_slug(spec) + Bundler.user_cache.join( + "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, + source_slug, spec.full_name + ) + end + + private + + def version_color(spec_version, locked_spec_version) + if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) + # display yellow if there appears to be a regression + earlier_version?(spec_version, locked_spec_version) ? :yellow : :green + else + # default to green if the versions cannot be directly compared + :green + end + end + + def earlier_version?(spec_version, locked_spec_version) + Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) + end + + def print_using_message(message) + if !message.include?("(was ") + Bundler.ui.debug message + else + Bundler.ui.info message + end + end + + def extension_cache_slug(_) + nil + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/gemspec.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/gemspec.rb new file mode 100644 index 00000000..7e3447e7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/gemspec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Gemspec < Path + attr_reader :gemspec + + def initialize(options) + super + @gemspec = options["gemspec"] + end + + def as_path_source + Path.new(options) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/git.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/git.rb new file mode 100644 index 00000000..198e335b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/git.rb @@ -0,0 +1,380 @@ +# frozen_string_literal: true + +require_relative "../vendored_fileutils" + +module Bundler + class Source + class Git < Path + autoload :GitProxy, File.expand_path("git/git_proxy", __dir__) + + attr_reader :uri, :ref, :branch, :options, :glob, :submodules + + def initialize(options) + @options = options + @checksum_store = Checksum::Store.new + @glob = options["glob"] || DEFAULT_GLOB + + @allow_cached = false + @allow_remote = false + + # Stringify options that could be set as symbols + %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } + + @uri = URINormalizer.normalize_suffix(options["uri"] || "", trailing_slash: false) + @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) + @branch = options["branch"] + @ref = options["ref"] || options["branch"] || options["tag"] + @submodules = options["submodules"] + @name = options["name"] + @version = options["version"].to_s.strip.gsub("-", ".pre.") + + @copied = false + @local = false + end + + def self.from_lock(options) + new(options.merge("uri" => options.delete("remote"))) + end + + def to_lock + out = String.new("GIT\n") + out << " remote: #{@uri}\n" + out << " revision: #{revision}\n" + %w[ref branch tag submodules].each do |opt| + out << " #{opt}: #{options[opt]}\n" if options[opt] + end + out << " glob: #{@glob}\n" unless default_glob? + out << " specs:\n" + end + + def to_gemfile + specifiers = %w[ref branch tag submodules glob].map do |opt| + "#{opt}: #{options[opt]}" if options[opt] + end + + uri_with_specifiers(specifiers) + end + + def hash + [self.class, uri, ref, branch, name, version, glob, submodules].hash + end + + def eql?(other) + other.is_a?(Git) && uri == other.uri && ref == other.ref && + branch == other.branch && name == other.name && + version == other.version && glob == other.glob && + submodules == other.submodules + end + + alias_method :==, :eql? + + def include?(other) + other.is_a?(Git) && uri == other.uri && + name == other.name && + glob == other.glob && + submodules == other.submodules + end + + def to_s + begin + at = humanized_ref || current_branch + + rev = "at #{at}@#{shortref_for_display(revision)}" + rescue GitError + "" + end + + uri_with_specifiers([rev, glob_for_display]) + end + + def identifier + uri_with_specifiers([humanized_ref, cached_revision, glob_for_display]) + end + + def uri_with_specifiers(specifiers) + specifiers.compact! + + suffix = + if specifiers.any? + " (#{specifiers.join(", ")})" + else + "" + end + + "#{@safe_uri}#{suffix}" + end + + def name + File.basename(@uri, ".git") + end + + # This is the path which is going to contain a specific + # checkout of the git repository. When using local git + # repos, this is set to the local repo. + def install_path + @install_path ||= begin + git_scope = "#{base_name}-#{shortref_for_path(revision)}" + + Bundler.install_path.join(git_scope) + end + end + + alias_method :path, :install_path + + def extension_dir_name + "#{base_name}-#{shortref_for_path(revision)}" + end + + def unlock! + git_proxy.revision = nil + options["revision"] = nil + + @unlocked = true + end + + def local_override!(path) + return false if local? + + original_path = path + path = Pathname.new(path) + path = path.expand_path(Bundler.root) unless path.relative? + + unless branch || Bundler.settings[:disable_local_branch_check] + raise GitError, "Cannot use local override for #{name} at #{path} because " \ + ":branch is not specified in Gemfile. Specify a branch or run " \ + "`bundle config unset local.#{override_for(original_path)}` to remove the local override" + end + + unless path.exist? + raise GitError, "Cannot use local override for #{name} because #{path} " \ + "does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override" + end + + set_local!(path) + + # Create a new git proxy without the cached revision + # so the Gemfile.lock always picks up the new revision. + @git_proxy = GitProxy.new(path, uri, options) + + if current_branch != branch && !Bundler.settings[:disable_local_branch_check] + raise GitError, "Local override for #{name} at #{path} is using branch " \ + "#{current_branch} but Gemfile specifies #{branch}" + end + + changed = cached_revision && cached_revision != revision + + if !Bundler.settings[:disable_local_revision_check] && changed && !@unlocked && !git_proxy.contains?(cached_revision) + raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \ + "but the current branch in your local override for #{name} does not contain such commit. " \ + "Please make sure your branch is up to date." + end + + changed + end + + def specs(*) + set_local!(app_cache_path) if has_app_cache? && !local? + + if requires_checkout? && !@copied + fetch + git_proxy.copy_to(install_path, submodules) + serialize_gemspecs_in(install_path) + @copied = true + end + + local_specs + end + + def install(spec, options = {}) + return if Bundler.settings[:no_install] + force = options[:force] + + print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}" + + if (requires_checkout? && !@copied) || force + Bundler.ui.debug " * Checking out revision: #{ref}" + git_proxy.copy_to(install_path, submodules) + serialize_gemspecs_in(install_path) + @copied = true + end + + generate_bin_options = { disable_extensions: !Bundler.rubygems.spec_missing_extensions?(spec), build_args: options[:build_args] } + generate_bin(spec, generate_bin_options) + + requires_checkout? ? spec.post_install_message : nil + end + + def cache(spec, custom_path = nil) + app_cache_path = app_cache_path(custom_path) + return unless Bundler.feature_flag.cache_all? + return if path == app_cache_path + cached! + FileUtils.rm_rf(app_cache_path) + git_proxy.checkout if requires_checkout? + git_proxy.copy_to(app_cache_path, @submodules) + serialize_gemspecs_in(app_cache_path) + end + + def load_spec_files + super + rescue PathError => e + Bundler.ui.trace e + raise GitError, "#{self} is not yet checked out. Run `bundle install` first." + end + + # This is the path which is going to contain a cache + # of the git repository. When using the same git repository + # across different projects, this cache will be shared. + # When using local git repos, this is set to the local repo. + def cache_path + @cache_path ||= if Bundler.feature_flag.global_gem_cache? + Bundler.user_cache + else + Bundler.bundle_path.join("cache", "bundler") + end.join("git", git_scope) + end + + def app_cache_dirname + "#{base_name}-#{shortref_for_path(cached_revision || revision)}" + end + + def revision + git_proxy.revision + end + + def current_branch + git_proxy.current_branch + end + + def allow_git_ops? + @allow_remote || @allow_cached + end + + def local? + @local + end + + private + + def humanized_ref + if local? + path + elsif user_ref = options["ref"] + if /\A[a-z0-9]{4,}\z/i.match?(ref) + shortref_for_display(user_ref) + else + user_ref + end + elsif ref + ref + end + end + + def serialize_gemspecs_in(destination) + destination = destination.expand_path(Bundler.root) if destination.relative? + Dir["#{destination}/#{@glob}"].each do |spec_path| + # Evaluate gemspecs and cache the result. Gemspecs + # in git might require git or other dependencies. + # The gemspecs we cache should already be evaluated. + spec = Bundler.load_gemspec(spec_path) + next unless spec + Bundler.rubygems.set_installed_by_version(spec) + Bundler.rubygems.validate(spec) + File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) } + end + end + + def set_local!(path) + @local = true + @local_specs = @git_proxy = nil + @cache_path = @install_path = path + end + + def has_app_cache? + cached_revision && super + end + + def requires_checkout? + allow_git_ops? && !local? && !cached_revision_checked_out? + end + + def cached_revision_checked_out? + cached_revision && cached_revision == revision && install_path.exist? + end + + def base_name + File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") + end + + def shortref_for_display(ref) + ref[0..6] + end + + def shortref_for_path(ref) + ref[0..11] + end + + def glob_for_display + default_glob? ? nil : "glob: #{@glob}" + end + + def default_glob? + @glob == DEFAULT_GLOB + end + + def uri_hash + if %r{^\w+://(\w+@)?}.match?(uri) + # Downcase the domain component of the URI + # and strip off a trailing slash, if one is present + input = Gem::URI.parse(uri).normalize.to_s.sub(%r{/$}, "") + else + # If there is no URI scheme, assume it is an ssh/git URI + input = uri + end + # We use SHA1 here for historical reason and to preserve backward compatibility. + # But a transition to a simpler mangling algorithm would be welcome. + Bundler::Digest.sha1(input) + end + + def cached_revision + options["revision"] + end + + def cached? + cache_path.exist? + end + + def git_proxy + @git_proxy ||= GitProxy.new(cache_path, uri, options, cached_revision, self) + end + + def fetch + git_proxy.checkout + rescue GitError => e + raise unless Bundler.feature_flag.allow_offline_install? + Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" + end + + # no-op, since we validate when re-serializing the gemspec + def validate_spec(_spec); end + + def load_gemspec(file) + stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent) + stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s + StubSpecification.from_stub(stub) + end + + def git_scope + "#{base_name}-#{uri_hash}" + end + + def extension_cache_slug(_) + extension_dir_name + end + + def override_for(path) + Bundler.settings.local_overrides.key(path) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/git/git_proxy.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/git/git_proxy.rb new file mode 100644 index 00000000..64585128 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/git/git_proxy.rb @@ -0,0 +1,455 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Git + class GitNotInstalledError < GitError + def initialize + msg = String.new + msg << "You need to install git to be able to use gems from git repositories. " + msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" + super msg + end + end + + class GitNotAllowedError < GitError + def initialize(command) + msg = String.new + msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, " + msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md " + msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" + super msg + end + end + + class GitCommandError < GitError + attr_reader :command + + def initialize(command, path, extra_info = nil) + @command = command + + msg = String.new("Git error: command `#{command}`") + msg << " in directory #{path}" if path + msg << " has failed." + msg << "\n#{extra_info}" if extra_info + super msg + end + end + + class MissingGitRevisionError < GitCommandError + def initialize(command, destination_path, ref, repo) + msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" + super command, destination_path, msg + end + end + + class AmbiguousGitReference < GitError + def initialize(options) + msg = "Specification of branch or ref with tag is ambiguous. You specified #{options.inspect}" + super msg + end + end + + # The GitProxy is responsible to interact with git repositories. + # All actions required by the Git source is encapsulated in this + # object. + class GitProxy + attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref + attr_writer :revision + + def initialize(path, uri, options = {}, revision = nil, git = nil) + @path = path + @uri = uri + @tag = options["tag"] + @branch = options["branch"] + @ref = options["ref"] + if @tag + raise AmbiguousGitReference.new(options) if @branch || @ref + @explicit_ref = @tag + else + @explicit_ref = @ref || @branch + end + @revision = revision + @git = git + @commit_ref = nil + end + + def revision + @revision ||= allowed_with_path { find_local_revision } + end + + def current_branch + @current_branch ||= with_path do + git_local("rev-parse", "--abbrev-ref", "HEAD", dir: path).strip + end + end + + def contains?(commit) + allowed_with_path do + result, status = git_null("branch", "--contains", commit, dir: path) + status.success? && result.match?(/^\* (.*)$/) + end + end + + def version + @version ||= full_version.match(/((\.?\d+)+).*/)[1] + end + + def full_version + @full_version ||= git_local("--version").sub(/git version\s*/, "").strip + end + + def checkout + return if has_revision_cached? + + Bundler.ui.info "Fetching #{credential_filtered_uri}" + + extra_fetch_needed = clone_needs_extra_fetch? + unshallow_needed = clone_needs_unshallow? + return unless extra_fetch_needed || unshallow_needed + + git_remote_fetch(unshallow_needed ? ["--unshallow"] : depth_args) + end + + def copy_to(destination, submodules = false) + unless File.exist?(destination.join(".git")) + begin + SharedHelpers.filesystem_access(destination.dirname) do |p| + FileUtils.mkdir_p(p) + end + SharedHelpers.filesystem_access(destination) do |p| + FileUtils.rm_rf(p) + end + git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s + File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination) + rescue Errno::EEXIST => e + file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1] + raise GitError, "Bundler could not install a gem because it needs to " \ + "create a directory, but a file exists - #{file_path}. Please delete " \ + "this file and try again." + end + end + + ref = @commit_ref || (locked_to_full_sha? && @revision) + if ref + git "config", "uploadpack.allowAnySHA1InWant", "true", dir: path.to_s if @commit_ref.nil? && needs_allow_any_sha1_in_want? + + git "fetch", "--force", "--quiet", *extra_fetch_args(ref), dir: destination + end + + git "reset", "--hard", @revision, dir: destination + + if submodules + git_retry "submodule", "update", "--init", "--recursive", dir: destination + elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0") + inner_command = "git -C $toplevel submodule deinit --force $sm_path" + git_retry "submodule", "foreach", "--quiet", inner_command, dir: destination + end + end + + private + + def git_remote_fetch(args) + command = ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do + out, err, status = capture(command, path) + return out if status.success? + + if err.include?("couldn't find remote ref") || err.include?("not our ref") + raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri) + else + raise GitCommandError.new(command_with_no_credentials, path, err) + end + end + end + + def clone_needs_extra_fetch? + return true if path.exist? + + SharedHelpers.filesystem_access(path.dirname) do |p| + FileUtils.mkdir_p(p) + end + + command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s] + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do + _, err, status = capture(command, nil) + return extra_ref if status.success? + + if err.include?("Could not find remote branch") + raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri) + else + raise GitCommandError.new(command_with_no_credentials, path, err) + end + end + end + + def clone_needs_unshallow? + return false unless path.join("shallow").exist? + return true if full_clone? + + @revision && @revision != head_revision + end + + def extra_ref + return false if not_pinned? + return true unless full_clone? + + ref.start_with?("refs/") + end + + def depth + return @depth if defined?(@depth) + + @depth = if !supports_fetching_unreachable_refs? + nil + elsif not_pinned? || pinned_to_full_sha? + 1 + elsif ref.include?("~") + parsed_depth = ref.split("~").last + parsed_depth.to_i + 1 + end + end + + def refspec + if commit + @commit_ref = "refs/#{commit}-sha" + return "#{commit}:#{@commit_ref}" + end + + reference = fully_qualified_ref + + reference ||= if ref.include?("~") + ref.split("~").first + elsif ref.start_with?("refs/") + ref + else + "refs/*" + end + + "#{reference}:#{reference}" + end + + def commit + @commit ||= pinned_to_full_sha? ? ref : @revision + end + + def fully_qualified_ref + if branch + "refs/heads/#{branch}" + elsif tag + "refs/tags/#{tag}" + elsif ref.nil? + "refs/heads/#{current_branch}" + end + end + + def not_pinned? + branch || tag || ref.nil? + end + + def pinned_to_full_sha? + full_sha_revision?(ref) + end + + def locked_to_full_sha? + full_sha_revision?(@revision) + end + + def full_sha_revision?(ref) + ref&.match?(/\A\h{40}\z/) + end + + def git_null(*command, dir: nil) + check_allowed(command) + + capture(command, dir, ignore_err: true) + end + + def git_retry(*command, dir: nil) + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do + git(*command, dir: dir) + end + end + + def git(*command, dir: nil) + run_command(*command, dir: dir) do |unredacted_command| + check_allowed(unredacted_command) + end + end + + def git_local(*command, dir: nil) + run_command(*command, dir: dir) do |unredacted_command| + redact_and_check_presence(unredacted_command) + end + end + + def has_revision_cached? + return unless @revision && path.exist? + git("cat-file", "-e", @revision, dir: path) + true + rescue GitError + false + end + + def find_local_revision + return head_revision if explicit_ref.nil? + + find_revision_for(explicit_ref) + end + + def head_revision + verify("HEAD") + end + + def find_revision_for(reference) + verify(reference) + rescue GitCommandError => e + raise MissingGitRevisionError.new(e.command, path, reference, credential_filtered_uri) + end + + def verify(reference) + git("rev-parse", "--verify", reference, dir: path).strip + end + + # Adds credentials to the URI + def configured_uri + if /https?:/.match?(uri) + remote = Gem::URI(uri) + config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host] + remote.userinfo ||= config_auth + remote.to_s + elsif File.exist?(uri) + "file://#{uri}" + else + uri.to_s + end + end + + # Removes credentials from the URI + def credential_filtered_uri + URICredentialsFilter.credential_filtered_uri(uri) + end + + def allow? + allowed = @git ? @git.allow_git_ops? : true + + raise GitNotInstalledError.new if allowed && !Bundler.git_present? + + allowed + end + + def with_path(&blk) + checkout unless path.exist? + blk.call + end + + def allowed_with_path + return with_path { yield } if allow? + raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application" + end + + def check_allowed(command) + command_with_no_credentials = redact_and_check_presence(command) + raise GitNotAllowedError.new(command_with_no_credentials) unless allow? + command_with_no_credentials + end + + def redact_and_check_presence(command) + raise GitNotInstalledError.new unless Bundler.git_present? + + require "shellwords" + URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri) + end + + def run_command(*command, dir: nil) + command_with_no_credentials = yield(command) + + out, err, status = capture(command, dir) + + raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, err) unless status.success? + + Bundler.ui.warn err unless err.empty? + + out + end + + def capture(cmd, dir, ignore_err: false) + SharedHelpers.with_clean_git_env do + require "open3" + out, err, status = Open3.capture3(*capture3_args_for(cmd, dir)) + + filtered_out = URICredentialsFilter.credential_filtered_string(out, uri) + return [filtered_out, status] if ignore_err + + filtered_err = URICredentialsFilter.credential_filtered_string(err, uri) + [filtered_out, filtered_err, status] + end + end + + def capture3_args_for(cmd, dir) + return ["git", *cmd] unless dir + + if Bundler.feature_flag.bundler_3_mode? || supports_minus_c? + ["git", "-C", dir.to_s, *cmd] + else + ["git", *cmd, { chdir: dir.to_s }] + end + end + + def extra_clone_args + args = depth_args + return [] if args.empty? + + args += ["--single-branch"] + args.unshift("--no-tags") if supports_cloning_with_no_tags? + + # If there's a locked revision, no need to clone any specific branch + # or tag, since we will end up checking out that locked revision + # anyways. + return args if @revision + + args += ["--branch", branch || tag] if branch || tag + args + end + + def depth_args + return [] if full_clone? + + ["--depth", depth.to_s] + end + + def extra_fetch_args(ref) + extra_args = [path.to_s, *depth_args] + extra_args.push(ref) + extra_args + end + + def full_clone? + depth.nil? + end + + def supports_minus_c? + @supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5") + end + + def needs_allow_any_sha1_in_want? + @needs_allow_any_sha1_in_want ||= Gem::Version.new(version) <= Gem::Version.new("2.13.7") + end + + def supports_fetching_unreachable_refs? + @supports_fetching_unreachable_refs ||= Gem::Version.new(version) >= Gem::Version.new("2.5.0") + end + + def supports_cloning_with_no_tags? + @supports_cloning_with_no_tags ||= Gem::Version.new(version) >= Gem::Version.new("2.14.0-rc0") + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/metadata.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/metadata.rb new file mode 100644 index 00000000..4d277613 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/metadata.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Metadata < Source + def specs + @specs ||= Index.build do |idx| + idx << Gem::Specification.new("Ruby\0", Bundler::RubyVersion.system.gem_version) + idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| + s.required_rubygems_version = Gem::Requirement.default + end + + if local_spec = Gem.loaded_specs["bundler"] + idx << local_spec + else + idx << Gem::Specification.new do |s| + s.name = "bundler" + s.version = VERSION + s.license = "MIT" + s.platform = Gem::Platform::RUBY + s.authors = ["bundler team"] + s.bindir = "exe" + s.homepage = "https://bundler.io" + s.summary = "The best way to manage your application's dependencies" + s.executables = %w[bundle] + # can't point to the actual gemspec or else the require paths will be wrong + s.loaded_from = __dir__ + end + end + + idx.each {|s| s.source = self } + end + end + + def options + {} + end + + def install(spec, _opts = {}) + print_using_message "Using #{version_message(spec)}" + nil + end + + def to_s + "the local ruby installation" + end + + def ==(other) + self.class == other.class + end + alias_method :eql?, :== + + def hash + self.class.hash + end + + def version_message(spec) + "#{spec.name} #{spec.version}" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/path.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/path.rb new file mode 100644 index 00000000..978b0b2c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/path.rb @@ -0,0 +1,261 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Path < Source + autoload :Installer, File.expand_path("path/installer", __dir__) + + attr_reader :path, :options, :root_path, :original_path + attr_writer :name + attr_accessor :version + + protected :original_path + + DEFAULT_GLOB = "{,*,*/*}.gemspec" + + def initialize(options) + @checksum_store = Checksum::Store.new + @options = options.dup + @glob = options["glob"] || DEFAULT_GLOB + + @allow_cached = false + @allow_remote = false + + @root_path = options["root_path"] || root + + if options["path"] + @path = Pathname.new(options["path"]) + expanded_path = expand(@path) + @path = if @path.relative? + expanded_path.relative_path_from(root_path.expand_path) + else + expanded_path + end + end + + @name = options["name"] + @version = options["version"] + + # Stores the original path. If at any point we move to the + # cached directory, we still have the original path to copy from. + @original_path = @path + end + + def remote! + @local_specs = nil + @allow_remote = true + end + + def cached! + @local_specs = nil + @allow_cached = true + end + + def self.from_lock(options) + new(options.merge("path" => options.delete("remote"))) + end + + def to_lock + out = String.new("PATH\n") + out << " remote: #{lockfile_path}\n" + out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB + out << " specs:\n" + end + + def to_s + "source at `#{@path}`" + end + + def hash + [self.class, expanded_path, version].hash + end + + def eql?(other) + return unless other.class == self.class + expanded_original_path == other.expanded_original_path && + version == other.version + end + + alias_method :==, :eql? + + def name + File.basename(expanded_path.to_s) + end + + def install(spec, options = {}) + using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}" + using_message += " and installing its executables" unless spec.executables.empty? + print_using_message using_message + generate_bin(spec, disable_extensions: true) + nil # no post-install message + end + + def cache(spec, custom_path = nil) + app_cache_path = app_cache_path(custom_path) + return unless Bundler.feature_flag.cache_all? + return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0 + + unless @original_path.exist? + raise GemNotFound, "Can't cache gem #{version_message(spec)} because #{self} is missing!" + end + + FileUtils.rm_rf(app_cache_path) + FileUtils.cp_r("#{@original_path}/.", app_cache_path) + FileUtils.touch(app_cache_path.join(".bundlecache")) + end + + def local_specs(*) + @local_specs ||= load_spec_files + end + + def specs + if has_app_cache? + @path = app_cache_path + @expanded_path = nil # Invalidate + end + local_specs + end + + def app_cache_dirname + name + end + + def root + Bundler.root + end + + def expanded_original_path + @expanded_original_path ||= expand(original_path) + end + + private + + def expanded_path + @expanded_path ||= expand(path) + end + + def expand(somepath) + if Bundler.current_ruby.jruby? # TODO: Unify when https://github.com/rubygems/bundler/issues/7598 fixed upstream and all supported jrubies include the fix + somepath.expand_path(root_path).expand_path + else + somepath.expand_path(root_path) + end + rescue ArgumentError => e + Bundler.ui.debug(e) + raise PathError, "There was an error while trying to use the path " \ + "`#{somepath}`.\nThe error message was: #{e.message}." + end + + def lockfile_path + return relative_path(original_path) if original_path.absolute? + expand(original_path).relative_path_from(root) + end + + def app_cache_path(custom_path = nil) + @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) + end + + def has_app_cache? + SharedHelpers.in_bundle? && app_cache_path.exist? + end + + def load_gemspec(file) + return unless spec = Bundler.load_gemspec(file) + Bundler.rubygems.set_installed_by_version(spec) + spec + end + + def validate_spec(spec) + Bundler.rubygems.validate(spec) + end + + def load_spec_files + index = Index.new + + if File.directory?(expanded_path) + # We sort depth-first since `<<` will override the earlier-found specs + Gem::Util.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file| + next unless spec = load_gemspec(file) + spec.source = self + + # Validation causes extension_dir to be calculated, which depends + # on #source, so we validate here instead of load_gemspec + validate_spec(spec) + index << spec + end + + if index.empty? && @name && @version + index << Gem::Specification.new do |s| + s.name = @name + s.source = self + s.version = Gem::Version.new(@version) + s.platform = Gem::Platform::RUBY + s.summary = "Fake gemspec for #{@name}" + s.relative_loaded_from = "#{@name}.gemspec" + s.authors = ["no one"] + if expanded_path.join("bin").exist? + executables = expanded_path.join("bin").children + executables.reject! {|p| File.directory?(p) } + s.executables = executables.map {|c| c.basename.to_s } + end + end + end + else + message = String.new("The path `#{expanded_path}` ") + message << if File.exist?(expanded_path) + "is not a directory." + else + "does not exist." + end + raise PathError, message + end + + index + end + + def relative_path(path = self.path) + if path.to_s.start_with?(root_path.to_s) + return path.relative_path_from(root_path) + end + path + end + + def generate_bin(spec, options = {}) + gem_dir = Pathname.new(spec.full_gem_path) + + # Some gem authors put absolute paths in their gemspec + # and we have to save them from themselves + spec.files = spec.files.map do |path| + next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path) + next if File.directory?(path) + begin + Pathname.new(path).relative_path_from(gem_dir).to_s + rescue ArgumentError + path + end + end.compact + + installer = Path::Installer.new( + spec, + env_shebang: false, + disable_extensions: options[:disable_extensions], + build_args: options[:build_args], + bundler_extension_cache_path: extension_cache_path(spec) + ) + installer.post_install + rescue Gem::InvalidSpecificationException => e + Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ + "This prevents bundler from installing bins or native extensions, but " \ + "that may not affect its functionality." + + if !spec.extensions.empty? && !spec.email.empty? + Bundler.ui.warn "If you need to use this package without installing it from a gem " \ + "repository, please contact #{spec.email} and ask them " \ + "to modify their .gemspec so it can work with `gem build`." + end + + Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}" + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/path/installer.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/path/installer.rb new file mode 100644 index 00000000..0af28fe7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/path/installer.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require_relative "../../rubygems_gem_installer" + +module Bundler + class Source + class Path + class Installer < Bundler::RubyGemsGemInstaller + attr_reader :spec + + def initialize(spec, options = {}) + @options = options + @spec = spec + @gem_dir = Bundler.rubygems.path(spec.full_gem_path) + @wrappers = true + @env_shebang = true + @format_executable = options[:format_executable] || false + @build_args = options[:build_args] || Bundler.rubygems.build_args + @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" + @disable_extensions = options[:disable_extensions] + @bin_dir = @gem_bin_dir + end + + def post_install + run_hooks(:pre_install) + + unless @disable_extensions + build_extensions + run_hooks(:post_build) + end + + generate_bin unless spec.executables.empty? + + run_hooks(:post_install) + end + + private + + def run_hooks(type) + hooks_meth = "#{type}_hooks" + return unless Gem.respond_to?(hooks_meth) + Gem.send(hooks_meth).each do |hook| + result = hook.call(self) + next unless result == false + location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ + message = "#{type} hook#{location} failed for #{spec.full_name}" + raise InstallHookError, message + end + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems.rb new file mode 100644 index 00000000..04cfc0a8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems.rb @@ -0,0 +1,516 @@ +# frozen_string_literal: true + +require "rubygems/user_interaction" + +module Bundler + class Source + class Rubygems < Source + autoload :Remote, File.expand_path("rubygems/remote", __dir__) + + # Ask for X gems per API request + API_REQUEST_SIZE = 50 + + attr_reader :remotes + + def initialize(options = {}) + @options = options + @remotes = [] + @dependency_names = [] + @allow_remote = false + @allow_cached = options["allow_cached"] || false + @allow_local = options["allow_local"] || false + @checksum_store = Checksum::Store.new + + Array(options["remotes"]).reverse_each {|r| add_remote(r) } + end + + def caches + @caches ||= [cache_path, *Bundler.rubygems.gem_cache] + end + + def local_only! + @specs = nil + @allow_local = true + @allow_cached = false + @allow_remote = false + end + + def local! + return if @allow_local + + @specs = nil + @allow_local = true + end + + def remote! + return if @allow_remote + + @specs = nil + @allow_remote = true + end + + def cached! + return if @allow_cached + + @specs = nil + @allow_local = true + @allow_cached = true + end + + def hash + @remotes.hash + end + + def eql?(other) + other.is_a?(Rubygems) && other.credless_remotes == credless_remotes + end + + alias_method :==, :eql? + + def include?(o) + o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? + end + + def multiple_remotes? + @remotes.size > 1 + end + + def no_remotes? + @remotes.size == 0 + end + + def can_lock?(spec) + return super unless multiple_remotes? + include?(spec.source) + end + + def options + { "remotes" => @remotes.map(&:to_s) } + end + + def self.from_lock(options) + options["remotes"] = Array(options.delete("remote")).reverse + new(options) + end + + def to_lock + out = String.new("GEM\n") + remotes.reverse_each do |remote| + out << " remote: #{suppress_configured_credentials remote}\n" + end + out << " specs:\n" + end + + def to_s + if remotes.empty? + "locally installed gems" + elsif @allow_remote && @allow_cached && @allow_local + "rubygems repository #{remote_names}, cached gems or installed locally" + elsif @allow_remote && @allow_local + "rubygems repository #{remote_names} or installed locally" + elsif @allow_remote + "rubygems repository #{remote_names}" + elsif @allow_cached && @allow_local + "cached gems or installed locally" + else + "locally installed gems" + end + end + + def identifier + if remotes.empty? + "locally installed gems" + else + "rubygems repository #{remote_names}" + end + end + alias_method :name, :identifier + alias_method :to_gemfile, :identifier + + def specs + @specs ||= begin + # remote_specs usually generates a way larger Index than the other + # sources, and large_idx.merge! small_idx is way faster than + # small_idx.merge! large_idx. + index = @allow_remote ? remote_specs.dup : Index.new + index.merge!(cached_specs) if @allow_cached + index.merge!(installed_specs) if @allow_local + index + end + end + + def install(spec, options = {}) + force = options[:force] + ensure_builtin_gems_cached = options[:ensure_builtin_gems_cached] + + if ensure_builtin_gems_cached && spec.default_gem? && !cached_path(spec) + cached_built_in_gem(spec) unless spec.remote + force = true + end + + if installed?(spec) && !force + print_using_message "Using #{version_message(spec, options[:previous_spec])}" + return nil # no post-install message + end + + if spec.remote + # Check for this spec from other sources + uris = [spec.remote, *remotes_for_spec(spec)].map(&:anonymized_uri).uniq + Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 + end + + path = fetch_gem_if_possible(spec, options[:previous_spec]) + raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path + + return if Bundler.settings[:no_install] + + install_path = rubygems_dir + bin_path = Bundler.system_bindir + + require_relative "../rubygems_gem_installer" + + installer = Bundler::RubyGemsGemInstaller.at( + path, + security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]], + install_dir: install_path.to_s, + bin_dir: bin_path.to_s, + ignore_dependencies: true, + wrappers: true, + env_shebang: true, + build_args: options[:build_args], + bundler_extension_cache_path: extension_cache_path(spec) + ) + + if spec.remote + s = begin + installer.spec + rescue Gem::Package::FormatError + Bundler.rm_rf(path) + raise + rescue Gem::Security::Exception => e + raise SecurityError, + "The gem #{File.basename(path, ".gem")} can't be installed because " \ + "the security policy didn't allow it, with the message: #{e.message}" + end + + spec.__swap__(s) + end + + spec.source.checksum_store.register(spec, installer.gem_checksum) + + message = "Installing #{version_message(spec, options[:previous_spec])}" + message += " with native extensions" if spec.extensions.any? + Bundler.ui.confirm message + + installed_spec = installer.install + + spec.full_gem_path = installed_spec.full_gem_path + spec.loaded_from = installed_spec.loaded_from + + spec.post_install_message + end + + def cache(spec, custom_path = nil) + cached_path = Bundler.settings[:cache_all_platforms] ? fetch_gem_if_possible(spec) : cached_gem(spec) + raise GemNotFound, "Missing gem file '#{spec.file_name}'." unless cached_path + return if File.dirname(cached_path) == Bundler.app_cache.to_s + Bundler.ui.info " * #{File.basename(cached_path)}" + FileUtils.cp(cached_path, Bundler.app_cache(custom_path)) + rescue Errno::EACCES => e + Bundler.ui.debug(e) + raise InstallError, e.message + end + + def cached_built_in_gem(spec) + cached_path = cached_path(spec) + if cached_path.nil? + remote_spec = remote_specs.search(spec).first + if remote_spec + cached_path = fetch_gem(remote_spec) + else + Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it." + end + end + cached_path + end + + def add_remote(source) + uri = normalize_uri(source) + @remotes.unshift(uri) unless @remotes.include?(uri) + end + + def spec_names + if dependency_api_available? + remote_specs.spec_names + else + [] + end + end + + def unmet_deps + if dependency_api_available? + remote_specs.unmet_dependency_names + else + [] + end + end + + def remote_fetchers + @remote_fetchers ||= remotes.to_h do |uri| + remote = Source::Rubygems::Remote.new(uri) + [remote, Bundler::Fetcher.new(remote)] + end.freeze + end + + def fetchers + @fetchers ||= remote_fetchers.values.freeze + end + + def double_check_for(unmet_dependency_names) + return unless dependency_api_available? + + unmet_dependency_names = unmet_dependency_names.call + unless unmet_dependency_names.nil? + if api_fetchers.size <= 1 + # can't do this when there are multiple fetchers because then we might not fetch from _all_ + # of them + unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten + end + return if unmet_dependency_names.empty? + end + + Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" + + fetch_names(api_fetchers, unmet_dependency_names, remote_specs) + + specs.use remote_specs + end + + def dependency_names_to_double_check + names = [] + remote_specs.each do |spec| + case spec + when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification + names.concat(spec.runtime_dependencies.map(&:name)) + when RemoteSpecification # from the full index + return nil + else + raise "unhandled spec type (#{spec.inspect})" + end + end + names + end + + def dependency_api_available? + @allow_remote && api_fetchers.any? + end + + protected + + def remote_names + remotes.map(&:to_s).join(", ") + end + + def credless_remotes + if Bundler.settings[:allow_deployment_source_credential_changes] + remotes.map(&method(:remove_auth)) + else + remotes.map(&method(:suppress_configured_credentials)) + end + end + + def remotes_for_spec(spec) + specs.search_all(spec.name).inject([]) do |uris, s| + uris << s.remote if s.remote + uris + end + end + + def cached_gem(spec) + if spec.default_gem? + cached_built_in_gem(spec) + else + cached_path(spec) + end + end + + def cached_path(spec) + global_cache_path = download_cache_path(spec) + caches << global_cache_path if global_cache_path + + possibilities = caches.map {|p| package_path(p, spec) } + possibilities.find {|p| File.exist?(p) } + end + + def package_path(cache_path, spec) + "#{cache_path}/#{spec.file_name}" + end + + def normalize_uri(uri) + uri = URINormalizer.normalize_suffix(uri.to_s) + require_relative "../vendored_uri" + uri = Gem::URI(uri) + raise ArgumentError, "The source must be an absolute URI. For example:\n" \ + "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Gem::URI::HTTP) && uri.host.nil?) + uri + end + + def suppress_configured_credentials(remote) + remote_nouser = remove_auth(remote) + if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser] + remote_nouser + else + remote + end + end + + def remove_auth(remote) + if remote.user || remote.password + remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s + else + remote.to_s + end + end + + def installed_specs + @installed_specs ||= Index.build do |idx| + Bundler.rubygems.all_specs.reverse_each do |spec| + spec.source = self + if Bundler.rubygems.spec_missing_extensions?(spec, false) + Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" + next + end + idx << spec + end + end + end + + def cached_specs + @cached_specs ||= begin + idx = Index.new + + Dir["#{cache_path}/*.gem"].each do |gemfile| + s ||= Bundler.rubygems.spec_from_gem(gemfile) + s.source = self + idx << s + end + + idx + end + end + + def api_fetchers + fetchers.select(&:api_fetcher?) + end + + def remote_specs + @remote_specs ||= Index.build do |idx| + index_fetchers = fetchers - api_fetchers + + if index_fetchers.empty? + fetch_names(api_fetchers, dependency_names, idx) + else + fetch_names(fetchers, nil, idx) + end + end + end + + def fetch_names(fetchers, dependency_names, index) + fetchers.each do |f| + if dependency_names + Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug? + index.use f.specs_with_retry(dependency_names, self) + Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over + else + Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}" + index.use f.specs_with_retry(nil, self) + end + end + end + + def fetch_gem_if_possible(spec, previous_spec = nil) + if spec.remote + fetch_gem(spec, previous_spec) + else + cached_gem(spec) + end + end + + def fetch_gem(spec, previous_spec = nil) + spec.fetch_platform + + cache_path = download_cache_path(spec) || default_cache_path_for(rubygems_dir) + gem_path = package_path(cache_path, spec) + return gem_path if File.exist?(gem_path) + + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end + download_gem(spec, cache_path, previous_spec) + + gem_path + end + + def installed?(spec) + installed_specs[spec].any? && !spec.deleted_gem? + end + + def rubygems_dir + Bundler.bundle_path + end + + def default_cache_path_for(dir) + "#{dir}/cache" + end + + def cache_path + Bundler.app_cache + end + + private + + # Checks if the requested spec exists in the global cache. If it does, + # we copy it to the download path, and if it does not, we download it. + # + # @param [Specification] spec + # the spec we want to download or retrieve from the cache. + # + # @param [String] download_cache_path + # the local directory the .gem will end up in. + # + # @param [Specification] previous_spec + # the spec previously locked + # + def download_gem(spec, download_cache_path, previous_spec = nil) + uri = spec.remote.uri + Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}") + gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher + Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher) + end + + # Returns the global cache path of the calling Rubygems::Source object. + # + # Note that the Source determines the path's subdirectory. We use this + # subdirectory in the global cache path so that gems with the same name + # -- and possibly different versions -- from different sources are saved + # to their respective subdirectories and do not override one another. + # + # @param [Gem::Specification] specification + # + # @return [Pathname] The global cache path. + # + def download_cache_path(spec) + return unless Bundler.feature_flag.global_gem_cache? + return unless remote = spec.remote + return unless cache_slug = remote.cache_slug + + Bundler.user_cache.join("gems", cache_slug) + end + + def extension_cache_slug(spec) + return unless remote = spec.remote + remote.cache_slug + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems/remote.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems/remote.rb new file mode 100644 index 00000000..9c5c06de --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems/remote.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Rubygems + class Remote + attr_reader :uri, :anonymized_uri, :original_uri + + def initialize(uri) + orig_uri = uri + uri = Bundler.settings.mirror_for(uri) + @original_uri = orig_uri if orig_uri != uri + fallback_auth = Bundler.settings.credentials_for(uri) + + @uri = apply_auth(uri, fallback_auth).freeze + @anonymized_uri = remove_auth(@uri).freeze + end + + # @return [String] A slug suitable for use as a cache key for this + # remote. + # + def cache_slug + @cache_slug ||= begin + return nil unless SharedHelpers.md5_available? + + cache_uri = original_uri || uri + + host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host + + uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] + uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join(".")) + + uri_parts[-1] = uri_digest + uri_parts.compact.join(".") + end + end + + def to_s + "rubygems remote at #{anonymized_uri}" + end + + private + + def apply_auth(uri, auth) + if auth && uri.userinfo.nil? + uri = uri.dup + uri.userinfo = auth + end + + uri + rescue Gem::URI::InvalidComponentError + error_message = "Please CGI escape your usernames and passwords before " \ + "setting them for authentication." + raise HTTPError.new(error_message) + end + + def remove_auth(uri) + if uri.userinfo + uri = uri.dup + uri.user = uri.password = nil + end + + uri + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems_aggregate.rb b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems_aggregate.rb new file mode 100644 index 00000000..99ef81ad --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source/rubygems_aggregate.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Bundler + class Source + class RubygemsAggregate + attr_reader :source_map, :sources + + def initialize(sources, source_map) + @sources = sources + @source_map = source_map + + @index = build_index + end + + def specs + @index + end + + def identifier + to_s + end + + def to_s + "any of the sources" + end + + private + + def build_index + Index.build do |idx| + dependency_names = source_map.pinned_spec_names + + sources.all_sources.each do |source| + source.dependency_names = dependency_names - source_map.pinned_spec_names(source) + idx.add_source source.specs + dependency_names.concat(source.unmet_deps).uniq! + end + + double_check_for_index(idx, dependency_names) + end + end + + # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both + # sources A and B. At this point, the API request will have found all the versions of Bar in source A, + # but will not have found any versions of Bar from source B, which is a problem if the requested version + # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for + # each spec we found, we add all possible versions from all sources to the index. + def double_check_for_index(idx, dependency_names) + pinned_names = source_map.pinned_spec_names + + names = :names # do this so we only have to traverse to get dependency_names from the index once + unmet_dependency_names = lambda do + return names unless names == :names + new_names = sources.all_sources.map(&:dependency_names_to_double_check) + return names = nil if new_names.compact! + names = new_names.flatten(1).concat(dependency_names) + names.uniq! + names -= pinned_names + names + end + + sources.all_sources.each do |source| + source.double_check_for(unmet_dependency_names) + end + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source_list.rb b/bin/gems/bundler-2.5.9/lib/bundler/source_list.rb new file mode 100644 index 00000000..d85e1c1c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source_list.rb @@ -0,0 +1,227 @@ +# frozen_string_literal: true + +module Bundler + class SourceList + attr_reader :path_sources, + :git_sources, + :plugin_sources, + :global_path_source, + :metadata_source + + def global_rubygems_source + @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true, "allow_cached" => true) + end + + def initialize + @path_sources = [] + @git_sources = [] + @plugin_sources = [] + @global_rubygems_source = nil + @global_path_source = nil + @rubygems_sources = [] + @metadata_source = Source::Metadata.new + + @merged_gem_lockfile_sections = false + end + + def merged_gem_lockfile_sections? + @merged_gem_lockfile_sections + end + + def merged_gem_lockfile_sections!(replacement_source) + @merged_gem_lockfile_sections = true + @global_rubygems_source = replacement_source + end + + def aggregate_global_source? + global_rubygems_source.multiple_remotes? + end + + def implicit_global_source? + global_rubygems_source.no_remotes? + end + + def add_path_source(options = {}) + if options["gemspec"] + add_source_to_list Source::Gemspec.new(options), path_sources + else + path_source = add_source_to_list Source::Path.new(options), path_sources + @global_path_source ||= path_source if options["global"] + path_source + end + end + + def add_git_source(options = {}) + add_source_to_list(Source::Git.new(options), git_sources).tap do |source| + warn_on_git_protocol(source) + end + end + + def add_rubygems_source(options = {}) + new_source = Source::Rubygems.new(options) + return @global_rubygems_source if @global_rubygems_source == new_source + + add_source_to_list new_source, @rubygems_sources + end + + def add_plugin_source(source, options = {}) + add_source_to_list Plugin.source(source).new(options), @plugin_sources + end + + def add_global_rubygems_remote(uri) + global_rubygems_source.add_remote(uri) + global_rubygems_source + end + + def default_source + global_path_source || global_rubygems_source + end + + def rubygems_sources + non_global_rubygems_sources + [global_rubygems_source] + end + + def non_global_rubygems_sources + @rubygems_sources + end + + def rubygems_remotes + rubygems_sources.map(&:remotes).flatten.uniq + end + + def all_sources + path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] + end + + def non_default_explicit_sources + all_sources - [default_source, metadata_source] + end + + def get(source) + source_list_for(source).find {|s| equivalent_source?(source, s) } + end + + def lock_sources + lock_other_sources + lock_rubygems_sources + end + + def lock_other_sources + (path_sources + git_sources + plugin_sources).sort_by(&:identifier) + end + + def lock_rubygems_sources + if merged_gem_lockfile_sections? + [combine_rubygems_sources] + else + rubygems_sources.sort_by(&:identifier) + end + end + + # Returns true if there are changes + def replace_sources!(replacement_sources) + return false if replacement_sources.empty? + + @rubygems_sources, @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) + @global_rubygems_source = global_replacement_source(replacement_sources) + + different_sources?(lock_sources, replacement_sources) + end + + # Returns true if there are changes + def expired_sources?(replacement_sources) + return false if replacement_sources.empty? + + lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources + + different_sources?(lock_sources, replacement_sources) + end + + def local_only! + all_sources.each(&:local_only!) + end + + def cached! + all_sources.each(&:cached!) + end + + def remote! + all_sources.each(&:remote!) + end + + private + + def dup_with_replaced_sources(replacement_sources) + new_source_list = dup + new_source_list.replace_sources!(replacement_sources) + new_source_list + end + + def map_sources(replacement_sources) + rubygems, git, plugin = [@rubygems_sources, @git_sources, @plugin_sources].map do |sources| + sources.map do |source| + replacement_sources.find {|s| s == source } || source + end + end + + path = @path_sources.map do |source| + replacement_sources.find {|s| s == (source.is_a?(Source::Gemspec) ? source.as_path_source : source) } || source + end + + [rubygems, path, git, plugin] + end + + def global_replacement_source(replacement_sources) + replacement_source = replacement_sources.find {|s| s == global_rubygems_source } + return global_rubygems_source unless replacement_source + + replacement_source.cached! + replacement_source + end + + def different_sources?(lock_sources, replacement_sources) + !equivalent_sources?(lock_sources, replacement_sources) + end + + def rubygems_aggregate_class + Source::Rubygems + end + + def add_source_to_list(source, list) + list.unshift(source).uniq! + source + end + + def source_list_for(source) + case source + when Source::Git then git_sources + when Source::Path then path_sources + when Source::Rubygems then rubygems_sources + when Plugin::API::Source then plugin_sources + else raise ArgumentError, "Invalid source: #{source.inspect}" + end + end + + def combine_rubygems_sources + Source::Rubygems.new("remotes" => rubygems_remotes) + end + + def warn_on_git_protocol(source) + return if Bundler.settings["git.allow_insecure"] + + if /^git\:/.match?(source.uri) + Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \ + "which transmits data without encryption. Disable this warning with " \ + "`bundle config set --local git.allow_insecure true`, or switch to the `https` " \ + "protocol to keep your data secure." + end + end + + def equivalent_sources?(lock_sources, replacement_sources) + lock_sources.sort_by(&:identifier) == replacement_sources.sort_by(&:identifier) + end + + def equivalent_source?(source, other_source) + source == other_source + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/source_map.rb b/bin/gems/bundler-2.5.9/lib/bundler/source_map.rb new file mode 100644 index 00000000..ca73e01f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/source_map.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Bundler + class SourceMap + attr_reader :sources, :dependencies, :locked_specs + + def initialize(sources, dependencies, locked_specs) + @sources = sources + @dependencies = dependencies + @locked_specs = locked_specs + end + + def pinned_spec_names(skip = nil) + direct_requirements.reject {|_, source| source == skip }.keys + end + + def all_requirements + requirements = direct_requirements.dup + + unmet_deps = sources.non_default_explicit_sources.map do |source| + (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| + previous_source = requirements[indirect_dependency_name] + if previous_source.nil? + requirements[indirect_dependency_name] = source + else + no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode? + + msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] + msg.concat [previous_source, source].map {|s| " * #{s}" }.sort + msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from." + msg = msg.join("\n") + + raise SecurityError, msg if no_ambiguous_sources + Bundler.ui.warn "Warning: #{msg}" + end + end + + source.unmet_deps + end + + sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) + + requirements + end + + def direct_requirements + @direct_requirements ||= begin + requirements = {} + default = sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + dep_source.add_dependency_names(dep.name) + requirements[dep.name] = dep_source + end + requirements + end + end + + def locked_requirements + @locked_requirements ||= begin + requirements = {} + locked_specs.each do |locked_spec| + source = locked_spec.source + source.add_dependency_names(locked_spec.name) + requirements[locked_spec.name] = source + end + requirements + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/spec_set.rb b/bin/gems/bundler-2.5.9/lib/bundler/spec_set.rb new file mode 100644 index 00000000..96e1403b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/spec_set.rb @@ -0,0 +1,296 @@ +# frozen_string_literal: true + +require_relative "vendored_tsort" + +module Bundler + class SpecSet + include Enumerable + include TSort + + attr_reader :incomplete_specs + + def initialize(specs, incomplete_specs = []) + @specs = specs + @incomplete_specs = incomplete_specs + end + + def for(dependencies, check = false, platforms = [nil]) + handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h + deps = dependencies.product(platforms) + specs = [] + + loop do + break unless dep = deps.shift + + name = dep[0].name + platform = dep[1] + incomplete = false + + key = [name, platform] + next if handled.key?(key) + + handled[key] = true + + specs_for_dep = specs_for_dependency(*dep) + if specs_for_dep.any? + specs.concat(specs_for_dep) + + specs_for_dep.first.dependencies.each do |d| + next if d.type == :development + incomplete = true if d.name != "bundler" && lookup[d.name].nil? + deps << [d, dep[1]] + end + else + incomplete = true + end + + if incomplete && check + @incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)] + end + end + + specs.uniq + end + + def add_extra_platforms!(platforms) + return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty? + + new_platforms = all_platforms.select do |platform| + next if platforms.include?(platform) + next unless GemHelpers.generic(platform) == Gem::Platform::RUBY + + complete_platform(platform) + end + return platforms if new_platforms.empty? + + platforms.concat(new_platforms) + + less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform } + platforms.delete(Bundler.local_platform) if less_specific_platform + + platforms + end + + def complete_platforms!(platforms) + platforms.each do |platform| + complete_platform(platform) + end + end + + def validate_deps(s) + s.runtime_dependencies.each do |dep| + next if dep.name == "bundler" + + return :missing unless names.include?(dep.name) + return :invalid if none? {|spec| dep.matches_spec?(spec) } + end + + :valid + end + + def [](key) + key = key.name if key.respond_to?(:name) + lookup[key]&.reverse || [] + end + + def []=(key, value) + @specs << value + + reset! + end + + def delete(specs) + specs.each {|spec| @specs.delete(spec) } + + reset! + end + + def sort! + self + end + + def to_a + sorted.dup + end + + def to_hash + lookup.dup + end + + def materialize(deps) + materialized = self.for(deps, true) + + SpecSet.new(materialized, incomplete_specs) + end + + # Materialize for all the specs in the spec set, regardless of what platform they're for + # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform) + # @return [Array] + def materialized_for_all_platforms + @specs.map do |s| + next s unless s.is_a?(LazySpecification) + s.source.remote! + spec = s.materialize_for_installation + raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec + spec + end + end + + def incomplete_for_platform?(deps, platform) + return false if @specs.empty? + + @incomplete_specs = [] + + self.for(deps, true, [platform]) + + @incomplete_specs.any? + end + + def missing_specs + @specs.select {|s| s.is_a?(LazySpecification) } + end + + def -(other) + SpecSet.new(to_a - other.to_a) + end + + def find_by_name_and_platform(name, platform) + @specs.detect {|spec| spec.name == name && spec.match_platform(platform) } + end + + def delete_by_name(name) + @specs.reject! {|spec| spec.name == name } + + reset! + end + + def what_required(spec) + unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } } + return [spec] + end + what_required(req) << spec + end + + def <<(spec) + @specs << spec + end + + def length + @specs.length + end + + def size + @specs.size + end + + def empty? + @specs.empty? + end + + def each(&b) + sorted.each(&b) + end + + def names + lookup.keys + end + + private + + def reset! + @sorted = nil + @lookup = nil + end + + def complete_platform(platform) + new_specs = [] + + valid_platform = lookup.all? do |_, specs| + spec = specs.first + matching_specs = spec.source.specs.search([spec.name, spec.version]) + platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s| + s.matches_current_metadata? && valid_dependencies?(s) + end + + if platform_spec + new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec) + true + else + false + end + end + + if valid_platform && new_specs.any? + @specs.concat(new_specs) + + reset! + end + + valid_platform + end + + def all_platforms + @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq + end + + def valid_dependencies?(s) + validate_deps(s) == :valid + end + + def sorted + rake = @specs.find {|s| s.name == "rake" } + begin + @sorted ||= ([rake] + tsort).compact.uniq + rescue TSort::Cyclic => error + cgems = extract_circular_gems(error) + raise CyclicDependencyError, "Your bundle requires gems that depend" \ + " on each other, creating an infinite loop. Please remove either" \ + " gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again." + end + end + + def extract_circular_gems(error) + error.message.scan(/@name="(.*?)"/).flatten + end + + def lookup + @lookup ||= begin + lookup = {} + @specs.each do |s| + lookup[s.name] ||= [] + lookup[s.name] << s + end + lookup + end + end + + def tsort_each_node + # MUST sort by name for backwards compatibility + @specs.sort_by(&:name).each {|s| yield s } + end + + def specs_for_dependency(dep, platform) + specs_for_name = lookup[dep.name] + return [] unless specs_for_name + + matching_specs = if dep.force_ruby_platform + GemHelpers.force_ruby_platform(specs_for_name) + else + GemHelpers.select_best_platform_match(specs_for_name, platform || Bundler.local_platform) + end + matching_specs.map!(&:materialize_for_installation).compact! if platform.nil? + matching_specs + end + + def tsort_each_child(s) + s.dependencies.sort_by(&:name).each do |d| + next if d.type == :development + + specs_for_name = lookup[d.name] + next unless specs_for_name + + specs_for_name.each {|s2| yield s2 } + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/stub_specification.rb b/bin/gems/bundler-2.5.9/lib/bundler/stub_specification.rb new file mode 100644 index 00000000..da830cf8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/stub_specification.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +module Bundler + class StubSpecification < RemoteSpecification + def self.from_stub(stub) + return stub if stub.is_a?(Bundler::StubSpecification) + spec = new(stub.name, stub.version, stub.platform, nil) + spec.stub = stub + spec + end + + attr_reader :checksum + attr_accessor :stub, :ignored + + def source=(source) + super + # Stub has no concept of source, which means that extension_dir may be wrong + # This is the case for git-based gems. So, instead manually assign the extension dir + return unless source.respond_to?(:extension_dir_name) + unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") + path = File.join(stub.extensions_dir, unique_extension_dir) + stub.extension_dir = File.expand_path(path) + end + + def to_yaml + _remote_specification.to_yaml + end + + # @!group Stub Delegates + + def manually_installed? + # This is for manually installed gems which are gems that were fixed in place after a + # failed installation. Once the issue was resolved, the user then manually created + # the gem specification using the instructions provided by `gem help install` + installed_by_version == Gem::Version.new(0) + end + + # This is defined directly to avoid having to loading the full spec + def missing_extensions? + return false if default_gem? + return false if extensions.empty? + return false if File.exist? gem_build_complete_path + return false if manually_installed? + + true + end + + def activated + stub.activated + end + + def activated=(activated) + stub.instance_variable_set(:@activated, activated) + end + + def extensions + stub.extensions + end + + def gem_build_complete_path + stub.gem_build_complete_path + end + + def default_gem? + stub.default_gem? + end + + def full_gem_path + stub.full_gem_path + end + + def full_gem_path=(path) + stub.full_gem_path = path + end + + def full_require_paths + stub.full_require_paths + end + + def load_paths + full_require_paths + end + + def loaded_from + stub.loaded_from + end + + def matches_for_glob(glob) + stub.matches_for_glob(glob) + end + + def raw_require_paths + stub.raw_require_paths + end + + private + + def _remote_specification + @_remote_specification ||= begin + rs = stub.to_spec + if rs.equal?(self) # happens when to_spec gets the spec from Gem.loaded_specs + rs = Gem::Specification.load(loaded_from) + Bundler.rubygems.stub_set_spec(stub, rs) + end + + unless rs + raise GemspecError, "The gemspec for #{full_name} at #{loaded_from}" \ + " was missing or broken. Try running `gem pristine #{name} -v #{version}`" \ + " to fix the cached spec." + end + + rs.source = source + rs.base_dir = stub.base_dir + + rs + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/.document b/bin/gems/bundler-2.5.9/lib/bundler/templates/.document new file mode 100644 index 00000000..fb66f13c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/.document @@ -0,0 +1 @@ +# Ignore all files in this directory diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable new file mode 100644 index 00000000..9ff6f008 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable @@ -0,0 +1,27 @@ +#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '<%= executable %>' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("<%= spec.name %>", "<%= executable %>") diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.bundler b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.bundler new file mode 100644 index 00000000..caa20217 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.bundler @@ -0,0 +1,109 @@ +#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '<%= executable %>' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("<%= relative_gemfile_path %>", __dir__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || + cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + bundler_gem_version.approximate_recommendation + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("<%= spec.name %>", "<%= executable %>") +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.standalone b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.standalone new file mode 100644 index 00000000..3117a27e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/Executable.standalone @@ -0,0 +1,14 @@ +#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '<%= executable %>' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +$:.unshift File.expand_path "<%= standalone_path %>", __dir__ + +require "bundler/setup" +load File.expand_path "<%= executable_path %>", __dir__ diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/Gemfile b/bin/gems/bundler-2.5.9/lib/bundler/templates/Gemfile new file mode 100644 index 00000000..d2403f18 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# gem "rails" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CHANGELOG.md.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CHANGELOG.md.tt new file mode 100644 index 00000000..c9ea96d4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CHANGELOG.md.tt @@ -0,0 +1,5 @@ +## [Unreleased] + +## [0.1.0] - <%= Time.now.strftime('%F') %> + +- Initial release diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt new file mode 100644 index 00000000..175b821a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt @@ -0,0 +1,84 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at <%= config[:email] %>. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, +available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Cargo.toml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Cargo.toml.tt new file mode 100644 index 00000000..f5a460c9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Cargo.toml.tt @@ -0,0 +1,7 @@ +# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is +# a Rust project. Your extensions dependencies should be added to the Cargo.toml +# in the ext/ directory. + +[workspace] +members = ["./ext/<%= config[:name] %>"] +resolver = "2" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Gemfile.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Gemfile.tt new file mode 100644 index 00000000..a0d2ac28 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Gemfile.tt @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in <%= config[:name] %>.gemspec +gemspec + +gem "rake", "~> 13.0" +<%- if config[:ext] -%> + +gem "rake-compiler" +<%- if config[:ext] == 'rust' -%> +gem "rb_sys", "~> 0.9.63" +<%- end -%> +<%- end -%> +<%- if config[:test] -%> + +gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" +<%- end -%> +<%- if config[:linter] == "rubocop" -%> + +gem "rubocop", "~> <%= config[:linter_version] %>" +<%- elsif config[:linter] == "standard" -%> + +gem "standard", "~> <%= config[:linter_version] %>" +<%- end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/LICENSE.txt.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/LICENSE.txt.tt new file mode 100644 index 00000000..76ef4b01 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/LICENSE.txt.tt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) <%= Time.now.year %> <%= config[:author] %> + +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/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/README.md.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/README.md.tt new file mode 100644 index 00000000..5bf36378 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/README.md.tt @@ -0,0 +1,45 @@ +# <%= config[:constant_name] %> + +TODO: Delete this and the text below, and describe your gem + +Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. + +## Installation + +TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org. + +Install the gem and add to the application's Gemfile by executing: + + $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG + +If bundler is not being used to manage dependencies, install the gem by executing: + + $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG + +## Usage + +TODO: Write usage instructions here + +## Development + +After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). +<% if config[:git] -%> + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %> +<% end -%> +<% if config[:mit] -%> + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). +<% end -%> +<% if config[:git] && config[:coc] -%> + +## Code of Conduct + +Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md). +<% end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Rakefile.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Rakefile.tt new file mode 100644 index 00000000..172183d4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/Rakefile.tt @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +<% default_task_names = [config[:test_task]].compact -%> +<% case config[:test] -%> +<% when "minitest" -%> +require "minitest/test_task" + +Minitest::TestTask.create + +<% when "test-unit" -%> +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/**/*_test.rb"] +end + +<% when "rspec" -%> +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +<% end -%> +<% if config[:linter] == "rubocop" -%> +<% default_task_names << :rubocop -%> +require "rubocop/rake_task" + +RuboCop::RakeTask.new + +<% elsif config[:linter] == "standard" -%> +<% default_task_names << :standard -%> +require "standard/rake" + +<% end -%> +<% if config[:ext] -%> +<% default_task_names.unshift(:compile) -%> +<% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%> +<% if config[:ext] == 'rust' -%> +require "rb_sys/extensiontask" + +task build: :compile + +GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec") + +RbSys::ExtensionTask.new(<%= config[:name].inspect %>, GEMSPEC) do |ext| + ext.lib_dir = "lib/<%= config[:namespaced_path] %>" +end +<% else -%> +require "rake/extensiontask" + +task build: :compile + +GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec") + +Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext| + ext.lib_dir = "lib/<%= config[:namespaced_path] %>" +end +<% end -%> + +<% end -%> +<% if default_task_names.size == 1 -%> +task default: <%= default_task_names.first.inspect %> +<% else -%> +task default: %i[<%= default_task_names.join(" ") %>] +<% end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/console.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/console.tt new file mode 100644 index 00000000..c91ee65f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/console.tt @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "<%= config[:namespaced_path] %>" + +# 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. + +require "irb" +IRB.start(__FILE__) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/setup.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/setup.tt new file mode 100644 index 00000000..dce67d86 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/bin/setup.tt @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/circleci/config.yml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/circleci/config.yml.tt new file mode 100644 index 00000000..f40f029b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/circleci/config.yml.tt @@ -0,0 +1,25 @@ +version: 2.1 +jobs: + build: + docker: + - image: ruby:<%= RUBY_VERSION %> +<%- if config[:ext] == 'rust' -%> + environment: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> + steps: + - checkout +<%- if config[:ext] == 'rust' -%> + - run: + name: Install Rust/Cargo dependencies + command: apt-get update && apt-get install -y clang + - run: + name: Install a RubyGems version that can compile rust extensions + command: gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> + - run: + name: Run the default task + command: | + gem install bundler -v <%= Bundler::VERSION %> + bundle install + bundle exec rake diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/exe/newgem.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/exe/newgem.tt new file mode 100644 index 00000000..a8339bb7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/exe/newgem.tt @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +require "<%= config[:namespaced_path] %>" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt new file mode 100644 index 00000000..0ebce0e4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt @@ -0,0 +1,15 @@ +[package] +name = <%= config[:name].inspect %> +version = "0.1.0" +edition = "2021" +authors = ["<%= config[:author] %> <<%= config[:email] %>>"] +<%- if config[:mit] -%> +license = "MIT" +<%- end -%> +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +magnus = { version = "0.6.2" } diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt new file mode 100644 index 00000000..0a0c5a3d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "mkmf" + +# Makes all symbols private by default to avoid unintended conflict +# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED +# selectively, or entirely remove this flag. +append_cflags("-fvisibility=hidden") + +create_makefile(<%= config[:makefile_path].inspect %>) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt new file mode 100644 index 00000000..e24566a1 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "mkmf" +require "rb_sys/mkmf" + +create_rust_makefile(<%= config[:makefile_path].inspect %>) diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt new file mode 100644 index 00000000..bcd51485 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt @@ -0,0 +1,9 @@ +#include "<%= config[:underscored_name] %>.h" + +VALUE rb_m<%= config[:constant_array].join %>; + +RUBY_FUNC_EXPORTED void +Init_<%= config[:underscored_name] %>(void) +{ + rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); +} diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt new file mode 100644 index 00000000..c6e420b6 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt @@ -0,0 +1,6 @@ +#ifndef <%= config[:underscored_name].upcase %>_H +#define <%= config[:underscored_name].upcase %>_H 1 + +#include "ruby.h" + +#endif /* <%= config[:underscored_name].upcase %>_H */ diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt new file mode 100644 index 00000000..ba234529 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt @@ -0,0 +1,12 @@ +use magnus::{function, prelude::*, Error, Ruby}; + +fn hello(subject: String) -> String { + format!("Hello from Rust, {subject}!") +} + +#[magnus::init] +fn init(ruby: &Ruby) -> Result<(), Error> { + let module = ruby.<%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>; + module.define_singleton_method("hello", function!(hello, 1))?; + Ok(()) +} diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/github/workflows/main.yml.tt new file mode 100644 index 00000000..32b39558 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/github/workflows/main.yml.tt @@ -0,0 +1,37 @@ +name: Ruby + +on: + push: + branches: + - <%= config[:git_default_branch] %> + + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + name: Ruby ${{ matrix.ruby }} + strategy: + matrix: + ruby: + - '<%= RUBY_VERSION %>' + + steps: + - uses: actions/checkout@v4 +<%- if config[:ext] == 'rust' -%> + - name: Set up Ruby & Rust + uses: oxidize-rb/actions/setup-ruby-and-rust@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + cargo-cache: true + rubygems: '<%= ::Gem.rubygems_version %>' +<%- else -%> + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true +<%- end -%> + - name: Run the default task + run: bundle exec rake diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitignore.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitignore.tt new file mode 100644 index 00000000..9b40ba5a --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitignore.tt @@ -0,0 +1,23 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +<%- if config[:ext] -%> +*.bundle +*.so +*.o +*.a +mkmf.log +<%- if config[:ext] == 'rust' -%> +target/ +<%- end -%> +<%- end -%> +<%- if config[:test] == "rspec" -%> + +# rspec failure tracking +.rspec_status +<%- end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitlab-ci.yml.tt new file mode 100644 index 00000000..d2e1f337 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/gitlab-ci.yml.tt @@ -0,0 +1,18 @@ +default: + image: ruby:<%= RUBY_VERSION %> + + before_script: +<%- if config[:ext] == 'rust' -%> + - apt-get update && apt-get install -y clang + - gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> + - gem install bundler -v <%= Bundler::VERSION %> + - bundle install + +example_job: +<%- if config[:ext] == 'rust' -%> + variables: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> + script: + - bundle exec rake diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem.rb.tt new file mode 100644 index 00000000..caf6e32f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require_relative "<%= File.basename(config[:namespaced_path]) %>/version" +<%- if config[:ext] -%> +require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>" +<%- end -%> + +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>class Error < StandardError; end +<%= " " * config[:constant_array].size %># Your code goes here... +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem/version.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem/version.rb.tt new file mode 100644 index 00000000..b5cd4cb2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/lib/newgem/version.rb.tt @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>VERSION = "0.1.0" +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/newgem.gemspec.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/newgem.gemspec.tt new file mode 100644 index 00000000..6e88f4da --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require_relative "lib/<%=config[:namespaced_path]%>/version" + +Gem::Specification.new do |spec| + spec.name = <%= config[:name].inspect %> + spec.version = <%= config[:constant_name] %>::VERSION + spec.authors = [<%= config[:author].inspect %>] + spec.email = [<%= config[:email].inspect %>] + + spec.summary = "TODO: Write a short summary, because RubyGems requires one." + spec.description = "TODO: Write a longer description or delete this line." + spec.homepage = "TODO: Put your gem's website or public repo URL here." +<%- if config[:mit] -%> + spec.license = "MIT" +<%- end -%> + spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" +<%- if config[:ext] == 'rust' -%> + spec.required_rubygems_version = ">= <%= config[:rust_builder_required_rubygems_version] %>" +<%- end -%> + + spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." + spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + gemspec = File.basename(__FILE__) + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| + ls.readlines("\x0", chomp: true).reject do |f| + (f == gemspec) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git <%= config[:ci_config_path] %>appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] +<%- if config[:ext] == 'c' -%> + spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] +<%- end -%> +<%- if config[:ext] == 'rust' -%> + spec.extensions = ["ext/<%= config[:underscored_name] %>/Cargo.toml"] +<%- end -%> + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" + + # For more information and examples about making a new gem, check out our + # guide at: https://bundler.io/guides/creating_gem.html +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rspec.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rspec.tt new file mode 100644 index 00000000..34c5164d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rspec.tt @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rubocop.yml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rubocop.yml.tt new file mode 100644 index 00000000..3d1c4ee7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/rubocop.yml.tt @@ -0,0 +1,8 @@ +AllCops: + TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> + +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + EnforcedStyle: double_quotes diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/sig/newgem.rbs.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/sig/newgem.rbs.tt new file mode 100644 index 00000000..eb7b380b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/sig/newgem.rbs.tt @@ -0,0 +1,8 @@ +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>VERSION: String +<%= " " * config[:constant_array].size %># See the writing guide of rbs: https://github.com/ruby/rbs#guides +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt new file mode 100644 index 00000000..82cada98 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +RSpec.describe <%= config[:constant_name] %> do + it "has a version number" do + expect(<%= config[:constant_name] %>::VERSION).not_to be nil + end + + it "does something useful" do + expect(false).to eq(true) + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/spec_helper.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/spec_helper.rb.tt new file mode 100644 index 00000000..70c6d1fc --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/spec/spec_helper.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "<%= config[:namespaced_path] %>" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/standard.yml.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/standard.yml.tt new file mode 100644 index 00000000..a0696cd2 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/standard.yml.tt @@ -0,0 +1,3 @@ +# For available configuration options, see: +# https://github.com/standardrb/standard +ruby_version: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt new file mode 100644 index 00000000..e05c387b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "<%= config[:namespaced_path] %>" + +require "minitest/autorun" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt new file mode 100644 index 00000000..4b35a630 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "test_helper" + +class <%= config[:minitest_constant_name] %> < Minitest::Test + def test_that_it_has_a_version_number + refute_nil ::<%= config[:constant_name] %>::VERSION + end + + def test_it_does_something_useful + assert false + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt new file mode 100644 index 00000000..5c61094e --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "test_helper" + +class <%= config[:constant_name] %>Test < Test::Unit::TestCase + test "VERSION" do + assert do + ::<%= config[:constant_name] %>.const_defined?(:VERSION) + end + end + + test "something useful" do + assert_equal("expected", "actual") + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt new file mode 100644 index 00000000..6f633c60 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "<%= config[:namespaced_path] %>" + +require "test-unit" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ui.rb b/bin/gems/bundler-2.5.9/lib/bundler/ui.rb new file mode 100644 index 00000000..7a4fa036 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ui.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Bundler + module UI + autoload :RGProxy, File.expand_path("ui/rg_proxy", __dir__) + autoload :Shell, File.expand_path("ui/shell", __dir__) + autoload :Silent, File.expand_path("ui/silent", __dir__) + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ui/rg_proxy.rb b/bin/gems/bundler-2.5.9/lib/bundler/ui/rg_proxy.rb new file mode 100644 index 00000000..b17ca65f --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ui/rg_proxy.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require_relative "../ui" +require "rubygems/user_interaction" + +module Bundler + module UI + class RGProxy < ::Gem::SilentUI + def initialize(ui) + @ui = ui + super() + end + + def say(message) + @ui&.debug(message) + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ui/shell.rb b/bin/gems/bundler-2.5.9/lib/bundler/ui/shell.rb new file mode 100644 index 00000000..4555612d --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ui/shell.rb @@ -0,0 +1,165 @@ +# frozen_string_literal: true + +require_relative "../vendored_thor" + +module Bundler + module UI + class Shell + LEVELS = %w[silent error warn confirm info debug].freeze + + attr_writer :shell + + def initialize(options = {}) + Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil + @shell = Thor::Base.shell.new + @level = ENV["DEBUG"] ? "debug" : "info" + @warning_history = [] + end + + def add_color(string, *color) + @shell.set_color(string, *color) + end + + def info(msg = nil, newline = nil) + return unless info? + + tell_me(msg || yield, nil, newline) + end + + def confirm(msg = nil, newline = nil) + return unless confirm? + + tell_me(msg || yield, :green, newline) + end + + def warn(msg = nil, newline = nil, color = :yellow) + return unless warn? + return if @warning_history.include? msg + @warning_history << msg + + tell_err(msg || yield, color, newline) + end + + def error(msg = nil, newline = nil, color = :red) + return unless error? + + tell_err(msg || yield, color, newline) + end + + def debug(msg = nil, newline = nil) + return unless debug? + + tell_me(msg || yield, nil, newline) + end + + def info? + level("info") + end + + def confirm? + level("confirm") + end + + def warn? + level("warn") + end + + def error? + level("error") + end + + def debug? + level("debug") + end + + def quiet? + level("quiet") + end + + def ask(msg) + @shell.ask(msg) + end + + def yes?(msg) + @shell.yes?(msg) + end + + def no? + @shell.no?(msg) + end + + def level=(level) + raise ArgumentError unless LEVELS.include?(level.to_s) + @level = level.to_s + end + + def level(name = nil) + return @level unless name + unless index = LEVELS.index(name) + raise "#{name.inspect} is not a valid level" + end + index <= LEVELS.index(@level) + end + + def trace(e, newline = nil, force = false) + return unless debug? || force + msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" + tell_err(msg, nil, newline) + end + + def silence(&blk) + with_level("silent", &blk) + end + + def unprinted_warnings + [] + end + + private + + # valimism + def tell_me(msg, color = nil, newline = nil) + msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] + if newline.nil? + @shell.say(msg, color) + else + @shell.say(msg, color, newline) + end + end + + def tell_err(message, color = nil, newline = nil) + return if @shell.send(:stderr).closed? + + newline ||= !message.to_s.match?(/( |\t)\Z/) + message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] + + color = nil if color && !$stderr.tty? + + buffer = @shell.send(:prepare_message, message, *color) + buffer << "\n" if newline && !message.to_s.end_with?("\n") + + @shell.send(:stderr).print(buffer) + @shell.send(:stderr).flush + end + + def strip_leading_spaces(text) + spaces = text[/\A\s+/, 0] + spaces ? text.gsub(/#{spaces}/, "") : text + end + + def word_wrap(text, line_width = Thor::Terminal.terminal_width) + strip_leading_spaces(text).split("\n").collect do |line| + line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line + end * "\n" + end + + def with_level(level) + original = @level + @level = level + yield + ensure + @level = original + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/ui/silent.rb b/bin/gems/bundler-2.5.9/lib/bundler/ui/silent.rb new file mode 100644 index 00000000..fa3292bd --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/ui/silent.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Bundler + module UI + class Silent + attr_writer :shell + + def initialize + @warnings = [] + end + + def add_color(string, color) + string + end + + def info(message = nil, newline = nil) + end + + def confirm(message = nil, newline = nil) + end + + def warn(message = nil, newline = nil) + @warnings |= [message] + end + + def error(message = nil, newline = nil) + end + + def debug(message = nil, newline = nil) + end + + def confirm? + false + end + + def error? + false + end + + def debug? + false + end + + def info? + false + end + + def quiet? + false + end + + def warn? + false + end + + def ask(message) + end + + def yes?(msg) + raise "Cannot ask yes? with a silent shell" + end + + def no? + raise "Cannot ask no? with a silent shell" + end + + def level=(name) + end + + def level(name = nil) + end + + def trace(message, newline = nil, force = false) + end + + def silence + yield + end + + def unprinted_warnings + @warnings + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/uri_credentials_filter.rb b/bin/gems/bundler-2.5.9/lib/bundler/uri_credentials_filter.rb new file mode 100644 index 00000000..a83f5304 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/uri_credentials_filter.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Bundler + module URICredentialsFilter + module_function + + def credential_filtered_uri(uri_to_anonymize) + return uri_to_anonymize if uri_to_anonymize.nil? + uri = uri_to_anonymize.dup + if uri.is_a?(String) + return uri if File.exist?(uri) + + require_relative "vendored_uri" + uri = Gem::URI(uri) + end + + if uri.userinfo + # oauth authentication + if uri.password == "x-oauth-basic" || uri.password == "x" + # URI as string does not display with password if no user is set + oauth_designation = uri.password + uri.user = oauth_designation + end + uri.password = nil + end + return uri.to_s if uri_to_anonymize.is_a?(String) + uri + rescue Gem::URI::InvalidURIError # uri is not canonical uri scheme + uri + end + + def credential_filtered_string(str_to_filter, uri) + return str_to_filter if uri.nil? || str_to_filter.nil? + str_with_no_credentials = str_to_filter.dup + anonymous_uri_str = credential_filtered_uri(uri).to_s + uri_str = uri.to_s + if anonymous_uri_str != uri_str + str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) + end + str_with_no_credentials + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/uri_normalizer.rb b/bin/gems/bundler-2.5.9/lib/bundler/uri_normalizer.rb new file mode 100644 index 00000000..ad085932 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/uri_normalizer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Bundler + module URINormalizer + module_function + + # Normalizes uri to a consistent version, either with or without trailing + # slash. + # + # TODO: Currently gem sources are locked with a trailing slash, while git + # sources are locked without a trailing slash. This should be normalized but + # the inconsistency is there for now to avoid changing all lockfiles + # including GIT sources. We could normalize this on the next major. + # + def normalize_suffix(uri, trailing_slash: true) + if trailing_slash + uri.end_with?("/") ? uri : "#{uri}/" + else + uri.end_with?("/") ? uri.delete_suffix("/") : uri + end + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_fileutils.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_fileutils.rb new file mode 100644 index 00000000..1be1138c --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_fileutils.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/fileutils/lib/fileutils" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_net_http.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_net_http.rb new file mode 100644 index 00000000..0dcabaa7 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_net_http.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +begin + require "rubygems/vendored_net_http" +rescue LoadError + begin + require "rubygems/net/http" + rescue LoadError + require "net/http" + Gem::Net = Net + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_persistent.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_persistent.rb new file mode 100644 index 00000000..ab985c26 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_persistent.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Bundler + module Persistent + module Net + module HTTP + end + end + end +end +require_relative "vendor/net-http-persistent/lib/net/http/persistent" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_pub_grub.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_pub_grub.rb new file mode 100644 index 00000000..b36a996b --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_pub_grub.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/pub_grub/lib/pub_grub" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_thor.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_thor.rb new file mode 100644 index 00000000..0666cfc9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_thor.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Bundler + def self.require_thor_actions + require_relative "vendor/thor/lib/thor/actions" + end +end +require_relative "vendor/thor/lib/thor" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_timeout.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_timeout.rb new file mode 100644 index 00000000..9b2507c0 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_timeout.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +begin + require "rubygems/vendored_timeout" +rescue LoadError + begin + require "rubygems/timeout" + rescue LoadError + require "timeout" + Gem::Timeout = Timeout + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_tsort.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_tsort.rb new file mode 100644 index 00000000..38aed0b5 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_tsort.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/tsort/lib/tsort" diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vendored_uri.rb b/bin/gems/bundler-2.5.9/lib/bundler/vendored_uri.rb new file mode 100644 index 00000000..2efddc65 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vendored_uri.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Bundler; end + +# Use RubyGems vendored copy when available. Otherwise fallback to Bundler +# vendored copy. The vendored copy in Bundler can be removed once support for +# RubyGems 3.5 is dropped. + +begin + require "rubygems/vendor/uri/lib/uri" +rescue LoadError + require_relative "vendor/uri/lib/uri" + Gem::URI = Bundler::URI + + module Gem + def URI(uri) # rubocop:disable Naming/MethodName + Bundler::URI(uri) + end + module_function :URI + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/version.rb b/bin/gems/bundler-2.5.9/lib/bundler/version.rb new file mode 100644 index 00000000..cc9550e9 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: false + +module Bundler + VERSION = "2.5.9".freeze + + def self.bundler_major_version + @bundler_major_version ||= VERSION.split(".").first.to_i + end + + def self.gem_version + @gem_version ||= Gem::Version.create(VERSION) + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/vlad.rb b/bin/gems/bundler-2.5.9/lib/bundler/vlad.rb new file mode 100644 index 00000000..6179d0e4 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/vlad.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.major_deprecation 2, + "The Bundler task for Vlad" + +# Vlad task for Bundler. +# +# Add "require 'bundler/vlad'" in your Vlad deploy.rb, and +# include the vlad:bundle:install task in your vlad:deploy task. +require_relative "deployment" + +include Rake::DSL if defined? Rake::DSL + +namespace :vlad do + Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, roles: :app) +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/worker.rb b/bin/gems/bundler-2.5.9/lib/bundler/worker.rb new file mode 100644 index 00000000..3ebd6f01 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/worker.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Bundler + class Worker + POISON = Object.new + + class WrappedException < StandardError + attr_reader :exception + def initialize(exn) + @exception = exn + end + end + + # @return [String] the name of the worker + attr_reader :name + + # Creates a worker pool of specified size + # + # @param size [Integer] Size of pool + # @param name [String] name the name of the worker + # @param func [Proc] job to run in inside the worker pool + def initialize(size, name, func) + @name = name + @request_queue = Thread::Queue.new + @response_queue = Thread::Queue.new + @func = func + @size = size + @threads = nil + @previous_interrupt_handler = nil + end + + # Enqueue a request to be executed in the worker pool + # + # @param obj [String] mostly it is name of spec that should be downloaded + def enq(obj) + create_threads unless @threads + @request_queue.enq obj + end + + # Retrieves results of job function being executed in worker pool + def deq + result = @response_queue.deq + raise result.exception if result.is_a?(WrappedException) + result + end + + def stop + stop_threads + end + + private + + def process_queue(i) + loop do + obj = @request_queue.deq + break if obj.equal? POISON + @response_queue.enq apply_func(obj, i) + end + end + + def apply_func(obj, i) + @func.call(obj, i) + rescue Exception => e # rubocop:disable Lint/RescueException + WrappedException.new(e) + end + + # Stop the worker threads by sending a poison object down the request queue + # so as worker threads after retrieving it, shut themselves down + def stop_threads + return unless @threads + + @threads.each { @request_queue.enq POISON } + @threads.each(&:join) + + remove_interrupt_handler + + @threads = nil + end + + def abort_threads + Bundler.ui.debug("\n#{caller.join("\n")}") + @threads.each(&:exit) + exit 1 + end + + def create_threads + creation_errors = [] + + @threads = Array.new(@size) do |i| + Thread.start { process_queue(i) }.tap do |thread| + thread.name = "#{name} Worker ##{i}" if thread.respond_to?(:name=) + end + rescue ThreadError => e + creation_errors << e + nil + end.compact + + add_interrupt_handler unless @threads.empty? + + return if creation_errors.empty? + + message = "Failed to create threads for the #{name} worker: #{creation_errors.map(&:to_s).uniq.join(", ")}" + raise ThreadCreationError, message if @threads.empty? + Bundler.ui.info message + end + + def add_interrupt_handler + @previous_interrupt_handler = trap("INT") { abort_threads } + end + + def remove_interrupt_handler + return unless @previous_interrupt_handler + + trap "INT", @previous_interrupt_handler + end + end +end diff --git a/bin/gems/bundler-2.5.9/lib/bundler/yaml_serializer.rb b/bin/gems/bundler-2.5.9/lib/bundler/yaml_serializer.rb new file mode 100644 index 00000000..42e6aaf8 --- /dev/null +++ b/bin/gems/bundler-2.5.9/lib/bundler/yaml_serializer.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +module Bundler + # A stub yaml serializer that can handle only hashes and strings (as of now). + module YAMLSerializer + module_function + + def dump(hash) + yaml = String.new("---") + yaml << dump_hash(hash) + end + + def dump_hash(hash) + yaml = String.new("\n") + hash.each do |k, v| + yaml << k << ":" + if v.is_a?(Hash) + yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines + elsif v.is_a?(Array) # Expected to be array of strings + if v.empty? + yaml << " []\n" + else + yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n" + end + else + yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n" + end + end + yaml + end + + ARRAY_REGEX = / + ^ + (?:[ ]*-[ ]) # '- ' before array items + (['"]?) # optional opening quote + (.*) # value + \1 # matching closing quote + $ + /xo + + HASH_REGEX = / + ^ + ([ ]*) # indentations + (.+) # key + (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value) + [ ]? + (['"]?) # optional opening quote + (.*) # value + \3 # matching closing quote + $ + /xo + + def load(str) + res = {} + stack = [res] + last_hash = nil + last_empty_key = nil + str.split(/\r?\n/) do |line| + if match = HASH_REGEX.match(line) + indent, key, quote, val = match.captures + val = strip_comment(val) + + convert_to_backward_compatible_key!(key) + depth = indent.size / 2 + if quote.empty? && val.empty? + new_hash = {} + stack[depth][key] = new_hash + stack[depth + 1] = new_hash + last_empty_key = key + last_hash = stack[depth] + else + val = [] if val == "[]" # empty array + stack[depth][key] = val + end + elsif match = ARRAY_REGEX.match(line) + _, val = match.captures + val = strip_comment(val) + + last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array) + + last_hash[last_empty_key].push(val) + end + end + res + end + + def strip_comment(val) + if val.include?("#") && !val.start_with?("#") + val.split("#", 2).first.strip + else + val + end + end + + # for settings' keys + def convert_to_backward_compatible_key!(key) + key << "/" if /https?:/i.match?(key) && !%r{/\Z}.match?(key) + key.gsub!(".", "__") + end + + class << self + private :dump_hash, :convert_to_backward_compatible_key! + end + end +end diff --git a/bin/gems/bundler-4.0.21/CHANGELOG.md b/bin/gems/bundler-4.0.21/CHANGELOG.md new file mode 100644 index 00000000..18bfb4de --- /dev/null +++ b/bin/gems/bundler-4.0.21/CHANGELOG.md @@ -0,0 +1,5784 @@ +# Changelog + +## 4.0.21 / 2026-09-16 + +### Enhancements: + +* Don't update bundler to a prerelease unless asked for one. Pull request [#9869](https://github.com/ruby/rubygems/pull/9869) by Hiroshi SHIBATA +* Reject Bundler redirects that downgrade https to http. Pull request [#9859](https://github.com/ruby/rubygems/pull/9859) by Hiroshi SHIBATA + +### Bug fixes: + +* Support `safe.bareRepository=explicit` in git sources. Pull request [#9876](https://github.com/ruby/rubygems/pull/9876) by Hiroshi SHIBATA +* Stop resolving locally for empty CHECKSUMS entries. Pull request [#9862](https://github.com/ruby/rubygems/pull/9862) by Hiroshi SHIBATA +* Expand the git source gemspec path before the chdir. Pull request [#9845](https://github.com/ruby/rubygems/pull/9845) by Hiroshi SHIBATA + +## 4.0.20 / 2026-09-02 + +### Enhancements: + +* Avoid duplicate relative path prefix in bundle exec. Pull request [#9596](https://github.com/ruby/rubygems/pull/9596) by samuel-williams-shopify +* Follow renamed default branch in git sources. Pull request [#9813](https://github.com/ruby/rubygems/pull/9813) by hsbt +* Bundler::Source::Git: avoid re-fetching the repo. Pull request [#9806](https://github.com/ruby/rubygems/pull/9806) by byroot +* Show the newest out-of-cooldown version in bundle outdated. Pull request [#9803](https://github.com/ruby/rubygems/pull/9803) by hsbt + +### Bug fixes: + +* Error out when `bundle init --gemspec` gets no specification. Pull request [#9818](https://github.com/ruby/rubygems/pull/9818) by hsbt +* Fix relative gemspec paths being expanded twice. Pull request [#9814](https://github.com/ruby/rubygems/pull/9814) by hsbt +* Fix gemspec evaluation under Ruby::Box. Pull request [#9809](https://github.com/ruby/rubygems/pull/9809) by hsbt +* Fix release date extraction for the current changelog header format. Pull request [#9767](https://github.com/ruby/rubygems/pull/9767) by meganemura +* Resolve globbed entries literally in Gem::Util.glob_files_in_dir. Pull request [#9802](https://github.com/ruby/rubygems/pull/9802) by hsbt +* Preserve native extensions during implicit clean. Pull request [#9800](https://github.com/ruby/rubygems/pull/9800) by sjh9714 + +### Documentation: + +* Clarify :path expectations and cross-link platform docs in man pages. Pull request [#9724](https://github.com/ruby/rubygems/pull/9724) by hsbt + +## 4.0.19 / 2026-08-20 + +### Enhancements: + +* Validate the platform field in Gem::Installer#verify_spec. Pull request [#9780](https://github.com/ruby/rubygems/pull/9780) by hsbt +* Restrict UserDefined handling to explicit class set for Gem::SafeMashal. Pull request [#9770](https://github.com/ruby/rubygems/pull/9770) by jackorp +* Filter git command output against the configured URI. Pull request [#9778](https://github.com/ruby/rubygems/pull/9778) by hsbt +* Summarize cooldown-skipped versions at the end of install, update, and lock. Pull request [#9762](https://github.com/ruby/rubygems/pull/9762) by hsbt + +### Bug fixes: + +* Make repeated bundle lock options accumulate. Pull request [#9748](https://github.com/ruby/rubygems/pull/9748) by hsbt +* Fail instead of warning when frozen mode can't update the lockfile. Pull request [#9750](https://github.com/ruby/rubygems/pull/9750) by hsbt +* Fix wrong $LOAD_PATH for gems installed in the same process. Pull request [#9784](https://github.com/ruby/rubygems/pull/9784) by hsbt + +### Documentation: + +* Fix auto-clean default version in bundle config docs. Pull request [#9783](https://github.com/ruby/rubygems/pull/9783) by hsbt +* Correct Bundler 5 default path documentation. Pull request [#9771](https://github.com/ruby/rubygems/pull/9771) by alloutflo + +## 4.0.18 / 2026-08-05 + +### Enhancements: + +* Don't mask install errors when no Gemfile can be located. Pull request [#9757](https://github.com/ruby/rubygems/pull/9757) by hsbt +* Warn when duplicate source declarations conflict on cooldown. Pull request [#9736](https://github.com/ruby/rubygems/pull/9736) by hsbt +* Redact URI userinfo from settings names in Bundler User-Agent. Pull request [#9716](https://github.com/ruby/rubygems/pull/9716) by hsbt +* Validate gem name before building compact index cache paths. Pull request [#9717](https://github.com/ruby/rubygems/pull/9717) by hsbt + +### Bug fixes: + +* Fail `bundle check` when frozen mode needs lockfile changes. Pull request [#9715](https://github.com/ruby/rubygems/pull/9715) by hsbt +* Skip empty checksum values in compact index metadata. Pull request [#9713](https://github.com/ruby/rubygems/pull/9713) by hsbt + +### Security: + +* Add --cooldown flag to bundle lock and bundle cache. Pull request [#9725](https://github.com/ruby/rubygems/pull/9725) by hsbt + +### Documentation: + +* Point bundler.io URLs at guides.rubygems.org. Pull request [#9737](https://github.com/ruby/rubygems/pull/9737) by hsbt +* Document Bundler checksum behavior for default gems. Pull request [#9735](https://github.com/ruby/rubygems/pull/9735) by p-linnane +* List missing subcommands in bundle(1) UTILITIES section. Pull request [#9721](https://github.com/ruby/rubygems/pull/9721) by hsbt +* Document pessimistic operator and eval_gemfile in gemfile(5). Pull request [#9719](https://github.com/ruby/rubygems/pull/9719) by hsbt + +## 4.0.17 / 2026-07-22 + +### Enhancements: + +* Open compact index cache in binary mode when appending. Pull request [#9679](https://github.com/ruby/rubygems/pull/9679) by hsbt + +### Bug fixes: + +* Unquote Gem.ruby when spawning it as a separate argv element. Pull request [#9695](https://github.com/ruby/rubygems/pull/9695) by hsbt +* Escape glob metacharacters in install paths when globbing. Pull request [#9687](https://github.com/ruby/rubygems/pull/9687) by hsbt +* Avoid space-containing absolute path in RUBYOPT. Pull request [#9696](https://github.com/ruby/rubygems/pull/9696) by hsbt +* Preserve the locked Bundler checksum when the gem isn't cached. Pull request [#9658](https://github.com/ruby/rubygems/pull/9658) by rwstauner + +### Documentation: + +* Point Bundler gemspec metadata at the moved docs. Pull request [#9648](https://github.com/ruby/rubygems/pull/9648) by hsbt + +## 4.0.16 / 2026-07-10 + +### Enhancements: + +* Bundler: Fix Bundler::Fetcher for PQC support, adding integration connection tests. Pull request [#9637](https://github.com/ruby/rubygems/pull/9637) by junaruga +* Reuse RubyGems' vendored tsort in Bundler. Pull request [#9647](https://github.com/ruby/rubygems/pull/9647) by hsbt + +### Bug fixes: + +* Initialize the new gem's git repo without a subshell. Pull request [#9670](https://github.com/ruby/rubygems/pull/9670) by hsbt +* Preserve CRLF lockfile line endings on Windows. Pull request [#9669](https://github.com/ruby/rubygems/pull/9669) by hsbt +* Fix the gemspec error snippet on Windows drive-letter paths. Pull request [#9668](https://github.com/ruby/rubygems/pull/9668) by hsbt + +### Documentation: + +* Point Bundler gemspec metadata at the moved docs. Pull request [#9648](https://github.com/ruby/rubygems/pull/9648) by hsbt + +## 4.0.15 / 2026-06-24 + +### Enhancements: + +* Resolve Git LFS files in git sources from the real remote. Pull request [#9632](https://github.com/ruby/rubygems/pull/9632) by hsbt +* Suggest access issues, not only yanking, for missing locked gems. Pull request [#9631](https://github.com/ruby/rubygems/pull/9631) by hsbt +* Implement a make jobserver (continuation of #9210). Pull request [#9625](https://github.com/ruby/rubygems/pull/9625) by hsbt +* Reduce peak memory usage of full index loading and bundle install. Pull request [#9618](https://github.com/ruby/rubygems/pull/9618) by hsbt +* Bump up to rb-sys 0.9.128. Pull request [#9569](https://github.com/ruby/rubygems/pull/9569) by hsbt + +### Bug fixes: + +* Skip the make jobserver on Windows. Pull request [#9630](https://github.com/ruby/rubygems/pull/9630) by hsbt +* Don't require source plugins to be installed to parse a lockfile: 4.0.x. Pull request [#9621](https://github.com/ruby/rubygems/pull/9621) by hsbt +* Exempt lockfile versions from cooldown on every resolution path. Pull request [#9619](https://github.com/ruby/rubygems/pull/9619) by hsbt +* Set `Bundler.settings[:ssl_ca_cert]` to download gems. Pull request [#9610](https://github.com/ruby/rubygems/pull/9610) by junaruga + +## 4.0.14 / 2026-06-10 + +### Bug fixes: + +* Preserve per-source cooldown when converging sources from the lockfile. Pull request [#9601](https://github.com/ruby/rubygems/pull/9601) by bryanwoods +* Don't exclude the locked version from cooldown during bundle update. Pull request [#9599](https://github.com/ruby/rubygems/pull/9599) by hsbt + +## 4.0.13 / 2026-06-03 + +### Enhancements: + +* Do not hard-code permissions for new gem directories during bundle install. Pull request [#9557](https://github.com/ruby/rubygems/pull/9557) by maxfelsher-cgi +* Clear gem specification cache after acquiring process lock. Pull request [#9310](https://github.com/ruby/rubygems/pull/9310) by ngan +* Show release date with bundle outdated. Pull request [#9337](https://github.com/ruby/rubygems/pull/9337) by hsbt + +### Bug fixes: + +* Apply cooldown to locally installed gem versions. Pull request [#9582](https://github.com/ruby/rubygems/pull/9582) by hsbt + +### Security: + +* Add `cooldown` to delay newly published gem. Pull request [#9576](https://github.com/ruby/rubygems/pull/9576) by hsbt + +## 4.0.12 / 2026-05-20 + +### Enhancements: + +* Make `bundle config get` return status 1 when the value is not set. Pull request [#9505](https://github.com/ruby/rubygems/pull/9505) by willnet +* Use Pathname#absolute?. Pull request [#9529](https://github.com/ruby/rubygems/pull/9529) by nobu +* Deprecate parsing non-lockfile content in LockfileParser. Pull request [#9502](https://github.com/ruby/rubygems/pull/9502) by kurotaky +* Print a warning for a potential confusion from the indirect dependencies. Pull request [#5029](https://github.com/ruby/rubygems/pull/5029) by junaruga +* Respect Gemfile bundler setting in `Bundler.setup`. Pull request [#4892](https://github.com/ruby/rubygems/pull/4892) by godfat + +### Bug fixes: + +* Gracefully handle missing checksums in Compact Index. Pull request [#9492](https://github.com/ruby/rubygems/pull/9492) by jneen +* Skip git source exclusion when lockfile cannot backfill. Pull request [#9544](https://github.com/ruby/rubygems/pull/9544) by yahonda +* Fix bundle config gemfile unset behavior. Pull request [#9514](https://github.com/ruby/rubygems/pull/9514) by afurm + +## 4.0.11 / 2026-04-30 + +### Enhancements: + +* Update gem creation guide URL to rubygems.org. Pull request [#9500](https://github.com/ruby/rubygems/pull/9500) by nissyi-gh +* Lock the checksum of Bundler itself in the lockfile. Pull request [#9366](https://github.com/ruby/rubygems/pull/9366) by Edouard-chin + +### Bug fixes: + +* Fix installing gems with native extensions + transitive dependencies. Pull request [#9477](https://github.com/ruby/rubygems/pull/9477) by nicholasdower +* Fix the bundler version not being updated in dev/test lockfile. Pull request [#9463](https://github.com/ruby/rubygems/pull/9463) by Edouard-chin +* Ensure the release CI doesn't break due to the Bundler checksum feature. Pull request [#9436](https://github.com/ruby/rubygems/pull/9436) by Edouard-chin + +### Documentation: + +* Fix formatting for BUNDLE_PREFER_PATCH variable in man page. Pull request [#9474](https://github.com/ruby/rubygems/pull/9474) by toy + +## 4.0.10 / 2026-04-08 + +### Enhancements: + +* Ignore warnings with spec different platforms. Pull request [#8508](https://github.com/ruby/rubygems/pull/8508) by hsbt +* Improve error message when current platform is not in lockfile. Pull request [#9439](https://github.com/ruby/rubygems/pull/9439) by 55728 +* Cache package version selection. Pull request [#9410](https://github.com/ruby/rubygems/pull/9410) by Edouard-chin +* Check happy path first when comparing gem version. Pull request [#9417](https://github.com/ruby/rubygems/pull/9417) by Edouard-chin +* [feature] default_cli_command for config what command bundler runs when no specific command is provided. Pull request [#8886](https://github.com/ruby/rubygems/pull/8886) by jonbarlo +* Introduce a fast path for comparing Gem::Version. Pull request [#9414](https://github.com/ruby/rubygems/pull/9414) by Edouard-chin + +### Bug fixes: + +* Restore rb_sys dependency for Rust. Pull request [#9416](https://github.com/ruby/rubygems/pull/9416) by bangseongbeom + +## 4.0.9 / 2026-03-25 + +### Enhancements: + +* Check the git version only **once** per `bundle install`. Pull request [#9406](https://github.com/ruby/rubygems/pull/9406) by Edouard-chin +* Normalize the number of workers when performing parallel operations. Pull request [#9400](https://github.com/ruby/rubygems/pull/9400) by Edouard-chin +* Add exponential backoff to bundler retries. Pull request [#9163](https://github.com/ruby/rubygems/pull/9163) by ChrisBr +* Introduce a priority queue. Pull request [#9389](https://github.com/ruby/rubygems/pull/9389) by Edouard-chin +* Split the download and install process of a gem. Pull request [#9381](https://github.com/ruby/rubygems/pull/9381) by Edouard-chin + +### Bug fixes: + +* Retry git fetch without --depth for dumb HTTP transport. Pull request [#9405](https://github.com/ruby/rubygems/pull/9405) by hsbt + +## 4.0.8 (2026-03-11) + +### Enhancements: + + - Add a new Bundler config to control how many specs are fetched [#9363](https://github.com/ruby/rubygems/pull/9363) + - Restrict GitHub Actions workflow permissions for newgem [#9361](https://github.com/ruby/rubygems/pull/9361) + +### Bug fixes: + + - Fix plugin new version not registering [#9355](https://github.com/ruby/rubygems/pull/9355) + +## 4.0.7 (2026-02-25) + +### Enhancements: + + - Don't check whether a plugin needs to be installed: [#9328](https://github.com/ruby/rubygems/pull/9328) + - [rust gem] Major improvements for gem scaffolding (rebased) [#8455](https://github.com/ruby/rubygems/pull/8455) + - Fix(bundler): only preload git sources for requested groups [#9234](https://github.com/ruby/rubygems/pull/9234) + - Raise error when gem contains capital letters [#5432](https://github.com/ruby/rubygems/pull/5432) + +### Bug fixes: + + - Fix Bundler crashing when it tries to install plugin: [#9335](https://github.com/ruby/rubygems/pull/9335) + - Run git operations in parallel (take 2): [#9323](https://github.com/ruby/rubygems/pull/9323) + - Add support for help flag in plugin commands [#9263](https://github.com/ruby/rubygems/pull/9263) + +### Documentation: + + - [DOC] Fix link in Bundler [#9315](https://github.com/ruby/rubygems/pull/9315) + +## 4.0.6 (2026-02-05) + +### Bug fixes: + + - Fix gzip cache corruption when recovering from HTTP 416 responses [#9272](https://github.com/ruby/rubygems/pull/9272) + - Fallback git/path sources to default source [#9301](https://github.com/ruby/rubygems/pull/9301) + - Ensure revision is always re-resolved in `git_proxy.rb` [#9294](https://github.com/ruby/rubygems/pull/9294) + +### Documentation: + + - Clarify local gem override docs to require git-sourced gems [#9305](https://github.com/ruby/rubygems/pull/9305) + +## 4.0.5 (2026-01-29) + +### Enhancements: + + - Fix Bundler that re-exec $0 when a `version` is present in the config: [#9249](https://github.com/ruby/rubygems/pull/9249) + +### Bug fixes: + + - Only use parent source with Git and Path sources [#9269](https://github.com/ruby/rubygems/pull/9269) + +## 4.0.4 (2026-01-15) + +### Enhancements: + + - Validate more options for add sub-command [#5905](https://github.com/ruby/rubygems/pull/5905) + - Support Ruby 4.1 [#9219](https://github.com/ruby/rubygems/pull/9219) + +### Bug fixes: + + - Fix dependency source bug in bundler [#9213](https://github.com/ruby/rubygems/pull/9213) + - Retain current bundler version on `bundle clean` [#9221](https://github.com/ruby/rubygems/pull/9221) + +## 4.0.3 (2025-12-23) + +### Enhancements: + + - Fall back to ruby platform gem when precompiled variant is incompatible [#9211](https://github.com/ruby/rubygems/pull/9211) + +## 4.0.2 (2025-12-17) + +### Enhancements: + + - Support single quotes in mise format ruby version [#9183](https://github.com/ruby/rubygems/pull/9183) + - Tweak the Bundler's "X gems now installed message": [#9194](https://github.com/ruby/rubygems/pull/9194) + +### Bug fixes: + + - Allow to show cli_help with `bundler` executable [#9198](https://github.com/ruby/rubygems/pull/9198) + - Allow bundle pristine to work for git gems in the same repo [#9196](https://github.com/ruby/rubygems/pull/9196) + +## 4.0.1 (2025-12-09) + +### Performance: + + - Increase connection pool to allow for up to 70% speed increase on `bundle install` [#9087](https://github.com/ruby/rubygems/pull/9087) + +### Enhancements: + + - Fix the config suggestion in the warning for `$ bundle` [#9164](https://github.com/ruby/rubygems/pull/9164) + - Fix native extension loading in newgem template for RHEL-based systems [#9156](https://github.com/ruby/rubygems/pull/9156) + +### Bug fixes: + + - Fix Bundler removing executables after creating them [#9169](https://github.com/ruby/rubygems/pull/9169) + +## 4.0.0 (2025-12-03) + +### Features: + + - Support bundle install --lockfile option [#9111](https://github.com/ruby/rubygems/pull/9111) + - Add support for lockfile in Gemfile and bundle install --no-lock [#9059](https://github.com/ruby/rubygems/pull/9059) + - Add `--ext=go` to `bundle gem` [#8183](https://github.com/ruby/rubygems/pull/8183) + - Update Bundler::CurrentRuby::ALL_RUBY_VERSIONS [#9058](https://github.com/ruby/rubygems/pull/9058) + - Introduce `bundle list --format=json` [#8728](https://github.com/ruby/rubygems/pull/8728) + +### Performance: + + - Run git operations in parallel to speed things up: [#9100](https://github.com/ruby/rubygems/pull/9100) + - Replace instance method look up in plugin installer [#9094](https://github.com/ruby/rubygems/pull/9094) + - Adjust the API_REQUEST_LIMIT to make less network roundtrip [#9071](https://github.com/ruby/rubygems/pull/9071) + +### Enhancements: + + - Make BUNDLE_LOCKFILE environment variable have precedence over lockfile method in Gemfile [#9146](https://github.com/ruby/rubygems/pull/9146) + - Improve banner message for the default command [#9145](https://github.com/ruby/rubygems/pull/9145) + - Introduce `install_or_cli_help` and use it default `bundle` command [#9136](https://github.com/ruby/rubygems/pull/9136) + - Add go_gem/rake_task for Go native extension gem skeleton [#9105](https://github.com/ruby/rubygems/pull/9105) + - Warn users that `bundle` now display the help: [#9092](https://github.com/ruby/rubygems/pull/9092) + - Use DidYouMean::SpellChecker for gem suggestions in Bundler [#3857](https://github.com/ruby/rubygems/pull/3857) + - Update all vendored libraries to latest version [#9089](https://github.com/ruby/rubygems/pull/9089) + - We don't need to allow some warning now [#9074](https://github.com/ruby/rubygems/pull/9074) + - Support to embedded Pathname [#9056](https://github.com/ruby/rubygems/pull/9056) + - Enforce activation of irb when running with bundle console [#9033](https://github.com/ruby/rubygems/pull/9033) + - Update Magnus version in Rust extension gem template [#9025](https://github.com/ruby/rubygems/pull/9025) + - Add checksum of gems hosted on private servers: [#9004](https://github.com/ruby/rubygems/pull/9004) + - Loading support on Windows [#8254](https://github.com/ruby/rubygems/pull/8254) + - Improve error message when the same source is specified through `gemspec` and `path` [#8460](https://github.com/ruby/rubygems/pull/8460) + - Raise an error in frozen mode if some registry gems have empty checksums [#8888](https://github.com/ruby/rubygems/pull/8888) + - Bump vendored thor to 1.4.0 [#8883](https://github.com/ruby/rubygems/pull/8883) + - Delay default path and global cache changes to Bundler 5 [#8867](https://github.com/ruby/rubygems/pull/8867) + - Fix spacing in bundle gem newgem.gemspec.tt [#8865](https://github.com/ruby/rubygems/pull/8865) + - Add some missing deprecation messages [#8844](https://github.com/ruby/rubygems/pull/8844) + +### Bug fixes: + + - Fixed checksums generation issue when no source is specified [#9133](https://github.com/ruby/rubygems/pull/9133) + - Check for file existence before deletion from cache [#9095](https://github.com/ruby/rubygems/pull/9095) + - Use method_defined?(:method, false) [#9098](https://github.com/ruby/rubygems/pull/9098) + - Handle BUNDLER_VERSION being set to an empty string [#6928](https://github.com/ruby/rubygems/pull/6928) + - Fix `bundle install` when the Gemfile contains "install_if" git gems: [#8992](https://github.com/ruby/rubygems/pull/8992) + - Fix installation issue related to path sources and precompiled gems [#8973](https://github.com/ruby/rubygems/pull/8973) + - Fix outdated lockfile during `bundle lock` when source changes [#8962](https://github.com/ruby/rubygems/pull/8962) + - Raise error on missing version file [#8963](https://github.com/ruby/rubygems/pull/8963) + - Fix `bundle cache --frozen` and `bundle cache --no-prune` not printing a deprecation message [#8926](https://github.com/ruby/rubygems/pull/8926) + - Fix local installation incorrectly forced if there's a `vendor/cache` directory and frozen mode is set [#8925](https://github.com/ruby/rubygems/pull/8925) + - Fix `bundle lock --update ` with `--lockfile` flag updating all gems [#8922](https://github.com/ruby/rubygems/pull/8922) + - Fix `bundle show --verbose` and recommend it as an alternative to `bundle show --outdated` [#8915](https://github.com/ruby/rubygems/pull/8915) + - Fix `bundle cache --no-all` not printing a deprecation warning [#8912](https://github.com/ruby/rubygems/pull/8912) + - Fix `bundle update foo` unable to update foo in an edge case [#8897](https://github.com/ruby/rubygems/pull/8897) + - Fix Bundler printing more flags than actually passed in verbose mode [#8914](https://github.com/ruby/rubygems/pull/8914) + - Fix bundler failing to install sorbet-static in truffleruby when there's no lockfile [#8872](https://github.com/ruby/rubygems/pull/8872) + - Cancel deprecation of `--force` flag to `bundle install` and `bundle update` [#8843](https://github.com/ruby/rubygems/pull/8843) + +### Security: + + - Bump up vendored URI to 1.0.4 [#9031](https://github.com/ruby/rubygems/pull/9031) + +### Breaking changes: + + - Fix triple spacing when generating lockfile [#9076](https://github.com/ruby/rubygems/pull/9076) + - Hide patchlevel from lockfile [#7772](https://github.com/ruby/rubygems/pull/7772) + - Remove `bundler_4_mode` [#9038](https://github.com/ruby/rubygems/pull/9038) + - Pick and add extra changes for 4.0.0 version [#9018](https://github.com/ruby/rubygems/pull/9018) + - Replaced Bundler::SharedHelpers.major_deprecation to feature_removed! or feature_deprecated! [#9016](https://github.com/ruby/rubygems/pull/9016) + - Removed legacy_check option from SpecSet#for [#9015](https://github.com/ruby/rubygems/pull/9015) + - Make update_requires_all_flag to settings [#9011](https://github.com/ruby/rubygems/pull/9011) + - Make default cli command settings [#9010](https://github.com/ruby/rubygems/pull/9010) + - Make global_gem_cache flag to settings [#9009](https://github.com/ruby/rubygems/pull/9009) + - Consolidate removal of `Bundler.rubygems.all_specs` [#9008](https://github.com/ruby/rubygems/pull/9008) + - Consolidate removal of `Bundler::SpecSet#-` and `Bundler::SpecSet#<<` [#9007](https://github.com/ruby/rubygems/pull/9007) + - Replaced Bundler.feature_flag.plugins? to Bundler.settings [#9006](https://github.com/ruby/rubygems/pull/9006) + - Make `bundle show --outdated` raise an error [#8980](https://github.com/ruby/rubygems/pull/8980) + - Make `--local-git` flag to `bundle plugin install` raise an error [#8979](https://github.com/ruby/rubygems/pull/8979) + - Switch `cache_all` to be `true` by default [#8975](https://github.com/ruby/rubygems/pull/8975) + - Completely forbid passing `--ext` to `bundle gem` without a value [#8976](https://github.com/ruby/rubygems/pull/8976) + - Switch `lockfile_checksums` to be `true` by default [#8981](https://github.com/ruby/rubygems/pull/8981) + - Make `bundle install --binstubs` raise an error [#8978](https://github.com/ruby/rubygems/pull/8978) + - Make `bundle remove --install` raise an error [#8977](https://github.com/ruby/rubygems/pull/8977) + - Remove support for multiple global sources in Gemfile & lockfile [#8968](https://github.com/ruby/rubygems/pull/8968) + - Remove `allow_offline_install` setting [#8969](https://github.com/ruby/rubygems/pull/8969) + - Completely remove `--rubocop` flag to `bundle gem`, and related configuration [#8967](https://github.com/ruby/rubygems/pull/8967) + - Completely remove all remembered CLI flags [#8958](https://github.com/ruby/rubygems/pull/8958) + - Remove implementation of `deployment`, `capistrano` and `vlad` entrypoints [#8957](https://github.com/ruby/rubygems/pull/8957) + - Remove deprecated `Bundler.*clean*`, and `Bundler.environment` helpers [#8924](https://github.com/ruby/rubygems/pull/8924) + - Remove deprecated `bundle viz` and `bundle inject` commands [#8923](https://github.com/ruby/rubygems/pull/8923) + - Removed to workaround for Bundler 2.2 [#8903](https://github.com/ruby/rubygems/pull/8903) + +### Documentation: + + - Unified UPGRADING.md and extract blog.rubygems.org [#9148](https://github.com/ruby/rubygems/pull/9148) + - Remove italic formatting from changelog section headers [#9128](https://github.com/ruby/rubygems/pull/9128) + - Small clarifications to Bundler 4 upgrade docs [#8964](https://github.com/ruby/rubygems/pull/8964) + - Improve documentation of `bundle doctor`, `bundle plugin`, and `bundle config` [#8919](https://github.com/ruby/rubygems/pull/8919) + - Make sure all CLI flags and subcommands are documented [#8861](https://github.com/ruby/rubygems/pull/8861) + - Clarify documentation about new default gem installation directory in Bundler 4 [#8857](https://github.com/ruby/rubygems/pull/8857) + - Use mailto link in Code of Conduct [#8849](https://github.com/ruby/rubygems/pull/8849) + - Update Code of Conduct email to conduct@rubygems.org [#8848](https://github.com/ruby/rubygems/pull/8848) + - Add missing link to `irb` repo in DEBUGGING.md [#8842](https://github.com/ruby/rubygems/pull/8842) + +## 2.7.2 (2025-09-09) + +### Enhancements: + + - Improve error message when the same source is specified through `gemspec` and `path` [#8460](https://github.com/ruby/rubygems/pull/8460) + - Raise an error in frozen mode if some registry gems have empty checksums [#8888](https://github.com/ruby/rubygems/pull/8888) + - Bump vendored thor to 1.4.0 [#8883](https://github.com/ruby/rubygems/pull/8883) + - Delay default path and global cache changes to Bundler 5 [#8867](https://github.com/ruby/rubygems/pull/8867) + - Fix spacing in bundle gem newgem.gemspec.tt [#8865](https://github.com/ruby/rubygems/pull/8865) + +### Bug fixes: + + - Fix `bundle cache --frozen` and `bundle cache --no-prune` not printing a deprecation message [#8926](https://github.com/ruby/rubygems/pull/8926) + - Fix local installation incorrectly forced if there's a `vendor/cache` directory and frozen mode is set [#8925](https://github.com/ruby/rubygems/pull/8925) + - Fix `bundle lock --update ` with `--lockfile` flag updating all gems [#8922](https://github.com/ruby/rubygems/pull/8922) + - Fix `bundle show --verbose` and recommend it as an alternative to `bundle show --outdated` [#8915](https://github.com/ruby/rubygems/pull/8915) + - Fix `bundle cache --no-all` not printing a deprecation warning [#8912](https://github.com/ruby/rubygems/pull/8912) + - Fix `bundle update foo` unable to update foo in an edge case [#8897](https://github.com/ruby/rubygems/pull/8897) + - Fix Bundler printing more flags than actually passed in verbose mode [#8914](https://github.com/ruby/rubygems/pull/8914) + - Fix bundler failing to install sorbet-static in truffleruby when there's no lockfile [#8872](https://github.com/ruby/rubygems/pull/8872) + +### Documentation: + + - Improve documentation of `bundle doctor`, `bundle plugin`, and `bundle config` [#8919](https://github.com/ruby/rubygems/pull/8919) + - Make sure all CLI flags and subcommands are documented [#8861](https://github.com/ruby/rubygems/pull/8861) + +## 2.7.1 (2025-07-21) + +### Enhancements: + + - Add some missing deprecation messages [#8844](https://github.com/ruby/rubygems/pull/8844) + +### Bug fixes: + + - Cancel deprecation of `--force` flag to `bundle install` and `bundle update` [#8843](https://github.com/ruby/rubygems/pull/8843) + +### Documentation: + + - Clarify documentation about new default gem installation directory in Bundler 4 [#8857](https://github.com/ruby/rubygems/pull/8857) + - Use mailto link in Code of Conduct [#8849](https://github.com/ruby/rubygems/pull/8849) + - Update Code of Conduct email to conduct@rubygems.org [#8848](https://github.com/ruby/rubygems/pull/8848) + - Add missing link to `irb` repo in DEBUGGING.md [#8842](https://github.com/ruby/rubygems/pull/8842) + +## 2.7.0 (2025-07-16) + +### Breaking changes: + + - Stop allowing calling `#gem` on random objects [#8819](https://github.com/ruby/rubygems/pull/8819) + - Remove `path_relative_to_cwd` setting [#8815](https://github.com/ruby/rubygems/pull/8815) + - Remove the `default_install_uses_path` and `auto_clean_without_path` settings [#8814](https://github.com/ruby/rubygems/pull/8814) + - Remove `print_only_version_number` setting [#8799](https://github.com/ruby/rubygems/pull/8799) + - Drop support for Ruby 3.1 [#8634](https://github.com/ruby/rubygems/pull/8634) + - Raise an error if incompatible or merge if compatible when a gemspec development dep is duplicated in Gemfile [#8556](https://github.com/ruby/rubygems/pull/8556) + - Remove MD5 digesting of compact index responses [#8530](https://github.com/ruby/rubygems/pull/8530) + - Stop generating binstubs for Bundler itself [#8345](https://github.com/ruby/rubygems/pull/8345) + +### Deprecations: + + - Deprecate unused `Bundler::SpecSet` methods [#8777](https://github.com/ruby/rubygems/pull/8777) + - Deprecate `x64-mingw32` in favour of `x64-mingw-ucrt` [#8733](https://github.com/ruby/rubygems/pull/8733) + - Deprecate legacy windows platforms (`:mswin`, `:mingw`) in Gemfile DSL in favor of `:windows` [#8447](https://github.com/ruby/rubygems/pull/8447) + - Deprecate `CurrentRuby#maglev?` and other related maglev methods [#8452](https://github.com/ruby/rubygems/pull/8452) + +### Features: + + - Allow simulating "Bundler 4 mode" more easily [#6472](https://github.com/ruby/rubygems/pull/6472) + +### Performance: + + - Cache git sources with commit SHA refs [#8741](https://github.com/ruby/rubygems/pull/8741) + +### Enhancements: + + - Load RubyGems extensions in the first place [#8835](https://github.com/ruby/rubygems/pull/8835) + - Update gemspec based on provided github username when exists [#8790](https://github.com/ruby/rubygems/pull/8790) + - Fail fast when connection errors happen [#8784](https://github.com/ruby/rubygems/pull/8784) + - Introduce a `verbose` setting to enable verbose output for all commands [#8801](https://github.com/ruby/rubygems/pull/8801) + - Introduce `gem.bundle` setting to run `bundle install` automatically after `bundle gem`, and make it the default [#8671](https://github.com/ruby/rubygems/pull/8671) + - Handle `Errno::EADDRNOTAVAIL` errors gracefully [#8776](https://github.com/ruby/rubygems/pull/8776) + - Use `persist-credentials: false` in workflow generated by `bundle gem` [#8779](https://github.com/ruby/rubygems/pull/8779) + - Recognize JRuby loaded from a classloader, not just any JAR [#8567](https://github.com/ruby/rubygems/pull/8567) + - Validate lockfile dependencies with bundle install [#8666](https://github.com/ruby/rubygems/pull/8666) + - Ignore local specifications if they have incorrect dependencies [#8647](https://github.com/ruby/rubygems/pull/8647) + - Move most of `Bundler::GemHelpers` to `Gem::Platform` [#8703](https://github.com/ruby/rubygems/pull/8703) + - Improve `spec.files` in the `.gemspec` template [#8732](https://github.com/ruby/rubygems/pull/8732) + +### Bug fixes: + + - Fix double `bundle gem` prompts [#8825](https://github.com/ruby/rubygems/pull/8825) + - Fix date displayed in `bundle version` help text [#8806](https://github.com/ruby/rubygems/pull/8806) + - Fix `bundle console` printing bug report template on `NameError` during require [#8804](https://github.com/ruby/rubygems/pull/8804) + - Fix `Bundler.original_env['GEM_HOME']` when Bundler is trampolined [#8781](https://github.com/ruby/rubygems/pull/8781) + - Fix rdoc issues when running `gem` commands in a `bundle exec` context [#8770](https://github.com/ruby/rubygems/pull/8770) + - Never ignore gems from path sources during activation [#8766](https://github.com/ruby/rubygems/pull/8766) + - Fix `bundle install` after pinning a git source with subgems [#8745](https://github.com/ruby/rubygems/pull/8745) + - Let `bundle update --bundler` upgrade bundler even if restarts are disabled [#8729](https://github.com/ruby/rubygems/pull/8729) + +### Documentation: + + - Rewrite and complete UPGRADING document [#8817](https://github.com/ruby/rubygems/pull/8817) + - Document that `global_gem_cache` also caches compiled extensions [#8823](https://github.com/ruby/rubygems/pull/8823) + - Add `default_cli_command` documentation [#8816](https://github.com/ruby/rubygems/pull/8816) + - Add a root CONTRIBUTING.md file [#8822](https://github.com/ruby/rubygems/pull/8822) + - Add a SECURITY.md file [#8812](https://github.com/ruby/rubygems/pull/8812) + - Update man pages for the `bundle doctor ssl` subcommand [#8803](https://github.com/ruby/rubygems/pull/8803) + - Remove duplicate documentation for `--changelog` flag [#8756](https://github.com/ruby/rubygems/pull/8756) + - Fix typos making some lists in documentation render incorrectly [#8759](https://github.com/ruby/rubygems/pull/8759) + - Fix heading ranks in documentation [#8711](https://github.com/ruby/rubygems/pull/8711) + - Clarify differences between `frozen` and `deployment` settings, and other bundle-config documentation improvements [#8715](https://github.com/ruby/rubygems/pull/8715) + +## 2.6.9 (2025-05-13) + +### Enhancements: + + - Fix doctor command parsing of otool output [#8665](https://github.com/ruby/rubygems/pull/8665) + - Add SSL troubleshooting to `bundle doctor` [#8624](https://github.com/ruby/rubygems/pull/8624) + - Let `bundle lock --normalize-platforms` remove invalid platforms [#8631](https://github.com/ruby/rubygems/pull/8631) + +### Bug fixes: + + - Fix `bundle lock` sometimes allowing invalid platforms into the lockfile [#8630](https://github.com/ruby/rubygems/pull/8630) + - Fix false positive warning about insecure materialization in frozen mode [#8629](https://github.com/ruby/rubygems/pull/8629) + +## 2.6.8 (2025-04-13) + +### Enhancements: + + - Refine `bundle update --verbose` logs [#8627](https://github.com/ruby/rubygems/pull/8627) + - Improve bug report instructions [#8607](https://github.com/ruby/rubygems/pull/8607) + +### Bug fixes: + + - Fix `bundle update` crash in an edge case [#8626](https://github.com/ruby/rubygems/pull/8626) + - Fix `bundle lock --normalize-platforms` regression [#8620](https://github.com/ruby/rubygems/pull/8620) + +## 2.6.7 (2025-04-03) + +### Enhancements: + + - Fix crash when server compact index API implementation only lists versions [#8594](https://github.com/ruby/rubygems/pull/8594) + - Fix lockfile when a gem ends up accidentally under two different sources [#8579](https://github.com/ruby/rubygems/pull/8579) + - Refuse to install and print an error in frozen mode if some entries are missing in CHECKSUMS lockfile section [#8563](https://github.com/ruby/rubygems/pull/8563) + - Support git 2.49 [#8581](https://github.com/ruby/rubygems/pull/8581) + - Improve wording of a few messages [#8570](https://github.com/ruby/rubygems/pull/8570) + +### Bug fixes: + + - Fix `bundle add` sometimes generating invalid lockfiles [#8586](https://github.com/ruby/rubygems/pull/8586) + +### Performance: + + - Implement pub_grub strategy interface [#8589](https://github.com/ruby/rubygems/pull/8589) + - Update vendored pub_grub [#8571](https://github.com/ruby/rubygems/pull/8571) + +## 2.6.6 (2025-03-13) + +### Enhancements: + + - Fix `ENAMETOOLONG` error when creating compact index cache [#5578](https://github.com/ruby/rubygems/pull/5578) + - Use shorthand hash syntax for bundle add [#8547](https://github.com/ruby/rubygems/pull/8547) + - Update vendored uri to 1.0.3 [#8534](https://github.com/ruby/rubygems/pull/8534) + - Retry gracefully on blank partial response in compact index [#8524](https://github.com/ruby/rubygems/pull/8524) + - Give a better error when trying to write the lock file on a read-only filesystem [#5920](https://github.com/ruby/rubygems/pull/5920) + - Improve log messages when lockfile platforms are added [#8523](https://github.com/ruby/rubygems/pull/8523) + - Allow noop `bundle install` to work on read-only or protected folders [#8519](https://github.com/ruby/rubygems/pull/8519) + +### Bug fixes: + + - Detect partial gem installs from a git source so that they are reinstalled on a successive run [#8539](https://github.com/ruby/rubygems/pull/8539) + - Modify `bundle doctor` to not report issue when files aren't writable [#8520](https://github.com/ruby/rubygems/pull/8520) + +### Performance: + + - Optimize resolution by removing an array allocation from `Candidate#<=>` [#8559](https://github.com/ruby/rubygems/pull/8559) + +### Documentation: + + - Update docs for with/without consistency [#8555](https://github.com/ruby/rubygems/pull/8555) + - Recommend non-deprecated methods in `bundle exec` documentation [#8537](https://github.com/ruby/rubygems/pull/8537) + - Hint about default group when using `only` configuration option [#8536](https://github.com/ruby/rubygems/pull/8536) + +## 2.6.5 (2025-02-20) + +### Enhancements: + + - Fix lockfile platforms inconveniently added on JRuby [#8494](https://github.com/ruby/rubygems/pull/8494) + +### Bug fixes: + + - Fix resolver issue due to ill-defined version ranges being created [#8503](https://github.com/ruby/rubygems/pull/8503) + - Make sure empty gems are not reinstalled every time [#8502](https://github.com/ruby/rubygems/pull/8502) + +## 2.6.4 (2025-02-17) + +### Enhancements: + + - Make Bundler never instantiate development dependencies [#8486](https://github.com/ruby/rubygems/pull/8486) + - Fix some invalid options to `gem` DSL not getting reported as invalid [#8480](https://github.com/ruby/rubygems/pull/8480) + - Add `irb` to a Gemfile for a newly created gem [#8467](https://github.com/ruby/rubygems/pull/8467) + - Auto-heal empty installation directory [#8457](https://github.com/ruby/rubygems/pull/8457) + - Fix `bundle console` unnecessarily trying to load IRB twice [#8443](https://github.com/ruby/rubygems/pull/8443) + - Add ruby_34 and ruby_35 as valid platform: [#8430](https://github.com/ruby/rubygems/pull/8430) + - Consider gems under `platform: :windows` filter in Gemfile when running on Windows with ARM architecture [#8428](https://github.com/ruby/rubygems/pull/8428) + +### Bug fixes: + + - Fix regression when running `bundle update ` would sometimes downgrade a top level dependency [#8491](https://github.com/ruby/rubygems/pull/8491) + - Fix dependency locking when Bundler finds incorrect lockfile dependencies [#8489](https://github.com/ruby/rubygems/pull/8489) + - Raise error when lockfile is missing deps in frozen mode [#8483](https://github.com/ruby/rubygems/pull/8483) + - Fix `bundle install --prefer-local` sometimes installing very old versions [#8484](https://github.com/ruby/rubygems/pull/8484) + - Fix incorrect error message when running `bundle update` in frozen mode [#8481](https://github.com/ruby/rubygems/pull/8481) + - Keep platform variants in `vendor/cache` even if incompatible with the current Ruby version [#8471](https://github.com/ruby/rubygems/pull/8471) + - Fix `bundle console` printing bug report template incorrectly [#8436](https://github.com/ruby/rubygems/pull/8436) + - Fix `--prefer-local` not respecting default gems [#8412](https://github.com/ruby/rubygems/pull/8412) + +### Performance: + + - Improve resolution performance [#8458](https://github.com/ruby/rubygems/pull/8458) + +### Documentation: + + - Fix more broken links [#8416](https://github.com/ruby/rubygems/pull/8416) + +## 2.6.3 (2025-01-16) + +### Enhancements: + + - Don't fallback to evaluating YAML gemspecs as Ruby code [#8404](https://github.com/ruby/rubygems/pull/8404) + - Print message when blocking on file locks [#8299](https://github.com/ruby/rubygems/pull/8299) + - Add support for mise version manager file [#8356](https://github.com/ruby/rubygems/pull/8356) + - Add Ruby 3.5 to Gemfile DSL platform values [#8365](https://github.com/ruby/rubygems/pull/8365) + +### Bug fixes: + + - Revert RubyGems plugins getting loaded on `Bundler.require` [#8410](https://github.com/ruby/rubygems/pull/8410) + - Fix platform specific gems sometimes being removed from the lockfile [#8401](https://github.com/ruby/rubygems/pull/8401) + - Serialize gemspec when caching git source [#8403](https://github.com/ruby/rubygems/pull/8403) + - Fix crash on read-only filesystems in Ruby 3.4 [#8372](https://github.com/ruby/rubygems/pull/8372) + - Fix `bundle outdated ` failing if not all gems are installed [#8361](https://github.com/ruby/rubygems/pull/8361) + - Fix `bundle install` crash on Windows [#8362](https://github.com/ruby/rubygems/pull/8362) + +### Documentation: + + - Fix broken links in the documents [#8389](https://github.com/ruby/rubygems/pull/8389) + +## 2.6.2 (2024-12-23) + +### Bug fixes: + + - Restart using `Process.argv0` only if `$PROGRAM_NAME` is not a script [#8343](https://github.com/ruby/rubygems/pull/8343) + +### Documentation: + + - Fix typo in `bundle lock` man page synopsis (`--add-checkums` → `--add-checksums`) [#8350](https://github.com/ruby/rubygems/pull/8350) + +## 2.6.1 (2024-12-17) + +### Bug fixes: + + - Fix missing `Gem::Uri.redact` on some Ruby 3.1 versions [#8337](https://github.com/ruby/rubygems/pull/8337) + - Fix `bundle lock --add-checksums` when gems are already installed [#8326](https://github.com/ruby/rubygems/pull/8326) + +## 2.6.0 (2024-12-16) + +### Security: + + - Fix gemfury credentials written to logs in verbose mode [#8283](https://github.com/ruby/rubygems/pull/8283) + - Fix private registry credentials being written to logs [#8222](https://github.com/ruby/rubygems/pull/8222) + +### Breaking changes: + + - Drop ruby 3.0 support [#8091](https://github.com/ruby/rubygems/pull/8091) + - Remove client-side MD5 ETag transition from compact index client [#7677](https://github.com/ruby/rubygems/pull/7677) + +### Deprecations: + + - Cancel `bundle console` deprecation [#8218](https://github.com/ruby/rubygems/pull/8218) + - Warn when platform of installed gem differs from platform in the lockfile [#8029](https://github.com/ruby/rubygems/pull/8029) + - Cancel deprecation of Gemfiles without a global source [#8213](https://github.com/ruby/rubygems/pull/8213) + +### Features: + + - Add a `lockfile_checksums` configuration to include checksums in fresh lockfiles [#8219](https://github.com/ruby/rubygems/pull/8219) + - Add `bundle lock --add-checksums` to add checksums to an existing lockfile [#8214](https://github.com/ruby/rubygems/pull/8214) + +### Performance: + + - Enable a couple of performance cops [#8261](https://github.com/ruby/rubygems/pull/8261) + - Remove override of worker jobs for `bundle install --local` [#8248](https://github.com/ruby/rubygems/pull/8248) + +### Enhancements: + + - Support `bundle exec ` when `Kernel.exec` is used under the hood [#8294](https://github.com/ruby/rubygems/pull/8294) + - Improve working with different rubies using the same lockfile [#8251](https://github.com/ruby/rubygems/pull/8251) + - Define a few `inspect` methods to help debugging [#8266](https://github.com/ruby/rubygems/pull/8266) + - Include original error when openssl fails to load [#8232](https://github.com/ruby/rubygems/pull/8232) + - Automatically fix lockfile when it's missing dependencies [#8103](https://github.com/ruby/rubygems/pull/8103) + - Fix some JRuby warnings when using `bundler/setup` with Ruby's -w flag [#8205](https://github.com/ruby/rubygems/pull/8205) + - Add a `--normalize-platforms` flag to `bundle lock` [#7896](https://github.com/ruby/rubygems/pull/7896) + - Add plugin hooks for Bundler.require [#3439](https://github.com/ruby/rubygems/pull/3439) + +### Bug fixes: + + - Fix restarting with locked version when `$PROGRAM_NAME` has been changed [#8320](https://github.com/ruby/rubygems/pull/8320) + - Restore the previous cache format for git sources [#8296](https://github.com/ruby/rubygems/pull/8296) + - Fix installs of subdependencies of unlocked dependencies to be conservative [#8281](https://github.com/ruby/rubygems/pull/8281) + - Fix test task name on generated readme when using test-unit [#8291](https://github.com/ruby/rubygems/pull/8291) + - Fix `bundle exec` executable detection on windows [#8276](https://github.com/ruby/rubygems/pull/8276) + - Fix `bundle remove` sometimes not removing gems [#8278](https://github.com/ruby/rubygems/pull/8278) + - Fix issue with git gems locking incorrect specs sometimes [#8269](https://github.com/ruby/rubygems/pull/8269) + +### Documentation: + + - Normalize command flag documentation and make sure all flags are documented [#8313](https://github.com/ruby/rubygems/pull/8313) + - Add missing man pages for `bundle env` and `bundle licenses` [#8315](https://github.com/ruby/rubygems/pull/8315) + - Add man page for 'bundle issue' command [#8271](https://github.com/ruby/rubygems/pull/8271) + - Add man page for 'bundle fund' command [#8258](https://github.com/ruby/rubygems/pull/8258) + - Move pry-related contents to `debugging.md` [#8263](https://github.com/ruby/rubygems/pull/8263) + - Add debugging instruction on Windows [#8236](https://github.com/ruby/rubygems/pull/8236) + - Unify rubygems and bundler docs directory [#8159](https://github.com/ruby/rubygems/pull/8159) + +## 2.5.23 (2024-11-05) + +### Enhancements: + + - Add useful error message for plugin load [#7639](https://github.com/ruby/rubygems/pull/7639) + - Indent github workflow steps for generated gems [#8193](https://github.com/ruby/rubygems/pull/8193) + - Improve several permission errors [#8168](https://github.com/ruby/rubygems/pull/8168) + - Add `bundle add` `--quiet` option [#8157](https://github.com/ruby/rubygems/pull/8157) + +### Bug fixes: + + - Fix incompatible encodings error when paths with UTF-8 characters are involved [#8196](https://github.com/ruby/rubygems/pull/8196) + - Update `--ext=rust` to support compiling the native extension from source [#7610](https://github.com/ruby/rubygems/pull/7610) + - Print a proper error when there's a previous empty installation path with bad permissions [#8169](https://github.com/ruby/rubygems/pull/8169) + - Fix running `bundler` (with a final `r`) in a `bundle exec` context [#8165](https://github.com/ruby/rubygems/pull/8165) + - Handle two `gemspec` usages in same Gemfile with same dep and compatible requirements [#7999](https://github.com/ruby/rubygems/pull/7999) + - Fix `bundle check` sometimes locking gems under the wrong source [#8148](https://github.com/ruby/rubygems/pull/8148) + +### Documentation: + + - Remove confusing `bundle config` documentation [#8177](https://github.com/ruby/rubygems/pull/8177) + - Rename bundler inline's `install` parameter and clarify docs [#8170](https://github.com/ruby/rubygems/pull/8170) + - Clarify `bundle install --quiet` documentation [#8163](https://github.com/ruby/rubygems/pull/8163) + +## 2.5.22 (2024-10-16) + +### Enhancements: + + - Update vendored `uri` and `net-http` [#8112](https://github.com/ruby/rubygems/pull/8112) + +### Bug fixes: + + - Fix bundler sometimes crashing because of trying to use a version of psych compiled for a different Ruby [#8104](https://github.com/ruby/rubygems/pull/8104) + +## 2.5.21 (2024-10-03) + +### Bug fixes: + + - Fix bug report template printed when changing a path source to a git source in frozen mode [#8079](https://github.com/ruby/rubygems/pull/8079) + - Fix `stub.activated?` sometimes returning false after activation under bundler [#8073](https://github.com/ruby/rubygems/pull/8073) + - Fix old cache format detection when application is not source controlled [#8076](https://github.com/ruby/rubygems/pull/8076) + - Fix `bundler/inline` resetting ENV changes [#8059](https://github.com/ruby/rubygems/pull/8059) + +## 2.5.20 (2024-09-24) + +### Enhancements: + + - Don't try to auto-install dev versions of Bundler not available remotely [#8045](https://github.com/ruby/rubygems/pull/8045) + - Don't try to install locked bundler when `--local` is passed [#8041](https://github.com/ruby/rubygems/pull/8041) + +### Bug fixes: + + - Fix `bundler/inline` overwriting lockfiles [#8055](https://github.com/ruby/rubygems/pull/8055) + - Ensure refs directory in cached git source [#8047](https://github.com/ruby/rubygems/pull/8047) + - Fix `bundle outdated` with `--group` option [#8052](https://github.com/ruby/rubygems/pull/8052) + +## 2.5.19 (2024-09-18) + +### Enhancements: + + - Raise original errors when unexpected errors happen during Gemfile evaluation [#8003](https://github.com/ruby/rubygems/pull/8003) + - Make an exe file executable when generating new gems [#8020](https://github.com/ruby/rubygems/pull/8020) + - Gracefully handle gem activation conflicts in inline mode [#5535](https://github.com/ruby/rubygems/pull/5535) + - Don't include hook templates in cached git source [#8013](https://github.com/ruby/rubygems/pull/8013) + - Fix some errors about a previous installation folder that's unsafe to remove, when there's no need to remove it [#7985](https://github.com/ruby/rubygems/pull/7985) + - Emit progress to stderr during `bundle outdated --parseable` [#7966](https://github.com/ruby/rubygems/pull/7966) + - Reject unknown platforms when running `bundle lock --add-platform` [#7967](https://github.com/ruby/rubygems/pull/7967) + - Emit progress to stderr when `--print` is passed to `bundle lock` [#7957](https://github.com/ruby/rubygems/pull/7957) + +### Bug fixes: + + - Fix `bundle install --local` hitting the network when default gems are included [#8027](https://github.com/ruby/rubygems/pull/8027) + - Remove temporary `.lock` files unintentionally left around by gem installer [#8022](https://github.com/ruby/rubygems/pull/8022) + - Fix `bundle exec rake install` failing when local gem has extensions [#7977](https://github.com/ruby/rubygems/pull/7977) + - Load gemspecs in the context of its parent also when using local overrides [#7993](https://github.com/ruby/rubygems/pull/7993) + - Fix `bundler/inline` failing in Ruby 3.2 due to conflicting `securerandom` versions [#7984](https://github.com/ruby/rubygems/pull/7984) + - Don't blow up when explicit version is removed from some git sources [#7973](https://github.com/ruby/rubygems/pull/7973) + - Fix `gem exec rails new project` failing on Ruby 3.2 [#7960](https://github.com/ruby/rubygems/pull/7960) + +### Documentation: + + - Improve `bundle add` man page [#5903](https://github.com/ruby/rubygems/pull/5903) + - Add some documentation about backwards compatibility [#7964](https://github.com/ruby/rubygems/pull/7964) + +## 2.5.18 (2024-08-26) + +### Enhancements: + + - Don't remove existing platform gems when PLATFORMS section is badly indented [#7916](https://github.com/ruby/rubygems/pull/7916) + +### Bug fixes: + + - Fix error message when Bundler refuses to install due to frozen being set without a lockfile [#7955](https://github.com/ruby/rubygems/pull/7955) + - Fix several issues with the `--prefer-local` flag [#7951](https://github.com/ruby/rubygems/pull/7951) + - Restore support for passing relative paths to `git:` sources [#7950](https://github.com/ruby/rubygems/pull/7950) + - Regenerate previous git application caches that didn't include bare repos [#7926](https://github.com/ruby/rubygems/pull/7926) + - Fix `bundle update ` failing to upgrade when versions present in two different sources [#7915](https://github.com/ruby/rubygems/pull/7915) + +### Documentation: + + - Change new gem README template to have copyable code blocks [#7935](https://github.com/ruby/rubygems/pull/7935) + +## 2.5.17 (2024-08-01) + +### Enhancements: + + - Print better log message when current platform is not present in the lockfile [#7891](https://github.com/ruby/rubygems/pull/7891) + - Explicitly encode `Gem::Dependency` to yaml [#7867](https://github.com/ruby/rubygems/pull/7867) + - Enable lockfile checksums on future Bundler 3 when there's no previous lockfile [#7805](https://github.com/ruby/rubygems/pull/7805) + +### Bug fixes: + + - Fix truffleruby removing gems from lockfile [#7795](https://github.com/ruby/rubygems/pull/7795) + - Fix `bundle check` exit code when gem git source is not checked out [#7894](https://github.com/ruby/rubygems/pull/7894) + - Generate gems.rb from Gemfile.tt template for `bundle-gem` [#7853](https://github.com/ruby/rubygems/pull/7853) + - Fix git source cache being used as the install location [#4469](https://github.com/ruby/rubygems/pull/4469) + - Fix `bundle exec gem uninstall` [#7886](https://github.com/ruby/rubygems/pull/7886) + +## 2.5.16 (2024-07-18) + +### Bug fixes: + + - Fix platform removal regression when `platforms:` used in the Gemfile [#7864](https://github.com/ruby/rubygems/pull/7864) + - Fix standalone script when default gems with extensions are used [#7870](https://github.com/ruby/rubygems/pull/7870) + - Fix another case of `bundle lock --add-platform` doing nothing [#7848](https://github.com/ruby/rubygems/pull/7848) + - Fix bad error messages when using `bundle add` with frozen mode set [#7845](https://github.com/ruby/rubygems/pull/7845) + - Fix generic platform gems getting incorrectly removed from lockfile [#7833](https://github.com/ruby/rubygems/pull/7833) + +### Performance: + + - Use `caller_locations` instead of splitting `caller` [#7708](https://github.com/ruby/rubygems/pull/7708) + +## 2.5.15 (2024-07-09) + +### Enhancements: + + - Support `--no-test`, `--no-ci`, and `--no-linter` options [#7780](https://github.com/ruby/rubygems/pull/7780) + - Allow bundle command in new gems with invalid metadata [#7707](https://github.com/ruby/rubygems/pull/7707) + +### Bug fixes: + + - Protect creating RubyGems binstubs with a file lock [#7841](https://github.com/ruby/rubygems/pull/7841) + - Only allow valid values for `--test`, `--ci`, and `--linter` options [#7801](https://github.com/ruby/rubygems/pull/7801) + - Fix `bundle lock --add-platform ` doing nothing [#7803](https://github.com/ruby/rubygems/pull/7803) + - Print a proper error when bin dir does not have writable permission bit [#7794](https://github.com/ruby/rubygems/pull/7794) + +### Documentation: + + - Regenerate bundler docs for June 2024 [#7787](https://github.com/ruby/rubygems/pull/7787) + +## 2.5.14 (2024-06-21) + +### Bug fixes: + + - Fix credentials being re-added when re-resolving without a full unlock [#7767](https://github.com/ruby/rubygems/pull/7767) + - Fix `bundle update ` edge case [#7770](https://github.com/ruby/rubygems/pull/7770) + - Fix `bundle fund` when the gemfile contains optional groups [#7758](https://github.com/ruby/rubygems/pull/7758) + +## 2.5.13 (2024-06-14) + +### Bug fixes: + + - Fix funding metadata not being printed in some situations [#7746](https://github.com/ruby/rubygems/pull/7746) + - Make sure to not re-resolve when a not fully specific local platform is locked [#7751](https://github.com/ruby/rubygems/pull/7751) + - Don't print bug report template when bin dir is not writable [#7748](https://github.com/ruby/rubygems/pull/7748) + +## 2.5.12 (2024-06-13) + +### Enhancements: + + - Keep credentials in lockfile if they are already there [#7720](https://github.com/ruby/rubygems/pull/7720) + - Auto switch to locked bundler version even when using binstubs [#7719](https://github.com/ruby/rubygems/pull/7719) + - Don't validate local gemspecs twice unnecessarily [#7725](https://github.com/ruby/rubygems/pull/7725) + - Improve default gem handling by treating default gems as any other gem [#7673](https://github.com/ruby/rubygems/pull/7673) + +### Bug fixes: + + - Fix slow and incorrect resolution when adding `sorbet` to a Gemfile and the lockfile only includes "RUBY" in the platforms section [#7731](https://github.com/ruby/rubygems/pull/7731) + - Fix duplicated config keys generated when `fallback_timeout` uri option is used [#7704](https://github.com/ruby/rubygems/pull/7704) + - Fix `bundle exec` no longer working in truffleruby after explicit `require` of `pathname` was removed [#7703](https://github.com/ruby/rubygems/pull/7703) + - Don't let `bundle config` report a path without a Gemfile as "local app" [#7687](https://github.com/ruby/rubygems/pull/7687) + +### Documentation: + + - Clarify BUNDLE_USER_CONFIG is a file [#7668](https://github.com/ruby/rubygems/pull/7668) + +## 2.5.11 (2024-05-28) + +### Deprecations: + + - Deprecate Bundler constants [#7653](https://github.com/ruby/rubygems/pull/7653) + +### Enhancements: + + - Bump `bundle gem` generated COC to Contributor Covenant 2.1 [#7692](https://github.com/ruby/rubygems/pull/7692) + - Retry a full clone when git server does not support shallow capabilities [#7649](https://github.com/ruby/rubygems/pull/7649) + +### Bug fixes: + + - Fix regression when caching gems from secondary sources [#7659](https://github.com/ruby/rubygems/pull/7659) + - Fix error when Bundler installation is corrupted [#7642](https://github.com/ruby/rubygems/pull/7642) + - Fix crash caused by RubyGems `require` gem activation logic running before Bundler can properly register its own monkeypatches [#7647](https://github.com/ruby/rubygems/pull/7647) + +### Performance: + + - Update cache checksums to decrease string allocations [#7637](https://github.com/ruby/rubygems/pull/7637) + - Fix performance regression in applications with a local cache [#7680](https://github.com/ruby/rubygems/pull/7680) + +### Documentation: + + - Recommend `bin/rake` over `rake` in contributing docs [#7648](https://github.com/ruby/rubygems/pull/7648) + - Monthly man update for May 2024 [#7640](https://github.com/ruby/rubygems/pull/7640) + - Clarify Bundler support policy [#7633](https://github.com/ruby/rubygems/pull/7633) + +## 2.5.10 (2024-05-03) + +### Security: + + - Never write credentials to lockfiles [#7560](https://github.com/ruby/rubygems/pull/7560) + +### Enhancements: + + - Add auto_install support to require "bundler/setup" [#6561](https://github.com/ruby/rubygems/pull/6561) + - Add `--glob` flag to `bundle add` [#7557](https://github.com/ruby/rubygems/pull/7557) + +### Bug fixes: + + - Make sure `bundle update ` can always update to the latest resolvable version of each requested gem [#7558](https://github.com/ruby/rubygems/pull/7558) + - Show better error when installed gemspecs are unreadable [#7603](https://github.com/ruby/rubygems/pull/7603) + - Fix `bundle update` not working on an out of sync lockfile [#7607](https://github.com/ruby/rubygems/pull/7607) + - Don't upcase Windows ENV before backing it up [#7574](https://github.com/ruby/rubygems/pull/7574) + - Properly resolve aliases when `bundle help` is run [#7601](https://github.com/ruby/rubygems/pull/7601) + - Fix issue installing gems with linux-musl variant on non musl linux [#7583](https://github.com/ruby/rubygems/pull/7583) + +### Documentation: + + - Clarify `bundle check` behaviour in docs [#7613](https://github.com/ruby/rubygems/pull/7613) + +## 2.5.9 (2024-04-12) + +### Bug fixes: + + - Fix installing plugins via relative paths [#7571](https://github.com/ruby/rubygems/pull/7571) + +## 2.5.8 (2024-04-11) + +### Enhancements: + + - Allow installing plugins from path via CLI [#6960](https://github.com/ruby/rubygems/pull/6960) + - Improve validation of `bundle plugin install` options [#7529](https://github.com/ruby/rubygems/pull/7529) + +### Bug fixes: + + - Fix resolver error message when it runs out of versions due to `--strict --patch` filtering out everything [#7527](https://github.com/ruby/rubygems/pull/7527) + - Fix incorrect `bundle update --bundler` message [#7516](https://github.com/ruby/rubygems/pull/7516) + +## 2.5.7 (2024-03-22) + +### Deprecations: + + - Deprecate `bundle plugin install --local-git=` [#7048](https://github.com/ruby/rubygems/pull/7048) + +### Enhancements: + + - Ignore commented out keys in config file [#7514](https://github.com/ruby/rubygems/pull/7514) + - Fix exclusion of `.gemspec` file itself in `bundle gem` generated gemspec file [#7488](https://github.com/ruby/rubygems/pull/7488) + - Remove redundant configs from `bundle gem` generated rubocop configuration [#7478](https://github.com/ruby/rubygems/pull/7478) + - Add `gitlab:` git source shorthand [#7449](https://github.com/ruby/rubygems/pull/7449) + - Use full path for `instance_eval` in `Bundler::DSL#eval_gemfile` [#7471](https://github.com/ruby/rubygems/pull/7471) + +### Documentation: + + - Use https instead of http in documentation links [#7481](https://github.com/ruby/rubygems/pull/7481) + +## 2.5.6 (2024-02-06) + +### Deprecations: + + - Refactor lockfile generation and deprecate `Definition#lock` with explicit lockfile [#7047](https://github.com/ruby/rubygems/pull/7047) + +### Enhancements: + + - Bump `required_ruby_version` to be used in `bundle gem` template [#7430](https://github.com/ruby/rubygems/pull/7430) + +### Bug fixes: + + - Fix musl platform not being added to the lockfile [#7441](https://github.com/ruby/rubygems/pull/7441) + - Let `Bundler.with_original_env` properly restore env variables originally empty [#7383](https://github.com/ruby/rubygems/pull/7383) + +## 2.5.5 (2024-01-18) + +### Bug fixes: + + - Fix development dependency not being added if introduced by two gemspecs [#7358](https://github.com/ruby/rubygems/pull/7358) + - Fix ETag quoting regression in If-None-Match header of compact index request [#7352](https://github.com/ruby/rubygems/pull/7352) + +### Documentation: + + - Refer to underscores as underscores [#7364](https://github.com/ruby/rubygems/pull/7364) + +## 2.5.4 (2024-01-04) + +### Bug fixes: + + - Fix resolution when different platform specific gems have different dependencies [#7324](https://github.com/ruby/rubygems/pull/7324) + +## 2.5.3 (2023-12-22) + +### Bug fixes: + + - Fix incorrect error when Gemfile overrides a gemspec development dependency [#7319](https://github.com/ruby/rubygems/pull/7319) + +## 2.5.2 (2023-12-21) + +### Enhancements: + + - Avoid vendored thor gem polluting the global namespace [#7305](https://github.com/ruby/rubygems/pull/7305) + +### Bug fixes: + + - Fix `bundle update --bundler` when latest version does not support current ruby [#7310](https://github.com/ruby/rubygems/pull/7310) + - Fix incorrect lockfiles being generated in some situations [#7307](https://github.com/ruby/rubygems/pull/7307) + - Fix incorrect re-resolve messages [#7306](https://github.com/ruby/rubygems/pull/7306) + +## 2.5.1 (2023-12-15) + +### Bug fixes: + + - Fix `ruby` Gemfile DSL with `file:` parameter no longer working [#7288](https://github.com/ruby/rubygems/pull/7288) + +### Performance: + + - Save array allocation for every dependency in Gemfile [#7270](https://github.com/ruby/rubygems/pull/7270) + +## 2.5.0 (2023-12-15) + +### Breaking changes: + + - Drop ruby 2.6 and 2.7 support [#7116](https://github.com/ruby/rubygems/pull/7116) + - The `:mswin`, `:mswin64`, `:mingw`, and `:x64_mingw` Gemfile `platform` values are soft-deprecated and aliased to `:windows` [#6391](https://github.com/ruby/rubygems/pull/6391) + +### Features: + + - Leverage ruby feature to warn when requiring default gems not included in the bundle that will be turned into bundled gems in the future [#6831](https://github.com/ruby/rubygems/pull/6831) + - Introduce `bundle config set version` feature to choose the version of Bundler that should be used and potentially disable using the `lockfile` version by setting it to `system` [#6817](https://github.com/ruby/rubygems/pull/6817) + +### Performance: + + - Use match? when regexp match data is unused [#7263](https://github.com/ruby/rubygems/pull/7263) + - Avoid some allocations when evaluating `ruby` Gemfile DSL [#7251](https://github.com/ruby/rubygems/pull/7251) + - Reduce array allocations when loading definition [#7199](https://github.com/ruby/rubygems/pull/7199) + - Avoid re-compiling static regexp in a loop [#7198](https://github.com/ruby/rubygems/pull/7198) + - Reduce allocations when installing gems with bundler [#6977](https://github.com/ruby/rubygems/pull/6977) + - Use a shared connection pool for fetching gems [#7079](https://github.com/ruby/rubygems/pull/7079) + - Reduce allocations when parsing compact index [#6971](https://github.com/ruby/rubygems/pull/6971) + +### Enhancements: + + - Add 3.4 as a supported ruby version in Gemfile DSL [#7264](https://github.com/ruby/rubygems/pull/7264) + - Improve install advice when some gems are not found [#7265](https://github.com/ruby/rubygems/pull/7265) + - Vendor `net-http`, `net-protocol`, `resolv`, and `timeout` to reduce conflicts between Gemfile gems and internal dependencies [#6793](https://github.com/ruby/rubygems/pull/6793) + - Allow `bundle pristine` to run in parallel [#6927](https://github.com/ruby/rubygems/pull/6927) + - Make `bundle lock` always touch the lockfile in non-frozen mode [#7220](https://github.com/ruby/rubygems/pull/7220) + - Use `Minitest::TestTask` in a template file for `minitest` [#7234](https://github.com/ruby/rubygems/pull/7234) + - Add missing services to CI detection and make it consistent between RubyGems and Bundler [#7205](https://github.com/ruby/rubygems/pull/7205) + - Allow auto-install to install missing git gems [#7197](https://github.com/ruby/rubygems/pull/7197) + - Stop remembering cli flags like `--jobs` or `--retry` in configuration [#7191](https://github.com/ruby/rubygems/pull/7191) + - Simplify remembered flags deprecation message [#7189](https://github.com/ruby/rubygems/pull/7189) + - Make sure to `require "rubygems"` explicitly [#7139](https://github.com/ruby/rubygems/pull/7139) + - Handle development dependencies duplicated in gemspec vs Gemfile [#6014](https://github.com/ruby/rubygems/pull/6014) + - Make lockfiles generated on macOS include a lock for Linux by default [#5700](https://github.com/ruby/rubygems/pull/5700) + - Only add a dummy bundler spec to the metadata source when necessary [#4443](https://github.com/ruby/rubygems/pull/4443) + +### Bug fixes: + + - Resolve `ruby file: ".ruby-version"` relative to containing Gemfile [#7250](https://github.com/ruby/rubygems/pull/7250) + - Implement opaque ETag in Compact Index to avoid falling back to old index in servers with different etag implementations [#7122](https://github.com/ruby/rubygems/pull/7122) + - Fix `bundle install --system` deprecation advice [#7190](https://github.com/ruby/rubygems/pull/7190) + - Fix invalid platform removal missing adjacent platforms [#7170](https://github.com/ruby/rubygems/pull/7170) + +### Documentation: + + - Add missing --prefer-local to Synopsis in bundle-install.1.ronn [#7194](https://github.com/ruby/rubygems/pull/7194) + - Update GitHub organization of Standard Ruby in `bundle gem` output and generated configuration [#6818](https://github.com/ruby/rubygems/pull/6818) + - Replace "prior to" with "immediately after" in `bundle gem` generated README file [#6338](https://github.com/ruby/rubygems/pull/6338) + +## 2.4.22 (2023-11-09) + +### Enhancements: + + - Add Bundler::Plugin.loaded? helper [#6964](https://github.com/ruby/rubygems/pull/6964) + - Give better error when previous installation folder is insecure to remove [#7030](https://github.com/ruby/rubygems/pull/7030) + - Set file path when eval-ing local specification in EndpointSpecification [#7106](https://github.com/ruby/rubygems/pull/7106) + - Git ignore the proper files for the CI service selected for `bundle gem` [#7101](https://github.com/ruby/rubygems/pull/7101) + - Update vendored thor to v1.3.0 [#7078](https://github.com/ruby/rubygems/pull/7078) + - Restore using old way of passing Ruby version to resolver [#7066](https://github.com/ruby/rubygems/pull/7066) + - Bump vendored net-http-persistent to 4.0.2 [#6787](https://github.com/ruby/rubygems/pull/6787) + +### Bug fixes: + + - Fix regression when installing native extensions on universal rubies [#7077](https://github.com/ruby/rubygems/pull/7077) + - Only remove bundler plugin gem when it's inside the cache [#7001](https://github.com/ruby/rubygems/pull/7001) + - Don't show bug report template when GEM_HOME has no writable bit [#7113](https://github.com/ruby/rubygems/pull/7113) + - Fix regression in old git versions [#7114](https://github.com/ruby/rubygems/pull/7114) + - Handle empty array at built-in YAML serializer [#7099](https://github.com/ruby/rubygems/pull/7099) + - Fix force_ruby_platform: when the lockfile only locks the ruby platform [#6936](https://github.com/ruby/rubygems/pull/6936) + +## 2.4.21 (2023-10-17) + +### Enhancements: + + - Avoid duplicates -rbundler/setup in RUBYOPT with Ruby preview [#7002](https://github.com/ruby/rubygems/pull/7002) + - Prevent gem activation in standalone mode [#6925](https://github.com/ruby/rubygems/pull/6925) + - Support Ruby's preview version format (Ex: 3.3.0-preview2) in Gemfile [#7016](https://github.com/ruby/rubygems/pull/7016) + - Fix `bundle install` when older revisions of git source [#6980](https://github.com/ruby/rubygems/pull/6980) + - Remove usage of Dir.chdir that only execute a subprocess [#6930](https://github.com/ruby/rubygems/pull/6930) + +### Bug fixes: + + - Don't delete the release version from pre-release string more than once [#7054](https://github.com/ruby/rubygems/pull/7054) + - Make the `lock` command not be affected by the `frozen` setting [#7034](https://github.com/ruby/rubygems/pull/7034) + - Raise an error when adding a gem incompatible with some locked platform [#7035](https://github.com/ruby/rubygems/pull/7035) + - Re-resolve when lockfile is invalid [#7020](https://github.com/ruby/rubygems/pull/7020) + - Don't re-resolve with prereleases if unlocked gem has no prereleases [#7021](https://github.com/ruby/rubygems/pull/7021) + - Include gemspec in ExtensionTask for native gem tasks [#7015](https://github.com/ruby/rubygems/pull/7015) + - Avoid error reporting relative path when validating frozen [#5128](https://github.com/ruby/rubygems/pull/5128) + - Fix `bundle lock --minor --update ` edge case [#6992](https://github.com/ruby/rubygems/pull/6992) + - Stop bundler eagerly loading all specs with exts [#6945](https://github.com/ruby/rubygems/pull/6945) + +### Performance: + + - Reduce allocations when parsing lockfile [#6976](https://github.com/ruby/rubygems/pull/6976) + - Stop allocating the same settings keys repeatedly [#6963](https://github.com/ruby/rubygems/pull/6963) + +### Documentation: + + - Improve formatting and global source information in `bundle plugin` man page [#7045](https://github.com/ruby/rubygems/pull/7045) + - Update man page of `bundle exec` to reflect default true of flag `--keep-file-descriptors` [#7033](https://github.com/ruby/rubygems/pull/7033) + +## 2.4.20 (2023-09-27) + +### Enhancements: + + - Bump actions/checkout to v4 in bundler gem template [#6966](https://github.com/ruby/rubygems/pull/6966) + - Add support for the `ruby-3.2.2` format in the `ruby file:` Gemfile directive, and explicitly test the `3.2.2@gemset` format as rejected [#6954](https://github.com/ruby/rubygems/pull/6954) + - Support `ruby file: ".tool-versions"` in Gemfile [#6898](https://github.com/ruby/rubygems/pull/6898) + - Unify LockfileParser loading of SPECS section [#6933](https://github.com/ruby/rubygems/pull/6933) + - Only check circular deps when dependency api is available, not on full index sources [#6919](https://github.com/ruby/rubygems/pull/6919) + +### Bug fixes: + + - Allow standalone mode to work on a Windows edge case [#6989](https://github.com/ruby/rubygems/pull/6989) + - Fix `bundle outdated` crashing when both `ref` and `branch` specified for a git gem in Gemfile [#6959](https://github.com/ruby/rubygems/pull/6959) + - Fix `bundle update --redownload` [#6924](https://github.com/ruby/rubygems/pull/6924) + - Fixed malformed bundler version in lockfile making Bundler crash [#6920](https://github.com/ruby/rubygems/pull/6920) + - Fix standalone install crashing when using legacy gemfiles with multiple global sources [#6918](https://github.com/ruby/rubygems/pull/6918) + - Resolve ruby version file relative to bundle root [#6892](https://github.com/ruby/rubygems/pull/6892) + +### Performance: + + - Lazily construct fetcher debug messages [#6973](https://github.com/ruby/rubygems/pull/6973) + - Avoid allocating empty hashes in Index [#6962](https://github.com/ruby/rubygems/pull/6962) + - Improve `Bundler::Index` efficiency by removing unnecessary creation and dups [#6931](https://github.com/ruby/rubygems/pull/6931) + - (Further) Improve Bundler::Settings#[] performance and memory usage [#6923](https://github.com/ruby/rubygems/pull/6923) + - Don't use full indexes unnecessarily on legacy Gemfiles [#6916](https://github.com/ruby/rubygems/pull/6916) + - Improve memory usage in Bundler::Settings, and thus improve boot time [#6884](https://github.com/ruby/rubygems/pull/6884) + +## 2.4.19 (2023-08-17) + +### Enhancements: + + - Add `file` option to `ruby` method in Gemfile [#6876](https://github.com/ruby/rubygems/pull/6876) + - Show better error when PAT can't authenticate to a private server [#6871](https://github.com/ruby/rubygems/pull/6871) + - Don't fallback to old dependency API when bad credentials are configured [#6869](https://github.com/ruby/rubygems/pull/6869) + +### Bug fixes: + + - Fix git source conservativeness [#6850](https://github.com/ruby/rubygems/pull/6850) + +### Documentation: + + - Clarify that `bundle info` takes a gem name [#6875](https://github.com/ruby/rubygems/pull/6875) + +## 2.4.18 (2023-08-02) + +### Security: + + - Merge URI-0.12.2 for Bundler [#6779](https://github.com/ruby/rubygems/pull/6779) + +### Enhancements: + + - Update Magnus version in Rust extension gem template [#6843](https://github.com/ruby/rubygems/pull/6843) + +### Documentation: + + - Update bundle-outdated(1) man to use table output [#6833](https://github.com/ruby/rubygems/pull/6833) + +## 2.4.17 (2023-07-14) + +### Enhancements: + + - Avoid printing "Using ..." messages when version has not changed [#6804](https://github.com/ruby/rubygems/pull/6804) + +### Bug fixes: + + - Fix `bundler/setup` unintendedly writing to the filesystem [#6814](https://github.com/ruby/rubygems/pull/6814) + +## 2.4.16 (2023-07-10) + +### Bug fixes: + + - Exclude Bundler from missing locked dependencies check [#6792](https://github.com/ruby/rubygems/pull/6792) + - Fix another incorrect removal of "ruby" platform from lockfile when changing path sources [#6784](https://github.com/ruby/rubygems/pull/6784) + - Fix git source lockfile instability [#6786](https://github.com/ruby/rubygems/pull/6786) + +### Documentation: + + - `gemfile.5`: Code format the default glob to escape Markdown [#6790](https://github.com/ruby/rubygems/pull/6790) + +## 2.4.15 (2023-06-29) + +### Enhancements: + + - Improve edge case error message [#6733](https://github.com/ruby/rubygems/pull/6733) + +### Bug fixes: + + - Fix `bundle lock --update --bundler` [#6213](https://github.com/ruby/rubygems/pull/6213) + +## 2.4.14 (2023-06-12) + +### Enhancements: + + - Stop publishing Gemfile in default gem template [#6723](https://github.com/ruby/rubygems/pull/6723) + - Avoid infinite loops when hitting resolution bugs [#6722](https://github.com/ruby/rubygems/pull/6722) + - Make `LockfileParser` usable with just a lockfile [#6694](https://github.com/ruby/rubygems/pull/6694) + - Always rely on `$LOAD_PATH` when jumping from `exe/` to `lib/` [#6702](https://github.com/ruby/rubygems/pull/6702) + - Make `frozen` setting take precedence over `deployment` setting [#6685](https://github.com/ruby/rubygems/pull/6685) + - Show an error when trying to update bundler in frozen mode [#6684](https://github.com/ruby/rubygems/pull/6684) + +### Bug fixes: + + - Fix `deployment` vs `path` precedence [#6703](https://github.com/ruby/rubygems/pull/6703) + - Fix inline mode with multiple sources [#6699](https://github.com/ruby/rubygems/pull/6699) + +## 2.4.13 (2023-05-09) + +### Bug fixes: + + - Fix unexpected fallbacks to full index by adding FalseClass and Time to the SafeMarshal list [#6655](https://github.com/ruby/rubygems/pull/6655) + +### Documentation: + + - Fix broken hyperlinks in bundle cache documentation [#6606](https://github.com/ruby/rubygems/pull/6606) + +## 2.4.12 (2023-04-11) + +### Enhancements: + + - Remove reference to `pry` gem from generated `bin/console` file [#6515](https://github.com/ruby/rubygems/pull/6515) + +## 2.4.11 (2023-04-10) + +### Security: + + - Use URI-0.12.1 (safe against CVE-2023-28755 ReDoS vulnerability) [#6558](https://github.com/ruby/rubygems/pull/6558) + +### Enhancements: + + - Remove one fallback to full indexes on big gemfiles [#6578](https://github.com/ruby/rubygems/pull/6578) + - Generate native gems with `-fvisibility=hidden` [#6541](https://github.com/ruby/rubygems/pull/6541) + +### Bug fixes: + + - Fix resolver hangs when dealing with an incomplete lockfile [#6552](https://github.com/ruby/rubygems/pull/6552) + - Fix prereleases not being considered by gem version promoter when there's no lockfile [#6537](https://github.com/ruby/rubygems/pull/6537) + +## 2.4.10 (2023-03-27) + +### Bug fixes: + + - Fix some unnecessary top level dependency downgrades [#6535](https://github.com/ruby/rubygems/pull/6535) + - Fix incorrect ruby platform removal from lockfile when adding Gemfile dependencies [#6540](https://github.com/ruby/rubygems/pull/6540) + - Fix installing plugins in frozen mode [#6543](https://github.com/ruby/rubygems/pull/6543) + - Restore "enumerability" of `SpecSet` [#6532](https://github.com/ruby/rubygems/pull/6532) + +## 2.4.9 (2023-03-20) + +### Security: + + - Don't recommend `--full-index` on errors [#6493](https://github.com/ruby/rubygems/pull/6493) + +### Enhancements: + + - Fix duplicated specs in some error messages [#6475](https://github.com/ruby/rubygems/pull/6475) + - When running `bundle lock --update `, checkout locked revision of unrelated git sources directly [#6459](https://github.com/ruby/rubygems/pull/6459) + - Avoid expiring git sources when unnecessary [#6458](https://github.com/ruby/rubygems/pull/6458) + - Use `RbSys::ExtensionTask` when creating new rust gems [#6352](https://github.com/ruby/rubygems/pull/6352) + - Don't ignore pre-releases when there's only one candidate [#6441](https://github.com/ruby/rubygems/pull/6441) + +### Bug fixes: + + - Fix incorrect removal of ruby platform when auto-healing corrupted lockfiles [#6495](https://github.com/ruby/rubygems/pull/6495) + - Don't consider platform specific candidates when `force_ruby_platform` set [#6442](https://github.com/ruby/rubygems/pull/6442) + - Better deal with circular dependencies [#6330](https://github.com/ruby/rubygems/pull/6330) + +### Documentation: + + - Add debugging docs [#6387](https://github.com/ruby/rubygems/pull/6387) + - Document our current release policy [#6450](https://github.com/ruby/rubygems/pull/6450) + +## 2.4.8 (2023-03-08) + +### Security: + + - Safe load all marshaled data [#6384](https://github.com/ruby/rubygems/pull/6384) + +### Enhancements: + + - Better suggestion when `bundler/setup` fails due to missing gems and Gemfile is not the default [#6428](https://github.com/ruby/rubygems/pull/6428) + - Simplify the gem package file filter in the gemspec template [#6344](https://github.com/ruby/rubygems/pull/6344) + - Auto-heal corrupted `Gemfile.lock` with no specs [#6423](https://github.com/ruby/rubygems/pull/6423) + - Auto-heal on corrupted lockfile with missing deps [#6400](https://github.com/ruby/rubygems/pull/6400) + - Give a better message when Gemfile branch does not exist [#6383](https://github.com/ruby/rubygems/pull/6383) + +### Bug fixes: + + - Respect --no-install option for git: sources [#6088](https://github.com/ruby/rubygems/pull/6088) + - Fix `gems.rb` lockfile for bundler version lookup in template [#6413](https://github.com/ruby/rubygems/pull/6413) + +### Documentation: + + - Switch supporting explanations to all Ruby Central [#6419](https://github.com/ruby/rubygems/pull/6419) + +## 2.4.7 (2023-02-15) + +### Enhancements: + + - Add `--gemfile` flag to `bundle init` to configure gemfile name to generate [#6046](https://github.com/ruby/rubygems/pull/6046) + - Improve solve failure explanations by using better wording [#6366](https://github.com/ruby/rubygems/pull/6366) + - Restore better error message when locked ref does not exist [#6356](https://github.com/ruby/rubygems/pull/6356) + - Avoid crashing when installing from a corrupted lockfile [#6355](https://github.com/ruby/rubygems/pull/6355) + - Improve wording of unmet dependencies warning [#6357](https://github.com/ruby/rubygems/pull/6357) + - Add Ruby 3.2 and 3.3 platforms to Gemfile DSL [#6346](https://github.com/ruby/rubygems/pull/6346) + +### Bug fixes: + + - Fix crash in pub grub involving empty ranges [#6365](https://github.com/ruby/rubygems/pull/6365) + - Make gemspec file generated by `bundle gem` properly exclude itself from packaged gem [#6339](https://github.com/ruby/rubygems/pull/6339) + - Preserve relative path sources in standalone setup [#6327](https://github.com/ruby/rubygems/pull/6327) + +## 2.4.6 (2023-01-31) + +### Enhancements: + + - Don't warn on `bundle binstubs --standalone --all` [#6312](https://github.com/ruby/rubygems/pull/6312) + +### Bug fixes: + + - Don't undo require decorations made by other gems [#6308](https://github.com/ruby/rubygems/pull/6308) + - Fix `bundler/inline` not properly installing gems with extensions when used more than once [#6306](https://github.com/ruby/rubygems/pull/6306) + - Fix `bundler/inline` not skipping installation when gems already there, when used more than once [#6305](https://github.com/ruby/rubygems/pull/6305) + +## 2.4.5 (2023-01-21) + +### Bug fixes: + + - Fix `bundler/inline` not resolving properly if gems not preinstalled [#6282](https://github.com/ruby/rubygems/pull/6282) + - Fix packages for external platforms being introduced in lockfile when Bundler retries resolution [#6285](https://github.com/ruby/rubygems/pull/6285) + +### Documentation: + + - Update bundle-exec man page to not use deprecated `Bundler.with_clean_env` [#6284](https://github.com/ruby/rubygems/pull/6284) + +## 2.4.4 (2023-01-16) + +### Bug fixes: + + - Fix platform specific gems removed from the lockfile [#6266](https://github.com/ruby/rubygems/pull/6266) + - Properly handle incompatibilities on platform specific gems [#6270](https://github.com/ruby/rubygems/pull/6270) + - Optimistically exclude prereleases from initial resolution [#6246](https://github.com/ruby/rubygems/pull/6246) + - Fix another case of not properly falling back to ruby variant when materializing [#6261](https://github.com/ruby/rubygems/pull/6261) + - Skip setting `BUNDLER_SETUP` on Ruby 2.6 [#6252](https://github.com/ruby/rubygems/pull/6252) + - Let resolver deal with legacy gems with equivalent version and different dependencies [#6219](https://github.com/ruby/rubygems/pull/6219) + +## 2.4.3 (2023-01-06) + +### Enhancements: + + - Enhance `bundle open` command to allow opening subdir/file of gem [#6146](https://github.com/ruby/rubygems/pull/6146) + +### Bug fixes: + + - Fix pointing GitHub sources to PRs [#6241](https://github.com/ruby/rubygems/pull/6241) + - Fix version ranges incorrectly handling platforms [#6240](https://github.com/ruby/rubygems/pull/6240) + - Cleanup unnecessary gems when removing lockfile platforms [#6234](https://github.com/ruby/rubygems/pull/6234) + - When auto-removing RUBY platform don't add specific platform if not needed [#6233](https://github.com/ruby/rubygems/pull/6233) + - Fallback to selecting installable candidates if possible when materializing specs [#6225](https://github.com/ruby/rubygems/pull/6225) + +### Documentation: + + - Fix several typos [#6224](https://github.com/ruby/rubygems/pull/6224) + +## 2.4.2 (2023-01-01) + +### Performance: + + - Speed up resolution by properly merging incompatibility ranges [#6215](https://github.com/ruby/rubygems/pull/6215) + +### Documentation: + + - Remove stray word in `bundle config` man page [#6220](https://github.com/ruby/rubygems/pull/6220) + +## 2.4.1 (2022-12-24) + +### Enhancements: + + - Allow Bundler to run on old RubyGems + Ruby 2.7 without warnings [#6187](https://github.com/ruby/rubygems/pull/6187) + +### Bug fixes: + + - Fix dependencies scoped to other platforms making resolver fail [#6189](https://github.com/ruby/rubygems/pull/6189) + - Restore annotated git tag support [#6186](https://github.com/ruby/rubygems/pull/6186) + +## 2.4.0 (2022-12-24) + +### Security: + + - In README generated by `bundle gem`, do not fill rubygems.org install commands with the gem name automatically [#6093](https://github.com/ruby/rubygems/pull/6093) + - Use safe Marshal deserialization for dependency API response [#6141](https://github.com/ruby/rubygems/pull/6141) + +### Breaking changes: + + - Remove Travis CI from gem skeleton [#6150](https://github.com/ruby/rubygems/pull/6150) + - Drop support for Ruby 2.3, 2.4, 2.5 and RubyGems 2.5, 2.6, 2.7 [#6107](https://github.com/ruby/rubygems/pull/6107) + - Completely remove "auto-sudo" feature [#5888](https://github.com/ruby/rubygems/pull/5888) + +### Deprecations: + + - Turn `--ext` option of `bundle gem` into string. Deprecate usage without explicit value [#6144](https://github.com/ruby/rubygems/pull/6144) + +### Features: + + - Add `--ext=rust` support to `bundle gem` for creating simple gems with Rust extensions [#6149](https://github.com/ruby/rubygems/pull/6149) + - Migrate our resolver engine to PubGrub [#5960](https://github.com/ruby/rubygems/pull/5960) + +### Performance: + + - Make cloning git repos faster [#4475](https://github.com/ruby/rubygems/pull/4475) + +### Enhancements: + + - Add `bundle lock --update --bundler` [#6134](https://github.com/ruby/rubygems/pull/6134) + - Support for pre flag in `bundle update`/`bundle lock` [#5258](https://github.com/ruby/rubygems/pull/5258) + - Improve error message when changing Gemfile to a mistyped git ref [#6130](https://github.com/ruby/rubygems/pull/6130) + - Remove special handling of some `LoadError` and `NoMethodError` [#6115](https://github.com/ruby/rubygems/pull/6115) + +### Bug fixes: + + - Don't unlock dependencies of a gemspec when its version changes [#6184](https://github.com/ruby/rubygems/pull/6184) + - Fix platform specific version for libv8-node and other allowlisted gems not being chosen in Truffleruby [#6169](https://github.com/ruby/rubygems/pull/6169) + - Fix `bundle outdated` with both `--groups` and `--parseable` flags [#6148](https://github.com/ruby/rubygems/pull/6148) + - Auto-heal lockfile when it's missing specs [#6132](https://github.com/ruby/rubygems/pull/6132) + - Fix unintentional downgrades when gemspec DSL is used [#6131](https://github.com/ruby/rubygems/pull/6131) + - Fix display of previous gem version when previously downloaded already [#6110](https://github.com/ruby/rubygems/pull/6110) + - Fix hang when a lockfile gem does not resolve on the current platform [#6070](https://github.com/ruby/rubygems/pull/6070) + +### Documentation: + + - Improve Bundler setup docs for development [#6154](https://github.com/ruby/rubygems/pull/6154) + - Fx link in bundle-platform man page [#6071](https://github.com/ruby/rubygems/pull/6071) + +## 2.3.26 (2022-11-16) + +### Enhancements: + + - Map 'universal' to the real arch in Bundler for prebuilt gem selection [#5978](https://github.com/ruby/rubygems/pull/5978) + +### Documentation: + + - Fix '--force' option documentation of 'bundle clean' [#6050](https://github.com/ruby/rubygems/pull/6050) + +## 2.3.25 (2022-11-02) + +### Bug fixes: + + - Properly sort specs when materializing [#6015](https://github.com/ruby/rubygems/pull/6015) + - Fix bad unfreeze recommendation [#6013](https://github.com/ruby/rubygems/pull/6013) + +### Documentation: + + - Bring docs for gemfile(5) manpage up to date [#6007](https://github.com/ruby/rubygems/pull/6007) + - Fix `github` DSL docs to mention they use https protocol over git under the hood [#5993](https://github.com/ruby/rubygems/pull/5993) + +## 2.3.24 (2022-10-17) + +### Enhancements: + + - Only add extra resolver spec group for Ruby platform when needed [#5698](https://github.com/ruby/rubygems/pull/5698) + - Fix little UI issue when bundler shows duplicated gems in a list [#5965](https://github.com/ruby/rubygems/pull/5965) + +### Bug fixes: + + - Fix incorrect materialization on Windows [#5975](https://github.com/ruby/rubygems/pull/5975) + +## 2.3.23 (2022-10-05) + +### Enhancements: + + - Update GitLab CI template with new one [#5944](https://github.com/ruby/rubygems/pull/5944) + +### Bug fixes: + + - Fix `bundle init` not respecting umask in generated gem's Gemfile [#5947](https://github.com/ruby/rubygems/pull/5947) + +### Performance: + + - Further speed up Bundler by not sorting specs unnecessarily [#5868](https://github.com/ruby/rubygems/pull/5868) + +### Documentation: + + - Update Bundler new feature instructions [#5912](https://github.com/ruby/rubygems/pull/5912) + +## 2.3.22 (2022-09-07) + +### Enhancements: + + - Use a more accurate source code uri in gemspec [#5896](https://github.com/ruby/rubygems/pull/5896) + - Support `--path` option in `bundle add` [#5897](https://github.com/ruby/rubygems/pull/5897) + - Improve lockfile dependency unlocking [#5881](https://github.com/ruby/rubygems/pull/5881) + - Add platform alias `:windows` to Gemfile DSL [#5650](https://github.com/ruby/rubygems/pull/5650) + - Make `#to_lock` consistent between `Gem::Dependency` and `Bundler::Dependency` [#5872](https://github.com/ruby/rubygems/pull/5872) + - Support marshaled index specifications with `nil` required ruby version [#5824](https://github.com/ruby/rubygems/pull/5824) + +### Bug fixes: + + - Fix resolution hanging on musl platforms [#5875](https://github.com/ruby/rubygems/pull/5875) + - Fix another regression affecting the sorbet family of gems [#5874](https://github.com/ruby/rubygems/pull/5874) + +### Documentation: + + - Introduce bundle-console(1) man [#5901](https://github.com/ruby/rubygems/pull/5901) + - Introduce bundle-version(1) man [#5895](https://github.com/ruby/rubygems/pull/5895) + - Introduce bundle-help(1) man [#5886](https://github.com/ruby/rubygems/pull/5886) + +## 2.3.21 (2022-08-24) + +### Enhancements: + + - Backport non gnu libc linux support from RubyGems [#4488](https://github.com/ruby/rubygems/pull/4488) + - Improve `Bundler.rm_rf` error message [#5861](https://github.com/ruby/rubygems/pull/5861) + - Disallow both `--branch` and `--ref` at the same time in bundle-plugin [#5855](https://github.com/ruby/rubygems/pull/5855) + - Restore previous performance of private RubyGems servers [#5826](https://github.com/ruby/rubygems/pull/5826) + +### Bug fixes: + + - Fix conservative update downgrading top level gems [#5847](https://github.com/ruby/rubygems/pull/5847) + - Fix edge case where `bundler/inline` unintentionally skips install [#5848](https://github.com/ruby/rubygems/pull/5848) + - Fix `bundle platform` crash when there's a lockfile with no Ruby locked [#5850](https://github.com/ruby/rubygems/pull/5850) + - Fix crash when incomplete locked specifications are found in transitive dependencies [#5840](https://github.com/ruby/rubygems/pull/5840) + - Fix Ruby platform incorrectly removed on `bundle update` [#5832](https://github.com/ruby/rubygems/pull/5832) + +### Documentation: + + - Explain cancelled CLI deprecations clearly [#5864](https://github.com/ruby/rubygems/pull/5864) + - Improve `bundle config` command synopsis [#5854](https://github.com/ruby/rubygems/pull/5854) + - Introduce bundle-plugin(1) man [#5853](https://github.com/ruby/rubygems/pull/5853) + +## 2.3.20 (2022-08-10) + +### Enhancements: + + - Consistently ignore patchlevel when reporting `bundle platform --ruby` [#5793](https://github.com/ruby/rubygems/pull/5793) + - Make `--standalone` play nice with `--local` [#5762](https://github.com/ruby/rubygems/pull/5762) + - Implement `bundle install --prefer-local` [#5761](https://github.com/ruby/rubygems/pull/5761) + +### Bug fixes: + + - Fix regression where yanked gems are now unintentionally updated when other gems are unlocked [#5812](https://github.com/ruby/rubygems/pull/5812) + - Automatically remove "ruby" from lockfile if incomplete [#5807](https://github.com/ruby/rubygems/pull/5807) + - Fix `bundle outdated --strict` showing too many outdated gems [#5798](https://github.com/ruby/rubygems/pull/5798) + - Don't discard candidates matching Ruby metadata [#5784](https://github.com/ruby/rubygems/pull/5784) + - Fix `bundle outdated` crash in debug mode [#5796](https://github.com/ruby/rubygems/pull/5796) + - Fix `ruby` DSL requirement matching for head and prerelease rubies [#5766](https://github.com/ruby/rubygems/pull/5766) + +### Documentation: + + - Update Bundler support policies to match what we do these days [#5813](https://github.com/ruby/rubygems/pull/5813) + - Fix arguments for bundle-config(1) docs [#5804](https://github.com/ruby/rubygems/pull/5804) + - Improve `bundle platform` man page [#5788](https://github.com/ruby/rubygems/pull/5788) + - Remove `bundle cache` from deprecated commands list, and consistently link to `bundle cache` in man pages [#5783](https://github.com/ruby/rubygems/pull/5783) + - Add package/pack aliases to man pages for cache [#5785](https://github.com/ruby/rubygems/pull/5785) + - Add deprecation notice of bundle console [#5775](https://github.com/ruby/rubygems/pull/5775) + +## 2.3.19 (2022-07-27) + +### Enhancements: + + - Add `Bundler.settings[:only]` to install gems of the specified groups [#5759](https://github.com/ruby/rubygems/pull/5759) + - Add `ignore_funding_requests` config flag [#5767](https://github.com/ruby/rubygems/pull/5767) + - Prevent random crash when autoloading `Pathname` [#5769](https://github.com/ruby/rubygems/pull/5769) + - Don't corrupt lockfile when user moves a gem that's already in the lockfile to an incorrect source by mistake [#5070](https://github.com/ruby/rubygems/pull/5070) + - Reconcile error/warning message for multiple global sources with documentation [#5741](https://github.com/ruby/rubygems/pull/5741) + - Improve error message when gems cannot be found to include the source for each gem [#5729](https://github.com/ruby/rubygems/pull/5729) + +### Bug fixes: + + - Fix yet another TruffleRuby platform selection regression [#5746](https://github.com/ruby/rubygems/pull/5746) + - Show a proper error if extension dir is not writable [#5726](https://github.com/ruby/rubygems/pull/5726) + +### Performance: + + - Lazily check incomplete lockfile to improve performance [#5546](https://github.com/ruby/rubygems/pull/5546) + +### Documentation: + + - Add deprecation notice of bundle inject [#5776](https://github.com/ruby/rubygems/pull/5776) + - Add deprecation notice of `bundle viz` to man pages [#5765](https://github.com/ruby/rubygems/pull/5765) + - Update command example in `bundle exec` man page [#5754](https://github.com/ruby/rubygems/pull/5754) + - Remove bundle show from obsolete commands [#5753](https://github.com/ruby/rubygems/pull/5753) + - Improve global source(s) documentation [#5732](https://github.com/ruby/rubygems/pull/5732) + - Use https protocol for URLs for config mirror in bundler man [#5722](https://github.com/ruby/rubygems/pull/5722) + +## 2.3.18 (2022-07-14) + +### Enhancements: + + - Extend `gem` DSL with a `force_ruby_platform` option [#4049](https://github.com/ruby/rubygems/pull/4049) + +### Bug fixes: + + - Fix misleading error if compact index cannot be copied [#5709](https://github.com/ruby/rubygems/pull/5709) + - Fix TruffleRuby no longer able to install lockfiles generated with other implementations [#5711](https://github.com/ruby/rubygems/pull/5711) + - Fix TruffleRuby no longer installing lockfiles using "ruby" platform correctly [#5694](https://github.com/ruby/rubygems/pull/5694) + - Fix crash when updating vendor cache of default gems [#5679](https://github.com/ruby/rubygems/pull/5679) + +### Performance: + + - Speed up `bundler/setup` by using the raw `Gemfile.lock` information without extra processing whenever possible [#5695](https://github.com/ruby/rubygems/pull/5695) + +### Documentation: + + - Use modern style hashes in Gemfile DSL docs [#5674](https://github.com/ruby/rubygems/pull/5674) + +## 2.3.17 (2022-06-29) + +### Enhancements: + + - Add support for platform `:x64_mingw` to correctly lookup "x64-mingw-ucrt" [#5649](https://github.com/ruby/rubygems/pull/5649) + - Fix some errors being printed twice in `--verbose` mode [#5654](https://github.com/ruby/rubygems/pull/5654) + - Fix extension paths in generated standalone script [#5632](https://github.com/ruby/rubygems/pull/5632) + +### Bug fixes: + + - Raise if ruby platform is forced and there are no ruby variants [#5495](https://github.com/ruby/rubygems/pull/5495) + - Fix `bundle package --no-install` no longer skipping install [#5639](https://github.com/ruby/rubygems/pull/5639) + +### Performance: + + - Improve performance of `Bundler::SpecSet#for` by using hash lookup of handled deps [#5537](https://github.com/ruby/rubygems/pull/5537) + +### Documentation: + + - Fix formatting issue in `bundle add` man page [#5642](https://github.com/ruby/rubygems/pull/5642) + +## 2.3.16 (2022-06-15) + +### Performance: + + - Improve performance of installing gems from gem server sources [#5614](https://github.com/ruby/rubygems/pull/5614) + +## 2.3.15 (2022-06-01) + +### Enhancements: + + - Show better error when previous installation fails to be removed [#5564](https://github.com/ruby/rubygems/pull/5564) + - Show exception cause in bug report template [#5563](https://github.com/ruby/rubygems/pull/5563) + +### Bug fixes: + + - Fix `bundle remove` by invalidating cached `Bundle.definition` [#5443](https://github.com/ruby/rubygems/pull/5443) + - Fix generated standalone script when it includes default gems [#5586](https://github.com/ruby/rubygems/pull/5586) + - Skip duplicated dependency warning for gemspec dev deps [#5587](https://github.com/ruby/rubygems/pull/5587) + - Give better conflict resolution advice [#5581](https://github.com/ruby/rubygems/pull/5581) + - Fix crash when commenting out a mirror in configuration [#5576](https://github.com/ruby/rubygems/pull/5576) + - Fix crash when installing gems with symlinks [#5570](https://github.com/ruby/rubygems/pull/5570) + - Ignore `Errno::EROFS` errors when creating `bundler.lock` [#5580](https://github.com/ruby/rubygems/pull/5580) + - Ignore `Errno::EPERM` errors when creating `bundler.lock` [#5579](https://github.com/ruby/rubygems/pull/5579) + - Fix crash when printing resolution conflicts on metadata requirements [#5562](https://github.com/ruby/rubygems/pull/5562) + +## 2.3.14 (2022-05-18) + +### Bug fixes: + + - Fix confusing inline mode install output [#5530](https://github.com/ruby/rubygems/pull/5530) + - Fix error message when locked version of a gem does not support running Ruby [#5525](https://github.com/ruby/rubygems/pull/5525) + +### Performance: + + - Improve `bundler/setup` performance again by not deduplicating intermediate results [#5533](https://github.com/ruby/rubygems/pull/5533) + +### Documentation: + + - Fix typo in documentation [#5514](https://github.com/ruby/rubygems/pull/5514) + - Update man page for `require` option in `bundle add` command [#5513](https://github.com/ruby/rubygems/pull/5513) + +## 2.3.13 (2022-05-04) + +### Bug fixes: + + - Fix missing required rubygems version when using old APIs [#5496](https://github.com/ruby/rubygems/pull/5496) + - Fix crash when gem used twice in Gemfile under different platforms [#5187](https://github.com/ruby/rubygems/pull/5187) + +### Performance: + + - Speed up `bundler/setup` time [#5503](https://github.com/ruby/rubygems/pull/5503) + +## 2.3.12 (2022-04-20) + +### Enhancements: + + - Improve Ruby version resolution conflicts [#5474](https://github.com/ruby/rubygems/pull/5474) + - Stop considering `RUBY_PATCHLEVEL` for resolution [#5472](https://github.com/ruby/rubygems/pull/5472) + - Add modern rubies as valid platform values in Gemfile DSL [#5469](https://github.com/ruby/rubygems/pull/5469) + +## 2.3.11 (2022-04-07) + +### Enhancements: + + - Bump actions/checkout to 3 in bundler gem template [#5445](https://github.com/ruby/rubygems/pull/5445) + - Prefer `__dir__` to `__FILE__` [#5444](https://github.com/ruby/rubygems/pull/5444) + +### Documentation: + + - Update bundler documentation to reflect bundle config scope changes [#5441](https://github.com/ruby/rubygems/pull/5441) + +## 2.3.10 (2022-03-23) + +### Enhancements: + + - More helpful reporting of marshal loading issues [#5416](https://github.com/ruby/rubygems/pull/5416) + - Report Github Actions CI provider within user agent string [#5400](https://github.com/ruby/rubygems/pull/5400) + - Remove extra closing bracket in version warning [#5397](https://github.com/ruby/rubygems/pull/5397) + +## 2.3.9 (2022-03-09) + +### Enhancements: + + - Add newline to validate_platforms! message when platform is missing [#5353](https://github.com/ruby/rubygems/pull/5353) + - Suggest quicker `bundle add` for installation in `README.md` generated by `bundle gem` [#5337](https://github.com/ruby/rubygems/pull/5337) + - Make `--strict` flag of `update` and `outdated` commands consistent [#5379](https://github.com/ruby/rubygems/pull/5379) + +### Bug fixes: + + - Fix regression when activating gem executables caused by Bundler monkey patches to RubyGems [#5386](https://github.com/ruby/rubygems/pull/5386) + +## 2.3.8 (2022-02-23) + +### Bug fixes: + + - Fix corrupted lockfile when running `bundle check` and having to re-resolve locally [#5344](https://github.com/ruby/rubygems/pull/5344) + - Fix typo in multiple gemfiles warning [#5342](https://github.com/ruby/rubygems/pull/5342) + +### Documentation: + + - Add clarification for bundle-config "with" option [#5346](https://github.com/ruby/rubygems/pull/5346) + +## 2.3.7 (2022-02-09) + +### Enhancements: + + - Don't activate `yaml` gem from Bundler [#5277](https://github.com/ruby/rubygems/pull/5277) + - Add Reverse Dependencies section to info command [#3966](https://github.com/ruby/rubygems/pull/3966) + +### Bug fixes: + + - Don't silently persist `BUNDLE_WITH` and `BUNDLE_WITHOUT` envs locally [#5335](https://github.com/ruby/rubygems/pull/5335) + - Fix `bundle config` inside an application saving configuration globally [#4152](https://github.com/ruby/rubygems/pull/4152) + +## 2.3.6 (2022-01-26) + +### Enhancements: + + - Use `Gem::Platform.local` instead of `RUBY_PLATFORM` when displaying local platform [#5306](https://github.com/ruby/rubygems/pull/5306) + - Lock standard.yml to the required ruby version [#5284](https://github.com/ruby/rubygems/pull/5284) + - Use `Fiddle` in `bundle doctor` to check for dynamic library presence [#5173](https://github.com/ruby/rubygems/pull/5173) + +### Bug fixes: + + - Fix edge case where gems were incorrectly removed from the lockfile [#5302](https://github.com/ruby/rubygems/pull/5302) + - Fix `force_ruby_platform` ignored when lockfile includes current specific platform [#5304](https://github.com/ruby/rubygems/pull/5304) + - Create minitest file to underscored path in "bundle gem" command with dashed gem name [#5273](https://github.com/ruby/rubygems/pull/5273) + - Fix regression with old marshaled specs having null `required_rubygems_version` [#5291](https://github.com/ruby/rubygems/pull/5291) + +## 2.3.5 (2022-01-12) + +### Enhancements: + + - Make `bundle update --bundler` actually lock to the latest bundler version (even if not yet installed) [#5182](https://github.com/ruby/rubygems/pull/5182) + - Use thor-1.2.1 [#5260](https://github.com/ruby/rubygems/pull/5260) + - Exclude bin directory for newgem template [#5259](https://github.com/ruby/rubygems/pull/5259) + +### Bug fixes: + + - Fix metadata requirements being bypassed when custom gem servers are used [#5256](https://github.com/ruby/rubygems/pull/5256) + - Fix `rake build:checksum` writing checksum of package path, not package contents [#5250](https://github.com/ruby/rubygems/pull/5250) + +## 2.3.4 (2021-12-29) + +### Enhancements: + + - Improve error message when `BUNDLED WITH` version does not exist [#5205](https://github.com/ruby/rubygems/pull/5205) + +### Bug fixes: + + - Fix `bundle update --bundler` no longer updating lockfile [#5224](https://github.com/ruby/rubygems/pull/5224) + +## 2.3.3 (2021-12-24) + +### Bug fixes: + + - Fix locked bundler not installed to the right path when `deployment` is set [#5217](https://github.com/ruby/rubygems/pull/5217) + +## 2.3.2 (2021-12-23) + +### Enhancements: + + - Remove unnecessary lockfile upgrade warning [#5209](https://github.com/ruby/rubygems/pull/5209) + +## 2.3.1 (2021-12-22) + +### Enhancements: + + - Vendor latest `thor` with fixes for latest `did_you_mean` deprecations [#5202](https://github.com/ruby/rubygems/pull/5202) + - Avoid unnecessary `shellwords` require on newer rubygems [#5195](https://github.com/ruby/rubygems/pull/5195) + - Re-exec prepending command with `Gem.ruby` if `$PROGRAM_NAME` is not executable [#5193](https://github.com/ruby/rubygems/pull/5193) + +## 2.3.0 (2021-12-21) + +### Features: + + - Change `bundle install` with a lockfile to respect the `BUNDLED WITH` bundler version [#4076](https://github.com/ruby/rubygems/pull/4076) + +### Enhancements: + + - Cancel deprecation of custom git sources [#5147](https://github.com/ruby/rubygems/pull/5147) + - Print warning when running Bundler on potentially problematic RubyGems & Ruby combinations [#5177](https://github.com/ruby/rubygems/pull/5177) + - Error tracing should be printed to stderr [#5179](https://github.com/ruby/rubygems/pull/5179) + - Add `github` and `ref` options to `bundle add` [#5159](https://github.com/ruby/rubygems/pull/5159) + - Add require parameter to `bundle add` [#5021](https://github.com/ruby/rubygems/pull/5021) + - Enable parallel installation on Windows by default [#4822](https://github.com/ruby/rubygems/pull/4822) + - More logging when compact index is not used and we fallback to other APIs [#4546](https://github.com/ruby/rubygems/pull/4546) + - `bundle gem` generated MiniTest file and class now start with 'test' [#3893](https://github.com/ruby/rubygems/pull/3893) + - Add `Bundler::Definition.no_lock` accessor for skipping lockfile creation/update [#3401](https://github.com/ruby/rubygems/pull/3401) + +### Bug fixes: + + - Fix crash when when no platform specific matches exist and show a proper error [#5168](https://github.com/ruby/rubygems/pull/5168) + - Ignore dependencies not actually locked from frozen check [#5152](https://github.com/ruby/rubygems/pull/5152) + - Fix `bundle cache --all-platforms` on Windows [#4552](https://github.com/ruby/rubygems/pull/4552) + +### Documentation: + + - Fix gemspec template typo [#4545](https://github.com/ruby/rubygems/pull/4545) + +## 2.2.33 (2021-12-07) + +### Security fixes: + + - Pass "--" to git commands to separate positional and optional args [#5142](https://github.com/ruby/rubygems/pull/5142) + +### Enhancements: + + - Accept pull request URLs as github source [#5126](https://github.com/ruby/rubygems/pull/5126) + - Add `--version` parameter to `bundle info` command [#5137](https://github.com/ruby/rubygems/pull/5137) + - Let original `Errno::EACCES` error be raised in compact index updater [#5110](https://github.com/ruby/rubygems/pull/5110) + - Improve gemfile-lockfile source equivalence errors [#5120](https://github.com/ruby/rubygems/pull/5120) + - Avoid float-to-string loss of characters in GitHub Actions configuration labels in new gem template [#5089](https://github.com/ruby/rubygems/pull/5089) + - Add an initial rbs template to `bundle gem` skeleton [#5041](https://github.com/ruby/rubygems/pull/5041) + - Avoid shared libraries not getting environment passed right after argv in memory when `bundle exec` is used [#4815](https://github.com/ruby/rubygems/pull/4815) + +### Bug fixes: + + - Don't cleanup paths from gems already activated from `$LOAD_PATH` [#5111](https://github.com/ruby/rubygems/pull/5111) + - Fix handling prereleases of 0 versions, like 0.0.0.dev or 0.0.0.SNAPSHOT [#5116](https://github.com/ruby/rubygems/pull/5116) + - Fix escape of filenames in `bundle doctor` [#5102](https://github.com/ruby/rubygems/pull/5102) + - Don't unlock dependencies when running `bundle install` after changing global source [#5090](https://github.com/ruby/rubygems/pull/5090) + - Fix missing locked specs when depended on another platform [#5092](https://github.com/ruby/rubygems/pull/5092) + - Fix `bundle info` sometimes claiming that bundler has been deleted [#5097](https://github.com/ruby/rubygems/pull/5097) + +### Documentation: + + - Ignore to generate the documentation from vendored libraries [#5118](https://github.com/ruby/rubygems/pull/5118) + +## 2.2.32 (2021-11-23) + +### Enhancements: + + - Clarify `bundle viz` deprecation [#5083](https://github.com/ruby/rubygems/pull/5083) + - Unlock dependencies that no longer match lockfile [#5068](https://github.com/ruby/rubygems/pull/5068) + - Use `shellsplit` instead of array of strings for git push [#5062](https://github.com/ruby/rubygems/pull/5062) + - Re-enable `default_ignores` option for standard [#5003](https://github.com/ruby/rubygems/pull/5003) + +### Bug fixes: + + - Fix downgrading dependencies by changing the `Gemfile` and running `bundle update` [#5078](https://github.com/ruby/rubygems/pull/5078) + +## 2.2.31 (2021-11-08) + +### Enhancements: + + - Link to working `bundler-graph` plugin in `bundle viz` deprecation message [#5061](https://github.com/ruby/rubygems/pull/5061) + - Memoize materialized specs when requiring `bundler/setup` [#5033](https://github.com/ruby/rubygems/pull/5033) + - Allow custom LicenseRef [#5013](https://github.com/ruby/rubygems/pull/5013) + - Better error when installing a lockfile with git sources and git is not installed [#5036](https://github.com/ruby/rubygems/pull/5036) + - Only delete cached gem when it's corrupted [#5031](https://github.com/ruby/rubygems/pull/5031) + - Support gemified `tsort` [#5032](https://github.com/ruby/rubygems/pull/5032) + - Add standard option alongside rubocop to `bundle gem` [#4411](https://github.com/ruby/rubygems/pull/4411) + +### Bug fixes: + + - Fix system man pages no longer working after bundler overrides `MANPATH` [#5039](https://github.com/ruby/rubygems/pull/5039) + - Don't warn when a lockfile is locked to a dev version [#5018](https://github.com/ruby/rubygems/pull/5018) + +## 2.2.30 (2021-10-26) + +### Enhancements: + + - Add a custom SHA1 digest implementation to no longer depend on the digest gem before we know which version to activate [#4989](https://github.com/ruby/rubygems/pull/4989) + - Ensure vendored gems have licenses [#4998](https://github.com/ruby/rubygems/pull/4998) + - Update broken link in Bundler::Fetcher::CertificateFailureError [#4987](https://github.com/ruby/rubygems/pull/4987) + - Give better errors for some permission issues [#4965](https://github.com/ruby/rubygems/pull/4965) + - Print better errors when `bundler/gem_tasks` fail [#4872](https://github.com/ruby/rubygems/pull/4872) + - Fix `bundle install` to reinstall deleted gems [#4974](https://github.com/ruby/rubygems/pull/4974) + - Unify issue template and ISSUES.md document [#4980](https://github.com/ruby/rubygems/pull/4980) + - Bump vendored connection_pool to 2.2.5 [#4738](https://github.com/ruby/rubygems/pull/4738) + +### Bug fixes: + + - Fix error message pointing to non existing file when using a global gem cache [#4999](https://github.com/ruby/rubygems/pull/4999) + - Fix install crash when lockfile has missing dependencies for the current platform [#4941](https://github.com/ruby/rubygems/pull/4941) + - Make `bundle info` show a proper warning every time it finds a deleted gem [#4971](https://github.com/ruby/rubygems/pull/4971) + +## 2.2.29 (2021-10-08) + +### Enhancements: + + - Require at least Ruby 2.6.0 for gems created with recent rubies [#4920](https://github.com/ruby/rubygems/pull/4920) + - Include glob information in string representation of git sources to make generated lockfiles deterministic [#4947](https://github.com/ruby/rubygems/pull/4947) + - Add missing `rubygem_push` prerequisite [#4930](https://github.com/ruby/rubygems/pull/4930) + +## 2.2.28 (2021-09-23) + +### Enhancements: + + - Use example.com in new gem template, since it will never have a potentially dangerous backing website [#4918](https://github.com/ruby/rubygems/pull/4918) + - Deprecate `--install` flag to `bundle remove` and trigger install by default [#4891](https://github.com/ruby/rubygems/pull/4891) + +## 2.2.27 (2021-09-03) + +### Enhancements: + + - Optimize some requires [#4887](https://github.com/ruby/rubygems/pull/4887) + - Correctly redact credentials when using x-oauth-basic [#4866](https://github.com/ruby/rubygems/pull/4866) + +### Bug fixes: + + - Add missing key `branches:` to template for GitHub Actions [#4883](https://github.com/ruby/rubygems/pull/4883) + - Fix `bundle plugin install` detection of already installed plugins [#4869](https://github.com/ruby/rubygems/pull/4869) + - Make plugin installation idempotent [#4864](https://github.com/ruby/rubygems/pull/4864) + - Fix `bundle check` showing duplicated gems when multiple platforms are locked [#4854](https://github.com/ruby/rubygems/pull/4854) + - Fix `bundle check` incorrectly considering cached gems [#4853](https://github.com/ruby/rubygems/pull/4853) + +## 2.2.26 (2021-08-17) + +### Enhancements: + + - Remove `RUBYGEMS_GEMDEPS` warning [#4827](https://github.com/ruby/rubygems/pull/4827) + - Better defaults for GitHub Actions template generated by `bundle gem` [#4619](https://github.com/ruby/rubygems/pull/4619) + - Make `bundle exec` keep file descriptors by default [#4812](https://github.com/ruby/rubygems/pull/4812) + - Exclude gemspec file itself from file list of gems generated by `bundle gem` [#4650](https://github.com/ruby/rubygems/pull/4650) + - Fix a couple small typos in deprecation / error messages [#4806](https://github.com/ruby/rubygems/pull/4806) + - Make script generated by `bundle install --standalone` resilient to moving the application to a differently nested folder when `path` sources are used [#4792](https://github.com/ruby/rubygems/pull/4792) + - Exclude CI files and issue templates from file list of gems generated by `bundle gem` [#4033](https://github.com/ruby/rubygems/pull/4033) + +### Bug fixes: + + - Respect `BUNDLE_USER_HOME` env when choosing config location [#4828](https://github.com/ruby/rubygems/pull/4828) + - Fix `bundle gem` on path with spaces [#4816](https://github.com/ruby/rubygems/pull/4816) + - Fix bundler hitting the network in some cases where not allowed [#4805](https://github.com/ruby/rubygems/pull/4805) + +## 2.2.25 (2021-07-30) + +### Deprecations: + + - Deprecate Gemfile without an explicit global source [#4779](https://github.com/ruby/rubygems/pull/4779) + - Deprecate `bundle cache --path` [#4496](https://github.com/ruby/rubygems/pull/4496) + +### Enhancements: + + - Give better errors when materialization fails [#4788](https://github.com/ruby/rubygems/pull/4788) + - Lazily load `shellwords` library [#4786](https://github.com/ruby/rubygems/pull/4786) + - Show original error and backtrace directly on `bundle install` errors instead of a more brittle `gem install` hint [#4778](https://github.com/ruby/rubygems/pull/4778) + - Remove LoadError message in regards to requiring a relative file [#4772](https://github.com/ruby/rubygems/pull/4772) + +### Bug fixes: + + - Fix `BUNDLE_USER_CONFIG` no longer respected as config location [#4797](https://github.com/ruby/rubygems/pull/4797) + - Fix `--standalone` installation of default gems [#4782](https://github.com/ruby/rubygems/pull/4782) + - Fix `--quiet` flag not printing warnings [#4781](https://github.com/ruby/rubygems/pull/4781) + - Fix bundler binstub version selection [#4775](https://github.com/ruby/rubygems/pull/4775) + - Fix interrupt handling in Bundler workers [#4767](https://github.com/ruby/rubygems/pull/4767) + +## 2.2.24 (2021-07-15) + +### Bug fixes: + + - Fix development gem unintentionally removed on an edge case [#4751](https://github.com/ruby/rubygems/pull/4751) + - Fix dangling empty plugin hooks [#4755](https://github.com/ruby/rubygems/pull/4755) + - Fix `bundle plugin install --help` showing `bundle install`'s help [#4756](https://github.com/ruby/rubygems/pull/4756) + - Make sure `bundle check` shows uniq missing gems [#4749](https://github.com/ruby/rubygems/pull/4749) + +### Performance: + + - Slightly speed up `bundler/setup` [#4750](https://github.com/ruby/rubygems/pull/4750) + +## 2.2.23 (2021-07-09) + +### Enhancements: + + - Fix `bundle install` on truffleruby selecting incorrect variant for `sorbet-static` gem [#4625](https://github.com/ruby/rubygems/pull/4625) + - Spare meaningless warning on read-only bundle invocations [#4724](https://github.com/ruby/rubygems/pull/4724) + +### Bug fixes: + + - Fix incorrect warning about duplicated gems in the Gemfile [#4732](https://github.com/ruby/rubygems/pull/4732) + - Fix `bundle plugin install foo` crashing [#4734](https://github.com/ruby/rubygems/pull/4734) + +## 2.2.22 (2021-07-06) + +### Enhancements: + + - Never downgrade indirect dependencies when running `bundle update` [#4713](https://github.com/ruby/rubygems/pull/4713) + - Fix `getaddrinfo` errors not treated as fatal on non darwin platforms [#4703](https://github.com/ruby/rubygems/pull/4703) + +### Bug fixes: + + - Fix `bundle update ` sometimes hanging and `bundle lock --update` not being able to update an insecure lockfile to the new format if it requires downgrades [#4652](https://github.com/ruby/rubygems/pull/4652) + - Fix edge case combination of DSL methods and duplicated sources causing gems to not be found [#4711](https://github.com/ruby/rubygems/pull/4711) + - Fix `bundle doctor` crashing when finding a broken symlink [#4707](https://github.com/ruby/rubygems/pull/4707) + - Fix incorrect re-resolve edge case [#4700](https://github.com/ruby/rubygems/pull/4700) + - Fix some gems being unintentionally locked under multiple lockfile sections [#4701](https://github.com/ruby/rubygems/pull/4701) + - Fix `--conservative` flag unexpectedly updating indirect dependencies. NOTE: As part of this bug fix, some undocumented, unintentional code causing `bundle update --source ` to update conservatively was fixed. Use the documented `bundle update --conservative ` instead [#4692](https://github.com/ruby/rubygems/pull/4692) + +## 2.2.21 (2021-06-23) + +### Security fixes: + + - Auto-update insecure lockfile to split GEM source sections whenever possible [#4647](https://github.com/ruby/rubygems/pull/4647) + +### Enhancements: + + - Use a more limited number of threads when fetching in parallel from the Compact Index API [#4670](https://github.com/ruby/rubygems/pull/4670) + - Update TODO link in bundle gem template to https [#4671](https://github.com/ruby/rubygems/pull/4671) + +### Bug fixes: + + - Fix `bundle install --local` hitting the network when `cache_all_platforms` configured [#4677](https://github.com/ruby/rubygems/pull/4677) + +## 2.2.20 (2021-06-11) + +### Enhancements: + + - Don't print bug report template on server side errors [#4663](https://github.com/ruby/rubygems/pull/4663) + - Don't load `resolv` unnecessarily [#4640](https://github.com/ruby/rubygems/pull/4640) + +### Bug fixes: + + - Fix `bundle outdated` edge case [#4648](https://github.com/ruby/rubygems/pull/4648) + - Fix `bundle check` with scoped rubygems sources [#4639](https://github.com/ruby/rubygems/pull/4639) + +### Performance: + + - Don't use `extra_rdoc_files` with md files in gemspec to make installing bundler with docs faster [#4628](https://github.com/ruby/rubygems/pull/4628) + +## 2.2.19 (2021-05-31) + +### Bug fixes: + + - Restore support for configuration keys with dashes [#4582](https://github.com/ruby/rubygems/pull/4582) + - Fix some cached gems being unintentionally ignored when using rubygems 3.2.18 [#4623](https://github.com/ruby/rubygems/pull/4623) + +## 2.2.18 (2021-05-25) + +### Security fixes: + + - Fix dependency confusion issues with implicit dependencies [#4609](https://github.com/ruby/rubygems/pull/4609) + +### Enhancements: + + - Use simpler notation for generated `required_ruby_version` [#4598](https://github.com/ruby/rubygems/pull/4598) + - Undeprecate bundle show [#4586](https://github.com/ruby/rubygems/pull/4586) + - Make sure link to new issue uses the proper template [#4592](https://github.com/ruby/rubygems/pull/4592) + +### Bug fixes: + + - Fix platform specific gems being removed from the lockfile [#4580](https://github.com/ruby/rubygems/pull/4580) + +## 2.2.17 (2021-05-05) + +### Enhancements: + + - Improve authentication required error message to include an alternative using `ENV` [#4565](https://github.com/ruby/rubygems/pull/4565) + - Discard partial range responses without etag [#4563](https://github.com/ruby/rubygems/pull/4563) + - Fix configuring ENV for a gem server with a name including dashes [#4571](https://github.com/ruby/rubygems/pull/4571) + - Redact credentials from `bundle env` and `bundle config` [#4566](https://github.com/ruby/rubygems/pull/4566) + - Redact all sources in verbose mode [#4564](https://github.com/ruby/rubygems/pull/4564) + - Improve `bundle pristine` error if `BUNDLE_GEMFILE` does not exist [#4536](https://github.com/ruby/rubygems/pull/4536) + - [CurrentRuby] Add 3.0 as a known minor [#4535](https://github.com/ruby/rubygems/pull/4535) + - Prefer File.read instead of IO.read [#4530](https://github.com/ruby/rubygems/pull/4530) + - Add space after open curly bracket in Gemfile and gems.rb template [#4518](https://github.com/ruby/rubygems/pull/4518) + +### Bug fixes: + + - Make sure specs are fetched from the right source when materializing [#4562](https://github.com/ruby/rubygems/pull/4562) + - Fix `bundle cache` with an up-to-date lockfile and specs not already installed [#4554](https://github.com/ruby/rubygems/pull/4554) + - Ignore `deployment` setting in inline mode [#4523](https://github.com/ruby/rubygems/pull/4523) + +### Performance: + + - Don't materialize resolutions when not necessary [#4556](https://github.com/ruby/rubygems/pull/4556) + +## 2.2.16 (2021-04-08) + +### Enhancements: + + - Add `--github-username` option and config to `bundle gem` [#3687](https://github.com/ruby/rubygems/pull/3687) + - Bump vendored `tmpdir` library copy [#4506](https://github.com/ruby/rubygems/pull/4506) + - Add `rake build:checksum` task to build checksums for a gem package [#4156](https://github.com/ruby/rubygems/pull/4156) + - Enable bundler-cache for GitHub Actions template [#4498](https://github.com/ruby/rubygems/pull/4498) + - Improve `bundle info` error when gem is on a "disabled" group [#4492](https://github.com/ruby/rubygems/pull/4492) + - Small tweak to yank message [#4494](https://github.com/ruby/rubygems/pull/4494) + - Don't show duplicate entries in `bundle outdated` output [#4474](https://github.com/ruby/rubygems/pull/4474) + - Never downgrade top level gems when running `bundle update` [#4473](https://github.com/ruby/rubygems/pull/4473) + +### Bug fixes: + + - Fix incorrect logic for filtering metadata matching candidates [#4497](https://github.com/ruby/rubygems/pull/4497) + +## 2.2.15 (2021-03-19) + +### Enhancements: + + - Add a hint about bundler installing executables for path gems [#4461](https://github.com/ruby/rubygems/pull/4461) + - Warn lockfiles with incorrect resolutions [#4459](https://github.com/ruby/rubygems/pull/4459) + - Don't generate duplicate redundant sources in the lockfile [#4456](https://github.com/ruby/rubygems/pull/4456) + +### Bug fixes: + + - Respect running ruby when resolving platforms [#4449](https://github.com/ruby/rubygems/pull/4449) + +## 2.2.14 (2021-03-08) + +### Security fixes: + + - Lock GEM sources separately and fix locally installed specs confusing bundler [#4381](https://github.com/ruby/rubygems/pull/4381) + +### Bug fixes: + + - Make `rake` available to other gems' installers right after it's installed [#4428](https://github.com/ruby/rubygems/pull/4428) + - Fix encoding issue on compact index updater [#4362](https://github.com/ruby/rubygems/pull/4362) + +## 2.2.13 (2021-03-03) + +### Enhancements: + + - Respect user configured default branch in README links in new generated gems [#4303](https://github.com/ruby/rubygems/pull/4303) + +### Bug fixes: + + - Fix gems sometimes being pulled from irrelevant sources [#4418](https://github.com/ruby/rubygems/pull/4418) + +## 2.2.12 (2021-03-01) + +### Bug fixes: + + - Fix sporadic warnings about `nil` gemspec on install/update and make those faster [#4409](https://github.com/ruby/rubygems/pull/4409) + - Fix deployment install with duplicate path gems added to Gemfile [#4410](https://github.com/ruby/rubygems/pull/4410) + +## 2.2.11 (2021-02-17) + +### Bug fixes: + + - Revert disable_multisource changes [#4385](https://github.com/ruby/rubygems/pull/4385) + +## 2.2.10 (2021-02-15) + +### Security fixes: + + - Fix source priority for transitive dependencies and split lockfile rubygems source sections [#3655](https://github.com/ruby/rubygems/pull/3655) + +### Bug fixes: + + - Fix adding platforms to lockfile sometimes conflicting on ruby requirements [#4371](https://github.com/ruby/rubygems/pull/4371) + - Fix bundler sometimes choosing ruby variants over java ones [#4367](https://github.com/ruby/rubygems/pull/4367) + +### Documentation: + + - Update man pages to reflect to new default for bundle install jobs [#4188](https://github.com/ruby/rubygems/pull/4188) + +## 2.2.9 (2021-02-08) + +### Enhancements: + + - Stop removing existing platforms when force_ruby_platform is true [#4336](https://github.com/ruby/rubygems/pull/4336) + +### Bug fixes: + + - Don't install platform specific gems on truffleruby [#4333](https://github.com/ruby/rubygems/pull/4333) + +## 2.2.8 (2021-02-02) + +### Enhancements: + + - Add a CHANGELOG.md file to gems generated by `bundle gem` [#4093](https://github.com/ruby/rubygems/pull/4093) + - Support gemified `set` [#4297](https://github.com/ruby/rubygems/pull/4297) + +### Bug fixes: + + - Fix standalone Kernel.require visibility [#4337](https://github.com/ruby/rubygems/pull/4337) + +### Performance: + + - Fix resolver edge cases and speed up bundler [#4277](https://github.com/ruby/rubygems/pull/4277) + +## 2.2.7 (2021-01-26) + +### Enhancements: + + - Improve error messages when dependency on bundler conflicts with running version [#4308](https://github.com/ruby/rubygems/pull/4308) + - Avoid showing platforms with requirements in error messages [#4310](https://github.com/ruby/rubygems/pull/4310) + - Introduce disable_local_revision_check config [#4237](https://github.com/ruby/rubygems/pull/4237) + - Reverse rubygems require mixin with bundler standalone [#4299](https://github.com/ruby/rubygems/pull/4299) + +### Bug fixes: + + - Fix releasing from a not yet pushed branch [#4309](https://github.com/ruby/rubygems/pull/4309) + - Install cache only once if it already exists [#4304](https://github.com/ruby/rubygems/pull/4304) + - Fix `force_ruby_platform` no longer being respected [#4302](https://github.com/ruby/rubygems/pull/4302) + +### Performance: + + - Fix resolver dependency comparison [#4289](https://github.com/ruby/rubygems/pull/4289) + +## 2.2.6 (2021-01-18) + +### Enhancements: + + - Improve resolver debugging [#4288](https://github.com/ruby/rubygems/pull/4288) + +### Bug fixes: + + - Fix dependency locking for path source [#4293](https://github.com/ruby/rubygems/pull/4293) + +### Performance: + + - Speed up complex dependency resolves by creating DepProxy factory and cache [#4216](https://github.com/ruby/rubygems/pull/4216) + +## 2.2.5 (2021-01-11) + +### Enhancements: + + - Improve rubocop setup in the new gem template [#4220](https://github.com/ruby/rubygems/pull/4220) + - Support repositories with default branch not named master [#4224](https://github.com/ruby/rubygems/pull/4224) + +### Bug fixes: + + - Let Net::HTTP decompress the index instead of doing it manually [#4081](https://github.com/ruby/rubygems/pull/4081) + - Workaround for another jruby crash when autoloading a constant [#4252](https://github.com/ruby/rubygems/pull/4252) + - Fix another performance regression in the resolver [#4243](https://github.com/ruby/rubygems/pull/4243) + - Restore support for old git versions [#4233](https://github.com/ruby/rubygems/pull/4233) + - Give a proper error if cache path does not have write access [#4215](https://github.com/ruby/rubygems/pull/4215) + - Fix running `rake release` from an ambiguous ref [#4219](https://github.com/ruby/rubygems/pull/4219) + +## 2.2.4 (2020-12-31) + +### Bug fixes: + + - Fix bundle man pages display on truffleruby [#4209](https://github.com/ruby/rubygems/pull/4209) + - Fix Windows + JRuby no longer being able to install git sources [#4196](https://github.com/ruby/rubygems/pull/4196) + +## 2.2.3 (2020-12-22) + +### Bug fixes: + + - Restore full compatibility with previous lockfiles [#4179](https://github.com/ruby/rubygems/pull/4179) + - Add all matching variants with the same platform specificity to the lockfile [#4180](https://github.com/ruby/rubygems/pull/4180) + - Fix bundler installing gems for a different platform when running in frozen mode and current platform not in the lockfile [#4172](https://github.com/ruby/rubygems/pull/4172) + - Fix crash when `bundle exec`'ing to bundler [#4175](https://github.com/ruby/rubygems/pull/4175) + +## 2.2.2 (2020-12-17) + +### Bug fixes: + + - Fix resolver crash when a candidate has 0 matching platforms [#4163](https://github.com/ruby/rubygems/pull/4163) + - Restore change to copy global with/without config locally upon `bundle install` [#4154](https://github.com/ruby/rubygems/pull/4154) + +## 2.2.1 (2020-12-14) + +### Bug fixes: + + - Ad-hoc fix for platform regression [#4127](https://github.com/ruby/rubygems/pull/4127) + - Workaround JRuby + Windows issue with net-http-persistent vendored code [#4138](https://github.com/ruby/rubygems/pull/4138) + - Reset also root when in a nested invocation [#4140](https://github.com/ruby/rubygems/pull/4140) + - Restore 2.1.4 resolution times [#4134](https://github.com/ruby/rubygems/pull/4134) + - Fix `bundle outdated --strict` crash [#4133](https://github.com/ruby/rubygems/pull/4133) + - Autoload `Bundler::RemoteSpecification` to workaround crash on jruby [#4114](https://github.com/ruby/rubygems/pull/4114) + +## 2.2.0 (2020-12-07) + +### Enhancements: + + - New gem template: prefer `require_relative` to `require` [#4066](https://github.com/ruby/rubygems/pull/4066) + - Always show underlying error when fetching specs fails [#4061](https://github.com/ruby/rubygems/pull/4061) + - Add `--all-platforms` flag to `bundle binstubs` to generate binstubs for all platforms [#3886](https://github.com/ruby/rubygems/pull/3886) + - Improve gem not found in source error messages [#4019](https://github.com/ruby/rubygems/pull/4019) + - Revert resolving all Gemfile platforms automatically [#4052](https://github.com/ruby/rubygems/pull/4052) + - Remove extra empty line from README template [#4041](https://github.com/ruby/rubygems/pull/4041) + - Lazily load `erb` [#4011](https://github.com/ruby/rubygems/pull/4011) + +### Bug fixes: + + - Fix `Bundler::Plugin::API::Source#to_s` having empty source type [#4084](https://github.com/ruby/rubygems/pull/4084) + - Raise consistent errors with or without `bundle exec` [#4063](https://github.com/ruby/rubygems/pull/4063) + - Fix edge case resulting in a crash when using `zeitwerk` inside a nested `bundle exec` invocation [#4062](https://github.com/ruby/rubygems/pull/4062) + - Enable `specific_platform` by default [#4015](https://github.com/ruby/rubygems/pull/4015) + - Prevent remove command from deleting gemfile lines that are comments [#4045](https://github.com/ruby/rubygems/pull/4045) + - Fix issue with `cache_all_platforms` and `specific_platform` configured [#4042](https://github.com/ruby/rubygems/pull/4042) + - Fix incorrect error message on Windows [#4039](https://github.com/ruby/rubygems/pull/4039) + - Make printed drive letters consistent on Windows [#4038](https://github.com/ruby/rubygems/pull/4038) + - Load rubygems plugins from RUBYLIB during `bundle install` and `bundle update` [#3534](https://github.com/ruby/rubygems/pull/3534) + - Fix `specific_platform` and `cache_all` with `bundle cache --all-platforms` [#4022](https://github.com/ruby/rubygems/pull/4022) + - Bring back the possibility to install a plugin from path [#4020](https://github.com/ruby/rubygems/pull/4020) + - Move ronn pages to lib [#3997](https://github.com/ruby/rubygems/pull/3997) + - Fix fileutils double load when using `bundler/inline` [#3991](https://github.com/ruby/rubygems/pull/3991) + - Accept responses with no etag header [#3865](https://github.com/ruby/rubygems/pull/3865) + +### Documentation: + + - Fix typo of `bundle-install.1` (v2.1) [#4079](https://github.com/ruby/rubygems/pull/4079) + - Add commented out example and more information link to generated gemspec [#4034](https://github.com/ruby/rubygems/pull/4034) + +## 2.2.0.rc.2 (2020-10-06) + +### Features: + + - Add `bundle fund` command [#3390](https://github.com/ruby/rubygems/pull/3390) + +### Enhancements: + + - Fix ls-files matching regexp [#3845](https://github.com/ruby/rubygems/pull/3845) + - Remove redundant `bundler/setup` require from `spec_helper.rb` generated by `bundle gem` [#3791](https://github.com/ruby/rubygems/pull/3791) + +### Bug fixes: + + - Deduplicate spec groups [#3965](https://github.com/ruby/rubygems/pull/3965) + - Fix some cases of running `bundler` on a path including brackets [#3854](https://github.com/ruby/rubygems/pull/3854) + - Don't warn when deinit'ing submodules [#3969](https://github.com/ruby/rubygems/pull/3969) + - Make `bundle clean --force` leave default gem executables untouched [#3907](https://github.com/ruby/rubygems/pull/3907) + - Prioritize `path.system` over `path` when it makes sense [#3933](https://github.com/ruby/rubygems/pull/3933) + - Sort requirements in Gem::Requirement to succeed comparison with different order [#3889](https://github.com/ruby/rubygems/pull/3889) + - Print bug report template to standard error [#3924](https://github.com/ruby/rubygems/pull/3924) + - Restore `bundle cache --all` in all cases [#3914](https://github.com/ruby/rubygems/pull/3914) + - Move shebang to the top of `bin/console` template [#3927](https://github.com/ruby/rubygems/pull/3927) + - Fix platform issues when running under a frozen bundle [#3909](https://github.com/ruby/rubygems/pull/3909) + - Fix deprecation messages for `bundle install` flags, the config should be --local as before [#3917](https://github.com/ruby/rubygems/pull/3917) + - Look for absolute path when removing bundler/setup from RUBYOPT in Bundler.unbundled_env method [#3877](https://github.com/ruby/rubygems/pull/3877) + - Fix incorrect re-resolution when path gem excluded and not available [#3902](https://github.com/ruby/rubygems/pull/3902) + - Fix error when building error message in `bundler/inline` [#3901](https://github.com/ruby/rubygems/pull/3901) + - Fix regression related to locked ruby [#3900](https://github.com/ruby/rubygems/pull/3900) + - Expand load paths in standalone setup.rb file [#3522](https://github.com/ruby/rubygems/pull/3522) + - Fix broken exception recovery code when installing plugins [#3487](https://github.com/ruby/rubygems/pull/3487) + - Fix incorrect build info on development versions of bundler, and on bundler versions installed as a default gem [#3778](https://github.com/ruby/rubygems/pull/3778) + - Avoid autoloading `openssl` to try help with jruby load service issues [#3809](https://github.com/ruby/rubygems/pull/3809) + - Fix `rake release` pushing all local tags instead of only the release tag [#3785](https://github.com/ruby/rubygems/pull/3785) + - Fix `rake release` aborting when credentials file is missing, even if properly configured through XDG [#3783](https://github.com/ruby/rubygems/pull/3783) + +### Deprecations: + + - Deprecate `bundle cache --all` flag [#3932](https://github.com/ruby/rubygems/pull/3932) + +### Documentation: + + - Correct grammar in Gemfile docs [#3990](https://github.com/ruby/rubygems/pull/3990) + - Fix typo in `bundle pristine` warning message [#3959](https://github.com/ruby/rubygems/pull/3959) + - Improve human readable fallback version of CLI help messages [#3921](https://github.com/ruby/rubygems/pull/3921) + - Note CLI flag deprecations in documentation [#3915](https://github.com/ruby/rubygems/pull/3915) + - Update man page and deprecation warning for binstubs --all [#3872](https://github.com/ruby/rubygems/pull/3872) + +## 2.2.0.rc.1 (2020-07-02) + +### Features: + + - Windows support. There's still gotchas and unimplemented features, but a Windows CI is now enforced. + - Full multiplatform support. Bundler should now seamlessly handle multiplatform `Gemfile` or `gems.rb` files. + +### Enhancements: + + - `bundle info` now includes gem metadata [#7376](https://github.com/rubygems/bundler/pull/7376) + - `bundle list --without-group` and `bundle list --only-group` now support space separated list of groups in addition to single groups [#7404](https://github.com/rubygems/bundler/pull/7404) + - `bundle gem` now supports a `--rubocop` flag that adds the `rubocop` gem to the new gem layout [#6455](https://github.com/rubygems/bundler/pull/6455) + - `bundle gem` now supports `--test-unit` in addition to `rspec` and `minitest` as a value for its `--test` option [#5521](https://github.com/rubygems/bundler/pull/5521) + - `bundle install` now uses the available number of processors automatically for concurrent gem install, except for Windows where it still uses a single thread by default [#3393](https://github.com/ruby/rubygems/pull/3393) and [#3718](https://github.com/ruby/rubygems/pull/3718) + - Report Gitlab CI within bundler user-agent string [#3432](https://github.com/ruby/rubygems/pull/3432) + - Add `bundle plugin uninstall` [#3482](https://github.com/ruby/rubygems/pull/3482) + - `bundle gem` now supports a `--ci` flag and a `gem.ci` configuration that adds CI config files for the main CI providers to the generated gem skeleton [#3667](https://github.com/ruby/rubygems/pull/3667) + - Allow setting a tag prefix to be used by release tasks [#3766](https://github.com/ruby/rubygems/pull/3766) + - `bundle outdated` now prints output in columns for better readability [#4474](https://github.com/rubygems/bundler/pull/4474) + - bundler's `release` rake task now prints a better message when not being logged in and trying to push a gem [#7513](https://github.com/rubygems/bundler/pull/7513) + - `BUNDLE_APP_CONFIG` environment variable is now documented [#7563](https://github.com/rubygems/bundler/pull/7563) + - Original exception is now reported when bundler fails to load OpenSSL [#7527](https://github.com/rubygems/bundler/pull/7527) + - RVM specific instructions for recompiling ruby is no longer recommended when bundler fails to load OpenSSL [#7597](https://github.com/rubygems/bundler/pull/7597) + - Improve resolver debugging out from resolver [#7589](https://github.com/rubygems/bundler/pull/7589) and [#7590](https://github.com/rubygems/bundler/pull/7590) + - Clarify `bundle config --local` docs [#3408](https://github.com/ruby/rubygems/pull/3408) + - Make sure to not "leak" to a different bundler install under any circumstances [#3595](https://github.com/ruby/rubygems/pull/3595) + - Make sure users messing with `$;` doesn't affect us [#3602](https://github.com/ruby/rubygems/pull/3602) + - Remove explicit psych activation which could potentially lead to packaging-specific issues [#3638](https://github.com/ruby/rubygems/pull/3638) + - Deprecate `--no-deployment` flag and never recommend it [#3657](https://github.com/ruby/rubygems/pull/3657) + - `bundle gem` test framework defaults to the `gem.test` setting and asks for a value without overwriting configuration if `-t` without a value is passed explicitly [#3544](https://github.com/ruby/rubygems/pull/3544) + - `bundle gem` now ships with a default `.rubocop.yml` file and an offense free initial gem skeleton [#3731](https://github.com/ruby/rubygems/pull/3731), [#3740](https://github.com/ruby/rubygems/pull/3740), [#3765](https://github.com/ruby/rubygems/pull/3765) + - Remove some requires that might workaround some autoloading issues on jruby [#3771](https://github.com/ruby/rubygems/pull/3771) + - Unswallow an error that should make some random crashes on jruby easier to troubleshoot [#3774](https://github.com/ruby/rubygems/pull/3774) + +### Bug fixes: + + - Fix `bundle pristine` removing gems with local overrides. Be conservative by printing a warning and skipping the removal [#7423](https://github.com/rubygems/bundler/pull/7423) + - Fix multiplaform resolution edge cases [#7522](https://github.com/rubygems/bundler/pull/7522) and [#7578](https://github.com/rubygems/bundler/pull/7578) + - Fix ruby version conflicts not displaying the current ruby version [7559](https://github.com/rubygems/bundler/pull/7559) + - Fix `Gemfile` or `gems.rb` files containing `:path` gems using relative paths not working when the app is packaged as a `jar` with `warbler` [#7614](https://github.com/rubygems/bundler/pull/7614) + - Fix config location edge case where if `BUNDLE_APP_CONFIG` is set to an absolute path like in official ruby docker images, and there's no Gemfile up in the directory hierarchy, bundler would end up using the default config location instead of the customized one [#7622](https://github.com/rubygems/bundler/pull/7622) + - Fix error message about missing permissions recommending a deprecated command [#7633](https://github.com/rubygems/bundler/pull/7633) + - Fix `init_gems_rb` setting being ignored by `bundle gem` [#7629](https://github.com/rubygems/bundler/pull/7629) + - Fix "unresolvable warning" being printed on `bundle install` of multipliplatform `Gemfile` or `gems.rb` files without lockfiles, multiplatform is now managed automatically [#7580](https://github.com/rubygems/bundler/pull/7580) + - Fix setting the number of `--jobs` to be one unit less than specified to the CLI [#3393](https://github.com/ruby/rubygems/pull/3393) + - Fix extension building when the same git source specifies several gems with extensions [#3475](https://github.com/ruby/rubygems/pull/3475) + - Fix uninitialized instance variable warning under ruby-head (2.8-dev) [#3477](https://github.com/ruby/rubygems/pull/3477) + - Fix double chdir warning while installing a git gem with extensions [#3479](https://github.com/ruby/rubygems/pull/3479) + - Fix some deprecations not showing up when CLI flags passed as `--flag=value` [#3561](https://github.com/ruby/rubygems/pull/3561) + - Fix man pages display when bundler installed as a default gem [#3562](https://github.com/ruby/rubygems/pull/3562) + - Fix bundler gem tasks not handling relative paths [#3586](https://github.com/ruby/rubygems/pull/3586) + - Fix deprecation warnings when options the dashed names are used, such as `--no-prune` [#3623](https://github.com/ruby/rubygems/pull/3623) + - Fix crash related to bundler gem activation under old rubygems version (2.6.1 or older) [#3626](https://github.com/ruby/rubygems/pull/3626) + - Avoid stack overflow inside `StubSpecification` on some edge cases [#3635](https://github.com/ruby/rubygems/pull/3635) + - Fix `bundle remove` with multiline gem specifications [#3400](https://github.com/ruby/rubygems/pull/3400) + - Fix `bundle info` not informing about deleted gems as opposed to old `bundle show` [#3509](https://github.com/ruby/rubygems/pull/3509) + - The `--no-deployment` flag to `bundle install` was deprecated just like the other flags that rely on their value being remembered [#3657](https://github.com/ruby/rubygems/pull/3657) + - Fix `bundle install` unintentionally copying `with` and `without` global config to local configuration [#3666](https://github.com/ruby/rubygems/pull/3666). This PR also address the `BUNDLE_WITH` environment variable unintentionally being persisted to configuration in a similar way ([#3708](https://github.com/ruby/rubygems/issues/3708)) + - Fix race condition in `bundle install` that could "empty" exceptions to be raised [#3669](https://github.com/ruby/rubygems/pull/3669) + - Fix `--no-cache` to `bundle install` being unintentionally deprecated [#3688](https://github.com/ruby/rubygems/pull/3688) + - Avoid calling `LoadError#message` to fix performance regression in future ruby 3.0 [#3762](https://github.com/ruby/rubygems/pull/3762) + +## 2.1.4 (2020-01-05) + +### Bug fixes: + + - Fix `net-http-pipeline` no longer being allowed in Gemfiles if already installed in the system due to our vendored version of `net-http-persistent` optionally requiring it [#7529](https://github.com/bundler/bundler/pull/7529) + - Fix inline gems no longer being requirable if no Gemfile is present in the directory hierarchy [#7537](https://github.com/bundler/bundler/pull/7537) + +## 2.1.3 (2020-01-02) + +### Bug fixes: + + - Fix `rake build` when path has spaces on it [#7514](https://github.com/bundler/bundler/pull/7514) + - Fix `rake release` git push tasks when the running shell has `git` as an alias of another command (like `hub`) [#7510](https://github.com/bundler/bundler/pull/7510) + - Fix some circular require warnings [#7520](https://github.com/bundler/bundler/pull/7520) + - Fix `bundle config set deployment true` recommended alternative to `bundle config --deployment` to behave in the same way as the `--deployment` flag [#7519](https://github.com/bundler/bundler/pull/7519) + +## 2.1.2 (2019-12-20) + +### Bug fixes: + + - Restore an explicit `require "rubygems"` on top `rubygems_integration.rb` to avoid some missing constant errors under some convoluted setups [#7505](https://github.com/rubygems/bundler/pull/7505) + +## 2.1.1 (2019-12-17) + +### Bug fixes: + + - Fix some cases of shelling out to `rubygems` still being silent [#7493](https://github.com/rubygems/bundler/pull/7493) + - Restore compatibility with `rubygems-bundler` so that binstubs work under `RVM` [#7498](https://github.com/rubygems/bundler/pull/7498) + +## 2.1.0 (2019-12-15) + +### Features: + + - Add support for new default gems. In particular, + + * `open3` [#7455](https://github.com/rubygems/bundler/pull/7455) + * `cgi`: [#7456](https://github.com/rubygems/bundler/pull/7456) + * `uri` [#7460](https://github.com/rubygems/bundler/pull/7460) + + plus other PRs removing or lazily loading usages of these gems from other places to not interfere with user's choice, such as [#7471](https://github.com/rubygems/bundler/pull/7471) or [#7473](https://github.com/bundler/bundler/pull/7473) + +### Bug fixes: + + - Fix `bundle exec rake install` failing [#7474](https://github.com/rubygems/bundler/pull/7474) + - Fix `bundle exec`'ing to rubygems being silent [#7442](https://github.com/rubygems/bundler/pull/7442) + - Restore previous `BUNDLE_GEMFILE` in `bundler/inline` [#7418](https://github.com/rubygems/bundler/pull/7418) + - Fix error when using `gem` DSL's `:glob` option for selecting gemspecs from a specific source [#7419](https://github.com/rubygems/bundler/pull/7419) + +### Enhancements: + + - `bundle config` no longer warns when using "old interface" (might be deprecated again in the future) [#7475](https://github.com/rubygems/bundler/pull/7475) + - `bundle update` no longer warns when used without arguments (might be deprecated again in the future) [#7475](https://github.com/rubygems/bundler/pull/7475) + +## 2.1.0.pre.3 (2019-11-12) + +### Features: + + - Add caller information to some deprecation messages to make them easier to fix [#7361](https://github.com/rubygems/bundler/pull/7361) + - Reconcile `bundle cache` vs `bundle package` everywhere. Now in docs, CLI help and everywhere else `bundle cache` is the preferred version and `bundle package` remains as an alias [#7389](https://github.com/rubygems/bundler/pull/7389) + - Display some basic `bundler` documentation together with ruby's RDoc based documentation [#7394](https://github.com/rubygems/bundler/pull/7394) + +### Bug fixes: + + - Fix typos deprecation message and upgrading docs [#7374](https://github.com/rubygems/bundler/pull/7374) + - Deprecation warnings about `taint` usage on ruby 2.7 [#7385](https://github.com/rubygems/bundler/pull/7385) + - Fix `--help` flag not correctly delegating to `man` when used with command aliases [#7388](https://github.com/rubygems/bundler/pull/7388) + - `bundle add` should cache newly added gems if an application cache exists [#7393](https://github.com/rubygems/bundler/pull/7393) + - Stop using an insecure folder as a "fallback home" when user home is not defined [#7416](https://github.com/rubygems/bundler/pull/7416) + - Fix `bundler/inline` warning about `Bundler.root` redefinition [#7417](https://github.com/rubygems/bundler/pull/7417) + +## 2.1.0.pre.2 (2019-09-15) + +### Bug fixes: + + - Fix `bundle clean` trying to delete non-existent directory ([#7340](https://github.com/rubygems/bundler/pull/7340)) + - Fix warnings about keyword argument separation on ruby 2.7 ([#7337](https://github.com/rubygems/bundler/pull/7337)) + +## 2.1.0.pre.1 (2019-08-28) + + One of the biggest changes in bundler 2.1.0 is that deprecations for upcoming + breaking changes in bundler 3 will be turned on by default. We do this to grab + feedback and communicate early to our users the kind of changes we're intending + to ship with bundler 3. See + [#6965](https://github.com/rubygems/bundler/pull/6965). + + Another important improvement is a better coexistence between bundler + installations and the default copy of bundler that comes with ruby installed as + a default gem. Since bundler is shipped as a default gem with ruby, a number of + users have been affected by issues where bundler ends up failing due to version + mismatches, because at some point of the execution, bundler switches to run the + default copy instead of the expected version. A number of PRs have been focused + on minimizing (hopefully eliminating) this, such as + [#7100](https://github.com/rubygems/bundler/pull/7100), + [#7137](https://github.com/rubygems/bundler/pull/7137), + [#6996](https://github.com/rubygems/bundler/pull/6996), + [#7056](https://github.com/rubygems/bundler/pull/7056), + [#7062](https://github.com/rubygems/bundler/pull/7062), + [#7193](https://github.com/rubygems/bundler/pull/7193), + [#7216](https://github.com/rubygems/bundler/pull/7216), + [#7274](https://github.com/rubygems/bundler/pull/7274) + +### Deprecations: + + * See the [the upgrading document](UPGRADING.md) for a detailed explanation of + the deprecations that are getting enabled in bundler 2.1, and the future + breaking changes in bundler 3. + +### Features: + + - Reimplement `config` command using subcommands ([#5981](https://github.com/rubygems/bundler/pull/5981)) + - Add `bundle plugin list` command ([#6120](https://github.com/rubygems/bundler/pull/6120)) + - Introduce a `bundle lock --gemfile` flag ([#6748](https://github.com/rubygems/bundler/pull/6748)) + - Add local git repository source option (`--local_git`) to plugin installation ([#6749](https://github.com/rubygems/bundler/pull/6749)) + - Add `quiet` flag to inline bundler ([#6828](https://github.com/rubygems/bundler/pull/6828)) + - Introduce a `prefer_patch` configuration that makes `bundle update` behave like `bundle update --patch` ([#6931](https://github.com/rubygems/bundler/pull/6931)) + - Introduce `Bundler.original_system` and `Bundler.original_exec` to shell out or exec to external programs using the original environment before bundler was loaded ([#7052](https://github.com/rubygems/bundler/pull/7052)) + - Add feature parity to `bundle info GEM` with respect to the old deprecated command `bundle show GEM` [#7026](https://github.com/rubygems/bundler/pull/7026) + - Introduce `bundle list` to list groups of gems in your Gemfile. This command was actually documented, but was working as an alias to `bundle show` so this could also be considered a bug fix :) [#7072](https://github.com/rubygems/bundler/pull/7072) + - Introduce `bundle outdated --filter-strict` as an alias to `bundle outdated --strict` [#6030](https://github.com/rubygems/bundler/pull/6030) + - Add `:git` and `:branch` options to `bundle add` ([#7127](https://github.com/rubygems/bundler/pull/7127)) + - Add `:ruby_26` as a valid value to the `:platform(s)` dsl ([#7155](https://github.com/rubygems/bundler/pull/7155)) + - Let the `bundle cache` command include all features currently provided by `bundle package` ([#7249](https://github.com/rubygems/bundler/pull/7249)) + - Several improvements on new gem templates ([#6924](https://github.com/rubygems/bundler/pull/6924), [#6968](https://github.com/bundler/bundler/pull/6968), [#7209](https://github.com/bundler/bundler/pull/7209), [#7222](https://github.com/bundler/bundler/pull/7222), [#7238](https://github.com/bundler/bundler/pull/7238)) + - Add `--[no-]git` option to `bundle gem` to generate non source control gems. Useful for monorepos, for example ([#7263](https://github.com/rubygems/bundler/pull/7263)) + +### Bug fixes: + + - Raise when the same gem is available in multiple sources, and show a suggestion to solve it ([#5985](https://github.com/rubygems/bundler/pull/5985)) + - Validate that bundler has permissions to write to the tmp directory, and raise with a meaningful error otherwise ([#5954](https://github.com/rubygems/bundler/pull/5954)) + - Remove downloaded `.gem` file from the cache if it's corrupted ([#6010](https://github.com/rubygems/bundler/pull/6010)) + - Fix generated README in new gems to explicitly suggest running `bundle install`, so that the outcome is independent from the major version of bundler being run ([#6068](https://github.com/rubygems/bundler/pull/6068)) + - Fix `bundle outdated --group NAME` when the group is listed second in the Gemfile ([#6116](https://github.com/rubygems/bundler/pull/6116)) + - Improve conflict resolution messages by not calling "ruby" a gem when conflict happens in the `required_ruby_version`, and by filtering out requirements that didn't contribute to the conflict ([#6647](https://github.com/rubygems/bundler/pull/6647)) + - Avoid fetching and rebuilding git gems whenever any gem is changed in the Gemfile ([#6711](https://github.com/rubygems/bundler/pull/6711)) + - Include the exact bundler version in the lockfile in the suggested command when bundler warns about version mismatches of itself [#6971](https://github.com/rubygems/bundler/pull/6971) + - Fix plugins being installed every time a command is run #[#6978](https://github.com/rubygems/bundler/pull/6978) + - Fallback to sequentially fetching specs on 429s [#6728](https://github.com/rubygems/bundler/pull/6728) + - Make `bundle clean` also clean native extensions for gems with a git source [#7058](https://github.com/rubygems/bundler/pull/7058) + - Fix `bundle info bundler` to show the correct path to the bundler gem [#7026](https://github.com/rubygems/bundler/pull/7026) + - Fix `bundle config build.` not sending multiple parameters to `extconf.rb` correctly [#7023](https://github.com/rubygems/bundler/pull/7023) + - Fix bad error message on Gemfile errors under ruby 2.7 (still unreleased, but it's a bugfix for beta testers after all) [#7038](https://github.com/rubygems/bundler/pull/7038) + - Warn about situations where multiple gems provide the same executable ([#7075](https://github.com/rubygems/bundler/pull/7075)) + - Ignore `frozen` setting in inline mode ([#7125](https://github.com/rubygems/bundler/pull/7125)) + - Fix incorrect "bundler attempted to update GEM but version stayed the same" message when updating git sourced gems ([#6325](https://github.com/rubygems/bundler/pull/6325)) + - Don't check for existence of a writable home directory if `BUNDLE_USER_HOME` is set ([#6885](https://github.com/rubygems/bundler/pull/6885)) + - Fix error message when server would respond to a bad username/password request with a 401 ([#6928](https://github.com/rubygems/bundler/pull/6928)) + - Fix `bundle outdated` pluralization when multiple groups are requested ([#7063](https://github.com/rubygems/bundler/pull/7063)) + - Fix `bundle install` not updating conservatively when gemspec is changed ([#7143](https://github.com/rubygems/bundler/pull/7143)) + - Fix `bundle exec` not respecting custom process titles inside scripts ([#7140](https://github.com/rubygems/bundler/pull/7140)) + - Fix `bundle update` message about exclude groups saying "installed" instead of "updated" ([#7150](https://github.com/rubygems/bundler/pull/7150)) + - Fix `bundle licenses` not showing correct information about bundler itself ([#7147](https://github.com/rubygems/bundler/pull/7147)) + - Fix installation path not including ruby scope when `BUNDLE_PATH` was set ([#7163](https://github.com/rubygems/bundler/pull/7163)) + - Fix `bundle clean` incorrectly removing git dependencies present in the Gemfile when rubygems 3.0+ was used and path involved a symlink ([#7211](https://github.com/rubygems/bundler/pull/7211)) + - Fix platform specific gems always being re-resolved when bundler was not running under that platform ([#7212](https://github.com/rubygems/bundler/pull/7212)) + - Fix `bundle package --all-platforms` causing `bundle install` to ignore `--with` and `--without` ([#6113](https://github.com/rubygems/bundler/pull/6113)) + - Fix `MissingRevision` git errors to include the specific `git` command that failed under the hood ([#7225](https://github.com/rubygems/bundler/pull/7225)) + - Fix using gemspec & `force_ruby_platform` on Windows ([#6809](https://github.com/rubygems/bundler/pull/6809)) + - Make bundler's binstub checks on bundler version consistent with rubygems `BundlerVersionFinder` ([#7259](https://github.com/rubygems/bundler/pull/7259)) + - Fix `bundle install` and `bundle update` generating different lockfiles when `path:` gems with relative paths starting with "./" were used ([#7264](https://github.com/rubygems/bundler/pull/7264)) + - Give a proper error when user tries to `bundle open` a default gem ([#7288](https://github.com/rubygems/bundler/pull/7288)) + - Fix `bundle doctor` command ([#7309](https://github.com/rubygems/bundler/pull/7309)) + - Fix bundler giving an unclear recommendation when duplicated gems are found in the Gemfile ([#7302](https://github.com/rubygems/bundler/pull/7302)) + +### Documentation: + + - Fix typo on a file extension in `bundle.ronn` [#7146](https://github.com/rubygems/bundler/pull/7146) + - Fix incorrect default value for `cache_path` configuration ([#7229](https://github.com/rubygems/bundler/pull/7229)) + - Binstubs documentation has been improved ([#5889](https://github.com/rubygems/bundler/pull/5889)) + - Fix incorrect sections when explaining `:git`, `:branch`, and `:ref` options ([#7265](https://github.com/rubygems/bundler/pull/7265)) + - Fix mentions to remembered options in docs to explain the current state ([#7242](https://github.com/rubygems/bundler/pull/7242)) + + Internally, there's also been a bunch of improvements in our development + environment, test suite, policies, contributing docs, and a bunch of cleanups of + old compatibility code. + +## 2.0.2 (2019-06-13) + +### Enhancements: + + - Fixes for Bundler integration with ruby-src ([#6941](https://github.com/rubygems/bundler/pull/6941), [#6973](https://github.com/bundler/bundler/pull/6973), [#6977](https://github.com/bundler/bundler/pull/6977), [#6315](https://github.com/bundler/bundler/pull/6315), [#7061](https://github.com/bundler/bundler/pull/7061)) + - Use `__dir__` instead of `__FILE__` when generating a gem with `bundle gem` ([#6503](https://github.com/rubygems/bundler/pull/6503)) + - Use `https` on externals links in the Bundler gemspec ([#6721](https://github.com/rubygems/bundler/pull/6721)) + - Removed duplicate gem names from the suggested `did you mean` list for gem typos ([#6739](https://github.com/rubygems/bundler/pull/6739)) + - Removed Ruby 1.x compatibility code ([#6764](https://github.com/rubygems/bundler/pull/6764), [#6806](https://github.com/bundler/bundler/pull/6806)) + - Fixed an issue where `bundle remove` would crash with certain Gemfiles ([#6768](https://github.com/rubygems/bundler/pull/6769)) + - Fixed indentation in the Bundler executable template ([#6773](https://github.com/rubygems/bundler/pull/6773)) + - Fixed an issue where plugins could register for the same Bundler hook multiple times ([#6775](https://github.com/rubygems/bundler/pull/6775)) + - Changed the "multiple sources" message in `bundle install` to be a warning instead of an error ([#6790](https://github.com/rubygems/bundler/pull/6790)) + - Fixed a bug where path gems would break when using `only_update_to_newer_versions` ([#6774](https://github.com/rubygems/bundler/pull/6774)) + - Fixed a bug where installing plugins with the `--deployment` setting would fail ([#6805](https://github.com/rubygems/bundler/pull/6805)) + - Fixed an issue where `bundle update` couldn't update & install a gem when `no_install` was set (a `bundle package` config) ([#7078](https://github.com/rubygems/bundler/pull/7078)) + - Fixed an issue where users could not run `bundle exec` on default gems ([#6963](https://github.com/rubygems/bundler/pull/6963)) + - Updated vendor libraries to their latest version ([#7076](https://github.com/rubygems/bundler/pull/7067), [#7068](https://github.com/bundler/bundler/pull/7068)) + - Fixed an issue where the `github` source was not using `https` by default that we mentioned in the 2.0 release ([#7182](https://github.com/rubygems/bundler/pull/7182)) + - Fixed an issue where `rake release` was not outputting the message to users asking for a 2fa token ([#7199](https://github.com/rubygems/bundler/pull/7199)) + +### Documentation: + + - Fix incorrect documented `BUNDLE_PATH_RELATIVE_TO_CWD` env var ([#6751](https://github.com/rubygems/bundler/pull/6751)) + - Update URLs in Bundler's documentation to use `https` ([#6935](https://github.com/rubygems/bundler/pull/6935)) + +## 2.0.1 (2019-01-04) + +### Bug fixes: + + - Relaxed RubyGems requirement to `>= 2.5.0` ([#6867](https://github.com/rubygems/bundler/pull/6867)) + +## 2.0.0 (2019-01-03) + + No changes. + +## 2.0.0.pre.3 (2018-12-30) + +### Breaking changes: + + - Bundler 2 now requires RubyGems 3.0.0 at minimum + +### Bug fixes: + + - Ruby 2.6 compatibility fixes (@segiddins) + +### Enhancements: + + - Import changes from Bundler 1.17.3 release + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +## 2.0.0.pre.2 (2018-11-27) + +### Breaking changes: + + - `:github` source in the Gemfile now defaults to using HTTPS + +Changes + + - Add compatibility for Bundler merge into ruby-src + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +## 2.0.0.pre.1 (2018-11-09) + +### Breaking changes: + + - Dropped support for versions of Ruby under 2.3 + - Dropped support for version of RubyGems under 2.5 + - Moved error messages from STDOUT to STDERR + + Note: To upgrade your Gemfile to Bundler 2 you will need to run `bundle update --bundler` + +## 1.17.3 (2018-12-27) + +### Bug fixes: + + - Fix a Bundler error when installing gems on old versions of RubyGems ([#6839](https://github.com/rubygems/bundler/issues/6839), @colby-swandale) + - Fix a rare issue where Bundler was removing itself after a `bundle clean` ([#6829](https://github.com/rubygems/bundler/issues/6829), @colby-swandale) + +### Documentation: + + - Add entry for the `bundle remove` command to the main Bundler manual page + +## 1.17.2 (2018-12-11) + + - Add compatibility for bundler merge with Ruby 2.6 + +## 1.17.1 (2018-10-25) + + - Convert `Pathname`s to `String`s before sorting them, fixing #6760 and #6758 ([#6761](https://github.com/rubygems/bundler/pull/6761), @alexggordon) + +## 1.17.0 (2018-10-25) + + No changes. + +## 1.17.0.pre.2 (2018-10-13) + +### Features: + + - Configure Bundler home, cache, config and plugin directories with `BUNDLE_USER_HOME`, `BUNDLE_USER_CACHE`, `BUNDLE_USER_CONFIG` and `BUNDLE_USER_PLUGIN` env vars ([#4333](https://github.com/rubygems/bundler/issues/4333), @gwerbin) + - Add `--all` option to `bundle binstubs` that will generate an executable file for all gems with commands in the bundle + - Add `bundle remove` command to remove gems from the Gemfile via the CLI + - Improve checking file permissions and asking for `sudo` in Bundler when it doesn't need to + - Add error message to `bundle add` to check adding duplicate gems to the Gemfile + - When asking for `sudo`, Bundler will show a list of folders/files that require elevated permissions to write to. + + The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Improve deprecation warning message for `bundle show` command + - Improve deprecation warning message for the `--force` option in `bundle install` + +## 1.17.0.pre.1 (2018-09-24) + +### Features: + + - Check folder/file permissions of the Bundle home directory in the `bundle doctor` command ([#5786](https://github.com/rubygems/bundler/issues/5786), @ajwann) + - Remove compiled gem extensions when running `bundle clean` ([#5596](https://github.com/rubygems/bundler/issues/5596), @akhramov) + - Add `--paths` option to `bundle list` command ([#6172](https://github.com/rubygems/bundler/issues/6172), @colby-swandale) + - Add base error class to gems generated from `bundle gem` ([#6260](https://github.com/rubygems/bundler/issues/6260), @christhekeele) + - Correctly re-install gem extensions with a git source when running `bundle pristine` ([#6294](https://github.com/rubygems/bundler/issues/6294), @wagenet) + - Add config option to disable platform warnings ([#6124](https://github.com/rubygems/bundler/issues/6124), @agrim123) + - Add `--skip-install` option to `bundle add` command to add gems to the Gemfile without installation ([#6511](https://github.com/rubygems/bundler/issues/6511), @agrim123) + - Add `--only-explicit` option to `bundle outdated` to list only outdated gems in the Gemfile ([#5366](https://github.com/rubygems/bundler/issues/5366), @peret) + - Support adding multiple gems to the Gemfile with `bundle add` ([#6543](https://github.com/rubygems/bundler/issues/6543), @agrim123) + - Make registered plugin events easier to manage in the Plugin API (@jules2689) + - Add new gem install hooks to the Plugin API (@jules2689) + - Add `--optimistic` and `--strict` options to `bundle add` ([#6553](https://github.com/rubygems/bundler/issues/6553), @agrim123) + - Add `--without-group` and `--only-group` options to `bundle list` ([#6564](https://github.com/rubygems/bundler/issues/6564), @agrim123) + - Add `--gemfile` option to the `bundle exec` command ([#5924](https://github.com/rubygems/bundler/issues/5924), @ankitkataria) + + The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Make `install --path` relative to the current working directory ([#2048](https://github.com/rubygems/bundler/issues/2048), @igorbozato) + - Auto-configure job count ([#5808](https://github.com/rubygems/bundler/issues/5808), @segiddins) + - Use the Gem Version Promoter for major gem updates ([#5993](https://github.com/rubygems/bundler/issues/5993), @segiddins) + - Add config option to add the Ruby scope to `bundle config path` when configured globally (@segiddins) + +## 1.16.6 (2018-10-05) + +### Enhancements: + + - Add an error message when adding a gem with `bundle add` that's already in the bundle ([#6341](https://github.com/rubygems/bundler/issues/6341), @agrim123) + - Add Homepage, Source Code and Changelog URI metadata fields to the `bundle gem` gemspec template (@walf443) + +### Bug fixes: + + - Fix issue where updating a gem resulted in the gem's version being downgraded when `BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS` was set ([#6529](https://github.com/rubygems/bundler/issues/6529), @theflow) + - Fix some rescue calls that don't specify error type (@utilum) + - Fix an issue when the Lockfile would contain platform-specific gems that it didn't need ([#6491](https://github.com/rubygems/bundler/issues/6491), @segiddins) + - Improve handling of adding new gems with only a single group to the Gemfile in `bundle add` (@agrim123) + - Refactor check for OpenSSL in `bundle env` (@voxik) + - Remove an unnecessary assignment in Metadata (@voxik) + +### Documentation: + + - Update docs to reflect revised guidance to check in Gemfile.lock into version control for gems ([#5879](https://github.com/rubygems/bundler/issues/5879), @arbonap) + - Add documentation for the `--all` flag in `bundle update` (@agrim123) + - Update README to use `bundle add` in usage examples (@hdf1986) + +## 1.16.5 (2018-09-18) + +### Enhancements: + + - Add support for TruffleRuby (@eregon) + +### Bug fixes: + + - Avoid printing git errors when checking the version on incorrectly packaged versions of Bundler ([#6453](https://github.com/rubygems/bundler/issues/6453), @greysteil) + - Fix issue where Bundler does not check the given class when comparing equality in DepProxy (@ChrisBr) + - Handle `RangeNotSatisfiable` error in Compact Index (@MaxLap) + - Check for initialized `search` variable in `LazySpecification` (@voxik) + - Fix LoadError occurring in nested bundle exec calls ([#6537](https://github.com/rubygems/bundler/issues/6537), @colby-swandale) + - Check that Bundler::Deprecate is not an autoload constant ([#6163](https://github.com/rubygems/bundler/issues/6163), @eregon) + - Prefer non-pre-release versions when performing a `bundle update --patch` ([#6684](https://github.com/rubygems/bundler/issues/6684), @segiddins) + +## 1.16.4 (2018-08-17) + +### Enhancements: + + - Welcome new members to the Bundler core team (@indirect) + - Don't mutate original error trees when determining version_conflict_message (@greysteil) + - Update vendored Molinillo to 0.6.6 (@segiddins) + +### Bug fixes: + + - Reword bundle update regression message to be more clear to the user when a gem's version is downgraded ([#6584](https://github.com/rubygems/bundler/issues/6584), @ralphbolo) + - Respect --conservative flag when updating a dependency group ([#6560](https://github.com/rubygems/bundler/issues/6560), @greysteil) + - Fix issue where a pre-release version was not being selected when it's specified in the Gemfile ([#6449](https://github.com/rubygems/bundler/issues/6449), @akihiro17) + - Fix issue where `Etc` was not loaded when getting the user's home dir ([#6640](https://github.com/rubygems/bundler/issues/6640), @colby-swandale) + - Use UTF-8 for reading files including Gemfile ([#6660](https://github.com/rubygems/bundler/issues/6660), @eregon) + - Remove unnecessary `while` loop in path resolver helper (@ojab) + +### Documentation: + + - Document that `bundle show [--paths]` sorts results by name (@kemitchell) + +## 1.16.3 (2018-07-17) + +### Features: + + - Support URI::File of Ruby 2.6 (@hsbt) + +### Bug fixes: + + - Expand symlinks during setup to allow Bundler to load correctly when using symlinks in $GEM_HOME ([#6465](https://github.com/rubygems/bundler/issues/6465), @ojab, @indirect) + - Dont let Bundler create temporary folders for gem installs which are owned by root ([#6258](https://github.com/rubygems/bundler/issues/6258), @colby-swandale) + - Don't fallback to using temporary directories when needed directories already exist ([#6546](https://github.com/rubygems/bundler/issues/6546), @brodock) + - Use SharedHelpers.filesystem_access when reading a Gemfile so friendly error messages can be given to the user ([#6541](https://github.com/rubygems/bundler/issues/6541), @segiddins) + - Check if source responds to `#remotes` before printing gem install error message ([#6211](https://github.com/rubygems/bundler/issues/6211), @colby-swandale) + - Handle Errno::ENOTSUP in the Bundler Process Lock to prevent exceptions when using NFS mounts ([#6566](https://github.com/rubygems/bundler/issues/6566), @colby-swandale) + - Respect encodings when reading gemspecs ([#6598](https://github.com/rubygems/bundler/issues/6598), @deivid-rodriguez) + +### Documentation: + + - Fix links between manual pages (@BanzaiMan) + - Add warning to Gemfile documentation for the use of the `source` option when declaring gems ([#6280](https://github.com/rubygems/bundler/issues/6280), @forestgagnon) + +## 1.16.2 (2018-04-20) + +### Enhancements: + + - Include the gem's source in the gem install error message when available (@papanikge) + - Remove unnecessary executable bit from gem template (@voxik) + - Dont add the timestamp comment with gems added to the Gemfile via `bundle add` ([#6193](https://github.com/rubygems/bundler/issues/6193), @cpgo) + - Improve yanked gem error message (@alyssais) + - Use `Bundler.rubygems.inflate` instead of the Gem::Util method directly (@segiddins) + - Remove unused instance variable (@segiddins) + +### Bug fixes: + + - Only trap INT signal and have Ruby's signal default handler be invoked (@shayonj) + - Fix warning about the use of `__FILE__` in RubyGems integration testing (@MSP-Greg) + - Skip the outdated bundler check when MD5 is not available ([#6032](https://github.com/rubygems/bundler/issues/6032), @segiddins) + - Fallback to the original error if the friendly message raises (@segiddins) + - Rename Bundler.frozen? to avoid Object method conflict ([#6252](https://github.com/rubygems/bundler/issues/6252), @segiddins) + - Ensure the bindir exists before installing gems (@segiddins) + - Handle gzip corruption errors in the compact index client ([#6261](https://github.com/rubygems/bundler/issues/6261), @colby-swandale) + - Check if the current directory is writeable when writing files in `bundle gem` ([#6219](https://github.com/rubygems/bundler/issues/6219), @nilsding) + - Fix hang when gemspec has incompatible encoding (@deivid-rodriguez) + - Gracefully handle when the lockfile is missing spec entries for the current platform ([#6079](https://github.com/rubygems/bundler/issues/6079), @segiddins) + - Use Gem::Util.inflate instead of Gem.inflate (@hsbt) + - Update binstub generator to use new ERB.new arity in Ruby 2.6 (@koic) + - Fix `source_location` call in rubygems integration (@MSP-Greg) + - Use `filesystem_access` when copying files in Compact Index Updater ([#6289](https://github.com/rubygems/bundler/issues/6289), @segiddins) + - Fail gracefully when resetting git gems to the given revision fails ([#6324](https://github.com/rubygems/bundler/issues/6324), @segiddins) + - Handle exceptions that do not have a backtrace ([#6342](https://github.com/rubygems/bundler/issues/6342), @nesaulov) + - Check if stderr was closed before writing to it (@shime) + - Handle updating a specific gem for a non-local platform ([#6350](https://github.com/rubygems/bundler/issues/6350), @greysteil) + - Bump the `bundle_binstub` check-length to 300 characters (@tduffield) + - Fix specifying alterntive Lockfile with `bundle lock` when default gemfile is present ([#6460](https://github.com/rubygems/bundler/issues/6460), @agrim123) + - Allow installing dependencies when the path is set to `.` ([#6475](https://github.com/rubygems/bundler/issues/6475), @segiddins) + - Support Bundler installing on a readonly filesystem without a home directory ([#6461](https://github.com/rubygems/bundler/issues/6461), @grosser) + - Filter git uri credentials in source description (@segiddins) + +### Documentation: + + - Correct typos in `bundle binstubs` man page (@erikj, @samueloph) + - Update links in `bundle gem` command documentation to use https (@KrauseFx) + - Fix broken links between bundler man pages (@segiddins) + - Add man page for the `bundle doctor` command ([#6243](https://github.com/rubygems/bundler/issues/6243), @nholden) + - Document `# frozen_string_literal` in `bundle init` Gemfile (@315tky) + - Explain the gemspec files attribute in `bundle gem` template and print a link to bundler.io guides when running `bundle gem` ([#6246](https://github.com/rubygems/bundler/issues/6246), @nesaulov) + - Small copy tweaks & removed redundant phrasing in the bundler man page (@rubymorillo) + - Improve the documentation of the settings load order in Bundler (@rubymorillo) + - Added license info to main README (@rubymorillo) + - Document parameters and return value of Injector#inject (@tobias-grasse) + +## 1.16.1 (2017-12-12) + +### Bug fixes: + + - avoid hanging on complex resolver errors ([#6114](https://github.com/rubygems/bundler/issues/6114), @halfbyte) + - avoid an error when running `bundle update --group` ([#6156](https://github.com/rubygems/bundler/issues/6156), @mattbrictson) + - ensure the resolver prefers non-pre-release gems when possible ([#6181](https://github.com/rubygems/bundler/issues/6181), @greysteil) + - include bundler's gemspec in the built gem ([#6165](https://github.com/rubygems/bundler/issues/6165), @dr-itz) + - ensure locally installed specs are not overridden by those in remote sources during dependency resolution ([#6072](https://github.com/rubygems/bundler/issues/6072), @indirect) + - ensure custom gemfiles are respected in generated binstubs (@pftg) + - fail gracefully when loading a bundler-generated binstub when `bin/bundle` was not generated by bundler ([#6149](https://github.com/rubygems/bundler/issues/6149), @hsbt) + - allow `bundle init` to be run even when a parent directory contains a gemfile ([#6205](https://github.com/rubygems/bundler/issues/6205), @colby-swandale) + +## 1.16.0 (2017-10-31) + +### Bug fixes: + + - avoid new RubyGems warning about unsafe YAML loading (to keep output consistent) (@segiddins) + - load digest subclasses in a thread-safe manner (@segiddins, @colby-swandale) + - avoid unused variable warnings under ruby 2.5 (@amatsuda) + - fix printing the same message twice in verbose mode ([#6028](https://github.com/rubygems/bundler/issues/6028), @akhramov) + - allow `SignalException`s to bubble up to the interpreter during `bundle exec` ([#6090](https://github.com/rubygems/bundler/issues/6090), @dekellum) + - avoid activating stdlib digest under Ruby 2.5 (@segiddins) + - prioritise explicitly requested gems in dependency resolution sort order (@segiddins) + - reduce memory usage during dependency resolution ([#6114](https://github.com/rubygems/bundler/issues/6114), @greysteil) + - ensure that the default bundler gem is not accidentally activated on ruby 2.5 when using local git overrides (@segiddins) + +## 1.16.0.pre.3 (2017-10-04) + +### Features: + + - the output from `bundle env` includes more information, particularly both the compiled & loaded versions of OpenSSL (@indirect) + +### Bug fixes: + + - fix a bug where installing on FreeBSD would accidentally raise an error ([#6013](https://github.com/rubygems/bundler/issues/6013), @olleolleolle) + - fix a regression in 1.16 where pre-release gems could accidentally be resolved even when the gemfile contained no pre-release requirements (@greysteil) + - bundler will avoid making unnecessary network requests to fetch dependency data, fixing a regression introduced in 1.16 (@segiddins) + - the outdated bundler version message is disabled by default until the message has been fine-tuned ([#6004](https://github.com/rubygems/bundler/issues/6004), @segiddins) + +## 1.16.0.pre.2 (2017-09-06) + +### Bug fixes: + + - handle when a connection is missing a socket when warning about OpenSSL version (@greysteil) + - the description for the `rake release` task now reflects `$RUBYGEMS_HOST` (@wadetandy) + - fix a bug where `bundle update` would regress transitive dependencies (@greysteil) + +## 1.16.0.pre.1 (2017-09-04) + +### Features: + + - allow using non-branch symbolic refs in a git source ([#4845](https://github.com/rubygems/bundler/issues/4845), @segiddins) + - allow absolute paths in the `cache path` setting ([#5627](https://github.com/rubygems/bundler/issues/5627), @mal) + - gems created via `bundle gem` with rspec have `--require spec_helper` in their `.rspec` file (@koic) + - `bundle env` includes `Gem.ruby` and the `bundle` binstub shebang when they don't match ([#5616](https://github.com/rubygems/bundler/issues/5616), @segiddins) + - allow passing gem names to `bundle pristine` (@segiddins) + - `bundle version` and `bundle env` include the commit and build date for the bundler gem ([#5049](https://github.com/rubygems/bundler/issues/5049), @segiddins) + - add the `--shebang` option to `bundle binstubs` ([#4070](https://github.com/rubygems/bundler/issues/4070), @segiddins, @Zorbash) + - gemfiles are `eval`ed one fewer time when running `bundle install` ([#4952](https://github.com/rubygems/bundler/issues/4952), [#3096](https://github.com/bundler/bundler/issues/3096), [#4417](https://github.com/bundler/bundler/issues/4417), @segiddins) + - the `fileutils` gem is now vendored so different versions of the gem can be activated (@segiddins) + - speed up no-op installations ([#5842](https://github.com/rubygems/bundler/issues/5842), @segiddins) + - default to keeping the lockfile in the default gem template (@deivid-rodriguez) + - add a special bundler binstub that ensures the correct version of bundler is activated ([#5876](https://github.com/rubygems/bundler/issues/5876), @segiddins) + - speed up dependency resolution and ensure that all resolvable gemfiles can be installed (@segiddins, @greysteil) + - add a `bundle list` command that prints the gems in use ([#4754](https://github.com/rubygems/bundler/issues/4754), @colby-swandale) + - allow adding credentials to a gem source during deployment when `allow_deployment_source_credential_changes` is set (@adrian-gomez) + - making an outdated (and insecure) TLS connection to rubygems.org will print a warning (@segiddins) + +### Bug fixes: + + - allow configuring a mirror fallback timeout without a trailing slash ([#4830](https://github.com/rubygems/bundler/issues/4830), @segiddins) + - fix handling of mirrors for file: urls that contain upper-case characters (@segiddins) + - list the correct gem host for `rake release` when `allowed_push_host` has been set (@mdeering) + - ensure `Bundler.original_env` preserves all env keys that bundler sets ([#5700](https://github.com/rubygems/bundler/issues/5700), @segiddins) + - ensure `bundle pristine` removes files added to a git gem (@segiddins) + - load plugin files from path gems before gem installation ([#5429](https://github.com/rubygems/bundler/issues/5429), @segiddins) + - ensure gems containing manpages are properly set up ([#5730](https://github.com/rubygems/bundler/issues/5730), @segiddins) + - avoid fetching remote specs when all effected gems are in groups that are not being installed (@segiddins) + - allow `BUNDLE_GEMFILE` to be a relative path ([#5712](https://github.com/rubygems/bundler/issues/5712), @gxespino) + - show a more helpful error message when a gem fails to install due to a corrupted lockfile ([#5846](https://github.com/rubygems/bundler/issues/5846), @segiddins) + - add a process lock to allow multiple concurrent `bundle install`s ([#5851](https://github.com/rubygems/bundler/issues/5851), @stefansedich) + - ensure that specifications always return an array for `#extensions` (@greysteil) + - print a helpful error message when using a gem in the Gemfile with an empty name (@colby-swandale) + - ensure that all gemfiles are included in `bundle env` (@segiddins) + - use ssl client cert and ca cert settings from gem configuration as fallbacks (@stan3) + - avoid global namespace pollution when loading gems ([#5958](https://github.com/rubygems/bundler/issues/5958), @shyouhei) + - avoid running a complete re-resolve on `bundle update --bundler` (@segiddins) + - allow `bundle binstubs --standalone` to work without `path` being set (@colby-swandale) + - fix support for bundle paths that include jars or wars on jruby ([#5975](https://github.com/rubygems/bundler/issues/5975), @torcido) + +## 1.15.4 (2017-08-19) + +### Bug fixes: + + - handle file conflicts gracefully in `bundle gem` (@rafaelfranca, @segiddins) + - bundler will fail gracefully when the bundle path contains the system path separator ([#5485](https://github.com/rubygems/bundler/issues/5485), ajwann) + - failed gem downloads will be retried consistently across different RubyGems versions (@shayonj) + - `bundle pristine` will respect build options while re-building native extensions (@NickLaMuro) + +## 1.15.3 (2017-07-21) + +### Bug fixes: + + - ensure that empty strings passed to `bundle config` are serialized & parsed properly ([#5881](https://github.com/rubygems/bundler/issues/5881), @segiddins) + - avoid printing an outdated version warning when running a parseable command (@segiddins) + +## 1.15.2 (2017-07-17) + +### Features: + + - new gemfiles created by bundler will include an explicit `github` git source that uses `https` (@segiddins) + +### Bug fixes: + + - inline gemfiles work when `BUNDLE_BIN` is set ([#5847](https://github.com/rubygems/bundler/issues/5847), @segiddins) + - avoid using the old dependency API when there are no changes to the compact index files ([#5373](https://github.com/rubygems/bundler/issues/5373), @greysteil) + - fail gracefully when the full index serves gemspecs with invalid dependencies ([#5797](https://github.com/rubygems/bundler/issues/5797), @segiddins) + - support installing gemfiles that use `eval_gemfile`, `:path` gems with relative paths, and `--deployment` simultaneously (@NickLaMuro) + - `bundle config` will print settings as the type they are interpreted as (@segiddins) + - respect the `no_proxy` environment variable when making network requests ([#5781](https://github.com/rubygems/bundler/issues/5781), @jakauppila) + - commands invoked with `--verbose` will not have default flags printed (@segiddins) + - allow `bundle viz` to work when another gem has a requirable `grapviz` file ([#5707](https://github.com/rubygems/bundler/issues/5707), @segiddins) + - ensure bundler puts activated gems on the `$LOAD_PATH` in a consistent order ([#5696](https://github.com/rubygems/bundler/issues/5696), @segiddins) + +## 1.15.1 (2017-06-02) + +### Bug fixes: + + - `bundle lock --update GEM` will fail gracefully when the gem is not in the lockfile ([#5693](https://github.com/rubygems/bundler/issues/5693), @segiddins) + - `bundle init --gemspec` will fail gracefully when the gemspec is invalid (@colby-swandale) + - `bundle install --force` works when the gemfile contains git gems ([#5678](https://github.com/rubygems/bundler/issues/5678), @segiddins) + - `bundle env` will print well-formed markdown when there are no settings ([#5677](https://github.com/rubygems/bundler/issues/5677), @segiddins) + +## 1.15.0 (2017-05-19) + + No changes. + +## 1.15.0.pre.4 (2017-05-10) + +### Bug fixes: + + - avoid conflicts when `Gem.finish_resolve` is called after the bundle has been set up (@segiddins) + - ensure that `Gem::Specification.find_by_name` always returns an object that can have `#to_spec` called on it ([#5592](https://github.com/rubygems/bundler/issues/5592), @jules2689) + +## 1.15.0.pre.3 (2017-04-30) + +### Bug fixes: + + - avoid redundant blank lines in the readme generated by `bundle gem` (@koic) + - ensure that `open-uri` is not loaded after `bundle exec` (@segiddins) + - print a helpful error message when an activated default gem conflicts with + a gem in the gemfile (@segiddins) + - only shorten `ref` option for git gems when it is a SHA ([#5620](https://github.com/rubygems/bundler/issues/5620), @segiddins) + +## 1.15.0.pre.2 (2017-04-23) + +### Bug fixes: + + - ensure pre-existing fit caches are updated from remote sources ([#5423](https://github.com/rubygems/bundler/issues/5423), @alextaylor000) + - avoid duplicating specs in the lockfile after updating with the gem uninstalled ([#5599](https://github.com/rubygems/bundler/issues/5599), @segiddins) + - ensure git gems have their extensions available at runtime ([#5594](https://github.com/rubygems/bundler/issues/5594), @jules2689, @segiddins) + +## 1.15.0.pre.1 (2017-04-16) + +### Features: + + - print a notification when a newer version of bundler is available ([#4683](https://github.com/rubygems/bundler/issues/4683), @segiddins) + - add man pages for all bundler commands ([#4988](https://github.com/rubygems/bundler/issues/4988), @feministy) + - add the `bundle info` command (@fredrb, @colby-swandale) + - all files created with `bundle gem` comply with the bundler style guide (@zachahn) + - if installing a gem fails, print out the reason the gem needed to be installed ([#5078](https://github.com/rubygems/bundler/issues/5078), @segiddins) + - allow setting `gem.push_key` to set the key used when running `rake release` (@DTrierweiler) + - print gem versions that are regressing during `bundle update` in yellow ([#5506](https://github.com/rubygems/bundler/issues/5506), @brchristian) + - avoid printing extraneous dependencies when the resolver encounters a conflict (@segiddins) + - add the `bundle issue` command that prints instructions for reporting issues ([#4871](https://github.com/rubygems/bundler/issues/4871), @jonathanpike) + - add `--source` and `--group` options to the `bundle inject` command ([#5452](https://github.com/rubygems/bundler/issues/5452), @Shekharrajak) + - add the `bundle add` command to add a gem to the gemfile (@denniss) + - add the `bundle pristine` command to re-install gems from cached `.gem` files ([#4509](https://github.com/rubygems/bundler/issues/4509), @denniss) + - add a `--parseable` option for `bundle config` (@JuanitoFatas, @colby-swandale) + +### Performance: + + - speed up gemfile initialization by storing locked dependencies as a hash (@jules2689) + - speed up gemfile initialization by making locked dependency comparison lazy, avoiding object allocation (@jules2689) + - only validate git gems when they are downloaded, instead of every time `Bundler.setup` is run (@segiddins) + - avoid regenerating the lockfile when nothing has changed (@segiddins) + - avoid diffing large arrays when no sources in the gemfile have changed (@segiddins) + - avoid evaluating full gemspecs when running with RubyGems 2.5+ (@segiddins) + +### Bug fixes: + + - fix cases where `bundle update` would print a resolver conflict instead of updating the selected gems ([#5031](https://github.com/rubygems/bundler/issues/5031), [#5095](https://github.com/bundler/bundler/issues/5095), @segiddins) + - print out a stack trace after an interrupt when running in debug mode (@segiddins) + - print out when bundler starts fetching a gem from a remote server (@segiddins) + - fix `bundle gem` failing when `git` is unavailable ([#5458](https://github.com/rubygems/bundler/issues/5458), @Shekharrajak, @colby-swandale) + - suggest the appropriate command to unfreeze a bundle ([#5009](https://github.com/rubygems/bundler/issues/5009), @denniss) + - ensure nested calls to `bundle exec` resolve default gems correctly ([#5500](https://github.com/rubygems/bundler/issues/5500), @segiddins) + - ensure that a plugin failing to install doesn't uninstall other plugins (@kerrizor, @roseaboveit) + - ensure `socket` is required before being referenced ([#5533](https://github.com/rubygems/bundler/issues/5533), @rafaelfranca) + - allow running `bundle outdated` when gems aren't installed locally ([#5553](https://github.com/rubygems/bundler/issues/5553), @segiddins) + - print a helpful error when `bundle exec`ing to a gem that isn't included in the bundle ([#5487](https://github.com/rubygems/bundler/issues/5487), @segiddins) + - print an error message when a non-git gem is given a `branch` option ([#5530](https://github.com/rubygems/bundler/issues/5530), @colby-swandale) + - allow interrupts to exit the process after gems have been installed (@segiddins) + - print the underlying error when downloading gem metadata fails ([#5579](https://github.com/rubygems/bundler/issues/5579), @segiddins) + - avoid deadlocking when installing with a lockfile that is missing dependencies ([#5378](https://github.com/rubygems/bundler/issues/5378), [#5480](https://github.com/bundler/bundler/issues/5480), [#5519](https://github.com/bundler/bundler/issues/5519), [#5526](https://github.com/bundler/bundler/issues/5526), [#5529](https://github.com/bundler/bundler/issues/5529), [#5549](https://github.com/bundler/bundler/issues/5549), [#5572](https://github.com/bundler/bundler/issues/5572), @segiddins) + +## 1.14.6 (2017-03-03) + +### Bug fixes: + + - avoid undefined constant `Bundler::Plugin::API::Source` exception ([#5409](https://github.com/rubygems/bundler/issues/5409), @segiddins) + - avoid incorrect warnings about needing to enable `specific_platform` (@segiddins) + - fail gracefully when the compact index does not send an ETag ([#5463](https://github.com/rubygems/bundler/issues/5463), @olleolleolle) + - ensure `bundle outdated --local` shows all outdated gems ([#5430](https://github.com/rubygems/bundler/issues/5430), @denniss) + - fix a case where ruby version requirements could lead to incorrect resolver conflicts ([#5425](https://github.com/rubygems/bundler/issues/5425), @segiddins) + +## 1.14.5 (2017-02-22) + +### Bug fixes: + + - avoid loading all unused gemspecs during `bundle exec` on RubyGems 2.3+ (@segiddins) + - improve resolver performance when dependencies have zero or one total possibilities ignoring requirements ([#5444](https://github.com/rubygems/bundler/issues/5444), [#5457](https://github.com/bundler/bundler/issues/5457), @segiddins) + - enable compact index when OpenSSL FIPS mode is enabled but not active ([#5433](https://github.com/rubygems/bundler/issues/5433), @wjordan) + - use github username instead of git name for the github url in `bundle gem` ([#5438](https://github.com/rubygems/bundler/issues/5438), @danielpclark) + - avoid a TypeError on RubyGems 2.6.8 when no build settings are set for native extensions (@okkez) + - fail gracefully when the dependency api is missing runtime dependencies for a gem (@segiddins) + - handle when a platform-specific gem has more dependencies than the ruby platform version ([#5339](https://github.com/rubygems/bundler/issues/5339), [#5426](https://github.com/bundler/bundler/issues/5426), @segiddins) + - allow running bundler on a machine with no home directory where the temporary directory is not writable ([#5371](https://github.com/rubygems/bundler/issues/5371), @segiddins) + - avoid gem version conflicts on openssl using Ruby 2.5 ([#5235](https://github.com/rubygems/bundler/issues/5235), @rhenium) + - fail when installing in frozen mode and the dependencies for `gemspec` gems have changed without the lockfile being updated ([#5264](https://github.com/rubygems/bundler/issues/5264), @segiddins) + +## 1.14.4 (2017-02-12) + +### Bug fixes: + + - fail gracefully when attempting to overwrite an existing directory with `bundle gem` ([#5358](https://github.com/rubygems/bundler/issues/5358), @nodo) + - fix a resolver bug that would cause bundler to report conflicts that it could resolve ([#5359](https://github.com/rubygems/bundler/issues/5359), [#5362](https://github.com/bundler/bundler/issues/5362), @segiddins) + - set native extension build arguments for git gems ([#5401](https://github.com/rubygems/bundler/issues/5401), @segiddins) + - fix the suggested `bundle lock` command printed when a dependency is unused on any platform (@5t111111) + - ensure the version passed to `ruby` in the Gemfile is valid during Gemfile parsing ([#5380](https://github.com/rubygems/bundler/issues/5380), @segiddins) + - show `bundle inject` usage when too many arguments are passed ([#5384](https://github.com/rubygems/bundler/issues/5384), @Shekharrajak) + - stop `bundle show --outdated` from implicitly running `bundle update` ([#5375](https://github.com/rubygems/bundler/issues/5375), @colby-swandale) + - allow the temporary home directory fallback to work for multiple users (@svoop) + +## 1.14.3 (2017-01-24) + +### Bug fixes: + + - fix the resolver attempting to activate ruby-platform gems when the bundle is only for other platforms ([#5349](https://github.com/rubygems/bundler/issues/5349), [#5356](https://github.com/bundler/bundler/issues/5356), @segiddins) + - avoid re-resolving a locked gemfile that uses `gemspec` and includes development dependencies ([#5349](https://github.com/rubygems/bundler/issues/5349), @segiddins) + +## 1.14.2 (2017-01-22) + +### Bug fixes: + + - fix using `force_ruby_platform` on windows ([#5344](https://github.com/rubygems/bundler/issues/5344), @segiddins) + - fix an incorrect version conflict error when using `gemspec` on multiple platforms ([#5340](https://github.com/rubygems/bundler/issues/5340), @segiddins) + +## 1.14.1 (2017-01-21) + +### Bug fixes: + + - work around a ruby 2.2.2 bug that caused a stack consistency error during installation ([#5342](https://github.com/rubygems/bundler/issues/5342), @segiddins) + +## 1.14.0 (2017-01-20) + +### Bug fixes: + + - ensure `Settings::Mirror` is autoloaded under the `Settings` namespace + ([#5238](https://github.com/rubygems/bundler/issues/5238), @segiddins) + - fix `bundler/inline` when `BUNDLE_GEMFILE=""` ([#5079](https://github.com/rubygems/bundler/issues/5079), @segiddins) + +## 1.14.0.pre.2 (2017-01-11) + +### Bug fixes: + + - allow not selecting a gem when running `bundle open` ([#5301](https://github.com/rubygems/bundler/issues/5301), @segiddins) + - support installing gems from git branches that contain shell metacharacters ([#5295](https://github.com/rubygems/bundler/issues/5295), @segiddins) + - fix a resolver error that could leave dependencies unresolved ([#5294](https://github.com/rubygems/bundler/issues/5294), @segiddins) + - fix a stack overflow error when invoking commands ([#5296](https://github.com/rubygems/bundler/issues/5296), @segiddins) + +## 1.14.0.pre.1 (2016-12-29) + +### Features: + + - `bundle doctor` first runs `bundle check` (@segiddins) + - the bundler trampoline is automatically enabled when the target version is greater than bundler 2 (@segiddins) + - gem checksums returned by rubygems.org are validated when installing gems ([#4464](https://github.com/rubygems/bundler/issues/4464), @segiddins) + - use the git username as a github username when running `bundle gem` (@JuanitoFatas) + - show more context when the resolver conflicts on required ruby and rubygems versions (@segiddins) + - improve platform support by allowing bundler to pick the best platform match during dependency resolution, enabled with the `specific_platform` setting ([#4295](https://github.com/rubygems/bundler/issues/4295), [#4896](https://github.com/bundler/bundler/issues/4896), @segiddins) + - always prompt the user for a password when using `sudo` ([#3006](https://github.com/rubygems/bundler/issues/3006), @segiddins) + - support running without a home directory ([#4778](https://github.com/rubygems/bundler/issues/4778), @segiddins) + - print a warning when the gemfile uses a platform conditional that will exclude the gem from all lockfile platforms (@segiddins) + - add the `force_ruby_platform` setting to force bundler to install ruby-platform gems, even on other platforms ([#4813](https://github.com/rubygems/bundler/issues/4813), @segiddins) + - add conservative update options to `bundle lock` ([#4912](https://github.com/rubygems/bundler/issues/4912), @chrismo) + - improve `bundle outdated` output to group gems by group (@ryanfox1985) + - add conservative update options to `bundle update` ([#5065](https://github.com/rubygems/bundler/issues/5065), [#5076](https://github.com/bundler/bundler/issues/5076), @chrismo) + - print the output of `bundle env` as github-flavored markdown, making it easier to preserve formatting when copy-pasting into a new issue (@segiddins) + - configure the persistence file when using `bundle gem` with `rspec` (@segiddins) + - add support for the `ruby_25` gemfile filter (@amatsuda) + - when installing with a lockfile that is missing dependencies, allow installation to proceed (but without parallelism) (@segiddins) + +### Performance: + + - improve `require "bundler"` performance by ~5x (@segiddins) + - allow install gems in parallel when running on rubygems 2+ + +### Bug fixes: + + - config files with CRLF line endings can be read ([#4435](https://github.com/rubygems/bundler/issues/4435), @segiddins) + - `bundle lock` activates gems for the current platform even if they were activated under a different platform for a separate dependency ([#4896](https://github.com/rubygems/bundler/issues/4896), @segiddins) + - running `bundle env` in a directory without a gemfile no longer crashes (@segiddins) + - fail gracefully when attempting to use a source with an unknown URI scheme ([#4953](https://github.com/rubygems/bundler/issues/4953), @segiddins) + - store paths in the lockfile relative to the root gemfile directory when using `eval_gemfile` ([#4966](https://github.com/rubygems/bundler/issues/4966), @segiddins) + - `bundle lock` will not update without the `--update` flag ([#4957](https://github.com/rubygems/bundler/issues/4957), @segiddins) + - the `console` binstub generated by `bundle gem` will load `.irbrc` files (@mattbrictson) + - print friendly filesystem access errors in the new index (@segiddins) + - print a helpful error when running out of memory on jruby ([#4673](https://github.com/rubygems/bundler/issues/4673), @segiddins) + - load all rubygems plugins when installing gems ([#2824](https://github.com/rubygems/bundler/issues/2824), @segiddins) + - `bundle clean --dry-run` prints the list of gems without the `--force` option when no path is set ([#5027](https://github.com/rubygems/bundler/issues/5027), @hmistry) + - local installs no longer print "this gem may have been yanked" ([#5022](https://github.com/rubygems/bundler/issues/5022), @hmistry) + - avoid leaking `which` output when running `bundle doctor` (@colby-swandale) + - print a warning when attempting to `bundle exec` an empty program ([#5084](https://github.com/rubygems/bundler/issues/5084), @bronzdoc) + - ensure `bundle outdated` lists all outdated gems ([#4979](https://github.com/rubygems/bundler/issues/4979), @chrismo) + - fail gracefully when attempting to `bundle gem` with an invalid constant name ([#5185](https://github.com/rubygems/bundler/issues/5185), @segiddins) + - allow `bundler/inline` to work in a directory that contains a gemfile ([#5117](https://github.com/rubygems/bundler/issues/5117), @colby-swandale) + - ensure that the new index is thread-safe, allowing installation on rbx ([#5142](https://github.com/rubygems/bundler/issues/5142), @segiddins) + - remove deprecated `rspec` syntax in `bundle gem` output (@gearnode) + - fail gracefully when any system error is encountered when touching the filesystem ([#5134](https://github.com/rubygems/bundler/issues/5134), @segiddins) + - fix compatibility with a machine running with FIPS mode enabled ([#4989](https://github.com/rubygems/bundler/issues/4989), @segiddins) + - fix `bundle lock --add-platform ruby` ([#5230](https://github.com/rubygems/bundler/issues/5230), @segiddins) + - print gem post-install messages when running `bundle update` (@smathy) + - ensure errors due to a retries are all separated by a newline (@segiddins) + - print out the bundle path in gem not found errors ([#4854](https://github.com/rubygems/bundler/issues/4854), @diegosteiner) + - fail gracefully when creating threads fails (@segiddins) + - avoid downloading metadata for gems that are only development dependencies (@Paxa) + +## 1.13.7 (2016-12-25) + +### Features: + + - add support for the `ruby_24` gemfile filter ([#5281](https://github.com/rubygems/bundler/issues/5281), @amatsuda) + +## 1.13.6 (2016-10-22) + +### Bug fixes: + + - make the `gem` method public again, fixing a regression in 1.13.4 ([#5102](https://github.com/rubygems/bundler/issues/5102), @segiddins) + +## 1.13.5 (2016-10-15) + +### Bug fixes: + + - Ensure a locked pre-release spec can always be re-resolved ([#5089](https://github.com/rubygems/bundler/issues/5089), @segiddins) + +## 1.13.4 (2016-10-11) + +### Bug fixes: + + - stop printing warning when compact index versions file is rewritten ([#5064](https://github.com/rubygems/bundler/issues/5064), @indirect) + - fix `parent directory is world writable but not sticky` error on install ([#5043](https://github.com/rubygems/bundler/issues/5043), @indirect) + - fix for `uninitialized constant Bundler::Plugin::API::Source` error ([#5010](https://github.com/rubygems/bundler/issues/5010), @hsbt, @aycabta) + - make `update` options for major, minor, and patch updates consistent ([#4934](https://github.com/rubygems/bundler/issues/4934), @chrismo) + +## 1.13.3 (2016-10-10) + +### Bug fixes: + + - add support for weak etags to the new index (@segiddins) + +## 1.13.2 (2016-09-30) + +### Bug fixes: + + - allow `Settings` to be initialized without a root directory (@m1k3) + - allow specifying ruby engines in the gemfile as a symbol ([#4919](https://github.com/rubygems/bundler/issues/4919), @JuanitoFatas) + - avoid an exception when using `bundler/deployment` with Vlad (@srbaker) + - ensure redefined methods have the same visibility as the one they're replacing, fixing `Kernel.require` failing on JRuby ([#4975](https://github.com/rubygems/bundler/issues/4975), @segiddins) + - ensure that Bundler won't complain about a corrupt lockfile when no lockfile exists when using `gemspec` in the Gemfile ([#5006](https://github.com/rubygems/bundler/issues/5006), @segiddins) + - fail gracefully when parsing the metadata for a gemspec from the compact index fails (@segiddins) + - fix system gems not being copied to --path on bundle install (e.g. --deployment) ([#4974](https://github.com/rubygems/bundler/issues/4974), @chrismo) + +### Performance: + + - avoid parsing the lockfile twice when evaluating gemfiles (@segiddins) + +## 1.13.1 (2016-09-13) + +### Bug fixes: + + - ensure that `Gem::Source` is available, fixing several exceptions ([#4944](https://github.com/rubygems/bundler/issues/4944), @dekellum) + - ensure that dependency resolution works when multiple gems have the same dependency ([#4961](https://github.com/rubygems/bundler/issues/4961), @segiddins) + +## 1.13.0 (2016-09-05) + + No changes. + +## 1.13.0.rc.2 (2016-08-21) + +### Features: + + - add setting `exec_disable_load` to force `exec` to spawn a new Ruby process (@segiddins) + - add `doctor` command to help with issues like unlinked compiled gems ([#4765](https://github.com/rubygems/bundler/issues/4765), @mistydemeo) + - rework the `update` command, providing fine-grained control via flags ([#4676](https://github.com/rubygems/bundler/issues/4676), @chrismo) + - add URI to http response output in debug mode ([#4808](https://github.com/rubygems/bundler/issues/4808), @NickLaMuro) + - add manpage for `binstubs` command ([#4847](https://github.com/rubygems/bundler/issues/4847), @Zorbash) + - support `mirror` settings for sources by hostname, not only full URL (@opiethehokie) + - print gem installation errors after other install output ([#4834](https://github.com/rubygems/bundler/issues/4834), @segiddins) + - add `lock --remove-platform` flag to remove platforms from the lock ([#4877](https://github.com/rubygems/bundler/issues/4877), @segiddins) + - add `only_update_to_newer_versions` setting to prevent downgrades during `update` (@segiddins) + - expanded experimental plugin support to include hooks and sources (@asutoshpalai) + +### Bug fixes: + + - retry gem downloads ([#4846](https://github.com/rubygems/bundler/issues/4846), @jkeiser) + - improve the CompactIndex to handle capitalized legacy gems ([#4867](https://github.com/rubygems/bundler/issues/4867), @segiddins) + - reuse persistent HTTP connections for CompactIndex (@NickLaMuro) + - respect `required_ruby_version` when Gemfile contains `ruby` version (@indirect) + - allow `rake release` to sign git tags ([#4743](https://github.com/rubygems/bundler/issues/4743), @eagletmt) + - set process titles when using `#load` during `exec` (@yob) + - recognize JRuby shebangs for using `#load` during `exec` (@ojab) + - handle world-writable home directories ([#4726](https://github.com/rubygems/bundler/issues/4726), @allenzhao) + - support multi-platform gems via the `gemspec` Gemfile method ([#4798](https://github.com/rubygems/bundler/issues/4798), @segiddins) + - print dots correctly for CompactIndex fetcher (@NickLaMuro) + - set an `open_timeout` when requesting gem data via HTTP (@NickLaMuro) + - rename the BUNDLE\_ORIG\_ENV variable so it no longer shows up in `config` (@indirect) + - show help only when `-h` or `--help` is passed to Bundler, not to `exec` ([#4801](https://github.com/rubygems/bundler/issues/4801), @segiddins) + - handle symlinks to binstubs created by `--standalone` ([#4782](https://github.com/rubygems/bundler/issues/4782), @terinjokes) + +## 1.13.0.rc.1 (2016-06-27) + +### Features: + + - when `bundle config major_deprecations` or `BUNDLE_MAJOR_DEPRECATIONS` is set, deprecation warnings for bundler 2 will be printed (@segiddins) + - when running with `--verbose`, bundler will print the reason it is re-resolving a gemfile (@segiddins) + +### Bug fixes: + + - fix support for running RubyGems 1.x on Ruby 2.3 ([#4698](https://github.com/rubygems/bundler/issues/4698), @segiddins) + - fix bundle exec'ing to a ruby file when gems are installed into a path ([#4592](https://github.com/rubygems/bundler/issues/4592), @chrismo) + - when multiple specs in a bundle have the same executable, prefer activating the one from the requested gem ([#4705](https://github.com/rubygems/bundler/issues/4705), @segiddins) + - stop changing the load path to require the vendored postit when trampolining (@segiddins) + - ensure relative paths are properly printed after completing an installation (@jenseng) + - fix re-resolving when there are multiple unchanged path sources (@segiddins) + - de-init submodules when running git 2.9 and requesting a git gem without submodules (@segiddins) + +## 1.13.0.pre.1 (2016-06-20) + +### Performance: + + - speed up gemfile resolution during `bundle install` by between 4x-100x ([#4376](https://github.com/rubygems/bundler/issues/4376), @segiddins) + - generally reduce object allocations when using bundler (@segiddins) + - speed up bin generation for path gems with many files ([#2846](https://github.com/rubygems/bundler/issues/2846), @segiddins) + - fix detecting path spec changes to avoid re-resolving unnecessarily (@jrafanie) + +### Features: + + - automatically trampoline to the bundler version locked in the lockfile, only updating to the running version on `bundle update --bundler` (@segiddins) + - laying the groundwork for plugin support, which is currently unsuppported, undocumented, disabled by default, and liable to change without notice (@asutoshpalai) + - allow `bundle viz --without` to accept multiple `:`-delimited groups (@mobilutz) + - support for RubyGems 2.6.4 ([#4368](https://github.com/rubygems/bundler/issues/4368), @segiddins, @RochesterinNYC) + - colorize updated gem versions ([#4334](https://github.com/rubygems/bundler/issues/4334), @bronzdoc) + - add the `--standalone` flag to `bundle binstubs` ([#4594](https://github.com/rubygems/bundler/issues/4594), @b-ggs) + - update the `bundle gem` CoC to contributor covenant v1.4 (@cllns) + - use a custom YAML serializer to make config file consistent (@segiddins) + - filter credentials from error messages (bundler/bundler-features[#111](https://github.com/rubygems/bundler/issues/111), @RochesterinNYC, @sandlerr) + - support relative paths used inside a nested invocation of `eval_gemfile` ([#4584](https://github.com/rubygems/bundler/issues/4584), @RochesterinNYC) + - fail gracefully when attempting to install a yanked gem ([#4344](https://github.com/rubygems/bundler/issues/4344), @allenzhao) + - automatically install an inline gemfile when gems are missing locally (@segiddins) + - allow conflicts for gems resolved via `gemspec` (@segiddins) + - add `--add-platform` option to `bundle lock` (@segiddins) + - fail gracefully when a resolved spec's `required_ruby_version` or `required_rubygems_version` is incompatible (@segiddins) + +### Bug fixes: + + - implicitly unlock the resolved ruby version when the declared requirements in the gemfile are incompatible with the locked version ([#4595](https://github.com/rubygems/bundler/issues/4595), [#4627](https://github.com/bundler/bundler/issues/4627), @segiddins) + - add support for quoted paths in `$PATH` ([#4323](https://github.com/rubygems/bundler/issues/4323), @segiddins) + - check out missing git repos that are not being installed ([#3981](https://github.com/rubygems/bundler/issues/3981), @asutoshpalai) + - write `bundler/setup.rb` to a consistent path (@glennpratt) + - open editor in `bundle open` with a clean environment (@sj26) + - resolve infinitely recursive copy when running `bundle package --all` with a `gemspec` in the gemfile ([#4392](https://github.com/rubygems/bundler/issues/4392), [#4430](https://github.com/bundler/bundler/issues/4430), @RochesterinNYC) + - fail gracefully when encountering an `Errno::ENOTSUP` ([#4394](https://github.com/rubygems/bundler/issues/4394), @segiddins) + - fail gracefully when encountering an `Errno::EHOSTUNREACH` ([#4642](https://github.com/rubygems/bundler/issues/4642), @allenzhao) + - fix loading config files with very long values ([#4370](https://github.com/rubygems/bundler/issues/4370), @segiddins) + - only show potential updates for gemfile platforms in `bundle outdated` ([#4450](https://github.com/rubygems/bundler/issues/4450), @RochesterinNYC) + - allow running `bundle install --deployment` after `bundle package --all` with path gems ([#2175](https://github.com/rubygems/bundler/issues/2175), @allenzhao) + - add support for patchlevels in ruby versions in the gemfile and gemspecs ([#4593](https://github.com/rubygems/bundler/issues/4593), @chalkos) + +## 1.12.6 (2016-10-10) + +### Bug fixes: + - add support for weak etags to the new index (@segiddins) + +## 1.12.5 (2016-05-25) + +### Bug fixes: + - only take over `--help` on `bundle exec` when the first two arguments are `exec` and `--help` ([#4596](https://github.com/rubygems/bundler/issues/4596), @segiddins) + - don't require `require: true` dependencies that are excluded via `env` or `install_if` (@BrianHawley) + - reduce the number of threads used simultaneously by bundler ([#4367](https://github.com/rubygems/bundler/issues/4367), @will-in-wi) + +## 1.12.4 (2016-05-16) + +### Bug fixes: + - ensure concurrent use of the new index can't corrupt the cache ([#4519](https://github.com/rubygems/bundler/issues/4519), @domcleal) + - allow missing rubygems credentials when pushing a gem with a custom host ([#4437](https://github.com/rubygems/bundler/issues/4437), @Cohen-Carlisle) + - fix installing built-in specs with `--standalone` ([#4557](https://github.com/rubygems/bundler/issues/4557), @segiddins) + - fix `bundle show` when a gem has a prerelease version that includes a `-` ([#4385](https://github.com/rubygems/bundler/issues/4385), @segiddins) + +## 1.12.3 (2016-05-06) + +### Bug fixes: + - fix uncoditionally writing `.bundle/config` when running `bundle install` (@segiddins) + - fall back to the dependency API and the full index when the home directory is not writable (@segiddins) + +## 1.12.2 (2016-05-04) + +### Bug fixes: + - fix modifying a frozen string when the resolver conflicts on dependencies with requirements ([#4520](https://github.com/rubygems/bundler/issues/4520), @grzuy) + - fix `bundle exec foo --help` not showing the invoked command's help ([#4480](https://github.com/rubygems/bundler/issues/4480), @b-ggs) + +## 1.12.1 (2016-04-30) + +### Bug fixes: + - automatically fallback when the new index has a checksum mismatch instead of erroring (@segiddins) + - fix computation of new index file local checksums on Windows ([#4472](https://github.com/rubygems/bundler/issues/4472), @mwrock) + - properly handle certain resolver backtracking cases without erroring (@segiddins, [#4484](https://github.com/rubygems/bundler/issues/4484)) + - ensure the `$LOAD_PATH` contains specs' load paths in the correct order (@segiddins, [#4482](https://github.com/rubygems/bundler/issues/4482)) + +## 1.12.0 (2016-04-28) + + No changes. + +## 1.12.0.rc.4 (2016-04-21) + +### Bug fixes: + + - don't fail when `bundle outdated` is run with flags and the lockfile contains non-semver versions ([#4438](https://github.com/rubygems/bundler/issues/4438), @RochesterinNYC) + +## 1.12.0.rc.3 (2016-04-19) + +### Bug fixes: + + - don't allow new attributes to dirty a lockfile when running `bundle exec`, `-rbundler/setup`, or `bundle check` (@segiddins) + +## 1.12.0.rc.2 (2016-04-15) + +### Features: + + - `bundle outdated` handles all combinations of `--major`, `--minor`, and `--patch` ([#4396](https://github.com/rubygems/bundler/issues/4396), @RochesterinNYC) + +### Bug fixes: + + - prevent endless recursive copy for `bundle package --all` ([#4392](https://github.com/rubygems/bundler/issues/4392), @RochesterinNYC) + - allow executables that are `load`ed to exit non-0 via an `at_exit` hook when invoked by `bundle exec` (@segiddins) + - nested invocations of `bundle exec` properly preserve the `$PATH` and `$GEM_PATH` environment variables (@segiddins) + +## 1.12.0.rc (2016-03-13) + +### Performance: + + - Download gem metadata from globally distributed CDN endpoints ([#4358](https://github.com/rubygems/bundler/issues/4358), @segiddins) + +### Bug fixes: + + - handle Ruby pre-releases built from source ([#4324](https://github.com/rubygems/bundler/issues/4324), @RochesterinNYC) + - support binstubs from RubyGems 2.6 ([#4341](https://github.com/rubygems/bundler/issues/4341), @segiddins) + - handle quotes present in in PATH ([#4326](https://github.com/rubygems/bundler/issues/4326), @segiddins) + +## 1.12.0.pre.2 (2016-02-26) + +### Performance: + + - speed up `bundle exec` by `load`ing the executable whenever possible, saving roughly .2 seconds per invocation (@segiddins) + +### Features: + + - add a `--patch` flag for `bundle outdated` (@RochesterinNYC) + - add `Bundler.clean_env` and `Bundler.original_env` ([#4232](https://github.com/rubygems/bundler/issues/4232), @njam) + - add `--frozen` support to `bundle package` ([#3356](https://github.com/rubygems/bundler/issues/3356), @RochesterinNYC) + +### Bug fixes: + + - place bundler loaded gems after `-I` and `RUBYLIB` (@Elffers) + - give a better error message when filesystem access raises an `EPROTO` error ([#3581](https://github.com/rubygems/bundler/issues/3581), [#3932](https://github.com/bundler/bundler/issues/3932), [#4163](https://github.com/bundler/bundler/issues/4163), @RochesterinNYC) + - give a better error message when both `--deployment` and `--system` are used together (@RochesterinNYC) + - fix `$PATH` being preserved for use in `Bundler.with_clean_env` ([#4251](https://github.com/rubygems/bundler/issues/4251), @segiddins, @njam) + - give a better error message when running `bundle outdated` in frozen mode ([#4287](https://github.com/rubygems/bundler/issues/4287), @RochesterinNYC) + - handle when `http_proxy` is set to `:no_proxy` in the rubygems configuration ([#4294](https://github.com/rubygems/bundler/issues/4294), @segiddins) + - give a better error message when authentication details aren't properly escaped ([#4288](https://github.com/rubygems/bundler/issues/4288), @RochesterinNYC) + - fix `bundle outdated --minor` to only report updates that match the current minor version (@RochesterinNYC) + - fix extra dependencies being resolved unnecessarily ([#4276](https://github.com/rubygems/bundler/issues/4276), @segiddins) + - give a better error message when missing specs due to platform mis-matches ([#4259](https://github.com/rubygems/bundler/issues/4259), @RochesterinNYC) + - skip rebuilding extensions for git gems if they are already built ([#4082](https://github.com/rubygems/bundler/issues/4082), @csfrancis, @indirect, @segiddins) + - fix `bundle install` not installing when the `no_install` setting is set ([#3966](https://github.com/rubygems/bundler/issues/3966), @chulkilee, @segiddins) + +## 1.12.0.pre.1 (2016-02-09) + +### Performance: + + - speed up `bundle install` and `bundle update` by using the new compact gem index (@segiddins, @fotanus, @indirect) + - speed up `bundle exec` by avoiding loading the gemfile twice ([#2951](https://github.com/rubygems/bundler/issues/2951), [#2952](https://github.com/bundler/bundler/issues/2952), @segiddins) + +### Features: + + - add support for using version operators to specify ruby versions in the Gemfile (@jtarchie) + - redirect `--help` flag for plugins to that plugin's man page (@RochesterinNYC) + - support probing a mirror with a fallback timeout ([#4128](https://github.com/rubygems/bundler/issues/4128), @pcarranza) + - add `--full-index` option to `bundle lock` (@segiddins) + - support running with frozen string literals (@deepj, @segiddins) + - add `--major` and `--minor` options to `bundle outdated` ([#3805](https://github.com/rubygems/bundler/issues/3805), @cirdes) + - allow passing a custom `ui` to `bundler/inline` (@lamont-granquist) + - add support for ruby 2.4 ([#4266](https://github.com/rubygems/bundler/issues/4266), @segiddins) + - add `bundle outdated --parseable` for machine-readable output (@RochesterinNYC) + +### Bug fixes: + + - fix `bundle package --all` recursing endlessly ([#4158](https://github.com/rubygems/bundler/issues/4158), @RochesterinNYC) + - fail fast on more errors when fetching remote resources ([#4154](https://github.com/rubygems/bundler/issues/4154), @RochesterinNYC) + - give a better error message when a given git commit can't be found ([#4140](https://github.com/rubygems/bundler/issues/4140), @doy) + - give a better error message when `bundle clean` doesn't have sufficient permissions ([#4170](https://github.com/rubygems/bundler/issues/4170), @RochesterinNYC) + - give a better error message when reading a bundler config file fails (@segiddins) + - restrict platforms when referencing a `gemspec` in the `Gemfile` to those defined in the gemspec ([#4102](https://github.com/rubygems/bundler/issues/4102), [#4150](https://github.com/bundler/bundler/issues/4150), @smellsblue) + - fix `bundle gem` with minitest to use the correct rake task (@kotoshenya) + - give a better error message when ssl isn't available ([#4054](https://github.com/rubygems/bundler/issues/4054), @RochesterinNYC) + - print the original `require` error when `Bundler.require` fails ([#4182](https://github.com/rubygems/bundler/issues/4182), @RochesterinNYC) + - give a better error message when certain resources are temporarily unavailable ([#4183](https://github.com/rubygems/bundler/issues/4183), @RochesterinNYC) + - fix returning case-sensitive gem mirror URIs on ruby 2.3 (@segiddins) + - ignore colorized output from `git` when determining the current branch ([#4056](https://github.com/rubygems/bundler/issues/4056), @agis-) + - fix storing the shared gems config option as a boolean (@vassilevsky) + - add support for running `bundle gem --exe` instead of using the `--bin` option (@christhekeele) + - fix `exec`-ing with 0 args in a directory with spaces ([#4230](https://github.com/rubygems/bundler/issues/4230), @segiddins) + - avoid installing extraneous gems when resolving to an older version of a spec ([#4101](https://github.com/rubygems/bundler/issues/4101), [#4198](https://github.com/bundler/bundler/issues/4198), @segiddins) + - ensure paths resolved when parsing a gemfile are relative to that file ([#3349](https://github.com/rubygems/bundler/issues/3349), @dtognazzini) + - give a better error message when encountering an invalid gemspec ([#4248](https://github.com/rubygems/bundler/issues/4248), [#4275](https://github.com/bundler/bundler/issues/4275), @RochesterinNYC) + - preserve the original `PATH` in `Bundler.with_clean_env` ([#4251](https://github.com/rubygems/bundler/issues/4251), @segiddins) + - ensure standalone file paths are relative to the project root ([#4144](https://github.com/rubygems/bundler/issues/4144), @glennpratt) + +## 1.11.2 (2015-12-15) + +### Bug fixes: + + - _really_ stop calling `required_ruby_version` on nil @specifications ([#4147](https://github.com/rubygems/bundler/issues/4147), @indirect) + +## 1.11.1 (2015-12-15) + +### Bug fixes: + + - lazy-load Psych, again ([#4149](https://github.com/rubygems/bundler/issues/4149), @indirect) + - allow gemspec gems on other platforms ([#4150](https://github.com/rubygems/bundler/issues/4150), @indirect) + - fix --no-coc and --no-mit flags on `gem` ([#4148](https://github.com/rubygems/bundler/issues/4148), @RochesterinNYC) + - stop calling `required_ruby_version` on nil @specifications ([#4147](https://github.com/rubygems/bundler/issues/4147), @indirect) + +## 1.11.0 (2015-12-12) + + No changes. + +## 1.11.0.pre.2 (2015-12-06) + +### Bug fixes: + + - fail gracefully when trying to execute a non-executable file ([#4081](https://github.com/rubygems/bundler/issues/4081), @fotanus) + - fix a crash when pushing a gem via `rake release` (@segiddins) + +## 1.11.0.pre.1 (2015-11-29) + +### Features: + + - actual Gemfile and lockfile filenames are used in messages ([#3672](https://github.com/rubygems/bundler/issues/3672), @segiddins) + - the git remote for `rake release` is now customizable (@skateman) + - file access permissions errors are now much more friendly ([#3703](https://github.com/rubygems/bundler/issues/3703), [#3735](https://github.com/bundler/bundler/issues/3735), [#3858](https://github.com/bundler/bundler/issues/3858), [#3988](https://github.com/bundler/bundler/issues/3988), [#4009](https://github.com/bundler/bundler/issues/4009) @repinel, @Elffers, @segiddins, @agis-) + - add support for showing help for plugin commands (@tf) + - send `X-Gemfile-Source` header to source mirrors (@agis-) + - show what version upstream dependencies were resolved to in conflict messages (@segiddins) + - add support for using bundler setting to add private access credentials for git sources (@frsyuki) + - take into consideration HTTP proxy settings in `.gemrc` (@PG-kura) + - allow specifying a gem host to push to in the `GEM_HOST` environment variable (@pmenglund) + - when gempec `required_ruby_version` is available and the Gemfile specifies a ruby version, resolve for the given ruby version (@segiddins) + - allow setting a `silence_root_warning` setting to silence the warning when `bundle install` is run as root (@blackxored) + - update the `bundle gem` code of conduct template to Contributor Covenant v1.3.0 (@CoralineAda) + - add support for specifying gems to update when running `bundle lock` via `--update gem1 gem2` (@JuanitoFatas) + - added support for MRI 2.3 (@amatsuda) + - show a helpful message when requiring a file in `bundler require` fails ([#3960](https://github.com/rubygems/bundler/issues/3960), @agis-) + - include git revision hash when printing a git source ([#3433](https://github.com/rubygems/bundler/issues/3433), @agis-) + - improve hint when a resolution conflict occurs (@seanlinsley) + - show a friendly error when a git ref is not found ([#3879](https://github.com/rubygems/bundler/issues/3879), @agis-) + - improve error message when sources are not absolute URIs ([#3925](https://github.com/rubygems/bundler/issues/3925), @agis-) + - add `pkg` to rake's clobber list ([#3676](https://github.com/rubygems/bundler/issues/3676), @jasonkarns) + - retry fetching specs when fetching version metadata fails (@jingweno) + +### Bug fixes: + + - avoid showing bundler version warning messages twice (@fotanus) + - fix running `bundle check` with `--path` when the gems are only installed globally (@akihiro17) + - fix `bin/setup` from `bundle gem` assuming `bash` is in `/bin` + - fail more gracefully when an HTTP remote is unreachable ([#3765](https://github.com/rubygems/bundler/issues/3765), @steverob) + - fix a warning running `bundle exec` on jruby 9.0.0.0 (@deivid-rodriguez, @mastfish) + - fix the `bundle gem` readme when no tests are generated (@roseweixel) + - the dependencies on test gems in `bundle gem` are now locked to major versions ([#3811](https://github.com/rubygems/bundler/issues/3811), @indirect) + - fix the paths for native extensions generated by `--standalone` ([#3813](https://github.com/rubygems/bundler/issues/3813), @AlexanderPavlenko) + - fix trying to cache a gem that has no source (@EduardoBautista) + - fix `--source` option to `bundle update` causing incorrect gem unlocking ([#3759](https://github.com/rubygems/bundler/issues/3759), [#3761](https://github.com/bundler/bundler/issues/3761), @neoeno) + - fix handling an empty `BUNDLE_GEMFILE` environment variables ([#3678](https://github.com/rubygems/bundler/issues/3678), @agis-) + - avoid cleaning up gem extension directory in `bundle clean` (@Sirupsen) + - fix the `ssl_verify_mode` setting not being treated as a number (@goughy000) + - fix not retrying on zlib errors ([#4047](https://github.com/rubygems/bundler/issues/4047), @andremedeiros) + - fix a warning being shown for using `URI.encode` (@EduardoBautista) + - fix handling of fatal HTTP errors ([#3830](https://github.com/rubygems/bundler/issues/3830), @indirect) + - ensure all `sudo` access is done in a thread-safe manner ([#3910](https://github.com/rubygems/bundler/issues/3910), @agis-) + - fix caching gems with a path with the same prefix as the bundled application (@indirect) + - fix showing gemspec validation errors on `bundle exec` ([#3895](https://github.com/rubygems/bundler/issues/3895), @agis-) + - distinguish Gemfile syntax and evaluation errors ([#3783](https://github.com/rubygems/bundler/issues/3783), @agis-) + - fix nested Gemfile sources not restoring the previous source ([#3974](https://github.com/rubygems/bundler/issues/3974), @agis-) + - fix the `RUBYLIB` environment variable not being cleaned ([#3982](https://github.com/rubygems/bundler/issues/3982), @agis-) + - fix handling a dependency missing from `Gemfile.lock` so parallel installation does not deadlock ([#4012](https://github.com/rubygems/bundler/issues/4012), @lukaso) + - also print gemspecs in `bundle env` output (@agis-) + - fix handling when a `path` source does not have a gemspec but a lockfile says there is ([#4004](https://github.com/rubygems/bundler/issues/4004), @segiddins) + - show a warning when the `RUBYGEMS_GEMDEPS` environment variable is set ([#3656](https://github.com/rubygems/bundler/issues/3656), @agis-) + - fix handling invalid RubyGems configuration files ([#4042](https://github.com/rubygems/bundler/issues/4042), @agis-) + - fix `bundle console` falling back to `irb` when the preferred console is unavailable (@felixbuenemann) + - restrict platforms when referencing a `gemspec` in the `Gemfile` to those defined in the gemspec ([#4102](https://github.com/rubygems/bundler/issues/4102), @smellsblue) + +### Performance: + + - speed up dependency resolution in pathological cases by 25x ([#3803](https://github.com/rubygems/bundler/issues/3803), @segiddins) + - drop string allocations when searching for gems (@jrafanie) + +## 1.10.6 (2015-07-22) + +### Bug fixes: + + - only warn on invalid gemspecs (@indirect) + - fix installing dependencies in the correct order ([#3799](https://github.com/rubygems/bundler/issues/3799), @pducks32) + - fix sorting of mixed DependencyLists ([#3762](https://github.com/rubygems/bundler/issues/3762), @tony-spataro-rs) + - fix `install_if` conditionals when using the block form (@danieltdt) + +## 1.10.5 (2015-06-24) + +### Bug fixes: + + - don't add or update BUNDLED WITH during `install` with no changes (@segiddins) + - fix sorting of mixed DependencyLists with RubyGems >= 2.23 ([#3762](https://github.com/rubygems/bundler/issues/3762), @tony-spataro-rs) + - speed up resolver for path and git gems (@segiddins) + - fix `install --force` to not reinstall Bundler ([#3743](https://github.com/rubygems/bundler/issues/3743), @karlo57) + +## 1.10.4 (2015-06-16) + +### Bug fixes: + + - don't add BUNDLED WITH to the lock when Spring runs `check` over and over (@indirect) + - display "with native extensions" log output correctly (@ivantsepp) + - alias `i` to `install`, `c` to `check`, and `e` to `exec` (@indirect) + +## 1.10.3 (2015-06-03) + +### Bug fixes: + + - allow missing gemspec files when validating path and git gems ([#3686](https://github.com/rubygems/bundler/issues/3686), [#3698](https://github.com/bundler/bundler/issues/3698), @segiddins) + - fix regression in `rake install` ([#3701](https://github.com/rubygems/bundler/issues/3701), [#3705](https://github.com/bundler/bundler/issues/3705), @segiddins) + - fix regression when calling `gem` with `bundle exec` or `-rbundler/setup` ([#3699](https://github.com/rubygems/bundler/issues/3699), @segiddins) + - fix `bundler/inline` requiring a newly-installed gem ([#3693](https://github.com/rubygems/bundler/issues/3693), @indirect, @segiddins) + +## 1.10.2 (2015-05-29) + +### Bug fixes: + + - fix regression in `bundle update GEM` performance introduced in 1.10.0 ([#3687](https://github.com/rubygems/bundler/issues/3687), @segiddins) + +## 1.10.1 (2015-05-28) + +### Bug fixes: + + - silence ruby warning when running CLI commands (@segiddins) + - validate gemspecs in non-packaging mode ([#3681](https://github.com/rubygems/bundler/issues/3681), @segiddins) + - ensure the same chdir mutex as RubyGems is used ([#3680](https://github.com/rubygems/bundler/issues/3680), @segiddins) + +## 1.10.0 (2015-05-28) + + No changes. + +## 1.10.0.rc (2015-05-16) + +### Features: + + - dramatically speed up resolving some slow Gemfiles ([#3635](https://github.com/rubygems/bundler/issues/3635), @segiddins) + - track CI platforms running Bundler ([#3646](https://github.com/rubygems/bundler/issues/3646), @fotanus) + +### Bug fixes: + + - allow `viz` to work with prereleases ([#3621](https://github.com/rubygems/bundler/issues/3621), [#3217](https://github.com/bundler/bundler/issues/3217), @aprescott) + - validate gemspecs used in path and git gems ([#3639](https://github.com/rubygems/bundler/issues/3639), @segiddins, @indirect) + - stop printing config warnings when config is unchanged ([#3649](https://github.com/rubygems/bundler/issues/3649), @fotanus, @indirect) + - Without groups saved via `config` are no longer ignored when the `--without` flag is used + +## 1.10.0.pre.2 (2015-05-07) + +### Bug fixes: + + - make BUNDLED WITH backwards compatible ([#3623](https://github.com/rubygems/bundler/issues/3623), @segiddins) + +## 1.10.0.pre.1 (2015-05-05) + +### Bug fixes: + + - always clean up tmp dirs ([#3277](https://github.com/rubygems/bundler/issues/3277), @hone, @indirect, @segiddins) + +## 1.10.0.pre (2015-05-03) + +### Features: + + - support gem extensions built into any directory on RubyGems 2.2+ ([#3582](https://github.com/rubygems/bundler/issues/3582), @voxik) + - add 'bundler/inline' which provides a `gemfile` method ([#3440](https://github.com/rubygems/bundler/issues/3440), @segiddins) + - improved error reports for Gemfile errors ([#3480](https://github.com/rubygems/bundler/issues/3480), @segiddins) + - `lock` command ([#3437](https://github.com/rubygems/bundler/issues/3437), @segiddins) + - add `ignore_messages` config to suppress post-install text ([#3510](https://github.com/rubygems/bundler/issues/3510), @pducks32) + - improve `gem` minitest template ([#3513](https://github.com/rubygems/bundler/issues/3513), [#3515](https://github.com/bundler/bundler/issues/3515), @arthurnn) + - add `install --force` to re-install installed gems ([#3519](https://github.com/rubygems/bundler/issues/3519), @segiddins) + - show more `outdated` information, including groups (@smlance, @indirect) + - add optional groups to the Gemfile ([#3531](https://github.com/rubygems/bundler/issues/3531), @jhass) + - accept glob argument to `gemspec` in Gemfile ([#3464](https://github.com/rubygems/bundler/issues/3464), @pjump) + - make timeouts and retries configurable via `config` ([#3601](https://github.com/rubygems/bundler/issues/3601), @pducks32) + - add `install_if` Gemfile method for conditional installs ([#3611](https://github.com/rubygems/bundler/issues/3611), @segiddins) + +### Bug fixes: + + - standalone mode now uses builtin gems correctly ([#3610](https://github.com/rubygems/bundler/issues/3610), @segiddins) + - fix `rake spec:deps` on MinGW Ruby 2.0+ ([#3487](https://github.com/rubygems/bundler/issues/3487), @marutosi) + - remember all y/n answers when generating gems ([#3579](https://github.com/rubygems/bundler/issues/3579), @pducks32) + +### Performance: + + - use RubyGems stub specifications when possible ([#3580](https://github.com/rubygems/bundler/issues/3580), @segiddins) + +### Deprecations: + + - deprecated the (never enabled) `bundle_ruby` binary (@smlance) + +## 1.9.10 (2015-06-22) + +### Features: + + - the `BUNDLED WITH` section of lockfiles generated by 1.10+ will be preserved (@segiddins) + +## 1.9.9 (2015-05-16) + +### Bug fixes: + + - read mirror and credential settings from older versions ([#3557](https://github.com/rubygems/bundler/issues/3557), @Strech) + +## 1.9.8 (2015-05-12) + +### Bug fixes: + + - fix regression in sudo mode introduced by 1.9.7 ([#3642](https://github.com/rubygems/bundler/issues/3642), @segiddins) + +## 1.9.7 (2015-05-11) + +### Bug fixes: + + - always clean up tmp dirs ([#3277](https://github.com/rubygems/bundler/issues/3277), @hone, @indirect, @segiddins) + +## 1.9.6 (2015-05-02) + +### Bug fixes: + + - use RubyGems spec stubs if available (@segiddins) + - allow creating gems with names containing two dashes ([#3483](https://github.com/rubygems/bundler/issues/3483), @janlelis) + - allow creating gems with names extending constants ([#3603](https://github.com/rubygems/bundler/issues/3603), @amatsuda) + +## 1.9.5 (2015-04-29) + +### Bug fixes: + + - respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +## 1.9.4 (2015-04-13) + +### Bug fixes: + + - fix regression in installing x86 and universal gems ([#3565](https://github.com/rubygems/bundler/issues/3565), @jdmundrawala) + - improve error when gems are missing ([#3564](https://github.com/rubygems/bundler/issues/3564), @sealocal) + +## 1.9.3 (2015-04-12) + +### Bug fixes: + + - handle removal of `specs` from ruby/rubygems@620910 ([#3558](https://github.com/rubygems/bundler/issues/3558), @indirect) + - install 'universal' gems on Windows ([#3066](https://github.com/rubygems/bundler/issues/3066), @jdmundrawala) + - stop passing --local during `rake install` task ([#3236](https://github.com/rubygems/bundler/issues/3236), @indirect) + - guard against all possible accidental public gem pushes ([#3533](https://github.com/rubygems/bundler/issues/3533), @indirect) + +## 1.9.2 (2015-03-30) + +### Bug fixes: + + - ensure gem executables are executable ([#3517](https://github.com/rubygems/bundler/issues/3517), [#3511](https://github.com/bundler/bundler/issues/3511), @indirect) + - fix warnings in Molinillo ([#3516](https://github.com/rubygems/bundler/issues/3516), @segiddins) + - ensure duplicate dependencies do not propagate ([#3522](https://github.com/rubygems/bundler/issues/3522), @segiddins) + - keep gems locked when updating another gem from the same source ([#3520](https://github.com/rubygems/bundler/issues/3520), @indirect) + - resolve race that could build gems without saved arguments ([#3404](https://github.com/rubygems/bundler/issues/3404), @indirect) + +## 1.9.1 (2015-03-21) + +### Bug fixes: + + - avoid exception in 'bundler/gem_tasks' ([#3492](https://github.com/rubygems/bundler/issues/3492), @segiddins) + +## 1.9.0 (2015-03-20) + +## 1.9.0.rc (2015-03-13) + +### Bug fixes: + + - make Bundler.which stop finding directories (@nohoho) + - handle Bundler prereleases correctly ([#3470](https://github.com/rubygems/bundler/issues/3470), @segiddins) + - add before_install to .travis.yml template for new gems (@kodnin) + +## 1.9.0.pre.1 (2015-03-11) + +### Bug fixes: + + - make `gem` command work again (@arthurnn) + +## 1.9.0.pre (2015-03-11) + +### Features: + + - prefer gemspecs closest to the directory root ([#3428](https://github.com/rubygems/bundler/issues/3428), @segiddins) + - debug log for API request limits ([#3452](https://github.com/rubygems/bundler/issues/3452), @neerfri) + +### Enhancements: + + - Molinillo resolver, shared with CocoaPods (@segiddins) + - updated Thor to v0.19.1 (@segiddins) + +## 1.8.9 (2015-05-02) + +### Bug fixes: + + - Use RubyGems spec stubs if available (@segiddins) + +## 1.8.8 (2015-04-29) + +### Bug fixes: + + - Respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +## 1.8.7 (2015-04-07) + +### Bug fixes: + + - stop suppressing errors inside gems that get required ([#3549](https://github.com/rubygems/bundler/issues/3549), @indirect) + +## 1.8.6 (2015-03-30) + +### Bug fixes: + + - keep gems locked when updating another gem from the same source ([#3250](https://github.com/rubygems/bundler/issues/3250), @indirect) + - resolve race that could build gems without saved arguments ([#3404](https://github.com/rubygems/bundler/issues/3404), @indirect) + +## 1.8.5 (2015-03-11) + +### Bug fixes: + + - remove MIT license from gemspec when removing license file (@indirect) + - respect 'no' immediately as well as saving it in `gem` config (@kirs) + +## 1.8.4 (2015-03-05) + +### Bug fixes: + + - document --all-platforms option ([#3449](https://github.com/rubygems/bundler/issues/3449), @moeffju) + - find gems from all sources on exec after install ([#3450](https://github.com/rubygems/bundler/issues/3450), @TimMoore) + +## 1.8.3 (2015-02-24) + +### Bug fixes: + + - handle boolean values for gem settings (@EduardoBautista) + - stop always looking for updated `path` gems ([#3414](https://github.com/rubygems/bundler/issues/3414), [#3417](https://github.com/bundler/bundler/issues/3417), [#3429](https://github.com/bundler/bundler/issues/3429), @TimMoore) + +## 1.8.2 (2015-02-14) + +### Bug fixes: + + - allow config settings for gems with 'http' in the name again ([#3398](https://github.com/rubygems/bundler/issues/3398), @TimMoore) + +## 1.8.1 (2015-02-13) + +### Bug fixes: + + - synchronize building git gem native extensions ([#3385](https://github.com/rubygems/bundler/issues/3385), @antifuchs & @indirect) + - set gemspec bindir correctly ([#3392](https://github.com/rubygems/bundler/issues/3392), @TimMoore) + - request lockfile deletion when it is malformed ([#3396](https://github.com/rubygems/bundler/issues/3396), @indirect) + - explain problem when mirror config is missing ([#3386](https://github.com/rubygems/bundler/issues/3386), @indirect) + - explain problem when caching causes permission error ([#3390](https://github.com/rubygems/bundler/issues/3390), @indirect) + - normalize URLs in config keys ([#3391](https://github.com/rubygems/bundler/issues/3391), @indirect) + +## 1.8.0 (2015-02-10) + +### Bug fixes: + + - gemfile `github` blocks now work ([#3379](https://github.com/rubygems/bundler/issues/3379), @indirect) + - look up installed gems in remote sources ([#3300](https://github.com/rubygems/bundler/issues/3300), [#3368](https://github.com/bundler/bundler/issues/3368), [#3377](https://github.com/bundler/bundler/issues/3377), [#3380](https://github.com/bundler/bundler/issues/3380), [#3381](https://github.com/bundler/bundler/issues/3381), @indirect) + - look up gems across all sources to satisfy dependencies ([#3365](https://github.com/rubygems/bundler/issues/3365), @keiths-osc) + - request dependencies for no more than 100 gems at a time ([#3367](https://github.com/rubygems/bundler/issues/3367), @segiddins) + +## 1.8.0.rc (2015-01-26) + +### Features: + + - add `config disable_multisource` option to ensure sources can't compete (@indirect) + +### Bug fixes: + + - don't add extra quotes around long, quoted config values (@aroben, [#3338](https://github.com/rubygems/bundler/issues/3338)) + +### Security fixes: + + - warn when more than one top-level source is present (@indirect) + +## 1.8.0.pre (2015-01-26) + +### Features: + + - add metadata allowed_push_host to new gem template ([#3002](https://github.com/rubygems/bundler/issues/3002), @juanitofatas) + - adds a `--no-install` flag to `bundle package` (@d-reinhold) + - add `bundle config auto_install true` to install automatically (@smashwilson) + - add `bundle viz --without` to exclude gem groups from resulting graph (@fnichol) + - prevent whitespace in gem declarations with clear messaging (@benlakey) + - tries to find a `bundler-` executable on your path for non-bundler commands (@andremedeiros) + - tries to find `gems.rb` and it's new counterpart, `gems.locked` (@andremedeiros) + - change the initial version of new gems from `0.0.1` to `0.1.0` (@petedmarsh) + - add `package --all-platforms` to cache gems for each known platform (@ccutrer) + - speed up `exec` when running commands on the $PATH (@kirs) + - add gem code of conduct file and option (@kirs) + - add config settings for gem license and tests (@kirs) + - add `bin/setup` and `bin/console` to new gems (@indirect) + - include configured user-agent in network requests (@indirect) + - support `github`, `gist`, and `bitbucket` options on git gems (@indirect) + - add `package --cache-path` and `config cache_path` for cache location (@jnraine) + - allow `config` to work even when a Gemfile is not present (@dholdren) + - add `config gemfile /path` for other Gemfile locations (@dholdren) + - add `github` method alonside the `git` method (@BenMorganIO) + +### Bug fixes: + + - reduce memory usage with threaded parallel workers (@Who828) + - support read-only git gems (@pmahoney) + - various resolver performance improvements (@dubek) + - untaint git gem paths for Rubygems compatibility (@tdtds) + +### Documentation: + + - add missing Gemfile global `path` explanation (@agenteo) + +## 1.7.15 (2015-04-29) + +### Bug fixes: + + - Respect Gemfile sources when installing a gem present in two sources ([#3585](https://github.com/rubygems/bundler/issues/3585), @tmoore) + +## 1.7.14 (2015-03-30) + +### Bug fixes: + + - Keep gems locked when updating another gem from the same source ([#3250](https://github.com/rubygems/bundler/issues/3250), @indirect) + - Don't add extra quotes around long, quoted config values (@aroben, [#3338](https://github.com/rubygems/bundler/issues/3338)) + +## 1.7.13 (2015-02-07) + +### Bug fixes: + + - Look up installed gems in remote sources ([#3300](https://github.com/rubygems/bundler/issues/3300), [#3368](https://github.com/bundler/bundler/issues/3368), [#3377](https://github.com/bundler/bundler/issues/3377), [#3380](https://github.com/bundler/bundler/issues/3380), [#3381](https://github.com/bundler/bundler/issues/3381), @indirect) + - Look up gems across all sources to satisfy dependencies ([#3365](https://github.com/rubygems/bundler/issues/3365), @keiths-osc) + - Request dependencies for no more than 100 gems at a time ([#3367](https://github.com/rubygems/bundler/issues/3367), @segiddins) + +## 1.7.12 (2015-01-08) + +### Bug fixes: + + - Always send credentials for sources, fixing private Gemfury gems ([#3342](https://github.com/rubygems/bundler/issues/3342), @TimMoore) + +## 1.7.11 (2015-01-04) + +### Bug fixes: + + - Recognize `:mri_22` and `:mingw_22`, rather than just `:ruby_22` ([#3328](https://github.com/rubygems/bundler/issues/3328), @myabc) + +## 1.7.10 (2014-12-29) + +### Bug fixes: + + - Fix source blocks sometimes causing deployment mode to fail wrongly ([#3298](https://github.com/rubygems/bundler/issues/3298), @TimMoore) + +### Features: + + - Support `platform :mri_22` and related version bits ([#3309](https://github.com/rubygems/bundler/issues/3309), @thomasfedb) + +## 1.7.9 (2014-12-09) + +### Bug fixes: + + - Fix an issue where bundler sometime spams one gem in Gemfile.lock ([#3216](https://github.com/rubygems/bundler/issues/3216), @Who828) + - Ensure bundle update installs the newer version of the gem ([#3089](https://github.com/rubygems/bundler/issues/3089), @Who828) + - Fix an regression which stopped Bundler from resolving some Gemfiles ([#3059](https://github.com/rubygems/bundler/issues/3059), [#3248](https://github.com/bundler/bundler/issues/3248), @Who828) + +## 1.7.8 (2014-12-06) + +### Bug fixes: + + - Hide credentials while warning about gems with ambiguous sources ([#3256](https://github.com/rubygems/bundler/issues/3256), @TimMoore) + +## 1.7.7 (2014-11-19) + +### Bug fixes: + + - Ensure server credentials stored in config or ENV will be used ([#3180](https://github.com/rubygems/bundler/issues/3180), @arronmabrey) + - Fix race condition causing errors while installing git-based gems ([#3174](https://github.com/rubygems/bundler/issues/3174), @Who828) + - Use single quotes in config so YAML won't add more quotes ([#3261](https://github.com/rubygems/bundler/issues/3261), @indirect) + +## 1.7.6 (2014-11-11) + +### Bug fixes: + + - CA certificates that work with all OpenSSLs (@luislavena, @indirect) + +## 1.7.5 (2014-11-10) + +### Bug fixes: + + - Fix --deployment with source blocks and non-alphabetical gems ([#3224](https://github.com/rubygems/bundler/issues/3224), @TimMoore) + - Vendor CA chain to validate new rubygems.org HTTPS certificate (@indirect) + +## 1.7.4 (2014-10-19) + +### Bug fixes: + + - Allow --deployment after `pack` while using source blocks ([#3167](https://github.com/rubygems/bundler/issues/3167), @TimMoore) + - Use dependency API even when HTTP credentials are in ENV ([#3191](https://github.com/rubygems/bundler/issues/3191), @fvaleur) + - Silence warnings (including root warning) in --quiet mode ([#3186](https://github.com/rubygems/bundler/issues/3186), @indirect) + - Stop asking gem servers for gems already found locally ([#2909](https://github.com/rubygems/bundler/issues/2909), @dubek) + +## 1.7.3 (2014-09-14) + +### Bug fixes: + + - `extconf.rb` is now generated with the right path for `create_makefile` (@andremedeiros) + - Fix various Ruby warnings (@piotrsanarki, @indirect) + +## 1.7.2 (2014-08-23) + +### Bug fixes: + + - Revert gem source sorting in lockfiles (@indirect) + +## 1.7.1 (2014-08-20) + +### Bug fixes: + + - Install gems from one source needed by gems in another source (@indirect) + - Install the same gem versions even after some are installed (@TimMoore) + - Download specs only when installing from servers (@indirect) + +## 1.7.0 (2014-08-13) + +### Security fixes: + + - Fix for CVE-2013-0334, installing gems from an unexpected source (@TimMoore) + +### Features: + + - Gemfile `source` calls now take a block containing gems from that source (@TimMoore) + - Added the `:source` option to `gem` to specify a source (@TimMoore) + +### Bug fixes: + + - Warn on ambiguous gems available from more than one source (@TimMoore) + +## 1.6.7 (2014-10-19) + +### Features: + + - warn to upgrade when using useless source blocks (@danfinnie) + +### Documentation: + + - explain how to use gem server credentials via ENV (@hwartig) + +## 1.6.6 (2014-08-23) + +### Bug fixes: + + - restore Gemfile credentials to Gemfile.lock (@indirect) + +## 1.6.5 (2014-07-23) + +### Bug fixes: + + - require openssl explicitly to fix rare HTTPS request failures (@indirect, [#3107](https://github.com/rubygems/bundler/issues/3107)) + +## 1.6.4 (2014-07-17) + +### Bug fixes: + + - fix undefined constant error when can't find gem during binstubs ([#3095](https://github.com/rubygems/bundler/issues/3095), @jetaggart) + - work when installed git gems are not writable ([#3092](https://github.com/rubygems/bundler/issues/3092), @pmahoney) + - don't store configured source credentials in Gemfile.lock ([#3045](https://github.com/rubygems/bundler/issues/3045), @lhz) + - don't include config source credentials in the lockfile (Lars Haugseth) + - use threads for jobs on Rubinius (@YorickPeterse) + - skip dependencies from other platforms (@mvz) + - work when Rubygems was built without SSL (@andremedeiros) + +## 1.6.3 (2014-06-16) + +### Bug fixes: + + - fix regression when resolving many conflicts ([#2994](https://github.com/rubygems/bundler/issues/2994), @Who828) + - use local gemspec for builtin gems during install --local ([#3041](https://github.com/rubygems/bundler/issues/3041), @Who828) + - don't warn about sudo when installing on Windows ([#2984](https://github.com/rubygems/bundler/issues/2984), @indirect) + - shell escape `bundle open` arguments (@indirect) + +## 1.6.2 (2014-04-13) + +### Bug fixes: + + - fix an exception when using builtin gems ([#2915](https://github.com/rubygems/bundler/issues/2915), [#2963](https://github.com/bundler/bundler/issues/2963), @gnufied) + - cache gems that are built in to the running ruby ([#2975](https://github.com/rubygems/bundler/issues/2975), @indirect) + - re-allow deploying cached git gems without git installed ([#2968](https://github.com/rubygems/bundler/issues/2968), @aughr) + - keep standalone working even with builtin gems (@indirect) + - don't update vendor/cache in deployment mode ([#2921](https://github.com/rubygems/bundler/issues/2921), @indirect) + +### Features: + + - warn informatively when `bundle install` is run as root ([#2936](https://github.com/rubygems/bundler/issues/2936), @1337807) + +## 1.6.1 (2014-04-02) + +### Bug fixes: + + - update C extensions when git gem versions change ([#2948](https://github.com/rubygems/bundler/issues/2948), @dylanahsmith) + +### Features: + + - add support for C extensions in sudo mode on Rubygems 2.2 + +## 1.6.0 (2014-03-28) + +### Bug fixes: + + - many Gemfiles that caused incorrect errors now resolve correctly (@Who828) + - redirects across hosts now work on rubies without OpenSSL ([#2686](https://github.com/rubygems/bundler/issues/2686), @grddev) + - gemspecs now handle filenames with newlines ([#2634](https://github.com/rubygems/bundler/issues/2634), @jasonmp85) + - support escaped characters in usernames and passwords (@punkie) + - no more exception on `update GEM` without lockfile (@simi) + - allow long config values ([#2823](https://github.com/rubygems/bundler/issues/2823), @kgrz) + - cache successfully even locked to gems shipped with Ruby ([#2869](https://github.com/rubygems/bundler/issues/2869), @aughr) + - respect NO_PROXY even if a proxy is configured ([#2878](https://github.com/rubygems/bundler/issues/2878), @stlay) + - only retry git commands that hit the network ([#2899](https://github.com/rubygems/bundler/issues/2899), @timmoore) + - fix NameError regression when OpenSSL is not available ([#2898](https://github.com/rubygems/bundler/issues/2898), @timmoore) + - handle exception installing when build_info owned by root (@Who828) + - skip HTTP redirects from rubygems.org, huge speed boost (@Who828) + +### Features: + + - resolver rewritten to avoid recursion (@Who828) + - add `git_source` for custom options like :github and :gist (@strzalek) + - HTTP auth may now be stored in `bundle config` (@smashwilson) + - some complex Gemfiles are resolved up to 10x faster (@Who828) + - add support for IRB alternatives such as Pry and Ripl (@joallard, @postmodern) + - highlight installed or updated gems ([#2722](https://github.com/rubygems/bundler/issues/2722), [#2741](https://github.com/bundler/bundler/issues/2741), @yaotti, @simi) + - display the `post_install_message` for gems installed via :git (@phallstrom) + - `bundle outdated --strict` now only reports allowed updates (@davidblondeau) + - `bundle show --verbose` Add gem summary to the output (@lardcanoe) + - `bundle gem GEM --ext` now generates a skeleton for a C extension (@superdealloc) + - Avoid using threequals operator where possible (@as-cii) + - Add `bundle update --group` to update specific group ([#2731](https://github.com/rubygems/bundler/issues/2731) @banyan) + +### Documentation: + + - Add missing switches for bundle-install(1) and bundle-update(1) (@as-cii) + +## 1.5.3 (2014-02-06) + +### Bug fixes: + + - find "missing" gems that are actually present ([#2780](https://github.com/rubygems/bundler/issues/2780), [#2818](https://github.com/bundler/bundler/issues/2818), [#2854](https://github.com/bundler/bundler/issues/2854)) + - use n-1 cores when given n jobs for parallel install (@jdickey) + +## 1.5.2 (2014-01-10) + +### Bug fixes: + + - fix integration with Rubygems 1.8.0-1.8.19 + - handle ENETDOWN exception during network requests + - gracefully shut down after interrupt during parallel install (@Who828) + - allow Rails to run Thor without debug mode (@rafaelfranca) + - set git binstub permissions by umask (@v-yarotsky) + - remove parallel install debug log + +## 1.5.1 (2013-12-28) + +### Bug fixes: + + - correctly find gems installed with Ruby by default + +## 1.5.0 (2013-12-26) + +### Features: + + - install missing gems if their specs are present (@hone) + +### Bug fixes: + + - use print for "Installing…" so messages are thread-safe (@TimMoore) + +## 1.5.0.rc.2 (2013-12-18) + +### Features: + + - Support threaded installation on Rubygems 2.0.7+ + - Debug installation logs in .bundle/install.log + +### Bug fixes: + + - Try to catch gem installation race conditions + +## 1.5.0.rc.1 (2013-11-09) + +### Features: + + - bundle update also accepts --jobs ([#2692](https://github.com/rubygems/bundler/issues/2692), @mrkn) + - add fork URL to README for new `bundle gem` ([#2665](https://github.com/rubygems/bundler/issues/2665), @zzak) + - add `bundle outdated --strict` ([#2685](https://github.com/rubygems/bundler/issues/2685), @davidblondeau) + - warn if same gem/version is added twice ([#2679](https://github.com/rubygems/bundler/issues/2679), @jendiamond) + - don't redownload installed specs for `bundle install` ([#2680](https://github.com/rubygems/bundler/issues/2680), @cainlevy) + - override gem sources with mirrors ([#2650](https://github.com/rubygems/bundler/issues/2650), @danielsdeleo, @mkristian) + +### Bug fixes: + + - fix sharing same SSL socket when forking workers for parallel install ([#2632](https://github.com/rubygems/bundler/issues/2632)) + - fix msg typo in GitNotAllowedError ([#2654](https://github.com/rubygems/bundler/issues/2654), @joyicecloud) + - fix Bundler.which for directories ([#2697](https://github.com/rubygems/bundler/issues/2697), @rhysd) + - properly require `Capistrano::Version` ([#2690](https://github.com/rubygems/bundler/issues/2690), @steveklabnik) + - search for git.exe and git + - fix the bug that downloads every spec when API fetcher encounters an error + - only retry network requests + +## 1.4.0.rc.1 (2013-09-29) + +### Features: + + - add support for the x64-mingw32 platform ([#2356](https://github.com/rubygems/bundler/issues/2356), [#2590](https://github.com/bundler/bundler/issues/2590), @larskanis) + - add :patchlevel option to ruby DSL + - add `bundler` bin ([#2598](https://github.com/rubygems/bundler/issues/2598), @kirs) + - friendly ambiguous error messages ([#2581](https://github.com/rubygems/bundler/issues/2581), [#2550](https://github.com/bundler/bundler/issues/2550), @jlsuttles, @jendiamond, @joyicecloud) + - add `:jruby_18` and `:jruby_19` platform options (@mcfiredrill) + - add X.509 client certificates for auth without passwords (@snackbandit) + - add `exec --keep-file-descriptors` for Ruby 1.9-like behavior on 2.0 (@steved555) + - print a better error when git is not installed (@joyicecloud) + - exit non-zero when `outdated` is run with an unknown gem (@joyicecloud) + - add `:ruby_21` platform option (@brandonblack) + - add `--retry` to retry failed network and git commands (@schneems) + - include command and versions in User-Agent (@indirect, @joyicecloud) + +### Bug fixes: + + - allow passwordless Basic Auth ([#2606](https://github.com/rubygems/bundler/issues/2606), @rykov) + - don't suggest `gem install foo` when `foo` is a git gem that fails (@kirs) + - revert [#2569](https://github.com/rubygems/bundler/issues/2569), staying compatible with git: instead of https: for :github gems + - handle exceptions while installing gems in parallel (@gnufied) + +## 1.4.0.pre.1 (2013-08-04) + +### Features: + + - retry network requests while installing gems ([#2561](https://github.com/rubygems/bundler/issues/2561), @ascherger) + - faster installs using gemspecs from the local system cache ([#2497](https://github.com/rubygems/bundler/issues/2497), @mipearson) + - add `bundle install -jN` for N parallel gem installations ([#2481](https://github.com/rubygems/bundler/issues/2481), @eagletmt) + - add `ENV['DEBUG_RESOLVER_TREE']` outputs resolver tree (@dblock) + - set $MANPATH so `bundle exec man name` works ([#1624](https://github.com/rubygems/bundler/issues/1624), @sunaku) + - use `man` instead of `groff` ([#2579](https://github.com/rubygems/bundler/issues/2579), @ixti, @simi) + - add Gemfile dependency info to bundle outdated output ([#2487](https://github.com/rubygems/bundler/issues/2487), @rahearn) + - allow `require: true` as an alias for `require: ` ([#2538](https://github.com/rubygems/bundler/issues/2538), @ndbroadbent) + - rescue and report Thor errors ([#2478](https://github.com/rubygems/bundler/issues/2478), @pjvds) + - detect cyclic dependencies ([#2564](https://github.com/rubygems/bundler/issues/2564), @gnufied) + - support multiple gems in `binstubs` ([#2576](https://github.com/rubygems/bundler/issues/2576), @lucasmazza) + - use https instead of git for :github gems ([#2569](https://github.com/rubygems/bundler/issues/2569), @fuadsaud) + - add quiet option to `bundle package` ([#2573](https://github.com/rubygems/bundler/issues/2573), @shtirlic) + - use RUBYLIB instead of RUBYOPT for better Windows support ([#2536](https://github.com/rubygems/bundler/issues/2536), @equinux) + +### Bug fixes: + + - reduce stack size while resolving to fix JRuby overflow ([#2510](https://github.com/rubygems/bundler/issues/2510), @headius) + - display GitErrors while loading specs in --verbose mode ([#2461](https://github.com/rubygems/bundler/issues/2461)) + - allow the same options hash to be passed to multiple gems ([#2447](https://github.com/rubygems/bundler/issues/2447)) + - handle missing binaries without an exception ([#2019](https://github.com/rubygems/bundler/issues/2019), @luismreis) + +## 1.3.6 (2014-01-08) + +### Bug fixes: + + - make gemspec path option preserve relative paths in lockfile (@bwillis) + - use umask when creating binstubs ([#1618](https://github.com/rubygems/bundler/issues/1618), @v-yarotsky) + - warn if graphviz is not installed ([#2435](https://github.com/rubygems/bundler/issues/2435), @Agis-) + - show git errors while loading gemspecs + - don't mutate gem method options hash ([#2447](https://github.com/rubygems/bundler/issues/2447)) + - print Thor errors ([#2478](https://github.com/rubygems/bundler/issues/2478), @pjvds) + - print Rubygems system exit errors (James Cook) + - more Pathnames into Strings for MacRuby (@kml) + - preserve original gemspec path (@bwillis) + - remove warning about deps with :git ([#1651](https://github.com/rubygems/bundler/issues/1651), @ixti) + - split git files on null ([#2634](https://github.com/rubygems/bundler/issues/2634), @jasonmp85) + - handle cross-host redirects without SSL ([#2686](https://github.com/rubygems/bundler/issues/2686), @grddev) + - handle Rubygems 2 security exception (@zzak) + - reinstall gems if they are missing with spec present + - set binstub permissions using umask ([#1618](https://github.com/rubygems/bundler/issues/1618), @v-yarotsky) + +## 1.3.5 (2013-04-03) + +### Features: + + - progress indicator while resolver is running (@chief) + +### Bug fixes: + + - update local overrides with orphaned revisions (@jamesferguson) + - revert to working quoting of RUBYOPT on Windows (@ogra) + - use basic auth even when SSL is not available (@jayniz) + - installing git gems without dependencies in deployment now works + +## 1.3.4 (2013-03-15) + +### Bug fixes: + + - load YAML on Rubygems versions that define module YAML + - fix regression that broke --without on ruby 1.8.7 + +## 1.3.3 (2013-03-13) + +### Features: + + - compatible with Rubygems 2.0.2 (higher and lower already work) + - mention skipped groups in bundle install and bundle update output (@simi) + - `gem` creates rake tasks for minitest (@coop) and rspec + +### Bug fixes: + + - require rbconfig for standalone mode + +## 1.3.2 (2013-03-07) + +### Features: + + - include rubygems.org CA chain + +### Bug fixes: + + - don't store --dry-run as a Bundler setting + +## 1.3.1 (2013-03-03) + +### Bug fixes: + + - include manpages in gem, restoring many help pages + - handle more SSL certificate verification failures + - check for the full version of SSL, which we need (@alup) + - gem rake task 'install' now depends on task 'build' (@sunaku) + +## 1.3.0 (2013-02-24) + +### Features: + + - raise a useful error when the lockfile contains a merge conflict (@zofrex) + - ensure `rake release` checks for uncommitted as well as unstaged (@benmoss) + - allow environment variables to be negated with 'false' and '0' (@brettporter) + - set $MANPATH inside `exec` for gems with man pages (@sunaku) + - partial gem names for `open` and `update` now return a list (@takkanm) + +### Bug fixes: + + - `update` now (again) finds gems that aren't listed in the Gemfile + - `install` now (again) updates cached gems that aren't in the Gemfile + - install Gemfiles with HTTP sources even without OpenSSL present + - display CerficateFailureError message in full + +## 1.3.0.pre.8 (2013-02-12) + +### Security fixes: + + - validate SSL certificate chain during HTTPS network requests + - don't send HTTP Basic Auth creds when redirected to other hosts (@perplexes) + - add `--trust-policy` to `install`, like `gem install -P` (@CosmicCat, [#2293](https://github.com/rubygems/bundler/issues/2293)) + +### Features: + + - optimize resolver when too new of a gem is already activated (@rykov, [#2248](https://github.com/rubygems/bundler/issues/2248)) + - update Net::HTTP::Persistent for SSL cert validation and no_proxy ENV + - explain SSL cert validation failures + - generate gemspecs when installing git repos, removing shellouts + - add pager selection (@csgui) + - add `licenses` command (@bryanwoods, [#1898](https://github.com/rubygems/bundler/issues/1898)) + - sort output from `outdated` (@richardkmichael, [#1896](https://github.com/rubygems/bundler/issues/1896)) + - add a .travis.yml to `gem -t` (@ndbroadbent, [#2143](https://github.com/rubygems/bundler/issues/2143)) + - inform users when the resolver starts + - disable reverse DNS to speed up API requests (@raggi) + +### Bug fixes: + + - raise errors while requiring dashed gems ([#1807](https://github.com/rubygems/bundler/issues/1807)) + - quote the Bundler path on Windows (@jgeiger, [#1862](https://github.com/rubygems/bundler/issues/1862), [#1856](https://github.com/bundler/bundler/issues/1856)) + - load gemspecs containing unicode (@gaffneyc, [#2301](https://github.com/rubygems/bundler/issues/2301)) + - support any ruby version in --standalone + - resolve some ruby -w warnings (@chastell, [#2193](https://github.com/rubygems/bundler/issues/2193)) + - don't scare users with an error message during API fallback + - `install --binstubs` is back to overwriting. thanks, SemVer. + +## 1.3.0.pre.7 (2013-01-22) + +### Bug fixes: + + - stubs for gems with dev deps no longer cause exceptions ([#2272](https://github.com/rubygems/bundler/issues/2272)) + - don't suggest binstubs to --binstubs users + +## 1.3.0.pre.6 (2013-01-22) + +### Features: + + - `binstubs` lists child gem bins if a gem has no binstubs + - `bundle gem --edit` will open the new gemspec (@ndbroadbent) + - `bundle gem --test rspec` now makes working tests (@tricknotes) + - `bundle env` prints info about bundler's environment (@peeja) + - add `BUNDLE_IGNORE_CONFIG` environment variable support (@richo) + +### Bug fixes: + + - don't overwrite custom binstubs during `install --binstubs` + - don't throw an exception if `binstubs` gem doesn't exist + - `bundle config` now works in directories without a Gemfile + +## 1.3.0.pre.5 (2013-01-09) + +### Features: + + - make `--standalone` require lines ruby engine/version agnostic + - add `--dry-run` to `bundle clean` (@wfarr, [#2237](https://github.com/rubygems/bundler/issues/2237)) + +### Bug fixes: + + - don't skip writing binstubs when doing `bundle install` + - distinguish between ruby 1.9/2.0 when using :platforms (@spastorino) + +## 1.3.0.pre.4 (2013-01-03) + +### Features: + + - `bundle binstubs ` to setup individual binstubs + - `bundle install --binstubs ""` will remove binstubs option + - `bundle clean --dry-run` will print out gems instead of removing them + +### Bug fixes: + + - Avoid stack traces when Ctrl+C during bundle command (@mitchellh) + - fix YAML parsing in in ruby-preview2 + +## 1.3.0.pre.3 (2012-12-21) + +### Features: + + - pushing gems during `rake release` can be disabled (@trans) + - installing gems with `rake install` is much faster (@utkarshkukreti) + - added platforms :ruby_20 and :mri_20, since the ABI has changed + - added '--edit' option to open generated gemspec in editor + +### Bug fixes: + + - :git gems with extensions now work with Rubygems >= 2.0 (@jeremy) + - revert SemVer breaking change to :github + - `outdated` exits non-zero if outdated gems found (@rohit, [#2021](https://github.com/rubygems/bundler/issues/2021)) + - https Gist URLs for compatibility with Gist 2.0 (@NARKOZ) + - namespaced gems no longer generate a superfluous directory (@banyan) + +## 1.3.0.pre.2 (2012-12-09) + +### Features: + + - `config` expands local overrides like `local.rack .` (@gkop, [#2205](https://github.com/rubygems/bundler/issues/2205)) + - `gem` generates files correctly for names like `jquery-rails` (@banyan, [#2201](https://github.com/rubygems/bundler/issues/2201)) + - use gems from gists with the :gist option in the Gemfile (@jgaskins) + +### Bug fixes: + + - Gemfile sources other than rubygems.org work even when .gemrc contains sources + - caching git gems now caches specs, fixing e.g. git ls-files (@bison, [#2039](https://github.com/rubygems/bundler/issues/2039)) + - `show GEM` now warns if the directory has been deleted (@rohit, [#2070](https://github.com/rubygems/bundler/issues/2070)) + - git output hidden when running in --quiet mode (@rohit) + +## 1.3.0.pre (2012-11-29) + +### Features: + + - compatible with Ruby 2.0.0-preview2 + - compatible with Rubygems 2.0.0.preview2 (@drbrain, @evanphx) + - ruby 2.0 added to the `:ruby19` ABI-compatible platform + - lazy load YAML, allowing Psych to be specified in the Gemfile + - significant performance improvements (@cheald, [#2181](https://github.com/rubygems/bundler/issues/2181)) + - `inject` command for scripted Gemfile additions (Engine Yard) + - :github option uses slashless arguments as repo owner (@rking) + - `open` suggests gem names for typos (@jdelStrother) + - `update` reports non-existent gems (@jdelStrother) + - `gem` option --test can generate rspec stubs (@MafcoCinco) + - `gem` option --test can generate minitest stubs (@kcurtin) + - `gem` command generates MIT license (@BrentWheeldon) + - gem rake task 'release' reuses existing tags (@shtirlic) + +### Bug fixes: + + - JRuby new works with HTTPS gem sources (@davidcelis) + - `install` installs both rake rake-built gems at once (@crowbot, [#2107](https://github.com/rubygems/bundler/issues/2107)) + - handle Errno::ETIMEDOUT errors (@jmoses) + - handle Errno::EAGAIN errors on JRuby + - disable ANSI coloring when output is redirected (@tomykaira) + - raise LoadErrors correctly during Bundler.require (@Empact) + - do not swallow --verbose on `bundle exec` (@sol, [#2102](https://github.com/rubygems/bundler/issues/2102)) + - `gem` generates gemspecs that block double-requires + - `gem` generates gemspecs that admit they depend on rake + +## 1.2.5 (2013-02-24) + +### Bug fixes: + + - install Gemfiles with HTTP sources even without OpenSSL present + - display CerficateFailureError message in full + +## 1.2.4 (2013-02-12) + +### Features: + + - warn about Ruby 2.0 and Rubygems 2.0 + - inform users when the resolver starts + - disable reverse DNS to speed up API requests (@raggi) + +### Bug fixes: + + - don't send user/pass when redirected to another host (@perplexes) + - load gemspecs containing unicode (@gaffneyc, [#2301](https://github.com/rubygems/bundler/issues/2301)) + - support any ruby version in --standalone + - resolve some ruby -w warnings (@chastell, [#2193](https://github.com/rubygems/bundler/issues/2193)) + - don't scare users with an error message during API fallback + +## 1.2.3 (2012-11-29) + +### Bug fixes: + + - fix exceptions while loading some gemspecs + +## 1.2.2 (2012-11-14) + +### Bug fixes: + + - support new Psych::SyntaxError for Ruby 2.0.0 (@tenderlove, @sol) + - `bundle viz` works with git gems again (@hirochachacha) + - recognize more cases when OpenSSL is not present + +## 1.2.1 (2012-09-19) + +### Bug fixes: + + - `bundle clean` now works with BUNDLE_WITHOUT groups again + - have a net/http read timeout around the Gemcutter API Endpoint + +## 1.2.0 (2012-08-30) + +### Bug fixes: + + - raise original error message from LoadError's + +### Documentation: + + - `platform` man pages + +## 1.2.0.rc.2 (2012-08-08) + +### Bug fixes: + + - `clean` doesn't remove gems that are included in the lockfile + +## 1.2.0.rc (2012-07-17) + +### Features: + + - `check` now has a `--dry-run` option (@svenfuchs, [#1811](https://github.com/rubygems/bundler/issues/1811)) + - loosen ruby directive for engines + - prune git/path directories inside vendor/cache (@josevalim, [#1988](https://github.com/rubygems/bundler/issues/1988)) + - update vendored thor to 0.15.2 (@sferik) + - add .txt to LICENSE (@postmodern, [#2001](https://github.com/rubygems/bundler/issues/2001)) + - add `config disable_local_branch_check` (@josevalim, [#1985](https://github.com/rubygems/bundler/issues/1985)) + - fall back on the full index when experiencing syck errors ([#1419](https://github.com/rubygems/bundler/issues/1419)) + - handle syntax errors in Ruby gemspecs ([#1974](https://github.com/rubygems/bundler/issues/1974)) + +### Bug fixes: + + - fix `pack`/`cache` with `--all` (@josevalim, [#1989](https://github.com/rubygems/bundler/issues/1989)) + - don't display warning message when `cache_all` is set + - check for `nil` PATH ([#2006](https://github.com/rubygems/bundler/issues/2006)) + - Always try to keep original GEM_PATH (@drogus, [#1920](https://github.com/rubygems/bundler/issues/1920)) + +## 1.2.0.pre.1 (2012-05-27) + +### Features: + + - Git gems import submodules of submodules recursively (@nwwatson, [#1935](https://github.com/rubygems/bundler/issues/1935)) + +### Bug fixes: + + - Exit from `check` with a non-zero status when frozen with no lock + - Use `latest_release` in Capistrano and Vlad integration ([#1264](https://github.com/rubygems/bundler/issues/1264)) + - Work around a Ruby 1.9.3p194 bug in Psych when config files are empty + +### Documentation: + + - Add instructions for local git repos to the `config` manpage + - Update the `Gemfile` manpage to include ruby versions (@stevenh512) + - When OpenSSL is missing, provide instructions for fixing ([#1776](https://github.com/rubygems/bundler/issues/1776) etc.) + - Unknown exceptions now link to ISSUES for help instead of a new ticket + - Correct inline help for `clean --force` (@dougbarth, [#1911](https://github.com/rubygems/bundler/issues/1911)) + +## 1.2.0.pre (2012-05-04) + +### Features: + + - bundle package now accepts --all to package git and path dependencies + - bundle config now accepts --local, --global and --delete options + - It is possible to override a git repository via configuration. + For instance, if you have a git dependency on rack, you can force + it to use a local repo with `bundle config local.rack ~/path/to/rack` + - Cache gemspec loads for performance (@dekellum, [#1635](https://github.com/rubygems/bundler/issues/1635)) + - add --full-index flag to `bundle update` (@fluxx, [#1829](https://github.com/rubygems/bundler/issues/1829)) + - add --quiet flag to `bundle update` (@nashby, [#1654](https://github.com/rubygems/bundler/issues/1654)) + - Add Bundler::GemHelper.gemspec (@knu, [#1637](https://github.com/rubygems/bundler/issues/1637)) + - Graceful handling of Gemfile syntax errors (@koraktor, [#1661](https://github.com/rubygems/bundler/issues/1661)) + - `bundle platform` command + - add ruby to DSL, to specify version of ruby + - error out if the ruby version doesn't match + +### Performance: + + - bundle exec shouldn't run Bundler.setup just setting the right rubyopts options is enough (@spastorino, [#1598](https://github.com/rubygems/bundler/issues/1598)) + +### Bug fixes: + + - Avoid passing RUBYOPT changes in with_clean_env block (@eric1234, [#1604](https://github.com/rubygems/bundler/issues/1604)) + - Use the same ruby to run subprocesses as is running rake (@brixen) + +### Documentation: + + - Add :github documentation in DSL (@zofrex, [#1848](https://github.com/rubygems/bundler/issues/1848), [#1851](https://github.com/bundler/bundler/issues/1851), [#1852](https://github.com/bundler/bundler/issues/1852)) + - Add docs for the --no-cache option (@fluxx, [#1796](https://github.com/rubygems/bundler/issues/1796)) + - Add basic documentation for bin_path and bundle_path (@radar) + - Add documentation for the run method in Bundler::Installer + +## 1.1.5 (2012-07-17) + +### Features: + + - Special case `ruby` directive from 1.2.0, so you can install Gemfiles that use it + +## 1.1.4 (2012-05-27) + +### Bug fixes: + + - Use `latest_release` in Capistrano and Vlad integration ([#1264](https://github.com/rubygems/bundler/issues/1264)) + - Unknown exceptions now link to ISSUES for help instead of a new ticket + - When OpenSSL is missing, provide instructions for fixing ([#1776](https://github.com/rubygems/bundler/issues/1776) etc.) + - Correct inline help for `clean --force` (@dougbarth, [#1911](https://github.com/rubygems/bundler/issues/1911)) + - Work around a Ruby 1.9.3p194 bug in Psych when config files are empty + +## 1.1.3 (2012-03-23) + +### Bug fixes: + + - escape the bundler root path (@tenderlove, [#1789](https://github.com/rubygems/bundler/issues/1789)) + +## 1.1.2 (2012-03-20) + +### Bug fixes: + + - Fix --deployment for multiple PATH sections of the same source ([#1782](https://github.com/rubygems/bundler/issues/1782)) + +## 1.1.1 (2012-03-14) + +### Bug fixes: + + - Rescue EAGAIN so the fetcher works on JRuby on Windows + - Stop asking users to report gem installation errors + - Clarify "no sources" message + - Use $\ so `bundle gem` gemspecs work on Windows (@postmodern) + - URI-encode gem names for dependency API (@rohit, [#1672](https://github.com/rubygems/bundler/issues/1672)) + - Fix `cache` edge case in rubygems 1.3.7 ([#1202](https://github.com/rubygems/bundler/issues/1202)) + +### Performance: + + - Reduce invocation of git ls-files in `bundle gem` gemspecs (@knu) + +## 1.1.0 (2012-03-07) + +### Bug fixes: + + - Clean up corrupted lockfiles on bundle installs + - Prevent duplicate GIT sources + - Fix post_install_message when uing the endpoint API + +## 1.1.rc.8 (2012-03-03) + +### Performance: + + - don't resolve if the Gemfile.lock and Gemfile haven't changed + +### Bug fixes: + + - Load gemspecs from git even when a released gem has the same version ([#1609](https://github.com/rubygems/bundler/issues/1609)) + - Declare an accurate Ruby version requirement of 1.8.7 or newer ([#1619](https://github.com/rubygems/bundler/issues/1619)) + - handle gemspec development dependencies correctly (@raggi, [#1639](https://github.com/rubygems/bundler/issues/1639)) + - Avoid passing RUBYOPT changes in with_clean_env block. (eric1234, [#1604](https://github.com/rubygems/bundler/issues/1604)) + +## 1.1.rc.7 (2011-12-29) + +### Bug fixes: + + - Fix bug where `clean` would break when using :path with no gemspec + +## 1.1.rc.6 (2011-12-22) + +### Bug fixes: + + - Fix performance regression from 1.0 (@spastorino, [#1511](https://github.com/rubygems/bundler/issues/1511), [#1591](https://github.com/bundler/bundler/issues/1591), [#1592](https://github.com/bundler/bundler/issues/1592)) + - Load gems correctly when GEM_HOME is blank + - Refresh gems so Bundler works from inside a bundle + - Handle empty .bundle/config files without an error + +## 1.1.rc.5 (2011-12-14) + +### Bug fixes: + + - Fix ASCII encoding errors with gem (rerelease with ruby 1.8) + +## 1.1.rc.4 (2011-12-14) + +### Features: + + - `bundle viz` has the option to output a DOT file instead of a PNG (@hirochachacha, [#683](https://github.com/rubygems/bundler/issues/683)) + +### Bug fixes: + + - Ensure binstubs generated when using --standalone point to the standalonde bundle (@cowboyd, [#1588](https://github.com/rubygems/bundler/issues/1588)) + - fix `bundle viz` (@hirochachacha, [#1586](https://github.com/rubygems/bundler/issues/1586)) + +## 1.1.rc.3 (2011-12-08) + +### Bug fixes: + + - fix relative_path so it checks Bundler.root is actually in the beginning of the path ([#1582](https://github.com/rubygems/bundler/issues/1582)) + - fix bundle outdated doesn't list all gems (@joelmoss, [#1521](https://github.com/rubygems/bundler/issues/1521)) + +## 1.1.rc.2 (2011-12-06) + +### Features: + + - Added README.md to `newgem` (@ognevsky, [#1574](https://github.com/rubygems/bundler/issues/1574)) + - Added LICENSE (MIT) to newgem (@ognevsky, [#1571](https://github.com/rubygems/bundler/issues/1571)) + +### Bug fixes: + + - only auto-namespace requires for implied requires ([#1531](https://github.com/rubygems/bundler/issues/1531)) + - fix bundle clean output for git repos ([#1473](https://github.com/rubygems/bundler/issues/1473)) + - use Gem.bindir for bundle clean ([#1544](https://github.com/rubygems/bundler/issues/1544), [#1532](https://github.com/bundler/bundler/issues/1532)) + - use `Gem.load_env_plugins` instead of `Gem.load_env_plugins` ([#1500](https://github.com/rubygems/bundler/issues/1500), [#1543](https://github.com/bundler/bundler/issues/1543)) + - differentiate Ruby 2.0 (trunk) from Ruby 1.9 (@tenderlove, [#1539](https://github.com/rubygems/bundler/issues/1539)) + - `bundle clean` handles 7 length git hash for bundle clean ([#1490](https://github.com/rubygems/bundler/issues/1490), [#1491](https://github.com/bundler/bundler/issues/1491)) + - fix Psych loading issues + - Search $PATH for a binary rather than shelling out to `which` (@tenderlove, [#1573](https://github.com/rubygems/bundler/issues/1573)) + - do not clear RG cache unless we actually modify GEM_PATH and GEM_HOME- use `Gem.load_env_plugins` instead of `Gem.load_env_plugins` ([#1500](https://github.com/rubygems/bundler/issues/1500), [#1543](https://github.com/bundler/bundler/issues/1543)) + - `newgem` now uses https://rubygems.org ([#1562](https://github.com/rubygems/bundler/issues/1562)) + - `bundle init` now uses https://rubygems.org (@jjb, [#1522](https://github.com/rubygems/bundler/issues/1522)) + - `bundle install/update` does not autoclean when using --path for semver + +### Documentation: + + - added documentation for --shebang option for `bundle install` (@lunks, [#1475](https://github.com/rubygems/bundler/issues/1475), [#1558](https://github.com/bundler/bundler/issues/1558)) + +## 1.1.rc (2011-10-03) + +### Features: + + - add `--shebang` option to bundle install (@bensie, [#1467](https://github.com/rubygems/bundler/issues/1467)) + - build passes on ruby 1.9.3rc1 ([#1458](https://github.com/rubygems/bundler/issues/1458), [#1469](https://github.com/bundler/bundler/issues/1469)) + - hide basic auth credentials for custom sources ([#1440](https://github.com/rubygems/bundler/issues/1440), [#1463](https://github.com/bundler/bundler/issues/1463)) + +### Bug fixes: + + - fix index search result caching ([#1446](https://github.com/rubygems/bundler/issues/1446), [#1466](https://github.com/bundler/bundler/issues/1466)) + - fix fetcher prints multiple times during install ([#1445](https://github.com/rubygems/bundler/issues/1445), [#1462](https://github.com/bundler/bundler/issues/1462)) + - don't mention API errors from non-rubygems.org sources + - fix autoclean so it doesn't remove bins that are used ([#1459](https://github.com/rubygems/bundler/issues/1459), [#1460](https://github.com/bundler/bundler/issues/1460)) + +### Documentation: + + - add :require => [...] to the gemfile(5) manpage (@nono, [#1468](https://github.com/rubygems/bundler/issues/1468)) + +## 1.1.pre.10 (2011-09-27) + +### Features: + + - `config system_bindir foo` added, works like "-n foo" in your .gemrc file + +## 1.1.pre.9 (2011-09-18) + +### Features: + + - `clean` will now clean up all old .gem and .gemspec files, cleaning up older pres + - `clean` will be automatically run after bundle install and update when using `--path` ([#1420](https://github.com/rubygems/bundler/issues/1420), [#1425](https://github.com/bundler/bundler/issues/1425)) + - `clean` now takes a `--force` option ([#1247](https://github.com/rubygems/bundler/issues/1247), [#1426](https://github.com/bundler/bundler/issues/1426)) + - `clean` will clean up cached git dirs in bundle clean ([#1390](https://github.com/rubygems/bundler/issues/1390)) + - remove deprecations from DSL ([#1119](https://github.com/rubygems/bundler/issues/1119)) + - autorequire tries directories for gems with dashed names ([#1205](https://github.com/rubygems/bundler/issues/1205)) + - adds a `--paths` flag to `bundle show` to list all the paths of bundled gems (@tiegz, [#1360](https://github.com/rubygems/bundler/issues/1360)) + - load rubygems plugins in the bundle binary (@tpope, [#1364](https://github.com/rubygems/bundler/issues/1364)) + - make `--standalone` respect `--path` (@cowboyd, [#1361](https://github.com/rubygems/bundler/issues/1361)) + +### Bug fixes: + + - Fix `clean` to handle nested gems in a git repo ([#1329](https://github.com/rubygems/bundler/issues/1329)) + - Fix conflict from revert of benchmark tool (@boffbowsh, [#1355](https://github.com/rubygems/bundler/issues/1355)) + - Fix fatal error when unable to connect to gem source ([#1269](https://github.com/rubygems/bundler/issues/1269)) + - Fix `outdated` to find pre-release gems that are installed. ([#1359](https://github.com/rubygems/bundler/issues/1359)) + - Fix color for ui. ([#1374](https://github.com/rubygems/bundler/issues/1374)) + - Fix installing to user-owned system gems on OS X + - Fix caching issue in the resolver ([#1353](https://github.com/rubygems/bundler/issues/1353), [#1421](https://github.com/bundler/bundler/issues/1421)) + - Fix :github DSL option + +## 1.1.pre.8 (2011-08-13) + +### Bug fixes: + + - Fix `bundle check` to not print fatal error message (@cldwalker, [#1347](https://github.com/rubygems/bundler/issues/1347)) + - Fix require_sudo when Gem.bindir isn't writeable ([#1352](https://github.com/rubygems/bundler/issues/1352)) + - Fix not asking Gemcutter API for dependency chain of git gems in --deployment ([#1254](https://github.com/rubygems/bundler/issues/1254)) + - Fix `install --binstubs` when using --path ([#1332](https://github.com/rubygems/bundler/issues/1332)) + +## 1.1.pre.7 (2011-08-08) + +### Bug fixes: + + - Fixed invalid byte sequence error while installing gem on Ruby 1.9 ([#1341](https://github.com/rubygems/bundler/issues/1341)) + - Fixed exception when sudo was needed to install gems (@spastorino) + +## 1.1.pre.6 (2011-08-08) + +### Bug fixes: + + - Fix cross repository dependencies ([#1138](https://github.com/rubygems/bundler/issues/1138)) + - Fix git dependency fetching from API endpoint ([#1254](https://github.com/rubygems/bundler/issues/1254)) + - Fixes for bundle outdated (@joelmoss, [#1238](https://github.com/rubygems/bundler/issues/1238)) + - Fix bundle standalone when using the endpoint ([#1240](https://github.com/rubygems/bundler/issues/1240)) + +### Features: + + - Implement `to_ary` to avoid calls to method_missing (@tenderlove, [#1274](https://github.com/rubygems/bundler/issues/1274)) + - bundle clean removes old .gem files (@cldwalker, [#1293](https://github.com/rubygems/bundler/issues/1293)) + - Correctly identify missing child dependency in error message + - Run pre-install, post-build, and post-install gem hooks for git gems (@warhammerkid, [#1120](https://github.com/rubygems/bundler/issues/1120)) + - create Gemfile.lock for empty Gemfile ([#1218](https://github.com/rubygems/bundler/issues/1218)) + +## 1.1.pre.5 (2011-06-11) + +### Bug fixes: + + - Fix LazySpecification on Ruby 1.9 (@dpiddy, [#1232](https://github.com/rubygems/bundler/issues/1232)) + - Fix HTTP proxy support (@leobessa, [#878](https://github.com/rubygems/bundler/issues/878)) + +### Features: + + - Speed up `install --deployment` by using the API endpoint + - Support Basic HTTP Auth for the API endpoint (@dpiddy, [#1229](https://github.com/rubygems/bundler/issues/1229)) + - Add `install --full-index` to disable the API endpoint, just in case + - Significantly speed up install by removing unneeded gemspec fetches + - `outdated` command shows outdated gems (@joelmoss, [#1130](https://github.com/rubygems/bundler/issues/1130)) + - Print gem post install messages (@csquared, [#1155](https://github.com/rubygems/bundler/issues/1155)) + - Reduce memory use by removing Specification.new inside method_missing (@tenderlove, [#1222](https://github.com/rubygems/bundler/issues/1222)) + - Allow `check --path` + +## 1.1.pre.4 (2011-05-05) + +### Bug fixes: + + - Fix bug that could prevent installing new gems + +## 1.1.pre.3 (2011-05-04) + +### Features: + + - Add `bundle outdated` to show outdated gems (@joelmoss) + - Remove BUNDLE_* from `Bundler.with_clean_env` (@wuputah) + - Add Bundler.clean_system, and clean_exec (@wuputah) + - Use git config for gem author name and email (@krekoten) + +### Bug fixes: + + - Fix error calling Bundler.rubygems.gem_path + - Fix error when Gem.path returns Gem::FS instead of String + +## 1.1.pre.2 (2011-04-28) + +### Features: + + - Add :github option to Gemfile DSL for easy git repos + - Merge all fixes from 1.0.12 and 1.0.13 + +## 1.1.pre.1 (2011-02-02) + +### Bug fixes: + + - Compatibility with changes made by Rubygems 1.5 + +## 1.1.pre (2011-01-21) + +### Features: + + - Add bundle clean. Removes unused gems from --path directory + - Initial Gemcutter Endpoint API work, BAI Fetching source index + - Added bundle install --standalone + - Ignore Gemfile.lock when building new gems + - Make it possible to override a .gemspec dependency's source in the + Gemfile + +### Breaking changes: + + - Removed bundle lock + - Removed bundle install + - Removed bundle install --production + - Removed bundle install --disable-shared-gems + +## 1.0.21 (2011-09-30) + + No changes. + +## 1.0.21.rc (2011-09-29) + +### Bug fixes: + + - Load Psych unless Syck is defined, because 1.9.2 defines YAML + +## 1.0.20 (2011-09-27) + +### Features: + + - Add platform :maglev (@timfel, [#1444](https://github.com/rubygems/bundler/issues/1444)) + +### Bug fixes: + + - Ensure YAML is required even if Psych is found + - Handle directory names that contain invalid regex characters + +## 1.0.20.rc (2011-09-18) + +### Features: + + - Rescue interrupts to `bundle` while loading bundler.rb ([#1395](https://github.com/rubygems/bundler/issues/1395)) + - Allow clearing without groups by passing `--without ''` ([#1259](https://github.com/rubygems/bundler/issues/1259)) + +### Bug fixes: + + - Manually sort requirements in the lockfile ([#1375](https://github.com/rubygems/bundler/issues/1375)) + - Remove several warnings generated by ruby -w (@stephencelis) + - Handle trailing slashes on names passed to `gem` ([#1372](https://github.com/rubygems/bundler/issues/1372)) + - Name modules for gems like 'test-foo_bar' correctly ([#1303](https://github.com/rubygems/bundler/issues/1303)) + - Don't require Psych if Syck is already loaded ([#1239](https://github.com/rubygems/bundler/issues/1239)) + +## 1.0.19.rc (2011-09-13) + +### Features: + + - Compatibility with Rubygems 1.8.10 installer changes + - Report gem installation failures clearly (@rwilcox, [#1380](https://github.com/rubygems/bundler/issues/1380)) + - Useful error for cap and vlad on first deploy (@nexmat, @kirs) + +### Bug fixes: + + - `exec` now works when the command contains 'exec' + - Only touch lock after changes on Windows (@robertwahler, [#1358](https://github.com/rubygems/bundler/issues/1358)) + - Keep load paths when #setup is called multiple times (@radsaq, [#1379](https://github.com/rubygems/bundler/issues/1379)) + +## 1.0.18 (2011-08-16) + +### Bug fixes: + + - Fix typo in DEBUG_RESOLVER (@geemus) + - Fixes rake 0.9.x warning (@mtylty, [#1333](https://github.com/rubygems/bundler/issues/1333)) + - Fix `bundle cache` again for rubygems 1.3.x + +### Features: + + - Run the bundle install earlier in a Capistrano deployment (@cgriego, [#1300](https://github.com/rubygems/bundler/issues/1300)) + - Support hidden gemspec (@trans, @cldwalker, [#827](https://github.com/rubygems/bundler/issues/827)) + - Make fetch_specs faster (@zeha, [#1294](https://github.com/rubygems/bundler/issues/1294)) + - Allow overriding development deps loaded by #gemspec (@lgierth, [#1245](https://github.com/rubygems/bundler/issues/1245)) + +## 1.0.17 (2011-08-08) + +### Bug fixes: + + - Fix rake issues with rubygems 1.3.x ([#1342](https://github.com/rubygems/bundler/issues/1342)) + - Fixed invalid byte sequence error while installing gem on Ruby 1.9 ([#1341](https://github.com/rubygems/bundler/issues/1341)) + +## 1.0.16 (2011-08-08) + +### Features: + + - Performance fix for MRI 1.9 (@efficientcloud, [#1288](https://github.com/rubygems/bundler/issues/1288)) + - Shortcuts (like `bundle i`) for all commands (@amatsuda) + - Correctly identify missing child dependency in error message + +### Bug fixes: + + - Allow Windows network share paths with forward slashes (@mtscout6, [#1253](https://github.com/rubygems/bundler/issues/1253)) + - Check for rubygems.org credentials so `rake release` doesn't hang ([#980](https://github.com/rubygems/bundler/issues/980)) + - Find cached prerelease gems on rubygems 1.3.x (@dburt, [#1202](https://github.com/rubygems/bundler/issues/1202)) + - Fix `bundle install --without` on kiji (@tmm1, [#1287](https://github.com/rubygems/bundler/issues/1287)) + - Get rid of warning in ruby 1.9.3 (@smartinez87, [#1231](https://github.com/rubygems/bundler/issues/1231)) + +### Documentation: + + - Documentation for `gem ..., :require => false` (@kmayer, [#1292](https://github.com/rubygems/bundler/issues/1292)) + - Gems provide "executables", they are rarely also binaries (@fxn, [#1242](https://github.com/rubygems/bundler/issues/1242)) + +## 1.0.15 (2011-06-09) + +### Features: + + - Improved Rubygems integration, removed many deprecation notices + +### Bug fixes: + + - Escape URL arguments to git correctly on Windows (1.0.14 regression) + +## 1.0.14 (2011-05-27) + +### Features: + + - Rubinius platform :rbx (@rkbodenner) + - Include gem rake tasks with "require 'bundler/gem_tasks" (@indirect) + - Include user name and email from git config in new gemspec (@ognevsky) + +### Bug fixes: + + - Set file permissions after checking out git repos (@tissak) + - Remove deprecated call to Gem::SourceIndex#all_gems (@mpj) + - Require the version file in new gemspecs (@rubiii) + - Allow relative paths from the Gemfile in gems with no gemspec (@mbirk) + - Install gems that contain 'bundler', e.g. guard-bundler (@hone) + - Display installed path correctly on Windows (@tadman) + - Escape quotes in git URIs (@mheffner) + - Improve Rake 0.9 support (@quix) + - Handle certain directories already existing (@raggi) + - Escape filenames containing regex characters (@indirect) + +## 1.0.13 (2011-05-04) + +### Features: + + - Compatibility with Rubygems master (soon to be v1.8) (@evanphx) + - Informative error when --path points to a broken symlink + - Support Rake 0.9 and greater (@e2) + - Output full errors for non-TTYs e.g. pow (@josh) + +### Bug fixes: + + - Allow spaces in gem path names for gem tasks (@rslifka) + - Have cap run bundle install from release_path (@martinjagusch) + - Quote git refspec so zsh doesn't expand it (@goneflyin) + +## 1.0.12 (2011-04-08) + +### Features: + + - Add --no-deployment option to `install` for disabling it on dev machines + - Better error message when git fails and cache is present (@parndt) + - Honor :bundle_cmd in cap `rake` command (@voidlock, @cgriego) + +### Bug fixes: + + - Compatibility with Rubygems 1.7 and Rails 2.3 and vendored gems (@evanphx) + - Fix changing gem order in lock (@gucki) + - Remove color escape sequences when displaying man pages (@bgreenlee) + - Fix creating GEM_HOME on both JRuby 1.5 and 1.6 (@nickseiger) + - Fix gems without a gemspec and directories in bin/ (@epall) + - Fix --no-prune option for `bundle install` (@cmeiklejohn) + +## 1.0.11 (2011-04-01) + +### Features: + + - Compatibility with Rubygems 1.6 and 1.7 + - Better error messages when a git command fails + +### Bug fixes: + + - Don't always update gemspec gems (@carllerche) + - Remove ivar warnings (@jackdempsey) + - Fix occasional git failures in zsh (@jonah-carbonfive) + - Consistent lock for gems with double deps like Cap (@akahn) + +## 1.0.10 (2011-02-01) + +### Bug fixes: + + - Fix a regression loading YAML gemspecs from :git and :path gems + - Requires, namespaces, etc. to work with changes in Rubygems 1.5 + +## 1.0.9 (2011-01-19) + +### Bug fixes: + + - Fix a bug where Bundler.require could remove gems from the load + path. In Rails apps with a default application.rb, this removed + all gems in groups other than :default and Rails.env + +## 1.0.8 (2011-01-18) + +### Features: + + - Allow overriding gemspec() deps with :git deps + - Add --local option to `bundle update` + - Ignore Gemfile.lock in newly generated gems + - Use `less` as help pager instead of `more` + - Run `bundle exec rake` instead of `rake` in Capistrano tasks + +### Bug fixes: + + - Fix --no-cache option for `bundle install` + - Allow Vlad deploys to work without Capistrano gem installed + - Fix group arguments to `bundle console` + - Allow groups to be loaded even if other groups were loaded + - Evaluate gemspec() gemspecs in their directory not the cwd + - Count on Rake to chdir to the right place in GemHelper + - Change Pathnames to Strings for MacRuby + - Check git process exit status correctly + - Fix some warnings in 1.9.3-trunk (thanks tenderlove) + +## 1.0.7 (2010-11-17) + +### Bug fixes: + + - Remove Bundler version from the lockfile because it broke + backwards compatibility with 1.0.0-1.0.5. Sorry. :( + +## 1.0.6 (2010-11-16) + +### Bug fixes: + + - Fix regression in `update` that caused long/wrong results + - Allow git gems on other platforms while installing ([#579](https://github.com/rubygems/bundler/issues/579)) + +### Features: + + - Speed up `install` command using various optimizations + - Significantly increase performance of resolver + - Use upcoming Rubygems performance improvements (@tmm1) + - Warn if the lockfile was generated by a newer version + - Set generated gems' homepage to "", so Rubygems will warn + +## 1.0.5 (2010-11-13) + +### Bug fixes: + + - Fix regression disabling all operations that employ sudo + +## 1.0.4 (2010-11-12) + +### Bug fixes: + + - Expand relative :paths from Bundler.root (eg ./foogem) + - Allow git gems in --without groups while --frozen + - Allow gem :ref to be a symbol as well as a string + - Fix exception when Gemfile needs a newer Bundler version + - Explanation when the current Bundler version conflicts + - Explicit error message if Gemfile needs newer Bundler + - Ignore an empty string BUNDLE_GEMFILE + - Skeleton gemspec now works with older versions of git + - Fix shell quoting and ref fetching in GemHelper + - Disable colored output in --deployment + - Preserve line endings in lockfile + +### Features: + + - Add support for 'mingw32' platform (aka RubyInstaller) + - Large speed increase when Gemfile.lock is already present + - Huge speed increase when many (100+) system gems are present + - Significant expansion of ISSUES, man pages, and docs site + - Remove Open3 from GemHelper (now it works on Windows™®©) + - Allow setting roles in built-in cap and vlad tasks + +## 1.0.3 (2010-10-15) + +### Bug fixes: + + - Use bitwise or in #hash to reduce the chance of overflow + - `bundle update` now works with :git + :tag updates + - Record relative :path options in the Gemfile.lock + - :groups option on gem method in Gemfile now works + - Add #platform method and :platform option to Gemfile DSL + - --without now accepts a quoted, space-separated list + - Installing after --deployment with no lock is now possible + - Binstubs can now be symlinked + - Print warning if cache for --local install is missing gems + - Improve output when installing to a path + - The tests all pass! Yay! + +## 1.0.2 (2010-10-02) + +### Bug fixes: + + - Actually include the man pages in the gem, so help works + +## 1.0.1 (2010-10-01) + +### Features: + + - Vlad deployment recipe, `require 'bundler/vlad'` + - Prettier bundle graphs + - Improved gem skeleton for `bundle gem` + - Prompt on file clashes when generating a gem + - Option to generate binary with gem skeleton + - Allow subclassing of GemHelper for custom tasks + - Chdir to gem directory during `bundle open` + +### Bug fixes: + + - Allow gemspec requirements with a list of versions + - Accept lockfiles with windows line endings + - Respect BUNDLE_WITHOUT env var + - Allow `gem "foo", :platform => :jruby` + - Specify loaded_from path in fake gemspec + - Flesh out gem_helper tasks, raise errors correctly + - Respect RBConfig::CONFIG['ruby_install_name'] in binstubs + +## 1.0.0 (2010-08-29) + +### Features: + + - You can now define `:bundle_cmd` in the capistrano task + +### Bug fixes: + + - Various bugfixes to the built-in rake helpers + - Fix a bug where shortrefs weren't unique enough and were + therefore colliding + - Fix a small bug involving checking whether a local git + clone is up to date + - Correctly handle explicit '=' dependencies with gems + pinned to a git source + - Fix an issue with Windows-generated lockfiles by reading + and writing the lockfile in binary mode + - Fix an issue with shelling out to git in Windows by + using double quotes around paths + - Detect new Rubygems sources in the Gemfile and update + the lockfile + +## 1.0.0.rc.6 (2010-08-23) + +### Features: + + - Much better documentation for most of the commands and Gemfile + format + +### Bug fixes: + + - Don't attempt to create directories if they already exist + - Fix the capistrano task so that it actually runs + - Update the Gemfile template to reference rubygems.org instead + of :gemcutter + - bundle exec should exit with a non zero exit code when the gem + binary does not exist or the file is not executable. + - Expand paths in Gemfile relative to the Gemfile and not the current + working directory. + +## 1.0.0.rc.5 (2010-08-10) + +### Features: + + - Make the Capistrano task more concise. + +### Bug fixes: + + - Fix a regression with determining whether or not to use sudo + - Allow using the --gemfile flag with the --deployment flag + +## 1.0.0.rc.4 (2010-08-09) + +### Features: + + - `bundle gem NAME` command to generate a new gem with Gemfile + - Bundle config file location can be specified by BUNDLE_APP_CONFIG + - Add --frozen to disable updating the Gemfile.lock at runtime + (default with --deployment) + - Basic Capistrano task now added as 'bundler/capistrano' + +### Bug fixes: + + - Multiple bundler process no longer share a tmp directory + - `bundle update GEM` always updates dependencies of GEM as well + - Deleting the cache directory no longer causes errors + - Moving the bundle after installation no longer causes git errors + - Bundle path is now correctly remembered on a read-only filesystem + - Gem binaries are installed to Gem.bindir, not #{Gem.dir}/bin + - Fetch gems from vendor/cache, even without --local + - Sort lockfile by platform as well as spec + +## 1.0.0.rc.3 (2010-08-03) + +### Features: + + - Deprecate --production flag for --deployment, since the former + was causing confusion with the :production group + - Add --gemfile option to `bundle check` + - Reduce memory usage of `bundle install` by 2-4x + - Improve message from `bundle check` under various conditions + - Better error when a changed Gemfile conflicts with Gemfile.lock + +### Bug fixes: + + - Create bin/ directory if it is missing, then install binstubs + - Error nicely on the edge case of a pinned gem with no spec + - Do not require gems for other platforms + - Update git sources along with the gems they contain + +## 1.0.0.rc.2 (2010-07-29) + + - `bundle install path` was causing confusion, so we now print + a clarifying warning. The preferred way to install to a path + (which will not print the warning) is + `bundle install --path path/to/install`. + - `bundle install --system` installs to the default system + location ($BUNDLE_PATH or $GEM_HOME) even if you previously + used `bundle install --path` + - completely remove `--disable-shared-gems`. If you install to + system, you will not be isolated, while if you install to + another path, you will be isolated from gems installed to + the system. This was mostly an internal option whose naming + and semantics were extremely confusing. + - Add a `--production` option to `bundle install`: + - by default, installs to `vendor/bundle`. This can be + overridden with the `--path` option + - uses `--local` if `vendor/cache` is found. This will + guarantee that Bundler does not attempt to connect to + Rubygems and will use the gems cached in `vendor/cache` + instead + - Raises an exception if a Gemfile.lock is not found + - Raises an exception if you modify your Gemfile in development + but do not check in an updated Gemfile.lock + - Fixes a bug where switching a source from Rubygems to git + would always say "the git source is not checked out" when + running `bundle install` + + NOTE: We received several reports of "the git source has not + been checked out. Please run bundle install". As far as we + can tell, these problems have two possible causes: + + 1. `bundle install ~/.bundle` in one user, but actually running + the application as another user. Never install gems to a + directory scoped to a user (`~` or `$HOME`) in deployment. + 2. A bug that happened when changing a gem to a git source. + + To mitigate several common causes of `(1)`, please use the + new `--production` flag. This flag is simply a roll-up of + the best practices we have been encouraging people to use + for deployment. + + If you want to share gems across deployments, and you use + Capistrano, symlink release_path/current/vendor/bundle to + release_path/shared/bundle. This will keep deployments + snappy while maintaining the benefits of clean, deploy-time + isolation. + +## 1.0.0.rc.1 (2010-07-26) + + - Fixed a bug with `bundle install` on multiple machines and git + +## 1.0.0.beta.10 (2010-07-25) + + - Last release before 1.0.0.rc.1 + - Added :mri as a valid platform (platforms :mri { gem "ruby-debug" }) + - Fix `bundle install` immediately after modifying the :submodule option + - Don't write to Gemfile.lock if nothing has changed, fixing situations + where bundle install was run with a different user than the app + itself + - Fix a bug where other platforms were being wiped on `bundle update` + - Don't ask for root password on `bundle install` if not needed + - Avoid setting `$GEM_HOME` where not needed + - First solid pass of `bundle config` + - Add build options + - `bundle config build.mysql --with-mysql-config=/path/to/config` + +## 1.0.0.beta.9 (2010-07-21) + + - Fix install failure when switching from a path to git source + - Fix `bundle exec bundle *` in a bundle with --disable-shared-gems + - Fix `bundle *` from inside a bundle with --disable-shared-gem + - Shim Gem.refresh. This is used by Unicorn + - Fix install failure when a path's dependencies changed + - Fix a bug in yanked Beta 7 involving Ruby 1.9 + - Running `bundle install` twice in a row with a git source always crashed + - Create executables with bundle install --binstubs + - You can customize the location (default is app/bin) with --binstubs other/location + - Fix a bug where the Gemfile.lock would be deleted even if the update was exited + - Fix a bug where cached gems for other platforms were sometimes deleted + - Clean up output when nothing was deleted from cache (it previously said + "Removing outdated gems ...") + - Improve performance of bundle install if the git gem was already checked out, + and the revision being used already exists locally + - Fix bundle show bundler in some cases + - Fix bugs with bundle update + - Don't ever run git commands at runtime (fixes a number of common passenger issues) + - Fixes an obscure bug where switching the source of a gem could fail to correctly + change the source of its dependencies + - Support multiple version dependencies in the Gemfile + (`gem "rails", ">= 3.0.0.beta1", "<= 3.0.0"`) + - Raise an exception for ambiguous uses of multiple declarations of the same gem + (for instance, with different versions or sources). + - Fix cases where the same dependency appeared several times in the Gemfile.lock + - Fix a bug where require errors were being swallowed during Bundler.require + +## 1.0.0.beta.1 (2010-06-08) + + - No `bundle lock` command. Locking happens automatically on install or update + - No .bundle/environment.rb. Require 'bundler/setup' instead. + - $BUNDLE_HOME defaults to $GEM_HOME instead of ~/.bundle + - Remove lockfiles generated by 0.9 + +## 0.9.26 (2010-06-08) + +### Features: + + - error nicely on incompatible 0.10 lockfiles + +## 0.9.25 (2010-05-03) + +### Bug fixes: + + - explicitly coerce Pathname objects to Strings for Ruby 1.9 + - fix some newline weirdness in output from install command + +## 0.9.24 (2010-04-22) + +### Features: + + - fetch submodules for git sources + - limit the bundled version of bundler to the same as the one installing + - force relative paths in git gemspecs to avoid raising Gem::NameTooLong + - serialize GemCache sources correctly, so locking works + - raise Bundler::GemNotFound instead of calling exit! inside library code + - Rubygems 1.3.5 compatibility for the adventurous, not supported by me :) + +### Bug fixes: + + - don't try to regenerate environment.rb if it is read-only + - prune outdated gems with the platform "ruby" + - prune cache without errors when there are directories or non-gem files + - don't re-write environment.rb if running after it has been loaded + - do not monkeypatch Specification#load_paths twice when inside a bundle + +## 0.9.23 (2010-04-20) + +### Bug fixes: + + - cache command no longer prunes gems created by an older rubygems version + - cache command no longer prunes gems that are for other platforms + +## 0.9.22 (2010-04-20) + +### Features: + + - cache command now prunes stale .gem files from vendor/cache + - init --gemspec command now generates development dependencies + - handle Polyglot's changes to Kernel#require with Bundler::ENV_LOADED ([#287](https://github.com/rubygems/bundler/issues/287)) + - remove .gem files generated after installing a gem from a :path ([#286](https://github.com/rubygems/bundler/issues/286)) + - improve install/lock messaging ([#284](https://github.com/rubygems/bundler/issues/284)) + +### Bug fixes: + + - ignore cached gems that are for another platform ([#288](https://github.com/rubygems/bundler/issues/288)) + - install Windows gems that have no architecture set, like rcov ([#277](https://github.com/rubygems/bundler/issues/277)) + - exec command while locked now includes the bundler lib in $LOAD_PATH ([#293](https://github.com/rubygems/bundler/issues/293)) + - fix the `rake install` task + - add GemspecError so it can be raised without (further) error ([#292](https://github.com/rubygems/bundler/issues/292)) + - create a parent directory before cloning for git 1.5 compatibility ([#285](https://github.com/rubygems/bundler/issues/285)) + +## 0.9.21 (2010-04-16) + +### Bug fixes: + + - don't raise 'omg wtf' when lockfile is outdated + +## 0.9.20 (2010-04-15) + +### Features: + + - load YAML format gemspecs + - no backtraces when calling Bundler.setup if gems are missing + - no backtraces when trying to exec a file without the executable bit + +### Bug fixes: + + - fix infinite recursion in Bundler.setup after loading a bundled Bundler gem + - request install instead of lock when env.rb is out of sync with Gemfile.lock + +## 0.9.19 (2010-04-12) + +### Features: + + - suggest `bundle install --relock` when the Gemfile has changed ([#272](https://github.com/rubygems/bundler/issues/272)) + - source support for Rubygems servers without prerelease gem indexes ([#262](https://github.com/rubygems/bundler/issues/262)) + +### Bug fixes: + + - don't set up all groups every time Bundler.setup is called while locked ([#263](https://github.com/rubygems/bundler/issues/263)) + - fix #full_gem_path for git gems while locked ([#268](https://github.com/rubygems/bundler/issues/268)) + - eval gemspecs at the top level, not inside the Bundler class ([#269](https://github.com/rubygems/bundler/issues/269)) + + +## 0.9.18 (2010-04-08) + +### Features: + + - console command that runs irb with bundle (and optional group) already loaded + +### Bug fixes: + + - Bundler.setup now fully disables system gems, even when unlocked ([#266](https://github.com/rubygems/bundler/issues/266), [#246](https://github.com/bundler/bundler/issues/246)) + - fixes Yard, which found plugins in Gem.source_index that it could not load + - makes behaviour of `Bundler.require` consistent between locked and unlocked loads + +## 0.9.17 (2010-04-07) + +### Features: + + - Bundler.require now calls Bundler.setup automatically + - Gem::Specification#add_bundler_dependencies added for gemspecs + +### Bug fixes: + + - Gem paths are not longer duplicated while loading bundler + - exec no longer duplicates RUBYOPT if it is already set correctly + +## 0.9.16 (2010-04-03) + +### Features: + + - exit gracefully on INT signal + - resolver output now indicates whether remote sources were checked + - print error instead of backtrace when exec cannot find a binary ([#241](https://github.com/rubygems/bundler/issues/241)) + +### Bug fixes: + + - show, check, and open commands work again while locked (oops) + - show command for git gems + - outputs branch names other than master + - gets the correct sha from the checkout + - doesn't print sha twice if :ref is set + - report errors from bundler/setup.rb without backtraces ([#243](https://github.com/rubygems/bundler/issues/243)) + - fix Gem::Spec#git_version to not error on unloaded specs + - improve deprecation, Gemfile, and command error messages ([#242](https://github.com/rubygems/bundler/issues/242)) + +## 0.9.15 (2010-04-01) + +### Features: + + - use the env_file if possible instead of doing a runtime resolve + - huge speedup when calling Bundler.setup while locked + - ensures bundle exec is fast while locked + - regenerates env_file if it was generated by an older version + - update cached/packed gems when you update gems via bundle install + +### Bug fixes: + + - prep for Rubygems 1.3.7 changes + - install command now pulls git branches correctly ([#211](https://github.com/rubygems/bundler/issues/211)) + - raise errors on invalid options in the Gemfile + +## 0.9.14 (2010-03-30) + +### Features: + + - install command output vastly improved + - installation message now accurate, with 'using' and 'installing' + - bundler gems no longer listed as 'system gems' + - show command output now includes sha and branch name for git gems + - init command now takes --gemspec option for bootstrapping gem Gemfiles + - Bundler.with_clean_env for shelling out to ruby scripts + - show command now aliased as 'list' + - VISUAL env var respected for GUI editors + +### Bug fixes: + + - exec command now finds binaries from gems with no gemspec + - note source of Gemfile resolver errors + - don't blow up if git urls are changed + +## 0.9.13 (2010-03-23) + +### Bug fixes: + + - exec command now finds binaries from gems installed via :path + - gem dependencies are pulled in even if their type is nil + - paths with spaces have double-quotes to work on Windows + - set GEM_PATH in environment.rb so generators work with Rails 2 + +## 0.9.12 (2010-03-17) + + - refactoring, internal cleanup, more solid specs + +### Features: + + - check command takes a --without option + - check command exits 1 if the check fails + +### Bug fixes: + + - perform a topological sort on resolved gems ([#191](https://github.com/rubygems/bundler/issues/191)) + - gems from git work even when paths or repos have spaces ([#196](https://github.com/rubygems/bundler/issues/196)) + - Specification#loaded_from returns a String, like Gem::Specification ([#197](https://github.com/rubygems/bundler/issues/197)) + - specs eval from inside the gem directory, even when locked + - virtual gemspecs are now saved in environment.rb for use when loading + - unify the Installer's local index and the runtime index ([#204](https://github.com/rubygems/bundler/issues/204)) + +## 0.9.11 (2010-03-09) + + - added roadmap with future development plans + +### Features: + + - install command can take the path to the gemfile with --gemfile ([#125](https://github.com/rubygems/bundler/issues/125)) + - unknown command line options are now rejected ([#163](https://github.com/rubygems/bundler/issues/163)) + - exec command hugely sped up while locked ([#177](https://github.com/rubygems/bundler/issues/177)) + - show command prints the install path if you pass it a gem name ([#148](https://github.com/rubygems/bundler/issues/148)) + - open command edits an installed gem with $EDITOR ([#148](https://github.com/rubygems/bundler/issues/148)) + - Gemfile allows assigning an array of groups to a gem ([#114](https://github.com/rubygems/bundler/issues/114)) + - Gemfile allows :tag option on :git sources + - improve backtraces when a gemspec is invalid + - improve performance by installing gems from the cache if present + +### Bug fixes: + + - normalize parameters to Bundler.require ([#153](https://github.com/rubygems/bundler/issues/153)) + - check now checks installed gems rather than cached gems ([#162](https://github.com/rubygems/bundler/issues/162)) + - don't update the gem index when installing after locking ([#169](https://github.com/rubygems/bundler/issues/169)) + - bundle parenthesises arguments for 1.8.6 ([#179](https://github.com/rubygems/bundler/issues/179)) + - gems can now be assigned to multiple groups without problems ([#135](https://github.com/rubygems/bundler/issues/135)) + - fix the warning when building extensions for a gem from git with Rubygems 1.3.6 + - fix a Dependency.to_yaml error due to accidentally including sources and groups + - don't reinstall packed gems + - fix gems with git sources that are private repositories + +## 0.9.10 (2010-03-01) + + - depends on Rubygems 1.3.6 + +### Bug fixes: + + - support locking after install --without + - don't reinstall gems from the cache if they're already in the bundle + - fixes for Ruby 1.8.7 and 1.9 + +## 0.9.9 (2010-02-25) + +### Bug fixes: + + - don't die if GEM_HOME is an empty string + - fixes for Ruby 1.8.6 and 1.9 + +## 0.9.8 (2010-02-23) + +### Features: + + - pack command which both caches and locks + - descriptive error if a cached gem is missing + - remember the --without option after installing + - expand paths given in the Gemfile via the :path option + - add block syntax to the git and group options in the Gemfile + - support gems with extensions that don't admit they depend on rake + - generate gems using gem build gemspec so git gems can have native extensions + - print a useful warning if building a gem fails + - allow manual configuration via BUNDLE_PATH + +### Bug fixes: + + - eval gemspecs in the gem directory so relative paths work + - make default spec for git sources valid + - don't reinstall gems that are already packed + +## 0.9.7 (2010-02-17) + +### Bug fixes: + + - don't say that a gem from an excluded group is "installing" + - improve crippling rubygems in locked scenarios + +## 0.9.6 (2010-02-16) + +### Features: + + - allow String group names + - a number of improvements in the documentation and error messages + +### Bug fixes: + + - set SourceIndex#spec_dirs to solve a problem involving Rails 2.3 in unlocked mode + - ensure Rubygems is fully loaded in Ruby 1.9 before patching it + - fix `bundle install` for a locked app without a .bundle directory + - require gems in the order that the resolver determines + - make the tests platform agnostic so we can confirm that they're green on JRuby + - fixes for Ruby 1.9 + +## 0.9.5 (2010-02-12) + +### Features: + + - added support for :path => "relative/path" + - added support for older versions of git + - added `bundle install --disable-shared-gems` + - Bundler.require fails silently if a library does not have a file on the load path with its name + - Basic support for multiple rubies by namespacing the default bundle path using the version and engine + +### Bug fixes: + + - if the bundle is locked and .bundle/environment.rb is not present when Bundler.setup is called, generate it + - same if it's not present with `bundle check` + - same if it's not present with `bundle install` diff --git a/bin/gems/bundler-4.0.21/LICENSE.md b/bin/gems/bundler-4.0.21/LICENSE.md new file mode 100644 index 00000000..52b5c213 --- /dev/null +++ b/bin/gems/bundler-4.0.21/LICENSE.md @@ -0,0 +1,22 @@ +The MIT License + +Portions copyright (c) 2010-2019 André Arko +Portions copyright (c) 2009 Engine Yard + +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/bin/gems/bundler-4.0.21/README.md b/bin/gems/bundler-4.0.21/README.md new file mode 100644 index 00000000..2d634b59 --- /dev/null +++ b/bin/gems/bundler-4.0.21/README.md @@ -0,0 +1,58 @@ +[![Version ](https://img.shields.io/gem/v/bundler.svg?style=flat)](https://rubygems.org/gems/bundler) + +# Bundler: a gem to bundle gems + +Bundler makes sure Ruby applications run the same code on every machine. + +It does this by managing the gems that the application depends on. Given a list of gems, it can automatically download and install those gems, as well as any other gems needed by the gems that are listed. Before installing gems, it checks the versions of every gem to make sure that they are compatible, and can all be loaded at the same time. After the gems have been installed, Bundler can help you update some or all of them when new versions become available. Finally, it records the exact versions that have been installed, so that others can install the exact same gems. + +## Installation and usage + +To install (or update to the latest version): + +``` +gem install bundler +``` + +To install a prerelease version (if one is available), run `gem install bundler --pre`. To uninstall Bundler, run `gem uninstall bundler`. + +Bundler is most commonly used to manage your application's dependencies. For example, these commands will allow you to use Bundler to manage the `rspec` gem for your application: + +``` +bundle init +bundle add rspec +bundle install +bundle exec rspec +``` + +See [bundler.io](https://bundler.io) for the full documentation. + +## Troubleshooting + +For help with common problems, see [TROUBLESHOOTING](../doc/bundler/TROUBLESHOOTING.md). + +Still stuck? Try [filing an issue](https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md). + +## Other questions + +To see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANGELOG.md). + +To get in touch with the Bundler core team and other Bundler users, please join [the Bundler slack](https://join.slack.com/t/bundler/shared_invite/zt-1rrsuuv3m-OmXKWQf8K6iSla4~F1DBjQ). + +## Contributing + +If you'd like to contribute to Bundler, that's awesome, and we <3 you. We've put together [the Bundler contributor guide](https://github.com/ruby/rubygems/blob/master/doc/bundler/contributing/README.md) with all of the information you need to get started. + +If you'd like to request a substantial change to Bundler or its documentation, refer to the [Bundler RFC process](https://github.com/rubygems/rfcs) for more information. + +## Supporting + +RubyGems is managed by [Ruby Central](https://rubycentral.org), a non-profit organization that supports the Ruby community through projects like this one, as well as [RubyConf](https://rubyconf.org), [RailsConf](https://railsconf.org), and [RubyGems.org](https://rubygems.org). You can support Ruby Central by attending or [sponsoring](sponsors@rubycentral.org) a conference, or by [joining as a supporting member](https://rubycentral.org/#/portal/signup). + +## Code of Conduct + +Everyone interacting in the Bundler project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [Bundler code of conduct](https://github.com/ruby/rubygems/blob/master/CODE_OF_CONDUCT.md). + +## License + +Bundler is available under an [MIT License](https://github.com/ruby/rubygems/blob/master/bundler/LICENSE.md). diff --git a/bin/gems/bundler-4.0.21/bundler.gemspec b/bin/gems/bundler-4.0.21/bundler.gemspec new file mode 100644 index 00000000..3c4a5e4e --- /dev/null +++ b/bin/gems/bundler-4.0.21/bundler.gemspec @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +begin + require_relative "lib/bundler/version" +rescue LoadError + # for Ruby core repository + require_relative "version" +end + +Gem::Specification.new do |s| + s.name = "bundler" + s.version = Bundler::VERSION + s.license = "MIT" + s.authors = [ + "André Arko", "Samuel Giddins", "Colby Swandale", "Hiroshi Shibata", + "David Rodríguez", "Grey Baker", "Stephanie Morillo", "Chris Morris", "James Wen", "Tim Moore", + "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", + "Yehuda Katz" + ] + s.email = ["team@bundler.io"] + s.homepage = "https://bundler.io" + s.summary = "The best way to manage your application's dependencies" + s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably" + + s.metadata = { + "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler", + "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/CHANGELOG.md", + "homepage_uri" => "https://bundler.io/", + "source_code_uri" => "https://github.com/ruby/rubygems", + } + + s.required_ruby_version = ">= 3.2.0" + + # It should match the RubyGems version shipped with `required_ruby_version` above + s.required_rubygems_version = ">= 3.4.1" + + s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + + # include the gemspec itself because warbler breaks w/o it + s.files += %w[bundler.gemspec] + + s.files += %w[CHANGELOG.md LICENSE.md README.md] + s.bindir = "exe" + s.executables = %w[bundle bundler] + s.require_paths = ["lib"] +end diff --git a/bin/gems/bundler-4.0.21/exe/bundle b/bin/gems/bundler-4.0.21/exe/bundle new file mode 100755 index 00000000..92387bc2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/exe/bundle @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Exit cleanly from an early interrupt +Signal.trap("INT") do + Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) + exit 1 +end + +base_path = File.expand_path("../lib", __dir__) + +if File.exist?(base_path) + $LOAD_PATH.unshift(base_path) +end + +require "bundler" + +require "bundler/friendly_errors" + +Bundler.with_friendly_errors do + require "bundler/cli" + + # Allow any command to use --help flag to show help for that command + help_flags = %w[--help -h] + help_flag_used = ARGV.any? {|a| help_flags.include? a } + args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV + + Bundler::CLI.start(args, debug: true) +end diff --git a/bin/gems/bundler-4.0.21/exe/bundler b/bin/gems/bundler-4.0.21/exe/bundler new file mode 100755 index 00000000..a6826a8c --- /dev/null +++ b/bin/gems/bundler-4.0.21/exe/bundler @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +load File.expand_path("bundle", __dir__) diff --git a/bin/gems/bundler-4.0.21/lib/bundler.rb b/bin/gems/bundler-4.0.21/lib/bundler.rb new file mode 100644 index 00000000..f8f793f4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler.rb @@ -0,0 +1,701 @@ +# frozen_string_literal: true + +require_relative "bundler/rubygems_ext" +require_relative "bundler/vendored_fileutils" +autoload :Pathname, "pathname" unless defined?(Pathname) +require "rbconfig" + +require_relative "bundler/errors" +require_relative "bundler/environment_preserver" +require_relative "bundler/plugin" +require_relative "bundler/rubygems_integration" +require_relative "bundler/version" +require_relative "bundler/current_ruby" +require_relative "bundler/build_metadata" + +# Bundler provides a consistent environment for Ruby projects by +# tracking and installing the exact gems and versions that are needed. +# +# Bundler is a part of Ruby's standard library. +# +# Bundler is used by creating _gemfiles_ listing all the project dependencies +# and (optionally) their versions and then using +# +# require 'bundler/setup' +# +# or Bundler.setup to setup environment where only specified gems and their +# specified versions could be used. +# +# See {Bundler documentation}[https://guides.rubygems.org/command-reference/bundle/] for extensive documentation +# on gemfiles creation and Bundler usage. +# +# As a standard library inside project, Bundler could be used for introspection +# of loaded and required modules. +# +module Bundler + environment_preserver = EnvironmentPreserver.from_env + ORIGINAL_ENV = environment_preserver.restore + environment_preserver.replace_with_backup + SUDO_MUTEX = Thread::Mutex.new + + autoload :Checksum, File.expand_path("bundler/checksum", __dir__) + autoload :CLI, File.expand_path("bundler/cli", __dir__) + autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__) + autoload :CompactIndexClient, File.expand_path("bundler/compact_index_client", __dir__) + autoload :Definition, File.expand_path("bundler/definition", __dir__) + autoload :Dependency, File.expand_path("bundler/dependency", __dir__) + autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__) + autoload :Digest, File.expand_path("bundler/digest", __dir__) + autoload :Dsl, File.expand_path("bundler/dsl", __dir__) + autoload :EndpointSpecification, File.expand_path("bundler/endpoint_specification", __dir__) + autoload :Env, File.expand_path("bundler/env", __dir__) + autoload :Fetcher, File.expand_path("bundler/fetcher", __dir__) + autoload :FeatureFlag, File.expand_path("bundler/feature_flag", __dir__) + autoload :FREEBSD, File.expand_path("bundler/constants", __dir__) + autoload :GemHelper, File.expand_path("bundler/gem_helper", __dir__) + autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__) + autoload :Index, File.expand_path("bundler/index", __dir__) + autoload :Injector, File.expand_path("bundler/injector", __dir__) + autoload :Installer, File.expand_path("bundler/installer", __dir__) + autoload :LazySpecification, File.expand_path("bundler/lazy_specification", __dir__) + autoload :LockfileParser, File.expand_path("bundler/lockfile_parser", __dir__) + autoload :MatchRemoteMetadata, File.expand_path("bundler/match_remote_metadata", __dir__) + autoload :Materialization, File.expand_path("bundler/materialization", __dir__) + autoload :NULL, File.expand_path("bundler/constants", __dir__) + autoload :ProcessLock, File.expand_path("bundler/process_lock", __dir__) + autoload :RemoteSpecification, File.expand_path("bundler/remote_specification", __dir__) + autoload :Resolver, File.expand_path("bundler/resolver", __dir__) + autoload :Retry, File.expand_path("bundler/retry", __dir__) + autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__) + autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__) + autoload :Runtime, File.expand_path("bundler/runtime", __dir__) + autoload :SelfManager, File.expand_path("bundler/self_manager", __dir__) + autoload :Settings, File.expand_path("bundler/settings", __dir__) + autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) + autoload :Source, File.expand_path("bundler/source", __dir__) + autoload :SourceList, File.expand_path("bundler/source_list", __dir__) + autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) + autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) + autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) + autoload :UI, File.expand_path("bundler/ui", __dir__) + autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__) + autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__) + autoload :WINDOWS, File.expand_path("bundler/constants", __dir__) + autoload :SafeMarshal, File.expand_path("bundler/safe_marshal", __dir__) + + class << self + def configure + @configure ||= configure_gem_home_and_path + end + + def ui + (defined?(@ui) && @ui) || (self.ui = UI::Shell.new) + end + + def ui=(ui) + Bundler.rubygems.ui = UI::RGProxy.new(ui) + @ui = ui + end + + # Returns absolute path of where gems are installed on the filesystem. + def bundle_path + @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) + end + + def create_bundle_path + mkdir_p(bundle_path) unless bundle_path.exist? + + @bundle_path = bundle_path.realpath + rescue Errno::EEXIST + raise PathError, "Could not install to path `#{bundle_path}` " \ + "because a file already exists at that path. Either remove or rename the file so the directory can be created." + end + + def configured_bundle_path + @configured_bundle_path ||= Bundler.settings.path.tap(&:validate!) + end + + # Returns absolute location of where binstubs are installed to. + def bin_path + @bin_path ||= begin + path = Bundler.settings[:bin] || "bin" + path = Pathname.new(path).expand_path(root).expand_path + mkdir_p(path) + path + end + end + + # Turns on the Bundler runtime. After +Bundler.setup+ call, all +load+ or + # +require+ of the gems would be allowed only if they are part of + # the Gemfile or Ruby's standard library. If the versions specified + # in Gemfile, only those versions would be loaded. + # + # Assuming Gemfile + # + # gem 'first_gem', '= 1.0' + # group :test do + # gem 'second_gem', '= 1.0' + # end + # + # The code using Bundler.setup works as follows: + # + # require 'third_gem' # allowed, required from global gems + # require 'first_gem' # allowed, loads the last installed version + # Bundler.setup + # require 'fourth_gem' # fails with LoadError + # require 'second_gem' # loads exactly version 1.0 + # + # +Bundler.setup+ can be called only once, all subsequent calls are no-op. + # + # If _groups_ list is provided, only gems from specified groups would + # be allowed (gems specified outside groups belong to special +:default+ group). + # + # To require all gems from Gemfile (or only some groups), see Bundler.require. + # + def setup(*groups) + # Return if all groups are already loaded + return @setup if defined?(@setup) && @setup + + configure_custom_gemfile + definition.validate_runtime! + + SharedHelpers.print_major_deprecations! + + if groups.empty? + # Load all groups, but only once + @setup = load.setup + else + load.setup(*groups) + end + end + + def auto_switch + self_manager.restart_with_locked_bundler_if_needed + end + + # Automatically install dependencies if settings[:auto_install] exists. + # This is set through config cmd `bundle config set --global auto_install 1`. + # + # Note that this method `nil`s out the global Definition object, so it + # should be called first, before you instantiate anything like an + # `Installer` that'll keep a reference to the old one instead. + def auto_install + return unless Bundler.settings[:auto_install] + + begin + definition.specs + rescue GemNotFound, GitError + ui.info "Automatically installing missing gems." + reset! + CLI::Install.new({}).run + reset! + end + end + + # Setups Bundler environment (see Bundler.setup) if it is not already set, + # and loads all gems from groups specified. Unlike ::setup, can be called + # multiple times with different groups (if they were allowed by setup). + # + # Assuming Gemfile + # + # gem 'first_gem', '= 1.0' + # group :test do + # gem 'second_gem', '= 1.0' + # end + # + # The code will work as follows: + # + # Bundler.setup # allow all groups + # Bundler.require(:default) # requires only first_gem + # # ...later + # Bundler.require(:test) # requires second_gem + # + def require(*groups) + setup(*groups).require(*groups) + end + + def load + @load ||= Runtime.new(root, definition) + end + + def environment + SharedHelpers.feature_removed! "Bundler.environment has been removed in favor of Bundler.load" + end + + # Returns an instance of Bundler::Definition for given Gemfile and lockfile + # + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @param lockfile [Pathname] Path to Gemfile.lock + # @return [Bundler::Definition] + def definition(unlock = nil, lockfile = default_lockfile) + @definition = nil if unlock + @definition ||= begin + configure + Definition.build(default_gemfile, lockfile, unlock) + end + end + + def frozen_bundle? + frozen = Bundler.settings[:frozen] + return frozen unless frozen.nil? + + Bundler.settings[:deployment] + end + + def locked_gems + @locked_gems ||= + if defined?(@definition) && @definition + definition.locked_gems + elsif Bundler.default_lockfile.file? + lock = Bundler.read_file(Bundler.default_lockfile) + LockfileParser.new(lock) + end + end + + def ruby_scope + "#{Bundler.rubygems.ruby_engine}/#{RbConfig::CONFIG["ruby_version"]}" + end + + def user_home + @user_home ||= begin + home = Bundler.rubygems.user_home + bundle_home = home ? File.join(home, ".bundle") : nil + + warning = if home.nil? + "Your home directory is not set." + elsif !File.directory?(home) + "`#{home}` is not a directory." + elsif !File.writable?(home) && (!File.directory?(bundle_home) || !File.writable?(bundle_home)) + "`#{home}` is not writable." + end + + if warning + Bundler.ui.warn "#{warning}\n" + user_home = tmp_home_path + Bundler.ui.warn "Bundler will use `#{user_home}' as your home directory temporarily.\n" + user_home + else + Pathname.new(home) + end + end + end + + def user_bundle_path(dir = "home") + env_var, fallback = case dir + when "home" + ["BUNDLE_USER_HOME", proc { Pathname.new(user_home).join(".bundle") }] + when "cache" + ["BUNDLE_USER_CACHE", proc { user_bundle_path.join("cache") }] + when "config" + ["BUNDLE_USER_CONFIG", proc { user_bundle_path.join("config") }] + when "plugin" + ["BUNDLE_USER_PLUGIN", proc { user_bundle_path.join("plugin") }] + else + raise BundlerError, "Unknown user path requested: #{dir}" + end + # `fallback` will already be a Pathname, but Pathname.new() is + # idempotent so it's OK + Pathname.new(ENV.fetch(env_var, &fallback)) + end + + def user_cache + user_bundle_path("cache") + end + + def home + bundle_path.join("bundler") + end + + def install_path + home.join("gems") + end + + def specs_path + bundle_path.join("specifications") + end + + def root + @root ||= begin + SharedHelpers.root + rescue GemfileNotFound + bundle_dir = default_bundle_dir + raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir + Pathname.new(File.expand_path("..", bundle_dir)) + end + end + + def app_config_path + if app_config = ENV["BUNDLE_APP_CONFIG"] + app_config_pathname = Pathname.new(app_config) + + if app_config_pathname.absolute? + app_config_pathname + else + app_config_pathname.expand_path(root) + end + else + root.join(".bundle") + end + end + + def app_cache(custom_path = nil) + path = custom_path || root + Pathname.new(path).join(Bundler.settings.app_cache_path) + end + + def tmp(name = Process.pid.to_s) + Kernel.send(:require, "tmpdir") + Pathname.new(Dir.mktmpdir(["bundler", name])) + end + + def rm_rf(path) + FileUtils.remove_entry_secure(path) if path && File.exist?(path) + end + + def settings + @settings ||= Settings.new(app_config_path) + rescue GemfileNotFound + @settings = Settings.new + end + + # @return [Hash] Environment present before Bundler was activated + def original_env + ORIGINAL_ENV.clone + end + + def clean_env + removed_message = + "`Bundler.clean_env` has been removed in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + Bundler::SharedHelpers.feature_removed!(removed_message) + end + + # @return [Hash] Environment with all bundler-related variables removed + def unbundled_env + unbundle_env(original_env) + end + + # Remove all bundler-related variables from ENV + def unbundle_env! + ENV.replace(unbundle_env(ENV)) + end + + # Run block with environment present before Bundler was activated + def with_original_env + with_env(original_env) { yield } + end + + def with_clean_env + removed_message = + "`Bundler.with_clean_env` has been removed in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + Bundler::SharedHelpers.feature_removed!(removed_message) + end + + # Run block with all bundler-related variables removed + def with_unbundled_env + with_env(unbundled_env) { yield } + end + + # Run subcommand with the environment present before Bundler was activated + def original_system(*args) + with_original_env { Kernel.system(*args) } + end + + def clean_system(*args) + removed_message = + "`Bundler.clean_system` has been removed in favor of `Bundler.unbundled_system`. " \ + "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`" + Bundler::SharedHelpers.feature_removed!(removed_message) + end + + # Run subcommand in an environment with all bundler related variables removed + def unbundled_system(*args) + with_unbundled_env { Kernel.system(*args) } + end + + # Run a `Kernel.exec` to a subcommand with the environment present before Bundler was activated + def original_exec(*args) + with_original_env { Kernel.exec(*args) } + end + + def clean_exec(*args) + removed_message = + "`Bundler.clean_exec` has been removed in favor of `Bundler.unbundled_exec`. " \ + "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`" + Bundler::SharedHelpers.feature_removed!(removed_message) + end + + # Run a `Kernel.exec` to a subcommand in an environment with all bundler related variables removed + def unbundled_exec(*args) + with_env(unbundled_env) { Kernel.exec(*args) } + end + + def local_platform + return Gem::Platform::RUBY if Bundler.settings[:force_ruby_platform] + Gem::Platform.local + end + + def generic_local_platform + Gem::Platform.generic(local_platform) + end + + def default_gemfile + SharedHelpers.default_gemfile + end + + def default_lockfile + SharedHelpers.default_lockfile + end + + def default_bundle_dir + SharedHelpers.default_bundle_dir + end + + def system_bindir + # Gem.bindir doesn't always return the location that RubyGems will install + # system binaries. If you put '-n foo' in your .gemrc, RubyGems will + # install binstubs there instead. Unfortunately, RubyGems doesn't expose + # that directory at all, so rather than parse .gemrc ourselves, we allow + # the directory to be set as well, via `bundle config set --local bindir foo`. + Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir + end + + def preferred_gemfile_name + Bundler.settings[:init_gems_rb] ? "gems.rb" : "Gemfile" + end + + def use_system_gems? + configured_bundle_path.use_system_gems? + end + + def mkdir_p(path) + SharedHelpers.filesystem_access(path, :create) do |p| + FileUtils.mkdir_p(p) + end + end + + def which(executable) + executable_path = find_executable(executable) + return executable_path if executable_path + + if (paths = ENV["PATH"]) + quote = '"' + paths.split(File::PATH_SEPARATOR).find do |path| + path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) + executable_path = find_executable(File.expand_path(executable, path)) + return executable_path if executable_path + end + end + end + + def find_executable(path) + extensions = RbConfig::CONFIG["EXECUTABLE_EXTS"]&.split + extensions = [RbConfig::CONFIG["EXEEXT"]] unless extensions&.any? + candidates = extensions.map {|ext| "#{path}#{ext}" } + + candidates.find {|candidate| File.file?(candidate) && File.executable?(candidate) } + end + + def read_file(file) + SharedHelpers.filesystem_access(file, :read) do + File.open(file, "r:UTF-8", &:read) + end + end + + def safe_load_marshal(data) + if Gem.respond_to?(:load_safe_marshal) + Gem.load_safe_marshal + begin + Gem::SafeMarshal.safe_load(data) + rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e + raise MarshalError, "#{e.class}: #{e.message}" + end + else + load_marshal(data, marshal_proc: SafeMarshal.proc) + end + end + + def load_gemspec(file, validate = false) + @gemspec_cache ||= {} + key = File.expand_path(file) + @gemspec_cache[key] ||= load_gemspec_uncached(file, validate) + # Protect against caching side-effected gemspecs by returning a + # new instance each time. + @gemspec_cache[key]&.dup + end + + def load_gemspec_uncached(file, validate = false) + path = Pathname.new(file).expand_path + contents = read_file(path.to_s) + spec = eval_gemspec(path, contents) + return unless spec + spec.loaded_from = path.to_s + Bundler.rubygems.validate(spec) if validate + spec + end + + def clear_gemspec_cache + @gemspec_cache = {} + end + + def git_present? + return @git_present if defined?(@git_present) + @git_present = Bundler.which("git") + end + + def feature_flag + @feature_flag ||= FeatureFlag.new(Bundler.settings[:simulate_version] || VERSION) + end + + def reset! + reset_paths! + Plugin.reset! + reset_rubygems! + end + + def reset_settings_and_root! + @settings = nil + @root = nil + end + + def reset_paths! + @bin_path = nil + @bundle_path = nil + @configure = nil + @configured_bundle_path = nil + @definition = nil + @load = nil + @locked_gems = nil + @root = nil + @settings = nil + @setup = nil + @user_home = nil + end + + def reset_rubygems! + return unless defined?(@rubygems) && @rubygems + rubygems.undo_replacements + rubygems.reset + @rubygems = nil + end + + def configure_gem_home_and_path(path = bundle_path) + configure_gem_path + configure_gem_home(path) + Bundler.rubygems.clear_paths + end + + def configure_custom_gemfile(custom_gemfile = nil) + custom_gemfile ||= Bundler.settings[:gemfile] + + if custom_gemfile && !custom_gemfile.empty? + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) + reset_settings_and_root! + end + end + + def self_manager + @self_manager ||= begin + require_relative "bundler/self_manager" + Bundler::SelfManager.new + end + end + + private + + def unbundle_env(env) + if env.key?("BUNDLER_ORIG_MANPATH") + env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"] + end + + env.delete_if {|k, _| k[0, 7] == "BUNDLE_" } + env.delete("BUNDLER_SETUP") + + if env.key?("RUBYOPT") + rubyopt = env["RUBYOPT"].split(" ") + rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}") + rubyopt.delete("-rbundler/setup") + env["RUBYOPT"] = rubyopt.join(" ") + end + + if env.key?("RUBYLIB") + rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR) + rubylib.delete(__dir__) + env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR) + end + + env + end + + def load_marshal(data, marshal_proc: nil) + Marshal.load(data, marshal_proc) + rescue TypeError => e + raise MarshalError, "#{e.class}: #{e.message}" + end + + def eval_yaml_gemspec(path, contents) + Kernel.require "psych" + + Gem::Specification.from_yaml(contents) + end + + def eval_gemspec(path, contents) + if contents.start_with?("---") # YAML header + eval_yaml_gemspec(path, contents) + else + # Eval the gemspec from its parent directory, because some gemspecs + # depend on "./" relative paths. The caller expands `path` first, since + # expanding it here would resolve against the gemspec directory once + # the chdir is active. + SharedHelpers.chdir(path.dirname.to_s) do + # TOPLEVEL_BINDING always belongs to the main box, so inside a + # Ruby::Box use a binding from the box Bundler is loaded in, where + # Gem::Specification carries Bundler's own monkey patches. + eval_binding = if defined?(Ruby::Box) && Ruby::Box.enabled? + Ruby::Box.current.eval("binding") + else + TOPLEVEL_BINDING.dup + end + eval(contents, eval_binding, path.to_s) + end + end + rescue ScriptError, StandardError => e + msg = "There was an error while loading `#{path.basename}`: #{e.message}" + + raise GemspecError, Dsl::DSLError.new(msg, path.to_s, e.backtrace, contents) + end + + def configure_gem_path + unless use_system_gems? + # this needs to be empty string to cause + # PathSupport.split_gem_path to only load up the + # Bundler --path setting as the GEM_PATH. + Bundler::SharedHelpers.set_env "GEM_PATH", "" + end + end + + def configure_gem_home(path) + Bundler::SharedHelpers.set_env "GEM_HOME", path.to_s + end + + def tmp_home_path + Kernel.send(:require, "tmpdir") + SharedHelpers.filesystem_access(Dir.tmpdir) do + path = Bundler.tmp + at_exit { Bundler.rm_rf(path) } + path + end + end + + # @param env [Hash] + def with_env(env) + backup = ENV.to_hash + ENV.replace(env) + yield + ensure + ENV.replace(backup) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/.document b/bin/gems/bundler-4.0.21/lib/bundler/.document new file mode 100644 index 00000000..238bbd87 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/.document @@ -0,0 +1 @@ +# not in RDoc diff --git a/bin/gems/bundler-4.0.21/lib/bundler/build_metadata.rb b/bin/gems/bundler-4.0.21/lib/bundler/build_metadata.rb new file mode 100644 index 00000000..cc826033 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/build_metadata.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Bundler + # Represents metadata from when the Bundler gem was built. + module BuildMetadata + # begin ivars + @built_at = "2026-09-16".freeze + @git_commit_sha = "a15d54ed692".freeze + # end ivars + + # A hash representation of the build metadata. + def self.to_h + { + "Timestamp" => timestamp, + "Git SHA" => git_commit_sha, + } + end + + # A timestamp representing the date the bundler gem was built, or the + # current time if never built + def self.timestamp + @timestamp ||= @built_at || Time.now.utc.strftime("%Y-%m-%d").freeze + end + + # A string representing the date the bundler gem was built. + def self.built_at + @built_at + end + + # The SHA for the git commit the bundler gem was built from. + def self.git_commit_sha + return @git_commit_sha if instance_variable_defined? :@git_commit_sha + + # If Bundler has been installed without its .git directory and without a + # commit instance variable then we can't determine its commits SHA. + git_dir = File.expand_path("../../../.git", __dir__) + if File.directory?(git_dir) + return @git_commit_sha = IO.popen(%w[git rev-parse --short HEAD], { chdir: git_dir }, &:read).strip.freeze + end + + @git_commit_sha ||= "unknown" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/capistrano.rb b/bin/gems/bundler-4.0.21/lib/bundler/capistrano.rb new file mode 100644 index 00000000..6d2437d8 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/capistrano.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.feature_removed! "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/checksum.rb b/bin/gems/bundler-4.0.21/lib/bundler/checksum.rb new file mode 100644 index 00000000..ce05818b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/checksum.rb @@ -0,0 +1,270 @@ +# frozen_string_literal: true + +module Bundler + class Checksum + ALGO_SEPARATOR = "=" + DEFAULT_ALGORITHM = "sha256" + private_constant :DEFAULT_ALGORITHM + DEFAULT_BLOCK_SIZE = 16_384 + private_constant :DEFAULT_BLOCK_SIZE + + class << self + def from_gem_package(gem_package, algo = DEFAULT_ALGORITHM) + return if Bundler.settings[:disable_checksum_validation] + return unless source = gem_package.instance_variable_get(:@gem) + return unless source.respond_to?(:with_read_io) + + source.with_read_io do |io| + from_gem(io, source.path) + ensure + io.rewind + end + end + + def from_gem(io, pathname, algo = DEFAULT_ALGORITHM) + digest = Bundler::SharedHelpers.digest(algo.upcase).new + buf = String.new(capacity: DEFAULT_BLOCK_SIZE) + digest << io.readpartial(DEFAULT_BLOCK_SIZE, buf) until io.eof? + Checksum.new(algo, digest.hexdigest!, Source.new(:gem, pathname)) + end + + def from_api(digest, source_uri, algo = DEFAULT_ALGORITHM) + return if Bundler.settings[:disable_checksum_validation] + + Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:api, source_uri)) + end + + def from_lock(lock_checksum, lockfile_location) + algo, digest = lock_checksum.strip.split(ALGO_SEPARATOR, 2) + Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:lock, lockfile_location)) + end + + def to_hexdigest(digest, algo = DEFAULT_ALGORITHM) + return digest unless algo == DEFAULT_ALGORITHM + return digest if digest.match?(/\A[0-9a-f]{64}\z/i) + + if digest.match?(%r{\A[-0-9a-z_+/]{43}={0,2}\z}i) + digest = digest.tr("-_", "+/") # fix urlsafe base64 + digest.unpack1("m0").unpack1("H*") + else + raise ArgumentError, "#{digest.inspect} is not a valid SHA256 hex or base64 digest" + end + end + end + + attr_reader :algo, :digest, :sources + + def initialize(algo, digest, source) + @algo = algo + @digest = digest + @sources = [source] + end + + def ==(other) + match?(other) && other.sources == sources + end + + alias_method :eql?, :== + + def same_source?(other) + sources.include?(other.sources.first) + end + + def match?(other) + other.is_a?(self.class) && other.digest == digest && other.algo == algo + end + + def hash + digest.hash + end + + def to_s + "#{to_lock} (from #{sources.first}#{", ..." if sources.size > 1})" + end + + def to_lock + "#{algo}#{ALGO_SEPARATOR}#{digest}" + end + + def merge!(other) + return nil unless match?(other) + + @sources.concat(other.sources).uniq! + self + end + + def formatted_sources + sources.join("\n and ").concat("\n") + end + + def removable? + sources.all?(&:removable?) + end + + def removal_instructions + msg = +"" + i = 1 + sources.each do |source| + msg << " #{i}. #{source.removal}\n" + i += 1 + end + msg << " #{i}. run `bundle install`\n" + end + + def inspect + abbr = "#{algo}#{ALGO_SEPARATOR}#{digest[0, 8]}" + from = "from #{sources.join(" and ")}" + "#<#{self.class}:#{object_id} #{abbr} #{from}>" + end + + class Source + attr_reader :type, :location + + def initialize(type, location) + @type = type + @location = location + end + + def removable? + [:lock, :gem].include?(type) + end + + def ==(other) + other.is_a?(self.class) && other.type == type && other.location == location + end + + # phrased so that the usual string format is grammatically correct + # rake (10.3.2) sha256=abc123 from #{to_s} + def to_s + case type + when :lock + "the lockfile CHECKSUMS at #{location}" + when :gem + "the gem at #{location}" + when :api + "the API at #{location}" + else + "#{location} (#{type})" + end + end + + # A full sentence describing how to remove the checksum + def removal + case type + when :lock + "remove the matching checksum in #{location}" + when :gem + "remove the gem at #{location}" + when :api + "checksums from #{location} cannot be locally modified, you may need to update your sources" + else + "remove #{location} (#{type})" + end + end + end + + class Store + attr_reader :store + protected :store + + def initialize + @store = {} + @store_mutex = Mutex.new + end + + def inspect + "#<#{self.class}:#{object_id} size=#{store.size}>" + end + + # Replace when the new checksum is from the same source. + # The primary purpose is registering checksums from gems where there are + # duplicates of the same gem (according to full_name) in the index. + # + # In particular, this is when 2 gems have two similar platforms, e.g. + # "darwin20" and "darwin-20", both of which resolve to darwin-20. + # In the Index, the later gem replaces the former, so we do that here. + # + # However, if the new checksum is from a different source, we register like normal. + # This ensures a mismatch error where there are multiple top level sources + # that contain the same gem with different checksums. + def replace(spec, checksum) + return unless checksum + + lock_name = spec.lock_name + @store_mutex.synchronize do + existing = fetch_checksum(lock_name, checksum.algo) + if !existing || existing.same_source?(checksum) + store_checksum(lock_name, checksum) + else + merge_checksum(lock_name, checksum, existing) + end + end + end + + def missing?(spec) + @store[spec.lock_name].nil? + end + + def empty?(spec) + return false unless spec.source.is_a?(Bundler::Source::Rubygems) + + @store[spec.lock_name].empty? + end + + def register(spec, checksum) + register_checksum(spec.lock_name, checksum) + end + + def merge!(other) + other.store.each do |lock_name, checksums| + checksums.each do |_algo, checksum| + register_checksum(lock_name, checksum) + end + end + end + + def to_lock(spec) + lock_name = spec.lock_name + checksums = @store[lock_name] + if checksums&.any? + "#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}" + else + lock_name + end + end + + private + + def register_checksum(lock_name, checksum) + @store_mutex.synchronize do + if checksum + existing = fetch_checksum(lock_name, checksum.algo) + if existing + merge_checksum(lock_name, checksum, existing) + else + store_checksum(lock_name, checksum) + end + else + init_checksum(lock_name) + end + end + end + + def merge_checksum(lock_name, checksum, existing) + existing.merge!(checksum) || raise(ChecksumMismatchError.new(lock_name, existing, checksum)) + end + + def store_checksum(lock_name, checksum) + init_checksum(lock_name)[checksum.algo] = checksum + end + + def init_checksum(lock_name) + @store[lock_name] ||= {} + end + + def fetch_checksum(lock_name, algo) + @store[lock_name]&.fetch(algo, nil) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ci_detector.rb b/bin/gems/bundler-4.0.21/lib/bundler/ci_detector.rb new file mode 100644 index 00000000..e5fedbdea --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ci_detector.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Bundler + module CIDetector + # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and + # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates). + # TODO: Drop that duplication once bundler drops support for RubyGems 3.4 + # + # ## Recognized CI providers, their signifiers, and the relevant docs ## + # + # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables + # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables + # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables + # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/ + # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/ + # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables + # dsari - CI, DSARI https://github.com/rfinnie/dsari#running + # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables + # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters + # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments + # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars + # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/ + # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables + # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html + # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables + # + # ### Some "standard" ENVs that multiple providers may set ### + # + # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard. + # * CI_NAME - Not as frequently used, but some providers set this to specify their own name + + # Any of these being set is a reasonably reliable indicator that we are + # executing in a CI environment. + ENV_INDICATORS = [ + "CI", + "CI_NAME", + "CONTINUOUS_INTEGRATION", + "BUILD_NUMBER", + "CI_APP_ID", + "CI_BUILD_ID", + "CI_BUILD_NUMBER", + "RUN_ID", + "TASKCLUSTER_ROOT_URL", + ].freeze + + # For each CI, this env suffices to indicate that we're on _that_ CI's + # containers. (A few of them only supply a CI_NAME variable, which is also + # nice). And if they set "CI" but we can't tell which one they are, we also + # want to know that - a bare "ci" without another token tells us as much. + ENV_DESCRIPTORS = { + "TRAVIS" => "travis", + "CIRCLECI" => "circle", + "CIRRUS_CI" => "cirrus", + "DSARI" => "dsari", + "SEMAPHORE" => "semaphore", + "JENKINS_URL" => "jenkins", + "BUILDKITE" => "buildkite", + "GO_SERVER_URL" => "go", + "GITLAB_CI" => "gitlab", + "GITHUB_ACTIONS" => "github", + "TASKCLUSTER_ROOT_URL" => "taskcluster", + "CI" => "ci", + }.freeze + + def self.ci? + ENV_INDICATORS.any? {|var| ENV.include?(var) } + end + + def self.ci_strings + matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values + matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"] + matching_names.reject(&:empty?).sort.uniq + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli.rb new file mode 100644 index 00000000..336ca721 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli.rb @@ -0,0 +1,831 @@ +# frozen_string_literal: true + +require_relative "vendored_thor" + +module Bundler + class CLI < Thor + require_relative "cli/common" + require_relative "cli/install" + + package_name "Bundler" + + AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze + PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze + EXTENSIONS = ["c", "rust", "go"].freeze + + COMMAND_ALIASES = { + "check" => "c", + "install" => "i", + "plugin" => "", + "list" => "ls", + "exec" => ["e", "ex", "exe"], + "cache" => ["package", "pack"], + "version" => ["-v", "--version"], + }.freeze + + def self.start(*) + check_invalid_ext_option(ARGV) if ARGV.include?("--ext") + + super + ensure + Bundler::SharedHelpers.print_major_deprecations! + end + + def self.dispatch(*) + super do |i| + i.send(:print_command) + i.send(:warn_on_outdated_bundler) + end + end + + def self.all_aliases + @all_aliases ||= begin + command_aliases = {} + + COMMAND_ALIASES.each do |name, aliases| + Array(aliases).each do |one_alias| + command_aliases[one_alias] = name + end + end + + command_aliases + end + end + + def self.aliases_for(command_name) + COMMAND_ALIASES.select {|k, _| k == command_name }.invert + end + + def initialize(*args) + super + + current_cmd = args.last[:current_command].name + + # `bundle config` manages stored settings, so avoid promoting settings + # like `gemfile` or `lockfile` to environment variables before it runs. + unless current_cmd == "config" + Bundler.configure_custom_gemfile(options[:gemfile]) + + # lock --lockfile works differently than install --lockfile + unless current_cmd == "lock" + custom_lockfile = options[:lockfile] || ENV["BUNDLE_LOCKFILE"] || Bundler.settings[:lockfile] + if custom_lockfile && !custom_lockfile.empty? + Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", File.expand_path(custom_lockfile) + reset_settings = true + end + end + end + + Bundler.reset_settings_and_root! if reset_settings + + Bundler.auto_switch + + Bundler.settings.set_command_option_if_given :retry, options[:retry] + + Bundler.auto_install if AUTO_INSTALL_CMDS.include?(current_cmd) + rescue UnknownArgumentError => e + raise InvalidOption, e.message + ensure + self.options ||= {} + unprinted_warnings = Bundler.ui.unprinted_warnings + Bundler.ui = UI::Shell.new(options) + Bundler.ui.level = "debug" if options[:verbose] || Bundler.settings[:verbose] + unprinted_warnings.each {|w| Bundler.ui.warn(w) } + end + + check_unknown_options!(except: [:config, :exec]) + stop_on_unknown_option! :exec + + desc "cli_help", "Prints a summary of bundler commands", hide: true + def cli_help + version + Bundler.ui.info "\n" + + primary_commands = ["install", "update", "cache", "exec", "config", "help"] + + list = self.class.printable_commands(true) + by_name = list.group_by {|name, _message| name.match(/^bundler? (\w+)/)[1] } + utilities = by_name.keys.sort - primary_commands + primary_commands.map! {|name| (by_name[name] || raise("no primary command #{name}")).first } + utilities.map! {|name| by_name[name].first } + + shell.say "Bundler commands:\n\n" + + shell.say " Primary commands:\n" + shell.print_table(primary_commands, indent: 4, truncate: true) + shell.say + shell.say " Utilities:\n" + shell.print_table(utilities, indent: 4, truncate: true) + shell.say + self.class.send(:class_options_help, shell) + end + + desc "install_or_cli_help", "Deprecated alias of install", hide: true + def install_or_cli_help + Bundler.ui.warn <<~MSG + `bundle install_or_cli_help` is a deprecated alias of `bundle install`. + It might be called due to the 'default_cli_command' being set to 'install_or_cli_help', + if so fix that by running `bundle config set default_cli_command install --global`. + MSG + invoke_other_command("install") + end + + def self.default_command(meth = nil) + return super if meth + + unless Bundler.settings[:default_cli_command] + Bundler.ui.info <<~MSG + In a future version of Bundler, running `bundle` without argument will no longer run `bundle install`. + Instead, the `cli_help` command will be displayed. Please use `bundle install` explicitly for scripts like CI/CD. + You can use the future behavior now with `bundle config set default_cli_command cli_help --global`, + or you can continue to use the current behavior with `bundle config set default_cli_command install --global`. + This message will be removed after a default_cli_command value is set. + + MSG + end + + Bundler.settings[:default_cli_command] || "install" + end + + class_option "no-color", type: :boolean, desc: "Disable colorization in output" + class_option "retry", type: :numeric, aliases: "-r", banner: "NUM", + desc: "Specify the number of times you wish to attempt network commands" + class_option "verbose", type: :boolean, desc: "Enable verbose output mode", aliases: "-V" + + def help(cli = nil) + cli = self.class.all_aliases[cli] if self.class.all_aliases[cli] + + if Bundler.settings[:plugins] && Bundler::Plugin.command?(cli) && !self.class.all_commands.key?(cli) + return Bundler::Plugin.exec_command(cli, ["--help"]) + end + + case cli + when "gemfile" then command = "gemfile" + when nil then command = "bundle" + else command = "bundle-#{cli}" + end + + man_path = File.expand_path("man", __dir__) + man_pages = Hash[Dir.glob(File.join(man_path, "**", "*")).grep(/.*\.\d*\Z/).collect do |f| + [File.basename(f, ".*"), f] + end] + + if man_pages.include?(command) + man_page = man_pages[command] + if Bundler.which("man") && !man_path.match?(%r{^(?:file:/.+!|uri:classloader:)/META-INF/jruby.home/.+}) + Kernel.exec("man", man_page) + else + puts File.read("#{man_path}/#{File.basename(man_page)}.ronn") + end + elsif command_path = Bundler.which("bundler-#{cli}") + Kernel.exec(command_path, "--help") + else + super + end + end + + def self.handle_no_command_error(command, has_namespace = $thor_runner) + if Bundler.settings[:plugins] && Bundler::Plugin.command?(command) + return Bundler::Plugin.exec_command(command, ARGV[1..-1]) + end + + return super unless command_path = Bundler.which("bundler-#{command}") + + Kernel.exec(command_path, *ARGV[1..-1]) + end + + desc "init [OPTIONS]", "Generates a Gemfile into the current working directory" + long_desc <<-D + Init generates a default Gemfile in the current working directory. When adding a + Gemfile to a gem with a gemspec, the --gemspec option will automatically add each + dependency listed in the gemspec file to the newly created Gemfile. + D + method_option "gemspec", type: :string, banner: "Use the specified .gemspec to create the Gemfile" + method_option "gemfile", type: :string, banner: "Use the specified name for the gemfile instead of 'Gemfile'" + def init + require_relative "cli/init" + Init.new(options.dup).run + end + + desc "check [OPTIONS]", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems" + long_desc <<-D + Check searches the local machine for each of the gems requested in the Gemfile. If + all gems are found, Bundler prints a success message and exits with a status of 0. + If not, the first missing gem is listed and Bundler exits status 1. + D + method_option "dry-run", type: :boolean, default: false, banner: "Lock the Gemfile" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)" + def check + remembered_flag_deprecation("path") + + require_relative "cli/check" + Check.new(options).run + end + + map aliases_for("check") + + desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile" + long_desc <<-D + Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning. + D + method_option "install", type: :boolean, banner: "Runs 'bundle install' after removing the gems from the Gemfile (removed)" + def remove(*gems) + if ARGV.include?("--install") + removed_message = "The `--install` flag has been removed. `bundle install` is triggered by default." + raise InvalidOption, removed_message + end + + require_relative "cli/remove" + Remove.new(gems, options).run + end + + desc "install [OPTIONS]", "Install the current environment to the system" + long_desc <<-D + Install will install all of the gems in the current bundle, making them available + for use. In a freshly checked out repository, this command will give you the same + gem versions as the last person who updated the Gemfile and ran `bundle update`. + + Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed + into the [DIR] directory rather than into system gems. + + If the bundle has already been installed, bundler will tell you so and then exit. + D + method_option "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin (removed)" + method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install (removed)" + method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments (removed)" + method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install (removed)" + method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "lockfile", type: :string, banner: "Use the specified lockfile instead of the default." + method_option "prefer-local", type: :boolean, banner: "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely" + method_option "no-cache", type: :boolean, banner: "Don't update the existing gem cache." + method_option "no-lock", type: :boolean, banner: "Don't create a lockfile." + method_option "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed" + method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)." + method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)." + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default, usually 'ruby' (removed)" + method_option "standalone", type: :array, lazy_default: [], banner: "Make a bundle that can work without the Bundler runtime" + method_option "system", type: :boolean, banner: "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application (removed)" + method_option "trust-policy", alias: "P", type: :string, banner: "Gem trust policy (like gem install -P). Must be one of #{Bundler.rubygems.security_policy_keys.join("|")}" + method_option "target-rbconfig", type: :string, banner: "Path to rbconfig.rb for the deployment target platform" + method_option "without", type: :array, banner: "Exclude gems that are part of the specified named group (removed)." + method_option "with", type: :array, banner: "Include gems that are part of the specified named group (removed)." + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + def install + %w[clean deployment frozen no-prune path shebang without with].each do |option| + remembered_flag_deprecation(option) + end + + print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system") + + remembered_flag_deprecation("deployment", negative: true) + + if ARGV.include?("--binstubs") + removed_message = "The --binstubs option has been removed in favor of `bundle binstubs --all`" + raise InvalidOption, removed_message + end + + require_relative "cli/install" + options = self.options.dup + options["lockfile"] ||= ENV["BUNDLE_LOCKFILE"] + Bundler.settings.temporary(no_install: false) do + Install.new(options).run + end + rescue GemfileNotFound => error + invoke_other_command("cli_help") + raise error # re-raise to show the error and get a failing exit status + end + + map aliases_for("install") + + desc "update [OPTIONS]", "Update the current environment" + long_desc <<-D + Update will install the newest versions of the gems listed in the Gemfile. Use + update when you have changed the Gemfile, or if you want to get the newest + possible versions of the gems in the bundle. + D + method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "group", aliases: "-g", type: :array, banner: "Update a specific group" + method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "source", type: :array, banner: "Update a specific source (and all gems associated with it)" + method_option "force", type: :boolean, aliases: "--redownload", banner: "Force reinstalling every gem, even if already installed" + method_option "ruby", type: :boolean, banner: "Update ruby specified in Gemfile.lock" + method_option "bundler", type: :string, lazy_default: ">= #{Bundler::VERSION}", banner: "Update the locked version of bundler" + method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version" + method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)" + method_option "pre", type: :boolean, banner: "Always choose the highest allowed version when updating gems, regardless of prerelease status" + method_option "strict", type: :boolean, banner: "Do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "conservative", type: :boolean, banner: "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." + method_option "all", type: :boolean, banner: "Update everything." + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + def update(*gems) + require_relative "cli/update" + Bundler.settings.temporary(no_install: false) do + Update.new(options, gems).run + end + end + + desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" + long_desc <<-D + Show lists the names and versions of all gems that are required by your Gemfile. + Calling show with [GEM] will list the exact location of that gem on your machine. + D + method_option "paths", type: :boolean, banner: "List the paths of all gems that are required by your Gemfile." + method_option "outdated", type: :boolean, banner: "Show verbose output including whether gems are outdated (removed)." + def show(gem_name = nil) + if ARGV.include?("--outdated") + removed_message = "the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`" + raise InvalidOption, removed_message + end + require_relative "cli/show" + Show.new(options, gem_name).run + end + + desc "list", "List all gems in the bundle" + method_option "name-only", type: :boolean, banner: "print only the gem names" + method_option "only-group", type: :array, default: [], banner: "print gems from a given set of groups" + method_option "without-group", type: :array, default: [], banner: "print all gems except from a given set of groups" + method_option "format", type: :string, banner: "format output ('json' is the only supported format)" + method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle" + def list + require_relative "cli/list" + List.new(options).run + end + + map aliases_for("list") + + desc "info GEM [OPTIONS]", "Show information for the given gem" + method_option "path", type: :boolean, banner: "Print full path to gem" + method_option "version", type: :boolean, banner: "Print gem version" + def info(gem_name) + require_relative "cli/info" + Info.new(options, gem_name).run + end + + desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem" + long_desc <<-D + Generate binstubs for executables in [GEM]. Binstubs are put into bin, + or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]] + will create binstubs for all given gems. + D + method_option "force", type: :boolean, default: false, banner: "Overwrite existing binstubs if they exist" + method_option "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory, `bin` by default (removed)" + method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')" + method_option "standalone", type: :boolean, banner: "Make binstubs that can work without the Bundler runtime" + method_option "all", type: :boolean, banner: "Install binstubs for all gems" + method_option "all-platforms", type: :boolean, default: false, banner: "Install binstubs for all platforms" + def binstubs(*gems) + remembered_flag_deprecation("path", option_name: "bin") + + require_relative "cli/binstubs" + Binstubs.new(options, gems).run + end + + desc "add GEM VERSION", "Add gem to Gemfile and run bundle install" + long_desc <<-D + Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step. + D + method_option "version", aliases: "-v", type: :string + method_option "group", aliases: "-g", type: :string + method_option "source", aliases: "-s", type: :string + method_option "require", aliases: "-r", type: :string, banner: "Adds require path to gem. Provide false, or a path as a string." + method_option "path", type: :string + method_option "git", type: :string + method_option "github", type: :string + method_option "branch", type: :string + method_option "ref", type: :string + method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it" + method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem" + method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem" + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + def add(*gems) + require_relative "cli/add" + Add.new(options.dup, gems).run + end + + desc "outdated GEM [OPTIONS]", "List installed gems with newer versions available" + long_desc <<-D + Outdated lists the names and versions of gems that have a newer version available + in the given source. Calling outdated with [GEM [GEM]] will only check for newer + versions of the given gems. Prerelease gems are ignored by default. If your gems + are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. + + For more information on patch level options (--major, --minor, --patch, + --strict) see documentation on the same options on the update command. + D + method_option "group", type: :string, banner: "List gems from a specific group" + method_option "groups", type: :boolean, banner: "List gems organized by groups" + method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "pre", type: :boolean, banner: "Check for newer pre-release gems" + method_option "source", type: :array, banner: "Check against a specific source" + method_option "filter-strict", type: :boolean, aliases: "--strict", banner: "Only list newer versions allowed by your Gemfile requirements" + method_option "update-strict", type: :boolean, banner: "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)" + method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version" + method_option "filter-major", type: :boolean, banner: "Only list major newer versions" + method_option "filter-minor", type: :boolean, banner: "Only list minor newer versions" + method_option "filter-patch", type: :boolean, banner: "Only list patch newer versions" + method_option "parseable", aliases: "--porcelain", type: :boolean, banner: "Use minimal formatting for more parseable output" + method_option "only-explicit", type: :boolean, banner: "Only list gems specified in your Gemfile, not their dependencies" + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + def outdated(*gems) + require_relative "cli/outdated" + Outdated.new(options, gems).run + end + + desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance" + method_option "group", aliases: "-g", type: :array, banner: "Fetch funding information for a specific group" + def fund + require_relative "cli/fund" + Fund.new(options).run + end + + desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache" + method_option "all", type: :boolean, default: Bundler.settings[:cache_all], banner: "Include all sources (including path and git) (removed)." + method_option "all-platforms", type: :boolean, banner: "Include gems for all platforms present in the lockfile, not only the current one" + method_option "cache-path", type: :string, banner: "Specify a different cache path than the default (vendor/cache)." + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "no-install", type: :boolean, banner: "Don't install the gems, only update the cache." + method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache (removed)." + method_option "path", type: :string, banner: "Specify a different path than the system default, namely, $BUNDLE_PATH or $GEM_HOME (removed)." + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install (removed)" + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + long_desc <<-D + The cache command will copy the .gem files for every gem in the bundle into the + directory ./vendor/cache. If you then check that directory into your source + control repository, others who check out your source will be able to install the + bundle without having to download any additional gems. + D + def cache + print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all") + print_remembered_flag_deprecation("--no-all", "cache_all", "false") if ARGV.include?("--no-all") + + %w[frozen no-prune].each do |option| + remembered_flag_deprecation(option) + end + + if flag_passed?("--path") + removed_message = + "The `--path` flag has been removed because its semantics were unclear. " \ + "Use `bundle config cache_path` to configure the path of your cache of gems, " \ + "and `bundle config path` to configure the path where your gems are installed, " \ + "and stop using this flag" + raise InvalidOption, removed_message + end + + require_relative "cli/cache" + Cache.new(options).run + end + + map aliases_for("cache") + + desc "exec [OPTIONS]", "Run the command in context of the bundle" + method_option :keep_file_descriptors, type: :boolean, default: true, banner: "Passes all file descriptors to the new processes. Default is true, and setting it to false is not permitted (removed)." + method_option :gemfile, type: :string, required: false, banner: "Use the specified gemfile instead of Gemfile" + long_desc <<-D + Exec runs a command, providing it access to the gems in the bundle. While using + bundle exec you can require and call the bundled gems as if they were installed + into the system wide RubyGems repository. + D + def exec(*args) + if ARGV.include?("--no-keep-file-descriptors") + removed_message = "The `--no-keep-file-descriptors` has been removed. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to" + raise InvalidOption, removed_message + end + + require_relative "cli/exec" + Exec.new(options, args).run + end + + map aliases_for("exec") + + desc "config NAME [VALUE]", "Retrieve or set a configuration value" + long_desc <<-D + Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the + existing value with the newly provided one. + + By default, setting a configuration value sets it for all projects + on the machine. + + If a global setting is superseded by local configuration, this command + will show the current value, as well as any superseded values and + where they were specified. + D + require_relative "cli/config" + subcommand "config", Config + + desc "open GEM", "Opens the source directory of the given bundled gem" + method_option "path", type: :string, lazy_default: "", banner: "Open relative path of the gem source." + def open(name) + require_relative "cli/open" + Open.new(options, name).run + end + + desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded" + def console(group = nil) + require_relative "cli/console" + Console.new(options, group).run + end + + desc "version", "Prints Bundler version information" + def version + cli_help = current_command.name == "cli_help" + if cli_help || ARGV.include?("version") + build_info = " (#{BuildMetadata.timestamp} commit #{BuildMetadata.git_commit_sha})" + end + + if !cli_help + Bundler.ui.info "#{Bundler.verbose_version}#{build_info}" + else + Bundler.ui.info "Bundler version #{Bundler.verbose_version}#{build_info}" + end + end + + map aliases_for("version") + + desc "licenses", "Prints the license of all gems in the bundle" + def licenses + Bundler.load.specs.sort_by {|s| s.license.to_s }.reverse_each do |s| + gem_name = s.name + license = s.license || s.licenses + + if license.empty? + Bundler.ui.warn "#{gem_name}: Unknown" + else + Bundler.ui.info "#{gem_name}: #{license}" + end + end + end + + desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true + def viz + SharedHelpers.feature_removed! "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph" + end + + desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem" + method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], banner: "Generate a binary executable for your library." + method_option :coc, type: :boolean, banner: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`." + method_option :edit, type: :string, aliases: "-e", required: false, lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, banner: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" + method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS + method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library." + method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." + method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true` (removed)." + method_option :changelog, type: :boolean, banner: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." + method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library", enum: %w[rspec minitest test-unit], desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." + method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", enum: %w[github gitlab circle], banner: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`" + method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "", enum: %w[rubocop standard], banner: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`" + method_option :github_username, type: :string, default: Bundler.settings["gem.github_username"], banner: "Set your username on GitHub", desc: "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username `." + method_option :bundle, type: :boolean, default: Bundler.settings["gem.bundle"], banner: "Automatically run `bundle install` after creation. Set a default with `bundle config set --global gem.bundle true`" + + def gem(name) + require_relative "cli/gem" + + raise InvalidOption, "--rubocop has been removed, use --linter=rubocop" if ARGV.include?("--rubocop") + raise InvalidOption, "--no-rubocop has been removed, use --no-linter" if ARGV.include?("--no-rubocop") + + cmd_args = args + [self] + cmd_args.unshift(options) + + Gem.new(*cmd_args).run + end + + def self.source_root + File.expand_path("templates", __dir__) + end + + desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory" + method_option "dry-run", type: :boolean, default: false, banner: "Only print out changes, do not clean gems" + method_option "force", type: :boolean, default: false, banner: "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application." + def clean + require_relative "cli/clean" + Clean.new(options.dup).run + end + + desc "platform [OPTIONS]", "Displays platform compatibility information" + method_option "ruby", type: :boolean, default: false, banner: "only display ruby related platform information" + def platform + require_relative "cli/platform" + Platform.new(options).run + end + + desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", hide: true + def inject(*) + SharedHelpers.feature_removed! "The `inject` command has been replaced by the `add` command" + end + + desc "lock", "Creates a lockfile without installing" + method_option "update", type: :array, lazy_default: true, repeatable: true, banner: "ignore the existing lockfile, update all gems by default, or update list of given gems" + method_option "local", type: :boolean, default: false, banner: "do not attempt to fetch remote gemspecs and use the local gem cache only" + method_option "print", type: :boolean, default: false, banner: "print the lockfile to STDOUT instead of writing to the file system" + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "lockfile", type: :string, default: nil, banner: "the path the lockfile should be written to" + method_option "full-index", type: :boolean, default: false, banner: "Fall back to using the single-file index of all gems" + method_option "add-checksums", type: :boolean, default: false, banner: "Adds checksums to the lockfile" + method_option "add-platform", type: :array, default: [], repeatable: true, banner: "Add a new platform to the lockfile" + method_option "remove-platform", type: :array, default: [], repeatable: true, banner: "Remove a platform from the lockfile" + method_option "normalize-platforms", type: :boolean, default: false, banner: "Normalize lockfile platforms" + method_option "patch", type: :boolean, banner: "If updating, prefer updating only to next patch version" + method_option "minor", type: :boolean, banner: "If updating, prefer updating only to next minor version" + method_option "major", type: :boolean, banner: "If updating, prefer updating to next major version (default)" + method_option "pre", type: :boolean, banner: "If updating, always choose the highest allowed version, regardless of prerelease status" + method_option "strict", type: :boolean, banner: "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" + method_option "conservative", type: :boolean, banner: "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" + method_option "bundler", type: :string, lazy_default: ">= #{Bundler::VERSION}", banner: "Update the locked version of bundler" + method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable." + def lock + require_relative "cli/lock" + Lock.new(options).run + end + + desc "env", "Print information about the environment Bundler is running under" + def env + Env.write($stdout) + end + + desc "doctor [OPTIONS]", "Checks the bundle for common problems" + require_relative "cli/doctor" + subcommand("doctor", Doctor) + + desc "issue", "Learn how to report an issue in Bundler" + def issue + require_relative "cli/issue" + Issue.new.run + end + + desc "pristine [GEMS...]", "Restores installed gems to pristine condition" + long_desc <<-D + Restores installed gems to pristine condition from files located in the + gem cache. Gems installed from a git repository will be issued `git + checkout --force`. + D + def pristine(*gems) + require_relative "cli/pristine" + Bundler.settings.temporary(no_install: false) do + Pristine.new(gems).run + end + end + + if Bundler.settings[:plugins] + require_relative "cli/plugin" + desc "plugin", "Manage the bundler plugins" + subcommand "plugin", Plugin + end + + # Reformat the arguments passed to bundle that include a --help flag + # into the corresponding `bundle help #{command}` call + def self.reformatted_help_args(args) + bundler_commands = (COMMAND_ALIASES.keys + COMMAND_ALIASES.values).flatten + + help_flags = %w[--help -h] + exec_commands = ["exec"] + COMMAND_ALIASES["exec"] + + help_used = args.index {|a| help_flags.include? a } + exec_used = args.index {|a| exec_commands.include? a } + + command = args.find {|a| bundler_commands.include? a } + + if exec_used && help_used + if exec_used + help_used == 1 + %w[help exec] + else + args + end + elsif help_used + args = args.dup + args.delete_at(help_used) + ["help", command || args].flatten.compact + else + args + end + end + + def self.check_invalid_ext_option(arguments) + # when invalid version of `--ext` is called + if invalid_ext_value?(arguments) + removed_message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been removed. Please select a language, e.g. `--ext=rust` to generate a Rust extension." + raise InvalidOption, removed_message + end + end + + def self.invalid_ext_value?(arguments) + index = arguments.index("--ext") + next_argument = arguments[index + 1] + + # it is ok when --ext is followed with valid extension value + # for example `bundle gem hello --ext c` + return false if EXTENSIONS.include?(next_argument) + + # invalid call when --ext is called with no value in last position + # for example `bundle gem hello_gem --ext` + return true if next_argument.nil? + + # invalid call when --ext is followed by other parameter + # for example `bundle gem --ext --no-ci hello_gem` + return true if next_argument.start_with?("-") + + # invalid call when --ext is followed by gem name + # for example `bundle gem --ext hello_gem` + return true if next_argument + + false + end + + private + + def current_command + _, _, config = @_initializer + config[:current_command] + end + + def invoke_other_command(name) + _, _, config = @_initializer + original_command = config[:current_command] + command = self.class.all_commands[name] + config[:current_command] = command + send(name) + ensure + config[:current_command] = original_command + end + + def current_command=(command) + end + + def print_command + return unless Bundler.ui.debug? + cmd = current_command + command_name = cmd.name + return if PARSEABLE_COMMANDS.include?(command_name) + command = ["bundle", command_name] + args + options_to_print = options.dup + options_to_print.delete_if do |k, v| + next unless o = cmd.options[k] + o.default == v + end + command << Thor::Options.to_switches(options_to_print.sort_by(&:first)).strip + command.reject!(&:empty?) + Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler.verbose_version}" + end + + def warn_on_outdated_bundler + return if Bundler.settings[:disable_version_check] + + command_name = current_command.name + return if PARSEABLE_COMMANDS.include?(command_name) + + return unless SharedHelpers.md5_available? + + require_relative "vendored_uri" + remote = Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org")) + cache_path = Bundler.user_cache.join("compact_index", remote.cache_slug) + latest = Bundler::CompactIndexClient.new(cache_path).latest_version("bundler") + return unless latest + + current = Gem::Version.new(VERSION) + return if current >= latest + + Bundler.ui.warn \ + "The latest bundler is #{latest}, but you are currently running #{current}.\n" \ + "To update to the most recent version, run `bundle update --bundler`" + rescue RuntimeError + nil + end + + def remembered_flag_deprecation(name, negative: false, option_name: nil) + option = current_command.options[name] + flag_name = option.switch_name + flag_name = "--no-" + flag_name.gsub(/\A--/, "") if negative + return unless flag_passed?(flag_name) + + value = options[name] + value = value.join(" ").to_s if option.type == :array + value = "'#{value}'" unless option.type == :boolean + + print_remembered_flag_deprecation(flag_name, option_name || name.tr("-", "_"), value) + end + + def print_remembered_flag_deprecation(flag_name, option_name, option_value) + removed_message = + "The `#{flag_name}` flag has been removed because it relied on being " \ + "remembered across bundler invocations, which bundler no longer does. " \ + "Instead please use `bundle config set #{option_name} #{option_value}`, " \ + "and stop using this flag" + raise InvalidOption, removed_message + end + + def flag_passed?(name) + ARGV.any? {|arg| name == arg.split("=")[0] } + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/add.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/add.rb new file mode 100644 index 00000000..ad76b019 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/add.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Add + attr_reader :gems, :options, :version + + def initialize(options, gems) + @gems = gems + @options = options + @options[:group] = options[:group].split(",").map(&:strip) unless options[:group].nil? + @version = options[:version].split(",").map(&:strip) unless options[:version].nil? + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + + Bundler::CLI::Common.validate_cooldown!(options[:cooldown]) + Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown] + + validate_options! + inject_dependencies + perform_bundle_install unless options["skip-install"] + end + + private + + def perform_bundle_install + Installer.install(Bundler.root, Bundler.definition) + Bundler.load.cache if Bundler.app_cache.exist? + end + + def inject_dependencies + dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) } + + Injector.inject(dependencies, + conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified + optimistic: options[:optimistic], + strict: options[:strict]) + end + + def validate_options! + raise InvalidOption, "You cannot specify `--git` and `--github` at the same time." if options["git"] && options["github"] + + unless options["git"] || options["github"] + raise InvalidOption, "You cannot specify `--branch` unless `--git` or `--github` is specified." if options["branch"] + + raise InvalidOption, "You cannot specify `--ref` unless `--git` or `--github` is specified." if options["ref"] + end + + raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"] + + raise InvalidOption, "You cannot specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic] + + # raise error when no gems are specified + raise InvalidOption, "Please specify gems to add." if gems.empty? + + version.to_a.each do |v| + raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN.match?(v.to_s) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/binstubs.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/binstubs.rb new file mode 100644 index 00000000..8ce138df --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/binstubs.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Binstubs + attr_reader :options, :gems + def initialize(options, gems) + @options = options + @gems = gems + end + + def run + Bundler.definition.validate_runtime! + path_option = options["path"] + path_option = nil if path_option&.empty? + Bundler.settings.set_command_option :bin, path_option if options["path"] + Bundler.settings.set_command_option_if_given :shebang, options["shebang"] + installer = Installer.new(Bundler.root, Bundler.definition) + + installer_opts = { + force: options[:force], + binstubs_cmd: true, + all_platforms: options["all-platforms"], + } + + if options[:all] + raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? + @gems = Bundler.definition.specs.map(&:name) + installer_opts.delete(:binstubs_cmd) + elsif gems.empty? + Bundler.ui.error "`bundle binstubs` needs at least one gem to run." + exit 1 + end + + gems.each do |gem_name| + spec = Bundler.definition.specs.find {|s| s.name == gem_name } + unless spec + raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( + gem_name, Bundler.definition.specs + ) + end + + if options[:standalone] + if gem_name == "bundler" + Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") unless options[:all] + next + end + + Bundler.settings.temporary(path: Bundler.settings[:path] || Bundler.root) do + installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) + end + else + installer.generate_bundler_executable_stubs(spec, installer_opts) + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/cache.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/cache.rb new file mode 100644 index 00000000..59605df8 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/cache.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Cache + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] + + install + + Bundler.settings.temporary(cache_all_platforms: options["all-platforms"]) do + Bundler.load.cache + end + end + + private + + def install + require_relative "install" + options = self.options.dup + options["local"] = false if Bundler.settings[:cache_all_platforms] + options["no-cache"] = true + Bundler::CLI::Install.new(options).run + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/check.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/check.rb new file mode 100644 index 00000000..eb2c49dd --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/check.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Check + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.settings.set_command_option_if_given :path, options[:path] + + definition = Bundler.definition + definition.ensure_equivalent_gemfile_and_lockfile + definition.validate_runtime! + + begin + definition.check! + not_installed = definition.missing_specs + rescue GemNotFound, GitError, SolveFailure + Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." + Bundler.ui.warn "Install missing gems with `bundle install`." + exit 1 + end + + if not_installed.any? + Bundler.ui.error "The following gems are missing" + not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } + Bundler.ui.warn "Install missing gems with `bundle install`" + exit 1 + else + definition.lock(true) unless options[:"dry-run"] + Bundler.ui.info "The Gemfile's dependencies are satisfied" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/clean.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/clean.rb new file mode 100644 index 00000000..c6b0968e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/clean.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Clean + attr_reader :options + + def initialize(options) + @options = options + end + + def run + require_path_or_force unless options[:"dry-run"] + Bundler.load.clean(options[:"dry-run"]) + end + + protected + + def require_path_or_force + return unless Bundler.use_system_gems? && !options[:force] + raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ + "If you're sure you want to remove every system gem not in this " \ + "bundle, run `bundle clean --force`." + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/common.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/common.rb new file mode 100644 index 00000000..070cc095 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/common.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +module Bundler + module CLI::Common + def self.validate_cooldown!(value) + return if value.nil? + return if value.is_a?(Integer) && value >= 0 + raise InvalidOption, "Expected `--cooldown` to be a non-negative integer, got #{value.inspect}" + end + + def self.output_post_install_messages(messages) + return if Bundler.settings["ignore_messages"] + messages.to_a.each do |name, msg| + print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] + end + end + + def self.print_post_install_message(name, msg) + Bundler.ui.confirm "Post-install message from #{name}:" + Bundler.ui.info msg + end + + def self.output_cooldown_skipped_summary(definition = Bundler.definition) + skipped = definition.cooldown_skipped + return if skipped.empty? + + Bundler.ui.info "The following gem versions were skipped by the cooldown setting:" + skipped.each do |entry| + days = entry[:available_in_days] + Bundler.ui.info " * #{entry[:name]} #{entry[:version]} (available in #{days} #{days == 1 ? "day" : "days"}), resolved #{entry[:resolved]} instead" + end + end + + def self.output_fund_metadata_summary + return if Bundler.settings["ignore_funding_requests"] + definition = Bundler.definition + current_dependencies = definition.requested_dependencies + current_specs = definition.specs + + count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") } + + return if count.zero? + + intro = count > 1 ? "#{count} installed gems you directly depend on are" : "#{count} installed gem you directly depend on is" + message = "#{intro} looking for funding.\n Run `bundle fund` for details" + Bundler.ui.info message + end + + def self.output_without_groups_message(command) + return if Bundler.settings[:without].empty? + Bundler.ui.confirm without_groups_message(command) + end + + def self.without_groups_message(command) + command_in_past_tense = command == :install ? "installed" : "updated" + groups = Bundler.settings[:without] + "Gems in the #{verbalize_groups(groups)} were not #{command_in_past_tense}." + end + + def self.verbalize_groups(groups) + groups.map! {|g| "'#{g}'" } + group_list = [groups[0...-1].join(", "), groups[-1..-1]]. + reject {|s| s.to_s.empty? }.join(" and ") + group_str = groups.size == 1 ? "group" : "groups" + "#{group_str} #{group_list}" + end + + def self.select_spec(name, regex_match = nil) + specs = [] + regexp = Regexp.new(name) if regex_match + + Bundler.definition.specs.each do |spec| + return spec if spec.name == name + specs << spec if regexp && spec.name.match?(regexp) + end + + default_spec = default_gem_spec(name) + specs << default_spec if default_spec + + case specs.count + when 0 + dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name } + + if dep_in_other_group + raise GemNotFound, "Could not find gem '#{name}', because it's in the #{verbalize_groups(dep_in_other_group.groups)}, configured to be ignored." + else + raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) + end + when 1 + specs.first + else + ask_for_spec_from(specs) + end + rescue RegexpError + raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) + end + + def self.default_gem_spec(name) + gem_spec = Gem::Specification.find_all_by_name(name).last + gem_spec if gem_spec&.default_gem? + end + + def self.ask_for_spec_from(specs) + specs.each_with_index do |spec, index| + Bundler.ui.info "#{index.succ} : #{spec.name}", true + end + Bundler.ui.info "0 : - exit -", true + + num = Bundler.ui.ask("> ").to_i + num > 0 ? specs[num - 1] : nil + end + + def self.gem_not_found_message(missing_gem_name, alternatives) + message = "Could not find gem '#{missing_gem_name}'." + alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } + if alternate_names.include?(missing_gem_name.downcase) + message += "\nDid you mean '#{missing_gem_name.downcase}'?" + elsif defined?(DidYouMean::SpellChecker) + suggestions = DidYouMean::SpellChecker.new(dictionary: alternate_names).correct(missing_gem_name) + message += "\nDid you mean #{word_list(suggestions)}?" unless suggestions.empty? + end + message + end + + def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) + return unless locked_gems + + locked_names = locked_gems.specs.map(&:name).uniq + names.-(locked_names).each do |g| + raise GemNotFound, gem_not_found_message(g, locked_names) + end + end + + def self.configure_gem_version_promoter(definition, options) + patch_level = patch_level_options(options) + patch_level << :patch if patch_level.empty? && Bundler.settings[:prefer_patch] + raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 + + definition.gem_version_promoter.tap do |gvp| + gvp.level = patch_level.first || :major + gvp.strict = options[:strict] || options["filter-strict"] + gvp.pre = options[:pre] + end + end + + def self.patch_level_options(options) + [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } + end + + def self.clean_after_install? + clean = Bundler.settings[:clean] + return clean unless clean.nil? + clean ||= Bundler.feature_flag.bundler_5_mode? && Bundler.settings[:path].nil? + clean &&= !Bundler.use_system_gems? + clean + end + + def self.word_list(words) + if words.empty? + return "" + end + + words = words.map {|word| "'#{word}'" } + + if words.length == 1 + return words[0] + end + + [words[0..-2].join(", "), words[-1]].join(" or ") + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/config.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/config.rb new file mode 100644 index 00000000..976cda74 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/config.rb @@ -0,0 +1,208 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Config < Thor + class_option :parseable, type: :boolean, banner: "Use minimal formatting for more parseable output" + + def self.scope_options + method_option :global, type: :boolean, banner: "Only change the global config" + method_option :local, type: :boolean, banner: "Only change the local config" + end + private_class_method :scope_options + + desc "base NAME [VALUE]", "The Bundler 1 config interface", hide: true + scope_options + method_option :delete, type: :boolean, banner: "delete" + def base(name = nil, *value) + new_args = + if ARGV.size == 1 + ["config", "list"] + elsif ARGV.include?("--delete") + ARGV.map {|arg| arg == "--delete" ? "unset" : arg } + elsif ARGV.include?("--global") || ARGV.include?("--local") || ARGV.size == 3 + ["config", "set", *ARGV[1..-1]] + else + ["config", "get", ARGV[1]] + end + + message = "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead." + SharedHelpers.feature_deprecated! message + + Base.new(options, name, value, self).run + end + + desc "list", "List out all configured settings" + def list + Base.new(options, nil, nil, self).run + end + + desc "get NAME", "Returns the value for the given key" + def get(name) + Base.new(options, name, nil, self).run + end + + desc "set NAME VALUE", "Sets the given value for the given key" + scope_options + def set(name, value, *value_) + Base.new(options, name, value_.unshift(value), self).run + end + + desc "unset NAME", "Unsets the value for the given key" + scope_options + def unset(name) + options[:delete] = true + Base.new(options, name, nil, self).run + end + + default_task :base + + class Base + attr_reader :name, :value, :options, :scope, :thor + + def initialize(options, name, value, thor) + @options = options + @name = name + value = Array(value) + @value = value.empty? ? nil : value.join(" ") + @thor = thor + validate_scope! + end + + def run + unless name + warn_unused_scope "Ignoring --#{scope}" + confirm_all + return + end + + if options[:delete] + if !explicit_scope? || scope != "global" + Bundler.settings.set_local(name, nil) + end + if !explicit_scope? || scope != "local" + Bundler.settings.set_global(name, nil) + end + return + end + + if value.nil? + warn_unused_scope "Ignoring --#{scope} since no value to set was given" + current_value = Bundler.settings[name] + + if options[:parseable] + if value = Bundler.settings[name] + Bundler.ui.info("#{name}=#{value}") + end + else + confirm(name) + end + + if current_value.nil? + exit 1 + else + return + end + end + + Bundler.ui.info(message) if message + Bundler.settings.send("set_#{scope}", name, new_value) + end + + def confirm_all + if @options[:parseable] + thor.with_padding do + Bundler.settings.all.each do |setting| + val = Bundler.settings[setting] + Bundler.ui.info "#{setting}=#{val}" + end + end + else + Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" + Bundler.settings.all.each do |setting| + Bundler.ui.confirm setting + show_pretty_values_for(setting) + Bundler.ui.confirm "" + end + end + end + + def confirm(name) + Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" + show_pretty_values_for(name) + end + + def new_value + pathname = Pathname.new(value) + if name.start_with?("local.") && pathname.directory? + pathname.expand_path.to_s + else + value + end + end + + def message + locations = Bundler.settings.locations(name) + if @options[:parseable] + "#{name}=#{new_value}" if new_value + elsif scope == "global" + if !locations[:local].nil? + "Your application has set #{name} to #{locations[:local].inspect}. " \ + "This will override the global value you are currently setting" + elsif locations[:env] + "You have a bundler environment variable for #{name} set to " \ + "#{locations[:env].inspect}. This will take precedence over the global value you are setting" + elsif !locations[:global].nil? && locations[:global] != value + "You are replacing the current global value of #{name}, which is currently " \ + "#{locations[:global].inspect}" + end + elsif scope == "local" && !locations[:local].nil? && locations[:local] != value + "You are replacing the current local value of #{name}, which is currently " \ + "#{locations[:local].inspect}" + end + end + + def show_pretty_values_for(setting) + thor.with_padding do + Bundler.settings.pretty_values_for(setting).each do |line| + Bundler.ui.info line + end + end + end + + def explicit_scope? + @explicit_scope + end + + def warn_unused_scope(msg) + return unless explicit_scope? + return if options[:parseable] + + Bundler.ui.warn(msg) + end + + def validate_scope! + @explicit_scope = true + scopes = %w[global local].select {|s| options[s] } + case scopes.size + when 0 + @scope = inside_app? ? "local" : "global" + @explicit_scope = false + when 1 + @scope = scopes.first + else + raise InvalidOption, + "The options #{scopes.join " and "} were specified. Please only use one of the switches at a time." + end + end + + private + + def inside_app? + Bundler.root + true + rescue GemfileNotFound + false + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/console.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/console.rb new file mode 100644 index 00000000..2d1a2ce4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/console.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Console + attr_reader :options, :group + def initialize(options, group) + @options = options + @group = group + end + + def run + group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require + ARGV.clear + + console = get_console(Bundler.settings[:console] || "irb") + console.start + end + + def get_console(name) + require name + get_constant(name) + rescue LoadError + if name == "irb" + if defined?(Gem::BUNDLED_GEMS) && Gem::BUNDLED_GEMS.respond_to?(:force_activate) + Gem::BUNDLED_GEMS.force_activate "irb" + require name + return get_constant(name) + end + Bundler.ui.error "#{name} is not available" + exit 1 + else + Bundler.ui.error "Couldn't load console #{name}, falling back to irb" + name = "irb" + retry + end + end + + def get_constant(name) + const_name = { + "pry" => :Pry, + "ripl" => :Ripl, + "irb" => :IRB, + }[name] + Object.const_get(const_name) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor.rb new file mode 100644 index 00000000..5fd6a73d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Doctor < Thor + default_command(:diagnose) + + desc "diagnose [OPTIONS]", "Checks the bundle for common problems" + long_desc <<-D + Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If + missing dependencies are detected, Bundler prints them and exits status 1. + Otherwise, Bundler prints a success message and exits with a status of 0. + D + method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile" + method_option "quiet", type: :boolean, banner: "Only output warnings and errors." + method_option "ssl", type: :boolean, default: false, banner: "Diagnose SSL problems." + def diagnose + require_relative "doctor/diagnose" + Diagnose.new(options).run + end + + desc "ssl [OPTIONS]", "Diagnose SSL problems" + long_desc <<-D + Diagnose SSL problems, especially related to certificates or TLS version while connecting to https://rubygems.org. + D + method_option "host", type: :string, banner: "The host to diagnose." + method_option "tls-version", type: :string, banner: "Specify the SSL/TLS version when running the diagnostic. Accepts either <1.1> or <1.2>" + method_option "verify-mode", type: :string, banner: "Specify the mode used for certification verification. Accepts either or " + def ssl + require_relative "doctor/ssl" + SSL.new(options).run + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/diagnose.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/diagnose.rb new file mode 100644 index 00000000..378ef9bf --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/diagnose.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +require "rbconfig" +require "shellwords" + +module Bundler + class CLI::Doctor::Diagnose + DARWIN_REGEX = /\s+(.+) \(compatibility / + LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/ + + attr_reader :options + + def initialize(options) + @options = options + end + + def otool_available? + Bundler.which("otool") + end + + def ldd_available? + Bundler.which("ldd") + end + + def dylibs_darwin(path) + output = `/usr/bin/otool -L #{path.shellescape}`.chomp + dylibs = output.split("\n")[1..-1].filter_map {|l| l.match(DARWIN_REGEX)&.match(1) }.uniq + # ignore @rpath and friends + dylibs.reject {|dylib| dylib.start_with? "@" } + end + + def dylibs_ldd(path) + output = `/usr/bin/ldd #{path.shellescape}`.chomp + output.split("\n").filter_map do |l| + match = l.match(LDD_REGEX) + next if match.nil? + match.captures[0] + end + end + + def dylibs(path) + case RbConfig::CONFIG["host_os"] + when /darwin/ + return [] unless otool_available? + dylibs_darwin(path) + when /(linux|solaris|bsd)/ + return [] unless ldd_available? + dylibs_ldd(path) + else # Windows, etc. + Bundler.ui.warn("Dynamic library check not supported on this platform.") + [] + end + end + + def bundles_for_gem(spec) + SharedHelpers.glob_files_in_dir("**/*.bundle", spec.full_gem_path) + end + + def lookup_with_fiddle(path) + require "fiddle" + Fiddle.dlopen(path) + false + rescue Fiddle::DLError + true + end + + def check! + require_relative "../check" + Bundler::CLI::Check.new({}).run + end + + def diagnose_ssl + require_relative "ssl" + Bundler::CLI::Doctor::SSL.new({}).run + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + Bundler.settings.validate! + check! + diagnose_ssl if options[:ssl] + + definition = Bundler.definition + broken_links = {} + + definition.specs.each do |spec| + bundles_for_gem(spec).each do |bundle| + bad_paths = dylibs(bundle).select do |f| + lookup_with_fiddle(f) + end + if bad_paths.any? + broken_links[spec] ||= [] + broken_links[spec].concat(bad_paths) + end + end + end + + permissions_valid = check_home_permissions + + if broken_links.any? + message = "The following gems are missing OS dependencies:" + broken_links.flat_map do |spec, paths| + paths.uniq.map do |path| + "\n * #{spec.name}: #{path}" + end + end.sort.each {|m| message += m } + raise ProductionError, message + elsif permissions_valid + Bundler.ui.info "No issues found with the installed bundle" + end + end + + private + + def check_home_permissions + require "find" + files_not_readable = [] + files_not_readable_and_owned_by_different_user = [] + files_not_owned_by_current_user_but_still_readable = [] + broken_symlinks = [] + Find.find(Bundler.bundle_path.to_s).each do |f| + if !File.exist?(f) + broken_symlinks << f + elsif !File.readable?(f) + if File.stat(f).uid != Process.uid + files_not_readable_and_owned_by_different_user << f + else + files_not_readable << f + end + elsif File.stat(f).uid != Process.uid + files_not_owned_by_current_user_but_still_readable << f + end + end + + ok = true + + if broken_symlinks.any? + Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" + + ok = false + end + + if files_not_owned_by_current_user_but_still_readable.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, but are still readable. These files are:\n - #{files_not_owned_by_current_user_but_still_readable.join("\n - ")}" + + ok = false + end + + if files_not_readable_and_owned_by_different_user.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, and are not readable. These files are:\n - #{files_not_readable_and_owned_by_different_user.join("\n - ")}" + + ok = false + end + + if files_not_readable.any? + Bundler.ui.warn "Files exist in the Bundler home that are not " \ + "readable by the current user. These files are:\n - #{files_not_readable.join("\n - ")}" + + ok = false + end + + ok + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/ssl.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/ssl.rb new file mode 100644 index 00000000..21fc4edf --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/doctor/ssl.rb @@ -0,0 +1,249 @@ +# frozen_string_literal: true + +require "rubygems/remote_fetcher" +require "uri" + +module Bundler + class CLI::Doctor::SSL + attr_reader :options + + def initialize(options) + @options = options + end + + def run + return unless openssl_installed? + + output_ssl_environment + bundler_success = bundler_connection_successful? + rubygem_success = rubygem_connection_successful? + + return unless net_http_connection_successful? + + Explanation.summarize(bundler_success, rubygem_success, host) + end + + private + + def host + @options[:host] || "rubygems.org" + end + + def tls_version + @options[:"tls-version"].then do |version| + "TLS#{version.sub(".", "_")}".to_sym if version + end + end + + def verify_mode + mode = @options[:"verify-mode"] || :peer + + @verify_mode ||= mode.then {|mod| OpenSSL::SSL.const_get("verify_#{mod}".upcase) } + end + + def uri + @uri ||= URI("https://#{host}") + end + + def openssl_installed? + require "openssl" + + true + rescue LoadError + Bundler.ui.warn(<<~MSG) + Oh no! Your Ruby doesn't have OpenSSL, so it can't connect to #{host}. + You'll need to recompile or reinstall Ruby with OpenSSL support and try again. + MSG + + false + end + + def output_ssl_environment + Bundler.ui.info(<<~MESSAGE) + Here's your OpenSSL environment: + + OpenSSL: #{OpenSSL::VERSION} + Compiled with: #{OpenSSL::OPENSSL_VERSION} + Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION} + MESSAGE + end + + def bundler_connection_successful? + Bundler.ui.info("\nTrying connections to #{uri}:\n") + + bundler_uri = Gem::URI(uri.to_s) + Bundler::Fetcher.new( + Bundler::Source::Rubygems::Remote.new(bundler_uri) + ).send(:connection).request(bundler_uri) + + Bundler.ui.info("Bundler: success") + + true + rescue StandardError => error + Bundler.ui.warn("Bundler: failed (#{Explanation.explain_bundler_or_rubygems_error(error)})") + + false + end + + def rubygem_connection_successful? + Gem::RemoteFetcher.fetcher.fetch_path(uri) + Bundler.ui.info("RubyGems: success") + + true + rescue StandardError => error + Bundler.ui.warn("RubyGems: failed (#{Explanation.explain_bundler_or_rubygems_error(error)})") + + false + end + + def net_http_connection_successful? + ::Gem::Net::HTTP.new(uri.host, uri.port).tap do |http| + http.use_ssl = true + http.min_version = tls_version + http.max_version = tls_version + http.verify_mode = verify_mode + end.start + + Bundler.ui.info("Ruby net/http: success") + warn_on_unsupported_tls12 + + true + rescue StandardError => error + Bundler.ui.warn(<<~MSG) + Ruby net/http: failed + + Unfortunately, this Ruby can't connect to #{host}. + + #{Explanation.explain_net_http_error(error, host, tls_version)} + MSG + + false + end + + def warn_on_unsupported_tls12 + ctx = OpenSSL::SSL::SSLContext.new + supported = true + + if ctx.respond_to?(:min_version=) + begin + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + rescue OpenSSL::SSL::SSLError, NameError + supported = false + end + else + supported = OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) # rubocop:disable Naming/VariableNumber + end + + Bundler.ui.warn(<<~EOM) unless supported + + WARNING: Although your Ruby can connect to #{host} today, your OpenSSL is very old! + WARNING: You will need to upgrade OpenSSL to use #{host}. + + EOM + end + + module Explanation + extend self + + def explain_bundler_or_rubygems_error(error) + case error.message + when /certificate verify failed/ + "certificate verification" + when /read server hello A/ + "SSL/TLS protocol version mismatch" + when /tlsv1 alert protocol version/ + "requested TLS version is too old" + else + error.message + end + end + + def explain_net_http_error(error, host, tls_version) + case error.message + # Check for certificate errors + when /certificate verify failed/ + <<~MSG + #{show_ssl_certs} + Your Ruby can't connect to #{host} because you are missing the certificate files OpenSSL needs to verify you are connecting to the genuine #{host} servers. + MSG + # Check for TLS version errors + when /read server hello A/, /tlsv1 alert protocol version/ + if tls_version.to_s == "TLS1_3" + "Your Ruby can't connect to #{host} because #{tls_version} isn't supported yet.\n" + else + <<~MSG + Your Ruby can't connect to #{host} because your version of OpenSSL is too old. + You'll need to upgrade your OpenSSL install and/or recompile Ruby to use a newer OpenSSL. + MSG + end + # OpenSSL doesn't support TLS version specified by argument + when /unknown SSL method/ + "Your Ruby can't connect because #{tls_version} isn't supported by your version of OpenSSL." + else + <<~MSG + Even worse, we're not sure why. + + Here's the full error information: + #{error.class}: #{error.message} + #{error.backtrace.join("\n ")} + + You might have more luck using Mislav's SSL doctor.rb script. You can get it here: + https://github.com/mislav/ssl-tools/blob/8b3dec4/doctor.rb + + Read more about the script and how to use it in this blog post: + https://mislav.net/2013/07/ruby-openssl/ + MSG + end + end + + def summarize(bundler_success, rubygems_success, host) + guide_url = "http://ruby.to/ssl-check-failed" + + message = if bundler_success && rubygems_success + <<~MSG + Hooray! This Ruby can connect to #{host}. + You are all set to use Bundler and RubyGems. + + MSG + elsif !bundler_success && !rubygems_success + <<~MSG + For some reason, your Ruby installation can connect to #{host}, but neither RubyGems nor Bundler can. + The most likely fix is to manually upgrade RubyGems by following the instructions at #{guide_url}. + After you've done that, run `gem install bundler` to upgrade Bundler, and then run this script again to make sure everything worked. ❣ + + MSG + elsif !bundler_success + <<~MSG + Although your Ruby installation and RubyGems can both connect to #{host}, Bundler is having trouble. + The most likely way to fix this is to upgrade Bundler by running `gem install bundler`. + Run this script again after doing that to make sure everything is all set. + If you're still having trouble, check out the troubleshooting guide at #{guide_url}. + + MSG + else + <<~MSG + It looks like Ruby and Bundler can connect to #{host}, but RubyGems itself cannot. + You can likely solve this by manually downloading and installing a RubyGems update. + Visit #{guide_url} for instructions on how to manually upgrade RubyGems. + + MSG + end + + Bundler.ui.info("\n#{message}") + end + + private + + def show_ssl_certs + ssl_cert_file = ENV["SSL_CERT_FILE"] || OpenSSL::X509::DEFAULT_CERT_FILE + ssl_cert_dir = ENV["SSL_CERT_DIR"] || OpenSSL::X509::DEFAULT_CERT_DIR + + <<~MSG + Below affect only Ruby net/http connections: + SSL_CERT_FILE: #{File.exist?(ssl_cert_file) ? "exists #{ssl_cert_file}" : "is missing #{ssl_cert_file}"} + SSL_CERT_DIR: #{Dir.exist?(ssl_cert_dir) ? "exists #{ssl_cert_dir}" : "is missing #{ssl_cert_dir}"} + MSG + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/exec.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/exec.rb new file mode 100644 index 00000000..20ed1d8b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/exec.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require_relative "../current_ruby" + +module Bundler + class CLI::Exec + attr_reader :options, :args, :cmd + + TRAPPED_SIGNALS = %w[INT].freeze + + def initialize(options, args) + @options = options + @cmd = args.shift + @args = args + @args << { close_others: !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby? + end + + def run + validate_cmd! + SharedHelpers.set_bundle_environment + if bin_path = Bundler.which(cmd) + if !Bundler.settings[:disable_exec_load] && directly_loadable?(bin_path) + bin_path.delete_suffix!(".bat") if Gem.win_platform? + kernel_load(bin_path, *args) + else + bin_path = explicit_path(bin_path) + kernel_exec(bin_path, *args) + end + else + # exec using the given command + kernel_exec(cmd, *args) + end + end + + private + + def validate_cmd! + return unless cmd.nil? + Bundler.ui.error "bundler: exec needs a command to run" + exit 128 + end + + def kernel_exec(*args) + Kernel.exec(*args) + rescue Errno::EACCES, Errno::ENOEXEC + Bundler.ui.error "bundler: not executable: #{cmd}" + exit 126 + rescue Errno::ENOENT + Bundler.ui.error "bundler: command not found: #{cmd}" + Bundler.ui.warn "Install missing gem executables with `bundle install`" + exit 127 + end + + def kernel_load(file, *args) + args.pop if args.last.is_a?(Hash) + ARGV.replace(args) + $0 = file + Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) + require_relative "../setup" + TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } + Kernel.load(file) + rescue SystemExit, SignalException + raise + rescue Exception # rubocop:disable Lint/RescueException + Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" + Bundler::FriendlyErrors.disable! + raise + end + + def process_title(file, args) + "#{file} #{args.join(" ")}".strip + end + + def explicit_path(path) + if File.absolute_path?(path) || explicit_relative_path?(path) + path + else + ".#{File::SEPARATOR}#{path}" + end + end + + def explicit_relative_path?(path) + [File::SEPARATOR, File::ALT_SEPARATOR].compact.any? do |separator| + path.start_with?(".#{separator}", "..#{separator}") + end + end + + def directly_loadable?(file) + if Gem.win_platform? + script_wrapper?(file) + else + ruby_shebang?(file) + end + end + + def script_wrapper?(file) + script_file = file.delete_suffix(".bat") + return false unless File.exist?(script_file) + + if File.zero?(script_file) + Bundler.ui.warn "#{script_file} is empty" + return false + end + + header = File.open(file, "r") {|f| f.read(32) } + ruby_exe = "#{RbConfig::CONFIG["RUBY_INSTALL_NAME"]}#{RbConfig::CONFIG["EXEEXT"]}" + ruby_exe = "ruby.exe" if ruby_exe.empty? + header.include?(ruby_exe) + end + + def ruby_shebang?(file) + possibilities = [ + "#!/usr/bin/env ruby\n", + "#!/usr/bin/env jruby\n", + "#!/usr/bin/env truffleruby\n", + "#!#{Gem.ruby}\n", + ] + + if File.zero?(file) + Bundler.ui.warn "#{file} is empty" + return false + end + + first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } + possibilities.any? {|shebang| first_line.start_with?(shebang) } + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/fund.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/fund.rb new file mode 100644 index 00000000..ad7f31f3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/fund.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Fund + attr_reader :options + + def initialize(options) + @options = options + end + + def run + Bundler.definition.validate_runtime! + + groups = Array(options[:group]).map(&:to_sym) + + deps = if groups.any? + Bundler.definition.dependencies_for(groups) + else + Bundler.definition.requested_dependencies + end + + fund_info = deps.each_with_object([]) do |dep, arr| + spec = Bundler.definition.specs[dep.name].first + if spec.metadata.key?("funding_uri") + arr << "* #{spec.name} (#{spec.version})\n Funding: #{spec.metadata["funding_uri"]}" + end + end + + if fund_info.empty? + Bundler.ui.info "None of the installed gems you directly depend on are looking for funding." + else + Bundler.ui.info fund_info.join("\n") + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/gem.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/gem.rb new file mode 100644 index 00000000..31948e49 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/gem.rb @@ -0,0 +1,492 @@ +# frozen_string_literal: true + +module Bundler + class CLI + Bundler.require_thor_actions + include Thor::Actions + end + + class CLI::Gem + TEST_FRAMEWORK_VERSIONS = { + "rspec" => "3.0", + "minitest" => "5.16", + "test-unit" => "3.0", + }.freeze + + DEFAULT_GITHUB_USERNAME = "[USERNAME]" + + attr_reader :options, :gem_name, :thor, :name, :target, :extension + + def initialize(options, gem_name, thor) + @options = options + @gem_name = resolve_name(gem_name) + + @thor = thor + thor.behavior = :invoke + thor.destination_root = nil + + @name = @gem_name + @target = Pathname.new(SharedHelpers.pwd).join(gem_name) + + @extension = options[:ext] + + validate_ext_name if @extension + end + + def run + Bundler.ui.confirm "Creating gem '#{name}'..." + + underscored_name = name.tr("-", "_") + namespaced_path = name.tr("-", "/") + constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } + constant_array = constant_name.split("::") + minitest_constant_name = constant_array.clone.tap {|a| a[-1] = "Test#{a[-1]}" }.join("::") # Foo::Bar => Foo::TestBar + + use_git = Bundler.git_present? && options[:git] + + git_author_name = use_git ? `git config user.name`.chomp : "" + git_username = use_git ? `git config github.user`.chomp : "" + git_user_email = use_git ? `git config user.email`.chomp : "" + github_username = github_username(git_username) + + if github_username.empty? + homepage_uri = "TODO: Put your gem's website or public repo URL here." + source_code_uri = "TODO: Put your gem's public repo URL here." + changelog_uri = "TODO: Put your gem's CHANGELOG.md URL here." + else + homepage_uri = "https://github.com/#{github_username}/#{name}" + source_code_uri = "https://github.com/#{github_username}/#{name}" + changelog_uri = "https://github.com/#{github_username}/#{name}/blob/main/CHANGELOG.md" + end + + config = { + name: name, + underscored_name: underscored_name, + namespaced_path: namespaced_path, + makefile_path: "#{underscored_name}/#{underscored_name}", + constant_name: constant_name, + constant_array: constant_array, + author: git_author_name.empty? ? "TODO: Write your name" : git_author_name, + email: git_user_email.empty? ? "TODO: Write your email address" : git_user_email, + test: options[:test], + ext: extension, + exe: options[:exe], + bundle: options[:bundle], + bundler_version: bundler_dependency_version, + git: use_git, + github_username: github_username.empty? ? DEFAULT_GITHUB_USERNAME : github_username, + required_ruby_version: required_ruby_version, + rust_builder_required_rubygems_version: rust_builder_required_rubygems_version, + minitest_constant_name: minitest_constant_name, + ignore_paths: %w[bin/], + homepage_uri: homepage_uri, + source_code_uri: source_code_uri, + changelog_uri: changelog_uri, + } + ensure_safe_gem_name(name, constant_array) + + templates = { + "Gemfile.tt" => Bundler.preferred_gemfile_name, + "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", + "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", + "sig/newgem.rbs.tt" => "sig/#{namespaced_path}.rbs", + "newgem.gemspec.tt" => "#{name}.gemspec", + "Rakefile.tt" => "Rakefile", + "README.md.tt" => "README.md", + "bin/console.tt" => "bin/console", + "bin/setup.tt" => "bin/setup", + } + + executables = %w[ + bin/console + bin/setup + ] + + case Bundler.preferred_gemfile_name + when "Gemfile" + config[:ignore_paths] << "Gemfile" + when "gems.rb" + config[:ignore_paths] << "gems.rb" + config[:ignore_paths] << "gems.locked" + end + + if use_git + templates.merge!("gitignore.tt" => ".gitignore") + config[:ignore_paths] << ".gitignore" + end + + if test_framework = ask_and_set_test_framework + config[:test] = test_framework + config[:test_framework_version] = TEST_FRAMEWORK_VERSIONS[test_framework] + + case test_framework + when "rspec" + templates.merge!( + "rspec.tt" => ".rspec", + "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", + "spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb" + ) + config[:test_task] = :spec + config[:ignore_paths] << ".rspec" + config[:ignore_paths] << "spec/" + when "minitest" + # Generate path for minitest target file (FileList["test/**/test_*.rb"]) + # foo => test/test_foo.rb + # foo-bar => test/foo/test_bar.rb + # foo_bar => test/test_foo_bar.rb + paths = namespaced_path.rpartition("/") + paths[2] = "test_#{paths[2]}" + minitest_namespaced_path = paths.join("") + + templates.merge!( + "test/minitest/test_helper.rb.tt" => "test/test_helper.rb", + "test/minitest/test_newgem.rb.tt" => "test/#{minitest_namespaced_path}.rb" + ) + config[:test_task] = :test + config[:ignore_paths] << "test/" + when "test-unit" + templates.merge!( + "test/test-unit/test_helper.rb.tt" => "test/test_helper.rb", + "test/test-unit/newgem_test.rb.tt" => "test/#{namespaced_path}_test.rb" + ) + config[:test_task] = :test + config[:ignore_paths] << "test/" + end + end + + config[:ci] = ask_and_set_ci + case config[:ci] + when "github" + templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml") + if extension == "rust" + templates.merge!("github/workflows/build-gems.yml.tt" => ".github/workflows/build-gems.yml") + end + config[:ignore_paths] << ".github/" + when "gitlab" + templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml") + config[:ignore_paths] << ".gitlab-ci.yml" + when "circle" + templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml") + config[:ignore_paths] << ".circleci/" + end + + if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", + "Using a MIT license means that any other developer or company will be legally allowed " \ + "to use your code for free as long as they admit you created it. You can read more about " \ + "the MIT license at https://choosealicense.com/licenses/mit.") + config[:mit] = true + Bundler.ui.info "MIT License enabled in config" + templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") + end + + if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", + "Codes of conduct can increase contributions to your project by contributors who " \ + "prefer safe, respectful, productive, and collaborative spaces. \n" \ + "See https://github.com/ruby/rubygems/blob/master/CODE_OF_CONDUCT.md") + config[:coc] = true + Bundler.ui.info "Code of conduct enabled in config" + templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") + end + + if ask_and_set(:changelog, "Do you want to include a changelog?", + "A changelog is a file which contains a curated, chronologically ordered list of notable " \ + "changes for each version of a project. To make it easier for users and contributors to" \ + " see precisely what notable changes have been made between each release (or version) of" \ + " the project. Whether consumers or developers, the end users of software are" \ + " human beings who care about what's in the software. When the software changes, people " \ + "want to know why and how. see https://keepachangelog.com") + config[:changelog] = true + Bundler.ui.info "Changelog enabled in config" + templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md") + end + + config[:linter] = ask_and_set_linter + case config[:linter] + when "rubocop" + config[:linter_version] = rubocop_version + Bundler.ui.info "RuboCop enabled in config" + templates.merge!("rubocop.yml.tt" => ".rubocop.yml") + config[:ignore_paths] << ".rubocop.yml" + when "standard" + config[:linter_version] = standard_version + Bundler.ui.info "Standard enabled in config" + templates.merge!("standard.yml.tt" => ".standard.yml") + config[:ignore_paths] << ".standard.yml" + end + + if config[:exe] + templates.merge!("exe/newgem.tt" => "exe/#{name}") + executables.push("exe/#{name}") + end + + if extension == "c" + templates.merge!( + "ext/newgem/extconf-c.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", + "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" + ) + end + + if extension == "rust" + templates.merge!( + "Cargo.toml.tt" => "Cargo.toml", + "ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml", + "ext/newgem/build.rs.tt" => "ext/#{name}/build.rs", + "ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs", + ) + end + + if extension == "go" + templates.merge!( + "ext/newgem/go.mod.tt" => "ext/#{name}/go.mod", + "ext/newgem/extconf-go.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", + "ext/newgem/newgem.go.tt" => "ext/#{name}/#{underscored_name}.go", + "ext/newgem/newgem-go.c.tt" => "ext/#{name}/#{underscored_name}.c", + ) + + config[:go_module_username] = config[:github_username] == DEFAULT_GITHUB_USERNAME ? "username" : config[:github_username] + end + + if target.exist? && !target.directory? + Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." + exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] + end + + if use_git + Bundler.ui.info "\nInitializing git repo in #{target}" + IO.popen(["git", "init", target.to_s], &:read) + + config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp + end + + templates.each do |src, dst| + destination = target.join(dst) + thor.template("newgem/#{src}", destination, config) + end + + executables.each do |file| + path = target.join(file) + executable = (path.stat.mode | 0o111) + path.chmod(executable) + end + + if use_git + IO.popen(%w[git add .], { chdir: target }, &:read) + end + + if config[:bundle] + Bundler.ui.info "Running bundle install in the new gem directory." + Dir.chdir(target) do + system("bundle install") + end + end + + # Open gemspec in editor + open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] + + Bundler.ui.info "\nGem '#{name}' was successfully created. " \ + "For more information on making a RubyGem visit https://guides.rubygems.org/make-your-own-gem/" + end + + private + + def resolve_name(name) + Pathname.new(SharedHelpers.pwd).join(name).basename.to_s + end + + def ask_and_set(key, prompt, explanation) + choice = options[key] + choice = Bundler.settings["gem.#{key}"] if choice.nil? + + if choice.nil? + Bundler.ui.info "\n#{explanation}" + choice = Bundler.ui.yes? "#{prompt} y/(n):" + Bundler.settings.set_global("gem.#{key}", choice) + end + + choice + end + + def validate_ext_name + return unless gem_name.index("-") + + Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ + "naming guidelines for C extensions. For more information, \n" \ + "see the 'Extension Naming' section at the following URL:\n" \ + "https://guides.rubygems.org/gems-with-extensions/\n" + exit 1 + end + + def ask_and_set_test_framework + return if skip?(:test) + test_framework = options[:test] || Bundler.settings["gem.test"] + + if test_framework.to_s.empty? + Bundler.ui.info "\nDo you want to generate tests with your gem?" + Bundler.ui.info hint_text("test") + + result = Bundler.ui.ask "Enter a test framework. rspec/minitest/test-unit/(none):" + if /rspec|minitest|test-unit/.match?(result) + test_framework = result + else + test_framework = false + end + end + + if Bundler.settings["gem.test"].nil? + Bundler.settings.set_global("gem.test", test_framework) + end + + if options[:test] == Bundler.settings["gem.test"] + Bundler.ui.info "#{options[:test]} is already configured, ignoring --test flag." + end + + test_framework + end + + def skip?(option) + options.key?(option) && options[option].nil? + end + + def hint_text(setting) + if Bundler.settings["gem.#{setting}"] == false + "Your choice will only be applied to this gem." + else + "Future `bundle gem` calls will use your choice. " \ + "This setting can be changed anytime with `bundle config gem.#{setting}`." + end + end + + def ask_and_set_ci + return if skip?(:ci) + ci_template = options[:ci] || Bundler.settings["gem.ci"] + + if ci_template.to_s.empty? + Bundler.ui.info "\nDo you want to set up continuous integration for your gem? " \ + "Supported services:\n" \ + "* CircleCI: https://circleci.com/\n" \ + "* GitHub Actions: https://github.com/features/actions\n" \ + "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" + Bundler.ui.info hint_text("ci") + + result = Bundler.ui.ask "Enter a CI service. github/gitlab/circle/(none):" + if /github|gitlab|circle/.match?(result) + ci_template = result + else + ci_template = false + end + end + + if Bundler.settings["gem.ci"].nil? + Bundler.settings.set_global("gem.ci", ci_template) + end + + if options[:ci] == Bundler.settings["gem.ci"] + Bundler.ui.info "#{options[:ci]} is already configured, ignoring --ci flag." + end + + ci_template + end + + def ask_and_set_linter + return if skip?(:linter) + linter_template = options[:linter] || Bundler.settings["gem.linter"] + + if linter_template.to_s.empty? + Bundler.ui.info "\nDo you want to add a code linter and formatter to your gem? " \ + "Supported Linters:\n" \ + "* RuboCop: https://rubocop.org\n" \ + "* Standard: https://github.com/standardrb/standard\n" + Bundler.ui.info hint_text("linter") + + result = Bundler.ui.ask "Enter a linter. rubocop/standard/(none):" + if /rubocop|standard/.match?(result) + linter_template = result + else + linter_template = false + end + end + + if Bundler.settings["gem.linter"].nil? + Bundler.settings.set_global("gem.linter", linter_template) + end + + # Once gem.linter safely set, unset the deprecated gem.rubocop + unless Bundler.settings["gem.rubocop"].nil? + Bundler.settings.set_global("gem.rubocop", nil) + end + + if options[:linter] == Bundler.settings["gem.linter"] + Bundler.ui.info "#{options[:linter]} is already configured, ignoring --linter flag." + end + + linter_template + end + + def bundler_dependency_version + v = Gem::Version.new(Bundler::VERSION) + req = v.segments[0..1] + req << "a" if v.prerelease? + req.join(".") + end + + def ensure_safe_gem_name(name, constant_array) + if /^\d/.match?(name) + Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." + exit 1 + end + + if /[A-Z]/.match?(name) + Bundler.ui.warn "Gem names with capital letters are not recommended. Please use only lowercase letters, numbers, and hyphens." + end + + constant_name = constant_array.join("::") + + existing_constant = constant_array.inject(Object) do |c, s| + defined = begin + c.const_defined?(s) + rescue NameError + Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name" + exit 1 + end + (defined && c.const_get(s)) || break + end + + return unless existing_constant + Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name." + exit 1 + end + + def open_editor(editor, file) + thor.run(%(#{editor} "#{file}")) + end + + def rust_builder_required_rubygems_version + "3.3.11" + end + + def required_ruby_version + "3.2.0" + end + + def rubocop_version + "1.21" + end + + def standard_version + "1.3" + end + + def github_username(git_username) + if options[:github_username].nil? + git_username + elsif options[:github_username] == false + "" + else + options[:github_username] + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/info.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/info.rb new file mode 100644 index 00000000..cd01d494 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/info.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Info + attr_reader :gem_name, :options + def initialize(options, gem_name) + @options = options + @gem_name = gem_name + end + + def run + Bundler.ui.silence do + Bundler.definition.validate_runtime! + Bundler.load.lock + end + + spec = spec_for_gem(gem_name) + + if spec + return print_gem_path(spec) if @options[:path] + return print_gem_version(spec) if @options[:version] + print_gem_info(spec) + end + end + + private + + def spec_for_gem(name) + Bundler::CLI::Common.select_spec(name, :regex_match) + end + + def print_gem_version(spec) + Bundler.ui.info spec.version.to_s + end + + def print_gem_path(spec) + name = spec.name + if name == "bundler" + path = File.expand_path("../../..", __dir__) + else + path = spec.full_gem_path + if spec.installation_missing? + return Bundler.ui.warn "The gem #{name} is missing. It should be installed at #{path}, but was not found" + end + end + + Bundler.ui.info path + end + + def print_gem_info(spec) + metadata = spec.metadata + name = spec.name + gem_info = String.new + gem_info << " * #{name} (#{spec.version}#{spec.git_version})\n" + gem_info << "\tSummary: #{spec.summary}\n" if spec.summary + gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage + gem_info << "\tDocumentation: #{metadata["documentation_uri"]}\n" if metadata.key?("documentation_uri") + gem_info << "\tSource Code: #{metadata["source_code_uri"]}\n" if metadata.key?("source_code_uri") + gem_info << "\tFunding: #{metadata["funding_uri"]}\n" if metadata.key?("funding_uri") + gem_info << "\tWiki: #{metadata["wiki_uri"]}\n" if metadata.key?("wiki_uri") + gem_info << "\tChangelog: #{metadata["changelog_uri"]}\n" if metadata.key?("changelog_uri") + gem_info << "\tBug Tracker: #{metadata["bug_tracker_uri"]}\n" if metadata.key?("bug_tracker_uri") + gem_info << "\tMailing List: #{metadata["mailing_list_uri"]}\n" if metadata.key?("mailing_list_uri") + gem_info << "\tPath: #{spec.full_gem_path}\n" + gem_info << "\tDefault Gem: yes\n" if spec.respond_to?(:default_gem?) && spec.default_gem? + gem_info << "\tReverse Dependencies: \n\t\t#{gem_dependencies.join("\n\t\t")}" if gem_dependencies.any? + + if name != "bundler" && spec.installation_missing? + return Bundler.ui.warn "The gem #{name} is missing. Gemspec information is still available though:\n#{gem_info}" + end + + Bundler.ui.info gem_info + end + + def gem_dependencies + @gem_dependencies ||= Bundler.definition.specs.filter_map do |spec| + dependency = spec.dependencies.find {|dep| dep.name == gem_name } + next unless dependency + "#{spec.name} (#{spec.version}) depends on #{gem_name} (#{dependency.requirements_list.join(", ")})" + end.sort + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/init.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/init.rb new file mode 100644 index 00000000..10a56866 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/init.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Init + attr_reader :options + def initialize(options) + @options = options + end + + def run + if File.exist?(gemfile) + Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" + exit 1 + end + + unless File.writable?(Dir.pwd) + Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." + exit 1 + end + + if options[:gemspec] + gemspec = File.expand_path(options[:gemspec]) + unless File.exist?(gemspec) + Bundler.ui.error "Gem specification #{gemspec} doesn't exist" + exit 1 + end + + spec = Bundler.load_gemspec_uncached(gemspec) + unless spec + Bundler.ui.error "Gem specification #{gemspec} did not produce a specification" + exit 1 + end + + File.open(gemfile, "wb") do |file| + file << "# Generated from #{gemspec}\n" + file << spec.to_gemfile + end + else + File.open(File.expand_path("../templates/Gemfile", __dir__), "r") do |template| + File.open(gemfile, "wb") do |destination| + IO.copy_stream(template, destination) + end + end + end + + puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" + end + + private + + def gemfile + @gemfile ||= options[:gemfile] || Bundler.preferred_gemfile_name + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/install.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/install.rb new file mode 100644 index 00000000..ab3e6f16 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/install.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Install + attr_reader :options + def initialize(options) + @options = options + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + + warn_if_root + + if options[:local] + Bundler.self_manager.restart_with_locked_bundler_if_needed + else + Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed + end + + Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Gem.freebsd_platform? + + if target_rbconfig_path = options[:"target-rbconfig"] + Bundler.rubygems.set_target_rbconfig(target_rbconfig_path) + end + + check_trust_policy + + if Bundler.frozen_bundle? && !Bundler.default_lockfile.exist? + flag = "deployment setting" if Bundler.settings[:deployment] + flag = "frozen setting" if Bundler.settings[:frozen] + raise ProductionError, "The #{flag} requires a lockfile. Please make " \ + "sure you have checked your #{SharedHelpers.relative_lockfile_path} into version control " \ + "before deploying." + end + + normalize_settings + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins] + + # For install we want to enable strict validation + # (rather than some optimizations we perform at app runtime). + definition = Bundler.definition(strict: true) + definition.validate_runtime! + definition.lockfile = options["lockfile"] if options["lockfile"] + definition.lockfile = false if options["no-lock"] + + installer = Installer.install(Bundler.root, definition, options) + + Bundler.settings.temporary(cache_all_platforms: options[:local] ? false : Bundler.settings[:cache_all_platforms]) do + Bundler.load.cache(nil, options[:local]) if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? + end + + Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." + Bundler::CLI::Common.output_without_groups_message(:install) + + if Bundler.use_system_gems? + Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." + else + relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd + Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" + end + + Bundler::CLI::Common.output_post_install_messages installer.post_install_messages + Bundler::CLI::Common.output_cooldown_skipped_summary(definition) + + if CLI::Common.clean_after_install? + require_relative "clean" + Bundler::CLI::Clean.new(options).run + end + + Bundler::CLI::Common.output_fund_metadata_summary + rescue Gem::InvalidSpecificationException + Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." + raise + end + + private + + def warn_if_root + return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? + Bundler.ui.warn "Don't run Bundler as root. Installing your bundle as root " \ + "will break this application for all non-root users on this machine.", wrap: true + end + + def dependencies_count_for(definition) + count = definition.dependencies.count + "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" + end + + def gems_installed_for(definition) + count = definition.specs.count {|spec| spec.name != "bundler" } + "#{count} #{count == 1 ? "gem" : "gems"} now installed" + end + + def check_trust_policy + trust_policy = options["trust-policy"] + unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) + raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ + "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." + end + Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy + end + + def normalize_settings + if options["standalone"] && Bundler.settings[:path].nil? && !options["local"] + Bundler.settings.set_command_option :path, "bundle" + end + + Bundler.settings.set_command_option_if_given :shebang, options["shebang"] + + Bundler.settings.set_command_option_if_given :jobs, options["jobs"] + + Bundler::CLI::Common.validate_cooldown!(options["cooldown"]) + Bundler.settings.set_command_option_if_given :cooldown, options["cooldown"] + + Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] + + Bundler.settings.set_command_option_if_given :no_install, options["no-install"] + + Bundler.settings.set_command_option_if_given :clean, options["clean"] + + options[:force] = options[:redownload] if options[:redownload] + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/issue.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/issue.rb new file mode 100644 index 00000000..332e41af --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/issue.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "rbconfig" + +module Bundler + class CLI::Issue + def run + Bundler.ui.info <<~EOS + Did you find an issue with Bundler? Before filing a new issue, + be sure to check out these resources: + + 1. Check out our troubleshooting guide for quick fixes to common issues: + https://github.com/ruby/rubygems/blob/master/doc/bundler/TROUBLESHOOTING.md + + 2. Instructions for common Bundler uses can be found on the documentation + site: https://guides.rubygems.org/ + + 3. Information about each Bundler command can be found in the Bundler + man pages: https://guides.rubygems.org/command-reference/bundle/ + + Hopefully the troubleshooting steps above resolved your problem! If things + still aren't working the way you expect them to, please let us know so + that we can diagnose and help fix the problem you're having, by filling + in the new issue form located at + https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md, + and copy and pasting the information below. + + EOS + + Bundler.ui.info Bundler::Env.report + + Bundler.ui.info "\n## Bundle Doctor" + doctor + end + + def doctor + require_relative "doctor/diagnose" + Bundler::CLI::Doctor::Diagnose.new({}).run + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/list.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/list.rb new file mode 100644 index 00000000..6a467f45 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/list.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require "json" + +module Bundler + class CLI::List + def initialize(options) + @options = options + @without_group = options["without-group"].map(&:to_sym) + @only_group = options["only-group"].map(&:to_sym) + @format = options["format"] + end + + def run + raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @only_group.any? && @without_group.any? + + raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] + + specs = if @only_group.any? || @without_group.any? + filtered_specs_by_groups + else + begin + Bundler.load.specs + rescue GemNotFound => e + Bundler.ui.error e.message + Bundler.ui.warn "Install missing gems with `bundle install`." + exit 1 + end + end.reject {|s| s.name == "bundler" }.sort_by(&:name) + + case @format + when "json" + print_json(specs: specs) + when nil + print_human(specs: specs) + else + raise InvalidOption, "Unknown option`--format=#{@format}`. Supported formats: `json`" + end + end + + private + + def print_json(specs:) + gems = if @options["name-only"] + specs.map {|s| { name: s.name } } + else + specs.map do |s| + { + name: s.name, + version: s.version.to_s, + git_version: s.git_version&.strip, + }.tap do |h| + h[:path] = s.full_gem_path if @options["paths"] + end + end + end + Bundler.ui.info({ gems: gems }.to_json) + end + + def print_human(specs:) + return Bundler.ui.info "No gems in the Gemfile" if specs.empty? + + return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] + return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] + + Bundler.ui.info "Gems included by the bundle:" + + specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } + + Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" + end + + def verify_group_exists(groups) + (@without_group + @only_group).each do |group| + raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) + end + end + + def filtered_specs_by_groups + definition = Bundler.definition + groups = definition.groups + + verify_group_exists(groups) + + show_groups = + if @without_group.any? + groups.reject {|g| @without_group.include?(g) } + elsif @only_group.any? + groups.select {|g| @only_group.include?(g) } + else + groups + end.map(&:to_sym) + + definition.specs_for(show_groups) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/lock.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/lock.rb new file mode 100644 index 00000000..dcb79068 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/lock.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Lock + attr_reader :options + + def initialize(options) + @options = options + end + + def run + unless Bundler.default_gemfile + Bundler.ui.error "Unable to find a Gemfile to lock" + exit 1 + end + + check_for_conflicting_options + + Bundler::CLI::Common.validate_cooldown!(options[:cooldown]) + Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown] + + print = options[:print] + previous_output_stream = Bundler.ui.output_stream + Bundler.ui.output_stream = :stderr if print + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + update = options[:update] + # --update is repeatable, so it parses as an array with one entry per + # occurrence, where a bare `--update` produces a `true` entry + update = update.include?(true) ? true : update.flatten if update.is_a?(Array) + conservative = options[:conservative] + bundler = options[:bundler] + + if update.is_a?(Array) # unlocking specific gems + Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) + update = { gems: update, conservative: conservative } + elsif update && conservative + update = { conservative: conservative } + elsif update && bundler + update = { bundler: bundler } + end + + Bundler.settings.temporary(frozen: false) do + definition = Bundler.definition(update, Bundler.default_lockfile) + definition.add_checksums if options["add-checksums"] + + Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update] + + options["remove-platform"].flatten.each do |platform_string| + platform = Gem::Platform.new(platform_string) + definition.remove_platform(platform) + end + + options["add-platform"].flatten.each do |platform_string| + platform = Gem::Platform.new(platform_string) + if platform.to_s == "unknown" + Bundler.ui.error "The platform `#{platform_string}` is unknown to RubyGems and can't be added to the lockfile." + exit 1 + end + definition.add_platform(platform) + end + + if definition.platforms.empty? + raise InvalidOption, "Removing all platforms from the bundle is not allowed" + end + + definition.remotely! unless options[:local] + + if options["normalize-platforms"] + definition.normalize_platforms + end + + if print + puts definition.to_lock + else + file = options[:lockfile] + file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile + + puts "Writing lockfile to #{file}" + definition.write_lock(file, false) + end + + Bundler::CLI::Common.output_cooldown_skipped_summary(definition) + end + + Bundler.ui.output_stream = previous_output_stream + end + + private + + def check_for_conflicting_options + if options["normalize-platforms"] && options["add-platform"].any? + raise InvalidOption, "--normalize-platforms can't be used with --add-platform" + end + + if options["normalize-platforms"] && options["remove-platform"].any? + raise InvalidOption, "--normalize-platforms can't be used with --remove-platform" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/open.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/open.rb new file mode 100644 index 00000000..64d44e6a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/open.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Open + attr_reader :options, :name, :path + def initialize(options, name) + @options = options + @name = name + @path = options[:path] unless options[:path].nil? + end + + def run + raise InvalidOption, "Cannot specify `--path` option without a value" if !@path.nil? && @path.empty? + editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } + return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor + return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) + if spec.default_gem? + Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist." + else + root_path = spec.full_gem_path + command = editor_command(editor) << File.join([root_path, path].compact) + Bundler.with_original_env do + system(*command, { chdir: root_path }) + end || Bundler.ui.info("Could not run '#{command.join(" ")}'") + end + end + + def editor_command(editor) + # On Windows an editor is often configured with a full path such as + # C:\Program Files\Microsoft VS Code\Code.exe, which shell splitting + # would corrupt. Take a value that names an existing file as a + # single word. + return [editor] if Gem.win_platform? && File.file?(editor) + + require "shellwords" + Shellwords.split(editor) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/outdated.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/outdated.rb new file mode 100644 index 00000000..8e566699 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/outdated.rb @@ -0,0 +1,367 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Outdated + attr_reader :options, :gems, :options_include_groups, :filter_options_patch, :sources, :strict + attr_accessor :outdated_gems + + def initialize(options, gems) + @options = options + @gems = gems + @sources = Array(options[:source]) + + @filter_options_patch = options.keys & %w[filter-major filter-minor filter-patch] + + @outdated_gems = [] + + @options_include_groups = [:group, :groups].any? do |v| + options.keys.include?(v.to_s) + end + + # the patch level options imply strict is also true. It wouldn't make + # sense otherwise. + @strict = options["filter-strict"] || Bundler::CLI::Common.patch_level_options(options).any? + end + + def run + check_for_deployment_mode! + + Bundler::CLI::Common.validate_cooldown!(options[:cooldown]) + Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown] + + Bundler.definition.validate_runtime! + current_specs = Bundler.ui.silence { Bundler.definition.resolve } + + gems.each do |gem_name| + if current_specs[gem_name].empty? + raise GemNotFound, "Could not find gem '#{gem_name}'." + end + end + + current_dependencies = Bundler.ui.silence do + Bundler.load.dependencies.map {|dep| [dep.name, dep] }.to_h + end + + definition = if gems.empty? && sources.empty? + # We're doing a full update + Bundler.definition(true) + else + Bundler.definition(gems: gems, sources: sources) + end + + Bundler::CLI::Common.configure_gem_version_promoter( + Bundler.definition, + options.merge(strict: @strict) + ) + + definition_resolution = proc do + options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! + end + + if options[:parseable] + Bundler.ui.progress(&definition_resolution) + else + definition_resolution.call + end + + Bundler.ui.info "" + + # Loop through the current specs + gemfile_specs, dependency_specs = current_specs.partition do |spec| + current_dependencies.key? spec.name + end + + specs = if options["only-explicit"] + gemfile_specs + else + gemfile_specs + dependency_specs + end + + specs.sort_by(&:name).uniq(&:name).each do |current_spec| + next unless gems.empty? || gems.include?(current_spec.name) + + active_spec = retrieve_active_spec(definition, current_spec) + next unless active_spec + + next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) + + gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) + next unless gem_outdated || (current_spec.git_version != active_spec.git_version) + + dependency = current_dependencies[current_spec.name] + groups = "" + if dependency && !options[:parseable] + groups = dependency.groups.join(", ") + end + + outdated_gems << { + active_spec: active_spec, + current_spec: current_spec, + dependency: dependency, + groups: groups, + } + end + + relevant_outdated_gems = if options_include_groups + outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| + contains_group = groups.split(", ").include?(options[:group]) + next unless options[:groups] || contains_group + + gems + end.compact + else + outdated_gems + end + + if relevant_outdated_gems.empty? + unless options[:parseable] + Bundler.ui.info(nothing_outdated_message) + end + else + if options[:parseable] + print_gems(relevant_outdated_gems) + else + print_gems_table(relevant_outdated_gems) + end + + exit 1 + end + end + + private + + def loaded_from_for(spec) + return unless spec.respond_to?(:loaded_from) + + spec.loaded_from + end + + def groups_text(group_text, groups) + "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" + end + + def nothing_outdated_message + if filter_options_patch.any? + display = filter_options_patch.map do |o| + o.sub("filter-", "") + end.join(" or ") + + "No #{display} updates to display.\n" + else + "Bundle up to date!\n" + end + end + + def retrieve_active_spec(definition, current_spec) + active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) + return unless active_spec + + return active_spec if strict + + matching_specs(active_spec, current_spec).last + end + + def matching_specs(active_spec, current_spec) + @matching_specs ||= {} + @matching_specs[[active_spec.source, current_spec.name, current_spec.platform]] ||= begin + active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.installable_on_platform?(current_spec.platform) }.sort_by(&:version) + if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 + active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } + end + active_specs + end + end + + # The newest version the cooldown setting would let bundler adopt right + # now, when the newest overall version is still inside the window. Only a + # version strictly between the installed one and the newest one is an + # adoptable update worth showing. + def newest_out_of_cooldown(active_spec, current_spec) + newest = matching_specs(active_spec, current_spec).reverse_each.find {|spec| cooldown_days_remaining(spec).nil? } + return unless newest + return if newest.version >= active_spec.version || newest.version <= current_spec.version + newest + end + + def print_gems(gems_list) + gems_list.each do |gem| + print_gem( + gem[:current_spec], + gem[:active_spec], + gem[:dependency], + gem[:groups], + ) + end + end + + def print_gems_table(gems_list) + data = gems_list.map do |gem| + gem_column_for( + gem[:current_spec], + gem[:active_spec], + gem[:dependency], + gem[:groups], + ) + end + + print_indented([table_header] + data) + end + + def print_gem(current_spec, active_spec, dependency, groups) + spec_version = "#{active_spec.version}#{active_spec.git_version}" + if Bundler.ui.debug? + loaded_from = loaded_from_for(active_spec) + spec_version += " (from #{loaded_from})" if loaded_from + end + current_version = "#{current_spec.version}#{current_spec.git_version}" + + if dependency&.specific? + dependency_version = %(, requested #{dependency.requirement}) + end + + spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ + "installed #{current_version}#{dependency_version}" + + release_date = release_date_for(active_spec) + spec_outdated_info += ", released #{release_date}" unless release_date.empty? + + remaining = cooldown_days_remaining(active_spec) + if remaining + spec_outdated_info += ", in cooldown for #{remaining} more day#{"s" if remaining > 1}" + adoptable = newest_out_of_cooldown(active_spec, current_spec) + spec_outdated_info += ", newest out of cooldown #{adoptable.version}" if adoptable + end + + spec_outdated_info += ")" + + output_message = if options[:parseable] + spec_outdated_info.to_s + elsif options_include_groups || groups.empty? + " * #{spec_outdated_info}" + else + " * #{spec_outdated_info} in #{groups_text("group", groups)}" + end + + Bundler.ui.info output_message.rstrip + end + + def gem_column_for(current_spec, active_spec, dependency, groups) + current_version = "#{current_spec.version}#{current_spec.git_version}" + spec_version = "#{active_spec.version}#{active_spec.git_version}" + remaining = cooldown_days_remaining(active_spec) + if remaining + adoptable = newest_out_of_cooldown(active_spec, current_spec) + adoptable_note = adoptable ? ", #{adoptable.version} out of cooldown" : "" + spec_version += " (cooldown #{remaining}d#{adoptable_note})" + end + dependency = dependency.requirement if dependency + + ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] + ret_val << release_date_for(active_spec) + ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug? + ret_val + end + + def cooldown_days_remaining(spec, now = cooldown_now) + return nil unless spec.respond_to?(:created_at) && spec.created_at + return nil unless spec.respond_to?(:remote) && spec.remote + days = spec.remote.effective_cooldown + return nil if days.nil? || days <= 0 + remaining = days - ((now - spec.created_at) / 86_400.0) + remaining > 0 ? remaining.ceil : nil + end + + def cooldown_now + @cooldown_now ||= Time.now + end + + def check_for_deployment_mode! + return unless Bundler.frozen_bundle? + suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? + "bundle config unset frozen" + elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? + "bundle config unset deployment" + end + raise ProductionError, "You are trying to check outdated gems in " \ + "deployment mode. Run `bundle outdated` elsewhere.\n" \ + "\nIf this is a development machine, remove the " \ + "#{Bundler.default_gemfile} freeze" \ + "\nby running `#{suggested_command}`." + end + + def update_present_via_semver_portions(current_spec, active_spec, options) + current_major = current_spec.version.segments.first + active_major = active_spec.version.segments.first + + update_present = false + update_present = active_major > current_major if options["filter-major"] + + if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major + current_minor = get_version_semver_portion_value(current_spec, 1) + active_minor = get_version_semver_portion_value(active_spec, 1) + + update_present = active_minor > current_minor if options["filter-minor"] + + if !update_present && options["filter-patch"] && current_minor == active_minor + current_patch = get_version_semver_portion_value(current_spec, 2) + active_patch = get_version_semver_portion_value(active_spec, 2) + + update_present = active_patch > current_patch + end + end + + update_present + end + + def get_version_semver_portion_value(spec, version_portion_index) + version_section = spec.version.segments[version_portion_index, 1] + version_section.to_a[0].to_i + end + + def print_indented(matrix) + header = matrix[0] + data = matrix[1..-1] + + column_sizes = Array.new(header.size) do |index| + matrix.max_by {|row| row[index].length }[index].length + end + + Bundler.ui.info justify(header, column_sizes) + + data.sort_by! {|row| row[0] } + + data.each do |row| + Bundler.ui.info justify(row, column_sizes) + end + end + + def table_header + header = ["Gem", "Current", "Latest", "Requested", "Groups", "Release Date"] + header << "Path" if Bundler.ui.debug? + header + end + + def release_date_for(spec) + return "" unless spec.respond_to?(:date) + + date = spec.date + return "" unless date + + return "" unless Gem.const_defined?(:DEFAULT_SOURCE_DATE_EPOCH) + default_date = Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc + default_date = Time.utc(default_date.year, default_date.month, default_date.day) + + date = date.utc if date.respond_to?(:utc) + + return "" if date == default_date + + date.strftime("%Y-%m-%d") + end + + def justify(row, sizes) + row.each_with_index.map do |element, index| + element.ljust(sizes[index]) + end.join(" ").strip + "\n" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/platform.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/platform.rb new file mode 100644 index 00000000..32d68abb --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/platform.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Platform + attr_reader :options + def initialize(options) + @options = options + end + + def run + ruby_version = if Bundler.locked_gems + Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "") + else + Bundler.definition.ruby_version&.single_version_string + end + + output = [] + + if options[:ruby] + if ruby_version + output << ruby_version + else + output << "No ruby version specified" + end + else + platforms = Bundler.definition.platforms.map {|p| "* #{p}" } + + output << "Your platform is: #{Gem::Platform.local}" + output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" + + if ruby_version + output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" + + begin + Bundler.definition.validate_runtime! + output << "Your current platform satisfies the Ruby version requirement." + rescue RubyVersionMismatch => e + output << e.message + end + else + output << "Your Gemfile does not specify a Ruby version requirement." + end + end + + Bundler.ui.info output.join("\n\n") + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/plugin.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/plugin.rb new file mode 100644 index 00000000..32fa660f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/plugin.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require_relative "../vendored_thor" +module Bundler + class CLI::Plugin < Thor + desc "install PLUGINS", "Install the plugin from the source" + long_desc <<-D + Install plugins either from the rubygems source provided (with --source option), from a git source provided with --git, or a local path provided with --path. If no sources are provided, it uses Gem.sources + D + method_option "source", type: :string, default: nil, banner: "URL of the RubyGems source to fetch the plugin from" + method_option "version", type: :string, default: nil, banner: "The version of the plugin to fetch" + method_option "git", type: :string, default: nil, banner: "URL of the git repo to fetch from" + method_option "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (removed)" + method_option "branch", type: :string, default: nil, banner: "The git branch to checkout" + method_option "ref", type: :string, default: nil, banner: "The git revision to check out" + method_option "path", type: :string, default: nil, banner: "Path of a local gem to directly use" + def install(*plugins) + if options.key?(:local_git) + raise InvalidOption, "--local_git has been removed, use --git" + end + + Bundler::Plugin.install(plugins, options) + end + + desc "uninstall PLUGINS", "Uninstall the plugins" + long_desc <<-D + Uninstall given list of plugins. To uninstall all the plugins, use -all option. + D + method_option "all", type: :boolean, default: nil, banner: "Uninstall all the installed plugins. If no plugin is installed, then it does nothing." + def uninstall(*plugins) + Bundler::Plugin.uninstall(plugins, options) + end + + desc "list", "List the installed plugins and available commands" + def list + Bundler::Plugin.list + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/pristine.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/pristine.rb new file mode 100644 index 00000000..f463f0bc --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/pristine.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Pristine + def initialize(gems) + @gems = gems + end + + def run + CLI::Common.ensure_all_gems_in_lockfile!(@gems) + definition = Bundler.definition + definition.validate_runtime! + installer = Bundler::Installer.new(Bundler.root, definition) + git_sources = [] + + ProcessLock.lock do + installed_specs = definition.specs.reject do |spec| + next if spec.name == "bundler" # Source::Rubygems doesn't install bundler + next if !@gems.empty? && !@gems.include?(spec.name) + + gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" + gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY + + case source = spec.source + when Source::Rubygems + cached_gem = spec.cache_file + unless File.exist?(cached_gem) + Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") + next + end + + FileUtils.rm_rf spec.full_gem_path + when Source::Git + if source.local? + Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.") + next + end + + source.remote! + if extension_cache_path = source.extension_cache_path(spec) + FileUtils.rm_rf extension_cache_path + end + FileUtils.rm_rf spec.extension_dir + FileUtils.rm_rf spec.full_gem_path + + next if git_sources.include?(source) + git_sources << source + else + Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") + next + end + + true + end.map(&:name) + + jobs = Bundler.settings.installation_parallelization + pristine_count = definition.specs.count - installed_specs.count + # allow a pristining a single gem to skip the parallel worker + jobs = [jobs, pristine_count].min + ParallelInstaller.call(installer, definition.specs, jobs, false, true, skip: installed_specs) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/remove.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/remove.rb new file mode 100644 index 00000000..44a4d891 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/remove.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Remove + def initialize(gems, options) + @gems = gems + @options = options + end + + def run + raise InvalidOption, "Please specify gems to remove." if @gems.empty? + + Injector.remove(@gems, {}) + Installer.install(Bundler.root, Bundler.definition) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/show.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/show.rb new file mode 100644 index 00000000..67fdcc79 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/show.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Show + attr_reader :options, :gem_name, :latest_specs + def initialize(options, gem_name) + @options = options + @gem_name = gem_name + @verbose = options[:verbose] + @latest_specs = fetch_latest_specs if @verbose + end + + def run + Bundler.ui.silence do + Bundler.definition.validate_runtime! + Bundler.load.lock + end + + if gem_name + if gem_name == "bundler" + path = File.expand_path("../../..", __dir__) + else + spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) + return unless spec + path = spec.full_gem_path + unless File.directory?(path) + return Bundler.ui.warn "The gem #{gem_name} is missing. It should be installed at #{path}, but was not found" + end + end + return Bundler.ui.info(path) + end + + if options[:paths] + Bundler.load.specs.sort_by(&:name).map do |s| + Bundler.ui.info s.full_gem_path + end + else + Bundler.ui.info "Gems included by the bundle:" + Bundler.load.specs.sort_by(&:name).each do |s| + desc = " * #{s.name} (#{s.version}#{s.git_version})" + if @verbose + latest = latest_specs.find {|l| l.name == s.name } + Bundler.ui.info <<~END + #{desc.lstrip} + \tSummary: #{s.summary || "No description available."} + \tHomepage: #{s.homepage || "No website available."} + \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} + END + else + Bundler.ui.info desc + end + end + end + end + + private + + def fetch_latest_specs + definition = Bundler.definition(true) + Bundler.ui.info "Fetching remote specs for outdated check...\n\n" + Bundler.ui.silence { definition.remotely! } + Bundler.reset! + definition.specs + end + + def outdated?(current, latest) + return false unless latest + Gem::Version.new(current.version) < Gem::Version.new(latest.version) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/cli/update.rb b/bin/gems/bundler-4.0.21/lib/bundler/cli/update.rb new file mode 100644 index 00000000..23c19896 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/cli/update.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +module Bundler + class CLI::Update + attr_reader :options, :gems + def initialize(options, gems) + @options = options + @gems = gems + end + + def run + Bundler.ui.level = "warn" if options[:quiet] + + update_bundler = options[:bundler] + + Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler, pre: options[:pre]) if update_bundler + + Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins] + + sources = Array(options[:source]) + groups = Array(options[:group]).map(&:to_sym) + + full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler + + if full_update && !options[:all] + if Bundler.settings[:update_requires_all_flag] + raise InvalidOption, "To update everything, pass the `--all` flag." + end + SharedHelpers.feature_deprecated! "Pass --all to `bundle update` to update everything" + elsif !full_update && options[:all] + raise InvalidOption, "Cannot specify --all along with specific options." + end + + conservative = options[:conservative] + + if full_update + if conservative + Bundler.definition(conservative: conservative) + else + Bundler.definition(true) + end + else + unless Bundler.default_lockfile.exist? + raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ + "Run `bundle install` to update and install the bundled gems." + end + Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) + + if groups.any? + deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } + gems.concat(deps.map(&:name)) + end + + Bundler.definition(gems: gems, sources: sources, ruby: options[:ruby], + conservative: conservative, + bundler: update_bundler) + end + + Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) + + Bundler::Fetcher.disable_endpoint = options["full-index"] + + opts = options.dup + opts["update"] = true + opts["local"] = options[:local] + opts["force"] = options[:redownload] if options[:redownload] + + Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] + Bundler::CLI::Common.validate_cooldown!(options[:cooldown]) + Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown] + + Bundler.definition.validate_runtime! + + if locked_gems = Bundler.definition.locked_gems + previous_locked_info = locked_gems.specs.reduce({}) do |h, s| + h[s.name] = { spec: s, version: s.version, source: s.source.identifier } + h + end + end + + installer = Installer.install Bundler.root, Bundler.definition, opts + Bundler.load.cache if Bundler.app_cache.exist? + + if CLI::Common.clean_after_install? + require_relative "clean" + Bundler::CLI::Clean.new(options).run + end + + if locked_gems + gems.each do |name| + locked_info = previous_locked_info[name] + next unless locked_info + + locked_spec = locked_info[:spec] + new_spec = Bundler.definition.specs[name].first + unless new_spec + unless locked_spec.installable_on_platform?(Bundler.local_platform) + Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one" + end + + next + end + + locked_source = locked_info[:source] + new_source = new_spec.source.identifier + next if locked_source != new_source + + new_version = new_spec.version + locked_version = locked_info[:version] + if new_version < locked_version + Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" + elsif new_version == locked_version + Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" + end + end + end + + Bundler.ui.confirm "Bundle updated!" + Bundler::CLI::Common.output_without_groups_message(:update) + Bundler::CLI::Common.output_post_install_messages installer.post_install_messages + Bundler::CLI::Common.output_cooldown_skipped_summary + + Bundler::CLI::Common.output_fund_metadata_summary + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client.rb b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client.rb new file mode 100644 index 00000000..6865e30d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require "set" + +module Bundler + # The CompactIndexClient is responsible for fetching and parsing the compact index. + # + # The compact index is a set of caching optimized files that are used to fetch gem information. + # The files are: + # - names: a list of all gem names + # - versions: a list of all gem versions + # - info/[gem]: a list of all versions of a gem + # + # The client is instantiated with: + # - `directory`: the root directory where the cache files are stored. + # - `fetcher`: (optional) an object that responds to #call(uri_path, headers) and returns an http response. + # If the `fetcher` is not provided, the client will only read cached files from disk. + # + # The client is organized into: + # - `Updater`: updates the cached files on disk using the fetcher. + # - `Cache`: calls the updater, caches files, read and return them from disk + # - `Parser`: parses the compact index file data + # - `CacheFile`: a concurrency safe file reader/writer that verifies checksums + # + # The client is intended to optimize memory usage and performance. + # It is called 100s or 1000s of times, parsing files with hundreds of thousands of lines. + # It may be called concurrently without global interpreter lock in some Rubies. + # As a result, some methods may look more complex than necessary to save memory or time. + class CompactIndexClient + SUPPORTED_DIGESTS = { "sha-256" => :SHA256 }.freeze + DEBUG_MUTEX = Thread::Mutex.new + + # info returns an Array of INFO Arrays. Each INFO Array has the following indices: + INFO_NAME = 0 + INFO_VERSION = 1 + INFO_PLATFORM = 2 + INFO_DEPS = 3 + INFO_REQS = 4 + + def self.debug + return unless ENV["DEBUG_COMPACT_INDEX"] + DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } + end + + class Error < StandardError; end + + require_relative "compact_index_client/cache" + require_relative "compact_index_client/cache_file" + require_relative "compact_index_client/parser" + require_relative "compact_index_client/updater" + + def initialize(directory, fetcher = nil) + @cache = Cache.new(directory, fetcher) + @parser = Parser.new(@cache) + end + + def names + Bundler::CompactIndexClient.debug { "names" } + @parser.names + end + + def versions + Bundler::CompactIndexClient.debug { "versions" } + @parser.versions + end + + def dependencies(names) + Bundler::CompactIndexClient.debug { "dependencies(#{names})" } + names.map {|name| info(name) } + end + + def info(name) + Bundler::CompactIndexClient.debug { "info(#{name})" } + @parser.info(name) + end + + def latest_version(name) + Bundler::CompactIndexClient.debug { "latest_version(#{name})" } + @parser.info(name).map {|d| Gem::Version.new(d[INFO_VERSION]) }.max + end + + def available? + Bundler::CompactIndexClient.debug { "available?" } + @parser.available? + end + + def reset! + Bundler::CompactIndexClient.debug { "reset!" } + @cache.reset! + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache.rb b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache.rb new file mode 100644 index 00000000..c47535a0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require "rubygems/resolver/api_set/gem_parser" + +module Bundler + class CompactIndexClient + class Cache + attr_reader :directory + + def initialize(directory, fetcher = nil) + @directory = Pathname.new(directory).expand_path + @updater = Updater.new(fetcher) if fetcher + @mutex = Thread::Mutex.new + @endpoints = Set.new + + @info_root = mkdir("info") + @special_characters_info_root = mkdir("info-special-characters") + @info_etag_root = mkdir("info-etags") + end + + def names + fetch("names", names_path, names_etag_path) + end + + def versions + fetch("versions", versions_path, versions_etag_path) + end + + def info(name, remote_checksum = nil) + path = info_path(name) + + if remote_checksum && remote_checksum != SharedHelpers.checksum_for_file(path, :MD5) + fetch("info/#{name}", path, info_etag_path(name)) + else + Bundler::CompactIndexClient.debug { "update skipped info/#{name} (#{remote_checksum ? "versions index checksum is nil" : "versions index checksum matches local"})" } + read(path) + end + end + + def reset! + @mutex.synchronize { @endpoints.clear } + end + + private + + def names_path = directory.join("names") + def names_etag_path = directory.join("names.etag") + def versions_path = directory.join("versions") + def versions_etag_path = directory.join("versions.etag") + + def info_path(name) + name = name.to_s + validate_name!(name) + # TODO: converge this into the info_root by hashing all filenames like info_etag_path + if /[^a-z0-9_-]/.match?(name) + name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" + @special_characters_info_root.join(name) + else + @info_root.join(name) + end + end + + def info_etag_path(name) + name = name.to_s + validate_name!(name) + @info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}") + end + + # Gem names come from the remote index and are not otherwise + # validated, so refuse anything that would escape the cache + # directory when used as a path component. + def validate_name!(name) + return if File.basename(name) == name + + raise SecurityError, "malformed gem name: #{name.inspect}" + end + + def mkdir(name) + directory.join(name).tap do |dir| + SharedHelpers.filesystem_access(dir) do + FileUtils.mkdir_p(dir) + end + end + end + + def fetch(remote_path, path, etag_path) + if already_fetched?(remote_path) + Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } + else + Bundler::CompactIndexClient.debug { "fetching #{remote_path}" } + @updater&.update(remote_path, path, etag_path) + end + + read(path) + end + + def already_fetched?(remote_path) + @mutex.synchronize { !@endpoints.add?(remote_path) } + end + + def read(path) + return unless path.file? + SharedHelpers.filesystem_access(path, :read, &:read) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache_file.rb b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache_file.rb new file mode 100644 index 00000000..03659aea --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/cache_file.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require_relative "../vendored_fileutils" +require "rubygems/package" + +module Bundler + class CompactIndexClient + # write cache files in a way that is robust to concurrent modifications + # if digests are given, the checksums will be verified + class CacheFile + DEFAULT_FILE_MODE = 0o644 + private_constant :DEFAULT_FILE_MODE + + class Error < RuntimeError; end + class ClosedError < Error; end + + class DigestMismatchError < Error + def initialize(digests, expected_digests) + super "Calculated checksums #{digests.inspect} did not match expected #{expected_digests.inspect}." + end + end + + # Initialize with a copy of the original file, then yield the instance. + def self.copy(path, &block) + new(path) do |file| + file.initialize_digests + + SharedHelpers.filesystem_access(path, :read) do + path.open("rb") do |s| + file.open {|f| IO.copy_stream(s, f) } + end + end + + yield file + end + end + + # Write data to a temp file, then replace the original file with it verifying the digests if given. + def self.write(path, data, digests = nil) + return unless data + new(path) do |file| + file.digests = digests + file.write(data) + end + end + + attr_reader :original_path, :path + + def initialize(original_path, &block) + @original_path = original_path + @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE + @path = original_path.sub(/$/, ".#{$$}.tmp") + return unless block_given? + begin + yield self + ensure + close + end + end + + def size + path.size + end + + # initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys. + def initialize_digests(keys = nil) + @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup + @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new } + end + + # reset the digests so they don't contain any previously read data + def reset_digests + @digests&.each_value(&:reset) + end + + # set the digests that will be verified at the end + def digests=(expected_digests) + @expected_digests = expected_digests + + if @expected_digests.nil? + @digests = nil + elsif @digests + @digests = @digests.slice(*@expected_digests.keys) + else + initialize_digests(@expected_digests.keys) + end + end + + def digests? + @digests&.any? + end + + # Open the temp file for writing, reusing original permissions, yielding the IO object. + def open(write_mode = "wb", perm = @perm, &block) + raise ClosedError, "Cannot reopen closed file" if @closed + SharedHelpers.filesystem_access(path, :write) do + path.open(write_mode, perm) do |f| + yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f + end + end + end + + # Returns false without appending when no digests since appending is too error prone to do without digests. + def append(data) + return false unless digests? + open("ab") {|f| f.write data } + verify && commit + end + + def write(data) + reset_digests + open {|f| f.write data } + commit! + end + + def commit! + verify || raise(DigestMismatchError.new(@base64digests, @expected_digests)) + commit + end + + # Verify the digests, returning true on match, false on mismatch. + def verify + return true unless @expected_digests && digests? + @base64digests = @digests.transform_values!(&:base64digest) + @digests = nil + @base64digests.all? {|algo, digest| @expected_digests[algo] == digest } + end + + # Replace the original file with the temp file without verifying digests. + # The file is permanently closed. + def commit + raise ClosedError, "Cannot commit closed file" if @closed + SharedHelpers.filesystem_access(original_path, :write) do + FileUtils.mv(path, original_path) + end + @closed = true + end + + # Remove the temp file without replacing the original file. + # The file is permanently closed. + def close + return if @closed + FileUtils.remove_file(path) if @path&.file? + @closed = true + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/parser.rb b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/parser.rb new file mode 100644 index 00000000..ad0d17ed --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/parser.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Bundler + class CompactIndexClient + class Parser + # `compact_index` - an object responding to #names, #versions, #info(name, checksum), + # returning the file contents as a string + def initialize(compact_index) + @compact_index = compact_index + @info_checksums = nil + @versions_by_name = nil + @available = nil + @gem_parser = nil + end + + def names + lines(@compact_index.names) + end + + def versions + @versions_by_name ||= Hash.new {|hash, key| hash[key] = [] } + @info_checksums = {} + + lines(@compact_index.versions).each do |line| + name, versions_string, checksum = line.split(" ", 3) + @info_checksums[name] = checksum || "" + versions_string.split(",") do |version| + delete = version.delete_prefix!("-") + version = version.split("-", 2).unshift(name) + if delete + @versions_by_name[name].delete(version) + else + @versions_by_name[name] << version + end + end + end + + @versions_by_name + end + + def info(name) + data = @compact_index.info(name, info_checksums[name]) + lines(data).map {|line| gem_parser.parse(line).unshift(name) } + end + + def available? + return @available unless @available.nil? + @available = !info_checksums.empty? + end + + private + + def info_checksums + @info_checksums ||= lines(@compact_index.versions).each_with_object({}) do |line, checksums| + parse_version_checksum(line, checksums) + end + end + + def lines(data) + return [] if data.nil? || data.empty? + lines = data.split("\n") + header = lines.index("---") + header ? lines[header + 1..-1] : lines + end + + def gem_parser + @gem_parser ||= Gem::Resolver::APISet::GemParser.new + end + + # This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects. + # This method gets called at least once for every gem when parsing versions. + def parse_version_checksum(line, checksums) + return unless (name_end = line.index(" ")) # Artifactory bug causes blank lines in artifactor index files + checksum_start = line.index(" ", name_end + 1) + return unless checksum_start + checksum_start += 1 + + checksum_end = line.size - checksum_start + + line.freeze # allows slicing into the string to not allocate a copy of the line + name = line[0, name_end] + checksum = line[checksum_start, checksum_end] + checksums[name.freeze] = checksum # freeze name since it is used as a hash key + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/updater.rb b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/updater.rb new file mode 100644 index 00000000..6066fdc7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/compact_index_client/updater.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +module Bundler + class CompactIndexClient + class Updater + class MismatchedChecksumError < Error + def initialize(path, message) + super "The checksum of /#{path} does not match the checksum provided by the server! Something is wrong. #{message}" + end + end + + def initialize(fetcher) + @fetcher = fetcher + end + + def update(remote_path, local_path, etag_path) + append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path) + rescue CacheFile::DigestMismatchError => e + raise MismatchedChecksumError.new(remote_path, e.message) + rescue Zlib::GzipFile::Error + raise Bundler::HTTPError + end + + private + + def append(remote_path, local_path, etag_path) + return false unless local_path.file? && local_path.size.nonzero? + + CacheFile.copy(local_path) do |file| + etag = etag_path.read.tap(&:chomp!) if etag_path.file? + + # Subtract a byte to ensure the range won't be empty. + # Avoids 416 (Range Not Satisfiable) responses. + response = @fetcher.call(remote_path, request_headers(etag, file.size - 1)) + break true if response.is_a?(Gem::Net::HTTPNotModified) + + file.digests = parse_digests(response) + # server may ignore Range and return the full response + if response.is_a?(Gem::Net::HTTPPartialContent) + tail = response.body.byteslice(1..-1) + break false unless tail && file.append(tail) + else + file.write(response.body) + end + CacheFile.write(etag_path, etag_from_response(response)) + true + end + end + + # request without range header to get the full file or a 304 Not Modified + def replace(remote_path, local_path, etag_path) + etag = etag_path.read.tap(&:chomp!) if etag_path.file? + response = @fetcher.call(remote_path, request_headers(etag)) + return true if response.is_a?(Gem::Net::HTTPNotModified) + CacheFile.write(local_path, response.body, parse_digests(response)) + CacheFile.write(etag_path, etag_from_response(response)) + end + + def request_headers(etag, range_start = nil) + headers = {} + headers["Range"] = "bytes=#{range_start}-" if range_start + headers["If-None-Match"] = %("#{etag}") if etag + headers + end + + def etag_for_request(etag_path) + etag_path.read.tap(&:chomp!) if etag_path.file? + end + + def etag_from_response(response) + return unless response["ETag"] + etag = response["ETag"].delete_prefix("W/") + return if etag.delete_prefix!('"') && !etag.delete_suffix!('"') + etag + end + + # Unwraps and returns a Hash of digest algorithms and base64 values + # according to RFC 8941 Structured Field Values for HTTP. + # https://www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence + # Ignores unsupported algorithms. + def parse_digests(response) + return unless header = response["Repr-Digest"] || response["Digest"] + digests = {} + header.split(",") do |param| + algorithm, value = param.split("=", 2) + algorithm.strip! + algorithm.downcase! + next unless SUPPORTED_DIGESTS.key?(algorithm) + next unless value = byte_sequence(value) + digests[algorithm] = value + end + digests.empty? ? nil : digests + end + + # Unwrap surrounding colons (byte sequence) + # The wrapping characters must be matched or we return nil. + # Also handles quotes because right now rubygems.org sends them. + def byte_sequence(value) + return if value.delete_prefix!(":") && !value.delete_suffix!(":") + return if value.delete_prefix!('"') && !value.delete_suffix!('"') + value + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/constants.rb b/bin/gems/bundler-4.0.21/lib/bundler/constants.rb new file mode 100644 index 00000000..9564771e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/constants.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "rbconfig" + +module Bundler + WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ + deprecate_constant :WINDOWS + + FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd") + deprecate_constant :FREEBSD + + NULL = File::NULL + deprecate_constant :NULL +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/current_ruby.rb b/bin/gems/bundler-4.0.21/lib/bundler/current_ruby.rb new file mode 100644 index 00000000..17c7655a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/current_ruby.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require_relative "rubygems_ext" + +module Bundler + # Returns current version of Ruby + # + # @return [CurrentRuby] Current version of Ruby + def self.current_ruby + @current_ruby ||= CurrentRuby.new + end + + class CurrentRuby + ALL_RUBY_VERSIONS = [*18..27, *30..34, *40..41].freeze + KNOWN_MINOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.reverse.join(".") }.freeze + KNOWN_MAJOR_VERSIONS = ALL_RUBY_VERSIONS.map {|v| v.digits.last.to_s }.uniq.freeze + PLATFORM_MAP = { + ruby: [Gem::Platform::RUBY, CurrentRuby::ALL_RUBY_VERSIONS], + mri: [Gem::Platform::RUBY, CurrentRuby::ALL_RUBY_VERSIONS], + rbx: [Gem::Platform::RUBY], + truffleruby: [Gem::Platform::RUBY], + jruby: [Gem::Platform::JAVA, [18, 19]], + windows: [Gem::Platform::WINDOWS, CurrentRuby::ALL_RUBY_VERSIONS], + # deprecated + mswin: [Gem::Platform::MSWIN, CurrentRuby::ALL_RUBY_VERSIONS], + mswin64: [Gem::Platform::MSWIN64, CurrentRuby::ALL_RUBY_VERSIONS - [18]], + mingw: [Gem::Platform::UNIVERSAL_MINGW, CurrentRuby::ALL_RUBY_VERSIONS], + x64_mingw: [Gem::Platform::UNIVERSAL_MINGW, CurrentRuby::ALL_RUBY_VERSIONS - [18, 19]], + }.each_with_object({}) do |(platform, spec), hash| + hash[platform] = spec[0] + spec[1]&.each {|version| hash[:"#{platform}_#{version}"] = spec[0] } + end.freeze + + def ruby? + return true if Bundler::MatchPlatform.generic_local_platform_is_ruby? + + !windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby") + end + + def mri? + !windows? && RUBY_ENGINE == "ruby" + end + + def rbx? + ruby? && RUBY_ENGINE == "rbx" + end + + def jruby? + RUBY_ENGINE == "jruby" + end + + def maglev? + removed_message = + "`CurrentRuby#maglev?` was removed with no replacement. Please use the " \ + "built-in Ruby `RUBY_ENGINE` constant to check the Ruby implementation you are running on." + SharedHelpers.feature_removed!(removed_message) + end + + def truffleruby? + RUBY_ENGINE == "truffleruby" + end + + def windows? + Gem.win_platform? + end + alias_method :mswin?, :windows? + alias_method :mswin64?, :windows? + alias_method :mingw?, :windows? + alias_method :x64_mingw?, :windows? + + (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| + trimmed_version = version.tr(".", "") + define_method(:"on_#{trimmed_version}?") do + RUBY_VERSION.start_with?("#{version}.") + end + + PLATFORM_MAP.keys.each do |platform| + define_method(:"#{platform}_#{trimmed_version}?") do + send(:"#{platform}?") && send(:"on_#{trimmed_version}?") + end + end + + define_method(:"maglev_#{trimmed_version}?") do + removed_message = + "`CurrentRuby##{__method__}` was removed with no replacement. Please use the " \ + "built-in Ruby `RUBY_ENGINE` and `RUBY_VERSION` constants to perform a similar check." + + SharedHelpers.feature_removed!(removed_message) + + send(:"maglev?") && send(:"on_#{trimmed_version}?") + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/definition.rb b/bin/gems/bundler-4.0.21/lib/bundler/definition.rb new file mode 100644 index 00000000..65b3d53d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/definition.rb @@ -0,0 +1,1328 @@ +# frozen_string_literal: true + +require_relative "lockfile_parser" +require_relative "worker" + +module Bundler + class Definition + class << self + # Do not create or modify a lockfile (Makes #lock a noop) + attr_accessor :no_lock + end + + attr_writer :lockfile + + attr_reader( + :dependencies, + :locked_checksums, + :locked_deps, + :locked_gems, + :platforms, + :ruby_version, + :lockfile, + :gemfiles, + :sources + ) + + # Given a gemfile and lockfile creates a Bundler definition + # + # @param gemfile [Pathname] Path to Gemfile + # @param lockfile [Pathname,nil] Path to Gemfile.lock + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @return [Bundler::Definition] + def self.build(gemfile, lockfile, unlock) + unlock ||= {} + gemfile = Pathname.new(gemfile).expand_path + + raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? + + Dsl.evaluate(gemfile, lockfile, unlock) + end + + # + # How does the new system work? + # + # * Load information from Gemfile and Lockfile + # * Invalidate stale locked specs + # * All specs from stale source are stale + # * All specs that are reachable only through a stale + # dependency are stale. + # * If all fresh dependencies are satisfied by the locked + # specs, then we can try to resolve locally. + # + # @param lockfile [Pathname] Path to Gemfile.lock + # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile + # @param sources [Bundler::SourceList] + # @param unlock [Hash, Boolean, nil] Gems that have been requested + # to be updated or true if all gems should be updated + # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version + # @param optional_groups [Array(String)] A list of optional groups + def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = []) + unlock ||= {} + + if unlock == true + @unlocking_all = true + strict = false + @unlocking_bundler = false + @unlocking = unlock + @sources_to_unlock = [] + @unlocking_ruby = false + @explicit_unlocks = [] + conservative = false + else + @unlocking_all = false + strict = unlock.delete(:strict) + @unlocking_bundler = unlock.delete(:bundler) + @unlocking = unlock.any? {|_k, v| !Array(v).empty? } + @sources_to_unlock = unlock.delete(:sources) || [] + @unlocking_ruby = unlock.delete(:ruby) + @explicit_unlocks = unlock.delete(:gems) || [] + conservative = unlock.delete(:conservative) + end + + @dependencies = dependencies + @sources = sources + @optional_groups = optional_groups + @prefer_local = false + @specs = nil + @ruby_version = ruby_version + @gemfiles = gemfiles + + @lockfile = lockfile + @lockfile_contents = String.new + + @locked_bundler_version = nil + @resolved_bundler_version = nil + + @locked_ruby_version = nil + @new_platforms = [] + @removed_platforms = [] + @originally_invalid_platforms = [] + + if lockfile_exists? + @lockfile_contents = Bundler.read_file(lockfile) + @locked_gems = LockfileParser.new(@lockfile_contents, strict: strict) + @locked_platforms = @locked_gems.platforms + @most_specific_locked_platform = @locked_gems.most_specific_locked_platform + @platforms = @locked_platforms.dup + @locked_bundler_version = @locked_gems.bundler_version + @locked_ruby_version = @locked_gems.ruby_version + @locked_deps = @locked_gems.dependencies + @originally_locked_specs = SpecSet.new(@locked_gems.specs) + @originally_locked_sources = @locked_gems.sources + @locked_checksums = @locked_gems.checksums + + if @unlocking_all + @locked_specs = SpecSet.new([]) + @locked_sources = [] + else + @locked_specs = @originally_locked_specs + @locked_sources = @originally_locked_sources + end + + locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) } + multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? + + if multisource_lockfile + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." + + Bundler::SharedHelpers.feature_removed! msg + end + else + @locked_gems = nil + @locked_platforms = [] + @most_specific_locked_platform = nil + @platforms = [] + @locked_deps = {} + @locked_specs = SpecSet.new([]) + @locked_sources = [] + @originally_locked_specs = @locked_specs + @originally_locked_sources = @locked_sources + @locked_checksums = Bundler.settings[:lockfile_checksums] + end + + @unlocking_ruby ||= if @ruby_version && locked_ruby_version_object + @ruby_version.diff(locked_ruby_version_object) + end + @unlocking ||= @unlocking_ruby ||= (!@locked_ruby_version ^ !@ruby_version) + + @current_platform_missing = add_current_platform unless Bundler.frozen_bundle? + + @source_changes = converge_sources + @path_changes = converge_paths + + if conservative + @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name) + else + eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") } + @gems_to_unlock = @locked_specs.for(eager_unlock, platforms).map(&:name).uniq + end + + @dependency_changes = converge_dependencies + @local_changes = converge_locals + + check_lockfile + end + + def gem_version_promoter + @gem_version_promoter ||= GemVersionPromoter.new + end + + def check! + # If dependencies have changed, we need to resolve remotely. Otherwise, + # since we'll be resolving with a single local source, we may end up + # locking gems under the wrong source in the lockfile, and missing lockfile + # checksums + resolve_remotely! if @dependency_changes + + # Now do a local only resolve, to verify if any gems are missing locally + sources.local_only! + resolve + end + + # + # Setup sources according to the given options and the state of the + # definition. + # + # @return [Boolean] Whether fetching remote information will be necessary or not + # + def setup_domain!(options = {}) + prefer_local! if options[:"prefer-local"] + + sources.cached! + + if options[:add_checksums] || (!options[:local] && (install_needed? || @locked_spec_with_empty_checksums)) + sources.remote! + true + else + Bundler.settings.set_command_option(:jobs, 1) unless install_needed? # to avoid the overhead of Bundler::Worker + sources.local! + false + end + end + + def resolve_with_cache! + with_cache! + + resolve + end + + def with_cache! + sources.local! + sources.cached! + end + + def resolve_remotely! + remotely! + + resolve + end + + def remotely! + sources.cached! + sources.remote! + end + + def prefer_local! + @prefer_local = true + + sources.prefer_local! + end + + # Releases memory only needed during resolution, such as remote spec + # indexes and resolver state. Only safe to call once resolution is + # complete and the result has been materialized, since any further + # resolution will need to refetch remote specs. + def release_resolution_memory! + @resolver = nil + @resolution_base = nil + sources.release_resolution_memory! + end + + # For given dependency list returns a SpecSet with Gemspec of all the required + # dependencies. + # 1. The method first resolves the dependencies specified in Gemfile + # 2. After that it tries and fetches gemspec of resolved dependencies + # + # @return [Bundler::SpecSet] + def specs + @specs ||= materialize(requested_dependencies) + end + + def new_specs + specs - @locked_specs + end + + def removed_specs + @locked_specs - specs + end + + def missing_specs + preload_git_sources + resolve.missing_specs_for(requested_dependencies) + end + + def missing_specs? + missing = missing_specs + return false if missing.empty? + Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" + true + rescue BundlerError => e + @resolve = nil + @resolver = nil + @resolution_base = nil + @source_requirements = nil + @specs = nil + + Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})" + true + end + + def requested_specs + specs_for(requested_groups) + end + + def requested_dependencies + dependencies_for(requested_groups) + end + + def current_dependencies + filter_relevant(dependencies) + end + + def current_locked_dependencies + filter_relevant(locked_dependencies) + end + + def filter_relevant(dependencies) + dependencies.select do |d| + relevant_deps?(d) + end + end + + def relevant_deps?(dep) + platforms_array = [Bundler.generic_local_platform].freeze + + dep.should_include? && !dep.gem_platforms(platforms_array).empty? + end + + def locked_dependencies + @locked_deps.values + end + + def new_deps + @new_deps ||= @dependencies - locked_dependencies + end + + def deleted_deps + @deleted_deps ||= locked_dependencies - @dependencies + end + + def specs_for(groups) + return specs if groups.empty? + deps = dependencies_for(groups) + materialize(deps) + end + + def dependencies_for(groups) + groups.map!(&:to_sym) + deps = current_dependencies # always returns a new array + deps.select! do |d| + d.groups.intersect?(groups) + end + deps + end + + # Resolve all the dependencies specified in Gemfile. It ensures that + # dependencies that have been already resolved via locked file and are fresh + # are reused when resolving dependencies + # + # @return [SpecSet] resolved dependencies + def resolve + @resolve ||= if Bundler.frozen_bundle? + Bundler.ui.debug "Frozen, using resolution from the lockfile" + @locked_specs + elsif no_resolve_needed? + if deleted_deps.any? + Bundler.ui.debug "Some dependencies were deleted, using a subset of the resolution from the lockfile" + SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) + else + Bundler.ui.debug "Found no changes, using resolution from the lockfile" + if @removed_platforms.any? || @locked_gems.may_include_redundant_platform_specific_gems? + SpecSet.new(filter_specs(@locked_specs, @dependencies)) + else + @locked_specs + end + end + else + Bundler.ui.debug resolve_needed_reason + + start_resolution + end + end + + def spec_git_paths + sources.git_sources.filter_map {|s| File.realpath(s.path) if File.exist?(s.path) } + end + + # Versions excluded by cooldown during the last resolution, one entry per + # gem with the newest skipped version. Empty when no resolution ran. + def cooldown_skipped + @cooldown_skipped || [] + end + + def groups + dependencies.flat_map(&:groups).uniq + end + + def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false) + if [true, false, nil].include?(file_or_preserve_unknown_sections) + target_lockfile = lockfile + preserve_unknown_sections = file_or_preserve_unknown_sections + else + target_lockfile = file_or_preserve_unknown_sections + preserve_unknown_sections = preserve_unknown_sections_or_unused + + suggestion = if target_lockfile == lockfile + "To fix this warning, remove it from the `Definition#lock` call." + else + "Instead, instantiate a new definition passing `#{target_lockfile}`, and call `lock` without a file argument on that definition" + end + + msg = "`Definition#lock` was passed a target file argument. #{suggestion}" + + Bundler::SharedHelpers.feature_removed! msg + end + + write_lock(target_lockfile, preserve_unknown_sections) + end + + def write_lock(file, preserve_unknown_sections) + return if Definition.no_lock || !lockfile || file.nil? + + contents = to_lock + + if @locked_bundler_version + locked_major = @locked_bundler_version.segments.first + current_major = bundler_version_to_lock.segments.first + + updating_major = locked_major < current_major + end + + preserve_unknown_sections ||= Bundler.frozen_bundle? || (!updating_major && !(unlocking? || @unlocking_bundler)) + + if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) + return if Bundler.frozen_bundle? + SharedHelpers.filesystem_access(file) { FileUtils.touch(file) } + return + end + + if Bundler.frozen_bundle? + msg = lockfile_changes_summary("frozen mode is set") || + "Your lockfile needs to be updated, but it can't be because frozen mode is set.\n\n" \ + "Run `bundle install` elsewhere and add the updated #{SharedHelpers.relative_lockfile_path} to version control." + raise ProductionError, msg + end + + # Convert to \r\n if the existing lock has them, i.e., Windows with + # `git config core.autocrlf=true`. Detect from the bytes on disk because + # reading in text mode strips carriage returns on Windows, which would + # otherwise defeat this check and rewrite a `\r\n` lockfile with `\n`. + if File.exist?(file) && SharedHelpers.filesystem_access(file, :read) {|p| File.binread(p).include?("\r\n") } + contents.gsub!(/\n/, "\r\n") + end + + begin + SharedHelpers.filesystem_access(file) do |p| + File.open(p, "wb") {|f| f.puts(contents) } + end + rescue ReadOnlyFileSystemError + raise ProductionError, lockfile_changes_summary("file system is read-only") + end + end + + def locked_ruby_version + return unless ruby_version + if @unlocking_ruby || !@locked_ruby_version + Bundler::RubyVersion.system + else + @locked_ruby_version + end + end + + def locked_ruby_version_object + return unless @locked_ruby_version + @locked_ruby_version_object ||= begin + unless version = RubyVersion.from_string(@locked_ruby_version) + raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \ + "#{@lockfile} could not be parsed. " \ + "Try running bundle update --ruby to resolve this." + end + version + end + end + + def bundler_version_to_lock + @resolved_bundler_version || Bundler.gem_version + end + + def to_lock + require_relative "lockfile_generator" + LockfileGenerator.generate(self) + end + + def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) + return unless Bundler.frozen_bundle? + + raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists? + + msg = lockfile_changes_summary("frozen mode is set") + return unless msg + + unless explicit_flag + suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env) + "bundle config set frozen false" + end + msg << "\n\nIf this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \ + "freeze by running `#{suggested_command}`." if suggested_command + end + + raise ProductionError, msg + end + + def validate_runtime! + validate_ruby! + validate_platforms! + end + + def validate_ruby! + return unless ruby_version + + if diff = ruby_version.diff(Bundler::RubyVersion.system) + problem, expected, actual = diff + + msg = case problem + when :engine + "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" + when :version + "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" + when :engine_version + "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" + when :patchlevel + if !expected.is_a?(String) + "The Ruby patchlevel in your Gemfile must be a string" + else + "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" + end + end + + raise RubyVersionMismatch, msg + end + end + + def validate_platforms! + return if current_platform_locked? || @platforms.include?(Gem::Platform::RUBY) + + raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \ + "but your local platform is #{Bundler.local_platform}. " \ + "Add the current platform to the lockfile with\n`bundle lock --add-platform #{Bundler.local_platform}` and try again." + end + + def normalize_platforms + resolve.normalize_platforms!(current_dependencies, platforms) + + @resolve = SpecSet.new(resolve.for(current_dependencies, @platforms)) + end + + def add_platform(platform) + return if @platforms.include?(platform) + + @new_platforms << platform + @platforms << platform + end + + def remove_platform(platform) + raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" unless @platforms.include?(platform) + + @removed_platforms << platform + @platforms.delete(platform) + end + + def nothing_changed? + !something_changed? + end + + def no_resolve_needed? + !resolve_needed? + end + + def unlocking? + @unlocking + end + + def add_checksums + require "rubygems/package" + + @locked_checksums = true + + setup_domain!(add_checksums: true) + + # force materialization to real specifications, so that checksums are fetched + specs.each do |spec| + next unless spec.source.is_a?(Bundler::Source::Rubygems) + # Checksum was fetched from the compact index API. + next if !spec.source.checksum_store.missing?(spec) && !spec.source.checksum_store.empty?(spec) + # The gem isn't installed, can't compute the checksum. + next unless spec.loaded_from + + package = Gem::Package.new(spec.source.cached_built_in_gem(spec)) + checksum = Checksum.from_gem_package(package) + spec.source.checksum_store.register(spec, checksum) + end + end + + private + + def lockfile_changes_summary(update_refused_reason) + added = [] + deleted = [] + changed = [] + + added.concat @new_platforms.map {|p| "* platform: #{p}" } + deleted.concat @removed_platforms.map {|p| "* platform: #{p}" } + + added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? + deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any? + + both_sources = Hash.new {|h, k| h[k] = [] } + current_dependencies.each {|d| both_sources[d.name][0] = d } + current_locked_dependencies.each {|d| both_sources[d.name][1] = d } + + both_sources.each do |name, (dep, lock_dep)| + next if dep.nil? || lock_dep.nil? + + gemfile_source = dep.source || default_source + lock_source = lock_dep.source || default_source + next if lock_source.include?(gemfile_source) + + gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source" + lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source" + changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`" + end + + return unless added.any? || deleted.any? || changed.any? || resolve_needed? + + msg = String.new("#{change_reason[0].upcase}#{change_reason[1..-1].strip}, but ") + msg << "the lockfile " unless msg.start_with?("Your lockfile") + msg << "can't be updated because #{update_refused_reason}" + msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? + msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? + msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? + msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_lockfile_path} to version control.\n" unless unlocking? + msg + end + + def install_needed? + resolve_needed? || missing_specs? + end + + def something_changed? + return true unless lockfile_exists? + + @source_changes || + @dependency_changes || + @current_platform_missing || + @new_platforms.any? || + @path_changes || + @local_changes || + @missing_lockfile_dep || + @unlocking_bundler || + @locked_spec_with_missing_checksums || + empty_checksums_actionable? || + @locked_spec_with_missing_deps || + @locked_spec_with_invalid_deps + end + + def resolve_needed? + unlocking? || something_changed? + end + + # Only a remote fetch can fill an empty CHECKSUMS entry, so it justifies a + # resolution only when one is coming. Resolving locally for it would repeat + # on every `Bundler.setup` without changing the lockfile. Frozen mode still + # has to refuse the entry. + def empty_checksums_actionable? + return false unless @locked_spec_with_empty_checksums + + Bundler.frozen_bundle? || !sources.local_mode? + end + + def should_add_extra_platforms? + !lockfile_exists? && Bundler::MatchPlatform.generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform] + end + + def lockfile_exists? + lockfile && File.exist?(lockfile) + end + + def resolver + @resolver ||= new_resolver(resolution_base) + end + + def expanded_dependencies + dependencies_with_bundler + metadata_dependencies + end + + def dependencies_with_bundler + return dependencies unless @unlocking_bundler + return dependencies if dependencies.any? {|d| d.name == "bundler" } + + [Dependency.new("bundler", @unlocking_bundler)] + dependencies + end + + def resolution_base + @resolution_base ||= begin + last_resolve = converge_locked_specs + remove_invalid_platforms! + base = new_resolution_base(last_resolve: last_resolve, unlock: @unlocking_all || @gems_to_unlock) + base = additional_base_requirements_to_prevent_downgrades(base) + base = additional_base_requirements_to_force_updates(base) + base + end + end + + def filter_specs(specs, deps, skips: []) + SpecSet.new(specs).for(deps, platforms, skips: skips) + end + + def materialize(dependencies) + specs = begin + resolve.materialize(dependencies) + rescue IncorrectLockfileDependencies => e + raise if Bundler.frozen_bundle? + + reresolve_without([e.spec]) + retry + end + + missing_specs = resolve.missing_specs + + if missing_specs.any? + missing_specs.each do |s| + locked_gem = @locked_specs[s.name].last + next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode? + + message = if sources.implicit_global_source? + "Because your Gemfile specifies no global remote source, your bundle is locked to " \ + "#{locked_gem} from #{locked_gem.source}. However, #{locked_gem} is not installed. You'll " \ + "need to either add a global remote source to your Gemfile or make sure #{locked_gem} is " \ + "available locally before rerunning Bundler." + else + "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ + "no longer be found in that source. That means either the author of #{locked_gem} has removed it, " \ + "or you no longer have access to that source. You'll need to update your bundle to a version other " \ + "than #{locked_gem} that hasn't been removed, or check your credentials and access rights for " \ + "#{locked_gem.source}, in order to install." + end + + raise GemNotFound, message + end + + missing_specs_list = missing_specs.group_by(&:source).map do |source, missing_specs_for_source| + "#{missing_specs_for_source.map(&:full_name).join(", ")} in #{source}" + end + + raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}" + end + + partially_missing_specs = resolve.partially_missing_specs + + if partially_missing_specs.any? && !sources.local_mode? + Bundler.ui.warn "Some locked specs have possibly been yanked (#{partially_missing_specs.map(&:full_name).join(", ")}). Ignoring them..." + + resolve.delete(partially_missing_specs) + end + + incomplete_specs = resolve.incomplete_specs + loop do + break if incomplete_specs.empty? + + Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies") + sources.remote! + reresolve_without(incomplete_specs) + specs = resolve.materialize(dependencies) + + still_incomplete_specs = resolve.incomplete_specs + + if still_incomplete_specs == incomplete_specs + resolver.raise_incomplete! incomplete_specs + end + + incomplete_specs = still_incomplete_specs + end + + insecurely_materialized_specs = resolve.insecurely_materialized_specs + + if insecurely_materialized_specs.any? + Bundler.ui.warn "The following platform specific gems are getting installed, yet the lockfile includes only their generic ruby version:\n" \ + " * #{insecurely_materialized_specs.map(&:full_name).join("\n * ")}\n" \ + "Please run `bundle lock --normalize-platforms` and commit the resulting lockfile.\n" \ + "Alternatively, you may run `bundle lock --add-platform `" + end + + bundler = sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last + specs["bundler"] = bundler + + specs + end + + def reresolve_without(incomplete_specs) + resolution_base.delete(incomplete_specs) + @resolve = start_resolution + end + + def start_resolution + local_platform_needed_for_resolvability = @most_specific_non_local_locked_platform && !@platforms.include?(Bundler.local_platform) + @platforms << Bundler.local_platform if local_platform_needed_for_resolvability + + result = SpecSet.new(resolver.start) + + @cooldown_skipped = resolver.cooldown_skipped + + @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version + + @new_platforms.each do |platform| + incomplete_specs = result.incomplete_specs_for_platform(current_dependencies, platform) + + if incomplete_specs.any? + resolver.raise_incomplete! incomplete_specs + end + end + + if @most_specific_non_local_locked_platform + if result.incomplete_for_platform?(current_dependencies, @most_specific_non_local_locked_platform) + @platforms.delete(@most_specific_non_local_locked_platform) + elsif local_platform_needed_for_resolvability + @platforms.delete(Bundler.local_platform) + end + end + + if should_add_extra_platforms? + result.add_extra_platforms!(platforms) + elsif @originally_invalid_platforms.any? + result.add_originally_invalid_platforms!(platforms, @originally_invalid_platforms) + end + + SpecSet.new(result.for(dependencies, @platforms | [Gem::Platform::RUBY])) + end + + def precompute_source_requirements_for_indirect_dependencies? + if sources.non_global_rubygems_sources.all?(&:dependency_api_available?) + true + else + non_dependency_api_warning + false + end + end + + def non_dependency_api_warning + non_api_sources = sources.non_global_rubygems_sources.reject(&:dependency_api_available?) + non_api_source_names = non_api_sources.map {|d| " * #{d}" }.join("\n") + + msg = String.new + msg << "Your Gemfile contains scoped sources that don't implement a dependency API, namely:\n\n" + msg << non_api_source_names + msg << "\n\nUsing the above gem servers may result in installing unexpected gems. " \ + "To resolve this warning, make sure you use gem servers that implement dependency APIs, " \ + "such as gemstash or geminabox gem servers." + Bundler.ui.warn msg + end + + def current_platform_locked? + @platforms.any? do |bundle_platform| + Bundler.generic_local_platform == bundle_platform || Bundler.local_platform === bundle_platform + end + end + + def add_current_platform + return if @platforms.include?(Bundler.local_platform) + + @most_specific_non_local_locked_platform = find_most_specific_locked_platform + return if @most_specific_non_local_locked_platform + + @platforms << Bundler.local_platform + true + end + + def find_most_specific_locked_platform + return unless current_platform_locked? + + @most_specific_locked_platform + end + + def resolve_needed_reason + if lockfile_exists? + if unlocking? + "Re-resolving dependencies because #{unlocking_reason}" + else + "Found changes from the lockfile, re-resolving dependencies because #{lockfile_changed_reason}" + end + else + "Resolving dependencies because there's no lockfile" + end + end + + def change_reason + if resolve_needed? + if unlocking? + unlocking_reason + else + lockfile_changed_reason + end + else + "some dependencies were deleted from your gemfile" + end + end + + def unlocking_reason + unlock_targets = if @gems_to_unlock.any? + ["gems", @gems_to_unlock] + elsif @sources_to_unlock.any? + ["sources", @sources_to_unlock] + end + + unlock_reason = if unlock_targets + "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})" + else + @unlocking_ruby ? "ruby" : "" + end + + "bundler is unlocking #{unlock_reason}" + end + + def lockfile_changed_reason + [ + [@source_changes, "the list of sources changed"], + [@dependency_changes, "the dependencies in your gemfile changed"], + [@current_platform_missing, "your lockfile is missing the current platform"], + [@new_platforms.any?, "you are adding a new platform to your lockfile"], + [@path_changes, "the gemspecs for path gems changed"], + [@local_changes, "the gemspecs for git local gems changed"], + [@missing_lockfile_dep, "your lockfile is missing \"#{@missing_lockfile_dep}\""], + [@unlocking_bundler, "an update to the version of Bundler itself was requested"], + [@locked_spec_with_missing_checksums, "your lockfile is missing a CHECKSUMS entry for \"#{@locked_spec_with_missing_checksums}\""], + [@locked_spec_with_empty_checksums, "your lockfile has an empty CHECKSUMS entry for \"#{@locked_spec_with_empty_checksums}\""], + [@locked_spec_with_missing_deps, "your lockfile includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"], + [@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""], + ].select(&:first).map(&:last).join(", ") + end + + def pretty_dep(dep) + SharedHelpers.pretty_dependency(dep) + end + + # Check if the specs of the given source changed + # according to the locked source. + def specs_changed?(source) + locked = @locked_sources.find {|s| s == source } + + !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source) + end + + def dependencies_for_source_changed?(source, locked_source) + deps_for_source = @dependencies.select {|dep| dep.source == source } + locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source } + + deps_for_source.uniq.sort != locked_deps_for_source.sort + end + + def specs_for_source_changed?(source) + locked_index = Index.new + locked_index.use(@locked_specs.select {|s| s.replace_source_with!(source) }) + + !locked_index.subset?(source.specs) + rescue PathError, GitError => e + Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" + false + end + + # Get all locals and override their matching sources. + # Return true if any of the locals changed (for example, + # they point to a new revision) or depend on new specs. + def converge_locals + locals = [] + + Bundler.settings.local_overrides.map do |k, v| + spec = @dependencies.find {|s| s.name == k } + source = spec&.source + if source&.respond_to?(:local_override!) + source.unlock! if @gems_to_unlock.include?(spec.name) + locals << [source, source.local_override!(v)] + end + end + + sources_with_changes = locals.select do |source, changed| + changed || specs_changed?(source) + end.map(&:first) + !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty? + end + + def check_lockfile + @locked_spec_with_invalid_deps = nil + @locked_spec_with_missing_deps = nil + @locked_spec_with_missing_checksums = nil + @locked_spec_with_empty_checksums = nil + + missing_deps = [] + missing_checksums = [] + empty_checksums = [] + invalid = [] + + @locked_specs.each do |s| + if @locked_checksums + checksum_store = s.source.checksum_store + + if checksum_store.missing?(s) + missing_checksums << s + elsif checksum_store.empty?(s) + empty_checksums << s + end + end + + validation = @locked_specs.validate_deps(s) + + missing_deps << s if validation == :missing + invalid << s if validation == :invalid + end + + @locked_spec_with_missing_checksums = missing_checksums.first.name if missing_checksums.any? + @locked_spec_with_empty_checksums = empty_checksums.first.name if empty_checksums.any? + + if missing_deps.any? + @locked_specs.delete(missing_deps) + + @locked_spec_with_missing_deps = missing_deps.first.name + end + + if invalid.any? + @locked_specs.delete(invalid) + + @locked_spec_with_invalid_deps = invalid.first.name + end + end + + def converge_paths + sources.path_sources.any? do |source| + specs_changed?(source) + end + end + + def converge_sources + # Replace the sources from the Gemfile with the sources from the Gemfile.lock, + # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent + # source in the Gemfile.lock, use the one from the Gemfile. + changes = sources.replace_sources!(@locked_sources) + + sources.all_sources.each do |source| + # has to be done separately, because we want to keep the locked checksum + # store for a source, even when doing a full update + if @locked_checksums && @locked_gems && locked_source = @originally_locked_sources.find {|s| s == source && !s.equal?(source) } + source.checksum_store.merge!(locked_source.checksum_store) + end + # If the source is unlockable and the current command allows an unlock of + # the source (for example, you are doing a `bundle update ` of a git-pinned + # gem), unlock it. For git sources, this means to unlock the revision, which + # will cause the `ref` used to be the most recent for the branch (or master) if + # an explicit `ref` is not used. + if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name) + source.unlock! + changes = true + end + end + + sources.metadata_source.checksum_store.merge!(@locked_gems.metadata_source.checksum_store) if @locked_gems + + changes + end + + def converge_dependencies + @missing_lockfile_dep = nil + @changed_dependencies = [] + + @dependencies.each do |dep| + if dep.source + dep.source = sources.get(dep.source) + end + next unless relevant_deps?(dep) + + name = dep.name + + dep_changed = @locked_deps[name].nil? + + unless name == "bundler" + locked_specs = @originally_locked_specs[name] + + if locked_specs.empty? + @missing_lockfile_dep = name if dep_changed == false + else + if locked_specs.map(&:source).uniq.size > 1 + @locked_specs.delete(locked_specs.select {|s| s.source != dep.source }) + end + + unless dep.matches_spec?(locked_specs.first) + @gems_to_unlock << name + dep_changed = true + end + end + end + + @changed_dependencies << name if dep_changed + end + + @changed_dependencies.any? + end + + # Remove elements from the locked specs that are expired. This will most + # commonly happen if the Gemfile has changed since the lockfile was last + # generated + def converge_locked_specs + converged = converge_specs(@locked_specs) + + resolve = SpecSet.new(converged) + + diff = nil + + # Now, we unlock any sources that do not have anymore gems pinned to it + sources.all_sources.each do |source| + next unless source.respond_to?(:unlock!) + + unless resolve.any? {|s| s.source == source } + diff ||= @locked_specs.to_a - resolve.to_a + source.unlock! if diff.any? {|s| s.source == source } + end + end + + resolve + end + + def converge_specs(specs) + converged = [] + deps = [] + + specs.each do |s| + name = s.name + next if @gems_to_unlock.include?(name) + + dep = @dependencies.find {|d| s.satisfies?(d) } + lockfile_source = s.source + + if dep + replacement_source = dep.source + + deps << dep if !replacement_source || lockfile_source.include?(replacement_source) || new_deps.include?(dep) + else + parent_dep = @dependencies.find do |d| + next unless d.source && d.source != lockfile_source + next if d.source.is_a?(Source::Gemspec) + + parent_locked_specs = @originally_locked_specs[d.name] + + parent_locked_specs.any? do |parent_spec| + parent_spec.runtime_dependencies.any? {|rd| rd.name == s.name } + end + end + + if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any? + replacement_source = parent_dep.source + else + replacement_source = sources.get(lockfile_source) + end + end + + # Replace the locked dependency's source with the equivalent source from the Gemfile + s.source = replacement_source || default_source + next if s.source_changed? + + source = s.source + next if @sources_to_unlock.include?(source.name) + + # Path sources have special logic + if source.is_a?(Source::Path) + new_spec = source.specs[s].first + if new_spec + s.runtime_dependencies.replace(new_spec.runtime_dependencies) + else + # If the spec is no longer in the path source, unlock it. This + # commonly happens if the version changed in the gemspec + @gems_to_unlock << name + end + end + + converged << s + end + + filter_specs(converged, deps, skips: @gems_to_unlock) + end + + def metadata_dependencies + @metadata_dependencies ||= [ + Dependency.new("Ruby\0", Bundler::RubyVersion.system.gem_version), + Dependency.new("RubyGems\0", Gem::VERSION), + ] + end + + def source_requirements + @source_requirements ||= find_source_requirements + end + + def preload_git_source_worker + workers = Bundler.settings.installation_parallelization + + @preload_git_source_worker ||= Bundler::Worker.new(workers, "Git source preloading", ->(source, _) { source.specs }) + end + + def preload_git_sources + if Gem.ruby_version < Gem::Version.new("3.3") + # Ruby 3.2 has a bug that incorrectly triggers a circular dependency warning. This version will continue to + # fetch git repositories one by one. + return + end + + begin + needed_git_sources.each {|source| preload_git_source_worker.enq(source) } + ensure + preload_git_source_worker.stop + end + end + + # Git sources needed for the requested groups (excludes sources only used by --without groups) + def needed_git_sources + needed_deps = dependencies_for(requested_groups) + sources.git_sources.select do |source| + needed_deps.any? {|d| d.source == source } + end + end + + # Git sources that should be excluded (only used by --without groups) + def excluded_git_sources + sources.git_sources - needed_git_sources + end + + def find_source_requirements + preload_git_sources + + # Only safe to exclude when locked_requirements (merged below) backfills the gap. + nothing_changed = nothing_changed? + excluded = nothing_changed ? excluded_git_sources : [] + + # Record the specs available in each gem's source, so that those + # specs will be available later when the resolver knows where to + # look for that gemspec (or its dependencies) + source_requirements = if precompute_source_requirements_for_indirect_dependencies? + all_requirements = source_map.all_requirements(excluded) + { default: default_source }.merge(all_requirements) + else + { default: Source::RubygemsAggregate.new(sources, source_map, excluded) }.merge(source_map.direct_requirements) + end + source_requirements.merge!(source_map.locked_requirements) if nothing_changed + metadata_dependencies.each do |dep| + source_requirements[dep.name] = sources.metadata_source + end + + default_bundler_source = source_requirements["bundler"] || default_source + + if @unlocking_bundler + default_bundler_source.add_dependency_names("bundler") + else + source_requirements[:default_bundler] = default_bundler_source + source_requirements["bundler"] = sources.metadata_source # needs to come last to override + end + + source_requirements + end + + def default_source + sources.default_source + end + + def requested_groups + values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] + values &= Bundler.settings[:only] unless Bundler.settings[:only].empty? + values + end + + def lockfiles_equal?(current, proposed, preserve_unknown_sections) + if preserve_unknown_sections + sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version) + sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current) + sections_to_ignore << LockfileParser::RUBY + sections_to_ignore << LockfileParser::BUNDLED unless @unlocking_bundler + pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/ + whitespace_cleanup = /\n{2,}/ + current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip + proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip + end + current == proposed + end + + def additional_base_requirements_to_prevent_downgrades(resolution_base) + return resolution_base unless @locked_gems + @originally_locked_specs.each do |locked_spec| + next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed? + + name = locked_spec.name + next if @changed_dependencies.include?(name) + + resolution_base.base_requirements[name] = Gem::Requirement.new(">= #{locked_spec.version}") + end + resolution_base + end + + def additional_base_requirements_to_force_updates(resolution_base) + return resolution_base if @explicit_unlocks.empty? + full_update = SpecSet.new(new_resolver_for_full_update.start) + @explicit_unlocks.each do |name| + version = full_update.version_for(name) + resolution_base.base_requirements[name] = Gem::Requirement.new("= #{version}") if version + end + resolution_base + end + + def remove_invalid_platforms! + return if Bundler.frozen_bundle? + + skips = (@new_platforms + [Bundler.local_platform]).uniq + + # We should probably avoid removing non-ruby platforms, since that means + # lockfile will no longer install on those platforms, so a error to give + # heads up to the user may be better. However, we have tests expecting + # non ruby platform autoremoval to work, so leaving that in place for + # now. + skips |= platforms - [Gem::Platform::RUBY] if @dependency_changes + + @originally_invalid_platforms = @originally_locked_specs.remove_invalid_platforms!(current_dependencies, platforms, skips: skips) + end + + def source_map + @source_map ||= SourceMap.new(sources, dependencies, @locked_specs) + end + + def new_resolver_for_full_update + new_resolver(unlocked_resolution_base) + end + + def unlocked_resolution_base + new_resolution_base(last_resolve: SpecSet.new([]), unlock: true) + end + + def new_resolution_base(last_resolve:, unlock:) + new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms + Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms, explicit_unlocks: @explicit_unlocks) + end + + def new_resolver(base) + Resolver.new(base, gem_version_promoter, @most_specific_locked_platform) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/dependency.rb b/bin/gems/bundler-4.0.21/lib/bundler/dependency.rb new file mode 100644 index 00000000..cb9c7a76 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/dependency.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +require "rubygems/dependency" +require_relative "shared_helpers" + +module Bundler + class Dependency < Gem::Dependency + def initialize(name, version, options = {}, &blk) + type = options["type"] || :runtime + super(name, version, type) + + @options = options + end + + def groups + @groups ||= Array(@options["group"] || :default).map(&:to_sym) + end + + def source + return @source if defined?(@source) + + @source = @options["source"] + end + + def path + return @path if defined?(@path) + + @path = @options["path"] + end + + def git + return @git if defined?(@git) + + @git = @options["git"] + end + + def github + return @github if defined?(@github) + + @github = @options["github"] + end + + def branch + return @branch if defined?(@branch) + + @branch = @options["branch"] + end + + def ref + return @ref if defined?(@ref) + + @ref = @options["ref"] + end + + def glob + return @glob if defined?(@glob) + + @glob = @options["glob"] + end + + def platforms + @platforms ||= Array(@options["platforms"]) + end + + def env + return @env if defined?(@env) + + @env = @options["env"] + end + + def should_include + @should_include ||= @options.fetch("should_include", true) + end + + def gemfile + return @gemfile if defined?(@gemfile) + + @gemfile = @options["gemfile"] + end + + def force_ruby_platform + return @force_ruby_platform if defined?(@force_ruby_platform) + + @force_ruby_platform = @options["force_ruby_platform"] + end + + def autorequire + return @autorequire if defined?(@autorequire) + + @autorequire = Array(@options["require"] || []) if @options.key?("require") + end + + RUBY_PLATFORM_ARRAY = [Gem::Platform::RUBY].freeze + private_constant :RUBY_PLATFORM_ARRAY + + # Returns the platforms this dependency is valid for, in the same order as + # passed in the `valid_platforms` parameter + def gem_platforms(valid_platforms) + return RUBY_PLATFORM_ARRAY if force_ruby_platform + return valid_platforms if platforms.empty? + + valid_platforms.select {|p| expanded_platforms.include?(Gem::Platform.generic(p)) } + end + + def expanded_platforms + @expanded_platforms ||= platforms.filter_map {|pl| CurrentRuby::PLATFORM_MAP[pl] }.flatten.uniq + end + + def should_include? + should_include && current_env? && current_platform? + end + + def gemspec_dev_dep? + @gemspec_dev_dep ||= @options.fetch("gemspec_dev_dep", false) + end + + def gemfile_dep? + !gemspec_dev_dep? + end + + def current_env? + return true unless env + if env.is_a?(Hash) + env.all? do |key, val| + ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val) + end + else + ENV[env.to_s] + end + end + + def current_platform? + return true if platforms.empty? + platforms.any? do |p| + Bundler.current_ruby.send("#{p}?") + end + end + + def to_lock + out = super + out << "!" if source + out + end + + def specific? + super + rescue NoMethodError + requirement != ">= 0" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/deployment.rb b/bin/gems/bundler-4.0.21/lib/bundler/deployment.rb new file mode 100644 index 00000000..3344449e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/deployment.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.feature_removed! "Bundler no longer integrates with " \ + "Capistrano, but Capistrano provides its own integration with " \ + "Bundler via the capistrano-bundler gem. Use it instead." diff --git a/bin/gems/bundler-4.0.21/lib/bundler/deprecate.rb b/bin/gems/bundler-4.0.21/lib/bundler/deprecate.rb new file mode 100644 index 00000000..f5953363 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/deprecate.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +begin + require "rubygems/deprecate" +rescue LoadError + # it's fine if it doesn't exist on the current RubyGems... + nil +end + +module Bundler + # If Bundler::Deprecate is an autoload constant, we need to define it + if defined?(Bundler::Deprecate) && !autoload?(:Deprecate) + # nothing to do! + elsif defined? ::Deprecate + Deprecate = ::Deprecate + elsif defined? Gem::Deprecate + Deprecate = Gem::Deprecate + else + class Deprecate + end + end + + unless Deprecate.respond_to?(:skip_during) + def Deprecate.skip_during + original = skip + self.skip = true + yield + ensure + self.skip = original + end + end + + unless Deprecate.respond_to?(:skip) + def Deprecate.skip + @skip ||= false + end + end + + unless Deprecate.respond_to?(:skip=) + def Deprecate.skip=(skip) + @skip = skip + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/digest.rb b/bin/gems/bundler-4.0.21/lib/bundler/digest.rb new file mode 100644 index 00000000..15880303 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/digest.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# This code was extracted from https://github.com/Solistra/ruby-digest which is under public domain +module Bundler + module Digest + # The initial constant values for the 32-bit constant words A, B, C, D, and + # E, respectively. + SHA1_WORDS = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0].freeze + + # The 8-bit field used for bitwise `AND` masking. Defaults to `0xFFFFFFFF`. + SHA1_MASK = 0xFFFFFFFF + + class << self + def sha1(string) + unless string.is_a?(String) + raise TypeError, "can't convert #{string.class.inspect} into String" + end + + buffer = string.b + + words = SHA1_WORDS.dup + generate_split_buffer(buffer) do |chunk| + w = [] + chunk.each_slice(4) do |a, b, c, d| + w << (((a << 8 | b) << 8 | c) << 8 | d) + end + a, b, c, d, e = *words + (16..79).each do |i| + w[i] = SHA1_MASK & rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1) + end + 0.upto(79) do |i| + case i + when 0..19 + f = ((b & c) | (~b & d)) + k = 0x5A827999 + when 20..39 + f = (b ^ c ^ d) + k = 0x6ED9EBA1 + when 40..59 + f = ((b & c) | (b & d) | (c & d)) + k = 0x8F1BBCDC + when 60..79 + f = (b ^ c ^ d) + k = 0xCA62C1D6 + end + t = SHA1_MASK & rotate(a, 5) + f + e + k + w[i] + a, b, c, d, e = t, a, SHA1_MASK & rotate(b, 30), c, d # rubocop:disable Style/ParallelAssignment + end + mutated = [a, b, c, d, e] + words.map!.with_index {|word, index| SHA1_MASK & (word + mutated[index]) } + end + + words.pack("N*").unpack1("H*") + end + + private + + def generate_split_buffer(string, &block) + size = string.bytesize * 8 + buffer = string.bytes << 128 + buffer << 0 while buffer.size % 64 != 56 + buffer.concat([size].pack("Q>").bytes) + buffer.each_slice(64, &block) + end + + def rotate(value, spaces) + value << spaces | value >> (32 - spaces) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/dsl.rb b/bin/gems/bundler-4.0.21/lib/bundler/dsl.rb new file mode 100644 index 00000000..17751282 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/dsl.rb @@ -0,0 +1,645 @@ +# frozen_string_literal: true + +require_relative "dependency" +require_relative "ruby_dsl" + +module Bundler + class Dsl + include RubyDsl + + def self.evaluate(gemfile, lockfile, unlock) + builder = new + builder.lockfile(lockfile) + builder.eval_gemfile(gemfile) + builder.to_definition(builder.lockfile_path, unlock) + end + + VALID_PLATFORMS = Bundler::CurrentRuby::PLATFORM_MAP.keys.freeze + + VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules + platform platforms source install_if force_ruby_platform].freeze + + GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z} + GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z} + + attr_reader :gemspecs, :gemfile + attr_accessor :dependencies + + def initialize + @source = nil + @sources = SourceList.new + @git_sources = {} + @dependencies = [] + @groups = [] + @install_conditionals = [] + @optional_groups = [] + @platforms = [] + @env = nil + @ruby_version = nil + @gemspecs = [] + @gemfile = nil + @gemfiles = [] + @lockfile = nil + add_git_sources + end + + def eval_gemfile(gemfile, contents = nil) + with_gemfile(gemfile) do |current_gemfile| + contents ||= Bundler.read_file(current_gemfile) + instance_eval(contents, current_gemfile, 1) + rescue GemfileEvalError => e + message = "There was an error evaluating `#{File.basename current_gemfile}`: #{e.message}" + raise DSLError.new(message, current_gemfile, e.backtrace, contents) + rescue GemfileError, InvalidArgumentError, InvalidOption, DeprecatedError, ScriptError => e + message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}" + raise DSLError.new(message, current_gemfile, e.backtrace, contents) + rescue StandardError => e + raise unless e.backtrace_locations.first.path == current_gemfile + message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}" + raise DSLError.new(message, current_gemfile, e.backtrace, contents) + end + end + + def gemspec(opts = nil) + opts ||= {} + path = opts[:path] || "." + glob = opts[:glob] + name = opts[:name] + development_group = opts[:development_group] || :development + expanded_path = gemfile_root.join(path) + + gemspecs = SharedHelpers.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) } + gemspecs.reject! {|s| s.name != name } if name + specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } + + case specs_by_name_and_version.size + when 1 + specs = specs_by_name_and_version.values.first + spec = specs.find {|s| s.installable_on_platform?(Bundler.local_platform) } || specs.first + + @gemspecs << spec + + path path, "glob" => glob, "name" => spec.name, "gemspec" => spec do + add_dependency spec.name + end + + spec.development_dependencies.each do |dep| + add_dependency dep.name, dep.requirement.as_list, "gemspec_dev_dep" => true, "group" => development_group + end + when 0 + raise InvalidOption, "There are no gemspecs at #{expanded_path}" + else + raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. " \ + "Please use the :name option to specify which one should be used" + end + end + + def gem(name, *args) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + version = args || [">= 0"] + + normalize_options(name, version, options) + + add_dependency(name, version, options) + end + + # For usage in Dsl.evaluate, since lockfile is used as part of the Gemfile. + def lockfile_path + @lockfile + end + + def lockfile(file) + @lockfile = file + end + + def source(source, *args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + options = normalize_hash(options) + source = normalize_source(source) + cooldown = options["cooldown"] + if cooldown && !(cooldown.is_a?(Integer) && cooldown >= 0) + raise InvalidOption, "Expected `cooldown` to be a non-negative integer, got #{cooldown.inspect}" + end + + if options.key?("type") + options["type"] = options["type"].to_s + unless Plugin.source?(options["type"]) + raise InvalidOption, "No plugin sources available for #{options["type"]}" + end + + unless block_given? + raise InvalidOption, "You need to pass a block to #source with :type option" + end + + source_opts = options.merge("uri" => source) + with_source(@sources.add_plugin_source(options["type"], source_opts), &blk) + elsif block_given? + with_source(@sources.add_rubygems_source("remotes" => source, "cooldown" => cooldown), &blk) + else + @sources.add_global_rubygems_remote(source, cooldown: cooldown) + end + end + + def git_source(name, &block) + unless block_given? + raise InvalidOption, "You need to pass a block to #git_source" + end + + if valid_keys.include?(name.to_s) + raise InvalidOption, "You cannot use #{name} as a git source. It " \ + "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}" + end + + @git_sources[name.to_s] = block + end + + def path(path, options = {}, &blk) + source_options = normalize_hash(options).merge( + "path" => Pathname.new(path), + "root_path" => gemfile_root + ) + + source_options["global"] = true unless block_given? + + source = @sources.add_path_source(source_options) + with_source(source, &blk) + end + + def git(uri, options = {}, &blk) + unless block_given? + msg = "You can no longer specify a git source by itself. Instead, \n" \ + "either use the :git option on a gem, or specify the gems that \n" \ + "bundler should find in the git source by passing a block to \n" \ + "the git method, like: \n\n" \ + " git 'git://github.com/rails/rails.git' do\n" \ + " gem 'rails'\n" \ + " end" + raise DeprecatedError, msg + end + + with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk) + end + + def github(repo, options = {}) + raise InvalidArgumentError, "GitHub sources require a block" unless block_given? + github_uri = @git_sources["github"].call(repo) + git_options = normalize_hash(options).merge("uri" => github_uri) + git_source = @sources.add_git_source(git_options) + with_source(git_source) { yield } + end + + def to_definition(lockfile, unlock) + check_primary_source_safety + lockfile = @lockfile unless @lockfile.nil? + Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) + end + + def group(*args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + normalize_group_options(options, args) + + @groups.concat args + + if options["optional"] + optional_groups = args - @optional_groups + @optional_groups.concat optional_groups + end + + yield + ensure + args.each { @groups.pop } + end + + def install_if(*args) + @install_conditionals.concat args + yield + ensure + args.each { @install_conditionals.pop } + end + + def platforms(*platforms) + @platforms.concat platforms + yield + ensure + platforms.each { @platforms.pop } + end + alias_method :platform, :platforms + + def env(name) + old = @env + @env = name + yield + ensure + @env = old + end + + def plugin(*args) + # Pass on + end + + def method_missing(name, *args) + raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" + end + + def check_primary_source_safety + check_path_source_safety + check_rubygems_source_safety + end + + private + + def add_dependency(name, version = nil, options = {}) + options["gemfile"] = @gemfile + options["source"] ||= @source + options["env"] ||= @env + + dep = Dependency.new(name, version, options) + + # if there's already a dependency with this name we try to prefer one + if current = @dependencies.find {|d| d.name == name } + if current.requirement != dep.requirement + current_requirement_open = current.requirements_list.include?(">= 0") + + gemspec_dep = [dep, current].find(&:gemspec_dev_dep?) + if gemspec_dep + require_relative "vendor/pub_grub/lib/pub_grub/version_range" + require_relative "vendor/pub_grub/lib/pub_grub/version_constraint" + require_relative "vendor/pub_grub/lib/pub_grub/version_union" + require_relative "vendor/pub_grub/lib/pub_grub/rubygems" + + current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement) + next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement) + + if current_gemspec_range.intersects?(next_gemspec_range) + dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options) + else + gemfile_dep = [dep, current].find(&:gemfile_dep?) + + if gemfile_dep + raise GemfileError, "The #{name} dependency has conflicting requirements in Gemfile (#{gemfile_dep.requirement}) and gemspec (#{gemspec_dep.requirement})" + else + raise GemfileError, "Two gemspec development dependencies have conflicting requirements on the same gem: #{dep} and #{current}" + end + end + else + update_prompt = "" + + if File.basename(@gemfile) == Injector::INJECTED_GEMS + if dep.requirements_list.include?(">= 0") && !current_requirement_open + update_prompt = ". Gem already added" + else + update_prompt = ". If you want to update the gem version, run `bundle update #{name}`" + + update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current_requirement_open + end + end + + raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ + "You specified: #{name} (#{current.requirement}) and #{name} (#{dep.requirement})" \ + "#{update_prompt}" + end + end + + unless current.gemspec_dev_dep? && dep.gemspec_dev_dep? + # Always prefer the dependency from the Gemfile + if current.gemspec_dev_dep? + @dependencies.delete(current) + elsif dep.gemspec_dev_dep? + return + elsif current.source.to_s != dep.source.to_s + raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ + "You specified that #{name} (#{dep.requirement}) should come from " \ + "#{current.source || "an unspecified source"} and #{dep.source}\n" + else + Bundler.ui.warn "Your Gemfile lists the gem #{name} (#{current.requirement}) more than once.\n" \ + "You should probably keep only one of them.\n" \ + "Remove any duplicate entries and specify the gem only once.\n" \ + "While it's not a problem now, it could cause errors if you change the version of one of them later." + end + end + end + + @dependencies << dep + end + + def with_gemfile(gemfile) + expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent) + original_gemfile = @gemfile + @gemfile = expanded_gemfile_path + @gemfiles << expanded_gemfile_path + yield @gemfile.to_s + ensure + @gemfile = original_gemfile + end + + def add_git_sources + git_source(:github) do |repo_name| + if repo_name =~ GITHUB_PULL_REQUEST_URL + { + "git" => "https://github.com/#{$1}.git", + "branch" => nil, + "ref" => "refs/pull/#{$2}/head", + "tag" => nil, + } + else + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://github.com/#{repo_name}.git" + end + end + + git_source(:gist) do |repo_name| + "https://gist.github.com/#{repo_name}.git" + end + + git_source(:bitbucket) do |repo_name| + user_name, repo_name = repo_name.split("/") + repo_name ||= user_name + "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" + end + + git_source(:gitlab) do |repo_name| + if repo_name =~ GITLAB_MERGE_REQUEST_URL + { + "git" => "https://gitlab.com/#{$1}.git", + "branch" => nil, + "ref" => "refs/merge-requests/#{$2}/head", + "tag" => nil, + } + else + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://gitlab.com/#{repo_name}.git" + end + end + end + + def with_source(source) + old_source = @source + if block_given? + @source = source + yield + end + source + ensure + @source = old_source + end + + def normalize_hash(opts) + opts.keys.each do |k| + opts[k.to_s] = opts.delete(k) unless k.is_a?(String) + end + opts + end + + def valid_keys + @valid_keys ||= VALID_KEYS + end + + def normalize_options(name, version, opts) + if name.is_a?(Symbol) + raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) + end + if /\s/.match?(name) + raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) + end + raise GemfileError, %(an empty gem name is not valid) if name.empty? + + normalize_hash(opts) + + git_names = @git_sources.keys.map(&:to_s) + validate_keys("gem '#{name}'", opts, valid_keys + git_names) + + groups = @groups.dup + opts["group"] = opts.delete("groups") || opts["group"] + groups.concat Array(opts.delete("group")) + groups = [:default] if groups.empty? + + install_if = @install_conditionals.dup + install_if.concat Array(opts.delete("install_if")) + install_if = install_if.reduce(true) do |memo, val| + memo && (val.respond_to?(:call) ? val.call : val) + end + + platforms = @platforms.dup + opts["platforms"] = opts["platform"] || opts["platforms"] + platforms.concat Array(opts.delete("platforms")) + platforms.map!(&:to_sym) + platforms.each do |p| + next if VALID_PLATFORMS.include?(p) + raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}" + end + + windows_platforms = platforms.select {|pl| pl.to_s.match?(/mingw|mswin/) } + if windows_platforms.any? + windows_platforms = windows_platforms.map! {|pl| ":#{pl}" }.join(", ") + deprecated_message = "Platform #{windows_platforms} will be removed in the future. Please use platform :windows instead." + Bundler::SharedHelpers.feature_deprecated! deprecated_message + end + + # Save sources passed in a key + if opts.key?("source") + source = normalize_source(opts["source"]) + opts["source"] = @sources.add_rubygems_source("remotes" => source) + end + + git_name = (git_names & opts.keys).last + if @git_sources[git_name] + git_opts = @git_sources[git_name].call(opts[git_name]) + git_opts = { "git" => git_opts } if git_opts.is_a?(String) + opts.merge!(git_opts) do |key, _gemfile_value, _git_source_value| + raise GemfileError, %(The :#{key} option can't be used with `#{git_name}: #{opts[git_name].inspect}`) + end + end + + %w[git path].each do |type| + next unless param = opts[type] + if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ + options = opts.merge("name" => name, "version" => $1) + else + options = opts.dup + end + source = send(type, param, options) {} + opts["source"] = source + end + + opts["platforms"] = platforms.dup + opts["group"] = groups + opts["should_include"] = install_if + end + + def normalize_group_options(opts, groups) + normalize_hash(opts) + + groups = groups.map {|group| ":#{group}" }.join(", ") + validate_keys("group #{groups}", opts, %w[optional]) + + opts["optional"] ||= false + end + + def validate_keys(command, opts, valid_keys) + if opts["branch"] && !(opts["git"] || opts["github"] || (opts.keys & @git_sources.keys.map(&:to_s)).any?) + raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) + end + + invalid_keys = opts.keys - valid_keys + return true unless invalid_keys.any? + + message = String.new + message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " + message << if invalid_keys.size > 1 + "as options for #{command}, but they are invalid." + else + "as an option for #{command}, but it is invalid." + end + + message << " Valid options are: #{valid_keys.join(", ")}." + message << " You may be able to resolve this by upgrading Bundler to the newest version." + raise InvalidOption, message + end + + def normalize_source(source) + case source + when :gemcutter, :rubygems, :rubyforge + removed_message = + "The source :#{source} is disallowed because HTTP requests are insecure.\n" \ + "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not." + Bundler::SharedHelpers.feature_removed! removed_message + when String + source + else + raise GemfileError, "Unknown source '#{source}'" + end + end + + def check_path_source_safety + return if @sources.global_path_source.nil? + + msg = "You can no longer specify a path source by itself. Instead, \n" \ + "either use the :path option on a gem, or specify the gems that \n" \ + "bundler should find in the path source by passing a block to \n" \ + "the path method, like: \n\n" \ + " path 'dir/containing/rails' do\n" \ + " gem 'rails'\n" \ + " end\n\n" + + SharedHelpers.feature_removed! msg.strip + end + + def check_rubygems_source_safety + multiple_global_source_warning if @sources.aggregate_global_source? + end + + def multiple_global_source_warning + msg = "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" + raise GemfileEvalError, msg + end + + class DSLError < GemfileError + # @return [String] the description that should be presented to the user. + # + attr_reader :description + + # @return [String] the path of the dsl file that raised the exception. + # + attr_reader :dsl_path + + # @return [Exception] the backtrace of the exception raised by the + # evaluation of the dsl file. + # + attr_reader :backtrace + + # @param [Exception] backtrace @see backtrace + # @param [String] dsl_path @see dsl_path + # + def initialize(description, dsl_path, backtrace, contents = nil) + @status_code = $!.respond_to?(:status_code) && $!.status_code + + @description = description + @dsl_path = dsl_path + @backtrace = backtrace + @contents = contents + end + + def status_code + @status_code || super + end + + # @return [String] the contents of the DSL that cause the exception to + # be raised. + # + def contents + @contents ||= dsl_path && File.exist?(dsl_path) && File.read(dsl_path) + end + + # The message of the exception reports the content of podspec for the + # line that generated the original exception. + # + # @example Output + # + # Invalid podspec at `RestKit.podspec` - undefined method + # `exclude_header_search_paths=' for # + # + # from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36 + # ------------------------------------------- + # # because it would break: #import + # > ns.exclude_header_search_paths = 'Code/RestKit.h' + # end + # ------------------------------------------- + # + # @return [String] the message of the exception. + # + def to_s + @to_s ||= begin + trace_line, description = parse_line_number_from_description + + m = String.new("\n[!] ") + m << description + m << ". Bundler cannot continue.\n" + + return m unless backtrace && dsl_path && contents + + trace_line = backtrace.find {|l| l.include?(dsl_path) } || trace_line + return m unless trace_line + # Match the line number right before `:in` or the end of the line so a + # Windows drive letter like `C:` does not get mistaken for the number. + line_number = trace_line[/:(\d+)(?::in\b|\z)/, 1] + return m unless line_number + line_number = line_number.to_i - 1 + + lines = contents.lines.to_a + indent = " # " + indicator = indent.tr("#", ">") + first_line = line_number.zero? + last_line = (line_number == (lines.count - 1)) + + m << "\n" + m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n" + m << "#{indent}-------------------------------------------\n" + m << "#{indent}#{lines[line_number - 1]}" unless first_line + m << "#{indicator}#{lines[line_number]}" + m << "#{indent}#{lines[line_number + 1]}" unless last_line + m << "\n" unless m.end_with?("\n") + m << "#{indent}-------------------------------------------\n" + end + end + + private + + def parse_line_number_from_description + description = self.description + if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path}):\d+)/ + trace_line = Regexp.last_match[1] + description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ") + end + [trace_line, description] + end + end + + def gemfile_root + @gemfile ||= Bundler.default_gemfile + @gemfile.dirname + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/endpoint_specification.rb b/bin/gems/bundler-4.0.21/lib/bundler/endpoint_specification.rb new file mode 100644 index 00000000..02d3ac37 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/endpoint_specification.rb @@ -0,0 +1,202 @@ +# frozen_string_literal: true + +module Bundler + # used for Creating Specifications from the Gemcutter Endpoint + class EndpointSpecification < Gem::Specification + include MatchRemoteMetadata + + attr_reader :name, :version, :platform, :checksum, :created_at + attr_writer :dependencies + attr_accessor :remote, :locked_platform + + def initialize(name, version, platform, spec_fetcher, dependencies, metadata = nil) + super() + @name = name + @version = Gem::Version.create version + @platform = Gem::Platform.new(platform) + @spec_fetcher = spec_fetcher + @dependencies = nil + @unbuilt_dependencies = dependencies + + @loaded_from = nil + @remote_specification = nil + @locked_platform = nil + + parse_metadata(metadata) + end + + def insecurely_materialized? + @locked_platform.to_s != @platform.to_s + end + + def fetch_platform + @platform + end + + def dependencies + @dependencies ||= @unbuilt_dependencies.map! {|dep, reqs| build_dependency(dep, reqs) } + end + alias_method :runtime_dependencies, :dependencies + + # needed for standalone, load required_paths from local gemspec + # after the gem is installed + def require_paths + if @remote_specification + @remote_specification.require_paths + elsif _local_specification + _local_specification.require_paths + else + super + end + end + + # `require_paths` is overridden above, but `full_require_paths` (and so + # `load_paths`) is computed from `raw_require_paths`, which would otherwise + # report the default `lib` for every gem + def raw_require_paths + if @remote_specification + @remote_specification.raw_require_paths + elsif _local_specification + _local_specification.raw_require_paths + else + super + end + end + + # needed for inline + def load_paths + # remote specs aren't installed, and can't have load_paths + if _local_specification + _local_specification.load_paths + else + super + end + end + + # needed for binstubs + def executables + if @remote_specification + @remote_specification.executables + elsif _local_specification + _local_specification.executables + else + super + end + end + + # needed for bundle clean + def bindir + if @remote_specification + @remote_specification.bindir + elsif _local_specification + _local_specification.bindir + else + super + end + end + + # needed for post_install_messages during install + def post_install_message + if @remote_specification + @remote_specification.post_install_message + elsif _local_specification + _local_specification.post_install_message + else + super + end + end + + # needed for "with native extensions" during install + def extensions + if @remote_specification + @remote_specification.extensions + elsif _local_specification + _local_specification.extensions + else + super + end + end + + # needed for `bundle fund` + def metadata + if @remote_specification + @remote_specification.metadata + elsif _local_specification + _local_specification.metadata + else + super + end + end + + def _local_specification + return unless @loaded_from && File.exist?(local_specification_path) + eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec| + spec.loaded_from = @loaded_from + end + end + + def __swap__(spec) + SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) + @remote_specification = spec + end + + def inspect + "#<#{self.class} @name=\"#{name}\" (#{full_name.delete_prefix("#{name}-")})>" + end + + private + + def _remote_specification + @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) + end + + def local_specification_path + "#{base_dir}/specifications/#{full_name}.gemspec" + end + + def parse_metadata(data) + unless data + @required_ruby_version = nil + @required_rubygems_version = nil + @created_at = nil + return + end + + data.each do |k, v| + next unless v + case k.to_s + when "checksum" + # Some registries send empty checksum values, treat them as if the + # checksum was not included at all + checksum = v.last + next unless checksum + + begin + @checksum = Checksum.from_api(checksum, @spec_fetcher.uri) + rescue ArgumentError => e + raise ArgumentError, "Invalid checksum for #{full_name}: #{e.message}" + end + when "rubygems" + @required_rubygems_version = Gem::Requirement.new(v) + when "ruby" + @required_ruby_version = Gem::Requirement.new(v) + when "created_at" + value = v.is_a?(Array) ? v.last : v + if value.is_a?(String) + @created_at = begin + Time.new(value) + rescue ArgumentError + nil + end + end + end + end + rescue StandardError => e + raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}" + end + + def build_dependency(name, requirements) + Dependency.new(name, requirements) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/env.rb b/bin/gems/bundler-4.0.21/lib/bundler/env.rb new file mode 100644 index 00000000..074bef6e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/env.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require_relative "rubygems_integration" +require_relative "source/git/git_proxy" + +module Bundler + class Env + def self.write(io) + io.write report + end + + def self.report(options = {}) + print_gemfile = options.delete(:print_gemfile) { true } + print_gemspecs = options.delete(:print_gemspecs) { true } + + out = String.new + append_formatted_table("Environment", environment, out) + append_formatted_table("Bundler Build Metadata", BuildMetadata.to_h, out) + + unless Bundler.settings.all.empty? + out << "\n## Bundler settings\n\n```\n" + Bundler.settings.all.each do |setting| + out << setting << "\n" + Bundler.settings.pretty_values_for(setting).each do |line| + out << " " << line << "\n" + end + end + out << "```\n" + end + + return out unless SharedHelpers.in_bundle? + + if print_gemfile + gemfiles = [Bundler.default_gemfile] + begin + gemfiles = Bundler.definition.gemfiles + rescue GemfileNotFound + nil + end + + out << "\n## Gemfile\n" + gemfiles.each do |gemfile| + out << "\n### #{SharedHelpers.relative_path_to(gemfile)}\n\n" + out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" + end + + out << "\n### #{SharedHelpers.relative_path_to(Bundler.default_lockfile)}\n\n" + out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" + end + + if print_gemspecs + dsl = Dsl.new.tap {|d| d.eval_gemfile(Bundler.default_gemfile) } + out << "\n## Gemspecs\n" unless dsl.gemspecs.empty? + dsl.gemspecs.each do |gs| + out << "\n### #{File.basename(gs.loaded_from)}" + out << "\n\n```ruby\n" << read_file(gs.loaded_from).chomp << "\n```\n" + end + end + + out + end + + def self.read_file(filename) + Bundler.read_file(filename.to_s).strip + rescue Errno::ENOENT + "" + rescue RuntimeError => e + "#{e.class}: #{e.message}" + end + + def self.ruby_version + "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]" + end + + def self.git_version + Bundler::Source::Git::GitProxy.new(nil, nil).full_version + rescue Bundler::Source::Git::GitNotInstalledError + "not installed" + end + + def self.version_of(script) + return "not installed" unless Bundler.which(script) + `#{script} --version`.chomp + end + + def self.chruby_version + return "not installed" unless Bundler.which("chruby-exec") + `chruby-exec -- chruby --version`. + sub(/.*^chruby: (#{Gem::Version::VERSION_PATTERN}).*/m, '\1') + end + + def self.environment + out = [] + + out << ["Bundler", Bundler::VERSION] + out << [" Platforms", Gem.platforms.join(", ")] + out << ["Ruby", ruby_version] + out << [" Full Path", Gem.ruby] + out << [" Config Dir", Pathname.new(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE).dirname] + out << ["RubyGems", Gem::VERSION] + out << [" Gem Home", Gem.dir] + out << [" Gem Path", Gem.path.join(File::PATH_SEPARATOR)] + out << [" User Home", Gem.user_home] + out << [" User Path", Gem.user_dir] + out << [" Bin Dir", Gem.bindir] + if defined?(OpenSSL::SSL) + out << ["OpenSSL"] + out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) + out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) + out << [" Cert File", OpenSSL::X509::DEFAULT_CERT_FILE] if defined?(OpenSSL::X509::DEFAULT_CERT_FILE) + out << [" Cert Dir", OpenSSL::X509::DEFAULT_CERT_DIR] if defined?(OpenSSL::X509::DEFAULT_CERT_DIR) + end + out << ["Tools"] + out << [" Git", git_version] + out << [" RVM", ENV.fetch("rvm_version") { version_of("rvm") }] + out << [" rbenv", version_of("rbenv")] + out << [" chruby", chruby_version] + + %w[rubygems-bundler open_gem].each do |name| + specs = Bundler.rubygems.find_name(name) + out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty? + end + if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z} + shebang = File.read(exe).lines.first + shebang.sub!(/^#!\s*/, "") + unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby") + out << ["Gem.ruby", Gem.ruby] + out << ["bundle #!", shebang] + end + end + + out + end + + def self.append_formatted_table(title, pairs, out) + return if pairs.empty? + out << "\n" unless out.empty? + out << "## #{title}\n\n```\n" + ljust = pairs.map {|k, _v| k.to_s.length }.max + pairs.each do |k, v| + out << "#{k.to_s.ljust(ljust)} #{v}\n" + end + out << "```\n" + end + + private_class_method :read_file, :ruby_version, :git_version, :append_formatted_table, :version_of, :chruby_version + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/environment_preserver.rb b/bin/gems/bundler-4.0.21/lib/bundler/environment_preserver.rb new file mode 100644 index 00000000..bf9478a2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/environment_preserver.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module Bundler + class EnvironmentPreserver + INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL" + BUNDLER_KEYS = %w[ + BUNDLE_BIN_PATH + BUNDLE_GEMFILE + BUNDLE_LOCKFILE + BUNDLER_VERSION + BUNDLER_SETUP + GEM_HOME + GEM_PATH + MANPATH + PATH + RB_USER_INSTALL + RUBYLIB + RUBYOPT + ].map(&:freeze).freeze + BUNDLER_PREFIX = "BUNDLER_ORIG_" + + def self.from_env + new(ENV.to_hash, BUNDLER_KEYS) + end + + # @param env [Hash] + # @param keys [Array] + def initialize(env, keys) + @original = env + @keys = keys + @prefix = BUNDLER_PREFIX + end + + # Replaces `ENV` with the bundler environment variables backed up + def replace_with_backup + ENV.replace(backup) + end + + # @return [Hash] + def backup + env = @original.clone + @keys.each do |key| + value = env[key] + if !value.nil? + env[@prefix + key] ||= value + else + env[@prefix + key] ||= INTENTIONALLY_NIL + end + end + env + end + + # @return [Hash] + def restore + env = @original.clone + @keys.each do |key| + value_original = env[@prefix + key] + next if value_original.nil? + if value_original == INTENTIONALLY_NIL + env.delete(key) + else + env[key] = value_original + end + env.delete(@prefix + key) + end + env + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/errors.rb b/bin/gems/bundler-4.0.21/lib/bundler/errors.rb new file mode 100644 index 00000000..8cd13363 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/errors.rb @@ -0,0 +1,277 @@ +# frozen_string_literal: true + +module Bundler + class BundlerError < StandardError + def self.status_code(code) + define_method(:status_code) { code } + if match = BundlerError.all_errors.find {|_k, v| v == code } + error, _ = match + raise ArgumentError, + "Trying to register #{self} for status code #{code} but #{error} is already registered" + end + BundlerError.all_errors[self] = code + end + + def self.all_errors + @all_errors ||= {} + end + end + + class GemfileError < BundlerError; status_code(4); end + class InstallError < BundlerError; status_code(5); end + + # Internal error, should be rescued + class SolveFailure < BundlerError; status_code(6); end + + class GemNotFound < BundlerError; status_code(7); end + class InstallHookError < BundlerError; status_code(8); end + class RemovedError < BundlerError; status_code(9); end + class GemfileNotFound < BundlerError; status_code(10); end + class GitError < BundlerError; status_code(11); end + class DeprecatedError < BundlerError; status_code(12); end + class PathError < BundlerError; status_code(13); end + class GemspecError < BundlerError; status_code(14); end + class InvalidOption < BundlerError; status_code(15); end + class ProductionError < BundlerError; status_code(16); end + + class HTTPError < BundlerError + status_code(17) + def filter_uri(uri) + URICredentialsFilter.credential_filtered_uri(uri) + end + end + + class RubyVersionMismatch < BundlerError; status_code(18); end + class SecurityError < BundlerError; status_code(19); end + class LockfileError < BundlerError; status_code(20); end + class CyclicDependencyError < BundlerError; status_code(21); end + class GemfileLockNotFound < BundlerError; status_code(22); end + class PluginError < BundlerError; status_code(29); end + class ThreadCreationError < BundlerError; status_code(33); end + class APIResponseMismatchError < BundlerError; status_code(34); end + class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end + class GemfileEvalError < GemfileError; end + class MarshalError < StandardError; end + + class ChecksumMismatchError < SecurityError + def initialize(lock_name, existing, checksum) + @lock_name = lock_name + @existing = existing + @checksum = checksum + end + + def message + <<~MESSAGE + Bundler found mismatched checksums. This is a potential security risk. + #{@lock_name} #{@existing.to_lock} + from #{@existing.sources.join("\n and ")} + #{@lock_name} #{@checksum.to_lock} + from #{@checksum.sources.join("\n and ")} + + #{mismatch_resolution_instructions} + To ignore checksum security warnings, disable checksum validation with + `bundle config set --local disable_checksum_validation true` + MESSAGE + end + + def mismatch_resolution_instructions + removable, remote = [@existing, @checksum].partition(&:removable?) + case removable.size + when 1 + msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n" + msg << removable.first.removal_instructions + when 2 + msg = +"To resolve this issue you can either:\n" + msg << @checksum.removal_instructions + msg << "or if you are sure that the new checksum from #{@checksum.sources.first} is correct:\n" + msg << @existing.removal_instructions + end + end + + status_code(37) + end + + class PermissionError < BundlerError + def initialize(path, permission_type = :write) + @path = path + @permission_type = permission_type + end + + def action + case @permission_type + when :read then "read from" + when :write then "write to" + when :executable, :exec then "execute" + else @permission_type.to_s + end + end + + def permission_type + case @permission_type + when :create + "executable permissions for all parent directories and write permissions for `#{parent_folder}`" + else + "#{@permission_type} permissions for that path" + end + end + + def parent_folder + File.dirname(@path) + end + + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "It is likely that you need to grant #{permission_type}." + end + + status_code(23) + end + + class GemRequireError < BundlerError + attr_reader :orig_exception + + def initialize(orig_exception, msg) + full_message = msg + "\nGem Load Error is: #{orig_exception.message}\n"\ + "Backtrace for gem load error is:\n"\ + "#{orig_exception.backtrace.join("\n")}\n"\ + "Bundler Error Backtrace:\n" + super(full_message) + @orig_exception = orig_exception + end + + status_code(24) + end + + class YamlSyntaxError < BundlerError + attr_reader :orig_exception + + def initialize(orig_exception, msg) + super(msg) + @orig_exception = orig_exception + end + + status_code(25) + end + + class TemporaryResourceError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "Some resource was temporarily unavailable. It's suggested that you try" \ + "the operation again." + end + + status_code(26) + end + + class VirtualProtocolError < BundlerError + def message + "There was an error relating to virtualization and file access. " \ + "It is likely that you need to grant access to or mount some file system correctly." + end + + status_code(27) + end + + class OperationNotSupportedError < PermissionError + def message + "Attempting to #{action} `#{@path}` is unsupported by your OS." + end + + status_code(28) + end + + class NoSpaceOnDeviceError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "There was insufficient space remaining on the device." + end + + status_code(31) + end + + class ReadOnlyFileSystemError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "File system is read-only." + end + + status_code(42) + end + + class OperationNotPermittedError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "Underlying OS system call raised an EPERM error." + end + + status_code(43) + end + + class GenericSystemCallError < BundlerError + attr_reader :underlying_error + + def initialize(underlying_error, message) + @underlying_error = underlying_error + super("#{message}\nThe underlying system error is #{@underlying_error.class}: #{@underlying_error}") + end + + status_code(32) + end + + class DirectoryRemovalError < BundlerError + def initialize(orig_exception, msg) + full_message = "#{msg}.\n" \ + "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \ + " #{orig_exception.backtrace.join("\n ")}\n\n" \ + "Bundler Error Backtrace:" + super(full_message) + end + + status_code(36) + end + + class InsecureInstallPathError < BundlerError + def initialize(name, path) + @name = name + @path = path + end + + def message + "Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \ + "The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \ + "Please change the permissions of #{File.dirname(@path)} or choose a different install path." + end + + status_code(38) + end + + class CorruptBundlerInstallError < BundlerError + def initialize(loaded_spec) + @loaded_spec = loaded_spec + end + + def message + "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \ + "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \ + "Reinstalling Ruby from scratch should fix the problem." + end + + status_code(39) + end + + class InvalidArgumentError < BundlerError; status_code(40); end + + class IncorrectLockfileDependencies < BundlerError + attr_reader :spec + + def initialize(spec) + @spec = spec + end + + def message + "Bundler found incorrect dependencies in the lockfile for #{spec.full_name}" + end + + status_code(41) + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/feature_flag.rb b/bin/gems/bundler-4.0.21/lib/bundler/feature_flag.rb new file mode 100644 index 00000000..dea8abed --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/feature_flag.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Bundler + class FeatureFlag + (1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } } + + def removed_major?(target_major_version) + @major_version > target_major_version + end + + def deprecated_major?(target_major_version) + @major_version >= target_major_version + end + + def initialize(bundler_version) + @bundler_version = Gem::Version.create(bundler_version) + @major_version = @bundler_version.segments.first + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher.rb new file mode 100644 index 00000000..ce6f5fdc --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher.rb @@ -0,0 +1,371 @@ +# frozen_string_literal: true + +require_relative "vendored_persistent" +require_relative "vendored_timeout" +require_relative "vendored_securerandom" +require "zlib" + +module Bundler + # Handles all the fetching with the rubygems server + class Fetcher + autoload :Base, File.expand_path("fetcher/base", __dir__) + autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__) + autoload :Downloader, File.expand_path("fetcher/downloader", __dir__) + autoload :Dependency, File.expand_path("fetcher/dependency", __dir__) + autoload :Index, File.expand_path("fetcher/index", __dir__) + + # This error is raised when it looks like the network is down + class NetworkDownError < HTTPError; end + # This error is raised if we should rate limit our requests to the API + class TooManyRequestsError < HTTPError; end + # This error is raised if the API returns a 413 (only printed in verbose) + class FallbackError < HTTPError; end + + # This is the error raised if OpenSSL fails the cert verification + class CertificateFailureError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Could not verify the SSL certificate for #{remote_uri}.\nThere" \ + " is a chance you are experiencing a man-in-the-middle attack, but" \ + " most likely your system doesn't have the CA certificates needed" \ + " for verification. For information about OpenSSL certificates, see" \ + " https://railsapps.github.io/openssl-certificate-verify-failed.html." + end + end + + # This is the error raised when a source is HTTPS and OpenSSL didn't load + class SSLError < HTTPError + def initialize(msg = nil) + super "Could not load OpenSSL.\n" \ + "You must recompile Ruby with OpenSSL support.\n" \ + "original error: #{msg}\n" + end + end + + # This error is raised if HTTP authentication is required, but not provided. + class AuthenticationRequiredError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Authentication is required for #{remote_uri}.\n" \ + "Please supply credentials for this source. You can do this by running:\n" \ + "`bundle config set --global #{remote_uri} username:password`\n" \ + "or by storing the credentials in the `#{Settings.key_for(remote_uri)}` environment variable" + end + end + + # This error is raised if HTTP authentication is provided, but incorrect. + class BadAuthenticationError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Bad username or password for #{remote_uri}.\n" \ + "Please double-check your credentials and correct them." + end + end + + # This error is raised if HTTP authentication is correct, but lacks + # necessary permissions. + class AuthenticationForbiddenError < HTTPError + def initialize(remote_uri) + remote_uri = filter_uri(remote_uri) + super "Access token could not be authenticated for #{remote_uri}.\n" \ + "Make sure it's valid and has the necessary scopes configured." + end + end + + HTTP_ERRORS = (Downloader::HTTP_RETRYABLE_ERRORS + Downloader::HTTP_NON_RETRYABLE_ERRORS).freeze + deprecate_constant :HTTP_ERRORS + + NET_ERRORS = [ + :HTTPBadGateway, + :HTTPBadRequest, + :HTTPFailedDependency, + :HTTPForbidden, + :HTTPInsufficientStorage, + :HTTPMethodNotAllowed, + :HTTPMovedPermanently, + :HTTPNoContent, + :HTTPNotFound, + :HTTPNotImplemented, + :HTTPPreconditionFailed, + :HTTPRequestEntityTooLarge, + :HTTPRequestURITooLong, + :HTTPUnauthorized, + :HTTPUnprocessableEntity, + :HTTPUnsupportedMediaType, + :HTTPVersionNotSupported, + ].freeze + deprecate_constant :NET_ERRORS + + # Exceptions classes that should bypass retry attempts. If your password didn't work the + # first time, it's not going to the third time. + FAIL_ERRORS = [ + AuthenticationRequiredError, + BadAuthenticationError, + AuthenticationForbiddenError, + FallbackError, + SecurityError, + Gem::Requirement::BadRequirementError, + Gem::Net::HTTPBadGateway, + Gem::Net::HTTPBadRequest, + Gem::Net::HTTPFailedDependency, + Gem::Net::HTTPForbidden, + Gem::Net::HTTPInsufficientStorage, + Gem::Net::HTTPMethodNotAllowed, + Gem::Net::HTTPMovedPermanently, + Gem::Net::HTTPNoContent, + Gem::Net::HTTPNotFound, + Gem::Net::HTTPNotImplemented, + Gem::Net::HTTPPreconditionFailed, + Gem::Net::HTTPRequestEntityTooLarge, + Gem::Net::HTTPRequestURITooLong, + Gem::Net::HTTPUnauthorized, + Gem::Net::HTTPUnprocessableEntity, + Gem::Net::HTTPUnsupportedMediaType, + Gem::Net::HTTPVersionNotSupported, + ].freeze + + class << self + attr_accessor :disable_endpoint, :api_timeout, :redirect_limit, :max_retries + end + + self.redirect_limit = Bundler.settings[:redirect] # How many redirects to allow in one request + self.api_timeout = Bundler.settings[:timeout] # How long to wait for each API call + self.max_retries = Bundler.settings[:retry] # How many retries for the API call + + def initialize(remote) + @cis = nil + @remote = remote + + Socket.do_not_reverse_lookup = true + connection # create persistent connection + end + + def uri + @remote.anonymized_uri + end + + # fetch a gem specification + def fetch_spec(spec) + spec -= [nil, "ruby", ""] + spec_file_name = "#{spec.join "-"}.gemspec" + + uri = Gem::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") + spec = if uri.scheme == "file" + path = Gem::Util.correct_for_windows_path(uri.path) + Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) + elsif cached_spec_path = gemspec_cached_path(spec_file_name) + Bundler.load_gemspec(cached_spec_path) + else + Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) + end + raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification) + spec + rescue MarshalError + raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ + "Your network or your gem server is probably having issues right now." + end + + # return the specs in the bundler format as an index with retries + def specs_with_retry(gem_names, source) + Bundler::Retry.new("fetcher", FAIL_ERRORS).attempts do + specs(gem_names, source) + end + end + + # return the specs in the bundler format as an index + def specs(gem_names, source) + index = Bundler::Index.new + + fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata| + spec = if dependencies + EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es| + source.checksum_store.replace(es, es.checksum) + end + else + RemoteSpecification.new(name, version, platform, self) + end + spec.source = source + spec.remote = @remote + index << spec + end + + index + rescue CertificateFailureError + Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots + raise + end + + def user_agent + @user_agent ||= begin + ruby = Bundler::RubyVersion.system + + agent = String.new("bundler/#{Bundler::VERSION}") + agent << " rubygems/#{Gem::VERSION}" + agent << " ruby/#{ruby.versions_string(ruby.versions)}" + agent << " (#{ruby.host})" + agent << " command/#{ARGV.first}" + + if ruby.engine != "ruby" + # engine_version raises on unknown engines + engine_version = begin + ruby.engine_versions + rescue RuntimeError + "???" + end + agent << " #{ruby.engine}/#{ruby.versions_string(engine_version)}" + end + + # Some settings keys embed a URI (e.g. `mirror.`) whose userinfo can + # carry credentials. Strip the userinfo before advertising the setting + # names so we don't leak secrets to every gem source we talk to. + options = Bundler.settings.all.map do |key| + key.include?("://") ? key.gsub(%r{//[^/@]+@}, "//") : key + end + agent << " options/#{options.join(",")}" + + agent << " ci/#{cis.join(",")}" if cis.any? + + # add a random ID so we can consolidate runs server-side + agent << " " << Gem::SecureRandom.hex(8) + + # add any user agent strings set in the config + extra_ua = Bundler.settings[:user_agent] + agent << " " << extra_ua if extra_ua + + agent + end + end + + def http_proxy + return unless uri = connection.proxy_uri + uri.to_s + end + + def inspect + "#<#{self.class}:0x#{object_id} uri=#{uri}>" + end + + def api_fetcher? + fetchers.first.api_fetcher? + end + + def release_resolution_memory! + @fetchers&.each(&:release_resolution_memory!) + end + + def gem_remote_fetcher + @gem_remote_fetcher ||= begin + require_relative "fetcher/gem_remote_fetcher" + fetcher = GemRemoteFetcher.new Gem.configuration[:http_proxy] + fetcher.headers["User-Agent"] = user_agent + fetcher.headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri + fetcher + end + end + + private + + def available_fetchers + if Bundler::Fetcher.disable_endpoint + [Index] + elsif remote_uri.scheme == "file" + Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API") + [Index] + else + [CompactIndex, Dependency, Index] + end + end + + def fetchers + @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri, gem_remote_fetcher) }.drop_while {|f| !f.available? } + end + + def fetch_specs(gem_names) + fetchers.reject!(&:api_fetcher?) unless gem_names + fetchers.reject! do |f| + specs = f.specs(gem_names) + return specs if specs + true + end + [] + end + + def cis + @cis ||= Bundler::CIDetector.ci_strings + end + + def connection + @connection ||= begin + needs_ssl = remote_uri.scheme == "https" || + Bundler.settings[:ssl_verify_mode] || + Bundler.settings[:ssl_client_cert] + if needs_ssl + begin + require "openssl" + rescue StandardError, LoadError => e + raise SSLError.new(e.message) + end + end + + con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV + if gem_proxy = Gem.configuration[:http_proxy] + con.proxy = Gem::URI.parse(gem_proxy) if gem_proxy != :no_proxy + end + + if remote_uri.scheme == "https" + con.verify_mode = (Bundler.settings[:ssl_verify_mode] || + OpenSSL::SSL::VERIFY_PEER) + con.cert_store = bundler_cert_store + end + + ssl_client_cert = Bundler.settings[:ssl_client_cert] || + (Gem.configuration.ssl_client_cert if + Gem.configuration.respond_to?(:ssl_client_cert)) + if ssl_client_cert + pem = File.read(ssl_client_cert) + con.cert = OpenSSL::X509::Certificate.new(pem) + con.key = OpenSSL::PKey.read(pem) + end + + con.read_timeout = Fetcher.api_timeout + con.open_timeout = Fetcher.api_timeout + con.override_headers["User-Agent"] = user_agent + con.override_headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri + con + end + end + + # cached gem specification path, if one exists + def gemspec_cached_path(spec_file_name) + paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) } + paths.find {|path| File.file? path } + end + + def bundler_cert_store + store = OpenSSL::X509::Store.new + ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || + (Gem.configuration.ssl_ca_cert if + Gem.configuration.respond_to?(:ssl_ca_cert)) + if ssl_ca_cert + if File.directory? ssl_ca_cert + store.add_path ssl_ca_cert + else + store.add_file ssl_ca_cert + end + else + store.set_default_paths + require "rubygems/request" + Gem::Request.get_cert_files.each {|c| store.add_file c } + end + store + end + + def remote_uri + @remote.uri + end + + def downloader + @downloader ||= Downloader.new(connection, self.class.redirect_limit) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/base.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/base.rb new file mode 100644 index 00000000..8012bbc7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/base.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Bundler + class Fetcher + class Base + attr_reader :downloader + attr_reader :display_uri + attr_reader :remote + attr_reader :gem_remote_fetcher + + def initialize(downloader, remote, display_uri, gem_remote_fetcher) + raise "Abstract class" if self.class == Base + @downloader = downloader + @remote = remote + @display_uri = display_uri + @gem_remote_fetcher = gem_remote_fetcher + end + + def remote_uri + @remote.uri + end + + def fetch_uri + @fetch_uri ||= if remote_uri.host == "rubygems.org" + uri = remote_uri.dup + uri.host = "index.rubygems.org" + uri + else + remote_uri + end + end + + def available? + true + end + + def api_fetcher? + false + end + + def release_resolution_memory! + end + + private + + def log_specs(&block) + if Bundler.ui.debug? + Bundler.ui.debug yield + else + Bundler.ui.info ".", false + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/compact_index.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/compact_index.rb new file mode 100644 index 00000000..b41d42b7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/compact_index.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +require_relative "base" +require_relative "../worker" + +module Bundler + class Fetcher + class CompactIndex < Base + def self.compact_index_request(method_name) + method = instance_method(method_name) + undef_method(method_name) + define_method(method_name) do |*args, &blk| + method.bind_call(self, *args, &blk) + rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e + raise HTTPError, e.message + rescue AuthenticationRequiredError, BadAuthenticationError + # Fail since we got a 401 from the server. + raise + rescue HTTPError => e + Bundler.ui.trace(e) + nil + end + end + + def specs(gem_names) + specs_for_names(gem_names) + end + compact_index_request :specs + + def specs_for_names(gem_names) + gem_info = [] + complete_gems = [] + remaining_gems = gem_names.dup + + until remaining_gems.empty? + log_specs { "Looking up gems #{remaining_gems.inspect}" } + deps = fetch_gem_infos(remaining_gems).flatten(1) + next_gems = deps.flat_map {|d| d[CompactIndexClient::INFO_DEPS].flat_map(&:first) }.uniq + deps.each {|dep| gem_info << dep } + complete_gems.concat(deps.map(&:first)).uniq! + remaining_gems = next_gems - complete_gems + end + @bundle_worker&.stop + @bundle_worker = nil # reset it. Not sure if necessary + + gem_info + end + + def available? + unless SharedHelpers.md5_available? + Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API") + return nil + end + # Read info file checksums out of /versions, so we can know if gems are up to date + compact_index_client.available? + rescue CompactIndexClient::Updater::MismatchedChecksumError => e + Bundler.ui.debug(e.message) + nil + end + compact_index_request :available? + + def api_fetcher? + true + end + + # The client holds the parsed checksums of all info files in the + # index. Dropping it is always safe because it is rebuilt from the + # local cache on demand. + def release_resolution_memory! + @compact_index_client = nil + end + + private + + def compact_index_client + @compact_index_client ||= + SharedHelpers.filesystem_access(cache_path) do + CompactIndexClient.new(cache_path, client_fetcher) + end + end + + def fetch_gem_infos(names) + # Create the client and update the versions file on this thread. + # Otherwise the workers race to lazily create the client and update + # the versions file concurrently, e.g. when the client was released + # after resolution and is being rebuilt for `bundle cache`. + compact_index_client.available? + + in_parallel(names) {|name| compact_index_client.info(name) } + rescue TooManyRequestsError # rubygems.org is rate limiting us, slow down. + @bundle_worker&.stop + @bundle_worker = nil # reset it. Not sure if necessary + compact_index_client.reset! + names.map {|name| compact_index_client.info(name) } + end + + def in_parallel(inputs, &blk) + func = lambda {|object, _index| blk.call(object) } + worker = bundle_worker(func) + inputs.each {|input| worker.enq(input) } + inputs.map { worker.deq } + end + + def bundle_worker(func = nil) + @bundle_worker ||= begin + worker_name = "Compact Index (#{display_uri.host})" + Bundler::Worker.new(Bundler.settings.processor_count, worker_name, func) + end + @bundle_worker.tap do |worker| + worker.instance_variable_set(:@func, func) if func + end + end + + def cache_path + Bundler.user_cache.join("compact_index", remote.cache_slug) + end + + def client_fetcher + ClientFetcher.new(self, Bundler.ui) + end + + ClientFetcher = Struct.new(:fetcher, :ui) do + def call(path, headers) + fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) + rescue NetworkDownError => e + raise unless headers["If-None-Match"] + ui.warn "Using the cached data for the new index because of a network error: #{e}" + Gem::Net::HTTPNotModified.new(nil, nil, nil) + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/dependency.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/dependency.rb new file mode 100644 index 00000000..4f2414e3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/dependency.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require_relative "base" +require "cgi/escape" +require "cgi/util" unless defined?(CGI::EscapeExt) + +module Bundler + class Fetcher + class Dependency < Base + def available? + @available ||= fetch_uri.scheme != "file" && downloader.fetch(dependency_api_uri) + rescue NetworkDownError => e + raise HTTPError, e.message + rescue AuthenticationRequiredError + # Fail since we got a 401 from the server. + raise + rescue HTTPError + false + end + + def api_fetcher? + true + end + + def specs(gem_names, full_dependency_list = [], last_spec_list = []) + query_list = gem_names.uniq - full_dependency_list + + log_specs { "Query List: #{query_list.inspect}" } + + return last_spec_list if query_list.empty? + + spec_list, deps_list = Bundler::Retry.new("dependency api", FAIL_ERRORS).attempts do + dependency_specs(query_list) + end + + returned_gems = spec_list.map(&:first).uniq + specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) + rescue MarshalError, HTTPError, GemspecError + Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over + Bundler.ui.debug "could not fetch from the dependency API, trying the full index" + nil + end + + def dependency_specs(gem_names) + Bundler.ui.debug "Query Gemcutter Dependency Endpoint API: #{gem_names.join(",")}" + + gem_list = unmarshalled_dep_gems(gem_names) + get_formatted_specs_and_deps(gem_list) + end + + def unmarshalled_dep_gems(gem_names) + gem_list = [] + gem_names.each_slice(api_request_size) do |names| + marshalled_deps = downloader.fetch(dependency_api_uri(names)).body + gem_list.concat(Bundler.safe_load_marshal(marshalled_deps)) + end + gem_list + end + + def get_formatted_specs_and_deps(gem_list) + deps_list = [] + spec_list = [] + + gem_list.each do |s| + deps_list.concat(s[:dependencies].map(&:first)) + deps = s[:dependencies].map {|n, d| [n, d.split(", ")] } + spec_list.push([s[:name], s[:number], s[:platform], deps]) + end + [spec_list, deps_list] + end + + def dependency_api_uri(gem_names = []) + uri = fetch_uri + "api/v1/dependencies" + uri.query = "gems=#{CGI.escape(gem_names.sort.join(","))}" if gem_names.any? + uri + end + + private + + def api_request_size + Bundler.settings[:api_request_size]&.to_i || Source::Rubygems::API_REQUEST_SIZE + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/downloader.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/downloader.rb new file mode 100644 index 00000000..d9cb819d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/downloader.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module Bundler + class Fetcher + class Downloader + HTTP_NON_RETRYABLE_ERRORS = [ + SocketError, + Errno::EADDRNOTAVAIL, + Errno::ENETDOWN, + Errno::ENETUNREACH, + Gem::Net::HTTP::Persistent::Error, + Errno::EHOSTUNREACH, + ].freeze + + HTTP_RETRYABLE_ERRORS = [ + Gem::Timeout::Error, + EOFError, + Errno::EINVAL, + Errno::ECONNRESET, + Errno::ETIMEDOUT, + Errno::EAGAIN, + Gem::Net::HTTPBadResponse, + Gem::Net::HTTPHeaderSyntaxError, + Gem::Net::ProtocolError, + Zlib::BufError, + ].freeze + + attr_reader :connection + attr_reader :redirect_limit + + def initialize(connection, redirect_limit) + @connection = connection + @redirect_limit = redirect_limit + end + + def fetch(uri, headers = {}, counter = 0) + raise HTTPError, "Too many redirects" if counter >= redirect_limit + + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + + response = request(uri, headers) + Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") + + case response + when Gem::Net::HTTPSuccess, Gem::Net::HTTPNotModified + response + when Gem::Net::HTTPRedirection + new_uri = Gem::URI.parse(response["location"]) + # Following a downgrade would put the credentials this request carries + # on a plaintext connection, so refuse it like Gem::RemoteFetcher does. + if https?(uri) && !https?(new_uri) + raise HTTPError, "Redirecting to a non-https URI is not allowed: #{URICredentialsFilter.credential_filtered_uri(new_uri)}" + end + if new_uri.host == uri.host + new_uri.user = uri.user + new_uri.password = uri.password + end + fetch(new_uri, headers, counter + 1) + when Gem::Net::HTTPRequestedRangeNotSatisfiable + new_headers = headers.dup + new_headers.delete("Range") + fetch(uri, new_headers) + when Gem::Net::HTTPRequestEntityTooLarge + raise FallbackError, response.body + when Gem::Net::HTTPTooManyRequests + raise TooManyRequestsError, response.body + when Gem::Net::HTTPUnauthorized + raise BadAuthenticationError, uri.host if uri.userinfo + raise AuthenticationRequiredError, uri.host + when Gem::Net::HTTPForbidden + raise AuthenticationForbiddenError, uri.host + when Gem::Net::HTTPNotFound + raise FallbackError, "Gem::Net::HTTPNotFound: #{filtered_uri}" + else + message = "Gem::#{response.class.name.gsub(/\AGem::/, "")}" + message += ": #{response.body}" unless response.body.empty? + raise HTTPError, message + end + end + + def request(uri, headers) + validate_uri_scheme!(uri) + + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + + Bundler.ui.debug "HTTP GET #{filtered_uri}" + req = Gem::Net::HTTP::Get.new uri.request_uri, headers + if uri.user + user = CGI.unescape(uri.user) + password = uri.password ? CGI.unescape(uri.password) : nil + req.basic_auth(user, password) + end + connection.request(uri, req) + rescue OpenSSL::SSL::SSLError + raise CertificateFailureError.new(uri) + rescue *HTTP_NON_RETRYABLE_ERRORS => e + Bundler.ui.trace e + + host = uri.host + host_port = "#{host}:#{uri.port}" + host = host_port if filtered_uri.to_s.include?(host_port) + raise NetworkDownError, "Could not reach host #{host}. Check your network " \ + "connection and try again." + rescue *HTTP_RETRYABLE_ERRORS => e + Bundler.ui.trace e + + raise HTTPError, "Network error while fetching #{filtered_uri}" \ + " (#{e})" + end + + private + + def https?(uri) + uri.scheme&.casecmp("https")&.zero? + end + + def validate_uri_scheme!(uri) + return if /\Ahttps?\z/.match?(uri.scheme) + raise InvalidOption, + "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \ + "Did you mean `http` or `https`?" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/gem_remote_fetcher.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/gem_remote_fetcher.rb new file mode 100644 index 00000000..d53a7ea5 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/gem_remote_fetcher.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require "rubygems/remote_fetcher" + +module Bundler + class Fetcher + class GemRemoteFetcher < Gem::RemoteFetcher + def initialize(*) + super + + @pool_size = Bundler.settings.installation_parallelization + ssl_ca_cert = Bundler.settings[:ssl_ca_cert] + @cert_files << ssl_ca_cert if ssl_ca_cert + end + + def request(*args) + super do |req| + req.delete("User-Agent") if headers["User-Agent"] + yield req if block_given? + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/fetcher/index.rb b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/index.rb new file mode 100644 index 00000000..6e37e1e5 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/fetcher/index.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "base" + +module Bundler + class Fetcher + class Index < Base + def specs(_gem_names) + Bundler.rubygems.fetch_all_remote_specs(remote, gem_remote_fetcher) + rescue Gem::RemoteFetcher::FetchError => e + case e.message + when /certificate verify failed/ + raise CertificateFailureError.new(display_uri) + when /401/ + raise BadAuthenticationError, remote_uri if remote_uri.userinfo + raise AuthenticationRequiredError, remote_uri + when /403/ + raise AuthenticationForbiddenError, remote_uri + else + raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>" + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/force_platform.rb b/bin/gems/bundler-4.0.21/lib/bundler/force_platform.rb new file mode 100644 index 00000000..7af33218 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/force_platform.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Bundler + module ForcePlatform + # The `:force_ruby_platform` value used by dependencies for resolution, and + # by locked specifications for materialization is `false` by default, except + # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform + # variant unless the name is explicitly allowlisted. + + def default_force_ruby_platform + return false unless RUBY_ENGINE == "truffleruby" + + !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/friendly_errors.rb b/bin/gems/bundler-4.0.21/lib/bundler/friendly_errors.rb new file mode 100644 index 00000000..5e8eaee6 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/friendly_errors.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require_relative "vendored_thor" + +module Bundler + module FriendlyErrors + module_function + + def enable! + @disabled = false + end + + def disabled? + @disabled + end + + def disable! + @disabled = true + end + + def log_error(error) + case error + when YamlSyntaxError + Bundler.ui.error error.message + Bundler.ui.trace error.orig_exception + when Dsl::DSLError, GemspecError + Bundler.ui.error error.message + when GemRequireError + Bundler.ui.error error.message + Bundler.ui.trace error.orig_exception + when BundlerError + if Bundler.ui.debug? + Bundler.ui.trace error + else + Bundler.ui.error error.message, wrap: true + end + when Thor::Error + Bundler.ui.error error.message + when Interrupt + Bundler.ui.error "\nQuitting..." + Bundler.ui.trace error + when Gem::InvalidSpecificationException + Bundler.ui.error error.message, wrap: true + when SystemExit + when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact + Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \ + "You can decrease the amount of memory Bundler needs by removing gems from your Gemfile, " \ + "especially large gems. (Gems can be as large as hundreds of megabytes, and Bundler has to read those files!). " \ + "Alternatively, you can increase the amount of memory the JVM is able to use by running Bundler with jruby -J-Xmx1024m -S bundle (JRuby defaults to 500MB)." + else request_issue_report_for(error) + end + end + + def exit_status(error) + case error + when BundlerError then error.status_code + when Thor::Error then 15 + when SystemExit then error.status + else 1 + end + end + + def request_issue_report_for(e) + Bundler.ui.error <<~EOS, nil, nil + --- ERROR REPORT TEMPLATE ------------------------------------------------------- + + ``` + #{exception_message(e)} + ``` + + #{Bundler::Env.report} + --- TEMPLATE END ---------------------------------------------------------------- + + EOS + + Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue." + + Bundler.ui.error <<~EOS, nil, :yellow + + First, try this link to see if there are any existing issue reports for this error: + #{issues_url(e)} + + If there aren't any reports for this error yet, please fill in the new issue form located at #{new_issue_url}. Make sure to copy and paste the full output of this command under the "What happened instead?" section. + EOS + end + + def exception_message(error) + message = serialized_exception_for(error) + cause = error.cause + return message unless cause + + message + serialized_exception_for(cause) + end + + def serialized_exception_for(e) + <<~EOS + #{e.class}: #{e.message} + #{e.backtrace&.join("\n ")&.chomp} + EOS + end + + def issues_url(exception) + message = exception.message.lines.first.tr(":", " ").chomp + message = message.split("-").first if exception.is_a?(Errno) + require "cgi/escape" + require "cgi/util" unless defined?(CGI::EscapeExt) + "https://github.com/ruby/rubygems/search?q=" \ + "#{CGI.escape(message)}&type=Issues" + end + + def new_issue_url + "https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md" + end + end + + def self.with_friendly_errors + FriendlyErrors.enable! + yield + rescue SignalException + raise + rescue Exception => e # rubocop:disable Lint/RescueException + raise if FriendlyErrors.disabled? + + FriendlyErrors.log_error(e) + exit FriendlyErrors.exit_status(e) + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/gem_helper.rb b/bin/gems/bundler-4.0.21/lib/bundler/gem_helper.rb new file mode 100644 index 00000000..e3af1b95 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/gem_helper.rb @@ -0,0 +1,237 @@ +# frozen_string_literal: true + +require_relative "../bundler" +require "shellwords" + +module Bundler + class GemHelper + include Rake::DSL if defined? Rake::DSL + + class << self + # set when install'd. + attr_accessor :instance + + def install_tasks(opts = {}) + new(opts[:dir], opts[:name]).install + end + + def tag_prefix=(prefix) + instance.tag_prefix = prefix + end + + def gemspec(&block) + gemspec = instance.gemspec + block&.call(gemspec) + gemspec + end + end + + attr_reader :spec_path, :base, :gemspec + + attr_writer :tag_prefix + + def initialize(base = nil, name = nil) + @base = File.expand_path(base || SharedHelpers.pwd) + gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : SharedHelpers.glob_files_in_dir("{,*}.gemspec", @base) + raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 + @spec_path = gemspecs.first + @gemspec = Bundler.load_gemspec(@spec_path) + @tag_prefix = "" + end + + def install + built_gem_path = nil + + desc "Build #{name}-#{version}.gem into the pkg directory." + task "build" do + built_gem_path = build_gem + end + + desc "Generate SHA512 checksum of #{name}-#{version}.gem into the checksums directory." + task "build:checksum" => "build" do + build_checksum(built_gem_path) + end + + desc "Build and install #{name}-#{version}.gem into system gems." + task "install" => "build" do + install_gem(built_gem_path) + end + + desc "Build and install #{name}-#{version}.gem into system gems without network access." + task "install:local" => "build" do + install_gem(built_gem_path, :local) + end + + desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to #{gem_push_host}\n" \ + "To prevent publishing in RubyGems use `gem_push=no rake release`" + task "release", [:remote] => ["build", "release:guard_clean", + "release:source_control_push", "release:rubygem_push"] do + end + + task "release:guard_clean" do + guard_clean + end + + task "release:source_control_push", [:remote] do |_, args| + tag_version { git_push(args[:remote]) } unless already_tagged? + end + + task "release:rubygem_push" => "build" do + rubygem_push(built_gem_path) if gem_push? + end + + GemHelper.instance = self + end + + def build_gem + file_name = nil + sh([*gem_command, "build", "-V", spec_path]) do + file_name = File.basename(built_gem_path) + SharedHelpers.filesystem_access(File.join(base, "pkg")) {|p| FileUtils.mkdir_p(p) } + FileUtils.mv(built_gem_path, "pkg") + Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}." + end + File.join(base, "pkg", file_name) + end + + def install_gem(built_gem_path = nil, local = false) + built_gem_path ||= build_gem + cmd = [*gem_command, "install", built_gem_path.to_s] + cmd << "--local" if local + sh(cmd) + Bundler.ui.confirm "#{name} (#{version}) installed." + end + + def build_checksum(built_gem_path = nil) + built_gem_path ||= build_gem + SharedHelpers.filesystem_access(File.join(base, "checksums")) {|p| FileUtils.mkdir_p(p) } + file_name = "#{File.basename(built_gem_path)}.sha512" + require "digest/sha2" + checksum = ::Digest::SHA512.file(built_gem_path).hexdigest + target = File.join(base, "checksums", file_name) + File.write(target, checksum + "\n") + Bundler.ui.confirm "#{name} #{version} checksum written to checksums/#{file_name}." + end + + protected + + def rubygem_push(path) + cmd = [*gem_command, "push", path] + cmd << "--key" << gem_key if gem_key + cmd << "--host" << allowed_push_host if allowed_push_host + sh_with_input(cmd) + Bundler.ui.confirm "Pushed #{name} #{version} to #{gem_push_host}" + end + + def built_gem_path + SharedHelpers.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last + end + + def git_push(remote = nil) + remote ||= default_remote + sh("git push #{remote} refs/heads/#{current_branch}".shellsplit) + sh("git push #{remote} refs/tags/#{version_tag}".shellsplit) + Bundler.ui.confirm "Pushed git commits and release tag." + end + + def default_remote + remote_for_branch, status = sh_with_status(%W[git config --get branch.#{current_branch}.remote]) + return "origin" unless status.success? + + remote_for_branch.strip + end + + def current_branch + # We can replace this with `git branch --show-current` once we drop support for git < 2.22.0 + sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip + end + + def allowed_push_host + @gemspec.metadata["allowed_push_host"] if @gemspec.respond_to?(:metadata) + end + + def gem_push_host + env_rubygems_host = ENV["RUBYGEMS_HOST"] + env_rubygems_host = nil if env_rubygems_host&.empty? + + allowed_push_host || env_rubygems_host || "rubygems.org" + end + + def already_tagged? + return false unless sh(%w[git tag]).split(/\n/).include?(version_tag) + Bundler.ui.confirm "Tag #{version_tag} has already been created." + true + end + + def guard_clean + clean? && committed? || raise("There are files that need to be committed first.") + end + + def clean? + sh_with_status(%w[git diff --exit-code])[1].success? + end + + def committed? + sh_with_status(%w[git diff-index --quiet --cached HEAD])[1].success? + end + + def tag_version + sh %W[git tag -m Version\ #{version} #{version_tag}] + Bundler.ui.confirm "Tagged #{version_tag}." + yield if block_given? + rescue RuntimeError + Bundler.ui.error "Untagging #{version_tag} due to error." + sh_with_status %W[git tag -d #{version_tag}] + raise + end + + def version + gemspec.version + end + + def version_tag + "#{@tag_prefix}v#{version}" + end + + def name + gemspec.name + end + + def sh_with_input(cmd) + Bundler.ui.debug(cmd) + SharedHelpers.chdir(base) do + abort unless Kernel.system(*cmd) + end + end + + def sh(cmd, &block) + out, status = sh_with_status(cmd, &block) + unless status.success? + raise("Running `#{cmd.shelljoin}` failed with the following output:\n\n#{out}\n") + end + out + end + + def sh_with_status(cmd, &block) + Bundler.ui.debug(cmd) + SharedHelpers.chdir(base) do + outbuf = IO.popen(cmd, err: [:child, :out], &:read) + status = $? + block&.call(outbuf) if status.success? + [outbuf, status] + end + end + + def gem_key + Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"] + end + + def gem_push? + !%w[n no nil false off 0].include?(ENV["gem_push"].to_s.downcase) + end + + def gem_command + ENV["GEM_COMMAND"]&.shellsplit || ["gem"] + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/gem_tasks.rb b/bin/gems/bundler-4.0.21/lib/bundler/gem_tasks.rb new file mode 100644 index 00000000..bc725d36 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/gem_tasks.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "rake/clean" +CLOBBER.include "pkg" + +require_relative "gem_helper" +Bundler::GemHelper.install_tasks diff --git a/bin/gems/bundler-4.0.21/lib/bundler/gem_version_promoter.rb b/bin/gems/bundler-4.0.21/lib/bundler/gem_version_promoter.rb new file mode 100644 index 00000000..d64dbacf --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/gem_version_promoter.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +module Bundler + # This class contains all of the logic for determining the next version of a + # Gem to update to based on the requested level (patch, minor, major). + # Primarily designed to work with Resolver which will provide it the list of + # available dependency versions as found in its index, before returning it to + # to the resolution engine to select the best version. + class GemVersionPromoter + attr_reader :level + attr_accessor :pre + + # By default, strict is false, meaning every available version of a gem + # is returned from sort_versions. The order gives preference to the + # requested level (:patch, :minor, :major) but in complicated requirement + # cases some gems will by necessity be promoted past the requested level, + # or even reverted to older versions. + # + # If strict is set to true, the results from sort_versions will be + # truncated, eliminating any version outside the current level scope. + # This can lead to unexpected outcomes or even VersionConflict exceptions + # that report a version of a gem not existing for versions that indeed do + # existing in the referenced source. + attr_accessor :strict + + # Creates a GemVersionPromoter instance. + # + # @return [GemVersionPromoter] + def initialize + @level = :major + @strict = false + @pre = false + end + + # @param value [Symbol] One of three Symbols: :major, :minor or :patch. + def level=(value) + v = case value + when String, Symbol + value.to_sym + end + + raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v) + @level = v + end + + # Given a Resolver::Package and an Array of Specifications of available + # versions for a gem, this method will return the Array of Specifications + # sorted in an order to give preference to the current level (:major, :minor + # or :patch) when resolution is deciding what versions best resolve all + # dependencies in the bundle. + # @param package [Resolver::Package] The package being resolved. + # @param specs [Specification] An array of Specifications for the package. + # @return [Specification] A new instance of the Specification Array sorted. + def sort_versions(package, specs) + locked_version = package.locked_version + + result = specs.sort do |a, b| + unless package.prerelease_specified? || pre? + a_pre = a.prerelease? + b_pre = b.prerelease? + + next 1 if a_pre && !b_pre + next -1 if b_pre && !a_pre + end + + if major? || locked_version.nil? + b <=> a + elsif either_version_older_than_locked?(a, b, locked_version) + b <=> a + elsif segments_do_not_match?(a, b, :major) + a <=> b + elsif !minor? && segments_do_not_match?(a, b, :minor) + a <=> b + else + b <=> a + end + end + post_sort(result, package.unlock?, locked_version) + end + + # @return [bool] Convenience method for testing value of level variable. + def major? + level == :major + end + + # @return [bool] Convenience method for testing value of level variable. + def minor? + level == :minor + end + + # @return [bool] Convenience method for testing value of pre variable. + def pre? + pre == true + end + + # Given a Resolver::Package and an Array of Specifications of available + # versions for a gem, this method will truncate the Array if strict + # is true. That means filtering out downgrades from the version currently + # locked, and filtering out upgrades that go past the selected level (major, + # minor, or patch). + # @param package [Resolver::Package] The package being resolved. + # @param specs [Specification] An array of Specifications for the package. + # @return [Specification] A new instance of the Specification Array + # truncated. + def filter_versions(package, specs) + return specs unless strict + + locked_version = package.locked_version + return specs if locked_version.nil? || major? + + specs.select do |spec| + gsv = spec.version + + must_match = minor? ? [0] : [0, 1] + + all_match = must_match.all? {|idx| gsv.segments[idx] == locked_version.segments[idx] } + all_match && gsv >= locked_version + end + end + + private + + def either_version_older_than_locked?(a, b, locked_version) + a.version < locked_version || b.version < locked_version + end + + def segments_do_not_match?(a, b, level) + index = [:major, :minor].index(level) + a.segments[index] != b.segments[index] + end + + # Specific version moves can't always reliably be done during sorting + # as not all elements are compared against each other. + def post_sort(result, unlock, locked_version) + if unlock || locked_version.nil? + result + else + move_version_to_beginning(result, locked_version) + end + end + + def move_version_to_beginning(result, version) + move, keep = result.partition {|s| s.version.to_s == version.to_s } + move.concat(keep) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/index.rb b/bin/gems/bundler-4.0.21/lib/bundler/index.rb new file mode 100644 index 00000000..9aef2dfa --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/index.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +module Bundler + class Index + include Enumerable + + def self.build + i = new + yield i + i + end + + attr_reader :specs, :duplicates, :sources + protected :specs, :duplicates + + RUBY = "ruby" + NULL = "\0" + + def initialize + @sources = [] + @cache = {} + @specs = {} + @duplicates = {} + end + + def initialize_copy(o) + @sources = o.sources.dup + @cache = {} + @specs = {} + @duplicates = {} + + o.specs.each do |name, hash| + @specs[name] = hash.dup + end + o.duplicates.each do |name, array| + @duplicates[name] = array.dup + end + end + + def inspect + "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>" + end + + def empty? + each { return false } + true + end + + # Search this index's specs, and any source indexes that this index knows + # about, returning all of the results. + def search(query) + results = local_search(query) + return results unless @sources.any? + + @sources.each do |source| + results = safe_concat(results, source.search(query)) + end + results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH + results + end + + alias_method :[], :search + + def local_search(query) + case query + when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) + when String then specs_by_name(query) + when Array then specs_by_name_and_version(*query) + else + raise "You can't search for a #{query.inspect}." + end + end + + def add(spec) + (@specs[spec.name] ||= {}).store(spec.full_name, spec) + end + alias_method :<<, :add + + def each(&blk) + return enum_for(:each) unless blk + specs.values.each do |spec_sets| + spec_sets.values.each(&blk) + end + sources.each {|s| s.each(&blk) } + self + end + + def spec_names + names = specs.keys + sources.map(&:spec_names) + names.uniq! + names + end + + def unmet_dependency_names + dependency_names.select do |name| + search(name).empty? + end + end + + def dependency_names + names = [] + each do |spec| + spec.dependencies.each do |dep| + next if dep.type == :development + names << dep.name + end + end + names.uniq + end + + # Combines indexes proritizing existing specs, like `Hash#reverse_merge!` + # Duplicate specs found in `other` are stored in `@duplicates`. + def use(other) + return unless other + other.each do |spec| + exist?(spec) ? add_duplicate(spec) : add(spec) + end + self + end + + # Combines indexes proritizing specs from `other`, like `Hash#merge!` + # Duplicate specs found in `self` are saved in `@duplicates`. + def merge!(other) + return unless other + other.each do |spec| + if existing = find_by_spec(spec) + unless dependencies_eql?(existing, spec) + Bundler.ui.warn "Local specification for #{spec.full_name} has different dependencies than the remote gem, ignoring it" + next + end + + add_duplicate(existing) + end + add spec + end + self + end + + def size + @sources.inject(@specs.size) do |size, source| + size += source.size + end + end + + # Whether all the specs in self are in other + def subset?(other) + all? do |spec| + other_spec = other[spec].first + other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source + end + end + + def dependencies_eql?(spec, other_spec) + deps = spec.runtime_dependencies + other_deps = other_spec.runtime_dependencies + deps.sort == other_deps.sort + end + + def add_source(index) + raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index) + @sources << index + @sources.uniq! # need to use uniq! here instead of checking for the item before adding + end + + private + + def safe_concat(a, b) + return a if b.empty? + return b if a.empty? + a.concat(b) + end + + def add_duplicate(spec) + (@duplicates[spec.name] ||= []) << spec + end + + def specs_by_name_and_version(name, version) + results = @specs[name]&.values + return EMPTY_SEARCH unless results + results.select! {|spec| spec.version == version } + results + end + + def specs_by_name(name) + @specs[name]&.values || EMPTY_SEARCH + end + + EMPTY_SEARCH = [].freeze + + def search_by_spec(spec) + spec = find_by_spec(spec) + spec ? [spec] : EMPTY_SEARCH + end + + def find_by_spec(spec) + @specs[spec.name]&.fetch(spec.full_name, nil) + end + + def exist?(spec) + @specs[spec.name]&.key?(spec.full_name) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/injector.rb b/bin/gems/bundler-4.0.21/lib/bundler/injector.rb new file mode 100644 index 00000000..3f8bf14e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/injector.rb @@ -0,0 +1,284 @@ +# frozen_string_literal: true + +module Bundler + class Injector + INJECTED_GEMS = "injected gems" + + def self.inject(new_deps, options = {}) + injector = new(new_deps, options) + injector.inject(Bundler.default_gemfile, Bundler.default_lockfile) + end + + def self.remove(gems, options = {}) + injector = new(gems, options) + injector.remove(Bundler.default_gemfile, Bundler.default_lockfile) + end + + def initialize(deps, options = {}) + @deps = deps + @options = options + end + + # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency. + # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency. + # @return [Array] + def inject(gemfile_path, lockfile_path) + Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true) + + # temporarily unfreeze + Bundler.settings.temporary(deployment: false, frozen: false) do + # evaluate the Gemfile we have now + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + # don't inject any gems that are already in the Gemfile + @deps -= builder.dependencies + + # add new deps to the end of the in-memory Gemfile + # Set conservative versioning to false because + # we want to let the resolver resolve the version first + builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any? + + # resolve to see if the new deps broke anything + @definition = builder.to_definition(lockfile_path, {}) + @definition.remotely! + + # since nothing broke, we can add those gems to the gemfile + append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any? + + # since we resolved successfully, write out the lockfile + @definition.lock + + # invalidate the cached Bundler.definition + Bundler.reset_paths! + + # return an array of the deps that we added + @deps + end + end + + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + # @param [Pathname] lockfile_path The lockfile from which to remove dependencies. + # @return [Array] + def remove(gemfile_path, lockfile_path) + # remove gems from each gemfiles we have + Bundler.definition.gemfiles.each do |path| + deps = remove_deps(path) + + show_warning("No gems were removed from the gemfile.") if deps.empty? + + deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep)} was removed." } + end + + # Invalidate the cached Bundler.definition. + # This prevents e.g. `bundle remove ...` from using outdated information. + Bundler.reset_paths! + end + + private + + def conservative_version(spec) + version = spec.version + return ">= 0" if version.nil? + seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2 + + prerelease_suffix = version.to_s.delete_prefix(version.release.to_s) if version.prerelease? + "#{version_prefix}#{version.segments[0..seg_end_index].join(".")}#{prerelease_suffix}" + end + + def version_prefix + if @options[:strict] + "= " + elsif @options[:optimistic] + ">= " + else + "~> " + end + end + + def build_gem_lines(conservative_versioning) + @deps.map do |d| + name = d.name.dump + + requirement = if conservative_versioning + ", \"#{conservative_version(@definition.specs[d.name][0])}\"" + else + ", #{d.requirement.as_list.map(&:dump).join(", ")}" + end + + if d.groups != Array(:default) + group = d.groups.size == 1 ? ", group: #{d.groups.first.inspect}" : ", groups: #{d.groups.inspect}" + end + + source = ", source: \"#{d.source}\"" unless d.source.nil? + path = ", path: \"#{d.path}\"" unless d.path.nil? + git = ", git: \"#{d.git}\"" unless d.git.nil? + github = ", github: \"#{d.github}\"" unless d.github.nil? + branch = ", branch: \"#{d.branch}\"" unless d.branch.nil? + ref = ", ref: \"#{d.ref}\"" unless d.ref.nil? + glob = ", glob: \"#{d.glob}\"" unless d.glob.nil? + require_path = ", require: #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil? + + %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{glob}#{require_path}) + end.join("\n") + end + + def append_to(gemfile_path, new_gem_lines) + gemfile_path.open("a") do |f| + f.puts + f.puts new_gem_lines + end + end + + # evaluates a gemfile to remove the specified gem + # from it. + def remove_deps(gemfile_path) + initial_gemfile = File.readlines(gemfile_path) + + Bundler.ui.info "Removing gems from #{gemfile_path}" + + # evaluate the Gemfile we have + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) + + # abort the operation if no gems were removed + # no need to operate on gemfile further + return [] if removed_deps.empty? + + cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) + + SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile) + + # check for errors + # including extra gems being removed + # or some gems not being removed + # and return the actual removed deps + cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile) + end + + # @param [Dsl] builder Dsl object of current Gemfile. + # @param [Array] gems Array of names of gems to be removed. + # @param [Pathname] gemfile_path Path of the Gemfile. + # @return [Array] Array of removed dependencies. + def remove_gems_from_dependencies(builder, gems, gemfile_path) + removed_deps = [] + + gems.each do |gem_name| + deleted_dep = builder.dependencies.find {|d| d.name == gem_name } + + if deleted_dep.nil? + raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed." + end + + builder.dependencies.delete(deleted_dep) + + removed_deps << deleted_dep + end + + removed_deps + end + + # @param [Array] gems Array of names of gems to be removed. + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + def remove_gems_from_gemfile(gems, gemfile_path) + patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2.*\)/ + new_gemfile = [] + multiline_removal = false + File.readlines(gemfile_path).each do |line| + match_data = line.match(patterns) + if match_data && is_not_within_comment?(line, match_data) + multiline_removal = line.rstrip.end_with?(",") + # skip lines which match the regex + next + end + + # skip followup lines until line does not end with ',' + new_gemfile << line unless multiline_removal + multiline_removal = line.rstrip.end_with?(",") if multiline_removal + end + + # remove line \n and append them with other strings + new_gemfile.each_with_index do |_line, index| + if new_gemfile[index + 1] == "\n" + new_gemfile[index] += new_gemfile[index + 1] + new_gemfile.delete_at(index + 1) + end + end + + %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) } + + new_gemfile.join.chomp + end + + # @param [String] line Individual line of gemfile content. + # @param [MatchData] match_data Data about Regex match. + def is_not_within_comment?(line, match_data) + match_start_index = match_data.offset(0).first + !line[0..match_start_index].include?("#") + end + + # @param [Array] gemfile Array of gemfile contents. + # @param [String] block_name Name of block name to look for. + def remove_nested_blocks(gemfile, block_name) + nested_blocks = 0 + + # count number of nested blocks + gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) } + + while nested_blocks >= 0 + nested_blocks -= 1 + + gemfile.each_with_index do |line, index| + next unless !line.nil? && line.strip.start_with?(block_name) + if /^\s*end\s*$/.match?(gemfile[index + 1]) + gemfile[index] = nil + gemfile[index + 1] = nil + end + end + + gemfile.compact! + end + end + + # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. + # @param [Array] original_deps Array of original dependencies. + # @param [Array] removed_deps Array of removed dependencies. + # @param [Array] initial_gemfile Contents of original Gemfile before any operation. + def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) + # evaluate the new gemfile to look for any failure cases + builder = Dsl.new + builder.eval_gemfile(gemfile_path) + + # record gems which were removed but not requested + extra_removed_gems = original_deps - builder.dependencies + + # if some extra gems were removed then raise error + # and revert Gemfile to original + unless extra_removed_gems.empty? + SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join) + + raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue." + end + + # record gems which could not be removed due to some reasons + errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path } + + show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty? + + # return actual removed dependencies + removed_deps - errored_deps + end + + def show_warning(message) + Bundler.ui.info Bundler.ui.add_color(message, :yellow) + end + + def convert_autorequire(autorequire) + autorequire = autorequire.first + return autorequire if autorequire == "false" + autorequire.inspect + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/inline.rb b/bin/gems/bundler-4.0.21/lib/bundler/inline.rb new file mode 100644 index 00000000..c861bee1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/inline.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +# Allows for declaring a Gemfile inline in a ruby script, installing any gems +# that aren't already installed on the user's system. +# +# @note Every gem that is specified in this 'Gemfile' will be `require`d, as if +# the user had manually called `Bundler.require`. To avoid a requested gem +# being automatically required, add the `:require => false` option to the +# `gem` dependency declaration. +# +# @param force_latest_compatible [Boolean] Force installing the *latest* +# compatible versions of the gems, +# even if compatible versions are +# already installed locally. +# This also logs output if the +# `:quiet` option is not set. +# Defaults to `false`. +# +# @param gemfile [Proc] a block that is evaluated as a `Gemfile`. +# +# @example Using an inline Gemfile +# +# #!/usr/bin/env ruby +# +# require 'bundler/inline' +# +# gemfile do +# source 'https://rubygems.org' +# gem 'json', require: false +# gem 'nap', require: 'rest' +# gem 'cocoapods', '~> 0.34.1' +# end +# +# puts Pod::VERSION # => "0.34.4" +# +def gemfile(force_latest_compatible = false, options = {}, &gemfile) + require_relative "../bundler" + Bundler.reset! + + opts = options.dup + ui = opts.delete(:ui) { Bundler::UI::Shell.new } + ui.level = "silent" if opts.delete(:quiet) || !force_latest_compatible + Bundler.ui = ui + raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? + + old_gemfile = ENV["BUNDLE_GEMFILE"] + old_lockfile = ENV["BUNDLE_LOCKFILE"] + + Bundler.unbundle_env! + + begin + Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir)) + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" + Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock" + + Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins] + builder = Bundler::Dsl.new + builder.instance_eval(&gemfile) + + Bundler.settings.temporary(deployment: false, frozen: false) do + definition = builder.to_definition(nil, true) + definition.validate_runtime! + + if force_latest_compatible || definition.missing_specs? + Bundler.settings.temporary(inline: true, no_install: false) do + installer = Bundler::Installer.install(Bundler.root, definition, system: true) + installer.post_install_messages.each do |name, message| + Bundler.ui.info "Post-install message from #{name}:\n#{message}" + end + end + end + + begin + runtime = Bundler::Runtime.new(nil, definition).setup + rescue Gem::LoadError => e + name = e.name + version = e.requirement.requirements.first[1] + activated_version = Gem.loaded_specs[name].version + + Bundler.ui.info \ + "The #{name} gem was resolved to #{version}, but #{activated_version} was activated by Bundler while installing it, causing a conflict. " \ + "Bundler will now retry resolving with #{activated_version} instead." + + builder.dependencies.delete_if {|d| d.name == name } + builder.instance_eval { gem name, activated_version } + definition = builder.to_definition(nil, true) + + retry + end + + runtime.require + end + ensure + if old_gemfile + ENV["BUNDLE_GEMFILE"] = old_gemfile + else + ENV["BUNDLE_GEMFILE"] = "" + end + + if old_lockfile + ENV["BUNDLE_LOCKFILE"] = old_lockfile + else + ENV["BUNDLE_LOCKFILE"] = "" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/installer.rb new file mode 100644 index 00000000..c3de428c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/installer.rb @@ -0,0 +1,247 @@ +# frozen_string_literal: true + +require_relative "worker" +require_relative "installer/parallel_installer" +require_relative "installer/standalone" +require_relative "installer/gem_installer" + +module Bundler + class Installer + attr_reader :post_install_messages, :definition + + # Begins the installation process for Bundler. + # For more information see the #run method on this class. + def self.install(root, definition, options = {}) + installer = new(root, definition) + Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL_ALL, definition.dependencies) + installer.run(options) + Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL_ALL, definition.dependencies) + installer + end + + def initialize(root, definition) + @root = root + @definition = definition + @post_install_messages = {} + end + + # Runs the install procedures for a specific Gemfile. + # + # Firstly, this method will check to see if `Bundler.bundle_path` exists + # and if not then Bundler will create the directory. This is usually the same + # location as RubyGems which typically is the `~/.gem` directory + # unless other specified. + # + # Secondly, it checks if Bundler has been configured to be "frozen". + # Frozen ensures that the Gemfile and the Gemfile.lock file are matching. + # This stops a situation where a developer may update the Gemfile but may not run + # `bundle install`, which leads to the Gemfile.lock file not being correctly updated. + # If this file is not correctly updated then any other developer running + # `bundle install` will potentially not install the correct gems. + # + # Thirdly, Bundler checks if there are any dependencies specified in the Gemfile. + # If there are no dependencies specified then Bundler returns a warning message stating + # so and this method returns. + # + # Fourthly, Bundler checks if the Gemfile.lock exists, and if so + # then proceeds to set up a definition based on the Gemfile and the Gemfile.lock. + # During this step Bundler will also download information about any new gems + # that are not in the Gemfile.lock and resolve any dependencies if needed. + # + # Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote. + # This then leads into the gems being installed, along with stubs for their executables, + # but only if the --binstubs option has been passed or Bundler.options[:bin] has been set + # earlier. + # + # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time + # that a user runs `bundle install` they will receive any updates from this process. + # + # Finally, if the user has specified the standalone flag, Bundler will generate the needed + # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more + # information. + def run(options) + Bundler.create_bundle_path + + ProcessLock.lock do + # Invalidate any stale gem specification cache from before we acquired the lock. + # Another process may have installed gems while we were waiting. + Gem::Specification.reset + @definition.sources.clear_cache + + @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment]) + + if @definition.dependencies.empty? + Bundler.ui.warn "The Gemfile specifies no dependencies" + lock + return + end + + if @definition.setup_domain!(options) + ensure_specs_are_compatible! + load_plugins + end + install(options) + + Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available + # Drop the source caches too, since releasing resolution memory dropped + # the source indexes. A resolution happening after this point would + # otherwise rebuild them around a snapshot of installed gems taken + # before the install, and materialize against remote specs that don't + # know where the gems they stand for ended up. + @definition.sources.clear_cache + + lock + Standalone.new(options[:standalone], @definition).generate if options[:standalone] + end + end + + def generate_bundler_executable_stubs(spec, options = {}) + if spec.name == "bundler" + Bundler.ui.warn "Bundler itself does not use binstubs because its version is selected by RubyGems" + return + end + + if options[:binstubs_cmd] && spec.executables.empty? + options = {} + spec.runtime_dependencies.each do |dep| + bins = @definition.specs[dep].first.executables + options[dep.name] = bins unless bins.empty? + end + if options.any? + Bundler.ui.warn "#{spec.name} has no executables, but you may want " \ + "one from a gem it depends on." + options.each {|name, bins| Bundler.ui.warn " #{name} has: #{bins.join(", ")}" } + else + Bundler.ui.warn "There are no executables for the gem #{spec.name}." + end + return + end + + # double-assignment to avoid warnings about variables that will be used by ERB + bin_path = Bundler.bin_path + bin_path = bin_path + relative_gemfile_path = Bundler.default_gemfile.relative_path_from(bin_path) + relative_gemfile_path = relative_gemfile_path + ruby_command = Thor::Util.ruby_command + ruby_command = ruby_command + template_path = File.expand_path("templates/Executable", __dir__) + template = File.read(template_path) + + exists = [] + spec.executables.each do |executable| + binstub_path = "#{bin_path}/#{executable}" + if File.exist?(binstub_path) && !options[:force] + exists << executable + next + end + + mode = Gem.win_platform? ? "wb:UTF-8" : "w" + require "erb" + content = ERB.new(template, trim_mode: "-").result(binding) + + File.write(binstub_path, content, mode: mode, perm: 0o777 & ~File.umask) + if Gem.win_platform? || options[:all_platforms] + prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" + File.write("#{binstub_path}.cmd", prefix + content, mode: mode) + end + end + + if options[:binstubs_cmd] && exists.any? + case exists.size + when 1 + Bundler.ui.warn "Skipped #{exists[0]} since it already exists." + when 2 + Bundler.ui.warn "Skipped #{exists.join(" and ")} since they already exist." + else + items = exists[0...-1].empty? ? nil : exists[0...-1].join(", ") + skipped = [items, exists[-1]].compact.join(" and ") + Bundler.ui.warn "Skipped #{skipped} since they already exist." + end + Bundler.ui.warn "If you want to overwrite skipped stubs, use --force." + end + end + + def generate_standalone_bundler_executable_stubs(spec, options = {}) + # double-assignment to avoid warnings about variables that will be used by ERB + bin_path = Bundler.bin_path + unless path = Bundler.settings[:path] + raise "Can't standalone without an explicit path set" + end + standalone_path = Bundler.root.join(path).relative_path_from(bin_path) + standalone_path = standalone_path + template = File.read(File.expand_path("templates/Executable.standalone", __dir__)) + ruby_command = Thor::Util.ruby_command + ruby_command = ruby_command + + spec.executables.each do |executable| + next if executable == "bundle" + executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) + executable_path = executable_path + + mode = Gem.win_platform? ? "wb:UTF-8" : "w" + require "erb" + content = ERB.new(template, trim_mode: "-").result(binding) + + File.write("#{bin_path}/#{executable}", content, mode: mode, perm: 0o755) + if Gem.win_platform? || options[:all_platforms] + prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" + File.write("#{bin_path}/#{executable}.cmd", prefix + content, mode: mode) + end + end + end + + private + + # the order that the resolver provides is significant, since + # dependencies might affect the installation of a gem. + # that said, it's a rare situation (other than rake), and parallel + # installation is SO MUCH FASTER. so we let people opt in. + def install(options) + standalone = options[:standalone] + force = options[:force] + local = options[:local] || options[:"prefer-local"] + jobs = Bundler.settings.installation_parallelization + specs = @definition.specs + # Installing default gems may need the remote index again to cache + # their .gem files, so keep resolution memory around in that case. + # The bundler spec itself is excluded because it comes from the + # metadata source and never goes through that path. + @definition.release_resolution_memory! if specs.none? {|s| s.default_gem? && s.source.is_a?(Source::Rubygems) } + spec_installations = ParallelInstaller.call(self, specs, jobs, standalone, force, local: local) + spec_installations.each do |installation| + post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message? + end + end + + def load_plugins + Gem.load_plugins + + requested_path_gems = @definition.specs.select {|s| s.source.is_a?(Source::Path) } + path_plugin_files = requested_path_gems.flat_map do |spec| + spec.matches_for_glob("rubygems_plugin#{Bundler.rubygems.suffix_pattern}") + rescue TypeError + error_message = "#{spec.name} #{spec.version} has an invalid gemspec" + raise Gem::InvalidSpecificationException, error_message + end + Gem.load_plugin_files(path_plugin_files) + Gem.load_env_plugins + end + + def ensure_specs_are_compatible! + @definition.specs.each do |spec| + unless spec.matches_current_ruby? + raise InstallError, "#{spec.full_name} requires ruby version #{spec.required_ruby_version}, " \ + "which is incompatible with the current version, #{Gem.ruby_version}" + end + unless spec.matches_current_rubygems? + raise InstallError, "#{spec.full_name} requires rubygems version #{spec.required_rubygems_version}, " \ + "which is incompatible with the current version, #{Gem.rubygems_version}" + end + end + end + + def lock + @definition.lock + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/installer/gem_installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/installer/gem_installer.rb new file mode 100644 index 00000000..f3b43c31 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/installer/gem_installer.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +module Bundler + class GemInstaller + attr_reader :spec, :standalone, :worker, :force, :local, :installer + + def initialize(spec, installer, standalone = false, worker = 0, force = false, local = false) + @spec = spec + @installer = installer + @standalone = standalone + @worker = worker + @force = force + @local = local + end + + def install_from_spec + post_install_message = install + Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}" + [true, post_install_message] + rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError, Bundler::InsecureInstallPathError + raise + rescue Errno::ENOSPC + [false, out_of_space_message] + rescue Bundler::BundlerError, Gem::InstallError => e + [false, specific_failure_message(e)] + end + + def download + spec.source.download( + spec, + force: force, + local: local, + build_args: Array(spec_settings), + previous_spec: previous_spec, + ) + + [true, nil] + rescue Bundler::BundlerError => e + [false, specific_failure_message(e)] + end + + private + + def specific_failure_message(e) + message = "#{e.class}: #{e.message}\n" + message += " " + e.backtrace.join("\n ") + "\n\n" + message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear) + message + Bundler.ui.add_color(failure_message, :red) + end + + def failure_message + install_error_message + end + + def install_error_message + "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue." + end + + def spec_settings + # Fetch the build settings, if there are any + if settings = Bundler.settings["build.#{spec.name}"] + require "shellwords" + Shellwords.shellsplit(settings) + end + end + + def install + spec.source.install( + spec, + force: force, + local: local, + build_args: Array(spec_settings), + previous_spec: previous_spec, + ) + end + + def previous_spec + locked_gems = installer.definition.locked_gems + return unless locked_gems + + locked_gems.specs.find {|s| s.name == spec.name } + end + + def out_of_space_message + "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle." + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/installer/parallel_installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/installer/parallel_installer.rb new file mode 100644 index 00000000..9a46f408 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/installer/parallel_installer.rb @@ -0,0 +1,294 @@ +# frozen_string_literal: true + +require_relative "../worker" +require_relative "gem_installer" + +module Bundler + class ParallelInstaller + class SpecInstallation + attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error, :dependencies + def initialize(spec) + @spec = spec + @name = spec.name + @full_name = spec.full_name + @state = :none + @post_install_message = "" + @error = nil + end + + def installed? + state == :installed + end + + def enqueued? + state == :enqueued + end + + def enqueue_with_priority? + state == :installable && spec.extensions.any? + end + + def failed? + state == :failed + end + + def ready_to_enqueue? + state == :none + end + + def ready_to_install?(installed_specs) + return false unless state == :downloaded + + spec.extensions.none? || dependencies_installed?(installed_specs) + end + + def has_post_install_message? + !post_install_message.empty? + end + + # Recursively checks that all dependencies (direct and transitive) have been installed. + def dependencies_installed?(installed_specs) + dependencies.all? do |dep| + installed_specs.include?(dep.name) && dep.dependencies_installed?(installed_specs) + end + end + + def to_s + "#<#{self.class} #{full_name} (#{state})>" + end + end + + def self.call(*args, **kwargs) + new(*args, **kwargs).call + end + + attr_reader :size + + def initialize(installer, all_specs, size, standalone, force, local: false, skip: nil) + @installer = installer + @size = size + @standalone = standalone + @force = force + @local = local + @specs = all_specs.map {|s| SpecInstallation.new(s) } + specs_by_name = @specs.to_h {|s| [s.name, s] } + @specs.each do |spec_install| + spec_install.dependencies = spec_install.spec.dependencies.filter_map do |dep| + specs_by_name[dep.name] unless dep.type == :development || dep.name == spec_install.name + end + end + @specs.each do |spec_install| + spec_install.state = :installed if skip.include?(spec_install.name) + end if skip + @spec_set = all_specs + @rake = @specs.find {|s| s.name == "rake" unless s.installed? } + end + + def call + if @rake + do_download(@rake, 0) + do_install(@rake, 0) + Gem::Specification.reset + end + + if @size > 1 + install_with_worker + else + install_serially + end + + handle_error if failed_specs.any? + @specs + ensure + worker_pool&.stop + end + + private + + def failed_specs + @specs.select(&:failed?) + end + + def install_with_worker + with_jobserver do + installed_specs = {} + enqueue_specs(installed_specs) + + process_specs(installed_specs) until finished_installing? + end + end + + def with_jobserver + # The jobserver hands tokens to child `make` processes through MAKEFLAGS + # using the GNU make `--jobserver-auth` protocol. nmake, the default make + # on mswin, instead reads MAKEFLAGS as bare option letters and aborts + # every native extension build with `fatal error U1065: invalid option + # '-'`. Skip the jobserver when nmake is in use. Other Windows toolchains + # such as mingw use GNU make and keep working through the inherited pipe. + return yield if nmake? || bsd_make? + + begin + r, w = IO.pipe + r.close_on_exec = false + w.close_on_exec = false + w.write("*" * @size) + + old_makeflags = ENV["MAKEFLAGS"] + ENV["MAKEFLAGS"] = [old_makeflags, "--jobserver-auth=#{r.fileno},#{w.fileno}"].compact.join(" ") + + yield + ensure + # Restore MAKEFLAGS before closing the pipe so a close failure can't + # leave the process with descriptors that point at a closed pipe. + old_makeflags ? ENV["MAKEFLAGS"] = old_makeflags : ENV.delete("MAKEFLAGS") + + r&.close + w&.close + end + end + + # Mirror how RubyGems' extension builder picks the make program so the + # jobserver is only set up when a GNU-compatible make will consume it. + def nmake? + make = ENV["MAKE"] || ENV["make"] + make ||= "nmake" if RUBY_PLATFORM.include?("mswin") + /\bnmake/i.match?(make.to_s) + end + + def bsd_make? + return false unless Gem.freebsd_platform? + make = ENV["MAKE"] || ENV["make"] || "make" + !/\bgmake/i.match?(make) + end + + def install_serially + until finished_installing? + raise "failed to find a spec to enqueue while installing serially" unless spec_install = @specs.find(&:ready_to_enqueue?) + spec_install.state = :enqueued + do_download(spec_install, 0) + do_install(spec_install, 0) + end + end + + def worker_pool + @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda {|spec_install, worker_num| + case spec_install.state + when :enqueued + do_download(spec_install, worker_num) + when :installable + do_install(spec_install, worker_num) + else + spec_install + end + } + end + + def do_download(spec_install, worker_num) + Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install) + + gem_installer = Bundler::GemInstaller.new( + spec_install.spec, @installer, @standalone, worker_num, @force, @local + ) + + success, message = gem_installer.download + + if success + spec_install.state = :downloaded + else + spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" + spec_install.state = :failed + end + + spec_install + end + + def do_install(spec_install, worker_num) + gem_installer = Bundler::GemInstaller.new( + spec_install.spec, @installer, @standalone, worker_num, @force, @local + ) + success, message = gem_installer.install_from_spec + if success + spec_install.state = :installed + spec_install.post_install_message = message unless message.nil? + else + spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}" + spec_install.state = :failed + end + Plugin.hook(Plugin::Events::GEM_AFTER_INSTALL, spec_install) + spec_install + end + + # Dequeue a spec and save its post-install message and then enqueue the + # remaining specs. + # Some specs might've had to wait til this spec was installed to be + # processed so the call to `enqueue_specs` is important after every + # dequeue. + def process_specs(installed_specs) + spec = worker_pool.deq + + if spec.installed? + installed_specs[spec.name] = true + return + elsif spec.failed? + return + elsif spec.ready_to_install?(installed_specs) + spec.state = :installable + end + + worker_pool.enq(spec, priority: spec.enqueue_with_priority?) + end + + def finished_installing? + @specs.all? do |spec| + return true if spec.failed? + spec.installed? + end + end + + def handle_error + errors = failed_specs.map(&:error) + if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) } + raise exception + end + raise Bundler::InstallError, errors.join("\n\n") + end + + def require_tree_for_spec(spec) + tree = @spec_set.what_required(spec) + gemfile_name = begin + File.basename(SharedHelpers.default_gemfile) + rescue GemfileNotFound + # This runs while reporting an install error. When no Gemfile can be + # located (e.g. Bundler used as a library), raising here would mask + # the original error, so fall back to a generic header instead. + "Gemfile" + end + t = String.new("In #{gemfile_name}:\n") + tree.each_with_index do |s, depth| + t << " " * depth.succ << s.name + unless tree.last == s + t << %( was resolved to #{s.version}, which depends on) + end + t << %(\n) + end + t + end + + # Keys in the remains hash represent uninstalled gems specs. + # We enqueue all gem specs that do not have any dependencies. + # Later we call this lambda again to install specs that depended on + # previously installed specifications. We continue until all specs + # are installed. + def enqueue_specs(installed_specs) + @specs.each do |spec| + if spec.installed? + installed_specs[spec.name] = true + next + end + + spec.state = :enqueued + worker_pool.enq spec + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/installer/standalone.rb b/bin/gems/bundler-4.0.21/lib/bundler/installer/standalone.rb new file mode 100644 index 00000000..8b4de64d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/installer/standalone.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Bundler + class Standalone + def initialize(groups, definition) + @specs = definition.specs_for(groups) + end + + def generate + SharedHelpers.filesystem_access(bundler_path) do |p| + FileUtils.mkdir_p(p) + end + File.open File.join(bundler_path, "setup.rb"), "w" do |file| + file.puts "require 'rbconfig'" + file.puts prevent_gem_activation + file.puts define_path_helpers + file.puts reverse_rubygems_kernel_mixin + paths.each do |path| + if Pathname.new(path).absolute? + file.puts %($:.unshift "#{path}") + else + file.puts %($:.unshift File.expand_path("\#{__dir__}/#{path}")) + end + end + end + end + + private + + def paths + @specs.flat_map do |spec| + next if spec.name == "bundler" + Array(spec.require_paths).map do |path| + gem_path(path, spec). + sub(version_dir, '#{RUBY_ENGINE}/#{Gem.ruby_api_version}'). + sub(extensions_dir, 'extensions/\k/#{Gem.extension_api_version}') + # This is a static string intentionally. It's interpolated at a later time. + end + end.compact + end + + def version_dir + "#{RUBY_ENGINE}/#{Gem.ruby_api_version}" + end + + def extensions_dir + %r{extensions/(?[^/]+)/#{Regexp.escape(Gem.extension_api_version)}} + end + + def bundler_path + Bundler.root.join(Bundler.settings[:path].to_s, "bundler") + end + + def gem_path(path, spec) + full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) + if spec.source.instance_of?(Source::Path) && spec.source.path.absolute? + full_path + else + SharedHelpers.relative_path_to(full_path, from: Bundler.root.join(bundler_path)) + end + end + + def prevent_gem_activation + <<~'END' + module Kernel + remove_method(:gem) if private_method_defined?(:gem) + + def gem(*) + end + + private :gem + end + END + end + + def define_path_helpers + <<~'END' + unless defined?(Gem) + module Gem + def self.ruby_api_version + RbConfig::CONFIG["ruby_version"] + end + + def self.extension_api_version + if 'no' == RbConfig::CONFIG['ENABLE_SHARED'] + "#{ruby_api_version}-static" + else + ruby_api_version + end + end + end + end + END + end + + def reverse_rubygems_kernel_mixin + <<~END + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + [::Kernel.singleton_class, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + private_require = k.private_method_defined?(:require) + k.send(:remove_method, :require) + k.send(:define_method, :require, k.instance_method(:gem_original_require)) + k.send(:private, :require) if private_require + end + end + end + END + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/lazy_specification.rb b/bin/gems/bundler-4.0.21/lib/bundler/lazy_specification.rb new file mode 100644 index 00000000..786dbcae --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/lazy_specification.rb @@ -0,0 +1,270 @@ +# frozen_string_literal: true + +require_relative "force_platform" + +module Bundler + class LazySpecification + include MatchMetadata + include MatchPlatform + include ForcePlatform + + attr_reader :name, :version, :platform, :materialization + attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version + + # + # For backwards compatibility with existing lockfiles, if the most specific + # locked platform is not a specific platform like x86_64-linux or + # universal-java-11, then we keep the previous behaviour of resolving the + # best platform variant at materiliazation time. For previous bundler + # versions (before 2.2.0) this was always the case (except when the lockfile + # only included non-ruby platforms), but we're also keeping this behaviour + # on newer bundlers unless users generate the lockfile from scratch or + # explicitly add a more specific platform. + # + attr_accessor :most_specific_locked_platform + + alias_method :runtime_dependencies, :dependencies + + def self.from_spec(s) + lazy_spec = new(s.name, s.version, s.platform, s.source) + lazy_spec.dependencies = s.runtime_dependencies + lazy_spec.required_ruby_version = s.required_ruby_version + lazy_spec.required_rubygems_version = s.required_rubygems_version + lazy_spec + end + + def initialize(name, version, platform, source = nil, **materialization_options) + @name = name + @version = version + @dependencies = [] + @required_ruby_version = Gem::Requirement.default + @required_rubygems_version = Gem::Requirement.default + @platform = platform || Gem::Platform::RUBY + + @original_source = source + @source = source + @materialization_options = materialization_options + + @force_ruby_platform = default_force_ruby_platform + @most_specific_locked_platform = nil + @materialization = nil + end + + def missing? + @materialization == self + end + + def incomplete? + @materialization.nil? + end + + def source_changed? + @original_source != source + end + + def full_name + @full_name ||= if platform == Gem::Platform::RUBY + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{platform}" + end + end + + def lock_name + @lock_name ||= name_tuple.lock_name + end + + def name_tuple + Gem::NameTuple.new(@name, @version, @platform) + end + + def ==(other) + full_name == other.full_name + end + + def eql?(other) + full_name.eql?(other.full_name) + end + + def hash + full_name.hash + end + + ## + # Does this locked specification satisfy +dependency+? + # + # NOTE: Rubygems default requirement is ">= 0", which doesn't match + # prereleases of 0 versions, like "0.0.0.dev" or "0.0.0.SNAPSHOT". However, + # bundler users expect those to work. We need to make sure that Gemfile + # dependencies without explicit requirements (which use ">= 0" under the + # hood by default) are still valid for locked specs using this kind of + # versions. The method implements an ad-hoc fix for that. A better solution + # might be to change default rubygems requirement of dependencies to be ">= + # 0.A" but that's a major refactoring likely to break things. Hopefully we + # can attempt it in the future. + # + + def satisfies?(dependency) + effective_requirement = dependency.requirement == Gem::Requirement.default ? Gem::Requirement.new(">= 0.A") : dependency.requirement + + @name == dependency.name && effective_requirement.satisfied_by?(Gem::Version.new(@version)) + end + + def to_lock + out = String.new + out << " #{lock_name}\n" + + dependencies.sort_by(&:to_s).uniq.each do |dep| + next if dep.type == :development + out << " #{dep.to_lock}\n" + end + + out + end + + def materialize_for_cache + source.remote! + + materialize(self, &:first) + end + + def materialized_for_installation + @materialization = materialize_for_installation + + self unless incomplete? + end + + def materialize_for_installation + source.local! + + if use_exact_resolved_specifications? + spec = materialize(self) {|specs| choose_compatible(specs, fallback_to_non_installable: false) } + return spec if spec + + # Exact spec is incompatible; in frozen mode, try to find a compatible platform variant + # In non-frozen mode, return nil to trigger re-resolution and lockfile update + if Bundler.frozen_bundle? + materialize([name, version]) {|specs| resolve_best_platform(specs) } + end + else + materialize([name, version]) {|specs| resolve_best_platform(specs) } + end + end + + def inspect + "#<#{self.class} @name=\"#{name}\" (#{full_name.delete_prefix("#{name}-")})>" + end + + def to_s + lock_name + end + + def git_version + return unless source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + def force_ruby_platform! + @force_ruby_platform = true + end + + def replace_source_with!(gemfile_source) + return unless gemfile_source.can_lock?(self) + + @source = gemfile_source + + true + end + + private + + def use_exact_resolved_specifications? + !source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform? + end + + # Try platforms in order of preference until finding a compatible spec. + # Used for legacy lockfiles and as a fallback when the exact locked spec + # is incompatible. Falls back to frozen bundle behavior if none match. + def resolve_best_platform(specs) + find_compatible_platform_spec(specs) || frozen_bundle_fallback(specs) + end + + def find_compatible_platform_spec(specs) + candidate_platforms.each do |plat| + candidates = MatchPlatform.select_best_platform_match(specs, plat) + spec = choose_compatible(candidates, fallback_to_non_installable: false) + return spec if spec + end + nil + end + + # Platforms to try in order of preference. Ruby platform is last since it + # requires compilation, but works when precompiled gems are incompatible. + def candidate_platforms + target = source.is_a?(Source::Path) ? platform : Bundler.local_platform + [target, platform, Gem::Platform::RUBY].uniq + end + + # In frozen mode, accept any candidate. Will error at install time. + # When target differs from locked platform, prefer locked platform's candidates + # to preserve lockfile integrity. + def frozen_bundle_fallback(specs) + target = source.is_a?(Source::Path) ? platform : Bundler.local_platform + fallback_platform = target == platform ? target : platform + candidates = MatchPlatform.select_best_platform_match(specs, fallback_platform) + choose_compatible(candidates) + end + + def ruby_platform_materializes_to_ruby_platform? + generic_platform = Bundler.generic_local_platform == Gem::Platform::JAVA ? Gem::Platform::JAVA : Gem::Platform::RUBY + + (most_specific_locked_platform != generic_platform) || force_ruby_platform || Bundler.settings[:force_ruby_platform] + end + + def materialize(query) + matching_specs = source.specs.search(query) + return self if matching_specs.empty? + + yield matching_specs + end + + # If in frozen mode, we fallback to a non-installable candidate because by + # doing this we avoid re-resolving and potentially end up changing the + # lockfile, which is not allowed. In that case, we will give a proper error + # about the mismatch higher up the stack, right before trying to install the + # bad gem. + def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?) + search = candidates.reverse.find do |spec| + spec.is_a?(StubSpecification) || spec.matches_current_metadata? + end + if search.nil? && fallback_to_non_installable + search = candidates.last + end + + if search + validate_dependencies(search) if search.platform == platform + + search.locked_platform = platform if search.instance_of?(RemoteSpecification) || search.instance_of?(EndpointSpecification) + end + search + end + + # Validate dependencies of this locked spec are consistent with dependencies + # of the actual spec that was materialized. + # + # Note that unless we are in strict mode (which we set during installation) + # we don't validate dependencies of locally installed gems but + # accept what's in the lockfile instead for performance, since loading + # dependencies of locally installed gems would mean evaluating all gemspecs, + # which would affect `bundler/setup` performance. + def validate_dependencies(spec) + if !@materialization_options[:strict] && spec.is_a?(StubSpecification) + spec.dependencies = dependencies + else + if !source.is_a?(Source::Path) && spec.runtime_dependencies.sort != dependencies.sort + raise IncorrectLockfileDependencies.new(self) + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/lockfile_generator.rb b/bin/gems/bundler-4.0.21/lib/bundler/lockfile_generator.rb new file mode 100644 index 00000000..f2b9afb3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/lockfile_generator.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +module Bundler + class LockfileGenerator + attr_reader :definition + attr_reader :out + + # @private + def initialize(definition) + @definition = definition + @out = String.new + end + + def self.generate(definition) + new(definition).generate! + end + + def generate! + add_sources + add_platforms + add_dependencies + add_checksums + add_locked_ruby_version + add_bundled_with + + out + end + + private + + def add_sources + definition.sources.lock_sources.each_with_index do |source, idx| + out << "\n" unless idx.zero? + + # Add the source header + out << source.to_lock + + # Find all specs for this source + specs = definition.resolve.select {|s| source.can_lock?(s) } + add_specs(specs) + end + end + + def add_specs(specs) + # This needs to be sorted by full name so that + # gems with the same name, but different platform + # are ordered consistently + specs.sort_by(&:full_name).each do |spec| + next if spec.name == "bundler" + out << spec.to_lock + end + end + + def add_platforms + add_section("PLATFORMS", definition.platforms) + end + + def add_dependencies + out << "\nDEPENDENCIES\n" + + handled = [] + definition.dependencies.sort_by(&:to_s).each do |dep| + next if handled.include?(dep.name) + out << dep.to_lock << "\n" + handled << dep.name + end + end + + def add_checksums + return unless definition.locked_checksums + checksums = definition.resolve.map do |spec| + spec.source.checksum_store.to_lock(spec) + end + + add_section("CHECKSUMS", checksums + bundler_checksum) + end + + def add_locked_ruby_version + return unless locked_ruby_version = definition.locked_ruby_version + add_section("RUBY VERSION", locked_ruby_version.to_s) + end + + def add_bundled_with + add_section("BUNDLED WITH", definition.bundler_version_to_lock.to_s) + end + + def add_section(name, value) + out << "\n#{name}\n" + case value + when Array + value.map(&:to_s).sort.each do |val| + out << " #{val}\n" + end + when Hash + value.to_a.sort_by {|k, _| k.to_s }.each do |key, val| + out << " #{key}: #{val}\n" + end + when String + out << " #{value}\n" + else + raise ArgumentError, "#{value.inspect} can't be serialized in a lockfile" + end + end + + def bundler_checksum + # In frozen mode the lockfile can't change, so reproduce whatever bundler + # entry is already locked instead of recording one for the running bundler + # version, which may legitimately differ from the locked one. + return locked_bundler_checksum if Bundler.frozen_bundle? + + # `.dev` versions and `SKIP_BUNDLER_CHECKSUM` are deliberate opt-outs (used + # by Bundler/RubyGems' own development and release tasks): never record a + # checksum for Bundler itself in those cases. + return [] if Bundler.gem_version.to_s.end_with?(".dev") || ENV["SKIP_BUNDLER_CHECKSUM"] + + bundler_spec = definition.sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last + + # Record a fresh checksum from the locally cached gem when it's available. + # When it isn't (e.g. a fresh checkout/CI that never downloaded the bundler + # gem), fall back to whatever checksum is already locked rather than + # dropping it, so the entry stays consistent across environments. + if File.exist?(bundler_spec.cache_file) + require "rubygems/package" + + package = Gem::Package.new(bundler_spec.cache_file) + definition.sources.metadata_source.checksum_store.register(bundler_spec, Checksum.from_gem_package(package)) + elsif bundled_with_changing? + # We can't compute a fresh checksum (the bundler gem isn't cached) and the + # BUNDLED WITH version is changing. Keeping the previously locked checksum + # would leave a `bundler () sha256=...` entry that no longer + # matches the new BUNDLED WITH version, so drop it instead. + return [] + end + + return [] if definition.sources.metadata_source.checksum_store.missing?(bundler_spec) + + [definition.sources.metadata_source.checksum_store.to_lock(bundler_spec)] + end + + def bundled_with_changing? + locked_gems = definition.locked_gems + return false unless locked_gems + + locked_gems.bundler_version != definition.bundler_version_to_lock + end + + def locked_bundler_checksum + locked_version = definition.locked_gems&.bundler_version + return [] unless locked_version + + metadata_source = definition.sources.metadata_source + locked_spec = LazySpecification.new("bundler", locked_version, Gem::Platform::RUBY, metadata_source) + return [] if metadata_source.checksum_store.missing?(locked_spec) + + [metadata_source.checksum_store.to_lock(locked_spec)] + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/lockfile_parser.rb b/bin/gems/bundler-4.0.21/lib/bundler/lockfile_parser.rb new file mode 100644 index 00000000..9e21f8f1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/lockfile_parser.rb @@ -0,0 +1,328 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" + +module Bundler + class LockfileParser + class Position + attr_reader :line, :column + def initialize(line, column) + @line = line + @column = column + end + + def advance!(string) + lines = string.count("\n") + if lines > 0 + @line += lines + @column = string.length - string.rindex("\n") + else + @column += string.length + end + end + + def to_s + "#{line}:#{column}" + end + end + + attr_reader( + :sources, + :metadata_source, + :dependencies, + :specs, + :platforms, + :most_specific_locked_platform, + :bundler_version, + :ruby_version, + :checksums, + ) + + BUNDLED = "BUNDLED WITH" + DEPENDENCIES = "DEPENDENCIES" + CHECKSUMS = "CHECKSUMS" + PLATFORMS = "PLATFORMS" + RUBY = "RUBY VERSION" + GIT = "GIT" + GEM = "GEM" + PATH = "PATH" + PLUGIN = "PLUGIN SOURCE" + SPECS = " specs:" + OPTIONS = /^ ([a-z]+): (.*)$/i + SOURCE = [GIT, GEM, PATH, PLUGIN].freeze + + SECTIONS_BY_VERSION_INTRODUCED = { + Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, + Gem::Version.create("1.10") => [BUNDLED].freeze, + Gem::Version.create("1.12") => [RUBY].freeze, + Gem::Version.create("1.13") => [PLUGIN].freeze, + Gem::Version.create("2.5.0") => [CHECKSUMS].freeze, + }.freeze + + KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze + + ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze + deprecate_constant(:ENVIRONMENT_VERSION_SECTIONS) + + def self.sections_in_lockfile(lockfile_contents) + sections = lockfile_contents.scan(/^\w[\w ]*$/) + sections.uniq! + sections + end + + def self.unknown_sections_in_lockfile(lockfile_contents) + sections_in_lockfile(lockfile_contents) - KNOWN_SECTIONS + end + + def self.sections_to_ignore(base_version = nil) + base_version &&= base_version.release + base_version ||= Gem::Version.create("1.0") + attributes = [] + SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced| + next if version <= base_version + attributes += introduced + end + attributes + end + + def self.bundled_with + lockfile = Bundler.default_lockfile + return unless lockfile.file? + + lockfile_contents = Bundler.read_file(lockfile) + return unless lockfile_contents.include?(BUNDLED) + + lockfile_contents.split(BUNDLED).last.strip + end + + def initialize(lockfile, strict: false) + @platforms = [] + @sources = [] + @metadata_source = Source::Metadata.new + @dependencies = {} + @parse_method = nil + @specs = {} + @lockfile_path = begin + SharedHelpers.relative_lockfile_path + rescue GemfileNotFound + "Gemfile.lock" + end + @pos = Position.new(1, 1) + @strict = strict + + if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) + raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \ + "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock." + end + + @valid = lockfile.strip.empty? || + lockfile.split(/(?:\r?\n)+/).any? {|l| KNOWN_SECTIONS.include?(l) } + + unless @valid + SharedHelpers.feature_deprecated!( + "Your #{@lockfile_path} does not appear to be a valid lockfile. " \ + "Run `rm #{@lockfile_path}` and then `bundle install` to generate a new lockfile. " \ + "This will raise a LockfileError in a future version of Bundler." + ) + end + + lockfile.split(/((?:\r?\n)+)/) do |line| + # split alternates between the line and the following whitespace + next @pos.advance!(line) if line.match?(/^\s*$/) + + if SOURCE.include?(line) + @parse_method = :parse_source + parse_source(line) + elsif line == DEPENDENCIES + @parse_method = :parse_dependency + elsif line == CHECKSUMS + # This is a temporary solution to make this feature disabled by default + # for all gemfiles that don't already explicitly include the feature. + @checksums = true + @parse_method = :parse_checksum + elsif line == PLATFORMS + @parse_method = :parse_platform + elsif line == RUBY + @parse_method = :parse_ruby + elsif line == BUNDLED + @parse_method = :parse_bundled_with + elsif /^[^\s]/.match?(line) + @parse_method = nil + elsif @parse_method + send(@parse_method, line) + end + @pos.advance!(line) + end + + if @platforms.include?(Gem::Platform::X64_MINGW_LEGACY) + SharedHelpers.feature_deprecated!("Found x64-mingw32 in lockfile, which is deprecated and will be removed in the future.") + end + + @most_specific_locked_platform = @platforms.min_by do |bundle_platform| + Gem::Platform.platform_specificity_match(bundle_platform, Bundler.local_platform) + end + @specs = @specs.values.sort_by!(&:full_name).each do |spec| + spec.most_specific_locked_platform = @most_specific_locked_platform + end + rescue ArgumentError => e + Bundler.ui.debug(e) + raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \ + "and then `bundle install` to generate a new lockfile. The error occurred while " \ + "evaluating #{@lockfile_path}:#{@pos}" + end + + def may_include_redundant_platform_specific_gems? + bundler_version.nil? || bundler_version < Gem::Version.new("1.16.2") + end + + def valid? + @valid + end + + private + + TYPES = { + GIT => Bundler::Source::Git, + GEM => Bundler::Source::Rubygems, + PATH => Bundler::Source::Path, + PLUGIN => Bundler::Plugin, + }.freeze + + def parse_source(line) + case line + when SPECS + return unless TYPES.key?(@type) + @current_source = TYPES[@type].from_lock(@opts) + @sources << @current_source + when OPTIONS + value = $2 + value = true if value == "true" + value = false if value == "false" + + key = $1 + + if @opts[key] + @opts[key] = Array(@opts[key]) + @opts[key] << value + else + @opts[key] = value + end + when *SOURCE + @current_source = nil + @opts = {} + @type = line + else + parse_spec(line) + end + end + + space = / / + NAME_VERSION = / + ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line + (.*?) # Name + (?:#{space}\(([^-]*) # Space, followed by version + (?:-(.*))?\))? # Optional platform + (!)? # Optional pinned marker + (?:#{space}([^ ]+))? # Optional checksum + $ # Line end + /xo + + def parse_dependency(line) + return unless line =~ NAME_VERSION + spaces = $1 + return unless spaces.size == 2 + name = -$2 + version = $3 + pinned = $5 + + version = version.split(",").each(&:strip!) if version + + dep = Bundler::Dependency.new(name, version) + + if pinned && dep.name != "bundler" + spec = @specs.find {|_, v| v.name == dep.name } + dep.source = spec.last.source if spec + + # Path sources need to know what the default name / version + # to use in the case that there are no gemspecs present. A fake + # gemspec is created based on the version set on the dependency + # TODO: Use the version from the spec instead of from the dependency + if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path) + dep.source.name = name + dep.source.version = $1 + end + end + + @dependencies[dep.name] = dep + end + + def parse_checksum(line) + return unless line =~ NAME_VERSION + + spaces = $1 + return unless spaces.size == 2 + checksums = $6 + name = $2 + version = $3 + platform = $4 + + version = Gem::Version.new(version) + platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + full_name = Gem::NameTuple.new(name, version, platform).full_name + spec = @specs[full_name] + + if name == "bundler" + spec ||= LazySpecification.new(name, version, platform, @metadata_source) + end + return unless spec + + if checksums + checksums.split(",") do |lock_checksum| + column = line.index(lock_checksum) + 1 + checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}") + spec.source.checksum_store.register(spec, checksum) + end + else + spec.source.checksum_store.register(spec, nil) + end + end + + def parse_spec(line) + return unless line =~ NAME_VERSION + spaces = $1 + name = -$2 + version = $3 + + if spaces.size == 4 + # only load platform for non-dependency (spec) line + platform = $4 + + version = Gem::Version.new(version) + platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + @current_spec = LazySpecification.new(name, version, platform, @current_source, strict: @strict) + @current_source.add_dependency_names(name) + + @specs[@current_spec.full_name] = @current_spec + elsif spaces.size == 6 + version = version.split(",").each(&:strip!) if version + dep = Gem::Dependency.new(name, version) + @current_spec.dependencies << dep + end + end + + def parse_platform(line) + @platforms << Gem::Platform.new($1.strip) if line =~ /^ (.*)$/ + end + + def parse_bundled_with(line) + line.strip! + return unless Gem::Version.correct?(line) + @bundler_version = Gem::Version.create(line) + end + + def parse_ruby(line) + line.strip! + @ruby_version = line + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/.document b/bin/gems/bundler-4.0.21/lib/bundler/man/.document new file mode 100644 index 00000000..fb66f13c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/.document @@ -0,0 +1 @@ +# Ignore all files in this directory diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1 new file mode 100644 index 00000000..9f103820 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1 @@ -0,0 +1,79 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-ADD" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install +.SH "SYNOPSIS" +\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT|\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-cooldown=NUMBER] [\-\-quiet] [\-\-skip\-install] [\-\-strict|\-\-optimistic] +.SH "DESCRIPTION" +Adds the named gem to the [\fBGemfile(5)\fR][Gemfile(5)] and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\. +.SH "OPTIONS" +.TP +\fB\-\-version=VERSION\fR, \fB\-v=VERSION\fR +Specify version requirements(s) for the added gem\. +.TP +\fB\-\-group=GROUP\fR, \fB\-g=GROUP\fR +Specify the group(s) for the added gem\. Multiple groups should be separated by commas\. +.TP +\fB\-\-source=SOURCE\fR, \fB\-s=SOURCE\fR +Specify the source for the added gem\. +.TP +\fB\-\-require=REQUIRE\fR, \fB\-r=REQUIRE\fR +Adds require path to gem\. Provide false, or a path as a string\. +.TP +\fB\-\-path=PATH\fR +Specify the file system path for the added gem\. +.TP +\fB\-\-git=GIT\fR +Specify the git source for the added gem\. +.TP +\fB\-\-github=GITHUB\fR +Specify the github source for the added gem\. +.TP +\fB\-\-branch=BRANCH\fR +Specify the git branch for the added gem\. +.TP +\fB\-\-ref=REF\fR +Specify the git ref for the added gem\. +.TP +\fB\-\-glob=GLOB\fR +Specify the location of a dependency's \.gemspec, expanded within Ruby (single quotes recommended)\. +.TP +\fB\-\-quiet\fR +Do not print progress information to the standard output\. +.TP +\fB\-\-skip\-install\fR +Adds the gem to the Gemfile but does not install it\. +.TP +\fB\-\-optimistic\fR +Adds optimistic declaration of version\. +.TP +\fB\-\-strict\fR +Adds strict declaration of version\. +.TP +\fB\-\-cooldown=\fR +Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run\. See \fBcooldown\fR in bundle\-config(1) for precedence rules\. +.SH "EXAMPLES" +.IP "1." 4 +You can add the \fBrails\fR gem to the Gemfile without any version restriction\. The source of the gem will be the global source\. +.IP +\fBbundle add rails\fR +.IP "2." 4 +You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\.1) and less than 3\.0\. +.IP +\fBbundle add rails \-\-version "> 1\.1, < 3\.0"\fR +.IP "3." 4 +You can use the \fBhttps://gems\.example\.com\fR custom source and assign the gem to a group\. +.IP +\fBbundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"\fR +.IP "4." 4 +The following adds the \fBgem\fR entry to the Gemfile without installing the gem\. You can install gems later via \fBbundle install\fR\. +.IP +\fBbundle add rails \-\-skip\-install\fR +.IP "5." 4 +You can assign the gem to more than one group\. +.IP +\fBbundle add rails \-\-group "development, test"\fR +.IP "" 0 +.SH "SEE ALSO" +Gemfile(5) \fIhttps://guides\.rubygems\.org/gemfile/\fR, bundle\-remove(1) \fIbundle\-remove\.1\.html\fR diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1.ronn new file mode 100644 index 00000000..9c9bdf7c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-add.1.ronn @@ -0,0 +1,92 @@ +bundle-add(1) -- Add gem to the Gemfile and run bundle install +============================================================== + +## SYNOPSIS + +`bundle add` [--group=GROUP] [--version=VERSION] [--source=SOURCE] + [--path=PATH] [--git=GIT|--github=GITHUB] [--branch=BRANCH] [--ref=REF] + [--cooldown=NUMBER] [--quiet] [--skip-install] [--strict|--optimistic] + +## DESCRIPTION + +Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`. +`bundle install` can be avoided by using the flag `--skip-install`. + +## OPTIONS + +* `--version=VERSION`, `-v=VERSION`: + Specify version requirements(s) for the added gem. + +* `--group=GROUP`, `-g=GROUP`: + Specify the group(s) for the added gem. Multiple groups should be separated by commas. + +* `--source=SOURCE`, `-s=SOURCE`: + Specify the source for the added gem. + +* `--require=REQUIRE`, `-r=REQUIRE`: + Adds require path to gem. Provide false, or a path as a string. + +* `--path=PATH`: + Specify the file system path for the added gem. + +* `--git=GIT`: + Specify the git source for the added gem. + +* `--github=GITHUB`: + Specify the github source for the added gem. + +* `--branch=BRANCH`: + Specify the git branch for the added gem. + +* `--ref=REF`: + Specify the git ref for the added gem. + +* `--glob=GLOB`: + Specify the location of a dependency's .gemspec, expanded within Ruby (single quotes recommended). + +* `--quiet`: + Do not print progress information to the standard output. + +* `--skip-install`: + Adds the gem to the Gemfile but does not install it. + +* `--optimistic`: + Adds optimistic declaration of version. + +* `--strict`: + Adds strict declaration of version. + +* `--cooldown=`: + Only consider gem versions published at least days ago when + resolving. Pass `0` to disable cooldown for this run. See `cooldown` + in bundle-config(1) for precedence rules. + +## EXAMPLES + +1. You can add the `rails` gem to the Gemfile without any version restriction. + The source of the gem will be the global source. + + `bundle add rails` + +2. You can add the `rails` gem with version greater than 1.1 (not including 1.1) and less than 3.0. + + `bundle add rails --version "> 1.1, < 3.0"` + +3. You can use the `https://gems.example.com` custom source and assign the gem + to a group. + + `bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"` + +4. The following adds the `gem` entry to the Gemfile without installing the + gem. You can install gems later via `bundle install`. + + `bundle add rails --skip-install` + +5. You can assign the gem to more than one group. + + `bundle add rails --group "development, test"` + +## SEE ALSO + +[Gemfile(5)](https://guides.rubygems.org/gemfile/), +[bundle-remove(1)](bundle-remove.1.html) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1 new file mode 100644 index 00000000..9dbd4f1d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1 @@ -0,0 +1,30 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-BINSTUBS" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems +.SH "SYNOPSIS" +\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-standalone] [\-\-all\-platforms] +.SH "DESCRIPTION" +Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\. +.P +For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\. +.P +This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the directory specified by \fBbin\fR setting if it has been configured\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\. +.SH "OPTIONS" +.TP +\fB\-\-force\fR +Overwrite existing binstubs if they exist\. +.TP +\fB\-\-standalone\fR +Makes binstubs that can work without depending on Rubygems or Bundler at runtime\. +.TP +\fB\-\-shebang=SHEBANG\fR +Specify a different shebang executable name than the default (default 'ruby') +.TP +\fB\-\-all\fR +Create binstubs for all gems in the bundle\. +.TP +\fB\-\-all\-platforms\fR +Install binstubs for all platforms\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1.ronn new file mode 100644 index 00000000..cbe5983f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-binstubs.1.ronn @@ -0,0 +1,42 @@ +bundle-binstubs(1) -- Install the binstubs of the listed gems +============================================================= + +## SYNOPSIS + +`bundle binstubs` [--force] [--standalone] [--all-platforms] + +## DESCRIPTION + +Binstubs are scripts that wrap around executables. Bundler creates a +small Ruby file (a binstub) that loads Bundler, runs the command, +and puts it into `bin/`. Binstubs are a shortcut-or alternative- +to always using `bundle exec`. This gives you a file that can be run +directly, and one that will always run the correct gem version +used by the application. + +For example, if you run `bundle binstubs rspec-core`, Bundler will create +the file `bin/rspec`. That file will contain enough code to load Bundler, +tell it to load the bundled gems, and then run rspec. + +This command generates binstubs for executables in `GEM_NAME`. +Binstubs are put into `bin`, or the directory specified by `bin` setting if it +has been configured. Calling binstubs with [GEM [GEM]] will create binstubs for +all given gems. + +## OPTIONS + +* `--force`: + Overwrite existing binstubs if they exist. + +* `--standalone`: + Makes binstubs that can work without depending on Rubygems or Bundler at + runtime. + +* `--shebang=SHEBANG`: + Specify a different shebang executable name than the default (default 'ruby') + +* `--all`: + Create binstubs for all gems in the bundle. + +* `--all-platforms`: + Install binstubs for all platforms. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1 new file mode 100644 index 00000000..94c0c386 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1 @@ -0,0 +1,59 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-CACHE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application +.SH "SYNOPSIS" +\fBbundle cache\fR [\fIOPTIONS\fR] +.P +alias: \fBpackage\fR, \fBpack\fR +.SH "DESCRIPTION" +Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. +.SH "OPTIONS" +.TP +\fB\-\-all\-platforms\fR +Include gems for all platforms present in the lockfile, not only the current one\. +.TP +\fB\-\-cache\-path=CACHE\-PATH\fR +Specify a different cache path than the default (vendor/cache)\. +.TP +\fB\-\-cooldown=\fR +Only consider gem versions published at least \fInumber\fR days ago when resolving before caching\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. See \fBcooldown\fR in bundle\-config(1)\. +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified gemfile instead of Gemfile\. +.TP +\fB\-\-no\-install\fR +Don't install the gems, only update the cache\. +.TP +\fB\-\-quiet\fR +Only output warnings and errors\. +.SH "GIT AND PATH GEMS" +The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This can be disabled setting \fBcache_all\fR to false\. +.SH "SUPPORT FOR MULTIPLE PLATFORMS" +When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\. +.SH "REMOTE FETCHING" +By default, if you run \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\. +.P +For instance, consider this Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "nokogiri" +.fi +.IP "" 0 +.P +If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\. +.P +Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\. +.P +This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\. +.P +If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\. +.P +One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\. +.P +By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. +.SH "HISTORY" +In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1.ronn new file mode 100644 index 00000000..91e16cde --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-cache.1.ronn @@ -0,0 +1,101 @@ +bundle-cache(1) -- Package your needed `.gem` files into your application +========================================================================= + +## SYNOPSIS + +`bundle cache` [*OPTIONS*] + +alias: `package`, `pack` + +## DESCRIPTION + +Copy all of the `.gem` files needed to run the application into the +`vendor/cache` directory. In the future, when running [`bundle install(1)`](bundle-install.1.html), +use the gems in the cache in preference to the ones on `rubygems.org`. + +## OPTIONS + +* `--all-platforms`: + Include gems for all platforms present in the lockfile, not only the current one. + +* `--cache-path=CACHE-PATH`: + Specify a different cache path than the default (vendor/cache). + +* `--cooldown=`: + Only consider gem versions published at least days ago when + resolving before caching. Pass `0` to disable cooldown for this run, + overriding any per-source or global configuration. See `cooldown` in + bundle-config(1). + +* `--gemfile=GEMFILE`: + Use the specified gemfile instead of Gemfile. + +* `--no-install`: + Don't install the gems, only update the cache. + +* `--quiet`: + Only output warnings and errors. + +## GIT AND PATH GEMS + +The `bundle cache` command can also package `:git` and `:path` dependencies +besides .gem files. This can be disabled setting `cache_all` to false. + +## SUPPORT FOR MULTIPLE PLATFORMS + +When using gems that have different packages for different platforms, Bundler +supports caching of gems for other platforms where the Gemfile has been resolved +(i.e. present in the lockfile) in `vendor/cache`. This needs to be enabled via +the `--all-platforms` option. This setting will be remembered in your local +bundler configuration. + +## REMOTE FETCHING + +By default, if you run [`bundle install(1)`](bundle-install.1.html) after running +[bundle cache(1)](bundle-cache.1.html), bundler will still connect to `rubygems.org` +to check whether a platform-specific gem exists for any of the gems +in `vendor/cache`. + +For instance, consider this Gemfile(5): + + source "https://rubygems.org" + + gem "nokogiri" + +If you run `bundle cache` under C Ruby, bundler will retrieve +the version of `nokogiri` for the `"ruby"` platform. If you deploy +to JRuby and run `bundle install`, bundler is forced to check to +see whether a `"java"` platformed `nokogiri` exists. + +Even though the `nokogiri` gem for the Ruby platform is +_technically_ acceptable on JRuby, it has a C extension +that does not run on JRuby. As a result, bundler will, by default, +still connect to `rubygems.org` to check whether it has a version +of one of your gems more specific to your platform. + +This problem is also not limited to the `"java"` platform. +A similar (common) problem can happen when developing on Windows +and deploying to Linux, or even when developing on OSX and +deploying to Linux. + +If you know for sure that the gems packaged in `vendor/cache` +are appropriate for the platform you are on, you can run +`bundle install --local` to skip checking for more appropriate +gems, and use the ones in `vendor/cache`. + +One way to be sure that you have the right platformed versions +of all your gems is to run `bundle cache` on an identical +machine and check in the gems. For instance, you can run +`bundle cache` on an identical staging box during your +staging process, and check in the `vendor/cache` before +deploying to production. + +By default, [bundle cache(1)](bundle-cache.1.html) fetches and also +installs the gems to the default location. To package the +dependencies to `vendor/cache` without installing them to the +local install location, you can run `bundle cache --no-install`. + +## HISTORY + +In Bundler 2.1, `cache` took in the functionalities of `package` and now +`package` and `pack` are aliases of `cache`. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1 new file mode 100644 index 00000000..825a2889 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1 @@ -0,0 +1,21 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-CHECK" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems +.SH "SYNOPSIS" +\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] +.SH "DESCRIPTION" +\fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\. +.P +If not, the first missing gem is listed and Bundler exits status 1\. +.P +If the lockfile needs to be updated then it will be resolved using the gems installed on the local machine, if they satisfy the requirements\. +.SH "OPTIONS" +.TP +\fB\-\-dry\-run\fR +Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\. +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1.ronn new file mode 100644 index 00000000..92589159 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-check.1.ronn @@ -0,0 +1,26 @@ +bundle-check(1) -- Verifies if dependencies are satisfied by installed gems +=========================================================================== + +## SYNOPSIS + +`bundle check` [--dry-run] + [--gemfile=FILE] + +## DESCRIPTION + +`check` searches the local machine for each of the gems requested in the +Gemfile. If all gems are found, Bundler prints a success message and exits with +a status of 0. + +If not, the first missing gem is listed and Bundler exits status 1. + +If the lockfile needs to be updated then it will be resolved using the gems +installed on the local machine, if they satisfy the requirements. + +## OPTIONS + +* `--dry-run`: + Locks the [`Gemfile(5)`][Gemfile(5)] before running the command. + +* `--gemfile=GEMFILE`: + Use the specified gemfile instead of the [`Gemfile(5)`][Gemfile(5)]. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1 new file mode 100644 index 00000000..0eae33d0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1 @@ -0,0 +1,17 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-CLEAN" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory +.SH "SYNOPSIS" +\fBbundle clean\fR [\-\-dry\-run] [\-\-force] +.SH "DESCRIPTION" +This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\. +.SH "OPTIONS" +.TP +\fB\-\-dry\-run\fR +Print the changes, but do not clean the unused gems\. +.TP +\fB\-\-force\fR +Forces cleaning up unused gems even if Bundler is configured to use globally installed gems\. As a consequence, removes all system gems except for the ones in the current application\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1.ronn new file mode 100644 index 00000000..dae27c21 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-clean.1.ronn @@ -0,0 +1,18 @@ +bundle-clean(1) -- Cleans up unused gems in your bundler directory +================================================================== + +## SYNOPSIS + +`bundle clean` [--dry-run] [--force] + +## DESCRIPTION + +This command will remove all unused gems in your bundler directory. This is +useful when you have made many changes to your gem dependencies. + +## OPTIONS + +* `--dry-run`: + Print the changes, but do not clean the unused gems. +* `--force`: + Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1 new file mode 100644 index 00000000..809c57ef --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1 @@ -0,0 +1,339 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-CONFIG" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-config\fR \- Set bundler configuration options +.SH "SYNOPSIS" +\fBbundle config\fR [list] +.br +\fBbundle config\fR [get [\-\-local|\-\-global]] NAME +.br +\fBbundle config\fR [set [\-\-local|\-\-global]] NAME VALUE +.br +\fBbundle config\fR unset [\-\-local|\-\-global] NAME +.SH "DESCRIPTION" +This command allows you to interact with Bundler's configuration system\. +.P +Bundler loads configuration settings in this order: +.IP "1." 4 +Local config (\fB/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR) +.IP "2." 4 +Environmental variables (\fBENV\fR) +.IP "3." 4 +Global config (\fB~/\.bundle/config\fR) +.IP "4." 4 +Bundler default config +.IP "" 0 +.P +Executing \fBbundle\fR with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. +.SH "SUB\-COMMANDS" +.SS "list (default command)" +Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\. +.SS "get" +Executing \fBbundle config get \fR will print the value of that configuration setting, and all locations where it was set\. +.P +\fBOPTIONS\fR +.TP +\fB\-\-local\fR +Get configuration from configuration file for the local application, namely, \fB/\.bundle/config\fR, or \fB$BUNDLE_APP_CONFIG/config\fR if \fBBUNDLE_APP_CONFIG\fR is set\. +.TP +\fB\-\-global\fR +Get configuration from configuration file global to all bundles executed as the current user, namely, from \fB~/\.bundle/config\fR\. +.SS "set" +Executing \fBbundle config set \fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. +.P +\fBOPTIONS\fR +.TP +\fB\-\-local\fR +Executing \fBbundle config set \-\-local \fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\. +.TP +\fB\-\-global\fR +Executing \fBbundle config set \-\-global \fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\. +.SS "unset" +Executing \fBbundle config unset \fR will delete the configuration in both local and global sources\. +.P +\fBOPTIONS\fR +.TP +\fB\-\-local\fR +Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. +.TP +\fB\-\-global\fR +Executing \fBbundle config unset \-\-global \fR will delete the configuration only from the user configuration\. +.SH "CONFIGURATION KEYS" +Configuration keys in bundler have two forms: the canonical form and the environment variable form\. +.P +For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn't install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\. +.P +The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\. +.P +Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\. +.SH "LIST OF AVAILABLE KEYS" +The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. +.IP "\(bu" 4 +\fBapi_request_size\fR (\fBBUNDLE_API_REQUEST_SIZE\fR): Configure how many dependencies to fetch when resolving the specifications\. This configuration is only used when fetchig specifications from RubyGems servers that didn't implement the Compact Index API\. Defaults to 100\. +.IP "\(bu" 4 +\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\. +.IP "\(bu" 4 +\fBbin\fR (\fBBUNDLE_BIN\fR): If configured, \fBbundle binstubs\fR will install executables from gems in the bundle to the specified directory\. Otherwise it will create them in a \fBbin\fR directory relative to the Gemfile directory\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, \fBbundle binstubs\fR will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\. +.IP "\(bu" 4 +\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly before bundler 4, but will be the default on bundler 4\. +.IP "\(bu" 4 +\fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\. +.IP "\(bu" 4 +\fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\. +.IP "\(bu" 4 +\fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\. Defaults to \fBtrue\fR in Bundler 5, as long as \fBpath\fR is not explicitly configured\. +.IP "\(bu" 4 +\fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\. +.IP "\(bu" 4 +\fBcooldown\fR (\fBBUNDLE_COOLDOWN\fR): Number of days a published gem version must age before bundler will resolve to it\. Defaults to unset (no cooldown)\. Pass \fB0\fR to disable cooldown for an individual run\. +.IP +The effective cooldown for any given gem is resolved from three layers, highest precedence first: +.IP "1." 4 +CLI flag \fB\-\-cooldown N\fR on \fBinstall\fR, \fBupdate\fR, \fBadd\fR, and \fBoutdated\fR\. +.IP "2." 4 +This setting (\fBbundle config set cooldown N\fR or \fBBUNDLE_COOLDOWN=N\fR)\. +.IP "3." 4 +The per\-source \fBcooldown:\fR keyword in the Gemfile, such as \fBsource "https://rubygems\.org", cooldown: 7\fR\. +.IP "" 0 +.IP +The CLI flag and this setting apply uniformly to every source, including ones declared with their own \fBcooldown:\fR value\. To keep a private registry permanently exempt while still cooling down public gems, declare \fBsource "https://internal", cooldown: 0\fR in the Gemfile; remember that \fB\-\-cooldown N\fR on the command line will still override it for that single run\. +.IP +Cooldown filtering depends on the gem server providing a per\-version \fBcreated_at\fR timestamp in the v2 compact\-index format\. Versions without that metadata \- older gem servers, historical entries that predate the v2 cutover on \fBrubygems\.org\fR, or private registries that still emit the v1 format \- are treated as outside the cooldown window and remain resolvable\. If you rely on cooldown for supply\-chain protection, confirm that the gem server emits \fBcreated_at\fR in its \fB/info/\fR responses\. +.IP "\(bu" 4 +\fBdefault_cli_command\fR (\fBBUNDLE_DEFAULT_CLI_COMMAND\fR): The command that running \fBbundle\fR without arguments should run\. Defaults to \fBcli_help\fR since Bundler 4, but can also be \fBinstall\fR which was the previous default\. +.IP "\(bu" 4 +\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Equivalent to setting \fBfrozen\fR to \fBtrue\fR and \fBpath\fR to \fBvendor/bundle\fR\. +.IP "\(bu" 4 +\fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\. +.IP "\(bu" 4 +\fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\. +.IP "\(bu" 4 +\fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\. +.IP "\(bu" 4 +\fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. +.IP "\(bu" 4 +\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems' normal location\. +.IP "\(bu" 4 +\fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\. +.IP "\(bu" 4 +\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine's platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\. +.IP "\(bu" 4 +\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow any automatic changes to \fBGemfile\.lock\fR\. Bundler commands will be blocked unless the lockfile can be installed exactly as written\. Usually this will happen when changing the \fBGemfile\fR manually and forgetting to update the lockfile through \fBbundle lock\fR or \fBbundle install\fR\. +.IP "\(bu" 4 +\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in the \fBREADME\fR and \fB\.gemspec\fR files when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. +.IP "\(bu" 4 +\fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\. +.IP "\(bu" 4 +\fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\. +.IP "\(bu" 4 +\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems and compiled extensions globally, rather than locally to the configured installation path\. +.IP "\(bu" 4 +\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\. +.IP "\(bu" 4 +\fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. +.IP "\(bu" 4 +\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. +.IP "\(bu" 4 +\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can download and install in parallel\. Defaults to the number of available processors\. +.IP "\(bu" 4 +\fBlockfile\fR (\fBBUNDLE_LOCKFILE\fR): The path to the lockfile that bundler should use\. By default, Bundler adds \fB\.lock\fR to the end of the \fBgemfile\fR entry\. Can be set to \fBfalse\fR in the Gemfile to disable lockfile creation entirely (see gemfile(5))\. +.IP "\(bu" 4 +\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\. Bundler's own checksum is only included when its \fB\.gem\fR file is cached, which may not be the case when Bundler is installed as a default gem\. +.IP "\(bu" 4 +\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\. +.IP "\(bu" 4 +\fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\. +.IP "\(bu" 4 +\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\. Please check carefully if you want to install also gems without a group, because they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\. +.IP "\(bu" 4 +\fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. When not set, Bundler install by default to a \fB\.bundle\fR directory relative to repository root in Bundler 5, and to the default system path (\fBGem\.dir\fR) before Bundler 5\. That means that before Bundler 5, Bundler shares this location with Rubygems, and \fBgem install \|\.\|\.\|\.\fR will have gems installed in the same location and therefore, gems installed without \fBpath\fR set will show up by calling \fBgem list\fR\. This will not be the case in Bundler 5\. +.IP "\(bu" 4 +\fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\. +.IP "\(bu" 4 +\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler's experimental plugin system\. +.IP "\(bu" 4 +\fBprefer_patch\fR (\fBBUNDLE_PREFER_PATCH\fR): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\. +.IP "\(bu" 4 +\fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\. +.IP "\(bu" 4 +\fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\. +.IP "\(bu" 4 +\fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\. +.IP "\(bu" 4 +\fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\. +.IP "\(bu" 4 +\fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\. +.IP "\(bu" 4 +\fBsimulate_version\fR (\fBBUNDLE_SIMULATE_VERSION\fR): The virtual version Bundler should use for activating feature flags\. Can be used to simulate all the new functionality that will be enabled in a future major version\. +.IP "\(bu" 4 +\fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\. +.IP "\(bu" 4 +\fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\. +.IP "\(bu" 4 +\fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\. +.IP "\(bu" 4 +\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\. +.IP "\(bu" 4 +\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. +.IP "\(bu" 4 +\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. +.IP "\(bu" 4 +\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. +.IP "\(bu" 4 +\fBverbose\fR (\fBBUNDLE_VERBOSE\fR): Whether Bundler should print verbose output\. Defaults to \fBfalse\fR, unless the \fB\-\-verbose\fR CLI flag is used\. +.IP "\(bu" 4 +\fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlockfile\fR\. You can also specify \fBsystem\fR or \fBx\.y\.z\fR\. \fBlockfile\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBsystem\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\. +.IP "\(bu" 4 +\fBwith\fR (\fBBUNDLE_WITH\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should install\. +.IP "\(bu" 4 +\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should not install\. +.IP "" 0 +.SH "BUILD OPTIONS" +You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\. +.P +A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\. +.IP "" 4 +.nf +gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config +.fi +.IP "" 0 +.P +Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\. +.IP "" 4 +.nf +bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config +.fi +.IP "" 0 +.P +After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\. +.SH "LOCAL GIT REPOS" +Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override: +.IP "" 4 +.nf +bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository +.fi +.IP "" 0 +.P +Important: This feature only works for gems that are specified with a git source in your Gemfile\. It does not work for gems installed from RubyGems or other sources\. The gem must be defined with \fBgit:\fR option pointing to a remote repository\. +.P +For example, if your Gemfile contains: +.IP "" 4 +.nf +gem "rack", git: "https://github\.com/rack/rack\.git", branch: "main" +.fi +.IP "" 0 +.P +Then you can use a local Rack repository by running: +.IP "" 4 +.nf +bundle config set \-\-local local\.rack ~/Work/git/rack +.fi +.IP "" 0 +.P +Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You'll also need to CGI escape your usernames and passwords as well\. +.P +Bundler does many checks to ensure a developer won't work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\. +.P +Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\. +.P +If you need to temporarily use a local version of a gem that is normally installed from RubyGems (not from git), use a path source instead: +.IP "" 4 +.nf +gem "rack", path: "~/Work/git/rack" +.fi +.IP "" 0 +.SH "MIRRORS OF GEM SOURCES" +Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\. +.IP "" 4 +.nf +bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL +.fi +.IP "" 0 +.P +For example, to use a mirror of https://rubygems\.org hosted at https://example\.org: +.IP "" 4 +.nf +bundle config set \-\-global mirror\.https://rubygems\.org https://example\.org +.fi +.IP "" 0 +.P +Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\. +.IP "" 4 +.nf +bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT +.fi +.IP "" 0 +.P +For example, to fall back to rubygems\.org after 3 seconds: +.IP "" 4 +.nf +bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3 +.fi +.IP "" 0 +.P +The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\. +.SH "CREDENTIALS FOR GEM SOURCES" +Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\. +.IP "" 4 +.nf +bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD +.fi +.IP "" 0 +.P +For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run: +.IP "" 4 +.nf +bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit +.fi +.IP "" 0 +.P +Or you can set the credentials as an environment variable like this: +.IP "" 4 +.nf +export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" +.fi +.IP "" 0 +.P +For gems with a git source with HTTP(S) URL you can specify credentials like so: +.IP "" 4 +.nf +bundle config set \-\-global https://github\.com/ruby/rubygems\.git username:password +.fi +.IP "" 0 +.P +Or you can set the credentials as an environment variable like so: +.IP "" 4 +.nf +export BUNDLE_GITHUB__COM=username:password +.fi +.IP "" 0 +.P +This is especially useful for private repositories on hosts such as GitHub, where you can use personal OAuth tokens: +.IP "" 4 +.nf +export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic +.fi +.IP "" 0 +.P +Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentionally leaking credentials when copy\-pasting bundler output\. +.P +Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: +.IP "\(bu" 4 +Any \fB\-\fR characters in a host name are mapped to a triple underscore (\fB___\fR) in the corresponding environment variable\. +.IP "\(bu" 4 +Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\fR) in the corresponding environment variable\. +.IP "" 0 +.P +This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\. +.SH "CONFIGURE BUNDLER DIRECTORIES" +Bundler's home, cache and plugin directories and config file can be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values +.IP "" 4 +.nf +BUNDLE_USER_HOME : $HOME/\.bundle +BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache +BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config +BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin +.fi +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1.ronn new file mode 100644 index 00000000..582a7b50 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-config.1.ronn @@ -0,0 +1,457 @@ +bundle-config(1) -- Set bundler configuration options +===================================================== + +## SYNOPSIS + +`bundle config` [list]
+`bundle config` [get [--local|--global]] NAME
+`bundle config` [set [--local|--global]] NAME VALUE
+`bundle config` unset [--local|--global] NAME + +## DESCRIPTION + +This command allows you to interact with Bundler's configuration system. + +Bundler loads configuration settings in this order: + +1. Local config (`/.bundle/config` or `$BUNDLE_APP_CONFIG/config`) +2. Environmental variables (`ENV`) +3. Global config (`~/.bundle/config`) +4. Bundler default config + +Executing `bundle` with the `BUNDLE_IGNORE_CONFIG` environment variable set will +cause it to ignore all configuration. + +## SUB-COMMANDS + +### list (default command) + +Executing `bundle config list` will print a list of all bundler +configuration for the current bundle, and where that configuration +was set. + +### get + +Executing `bundle config get ` will print the value of that configuration +setting, and all locations where it was set. + +**OPTIONS** + +* `--local`: + Get configuration from configuration file for the local application, namely, + `/.bundle/config`, or `$BUNDLE_APP_CONFIG/config` if + `BUNDLE_APP_CONFIG` is set. + +* `--global`: + Get configuration from configuration file global to all bundles executed as + the current user, namely, from `~/.bundle/config`. + +### set + +Executing `bundle config set ` defaults to setting `local` +configuration if executing from within a local application, otherwise it will +set `global` configuration. + +**OPTIONS** + +* `--local`: + Executing `bundle config set --local ` will set that configuration + in the directory for the local application. The configuration will be stored in + `/.bundle/config`. If `BUNDLE_APP_CONFIG` is set, the configuration + will be stored in `$BUNDLE_APP_CONFIG/config`. + +* `--global`: + Executing `bundle config set --global ` will set that + configuration to the value specified for all bundles executed as the current + user. The configuration will be stored in `~/.bundle/config`. If already + is set, will be overridden and user will be warned. + +### unset + +Executing `bundle config unset ` will delete the configuration in both +local and global sources. + +**OPTIONS** + +* `--local`: + Executing `bundle config unset --local ` will delete the configuration + only from the local application. + +* `--global`: + Executing `bundle config unset --global ` will delete the configuration + only from the user configuration. + +## CONFIGURATION KEYS + +Configuration keys in bundler have two forms: the canonical form and the +environment variable form. + +For instance, passing the `--without` flag to [bundle install(1)](bundle-install.1.html) +prevents Bundler from installing certain groups specified in the Gemfile(5). Bundler +persists this value in `app/.bundle/config` so that calls to `Bundler.setup` +do not try to find gems from the `Gemfile` that you didn't install. Additionally, +subsequent calls to [bundle install(1)](bundle-install.1.html) remember this setting +and skip those groups. + +The canonical form of this configuration is `"without"`. To convert the canonical +form to the environment variable form, capitalize it, and prepend `BUNDLE_`. The +environment variable form of `"without"` is `BUNDLE_WITHOUT`. + +Any periods in the configuration keys must be replaced with two underscores when +setting it via environment variables. The configuration key `local.rack` becomes +the environment variable `BUNDLE_LOCAL__RACK`. + +## LIST OF AVAILABLE KEYS + +The following is a list of all configuration keys and their purpose. You can +learn more about their operation in [bundle install(1)](bundle-install.1.html). + +* `api_request_size` (`BUNDLE_API_REQUEST_SIZE`): + Configure how many dependencies to fetch when resolving the specifications. + This configuration is only used when fetchig specifications from RubyGems + servers that didn't implement the Compact Index API. + Defaults to 100. +* `auto_install` (`BUNDLE_AUTO_INSTALL`): + Automatically run `bundle install` when gems are missing. +* `bin` (`BUNDLE_BIN`): + If configured, `bundle binstubs` will install executables from gems in the + bundle to the specified directory. Otherwise it will create them in a `bin` + directory relative to the Gemfile directory. These executables run in + Bundler's context. If used, you might add this directory to your + environment's `PATH` variable. For instance, if the `rails` gem comes with a + `rails` executable, `bundle binstubs` will create a `bin/rails` executable + that ensures that all referred dependencies will be resolved using the + bundled gems. +* `cache_all` (`BUNDLE_CACHE_ALL`): + Cache all gems, including path and git gems. This needs to be explicitly + before bundler 4, but will be the default on bundler 4. +* `cache_all_platforms` (`BUNDLE_CACHE_ALL_PLATFORMS`): + Cache gems for all platforms. +* `cache_path` (`BUNDLE_CACHE_PATH`): + The directory that bundler will place cached gems in when running + bundle package, and that bundler will look in when installing gems. + Defaults to `vendor/cache`. +* `clean` (`BUNDLE_CLEAN`): + Whether Bundler should run `bundle clean` automatically after + `bundle install`. Defaults to `true` in Bundler 5, as long as `path` is not + explicitly configured. +* `console` (`BUNDLE_CONSOLE`): + The console that `bundle console` starts. Defaults to `irb`. +* `cooldown` (`BUNDLE_COOLDOWN`): + Number of days a published gem version must age before bundler will + resolve to it. Defaults to unset (no cooldown). Pass `0` to disable + cooldown for an individual run. + + The effective cooldown for any given gem is resolved from three + layers, highest precedence first: + + 1. CLI flag `--cooldown N` on `install`, `update`, `add`, and + `outdated`. + 2. This setting (`bundle config set cooldown N` or + `BUNDLE_COOLDOWN=N`). + 3. The per-source `cooldown:` keyword in the Gemfile, such as + `source "https://rubygems.org", cooldown: 7`. + + The CLI flag and this setting apply uniformly to every source, + including ones declared with their own `cooldown:` value. To keep a + private registry permanently exempt while still cooling down public + gems, declare `source "https://internal", cooldown: 0` in the + Gemfile; remember that `--cooldown N` on the command line will + still override it for that single run. + + Cooldown filtering depends on the gem server providing a per-version + `created_at` timestamp in the v2 compact-index format. Versions + without that metadata - older gem servers, historical entries that + predate the v2 cutover on `rubygems.org`, or private registries that + still emit the v1 format - are treated as outside the cooldown + window and remain resolvable. If you rely on cooldown for + supply-chain protection, confirm that the gem server emits + `created_at` in its `/info/` responses. +* `default_cli_command` (`BUNDLE_DEFAULT_CLI_COMMAND`): + The command that running `bundle` without arguments should run. Defaults to + `cli_help` since Bundler 4, but can also be `install` which was the previous + default. +* `deployment` (`BUNDLE_DEPLOYMENT`): + Equivalent to setting `frozen` to `true` and `path` to `vendor/bundle`. +* `disable_checksum_validation` (`BUNDLE_DISABLE_CHECKSUM_VALIDATION`): + Allow installing gems even if they do not match the checksum provided by + RubyGems. +* `disable_exec_load` (`BUNDLE_DISABLE_EXEC_LOAD`): + Stop Bundler from using `load` to launch an executable in-process in + `bundle exec`. +* `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`): + Allow Bundler to use a local git override without a branch specified in the + Gemfile. +* `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): + Allow Bundler to use a local git override without checking if the revision + present in the lockfile is present in the repository. +* `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): + Stop Bundler from accessing gems installed to RubyGems' normal location. +* `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): + Stop Bundler from checking if a newer Bundler version is available on + rubygems.org. +* `force_ruby_platform` (`BUNDLE_FORCE_RUBY_PLATFORM`): + Ignore the current machine's platform and install only `ruby` platform gems. + As a result, gems with native extensions will be compiled from source. +* `frozen` (`BUNDLE_FROZEN`): + Disallow any automatic changes to `Gemfile.lock`. Bundler commands will + be blocked unless the lockfile can be installed exactly as written. + Usually this will happen when changing the `Gemfile` manually and forgetting + to update the lockfile through `bundle lock` or `bundle install`. +* `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`): + Sets a GitHub username or organization to be used in the `README` and `.gemspec` files + when you create a new gem via `bundle gem` command. It can be overridden by passing an + explicit `--github-username` flag to `bundle gem`. +* `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`): + Sets the `--key` parameter for `gem push` when using the `rake release` + command with a private gemstash server. +* `gemfile` (`BUNDLE_GEMFILE`): + The name of the file that bundler should use as the `Gemfile`. This location + of this file also sets the root of the project, which is used to resolve + relative paths in the `Gemfile`, among other things. By default, bundler + will search up from the current working directory until it finds a + `Gemfile`. +* `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): + Whether Bundler should cache all gems and compiled extensions globally, + rather than locally to the configured installation path. +* `ignore_funding_requests` (`BUNDLE_IGNORE_FUNDING_REQUESTS`): + When set, no funding requests will be printed. +* `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): + When set, no post install messages will be printed. To silence a single gem, + use dot notation like `ignore_messages.httparty true`. +* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`): + Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`. +* `jobs` (`BUNDLE_JOBS`): + The number of gems Bundler can download and install in parallel. + Defaults to the number of available processors. +* `lockfile` (`BUNDLE_LOCKFILE`): + The path to the lockfile that bundler should use. By default, Bundler adds + `.lock` to the end of the `gemfile` entry. Can be set to `false` in the + Gemfile to disable lockfile creation entirely (see gemfile(5)). +* `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`): + Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true. + Bundler's own checksum is only included when its `.gem` file is cached, which + may not be the case when Bundler is installed as a default gem. +* `no_install` (`BUNDLE_NO_INSTALL`): + Whether `bundle package` should skip installing gems. +* `no_prune` (`BUNDLE_NO_PRUNE`): + Whether Bundler should leave outdated gems unpruned when caching. +* `only` (`BUNDLE_ONLY`): + A space-separated list of groups to install only gems of the specified groups. + Please check carefully if you want to install also gems without a group, because + they get put inside `default` group. For example `only test:default` will install + all gems specified in test group and without one. +* `path` (`BUNDLE_PATH`): + The location on disk where all gems in your bundle will be located regardless + of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location + will be installed by `bundle install`. When not set, Bundler install by + default to a `.bundle` directory relative to repository root in Bundler 5, + and to the default system path (`Gem.dir`) before Bundler 5. That means that + before Bundler 5, Bundler shares this location with Rubygems, and `gem + install ...` will have gems installed in the same location and therefore, + gems installed without `path` set will show up by calling `gem list`. This + will not be the case in Bundler 5. +* `path.system` (`BUNDLE_PATH__SYSTEM`): + Whether Bundler will install gems into the default system path (`Gem.dir`). +* `plugins` (`BUNDLE_PLUGINS`): + Enable Bundler's experimental plugin system. +* `prefer_patch` (`BUNDLE_PREFER_PATCH`): + Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`. +* `redirect` (`BUNDLE_REDIRECT`): + The number of redirects allowed for network requests. Defaults to `5`. +* `retry` (`BUNDLE_RETRY`): + The number of times to retry failed network requests. Defaults to `3`. +* `shebang` (`BUNDLE_SHEBANG`): + The program name that should be invoked for generated binstubs. Defaults to + the ruby install name used to generate the binstub. +* `silence_deprecations` (`BUNDLE_SILENCE_DEPRECATIONS`): + Whether Bundler should silence deprecation warnings for behavior that will + be changed in the next major version. +* `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`): + Silence the warning Bundler prints when installing gems as root. +* `simulate_version` (`BUNDLE_SIMULATE_VERSION`): + The virtual version Bundler should use for activating feature flags. Can be + used to simulate all the new functionality that will be enabled in a future + major version. +* `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`): + Path to a designated CA certificate file or folder containing multiple + certificates for trusted CAs in PEM format. +* `ssl_client_cert` (`BUNDLE_SSL_CLIENT_CERT`): + Path to a designated file containing a X.509 client certificate + and key in PEM format. +* `ssl_verify_mode` (`BUNDLE_SSL_VERIFY_MODE`): + The SSL verification mode Bundler uses when making HTTPS requests. + Defaults to verify peer. +* `system_bindir` (`BUNDLE_SYSTEM_BINDIR`): + The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. +* `timeout` (`BUNDLE_TIMEOUT`): + The seconds allowed before timing out for network requests. Defaults to `10`. +* `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): + Require passing `--all` to `bundle update` when everything should be updated, + and disallow passing no options to `bundle update`. +* `user_agent` (`BUNDLE_USER_AGENT`): + The custom user agent fragment Bundler includes in API requests. +* `verbose` (`BUNDLE_VERBOSE`): + Whether Bundler should print verbose output. Defaults to `false`, unless the + `--verbose` CLI flag is used. +* `version` (`BUNDLE_VERSION`): + The version of Bundler to use when running under Bundler environment. + Defaults to `lockfile`. You can also specify `system` or `x.y.z`. + `lockfile` will use the Bundler version specified in the `Gemfile.lock`, + `system` will use the system version of Bundler, and `x.y.z` will use + the specified version of Bundler. +* `with` (`BUNDLE_WITH`): + A space-separated or `:`-separated list of groups whose gems bundler should install. +* `without` (`BUNDLE_WITHOUT`): + A space-separated or `:`-separated list of groups whose gems bundler should not install. + +## BUILD OPTIONS + +You can use `bundle config` to give Bundler the flags to pass to the gem +installer every time bundler tries to install a particular gem. + +A very common example, the `mysql` gem, requires Snow Leopard users to +pass configuration flags to `gem install` to specify where to find the +`mysql_config` executable. + + gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config + +Since the specific location of that executable can change from machine +to machine, you can specify these flags on a per-machine basis. + + bundle config set --global build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config + +After running this command, every time bundler needs to install the +`mysql` gem, it will pass along the flags you specified. + +## LOCAL GIT REPOS + +Bundler also allows you to work against a git repository locally +instead of using the remote version. This can be achieved by setting +up a local override: + + bundle config set --local local.GEM_NAME /path/to/local/git/repository + +Important: This feature only works for gems that are specified with a git +source in your Gemfile. It does not work for gems installed from RubyGems +or other sources. The gem must be defined with `git:` option pointing to a +remote repository. + +For example, if your Gemfile contains: + + gem "rack", git: "https://github.com/rack/rack.git", branch: "main" + +Then you can use a local Rack repository by running: + + bundle config set --local local.rack ~/Work/git/rack + +Now instead of checking out the remote git repository, the local +override will be used. Similar to a path source, every time the local +git repository change, changes will be automatically picked up by +Bundler. This means a commit in the local git repo will update the +revision in the `Gemfile.lock` to the local git repo revision. This +requires the same attention as git submodules. Before pushing to +the remote, you need to ensure the local override was pushed, otherwise +you may point to a commit that only exists in your local machine. +You'll also need to CGI escape your usernames and passwords as well. + +Bundler does many checks to ensure a developer won't work with +invalid references. Particularly, we force a developer to specify +a branch in the `Gemfile` in order to use this feature. If the branch +specified in the `Gemfile` and the current branch in the local git +repository do not match, Bundler will abort. This ensures that +a developer is always working against the correct branches, and prevents +accidental locking to a different branch. + +Finally, Bundler also ensures that the current revision in the +`Gemfile.lock` exists in the local git repository. By doing this, Bundler +forces you to fetch the latest changes in the remotes. + +If you need to temporarily use a local version of a gem that is normally +installed from RubyGems (not from git), use a path source instead: + + gem "rack", path: "~/Work/git/rack" + +## MIRRORS OF GEM SOURCES + +Bundler supports overriding gem sources with mirrors. This allows you to +configure rubygems.org as the gem source in your Gemfile while still using your +mirror to fetch gems. + + bundle config set --global mirror.SOURCE_URL MIRROR_URL + +For example, to use a mirror of https://rubygems.org hosted at https://example.org: + + bundle config set --global mirror.https://rubygems.org https://example.org + +Each mirror also provides a fallback timeout setting. If the mirror does not +respond within the fallback timeout, Bundler will try to use the original +server instead of the mirror. + + bundle config set --global mirror.SOURCE_URL.fallback_timeout TIMEOUT + +For example, to fall back to rubygems.org after 3 seconds: + + bundle config set --global mirror.https://rubygems.org.fallback_timeout 3 + +The default fallback timeout is 0.1 seconds, but the setting can currently +only accept whole seconds (for example, 1, 15, or 30). + +## CREDENTIALS FOR GEM SOURCES + +Bundler allows you to configure credentials for any gem source, which allows +you to avoid putting secrets into your Gemfile. + + bundle config set --global SOURCE_HOSTNAME USERNAME:PASSWORD + +For example, to save the credentials of user `claudette` for the gem source at +`gems.longerous.com`, you would run: + + bundle config set --global gems.longerous.com claudette:s00pers3krit + +Or you can set the credentials as an environment variable like this: + + export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" + +For gems with a git source with HTTP(S) URL you can specify credentials like so: + + bundle config set --global https://github.com/ruby/rubygems.git username:password + +Or you can set the credentials as an environment variable like so: + + export BUNDLE_GITHUB__COM=username:password + +This is especially useful for private repositories on hosts such as GitHub, +where you can use personal OAuth tokens: + + export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic + +Note that any configured credentials will be redacted by informative commands +such as `bundle config list` or `bundle config get`, unless you use the +`--parseable` flag. This is to avoid unintentionally leaking credentials when +copy-pasting bundler output. + +Also note that to guarantee a sane mapping between valid environment variable +names and valid host names, bundler makes the following transformations: + +* Any `-` characters in a host name are mapped to a triple underscore (`___`) in the + corresponding environment variable. + +* Any `.` characters in a host name are mapped to a double underscore (`__`) in the + corresponding environment variable. + +This means that if you have a gem server named `my.gem-host.com`, you'll need to +use the `BUNDLE_MY__GEM___HOST__COM` variable to configure credentials for it +through ENV. + +## CONFIGURE BUNDLER DIRECTORIES + +Bundler's home, cache and plugin directories and config file can be configured +through environment variables. The default location for Bundler's home directory is +`~/.bundle`, which all directories inherit from by default. The following +outlines the available environment variables and their default values + + BUNDLE_USER_HOME : $HOME/.bundle + BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache + BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config + BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1 new file mode 100644 index 00000000..2e56e651 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1 @@ -0,0 +1,33 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-CONSOLE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-console\fR \- Open an IRB session with the bundle pre\-loaded +.SH "SYNOPSIS" +\fBbundle console\fR [GROUP] +.SH "DESCRIPTION" +Starts an interactive Ruby console session in the context of the current bundle\. +.P +If no \fBGROUP\fR is specified, all gems in the \fBdefault\fR group in the Gemfile(5) \fIhttps://guides\.rubygems\.org/gemfile/\fR are preliminarily loaded\. +.P +If \fBGROUP\fR is specified, all gems in the given group in the Gemfile in addition to the gems in \fBdefault\fR group are loaded\. Even if the given group does not exist in the Gemfile, IRB console starts without any warning or error\. +.P +The environment variable \fBBUNDLE_CONSOLE\fR or \fBbundle config set console\fR can be used to change the shell from the following: +.IP "\(bu" 4 +\fBirb\fR (default) +.IP "\(bu" 4 +\fBpry\fR (https://github\.com/pry/pry) +.IP "\(bu" 4 +\fBripl\fR (https://github\.com/cldwalker/ripl) +.IP "" 0 +.P +\fBbundle console\fR uses irb by default\. An alternative Pry or Ripl can be used with \fBbundle console\fR by adjusting the \fBconsole\fR Bundler setting\. Also make sure that \fBpry\fR or \fBripl\fR is in your Gemfile\. +.SH "EXAMPLE" +.nf +$ bundle config set console pry +$ bundle console +Resolving dependencies\|\.\|\.\|\. +[1] pry(main)> +.fi +.SH "SEE ALSO" +Gemfile(5) \fIhttps://guides\.rubygems\.org/gemfile/\fR diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1.ronn new file mode 100644 index 00000000..41a0b634 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-console.1.ronn @@ -0,0 +1,39 @@ +bundle-console(1) -- Open an IRB session with the bundle pre-loaded +=================================================================== + +## SYNOPSIS + +`bundle console` [GROUP] + +## DESCRIPTION + +Starts an interactive Ruby console session in the context of the current bundle. + +If no `GROUP` is specified, all gems in the `default` group in the [Gemfile(5)](https://guides.rubygems.org/gemfile/) are +preliminarily loaded. + +If `GROUP` is specified, all gems in the given group in the Gemfile in addition +to the gems in `default` group are loaded. Even if the given group does not +exist in the Gemfile, IRB console starts without any warning or error. + +The environment variable `BUNDLE_CONSOLE` or `bundle config set console` can be used to change +the shell from the following: + +* `irb` (default) +* `pry` (https://github.com/pry/pry) +* `ripl` (https://github.com/cldwalker/ripl) + +`bundle console` uses irb by default. An alternative Pry or Ripl can be used with +`bundle console` by adjusting the `console` Bundler setting. Also make sure that +`pry` or `ripl` is in your Gemfile. + +## EXAMPLE + + $ bundle config set console pry + $ bundle console + Resolving dependencies... + [1] pry(main)> + +## SEE ALSO + +[Gemfile(5)](https://guides.rubygems.org/gemfile/) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1 new file mode 100644 index 00000000..fe9a8a35 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1 @@ -0,0 +1,69 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-DOCTOR" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-doctor\fR \- Checks the bundle for common problems +.SH "SYNOPSIS" +\fBbundle doctor [diagnose]\fR [\-\-quiet] [\-\-gemfile=GEMFILE] [\-\-ssl] +.br +\fBbundle doctor ssl\fR [\-\-host=HOST] [\-\-tls\-version=TLS\-VERSION] [\-\-verify\-mode=VERIFY\-MODE] +.br +\fBbundle doctor\fR help [COMMAND] +.SH "DESCRIPTION" +You can diagnose common Bundler problems with this command such as checking gem environment or SSL/TLS issue\. +.SH "SUB\-COMMANDS" +.SS "diagnose (default command)" +Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\. +.P +Examples of common problems caught include: +.IP "\(bu" 4 +Invalid Bundler settings +.IP "\(bu" 4 +Mismatched Ruby versions +.IP "\(bu" 4 +Mismatched platforms +.IP "\(bu" 4 +Uninstalled gems +.IP "\(bu" 4 +Missing dependencies +.IP "" 0 +.P +\fBOPTIONS\fR +.TP +\fB\-\-quiet\fR +Only output warnings and errors\. +.TP +\fB\-\-gemfile=GEMFILE\fR +The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. +.TP +\fB\-\-ssl\fR +Diagnose common SSL problems when connecting to https://rubygems\.org\. +.IP +This flag runs the \fBbundle doctor ssl\fR subcommand with default values underneath\. +.SS "ssl" +If you've experienced issues related to SSL certificates and/or TLS versions while connecting to https://rubygems\.org, this command can help troubleshoot common problems\. The diagnostic will perform a few checks such as: +.IP "\(bu" 4 +Verify the Ruby OpenSSL version installed on your system\. +.IP "\(bu" 4 +Check the OpenSSL library version used for compilation\. +.IP "\(bu" 4 +Ensure CA certificates are correctly setup on your machine\. +.IP "\(bu" 4 +Open a TLS connection and verify the outcome\. +.IP "" 0 +.P +\fBOPTIONS\fR +.TP +\fB\-\-host=HOST\fR +Perform the diagnostic on HOST\. Defaults to \fBrubygems\.org\fR\. +.TP +\fB\-\-tls\-version=TLS\-VERSION\fR +Specify the TLS version when opening the connection to HOST\. +.IP +Accepted values are: \fB1\.1\fR or \fB1\.2\fR\. +.TP +\fB\-\-verify\-mode=VERIFY\-MODE\fR +Specify the TLS verify mode when opening the connection to HOST\. Defaults to \fBSSL_VERIFY_PEER\fR\. +.IP +Accepted values are: \fBCLIENT_ONCE\fR, \fBFAIL_IF_NO_PEER_CERT\fR, \fBNONE\fR, \fBPEER\fR\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1.ronn new file mode 100644 index 00000000..7495099f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-doctor.1.ronn @@ -0,0 +1,77 @@ +bundle-doctor(1) -- Checks the bundle for common problems +========================================================= + +## SYNOPSIS + +`bundle doctor [diagnose]` [--quiet] + [--gemfile=GEMFILE] + [--ssl]
+`bundle doctor ssl` [--host=HOST] + [--tls-version=TLS-VERSION] + [--verify-mode=VERIFY-MODE]
+`bundle doctor` help [COMMAND] + +## DESCRIPTION + +You can diagnose common Bundler problems with this command such as checking gem environment or SSL/TLS issue. + +## SUB-COMMANDS + +### diagnose (default command) + +Checks your Gemfile and gem environment for common problems. If issues +are detected, Bundler prints them and exits status 1. Otherwise, +Bundler prints a success message and exits status 0. + +Examples of common problems caught include: + +* Invalid Bundler settings +* Mismatched Ruby versions +* Mismatched platforms +* Uninstalled gems +* Missing dependencies + +**OPTIONS** + +* `--quiet`: + Only output warnings and errors. + +* `--gemfile=GEMFILE`: + The location of the Gemfile(5) which Bundler should use. This defaults + to a Gemfile(5) in the current working directory. In general, Bundler + will assume that the location of the Gemfile(5) is also the project's + root and will try to find `Gemfile.lock` and `vendor/cache` relative + to this location. + +* `--ssl`: + Diagnose common SSL problems when connecting to https://rubygems.org. + + This flag runs the `bundle doctor ssl` subcommand with default values + underneath. + +### ssl + +If you've experienced issues related to SSL certificates and/or TLS versions while connecting +to https://rubygems.org, this command can help troubleshoot common problems. +The diagnostic will perform a few checks such as: + +* Verify the Ruby OpenSSL version installed on your system. +* Check the OpenSSL library version used for compilation. +* Ensure CA certificates are correctly setup on your machine. +* Open a TLS connection and verify the outcome. + +**OPTIONS** + +* `--host=HOST`: + Perform the diagnostic on HOST. Defaults to `rubygems.org`. + +* `--tls-version=TLS-VERSION`: + Specify the TLS version when opening the connection to HOST. + + Accepted values are: `1.1` or `1.2`. + +* `--verify-mode=VERIFY-MODE`: + Specify the TLS verify mode when opening the connection to HOST. + Defaults to `SSL_VERIFY_PEER`. + + Accepted values are: `CLIENT_ONCE`, `FAIL_IF_NO_PEER_CERT`, `NONE`, `PEER`. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1 new file mode 100644 index 00000000..29c4ac2a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1 @@ -0,0 +1,9 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-ENV" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-env\fR \- Print information about the environment Bundler is running under +.SH "SYNOPSIS" +\fBbundle env\fR +.SH "DESCRIPTION" +Prints information about the environment Bundler is running under\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1.ronn new file mode 100644 index 00000000..c2df9c29 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-env.1.ronn @@ -0,0 +1,10 @@ +bundle-env(1) -- Print information about the environment Bundler is running under +================================================================================= + +## SYNOPSIS + +`bundle env` + +## DESCRIPTION + +Prints information about the environment Bundler is running under. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1 new file mode 100644 index 00000000..fec7bee3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1 @@ -0,0 +1,104 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-EXEC" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-exec\fR \- Execute a command in the context of the bundle +.SH "SYNOPSIS" +\fBbundle exec\fR [\-\-gemfile=GEMFILE] \fIcommand\fR +.SH "DESCRIPTION" +This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\. +.P +Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\. +.P +Note that \fBbundle exec\fR does not require that an executable is available on your shell's \fB$PATH\fR\. +.SH "OPTIONS" +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified gemfile instead of [\fBGemfile(5)\fR][Gemfile(5)]\. +.SH "BUNDLE INSTALL \-\-BINSTUBS" +If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\. +.P +After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\. +.SH "ENVIRONMENT MODIFICATIONS" +\fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\. +.IP "\(bu" 4 +make sure that it's still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR) +.IP "\(bu" 4 +put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR +.IP "\(bu" 4 +make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR) +.IP "\(bu" 4 +add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle +.IP "" 0 +.P +It also modifies Rubygems: +.IP "\(bu" 4 +disallow loading additional gems not in the bundle +.IP "\(bu" 4 +modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it's not +.IP "\(bu" 4 +Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment +.IP "\(bu" 4 +Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work +.IP "\(bu" 4 +Add all gems in the bundle into Gem\.loaded_specs +.IP "" 0 +.P +Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem's groups, \fBautorequire\fR, and platforms, etc\., and that information isn't stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\. +.SS "Loading" +By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\. +.SS "Shelling out" +Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don't work inside a bundle: +.IP "" 4 +.nf +Bundler\.with_unbundled_env do + `brew install wget` +end +.fi +.IP "" 0 +.P +Using \fBwith_unbundled_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_unbundled_env\fR\. +.IP "" 4 +.nf +Bundler\.with_unbundled_env do + Dir\.chdir "/other/bundler/project" do + `bundle exec \./script` + end +end +.fi +.IP "" 0 +.P +Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this: +.IP "" 4 +.nf +Bundler\.unbundled_system('brew install wget') +Bundler\.unbundled_exec('brew install wget') +.fi +.IP "" 0 +.SH "RUBYGEMS PLUGINS" +At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\. +.P +Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\. +.P +For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure \fR\. +.P +If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\. +.P +If this happens, bundler will say: +.IP "" 4 +.nf +You have already activated json_pure 1\.4\.6 but your Gemfile +requires json_pure 1\.4\.3\. Consider using bundle exec\. +.fi +.IP "" 0 +.P +In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\. +.P +You can find a list of all the gems containing gem plugins by running +.IP "" 4 +.nf +ruby \-e "puts Gem\.find_files('rubygems_plugin\.rb')" +.fi +.IP "" 0 +.P +At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (\fBgem uninstall gem_name\fR)\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1.ronn new file mode 100644 index 00000000..e51a66a0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-exec.1.ronn @@ -0,0 +1,150 @@ +bundle-exec(1) -- Execute a command in the context of the bundle +================================================================ + +## SYNOPSIS + +`bundle exec` [--gemfile=GEMFILE] + +## DESCRIPTION + +This command executes the command, making all gems specified in the +[`Gemfile(5)`][Gemfile(5)] available to `require` in Ruby programs. + +Essentially, if you would normally have run something like +`rspec spec/my_spec.rb`, and you want to use the gems specified +in the [`Gemfile(5)`][Gemfile(5)] and installed via [bundle install(1)](bundle-install.1.html), you +should run `bundle exec rspec spec/my_spec.rb`. + +Note that `bundle exec` does not require that an executable is +available on your shell's `$PATH`. + +## OPTIONS + +* `--gemfile=GEMFILE`: + Use the specified gemfile instead of [`Gemfile(5)`][Gemfile(5)]. + +## BUNDLE INSTALL --BINSTUBS + +If you use the `--binstubs` flag in [bundle install(1)](bundle-install.1.html), Bundler will +automatically create a directory (which defaults to `app_root/bin`) +containing all of the executables available from gems in the bundle. + +After using `--binstubs`, `bin/rspec spec/my_spec.rb` is identical +to `bundle exec rspec spec/my_spec.rb`. + +## ENVIRONMENT MODIFICATIONS + +`bundle exec` makes a number of changes to the shell environment, +then executes the command you specify in full. + +* make sure that it's still possible to shell out to `bundle` + from inside a command invoked by `bundle exec` (using + `$BUNDLE_BIN_PATH`) +* put the directory containing executables (like `rails`, `rspec`, + `rackup`) for your bundle on `$PATH` +* make sure that if bundler is invoked in the subshell, it uses + the same `Gemfile` (by setting `BUNDLE_GEMFILE`) +* add `-rbundler/setup` to `$RUBYOPT`, which makes sure that + Ruby programs invoked in the subshell can see the gems in + the bundle + +It also modifies Rubygems: + +* disallow loading additional gems not in the bundle +* modify the `gem` method to be a no-op if a gem matching + the requirements is in the bundle, and to raise a + `Gem::LoadError` if it's not +* Define `Gem.refresh` to be a no-op, since the source + index is always frozen when using bundler, and to + prevent gems from the system leaking into the environment +* Override `Gem.bin_path` to use the gems in the bundle, + making system executables work +* Add all gems in the bundle into Gem.loaded_specs + +Finally, `bundle exec` also implicitly modifies `Gemfile.lock` if the lockfile +and the Gemfile do not match. Bundler needs the Gemfile to determine things +such as a gem's groups, `autorequire`, and platforms, etc., and that +information isn't stored in the lockfile. The Gemfile and lockfile must be +synced in order to `bundle exec` successfully, so `bundle exec` +updates the lockfile beforehand. + +### Loading + +By default, when attempting to `bundle exec` to a file with a ruby shebang, +Bundler will `Kernel.load` that file instead of using `Kernel.exec`. For the +vast majority of cases, this is a performance improvement. In a rare few cases, +this could cause some subtle side-effects (such as dependence on the exact +contents of `$0` or `__FILE__`) and the optimization can be disabled by enabling +the `disable_exec_load` setting. + +### Shelling out + +Any Ruby code that opens a subshell (like `system`, backticks, or `%x{}`) will +automatically use the current Bundler environment. If you need to shell out to +a Ruby command that is not part of your current bundle, use the +`with_unbundled_env` method with a block. Any subshells created inside the block +will be given the environment present before Bundler was activated. For +example, Homebrew commands run Ruby, but don't work inside a bundle: + + Bundler.with_unbundled_env do + `brew install wget` + end + +Using `with_unbundled_env` is also necessary if you are shelling out to a different +bundle. Any Bundler commands run in a subshell will inherit the current +Gemfile, so commands that need to run in the context of a different bundle also +need to use `with_unbundled_env`. + + Bundler.with_unbundled_env do + Dir.chdir "/other/bundler/project" do + `bundle exec ./script` + end + end + +Bundler provides convenience helpers that wrap `system` and `exec`, and they +can be used like this: + + Bundler.unbundled_system('brew install wget') + Bundler.unbundled_exec('brew install wget') + + +## RUBYGEMS PLUGINS + +At present, the Rubygems plugin system requires all files +named `rubygems_plugin.rb` on the load path of _any_ installed +gem when any Ruby code requires `rubygems.rb`. This includes +executables installed into the system, like `rails`, `rackup`, +and `rspec`. + +Since Rubygems plugins can contain arbitrary Ruby code, they +commonly end up activating themselves or their dependencies. + +For instance, the `gemcutter 0.5` gem depended on `json_pure`. +If you had that version of gemcutter installed (even if +you _also_ had a newer version without this problem), Rubygems +would activate `gemcutter 0.5` and `json_pure `. + +If your Gemfile(5) also contained `json_pure` (or a gem +with a dependency on `json_pure`), the latest version on +your system might conflict with the version in your +Gemfile(5), or the snapshot version in your `Gemfile.lock`. + +If this happens, bundler will say: + + You have already activated json_pure 1.4.6 but your Gemfile + requires json_pure 1.4.3. Consider using bundle exec. + +In this situation, you almost certainly want to remove the +underlying gem with the problematic gem plugin. In general, +the authors of these plugins (in this case, the `gemcutter` +gem) have released newer versions that are more careful in +their plugins. + +You can find a list of all the gems containing gem plugins +by running + + ruby -e "puts Gem.find_files('rubygems_plugin.rb')" + +At the very least, you should remove all but the newest +version of each gem plugin, and also remove all gem plugins +that you aren't using (`gem uninstall gem_name`). diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1 new file mode 100644 index 00000000..2eb07a6c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1 @@ -0,0 +1,22 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-FUND" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-fund\fR \- Lists information about gems seeking funding assistance +.SH "SYNOPSIS" +\fBbundle fund\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +\fBbundle fund\fR lists information about gems seeking funding assistance\. +.SH "OPTIONS" +.TP +\fB\-\-group=\fR, \fB\-g=\fR +Fetch funding information for a specific group\. +.SH "EXAMPLES" +.nf +# Lists funding information for all gems +bundle fund + +# Lists funding information for a specific group +bundle fund \-\-group=security +.fi + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1.ronn new file mode 100644 index 00000000..faf8b9c4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-fund.1.ronn @@ -0,0 +1,25 @@ +bundle-fund(1) -- Lists information about gems seeking funding assistance +========================================================================= + +## SYNOPSIS + +`bundle fund` [*OPTIONS*] + +## DESCRIPTION + +**bundle fund** lists information about gems seeking funding assistance. + +## OPTIONS + +* `--group=`, `-g=`: + Fetch funding information for a specific group. + +## EXAMPLES + +``` +# Lists funding information for all gems +bundle fund + +# Lists funding information for a specific group +bundle fund --group=security +``` diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1 new file mode 100644 index 00000000..bdb84fae --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1 @@ -0,0 +1,107 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-GEM" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem +.SH "SYNOPSIS" +\fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR +.SH "DESCRIPTION" +Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\. +.P +Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\. +.P +The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler's global configuration file using the following names: +.IP "\(bu" 4 +\fBgem\.coc\fR +.IP "\(bu" 4 +\fBgem\.mit\fR +.IP "\(bu" 4 +\fBgem\.test\fR +.IP "" 0 +.SH "OPTIONS" +.TP +\fB\-\-exe\fR, \fB\-\-bin\fR, \fB\-b\fR +Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. +.TP +\fB\-\-no\-exe\fR +Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. +.TP +\fB\-\-coc\fR +Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.TP +\fB\-\-no\-coc\fR +Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. +.TP +\fB\-\-changelog\fR +Add a \fBCHANGELOG\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. Update the default with \fBbundle config set \-\-global gem\.changelog \fR\. +.TP +\fB\-\-no\-changelog\fR +Do not create a \fBCHANGELOG\.md\fR (overrides \fB\-\-changelog\fR specified in the global config)\. +.TP +\fB\-\-ext=c\fR, \fB\-\-ext=go\fR, \fB\-\-ext=rust\fR +Add boilerplate for C, Go (currently go\-gem\-wrapper \fIhttps://github\.com/ruby\-go\-gem/go\-gem\-wrapper\fR based) or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\. +.TP +\fB\-\-no\-ext\fR +Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\. +.TP +\fB\-\-git\fR +Initialize a git repo inside your library\. +.TP +\fB\-\-github\-username=GITHUB_USERNAME\fR +Fill in GitHub username on README so that you don't have to do it manually\. Set a default with \fBbundle config set \-\-global gem\.github_username \fR\. +.TP +\fB\-\-mit\fR +Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.TP +\fB\-\-no\-mit\fR +Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. +.TP +\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR +Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: +.IP +When Bundler is configured to generate tests, this defaults to Bundler's global config setting \fBgem\.test\fR\. +.IP +When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.TP +\fB\-\-no\-test\fR +Do not use a test framework (overrides \fB\-\-test\fR specified in the global config)\. +.TP +\fB\-\-ci\fR, \fB\-\-ci=circle\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR +Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP +When Bundler is configured to generate CI files, this defaults to Bundler's global config setting \fBgem\.ci\fR\. +.IP +When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.TP +\fB\-\-no\-ci\fR +Do not use a continuous integration service (overrides \fB\-\-ci\fR specified in the global config)\. +.TP +\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR +Specify the linter and code formatter that Bundler should add to the project's development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP +When Bundler is configured to add a linter, this defaults to Bundler's global config setting \fBgem\.linter\fR\. +.IP +When Bundler is configured not to add a linter, an interactive prompt will be displayed and the answer will be used for the current rubygem project\. +.IP +When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\. +.TP +\fB\-\-no\-linter\fR +Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\. +.TP +\fB\-\-edit=EDIT\fR, \fB\-e=EDIT\fR +Open the resulting GEM_NAME\.gemspec in EDIT, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +.TP +\fB\-\-bundle\fR +Run \fBbundle install\fR after creating the gem\. +.TP +\fB\-\-no\-bundle\fR +Do not run \fBbundle install\fR after creating the gem\. +.SH "SEE ALSO" +.IP "\(bu" 4 +bundle config(1) \fIbundle\-config\.1\.html\fR +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1.ronn new file mode 100644 index 00000000..488c8113 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-gem.1.ronn @@ -0,0 +1,150 @@ +bundle-gem(1) -- Generate a project skeleton for creating a rubygem +=================================================================== + +## SYNOPSIS + +`bundle gem` [OPTIONS] + +## DESCRIPTION + +Generates a directory named `GEM_NAME` with a `Rakefile`, `GEM_NAME.gemspec`, +and other supporting files and directories that can be used to develop a +rubygem with that name. + +Run `rake -T` in the resulting project for a list of Rake tasks that can be used +to test and publish the gem to rubygems.org. + +The generated project skeleton can be customized with OPTIONS, as explained +below. Note that these options can also be specified via Bundler's global +configuration file using the following names: + +* `gem.coc` +* `gem.mit` +* `gem.test` + +## OPTIONS + +* `--exe`, `--bin`, `-b`: + Specify that Bundler should create a binary executable (as `exe/GEM_NAME`) + in the generated rubygem project. This binary will also be added to the + `GEM_NAME.gemspec` manifest. This behavior is disabled by default. + +* `--no-exe`: + Do not create a binary (overrides `--exe` specified in the global config). + +* `--coc`: + Add a `CODE_OF_CONDUCT.md` file to the root of the generated project. If + this option is unspecified, an interactive prompt will be displayed and the + answer will be saved in Bundler's global config for future `bundle gem` use. + +* `--no-coc`: + Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the + global config). + +* `--changelog`: + Add a `CHANGELOG.md` file to the root of the generated project. If + this option is unspecified, an interactive prompt will be displayed and the + answer will be saved in Bundler's global config for future `bundle gem` use. + Update the default with `bundle config set --global gem.changelog `. + +* `--no-changelog`: + Do not create a `CHANGELOG.md` (overrides `--changelog` specified in the + global config). + +* `--ext=c`, `--ext=go`, `--ext=rust`: + Add boilerplate for C, Go (currently [go-gem-wrapper](https://github.com/ruby-go-gem/go-gem-wrapper) based) or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior + is disabled by default. + +* `--no-ext`: + Do not add extension code (overrides `--ext` specified in the global + config). + +* `--git`: + Initialize a git repo inside your library. + +* `--github-username=GITHUB_USERNAME`: + Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username `. + +* `--mit`: + Add an MIT license to a `LICENSE.txt` file in the root of the generated + project. Your name from the global git config is used for the copyright + statement. If this option is unspecified, an interactive prompt will be + displayed and the answer will be saved in Bundler's global config for future + `bundle gem` use. + +* `--no-mit`: + Do not create a `LICENSE.txt` (overrides `--mit` specified in the global + config). + +* `-t`, `--test=minitest`, `--test=rspec`, `--test=test-unit`: + Specify the test framework that Bundler should use when generating the + project. Acceptable values are `minitest`, `rspec` and `test-unit`. The + `GEM_NAME.gemspec` will be configured and a skeleton test/spec directory will + be created based on this option. Given no option is specified: + + When Bundler is configured to generate tests, this defaults to Bundler's + global config setting `gem.test`. + + When Bundler is configured to not generate tests, an interactive prompt will + be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `--no-test`: + Do not use a test framework (overrides `--test` specified in the global + config). + +* `--ci`, `--ci=circle`, `--ci=github`, `--ci=gitlab`: + Specify the continuous integration service that Bundler should use when + generating the project. Acceptable values are `github`, `gitlab` + and `circle`. A configuration file will be generated in the project directory. + Given no option is specified: + + When Bundler is configured to generate CI files, this defaults to Bundler's + global config setting `gem.ci`. + + When Bundler is configured to not generate CI files, an interactive prompt + will be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `--no-ci`: + Do not use a continuous integration service (overrides `--ci` specified in + the global config). + +* `--linter`, `--linter=rubocop`, `--linter=standard`: + Specify the linter and code formatter that Bundler should add to the + project's development dependencies. Acceptable values are `rubocop` and + `standard`. A configuration file will be generated in the project directory. + Given no option is specified: + + When Bundler is configured to add a linter, this defaults to Bundler's + global config setting `gem.linter`. + + When Bundler is configured not to add a linter, an interactive prompt + will be displayed and the answer will be used for the current rubygem project. + + When Bundler is unconfigured, an interactive prompt will be displayed and + the answer will be saved in Bundler's global config for future `bundle gem` + use. + +* `--no-linter`: + Do not add a linter (overrides `--linter` specified in the global config). + +* `--edit=EDIT`, `-e=EDIT`: + Open the resulting GEM_NAME.gemspec in EDIT, or the default editor if not + specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`. + +* `--bundle`: + Run `bundle install` after creating the gem. + +* `--no-bundle`: + Do not run `bundle install` after creating the gem. + +## SEE ALSO + +* [bundle config(1)](bundle-config.1.html) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1 new file mode 100644 index 00000000..6e6ad146 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1 @@ -0,0 +1,9 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-HELP" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-help\fR \- Displays detailed help for each subcommand +.SH "SYNOPSIS" +\fBbundle help\fR [COMMAND] +.SH "DESCRIPTION" +Displays detailed help for the given subcommand\. You can specify a single \fBCOMMAND\fR at the same time\. When \fBCOMMAND\fR is omitted, help for \fBhelp\fR command will be displayed\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1.ronn new file mode 100644 index 00000000..0e144aea --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-help.1.ronn @@ -0,0 +1,12 @@ +bundle-help(1) -- Displays detailed help for each subcommand +============================================================ + +## SYNOPSIS + +`bundle help` [COMMAND] + +## DESCRIPTION + +Displays detailed help for the given subcommand. +You can specify a single `COMMAND` at the same time. +When `COMMAND` is omitted, help for `help` command will be displayed. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1 new file mode 100644 index 00000000..b18b7030 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1 @@ -0,0 +1,17 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-INFO" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-info\fR \- Show information for the given gem in your bundle +.SH "SYNOPSIS" +\fBbundle info\fR [GEM_NAME] [\-\-path] [\-\-version] +.SH "DESCRIPTION" +Given a gem name present in your bundle, print the basic information about it such as homepage, version, path and summary\. +.SH "OPTIONS" +.TP +\fB\-\-path\fR +Print the path of the given gem +.TP +\fB\-\-version\fR +Print gem version + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1.ronn new file mode 100644 index 00000000..e99db8c6 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-info.1.ronn @@ -0,0 +1,21 @@ +bundle-info(1) -- Show information for the given gem in your bundle +=================================================================== + +## SYNOPSIS + +`bundle info` [GEM_NAME] + [--path] + [--version] + +## DESCRIPTION + +Given a gem name present in your bundle, print the basic information about it + such as homepage, version, path and summary. + +## OPTIONS + +* `--path`: + Print the path of the given gem + +* `--version`: + Print gem version diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1 new file mode 100644 index 00000000..661ad1d2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1 @@ -0,0 +1,20 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-INIT" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-init\fR \- Generates a Gemfile into the current working directory +.SH "SYNOPSIS" +\fBbundle init\fR [\-\-gemspec=FILE] +.SH "DESCRIPTION" +Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\. +.SH "OPTIONS" +.TP +\fB\-\-gemspec=GEMSPEC\fR +Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)] +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified name for the gemfile instead of \fBGemfile\fR +.SH "FILES" +Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\. +.SH "SEE ALSO" +Gemfile(5) \fIhttps://guides\.rubygems\.org/gemfile/\fR diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1.ronn new file mode 100644 index 00000000..39238931 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-init.1.ronn @@ -0,0 +1,32 @@ +bundle-init(1) -- Generates a Gemfile into the current working directory +======================================================================== + +## SYNOPSIS + +`bundle init` [--gemspec=FILE] + +## DESCRIPTION + +Init generates a default [`Gemfile(5)`][Gemfile(5)] in the current working directory. When +adding a [`Gemfile(5)`][Gemfile(5)] to a gem with a gemspec, the `--gemspec` option will +automatically add each dependency listed in the gemspec file to the newly +created [`Gemfile(5)`][Gemfile(5)]. + +## OPTIONS + +* `--gemspec=GEMSPEC`: + Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)] + +* `--gemfile=GEMFILE`: + Use the specified name for the gemfile instead of `Gemfile` + +## FILES + +Included in the default [`Gemfile(5)`][Gemfile(5)] +generated is the line `# frozen_string_literal: true`. This is a magic comment +supported for the first time in Ruby 2.3. The presence of this line +results in all string literals in the file being implicitly frozen. + +## SEE ALSO + +[Gemfile(5)](https://guides.rubygems.org/gemfile/) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1 new file mode 100644 index 00000000..7c2e9eea --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1 @@ -0,0 +1,178 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-INSTALL" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile +.SH "SYNOPSIS" +\fBbundle install\fR [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-lockfile=LOCKFILE] [\-\-no\-cache] [\-\-no\-lock] [\-\-prefer\-local] [\-\-quiet] [\-\-retry=NUMBER] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-trust\-policy=TRUST\-POLICY] [\-\-target\-rbconfig=TARGET\-RBCONFIG] +.SH "DESCRIPTION" +Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\. +.P +If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\. +.P +If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\. +.SH "OPTIONS" +.TP +\fB\-\-cooldown=\fR +Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. See \fBcooldown\fR in bundle\-config(1) for details on the precedence between the CLI flag, Bundler config, and Gemfile per\-source settings\. +.TP +\fB\-\-force\fR, \fB\-\-redownload\fR +Force reinstalling every gem, even if already installed\. +.TP +\fB\-\-full\-index\fR +Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\. +.TP +\fB\-\-gemfile=GEMFILE\fR +The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\. +.TP +\fB\-\-jobs=\fR, \fB\-j=\fR +The maximum number of parallel download and install jobs\. The default is the number of available processors\. +.TP +\fB\-\-local\fR +Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. +.TP +\fB\-\-lockfile=LOCKFILE\fR +The location of the lockfile which Bundler should use\. This defaults to the Gemfile location with \fB\.lock\fR appended\. +.TP +\fB\-\-prefer\-local\fR +Force using locally installed gems, or gems already present in Rubygems' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\. +.TP +\fB\-\-no\-cache\fR +Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. +.TP +\fB\-\-no\-lock\fR +Do not create a lockfile\. Useful if you want to install dependencies but not lock versions of gems\. Recommended for library development, and other situations where the code is expected to work with a range of dependency versions\. +.IP +This has the same effect as using \fBlockfile false\fR in the Gemfile\. See gemfile(5) for more information\. +.TP +\fB\-\-quiet\fR +Do not print progress information to the standard output\. +.TP +\fB\-\-retry=[]\fR +Retry failed network or git requests for \fInumber\fR times\. +.TP +\fB\-\-standalone[=]\fR +Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install can be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler's own setup in the manner required\. +.TP +\fB\-\-trust\-policy=TRUST\-POLICY\fR +Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\. +.TP +\fB\-\-target\-rbconfig=TARGET\-RBCONFIG\fR +Path to rbconfig\.rb for the deployment target platform\. +.SH "DEPLOYMENT MODE" +Bundler's defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fBdeployment\fR setting\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\. +.IP "1." 4 +A \fBGemfile\.lock\fR is required\. +.IP +To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\. +.IP +This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\. +.IP "2." 4 +The \fBGemfile\.lock\fR must be up to date +.IP +In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\. +.IP +In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\. +.IP "3." 4 +Gems are installed to \fBvendor/bundle\fR not your default system location +.IP +In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system\. +.IP +In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\. +.IP +As a result, when \fBdeployment\fR is configured, \fBbundle install\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fBpath\fR setting\. +.IP "" 0 +.SH "INSTALLING GROUPS" +By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\. +.P +However, you can explicitly tell Bundler to skip installing certain groups with the \fBwithout\fR setting\. This setting takes a space\-separated list of groups\. +.P +While the \fBwithout\fR setting will skip \fIinstalling\fR the gems in the specified groups, \fBbundle install\fR will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\. +.P +This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\. +.P +\fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR +.P +For a simple illustration, consider the following Gemfile(5): +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'sinatra' + +group :production do + gem 'rack\-perftools\-profiler' +end +.fi +.IP "" 0 +.P +In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\. +.P +When you configure \fBbundle config without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\. +.P +This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\. +.P +This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\. +.SH "THE GEMFILE\.LOCK" +When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\. +.P +Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\. +.P +Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\. +.P +As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\. +.P +When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\. +.SH "CONSERVATIVE UPDATING" +When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\. +.P +In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\. +.P +Let's take a look at an example\. Here's your original Gemfile(5): +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'actionpack', '2\.3\.8' +gem 'activemerchant' +.fi +.IP "" 0 +.P +In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\. +.P +When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\. +.P +Next, you modify your Gemfile(5) to: +.IP "" 4 +.nf +source 'https://rubygems\.org' + +gem 'actionpack', '3\.0\.0\.rc' +gem 'activemerchant' +.fi +.IP "" 0 +.P +The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\. +.P +When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements: +.TP +\fBactivesupport 2\.3\.8\fR +also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated +.TP +\fBrack ~> 1\.1\.0\fR +not currently being used to satisfy another dependency +.P +Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\. +.P +Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\. +.P +To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\. +.P +\fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\. +.SH "SEE ALSO" +.IP "\(bu" 4 +Gem install docs \fIhttps://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR +.IP "\(bu" 4 +Rubygems signing docs \fIhttps://guides\.rubygems\.org/security/\fR +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1.ronn new file mode 100644 index 00000000..56fd8bdf --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-install.1.ronn @@ -0,0 +1,314 @@ +bundle-install(1) -- Install the dependencies specified in your Gemfile +======================================================================= + +## SYNOPSIS + +`bundle install` [--cooldown=NUMBER] + [--force] + [--full-index] + [--gemfile=GEMFILE] + [--jobs=NUMBER] + [--local] + [--lockfile=LOCKFILE] + [--no-cache] + [--no-lock] + [--prefer-local] + [--quiet] + [--retry=NUMBER] + [--standalone[=GROUP[ GROUP...]]] + [--trust-policy=TRUST-POLICY] + [--target-rbconfig=TARGET-RBCONFIG] + +## DESCRIPTION + +Install the gems specified in your Gemfile(5). If this is the first +time you run bundle install (and a `Gemfile.lock` does not exist), +Bundler will fetch all remote sources, resolve dependencies and +install all needed gems. + +If a `Gemfile.lock` does exist, and you have not updated your Gemfile(5), +Bundler will fetch all remote sources, but use the dependencies +specified in the `Gemfile.lock` instead of resolving dependencies. + +If a `Gemfile.lock` does exist, and you have updated your Gemfile(5), +Bundler will use the dependencies in the `Gemfile.lock` for all gems +that you did not update, but will re-resolve the dependencies of +gems that you did update. You can find more information about this +update process below under [CONSERVATIVE UPDATING][]. + +## OPTIONS + +* `--cooldown=`: + Only consider gem versions published at least days ago when + resolving. Pass `0` to disable cooldown for this run, overriding any + per-source or global configuration. See `cooldown` in bundle-config(1) + for details on the precedence between the CLI flag, Bundler config, + and Gemfile per-source settings. + +* `--force`, `--redownload`: + Force reinstalling every gem, even if already installed. + +* `--full-index`: + Bundler will not call Rubygems' API endpoint (default) but download and cache + a (currently big) index file of all gems. Performance can be improved for + large bundles that seldom change by enabling this option. + +* `--gemfile=GEMFILE`: + The location of the Gemfile(5) which Bundler should use. This defaults + to a Gemfile(5) in the current working directory. In general, Bundler + will assume that the location of the Gemfile(5) is also the project's + root and will try to find `Gemfile.lock` and `vendor/cache` relative + to this location. + +* `--jobs=`, `-j=`: + The maximum number of parallel download and install jobs. The default is the + number of available processors. + +* `--local`: + Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the + gems already present in Rubygems' cache or in `vendor/cache`. Note that if an + appropriate platform-specific gem exists on `rubygems.org` it will not be + found. + +* `--lockfile=LOCKFILE`: + The location of the lockfile which Bundler should use. This defaults + to the Gemfile location with `.lock` appended. + +* `--prefer-local`: + Force using locally installed gems, or gems already present in Rubygems' cache + or in `vendor/cache`, when resolving, even if newer versions are available + remotely. Only attempt to connect to `rubygems.org` for gems that are not + present locally. + +* `--no-cache`: + Do not update the cache in `vendor/cache` with the newly bundled gems. This + does not remove any gems in the cache but keeps the newly bundled gems from + being cached during the install. + +* `--no-lock`: + Do not create a lockfile. Useful if you want to install dependencies but not + lock versions of gems. Recommended for library development, and other + situations where the code is expected to work with a range of dependency + versions. + + This has the same effect as using `lockfile false` in the Gemfile. + See gemfile(5) for more information. + +* `--quiet`: + Do not print progress information to the standard output. + +* `--retry=[]`: + Retry failed network or git requests for times. + +* `--standalone[=]`: + Makes a bundle that can work without depending on Rubygems or Bundler at + runtime. A space separated list of groups to install can be specified. + Bundler creates a directory named `bundle` and installs the bundle there. It + also generates a `bundle/bundler/setup.rb` file to replace Bundler's own setup + in the manner required. + +* `--trust-policy=TRUST-POLICY`: + Apply the Rubygems security policy , where policy is one of + `HighSecurity`, `MediumSecurity`, `LowSecurity`, `AlmostNoSecurity`, or + `NoSecurity`. For more details, please see the Rubygems signing documentation + linked below in [SEE ALSO][]. + +* `--target-rbconfig=TARGET-RBCONFIG`: + Path to rbconfig.rb for the deployment target platform. + +## DEPLOYMENT MODE + +Bundler's defaults are optimized for development. To switch to +defaults optimized for deployment and for CI, use the `deployment` +setting. Do not activate deployment mode on development machines, as it +will cause an error when the Gemfile(5) is modified. + +1. A `Gemfile.lock` is required. + + To ensure that the same versions of the gems you developed with + and tested with are also used in deployments, a `Gemfile.lock` + is required. + + This is mainly to ensure that you remember to check your + `Gemfile.lock` into version control. + +2. The `Gemfile.lock` must be up to date + + In development, you can modify your Gemfile(5) and re-run + `bundle install` to [conservatively update][CONSERVATIVE UPDATING] + your `Gemfile.lock` snapshot. + + In deployment, your `Gemfile.lock` should be up-to-date with + changes made in your Gemfile(5). + +3. Gems are installed to `vendor/bundle` not your default system location + + In development, it's convenient to share the gems used in your + application with other applications and other scripts that run on + the system. + + In deployment, isolation is a more important default. In addition, + the user deploying the application may not have permission to install + gems to the system, or the web server may not have permission to + read them. + + As a result, when `deployment` is configured, `bundle install` installs gems + to the `vendor/bundle` directory in the application. This may be + overridden using the `path` setting. + +## INSTALLING GROUPS + +By default, `bundle install` will install all gems in all groups +in your Gemfile(5), except those declared for a different platform. + +However, you can explicitly tell Bundler to skip installing +certain groups with the `without` setting. This setting takes +a space-separated list of groups. + +While the `without` setting will skip _installing_ the gems in the +specified groups, `bundle install` will still _download_ those gems and use them +to resolve the dependencies of every gem in your Gemfile(5). + +This is so that installing a different set of groups on another + machine (such as a production server) will not change the +gems and versions that you have already developed and tested against. + +`Bundler offers a rock-solid guarantee that the third-party +code you are running in development and testing is also the +third-party code you are running in production. You can choose +to exclude some of that code in different environments, but you +will never be caught flat-footed by different versions of +third-party code being used in different environments.` + +For a simple illustration, consider the following Gemfile(5): + + source 'https://rubygems.org' + + gem 'sinatra' + + group :production do + gem 'rack-perftools-profiler' + end + +In this case, `sinatra` depends on any version of Rack (`>= 1.0`), while +`rack-perftools-profiler` depends on 1.x (`~> 1.0`). + +When you configure `bundle config without production` in development, we +look at the dependencies of `rack-perftools-profiler` as well. That way, +you do not spend all your time developing against Rack 2.0, using new +APIs unavailable in Rack 1.x, only to have Bundler switch to Rack 1.2 +when the `production` group _is_ used. + +This should not cause any problems in practice, because we do not +attempt to `install` the gems in the excluded groups, and only evaluate +as part of the dependency resolution process. + +This also means that you cannot include different versions of the same +gem in different groups, because doing so would result in different +sets of dependencies used in development and production. Because of +the vagaries of the dependency resolution process, this usually +affects more than the gems you list in your Gemfile(5), and can +(surprisingly) radically change the gems you are using. + +## THE GEMFILE.LOCK + +When you run `bundle install`, Bundler will persist the full names +and versions of all gems that you used (including dependencies of +the gems specified in the Gemfile(5)) into a file called `Gemfile.lock`. + +Bundler uses this file in all subsequent calls to `bundle install`, +which guarantees that you always use the same exact code, even +as your application moves across machines. + +Because of the way dependency resolution works, even a +seemingly small change (for instance, an update to a point-release +of a dependency of a gem in your Gemfile(5)) can result in radically +different gems being needed to satisfy all dependencies. + +As a result, you `SHOULD` check your `Gemfile.lock` into version +control, in both applications and gems. If you do not, every machine that +checks out your repository (including your production server) will resolve all +dependencies again, which will result in different versions of +third-party code being used if `any` of the gems in the Gemfile(5) +or any of their dependencies have been updated. + +When Bundler first shipped, the `Gemfile.lock` was included in the `.gitignore` +file included with generated gems. Over time, however, it became clear that +this practice forces the pain of broken dependencies onto new contributors, +while leaving existing contributors potentially unaware of the problem. Since +`bundle install` is usually the first step towards a contribution, the pain of +broken dependencies would discourage new contributors from contributing. As a +result, we have revised our guidance for gem authors to now recommend checking +in the lock for gems. + +## CONSERVATIVE UPDATING + +When you make a change to the Gemfile(5) and then run `bundle install`, +Bundler will update only the gems that you modified. + +In other words, if a gem that you `did not modify` worked before +you called `bundle install`, it will continue to use the exact +same versions of all dependencies as it used before the update. + +Let's take a look at an example. Here's your original Gemfile(5): + + source 'https://rubygems.org' + + gem 'actionpack', '2.3.8' + gem 'activemerchant' + +In this case, both `actionpack` and `activemerchant` depend on +`activesupport`. The `actionpack` gem depends on `activesupport 2.3.8` +and `rack ~> 1.1.0`, while the `activemerchant` gem depends on +`activesupport >= 2.3.2`, `braintree >= 2.0.0`, and `builder >= 2.0.0`. + +When the dependencies are first resolved, Bundler will select +`activesupport 2.3.8`, which satisfies the requirements of both +gems in your Gemfile(5). + +Next, you modify your Gemfile(5) to: + + source 'https://rubygems.org' + + gem 'actionpack', '3.0.0.rc' + gem 'activemerchant' + +The `actionpack 3.0.0.rc` gem has a number of new dependencies, +and updates the `activesupport` dependency to `= 3.0.0.rc` and +the `rack` dependency to `~> 1.2.1`. + +When you run `bundle install`, Bundler notices that you changed +the `actionpack` gem, but not the `activemerchant` gem. It +evaluates the gems currently being used to satisfy its requirements: + + * `activesupport 2.3.8`: + also used to satisfy a dependency in `activemerchant`, + which is not being updated + * `rack ~> 1.1.0`: + not currently being used to satisfy another dependency + +Because you did not explicitly ask to update `activemerchant`, +you would not expect it to suddenly stop working after updating +`actionpack`. However, satisfying the new `activesupport 3.0.0.rc` +dependency of actionpack requires updating one of its dependencies. + +Even though `activemerchant` declares a very loose dependency +that theoretically matches `activesupport 3.0.0.rc`, Bundler treats +gems in your Gemfile(5) that have not changed as an atomic unit +together with their dependencies. In this case, the `activemerchant` +dependency is treated as `activemerchant 1.7.1 + activesupport 2.3.8`, +so `bundle install` will report that it cannot update `actionpack`. + +To explicitly update `actionpack`, including its dependencies +which other gems in the Gemfile(5) still depend on, run +`bundle update actionpack` (see `bundle update(1)`). + +`Summary`: In general, after making a change to the Gemfile(5) , you +should first try to run `bundle install`, which will guarantee that no +other gem in the Gemfile(5) is impacted by the change. If that +does not work, run [bundle update(1)](bundle-update.1.html). + +## SEE ALSO + +* [Gem install docs](https://guides.rubygems.org/rubygems-basics/#installing-gems) +* [Rubygems signing docs](https://guides.rubygems.org/security/) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1 new file mode 100644 index 00000000..e99cf676 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1 @@ -0,0 +1,45 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-ISSUE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-issue\fR \- Get help reporting Bundler issues +.SH "SYNOPSIS" +\fBbundle issue\fR +.SH "DESCRIPTION" +Provides guidance on reporting Bundler issues and outputs detailed system information that should be included when filing a bug report\. This command: +.IP "1." 4 +Displays links to troubleshooting resources +.IP "2." 4 +Shows instructions for reporting issues +.IP "3." 4 +Outputs comprehensive environment information needed for debugging +.IP "" 0 +.P +The command helps ensure that bug reports include all necessary system details for effective troubleshooting\. +.SH "OUTPUT" +The command outputs several sections: +.IP "\(bu" 4 +Troubleshooting links and resources +.IP "\(bu" 4 +Link to the GitHub issue template +.IP "\(bu" 4 +Environment information including: Bundler version and platforms, Ruby version and configuration, RubyGems version and paths, Development tool versions (Git, RVM, rbenv, chruby) +.IP "\(bu" 4 +Bundler build metadata +.IP "\(bu" 4 +Current Bundler settings +.IP "\(bu" 4 +Bundle Doctor output +.IP "" 0 +.SH "EXAMPLES" +Get issue reporting information: +.IP "" 4 +.nf +$ bundle issue +.fi +.IP "" 0 +.SH "SEE ALSO" +.IP "\(bu" 4 +bundle\-doctor(1) +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1.ronn new file mode 100644 index 00000000..37f676a3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-issue.1.ronn @@ -0,0 +1,37 @@ +bundle-issue(1) -- Get help reporting Bundler issues +==================================================== + +## SYNOPSIS + +`bundle issue` + +## DESCRIPTION + +Provides guidance on reporting Bundler issues and outputs detailed system information that should be included when filing a bug report. This command: + +1. Displays links to troubleshooting resources +2. Shows instructions for reporting issues +3. Outputs comprehensive environment information needed for debugging + +The command helps ensure that bug reports include all necessary system details for effective troubleshooting. + +## OUTPUT + +The command outputs several sections: + +* Troubleshooting links and resources +* Link to the GitHub issue template +* Environment information including: Bundler version and platforms, Ruby version and configuration, RubyGems version and paths, Development tool versions (Git, RVM, rbenv, chruby) +* Bundler build metadata +* Current Bundler settings +* Bundle Doctor output + +## EXAMPLES + +Get issue reporting information: + + $ bundle issue + +## SEE ALSO + +* bundle-doctor(1) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1 new file mode 100644 index 00000000..eb5f7203 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1 @@ -0,0 +1,9 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-LICENSES" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-licenses\fR \- Print the license of all gems in the bundle +.SH "SYNOPSIS" +\fBbundle licenses\fR +.SH "DESCRIPTION" +Prints the license of all gems in the bundle\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1.ronn new file mode 100644 index 00000000..91caba6c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-licenses.1.ronn @@ -0,0 +1,10 @@ +bundle-licenses(1) -- Print the license of all gems in the bundle +================================================================= + +## SYNOPSIS + +`bundle licenses` + +## DESCRIPTION + +Prints the license of all gems in the bundle. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1 new file mode 100644 index 00000000..69276822 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1 @@ -0,0 +1,40 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-LIST" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-list\fR \- List all the gems in the bundle +.SH "SYNOPSIS" +\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-only\-group=GROUP[ GROUP\|\.\|\.\|\.]] +.SH "DESCRIPTION" +Prints a list of all the gems in the bundle including their version\. +.P +Example: +.P +bundle list \-\-name\-only +.P +bundle list \-\-paths +.P +bundle list \-\-without\-group test +.P +bundle list \-\-only\-group dev +.P +bundle list \-\-only\-group dev test \-\-paths +.P +bundle list \-\-format json +.SH "OPTIONS" +.TP +\fB\-\-name\-only\fR +Print only the name of each gem\. +.TP +\fB\-\-paths\fR +Print the path to each gem in the bundle\. +.TP +\fB\-\-without\-group=\fR +A space\-separated list of groups of gems to skip during printing\. +.TP +\fB\-\-only\-group=\fR +A space\-separated list of groups of gems to print\. +.TP +\fB\-\-format=FORMAT\fR +Format output ('json' is the only supported format) + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1.ronn new file mode 100644 index 00000000..9ec2b132 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-list.1.ronn @@ -0,0 +1,41 @@ +bundle-list(1) -- List all the gems in the bundle +================================================= + +## SYNOPSIS + +`bundle list` [--name-only] [--paths] [--without-group=GROUP[ GROUP...]] [--only-group=GROUP[ GROUP...]] + +## DESCRIPTION + +Prints a list of all the gems in the bundle including their version. + +Example: + +bundle list --name-only + +bundle list --paths + +bundle list --without-group test + +bundle list --only-group dev + +bundle list --only-group dev test --paths + +bundle list --format json + +## OPTIONS + +* `--name-only`: + Print only the name of each gem. + +* `--paths`: + Print the path to each gem in the bundle. + +* `--without-group=`: + A space-separated list of groups of gems to skip during printing. + +* `--only-group=`: + A space-separated list of groups of gems to print. + +* `--format=FORMAT`: + Format output ('json' is the only supported format) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1 new file mode 100644 index 00000000..130b50fe --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1 @@ -0,0 +1,78 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-LOCK" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing +.SH "SYNOPSIS" +\fBbundle lock\fR [\-\-update] [\-\-bundler[=BUNDLER]] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-add\-checksums] [\-\-add\-platform] [\-\-remove\-platform] [\-\-normalize\-platforms] [\-\-patch] [\-\-minor] [\-\-major] [\-\-pre] [\-\-strict] [\-\-conservative] [\-\-cooldown=NUMBER] +.SH "DESCRIPTION" +Lock the gems specified in Gemfile\. +.SH "OPTIONS" +.TP +\fB\-\-update[=]\fR +Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\. +.TP +\fB\-\-bundler[=BUNDLER]\fR +Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\. +.TP +\fB\-\-local\fR +Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. +.TP +\fB\-\-print\fR +Prints the lockfile to STDOUT instead of writing to the file system\. +.TP +\fB\-\-lockfile=LOCKFILE\fR +The path where the lockfile should be written to\. +.TP +\fB\-\-full\-index\fR +Fall back to using the single\-file index of all gems\. +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified gemfile instead of [\fBGemfile(5)\fR][Gemfile(5)]\. +.TP +\fB\-\-add\-checksums\fR +Add checksums to the lockfile\. +.TP +\fB\-\-add\-platform=\fR +Add a new platform to the lockfile, re\-resolving for the addition of that platform\. +.TP +\fB\-\-remove\-platform=\fR +Remove a platform from the lockfile\. +.TP +\fB\-\-normalize\-platforms\fR +Normalize lockfile platforms\. +.TP +\fB\-\-patch\fR +If updating, prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +If updating, prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +If updating, prefer updating to next major version (default)\. +.TP +\fB\-\-pre\fR +If updating, always choose the highest allowed version, regardless of prerelease status\. +.TP +\fB\-\-strict\fR +If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\. +.TP +\fB\-\-conservative\fR +If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\. +.TP +\fB\-\-cooldown=\fR +Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. See \fBcooldown\fR in bundle\-config(1)\. +.SH "UPDATING ALL GEMS" +If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. +.SH "UPDATING A LIST OF GEMS" +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.P +For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\. +.P +Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.SH "SUPPORTING OTHER PLATFORMS" +If you want your bundle to support platforms other than the one you're running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\. +.P +For a full explanation of gem platforms, see \fBgem help platform\fR\. +.SH "PATCH LEVEL OPTIONS" +See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1.ronn new file mode 100644 index 00000000..96c37a66 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-lock.1.ronn @@ -0,0 +1,122 @@ +bundle-lock(1) -- Creates / Updates a lockfile without installing +================================================================= + +## SYNOPSIS + +`bundle lock` [--update] + [--bundler[=BUNDLER]] + [--local] + [--print] + [--lockfile=PATH] + [--full-index] + [--gemfile=GEMFILE] + [--add-checksums] + [--add-platform] + [--remove-platform] + [--normalize-platforms] + [--patch] + [--minor] + [--major] + [--pre] + [--strict] + [--conservative] + [--cooldown=NUMBER] + +## DESCRIPTION + +Lock the gems specified in Gemfile. + +## OPTIONS + +* `--update[=]`: + Ignores the existing lockfile. Resolve then updates lockfile. Taking a list + of gems or updating all gems if no list is given. + +* `--bundler[=BUNDLER]`: + Update the locked version of bundler. BUNDLER can be a version such as + `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the + latest released version, which never selects a prerelease. + +* `--local`: + Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the + gems already present in Rubygems' cache or in `vendor/cache`. Note that if a + appropriate platform-specific gem exists on `rubygems.org` it will not be + found. + +* `--print`: + Prints the lockfile to STDOUT instead of writing to the file system. + +* `--lockfile=LOCKFILE`: + The path where the lockfile should be written to. + +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--gemfile=GEMFILE`: + Use the specified gemfile instead of [`Gemfile(5)`][Gemfile(5)]. + +* `--add-checksums`: + Add checksums to the lockfile. + +* `--add-platform=`: + Add a new platform to the lockfile, re-resolving for the addition of that + platform. + +* `--remove-platform=`: + Remove a platform from the lockfile. + +* `--normalize-platforms`: + Normalize lockfile platforms. + +* `--patch`: + If updating, prefer updating only to next patch version. + +* `--minor`: + If updating, prefer updating only to next minor version. + +* `--major`: + If updating, prefer updating to next major version (default). + +* `--pre`: + If updating, always choose the highest allowed version, regardless of prerelease status. + +* `--strict`: + If updating, do not allow any gem to be updated past latest --patch | --minor | --major. + +* `--conservative`: + If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated. + +* `--cooldown=`: + Only consider gem versions published at least days ago when + resolving. Pass `0` to disable cooldown for this run, overriding any + per-source or global configuration. See `cooldown` in bundle-config(1). + +## UPDATING ALL GEMS + +If you run `bundle lock` with `--update` option without list of gems, bundler will +ignore any previously installed gems and resolve all dependencies again based +on the latest versions of all gems available in the sources. + +## UPDATING A LIST OF GEMS + +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of +the gems that you specified locked to the versions in the `Gemfile.lock`. + +For instance, you only want to update `nokogiri`, run `bundle lock --update nokogiri`. + +Bundler will update `nokogiri` and any of its dependencies, but leave the rest of the +gems that you specified locked to the versions in the `Gemfile.lock`. + +## SUPPORTING OTHER PLATFORMS + +If you want your bundle to support platforms other than the one you're running +locally, you can run `bundle lock --add-platform PLATFORM` to add PLATFORM to +the lockfile, force bundler to re-resolve and consider the new platform when +picking gems, all without needing to have a machine that matches PLATFORM handy +to install those platform-specific gems on. + +For a full explanation of gem platforms, see `gem help platform`. + +## PATCH LEVEL OPTIONS + +See [bundle update(1)](bundle-update.1.html) for details. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1 new file mode 100644 index 00000000..99166e85 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1 @@ -0,0 +1,32 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-OPEN" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle +.SH "SYNOPSIS" +\fBbundle open\fR [GEM] [\-\-path=PATH] +.SH "DESCRIPTION" +Opens the source directory of the provided GEM in your editor\. +.P +For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\. +.P +Example: +.IP "" 4 +.nf +bundle open 'rack' +.fi +.IP "" 0 +.P +Will open the source directory for the 'rack' gem in your bundle\. +.IP "" 4 +.nf +bundle open 'rack' \-\-path 'README\.md' +.fi +.IP "" 0 +.P +Will open the README\.md file of the 'rack' gem source in your bundle\. +.SH "OPTIONS" +.TP +\fB\-\-path[=PATH]\fR +Specify GEM source relative path to open\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1.ronn new file mode 100644 index 00000000..24dbe97e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-open.1.ronn @@ -0,0 +1,28 @@ +bundle-open(1) -- Opens the source directory for a gem in your bundle +===================================================================== + +## SYNOPSIS + +`bundle open` [GEM] [--path=PATH] + +## DESCRIPTION + +Opens the source directory of the provided GEM in your editor. + +For this to work the `EDITOR` or `BUNDLER_EDITOR` environment variable has to +be set. + +Example: + + bundle open 'rack' + +Will open the source directory for the 'rack' gem in your bundle. + + bundle open 'rack' --path 'README.md' + +Will open the README.md file of the 'rack' gem source in your bundle. + +## OPTIONS + +* `--path[=PATH]`: + Specify GEM source relative path to open. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1 new file mode 100644 index 00000000..5118a377 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1 @@ -0,0 +1,106 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-OUTDATED" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-outdated\fR \- List installed gems with newer versions available +.SH "SYNOPSIS" +\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-filter\-strict | \-\-strict] [\-\-update\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit] [\-\-cooldown=NUMBER] +.SH "DESCRIPTION" +Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\. +.SH "OPTIONS" +.TP +\fB\-\-local\fR +Do not attempt to fetch gems remotely and use the gem cache instead\. +.TP +\fB\-\-pre\fR +Check for newer pre\-release gems\. +.TP +\fB\-\-source=\fR +Check against a specific source\. +.TP +\fB\-\-filter\-strict\fR, \fB\-\-strict\fR +Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (\-\-patch, \-\-minor, \-\-major)\. +.TP +\fB\-\-update\-strict\fR +Strict conservative resolution, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\. +.TP +\fB\-\-parseable\fR, \fB\-\-porcelain\fR +Use minimal formatting for more parseable output\. +.TP +\fB\-\-group=GROUP\fR +List gems from a specific group\. +.TP +\fB\-\-groups\fR +List gems organized by groups\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-filter\-major\fR +Only list major newer versions\. +.TP +\fB\-\-filter\-minor\fR +Only list minor newer versions\. +.TP +\fB\-\-filter\-patch\fR +Only list patch newer versions\. +.TP +\fB\-\-only\-explicit\fR +Only list gems specified in your Gemfile, not their dependencies\. +.TP +\fB\-\-cooldown=\fR +Annotate (rather than hide) versions that are still inside the cooldown window of \fInumber\fR days\. The prose output appends "in cooldown for Nd more days" and the table form adds "(cooldown Nd)" to the Latest column\. When a version outside the window is newer than the installed one, the prose output also appends "newest out of cooldown X" and the table form becomes "(cooldown Nd, X out of cooldown)"\. With \fB\-\-filter\-strict\fR (or \fB\-\-patch\fR, \fB\-\-minor\fR, \fB\-\-major\fR, which imply it), "newest" is already the cooldown\-filtered resolved version, so none of these annotations appear\. See \fBcooldown\fR in bundle\-config(1)\. +.SH "PATCH LEVEL OPTIONS" +See bundle update(1) \fIbundle\-update\.1\.html\fR for details\. +.SH "FILTERING OUTPUT" +The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\. +.P +If the regular output shows the following: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups Release Date +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05 +* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10 +* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19 +.fi +.IP "" 0 +.P +\fB\-\-filter\-major\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups Release Date +* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default 2023\-11\-10 +.fi +.IP "" 0 +.P +\fB\-\-filter\-minor\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups Release Date +* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test 2022\-08\-19 +.fi +.IP "" 0 +.P +\fB\-\-filter\-patch\fR would only show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups Release Date +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05 +.fi +.IP "" 0 +.P +Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show: +.IP "" 4 +.nf +* Gem Current Latest Requested Groups Release Date +* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test 2024\-02\-05 +.fi +.IP "" 0 +.P +Combining all three \fBfilter\fR options would be the same result as providing none of them\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1.ronn new file mode 100644 index 00000000..468b84d0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-outdated.1.ronn @@ -0,0 +1,123 @@ +bundle-outdated(1) -- List installed gems with newer versions available +======================================================================= + +## SYNOPSIS + +`bundle outdated` [GEM] [--local] + [--pre] + [--source] + [--filter-strict | --strict] + [--update-strict] + [--parseable | --porcelain] + [--group=GROUP] + [--groups] + [--patch|--minor|--major] + [--filter-major] + [--filter-minor] + [--filter-patch] + [--only-explicit] + [--cooldown=NUMBER] + +## DESCRIPTION + +Outdated lists the names and versions of gems that have a newer version available +in the given source. Calling outdated with [GEM [GEM]] will only check for newer +versions of the given gems. Prerelease gems are ignored by default. If your gems +are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. + +## OPTIONS + +* `--local`: + Do not attempt to fetch gems remotely and use the gem cache instead. + +* `--pre`: + Check for newer pre-release gems. + +* `--source=`: + Check against a specific source. + +* `--filter-strict`, `--strict`: + Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (--patch, --minor, --major). + +* `--update-strict`: + Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major. + +* `--parseable`, `--porcelain`: + Use minimal formatting for more parseable output. + +* `--group=GROUP`: + List gems from a specific group. + +* `--groups`: + List gems organized by groups. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--patch`: + Prefer updating only to next patch version. + +* `--filter-major`: + Only list major newer versions. + +* `--filter-minor`: + Only list minor newer versions. + +* `--filter-patch`: + Only list patch newer versions. + +* `--only-explicit`: + Only list gems specified in your Gemfile, not their dependencies. + +* `--cooldown=`: + Annotate (rather than hide) versions that are still inside the + cooldown window of days. The prose output appends "in + cooldown for Nd more days" and the table form adds "(cooldown Nd)" to + the Latest column. When a version outside the window is newer than the + installed one, the prose output also appends "newest out of cooldown + X" and the table form becomes "(cooldown Nd, X out of cooldown)". + With `--filter-strict` (or `--patch`, `--minor`, `--major`, which + imply it), "newest" is already the cooldown-filtered resolved version, + so none of these annotations appear. See `cooldown` in + bundle-config(1). + +## PATCH LEVEL OPTIONS + +See [bundle update(1)](bundle-update.1.html) for details. + +## FILTERING OUTPUT + +The 3 filtering options do not affect the resolution of versions, merely what versions are shown +in the output. + +If the regular output shows the following: + + * Gem Current Latest Requested Groups Release Date + * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05 + * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10 + * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19 + +`--filter-major` would only show: + + * Gem Current Latest Requested Groups Release Date + * hashie 1.2.0 3.4.6 = 1.2.0 default 2023-11-10 + +`--filter-minor` would only show: + + * Gem Current Latest Requested Groups Release Date + * headless 2.2.3 2.3.1 = 2.2.3 test 2022-08-19 + +`--filter-patch` would only show: + + * Gem Current Latest Requested Groups Release Date + * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05 + +Filter options can be combined. `--filter-minor` and `--filter-patch` would show: + + * Gem Current Latest Requested Groups Release Date + * faker 1.6.5 1.6.6 ~> 1.4 development, test 2024-02-05 + +Combining all three `filter` options would be the same result as providing none of them. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1 new file mode 100644 index 00000000..f60939b7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1 @@ -0,0 +1,53 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-PLATFORM" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-platform\fR \- Displays platform compatibility information +.SH "SYNOPSIS" +\fBbundle platform\fR [\-\-ruby] +.SH "DESCRIPTION" +\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. +.P +For instance, using this Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +ruby "3\.1\.2" + +gem "rack" +.fi +.IP "" 0 +.P +If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output: +.IP "" 4 +.nf +Your platform is: x86_64\-linux + +Your app has gems that work on these platforms: +* arm64\-darwin\-21 +* ruby +* x64\-mingw\-ucrt +* x86_64\-linux + +Your Gemfile specifies a Ruby version requirement: +* ruby 3\.1\.2 + +Your current platform satisfies the Ruby version requirement\. +.fi +.IP "" 0 +.P +\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn't match the running Ruby VM, it tells you what part does not\. +.P +For a detailed explanation of how bundler handles platforms, see the \fBPLATFORMS\fR section in Gemfile(5)\. +.SH "OPTIONS" +.TP +\fB\-\-ruby\fR +It will display the ruby directive information, so you don't have to parse it from the Gemfile(5)\. +.SH "SEE ALSO" +.IP "\(bu" 4 +bundle\-lock(1) \fIbundle\-lock\.1\.html\fR +.IP "\(bu" 4 +Gemfile(5) \fIgemfile\.5\.html\fR +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1.ronn new file mode 100644 index 00000000..421be7df --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-platform.1.ronn @@ -0,0 +1,53 @@ +bundle-platform(1) -- Displays platform compatibility information +================================================================= + +## SYNOPSIS + +`bundle platform` [--ruby] + +## DESCRIPTION + +`platform` displays information from your Gemfile, Gemfile.lock, and Ruby +VM about your platform. + +For instance, using this Gemfile(5): + + source "https://rubygems.org" + + ruby "3.1.2" + + gem "rack" + +If you run `bundle platform` on Ruby 3.1.2, it displays the following output: + + Your platform is: x86_64-linux + + Your app has gems that work on these platforms: + * arm64-darwin-21 + * ruby + * x64-mingw-ucrt + * x86_64-linux + + Your Gemfile specifies a Ruby version requirement: + * ruby 3.1.2 + + Your current platform satisfies the Ruby version requirement. + +`platform` lists all the platforms in your `Gemfile.lock` as well as the +`ruby` directive if applicable from your Gemfile(5). It also lets you know +if the `ruby` directive requirement has been met. If `ruby` directive doesn't +match the running Ruby VM, it tells you what part does not. + +For a detailed explanation of how bundler handles platforms, see the +`PLATFORMS` section in Gemfile(5). + +## OPTIONS + +* `--ruby`: + It will display the ruby directive information, so you don't have to + parse it from the Gemfile(5). + +## SEE ALSO + +* [bundle-lock(1)](bundle-lock.1.html) +* [Gemfile(5)](gemfile.5.html) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1 new file mode 100644 index 00000000..56f215c5 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1 @@ -0,0 +1,76 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-PLUGIN" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-plugin\fR \- Manage Bundler plugins +.SH "SYNOPSIS" +\fBbundle plugin\fR install PLUGINS [\-\-source=SOURCE] [\-\-version=VERSION] [\-\-git=GIT] [\-\-branch=BRANCH|\-\-ref=REF] [\-\-path=PATH] +.br +\fBbundle plugin\fR uninstall PLUGINS [\-\-all] +.br +\fBbundle plugin\fR list +.br +\fBbundle plugin\fR help [COMMAND] +.SH "DESCRIPTION" +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler\. +.SH "SUB\-COMMANDS" +.SS "install" +Install the given plugin(s)\. +.P +For example, \fBbundle plugin install bundler\-graph\fR will install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. Note that the global source specified in Gemfile is ignored\. +.P +\fBOPTIONS\fR +.TP +\fB\-\-source=SOURCE\fR +Install the plugin gem from a specific source, rather than from globally configured sources\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR +.TP +\fB\-\-version=VERSION\fR +Specify a version of the plugin gem to install via \fB\-\-version\fR\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR +.TP +\fB\-\-git=GIT\fR +Install the plugin gem from a Git repository\. You can use standard Git URLs like: +.IP +\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR +.br +\fBhttp[s]://host\.xz[:port]/path/to/repo\.git\fR +.br +\fB/path/to/repo\fR +.br +\fBfile:///path/to/repo\fR +.IP +Example: \fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR +.TP +\fB\-\-branch=BRANCH\fR +When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR to use\. +.TP +\fB\-\-ref=REF\fR +When you specify \fB\-\-git\fR, you can use \fB\-\-ref\fR to specify any tag, or commit hash (revision) to use\. +.TP +\fB\-\-path=PATH\fR +Install the plugin gem from a local path\. +.IP +Example: \fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR +.SS "uninstall" +Uninstall the plugin(s) specified in PLUGINS\. +.P +\fBOPTIONS\fR +.TP +\fB\-\-all\fR +Uninstall all the installed plugins\. If no plugin is installed, then it does nothing\. +.SS "list" +List the installed plugins and available commands\. +.P +No options\. +.SS "help" +Describe subcommands or one specific subcommand\. +.P +No options\. +.SH "SEE ALSO" +.IP "\(bu" 4 +How to write a Bundler plugin \fIhttps://guides\.rubygems\.org/bundler_plugins/\fR +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1.ronn new file mode 100644 index 00000000..e5cf9eb1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-plugin.1.ronn @@ -0,0 +1,84 @@ +bundle-plugin(1) -- Manage Bundler plugins +========================================== + +## SYNOPSIS + +`bundle plugin` install PLUGINS [--source=SOURCE] [--version=VERSION] + [--git=GIT] [--branch=BRANCH|--ref=REF] + [--path=PATH]
+`bundle plugin` uninstall PLUGINS [--all]
+`bundle plugin` list
+`bundle plugin` help [COMMAND] + +## DESCRIPTION + +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler. + +## SUB-COMMANDS + +### install + +Install the given plugin(s). + +For example, `bundle plugin install bundler-graph` will install bundler-graph +gem from globally configured sources (defaults to RubyGems.org). Note that the +global source specified in Gemfile is ignored. + +**OPTIONS** + +* `--source=SOURCE`: + Install the plugin gem from a specific source, rather than from globally configured sources. + + Example: `bundle plugin install bundler-graph --source https://example.com` + +* `--version=VERSION`: + Specify a version of the plugin gem to install via `--version`. + + Example: `bundle plugin install bundler-graph --version 0.2.1` + +* `--git=GIT`: + Install the plugin gem from a Git repository. You can use standard Git URLs like: + + `ssh://[user@]host.xz[:port]/path/to/repo.git`
+ `http[s]://host.xz[:port]/path/to/repo.git`
+ `/path/to/repo`
+ `file:///path/to/repo` + + Example: `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph` + +* `--branch=BRANCH`: + When you specify `--git`, you can use `--branch` to use. + +* `--ref=REF`: + When you specify `--git`, you can use `--ref` to specify any tag, or commit + hash (revision) to use. + +* `--path=PATH`: + Install the plugin gem from a local path. + + Example: `bundle plugin install bundler-graph --path ../bundler-graph` + +### uninstall + +Uninstall the plugin(s) specified in PLUGINS. + +**OPTIONS** + +* `--all`: + Uninstall all the installed plugins. If no plugin is installed, then it does nothing. + +### list + +List the installed plugins and available commands. + +No options. + +### help + +Describe subcommands or one specific subcommand. + +No options. + +## SEE ALSO + +* [How to write a Bundler plugin](https://guides.rubygems.org/bundler_plugins/) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1 new file mode 100644 index 00000000..cbfc5139 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1 @@ -0,0 +1,23 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-PRISTINE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition +.SH "SYNOPSIS" +\fBbundle pristine\fR +.SH "DESCRIPTION" +\fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\. +.P +For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem's git repository as if one were installing from scratch\. +.P +Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from\. +.P +When is it practical to use \fBbundle pristine\fR? +.P +It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\. +.P +Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR? +.P +Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\. +.P +If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1.ronn new file mode 100644 index 00000000..984debeb --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-pristine.1.ronn @@ -0,0 +1,34 @@ +bundle-pristine(1) -- Restores installed gems to their pristine condition +========================================================================= + +## SYNOPSIS + +`bundle pristine` + +## DESCRIPTION + +`pristine` restores the installed gems in the bundle to their pristine condition +using the local gem cache from RubyGems. For git gems, a forced checkout will be performed. + +For further explanation, `bundle pristine` ignores unpacked files on disk. In other +words, this command utilizes the local `.gem` cache or the gem's git repository +as if one were installing from scratch. + +Note: the Bundler gem cannot be restored to its original state with `pristine`. +One also cannot use `bundle pristine` on gems with a 'path' option in the Gemfile, +because bundler has no original copy it can restore from. + +When is it practical to use `bundle pristine`? + +It comes in handy when a developer is debugging a gem. `bundle pristine` is a +great way to get rid of experimental changes to a gem that one may not want. + +Why use `bundle pristine` over `gem pristine --all`? + +Both commands are very similar. +For context: `bundle pristine`, without arguments, cleans all gems from the lockfile. +Meanwhile, `gem pristine --all` cleans all installed gems for that Ruby version. + +If a developer forgets which gems in their project they might +have been debugging, the Rubygems `gem pristine [GEMNAME]` command may be inconvenient. +One can avoid waiting for `gem pristine --all`, and instead run `bundle pristine`. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1 new file mode 100644 index 00000000..f8981f9f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1 @@ -0,0 +1,15 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-REMOVE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-remove\fR \- Removes gems from the Gemfile +.SH "SYNOPSIS" +`bundle remove [GEM [GEM \|\.\|\.\|\.]] +.SH "DESCRIPTION" +Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\. +.P +Example: +.P +bundle remove rails +.P +bundle remove rails rack diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1.ronn new file mode 100644 index 00000000..49cb4dc1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-remove.1.ronn @@ -0,0 +1,16 @@ +bundle-remove(1) -- Removes gems from the Gemfile +================================================= + +## SYNOPSIS + +`bundle remove [GEM [GEM ...]] + +## DESCRIPTION + +Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If a gem cannot be removed, a warning is printed. If a gem is already absent from the Gemfile, and error is raised. + +Example: + +bundle remove rails + +bundle remove rails rack diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1 new file mode 100644 index 00000000..aaf146fa --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1 @@ -0,0 +1,16 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-SHOW" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem +.SH "SYNOPSIS" +\fBbundle show\fR [GEM] [\-\-paths] +.SH "DESCRIPTION" +Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\. +.P +Calling show with [GEM] will list the exact location of that gem on your machine\. +.SH "OPTIONS" +.TP +\fB\-\-paths\fR +List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\. + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1.ronn new file mode 100644 index 00000000..a6a59a14 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-show.1.ronn @@ -0,0 +1,21 @@ +bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem +========================================================================= + +## SYNOPSIS + +`bundle show` [GEM] + [--paths] + +## DESCRIPTION + +Without the [GEM] option, `show` will print a list of the names and versions of +all gems that are required by your [`Gemfile(5)`][Gemfile(5)], sorted by name. + +Calling show with [GEM] will list the exact location of that gem on your +machine. + +## OPTIONS + +* `--paths`: + List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)], + sorted by gem name. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1 new file mode 100644 index 00000000..1e9081b9 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1 @@ -0,0 +1,284 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-UPDATE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-update\fR \- Update your gems to the latest available versions +.SH "SYNOPSIS" +\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-cooldown=NUMBER] [\-\-force] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-pre] [\-\-strict] [\-\-conservative] +.SH "DESCRIPTION" +Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\. +.P +You would use \fBbundle update\fR to explicitly update the version of a gem\. +.SH "OPTIONS" +.TP +\fB\-\-all\fR +Update all gems specified in Gemfile\. +.TP +\fB\-\-group=\fR, \fB\-g=\fR +Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\. +.TP +\fB\-\-source=\fR +The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR +.TP +\fB\-\-local\fR +Do not attempt to fetch gems remotely and use the gem cache instead\. +.TP +\fB\-\-ruby\fR +Update the locked version of Ruby to the current version of Ruby\. +.TP +\fB\-\-bundler[=BUNDLER]\fR +Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\. +.TP +\fB\-\-force\fR, \fB\-\-redownload\fR +Force reinstalling every gem, even if already installed\. +.TP +\fB\-\-full\-index\fR +Fall back to using the single\-file index of all gems\. +.TP +\fB\-\-gemfile=GEMFILE\fR +Use the specified gemfile instead of [\fBGemfile(5)\fR][Gemfile(5)]\. +.TP +\fB\-\-jobs=\fR, \fB\-j=\fR +Specify the number of jobs to run in parallel\. The default is the number of available processors\. +.TP +\fB\-\-retry=[]\fR +Retry failed network or git requests for \fInumber\fR times\. +.TP +\fB\-\-quiet\fR +Only output warnings and errors\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-pre\fR +Always choose the highest allowed version, regardless of prerelease status\. +.TP +\fB\-\-strict\fR +Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. +.TP +\fB\-\-conservative\fR +Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. +.TP +\fB\-\-cooldown=\fR +Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. Combine with \fB\-\-conservative\fR to minimize transitive churn when bypassing cooldown for an urgent update\. See \fBcooldown\fR in bundle\-config(1)\. +.SH "UPDATING ALL GEMS" +If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. +.P +Consider the following Gemfile(5): +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "rails", "3\.0\.0\.rc" +gem "nokogiri" +.fi +.IP "" 0 +.P +When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need: +.IP "" 4 +.nf +Fetching gem metadata from https://rubygems\.org/\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\. +Resolving dependencies\|\.\|\.\|\. +Installing builder 2\.1\.2 +Installing abstract 1\.0\.0 +Installing rack 1\.2\.8 +Using bundler 1\.7\.6 +Installing rake 10\.4\.0 +Installing polyglot 0\.3\.5 +Installing mime\-types 1\.25\.1 +Installing i18n 0\.4\.2 +Installing mini_portile 0\.6\.1 +Installing tzinfo 0\.3\.42 +Installing rack\-mount 0\.6\.14 +Installing rack\-test 0\.5\.7 +Installing treetop 1\.4\.15 +Installing thor 0\.14\.6 +Installing activesupport 3\.0\.0\.rc +Installing erubis 2\.6\.6 +Installing activemodel 3\.0\.0\.rc +Installing arel 0\.4\.0 +Installing mail 2\.2\.20 +Installing activeresource 3\.0\.0\.rc +Installing actionpack 3\.0\.0\.rc +Installing activerecord 3\.0\.0\.rc +Installing actionmailer 3\.0\.0\.rc +Installing railties 3\.0\.0\.rc +Installing rails 3\.0\.0\.rc +Installing nokogiri 1\.6\.5 + +Bundle complete! 2 Gemfile dependencies, 26 gems total\. +Use `bundle show [gemname]` to see where a bundled gem is installed\. +.fi +.IP "" 0 +.P +As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\. +.P +After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don't need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\. +.P +However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\. +.P +To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\. +.SH "UPDATING A LIST OF GEMS" +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\. +.P +For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\. +.P +Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\. +.SH "OVERLAPPING DEPENDENCIES" +Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\. +.IP "" 4 +.nf +source "https://rubygems\.org" + +gem "thin" +gem "rack\-perftools\-profiler" +.fi +.IP "" 0 +.P +The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get: +.IP "" 4 +.nf +Fetching source index for https://rubygems\.org/ +Installing daemons (1\.1\.0) +Installing eventmachine (0\.12\.10) with native extensions +Installing open4 (1\.0\.1) +Installing perftools\.rb (0\.4\.7) with native extensions +Installing rack (1\.2\.1) +Installing rack\-perftools_profiler (0\.0\.2) +Installing thin (1\.2\.7) with native extensions +Using bundler (1\.0\.0\.rc\.3) +.fi +.IP "" 0 +.P +In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it's \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\. +.P +In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. +.P +To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: +.P +In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. +.P +Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. +.SH "PATCH LEVEL OPTIONS" +Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. +.TP +\fB\-\-patch\fR +Prefer updating only to next patch version\. +.TP +\fB\-\-minor\fR +Prefer updating only to next minor version\. +.TP +\fB\-\-major\fR +Prefer updating to next major version (default)\. +.TP +\fB\-\-strict\fR +Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\. +.P +When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\. +.P +Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\. +.P +For example, if gem 'foo' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. +.P +If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\. +.P +If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\. +.P +Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\. +.P +To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\. +.P +Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is '~> 1\.0', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\. +.SH "PATCH LEVEL EXAMPLES" +Given the following gem specifications: +.IP "" 4 +.nf +foo 1\.4\.3, requires: ~> bar 2\.0 +foo 1\.4\.4, requires: ~> bar 2\.0 +foo 1\.4\.5, requires: ~> bar 2\.1 +foo 1\.5\.0, requires: ~> bar 2\.1 +foo 1\.5\.1, requires: ~> bar 3\.0 +bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0 +.fi +.IP "" 0 +.P +Gemfile: +.IP "" 4 +.nf +gem 'foo' +.fi +.IP "" 0 +.P +Gemfile\.lock: +.IP "" 4 +.nf +foo (1\.4\.3) + bar (~> 2\.0) +bar (2\.0\.3) +.fi +.IP "" 0 +.P +Cases: +.IP "" 4 +.nf +# Command Line Result +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +1 bundle update \-\-patch 'foo 1\.4\.5', 'bar 2\.1\.1' +2 bundle update \-\-patch foo 'foo 1\.4\.5', 'bar 2\.1\.1' +3 bundle update \-\-minor 'foo 1\.5\.1', 'bar 3\.0\.0' +4 bundle update \-\-minor \-\-strict 'foo 1\.5\.0', 'bar 2\.1\.1' +5 bundle update \-\-patch \-\-strict 'foo 1\.4\.4', 'bar 2\.0\.4' +.fi +.IP "" 0 +.P +In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\. +.P +In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile\. +.P +In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\. +.P +In case 4, foo is preferred up to a minor version, but 1\.5\.1 won't work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it's a major increment\. +.P +In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\. +.SH "RECOMMENDED WORKFLOW" +In general, when working with an application managed with bundler, you should use the following workflow: +.IP "\(bu" 4 +After you create your Gemfile(5) for the first time, run +.IP +$ bundle install +.IP "\(bu" 4 +Check the resulting \fBGemfile\.lock\fR into version control +.IP +$ git add Gemfile\.lock +.IP "\(bu" 4 +When checking out this repository on another development machine, run +.IP +$ bundle install +.IP "\(bu" 4 +When checking out this repository on a deployment machine, run +.IP +$ bundle install \-\-deployment +.IP "\(bu" 4 +After changing the Gemfile(5) to reflect a new or update dependency, run +.IP +$ bundle install +.IP "\(bu" 4 +Make sure to check the updated \fBGemfile\.lock\fR into version control +.IP +$ git add Gemfile\.lock +.IP "\(bu" 4 +If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5) +.IP +$ bundle update rails thin +.IP "\(bu" 4 +If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run +.IP +$ bundle update \-\-all +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1.ronn new file mode 100644 index 00000000..659ec2da --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-update.1.ronn @@ -0,0 +1,369 @@ +bundle-update(1) -- Update your gems to the latest available versions +===================================================================== + +## SYNOPSIS + +`bundle update` <*gems> [--all] + [--group=NAME] + [--source=NAME] + [--local] + [--ruby] + [--bundler[=VERSION]] + [--cooldown=NUMBER] + [--force] + [--full-index] + [--gemfile=GEMFILE] + [--jobs=NUMBER] + [--quiet] + [--patch|--minor|--major] + [--pre] + [--strict] + [--conservative] + +## DESCRIPTION + +Update the gems specified (all gems, if `--all` flag is used), ignoring +the previously installed gems specified in the `Gemfile.lock`. In +general, you should use [bundle install(1)](bundle-install.1.html) to install the same exact +gems and versions across machines. + +You would use `bundle update` to explicitly update the version of a +gem. + +## OPTIONS + +* `--all`: + Update all gems specified in Gemfile. + +* `--group=`, `-g=`: + Only update the gems in the specified group. For instance, you can update all gems + in the development group with `bundle update --group development`. You can also + call `bundle update rails --group test` to update the rails gem and all gems in + the test group, for example. + +* `--source=`: + The name of a `:git` or `:path` source used in the Gemfile(5). For + instance, with a `:git` source of `http://github.com/rails/rails.git`, + you would call `bundle update --source rails` + +* `--local`: + Do not attempt to fetch gems remotely and use the gem cache instead. + +* `--ruby`: + Update the locked version of Ruby to the current version of Ruby. + +* `--bundler[=BUNDLER]`: + Update the locked version of bundler. BUNDLER can be a version such as + `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the + latest released version, which never selects a prerelease. + +* `--force`, `--redownload`: + Force reinstalling every gem, even if already installed. + +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--gemfile=GEMFILE`: + Use the specified gemfile instead of [`Gemfile(5)`][Gemfile(5)]. + +* `--jobs=`, `-j=`: + Specify the number of jobs to run in parallel. The default is the number of + available processors. + +* `--retry=[]`: + Retry failed network or git requests for times. + +* `--quiet`: + Only output warnings and errors. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--pre`: + Always choose the highest allowed version, regardless of prerelease status. + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +* `--conservative`: + Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. + +* `--cooldown=`: + Only consider gem versions published at least days ago when + resolving. Pass `0` to disable cooldown for this run, overriding any + per-source or global configuration. Combine with `--conservative` to + minimize transitive churn when bypassing cooldown for an urgent + update. See `cooldown` in bundle-config(1). + +## UPDATING ALL GEMS + +If you run `bundle update --all`, bundler will ignore +any previously installed gems and resolve all dependencies again +based on the latest versions of all gems available in the sources. + +Consider the following Gemfile(5): + + source "https://rubygems.org" + + gem "rails", "3.0.0.rc" + gem "nokogiri" + +When you run [bundle install(1)](bundle-install.1.html) the first time, bundler will resolve +all of the dependencies, all the way down, and install what you need: + + Fetching gem metadata from https://rubygems.org/......... + Resolving dependencies... + Installing builder 2.1.2 + Installing abstract 1.0.0 + Installing rack 1.2.8 + Using bundler 1.7.6 + Installing rake 10.4.0 + Installing polyglot 0.3.5 + Installing mime-types 1.25.1 + Installing i18n 0.4.2 + Installing mini_portile 0.6.1 + Installing tzinfo 0.3.42 + Installing rack-mount 0.6.14 + Installing rack-test 0.5.7 + Installing treetop 1.4.15 + Installing thor 0.14.6 + Installing activesupport 3.0.0.rc + Installing erubis 2.6.6 + Installing activemodel 3.0.0.rc + Installing arel 0.4.0 + Installing mail 2.2.20 + Installing activeresource 3.0.0.rc + Installing actionpack 3.0.0.rc + Installing activerecord 3.0.0.rc + Installing actionmailer 3.0.0.rc + Installing railties 3.0.0.rc + Installing rails 3.0.0.rc + Installing nokogiri 1.6.5 + + Bundle complete! 2 Gemfile dependencies, 26 gems total. + Use `bundle show [gemname]` to see where a bundled gem is installed. + +As you can see, even though you have two gems in the Gemfile(5), your application +needs 26 different gems in order to run. Bundler remembers the exact versions +it installed in `Gemfile.lock`. The next time you run [bundle install(1)](bundle-install.1.html), bundler skips +the dependency resolution and installs the same gems as it installed last time. + +After checking in the `Gemfile.lock` into version control and cloning it on another +machine, running [bundle install(1)](bundle-install.1.html) will _still_ install the gems that you installed +last time. You don't need to worry that a new release of `erubis` or `mail` changes +the gems you use. + +However, from time to time, you might want to update the gems you are using to the +newest versions that still match the gems in your Gemfile(5). + +To do this, run `bundle update --all`, which will ignore the `Gemfile.lock`, and resolve +all the dependencies again. Keep in mind that this process can result in a significantly +different set of the 25 gems, based on the requirements of new gems that the gem +authors released since the last time you ran `bundle update --all`. + +## UPDATING A LIST OF GEMS + +Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the +gems that you specified locked to the versions in the `Gemfile.lock`. + +For instance, in the scenario above, imagine that `nokogiri` releases version `1.4.4`, and +you want to update it _without_ updating Rails and all of its dependencies. To do this, +run `bundle update nokogiri`. + +Bundler will update `nokogiri` and any of its dependencies, but leave alone Rails and +its dependencies. + +## OVERLAPPING DEPENDENCIES + +Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same +second-level dependency. For instance, consider the case of `thin` and +`rack-perftools-profiler`. + + source "https://rubygems.org" + + gem "thin" + gem "rack-perftools-profiler" + +The `thin` gem depends on `rack >= 1.0`, while `rack-perftools-profiler` depends +on `rack ~> 1.0`. If you run bundle install, you get: + + Fetching source index for https://rubygems.org/ + Installing daemons (1.1.0) + Installing eventmachine (0.12.10) with native extensions + Installing open4 (1.0.1) + Installing perftools.rb (0.4.7) with native extensions + Installing rack (1.2.1) + Installing rack-perftools_profiler (0.0.2) + Installing thin (1.2.7) with native extensions + Using bundler (1.0.0.rc.3) + +In this case, the two gems have their own set of dependencies, but they share +`rack` in common. If you run `bundle update thin`, bundler will update `daemons`, +`eventmachine` and `rack`, which are dependencies of `thin`, but not `open4` or +`perftools.rb`, which are dependencies of `rack-perftools_profiler`. Note that +`bundle update thin` will update `rack` even though it's _also_ a dependency of +`rack-perftools_profiler`. + +In short, by default, when you update a gem using `bundle update`, bundler will +update all dependencies of that gem, including those that are also dependencies +of another gem. + +To prevent updating indirect dependencies, prior to version 1.14 the only option +was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): + +In this scenario, updating the `thin` version manually in the Gemfile(5), +and then running [bundle install(1)](bundle-install.1.html) will only update `daemons` and `eventmachine`, +but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section +of [bundle install(1)](bundle-install.1.html). + +Starting with 1.14, specifying the `--conservative` option will also prevent indirect +dependencies from being updated. + +## PATCH LEVEL OPTIONS + +Version 1.14 introduced 4 patch-level options that will influence how gem +versions are resolved. One of the following options can be used: `--patch`, +`--minor` or `--major`. `--strict` can be added to further influence resolution. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +When Bundler is resolving what versions to use to satisfy declared +requirements in the Gemfile or in parent gems, it looks up all +available versions, filters out any versions that don't satisfy +the requirement, and then, by default, sorts them from newest to +oldest, considering them in that order. + +Providing one of the patch level options (e.g. `--patch`) changes the +sort order of the satisfying versions, causing Bundler to consider the +latest `--patch` or `--minor` version available before other versions. +Note that versions outside the stated patch level could still be +resolved to if necessary to find a suitable dependency graph. + +For example, if gem 'foo' is locked at 1.0.2, with no gem requirement +defined in the Gemfile, and versions 1.0.3, 1.0.4, 1.1.0, 1.1.1, 2.0.0 +all exist, the default order of preference by default (`--major`) will +be "2.0.0, 1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +If the `--patch` option is used, the order of preference will change to +"1.0.4, 1.0.3, 1.0.2, 1.1.1, 1.1.0, 2.0.0". + +If the `--minor` option is used, the order of preference will change to +"1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2, 2.0.0". + +Combining the `--strict` option with any of the patch level options +will remove any versions beyond the scope of the patch level option, +to ensure that no gem is updated that far. + +To continue the previous example, if both `--patch` and `--strict` +options are used, the available versions for resolution would be +"1.0.4, 1.0.3, 1.0.2". If `--minor` and `--strict` are used, it would +be "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +Gem requirements as defined in the Gemfile will still be the first +determining factor for what versions are available. If the gem +requirement for `foo` in the Gemfile is '~> 1.0', that will accomplish +the same thing as providing the `--minor` and `--strict` options. + +## PATCH LEVEL EXAMPLES + +Given the following gem specifications: + + foo 1.4.3, requires: ~> bar 2.0 + foo 1.4.4, requires: ~> bar 2.0 + foo 1.4.5, requires: ~> bar 2.1 + foo 1.5.0, requires: ~> bar 2.1 + foo 1.5.1, requires: ~> bar 3.0 + bar with versions 2.0.3, 2.0.4, 2.1.0, 2.1.1, 3.0.0 + +Gemfile: + + gem 'foo' + +Gemfile.lock: + + foo (1.4.3) + bar (~> 2.0) + bar (2.0.3) + +Cases: + + # Command Line Result + ------------------------------------------------------------ + 1 bundle update --patch 'foo 1.4.5', 'bar 2.1.1' + 2 bundle update --patch foo 'foo 1.4.5', 'bar 2.1.1' + 3 bundle update --minor 'foo 1.5.1', 'bar 3.0.0' + 4 bundle update --minor --strict 'foo 1.5.0', 'bar 2.1.1' + 5 bundle update --patch --strict 'foo 1.4.4', 'bar 2.0.4' + +In case 1, bar is upgraded to 2.1.1, a minor version increase, because +the dependency from foo 1.4.5 required it. + +In case 2, only foo is requested to be unlocked, but bar is also +allowed to move because it's not a declared dependency in the Gemfile. + +In case 3, bar goes up a whole major release, because a minor increase +is preferred now for foo, and when it goes to 1.5.1, it requires 3.0.0 +of bar. + +In case 4, foo is preferred up to a minor version, but 1.5.1 won't work +because the --strict flag removes bar 3.0.0 from consideration since +it's a major increment. + +In case 5, both foo and bar have any minor or major increments removed +from consideration because of the --strict flag, so the most they can +move is up to 1.4.4 and 2.0.4. + +## RECOMMENDED WORKFLOW + +In general, when working with an application managed with bundler, you should +use the following workflow: + +* After you create your Gemfile(5) for the first time, run + + $ bundle install + +* Check the resulting `Gemfile.lock` into version control + + $ git add Gemfile.lock + +* When checking out this repository on another development machine, run + + $ bundle install + +* When checking out this repository on a deployment machine, run + + $ bundle install --deployment + +* After changing the Gemfile(5) to reflect a new or update dependency, run + + $ bundle install + +* Make sure to check the updated `Gemfile.lock` into version control + + $ git add Gemfile.lock + +* If [bundle install(1)](bundle-install.1.html) reports a conflict, manually update the specific + gems that you changed in the Gemfile(5) + + $ bundle update rails thin + +* If you want to update all the gems to the latest possible versions that + still match the gems listed in the Gemfile(5), run + + $ bundle update --all diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1 new file mode 100644 index 00000000..24b5dcef --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1 @@ -0,0 +1,22 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE\-VERSION" "1" "April 2026" "" +.SH "NAME" +\fBbundle\-version\fR \- Prints Bundler version information +.SH "SYNOPSIS" +\fBbundle version\fR +.SH "DESCRIPTION" +Prints Bundler version information\. +.SH "OPTIONS" +No options\. +.SH "EXAMPLE" +Print the version of Bundler with build date and commit hash of the in the Git source\. +.IP "" 4 +.nf +bundle version +.fi +.IP "" 0 +.P +shows \fBBundler version 2\.3\.21 (2022\-08\-24 commit d54be5fdd8)\fR for example\. +.P +cf\. \fBbundle \-\-version\fR shows \fBBundler version 2\.3\.21\fR\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1.ronn new file mode 100644 index 00000000..46c6f0b3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle-version.1.ronn @@ -0,0 +1,24 @@ +bundle-version(1) -- Prints Bundler version information +======================================================= + +## SYNOPSIS + +`bundle version` + +## DESCRIPTION + +Prints Bundler version information. + +## OPTIONS + +No options. + +## EXAMPLE + +Print the version of Bundler with build date and commit hash of the in the Git source. + + bundle version + +shows `Bundler version 2.3.21 (2022-08-24 commit d54be5fdd8)` for example. + +cf. `bundle --version` shows `Bundler version 2.3.21`. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1 b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1 new file mode 100644 index 00000000..03bd3de1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1 @@ -0,0 +1,114 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "BUNDLE" "1" "April 2026" "" +.SH "NAME" +\fBbundle\fR \- Ruby Dependency Management +.SH "SYNOPSIS" +\fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS] +.SH "DESCRIPTION" +Bundler manages an \fBapplication's dependencies\fR through its entire life across many machines systematically and repeatably\. +.P +See the RubyGems guides \fIhttps://guides\.rubygems\.org/\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\. +.SH "OPTIONS" +.TP +\fB\-\-no\-color\fR +Print all output without color +.TP +\fB\-\-retry\fR, \fB\-r\fR +Specify the number of times you wish to attempt network commands +.TP +\fB\-\-verbose\fR, \fB\-V\fR +Print out additional logging information +.SH "BUNDLE COMMANDS" +We divide \fBbundle\fR subcommands into primary commands and utilities: +.SH "PRIMARY COMMANDS" +.TP +\fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR +Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR +.TP +\fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR +Update dependencies to their latest versions +.TP +\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR +Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR) +.TP +\fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR +Execute a script in the current bundle +.TP +\fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR +Specify and read configuration options for Bundler +.TP +\fBbundle help(1)\fR \fIbundle\-help\.1\.html\fR +Display detailed help for each subcommand +.SH "UTILITIES" +.TP +\fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR +Add the named gem to the Gemfile and run \fBbundle install\fR +.TP +\fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR +Generate binstubs for executables in a gem +.TP +\fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR +Determine whether the requirements for your application are installed and available to Bundler +.TP +\fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR +Show the source location of a particular gem in the bundle +.TP +\fBbundle info(1)\fR \fIbundle\-info\.1\.html\fR +Show information for the given gem in your bundle +.TP +\fBbundle list(1)\fR \fIbundle\-list\.1\.html\fR +List all the gems in the bundle +.TP +\fBbundle licenses(1)\fR \fIbundle\-licenses\.1\.html\fR +Print the license of all gems in the bundle +.TP +\fBbundle fund(1)\fR \fIbundle\-fund\.1\.html\fR +Lists information about gems seeking funding assistance +.TP +\fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR +Show all of the outdated gems in the current bundle +.TP +\fBbundle console(1)\fR (deprecated) +Start an IRB session in the current bundle +.TP +\fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR +Open an installed gem in the editor +.TP +\fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR +Generate a lockfile for your dependencies +.TP +\fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR +Generate a simple \fBGemfile\fR, placed in the current directory +.TP +\fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR +Create a simple gem, suitable for development with Bundler +.TP +\fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR +Display platform compatibility information +.TP +\fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR +Clean up unused gems in your Bundler directory +.TP +\fBbundle pristine(1)\fR \fIbundle\-pristine\.1\.html\fR +Restores installed gems to their pristine condition +.TP +\fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR +Display warnings about common problems +.TP +\fBbundle env(1)\fR \fIbundle\-env\.1\.html\fR +Print information about the environment Bundler is running under +.TP +\fBbundle issue(1)\fR \fIbundle\-issue\.1\.html\fR +Get help reporting Bundler issues +.TP +\fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR +Removes gems from the Gemfile +.TP +\fBbundle plugin(1)\fR \fIbundle\-plugin\.1\.html\fR +Manage Bundler plugins +.TP +\fBbundle version(1)\fR \fIbundle\-version\.1\.html\fR +Prints Bundler version information +.SH "PLUGINS" +When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-\fR and execute it, passing down any extra arguments to it\. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1.ronn new file mode 100644 index 00000000..bf322f79 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/bundle.1.ronn @@ -0,0 +1,128 @@ +bundle(1) -- Ruby Dependency Management +======================================= + +## SYNOPSIS + +`bundle` COMMAND [--no-color] [--verbose] [ARGS] + +## DESCRIPTION + +Bundler manages an `application's dependencies` through its entire life +across many machines systematically and repeatably. + +See [the RubyGems guides](https://guides.rubygems.org/) for information on getting +started, and Gemfile(5) for more information on the `Gemfile` format. + +## OPTIONS + +* `--no-color`: + Print all output without color + +* `--retry`, `-r`: + Specify the number of times you wish to attempt network commands + +* `--verbose`, `-V`: + Print out additional logging information + +## BUNDLE COMMANDS + +We divide `bundle` subcommands into primary commands and utilities: + +## PRIMARY COMMANDS + +* [`bundle install(1)`](bundle-install.1.html): + Install the gems specified by the `Gemfile` or `Gemfile.lock` + +* [`bundle update(1)`](bundle-update.1.html): + Update dependencies to their latest versions + +* [`bundle cache(1)`](bundle-cache.1.html): + Package the .gem files required by your application into the + `vendor/cache` directory (aliases: `bundle package`, `bundle pack`) + +* [`bundle exec(1)`](bundle-exec.1.html): + Execute a script in the current bundle + +* [`bundle config(1)`](bundle-config.1.html): + Specify and read configuration options for Bundler + +* [`bundle help(1)`](bundle-help.1.html): + Display detailed help for each subcommand + +## UTILITIES + +* [`bundle add(1)`](bundle-add.1.html): + Add the named gem to the Gemfile and run `bundle install` + +* [`bundle binstubs(1)`](bundle-binstubs.1.html): + Generate binstubs for executables in a gem + +* [`bundle check(1)`](bundle-check.1.html): + Determine whether the requirements for your application are installed + and available to Bundler + +* [`bundle show(1)`](bundle-show.1.html): + Show the source location of a particular gem in the bundle + +* [`bundle info(1)`](bundle-info.1.html): + Show information for the given gem in your bundle + +* [`bundle list(1)`](bundle-list.1.html): + List all the gems in the bundle + +* [`bundle licenses(1)`](bundle-licenses.1.html): + Print the license of all gems in the bundle + +* [`bundle fund(1)`](bundle-fund.1.html): + Lists information about gems seeking funding assistance + +* [`bundle outdated(1)`](bundle-outdated.1.html): + Show all of the outdated gems in the current bundle + +* `bundle console(1)` (deprecated): + Start an IRB session in the current bundle + +* [`bundle open(1)`](bundle-open.1.html): + Open an installed gem in the editor + +* [`bundle lock(1)`](bundle-lock.1.html): + Generate a lockfile for your dependencies + +* [`bundle init(1)`](bundle-init.1.html): + Generate a simple `Gemfile`, placed in the current directory + +* [`bundle gem(1)`](bundle-gem.1.html): + Create a simple gem, suitable for development with Bundler + +* [`bundle platform(1)`](bundle-platform.1.html): + Display platform compatibility information + +* [`bundle clean(1)`](bundle-clean.1.html): + Clean up unused gems in your Bundler directory + +* [`bundle pristine(1)`](bundle-pristine.1.html): + Restores installed gems to their pristine condition + +* [`bundle doctor(1)`](bundle-doctor.1.html): + Display warnings about common problems + +* [`bundle env(1)`](bundle-env.1.html): + Print information about the environment Bundler is running under + +* [`bundle issue(1)`](bundle-issue.1.html): + Get help reporting Bundler issues + +* [`bundle remove(1)`](bundle-remove.1.html): + Removes gems from the Gemfile + +* [`bundle plugin(1)`](bundle-plugin.1.html): + Manage Bundler plugins + +* [`bundle version(1)`](bundle-version.1.html): + Prints Bundler version information + +## PLUGINS + +When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, +Bundler will try to find an executable on your path named `bundler-` +and execute it, passing down any extra arguments to it. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5 b/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5 new file mode 100644 index 00000000..0a1c4f5c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5 @@ -0,0 +1,514 @@ +.\" generated with Ronn-NG/v0.10.1 +.\" http://github.com/apjanke/ronn-ng/tree/0.10.1 +.TH "GEMFILE" "5" "April 2026" "" +.SH "NAME" +\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs +.SH "SYNOPSIS" +A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\. +.P +Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\. +.SH "SYNTAX" +A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\. +.SH "GLOBAL SOURCE" +At the top of the \fBGemfile\fR, add a single line for the \fBRubyGems\fR source that contains the gems listed in the \fBGemfile\fR\. +.IP "" 4 +.nf +source "https://rubygems\.org" +.fi +.IP "" 0 +.P +You can add only one global source\. In Bundler 1\.13, adding multiple global sources was deprecated\. The \fBsource\fR \fBMUST\fR be a valid RubyGems repository\. +.P +To use more than one source of RubyGems, you should use \fI\fBsource\fR block\fR\. +.P +A source is checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\. +.P +\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or \fBsource\fR block\. +.SS "CREDENTIALS" +Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\. +.IP "" 4 +.nf +bundle config gems\.example\.com user:password +.fi +.IP "" 0 +.P +For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\. +.IP "" 4 +.nf +source "https://user:password@gems\.example\.com" +.fi +.IP "" 0 +.P +Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\. +.SH "RUBY" +If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. +.SS "VERSION (required)" +The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc\., this should be the Ruby version that the engine is compatible with\. +.IP "" 4 +.nf +ruby "3\.1\.2" +.fi +.IP "" 0 +.P +If you wish to derive your Ruby version from a version file (ie \.ruby\-version), you can use the \fBfile\fR option instead\. +.IP "" 4 +.nf +ruby file: "\.ruby\-version" +.fi +.IP "" 0 +.P +The version file should conform to any of the following formats: +.IP "\(bu" 4 +\fB3\.1\.2\fR (\.ruby\-version) +.IP "\(bu" 4 +\fBruby 3\.1\.2\fR (\.tool\-versions, read: https://asdf\-vm\.com/manage/configuration\.html#tool\-versions) +.IP "" 0 +.SS "ENGINE" +Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\. +.P +What exactly is an Engine? +.IP "\(bu" 4 +A Ruby engine is an implementation of the Ruby language\. +.IP "\(bu" 4 +For background: the reference or original implementation of the Ruby programming language is called Matz's Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\. +.IP "\(bu" 4 +Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttps://www\.jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\. +.IP "" 0 +.SS "ENGINE VERSION" +Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\. +.IP "" 4 +.nf +ruby "2\.6\.8", engine: "jruby", engine_version: "9\.3\.8\.0" +.fi +.IP "" 0 +.SS "PATCHLEVEL" +Each application \fImay\fR specify a Ruby patchlevel\. Specifying the patchlevel has been meaningless since Ruby 2\.1\.0 was released as the patchlevel is now uniquely determined by a combination of major, minor, and teeny version numbers\. +.P +This option was implemented in Bundler 1\.4\.0 for Ruby 2\.0 or earlier\. +.IP "" 4 +.nf +ruby "3\.1\.2", patchlevel: "20" +.fi +.IP "" 0 +.SH "GEMS" +Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\. +.SS "NAME (required)" +For each gem requirement, list a single \fIgem\fR line\. +.IP "" 4 +.nf +gem "nokogiri" +.fi +.IP "" 0 +.SS "VERSION" +Each \fIgem\fR \fBMAY\fR have one or more version specifiers\. +.IP "" 4 +.nf +gem "nokogiri", ">= 1\.4\.2" +gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0" +.fi +.IP "" 0 +.P +Most version specifiers, like \fB>= 1\.0\fR, are self\-explanatory\. The pessimistic specifier \fB~>\fR constrains both a lower and an upper bound: \fB~> 2\.0\.3\fR is identical to \fB>= 2\.0\.3\fR and \fB< 2\.1\fR, and \fB~> 2\.1\fR is identical to \fB>= 2\.1\fR and \fB< 3\.0\fR\. A pessimistic specifier with a prerelease component, like \fB~> 2\.2\.beta\fR, will match prerelease versions like \fB2\.2\.beta\.12\fR\. \fB~> 0\fR is identical to \fB>= 0\.0\fR and \fB< 1\.0\fR\. +.SS "REQUIRE AS" +Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\. +.IP "" 4 +.nf +gem "redis", require: ["redis/connection/hiredis", "redis"] +gem "webmock", require: false +gem "byebug", require: true +.fi +.IP "" 0 +.P +The argument defaults to the name of the gem\. For example, these are identical: +.IP "" 4 +.nf +gem "nokogiri" +gem "nokogiri", require: "nokogiri" +gem "nokogiri", require: true +.fi +.IP "" 0 +.SS "GROUPS" +Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\. +.IP "" 4 +.nf +gem "rspec", group: :test +gem "wirble", groups: [:development, :test] +.fi +.IP "" 0 +.P +The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\. +.IP "" 4 +.nf +# setup adds gems to Ruby's load path +Bundler\.setup # defaults to all groups +require "bundler/setup" # same as Bundler\.setup +Bundler\.setup(:default) # only set up the _default_ group +Bundler\.setup(:test) # only set up the _test_ group (but `not` _default_) +Bundler\.setup(:default, :test) # set up the _default_ and _test_ groups, but no others + +# require requires all of the gems in the specified groups +Bundler\.require # defaults to the _default_ group +Bundler\.require(:default) # identical +Bundler\.require(:default, :test) # requires the _default_ and _test_ groups +Bundler\.require(:test) # requires the _test_ group +.fi +.IP "" 0 +.P +The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\. +.P +To specify multiple groups to ignore, specify a list of groups separated by spaces\. +.IP "" 4 +.nf +bundle config set \-\-local without test +bundle config set \-\-local without development test +.fi +.IP "" 0 +.P +Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\. +.P +Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Dependency management \fIhttps://guides\.rubygems\.org/dependency_management/\fR\. +.SS "PLATFORMS" +If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\. +.P +There are a number of \fBGemfile\fR platforms: +.TP +\fBruby\fR +C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows +.TP +\fBmri\fR +C Ruby (MRI) only, but not Windows +.TP +\fBwindows\fR +Windows C Ruby (MRI), including RubyInstaller 32\-bit and 64\-bit versions +.TP +\fBmswin\fR +Windows C Ruby (MRI), including RubyInstaller 32\-bit versions +.TP +\fBmswin64\fR +Windows C Ruby (MRI), including RubyInstaller 64\-bit versions +.TP +\fBrbx\fR +Rubinius +.TP +\fBjruby\fR +JRuby +.TP +\fBtruffleruby\fR +TruffleRuby +.P +On platforms \fBruby\fR, \fBmri\fR, \fBmswin\fR, \fBmswin64\fR, and \fBwindows\fR, you may additionally specify a version by appending the major and minor version numbers without a delimiter\. For example, to specify that a gem should only be used on platform \fBruby\fR version 3\.1, use: +.IP "" 4 +.nf +ruby_31 +.fi +.IP "" 0 +.P +As with groups (above), you may specify one or more platforms: +.IP "" 4 +.nf +gem "weakling", platforms: :jruby +gem "ruby\-debug", platforms: :mri_31 +gem "nokogiri", platforms: [:windows_31, :jruby] +.fi +.IP "" 0 +.P +All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\. +.P +The following platform values are deprecated and should be replaced with \fBwindows\fR: +.IP "\(bu" 4 +\fBmswin\fR, \fBmswin64\fR, \fBmingw32\fR, \fBx64_mingw\fR +.IP "" 0 +.P +Note that, while unfortunately using the same terminology, the values of this option are different from the values that \fBbundle lock \-\-add\-platform\fR can take\. The values of this option are more closer to "Ruby Implementation" while the values that \fBbundle lock \-\-add\-platform\fR understands are more related to OS and architecture of the different systems where your lockfile will be used\. +.SS "FORCE_RUBY_PLATFORM" +If you always want the pure ruby variant of a gem to be chosen over platform specific variants, you can use the \fBforce_ruby_platform\fR option: +.IP "" 4 +.nf +gem "ffi", force_ruby_platform: true +.fi +.IP "" 0 +.P +This can be handy (assuming the pure ruby variant works fine) when: +.IP "\(bu" 4 +You're having issues with the platform specific variant\. +.IP "\(bu" 4 +The platform specific variant does not yet support a newer ruby (and thus has a \fBrequired_ruby_version\fR upper bound), but you still want your Gemfile{\.lock} files to resolve under that ruby\. +.IP "" 0 +.SS "SOURCE" +You can select an alternate RubyGems repository for a gem using the ':source' option\. +.IP "" 4 +.nf +gem "some_internal_gem", source: "https://gems\.example\.com" +.fi +.IP "" 0 +.P +This forces the gem to be loaded from this source and ignores the global source declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\. +.P +Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on the global source\. +.P +\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCE\fR\. +.P +Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\. +.SS "GIT" +If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols: +.TP +\fBHTTP(S)\fR +gem "rails", git: "https://github\.com/rails/rails\.git" +.TP +\fBSSH\fR +gem "rails", git: "git@github\.com:rails/rails\.git" +.TP +\fBgit\fR +gem "rails", git: "git://github\.com/rails/rails\.git" +.P +If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\. +.P +\fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\. +.P +The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\. +.P +A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\. +.P +If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\. +.P +If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\. +.IP "" 4 +.nf +gem "rails", "2\.3\.8", git: "https://github\.com/rails/rails\.git" +# bundle install will fail, because the \.gemspec in the rails +# repository's master branch specifies version 3\.0\.0 +.fi +.IP "" 0 +.P +If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\. +.P +Git repositories support a number of additional options\. +.TP +\fBbranch\fR, \fBtag\fR, and \fBref\fR +You \fBMUST\fR only specify at most one of these options\. The default is \fBbranch: "master"\fR\. For example: +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", branch: "5\-0\-stable" +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", tag: "v5\.0\.0" +.IP +gem "rails", git: "https://github\.com/rails/rails\.git", ref: "4aded" +.TP +\fBsubmodules\fR +For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fBsubmodules: true\fR to cause bundler to expand any submodules included in the git repository +.P +If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\. +.IP "" 4 +.nf +|~rails [git root] +| |\-rails\.gemspec [rails gem located here] +|~actionpack +| |\-actionpack\.gemspec [actionpack gem located here] +|~activesupport +| |\-activesupport\.gemspec [activesupport gem located here] +|\|\.\|\.\|\. +.fi +.IP "" 0 +.P +To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\. +.SS "GIT SOURCE" +A custom git source can be defined via the \fBgit_source\fR method\. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address: +.IP "" 4 +.nf +git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" } +gem 'rails', stash: 'forks/rails' +.fi +.IP "" 0 +.P +In addition, if you wish to choose a specific branch: +.IP "" 4 +.nf +gem "rails", stash: "forks/rails", branch: "branch_name" +.fi +.IP "" 0 +.SS "GITHUB" +\fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\. +.P +If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. +.IP "" 4 +.nf +gem "rails", github: "rails/rails" +gem "rails", github: "rails" +.fi +.IP "" 0 +.P +Are both equivalent to +.IP "" 4 +.nf +gem "rails", git: "https://github\.com/rails/rails\.git" +.fi +.IP "" 0 +.P +Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.P +You can also directly pass a pull request URL: +.IP "" 4 +.nf +gem "rails", github: "https://github\.com/rails/rails/pull/43753" +.fi +.IP "" 0 +.P +Which is equivalent to: +.IP "" 4 +.nf +gem "rails", github: "rails/rails", branch: "refs/pull/43753/head" +.fi +.IP "" 0 +.SS "GIST" +If the git repository you want to use is hosted as a GitHub Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\. +.IP "" 4 +.nf +gem "the_hatch", gist: "4815162342" +.fi +.IP "" 0 +.P +Is equivalent to: +.IP "" 4 +.nf +gem "the_hatch", git: "https://gist\.github\.com/4815162342\.git" +.fi +.IP "" 0 +.P +Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.SS "BITBUCKET" +If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\. +.IP "" 4 +.nf +gem "rails", bitbucket: "rails/rails" +gem "rails", bitbucket: "rails" +.fi +.IP "" 0 +.P +Are both equivalent to +.IP "" 4 +.nf +gem "rails", git: "https://rails@bitbucket\.org/rails/rails\.git" +.fi +.IP "" 0 +.P +Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\. +.SS "PATH" +You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\. The path must point to a directory containing the gem's unpacked source code, not to a packaged \fB\.gem\fR file\. +.P +Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\. +.P +Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\. +.IP "" 4 +.nf +gem "rails", path: "vendor/rails" +.fi +.IP "" 0 +.P +If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem's files\. This will automatically load gemspec files from subdirectories\. +.IP "" 4 +.nf +path 'components' do + gem 'admin_ui' + gem 'public_ui' +end +.fi +.IP "" 0 +.SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS" +The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\. +.IP "" 4 +.nf +source "https://gems\.example\.com" do + gem "some_internal_gem" + gem "another_internal_gem" +end + +git "https://github\.com/rails/rails\.git" do + gem "activesupport" + gem "actionpack" +end + +platforms :ruby do + gem "ruby\-debug" + gem "sqlite3" +end + +group :development, optional: true do + gem "wirble" + gem "faker" +end +.fi +.IP "" 0 +.P +In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\. +.P +In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\. +.P +The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\. +.SH "INSTALL_IF" +The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\. +.IP "" 4 +.nf +install_if \-> { RUBY_PLATFORM =~ /darwin/ } do + gem "pasteboard" +end +.fi +.IP "" 0 +.SH "GEMSPEC" +The \fB\.gemspec\fR \fIhttps://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\. +.P +If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\. +.P +The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: '\.'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\. +.P +The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: \fB{,*,*/*}\.gemspec\fR), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\. +.P +When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\. +.SH "EVAL_GEMFILE" +A Gemfile \fBMAY\fR be split across multiple files\. The \fBeval_gemfile\fR method reads the contents of another file as if they appeared in the current Gemfile\. A relative path is resolved against the directory of the file containing the call\. +.IP "" 4 +.nf +eval_gemfile "another\.gemfile" +.fi +.IP "" 0 +.P +This can be useful to run tests against multiple combinations of dependencies, or to load per\-developer gems from an untracked gemfile\. +.SH "SOURCE PRIORITY" +When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order: +.IP "1." 4 +The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR) +.IP "2." 4 +For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR +.IP "3." 4 +If neither of the above conditions are met, the global source will be used\. If multiple global sources are specified, they will be prioritized from last to first, but this is deprecated since Bundler 1\.13, so Bundler prints a warning and will abort with an error in the future\. +.IP "" 0 +.SH "LOCKFILE" +By default, Bundler will create a lockfile by adding \fB\.lock\fR to the end of the Gemfile name\. To change this, use the \fBlockfile\fR method: +.IP "" 4 +.nf +lockfile "/path/to/lockfile\.lock" +.fi +.IP "" 0 +.P +This is useful when you want to use different lockfiles per ruby version or platform\. +.P +To avoid writing a lock file, use \fBfalse\fR as the argument: +.IP "" 4 +.nf +lockfile false +.fi +.IP "" 0 +.P +This is useful for library development and other situations where the code is expected to work with a range of dependency versions\. +.SS "LOCKFILE PRECEDENCE" +When determining path to the lockfile or whether to create a lockfile, the following precedence is used: +.IP "1." 4 +The \fBbundle install\fR \fB\-\-no\-lock\fR option (which disables lockfile creation)\. +.IP "2." 4 +The \fBbundle install\fR \fB\-\-lockfile\fR option\. +.IP "3." 4 +The \fBBUNDLE_LOCKFILE\fR environment variable\. +.IP "4." 4 +The \fBlockfile\fR method in the Gemfile\. +.IP "5." 4 +The default behavior of adding \fB\.lock\fR to the end of the Gemfile name\. +.IP "" 0 + diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5.ronn b/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5.ronn new file mode 100644 index 00000000..b9bee640 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/gemfile.5.ronn @@ -0,0 +1,607 @@ +Gemfile(5) -- A format for describing gem dependencies for Ruby programs +======================================================================== + +## SYNOPSIS + +A `Gemfile` describes the gem dependencies required to execute associated +Ruby code. + +Place the `Gemfile` in the root of the directory containing the associated +code. For instance, in a Rails application, place the `Gemfile` in the same +directory as the `Rakefile`. + +## SYNTAX + +A `Gemfile` is evaluated as Ruby code, in a context which makes available +a number of methods used to describe the gem requirements. + +## GLOBAL SOURCE + +At the top of the `Gemfile`, add a single line for the `RubyGems` source that +contains the gems listed in the `Gemfile`. + + source "https://rubygems.org" + +You can add only one global source. In Bundler 1.13, adding multiple global +sources was deprecated. The `source` `MUST` be a valid RubyGems repository. + +To use more than one source of RubyGems, you should use [`source` block +](#BLOCK-FORM-OF-SOURCE-GIT-PATH-GROUP-and-PLATFORMS). + +A source is checked for gems following the heuristics described in +[SOURCE PRIORITY][]. + +**Note about a behavior of the feature deprecated in Bundler 1.13**: +If a gem is found in more than one global source, Bundler +will print a warning after installing the gem indicating which source was used, +and listing the other sources where the gem is available. A specific source can +be selected for gems that need to use a non-standard repository, suppressing +this warning, by using the [`:source` option](#SOURCE) or `source` block. + +### CREDENTIALS + +Some gem sources require a username and password. Use [bundle config(1)](bundle-config.1.html) to set +the username and password for any of the sources that need it. The command must +be run once on each computer that will install the Gemfile, but this keeps the +credentials from being stored in plain text in version control. + + bundle config gems.example.com user:password + +For some sources, like a company Gemfury account, it may be easier to +include the credentials in the Gemfile as part of the source URL. + + source "https://user:password@gems.example.com" + +Credentials in the source URL will take precedence over credentials set using +`config`. + +## RUBY + +If your application requires a specific Ruby version or engine, specify your +requirements using the `ruby` method, with the following arguments. +All parameters are `OPTIONAL` unless otherwise specified. + +### VERSION (required) + +The version of Ruby that your application requires. If your application +requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc., this +should be the Ruby version that the engine is compatible with. + + ruby "3.1.2" + +If you wish to derive your Ruby version from a version file (ie .ruby-version), +you can use the `file` option instead. + + ruby file: ".ruby-version" + +The version file should conform to any of the following formats: + + - `3.1.2` (.ruby-version) + - `ruby 3.1.2` (.tool-versions, read: https://asdf-vm.com/manage/configuration.html#tool-versions) + +### ENGINE + +Each application _may_ specify a Ruby engine. If an engine is specified, an +engine version _must_ also be specified. + +What exactly is an Engine? + - A Ruby engine is an implementation of the Ruby language. + + - For background: the reference or original implementation of the Ruby + programming language is called + [Matz's Ruby Interpreter](https://en.wikipedia.org/wiki/Ruby_MRI), or MRI + for short. This is named after Ruby creator Yukihiro Matsumoto, + also known as Matz. MRI is also known as CRuby, because it is written in C. + MRI is the most widely used Ruby engine. + + - [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist. + Some of the more well-known implementations include + [JRuby](https://www.jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/). + Rubinius is an alternative implementation of Ruby written in Ruby. + JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine. + TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM. + +### ENGINE VERSION + +Each application _may_ specify a Ruby engine version. If an engine version is +specified, an engine _must_ also be specified. If the engine is "ruby" the +engine version specified _must_ match the Ruby version. + + ruby "2.6.8", engine: "jruby", engine_version: "9.3.8.0" + +### PATCHLEVEL + +Each application _may_ specify a Ruby patchlevel. Specifying the patchlevel has +been meaningless since Ruby 2.1.0 was released as the patchlevel is now +uniquely determined by a combination of major, minor, and teeny version numbers. + +This option was implemented in Bundler 1.4.0 for Ruby 2.0 or earlier. + + ruby "3.1.2", patchlevel: "20" + +## GEMS + +Specify gem requirements using the `gem` method, with the following arguments. +All parameters are `OPTIONAL` unless otherwise specified. + +### NAME (required) + +For each gem requirement, list a single _gem_ line. + + gem "nokogiri" + +### VERSION + +Each _gem_ `MAY` have one or more version specifiers. + + gem "nokogiri", ">= 1.4.2" + gem "RedCloth", ">= 4.1.0", "< 4.2.0" + +Most version specifiers, like `>= 1.0`, are self-explanatory. The pessimistic +specifier `~>` constrains both a lower and an upper bound: `~> 2.0.3` is +identical to `>= 2.0.3` and `< 2.1`, and `~> 2.1` is identical to `>= 2.1` and +`< 3.0`. A pessimistic specifier with a prerelease component, like +`~> 2.2.beta`, will match prerelease versions like `2.2.beta.12`. `~> 0` is +identical to `>= 0.0` and `< 1.0`. + +### REQUIRE AS + +Each _gem_ `MAY` specify files that should be used when autorequiring via +`Bundler.require`. You may pass an array with multiple files or `true` if the file +you want `required` has the same name as _gem_ or `false` to +prevent any file from being autorequired. + + gem "redis", require: ["redis/connection/hiredis", "redis"] + gem "webmock", require: false + gem "byebug", require: true + +The argument defaults to the name of the gem. For example, these are identical: + + gem "nokogiri" + gem "nokogiri", require: "nokogiri" + gem "nokogiri", require: true + +### GROUPS + +Each _gem_ `MAY` specify membership in one or more groups. Any _gem_ that does +not specify membership in any group is placed in the `default` group. + + gem "rspec", group: :test + gem "wirble", groups: [:development, :test] + +The Bundler runtime allows its two main methods, `Bundler.setup` and +`Bundler.require`, to limit their impact to particular groups. + + # setup adds gems to Ruby's load path + Bundler.setup # defaults to all groups + require "bundler/setup" # same as Bundler.setup + Bundler.setup(:default) # only set up the _default_ group + Bundler.setup(:test) # only set up the _test_ group (but `not` _default_) + Bundler.setup(:default, :test) # set up the _default_ and _test_ groups, but no others + + # require requires all of the gems in the specified groups + Bundler.require # defaults to the _default_ group + Bundler.require(:default) # identical + Bundler.require(:default, :test) # requires the _default_ and _test_ groups + Bundler.require(:test) # requires the _test_ group + +The Bundler CLI allows you to specify a list of groups whose gems `bundle install` should +not install with the `without` configuration. + +To specify multiple groups to ignore, specify a list of groups separated by spaces. + + bundle config set --local without test + bundle config set --local without development test + +Also, calling `Bundler.setup` with no parameters, or calling `require "bundler/setup"` +will setup all groups except for the ones you excluded via `--without` (since they +are not available). + +Note that on `bundle install`, bundler downloads and evaluates all gems, in order to +create a single canonical list of all of the required gems and their dependencies. +This means that you cannot list different versions of the same gems in different +groups. For more details, see [Dependency management](https://guides.rubygems.org/dependency_management/). + +### PLATFORMS + +If a gem should only be used in a particular platform or set of platforms, you can +specify them. Platforms are essentially identical to groups, except that you do not +need to use the `--without` install-time flag to exclude groups of gems for other +platforms. + +There are a number of `Gemfile` platforms: + + * `ruby`: + C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows + * `mri`: + C Ruby (MRI) only, but not Windows + * `windows`: + Windows C Ruby (MRI), including RubyInstaller 32-bit and 64-bit versions + * `mswin`: + Windows C Ruby (MRI), including RubyInstaller 32-bit versions + * `mswin64`: + Windows C Ruby (MRI), including RubyInstaller 64-bit versions + * `rbx`: + Rubinius + * `jruby`: + JRuby + * `truffleruby`: + TruffleRuby + +On platforms `ruby`, `mri`, `mswin`, `mswin64`, and `windows`, you may +additionally specify a version by appending the major and minor version numbers +without a delimiter. For example, to specify that a gem should only be used on +platform `ruby` version 3.1, use: + + ruby_31 + +As with groups (above), you may specify one or more platforms: + + gem "weakling", platforms: :jruby + gem "ruby-debug", platforms: :mri_31 + gem "nokogiri", platforms: [:windows_31, :jruby] + +All operations involving groups ([`bundle install`](bundle-install.1.html), `Bundler.setup`, +`Bundler.require`) behave exactly the same as if any groups not +matching the current platform were explicitly excluded. + +The following platform values are deprecated and should be replaced with `windows`: + + * `mswin`, `mswin64`, `mingw32`, `x64_mingw` + +Note that, while unfortunately using the same terminology, the values of this +option are different from the values that `bundle lock --add-platform` can take. +The values of this option are more closer to "Ruby Implementation" while the +values that `bundle lock --add-platform` understands are more related to OS and +architecture of the different systems where your lockfile will be used. + +### FORCE_RUBY_PLATFORM + +If you always want the pure ruby variant of a gem to be chosen over platform +specific variants, you can use the `force_ruby_platform` option: + + gem "ffi", force_ruby_platform: true + +This can be handy (assuming the pure ruby variant works fine) when: + +* You're having issues with the platform specific variant. +* The platform specific variant does not yet support a newer ruby (and thus has + a `required_ruby_version` upper bound), but you still want your Gemfile{.lock} + files to resolve under that ruby. + +### SOURCE + +You can select an alternate RubyGems repository for a gem using the ':source' +option. + + gem "some_internal_gem", source: "https://gems.example.com" + +This forces the gem to be loaded from this source and ignores the global source +declared at the top level of the file. If the gem does not exist in this source, +it will not be installed. + +Bundler will search for child dependencies of this gem by first looking in the +source selected for the parent, but if they are not found there, it will fall +back on the global source. + +**Note about a behavior of the feature deprecated in Bundler 1.13**: +Selecting a specific source repository this way also suppresses the ambiguous +gem warning described above in [GLOBAL SOURCE](#GLOBAL-SOURCE). + +Using the `:source` option for an individual gem will also make that source +available as a possible global source for any other gems which do not specify +explicit sources. Thus, when adding gems with explicit sources, it is +recommended that you also ensure all other gems in the Gemfile are using +explicit sources. + +### GIT + +If necessary, you can specify that a gem is located at a particular +git repository using the `:git` parameter. The repository can be accessed via +several protocols: + + * `HTTP(S)`: + gem "rails", git: "https://github.com/rails/rails.git" + * `SSH`: + gem "rails", git: "git@github.com:rails/rails.git" + * `git`: + gem "rails", git: "git://github.com/rails/rails.git" + +If using SSH, the user that you use to run `bundle install` `MUST` have the +appropriate keys available in their `$HOME/.ssh`. + +`NOTE`: `http://` and `git://` URLs should be avoided if at all possible. These +protocols are unauthenticated, so a man-in-the-middle attacker can deliver +malicious code and compromise your system. HTTPS and SSH are strongly +preferred. + +The `group`, `platforms`, and `require` options are available and behave +exactly the same as they would for a normal gem. + +A git repository `SHOULD` have at least one file, at the root of the +directory containing the gem, with the extension `.gemspec`. This file +`MUST` contain a valid gem specification, as expected by the `gem build` +command. + +If a git repository does not have a `.gemspec`, bundler will attempt to +create one, but it will not contain any dependencies, executables, or +C extension compilation instructions. As a result, it may fail to properly +integrate into your application. + +If a git repository does have a `.gemspec` for the gem you attached it +to, a version specifier, if provided, means that the git repository is +only valid if the `.gemspec` specifies a version matching the version +specifier. If not, bundler will print a warning. + + gem "rails", "2.3.8", git: "https://github.com/rails/rails.git" + # bundle install will fail, because the .gemspec in the rails + # repository's master branch specifies version 3.0.0 + +If a git repository does `not` have a `.gemspec` for the gem you attached +it to, a version specifier `MUST` be provided. Bundler will use this +version in the simple `.gemspec` it creates. + +Git repositories support a number of additional options. + + * `branch`, `tag`, and `ref`: + You `MUST` only specify at most one of these options. The default + is `branch: "master"`. For example: + + gem "rails", git: "https://github.com/rails/rails.git", branch: "5-0-stable" + + gem "rails", git: "https://github.com/rails/rails.git", tag: "v5.0.0" + + gem "rails", git: "https://github.com/rails/rails.git", ref: "4aded" + + * `submodules`: + For reference, a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) + lets you have another git repository within a subfolder of your repository. + Specify `submodules: true` to cause bundler to expand any + submodules included in the git repository + +If a git repository contains multiple `.gemspecs`, each `.gemspec` +represents a gem located at the same place in the file system as +the `.gemspec`. + + |~rails [git root] + | |-rails.gemspec [rails gem located here] + |~actionpack + | |-actionpack.gemspec [actionpack gem located here] + |~activesupport + | |-activesupport.gemspec [activesupport gem located here] + |... + +To install a gem located in a git repository, bundler changes to +the directory containing the gemspec, runs `gem build name.gemspec` +and then installs the resulting gem. The `gem build` command, +which comes standard with Rubygems, evaluates the `.gemspec` in +the context of the directory in which it is located. + +### GIT SOURCE + +A custom git source can be defined via the `git_source` method. Provide the source's name +as an argument, and a block which receives a single argument and interpolates it into a +string to return the full repo address: + + git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" } + gem 'rails', stash: 'forks/rails' + +In addition, if you wish to choose a specific branch: + + gem "rails", stash: "forks/rails", branch: "branch_name" + +### GITHUB + +`NOTE`: This shorthand should be avoided until Bundler 2.0, since it +currently expands to an insecure `git://` URL. This allows a +man-in-the-middle attacker to compromise your system. + +If the git repository you want to use is hosted on GitHub and is public, you can use the +:github shorthand to specify the github username and repository name (without the +trailing ".git"), separated by a slash. If both the username and repository name are the +same, you can omit one. + + gem "rails", github: "rails/rails" + gem "rails", github: "rails" + +Are both equivalent to + + gem "rails", git: "https://github.com/rails/rails.git" + +Since the `github` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +You can also directly pass a pull request URL: + + gem "rails", github: "https://github.com/rails/rails/pull/43753" + +Which is equivalent to: + + gem "rails", github: "rails/rails", branch: "refs/pull/43753/head" + +### GIST + +If the git repository you want to use is hosted as a GitHub Gist and is public, you can use +the :gist shorthand to specify the gist identifier (without the trailing ".git"). + + gem "the_hatch", gist: "4815162342" + +Is equivalent to: + + gem "the_hatch", git: "https://gist.github.com/4815162342.git" + +Since the `gist` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +### BITBUCKET + +If the git repository you want to use is hosted on Bitbucket and is public, you can use the +:bitbucket shorthand to specify the bitbucket username and repository name (without the +trailing ".git"), separated by a slash. If both the username and repository name are the +same, you can omit one. + + gem "rails", bitbucket: "rails/rails" + gem "rails", bitbucket: "rails" + +Are both equivalent to + + gem "rails", git: "https://rails@bitbucket.org/rails/rails.git" + +Since the `bitbucket` method is a specialization of `git_source`, it accepts a `:branch` named argument. + +### PATH + +You can specify that a gem is located in a particular location +on the file system. Relative paths are resolved relative to the +directory containing the `Gemfile`. The path must point to a +directory containing the gem's unpacked source code, not to a +packaged `.gem` file. + +Similar to the semantics of the `:git` option, the `:path` +option requires that the directory in question either contains +a `.gemspec` for the gem, or that you specify an explicit +version that bundler should use. + +Unlike `:git`, bundler does not compile C extensions for +gems specified as paths. + + gem "rails", path: "vendor/rails" + +If you would like to use multiple local gems directly from the filesystem, you can set a global `path` option to the path containing the gem's files. This will automatically load gemspec files from subdirectories. + + path 'components' do + gem 'admin_ui' + gem 'public_ui' + end + +## BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS + +The `:source`, `:git`, `:path`, `:group`, and `:platforms` options may be +applied to a group of gems by using block form. + + source "https://gems.example.com" do + gem "some_internal_gem" + gem "another_internal_gem" + end + + git "https://github.com/rails/rails.git" do + gem "activesupport" + gem "actionpack" + end + + platforms :ruby do + gem "ruby-debug" + gem "sqlite3" + end + + group :development, optional: true do + gem "wirble" + gem "faker" + end + +In the case of the group block form the :optional option can be given +to prevent a group from being installed unless listed in the `--with` +option given to the `bundle install` command. + +In the case of the `git` block form, the `:ref`, `:branch`, `:tag`, +and `:submodules` options may be passed to the `git` method, and +all gems in the block will inherit those options. + +The presence of a `source` block in a Gemfile also makes that source +available as a possible global source for any other gems which do not specify +explicit sources. Thus, when defining source blocks, it is +recommended that you also ensure all other gems in the Gemfile are using +explicit sources, either via source blocks or `:source` directives on +individual gems. + +## INSTALL_IF + +The `install_if` method allows gems to be installed based on a proc or lambda. +This is especially useful for optional gems that can only be used if certain +software is installed or some other conditions are met. + + install_if -> { RUBY_PLATFORM =~ /darwin/ } do + gem "pasteboard" + end + +## GEMSPEC + +The [`.gemspec`](https://guides.rubygems.org/specification-reference/) file is where + you provide metadata about your gem to Rubygems. Some required Gemspec + attributes include the name, description, and homepage of your gem. This is + also where you specify the dependencies your gem needs to run. + +If you wish to use Bundler to help install dependencies for a gem while it is +being developed, use the `gemspec` method to pull in the dependencies listed in +the `.gemspec` file. + +The `gemspec` method adds any runtime dependencies as gem requirements in the +default group. It also adds development dependencies as gem requirements in the +`development` group. Finally, it adds a gem requirement on your project (`path: +'.'`). In conjunction with `Bundler.setup`, this allows you to require project +files in your test code as you would if the project were installed as a gem; you +need not manipulate the load path manually or require project files via relative +paths. + +The `gemspec` method supports optional `:path`, `:glob`, `:name`, and `:development_group` +options, which control where bundler looks for the `.gemspec`, the glob it uses to look +for the gemspec (defaults to: `{,*,*/*}.gemspec`), what named `.gemspec` it uses +(if more than one is present), and which group development dependencies are included in. + +When a `gemspec` dependency encounters version conflicts during resolution, the +local version under development will always be selected -- even if there are +remote versions that better match other requirements for the `gemspec` gem. + +## EVAL_GEMFILE + +A Gemfile `MAY` be split across multiple files. The `eval_gemfile` method reads +the contents of another file as if they appeared in the current Gemfile. A +relative path is resolved against the directory of the file containing the +call. + + eval_gemfile "another.gemfile" + +This can be useful to run tests against multiple combinations of dependencies, +or to load per-developer gems from an untracked gemfile. + +## SOURCE PRIORITY + +When attempting to locate a gem to satisfy a gem requirement, +bundler uses the following priority order: + + 1. The source explicitly attached to the gem (using `:source`, `:path`, or + `:git`) + 2. For implicit gems (dependencies of explicit gems), any source, git, or path + repository declared on the parent. This results in bundler prioritizing the + ActiveSupport gem from the Rails git repository over ones from + `rubygems.org` + 3. If neither of the above conditions are met, the global source will be used. + If multiple global sources are specified, they will be prioritized from + last to first, but this is deprecated since Bundler 1.13, so Bundler prints + a warning and will abort with an error in the future. + +## LOCKFILE + +By default, Bundler will create a lockfile by adding `.lock` to the end of the +Gemfile name. To change this, use the `lockfile` method: + + lockfile "/path/to/lockfile.lock" + +This is useful when you want to use different lockfiles per ruby version or +platform. + +To avoid writing a lock file, use `false` as the argument: + + lockfile false + +This is useful for library development and other situations where the code is +expected to work with a range of dependency versions. + +### LOCKFILE PRECEDENCE + +When determining path to the lockfile or whether to create a lockfile, the +following precedence is used: + +1. The `bundle install` `--no-lock` option (which disables lockfile creation). +1. The `bundle install` `--lockfile` option. +1. The `BUNDLE_LOCKFILE` environment variable. +1. The `lockfile` method in the Gemfile. +1. The default behavior of adding `.lock` to the end of the Gemfile name. diff --git a/bin/gems/bundler-4.0.21/lib/bundler/man/index.txt b/bin/gems/bundler-4.0.21/lib/bundler/man/index.txt new file mode 100644 index 00000000..f610ba85 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/man/index.txt @@ -0,0 +1,31 @@ +Gemfile(5) gemfile.5 +bundle(1) bundle.1 +bundle-add(1) bundle-add.1 +bundle-binstubs(1) bundle-binstubs.1 +bundle-cache(1) bundle-cache.1 +bundle-check(1) bundle-check.1 +bundle-clean(1) bundle-clean.1 +bundle-config(1) bundle-config.1 +bundle-console(1) bundle-console.1 +bundle-doctor(1) bundle-doctor.1 +bundle-env(1) bundle-env.1 +bundle-exec(1) bundle-exec.1 +bundle-fund(1) bundle-fund.1 +bundle-gem(1) bundle-gem.1 +bundle-help(1) bundle-help.1 +bundle-info(1) bundle-info.1 +bundle-init(1) bundle-init.1 +bundle-install(1) bundle-install.1 +bundle-issue(1) bundle-issue.1 +bundle-licenses(1) bundle-licenses.1 +bundle-list(1) bundle-list.1 +bundle-lock(1) bundle-lock.1 +bundle-open(1) bundle-open.1 +bundle-outdated(1) bundle-outdated.1 +bundle-platform(1) bundle-platform.1 +bundle-plugin(1) bundle-plugin.1 +bundle-pristine(1) bundle-pristine.1 +bundle-remove(1) bundle-remove.1 +bundle-show(1) bundle-show.1 +bundle-update(1) bundle-update.1 +bundle-version(1) bundle-version.1 diff --git a/bin/gems/bundler-4.0.21/lib/bundler/match_metadata.rb b/bin/gems/bundler-4.0.21/lib/bundler/match_metadata.rb new file mode 100644 index 00000000..6fd2994a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/match_metadata.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Bundler + module MatchMetadata + def matches_current_metadata? + matches_current_ruby? && matches_current_rubygems? + end + + def matches_current_ruby? + @required_ruby_version.satisfied_by?(Gem.ruby_version) + end + + def matches_current_rubygems? + @required_rubygems_version.satisfied_by?(Gem.rubygems_version) + end + + def expanded_dependencies + runtime_dependencies + [ + metadata_dependency("Ruby", @required_ruby_version), + metadata_dependency("RubyGems", @required_rubygems_version), + ].compact + end + + def metadata_dependency(name, requirement) + return if requirement.nil? || requirement.none? + + Gem::Dependency.new("#{name}\0", requirement) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/match_platform.rb b/bin/gems/bundler-4.0.21/lib/bundler/match_platform.rb new file mode 100644 index 00000000..479818e5 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/match_platform.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Bundler + module MatchPlatform + def installable_on_platform?(target_platform) # :nodoc: + return true if [Gem::Platform::RUBY, nil, target_platform].include?(platform) + return true if Gem::Platform.new(platform) === target_platform + + false + end + + def self.select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false) + matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked) + + Gem::Platform.sort_and_filter_best_platform_match(matching, platform) + end + + def self.select_best_local_platform_match(specs, force_ruby: false) + local = Bundler.local_platform + matching = select_all_platform_match(specs, local, force_ruby: force_ruby).filter_map(&:materialized_for_installation) + + Gem::Platform.sort_best_platform_match(matching, local) + end + + def self.select_all_platform_match(specs, platform, force_ruby: false, prefer_locked: false) + matching = specs.select {|spec| spec.installable_on_platform?(force_ruby ? Gem::Platform::RUBY : platform) } + + specs.each(&:force_ruby_platform!) if force_ruby + + if prefer_locked + locked_originally = matching.select {|spec| spec.is_a?(::Bundler::LazySpecification) } + return locked_originally if locked_originally.any? + end + + matching + end + + def self.generic_local_platform_is_ruby? + Bundler.generic_local_platform == Gem::Platform::RUBY + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/match_remote_metadata.rb b/bin/gems/bundler-4.0.21/lib/bundler/match_remote_metadata.rb new file mode 100644 index 00000000..5e46d524 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/match_remote_metadata.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Bundler + module FetchMetadata + # A fallback is included because the original version of the specification + # API didn't include that field, so some marshalled specs in the index have it + # set to +nil+. + def matches_current_ruby? + @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default + + super + end + + def matches_current_rubygems? + # A fallback is included because the original version of the specification + # API didn't include that field, so some marshalled specs in the index have it + # set to +nil+. + @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default + + super + end + end + + module MatchRemoteMetadata + include MatchMetadata + + prepend FetchMetadata + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/materialization.rb b/bin/gems/bundler-4.0.21/lib/bundler/materialization.rb new file mode 100644 index 00000000..82e48464 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/materialization.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Bundler + # + # This class materializes a set of resolved specifications (`LazySpecification`) + # for a given gem into the most appropriate real specifications + # (`StubSepecification`, `EndpointSpecification`, etc), given a dependency and a + # target platform. + # + class Materialization + def initialize(dep, platform, candidates:) + @dep = dep + @platform = platform + @candidates = candidates + end + + def complete? + specs.any? + end + + def specs + @specs ||= if @candidates.nil? + [] + elsif platform + MatchPlatform.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform) + else + MatchPlatform.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform) + end + end + + def dependencies + (materialized_spec || specs.first).runtime_dependencies.map {|d| [d, platform] } + end + + def materialized_spec + specs.reject(&:missing?).first&.materialization + end + + def completely_missing_specs + return [] unless specs.all?(&:missing?) + + specs + end + + def partially_missing_specs + specs.select(&:missing?) + end + + def incomplete_specs + return [] if complete? + + @candidates || LazySpecification.new(dep.name, nil, nil) + end + + private + + attr_reader :dep, :platform + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/mirror.rb b/bin/gems/bundler-4.0.21/lib/bundler/mirror.rb new file mode 100644 index 00000000..234c6bd3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/mirror.rb @@ -0,0 +1,221 @@ +# frozen_string_literal: true + +require "socket" + +module Bundler + class Settings + # Class used to build the mirror set and then find a mirror for a given URI + # + # @param prober [Prober object, nil] by default a TCPSocketProbe, this object + # will be used to probe the mirror address to validate that the mirror replies. + class Mirrors + def initialize(prober = nil) + @all = Mirror.new + @prober = prober || TCPSocketProbe.new + @mirrors = {} + end + + # Returns a mirror for the given uri. + # + # Depending on the uri having a valid mirror or not, it may be a + # mirror that points to the provided uri + def for(uri) + if @all.validate!(@prober).valid? + @all + else + fetch_valid_mirror_for(Settings.normalize_uri(uri)) + end + end + + def each + @mirrors.each do |k, v| + yield k, v.uri.to_s + end + end + + def parse(key, value) + config = MirrorConfig.new(key, value) + mirror = if config.all? + @all + else + @mirrors[config.uri] ||= Mirror.new + end + config.update_mirror(mirror) + end + + private + + def fetch_valid_mirror_for(uri) + downcased = uri.to_s.downcase + mirror = @mirrors[downcased] || @mirrors[Gem::URI(downcased).host] || Mirror.new(uri) + mirror.validate!(@prober) + mirror = Mirror.new(uri) unless mirror.valid? + mirror + end + end + + # A mirror + # + # Contains both the uri that should be used as a mirror and the + # fallback timeout which will be used for probing if the mirror + # replies on time or not. + class Mirror + DEFAULT_FALLBACK_TIMEOUT = 0.1 + + attr_reader :uri, :fallback_timeout + + def initialize(uri = nil, fallback_timeout = 0) + self.uri = uri + self.fallback_timeout = fallback_timeout + @valid = nil + end + + def uri=(uri) + @uri = if uri.nil? + nil + else + Gem::URI(uri.to_s) + end + @valid = nil + end + + def fallback_timeout=(timeout) + case timeout + when true, "true" + @fallback_timeout = DEFAULT_FALLBACK_TIMEOUT + when false, "false" + @fallback_timeout = 0 + else + @fallback_timeout = timeout.to_i + end + @valid = nil + end + + def ==(other) + !other.nil? && uri == other.uri && fallback_timeout == other.fallback_timeout + end + + def valid? + return false if @uri.nil? + return @valid unless @valid.nil? + false + end + + def validate!(probe = nil) + @valid = false if uri.nil? + if @valid.nil? + @valid = fallback_timeout == 0 || (probe || TCPSocketProbe.new).replies?(self) + end + self + end + end + + # Class used to parse one configuration line + # + # Gets the configuration line and the value. + # This object provides a `update_mirror` method + # used to setup the given mirror value. + class MirrorConfig + attr_accessor :uri, :value + + def initialize(config_line, value) + uri, fallback = + config_line.match(%r{\Amirror\.(all|.+?)(\.fallback_timeout)?\/?\z}).captures + @fallback = !fallback.nil? + @all = false + if uri == "all" + @all = true + else + @uri = Gem::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri + end + @value = value + end + + def all? + @all + end + + def update_mirror(mirror) + if @fallback + mirror.fallback_timeout = @value + else + mirror.uri = Settings.normalize_uri(@value) + end + end + end + + # Class used for probing TCP availability for a given mirror. + class TCPSocketProbe + def replies?(mirror) + MirrorSockets.new(mirror).any? do |socket, address, timeout| + socket.connect_nonblock(address) + rescue Errno::EINPROGRESS + wait_for_writtable_socket(socket, address, timeout) + rescue RuntimeError # Connection failed somehow, again + false + end + end + + private + + def wait_for_writtable_socket(socket, address, timeout) + if IO.select(nil, [socket], nil, timeout) + probe_writtable_socket(socket) + else # TCP Handshake timed out, or there is something dropping packets + false + end + end + + def probe_writtable_socket(socket) + # Check the pending error on the socket rather than calling + # +connect_nonblock+ a second time. On BSD-based systems such as macOS a + # second connect returns +EISCONN+ even when the asynchronous connect + # failed, which would make a down mirror look reachable. + socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).int == 0 + end + end + end + + # Class used to build the list of sockets that correspond to + # a given mirror. + # + # One mirror may correspond to many different addresses, both + # because of it having many dns entries or because + # the network interface is both ipv4 and ipv5 + class MirrorSockets + def initialize(mirror) + @timeout = mirror.fallback_timeout + @addresses = Socket.getaddrinfo(mirror.uri.host, mirror.uri.port).map do |address| + SocketAddress.new(address[0], address[3], address[1]) + end + end + + def any? + @addresses.any? do |address| + socket = Socket.new(Socket.const_get(address.type), Socket::SOCK_STREAM, 0) + socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) + value = yield socket, address.to_socket_address, @timeout + socket.close unless socket.closed? + value + end + end + end + + # Socket address builder. + # + # Given a socket type, a host and a port, + # provides a method to build sockaddr string + class SocketAddress + attr_reader :type, :host, :port + + def initialize(type, host, port) + @type = type + @host = host + @port = port + end + + def to_socket_address + Socket.pack_sockaddr_in(@port, @host) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin.rb new file mode 100644 index 00000000..637b6125 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin.rb @@ -0,0 +1,387 @@ +# frozen_string_literal: true + +require_relative "plugin/api" + +module Bundler + module Plugin + autoload :DSL, File.expand_path("plugin/dsl", __dir__) + autoload :Events, File.expand_path("plugin/events", __dir__) + autoload :Index, File.expand_path("plugin/index", __dir__) + autoload :Installer, File.expand_path("plugin/installer", __dir__) + autoload :SourceList, File.expand_path("plugin/source_list", __dir__) + autoload :UnloadedSource, File.expand_path("plugin/unloaded_source", __dir__) + + class MalformattedPlugin < PluginError; end + class UndefinedCommandError < PluginError; end + class UnknownSourceError < PluginError; end + class PluginInstallError < PluginError; end + + PLUGIN_FILE_NAME = "plugins.rb" + + module_function + + def reset! + instance_variables.each {|i| remove_instance_variable(i) } + + @sources = {} + @commands = {} + @hooks_by_event = Hash.new {|h, k| h[k] = [] } + @loaded_plugin_names = [] + end + + reset! + + # Installs a new plugin by the given name + # + # @param [Array] names the name of plugin to be installed + # @param [Hash] options various parameters as described in description. + # Refer to cli/plugin for available options + def install(names, options) + raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"] + + specs = Installer.new.install(names, options) + + save_plugins names, specs + rescue PluginError + specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) } + specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) } + + raise + end + + # Uninstalls plugins by the given names + # + # @param [Array] names the names of plugins to be uninstalled + def uninstall(names, options) + if names.empty? && !options[:all] + Bundler.ui.error "No plugins to uninstall. Specify at least 1 plugin to uninstall.\n"\ + "Use --all option to uninstall all the installed plugins." + return + end + + names = index.installed_plugins if options[:all] + if names.any? + names.each do |name| + if index.installed?(name) + path = index.plugin_path(name).to_s + Bundler.rm_rf(path) if index.installed_in_plugin_root?(name) + index.unregister_plugin(name) + Bundler.ui.info "Uninstalled plugin #{name}" + else + Bundler.ui.error "Plugin #{name} is not installed \n" + end + end + else + Bundler.ui.info "No plugins installed" + end + end + + # List installed plugins and commands + # + def list + installed_plugins = index.installed_plugins + if installed_plugins.any? + output = String.new + installed_plugins.each do |plugin| + output << "#{plugin}\n" + output << "-----\n" + index.plugin_commands(plugin).each do |command| + output << " #{command}\n" + end + output << "\n" + end + else + output = "No plugins installed" + end + Bundler.ui.info output + end + + # Evaluates the Gemfile with a limited DSL and installs the plugins + # specified by plugin method + # + # @param [Pathname] gemfile path + # @param [Proc] block that can be evaluated for (inline) Gemfile + def gemfile_install(gemfile = nil, &inline) + Bundler.settings.temporary(frozen: false, deployment: false) do + builder = DSL.new + if block_given? + builder.instance_eval(&inline) + else + builder.eval_gemfile(gemfile) + end + builder.check_primary_source_safety + definition = builder.to_definition(nil, true) + + return if definition.dependencies.empty? + + plugins = definition.dependencies.map(&:name) + installed_specs = Installer.new.install_definition(definition) + + save_plugins plugins, installed_specs, builder.inferred_plugins + end + rescue RuntimeError => e + unless e.is_a?(GemfileError) + Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" + end + raise + end + + # The index object used to store the details about the plugin + def index + @index ||= Index.new + end + + # The directory root for all plugin related data + # + # If run in an app, points to local root, in app_config_path + # Otherwise, points to global root, in Bundler.user_bundle_path("plugin") + def root + @root ||= if SharedHelpers.in_bundle? + local_root + else + global_root + end + end + + def local_root + Bundler.app_config_path.join("plugin") + end + + # The global directory root for all plugin related data + def global_root + Bundler.user_bundle_path("plugin") + end + + # The cache directory for plugin stuffs + def cache + @cache ||= root.join("cache") + end + + # To be called via the API to register to handle a command + def add_command(command, cls) + @commands[command] = cls + end + + # Checks if any plugin handles the command + def command?(command) + !index.command_plugin(command).nil? + end + + # To be called from Cli class to pass the command and argument to + # appropriate plugin class + def exec_command(command, args) + raise UndefinedCommandError, "Command `#{command}` not found" unless command? command + + load_plugin index.command_plugin(command) unless @commands.key? command + + @commands[command].new.exec(command, args) + end + + # To be called via the API to register to handle a source plugin + def add_source(source, cls) + @sources[source] = cls + end + + # Checks if any plugin declares the source + def source?(name) + !index.source_plugin(name.to_s).nil? + end + + # @return [Class] that handles the source. The class includes API::Source + def source(name) + raise UnknownSourceError, "Source #{name} not found" unless source? name + + load_plugin(index.source_plugin(name)) unless @sources.key? name + + @sources[name] + end + + # @param [Hash] The options that are present in the lockfile + # @return [API::Source] the instance of the class that handles the source + # type passed in locked_opts + def from_lock(locked_opts) + opts = locked_opts.merge("uri" => locked_opts["remote"]) + # use an inert placeholder when the plugin handling this source is not + # installed, so that the lockfile can still be parsed + return UnloadedSource.new(opts) unless source?(locked_opts["type"]) + + src = source(locked_opts["type"]) + + src.new(opts) + end + + # To be called via the API to register a hooks and corresponding block that + # will be called to handle the hook + def add_hook(event, &block) + unless Events.defined_event?(event) + raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" + end + @hooks_by_event[event.to_s] << block + end + + # Runs all the hooks that are registered for the passed event + # + # It passes the passed arguments and block to the block registered with + # the api. + # + # @param [String] event + def hook(event, *args, &arg_blk) + return unless Bundler.settings[:plugins] + unless Events.defined_event?(event) + raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events" + end + + plugins = index.hook_plugins(event) + return unless plugins.any? + + plugins.each {|name| load_plugin(name) } + + @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) } + end + + # currently only intended for specs + # + # @return [String, nil] installed path + def installed?(plugin) + Index.new.installed?(plugin) + end + + # @return [true, false] whether the plugin is loaded + def loaded?(plugin) + @loaded_plugin_names.include?(plugin) + end + + # Post installation processing and registering with index + # + # @param [Array] plugins list to be installed + # @param [Hash] specs of plugins mapped to installation path (currently they + # contain all the installed specs, including plugins) + # @param [Array] names of inferred source plugins that can be ignored + def save_plugins(plugins, specs, optional_plugins = []) + plugins.each do |name| + spec = specs[name] + + # It's possible that the `plugin` found in the Gemfile don't appear in the specs. For instance when + # calling `BUNDLE_WITHOUT=default bundle install`, the plugins will not get installed. + next if spec.nil? + next if index.up_to_date?(spec) + + save_plugin(name, spec, optional_plugins.include?(name)) + end + end + + # Checks if the gem is good to be a plugin + # + # At present it only checks whether it contains plugins.rb file + # + # @param [Pathname] plugin_path the path plugin is installed at + # @raise [MalformattedPlugin] if plugins.rb file is not found + def validate_plugin!(plugin_path) + plugin_file = plugin_path.join(PLUGIN_FILE_NAME) + raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file? + end + + # Validates and registers a plugin. + # + # @param [String] name the name of the plugin + # @param [Specification] spec of installed plugin + # @param [Boolean] optional_plugin, removed if there is conflict with any + # other plugin (used for default source plugins) + # + # @raise [PluginInstallError] if validation or registration raises any error + def save_plugin(name, spec, optional_plugin = false) + validate_plugin! Pathname.new(spec.full_gem_path) + installed = register_plugin(name, spec, optional_plugin) + Bundler.ui.info "Installed plugin #{name}" if installed + rescue PluginError => e + raise PluginInstallError, "Failed to install plugin `#{spec.name}`, due to #{e.class} (#{e.message})" + end + + # Runs the plugins.rb file in an isolated namespace, records the plugin + # actions it registers for and then passes the data to index to be stored. + # + # @param [String] name the name of the plugin + # @param [Specification] spec of installed plugin + # @param [Boolean] optional_plugin, removed if there is conflict with any + # other plugin (used for default source plugins) + # + # @raise [MalformattedPlugin] if plugins.rb raises any error + def register_plugin(name, spec, optional_plugin = false) + commands = @commands + sources = @sources + hooks = @hooks_by_event + + @commands = {} + @sources = {} + @hooks_by_event = Hash.new {|h, k| h[k] = [] } + + load_paths = spec.load_paths + Gem.add_to_load_path(*load_paths) + path = Pathname.new spec.full_gem_path + + begin + load path.join(PLUGIN_FILE_NAME), true + rescue StandardError => e + raise MalformattedPlugin, "#{e.class}: #{e.message}" + end + + if optional_plugin && @sources.keys.any? {|s| source? s } + Bundler.rm_rf(path) + false + else + index.register_plugin(name, path.to_s, load_paths, @commands.keys, + @sources.keys, @hooks_by_event.keys) + true + end + ensure + @commands = commands + @sources = sources + @hooks_by_event = hooks + end + + # Executes the plugins.rb file + # + # @param [String] name of the plugin + def load_plugin(name) + return unless name && !name.empty? + return if loaded?(name) + + # Need to ensure before this that plugin root where the rest of gems + # are installed to be on load path to support plugin deps. Currently not + # done to avoid conflicts + path = index.plugin_path(name) + + paths = index.load_paths(name) + invalid_paths = paths.reject {|p| File.directory?(p) } + + if invalid_paths.any? + Bundler.ui.warn <<~MESSAGE + The following plugin paths don't exist: #{invalid_paths.join(", ")}. + + This can happen if the plugin was installed with a different version of Ruby that has since been uninstalled. + + If you would like to reinstall the plugin, run: + + bundler plugin uninstall #{name} && bundler plugin install #{name} + + Continuing without installing plugin #{name}. + MESSAGE + + return + end + + Gem.add_to_load_path(*paths) + + load path.join(PLUGIN_FILE_NAME) + + @loaded_plugin_names << name + rescue RuntimeError => e + Bundler.ui.error "Failed loading plugin #{name}: #{e.message}" + raise + end + + class << self + private :load_plugin, :register_plugin, :save_plugins, :validate_plugin! + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/api.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/api.rb new file mode 100644 index 00000000..ee2bffe3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/api.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module Bundler + # This is the interfacing class represents the API that we intend to provide + # the plugins to use. + # + # For plugins to be independent of the Bundler internals they shall limit their + # interactions to methods of this class only. This will save them from breaking + # when some internal change. + # + # Currently we are delegating the methods defined in Bundler class to + # itself. So, this class acts as a buffer. + # + # If there is some change in the Bundler class that is incompatible to its + # previous behavior or if otherwise desired, we can reimplement(or implement) + # the method to preserve compatibility. + # + # To use this, either the class can inherit this class or use it directly. + # For example of both types of use, refer the file `spec/plugins/command.rb` + # + # To use it without inheriting, you will have to create an object of this + # to use the functions (except for declaration functions like command, source, + # and hooks). + module Plugin + class API + autoload :Source, File.expand_path("api/source", __dir__) + + # The plugins should declare that they handle a command through this helper. + # + # @param [String] command being handled by them + # @param [Class] (optional) class that handles the command. If not + # provided, the `self` class will be used. + def self.command(command, cls = self) + Plugin.add_command command, cls + end + + # The plugins should declare that they provide a installation source + # through this helper. + # + # @param [String] the source type they provide + # @param [Class] (optional) class that handles the source. If not + # provided, the `self` class will be used. + def self.source(source, cls = self) + cls.send :include, Bundler::Plugin::API::Source + Plugin.add_source source, cls + end + + def self.hook(event, &block) + Plugin.add_hook(event, &block) + end + + # The cache dir to be used by the plugins for storage + # + # @return [Pathname] path of the cache dir + def cache_dir + Plugin.cache.join("plugins") + end + + # A tmp dir to be used by plugins + # Accepts names that get concatenated as suffix + # + # @return [Pathname] object for the new directory created + def tmp(*names) + Bundler.tmp(["plugin", *names].join("-")) + end + + def method_missing(name, *args, &blk) + return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name) + + return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name) + + super + end + + def respond_to_missing?(name, include_private = false) + SharedHelpers.respond_to?(name, include_private) || + Bundler.respond_to?(name, include_private) || super + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/api/source.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/api/source.rb new file mode 100644 index 00000000..79832667 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/api/source.rb @@ -0,0 +1,330 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class API + # This class provides the base to build source plugins + # All the method here are required to build a source plugin (except + # `uri_hash`, `gem_install_dir`; they are helpers). + # + # Defaults for methods, where ever possible are provided which is + # expected to work. But, all source plugins have to override + # `fetch_gemspec_files` and `install`. Defaults are also not provided for + # `remote!`, `cache!` and `unlock!`. + # + # The defaults shall work for most situations but nevertheless they can + # be (preferably should be) overridden as per the plugins' needs safely + # (as long as they behave as expected). + # On overriding `initialize` you should call super first. + # + # If required plugin should override `hash`, `==` and `eql?` methods to be + # able to match objects representing same sources, but may be created in + # different situation (like form gemfile and lockfile). The default ones + # checks only for class and uri, but elaborate source plugins may need + # more comparisons (e.g. git checking on branch or tag). + # + # @!attribute [r] uri + # @return [String] the remote specified with `source` block in Gemfile + # + # @!attribute [r] options + # @return [String] options passed during initialization (either from + # lockfile or Gemfile) + # + # @!attribute [r] name + # @return [String] name that can be used to uniquely identify a source + # + # @!attribute [rw] dependency_names + # @return [Array] Names of dependencies that the source should + # try to resolve. It is not necessary to use this list internally. This + # is present to be compatible with `Definition` and is used by + # rubygems source. + module Source + attr_reader :uri, :options, :name, :checksum_store + attr_accessor :dependency_names + + def initialize(opts) + @options = opts + @dependency_names = [] + @uri = opts["uri"] + @type = opts["type"] + @name = opts["name"] || "#{@type} at #{@uri}" + @checksum_store = Checksum::Store.new + end + + # This is used by the default `spec` method to constructs the + # Specification objects for the gems and versions that can be installed + # by this source plugin. + # + # Note: If the spec method is overridden, this function is not necessary + # + # @return [Array] paths of the gemspec files for gems that can + # be installed + def fetch_gemspec_files + [] + end + + # Options to be saved in the lockfile so that the source plugin is able + # to check out same version of gem later. + # + # There options are passed when the source plugin is created from the + # lockfile. + # + # @return [Hash] + def options_to_lock + {} + end + + # Download the gem specified by the spec at appropriate path. + # + # A source plugin can implement this method to split the download and the + # installation of a gem. + # + # @return [Boolean] Whether the download of the gem succeeded. + def download(spec, opts); end + + # Install the gem specified by the spec at appropriate path. + # `install_path` provides a sufficient default, if the source can only + # satisfy one gem, but is not binding. + # + # @return [String] post installation message (if any) + def install(spec, opts) + raise MalformattedPlugin, "Source plugins need to override the install method." + end + + # It builds extensions, generates bins and installs them for the spec + # provided. + # + # It depends on `spec.loaded_from` to get full_gem_path. The source + # plugins should set that. + # + # It should be called in `install` after the plugin is done placing the + # gem at correct install location. + # + # It also runs Gem hooks `pre_install`, `post_build` and `post_install` + # + # Note: Do not override if you don't know what you are doing. + def post_install(spec, disable_exts = false) + opts = { env_shebang: false, disable_extensions: disable_exts } + installer = Bundler::Source::Path::Installer.new(spec, opts) + installer.post_install + end + + # A default installation path to install a single gem. If the source + # servers multiple gems, it's not of much use and the source should one + # of its own. + def install_path + @install_path ||= + begin + base_name = File.basename(Gem::URI.parse(uri).normalize.path) + + gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") + end + end + + # Parses the gemspec files to find the specs for the gems that can be + # satisfied by the source. + # + # Few important points to keep in mind: + # - If the gems are not installed then it shall return specs for all + # the gems it can satisfy + # - If gem is installed (that is to be detected by the plugin itself) + # then it shall return at least the specs that are installed. + # - The `loaded_from` for each of the specs shall be correct (it is + # used to find the load path) + # + # @return [Bundler::Index] index containing the specs + def specs + files = fetch_gemspec_files + + Bundler::Index.build do |index| + files.each do |file| + next unless spec = Bundler.load_gemspec(file) + spec.installed_by_version = Gem::VERSION + + spec.source = self + Bundler.rubygems.validate(spec) + + index << spec + end + end + end + + # Set internal representation to fetch the gems/specs locally. + # + # When this is called, the source should try to fetch the specs and + # install from the local system. + def local! + end + + # Set internal representation to fetch the gems/specs from remote. + # + # When this is called, the source should try to fetch the specs and + # install from remote path. + def remote! + end + + # Set internal representation to fetch the gems/specs from app cache. + # + # When this is called, the source should try to fetch the specs and + # install from the path provided by `app_cache_path`. + def cached! + end + + # This is called to update the spec and installation. + # + # If the source plugin is loaded from lockfile or otherwise, it shall + # refresh the cache/specs (e.g. git sources can make a fresh clone). + def unlock! + end + + # Name of directory where plugin the is expected to cache the gems when + # #cache is called. + # + # Also this name is matched against the directories in cache for pruning + # + # This is used by `app_cache_path` + def app_cache_dirname + base_name = File.basename(Gem::URI.parse(uri).normalize.path) + "#{base_name}-#{uri_hash}" + end + + # This method is called while caching to save copy of the gems that the + # source can resolve to path provided by `app_cache_app`so that they can + # be reinstalled from the cache without querying the remote (i.e. an + # alternative to remote) + # + # This is stored with the app and source plugins should try to provide + # specs and install only from this cache when `cached!` is called. + # + # This cache is different from the internal caching that can be done + # at sub paths of `cache_path` (from API). This can be though as caching + # by bundler. + def cache(spec, custom_path = nil) + new_cache_path = app_cache_path(custom_path) + + FileUtils.rm_rf(new_cache_path) + FileUtils.cp_r(install_path, new_cache_path) + FileUtils.rm_rf(app_cache_path.join(".git")) + FileUtils.touch(app_cache_path.join(".bundlecache")) + end + + # This shall check if two source object represent the same source. + # + # The comparison shall take place only on the attribute that can be + # inferred from the options passed from Gemfile and not on attributes + # that are used to pin down the gem to specific version (e.g. Git + # sources should compare on branch and tag but not on commit hash) + # + # The sources objects are constructed from Gemfile as well as from + # lockfile. To converge the sources, it is necessary that they match. + # + # The same applies for `eql?` and `hash` + def ==(other) + other.is_a?(self.class) && uri == other.uri + end + + # When overriding `eql?` please preserve the behaviour as mentioned in + # docstring for `==` method. + alias_method :eql?, :== + + # When overriding `hash` please preserve the behaviour as mentioned in + # docstring for `==` method, i.e. two methods equal by above comparison + # should have same hash. + def hash + [self.class, uri].hash + end + + # A helper method, not necessary if not used internally. + def installed? + File.directory?(install_path) + end + + # The full path where the plugin should cache the gem so that it can be + # installed latter. + # + # Note: Do not override if you don't know what you are doing. + def app_cache_path(custom_path = nil) + @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def unmet_deps + specs.unmet_dependency_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def spec_names + specs.spec_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def add_dependency_names(names) + @dependencies |= Array(names) + end + + # NOTE: Do not override if you don't know what you are doing. + def can_lock?(spec) + spec.source == self + end + + # Generates the content to be entered into the lockfile. + # Saves type and remote and also calls to `options_to_lock`. + # + # Plugin should use `options_to_lock` to save information in lockfile + # and not override this. + # + # Note: Do not override if you don't know what you are doing. + def to_lock + out = String.new("#{LockfileParser::PLUGIN}\n") + out << " remote: #{@uri}\n" + out << " type: #{@type}\n" + options_to_lock.each do |opt, value| + out << " #{opt}: #{value}\n" + end + out << " specs:\n" + end + + def to_s + "plugin source for #{@type} with uri #{@uri}" + end + alias_method :identifier, :to_s + + # NOTE: Do not override if you don't know what you are doing. + def include?(other) + other == self + end + + def uri_hash + SharedHelpers.digest(:SHA1).hexdigest(uri) + end + + # NOTE: Do not override if you don't know what you are doing. + def gem_install_dir + Bundler.install_path + end + + # It is used to obtain the full_gem_path. + # + # spec's loaded_from path is expanded against this to get full_gem_path + # + # Note: Do not override if you don't know what you are doing. + def root + Bundler.root + end + + # @private + # This API on source might not be stable, and for now we expect plugins + # to download all specs in `#specs`, so we implement the method for + # compatibility purposes and leave it undocumented (and don't support) + # overriding it) + def double_check_for(*); end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/dsl.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/dsl.rb new file mode 100644 index 00000000..da751d17 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/dsl.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + # Dsl to parse the Gemfile looking for plugins to install + class DSL < Bundler::Dsl + class PluginGemfileError < PluginError; end + alias_method :_gem, :gem # To use for plugin installation as gem + + # So that we don't have to override all there methods to dummy ones + # explicitly. + # They will be handled by method_missing + [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m } + + # This lists the plugins that was added automatically and not specified by + # the user. + # + # When we encounter :type attribute with a source block, we add a plugin + # by name bundler-source- to list of plugins to be installed. + # + # These plugins are optional and are not installed when there is conflict + # with any other plugin. + attr_reader :inferred_plugins + + def initialize + super + @sources = Plugin::SourceList.new + @inferred_plugins = [] # The source plugins inferred from :type + end + + def plugin(name, *args) + _gem(name, *args) + end + + def method_missing(name, *args) + raise PluginGemfileError, "Undefined local variable or method `#{name}' for Gemfile" unless Bundler::Dsl.method_defined? name + end + + def source(source, *args, &blk) + options = args.last.is_a?(Hash) ? args.pop.dup : {} + options = normalize_hash(options) + return super unless options.key?("type") + + plugin_name = "bundler-source-#{options["type"]}" + + return if @dependencies.any? {|d| d.name == plugin_name } + + plugin(plugin_name) + @inferred_plugins << plugin_name + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/events.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/events.rb new file mode 100644 index 00000000..29c05098 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/events.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + module Events + def self.define(const, event) + const = const.to_sym.freeze + if const_defined?(const) && const_get(const) != event + raise ArgumentError, "Attempting to reassign #{const} to a different value" + end + const_set(const, event) unless const_defined?(const) + @events ||= {} + @events[event] = const + end + private_class_method :define + + def self.reset + @events.each_value do |const| + remove_const(const) + end + @events = nil + end + private_class_method :reset + + # Check if an event has been defined + # @param event [String] An event to check + # @return [Boolean] A boolean indicating if the event has been defined + def self.defined_event?(event) + @events ||= {} + @events.key?(event) + end + + # @!parse + # A hook called before each individual gem is installed + # Includes a Bundler::ParallelInstaller::SpecInstallation. + # No state, error, post_install_message will be present as nothing has installed yet + # GEM_BEFORE_INSTALL = "before-install" + define :GEM_BEFORE_INSTALL, "before-install" + + # @!parse + # A hook called after each individual gem is installed + # Includes a Bundler::ParallelInstaller::SpecInstallation. + # - If state is failed, an error will be present. + # - If state is success, a post_install_message may be present. + # GEM_AFTER_INSTALL = "after-install" + define :GEM_AFTER_INSTALL, "after-install" + + # @!parse + # A hook called before any gems install + # Includes an Array of Bundler::Dependency objects + # GEM_BEFORE_INSTALL_ALL = "before-install-all" + define :GEM_BEFORE_INSTALL_ALL, "before-install-all" + + # @!parse + # A hook called after any gems install + # Includes an Array of Bundler::Dependency objects + # GEM_AFTER_INSTALL_ALL = "after-install-all" + define :GEM_AFTER_INSTALL_ALL, "after-install-all" + + # @!parse + # A hook called before each individual gem is required + # Includes a Bundler::Dependency. + # GEM_BEFORE_REQUIRE = "before-require" + define :GEM_BEFORE_REQUIRE, "before-require" + + # @!parse + # A hook called after each individual gem is required + # Includes a Bundler::Dependency. + # GEM_AFTER_REQUIRE = "after-require" + define :GEM_AFTER_REQUIRE, "after-require" + + # @!parse + # A hook called before any gems require + # Includes an Array of Bundler::Dependency objects. + # GEM_BEFORE_REQUIRE_ALL = "before-require-all" + define :GEM_BEFORE_REQUIRE_ALL, "before-require-all" + + # @!parse + # A hook called after all gems required + # Includes an Array of Bundler::Dependency objects. + # GEM_AFTER_REQUIRE_ALL = "after-require-all" + define :GEM_AFTER_REQUIRE_ALL, "after-require-all" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/index.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/index.rb new file mode 100644 index 00000000..94683a5e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/index.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +module Bundler + # Manages which plugins are installed and their sources. This also is supposed to map + # which plugin does what (currently the features are not implemented so this class is + # now a stub class). + module Plugin + class Index + class CommandConflict < PluginError + def initialize(plugin, commands) + msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered." + super msg + end + end + + class SourceConflict < PluginError + def initialize(plugin, sources) + msg = "Source(s) `#{sources.join("`, `")}` declared by #{plugin} are already registered." + super msg + end + end + + attr_reader :commands + + def initialize + @plugin_paths = {} + @commands = {} + @sources = {} + @hooks = {} + @load_paths = {} + + begin + load_index(global_index_file, true) + rescue PermissionError + # no need to fail when on a read-only FS, for example + nil + rescue ArgumentError => e + # ruby 3.4 checks writability in Dir.tmpdir + raise unless e.message&.include?("could not find a temporary directory") + nil + end + load_index(local_index_file) if SharedHelpers.in_bundle? + end + + # This function is to be called when a new plugin is installed. This + # function shall add the functions of the plugin to existing maps and also + # the name to source location. + # + # @param [String] name of the plugin to be registered + # @param [String] path where the plugin is installed + # @param [Array] load_paths for the plugin + # @param [Array] commands that are handled by the plugin + # @param [Array] sources that are handled by the plugin + def register_plugin(name, path, load_paths, commands, sources, hooks) + old_commands = @commands.dup + + common = commands & @commands.keys + raise CommandConflict.new(name, common) unless common.empty? + commands.each {|c| @commands[c] = name } + + common = sources & @sources.keys + raise SourceConflict.new(name, common) unless common.empty? + sources.each {|k| @sources[k] = name } + + hooks.each do |event| + event_hooks = (@hooks[event] ||= []) << name + event_hooks.uniq! + end + + @plugin_paths[name] = path + @load_paths[name] = load_paths + save_index + rescue StandardError + @commands = old_commands + raise + end + + def unregister_plugin(name) + @commands.delete_if {|_, v| v == name } + @sources.delete_if {|_, v| v == name } + @hooks.each do |hook, names| + names.delete(name) + @hooks.delete(hook) if names.empty? + end + @plugin_paths.delete(name) + @load_paths.delete(name) + save_index + end + + # Path of default index file + def index_file + Plugin.root.join("index") + end + + # Path where the global index file is stored + def global_index_file + Plugin.global_root.join("index") + end + + # Path where the local index file is stored + def local_index_file + Plugin.local_root.join("index") + end + + def plugin_path(name) + Pathname.new @plugin_paths[name] + end + + def load_paths(name) + @load_paths[name] + end + + # Fetch the name of plugin handling the command + def command_plugin(command) + @commands[command] + end + + def installed?(name) + @plugin_paths[name] + end + + def up_to_date?(spec) + path = installed?(spec.name) + + path == spec.full_gem_path + end + + def installed_plugins + @plugin_paths.keys + end + + def plugin_commands(plugin) + @commands.find_all {|_, n| n == plugin }.map(&:first) + end + + def source?(source) + @sources.key? source + end + + def source_plugin(name) + @sources[name] + end + + # Returns the list of plugin names handling the passed event + def hook_plugins(event) + @hooks[event] || [] + end + + # This plugin is installed inside the .bundle/plugin directory, + # and thus is managed solely by Bundler + def installed_in_plugin_root?(name) + return false unless (path = installed?(name)) + + path.start_with?("#{Plugin.root}/") + end + + private + + # Reads the index file from the directory and initializes the instance + # variables. + # + # It skips the sources if the second param is true + # @param [Pathname] index file path + # @param [Boolean] is the index file global index + def load_index(index_file, global = false) + SharedHelpers.filesystem_access(index_file, :read) do |index_f| + valid_file = index_f&.exist? && !index_f.size.zero? + break unless valid_file + + data = index_f.read + + require_relative "../yaml_serializer" + index = YAMLSerializer.load(data) + + @commands.merge!(index["commands"]) + @hooks.merge!(index["hooks"]) + @load_paths.merge!(index["load_paths"]) + @plugin_paths.merge!(index["plugin_paths"]) + @sources.merge!(index["sources"]) unless global + end + end + + # Should be called when any of the instance variables change. Stores the + # instance variables in YAML format. (The instance variables are supposed + # to be only String key value pairs) + def save_index + index = { + "commands" => @commands, + "hooks" => @hooks, + "load_paths" => @load_paths, + "plugin_paths" => @plugin_paths, + "sources" => @sources, + } + + require_relative "../yaml_serializer" + SharedHelpers.filesystem_access(index_file) do |index_f| + FileUtils.mkdir_p(index_f.dirname) + File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer.rb new file mode 100644 index 00000000..9be8b368 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +module Bundler + # Handles the installation of plugin in appropriate directories. + # + # This class is supposed to be wrapper over the existing gem installation infra + # but currently it itself handles everything as the Source's subclasses (e.g. Source::RubyGems) + # are heavily dependent on the Gemfile. + module Plugin + class Installer + autoload :Rubygems, File.expand_path("installer/rubygems", __dir__) + autoload :Git, File.expand_path("installer/git", __dir__) + autoload :Path, File.expand_path("installer/path", __dir__) + + def install(names, options) + check_sources_consistency!(options) + + version = options[:version] || [">= 0"] + + if options[:git] + install_git(names, version, options) + elsif options[:path] + install_path(names, version, options[:path]) + else + sources = options[:source] || Gem.sources + install_rubygems(names, version, sources) + end + end + + # Installs the plugin from Definition object created by limited parsing of + # Gemfile searching for plugins to be installed + # + # @param [Definition] definition object + # @return [Hash] map of names to their specs they are installed with + def install_definition(definition) + def definition.lock(*); end + definition.remotely! + specs = definition.specs + + install_from_specs specs + end + + private + + def check_sources_consistency!(options) + if (options.keys & [:source, :git, :path]).length > 1 + raise InvalidOption, "Only one of --source, --git, or --path may be specified" + end + + if (options.key?(:branch) || options.key?(:ref)) && !options.key?(:git) + raise InvalidOption, "--#{options.key?(:branch) ? "branch" : "ref"} can only be used with git sources" + end + + if options.key?(:branch) && options.key?(:ref) + raise InvalidOption, "--branch and --ref can't be both specified" + end + end + + def install_git(names, version, options) + source_list = SourceList.new + source = source_list.add_git_source({ "uri" => options[:git], + "branch" => options[:branch], + "ref" => options[:ref] }) + + install_all_sources(names, version, source_list, source) + end + + def install_path(names, version, path) + source_list = SourceList.new + source = source_list.add_path_source({ "path" => path, "root_path" => SharedHelpers.pwd }) + + install_all_sources(names, version, source_list, source) + end + + # Installs the plugin from rubygems source and returns the path where the + # plugin was installed + # + # @param [String] name of the plugin gem to search in the source + # @param [Array] version of the gem to install + # @param [String, Array] source(s) to resolve the gem + # + # @return [Hash] map of names to the specs of plugins installed + def install_rubygems(names, version, sources) + source_list = SourceList.new + + Array(sources).each {|remote| source_list.add_global_rubygems_remote(remote) } + + install_all_sources(names, version, source_list) + end + + def install_all_sources(names, version, source_list, source = nil) + deps = names.map {|name| Dependency.new(name, version, { "source" => source }) } + + Bundler.configure_gem_home_and_path(Plugin.root) + + Bundler.settings.temporary(deployment: false, frozen: false) do + definition = Definition.new(nil, deps, source_list, true) + + install_definition(definition) + end + end + + # Installs the plugins and deps from the provided specs and returns map of + # gems to their paths + # + # @param specs to install + # + # @return [Hash] map of names to the specs + def install_from_specs(specs) + paths = {} + + specs.each do |spec| + spec.source.download(spec) + spec.source.install(spec) + + paths[spec.name] = spec + end + + paths + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/git.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/git.rb new file mode 100644 index 00000000..deec5e99 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/git.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Git < Bundler::Source::Git + def cache_path + @cache_path ||= begin + git_scope = "#{base_name}-#{uri_hash}" + + Plugin.cache.join("bundler", "git", git_scope) + end + end + + def install_path + @install_path ||= begin + git_scope = "#{base_name}-#{shortref_for_path(revision)}" + + Plugin.root.join("bundler", "gems", git_scope) + end + end + + def root + Plugin.root + end + + def generate_bin(spec, disable_extensions = false) + # Need to find a way without code duplication + # For now, we can ignore this + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/path.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/path.rb new file mode 100644 index 00000000..58c4924e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/path.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Path < Bundler::Source::Path + def root + SharedHelpers.in_bundle? ? Bundler.root : Plugin.root + end + + def eql?(other) + return unless other.class == self.class + expanded_original_path == other.expanded_original_path && + version == other.version + end + + alias_method :==, :eql? + + def generate_bin(spec, disable_extensions = false) + # Need to find a way without code duplication + # For now, we can ignore this + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/rubygems.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/rubygems.rb new file mode 100644 index 00000000..cb5db9c3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/installer/rubygems.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + class Installer + class Rubygems < Bundler::Source::Rubygems + private + + def rubygems_dir + Plugin.root + end + + def cache_path + Plugin.cache + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/source_list.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/source_list.rb new file mode 100644 index 00000000..d929ade2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/source_list.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + # SourceList object to be used while parsing the Gemfile, setting the + # approptiate options to be used with Source classes for plugin installation + module Plugin + class SourceList < Bundler::SourceList + def add_git_source(options = {}) + add_source_to_list Plugin::Installer::Git.new(options), git_sources + end + + def add_path_source(options = {}) + add_source_to_list Plugin::Installer::Path.new(options), path_sources + end + + def add_rubygems_source(options = {}) + add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources + end + + def all_sources + path_sources + git_sources + rubygems_sources + [metadata_source] + end + + private + + def source_class + Plugin::Installer::Rubygems + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/plugin/unloaded_source.rb b/bin/gems/bundler-4.0.21/lib/bundler/plugin/unloaded_source.rb new file mode 100644 index 00000000..948b6c7e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/plugin/unloaded_source.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Bundler + module Plugin + # Stands in for a source handled by a plugin that is not loaded yet, so + # that the lockfile can still be parsed during the plugin install pass, + # and by external tools reading a lockfile without the plugin installed. + class UnloadedSource + include API::Source + + # Unlike real plugin sources, where the handling class encodes the + # source type, all unloaded sources share this class, so the type must + # be compared explicitly. + def ==(other) + super && options["type"] == other.options["type"] + end + + alias_method :eql?, :== + + def hash + [super, options["type"]].hash + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/process_lock.rb b/bin/gems/bundler-4.0.21/lib/bundler/process_lock.rb new file mode 100644 index 00000000..784b17e3 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/process_lock.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Bundler + class ProcessLock + def self.lock(bundle_path = Bundler.bundle_path, &block) + lock_file_path = File.join(bundle_path, "bundler.lock") + base_lock_file_path = lock_file_path.delete_suffix(".lock") + + require "fileutils" if Bundler.rubygems.provides?("< 3.6.0") + + begin + SharedHelpers.filesystem_access(lock_file_path, :write) do + Gem.open_file_with_lock(base_lock_file_path, &block) + end + rescue PermissionError + block.call + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/remote_specification.rb b/bin/gems/bundler-4.0.21/lib/bundler/remote_specification.rb new file mode 100644 index 00000000..dcaaf6af --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/remote_specification.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +module Bundler + # Represents a lazily loaded gem specification, where the full specification + # is on the source server in rubygems' "quick" index. The proxy object is to + # be seeded with what we're given from the source's abbreviated index - the + # full specification will only be fetched when necessary. + class RemoteSpecification + include MatchRemoteMetadata + include MatchPlatform + include Comparable + + attr_reader :name, :version, :platform + attr_writer :dependencies + attr_accessor :source, :remote, :locked_platform, :created_at + + def initialize(name, version, platform, spec_fetcher) + @name = name + @version = Gem::Version.create version + @original_platform = platform || Gem::Platform::RUBY + @platform = Gem::Platform.new(platform) + @spec_fetcher = spec_fetcher + @dependencies = nil + @locked_platform = nil + end + + def insecurely_materialized? + @locked_platform.to_s != @platform.to_s + end + + # Needed before installs, since the arch matters then and quick + # specs don't bother to include the arch in the platform string + def fetch_platform + @platform = _remote_specification.platform + end + + def full_name + @full_name ||= if @platform == Gem::Platform::RUBY + "#{@name}-#{@version}" + else + "#{@name}-#{@version}-#{@platform}" + end + end + + # Compare this specification against another object. Using sort_obj + # is compatible with Gem::Specification and other Bundler or RubyGems + # objects. Otherwise, use the default Object comparison. + def <=>(other) + if other.respond_to?(:sort_obj) + sort_obj <=> other.sort_obj + else + super + end + end + + # Because Rubyforge cannot be trusted to provide valid specifications + # once the remote gem is downloaded, the backend specification will + # be swapped out. + def __swap__(spec) + raise APIResponseInvalidDependenciesError unless spec.dependencies.all? {|d| d.is_a?(Gem::Dependency) } + + SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies) + @_remote_specification = spec + end + + # Create a delegate used for sorting. This strategy is copied from + # RubyGems 2.23 and ensures that Bundler's specifications can be + # compared and sorted with RubyGems' own specifications. + # + # @see #<=> + # @see Gem::Specification#sort_obj + # + # @return [Array] an object you can use to compare and sort this + # specification against other specifications + def sort_obj + [@name, @version, @platform == Gem::Platform::RUBY ? -1 : 1] + end + + def to_s + "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>" + end + + def dependencies + @dependencies ||= begin + deps = method_missing(:dependencies) + + # allow us to handle when the specs dependencies are an array of array of string + # in order to delay the crash to `#__swap__` where it results in a friendlier error + # see https://github.com/rubygems/bundler/issues/5797 + deps = deps.map {|d| d.is_a?(Gem::Dependency) ? d : Gem::Dependency.new(*d) } + + deps + end + end + + def runtime_dependencies + dependencies.select(&:runtime?) + end + + def git_version + return unless loaded_from && source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + private + + def to_ary + nil + end + + def _remote_specification + @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) + @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ + " missing from the server!") + end + + def method_missing(method, *args, &blk) + _remote_specification.send(method, *args, &blk) + end + + def respond_to?(method, include_all = false) + super || _remote_specification.respond_to?(method, include_all) + end + public :respond_to? + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver.rb new file mode 100644 index 00000000..2ea819d2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver.rb @@ -0,0 +1,656 @@ +# frozen_string_literal: true + +module Bundler + # + # This class implements the interface needed by PubGrub for resolution. It is + # equivalent to the `PubGrub::BasicPackageSource` class provided by PubGrub by + # default and used by the most simple PubGrub consumers. + # + class Resolver + require_relative "vendored_pub_grub" + require_relative "resolver/base" + require_relative "resolver/candidate" + require_relative "resolver/incompatibility" + require_relative "resolver/root" + require_relative "resolver/strategy" + + attr_reader :cooldown_skipped + + def initialize(base, gem_version_promoter, most_specific_locked_platform = nil) + @source_requirements = base.source_requirements + @base = base + @gem_version_promoter = gem_version_promoter + @most_specific_locked_platform = most_specific_locked_platform + @cooldown_skipped = [] + @cooldown_skipped_specs = {} + end + + def start + @requirements = @base.requirements + @packages = @base.packages + + root, logger = setup_solver + + Bundler.ui.info "Resolving dependencies...", true + + solve_versions(root: root, logger: logger) + end + + def setup_solver + root = Resolver::Root.new(name_for_explicit_dependency_source) + root_version = Resolver::Candidate.new(0) + + @cooldown_skipped_specs = {} + + @all_specs = Hash.new do |specs, name| + source = source_for(name) + matches = source.specs.search(name) + + # Don't bother to check for circular deps when no dependency API are + # available, since it's too slow to be usable. That edge case won't work + # but resolution other than that should work fine and reasonably fast. + if source.respond_to?(:dependency_api_available?) && source.dependency_api_available? + matches = filter_invalid_self_dependencies(matches, name) + end + + specs[name] = matches.sort_by {|s| [s.version, s.platform.to_s] } + end + + @all_versions = Hash.new do |candidates, package| + candidates[package] = all_versions_for(package) + end + + @sorted_versions = Hash.new do |candidates, package| + candidates[package] = filtered_versions_for(package).sort + end + + @sorted_versions[root] = [root_version] + + root_dependencies = prepare_dependencies(@requirements, @packages) + + @cached_dependencies = Hash.new do |dependencies, package| + dependencies[package] = Hash.new do |versions, version| + versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages) + end + end + + @cached_dependencies[root] = { root_version => root_dependencies } + + logger = Bundler::UI::Shell.new + logger.level = debug? ? "debug" : "warn" + + [root, logger] + end + + def solve_versions(root:, logger:) + solver = PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger) + result = solver.solve + resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) } + spec_set = SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs) + @cooldown_skipped = cooldown_skipped_summary(spec_set) + spec_set + rescue PubGrub::SolveFailure => e + incompatibility = e.incompatibility + + names_to_unlock, names_to_allow_prereleases_for, names_to_allow_remote_specs_for, extended_explanation = find_names_to_relax(incompatibility) + + names_to_relax = names_to_unlock + names_to_allow_prereleases_for + names_to_allow_remote_specs_for + + if names_to_relax.any? + if names_to_unlock.any? + Bundler.ui.debug "Found conflicts with locked dependencies. Will retry with #{names_to_unlock.join(", ")} unlocked...", true + + @base.unlock_names(names_to_unlock) + end + + if names_to_allow_prereleases_for.any? + Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retry considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true + + @base.include_prereleases(names_to_allow_prereleases_for) + end + + if names_to_allow_remote_specs_for.any? + Bundler.ui.debug "Found conflicts with local versions of #{names_to_allow_remote_specs_for.join(", ")}. Will retry considering remote versions...", true + + @base.include_remote_specs(names_to_allow_remote_specs_for) + end + + root, logger = setup_solver + + Bundler.ui.debug "Retrying resolution...", true + retry + end + + explanation = e.message + + if extended_explanation + explanation << "\n\n" + explanation << extended_explanation + end + + raise SolveFailure.new(explanation) + end + + def find_names_to_relax(incompatibility) + names_to_unlock = [] + names_to_allow_prereleases_for = [] + names_to_allow_remote_specs_for = [] + extended_explanation = nil + + while incompatibility.conflict? + cause = incompatibility.cause + incompatibility = cause.incompatibility + + incompatibility.terms.each do |term| + package = term.package + name = package.name + + if base_requirements[name] + names_to_unlock << name + elsif package.ignores_prereleases? && @all_specs[name].any? {|s| s.version.prerelease? } + names_to_allow_prereleases_for << name + elsif package.prefer_local? && @all_specs[name].any? {|s| !s.is_a?(StubSpecification) } + names_to_allow_remote_specs_for << name + end + + no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) } + next unless no_versions_incompat + + extended_explanation = no_versions_incompat.extended_explanation + end + end + + [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, names_to_allow_remote_specs_for.uniq, extended_explanation] + end + + def parse_dependency(package, dependency) + range = if repository_for(package).is_a?(Source::Gemspec) + PubGrub::VersionRange.any + else + requirement_to_range(dependency) + end + + PubGrub::VersionConstraint.new(package, range: range) + end + + def versions_for(package, range = VersionRange.any) + range.select_versions(@sorted_versions[package]) + end + + def no_versions_incompatibility_for(package, unsatisfied_term) + cause = PubGrub::Incompatibility::NoVersions.new(unsatisfied_term) + name = package.name + constraint = unsatisfied_term.constraint + constraint_string = constraint.constraint_string + requirements = constraint_string.split(" OR ").map {|req| Gem::Requirement.new(req.split(",")) } + + if name == "bundler" && bundler_pinned_to_current_version? + custom_explanation = "the current Bundler version (#{Bundler::VERSION}) does not satisfy #{constraint}" + extended_explanation = bundler_not_found_message(requirements) + else + specs_matching_other_platforms = filter_matching_specs(@all_specs[name], requirements) + + platforms_explanation = specs_matching_other_platforms.any? ? " for any resolution platforms (#{package.platforms.join(", ")})" : "" + custom_explanation = "#{constraint} could not be found in #{repository_for(package)}#{platforms_explanation}" + if hint = cooldown_hint(specs_matching_other_platforms) + custom_explanation += " (#{hint})" + end + + label = "#{name} (#{constraint_string})" + extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any? + end + + Incompatibility.new([unsatisfied_term], cause: cause, custom_explanation: custom_explanation, extended_explanation: extended_explanation) + end + + def debug? + ENV["BUNDLER_DEBUG_RESOLVER"] || + ENV["BUNDLER_DEBUG_RESOLVER_TREE"] || + ENV["DEBUG_RESOLVER"] || + ENV["DEBUG_RESOLVER_TREE"] || + false + end + + def incompatibilities_for(package, version) + package_deps = @cached_dependencies[package] + sorted_versions = @sorted_versions[package] + package_deps[version].map do |dep_package, dep_constraint| + low = high = sorted_versions.index(version) + + # find version low such that all >= low share the same dep + while low > 0 && package_deps[sorted_versions[low - 1]][dep_package] == dep_constraint + low -= 1 + end + low = + if low == 0 + nil + else + sorted_versions[low] + end + + # find version high such that all < high share the same dep + while high < sorted_versions.length && package_deps[sorted_versions[high]][dep_package] == dep_constraint + high += 1 + end + high = + if high == sorted_versions.length + nil + else + sorted_versions[high] + end + + range = PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?) + + self_constraint = PubGrub::VersionConstraint.new(package, range: range) + + dep_term = PubGrub::Term.new(dep_constraint, false) + self_term = PubGrub::Term.new(self_constraint, true) + + custom_explanation = if dep_package.meta? && package.root? + "current #{dep_package} version is #{dep_constraint.constraint_string}" + end + + PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation) + end + end + + def all_versions_for(package) + name = package.name + results = (@base[name] + filter_specs(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] } + + if name == "bundler" && !bundler_pinned_to_current_version? + bundler_spec = Gem.loaded_specs["bundler"] + results << bundler_spec if bundler_spec + end + + locked_requirement = base_requirements[name] + results = filter_matching_specs(results, locked_requirement) if locked_requirement + + results.group_by(&:version).reduce([]) do |groups, (version, specs)| + platform_specs = package.platform_specs(specs) + + # If package is a top-level dependency, + # candidate is only valid if there are matching versions for all resolution platforms. + # + # If package is not a top-level deependency, + # then it's not necessary that it has matching versions for all platforms, since it may have been introduced only as + # a dependency for a platform specific variant, so it will only need to have a valid version for that platform. + # + if package.top_level? + next groups if platform_specs.any?(&:empty?) + else + next groups if platform_specs.all?(&:empty?) + end + + ruby_specs = MatchPlatform.select_best_platform_match(specs, Gem::Platform::RUBY) + ruby_group = Resolver::SpecGroup.new(ruby_specs) + + unless ruby_group.empty? + platform_specs.each do |s| + ruby_group.merge(Resolver::SpecGroup.new(s)) + end + + groups << Resolver::Candidate.new(version, group: ruby_group, priority: -1) + next groups if package.force_ruby_platform? + end + + platform_group = Resolver::SpecGroup.new(platform_specs.flatten.uniq) + next groups if platform_group == ruby_group + + groups << Resolver::Candidate.new(version, group: platform_group, priority: 1) + + groups + end + end + + def source_for(name) + @source_requirements[name] || @source_requirements[:default] + end + + def default_bundler_source + @source_requirements[:default_bundler] + end + + def bundler_pinned_to_current_version? + !default_bundler_source.nil? + end + + def name_for_explicit_dependency_source + Bundler.default_gemfile.basename.to_s + rescue StandardError + "Gemfile" + end + + def raise_incomplete!(incomplete_specs) + raise_not_found!(@base.get_package(incomplete_specs.first.name)) + end + + def sort_versions_by_preferred(package, versions) + @gem_version_promoter.sort_versions(package, versions) + end + + private + + def raise_not_found!(package) + name = package.name + source = source_for(name) + specs = @all_specs[name] + matching_part = name + requirement_label = SharedHelpers.pretty_dependency(package.dependency) + cache_message = begin + " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? + rescue GemfileNotFound + nil + end + specs_matching_requirement = filter_matching_specs(specs, package.dependency.requirement) + + not_found_message = if specs_matching_requirement.any? + specs = specs_matching_requirement + matching_part = requirement_label + platforms = package.platforms + + if platforms.size == 1 + "Could not find gem '#{requirement_label}' with platform '#{platforms.first}'" + else + "Could not find gems matching '#{requirement_label}' valid for all resolution platforms (#{platforms.join(", ")})" + end + else + "Could not find gem '#{requirement_label}'" + end + + message = String.new("#{not_found_message} in #{source}#{cache_message}.\n") + + if specs.any? + message << "\n#{other_specs_matching_message(specs, matching_part)}" + end + + if hint = cooldown_hint(specs_matching_requirement) + message << "\n\n#{hint}." + end + + if specs_matching_requirement.any? && (hint = platform_mismatch_hint) + message << "\n\n#{hint}" + end + + raise GemNotFound, message + end + + def platform_mismatch_hint + locked_platforms = Bundler.locked_gems&.platforms + return unless locked_platforms + + local_platform = Bundler.local_platform + return if locked_platforms.include?(local_platform) + return if locked_platforms.any? {|p| p == Gem::Platform::RUBY } + + "Your current platform (#{local_platform}) is not included in the lockfile's platforms (#{locked_platforms.join(", ")}). " \ + "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again." + rescue GemfileNotFound + nil + end + + def filtered_versions_for(package) + @gem_version_promoter.filter_versions(package, @all_versions[package]) + end + + def raise_all_versions_filtered_out!(package) + level = @gem_version_promoter.level + name = package.name + locked_version = package.locked_version + requirement = package.dependency + + raise GemNotFound, + "#{name} is locked to #{locked_version}, while Gemfile is requesting #{requirement}. " \ + "--strict --#{level} was specified, but there are no #{level} level upgrades from #{locked_version} satisfying #{requirement}, so version solving has failed" + end + + def filter_matching_specs(specs, requirements) + Array(requirements).flat_map do |requirement| + specs.select {| spec| requirement_satisfied_by?(requirement, spec) } + end + end + + def filter_specs(specs, package) + filter_remote_specs(filter_cooldown(filter_prereleases(specs, package)), package) + end + + def filter_prereleases(specs, package) + return specs unless package.ignores_prereleases? && specs.size > 1 + + specs.reject {|s| s.version.prerelease? } + end + + def filter_cooldown(specs) + return specs if specs.empty? + excluded_versions = cooldown_excluded_versions(specs) + return specs if excluded_versions.empty? + specs.reject {|s| excluded_versions.include?([s.name, s.version]) } + end + + def cooldown_excluded_versions(specs) + excluded = {} + specs.each do |spec| + next unless cooldown_excluded?(spec) + excluded[[spec.name, spec.version]] = true + (@cooldown_skipped_specs ||= {})[[spec.name, spec.version]] ||= spec + end + excluded + end + + def cooldown_hint(specs) + excluded_versions = cooldown_excluded_versions(specs) + return nil if excluded_versions.empty? + "#{excluded_versions.size} version#{"s" if excluded_versions.size > 1} excluded by the cooldown setting; pass `--cooldown 0` to bypass" + end + + def cooldown_excluded?(spec) + return false unless spec.respond_to?(:created_at) && spec.created_at + return false unless spec.respond_to?(:remote) && spec.remote + return false if locked_by_lockfile?(spec) + days = spec.remote.effective_cooldown + return false if days.nil? || days <= 0 + (cooldown_now - spec.created_at) < (days * 86_400) + end + + # A version already written to the lockfile has been adopted, and cooldown + # only governs the adoption of *new* versions, so it must never retract one + # the lockfile already pins. Keying this off the locked specs rather than the + # prevent-downgrade floor matters because that floor is absent on resolutions + # that re-pick a gem from scratch: the auxiliary full update run to compute + # `--update` targets, and the from-scratch retries after a conflict unlocks a + # gem. In those passes the locked version is the only candidate, so filtering + # it out makes an unrelated operation impossible whenever every published + # version matching the requirement sits inside the cooldown window. + # + # Gems named on a `bundle update GEM` command are the exception: the user + # asked to move them, so they stay subject to cooldown and a locked-but-fresh + # release is pushed back to an older one (or fails loudly when none exists). + def locked_by_lockfile?(spec) + return false unless defined?(@base) && @base + return false if @base.explicitly_unlocked?(spec.name) + @base.locked_specs[spec.name].any? {|locked| locked.version == spec.version } + end + + def cooldown_now + @cooldown_now ||= Time.now + end + + # Reports, per gem, the newest version that cooldown kept out of a + # successful resolution. A skipped version is only worth reporting when it + # is newer than the resolved version and satisfies every requirement the + # final resolution places on that gem, so we don't claim a version the + # resolver could never have picked anyway. + def cooldown_skipped_summary(spec_set) + return [] if @cooldown_skipped_specs.empty? + + requirements = Hash.new {|h, name| h[name] = [] } + @requirements.each {|dep| requirements[dep.name] << dep.requirement } + spec_set.each do |spec| + spec.dependencies.each {|dep| requirements[dep.name] << dep.requirement } + end + + resolved_versions = {} + spec_set.each do |spec| + version = resolved_versions[spec.name] + resolved_versions[spec.name] = spec.version if version.nil? || spec.version > version + end + + newest_skipped = {} + @cooldown_skipped_specs.each do |(name, version), spec| + resolved = resolved_versions[name] + next unless resolved && version > resolved + next unless requirements[name].all? {|req| req.satisfied_by?(version) } + newest = newest_skipped[name] + newest_skipped[name] = spec if newest.nil? || version > newest.version + end + + newest_skipped.values.sort_by(&:name).map do |spec| + { + name: spec.name, + version: spec.version, + resolved: resolved_versions[spec.name], + available_in_days: remaining_cooldown_days(spec), + } + end + end + + def remaining_cooldown_days(spec) + remaining = (spec.remote.effective_cooldown * 86_400) - (cooldown_now - spec.created_at) + [(remaining / 86_400.0).ceil, 1].max + end + + def filter_remote_specs(specs, package) + if package.prefer_local? + local_specs = specs.select {|s| s.is_a?(StubSpecification) } + + if local_specs.empty? + package.consider_remote_versions! + specs + else + local_specs + end + else + specs + end + end + + # Ignore versions that depend on themselves incorrectly + def filter_invalid_self_dependencies(specs, name) + specs.reject do |s| + s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } + end + end + + def requirement_satisfied_by?(requirement, spec) + requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec) + end + + def repository_for(package) + source_for(package.name) + end + + def base_requirements + @base.base_requirements + end + + def prepare_dependencies(requirements, packages) + to_dependency_hash(requirements, packages).filter_map do |dep_package, dep_constraint| + name = dep_package.name + + next [dep_package, dep_constraint] if name == "bundler" + + dep_range = dep_constraint.range + versions = versions_for(dep_package, dep_range) + if versions.empty? + if dep_package.ignores_prereleases? || dep_package.prefer_local? + @all_versions.delete(dep_package) + @sorted_versions.delete(dep_package) + end + dep_package.consider_prereleases! if dep_package.ignores_prereleases? + dep_package.consider_remote_versions! if dep_package.prefer_local? + versions = versions_for(dep_package, dep_range) + end + + if versions.empty? && select_all_versions(dep_package, dep_range).any? + raise_all_versions_filtered_out!(dep_package) + end + + next [dep_package, dep_constraint] unless versions.empty? + + next unless dep_package.current_platform? + + raise_not_found!(dep_package) + end.to_h + end + + def select_all_versions(package, range) + range.select_versions(@all_versions[package]) + end + + def other_specs_matching_message(specs, requirement) + message = String.new("The source contains the following gems matching '#{requirement}':\n") + message << specs.map {|s| " * #{s.full_name}" }.join("\n") + message + end + + def requirement_to_range(requirement) + ranges = requirement.requirements.map do |(op, version)| + ver = Resolver::Candidate.new(version, priority: -1) + platform_ver = Resolver::Candidate.new(version, priority: 1) + + case op + when "~>" + name = "~> #{ver}" + bump = Resolver::Candidate.new(version.bump.to_s + ".A") + PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true) + when ">" + PubGrub::VersionRange.new(min: platform_ver) + when ">=" + PubGrub::VersionRange.new(min: ver, include_min: true) + when "<" + PubGrub::VersionRange.new(max: ver) + when "<=" + PubGrub::VersionRange.new(max: platform_ver, include_max: true) + when "=" + PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true) + when "!=" + PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert + else + raise "bad version specifier: #{op}" + end + end + + ranges.inject(&:intersect) + end + + def to_dependency_hash(dependencies, packages) + dependencies.inject({}) do |deps, dep| + package = packages[dep.name] + + current_req = deps[package] + new_req = parse_dependency(package, dep.requirement) + + deps[package] = if current_req + current_req.intersect(new_req) + else + new_req + end + + deps + end + end + + def bundler_not_found_message(conflict_dependencies) + candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies) + + if candidate_specs.any? + target_version = candidate_specs.last.version + new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") + "Your bundle requires a different version of Bundler than the one you're running.\n" \ + "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n" + else + "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/base.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/base.rb new file mode 100644 index 00000000..e2b8935a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/base.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require_relative "package" + +module Bundler + class Resolver + class Base + attr_reader :packages, :requirements, :source_requirements, :locked_specs + + def initialize(source_requirements, dependencies, base, platforms, options) + @explicit_unlocks = options.delete(:explicit_unlocks) || [] + @source_requirements = source_requirements + @locked_specs = options[:locked_specs] + + @base = base + + @packages = Hash.new do |hash, name| + hash[name] = Package.new(name, platforms, **options) + end + + @requirements = dependencies.filter_map do |dep| + dep_platforms = dep.gem_platforms(platforms) + + # Dependencies scoped to external platforms are ignored + next if dep_platforms.empty? + + name = dep.name + + @packages[name] = Package.new(name, dep_platforms, **options.merge(dependency: dep)) + + dep + end + end + + def [](name) + @base[name] + end + + def delete(specs) + @base.delete(specs) + end + + def get_package(name) + @packages[name] + end + + # Gems the user named on a `bundle update GEM` / `bundle lock --update GEM` + # command line. These are the only ones meant to move off their locked + # version, so cooldown keeps applying to them while every other locked gem + # stays exempt. + def explicitly_unlocked?(name) + @explicit_unlocks.include?(name) + end + + def base_requirements + @base_requirements ||= build_base_requirements + end + + def unlock_names(names) + indirect_pins = indirect_pins(names) + + if indirect_pins.any? + loosen_names(indirect_pins) + else + pins = pins(names) + + if pins.any? + loosen_names(pins) + else + unrestrict_names(names) + end + end + end + + def include_prereleases(names) + names.each do |name| + get_package(name).consider_prereleases! + end + end + + def include_remote_specs(names) + names.each do |name| + get_package(name).consider_remote_versions! + end + end + + private + + def indirect_pins(names) + names.select {|name| @base_requirements[name].exact? && @requirements.none? {|dep| dep.name == name } } + end + + def pins(names) + names.select {|name| @base_requirements[name].exact? } + end + + def loosen_names(names) + names.each do |name| + version = @base_requirements[name].requirements.first[1] + + @base_requirements[name] = Gem::Requirement.new(">= #{version}") + + @base.delete_by_name(name) + end + end + + def unrestrict_names(names) + names.each do |name| + @base_requirements.delete(name) + end + end + + def build_base_requirements + base_requirements = {} + @base.each do |ls| + if ls.source_changed? && ls.source.specs.search(ls.name).empty? + raise GemNotFound, "Could not find gem '#{ls.name}' in #{ls.source}" + end + + req = Gem::Requirement.new(ls.version) + base_requirements[ls.name] = req + end + base_requirements + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/candidate.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/candidate.rb new file mode 100644 index 00000000..5298b253 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/candidate.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require_relative "spec_group" + +module Bundler + class Resolver + # + # This class is a PubGrub compatible "Version" class that takes Bundler + # resolution complexities into account. + # + # Each Resolver::Candidate has a underlying `Gem::Version` plus a set of + # platforms. For example, 1.1.0-x86_64-linux is a different resolution candidate + # from 1.1.0 (generic). This is because different platform variants of the + # same gem version can bring different dependencies, so they need to be + # considered separately. + # + # Some candidates may also keep some information explicitly about the + # package they refer to. These candidates are referred to as "canonical" and + # are used when materializing resolution results back into RubyGems + # specifications that can be installed, written to lockfiles, and so on. + # + class Candidate + include Comparable + + attr_reader :version + + def initialize(version, group: nil, priority: -1) + @spec_group = group || SpecGroup.new([]) + @version = Gem::Version.new(version) + @priority = priority + end + + def dependencies + @spec_group.dependencies + end + + def to_specs(package, most_specific_locked_platform) + return [] if package.meta? + + @spec_group.to_specs(package.force_ruby_platform?, most_specific_locked_platform) + end + + def prerelease? + @version.prerelease? + end + + def segments + @version.segments + end + + def <=>(other) + return unless other.is_a?(self.class) + + version_comparison = version <=> other.version + return version_comparison unless version_comparison.zero? + + priority <=> other.priority + end + + def ==(other) + return unless other.is_a?(self.class) + + version == other.version && priority == other.priority + end + + def eql?(other) + return unless other.is_a?(self.class) + + version.eql?(other.version) && priority.eql?(other.priority) + end + + def hash + [@version, @priority].hash + end + + def to_s + @version.to_s + end + + protected + + attr_reader :priority + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/incompatibility.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/incompatibility.rb new file mode 100644 index 00000000..4ac1b2e1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/incompatibility.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class Incompatibility < PubGrub::Incompatibility + attr_reader :extended_explanation + + def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil) + @extended_explanation = extended_explanation + + super(terms, cause: cause, custom_explanation: custom_explanation) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/package.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/package.rb new file mode 100644 index 00000000..3906be3f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/package.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + # + # Represents a gem being resolved, in a format PubGrub likes. + # + # The class holds the following information: + # + # * Platforms this gem will be resolved on. + # * The locked version of this gem resolution should favor (if any). + # * Whether the gem should be unlocked to its latest version. + # * The dependency explicit set in the Gemfile for this gem (if any). + # + class Package + attr_reader :name, :platforms, :dependency, :locked_version + + def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, prefer_local: false, dependency: nil, new_platforms: []) + @name = name + @platforms = platforms + @locked_version = locked_specs.version_for(name) + @unlock = unlock + @dependency = dependency || Dependency.new(name, @locked_version) + @platforms |= [Gem::Platform::RUBY] if @dependency.default_force_ruby_platform + @top_level = !dependency.nil? + @prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore + @prefer_local = prefer_local + @new_platforms = new_platforms + end + + def platform_specs(specs) + platforms.map do |platform| + prefer_locked = @new_platforms.include?(platform) ? false : !unlock? + MatchPlatform.select_best_platform_match(specs, platform, prefer_locked: prefer_locked) + end + end + + def to_s + @name.delete("\0") + end + + def root? + false + end + + def top_level? + @top_level + end + + def meta? + @name.end_with?("\0") + end + + def ==(other) + self.class == other.class && @name == other.name + end + + def hash + @name.hash + end + + def unlock? + @unlock == true || @unlock.include?(name) + end + + def ignores_prereleases? + @prerelease == :ignore + end + + def prerelease_specified? + @prerelease == :consider_first + end + + def consider_prereleases! + @prerelease = :consider_last + end + + def prefer_local? + @prefer_local + end + + def consider_remote_versions! + @prefer_local = false + end + + def force_ruby_platform? + @dependency.force_ruby_platform + end + + def current_platform? + @dependency.current_platform? + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/root.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/root.rb new file mode 100644 index 00000000..e5eb634f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/root.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "package" + +module Bundler + class Resolver + # + # Represents the Gemfile from the resolver's perspective. It's the root + # package and Gemfile entries depend on it. + # + class Root < Package + def initialize(name) + @name = name + end + + def meta? + true + end + + def root? + true + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/spec_group.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/spec_group.rb new file mode 100644 index 00000000..ac6ba86c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/spec_group.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class SpecGroup + attr_reader :specs + + def initialize(specs) + @specs = specs + end + + def empty? + @specs.empty? + end + + def name + @name ||= exemplary_spec.name + end + + def version + @version ||= exemplary_spec.version + end + + def source + @source ||= exemplary_spec.source + end + + def to_specs(force_ruby_platform, most_specific_locked_platform) + @specs.map do |s| + lazy_spec = LazySpecification.from_spec(s) + lazy_spec.force_ruby_platform = force_ruby_platform + lazy_spec.most_specific_locked_platform = most_specific_locked_platform + lazy_spec + end + end + + def to_s + sorted_spec_names.join(", ") + end + + def dependencies + @dependencies ||= @specs.flat_map(&:expanded_dependencies).uniq.sort + end + + def ==(other) + sorted_spec_names == other.sorted_spec_names + end + + def merge(other) + return false unless equivalent?(other) + + @specs |= other.specs + + true + end + + protected + + def sorted_spec_names + @specs.map(&:full_name).sort + end + + private + + def equivalent?(other) + name == other.name && version == other.version && source == other.source && dependencies == other.dependencies + end + + def exemplary_spec + @specs.first + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/resolver/strategy.rb b/bin/gems/bundler-4.0.21/lib/bundler/resolver/strategy.rb new file mode 100644 index 00000000..7519d389 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/resolver/strategy.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class Strategy + def initialize(source) + @source = source + @package_priority_cache = {} + end + + def next_package_and_version(unsatisfied) + package, range = next_term_to_try_from(unsatisfied) + + [package, most_preferred_version_of(package, range).first] + end + + private + + def next_term_to_try_from(unsatisfied) + unsatisfied.min_by do |package, range| + @package_priority_cache[[package, range]] ||= begin + matching_versions = @source.versions_for(package, range) + higher_versions = @source.versions_for(package, range.upper_invert) + + [matching_versions.count <= 1 ? 0 : 1, higher_versions.count] + end + end + end + + def most_preferred_version_of(package, range) + versions = @source.versions_for(package, range) + + # Conditional avoids (among other things) calling + # sort_versions_by_preferred with the root package + if versions.size > 1 + @source.sort_versions_by_preferred(package, versions) + else + versions + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/retry.rb b/bin/gems/bundler-4.0.21/lib/bundler/retry.rb new file mode 100644 index 00000000..49b0f638 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/retry.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module Bundler + # General purpose class for retrying code that may fail + class Retry + attr_accessor :name, :total_runs, :current_run + + class << self + attr_accessor :default_base_delay + + def default_attempts + default_retries + 1 + end + alias_method :attempts, :default_attempts + + def default_retries + Bundler.settings[:retry] + end + end + + # Set default base delay for exponential backoff + self.default_base_delay = 1.0 + + def initialize(name, exceptions = nil, retries = self.class.default_retries, opts = {}) + @name = name + @retries = retries + @exceptions = Array(exceptions) || [] + @total_runs = @retries + 1 # will run once, then upto attempts.times + @base_delay = opts[:base_delay] || self.class.default_base_delay + @max_delay = opts[:max_delay] || 60.0 + @jitter = opts[:jitter] || 0.5 + end + + def attempt(&block) + @current_run = 0 + @failed = false + @error = nil + run(&block) while keep_trying? + @result + end + alias_method :attempts, :attempt + + private + + def run(&block) + @failed = false + @current_run += 1 + @result = block.call + rescue StandardError => e + fail_attempt(e) + end + + def fail_attempt(e) + @failed = true + if last_attempt? || @exceptions.any? {|k| e.is_a?(k) } + Bundler.ui.info "" unless Bundler.ui.debug? + raise e + end + if name + Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this + Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", true + end + backoff_sleep if @base_delay > 0 + true + end + + def backoff_sleep + # Exponential backoff: delay = base_delay * 2^(attempt - 1) + # Add jitter to prevent thundering herd: random value between 0 and jitter seconds + delay = @base_delay * (2**(@current_run - 1)) + delay = [@max_delay, delay].min + jitter_amount = rand * @jitter + total_delay = delay + jitter_amount + Bundler.ui.debug "Sleeping for #{total_delay.round(2)} seconds before retry" + sleep(total_delay) + end + + def sleep(duration) + Kernel.sleep(duration) + end + + def keep_trying? + return true if current_run.zero? + return false if last_attempt? + true if @failed + end + + def last_attempt? + current_run >= total_runs + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ruby_dsl.rb b/bin/gems/bundler-4.0.21/lib/bundler/ruby_dsl.rb new file mode 100644 index 00000000..5e52f38c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ruby_dsl.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module Bundler + module RubyDsl + def ruby(*ruby_version) + options = ruby_version.pop if ruby_version.last.is_a?(Hash) + ruby_version.flatten! + + if options + patchlevel = options[:patchlevel] + engine = options[:engine] + engine_version = options[:engine_version] + + raise GemfileError, "Please define :engine_version" if engine && engine_version.nil? + raise GemfileError, "Please define :engine" if engine_version && engine.nil? + + if options[:file] + raise GemfileError, "Do not pass version argument when using :file option" unless ruby_version.empty? + ruby_version << normalize_ruby_file(options[:file]) + end + + if engine == "ruby" && engine_version && ruby_version != Array(engine_version) + raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" + end + end + + @ruby_version = RubyVersion.new(ruby_version, patchlevel, engine, engine_version) + end + + # Support the various file formats found in .ruby-version files. + # + # 3.2.2 + # ruby-3.2.2 + # + # Also supports .tool-versions files for asdf. Lines not starting with "ruby" are ignored. + # + # ruby 2.5.1 # comment is ignored + # ruby 2.5.1# close comment and extra spaces doesn't confuse + # + # Intentionally does not support `3.2.1@gemset` since rvm recommends using .ruby-gemset instead + # + # Loads the file relative to the dirname of the Gemfile itself. + def normalize_ruby_file(filename) + file_content = Bundler.read_file(gemfile.dirname.join(filename)) + # match "ruby-3.2.2", ruby = "3.2.2", ruby = '3.2.2' or "ruby 3.2.2" capturing version string up to the first space or comment + version_match = /^ # Start of line + ruby # Literal "ruby" + [\s-]* # Optional whitespace or hyphens (for "ruby-3.2.2" format) + (?:=\s*)? # Optional equals sign with whitespace (for ruby = "3.2.2" format) + (?: + "([^"]+)" # Double quoted version + | + '([^']+)' # Single quoted version + | + ([^\s#"']+) # Unquoted version + ) + /x.match(file_content) + if version_match + version_match[1] || version_match[2] || version_match[3] + else + file_content.strip + end + rescue Errno::ENOENT + raise GemfileError, "Could not find version file #{filename}" + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ruby_version.rb b/bin/gems/bundler-4.0.21/lib/bundler/ruby_version.rb new file mode 100644 index 00000000..7f60dde4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ruby_version.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +module Bundler + class RubyVersion + attr_reader :versions, + :patchlevel, + :engine, + :engine_versions, + :gem_version, + :engine_gem_version + + def initialize(versions, patchlevel, engine, engine_version) + # The parameters to this method must satisfy the + # following constraints, which are verified in + # the DSL: + # + # * If an engine is specified, an engine version + # must also be specified + # * If an engine version is specified, an engine + # must also be specified + # * If the engine is "ruby", the engine version + # must not be specified, or the engine version + # specified must match the version. + + @versions = Array(versions).map do |v| + normalized_v = normalize_version(v) + + unless Gem::Requirement::PATTERN.match?(normalized_v) + raise InvalidArgumentError, "#{v} is not a valid requirement on the Ruby version" + end + + op, v = Gem::Requirement.parse(normalized_v) + op == "=" ? v.to_s : "#{op} #{v}" + end + + @gem_version = Gem::Requirement.create(@versions.first).requirements.first.last + @input_engine = engine&.to_s + @engine = engine&.to_s || "ruby" + @engine_versions = (engine_version && Array(engine_version)) || @versions + @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last + @patchlevel = patchlevel || (@gem_version.prerelease? ? "-1" : nil) + end + + def to_s(versions = self.versions) + output = String.new("ruby #{versions_string(versions)}") + output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" + + output + end + + # @private + PATTERN = / + ruby\s + (\d+\.\d+\.\d+(?:\.\S+)?) # ruby version + (?:p(-?\d+))? # optional patchlevel + (?:\s\((\S+)\s(.+)\))? # optional engine info + /xo + + # Returns a RubyVersion from the given string. + # @param [String] the version string to match. + # @return [RubyVersion,Nil] The version if the string is a valid RubyVersion + # description, and nil otherwise. + def self.from_string(string) + new($1, $2, $3, $4) if string =~ PATTERN + end + + def single_version_string + to_s(gem_version) + end + + def ==(other) + versions == other.versions && + engine == other.engine && + engine_versions == other.engine_versions + end + + def host + @host ||= [ + RbConfig::CONFIG["host_cpu"], + RbConfig::CONFIG["host_vendor"], + RbConfig::CONFIG["host_os"], + ].join("-") + end + + # Returns a tuple of these things: + # [diff, this, other] + # The priority of attributes are + # 1. engine + # 2. ruby_version + # 3. engine_version + def diff(other) + raise ArgumentError, "Can only diff with a RubyVersion, not a #{other.class}" unless other.is_a?(RubyVersion) + if engine != other.engine && @input_engine + [:engine, engine, other.engine] + elsif versions.empty? || !matches?(versions, other.gem_version) + [:version, versions_string(versions), versions_string(other.versions)] + elsif @input_engine && !matches?(engine_versions, other.engine_gem_version) + [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)] + elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) + [:patchlevel, patchlevel, other.patchlevel] + end + end + + def versions_string(versions) + Array(versions).join(", ") + end + + def self.system + ruby_engine = RUBY_ENGINE.dup + ruby_version = Gem.ruby_version.to_s + ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup + patchlevel = RUBY_PATCHLEVEL.to_s + + @system ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) + end + + private + + # Ruby's official preview version format uses a `-`: Example: 3.3.0-preview2 + # However, RubyGems recognizes preview version format with a `.`: Example: 3.3.0.preview2 + # Returns version string after replacing `-` with `.` + def normalize_version(version) + version.tr("-", ".") + end + + def matches?(requirements, version) + # Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head + return requirements == version if requirements.to_s == "-1" || version.to_s == "-1" + + Array(requirements).all? do |requirement| + Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.create(version)) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/rubygems_ext.rb b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_ext.rb new file mode 100644 index 00000000..4ad2bdf4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_ext.rb @@ -0,0 +1,503 @@ +# frozen_string_literal: true + +require "rubygems" unless defined?(Gem) + +# We can't let `Gem::Source` be autoloaded in the `Gem::Specification#source` +# redefinition below, so we need to load it upfront. The reason is that if +# Bundler monkeypatches are loaded before RubyGems activates an executable (for +# example, through `ruby -rbundler -S irb`), gem activation might end up calling +# the redefined `Gem::Specification#source` and triggering the `Gem::Source` +# autoload. That would result in requiring "rubygems/source" inside another +# require, which would trigger a monitor error and cause the `autoload` to +# eventually fail. A better solution is probably to completely avoid autoloading +# `Gem::Source` from the redefined `Gem::Specification#source`. +require "rubygems/source" + +module Gem + # Can be removed once RubyGems 3.5.11 support is dropped + unless Gem.respond_to?(:freebsd_platform?) + def self.freebsd_platform? + RbConfig::CONFIG["host_os"].to_s.include?("bsd") + end + end + + # Can be removed once RubyGems 3.5.18 support is dropped + unless Gem.respond_to?(:open_file_with_lock) + class << self + remove_method :open_file_with_flock if Gem.respond_to?(:open_file_with_flock) + + def open_file_with_flock(path, &block) + # read-write mode is used rather than read-only in order to support NFS + mode = IO::RDWR | IO::APPEND | IO::CREAT | IO::BINARY + mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE) + + File.open(path, mode) do |io| + begin + io.flock(File::LOCK_EX) + rescue Errno::ENOSYS, Errno::ENOTSUP + end + yield io + end + end + + def open_file_with_lock(path, &block) + file_lock = "#{path}.lock" + open_file_with_flock(file_lock, &block) + ensure + FileUtils.rm_f file_lock + end + end + end + + require "rubygems/platform" + + class Platform + # Can be removed once RubyGems 3.6.9 support is dropped + unless respond_to?(:generic) + JAVA = Gem::Platform.new("java") # :nodoc: + MSWIN = Gem::Platform.new("mswin32") # :nodoc: + MSWIN64 = Gem::Platform.new("mswin64") # :nodoc: + MINGW = Gem::Platform.new("x86-mingw32") # :nodoc: + X64_MINGW_LEGACY = Gem::Platform.new("x64-mingw32") # :nodoc: + X64_MINGW = Gem::Platform.new("x64-mingw-ucrt") # :nodoc: + UNIVERSAL_MINGW = Gem::Platform.new("universal-mingw") # :nodoc: + WINDOWS = [MSWIN, MSWIN64, UNIVERSAL_MINGW].freeze # :nodoc: + X64_LINUX = Gem::Platform.new("x86_64-linux") # :nodoc: + X64_LINUX_MUSL = Gem::Platform.new("x86_64-linux-musl") # :nodoc: + + GENERICS = [JAVA, *WINDOWS].freeze # :nodoc: + private_constant :GENERICS + + GENERIC_CACHE = GENERICS.each_with_object({}) {|g, h| h[g] = g } # :nodoc: + private_constant :GENERIC_CACHE + + class << self + ## + # Returns the generic platform for the given platform. + + def generic(platform) + return Gem::Platform::RUBY if platform.nil? || platform == Gem::Platform::RUBY + + GENERIC_CACHE[platform] ||= begin + found = GENERICS.find do |match| + platform === match + end + found || Gem::Platform::RUBY + end + end + + ## + # Returns the platform specificity match for the given spec platform and user platform. + + def platform_specificity_match(spec_platform, user_platform) + return -1 if spec_platform == user_platform + return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY + + os_match(spec_platform, user_platform) + + cpu_match(spec_platform, user_platform) * 10 + + version_match(spec_platform, user_platform) * 100 + end + + ## + # Sorts and filters the best platform match for the given matching specs and platform. + + def sort_and_filter_best_platform_match(matching, platform) + return matching if matching.one? + + exact = matching.select {|spec| spec.platform == platform } + return exact if exact.any? + + sorted_matching = sort_best_platform_match(matching, platform) + exemplary_spec = sorted_matching.first + + sorted_matching.take_while {|spec| same_specificity?(platform, spec, exemplary_spec) && same_deps?(spec, exemplary_spec) } + end + + ## + # Sorts the best platform match for the given matching specs and platform. + + def sort_best_platform_match(matching, platform) + matching.sort_by.with_index do |spec, i| + [ + platform_specificity_match(spec.platform, platform), + i, # for stable sort + ] + end + end + + private + + def same_specificity?(platform, spec, exemplary_spec) + platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform) + end + + def same_deps?(spec, exemplary_spec) + spec.required_ruby_version == exemplary_spec.required_ruby_version && + spec.required_rubygems_version == exemplary_spec.required_rubygems_version && + spec.dependencies.sort == exemplary_spec.dependencies.sort + end + + def os_match(spec_platform, user_platform) + if spec_platform.os == user_platform.os + 0 + else + 1 + end + end + + def cpu_match(spec_platform, user_platform) + if spec_platform.cpu == user_platform.cpu + 0 + elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm") + 0 + elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal" + 1 + else + 2 + end + end + + def version_match(spec_platform, user_platform) + if spec_platform.version == user_platform.version + 0 + elsif spec_platform.version.nil? + 1 + else + 2 + end + end + end + + end + end + + require "rubygems/specification" + + # Can be removed once RubyGems 3.5.14 support is dropped + VALIDATES_FOR_RESOLUTION = Specification.new.respond_to?(:validate_for_resolution).freeze + + class Specification + # Can be removed once RubyGems 3.5.15 support is dropped + correct_array_attributes = @@default_value.select {|_k,v| v.is_a?(Array) }.keys + unless @@array_attributes == correct_array_attributes + @@array_attributes = correct_array_attributes # rubocop:disable Style/ClassVars + end + + require_relative "match_metadata" + require_relative "match_platform" + + include ::Bundler::MatchMetadata + + attr_accessor :remote, :relative_loaded_from + + module AllowSettingSource + attr_writer :source + + def source + (defined?(@source) && @source) || super + end + end + + prepend AllowSettingSource + + alias_method :rg_full_gem_path, :full_gem_path + alias_method :rg_loaded_from, :loaded_from + + def full_gem_path + if source.respond_to?(:root) + File.expand_path(File.dirname(loaded_from), source.root) + else + rg_full_gem_path + end + end + + def loaded_from + if relative_loaded_from + source.path.join(relative_loaded_from).to_s + else + rg_loaded_from + end + end + + def load_paths + full_require_paths + end + + alias_method :rg_extension_dir, :extension_dir + def extension_dir + # following instance variable is already used in original method + # and that is the reason to prefix it with bundler_ and add rubocop exception + @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) # rubocop:disable Naming/MemoizedInstanceVariableName + unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") + File.expand_path(File.join(extensions_dir, unique_extension_dir)) + else + rg_extension_dir + end + end + + # Can be removed once RubyGems 3.5.21 support is dropped + remove_method :gem_dir if method_defined?(:gem_dir, false) + + def gem_dir + full_gem_path + end + + def insecurely_materialized? + false + end + + def groups + @groups ||= [] + end + + def git_version + return unless loaded_from && source.is_a?(Bundler::Source::Git) + " #{source.revision[0..6]}" + end + + def to_gemfile(path = nil) + gemfile = String.new("source 'https://rubygems.org'\n") + gemfile << dependencies_to_gemfile(nondevelopment_dependencies) + unless development_dependencies.empty? + gemfile << "\n" + gemfile << dependencies_to_gemfile(development_dependencies, :development) + end + gemfile + end + + def nondevelopment_dependencies + dependencies - development_dependencies + end + + def installation_missing? + !default_gem? && !File.directory?(full_gem_path) + end + + def lock_name + @lock_name ||= name_tuple.lock_name + end + + unless VALIDATES_FOR_RESOLUTION + def validate_for_resolution + SpecificationPolicy.new(self).validate_for_resolution + end + end + + if Gem.rubygems_version < Gem::Version.new("3.5.22") + module FixPathSourceMissingExtensions + def missing_extensions? + return false if %w[Bundler::Source::Path Bundler::Source::Gemspec].include?(source.class.name) + + super + end + end + + prepend FixPathSourceMissingExtensions + end + + private + + def dependencies_to_gemfile(dependencies, group = nil) + gemfile = String.new + if dependencies.any? + gemfile << "group :#{group} do\n" if group + dependencies.each do |dependency| + gemfile << " " if group + gemfile << %(gem "#{dependency.name}") + req = dependency.requirements_list.first + gemfile << %(, "#{req}") if req + gemfile << "\n" + end + gemfile << "end\n" if group + end + gemfile + end + end + + unless VALIDATES_FOR_RESOLUTION + class SpecificationPolicy + def validate_for_resolution + validate_required! + end + end + end + + module BetterPermissionError + def data + super + rescue Errno::EACCES + raise Bundler::PermissionError.new(loaded_from, :read) + end + end + + require "rubygems/stub_specification" + + class StubSpecification + prepend BetterPermissionError + end + + class Dependency + require_relative "force_platform" + + include ::Bundler::ForcePlatform + + attr_reader :force_ruby_platform + + attr_accessor :source, :groups + + alias_method :eql?, :== + + unless method_defined?(:encode_with, false) + def encode_with(coder) + [:@name, :@requirement, :@type, :@prerelease, :@version_requirements].each do |ivar| + coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) + end + end + end + + def to_lock + out = String.new(" #{name}") + unless requirement.none? + reqs = requirement.requirements.map {|o, v| "#{o} #{v}" }.sort.reverse + out << " (#{reqs.join(", ")})" + end + out + end + + if Gem.rubygems_version < Gem::Version.new("3.5.22") + module FilterIgnoredSpecs + def matching_specs(platform_only = false) + super.reject(&:ignored?) + end + end + + prepend FilterIgnoredSpecs + end + end + + # On universal Rubies, resolve the "universal" arch to the real CPU arch, without changing the extension directory. + class BasicSpecification + if /^universal\.(?.*?)-/ =~ (CROSS_COMPILING || RUBY_PLATFORM) + local_platform = Platform.local + if local_platform.cpu == "universal" + ORIGINAL_LOCAL_PLATFORM = local_platform.to_s.freeze + + local_platform.cpu = if arch == "arm64e" # arm64e is only permitted for Apple system binaries + "arm64" + else + arch + end + + def extensions_dir + @extensions_dir ||= + Gem.default_ext_dir_for(base_dir) || File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM, Gem.extension_api_version) + end + end + end + + # Can be removed once RubyGems 3.5.22 support is dropped + unless new.respond_to?(:ignored?) + def ignored? + return @ignored unless @ignored.nil? + + @ignored = missing_extensions? + end + end + + # Can be removed once RubyGems 3.6.9 support is dropped + unless new.respond_to?(:installable_on_platform?) + include(::Bundler::MatchPlatform) + end + end + + require "rubygems/name_tuple" + + class NameTuple + # Versions of RubyGems before about 3.5.0 don't to_s the platform. + unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String) + alias_method :initialize_with_platform, :initialize + + def initialize(name, version, platform = Gem::Platform::RUBY) + if Gem::Platform === platform + initialize_with_platform(name, version, platform.to_s) + else + initialize_with_platform(name, version, platform) + end + end + end + + def lock_name + if platform == Gem::Platform::RUBY + "#{name} (#{version})" + else + "#{name} (#{version}-#{platform})" + end + end + end + + unless Gem.rubygems_version >= Gem::Version.new("3.5.19") + class Resolver::ActivationRequest + remove_method :installed? + + def installed? + case @spec + when Gem::Resolver::VendorSpecification then + true + else + this_spec = full_spec + + Gem::Specification.any? do |s| + s == this_spec && s.base_dir == this_spec.base_dir + end + end + end + end + end + + unless Gem.rubygems_version >= Gem::Version.new("3.6.7") + module UnfreezeCompactIndexParsedResponse + def parse(line) + version, platform, dependencies, requirements = super + [version, platform, dependencies.frozen? ? dependencies.dup : dependencies, requirements.frozen? ? requirements.dup : requirements] + end + end + + Resolver::APISet::GemParser.prepend(UnfreezeCompactIndexParsedResponse) + end + + # RubyGems before 4.0.13 split compact index dependency/requirement entries + # on every colon, which mangles metadata values that contain colons such as + # the `created_at` timestamps the cooldown feature relies on. Split only on + # the first colon so those values survive on older RubyGems. + # + # The module is defined unconditionally so it stays testable on any RubyGems, + # but only prepended when the host RubyGems still has the buggy behavior. + module SplitCompactIndexEntryOnFirstColon + private + + def parse_dependency(string) + dependency = string.split(":", 2) + dependency[-1] = dependency[-1].split("&") if dependency.size > 1 + dependency[0] = -dependency[0] + dependency + end + end + + unless Gem.rubygems_version >= Gem::Version.new("4.0.13") + Resolver::APISet::GemParser.prepend(SplitCompactIndexEntryOnFirstColon) + end + + if Gem.rubygems_version < Gem::Version.new("3.6.0") + class Package; end + require "rubygems/package/tar_reader" + require "rubygems/package/tar_reader/entry" + + module FixFullNameEncoding + def full_name + super.force_encoding(Encoding::UTF_8) + end + end + + Package::TarReader::Entry.prepend(FixFullNameEncoding) + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/rubygems_gem_installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_gem_installer.rb new file mode 100644 index 00000000..1c7398ac --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_gem_installer.rb @@ -0,0 +1,206 @@ +# frozen_string_literal: true + +require "rubygems/installer" + +module Bundler + class RubyGemsGemInstaller < Gem::Installer + # Cap how many jobserver slots a single gem's `make` may grab so that one + # gem with many recipes doesn't starve the others sharing the pool. Beyond + # a handful of jobs the extra parallelism rarely pays off in practice. + MAX_JOBS_PER_GEM = 3 + + def check_executable_overwrite(filename) + # Bundler needs to install gems regardless of binstub overwriting + end + + def install + pre_install_checks + + run_pre_install_hooks + + spec.loaded_from = spec_file + + # Completely remove any previous gem files + strict_rm_rf gem_dir + strict_rm_rf spec.extension_dir + + SharedHelpers.filesystem_access(gem_dir, :create) do + FileUtils.mkdir_p gem_dir + end + + SharedHelpers.filesystem_access(gem_dir, :write) do + extract_files + end + + build_extensions if spec.extensions.any? + write_build_info_file + run_post_build_hooks + + SharedHelpers.filesystem_access(bin_dir, :write) do + generate_bin + end + + generate_plugins + + write_spec + + SharedHelpers.filesystem_access("#{gem_home}/cache", :write) do + write_cache_file + end + + say spec.post_install_message unless spec.post_install_message.nil? + + run_post_install_hooks + + spec + end + + if Bundler.rubygems.provides?("< 3.5") + def pre_install_checks + super + rescue Gem::FilePermissionError + # Ignore permission checks in RubyGems. Instead, go on, and try to write + # for real. We properly handle permission errors when they happen. + nil + end + end + + def ensure_writable_dir(dir) + super + rescue Gem::FilePermissionError + # Ignore permission checks in RubyGems. Instead, go on, and try to write + # for real. We properly handle permission errors when they happen. + nil + end + + def generate_plugins + return unless Gem::Installer.method_defined?(:generate_plugins, false) + + ensure_writable_dir @plugins_dir + + if spec.plugins.empty? + remove_plugins_for(spec, @plugins_dir) + else + regenerate_plugins_for(spec, @plugins_dir) + end + end + + if Bundler.rubygems.provides?("< 3.5.19") + def generate_bin_script(filename, bindir) + bin_script_path = File.join bindir, formatted_program_filename(filename) + + Gem.open_file_with_lock(bin_script_path) do + require "fileutils" + FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers + + File.open(bin_script_path, "wb", 0o755) do |file| + file.write app_script_text(filename) + file.chmod(options[:prog_mode] || 0o755) + end + end + + verbose bin_script_path + + generate_windows_script filename, bindir + end + end + + def build_jobs + @jobserver_read_io&.read_nonblock(MAX_JOBS_PER_GEM, @jobserver_tokens) + acquired_jobs = @jobserver_tokens.empty? ? nil : @jobserver_tokens.size + + acquired_jobs || Bundler.settings[:jobs] || super + rescue IO::WaitReadable, EOFError + 1 + end + + def build_extensions + @jobserver_tokens = +"" + @jobserver_read_io, @jobserver_write_io = connect_to_jobserver + + extension_cache_path = options[:bundler_extension_cache_path] + extension_dir = spec.extension_dir + unless extension_cache_path && extension_dir + prepare_extension_build(extension_dir) + return super + end + + build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) + if build_complete && !options[:force] + SharedHelpers.filesystem_access(File.dirname(extension_dir)) do |p| + FileUtils.mkpath p + end + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_cache_path, extension_dir + end + else + prepare_extension_build(extension_dir) + super + SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_dir, extension_cache_path + end + end + ensure + unless @jobserver_tokens.empty? + @jobserver_write_io.write(@jobserver_tokens) + @jobserver_write_io.flush + end + end + + def spec + if Bundler.rubygems.provides?("< 3.3.12") # RubyGems implementation rescues and re-raises errors before 3.3.12 and we don't want that + @package.spec + else + super + end + end + + def gem_checksum + Checksum.from_gem_package(@package) + end + + private + + def connect_to_jobserver + return unless ENV["MAKEFLAGS"] + # We append our own --jobserver-auth, so read the last one. Otherwise a + # parent jobserver's descriptors (e.g. `bundle install` run under + # `make -j`) would be picked up instead of the pool ParallelInstaller created. + read_fd, write_fd = ENV["MAKEFLAGS"].scan(/--jobserver-auth=(\d+),(\d+)/).last + + return unless read_fd && write_fd + + # Pass explicit modes. On POSIX, IO.new detects the descriptor's access + # mode, but on Windows it can't, so the write end would default to read + # mode and raise "IOError: not opened for writing" when releasing slots. + [IO.new(read_fd.to_i, "r", autoclose: false), IO.new(write_fd.to_i, "w", autoclose: false)] + end + + def prepare_extension_build(extension_dir) + SharedHelpers.filesystem_access(extension_dir, :create) do + FileUtils.mkdir_p extension_dir + end + end + + def strict_rm_rf(dir) + return unless File.exist?(dir) + return if Dir.empty?(dir) + + parent = File.dirname(dir) + parent_st = File.stat(parent) + + if parent_st.world_writable? && !parent_st.sticky? + raise InsecureInstallPathError.new(spec.full_name, dir) + end + + begin + FileUtils.remove_entry_secure(dir) + rescue StandardError => e + raise unless File.exist?(dir) + + raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`") + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/rubygems_integration.rb b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_integration.rb new file mode 100644 index 00000000..e04ef232 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/rubygems_integration.rb @@ -0,0 +1,456 @@ +# frozen_string_literal: true + +require "rubygems" unless defined?(Gem) + +module Bundler + class RubygemsIntegration + require "monitor" + + EXT_LOCK = Monitor.new + + def initialize + @replaced_methods = {} + end + + def version + @version ||= Gem.rubygems_version + end + + def provides?(req_str) + Gem::Requirement.new(req_str).satisfied_by?(version) + end + + def build_args + require "rubygems/command" + Gem::Command.build_args + end + + def build_args=(args) + require "rubygems/command" + Gem::Command.build_args = args + end + + def set_target_rbconfig(path) + Gem.set_target_rbconfig(path) + end + + def loaded_specs(name) + Gem.loaded_specs[name] + end + + def mark_loaded(spec) + if spec.respond_to?(:activated=) + current = Gem.loaded_specs[spec.name] + current.activated = false if current + spec.activated = true + end + Gem.loaded_specs[spec.name] = spec + end + + def validate(spec) + Bundler.ui.silence { spec.validate_for_resolution } + rescue Gem::InvalidSpecificationException => e + error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \ + "The validation error was '#{e.message}'\n" + raise Gem::InvalidSpecificationException.new(error_message) + rescue Errno::ENOENT + nil + end + + def stub_set_spec(stub, spec) + stub.instance_variable_set(:@spec, spec) + end + + def path(obj) + obj.to_s + end + + def ruby_engine + Gem.ruby_engine + end + + def read_binary(path) + Gem.read_binary(path) + end + + def inflate(obj) + Gem::Util.inflate(obj) + end + + def gem_dir + Gem.dir + end + + def gem_bindir + Gem.bindir + end + + def user_home + Gem.user_home + end + + def gem_path + Gem.path + end + + def reset + Gem::Specification.reset + end + + def post_reset_hooks + Gem.post_reset_hooks + end + + def suffix_pattern + Gem.suffix_pattern + end + + def gem_cache + gem_path.map {|p| File.expand_path("cache", p) } + end + + def spec_cache_dirs + @spec_cache_dirs ||= begin + dirs = gem_path.map {|dir| File.join(dir, "specifications") } + dirs << Gem.spec_cache_dir + dirs.uniq.select {|dir| File.directory? dir } + end + end + + def marshal_spec_dir + Gem::MARSHAL_SPEC_DIR + end + + def clear_paths + Gem.clear_paths + end + + def bin_path(gem, bin, ver) + Gem.bin_path(gem, bin, ver) + end + + def loaded_gem_paths + loaded_gem_paths = Gem.loaded_specs.map {|_, s| s.full_require_paths } + loaded_gem_paths.flatten + end + + def ui=(obj) + Gem::DefaultUserInteraction.ui = obj + end + + def ext_lock + EXT_LOCK + end + + def spec_from_gem(path) + require "rubygems/package" + Gem::Package.new(path).spec + end + + def build_gem(gem_dir, spec) + build(spec) + end + + def security_policy_keys + %w[High Medium Low AlmostNo No].map {|level| "#{level}Security" } + end + + def security_policies + @security_policies ||= begin + require "rubygems/security" + Gem::Security::Policies + rescue LoadError, NameError + {} + end + end + + def reverse_rubygems_kernel_mixin + # Disable rubygems' gem activation system + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + [::Kernel.singleton_class, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + redefine_method(k, :require, k.instance_method(:gem_original_require)) + end + end + end + end + + def replace_gem(specs_by_name) + executables = nil + + [::Kernel.singleton_class, ::Kernel].each do |kernel_class| + redefine_method(kernel_class, :gem) do |dep, *reqs| + if executables&.include?(File.basename(caller_locations(1, 1).first.path)) + break + end + + reqs.pop if reqs.last.is_a?(Hash) + + unless dep.respond_to?(:name) && dep.respond_to?(:requirement) + dep = Gem::Dependency.new(dep, reqs) + end + + if spec = specs_by_name[dep.name] + return true if dep.matches_spec?(spec) + end + + message = if spec.nil? + target_file = begin + Bundler.default_gemfile.basename + rescue GemfileNotFound + "inline Gemfile" + end + "#{dep.name} is not part of the bundle." \ + " Add it to your #{target_file}." + else + "can't activate #{dep}, already activated #{spec.full_name}. " \ + "Make sure all dependencies are added to Gemfile." + end + + e = Gem::LoadError.new(message) + e.name = dep.name + e.requirement = dep.requirement + raise e + end + end + end + + # Used to give better error messages when activating specs outside of the current bundle + def replace_bin_path(specs_by_name) + redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args| + exec_name = args.first + raise ArgumentError, "you must supply exec_name" unless exec_name + + spec_with_name = specs_by_name[gem_name] + matching_specs_by_exec_name = specs_by_name.values.select {|s| s.executables.include?(exec_name) } + spec = matching_specs_by_exec_name.delete(spec_with_name) + + unless spec || !matching_specs_by_exec_name.empty? + message = "can't find executable #{exec_name} for gem #{gem_name}" + if spec_with_name.nil? + message += ". #{gem_name} is not currently included in the bundle, " \ + "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?" + end + raise Gem::Exception, message + end + + unless spec + spec = matching_specs_by_exec_name.shift + warn \ + "Bundler is using a binstub that was created for a different gem (#{spec.name}).\n" \ + "You should run `bundle binstub #{gem_name}` " \ + "to work around a system/bundle conflict." + end + + unless matching_specs_by_exec_name.empty? + conflicting_names = matching_specs_by_exec_name.map(&:name).join(", ") + warn \ + "The `#{exec_name}` executable in the `#{spec.name}` gem is being loaded, but it's also present in other gems (#{conflicting_names}).\n" \ + "If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub `).\n" \ + "If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names." + end + + spec + end + end + + # Replace or hook into RubyGems to provide a bundlerized view + # of the world. + def replace_entrypoints(specs) + specs_by_name = add_default_gems_to(specs) + + reverse_rubygems_kernel_mixin + begin + # bundled_gems only provide with Ruby 3.3 or later + require "bundled_gems" + rescue LoadError + else + Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require) + end + replace_gem(specs_by_name) + stub_rubygems(specs_by_name.values) + replace_bin_path(specs_by_name) + + Gem.clear_paths + end + + # Add default gems not already present in specs, and return them as a hash. + def add_default_gems_to(specs) + specs_by_name = specs.reduce({}) do |h, s| + h[s.name] = s + h + end + + Bundler.rubygems.default_stubs.each do |stub| + default_spec = stub.to_spec + default_spec_name = default_spec.name + next if specs_by_name.key?(default_spec_name) + + specs_by_name[default_spec_name] = default_spec + end + + specs_by_name + end + + def undo_replacements + @replaced_methods.each do |(sym, klass), method| + redefine_method(klass, sym, method) + end + post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ } + @replaced_methods.clear + end + + def redefine_method(klass, method, unbound_method = nil, &block) + visibility = method_visibility(klass, method) + begin + if (instance_method = klass.instance_method(method)) && method != :initialize + # doing this to ensure we also get private methods + klass.send(:remove_method, method) + end + rescue NameError + # method isn't defined + nil + end + @replaced_methods[[method, klass]] = instance_method + if unbound_method + klass.send(:define_method, method, unbound_method) + klass.send(visibility, method) + elsif block + klass.send(:define_method, method, &block) + klass.send(visibility, method) + end + end + + def method_visibility(klass, method) + if klass.private_method_defined?(method) + :private + elsif klass.protected_method_defined?(method) + :protected + else + :public + end + end + + def stub_rubygems(specs) + Gem::Specification.all = specs + + Gem.post_reset do + Gem::Specification.all = specs + end + + redefine_method(gem_class, :finish_resolve) do |*| + [] + end + + redefine_method(gem_class, :load_plugins) do |*| + load_plugin_files specs.flat_map(&:plugins) + end + end + + def plain_specs + Gem::Specification._all + end + + def plain_specs=(specs) + Gem::Specification.all = specs + end + + def fetch_specs(remote, name, fetcher) + require "rubygems/remote_fetcher" + path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz" + string = fetcher.fetch_path(path) + specs = Bundler.safe_load_marshal(string) + raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array) + specs + rescue Gem::RemoteFetcher::FetchError + # it's okay for prerelease to fail + raise unless name == "prerelease_specs" + end + + def fetch_all_remote_specs(remote, gem_remote_fetcher) + specs = fetch_specs(remote, "specs", gem_remote_fetcher) + pres = fetch_specs(remote, "prerelease_specs", gem_remote_fetcher) || [] + + specs.concat(pres) + end + + def download_gem(spec, uri, cache_dir, fetcher) + require "rubygems/remote_fetcher" + uri = Bundler.settings.mirror_for(uri) + redacted_uri = Gem::Uri.redact(uri) + + Bundler::Retry.new("download gem from #{redacted_uri}").attempts do + gem_file_name = spec.file_name + local_gem_path = File.join cache_dir, gem_file_name + return if File.exist? local_gem_path + + begin + remote_gem_path = uri + "gems/#{gem_file_name}" + + SharedHelpers.filesystem_access(local_gem_path) do + fetcher.cache_update_path remote_gem_path, local_gem_path + end + rescue Gem::RemoteFetcher::FetchError + raise if spec.original_platform == spec.platform + + original_gem_file_name = "#{spec.original_name}.gem" + raise if gem_file_name == original_gem_file_name + + gem_file_name = original_gem_file_name + retry + end + end + rescue Gem::RemoteFetcher::FetchError => e + raise Bundler::HTTPError, "Could not download gem from #{redacted_uri} due to underlying error <#{e.message}>" + end + + def build(spec, skip_validation = false) + require "rubygems/package" + Gem::Package.build(spec, skip_validation) + end + + def path_separator + Gem.path_separator + end + + def all_specs + SharedHelpers.feature_removed! "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs" + end + + def installed_specs + Gem::Specification.stubs.reject(&:default_gem?).map do |stub| + StubSpecification.from_stub(stub) + end + end + + def default_specs + Gem::Specification.default_stubs.map do |stub| + StubSpecification.from_stub(stub) + end + end + + def find_bundler(version) + find_name("bundler").find {|s| s.version.to_s == version.to_s } + end + + def find_name(name) + Gem::Specification.stubs_for(name).map(&:to_spec) + end + + def default_stubs + Gem::Specification.default_stubs("*.gemspec") + end + + private + + def gem_class + class << Gem; self; end + end + end + + def self.rubygems + @rubygems ||= RubygemsIntegration.new + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/runtime.rb b/bin/gems/bundler-4.0.21/lib/bundler/runtime.rb new file mode 100644 index 00000000..b76734f5 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/runtime.rb @@ -0,0 +1,331 @@ +# frozen_string_literal: true + +module Bundler + class Runtime + include SharedHelpers + + def initialize(root, definition) + @root = root + @definition = definition + end + + def setup(*groups) + @definition.ensure_equivalent_gemfile_and_lockfile + + # Has to happen first + clean_load_path + + specs = @definition.specs_for(groups) + + SharedHelpers.set_bundle_environment + Bundler.rubygems.replace_entrypoints(specs) + + # Activate the specs + load_paths = specs.map do |spec| + check_for_activated_spec!(spec) + + Bundler.rubygems.mark_loaded(spec) + spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } + end.reverse.flatten + + Gem.add_to_load_path(*load_paths) + + setup_manpath + + lock(preserve_unknown_sections: true) + + self + end + + def require(*groups) + groups.map!(&:to_sym) + groups = [:default] if groups.empty? + + dependencies = @definition.dependencies.select do |dep| + # Select the dependency if it is in any of the requested groups, and + # for the current platform, and matches the gem constraints. + (dep.groups & groups).any? && dep.should_include? + end + + Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE_ALL, dependencies) + + dependencies.each do |dep| + Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE, dep) + + # Loop through all the specified autorequires for the + # dependency. If there are none, use the dependency's name + # as the autorequire. + Array(dep.autorequire || dep.name).each do |file| + # Allow `require: true` as an alias for `require: ` + file = dep.name if file == true + required_file = file + begin + Kernel.require required_file + rescue LoadError => e + if dep.autorequire.nil? && e.path == required_file + if required_file.include?("-") + required_file = required_file.tr("-", "/") + retry + end + else + raise Bundler::GemRequireError.new e, + "There was an error while trying to load the gem '#{file}'." + end + rescue StandardError => e + raise Bundler::GemRequireError.new e, + "There was an error while trying to load the gem '#{file}'." + end + end + + Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE, dep) + end + + Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE_ALL, dependencies) + + dependencies + end + + def self.definition_method(meth) + define_method(meth) do + raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition + @definition.send(meth) + end + end + private_class_method :definition_method + + definition_method :requested_specs + definition_method :specs + definition_method :dependencies + definition_method :current_dependencies + definition_method :requires + + def lock(opts = {}) + return if @definition.no_resolve_needed? + @definition.lock(opts[:preserve_unknown_sections]) + end + + alias_method :gems, :specs + + def cache(custom_path = nil, local = false) + cache_path = Bundler.app_cache(custom_path) + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end unless File.exist?(cache_path) + + Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" + + specs_to_cache = if Bundler.settings[:cache_all_platforms] + @definition.resolve.materialized_for_all_platforms + else + begin + specs + rescue GemNotFound + if local + Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." + end + + raise + end + end + + specs_to_cache.each do |spec| + next if spec.name == "bundler" + + source = spec.source + next if source.is_a?(Source::Gemspec) + + if source.respond_to?(:migrate_cache) + source.migrate_cache(custom_path, local: local) + elsif source.respond_to?(:cache) + source.cache(spec, custom_path) + end + end + + SharedHelpers.glob_files_in_dir("*/.git", cache_path.to_s).each do |git_dir| + FileUtils.rm_rf(git_dir) + FileUtils.touch(File.expand_path("../.bundlecache", git_dir)) + end + + prune_cache(cache_path) unless Bundler.settings[:no_prune] + end + + def prune_cache(cache_path) + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end unless File.exist?(cache_path) + resolve = @definition.resolve + prune_gem_cache(resolve, cache_path) + prune_git_and_path_cache(resolve, cache_path) + end + + def clean(dry_run = false) + gem_bins = SharedHelpers.glob_files_in_dir("bin/*", Gem.dir) + git_dirs = SharedHelpers.glob_files_in_dir("bundler/gems/*", Gem.dir) + git_cache_dirs = SharedHelpers.glob_files_in_dir("cache/bundler/git/*", Gem.dir) + gem_dirs = SharedHelpers.glob_files_in_dir("gems/*", Gem.dir) + gem_files = SharedHelpers.glob_files_in_dir("cache/*.gem", Gem.dir) + gemspec_files = SharedHelpers.glob_files_in_dir("specifications/*.gemspec", Gem.dir) + extension_dirs = SharedHelpers.glob_files_in_dir("extensions/*/*/*", Gem.dir) + SharedHelpers.glob_files_in_dir("bundler/gems/extensions/*/*/*", Gem.dir) + spec_gem_paths = [] + # need to keep git sources around + spec_git_paths = @definition.spec_git_paths + spec_git_cache_dirs = [] + spec_gem_executables = [] + spec_cache_paths = [] + spec_gemspec_paths = [] + spec_extension_paths = [] + specs_to_keep = Bundler.rubygems.add_default_gems_to(specs).values + + current_bundler = Bundler.rubygems.find_bundler(Bundler.gem_version) + if current_bundler + specs_to_keep << current_bundler + end + + specs_to_keep.each do |spec| + spec_gem_paths << spec.full_gem_path + # need to check here in case gems are nested like for the rails git repo + md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) + spec_git_paths << md[1] if md + spec_gem_executables << spec.executables.collect do |executable| + e = "#{Bundler.rubygems.gem_bindir}/#{executable}" + [e, "#{e}.bat"] + end + spec_cache_paths << spec.cache_file + spec_gemspec_paths << spec.spec_file + spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) + spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) + end + spec_gem_paths.uniq! + spec_gem_executables.flatten! + + stale_gem_bins = gem_bins - spec_gem_executables + stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"] + stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs + stale_gem_dirs = gem_dirs - spec_gem_paths + stale_gem_files = gem_files - spec_cache_paths + stale_gemspec_files = gemspec_files - spec_gemspec_paths + stale_extension_dirs = extension_dirs - spec_extension_paths + + removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } + removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } + output = removed_stale_gem_dirs + removed_stale_git_dirs + + unless dry_run + stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files + stale_files.each do |file| + SharedHelpers.filesystem_access(File.dirname(file)) do |_p| + FileUtils.rm(file) if File.exist?(file) + end + end + + stale_dirs = stale_git_cache_dirs + stale_extension_dirs + stale_dirs.each do |stale_dir| + SharedHelpers.filesystem_access(stale_dir) do |dir| + FileUtils.rm_rf(dir) if File.exist?(dir) + end + end + end + + output + end + + private + + def prune_gem_cache(resolve, cache_path) + cached = SharedHelpers.glob_files_in_dir("*.gem", cache_path.to_s) + + cached = cached.delete_if do |path| + spec = Bundler.rubygems.spec_from_gem path + + resolve.any? do |s| + s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git) + end + end + + if cached.any? + Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}" + + cached.each do |path| + Bundler.ui.info " * #{File.basename(path)}" + + begin + File.delete(path) + rescue Errno::ENOENT + end + end + end + end + + def prune_git_and_path_cache(resolve, cache_path) + cached = SharedHelpers.glob_files_in_dir("*/.bundlecache", cache_path.to_s) + + cached = cached.delete_if do |path| + name = File.basename(File.dirname(path)) + + resolve.any? do |s| + source = s.source + source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name + end + end + + if cached.any? + Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}" + + cached.each do |path| + path = File.dirname(path) + Bundler.ui.info " * #{File.basename(path)}" + FileUtils.rm_rf(path) + end + end + end + + def setup_manpath + # Add man/ subdirectories from activated bundles to MANPATH for man(1) + manuals = $LOAD_PATH.filter_map do |path| + man_subdir = path.sub(/lib$/, "man") + man_subdir unless SharedHelpers.glob_files_in_dir("man?/", man_subdir).empty? + end + + return if manuals.empty? + Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( + ENV["MANPATH"] ? ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) : [""] + ).uniq.join(File::PATH_SEPARATOR) + end + + def remove_dir(dir, dry_run) + full_name = Pathname.new(dir).basename.to_s + + parts = full_name.split("-") + name = parts[0..-2].join("-") + version = parts.last + output = "#{name} (#{version})" + + if dry_run + Bundler.ui.info "Would have removed #{output}" + else + Bundler.ui.info "Removing #{output}" + FileUtils.rm_rf(dir) + end + + output + end + + def check_for_activated_spec!(spec) + return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) + return if activated_spec.version == spec.version + + suggestion = if activated_spec.default_gem? + "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ + " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." + else + "Prepending `bundle exec` to your command may solve this." + end + + e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ + "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" + e.name = spec.name + e.requirement = Gem::Requirement.new(spec.version.to_s) + raise e + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/safe_marshal.rb b/bin/gems/bundler-4.0.21/lib/bundler/safe_marshal.rb new file mode 100644 index 00000000..50aa0f60 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/safe_marshal.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + module SafeMarshal + ALLOWED_CLASSES = [ + Array, + FalseClass, + Gem::Specification, + Gem::Version, + Hash, + String, + Symbol, + Time, + TrueClass, + ].freeze + + ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed." + + PROC = proc do |object| + object.tap do + unless ALLOWED_CLASSES.include?(object.class) + raise TypeError, format(ERROR, object.class, ALLOWED_CLASSES.join(", ")) + end + end + end + + def self.proc + PROC + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/self_manager.rb b/bin/gems/bundler-4.0.21/lib/bundler/self_manager.rb new file mode 100644 index 00000000..aa948841 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/self_manager.rb @@ -0,0 +1,208 @@ +# frozen_string_literal: true + +module Bundler + # + # This class handles installing and switching to the version of bundler needed + # by an application. + # + class SelfManager + def restart_with_locked_bundler_if_needed + restart_version = find_restart_version + return unless restart_version && installed?(restart_version) + + restart_with(restart_version) + end + + def install_locked_bundler_and_restart_with_it_if_needed + restart_version = find_restart_version + return unless restart_version + + if restart_version == lockfile_version + Bundler.ui.info \ + "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \ + "Installing Bundler #{lockfile_version} and restarting using that version." + else + Bundler.ui.info \ + "Bundler #{current_version} is running, but your configuration was #{restart_version}. " \ + "Installing Bundler #{restart_version} and restarting using that version." + end + + install_and_restart_with(restart_version) + end + + def update_bundler_and_restart_with_it_if_needed(target, pre: false) + spec = resolve_update_version_from(target, pre: pre) + return unless spec + + version = spec.version + + Bundler.ui.info "Updating bundler to #{version}." + + install(spec) unless installed?(version) + + restart_with(version) + end + + private + + def install_and_restart_with(version) + requirement = Gem::Requirement.new(version) + spec = find_latest_matching_spec(requirement) + + if spec.nil? + Bundler.ui.warn "Your lockfile is locked to a version of bundler (#{lockfile_version}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}" + return + end + + install(spec) + rescue StandardError => e + Bundler.ui.trace e + Bundler.ui.warn "There was an error installing the locked bundler version (#{lockfile_version}), rerun with the `--verbose` flag for more details. Going on using bundler #{current_version}." + else + restart_with(version) + end + + def install(spec) + spec.source.download(spec) + spec.source.install(spec) + end + + def restart_with(version) + configured_gem_home = ENV["GEM_HOME"] + configured_orig_gem_home = ENV["BUNDLER_ORIG_GEM_HOME"] + configured_gem_path = ENV["GEM_PATH"] + configured_orig_gem_path = ENV["BUNDLER_ORIG_GEM_PATH"] + + argv0 = File.exist?($PROGRAM_NAME) ? $PROGRAM_NAME : Process.argv0 + cmd = [argv0, *ARGV] + unless File.executable?(argv0) + # Gem.ruby is quoted if it contains whitespace, so split it into argv + # elements to keep the quotes out of the exec'd command. + require "shellwords" + cmd.unshift(*Shellwords.split(Gem.ruby)) + end + + Bundler.with_original_env do + Kernel.exec( + { + "GEM_HOME" => configured_gem_home, + "BUNDLER_ORIG_GEM_HOME" => configured_orig_gem_home, + "GEM_PATH" => configured_gem_path, + "BUNDLER_ORIG_GEM_PATH" => configured_orig_gem_path, + "BUNDLER_VERSION" => version.to_s, + }, + *cmd + ) + end + end + + def needs_switching?(restart_version) + autoswitching_applies? && + released?(restart_version) && + !running?(restart_version) + end + + def autoswitching_applies? + (ENV["BUNDLER_VERSION"].nil? || ENV["BUNDLER_VERSION"].empty?) && + ruby_can_restart_with_same_arguments? && + lockfile_version + end + + def resolve_update_version_from(target, pre: false) + requirement = Gem::Requirement.new(target) + update_candidate = find_latest_matching_spec(requirement, pre: pre) + + if update_candidate.nil? + raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist" + end + + resolved_version = update_candidate.version + needs_update = requirement.specific? ? !running?(resolved_version) : running_older_than?(resolved_version) + + return unless needs_update + + update_candidate + end + + def local_specs + @local_specs ||= Bundler::Source::Rubygems.new("allow_local" => true).specs.select {|spec| spec.name == "bundler" } + end + + def remote_specs + @remote_specs ||= begin + source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org") + source.remote! + source.add_dependency_names("bundler") + source.specs.select(&:matches_current_metadata?) + end + end + + def find_latest_matching_spec(requirement, pre: false) + Bundler.configure + # A bare `bundle update --bundler` must stay on releases, like `gem update + # --system`, so only `--pre` or a prerelease requirement opts into one. + allow_prerelease = pre || requirement.prerelease? + + local_result = find_latest_matching_spec_from_collection(local_specs, requirement, allow_prerelease) + return local_result if local_result && requirement.specific? + + remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement, allow_prerelease) + return remote_result if local_result.nil? + + [local_result, remote_result].compact.max + end + + def find_latest_matching_spec_from_collection(specs, requirement, allow_prerelease) + specs = specs.reject {|spec| spec.version.prerelease? } unless allow_prerelease + + specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) } + end + + def running?(version) + version == current_version + end + + def running_older_than?(version) + current_version < version + end + + def released?(version) + !version.to_s.end_with?(".dev") + end + + def ruby_can_restart_with_same_arguments? + $PROGRAM_NAME != "-e" + end + + def installed?(restart_version) + Bundler.configure + + Bundler.rubygems.find_bundler(restart_version.to_s) + end + + def current_version + @current_version ||= Bundler.gem_version + end + + def lockfile_version + return @lockfile_version if defined?(@lockfile_version) + + parsed_version = Bundler::LockfileParser.bundled_with + @lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil + rescue ArgumentError + @lockfile_version = nil + end + + def find_restart_version + return unless SharedHelpers.in_bundle? + + configured_version = Bundler.settings[:version] + return if configured_version == "system" + + restart_version = configured_version == "lockfile" ? lockfile_version : Gem::Version.new(configured_version) + return unless needs_switching?(restart_version) + + restart_version + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/settings.rb b/bin/gems/bundler-4.0.21/lib/bundler/settings.rb new file mode 100644 index 00000000..d49cb9a0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/settings.rb @@ -0,0 +1,585 @@ +# frozen_string_literal: true + +module Bundler + class Settings + autoload :Mirror, File.expand_path("mirror", __dir__) + autoload :Mirrors, File.expand_path("mirror", __dir__) + autoload :Validator, File.expand_path("settings/validator", __dir__) + + BOOL_KEYS = %w[ + auto_install + cache_all + cache_all_platforms + clean + deployment + disable_checksum_validation + disable_exec_load + disable_local_branch_check + disable_local_revision_check + disable_shared_gems + disable_version_check + force_ruby_platform + frozen + gem.changelog + gem.coc + gem.mit + gem.bundle + git.allow_insecure + global_gem_cache + ignore_messages + init_gems_rb + inline + lockfile_checksums + no_install + no_prune + path.system + plugins + prefer_patch + silence_deprecations + silence_root_warning + update_requires_all_flag + verbose + ].freeze + + NUMBER_KEYS = %w[ + cooldown + jobs + redirect + retry + ssl_verify_mode + timeout + ].freeze + + ARRAY_KEYS = %w[ + only + with + without + ].freeze + + STRING_KEYS = %w[ + bin + cache_path + console + default_cli_command + gem.ci + gem.github_username + gem.linter + gem.rubocop + gem.test + gemfile + lockfile + path + shebang + simulate_version + system_bindir + trust-policy + version + ].freeze + + DEFAULT_CONFIG = { + "BUNDLE_SILENCE_DEPRECATIONS" => false, + "BUNDLE_DISABLE_VERSION_CHECK" => true, + "BUNDLE_PREFER_PATCH" => false, + "BUNDLE_REDIRECT" => 5, + "BUNDLE_RETRY" => 3, + "BUNDLE_TIMEOUT" => 10, + "BUNDLE_VERSION" => "lockfile", + "BUNDLE_LOCKFILE_CHECKSUMS" => true, + "BUNDLE_CACHE_ALL" => true, + "BUNDLE_PLUGINS" => true, + "BUNDLE_GLOBAL_GEM_CACHE" => false, + "BUNDLE_UPDATE_REQUIRES_ALL_FLAG" => false, + }.freeze + + def initialize(root = nil) + @root = root + @local_config = load_config(local_config_file) + @local_root = root || Pathname.new(".bundle").expand_path + + @env_config = ENV.to_h + @env_config.select! {|key, _value| key.start_with?("BUNDLE_") } + @env_config.delete("BUNDLE_") + + @global_config = load_config(global_config_file) + @temporary = {} + + @key_cache = {} + end + + def [](name) + key = key_for(name) + + value = nil + configs.each do |_, config| + value = config[key] + next if value.nil? + break + end + + converted_value(value, name) + end + + def set_command_option(key, value) + temporary(key => value) + value + end + + def set_command_option_if_given(key, value) + return if value.nil? + set_command_option(key, value) + end + + def set_local(key, value) + local_config_file = @local_root.join("config") + + set_key(key, value, @local_config, local_config_file) + end + + def temporary(update) + existing = Hash[update.map {|k, _| [k, @temporary[key_for(k)]] }] + update.each do |k, v| + set_key(k, v, @temporary, nil) + end + return unless block_given? + begin + yield + ensure + existing.each {|k, v| set_key(k, v, @temporary, nil) } + end + end + + def set_global(key, value) + set_key(key, value, @global_config, global_config_file) + end + + def all + keys = @temporary.keys.union(@global_config.keys, @local_config.keys, @env_config.keys) + + keys.map! do |key| + key = key.delete_prefix("BUNDLE_") + key.gsub!("___", "-") + key.gsub!("__", ".") + key.downcase! + key + end.sort! + keys + end + + def local_overrides + repos = {} + all.each do |k| + repos[k.delete_prefix("local.")] = self[k] if k.start_with?("local.") + end + repos + end + + def mirror_for(uri) + if uri.is_a?(String) + require_relative "vendored_uri" + uri = Gem::URI(uri) + end + + gem_mirrors.for(uri.to_s).uri + end + + def credentials_for(uri) + self[uri.to_s] || self[uri.host] + end + + def gem_mirrors + all.inject(Mirrors.new) do |mirrors, k| + mirrors.parse(k, self[k]) if k.start_with?("mirror.") + mirrors + end + end + + def locations(key) + key = key_for(key) + configs.keys.inject({}) do |partial_locations, level| + value_on_level = configs[level][key] + partial_locations[level] = value_on_level unless value_on_level.nil? + partial_locations + end + end + + def pretty_values_for(exposed_key) + key = key_for(exposed_key) + + locations = [] + + if value = @temporary[key] + locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}" + end + + if value = @local_config[key] + locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}" + end + + if value = @env_config[key] + locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}" + end + + if value = @global_config[key] + locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}" + end + + return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? + locations + end + + def processor_count + require "etc" + Etc.nprocessors + rescue StandardError + 1 + end + + # for legacy reasons, in Bundler 2, we do not respect :disable_shared_gems + def path + configs.each do |_level, settings| + path = value_for("path", settings) + path_system = value_for("path.system", settings) + disabled_shared_gems = value_for("disable_shared_gems", settings) + next if path.nil? && path_system.nil? && disabled_shared_gems.nil? + system_path = path_system || (disabled_shared_gems == false) + return Path.new(path, system_path) + end + + path = "vendor/bundle" if self[:deployment] + + Path.new(path, false) + end + + Path = Struct.new(:explicit_path, :system_path) do + def path + path = base_path + path = File.join(path, Bundler.ruby_scope) unless use_system_gems? + path + end + + def use_system_gems? + return true if system_path + return false if explicit_path + !Bundler.feature_flag.bundler_5_mode? + end + + def base_path + path = explicit_path + path ||= ".bundle" unless use_system_gems? + path ||= Bundler.rubygems.gem_dir + path + end + + def base_path_relative_to_pwd + base_path = Pathname.new(self.base_path) + expanded_base_path = base_path.expand_path(Bundler.root) + relative_path = expanded_base_path.relative_path_from(Pathname.pwd) + if relative_path.to_s.start_with?("..") + relative_path = base_path if base_path.absolute? + else + relative_path = Pathname.new(File.join(".", relative_path)) + end + relative_path + rescue ArgumentError + expanded_base_path + end + + def validate! + return unless explicit_path && system_path + path = Bundler.settings.pretty_values_for(:path) + path.unshift(nil, "path:") unless path.empty? + system_path = Bundler.settings.pretty_values_for("path.system") + system_path.unshift(nil, "path.system:") unless system_path.empty? + disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems) + disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty? + raise InvalidOption, + "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}" + end + end + + def ignore_config? + ENV["BUNDLE_IGNORE_CONFIG"] + end + + def app_cache_path + @app_cache_path ||= self[:cache_path] || "vendor/cache" + end + + def installation_parallelization + self[:jobs] || processor_count + end + + def validate! + all.each do |raw_key| + [@local_config, @env_config, @global_config].each do |settings| + value = value_for(raw_key, settings) + Validator.validate!(raw_key, value, settings.dup) + end + end + end + + def key_for(key) + @key_cache[key] ||= self.class.key_for(key) + end + + private + + def configs + @configs ||= { + temporary: @temporary, + local: @local_config, + env: @env_config, + global: @global_config, + default: DEFAULT_CONFIG, + } + end + + def value_for(name, config) + converted_value(config[key_for(name)], name) + end + + def parent_setting_for(name) + split_specific_setting_for(name)[0] + end + + def specific_gem_for(name) + split_specific_setting_for(name)[1] + end + + def split_specific_setting_for(name) + name.split(".") + end + + def is_bool(name) + name = self.class.key_to_s(name) + BOOL_KEYS.include?(name) || BOOL_KEYS.include?(parent_setting_for(name)) + end + + def is_string(name) + name = self.class.key_to_s(name) + STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.") + end + + def to_bool(value) + case value + when String + value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true + when nil, false + false + else + true + end + end + + def is_num(key) + NUMBER_KEYS.include?(self.class.key_to_s(key)) + end + + def is_array(key) + ARRAY_KEYS.include?(self.class.key_to_s(key)) + end + + def is_credential(key) + key == "gem.push_key" + end + + def is_userinfo(value) + value.include?(":") + end + + def to_array(value) + return [] unless value + value.tr(" ", ":").split(":").map(&:to_sym) + end + + def array_to_s(array) + array = Array(array) + return nil if array.empty? + array.join(":").tr(" ", ":") + end + + def set_key(raw_key, value, hash, file) + raw_key = self.class.key_to_s(raw_key) + value = array_to_s(value) if is_array(raw_key) + + key = key_for(raw_key) + + return if hash[key] == value + + hash[key] = value + hash.delete(key) if value.nil? + + Validator.validate!(raw_key, converted_value(value, raw_key), hash) + + return unless file + + SharedHelpers.filesystem_access(file.dirname, :create) do |p| + FileUtils.mkdir_p(p) + end + + SharedHelpers.filesystem_access(file) do |p| + p.open("w") {|f| f.write(serializer_class.dump(hash)) } + end + end + + def converted_value(value, key) + key = self.class.key_to_s(key) + + if is_array(key) + to_array(value) + elsif value.nil? + nil + elsif is_bool(key) || value == "false" + to_bool(value) + elsif is_num(key) + value.to_i + else + value.to_s + end + end + + def printable_value(value, key) + converted = converted_value(value, key) + return converted unless converted.is_a?(String) + + if is_string(key) + converted + elsif is_credential(key) + "[REDACTED]" + elsif is_userinfo(converted) + username, pass = converted.split(":", 2) + + if pass == "x-oauth-basic" + username = "[REDACTED]" + else + pass = "[REDACTED]" + end + + [username, pass].join(":") + else + converted + end + end + + def global_config_file + if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? + Pathname.new(ENV["BUNDLE_CONFIG"]) + elsif ENV["BUNDLE_USER_CONFIG"] && !ENV["BUNDLE_USER_CONFIG"].empty? + Pathname.new(ENV["BUNDLE_USER_CONFIG"]) + elsif ENV["BUNDLE_USER_HOME"] && !ENV["BUNDLE_USER_HOME"].empty? + Pathname.new(ENV["BUNDLE_USER_HOME"]).join("config") + elsif Bundler.rubygems.user_home && !Bundler.rubygems.user_home.empty? + Pathname.new(Bundler.rubygems.user_home).join(".bundle/config") + end + end + + def local_config_file + Pathname.new(@root).join("config") if @root + end + + def load_config(config_file) + return {} if !config_file || ignore_config? + SharedHelpers.filesystem_access(config_file, :read) do |file| + valid_file = file.exist? && !file.size.zero? + return {} unless valid_file + serializer_class.load(file.read).inject({}) do |config, (k, v)| + k = k.dup + k << "/" if /https?:/i.match?(k) && !k.end_with?("/", "__#{FALLBACK_TIMEOUT_URI_OPTION.upcase}") + k.gsub!(".", "__") + + unless k.start_with?("#") + if k.include?("-") + Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \ + "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \ + "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)." + + # string hash keys are frozen + k = k.gsub("-", "___") + end + + config[k] = v + end + + config + end + end + end + + def serializer_class + require "rubygems/yaml_serializer" + Gem::YAMLSerializer + rescue LoadError + # TODO: Remove this when RubyGems 3.4 is EOL + require_relative "yaml_serializer" + YAMLSerializer + end + + FALLBACK_TIMEOUT_URI_OPTION = "fallback_timeout" + + NORMALIZE_URI_OPTIONS_PATTERN = + / + \A + (\w+\.)? # optional prefix key + (https?.*?) # URI + (\.#{FALLBACK_TIMEOUT_URI_OPTION})? # optional suffix key + \z + /ix + + def self.key_for(key) + key = key_to_s(key) + key = normalize_uri(key) if key.start_with?("http", "mirror.http") + key = key.gsub(".", "__") + key.gsub!("-", "___") + key.upcase! + + key.gsub(/\A([ #]*)/, '\1BUNDLE_') + end + + # TODO: duplicates Rubygems#normalize_uri + # TODO: is this the correct place to validate mirror URIs? + def self.normalize_uri(uri) + uri = uri.to_s + if uri =~ NORMALIZE_URI_OPTIONS_PATTERN + prefix = $1 + uri = $2 + suffix = $3 + end + uri = URINormalizer.normalize_suffix(uri) + require_relative "vendored_uri" + uri = Gem::URI(uri) + unless uri.absolute? + raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri) + end + "#{prefix}#{uri}#{suffix}" + end + + # This is a hot method, so avoid respond_to? checks on every invocation + if :read.respond_to?(:name) + def self.key_to_s(key) + case key + when String + key + when Symbol + key.name + when Gem::URI::HTTP + key.to_s + else + raise ArgumentError, "Invalid key: #{key.inspect}" + end + end + else + def self.key_to_s(key) + case key + when String + key + when Symbol + key.to_s + when Gem::URI::HTTP + key.to_s + else + raise ArgumentError, "Invalid key: #{key.inspect}" + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/settings/validator.rb b/bin/gems/bundler-4.0.21/lib/bundler/settings/validator.rb new file mode 100644 index 00000000..70a0ca36 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/settings/validator.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +module Bundler + class Settings + class Validator + class Rule + attr_reader :description + + def initialize(keys, description, &validate) + @keys = keys + @description = description + @validate = validate + end + + def validate!(key, value, settings) + instance_exec(key, value, settings, &@validate) + end + + def fail!(key, value, *reasons) + reasons.unshift @description + raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}" + end + + def set(settings, key, value, *reasons) + hash_key = k(key) + return if settings[hash_key] == value + reasons.unshift @description + Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}" + if value.nil? + settings.delete(hash_key) + else + settings[hash_key] = value + end + end + + def k(key) + Bundler.settings.key_for(key) + end + end + + def self.rules + @rules ||= Hash.new {|h, k| h[k] = [] } + end + private_class_method :rules + + def self.rule(keys, description, &blk) + rule = Rule.new(keys, description, &blk) + keys.each {|k| rules[k] << rule } + end + private_class_method :rule + + def self.validate!(key, value, settings) + rules_to_validate = rules[key] + rules_to_validate.each {|rule| rule.validate!(key, value, settings) } + end + + rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings| + if key == "path" && value + set(settings, "path.system", nil) + elsif key == "path.system" && value + set(settings, :path, nil) + end + end + + rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings| + with = settings.fetch(k(:with), "").split(":").map(&:to_sym) + without = settings.fetch(k(:without), "").split(":").map(&:to_sym) + + other_key = key == "with" ? :without : :with + other_setting = key == "with" ? without : with + + conflicting = with & without + if conflicting.any? + fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict") + end + end + + rule %w[default_cli_command], "default_cli_command must be either 'install' or 'cli_help'" do |key, value, _settings| + valid_values = %w[install cli_help] + if !value.nil? && !valid_values.include?(value.to_s) + fail!(key, value, "must be one of: #{valid_values.join(", ")}") + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/setup.rb b/bin/gems/bundler-4.0.21/lib/bundler/setup.rb new file mode 100644 index 00000000..5a0fd8e0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/setup.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" + +if Bundler::SharedHelpers.in_bundle? + require_relative "../bundler" + + # autoswitch to locked Bundler version if available + Bundler.auto_switch + + # try to auto_install first before we get to the `Bundler.ui.silence`, so user knows what is happening + Bundler.auto_install + + if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"] + begin + Bundler.ui.silence { Bundler.setup } + rescue Bundler::BundlerError => e + Bundler.ui.error e.message + Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"] + if e.is_a?(Bundler::GemNotFound) + default_bundle = Gem.bin_path("bundler", "bundle") + current_bundle = Bundler::SharedHelpers.bundle_bin_path + suggested_bundle = default_bundle == current_bundle ? "bundle" : current_bundle + suggested_cmd = "#{suggested_bundle} install" + original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"] + suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile + Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems." + end + exit e.status_code + end + else + Bundler.ui.silence { Bundler.setup } + end + + # We might be in the middle of shelling out to rubygems + # (RUBYOPT=-rbundler/setup), so we need to give rubygems the opportunity of + # not being silent. + Gem::DefaultUserInteraction.ui = nil +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/shared_helpers.rb b/bin/gems/bundler-4.0.21/lib/bundler/shared_helpers.rb new file mode 100644 index 00000000..73380b12 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/shared_helpers.rb @@ -0,0 +1,412 @@ +# frozen_string_literal: true + +require_relative "version" +require_relative "rubygems_integration" +require_relative "current_ruby" + +module Bundler + autoload :WINDOWS, File.expand_path("constants", __dir__) + autoload :FREEBSD, File.expand_path("constants", __dir__) + autoload :NULL, File.expand_path("constants", __dir__) + + module SharedHelpers + def root + gemfile = find_gemfile + raise GemfileNotFound, "Could not locate Gemfile" unless gemfile + Pathname.new(gemfile).expand_path.parent + end + + def default_gemfile + gemfile = find_gemfile + raise GemfileNotFound, "Could not locate Gemfile" unless gemfile + Pathname.new(gemfile).expand_path + end + + def default_lockfile + given = ENV["BUNDLE_LOCKFILE"] + return Pathname.new(given) if given && !given.empty? + + gemfile = default_gemfile + + case gemfile.basename.to_s + when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) + else Pathname.new("#{gemfile}.lock") + end + end + + def default_bundle_dir + bundle_dir = find_directory(".bundle") + return nil unless bundle_dir + + bundle_dir = Pathname.new(bundle_dir) + + global_bundle_dir = Bundler.user_home.join(".bundle") + return nil if bundle_dir == global_bundle_dir + + bundle_dir + end + + def in_bundle? + find_gemfile + end + + def chdir(dir, &blk) + Bundler.rubygems.ext_lock.synchronize do + Dir.chdir dir, &blk + end + end + + def pwd + Bundler.rubygems.ext_lock.synchronize do + Dir.pwd + end + end + + def with_clean_git_env(&block) + keys = %w[GIT_DIR GIT_WORK_TREE] + old_env = keys.inject({}) do |h, k| + h.update(k => ENV[k]) + end + + keys.each {|key| ENV.delete(key) } + + block.call + ensure + keys.each {|key| ENV[key] = old_env[key] } + end + + def set_bundle_environment + set_bundle_variables + set_path + set_rubyopt + set_rubylib + end + + # Rescues permissions errors raised by file system operations + # (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead. + # + # @param path [String] the path that the action will be attempted to + # @param action [Symbol, #to_s] the type of operation that will be + # performed. For example: :write, :read, :exec + # + # @yield path + # + # @raise [Bundler::PermissionError] if Errno:EACCES is raised in the + # given block + # @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the + # given block + # + # @example + # filesystem_access("vendor/cache", :create) do + # FileUtils.mkdir_p("vendor/cache") + # end + # + # @see {Bundler::PermissionError} + def filesystem_access(path, action = :write, &block) + yield(path.dup) + rescue Errno::EACCES => e + raise unless e.message.include?(path.to_s) || action == :create + + raise PermissionError.new(path, action) + rescue Errno::EAGAIN + raise TemporaryResourceError.new(path, action) + rescue Errno::EPROTO + raise VirtualProtocolError.new + rescue Errno::ENOSPC + raise NoSpaceOnDeviceError.new(path, action) + rescue Errno::ENOTSUP + raise OperationNotSupportedError.new(path, action) + rescue Errno::EPERM + raise OperationNotPermittedError.new(path, action) + rescue Errno::EROFS + raise ReadOnlyFileSystemError.new(path, action) + rescue Errno::EEXIST, Errno::ENOENT + raise + rescue SystemCallError => e + raise GenericSystemCallError.new(e, "There was an error #{[:create, :write].include?(action) ? "creating" : "accessing"} `#{path}`.") + end + + def feature_deprecated!(message) + return unless prints_major_deprecations? + + Bundler.ui.warn("[DEPRECATED] #{message}") + end + + def feature_removed!(message) + require_relative "errors" + raise RemovedError, "[REMOVED] #{message}" + end + + def print_major_deprecations! + multiple_gemfiles = search_up(".") do |dir| + gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) } + next if gemfiles.empty? + break gemfiles.size != 1 + end + return unless multiple_gemfiles + message = "Multiple gemfiles (gems.rb and Gemfile) detected. " \ + "Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.locked." + Bundler.ui.warn message + end + + def ensure_same_dependencies(spec, old_deps, new_deps) + new_deps = new_deps.reject {|d| d.type == :development } + old_deps = old_deps.reject {|d| d.type == :development } + + without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } + new_deps.map!(&without_type) + old_deps.map!(&without_type) + + extra_deps = new_deps - old_deps + return if extra_deps.empty? + + Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has corrupted API dependencies" \ + " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" + raise APIResponseMismatchError, + "Downloading #{spec.full_name} revealed dependencies not in the API (#{extra_deps.join(", ")})." \ + "\nRunning `bundle update #{spec.name}` should fix the problem." + end + + def pretty_dependency(dep) + msg = String.new(dep.name) + msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default + + if dep.is_a?(Bundler::Dependency) + platform_string = dep.platforms.join(", ") + msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY + end + + msg + end + + def md5_available? + return @md5_available if defined?(@md5_available) + @md5_available = begin + require "openssl" + ::OpenSSL::Digest.digest("MD5", "") + true + rescue LoadError + true + rescue ::OpenSSL::Digest::DigestError + false + end + end + + def digest(name) + require "digest" + Digest(name) + end + + def checksum_for_file(path, digest) + return unless path.file? + # This must use File.read instead of Digest.file().hexdigest + # because we need to preserve \n line endings on windows when calculating + # the checksum + SharedHelpers.filesystem_access(path, :read) do + File.open(path, "rb") do |f| + digest = SharedHelpers.digest(digest).new + buf = String.new(capacity: 16_384, encoding: Encoding::BINARY) + digest << buf while f.read(16_384, buf) + digest.hexdigest + end + end + end + + def write_to_gemfile(gemfile_path, contents) + filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } } + end + + def relative_gemfile_path + relative_path_to(Bundler.default_gemfile) + end + + def relative_lockfile_path + relative_path_to(Bundler.default_lockfile) + end + + def relative_path_to(destination, from: pwd) + Pathname.new(destination).relative_path_from(from).to_s + rescue ArgumentError + # on Windows, if source and destination are on different drivers, there's no relative path from one to the other + destination + end + + # Globs for entries matching +glob+ inside of +base_path+, returning + # absolute paths. Glob metacharacters in +base_path+ are not treated as + # part of the pattern, and matched entries are joined literally, so an + # entry starting with `~` is not expanded into the home directory. + # + # Bundler runs against whatever RubyGems the host provides, so this cannot + # delegate to Gem::Util.glob_files_in_dir, which only gained the literal + # join in RubyGems 4.1. + def glob_files_in_dir(glob, base_path) + expanded_path = nil + Dir.glob(glob, base: base_path).map! do |f| + File.join(expanded_path ||= File.expand_path(base_path), f) + end + end + + private + + def validate_bundle_path + path_separator = Bundler.rubygems.path_separator + return unless Bundler.bundle_path.to_s.split(path_separator).size > 1 + message = "Your bundle path contains text matching #{path_separator.inspect}, " \ + "which is the path separator for your system. Bundler cannot " \ + "function correctly when the Bundle path contains the " \ + "system's PATH separator. Please change your " \ + "bundle path to not match #{path_separator.inspect}." \ + "\nYour current bundle path is '#{Bundler.bundle_path}'." + raise Bundler::PathError, message + end + + def find_gemfile + given = ENV["BUNDLE_GEMFILE"] + return given if given && !given.empty? + find_file(*gemfile_names) + end + + def gemfile_names + ["gems.rb", "Gemfile"] + end + + def find_file(*names) + search_up(*names) do |filename| + return filename if File.file?(filename) + end + end + + def find_directory(*names) + search_up(*names) do |dirname| + return dirname if File.directory?(dirname) + end + end + + def search_up(*names) + previous = nil + current = File.expand_path(SharedHelpers.pwd) + + until !File.directory?(current) || current == previous + if ENV["BUNDLER_SPEC_RUN"] + # avoid stepping above the tmp directory when testing + return nil if File.directory?(File.join(current, "tmp")) + end + + names.each do |name| + filename = File.join(current, name) + yield filename + end + previous = current + current = File.expand_path("..", current) + end + end + + def set_env(key, value) + raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key) + orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}" + orig = ENV[key] + orig ||= EnvironmentPreserver::INTENTIONALLY_NIL + ENV[orig_key] ||= orig + + ENV[key] = value + end + public :set_env + + def set_bundle_variables + Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", bundle_bin_path + Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s + Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", default_lockfile.to_s + Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION + Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) + end + + def bundle_bin_path + # bundler exe & lib folders have same root folder, typical gem installation + exe_file = File.join(source_root, "exe/bundle") + + # for Ruby core repository testing + exe_file = File.join(source_root, "libexec/bundle") unless File.exist?(exe_file) + + # bundler is a default gem, exe path is separate + exe_file = Gem.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file) + + exe_file + end + public :bundle_bin_path + + def gemspec_path + # inside a gem repository, typical gem installation + gemspec_file = File.join(source_root, "../../specifications/bundler-#{VERSION}.gemspec") + + # for Ruby core repository testing + gemspec_file = File.expand_path("bundler.gemspec", __dir__) unless File.exist?(gemspec_file) + + # bundler is a default gem + gemspec_file = File.join(Gem.default_specifications_dir, "bundler-#{VERSION}.gemspec") unless File.exist?(gemspec_file) + + gemspec_file + end + public :gemspec_path + + def source_root + File.expand_path("../..", __dir__) + end + + def set_path + validate_bundle_path + paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR) + paths.unshift "#{Bundler.bundle_path}/bin" + Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR) + end + + def set_rubyopt + rubyopt = [ENV["RUBYOPT"]].compact + setup_path = File.expand_path("setup", __dir__) + # RUBYOPT is split on whitespace with no quoting mechanism, so an + # absolute path containing spaces would be torn apart. Fall back to + # requiring by feature name; set_rubylib puts our lib directory first + # on the child's load path. + setup_require = /\s/.match?(setup_path) ? "-rbundler/setup" : "-r#{setup_path}" + return if !rubyopt.empty? && rubyopt.first.include?(setup_require) + rubyopt.unshift setup_require + Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ") + end + + def set_rubylib + rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) + rubylib.unshift bundler_ruby_lib unless RbConfig::CONFIG["rubylibdir"] == bundler_ruby_lib + Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR) + end + + def bundler_ruby_lib + File.expand_path("..", __dir__) + end + + def clean_load_path + loaded_gem_paths = Bundler.rubygems.loaded_gem_paths + + $LOAD_PATH.reject! do |p| + resolved_path = resolve_path(p) + next if $LOADED_FEATURES.any? {|lf| lf.start_with?(resolved_path) } + loaded_gem_paths.delete(p) + end + $LOAD_PATH.uniq! + end + + def resolve_path(path) + expanded = File.expand_path(path) + return expanded unless File.exist?(expanded) + + File.realpath(expanded) + end + + def prints_major_deprecations? + return false if Bundler.settings[:silence_deprecations] + require_relative "deprecate" + return false if Bundler::Deprecate.skip + true + end + + extend self + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source.rb b/bin/gems/bundler-4.0.21/lib/bundler/source.rb new file mode 100644 index 00000000..cf71be88 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +module Bundler + class Source + autoload :Gemspec, File.expand_path("source/gemspec", __dir__) + autoload :Git, File.expand_path("source/git", __dir__) + autoload :Metadata, File.expand_path("source/metadata", __dir__) + autoload :Path, File.expand_path("source/path", __dir__) + autoload :Rubygems, File.expand_path("source/rubygems", __dir__) + autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) + + attr_accessor :dependency_names + + attr_reader :checksum_store + + def unmet_deps + specs.unmet_dependency_names + end + + def version_message(spec, locked_spec = nil) + message = "#{spec.name} #{spec.version}" + message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? + + if locked_spec + locked_spec_version = locked_spec.version + if locked_spec_version && spec.version != locked_spec_version + message += Bundler.ui.add_color(" (was #{locked_spec_version})", version_color(spec.version, locked_spec_version)) + end + end + + message + end + + def download(*); end + + def can_lock?(spec) + spec.source == self + end + + def prefer_local!; end + + def local!; end + + def local_only!; end + + def cached!; end + + def remote!; end + + def add_dependency_names(names) + @dependency_names = Array(dependency_names) | Array(names) + end + + # it's possible that gems from one source depend on gems from some + # other source, so now we download gemspecs and iterate over those + # dependencies, looking for gems we don't have info on yet. + def double_check_for(*); end + + def dependency_names_to_double_check + specs.dependency_names + end + + def spec_names + specs.spec_names + end + + def include?(other) + other == self + end + + def inspect + "#<#{self.class}:0x#{object_id} #{self}>" + end + + def identifier + to_s + end + + def path? + instance_of?(Bundler::Source::Path) + end + + def extension_cache_path(spec) + return unless Bundler.settings[:global_gem_cache] + return unless source_slug = extension_cache_slug(spec) + Bundler.user_cache.join( + "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, + source_slug, spec.full_name + ) + end + + private + + def version_color(spec_version, locked_spec_version) + if Gem::Version.correct?(spec_version) && Gem::Version.correct?(locked_spec_version) + # display yellow if there appears to be a regression + earlier_version?(spec_version, locked_spec_version) ? :yellow : :green + else + # default to green if the versions cannot be directly compared + :green + end + end + + def earlier_version?(spec_version, locked_spec_version) + Gem::Version.new(spec_version) < Gem::Version.new(locked_spec_version) + end + + def print_using_message(message) + if !message.include?("(was ") + Bundler.ui.debug message + else + Bundler.ui.info message + end + end + + def extension_cache_slug(_) + nil + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/gemspec.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/gemspec.rb new file mode 100644 index 00000000..ed766dbe --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/gemspec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Gemspec < Path + attr_reader :gemspec + attr_writer :checksum_store + + def initialize(options) + super + @gemspec = options["gemspec"] + end + + def to_s + "gemspec at `#{@path}`" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/git.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/git.rb new file mode 100644 index 00000000..d47eccc7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/git.rb @@ -0,0 +1,453 @@ +# frozen_string_literal: true + +require_relative "../vendored_fileutils" + +module Bundler + class Source + class Git < Path + autoload :GitProxy, File.expand_path("git/git_proxy", __dir__) + + attr_reader :uri, :ref, :branch, :options, :glob, :submodules + + def initialize(options) + @options = options + @checksum_store = Checksum::Store.new + @glob = options["glob"] || DEFAULT_GLOB + + @allow_cached = false + @allow_remote = false + + # Stringify options that could be set as symbols + %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } + + @uri = URINormalizer.normalize_suffix(options["uri"] || "", trailing_slash: false) + @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) + @branch = options["branch"] + @ref = options["ref"] || options["branch"] || options["tag"] + @submodules = options["submodules"] + @name = options["name"] + @version = options["version"].to_s.strip.gsub("-", ".pre.") + + @copied = false + @local = false + end + + def remote! + return if @allow_remote + + @local_specs = nil + @allow_remote = true + end + + def cached! + return if @allow_cached + + @local_specs = nil + @allow_cached = true + end + + def self.from_lock(options) + new(options.merge("uri" => options.delete("remote"))) + end + + def to_lock + out = String.new("GIT\n") + out << " remote: #{@uri}\n" + out << " revision: #{revision}\n" + %w[ref branch tag submodules].each do |opt| + out << " #{opt}: #{options[opt]}\n" if options[opt] + end + out << " glob: #{@glob}\n" unless default_glob? + out << " specs:\n" + end + + def to_gemfile + specifiers = %w[ref branch tag submodules glob].map do |opt| + "#{opt}: #{options[opt]}" if options[opt] + end + + uri_with_specifiers(specifiers) + end + + def hash + [self.class, uri, ref, branch, name, glob, submodules].hash + end + + def eql?(other) + other.is_a?(Git) && uri == other.uri && ref == other.ref && + branch == other.branch && name == other.name && + glob == other.glob && + submodules == other.submodules + end + + alias_method :==, :eql? + + def include?(other) + other.is_a?(Git) && uri == other.uri && + name == other.name && + glob == other.glob && + submodules == other.submodules + end + + def to_s + begin + at = humanized_ref + at = "#{at}@" if at + rev = "at #{at}#{shortref_for_display(revision)}" + rescue GitError + "" + end + + uri_with_specifiers([rev, glob_for_display]) + end + + def identifier + uri_with_specifiers([humanized_ref, locked_revision, glob_for_display]) + end + + def uri_with_specifiers(specifiers) + specifiers.compact! + + suffix = + if specifiers.any? + " (#{specifiers.join(", ")})" + else + "" + end + + "#{@safe_uri}#{suffix}" + end + + def name + File.basename(@uri, ".git") + end + + # This is the path which is going to contain a specific + # checkout of the git repository. When using local git + # repos, this is set to the local repo. + def install_path + @install_path ||= begin + git_scope = "#{base_name}-#{shortref_for_path(revision)}" + + Bundler.install_path.join(git_scope) + end + end + + alias_method :path, :install_path + + def extension_dir_name + "#{base_name}-#{shortref_for_path(revision)}" + end + + def unlock! + git_proxy.revision = nil + options["revision"] = nil + + @unlocked = true + end + + def local_override!(path) + return false if local? + + original_path = path + path = Pathname.new(path) + path = path.expand_path(Bundler.root) unless path.relative? + + unless branch || Bundler.settings[:disable_local_branch_check] + raise GitError, "Cannot use local override for #{name} at #{path} because " \ + ":branch is not specified in Gemfile. Specify a branch or run " \ + "`bundle config unset local.#{override_for(original_path)}` to remove the local override" + end + + unless path.exist? + raise GitError, "Cannot use local override for #{name} because #{path} " \ + "does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override" + end + + @local = true + set_paths!(path) + + # Create a new git proxy without the cached revision + # so the Gemfile.lock always picks up the new revision. + @git_proxy = GitProxy.new(path, uri, options) + + if current_branch != branch && !Bundler.settings[:disable_local_branch_check] + raise GitError, "Local override for #{name} at #{path} is using branch " \ + "#{current_branch} but Gemfile specifies #{branch}" + end + + changed = locked_revision && locked_revision != revision + + if !Bundler.settings[:disable_local_revision_check] && changed && !@unlocked && !git_proxy.contains?(locked_revision) + raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(locked_revision)} " \ + "but the current branch in your local override for #{name} does not contain such commit. " \ + "Please make sure your branch is up to date." + end + + changed + end + + def specs(*) + set_cache_path!(app_cache_path) if use_app_cache? + + if requires_checkout? && !@copied + fetch unless use_app_cache? + checkout + end + + local_specs + end + + def install(spec, options = {}) + return if Bundler.settings[:no_install] + force = options[:force] + + print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}" + + if (requires_checkout? && !@copied) || force + checkout + end + + generate_bin_options = { disable_extensions: !spec.missing_extensions?, build_args: options[:build_args] } + generate_bin(spec, generate_bin_options) + + requires_checkout? ? spec.post_install_message : nil + end + + def migrate_cache(custom_path = nil, local: false) + if local + cache_to(custom_path, try_migrate: false) + else + cache_to(custom_path, try_migrate: true) + end + end + + def cache(spec, custom_path = nil) + cache_to(custom_path, try_migrate: false) + end + + def load_spec_files + super + rescue PathError => e + Bundler.ui.trace e + raise GitError, "#{self} is not yet checked out. Run `bundle install` first." + end + + # This is the path which is going to contain a cache + # of the git repository. When using the same git repository + # across different projects, this cache will be shared. + # When using local git repos, this is set to the local repo. + def cache_path + @cache_path ||= if Bundler.settings[:global_gem_cache] + Bundler.user_cache + else + Bundler.bundle_path.join("cache", "bundler") + end.join("git", git_scope) + end + + def app_cache_dirname + "#{base_name}-#{shortref_for_path(locked_revision || revision)}" + end + + def revision + git_proxy.revision + end + + def current_branch + git_proxy.current_branch + end + + def allow_git_ops? + @allow_remote || @allow_cached + end + + def local? + @local + end + + private + + def cache_to(custom_path, try_migrate: false) + return unless Bundler.settings[:cache_all] + + app_cache_path = app_cache_path(custom_path) + + migrate = try_migrate ? bare_repo?(app_cache_path) : false + + set_cache_path!(nil) if migrate + + return if cache_path == app_cache_path + + cached! + FileUtils.rm_rf(app_cache_path) + git_proxy.checkout if migrate || requires_checkout? + git_proxy.copy_to(app_cache_path, @submodules) + serialize_gemspecs_in(app_cache_path) + end + + def checkout + Bundler.ui.debug " * Checking out revision: #{ref}" + if use_app_cache? && !bare_repo?(app_cache_path) + SharedHelpers.filesystem_access(install_path.dirname) do |p| + FileUtils.mkdir_p(p) + end + FileUtils.cp_r("#{app_cache_path}/.", install_path) + else + if use_app_cache? && bare_repo?(app_cache_path) + Bundler.ui.warn "Installing from cache in old \"bare repository\" format for compatibility. " \ + "Please run `bundle cache` and commit the updated cache to migrate to the new format and get rid of this warning." + end + + git_proxy.copy_to(install_path, submodules) + end + serialize_gemspecs_in(install_path) + @copied = true + end + + def humanized_ref + if local? + path + elsif user_ref = options["ref"] + if /\A[a-z0-9]{4,}\z/i.match?(ref) + shortref_for_display(user_ref) + else + user_ref + end + elsif ref + ref + end + end + + def serialize_gemspecs_in(destination) + destination = destination.expand_path(Bundler.root) if destination.relative? + SharedHelpers.glob_files_in_dir(@glob, destination.to_s).each do |spec_path| + # Evaluate gemspecs and cache the result. Gemspecs + # in git might require git or other dependencies. + # The gemspecs we cache should already be evaluated. + spec = Bundler.load_gemspec(spec_path) + next unless spec + spec.installed_by_version = Gem::VERSION + Bundler.rubygems.validate(spec) + File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) } + end + end + + def set_paths!(path) + set_cache_path!(path) + set_install_path!(path) + end + + def set_cache_path!(path) + @git_proxy = nil + @cache_path = path + end + + def set_install_path!(path) + @local_specs = nil + @install_path = path + end + + def has_app_cache? + locked_revision && super + end + + def use_app_cache? + has_app_cache? && !local? + end + + def requires_checkout? + allow_git_ops? && !local? && !locked_revision_checked_out? + end + + def locked_revision_checked_out? + locked_revision && locked_revision == revision && installed? + end + + def installed? + git_proxy.installed_to?(install_path) + end + + def base_name + File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") + end + + def shortref_for_display(ref) + ref[0..6] + end + + def shortref_for_path(ref) + ref[0..11] + end + + def glob_for_display + default_glob? ? nil : "glob: #{@glob}" + end + + def default_glob? + @glob == DEFAULT_GLOB + end + + def uri_hash + if %r{^\w+://(\w+@)?}.match?(uri) + # Downcase the domain component of the URI + # and strip off a trailing slash, if one is present + input = Gem::URI.parse(uri).normalize.to_s.sub(%r{/$}, "") + else + # If there is no URI scheme, assume it is an ssh/git URI + input = uri + end + # We use SHA1 here for historical reason and to preserve backward compatibility. + # But a transition to a simpler mangling algorithm would be welcome. + Bundler::Digest.sha1(input) + end + + def locked_revision + options["revision"] + end + + def cached? + cache_path.exist? + end + + def git_proxy + @git_proxy ||= GitProxy.new(cache_path, uri, options, locked_revision, self) + end + + def fetch + git_proxy.checkout + rescue GitError => e + Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" + end + + # no-op, since we validate when re-serializing the gemspec + def validate_spec(_spec); end + + def load_gemspec(file) + # Expand the path before the chdir below, since resolving it inside the + # block would base it on the gemspec directory instead of `root`. + gemspec_path = Pathname.new(file).expand_path(root) + SharedHelpers.chdir(gemspec_path.dirname.to_s) do + stub = Gem::StubSpecification.gemspec_stub(gemspec_path.to_s, install_path.parent, install_path.parent) + stub.full_gem_path = gemspec_path.dirname.to_s + StubSpecification.from_stub(stub) + end + end + + def git_scope + "#{base_name}-#{uri_hash}" + end + + def extension_cache_slug(_) + extension_dir_name + end + + def override_for(path) + Bundler.settings.local_overrides.key(path) + end + + def bare_repo?(path) + File.exist?(path.join("objects")) && File.exist?(path.join("HEAD")) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/git/git_proxy.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/git/git_proxy.rb new file mode 100644 index 00000000..c22f5919 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/git/git_proxy.rb @@ -0,0 +1,579 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Git + class GitNotInstalledError < GitError + def initialize + msg = String.new + msg << "You need to install git to be able to use gems from git repositories. " + msg << "For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git" + super msg + end + end + + class GitNotAllowedError < GitError + def initialize(command) + msg = String.new + msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, " + msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/ruby/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md " + msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" + super msg + end + end + + class GitCommandError < GitError + attr_reader :command + + def initialize(command, path, extra_info = nil) + @command = command + + msg = String.new("Git error: command `#{command}`") + msg << " in directory #{path}" if path + msg << " has failed." + msg << "\n#{extra_info}" if extra_info + super msg + end + end + + class MissingGitRevisionError < GitCommandError + def initialize(command, destination_path, ref, repo) + msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" + super command, destination_path, msg + end + end + + class AmbiguousGitReference < GitError + def initialize(options) + msg = "Specification of branch or ref with tag is ambiguous. You specified #{options.inspect}" + super msg + end + end + + # The GitProxy is responsible to interact with git repositories. + # All actions required by the Git source is encapsulated in this + # object. + class GitProxy + attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref + attr_writer :revision + + def self.version + @version ||= full_version[/((\.?\d+)+).*/, 1] + end + + def self.full_version + @full_version ||= begin + raise GitNotInstalledError.new unless Bundler.git_present? + + require "open3" + out, err, status = Open3.capture3("git", "--version") + + raise GitCommandError.new("--version", SharedHelpers.pwd, err) unless status.success? + Bundler.ui.warn err unless err.empty? + + out.sub(/git version\s*/, "").strip + end + end + + def self.reset + @version = nil + @full_version = nil + end + + def initialize(path, uri, options = {}, revision = nil, git = nil) + @path = path + @uri = uri + @tag = options["tag"] + @branch = options["branch"] + @ref = options["ref"] + if @tag + raise AmbiguousGitReference.new(options) if @branch || @ref + @explicit_ref = @tag + else + @explicit_ref = @ref || @branch + end + @revision = revision + @git = git + @commit_ref = nil + end + + def revision + @revision ||= allowed_with_path { find_local_revision } + end + + def current_branch + @current_branch ||= with_path do + git_local("rev-parse", "--abbrev-ref", "HEAD", dir: path).strip + end + end + + def contains?(commit) + allowed_with_path do + result, status = git_null("branch", "--contains", commit, dir: path) + status.success? && result.match?(/^\* (.*)$/) + end + end + + def version + self.class.version + end + + def full_version + self.class.full_version + end + + def checkout + return if has_revision_cached? + + Bundler.ui.info "Fetching #{credential_filtered_uri}" + + extra_fetch_needed = clone_needs_extra_fetch? + unshallow_needed = clone_needs_unshallow? + return unless extra_fetch_needed || unshallow_needed + + git_remote_fetch(unshallow_needed ? ["--unshallow"] : depth_args) + end + + def copy_to(destination, submodules = false) + unless File.exist?(destination.join(".git")) + begin + SharedHelpers.filesystem_access(destination.dirname) do |p| + FileUtils.mkdir_p(p) + end + SharedHelpers.filesystem_access(destination) do |p| + FileUtils.rm_rf(p) + end + git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s + # The copy is cloned from the local bare cache, which holds no Git LFS + # objects, so point origin back at the real remote and let git-lfs derive + # its endpoint from there when checking out. Use the credential-filtered + # URI to avoid persisting secrets in the copy's .git/config; auth is left + # to git's credential helper. + git "remote", "set-url", "origin", credential_filtered_uri, dir: destination + File.chmod((File.stat(destination).mode | 0o777) & ~File.umask, destination) + rescue Errno::EEXIST => e + file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1] + raise GitError, "Bundler could not install a gem because it needs to " \ + "create a directory, but a file exists - #{file_path}. Please delete " \ + "this file and try again." + end + end + + ref = @commit_ref || (locked_to_full_sha? && @revision) + if ref + git "config", "uploadpack.allowAnySHA1InWant", "true", dir: path.to_s if @commit_ref.nil? && needs_allow_any_sha1_in_want? + + git "fetch", "--force", "--quiet", *extra_fetch_args(ref), dir: destination + end + + git "reset", "--hard", revision, dir: destination + + if submodules + git_retry "submodule", "update", "--init", "--recursive", dir: destination + elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0") + inner_command = "git -C $toplevel submodule deinit --force $sm_path" + git_retry "submodule", "foreach", "--quiet", inner_command, dir: destination + end + end + + def installed_to?(destination) + # if copy_to is interrupted, it may leave a partially installed directory that + # contains .git but no other files -- consider this not to be installed + Dir.exist?(destination) && (Dir.children(destination) - [".git"]).any? + end + + private + + def git_remote_fetch(args) + command = fetch_command(args) + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do + out, err, status = capture(command, path) + return out if status.success? + + if err.include?("couldn't find remote ref") || err.include?("not our ref") + default_branch = renamed_remote_default_branch if tracking_remote_default_branch? + if default_branch + out = follow_remote_default_branch(args, default_branch) + return out if out + end + + raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref || current_branch, credential_filtered_uri) + else + if shallow? + args -= depth_args + command = fetch_command(args) + command_with_no_credentials = check_allowed(command) + end + raise GitCommandError.new(command_with_no_credentials, path, err) + end + end + end + + def clone_needs_extra_fetch? + return true if path.exist? + + SharedHelpers.filesystem_access(path.dirname) do |p| + FileUtils.mkdir_p(p) + end + + clone_args = extra_clone_args + command = clone_command(clone_args) + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do + _, err, status = capture(command, nil) + return extra_ref if status.success? + + if err.include?("Could not find remote branch") || # git up to 2.49 + err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher + raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri) + else + if shallow? + clone_args -= depth_args + command = clone_command(clone_args) + command_with_no_credentials = check_allowed(command) + end + raise GitCommandError.new(command_with_no_credentials, path, err) + end + end + end + + def clone_needs_unshallow? + return false unless path.join("shallow").exist? + return true unless shallow? + + @revision && @revision != head_revision + end + + def extra_ref + return false if not_pinned? + return true if shallow? + + ref.start_with?("refs/") + end + + def depth + return @depth if defined?(@depth) + + @depth = if !supports_fetching_unreachable_refs? + nil + elsif not_pinned? || pinned_to_full_sha? + 1 + elsif ref.include?("~") + parsed_depth = ref.split("~").last + parsed_depth.to_i + 1 + end + end + + def refspec + if commit + @commit_ref = "refs/#{commit}-sha" + return "#{commit}:#{@commit_ref}" + end + + reference = fully_qualified_ref + + reference ||= if ref.include?("~") + ref.split("~").first + elsif ref.start_with?("refs/") + ref + else + "refs/*" + end + + "#{reference}:#{reference}" + end + + def commit + @commit ||= pinned_to_full_sha? ? ref : @revision + end + + def fully_qualified_ref + if branch + "refs/heads/#{branch}" + elsif tag + "refs/tags/#{tag}" + elsif ref.nil? + "refs/heads/#{current_branch}" + end + end + + def not_pinned? + branch_option || ref.nil? + end + + def tracking_remote_default_branch? + explicit_ref.nil? && commit.nil? + end + + # Returns nil on any failure, leaving HEAD untouched so the caller reports + # the original fetch failure. Runs inside the retry block, so it must not + # touch the caller's command locals. + def follow_remote_default_branch(args, default_branch) + reference = "refs/heads/#{default_branch}" + command = fetch_command(args, "#{reference}:#{reference}") + check_allowed(command) + + out, err, status = capture(command, path) + unless status.success? + Bundler.ui.debug "Could not fetch #{reference} from #{credential_filtered_uri}: #{err}" + return + end + + previous_branch = current_branch + begin + git "symbolic-ref", "HEAD", reference, dir: path + rescue GitError => e + Bundler.ui.debug "Could not repoint the cached clone at #{reference}: #{e.message}" + return + end + @current_branch = nil + Bundler.ui.warn "#{credential_filtered_uri} no longer has #{previous_branch}, " \ + "now following its default branch #{default_branch}" + out + end + + # The cached clone's HEAD branch is gone from the remote, so the remote's + # own idea of its default branch is the only thing left to follow. + def renamed_remote_default_branch + default_branch = remote_default_branch + return if default_branch.nil? || default_branch == current_branch + + default_branch + end + + def remote_default_branch + command = ["ls-remote", "--symref", "--", configured_uri, "HEAD"] + check_allowed(command) + + out, err, status = capture(command, path) + unless status.success? + Bundler.ui.debug "Could not ask #{credential_filtered_uri} for its default branch: #{err}" + return + end + + # A remote is free to advertise a ref name that is not valid UTF-8, and + # matching that as text raises out of the GitError family. + out.b[%r{^ref:\s+refs/heads/(.+?)\s+HEAD}, 1] + end + + def pinned_to_full_sha? + full_sha_revision?(ref) + end + + def locked_to_full_sha? + full_sha_revision?(@revision) + end + + def full_sha_revision?(ref) + ref&.match?(/\A\h{40}\z/) + end + + def git_null(*command, dir: nil) + check_allowed(command) + + capture(command, dir, ignore_err: true) + end + + def git_retry(*command, dir: nil) + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do + git(*command, dir: dir) + end + end + + def git(*command, dir: nil) + run_command(*command, dir: dir) do |unredacted_command| + check_allowed(unredacted_command) + end + end + + def git_local(*command, dir: nil) + run_command(*command, dir: dir) do |unredacted_command| + redact_and_check_presence(unredacted_command) + end + end + + def has_revision_cached? + return unless commit && path.exist? + git("cat-file", "-e", commit, dir: path) + true + rescue GitError + false + end + + def find_local_revision + return head_revision if explicit_ref.nil? + + find_revision_for(explicit_ref) + end + + def head_revision + verify("HEAD") + end + + def find_revision_for(reference) + verify(reference) + rescue GitCommandError => e + raise MissingGitRevisionError.new(e.command, path, reference, credential_filtered_uri) + end + + def verify(reference) + git("rev-parse", "--verify", reference, dir: path).strip + end + + # Adds credentials to the URI. This is the URI given to git, so it's + # also the one command output must be filtered against. + def configured_uri + @configured_uri ||= if /https?:/.match?(uri) + remote = Gem::URI(uri) + config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host] + remote.userinfo ||= config_auth + remote.to_s + else + uri.to_s + end + end + + # Removes credentials from the URI + def credential_filtered_uri + URICredentialsFilter.credential_filtered_uri(uri) + end + + def allow? + allowed = @git ? @git.allow_git_ops? : true + + raise GitNotInstalledError.new if allowed && !Bundler.git_present? + + allowed + end + + def with_path(&blk) + checkout unless path.exist? + blk.call + end + + def allowed_with_path + return with_path { yield } if allow? + raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application" + end + + def check_allowed(command) + command_with_no_credentials = redact_and_check_presence(command) + raise GitNotAllowedError.new(command_with_no_credentials) unless allow? + command_with_no_credentials + end + + def redact_and_check_presence(command) + raise GitNotInstalledError.new unless Bundler.git_present? + + require "shellwords" + URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", configured_uri) + end + + def run_command(*command, dir: nil) + command_with_no_credentials = yield(command) + + out, err, status = capture(command, dir) + + raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, err) unless status.success? + + Bundler.ui.warn err unless err.empty? + + out + end + + def capture(cmd, dir, ignore_err: false) + SharedHelpers.with_clean_git_env do + require "open3" + out, err, status = Open3.capture3(*capture3_args_for(cmd, dir)) + + filtered_out = URICredentialsFilter.credential_filtered_string(out, configured_uri) + return [filtered_out, status] if ignore_err + + filtered_err = URICredentialsFilter.credential_filtered_string(err, configured_uri) + [filtered_out, filtered_err, status] + end + end + + def capture3_args_for(cmd, dir) + # Disable automatic maintenance so a background commit-graph write in + # the source repo can't race the hardlinking local clone and fail with + # "hardlink different from source". + opts = ["-c", "gc.auto=0", "-c", "maintenance.auto=false"] + + return ["git", *opts, *cmd] unless dir + + # With safe.bareRepository=explicit, git refuses to discover a bare + # repository from -C, so the cache clone is named with --git-dir. + # Working trees, like a local override, still go through -C. + location = bare_repo?(dir) ? "--git-dir" : "-C" + ["git", location, dir.to_s, *opts, *cmd] + end + + def bare_repo?(dir) + File.exist?(File.join(dir, "objects")) && File.exist?(File.join(dir, "HEAD")) + end + + def extra_clone_args + args = depth_args + return [] if args.empty? + + args += ["--single-branch"] + args.unshift("--no-tags") if supports_cloning_with_no_tags? + + # If there's a locked revision, no need to clone any specific branch + # or tag, since we will end up checking out that locked revision + # anyways. + return args if @revision + + args += ["--branch", branch_option] if branch_option + args + end + + def fetch_command(args, spec = refspec) + ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, spec].compact + end + + def clone_command(args) + ["clone", "--bare", "--no-hardlinks", "--quiet", *args, "--", configured_uri, path.to_s] + end + + def depth_args + return [] unless shallow? + + ["--depth", depth.to_s] + end + + def extra_fetch_args(ref) + extra_args = [path.to_s, *depth_args] + extra_args.push(ref) + extra_args + end + + def branch_option + branch || tag + end + + def shallow? + !depth.nil? + end + + def needs_allow_any_sha1_in_want? + @needs_allow_any_sha1_in_want ||= Gem::Version.new(version) <= Gem::Version.new("2.13.7") + end + + def supports_fetching_unreachable_refs? + @supports_fetching_unreachable_refs ||= Gem::Version.new(version) >= Gem::Version.new("2.5.0") + end + + def supports_cloning_with_no_tags? + @supports_cloning_with_no_tags ||= Gem::Version.new(version) >= Gem::Version.new("2.14.0-rc0") + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/metadata.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/metadata.rb new file mode 100644 index 00000000..ecf88951 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/metadata.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Metadata < Source + def specs + @specs ||= Index.build do |idx| + idx << Gem::Specification.new("Ruby\0", Bundler::RubyVersion.system.gem_version) + idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| + s.required_rubygems_version = Gem::Requirement.default + end + + if local_spec = Gem.loaded_specs["bundler"] + raise CorruptBundlerInstallError.new(local_spec) if local_spec.version.to_s != Bundler::VERSION + + idx << local_spec + else + idx << Gem::Specification.new do |s| + s.name = "bundler" + s.version = VERSION + s.license = "MIT" + s.platform = Gem::Platform::RUBY + s.authors = ["bundler team"] + s.bindir = "exe" + s.homepage = "https://bundler.io" + s.summary = "The best way to manage your application's dependencies" + s.executables = %w[bundle bundler] + s.loaded_from = SharedHelpers.gemspec_path + end + end + + idx.each {|s| s.source = self } + end + end + + def options + {} + end + + def install(spec, _opts = {}) + print_using_message "Using #{version_message(spec)}" + nil + end + + def to_s + "the local ruby installation" + end + + def ==(other) + self.class == other.class + end + alias_method :eql?, :== + + def hash + self.class.hash + end + + def version_message(spec) + "#{spec.name} #{spec.version}" + end + + def checksum_store + @checksum_store ||= Checksum::Store.new + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/path.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/path.rb new file mode 100644 index 00000000..db6c0ff8 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/path.rb @@ -0,0 +1,256 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Path < Source + autoload :Installer, File.expand_path("path/installer", __dir__) + + attr_reader :path, :options, :root_path, :original_path + attr_writer :name + attr_accessor :version + + protected :original_path + + DEFAULT_GLOB = "{,*,*/*}.gemspec" + + def initialize(options) + @checksum_store = Checksum::Store.new + @options = options.dup + @glob = options["glob"] || DEFAULT_GLOB + + @root_path = options["root_path"] || root + + if options["path"] + @path = Pathname.new(options["path"]) + expanded_path = expand(@path) + @path = if @path.relative? + expanded_path.relative_path_from(File.expand_path(root_path)) + else + expanded_path + end + end + + @name = options["name"] + @version = options["version"] + + # Stores the original path. If at any point we move to the + # cached directory, we still have the original path to copy from. + @original_path = @path + end + + def self.from_lock(options) + new(options.merge("path" => options.delete("remote"))) + end + + def to_lock + out = String.new("PATH\n") + out << " remote: #{lockfile_path}\n" + out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB + out << " specs:\n" + end + + def to_s + "source at `#{@path}`" + end + + alias_method :identifier, :to_s + + alias_method :to_gemfile, :path + + def hash + [self.class, expanded_path, version].hash + end + + def eql?(other) + [Gemspec, Path].include?(other.class) && + expanded_original_path == other.expanded_original_path && + version == other.version + end + + alias_method :==, :eql? + + def name + File.basename(expanded_path.to_s) + end + + def install(spec, options = {}) + using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}" + using_message += " and installing its executables" unless spec.executables.empty? + print_using_message using_message + generate_bin(spec, disable_extensions: true) + nil # no post-install message + end + + def cache(spec, custom_path = nil) + app_cache_path = app_cache_path(custom_path) + return unless Bundler.settings[:cache_all] + return if expand(@original_path).to_s.index(root_path.to_s + "/") == 0 + + unless @original_path.exist? + raise GemNotFound, "Can't cache gem #{version_message(spec)} because #{self} is missing!" + end + + FileUtils.rm_rf(app_cache_path) + FileUtils.cp_r("#{@original_path}/.", app_cache_path) + FileUtils.touch(app_cache_path.join(".bundlecache")) + end + + def local_specs(*) + @local_specs ||= load_spec_files + end + + def specs + if has_app_cache? + @path = app_cache_path + @expanded_path = nil # Invalidate + end + local_specs + end + + def app_cache_dirname + name + end + + def root + Bundler.root + end + + def expanded_original_path + @expanded_original_path ||= expand(original_path) + end + + private + + def expanded_path + @expanded_path ||= expand(path) + end + + def expand(somepath) + somepath.expand_path(root_path) + rescue ArgumentError => e + Bundler.ui.debug(e) + raise PathError, "There was an error while trying to use the path " \ + "`#{somepath}`.\nThe error message was: #{e.message}." + end + + def lockfile_path + return relative_path(original_path) if original_path.absolute? + expand(original_path).relative_path_from(root) + end + + def app_cache_path(custom_path = nil) + @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) + end + + def has_app_cache? + SharedHelpers.in_bundle? && app_cache_path.exist? + end + + def load_gemspec(file) + return unless spec = Bundler.load_gemspec(file) + spec.installed_by_version = Gem::VERSION + spec + end + + def validate_spec(spec) + Bundler.rubygems.validate(spec) + end + + def load_spec_files + index = Index.new + + if File.directory?(expanded_path) + # We sort depth-first since `<<` will override the earlier-found specs + SharedHelpers.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file| + next unless spec = load_gemspec(file) + spec.source = self + + # The ignore attribute is for ignoring installed gems that don't + # have extensions correctly compiled for activation. In the case of + # path sources, there's a single version of each gem in the path + # source available to Bundler, so we always certainly want to + # consider that for activation and never makes sense to ignore it. + spec.ignored = false + + # Validation causes extension_dir to be calculated, which depends + # on #source, so we validate here instead of load_gemspec + validate_spec(spec) + index << spec + end + + if index.empty? && @name && @version + index << Gem::Specification.new do |s| + s.name = @name + s.source = self + s.version = Gem::Version.new(@version) + s.platform = Gem::Platform::RUBY + s.summary = "Fake gemspec for #{@name}" + s.relative_loaded_from = "#{@name}.gemspec" + s.authors = ["no one"] + if expanded_path.join("bin").exist? + executables = expanded_path.join("bin").children + executables.reject! {|p| File.directory?(p) } + s.executables = executables.map {|c| c.basename.to_s } + end + end + end + else + message = String.new("The path `#{expanded_path}` ") + message << if File.exist?(expanded_path) + "is not a directory." + else + "does not exist." + end + raise PathError, message + end + + index + end + + def relative_path(path = self.path) + if path.to_s.start_with?(root_path.to_s) + return path.relative_path_from(root_path) + end + path + end + + def generate_bin(spec, options = {}) + gem_dir = Pathname.new(spec.full_gem_path) + + # Some gem authors put absolute paths in their gemspec + # and we have to save them from themselves + spec.files = spec.files.filter_map do |path| + pathname = Pathname.new(path) + next path unless pathname.absolute? + next if File.directory?(path) + begin + pathname.relative_path_from(gem_dir).to_s + rescue ArgumentError + path + end + end + + installer = Path::Installer.new( + spec, + env_shebang: false, + disable_extensions: options[:disable_extensions], + build_args: options[:build_args], + bundler_extension_cache_path: extension_cache_path(spec) + ) + installer.post_install + rescue Gem::InvalidSpecificationException => e + Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ + "This prevents bundler from installing bins or native extensions, but " \ + "that may not affect its functionality." + + if !spec.extensions.empty? && !spec.email.empty? + Bundler.ui.warn "If you need to use this package without installing it from a gem " \ + "repository, please contact #{spec.email} and ask them " \ + "to modify their .gemspec so it can work with `gem build`." + end + + Bundler.ui.warn "The validation message from RubyGems was:\n #{e.message}" + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/path/installer.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/path/installer.rb new file mode 100644 index 00000000..0af28fe7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/path/installer.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require_relative "../../rubygems_gem_installer" + +module Bundler + class Source + class Path + class Installer < Bundler::RubyGemsGemInstaller + attr_reader :spec + + def initialize(spec, options = {}) + @options = options + @spec = spec + @gem_dir = Bundler.rubygems.path(spec.full_gem_path) + @wrappers = true + @env_shebang = true + @format_executable = options[:format_executable] || false + @build_args = options[:build_args] || Bundler.rubygems.build_args + @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" + @disable_extensions = options[:disable_extensions] + @bin_dir = @gem_bin_dir + end + + def post_install + run_hooks(:pre_install) + + unless @disable_extensions + build_extensions + run_hooks(:post_build) + end + + generate_bin unless spec.executables.empty? + + run_hooks(:post_install) + end + + private + + def run_hooks(type) + hooks_meth = "#{type}_hooks" + return unless Gem.respond_to?(hooks_meth) + Gem.send(hooks_meth).each do |hook| + result = hook.call(self) + next unless result == false + location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ + message = "#{type} hook#{location} failed for #{spec.full_name}" + raise InstallHookError, message + end + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems.rb new file mode 100644 index 00000000..c69e386d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems.rb @@ -0,0 +1,606 @@ +# frozen_string_literal: true + +require "rubygems/user_interaction" + +module Bundler + class Source + class Rubygems < Source + autoload :Remote, File.expand_path("rubygems/remote", __dir__) + + # Ask for X gems per API request + API_REQUEST_SIZE = 100 + REQUIRE_MUTEX = Mutex.new + + attr_accessor :remotes, :remote_cooldowns + + def initialize(options = {}) + @options = options + @remotes = [] + @remote_cooldowns = {} + @dependency_names = [] + @allow_remote = false + @allow_cached = false + @allow_local = options["allow_local"] || false + @prefer_local = false + @checksum_store = Checksum::Store.new + @gem_installers = {} + @gem_installers_mutex = Mutex.new + @remote_specs_mutex = Mutex.new + + cooldown = options["cooldown"] + Array(options["remotes"]).reverse_each {|r| add_remote(r, cooldown: cooldown) } + + @lockfile_remotes = @remotes if options["from_lockfile"] + end + + def caches + @caches ||= [cache_path, *Bundler.rubygems.gem_cache] + end + + def prefer_local! + @prefer_local = true + end + + def local_only! + @specs = nil + @allow_local = true + @allow_cached = false + @allow_remote = false + end + + def local_only? + @allow_local && !@allow_remote + end + + def local! + return if @allow_local + + @specs = nil + @allow_local = true + end + + def remote! + return if @allow_remote + + @specs = nil + @allow_remote = true + end + + def cached! + return unless File.exist?(cache_path) + + return if @allow_cached + + @specs = nil + @allow_cached = true + end + + def hash + @remotes.hash + end + + def eql?(other) + other.is_a?(Rubygems) && other.credless_remotes == credless_remotes + end + + alias_method :==, :eql? + + def include?(o) + o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? + end + + def multiple_remotes? + @remotes.size > 1 + end + + def no_remotes? + @remotes.size == 0 + end + + def can_lock?(spec) + return super unless multiple_remotes? + include?(spec.source) + end + + def options + { "remotes" => @remotes.map(&:to_s) } + end + + def self.from_lock(options) + options["remotes"] = Array(options.delete("remote")).reverse + new(options.merge("from_lockfile" => true)) + end + + def to_lock + out = String.new("GEM\n") + lockfile_remotes.reverse_each do |remote| + out << " remote: #{remote}\n" + end + out << " specs:\n" + end + + def to_s + if remotes.empty? + "locally installed gems" + elsif @allow_remote && @allow_cached && @allow_local + "rubygems repository #{remote_names}, cached gems or installed locally" + elsif @allow_remote && @allow_local + "rubygems repository #{remote_names} or installed locally" + elsif @allow_remote + "rubygems repository #{remote_names}" + elsif @allow_cached && @allow_local + "cached gems or installed locally" + else + "locally installed gems" + end + end + + def identifier + if remotes.empty? + "locally installed gems" + else + "rubygems repository #{remote_names}" + end + end + alias_method :name, :identifier + alias_method :to_gemfile, :identifier + + def specs + @specs ||= begin + # remote_specs usually generates a way larger Index than the other + # sources, and large_idx.merge! small_idx is way faster than + # small_idx.merge! large_idx. + index = @allow_remote ? remote_specs.dup : Index.new + + # Snapshot per-version `created_at` from the remote info before installed + # / cached specs overwrite the EndpointSpecification objects that carry + # it. The cooldown filter consults `created_at` on every candidate, so + # local stubs need the published date back-filled to participate. + remote_created_at = collect_remote_created_at(index) + + index.merge!(cached_specs) if @allow_cached + index.merge!(installed_specs) if @allow_local + + if @allow_local + if @prefer_local + index.merge!(default_specs) + else + # complete with default specs, only if not already available in the + # index through remote, cached, or installed specs + index.use(default_specs) + end + end + + backfill_created_at(index, remote_created_at) unless remote_created_at.empty? + + index + end + end + + def download(spec, options = {}) + if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force]) + return true + end + + installer = rubygems_gem_installer(spec, options) + + if spec.remote + s = begin + installer.spec + rescue Gem::Package::FormatError + Bundler.rm_rf(installer.gem) + raise + rescue Gem::Security::Exception => e + raise SecurityError, + "The gem #{installer.gem} can't be installed because " \ + "the security policy didn't allow it, with the message: #{e.message}" + end + + spec.__swap__(s) + end + + spec + end + + def install(spec, options = {}) + if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force]) + print_using_message "Using #{version_message(spec, options[:previous_spec])}" + return nil # no post-install message + end + + return if Bundler.settings[:no_install] + + installer = rubygems_gem_installer(spec, options) + spec.source.checksum_store.register(spec, installer.gem_checksum) + + message = "Installing #{version_message(spec, options[:previous_spec])}" + message += " with native extensions" if spec.extensions.any? + Bundler.ui.confirm message + + installed_spec = nil + + Gem.time("Installed #{spec.name} in", 0, true) do + installed_spec = installer.install + end + + spec.full_gem_path = installed_spec.full_gem_path + spec.loaded_from = installed_spec.loaded_from + spec.base_dir = installed_spec.base_dir + + spec.post_install_message + end + + def cache(spec, custom_path = nil) + cached_path = Bundler.settings[:cache_all_platforms] ? fetch_gem_if_possible(spec) : cached_gem(spec) + raise GemNotFound, "Missing gem file '#{spec.file_name}'." unless cached_path + return if File.dirname(cached_path) == Bundler.app_cache.to_s + Bundler.ui.info " * #{File.basename(cached_path)}" + FileUtils.cp(cached_path, Bundler.app_cache(custom_path)) + rescue Errno::EACCES => e + Bundler.ui.debug(e) + raise InstallError, e.message + end + + def cached_built_in_gem(spec, local: false) + cached_path = cached_gem(spec) + if cached_path.nil? && !local + remote_spec = remote_spec_for(spec) + if remote_spec + cached_path = fetch_gem(remote_spec) + spec.remote = remote_spec.remote + else + Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it." + end + end + cached_path + end + + def add_remote(source, cooldown: nil) + uri = normalize_uri(source) + @remotes.unshift(uri) unless @remotes.include?(uri) + @remote_cooldowns[uri] = cooldown if cooldown + end + + def cooldown_for(uri) + @remote_cooldowns[uri] + end + + def spec_names + if dependency_api_available? + remote_specs.spec_names + else + [] + end + end + + def unmet_deps + if dependency_api_available? + remote_specs.unmet_dependency_names + else + [] + end + end + + def remote_fetchers + @remote_fetchers ||= remotes.to_h do |uri| + remote = Source::Rubygems::Remote.new(uri, cooldown: cooldown_for(uri)) + [remote, Bundler::Fetcher.new(remote)] + end.freeze + end + + def fetchers + @fetchers ||= remote_fetchers.values.freeze + end + + def double_check_for(unmet_dependency_names) + return unless dependency_api_available? + + unmet_dependency_names = unmet_dependency_names.call + unless unmet_dependency_names.nil? + if api_fetchers.size <= 1 + # can't do this when there are multiple fetchers because then we might not fetch from _all_ + # of them + unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten + end + return if unmet_dependency_names.empty? + end + + Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" + + fetch_names(api_fetchers, unmet_dependency_names, remote_specs) + + specs.use remote_specs + end + + def dependency_names_to_double_check + names = [] + remote_specs.each do |spec| + case spec + when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification + names.concat(spec.runtime_dependencies.map(&:name)) + when RemoteSpecification # from the full index + return nil + else + raise "unhandled spec type (#{spec.inspect})" + end + end + names + end + + def dependency_api_available? + @allow_remote && api_fetchers.any? + end + + def clear_cache + @specs = nil + @installed_specs = nil + @default_specs = nil + @cached_specs = nil + end + + def release_resolution_memory! + @specs = nil + @remote_specs_mutex.synchronize { @remote_specs = nil } + @fetchers&.each(&:release_resolution_memory!) + end + + protected + + def remote_names + remotes.map(&:to_s).join(", ") + end + + def credless_remotes + remotes.map(&method(:remove_auth)) + end + + def cached_gem(spec) + global_cache_path = download_cache_path(spec) + caches << global_cache_path if global_cache_path + + possibilities = caches.map {|p| package_path(p, spec) } + possibilities.find {|p| File.exist?(p) } + end + + def package_path(cache_path, spec) + "#{cache_path}/#{spec.file_name}" + end + + def normalize_uri(uri) + uri = URINormalizer.normalize_suffix(uri.to_s) + require_relative "../vendored_uri" + uri = Gem::URI(uri) + raise ArgumentError, "The source must be an absolute URI. For example:\n" \ + "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Gem::URI::HTTP) && uri.host.nil?) + uri + end + + def remove_auth(remote) + if remote.user || remote.password + remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s + else + remote.to_s + end + end + + def installed_specs + @installed_specs ||= Index.build do |idx| + Bundler.rubygems.installed_specs.reverse_each do |spec| + spec.source = self + next if spec.ignored? + idx << spec + end + end + end + + def default_specs + @default_specs ||= Index.build do |idx| + Bundler.rubygems.default_specs.each do |spec| + spec.source = self + idx << spec + end + end + end + + def cached_specs + @cached_specs ||= begin + idx = Index.new + + SharedHelpers.glob_files_in_dir("*.gem", cache_path.to_s).each do |gemfile| + s ||= Bundler.rubygems.spec_from_gem(gemfile) + s.source = self + idx << s + end + + idx + end + end + + def api_fetchers + fetchers.select(&:api_fetcher?) + end + + def remote_specs + @remote_specs ||= @remote_specs_mutex.synchronize do + @remote_specs ||= Index.build do |idx| + index_fetchers = fetchers - api_fetchers + + if index_fetchers.empty? + fetch_names(api_fetchers, dependency_names, idx) + else + fetch_names(fetchers, nil, idx) + end + end + end + end + + # Looks up a single spec in the remote sources, fetching only its own + # name when the full remote index is not already materialized. + def remote_spec_for(spec) + return remote_specs.search(spec).first if @remote_specs || api_fetchers.empty? + + index = Index.build do |idx| + fetch_names(api_fetchers, [spec.name], idx) + end + index.search(spec).first + end + + def fetch_names(fetchers, dependency_names, index) + fetchers.each do |f| + if dependency_names + Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug? + index.use f.specs_with_retry(dependency_names, self) + Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over + else + Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}" + index.use f.specs_with_retry(nil, self) + end + end + end + + def fetch_gem_if_possible(spec, previous_spec = nil) + if spec.remote + fetch_gem(spec, previous_spec) + else + cached_gem(spec) + end + end + + def fetch_gem(spec, previous_spec = nil) + spec.fetch_platform + + cache_path = download_cache_path(spec) || default_cache_path_for(rubygems_dir) + gem_path = package_path(cache_path, spec) + return gem_path if File.exist?(gem_path) + + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end + download_gem(spec, cache_path, previous_spec) + + gem_path + end + + def installed?(spec) + installed_specs[spec].any? && !spec.installation_missing? + end + + def rubygems_dir + Bundler.bundle_path + end + + def default_cache_path_for(dir) + "#{dir}/cache" + end + + def cache_path + Bundler.app_cache + end + + private + + def collect_remote_created_at(index) + return {} unless @allow_remote + + snapshot = {} + index.each do |spec| + next unless spec.respond_to?(:created_at) && spec.created_at + # Remember the remote that supplied the date too: when a source has + # several remotes with different per-URI cooldown settings we must + # restore the same one during backfill so `effective_cooldown` agrees. + snapshot[[spec.name, spec.version]] = [spec.created_at, spec.remote] + end + snapshot + end + + def backfill_created_at(index, snapshot) + index.each do |spec| + next unless spec.respond_to?(:created_at=) + next if spec.created_at + remote_created_at, remote = snapshot[[spec.name, spec.version]] + next unless remote_created_at + spec.created_at = remote_created_at + spec.remote ||= remote if remote && spec.respond_to?(:remote=) + end + end + + def lockfile_remotes + @lockfile_remotes || credless_remotes + end + + # Checks if the requested spec exists in the global cache. If it does, + # we copy it to the download path, and if it does not, we download it. + # + # @param [Specification] spec + # the spec we want to download or retrieve from the cache. + # + # @param [String] download_cache_path + # the local directory the .gem will end up in. + # + # @param [Specification] previous_spec + # the spec previously locked + # + def download_gem(spec, download_cache_path, previous_spec = nil) + uri = spec.remote.uri + Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}") + gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher + + Gem.time("Downloaded #{spec.name} in", 0, true) do + Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher) + end + end + + # Returns the global cache path of the calling Rubygems::Source object. + # + # Note that the Source determines the path's subdirectory. We use this + # subdirectory in the global cache path so that gems with the same name + # -- and possibly different versions -- from different sources are saved + # to their respective subdirectories and do not override one another. + # + # @param [Gem::Specification] specification + # + # @return [Pathname] The global cache path. + # + def download_cache_path(spec) + return unless Bundler.settings[:global_gem_cache] + return unless remote = spec.remote + return unless cache_slug = remote.cache_slug + + Bundler.user_cache.join("gems", cache_slug) + end + + def extension_cache_slug(spec) + return unless remote = spec.remote + remote.cache_slug + end + + # We are using a mutex to reaed and write from/to the hash. + # The reason this double synchronization was added is for performance + # and to lock the mutex for the shortest possible amount of time. Otherwise, + # all threads are fighting over this mutex and when it gets acquired it gets locked + # until a threads finishes downloading a gem, leaving the other threads waiting + # doing nothing. + def rubygems_gem_installer(spec, options) + @gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin + path = fetch_gem_if_possible(spec, options[:previous_spec]) + raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path + + REQUIRE_MUTEX.synchronize { require_relative "../rubygems_gem_installer" } + + installer = Bundler::RubyGemsGemInstaller.at( + path, + security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]], + install_dir: rubygems_dir.to_s, + bin_dir: Bundler.system_bindir.to_s, + ignore_dependencies: true, + wrappers: true, + env_shebang: true, + build_args: options[:build_args], + bundler_extension_cache_path: extension_cache_path(spec) + ) + @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer } + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems/remote.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems/remote.rb new file mode 100644 index 00000000..3d847424 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems/remote.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Rubygems + class Remote + attr_reader :uri, :anonymized_uri, :original_uri, :cooldown + + def initialize(uri, cooldown: nil) + orig_uri = uri + uri = Bundler.settings.mirror_for(uri) + @original_uri = orig_uri if orig_uri != uri + fallback_auth = Bundler.settings.credentials_for(uri) + + @uri = apply_auth(uri, fallback_auth).freeze + @anonymized_uri = remove_auth(@uri).freeze + @cooldown = cooldown + end + + # Returns the cooldown days that apply to this remote, resolving the + # precedence CLI > config > Gemfile per-source. Returns nil if no + # cooldown applies. + def effective_cooldown + override = Bundler.settings[:cooldown] + return override if override + @cooldown + end + + MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length + private_constant :MAX_CACHE_SLUG_HOST_SIZE + + # @return [String] A slug suitable for use as a cache key for this + # remote. + # + def cache_slug + @cache_slug ||= begin + return nil unless SharedHelpers.md5_available? + + cache_uri = original_uri || uri + + host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host + + uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] + uri_parts.compact! + uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.join(".")) + + uri_parts.pop + host_parts = uri_parts.join(".") + return uri_digest if host_parts.empty? + + shortened_host_parts = host_parts[0...MAX_CACHE_SLUG_HOST_SIZE] + [shortened_host_parts, uri_digest].join(".") + end + end + + def to_s + "rubygems remote at #{anonymized_uri}" + end + + private + + def apply_auth(uri, auth) + if auth && uri.userinfo.nil? + uri = uri.dup + uri.userinfo = auth + end + + uri + rescue Gem::URI::InvalidComponentError + error_message = "Please CGI escape your usernames and passwords before " \ + "setting them for authentication." + raise HTTPError.new(error_message) + end + + def remove_auth(uri) + if uri.userinfo + uri = uri.dup + uri.user = uri.password = nil + end + + uri + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems_aggregate.rb b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems_aggregate.rb new file mode 100644 index 00000000..8aeaa375 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source/rubygems_aggregate.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Bundler + class Source + class RubygemsAggregate + attr_reader :source_map, :sources + + def initialize(sources, source_map, excluded_sources = []) + @sources = sources + @source_map = source_map + @excluded_sources = excluded_sources + + @index = build_index + end + + def specs + @index + end + + def identifier + to_s + end + + def to_s + "any of the sources" + end + + private + + def build_index + Index.build do |idx| + dependency_names = source_map.pinned_spec_names + + sources.all_sources.each do |source| + next if @excluded_sources.include?(source) + + source.dependency_names = dependency_names - source_map.pinned_spec_names(source) + idx.add_source source.specs + dependency_names.concat(source.unmet_deps).uniq! + end + + double_check_for_index(idx, dependency_names) + end + end + + # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both + # sources A and B. At this point, the API request will have found all the versions of Bar in source A, + # but will not have found any versions of Bar from source B, which is a problem if the requested version + # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for + # each spec we found, we add all possible versions from all sources to the index. + def double_check_for_index(idx, dependency_names) + pinned_names = source_map.pinned_spec_names + + names = :names # do this so we only have to traverse to get dependency_names from the index once + unmet_dependency_names = lambda do + return names unless names == :names + new_names = sources.all_sources.map(&:dependency_names_to_double_check) + return names = nil if new_names.compact! + names = new_names.flatten(1).concat(dependency_names) + names.uniq! + names -= pinned_names + names + end + + sources.all_sources.each do |source| + source.double_check_for(unmet_dependency_names) + end + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source_list.rb b/bin/gems/bundler-4.0.21/lib/bundler/source_list.rb new file mode 100644 index 00000000..ea59ecdd --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source_list.rb @@ -0,0 +1,269 @@ +# frozen_string_literal: true + +module Bundler + class SourceList + attr_reader :path_sources, + :git_sources, + :plugin_sources, + :global_path_source, + :metadata_source + + def global_rubygems_source + @global_rubygems_source ||= source_class.new("allow_local" => true) + end + + def initialize + @path_sources = [] + @git_sources = [] + @plugin_sources = [] + @global_rubygems_source = nil + @global_path_source = nil + @rubygems_sources = [] + @metadata_source = Source::Metadata.new + + @local_mode = true + end + + def aggregate_global_source? + global_rubygems_source.multiple_remotes? + end + + def implicit_global_source? + global_rubygems_source.no_remotes? + end + + def add_path_source(options = {}) + if options["gemspec"] + add_source_to_list Source::Gemspec.new(options), path_sources + else + path_source = add_source_to_list Source::Path.new(options), path_sources + @global_path_source ||= path_source if options["global"] + path_source + end + end + + def add_git_source(options = {}) + add_source_to_list(Source::Git.new(options), git_sources).tap do |source| + warn_on_git_protocol(source) + end + end + + def add_rubygems_source(options = {}) + new_source = Source::Rubygems.new(options) + if @global_rubygems_source == new_source + warn_on_cooldown_conflict(new_source, @global_rubygems_source) + return @global_rubygems_source + end + + existing_source = @rubygems_sources.find {|s| s == new_source } + warn_on_cooldown_conflict(new_source, existing_source) if existing_source + + add_source_to_list new_source, @rubygems_sources + end + + def add_plugin_source(source, options = {}) + add_source_to_list Plugin.source(source).new(options), @plugin_sources + end + + def add_global_rubygems_remote(uri, cooldown: nil) + unless cooldown.nil? + new_source = source_class.new("remotes" => uri, "cooldown" => cooldown) + [global_rubygems_source, *@rubygems_sources].find do |existing_source| + warn_on_cooldown_conflict(new_source, existing_source) + end + end + + global_rubygems_source.add_remote(uri, cooldown: cooldown) + global_rubygems_source + end + + def local_mode? + @local_mode + end + + def default_source + global_path_source || global_rubygems_source + end + + def rubygems_sources + non_global_rubygems_sources + [global_rubygems_source] + end + + def non_global_rubygems_sources + @rubygems_sources + end + + def all_sources + path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] + end + + def non_default_explicit_sources + all_sources - [default_source, metadata_source] + end + + def get(source) + source_list_for(source).find {|s| s.include?(source) } + end + + def lock_sources + lock_other_sources + lock_rubygems_sources + end + + def lock_other_sources + (path_sources + git_sources + plugin_sources).sort_by(&:identifier) + end + + def lock_rubygems_sources + rubygems_sources.sort_by(&:identifier) + end + + # Returns true if there are changes + def replace_sources!(replacement_sources) + return false if replacement_sources.empty? + + @rubygems_sources, @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) + @global_rubygems_source = global_replacement_source(replacement_sources) + + !equivalent_sources?(lock_sources, replacement_sources) + end + + def prefer_local! + all_sources.each(&:prefer_local!) + end + + def local_only! + all_sources.each(&:local_only!) + end + + def local! + all_sources.each(&:local!) + end + + def cached! + all_sources.each(&:cached!) + end + + def remote! + @local_mode = false + + all_sources.each(&:remote!) + end + + def clear_cache + rubygems_sources.each(&:clear_cache) + end + + def release_resolution_memory! + rubygems_sources.each(&:release_resolution_memory!) + end + + private + + def map_sources(replacement_sources) + rubygems = @rubygems_sources.map do |source| + replace_rubygems_source(replacement_sources, source) + end + + git, plugin = [@git_sources, @plugin_sources].map do |sources| + sources.map do |source| + replace_source(replacement_sources, source) + end + end + + path = @path_sources.map do |source| + replace_path_source(replacement_sources, source) + end + + [rubygems, path, git, plugin] + end + + def global_replacement_source(replacement_sources) + replace_rubygems_source(replacement_sources, global_rubygems_source, &:local!) + end + + def replace_rubygems_source(replacement_sources, gemfile_source) + replace_source(replacement_sources, gemfile_source) do |replacement_source| + # locked sources never include credentials so always prefer remotes from the gemfile + replacement_source.remotes = gemfile_source.remotes + + # cooldowns are only ever declared in the Gemfile, so carry them over + # along with the remotes they apply to + replacement_source.remote_cooldowns = gemfile_source.remote_cooldowns + + yield replacement_source if block_given? + + replacement_source + end + end + + def replace_source(replacement_sources, gemfile_source) + replacement_source = replacement_sources.find {|s| s == gemfile_source } + return gemfile_source unless replacement_source + + replacement_source = yield(replacement_source) if block_given? + + replacement_source + end + + def replace_path_source(replacement_sources, gemfile_source) + replace_source(replacement_sources, gemfile_source) do |replacement_source| + if gemfile_source.is_a?(Source::Gemspec) + gemfile_source.checksum_store = replacement_source.checksum_store + gemfile_source + else + replacement_source + end + end + end + + def source_class + Source::Rubygems + end + + def add_source_to_list(source, list) + list.unshift(source).uniq! + source + end + + def source_list_for(source) + case source + when Source::Git then git_sources + when Source::Path then path_sources + when Source::Rubygems then rubygems_sources + when Plugin::API::Source then plugin_sources + else raise ArgumentError, "Invalid source: #{source.inspect}" + end + end + + def warn_on_cooldown_conflict(new_source, existing_source) + new_source.remote_cooldowns.any? do |uri, cooldown| + next false unless existing_source.remotes.include?(uri) + + existing_cooldown = existing_source.cooldown_for(uri) + next false if existing_cooldown == cooldown + + previous = existing_cooldown ? "`cooldown: #{existing_cooldown}`" : "no cooldown" + Bundler.ui.warn "The source #{uri} is declared more than once with different cooldown " \ + "values (`cooldown: #{cooldown}` here, #{previous} previously). All declarations of " \ + "the same source URL share a single cooldown, so only one of these values will apply " \ + "to all gems from this source." + true + end + end + + def warn_on_git_protocol(source) + return if Bundler.settings["git.allow_insecure"] + + if /^git\:/.match?(source.uri) + Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \ + "which transmits data without encryption. Disable this warning with " \ + "`bundle config set --local git.allow_insecure true`, or switch to the `https` " \ + "protocol to keep your data secure." + end + end + + def equivalent_sources?(lock_sources, replacement_sources) + lock_sources.sort_by(&:identifier) == replacement_sources.sort_by(&:identifier) + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/source_map.rb b/bin/gems/bundler-4.0.21/lib/bundler/source_map.rb new file mode 100644 index 00000000..513eb37f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/source_map.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Bundler + class SourceMap + attr_reader :sources, :dependencies, :locked_specs + + def initialize(sources, dependencies, locked_specs) + @sources = sources + @dependencies = dependencies + @locked_specs = locked_specs + end + + def pinned_spec_names(skip = nil) + direct_requirements.reject {|_, source| source == skip }.keys + end + + def all_requirements(excluded_sources = []) + requirements = direct_requirements.dup + + explicit_sources = sources.non_default_explicit_sources.reject do |source| + excluded_sources.include?(source) + end + + unmet_deps = explicit_sources.map do |source| + (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| + previous_source = requirements[indirect_dependency_name] + if previous_source.nil? + requirements[indirect_dependency_name] = source + else + msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] + msg.concat [previous_source, source].map {|s| " * #{s}" }.sort + msg << "You must add this gem to the source block for the source you wish it to be installed from." + msg = msg.join("\n") + + raise SecurityError, msg + end + end + + source.unmet_deps + end + + sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) + + requirements + end + + def direct_requirements + @direct_requirements ||= begin + requirements = {} + default = sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + dep_source.add_dependency_names(dep.name) + requirements[dep.name] = dep_source + end + requirements + end + end + + def locked_requirements + @locked_requirements ||= begin + requirements = {} + locked_specs.each do |locked_spec| + source = locked_spec.source + source.add_dependency_names(locked_spec.name) + requirements[locked_spec.name] = source + end + requirements + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/spec_set.rb b/bin/gems/bundler-4.0.21/lib/bundler/spec_set.rb new file mode 100644 index 00000000..98bec709 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/spec_set.rb @@ -0,0 +1,390 @@ +# frozen_string_literal: true + +require_relative "vendored_tsort" + +module Bundler + class SpecSet + include Enumerable + include Gem::TSort + + def initialize(specs) + @specs = specs + end + + def for(dependencies, platforms = [nil], legacy_platforms = [nil], skips: []) + if [true, false].include?(platforms) + Bundler::SharedHelpers.feature_removed! \ + "SpecSet#for received a `check` parameter, but that's no longer used and deprecated. " \ + "SpecSet#for always implicitly performs validation. Please remove this parameter" + end + + materialize_dependencies(dependencies, platforms, skips: skips) + + @materializations.flat_map(&:specs).uniq + end + + def normalize_platforms!(deps, platforms) + remove_invalid_platforms!(deps, platforms) + add_extra_platforms!(platforms) + + platforms.map! do |platform| + next platform if platform == Gem::Platform::RUBY + + begin + Integer(platform.version) + rescue ArgumentError, TypeError + next platform + end + + less_specific_platform = Gem::Platform.new([platform.cpu, platform.os, nil]) + next platform if incomplete_for_platform?(deps, less_specific_platform) + + less_specific_platform + end.uniq! + end + + def add_originally_invalid_platforms!(platforms, originally_invalid_platforms) + originally_invalid_platforms.each do |originally_invalid_platform| + platforms << originally_invalid_platform if complete_platform(originally_invalid_platform) + end + end + + def remove_invalid_platforms!(deps, platforms, skips: []) + invalid_platforms = [] + + platforms.reject! do |platform| + next false if skips.include?(platform) + + invalid = incomplete_for_platform?(deps, platform) + invalid_platforms << platform if invalid + invalid + end + + invalid_platforms + end + + def add_extra_platforms!(platforms) + if @specs.empty? + platforms.concat([Gem::Platform::RUBY]).uniq + return + end + + new_platforms = all_platforms.select do |platform| + next if platforms.include?(platform) + next unless Gem::Platform.generic(platform) == Gem::Platform::RUBY + + complete_platform(platform) + end + return if new_platforms.empty? + + platforms.concat(new_platforms) + return if new_platforms.include?(Bundler.local_platform) + + less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform } + platforms.delete(Bundler.local_platform) if less_specific_platform + end + + def validate_deps(s) + s.runtime_dependencies.each do |dep| + next if dep.name == "bundler" + + return :missing unless names.include?(dep.name) + return :invalid if none? {|spec| dep.matches_spec?(spec) } + end + + :valid + end + + def [](key) + key = key.name if key.respond_to?(:name) + lookup[key]&.reverse || [] + end + + def []=(key, value) + delete_by_name(key) + + add_spec(value) + end + + def delete(specs) + Array(specs).each {|spec| remove_spec(spec) } + end + + def sort! + self + end + + def to_a + sorted.dup + end + + def to_hash + lookup.dup + end + + def materialize(deps) + materialize_dependencies(deps) + + SpecSet.new(materialized_specs) + end + + # Materialize for all the specs in the spec set, regardless of what platform they're for + # @return [Array] + def materialized_for_all_platforms + @specs.map do |s| + next s unless s.is_a?(LazySpecification) + spec = s.materialize_for_cache + raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec + spec + end + end + + def incomplete_for_platform?(deps, platform) + incomplete_specs_for_platform(deps, platform).any? + end + + def incomplete_specs_for_platform(deps, platform) + return [] if @specs.empty? + + validation_set = self.class.new(@specs) + validation_set.for(deps, [platform]) + validation_set.incomplete_specs + end + + def missing_specs_for(deps) + materialize_dependencies(deps) + + missing_specs + end + + def missing_specs + @materializations.flat_map(&:completely_missing_specs) + end + + def partially_missing_specs + @materializations.flat_map(&:partially_missing_specs) + end + + def incomplete_specs + @materializations.flat_map(&:incomplete_specs) + end + + def insecurely_materialized_specs + materialized_specs.select(&:insecurely_materialized?) + end + + def -(other) + SharedHelpers.feature_removed! "SpecSet#- has been removed with no replacement" + end + + def find_by_name_and_platform(name, platform) + @specs.detect {|spec| spec.name == name && spec.installable_on_platform?(platform) } + end + + def specs_with_additional_variants_from(other) + sorted | additional_variants_from(other) + end + + def delete_by_name(name) + @specs.reject! {|spec| spec.name == name } + @sorted&.reject! {|spec| spec.name == name } + return if @lookup.nil? + + @lookup[name] = nil + end + + def version_for(name) + exemplary_spec(name)&.version + end + + def what_required(spec) + unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } } + return [spec] + end + what_required(req) << spec + end + + def <<(spec) + SharedHelpers.feature_removed! "SpecSet#<< has been removed with no replacement" + end + + def length + @specs.length + end + + def size + @specs.size + end + + def empty? + @specs.empty? + end + + def each(&b) + sorted.each(&b) + end + + def names + lookup.keys + end + + def valid?(s) + s.matches_current_metadata? && valid_dependencies?(s) + end + + def to_s + map(&:full_name).to_s + end + + private + + def materialize_dependencies(dependencies, platforms = [nil], skips: []) + handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h + deps = dependencies.product(platforms) + @materializations = [] + + loop do + break unless dep = deps.shift + + dependency = dep[0] + platform = dep[1] + name = dependency.name + + key = [name, platform] + next if handled.key?(key) + + handled[key] = true + + materialization = Materialization.new(dependency, platform, candidates: lookup[name]) + + deps.concat(materialization.dependencies) if materialization.complete? + + @materializations << materialization unless skips.include?(name) + end + + @materializations + end + + def materialized_specs + @materializations.filter_map(&:materialized_spec) + end + + def complete_platform(platform) + new_specs = [] + + valid_platform = lookup.all? do |_, specs| + spec = specs.first + matching_specs = spec.source.specs.search([spec.name, spec.version]) + platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s| + valid?(s) + end + + if platform_spec + new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec) + true + else + false + end + end + + if valid_platform && new_specs.any? + new_specs.each {|spec| add_spec(spec) } + end + + valid_platform + end + + def all_platforms + @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq + end + + def additional_variants_from(other) + other.select do |other_spec| + spec = exemplary_spec(other_spec.name) + next unless spec + + selected = spec.version == other_spec.version && valid_dependencies?(other_spec) + other_spec.source = spec.source if selected + selected + end + end + + def valid_dependencies?(s) + validate_deps(s) == :valid + end + + def sorted + @sorted ||= ([@specs.find {|s| s.name == "rake" }] + tsort).compact.uniq + rescue Gem::TSort::Cyclic => error + cgems = extract_circular_gems(error) + raise CyclicDependencyError, "Your bundle requires gems that depend" \ + " on each other, creating an infinite loop. Please remove either" \ + " gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again." + end + + def extract_circular_gems(error) + error.message.scan(/@name="(.*?)"/).flatten + end + + def lookup + @lookup ||= begin + lookup = {} + @specs.each do |s| + index_spec(lookup, s.name, s) + end + lookup + end + end + + def tsort_each_node + # MUST sort by name for backwards compatibility + @specs.sort_by(&:name).each {|s| yield s } + end + + def tsort_each_child(s) + s.dependencies.sort_by(&:name).each do |d| + next if d.type == :development + + specs_for_name = lookup[d.name] + next unless specs_for_name + + specs_for_name.each {|s2| yield s2 } + end + end + + def add_spec(spec) + @specs << spec + + name = spec.name + + @sorted&.insert(@sorted.bsearch_index {|s| s.name >= name } || @sorted.size, spec) + return if @lookup.nil? + + index_spec(@lookup, name, spec) + end + + def remove_spec(spec) + @specs.delete(spec) + @sorted&.delete(spec) + return if @lookup.nil? + + indexed_specs = @lookup[spec.name] + return unless indexed_specs + + if indexed_specs.size > 1 + @lookup[spec.name].delete(spec) + else + @lookup[spec.name] = nil + end + end + + def index_spec(hash, key, value) + hash[key] ||= [] + hash[key] << value + end + + def exemplary_spec(name) + self[name].first + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/stub_specification.rb b/bin/gems/bundler-4.0.21/lib/bundler/stub_specification.rb new file mode 100644 index 00000000..6de398a1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/stub_specification.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +module Bundler + class StubSpecification < RemoteSpecification + def self.from_stub(stub) + return stub if stub.is_a?(Bundler::StubSpecification) + spec = new(stub.name, stub.version, stub.platform, nil) + spec.stub = stub + spec + end + + def insecurely_materialized? + false + end + + attr_reader :checksum + attr_accessor :stub, :ignored + + def source=(source) + super + # Stub has no concept of source, which means that extension_dir may be wrong + # This is the case for git-based gems. So, instead manually assign the extension dir + return unless source.respond_to?(:extension_dir_name) + unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-") + path = File.join(stub.extensions_dir, unique_extension_dir) + stub.extension_dir = File.expand_path(path) + end + + def to_yaml + _remote_specification.to_yaml + end + + # @!group Stub Delegates + + def ignored? + return @ignored unless @ignored.nil? + + @ignored = missing_extensions? + return false unless @ignored + + warn "Source #{source} is ignoring #{self} because it is missing extensions" + + true + end + + def manually_installed? + # This is for manually installed gems which are gems that were fixed in place after a + # failed installation. Once the issue was resolved, the user then manually created + # the gem specification using the instructions provided by `gem help install` + installed_by_version == Gem::Version.new(0) + end + + # This is defined directly to avoid having to loading the full spec + def missing_extensions? + return false if RUBY_ENGINE == "jruby" + return false if default_gem? + return false if extensions.empty? + return false if File.exist? gem_build_complete_path + return false if manually_installed? + + true + end + + def activated? + stub.activated? + end + + def activated=(activated) + stub.instance_variable_set(:@activated, activated) + end + + def extensions + stub.extensions + end + + def gem_build_complete_path + stub.gem_build_complete_path + end + + def default_gem? + stub.default_gem? + end + + def full_gem_path + stub.full_gem_path + end + + def full_gem_path=(path) + stub.full_gem_path = path + end + + def full_require_paths + stub.full_require_paths + end + + def require_paths + stub.require_paths + end + + def base_dir=(path) + stub.base_dir = path + end + + def load_paths + full_require_paths + end + + def loaded_from + stub.loaded_from + end + + def matches_for_glob(glob) + stub.matches_for_glob(glob) + end + + def raw_require_paths + stub.raw_require_paths + end + + def inspect + "#<#{self.class} @name=\"#{name}\" (#{full_name.delete_prefix("#{name}-")})>" + end + + private + + def _remote_specification + @_remote_specification ||= begin + rs = stub.to_spec + # Gem::StubSpecification#to_spec may return an activated specification + # with the same name and version from a different gem installation. + if rs.equal?(self) || rs.loaded_from != loaded_from + rs = Gem::Specification.load(loaded_from) + Bundler.rubygems.stub_set_spec(stub, rs) + end + + unless rs + raise GemspecError, "The gemspec for #{full_name} at #{loaded_from}" \ + " was missing or broken. Try running `gem pristine #{name} -v #{version}`" \ + " to fix the cached spec." + end + + rs.source = source + rs.base_dir = stub.base_dir + + rs + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/.document b/bin/gems/bundler-4.0.21/lib/bundler/templates/.document new file mode 100644 index 00000000..fb66f13c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/.document @@ -0,0 +1 @@ +# Ignore all files in this directory diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable b/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable new file mode 100644 index 00000000..b085c24d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable @@ -0,0 +1,16 @@ +#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '<%= executable %>' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__) + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("<%= spec.name %>", "<%= executable %>") diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable.standalone b/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable.standalone new file mode 100644 index 00000000..3117a27e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/Executable.standalone @@ -0,0 +1,14 @@ +#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '<%= executable %>' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +$:.unshift File.expand_path "<%= standalone_path %>", __dir__ + +require "bundler/setup" +load File.expand_path "<%= executable_path %>", __dir__ diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/Gemfile b/bin/gems/bundler-4.0.21/lib/bundler/templates/Gemfile new file mode 100644 index 00000000..d2403f18 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# gem "rails" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CHANGELOG.md.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CHANGELOG.md.tt new file mode 100644 index 00000000..c9ea96d4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CHANGELOG.md.tt @@ -0,0 +1,5 @@ +## [Unreleased] + +## [0.1.0] - <%= Time.now.strftime('%F') %> + +- Initial release diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt new file mode 100644 index 00000000..633baebd --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt @@ -0,0 +1,10 @@ +# Code of Conduct + +<%= config[:name].inspect %> follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in 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. + +If you have any concerns about behaviour within this project, please contact us at [<%= config[:email].inspect %>](mailto:<%= config[:email].inspect %>). diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Cargo.toml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Cargo.toml.tt new file mode 100644 index 00000000..cd00f97e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Cargo.toml.tt @@ -0,0 +1,13 @@ +# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is +# a Rust project. Your extensions dependencies should be added to the Cargo.toml +# in the ext/ directory. + +[workspace] +members = ["./ext/<%= config[:name] %>"] +resolver = "2" + +[profile.release] +# By default, debug symbols are stripped from the final binary which makes it +# harder to debug if something goes wrong. It's recommended to keep debug +# symbols in the release build so that you can debug the final binary if needed. +debug = true diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Gemfile.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Gemfile.tt new file mode 100644 index 00000000..ea7a33ee --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Gemfile.tt @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in <%= config[:name] %>.gemspec +gemspec + +gem "irb" +gem "rake", "~> 13.0" +<%- if config[:ext] -%> + +gem "rake-compiler" +<%- end -%> +<%- if config[:test] -%> + +gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>" +<%- end -%> +<%- if config[:linter] == "rubocop" -%> + +gem "rubocop", "~> <%= config[:linter_version] %>" +<%- elsif config[:linter] == "standard" -%> + +gem "standard", "~> <%= config[:linter_version] %>" +<%- end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/LICENSE.txt.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/LICENSE.txt.tt new file mode 100644 index 00000000..76ef4b01 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/LICENSE.txt.tt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) <%= Time.now.year %> <%= config[:author] %> + +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/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/README.md.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/README.md.tt new file mode 100644 index 00000000..0ec6a12f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/README.md.tt @@ -0,0 +1,49 @@ +# <%= config[:constant_name] %> + +TODO: Delete this and the text below, and describe your gem + +Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. + +## Installation + +TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org. + +Install the gem and add to the application's Gemfile by executing: + +```bash +bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG +``` + +If bundler is not being used to manage dependencies, install the gem by executing: + +```bash +gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG +``` + +## Usage + +TODO: Write usage instructions here + +## Development + +After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test_task] %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). +<% if config[:git] -%> + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %> +<% end -%> +<% if config[:mit] -%> + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). +<% end -%> +<% if config[:git] && config[:coc] -%> + +## Code of Conduct + +Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md). +<% end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Rakefile.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Rakefile.tt new file mode 100644 index 00000000..83f10009 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/Rakefile.tt @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +<% default_task_names = [config[:test_task]].compact -%> +<% case config[:test] -%> +<% when "minitest" -%> +require "minitest/test_task" + +Minitest::TestTask.create + +<% when "test-unit" -%> +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/**/*_test.rb"] +end + +<% when "rspec" -%> +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +<% end -%> +<% if config[:linter] == "rubocop" -%> +<% default_task_names << :rubocop -%> +require "rubocop/rake_task" + +RuboCop::RakeTask.new + +<% elsif config[:linter] == "standard" -%> +<% default_task_names << :standard -%> +require "standard/rake" + +<% end -%> +<% if config[:ext] -%> +<% default_task_names.unshift(:compile) -%> +<% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%> +<% if config[:ext] == 'rust' -%> +require "rb_sys/extensiontask" + +task build: :compile + +GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec") + +RbSys::ExtensionTask.new(<%= config[:name].inspect %>, GEMSPEC) do |ext| + ext.lib_dir = "lib/<%= config[:namespaced_path] %>" +end +<% else -%> +require "rake/extensiontask" + +task build: :compile + +GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec") + +Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext| + ext.lib_dir = "lib/<%= config[:namespaced_path] %>" +end +<% end -%> + +<% if config[:ext] == "go" -%> +require "go_gem/rake_task" + +GoGem::RakeTask.new("<%= config[:underscored_name] %>") +<% end -%> +<% end -%> +<% if default_task_names.size == 1 -%> +task default: <%= default_task_names.first.inspect %> +<% else -%> +task default: %i[<%= default_task_names.join(" ") %>] +<% end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/console.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/console.tt new file mode 100644 index 00000000..c91ee65f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/console.tt @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "<%= config[:namespaced_path] %>" + +# 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. + +require "irb" +IRB.start(__FILE__) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/setup.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/setup.tt new file mode 100644 index 00000000..dce67d86 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/bin/setup.tt @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/circleci/config.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/circleci/config.yml.tt new file mode 100644 index 00000000..c4dd9d06 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/circleci/config.yml.tt @@ -0,0 +1,37 @@ +version: 2.1 +jobs: + build: + docker: + - image: ruby:<%= RUBY_VERSION %> +<%- if config[:ext] == 'rust' -%> + environment: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> +<%- if config[:ext] == 'go' -%> + environment: + GO_VERSION: '1.23.0' +<%- end -%> + steps: + - checkout +<%- if config[:ext] == 'rust' -%> + - run: + name: Install Rust/Cargo dependencies + command: apt-get update && apt-get install -y clang + - run: + name: Install a RubyGems version that can compile rust extensions + command: gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> +<%- if config[:ext] == 'go' -%> + - run: + name: Install Go + command: | + wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz + tar -C /usr/local -xzf /tmp/go.tar.gz + echo 'export PATH=/usr/local/go/bin:"$PATH"' >> "$BASH_ENV" +<%- end -%> + - run: + name: Run the default task + command: | + gem install bundler -v <%= Bundler::VERSION %> + bundle install + bundle exec rake diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/exe/newgem.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/exe/newgem.tt new file mode 100644 index 00000000..a8339bb7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/exe/newgem.tt @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +require "<%= config[:namespaced_path] %>" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt new file mode 100644 index 00000000..a06166ae --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt @@ -0,0 +1,22 @@ +[package] +name = <%= config[:name].inspect %> +version = "0.1.0" +edition = "2021" +authors = ["<%= config[:author] %> <<%= config[:email] %>>"] +<%- if config[:mit] -%> +license = "MIT" +<%- end -%> +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +magnus = { version = "0.8.2" } +rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] } + +[build-dependencies] +rb-sys-env = "0.2.2" + +[dev-dependencies] +rb-sys-test-helpers = { version = "0.2.2" } diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/build.rs.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/build.rs.tt new file mode 100644 index 00000000..80a78427 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/build.rs.tt @@ -0,0 +1,5 @@ +pub fn main() -> Result<(), Box> { + let _ = rb_sys_env::activate()?; + + Ok(()) +} diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt new file mode 100644 index 00000000..0a0c5a3d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "mkmf" + +# Makes all symbols private by default to avoid unintended conflict +# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED +# selectively, or entirely remove this flag. +append_cflags("-fvisibility=hidden") + +create_makefile(<%= config[:makefile_path].inspect %>) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt new file mode 100644 index 00000000..a689e21e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-go.rb.tt @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "mkmf" +require "go_gem/mkmf" + +# Makes all symbols private by default to avoid unintended conflict +# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED +# selectively, or entirely remove this flag. +append_cflags("-fvisibility=hidden") + +create_go_makefile(<%= config[:makefile_path].inspect %>) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt new file mode 100644 index 00000000..e24566a1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "mkmf" +require "rb_sys/mkmf" + +create_rust_makefile(<%= config[:makefile_path].inspect %>) diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/go.mod.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/go.mod.tt new file mode 100644 index 00000000..3f4819d0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/go.mod.tt @@ -0,0 +1,5 @@ +module github.com/<%= config[:go_module_username] %>/<%= config[:underscored_name] %> + +go 1.23 + +require github.com/ruby-go-gem/go-gem-wrapper latest diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt new file mode 100644 index 00000000..119c0c96 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem-go.c.tt @@ -0,0 +1,2 @@ +#include "<%= config[:underscored_name] %>.h" +#include "_cgo_export.h" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt new file mode 100644 index 00000000..bcd51485 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt @@ -0,0 +1,9 @@ +#include "<%= config[:underscored_name] %>.h" + +VALUE rb_m<%= config[:constant_array].join %>; + +RUBY_FUNC_EXPORTED void +Init_<%= config[:underscored_name] %>(void) +{ + rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>); +} diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt new file mode 100644 index 00000000..f19b750e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.go.tt @@ -0,0 +1,31 @@ +package main + +/* +#include "<%= config[:underscored_name] %>.h" + +VALUE rb_<%= config[:underscored_name] %>_sum(VALUE self, VALUE a, VALUE b); +*/ +import "C" + +import ( + "github.com/ruby-go-gem/go-gem-wrapper/ruby" +) + +//export rb_<%= config[:underscored_name] %>_sum +func rb_<%= config[:underscored_name] %>_sum(_ C.VALUE, a C.VALUE, b C.VALUE) C.VALUE { + longA := ruby.NUM2LONG(ruby.VALUE(a)) + longB := ruby.NUM2LONG(ruby.VALUE(b)) + + sum := longA + longB + + return C.VALUE(ruby.LONG2NUM(sum)) +} + +//export Init_<%= config[:underscored_name] %> +func Init_<%= config[:underscored_name] %>() { + rb_m<%= config[:constant_array].join %> := ruby.RbDefineModule(<%= config[:constant_name].inspect %>) + ruby.RbDefineSingletonMethod(rb_m<%= config[:constant_array].join %>, "sum", C.rb_<%= config[:underscored_name] %>_sum, 2) +} + +func main() { +} diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt new file mode 100644 index 00000000..c6e420b6 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt @@ -0,0 +1,6 @@ +#ifndef <%= config[:underscored_name].upcase %>_H +#define <%= config[:underscored_name].upcase %>_H 1 + +#include "ruby.h" + +#endif /* <%= config[:underscored_name].upcase %>_H */ diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt new file mode 100644 index 00000000..09ce9768 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt @@ -0,0 +1,23 @@ +use magnus::{function, prelude::*, Error, Ruby}; + +pub fn hello(subject: String) -> String { + format!("Hello {subject}, from Rust!") +} + +#[magnus::init] +fn init(ruby: &Ruby) -> Result<(), Error> { + let module = ruby.<%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>; + module.define_singleton_method("hello", function!(hello, 1))?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use rb_sys_test_helpers::ruby_test; + use super::hello; + + #[ruby_test] + fn test_hello() { + assert_eq!("Hello world, from Rust!", hello("world".to_string())); + } +} diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt new file mode 100644 index 00000000..d49954d2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/build-gems.yml.tt @@ -0,0 +1,69 @@ +--- +name: Build gems + +on: + push: + tags: + - "v*" + - "cross-gem/*" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + ci-data: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.fetch.outputs.result }} + steps: + - uses: oxidize-rb/actions/fetch-ci-data@v1 + id: fetch + with: + supported-ruby-platforms: | + exclude: ["arm-linux", "x64-mingw32"] + stable-ruby-versions: | + exclude: ["head"] + + source-gem: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - name: Build gem + run: bundle exec rake build + + - uses: actions/upload-artifact@v7 + with: + name: source-gem + path: pkg/*.gem + + cross-gem: + name: Compile native gem for ${{ matrix.platform }} + runs-on: ubuntu-latest + needs: ci-data + strategy: + matrix: + platform: ${{ fromJSON(needs.ci-data.outputs.result).supported-ruby-platforms }} + steps: + - uses: actions/checkout@v6 + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - uses: oxidize-rb/actions/cross-gem@v1 + id: cross-gem + with: + platform: ${{ matrix.platform }} + ruby-versions: ${{ join(fromJSON(needs.ci-data.outputs.result).stable-ruby-versions, ',') }} + + - uses: actions/upload-artifact@v7 + with: + name: cross-gem + path: ${{ steps.cross-gem.outputs.gem-path }} diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/main.yml.tt new file mode 100644 index 00000000..cc8f04dd --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/github/workflows/main.yml.tt @@ -0,0 +1,48 @@ +name: Ruby + +on: + push: + branches: + - <%= config[:git_default_branch] %> + + pull_request: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + name: Ruby ${{ matrix.ruby }} + strategy: + matrix: + ruby: + - '<%= RUBY_VERSION %>' + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false +<%- if config[:ext] == 'rust' -%> + - name: Set up Ruby & Rust + uses: oxidize-rb/actions/setup-ruby-and-rust@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + cargo-cache: true + rubygems: '<%= ::Gem.rubygems_version %>' +<%- else -%> + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true +<%- end -%> +<%- if config[:ext] == 'go' -%> + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: ext/<%= config[:underscored_name] %>/go.mod +<%- end -%> + - name: Run the default task + run: bundle exec rake diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitignore.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitignore.tt new file mode 100644 index 00000000..9b40ba5a --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitignore.tt @@ -0,0 +1,23 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +<%- if config[:ext] -%> +*.bundle +*.so +*.o +*.a +mkmf.log +<%- if config[:ext] == 'rust' -%> +target/ +<%- end -%> +<%- end -%> +<%- if config[:test] == "rspec" -%> + +# rspec failure tracking +.rspec_status +<%- end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitlab-ci.yml.tt new file mode 100644 index 00000000..adbd70cb --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/gitlab-ci.yml.tt @@ -0,0 +1,27 @@ +default: + image: ruby:<%= RUBY_VERSION %> + + before_script: +<%- if config[:ext] == 'rust' -%> + - apt-get update && apt-get install -y clang + - gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> +<%- if config[:ext] == 'go' -%> + - wget https://go.dev/dl/go$GO_VERSION.linux-amd64.tar.gz -O /tmp/go.tar.gz + - tar -C /usr/local -xzf /tmp/go.tar.gz + - export PATH=/usr/local/go/bin:$PATH +<%- end -%> + - gem install bundler -v <%= Bundler::VERSION %> + - bundle install + +example_job: +<%- if config[:ext] == 'rust' -%> + variables: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> +<%- if config[:ext] == 'go' -%> + variables: + GO_VERSION: '1.23.0' +<%- end -%> + script: + - bundle exec rake diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem.rb.tt new file mode 100644 index 00000000..3aedee0d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require_relative "<%= File.basename(config[:namespaced_path]) %>/version" +<%- if config[:ext] -%> +require "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>" +<%- end -%> + +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>class Error < StandardError; end +<%= " " * config[:constant_array].size %># Your code goes here... +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem/version.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem/version.rb.tt new file mode 100644 index 00000000..b5cd4cb2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/lib/newgem/version.rb.tt @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>VERSION = "0.1.0" +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/newgem.gemspec.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/newgem.gemspec.tt new file mode 100644 index 00000000..90b3ae32 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require_relative "lib/<%=config[:namespaced_path]%>/version" + +Gem::Specification.new do |spec| + spec.name = <%= config[:name].inspect %> + spec.version = <%= config[:constant_name] %>::VERSION + spec.authors = [<%= config[:author].inspect %>] + spec.email = [<%= config[:email].inspect %>] + + spec.summary = "TODO: Write a short summary, because RubyGems requires one." + spec.description = "TODO: Write a longer description or delete this line." + spec.homepage = "<%= config[:homepage_uri] %>" +<%- if config[:mit] -%> + spec.license = "MIT" +<%- end -%> + spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" + spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "<%= config[:source_code_uri] %>" +<%- if config[:changelog] -%> + spec.metadata["changelog_uri"] = "<%= config[:changelog_uri] %>" +<%- end -%> + + # Uncomment the line below to require MFA for gem pushes. + # This helps protect your gem from supply chain attacks by ensuring + # no one can publish a new version without multi-factor authentication. + # See: https://guides.rubygems.org/mfa-requirement-opt-in/ + # spec.metadata["rubygems_mfa_required"] = "true" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + gemspec = File.basename(__FILE__) + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| + ls.readlines("\x0", chomp: true).reject do |f| + (f == gemspec) || + f.start_with?(*%w[<%= config[:ignore_paths].join(" ") %>]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] +<%- if %w(c rust go).include?(config[:ext]) -%> + spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] +<%- end -%> + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" +<%- if config[:ext] == 'rust' -%> + spec.add_dependency "rb_sys", "~> 0.9.128" +<%- end -%> +<%- if config[:ext] == 'go' -%> + spec.add_dependency "go_gem", "~> 0.2" +<%- end -%> + + # For more information and examples about making a new gem, check out our + # guide at: https://guides.rubygems.org/make-your-own-gem/ +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rspec.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rspec.tt new file mode 100644 index 00000000..34c5164d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rspec.tt @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rubocop.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rubocop.yml.tt new file mode 100644 index 00000000..3d1c4ee7 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/rubocop.yml.tt @@ -0,0 +1,8 @@ +AllCops: + TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> + +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + EnforcedStyle: double_quotes diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/sig/newgem.rbs.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/sig/newgem.rbs.tt new file mode 100644 index 00000000..eb7b380b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/sig/newgem.rbs.tt @@ -0,0 +1,8 @@ +<%- config[:constant_array].each_with_index do |c, i| -%> +<%= " " * i %>module <%= c %> +<%- end -%> +<%= " " * config[:constant_array].size %>VERSION: String +<%= " " * config[:constant_array].size %># See the writing guide of rbs: https://github.com/ruby/rbs#guides +<%- (config[:constant_array].size-1).downto(0) do |i| -%> +<%= " " * i %>end +<%- end -%> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt new file mode 100644 index 00000000..dd39342f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +RSpec.describe <%= config[:constant_name] %> do + it "has a version number" do + expect(<%= config[:constant_name] %>::VERSION).not_to be nil + end + +<%- if config[:ext] == 'rust' -%> + it "can call into Rust" do + result = <%= config[:constant_name] %>.hello("world") + + expect(result).to be("Hello earth, from Rust!") + end +<%- else -%> + it "does something useful" do + expect(false).to eq(true) + end +<%- end -%> +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/spec_helper.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/spec_helper.rb.tt new file mode 100644 index 00000000..70c6d1fc --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/spec/spec_helper.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "<%= config[:namespaced_path] %>" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/standard.yml.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/standard.yml.tt new file mode 100644 index 00000000..a0696cd2 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/standard.yml.tt @@ -0,0 +1,3 @@ +# For available configuration options, see: +# https://github.com/standardrb/standard +ruby_version: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt new file mode 100644 index 00000000..e05c387b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "<%= config[:namespaced_path] %>" + +require "minitest/autorun" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt new file mode 100644 index 00000000..9a859fa4 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "test_helper" + +class <%= config[:minitest_constant_name] %> < Minitest::Test + def test_that_it_has_a_version_number + refute_nil ::<%= config[:constant_name] %>::VERSION + end + +<%- if config[:ext] == 'rust' -%> + def test_hello_world + assert_equal "Hello earth, from Rust!", <%= config[:constant_name] %>.hello("world") + end +<%- else -%> + def test_it_does_something_useful + assert false + end +<%- end -%> +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt new file mode 100644 index 00000000..5c61094e --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "test_helper" + +class <%= config[:constant_name] %>Test < Test::Unit::TestCase + test "VERSION" do + assert do + ::<%= config[:constant_name] %>.const_defined?(:VERSION) + end + end + + test "something useful" do + assert_equal("expected", "actual") + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt new file mode 100644 index 00000000..6f633c60 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) +require "<%= config[:namespaced_path] %>" + +require "test-unit" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ui.rb b/bin/gems/bundler-4.0.21/lib/bundler/ui.rb new file mode 100644 index 00000000..7a4fa036 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ui.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Bundler + module UI + autoload :RGProxy, File.expand_path("ui/rg_proxy", __dir__) + autoload :Shell, File.expand_path("ui/shell", __dir__) + autoload :Silent, File.expand_path("ui/silent", __dir__) + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ui/rg_proxy.rb b/bin/gems/bundler-4.0.21/lib/bundler/ui/rg_proxy.rb new file mode 100644 index 00000000..b17ca65f --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ui/rg_proxy.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require_relative "../ui" +require "rubygems/user_interaction" + +module Bundler + module UI + class RGProxy < ::Gem::SilentUI + def initialize(ui) + @ui = ui + super() + end + + def say(message) + @ui&.debug(message) + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ui/shell.rb b/bin/gems/bundler-4.0.21/lib/bundler/ui/shell.rb new file mode 100644 index 00000000..b836208d --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ui/shell.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +require_relative "../vendored_thor" + +module Bundler + module UI + class Shell + LEVELS = %w[silent error warn confirm info debug].freeze + OUTPUT_STREAMS = [:stdout, :stderr].freeze + + attr_writer :shell + attr_reader :output_stream + + def initialize(options = {}) + Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil + @shell = Thor::Base.shell.new + @level = ENV["DEBUG"] ? "debug" : "info" + @warning_history = [] + @output_stream = :stdout + @thread_safe_logger_key = "logger_level_#{object_id}" + end + + def add_color(string, *color) + @shell.set_color(string, *color) + end + + def info(msg = nil, newline = nil) + return unless info? + + tell_me(msg || yield, nil, newline) + end + + def confirm(msg = nil, newline = nil) + return unless confirm? + + tell_me(msg || yield, :green, newline) + end + + def warn(msg = nil, newline = nil, color = :yellow) + return unless warn? + return if @warning_history.include? msg + @warning_history << msg + + tell_err(msg || yield, color, newline) + end + + def error(msg = nil, newline = nil, color = :red) + return unless error? + + tell_err(msg || yield, color, newline) + end + + def debug(msg = nil, newline = nil) + return unless debug? + + tell_me(msg || yield, nil, newline) + end + + def info? + level("info") + end + + def confirm? + level("confirm") + end + + def warn? + level("warn") + end + + def error? + level("error") + end + + def debug? + level("debug") + end + + def quiet? + level("quiet") + end + + def ask(msg) + @shell.ask(msg, :green) + end + + def yes?(msg) + @shell.yes?(msg, :green) + end + + def no?(msg) + @shell.no?(msg) + end + + def level=(level) + raise ArgumentError unless LEVELS.include?(level.to_s) + @level = level.to_s + end + + def level(name = nil) + current_level = Thread.current.thread_variable_get(@thread_safe_logger_key) || @level + return current_level unless name + + unless index = LEVELS.index(name) + raise "#{name.inspect} is not a valid level" + end + index <= LEVELS.index(current_level) + end + + def output_stream=(symbol) + raise ArgumentError unless OUTPUT_STREAMS.include?(symbol) + @output_stream = symbol + end + + def trace(e, newline = nil, force = false) + return unless debug? || force + msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" + tell_err(msg, nil, newline) + end + + def silence(&blk) + with_level("silent", &blk) + end + + def progress(&blk) + with_output_stream(:stderr, &blk) + end + + def unprinted_warnings + [] + end + + private + + # valimism + def tell_me(msg, color = nil, newline = nil) + return tell_err(msg, color, newline) if output_stream == :stderr + + msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] + if newline.nil? + @shell.say(msg, color) + else + @shell.say(msg, color, newline) + end + end + + def tell_err(message, color = nil, newline = nil) + return if @shell.send(:stderr).closed? + + newline = !message.to_s.match?(/( |\t)\Z/) if newline.nil? + message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] + + color = nil if color && !$stderr.tty? + + buffer = @shell.send(:prepare_message, message, *color) + buffer << "\n" if newline && !message.to_s.end_with?("\n") + + @shell.send(:stderr).print(buffer) + @shell.send(:stderr).flush + end + + def strip_leading_spaces(text) + spaces = text[/\A\s+/, 0] + spaces ? text.gsub(/#{spaces}/, "") : text + end + + def word_wrap(text, line_width = Thor::Terminal.terminal_width) + strip_leading_spaces(text).split("\n").collect do |line| + line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line + end * "\n" + end + + def with_level(desired_level) + old_level = level + Thread.current.thread_variable_set(@thread_safe_logger_key, desired_level) + + yield + ensure + Thread.current.thread_variable_set(@thread_safe_logger_key, old_level) + end + + def with_output_stream(symbol) + original = output_stream + self.output_stream = symbol + yield + ensure + @output_stream = original + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/ui/silent.rb b/bin/gems/bundler-4.0.21/lib/bundler/ui/silent.rb new file mode 100644 index 00000000..83d31d4b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/ui/silent.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Bundler + module UI + class Silent + attr_writer :shell + + def initialize + @warnings = [] + end + + def add_color(string, color) + string + end + + def info(message = nil, newline = nil) + end + + def confirm(message = nil, newline = nil) + end + + def warn(message = nil, newline = nil) + @warnings |= [message] + end + + def error(message = nil, newline = nil) + end + + def debug(message = nil, newline = nil) + end + + def confirm? + false + end + + def error? + false + end + + def debug? + false + end + + def info? + false + end + + def quiet? + false + end + + def warn? + false + end + + def output_stream=(_symbol) + end + + def output_stream + nil + end + + def ask(message) + end + + def yes?(msg) + raise "Cannot ask yes? with a silent shell" + end + + def no?(msg) + raise "Cannot ask no? with a silent shell" + end + + def level=(name) + end + + def level(name = nil) + end + + def trace(message, newline = nil, force = false) + end + + def silence + yield + end + + def progress + yield + end + + def unprinted_warnings + @warnings + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/uri_credentials_filter.rb b/bin/gems/bundler-4.0.21/lib/bundler/uri_credentials_filter.rb new file mode 100644 index 00000000..68041874 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/uri_credentials_filter.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Bundler + module URICredentialsFilter + module_function + + def credential_filtered_uri(uri_to_anonymize) + return uri_to_anonymize if uri_to_anonymize.nil? + uri = uri_to_anonymize.dup + if uri.is_a?(String) + return uri if File.exist?(uri) + + require_relative "vendored_uri" + uri = Gem::URI(uri) + end + + if uri.userinfo + # oauth authentication + if uri.password == "x-oauth-basic" || uri.password == "x" || uri.password.nil? + # URI as string does not display with password if no user is set + oauth_designation = uri.password + uri.user = oauth_designation + end + uri.password = nil + end + return uri.to_s if uri_to_anonymize.is_a?(String) + uri + rescue Gem::URI::InvalidURIError # uri is not canonical uri scheme + uri + end + + def credential_filtered_string(str_to_filter, uri) + return str_to_filter if uri.nil? || str_to_filter.nil? + str_with_no_credentials = str_to_filter.dup + anonymous_uri_str = credential_filtered_uri(uri).to_s + uri_str = uri.to_s + if anonymous_uri_str != uri_str + str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str) + end + str_with_no_credentials + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/uri_normalizer.rb b/bin/gems/bundler-4.0.21/lib/bundler/uri_normalizer.rb new file mode 100644 index 00000000..ad085932 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/uri_normalizer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Bundler + module URINormalizer + module_function + + # Normalizes uri to a consistent version, either with or without trailing + # slash. + # + # TODO: Currently gem sources are locked with a trailing slash, while git + # sources are locked without a trailing slash. This should be normalized but + # the inconsistency is there for now to avoid changing all lockfiles + # including GIT sources. We could normalize this on the next major. + # + def normalize_suffix(uri, trailing_slash: true) + if trailing_slash + uri.end_with?("/") ? uri : "#{uri}/" + else + uri.end_with?("/") ? uri.delete_suffix("/") : uri + end + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_fileutils.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_fileutils.rb new file mode 100644 index 00000000..1be1138c --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_fileutils.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/fileutils/lib/fileutils" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_net_http.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_net_http.rb new file mode 100644 index 00000000..8ff2ccd1 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_net_http.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# This defined? guard can be removed once RubyGems 3.4 support is dropped. +# +# Bundler specs load this code from `spec/support/vendored_net_http.rb` to avoid +# activating the Bundler gem too early. Without this guard, we get redefinition +# warnings once Bundler is actually activated and +# `lib/bundler/vendored_net_http.rb` is required. This is not an issue in +# RubyGems versions including `rubygems/vendored_net_http` since `require` takes +# care of avoiding the double load. +# +unless defined?(Gem::Net) + begin + require "rubygems/vendored_net_http" + rescue LoadError + begin + require "rubygems/net/http" + rescue LoadError + require "net/http" + Gem::Net = Net + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_persistent.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_persistent.rb new file mode 100644 index 00000000..ab985c26 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_persistent.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Bundler + module Persistent + module Net + module HTTP + end + end + end +end +require_relative "vendor/net-http-persistent/lib/net/http/persistent" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_pub_grub.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_pub_grub.rb new file mode 100644 index 00000000..b36a996b --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_pub_grub.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/pub_grub/lib/pub_grub" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_securerandom.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_securerandom.rb new file mode 100644 index 00000000..6a704dbd --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_securerandom.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Use RubyGems vendored copy when available. Otherwise fallback to Bundler +# vendored copy. The vendored copy in Bundler can be removed once support for +# RubyGems 3.5.18 is dropped. + +begin + require "rubygems/vendored_securerandom" +rescue LoadError + require_relative "vendor/securerandom/lib/securerandom" + Gem::SecureRandom = Bundler::SecureRandom +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_thor.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_thor.rb new file mode 100644 index 00000000..0666cfc9 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_thor.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Bundler + def self.require_thor_actions + require_relative "vendor/thor/lib/thor/actions" + end +end +require_relative "vendor/thor/lib/thor" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_timeout.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_timeout.rb new file mode 100644 index 00000000..9b2507c0 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_timeout.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +begin + require "rubygems/vendored_timeout" +rescue LoadError + begin + require "rubygems/timeout" + rescue LoadError + require "timeout" + Gem::Timeout = Timeout + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_tsort.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_tsort.rb new file mode 100644 index 00000000..d7d68034 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_tsort.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# The defined? guard avoids reopening Gem::TSort when an old RubyGems has +# already loaded its own copy, e.g. through rubygems/request_set from +# Gem.activate_bin_path in binstubs. +# +unless defined?(Gem::TSort) + begin + require "rubygems/vendored_tsort" + rescue LoadError + begin + # RubyGems 3.4 and 3.5 ship the same file under its pre-3.6 name. + # Requiring the real tsort here instead would activate the tsort + # default gem, and `bundler/setup` must not activate any gems. + require "rubygems/tsort" + rescue LoadError + require "tsort" + Gem::TSort = TSort + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vendored_uri.rb b/bin/gems/bundler-4.0.21/lib/bundler/vendored_uri.rb new file mode 100644 index 00000000..2efddc65 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vendored_uri.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Bundler; end + +# Use RubyGems vendored copy when available. Otherwise fallback to Bundler +# vendored copy. The vendored copy in Bundler can be removed once support for +# RubyGems 3.5 is dropped. + +begin + require "rubygems/vendor/uri/lib/uri" +rescue LoadError + require_relative "vendor/uri/lib/uri" + Gem::URI = Bundler::URI + + module Gem + def URI(uri) # rubocop:disable Naming/MethodName + Bundler::URI(uri) + end + module_function :URI + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/version.rb b/bin/gems/bundler-4.0.21/lib/bundler/version.rb new file mode 100644 index 00000000..791b1001 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/version.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: false + +module Bundler + VERSION = "4.0.21".freeze + + def self.bundler_major_version + @bundler_major_version ||= gem_version.segments.first + end + + def self.gem_version + @gem_version ||= Gem::Version.create(VERSION) + end + + def self.verbose_version + @verbose_version ||= "#{VERSION}#{simulated_version ? " (simulating Bundler #{simulated_version})" : ""}" + end + + def self.simulated_version + @simulated_version ||= Bundler.settings[:simulate_version] + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/vlad.rb b/bin/gems/bundler-4.0.21/lib/bundler/vlad.rb new file mode 100644 index 00000000..c3a3d949 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/vlad.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require_relative "shared_helpers" +Bundler::SharedHelpers.feature_removed! "The Bundler task for Vlad" diff --git a/bin/gems/bundler-4.0.21/lib/bundler/worker.rb b/bin/gems/bundler-4.0.21/lib/bundler/worker.rb new file mode 100644 index 00000000..77f4f004 --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/worker.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module Bundler + class Worker + POISON = Object.new + + class WrappedException < StandardError + attr_reader :exception + def initialize(exn) + @exception = exn + end + end + + # @return [String] the name of the worker + attr_reader :name + + # Creates a worker pool of specified size + # + # @param size [Integer] Size of pool + # @param name [String] name the name of the worker + # @param func [Proc] job to run in inside the worker pool + def initialize(size, name, func) + @name = name + @request_queue = Thread::Queue.new + @request_queue_with_priority = Thread::Queue.new + @response_queue = Thread::Queue.new + @func = func + @size = size + @threads = nil + @previous_interrupt_handler = nil + end + + # Enqueue a request to be executed in the worker pool + # + # @param obj [String] mostly it is name of spec that should be downloaded + def enq(obj, priority: false) + queue = priority ? @request_queue_with_priority : @request_queue + create_threads unless @threads + queue.enq obj + end + + # Retrieves results of job function being executed in worker pool + def deq + result = @response_queue.deq + raise result.exception if result.is_a?(WrappedException) + result + end + + def stop + stop_threads + end + + private + + def process_queue(i) + loop do + obj = begin + @request_queue_with_priority.deq(true) + rescue ThreadError + @request_queue.deq(false, timeout: 0.05) + end + + next if obj.nil? + break if obj.equal? POISON + @response_queue.enq apply_func(obj, i) + end + end + + def apply_func(obj, i) + @func.call(obj, i) + rescue Exception => e # rubocop:disable Lint/RescueException + WrappedException.new(e) + end + + # Stop the worker threads by sending a poison object down the request queue + # so as worker threads after retrieving it, shut themselves down + def stop_threads + return unless @threads + + @threads.each { @request_queue.enq POISON } + @threads.each(&:join) + + remove_interrupt_handler + + @threads = nil + end + + def abort_threads + Bundler.ui.debug("\n#{caller.join("\n")}") + @threads.each(&:exit) + exit 1 + end + + def create_threads + creation_errors = [] + + @threads = Array.new(@size) do |i| + Thread.start { process_queue(i) }.tap do |thread| + thread.name = "#{name} Worker ##{i}" + end + rescue ThreadError => e + creation_errors << e + nil + end.compact + + add_interrupt_handler unless @threads.empty? + + return if creation_errors.empty? + + message = "Failed to create threads for the #{name} worker: #{creation_errors.map(&:to_s).uniq.join(", ")}" + raise ThreadCreationError, message if @threads.empty? + Bundler.ui.info message + end + + def add_interrupt_handler + @previous_interrupt_handler = trap("INT") { abort_threads } + end + + def remove_interrupt_handler + return unless @previous_interrupt_handler + + trap "INT", @previous_interrupt_handler + end + end +end diff --git a/bin/gems/bundler-4.0.21/lib/bundler/yaml_serializer.rb b/bin/gems/bundler-4.0.21/lib/bundler/yaml_serializer.rb new file mode 100644 index 00000000..ab1eb6db --- /dev/null +++ b/bin/gems/bundler-4.0.21/lib/bundler/yaml_serializer.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module Bundler + # A stub yaml serializer that can handle only hashes and strings (as of now). + module YAMLSerializer + module_function + + def dump(hash) + yaml = String.new("---") + yaml << dump_hash(hash) + end + + def dump_hash(hash) + yaml = String.new("\n") + hash.each do |k, v| + yaml << k << ":" + if v.is_a?(Hash) + yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines + elsif v.is_a?(Array) # Expected to be array of strings + if v.empty? + yaml << " []\n" + else + yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n" + end + else + yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n" + end + end + yaml + end + + ARRAY_REGEX = / + ^ + (?:[ ]*-[ ]) # '- ' before array items + (['"]?) # optional opening quote + (.*) # value + \1 # matching closing quote + $ + /xo + + HASH_REGEX = / + ^ + ([ ]*) # indentations + ([^#]+) # key excludes comment char '#' + (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value) + [ ]? + (['"]?) # optional opening quote + (.*) # value + \3 # matching closing quote + $ + /xo + + def load(str) + res = {} + stack = [res] + last_hash = nil + last_empty_key = nil + str.split(/\r?\n/) do |line| + if match = HASH_REGEX.match(line) + indent, key, quote, val = match.captures + val = strip_comment(val) + + depth = indent.size / 2 + if quote.empty? && val.empty? + new_hash = {} + stack[depth][key] = new_hash + stack[depth + 1] = new_hash + last_empty_key = key + last_hash = stack[depth] + else + val = [] if val == "[]" # empty array + stack[depth][key] = val + end + elsif match = ARRAY_REGEX.match(line) + _, val = match.captures + val = strip_comment(val) + + last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array) + + last_hash[last_empty_key].push(val) + end + end + res + end + + def strip_comment(val) + if val.include?("#") && !val.start_with?("#") + val.split("#", 2).first.strip + else + val + end + end + + class << self + private :dump_hash + end + end +end diff --git a/bin/gems/coderay-1.1.3/MIT-LICENSE b/bin/gems/coderay-1.1.3/MIT-LICENSE new file mode 100644 index 00000000..d8d009d1 --- /dev/null +++ b/bin/gems/coderay-1.1.3/MIT-LICENSE @@ -0,0 +1,22 @@ +Copyright (C) 2005-2012 Kornelius Kalnbach (@murphy_karasu) + +http://coderay.rubychan.de/ + +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. \ No newline at end of file diff --git a/bin/gems/coderay-1.1.3/README_INDEX.rdoc b/bin/gems/coderay-1.1.3/README_INDEX.rdoc new file mode 100644 index 00000000..7332653c --- /dev/null +++ b/bin/gems/coderay-1.1.3/README_INDEX.rdoc @@ -0,0 +1,123 @@ += CodeRay + +Tired of blue'n'gray? Try the original version of this documentation on +coderay.rubychan.de[http://coderay.rubychan.de/doc/] :-) + +== About + +CodeRay is a Ruby library for syntax highlighting. + +You put your code in, and you get it back colored; Keywords, strings, +floats, comments - all in different colors. And with line numbers. + +*Syntax* *Highlighting*... +* makes code easier to read and maintain +* lets you detect syntax errors faster +* helps you to understand the syntax of a language +* looks nice +* is what everybody wants to have on their website +* solves all your problems and makes the girls run after you + + +== Installation + + % gem install coderay + + +=== Dependencies + +CodeRay needs Ruby 1.8.7+ or 1.9.2+. It also runs on Rubinius and JRuby. + + +== Example Usage + + require 'coderay' + + html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table) + + +== Documentation + +See CodeRay. + + +== Credits + +=== Special Thanks to + +* licenser (Heinz N. Gies) for ending my QBasic career, inventing the Coder + project and the input/output plugin system. + CodeRay would not exist without him. +* bovi (Daniel Bovensiepen) for helping me out on various occasions. + +=== Thanks to + +* Caleb Clausen for writing RubyLexer (see + http://rubyforge.org/projects/rubylexer) and lots of very interesting mail + traffic +* birkenfeld (Georg Brandl) and mitsuhiku (Arnim Ronacher) for PyKleur, now pygments. + You guys rock! +* Jamis Buck for writing Syntax (see http://rubyforge.org/projects/syntax) + I got some useful ideas from it. +* Doug Kearns and everyone else who worked on ruby.vim - it not only helped me + coding CodeRay, but also gave me a wonderful target to reach for the Ruby + scanner. +* everyone who uses CodeBB on http://www.rubyforen.de and http://www.python-forum.de +* iGEL, magichisoka, manveru, WoNáDo and everyone I forgot from rubyforen.de +* Dethix from ruby-mine.de +* zickzackw +* Dookie (who is no longer with us...) and Leonidas from http://www.python-forum.de +* Andreas Schwarz for finding out that CaseIgnoringWordList was not case + ignoring! Such things really make you write tests. +* closure for the first version of the Scheme scanner. +* Stefan Walk for the first version of the JavaScript and PHP scanners. +* Josh Goebel for another version of the JavaScript scanner, a SQL and a Diff scanner. +* Jonathan Younger for pointing out the licence confusion caused by wrong LICENSE file. +* Jeremy Hinegardner for finding the shebang-on-empty-file bug in FileType. +* Charles Oliver Nutter and Yehuda Katz for helping me benchmark CodeRay on JRuby. +* Andreas Neuhaus for pointing out a markup bug in coderay/for_redcloth. +* 0xf30fc7 for the FileType patch concerning Delphi file extensions. +* The folks at redmine.org - thank you for using and fixing CodeRay! +* Keith Pitt for his SQL scanners +* Rob Aldred for the terminal encoder +* Trans for pointing out $DEBUG dependencies +* Flameeyes for finding that Term::ANSIColor was obsolete +* matz and all Ruby gods and gurus +* The inventors of: the computer, the internet, the true color display, HTML & + CSS, VIM, Ruby, pizza, microwaves, guitars, scouting, programming, anime, + manga, coke and green ice tea. + +Where would we be without all those people? + +=== Created using + +* Ruby[http://ruby-lang.org/] +* Chihiro (my Sony VAIO laptop); Henrietta (my old MacBook); + Triella, born Rico (my new MacBook); as well as + Seras and Hikari (my PCs) +* RDE[http://homepage2.nifty.com/sakazuki/rde_e.html], + VIM[http://vim.org] and TextMate[http://macromates.com] +* Subversion[http://subversion.tigris.org/] +* Redmine[http://redmine.org/] +* Firefox[http://www.mozilla.org/products/firefox/], + Firebug[http://getfirebug.com/], Safari[http://www.apple.com/safari/], and + Thunderbird[http://www.mozilla.org/products/thunderbird/] +* RubyGems[http://docs.rubygems.org/] and Rake[http://rake.rubyforge.org/] +* TortoiseSVN[http://tortoisesvn.tigris.org/] using Apache via + XAMPP[http://www.apachefriends.org/en/xampp.html] +* RDoc (though I'm quite unsatisfied with it) +* Microsoft Windows (yes, I confess!) and MacOS X +* GNUWin32, MinGW and some other tools to make the shell under windows a bit + less useless +* Term::ANSIColor[http://term-ansicolor.rubyforge.org/] +* PLEAC[http://pleac.sourceforge.net/] code examples +* Github +* Travis CI (http://travis-ci.org/rubychan/github) + +=== Free + +* As you can see, CodeRay was created under heavy use of *free* software. +* So CodeRay is also *free*. +* If you use CodeRay to create software, think about making this software + *free*, too. +* Thanks :) diff --git a/bin/gems/coderay-1.1.3/bin/coderay b/bin/gems/coderay-1.1.3/bin/coderay new file mode 100755 index 00000000..130a50ba --- /dev/null +++ b/bin/gems/coderay-1.1.3/bin/coderay @@ -0,0 +1,215 @@ +#!/usr/bin/env ruby +require 'coderay' + +$options, args = ARGV.partition { |arg| arg[/^-[hv]$|--\w+/] } +subcommand = args.first if /^\w/ === args.first +subcommand = nil if subcommand && File.exist?(subcommand) +args.delete subcommand + +def option? *options + !($options & options).empty? +end + +def tty? + $stdout.tty? || option?('--tty') +end + +def version + puts <<-USAGE +CodeRay #{CodeRay::VERSION} + USAGE +end + +def help + puts <<-HELP +This is CodeRay #{CodeRay::VERSION}, a syntax highlighting tool for selected languages. + +usage: + coderay [-language] [input] [-format] [output] + +defaults: + language detect from input file name or shebang; fall back to plain text + input STDIN + format detect from output file name or use terminal; fall back to HTML + output STDOUT + +common: + coderay file.rb # highlight file to terminal + coderay file.rb -page > file.html # highlight file to HTML page + coderay file.rb -div > file.html # highlight file to HTML snippet + +configure output: + coderay file.py output.json # output tokens as JSON + coderay file.py -loc # count lines of code in Python file + +configure input: + coderay -python file # specify the input language + coderay -ruby # take input from STDIN + +more: + coderay stylesheet [style] # print CSS stylesheet + HELP +end + +def commands + puts <<-COMMANDS + general: + highlight code highlighting (default command, optional) + stylesheet print the CSS stylesheet with the given name (aliases: style, css) + + about: + list [of] list all available plugins (or just the scanners|encoders|styles|filetypes) + commands print this list + help show some help + version print CodeRay version + COMMANDS +end + +def print_list_of plugin_host + plugins = plugin_host.all_plugins.map do |plugin| + info = " #{plugin.plugin_id}: #{plugin.title}" + + aliases = (plugin.aliases - [:default]).map { |key| "-#{key}" }.sort_by { |key| key.size } + if plugin.respond_to?(:file_extension) || !aliases.empty? + additional_info = [] + additional_info << aliases.join(', ') unless aliases.empty? + info << " (#{additional_info.join('; ')})" + end + + info << ' <-- default' if plugin.aliases.include? :default + + info + end + puts plugins.sort +end + +if option? '-v', '--version' + version +end + +if option? '-h', '--help' + help +end + +case subcommand +when 'highlight', nil + if ARGV.empty? + version + help + else + signature = args.map { |arg| arg[/^-/] ? '-' : 'f' }.join + names = args.map { |arg| arg.sub(/^-/, '') } + case signature + when /^$/ + exit + when /^ff?$/ + input_file, output_file, = *names + when /^f-f?$/ + input_file, output_format, output_file, = *names + when /^-ff?$/ + input_lang, input_file, output_file, = *names + when /^-f-f?$/ + input_lang, input_file, output_format, output_file, = *names + when /^--?f?$/ + input_lang, output_format, output_file, = *names + else + $stdout = $stderr + help + puts + puts "Unknown parameter order: #{args.join ' '}, expected: [-language] [input] [-format] [output]" + exit 1 + end + + if input_file + input_lang ||= CodeRay::FileType.fetch input_file, :text, true + end + + if output_file + output_format ||= CodeRay::FileType[output_file] || :plain + else + output_format ||= :terminal + end + + output_format = :page if output_format.to_s == 'html' + + if input_file + input = File.read input_file + else + input = $stdin.read + end + + begin + file = + if output_file + File.open output_file, 'w' + else + $stdout + end + CodeRay.encode(input, input_lang, output_format, :out => file) + file.puts + rescue CodeRay::PluginHost::PluginNotFound => boom + $stdout = $stderr + if boom.message[/CodeRay::(\w+)s could not load plugin :?(.*?): /] + puts "I don't know the #$1 \"#$2\"." + else + puts boom.message + end + # puts "I don't know this plugin: #{boom.message[/Could not load plugin (.*?): /, 1]}." + rescue CodeRay::Scanners::Scanner::ScanError + # this is sometimes raised by pagers; ignore + # FIXME: rescue Errno::EPIPE + ensure + file.close if output_file + end + end +when 'li', 'list' + arg = args.first && args.first.downcase + if [nil, 's', 'sc', 'scanner', 'scanners'].include? arg + puts 'input languages (Scanners):' + print_list_of CodeRay::Scanners + end + + if [nil, 'e', 'en', 'enc', 'encoder', 'encoders'].include? arg + puts 'output formats (Encoders):' + print_list_of CodeRay::Encoders + end + + if [nil, 'st', 'style', 'styles'].include? arg + puts 'CSS themes for HTML output (Styles):' + print_list_of CodeRay::Styles + end + + if [nil, 'f', 'ft', 'file', 'filetype', 'filetypes'].include? arg + puts 'recognized file types:' + + filetypes = Hash.new { |h, k| h[k] = [] } + CodeRay::FileType::TypeFromExt.inject filetypes do |types, (ext, type)| + types[type.to_s] << ".#{ext}" + types + end + CodeRay::FileType::TypeFromName.inject filetypes do |types, (name, type)| + types[type.to_s] << name + types + end + + filetypes.sort.each do |type, exts| + puts " #{type}: #{exts.sort_by { |ext| ext.size }.join(', ')}" + end + end +when 'stylesheet', 'style', 'css' + puts CodeRay::Encoders[:html]::CSS.new(args.first || :default).stylesheet +when 'commands' + commands +when 'help' + help +else + $stdout = $stderr + help + puts + if subcommand[/\A\w+\z/] + puts "Unknown command: #{subcommand}" + else + puts "File not found: #{subcommand}" + end + exit 1 +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay.rb b/bin/gems/coderay-1.1.3/lib/coderay.rb new file mode 100644 index 00000000..c3de20b5 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay.rb @@ -0,0 +1,284 @@ +# encoding: utf-8 +# Encoding.default_internal = 'UTF-8' + +# = CodeRay Library +# +# CodeRay is a Ruby library for syntax highlighting. +# +# I try to make CodeRay easy to use and intuitive, but at the same time fully +# featured, complete, fast and efficient. +# +# See README. +# +# It consists mainly of +# * the main engine: CodeRay (Scanners::Scanner, Tokens, Encoders::Encoder) +# * the plugin system: PluginHost, Plugin +# * the scanners in CodeRay::Scanners +# * the encoders in CodeRay::Encoders +# * the styles in CodeRay::Styles +# +# Here's a fancy graphic to light up this gray docu: +# +# http://cycnus.de/raindark/coderay/scheme.png +# +# == Documentation +# +# See CodeRay, Encoders, Scanners, Tokens. +# +# == Usage +# +# Remember you need RubyGems to use CodeRay, unless you have it in your load +# path. Run Ruby with -rubygems option if required. +# +# === Highlight Ruby code in a string as html +# +# require 'coderay' +# print CodeRay.scan('puts "Hello, world!"', :ruby).html +# +# # prints something like this: +# puts "Hello, world!" +# +# +# === Highlight C code from a file in a html div +# +# require 'coderay' +# print CodeRay.scan(File.read('ruby.h'), :c).div +# print CodeRay.scan_file('ruby.h').html.div +# +# You can include this div in your page. The used CSS styles can be printed with +# +# % coderay_stylesheet +# +# === Highlight without typing too much +# +# If you are one of the hasty (or lazy, or extremely curious) people, just run this file: +# +# % ruby -rubygems /path/to/coderay/coderay.rb > example.html +# +# and look at the file it created in your browser. +# +# = CodeRay Module +# +# The CodeRay module provides convenience methods for the engine. +# +# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are +# simply lower-case symbols, like :python or :html. +# * All methods take an optional hash as last parameter, +options+, that is send to +# the Encoder / Scanner. +# * Input and language are always sorted in this order: +code+, +lang+. +# (This is in alphabetical order, if you need a mnemonic ;) +# +# You should be able to highlight everything you want just using these methods; +# so there is no need to dive into CodeRay's deep class hierarchy. +# +# The examples in the demo directory demonstrate common cases using this interface. +# +# = Basic Access Ways +# +# Read this to get a general view what CodeRay provides. +# +# == Scanning +# +# Scanning means analysing an input string, splitting it up into Tokens. +# Each Token knows about what type it is: string, comment, class name, etc. +# +# Each +lang+ (language) has its own Scanner; for example, :ruby code is +# handled by CodeRay::Scanners::Ruby. +# +# CodeRay.scan:: Scan a string in a given language into Tokens. +# This is the most common method to use. +# CodeRay.scan_file:: Scan a file and guess the language using FileType. +# +# The Tokens object you get from these methods can encode itself; see Tokens. +# +# == Encoding +# +# Encoding means compiling Tokens into an output. This can be colored HTML or +# LaTeX, a textual statistic or just the number of non-whitespace tokens. +# +# Each Encoder provides output in a specific +format+, so you select Encoders via +# formats like :html or :statistic. +# +# CodeRay.encode:: Scan and encode a string in a given language. +# CodeRay.encode_tokens:: Encode the given tokens. +# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it. +# +# == All-in-One Encoding +# +# CodeRay.encode:: Highlight a string with a given input and output format. +# +# == Instanciating +# +# You can use an Encoder instance to highlight multiple inputs. This way, the setup +# for this Encoder must only be done once. +# +# CodeRay.encoder:: Create an Encoder instance with format and options. +# CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code. +# +# To make use of CodeRay.scanner, use CodeRay::Scanner::code=. +# +# The scanning methods provide more flexibility; we recommend to use these. +# +# == Reusing Scanners and Encoders +# +# If you want to re-use scanners and encoders (because that is faster), see +# CodeRay::Duo for the most convenient (and recommended) interface. +module CodeRay + + $CODERAY_DEBUG ||= false + + CODERAY_PATH = File.expand_path('../coderay', __FILE__) + + # Assuming the path is a subpath of lib/coderay/ + def self.coderay_path *path + File.join CODERAY_PATH, *path + end + + autoload :VERSION, 'coderay/version' + + # helpers + autoload :FileType, coderay_path('helpers', 'file_type') + + # Tokens + autoload :Tokens, coderay_path('tokens') + autoload :TokensProxy, coderay_path('tokens_proxy') + autoload :TokenKinds, coderay_path('token_kinds') + + # Plugin system + autoload :PluginHost, coderay_path('helpers', 'plugin_host') + autoload :Plugin, coderay_path('helpers', 'plugin') + + # Plugins + autoload :Scanners, coderay_path('scanners') + autoload :Encoders, coderay_path('encoders') + autoload :Styles, coderay_path('styles') + + # convenience access and reusable Encoder/Scanner pair + autoload :Duo, coderay_path('duo') + + class << self + + # Scans the given +code+ (a String) with the Scanner for +lang+. + # + # This is a simple way to use CodeRay. Example: + # require 'coderay' + # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html + # + # See also demo/demo_simple. + def scan code, lang, options = {}, &block + CodeRay::TokensProxy.new code, lang, options, block + end + + # Scans +filename+ (a path to a code file) with the Scanner for +lang+. + # + # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to + # determine it. If it cannot find out what type it is, it uses + # CodeRay::Scanners::Text. + # + # Calls CodeRay.scan. + # + # Example: + # require 'coderay' + # page = CodeRay.scan_file('some_c_code.c').html + def scan_file filename, lang = :auto, options = {}, &block + lang = CodeRay::FileType.fetch filename, :text, true if lang == :auto + code = File.read filename + scan code, lang, options, &block + end + + # Encode a string. + # + # This scans +code+ with the the Scanner for +lang+ and then + # encodes it with the Encoder for +format+. + # +options+ will be passed to the Encoder. + # + # See CodeRay::Encoder.encode. + def encode code, lang, format, options = {} + encoder(format, options).encode code, lang, options + end + + # Encode pre-scanned Tokens. + # Use this together with CodeRay.scan: + # + # require 'coderay' + # + # # Highlight a short Ruby code example in a HTML span + # tokens = CodeRay.scan '1 + 2', :ruby + # puts CodeRay.encode_tokens(tokens, :span) + # + def encode_tokens tokens, format, options = {} + encoder(format, options).encode_tokens tokens, options + end + + # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. + # + # See CodeRay.scan_file. + # Notice that the second argument is the output +format+, not the input language. + # + # Example: + # require 'coderay' + # page = CodeRay.encode_file 'some_c_code.c', :html + def encode_file filename, format, options = {} + tokens = scan_file filename, :auto, get_scanner_options(options) + encode_tokens tokens, format, options + end + + # Highlight a string into a HTML
. + # + # CSS styles use classes, so you have to include a stylesheet + # in your output. + # + # See encode. + def highlight code, lang, options = { :css => :class }, format = :div + encode code, lang, format, options + end + + # Highlight a file into a HTML
. + # + # CSS styles use classes, so you have to include a stylesheet + # in your output. + # + # See encode. + def highlight_file filename, options = { :css => :class }, format = :div + encode_file filename, format, options + end + + # Finds the Encoder class for +format+ and creates an instance, passing + # +options+ to it. + # + # Example: + # require 'coderay' + # + # stats = CodeRay.encoder(:statistic) + # stats.encode("puts 17 + 4\n", :ruby) + # + # puts '%d out of %d tokens have the kind :integer.' % [ + # stats.type_stats[:integer].count, + # stats.real_token_count + # ] + # #-> 2 out of 4 tokens have the kind :integer. + def encoder format, options = {} + CodeRay::Encoders[format].new options + end + + # Finds the Scanner class for +lang+ and creates an instance, passing + # +options+ to it. + # + # See Scanner.new. + def scanner lang, options = {}, &block + CodeRay::Scanners[lang].new '', options, &block + end + + # Extract the options for the scanner from the +options+ hash. + # + # Returns an empty Hash if :scanner_options is not set. + # + # This is used if a method like CodeRay.encode has to provide options + # for Encoder _and_ scanner. + def get_scanner_options options + options.fetch :scanner_options, {} + end + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/duo.rb b/bin/gems/coderay-1.1.3/lib/coderay/duo.rb new file mode 100644 index 00000000..cb3f8ee8 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/duo.rb @@ -0,0 +1,81 @@ +module CodeRay + + # = Duo + # + # A Duo is a convenient way to use CodeRay. You just create a Duo, + # giving it a lang (language of the input code) and a format (desired + # output format), and call Duo#highlight with the code. + # + # Duo makes it easy to re-use both scanner and encoder for a repetitive + # task. It also provides a very easy interface syntax: + # + # require 'coderay' + # CodeRay::Duo[:python, :div].highlight 'import this' + # + # Until you want to do uncommon things with CodeRay, I recommend to use + # this method, since it takes care of everything. + class Duo + + attr_accessor :lang, :format, :options + + # Create a new Duo, holding a lang and a format to highlight code. + # + # simple: + # CodeRay::Duo[:ruby, :html].highlight 'bla 42' + # + # with options: + # CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??' + # + # alternative syntax without options: + # CodeRay::Duo[:ruby => :statistic].encode 'class << self; end' + # + # alternative syntax with options: + # CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc' + # + # The options are forwarded to scanner and encoder + # (see CodeRay.get_scanner_options). + def initialize lang = nil, format = nil, options = {} + if format.nil? && lang.is_a?(Hash) && lang.size == 1 + @lang = lang.keys.first + @format = lang[@lang] + else + @lang = lang + @format = format + end + @options = options + end + + class << self + # To allow calls like Duo[:ruby, :html].highlight. + alias [] new + end + + # The scanner of the duo. Only created once. + def scanner + @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options) + end + + # The encoder of the duo. Only created once. + def encoder + @encoder ||= CodeRay.encoder @format, @options + end + + # Tokenize and highlight the code using +scanner+ and +encoder+. + def encode code, options = {} + options = @options.merge options + encoder.encode(code, @lang, options) + end + alias highlight encode + + # Allows to use Duo like a proc object: + # + # CodeRay::Duo[:python => :yaml].call(code) + # + # or, in Ruby 1.9 and later: + # + # CodeRay::Duo[:python => :yaml].(code) + alias call encode + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders.rb new file mode 100644 index 00000000..6599186e --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders.rb @@ -0,0 +1,18 @@ +module CodeRay + + # This module holds the Encoder class and its subclasses. + # For example, the HTML encoder is named CodeRay::Encoders::HTML + # can be found in coderay/encoders/html. + # + # Encoders also provides methods and constants for the register + # mechanism and the [] method that returns the Encoder class + # belonging to the given format. + module Encoders + + extend PluginHost + plugin_path File.dirname(__FILE__), 'encoders' + + autoload :Encoder, CodeRay.coderay_path('encoders', 'encoder') + + end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/_map.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/_map.rb new file mode 100644 index 00000000..4cca1963 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/_map.rb @@ -0,0 +1,17 @@ +module CodeRay +module Encoders + + map \ + :loc => :lines_of_code, + :plain => :text, + :plaintext => :text, + :remove_comments => :comment_filter, + :stats => :statistic, + :term => :terminal, + :tty => :terminal, + :yml => :yaml + + # No default because Tokens#nonsense should raise NoMethodError. + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/comment_filter.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/comment_filter.rb new file mode 100644 index 00000000..28336b3d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/comment_filter.rb @@ -0,0 +1,25 @@ +module CodeRay +module Encoders + + load :token_kind_filter + + # A simple Filter that removes all tokens of the :comment kind. + # + # Alias: +remove_comments+ + # + # Usage: + # CodeRay.scan('print # foo', :ruby).comment_filter.text + # #-> "print " + # + # See also: TokenKindFilter, LinesOfCode + class CommentFilter < TokenKindFilter + + register_for :comment_filter + + DEFAULT_OPTIONS = superclass::DEFAULT_OPTIONS.merge \ + :exclude => [:comment, :docstring] + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/count.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/count.rb new file mode 100644 index 00000000..98a427e1 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/count.rb @@ -0,0 +1,39 @@ +module CodeRay +module Encoders + + # Returns the number of tokens. + # + # Text and block tokens are counted. + class Count < Encoder + + register_for :count + + protected + + def setup options + super + + @count = 0 + end + + def finish options + output @count + end + + public + + def text_token text, kind + @count += 1 + end + + def begin_group kind + @count += 1 + end + alias end_group begin_group + alias begin_line begin_group + alias end_line begin_group + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug.rb new file mode 100644 index 00000000..f4db3301 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug.rb @@ -0,0 +1,49 @@ +module CodeRay +module Encoders + + # = Debug Encoder + # + # Fast encoder producing simple debug output. + # + # It is readable and diff-able and is used for testing. + # + # You cannot fully restore the tokens information from the + # output, because consecutive :space tokens are merged. + # + # See also: Scanners::Debug + class Debug < Encoder + + register_for :debug + + FILE_EXTENSION = 'raydebug' + + def text_token text, kind + if kind == :space + @out << text + else + text = text.gsub('\\', '\\\\\\\\') if text.index('\\') + text = text.gsub(')', '\\\\)') if text.index(')') + @out << "#{kind}(#{text})" + end + end + + def begin_group kind + @out << "#{kind}<" + end + + def end_group kind + @out << '>' + end + + def begin_line kind + @out << "#{kind}[" + end + + def end_line kind + @out << ']' + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug_lint.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug_lint.rb new file mode 100644 index 00000000..a4eba2c7 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/debug_lint.rb @@ -0,0 +1,63 @@ +module CodeRay +module Encoders + + load :lint + + # = Debug Lint Encoder + # + # Debug encoder with additional checks for: + # + # - empty tokens + # - incorrect nesting + # + # It will raise an InvalidTokenStream exception when any of the above occurs. + # + # See also: Encoders::Debug + class DebugLint < Debug + + register_for :debug_lint + + def text_token text, kind + raise Lint::EmptyToken, 'empty token for %p' % [kind] if text.empty? + raise Lint::UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind + super + end + + def begin_group kind + @opened << kind + super + end + + def end_group kind + raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind + @opened.pop + super + end + + def begin_line kind + @opened << kind + super + end + + def end_line kind + raise Lint::IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind + @opened.pop + super + end + + protected + + def setup options + super + @opened = [] + end + + def finish options + raise 'Some tokens still open at end of token stream: %p' % [@opened] unless @opened.empty? + super + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/div.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/div.rb new file mode 100644 index 00000000..efd9435c --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/div.rb @@ -0,0 +1,23 @@ +module CodeRay +module Encoders + + load :html + + # Wraps HTML output into a DIV element, using inline styles by default. + # + # See Encoders::HTML for available options. + class Div < HTML + + FILE_EXTENSION = 'div.html' + + register_for :div + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :style, + :wrap => :div, + :line_numbers => false + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/encoder.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/encoder.rb new file mode 100644 index 00000000..2baeedb6 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/encoder.rb @@ -0,0 +1,190 @@ +module CodeRay + module Encoders + + # = Encoder + # + # The Encoder base class. Together with Scanner and + # Tokens, it forms the highlighting triad. + # + # Encoder instances take a Tokens object and do something with it. + # + # The most common Encoder is surely the HTML encoder + # (CodeRay::Encoders::HTML). It highlights the code in a colorful + # html page. + # If you want the highlighted code in a div or a span instead, + # use its subclasses Div and Span. + class Encoder + extend Plugin + plugin_host Encoders + + class << self + + # If FILE_EXTENSION isn't defined, this method returns the + # downcase class name instead. + def const_missing sym + if sym == :FILE_EXTENSION + (defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s + else + super + end + end + + # The default file extension for output file of this encoder class. + def file_extension + self::FILE_EXTENSION + end + + end + + # Subclasses are to store their default options in this constant. + DEFAULT_OPTIONS = { } + + # The options you gave the Encoder at creating. + attr_accessor :options, :scanner + + # Creates a new Encoder. + # +options+ is saved and used for all encode operations, as long + # as you don't overwrite it there by passing additional options. + # + # Encoder objects provide three encode methods: + # - encode simply takes a +code+ string and a +lang+ + # - encode_tokens expects a +tokens+ object instead + # + # Each method has an optional +options+ parameter. These are + # added to the options you passed at creation. + def initialize options = {} + @options = self.class::DEFAULT_OPTIONS.merge options + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false + end + + # Encode a Tokens object. + def encode_tokens tokens, options = {} + options = @options.merge options + @scanner = tokens.scanner if tokens.respond_to? :scanner + setup options + compile tokens, options + finish options + end + + # Encode the given +code+ using the Scanner for +lang+. + def encode code, lang, options = {} + options = @options.merge options + @scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self) + setup options + @scanner.tokenize + finish options + end + + # You can use highlight instead of encode, if that seems + # more clear to you. + alias highlight encode + + # The default file extension for this encoder. + def file_extension + self.class.file_extension + end + + def << token + unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN + warn 'Using old Tokens#<< interface.' + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true + end + self.token(*token) + end + + # Called with +content+ and +kind+ of the currently scanned token. + # For simple scanners, it's enougth to implement this method. + # + # By default, it calls text_token, begin_group, end_group, begin_line, + # or end_line, depending on the +content+. + def token content, kind + case content + when String + text_token content, kind + when :begin_group + begin_group kind + when :end_group + end_group kind + when :begin_line + begin_line kind + when :end_line + end_line kind + else + raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind] + end + end + + # Called for each text token ([text, kind]), where text is a String. + def text_token text, kind + @out << text + end + + # Starts a token group with the given +kind+. + def begin_group kind + end + + # Ends a token group with the given +kind+. + def end_group kind + end + + # Starts a new line token group with the given +kind+. + def begin_line kind + end + + # Ends a new line token group with the given +kind+. + def end_line kind + end + + protected + + # Called with merged options before encoding starts. + # Sets @out to an empty string. + # + # See the HTML Encoder for an example of option caching. + def setup options + @out = get_output(options) + end + + def get_output options + options[:out] || ''.dup + end + + # Append data.to_s to the output. Returns the argument. + def output data + @out << data.to_s + data + end + + # Called with merged options after encoding starts. + # The return value is the result of encoding, typically @out. + def finish options + @out + end + + # Do the encoding. + # + # The already created +tokens+ object must be used; it must be a + # Tokens object. + def compile tokens, options = {} + content = nil + for item in tokens + if item.is_a? Array + raise ArgumentError, 'Two-element array tokens are no longer supported.' + end + if content + token content, item + content = nil + else + content = item + end + end + raise 'odd number list for Tokens' if content + end + + alias tokens compile + public :tokens + + end + + end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/filter.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/filter.rb new file mode 100644 index 00000000..e7f34d6a --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/filter.rb @@ -0,0 +1,58 @@ +module CodeRay +module Encoders + + # A Filter encoder has another Tokens instance as output. + # It can be subclass to select, remove, or modify tokens in the stream. + # + # Subclasses of Filter are called "Filters" and can be chained. + # + # == Options + # + # === :tokens + # + # The Tokens object which will receive the output. + # + # Default: Tokens.new + # + # See also: TokenKindFilter + class Filter < Encoder + + register_for :filter + + protected + def setup options + super + + @tokens = options[:tokens] || Tokens.new + end + + def finish options + output @tokens + end + + public + + def text_token text, kind # :nodoc: + @tokens.text_token text, kind + end + + def begin_group kind # :nodoc: + @tokens.begin_group kind + end + + def begin_line kind # :nodoc: + @tokens.begin_line kind + end + + def end_group kind # :nodoc: + @tokens.end_group kind + end + + def end_line kind # :nodoc: + @tokens.end_line kind + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/html.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html.rb new file mode 100644 index 00000000..1b33e921 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html.rb @@ -0,0 +1,333 @@ +require 'set' + +module CodeRay +module Encoders + + # = HTML Encoder + # + # This is CodeRay's most important highlighter: + # It provides save, fast XHTML generation and CSS support. + # + # == Usage + # + # require 'coderay' + # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page + # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) + # #-> Some /code/ + # puts CodeRay.scan('Some /code/', :ruby).span #-> the same + # + # puts CodeRay.scan('Some code', :ruby).html( + # :wrap => nil, + # :line_numbers => :inline, + # :css => :style + # ) + # + # == Options + # + # === :tab_width + # Convert \t characters to +n+ spaces (a number or false.) + # false will keep tab characters untouched. + # + # Default: 8 + # + # === :css + # How to include the styles; can be :class or :style. + # + # Default: :class + # + # === :wrap + # Wrap in :page, :div, :span or nil. + # + # You can also use Encoders::Div and Encoders::Span. + # + # Default: nil + # + # === :title + # + # The title of the HTML page (works only when :wrap is set to :page.) + # + # Default: 'CodeRay output' + # + # === :break_lines + # + # Split multiline blocks at line breaks. + # Forced to true if :line_numbers option is set to :inline. + # + # Default: false + # + # === :line_numbers + # Include line numbers in :table, :inline, or nil (no line numbers) + # + # Default: nil + # + # === :line_number_anchors + # Adds anchors and links to the line numbers. Can be false (off), true (on), + # or a prefix string that will be prepended to the anchor name. + # + # The prefix must consist only of letters, digits, and underscores. + # + # Default: true, default prefix name: "line" + # + # === :line_number_start + # Where to start with line number counting. + # + # Default: 1 + # + # === :bold_every + # Make every +n+-th number appear bold. + # + # Default: 10 + # + # === :highlight_lines + # + # Highlights certain line numbers. + # Can be any Enumerable, typically just an Array or Range, of numbers. + # + # Bolding is deactivated when :highlight_lines is set. It only makes sense + # in combination with :line_numbers. + # + # Default: nil + # + # === :hint + # Include some information into the output using the title attribute. + # Can be :info (show token kind on mouse-over), :info_long (with full path) + # or :debug (via inspect). + # + # Default: false + class HTML < Encoder + + register_for :html + + FILE_EXTENSION = 'snippet.html' + + DEFAULT_OPTIONS = { + :tab_width => 8, + + :css => :class, + :style => :alpha, + :wrap => nil, + :title => 'CodeRay output', + + :break_lines => false, + + :line_numbers => nil, + :line_number_anchors => 'n', + :line_number_start => 1, + :bold_every => 10, + :highlight_lines => nil, + + :hint => false, + } + + autoload :Output, CodeRay.coderay_path('encoders', 'html', 'output') + autoload :CSS, CodeRay.coderay_path('encoders', 'html', 'css') + autoload :Numbering, CodeRay.coderay_path('encoders', 'html', 'numbering') + + attr_reader :css + + protected + + def self.make_html_escape_hash + { + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + # "\t" => will be set to ' ' * options[:tab_width] during setup + }.tap do |hash| + # Escape ASCII control codes except \x9 == \t and \xA == \n. + (Array(0x00..0x8) + Array(0xB..0x1F)).each { |invalid| hash[invalid.chr] = ' ' } + end + end + + HTML_ESCAPE = make_html_escape_hash + HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1F]/ + + TOKEN_KIND_TO_INFO = Hash.new do |h, kind| + h[kind] = kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } + end + + TRANSPARENT_TOKEN_KINDS = Set[ + :delimiter, :modifier, :content, :escape, :inline_delimiter, + ] + + # Generate a hint about the given +kinds+ in a +hint+ style. + # + # +hint+ may be :info, :info_long or :debug. + def self.token_path_to_hint hint, kinds + kinds = Array kinds + title = + case hint + when :info + kinds = kinds[1..-1] if TRANSPARENT_TOKEN_KINDS.include? kinds.first + TOKEN_KIND_TO_INFO[kinds.first] + when :info_long + kinds.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') + when :debug + kinds.inspect + end + title ? " title=\"#{title}\"" : '' + end + + def setup options + super + + check_options! options + + if options[:wrap] || options[:line_numbers] + @real_out = @out + @out = ''.dup + end + + @break_lines = (options[:break_lines] == true) + + @HTML_ESCAPE = HTML_ESCAPE.merge("\t" => options[:tab_width] ? ' ' * options[:tab_width] : "\t") + + @opened = [] + @last_opened = nil + @css = CSS.new options[:style] + + @span_for_kinds = make_span_for_kinds(options[:css], options[:hint]) + + @set_last_opened = options[:hint] || options[:css] == :style + end + + def finish options + unless @opened.empty? + @out << '' while @opened.pop + @last_opened = nil + end + + if @out.respond_to? :to_str + @out.extend Output + @out.css = @css + if options[:line_numbers] + Numbering.number! @out, options[:line_numbers], options + end + @out.wrap! options[:wrap] + @out.apply_title! options[:title] + end + + if defined?(@real_out) && @real_out + @real_out << @out + @out = @real_out + end + + super + end + + public + + def text_token text, kind + style = @span_for_kinds[@last_opened ? [kind, *@opened] : kind] + + text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } if text =~ /#{HTML_ESCAPE_PATTERN}/o + text = break_lines(text, style) if @break_lines && (style || @opened.size > 0) && text.index("\n") + + if style + @out << style << text << '' + else + @out << text + end + end + + # token groups, eg. strings + def begin_group kind + @out << (@span_for_kinds[@last_opened ? [kind, *@opened] : kind] || '') + @opened << kind + @last_opened = kind if @set_last_opened + end + + def end_group kind + check_group_nesting 'token group', kind if $CODERAY_DEBUG + close_span + end + + # whole lines to be highlighted, eg. a deleted line in a diff + def begin_line kind + if style = @span_for_kinds[@last_opened ? [kind, *@opened] : kind] + if style['class="'] + @out << style.sub('class="', 'class="line ') + else + @out << style.sub('>', ' class="line">') + end + else + @out << '' + end + @opened << kind + @last_opened = kind if @options[:css] == :style + end + + def end_line kind + check_group_nesting 'line', kind if $CODERAY_DEBUG + close_span + end + + protected + + def check_options! options + unless [false, nil, :debug, :info, :info_long].include? options[:hint] + raise ArgumentError, "Unknown value %p for :hint; expected :info, :info_long, :debug, false, or nil." % [options[:hint]] + end + + unless [:class, :style].include? options[:css] + raise ArgumentError, 'Unknown value %p for :css.' % [options[:css]] + end + + options[:break_lines] = true if options[:line_numbers] == :inline + end + + def css_class_for_kinds kinds + TokenKinds[kinds.is_a?(Symbol) ? kinds : kinds.first] + end + + def style_for_kinds kinds + css_classes = kinds.is_a?(Array) ? kinds.map { |c| TokenKinds[c] } : [TokenKinds[kinds]] + @css.get_style_for_css_classes css_classes + end + + def make_span_for_kinds method, hint + Hash.new do |h, kinds| + begin + css_class = css_class_for_kinds(kinds) + title = HTML.token_path_to_hint hint, kinds if hint + + if css_class || title + if method == :style + style = style_for_kinds(kinds) + "" + else + "" + end + end + end.tap do |span| + h.clear if h.size >= 100 + h[kinds] = span + end + end + end + + def check_group_nesting name, kind + if @opened.empty? || @opened.last != kind + warn "Malformed token stream: Trying to close a #{name} (%p) that is not open. Open are: %p." % [kind, @opened[1..-1]] + end + end + + def break_lines text, style + reopen = ''.dup + @opened.each_with_index do |kind, index| + reopen << (@span_for_kinds[index > 0 ? [kind, *@opened[0...index]] : kind] || '') + end + text.gsub("\n", "#{'' * @opened.size}#{'' if style}\n#{reopen}#{style}") + end + + def close_span + if @opened.pop + @out << '' + @last_opened = @opened.last if @last_opened + end + end + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/css.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/css.rb new file mode 100644 index 00000000..164d7f85 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/css.rb @@ -0,0 +1,65 @@ +module CodeRay +module Encoders + + class HTML + class CSS # :nodoc: + + attr :stylesheet + + def CSS.load_stylesheet style = nil + CodeRay::Styles[style] + end + + def initialize style = :default + @styles = Hash.new + style = CSS.load_stylesheet style + @stylesheet = [ + style::CSS_MAIN_STYLES, + style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') + ].join("\n") + parse style::TOKEN_COLORS + end + + def get_style_for_css_classes css_classes + cl = @styles[css_classes.first] + return '' unless cl + style = '' + 1.upto css_classes.size do |offset| + break if style = cl[css_classes[offset .. -1]] + end + # warn 'Style not found: %p' % [styles] if style.empty? + return style + end + + private + + CSS_CLASS_PATTERN = / + ( # $1 = selectors + (?: + (?: \s* \. [-\w]+ )+ + \s* ,? + )+ + ) + \s* \{ \s* + ( [^\}]+ )? # $2 = style + \s* \} \s* + | + ( [^\n]+ ) # $3 = error + /mx + def parse stylesheet + stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| + raise "CSS parse error: '#{error.inspect}' not recognized" if error + for selector in selectors.split(',') + classes = selector.scan(/[-\w]+/) + cl = classes.pop + @styles[cl] ||= Hash.new + @styles[cl][classes] = style.to_s.strip.delete(' ').chomp(';') + end + end + end + + end + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/numbering.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/numbering.rb new file mode 100644 index 00000000..a1b9c04a --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/numbering.rb @@ -0,0 +1,108 @@ +module CodeRay +module Encoders + + class HTML + + module Numbering # :nodoc: + + def self.number! output, mode = :table, options = {} + return self unless mode + + options = DEFAULT_OPTIONS.merge options + + start = options[:line_number_start] + unless start.is_a? Integer + raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start + end + + anchor_prefix = options[:line_number_anchors] + anchor_prefix = 'line' if anchor_prefix == true + anchor_prefix = anchor_prefix.to_s[/[\w-]+/] if anchor_prefix + anchoring = + if anchor_prefix + proc do |line| + line = line.to_s + anchor = anchor_prefix + line + "#{line}" + end + else + :to_s.to_proc + end + + bold_every = options[:bold_every] + highlight_lines = options[:highlight_lines] + bolding = + if bold_every == false && highlight_lines == nil + anchoring + elsif highlight_lines.is_a? Enumerable + highlight_lines = highlight_lines.to_set + proc do |line| + if highlight_lines.include? line + "#{anchoring[line]}" # highlighted line numbers in bold + else + anchoring[line] + end + end + elsif bold_every.is_a? Integer + raise ArgumentError, ":bolding can't be 0." if bold_every == 0 + proc do |line| + if line % bold_every == 0 + "#{anchoring[line]}" # every bold_every-th number in bold + else + anchoring[line] + end + end + else + raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every + end + + if position_of_last_newline = output.rindex(RUBY_VERSION >= '1.9' ? /\n/ : ?\n) + after_last_newline = output[position_of_last_newline + 1 .. -1] + ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/] + + if ends_with_newline + line_count = output.count("\n") + else + line_count = output.count("\n") + 1 + end + else + line_count = 1 + end + + case mode + when :inline + max_width = (start + line_count).to_s.size + line_number = start + output.gsub!(/^.*$\n?/) do |line| + line_number_text = bolding.call line_number + indent = ' ' * (max_width - line_number.to_s.size) + line_number += 1 + "#{indent}#{line_number_text}#{line}" + end + + when :table + line_numbers = (start ... start + line_count).map(&bolding).join("\n") + line_numbers << "\n" + line_numbers_table_template = Output::TABLE.apply('LINE_NUMBERS', line_numbers) + + output.gsub!(/<\/div>\n/, '
') + output.wrap_in! line_numbers_table_template + output.wrapped_in = :div + + when :list + raise NotImplementedError, 'The :list option is no longer available. Use :table.' + + else + raise ArgumentError, 'Unknown value %p for mode: expected one of %p' % + [mode, [:table, :inline]] + end + + output + end + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/output.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/output.rb new file mode 100644 index 00000000..ee87fea5 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/html/output.rb @@ -0,0 +1,164 @@ +module CodeRay +module Encoders + + class HTML + + # This module is included in the output String of the HTML Encoder. + # + # It provides methods like wrap, div, page etc. + # + # Remember to use #clone instead of #dup to keep the modules the object was + # extended with. + # + # TODO: Rewrite this without monkey patching. + module Output + + attr_accessor :css + + class << self + + # Raises an exception if an object that doesn't respond to to_str is extended by Output, + # to prevent users from misuse. Use Module#remove_method to disable. + def extended o # :nodoc: + warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str + end + + def make_stylesheet css, in_tag = false # :nodoc: + sheet = css.stylesheet + sheet = <<-'CSS' if in_tag + + CSS + sheet + end + + def page_template_for_css css # :nodoc: + sheet = make_stylesheet css + PAGE.apply 'CSS', sheet + end + + end + + def wrapped_in? element + wrapped_in == element + end + + def wrapped_in + @wrapped_in ||= nil + end + attr_writer :wrapped_in + + def wrap_in! template + Template.wrap! self, template, 'CONTENT' + self + end + + def apply_title! title + self.sub!(/()(<\/title>)/) { $1 + title + $2 } + self + end + + def wrap! element, *args + return self if not element or element == wrapped_in + case element + when :div + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! DIV + when :span + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! SPAN + when :page + wrap! :div if wrapped_in? nil + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div + wrap_in! Output.page_template_for_css(@css) + if args.first.is_a?(Hash) && title = args.first[:title] + apply_title! title + end + self + else + raise "Unknown value %p for :wrap" % element + end + @wrapped_in = element + self + end + + def stylesheet in_tag = false + Output.make_stylesheet @css, in_tag + end + +#-- don't include the templates in docu + + class Template < String # :nodoc: + + def self.wrap! str, template, target + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if template =~ target + str[0,0] = $` + str << $' + else + raise "Template target <%%%p%%> not found" % target + end + end + + def apply target, replacement + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if self =~ target + Template.new($` + replacement + $') + else + raise "Template target <%%%p%%> not found" % target + end + end + + end + + SPAN = Template.new '<span class="CodeRay"><%CONTENT%></span>' + + DIV = Template.new <<-DIV +<div class="CodeRay"> + <div class="code"><pre><%CONTENT%></pre></div> +</div> + DIV + + TABLE = Template.new <<-TABLE +<table class="CodeRay"><tr> + <td class="line-numbers"><pre><%LINE_NUMBERS%></pre></td> + <td class="code"><pre><%CONTENT%></pre></td> +</tr></table> + TABLE + + PAGE = Template.new <<-PAGE +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title> + + + + +<%CONTENT%> + + + PAGE + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/json.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/json.rb new file mode 100644 index 00000000..a9e40dc6 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/json.rb @@ -0,0 +1,83 @@ +module CodeRay +module Encoders + + # A simple JSON Encoder. + # + # Example: + # CodeRay.scan('puts "Hello world!"', :ruby).json + # yields + # [ + # {"type"=>"text", "text"=>"puts", "kind"=>"ident"}, + # {"type"=>"text", "text"=>" ", "kind"=>"space"}, + # {"type"=>"block", "action"=>"open", "kind"=>"string"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"block", "action"=>"close", "kind"=>"string"}, + # ] + class JSON < Encoder + + begin + require 'json' + rescue LoadError + begin + require 'rubygems' unless defined? Gem + gem 'json' + require 'json' + rescue LoadError + $stderr.puts "The JSON encoder needs the JSON library.\n" \ + "Please gem install json." + raise + end + end + + register_for :json + FILE_EXTENSION = 'json' + + protected + def setup options + super + + @first = true + @out << '[' + end + + def finish options + @out << ']' + end + + def append data + if @first + @first = false + else + @out << ',' + end + + @out << data.to_json + end + + public + def text_token text, kind + append :type => 'text', :text => text, :kind => kind + end + + def begin_group kind + append :type => 'block', :action => 'open', :kind => kind + end + + def end_group kind + append :type => 'block', :action => 'close', :kind => kind + end + + def begin_line kind + append :type => 'block', :action => 'begin_line', :kind => kind + end + + def end_line kind + append :type => 'block', :action => 'end_line', :kind => kind + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/lines_of_code.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/lines_of_code.rb new file mode 100644 index 00000000..5f8422f3 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/lines_of_code.rb @@ -0,0 +1,45 @@ +module CodeRay +module Encoders + + # Counts the LoC (Lines of Code). Returns an Integer >= 0. + # + # Alias: +loc+ + # + # Everything that is not comment, markup, doctype/shebang, or an empty line, + # is considered to be code. + # + # For example, + # * HTML files not containing JavaScript have 0 LoC + # * in a Java class without comments, LoC is the number of non-empty lines + # + # A Scanner class should define the token kinds that are not code in the + # KINDS_NOT_LOC constant, which defaults to [:comment, :doctype]. + class LinesOfCode < TokenKindFilter + + register_for :lines_of_code + + NON_EMPTY_LINE = /^\s*\S.*$/ + + protected + + def setup options + if scanner + kinds_not_loc = scanner.class::KINDS_NOT_LOC + else + warn "Tokens have no associated scanner, counting all nonempty lines." if $VERBOSE + kinds_not_loc = CodeRay::Scanners::Scanner::KINDS_NOT_LOC + end + + options[:exclude] = kinds_not_loc + + super options + end + + def finish options + output @tokens.text.scan(NON_EMPTY_LINE).size + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/lint.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/lint.rb new file mode 100644 index 00000000..88c8bd1d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/lint.rb @@ -0,0 +1,59 @@ +module CodeRay +module Encoders + + # = Lint Encoder + # + # Checks for: + # + # - empty tokens + # - incorrect nesting + # + # It will raise an InvalidTokenStream exception when any of the above occurs. + # + # See also: Encoders::DebugLint + class Lint < Debug + + register_for :lint + + InvalidTokenStream = Class.new StandardError + EmptyToken = Class.new InvalidTokenStream + UnknownTokenKind = Class.new InvalidTokenStream + IncorrectTokenGroupNesting = Class.new InvalidTokenStream + + def text_token text, kind + raise EmptyToken, 'empty token for %p' % [kind] if text.empty? + raise UnknownTokenKind, 'unknown token kind %p (text was %p)' % [kind, text] unless TokenKinds.has_key? kind + end + + def begin_group kind + @opened << kind + end + + def end_group kind + raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_group)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind + @opened.pop + end + + def begin_line kind + @opened << kind + end + + def end_line kind + raise IncorrectTokenGroupNesting, 'We are inside %s, not %p (end_line)' % [@opened.reverse.map(&:inspect).join(' < '), kind] if @opened.last != kind + @opened.pop + end + + protected + + def setup options + @opened = [] + end + + def finish options + raise 'Some tokens still open at end of token stream: %p' % [@opened] unless @opened.empty? + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/null.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/null.rb new file mode 100644 index 00000000..73ba47d3 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/null.rb @@ -0,0 +1,18 @@ +module CodeRay +module Encoders + + # = Null Encoder + # + # Does nothing and returns an empty string. + class Null < Encoder + + register_for :null + + def text_token text, kind + # do nothing + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/page.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/page.rb new file mode 100644 index 00000000..800e73f3 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/page.rb @@ -0,0 +1,24 @@ +module CodeRay +module Encoders + + load :html + + # Wraps the output into a HTML page, using CSS classes and + # line numbers in the table format by default. + # + # See Encoders::HTML for available options. + class Page < HTML + + FILE_EXTENSION = 'html' + + register_for :page + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :class, + :wrap => :page, + :line_numbers => :table + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/span.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/span.rb new file mode 100644 index 00000000..da705bdc --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/span.rb @@ -0,0 +1,23 @@ +module CodeRay +module Encoders + + load :html + + # Wraps HTML output into a SPAN element, using inline styles by default. + # + # See Encoders::HTML for available options. + class Span < HTML + + FILE_EXTENSION = 'span.html' + + register_for :span + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :style, + :wrap => :span, + :line_numbers => false + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/statistic.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/statistic.rb new file mode 100644 index 00000000..b2f8b830 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/statistic.rb @@ -0,0 +1,95 @@ +module CodeRay +module Encoders + + # Makes a statistic for the given tokens. + # + # Alias: +stats+ + class Statistic < Encoder + + register_for :statistic + + attr_reader :type_stats, :real_token_count # :nodoc: + + TypeStats = Struct.new :count, :size # :nodoc: + + protected + + def setup options + super + + @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 } + @real_token_count = 0 + end + + STATS = <<-STATS # :nodoc: + +Code Statistics + +Tokens %8d + Non-Whitespace %8d +Bytes Total %8d + +Token Types (%d): + type count ratio size (average) +------------------------------------------------------------- +%s + STATS + + TOKEN_TYPES_ROW = <<-TKR # :nodoc: + %-20s %8d %6.2f %% %5.1f + TKR + + def finish options + all = @type_stats['TOTAL'] + all_count, all_size = all.count, all.size + @type_stats.each do |type, stat| + stat.size /= stat.count.to_f + end + types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v| + TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size] + end.join + @out << STATS % [ + all_count, @real_token_count, all_size, + @type_stats.delete_if { |k, v| k.is_a? String }.size, + types_stats + ] + + super + end + + public + + def text_token text, kind + @real_token_count += 1 unless kind == :space + @type_stats[kind].count += 1 + @type_stats[kind].size += text.size + @type_stats['TOTAL'].size += text.size + @type_stats['TOTAL'].count += 1 + end + + def begin_group kind + block_token ':begin_group', kind + end + + def end_group kind + block_token ':end_group', kind + end + + def begin_line kind + block_token ':begin_line', kind + end + + def end_line kind + block_token ':end_line', kind + end + + def block_token action, kind + @type_stats['TOTAL'].count += 1 + @type_stats[action].count += 1 + @type_stats[kind].count += 1 + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/terminal.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/terminal.rb new file mode 100644 index 00000000..c7ae0146 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/terminal.rb @@ -0,0 +1,195 @@ +module CodeRay + module Encoders + + # Outputs code highlighted for a color terminal. + # + # Note: This encoder is in beta. It currently doesn't use the Styles. + # + # Alias: +term+ + # + # == Authors & License + # + # By Rob Aldred (http://robaldred.co.uk) + # + # Based on idea by Nathan Weizenbaum (http://nex-3.com) + # + # MIT License (http://www.opensource.org/licenses/mit-license.php) + class Terminal < Encoder + + register_for :terminal + + TOKEN_COLORS = { + :debug => "\e[1;37;44m", + + :annotation => "\e[34m", + :attribute_name => "\e[35m", + :attribute_value => "\e[31m", + :binary => { + :self => "\e[31m", + :char => "\e[1;31m", + :delimiter => "\e[1;31m", + }, + :char => { + :self => "\e[35m", + :delimiter => "\e[1;35m" + }, + :class => "\e[1;35;4m", + :class_variable => "\e[36m", + :color => "\e[32m", + :comment => { + :self => "\e[1;30m", + :char => "\e[37m", + :delimiter => "\e[37m", + }, + :constant => "\e[1;34;4m", + :decorator => "\e[35m", + :definition => "\e[1;33m", + :directive => "\e[33m", + :docstring => "\e[31m", + :doctype => "\e[1;34m", + :done => "\e[1;30;2m", + :entity => "\e[31m", + :error => "\e[1;37;41m", + :exception => "\e[1;31m", + :float => "\e[1;35m", + :function => "\e[1;34m", + :global_variable => "\e[1;32m", + :hex => "\e[1;36m", + :id => "\e[1;34m", + :include => "\e[31m", + :integer => "\e[1;34m", + :imaginary => "\e[1;34m", + :important => "\e[1;31m", + :key => { + :self => "\e[35m", + :char => "\e[1;35m", + :delimiter => "\e[1;35m", + }, + :keyword => "\e[32m", + :label => "\e[1;33m", + :local_variable => "\e[33m", + :namespace => "\e[1;35m", + :octal => "\e[1;34m", + :predefined => "\e[36m", + :predefined_constant => "\e[1;36m", + :predefined_type => "\e[1;32m", + :preprocessor => "\e[1;36m", + :pseudo_class => "\e[1;34m", + :regexp => { + :self => "\e[35m", + :delimiter => "\e[1;35m", + :modifier => "\e[35m", + :char => "\e[1;35m", + }, + :reserved => "\e[32m", + :shell => { + :self => "\e[33m", + :char => "\e[1;33m", + :delimiter => "\e[1;33m", + :escape => "\e[1;33m", + }, + :string => { + :self => "\e[31m", + :modifier => "\e[1;31m", + :char => "\e[1;35m", + :delimiter => "\e[1;31m", + :escape => "\e[1;31m", + }, + :symbol => { + :self => "\e[33m", + :delimiter => "\e[1;33m", + }, + :tag => "\e[32m", + :type => "\e[1;34m", + :value => "\e[36m", + :variable => "\e[34m", + + :insert => { + :self => "\e[42m", + :insert => "\e[1;32;42m", + :eyecatcher => "\e[102m", + }, + :delete => { + :self => "\e[41m", + :delete => "\e[1;31;41m", + :eyecatcher => "\e[101m", + }, + :change => { + :self => "\e[44m", + :change => "\e[37;44m", + }, + :head => { + :self => "\e[45m", + :filename => "\e[37;45m" + }, + } + + TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved] + TOKEN_COLORS[:method] = TOKEN_COLORS[:function] + TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter] + + protected + + def setup(options) + super + @opened = [] + @color_scopes = [TOKEN_COLORS] + end + + public + + def text_token text, kind + if color = @color_scopes.last[kind] + color = color[:self] if color.is_a? Hash + + @out << color + @out << (text.index("\n") ? text.gsub("\n", "\e[0m\n" + color) : text) + @out << "\e[0m" + if outer_color = @color_scopes.last[:self] + @out << outer_color + end + else + @out << text + end + end + + def begin_group kind + @opened << kind + @out << open_token(kind) + end + alias begin_line begin_group + + def end_group kind + if @opened.pop + @color_scopes.pop + @out << "\e[0m" + if outer_color = @color_scopes.last[:self] + @out << outer_color + end + end + end + + def end_line kind + @out << (@line_filler ||= "\t" * 100) + end_group kind + end + + private + + def open_token kind + if color = @color_scopes.last[kind] + if color.is_a? Hash + @color_scopes << color + color[:self] + else + @color_scopes << @color_scopes.last + color + end + else + @color_scopes << @color_scopes.last + '' + end + end + end + end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/text.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/text.rb new file mode 100644 index 00000000..15c66f9c --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/text.rb @@ -0,0 +1,46 @@ +module CodeRay +module Encoders + + # Concats the tokens into a single string, resulting in the original + # code string if no tokens were removed. + # + # Alias: +plain+, +plaintext+ + # + # == Options + # + # === :separator + # A separator string to join the tokens. + # + # Default: empty String + class Text < Encoder + + register_for :text + + FILE_EXTENSION = 'txt' + + DEFAULT_OPTIONS = { + :separator => nil + } + + def text_token text, kind + super + + if @first + @first = false + else + @out << @sep + end if @sep + end + + protected + def setup options + super + + @first = true + @sep = options[:separator] + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/token_kind_filter.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/token_kind_filter.rb new file mode 100644 index 00000000..4773ea34 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/token_kind_filter.rb @@ -0,0 +1,111 @@ +module CodeRay +module Encoders + + load :filter + + # A Filter that selects tokens based on their token kind. + # + # == Options + # + # === :exclude + # + # One or many symbols (in an Array) which shall be excluded. + # + # Default: [] + # + # === :include + # + # One or many symbols (in an array) which shall be included. + # + # Default: :all, which means all tokens are included. + # + # Exclusion wins over inclusion. + # + # See also: CommentFilter + class TokenKindFilter < Filter + + register_for :token_kind_filter + + DEFAULT_OPTIONS = { + :exclude => [], + :include => :all + } + + protected + def setup options + super + + @group_excluded = false + @exclude = options[:exclude] + @exclude = Array(@exclude) unless @exclude == :all + @include = options[:include] + @include = Array(@include) unless @include == :all + end + + def include_text_token? text, kind + include_group? kind + end + + def include_group? kind + (@include == :all || @include.include?(kind)) && + !(@exclude == :all || @exclude.include?(kind)) + end + + public + + # Add the token to the output stream if +kind+ matches the conditions. + def text_token text, kind + super if !@group_excluded && include_text_token?(text, kind) + end + + # Add the token group to the output stream if +kind+ matches the + # conditions. + # + # If it does not, all tokens inside the group are excluded from the + # stream, even if their kinds match. + def begin_group kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # See +begin_group+. + def begin_line kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # Take care of re-enabling the delegation of tokens to the output stream + # if an exluded group has ended. + def end_group kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + # See +end_group+. + def end_line kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/xml.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/xml.rb new file mode 100644 index 00000000..3d306a60 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/xml.rb @@ -0,0 +1,72 @@ +module CodeRay +module Encoders + + # = XML Encoder + # + # Uses REXML. Very slow. + class XML < Encoder + + register_for :xml + + FILE_EXTENSION = 'xml' + + autoload :REXML, 'rexml/document' + + DEFAULT_OPTIONS = { + :tab_width => 8, + :pretty => -1, + :transitive => false, + } + + protected + def setup options + super + + @doc = REXML::Document.new + @doc << REXML::XMLDecl.new + @tab_width = options[:tab_width] + @root = @node = @doc.add_element('coderay-tokens') + end + + def finish options + @doc.write @out, options[:pretty], options[:transitive], true + + super + end + + public + def text_token text, kind + if kind == :space + token = @node + else + token = @node.add_element kind.to_s + end + text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| + case + when space + token << REXML::Text.new(space, true) + when tab + token << REXML::Text.new(tab, true) + when nl + token << REXML::Text.new(nl, true) + else + token << REXML::Text.new($&) + end + end + end + + def begin_group kind + @node = @node.add_element kind.to_s + end + + def end_group kind + if @node == @root + raise 'no token to close!' + end + @node = @node.parent + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/encoders/yaml.rb b/bin/gems/coderay-1.1.3/lib/coderay/encoders/yaml.rb new file mode 100644 index 00000000..ba6e7155 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/encoders/yaml.rb @@ -0,0 +1,50 @@ +autoload :YAML, 'yaml' + +module CodeRay +module Encoders + + # = YAML Encoder + # + # Slow. + class YAML < Encoder + + register_for :yaml + + FILE_EXTENSION = 'yaml' + + protected + def setup options + super + + @data = [] + end + + def finish options + output ::YAML.dump(@data) + end + + public + def text_token text, kind + @data << [text, kind] + end + + def begin_group kind + @data << [:begin_group, kind] + end + + def end_group kind + @data << [:end_group, kind] + end + + def begin_line kind + @data << [:begin_line, kind] + end + + def end_line kind + @data << [:end_line, kind] + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/for_redcloth.rb b/bin/gems/coderay-1.1.3/lib/coderay/for_redcloth.rb new file mode 100644 index 00000000..f9df32be --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/for_redcloth.rb @@ -0,0 +1,95 @@ +module CodeRay + + # A little hack to enable CodeRay highlighting in RedCloth. + # + # Usage: + # require 'coderay' + # require 'coderay/for_redcloth' + # RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + # + # Make sure you have RedCloth 4.0.3 activated, for example by calling + # require 'rubygems' + # before RedCloth is loaded and before calling CodeRay.for_redcloth. + module ForRedCloth + + def self.install + gem 'RedCloth', '>= 4.0.3' if defined? gem + require 'redcloth' + unless RedCloth::VERSION.to_s >= '4.0.3' + if defined? gem + raise 'CodeRay.for_redcloth needs RedCloth version 4.0.3 or later. ' + + "You have #{RedCloth::VERSION}. Please gem install RedCloth." + else + $".delete 'redcloth.rb' # sorry, but it works + require 'rubygems' + return install # retry + end + end + unless RedCloth::VERSION.to_s >= '4.2.2' + warn 'CodeRay.for_redcloth works best with RedCloth version 4.2.2 or later.' + end + RedCloth::TextileDoc.send :include, ForRedCloth::TextileDoc + RedCloth::Formatters::HTML.module_eval do + def unescape(html) # :nodoc: + replacements = { + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + } + html.gsub(/&(?:amp|quot|[gl]t);/) { |entity| replacements[entity] } + end + undef code, bc_open, bc_close, escape_pre + def code(opts) # :nodoc: + opts[:block] = true + if !opts[:lang] && RedCloth::VERSION.to_s >= '4.2.0' + # simulating pre-4.2 behavior + if opts[:text].sub!(/\A\[(\w+)\]/, '') + if CodeRay::Scanners[$1].lang == :text + opts[:text] = $& + opts[:text] + else + opts[:lang] = $1 + end + end + end + if opts[:lang] && !filter_coderay + require 'coderay' + @in_bc ||= nil + format = @in_bc ? :div : :span + opts[:text] = unescape(opts[:text]) unless @in_bc + highlighted_code = CodeRay.encode opts[:text], opts[:lang], format + highlighted_code.sub!(/\A<(span|div)/) { |m| m + pba(@in_bc || opts) } + highlighted_code + else + "#{opts[:text]}" + end + end + def bc_open(opts) # :nodoc: + opts[:block] = true + @in_bc = opts + opts[:lang] ? '' : "" + end + def bc_close(opts) # :nodoc: + opts = @in_bc + @in_bc = nil + opts[:lang] ? '' : "\n" + end + def escape_pre(text) # :nodoc: + if @in_bc ||= nil + text + else + html_esc(text, :html_escape_preformatted) + end + end + end + end + + module TextileDoc # :nodoc: + attr_accessor :filter_coderay + end + + end + +end + +CodeRay::ForRedCloth.install \ No newline at end of file diff --git a/bin/gems/coderay-1.1.3/lib/coderay/helpers/file_type.rb b/bin/gems/coderay-1.1.3/lib/coderay/helpers/file_type.rb new file mode 100644 index 00000000..7de34d58 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/helpers/file_type.rb @@ -0,0 +1,151 @@ +module CodeRay + + # = FileType + # + # A simple filetype recognizer. + # + # == Usage + # + # # determine the type of the given + # lang = FileType[file_name] + # + # # return :text if the file type is unknown + # lang = FileType.fetch file_name, :text + # + # # try the shebang line, too + # lang = FileType.fetch file_name, :text, true + module FileType + + UnknownFileType = Class.new Exception + + class << self + + # Try to determine the file type of the file. + # + # +filename+ is a relative or absolute path to a file. + # + # The file itself is only accessed when +read_shebang+ is set to true. + # That means you can get filetypes from files that don't exist. + def [] filename, read_shebang = false + name = File.basename filename + ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot + ext2 = filename.to_s[/\.(.*)/, 1] # from first dot + + type = + TypeFromExt[ext] || + TypeFromExt[ext.downcase] || + (TypeFromExt[ext2] if ext2) || + (TypeFromExt[ext2.downcase] if ext2) || + TypeFromName[name] || + TypeFromName[name.downcase] + type ||= type_from_shebang(filename) if read_shebang + + type + end + + # This works like Hash#fetch. + # + # If the filetype cannot be found, the +default+ value + # is returned. + def fetch filename, default = nil, read_shebang = false + if default && block_given? + warn 'Block supersedes default value argument; use either.' + end + + if type = self[filename, read_shebang] + type + else + return yield if block_given? + return default if default + raise UnknownFileType, 'Could not determine type of %p.' % filename + end + end + + protected + + def type_from_shebang filename + return unless File.exist? filename + File.open filename, 'r' do |f| + if first_line = f.gets + if type = first_line[TypeFromShebang] + type.to_sym + end + end + end + end + + end + + TypeFromExt = { + 'c' => :c, + 'cfc' => :xml, + 'cfm' => :xml, + 'clj' => :clojure, + 'css' => :css, + 'diff' => :diff, + 'dpr' => :delphi, + 'erb' => :erb, + 'gemspec' => :ruby, + 'go' => :go, + 'groovy' => :groovy, + 'gvy' => :groovy, + 'h' => :c, + 'haml' => :haml, + 'htm' => :html, + 'html' => :html, + 'html.erb' => :erb, + 'java' => :java, + 'js' => :java_script, + 'json' => :json, + 'lua' => :lua, + 'mab' => :ruby, + 'pas' => :delphi, + 'patch' => :diff, + 'phtml' => :php, + 'php' => :php, + 'php3' => :php, + 'php4' => :php, + 'php5' => :php, + 'prawn' => :ruby, + 'py' => :python, + 'py3' => :python, + 'pyw' => :python, + 'rake' => :ruby, + 'raydebug' => :raydebug, + 'rb' => :ruby, + 'rbw' => :ruby, + 'rhtml' => :erb, + 'rjs' => :ruby, + 'rpdf' => :ruby, + 'ru' => :ruby, # config.ru + 'rxml' => :ruby, + 'sass' => :sass, + 'sql' => :sql, + 'taskpaper' => :taskpaper, + 'template' => :json, # AWS CloudFormation template + 'tmproj' => :xml, + 'xaml' => :xml, + 'xhtml' => :html, + 'xml' => :xml, + 'yaml' => :yaml, + 'yml' => :yaml, + } + for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] + TypeFromExt[cpp_alias] = :cpp + end + + TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ + + TypeFromName = { + 'Capfile' => :ruby, + 'Rakefile' => :ruby, + 'Rantfile' => :ruby, + 'Gemfile' => :ruby, + 'Guardfile' => :ruby, + 'Vagrantfile' => :ruby, + 'Appraisals' => :ruby + } + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin.rb b/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin.rb new file mode 100644 index 00000000..45679436 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin.rb @@ -0,0 +1,55 @@ +module CodeRay + + # = Plugin + # + # Plugins have to include this module. + # + # IMPORTANT: Use extend for this module. + # + # See CodeRay::PluginHost for examples. + module Plugin + + attr_reader :plugin_id + + # Register this class for the given +id+. + # + # Example: + # class MyPlugin < PluginHost::BaseClass + # register_for :my_id + # ... + # end + # + # See PluginHost.register. + def register_for id + @plugin_id = id + plugin_host.register self, id + end + + # Returns the title of the plugin, or sets it to the + # optional argument +title+. + def title title = nil + if title + @title = title.to_s + else + @title ||= name[/([^:]+)$/, 1] + end + end + + # The PluginHost for this Plugin class. + def plugin_host host = nil + if host.is_a? PluginHost + const_set :PLUGIN_HOST, host + end + self::PLUGIN_HOST + end + + def aliases + plugin_host.plugin_hash.inject [] do |aliases, (key, _)| + aliases << key if plugin_host[key] == self + aliases + end + end + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin_host.rb b/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin_host.rb new file mode 100644 index 00000000..e9bc17c1 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/helpers/plugin_host.rb @@ -0,0 +1,221 @@ +module CodeRay + + # = PluginHost + # + # A simple subclass/subfolder plugin system. + # + # Example: + # class Generators + # extend PluginHost + # plugin_path 'app/generators' + # end + # + # class Generator + # extend Plugin + # PLUGIN_HOST = Generators + # end + # + # class FancyGenerator < Generator + # register_for :fancy + # end + # + # Generators[:fancy] #-> FancyGenerator + # # or + # CodeRay.require_plugin 'Generators/fancy' + # # or + # Generators::Fancy + module PluginHost + + # Raised if Encoders::[] fails because: + # * a file could not be found + # * the requested Plugin is not registered + PluginNotFound = Class.new LoadError + HostNotFound = Class.new LoadError + + PLUGIN_HOSTS = [] + PLUGIN_HOSTS_BY_ID = {} # dummy hash + + # Loads all plugins using list and load. + def load_all + for plugin in list + load plugin + end + end + + # Returns the Plugin for +id+. + # + # Example: + # yaml_plugin = MyPluginHost[:yaml] + def [] id, *args, &blk + plugin = validate_id(id) + begin + plugin = plugin_hash.[](plugin, *args, &blk) + end while plugin.is_a? String + plugin + end + + alias load [] + + # Tries to +load+ the missing plugin by translating +const+ to the + # underscore form (eg. LinesOfCode becomes lines_of_code). + def const_missing const + id = const.to_s. + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + downcase + load id + end + + class << self + + # Adds the module/class to the PLUGIN_HOSTS list. + def extended mod + PLUGIN_HOSTS << mod + end + + end + + # The path where the plugins can be found. + def plugin_path *args + unless args.empty? + @plugin_path = File.expand_path File.join(*args) + end + @plugin_path ||= '' + end + + # Map a plugin_id to another. + # + # Usage: Put this in a file plugin_path/_map.rb. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue, + # :maroon => :brown, + # :luna => :moon + # end + def map hash + for from, to in hash + from = validate_id from + to = validate_id to + plugin_hash[from] = to unless plugin_hash.has_key? from + end + end + + # Define the default plugin to use when no plugin is found + # for a given id, or return the default plugin. + # + # See also map. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue + # default :gray + # end + # + # MyColorHost.default # loads and returns the Gray plugin + def default id = nil + if id + id = validate_id id + raise "The default plugin can't be named \"default\"." if id == :default + plugin_hash[:default] = id + else + load :default + end + end + + # Every plugin must register itself for +id+ by calling register_for, + # which calls this method. + # + # See Plugin#register_for. + def register plugin, id + plugin_hash[validate_id(id)] = plugin + end + + # A Hash of plugion_id => Plugin pairs. + def plugin_hash + @plugin_hash ||= (@plugin_hash = make_plugin_hash).tap { load_plugin_map } + end + + # Returns an array of all .rb files in the plugin path. + # + # The extension .rb is not included. + def list + Dir[path_to('*')].select do |file| + File.basename(file)[/^(?!_)\w+\.rb$/] + end.map do |file| + File.basename(file, '.rb').to_sym + end + end + + # Returns an array of all Plugins. + # + # Note: This loads all plugins using load_all. + def all_plugins + load_all + plugin_hash.values.grep(Class) + end + + # Loads the map file (see map). + # + # This is done automatically when plugin_path is called. + def load_plugin_map + mapfile = path_to '_map' + if File.exist? mapfile + require mapfile + true + else + false + end + end + + protected + + # Return a plugin hash that automatically loads plugins. + def make_plugin_hash + Hash.new do |h, plugin_id| + id = validate_id(plugin_id) + path = path_to id + begin + require path + rescue LoadError => boom + if h.has_key?(:default) + h[:default] + else + raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom] + end + else + # Plugin should have registered by now + if h.has_key? id + h[id] + else + raise PluginNotFound, "No #{self.name} plugin for #{id.inspect} found in #{path}." + end + end + end + end + + # Returns the expected path to the plugin file for the given id. + def path_to plugin_id + File.join plugin_path, "#{plugin_id}.rb" + end + + # Converts +id+ to a valid plugin ID String, or returns +nil+. + # + # Raises +ArgumentError+ for all other objects, or if the + # given String includes non-alphanumeric characters (\W). + def validate_id id + case id + when Symbol + id.to_s + when String + if id[/\w+/] == id + id.downcase + else + raise ArgumentError, "Invalid id given: #{id}" + end + else + raise ArgumentError, "Symbol or String expected, but #{id.class} given." + end + end + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/helpers/word_list.rb b/bin/gems/coderay-1.1.3/lib/coderay/helpers/word_list.rb new file mode 100644 index 00000000..4a42c4a7 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/helpers/word_list.rb @@ -0,0 +1,72 @@ +module CodeRay + + # = WordList + # + # A Hash subclass designed for mapping word lists to token types. + # + # A WordList is a Hash with some additional features. + # It is intended to be used for keyword recognition. + # + # WordList is optimized to be used in Scanners, + # typically to decide whether a given ident is a special token. + # + # For case insensitive words use WordList::CaseIgnoring. + # + # Example: + # + # # define word arrays + # RESERVED_WORDS = %w[ + # asm break case continue default do else + # ] + # + # PREDEFINED_TYPES = %w[ + # int long short char void + # ] + # + # # make a WordList + # IDENT_KIND = WordList.new(:ident). + # add(RESERVED_WORDS, :reserved). + # add(PREDEFINED_TYPES, :predefined_type) + # + # ... + # + # def scan_tokens tokens, options + # ... + # + # elsif scan(/[A-Za-z_][A-Za-z_0-9]*/) + # # use it + # kind = IDENT_KIND[match] + # ... + class WordList < Hash + + # Create a new WordList with +default+ as default value. + def initialize default = false + super default + end + + # Add words to the list and associate them with +value+. + # + # Returns +self+, so you can concat add calls. + def add words, value = true + words.each { |word| self[word] = value } + self + end + + end + + + # A CaseIgnoring WordList is like a WordList, only that + # keys are compared case-insensitively (normalizing keys using +downcase+). + class WordList::CaseIgnoring < WordList + + def [] key + super key.downcase + end + + def []= key, value + super key.downcase, value + end + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners.rb new file mode 100644 index 00000000..3c7e594d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners.rb @@ -0,0 +1,27 @@ +require 'strscan' + +module CodeRay + + autoload :WordList, coderay_path('helpers', 'word_list') + + # = Scanners + # + # This module holds the Scanner class and its subclasses. + # For example, the Ruby scanner is named CodeRay::Scanners::Ruby + # can be found in coderay/scanners/ruby. + # + # Scanner also provides methods and constants for the register + # mechanism and the [] method that returns the Scanner class + # belonging to the given lang. + # + # See PluginHost. + module Scanners + + extend PluginHost + plugin_path File.dirname(__FILE__), 'scanners' + + autoload :Scanner, CodeRay.coderay_path('scanners', 'scanner') + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/_map.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/_map.rb new file mode 100644 index 00000000..a240298d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/_map.rb @@ -0,0 +1,24 @@ +module CodeRay +module Scanners + + map \ + :'c++' => :cpp, + :cplusplus => :cpp, + :ecmascript => :java_script, + :ecma_script => :java_script, + :rhtml => :erb, + :eruby => :erb, + :irb => :ruby, + :javascript => :java_script, + :js => :java_script, + :pascal => :delphi, + :patch => :diff, + :plain => :text, + :plaintext => :text, + :xhtml => :html, + :yml => :yaml + + default :text + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/c.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/c.rb new file mode 100644 index 00000000..fb2f30db --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/c.rb @@ -0,0 +1,189 @@ +module CodeRay +module Scanners + + # Scanner for C. + class C < Scanner + + register_for :c + file_extension 'c' + + KEYWORDS = [ + 'asm', 'break', 'case', 'continue', 'default', 'do', + 'else', 'enum', 'for', 'goto', 'if', 'return', + 'sizeof', 'struct', 'switch', 'typedef', 'union', 'while', + 'restrict', # added in C99 + ] # :nodoc: + + PREDEFINED_TYPES = [ + 'int', 'long', 'short', 'char', + 'signed', 'unsigned', 'float', 'double', + 'bool', 'complex', # added in C99 + ] # :nodoc: + + PREDEFINED_CONSTANTS = [ + 'EOF', 'NULL', + 'true', 'false', # added in C99 + ] # :nodoc: + DIRECTIVES = [ + 'auto', 'extern', 'register', 'static', 'void', + 'const', 'volatile', # added in C89 + 'inline', # added in C99 + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(DIRECTIVES, :directive). + add(PREDEFINED_CONSTANTS, :predefined_constant) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + label_expected = match =~ /[;\{\}]/ + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token 'L', :modifier + match = '"' + end + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + elsif match = scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + label_expected = false + encoder.text_token match, :float + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\\n"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ | $ /x) + encoder.end_group :string + encoder.text_token match, :error unless match.empty? + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/clojure.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/clojure.rb new file mode 100644 index 00000000..f8fbf650 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/clojure.rb @@ -0,0 +1,217 @@ +# encoding: utf-8 +module CodeRay + module Scanners + + # Clojure scanner by Licenser. + class Clojure < Scanner + + register_for :clojure + file_extension 'clj' + + SPECIAL_FORMS = %w[ + def if do let quote var fn loop recur throw try catch monitor-enter monitor-exit . + new + ] # :nodoc: + + CORE_FORMS = %w[ + + - -> ->> .. / * <= < = == >= > accessor aclone add-classpath add-watch + agent agent-error agent-errors aget alength alias all-ns alter alter-meta! + alter-var-root amap ancestors and apply areduce array-map aset aset-boolean + aset-byte aset-char aset-double aset-float aset-int aset-long aset-short + assert assoc assoc! assoc-in associative? atom await await-for bases bean + bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or + bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array + booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char + char-array char-escape-string char-name-string char? chars class class? + clear-agent-errors clojure-version coll? comment commute comp comparator + compare compare-and-set! compile complement concat cond condp conj conj! + cons constantly construct-proxy contains? count counted? create-ns + create-struct cycle dec decimal? declare definline defmacro defmethod defmulti + defn defn- defonce defprotocol defrecord defstruct deftype delay delay? + deliver denominator deref derive descendants disj disj! dissoc dissoc! + distinct distinct? doall doc dorun doseq dosync dotimes doto double + double-array doubles drop drop-last drop-while empty empty? ensure + enumeration-seq error-handler error-mode eval even? every? extend + extend-protocol extend-type extenders extends? false? ffirst file-seq + filter find find-doc find-ns find-var first float float-array float? + floats flush fn fn? fnext for force format future future-call future-cancel + future-cancelled? future-done? future? gen-class gen-interface gensym get + get-in get-method get-proxy-class get-thread-bindings get-validator hash + hash-map hash-set identical? identity if-let if-not ifn? import in-ns + inc init-proxy instance? int int-array integer? interleave intern + interpose into into-array ints io! isa? iterate iterator-seq juxt key + keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* + list? load load-file load-reader load-string loaded-libs locking long + long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy + map map? mapcat max max-key memfn memoize merge merge-with meta methods + min min-key mod name namespace neg? newline next nfirst nil? nnext not + not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns + ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth + nthnext num number? numerator object-array odd? or parents partial + partition pcalls peek persistent! pmap pop pop! pop-thread-bindings + pos? pr pr-str prefer-method prefers print print-namespace-doc + print-str printf println println-str prn prn-str promise proxy + proxy-mappings proxy-super push-thread-bindings pvalues quot rand + rand-int range ratio? rationalize re-find re-groups re-matcher + re-matches re-pattern re-seq read read-line read-string reduce ref + ref-history-count ref-max-history ref-min-history ref-set refer + refer-clojure reify release-pending-sends rem remove remove-all-methods + remove-method remove-ns remove-watch repeat repeatedly replace replicate + require reset! reset-meta! resolve rest restart-agent resultset-seq + reverse reversible? rseq rsubseq satisfies? second select-keys send + send-off seq seq? seque sequence sequential? set set-error-handler! + set-error-mode! set-validator! set? short short-array shorts + shutdown-agents slurp some sort sort-by sorted-map sorted-map-by + sorted-set sorted-set-by sorted? special-form-anchor special-symbol? + split-at split-with str string? struct struct-map subs subseq subvec + supers swap! symbol symbol? sync syntax-symbol-anchor take take-last + take-nth take-while test the-ns thread-bound? time to-array to-array-2d + trampoline transient tree-seq true? type unchecked-add unchecked-dec + unchecked-divide unchecked-inc unchecked-multiply unchecked-negate + unchecked-remainder unchecked-subtract underive update-in update-proxy + use val vals var-get var-set var? vary-meta vec vector vector-of vector? + when when-first when-let when-not while with-bindings with-bindings* + with-in-str with-local-vars with-meta with-open with-out-str + with-precision xml-seq zero? zipmap + ] # :nodoc: + + PREDEFINED_CONSTANTS = %w[ + true false nil *1 *2 *3 *agent* *clojure-version* *command-line-args* + *compile-files* *compile-path* *e *err* *file* *flush-on-newline* + *in* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* + *print-readably* *read-eval* *warn-on-reflection* + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(SPECIAL_FORMS, :keyword). + add(CORE_FORMS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEXT_TOKEN_KIND = WordList.new(nil). + add(%w[ def defn defn- definline defmacro defmulti defmethod defstruct defonce declare ], :function). + add(%w[ ns ], :namespace). + add(%w[ defprotocol defrecord ], :class) + + BASIC_IDENTIFIER = /[a-zA-Z$%*\/_+!?&<>\-=]=?[a-zA-Z0-9$&*+!\/_?<>\-\#]*/ + IDENTIFIER = /(?!-\d)(?:(?:#{BASIC_IDENTIFIER}\.)*#{BASIC_IDENTIFIER}(?:\/#{BASIC_IDENTIFIER})?\.?)|\.\.?/ + SYMBOL = /::?#{IDENTIFIER}/o + DIGIT = /\d/ + DIGIT10 = DIGIT + DIGIT16 = /[0-9a-f]/i + DIGIT8 = /[0-7]/ + DIGIT2 = /[01]/ + RADIX16 = /\#x/i + RADIX8 = /\#o/i + RADIX2 = /\#b/i + RADIX10 = /\#d/i + EXACTNESS = /#i|#e/i + SIGN = /[\+-]?/ + EXP_MARK = /[esfdl]/i + EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ + SUFFIX = /#{EXP}?/ + PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ + PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ + PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ + PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ + UINT10 = /#{DIGIT10}+#*/ + UINT16 = /#{DIGIT16}+#*/ + UINT8 = /#{DIGIT8}+#*/ + UINT2 = /#{DIGIT2}+#*/ + DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ + UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ + UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ + UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ + UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ + REAL10 = /#{SIGN}#{UREAL10}/ + REAL16 = /#{SIGN}#{UREAL16}/ + REAL8 = /#{SIGN}#{UREAL8}/ + REAL2 = /#{SIGN}#{UREAL2}/ + IMAG10 = /i|#{UREAL10}i/ + IMAG16 = /i|#{UREAL16}i/ + IMAG8 = /i|#{UREAL8}i/ + IMAG2 = /i|#{UREAL2}i/ + COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ + COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ + COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ + COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ + NUM10 = /#{PREFIX10}?#{COMPLEX10}/ + NUM16 = /#{PREFIX16}#{COMPLEX16}/ + NUM8 = /#{PREFIX8}#{COMPLEX8}/ + NUM2 = /#{PREFIX2}#{COMPLEX2}/ + NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ + + protected + + def scan_tokens encoder, options + + state = :initial + kind = nil + + until eos? + + case state + when :initial + if match = scan(/ \s+ | \\\n | , /x) + encoder.text_token match, :space + elsif match = scan(/['`\(\[\)\]\{\}]|\#[({]|~@?|[@\^]/) + encoder.text_token match, :operator + elsif match = scan(/;.*/) + encoder.text_token match, :comment # TODO: recognize (comment ...) too + elsif match = scan(/\#?\\(?:newline|space|.?)/) + encoder.text_token match, :char + elsif match = scan(/\#[ft]/) + encoder.text_token match, :predefined_constant + elsif match = scan(/#{IDENTIFIER}/o) + kind = IDENT_KIND[match] + encoder.text_token match, kind + if rest? && kind == :keyword + if kind = KEYWORD_NEXT_TOKEN_KIND[match] + encoder.text_token match, :space if match = scan(/\s+/o) + encoder.text_token match, kind if match = scan(/#{IDENTIFIER}/o) + end + end + elsif match = scan(/#{SYMBOL}/o) + encoder.text_token match, :symbol + elsif match = scan(/\./) + encoder.text_token match, :operator + elsif match = scan(/ \# \^ #{IDENTIFIER} /ox) + encoder.text_token match, :type + elsif match = scan(/ (\#)? " /x) + state = self[1] ? :regexp : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/#{NUM}/o) and not matched.empty? + encoder.text_token match, match[/[.e\/]/i] ? :float : :integer + else + encoder.text_token getch, :error + end + + when :string, :regexp + if match = scan(/[^"\\]+|\\.?/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), + encoder, state + end + + else + raise 'else case reached' + + end + + end + + if [:string, :regexp].include? state + encoder.end_group state + end + + encoder + + end + end + end +end \ No newline at end of file diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/cpp.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/cpp.rb new file mode 100644 index 00000000..cd4d0941 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/cpp.rb @@ -0,0 +1,217 @@ +module CodeRay +module Scanners + + # Scanner for C++. + # + # Aliases: +cplusplus+, c++ + class CPlusPlus < Scanner + + register_for :cpp + file_extension 'cpp' + title 'C++' + + #-- http://www.cppreference.com/wiki/keywords/start + KEYWORDS = [ + 'and', 'and_eq', 'asm', 'bitand', 'bitor', 'break', + 'case', 'catch', 'class', 'compl', 'const_cast', + 'continue', 'default', 'delete', 'do', 'dynamic_cast', 'else', + 'enum', 'export', 'for', 'goto', 'if', 'namespace', 'new', + 'not', 'not_eq', 'or', 'or_eq', 'reinterpret_cast', 'return', + 'sizeof', 'static_assert', 'static_cast', 'struct', 'switch', + 'template', 'throw', 'try', 'typedef', 'typeid', 'typename', 'union', + 'while', 'xor', 'xor_eq', + ] # :nodoc: + + PREDEFINED_TYPES = [ + 'bool', 'char', 'char16_t', 'char32_t', 'double', 'float', + 'int', 'long', 'short', 'signed', 'unsigned', + 'wchar_t', 'string', + ] # :nodoc: + PREDEFINED_CONSTANTS = [ + 'false', 'true', + 'EOF', 'NULL', 'nullptr' + ] # :nodoc: + PREDEFINED_VARIABLES = [ + 'this', + ] # :nodoc: + DIRECTIVES = [ + 'alignas', 'alignof', 'auto', 'const', 'constexpr', 'decltype', 'explicit', + 'extern', 'final', 'friend', 'inline', 'mutable', 'noexcept', 'operator', + 'override', 'private', 'protected', 'public', 'register', 'static', + 'thread_local', 'using', 'virtual', 'void', 'volatile', + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_VARIABLES, :local_variable). + add(DIRECTIVES, :directive). + add(PREDEFINED_CONSTANTS, :predefined_constant) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + label_expected = match =~ /[;\{\}]/ + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'class' + state = :class_name_expected + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token match, 'L', :modifier + match = '"' + end + state = :string + encoder.text_token match, :delimiter + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + elsif match = scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + label_expected = false + encoder.text_token match, :float + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ | $ /x) + encoder.end_group :string + encoder.text_token match, :error unless match.empty? + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + when :class_name_expected + if match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, :class + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + + else + encoder.text_token getch, :error + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/css.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/css.rb new file mode 100644 index 00000000..55d52397 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/css.rb @@ -0,0 +1,196 @@ +module CodeRay +module Scanners + + class CSS < Scanner + + register_for :css + + KINDS_NOT_LOC = [ + :comment, + :class, :pseudo_class, :tag, + :id, :directive, + :key, :value, :operator, :color, :float, :string, + :error, :important, :type, + ] # :nodoc: + + module RE # :nodoc: + Hex = /[0-9a-fA-F]/ + Unicode = /\\#{Hex}{1,6}\b/ # differs from standard because it allows uppercase hex too + Escape = /#{Unicode}|\\[^\n0-9a-fA-F]/ + NMChar = /[-_a-zA-Z0-9]/ + NMStart = /[_a-zA-Z]/ + String1 = /"(?:[^\n\\"]+|\\\n|#{Escape})*"?/ # TODO: buggy regexp + String2 = /'(?:[^\n\\']+|\\\n|#{Escape})*'?/ # TODO: buggy regexp + String = /#{String1}|#{String2}/ + + HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ + + Num = /-?(?:[0-9]*\.[0-9]+|[0-9]+)n?/ + Name = /#{NMChar}+/ + Ident = /-?#{NMStart}#{NMChar}*/ + AtKeyword = /@#{Ident}/ + Percentage = /#{Num}%/ + + reldimensions = %w[em ex px] + absdimensions = %w[in cm mm pt pc] + Unit = Regexp.union(*(reldimensions + absdimensions + %w[s dpi dppx deg])) + + Dimension = /#{Num}#{Unit}/ + + Function = /(?:url|alpha|attr|counters?)\((?:[^)\n]|\\\))*\)?/ + + Id = /(?!#{HexColor}\b(?!-))##{Name}/ + Class = /\.#{Name}/ + PseudoClass = /::?#{Ident}/ + AttributeSelector = /\[[^\]]*\]?/ + end + + protected + + def setup + @state = :initial + @value_expected = false + end + + def scan_tokens encoder, options + states = Array(options[:state] || @state).dup + value_expected = @value_expected + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif case states.last + when :initial, :media + if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox) + encoder.text_token match, :tag + next + elsif match = scan(RE::Class) + encoder.text_token match, :class + next + elsif match = scan(RE::Id) + encoder.text_token match, :id + next + elsif match = scan(RE::PseudoClass) + encoder.text_token match, :pseudo_class + next + elsif match = scan(RE::AttributeSelector) + # TODO: Improve highlighting inside of attribute selectors. + encoder.text_token match[0,1], :operator + encoder.text_token match[1..-2], :attribute_name if match.size > 2 + encoder.text_token match[-1,1], :operator if match[-1] == ?] + next + elsif match = scan(/@media/) + encoder.text_token match, :directive + states.push :media_before_name + next + end + + when :block + if match = scan(/(?>#{RE::Ident})(?!\()/ox) + if value_expected + encoder.text_token match, :value + else + encoder.text_token match, :key + end + next + end + + when :media_before_name + if match = scan(RE::Ident) + encoder.text_token match, :type + states[-1] = :media_after_name + next + end + + when :media_after_name + if match = scan(/\{/) + encoder.text_token match, :operator + states[-1] = :media + next + end + + else + #:nocov: + raise_inspect 'Unknown state', encoder + #:nocov: + + end + + elsif match = scan(/\/\*(?:.*?\*\/|\z)/m) + encoder.text_token match, :comment + + elsif match = scan(/\{/) + value_expected = false + encoder.text_token match, :operator + states.push :block + + elsif match = scan(/\}/) + value_expected = false + encoder.text_token match, :operator + if states.last == :block || states.last == :media + states.pop + end + + elsif match = scan(/#{RE::String}/o) + encoder.begin_group :string + encoder.text_token match[0, 1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1, 1], :delimiter if match.size >= 2 + encoder.end_group :string + + elsif match = scan(/#{RE::Function}/o) + encoder.begin_group :function + start = match[/^\w+\(/] + encoder.text_token start, :delimiter + if match[-1] == ?) + encoder.text_token match[start.size..-2], :content if match.size > start.size + 1 + encoder.text_token ')', :delimiter + else + encoder.text_token match[start.size..-1], :content if match.size > start.size + end + encoder.end_group :function + + elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) + encoder.text_token match, :float + + elsif match = scan(/#{RE::HexColor}/o) + encoder.text_token match, :color + + elsif match = scan(/! *important/) + encoder.text_token match, :important + + elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/) + encoder.text_token match, :color + + elsif match = scan(RE::AtKeyword) + encoder.text_token match, :directive + + elsif match = scan(/ [+>~:;,.=()\/] /x) + if match == ':' + value_expected = true + elsif match == ';' + value_expected = false + end + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + end + + if options[:keep_state] + @state = states + @value_expected = value_expected + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/debug.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/debug.rb new file mode 100644 index 00000000..83ede9a5 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/debug.rb @@ -0,0 +1,75 @@ +require 'set' + +module CodeRay +module Scanners + + # = Debug Scanner + # + # Interprets the output of the Encoders::Debug encoder (basically the inverse function). + class Debug < Scanner + + register_for :debug + title 'CodeRay Token Dump Import' + + protected + + def setup + super + @known_token_kinds = TokenKinds.keys.map(&:to_s).to_set + end + + def scan_tokens encoder, options + + opened_tokens = [] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) \)? /x) + if @known_token_kinds.include? self[1] + encoder.text_token self[2].gsub(/\\(.)/m, '\1'), self[1].to_sym + else + encoder.text_token matched, :unknown + end + + elsif match = scan(/ (\w+) ([<\[]) /x) + if @known_token_kinds.include? self[1] + kind = self[1].to_sym + else + kind = :unknown + end + + opened_tokens << kind + case self[2] + when '<' + encoder.begin_group kind + when '[' + encoder.begin_line kind + else + raise 'CodeRay bug: This case should not be reached.' + end + + elsif !opened_tokens.empty? && match = scan(/ > /x) + encoder.end_group opened_tokens.pop + + elsif !opened_tokens.empty? && match = scan(/ \] /x) + encoder.end_line opened_tokens.pop + + else + encoder.text_token getch, :space + + end + + end + + encoder.end_group opened_tokens.pop until opened_tokens.empty? + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/delphi.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/delphi.rb new file mode 100644 index 00000000..b328155a --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/delphi.rb @@ -0,0 +1,144 @@ +module CodeRay +module Scanners + + # Scanner for the Delphi language (Object Pascal). + # + # Alias: +pascal+ + class Delphi < Scanner + + register_for :delphi + file_extension 'pas' + + KEYWORDS = [ + 'and', 'array', 'as', 'at', 'asm', 'at', 'begin', 'case', 'class', + 'const', 'constructor', 'destructor', 'dispinterface', 'div', 'do', + 'downto', 'else', 'end', 'except', 'exports', 'file', 'finalization', + 'finally', 'for', 'function', 'goto', 'if', 'implementation', 'in', + 'inherited', 'initialization', 'inline', 'interface', 'is', 'label', + 'library', 'mod', 'nil', 'not', 'object', 'of', 'or', 'out', 'packed', + 'procedure', 'program', 'property', 'raise', 'record', 'repeat', + 'resourcestring', 'set', 'shl', 'shr', 'string', 'then', 'threadvar', + 'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 'while', 'with', + 'xor', 'on', + ] # :nodoc: + + DIRECTIVES = [ + 'absolute', 'abstract', 'assembler', 'at', 'automated', 'cdecl', + 'contains', 'deprecated', 'dispid', 'dynamic', 'export', + 'external', 'far', 'forward', 'implements', 'local', + 'near', 'nodefault', 'on', 'overload', 'override', + 'package', 'pascal', 'platform', 'private', 'protected', 'public', + 'published', 'read', 'readonly', 'register', 'reintroduce', + 'requires', 'resident', 'safecall', 'stdcall', 'stored', 'varargs', + 'virtual', 'write', 'writeonly', + ] # :nodoc: + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(DIRECTIVES, :directive) # :nodoc: + + NAME_FOLLOWS = WordList::CaseIgnoring.new(false). + add(%w(procedure function .)) # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + last_token = '' + + until eos? + + if state == :initial + + if match = scan(/ \s+ /x) + encoder.text_token match, :space + next + + elsif match = scan(%r! \{ \$ [^}]* \}? | \(\* \$ (?: .*? \*\) | .* ) !mx) + encoder.text_token match, :preprocessor + next + + elsif match = scan(%r! // [^\n]* | \{ [^}]* \}? | \(\* (?: .*? \*\) | .* ) !mx) + encoder.text_token match, :comment + next + + elsif match = scan(/ <[>=]? | >=? | :=? | [-+=*\/;,@\^|\(\)\[\]] | \.\. /x) + encoder.text_token match, :operator + + elsif match = scan(/\./) + encoder.text_token match, :operator + next if last_token == 'end' + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, NAME_FOLLOWS[last_token] ? :ident : IDENT_KIND[match] + + elsif match = skip(/ ' ( [^\n']|'' ) (?:'|$) /x) + encoder.begin_group :char + encoder.text_token "'", :delimiter + encoder.text_token self[1], :content + encoder.text_token "'", :delimiter + encoder.end_group :char + next + + elsif match = scan(/ ' /x) + encoder.begin_group :string + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ \# (?: \d+ | \$[0-9A-Fa-f]+ ) /x) + encoder.text_token match, :char + + elsif match = scan(/ \$ [0-9A-Fa-f]+ /x) + encoder.text_token match, :hex + + elsif match = scan(/ (?: \d+ ) (?![eE]|\.[^.]) /x) + encoder.text_token match, :integer + + elsif match = scan(/ \d+ (?: \.\d+ (?: [eE][+-]? \d+ )? | [eE][+-]? \d+ ) /x) + encoder.text_token match, :float + + else + encoder.text_token getch, :error + next + + end + + elsif state == :string + if match = scan(/[^\n']+/) + encoder.text_token match, :content + elsif match = scan(/''/) + encoder.text_token match, :char + elsif match = scan(/'/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + next + elsif match = scan(/\n/) + encoder.end_group :string + encoder.text_token match, :space + state = :initial + else + raise "else case \' reached; %p not handled." % peek(1), encoder + end + + else + raise 'else-case reached', encoder + + end + + last_token = match + + end + + if state == :string + encoder.end_group state + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/diff.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/diff.rb new file mode 100644 index 00000000..a2a6fccf --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/diff.rb @@ -0,0 +1,221 @@ +module CodeRay +module Scanners + + # Scanner for output of the diff command. + # + # Alias: +patch+ + class Diff < Scanner + + register_for :diff + title 'diff output' + + DEFAULT_OPTIONS = { + :highlight_code => true, + :inline_diff => true, + } + + protected + + def scan_tokens encoder, options + + line_kind = nil + state = :initial + deleted_lines_count = 0 + scanners = Hash.new do |h, lang| + h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true + end + content_scanner = scanners[:plain] + content_scanner_entry_state = nil + + until eos? + + if match = scan(/\n/) + deleted_lines_count = 0 unless line_kind == :delete + if line_kind + encoder.end_line line_kind + line_kind = nil + end + encoder.text_token match, :space + next + end + + case state + + when :initial + if match = scan(/--- |\+\+\+ |=+|_+/) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + if match = scan(/[^\x00\n]+?(?=$|[\t\n]| \(revision)/) + encoder.text_token match, :filename + if options[:highlight_code] && match != '/dev/null' + file_type = CodeRay::FileType.fetch(match, :text) + file_type = :text if file_type == :diff + content_scanner = scanners[file_type] + content_scanner_entry_state = nil + end + end + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Index: |Property changes on: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Added: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + state = :added + elsif match = scan(/\\ .*/) + encoder.text_token match, :comment + elsif match = scan(/@@(?>[^@\n]+)@@/) + content_scanner.state = :initial unless match?(/\n\+/) + content_scanner_entry_state = nil + if check(/\n|$/) + encoder.begin_line line_kind = :change + else + encoder.begin_group :change + end + encoder.text_token match[0,2], :change + encoder.text_token match[2...-2], :plain + encoder.text_token match[-2,2], :change + encoder.end_group :change unless line_kind + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/\+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/-/) + deleted_lines_count += 1 + if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/.*(?:\n\-.*)*/).count("\n")) && changed_lines_count <= 100_000 && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/) + deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) } + inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) } + + deleted_lines_tokenized = [] + inserted_lines_tokenized = [] + for deleted_line, inserted_line in deleted_lines.zip(inserted_lines) + pre, deleted_part, inserted_part, post = diff deleted_line, inserted_line + content_scanner_entry_state = content_scanner.state + deleted_lines_tokenized << content_scanner.tokenize([pre, deleted_part, post], :tokens => Tokens.new) + content_scanner.state = content_scanner_entry_state || :initial + inserted_lines_tokenized << content_scanner.tokenize([pre, inserted_part, post], :tokens => Tokens.new) + end + + for pre, deleted_part, post in deleted_lines_tokenized + encoder.begin_line :delete + encoder.text_token '-', :delete + encoder.tokens pre + unless deleted_part.empty? + encoder.begin_group :eyecatcher + encoder.tokens deleted_part + encoder.end_group :eyecatcher + end + encoder.tokens post + encoder.end_line :delete + encoder.text_token "\n", :space + end + + for pre, inserted_part, post in inserted_lines_tokenized + encoder.begin_line :insert + encoder.text_token '+', :insert + encoder.tokens pre + unless inserted_part.empty? + encoder.begin_group :eyecatcher + encoder.tokens inserted_part + encoder.end_group :eyecatcher + end + encoder.tokens post + changed_lines_count -= 1 + if changed_lines_count > 0 + encoder.end_line :insert + encoder.text_token "\n", :space + end + end + + line_kind = :insert + + elsif match = scan(/.*/) + encoder.begin_line line_kind = :delete + encoder.text_token '-', :delete + if options[:highlight_code] + if deleted_lines_count == 1 + content_scanner_entry_state = content_scanner.state + end + content_scanner.tokenize match, :tokens => encoder unless match.empty? + if !match?(/\n-/) + if match?(/\n\+/) + content_scanner.state = content_scanner_entry_state || :initial + end + content_scanner_entry_state = nil + end + else + encoder.text_token match, :plain + end + end + next + elsif match = scan(/ .*/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/.+/) + encoder.begin_line line_kind = :comment + encoder.text_token match, :plain + else + raise_inspect 'else case rached' + end + + when :added + if match = scan(/ \+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + encoder.text_token match, :plain + else + state = :initial + next + end + end + + end + + encoder.end_line line_kind if line_kind + + encoder + end + + private + + def diff a, b + # i will be the index of the leftmost difference from the left. + i_max = [a.size, b.size].min + i = 0 + i += 1 while i < i_max && a[i] == b[i] + # j_min will be the index of the leftmost difference from the right. + j_min = i - i_max + # j will be the index of the rightmost difference from the right which + # does not precede the leftmost one from the left. + j = -1 + j -= 1 while j >= j_min && a[j] == b[j] + return a[0...i], a[i..j], b[i..j], (j < -1) ? a[j + 1..-1] : '' + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/erb.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/erb.rb new file mode 100644 index 00000000..727a993b --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/erb.rb @@ -0,0 +1,81 @@ +module CodeRay +module Scanners + + load :html + load :ruby + + # Scanner for HTML ERB templates. + class ERB < Scanner + + register_for :erb + title 'HTML ERB Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + ERB_RUBY_BLOCK = / + (<%(?!%)[-=\#]?) + ((?> + [^\-%]* # normal* + (?> # special + (?: %(?!>) | -(?!%>) ) + [^\-%]* # normal* + )* + )) + ((?: -?%> )?) + /x # :nodoc: + + START_OF_ERB = / + <%(?!%) + /x # :nodoc: + + protected + + def setup + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + def scan_tokens encoder, options + + until eos? + + if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_rest) and not match.empty? + @html_scanner.tokenize match, :tokens => encoder + + elsif match = scan(/#{ERB_RUBY_BLOCK}/o) + start_tag = self[1] + code = self[2] + end_tag = self[3] + + encoder.begin_group :inline + encoder.text_token start_tag, :inline_delimiter + + if start_tag == '<%#' + encoder.text_token code, :comment + else + @ruby_scanner.tokenize code, :tokens => encoder + end unless code.empty? + + encoder.text_token end_tag, :inline_delimiter unless end_tag.empty? + encoder.end_group :inline + + else + raise_inspect 'else-case reached!', encoder + + end + + end + + encoder + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/go.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/go.rb new file mode 100644 index 00000000..99fdd638 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/go.rb @@ -0,0 +1,208 @@ +module CodeRay +module Scanners + + class Go < Scanner + + register_for :go + file_extension 'go' + + # http://golang.org/ref/spec#Keywords + KEYWORDS = [ + 'break', 'default', 'func', 'interface', 'select', + 'case', 'defer', 'go', 'map', 'struct', + 'chan', 'else', 'goto', 'package', 'switch', + 'const', 'fallthrough', 'if', 'range', 'type', + 'continue', 'for', 'import', 'return', 'var', + ] # :nodoc: + + # http://golang.org/ref/spec#Types + PREDEFINED_TYPES = [ + 'bool', + 'uint8', 'uint16', 'uint32', 'uint64', + 'int8', 'int16', 'int32', 'int64', + 'float32', 'float64', + 'complex64', 'complex128', + 'byte', 'rune', 'string', 'error', + 'uint', 'int', 'uintptr', + ] # :nodoc: + + PREDEFINED_CONSTANTS = [ + 'nil', 'iota', + 'true', 'false', + ] # :nodoc: + + PREDEFINED_FUNCTIONS = %w[ + append cap close complex copy delete imag len + make new panic print println real recover + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(PREDEFINED_FUNCTIONS, :predefined) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + case_expected = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ ?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + label_expected = false + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token 'L', :modifier + match = '"' + end + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ ` ([^`]+)? (`)? /x) + encoder.begin_group :shell + encoder.text_token '`', :delimiter + encoder.text_token self[1], :content if self[1] + encoder.text_token self[2], :delimiter if self[2] + encoder.end_group :shell + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/-?\d*(\.\d*)?([eE][+-]?\d+)?i/) + label_expected = false + encoder.text_token match, :imaginary + + elsif match = scan(/-?0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/-?(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/-?(?:\d*\.\d+|\d+\.)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) + label_expected = false + encoder.text_token match, :float + + elsif match = scan(/-?(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\\n"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ /x) + encoder.text_token match, :error + elsif match = scan(/$/) + encoder.end_group :string + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/groovy.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/groovy.rb new file mode 100644 index 00000000..c52ce8d3 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/groovy.rb @@ -0,0 +1,268 @@ +module CodeRay +module Scanners + + load :java + + # Scanner for Groovy. + class Groovy < Java + + register_for :groovy + + # TODO: check list of keywords + GROOVY_KEYWORDS = %w[ + as assert def in + ] # :nodoc: + KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ + case instanceof new return throw typeof while as assert in + ] # :nodoc: + GROOVY_MAGIC_VARIABLES = %w[ it ] # :nodoc: + + IDENT_KIND = Java::IDENT_KIND.dup. + add(GROOVY_KEYWORDS, :keyword). + add(GROOVY_MAGIC_VARIABLES, :local_variable) # :nodoc: + + ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: no 4-byte unicode chars? U[a-fA-F0-9]{8} + REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x # :nodoc: + + # TODO: interpretation inside ', ", / + STRING_CONTENT_PATTERN = { + "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/, + '"' => /[^\\$"\n]+/, + "'''" => /(?>[^\\']+|'(?!''))+/, + '"""' => /(?>[^\\$"]+|"(?!""))+/, + '/' => /[^\\$\/\n]+/, + } # :nodoc: + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + state = options[:state] || @state + inline_block_stack = [] + inline_block_paren_depth = nil + string_delimiter = nil + import_clause = class_name_follows = last_token = after_def = false + value_expected = true + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + if match.index ?\n + import_clause = after_def = false + value_expected = true unless value_expected + end + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + value_expected = true + after_def = false + encoder.text_token match, :comment + + elsif bol? && match = scan(/ \#!.* /x) + encoder.text_token match, :doctype + + elsif import_clause && match = scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox) + after_def = value_expected = false + encoder.text_token match, :include + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] + if last_token == '.' + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + elsif after_def && check(/\s*[({]/) + kind = :method + after_def = false + elsif kind == :ident && last_token != '?' && check(/:/) + kind = :key + else + class_name_follows = true if match == 'class' || (import_clause && match == 'as') + import_clause = match == 'import' + after_def = true if match == 'def' + end + encoder.text_token match, kind + + elsif match = scan(/;/) + import_clause = after_def = false + value_expected = true + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = after_def = false + value_expected = true + encoder.text_token match, :operator + if !inline_block_stack.empty? + inline_block_paren_depth += 1 + end + + # TODO: ~'...', ~"..." and ~/.../ style regexps + elsif match = scan(/ \.\.] | \+\+ | + && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<>>?=? /x) + value_expected = true + value_expected = :regexp if match == '~' + after_def = false + encoder.text_token match, :operator + + elsif match = scan(/ [)\]}] /x) + value_expected = after_def = false + if !inline_block_stack.empty? && match == '}' + inline_block_paren_depth -= 1 + if inline_block_paren_depth == 0 # closing brace of inline block reached + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop + next + end + end + encoder.text_token match, :operator + + elsif check(/[\d.]/) + after_def = value_expected = false + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lLgG]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/'''|"""/) + after_def = value_expected = false + state = :multiline_string + encoder.begin_group :string + string_delimiter = match + encoder.text_token match, :delimiter + + # TODO: record.'name' syntax + elsif match = scan(/["']/) + after_def = value_expected = false + state = match == '/' ? :regexp : :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/\//) + after_def = value_expected = false + encoder.begin_group :regexp + state = :regexp + string_delimiter = '/' + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + after_def = value_expected = false + encoder.text_token match, :annotation + + elsif match = scan(/\//) + after_def = false + value_expected = true + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + when :string, :regexp, :multiline_string + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + + elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/) + encoder.text_token match, :delimiter + if state == :regexp + # TODO: regexp modifiers? s, m, x, i? + modifiers = scan(/[ix]+/) + encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty? + end + state = :string if state == :multiline_string + encoder.end_group state + string_delimiter = nil + after_def = value_expected = false + state = :initial + next + + elsif (state == :string || state == :multiline_string) && + (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif state == :regexp && match = scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + + elsif match = scan(/ \$ #{IDENT} /mox) + encoder.begin_group :inline + encoder.text_token '$', :inline_delimiter + match = match[1..-1] + encoder.text_token match, IDENT_KIND[match] + encoder.end_group :inline + next + elsif match = scan(/ \$ \{ /x) + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + inline_block_stack << [state, string_delimiter, inline_block_paren_depth] + inline_block_paren_depth = 1 + state = :initial + next + + elsif match = scan(/ \$ /mx) + encoder.text_token match, :content + + elsif match = scan(/ \\. /mx) + encoder.text_token match, :content # TODO: Shouldn't this be :error? + + elsif match = scan(/ \\ | \n /x) + encoder.end_group state == :regexp ? :regexp : :string + encoder.text_token match, :error + after_def = value_expected = false + state = :initial + + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token = match unless [:space, :comment, :doctype].include? kind + + end + + if [:multiline_string, :string, :regexp].include? state + encoder.end_group state == :regexp ? :regexp : :string + end + + if options[:keep_state] + @state = state + end + + until inline_block_stack.empty? + state, = *inline_block_stack.pop + encoder.end_group :inline + encoder.end_group state == :regexp ? :regexp : :string + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/haml.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/haml.rb new file mode 100644 index 00000000..d516ba9e --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/haml.rb @@ -0,0 +1,168 @@ +module CodeRay +module Scanners + + load :ruby + load :html + load :java_script + + class HAML < Scanner + + register_for :haml + title 'HAML Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + super + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @embedded_ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true, :state => @ruby_scanner.interpreted_string_state + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true + end + + def scan_tokens encoder, options + + match = nil + code = '' + + until eos? + + if bol? + if match = scan(/!!!.*/) + encoder.text_token match, :doctype + next + end + + if match = scan(/(?>( *)(\/(?!\[if)|-\#|:javascript|:ruby|:\w+) *)(?=\n)/) + encoder.text_token match, :comment + + code = self[2] + if match = scan(/(?:\n+#{self[1]} .*)+/) + case code + when '/', '-#' + encoder.text_token match, :comment + when ':javascript' + # TODO: recognize #{...} snippets inside JavaScript + @java_script_scanner ||= CodeRay.scanner :java_script, :tokens => @tokens, :keep_tokens => true + @java_script_scanner.tokenize match, :tokens => encoder + when ':ruby' + @ruby_scanner.tokenize match, :tokens => encoder + when /:\w+/ + encoder.text_token match, :comment + else + raise 'else-case reached: %p' % [code] + end + end + end + + if match = scan(/ +/) + encoder.text_token match, :space + end + + if match = scan(/\/.*/) + encoder.text_token match, :comment + next + end + + if match = scan(/\\/) + encoder.text_token match, :plain + if match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + end + next + end + + tag = false + + if match = scan(/%[-\w:]+\/?/) + encoder.text_token match, :tag + # if match = scan(/( +)(.+)/) + # encoder.text_token self[1], :space + # @embedded_ruby_scanner.tokenize self[2], :tokens => encoder + # end + tag = true + end + + while match = scan(/([.#])[-\w]*\w/) + encoder.text_token match, self[1] == '#' ? :constant : :class + tag = true + end + + if tag && match = scan(/(\()([^)]+)?(\))?/) + # TODO: recognize title=@title, class="widget_#{@widget.number}" + encoder.text_token self[1], :plain + @html_scanner.tokenize self[2], :tokens => encoder, :state => :attribute if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\{/) + encoder.text_token match, :plain + + code = '' + level = 1 + while true + code << scan(/([^\{\},\n]|, *\n?)*/) + case match = getch + when '{' + level += 1 + code << match + when '}' + level -= 1 + if level > 0 + code << match + else + break + end + when "\n", ",", nil + break + end + end + @ruby_scanner.tokenize code, :tokens => encoder unless code.empty? + + encoder.text_token match, :plain if match + end + + if tag && match = scan(/(\[)([^\]\n]+)?(\])?/) + encoder.text_token self[1], :plain + @ruby_scanner.tokenize self[2], :tokens => encoder if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\//) + encoder.text_token match, :tag + end + + if scan(/(>? encoder + else + @ruby_scanner.tokenize self[4], :tokens => encoder + end + end + elsif match = scan(/((?:<|> encoder if self[2] + end + + elsif match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + + end + + if match = scan(/\n/) + encoder.text_token match, :space + end + end + + encoder + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/html.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/html.rb new file mode 100644 index 00000000..ebe7b01d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/html.rb @@ -0,0 +1,275 @@ +module CodeRay +module Scanners + + # HTML Scanner + # + # Alias: +xhtml+ + # + # See also: Scanners::XML + class HTML < Scanner + + register_for :html + + KINDS_NOT_LOC = [ + :comment, :doctype, :preprocessor, + :tag, :attribute_name, :operator, + :attribute_value, :string, + :plain, :entity, :error, + ] # :nodoc: + + EVENT_ATTRIBUTES = %w( + onabort onafterprint onbeforeprint onbeforeunload onblur oncanplay + oncanplaythrough onchange onclick oncontextmenu oncuechange ondblclick + ondrag ondragdrop ondragend ondragenter ondragleave ondragover + ondragstart ondrop ondurationchange onemptied onended onerror onfocus + onformchange onforminput onhashchange oninput oninvalid onkeydown + onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart + onmessage onmousedown onmousemove onmouseout onmouseover onmouseup + onmousewheel onmove onoffline ononline onpagehide onpageshow onpause + onplay onplaying onpopstate onprogress onratechange onreadystatechange + onredo onreset onresize onscroll onseeked onseeking onselect onshow + onstalled onstorage onsubmit onsuspend ontimeupdate onundo onunload + onvolumechange onwaiting + ) + + IN_ATTRIBUTE = WordList::CaseIgnoring.new(nil). + add(EVENT_ATTRIBUTES, :script). + add(['style'], :style) + + ATTR_NAME = /[\w.:-]+/ # :nodoc: + TAG_END = /\/?>/ # :nodoc: + HEX = /[0-9a-fA-F]/ # :nodoc: + ENTITY = / + & + (?: + \w+ + | + \# + (?: + \d+ + | + x#{HEX}+ + ) + ) + ; + /ox # :nodoc: + + PLAIN_STRING_CONTENT = { + "'" => /[^&'>\n]+/, + '"' => /[^&">\n]+/, + } # :nodoc: + + def reset + super + @state = :initial + @plain_string_content = nil + end + + protected + + def setup + @state = :initial + @plain_string_content = nil + @in_tag = nil + end + + def scan_java_script encoder, code + if code && !code.empty? + @java_script_scanner ||= Scanners::JavaScript.new '', :keep_tokens => true + @java_script_scanner.tokenize code, :tokens => encoder + end + end + + def scan_css encoder, code, state = [:initial] + if code && !code.empty? + @css_scanner ||= Scanners::CSS.new '', :keep_tokens => true + @css_scanner.tokenize code, :tokens => encoder, :state => state + end + end + + def scan_tokens encoder, options + state = options[:state] || @state + plain_string_content = @plain_string_content + in_tag = @in_tag + in_attribute = nil + + encoder.begin_group :string if state == :attribute_value_string + + until eos? + + if state != :in_special_tag && match = scan(/\s+/m) + encoder.text_token match, :space + + else + + case state + + when :initial + if match = scan(//m) + encoder.text_token match[0..-4], :plain + encoder.text_token ']]>', :inline_delimiter + elsif match = scan(/.+/) + encoder.text_token match, :error + end + elsif match = scan(/|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/|.*)|\]>/m) + encoder.text_token match, :doctype + elsif match = scan(/<\?xml(?:.*?\?>|.*)/m) + encoder.text_token match, :preprocessor + elsif match = scan(/<\?(?:.*?\?>|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/<\/[-\w.:]*>?/m) + in_tag = nil + encoder.text_token match, :tag + elsif match = scan(/<(?:(script|style)|[-\w.:]+)(>)?/m) + encoder.text_token match, :tag + in_tag = self[1] + if self[2] + state = :in_special_tag if in_tag + else + state = :attribute + end + elsif match = scan(/[^<>&]+/) + encoder.text_token match, :plain + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/[<>&]/) + in_tag = nil + encoder.text_token match, :error + else + raise_inspect '[BUG] else-case reached with state %p' % [state], encoder + end + + when :attribute + if match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + in_attribute = nil + if in_tag + state = :in_special_tag + else + state = :initial + end + elsif match = scan(/#{ATTR_NAME}/o) + in_attribute = IN_ATTRIBUTE[match] + encoder.text_token match, :attribute_name + state = :attribute_equal + else + in_tag = nil + encoder.text_token getch, :error + end + + when :attribute_equal + if match = scan(/=/) #/ + encoder.text_token match, :operator + state = :attribute_value + else + state = :attribute + next + end + + when :attribute_value + if match = scan(/#{ATTR_NAME}/o) + encoder.text_token match, :attribute_value + state = :attribute + elsif match = scan(/["']/) + if in_attribute == :script || in_attribute == :style + encoder.begin_group :string + encoder.text_token match, :delimiter + if scan(/javascript:[ \t]*/) + encoder.text_token matched, :comment + end + code = scan_until(match == '"' ? /(?="|\z)/ : /(?='|\z)/) + if in_attribute == :script + scan_java_script encoder, code + else + scan_css encoder, code, [:block] + end + match = scan(/["']/) + encoder.text_token match, :delimiter if match + encoder.end_group :string + state = :attribute + in_attribute = nil + else + encoder.begin_group :string + state = :attribute_value_string + plain_string_content = PLAIN_STRING_CONTENT[match] + encoder.text_token match, :delimiter + end + elsif match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + state = :initial + else + encoder.text_token getch, :error + end + + when :attribute_value_string + if match = scan(plain_string_content) + encoder.text_token match, :content + elsif match = scan(/['"]/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :attribute + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/&/) + encoder.text_token match, :content + elsif match = scan(/[\n>]/) + encoder.end_group :string + state = :initial + encoder.text_token match, :error + end + + when :in_special_tag + case in_tag + when 'script', 'style' + encoder.text_token match, :space if match = scan(/[ \t]*\n/) + if scan(/(\s*)|(.*))/m) + code = self[2] || self[4] + closing = self[3] + encoder.text_token self[1], :comment + else + code = scan_until(/(?=(?:\n\s*)?<\/#{in_tag}>)|\z/) + closing = false + end + unless code.empty? + encoder.begin_group :inline + if in_tag == 'script' + scan_java_script encoder, code + else + scan_css encoder, code + end + encoder.end_group :inline + end + encoder.text_token closing, :comment if closing + state = :initial + else + raise 'unknown special tag: %p' % [in_tag] + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + + end + + end + + if options[:keep_state] + @state = state + @plain_string_content = plain_string_content + @in_tag = in_tag + end + + encoder.end_group :string if state == :attribute_value_string + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/java.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java.rb new file mode 100644 index 00000000..7dd1919e --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java.rb @@ -0,0 +1,174 @@ +module CodeRay +module Scanners + + # Scanner for Java. + class Java < Scanner + + register_for :java + + autoload :BuiltinTypes, CodeRay.coderay_path('scanners', 'java', 'builtin_types') + + # http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html + KEYWORDS = %w[ + assert break case catch continue default do else + finally for if instanceof import new package + return switch throw try typeof while + debugger export + ] # :nodoc: + RESERVED = %w[ const goto ] # :nodoc: + CONSTANTS = %w[ false null true ] # :nodoc: + MAGIC_VARIABLES = %w[ this super ] # :nodoc: + TYPES = %w[ + boolean byte char class double enum float int interface long + short void var + ] << '[]' # :nodoc: because int[] should be highlighted as a type + DIRECTIVES = %w[ + abstract extends final implements native private protected public + static strictfp synchronized throws transient volatile + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(RESERVED, :reserved). + add(CONSTANTS, :predefined_constant). + add(MAGIC_VARIABLES, :local_variable). + add(TYPES, :type). + add(BuiltinTypes::List, :predefined_type). + add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception). + add(DIRECTIVES, :directive) # :nodoc: + + ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + STRING_CONTENT_PATTERN = { + "'" => /[^\\']+/, + '"' => /[^\\"]+/, + '/' => /[^\\\/]+/, + } # :nodoc: + IDENT = RUBY_VERSION < '1.9' ? /[a-zA-Z_][A-Za-z_0-9]*/ : Regexp.new('[[[:alpha:]]_][[[:alnum:]]_]*') # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + package_name_expected = false + class_name_follows = false + last_token_dot = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + next + + elsif package_name_expected && match = scan(/ #{IDENT} (?: \. #{IDENT} )* /ox) + encoder.text_token match, package_name_expected + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + if last_token_dot + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + else + case match + when 'import' + package_name_expected = :include + when 'package' + package_name_expected = :namespace + when 'class', 'interface' + class_name_follows = true + end + end + encoder.text_token match, kind + + elsif match = scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<>>?=? /x) + encoder.text_token match, :operator + + elsif match = scan(/;/) + package_name_expected = false + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = false + encoder.text_token match, :operator + + elsif check(/[\d.]/) + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lL]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/["']/) + state = :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + encoder.text_token match, :annotation + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + elsif match = scan(/["'\/]/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + string_delimiter = nil + elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + state = :initial + encoder.text_token match, :error unless match.empty? + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group state + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/java/builtin_types.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java/builtin_types.rb new file mode 100644 index 00000000..d1b8b73b --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java/builtin_types.rb @@ -0,0 +1,421 @@ +module CodeRay +module Scanners + + module Java::BuiltinTypes # :nodoc: + + #:nocov: + List = %w[ + AbstractAction AbstractBorder AbstractButton AbstractCellEditor AbstractCollection + AbstractColorChooserPanel AbstractDocument AbstractExecutorService AbstractInterruptibleChannel + AbstractLayoutCache AbstractList AbstractListModel AbstractMap AbstractMethodError AbstractPreferences + AbstractQueue AbstractQueuedSynchronizer AbstractSelectableChannel AbstractSelectionKey AbstractSelector + AbstractSequentialList AbstractSet AbstractSpinnerModel AbstractTableModel AbstractUndoableEdit + AbstractWriter AccessControlContext AccessControlException AccessController AccessException Accessible + AccessibleAction AccessibleAttributeSequence AccessibleBundle AccessibleComponent AccessibleContext + AccessibleEditableText AccessibleExtendedComponent AccessibleExtendedTable AccessibleExtendedText + AccessibleHyperlink AccessibleHypertext AccessibleIcon AccessibleKeyBinding AccessibleObject + AccessibleRelation AccessibleRelationSet AccessibleResourceBundle AccessibleRole AccessibleSelection + AccessibleState AccessibleStateSet AccessibleStreamable AccessibleTable AccessibleTableModelChange + AccessibleText AccessibleTextSequence AccessibleValue AccountException AccountExpiredException + AccountLockedException AccountNotFoundException Acl AclEntry AclNotFoundException Action ActionEvent + ActionListener ActionMap ActionMapUIResource Activatable ActivateFailedException ActivationDesc + ActivationException ActivationGroup ActivationGroupDesc ActivationGroupID ActivationGroup_Stub + ActivationID ActivationInstantiator ActivationMonitor ActivationSystem Activator ActiveEvent + ActivityCompletedException ActivityRequiredException Adjustable AdjustmentEvent AdjustmentListener + Adler32 AffineTransform AffineTransformOp AlgorithmParameterGenerator AlgorithmParameterGeneratorSpi + AlgorithmParameters AlgorithmParameterSpec AlgorithmParametersSpi AllPermission AlphaComposite + AlreadyBoundException AlreadyConnectedException AncestorEvent AncestorListener AnnotatedElement + Annotation AnnotationFormatError AnnotationTypeMismatchException AppConfigurationEntry Appendable Applet + AppletContext AppletInitializer AppletStub Arc2D Area AreaAveragingScaleFilter ArithmeticException Array + ArrayBlockingQueue ArrayIndexOutOfBoundsException ArrayList Arrays ArrayStoreException ArrayType + AssertionError AsyncBoxView AsynchronousCloseException AtomicBoolean AtomicInteger AtomicIntegerArray + AtomicIntegerFieldUpdater AtomicLong AtomicLongArray AtomicLongFieldUpdater AtomicMarkableReference + AtomicReference AtomicReferenceArray AtomicReferenceFieldUpdater AtomicStampedReference Attribute + AttributeChangeNotification AttributeChangeNotificationFilter AttributedCharacterIterator + AttributedString AttributeException AttributeInUseException AttributeList AttributeModificationException + AttributeNotFoundException Attributes AttributeSet AttributeSetUtilities AttributeValueExp AudioClip + AudioFileFormat AudioFileReader AudioFileWriter AudioFormat AudioInputStream AudioPermission AudioSystem + AuthenticationException AuthenticationNotSupportedException Authenticator AuthorizeCallback + AuthPermission AuthProvider Autoscroll AWTError AWTEvent AWTEventListener AWTEventListenerProxy + AWTEventMulticaster AWTException AWTKeyStroke AWTPermission BackingStoreException + BadAttributeValueExpException BadBinaryOpValueExpException BadLocationException BadPaddingException + BadStringOperationException BandCombineOp BandedSampleModel BaseRowSet BasicArrowButton BasicAttribute + BasicAttributes BasicBorders BasicButtonListener BasicButtonUI BasicCheckBoxMenuItemUI BasicCheckBoxUI + BasicColorChooserUI BasicComboBoxEditor BasicComboBoxRenderer BasicComboBoxUI BasicComboPopup + BasicControl BasicDesktopIconUI BasicDesktopPaneUI BasicDirectoryModel BasicEditorPaneUI + BasicFileChooserUI BasicFormattedTextFieldUI BasicGraphicsUtils BasicHTML BasicIconFactory + BasicInternalFrameTitlePane BasicInternalFrameUI BasicLabelUI BasicListUI BasicLookAndFeel + BasicMenuBarUI BasicMenuItemUI BasicMenuUI BasicOptionPaneUI BasicPanelUI BasicPasswordFieldUI + BasicPermission BasicPopupMenuSeparatorUI BasicPopupMenuUI BasicProgressBarUI BasicRadioButtonMenuItemUI + BasicRadioButtonUI BasicRootPaneUI BasicScrollBarUI BasicScrollPaneUI BasicSeparatorUI BasicSliderUI + BasicSpinnerUI BasicSplitPaneDivider BasicSplitPaneUI BasicStroke BasicTabbedPaneUI BasicTableHeaderUI + BasicTableUI BasicTextAreaUI BasicTextFieldUI BasicTextPaneUI BasicTextUI BasicToggleButtonUI + BasicToolBarSeparatorUI BasicToolBarUI BasicToolTipUI BasicTreeUI BasicViewportUI BatchUpdateException + BeanContext BeanContextChild BeanContextChildComponentProxy BeanContextChildSupport + BeanContextContainerProxy BeanContextEvent BeanContextMembershipEvent BeanContextMembershipListener + BeanContextProxy BeanContextServiceAvailableEvent BeanContextServiceProvider + BeanContextServiceProviderBeanInfo BeanContextServiceRevokedEvent BeanContextServiceRevokedListener + BeanContextServices BeanContextServicesListener BeanContextServicesSupport BeanContextSupport + BeanDescriptor BeanInfo Beans BevelBorder Bidi BigDecimal BigInteger BinaryRefAddr BindException Binding + BitSet Blob BlockingQueue BlockView BMPImageWriteParam Book Boolean BooleanControl Border BorderFactory + BorderLayout BorderUIResource BoundedRangeModel Box BoxLayout BoxView BreakIterator + BrokenBarrierException Buffer BufferCapabilities BufferedImage BufferedImageFilter BufferedImageOp + BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter BufferOverflowException + BufferStrategy BufferUnderflowException Button ButtonGroup ButtonModel ButtonUI Byte + ByteArrayInputStream ByteArrayOutputStream ByteBuffer ByteChannel ByteLookupTable ByteOrder CachedRowSet + CacheRequest CacheResponse Calendar Callable CallableStatement Callback CallbackHandler + CancelablePrintJob CancellationException CancelledKeyException CannotProceedException + CannotRedoException CannotUndoException Canvas CardLayout Caret CaretEvent CaretListener CellEditor + CellEditorListener CellRendererPane Certificate CertificateEncodingException CertificateException + CertificateExpiredException CertificateFactory CertificateFactorySpi CertificateNotYetValidException + CertificateParsingException CertPath CertPathBuilder CertPathBuilderException CertPathBuilderResult + CertPathBuilderSpi CertPathParameters CertPathTrustManagerParameters CertPathValidator + CertPathValidatorException CertPathValidatorResult CertPathValidatorSpi CertSelector CertStore + CertStoreException CertStoreParameters CertStoreSpi ChangedCharSetException ChangeEvent ChangeListener + Channel Channels Character CharacterCodingException CharacterIterator CharArrayReader CharArrayWriter + CharBuffer CharConversionException CharSequence Charset CharsetDecoder CharsetEncoder CharsetProvider + Checkbox CheckboxGroup CheckboxMenuItem CheckedInputStream CheckedOutputStream Checksum Choice + ChoiceCallback ChoiceFormat Chromaticity Cipher CipherInputStream CipherOutputStream CipherSpi Class + ClassCastException ClassCircularityError ClassDefinition ClassDesc ClassFileTransformer ClassFormatError + ClassLoader ClassLoaderRepository ClassLoadingMXBean ClassNotFoundException Clip Clipboard + ClipboardOwner Clob Cloneable CloneNotSupportedException Closeable ClosedByInterruptException + ClosedChannelException ClosedSelectorException CMMException CoderMalfunctionError CoderResult CodeSigner + CodeSource CodingErrorAction CollationElementIterator CollationKey Collator Collection + CollectionCertStoreParameters Collections Color ColorChooserComponentFactory ColorChooserUI + ColorConvertOp ColorModel ColorSelectionModel ColorSpace ColorSupported ColorType ColorUIResource + ComboBoxEditor ComboBoxModel ComboBoxUI ComboPopup CommunicationException Comparable Comparator + CompilationMXBean Compiler CompletionService Component ComponentAdapter ComponentColorModel + ComponentEvent ComponentInputMap ComponentInputMapUIResource ComponentListener ComponentOrientation + ComponentSampleModel ComponentUI ComponentView Composite CompositeContext CompositeData + CompositeDataSupport CompositeName CompositeType CompositeView CompoundBorder CompoundControl + CompoundEdit CompoundName Compression ConcurrentHashMap ConcurrentLinkedQueue ConcurrentMap + ConcurrentModificationException Condition Configuration ConfigurationException ConfirmationCallback + ConnectException ConnectIOException Connection ConnectionEvent ConnectionEventListener + ConnectionPendingException ConnectionPoolDataSource ConsoleHandler Constructor Container + ContainerAdapter ContainerEvent ContainerListener ContainerOrderFocusTraversalPolicy ContentHandler + ContentHandlerFactory ContentModel Context ContextNotEmptyException ContextualRenderedImageFactory + Control ControlFactory ControllerEventListener ConvolveOp CookieHandler Copies CopiesSupported + CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CounterMonitor CounterMonitorMBean CRC32 + CredentialException CredentialExpiredException CredentialNotFoundException CRL CRLException CRLSelector + CropImageFilter CSS CubicCurve2D Currency Cursor Customizer CyclicBarrier DatabaseMetaData DataBuffer + DataBufferByte DataBufferDouble DataBufferFloat DataBufferInt DataBufferShort DataBufferUShort + DataFlavor DataFormatException DatagramChannel DatagramPacket DatagramSocket DatagramSocketImpl + DatagramSocketImplFactory DataInput DataInputStream DataLine DataOutput DataOutputStream DataSource + DataTruncation DatatypeConfigurationException DatatypeConstants DatatypeFactory Date DateFormat + DateFormatSymbols DateFormatter DateTimeAtCompleted DateTimeAtCreation DateTimeAtProcessing + DateTimeSyntax DebugGraphics DecimalFormat DecimalFormatSymbols DefaultBoundedRangeModel + DefaultButtonModel DefaultCaret DefaultCellEditor DefaultColorSelectionModel DefaultComboBoxModel + DefaultDesktopManager DefaultEditorKit DefaultFocusManager DefaultFocusTraversalPolicy DefaultFormatter + DefaultFormatterFactory DefaultHighlighter DefaultKeyboardFocusManager DefaultListCellRenderer + DefaultListModel DefaultListSelectionModel DefaultLoaderRepository DefaultMenuLayout DefaultMetalTheme + DefaultMutableTreeNode DefaultPersistenceDelegate DefaultSingleSelectionModel DefaultStyledDocument + DefaultTableCellRenderer DefaultTableColumnModel DefaultTableModel DefaultTextUI DefaultTreeCellEditor + DefaultTreeCellRenderer DefaultTreeModel DefaultTreeSelectionModel Deflater DeflaterOutputStream Delayed + DelayQueue DelegationPermission Deprecated Descriptor DescriptorAccess DescriptorSupport DESedeKeySpec + DesignMode DESKeySpec DesktopIconUI DesktopManager DesktopPaneUI Destination Destroyable + DestroyFailedException DGC DHGenParameterSpec DHKey DHParameterSpec DHPrivateKey DHPrivateKeySpec + DHPublicKey DHPublicKeySpec Dialog Dictionary DigestException DigestInputStream DigestOutputStream + Dimension Dimension2D DimensionUIResource DirContext DirectColorModel DirectoryManager DirObjectFactory + DirStateFactory DisplayMode DnDConstants Doc DocAttribute DocAttributeSet DocFlavor DocPrintJob Document + DocumentBuilder DocumentBuilderFactory Documented DocumentEvent DocumentFilter DocumentListener + DocumentName DocumentParser DomainCombiner DOMLocator DOMResult DOMSource Double DoubleBuffer + DragGestureEvent DragGestureListener DragGestureRecognizer DragSource DragSourceAdapter + DragSourceContext DragSourceDragEvent DragSourceDropEvent DragSourceEvent DragSourceListener + DragSourceMotionListener Driver DriverManager DriverPropertyInfo DropTarget DropTargetAdapter + DropTargetContext DropTargetDragEvent DropTargetDropEvent DropTargetEvent DropTargetListener DSAKey + DSAKeyPairGenerator DSAParameterSpec DSAParams DSAPrivateKey DSAPrivateKeySpec DSAPublicKey + DSAPublicKeySpec DTD DTDConstants DuplicateFormatFlagsException Duration DynamicMBean ECField ECFieldF2m + ECFieldFp ECGenParameterSpec ECKey ECParameterSpec ECPoint ECPrivateKey ECPrivateKeySpec ECPublicKey + ECPublicKeySpec EditorKit Element ElementIterator ElementType Ellipse2D EllipticCurve EmptyBorder + EmptyStackException EncodedKeySpec Encoder EncryptedPrivateKeyInfo Entity Enum + EnumConstantNotPresentException EnumControl Enumeration EnumMap EnumSet EnumSyntax EOFException Error + ErrorListener ErrorManager EtchedBorder Event EventContext EventDirContext EventHandler EventListener + EventListenerList EventListenerProxy EventObject EventQueue EventSetDescriptor Exception + ExceptionInInitializerError ExceptionListener Exchanger ExecutionException Executor + ExecutorCompletionService Executors ExecutorService ExemptionMechanism ExemptionMechanismException + ExemptionMechanismSpi ExpandVetoException ExportException Expression ExtendedRequest ExtendedResponse + Externalizable FactoryConfigurationError FailedLoginException FeatureDescriptor Fidelity Field + FieldPosition FieldView File FileCacheImageInputStream FileCacheImageOutputStream FileChannel + FileChooserUI FileDescriptor FileDialog FileFilter FileHandler FileImageInputStream + FileImageOutputStream FileInputStream FileLock FileLockInterruptionException FilenameFilter FileNameMap + FileNotFoundException FileOutputStream FilePermission FileReader FileSystemView FileView FileWriter + Filter FilteredImageSource FilteredRowSet FilterInputStream FilterOutputStream FilterReader FilterWriter + Finishings FixedHeightLayoutCache FlatteningPathIterator FlavorEvent FlavorException FlavorListener + FlavorMap FlavorTable Float FloatBuffer FloatControl FlowLayout FlowView Flushable FocusAdapter + FocusEvent FocusListener FocusManager FocusTraversalPolicy Font FontFormatException FontMetrics + FontRenderContext FontUIResource Format FormatConversionProvider FormatFlagsConversionMismatchException + Formattable FormattableFlags Formatter FormatterClosedException FormSubmitEvent FormView Frame Future + FutureTask GapContent GarbageCollectorMXBean GatheringByteChannel GaugeMonitor GaugeMonitorMBean + GeneralPath GeneralSecurityException GenericArrayType GenericDeclaration GenericSignatureFormatError + GlyphJustificationInfo GlyphMetrics GlyphVector GlyphView GradientPaint GraphicAttribute Graphics + Graphics2D GraphicsConfigTemplate GraphicsConfiguration GraphicsDevice GraphicsEnvironment GrayFilter + GregorianCalendar GridBagConstraints GridBagLayout GridLayout Group Guard GuardedObject GZIPInputStream + GZIPOutputStream Handler HandshakeCompletedEvent HandshakeCompletedListener HasControls HashAttributeSet + HashDocAttributeSet HashMap HashPrintJobAttributeSet HashPrintRequestAttributeSet + HashPrintServiceAttributeSet HashSet Hashtable HeadlessException HierarchyBoundsAdapter + HierarchyBoundsListener HierarchyEvent HierarchyListener Highlighter HostnameVerifier HTML HTMLDocument + HTMLEditorKit HTMLFrameHyperlinkEvent HTMLWriter HttpRetryException HttpsURLConnection HttpURLConnection + HyperlinkEvent HyperlinkListener ICC_ColorSpace ICC_Profile ICC_ProfileGray ICC_ProfileRGB Icon + IconUIResource IconView Identity IdentityHashMap IdentityScope IIOByteBuffer IIOException IIOImage + IIOInvalidTreeException IIOMetadata IIOMetadataController IIOMetadataFormat IIOMetadataFormatImpl + IIOMetadataNode IIOParam IIOParamController IIOReadProgressListener IIOReadUpdateListener + IIOReadWarningListener IIORegistry IIOServiceProvider IIOWriteProgressListener IIOWriteWarningListener + IllegalAccessError IllegalAccessException IllegalArgumentException IllegalBlockingModeException + IllegalBlockSizeException IllegalCharsetNameException IllegalClassFormatException + IllegalComponentStateException IllegalFormatCodePointException IllegalFormatConversionException + IllegalFormatException IllegalFormatFlagsException IllegalFormatPrecisionException + IllegalFormatWidthException IllegalMonitorStateException IllegalPathStateException + IllegalSelectorException IllegalStateException IllegalThreadStateException Image ImageCapabilities + ImageConsumer ImageFilter ImageGraphicAttribute ImageIcon ImageInputStream ImageInputStreamImpl + ImageInputStreamSpi ImageIO ImageObserver ImageOutputStream ImageOutputStreamImpl ImageOutputStreamSpi + ImageProducer ImageReader ImageReaderSpi ImageReaderWriterSpi ImageReadParam ImageTranscoder + ImageTranscoderSpi ImageTypeSpecifier ImageView ImageWriteParam ImageWriter ImageWriterSpi + ImagingOpException IncompatibleClassChangeError IncompleteAnnotationException IndexColorModel + IndexedPropertyChangeEvent IndexedPropertyDescriptor IndexOutOfBoundsException Inet4Address Inet6Address + InetAddress InetSocketAddress Inflater InflaterInputStream InheritableThreadLocal Inherited + InitialContext InitialContextFactory InitialContextFactoryBuilder InitialDirContext InitialLdapContext + InlineView InputContext InputEvent InputMap InputMapUIResource InputMethod InputMethodContext + InputMethodDescriptor InputMethodEvent InputMethodHighlight InputMethodListener InputMethodRequests + InputMismatchException InputStream InputStreamReader InputSubset InputVerifier Insets InsetsUIResource + InstanceAlreadyExistsException InstanceNotFoundException InstantiationError InstantiationException + Instrument Instrumentation InsufficientResourcesException IntBuffer Integer IntegerSyntax InternalError + InternalFrameAdapter InternalFrameEvent InternalFrameFocusTraversalPolicy InternalFrameListener + InternalFrameUI InternationalFormatter InterruptedException InterruptedIOException + InterruptedNamingException InterruptibleChannel IntrospectionException Introspector + InvalidActivityException InvalidAlgorithmParameterException InvalidApplicationException + InvalidAttributeIdentifierException InvalidAttributesException InvalidAttributeValueException + InvalidClassException InvalidDnDOperationException InvalidKeyException InvalidKeySpecException + InvalidMarkException InvalidMidiDataException InvalidNameException InvalidObjectException + InvalidOpenTypeException InvalidParameterException InvalidParameterSpecException + InvalidPreferencesFormatException InvalidPropertiesFormatException InvalidRelationIdException + InvalidRelationServiceException InvalidRelationTypeException InvalidRoleInfoException + InvalidRoleValueException InvalidSearchControlsException InvalidSearchFilterException + InvalidTargetObjectTypeException InvalidTransactionException InvocationEvent InvocationHandler + InvocationTargetException IOException ItemEvent ItemListener ItemSelectable Iterable Iterator + IvParameterSpec JApplet JarEntry JarException JarFile JarInputStream JarOutputStream JarURLConnection + JButton JCheckBox JCheckBoxMenuItem JColorChooser JComboBox JComponent JdbcRowSet JDesktopPane JDialog + JEditorPane JFileChooser JFormattedTextField JFrame JInternalFrame JLabel JLayeredPane JList JMenu + JMenuBar JMenuItem JMException JMRuntimeException JMXAuthenticator JMXConnectionNotification + JMXConnector JMXConnectorFactory JMXConnectorProvider JMXConnectorServer JMXConnectorServerFactory + JMXConnectorServerMBean JMXConnectorServerProvider JMXPrincipal JMXProviderException + JMXServerErrorException JMXServiceURL JobAttributes JobHoldUntil JobImpressions JobImpressionsCompleted + JobImpressionsSupported JobKOctets JobKOctetsProcessed JobKOctetsSupported JobMediaSheets + JobMediaSheetsCompleted JobMediaSheetsSupported JobMessageFromOperator JobName JobOriginatingUserName + JobPriority JobPrioritySupported JobSheets JobState JobStateReason JobStateReasons Joinable JoinRowSet + JOptionPane JPanel JPasswordField JPEGHuffmanTable JPEGImageReadParam JPEGImageWriteParam JPEGQTable + JPopupMenu JProgressBar JRadioButton JRadioButtonMenuItem JRootPane JScrollBar JScrollPane JSeparator + JSlider JSpinner JSplitPane JTabbedPane JTable JTableHeader JTextArea JTextComponent JTextField + JTextPane JToggleButton JToolBar JToolTip JTree JViewport JWindow KerberosKey KerberosPrincipal + KerberosTicket Kernel Key KeyAdapter KeyAgreement KeyAgreementSpi KeyAlreadyExistsException + KeyboardFocusManager KeyEvent KeyEventDispatcher KeyEventPostProcessor KeyException KeyFactory + KeyFactorySpi KeyGenerator KeyGeneratorSpi KeyListener KeyManagementException KeyManager + KeyManagerFactory KeyManagerFactorySpi Keymap KeyPair KeyPairGenerator KeyPairGeneratorSpi KeyRep + KeySpec KeyStore KeyStoreBuilderParameters KeyStoreException KeyStoreSpi KeyStroke Label LabelUI + LabelView LanguageCallback LastOwnerException LayeredHighlighter LayoutFocusTraversalPolicy + LayoutManager LayoutManager2 LayoutQueue LDAPCertStoreParameters LdapContext LdapName + LdapReferralException Lease Level LimitExceededException Line Line2D LineBorder LineBreakMeasurer + LineEvent LineListener LineMetrics LineNumberInputStream LineNumberReader LineUnavailableException + LinkageError LinkedBlockingQueue LinkedHashMap LinkedHashSet LinkedList LinkException LinkLoopException + LinkRef List ListCellRenderer ListDataEvent ListDataListener ListenerNotFoundException ListIterator + ListModel ListResourceBundle ListSelectionEvent ListSelectionListener ListSelectionModel ListUI ListView + LoaderHandler Locale LocateRegistry Lock LockSupport Logger LoggingMXBean LoggingPermission LoginContext + LoginException LoginModule LogManager LogRecord LogStream Long LongBuffer LookAndFeel LookupOp + LookupTable Mac MacSpi MalformedInputException MalformedLinkException MalformedObjectNameException + MalformedParameterizedTypeException MalformedURLException ManagementFactory ManagementPermission + ManageReferralControl ManagerFactoryParameters Manifest Map MappedByteBuffer MarshalException + MarshalledObject MaskFormatter Matcher MatchResult Math MathContext MatteBorder MBeanAttributeInfo + MBeanConstructorInfo MBeanException MBeanFeatureInfo MBeanInfo MBeanNotificationInfo MBeanOperationInfo + MBeanParameterInfo MBeanPermission MBeanRegistration MBeanRegistrationException MBeanServer + MBeanServerBuilder MBeanServerConnection MBeanServerDelegate MBeanServerDelegateMBean MBeanServerFactory + MBeanServerForwarder MBeanServerInvocationHandler MBeanServerNotification MBeanServerNotificationFilter + MBeanServerPermission MBeanTrustPermission Media MediaName MediaPrintableArea MediaSize MediaSizeName + MediaTracker MediaTray Member MemoryCacheImageInputStream MemoryCacheImageOutputStream MemoryHandler + MemoryImageSource MemoryManagerMXBean MemoryMXBean MemoryNotificationInfo MemoryPoolMXBean MemoryType + MemoryUsage Menu MenuBar MenuBarUI MenuComponent MenuContainer MenuDragMouseEvent MenuDragMouseListener + MenuElement MenuEvent MenuItem MenuItemUI MenuKeyEvent MenuKeyListener MenuListener MenuSelectionManager + MenuShortcut MessageDigest MessageDigestSpi MessageFormat MetaEventListener MetalBorders MetalButtonUI + MetalCheckBoxIcon MetalCheckBoxUI MetalComboBoxButton MetalComboBoxEditor MetalComboBoxIcon + MetalComboBoxUI MetalDesktopIconUI MetalFileChooserUI MetalIconFactory MetalInternalFrameTitlePane + MetalInternalFrameUI MetalLabelUI MetalLookAndFeel MetalMenuBarUI MetalPopupMenuSeparatorUI + MetalProgressBarUI MetalRadioButtonUI MetalRootPaneUI MetalScrollBarUI MetalScrollButton + MetalScrollPaneUI MetalSeparatorUI MetalSliderUI MetalSplitPaneUI MetalTabbedPaneUI MetalTextFieldUI + MetalTheme MetalToggleButtonUI MetalToolBarUI MetalToolTipUI MetalTreeUI MetaMessage Method + MethodDescriptor MGF1ParameterSpec MidiChannel MidiDevice MidiDeviceProvider MidiEvent MidiFileFormat + MidiFileReader MidiFileWriter MidiMessage MidiSystem MidiUnavailableException MimeTypeParseException + MinimalHTMLWriter MissingFormatArgumentException MissingFormatWidthException MissingResourceException + Mixer MixerProvider MLet MLetMBean ModelMBean ModelMBeanAttributeInfo ModelMBeanConstructorInfo + ModelMBeanInfo ModelMBeanInfoSupport ModelMBeanNotificationBroadcaster ModelMBeanNotificationInfo + ModelMBeanOperationInfo ModificationItem Modifier Monitor MonitorMBean MonitorNotification + MonitorSettingException MouseAdapter MouseDragGestureRecognizer MouseEvent MouseInfo MouseInputAdapter + MouseInputListener MouseListener MouseMotionAdapter MouseMotionListener MouseWheelEvent + MouseWheelListener MultiButtonUI MulticastSocket MultiColorChooserUI MultiComboBoxUI MultiDesktopIconUI + MultiDesktopPaneUI MultiDoc MultiDocPrintJob MultiDocPrintService MultiFileChooserUI + MultiInternalFrameUI MultiLabelUI MultiListUI MultiLookAndFeel MultiMenuBarUI MultiMenuItemUI + MultiOptionPaneUI MultiPanelUI MultiPixelPackedSampleModel MultipleDocumentHandling MultipleMaster + MultiPopupMenuUI MultiProgressBarUI MultiRootPaneUI MultiScrollBarUI MultiScrollPaneUI MultiSeparatorUI + MultiSliderUI MultiSpinnerUI MultiSplitPaneUI MultiTabbedPaneUI MultiTableHeaderUI MultiTableUI + MultiTextUI MultiToolBarUI MultiToolTipUI MultiTreeUI MultiViewportUI MutableAttributeSet + MutableComboBoxModel MutableTreeNode Name NameAlreadyBoundException NameCallback NameClassPair + NameNotFoundException NameParser NamespaceChangeListener NamespaceContext Naming NamingEnumeration + NamingEvent NamingException NamingExceptionEvent NamingListener NamingManager NamingSecurityException + NavigationFilter NegativeArraySizeException NetPermission NetworkInterface NoClassDefFoundError + NoConnectionPendingException NodeChangeEvent NodeChangeListener NoInitialContextException + NoninvertibleTransformException NonReadableChannelException NonWritableChannelException + NoPermissionException NoRouteToHostException NoSuchAlgorithmException NoSuchAttributeException + NoSuchElementException NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException + NoSuchObjectException NoSuchPaddingException NoSuchProviderException NotActiveException + NotBoundException NotCompliantMBeanException NotContextException Notification NotificationBroadcaster + NotificationBroadcasterSupport NotificationEmitter NotificationFilter NotificationFilterSupport + NotificationListener NotificationResult NotOwnerException NotSerializableException NotYetBoundException + NotYetConnectedException NullCipher NullPointerException Number NumberFormat NumberFormatException + NumberFormatter NumberOfDocuments NumberOfInterveningJobs NumberUp NumberUpSupported NumericShaper + OAEPParameterSpec Object ObjectChangeListener ObjectFactory ObjectFactoryBuilder ObjectInput + ObjectInputStream ObjectInputValidation ObjectInstance ObjectName ObjectOutput ObjectOutputStream + ObjectStreamClass ObjectStreamConstants ObjectStreamException ObjectStreamField ObjectView ObjID + Observable Observer OceanTheme OpenDataException OpenMBeanAttributeInfo OpenMBeanAttributeInfoSupport + OpenMBeanConstructorInfo OpenMBeanConstructorInfoSupport OpenMBeanInfo OpenMBeanInfoSupport + OpenMBeanOperationInfo OpenMBeanOperationInfoSupport OpenMBeanParameterInfo + OpenMBeanParameterInfoSupport OpenType OperatingSystemMXBean Operation OperationNotSupportedException + OperationsException Option OptionalDataException OptionPaneUI OrientationRequested OutOfMemoryError + OutputDeviceAssigned OutputKeys OutputStream OutputStreamWriter OverlappingFileLockException + OverlayLayout Override Owner Pack200 Package PackedColorModel Pageable PageAttributes + PagedResultsControl PagedResultsResponseControl PageFormat PageRanges PagesPerMinute PagesPerMinuteColor + Paint PaintContext PaintEvent Panel PanelUI Paper ParagraphView ParameterBlock ParameterDescriptor + ParameterizedType ParameterMetaData ParseException ParsePosition Parser ParserConfigurationException + ParserDelegator PartialResultException PasswordAuthentication PasswordCallback PasswordView Patch + PathIterator Pattern PatternSyntaxException PBEKey PBEKeySpec PBEParameterSpec PDLOverrideSupported + Permission PermissionCollection Permissions PersistenceDelegate PersistentMBean PhantomReference Pipe + PipedInputStream PipedOutputStream PipedReader PipedWriter PixelGrabber PixelInterleavedSampleModel + PKCS8EncodedKeySpec PKIXBuilderParameters PKIXCertPathBuilderResult PKIXCertPathChecker + PKIXCertPathValidatorResult PKIXParameters PlainDocument PlainView Point Point2D PointerInfo Policy + PolicyNode PolicyQualifierInfo Polygon PooledConnection Popup PopupFactory PopupMenu PopupMenuEvent + PopupMenuListener PopupMenuUI Port PortableRemoteObject PortableRemoteObjectDelegate + PortUnreachableException Position Predicate PreferenceChangeEvent PreferenceChangeListener Preferences + PreferencesFactory PreparedStatement PresentationDirection Principal Printable PrinterAbortException + PrinterException PrinterGraphics PrinterInfo PrinterIOException PrinterIsAcceptingJobs PrinterJob + PrinterLocation PrinterMakeAndModel PrinterMessageFromOperator PrinterMoreInfo + PrinterMoreInfoManufacturer PrinterName PrinterResolution PrinterState PrinterStateReason + PrinterStateReasons PrinterURI PrintEvent PrintException PrintGraphics PrintJob PrintJobAdapter + PrintJobAttribute PrintJobAttributeEvent PrintJobAttributeListener PrintJobAttributeSet PrintJobEvent + PrintJobListener PrintQuality PrintRequestAttribute PrintRequestAttributeSet PrintService + PrintServiceAttribute PrintServiceAttributeEvent PrintServiceAttributeListener PrintServiceAttributeSet + PrintServiceLookup PrintStream PrintWriter PriorityBlockingQueue PriorityQueue PrivateClassLoader + PrivateCredentialPermission PrivateKey PrivateMLet PrivilegedAction PrivilegedActionException + PrivilegedExceptionAction Process ProcessBuilder ProfileDataException ProgressBarUI ProgressMonitor + ProgressMonitorInputStream Properties PropertyChangeEvent PropertyChangeListener + PropertyChangeListenerProxy PropertyChangeSupport PropertyDescriptor PropertyEditor + PropertyEditorManager PropertyEditorSupport PropertyPermission PropertyResourceBundle + PropertyVetoException ProtectionDomain ProtocolException Provider ProviderException Proxy ProxySelector + PSource PSSParameterSpec PublicKey PushbackInputStream PushbackReader QName QuadCurve2D Query QueryEval + QueryExp Queue QueuedJobCount Random RandomAccess RandomAccessFile Raster RasterFormatException RasterOp + RC2ParameterSpec RC5ParameterSpec Rdn Readable ReadableByteChannel Reader ReadOnlyBufferException + ReadWriteLock RealmCallback RealmChoiceCallback Receiver Rectangle Rectangle2D RectangularShape + ReentrantLock ReentrantReadWriteLock Ref RefAddr Reference Referenceable ReferenceQueue + ReferenceUriSchemesSupported ReferralException ReflectionException ReflectPermission Refreshable + RefreshFailedException Region RegisterableService Registry RegistryHandler RejectedExecutionException + RejectedExecutionHandler Relation RelationException RelationNotFoundException RelationNotification + RelationService RelationServiceMBean RelationServiceNotRegisteredException RelationSupport + RelationSupportMBean RelationType RelationTypeNotFoundException RelationTypeSupport Remote RemoteCall + RemoteException RemoteObject RemoteObjectInvocationHandler RemoteRef RemoteServer RemoteStub + RenderableImage RenderableImageOp RenderableImageProducer RenderContext RenderedImage + RenderedImageFactory Renderer RenderingHints RepaintManager ReplicateScaleFilter RequestingUserName + RequiredModelMBean RescaleOp ResolutionSyntax Resolver ResolveResult ResourceBundle ResponseCache Result + ResultSet ResultSetMetaData Retention RetentionPolicy ReverbType RGBImageFilter RMIClassLoader + RMIClassLoaderSpi RMIClientSocketFactory RMIConnection RMIConnectionImpl RMIConnectionImpl_Stub + RMIConnector RMIConnectorServer RMIFailureHandler RMIIIOPServerImpl RMIJRMPServerImpl + RMISecurityException RMISecurityManager RMIServer RMIServerImpl RMIServerImpl_Stub + RMIServerSocketFactory RMISocketFactory Robot Role RoleInfo RoleInfoNotFoundException RoleList + RoleNotFoundException RoleResult RoleStatus RoleUnresolved RoleUnresolvedList RootPaneContainer + RootPaneUI RoundingMode RoundRectangle2D RowMapper RowSet RowSetEvent RowSetInternal RowSetListener + RowSetMetaData RowSetMetaDataImpl RowSetReader RowSetWarning RowSetWriter RSAKey RSAKeyGenParameterSpec + RSAMultiPrimePrivateCrtKey RSAMultiPrimePrivateCrtKeySpec RSAOtherPrimeInfo RSAPrivateCrtKey + RSAPrivateCrtKeySpec RSAPrivateKey RSAPrivateKeySpec RSAPublicKey RSAPublicKeySpec RTFEditorKit + RuleBasedCollator Runnable Runtime RuntimeErrorException RuntimeException RuntimeMBeanException + RuntimeMXBean RuntimeOperationsException RuntimePermission SampleModel Sasl SaslClient SaslClientFactory + SaslException SaslServer SaslServerFactory Savepoint SAXParser SAXParserFactory SAXResult SAXSource + SAXTransformerFactory Scanner ScatteringByteChannel ScheduledExecutorService ScheduledFuture + ScheduledThreadPoolExecutor Schema SchemaFactory SchemaFactoryLoader SchemaViolationException Scrollable + Scrollbar ScrollBarUI ScrollPane ScrollPaneAdjustable ScrollPaneConstants ScrollPaneLayout ScrollPaneUI + SealedObject SearchControls SearchResult SecretKey SecretKeyFactory SecretKeyFactorySpi SecretKeySpec + SecureCacheResponse SecureClassLoader SecureRandom SecureRandomSpi Security SecurityException + SecurityManager SecurityPermission Segment SelectableChannel SelectionKey Selector SelectorProvider + Semaphore SeparatorUI Sequence SequenceInputStream Sequencer SerialArray SerialBlob SerialClob + SerialDatalink SerialException Serializable SerializablePermission SerialJavaObject SerialRef + SerialStruct ServerCloneException ServerError ServerException ServerNotActiveException ServerRef + ServerRuntimeException ServerSocket ServerSocketChannel ServerSocketFactory ServiceNotFoundException + ServicePermission ServiceRegistry ServiceUI ServiceUIFactory ServiceUnavailableException Set + SetOfIntegerSyntax Severity Shape ShapeGraphicAttribute SheetCollate Short ShortBuffer + ShortBufferException ShortLookupTable ShortMessage Sides Signature SignatureException SignatureSpi + SignedObject Signer SimpleAttributeSet SimpleBeanInfo SimpleDateFormat SimpleDoc SimpleFormatter + SimpleTimeZone SimpleType SinglePixelPackedSampleModel SingleSelectionModel Size2DSyntax + SizeLimitExceededException SizeRequirements SizeSequence Skeleton SkeletonMismatchException + SkeletonNotFoundException SliderUI Socket SocketAddress SocketChannel SocketException SocketFactory + SocketHandler SocketImpl SocketImplFactory SocketOptions SocketPermission SocketSecurityException + SocketTimeoutException SoftBevelBorder SoftReference SortControl SortedMap SortedSet + SortingFocusTraversalPolicy SortKey SortResponseControl Soundbank SoundbankReader SoundbankResource + Source SourceDataLine SourceLocator SpinnerDateModel SpinnerListModel SpinnerModel SpinnerNumberModel + SpinnerUI SplitPaneUI Spring SpringLayout SQLData SQLException SQLInput SQLInputImpl SQLOutput + SQLOutputImpl SQLPermission SQLWarning SSLContext SSLContextSpi SSLEngine SSLEngineResult SSLException + SSLHandshakeException SSLKeyException SSLPeerUnverifiedException SSLPermission SSLProtocolException + SslRMIClientSocketFactory SslRMIServerSocketFactory SSLServerSocket SSLServerSocketFactory SSLSession + SSLSessionBindingEvent SSLSessionBindingListener SSLSessionContext SSLSocket SSLSocketFactory Stack + StackOverflowError StackTraceElement StandardMBean StartTlsRequest StartTlsResponse StateEdit + StateEditable StateFactory Statement StreamCorruptedException StreamHandler StreamPrintService + StreamPrintServiceFactory StreamResult StreamSource StreamTokenizer StrictMath String StringBuffer + StringBufferInputStream StringBuilder StringCharacterIterator StringContent + StringIndexOutOfBoundsException StringMonitor StringMonitorMBean StringReader StringRefAddr + StringSelection StringTokenizer StringValueExp StringWriter Stroke Struct Stub StubDelegate + StubNotFoundException Style StyleConstants StyleContext StyledDocument StyledEditorKit StyleSheet + Subject SubjectDelegationPermission SubjectDomainCombiner SupportedValuesAttribute SuppressWarnings + SwingConstants SwingPropertyChangeSupport SwingUtilities SyncFactory SyncFactoryException + SyncFailedException SynchronousQueue SyncProvider SyncProviderException SyncResolver SynthConstants + SynthContext Synthesizer SynthGraphicsUtils SynthLookAndFeel SynthPainter SynthStyle SynthStyleFactory + SysexMessage System SystemColor SystemFlavorMap TabableView TabbedPaneUI TabExpander TableCellEditor + TableCellRenderer TableColumn TableColumnModel TableColumnModelEvent TableColumnModelListener + TableHeaderUI TableModel TableModelEvent TableModelListener TableUI TableView TabSet TabStop TabularData + TabularDataSupport TabularType TagElement Target TargetDataLine TargetedNotification Templates + TemplatesHandler TextAction TextArea TextAttribute TextComponent TextEvent TextField TextHitInfo + TextInputCallback TextLayout TextListener TextMeasurer TextOutputCallback TextSyntax TextUI TexturePaint + Thread ThreadDeath ThreadFactory ThreadGroup ThreadInfo ThreadLocal ThreadMXBean ThreadPoolExecutor + Throwable Tie TileObserver Time TimeLimitExceededException TimeoutException Timer + TimerAlarmClockNotification TimerMBean TimerNotification TimerTask Timestamp TimeUnit TimeZone + TitledBorder ToolBarUI Toolkit ToolTipManager ToolTipUI TooManyListenersException Track + TransactionalWriter TransactionRequiredException TransactionRolledbackException Transferable + TransferHandler TransformAttribute Transformer TransformerConfigurationException TransformerException + TransformerFactory TransformerFactoryConfigurationError TransformerHandler Transmitter Transparency + TreeCellEditor TreeCellRenderer TreeExpansionEvent TreeExpansionListener TreeMap TreeModel + TreeModelEvent TreeModelListener TreeNode TreePath TreeSelectionEvent TreeSelectionListener + TreeSelectionModel TreeSet TreeUI TreeWillExpandListener TrustAnchor TrustManager TrustManagerFactory + TrustManagerFactorySpi Type TypeInfoProvider TypeNotPresentException Types TypeVariable UID UIDefaults + UIManager UIResource UndeclaredThrowableException UndoableEdit UndoableEditEvent UndoableEditListener + UndoableEditSupport UndoManager UnexpectedException UnicastRemoteObject UnknownError + UnknownFormatConversionException UnknownFormatFlagsException UnknownGroupException UnknownHostException + UnknownObjectException UnknownServiceException UnmappableCharacterException UnmarshalException + UnmodifiableClassException UnmodifiableSetException UnrecoverableEntryException + UnrecoverableKeyException Unreferenced UnresolvedAddressException UnresolvedPermission + UnsatisfiedLinkError UnsolicitedNotification UnsolicitedNotificationEvent + UnsolicitedNotificationListener UnsupportedAddressTypeException UnsupportedAudioFileException + UnsupportedCallbackException UnsupportedCharsetException UnsupportedClassVersionError + UnsupportedEncodingException UnsupportedFlavorException UnsupportedLookAndFeelException + UnsupportedOperationException URI URIException URIResolver URISyntax URISyntaxException URL + URLClassLoader URLConnection URLDecoder URLEncoder URLStreamHandler URLStreamHandlerFactory + UTFDataFormatException Util UtilDelegate Utilities UUID Validator ValidatorHandler ValueExp ValueHandler + ValueHandlerMultiFormat VariableHeightLayoutCache Vector VerifyError VetoableChangeListener + VetoableChangeListenerProxy VetoableChangeSupport View ViewFactory ViewportLayout ViewportUI + VirtualMachineError Visibility VMID VoiceStatus Void VolatileImage WeakHashMap WeakReference WebRowSet + WildcardType Window WindowAdapter WindowConstants WindowEvent WindowFocusListener WindowListener + WindowStateListener WrappedPlainView WritableByteChannel WritableRaster WritableRenderedImage + WriteAbortedException Writer X500Principal X500PrivateCredential X509Certificate X509CertSelector + X509CRL X509CRLEntry X509CRLSelector X509EncodedKeySpec X509ExtendedKeyManager X509Extension + X509KeyManager X509TrustManager XAConnection XADataSource XAException XAResource Xid XMLConstants + XMLDecoder XMLEncoder XMLFormatter XMLGregorianCalendar XMLParseException XmlReader XmlWriter XPath + XPathConstants XPathException XPathExpression XPathExpressionException XPathFactory + XPathFactoryConfigurationException XPathFunction XPathFunctionException XPathFunctionResolver + XPathVariableResolver ZipEntry ZipException ZipFile ZipInputStream ZipOutputStream ZoneView + ] + #:nocov: + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/java_script.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java_script.rb new file mode 100644 index 00000000..8c13d4ff --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/java_script.rb @@ -0,0 +1,236 @@ +module CodeRay +module Scanners + + # Scanner for JavaScript. + # + # Aliases: +ecmascript+, +ecma_script+, +javascript+ + class JavaScript < Scanner + + register_for :java_script + file_extension 'js' + + # The actual JavaScript keywords. + KEYWORDS = %w[ + break case catch continue default delete do else + finally for function if in instanceof new + return switch throw try typeof var void while with + ] # :nodoc: + PREDEFINED_CONSTANTS = %w[ + false null true undefined NaN Infinity + ] # :nodoc: + + MAGIC_VARIABLES = %w[ this arguments ] # :nodoc: arguments was introduced in JavaScript 1.4 + + KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ + case delete in instanceof new return throw typeof with + ] # :nodoc: + + # Reserved for future use. + RESERVED_WORDS = %w[ + abstract boolean byte char class debugger double enum export extends + final float goto implements import int interface long native package + private protected public short static super synchronized throws transient + volatile + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(RESERVED_WORDS, :reserved). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(MAGIC_VARIABLES, :local_variable). + add(KEYWORDS, :keyword) # :nodoc: + + ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + REGEXP_ESCAPE = / [bBdDsSwW] /x # :nodoc: + STRING_CONTENT_PATTERN = { + "'" => /[^\\']+/, + '"' => /[^\\"]+/, + '/' => /[^\\\/]+/, + } # :nodoc: + KEY_CHECK_PATTERN = { + "'" => / (?> [^\\']* (?: \\. [^\\']* )* ) ' \s* : /mx, + '"' => / (?> [^\\"]* (?: \\. [^\\"]* )* ) " \s* : /mx, + } # :nodoc: + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + + state, string_delimiter = options[:state] || @state + if string_delimiter + encoder.begin_group state + end + + value_expected = true + key_expected = false + function_expected = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + value_expected = true if !value_expected && match.index(?\n) + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .*() ) !mx) + value_expected = true + encoder.text_token match, :comment + state = :open_multi_line_comment if self[1] + + elsif check(/\.?\d/) + key_expected = value_expected = false + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + encoder.text_token match, :float + elsif match = scan(/\d+/) + encoder.text_token match, :integer + end + + elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) + # TODO: scan over nested tags + xml_scanner.tokenize match, :tokens => encoder + value_expected = false + + elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) + value_expected = true + last_operator = match[-1] + key_expected = (last_operator == ?{) || (last_operator == ?,) + function_expected = false + encoder.text_token match, :operator + + elsif match = scan(/ [)\]}]+ /x) + function_expected = key_expected = value_expected = false + encoder.text_token match, :operator + + elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) + kind = IDENT_KIND[match] + value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] + # TODO: labels + if kind == :ident + if match.index(?$) # $ allowed inside an identifier + kind = :predefined + elsif function_expected + kind = :function + elsif check(/\s*[=:]\s*function\b/) + kind = :function + elsif key_expected && check(/\s*:/) + kind = :key + end + end + function_expected = (kind == :keyword) && (match == 'function') + key_expected = false + encoder.text_token match, kind + + elsif match = scan(/["']/) + if key_expected && check(KEY_CHECK_PATTERN[match]) + state = :key + else + state = :string + end + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif value_expected && (match = scan(/\//)) + encoder.begin_group :regexp + state = :regexp + string_delimiter = '/' + encoder.text_token match, :delimiter + + elsif match = scan(/ \/ /x) + value_expected = true + key_expected = false + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + when :string, :regexp, :key + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + elsif match = scan(/["'\/]/) + encoder.text_token match, :delimiter + if state == :regexp + modifiers = scan(/[gim]+/) + encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty? + end + encoder.end_group state + string_delimiter = nil + key_expected = value_expected = false + state = :initial + elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif state == :regexp && match = scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + encoder.text_token match, :error unless match.empty? + string_delimiter = nil + key_expected = value_expected = false + state = :initial + else + raise_inspect "else case #{string_delimiter} reached; %p not handled." % peek(1), encoder + end + + when :open_multi_line_comment + if match = scan(%r! .*? \*/ !mx) + state = :initial + else + match = scan(%r! .+ !mx) + end + value_expected = true + encoder.text_token match, :comment if match + + else + #:nocov: + raise_inspect 'Unknown state: %p' % [state], encoder + #:nocov: + + end + + end + + if options[:keep_state] + @state = state, string_delimiter + end + + if [:string, :regexp].include? state + encoder.end_group state + end + + encoder + end + + protected + + def reset_instance + super + @xml_scanner.reset if defined? @xml_scanner + end + + def xml_scanner + @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/json.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/json.rb new file mode 100644 index 00000000..b09970c2 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/json.rb @@ -0,0 +1,98 @@ +module CodeRay +module Scanners + + # Scanner for JSON (JavaScript Object Notation). + class JSON < Scanner + + register_for :json + file_extension 'json' + + KINDS_NOT_LOC = [ + :float, :char, :content, :delimiter, + :error, :integer, :operator, :value, + ] # :nodoc: + + ESCAPE = / [bfnrt\\"\/] /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: + KEY = / (?> (?: [^\\"]+ | \\. )* ) " \s* : /x + + protected + + def setup + @state = :initial + end + + # See http://json.org/ for a definition of the JSON lexic/grammar. + def scan_tokens encoder, options + state = options[:state] || @state + + if [:string, :key].include? state + encoder.begin_group state + end + + until eos? + + case state + + when :initial + if match = scan(/ \s+ /x) + encoder.text_token match, :space + elsif match = scan(/"/) + state = check(/#{KEY}/o) ? :key : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/ [:,\[{\]}] /x) + encoder.text_token match, :operator + elsif match = scan(/ true | false | null /x) + encoder.text_token match, :value + elsif match = scan(/ -? (?: 0 | [1-9]\d* ) /x) + if scan(/ \.\d+ (?:[eE][-+]?\d+)? | [eE][-+]? \d+ /x) + match << matched + encoder.text_token match, :float + else + encoder.text_token match, :integer + end + else + encoder.text_token getch, :error + end + + when :string, :key + if match = scan(/[^\\"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + encoder.text_token match, :error unless match.empty? + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + end + + if options[:keep_state] + @state = state + end + + if [:string, :key].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/lua.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/lua.rb new file mode 100644 index 00000000..81d7dae4 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/lua.rb @@ -0,0 +1,280 @@ +# encoding: utf-8 + +module CodeRay +module Scanners + + # Scanner for the Lua[http://lua.org] programming lanuage. + # + # The language’s complete syntax is defined in + # {the Lua manual}[http://www.lua.org/manual/5.2/manual.html], + # which is what this scanner tries to conform to. + class Lua < Scanner + + register_for :lua + file_extension 'lua' + title 'Lua' + + # Keywords used in Lua. + KEYWORDS = %w[and break do else elseif end + for function goto if in + local not or repeat return + then until while + ] + + # Constants set by the Lua core. + PREDEFINED_CONSTANTS = %w[false true nil] + + # The expressions contained in this array are parts of Lua’s `basic' + # library. Although it’s not entirely necessary to load that library, + # it is highly recommended and one would have to provide own implementations + # of some of these expressions if one does not do so. They however aren’t + # keywords, neither are they constants, but nearly predefined, so they + # get tagged as `predefined' rather than anything else. + # + # This list excludes values of form `_UPPERCASE' because the Lua manual + # requires such identifiers to be reserved by Lua anyway and they are + # highlighted directly accordingly, without the need for specific + # identifiers to be listed here. + PREDEFINED_EXPRESSIONS = %w[ + assert collectgarbage dofile error getmetatable + ipairs load loadfile next pairs pcall print + rawequal rawget rawlen rawset select setmetatable + tonumber tostring type xpcall + ] + + # Automatic token kind selection for normal words. + IDENT_KIND = CodeRay::WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(PREDEFINED_EXPRESSIONS, :predefined) + + protected + + # Scanner initialization. + def setup + @state = :initial + @brace_depth = 0 + end + + # CodeRay entry hook. Starts parsing. + def scan_tokens(encoder, options) + state = options[:state] || @state + brace_depth = @brace_depth + num_equals = nil + + until eos? + case state + + when :initial + if match = scan(/\-\-\[\=*\[/) #--[[ long (possibly multiline) comment ]] + num_equals = match.count("=") # Number must match for comment end + encoder.begin_group(:comment) + encoder.text_token(match, :delimiter) + state = :long_comment + + elsif match = scan(/--.*$/) # --Lua comment + encoder.text_token(match, :comment) + + elsif match = scan(/\[=*\[/) # [[ long (possibly multiline) string ]] + num_equals = match.count("=") # Number must match for string end + encoder.begin_group(:string) + encoder.text_token(match, :delimiter) + state = :long_string + + elsif match = scan(/::\s*[a-zA-Z_][a-zA-Z0-9_]+\s*::/) # ::goto_label:: + encoder.text_token(match, :label) + + elsif match = scan(/_[A-Z]+/) # _UPPERCASE are names reserved for Lua + encoder.text_token(match, :predefined) + + elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) # Normal letters (or letters followed by digits) + kind = IDENT_KIND[match] + + # Extra highlighting for entities following certain keywords + if kind == :keyword and match == "function" + state = :function_expected + elsif kind == :keyword and match == "goto" + state = :goto_label_expected + elsif kind == :keyword and match == "local" + state = :local_var_expected + end + + encoder.text_token(match, kind) + + elsif match = scan(/\{/) # Opening table brace { + encoder.begin_group(:map) + encoder.text_token(match, brace_depth >= 1 ? :inline_delimiter : :delimiter) + brace_depth += 1 + state = :map + + elsif match = scan(/\}/) # Closing table brace } + if brace_depth == 1 + brace_depth = 0 + encoder.text_token(match, :delimiter) + encoder.end_group(:map) + elsif brace_depth == 0 # Mismatched brace + encoder.text_token(match, :error) + else + brace_depth -= 1 + encoder.text_token(match, :inline_delimiter) + encoder.end_group(:map) + state = :map + end + + elsif match = scan(/["']/) # String delimiters " and ' + encoder.begin_group(:string) + encoder.text_token(match, :delimiter) + start_delim = match + state = :string + + # ↓Prefix hex number ←|→ decimal number + elsif match = scan(/-? (?:0x\h* \. \h+ (?:p[+\-]?\d+)? | \d*\.\d+ (?:e[+\-]?\d+)?)/ix) # hexadecimal constants have no E power, decimal ones no P power + encoder.text_token(match, :float) + + # ↓Prefix hex number ←|→ decimal number + elsif match = scan(/-? (?:0x\h+ (?:p[+\-]?\d+)? | \d+ (?:e[+\-]?\d+)?)/ix) # hexadecimal constants have no E power, decimal ones no P power + encoder.text_token(match, :integer) + + elsif match = scan(/[\+\-\*\/%^\#=~<>\(\)\[\]:;,] | \.(?!\d)/x) # Operators + encoder.text_token(match, :operator) + + elsif match = scan(/\s+/) # Space + encoder.text_token(match, :space) + + else # Invalid stuff. Note that Lua doesn’t accept multibyte chars outside of strings, hence these are also errors. + encoder.text_token(getch, :error) + end + + # It may be that we’re scanning a full-blown subexpression of a table + # (tables can contain full expressions in parts). + # If this is the case, return to :map scanning state. + state = :map if state == :initial && brace_depth >= 1 + + when :function_expected + if match = scan(/\(.*?\)/m) # x = function() # "Anonymous" function without explicit name + encoder.text_token(match, :operator) + state = :initial + elsif match = scan(/[a-zA-Z_] (?:[a-zA-Z0-9_\.] (?!\.\d))* [\.\:]/x) # function tbl.subtbl.foo() | function tbl:foo() # Colon only allowed as last separator + encoder.text_token(match, :ident) + elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) # function foo() + encoder.text_token(match, :function) + state = :initial + elsif match = scan(/\s+/) # Between the `function' keyword and the ident may be any amount of whitespace + encoder.text_token(match, :space) + else + encoder.text_token(getch, :error) + state = :initial + end + + when :goto_label_expected + if match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) + encoder.text_token(match, :label) + state = :initial + elsif match = scan(/\s+/) # Between the `goto' keyword and the label may be any amount of whitespace + encoder.text_token(match, :space) + else + encoder.text_token(getch, :error) + end + + when :local_var_expected + if match = scan(/function/) # local function ... + encoder.text_token(match, :keyword) + state = :function_expected + elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]*/) + encoder.text_token(match, :local_variable) + elsif match = scan(/,/) + encoder.text_token(match, :operator) + elsif match = scan(/\=/) + encoder.text_token(match, :operator) + # After encountering the equal sign, arbitrary expressions are + # allowed again, so just return to the main state for further + # parsing. + state = :initial + elsif match = scan(/\n/) + encoder.text_token(match, :space) + state = :initial + elsif match = scan(/\s+/) + encoder.text_token(match, :space) + else + encoder.text_token(getch, :error) + end + + when :long_comment + if match = scan(/.*?(?=\]={#{num_equals}}\])/m) + encoder.text_token(match, :content) + + delim = scan(/\]={#{num_equals}}\]/) + encoder.text_token(delim, :delimiter) + else # No terminator found till EOF + encoder.text_token(rest, :error) + terminate + end + encoder.end_group(:comment) + state = :initial + + when :long_string + if match = scan(/.*?(?=\]={#{num_equals}}\])/m) # Long strings do not interpret any escape sequences + encoder.text_token(match, :content) + + delim = scan(/\]={#{num_equals}}\]/) + encoder.text_token(delim, :delimiter) + else # No terminator found till EOF + encoder.text_token(rest, :error) + terminate + end + encoder.end_group(:string) + state = :initial + + when :string + if match = scan(/[^\\#{start_delim}\n]+/) # Everything except \ and the start delimiter character is string content (newlines are only allowed if preceeded by \ or \z) + encoder.text_token(match, :content) + elsif match = scan(/\\(?:['"abfnrtv\\]|z\s*|x\h\h|\d{1,3}|\n)/m) + encoder.text_token(match, :char) + elsif match = scan(Regexp.compile(start_delim)) + encoder.text_token(match, :delimiter) + encoder.end_group(:string) + state = :initial + elsif match = scan(/\n/) # Lua forbids unescaped newlines in normal non-long strings + encoder.text_token("\\n\n", :error) # Visually appealing error indicator--otherwise users may wonder whether the highlighter cannot highlight multine strings + encoder.end_group(:string) + state = :initial + else + encoder.text_token(getch, :error) + end + + when :map + if match = scan(/[,;]/) + encoder.text_token(match, :operator) + elsif match = scan(/[a-zA-Z_][a-zA-Z0-9_]* (?=\s*=)/x) + encoder.text_token(match, :key) + encoder.text_token(scan(/\s+/), :space) if check(/\s+/) + encoder.text_token(scan(/\=/), :operator) + state = :initial + elsif match = scan(/\s+/m) + encoder.text_token(match, :space) + else + # Note this clause doesn’t advance the scan pointer, it’s a kind of + # "retry with other options" (the :initial state then of course + # advances the pointer). + state = :initial + end + else + raise + end + + end + + if options[:keep_state] + @state = state + end + + encoder.end_group :string if [:string].include? state + brace_depth.times { encoder.end_group :map } + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/php.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/php.rb new file mode 100644 index 00000000..7a8d75d9 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/php.rb @@ -0,0 +1,527 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + load :html + + # Scanner for PHP. + # + # Original by Stefan Walk. + class PHP < Scanner + + register_for :php + file_extension 'php' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + module Words # :nodoc: + + # according to http://www.php.net/manual/en/reserved.keywords.php + KEYWORDS = %w[ + abstract and array as break case catch class clone const continue declare default do else elseif + enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global + goto if implements interface instanceof namespace new or private protected public static switch + throw try use var while xor + cfunction old_function + ] + + TYPES = %w[ int integer float double bool boolean string array object resource ] + + LANGUAGE_CONSTRUCTS = %w[ + die echo empty exit eval include include_once isset list + require require_once return print unset + ] + + CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] + + # according to http://php.net/quickref.php on 2009-04-21; + # all functions with _ excluded (module functions) and selected additional functions + BUILTIN_FUNCTIONS = %w[ + abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 + atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec + bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite + calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog + compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex + decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each + ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract + fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner + fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv + fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate + getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid + getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext + gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate + gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell + gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate + implode include intval ip2long iptcembed iptcparse isset + jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp + juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log + log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort + natsort next ngettext nl2br nthmac octdec opendir openlog + ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow + prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile + readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir + serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget + snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat + strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen + strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn + strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam + textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack + unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap + array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc + array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip + array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey + array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad + array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift + array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect + array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk + array_walk_recursive + assert_options base_convert base64_decode base64_encode + chunk_split class_exists class_implements class_parents + count_chars debug_backtrace debug_print_backtrace debug_zval_dump + error_get_last error_log error_reporting extension_loaded + file_exists file_get_contents file_put_contents load_file + func_get_arg func_get_args func_num_args function_exists + get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars + get_current_user get_declared_classes get_declared_interfaces get_defined_constants + get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table + get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime + get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type + gc_collect_cycles gc_disable gc_enable gc_enabled + halt_compiler headers_list headers_sent highlight_file highlight_string + html_entity_decode htmlspecialchars_decode + in_array include_once inclued_get_data + is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite + is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable + is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file + is_writable is_writeable + locale_get_default locale_set_default + number_format override_function parse_str parse_url + php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name + php_strip_whitespace php_uname + preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace + preg_replace_callback preg_split print_r + require_once register_shutdown_function register_tick_function + set_error_handler set_exception_handler set_file_buffer set_include_path + set_magic_quotes_runtime set_time_limit shell_exec + str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count + strip_tags substr_compare substr_count substr_replace + time_nanosleep time_sleep_until + token_get_all token_name trigger_error + unregister_tick_function use_soap_error_handler user_error + utf8_decode utf8_encode var_dump var_export + version_compare + zend_logo_guid zend_thread_id zend_version + create_function call_user_func_array + posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid + posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups + posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid + posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid + posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod + posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid + posix_setuid posix_strerror posix_times posix_ttyname posix_uname + pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority + pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait + pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited + pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig + ] + # TODO: more built-in PHP functions? + + EXCEPTIONS = %w[ + E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING + E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT + ] + + CONSTANTS = %w[ + null true false self parent + __LINE__ __DIR__ __FILE__ __LINE__ + __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ + PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS + PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH + PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR + PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX + PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END + __COMPILER_HALT_OFFSET__ + EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS + EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL + COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED + CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 + M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES + CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB + HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS + INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP + CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT + STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX + LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 + ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 + ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 + MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT + ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING + POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES + N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR + YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN + LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 + LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY + LOG_NDELAY LOG_NOWAIT LOG_PERROR + ] + + PREDEFINED = %w[ + $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV + $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header + $argc $argv + ] + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(TYPES, :predefined_type). + add(LANGUAGE_CONSTRUCTS, :keyword). + add(BUILTIN_FUNCTIONS, :predefined). + add(CLASSES, :predefined_constant). + add(EXCEPTIONS, :exception). + add(CONSTANTS, :predefined_constant) + + VARIABLE_KIND = WordList.new(:local_variable). + add(PREDEFINED, :predefined) + end + + module RE # :nodoc: + + PHP_START = / + ]*?language\s*=\s*"php"[^>]*?> | + ]*?language\s*=\s*'php'[^>]*?> | + <\?php\d? | + <\?(?!xml) + /xi + + PHP_END = %r! + | + \?> + !xi + + HTML_INDICATOR = / ]/i + + IDENTIFIER = 'ä'[/[[:alpha:]]/] == 'ä' ? Regexp.new('[[:alpha:]_[^\0-\177]][[:alnum:]_[^\0-\177]]*') : Regexp.new('[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*', true) + VARIABLE = /\$#{IDENTIFIER}/ + + OPERATOR = / + \.(?!\d)=? | # dot that is not decimal point, string concatenation + && | \|\| | # logic + :: | -> | => | # scope, member, dictionary + \\(?!\n) | # namespace + \+\+ | -- | # increment, decrement + [,;?:()\[\]{}] | # simple delimiters + [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts + [~$] | # whatever + =& | # reference assignment + [=!]=?=? | <> | # comparison and assignment + <<=? | >>=? | [<>]=? # comparison and shift + /x + + end + + protected + + def scan_tokens encoder, options + + if check(RE::PHP_START) || # starts with #{RE::IDENTIFIER}/o) + encoder.begin_group :inline + encoder.text_token match, :local_variable + encoder.text_token scan(/->/), :operator + encoder.text_token scan(/#{RE::IDENTIFIER}/o), :ident + encoder.end_group :inline + elsif check(/->/) + match << scan(/->/) + encoder.text_token match, :error + else + encoder.text_token match, :local_variable + end + elsif match = scan(/\{/) + if check(/\$/) + encoder.begin_group :inline + states[-1] = [states.last, delimiter] + delimiter = nil + states.push :php_inline + encoder.text_token match, :delimiter + else + encoder.text_token match, :content + end + elsif match = scan(/\$\{#{RE::IDENTIFIER}\}/o) + encoder.text_token match, :local_variable + elsif match = scan(/\$/) + encoder.text_token match, :content + else + encoder.end_group :string + states.pop + end + + when :class_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :class + states.pop + else + states.pop + end + + when :function_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/&/) + encoder.text_token match, :operator + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :function + states.pop + else + states.pop + end + + else + raise_inspect 'Unknown state!', encoder, states + end + + end + + while state = states.pop + encoder.end_group :string if [:sqstring, :dqstring].include? state + if state.is_a? Array + encoder.end_group :inline + encoder.end_group :string if [:sqstring, :dqstring].include? state.first + end + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/python.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/python.rb new file mode 100644 index 00000000..5da553a6 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/python.rb @@ -0,0 +1,287 @@ +module CodeRay +module Scanners + + # Scanner for Python. Supports Python 3. + # + # Based on pygments' PythonLexer, see + # http://dev.pocoo.org/projects/pygments/browser/pygments/lexers/agile.py. + class Python < Scanner + + register_for :python + file_extension 'py' + + KEYWORDS = [ + 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', + 'del', 'elif', 'else', 'except', 'finally', 'for', + 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', + 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', + 'nonlocal', # new in Python 3 + ] # :nodoc: + + OLD_KEYWORDS = [ + 'exec', 'print', # gone in Python 3 + ] # :nodoc: + + PREDEFINED_METHODS_AND_TYPES = %w[ + __import__ abs all any apply basestring bin bool buffer + bytearray bytes callable chr classmethod cmp coerce compile + complex delattr dict dir divmod enumerate eval execfile exit + file filter float frozenset getattr globals hasattr hash hex id + input int intern isinstance issubclass iter len list locals + long map max min next object oct open ord pow property range + raw_input reduce reload repr reversed round set setattr slice + sorted staticmethod str sum super tuple type unichr unicode + vars xrange zip + ] # :nodoc: + + PREDEFINED_EXCEPTIONS = %w[ + ArithmeticError AssertionError AttributeError + BaseException DeprecationWarning EOFError EnvironmentError + Exception FloatingPointError FutureWarning GeneratorExit IOError + ImportError ImportWarning IndentationError IndexError KeyError + KeyboardInterrupt LookupError MemoryError NameError + NotImplemented NotImplementedError OSError OverflowError + OverflowWarning PendingDeprecationWarning ReferenceError + RuntimeError RuntimeWarning StandardError StopIteration + SyntaxError SyntaxWarning SystemError SystemExit TabError + TypeError UnboundLocalError UnicodeDecodeError + UnicodeEncodeError UnicodeError UnicodeTranslateError + UnicodeWarning UserWarning ValueError Warning ZeroDivisionError + ] # :nodoc: + + PREDEFINED_VARIABLES_AND_CONSTANTS = [ + 'False', 'True', 'None', # "keywords" since Python 3 + 'self', 'Ellipsis', 'NotImplemented', + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(OLD_KEYWORDS, :old_keyword). + add(PREDEFINED_METHODS_AND_TYPES, :predefined). + add(PREDEFINED_VARIABLES_AND_CONSTANTS, :predefined_constant). + add(PREDEFINED_EXCEPTIONS, :exception) # :nodoc: + + NAME = / [[:alpha:]_] \w* /x # :nodoc: + ESCAPE = / [abfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} | N\{[-\w ]+\} /x # :nodoc: + + OPERATOR = / + \.\.\. | # ellipsis + \.(?!\d) | # dot but not decimal point + [,;:()\[\]{}] | # simple delimiters + \/\/=? | \*\*=? | # special math + [-+*\/%&|^]=? | # ordinary math and binary logic + [~`] | # binary complement and inspection + <<=? | >>=? | [<>=]=? | != # comparison and assignment + /x # :nodoc: + + STRING_DELIMITER_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = Regexp.union delimiter # :nodoc: + } + + STRING_CONTENT_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = / [^\\\n]+? (?= \\ | $ | #{Regexp.escape(delimiter)} ) /x # :nodoc: + } + + DEF_NEW_STATE = WordList.new(:initial). + add(%w(def), :def_expected). + add(%w(import from), :include_expected). + add(%w(class), :class_expected) # :nodoc: + + DESCRIPTOR = / + #{NAME} + (?: \. #{NAME} )* + | \* + /x # :nodoc: + + DOCSTRING_COMING = / + [ \t]* u?r? ("""|''') + /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + string_raw = false + string_type = nil + docstring_coming = match?(/#{DOCSTRING_COMING}/o) + last_token_dot = false + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + from_import_state = [] + + until eos? + + if state == :string + if match = scan(STRING_DELIMITER_REGEXP[string_delimiter]) + encoder.text_token match, :delimiter + encoder.end_group string_type + string_type = nil + state = :initial + next + elsif string_delimiter.size == 3 && match = scan(/\n/) + encoder.text_token match, :content + elsif match = scan(STRING_CONTENT_REGEXP[string_delimiter]) + encoder.text_token match, :content + elsif !string_raw && match = scan(/ \\ #{ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ #{UNICODE_ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ . /x) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group string_type + string_type = nil + encoder.text_token match, :error unless match.empty? + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder, state + end + + elsif match = scan(/ [ \t]+ | \\?\n /x) + encoder.text_token match, :space + if match == "\n" + state = :initial if state == :include_expected + docstring_coming = true if match?(/#{DOCSTRING_COMING}/o) + end + next + + elsif match = scan(/ \# [^\n]* /mx) + encoder.text_token match, :comment + next + + elsif state == :initial + + if match = scan(/#{OPERATOR}/o) + encoder.text_token match, :operator + + elsif match = scan(/(u?r?|b)?("""|"|'''|')/i) + modifiers = self[1] + string_delimiter = self[2] + string_type = docstring_coming ? :docstring : (modifiers == 'b' ? :binary : :string) + docstring_coming = false if docstring_coming + encoder.begin_group string_type + string_raw = false + unless modifiers.empty? + string_raw = !!modifiers.index(?r) + encoder.text_token modifiers, :modifier + match = string_delimiter + end + state = :string + encoder.text_token match, :delimiter + + # TODO: backticks + + elsif match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + kind = IDENT_KIND[match] + # TODO: keyword arguments + kind = :ident if last_token_dot + if kind == :old_keyword + kind = check(/\(/) ? :ident : :keyword + elsif kind == :predefined && check(/ *=/) + kind = :ident + elsif kind == :keyword + state = DEF_NEW_STATE[match] + from_import_state << match.to_sym if state == :include_expected + end + encoder.text_token match, kind + + elsif match = scan(/@[a-zA-Z0-9_.]+[lL]?/) + encoder.text_token match, :decorator + + elsif match = scan(/0[xX][0-9A-Fa-f]+[lL]?/) + encoder.text_token match, :hex + + elsif match = scan(/0[bB][01]+[lL]?/) + encoder.text_token match, :binary + + elsif match = scan(/(?:\d*\.\d+|\d+\.\d*)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) + if scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :float + end + + elsif match = scan(/0[oO][0-7]+|0[0-7]+(?![89.eE])[lL]?/) + encoder.text_token match, :octal + + elsif match = scan(/\d+([lL])?/) + if self[1] == nil && scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :integer + end + + else + encoder.text_token getch, :error + + end + + elsif state == :def_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :method + else + next + end + + elsif state == :class_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :class + else + next + end + + elsif state == :include_expected + if match = scan(unicode ? /#{DESCRIPTOR}/uo : /#{DESCRIPTOR}/o) + if match == 'as' + encoder.text_token match, :keyword + from_import_state << :as + elsif from_import_state.first == :from && match == 'import' + encoder.text_token match, :keyword + from_import_state << :import + elsif from_import_state.last == :as + # encoder.text_token match, match[0,1][unicode ? /[[:upper:]]/u : /[[:upper:]]/] ? :class : :method + encoder.text_token match, :ident + from_import_state.pop + elsif IDENT_KIND[match] == :keyword + unscan + match = nil + state = :initial + next + else + encoder.text_token match, :include + end + elsif match = scan(/,/) + from_import_state.pop if from_import_state.last == :as + encoder.text_token match, :operator + else + from_import_state = [] + state = :initial + next + end + + else + raise_inspect 'Unknown state', encoder, state + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group string_type + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/raydebug.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/raydebug.rb new file mode 100644 index 00000000..1effdc85 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/raydebug.rb @@ -0,0 +1,75 @@ +require 'set' + +module CodeRay +module Scanners + + # = Raydebug Scanner + # + # Highlights the output of the Encoders::Debug encoder. + class Raydebug < Scanner + + register_for :raydebug + file_extension 'raydebug' + title 'CodeRay Token Dump' + + protected + + def setup + super + @known_token_kinds = TokenKinds.keys.map(&:to_s).to_set + end + + def scan_tokens encoder, options + + opened_tokens = [] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) /x) + kind = self[1] + encoder.text_token kind, :class + encoder.text_token '(', :operator + match = self[2] + unless match.empty? + if @known_token_kinds.include? kind + encoder.text_token match, kind.to_sym + else + encoder.text_token match, :plain + end + end + encoder.text_token match, :operator if match = scan(/\)/) + + elsif match = scan(/ (\w+) ([<\[]) /x) + encoder.text_token self[1], :class + if @known_token_kinds.include? self[1] + kind = self[1].to_sym + else + kind = :unknown + end + opened_tokens << kind + encoder.begin_group kind + encoder.text_token self[2], :operator + + elsif !opened_tokens.empty? && match = scan(/ [>\]] /x) + encoder.text_token match, :operator + encoder.end_group opened_tokens.pop + + else + encoder.text_token getch, :space + + end + + end + + encoder.end_group opened_tokens.pop until opened_tokens.empty? + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby.rb new file mode 100644 index 00000000..5b8de42f --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby.rb @@ -0,0 +1,477 @@ +module CodeRay +module Scanners + + # This scanner is really complex, since Ruby _is_ a complex language! + # + # It tries to highlight 100% of all common code, + # and 90% of strange codes. + # + # It is optimized for HTML highlighting, and is not very useful for + # parsing or pretty printing. + class Ruby < Scanner + + register_for :ruby + file_extension 'rb' + + autoload :Patterns, CodeRay.coderay_path('scanners', 'ruby', 'patterns') + autoload :StringState, CodeRay.coderay_path('scanners', 'ruby', 'string_state') + + def interpreted_string_state + StringState.new :string, true, '"' + end + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + state, heredocs = options[:state] || @state + heredocs = heredocs.dup if heredocs.is_a?(Array) + + if state && state.instance_of?(StringState) + encoder.begin_group state.type + end + + last_state = nil + + method_call_expected = false + value_expected = true + + inline_block_stack = nil + inline_block_curly_depth = 0 + + if heredocs + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + end + + # def_object_stack = nil + # def_object_paren_depth = 0 + + patterns = Patterns # avoid constant lookup + + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + + until eos? + + if state.instance_of? ::Symbol + + if match = scan(/[ \t\f\v]+/) + encoder.text_token match, :space + + elsif match = scan(/\n/) + if heredocs + unscan # heredoc scanning needs \n at start + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + state = :initial if state == :undef_comma_expected + encoder.text_token match, :space + value_expected = true + end + + elsif match = scan(bol? ? / \#(!)?.* | #{patterns::RUBYDOC_OR_DATA} /ox : /\#.*/) + encoder.text_token match, self[1] ? :doctype : :comment + + elsif match = scan(/\\\n/) + if heredocs + unscan # heredoc scanning needs \n at start + encoder.text_token scan(/\\/), :space + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + encoder.text_token match, :space + end + + elsif state == :initial + + # IDENTS # + if !method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_NAME}/uo : + /#{patterns::METHOD_NAME}/o) + + kind = patterns::IDENT_KIND[match] + if value_expected != :colon_expected && scan(/:(?!:)/) + value_expected = true + encoder.text_token match, :key + encoder.text_token ':', :operator + else + value_expected = false + if kind == :ident + if match[/\A[A-Z]/] && !(match[/[!?]$/] || match?(/\(/)) + kind = :constant + end + elsif kind == :keyword + state = patterns::KEYWORD_NEW_STATE[match] + if patterns::KEYWORDS_EXPECTING_VALUE[match] + value_expected = match == 'when' ? :colon_expected : true + end + end + value_expected = true if !value_expected && check(/#{patterns::VALUE_FOLLOWS}/o) + encoder.text_token match, kind + end + + elsif method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_AFTER_DOT}/uo : + /#{patterns::METHOD_AFTER_DOT}/o) + if method_call_expected == '::' && match[/\A[A-Z]/] && !match?(/\(/) + encoder.text_token match, :constant + else + encoder.text_token match, :ident + end + method_call_expected = false + value_expected = check(/#{patterns::VALUE_FOLLOWS}/o) + + # OPERATORS # + elsif !method_call_expected && match = scan(/ (\.(?!\.)|::) | ( \.\.\.? | ==?=? | [,\(\[\{] ) | [\)\]\}] /x) + method_call_expected = self[1] + value_expected = !method_call_expected && !!self[2] + if inline_block_stack + case match + when '{' + inline_block_curly_depth += 1 + when '}' + inline_block_curly_depth -= 1 + if inline_block_curly_depth == 0 # closing brace of inline block reached + state, inline_block_curly_depth, heredocs = inline_block_stack.pop + inline_block_stack = nil if inline_block_stack.empty? + heredocs = nil if heredocs && heredocs.empty? + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + next + end + end + end + encoder.text_token match, :operator + + elsif match = scan(unicode ? /#{patterns::SYMBOL}/uo : + /#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + else + encoder.text_token match, :symbol + value_expected = false + end + + elsif match = scan(/ ' (?:(?>[^'\\]*) ')? | " (?:(?>[^"\\\#]*) ")? /mx) + if match.size == 1 + kind = check(self.class::StringState.simple_key_pattern(match)) ? :key : :string + encoder.begin_group kind + encoder.text_token match, :delimiter + state = self.class::StringState.new kind, match == '"', match # important for streaming + else + kind = value_expected == true && scan(/:/) ? :key : :string + encoder.begin_group kind + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1,1], :delimiter + encoder.end_group kind + encoder.text_token ':', :operator if kind == :key + value_expected = false + end + + elsif match = scan(unicode ? /#{patterns::INSTANCE_VARIABLE}/uo : + /#{patterns::INSTANCE_VARIABLE}/o) + value_expected = false + encoder.text_token match, :instance_variable + + elsif value_expected && match = scan(/\//) + encoder.begin_group :regexp + encoder.text_token match, :delimiter + state = self.class::StringState.new :regexp, true, '/' + + elsif match = scan(value_expected ? /[-+]?#{patterns::NUMERIC}/o : /#{patterns::NUMERIC}/o) + if method_call_expected + encoder.text_token match, :error + method_call_expected = false + else + kind = self[1] ? :float : :integer # TODO: send :hex/:octal/:binary + match << 'r' if match !~ /e/i && scan(/r/) + match << 'i' if scan(/i/) + encoder.text_token match, kind + end + value_expected = false + + elsif match = scan(/ [-+!~^\/]=? | [:;] | &\. | [*|&]{1,2}=? | >>? /x) + value_expected = true + encoder.text_token match, :operator + + elsif value_expected && match = scan(/#{patterns::HEREDOC_OPEN}/o) + quote = self[3] + delim = self[quote ? 4 : 2] + kind = patterns::QUOTE_TO_TYPE[quote] + encoder.begin_group kind + encoder.text_token match, :delimiter + encoder.end_group kind + heredocs ||= [] # create heredocs if empty + heredocs << self.class::StringState.new(kind, quote != "'", delim, + self[1] ? :indented : :linestart) + value_expected = false + + elsif value_expected && match = scan(/#{patterns::FANCY_STRING_START}/o) + kind = patterns::FANCY_STRING_KIND[self[1]] + encoder.begin_group kind + state = self.class::StringState.new kind, patterns::FANCY_STRING_INTERPRETED[self[1]], self[2] + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/#{patterns::CHARACTER}/o) + value_expected = false + encoder.text_token match, :integer + + elsif match = scan(/ %=? | <(?:<|=>?)? | \? /x) + value_expected = match == '?' ? :colon_expected : true + encoder.text_token match, :operator + + elsif match = scan(/`/) + encoder.begin_group :shell + encoder.text_token match, :delimiter + state = self.class::StringState.new :shell, true, match + + elsif match = scan(unicode ? /#{patterns::GLOBAL_VARIABLE}/uo : + /#{patterns::GLOBAL_VARIABLE}/o) + encoder.text_token match, :global_variable + value_expected = false + + elsif match = scan(unicode ? /#{patterns::CLASS_VARIABLE}/uo : + /#{patterns::CLASS_VARIABLE}/o) + encoder.text_token match, :class_variable + value_expected = false + + elsif match = scan(/\\\z/) + encoder.text_token match, :space + + else + if method_call_expected + method_call_expected = false + next + end + unless unicode + # check for unicode + $DEBUG_BEFORE, $DEBUG = $DEBUG, false + begin + if check(/./mu).size > 1 + # seems like we should try again with unicode + unicode = true + end + rescue + # bad unicode char; use getch + ensure + $DEBUG = $DEBUG_BEFORE + end + next if unicode + end + + encoder.text_token getch, :error + + end + + if last_state + state = last_state unless state.is_a?(StringState) # otherwise, a simple 'def"' results in unclosed tokens + last_state = nil + end + + elsif state == :def_expected + if match = scan(unicode ? /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + state = :initial + else + last_state = :dot_expected + state = :initial + end + + elsif state == :dot_expected + if match = scan(/\.|::/) + # invalid definition + state = :def_expected + encoder.text_token match, :operator + else + state = :initial + end + + elsif state == :module_expected + if match = scan(/<#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + elsif match = scan(/#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + state.next_state = :undef_comma_expected + else + encoder.text_token match, :symbol + end + else + state = :initial + end + + elsif state == :undef_comma_expected + if match = scan(/,/) + encoder.text_token match, :operator + state = :undef_expected + else + state = :initial + end + + elsif state == :alias_expected + match = scan(unicode ? /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/uo : + /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/o) + + if match + encoder.text_token self[1], (self[1][0] == ?: ? :symbol : :method) + encoder.text_token self[2], :space + encoder.text_token self[3], (self[3][0] == ?: ? :symbol : :method) + end + state = :initial + + else + #:nocov: + raise_inspect 'Unknown state: %p' % [state], encoder + #:nocov: + end + + else # StringState + + match = scan_until(state.pattern) || scan_rest + unless match.empty? + encoder.text_token match, :content + break if eos? + end + + if state.heredoc && self[1] # end of heredoc + match = getch + match << scan_until(/$/) unless eos? + encoder.text_token match, :delimiter unless match.empty? + encoder.end_group state.type + state = state.next_state + next + end + + case match = getch + + when state.delim + if state.paren_depth + state.paren_depth -= 1 + if state.paren_depth > 0 + encoder.text_token match, :content + next + end + end + encoder.text_token match, :delimiter + if state.type == :regexp && !eos? + match = scan(/#{patterns::REGEXP_MODIFIERS}/o) + encoder.text_token match, :modifier unless match.empty? + end + encoder.end_group state.type + value_expected = false + state = state.next_state + + when '\\' + if state.interpreted + if esc = scan(/#{patterns::ESCAPE}/o) + encoder.text_token match + esc, :char + else + encoder.text_token match, :error + end + else + case esc = getch + when nil + encoder.text_token match, :content + when state.delim, '\\' + encoder.text_token match + esc, :char + else + encoder.text_token match + esc, :content + end + end + + when '#' + case peek(1) + when '{' + inline_block_stack ||= [] + inline_block_stack << [state, inline_block_curly_depth, heredocs] + value_expected = true + state = :initial + inline_block_curly_depth = 1 + encoder.begin_group :inline + encoder.text_token match + getch, :inline_delimiter + when '$', '@' + encoder.text_token match, :escape + last_state = state + state = :initial + else + #:nocov: + raise_inspect 'else-case # reached; #%p not handled' % [peek(1)], encoder + #:nocov: + end + + when state.opening_paren + state.paren_depth += 1 + encoder.text_token match, :content + + else + #:nocov + raise_inspect 'else-case " reached; %p not handled, state = %p' % [match, state], encoder + #:nocov: + + end + + end + + end + + # cleaning up + if state.is_a? StringState + encoder.end_group state.type + end + + if options[:keep_state] + if state.is_a?(StringState) && state.heredoc + (heredocs ||= []).unshift state + state = :initial + elsif heredocs && heredocs.empty? + heredocs = nil + end + @state = state, heredocs + end + + if inline_block_stack + until inline_block_stack.empty? + state, = *inline_block_stack.pop + encoder.end_group :inline + encoder.end_group state.type + end + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/patterns.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/patterns.rb new file mode 100644 index 00000000..cd942d0d --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/patterns.rb @@ -0,0 +1,178 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + module Ruby::Patterns # :nodoc: all + + KEYWORDS = %w[ + and def end in or unless begin + defined? ensure module redo super until + BEGIN break do next rescue then + when END case else for retry + while alias class elsif if not return + undef yield + ] + + # See http://murfy.de/ruby-constants. + PREDEFINED_CONSTANTS = %w[ + nil true false self + DATA ARGV ARGF ENV + FALSE TRUE NIL + STDERR STDIN STDOUT + TOPLEVEL_BINDING + RUBY_COPYRIGHT RUBY_DESCRIPTION RUBY_ENGINE RUBY_PATCHLEVEL + RUBY_PLATFORM RUBY_RELEASE_DATE RUBY_REVISION RUBY_VERSION + __FILE__ __LINE__ __ENCODING__ + ] + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEW_STATE = WordList.new(:initial). + add(%w[ def ], :def_expected). + add(%w[ undef ], :undef_expected). + add(%w[ alias ], :alias_expected). + add(%w[ class module ], :module_expected) + + IDENT = 'ä'[/[[:alpha:]]/] == 'ä' ? Regexp.new('[[:alpha:]_[^\0-\177]][[:alnum:]_[^\0-\177]]*') : /[^\W\d]\w*/ + + METHOD_NAME = / #{IDENT} [?!]? /ox + METHOD_NAME_OPERATOR = / + \*\*? # multiplication and power + | [-+~]@? # plus, minus, tilde with and without at sign + | [\/%&|^`] # division, modulo or format strings, and, or, xor, system + | \[\]=? # array getter and setter + | << | >> # append or shift left, shift right + | <=?>? | >=? # comparison, rocket operator + | ===? | =~ # simple equality, case equality, match + | ![~=@]? # negation with and without at sign, not-equal and not-match + /ox + METHOD_SUFFIX = / (?: [?!] | = (?![~>]|=(?!>)) ) /x + METHOD_NAME_EX = / #{IDENT} #{METHOD_SUFFIX}? | #{METHOD_NAME_OPERATOR} /ox + METHOD_AFTER_DOT = / #{IDENT} [?!]? | #{METHOD_NAME_OPERATOR} /ox + INSTANCE_VARIABLE = / @ #{IDENT} /ox + CLASS_VARIABLE = / @@ #{IDENT} /ox + OBJECT_VARIABLE = / @@? #{IDENT} /ox + GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox + PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox + VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox + + QUOTE_TO_TYPE = { + '`' => :shell, + '/' => :regexp, + } + QUOTE_TO_TYPE.default = :string + + REGEXP_MODIFIERS = /[mousenix]*/ + + DECIMAL = /\d+(?:_\d+)*/ + OCTAL = /0_?[0-7]+(?:_[0-7]+)*/ + HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/ + BINARY = /0b[01]+(?:_[01]+)*/ + + EXPONENT = / [eE] [+-]? #{DECIMAL} /ox + FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox + FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox + NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox + + SYMBOL = / + : + (?: + #{METHOD_NAME_EX} + | #{PREFIX_VARIABLE} + | ['"] + ) + /ox + METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox + + SIMPLE_ESCAPE = / + [abefnrstv] + | [0-7]{1,3} + | x[0-9A-Fa-f]{1,2} + | . + /mx + + CONTROL_META_ESCAPE = / + (?: M-|C-|c ) + (?: \\ (?: M-|C-|c ) )* + (?: [^\\] | \\ #{SIMPLE_ESCAPE} )? + /mox + + ESCAPE = / + #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE} + /mox + + CHARACTER = / + \? + (?: + [^\s\\] + | \\ #{ESCAPE} + ) + /mox + + # NOTE: This is not completely correct, but + # nobody needs heredoc delimiters ending with \n. + HEREDOC_OPEN = / + << ([-~])? # $1 = float + (?: + ( [A-Za-z_0-9]+ ) # $2 = delim + | + ( ["'`\/] ) # $3 = quote, type + ( [^\n]*? ) \3 # $4 = delim + ) + /mx + + RUBYDOC = / + =begin (?!\S) + .*? + (?: \Z | ^=end (?!\S) [^\n]* ) + /mx + + DATA = / + __END__$ + .*? + (?: \Z | (?=^\#CODE) ) + /mx + + RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo + + # Checks for a valid value to follow. This enables + # value_expected in method calls without parentheses. + VALUE_FOLLOWS = / + (?>[ \t\f\v]+) + (?: + [%\/][^\s=] + | <<-?\S + | [-+] \d + | #{CHARACTER} + ) + /ox + KEYWORDS_EXPECTING_VALUE = WordList.new.add(%w[ + and end in or unless begin + defined? ensure redo super until + break do next rescue then + when case else for retry + while elsif if not return + yield + ]) + + FANCY_STRING_START = / % ( [iIqQrswWx] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /x + FANCY_STRING_KIND = Hash.new(:string).merge({ + 'i' => :symbol, + 'I' => :symbol, + 'r' => :regexp, + 's' => :symbol, + 'x' => :shell, + }) + FANCY_STRING_INTERPRETED = Hash.new(true).merge({ + 'i' => false, + 'q' => false, + 's' => false, + 'w' => false, + }) + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/string_state.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/string_state.rb new file mode 100644 index 00000000..95f1e832 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/ruby/string_state.rb @@ -0,0 +1,79 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + class Ruby + + class StringState < Struct.new :type, :interpreted, :delim, :heredoc, + :opening_paren, :paren_depth, :pattern, :next_state # :nodoc: all + + CLOSING_PAREN = Hash[ *%w[ + ( ) + [ ] + < > + { } + ] ].each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << + + STRING_PATTERN = Hash.new do |h, k| + delim, interpreted = *k + delim_pattern = Regexp.escape(delim) + if closing_paren = CLOSING_PAREN[delim] + delim_pattern << Regexp.escape(closing_paren) + end + delim_pattern << '\\\\' unless delim == '\\' + + # special_escapes = + # case interpreted + # when :regexp_symbols + # '| [|?*+(){}\[\].^$]' + # end + + if interpreted && delim != '#' + / (?= [#{delim_pattern}] | \# [{$@] ) /mx + else + / (?= [#{delim_pattern}] ) /mx + end.tap do |pattern| + h[k] = pattern if (delim.respond_to?(:ord) ? delim.ord : delim[0]) < 256 + end + end + + def self.simple_key_pattern delim + if delim == "'" + / (?> (?: [^\\']+ | \\. )* ) ' : /mx + else + / (?> (?: [^\\"\#]+ | \\. | \#\$[\\"] | \#\{[^\{\}]+\} | \#(?!\{) )* ) " : /mx + end + end + + def initialize kind, interpreted, delim, heredoc = false + if heredoc + pattern = heredoc_pattern delim, interpreted, heredoc == :indented + delim = nil + else + pattern = STRING_PATTERN[ [delim, interpreted] ] + if closing_paren = CLOSING_PAREN[delim] + opening_paren = delim + delim = closing_paren + paren_depth = 1 + end + end + super kind, interpreted, delim, heredoc, opening_paren, paren_depth, pattern, :initial + end + + def heredoc_pattern delim, interpreted, indented + # delim = delim.dup # workaround for old Ruby + delim_pattern = Regexp.escape(delim) + delim_pattern = / (?:\A|\n) #{ '(?>[ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x + if interpreted + / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc + else + / (?= #{delim_pattern}() | \\ ) /mx + end + end + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/sass.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/sass.rb new file mode 100644 index 00000000..e3296b90 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/sass.rb @@ -0,0 +1,232 @@ +module CodeRay +module Scanners + + # A scanner for Sass. + class Sass < CSS + + register_for :sass + file_extension 'sass' + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + states = Array(options[:state] || @state).dup + + encoder.begin_group :string if states.last == :sqstring || states.last == :dqstring + + until eos? + + if bol? && (match = scan(/(?>( +)?(\/[\*\/])(.+)?)(?=\n)/)) + encoder.text_token self[1], :space if self[1] + encoder.begin_group :comment + encoder.text_token self[2], :delimiter + encoder.text_token self[3], :content if self[3] + if match = scan(/(?:\n+#{self[1]} .*)+/) + encoder.text_token match, :content + end + encoder.end_group :comment + elsif match = scan(/\n|[^\n\S]+\n?/) + encoder.text_token match, :space + if match.index(/\n/) + value_expected = false + states.pop if states.last == :include + end + + elsif states.last == :sass_inline && (match = scan(/\}/)) + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + states.pop + + elsif case states.last + when :initial, :media, :sass_inline + if match = scan(/(?>#{RE::Ident})(?!\()/ox) + encoder.text_token match, value_expected ? :value : (check(/.*:(?![a-z])/) ? :key : :tag) + next + elsif !value_expected && (match = scan(/\*/)) + encoder.text_token match, :tag + next + elsif match = scan(RE::Class) + encoder.text_token match, :class + next + elsif match = scan(RE::Id) + encoder.text_token match, :id + next + elsif match = scan(RE::PseudoClass) + encoder.text_token match, :pseudo_class + next + elsif match = scan(RE::AttributeSelector) + # TODO: Improve highlighting inside of attribute selectors. + encoder.text_token match[0,1], :operator + encoder.text_token match[1..-2], :attribute_name if match.size > 2 + encoder.text_token match[-1,1], :operator if match[-1] == ?] + next + elsif match = scan(/(\=|@mixin +)#{RE::Ident}/o) + encoder.text_token match, :function + next + elsif match = scan(/@import\b/) + encoder.text_token match, :directive + states << :include + next + elsif match = scan(/@media\b/) + encoder.text_token match, :directive + # states.push :media_before_name + next + end + + when :block + if match = scan(/(?>#{RE::Ident})(?!\()/ox) + if value_expected + encoder.text_token match, :value + else + encoder.text_token match, :key + end + next + end + + when :sqstring, :dqstring + if match = scan(states.last == :sqstring ? /(?:[^\n\'\#]+|\\\n|#{RE::Escape}|#(?!\{))+/o : /(?:[^\n\"\#]+|\\\n|#{RE::Escape}|#(?!\{))+/o) + encoder.text_token match, :content + elsif match = scan(/['"]/) + encoder.text_token match, :delimiter + encoder.end_group :string + states.pop + elsif match = scan(/#\{/) + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + states.push :sass_inline + elsif match = scan(/ \\ | $ /x) + encoder.end_group states.last + encoder.text_token match, :error unless match.empty? + states.pop + else + raise_inspect "else case #{states.last} reached; %p not handled." % peek(1), encoder + end + + when :include + if match = scan(/[^\s'",]+/) + encoder.text_token match, :include + next + end + + else + #:nocov: + raise_inspect 'Unknown state: %p' % [states.last], encoder + #:nocov: + + end + + elsif match = scan(/\$#{RE::Ident}/o) + encoder.text_token match, :variable + next + + elsif match = scan(/&/) + encoder.text_token match, :local_variable + + elsif match = scan(/\+#{RE::Ident}/o) + encoder.text_token match, :include + value_expected = true + + elsif match = scan(/\/\*(?:.*?\*\/|.*)|\/\/.*/) + encoder.text_token match, :comment + + elsif match = scan(/#\{/) + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + states.push :sass_inline + + elsif match = scan(/\{/) + value_expected = false + encoder.text_token match, :operator + states.push :block + + elsif match = scan(/\}/) + value_expected = false + encoder.text_token match, :operator + if states.last == :block || states.last == :media + states.pop + end + + elsif match = scan(/['"]/) + encoder.begin_group :string + encoder.text_token match, :delimiter + if states.include? :sass_inline + # no nesting, just scan the string until delimiter + content = scan_until(/(?=#{match}|\}|\z)/) + encoder.text_token content, :content unless content.empty? + encoder.text_token match, :delimiter if scan(/#{match}/) + encoder.end_group :string + else + states.push match == "'" ? :sqstring : :dqstring + end + + elsif match = scan(/#{RE::Function}/o) + encoder.begin_group :function + start = match[/^[-\w]+\(/] + encoder.text_token start, :delimiter + if match[-1] == ?) + encoder.text_token match[start.size..-2], :content + encoder.text_token ')', :delimiter + else + encoder.text_token match[start.size..-1], :content if start.size < match.size + end + encoder.end_group :function + + elsif match = scan(/[a-z][-a-z_]*(?=\()/o) + encoder.text_token match, :predefined + + elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) + encoder.text_token match, :float + + elsif match = scan(/#{RE::HexColor}/o) + encoder.text_token match, :color + + elsif match = scan(/! *(?:important|optional)/) + encoder.text_token match, :important + + elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/) + encoder.text_token match, :color + + elsif match = scan(/@else if\b|#{RE::AtKeyword}/o) + encoder.text_token match, :directive + value_expected = true + + elsif match = scan(/ == | != | [-+*\/>~:;,.=()] /x) + if match == ':' + value_expected = true + elsif match == ';' + value_expected = false + end + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + end + + states.pop if states.last == :include + + if options[:keep_state] + @state = states.dup + end + + while state = states.pop + if state == :sass_inline + encoder.end_group :inline + elsif state == :sqstring || state == :dqstring + encoder.end_group :string + end + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/scanner.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/scanner.rb new file mode 100644 index 00000000..efa710d9 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/scanner.rb @@ -0,0 +1,337 @@ +# encoding: utf-8 + +module CodeRay + module Scanners + + # = Scanner + # + # The base class for all Scanners. + # + # It is a subclass of Ruby's great +StringScanner+, which + # makes it easy to access the scanning methods inside. + # + # It is also +Enumerable+, so you can use it like an Array of + # Tokens: + # + # require 'coderay' + # + # c_scanner = CodeRay::Scanners[:c].new "if (*p == '{') nest++;" + # + # for text, kind in c_scanner + # puts text if kind == :operator + # end + # + # # prints: (*==)++; + # + # OK, this is a very simple example :) + # You can also use +map+, +any?+, +find+ and even +sort_by+, + # if you want. + class Scanner < StringScanner + + extend Plugin + plugin_host Scanners + + # Raised if a Scanner fails while scanning + ScanError = Class.new StandardError + + # The default options for all scanner classes. + # + # Define @default_options for subclasses. + DEFAULT_OPTIONS = { } + + KINDS_NOT_LOC = [:comment, :doctype, :docstring] + + attr_accessor :state + + class << self + + # Normalizes the given code into a string with UNIX newlines, in the + # scanner's internal encoding, with invalid and undefined charachters + # replaced by placeholders. Always returns a new object. + def normalize code + # original = code + code = code.to_s unless code.is_a? ::String + return code if code.empty? + + if code.respond_to? :encoding + code = encode_with_encoding code, self.encoding + else + code = to_unix code + end + # code = code.dup if code.eql? original + code + end + + # The typical filename suffix for this scanner's language. + def file_extension extension = lang + @file_extension ||= extension.to_s + end + + # The encoding used internally by this scanner. + def encoding name = 'UTF-8' + @encoding ||= defined?(Encoding.find) && Encoding.find(name) + end + + # The lang of this Scanner class, which is equal to its Plugin ID. + def lang + @plugin_id + end + + protected + + def encode_with_encoding code, target_encoding + if code.encoding == target_encoding + if code.valid_encoding? + return to_unix(code) + else + source_encoding = guess_encoding code + end + else + source_encoding = code.encoding + end + # print "encode_with_encoding from #{source_encoding} to #{target_encoding}" + code.encode target_encoding, source_encoding, :universal_newline => true, :undef => :replace, :invalid => :replace + end + + def to_unix code + code.index(?\r) ? code.gsub(/\r\n?/, "\n") : code + end + + def guess_encoding s + #:nocov: + IO.popen("file -b --mime -", "w+") do |file| + file.write s[0, 1024] + file.close_write + begin + Encoding.find file.gets[/charset=([-\w]+)/, 1] + rescue ArgumentError + Encoding::BINARY + end + end + #:nocov: + end + + end + + # Create a new Scanner. + # + # * +code+ is the input String and is handled by the superclass + # StringScanner. + # * +options+ is a Hash with Symbols as keys. + # It is merged with the default options of the class (you can + # overwrite default options here.) + # + # Else, a Tokens object is used. + def initialize code = '', options = {} + if self.class == Scanner + raise NotImplementedError, "I am only the basic Scanner class. I can't scan anything. :( Use my subclasses." + end + + @options = self.class::DEFAULT_OPTIONS.merge options + + super self.class.normalize(code) + + @tokens = options[:tokens] || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + + setup + end + + # Sets back the scanner. Subclasses should redefine the reset_instance + # method instead of this one. + def reset + super + reset_instance + end + + # Set a new string to be scanned. + def string= code + code = self.class.normalize(code) + super code + reset_instance + end + + # the Plugin ID for this scanner + def lang + self.class.lang + end + + # the default file extension for this scanner + def file_extension + self.class.file_extension + end + + # Scan the code and returns all tokens in a Tokens object. + def tokenize source = nil, options = {} + options = @options.merge(options) + + set_tokens_from_options options + set_string_from_source source + + begin + scan_tokens @tokens, options + rescue => e + message = "Error in %s#scan_tokens, initial state was: %p" % [self.class, defined?(state) && state] + raise_inspect e.message, @tokens, message, 30, e.backtrace + end + + @cached_tokens = @tokens + if source.is_a? Array + @tokens.split_into_parts(*source.map { |part| part.size }) + else + @tokens + end + end + + # Cache the result of tokenize. + def tokens + @cached_tokens ||= tokenize + end + + # Traverse the tokens. + def each &block + tokens.each(&block) + end + include Enumerable + + # The current line position of the scanner, starting with 1. + # See also: #column. + # + # Beware, this is implemented inefficiently. It should be used + # for debugging only. + def line pos = self.pos + return 1 if pos <= 0 + binary_string[0...pos].count("\n") + 1 + end + + # The current column position of the scanner, starting with 1. + # See also: #line. + def column pos = self.pos + return 1 if pos <= 0 + pos - (binary_string.rindex(?\n, pos - 1) || -1) + end + + # The string in binary encoding. + # + # To be used with #pos, which is the index of the byte the scanner + # will scan next. + def binary_string + @binary_string ||= + if string.respond_to?(:bytesize) && string.bytesize != string.size + #:nocov: + string.dup.force_encoding('binary') + #:nocov: + else + string + end + end + + protected + + # Can be implemented by subclasses to do some initialization + # that has to be done once per instance. + # + # Use reset for initialization that has to be done once per + # scan. + def setup # :doc: + end + + def set_string_from_source source + case source + when Array + self.string = self.class.normalize(source.join) + when nil + reset + else + self.string = self.class.normalize(source) + end + end + + def set_tokens_from_options options + @tokens = options[:tokens] || @tokens || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + end + + # This is the central method, and commonly the only one a + # subclass implements. + # + # Subclasses must implement this method; it must return +tokens+ + # and must only use Tokens#<< for storing scanned tokens! + def scan_tokens tokens, options # :doc: + raise NotImplementedError, "#{self.class}#scan_tokens not implemented." + end + + # Resets the scanner. + def reset_instance + @tokens.clear if @tokens.respond_to?(:clear) && !@options[:keep_tokens] + @cached_tokens = nil + @binary_string = nil if defined? @binary_string + end + + SCAN_ERROR_MESSAGE = <<-MESSAGE + + +***ERROR in %s: %s (after %s tokens) + +tokens: +%s + +%s + +surrounding code: +%p ~~ %p + + +***ERROR*** + + MESSAGE + + def raise_inspect_arguments message, tokens, state, ambit + return File.basename(caller[0]), + message, + tokens_size(tokens), + tokens_last(tokens, 10).map(&:inspect).join("\n"), + scanner_state_info(state), + binary_string[pos - ambit, ambit], + binary_string[pos, ambit] + end + + SCANNER_STATE_INFO = <<-INFO +current line: %d column: %d pos: %d +matched: %p state: %p +bol?: %p, eos?: %p + INFO + + def scanner_state_info state + SCANNER_STATE_INFO % [ + line, column, pos, + matched, state || 'No state given!', + bol?, eos?, + ] + end + + # Scanner error with additional status information + def raise_inspect message, tokens, state = self.state, ambit = 30, backtrace = caller + raise ScanError, SCAN_ERROR_MESSAGE % raise_inspect_arguments(message, tokens, state, ambit), backtrace + end + + def tokens_size tokens + tokens.size if tokens.respond_to?(:size) + end + + def tokens_last tokens, n + tokens.respond_to?(:last) ? tokens.last(n) : [] + end + + # Shorthand for scan_until(/\z/). + # This method also avoids a JRuby 1.9 mode bug. + def scan_rest + rest = self.rest + terminate + rest + end + + end + + end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/sql.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/sql.rb new file mode 100644 index 00000000..c8725a8f --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/sql.rb @@ -0,0 +1,169 @@ +module CodeRay +module Scanners + + # by Josh Goebel + class SQL < Scanner + + register_for :sql + + KEYWORDS = %w( + all and any as before begin between by case check collate + each else end exists + for foreign from full group having if in inner is join + like not of on or order outer over references + then to union using values when where + left right distinct + ) + + OBJECTS = %w( + database databases table tables column columns fields index constraint + constraints transaction function procedure row key view trigger + ) + + COMMANDS = %w( + add alter comment create delete drop grant insert into select update set + show prompt begin commit rollback replace truncate + ) + + PREDEFINED_TYPES = %w( + char varchar varchar2 enum binary text tinytext mediumtext + longtext blob tinyblob mediumblob longblob timestamp + date time datetime year double decimal float int + integer tinyint mediumint bigint smallint unsigned bit numeric + bool boolean hex bin oct + ) + + PREDEFINED_FUNCTIONS = %w( sum cast substring abs pi count min max avg now ) + + DIRECTIVES = %w( + auto_increment unique default charset initially deferred + deferrable cascade immediate read write asc desc after + primary foreign return engine + ) + + PREDEFINED_CONSTANTS = %w( null true false ) + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(OBJECTS, :type). + add(COMMANDS, :class). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(PREDEFINED_FUNCTIONS, :predefined). + add(DIRECTIVES, :directive) + + ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x + + STRING_PREFIXES = /[xnb]|_\w+/i + + STRING_CONTENT_PATTERN = { + '"' => / (?: [^\\"] | "" )+ /x, + "'" => / (?: [^\\'] | '' )+ /x, + '`' => / (?: [^\\`] | `` )+ /x, + } + + def scan_tokens encoder, options + + state = :initial + string_type = nil + string_content = '' + name_expected = false + + until eos? + + if state == :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + + elsif match = scan(/(?:--\s?|#).*/) + encoder.text_token match, :comment + + elsif match = scan(%r( /\* (!)? (?: .*? \*/ | .* ) )mx) + encoder.text_token match, self[1] ? :directive : :comment + + elsif match = scan(/ [*\/=<>:;,!&^|()\[\]{}~%] | [-+\.](?!\d) /x) + name_expected = true if match == '.' && check(/[A-Za-z_]/) + encoder.text_token match, :operator + + elsif match = scan(/(#{STRING_PREFIXES})?([`"'])/o) + prefix = self[1] + string_type = self[2] + encoder.begin_group :string + encoder.text_token prefix, :modifier if prefix + match = string_type + state = :string + encoder.text_token match, :delimiter + + elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9\$]* /x) + encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match]) + name_expected = false + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + + elsif match = scan(/0[0-7]+(?![89.eEfF])/) + encoder.text_token match, :octal + + elsif match = scan(/[-+]?(?>\d+)(?![.eEfF])/) + encoder.text_token match, :integer + + elsif match = scan(/[-+]?(?:\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+)/) + encoder.text_token match, :float + + elsif match = scan(/\\N/) + encoder.text_token match, :predefined_constant + + else + encoder.text_token getch, :error + + end + + elsif state == :string + if match = scan(STRING_CONTENT_PATTERN[string_type]) + encoder.text_token match, :content + elsif match = scan(/["'`]/) + if string_type == match + if peek(1) == string_type # doubling means escape + encoder.text_token match + getch, :content + else + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + string_type = nil + end + else + encoder.text_token match, :content + end + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ . /mox) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.text_token match, :error unless match.empty? + encoder.end_group :string + state = :initial + else + raise "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise 'else-case reached', encoder + + end + + end + + if state == :string + encoder.end_group state + end + + encoder + + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/taskpaper.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/taskpaper.rb new file mode 100644 index 00000000..42670bcc --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/taskpaper.rb @@ -0,0 +1,36 @@ +module CodeRay +module Scanners + + class Taskpaper < Scanner + + register_for :taskpaper + file_extension 'taskpaper' + + protected + + def scan_tokens encoder, options + until eos? + if match = scan(/\S.*:.*$/) # project + encoder.text_token(match, :namespace) + elsif match = scan(/-.+@done.*/) # completed task + encoder.text_token(match, :done) + elsif match = scan(/-(?:[^@\n]+|@(?!due))*/) # task + encoder.text_token(match, :plain) + elsif match = scan(/@due.*/) # comment + encoder.text_token(match, :important) + elsif match = scan(/.+/) # comment + encoder.text_token(match, :comment) + elsif match = scan(/\s+/) # space + encoder.text_token(match, :space) + else # other + encoder.text_token getch, :error + end + end + + encoder + end + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/text.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/text.rb new file mode 100644 index 00000000..bde90297 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/text.rb @@ -0,0 +1,26 @@ +module CodeRay + module Scanners + + # Scanner for plain text. + # + # Yields just one token of the kind :plain. + # + # Alias: +plaintext+, +plain+ + class Text < Scanner + + register_for :text + title 'Plain text' + + KINDS_NOT_LOC = [:plain] # :nodoc: + + protected + + def scan_tokens encoder, options + encoder.text_token string, :plain + encoder + end + + end + + end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/xml.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/xml.rb new file mode 100644 index 00000000..947f16ee --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/xml.rb @@ -0,0 +1,17 @@ +module CodeRay +module Scanners + + load :html + + # Scanner for XML. + # + # Currently this is the same scanner as Scanners::HTML. + class XML < HTML + + register_for :xml + file_extension 'xml' + + end + +end +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/scanners/yaml.rb b/bin/gems/coderay-1.1.3/lib/coderay/scanners/yaml.rb new file mode 100644 index 00000000..32c8e2cb --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/scanners/yaml.rb @@ -0,0 +1,140 @@ +module CodeRay +module Scanners + + # Scanner for YAML. + # + # Based on the YAML scanner from Syntax by Jamis Buck. + class YAML < Scanner + + register_for :yaml + file_extension 'yml' + + KINDS_NOT_LOC = :all + + protected + + def scan_tokens encoder, options + + state = :initial + key_indent = string_indent = 0 + + until eos? + + key_indent = nil if bol? + + if match = scan(/ +[\t ]*/) + encoder.text_token match, :space + + elsif match = scan(/\n+/) + encoder.text_token match, :space + state = :initial if match.index(?\n) + + elsif match = scan(/#.*/) + encoder.text_token match, :comment + + elsif bol? and case + when match = scan(/---|\.\.\./) + encoder.begin_group :head + encoder.text_token match, :head + encoder.end_group :head + next + when match = scan(/%.*/) + encoder.text_token match, :doctype + next + end + + elsif state == :value and case + when !check(/(?:"[^"]*")(?=: |:$)/) && match = scan(/"/) + encoder.begin_group :string + encoder.text_token match, :delimiter + encoder.text_token match, :content if (match = scan(/ [^"\\]* (?: \\. [^"\\]* )* /mx)) && !match.empty? + encoder.text_token match, :delimiter if match = scan(/"/) + encoder.end_group :string + next + when match = scan(/[|>][-+]?/) + encoder.begin_group :string + encoder.text_token match, :delimiter + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + when match = scan(/(?![!"*&]).+?(?=$|\s+#)/) + encoder.begin_group :string + encoder.text_token match, :content + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + end + + elsif case + when match = scan(/[-:](?= |$)/) + state = :value if state == :colon && (match == ':' || match == '-') + state = :value if state == :initial && match == '-' + encoder.text_token match, :operator + next + when match = scan(/[,{}\[\]]/) + encoder.text_token match, :operator + next + when state == :initial && match = scan(/[-\w.()\/ ]*\S(?= *:(?: |$))/) + encoder.text_token match, :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(?:"[^"\n]*"|'[^'\n]*')(?= *:(?: |$))/) + encoder.begin_group :key + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1,1], :delimiter + encoder.end_group :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(![\w\/]+)(:([\w:]+))?/) + encoder.text_token self[1], :type + if self[2] + encoder.text_token ':', :operator + encoder.text_token self[3], :class + end + next + when match = scan(/&\S+/) + encoder.text_token match, :variable + next + when match = scan(/\*\w+/) + encoder.text_token match, :global_variable + next + when match = scan(/< 'debug', # highlight for debugging (white on blue background) + + :annotation => 'annotation', # Groovy, Java + :attribute_name => 'attribute-name', # HTML, CSS + :attribute_value => 'attribute-value', # HTML + :binary => 'binary', # Python, Ruby + :char => 'char', # most scanners, also inside of strings + :class => 'class', # lots of scanners, for different purposes also in CSS + :class_variable => 'class-variable', # Ruby, YAML + :color => 'color', # CSS + :comment => 'comment', # most scanners + :constant => 'constant', # PHP, Ruby + :content => 'content', # inside of strings, most scanners + :decorator => 'decorator', # Python + :definition => 'definition', # CSS + :delimiter => 'delimiter', # inside strings, comments and other types + :directive => 'directive', # lots of scanners + :doctype => 'doctype', # Goorvy, HTML, Ruby, YAML + :docstring => 'docstring', # Python + :done => 'done', # Taskpaper + :entity => 'entity', # HTML + :error => 'error', # invalid token, most scanners + :escape => 'escape', # Ruby (string inline variables like #$foo, #@bar) + :exception => 'exception', # Java, PHP, Python + :filename => 'filename', # Diff + :float => 'float', # most scanners + :function => 'function', # CSS, JavaScript, PHP + :global_variable => 'global-variable', # Ruby, YAML + :hex => 'hex', # hexadecimal number; lots of scanners + :id => 'id', # CSS + :imaginary => 'imaginary', # Python + :important => 'important', # CSS, Taskpaper + :include => 'include', # C, Groovy, Java, Python, Sass + :inline => 'inline', # nested code, eg. inline string evaluation; lots of scanners + :inline_delimiter => 'inline-delimiter', # used instead of :inline > :delimiter FIXME: Why use inline_delimiter? + :instance_variable => 'instance-variable', # Ruby + :integer => 'integer', # most scanners + :key => 'key', # lots of scanners, used together with :value + :keyword => 'keyword', # reserved word that's actually implemented; most scanners + :label => 'label', # C, PHP + :local_variable => 'local-variable', # local and magic variables; some scanners + :map => 'map', # Lua tables + :modifier => 'modifier', # used inside on strings; lots of scanners + :namespace => 'namespace', # Clojure, Java, Taskpaper + :octal => 'octal', # lots of scanners + :predefined => 'predefined', # predefined function: lots of scanners + :predefined_constant => 'predefined-constant',# lots of scanners + :predefined_type => 'predefined-type', # C, Java, PHP + :preprocessor => 'preprocessor', # C, Delphi, HTML + :pseudo_class => 'pseudo-class', # CSS + :regexp => 'regexp', # Groovy, JavaScript, Ruby + :reserved => 'reserved', # most scanners + :shell => 'shell', # Ruby + :string => 'string', # most scanners + :symbol => 'symbol', # Clojure, Ruby, YAML + :tag => 'tag', # CSS, HTML + :type => 'type', # CSS, Java, SQL, YAML + :value => 'value', # used together with :key; CSS, JSON, YAML + :variable => 'variable', # Sass, SQL, YAML + + :change => 'change', # Diff + :delete => 'delete', # Diff + :head => 'head', # Diff, YAML + :insert => 'insert', # Diff + :eyecatcher => 'eyecatcher', # Diff + + :ident => false, # almost all scanners + :operator => false, # almost all scanners + + :space => false, # almost all scanners + :plain => false # almost all scanners + ) + + TokenKinds[:method] = TokenKinds[:function] + TokenKinds[:unknown] = TokenKinds[:plain] +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/tokens.rb b/bin/gems/coderay-1.1.3/lib/coderay/tokens.rb new file mode 100644 index 00000000..b5f78e71 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/tokens.rb @@ -0,0 +1,164 @@ +module CodeRay + + # The Tokens class represents a list of tokens returned from + # a Scanner. It's actually just an Array with a few helper methods. + # + # A token itself is not a special object, just two elements in an Array: + # * the _token_ _text_ (the original source of the token in a String) or + # a _token_ _action_ (begin_group, end_group, begin_line, end_line) + # * the _token_ _kind_ (a Symbol representing the type of the token) + # + # It looks like this: + # + # ..., '# It looks like this', :comment, ... + # ..., '3.1415926', :float, ... + # ..., '$^', :error, ... + # + # Some scanners also yield sub-tokens, represented by special + # token actions, for example :begin_group and :end_group. + # + # The Ruby scanner, for example, splits "a string" into: + # + # [ + # :begin_group, :string, + # '"', :delimiter, + # 'a string', :content, + # '"', :delimiter, + # :end_group, :string + # ] + # + # Tokens can be used to save the output of a Scanners in a simple + # Ruby object that can be send to an Encoder later: + # + # tokens = CodeRay.scan('price = 2.59', :ruby).tokens + # tokens.encode(:html) + # tokens.html + # CodeRay.encoder(:html).encode_tokens(tokens) + # + # Tokens gives you the power to handle pre-scanned code very easily: + # You can serialize it to a JSON string and store it in a database, pass it + # around to encode it more than once, send it to other algorithms... + class Tokens < Array + # Remove Array#filter that is a new alias for Array#select on Ruby 2.6, + # for method_missing called with filter method. + undef_method :filter if instance_methods.include?(:filter) + + # The Scanner instance that created the tokens. + attr_accessor :scanner + + # Encode the tokens using encoder. + # + # encoder can be + # * a plugin name like :html oder 'statistic' + # * an Encoder object + # + # options are passed to the encoder. + def encode encoder, options = {} + encoder = Encoders[encoder].new options if encoder.respond_to? :to_sym + encoder.encode_tokens self, options + end + + # Turn tokens into a string by concatenating them. + def to_s + encode CodeRay::Encoders::Encoder.new + end + + # Redirects unknown methods to encoder calls. + # + # For example, if you call +tokens.html+, the HTML encoder + # is used to highlight the tokens. + def method_missing meth, options = {} + encode meth, options + rescue PluginHost::PluginNotFound + super + end + + # Split the tokens into parts of the given +sizes+. + # + # The result will be an Array of Tokens objects. The parts have + # the text size specified by the parameter. In addition, each + # part closes all opened tokens. This is useful to insert tokens + # betweem them. + # + # This method is used by @Scanner#tokenize@ when called with an Array + # of source strings. The Diff encoder uses it for inline highlighting. + def split_into_parts *sizes + return Array.new(sizes.size) { Tokens.new } if size == 2 && first == '' + parts = [] + opened = [] + content = nil + part = Tokens.new + part_size = 0 + size = sizes.first + i = 0 + for item in self + case content + when nil + content = item + when String + if size && part_size + content.size > size # token must be cut + if part_size < size # some part of the token goes into this part + content = content.dup # content may no be safe to change + part << content.slice!(0, size - part_size) << item + end + # close all open groups and lines... + closing = opened.reverse.flatten.map do |content_or_kind| + case content_or_kind + when :begin_group + :end_group + when :begin_line + :end_line + else + content_or_kind + end + end + part.concat closing + begin + parts << part + part = Tokens.new + size = sizes[i += 1] + end until size.nil? || size > 0 + # ...and open them again. + part.concat opened.flatten + part_size = 0 + redo unless content.empty? + else + part << content << item + part_size += content.size + end + content = nil + when Symbol + case content + when :begin_group, :begin_line + opened << [content, item] + when :end_group, :end_line + opened.pop + else + raise ArgumentError, 'Unknown token action: %p, kind = %p' % [content, item] + end + part << content << item + content = nil + else + raise ArgumentError, 'Token input junk: %p, kind = %p' % [content, item] + end + end + parts << part + parts << Tokens.new while parts.size < sizes.size + parts + end + + # Return the actual number of tokens. + def count + size / 2 + end + + alias text_token push + def begin_group kind; push :begin_group, kind end + def end_group kind; push :end_group, kind end + def begin_line kind; push :begin_line, kind end + def end_line kind; push :end_line, kind end + alias tokens concat + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/tokens_proxy.rb b/bin/gems/coderay-1.1.3/lib/coderay/tokens_proxy.rb new file mode 100644 index 00000000..31ff39be --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/tokens_proxy.rb @@ -0,0 +1,55 @@ +module CodeRay + + # The result of a scan operation is a TokensProxy, but should act like Tokens. + # + # This proxy makes it possible to use the classic CodeRay.scan.encode API + # while still providing the benefits of direct streaming. + class TokensProxy + + attr_accessor :input, :lang, :options, :block + + # Create a new TokensProxy with the arguments of CodeRay.scan. + def initialize input, lang, options = {}, block = nil + @input = input + @lang = lang + @options = options + @block = block + end + + # Call CodeRay.encode if +encoder+ is a Symbol; + # otherwise, convert the receiver to tokens and call encoder.encode_tokens. + def encode encoder, options = {} + if encoder.respond_to? :to_sym + CodeRay.encode(input, lang, encoder, options) + else + encoder.encode_tokens tokens, options + end + end + + # Tries to call encode; + # delegates to tokens otherwise. + def method_missing method, *args, &blk + encode method.to_sym, *args + rescue PluginHost::PluginNotFound + tokens.send(method, *args, &blk) + end + + # The (cached) result of the tokenized input; a Tokens instance. + def tokens + @tokens ||= scanner.tokenize(input) + end + + # A (cached) scanner instance to use for the scan task. + def scanner + @scanner ||= CodeRay.scanner(lang, options, &block) + end + + # Overwrite Struct#each. + def each *args, &blk + tokens.each(*args, &blk) + self + end + + end + +end diff --git a/bin/gems/coderay-1.1.3/lib/coderay/version.rb b/bin/gems/coderay-1.1.3/lib/coderay/version.rb new file mode 100644 index 00000000..3c68bd83 --- /dev/null +++ b/bin/gems/coderay-1.1.3/lib/coderay/version.rb @@ -0,0 +1,3 @@ +module CodeRay + VERSION = '1.1.3' +end diff --git a/bin/gems/colorator-1.1.0/Gemfile b/bin/gems/colorator-1.1.0/Gemfile new file mode 100644 index 00000000..044fba3b --- /dev/null +++ b/bin/gems/colorator-1.1.0/Gemfile @@ -0,0 +1,11 @@ +source "https://rubygems.org" +gemspec + +gem "rake" +group :development do + gem "rspec-helpers", :require => false + gem "luna-rspec-formatters", :require => false + gem "pry", :require => false unless ENV[ + "CI" + ] +end diff --git a/bin/gems/colorator-1.1.0/History.markdown b/bin/gems/colorator-1.1.0/History.markdown new file mode 100644 index 00000000..bac42704 --- /dev/null +++ b/bin/gems/colorator-1.1.0/History.markdown @@ -0,0 +1,25 @@ +## 1.1.0 / 2016-06-28 + +### Minor Enhancements + +* Support jruby (#8) + +## 1.0.0 / 2016-04-28 + +### Major enhancements + +- Merge Simple::ANSI and Colorator. (#7) + +### Minor Enhancements + +- Delete unnecessary `Symbol#to_sym` (#2) +- Change argument name of `Enumerator#each` for better code legibility (#3) + +### Development Fixes + +- Convert to new RSpec expectation syntax (#1) +- Fix `String#blue` result in README (#4) + +## 0.1 / 2013-04-13 + +Birthday! diff --git a/bin/gems/colorator-1.1.0/LICENSE b/bin/gems/colorator-1.1.0/LICENSE new file mode 100644 index 00000000..b3b6be9a --- /dev/null +++ b/bin/gems/colorator-1.1.0/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) Parker Moore + +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. \ No newline at end of file diff --git a/bin/gems/colorator-1.1.0/README.markdown b/bin/gems/colorator-1.1.0/README.markdown new file mode 100644 index 00000000..9cf886de --- /dev/null +++ b/bin/gems/colorator-1.1.0/README.markdown @@ -0,0 +1,47 @@ +# colorator + +Colorize your text for the terminal + +[![Build Status](https://travis-ci.org/octopress/colorator.png?branch=master)](https://travis-ci.org/octopress/colorator) + +## Example + +```ruby +"this string".red +# => \e[31mthis string\e[0m +"my string".blue +# => \e[34mmy string\e[0m +# etc... +``` + +## Supported Colors + +- `red` +- `black` +- `green` +- `yellow` +- `magenta` +- `white` +- `blue` +- `cyan` +- `bold` + +## Other supported Ansi methods + +- `clear_line` +- `has_ansi?`, `has_color?` +- `strip_ansi`, `strip_color` +- `reset_ansi`, `reset_color` +- `clear_screen` +- `ansi_jump` + +## Why + +There are a bunch of gems that provide functionality like this, but none have +as simple an API as this. Just call `"string".color` and your text will be +colorized. + +## License + +MIT. Written as a single Ruby file by Brandon Mathis, converted into a gem by +Parker Moore. diff --git a/bin/gems/colorator-1.1.0/Rakefile b/bin/gems/colorator-1.1.0/Rakefile new file mode 100644 index 00000000..b7e9ed54 --- /dev/null +++ b/bin/gems/colorator-1.1.0/Rakefile @@ -0,0 +1,6 @@ +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/bin/gems/colorator-1.1.0/colorator.gemspec b/bin/gems/colorator-1.1.0/colorator.gemspec new file mode 100644 index 00000000..a4bd0cd0 --- /dev/null +++ b/bin/gems/colorator-1.1.0/colorator.gemspec @@ -0,0 +1,23 @@ +# coding: utf-8 + +require File.expand_path('lib/colorator.rb', __dir__) + +Gem::Specification.new do |spec| + spec.name = "colorator" + spec.summary = "Colorize your text in the terminal." + spec.version = Colorator::VERSION + spec.authors = ["Parker Moore", "Brandon Mathis"] + spec.email = ["parkrmoore@gmail.com", "brandon@imathis.com"] + spec.homepage = "https://github.com/octopress/colorator" + spec.licenses = ["MIT"] + + all = `git ls-files -z`.split("\x0").reject { |f| f.start_with?(".") } + spec.files = all.select { |f| File.basename(f) == f || f =~ %r{^(bin|lib)/} } + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.extra_rdoc_files = ["README.markdown", "LICENSE"] + spec.rdoc_options = ["--charset=UTF-8"] + + spec.add_development_dependency "rspec", "~> 3.1" +end diff --git a/bin/gems/colorator-1.1.0/lib/colorator.rb b/bin/gems/colorator-1.1.0/lib/colorator.rb new file mode 100644 index 00000000..107f6e3a --- /dev/null +++ b/bin/gems/colorator-1.1.0/lib/colorator.rb @@ -0,0 +1,111 @@ +$:.unshift File.dirname(__FILE__) + +module Colorator + module_function + VERSION = "1.1.0" + + # -------------------------------------------------------------------------- + + ANSI_MATCHR = /\x1b.*?[jkmsuABGKH]/ + ANSI_COLORS = { + :black => 30, + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :magenta => 35, + :cyan => 36, + :white => 37, + :bold => 1 + } + + # -------------------------------------------------------------------------- + # Allows you to check if a string currently has ansi. + # -------------------------------------------------------------------------- + + def has_ansi?(str) + str.match(ANSI_MATCHR).is_a?( + MatchData + ) + end + + # -------------------------------------------------------------------------- + # Jump the cursor, moving it up and then back down to it's spot, allowing + # you to do fancy things like multiple output (downloads) the way that Docker + # does them in an async way without breaking term. + # -------------------------------------------------------------------------- + + def ansi_jump(str, num) + "\x1b[#{num}A#{clear_line(str)}\x1b[#{ + num + }B" + end + + # -------------------------------------------------------------------------- + + def reset_ansi(str = "") + "\x1b[0m#{ + str + }" + end + + # -------------------------------------------------------------------------- + + def clear_line(str = "") + "\x1b[2K\r#{ + str + }" + end + + # -------------------------------------------------------------------------- + # Strip ANSI from the current string, making it just a normal string. + # -------------------------------------------------------------------------- + + def strip_ansi(str) + str.gsub( + ANSI_MATCHR, "" + ) + end + + # -------------------------------------------------------------------------- + # Clear the screen's current view, so the user gets a clean output. + # -------------------------------------------------------------------------- + + def clear_screen(str = "") + "\x1b[H\x1b[2J#{ + str + }" + end + + # -------------------------------------------------------------------------- + + def colorize(str = "", color) + "\x1b[#{color}m#{str}\x1b[0m" + end + + # -------------------------------------------------------------------------- + + Colorator::ANSI_COLORS.each do |color, code| + define_singleton_method color do |str| + colorize( + str, code + ) + end + end + + # -------------------------------------------------------------------------- + + class << self + alias reset_color reset_ansi + alias strip_color strip_ansi + alias has_color? has_ansi? + end + + # -------------------------------------------------------------------------- + + CORE_METHODS = ( + public_methods - Object.methods + ) +end + +require "colorator/core_ext" diff --git a/bin/gems/colorator-1.1.0/lib/colorator/core_ext.rb b/bin/gems/colorator-1.1.0/lib/colorator/core_ext.rb new file mode 100644 index 00000000..f2e0bf0d --- /dev/null +++ b/bin/gems/colorator-1.1.0/lib/colorator/core_ext.rb @@ -0,0 +1,9 @@ +class String + Colorator::CORE_METHODS.each do |method| + define_method method do |*args| + Colorator.public_send(method, + self, *args + ) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/CHANGELOG.md b/bin/gems/concurrent-ruby-1.3.5/CHANGELOG.md new file mode 100644 index 00000000..30810b72 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/CHANGELOG.md @@ -0,0 +1,603 @@ +## Current + +## Release v1.3.5, edge v0.7.2 (15 January 2025) + +concurrent-ruby: + +* (#1062) Remove dependency on logger. + +concurrent-ruby-edge: + +* (#1062) Remove dependency on logger. + +## Release v1.3.4 (10 August 2024) + +* (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1. +* (#1058) Add `Concurrent.cpu_shares` that is cgroups aware. + +## Release v1.3.3 (9 June 2024) + +* (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows. + +## Release v1.3.2, edge v0.7.1 (7 June 2024) + +concurrent-ruby: + +* (#1051) Remove dependency on `win32ole`. + +concurrent-ruby-edge: + +* (#1052) Fix dependency on `concurrent-ruby` to allow the latest release. + +## Release v1.3.1 (29 May 2024) + +* Release 1.3.0 was broken when pushed to RubyGems. 1.3.1 is a packaging fix. + +## Release v1.3.0 (28 May 2024) + +* (#1042) Align Java Executor Service behavior for `shuttingdown?`, `shutdown?` +* (#1038) Add `Concurrent.available_processor_count` that is cgroups aware. + +## Release v1.2.3 (16 Jan 2024) + +* See [the GitHub release](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.2.3) for details. + +## Release v1.2.2 (24 Feb 2023) + +* (#993) Fix arguments passed to `Concurrent::Map`'s `default_proc`. + +## Release v1.2.1 (24 Feb 2023) + +* (#990) Add missing `require 'fiber'` for `FiberLocalVar`. +* (#989) Optimize `Concurrent::Map#[]` on CRuby by letting the backing Hash handle the `default_proc`. + +## Release v1.2.0 (23 Jan 2023) + +* (#962) Fix ReentrantReadWriteLock to use the same granularity for locals as for Mutex it uses. +* (#983) Add FiberLocalVar +* (#934) concurrent-ruby now supports requiring individual classes (public classes listed in the docs), e.g., `require 'concurrent/map'` +* (#976) Let `Promises.any_fulfilled_future` take an `Event` +* Improve documentation of various classes +* (#975) Set the Ruby compatibility version at 2.3 +* (#972) Remove Rubinius-related code + +## Release v1.1.10 (22 Mar 2022) + +concurrent-ruby: + +* (#951) Set the Ruby compatibility version at 2.2 +* (#939, #933) The `caller_runs` fallback policy no longer blocks reads from the job queue by worker threads +* (#938, #761, #652) You can now explicitly `prune_pool` a thread pool (Sylvain Joyeux) +* (#937, #757, #670) We switched the Yahoo stock API for demos to Alpha Vantage (Gustavo Caso) +* (#932, #931) We changed how `SafeTaskExecutor` handles local jump errors (Aaron Jensen) +* (#927) You can use keyword arguments in your initialize when using `Async` (Matt Larraz) +* (#926, #639) We removed timeout from `TimerTask` because it wasn't sound, and now it's a no-op with a warning (Jacob Atzen) +* (#919) If you double-lock a re-entrant read-write lock, we promote to locked for writing (zp yuan) +* (#915) `monotonic_time` now accepts an optional unit parameter, as Ruby's `clock_gettime` (Jean Boussier) + +## Release v1.1.9 (5 Jun 2021) + +concurrent-ruby: + +* (#866) Child promise state not set to :pending immediately after #execute when parent has completed +* (#905, #872) Fix RubyNonConcurrentPriorityQueue#delete method +* (2df0337d) Make sure locks are not shared on shared when objects are dup/cloned +* (#900, #906, #796, #847, #911) Fix Concurrent::Set tread-safety issues on CRuby +* (#907) Add new ConcurrentMap backend for TruffleRuby + +## Release v1.1.8 (20 January 2021) + +concurrent-ruby: + +* (#885) Fix race condition in TVar for stale reads +* (#884) RubyThreadLocalVar: Do not iterate over hash which might conflict with new pair addition + +## Release v1.1.7 (6 August 2020) + +concurrent-ruby: + +* (#879) Consider falsy value on `Concurrent::Map#compute_if_absent` for fast non-blocking path +* (#876) Reset Async queue on forking, makes Async fork-safe +* (#856) Avoid running problematic code in RubyThreadLocalVar on MRI that occasionally results in segfault +* (#853) Introduce ThreadPoolExecutor without a Queue + +## Release v1.1.6, edge v0.6.0 (10 Feb 2020) + +concurrent-ruby: + +* (#841) Concurrent.disable_at_exit_handlers! is no longer needed and was deprecated. +* (#841) AbstractExecutorService#auto_terminate= was deprecated and has no effect. + Set :auto_terminate option instead when executor is initialized. + +## Release v1.1.6.pre1, edge v0.6.0.pre1 (26 Jan 2020) + +concurrent-ruby: + +* (#828) Allow to name executors, the name is also used to name their threads +* (#838) Implement #dup and #clone for structs +* (#821) Safer finalizers for thread local variables +* Documentation fixes +* (#814) Use Ruby's Etc.nprocessors if available +* (#812) Fix directory structure not to mess with packaging tools +* (#840) Fix termination of pools on JRuby + +concurrent-ruby-edge: + +* Add WrappingExecutor (#830) + +## Release v1.1.5, edge v0.5.0 (10 Mar 2019) + +concurrent-ruby: + +* fix potential leak of context on JRuby and Java 7 + +concurrent-ruby-edge: + +* Add finalized Concurrent::Cancellation +* Add finalized Concurrent::Throttle +* Add finalized Concurrent::Promises::Channel +* Add new Concurrent::ErlangActor + +## Release v1.1.4 (14 Dec 2018) + +* (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11 +* (#776) Fix NameError on defining a struct with a name which is already taken in an ancestor + +## Release v1.1.3 (7 Nov 2018) + +* (#775) fix partial require of the gem (although not officially supported) + +## Release v1.1.2 (6 Nov 2018) + +* (#773) more defensive 1.9.3 support + +## Release v1.1.1, edge v0.4.1 (1 Nov 2018) + +* (#768) add support for 1.9.3 back + +## Release v1.1.0, edge v0.4.0 (31 OCt 2018) (yanked) + +* (#768) yanked because of issues with removed 1.9.3 support + +## Release v1.1.0.pre2, edge v0.4.0.pre2 (18 Sep 2018) + +concurrent-ruby: + +* fixed documentation and README links +* fix Set for TruffleRuby and Rubinius +* use properly supported TruffleRuby APIs + +concurrent-ruby-edge: + +* add Promises.zip_futures_over_on + +## Release v1.1.0.pre1, edge v0.4.0.pre1 (15 Aug 2018) + +concurrent-ruby: + +* requires at least Ruby 2.0 +* [Promises](http://ruby-concurrency.github.io/concurrent-ruby/1.1.0/Concurrent/Promises.html) + are moved from `concurrent-ruby-edge` to `concurrent-ruby` +* Add support for TruffleRuby + * (#734) Fix Array/Hash/Set construction broken on TruffleRuby + * AtomicReference fixed +* CI stabilization +* remove sharp dependency edge -> core +* remove warnings +* documentation updates +* Exchanger is no longer documented as edge since it was already available in + `concurrent-ruby` +* (#644) Fix Map#each and #each_pair not returning enumerator outside of MRI +* (#659) Edge promises fail during error handling +* (#741) Raise on recursive Delay#value call +* (#727) #717 fix global IO executor on JRuby +* (#740) Drop support for CRuby 1.9, JRuby 1.7, Rubinius. +* (#737) Move AtomicMarkableReference out of Edge +* (#708) Prefer platform specific memory barriers +* (#735) Fix wrong expected exception in channel spec assertion +* (#729) Allow executor option in `Promise#then` +* (#725) fix timeout check to use timeout_interval +* (#719) update engine detection +* (#660) Add specs for Promise#zip/Promise.zip ordering +* (#654) Promise.zip execution changes +* (#666) Add thread safe set implementation +* (#651) #699 #to_s, #inspect should not output negative object IDs. +* (#685) Avoid RSpec warnings about raise_error +* (#680) Avoid RSpec monkey patching, persist spec results locally, use RSpec + v3.7.0 +* (#665) Initialize the monitor for new subarrays on Rubinius +* (#661) Fix error handling in edge promises + +concurrent-ruby-edge: + +* (#659) Edge promises fail during error handling +* Edge files clearly separated in `lib-edge` +* added ReInclude + +## Release v1.0.5, edge v0.3.1 (26 Feb 2017) + +concurrent-ruby: + +* Documentation for Event and Semaphore +* Use Unsafe#fullFence and #loadFence directly since the shortcuts were removed in JRuby +* Do not depend on org.jruby.util.unsafe.UnsafeHolder + +concurrent-ruby-edge: + +* (#620) Actors on Pool raise an error +* (#624) Delayed promises did not interact correctly with flatting + * Fix arguments yielded by callback methods +* Overridable default executor in promises factory methods +* Asking actor to terminate will always resolve to `true` + +## Release v1.0.4, edge v0.3.0 (27 Dec 2016) + +concurrent-ruby: + +* Nothing + +concurrent-ruby-edge: + +* New promises' API renamed, lots of improvements, edge bumped to 0.3.0 + * **Incompatible** with previous 0.2.3 version + * see https://github.com/ruby-concurrency/concurrent-ruby/pull/522 + +## Release v1.0.3 (17 Dec 2016) + +* Trigger execution of flattened delayed futures +* Avoid forking for processor_count if possible +* Semaphore Mutex and JRuby parity +* Adds Map#each as alias to Map#each_pair +* Fix uninitialized instance variables +* Make Fixnum, Bignum merger ready +* Allows Promise#then to receive an executor +* TimerSet now survives a fork +* Reject promise on any exception +* Allow ThreadLocalVar to be initialized with a block +* Support Alpha with `Concurrent::processor_count` +* Fixes format-security error when compiling ruby_193_compatible.h +* Concurrent::Atom#swap fixed: reraise the exceptions from block + +## Release v1.0.2 (2 May 2016) + +* Fix bug with `Concurrent::Map` MRI backend `#inspect` method +* Fix bug with `Concurrent::Map` MRI backend using `Hash#value?` +* Improved documentation and examples +* Minor updates to Edge + +## Release v1.0.1 (27 February 2016) + +* Fix "uninitialized constant Concurrent::ReentrantReadWriteLock" error. +* Better handling of `autoload` vs. `require`. +* Improved API for Edge `Future` zipping. +* Fix reference leak in Edge `Future` constructor . +* Fix bug which prevented thread pools from surviving a `fork`. +* Fix bug in which `TimerTask` did not correctly specify all its dependencies. +* Improved support for JRuby+Truffle +* Improved error messages. +* Improved documentation. +* Updated README and CONTRIBUTING. + +## Release v1.0.0 (13 November 2015) + +* Rename `attr_volatile_with_cas` to `attr_atomic` +* Add `clear_each` to `LockFreeStack` +* Update `AtomicReference` documentation +* Further updates and improvements to the synchronization layer. +* Performance and memory usage performance with `Actor` logging. +* Fixed `ThreadPoolExecutor` task count methods. +* Improved `Async` performance for both short and long-lived objects. +* Fixed bug in `LockFreeLinkedSet`. +* Fixed bug in which `Agent#await` triggered a validation failure. +* Further `Channel` updates. +* Adopted a project Code of Conduct +* Cleared interpreter warnings +* Fixed bug in `ThreadPoolExecutor` task count methods +* Fixed bug in 'LockFreeLinkedSet' +* Improved Java extension loading +* Handle Exception children in Edge::Future +* Continued improvements to channel +* Removed interpreter warnings. +* Shared constants now in `lib/concurrent/constants.rb` +* Refactored many tests. +* Improved synchronization layer/memory model documentation. +* Bug fix in Edge `Future#flat` +* Brand new `Channel` implementation in Edge gem. +* Simplification of `RubySingleThreadExecutor` +* `Async` improvements + - Each object uses its own `SingleThreadExecutor` instead of the global thread pool. + - No longer supports executor injection + - Much better documentation +* `Atom` updates + - No longer `Dereferenceable` + - Now `Observable` + - Added a `#reset` method +* Brand new `Agent` API and implementation. Now functionally equivalent to Clojure. +* Continued improvements to the synchronization layer +* Merged in the `thread_safe` gem + - `Concurrent::Array` + - `Concurrent::Hash` + - `Concurrent::Map` (formerly ThreadSafe::Cache) + - `Concurrent::Tuple` +* Minor improvements to Concurrent::Map +* Complete rewrite of `Exchanger` +* Removed all deprecated code (classes, methods, constants, etc.) +* Updated Agent, MutexAtomic, and BufferedChannel to inherit from Synchronization::Object. +* Many improved tests +* Some internal reorganization + +## Release v0.9.1 (09 August 2015) + +* Fixed a Rubiniux bug in synchronization object +* Fixed all interpreter warnings (except circular references) +* Fixed require statements when requiring `Atom` alone +* Significantly improved `ThreadLocalVar` on non-JRuby platforms +* Fixed error handling in Edge `Concurrent.zip` +* `AtomicFixnum` methods `#increment` and `#decrement` now support optional delta +* New `AtomicFixnum#update` method +* Minor optimizations in `ReadWriteLock` +* New `ReentrantReadWriteLock` class +* `ThreadLocalVar#bind` method is now public +* Refactored many tests + +## Release v0.9.0 (10 July 2015) + +* Updated `AtomicReference` + - `AtomicReference#try_update` now simply returns instead of raising exception + - `AtomicReference#try_update!` was added to raise exceptions if an update + fails. Note: this is the same behavior as the old `try_update` +* Pure Java implementations of + - `AtomicBoolean` + - `AtomicFixnum` + - `Semaphore` +* Fixed bug when pruning Ruby thread pools +* Fixed bug in time calculations within `ScheduledTask` +* Default `count` in `CountDownLatch` to 1 +* Use monotonic clock for all timers via `Concurrent.monotonic_time` + - Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` when available + - Fallback to `java.lang.System.nanoTime()` on unsupported JRuby versions + - Pure Ruby implementation for everything else + - Effects `Concurrent.timer`, `Concurrent.timeout`, `TimerSet`, `TimerTask`, and `ScheduledTask` +* Deprecated all clock-time based timer scheduling + - Only support scheduling by delay + - Effects `Concurrent.timer`, `TimerSet`, and `ScheduledTask` +* Added new `ReadWriteLock` class +* Consistent `at_exit` behavior for Java and Ruby thread pools. +* Added `at_exit` handler to Ruby thread pools (already in Java thread pools) + - Ruby handler stores the object id and retrieves from `ObjectSpace` + - JRuby disables `ObjectSpace` by default so that handler stores the object reference +* Added a `:stop_on_exit` option to thread pools to enable/disable `at_exit` handler +* Updated thread pool docs to better explain shutting down thread pools +* Simpler `:executor` option syntax for all abstractions which support this option +* Added `Executor#auto_terminate?` predicate method (for thread pools) +* Added `at_exit` handler to `TimerSet` +* Simplified auto-termination of the global executors + - Can now disable auto-termination of global executors + - Added shutdown/kill/wait_for_termination variants for global executors +* Can now disable auto-termination for *all* executors (the nuclear option) +* Simplified auto-termination of the global executors +* Deprecated terms "task pool" and "operation pool" + - New terms are "io executor" and "fast executor" + - New functions added with new names + - Deprecation warnings added to functions referencing old names +* Moved all thread pool related functions from `Concurrent::Configuration` to `Concurrent` + - Old functions still exist with deprecation warnings + - New functions have updated names as appropriate +* All high-level abstractions default to the "io executor" +* Fixed bug in `Actor` causing it to prematurely warm global thread pools on gem load + - This also fixed a `RejectedExecutionError` bug when running with minitest/autorun via JRuby +* Moved global logger up to the `Concurrent` namespace and refactored the code +* Optimized the performance of `Delay` + - Fixed a bug in which no executor option on construction caused block execution on a global thread pool +* Numerous improvements and bug fixes to `TimerSet` +* Fixed deadlock of `Future` when the handler raises Exception +* Added shared specs for more classes +* New concurrency abstractions including: + - `Atom` + - `Maybe` + - `ImmutableStruct` + - `MutableStruct` + - `SettableStruct` +* Created an Edge gem for unstable abstractions including + - `Actor` + - `Agent` + - `Channel` + - `Exchanger` + - `LazyRegister` + - **new Future Framework** - unified + implementation of Futures and Promises which combines Features of previous `Future`, + `Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively + new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`. + It offers better performance and does not block threads when not required. +* Actor framework changes: + - fixed reset loop in Pool + - Pool can use any actor as a worker, abstract worker class is no longer needed. + - Actor events not have format `[:event_name, *payload]` instead of just the Symbol. + - Actor now uses new Future/Promise Framework instead of `IVar` for better interoperability + - Behaviour definition array was simplified to `[BehaviourClass1, [BehaviourClass2, *initialization_args]]` + - Linking behavior responds to :linked message by returning array of linked actors + - Supervised behavior is removed in favour of just Linking + - RestartingContext is supervised by default now, `supervise: true` is not required any more + - Events can be private and public, so far only difference is that Linking will + pass to linked actors only public messages. Adding private :restarting and + :resetting events which are send before the actor restarts or resets allowing + to add callbacks to cleanup current child actors. + - Print also object_id in Reference to_s + - Add AbstractContext#default_executor to be able to override executor class wide + - Add basic IO example + - Documentation somewhat improved + - All messages should have same priority. It's now possible to send `actor << job1 << job2 << :terminate!` and + be sure that both jobs are processed first. +* Refactored `Channel` to use newer synchronization objects +* Added `#reset` and `#cancel` methods to `TimerSet` +* Added `#cancel` method to `Future` and `ScheduledTask` +* Refactored `TimerSet` to use `ScheduledTask` +* Updated `Async` with a factory that initializes the object +* Deprecated `Concurrent.timer` and `Concurrent.timeout` +* Reduced max threads on pure-Ruby thread pools (abends around 14751 threads) +* Moved many private/internal classes/modules into "namespace" modules +* Removed brute-force killing of threads in tests +* Fixed a thread pool bug when the operating system cannot allocate more threads + +## Release v0.8.0 (25 January 2015) + +* C extension for MRI have been extracted into the `concurrent-ruby-ext` companion gem. + Please see the README for more detail. +* Better variable isolation in `Promise` and `Future` via an `:args` option +* Continued to update intermittently failing tests + +## Release v0.7.2 (24 January 2015) + +* New `Semaphore` class based on [java.util.concurrent.Semaphore](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html) +* New `Promise.all?` and `Promise.any?` class methods +* Renamed `:overflow_policy` on thread pools to `:fallback_policy` +* Thread pools still accept the `:overflow_policy` option but display a warning +* Thread pools now implement `fallback_policy` behavior when not running (rather than universally rejecting tasks) +* Fixed minor `set_deref_options` constructor bug in `Promise` class +* Fixed minor `require` bug in `ThreadLocalVar` class +* Fixed race condition bug in `TimerSet` class +* Fixed race condition bug in `TimerSet` class +* Fixed signal bug in `TimerSet#post` method +* Numerous non-functional updates to clear warning when running in debug mode +* Fixed more intermittently failing tests +* Tests now run on new Travis build environment +* Multiple documentation updates + +## Release v0.7.1 (4 December 2014) + +Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/issues/142) for more information on the next planned release. + +* Added `flat_map` method to `Promise` +* Added `zip` method to `Promise` +* Fixed bug with logging in `Actor` +* Improvements to `Promise` tests +* Removed actor-experimental warning +* Added an `IndirectImmediateExecutor` class +* Allow disabling auto termination of global executors +* Fix thread leaking in `ThreadLocalVar` (uses `Ref` gem on non-JRuby systems) +* Fix thread leaking when pruning pure-Ruby thread pools +* Prevent `Actor` from using an `ImmediateExecutor` (causes deadlock) +* Added missing synchronizations to `TimerSet` +* Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask` +* Fixed timing bug in `TimerTask` +* Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero +* Removed confusing warning when not using native extensions +* Improved documentation + +## Release v0.7.0 (13 August 2014) + +* Merge the [atomic](https://github.com/ruby-concurrency/atomic) gem + - Pure Ruby `MutexAtomic` atomic reference class + - Platform native atomic reference classes `CAtomic`, `JavaAtomic`, and `RbxAtomic` + - Automated [build process](https://github.com/ruby-concurrency/rake-compiler-dev-box) + - Fat binary releases for [multiple platforms](https://rubygems.org/gems/concurrent-ruby/versions) including Windows (32/64), Linux (32/64), OS X (64-bit), Solaris (64-bit), and JRuby +* C native `CAtomicBoolean` +* C native `CAtomicFixnum` +* Refactored intermittently failing tests +* Added `dataflow!` and `dataflow_with!` methods to match `Future#value!` method +* Better handling of timeout in `Agent` +* Actor Improvements + - Fine-grained implementation using chain of behaviors. Each behavior is responsible for single aspect like: `Termination`, `Pausing`, `Linking`, `Supervising`, etc. Users can create custom Actors easily based on their needs. + - Supervision was added. `RestartingContext` will pause on error waiting on its supervisor to decide what to do next ( options are `:terminate!`, `:resume!`, `:reset!`, `:restart!`). Supervising behavior also supports strategies `:one_for_one` and `:one_for_all`. + - Linking was added to be able to monitor actor's events like: `:terminated`, `:paused`, `:restarted`, etc. + - Dead letter routing added. Rejected envelopes are collected in a configurable actor (default: `Concurrent::Actor.root.ask!(:dead_letter_routing)`) + - Old `Actor` class removed and replaced by new implementation previously called `Actress`. `Actress` was kept as an alias for `Actor` to keep compatibility. + - `Utils::Broadcast` actor which allows Publish–subscribe pattern. +* More executors for managing serialized operations + - `SerializedExecution` mixin module + - `SerializedExecutionDelegator` for serializing *any* executor +* Updated `Async` with serialized execution +* Updated `ImmediateExecutor` and `PerThreadExecutor` with full executor service lifecycle +* Added a `Delay` to root `Actress` initialization +* Minor bug fixes to thread pools +* Refactored many intermittently failing specs +* Removed Java interop warning `executor.rb:148 warning: ambiguous Java methods found, using submit(java.lang.Runnable)` +* Fixed minor bug in `RubyCachedThreadPool` overflow policy +* Updated tests to use [RSpec 3.0](http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3) +* Removed deprecated `Actor` class +* Better support for Rubinius + +## Release v0.6.1 (14 June 2014) + +* Many improvements to `Concurrent::Actress` +* Bug fixes to `Concurrent::RubyThreadPoolExecutor` +* Fixed several brittle tests +* Moved documentation to http://ruby-concurrency.github.io/concurrent-ruby/frames.html + +## Release v0.6.0 (25 May 2014) + +* Added `Concurrent::Observable` to encapsulate our thread safe observer sets +* Improvements to new `Channel` +* Major improvements to `CachedThreadPool` and `FixedThreadPool` +* Added `SingleThreadExecutor` +* Added `Current::timer` function +* Added `TimerSet` executor +* Added `AtomicBoolean` +* `ScheduledTask` refactoring +* Pure Ruby and JRuby-optimized `PriorityQueue` classes +* Updated `Agent` behavior to more closely match Clojure +* Observer sets support block callbacks to the `add_observer` method +* New algorithm for thread creation in `RubyThreadPoolExecutor` +* Minor API updates to `Event` +* Rewritten `TimerTask` now an `Executor` instead of a `Runnable` +* Fixed many brittle specs +* Renamed `FixedThreadPool` and `CachedThreadPool` to `RubyFixedThreadPool` and `RubyCachedThreadPool` +* Created JRuby optimized `JavaFixedThreadPool` and `JavaCachedThreadPool` +* Consolidated fixed thread pool tests into `spec/concurrent/fixed_thread_pool_shared.rb` and `spec/concurrent/cached_thread_pool_shared.rb` +* `FixedThreadPool` now subclasses `RubyFixedThreadPool` or `JavaFixedThreadPool` as appropriate +* `CachedThreadPool` now subclasses `RubyCachedThreadPool` or `JavaCachedThreadPool` as appropriate +* New `Delay` class +* `Concurrent::processor_count` helper function +* New `Async` module +* Renamed `NullThreadPool` to `PerThreadExecutor` +* Deprecated `Channel` (we are planning a new implementation based on [Go](http://golangtutorials.blogspot.com/2011/06/channels-in-go.html)) +* Added gem-level [configuration](http://robots.thoughtbot.com/mygem-configure-block) +* Deprecated `$GLOBAL_THREAD_POOL` in lieu of gem-level configuration +* Removed support for Ruby [1.9.2](https://www.ruby-lang.org/en/news/2013/12/17/maintenance-of-1-8-7-and-1-9-2/) +* New `RubyThreadPoolExecutor` and `JavaThreadPoolExecutor` classes +* All thread pools now extend the appropriate thread pool executor classes +* All thread pools now support `:overflow_policy` (based on Java's [reject policies](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html)) +* Deprecated `UsesGlobalThreadPool` in lieu of explicit `:executor` option (dependency injection) on `Future`, `Promise`, and `Agent` +* Added `Concurrent::dataflow_with(executor, *inputs)` method to support executor dependency injection for dataflow +* Software transactional memory with `TVar` and `Concurrent::atomically` +* First implementation of [new, high-performance](https://github.com/ruby-concurrency/concurrent-ruby/pull/49) `Channel` +* `Actor` is deprecated in favor of new experimental actor implementation [#73](https://github.com/ruby-concurrency/concurrent-ruby/pull/73). To avoid namespace collision it is living in `Actress` namespace until `Actor` is removed in next release. + +## Release v0.5.0 + +This is the most significant release of this gem since its inception. This release includes many improvements and optimizations. It also includes several bug fixes. The major areas of focus for this release were: + +* Stability improvements on Ruby versions with thread-level parallelism ([JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) +* Creation of new low-level concurrency abstractions +* Internal refactoring to use the new low-level abstractions + +Most of these updates had no effect on the gem API. There are a few notable exceptions which were unavoidable. Please read the [release notes](API-Updates-in-v0.5.0) for more information. + +Specific changes include: + +* New class `IVar` +* New class `MVar` +* New class `ThreadLocalVar` +* New class `AtomicFixnum` +* New class method `dataflow` +* New class `Condition` +* New class `CountDownLatch` +* New class `DependencyCounter` +* New class `SafeTaskExecutor` +* New class `CopyOnNotifyObserverSet` +* New class `CopyOnWriteObserverSet` +* `Future` updated with `execute` API +* `ScheduledTask` updated with `execute` API +* New `Promise` API +* `Future` now extends `IVar` +* `Postable#post?` now returns an `IVar` +* Thread safety fixes to `Dereferenceable` +* Thread safety fixes to `Obligation` +* Thread safety fixes to `Supervisor` +* Thread safety fixes to `Event` +* Various other thread safety (race condition) fixes +* Refactored brittle tests +* Implemented pending tests +* Added JRuby and Rubinius as Travis CI build targets +* Added [CodeClimate](https://codeclimate.com/) code review +* Improved YARD documentation diff --git a/bin/gems/concurrent-ruby-1.3.5/Gemfile b/bin/gems/concurrent-ruby-1.3.5/Gemfile new file mode 100644 index 00000000..1786c8b2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/Gemfile @@ -0,0 +1,36 @@ +source 'https://rubygems.org' + +version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise +edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise + +no_path = ENV['NO_PATH'] +options = no_path ? {} : { path: '.' } + +gem 'concurrent-ruby', version, options +gem 'concurrent-ruby-edge', edge_version, options +gem 'concurrent-ruby-ext', version, options.merge(platform: :mri) + +group :development do + gem 'rake', '~> 13.0' + gem 'rake-compiler', '~> 1.0', '>= 1.0.7', '!= 1.2.4' + gem 'rake-compiler-dock', '~> 1.0' + gem 'pry', '~> 0.11', platforms: :mri +end + +group :documentation, optional: true do + gem 'yard', '~> 0.9.0', require: false + gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown + gem 'md-ruby-eval', '~> 0.6' +end + +group :testing do + gem 'rspec', '~> 3.7' + gem 'timecop', '~> 0.9' + gem 'sigdump', require: false +end + +# made opt-in since it will not install on jruby 1.7 +group :coverage, optional: !ENV['COVERAGE'] do + gem 'simplecov', '~> 0.16.0', require: false + gem 'coveralls', '~> 0.8.2', require: false +end diff --git a/bin/gems/concurrent-ruby-1.3.5/LICENSE.txt b/bin/gems/concurrent-ruby-1.3.5/LICENSE.txt new file mode 100644 index 00000000..1026f28d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) Jerry D'Antonio -- released under the MIT license. + +http://www.opensource.org/licenses/mit-license.php + +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/bin/gems/concurrent-ruby-1.3.5/README.md b/bin/gems/concurrent-ruby-1.3.5/README.md new file mode 100644 index 00000000..63ee743c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/README.md @@ -0,0 +1,407 @@ +# Concurrent Ruby + +[![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) +[![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) +[![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby) + +Modern concurrency tools for Ruby. Inspired by +[Erlang](http://www.erlang.org/doc/reference_manual/processes.html), +[Clojure](http://clojure.org/concurrent_programming), +[Scala](http://akka.io/), +[Haskell](http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell), +[F#](http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx), +[C#](http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx), +[Java](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html), +and classic concurrency patterns. + + + +The design goals of this gem are: + +* Be an 'unopinionated' toolbox that provides useful utilities without debating which is better + or why +* Remain free of external gem dependencies +* Stay true to the spirit of the languages providing inspiration +* But implement in a way that makes sense for Ruby +* Keep the semantics as idiomatic Ruby as possible +* Support features that make sense in Ruby +* Exclude features that don't make sense in Ruby +* Be small, lean, and loosely coupled +* Thread-safety +* Backward compatibility + +## Contributing + +**This gem depends on +[contributions](https://github.com/ruby-concurrency/concurrent-ruby/graphs/contributors) and we +appreciate your help. Would you like to contribute? Great! Have a look at +[issues with `looking-for-contributor` label](https://github.com/ruby-concurrency/concurrent-ruby/issues?q=is%3Aissue+is%3Aopen+label%3Alooking-for-contributor).** And if you pick something up let us know on the issue. + +You can also get started by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to concurrent-ruby on CodeTriage](https://www.codetriage.com/ruby-concurrency/concurrent-ruby). [![Open Source Helpers](https://www.codetriage.com/ruby-concurrency/concurrent-ruby/badges/users.svg)](https://www.codetriage.com/ruby-concurrency/concurrent-ruby) + +## Thread Safety + +*Concurrent Ruby makes one of the strongest thread safety guarantees of any Ruby concurrency +library, providing consistent behavior and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby).* + +Every abstraction in this library is thread safe. Specific thread safety guarantees are documented +with each abstraction. + +It is critical to remember, however, that Ruby is a language of mutable references. *No* +concurrency library for Ruby can ever prevent the user from making thread safety mistakes (such as +sharing a mutable object between threads and modifying it on both threads) or from creating +deadlocks through incorrect use of locks. All the library can do is provide safe abstractions which +encourage safe practices. Concurrent Ruby provides more safe concurrency abstractions than any +other Ruby library, many of which support the mantra of +["Do not communicate by sharing memory; instead, share memory by communicating"](https://blog.golang.org/share-memory-by-communicating). +Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and +immutable variable types and data structures. + +We've also initiated discussion to document the [memory model](docs-source/synchronization.md) of Ruby which +would provide consistent behaviour and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby). + +## Features & Documentation + +**The primary site for documentation is the automatically generated +[API documentation](http://ruby-concurrency.github.io/concurrent-ruby/index.html) which is up to +date with latest release.** This readme matches the master so may contain new stuff not yet +released. + +We also have a [IRC (gitter)](https://gitter.im/ruby-concurrency/concurrent-ruby). + +### Versioning + +* `concurrent-ruby` uses [Semantic Versioning](http://semver.org/) +* `concurrent-ruby-ext` has always same version as `concurrent-ruby` +* `concurrent-ruby-edge` will always be 0.y.z therefore following + [point 4](http://semver.org/#spec-item-4) applies *"Major version zero + (0.y.z) is for initial development. Anything may change at any time. The + public API should not be considered stable."* However we additionally use + following rules: + * Minor version increment means incompatible changes were made + * Patch version increment means only compatible changes were made + + +#### General-purpose Concurrency Abstractions + +* [Async](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Async.html): + A mixin module that provides simple asynchronous behavior to a class. Loosely based on Erlang's + [gen_server](http://www.erlang.org/doc/man/gen_server.html). +* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ScheduledTask.html): + Like a Future scheduled for a specific future time. +* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/TimerTask.html): + A Thread that periodically wakes up to perform work at regular intervals. +* [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html): + Unified implementation of futures and promises which combines features of previous `Future`, + `Promise`, `IVar`, `Event`, `dataflow`, `Delay`, and (partially) `TimerTask` into a single + framework. It extensively uses the new synchronization layer to make all the features + **non-blocking** and **lock-free**, with the exception of obviously blocking operations like + `#wait`, `#value`. It also offers better performance. + +#### Thread-safe Value Objects, Structures, and Collections + +Collection classes that were originally part of the (deprecated) `thread_safe` gem: + +* [Array](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Array.html) A thread-safe + subclass of Ruby's standard [Array](http://ruby-doc.org/core/Array.html). +* [Hash](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Hash.html) A thread-safe + subclass of Ruby's standard [Hash](http://ruby-doc.org/core/Hash.html). +* [Set](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Set.html) A thread-safe + subclass of Ruby's standard [Set](http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html). +* [Map](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Map.html) A hash-like object + that should have much better performance characteristics, especially under high concurrency, + than `Concurrent::Hash`. +* [Tuple](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Tuple.html) A fixed size + array with volatile (synchronized, thread safe) getters/setters. + +Value objects inspired by other languages: + +* [Maybe](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Maybe.html) A thread-safe, + immutable object representing an optional value, based on + [Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html). + +Structure classes derived from Ruby's [Struct](http://ruby-doc.org/core/Struct.html): + +* [ImmutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ImmutableStruct.html) + Immutable struct where values are set at construction and cannot be changed later. +* [MutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/MutableStruct.html) + Synchronized, mutable struct where values can be safely changed at any time. +* [SettableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/SettableStruct.html) + Synchronized, write-once struct where values can be set at most once, either at construction + or any time thereafter. + +Thread-safe variables: + +* [Agent](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Agent.html): A way to + manage shared, mutable, *asynchronous*, independent state. Based on Clojure's + [Agent](http://clojure.org/agents). +* [Atom](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Atom.html): A way to manage + shared, mutable, *synchronous*, independent state. Based on Clojure's + [Atom](http://clojure.org/atoms). +* [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicBoolean.html) + A boolean value that can be updated atomically. +* [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicFixnum.html) + A numeric value that can be updated atomically. +* [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicReference.html) + An object reference that may be updated atomically. +* [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Exchanger.html) + A synchronization point at which threads can pair and swap elements within pairs. Based on + Java's [Exchanger](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html). +* [MVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/MVar.html) A synchronized + single element container. Based on Haskell's + [MVar](https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Concurrent-MVar.html) and + Scala's [MVar](http://docs.typelevel.org/api/scalaz/nightly/index.html#scalaz.concurrent.MVar$). +* [ThreadLocalVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ThreadLocalVar.html) + A variable where the value is different for each thread. +* [TVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/TVar.html) A transactional + variable implementing software transactional memory (STM). Based on Clojure's + [Ref](http://clojure.org/refs). + +#### Java-inspired ThreadPools and Other Executors + +* See the [thread pool](http://ruby-concurrency.github.io/concurrent-ruby/master/file.thread_pools.html) + overview, which also contains a list of other Executors available. + +#### Thread Synchronization Classes and Algorithms + +* [CountDownLatch](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/CountDownLatch.html) + A synchronization object that allows one thread to wait on multiple other threads. +* [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/CyclicBarrier.html) + A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. +* [Event](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Event.html) Old school + kernel-style event. +* [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ReadWriteLock.html) + A lock that supports multiple readers but only one writer. +* [ReentrantReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ReentrantReadWriteLock.html) + A read/write lock with reentrant and upgrade features. +* [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Semaphore.html) + A counting-based locking mechanism that uses permits. +* [AtomicMarkableReference](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicMarkableReference.html) + +#### Deprecated + +Deprecated features are still available and bugs are being fixed, but new features will not be added. + +* ~~[Future](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Future.html): + An asynchronous operation that produces a value.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). + * ~~[.dataflow](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#dataflow-class_method): + Built on Futures, Dataflow allows you to create a task that will be scheduled when all of + its data dependencies are available.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[Promise](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promise.html): Similar + to Futures, with more features.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[Delay](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Delay.html) Lazy evaluation + of a block yielding an immutable result. Based on Clojure's + [delay](https://clojuredocs.org/clojure.core/delay).~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[IVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/IVar.html) Similar to a + "future" but can be manually assigned once, after which it becomes immutable.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). + +### Edge Features + +These are available in the `concurrent-ruby-edge` companion gem. + +These features are under active development and may change frequently. They are expected not to +keep backward compatibility (there may also lack tests and documentation). Semantic versions will +be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to +`concurrent-ruby` when final. + +* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Actor.html): Implements + the Actor Model, where concurrent actors exchange messages. + *Status: Partial documentation and tests; depends on new future/promise framework; stability is good.* +* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Channel.html): + Communicating Sequential Processes ([CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes)). + Functionally equivalent to Go [channels](https://tour.golang.org/concurrency/2) with additional + inspiration from Clojure [core.async](https://clojure.github.io/core.async/). + *Status: Partial documentation and tests.* +* [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LazyRegister.html) +* [LockFreeLinkedSet](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Edge/LockFreeLinkedSet.html) + *Status: will be moved to core soon.* +* [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LockFreeStack.html) + *Status: missing documentation and tests.* +* [Promises::Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises/Channel.html) + A first in first out channel that accepts messages with push family of methods and returns + messages with pop family of methods. + Pop and push operations can be represented as futures, see `#pop_op` and `#push_op`. + The capacity of the channel can be limited to support back pressure, use capacity option in `#initialize`. + `#pop` method blocks ans `#pop_op` returns pending future if there is no message in the channel. + If the capacity is limited the `#push` method blocks and `#push_op` returns pending future. +* [Cancellation](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Cancellation.html) + The Cancellation abstraction provides cooperative cancellation. + + The standard methods `Thread#raise` of `Thread#kill` available in Ruby + are very dangerous (see linked the blog posts bellow). + Therefore concurrent-ruby provides an alternative. + + * + * + * + + It provides an object which represents a task which can be executed, + the task has to get the reference to the object and periodically cooperatively check that it is not cancelled. + Good practices to make tasks cancellable: + * check cancellation every cycle of a loop which does significant work, + * do all blocking actions in a loop with a timeout then on timeout check cancellation + and if ok block again with the timeout +* [Throttle](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Throttle.html) + A tool managing concurrency level of tasks. +* [ErlangActor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ErlangActor.html) + Actor implementation which precisely matches Erlang actor behaviour. + Requires at least Ruby 2.1 otherwise it's not loaded. +* [WrappingExecutor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/WrappingExecutor.html) + A delegating executor which modifies each task before the task is given to + the target executor it delegates to. + +## Supported Ruby versions + +* MRI 2.3 and above +* Latest JRuby 9000 +* Latest TruffleRuby + +## Usage + +Everything within this gem can be loaded simply by requiring it: + +```ruby +require 'concurrent' +``` + +You can also require a specific abstraction [part of the public documentation](https://ruby-concurrency.github.io/concurrent-ruby/master/index.html) since concurrent-ruby 1.2.0, for example: +```ruby +require 'concurrent/map' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/executor/fixed_thread_pool' +``` + +To use the tools in the Edge gem it must be required separately: + +```ruby +require 'concurrent-edge' +``` + +If the library does not behave as expected, `Concurrent.use_simple_logger(:DEBUG)` could +help to reveal the problem. + +## Installation + +```shell +gem install concurrent-ruby +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby', require: 'concurrent' +``` + +and run `bundle install` from your shell. + +### Edge Gem Installation + +The Edge gem must be installed separately from the core gem: + +```shell +gem install concurrent-ruby-edge +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby-edge', require: 'concurrent-edge' +``` + +and run `bundle install` from your shell. + + +### C Extensions for MRI + +Potential performance improvements may be achieved under MRI by installing optional C extensions. +To minimise installation errors the C extensions are available in the `concurrent-ruby-ext` +extension gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same +version. Simply install the extension gem too: + +```ruby +gem install concurrent-ruby-ext +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby-ext' +``` + +and run `bundle install` from your shell. + +In code it is only necessary to + +```ruby +require 'concurrent' +``` + +The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem +and load the appropriate C extensions. + +#### Note For gem developers + +No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The +best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions. + +## Building the gem + +### Requirements + +* Recent CRuby +* JRuby, `rbenv install jruby-9.2.17.0` +* Set env variable `CONCURRENT_JRUBY_HOME` to point to it, e.g. `/usr/local/opt/rbenv/versions/jruby-9.2.17.0` +* Install Docker, required for Windows builds + +### Publishing the Gem + +* Update `version.rb` +* Update the CHANGELOG +* Add the new version to `docs-source/signpost.md`. Needs to be done only if there are visible changes in the documentation. +* Commit (and push) the changes. +* Use `bundle exec rake release` to release the gem. + It consists of `['release:checks', 'release:build', 'release:test', 'release:publish']` steps. + It will ask at the end before publishing anything. Steps can also be executed individually. + +## Maintainers + +* [Benoit Daloze](https://github.com/eregon) +* [Matthew Draper](https://github.com/matthewd) +* [Rafael França](https://github.com/rafaelfranca) +* [Charles Oliver Nutter](https://github.com/headius) +* [Ben Sheldon](https://github.com/bensheldon) +* [Samuel Williams](https://github.com/ioquatix) + +### Special Thanks to + +* [Jerry D'Antonio](https://github.com/jdantonio) for creating the gem +* [Brian Durand](https://github.com/bdurand) for the `ref` gem +* [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems +* [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem + +to the past maintainers + +* [Chris Seaton](https://github.com/chrisseaton) +* [Petr Chalupa](https://github.com/pitr-ch) +* [Michele Della Torre](https://github.com/mighe) +* [Paweł Obrok](https://github.com/obrok) +* [Lucas Allan](https://github.com/lucasallan) + +and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project +["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018. + +## License and Copyright + +*Concurrent Ruby* is free software released under the +[MIT License](http://www.opensource.org/licenses/MIT). + +The *Concurrent Ruby* [logo](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/docs-source/logo/concurrent-ruby-logo-300x300.png) was +designed by [David Jones](https://twitter.com/zombyboy). It is Copyright © 2014 +[Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved. diff --git a/bin/gems/concurrent-ruby-1.3.5/Rakefile b/bin/gems/concurrent-ruby-1.3.5/Rakefile new file mode 100644 index 00000000..3d157d47 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/Rakefile @@ -0,0 +1,344 @@ +version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise +edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise + +core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec') +ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec') +edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.gemspec') + +require 'rake/javaextensiontask' + +ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && RUBY_ENGINE != 'jruby' + +Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext| + ext.ext_dir = 'ext/concurrent-ruby' + ext.lib_dir = 'lib/concurrent-ruby/concurrent' + ext.source_version = '8' + ext.target_version = '8' +end + +if RUBY_ENGINE == 'ruby' + require 'rake/extensiontask' + + Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext| + ext.ext_dir = 'ext/concurrent-ruby-ext' + ext.lib_dir = 'lib/concurrent-ruby/concurrent' + ext.source_pattern = '*.{c,h}' + + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] + end +end + +def which?(executable) + !`which #{executable} 2>/dev/null`.empty? +end + +require 'rake_compiler_dock' +namespace :repackage do + desc '* with Windows fat distributions' + task :all do + Dir.chdir(__dir__) do + # store gems in vendor cache for docker + Bundler.with_original_env do + sh 'bundle package' + end + + # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem + Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke + + # build all gem files + rack_compiler_dock_kwargs = {} + if which?('podman') and (!which?('docker') || `docker --version`.include?('podman')) + # podman and only podman available, so RakeCompilerDock will use podman, otherwise it uses docker + rack_compiler_dock_kwargs = { + options: ['--privileged'], # otherwise the directory in the image is empty + runas: false + } + end + %w[x86-mingw32 x64-mingw32].each do |plat| + RakeCompilerDock.sh( + "bundle install --local && bundle exec rake native:#{plat} gem --trace", + platform: plat, + **rack_compiler_dock_kwargs) + end + end + end +end + +require 'rubygems' +require 'rubygems/package_task' + +Gem::PackageTask.new(core_gemspec) {} if core_gemspec +Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby' +Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec + +CLEAN.include( + 'lib/concurrent-ruby/concurrent/concurrent_ruby_ext.*', + 'lib/concurrent-ruby/concurrent/2.*', + 'lib/concurrent-ruby/concurrent/*.jar') + +begin + require 'rspec' + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec) + + namespace :spec do + desc '* Configured for ci' + RSpec::Core::RakeTask.new(:ci) do |t| + options = %w[ --color + --backtrace + --order defined + --format documentation ] + t.rspec_opts = [*options].join(' ') + end + + desc '* test packaged and installed gems instead of local files' + task :installed do + Bundler.with_original_env do + Dir.chdir(__dir__) do + sh "gem install pkg/concurrent-ruby-#{version}.gem" + sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby' + sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem" + ENV['NO_PATH'] = 'true' + sh 'bundle update' + sh 'bundle exec rake spec:ci' + end + end + end + end + + desc 'executed in CI' + task :ci => [:compile, 'spec:ci'] + + desc 'run each spec file in a separate process to help find missing requires' + task 'spec:isolated' do + glob = "#{ENV['DIR'] || 'spec'}/**/*_spec.rb" + from = ENV['FROM'] + env = { 'ISOLATED' => 'true' } + Dir[glob].each do |spec| + next if from and from != spec + from = nil if from == spec + + sh env, 'rspec', spec + end + end + + task :default => [:clobber, :compile, :spec] +rescue LoadError => e + puts 'RSpec is not installed, skipping test task definitions: ' + e.message +end + +current_yard_version_name = version + +begin + require 'yard' + require 'md_ruby_eval' + require_relative 'support/yard_full_types' + + common_yard_options = ['--no-yardopts', + '--no-document', + '--no-private', + '--embed-mixins', + '--markup', 'markdown', + '--title', 'Concurrent Ruby', + '--template', 'default', + '--template-path', 'yard-template', + '--default-return', 'undocumented'] + + desc 'Generate YARD Documentation (signpost, master)' + task :yard => ['yard:signpost', 'yard:master'] + + namespace :yard do + + desc '* eval markdown files' + task :eval_md do + Dir.chdir File.join(__dir__, 'docs-source') do + sh 'bundle exec md-ruby-eval --auto' + end + end + + task :update_readme do + Dir.chdir __dir__ do + content = File.read(File.join('README.md')). + gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_| + case $1 + when 'LockFreeLinkedSet' + "{Concurrent::Edge::#{$1} #{$1}}" + when '.dataflow' + '{Concurrent.dataflow Concurrent.dataflow}' + when 'thread pool' + '{file:thread_pools.md thread pool}' + else + "{Concurrent::#{$1} #{$1}}" + end + end + FileUtils.mkpath 'tmp' + File.write 'tmp/README.md', content + end + end + + define_yard_task = -> name do + output_dir = "docs/#{name}" + + removal_name = "remove.#{name}" + task removal_name do + Dir.chdir __dir__ do + FileUtils.rm_rf output_dir + end + end + + desc "* of #{name} into subdir #{name}" + YARD::Rake::YardocTask.new(name) do |yard| + yard.options.push( + '--output-dir', output_dir, + '--main', 'tmp/README.md', + *common_yard_options) + yard.files = ['./lib/concurrent-ruby/**/*.rb', + './lib/concurrent-ruby-edge/**/*.rb', + './ext/concurrent_ruby_ext/**/*.c', + '-', + 'docs-source/thread_pools.md', + 'docs-source/promises.out.md', + 'docs-source/medium-example.out.rb', + 'LICENSE.txt', + 'CHANGELOG.md'] + end + Rake::Task[name].prerequisites.push removal_name, + # 'yard:eval_md', + 'yard:update_readme' + end + + define_yard_task.call current_yard_version_name + define_yard_task.call 'master' + + desc "* signpost for versions" + YARD::Rake::YardocTask.new(:signpost) do |yard| + yard.options.push( + '--output-dir', 'docs', + '--main', 'docs-source/signpost.md', + *common_yard_options) + yard.files = ['no-lib'] + end + end + +rescue LoadError => e + puts 'YARD is not installed, skipping documentation task definitions: ' + e.message +end + +desc 'build, test, and publish the gem' +task :release => ['release:checks', 'release:build', 'release:test', 'release:publish'] + +namespace :release do + # Depends on environment of @pitr-ch + + task :checks do + raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME'] + + Dir.chdir(__dir__) do + sh 'test -z "$(git status --porcelain)"' do |ok, res| + unless ok + begin + status = `git status --porcelain` + STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + end + end + sh 'git fetch' + sh 'test $(git show-ref --verify --hash refs/heads/master) = ' + + '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res| + unless ok + begin + STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + end + end + end + end + + desc '* build all *.gem files necessary for release' + task :build => [:clobber, 'repackage:all'] + + desc '* test actual installed gems instead of cloned repository on MRI and JRuby' + task :test do + raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME'] + + Dir.chdir(__dir__) do + puts "Testing with the installed gem" + + Bundler.with_original_env do + sh 'ruby -v' + sh 'bundle install' + sh 'bundle exec rake spec:installed' + + env = { "PATH" => "#{ENV.fetch('CONCURRENT_JRUBY_HOME')}/bin:#{ENV['PATH']}" } + sh env, 'ruby -v' + sh env, 'bundle install' + sh env, 'bundle exec rake spec:installed' + end + + puts 'Windows build is untested' + end + end + + desc '* do all nested steps' + task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps'] + + namespace :publish do + publish_base = nil + publish_edge = nil + + task :ask do + begin + STDOUT.puts 'Do you want to publish anything now? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + + begin + STDOUT.puts 'Do you want to publish `concurrent-ruby`? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + publish_base = input == 'y' + + begin + STDOUT.puts 'Do you want to publish `concurrent-ruby-edge`? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + publish_edge = input == 'y' + end + + desc '** tag HEAD with current version and push to github' + task :tag => :ask do + Dir.chdir(__dir__) do + sh "git tag v#{version}" if publish_base + sh "git push origin v#{version}" if publish_base + sh "git tag edge-v#{edge_version}" if publish_edge + sh "git push origin edge-v#{edge_version}" if publish_edge + end + end + + desc '** push all *.gem files to rubygems' + task :rubygems => :ask do + Dir.chdir(__dir__) do + sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base + sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge + sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base + sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base + sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base + end + end + + desc '** print post release steps' + task :post_steps do + # TODO: (petr 05-Jun-2021) automate and renew the process + puts 'Manually: create a release on GitHub with relevant changelog part' + puts 'Manually: send email same as release with relevant changelog part' + puts 'Manually: tweet' + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/ConcurrentRubyService.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/ConcurrentRubyService.java new file mode 100644 index 00000000..fb6be96d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/ConcurrentRubyService.java @@ -0,0 +1,17 @@ +import org.jruby.Ruby; +import org.jruby.runtime.load.BasicLibraryService; + +import java.io.IOException; + +public class ConcurrentRubyService implements BasicLibraryService { + + public boolean basicLoad(final Ruby runtime) throws IOException { + new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaSemaphoreLibrary().load(runtime, false); + new com.concurrent_ruby.ext.SynchronizationLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JRubyMapBackendLibrary().load(runtime, false); + return true; + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java new file mode 100644 index 00000000..dfa9e770 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java @@ -0,0 +1,175 @@ +package com.concurrent_ruby.ext; + +import java.lang.reflect.Field; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +/** + * This library adds an atomic reference type to JRuby for use in the atomic + * library. We do a native version to avoid the implicit value coercion that + * normally happens through JI. + * + * @author headius + */ +public class AtomicReferenceLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + try { + sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class); + atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR); + } catch (Exception e) { + // leave it as Java 6/7 version + } + atomicCls.defineAnnotatedMethods(JRubyReference.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference(runtime, klazz); + } + }; + + private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference8(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyReference", parent="Object") + public static class JRubyReference extends RubyObject { + volatile IRubyObject reference; + + static final sun.misc.Unsafe UNSAFE; + static final long referenceOffset; + + static { + try { + UNSAFE = UnsafeHolder.U; + Class k = JRubyReference.class; + referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference")); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public JRubyReference(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + UNSAFE.putObject(this, referenceOffset, context.nil); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + UNSAFE.putObject(this, referenceOffset, value); + return context.nil; + } + + @JRubyMethod(name = {"get", "value"}) + public IRubyObject get() { + return reference; + } + + @JRubyMethod(name = {"set", "value="}) + public IRubyObject set(IRubyObject newValue) { + UNSAFE.putObjectVolatile(this, referenceOffset, newValue); + return newValue; + } + + @JRubyMethod(name = {"compare_and_set", "compare_and_swap"}) + public IRubyObject compare_and_set(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { + Ruby runtime = context.runtime; + + if (expectedValue instanceof RubyNumeric) { + // numerics are not always idempotent in Ruby, so we need to do slower logic + return compareAndSetNumeric(context, expectedValue, newValue); + } + + return runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, expectedValue, newValue)); + } + + @JRubyMethod(name = {"get_and_set", "swap"}) + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + // less-efficient version for Java 6 and 7 + while (true) { + IRubyObject oldValue = get(); + if (UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)) { + return oldValue; + } + } + } + + private IRubyObject compareAndSetNumeric(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { + Ruby runtime = context.runtime; + + // loop until: + // * reference CAS would succeed for same-valued objects + // * current and expected have different values as determined by #equals + while (true) { + IRubyObject current = reference; + + if (!(current instanceof RubyNumeric)) { + // old value is not numeric, CAS fails + return runtime.getFalse(); + } + + RubyNumeric currentNumber = (RubyNumeric)current; + if (!currentNumber.equals(expectedValue)) { + // current number does not equal expected, fail CAS + return runtime.getFalse(); + } + + // check that current has not changed, or else allow loop to repeat + boolean success = UNSAFE.compareAndSwapObject(this, referenceOffset, current, newValue); + if (success) { + // value is same and did not change in interim...success + return runtime.getTrue(); + } + } + } + } + + private static final class UnsafeHolder { + private UnsafeHolder(){} + + public static final sun.misc.Unsafe U = loadUnsafe(); + + private static sun.misc.Unsafe loadUnsafe() { + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + return null; + } + } + } + + public static class JRubyReference8 extends JRubyReference { + public JRubyReference8(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @Override + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + // efficient version for Java 8 + return (IRubyObject)UNSAFE.getAndSetObject(this, referenceOffset, newValue); + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java new file mode 100644 index 00000000..a09f9162 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java @@ -0,0 +1,248 @@ +package com.concurrent_ruby.ext; + +import org.jruby.*; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8; +import com.concurrent_ruby.ext.jsr166e.nounsafe.*; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +import java.io.IOException; +import java.util.Map; + +import static org.jruby.runtime.Visibility.PRIVATE; + +/** + * Native Java implementation to avoid the JI overhead. + * + * @author thedarkone + */ +public class JRubyMapBackendLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyModule thread_safeMod = concurrentMod.defineModuleUnder("Collection"); + RubyClass jrubyRefClass = thread_safeMod.defineClassUnder("JRubyMapBackend", runtime.getObject(), BACKEND_ALLOCATOR); + jrubyRefClass.setAllocator(BACKEND_ALLOCATOR); + jrubyRefClass.defineAnnotatedMethods(JRubyMapBackend.class); + } + + private static final ObjectAllocator BACKEND_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyMapBackend(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyMapBackend", parent="Object") + public static class JRubyMapBackend extends RubyObject { + // Defaults used by the CHM + static final int DEFAULT_INITIAL_CAPACITY = 16; + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM(); + + private ConcurrentHashMap map; + + private static ConcurrentHashMap newCHM(int initialCapacity, float loadFactor) { + if (CAN_USE_UNSAFE_CHM) { + return new ConcurrentHashMapV8(initialCapacity, loadFactor); + } else { + return new com.concurrent_ruby.ext.jsr166e.nounsafe.ConcurrentHashMapV8(initialCapacity, loadFactor); + } + } + + private static ConcurrentHashMap newCHM() { + return newCHM(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + private static boolean canUseUnsafeCHM() { + try { + new com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8(); // force class load and initialization + return true; + } catch (Throwable t) { // ensuring we really do catch everything + // Doug's Unsafe setup errors always have this "Could not ini.." message + if (isCausedBySecurityException(t)) { + return false; + } + throw (t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t)); + } + } + + private static boolean isCausedBySecurityException(Throwable t) { + while (t != null) { + if ((t.getMessage() != null && t.getMessage().contains("Could not initialize intrinsics")) || t instanceof SecurityException) { + return true; + } + t = t.getCause(); + } + return false; + } + + public JRubyMapBackend(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + map = newCHM(); + return context.getRuntime().getNil(); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject options) { + map = toCHM(context, options); + return context.getRuntime().getNil(); + } + + private ConcurrentHashMap toCHM(ThreadContext context, IRubyObject options) { + Ruby runtime = context.getRuntime(); + if (!options.isNil() && options.respondsTo("[]")) { + IRubyObject rInitialCapacity = options.callMethod(context, "[]", runtime.newSymbol("initial_capacity")); + IRubyObject rLoadFactor = options.callMethod(context, "[]", runtime.newSymbol("load_factor")); + int initialCapacity = !rInitialCapacity.isNil() ? RubyNumeric.num2int(rInitialCapacity.convertToInteger()) : DEFAULT_INITIAL_CAPACITY; + float loadFactor = !rLoadFactor.isNil() ? (float)RubyNumeric.num2dbl(rLoadFactor.convertToFloat()) : DEFAULT_LOAD_FACTOR; + return newCHM(initialCapacity, loadFactor); + } else { + return newCHM(); + } + } + + @JRubyMethod(name = "[]", required = 1) + public IRubyObject op_aref(ThreadContext context, IRubyObject key) { + IRubyObject value; + return ((value = map.get(key)) == null) ? context.getRuntime().getNil() : value; + } + + @JRubyMethod(name = {"[]="}, required = 2) + public IRubyObject op_aset(IRubyObject key, IRubyObject value) { + map.put(key, value); + return value; + } + + @JRubyMethod + public IRubyObject put_if_absent(IRubyObject key, IRubyObject value) { + IRubyObject result = map.putIfAbsent(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute_if_absent(final ThreadContext context, final IRubyObject key, final Block block) { + return map.computeIfAbsent(key, new ConcurrentHashMap.Fun() { + @Override + public IRubyObject apply(IRubyObject key) { + return block.yieldSpecific(context); + } + }); + } + + @JRubyMethod + public IRubyObject compute_if_present(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.computeIfPresent(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.compute(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject merge_pair(final ThreadContext context, final IRubyObject key, final IRubyObject value, final Block block) { + IRubyObject result = map.merge(key, value, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject oldValue, IRubyObject newValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObject newValue) { + return getRuntime().newBoolean(map.replace(key, oldValue, newValue)); + } + + @JRubyMethod(name = "key?", required = 1) + public RubyBoolean has_key_p(IRubyObject key) { + return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse(); + } + + @JRubyMethod + public IRubyObject key(IRubyObject value) { + final IRubyObject key = map.findKey(value); + return key == null ? getRuntime().getNil() : key; + } + + @JRubyMethod + public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) { + IRubyObject result = map.replace(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject get_and_set(IRubyObject key, IRubyObject value) { + IRubyObject result = map.put(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject delete(IRubyObject key) { + IRubyObject result = map.remove(key); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean delete_pair(IRubyObject key, IRubyObject value) { + return getRuntime().newBoolean(map.remove(key, value)); + } + + @JRubyMethod + public IRubyObject clear() { + map.clear(); + return this; + } + + @JRubyMethod + public IRubyObject each_pair(ThreadContext context, Block block) { + for (Map.Entry entry : map.entrySet()) { + block.yieldSpecific(context, entry.getKey(), entry.getValue()); + } + return this; + } + + @JRubyMethod + public RubyFixnum size(ThreadContext context) { + return context.getRuntime().newFixnum(map.size()); + } + + @JRubyMethod + public IRubyObject get_or_default(IRubyObject key, IRubyObject defaultValue) { + return map.getValueOrDefault(key, defaultValue); + } + + @JRubyMethod(visibility = PRIVATE) + public JRubyMapBackend initialize_copy(ThreadContext context, IRubyObject other) { + map = newCHM(); + return this; + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java new file mode 100644 index 00000000..b5660762 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java @@ -0,0 +1,93 @@ +package com.concurrent_ruby.ext; + +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNil; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class JavaAtomicBooleanLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicBoolean", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + atomicCls.defineAnnotatedMethods(JavaAtomicBoolean.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicBoolean(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicBoolean", parent = "Object") + public static class JavaAtomicBoolean extends RubyObject { + + private AtomicBoolean atomicBoolean; + + public JavaAtomicBoolean(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + atomicBoolean = new AtomicBoolean(convertRubyBooleanToJavaBoolean(value)); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + atomicBoolean = new AtomicBoolean(); + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject value() { + return getRuntime().newBoolean(atomicBoolean.get()); + } + + @JRubyMethod(name = "true?") + public IRubyObject isAtomicTrue() { + return getRuntime().newBoolean(atomicBoolean.get()); + } + + @JRubyMethod(name = "false?") + public IRubyObject isAtomicFalse() { + return getRuntime().newBoolean((atomicBoolean.get() == false)); + } + + @JRubyMethod(name = "value=") + public IRubyObject setAtomic(ThreadContext context, IRubyObject newValue) { + atomicBoolean.set(convertRubyBooleanToJavaBoolean(newValue)); + return context.nil; + } + + @JRubyMethod(name = "make_true") + public IRubyObject makeTrue() { + return getRuntime().newBoolean(atomicBoolean.compareAndSet(false, true)); + } + + @JRubyMethod(name = "make_false") + public IRubyObject makeFalse() { + return getRuntime().newBoolean(atomicBoolean.compareAndSet(true, false)); + } + + private boolean convertRubyBooleanToJavaBoolean(IRubyObject newValue) { + if (newValue instanceof RubyBoolean.False || newValue instanceof RubyNil) { + return false; + } else { + return true; + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java new file mode 100644 index 00000000..672bfc04 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java @@ -0,0 +1,113 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyFixnum; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; +import org.jruby.runtime.Block; + +public class JavaAtomicFixnumLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + + atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicFixnum(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicFixnum", parent = "Object") + public static class JavaAtomicFixnum extends RubyObject { + + private AtomicLong atomicLong; + + public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + this.atomicLong = new AtomicLong(0); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + this.atomicLong = new AtomicLong(rubyFixnumToLong(value)); + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject getValue() { + return getRuntime().newFixnum(atomicLong.get()); + } + + @JRubyMethod(name = "value=") + public IRubyObject setValue(ThreadContext context, IRubyObject newValue) { + atomicLong.set(rubyFixnumToLong(newValue)); + return context.nil; + } + + @JRubyMethod(name = {"increment", "up"}) + public IRubyObject increment() { + return getRuntime().newFixnum(atomicLong.incrementAndGet()); + } + + @JRubyMethod(name = {"increment", "up"}) + public IRubyObject increment(IRubyObject value) { + long delta = rubyFixnumToLong(value); + return getRuntime().newFixnum(atomicLong.addAndGet(delta)); + } + + @JRubyMethod(name = {"decrement", "down"}) + public IRubyObject decrement() { + return getRuntime().newFixnum(atomicLong.decrementAndGet()); + } + + @JRubyMethod(name = {"decrement", "down"}) + public IRubyObject decrement(IRubyObject value) { + long delta = rubyFixnumToLong(value); + return getRuntime().newFixnum(atomicLong.addAndGet(-delta)); + } + + @JRubyMethod(name = "compare_and_set") + public IRubyObject compareAndSet(ThreadContext context, IRubyObject expect, IRubyObject update) { + return getRuntime().newBoolean(atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update))); + } + + @JRubyMethod + public IRubyObject update(ThreadContext context, Block block) { + for (;;) { + long _oldValue = atomicLong.get(); + IRubyObject oldValue = getRuntime().newFixnum(_oldValue); + IRubyObject newValue = block.yield(context, oldValue); + if (atomicLong.compareAndSet(_oldValue, rubyFixnumToLong(newValue))) { + return newValue; + } + } + } + + private long rubyFixnumToLong(IRubyObject value) { + if (value instanceof RubyFixnum) { + RubyFixnum fixNum = (RubyFixnum) value; + return fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError("value must be a Fixnum"); + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java new file mode 100644 index 00000000..d887f250 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java @@ -0,0 +1,189 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +import java.util.concurrent.Semaphore; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyFixnum; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +public class JavaSemaphoreLibrary { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaSemaphore", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + + atomicCls.defineAnnotatedMethods(JavaSemaphore.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaSemaphore(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaSemaphore", parent = "Object") + public static class JavaSemaphore extends RubyObject { + + private JRubySemaphore semaphore; + + public JavaSemaphore(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + this.semaphore = new JRubySemaphore(rubyFixnumInt(value, "count")); + return context.nil; + } + + @JRubyMethod + public IRubyObject acquire(ThreadContext context, final Block block) throws InterruptedException { + return this.acquire(context, 1, block); + } + + @JRubyMethod + public IRubyObject acquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException { + return this.acquire(context, rubyFixnumToPositiveInt(permits, "permits"), block); + } + + @JRubyMethod(name = "available_permits") + public IRubyObject availablePermits(ThreadContext context) { + return getRuntime().newFixnum(this.semaphore.availablePermits()); + } + + @JRubyMethod(name = "drain_permits") + public IRubyObject drainPermits(ThreadContext context) { + return getRuntime().newFixnum(this.semaphore.drainPermits()); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, final Block block) throws InterruptedException { + int permitsInt = 1; + boolean acquired = semaphore.tryAcquire(permitsInt); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException { + int permitsInt = rubyFixnumToPositiveInt(permits, "permits"); + boolean acquired = semaphore.tryAcquire(permitsInt); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout, final Block block) throws InterruptedException { + int permitsInt = rubyFixnumToPositiveInt(permits, "permits"); + boolean acquired = semaphore.tryAcquire( + permitsInt, + rubyNumericToLong(timeout, "timeout"), + java.util.concurrent.TimeUnit.SECONDS + ); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod + public IRubyObject release(ThreadContext context) { + this.semaphore.release(1); + return getRuntime().newBoolean(true); + } + + @JRubyMethod + public IRubyObject release(ThreadContext context, IRubyObject permits) { + this.semaphore.release(rubyFixnumToPositiveInt(permits, "permits")); + return getRuntime().newBoolean(true); + } + + @JRubyMethod(name = "reduce_permits") + public IRubyObject reducePermits(ThreadContext context, IRubyObject reduction) throws InterruptedException { + this.semaphore.publicReducePermits(rubyFixnumToNonNegativeInt(reduction, "reduction")); + return context.nil; + } + + private IRubyObject acquire(ThreadContext context, int permits, final Block block) throws InterruptedException { + this.semaphore.acquire(permits); + + if (!block.isGiven()) return context.nil; + + try { + return block.yieldSpecific(context); + } finally { + this.semaphore.release(permits); + } + } + + private IRubyObject triedAcquire(ThreadContext context, int permits, boolean acquired, final Block block) { + if (!block.isGiven()) return getRuntime().newBoolean(acquired); + if (!acquired) return context.nil; + + try { + return block.yieldSpecific(context); + } finally { + this.semaphore.release(permits); + } + } + + private int rubyFixnumInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be integer"); + } + } + + private int rubyFixnumToNonNegativeInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() >= 0) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be a non-negative integer"); + } + } + + private int rubyFixnumToPositiveInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() > 0) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be an integer greater than zero"); + } + } + + private long rubyNumericToLong(IRubyObject value, String paramName) { + if (value instanceof RubyNumeric && ((RubyNumeric) value).getDoubleValue() > 0) { + RubyNumeric fixNum = (RubyNumeric) value; + return fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be a float greater than zero"); + } + } + + class JRubySemaphore extends Semaphore { + + public JRubySemaphore(int permits) { + super(permits); + } + + public JRubySemaphore(int permits, boolean value) { + super(permits, value); + } + + public void publicReducePermits(int i) { + reducePermits(i); + } + + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java new file mode 100644 index 00000000..f0c75ee4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java @@ -0,0 +1,292 @@ +package com.concurrent_ruby.ext; + +import org.jruby.Ruby; +import org.jruby.RubyBasicObject; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyThread; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.Visibility; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; +import sun.misc.Unsafe; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class SynchronizationLibrary implements Library { + + private static final Unsafe UNSAFE = loadUnsafe(); + private static final boolean FULL_FENCE = supportsFences(); + + private static Unsafe loadUnsafe() { + try { + Class ncdfe = Class.forName("sun.misc.Unsafe"); + Field f = ncdfe.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get((java.lang.Object) null); + } catch (Exception var2) { + return null; + } catch (NoClassDefFoundError var3) { + return null; + } + } + + private static boolean supportsFences() { + if (UNSAFE == null) { + return false; + } else { + try { + Method m = UNSAFE.getClass().getDeclaredMethod("fullFence", new Class[0]); + if (m != null) { + return true; + } + } catch (Exception var1) { + // nothing + } + + return false; + } + } + + private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new Object(runtime, klazz); + } + }; + + private static final ObjectAllocator ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new AbstractLockableObject(runtime, klazz); + } + }; + + private static final ObjectAllocator JRUBY_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyLockableObject(runtime, klazz); + } + }; + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule synchronizationModule = runtime. + defineModule("Concurrent"). + defineModuleUnder("Synchronization"); + + RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile"); + jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class); + + defineClass(runtime, synchronizationModule, "AbstractObject", "Object", + Object.class, OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject", + AbstractLockableObject.class, ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "AbstractLockableObject", "JRubyLockableObject", + JRubyLockableObject.class, JRUBY_LOCKABLE_OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "Object", "JRuby", + JRuby.class, new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRuby(runtime, klazz); + } + }); + } + + private RubyClass defineClass( + Ruby runtime, + RubyModule namespace, + String parentName, + String name, + Class javaImplementation, + ObjectAllocator allocator) { + final RubyClass parentClass = namespace.getClass(parentName); + + if (parentClass == null) { + System.out.println("not found " + parentName); + throw runtime.newRuntimeError(namespace.toString() + "::" + parentName + " is missing"); + } + + final RubyClass newClass = namespace.defineClassUnder(name, parentClass, allocator); + newClass.defineAnnotatedMethods(javaImplementation); + return newClass; + } + + // Facts: + // - all ivar reads are without any synchronisation of fences see + // https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110 + // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor + // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or + // volatilePut + // TODO (pitr 16-Sep-2015): what do we do in Java 9 ? + + // module JRubyAttrVolatile + public static class JRubyAttrVolatile { + + // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic + // on volatile fields. any volatile field could have been used but using the thread context is an + // attempt to avoid code elimination. + private static volatile int volatileField; + + @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject module) { + // Prevent reordering of ivar writes with publication of this instance + if (!FULL_FENCE) { + // Assuming that following volatile read and write is not eliminated it simulates fullFence. + // If it's eliminated it'll cause problems only on non-x86 platforms. + // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding + final int volatileRead = volatileField; + volatileField = context.getLine(); + } else { + UNSAFE.fullFence(); + } + return context.nil; + } + + @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject instanceVariableGetVolatile( + ThreadContext context, + IRubyObject module, + IRubyObject self, + IRubyObject name) { + // Ensure we ses latest value with loadFence + if (!FULL_FENCE) { + // piggybacking on volatile read, simulating loadFence + final int volatileRead = volatileField; + return ((RubyBasicObject) self).instance_variable_get(context, name); + } else { + UNSAFE.loadFence(); + return ((RubyBasicObject) self).instance_variable_get(context, name); + } + } + + @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject InstanceVariableSetVolatile( + ThreadContext context, + IRubyObject module, + IRubyObject self, + IRubyObject name, + IRubyObject value) { + // Ensure we make last update visible + if (!FULL_FENCE) { + // piggybacking on volatile write, simulating storeFence + final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value); + volatileField = context.getLine(); + return result; + } else { + // JRuby uses StampedVariableAccessor which calls fullFence + // so no additional steps needed. + // See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159 + return ((RubyBasicObject) self).instance_variable_set(name, value); + } + } + } + + @JRubyClass(name = "Object", parent = "AbstractObject") + public static class Object extends RubyObject { + + public Object(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + } + + @JRubyClass(name = "AbstractLockableObject", parent = "Object") + public static class AbstractLockableObject extends Object { + + public AbstractLockableObject(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + } + + @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject") + public static class JRubyLockableObject extends AbstractLockableObject { + + public JRubyLockableObject(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod(name = "synchronize", visibility = Visibility.PROTECTED) + public IRubyObject rubySynchronize(ThreadContext context, Block block) { + synchronized (this) { + return block.yield(context, null); + } + } + + @JRubyMethod(name = "ns_wait", optional = 1, visibility = Visibility.PROTECTED) + public IRubyObject nsWait(ThreadContext context, IRubyObject[] args) { + Ruby runtime = context.runtime; + if (args.length > 1) { + throw runtime.newArgumentError(args.length, 1); + } + Double timeout = null; + if (args.length > 0 && !args[0].isNil()) { + timeout = args[0].convertToFloat().getDoubleValue(); + if (timeout < 0) { + throw runtime.newArgumentError("time interval must be positive"); + } + } + if (Thread.interrupted()) { + throw runtime.newConcurrencyError("thread interrupted"); + } + boolean success = false; + try { + success = context.getThread().wait_timeout(this, timeout); + } catch (InterruptedException ie) { + throw runtime.newConcurrencyError(ie.getLocalizedMessage()); + } finally { + // An interrupt or timeout may have caused us to miss + // a notify that we consumed, so do another notify in + // case someone else is available to pick it up. + if (!success) { + this.notify(); + } + } + return this; + } + + @JRubyMethod(name = "ns_signal", visibility = Visibility.PROTECTED) + public IRubyObject nsSignal(ThreadContext context) { + notify(); + return this; + } + + @JRubyMethod(name = "ns_broadcast", visibility = Visibility.PROTECTED) + public IRubyObject nsBroadcast(ThreadContext context) { + notifyAll(); + return this; + } + } + + @JRubyClass(name = "JRuby") + public static class JRuby extends RubyObject { + public JRuby(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod(name = "sleep_interruptibly", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject sleepInterruptibly(final ThreadContext context, IRubyObject receiver, final Block block) { + try { + context.getThread().executeBlockingTask(new RubyThread.BlockingTask() { + @Override + public void run() throws InterruptedException { + block.call(context); + } + + @Override + public void wakeup() { + context.getThread().getNativeThread().interrupt(); + } + }); + } catch (InterruptedException e) { + throw context.runtime.newThreadError("interrupted in Concurrent::Synchronization::JRuby.sleep_interruptibly"); + } + return context.nil; + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java new file mode 100644 index 00000000..e11e15aa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java @@ -0,0 +1,31 @@ +package com.concurrent_ruby.ext.jsr166e; + +import java.util.Map; +import java.util.Set; + +public interface ConcurrentHashMap { + /** Interface describing a function of one argument */ + public interface Fun { T apply(A a); } + /** Interface describing a function of two arguments */ + public interface BiFun { T apply(A a, B b); } + + public V get(K key); + public V put(K key, V value); + public V putIfAbsent(K key, V value); + public V computeIfAbsent(K key, Fun mf); + public V computeIfPresent(K key, BiFun mf); + public V compute(K key, BiFun mf); + public V merge(K key, V value, BiFun mf); + public boolean replace(K key, V oldVal, V newVal); + public V replace(K key, V value); + public boolean containsKey(K key); + public boolean remove(Object key, Object value); + public V remove(K key); + public void clear(); + public Set> entrySet(); + public int size(); + public V getValueOrDefault(Object key, V defaultValue); + + public boolean containsValue(V value); + public K findKey(V value); +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java new file mode 100644 index 00000000..dc9901fb --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java @@ -0,0 +1,3863 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package com.concurrent_ruby.ext.jsr166e; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

    + *
  • forEach: Perform a given action on each element. + * A variant form applies a given transformation on each element + * before performing the action.
  • + * + *
  • search: Return the first available non-null result of + * applying a given function on each element; skipping further + * search when a result is found.
  • + * + *
  • reduce: Accumulate each element. The supplied reduction + * function cannot rely on ordering (more formally, it should be + * both associative and commutative). There are five variants: + * + *
      + * + *
    • Plain reductions. (There is not a form of this method for + * (key, value) function arguments since there is no corresponding + * return type.)
    • + * + *
    • Mapped reductions that accumulate the results of a given + * function applied to each element.
    • + * + *
    • Reductions to scalar doubles, longs, and ints, using a + * given basis value.
    • + * + * + *
    + *
+ * + *

The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

All arguments to all task methods must be non-null. + * + *

jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

This interface exports a subset of expected JDK8 + * functionality. + * + *

Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

+     * {@code ConcurrentHashMapV8 m = ...
+     * // split as if have 8 * parallelism, for load balance
+     * int n = m.size();
+     * int p = aForkJoinPool.getParallelism() * 8;
+     * int split = (n < p)? n : p;
+     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
+     * // ...
+     * static class SumValues extends RecursiveTask {
+     *   final Spliterator s;
+     *   final int split;             // split while > 1
+     *   final SumValues nextJoin;    // records forked subtasks to join
+     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
+     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
+     *   }
+     *   public Long compute() {
+     *     long sum = 0;
+     *     SumValues subtasks = null; // fork subtasks
+     *     for (int s = split >>> 1; s > 0; s >>>= 1)
+     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
+     *     while (s.hasNext())        // directly process remaining elements
+     *       sum += s.next();
+     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
+     *       sum += t.join();         // collect subtask results
+     *     return sum;
+     *   }
+     * }
+     * }
+ */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments referring to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile Node[] table; + + /** + * The counter maintaining number of elements. + */ + private transient final LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(Node[] tab, int i) { // used by Iter + return (Node)UNSAFE.getObjectVolatile(tab, ((long)i< 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(Node[] tab, int i) { + if (tab != null && i >= 0 && i < tab.length) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + + // Unsafe mechanics for casHash + private static final sun.misc.Unsafe UNSAFE; + private static final long hashOffset; + + static { + try { + UNSAFE = getUnsafe(); + Class k = Node.class; + hashOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("hash")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(Node[] tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (Node[] tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (Node[])ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final Node[] initTable() { + Node[] tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + Node[] tab; int n, sc; + while ((tab = table) != null && + (n = tab.length) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + Node[] tab = table; int n; + if (tab == null || (n = tab.length) == 0) { + n = (sc > c) ? sc : c; + if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final Node[] rebuild(Node[] tab) { + int n = tab.length; + Node[] nextTab = new Node[n << 1]; + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(Node[] nextTab, int i, Node e) { + int bit = nextTab.length >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(Node[] nextTab, int i, TreeBin t) { + int bit = nextTab.length >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + Node[] tab = table; + while (tab != null && i < tab.length) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + Node[] tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; Node[] t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length; + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + Node[] t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length; + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length; + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (Node[])ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

 {@code
+     * if (map.containsKey(key))
+     *   return map.get(key);
+     * value = mappingFunction.apply(key);
+     * if (value != null)
+     *   map.put(key, value);
+     * return value;}
+ * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
 {@code
+     * map.computeIfAbsent(key, new Fun() {
+     *   public V map(K k) { return new Value(f(k)); }});}
+ * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
 {@code
+     *   if (map.containsKey(key)) {
+     *     value = remappingFunction.apply(key, map.get(key));
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
 {@code
+     *   value = remappingFunction.apply(key, map.get(key));
+     *   if (value != null)
+     *     map.put(key, value);
+     *   else
+     *     map.remove(key);
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
 {@code
+     * Map map = ...;
+     * final String msg = ...;
+     * map.compute(key, new BiFun() {
+     *   public String apply(Key k, String v) {
+     *    return (v == null) ? msg : v + msg;});}}
+ * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
 {@code
+     *   if (!map.containsKey(key))
+     *     map.put(value);
+     *   else {
+     *     newValue = remappingFunction.apply(map.get(key), value);
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder()); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == null) { + init = true; + Node[] tab = new Node[n]; + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + Node[] tab = table; + for (int i = 0; i < tab.length; ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long counterOffset; + private static final long sizeCtlOffset; + private static final long ABASE; + private static final int ASHIFT; + + static { + int ss; + try { + UNSAFE = getUnsafe(); + Class k = ConcurrentHashMapV8.class; + counterOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("counter")); + sizeCtlOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("sizeCtl")); + Class sc = Node[].class; + ABASE = UNSAFE.arrayBaseOffset(sc); + ss = UNSAFE.arrayIndexScale(sc); + } catch (Exception e) { + throw new Error(e); + } + if ((ss & (ss-1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(ss); + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java new file mode 100644 index 00000000..47a923c8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java @@ -0,0 +1,203 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package com.concurrent_ruby.ext.jsr166e; +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java new file mode 100644 index 00000000..93a277fb --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java @@ -0,0 +1,342 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package com.concurrent_ruby.ext.jsr166e; +import java.util.Random; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long valueOffset; + static { + try { + UNSAFE = getUnsafe(); + Class ak = Cell.class; + valueOffset = UNSAFE.objectFieldOffset + (ak.getDeclaredField("value")); + } catch (Exception e) { + throw new Error(e); + } + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long baseOffset; + private static final long busyOffset; + static { + try { + UNSAFE = getUnsafe(); + Class sk = Striped64.class; + baseOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("base")); + busyOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("busy")); + } catch (Exception e) { + throw new Error(e); + } + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java new file mode 100644 index 00000000..a4e73ea1 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java @@ -0,0 +1,3800 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; +import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

+ * + *

The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

All arguments to all task methods must be non-null. + * + *

jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

This interface exports a subset of expected JDK8 + * functionality. + * + *

Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

+     * {@code ConcurrentHashMapV8 m = ...
+     * // split as if have 8 * parallelism, for load balance
+     * int n = m.size();
+     * int p = aForkJoinPool.getParallelism() * 8;
+     * int split = (n < p)? n : p;
+     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
+     * // ...
+     * static class SumValues extends RecursiveTask {
+     *   final Spliterator s;
+     *   final int split;             // split while > 1
+     *   final SumValues nextJoin;    // records forked subtasks to join
+     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
+     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
+     *   }
+     *   public Long compute() {
+     *     long sum = 0;
+     *     SumValues subtasks = null; // fork subtasks
+     *     for (int s = split >>> 1; s > 0; s >>>= 1)
+     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
+     *     while (s.hasNext())        // directly process remaining elements
+     *       sum += s.next();
+     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
+     *       sum += t.join();         // collect subtask results
+     *     return sum;
+     *   }
+     * }
+     * }
+ */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments referring to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile AtomicReferenceArray table; + + /** + * The counter maintaining number of elements. + */ + private transient LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + static AtomicIntegerFieldUpdater SIZE_CTRL_UPDATER = AtomicIntegerFieldUpdater.newUpdater(ConcurrentHashMapV8.class, "sizeCtl"); + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(AtomicReferenceArray tab, int i) { // used by Iter + return tab.get(i); + } + + private static final boolean casTabAt(AtomicReferenceArray tab, int i, Node c, Node v) { + return tab.compareAndSet(i, c, v); + } + + private static final void setTabAt(AtomicReferenceArray tab, int i, Node v) { + tab.set(i, v); + } + + /* ---------------- Nodes -------------- */ + + /** + * Key-value entry. Note that this is never exported out as a + * user-visible Map.Entry (see MapEntry below). Nodes with a hash + * field of MOVED are special, and do not contain user keys or + * values. Otherwise, keys are never null, and null val fields + * indicate that a node is in the process of being deleted or + * created. For purposes of read-only access, a key may be read + * before a val, but can only be used after checking val to be + * non-null. + */ + static class Node { + volatile int hash; + final Object key; + volatile Object val; + volatile Node next; + + static AtomicIntegerFieldUpdater HASH_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Node.class, "hash"); + + Node(int hash, Object key, Object val, Node next) { + this.hash = hash; + this.key = key; + this.val = val; + this.next = next; + } + + /** CompareAndSet the hash field */ + final boolean casHash(int cmp, int val) { + return HASH_UPDATER.compareAndSet(this, cmp, val); + } + + /** The number of spins before blocking for a lock */ + static final int MAX_SPINS = + Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(AtomicReferenceArray tab, int i) { + if (tab != null && i >= 0 && i < tab.length()) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(AtomicReferenceArray tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length() >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (AtomicReferenceArray tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length() - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (AtomicReferenceArray)ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length() - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final AtomicReferenceArray initTable() { + AtomicReferenceArray tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + AtomicReferenceArray tab; int n, sc; + while ((tab = table) != null && + (n = tab.length()) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + AtomicReferenceArray tab = table; int n; + if (tab == null || (n = tab.length()) == 0) { + n = (sc > c) ? sc : c; + if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final AtomicReferenceArray rebuild(AtomicReferenceArray tab) { + int n = tab.length(); + AtomicReferenceArray nextTab = new AtomicReferenceArray(n << 1); + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(AtomicReferenceArray nextTab, int i, Node e) { + int bit = nextTab.length() >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(AtomicReferenceArray nextTab, int i, TreeBin t) { + int bit = nextTab.length() >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + AtomicReferenceArray tab = table; + while (tab != null && i < tab.length()) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + AtomicReferenceArray tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; AtomicReferenceArray t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length(); + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + AtomicReferenceArray t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length(); + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length(); + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (AtomicReferenceArray)ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

 {@code
+     * if (map.containsKey(key))
+     *   return map.get(key);
+     * value = mappingFunction.apply(key);
+     * if (value != null)
+     *   map.put(key, value);
+     * return value;}
+ * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
 {@code
+     * map.computeIfAbsent(key, new Fun() {
+     *   public V map(K k) { return new Value(f(k)); }});}
+ * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
 {@code
+     *   if (map.containsKey(key)) {
+     *     value = remappingFunction.apply(key, map.get(key));
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
 {@code
+     *   value = remappingFunction.apply(key, map.get(key));
+     *   if (value != null)
+     *     map.put(key, value);
+     *   else
+     *     map.remove(key);
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
 {@code
+     * Map map = ...;
+     * final String msg = ...;
+     * map.compute(key, new BiFun() {
+     *   public String apply(Key k, String v) {
+     *    return (v == null) ? msg : v + msg;});}}
+ * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
 {@code
+     *   if (!map.containsKey(key))
+     *     map.put(value);
+     *   else {
+     *     newValue = remappingFunction.apply(map.get(key), value);
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + this.counter = new LongAdder(); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == null) { + init = true; + AtomicReferenceArray tab = new AtomicReferenceArray(n); + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + AtomicReferenceArray tab = table; + for (int i = 0; i < tab.length(); ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java new file mode 100644 index 00000000..ecf552a2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java @@ -0,0 +1,204 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java new file mode 100644 index 00000000..f5216424 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java @@ -0,0 +1,291 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + + static AtomicLongFieldUpdater VALUE_UPDATER = AtomicLongFieldUpdater.newUpdater(Cell.class, "value"); + + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return VALUE_UPDATER.compareAndSet(this, cmp, val); + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + AtomicLongFieldUpdater BASE_UPDATER = AtomicLongFieldUpdater.newUpdater(Striped64.class, "base"); + AtomicIntegerFieldUpdater BUSY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Striped64.class, "busy"); + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return BASE_UPDATER.compareAndSet(this, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return BUSY_UPDATER.compareAndSet(this, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java new file mode 100644 index 00000000..3ea409ff --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java @@ -0,0 +1,199 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.16 version + +package com.concurrent_ruby.ext.jsr166y; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit calls to setSeed to succeed only + * while executing the Random constructor. We can't allow others + * since it would cause setting seed in one part of a program to + * unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + */ + ThreadLocalRandom() { + super(); + initialized = true; + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +} diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent-ruby.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent-ruby.rb new file mode 100644 index 00000000..e9a3dea4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent-ruby.rb @@ -0,0 +1,5 @@ +# This file is here so that there is a file with the same name as the gem that +# can be required by Bundler.require. Applications should normally +# require 'concurrent'. + +require_relative "concurrent" diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent.rb new file mode 100644 index 00000000..87de46f1 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent.rb @@ -0,0 +1,134 @@ +require 'concurrent/version' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/configuration' + +require 'concurrent/atomics' +require 'concurrent/executors' +require 'concurrent/synchronization' + +require 'concurrent/atomic/atomic_markable_reference' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/agent' +require 'concurrent/atom' +require 'concurrent/array' +require 'concurrent/hash' +require 'concurrent/set' +require 'concurrent/map' +require 'concurrent/tuple' +require 'concurrent/async' +require 'concurrent/dataflow' +require 'concurrent/delay' +require 'concurrent/exchanger' +require 'concurrent/future' +require 'concurrent/immutable_struct' +require 'concurrent/ivar' +require 'concurrent/maybe' +require 'concurrent/mutable_struct' +require 'concurrent/mvar' +require 'concurrent/promise' +require 'concurrent/scheduled_task' +require 'concurrent/settable_struct' +require 'concurrent/timer_task' +require 'concurrent/tvar' +require 'concurrent/promises' + +require 'concurrent/thread_safe/synchronized_delegator' +require 'concurrent/thread_safe/util' + +require 'concurrent/options' + +# @!macro internal_implementation_note +# +# @note **Private Implementation:** This abstraction is a private, internal +# implementation detail. It should never be used directly. + +# @!macro monotonic_clock_warning +# +# @note Time calculations on all platforms and languages are sensitive to +# changes to the system clock. To alleviate the potential problems +# associated with changing the system clock while an application is running, +# most modern operating systems provide a monotonic clock that operates +# independently of the system clock. A monotonic clock cannot be used to +# determine human-friendly clock times. A monotonic clock is used exclusively +# for calculating time intervals. Not all Ruby platforms provide access to an +# operating system monotonic clock. On these platforms a pure-Ruby monotonic +# clock will be used as a fallback. An operating system monotonic clock is both +# faster and more reliable than the pure-Ruby implementation. The pure-Ruby +# implementation should be fast and reliable enough for most non-realtime +# operations. At this time the common Ruby platforms that provide access to an +# operating system monotonic clock are MRI 2.1 and above and JRuby (all versions). +# +# @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3) + +# @!macro copy_options +# +# ## Copy Options +# +# Object references in Ruby are mutable. This can lead to serious +# problems when the {#value} of an object is a mutable reference. Which +# is always the case unless the value is a `Fixnum`, `Symbol`, or similar +# "primitive" data type. Each instance can be configured with a few +# options that can help protect the program from potentially dangerous +# operations. Each of these options can be optionally set when the object +# instance is created: +# +# * `:dup_on_deref` When true the object will call the `#dup` method on +# the `value` object every time the `#value` method is called +# (default: false) +# * `:freeze_on_deref` When true the object will call the `#freeze` +# method on the `value` object every time the `#value` method is called +# (default: false) +# * `:copy_on_deref` When given a `Proc` object the `Proc` will be run +# every time the `#value` method is called. The `Proc` will be given +# the current `value` as its only argument and the result returned by +# the block will be the return value of the `#value` call. When `nil` +# this option will be ignored (default: nil) +# +# When multiple deref options are set the order of operations is strictly defined. +# The order of deref operations is: +# * `:copy_on_deref` +# * `:dup_on_deref` +# * `:freeze_on_deref` +# +# Because of this ordering there is no need to `#freeze` an object created by a +# provided `:copy_on_deref` block. Simply set `:freeze_on_deref` to `true`. +# Setting both `:dup_on_deref` to `true` and `:freeze_on_deref` to `true` is +# as close to the behavior of a "pure" functional language (like Erlang, Clojure, +# or Haskell) as we are likely to get in Ruby. + +# @!macro deref_options +# +# @option opts [Boolean] :dup_on_deref (false) Call `#dup` before +# returning the data from {#value} +# @option opts [Boolean] :freeze_on_deref (false) Call `#freeze` before +# returning the data from {#value} +# @option opts [Proc] :copy_on_deref (nil) When calling the {#value} +# method, call the given proc passing the internal value as the sole +# argument then return the new value returned from the proc. + +# @!macro executor_and_deref_options +# +# @param [Hash] opts the options used to define the behavior at update and deref +# and to specify the executor on which to perform actions +# @option opts [Executor] :executor when set use the given `Executor` instance. +# Three special values are also supported: `:io` returns the global pool for +# long, blocking (IO) tasks, `:fast` returns the global pool for short, fast +# operations, and `:immediate` returns the global `ImmediateExecutor` object. +# @!macro deref_options + +# @!macro warn.edge +# @api Edge +# @note **Edge Features** are under active development and may change frequently. +# +# - Deprecations are not added before incompatible changes. +# - Edge version: _major_ is always 0, _minor_ bump means incompatible change, +# _patch_ bump means compatible change. +# - Edge features may also lack tests and documentation. +# - Features developed in `concurrent-ruby-edge` are expected to move +# to `concurrent-ruby` when finalised. + + +# {include:file:README.md} +module Concurrent +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/agent.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/agent.rb new file mode 100644 index 00000000..dc8a2600 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/agent.rb @@ -0,0 +1,588 @@ +require 'concurrent/configuration' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/atomic/thread_local_var' +require 'concurrent/collection/copy_on_write_observer_set' +require 'concurrent/concern/observable' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # `Agent` is inspired by Clojure's [agent](http://clojure.org/agents) + # function. An agent is a shared, mutable variable providing independent, + # uncoordinated, *asynchronous* change of individual values. Best used when + # the value will undergo frequent, complex updates. Suitable when the result + # of an update does not need to be known immediately. `Agent` is (mostly) + # functionally equivalent to Clojure's agent, except where the runtime + # prevents parity. + # + # Agents are reactive, not autonomous - there is no imperative message loop + # and no blocking receive. The state of an Agent should be itself immutable + # and the `#value` of an Agent is always immediately available for reading by + # any thread without any messages, i.e. observation does not require + # cooperation or coordination. + # + # Agent action dispatches are made using the various `#send` methods. These + # methods always return immediately. At some point later, in another thread, + # the following will happen: + # + # 1. The given `action` will be applied to the state of the Agent and the + # `args`, if any were supplied. + # 2. The return value of `action` will be passed to the validator lambda, + # if one has been set on the Agent. + # 3. If the validator succeeds or if no validator was given, the return value + # of the given `action` will become the new `#value` of the Agent. See + # `#initialize` for details. + # 4. If any observers were added to the Agent, they will be notified. See + # `#add_observer` for details. + # 5. If during the `action` execution any other dispatches are made (directly + # or indirectly), they will be held until after the `#value` of the Agent + # has been changed. + # + # If any exceptions are thrown by an action function, no nested dispatches + # will occur, and the exception will be cached in the Agent itself. When an + # Agent has errors cached, any subsequent interactions will immediately throw + # an exception, until the agent's errors are cleared. Agent errors can be + # examined with `#error` and the agent restarted with `#restart`. + # + # The actions of all Agents get interleaved amongst threads in a thread pool. + # At any point in time, at most one action for each Agent is being executed. + # Actions dispatched to an agent from another single agent or thread will + # occur in the order they were sent, potentially interleaved with actions + # dispatched to the same agent from other sources. The `#send` method should + # be used for actions that are CPU limited, while the `#send_off` method is + # appropriate for actions that may block on IO. + # + # Unlike in Clojure, `Agent` cannot participate in `Concurrent::TVar` transactions. + # + # ## Example + # + # ``` + # def next_fibonacci(set = nil) + # return [0, 1] if set.nil? + # set + [set[-2..-1].reduce{|sum,x| sum + x }] + # end + # + # # create an agent with an initial value + # agent = Concurrent::Agent.new(next_fibonacci) + # + # # send a few update requests + # 5.times do + # agent.send{|set| next_fibonacci(set) } + # end + # + # # wait for them to complete + # agent.await + # + # # get the current value + # agent.value #=> [0, 1, 1, 2, 3, 5, 8] + # ``` + # + # ## Observation + # + # Agents support observers through the {Concurrent::Observable} mixin module. + # Notification of observers occurs every time an action dispatch returns and + # the new value is successfully validated. Observation will *not* occur if the + # action raises an exception, if validation fails, or when a {#restart} occurs. + # + # When notified the observer will receive three arguments: `time`, `old_value`, + # and `new_value`. The `time` argument is the time at which the value change + # occurred. The `old_value` is the value of the Agent when the action began + # processing. The `new_value` is the value to which the Agent was set when the + # action completed. Note that `old_value` and `new_value` may be the same. + # This is not an error. It simply means that the action returned the same + # value. + # + # ## Nested Actions + # + # It is possible for an Agent action to post further actions back to itself. + # The nested actions will be enqueued normally then processed *after* the + # outer action completes, in the order they were sent, possibly interleaved + # with action dispatches from other threads. Nested actions never deadlock + # with one another and a failure in a nested action will never affect the + # outer action. + # + # Nested actions can be called using the Agent reference from the enclosing + # scope or by passing the reference in as a "send" argument. Nested actions + # cannot be post using `self` from within the action block/proc/lambda; `self` + # in this context will not reference the Agent. The preferred method for + # dispatching nested actions is to pass the Agent as an argument. This allows + # Ruby to more effectively manage the closing scope. + # + # Prefer this: + # + # ``` + # agent = Concurrent::Agent.new(0) + # agent.send(agent) do |value, this| + # this.send {|v| v + 42 } + # 3.14 + # end + # agent.value #=> 45.14 + # ``` + # + # Over this: + # + # ``` + # agent = Concurrent::Agent.new(0) + # agent.send do |value| + # agent.send {|v| v + 42 } + # 3.14 + # end + # ``` + # + # @!macro agent_await_warning + # + # **NOTE** Never, *under any circumstances*, call any of the "await" methods + # ({#await}, {#await_for}, {#await_for!}, and {#wait}) from within an action + # block/proc/lambda. The call will block the Agent and will always fail. + # Calling either {#await} or {#wait} (with a timeout of `nil`) will + # hopelessly deadlock the Agent with no possibility of recovery. + # + # @!macro thread_safe_variable_comparison + # + # @see http://clojure.org/Agents Clojure Agents + # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State + class Agent < Synchronization::LockableObject + include Concern::Observable + + ERROR_MODES = [:continue, :fail].freeze + private_constant :ERROR_MODES + + AWAIT_FLAG = ::Object.new + private_constant :AWAIT_FLAG + + AWAIT_ACTION = ->(value, latch) { latch.count_down; AWAIT_FLAG } + private_constant :AWAIT_ACTION + + DEFAULT_ERROR_HANDLER = ->(agent, error) { nil } + private_constant :DEFAULT_ERROR_HANDLER + + DEFAULT_VALIDATOR = ->(value) { true } + private_constant :DEFAULT_VALIDATOR + + Job = Struct.new(:action, :args, :executor, :caller) + private_constant :Job + + # Raised during action processing or any other time in an Agent's lifecycle. + class Error < StandardError + def initialize(message = nil) + message ||= 'agent must be restarted before jobs can post' + super(message) + end + end + + # Raised when a new value obtained during action processing or at `#restart` + # fails validation. + class ValidationError < Error + def initialize(message = nil) + message ||= 'invalid value' + super(message) + end + end + + # The error mode this Agent is operating in. See {#initialize} for details. + attr_reader :error_mode + + # Create a new `Agent` with the given initial value and options. + # + # The `:validator` option must be `nil` or a side-effect free proc/lambda + # which takes one argument. On any intended value change the validator, if + # provided, will be called. If the new value is invalid the validator should + # return `false` or raise an error. + # + # The `:error_handler` option must be `nil` or a proc/lambda which takes two + # arguments. When an action raises an error or validation fails, either by + # returning false or raising an error, the error handler will be called. The + # arguments to the error handler will be a reference to the agent itself and + # the error object which was raised. + # + # The `:error_mode` may be either `:continue` (the default if an error + # handler is given) or `:fail` (the default if error handler nil or not + # given). + # + # If an action being run by the agent throws an error or doesn't pass + # validation the error handler, if present, will be called. After the + # handler executes if the error mode is `:continue` the Agent will continue + # as if neither the action that caused the error nor the error itself ever + # happened. + # + # If the mode is `:fail` the Agent will become {#failed?} and will stop + # accepting new action dispatches. Any previously queued actions will be + # held until {#restart} is called. The {#value} method will still work, + # returning the value of the Agent before the error. + # + # @param [Object] initial the initial value + # @param [Hash] opts the configuration options + # + # @option opts [Symbol] :error_mode either `:continue` or `:fail` + # @option opts [nil, Proc] :error_handler the (optional) error handler + # @option opts [nil, Proc] :validator the (optional) validation procedure + def initialize(initial, opts = {}) + super() + synchronize { ns_initialize(initial, opts) } + end + + # The current value (state) of the Agent, irrespective of any pending or + # in-progress actions. The value is always available and is non-blocking. + # + # @return [Object] the current value + def value + @current.value # TODO (pitr 12-Sep-2015): broken unsafe read? + end + + alias_method :deref, :value + + # When {#failed?} and {#error_mode} is `:fail`, returns the error object + # which caused the failure, else `nil`. When {#error_mode} is `:continue` + # will *always* return `nil`. + # + # @return [nil, Error] the error which caused the failure when {#failed?} + def error + @error.value + end + + alias_method :reason, :error + + # @!macro agent_send + # + # Dispatches an action to the Agent and returns immediately. Subsequently, + # in a thread from a thread pool, the {#value} will be set to the return + # value of the action. Action dispatches are only allowed when the Agent + # is not {#failed?}. + # + # The action must be a block/proc/lambda which takes 1 or more arguments. + # The first argument is the current {#value} of the Agent. Any arguments + # passed to the send method via the `args` parameter will be passed to the + # action as the remaining arguments. The action must return the new value + # of the Agent. + # + # * {#send} and {#send!} should be used for actions that are CPU limited + # * {#send_off}, {#send_off!}, and {#<<} are appropriate for actions that + # may block on IO + # * {#send_via} and {#send_via!} are used when a specific executor is to + # be used for the action + # + # @param [Array] args zero or more arguments to be passed to + # the action + # @param [Proc] action the action dispatch to be enqueued + # + # @yield [agent, value, *args] process the old value and return the new + # @yieldparam [Object] value the current {#value} of the Agent + # @yieldparam [Array] args zero or more arguments to pass to the + # action + # @yieldreturn [Object] the new value of the Agent + # + # @!macro send_return + # @return [Boolean] true if the action is successfully enqueued, false if + # the Agent is {#failed?} + def send(*args, &action) + enqueue_action_job(action, args, Concurrent.global_fast_executor) + end + + # @!macro agent_send + # + # @!macro send_bang_return_and_raise + # @return [Boolean] true if the action is successfully enqueued + # @raise [Concurrent::Agent::Error] if the Agent is {#failed?} + def send!(*args, &action) + raise Error.new unless send(*args, &action) + true + end + + # @!macro agent_send + # @!macro send_return + def send_off(*args, &action) + enqueue_action_job(action, args, Concurrent.global_io_executor) + end + + alias_method :post, :send_off + + # @!macro agent_send + # @!macro send_bang_return_and_raise + def send_off!(*args, &action) + raise Error.new unless send_off(*args, &action) + true + end + + # @!macro agent_send + # @!macro send_return + # @param [Concurrent::ExecutorService] executor the executor on which the + # action is to be dispatched + def send_via(executor, *args, &action) + enqueue_action_job(action, args, executor) + end + + # @!macro agent_send + # @!macro send_bang_return_and_raise + # @param [Concurrent::ExecutorService] executor the executor on which the + # action is to be dispatched + def send_via!(executor, *args, &action) + raise Error.new unless send_via(executor, *args, &action) + true + end + + # Dispatches an action to the Agent and returns immediately. Subsequently, + # in a thread from a thread pool, the {#value} will be set to the return + # value of the action. Appropriate for actions that may block on IO. + # + # @param [Proc] action the action dispatch to be enqueued + # @return [Concurrent::Agent] self + # @see #send_off + def <<(action) + send_off(&action) + self + end + + # Blocks the current thread (indefinitely!) until all actions dispatched + # thus far, from this thread or nested by the Agent, have occurred. Will + # block when {#failed?}. Will never return if a failed Agent is {#restart} + # with `:clear_actions` true. + # + # Returns a reference to `self` to support method chaining: + # + # ``` + # current_value = agent.await.value + # ``` + # + # @return [Boolean] self + # + # @!macro agent_await_warning + def await + wait(nil) + self + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def await_for(timeout) + wait(timeout.to_f) + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout + # + # @raise [Concurrent::TimeoutError] when timeout is reached + # + # @!macro agent_await_warning + def await_for!(timeout) + raise Concurrent::TimeoutError unless wait(timeout.to_f) + true + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. Will block indefinitely when timeout is nil or not given. + # + # Provided mainly for consistency with other classes in this library. Prefer + # the various `await` methods instead. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def wait(timeout = nil) + latch = Concurrent::CountDownLatch.new(1) + enqueue_await_job(latch) + latch.wait(timeout) + end + + # Is the Agent in a failed state? + # + # @see #restart + def failed? + !@error.value.nil? + end + + alias_method :stopped?, :failed? + + # When an Agent is {#failed?}, changes the Agent {#value} to `new_value` + # then un-fails the Agent so that action dispatches are allowed again. If + # the `:clear_actions` option is give and true, any actions queued on the + # Agent that were being held while it was failed will be discarded, + # otherwise those held actions will proceed. The `new_value` must pass the + # validator if any, or `restart` will raise an exception and the Agent will + # remain failed with its old {#value} and {#error}. Observers, if any, will + # not be notified of the new state. + # + # @param [Object] new_value the new value for the Agent once restarted + # @param [Hash] opts the configuration options + # @option opts [Symbol] :clear_actions true if all enqueued but unprocessed + # actions should be discarded on restart, else false (default: false) + # @return [Boolean] true + # + # @raise [Concurrent:AgentError] when not failed + def restart(new_value, opts = {}) + clear_actions = opts.fetch(:clear_actions, false) + synchronize do + raise Error.new('agent is not failed') unless failed? + raise ValidationError unless ns_validate(new_value) + @current.value = new_value + @error.value = nil + @queue.clear if clear_actions + ns_post_next_job unless @queue.empty? + end + true + end + + class << self + + # Blocks the current thread (indefinitely!) until all actions dispatched + # thus far to all the given Agents, from this thread or nested by the + # given Agents, have occurred. Will block when any of the agents are + # failed. Will never return if a failed Agent is restart with + # `:clear_actions` true. + # + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true + # + # @!macro agent_await_warning + def await(*agents) + agents.each { |agent| agent.await } + true + end + + # Blocks the current thread until all actions dispatched thus far to all + # the given Agents, from this thread or nested by the given Agents, have + # occurred, or the timeout (in seconds) has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def await_for(timeout, *agents) + end_at = Concurrent.monotonic_time + timeout.to_f + ok = agents.length.times do |i| + break false if (delay = end_at - Concurrent.monotonic_time) < 0 + break false unless agents[i].await_for(delay) + end + !!ok + end + + # Blocks the current thread until all actions dispatched thus far to all + # the given Agents, from this thread or nested by the given Agents, have + # occurred, or the timeout (in seconds) has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true if all actions complete before timeout + # + # @raise [Concurrent::TimeoutError] when timeout is reached + # @!macro agent_await_warning + def await_for!(timeout, *agents) + raise Concurrent::TimeoutError unless await_for(timeout, *agents) + true + end + end + + private + + def ns_initialize(initial, opts) + @error_mode = opts[:error_mode] + @error_handler = opts[:error_handler] + + if @error_mode && !ERROR_MODES.include?(@error_mode) + raise ArgumentError.new('unrecognized error mode') + elsif @error_mode.nil? + @error_mode = @error_handler ? :continue : :fail + end + + @error_handler ||= DEFAULT_ERROR_HANDLER + @validator = opts.fetch(:validator, DEFAULT_VALIDATOR) + @current = Concurrent::AtomicReference.new(initial) + @error = Concurrent::AtomicReference.new(nil) + @caller = Concurrent::ThreadLocalVar.new(nil) + @queue = [] + + self.observers = Collection::CopyOnNotifyObserverSet.new + end + + def enqueue_action_job(action, args, executor) + raise ArgumentError.new('no action given') unless action + job = Job.new(action, args, executor, @caller.value || Thread.current.object_id) + synchronize { ns_enqueue_job(job) } + end + + def enqueue_await_job(latch) + synchronize do + if (index = ns_find_last_job_for_thread) + job = Job.new(AWAIT_ACTION, [latch], Concurrent.global_immediate_executor, + Thread.current.object_id) + ns_enqueue_job(job, index+1) + else + latch.count_down + true + end + end + end + + def ns_enqueue_job(job, index = nil) + # a non-nil index means this is an await job + return false if index.nil? && failed? + index ||= @queue.length + @queue.insert(index, job) + # if this is the only job, post to executor + ns_post_next_job if @queue.length == 1 + true + end + + def ns_post_next_job + @queue.first.executor.post { execute_next_job } + end + + def execute_next_job + job = synchronize { @queue.first } + old_value = @current.value + + @caller.value = job.caller # for nested actions + new_value = job.action.call(old_value, *job.args) + @caller.value = nil + + return if new_value == AWAIT_FLAG + + if ns_validate(new_value) + @current.value = new_value + observers.notify_observers(Time.now, old_value, new_value) + else + handle_error(ValidationError.new) + end + rescue => error + handle_error(error) + ensure + synchronize do + @queue.shift + unless failed? || @queue.empty? + ns_post_next_job + end + end + end + + def ns_validate(value) + @validator.call(value) + rescue + false + end + + def handle_error(error) + # stop new jobs from posting + @error.value = error if @error_mode == :fail + @error_handler.call(self, error) + rescue + # do nothing + end + + def ns_find_last_job_for_thread + @queue.rindex { |job| job.caller == Thread.current.object_id } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/array.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/array.rb new file mode 100644 index 00000000..c8761af8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/array.rb @@ -0,0 +1,56 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!macro concurrent_array + # + # A thread-safe subclass of Array. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`. + # + # @note `a += b` is **not** a **thread-safe** operation on + # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array` + # which is concatenation of `a` and `b`, then it writes the concatenation to `a`. + # The read and write are independent operations they do not form a single atomic + # operation therefore when two `+=` operations are executed concurrently updates + # may be lost. Use `#concat` instead. + # + # @see http://ruby-doc.org/core/Array.html Ruby standard library `Array` + + # @!macro internal_implementation_note + ArrayImplementation = case + when Concurrent.on_cruby? + # Array is not fully thread-safe on CRuby, see + # https://github.com/ruby-concurrency/concurrent-ruby/issues/929 + # So we will need to add synchronization here + ::Array + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubyArray < ::Array + include JRuby::Synchronized + end + JRubyArray + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubyArray < ::Array + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyArray + TruffleRubyArray + + else + warn 'Possibly unsupported Ruby implementation' + ::Array + end + private_constant :ArrayImplementation + + # @!macro concurrent_array + class Array < ArrayImplementation + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/async.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/async.rb new file mode 100644 index 00000000..97c5a6b2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/async.rb @@ -0,0 +1,449 @@ +require 'concurrent/configuration' +require 'concurrent/ivar' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A mixin module that provides simple asynchronous behavior to a class, + # turning it into a simple actor. Loosely based on Erlang's + # [gen_server](http://www.erlang.org/doc/man/gen_server.html), but without + # supervision or linking. + # + # A more feature-rich {Concurrent::Actor} is also available when the + # capabilities of `Async` are too limited. + # + # ```cucumber + # Feature: + # As a stateful, plain old Ruby class + # I want safe, asynchronous behavior + # So my long-running methods don't block the main thread + # ``` + # + # The `Async` module is a way to mix simple yet powerful asynchronous + # capabilities into any plain old Ruby object or class, turning each object + # into a simple Actor. Method calls are processed on a background thread. The + # caller is free to perform other actions while processing occurs in the + # background. + # + # Method calls to the asynchronous object are made via two proxy methods: + # `async` (alias `cast`) and `await` (alias `call`). These proxy methods post + # the method call to the object's background thread and return a "future" + # which will eventually contain the result of the method call. + # + # This behavior is loosely patterned after Erlang's `gen_server` behavior. + # When an Erlang module implements the `gen_server` behavior it becomes + # inherently asynchronous. The `start` or `start_link` function spawns a + # process (similar to a thread but much more lightweight and efficient) and + # returns the ID of the process. Using the process ID, other processes can + # send messages to the `gen_server` via the `cast` and `call` methods. Unlike + # Erlang's `gen_server`, however, `Async` classes do not support linking or + # supervision trees. + # + # ## Basic Usage + # + # When this module is mixed into a class, objects of the class become inherently + # asynchronous. Each object gets its own background thread on which to post + # asynchronous method calls. Asynchronous method calls are executed in the + # background one at a time in the order they are received. + # + # To create an asynchronous class, simply mix in the `Concurrent::Async` module: + # + # ``` + # class Hello + # include Concurrent::Async + # + # def hello(name) + # "Hello, #{name}!" + # end + # end + # ``` + # + # Mixing this module into a class provides each object two proxy methods: + # `async` and `await`. These methods are thread safe with respect to the + # enclosing object. The former proxy allows methods to be called + # asynchronously by posting to the object's internal thread. The latter proxy + # allows a method to be called synchronously but does so safely with respect + # to any pending asynchronous method calls and ensures proper ordering. Both + # methods return a {Concurrent::IVar} which can be inspected for the result + # of the proxied method call. Calling a method with `async` will return a + # `:pending` `IVar` whereas `await` will return a `:complete` `IVar`. + # + # ``` + # class Echo + # include Concurrent::Async + # + # def echo(msg) + # print "#{msg}\n" + # end + # end + # + # horn = Echo.new + # horn.echo('zero') # synchronous, not thread-safe + # # returns the actual return value of the method + # + # horn.async.echo('one') # asynchronous, non-blocking, thread-safe + # # returns an IVar in the :pending state + # + # horn.await.echo('two') # synchronous, blocking, thread-safe + # # returns an IVar in the :complete state + # ``` + # + # ## Let It Fail + # + # The `async` and `await` proxy methods have built-in error protection based + # on Erlang's famous "let it fail" philosophy. Instance methods should not be + # programmed defensively. When an exception is raised by a delegated method + # the proxy will rescue the exception, expose it to the caller as the `reason` + # attribute of the returned future, then process the next method call. + # + # ## Calling Methods Internally + # + # External method calls should *always* use the `async` and `await` proxy + # methods. When one method calls another method, the `async` proxy should + # rarely be used and the `await` proxy should *never* be used. + # + # When an object calls one of its own methods using the `await` proxy the + # second call will be enqueued *behind* the currently running method call. + # Any attempt to wait on the result will fail as the second call will never + # run until after the current call completes. + # + # Calling a method using the `await` proxy from within a method that was + # itself called using `async` or `await` will irreversibly deadlock the + # object. Do *not* do this, ever. + # + # ## Instance Variables and Attribute Accessors + # + # Instance variables do not need to be thread-safe so long as they are private. + # Asynchronous method calls are processed in the order they are received and + # are processed one at a time. Therefore private instance variables can only + # be accessed by one thread at a time. This is inherently thread-safe. + # + # When using private instance variables within asynchronous methods, the best + # practice is to read the instance variable into a local variable at the start + # of the method then update the instance variable at the *end* of the method. + # This way, should an exception be raised during method execution the internal + # state of the object will not have been changed. + # + # ### Reader Attributes + # + # The use of `attr_reader` is discouraged. Internal state exposed externally, + # when necessary, should be done through accessor methods. The instance + # variables exposed by these methods *must* be thread-safe, or they must be + # called using the `async` and `await` proxy methods. These two approaches are + # subtly different. + # + # When internal state is accessed via the `async` and `await` proxy methods, + # the returned value represents the object's state *at the time the call is + # processed*, which may *not* be the state of the object at the time the call + # is made. + # + # To get the state *at the current* time, irrespective of an enqueued method + # calls, a reader method must be called directly. This is inherently unsafe + # unless the instance variable is itself thread-safe, preferably using one + # of the thread-safe classes within this library. Because the thread-safe + # classes within this library are internally-locking or non-locking, they can + # be safely used from within asynchronous methods without causing deadlocks. + # + # Generally speaking, the best practice is to *not* expose internal state via + # reader methods. The best practice is to simply use the method's return value. + # + # ### Writer Attributes + # + # Writer attributes should never be used with asynchronous classes. Changing + # the state externally, even when done in the thread-safe way, is not logically + # consistent. Changes to state need to be timed with respect to all asynchronous + # method calls which my be in-process or enqueued. The only safe practice is to + # pass all necessary data to each method as arguments and let the method update + # the internal state as necessary. + # + # ## Class Constants, Variables, and Methods + # + # ### Class Constants + # + # Class constants do not need to be thread-safe. Since they are read-only and + # immutable they may be safely read both externally and from within + # asynchronous methods. + # + # ### Class Variables + # + # Class variables should be avoided. Class variables represent shared state. + # Shared state is anathema to concurrency. Should there be a need to share + # state using class variables they *must* be thread-safe, preferably + # using the thread-safe classes within this library. When updating class + # variables, never assign a new value/object to the variable itself. Assignment + # is not thread-safe in Ruby. Instead, use the thread-safe update functions + # of the variable itself to change the value. + # + # The best practice is to *never* use class variables with `Async` classes. + # + # ### Class Methods + # + # Class methods which are pure functions are safe. Class methods which modify + # class variables should be avoided, for all the reasons listed above. + # + # ## An Important Note About Thread Safe Guarantees + # + # > Thread safe guarantees can only be made when asynchronous method calls + # > are not mixed with direct method calls. Use only direct method calls + # > when the object is used exclusively on a single thread. Use only + # > `async` and `await` when the object is shared between threads. Once you + # > call a method using `async` or `await`, you should no longer call methods + # > directly on the object. Use `async` and `await` exclusively from then on. + # + # @example + # + # class Echo + # include Concurrent::Async + # + # def echo(msg) + # print "#{msg}\n" + # end + # end + # + # horn = Echo.new + # horn.echo('zero') # synchronous, not thread-safe + # # returns the actual return value of the method + # + # horn.async.echo('one') # asynchronous, non-blocking, thread-safe + # # returns an IVar in the :pending state + # + # horn.await.echo('two') # synchronous, blocking, thread-safe + # # returns an IVar in the :complete state + # + # @see Concurrent::Actor + # @see https://en.wikipedia.org/wiki/Actor_model "Actor Model" at Wikipedia + # @see http://www.erlang.org/doc/man/gen_server.html Erlang gen_server + # @see http://c2.com/cgi/wiki?LetItCrash "Let It Crash" at http://c2.com/ + module Async + + # @!method self.new(*args, &block) + # + # Instantiate a new object and ensure proper initialization of the + # synchronization mechanisms. + # + # @param [Array] args Zero or more arguments to be passed to the + # object's initializer. + # @param [Proc] block Optional block to pass to the object's initializer. + # @return [Object] A properly initialized object of the asynchronous class. + + # Check for the presence of a method on an object and determine if a given + # set of arguments matches the required arity. + # + # @param [Object] obj the object to check against + # @param [Symbol] method the method to check the object for + # @param [Array] args zero or more arguments for the arity check + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + # + # @note This check is imperfect because of the way Ruby reports the arity of + # methods with a variable number of arguments. It is possible to determine + # if too few arguments are given but impossible to determine if too many + # arguments are given. This check may also fail to recognize dynamic behavior + # of the object, such as methods simulated with `method_missing`. + # + # @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity + # @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to? + # @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing + # + # @!visibility private + def self.validate_argc(obj, method, *args) + argc = args.length + arity = obj.method(method).arity + + if arity >= 0 && argc != arity + raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity})") + elsif arity < 0 && (arity = (arity + 1).abs) > argc + raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity}..*)") + end + end + + # @!visibility private + def self.included(base) + base.singleton_class.send(:alias_method, :original_new, :new) + base.extend(ClassMethods) + super(base) + end + + # @!visibility private + module ClassMethods + def new(*args, &block) + obj = original_new(*args, &block) + obj.send(:init_synchronization) + obj + end + ruby2_keywords :new if respond_to?(:ruby2_keywords, true) + end + private_constant :ClassMethods + + # Delegates asynchronous, thread-safe method calls to the wrapped object. + # + # @!visibility private + class AsyncDelegator < Synchronization::LockableObject + safe_initialization! + + # Create a new delegator object wrapping the given delegate. + # + # @param [Object] delegate the object to wrap and delegate method calls to + def initialize(delegate) + super() + @delegate = delegate + @queue = [] + @executor = Concurrent.global_io_executor + @ruby_pid = $$ + end + + # Delegates method calls to the wrapped object. + # + # @param [Symbol] method the method being called + # @param [Array] args zero or more arguments to the method + # + # @return [IVar] the result of the method call + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + def method_missing(method, *args, &block) + super unless @delegate.respond_to?(method) + Async::validate_argc(@delegate, method, *args) + + ivar = Concurrent::IVar.new + synchronize do + reset_if_forked + @queue.push [ivar, method, args, block] + @executor.post { perform } if @queue.length == 1 + end + + ivar + end + + # Check whether the method is responsive + # + # @param [Symbol] method the method being called + def respond_to_missing?(method, include_private = false) + @delegate.respond_to?(method) || super + end + + # Perform all enqueued tasks. + # + # This method must be called from within the executor. It must not be + # called while already running. It will loop until the queue is empty. + def perform + loop do + ivar, method, args, block = synchronize { @queue.first } + break unless ivar # queue is empty + + begin + ivar.set(@delegate.send(method, *args, &block)) + rescue => error + ivar.fail(error) + end + + synchronize do + @queue.shift + return if @queue.empty? + end + end + end + + def reset_if_forked + if $$ != @ruby_pid + @queue.clear + @ruby_pid = $$ + end + end + end + private_constant :AsyncDelegator + + # Delegates synchronous, thread-safe method calls to the wrapped object. + # + # @!visibility private + class AwaitDelegator + + # Create a new delegator object wrapping the given delegate. + # + # @param [AsyncDelegator] delegate the object to wrap and delegate method calls to + def initialize(delegate) + @delegate = delegate + end + + # Delegates method calls to the wrapped object. + # + # @param [Symbol] method the method being called + # @param [Array] args zero or more arguments to the method + # + # @return [IVar] the result of the method call + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + def method_missing(method, *args, &block) + ivar = @delegate.send(method, *args, &block) + ivar.wait + ivar + end + + # Check whether the method is responsive + # + # @param [Symbol] method the method being called + def respond_to_missing?(method, include_private = false) + @delegate.respond_to?(method) || super + end + end + private_constant :AwaitDelegator + + # Causes the chained method call to be performed asynchronously on the + # object's thread. The delegated method will return a future in the + # `:pending` state and the method call will have been scheduled on the + # object's thread. The final disposition of the method call can be obtained + # by inspecting the returned future. + # + # @!macro async_thread_safety_warning + # @note The method call is guaranteed to be thread safe with respect to + # all other method calls against the same object that are called with + # either `async` or `await`. The mutable nature of Ruby references + # (and object orientation in general) prevent any other thread safety + # guarantees. Do NOT mix direct method calls with delegated method calls. + # Use *only* delegated method calls when sharing the object between threads. + # + # @return [Concurrent::IVar] the pending result of the asynchronous operation + # + # @raise [NameError] the object does not respond to the requested method + # @raise [ArgumentError] the given `args` do not match the arity of + # the requested method + def async + @__async_delegator__ + end + alias_method :cast, :async + + # Causes the chained method call to be performed synchronously on the + # current thread. The delegated will return a future in either the + # `:fulfilled` or `:rejected` state and the delegated method will have + # completed. The final disposition of the delegated method can be obtained + # by inspecting the returned future. + # + # @!macro async_thread_safety_warning + # + # @return [Concurrent::IVar] the completed result of the synchronous operation + # + # @raise [NameError] the object does not respond to the requested method + # @raise [ArgumentError] the given `args` do not match the arity of the + # requested method + def await + @__await_delegator__ + end + alias_method :call, :await + + # Initialize the internal serializer and other stnchronization mechanisms. + # + # @note This method *must* be called immediately upon object construction. + # This is the only way thread-safe initialization can be guaranteed. + # + # @!visibility private + def init_synchronization + return self if defined?(@__async_initialized__) && @__async_initialized__ + @__async_initialized__ = true + @__async_delegator__ = AsyncDelegator.new(self) + @__await_delegator__ = AwaitDelegator.new(@__async_delegator__) + self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atom.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atom.rb new file mode 100644 index 00000000..f590a23d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atom.rb @@ -0,0 +1,222 @@ +require 'concurrent/atomic/atomic_reference' +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/concern/observable' +require 'concurrent/synchronization/object' + +# @!macro thread_safe_variable_comparison +# +# ## Thread-safe Variable Classes +# +# Each of the thread-safe variable classes is designed to solve a different +# problem. In general: +# +# * *{Concurrent::Agent}:* Shared, mutable variable providing independent, +# uncoordinated, *asynchronous* change of individual values. Best used when +# the value will undergo frequent, complex updates. Suitable when the result +# of an update does not need to be known immediately. +# * *{Concurrent::Atom}:* Shared, mutable variable providing independent, +# uncoordinated, *synchronous* change of individual values. Best used when +# the value will undergo frequent reads but only occasional, though complex, +# updates. Suitable when the result of an update must be known immediately. +# * *{Concurrent::AtomicReference}:* A simple object reference that can be updated +# atomically. Updates are synchronous but fast. Best used when updates a +# simple set operations. Not suitable when updates are complex. +# {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar +# but optimized for the given data type. +# * *{Concurrent::Exchanger}:* Shared, stateless synchronization point. Used +# when two or more threads need to exchange data. The threads will pair then +# block on each other until the exchange is complete. +# * *{Concurrent::MVar}:* Shared synchronization point. Used when one thread +# must give a value to another, which must take the value. The threads will +# block on each other until the exchange is complete. +# * *{Concurrent::ThreadLocalVar}:* Shared, mutable, isolated variable which +# holds a different value for each thread which has access. Often used as +# an instance variable in objects which must maintain different state +# for different threads. +# * *{Concurrent::TVar}:* Shared, mutable variables which provide +# *coordinated*, *synchronous*, change of *many* stated. Used when multiple +# value must change together, in an all-or-nothing transaction. + + +module Concurrent + + # Atoms provide a way to manage shared, synchronous, independent state. + # + # An atom is initialized with an initial value and an optional validation + # proc. At any time the value of the atom can be synchronously and safely + # changed. If a validator is given at construction then any new value + # will be checked against the validator and will be rejected if the + # validator returns false or raises an exception. + # + # There are two ways to change the value of an atom: {#compare_and_set} and + # {#swap}. The former will set the new value if and only if it validates and + # the current value matches the new value. The latter will atomically set the + # new value to the result of running the given block if and only if that + # value validates. + # + # ## Example + # + # ``` + # def next_fibonacci(set = nil) + # return [0, 1] if set.nil? + # set + [set[-2..-1].reduce{|sum,x| sum + x }] + # end + # + # # create an atom with an initial value + # atom = Concurrent::Atom.new(next_fibonacci) + # + # # send a few update requests + # 5.times do + # atom.swap{|set| next_fibonacci(set) } + # end + # + # # get the current value + # atom.value #=> [0, 1, 1, 2, 3, 5, 8] + # ``` + # + # ## Observation + # + # Atoms support observers through the {Concurrent::Observable} mixin module. + # Notification of observers occurs every time the value of the Atom changes. + # When notified the observer will receive three arguments: `time`, `old_value`, + # and `new_value`. The `time` argument is the time at which the value change + # occurred. The `old_value` is the value of the Atom when the change began + # The `new_value` is the value to which the Atom was set when the change + # completed. Note that `old_value` and `new_value` may be the same. This is + # not an error. It simply means that the change operation returned the same + # value. + # + # Unlike in Clojure, `Atom` cannot participate in {Concurrent::TVar} transactions. + # + # @!macro thread_safe_variable_comparison + # + # @see http://clojure.org/atoms Clojure Atoms + # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State + class Atom < Synchronization::Object + include Concern::Observable + + safe_initialization! + attr_atomic(:value) + private :value=, :swap_value, :compare_and_set_value, :update_value + public :value + alias_method :deref, :value + + # @!method value + # The current value of the atom. + # + # @return [Object] The current value. + + # Create a new atom with the given initial value. + # + # @param [Object] value The initial value + # @param [Hash] opts The options used to configure the atom + # @option opts [Proc] :validator (nil) Optional proc used to validate new + # values. It must accept one and only one argument which will be the + # intended new value. The validator will return true if the new value + # is acceptable else return false (preferably) or raise an exception. + # + # @!macro deref_options + # + # @raise [ArgumentError] if the validator is not a `Proc` (when given) + def initialize(value, opts = {}) + super() + @Validator = opts.fetch(:validator, -> v { true }) + self.observers = Collection::CopyOnNotifyObserverSet.new + self.value = value + end + + # Atomically swaps the value of atom using the given block. The current + # value will be passed to the block, as will any arguments passed as + # arguments to the function. The new value will be validated against the + # (optional) validator proc given at construction. If validation fails the + # value will not be changed. + # + # Internally, {#swap} reads the current value, applies the block to it, and + # attempts to compare-and-set it in. Since another thread may have changed + # the value in the intervening time, it may have to retry, and does so in a + # spin loop. The net effect is that the value will always be the result of + # the application of the supplied block to a current value, atomically. + # However, because the block might be called multiple times, it must be free + # of side effects. + # + # @note The given block may be called multiple times, and thus should be free + # of side effects. + # + # @param [Object] args Zero or more arguments passed to the block. + # + # @yield [value, args] Calculates a new value for the atom based on the + # current value and any supplied arguments. + # @yieldparam value [Object] The current value of the atom. + # @yieldparam args [Object] All arguments passed to the function, in order. + # @yieldreturn [Object] The intended new value of the atom. + # + # @return [Object] The final value of the atom after all operations and + # validations are complete. + # + # @raise [ArgumentError] When no block is given. + def swap(*args) + raise ArgumentError.new('no block given') unless block_given? + + loop do + old_value = value + new_value = yield(old_value, *args) + begin + break old_value unless valid?(new_value) + break new_value if compare_and_set(old_value, new_value) + rescue + break old_value + end + end + end + + # Atomically sets the value of atom to the new value if and only if the + # current value of the atom is identical to the old value and the new + # value successfully validates against the (optional) validator given + # at construction. + # + # @param [Object] old_value The expected current value. + # @param [Object] new_value The intended new value. + # + # @return [Boolean] True if the value is changed else false. + def compare_and_set(old_value, new_value) + if valid?(new_value) && compare_and_set_value(old_value, new_value) + observers.notify_observers(Time.now, old_value, new_value) + true + else + false + end + end + + # Atomically sets the value of atom to the new value without regard for the + # current value so long as the new value successfully validates against the + # (optional) validator given at construction. + # + # @param [Object] new_value The intended new value. + # + # @return [Object] The final value of the atom after all operations and + # validations are complete. + def reset(new_value) + old_value = value + if valid?(new_value) + self.value = new_value + observers.notify_observers(Time.now, old_value, new_value) + new_value + else + old_value + end + end + + private + + # Is the new value valid? + # + # @param [Object] new_value The intended new value. + # @return [Boolean] false if the validator function returns false or raises + # an exception else true + def valid?(new_value) + @Validator.call(new_value) + rescue + false + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb new file mode 100644 index 00000000..f775691a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb @@ -0,0 +1,127 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic/mutex_atomic_boolean' + +module Concurrent + + ################################################################### + + # @!macro atomic_boolean_method_initialize + # + # Creates a new `AtomicBoolean` with the given initial value. + # + # @param [Boolean] initial the initial value + + # @!macro atomic_boolean_method_value_get + # + # Retrieves the current `Boolean` value. + # + # @return [Boolean] the current value + + # @!macro atomic_boolean_method_value_set + # + # Explicitly sets the value. + # + # @param [Boolean] value the new value to be set + # + # @return [Boolean] the current value + + # @!macro atomic_boolean_method_true_question + # + # Is the current value `true` + # + # @return [Boolean] true if the current value is `true`, else false + + # @!macro atomic_boolean_method_false_question + # + # Is the current value `false` + # + # @return [Boolean] true if the current value is `false`, else false + + # @!macro atomic_boolean_method_make_true + # + # Explicitly sets the value to true. + # + # @return [Boolean] true if value has changed, otherwise false + + # @!macro atomic_boolean_method_make_false + # + # Explicitly sets the value to false. + # + # @return [Boolean] true if value has changed, otherwise false + + ################################################################### + + # @!macro atomic_boolean_public_api + # + # @!method initialize(initial = false) + # @!macro atomic_boolean_method_initialize + # + # @!method value + # @!macro atomic_boolean_method_value_get + # + # @!method value=(value) + # @!macro atomic_boolean_method_value_set + # + # @!method true? + # @!macro atomic_boolean_method_true_question + # + # @!method false? + # @!macro atomic_boolean_method_false_question + # + # @!method make_true + # @!macro atomic_boolean_method_make_true + # + # @!method make_false + # @!macro atomic_boolean_method_make_false + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + AtomicBooleanImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + CAtomicBoolean + when Concurrent.on_jruby? + JavaAtomicBoolean + else + MutexAtomicBoolean + end + private_constant :AtomicBooleanImplementation + + # @!macro atomic_boolean + # + # A boolean value that can be updated atomically. Reads and writes to an atomic + # boolean and thread-safe and guaranteed to succeed. Reads and writes may block + # briefly but no explicit locking is required. + # + # @!macro thread_safe_variable_comparison + # + # Performance: + # + # ``` + # Testing with ruby 2.1.2 + # Testing with Concurrent::MutexAtomicBoolean... + # 2.790000 0.000000 2.790000 ( 2.791454) + # Testing with Concurrent::CAtomicBoolean... + # 0.740000 0.000000 0.740000 ( 0.740206) + # + # Testing with jruby 1.9.3 + # Testing with Concurrent::MutexAtomicBoolean... + # 5.240000 2.520000 7.760000 ( 3.683000) + # Testing with Concurrent::JavaAtomicBoolean... + # 3.340000 0.010000 3.350000 ( 0.855000) + # ``` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean + # + # @!macro atomic_boolean_public_api + class AtomicBoolean < AtomicBooleanImplementation + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], value + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb new file mode 100644 index 00000000..26cd05d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb @@ -0,0 +1,144 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic/mutex_atomic_fixnum' + +module Concurrent + + ################################################################### + + # @!macro atomic_fixnum_method_initialize + # + # Creates a new `AtomicFixnum` with the given initial value. + # + # @param [Fixnum] initial the initial value + # @raise [ArgumentError] if the initial value is not a `Fixnum` + + # @!macro atomic_fixnum_method_value_get + # + # Retrieves the current `Fixnum` value. + # + # @return [Fixnum] the current value + + # @!macro atomic_fixnum_method_value_set + # + # Explicitly sets the value. + # + # @param [Fixnum] value the new value to be set + # + # @return [Fixnum] the current value + # + # @raise [ArgumentError] if the new value is not a `Fixnum` + + # @!macro atomic_fixnum_method_increment + # + # Increases the current value by the given amount (defaults to 1). + # + # @param [Fixnum] delta the amount by which to increase the current value + # + # @return [Fixnum] the current value after incrementation + + # @!macro atomic_fixnum_method_decrement + # + # Decreases the current value by the given amount (defaults to 1). + # + # @param [Fixnum] delta the amount by which to decrease the current value + # + # @return [Fixnum] the current value after decrementation + + # @!macro atomic_fixnum_method_compare_and_set + # + # Atomically sets the value to the given updated value if the current + # value == the expected value. + # + # @param [Fixnum] expect the expected value + # @param [Fixnum] update the new value + # + # @return [Boolean] true if the value was updated else false + + # @!macro atomic_fixnum_method_update + # + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # + # @return [Object] the new value + + ################################################################### + + # @!macro atomic_fixnum_public_api + # + # @!method initialize(initial = 0) + # @!macro atomic_fixnum_method_initialize + # + # @!method value + # @!macro atomic_fixnum_method_value_get + # + # @!method value=(value) + # @!macro atomic_fixnum_method_value_set + # + # @!method increment(delta = 1) + # @!macro atomic_fixnum_method_increment + # + # @!method decrement(delta = 1) + # @!macro atomic_fixnum_method_decrement + # + # @!method compare_and_set(expect, update) + # @!macro atomic_fixnum_method_compare_and_set + # + # @!method update + # @!macro atomic_fixnum_method_update + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + AtomicFixnumImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + CAtomicFixnum + when Concurrent.on_jruby? + JavaAtomicFixnum + else + MutexAtomicFixnum + end + private_constant :AtomicFixnumImplementation + + # @!macro atomic_fixnum + # + # A numeric value that can be updated atomically. Reads and writes to an atomic + # fixnum and thread-safe and guaranteed to succeed. Reads and writes may block + # briefly but no explicit locking is required. + # + # @!macro thread_safe_variable_comparison + # + # Performance: + # + # ``` + # Testing with ruby 2.1.2 + # Testing with Concurrent::MutexAtomicFixnum... + # 3.130000 0.000000 3.130000 ( 3.136505) + # Testing with Concurrent::CAtomicFixnum... + # 0.790000 0.000000 0.790000 ( 0.785550) + # + # Testing with jruby 1.9.3 + # Testing with Concurrent::MutexAtomicFixnum... + # 5.460000 2.460000 7.920000 ( 3.715000) + # Testing with Concurrent::JavaAtomicFixnum... + # 4.520000 0.030000 4.550000 ( 1.187000) + # ``` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong + # + # @!macro atomic_fixnum_public_api + class AtomicFixnum < AtomicFixnumImplementation + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], value + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb new file mode 100644 index 00000000..e16be657 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb @@ -0,0 +1,167 @@ +require 'concurrent/errors' +require 'concurrent/synchronization/object' + +module Concurrent + # An atomic reference which maintains an object reference along with a mark bit + # that can be updated atomically. + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html + # java.util.concurrent.atomic.AtomicMarkableReference + class AtomicMarkableReference < ::Concurrent::Synchronization::Object + + attr_atomic(:reference) + private :reference, :reference=, :swap_reference, :compare_and_set_reference, :update_reference + + def initialize(value = nil, mark = false) + super() + self.reference = immutable_array(value, mark) + end + + # Atomically sets the value and mark to the given updated value and + # mark given both: + # - the current value == the expected value && + # - the current mark == the expected mark + # + # @param [Object] expected_val the expected value + # @param [Object] new_val the new value + # @param [Boolean] expected_mark the expected mark + # @param [Boolean] new_mark the new mark + # + # @return [Boolean] `true` if successful. A `false` return indicates + # that the actual value was not equal to the expected value or the + # actual mark was not equal to the expected mark + def compare_and_set(expected_val, new_val, expected_mark, new_mark) + # Memoize a valid reference to the current AtomicReference for + # later comparison. + current = reference + curr_val, curr_mark = current + + # Ensure that that the expected marks match. + return false unless expected_mark == curr_mark + + if expected_val.is_a? Numeric + # If the object is a numeric, we need to ensure we are comparing + # the numerical values + return false unless expected_val == curr_val + else + # Otherwise, we need to ensure we are comparing the object identity. + # Theoretically, this could be incorrect if a user monkey-patched + # `Object#equal?`, but they should know that they are playing with + # fire at that point. + return false unless expected_val.equal? curr_val + end + + prospect = immutable_array(new_val, new_mark) + + compare_and_set_reference current, prospect + end + + alias_method :compare_and_swap, :compare_and_set + + # Gets the current reference and marked values. + # + # @return [Array] the current reference and marked values + def get + reference + end + + # Gets the current value of the reference + # + # @return [Object] the current value of the reference + def value + reference[0] + end + + # Gets the current marked value + # + # @return [Boolean] the current marked value + def mark + reference[1] + end + + alias_method :marked?, :mark + + # _Unconditionally_ sets to the given value of both the reference and + # the mark. + # + # @param [Object] new_val the new value + # @param [Boolean] new_mark the new mark + # + # @return [Array] both the new value and the new mark + def set(new_val, new_mark) + self.reference = immutable_array(new_val, new_mark) + end + + # Pass the current value and marked state to the given block, replacing it + # with the block's results. May retry if the value changes during the + # block's execution. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and new mark + def update + loop do + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + if compare_and_set old_val, new_val, old_mark, new_mark + return immutable_array(new_val, new_mark) + end + end + end + + # Pass the current value to the given block, replacing it + # with the block's result. Raise an exception if the update + # fails. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and marked state + # + # @raise [Concurrent::ConcurrentUpdateError] if the update fails + def try_update! + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + unless compare_and_set old_val, new_val, old_mark, new_mark + fail ::Concurrent::ConcurrentUpdateError, + 'AtomicMarkableReference: Update failed due to race condition.', + 'Note: If you would like to guarantee an update, please use ' + + 'the `AtomicMarkableReference#update` method.' + end + + immutable_array(new_val, new_mark) + end + + # Pass the current value to the given block, replacing it with the + # block's result. Simply return nil if update fails. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and marked state, or nil if + # the update failed + def try_update + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + return unless compare_and_set old_val, new_val, old_mark, new_mark + + immutable_array(new_val, new_mark) + end + + private + + def immutable_array(*args) + args.freeze + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb new file mode 100644 index 00000000..bb5fb774 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb @@ -0,0 +1,135 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic_reference/atomic_direct_update' +require 'concurrent/atomic_reference/numeric_cas_wrapper' +require 'concurrent/atomic_reference/mutex_atomic' + +# Shim for TruffleRuby::AtomicReference +if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference) + # @!visibility private + module TruffleRuby + AtomicReference = Truffle::AtomicReference + end +end + +module Concurrent + + # @!macro internal_implementation_note + AtomicReferenceImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + # @!visibility private + # @!macro internal_implementation_note + class CAtomicReference + include AtomicDirectUpdate + include AtomicNumericCompareAndSetWrapper + alias_method :compare_and_swap, :compare_and_set + end + CAtomicReference + when Concurrent.on_jruby? + # @!visibility private + # @!macro internal_implementation_note + class JavaAtomicReference + include AtomicDirectUpdate + end + JavaAtomicReference + when Concurrent.on_truffleruby? + class TruffleRubyAtomicReference < TruffleRuby::AtomicReference + include AtomicDirectUpdate + alias_method :value, :get + alias_method :value=, :set + alias_method :compare_and_swap, :compare_and_set + alias_method :swap, :get_and_set + end + TruffleRubyAtomicReference + else + MutexAtomicReference + end + private_constant :AtomicReferenceImplementation + + # An object reference that may be updated atomically. All read and write + # operations have java volatile semantic. + # + # @!macro thread_safe_variable_comparison + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html + # + # @!method initialize(value = nil) + # @!macro atomic_reference_method_initialize + # @param [Object] value The initial value. + # + # @!method get + # @!macro atomic_reference_method_get + # Gets the current value. + # @return [Object] the current value + # + # @!method set(new_value) + # @!macro atomic_reference_method_set + # Sets to the given value. + # @param [Object] new_value the new value + # @return [Object] the new value + # + # @!method get_and_set(new_value) + # @!macro atomic_reference_method_get_and_set + # Atomically sets to the given value and returns the old value. + # @param [Object] new_value the new value + # @return [Object] the old value + # + # @!method compare_and_set(old_value, new_value) + # @!macro atomic_reference_method_compare_and_set + # + # Atomically sets the value to the given updated value if + # the current value == the expected value. + # + # @param [Object] old_value the expected value + # @param [Object] new_value the new value + # + # @return [Boolean] `true` if successful. A `false` return indicates + # that the actual value was not equal to the expected value. + # + # @!method update + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @return [Object] the new value + # + # @!method try_update + # Pass the current value to the given block, replacing it + # with the block's result. Return nil if the update fails. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @note This method was altered to avoid raising an exception by default. + # Instead, this method now returns `nil` in case of failure. For more info, + # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 + # @return [Object] the new value, or nil if update failed + # + # @!method try_update! + # Pass the current value to the given block, replacing it + # with the block's result. Raise an exception if the update + # fails. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @note This behavior mimics the behavior of the original + # `AtomicReference#try_update` API. The reason this was changed was to + # avoid raising exceptions (which are inherently slow) by default. For more + # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 + # @return [Object] the new value + # @raise [Concurrent::ConcurrentUpdateError] if the update fails + class AtomicReference < AtomicReferenceImplementation + + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], get + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb new file mode 100644 index 00000000..d883aed6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb @@ -0,0 +1,100 @@ +require 'concurrent/utility/engine' +require 'concurrent/atomic/mutex_count_down_latch' +require 'concurrent/atomic/java_count_down_latch' + +module Concurrent + + ################################################################### + + # @!macro count_down_latch_method_initialize + # + # Create a new `CountDownLatch` with the initial `count`. + # + # @param [new] count the initial count + # + # @raise [ArgumentError] if `count` is not an integer or is less than zero + + # @!macro count_down_latch_method_wait + # + # Block on the latch until the counter reaches zero or until `timeout` is reached. + # + # @param [Fixnum] timeout the number of seconds to wait for the counter or `nil` + # to block indefinitely + # @return [Boolean] `true` if the `count` reaches zero else false on `timeout` + + # @!macro count_down_latch_method_count_down + # + # Signal the latch to decrement the counter. Will signal all blocked threads when + # the `count` reaches zero. + + # @!macro count_down_latch_method_count + # + # The current value of the counter. + # + # @return [Fixnum] the current value of the counter + + ################################################################### + + # @!macro count_down_latch_public_api + # + # @!method initialize(count = 1) + # @!macro count_down_latch_method_initialize + # + # @!method wait(timeout = nil) + # @!macro count_down_latch_method_wait + # + # @!method count_down + # @!macro count_down_latch_method_count_down + # + # @!method count + # @!macro count_down_latch_method_count + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + CountDownLatchImplementation = case + when Concurrent.on_jruby? + JavaCountDownLatch + else + MutexCountDownLatch + end + private_constant :CountDownLatchImplementation + + # @!macro count_down_latch + # + # A synchronization object that allows one thread to wait on multiple other threads. + # The thread that will wait creates a `CountDownLatch` and sets the initial value + # (normally equal to the number of other threads). The initiating thread passes the + # latch to the other threads then waits for the other threads by calling the `#wait` + # method. Each of the other threads calls `#count_down` when done with its work. + # When the latch counter reaches zero the waiting thread is unblocked and continues + # with its work. A `CountDownLatch` can be used only once. Its value cannot be reset. + # + # @!macro count_down_latch_public_api + # @example Waiter and Decrementer + # latch = Concurrent::CountDownLatch.new(3) + # + # waiter = Thread.new do + # latch.wait() + # puts ("Waiter released") + # end + # + # decrementer = Thread.new do + # sleep(1) + # latch.count_down + # puts latch.count + # + # sleep(1) + # latch.count_down + # puts latch.count + # + # sleep(1) + # latch.count_down + # puts latch.count + # end + # + # [waiter, decrementer].each(&:join) + class CountDownLatch < CountDownLatchImplementation + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb new file mode 100644 index 00000000..9ebe29dd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb @@ -0,0 +1,128 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # A synchronization aid that allows a set of threads to all wait for each + # other to reach a common barrier point. + # @example + # barrier = Concurrent::CyclicBarrier.new(3) + # jobs = Array.new(3) { |i| -> { sleep i; p done: i } } + # process = -> (i) do + # # waiting to start at the same time + # barrier.wait + # # execute job + # jobs[i].call + # # wait for others to finish + # barrier.wait + # end + # threads = 2.times.map do |i| + # Thread.new(i, &process) + # end + # + # # use main as well + # process.call 2 + # + # # here we can be sure that all jobs are processed + class CyclicBarrier < Synchronization::LockableObject + + # @!visibility private + Generation = Struct.new(:status) + private_constant :Generation + + # Create a new `CyclicBarrier` that waits for `parties` threads + # + # @param [Fixnum] parties the number of parties + # @yield an optional block that will be executed that will be executed after + # the last thread arrives and before the others are released + # + # @raise [ArgumentError] if `parties` is not an integer or is less than zero + def initialize(parties, &block) + Utility::NativeInteger.ensure_integer_and_bounds parties + Utility::NativeInteger.ensure_positive_and_no_zero parties + + super(&nil) + synchronize { ns_initialize parties, &block } + end + + # @return [Fixnum] the number of threads needed to pass the barrier + def parties + synchronize { @parties } + end + + # @return [Fixnum] the number of threads currently waiting on the barrier + def number_waiting + synchronize { @number_waiting } + end + + # Blocks on the barrier until the number of waiting threads is equal to + # `parties` or until `timeout` is reached or `reset` is called + # If a block has been passed to the constructor, it will be executed once by + # the last arrived thread before releasing the others + # @param [Fixnum] timeout the number of seconds to wait for the counter or + # `nil` to block indefinitely + # @return [Boolean] `true` if the `count` reaches zero else false on + # `timeout` or on `reset` or if the barrier is broken + def wait(timeout = nil) + synchronize do + + return false unless @generation.status == :waiting + + @number_waiting += 1 + + if @number_waiting == @parties + @action.call if @action + ns_generation_done @generation, :fulfilled + true + else + generation = @generation + if ns_wait_until(timeout) { generation.status != :waiting } + generation.status == :fulfilled + else + ns_generation_done generation, :broken, false + false + end + end + end + end + + # resets the barrier to its initial state + # If there is at least one waiting thread, it will be woken up, the `wait` + # method will return false and the barrier will be broken + # If the barrier is broken, this method restores it to the original state + # + # @return [nil] + def reset + synchronize { ns_generation_done @generation, :reset } + end + + # A barrier can be broken when: + # - a thread called the `reset` method while at least one other thread was waiting + # - at least one thread timed out on `wait` method + # + # A broken barrier can be restored using `reset` it's safer to create a new one + # @return [Boolean] true if the barrier is broken otherwise false + def broken? + synchronize { @generation.status != :waiting } + end + + protected + + def ns_generation_done(generation, status, continue = true) + generation.status = status + ns_next_generation if continue + ns_broadcast + end + + def ns_next_generation + @generation = Generation.new(:waiting) + @number_waiting = 0 + end + + def ns_initialize(parties, &block) + @parties = parties + @action = block + ns_next_generation + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/event.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/event.rb new file mode 100644 index 00000000..ccf84c9d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/event.rb @@ -0,0 +1,109 @@ +require 'thread' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # Old school kernel-style event reminiscent of Win32 programming in C++. + # + # When an `Event` is created it is in the `unset` state. Threads can choose to + # `#wait` on the event, blocking until released by another thread. When one + # thread wants to alert all blocking threads it calls the `#set` method which + # will then wake up all listeners. Once an `Event` has been set it remains set. + # New threads calling `#wait` will return immediately. An `Event` may be + # `#reset` at any time once it has been set. + # + # @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx + # @example + # event = Concurrent::Event.new + # + # t1 = Thread.new do + # puts "t1 is waiting" + # event.wait(1) + # puts "event occurred" + # end + # + # t2 = Thread.new do + # puts "t2 calling set" + # event.set + # end + # + # [t1, t2].each(&:join) + # + # # prints: + # # t1 is waiting + # # t2 calling set + # # event occurred + class Event < Synchronization::LockableObject + + # Creates a new `Event` in the unset state. Threads calling `#wait` on the + # `Event` will block. + def initialize + super + synchronize { ns_initialize } + end + + # Is the object in the set state? + # + # @return [Boolean] indicating whether or not the `Event` has been set + def set? + synchronize { @set } + end + + # Trigger the event, setting the state to `set` and releasing all threads + # waiting on the event. Has no effect if the `Event` has already been set. + # + # @return [Boolean] should always return `true` + def set + synchronize { ns_set } + end + + def try? + synchronize { @set ? false : ns_set } + end + + # Reset a previously set event back to the `unset` state. + # Has no effect if the `Event` has not yet been set. + # + # @return [Boolean] should always return `true` + def reset + synchronize do + if @set + @set = false + @iteration +=1 + end + true + end + end + + # Wait a given number of seconds for the `Event` to be set by another + # thread. Will wait forever when no `timeout` value is given. Returns + # immediately if the `Event` has already been set. + # + # @return [Boolean] true if the `Event` was set before timeout else false + def wait(timeout = nil) + synchronize do + unless @set + iteration = @iteration + ns_wait_until(timeout) { iteration < @iteration || @set } + else + true + end + end + end + + protected + + def ns_set + unless @set + @set = true + ns_broadcast + end + true + end + + def ns_initialize + @set = false + @iteration = 0 + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb new file mode 100644 index 00000000..e90fc24f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb @@ -0,0 +1,109 @@ +require 'concurrent/constants' +require_relative 'locals' + +module Concurrent + + # A `FiberLocalVar` is a variable where the value is different for each fiber. + # Each variable may have a default value, but when you modify the variable only + # the current fiber will ever see that change. + # + # This is similar to Ruby's built-in fiber-local variables (`Thread.current[:name]`), + # but with these major advantages: + # * `FiberLocalVar` has its own identity, it doesn't need a Symbol. + # * Each Ruby's built-in fiber-local variable leaks some memory forever (it's a Symbol held forever on the fiber), + # so it's only OK to create a small amount of them. + # `FiberLocalVar` has no such issue and it is fine to create many of them. + # * Ruby's built-in fiber-local variables leak forever the value set on each fiber (unless set to nil explicitly). + # `FiberLocalVar` automatically removes the mapping for each fiber once the `FiberLocalVar` instance is GC'd. + # + # @example + # v = FiberLocalVar.new(14) + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # + # @example + # v = FiberLocalVar.new(14) + # + # Fiber.new do + # v.value #=> 14 + # v.value = 1 + # v.value #=> 1 + # end.resume + # + # Fiber.new do + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # end.resume + # + # v.value #=> 14 + class FiberLocalVar + LOCALS = FiberLocals.new + + # Creates a fiber local variable. + # + # @param [Object] default the default value when otherwise unset + # @param [Proc] default_block Optional block that gets called to obtain the + # default value for each fiber + def initialize(default = nil, &default_block) + if default && block_given? + raise ArgumentError, "Cannot use both value and block as default value" + end + + if block_given? + @default_block = default_block + @default = nil + else + @default_block = nil + @default = default + end + + @index = LOCALS.next_index(self) + end + + # Returns the value in the current fiber's copy of this fiber-local variable. + # + # @return [Object] the current value + def value + LOCALS.fetch(@index) { default } + end + + # Sets the current fiber's copy of this fiber-local variable to the specified value. + # + # @param [Object] value the value to set + # @return [Object] the new value + def value=(value) + LOCALS.set(@index, value) + end + + # Bind the given value to fiber local storage during + # execution of the given block. + # + # @param [Object] value the value to bind + # @yield the operation to be performed with the bound variable + # @return [Object] the value + def bind(value) + if block_given? + old_value = self.value + self.value = value + begin + yield + ensure + self.value = old_value + end + end + end + + protected + + # @!visibility private + def default + if @default_block + self.value = @default_block.call + else + @default + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb new file mode 100644 index 00000000..3c119bc3 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb @@ -0,0 +1,43 @@ +if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + + module Concurrent + + # @!macro count_down_latch + # @!visibility private + # @!macro internal_implementation_note + class JavaCountDownLatch + + # @!macro count_down_latch_method_initialize + def initialize(count = 1) + Utility::NativeInteger.ensure_integer_and_bounds(count) + Utility::NativeInteger.ensure_positive(count) + @latch = java.util.concurrent.CountDownLatch.new(count) + end + + # @!macro count_down_latch_method_wait + def wait(timeout = nil) + result = nil + if timeout.nil? + Synchronization::JRuby.sleep_interruptibly { @latch.await } + result = true + else + Synchronization::JRuby.sleep_interruptibly do + result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + result + end + + # @!macro count_down_latch_method_count_down + def count_down + @latch.countDown + end + + # @!macro count_down_latch_method_count + def count + @latch.getCount + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/locals.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/locals.rb new file mode 100644 index 00000000..0a276aed --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/locals.rb @@ -0,0 +1,189 @@ +require 'fiber' +require 'concurrent/utility/engine' +require 'concurrent/constants' + +module Concurrent + # @!visibility private + # @!macro internal_implementation_note + # + # An abstract implementation of local storage, with sub-classes for + # per-thread and per-fiber locals. + # + # Each execution context (EC, thread or fiber) has a lazily initialized array + # of local variable values. Each time a new local variable is created, we + # allocate an "index" for it. + # + # For example, if the allocated index is 1, that means slot #1 in EVERY EC's + # locals array will be used for the value of that variable. + # + # The good thing about using a per-EC structure to hold values, rather than + # a global, is that no synchronization is needed when reading and writing + # those values (since the structure is only ever accessed by a single + # thread). + # + # Of course, when a local variable is GC'd, 1) we need to recover its index + # for use by other new local variables (otherwise the locals arrays could + # get bigger and bigger with time), and 2) we need to null out all the + # references held in the now-unused slots (both to avoid blocking GC of those + # objects, and also to prevent "stale" values from being passed on to a new + # local when the index is reused). + # + # Because we need to null out freed slots, we need to keep references to + # ALL the locals arrays, so we can null out the appropriate slots in all of + # them. This is why we need to use a finalizer to clean up the locals array + # when the EC goes out of scope. + class AbstractLocals + def initialize + @free = [] + @lock = Mutex.new + @all_arrays = {} + @next = 0 + end + + def synchronize + @lock.synchronize { yield } + end + + if Concurrent.on_cruby? + def weak_synchronize + yield + end + else + alias_method :weak_synchronize, :synchronize + end + + def next_index(local) + index = synchronize do + if @free.empty? + @next += 1 + else + @free.pop + end + end + + # When the local goes out of scope, we should free the associated index + # and all values stored into it. + ObjectSpace.define_finalizer(local, local_finalizer(index)) + + index + end + + def free_index(index) + weak_synchronize do + # The cost of GC'ing a TLV is linear in the number of ECs using local + # variables. But that is natural! More ECs means more storage is used + # per local variable. So naturally more CPU time is required to free + # more storage. + # + # DO NOT use each_value which might conflict with new pair assignment + # into the hash in #set method. + @all_arrays.values.each do |locals| + locals[index] = nil + end + + # free index has to be published after the arrays are cleared: + @free << index + end + end + + def fetch(index) + locals = self.locals + value = locals ? locals[index] : nil + + if nil == value + yield + elsif NULL.equal?(value) + nil + else + value + end + end + + def set(index, value) + locals = self.locals! + locals[index] = (nil == value ? NULL : value) + + value + end + + private + + # When the local goes out of scope, clean up that slot across all locals currently assigned. + def local_finalizer(index) + proc do + free_index(index) + end + end + + # When a thread/fiber goes out of scope, remove the array from @all_arrays. + def thread_fiber_finalizer(array_object_id) + proc do + weak_synchronize do + @all_arrays.delete(array_object_id) + end + end + end + + # Returns the locals for the current scope, or nil if none exist. + def locals + raise NotImplementedError + end + + # Returns the locals for the current scope, creating them if necessary. + def locals! + raise NotImplementedError + end + end + + # @!visibility private + # @!macro internal_implementation_note + # An array-backed storage of indexed variables per thread. + class ThreadLocals < AbstractLocals + def locals + Thread.current.thread_variable_get(:concurrent_thread_locals) + end + + def locals! + thread = Thread.current + locals = thread.thread_variable_get(:concurrent_thread_locals) + + unless locals + locals = thread.thread_variable_set(:concurrent_thread_locals, []) + weak_synchronize do + @all_arrays[locals.object_id] = locals + end + # When the thread goes out of scope, we should delete the associated locals: + ObjectSpace.define_finalizer(thread, thread_fiber_finalizer(locals.object_id)) + end + + locals + end + end + + # @!visibility private + # @!macro internal_implementation_note + # An array-backed storage of indexed variables per fiber. + class FiberLocals < AbstractLocals + def locals + Thread.current[:concurrent_fiber_locals] + end + + def locals! + thread = Thread.current + locals = thread[:concurrent_fiber_locals] + + unless locals + locals = thread[:concurrent_fiber_locals] = [] + weak_synchronize do + @all_arrays[locals.object_id] = locals + end + # When the fiber goes out of scope, we should delete the associated locals: + ObjectSpace.define_finalizer(Fiber.current, thread_fiber_finalizer(locals.object_id)) + end + + locals + end + end + + private_constant :AbstractLocals, :ThreadLocals, :FiberLocals +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb new file mode 100644 index 00000000..ebf23a24 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb @@ -0,0 +1,28 @@ +require 'concurrent/utility/engine' +require_relative 'fiber_local_var' +require_relative 'thread_local_var' + +module Concurrent + # @!visibility private + def self.mutex_owned_per_thread? + return false if Concurrent.on_jruby? || Concurrent.on_truffleruby? + + mutex = Mutex.new + # Lock the mutex: + mutex.synchronize do + # Check if the mutex is still owned in a child fiber: + Fiber.new { mutex.owned? }.resume + end + end + + if mutex_owned_per_thread? + LockLocalVar = ThreadLocalVar + else + LockLocalVar = FiberLocalVar + end + + # Either {FiberLocalVar} or {ThreadLocalVar} depending on whether Mutex (and Monitor) + # are held, respectively, per Fiber or per Thread. + class LockLocalVar + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb new file mode 100644 index 00000000..015996b0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb @@ -0,0 +1,68 @@ +require 'concurrent/synchronization/safe_initialization' + +module Concurrent + + # @!macro atomic_boolean + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicBoolean + extend Concurrent::Synchronization::SafeInitialization + + # @!macro atomic_boolean_method_initialize + def initialize(initial = false) + super() + @Lock = ::Mutex.new + @value = !!initial + end + + # @!macro atomic_boolean_method_value_get + def value + synchronize { @value } + end + + # @!macro atomic_boolean_method_value_set + def value=(value) + synchronize { @value = !!value } + end + + # @!macro atomic_boolean_method_true_question + def true? + synchronize { @value } + end + + # @!macro atomic_boolean_method_false_question + def false? + synchronize { !@value } + end + + # @!macro atomic_boolean_method_make_true + def make_true + synchronize { ns_make_value(true) } + end + + # @!macro atomic_boolean_method_make_false + def make_false + synchronize { ns_make_value(false) } + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + + private + + # @!visibility private + def ns_make_value(value) + old = @value + @value = value + old != @value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb new file mode 100644 index 00000000..0ca39557 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb @@ -0,0 +1,81 @@ +require 'concurrent/synchronization/safe_initialization' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro atomic_fixnum + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicFixnum + extend Concurrent::Synchronization::SafeInitialization + + # @!macro atomic_fixnum_method_initialize + def initialize(initial = 0) + super() + @Lock = ::Mutex.new + ns_set(initial) + end + + # @!macro atomic_fixnum_method_value_get + def value + synchronize { @value } + end + + # @!macro atomic_fixnum_method_value_set + def value=(value) + synchronize { ns_set(value) } + end + + # @!macro atomic_fixnum_method_increment + def increment(delta = 1) + synchronize { ns_set(@value + delta.to_i) } + end + + alias_method :up, :increment + + # @!macro atomic_fixnum_method_decrement + def decrement(delta = 1) + synchronize { ns_set(@value - delta.to_i) } + end + + alias_method :down, :decrement + + # @!macro atomic_fixnum_method_compare_and_set + def compare_and_set(expect, update) + synchronize do + if @value == expect.to_i + @value = update.to_i + true + else + false + end + end + end + + # @!macro atomic_fixnum_method_update + def update + synchronize do + @value = yield @value + end + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + + private + + # @!visibility private + def ns_set(value) + Utility::NativeInteger.ensure_integer_and_bounds value + @value = value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb new file mode 100644 index 00000000..29aa1caa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb @@ -0,0 +1,44 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro count_down_latch + # @!visibility private + # @!macro internal_implementation_note + class MutexCountDownLatch < Synchronization::LockableObject + + # @!macro count_down_latch_method_initialize + def initialize(count = 1) + Utility::NativeInteger.ensure_integer_and_bounds count + Utility::NativeInteger.ensure_positive count + + super() + synchronize { ns_initialize count } + end + + # @!macro count_down_latch_method_wait + def wait(timeout = nil) + synchronize { ns_wait_until(timeout) { @count == 0 } } + end + + # @!macro count_down_latch_method_count_down + def count_down + synchronize do + @count -= 1 if @count > 0 + ns_broadcast if @count == 0 + end + end + + # @!macro count_down_latch_method_count + def count + synchronize { @count } + end + + protected + + def ns_initialize(count) + @count = count + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb new file mode 100644 index 00000000..4347289f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb @@ -0,0 +1,131 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro semaphore + # @!visibility private + # @!macro internal_implementation_note + class MutexSemaphore < Synchronization::LockableObject + + # @!macro semaphore_method_initialize + def initialize(count) + Utility::NativeInteger.ensure_integer_and_bounds count + + super() + synchronize { ns_initialize count } + end + + # @!macro semaphore_method_acquire + def acquire(permits = 1) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + synchronize do + try_acquire_timed(permits, nil) + end + + return unless block_given? + + begin + yield + ensure + release(permits) + end + end + + # @!macro semaphore_method_available_permits + def available_permits + synchronize { @free } + end + + # @!macro semaphore_method_drain_permits + # + # Acquires and returns all permits that are immediately available. + # + # @return [Integer] + def drain_permits + synchronize do + @free.tap { |_| @free = 0 } + end + end + + # @!macro semaphore_method_try_acquire + def try_acquire(permits = 1, timeout = nil) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + acquired = synchronize do + if timeout.nil? + try_acquire_now(permits) + else + try_acquire_timed(permits, timeout) + end + end + + return acquired unless block_given? + return unless acquired + + begin + yield + ensure + release(permits) + end + end + + # @!macro semaphore_method_release + def release(permits = 1) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + synchronize do + @free += permits + permits.times { ns_signal } + end + nil + end + + # Shrinks the number of available permits by the indicated reduction. + # + # @param [Fixnum] reduction Number of permits to remove. + # + # @raise [ArgumentError] if `reduction` is not an integer or is negative + # + # @raise [ArgumentError] if `@free` - `@reduction` is less than zero + # + # @return [nil] + # + # @!visibility private + def reduce_permits(reduction) + Utility::NativeInteger.ensure_integer_and_bounds reduction + Utility::NativeInteger.ensure_positive reduction + + synchronize { @free -= reduction } + nil + end + + protected + + # @!visibility private + def ns_initialize(count) + @free = count + end + + private + + # @!visibility private + def try_acquire_now(permits) + if @free >= permits + @free -= permits + true + else + false + end + end + + # @!visibility private + def try_acquire_timed(permits, timeout) + ns_wait_until(timeout) { try_acquire_now(permits) } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb new file mode 100644 index 00000000..b26bd17a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb @@ -0,0 +1,255 @@ +require 'thread' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/errors' +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lock' + +module Concurrent + + # Ruby read-write lock implementation + # + # Allows any number of concurrent readers, but only one concurrent writer + # (And if the "write" lock is taken, any readers who come along will have to wait) + # + # If readers are already active when a writer comes along, the writer will wait for + # all the readers to finish before going ahead. + # Any additional readers that come when the writer is already waiting, will also + # wait (so writers are not starved). + # + # This implementation is based on `java.util.concurrent.ReentrantReadWriteLock`. + # + # @example + # lock = Concurrent::ReadWriteLock.new + # lock.with_read_lock { data.retrieve } + # lock.with_write_lock { data.modify! } + # + # @note Do **not** try to acquire the write lock while already holding a read lock + # **or** try to acquire the write lock while you already have it. + # This will lead to deadlock + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock + class ReadWriteLock < Synchronization::Object + + # @!visibility private + WAITING_WRITER = 1 << 15 + + # @!visibility private + RUNNING_WRITER = 1 << 29 + + # @!visibility private + MAX_READERS = WAITING_WRITER - 1 + + # @!visibility private + MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 + + safe_initialization! + + # Implementation notes: + # A goal is to make the uncontended path for both readers/writers lock-free + # Only if there is reader-writer or writer-writer contention, should locks be used + # Internal state is represented by a single integer ("counter"), and updated + # using atomic compare-and-swap operations + # When the counter is 0, the lock is free + # Each reader increments the counter by 1 when acquiring a read lock + # (and decrements by 1 when releasing the read lock) + # The counter is increased by (1 << 15) for each writer waiting to acquire the + # write lock, and by (1 << 29) if the write lock is taken + + # Create a new `ReadWriteLock` in the unlocked state. + def initialize + super() + @Counter = AtomicFixnum.new(0) # single integer which represents lock state + @ReadLock = Synchronization::Lock.new + @WriteLock = Synchronization::Lock.new + end + + # Execute a block operation within a read lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_read_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_read_lock + begin + yield + ensure + release_read_lock + end + end + + # Execute a block operation within a write lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_write_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_write_lock + begin + yield + ensure + release_write_lock + end + end + + # Acquire a read lock. If a write lock has been acquired will block until + # it is released. Will not block if other read locks have been acquired. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def acquire_read_lock + while true + c = @Counter.value + raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) + + # If a writer is waiting when we first queue up, we need to wait + if waiting_writer?(c) + @ReadLock.wait_until { !waiting_writer? } + + # after a reader has waited once, they are allowed to "barge" ahead of waiting writers + # but if a writer is *running*, the reader still needs to wait (naturally) + while true + c = @Counter.value + if running_writer?(c) + @ReadLock.wait_until { !running_writer? } + else + return if @Counter.compare_and_set(c, c+1) + end + end + else + break if @Counter.compare_and_set(c, c+1) + end + end + true + end + + # Release a previously acquired read lock. + # + # @return [Boolean] true if the lock is successfully released + def release_read_lock + while true + c = @Counter.value + if @Counter.compare_and_set(c, c-1) + # If one or more writers were waiting, and we were the last reader, wake a writer up + if waiting_writer?(c) && running_readers(c) == 1 + @WriteLock.signal + end + break + end + end + true + end + + # Acquire a write lock. Will block and wait for all active readers and writers. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of writers + # is exceeded. + def acquire_write_lock + while true + c = @Counter.value + raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) + + if c == 0 # no readers OR writers running + # if we successfully swap the RUNNING_WRITER bit on, then we can go ahead + break if @Counter.compare_and_set(0, RUNNING_WRITER) + elsif @Counter.compare_and_set(c, c+WAITING_WRITER) + while true + # Now we have successfully incremented, so no more readers will be able to increment + # (they will wait instead) + # However, readers OR writers could decrement right here, OR another writer could increment + @WriteLock.wait_until do + # So we have to do another check inside the synchronized section + # If a writer OR reader is running, then go to sleep + c = @Counter.value + !running_writer?(c) && !running_readers?(c) + end + + # We just came out of a wait + # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, + # Then we are OK to stop waiting and go ahead + # Otherwise go back and wait again + c = @Counter.value + break if !running_writer?(c) && !running_readers?(c) && @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) + end + break + end + end + true + end + + # Release a previously acquired write lock. + # + # @return [Boolean] true if the lock is successfully released + def release_write_lock + return true unless running_writer? + c = @Counter.update { |counter| counter - RUNNING_WRITER } + @ReadLock.broadcast + @WriteLock.signal if waiting_writers(c) > 0 + true + end + + # Queries if the write lock is held by any thread. + # + # @return [Boolean] true if the write lock is held else false` + def write_locked? + @Counter.value >= RUNNING_WRITER + end + + # Queries whether any threads are waiting to acquire the read or write lock. + # + # @return [Boolean] true if any threads are waiting for a lock else false + def has_waiters? + waiting_writer?(@Counter.value) + end + + private + + # @!visibility private + def running_readers(c = @Counter.value) + c & MAX_READERS + end + + # @!visibility private + def running_readers?(c = @Counter.value) + (c & MAX_READERS) > 0 + end + + # @!visibility private + def running_writer?(c = @Counter.value) + c >= RUNNING_WRITER + end + + # @!visibility private + def waiting_writers(c = @Counter.value) + (c & MAX_WRITERS) / WAITING_WRITER + end + + # @!visibility private + def waiting_writer?(c = @Counter.value) + c >= WAITING_WRITER + end + + # @!visibility private + def max_readers?(c = @Counter.value) + (c & MAX_READERS) == MAX_READERS + end + + # @!visibility private + def max_writers?(c = @Counter.value) + (c & MAX_WRITERS) == MAX_WRITERS + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb new file mode 100644 index 00000000..6d72a3a0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb @@ -0,0 +1,379 @@ +require 'thread' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/errors' +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lock' +require 'concurrent/atomic/lock_local_var' + +module Concurrent + + # Re-entrant read-write lock implementation + # + # Allows any number of concurrent readers, but only one concurrent writer + # (And while the "write" lock is taken, no read locks can be obtained either. + # Hence, the write lock can also be called an "exclusive" lock.) + # + # If another thread has taken a read lock, any thread which wants a write lock + # will block until all the readers release their locks. However, once a thread + # starts waiting to obtain a write lock, any additional readers that come along + # will also wait (so writers are not starved). + # + # A thread can acquire both a read and write lock at the same time. A thread can + # also acquire a read lock OR a write lock more than once. Only when the read (or + # write) lock is released as many times as it was acquired, will the thread + # actually let it go, allowing other threads which might have been waiting + # to proceed. Therefore the lock can be upgraded by first acquiring + # read lock and then write lock and that the lock can be downgraded by first + # having both read and write lock a releasing just the write lock. + # + # If both read and write locks are acquired by the same thread, it is not strictly + # necessary to release them in the same order they were acquired. In other words, + # the following code is legal: + # + # @example + # lock = Concurrent::ReentrantReadWriteLock.new + # lock.acquire_write_lock + # lock.acquire_read_lock + # lock.release_write_lock + # # At this point, the current thread is holding only a read lock, not a write + # # lock. So other threads can take read locks, but not a write lock. + # lock.release_read_lock + # # Now the current thread is not holding either a read or write lock, so + # # another thread could potentially acquire a write lock. + # + # This implementation was inspired by `java.util.concurrent.ReentrantReadWriteLock`. + # + # @example + # lock = Concurrent::ReentrantReadWriteLock.new + # lock.with_read_lock { data.retrieve } + # lock.with_write_lock { data.modify! } + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock + class ReentrantReadWriteLock < Synchronization::Object + + # Implementation notes: + # + # A goal is to make the uncontended path for both readers/writers mutex-free + # Only if there is reader-writer or writer-writer contention, should mutexes be used + # Otherwise, a single CAS operation is all we need to acquire/release a lock + # + # Internal state is represented by a single integer ("counter"), and updated + # using atomic compare-and-swap operations + # When the counter is 0, the lock is free + # Each thread which has one OR MORE read locks increments the counter by 1 + # (and decrements by 1 when releasing the read lock) + # The counter is increased by (1 << 15) for each writer waiting to acquire the + # write lock, and by (1 << 29) if the write lock is taken + # + # Additionally, each thread uses a thread-local variable to count how many times + # it has acquired a read lock, AND how many times it has acquired a write lock. + # It uses a similar trick; an increment of 1 means a read lock was taken, and + # an increment of (1 << 15) means a write lock was taken + # This is what makes re-entrancy possible + # + # 2 rules are followed to ensure good liveness properties: + # 1) Once a writer has queued up and is waiting for a write lock, no other thread + # can take a lock without waiting + # 2) When a write lock is released, readers are given the "first chance" to wake + # up and acquire a read lock + # Following these rules means readers and writers tend to "take turns", so neither + # can starve the other, even under heavy contention + + # @!visibility private + READER_BITS = 15 + # @!visibility private + WRITER_BITS = 14 + + # Used with @Counter: + # @!visibility private + WAITING_WRITER = 1 << READER_BITS + # @!visibility private + RUNNING_WRITER = 1 << (READER_BITS + WRITER_BITS) + # @!visibility private + MAX_READERS = WAITING_WRITER - 1 + # @!visibility private + MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 + + # Used with @HeldCount: + # @!visibility private + WRITE_LOCK_HELD = 1 << READER_BITS + # @!visibility private + READ_LOCK_MASK = WRITE_LOCK_HELD - 1 + # @!visibility private + WRITE_LOCK_MASK = MAX_WRITERS + + safe_initialization! + + # Create a new `ReentrantReadWriteLock` in the unlocked state. + def initialize + super() + @Counter = AtomicFixnum.new(0) # single integer which represents lock state + @ReadQueue = Synchronization::Lock.new # used to queue waiting readers + @WriteQueue = Synchronization::Lock.new # used to queue waiting writers + @HeldCount = LockLocalVar.new(0) # indicates # of R & W locks held by this thread + end + + # Execute a block operation within a read lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_read_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_read_lock + begin + yield + ensure + release_read_lock + end + end + + # Execute a block operation within a write lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_write_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_write_lock + begin + yield + ensure + release_write_lock + end + end + + # Acquire a read lock. If a write lock is held by another thread, will block + # until it is released. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def acquire_read_lock + if (held = @HeldCount.value) > 0 + # If we already have a lock, there's no need to wait + if held & READ_LOCK_MASK == 0 + # But we do need to update the counter, if we were holding a write + # lock but not a read lock + @Counter.update { |c| c + 1 } + end + @HeldCount.value = held + 1 + return true + end + + while true + c = @Counter.value + raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) + + # If a writer is waiting OR running when we first queue up, we need to wait + if waiting_or_running_writer?(c) + # Before going to sleep, check again with the ReadQueue mutex held + @ReadQueue.synchronize do + @ReadQueue.ns_wait if waiting_or_running_writer? + end + # Note: the above 'synchronize' block could have used #wait_until, + # but that waits repeatedly in a loop, checking the wait condition + # each time it wakes up (to protect against spurious wakeups) + # But we are already in a loop, which is only broken when we successfully + # acquire the lock! So we don't care about spurious wakeups, and would + # rather not pay the extra overhead of using #wait_until + + # After a reader has waited once, they are allowed to "barge" ahead of waiting writers + # But if a writer is *running*, the reader still needs to wait (naturally) + while true + c = @Counter.value + if running_writer?(c) + @ReadQueue.synchronize do + @ReadQueue.ns_wait if running_writer? + end + elsif @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + elsif @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + end + + # Try to acquire a read lock and return true if we succeed. If it cannot be + # acquired immediately, return false. + # + # @return [Boolean] true if the lock is successfully acquired + def try_read_lock + if (held = @HeldCount.value) > 0 + if held & READ_LOCK_MASK == 0 + # If we hold a write lock, but not a read lock... + @Counter.update { |c| c + 1 } + end + @HeldCount.value = held + 1 + return true + else + c = @Counter.value + if !waiting_or_running_writer?(c) && @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + false + end + + # Release a previously acquired read lock. + # + # @return [Boolean] true if the lock is successfully released + def release_read_lock + held = @HeldCount.value = @HeldCount.value - 1 + rlocks_held = held & READ_LOCK_MASK + if rlocks_held == 0 + c = @Counter.update { |counter| counter - 1 } + # If one or more writers were waiting, and we were the last reader, wake a writer up + if waiting_or_running_writer?(c) && running_readers(c) == 0 + @WriteQueue.signal + end + elsif rlocks_held == READ_LOCK_MASK + raise IllegalOperationError, "Cannot release a read lock which is not held" + end + true + end + + # Acquire a write lock. Will block and wait for all active readers and writers. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of writers + # is exceeded. + def acquire_write_lock + if (held = @HeldCount.value) >= WRITE_LOCK_HELD + # if we already have a write (exclusive) lock, there's no need to wait + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + + while true + c = @Counter.value + raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) + + # To go ahead and take the lock without waiting, there must be no writer + # running right now, AND no writers who came before us still waiting to + # acquire the lock + # Additionally, if any read locks have been taken, we must hold all of them + if held > 0 && @Counter.compare_and_set(1, c+RUNNING_WRITER) + # If we are the only one reader and successfully swap the RUNNING_WRITER bit on, then we can go ahead + @HeldCount.value = held + WRITE_LOCK_HELD + return true + elsif @Counter.compare_and_set(c, c+WAITING_WRITER) + while true + # Now we have successfully incremented, so no more readers will be able to increment + # (they will wait instead) + # However, readers OR writers could decrement right here + @WriteQueue.synchronize do + # So we have to do another check inside the synchronized section + # If a writer OR another reader is running, then go to sleep + c = @Counter.value + @WriteQueue.ns_wait if running_writer?(c) || running_readers(c) != held + end + # Note: if you are thinking of replacing the above 'synchronize' block + # with #wait_until, read the comment in #acquire_read_lock first! + + # We just came out of a wait + # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, + # then we are OK to stop waiting and go ahead + # Otherwise go back and wait again + c = @Counter.value + if !running_writer?(c) && + running_readers(c) == held && + @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + end + end + end + end + + # Try to acquire a write lock and return true if we succeed. If it cannot be + # acquired immediately, return false. + # + # @return [Boolean] true if the lock is successfully acquired + def try_write_lock + if (held = @HeldCount.value) >= WRITE_LOCK_HELD + @HeldCount.value = held + WRITE_LOCK_HELD + return true + else + c = @Counter.value + if !waiting_or_running_writer?(c) && + running_readers(c) == held && + @Counter.compare_and_set(c, c+RUNNING_WRITER) + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + end + false + end + + # Release a previously acquired write lock. + # + # @return [Boolean] true if the lock is successfully released + def release_write_lock + held = @HeldCount.value = @HeldCount.value - WRITE_LOCK_HELD + wlocks_held = held & WRITE_LOCK_MASK + if wlocks_held == 0 + c = @Counter.update { |counter| counter - RUNNING_WRITER } + @ReadQueue.broadcast + @WriteQueue.signal if waiting_writers(c) > 0 + elsif wlocks_held == WRITE_LOCK_MASK + raise IllegalOperationError, "Cannot release a write lock which is not held" + end + true + end + + private + + # @!visibility private + def running_readers(c = @Counter.value) + c & MAX_READERS + end + + # @!visibility private + def running_readers?(c = @Counter.value) + (c & MAX_READERS) > 0 + end + + # @!visibility private + def running_writer?(c = @Counter.value) + c >= RUNNING_WRITER + end + + # @!visibility private + def waiting_writers(c = @Counter.value) + (c & MAX_WRITERS) >> READER_BITS + end + + # @!visibility private + def waiting_or_running_writer?(c = @Counter.value) + c >= WAITING_WRITER + end + + # @!visibility private + def max_readers?(c = @Counter.value) + (c & MAX_READERS) == MAX_READERS + end + + # @!visibility private + def max_writers?(c = @Counter.value) + (c & MAX_WRITERS) == MAX_WRITERS + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/semaphore.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/semaphore.rb new file mode 100644 index 00000000..f0799f0f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/semaphore.rb @@ -0,0 +1,163 @@ +require 'concurrent/atomic/mutex_semaphore' + +module Concurrent + + ################################################################### + + # @!macro semaphore_method_initialize + # + # Create a new `Semaphore` with the initial `count`. + # + # @param [Fixnum] count the initial count + # + # @raise [ArgumentError] if `count` is not an integer + + # @!macro semaphore_method_acquire + # + # Acquires the given number of permits from this semaphore, + # blocking until all are available. If a block is given, + # yields to it and releases the permits afterwards. + # + # @param [Fixnum] permits Number of permits to acquire + # + # @raise [ArgumentError] if `permits` is not an integer or is less than zero + # + # @return [nil, BasicObject] Without a block, `nil` is returned. If a block + # is given, its return value is returned. + + # @!macro semaphore_method_available_permits + # + # Returns the current number of permits available in this semaphore. + # + # @return [Integer] + + # @!macro semaphore_method_drain_permits + # + # Acquires and returns all permits that are immediately available. + # + # @return [Integer] + + # @!macro semaphore_method_try_acquire + # + # Acquires the given number of permits from this semaphore, + # only if all are available at the time of invocation or within + # `timeout` interval. If a block is given, yields to it if the permits + # were successfully acquired, and releases them afterward, returning the + # block's return value. + # + # @param [Fixnum] permits the number of permits to acquire + # + # @param [Fixnum] timeout the number of seconds to wait for the counter + # or `nil` to return immediately + # + # @raise [ArgumentError] if `permits` is not an integer or is less than zero + # + # @return [true, false, nil, BasicObject] `false` if no permits are + # available, `true` when acquired a permit. If a block is given, the + # block's return value is returned if the permits were acquired; if not, + # `nil` is returned. + + # @!macro semaphore_method_release + # + # Releases the given number of permits, returning them to the semaphore. + # + # @param [Fixnum] permits Number of permits to return to the semaphore. + # + # @raise [ArgumentError] if `permits` is not a number or is less than zero + # + # @return [nil] + + ################################################################### + + # @!macro semaphore_public_api + # + # @!method initialize(count) + # @!macro semaphore_method_initialize + # + # @!method acquire(permits = 1) + # @!macro semaphore_method_acquire + # + # @!method available_permits + # @!macro semaphore_method_available_permits + # + # @!method drain_permits + # @!macro semaphore_method_drain_permits + # + # @!method try_acquire(permits = 1, timeout = nil) + # @!macro semaphore_method_try_acquire + # + # @!method release(permits = 1) + # @!macro semaphore_method_release + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + SemaphoreImplementation = if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + JavaSemaphore + else + MutexSemaphore + end + private_constant :SemaphoreImplementation + + # @!macro semaphore + # + # A counting semaphore. Conceptually, a semaphore maintains a set of + # permits. Each {#acquire} blocks if necessary until a permit is + # available, and then takes it. Each {#release} adds a permit, potentially + # releasing a blocking acquirer. + # However, no actual permit objects are used; the Semaphore just keeps a + # count of the number available and acts accordingly. + # Alternatively, permits may be acquired within a block, and automatically + # released after the block finishes executing. + # + # @!macro semaphore_public_api + # @example + # semaphore = Concurrent::Semaphore.new(2) + # + # t1 = Thread.new do + # semaphore.acquire + # puts "Thread 1 acquired semaphore" + # end + # + # t2 = Thread.new do + # semaphore.acquire + # puts "Thread 2 acquired semaphore" + # end + # + # t3 = Thread.new do + # semaphore.acquire + # puts "Thread 3 acquired semaphore" + # end + # + # t4 = Thread.new do + # sleep(2) + # puts "Thread 4 releasing semaphore" + # semaphore.release + # end + # + # [t1, t2, t3, t4].each(&:join) + # + # # prints: + # # Thread 3 acquired semaphore + # # Thread 2 acquired semaphore + # # Thread 4 releasing semaphore + # # Thread 1 acquired semaphore + # + # @example + # semaphore = Concurrent::Semaphore.new(1) + # + # puts semaphore.available_permits + # semaphore.acquire do + # puts semaphore.available_permits + # end + # puts semaphore.available_permits + # + # # prints: + # # 1 + # # 0 + # # 1 + class Semaphore < SemaphoreImplementation + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb new file mode 100644 index 00000000..3b7e12b5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb @@ -0,0 +1,111 @@ +require 'concurrent/constants' +require_relative 'locals' + +module Concurrent + + # A `ThreadLocalVar` is a variable where the value is different for each thread. + # Each variable may have a default value, but when you modify the variable only + # the current thread will ever see that change. + # + # This is similar to Ruby's built-in thread-local variables (`Thread#thread_variable_get`), + # but with these major advantages: + # * `ThreadLocalVar` has its own identity, it doesn't need a Symbol. + # * Each Ruby's built-in thread-local variable leaks some memory forever (it's a Symbol held forever on the thread), + # so it's only OK to create a small amount of them. + # `ThreadLocalVar` has no such issue and it is fine to create many of them. + # * Ruby's built-in thread-local variables leak forever the value set on each thread (unless set to nil explicitly). + # `ThreadLocalVar` automatically removes the mapping for each thread once the `ThreadLocalVar` instance is GC'd. + # + # @!macro thread_safe_variable_comparison + # + # @example + # v = ThreadLocalVar.new(14) + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # + # @example + # v = ThreadLocalVar.new(14) + # + # t1 = Thread.new do + # v.value #=> 14 + # v.value = 1 + # v.value #=> 1 + # end + # + # t2 = Thread.new do + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # end + # + # v.value #=> 14 + class ThreadLocalVar + LOCALS = ThreadLocals.new + + # Creates a thread local variable. + # + # @param [Object] default the default value when otherwise unset + # @param [Proc] default_block Optional block that gets called to obtain the + # default value for each thread + def initialize(default = nil, &default_block) + if default && block_given? + raise ArgumentError, "Cannot use both value and block as default value" + end + + if block_given? + @default_block = default_block + @default = nil + else + @default_block = nil + @default = default + end + + @index = LOCALS.next_index(self) + end + + # Returns the value in the current thread's copy of this thread-local variable. + # + # @return [Object] the current value + def value + LOCALS.fetch(@index) { default } + end + + # Sets the current thread's copy of this thread-local variable to the specified value. + # + # @param [Object] value the value to set + # @return [Object] the new value + def value=(value) + LOCALS.set(@index, value) + end + + # Bind the given value to thread local storage during + # execution of the given block. + # + # @param [Object] value the value to bind + # @yield the operation to be performed with the bound variable + # @return [Object] the value + def bind(value) + if block_given? + old_value = self.value + self.value = value + begin + yield + ensure + self.value = old_value + end + end + end + + protected + + # @!visibility private + def default + if @default_block + self.value = @default_block.call + else + @default + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb new file mode 100644 index 00000000..5d2d7edd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb @@ -0,0 +1,37 @@ +require 'concurrent/errors' + +module Concurrent + + # Define update methods that use direct paths + # + # @!visibility private + # @!macro internal_implementation_note + module AtomicDirectUpdate + def update + true until compare_and_set(old_value = get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = get + new_value = yield old_value + + return unless compare_and_set old_value, new_value + + new_value + end + + def try_update! + old_value = get + new_value = yield old_value + unless compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb new file mode 100644 index 00000000..e5e2a637 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb @@ -0,0 +1,67 @@ +require 'concurrent/atomic_reference/atomic_direct_update' +require 'concurrent/atomic_reference/numeric_cas_wrapper' +require 'concurrent/synchronization/safe_initialization' + +module Concurrent + + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicReference + extend Concurrent::Synchronization::SafeInitialization + include AtomicDirectUpdate + include AtomicNumericCompareAndSetWrapper + alias_method :compare_and_swap, :compare_and_set + + # @!macro atomic_reference_method_initialize + def initialize(value = nil) + super() + @Lock = ::Mutex.new + @value = value + end + + # @!macro atomic_reference_method_get + def get + synchronize { @value } + end + alias_method :value, :get + + # @!macro atomic_reference_method_set + def set(new_value) + synchronize { @value = new_value } + end + alias_method :value=, :set + + # @!macro atomic_reference_method_get_and_set + def get_and_set(new_value) + synchronize do + old_value = @value + @value = new_value + old_value + end + end + alias_method :swap, :get_and_set + + # @!macro atomic_reference_method_compare_and_set + def _compare_and_set(old_value, new_value) + synchronize do + if @value.equal? old_value + @value = new_value + true + else + false + end + end + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb new file mode 100644 index 00000000..709a3822 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb @@ -0,0 +1,28 @@ +module Concurrent + + # Special "compare and set" handling of numeric values. + # + # @!visibility private + # @!macro internal_implementation_note + module AtomicNumericCompareAndSetWrapper + + # @!macro atomic_reference_method_compare_and_set + def compare_and_set(old_value, new_value) + if old_value.kind_of? Numeric + while true + old = get + + return false unless old.kind_of? Numeric + + return false unless old == old_value + + result = _compare_and_set(old, new_value) + return result if result + end + else + _compare_and_set(old_value, new_value) + end + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomics.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomics.rb new file mode 100644 index 00000000..16cbe661 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomics.rb @@ -0,0 +1,10 @@ +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/atomic/cyclic_barrier' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/atomic/event' +require 'concurrent/atomic/read_write_lock' +require 'concurrent/atomic/reentrant_read_write_lock' +require 'concurrent/atomic/semaphore' +require 'concurrent/atomic/thread_local_var' diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb new file mode 100644 index 00000000..7c700bd7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb @@ -0,0 +1,107 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Collection + + # A thread safe observer set implemented using copy-on-read approach: + # observers are added and removed from a thread safe collection; every time + # a notification is required the internal data structure is copied to + # prevent concurrency issues + # + # @api private + class CopyOnNotifyObserverSet < Synchronization::LockableObject + + def initialize + super() + synchronize { ns_initialize } + end + + # @!macro observable_add_observer + def add_observer(observer = nil, func = :update, &block) + if observer.nil? && block.nil? + raise ArgumentError, 'should pass observer as a first argument or block' + elsif observer && block + raise ArgumentError.new('cannot provide both an observer and a block') + end + + if block + observer = block + func = :call + end + + synchronize do + @observers[observer] = func + observer + end + end + + # @!macro observable_delete_observer + def delete_observer(observer) + synchronize do + @observers.delete(observer) + observer + end + end + + # @!macro observable_delete_observers + def delete_observers + synchronize do + @observers.clear + self + end + end + + # @!macro observable_count_observers + def count_observers + synchronize { @observers.count } + end + + # Notifies all registered observers with optional args + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_observers(*args, &block) + observers = duplicate_observers + notify_to(observers, *args, &block) + self + end + + # Notifies all registered observers with optional args and deletes them. + # + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_and_delete_observers(*args, &block) + observers = duplicate_and_clear_observers + notify_to(observers, *args, &block) + self + end + + protected + + def ns_initialize + @observers = {} + end + + private + + def duplicate_and_clear_observers + synchronize do + observers = @observers.dup + @observers.clear + observers + end + end + + def duplicate_observers + synchronize { @observers.dup } + end + + def notify_to(observers, *args) + raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? + observers.each do |observer, function| + args = yield if block_given? + observer.send(function, *args) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb new file mode 100644 index 00000000..bcb6750d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb @@ -0,0 +1,111 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Collection + + # A thread safe observer set implemented using copy-on-write approach: + # every time an observer is added or removed the whole internal data structure is + # duplicated and replaced with a new one. + # + # @api private + class CopyOnWriteObserverSet < Synchronization::LockableObject + + def initialize + super() + synchronize { ns_initialize } + end + + # @!macro observable_add_observer + def add_observer(observer = nil, func = :update, &block) + if observer.nil? && block.nil? + raise ArgumentError, 'should pass observer as a first argument or block' + elsif observer && block + raise ArgumentError.new('cannot provide both an observer and a block') + end + + if block + observer = block + func = :call + end + + synchronize do + new_observers = @observers.dup + new_observers[observer] = func + @observers = new_observers + observer + end + end + + # @!macro observable_delete_observer + def delete_observer(observer) + synchronize do + new_observers = @observers.dup + new_observers.delete(observer) + @observers = new_observers + observer + end + end + + # @!macro observable_delete_observers + def delete_observers + self.observers = {} + self + end + + # @!macro observable_count_observers + def count_observers + observers.count + end + + # Notifies all registered observers with optional args + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_observers(*args, &block) + notify_to(observers, *args, &block) + self + end + + # Notifies all registered observers with optional args and deletes them. + # + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_and_delete_observers(*args, &block) + old = clear_observers_and_return_old + notify_to(old, *args, &block) + self + end + + protected + + def ns_initialize + @observers = {} + end + + private + + def notify_to(observers, *args) + raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? + observers.each do |observer, function| + args = yield if block_given? + observer.send(function, *args) + end + end + + def observers + synchronize { @observers } + end + + def observers=(new_set) + synchronize { @observers = new_set } + end + + def clear_observers_and_return_old + synchronize do + old_observers = @observers + @observers = {} + old_observers + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb new file mode 100644 index 00000000..2be9e437 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb @@ -0,0 +1,84 @@ +if Concurrent.on_jruby? + + module Concurrent + module Collection + + + # @!macro priority_queue + # + # @!visibility private + # @!macro internal_implementation_note + class JavaNonConcurrentPriorityQueue + + # @!macro priority_queue_method_initialize + def initialize(opts = {}) + order = opts.fetch(:order, :max) + if [:min, :low].include?(order) + @queue = java.util.PriorityQueue.new(11) # 11 is the default initial capacity + else + @queue = java.util.PriorityQueue.new(11, java.util.Collections.reverseOrder()) + end + end + + # @!macro priority_queue_method_clear + def clear + @queue.clear + true + end + + # @!macro priority_queue_method_delete + def delete(item) + found = false + while @queue.remove(item) do + found = true + end + found + end + + # @!macro priority_queue_method_empty + def empty? + @queue.size == 0 + end + + # @!macro priority_queue_method_include + def include?(item) + @queue.contains(item) + end + alias_method :has_priority?, :include? + + # @!macro priority_queue_method_length + def length + @queue.size + end + alias_method :size, :length + + # @!macro priority_queue_method_peek + def peek + @queue.peek + end + + # @!macro priority_queue_method_pop + def pop + @queue.poll + end + alias_method :deq, :pop + alias_method :shift, :pop + + # @!macro priority_queue_method_push + def push(item) + raise ArgumentError.new('cannot enqueue nil') if item.nil? + @queue.add(item) + end + alias_method :<<, :push + alias_method :enq, :push + + # @!macro priority_queue_method_from_list + def self.from_list(list, opts = {}) + queue = new(opts) + list.each{|item| queue << item } + queue + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb new file mode 100644 index 00000000..3704410b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb @@ -0,0 +1,160 @@ +require 'concurrent/synchronization/object' + +module Concurrent + + # @!macro warn.edge + class LockFreeStack < Synchronization::Object + + safe_initialization! + + class Node + # TODO (pitr-ch 20-Dec-2016): Could be unified with Stack class? + + # @return [Node] + attr_reader :next_node + + # @return [Object] + attr_reader :value + + # @!visibility private + # allow to nil-ify to free GC when the entry is no longer relevant, not synchronised + attr_writer :value + + def initialize(value, next_node) + @value = value + @next_node = next_node + end + + singleton_class.send :alias_method, :[], :new + end + + # The singleton for empty node + EMPTY = Node[nil, nil] + def EMPTY.next_node + self + end + + attr_atomic(:head) + private :head, :head=, :swap_head, :compare_and_set_head, :update_head + + # @!visibility private + def self.of1(value) + new Node[value, EMPTY] + end + + # @!visibility private + def self.of2(value1, value2) + new Node[value1, Node[value2, EMPTY]] + end + + # @param [Node] head + def initialize(head = EMPTY) + super() + self.head = head + end + + # @param [Node] head + # @return [true, false] + def empty?(head = head()) + head.equal? EMPTY + end + + # @param [Node] head + # @param [Object] value + # @return [true, false] + def compare_and_push(head, value) + compare_and_set_head head, Node[value, head] + end + + # @param [Object] value + # @return [self] + def push(value) + while true + current_head = head + return self if compare_and_set_head current_head, Node[value, current_head] + end + end + + # @return [Node] + def peek + head + end + + # @param [Node] head + # @return [true, false] + def compare_and_pop(head) + compare_and_set_head head, head.next_node + end + + # @return [Object] + def pop + while true + current_head = head + return current_head.value if compare_and_set_head current_head, current_head.next_node + end + end + + # @param [Node] head + # @return [true, false] + def compare_and_clear(head) + compare_and_set_head head, EMPTY + end + + include Enumerable + + # @param [Node] head + # @return [self] + def each(head = nil) + return to_enum(:each, head) unless block_given? + it = head || peek + until it.equal?(EMPTY) + yield it.value + it = it.next_node + end + self + end + + # @return [true, false] + def clear + while true + current_head = head + return false if current_head == EMPTY + return true if compare_and_set_head current_head, EMPTY + end + end + + # @param [Node] head + # @return [true, false] + def clear_if(head) + compare_and_set_head head, EMPTY + end + + # @param [Node] head + # @param [Node] new_head + # @return [true, false] + def replace_if(head, new_head) + compare_and_set_head head, new_head + end + + # @return [self] + # @yield over the cleared stack + # @yieldparam [Object] value + def clear_each(&block) + while true + current_head = head + return self if current_head == EMPTY + if compare_and_set_head current_head, EMPTY + each current_head, &block + return self + end + end + end + + # @return [String] Short string representation. + def to_s + format '%s %s>', super[0..-2], to_a.to_s + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb new file mode 100644 index 00000000..e0cf9990 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb @@ -0,0 +1,66 @@ +require 'thread' +require 'concurrent/collection/map/non_concurrent_map_backend' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class MriMapBackend < NonConcurrentMapBackend + + def initialize(options = nil, &default_proc) + super(options, &default_proc) + @write_lock = Mutex.new + end + + def []=(key, value) + @write_lock.synchronize { super } + end + + def compute_if_absent(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) # fast non-blocking path for the most likely case + stored_value + else + @write_lock.synchronize { super } + end + end + + def compute_if_present(key) + @write_lock.synchronize { super } + end + + def compute(key) + @write_lock.synchronize { super } + end + + def merge_pair(key, value) + @write_lock.synchronize { super } + end + + def replace_pair(key, old_value, new_value) + @write_lock.synchronize { super } + end + + def replace_if_exists(key, new_value) + @write_lock.synchronize { super } + end + + def get_and_set(key, value) + @write_lock.synchronize { super } + end + + def delete(key) + @write_lock.synchronize { super } + end + + def delete_pair(key, value) + @write_lock.synchronize { super } + end + + def clear + @write_lock.synchronize { super } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb new file mode 100644 index 00000000..ca5fd9b4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb @@ -0,0 +1,148 @@ +require 'concurrent/constants' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class NonConcurrentMapBackend + + # WARNING: all public methods of the class must operate on the @backend + # directly without calling each other. This is important because of the + # SynchronizedMapBackend which uses a non-reentrant mutex for performance + # reasons. + def initialize(options = nil, &default_proc) + validate_options_hash!(options) if options.kind_of?(::Hash) + set_backend(default_proc) + @default_proc = default_proc + end + + def [](key) + @backend[key] + end + + def []=(key, value) + @backend[key] = value + end + + def compute_if_absent(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + stored_value + else + @backend[key] = yield + end + end + + def replace_pair(key, old_value, new_value) + if pair?(key, old_value) + @backend[key] = new_value + true + else + false + end + end + + def replace_if_exists(key, new_value) + if NULL != (stored_value = @backend.fetch(key, NULL)) + @backend[key] = new_value + stored_value + end + end + + def compute_if_present(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + store_computed_value(key, yield(stored_value)) + end + end + + def compute(key) + store_computed_value(key, yield(get_or_default(key, nil))) + end + + def merge_pair(key, value) + if NULL == (stored_value = @backend.fetch(key, NULL)) + @backend[key] = value + else + store_computed_value(key, yield(stored_value)) + end + end + + def get_and_set(key, value) + stored_value = get_or_default(key, nil) + @backend[key] = value + stored_value + end + + def key?(key) + @backend.key?(key) + end + + def delete(key) + @backend.delete(key) + end + + def delete_pair(key, value) + if pair?(key, value) + @backend.delete(key) + true + else + false + end + end + + def clear + @backend.clear + self + end + + def each_pair + dupped_backend.each_pair do |k, v| + yield k, v + end + self + end + + def size + @backend.size + end + + def get_or_default(key, default_value) + @backend.fetch(key, default_value) + end + + private + + def set_backend(default_proc) + if default_proc + @backend = ::Hash.new { |_h, key| default_proc.call(self, key) } + else + @backend = {} + end + end + + def initialize_copy(other) + super + set_backend(@default_proc) + self + end + + def dupped_backend + @backend.dup + end + + def pair?(key, expected_value) + NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value) + end + + def store_computed_value(key, new_value) + if new_value.nil? + @backend.delete(key) + nil + else + @backend[key] = new_value + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb new file mode 100644 index 00000000..efa161ed --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb @@ -0,0 +1,85 @@ +require 'concurrent/collection/map/non_concurrent_map_backend' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class SynchronizedMapBackend < NonConcurrentMapBackend + + def initialize(*args, &block) + super + + # WARNING: Mutex is a non-reentrant lock, so the synchronized methods are + # not allowed to call each other. + @mutex = Mutex.new + end + + def [](key) + @mutex.synchronize { super } + end + + def []=(key, value) + @mutex.synchronize { super } + end + + def compute_if_absent(key) + @mutex.synchronize { super } + end + + def compute_if_present(key) + @mutex.synchronize { super } + end + + def compute(key) + @mutex.synchronize { super } + end + + def merge_pair(key, value) + @mutex.synchronize { super } + end + + def replace_pair(key, old_value, new_value) + @mutex.synchronize { super } + end + + def replace_if_exists(key, new_value) + @mutex.synchronize { super } + end + + def get_and_set(key, value) + @mutex.synchronize { super } + end + + def key?(key) + @mutex.synchronize { super } + end + + def delete(key) + @mutex.synchronize { super } + end + + def delete_pair(key, value) + @mutex.synchronize { super } + end + + def clear + @mutex.synchronize { super } + end + + def size + @mutex.synchronize { super } + end + + def get_or_default(key, default_value) + @mutex.synchronize { super } + end + + private + def dupped_backend + @mutex.synchronize { super } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb new file mode 100644 index 00000000..68a1b388 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb @@ -0,0 +1,14 @@ +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap + def initialize(options = nil) + options ||= {} + super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor]) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb new file mode 100644 index 00000000..694cd7ac --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb @@ -0,0 +1,143 @@ +require 'concurrent/utility/engine' +require 'concurrent/collection/java_non_concurrent_priority_queue' +require 'concurrent/collection/ruby_non_concurrent_priority_queue' + +module Concurrent + module Collection + + # @!visibility private + # @!macro internal_implementation_note + NonConcurrentPriorityQueueImplementation = case + when Concurrent.on_jruby? + JavaNonConcurrentPriorityQueue + else + RubyNonConcurrentPriorityQueue + end + private_constant :NonConcurrentPriorityQueueImplementation + + # @!macro priority_queue + # + # A queue collection in which the elements are sorted based on their + # comparison (spaceship) operator `<=>`. Items are added to the queue + # at a position relative to their priority. On removal the element + # with the "highest" priority is removed. By default the sort order is + # from highest to lowest, but a lowest-to-highest sort order can be + # set on construction. + # + # The API is based on the `Queue` class from the Ruby standard library. + # + # The pure Ruby implementation, `RubyNonConcurrentPriorityQueue` uses a heap algorithm + # stored in an array. The algorithm is based on the work of Robert Sedgewick + # and Kevin Wayne. + # + # The JRuby native implementation is a thin wrapper around the standard + # library `java.util.NonConcurrentPriorityQueue`. + # + # When running under JRuby the class `NonConcurrentPriorityQueue` extends `JavaNonConcurrentPriorityQueue`. + # When running under all other interpreters it extends `RubyNonConcurrentPriorityQueue`. + # + # @note This implementation is *not* thread safe. + # + # @see http://en.wikipedia.org/wiki/Priority_queue + # @see http://ruby-doc.org/stdlib-2.0.0/libdoc/thread/rdoc/Queue.html + # + # @see http://algs4.cs.princeton.edu/24pq/index.php#2.6 + # @see http://algs4.cs.princeton.edu/24pq/MaxPQ.java.html + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html + # + # @!visibility private + class NonConcurrentPriorityQueue < NonConcurrentPriorityQueueImplementation + + alias_method :has_priority?, :include? + + alias_method :size, :length + + alias_method :deq, :pop + alias_method :shift, :pop + + alias_method :<<, :push + alias_method :enq, :push + + # @!method initialize(opts = {}) + # @!macro priority_queue_method_initialize + # + # Create a new priority queue with no items. + # + # @param [Hash] opts the options for creating the queue + # @option opts [Symbol] :order (:max) dictates the order in which items are + # stored: from highest to lowest when `:max` or `:high`; from lowest to + # highest when `:min` or `:low` + + # @!method clear + # @!macro priority_queue_method_clear + # + # Removes all of the elements from this priority queue. + + # @!method delete(item) + # @!macro priority_queue_method_delete + # + # Deletes all items from `self` that are equal to `item`. + # + # @param [Object] item the item to be removed from the queue + # @return [Object] true if the item is found else false + + # @!method empty? + # @!macro priority_queue_method_empty + # + # Returns `true` if `self` contains no elements. + # + # @return [Boolean] true if there are no items in the queue else false + + # @!method include?(item) + # @!macro priority_queue_method_include + # + # Returns `true` if the given item is present in `self` (that is, if any + # element == `item`), otherwise returns false. + # + # @param [Object] item the item to search for + # + # @return [Boolean] true if the item is found else false + + # @!method length + # @!macro priority_queue_method_length + # + # The current length of the queue. + # + # @return [Fixnum] the number of items in the queue + + # @!method peek + # @!macro priority_queue_method_peek + # + # Retrieves, but does not remove, the head of this queue, or returns `nil` + # if this queue is empty. + # + # @return [Object] the head of the queue or `nil` when empty + + # @!method pop + # @!macro priority_queue_method_pop + # + # Retrieves and removes the head of this queue, or returns `nil` if this + # queue is empty. + # + # @return [Object] the head of the queue or `nil` when empty + + # @!method push(item) + # @!macro priority_queue_method_push + # + # Inserts the specified element into this priority queue. + # + # @param [Object] item the item to insert onto the queue + + # @!method self.from_list(list, opts = {}) + # @!macro priority_queue_method_from_list + # + # Create a new priority queue from the given list. + # + # @param [Enumerable] list the list to build the queue from + # @param [Hash] opts the options for creating the queue + # + # @return [NonConcurrentPriorityQueue] the newly created and populated queue + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb new file mode 100644 index 00000000..322b4ac2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb @@ -0,0 +1,160 @@ +module Concurrent + module Collection + + # @!macro priority_queue + # + # @!visibility private + # @!macro internal_implementation_note + class RubyNonConcurrentPriorityQueue + + # @!macro priority_queue_method_initialize + def initialize(opts = {}) + order = opts.fetch(:order, :max) + @comparator = [:min, :low].include?(order) ? -1 : 1 + clear + end + + # @!macro priority_queue_method_clear + def clear + @queue = [nil] + @length = 0 + true + end + + # @!macro priority_queue_method_delete + def delete(item) + return false if empty? + original_length = @length + k = 1 + while k <= @length + if @queue[k] == item + swap(k, @length) + @length -= 1 + sink(k) || swim(k) + @queue.pop + else + k += 1 + end + end + @length != original_length + end + + # @!macro priority_queue_method_empty + def empty? + size == 0 + end + + # @!macro priority_queue_method_include + def include?(item) + @queue.include?(item) + end + alias_method :has_priority?, :include? + + # @!macro priority_queue_method_length + def length + @length + end + alias_method :size, :length + + # @!macro priority_queue_method_peek + def peek + empty? ? nil : @queue[1] + end + + # @!macro priority_queue_method_pop + def pop + return nil if empty? + max = @queue[1] + swap(1, @length) + @length -= 1 + sink(1) + @queue.pop + max + end + alias_method :deq, :pop + alias_method :shift, :pop + + # @!macro priority_queue_method_push + def push(item) + raise ArgumentError.new('cannot enqueue nil') if item.nil? + @length += 1 + @queue << item + swim(@length) + true + end + alias_method :<<, :push + alias_method :enq, :push + + # @!macro priority_queue_method_from_list + def self.from_list(list, opts = {}) + queue = new(opts) + list.each{|item| queue << item } + queue + end + + private + + # Exchange the values at the given indexes within the internal array. + # + # @param [Integer] x the first index to swap + # @param [Integer] y the second index to swap + # + # @!visibility private + def swap(x, y) + temp = @queue[x] + @queue[x] = @queue[y] + @queue[y] = temp + end + + # Are the items at the given indexes ordered based on the priority + # order specified at construction? + # + # @param [Integer] x the first index from which to retrieve a comparable value + # @param [Integer] y the second index from which to retrieve a comparable value + # + # @return [Boolean] true if the two elements are in the correct priority order + # else false + # + # @!visibility private + def ordered?(x, y) + (@queue[x] <=> @queue[y]) == @comparator + end + + # Percolate down to maintain heap invariant. + # + # @param [Integer] k the index at which to start the percolation + # + # @!visibility private + def sink(k) + success = false + + while (j = (2 * k)) <= @length do + j += 1 if j < @length && ! ordered?(j, j+1) + break if ordered?(k, j) + swap(k, j) + success = true + k = j + end + + success + end + + # Percolate up to maintain heap invariant. + # + # @param [Integer] k the index at which to start the percolation + # + # @!visibility private + def swim(k) + success = false + + while k > 1 && ! ordered?(k/2, k) do + swap(k, k/2) + k = k/2 + success = true + end + + success + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/deprecation.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/deprecation.rb new file mode 100644 index 00000000..35ae4b2c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/deprecation.rb @@ -0,0 +1,34 @@ +require 'concurrent/concern/logging' + +module Concurrent + module Concern + + # @!visibility private + # @!macro internal_implementation_note + module Deprecation + # TODO require additional parameter: a version. Display when it'll be removed based on that. Error if not removed. + include Concern::Logging + + def deprecated(message, strip = 2) + caller_line = caller(strip).first if strip > 0 + klass = if Module === self + self + else + self.class + end + message = if strip > 0 + format("[DEPRECATED] %s\ncalled on: %s", message, caller_line) + else + format('[DEPRECATED] %s', message) + end + log WARN, klass.to_s, message + end + + def deprecated_method(old_name, new_name) + deprecated "`#{old_name}` is deprecated and it'll removed in next release, use `#{new_name}` instead", 3 + end + + extend self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb new file mode 100644 index 00000000..dc172ba7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb @@ -0,0 +1,73 @@ +module Concurrent + module Concern + + # Object references in Ruby are mutable. This can lead to serious problems when + # the `#value` of a concurrent object is a mutable reference. Which is always the + # case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type. + # Most classes in this library that expose a `#value` getter method do so using the + # `Dereferenceable` mixin module. + # + # @!macro copy_options + module Dereferenceable + # NOTE: This module is going away in 2.0. In the mean time we need it to + # play nicely with the synchronization layer. This means that the + # including class SHOULD be synchronized and it MUST implement a + # `#synchronize` method. Not doing so will lead to runtime errors. + + # Return the value this object represents after applying the options specified + # by the `#set_deref_options` method. + # + # @return [Object] the current value of the object + def value + synchronize { apply_deref_options(@value) } + end + alias_method :deref, :value + + protected + + # Set the internal value of this object + # + # @param [Object] value the new value + def value=(value) + synchronize{ @value = value } + end + + # @!macro dereferenceable_set_deref_options + # Set the options which define the operations #value performs before + # returning data to the caller (dereferencing). + # + # @note Most classes that include this module will call `#set_deref_options` + # from within the constructor, thus allowing these options to be set at + # object creation. + # + # @param [Hash] opts the options defining dereference behavior. + # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data + # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data + # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing + # the internal value and returning the value returned from the proc + def set_deref_options(opts = {}) + synchronize{ ns_set_deref_options(opts) } + end + + # @!macro dereferenceable_set_deref_options + # @!visibility private + def ns_set_deref_options(opts) + @dup_on_deref = opts[:dup_on_deref] || opts[:dup] + @freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze] + @copy_on_deref = opts[:copy_on_deref] || opts[:copy] + @do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref) + nil + end + + # @!visibility private + def apply_deref_options(value) + return nil if value.nil? + return value if @do_nothing_on_deref + value = @copy_on_deref.call(value) if @copy_on_deref + value = value.dup if @dup_on_deref + value = value.freeze if @freeze_on_deref + value + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/logging.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/logging.rb new file mode 100644 index 00000000..d1aae81a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/logging.rb @@ -0,0 +1,121 @@ +require 'concurrent/atomic/atomic_reference' + +module Concurrent + module Concern + + # Include where logging is needed + # + # @!visibility private + module Logging + # The same as Logger::Severity but we copy it here to avoid a dependency on the logger gem just for these 7 constants + DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN = 0, 1, 2, 3, 4, 5 + SEV_LABEL = %w[DEBUG INFO WARN ERROR FATAL ANY].freeze + + # Logs through {Concurrent.global_logger}, it can be overridden by setting @logger + # @param [Integer] level one of Concurrent::Concern::Logging constants + # @param [String] progname e.g. a path of an Actor + # @param [String, nil] message when nil block is used to generate the message + # @yieldreturn [String] a message + def log(level, progname, message = nil, &block) + logger = if defined?(@logger) && @logger + @logger + else + Concurrent.global_logger + end + logger.call level, progname, message, &block + rescue => error + $stderr.puts "`Concurrent.global_logger` failed to log #{[level, progname, message, block]}\n" + + "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}" + end + end + end +end + +module Concurrent + extend Concern::Logging + + # Create a simple logger with provided level and output. + def self.create_simple_logger(level = :FATAL, output = $stderr) + level = Concern::Logging.const_get(level) unless level.is_a?(Integer) + + # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking + lambda do |severity, progname, message = nil, &block| + return false if severity < level + + message = block ? block.call : message + formatted_message = case message + when String + message + when Exception + format "%s (%s)\n%s", + message.message, message.class, (message.backtrace || []).join("\n") + else + message.inspect + end + + output.print format "[%s] %5s -- %s: %s\n", + Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'), + Concern::Logging::SEV_LABEL[severity], + progname, + formatted_message + true + end + end + + # Use logger created by #create_simple_logger to log concurrent-ruby messages. + def self.use_simple_logger(level = :FATAL, output = $stderr) + Concurrent.global_logger = create_simple_logger level, output + end + + # Create a stdlib logger with provided level and output. + # If you use this deprecated method you might need to add logger to your Gemfile to avoid warnings from Ruby 3.3.5+. + # @deprecated + def self.create_stdlib_logger(level = :FATAL, output = $stderr) + require 'logger' + logger = Logger.new(output) + logger.level = level + logger.formatter = lambda do |severity, datetime, progname, msg| + formatted_message = case msg + when String + msg + when Exception + format "%s (%s)\n%s", + msg.message, msg.class, (msg.backtrace || []).join("\n") + else + msg.inspect + end + format "[%s] %5s -- %s: %s\n", + datetime.strftime('%Y-%m-%d %H:%M:%S.%L'), + severity, + progname, + formatted_message + end + + lambda do |loglevel, progname, message = nil, &block| + logger.add loglevel, message, progname, &block + end + end + + # Use logger created by #create_stdlib_logger to log concurrent-ruby messages. + # @deprecated + def self.use_stdlib_logger(level = :FATAL, output = $stderr) + Concurrent.global_logger = create_stdlib_logger level, output + end + + # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods + + # Suppresses all output when used for logging. + NULL_LOGGER = lambda { |level, progname, message = nil, &block| } + + # @!visibility private + GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(:WARN)) + private_constant :GLOBAL_LOGGER + + def self.global_logger + GLOBAL_LOGGER.value + end + + def self.global_logger=(value) + GLOBAL_LOGGER.value = value + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/obligation.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/obligation.rb new file mode 100644 index 00000000..2c9ac120 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/obligation.rb @@ -0,0 +1,220 @@ +require 'thread' +require 'timeout' + +require 'concurrent/atomic/event' +require 'concurrent/concern/dereferenceable' + +module Concurrent + module Concern + + module Obligation + include Concern::Dereferenceable + # NOTE: The Dereferenceable module is going away in 2.0. In the mean time + # we need it to place nicely with the synchronization layer. This means + # that the including class SHOULD be synchronized and it MUST implement a + # `#synchronize` method. Not doing so will lead to runtime errors. + + # Has the obligation been fulfilled? + # + # @return [Boolean] + def fulfilled? + state == :fulfilled + end + alias_method :realized?, :fulfilled? + + # Has the obligation been rejected? + # + # @return [Boolean] + def rejected? + state == :rejected + end + + # Is obligation completion still pending? + # + # @return [Boolean] + def pending? + state == :pending + end + + # Is the obligation still unscheduled? + # + # @return [Boolean] + def unscheduled? + state == :unscheduled + end + + # Has the obligation completed processing? + # + # @return [Boolean] + def complete? + [:fulfilled, :rejected].include? state + end + + # Is the obligation still awaiting completion of processing? + # + # @return [Boolean] + def incomplete? + ! complete? + end + + # The current value of the obligation. Will be `nil` while the state is + # pending or the operation has been rejected. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Object] see Dereferenceable#deref + def value(timeout = nil) + wait timeout + deref + end + + # Wait until obligation is complete or the timeout has been reached. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Obligation] self + def wait(timeout = nil) + event.wait(timeout) if timeout != 0 && incomplete? + self + end + + # Wait until obligation is complete or the timeout is reached. Will re-raise + # any exceptions raised during processing (but will not raise an exception + # on timeout). + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Obligation] self + # @raise [Exception] raises the reason when rejected + def wait!(timeout = nil) + wait(timeout).tap { raise self if rejected? } + end + alias_method :no_error!, :wait! + + # The current value of the obligation. Will be `nil` while the state is + # pending or the operation has been rejected. Will re-raise any exceptions + # raised during processing (but will not raise an exception on timeout). + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Object] see Dereferenceable#deref + # @raise [Exception] raises the reason when rejected + def value!(timeout = nil) + wait(timeout) + if rejected? + raise self + else + deref + end + end + + # The current state of the obligation. + # + # @return [Symbol] the current state + def state + synchronize { @state } + end + + # If an exception was raised during processing this will return the + # exception object. Will return `nil` when the state is pending or if + # the obligation has been successfully fulfilled. + # + # @return [Exception] the exception raised during processing or `nil` + def reason + synchronize { @reason } + end + + # @example allows Obligation to be risen + # rejected_ivar = Ivar.new.fail + # raise rejected_ivar + def exception(*args) + raise 'obligation is not rejected' unless rejected? + reason.exception(*args) + end + + protected + + # @!visibility private + def get_arguments_from(opts = {}) + [*opts.fetch(:args, [])] + end + + # @!visibility private + def init_obligation + @event = Event.new + @value = @reason = nil + end + + # @!visibility private + def event + @event + end + + # @!visibility private + def set_state(success, value, reason) + if success + @value = value + @state = :fulfilled + else + @reason = reason + @state = :rejected + end + end + + # @!visibility private + def state=(value) + synchronize { ns_set_state(value) } + end + + # Atomic compare and set operation + # State is set to `next_state` only if `current state == expected_current`. + # + # @param [Symbol] next_state + # @param [Symbol] expected_current + # + # @return [Boolean] true is state is changed, false otherwise + # + # @!visibility private + def compare_and_set_state(next_state, *expected_current) + synchronize do + if expected_current.include? @state + @state = next_state + true + else + false + end + end + end + + # Executes the block within mutex if current state is included in expected_states + # + # @return block value if executed, false otherwise + # + # @!visibility private + def if_state(*expected_states) + synchronize do + raise ArgumentError.new('no block given') unless block_given? + + if expected_states.include? @state + yield + else + false + end + end + end + + protected + + # Am I in the current state? + # + # @param [Symbol] expected The state to check against + # @return [Boolean] true if in the expected state else false + # + # @!visibility private + def ns_check_state?(expected) + @state == expected + end + + # @!visibility private + def ns_set_state(value) + @state = value + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/observable.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/observable.rb new file mode 100644 index 00000000..b5132714 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concern/observable.rb @@ -0,0 +1,110 @@ +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/collection/copy_on_write_observer_set' + +module Concurrent + module Concern + + # The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one + # of the most useful design patterns. + # + # The workflow is very simple: + # - an `observer` can register itself to a `subject` via a callback + # - many `observers` can be registered to the same `subject` + # - the `subject` notifies all registered observers when its status changes + # - an `observer` can deregister itself when is no more interested to receive + # event notifications + # + # In a single threaded environment the whole pattern is very easy: the + # `subject` can use a simple data structure to manage all its subscribed + # `observer`s and every `observer` can react directly to every event without + # caring about synchronization. + # + # In a multi threaded environment things are more complex. The `subject` must + # synchronize the access to its data structure and to do so currently we're + # using two specialized ObserverSet: {Concurrent::Concern::CopyOnWriteObserverSet} + # and {Concurrent::Concern::CopyOnNotifyObserverSet}. + # + # When implementing and `observer` there's a very important rule to remember: + # **there are no guarantees about the thread that will execute the callback** + # + # Let's take this example + # ``` + # class Observer + # def initialize + # @count = 0 + # end + # + # def update + # @count += 1 + # end + # end + # + # obs = Observer.new + # [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) } + # # execute [obj1, obj2, obj3, obj4] + # ``` + # + # `obs` is wrong because the variable `@count` can be accessed by different + # threads at the same time, so it should be synchronized (using either a Mutex + # or an AtomicFixum) + module Observable + + # @!macro observable_add_observer + # + # Adds an observer to this set. If a block is passed, the observer will be + # created by this method and no other params should be passed. + # + # @param [Object] observer the observer to add + # @param [Symbol] func the function to call on the observer during notification. + # Default is :update + # @return [Object] the added observer + def add_observer(observer = nil, func = :update, &block) + observers.add_observer(observer, func, &block) + end + + # As `#add_observer` but can be used for chaining. + # + # @param [Object] observer the observer to add + # @param [Symbol] func the function to call on the observer during notification. + # @return [Observable] self + def with_observer(observer = nil, func = :update, &block) + add_observer(observer, func, &block) + self + end + + # @!macro observable_delete_observer + # + # Remove `observer` as an observer on this object so that it will no + # longer receive notifications. + # + # @param [Object] observer the observer to remove + # @return [Object] the deleted observer + def delete_observer(observer) + observers.delete_observer(observer) + end + + # @!macro observable_delete_observers + # + # Remove all observers associated with this object. + # + # @return [Observable] self + def delete_observers + observers.delete_observers + self + end + + # @!macro observable_count_observers + # + # Return the number of observers associated with this object. + # + # @return [Integer] the observers count + def count_observers + observers.count_observers + end + + protected + + attr_accessor :observers + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concurrent_ruby.jar b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concurrent_ruby.jar new file mode 100644 index 00000000..d5b8d275 Binary files /dev/null and b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/concurrent_ruby.jar differ diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/configuration.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/configuration.rb new file mode 100644 index 00000000..5571d39b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/configuration.rb @@ -0,0 +1,105 @@ +require 'thread' +require 'concurrent/delay' +require 'concurrent/errors' +require 'concurrent/concern/deprecation' +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/fixed_thread_pool' +require 'concurrent/executor/cached_thread_pool' +require 'concurrent/utility/processor_counter' + +module Concurrent + extend Concern::Deprecation + + autoload :Options, 'concurrent/options' + autoload :TimerSet, 'concurrent/executor/timer_set' + autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor' + + # @!visibility private + GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor } + private_constant :GLOBAL_FAST_EXECUTOR + + # @!visibility private + GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor } + private_constant :GLOBAL_IO_EXECUTOR + + # @!visibility private + GLOBAL_TIMER_SET = Delay.new { TimerSet.new } + private_constant :GLOBAL_TIMER_SET + + # @!visibility private + GLOBAL_IMMEDIATE_EXECUTOR = ImmediateExecutor.new + private_constant :GLOBAL_IMMEDIATE_EXECUTOR + + # Disables AtExit handlers including pool auto-termination handlers. + # When disabled it will be the application programmer's responsibility + # to ensure that the handlers are shutdown properly prior to application + # exit by calling `AtExit.run` method. + # + # @note this option should be needed only because of `at_exit` ordering + # issues which may arise when running some of the testing frameworks. + # E.g. Minitest's test-suite runs itself in `at_exit` callback which + # executes after the pools are already terminated. Then auto termination + # needs to be disabled and called manually after test-suite ends. + # @note This method should *never* be called + # from within a gem. It should *only* be used from within the main + # application and even then it should be used only when necessary. + # @deprecated Has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841. + # + def self.disable_at_exit_handlers! + deprecated "Method #disable_at_exit_handlers! has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841." + end + + # Global thread pool optimized for short, fast *operations*. + # + # @return [ThreadPoolExecutor] the thread pool + def self.global_fast_executor + GLOBAL_FAST_EXECUTOR.value! + end + + # Global thread pool optimized for long, blocking (IO) *tasks*. + # + # @return [ThreadPoolExecutor] the thread pool + def self.global_io_executor + GLOBAL_IO_EXECUTOR.value! + end + + def self.global_immediate_executor + GLOBAL_IMMEDIATE_EXECUTOR + end + + # Global thread pool user for global *timers*. + # + # @return [Concurrent::TimerSet] the thread pool + def self.global_timer_set + GLOBAL_TIMER_SET.value! + end + + # General access point to global executors. + # @param [Symbol, Executor] executor_identifier symbols: + # - :fast - {Concurrent.global_fast_executor} + # - :io - {Concurrent.global_io_executor} + # - :immediate - {Concurrent.global_immediate_executor} + # @return [Executor] + def self.executor(executor_identifier) + Options.executor(executor_identifier) + end + + def self.new_fast_executor(opts = {}) + FixedThreadPool.new( + [2, Concurrent.processor_count].max, + auto_terminate: opts.fetch(:auto_terminate, true), + idletime: 60, # 1 minute + max_queue: 0, # unlimited + fallback_policy: :abort, # shouldn't matter -- 0 max queue + name: "fast" + ) + end + + def self.new_io_executor(opts = {}) + CachedThreadPool.new( + auto_terminate: opts.fetch(:auto_terminate, true), + fallback_policy: :abort, # shouldn't matter -- 0 max queue + name: "io" + ) + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/constants.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/constants.rb new file mode 100644 index 00000000..676c2afb --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/constants.rb @@ -0,0 +1,8 @@ +module Concurrent + + # Various classes within allows for +nil+ values to be stored, + # so a special +NULL+ token is required to indicate the "nil-ness". + # @!visibility private + NULL = ::Object.new + +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/dataflow.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/dataflow.rb new file mode 100644 index 00000000..d55f19d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/dataflow.rb @@ -0,0 +1,81 @@ +require 'concurrent/future' +require 'concurrent/atomic/atomic_fixnum' + +module Concurrent + + # @!visibility private + class DependencyCounter # :nodoc: + + def initialize(count, &block) + @counter = AtomicFixnum.new(count) + @block = block + end + + def update(time, value, reason) + if @counter.decrement == 0 + @block.call + end + end + end + + # Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available. + # {include:file:docs-source/dataflow.md} + # + # @param [Future] inputs zero or more `Future` operations that this dataflow depends upon + # + # @yield The operation to perform once all the dependencies are met + # @yieldparam [Future] inputs each of the `Future` inputs to the dataflow + # @yieldreturn [Object] the result of the block operation + # + # @return [Object] the result of all the operations + # + # @raise [ArgumentError] if no block is given + # @raise [ArgumentError] if any of the inputs are not `IVar`s + def dataflow(*inputs, &block) + dataflow_with(Concurrent.global_io_executor, *inputs, &block) + end + module_function :dataflow + + def dataflow_with(executor, *inputs, &block) + call_dataflow(:value, executor, *inputs, &block) + end + module_function :dataflow_with + + def dataflow!(*inputs, &block) + dataflow_with!(Concurrent.global_io_executor, *inputs, &block) + end + module_function :dataflow! + + def dataflow_with!(executor, *inputs, &block) + call_dataflow(:value!, executor, *inputs, &block) + end + module_function :dataflow_with! + + private + + def call_dataflow(method, executor, *inputs, &block) + raise ArgumentError.new('an executor must be provided') if executor.nil? + raise ArgumentError.new('no block given') unless block_given? + unless inputs.all? { |input| input.is_a? IVar } + raise ArgumentError.new("Not all dependencies are IVars.\nDependencies: #{ inputs.inspect }") + end + + result = Future.new(executor: executor) do + values = inputs.map { |input| input.send(method) } + block.call(*values) + end + + if inputs.empty? + result.execute + else + counter = DependencyCounter.new(inputs.size) { result.execute } + + inputs.each do |input| + input.add_observer counter + end + end + + result + end + module_function :call_dataflow +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/delay.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/delay.rb new file mode 100644 index 00000000..0d6d91a5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/delay.rb @@ -0,0 +1,199 @@ +require 'thread' +require 'concurrent/concern/obligation' +require 'concurrent/executor/immediate_executor' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # This file has circular require issues. It must be autoloaded here. + autoload :Options, 'concurrent/options' + + # Lazy evaluation of a block yielding an immutable result. Useful for + # expensive operations that may never be needed. It may be non-blocking, + # supports the `Concern::Obligation` interface, and accepts the injection of + # custom executor upon which to execute the block. Processing of + # block will be deferred until the first time `#value` is called. + # At that time the caller can choose to return immediately and let + # the block execute asynchronously, block indefinitely, or block + # with a timeout. + # + # When a `Delay` is created its state is set to `pending`. The value and + # reason are both `nil`. The first time the `#value` method is called the + # enclosed operation will be run and the calling thread will block. Other + # threads attempting to call `#value` will block as well. Once the operation + # is complete the *value* will be set to the result of the operation or the + # *reason* will be set to the raised exception, as appropriate. All threads + # blocked on `#value` will return. Subsequent calls to `#value` will immediately + # return the cached value. The operation will only be run once. This means that + # any side effects created by the operation will only happen once as well. + # + # `Delay` includes the `Concurrent::Concern::Dereferenceable` mixin to support thread + # safety of the reference returned by `#value`. + # + # @!macro copy_options + # + # @!macro delay_note_regarding_blocking + # @note The default behavior of `Delay` is to block indefinitely when + # calling either `value` or `wait`, executing the delayed operation on + # the current thread. This makes the `timeout` value completely + # irrelevant. To enable non-blocking behavior, use the `executor` + # constructor option. This will cause the delayed operation to be + # execute on the given executor, allowing the call to timeout. + # + # @see Concurrent::Concern::Dereferenceable + class Delay < Synchronization::LockableObject + include Concern::Obligation + + # NOTE: Because the global thread pools are lazy-loaded with these objects + # there is a performance hit every time we post a new task to one of these + # thread pools. Subsequently it is critical that `Delay` perform as fast + # as possible post-completion. This class has been highly optimized using + # the benchmark script `examples/lazy_and_delay.rb`. Do NOT attempt to + # DRY-up this class or perform other refactoring with running the + # benchmarks and ensuring that performance is not negatively impacted. + + # Create a new `Delay` in the `:pending` state. + # + # @!macro executor_and_deref_options + # + # @yield the delayed operation to perform + # + # @raise [ArgumentError] if no block is given + def initialize(opts = {}, &block) + raise ArgumentError.new('no block given') unless block_given? + super(&nil) + synchronize { ns_initialize(opts, &block) } + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. If the delayed operation + # raised an exception this method will return nil. The exception object + # can be accessed via the `#reason` method. + # + # @param [Numeric] timeout the maximum number of seconds to wait + # @return [Object] the current value of the object + # + # @!macro delay_note_regarding_blocking + def value(timeout = nil) + if @executor # TODO (pitr 12-Sep-2015): broken unsafe read? + super + else + # this function has been optimized for performance and + # should not be modified without running new benchmarks + synchronize do + execute = @evaluation_started = true unless @evaluation_started + if execute + begin + set_state(true, @task.call, nil) + rescue => ex + set_state(false, nil, ex) + end + elsif incomplete? + raise IllegalOperationError, 'Recursive call to #value during evaluation of the Delay' + end + end + if @do_nothing_on_deref + @value + else + apply_deref_options(@value) + end + end + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. If the delayed operation + # raised an exception, this method will raise that exception (even when) + # the operation has already been executed). + # + # @param [Numeric] timeout the maximum number of seconds to wait + # @return [Object] the current value of the object + # @raise [Exception] when `#rejected?` raises `#reason` + # + # @!macro delay_note_regarding_blocking + def value!(timeout = nil) + if @executor + super + else + result = value + raise @reason if @reason + result + end + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. + # + # @param [Integer] timeout (nil) the maximum number of seconds to wait for + # the value to be computed. When `nil` the caller will block indefinitely. + # + # @return [Object] self + # + # @!macro delay_note_regarding_blocking + def wait(timeout = nil) + if @executor + execute_task_once + super(timeout) + else + value + end + self + end + + # Reconfigures the block returning the value if still `#incomplete?` + # + # @yield the delayed operation to perform + # @return [true, false] if success + def reconfigure(&block) + synchronize do + raise ArgumentError.new('no block given') unless block_given? + unless @evaluation_started + @task = block + true + else + false + end + end + end + + protected + + def ns_initialize(opts, &block) + init_obligation + set_deref_options(opts) + @executor = opts[:executor] + + @task = block + @state = :pending + @evaluation_started = false + end + + private + + # @!visibility private + def execute_task_once # :nodoc: + # this function has been optimized for performance and + # should not be modified without running new benchmarks + execute = task = nil + synchronize do + execute = @evaluation_started = true unless @evaluation_started + task = @task + end + + if execute + executor = Options.executor_from_options(executor: @executor) + executor.post do + begin + result = task.call + success = true + rescue => ex + reason = ex + end + synchronize do + set_state(success, result, reason) + event.set + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/errors.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/errors.rb new file mode 100644 index 00000000..74f1fc3d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/errors.rb @@ -0,0 +1,74 @@ +module Concurrent + + Error = Class.new(StandardError) + + # Raised when errors occur during configuration. + ConfigurationError = Class.new(Error) + + # Raised when an asynchronous operation is cancelled before execution. + CancelledOperationError = Class.new(Error) + + # Raised when a lifecycle method (such as `stop`) is called in an improper + # sequence or when the object is in an inappropriate state. + LifecycleError = Class.new(Error) + + # Raised when an attempt is made to violate an immutability guarantee. + ImmutabilityError = Class.new(Error) + + # Raised when an operation is attempted which is not legal given the + # receiver's current state + IllegalOperationError = Class.new(Error) + + # Raised when an object's methods are called when it has not been + # properly initialized. + InitializationError = Class.new(Error) + + # Raised when an object with a start/stop lifecycle has been started an + # excessive number of times. Often used in conjunction with a restart + # policy or strategy. + MaxRestartFrequencyError = Class.new(Error) + + # Raised when an attempt is made to modify an immutable object + # (such as an `IVar`) after its final state has been set. + class MultipleAssignmentError < Error + attr_reader :inspection_data + + def initialize(message = nil, inspection_data = nil) + @inspection_data = inspection_data + super message + end + + def inspect + format '%s %s>', super[0..-2], @inspection_data.inspect + end + end + + # Raised by an `Executor` when it is unable to process a given task, + # possibly because of a reject policy or other internal error. + RejectedExecutionError = Class.new(Error) + + # Raised when any finite resource, such as a lock counter, exceeds its + # maximum limit/threshold. + ResourceLimitError = Class.new(Error) + + # Raised when an operation times out. + TimeoutError = Class.new(Error) + + # Aggregates multiple exceptions. + class MultipleErrors < Error + attr_reader :errors + + def initialize(errors, message = "#{errors.size} errors") + @errors = errors + super [*message, + *errors.map { |e| [format('%s (%s)', e.message, e.class), *e.backtrace] }.flatten(1) + ].join("\n") + end + end + + # @!macro internal_implementation_note + class ConcurrentUpdateError < ThreadError + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/exchanger.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/exchanger.rb new file mode 100644 index 00000000..a5405d25 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/exchanger.rb @@ -0,0 +1,353 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/maybe' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/utility/engine' +require 'concurrent/utility/monotonic_time' + +module Concurrent + + # @!macro exchanger + # + # A synchronization point at which threads can pair and swap elements within + # pairs. Each thread presents some object on entry to the exchange method, + # matches with a partner thread, and receives its partner's object on return. + # + # @!macro thread_safe_variable_comparison + # + # This implementation is very simple, using only a single slot for each + # exchanger (unlike more advanced implementations which use an "arena"). + # This approach will work perfectly fine when there are only a few threads + # accessing a single `Exchanger`. Beyond a handful of threads the performance + # will degrade rapidly due to contention on the single slot, but the algorithm + # will remain correct. + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger + # @example + # + # exchanger = Concurrent::Exchanger.new + # + # threads = [ + # Thread.new { puts "first: " << exchanger.exchange('foo', 1) }, #=> "first: bar" + # Thread.new { puts "second: " << exchanger.exchange('bar', 1) } #=> "second: foo" + # ] + # threads.each {|t| t.join(2) } + + # @!visibility private + class AbstractExchanger < Synchronization::Object + + # @!visibility private + CANCEL = ::Object.new + private_constant :CANCEL + + def initialize + super + end + + # @!macro exchanger_method_do_exchange + # + # Waits for another thread to arrive at this exchange point (unless the + # current thread is interrupted), and then transfers the given object to + # it, receiving its object in return. The timeout value indicates the + # approximate number of seconds the method should block while waiting + # for the exchange. When the timeout value is `nil` the method will + # block indefinitely. + # + # @param [Object] value the value to exchange with another thread + # @param [Numeric, nil] timeout in seconds, `nil` blocks indefinitely + # + # @!macro exchanger_method_exchange + # + # In some edge cases when a `timeout` is given a return value of `nil` may be + # ambiguous. Specifically, if `nil` is a valid value in the exchange it will + # be impossible to tell whether `nil` is the actual return value or if it + # signifies timeout. When `nil` is a valid value in the exchange consider + # using {#exchange!} or {#try_exchange} instead. + # + # @return [Object] the value exchanged by the other thread or `nil` on timeout + def exchange(value, timeout = nil) + (value = do_exchange(value, timeout)) == CANCEL ? nil : value + end + + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange_bang + # + # On timeout a {Concurrent::TimeoutError} exception will be raised. + # + # @return [Object] the value exchanged by the other thread + # @raise [Concurrent::TimeoutError] on timeout + def exchange!(value, timeout = nil) + if (value = do_exchange(value, timeout)) == CANCEL + raise Concurrent::TimeoutError + else + value + end + end + + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_try_exchange + # + # The return value will be a {Concurrent::Maybe} set to `Just` on success or + # `Nothing` on timeout. + # + # @return [Concurrent::Maybe] on success a `Just` maybe will be returned with + # the item exchanged by the other thread as `#value`; on timeout a + # `Nothing` maybe will be returned with {Concurrent::TimeoutError} as `#reason` + # + # @example + # + # exchanger = Concurrent::Exchanger.new + # + # result = exchanger.exchange(:foo, 0.5) + # + # if result.just? + # puts result.value #=> :bar + # else + # puts 'timeout' + # end + def try_exchange(value, timeout = nil) + if (value = do_exchange(value, timeout)) == CANCEL + Concurrent::Maybe.nothing(Concurrent::TimeoutError) + else + Concurrent::Maybe.just(value) + end + end + + private + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + raise NotImplementedError + end + end + + # @!macro internal_implementation_note + # @!visibility private + class RubyExchanger < AbstractExchanger + # A simplified version of java.util.concurrent.Exchanger written by + # Doug Lea, Bill Scherer, and Michael Scott with assistance from members + # of JCP JSR-166 Expert Group and released to the public domain. It does + # not include the arena or the multi-processor spin loops. + # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/Exchanger.java + + safe_initialization! + + class Node < Concurrent::Synchronization::Object + attr_atomic :value + safe_initialization! + + def initialize(item) + super() + @Item = item + @Latch = Concurrent::CountDownLatch.new + self.value = nil + end + + def latch + @Latch + end + + def item + @Item + end + end + private_constant :Node + + def initialize + super + end + + private + + attr_atomic(:slot) + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + + # ALGORITHM + # + # From the original Java version: + # + # > The basic idea is to maintain a "slot", which is a reference to + # > a Node containing both an Item to offer and a "hole" waiting to + # > get filled in. If an incoming "occupying" thread sees that the + # > slot is null, it CAS'es (compareAndSets) a Node there and waits + # > for another to invoke exchange. That second "fulfilling" thread + # > sees that the slot is non-null, and so CASes it back to null, + # > also exchanging items by CASing the hole, plus waking up the + # > occupying thread if it is blocked. In each case CAS'es may + # > fail because a slot at first appears non-null but is null upon + # > CAS, or vice-versa. So threads may need to retry these + # > actions. + # + # This version: + # + # An exchange occurs between an "occupier" thread and a "fulfiller" thread. + # The "slot" is used to setup this interaction. The first thread in the + # exchange puts itself into the slot (occupies) and waits for a fulfiller. + # The second thread removes the occupier from the slot and attempts to + # perform the exchange. Removing the occupier also frees the slot for + # another occupier/fulfiller pair. + # + # Because the occupier and the fulfiller are operating independently and + # because there may be contention with other threads, any failed operation + # indicates contention. Both the occupier and the fulfiller operate within + # spin loops. Any failed actions along the happy path will cause the thread + # to repeat the loop and try again. + # + # When a timeout value is given the thread must be cognizant of time spent + # in the spin loop. The remaining time is checked every loop. When the time + # runs out the thread will exit. + # + # A "node" is the data structure used to perform the exchange. Only the + # occupier's node is necessary. It's the node used for the exchange. + # Each node has an "item," a "hole" (self), and a "latch." The item is the + # node's initial value. It never changes. It's what the fulfiller returns on + # success. The occupier's hole is where the fulfiller put its item. It's the + # item that the occupier returns on success. The latch is used for synchronization. + # Because a thread may act as either an occupier or fulfiller (or possibly + # both in periods of high contention) every thread creates a node when + # the exchange method is first called. + # + # The following steps occur within the spin loop. If any actions fail + # the thread will loop and try again, so long as there is time remaining. + # If time runs out the thread will return CANCEL. + # + # Check the slot for an occupier: + # + # * If the slot is empty try to occupy + # * If the slot is full try to fulfill + # + # Attempt to occupy: + # + # * Attempt to CAS myself into the slot + # * Go to sleep and wait to be woken by a fulfiller + # * If the sleep is successful then the fulfiller completed its happy path + # - Return the value from my hole (the value given by the fulfiller) + # * When the sleep fails (time ran out) attempt to cancel the operation + # - Attempt to CAS myself out of the hole + # - If successful there is no contention + # - Return CANCEL + # - On failure, I am competing with a fulfiller + # - Attempt to CAS my hole to CANCEL + # - On success + # - Let the fulfiller deal with my cancel + # - Return CANCEL + # - On failure the fulfiller has completed its happy path + # - Return th value from my hole (the fulfiller's value) + # + # Attempt to fulfill: + # + # * Attempt to CAS the occupier out of the slot + # - On failure loop again + # * Attempt to CAS my item into the occupier's hole + # - On failure the occupier is trying to cancel + # - Loop again + # - On success we are on the happy path + # - Wake the sleeping occupier + # - Return the occupier's item + + value = NULL if value.nil? # The sentinel allows nil to be a valid value + me = Node.new(value) # create my node in case I need to occupy + end_at = Concurrent.monotonic_time + timeout.to_f # The time to give up + + result = loop do + other = slot + if other && compare_and_set_slot(other, nil) + # try to fulfill + if other.compare_and_set_value(nil, value) + # happy path + other.latch.count_down + break other.item + end + elsif other.nil? && compare_and_set_slot(nil, me) + # try to occupy + timeout = end_at - Concurrent.monotonic_time if timeout + if me.latch.wait(timeout) + # happy path + break me.value + else + # attempt to remove myself from the slot + if compare_and_set_slot(me, nil) + break CANCEL + elsif !me.compare_and_set_value(nil, CANCEL) + # I've failed to block the fulfiller + break me.value + end + end + end + break CANCEL if timeout && Concurrent.monotonic_time >= end_at + end + + result == NULL ? nil : result + end + end + + if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + + # @!macro internal_implementation_note + # @!visibility private + class JavaExchanger < AbstractExchanger + + def initialize + @exchanger = java.util.concurrent.Exchanger.new + end + + private + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + result = nil + if timeout.nil? + Synchronization::JRuby.sleep_interruptibly do + result = @exchanger.exchange(value) + end + else + Synchronization::JRuby.sleep_interruptibly do + result = @exchanger.exchange(value, 1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + result + rescue java.util.concurrent.TimeoutException + CANCEL + end + end + end + + # @!visibility private + # @!macro internal_implementation_note + ExchangerImplementation = case + when Concurrent.on_jruby? + JavaExchanger + else + RubyExchanger + end + private_constant :ExchangerImplementation + + # @!macro exchanger + class Exchanger < ExchangerImplementation + + # @!method initialize + # Creates exchanger instance + + # @!method exchange(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange + + # @!method exchange!(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange_bang + + # @!method try_exchange(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_try_exchange + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb new file mode 100644 index 00000000..ac429531 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb @@ -0,0 +1,131 @@ +require 'concurrent/errors' +require 'concurrent/concern/deprecation' +require 'concurrent/executor/executor_service' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class AbstractExecutorService < Synchronization::LockableObject + include ExecutorService + include Concern::Deprecation + + # The set of possible fallback policies that may be set at thread pool creation. + FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze + + # @!macro executor_service_attr_reader_fallback_policy + attr_reader :fallback_policy + + attr_reader :name + + # Create a new thread pool. + def initialize(opts = {}, &block) + super(&nil) + synchronize do + @auto_terminate = opts.fetch(:auto_terminate, true) + @name = opts.fetch(:name) if opts.key?(:name) + ns_initialize(opts, &block) + end + end + + def to_s + name ? "#{super[0..-2]} name: #{name}>" : super + end + + # @!macro executor_service_method_shutdown + def shutdown + raise NotImplementedError + end + + # @!macro executor_service_method_kill + def kill + raise NotImplementedError + end + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + raise NotImplementedError + end + + # @!macro executor_service_method_running_question + def running? + synchronize { ns_running? } + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + synchronize { ns_shuttingdown? } + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + synchronize { ns_shutdown? } + end + + # @!macro executor_service_method_auto_terminate_question + def auto_terminate? + synchronize { @auto_terminate } + end + + # @!macro executor_service_method_auto_terminate_setter + def auto_terminate=(value) + deprecated "Method #auto_terminate= has no effect. Set :auto_terminate option when executor is initialized." + end + + private + + # Returns an action which executes the `fallback_policy` once the queue + # size reaches `max_queue`. The reason for the indirection of an action + # is so that the work can be deferred outside of synchronization. + # + # @param [Array] args the arguments to the task which is being handled. + # + # @!visibility private + def fallback_action(*args) + case fallback_policy + when :abort + lambda { raise RejectedExecutionError } + when :discard + lambda { false } + when :caller_runs + lambda { + begin + yield(*args) + rescue => ex + # let it fail + log DEBUG, ex + end + true + } + else + lambda { fail "Unknown fallback policy #{fallback_policy}" } + end + end + + def ns_execute(*args, &task) + raise NotImplementedError + end + + # @!macro executor_service_method_ns_shutdown_execution + # + # Callback method called when an orderly shutdown has completed. + # The default behavior is to signal all waiting threads. + def ns_shutdown_execution + # do nothing + end + + # @!macro executor_service_method_ns_kill_execution + # + # Callback method called when the executor has been killed. + # The default behavior is to do nothing. + def ns_kill_execution + # do nothing + end + + def ns_auto_terminate? + @auto_terminate + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb new file mode 100644 index 00000000..de50ed17 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb @@ -0,0 +1,62 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/thread_pool_executor' + +module Concurrent + + # A thread pool that dynamically grows and shrinks to fit the current workload. + # New threads are created as needed, existing threads are reused, and threads + # that remain idle for too long are killed and removed from the pool. These + # pools are particularly suited to applications that perform a high volume of + # short-lived tasks. + # + # On creation a `CachedThreadPool` has zero running threads. New threads are + # created on the pool as new operations are `#post`. The size of the pool + # will grow until `#max_length` threads are in the pool or until the number + # of threads exceeds the number of running and pending operations. When a new + # operation is post to the pool the first available idle thread will be tasked + # with the new operation. + # + # Should a thread crash for any reason the thread will immediately be removed + # from the pool. Similarly, threads which remain idle for an extended period + # of time will be killed and reclaimed. Thus these thread pools are very + # efficient at reclaiming unused resources. + # + # The API and behavior of this class are based on Java's `CachedThreadPool` + # + # @!macro thread_pool_options + class CachedThreadPool < ThreadPoolExecutor + + # @!macro cached_thread_pool_method_initialize + # + # Create a new thread pool. + # + # @param [Hash] opts the options defining pool behavior. + # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy + # + # @raise [ArgumentError] if `fallback_policy` is not a known policy + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool-- + def initialize(opts = {}) + defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT } + overrides = { min_threads: 0, + max_threads: DEFAULT_MAX_POOL_SIZE, + max_queue: DEFAULT_MAX_QUEUE_SIZE } + super(defaults.merge(opts).merge(overrides)) + end + + private + + # @!macro cached_thread_pool_method_initialize + # @!visibility private + def ns_initialize(opts) + super(opts) + if Concurrent.on_jruby? + @max_queue = 0 + @executor = java.util.concurrent.Executors.newCachedThreadPool( + DaemonThreadFactory.new(ns_auto_terminate?)) + @executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new) + @executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/executor_service.rb new file mode 100644 index 00000000..7e344919 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/executor_service.rb @@ -0,0 +1,185 @@ +require 'concurrent/concern/logging' + +module Concurrent + + ################################################################### + + # @!macro executor_service_method_post + # + # Submit a task to the executor for asynchronous processing. + # + # @param [Array] args zero or more arguments to be passed to the task + # + # @yield the asynchronous task to perform + # + # @return [Boolean] `true` if the task is queued, `false` if the executor + # is not running + # + # @raise [ArgumentError] if no task is given + + # @!macro executor_service_method_left_shift + # + # Submit a task to the executor for asynchronous processing. + # + # @param [Proc] task the asynchronous task to perform + # + # @return [self] returns itself + + # @!macro executor_service_method_can_overflow_question + # + # Does the task queue have a maximum size? + # + # @return [Boolean] True if the task queue has a maximum size else false. + + # @!macro executor_service_method_serialized_question + # + # Does this executor guarantee serialization of its operations? + # + # @return [Boolean] True if the executor guarantees that all operations + # will be post in the order they are received and no two operations may + # occur simultaneously. Else false. + + ################################################################### + + # @!macro executor_service_public_api + # + # @!method post(*args, &task) + # @!macro executor_service_method_post + # + # @!method <<(task) + # @!macro executor_service_method_left_shift + # + # @!method can_overflow? + # @!macro executor_service_method_can_overflow_question + # + # @!method serialized? + # @!macro executor_service_method_serialized_question + + ################################################################### + + # @!macro executor_service_attr_reader_fallback_policy + # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`. + + # @!macro executor_service_method_shutdown + # + # Begin an orderly shutdown. Tasks already in the queue will be executed, + # but no new tasks will be accepted. Has no additional effect if the + # thread pool is not running. + + # @!macro executor_service_method_kill + # + # Begin an immediate shutdown. In-progress tasks will be allowed to + # complete but enqueued tasks will be dismissed and no new tasks + # will be accepted. Has no additional effect if the thread pool is + # not running. + + # @!macro executor_service_method_wait_for_termination + # + # Block until executor shutdown is complete or until `timeout` seconds have + # passed. + # + # @note Does not initiate shutdown or termination. Either `shutdown` or `kill` + # must be called before this method (or on another thread). + # + # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete + # + # @return [Boolean] `true` if shutdown complete or false on `timeout` + + # @!macro executor_service_method_running_question + # + # Is the executor running? + # + # @return [Boolean] `true` when running, `false` when shutting down or shutdown + + # @!macro executor_service_method_shuttingdown_question + # + # Is the executor shuttingdown? + # + # @return [Boolean] `true` when not running and not shutdown, else `false` + + # @!macro executor_service_method_shutdown_question + # + # Is the executor shutdown? + # + # @return [Boolean] `true` when shutdown, `false` when shutting down or running + + # @!macro executor_service_method_auto_terminate_question + # + # Is the executor auto-terminate when the application exits? + # + # @return [Boolean] `true` when auto-termination is enabled else `false`. + + # @!macro executor_service_method_auto_terminate_setter + # + # + # Set the auto-terminate behavior for this executor. + # @deprecated Has no effect + # @param [Boolean] value The new auto-terminate value to set for this executor. + # @return [Boolean] `true` when auto-termination is enabled else `false`. + + ################################################################### + + # @!macro abstract_executor_service_public_api + # + # @!macro executor_service_public_api + # + # @!attribute [r] fallback_policy + # @!macro executor_service_attr_reader_fallback_policy + # + # @!method shutdown + # @!macro executor_service_method_shutdown + # + # @!method kill + # @!macro executor_service_method_kill + # + # @!method wait_for_termination(timeout = nil) + # @!macro executor_service_method_wait_for_termination + # + # @!method running? + # @!macro executor_service_method_running_question + # + # @!method shuttingdown? + # @!macro executor_service_method_shuttingdown_question + # + # @!method shutdown? + # @!macro executor_service_method_shutdown_question + # + # @!method auto_terminate? + # @!macro executor_service_method_auto_terminate_question + # + # @!method auto_terminate=(value) + # @!macro executor_service_method_auto_terminate_setter + + ################################################################### + + # @!macro executor_service_public_api + # @!visibility private + module ExecutorService + include Concern::Logging + + # @!macro executor_service_method_post + def post(*args, &task) + raise NotImplementedError + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_can_overflow_question + # + # @note Always returns `false` + def can_overflow? + false + end + + # @!macro executor_service_method_serialized_question + # + # @note Always returns `false` + def serialized? + false + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb new file mode 100644 index 00000000..8324c067 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb @@ -0,0 +1,224 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/thread_pool_executor' + +module Concurrent + + # @!macro thread_pool_executor_constant_default_max_pool_size + # Default maximum number of threads that will be created in the pool. + + # @!macro thread_pool_executor_constant_default_min_pool_size + # Default minimum number of threads that will be retained in the pool. + + # @!macro thread_pool_executor_constant_default_max_queue_size + # Default maximum number of tasks that may be added to the task queue. + + # @!macro thread_pool_executor_constant_default_thread_timeout + # Default maximum number of seconds a thread in the pool may remain idle + # before being reclaimed. + + # @!macro thread_pool_executor_constant_default_synchronous + # Default value of the :synchronous option. + + # @!macro thread_pool_executor_attr_reader_max_length + # The maximum number of threads that may be created in the pool. + # @return [Integer] The maximum number of threads that may be created in the pool. + + # @!macro thread_pool_executor_attr_reader_min_length + # The minimum number of threads that may be retained in the pool. + # @return [Integer] The minimum number of threads that may be retained in the pool. + + # @!macro thread_pool_executor_attr_reader_largest_length + # The largest number of threads that have been created in the pool since construction. + # @return [Integer] The largest number of threads that have been created in the pool since construction. + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + # The number of tasks that have been scheduled for execution on the pool since construction. + # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction. + + # @!macro thread_pool_executor_attr_reader_completed_task_count + # The number of tasks that have been completed by the pool since construction. + # @return [Integer] The number of tasks that have been completed by the pool since construction. + + # @!macro thread_pool_executor_method_active_count + # The number of threads that are actively executing tasks. + # @return [Integer] The number of threads that are actively executing tasks. + + # @!macro thread_pool_executor_attr_reader_idletime + # The number of seconds that a thread may be idle before being reclaimed. + # @return [Integer] The number of seconds that a thread may be idle before being reclaimed. + + # @!macro thread_pool_executor_attr_reader_synchronous + # Whether or not a value of 0 for :max_queue option means the queue must perform direct hand-off or rather unbounded queue. + # @return [true, false] + + # @!macro thread_pool_executor_attr_reader_max_queue + # The maximum number of tasks that may be waiting in the work queue at any one time. + # When the queue size reaches `max_queue` subsequent tasks will be rejected in + # accordance with the configured `fallback_policy`. + # + # @return [Integer] The maximum number of tasks that may be waiting in the work queue at any one time. + # When the queue size reaches `max_queue` subsequent tasks will be rejected in + # accordance with the configured `fallback_policy`. + + # @!macro thread_pool_executor_attr_reader_length + # The number of threads currently in the pool. + # @return [Integer] The number of threads currently in the pool. + + # @!macro thread_pool_executor_attr_reader_queue_length + # The number of tasks in the queue awaiting execution. + # @return [Integer] The number of tasks in the queue awaiting execution. + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + # Number of tasks that may be enqueued before reaching `max_queue` and rejecting + # new tasks. A value of -1 indicates that the queue may grow without bound. + # + # @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting + # new tasks. A value of -1 indicates that the queue may grow without bound. + + # @!macro thread_pool_executor_method_prune_pool + # Prune the thread pool of unneeded threads + # + # What is being pruned is controlled by the min_threads and idletime + # parameters passed at pool creation time + # + # This is a no-op on some pool implementation (e.g. the Java one). The Ruby + # pool will auto-prune each time a new job is posted. You will need to call + # this method explicitly in case your application post jobs in bursts (a + # lot of jobs and then nothing for long periods) + + # @!macro thread_pool_executor_public_api + # + # @!macro abstract_executor_service_public_api + # + # @!attribute [r] max_length + # @!macro thread_pool_executor_attr_reader_max_length + # + # @!attribute [r] min_length + # @!macro thread_pool_executor_attr_reader_min_length + # + # @!attribute [r] largest_length + # @!macro thread_pool_executor_attr_reader_largest_length + # + # @!attribute [r] scheduled_task_count + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + # + # @!attribute [r] completed_task_count + # @!macro thread_pool_executor_attr_reader_completed_task_count + # + # @!attribute [r] idletime + # @!macro thread_pool_executor_attr_reader_idletime + # + # @!attribute [r] max_queue + # @!macro thread_pool_executor_attr_reader_max_queue + # + # @!attribute [r] length + # @!macro thread_pool_executor_attr_reader_length + # + # @!attribute [r] queue_length + # @!macro thread_pool_executor_attr_reader_queue_length + # + # @!attribute [r] remaining_capacity + # @!macro thread_pool_executor_attr_reader_remaining_capacity + # + # @!method can_overflow? + # @!macro executor_service_method_can_overflow_question + # + # @!method prune_pool + # @!macro thread_pool_executor_method_prune_pool + + + + + # @!macro thread_pool_options + # + # **Thread Pool Options** + # + # Thread pools support several configuration options: + # + # * `idletime`: The number of seconds that a thread may be idle before being reclaimed. + # * `name`: The name of the executor (optional). Printed in the executor's `#to_s` output and + # a `-worker-` name is given to its threads if supported by used Ruby + # implementation. `` is uniq for each thread. + # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at + # any one time. When the queue size reaches `max_queue` and no new threads can be created, + # subsequent tasks will be rejected in accordance with the configured `fallback_policy`. + # * `auto_terminate`: When true (default), the threads started will be marked as daemon. + # * `fallback_policy`: The policy defining how rejected tasks are handled. + # + # Three fallback policies are supported: + # + # * `:abort`: Raise a `RejectedExecutionError` exception and discard the task. + # * `:discard`: Discard the task and return false. + # * `:caller_runs`: Execute the task on the calling thread. + # + # **Shutting Down Thread Pools** + # + # Killing a thread pool while tasks are still being processed, either by calling + # the `#kill` method or at application exit, will have unpredictable results. There + # is no way for the thread pool to know what resources are being used by the + # in-progress tasks. When those tasks are killed the impact on those resources + # cannot be predicted. The *best* practice is to explicitly shutdown all thread + # pools using the provided methods: + # + # * Call `#shutdown` to initiate an orderly termination of all in-progress tasks + # * Call `#wait_for_termination` with an appropriate timeout interval an allow + # the orderly shutdown to complete + # * Call `#kill` *only when* the thread pool fails to shutdown in the allotted time + # + # On some runtime platforms (most notably the JVM) the application will not + # exit until all thread pools have been shutdown. To prevent applications from + # "hanging" on exit, all threads can be marked as daemon according to the + # `:auto_terminate` option. + # + # ```ruby + # pool1 = Concurrent::FixedThreadPool.new(5) # threads will be marked as daemon + # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # mark threads as non-daemon + # ``` + # + # @note Failure to properly shutdown a thread pool can lead to unpredictable results. + # Please read *Shutting Down Thread Pools* for more information. + # + # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface + # @see https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDaemon-boolean- + + + + + + # @!macro fixed_thread_pool + # + # A thread pool that reuses a fixed number of threads operating off an unbounded queue. + # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new + # tasks `#post` to the thread pool are enqueued until a thread becomes available. + # Should a thread crash for any reason the thread will immediately be removed + # from the pool and replaced. + # + # The API and behavior of this class are based on Java's `FixedThreadPool` + # + # @!macro thread_pool_options + class FixedThreadPool < ThreadPoolExecutor + + # @!macro fixed_thread_pool_method_initialize + # + # Create a new thread pool. + # + # @param [Integer] num_threads the number of threads to allocate + # @param [Hash] opts the options defining pool behavior. + # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy + # + # @raise [ArgumentError] if `num_threads` is less than or equal to zero + # @raise [ArgumentError] if `fallback_policy` is not a known policy + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int- + def initialize(num_threads, opts = {}) + raise ArgumentError.new('number of threads must be greater than zero') if num_threads.to_i < 1 + defaults = { max_queue: DEFAULT_MAX_QUEUE_SIZE, + idletime: DEFAULT_THREAD_IDLETIMEOUT } + overrides = { min_threads: num_threads, + max_threads: num_threads } + super(defaults.merge(opts).merge(overrides)) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb new file mode 100644 index 00000000..282df7a0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb @@ -0,0 +1,66 @@ +require 'concurrent/atomic/event' +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/executor/serial_executor_service' + +module Concurrent + + # An executor service which runs all operations on the current thread, + # blocking as necessary. Operations are performed in the order they are + # received and no two operations can be performed simultaneously. + # + # This executor service exists mainly for testing an debugging. When used + # it immediately runs every `#post` operation on the current thread, blocking + # that thread until the operation is complete. This can be very beneficial + # during testing because it makes all operations deterministic. + # + # @note Intended for use primarily in testing and debugging. + class ImmediateExecutor < AbstractExecutorService + include SerialExecutorService + + # Creates a new executor + def initialize + @stopped = Concurrent::Event.new + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + task.call(*args) + true + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_running_question + def running? + ! shutdown? + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + false + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + @stopped.set? + end + + # @!macro executor_service_method_shutdown + def shutdown + @stopped.set + true + end + alias_method :kill, :shutdown + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + @stopped.wait(timeout) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb new file mode 100644 index 00000000..4f9769fa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb @@ -0,0 +1,44 @@ +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/simple_executor_service' + +module Concurrent + # An executor service which runs all operations on a new thread, blocking + # until it completes. Operations are performed in the order they are received + # and no two operations can be performed simultaneously. + # + # This executor service exists mainly for testing an debugging. When used it + # immediately runs every `#post` operation on a new thread, blocking the + # current thread until the operation is complete. This is similar to how the + # ImmediateExecutor works, but the operation has the full stack of the new + # thread at its disposal. This can be helpful when the operations will spawn + # more operations on the same executor and so on - such a situation might + # overflow the single stack in case of an ImmediateExecutor, which is + # inconsistent with how it would behave for a threaded executor. + # + # @note Intended for use primarily in testing and debugging. + class IndirectImmediateExecutor < ImmediateExecutor + # Creates a new executor + def initialize + super + @internal_executor = SimpleExecutorService.new + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new("no block given") unless block_given? + return false unless running? + + event = Concurrent::Event.new + @internal_executor.post do + begin + task.call(*args) + ensure + event.set + end + end + event.wait + + true + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb new file mode 100644 index 00000000..b2bc69a6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb @@ -0,0 +1,100 @@ +require 'concurrent/utility/engine' + +if Concurrent.on_jruby? + require 'concurrent/errors' + require 'concurrent/executor/abstract_executor_service' + + module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class JavaExecutorService < AbstractExecutorService + java_import 'java.lang.Runnable' + + FALLBACK_POLICY_CLASSES = { + abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy, + discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy, + caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy + }.freeze + private_constant :FALLBACK_POLICY_CLASSES + + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return fallback_action(*args, &task).call unless running? + @executor.submit Job.new(args, task) + true + rescue Java::JavaUtilConcurrent::RejectedExecutionException + raise RejectedExecutionError + end + + def wait_for_termination(timeout = nil) + if timeout.nil? + ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok + true + else + @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + + def shutdown + synchronize do + @executor.shutdown + nil + end + end + + def kill + synchronize do + @executor.shutdownNow + nil + end + end + + private + + def ns_running? + !(ns_shuttingdown? || ns_shutdown?) + end + + def ns_shuttingdown? + @executor.isShutdown && !@executor.isTerminated + end + + def ns_shutdown? + @executor.isTerminated + end + + class Job + include Runnable + def initialize(args, block) + @args = args + @block = block + end + + def run + @block.call(*@args) + end + end + private_constant :Job + end + + class DaemonThreadFactory + # hide include from YARD + send :include, java.util.concurrent.ThreadFactory + + def initialize(daemonize = true) + @daemonize = daemonize + @java_thread_factory = java.util.concurrent.Executors.defaultThreadFactory + end + + def newThread(runnable) + thread = @java_thread_factory.newThread(runnable) + thread.setDaemon(@daemonize) + return thread + end + end + + private_constant :DaemonThreadFactory + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb new file mode 100644 index 00000000..7aa24f2d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb @@ -0,0 +1,30 @@ +if Concurrent.on_jruby? + + require 'concurrent/executor/java_executor_service' + require 'concurrent/executor/serial_executor_service' + + module Concurrent + + # @!macro single_thread_executor + # @!macro abstract_executor_service_public_api + # @!visibility private + class JavaSingleThreadExecutor < JavaExecutorService + include SerialExecutorService + + # @!macro single_thread_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + private + + def ns_initialize(opts) + @executor = java.util.concurrent.Executors.newSingleThreadExecutor( + DaemonThreadFactory.new(ns_auto_terminate?) + ) + @fallback_policy = opts.fetch(:fallback_policy, :discard) + raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.keys.include?(@fallback_policy) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb new file mode 100644 index 00000000..598a5f91 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb @@ -0,0 +1,145 @@ +if Concurrent.on_jruby? + + require 'concurrent/executor/java_executor_service' + + module Concurrent + + # @!macro thread_pool_executor + # @!macro thread_pool_options + # @!visibility private + class JavaThreadPoolExecutor < JavaExecutorService + + # @!macro thread_pool_executor_constant_default_max_pool_size + DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647 + + # @!macro thread_pool_executor_constant_default_min_pool_size + DEFAULT_MIN_POOL_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_max_queue_size + DEFAULT_MAX_QUEUE_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_thread_timeout + DEFAULT_THREAD_IDLETIMEOUT = 60 + + # @!macro thread_pool_executor_constant_default_synchronous + DEFAULT_SYNCHRONOUS = false + + # @!macro thread_pool_executor_attr_reader_max_length + attr_reader :max_length + + # @!macro thread_pool_executor_attr_reader_max_queue + attr_reader :max_queue + + # @!macro thread_pool_executor_attr_reader_synchronous + attr_reader :synchronous + + # @!macro thread_pool_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + # @!macro executor_service_method_can_overflow_question + def can_overflow? + @max_queue != 0 + end + + # @!macro thread_pool_executor_attr_reader_min_length + def min_length + @executor.getCorePoolSize + end + + # @!macro thread_pool_executor_attr_reader_max_length + def max_length + @executor.getMaximumPoolSize + end + + # @!macro thread_pool_executor_attr_reader_length + def length + @executor.getPoolSize + end + + # @!macro thread_pool_executor_attr_reader_largest_length + def largest_length + @executor.getLargestPoolSize + end + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + def scheduled_task_count + @executor.getTaskCount + end + + # @!macro thread_pool_executor_attr_reader_completed_task_count + def completed_task_count + @executor.getCompletedTaskCount + end + + # @!macro thread_pool_executor_method_active_count + def active_count + @executor.getActiveCount + end + + # @!macro thread_pool_executor_attr_reader_idletime + def idletime + @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS) + end + + # @!macro thread_pool_executor_attr_reader_queue_length + def queue_length + @executor.getQueue.size + end + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + def remaining_capacity + @max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity + end + + # @!macro executor_service_method_running_question + def running? + super && !@executor.isTerminating + end + + # @!macro thread_pool_executor_method_prune_pool + def prune_pool + end + + private + + def ns_initialize(opts) + min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i + max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i + idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i + @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i + @synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS) + @fallback_policy = opts.fetch(:fallback_policy, :abort) + + raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0 + raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length + raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy) + + if @max_queue == 0 + if @synchronous + queue = java.util.concurrent.SynchronousQueue.new + else + queue = java.util.concurrent.LinkedBlockingQueue.new + end + else + queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue) + end + + @executor = java.util.concurrent.ThreadPoolExecutor.new( + min_length, + max_length, + idletime, + java.util.concurrent.TimeUnit::SECONDS, + queue, + DaemonThreadFactory.new(ns_auto_terminate?), + FALLBACK_POLICY_CLASSES[@fallback_policy].new) + + end + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb new file mode 100644 index 00000000..1f7301b9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb @@ -0,0 +1,82 @@ +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/atomic/event' + +module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class RubyExecutorService < AbstractExecutorService + safe_initialization! + + def initialize(*args, &block) + super + @StopEvent = Event.new + @StoppedEvent = Event.new + end + + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + deferred_action = synchronize { + if running? + ns_execute(*args, &task) + else + fallback_action(*args, &task) + end + } + if deferred_action + deferred_action.call + else + true + end + end + + def shutdown + synchronize do + break unless running? + stop_event.set + ns_shutdown_execution + end + true + end + + def kill + synchronize do + break if shutdown? + stop_event.set + ns_kill_execution + stopped_event.set + end + true + end + + def wait_for_termination(timeout = nil) + stopped_event.wait(timeout) + end + + private + + def stop_event + @StopEvent + end + + def stopped_event + @StoppedEvent + end + + def ns_shutdown_execution + stopped_event.set + end + + def ns_running? + !stop_event.set? + end + + def ns_shuttingdown? + !(ns_running? || ns_shutdown?) + end + + def ns_shutdown? + stopped_event.set? + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb new file mode 100644 index 00000000..916337d4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb @@ -0,0 +1,21 @@ +require 'concurrent/executor/ruby_thread_pool_executor' + +module Concurrent + + # @!macro single_thread_executor + # @!macro abstract_executor_service_public_api + # @!visibility private + class RubySingleThreadExecutor < RubyThreadPoolExecutor + + # @!macro single_thread_executor_method_initialize + def initialize(opts = {}) + super( + min_threads: 1, + max_threads: 1, + max_queue: 0, + idletime: DEFAULT_THREAD_IDLETIMEOUT, + fallback_policy: opts.fetch(:fallback_policy, :discard), + ) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb new file mode 100644 index 00000000..9375acf3 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb @@ -0,0 +1,373 @@ +require 'thread' +require 'concurrent/atomic/event' +require 'concurrent/concern/logging' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/utility/monotonic_time' + +module Concurrent + + # @!macro thread_pool_executor + # @!macro thread_pool_options + # @!visibility private + class RubyThreadPoolExecutor < RubyExecutorService + + # @!macro thread_pool_executor_constant_default_max_pool_size + DEFAULT_MAX_POOL_SIZE = 2_147_483_647 # java.lang.Integer::MAX_VALUE + + # @!macro thread_pool_executor_constant_default_min_pool_size + DEFAULT_MIN_POOL_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_max_queue_size + DEFAULT_MAX_QUEUE_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_thread_timeout + DEFAULT_THREAD_IDLETIMEOUT = 60 + + # @!macro thread_pool_executor_constant_default_synchronous + DEFAULT_SYNCHRONOUS = false + + # @!macro thread_pool_executor_attr_reader_max_length + attr_reader :max_length + + # @!macro thread_pool_executor_attr_reader_min_length + attr_reader :min_length + + # @!macro thread_pool_executor_attr_reader_idletime + attr_reader :idletime + + # @!macro thread_pool_executor_attr_reader_max_queue + attr_reader :max_queue + + # @!macro thread_pool_executor_attr_reader_synchronous + attr_reader :synchronous + + # @!macro thread_pool_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + # @!macro thread_pool_executor_attr_reader_largest_length + def largest_length + synchronize { @largest_length } + end + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + def scheduled_task_count + synchronize { @scheduled_task_count } + end + + # @!macro thread_pool_executor_attr_reader_completed_task_count + def completed_task_count + synchronize { @completed_task_count } + end + + # @!macro thread_pool_executor_method_active_count + def active_count + synchronize do + @pool.length - @ready.length + end + end + + # @!macro executor_service_method_can_overflow_question + def can_overflow? + synchronize { ns_limited_queue? } + end + + # @!macro thread_pool_executor_attr_reader_length + def length + synchronize { @pool.length } + end + + # @!macro thread_pool_executor_attr_reader_queue_length + def queue_length + synchronize { @queue.length } + end + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + def remaining_capacity + synchronize do + if ns_limited_queue? + @max_queue - @queue.length + else + -1 + end + end + end + + # @!visibility private + def remove_busy_worker(worker) + synchronize { ns_remove_busy_worker worker } + end + + # @!visibility private + def ready_worker(worker, last_message) + synchronize { ns_ready_worker worker, last_message } + end + + # @!visibility private + def worker_died(worker) + synchronize { ns_worker_died worker } + end + + # @!visibility private + def worker_task_completed + synchronize { @completed_task_count += 1 } + end + + # @!macro thread_pool_executor_method_prune_pool + def prune_pool + synchronize { ns_prune_pool } + end + + private + + # @!visibility private + def ns_initialize(opts) + @min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i + @max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i + @idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i + @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i + @synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS) + @fallback_policy = opts.fetch(:fallback_policy, :abort) + + raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0 + raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy) + raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @max_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if @max_length > DEFAULT_MAX_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @min_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length + + @pool = [] # all workers + @ready = [] # used as a stash (most idle worker is at the start) + @queue = [] # used as queue + # @ready or @queue is empty at all times + @scheduled_task_count = 0 + @completed_task_count = 0 + @largest_length = 0 + @workers_counter = 0 + @ruby_pid = $$ # detects if Ruby has forked + + @gc_interval = opts.fetch(:gc_interval, @idletime / 2.0).to_i # undocumented + @next_gc_time = Concurrent.monotonic_time + @gc_interval + end + + # @!visibility private + def ns_limited_queue? + @max_queue != 0 + end + + # @!visibility private + def ns_execute(*args, &task) + ns_reset_if_forked + + if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task) + @scheduled_task_count += 1 + else + return fallback_action(*args, &task) + end + + ns_prune_pool if @next_gc_time < Concurrent.monotonic_time + nil + end + + # @!visibility private + def ns_shutdown_execution + ns_reset_if_forked + + if @pool.empty? + # nothing to do + stopped_event.set + end + + if @queue.empty? + # no more tasks will be accepted, just stop all workers + @pool.each(&:stop) + end + end + + # @!visibility private + def ns_kill_execution + # TODO log out unprocessed tasks in queue + # TODO try to shutdown first? + @pool.each(&:kill) + @pool.clear + @ready.clear + end + + # tries to assign task to a worker, tries to get one from @ready or to create new one + # @return [true, false] if task is assigned to a worker + # + # @!visibility private + def ns_assign_worker(*args, &task) + # keep growing if the pool is not at the minimum yet + worker, _ = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker + if worker + worker << [task, args] + true + else + false + end + rescue ThreadError + # Raised when the operating system refuses to create the new thread + return false + end + + # tries to enqueue task + # @return [true, false] if enqueued + # + # @!visibility private + def ns_enqueue(*args, &task) + return false if @synchronous + + if !ns_limited_queue? || @queue.size < @max_queue + @queue << [task, args] + true + else + false + end + end + + # @!visibility private + def ns_worker_died(worker) + ns_remove_busy_worker worker + replacement_worker = ns_add_busy_worker + ns_ready_worker replacement_worker, Concurrent.monotonic_time, false if replacement_worker + end + + # creates new worker which has to receive work to do after it's added + # @return [nil, Worker] nil of max capacity is reached + # + # @!visibility private + def ns_add_busy_worker + return if @pool.size >= @max_length + + @workers_counter += 1 + @pool << (worker = Worker.new(self, @workers_counter)) + @largest_length = @pool.length if @pool.length > @largest_length + worker + end + + # handle ready worker, giving it new job or assigning back to @ready + # + # @!visibility private + def ns_ready_worker(worker, last_message, success = true) + task_and_args = @queue.shift + if task_and_args + worker << task_and_args + else + # stop workers when !running?, do not return them to @ready + if running? + raise unless last_message + @ready.push([worker, last_message]) + else + worker.stop + end + end + end + + # removes a worker which is not in not tracked in @ready + # + # @!visibility private + def ns_remove_busy_worker(worker) + @pool.delete(worker) + stopped_event.set if @pool.empty? && !running? + true + end + + # try oldest worker if it is idle for enough time, it's returned back at the start + # + # @!visibility private + def ns_prune_pool + now = Concurrent.monotonic_time + stopped_workers = 0 + while !@ready.empty? && (@pool.size - stopped_workers > @min_length) + worker, last_message = @ready.first + if now - last_message > self.idletime + stopped_workers += 1 + @ready.shift + worker << :stop + else break + end + end + + @next_gc_time = Concurrent.monotonic_time + @gc_interval + end + + def ns_reset_if_forked + if $$ != @ruby_pid + @queue.clear + @ready.clear + @pool.clear + @scheduled_task_count = 0 + @completed_task_count = 0 + @largest_length = 0 + @workers_counter = 0 + @ruby_pid = $$ + end + end + + # @!visibility private + class Worker + include Concern::Logging + + def initialize(pool, id) + # instance variables accessed only under pool's lock so no need to sync here again + @queue = Queue.new + @pool = pool + @thread = create_worker @queue, pool, pool.idletime + + if @thread.respond_to?(:name=) + @thread.name = [pool.name, 'worker', id].compact.join('-') + end + end + + def <<(message) + @queue << message + end + + def stop + @queue << :stop + end + + def kill + @thread.kill + end + + private + + def create_worker(queue, pool, idletime) + Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime| + catch(:stop) do + loop do + + case message = my_queue.pop + when :stop + my_pool.remove_busy_worker(self) + throw :stop + + else + task, args = message + run_task my_pool, task, args + my_pool.ready_worker(self, Concurrent.monotonic_time) + end + end + end + end + end + + def run_task(pool, task, args) + task.call(*args) + pool.worker_task_completed + rescue => ex + # let it fail + log DEBUG, ex + rescue Exception => ex + log ERROR, ex + pool.worker_died(self) + throw :stop + end + end + + private_constant :Worker + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb new file mode 100644 index 00000000..f796b857 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb @@ -0,0 +1,35 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A simple utility class that executes a callable and returns and array of three elements: + # success - indicating if the callable has been executed without errors + # value - filled by the callable result if it has been executed without errors, nil otherwise + # reason - the error risen by the callable if it has been executed with errors, nil otherwise + class SafeTaskExecutor < Synchronization::LockableObject + + def initialize(task, opts = {}) + @task = task + @exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError + super() # ensures visibility + end + + # @return [Array] + def execute(*args) + success = true + value = reason = nil + + synchronize do + begin + value = @task.call(*args) + success = true + rescue @exception_class => ex + reason = ex + success = false + end + end + + [success, value, reason] + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb new file mode 100644 index 00000000..f1c38ecf --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb @@ -0,0 +1,34 @@ +require 'concurrent/executor/executor_service' + +module Concurrent + + # Indicates that the including `ExecutorService` guarantees + # that all operations will occur in the order they are post and that no + # two operations may occur simultaneously. This module provides no + # functionality and provides no guarantees. That is the responsibility + # of the including class. This module exists solely to allow the including + # object to be interrogated for its serialization status. + # + # @example + # class Foo + # include Concurrent::SerialExecutor + # end + # + # foo = Foo.new + # + # foo.is_a? Concurrent::ExecutorService #=> true + # foo.is_a? Concurrent::SerialExecutor #=> true + # foo.serialized? #=> true + # + # @!visibility private + module SerialExecutorService + include ExecutorService + + # @!macro executor_service_method_serialized_question + # + # @note Always returns `true` + def serialized? + true + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb new file mode 100644 index 00000000..4db7c7f0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb @@ -0,0 +1,107 @@ +require 'concurrent/errors' +require 'concurrent/concern/logging' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # Ensures passed jobs in a serialized order never running at the same time. + class SerializedExecution < Synchronization::LockableObject + include Concern::Logging + + def initialize() + super() + synchronize { ns_initialize } + end + + Job = Struct.new(:executor, :args, :block) do + def call + block.call(*args) + end + end + + # Submit a task to the executor for asynchronous processing. + # + # @param [Executor] executor to be used for this job + # + # @param [Array] args zero or more arguments to be passed to the task + # + # @yield the asynchronous task to perform + # + # @return [Boolean] `true` if the task is queued, `false` if the executor + # is not running + # + # @raise [ArgumentError] if no task is given + def post(executor, *args, &task) + posts [[executor, args, task]] + true + end + + # As {#post} but allows to submit multiple tasks at once, it's guaranteed that they will not + # be interleaved by other tasks. + # + # @param [Array, Proc)>] posts array of triplets where + # first is a {ExecutorService}, second is array of args for task, third is a task (Proc) + def posts(posts) + # if can_overflow? + # raise ArgumentError, 'SerializedExecution does not support thread-pools which can overflow' + # end + + return nil if posts.empty? + + jobs = posts.map { |executor, args, task| Job.new executor, args, task } + + job_to_post = synchronize do + if @being_executed + @stash.push(*jobs) + nil + else + @being_executed = true + @stash.push(*jobs[1..-1]) + jobs.first + end + end + + call_job job_to_post if job_to_post + true + end + + private + + def ns_initialize + @being_executed = false + @stash = [] + end + + def call_job(job) + did_it_run = begin + job.executor.post { work(job) } + true + rescue RejectedExecutionError => ex + false + end + + # TODO not the best idea to run it myself + unless did_it_run + begin + work job + rescue => ex + # let it fail + log DEBUG, ex + end + end + end + + # ensures next job is executed if any is stashed + def work(job) + job.call + ensure + synchronize do + job = @stash.shift || (@being_executed = false) + end + + # TODO maybe be able to tell caching pool to just enqueue this job, because the current one end at the end + # of this block + call_job job if job + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb new file mode 100644 index 00000000..8197781b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb @@ -0,0 +1,28 @@ +require 'delegate' +require 'concurrent/executor/serial_executor_service' +require 'concurrent/executor/serialized_execution' + +module Concurrent + + # A wrapper/delegator for any `ExecutorService` that + # guarantees serialized execution of tasks. + # + # @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html) + # @see Concurrent::SerializedExecution + class SerializedExecutionDelegator < SimpleDelegator + include SerialExecutorService + + def initialize(executor) + @executor = executor + @serializer = SerializedExecution.new + super(executor) + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + @serializer.post(@executor, *args, &task) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb new file mode 100644 index 00000000..0bc62afd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb @@ -0,0 +1,103 @@ +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/atomic/event' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/ruby_executor_service' + +module Concurrent + + # An executor service in which every operation spawns a new, + # independently operating thread. + # + # This is perhaps the most inefficient executor service in this + # library. It exists mainly for testing an debugging. Thread creation + # and management is expensive in Ruby and this executor performs no + # resource pooling. This can be very beneficial during testing and + # debugging because it decouples the using code from the underlying + # executor implementation. In production this executor will likely + # lead to suboptimal performance. + # + # @note Intended for use primarily in testing and debugging. + class SimpleExecutorService < RubyExecutorService + + # @!macro executor_service_method_post + def self.post(*args) + raise ArgumentError.new('no block given') unless block_given? + Thread.new(*args) do + Thread.current.abort_on_exception = false + yield(*args) + end + true + end + + # @!macro executor_service_method_left_shift + def self.<<(task) + post(&task) + self + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + @count.increment + Thread.new(*args) do + Thread.current.abort_on_exception = false + begin + yield(*args) + ensure + @count.decrement + @stopped.set if @running.false? && @count.value == 0 + end + end + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_running_question + def running? + @running.true? + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + @running.false? && ! @stopped.set? + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + @stopped.set? + end + + # @!macro executor_service_method_shutdown + def shutdown + @running.make_false + @stopped.set if @count.value == 0 + true + end + + # @!macro executor_service_method_kill + def kill + @running.make_false + @stopped.set + true + end + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + @stopped.wait(timeout) + end + + private + + def ns_initialize(*args) + @running = Concurrent::AtomicBoolean.new(true) + @stopped = Concurrent::Event.new + @count = Concurrent::AtomicFixnum.new(0) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb new file mode 100644 index 00000000..220eb0ff --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb @@ -0,0 +1,57 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/ruby_single_thread_executor' + +module Concurrent + + if Concurrent.on_jruby? + require 'concurrent/executor/java_single_thread_executor' + end + + SingleThreadExecutorImplementation = case + when Concurrent.on_jruby? + JavaSingleThreadExecutor + else + RubySingleThreadExecutor + end + private_constant :SingleThreadExecutorImplementation + + # @!macro single_thread_executor + # + # A thread pool with a single thread an unlimited queue. Should the thread + # die for any reason it will be removed and replaced, thus ensuring that + # the executor will always remain viable and available to process jobs. + # + # A common pattern for background processing is to create a single thread + # on which an infinite loop is run. The thread's loop blocks on an input + # source (perhaps blocking I/O or a queue) and processes each input as it + # is received. This pattern has several issues. The thread itself is highly + # susceptible to errors during processing. Also, the thread itself must be + # constantly monitored and restarted should it die. `SingleThreadExecutor` + # encapsulates all these behaviors. The task processor is highly resilient + # to errors from within tasks. Also, should the thread die it will + # automatically be restarted. + # + # The API and behavior of this class are based on Java's `SingleThreadExecutor`. + # + # @!macro abstract_executor_service_public_api + class SingleThreadExecutor < SingleThreadExecutorImplementation + + # @!macro single_thread_executor_method_initialize + # + # Create a new thread pool. + # + # @option opts [Symbol] :fallback_policy (:discard) the policy for handling new + # tasks that are received when the queue size has reached + # `max_queue` or the executor has shut down + # + # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified + # in `FALLBACK_POLICIES` + # + # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html + + # @!method initialize(opts = {}) + # @!macro single_thread_executor_method_initialize + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb new file mode 100644 index 00000000..253d46a9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb @@ -0,0 +1,88 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/ruby_thread_pool_executor' + +module Concurrent + + if Concurrent.on_jruby? + require 'concurrent/executor/java_thread_pool_executor' + end + + ThreadPoolExecutorImplementation = case + when Concurrent.on_jruby? + JavaThreadPoolExecutor + else + RubyThreadPoolExecutor + end + private_constant :ThreadPoolExecutorImplementation + + # @!macro thread_pool_executor + # + # An abstraction composed of one or more threads and a task queue. Tasks + # (blocks or `proc` objects) are submitted to the pool and added to the queue. + # The threads in the pool remove the tasks and execute them in the order + # they were received. + # + # A `ThreadPoolExecutor` will automatically adjust the pool size according + # to the bounds set by `min-threads` and `max-threads`. When a new task is + # submitted and fewer than `min-threads` threads are running, a new thread + # is created to handle the request, even if other worker threads are idle. + # If there are more than `min-threads` but less than `max-threads` threads + # running, a new thread will be created only if the queue is full. + # + # Threads that are idle for too long will be garbage collected, down to the + # configured minimum options. Should a thread crash it, too, will be garbage collected. + # + # `ThreadPoolExecutor` is based on the Java class of the same name. From + # the official Java documentation; + # + # > Thread pools address two different problems: they usually provide + # > improved performance when executing large numbers of asynchronous tasks, + # > due to reduced per-task invocation overhead, and they provide a means + # > of bounding and managing the resources, including threads, consumed + # > when executing a collection of tasks. Each ThreadPoolExecutor also + # > maintains some basic statistics, such as the number of completed tasks. + # > + # > To be useful across a wide range of contexts, this class provides many + # > adjustable parameters and extensibility hooks. However, programmers are + # > urged to use the more convenient Executors factory methods + # > [CachedThreadPool] (unbounded thread pool, with automatic thread reclamation), + # > [FixedThreadPool] (fixed size thread pool) and [SingleThreadExecutor] (single + # > background thread), that preconfigure settings for the most common usage + # > scenarios. + # + # @!macro thread_pool_options + # + # @!macro thread_pool_executor_public_api + class ThreadPoolExecutor < ThreadPoolExecutorImplementation + + # @!macro thread_pool_executor_method_initialize + # + # Create a new thread pool. + # + # @param [Hash] opts the options which configure the thread pool. + # + # @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum + # number of threads to be created + # @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) When a new task is submitted + # and fewer than `min_threads` are running, a new thread is created + # @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum + # number of seconds a thread may be idle before being reclaimed + # @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum + # number of tasks allowed in the work queue at any one time; a value of + # zero means the queue may grow without bound + # @option opts [Symbol] :fallback_policy (:abort) the policy for handling new + # tasks that are received when the queue size has reached + # `max_queue` or the executor has shut down + # @option opts [Boolean] :synchronous (DEFAULT_SYNCHRONOUS) whether or not a value of 0 + # for :max_queue means the queue must perform direct hand-off rather than unbounded. + # @raise [ArgumentError] if `:max_threads` is less than one + # @raise [ArgumentError] if `:min_threads` is less than zero + # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified + # in `FALLBACK_POLICIES` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html + + # @!method initialize(opts = {}) + # @!macro thread_pool_executor_method_initialize + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/timer_set.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/timer_set.rb new file mode 100644 index 00000000..759dce09 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/timer_set.rb @@ -0,0 +1,176 @@ +require 'concurrent/scheduled_task' +require 'concurrent/atomic/event' +require 'concurrent/collection/non_concurrent_priority_queue' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/single_thread_executor' +require 'concurrent/errors' +require 'concurrent/options' + +module Concurrent + + # Executes a collection of tasks, each after a given delay. A master task + # monitors the set and schedules each task for execution at the appropriate + # time. Tasks are run on the global thread pool or on the supplied executor. + # Each task is represented as a `ScheduledTask`. + # + # @see Concurrent::ScheduledTask + # + # @!macro monotonic_clock_warning + class TimerSet < RubyExecutorService + + # Create a new set of timed tasks. + # + # @!macro executor_options + # + # @param [Hash] opts the options used to specify the executor on which to perform actions + # @option opts [Executor] :executor when set use the given `Executor` instance. + # Three special values are also supported: `:task` returns the global task pool, + # `:operation` returns the global operation pool, and `:immediate` returns a new + # `ImmediateExecutor` object. + def initialize(opts = {}) + super(opts) + end + + # Post a task to be execute run after a given delay (in seconds). If the + # delay is less than 1/100th of a second the task will be immediately post + # to the executor. + # + # @param [Float] delay the number of seconds to wait for before executing the task. + # @param [Array] args the arguments passed to the task on execution. + # + # @yield the task to be performed. + # + # @return [Concurrent::ScheduledTask, false] IVar representing the task if the post + # is successful; false after shutdown. + # + # @raise [ArgumentError] if the intended execution time is not in the future. + # @raise [ArgumentError] if no block is given. + def post(delay, *args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + opts = { executor: @task_executor, + args: args, + timer_set: self } + task = ScheduledTask.execute(delay, opts, &task) # may raise exception + task.unscheduled? ? false : task + end + + # Begin an immediate shutdown. In-progress tasks will be allowed to + # complete but enqueued tasks will be dismissed and no new tasks + # will be accepted. Has no additional effect if the thread pool is + # not running. + def kill + shutdown + end + + private :<< + + private + + # Initialize the object. + # + # @param [Hash] opts the options to create the object with. + # @!visibility private + def ns_initialize(opts) + @queue = Collection::NonConcurrentPriorityQueue.new(order: :min) + @task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @timer_executor = SingleThreadExecutor.new + @condition = Event.new + @ruby_pid = $$ # detects if Ruby has forked + end + + # Post the task to the internal queue. + # + # @note This is intended as a callback method from ScheduledTask + # only. It is not intended to be used directly. Post a task + # by using the `SchedulesTask#execute` method. + # + # @!visibility private + def post_task(task) + synchronize { ns_post_task(task) } + end + + # @!visibility private + def ns_post_task(task) + return false unless ns_running? + ns_reset_if_forked + if (task.initial_delay) <= 0.01 + task.executor.post { task.process_task } + else + @queue.push(task) + # only post the process method when the queue is empty + @timer_executor.post(&method(:process_tasks)) if @queue.length == 1 + @condition.set + end + true + end + + # Remove the given task from the queue. + # + # @note This is intended as a callback method from `ScheduledTask` + # only. It is not intended to be used directly. Cancel a task + # by using the `ScheduledTask#cancel` method. + # + # @!visibility private + def remove_task(task) + synchronize { @queue.delete(task) } + end + + # `ExecutorService` callback called during shutdown. + # + # @!visibility private + def ns_shutdown_execution + ns_reset_if_forked + @queue.clear + @timer_executor.kill + stopped_event.set + end + + def ns_reset_if_forked + if $$ != @ruby_pid + @queue.clear + @condition.reset + @ruby_pid = $$ + end + end + + # Run a loop and execute tasks in the scheduled order and at the approximate + # scheduled time. If no tasks remain the thread will exit gracefully so that + # garbage collection can occur. If there are no ready tasks it will sleep + # for up to 60 seconds waiting for the next scheduled task. + # + # @!visibility private + def process_tasks + loop do + task = synchronize { @condition.reset; @queue.peek } + break unless task + + now = Concurrent.monotonic_time + diff = task.schedule_time - now + + if diff <= 0 + # We need to remove the task from the queue before passing + # it to the executor, to avoid race conditions where we pass + # the peek'ed task to the executor and then pop a different + # one that's been added in the meantime. + # + # Note that there's no race condition between the peek and + # this pop - this pop could retrieve a different task from + # the peek, but that task would be due to fire now anyway + # (because @queue is a priority queue, and this thread is + # the only reader, so whatever timer is at the head of the + # queue now must have the same pop time, or a closer one, as + # when we peeked). + task = synchronize { @queue.pop } + begin + task.executor.post { task.process_task } + rescue RejectedExecutionError + # ignore and continue + end + else + @condition.wait([diff, 60].min) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executors.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executors.rb new file mode 100644 index 00000000..eb1972ce --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executors.rb @@ -0,0 +1,20 @@ +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/executor/cached_thread_pool' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/fixed_thread_pool' +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/indirect_immediate_executor' +require 'concurrent/executor/java_executor_service' +require 'concurrent/executor/java_single_thread_executor' +require 'concurrent/executor/java_thread_pool_executor' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/executor/ruby_single_thread_executor' +require 'concurrent/executor/ruby_thread_pool_executor' +require 'concurrent/executor/cached_thread_pool' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/executor/serial_executor_service' +require 'concurrent/executor/serialized_execution' +require 'concurrent/executor/serialized_execution_delegator' +require 'concurrent/executor/single_thread_executor' +require 'concurrent/executor/thread_pool_executor' +require 'concurrent/executor/timer_set' diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/future.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/future.rb new file mode 100644 index 00000000..1af182ec --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/future.rb @@ -0,0 +1,141 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/ivar' +require 'concurrent/executor/safe_task_executor' + +require 'concurrent/options' + +# TODO (pitr-ch 14-Mar-2017): deprecate, Future, Promise, etc. + + +module Concurrent + + # {include:file:docs-source/future.md} + # + # @!macro copy_options + # + # @see http://ruby-doc.org/stdlib-2.1.1/libdoc/observer/rdoc/Observable.html Ruby Observable module + # @see http://clojuredocs.org/clojure_core/clojure.core/future Clojure's future function + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html java.util.concurrent.Future + class Future < IVar + + # Create a new `Future` in the `:unscheduled` state. + # + # @yield the asynchronous operation to perform + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] if no block is given + def initialize(opts = {}, &block) + raise ArgumentError.new('no block given') unless block_given? + super(NULL, opts.merge(__task_from_block__: block), &nil) + end + + # Execute an `:unscheduled` `Future`. Immediately sets the state to `:pending` and + # passes the block to a new thread/thread pool for eventual execution. + # Does nothing if the `Future` is in any state other than `:unscheduled`. + # + # @return [Future] a reference to `self` + # + # @example Instance and execute in separate steps + # future = Concurrent::Future.new{ sleep(1); 42 } + # future.state #=> :unscheduled + # future.execute + # future.state #=> :pending + # + # @example Instance and execute in one line + # future = Concurrent::Future.new{ sleep(1); 42 }.execute + # future.state #=> :pending + def execute + if compare_and_set_state(:pending, :unscheduled) + @executor.post{ safe_execute(@task, @args) } + self + end + end + + # Create a new `Future` object with the given block, execute it, and return the + # `:pending` object. + # + # @yield the asynchronous operation to perform + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] if no block is given + # + # @return [Future] the newly created `Future` in the `:pending` state + # + # @example + # future = Concurrent::Future.execute{ sleep(1); 42 } + # future.state #=> :pending + def self.execute(opts = {}, &block) + Future.new(opts, &block).execute + end + + # @!macro ivar_set_method + def set(value = NULL, &block) + check_for_block_or_value!(block_given?, value) + synchronize do + if @state != :unscheduled + raise MultipleAssignmentError + else + @task = block || Proc.new { value } + end + end + execute + end + + # Attempt to cancel the operation if it has not already processed. + # The operation can only be cancelled while still `pending`. It cannot + # be cancelled once it has begun processing or has completed. + # + # @return [Boolean] was the operation successfully cancelled. + def cancel + if compare_and_set_state(:cancelled, :pending) + complete(false, nil, CancelledOperationError.new) + true + else + false + end + end + + # Has the operation been successfully cancelled? + # + # @return [Boolean] + def cancelled? + state == :cancelled + end + + # Wait the given number of seconds for the operation to complete. + # On timeout attempt to cancel the operation. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Boolean] true if the operation completed before the timeout + # else false + def wait_or_cancel(timeout) + wait(timeout) + if complete? + true + else + cancel + false + end + end + + protected + + def ns_initialize(value, opts) + super + @state = :unscheduled + @task = opts[:__task_from_block__] + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @args = get_arguments_from(opts) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/hash.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/hash.rb new file mode 100644 index 00000000..db0208e0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/hash.rb @@ -0,0 +1,52 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!macro concurrent_hash + # + # A thread-safe subclass of Hash. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`, + # which takes the lock repeatedly when reading an item. + # + # @see http://ruby-doc.org/core/Hash.html Ruby standard library `Hash` + + # @!macro internal_implementation_note + HashImplementation = case + when Concurrent.on_cruby? + # Hash is not fully thread-safe on CRuby, see + # https://bugs.ruby-lang.org/issues/19237 + # https://github.com/ruby/ruby/commit/ffd52412ab + # https://github.com/ruby-concurrency/concurrent-ruby/issues/929 + # So we will need to add synchronization here (similar to Concurrent::Map). + ::Hash + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubyHash < ::Hash + include JRuby::Synchronized + end + JRubyHash + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubyHash < ::Hash + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyHash + TruffleRubyHash + + else + warn 'Possibly unsupported Ruby implementation' + ::Hash + end + private_constant :HashImplementation + + # @!macro concurrent_hash + class Hash < HashImplementation + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/immutable_struct.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/immutable_struct.rb new file mode 100644 index 00000000..48462e83 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/immutable_struct.rb @@ -0,0 +1,101 @@ +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A thread-safe, immutable variation of Ruby's standard `Struct`. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + module ImmutableStruct + include Synchronization::AbstractStruct + + def self.included(base) + base.safe_initialization! + end + + # @!macro struct_values + def values + ns_values + end + + alias_method :to_a, :values + + # @!macro struct_values_at + def values_at(*indexes) + ns_values_at(indexes) + end + + # @!macro struct_inspect + def inspect + ns_inspect + end + + alias_method :to_s, :inspect + + # @!macro struct_merge + def merge(other, &block) + ns_merge(other, &block) + end + + # @!macro struct_to_h + def to_h + ns_to_h + end + + # @!macro struct_get + def [](member) + ns_get(member) + end + + # @!macro struct_equality + def ==(other) + ns_equality(other) + end + + # @!macro struct_each + def each(&block) + return enum_for(:each) unless block_given? + ns_each(&block) + end + + # @!macro struct_each_pair + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + ns_each_pair(&block) + end + + # @!macro struct_select + def select(&block) + return enum_for(:select) unless block_given? + ns_select(&block) + end + + private + + # @!visibility private + def initialize_copy(original) + super(original) + ns_initialize_copy + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block) + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/ivar.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/ivar.rb new file mode 100644 index 00000000..4165038f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/ivar.rb @@ -0,0 +1,208 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/collection/copy_on_write_observer_set' +require 'concurrent/concern/obligation' +require 'concurrent/concern/observable' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An `IVar` is like a future that you can assign. As a future is a value that + # is being computed that you can wait on, an `IVar` is a value that is waiting + # to be assigned, that you can wait on. `IVars` are single assignment and + # deterministic. + # + # Then, express futures as an asynchronous computation that assigns an `IVar`. + # The `IVar` becomes the primitive on which [futures](Future) and + # [dataflow](Dataflow) are built. + # + # An `IVar` is a single-element container that is normally created empty, and + # can only be set once. The I in `IVar` stands for immutable. Reading an + # `IVar` normally blocks until it is set. It is safe to set and read an `IVar` + # from different threads. + # + # If you want to have some parallel task set the value in an `IVar`, you want + # a `Future`. If you want to create a graph of parallel tasks all executed + # when the values they depend on are ready you want `dataflow`. `IVar` is + # generally a low-level primitive. + # + # ## Examples + # + # Create, set and get an `IVar` + # + # ```ruby + # ivar = Concurrent::IVar.new + # ivar.set 14 + # ivar.value #=> 14 + # ivar.set 2 # would now be an error + # ``` + # + # ## See Also + # + # 1. For the theory: Arvind, R. Nikhil, and K. Pingali. + # [I-Structures: Data structures for parallel computing](http://dl.acm.org/citation.cfm?id=69562). + # In Proceedings of Workshop on Graph Reduction, 1986. + # 2. For recent application: + # [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html). + class IVar < Synchronization::LockableObject + include Concern::Obligation + include Concern::Observable + + # Create a new `IVar` in the `:pending` state with the (optional) initial value. + # + # @param [Object] value the initial value + # @param [Hash] opts the options to create a message with + # @option opts [String] :dup_on_deref (false) call `#dup` before returning + # the data + # @option opts [String] :freeze_on_deref (false) call `#freeze` before + # returning the data + # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing + # the internal value and returning the value returned from the proc + def initialize(value = NULL, opts = {}, &block) + if value != NULL && block_given? + raise ArgumentError.new('provide only a value or a block') + end + super(&nil) + synchronize { ns_initialize(value, opts, &block) } + end + + # Add an observer on this object that will receive notification on update. + # + # Upon completion the `IVar` will notify all observers in a thread-safe way. + # The `func` method of the observer will be called with three arguments: the + # `Time` at which the `Future` completed the asynchronous operation, the + # final `value` (or `nil` on rejection), and the final `reason` (or `nil` on + # fulfillment). + # + # @param [Object] observer the object that will be notified of changes + # @param [Symbol] func symbol naming the method to call when this + # `Observable` has changes` + def add_observer(observer = nil, func = :update, &block) + raise ArgumentError.new('cannot provide both an observer and a block') if observer && block + direct_notification = false + + if block + observer = block + func = :call + end + + synchronize do + if event.set? + direct_notification = true + else + observers.add_observer(observer, func) + end + end + + observer.send(func, Time.now, self.value, reason) if direct_notification + observer + end + + # @!macro ivar_set_method + # Set the `IVar` to a value and wake or notify all threads waiting on it. + # + # @!macro ivar_set_parameters_and_exceptions + # @param [Object] value the value to store in the `IVar` + # @yield A block operation to use for setting the value + # @raise [ArgumentError] if both a value and a block are given + # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already + # been set or otherwise completed + # + # @return [IVar] self + def set(value = NULL) + check_for_block_or_value!(block_given?, value) + raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending) + + begin + value = yield if block_given? + complete_without_notification(true, value, nil) + rescue => ex + complete_without_notification(false, nil, ex) + end + + notify_observers(self.value, reason) + self + end + + # @!macro ivar_fail_method + # Set the `IVar` to failed due to some error and wake or notify all threads waiting on it. + # + # @param [Object] reason for the failure + # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already + # been set or otherwise completed + # @return [IVar] self + def fail(reason = StandardError.new) + complete(false, nil, reason) + end + + # Attempt to set the `IVar` with the given value or block. Return a + # boolean indicating the success or failure of the set operation. + # + # @!macro ivar_set_parameters_and_exceptions + # + # @return [Boolean] true if the value was set else false + def try_set(value = NULL, &block) + set(value, &block) + true + rescue MultipleAssignmentError + false + end + + protected + + # @!visibility private + def ns_initialize(value, opts) + value = yield if block_given? + init_obligation + self.observers = Collection::CopyOnWriteObserverSet.new + set_deref_options(opts) + + @state = :pending + if value != NULL + ns_complete_without_notification(true, value, nil) + end + end + + # @!visibility private + def safe_execute(task, args = []) + if compare_and_set_state(:processing, :pending) + success, val, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) + complete(success, val, reason) + yield(success, val, reason) if block_given? + end + end + + # @!visibility private + def complete(success, value, reason) + complete_without_notification(success, value, reason) + notify_observers(self.value, reason) + self + end + + # @!visibility private + def complete_without_notification(success, value, reason) + synchronize { ns_complete_without_notification(success, value, reason) } + self + end + + # @!visibility private + def notify_observers(value, reason) + observers.notify_and_delete_observers{ [Time.now, value, reason] } + end + + # @!visibility private + def ns_complete_without_notification(success, value, reason) + raise MultipleAssignmentError if [:fulfilled, :rejected].include? @state + set_state(success, value, reason) + event.set + end + + # @!visibility private + def check_for_block_or_value!(block_given, value) # :nodoc: + if (block_given && value != NULL) || (! block_given && value == NULL) + raise ArgumentError.new('must set with either a value or a block') + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/map.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/map.rb new file mode 100644 index 00000000..b263f83d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/map.rb @@ -0,0 +1,350 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/utility/engine' + +module Concurrent + # @!visibility private + module Collection + + # @!visibility private + MapImplementation = case + when Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + # noinspection RubyResolve + JRubyMapBackend + when Concurrent.on_cruby? + require 'concurrent/collection/map/mri_map_backend' + MriMapBackend + when Concurrent.on_truffleruby? + if defined?(::TruffleRuby::ConcurrentMap) + require 'concurrent/collection/map/truffleruby_map_backend' + TruffleRubyMapBackend + else + require 'concurrent/collection/map/synchronized_map_backend' + SynchronizedMapBackend + end + else + warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' + require 'concurrent/collection/map/synchronized_map_backend' + SynchronizedMapBackend + end + end + + # `Concurrent::Map` is a hash-like object and should have much better performance + # characteristics, especially under high concurrency, than `Concurrent::Hash`. + # However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash` + # -- for instance, it does not necessarily retain ordering by insertion time as `Hash` + # does. For most uses it should do fine though, and we recommend you consider + # `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs. + class Map < Collection::MapImplementation + + # @!macro map.atomic_method + # This method is atomic. + + # @!macro map.atomic_method_with_block + # This method is atomic. + # @note Atomic methods taking a block do not allow the `self` instance + # to be used within the block. Doing so will cause a deadlock. + + # @!method []=(key, value) + # Set a value with key + # @param [Object] key + # @param [Object] value + # @return [Object] the new value + + # @!method compute_if_absent(key) + # Compute and store new value for key if the key is absent. + # @param [Object] key + # @yield new value + # @yieldreturn [Object] new value + # @return [Object] new value or current value + # @!macro map.atomic_method_with_block + + # @!method compute_if_present(key) + # Compute and store new value for key if the key is present. + # @param [Object] key + # @yield new value + # @yieldparam old_value [Object] + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method compute(key) + # Compute and store new value for key. + # @param [Object] key + # @yield compute new value from old one + # @yieldparam old_value [Object, nil] old_value, or nil when key is absent + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method merge_pair(key, value) + # If the key is absent, the value is stored, otherwise new value is + # computed with a block. + # @param [Object] key + # @param [Object] value + # @yield compute new value from old one + # @yieldparam old_value [Object] old value + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method replace_pair(key, old_value, new_value) + # Replaces old_value with new_value if key exists and current value + # matches old_value + # @param [Object] key + # @param [Object] old_value + # @param [Object] new_value + # @return [true, false] true if replaced + # @!macro map.atomic_method + + # @!method replace_if_exists(key, new_value) + # Replaces current value with new_value if key exists + # @param [Object] key + # @param [Object] new_value + # @return [Object, nil] old value or nil + # @!macro map.atomic_method + + # @!method get_and_set(key, value) + # Get the current value under key and set new value. + # @param [Object] key + # @param [Object] value + # @return [Object, nil] old value or nil when the key was absent + # @!macro map.atomic_method + + # @!method delete(key) + # Delete key and its value. + # @param [Object] key + # @return [Object, nil] old value or nil when the key was absent + # @!macro map.atomic_method + + # @!method delete_pair(key, value) + # Delete pair and its value if current value equals the provided value. + # @param [Object] key + # @param [Object] value + # @return [true, false] true if deleted + # @!macro map.atomic_method + + # NonConcurrentMapBackend handles default_proc natively + unless defined?(Collection::NonConcurrentMapBackend) and self < Collection::NonConcurrentMapBackend + + # @param [Hash, nil] options options to set the :initial_capacity or :load_factor. Ignored on some Rubies. + # @param [Proc] default_proc Optional block to compute the default value if the key is not set, like `Hash#default_proc` + def initialize(options = nil, &default_proc) + if options.kind_of?(::Hash) + validate_options_hash!(options) + else + options = nil + end + + super(options) + @default_proc = default_proc + end + + # Get a value with key + # @param [Object] key + # @return [Object] the value + def [](key) + if value = super # non-falsy value is an existing mapping, return it right away + value + # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call + # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrect +nil+ value + # would be returned) + # note: nil == value check is not technically necessary + elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) + @default_proc.call(self, key) + else + value + end + end + end + + alias_method :get, :[] + alias_method :put, :[]= + + # Get a value with key, or default_value when key is absent, + # or fail when no default_value is given. + # @param [Object] key + # @param [Object] default_value + # @yield default value for a key + # @yieldparam key [Object] + # @yieldreturn [Object] default value + # @return [Object] the value or default value + # @raise [KeyError] when key is missing and no default_value is provided + # @!macro map_method_not_atomic + # @note The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended + # to be use as a concurrency primitive with strong happens-before + # guarantees. It is not intended to be used as a high-level abstraction + # supporting complex operations. All read and write operations are + # thread safe, but no guarantees are made regarding race conditions + # between the fetch operation and yielding to the block. Additionally, + # this method does not support recursion. This is due to internal + # constraints that are very unlikely to change in the near future. + def fetch(key, default_value = NULL) + if NULL != (value = get_or_default(key, NULL)) + value + elsif block_given? + yield key + elsif NULL != default_value + default_value + else + raise_fetch_no_key + end + end + + # Fetch value with key, or store default value when key is absent, + # or fail when no default_value is given. This is a two step operation, + # therefore not atomic. The store can overwrite other concurrently + # stored value. + # @param [Object] key + # @param [Object] default_value + # @yield default value for a key + # @yieldparam key [Object] + # @yieldreturn [Object] default value + # @return [Object] the value or default value + def fetch_or_store(key, default_value = NULL) + fetch(key) do + put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) + end + end + + # Insert value into map with key if key is absent in one atomic step. + # @param [Object] key + # @param [Object] value + # @return [Object, nil] the previous value when key was present or nil when there was no key + def put_if_absent(key, value) + computed = false + result = compute_if_absent(key) do + computed = true + value + end + computed ? nil : result + end unless method_defined?(:put_if_absent) + + # Is the value stored in the map. Iterates over all values. + # @param [Object] value + # @return [true, false] + def value?(value) + each_value do |v| + return true if value.equal?(v) + end + false + end + + # All keys + # @return [::Array] keys + def keys + arr = [] + each_pair { |k, v| arr << k } + arr + end unless method_defined?(:keys) + + # All values + # @return [::Array] values + def values + arr = [] + each_pair { |k, v| arr << v } + arr + end unless method_defined?(:values) + + # Iterates over each key. + # @yield for each key in the map + # @yieldparam key [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_key + each_pair { |k, v| yield k } + end unless method_defined?(:each_key) + + # Iterates over each value. + # @yield for each value in the map + # @yieldparam value [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_value + each_pair { |k, v| yield v } + end unless method_defined?(:each_value) + + # Iterates over each key value pair. + # @yield for each key value pair in the map + # @yieldparam key [Object] + # @yieldparam value [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_pair + return enum_for :each_pair unless block_given? + super + end + + alias_method :each, :each_pair unless method_defined?(:each) + + # Find key of a value. + # @param [Object] value + # @return [Object, nil] key or nil when not found + def key(value) + each_pair { |k, v| return k if v == value } + nil + end unless method_defined?(:key) + + # Is map empty? + # @return [true, false] + def empty? + each_pair { |k, v| return false } + true + end unless method_defined?(:empty?) + + # The size of map. + # @return [Integer] size + def size + count = 0 + each_pair { |k, v| count += 1 } + count + end unless method_defined?(:size) + + # @!visibility private + def marshal_dump + raise TypeError, "can't dump hash with default proc" if @default_proc + h = {} + each_pair { |k, v| h[k] = v } + h + end + + # @!visibility private + def marshal_load(hash) + initialize + populate_from(hash) + end + + undef :freeze + + # @!visibility private + def inspect + format '%s entries=%d default_proc=%s>', to_s[0..-2], size.to_s, @default_proc.inspect + end + + private + + def raise_fetch_no_key + raise KeyError, 'key not found' + end + + def initialize_copy(other) + super + populate_from(other) + end + + def populate_from(hash) + hash.each_pair { |k, v| self[k] = v } + self + end + + def validate_options_hash!(options) + if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0) + raise ArgumentError, ":initial_capacity must be a positive Integer" + end + if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1) + raise ArgumentError, ":load_factor must be a number between 0 and 1" + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/maybe.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/maybe.rb new file mode 100644 index 00000000..317c82b8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/maybe.rb @@ -0,0 +1,229 @@ +require 'concurrent/synchronization/object' + +module Concurrent + + # A `Maybe` encapsulates an optional value. A `Maybe` either contains a value + # of (represented as `Just`), or it is empty (represented as `Nothing`). Using + # `Maybe` is a good way to deal with errors or exceptional cases without + # resorting to drastic measures such as exceptions. + # + # `Maybe` is a replacement for the use of `nil` with better type checking. + # + # For compatibility with {Concurrent::Concern::Obligation} the predicate and + # accessor methods are aliased as `fulfilled?`, `rejected?`, `value`, and + # `reason`. + # + # ## Motivation + # + # A common pattern in languages with pattern matching, such as Erlang and + # Haskell, is to return *either* a value *or* an error from a function + # Consider this Erlang code: + # + # ```erlang + # case file:consult("data.dat") of + # {ok, Terms} -> do_something_useful(Terms); + # {error, Reason} -> lager:error(Reason) + # end. + # ``` + # + # In this example the standard library function `file:consult` returns a + # [tuple](http://erlang.org/doc/reference_manual/data_types.html#id69044) + # with two elements: an [atom](http://erlang.org/doc/reference_manual/data_types.html#id64134) + # (similar to a ruby symbol) and a variable containing ancillary data. On + # success it returns the atom `ok` and the data from the file. On failure it + # returns `error` and a string with an explanation of the problem. With this + # pattern there is no ambiguity regarding success or failure. If the file is + # empty the return value cannot be misinterpreted as an error. And when an + # error occurs the return value provides useful information. + # + # In Ruby we tend to return `nil` when an error occurs or else we raise an + # exception. Both of these idioms are problematic. Returning `nil` is + # ambiguous because `nil` may also be a valid value. It also lacks + # information pertaining to the nature of the error. Raising an exception + # is both expensive and usurps the normal flow of control. All of these + # problems can be solved with the use of a `Maybe`. + # + # A `Maybe` is unambiguous with regard to whether or not it contains a value. + # When `Just` it contains a value, when `Nothing` it does not. When `Just` + # the value it contains may be `nil`, which is perfectly valid. When + # `Nothing` the reason for the lack of a value is contained as well. The + # previous Erlang example can be duplicated in Ruby in a principled way by + # having functions return `Maybe` objects: + # + # ```ruby + # result = MyFileUtils.consult("data.dat") # returns a Maybe + # if result.just? + # do_something_useful(result.value) # or result.just + # else + # logger.error(result.reason) # or result.nothing + # end + # ``` + # + # @example Returning a Maybe from a Function + # module MyFileUtils + # def self.consult(path) + # file = File.open(path, 'r') + # Concurrent::Maybe.just(file.read) + # rescue => ex + # return Concurrent::Maybe.nothing(ex) + # ensure + # file.close if file + # end + # end + # + # maybe = MyFileUtils.consult('bogus.file') + # maybe.just? #=> false + # maybe.nothing? #=> true + # maybe.reason #=> # + # + # maybe = MyFileUtils.consult('README.md') + # maybe.just? #=> true + # maybe.nothing? #=> false + # maybe.value #=> "# Concurrent Ruby\n[![Gem Version..." + # + # @example Using Maybe with a Block + # result = Concurrent::Maybe.from do + # Client.find(10) # Client is an ActiveRecord model + # end + # + # # -- if the record was found + # result.just? #=> true + # result.value #=> # + # + # # -- if the record was not found + # result.just? #=> false + # result.reason #=> ActiveRecord::RecordNotFound + # + # @example Using Maybe with the Null Object Pattern + # # In a Rails controller... + # result = ClientService.new(10).find # returns a Maybe + # render json: result.or(NullClient.new) + # + # @see https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html Haskell Data.Maybe + # @see https://github.com/purescript/purescript-maybe/blob/master/docs/Data.Maybe.md PureScript Data.Maybe + class Maybe < Synchronization::Object + include Comparable + safe_initialization! + + # Indicates that the given attribute has not been set. + # When `Just` the {#nothing} getter will return `NONE`. + # When `Nothing` the {#just} getter will return `NONE`. + NONE = ::Object.new.freeze + + # The value of a `Maybe` when `Just`. Will be `NONE` when `Nothing`. + attr_reader :just + + # The reason for the `Maybe` when `Nothing`. Will be `NONE` when `Just`. + attr_reader :nothing + + private_class_method :new + + # Create a new `Maybe` using the given block. + # + # Runs the given block passing all function arguments to the block as block + # arguments. If the block runs to completion without raising an exception + # a new `Just` is created with the value set to the return value of the + # block. If the block raises an exception a new `Nothing` is created with + # the reason being set to the raised exception. + # + # @param [Array] args Zero or more arguments to pass to the block. + # @yield The block from which to create a new `Maybe`. + # @yieldparam [Array] args Zero or more block arguments passed as + # arguments to the function. + # + # @return [Maybe] The newly created object. + # + # @raise [ArgumentError] when no block given. + def self.from(*args) + raise ArgumentError.new('no block given') unless block_given? + begin + value = yield(*args) + return new(value, NONE) + rescue => ex + return new(NONE, ex) + end + end + + # Create a new `Just` with the given value. + # + # @param [Object] value The value to set for the new `Maybe` object. + # + # @return [Maybe] The newly created object. + def self.just(value) + return new(value, NONE) + end + + # Create a new `Nothing` with the given (optional) reason. + # + # @param [Exception] error The reason to set for the new `Maybe` object. + # When given a string a new `StandardError` will be created with the + # argument as the message. When no argument is given a new + # `StandardError` with an empty message will be created. + # + # @return [Maybe] The newly created object. + def self.nothing(error = '') + if error.is_a?(Exception) + nothing = error + else + nothing = StandardError.new(error.to_s) + end + return new(NONE, nothing) + end + + # Is this `Maybe` a `Just` (successfully fulfilled with a value)? + # + # @return [Boolean] True if `Just` or false if `Nothing`. + def just? + ! nothing? + end + alias :fulfilled? :just? + + # Is this `Maybe` a `nothing` (rejected with an exception upon fulfillment)? + # + # @return [Boolean] True if `Nothing` or false if `Just`. + def nothing? + @nothing != NONE + end + alias :rejected? :nothing? + + alias :value :just + + alias :reason :nothing + + # Comparison operator. + # + # @return [Integer] 0 if self and other are both `Nothing`; + # -1 if self is `Nothing` and other is `Just`; + # 1 if self is `Just` and other is nothing; + # `self.just <=> other.just` if both self and other are `Just`. + def <=>(other) + if nothing? + other.nothing? ? 0 : -1 + else + other.nothing? ? 1 : just <=> other.just + end + end + + # Return either the value of self or the given default value. + # + # @return [Object] The value of self when `Just`; else the given default. + def or(other) + just? ? just : other + end + + private + + # Create a new `Maybe` with the given attributes. + # + # @param [Object] just The value when `Just` else `NONE`. + # @param [Exception, Object] nothing The exception when `Nothing` else `NONE`. + # + # @return [Maybe] The new `Maybe`. + # + # @!visibility private + def initialize(just, nothing) + @just = just + @nothing = nothing + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mutable_struct.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mutable_struct.rb new file mode 100644 index 00000000..5d0e9b9a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mutable_struct.rb @@ -0,0 +1,239 @@ +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An thread-safe variation of Ruby's standard `Struct`. Values can be set at + # construction or safely changed at any time during the object's lifecycle. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + module MutableStruct + include Synchronization::AbstractStruct + + # @!macro struct_new + # + # Factory for creating new struct classes. + # + # ``` + # new([class_name] [, member_name]+>) -> StructClass click to toggle source + # new([class_name] [, member_name]+>) {|StructClass| block } -> StructClass + # new(value, ...) -> obj + # StructClass[value, ...] -> obj + # ``` + # + # The first two forms are used to create a new struct subclass `class_name` + # that can contain a value for each member_name . This subclass can be + # used to create instances of the structure like any other Class . + # + # If the `class_name` is omitted an anonymous struct class will be created. + # Otherwise, the name of this struct will appear as a constant in the struct class, + # so it must be unique for all structs under this base class and must start with a + # capital letter. Assigning a struct class to a constant also gives the class + # the name of the constant. + # + # If a block is given it will be evaluated in the context of `StructClass`, passing + # the created class as a parameter. This is the recommended way to customize a struct. + # Subclassing an anonymous struct creates an extra anonymous class that will never be used. + # + # The last two forms create a new instance of a struct subclass. The number of value + # parameters must be less than or equal to the number of attributes defined for the + # struct. Unset parameters default to nil. Passing more parameters than number of attributes + # will raise an `ArgumentError`. + # + # @see http://ruby-doc.org/core/Struct.html#method-c-new Ruby standard library `Struct#new` + + # @!macro struct_values + # + # Returns the values for this struct as an Array. + # + # @return [Array] the values for this struct + # + def values + synchronize { ns_values } + end + alias_method :to_a, :values + + # @!macro struct_values_at + # + # Returns the struct member values for each selector as an Array. + # + # A selector may be either an Integer offset or a Range of offsets (as in `Array#values_at`). + # + # @param [Fixnum, Range] indexes the index(es) from which to obatin the values (in order) + def values_at(*indexes) + synchronize { ns_values_at(indexes) } + end + + # @!macro struct_inspect + # + # Describe the contents of this struct in a string. + # + # @return [String] the contents of this struct in a string + def inspect + synchronize { ns_inspect } + end + alias_method :to_s, :inspect + + # @!macro struct_merge + # + # Returns a new struct containing the contents of `other` and the contents + # of `self`. If no block is specified, the value for entries with duplicate + # keys will be that of `other`. Otherwise the value for each duplicate key + # is determined by calling the block with the key, its value in `self` and + # its value in `other`. + # + # @param [Hash] other the hash from which to set the new values + # @yield an options block for resolving duplicate keys + # @yieldparam [String, Symbol] member the name of the member which is duplicated + # @yieldparam [Object] selfvalue the value of the member in `self` + # @yieldparam [Object] othervalue the value of the member in `other` + # + # @return [Synchronization::AbstractStruct] a new struct with the new values + # + # @raise [ArgumentError] of given a member that is not defined in the struct + def merge(other, &block) + synchronize { ns_merge(other, &block) } + end + + # @!macro struct_to_h + # + # Returns a hash containing the names and values for the struct’s members. + # + # @return [Hash] the names and values for the struct’s members + def to_h + synchronize { ns_to_h } + end + + # @!macro struct_get + # + # Attribute Reference + # + # @param [Symbol, String, Integer] member the string or symbol name of the member + # for which to obtain the value or the member's index + # + # @return [Object] the value of the given struct member or the member at the given index. + # + # @raise [NameError] if the member does not exist + # @raise [IndexError] if the index is out of range. + def [](member) + synchronize { ns_get(member) } + end + + # @!macro struct_equality + # + # Equality + # + # @return [Boolean] true if other has the same struct subclass and has + # equal member values (according to `Object#==`) + def ==(other) + synchronize { ns_equality(other) } + end + + # @!macro struct_each + # + # Yields the value of each struct member in order. If no block is given + # an enumerator is returned. + # + # @yield the operation to be performed on each struct member + # @yieldparam [Object] value each struct value (in order) + def each(&block) + return enum_for(:each) unless block_given? + synchronize { ns_each(&block) } + end + + # @!macro struct_each_pair + # + # Yields the name and value of each struct member in order. If no block is + # given an enumerator is returned. + # + # @yield the operation to be performed on each struct member/value pair + # @yieldparam [Object] member each struct member (in order) + # @yieldparam [Object] value each struct value (in order) + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + synchronize { ns_each_pair(&block) } + end + + # @!macro struct_select + # + # Yields each member value from the struct to the block and returns an Array + # containing the member values from the struct for which the given block + # returns a true value (equivalent to `Enumerable#select`). + # + # @yield the operation to be performed on each struct member + # @yieldparam [Object] value each struct value (in order) + # + # @return [Array] an array containing each value for which the block returns true + def select(&block) + return enum_for(:select) unless block_given? + synchronize { ns_select(&block) } + end + + # @!macro struct_set + # + # Attribute Assignment + # + # Sets the value of the given struct member or the member at the given index. + # + # @param [Symbol, String, Integer] member the string or symbol name of the member + # for which to obtain the value or the member's index + # + # @return [Object] the value of the given struct member or the member at the given index. + # + # @raise [NameError] if the name does not exist + # @raise [IndexError] if the index is out of range. + def []=(member, value) + if member.is_a? Integer + length = synchronize { @values.length } + if member >= length + raise IndexError.new("offset #{member} too large for struct(size:#{length})") + end + synchronize { @values[member] = value } + else + send("#{member}=", value) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + private + + # @!visibility private + def initialize_copy(original) + synchronize do + super(original) + ns_initialize_copy + end + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::LockableObject, name, members, &block) + members.each_with_index do |member, index| + clazz.send :remove_method, member + clazz.send(:define_method, member) do + synchronize { @values[index] } + end + clazz.send(:define_method, "#{member}=") do |value| + synchronize { @values[index] = value } + end + end + clazz + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mvar.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mvar.rb new file mode 100644 index 00000000..dfc41950 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/mvar.rb @@ -0,0 +1,242 @@ +require 'concurrent/concern/dereferenceable' +require 'concurrent/synchronization/object' + +module Concurrent + + # An `MVar` is a synchronized single element container. They are empty or + # contain one item. Taking a value from an empty `MVar` blocks, as does + # putting a value into a full one. You can either think of them as blocking + # queue of length one, or a special kind of mutable variable. + # + # On top of the fundamental `#put` and `#take` operations, we also provide a + # `#mutate` that is atomic with respect to operations on the same instance. + # These operations all support timeouts. + # + # We also support non-blocking operations `#try_put!` and `#try_take!`, a + # `#set!` that ignores existing values, a `#value` that returns the value + # without removing it or returns `MVar::EMPTY`, and a `#modify!` that yields + # `MVar::EMPTY` if the `MVar` is empty and can be used to set `MVar::EMPTY`. + # You shouldn't use these operations in the first instance. + # + # `MVar` is a [Dereferenceable](Dereferenceable). + # + # `MVar` is related to M-structures in Id, `MVar` in Haskell and `SyncVar` in Scala. + # + # Note that unlike the original Haskell paper, our `#take` is blocking. This is how + # Haskell and Scala do it today. + # + # @!macro copy_options + # + # ## See Also + # + # 1. P. Barth, R. Nikhil, and Arvind. [M-Structures: Extending a parallel, non- strict, functional language with state](http://dl.acm.org/citation.cfm?id=652538). In Proceedings of the 5th + # ACM Conference on Functional Programming Languages and Computer Architecture (FPCA), 1991. + # + # 2. S. Peyton Jones, A. Gordon, and S. Finne. [Concurrent Haskell](http://dl.acm.org/citation.cfm?id=237794). + # In Proceedings of the 23rd Symposium on Principles of Programming Languages + # (PoPL), 1996. + class MVar < Synchronization::Object + include Concern::Dereferenceable + safe_initialization! + + # Unique value that represents that an `MVar` was empty + EMPTY = ::Object.new + + # Unique value that represents that an `MVar` timed out before it was able + # to produce a value. + TIMEOUT = ::Object.new + + # Create a new `MVar`, either empty or with an initial value. + # + # @param [Hash] opts the options controlling how the future will be processed + # + # @!macro deref_options + def initialize(value = EMPTY, opts = {}) + @value = value + @mutex = Mutex.new + @empty_condition = ConditionVariable.new + @full_condition = ConditionVariable.new + set_deref_options(opts) + end + + # Remove the value from an `MVar`, leaving it empty, and blocking if there + # isn't a value. A timeout can be set to limit the time spent blocked, in + # which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value that was taken, or `TIMEOUT` + def take(timeout = nil) + @mutex.synchronize do + wait_for_full(timeout) + + # If we timed out we'll still be empty + if unlocked_full? + value = @value + @value = EMPTY + @empty_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # acquires lock on the from an `MVAR`, yields the value to provided block, + # and release lock. A timeout can be set to limit the time spent blocked, + # in which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value returned by the block, or `TIMEOUT` + def borrow(timeout = nil) + @mutex.synchronize do + wait_for_full(timeout) + + # if we timeoud out we'll still be empty + if unlocked_full? + yield @value + else + TIMEOUT + end + end + end + + # Put a value into an `MVar`, blocking if there is already a value until + # it is empty. A timeout can be set to limit the time spent blocked, in + # which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value that was put, or `TIMEOUT` + def put(value, timeout = nil) + @mutex.synchronize do + wait_for_empty(timeout) + + # If we timed out we won't be empty + if unlocked_empty? + @value = value + @full_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # Atomically `take`, yield the value to a block for transformation, and then + # `put` the transformed value. Returns the transformed value. A timeout can + # be set to limit the time spent blocked, in which case it returns `TIMEOUT` + # if the time is exceeded. + # @return [Object] the transformed value, or `TIMEOUT` + def modify(timeout = nil) + raise ArgumentError.new('no block given') unless block_given? + + @mutex.synchronize do + wait_for_full(timeout) + + # If we timed out we'll still be empty + if unlocked_full? + value = @value + @value = yield value + @full_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # Non-blocking version of `take`, that returns `EMPTY` instead of blocking. + def try_take! + @mutex.synchronize do + if unlocked_full? + value = @value + @value = EMPTY + @empty_condition.signal + apply_deref_options(value) + else + EMPTY + end + end + end + + # Non-blocking version of `put`, that returns whether or not it was successful. + def try_put!(value) + @mutex.synchronize do + if unlocked_empty? + @value = value + @full_condition.signal + true + else + false + end + end + end + + # Non-blocking version of `put` that will overwrite an existing value. + def set!(value) + @mutex.synchronize do + old_value = @value + @value = value + @full_condition.signal + apply_deref_options(old_value) + end + end + + # Non-blocking version of `modify` that will yield with `EMPTY` if there is no value yet. + def modify! + raise ArgumentError.new('no block given') unless block_given? + + @mutex.synchronize do + value = @value + @value = yield value + if unlocked_empty? + @empty_condition.signal + else + @full_condition.signal + end + apply_deref_options(value) + end + end + + # Returns if the `MVar` is currently empty. + def empty? + @mutex.synchronize { @value == EMPTY } + end + + # Returns if the `MVar` currently contains a value. + def full? + !empty? + end + + protected + + def synchronize(&block) + @mutex.synchronize(&block) + end + + private + + def unlocked_empty? + @value == EMPTY + end + + def unlocked_full? + ! unlocked_empty? + end + + def wait_for_full(timeout) + wait_while(@full_condition, timeout) { unlocked_empty? } + end + + def wait_for_empty(timeout) + wait_while(@empty_condition, timeout) { unlocked_full? } + end + + def wait_while(condition, timeout) + if timeout.nil? + while yield + condition.wait(@mutex) + end + else + stop = Concurrent.monotonic_time + timeout + while yield && timeout > 0.0 + condition.wait(@mutex, timeout) + timeout = stop - Concurrent.monotonic_time + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/options.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/options.rb new file mode 100644 index 00000000..bdd22a9d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/options.rb @@ -0,0 +1,42 @@ +require 'concurrent/configuration' + +module Concurrent + + # @!visibility private + module Options + + # Get the requested `Executor` based on the values set in the options hash. + # + # @param [Hash] opts the options defining the requested executor + # @option opts [Executor] :executor when set use the given `Executor` instance. + # Three special values are also supported: `:fast` returns the global fast executor, + # `:io` returns the global io executor, and `:immediate` returns a new + # `ImmediateExecutor` object. + # + # @return [Executor, nil] the requested thread pool, or nil when no option specified + # + # @!visibility private + def self.executor_from_options(opts = {}) # :nodoc: + if identifier = opts.fetch(:executor, nil) + executor(identifier) + else + nil + end + end + + def self.executor(executor_identifier) + case executor_identifier + when :fast + Concurrent.global_fast_executor + when :io + Concurrent.global_io_executor + when :immediate + Concurrent.global_immediate_executor + when Concurrent::ExecutorService + executor_identifier + else + raise ArgumentError, "executor not recognized by '#{executor_identifier}'" + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promise.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promise.rb new file mode 100644 index 00000000..c717f9b0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promise.rb @@ -0,0 +1,580 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/ivar' +require 'concurrent/executor/safe_task_executor' + +require 'concurrent/options' + +module Concurrent + + PromiseExecutionError = Class.new(StandardError) + + # Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) + # and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications. + # + # > A promise represents the eventual value returned from the single + # > completion of an operation. + # + # Promises are similar to futures and share many of the same behaviours. + # Promises are far more robust, however. Promises can be chained in a tree + # structure where each promise may have zero or more children. Promises are + # chained using the `then` method. The result of a call to `then` is always + # another promise. Promises are resolved asynchronously (with respect to the + # main thread) but in a strict order: parents are guaranteed to be resolved + # before their children, children before their younger siblings. The `then` + # method takes two parameters: an optional block to be executed upon parent + # resolution and an optional callable to be executed upon parent failure. The + # result of each promise is passed to each of its children upon resolution. + # When a promise is rejected all its children will be summarily rejected and + # will receive the reason. + # + # Promises have several possible states: *:unscheduled*, *:pending*, + # *:processing*, *:rejected*, or *:fulfilled*. These are also aggregated as + # `#incomplete?` and `#complete?`. When a Promise is created it is set to + # *:unscheduled*. Once the `#execute` method is called the state becomes + # *:pending*. Once a job is pulled from the thread pool's queue and is given + # to a thread for processing (often immediately upon `#post`) the state + # becomes *:processing*. The future will remain in this state until processing + # is complete. A future that is in the *:unscheduled*, *:pending*, or + # *:processing* is considered `#incomplete?`. A `#complete?` Promise is either + # *:rejected*, indicating that an exception was thrown during processing, or + # *:fulfilled*, indicating success. If a Promise is *:fulfilled* its `#value` + # will be updated to reflect the result of the operation. If *:rejected* the + # `reason` will be updated with a reference to the thrown exception. The + # predicate methods `#unscheduled?`, `#pending?`, `#rejected?`, and + # `#fulfilled?` can be called at any time to obtain the state of the Promise, + # as can the `#state` method, which returns a symbol. + # + # Retrieving the value of a promise is done through the `value` (alias: + # `deref`) method. Obtaining the value of a promise is a potentially blocking + # operation. When a promise is *rejected* a call to `value` will return `nil` + # immediately. When a promise is *fulfilled* a call to `value` will + # immediately return the current value. When a promise is *pending* a call to + # `value` will block until the promise is either *rejected* or *fulfilled*. A + # *timeout* value can be passed to `value` to limit how long the call will + # block. If `nil` the call will block indefinitely. If `0` the call will not + # block. Any other integer or float value will indicate the maximum number of + # seconds to block. + # + # Promises run on the global thread pool. + # + # @!macro copy_options + # + # ### Examples + # + # Start by requiring promises + # + # ```ruby + # require 'concurrent/promise' + # ``` + # + # Then create one + # + # ```ruby + # p = Concurrent::Promise.execute do + # # do something + # 42 + # end + # ``` + # + # Promises can be chained using the `then` method. The `then` method accepts a + # block and an executor, to be executed on fulfillment, and a callable argument to be executed + # on rejection. The result of the each promise is passed as the block argument + # to chained promises. + # + # ```ruby + # p = Concurrent::Promise.new{10}.then{|x| x * 2}.then{|result| result - 10 }.execute + # ``` + # + # And so on, and so on, and so on... + # + # ```ruby + # p = Concurrent::Promise.fulfill(20). + # then{|result| result - 10 }. + # then{|result| result * 3 }. + # then(executor: different_executor){|result| result % 5 }.execute + # ``` + # + # The initial state of a newly created Promise depends on the state of its parent: + # - if parent is *unscheduled* the child will be *unscheduled* + # - if parent is *pending* the child will be *pending* + # - if parent is *fulfilled* the child will be *pending* + # - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*) + # + # Promises are executed asynchronously from the main thread. By the time a + # child Promise finishes initialization it may be in a different state than its + # parent (by the time a child is created its parent may have completed + # execution and changed state). Despite being asynchronous, however, the order + # of execution of Promise objects in a chain (or tree) is strictly defined. + # + # There are multiple ways to create and execute a new `Promise`. Both ways + # provide identical behavior: + # + # ```ruby + # # create, operate, then execute + # p1 = Concurrent::Promise.new{ "Hello World!" } + # p1.state #=> :unscheduled + # p1.execute + # + # # create and immediately execute + # p2 = Concurrent::Promise.new{ "Hello World!" }.execute + # + # # execute during creation + # p3 = Concurrent::Promise.execute{ "Hello World!" } + # ``` + # + # Once the `execute` method is called a `Promise` becomes `pending`: + # + # ```ruby + # p = Concurrent::Promise.execute{ "Hello, world!" } + # p.state #=> :pending + # p.pending? #=> true + # ``` + # + # Wait a little bit, and the promise will resolve and provide a value: + # + # ```ruby + # p = Concurrent::Promise.execute{ "Hello, world!" } + # sleep(0.1) + # + # p.state #=> :fulfilled + # p.fulfilled? #=> true + # p.value #=> "Hello, world!" + # ``` + # + # If an exception occurs, the promise will be rejected and will provide + # a reason for the rejection: + # + # ```ruby + # p = Concurrent::Promise.execute{ raise StandardError.new("Here comes the Boom!") } + # sleep(0.1) + # + # p.state #=> :rejected + # p.rejected? #=> true + # p.reason #=> "#" + # ``` + # + # #### Rejection + # + # When a promise is rejected all its children will be rejected and will + # receive the rejection `reason` as the rejection callable parameter: + # + # ```ruby + # p = Concurrent::Promise.execute { Thread.pass; raise StandardError } + # + # c1 = p.then(-> reason { 42 }) + # c2 = p.then(-> reason { raise 'Boom!' }) + # + # c1.wait.state #=> :fulfilled + # c1.value #=> 45 + # c2.wait.state #=> :rejected + # c2.reason #=> # + # ``` + # + # Once a promise is rejected it will continue to accept children that will + # receive immediately rejection (they will be executed asynchronously). + # + # #### Aliases + # + # The `then` method is the most generic alias: it accepts a block to be + # executed upon parent fulfillment and a callable to be executed upon parent + # rejection. At least one of them should be passed. The default block is `{ + # |result| result }` that fulfills the child with the parent value. The + # default callable is `{ |reason| raise reason }` that rejects the child with + # the parent reason. + # + # - `on_success { |result| ... }` is the same as `then {|result| ... }` + # - `rescue { |reason| ... }` is the same as `then(Proc.new { |reason| ... } )` + # - `rescue` is aliased by `catch` and `on_error` + class Promise < IVar + + # Initialize a new Promise with the provided options. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @option opts [Promise] :parent the parent `Promise` when building a chain/tree + # @option opts [Proc] :on_fulfill fulfillment handler + # @option opts [Proc] :on_reject rejection handler + # @option opts [object, Array] :args zero or more arguments to be passed + # the task block on execution + # + # @yield The block operation to be performed asynchronously. + # + # @raise [ArgumentError] if no block is given + # + # @see http://wiki.commonjs.org/wiki/Promises/A + # @see http://promises-aplus.github.io/promises-spec/ + def initialize(opts = {}, &block) + opts.delete_if { |k, v| v.nil? } + super(NULL, opts.merge(__promise_body_from_block__: block), &nil) + end + + # Create a new `Promise` and fulfill it immediately. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @raise [ArgumentError] if no block is given + # + # @return [Promise] the newly created `Promise` + def self.fulfill(value, opts = {}) + Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, true, value, nil) } + end + + # Create a new `Promise` and reject it immediately. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @raise [ArgumentError] if no block is given + # + # @return [Promise] the newly created `Promise` + def self.reject(reason, opts = {}) + Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, false, nil, reason) } + end + + # Execute an `:unscheduled` `Promise`. Immediately sets the state to `:pending` and + # passes the block to a new thread/thread pool for eventual execution. + # Does nothing if the `Promise` is in any state other than `:unscheduled`. + # + # @return [Promise] a reference to `self` + def execute + if root? + if compare_and_set_state(:pending, :unscheduled) + set_pending + realize(@promise_body) + end + else + compare_and_set_state(:pending, :unscheduled) + @parent.execute + end + self + end + + # @!macro ivar_set_method + # + # @raise [Concurrent::PromiseExecutionError] if not the root promise + def set(value = NULL, &block) + raise PromiseExecutionError.new('supported only on root promise') unless root? + check_for_block_or_value!(block_given?, value) + synchronize do + if @state != :unscheduled + raise MultipleAssignmentError + else + @promise_body = block || Proc.new { |result| value } + end + end + execute + end + + # @!macro ivar_fail_method + # + # @raise [Concurrent::PromiseExecutionError] if not the root promise + def fail(reason = StandardError.new) + set { raise reason } + end + + # Create a new `Promise` object with the given block, execute it, and return the + # `:pending` object. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @return [Promise] the newly created `Promise` in the `:pending` state + # + # @raise [ArgumentError] if no block is given + # + # @example + # promise = Concurrent::Promise.execute{ sleep(1); 42 } + # promise.state #=> :pending + def self.execute(opts = {}, &block) + new(opts, &block).execute + end + + # Chain a new promise off the current promise. + # + # @return [Promise] the new promise + # @yield The block operation to be performed asynchronously. + # @overload then(rescuer, executor, &block) + # @param [Proc] rescuer An optional rescue block to be executed if the + # promise is rejected. + # @param [ThreadPool] executor An optional thread pool executor to be used + # in the new Promise + # @overload then(rescuer, executor: executor, &block) + # @param [Proc] rescuer An optional rescue block to be executed if the + # promise is rejected. + # @param [ThreadPool] executor An optional thread pool executor to be used + # in the new Promise + def then(*args, &block) + if args.last.is_a?(::Hash) + executor = args.pop[:executor] + rescuer = args.first + else + rescuer, executor = args + end + + executor ||= @executor + + raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given? + block = Proc.new { |result| result } unless block_given? + child = Promise.new( + parent: self, + executor: executor, + on_fulfill: block, + on_reject: rescuer + ) + + synchronize do + child.state = :pending if @state == :pending + child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled + child.on_reject(@reason) if @state == :rejected + @children << child + end + + child + end + + # Chain onto this promise an action to be undertaken on success + # (fulfillment). + # + # @yield The block to execute + # + # @return [Promise] self + def on_success(&block) + raise ArgumentError.new('no block given') unless block_given? + self.then(&block) + end + + # Chain onto this promise an action to be undertaken on failure + # (rejection). + # + # @yield The block to execute + # + # @return [Promise] self + def rescue(&block) + self.then(block) + end + + alias_method :catch, :rescue + alias_method :on_error, :rescue + + # Yield the successful result to the block that returns a promise. If that + # promise is also successful the result is the result of the yielded promise. + # If either part fails the whole also fails. + # + # @example + # Promise.execute { 1 }.flat_map { |v| Promise.execute { v + 2 } }.value! #=> 3 + # + # @return [Promise] + def flat_map(&block) + child = Promise.new( + parent: self, + executor: ImmediateExecutor.new, + ) + + on_error { |e| child.on_reject(e) } + on_success do |result1| + begin + inner = block.call(result1) + inner.execute + inner.on_success { |result2| child.on_fulfill(result2) } + inner.on_error { |e| child.on_reject(e) } + rescue => e + child.on_reject(e) + end + end + + child + end + + # Builds a promise that produces the result of promises in an Array + # and fails if any of them fails. + # + # @overload zip(*promises) + # @param [Array] promises + # + # @overload zip(*promises, opts) + # @param [Array] promises + # @param [Hash] opts the configuration options + # @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance. + # @option opts [Boolean] :execute (true) execute promise before returning + # + # @return [Promise] + def self.zip(*promises) + opts = promises.last.is_a?(::Hash) ? promises.pop.dup : {} + opts[:executor] ||= ImmediateExecutor.new + zero = if !opts.key?(:execute) || opts.delete(:execute) + fulfill([], opts) + else + Promise.new(opts) { [] } + end + + promises.reduce(zero) do |p1, p2| + p1.flat_map do |results| + p2.then do |next_result| + results << next_result + end + end + end + end + + # Builds a promise that produces the result of self and others in an Array + # and fails if any of them fails. + # + # @overload zip(*promises) + # @param [Array] others + # + # @overload zip(*promises, opts) + # @param [Array] others + # @param [Hash] opts the configuration options + # @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance. + # @option opts [Boolean] :execute (true) execute promise before returning + # + # @return [Promise] + def zip(*others) + self.class.zip(self, *others) + end + + # Aggregates a collection of promises and executes the `then` condition + # if all aggregated promises succeed. Executes the `rescue` handler with + # a `Concurrent::PromiseExecutionError` if any of the aggregated promises + # fail. Upon execution will execute any of the aggregate promises that + # were not already executed. + # + # @!macro promise_self_aggregate + # + # The returned promise will not yet have been executed. Additional `#then` + # and `#rescue` handlers may still be provided. Once the returned promise + # is execute the aggregate promises will be also be executed (if they have + # not been executed already). The results of the aggregate promises will + # be checked upon completion. The necessary `#then` and `#rescue` blocks + # on the aggregating promise will then be executed as appropriate. If the + # `#rescue` handlers are executed the raises exception will be + # `Concurrent::PromiseExecutionError`. + # + # @param [Array] promises Zero or more promises to aggregate + # @return [Promise] an unscheduled (not executed) promise that aggregates + # the promises given as arguments + def self.all?(*promises) + aggregate(:all?, *promises) + end + + # Aggregates a collection of promises and executes the `then` condition + # if any aggregated promises succeed. Executes the `rescue` handler with + # a `Concurrent::PromiseExecutionError` if any of the aggregated promises + # fail. Upon execution will execute any of the aggregate promises that + # were not already executed. + # + # @!macro promise_self_aggregate + def self.any?(*promises) + aggregate(:any?, *promises) + end + + protected + + def ns_initialize(value, opts) + super + + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @args = get_arguments_from(opts) + + @parent = opts.fetch(:parent) { nil } + @on_fulfill = opts.fetch(:on_fulfill) { Proc.new { |result| result } } + @on_reject = opts.fetch(:on_reject) { Proc.new { |reason| raise reason } } + + @promise_body = opts[:__promise_body_from_block__] || Proc.new { |result| result } + @state = :unscheduled + @children = [] + end + + # Aggregate a collection of zero or more promises under a composite promise, + # execute the aggregated promises and collect them into a standard Ruby array, + # call the given Ruby `Ennnumerable` predicate (such as `any?`, `all?`, `none?`, + # or `one?`) on the collection checking for the success or failure of each, + # then executing the composite's `#then` handlers if the predicate returns + # `true` or executing the composite's `#rescue` handlers if the predicate + # returns false. + # + # @!macro promise_self_aggregate + def self.aggregate(method, *promises) + composite = Promise.new do + completed = promises.collect do |promise| + promise.execute if promise.unscheduled? + promise.wait + promise + end + unless completed.empty? || completed.send(method){|promise| promise.fulfilled? } + raise PromiseExecutionError + end + end + composite + end + + # @!visibility private + def set_pending + synchronize do + @state = :pending + @children.each { |c| c.set_pending } + end + end + + # @!visibility private + def root? # :nodoc: + @parent.nil? + end + + # @!visibility private + def on_fulfill(result) + realize Proc.new { @on_fulfill.call(result) } + nil + end + + # @!visibility private + def on_reject(reason) + realize Proc.new { @on_reject.call(reason) } + nil + end + + # @!visibility private + def notify_child(child) + if_state(:fulfilled) { child.on_fulfill(apply_deref_options(@value)) } + if_state(:rejected) { child.on_reject(@reason) } + end + + # @!visibility private + def complete(success, value, reason) + children_to_notify = synchronize do + set_state!(success, value, reason) + @children.dup + end + + children_to_notify.each { |child| notify_child(child) } + observers.notify_and_delete_observers{ [Time.now, self.value, reason] } + end + + # @!visibility private + def realize(task) + @executor.post do + success, value, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) + complete(success, value, reason) + end + end + + # @!visibility private + def set_state!(success, value, reason) + set_state(success, value, reason) + event.set + end + + # @!visibility private + def synchronized_set_state!(success, value, reason) + synchronize { set_state!(success, value, reason) } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb new file mode 100644 index 00000000..c5df8fe9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb @@ -0,0 +1,2178 @@ +require 'concurrent/synchronization/object' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/collection/lock_free_stack' +require 'concurrent/configuration' +require 'concurrent/errors' +require 'concurrent/re_include' +require 'concurrent/utility/monotonic_time' + +module Concurrent + + # {include:file:docs-source/promises-main.md} + module Promises + + # @!macro promises.param.default_executor + # @param [Executor, :io, :fast] default_executor Instance of an executor or a name of the + # global executor. Default executor propagates to chained futures unless overridden with + # executor parameter or changed with {AbstractEventFuture#with_default_executor}. + # + # @!macro promises.param.executor + # @param [Executor, :io, :fast] executor Instance of an executor or a name of the + # global executor. The task is executed on it, default executor remains unchanged. + # + # @!macro promises.param.args + # @param [Object] args arguments which are passed to the task when it's executed. + # (It might be prepended with other arguments, see the @yield section). + # + # @!macro promises.shortcut.on + # Shortcut of {#$0_on} with default `:io` executor supplied. + # @see #$0_on + # + # @!macro promises.shortcut.using + # Shortcut of {#$0_using} with default `:io` executor supplied. + # @see #$0_using + # + # @!macro promise.param.task-future + # @yieldreturn will become result of the returned Future. + # Its returned value becomes {Future#value} fulfilling it, + # raised exception becomes {Future#reason} rejecting it. + # + # @!macro promise.param.callback + # @yieldreturn is forgotten. + + # Container of all {Future}, {Event} factory methods. They are never constructed directly with + # new. + module FactoryMethods + extend ReInclude + extend self + + module Configuration + # @return [Executor, :io, :fast] the executor which is used when none is supplied + # to a factory method. The method can be overridden in the receivers of + # `include FactoryMethod` + def default_executor + :io + end + end + + include Configuration + + # @!macro promises.shortcut.on + # @return [ResolvableEvent] + def resolvable_event + resolvable_event_on default_executor + end + + # Creates a resolvable event, user is responsible for resolving the event once + # by calling {Promises::ResolvableEvent#resolve}. + # + # @!macro promises.param.default_executor + # @return [ResolvableEvent] + def resolvable_event_on(default_executor = self.default_executor) + ResolvableEventPromise.new(default_executor).future + end + + # @!macro promises.shortcut.on + # @return [ResolvableFuture] + def resolvable_future + resolvable_future_on default_executor + end + + # Creates resolvable future, user is responsible for resolving the future once by + # {Promises::ResolvableFuture#resolve}, {Promises::ResolvableFuture#fulfill}, + # or {Promises::ResolvableFuture#reject} + # + # @!macro promises.param.default_executor + # @return [ResolvableFuture] + def resolvable_future_on(default_executor = self.default_executor) + ResolvableFuturePromise.new(default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def future(*args, &task) + future_on(default_executor, *args, &task) + end + + # Constructs a new Future which will be resolved after block is evaluated on default executor. + # Evaluation begins immediately. + # + # @!macro promises.param.default_executor + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + def future_on(default_executor, *args, &task) + ImmediateEventPromise.new(default_executor).future.then(*args, &task) + end + + # Creates a resolved future with will be either fulfilled with the given value or rejected with + # the given reason. + # + # @param [true, false] fulfilled + # @param [Object] value + # @param [Object] reason + # @!macro promises.param.default_executor + # @return [Future] + def resolved_future(fulfilled, value, reason, default_executor = self.default_executor) + ImmediateFuturePromise.new(default_executor, fulfilled, value, reason).future + end + + # Creates a resolved future which will be fulfilled with the given value. + # + # @!macro promises.param.default_executor + # @param [Object] value + # @return [Future] + def fulfilled_future(value, default_executor = self.default_executor) + resolved_future true, value, nil, default_executor + end + + # Creates a resolved future which will be rejected with the given reason. + # + # @!macro promises.param.default_executor + # @param [Object] reason + # @return [Future] + def rejected_future(reason, default_executor = self.default_executor) + resolved_future false, nil, reason, default_executor + end + + # Creates resolved event. + # + # @!macro promises.param.default_executor + # @return [Event] + def resolved_event(default_executor = self.default_executor) + ImmediateEventPromise.new(default_executor).event + end + + # General constructor. Behaves differently based on the argument's type. It's provided for convenience + # but it's better to be explicit. + # + # @see rejected_future, resolved_event, fulfilled_future + # @!macro promises.param.default_executor + # @return [Event, Future] + # + # @overload make_future(nil, default_executor = self.default_executor) + # @param [nil] nil + # @return [Event] resolved event. + # + # @overload make_future(a_future, default_executor = self.default_executor) + # @param [Future] a_future + # @return [Future] a future which will be resolved when a_future is. + # + # @overload make_future(an_event, default_executor = self.default_executor) + # @param [Event] an_event + # @return [Event] an event which will be resolved when an_event is. + # + # @overload make_future(exception, default_executor = self.default_executor) + # @param [Exception] exception + # @return [Future] a rejected future with the exception as its reason. + # + # @overload make_future(value, default_executor = self.default_executor) + # @param [Object] value when none of the above overloads fits + # @return [Future] a fulfilled future with the value. + def make_future(argument = nil, default_executor = self.default_executor) + case argument + when AbstractEventFuture + # returning wrapper would change nothing + argument + when Exception + rejected_future argument, default_executor + when nil + resolved_event default_executor + else + fulfilled_future argument, default_executor + end + end + + # @!macro promises.shortcut.on + # @return [Future, Event] + def delay(*args, &task) + delay_on default_executor, *args, &task + end + + # Creates a new event or future which is resolved only after it is touched, + # see {Concurrent::AbstractEventFuture#touch}. + # + # @!macro promises.param.default_executor + # @overload delay_on(default_executor, *args, &task) + # If task is provided it returns a {Future} representing the result of the task. + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + # @overload delay_on(default_executor) + # If no task is provided, it returns an {Event} + # @return [Event] + def delay_on(default_executor, *args, &task) + event = DelayPromise.new(default_executor).event + task ? event.chain(*args, &task) : event + end + + # @!macro promises.shortcut.on + # @return [Future, Event] + def schedule(intended_time, *args, &task) + schedule_on default_executor, intended_time, *args, &task + end + + # Creates a new event or future which is resolved in intended_time. + # + # @!macro promises.param.default_executor + # @!macro promises.param.intended_time + # @param [Numeric, Time] intended_time `Numeric` means to run in `intended_time` seconds. + # `Time` means to run on `intended_time`. + # @overload schedule_on(default_executor, intended_time, *args, &task) + # If task is provided it returns a {Future} representing the result of the task. + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + # @overload schedule_on(default_executor, intended_time) + # If no task is provided, it returns an {Event} + # @return [Event] + def schedule_on(default_executor, intended_time, *args, &task) + event = ScheduledPromise.new(default_executor, intended_time).event + task ? event.chain(*args, &task) : event + end + + # @!macro promises.shortcut.on + # @return [Future] + def zip_futures(*futures_and_or_events) + zip_futures_on default_executor, *futures_and_or_events + end + + # Creates a new future which is resolved after all futures_and_or_events are resolved. + # Its value is an array of zipped future values. Its reason is an array of reasons for rejection. + # If there is an error it rejects. + # @!macro promises.event-conversion + # If event is supplied, which does not have value and can be only resolved, it's + # represented as `:fulfilled` with value `nil`. + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def zip_futures_on(default_executor, *futures_and_or_events) + ZipFuturesPromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + alias_method :zip, :zip_futures + + # @!macro promises.shortcut.on + # @return [Event] + def zip_events(*futures_and_or_events) + zip_events_on default_executor, *futures_and_or_events + end + + # Creates a new event which is resolved after all futures_and_or_events are resolved. + # (Future is resolved when fulfilled or rejected.) + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Event] + def zip_events_on(default_executor, *futures_and_or_events) + ZipEventsPromise.new_blocked_by(futures_and_or_events, default_executor).event + end + + # @!macro promises.shortcut.on + # @return [Future] + def any_resolved_future(*futures_and_or_events) + any_resolved_future_on default_executor, *futures_and_or_events + end + + alias_method :any, :any_resolved_future + + # Creates a new future which is resolved after the first futures_and_or_events is resolved. + # Its result equals the result of the first resolved future. + # @!macro promises.any-touch + # If resolved it does not propagate {Concurrent::AbstractEventFuture#touch}, leaving delayed + # futures un-executed if they are not required any more. + # @!macro promises.event-conversion + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def any_resolved_future_on(default_executor, *futures_and_or_events) + AnyResolvedFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def any_fulfilled_future(*futures_and_or_events) + any_fulfilled_future_on default_executor, *futures_and_or_events + end + + # Creates a new future which is resolved after the first futures_and_or_events is fulfilled. + # Its result equals the result of the first resolved future or if all futures_and_or_events reject, + # it has reason of the last rejected future. + # @!macro promises.any-touch + # @!macro promises.event-conversion + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def any_fulfilled_future_on(default_executor, *futures_and_or_events) + AnyFulfilledFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Event] + def any_event(*futures_and_or_events) + any_event_on default_executor, *futures_and_or_events + end + + # Creates a new event which becomes resolved after the first futures_and_or_events resolves. + # @!macro promises.any-touch + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Event] + def any_event_on(default_executor, *futures_and_or_events) + AnyResolvedEventPromise.new_blocked_by(futures_and_or_events, default_executor).event + end + + # TODO consider adding first(count, *futures) + # TODO consider adding zip_by(slice, *futures) processing futures in slices + # TODO or rather a generic aggregator taking a function + end + + module InternalStates + # @!visibility private + class State + def resolved? + raise NotImplementedError + end + + def to_sym + raise NotImplementedError + end + end + + # @!visibility private + class Pending < State + def resolved? + false + end + + def to_sym + :pending + end + end + + # @!visibility private + class Reserved < Pending + end + + # @!visibility private + class ResolvedWithResult < State + def resolved? + true + end + + def to_sym + :resolved + end + + def result + [fulfilled?, value, reason] + end + + def fulfilled? + raise NotImplementedError + end + + def value + raise NotImplementedError + end + + def reason + raise NotImplementedError + end + + def apply + raise NotImplementedError + end + end + + # @!visibility private + class Fulfilled < ResolvedWithResult + + def initialize(value) + @Value = value + end + + def fulfilled? + true + end + + def apply(args, block) + block.call value, *args + end + + def value + @Value + end + + def reason + nil + end + + def to_sym + :fulfilled + end + end + + # @!visibility private + class FulfilledArray < Fulfilled + def apply(args, block) + block.call(*value, *args) + end + end + + # @!visibility private + class Rejected < ResolvedWithResult + def initialize(reason) + @Reason = reason + end + + def fulfilled? + false + end + + def value + nil + end + + def reason + @Reason + end + + def to_sym + :rejected + end + + def apply(args, block) + block.call reason, *args + end + end + + # @!visibility private + class PartiallyRejected < ResolvedWithResult + def initialize(value, reason) + super() + @Value = value + @Reason = reason + end + + def fulfilled? + false + end + + def to_sym + :rejected + end + + def value + @Value + end + + def reason + @Reason + end + + def apply(args, block) + block.call(*reason, *args) + end + end + + # @!visibility private + PENDING = Pending.new + # @!visibility private + RESERVED = Reserved.new + # @!visibility private + RESOLVED = Fulfilled.new(nil) + + def RESOLVED.to_sym + :resolved + end + end + + private_constant :InternalStates + + # @!macro promises.shortcut.event-future + # @see Event#$0 + # @see Future#$0 + + # @!macro promises.param.timeout + # @param [Numeric] timeout the maximum time in second to wait. + + # @!macro promises.warn.blocks + # @note This function potentially blocks current thread until the Future is resolved. + # Be careful it can deadlock. Try to chain instead. + + # Common ancestor of {Event} and {Future} classes, many shared methods are defined here. + class AbstractEventFuture < Synchronization::Object + safe_initialization! + attr_atomic(:internal_state) + private :internal_state=, :swap_internal_state, :compare_and_set_internal_state, :update_internal_state + # @!method internal_state + # @!visibility private + + include InternalStates + + def initialize(promise, default_executor) + super() + @Lock = Mutex.new + @Condition = ConditionVariable.new + @Promise = promise + @DefaultExecutor = default_executor + @Callbacks = LockFreeStack.new + @Waiters = AtomicFixnum.new 0 + self.internal_state = PENDING + end + + private :initialize + + # Returns its state. + # @return [Symbol] + # + # @overload an_event.state + # @return [:pending, :resolved] + # @overload a_future.state + # Both :fulfilled, :rejected implies :resolved. + # @return [:pending, :fulfilled, :rejected] + def state + internal_state.to_sym + end + + # Is it in pending state? + # @return [Boolean] + def pending? + !internal_state.resolved? + end + + # Is it in resolved state? + # @return [Boolean] + def resolved? + internal_state.resolved? + end + + # Propagates touch. Requests all the delayed futures, which it depends on, to be + # executed. This method is called by any other method requiring resolved state, like {#wait}. + # @return [self] + def touch + @Promise.touch + self + end + + # @!macro promises.touches + # Calls {Concurrent::AbstractEventFuture#touch}. + + # @!macro promises.method.wait + # Wait (block the Thread) until receiver is {#resolved?}. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.param.timeout + # @return [self, true, false] self implies timeout was not used, true implies timeout was used + # and it was resolved, false implies it was not resolved within timeout. + def wait(timeout = nil) + result = wait_until_resolved(timeout) + timeout ? result : self + end + + # Returns default executor. + # @return [Executor] default executor + # @see #with_default_executor + # @see FactoryMethods#future_on + # @see FactoryMethods#resolvable_future + # @see FactoryMethods#any_fulfilled_future_on + # @see similar + def default_executor + @DefaultExecutor + end + + # @!macro promises.shortcut.on + # @return [Future] + def chain(*args, &task) + chain_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it is resolved. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @return [Future] + # @!macro promise.param.task-future + # + # @overload an_event.chain_on(executor, *args, &task) + # @yield [*args] to the task. + # @overload a_future.chain_on(executor, *args, &task) + # @yield [fulfilled, value, reason, *args] to the task. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def chain_on(executor, *args, &task) + ChainPromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @return [String] Short string representation. + def to_s + format '%s %s>', super[0..-2], state + end + + alias_method :inspect, :to_s + + # Resolves the resolvable when receiver is resolved. + # + # @param [Resolvable] resolvable + # @return [self] + def chain_resolvable(resolvable) + on_resolution! { resolvable.resolve_with internal_state } + end + + alias_method :tangle, :chain_resolvable + + # @!macro promises.shortcut.using + # @return [self] + def on_resolution(*args, &callback) + on_resolution_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # resolved. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # + # @overload an_event.on_resolution!(*args, &callback) + # @yield [*args] to the callback. + # @overload a_future.on_resolution!(*args, &callback) + # @yield [fulfilled, value, reason, *args] to the callback. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def on_resolution!(*args, &callback) + add_callback :callback_on_resolution, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is resolved. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # + # @overload an_event.on_resolution_using(executor, *args, &callback) + # @yield [*args] to the callback. + # @overload a_future.on_resolution_using(executor, *args, &callback) + # @yield [fulfilled, value, reason, *args] to the callback. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def on_resolution_using(executor, *args, &callback) + add_callback :async_callback_on_resolution, executor, args, callback + end + + # @!macro promises.method.with_default_executor + # Crates new object with same class with the executor set as its new default executor. + # Any futures depending on it will use the new default executor. + # @!macro promises.shortcut.event-future + # @abstract + # @return [AbstractEventFuture] + def with_default_executor(executor) + raise NotImplementedError + end + + # @!visibility private + def resolve_with(state, raise_on_reassign = true, reserved = false) + if compare_and_set_internal_state(reserved ? RESERVED : PENDING, state) + # go to synchronized block only if there were waiting threads + @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0 + call_callbacks state + else + return rejected_resolution(raise_on_reassign, state) + end + self + end + + # For inspection. + # @!visibility private + # @return [Array] + def blocks + @Callbacks.each_with_object([]) do |(method, args), promises| + promises.push(args[0]) if method == :callback_notify_blocked + end + end + + # For inspection. + # @!visibility private + def callbacks + @Callbacks.each.to_a + end + + # For inspection. + # @!visibility private + def promise + @Promise + end + + # For inspection. + # @!visibility private + def touched? + promise.touched? + end + + # For inspection. + # @!visibility private + def waiting_threads + @Waiters.each.to_a + end + + # @!visibility private + def add_callback_notify_blocked(promise, index) + add_callback :callback_notify_blocked, promise, index + end + + # @!visibility private + def add_callback_clear_delayed_node(node) + add_callback(:callback_clear_delayed_node, node) + end + + # @!visibility private + def with_hidden_resolvable + # TODO (pitr-ch 10-Dec-2018): documentation, better name if in edge + self + end + + private + + def add_callback(method, *args) + state = internal_state + if state.resolved? + call_callback method, state, args + else + @Callbacks.push [method, args] + state = internal_state + # take back if it was resolved in the meanwhile + call_callbacks state if state.resolved? + end + self + end + + def callback_clear_delayed_node(state, node) + node.value = nil + end + + # @return [Boolean] + def wait_until_resolved(timeout) + return true if resolved? + + touch + + @Lock.synchronize do + @Waiters.increment + begin + if timeout + start = Concurrent.monotonic_time + until resolved? + break if @Condition.wait(@Lock, timeout) == nil # nil means timeout + timeout -= (Concurrent.monotonic_time - start) + break if timeout <= 0 + end + else + until resolved? + @Condition.wait(@Lock, timeout) + end + end + ensure + # JRuby may raise ConcurrencyError + @Waiters.decrement + end + end + resolved? + end + + def call_callback(method, state, args) + self.send method, state, *args + end + + def call_callbacks(state) + method, args = @Callbacks.pop + while method + call_callback method, state, args + method, args = @Callbacks.pop + end + end + + def with_async(executor, *args, &block) + Concurrent.executor(executor).post(*args, &block) + end + + def async_callback_on_resolution(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_resolution st, ar, cb + end + end + + def callback_notify_blocked(state, promise, index) + promise.on_blocker_resolution self, index + end + end + + # Represents an event which will happen in future (will be resolved). The event is either + # pending or resolved. It should be always resolved. Use {Future} to communicate rejections and + # cancellation. + class Event < AbstractEventFuture + + alias_method :then, :chain + + + # @!macro promises.method.zip + # Creates a new event or a future which will be resolved when receiver and other are. + # Returns an event if receiver and other are events, otherwise returns a future. + # If just one of the parties is Future then the result + # of the returned future is equal to the result of the supplied future. If both are futures + # then the result is as described in {FactoryMethods#zip_futures_on}. + # + # @return [Future, Event] + def zip(other) + if other.is_a?(Future) + ZipFutureEventPromise.new_blocked_by2(other, self, @DefaultExecutor).future + else + ZipEventEventPromise.new_blocked_by2(self, other, @DefaultExecutor).event + end + end + + alias_method :&, :zip + + # Creates a new event which will be resolved when the first of receiver, `event_or_future` + # resolves. + # + # @return [Event] + def any(event_or_future) + AnyResolvedEventPromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).event + end + + alias_method :|, :any + + # Creates new event dependent on receiver which will not evaluate until touched, see {#touch}. + # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. + # + # @return [Event] + def delay + event = DelayPromise.new(@DefaultExecutor).event + ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event + end + + # @!macro promise.method.schedule + # Creates new event dependent on receiver scheduled to execute on/in intended_time. + # In time is interpreted from the moment the receiver is resolved, therefore it inserts + # delay into the chain. + # + # @!macro promises.param.intended_time + # @return [Event] + def schedule(intended_time) + chain do + event = ScheduledPromise.new(@DefaultExecutor, intended_time).event + ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event + end.flat_event + end + + # Converts event to a future. The future is fulfilled when the event is resolved, the future may never fail. + # + # @return [Future] + def to_future + future = Promises.resolvable_future + ensure + chain_resolvable(future) + end + + # Returns self, since this is event + # @return [Event] + def to_event + self + end + + # @!macro promises.method.with_default_executor + # @return [Event] + def with_default_executor(executor) + EventWrapperPromise.new_blocked_by1(self, executor).event + end + + private + + def rejected_resolution(raise_on_reassign, state) + raise Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign + return false + end + + def callback_on_resolution(state, args, callback) + callback.call(*args) + end + end + + # Represents a value which will become available in future. May reject with a reason instead, + # e.g. when the tasks raises an exception. + class Future < AbstractEventFuture + + # Is it in fulfilled state? + # @return [Boolean] + def fulfilled? + state = internal_state + state.resolved? && state.fulfilled? + end + + # Is it in rejected state? + # @return [Boolean] + def rejected? + state = internal_state + state.resolved? && !state.fulfilled? + end + + # @!macro promises.warn.nil + # @note Make sure returned `nil` is not confused with timeout, no value when rejected, + # no reason when fulfilled, etc. + # Use more exact methods if needed, like {#wait}, {#value!}, {#result}, etc. + + # @!macro promises.method.value + # Return value of the future. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.warn.nil + # @!macro promises.param.timeout + # @!macro promises.param.timeout_value + # @param [Object] timeout_value a value returned by the method when it times out + # @return [Object, nil, timeout_value] the value of the Future when fulfilled, + # timeout_value on timeout, + # nil on rejection. + def value(timeout = nil, timeout_value = nil) + if wait_until_resolved timeout + internal_state.value + else + timeout_value + end + end + + # Returns reason of future's rejection. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.warn.nil + # @!macro promises.param.timeout + # @!macro promises.param.timeout_value + # @return [Object, timeout_value] the reason, or timeout_value on timeout, or nil on fulfillment. + def reason(timeout = nil, timeout_value = nil) + if wait_until_resolved timeout + internal_state.reason + else + timeout_value + end + end + + # Returns triplet fulfilled?, value, reason. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.param.timeout + # @return [Array(Boolean, Object, Object), nil] triplet of fulfilled?, value, reason, or nil + # on timeout. + def result(timeout = nil) + internal_state.result if wait_until_resolved timeout + end + + # @!macro promises.method.wait + # @raise [Exception] {#reason} on rejection + def wait!(timeout = nil) + result = wait_until_resolved!(timeout) + timeout ? result : self + end + + # @!macro promises.method.value + # @return [Object, nil, timeout_value] the value of the Future when fulfilled, + # or nil on rejection, + # or timeout_value on timeout. + # @raise [Exception] {#reason} on rejection + def value!(timeout = nil, timeout_value = nil) + if wait_until_resolved! timeout + internal_state.value + else + timeout_value + end + end + + # Allows rejected Future to be risen with `raise` method. + # If the reason is not an exception `Runtime.new(reason)` is returned. + # + # @example + # raise Promises.rejected_future(StandardError.new("boom")) + # raise Promises.rejected_future("or just boom") + # @raise [Concurrent::Error] when raising not rejected future + # @return [Exception] + def exception(*args) + raise Concurrent::Error, 'it is not rejected' unless rejected? + raise ArgumentError unless args.size <= 1 + reason = Array(internal_state.reason).flatten.compact + if reason.size > 1 + ex = Concurrent::MultipleErrors.new reason + ex.set_backtrace(caller) + ex + else + ex = if reason[0].respond_to? :exception + reason[0].exception(*args) + else + RuntimeError.new(reason[0]).exception(*args) + end + ex.set_backtrace Array(ex.backtrace) + caller + ex + end + end + + # @!macro promises.shortcut.on + # @return [Future] + def then(*args, &task) + then_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it fulfills. Does not run + # the task if it rejects. It will resolve though, triggering any dependent futures. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.task-future + # @return [Future] + # @yield [value, *args] to the task. + def then_on(executor, *args, &task) + ThenPromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def rescue(*args, &task) + rescue_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it rejects. Does not run + # the task if it fulfills. It will resolve though, triggering any dependent futures. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.task-future + # @return [Future] + # @yield [reason, *args] to the task. + def rescue_on(executor, *args, &task) + RescuePromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @!macro promises.method.zip + # @return [Future] + def zip(other) + if other.is_a?(Future) + ZipFuturesPromise.new_blocked_by2(self, other, @DefaultExecutor).future + else + ZipFutureEventPromise.new_blocked_by2(self, other, @DefaultExecutor).future + end + end + + alias_method :&, :zip + + # Creates a new event which will be resolved when the first of receiver, `event_or_future` + # resolves. Returning future will have value nil if event_or_future is event and resolves + # first. + # + # @return [Future] + def any(event_or_future) + AnyResolvedFuturePromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).future + end + + alias_method :|, :any + + # Creates new future dependent on receiver which will not evaluate until touched, see {#touch}. + # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. + # + # @return [Future] + def delay + event = DelayPromise.new(@DefaultExecutor).event + ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future + end + + # @!macro promise.method.schedule + # @return [Future] + def schedule(intended_time) + chain do + event = ScheduledPromise.new(@DefaultExecutor, intended_time).event + ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future + end.flat + end + + # @!macro promises.method.with_default_executor + # @return [Future] + def with_default_executor(executor) + FutureWrapperPromise.new_blocked_by1(self, executor).future + end + + # Creates new future which will have result of the future returned by receiver. If receiver + # rejects it will have its rejection. + # + # @param [Integer] level how many levels of futures should flatten + # @return [Future] + def flat_future(level = 1) + FlatFuturePromise.new_blocked_by1(self, level, @DefaultExecutor).future + end + + alias_method :flat, :flat_future + + # Creates new event which will be resolved when the returned event by receiver is. + # Be careful if the receiver rejects it will just resolve since Event does not hold reason. + # + # @return [Event] + def flat_event + FlatEventPromise.new_blocked_by1(self, @DefaultExecutor).event + end + + # @!macro promises.shortcut.using + # @return [self] + def on_fulfillment(*args, &callback) + on_fulfillment_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # fulfilled. Does nothing on rejection. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [value, *args] to the callback. + def on_fulfillment!(*args, &callback) + add_callback :callback_on_fulfillment, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is + # fulfilled. Does nothing on rejection. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [value, *args] to the callback. + def on_fulfillment_using(executor, *args, &callback) + add_callback :async_callback_on_fulfillment, executor, args, callback + end + + # @!macro promises.shortcut.using + # @return [self] + def on_rejection(*args, &callback) + on_rejection_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # rejected. Does nothing on fulfillment. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [reason, *args] to the callback. + def on_rejection!(*args, &callback) + add_callback :callback_on_rejection, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is + # rejected. Does nothing on fulfillment. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [reason, *args] to the callback. + def on_rejection_using(executor, *args, &callback) + add_callback :async_callback_on_rejection, executor, args, callback + end + + # Allows to use futures as green threads. The receiver has to evaluate to a future which + # represents what should be done next. It basically flattens indefinitely until non Future + # values is returned which becomes result of the returned future. Any encountered exception + # will become reason of the returned future. + # + # @return [Future] + # @param [#call(value)] run_test + # an object which when called returns either Future to keep running with + # or nil, then the run completes with the value. + # The run_test can be used to extract the Future from deeper structure, + # or to distinguish Future which is a resulting value from a future + # which is suppose to continue running. + # @example + # body = lambda do |v| + # v += 1 + # v < 5 ? Promises.future(v, &body) : v + # end + # Promises.future(0, &body).run.value! # => 5 + def run(run_test = method(:run_test)) + RunFuturePromise.new_blocked_by1(self, @DefaultExecutor, run_test).future + end + + # @!visibility private + def apply(args, block) + internal_state.apply args, block + end + + # Converts future to event which is resolved when future is resolved by fulfillment or rejection. + # + # @return [Event] + def to_event + event = Promises.resolvable_event + ensure + chain_resolvable(event) + end + + # Returns self, since this is a future + # @return [Future] + def to_future + self + end + + # @return [String] Short string representation. + def to_s + if resolved? + format '%s with %s>', super[0..-2], (fulfilled? ? value : reason).inspect + else + super + end + end + + alias_method :inspect, :to_s + + private + + def run_test(v) + v if v.is_a?(Future) + end + + def rejected_resolution(raise_on_reassign, state) + if raise_on_reassign + if internal_state == RESERVED + raise Concurrent::MultipleAssignmentError.new( + "Future can be resolved only once. It is already reserved.") + else + raise Concurrent::MultipleAssignmentError.new( + "Future can be resolved only once. It's #{result}, trying to set #{state.result}.", + current_result: result, + new_result: state.result) + end + end + return false + end + + def wait_until_resolved!(timeout = nil) + result = wait_until_resolved(timeout) + raise self if rejected? + result + end + + def async_callback_on_fulfillment(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_fulfillment st, ar, cb + end + end + + def async_callback_on_rejection(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_rejection st, ar, cb + end + end + + def callback_on_fulfillment(state, args, callback) + state.apply args, callback if state.fulfilled? + end + + def callback_on_rejection(state, args, callback) + state.apply args, callback unless state.fulfilled? + end + + def callback_on_resolution(state, args, callback) + callback.call(*state.result, *args) + end + + end + + # Marker module of Future, Event resolved manually. + module Resolvable + include InternalStates + end + + # A Event which can be resolved by user. + class ResolvableEvent < Event + include Resolvable + + # @!macro raise_on_reassign + # @raise [MultipleAssignmentError] when already resolved and raise_on_reassign is true. + + # @!macro promise.param.raise_on_reassign + # @param [Boolean] raise_on_reassign should method raise exception if already resolved + # @return [self, false] false is returned when raise_on_reassign is false and the receiver + # is already resolved. + # + + # Makes the event resolved, which triggers all dependent futures. + # + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + # @param [true, false] reserved + # Set to true if the resolvable is {#reserve}d by you, + # marks resolution of reserved resolvable events and futures explicitly. + # Advanced feature, ignore unless you use {Resolvable#reserve} from edge. + def resolve(raise_on_reassign = true, reserved = false) + resolve_with RESOLVED, raise_on_reassign, reserved + end + + # Creates new event wrapping receiver, effectively hiding the resolve method. + # + # @return [Event] + def with_hidden_resolvable + @with_hidden_resolvable ||= EventWrapperPromise.new_blocked_by1(self, @DefaultExecutor).event + end + + # Behaves as {AbstractEventFuture#wait} but has one additional optional argument + # resolve_on_timeout. + # + # @param [true, false] resolve_on_timeout + # If it times out and the argument is true it will also resolve the event. + # @return [self, true, false] + # @see AbstractEventFuture#wait + def wait(timeout = nil, resolve_on_timeout = false) + super(timeout) or if resolve_on_timeout + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + !resolve(false) + else + false + end + end + end + + # A Future which can be resolved by user. + class ResolvableFuture < Future + include Resolvable + + # Makes the future resolved with result of triplet `fulfilled?`, `value`, `reason`, + # which triggers all dependent futures. + # + # @param [true, false] fulfilled + # @param [Object] value + # @param [Object] reason + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def resolve(fulfilled = true, value = nil, reason = nil, raise_on_reassign = true, reserved = false) + resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason), raise_on_reassign, reserved) + end + + # Makes the future fulfilled with `value`, + # which triggers all dependent futures. + # + # @param [Object] value + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def fulfill(value, raise_on_reassign = true, reserved = false) + resolve_with Fulfilled.new(value), raise_on_reassign, reserved + end + + # Makes the future rejected with `reason`, + # which triggers all dependent futures. + # + # @param [Object] reason + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def reject(reason, raise_on_reassign = true, reserved = false) + resolve_with Rejected.new(reason), raise_on_reassign, reserved + end + + # Evaluates the block and sets its result as future's value fulfilling, if the block raises + # an exception the future rejects with it. + # + # @yield [*args] to the block. + # @yieldreturn [Object] value + # @return [self] + def evaluate_to(*args, &block) + promise.evaluate_to(*args, block) + end + + # Evaluates the block and sets its result as future's value fulfilling, if the block raises + # an exception the future rejects with it. + # + # @yield [*args] to the block. + # @yieldreturn [Object] value + # @return [self] + # @raise [Exception] also raise reason on rejection. + def evaluate_to!(*args, &block) + promise.evaluate_to(*args, block).wait! + end + + # @!macro promises.resolvable.resolve_on_timeout + # @param [::Array(true, Object, nil), ::Array(false, nil, Exception), nil] resolve_on_timeout + # If it times out and the argument is not nil it will also resolve the future + # to the provided resolution. + + # Behaves as {AbstractEventFuture#wait} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [self, true, false] + # @see AbstractEventFuture#wait + def wait(timeout = nil, resolve_on_timeout = nil) + super(timeout) or if resolve_on_timeout + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + !resolve(*resolve_on_timeout, false) + else + false + end + end + + # Behaves as {Future#wait!} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [self, true, false] + # @raise [Exception] {#reason} on rejection + # @see Future#wait! + def wait!(timeout = nil, resolve_on_timeout = nil) + super(timeout) or if resolve_on_timeout + if resolve(*resolve_on_timeout, false) + false + else + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + raise self if rejected? + true + end + else + false + end + end + + # Behaves as {Future#value} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Object, timeout_value, nil] + # @see Future#value + def value(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.value + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + return internal_state.value + end + end + timeout_value + end + end + + # Behaves as {Future#value!} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Object, timeout_value, nil] + # @raise [Exception] {#reason} on rejection + # @see Future#value! + def value!(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved! timeout + internal_state.value + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + raise self if rejected? + return internal_state.value + end + end + timeout_value + end + end + + # Behaves as {Future#reason} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Exception, timeout_value, nil] + # @see Future#reason + def reason(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.reason + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + return internal_state.reason + end + end + timeout_value + end + end + + # Behaves as {Future#result} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [::Array(Boolean, Object, Exception), nil] + # @see Future#result + def result(timeout = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.result + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + internal_state.result + end + end + # otherwise returns nil + end + end + + # Creates new future wrapping receiver, effectively hiding the resolve method and similar. + # + # @return [Future] + def with_hidden_resolvable + @with_hidden_resolvable ||= FutureWrapperPromise.new_blocked_by1(self, @DefaultExecutor).future + end + end + + # @abstract + # @private + class AbstractPromise < Synchronization::Object + safe_initialization! + include InternalStates + + def initialize(future) + super() + @Future = future + end + + def future + @Future + end + + alias_method :event, :future + + def default_executor + future.default_executor + end + + def state + future.state + end + + def touch + end + + def to_s + format '%s %s>', super[0..-2], @Future + end + + alias_method :inspect, :to_s + + def delayed_because + nil + end + + private + + def resolve_with(new_state, raise_on_reassign = true) + @Future.resolve_with(new_state, raise_on_reassign) + end + + # @return [Future] + def evaluate_to(*args, block) + resolve_with Fulfilled.new(block.call(*args)) + rescue Exception => error + resolve_with Rejected.new(error) + raise error unless error.is_a?(StandardError) + end + end + + class ResolvableEventPromise < AbstractPromise + def initialize(default_executor) + super ResolvableEvent.new(self, default_executor) + end + end + + class ResolvableFuturePromise < AbstractPromise + def initialize(default_executor) + super ResolvableFuture.new(self, default_executor) + end + + public :evaluate_to + end + + # @abstract + class InnerPromise < AbstractPromise + end + + # @abstract + class BlockedPromise < InnerPromise + + private_class_method :new + + def self.new_blocked_by1(blocker, *args, &block) + blocker_delayed = blocker.promise.delayed_because + promise = new(blocker_delayed, 1, *args, &block) + blocker.add_callback_notify_blocked promise, 0 + promise + end + + def self.new_blocked_by2(blocker1, blocker2, *args, &block) + blocker_delayed1 = blocker1.promise.delayed_because + blocker_delayed2 = blocker2.promise.delayed_because + delayed = if blocker_delayed1 && blocker_delayed2 + # TODO (pitr-ch 23-Dec-2016): use arrays when we know it will not grow (only flat adds delay) + LockFreeStack.of2(blocker_delayed1, blocker_delayed2) + else + blocker_delayed1 || blocker_delayed2 + end + promise = new(delayed, 2, *args, &block) + blocker1.add_callback_notify_blocked promise, 0 + blocker2.add_callback_notify_blocked promise, 1 + promise + end + + def self.new_blocked_by(blockers, *args, &block) + delayed = blockers.reduce(nil) { |d, f| add_delayed d, f.promise.delayed_because } + promise = new(delayed, blockers.size, *args, &block) + blockers.each_with_index { |f, i| f.add_callback_notify_blocked promise, i } + promise + end + + def self.add_delayed(delayed1, delayed2) + if delayed1 && delayed2 + delayed1.push delayed2 + delayed1 + else + delayed1 || delayed2 + end + end + + def initialize(delayed, blockers_count, future) + super(future) + @Delayed = delayed + @Countdown = AtomicFixnum.new blockers_count + end + + def on_blocker_resolution(future, index) + countdown = process_on_blocker_resolution(future, index) + resolvable = resolvable?(countdown, future, index) + + on_resolvable(future, index) if resolvable + end + + def delayed_because + @Delayed + end + + def touch + clear_and_propagate_touch + end + + # for inspection only + def blocked_by + blocked_by = [] + ObjectSpace.each_object(AbstractEventFuture) { |o| blocked_by.push o if o.blocks.include? self } + blocked_by + end + + private + + def clear_and_propagate_touch(stack_or_element = @Delayed) + return if stack_or_element.nil? + + if stack_or_element.is_a? LockFreeStack + stack_or_element.clear_each { |element| clear_and_propagate_touch element } + else + stack_or_element.touch unless stack_or_element.nil? # if still present + end + end + + # @return [true,false] if resolvable + def resolvable?(countdown, future, index) + countdown.zero? + end + + def process_on_blocker_resolution(future, index) + @Countdown.decrement + end + + def on_resolvable(resolved_future, index) + raise NotImplementedError + end + end + + # @abstract + class BlockedTaskPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + raise ArgumentError, 'no block given' unless block_given? + super delayed, 1, Future.new(self, default_executor) + @Executor = executor + @Task = task + @Args = args + end + + def executor + @Executor + end + end + + class ThenPromise < BlockedTaskPromise + private + + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + super delayed, blockers_count, default_executor, executor, args, &task + end + + def on_resolvable(resolved_future, index) + if resolved_future.fulfilled? + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to lambda { future.apply args, task } + end + else + resolve_with resolved_future.internal_state + end + end + end + + class RescuePromise < BlockedTaskPromise + private + + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + super delayed, blockers_count, default_executor, executor, args, &task + end + + def on_resolvable(resolved_future, index) + if resolved_future.rejected? + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to lambda { future.apply args, task } + end + else + resolve_with resolved_future.internal_state + end + end + end + + class ChainPromise < BlockedTaskPromise + private + + def on_resolvable(resolved_future, index) + if Future === resolved_future + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to(*future.result, *args, task) + end + else + Concurrent.executor(@Executor).post(@Args, @Task) do |args, task| + evaluate_to(*args, task) + end + end + end + end + + # will be immediately resolved + class ImmediateEventPromise < InnerPromise + def initialize(default_executor) + super Event.new(self, default_executor).resolve_with(RESOLVED) + end + end + + class ImmediateFuturePromise < InnerPromise + def initialize(default_executor, fulfilled, value, reason) + super Future.new(self, default_executor). + resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason)) + end + end + + class AbstractFlatPromise < BlockedPromise + + def initialize(delayed_because, blockers_count, event_or_future) + delayed = LockFreeStack.of1(self) + super(delayed, blockers_count, event_or_future) + # noinspection RubyArgCount + @Touched = AtomicBoolean.new false + @DelayedBecause = delayed_because || LockFreeStack.new + + event_or_future.add_callback_clear_delayed_node delayed.peek + end + + def touch + if @Touched.make_true + clear_and_propagate_touch @DelayedBecause + end + end + + private + + def touched? + @Touched.value + end + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state + end + + def resolvable?(countdown, future, index) + !@Future.internal_state.resolved? && super(countdown, future, index) + end + + def add_delayed_of(future) + delayed = future.promise.delayed_because + if touched? + clear_and_propagate_touch delayed + else + BlockedPromise.add_delayed @DelayedBecause, delayed + clear_and_propagate_touch @DelayedBecause if touched? + end + end + + end + + class FlatEventPromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Event.new(self, default_executor) + end + + def process_on_blocker_resolution(future, index) + countdown = super(future, index) + if countdown.nonzero? + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with RESOLVED + return countdown + end + + value = internal_state.value + case value + when AbstractEventFuture + add_delayed_of value + value.add_callback_notify_blocked self, nil + countdown + else + resolve_with RESOLVED + end + end + countdown + end + + end + + class FlatFuturePromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, levels, default_executor) + raise ArgumentError, 'levels has to be higher than 0' if levels < 1 + # flat promise may result to a future having delayed futures, therefore we have to have empty stack + # to be able to add new delayed futures + super delayed || LockFreeStack.new, 1 + levels, Future.new(self, default_executor) + end + + def process_on_blocker_resolution(future, index) + countdown = super(future, index) + if countdown.nonzero? + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with internal_state + return countdown + end + + value = internal_state.value + case value + when AbstractEventFuture + add_delayed_of value + value.add_callback_notify_blocked self, nil + countdown + else + evaluate_to(lambda { raise TypeError, "returned value #{value.inspect} is not a Future" }) + end + end + countdown + end + + end + + class RunFuturePromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, default_executor, run_test) + super delayed, 1, Future.new(self, default_executor) + @RunTest = run_test + end + + def process_on_blocker_resolution(future, index) + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with internal_state + return 0 + end + + value = internal_state.value + continuation_future = @RunTest.call value + + if continuation_future + add_delayed_of continuation_future + continuation_future.add_callback_notify_blocked self, nil + else + resolve_with internal_state + end + + 1 + end + end + + class ZipEventEventPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Event.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + class ZipFutureEventPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Future.new(self, default_executor) + @result = nil + end + + private + + def process_on_blocker_resolution(future, index) + # first blocking is future, take its result + @result = future.internal_state if index == 0 + # super has to be called after above to piggyback on volatile @Countdown + super future, index + end + + def on_resolvable(resolved_future, index) + resolve_with @result + end + end + + class EventWrapperPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 1, Event.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + class FutureWrapperPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 1, Future.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state + end + end + + class ZipFuturesPromise < BlockedPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super(delayed, blockers_count, Future.new(self, default_executor)) + @Resolutions = ::Array.new(blockers_count, nil) + + on_resolvable nil, nil if blockers_count == 0 + end + + def process_on_blocker_resolution(future, index) + # TODO (pitr-ch 18-Dec-2016): Can we assume that array will never break under parallel access when never re-sized? + @Resolutions[index] = future.internal_state # has to be set before countdown in super + super future, index + end + + def on_resolvable(resolved_future, index) + all_fulfilled = true + values = ::Array.new(@Resolutions.size) + reasons = ::Array.new(@Resolutions.size) + + @Resolutions.each_with_index do |internal_state, i| + fulfilled, values[i], reasons[i] = internal_state.result + all_fulfilled &&= fulfilled + end + + if all_fulfilled + resolve_with FulfilledArray.new(values) + else + resolve_with PartiallyRejected.new(values, reasons) + end + end + end + + class ZipEventsPromise < BlockedPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Event.new(self, default_executor) + + on_resolvable nil, nil if blockers_count == 0 + end + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + # @abstract + class AbstractAnyPromise < BlockedPromise + end + + class AnyResolvedEventPromise < AbstractAnyPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Event.new(self, default_executor) + end + + def resolvable?(countdown, future, index) + true + end + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED, false + end + end + + class AnyResolvedFuturePromise < AbstractAnyPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Future.new(self, default_executor) + end + + def resolvable?(countdown, future, index) + true + end + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state, false + end + end + + class AnyFulfilledFuturePromise < AnyResolvedFuturePromise + + private + + def resolvable?(countdown, event_or_future, index) + (event_or_future.is_a?(Event) ? event_or_future.resolved? : event_or_future.fulfilled?) || + # inlined super from BlockedPromise + countdown.zero? + end + end + + class DelayPromise < InnerPromise + + def initialize(default_executor) + event = Event.new(self, default_executor) + @Delayed = LockFreeStack.of1(self) + super event + event.add_callback_clear_delayed_node @Delayed.peek + end + + def touch + @Future.resolve_with RESOLVED + end + + def delayed_because + @Delayed + end + + end + + class ScheduledPromise < InnerPromise + def intended_time + @IntendedTime + end + + def inspect + "#{to_s[0..-2]} intended_time: #{@IntendedTime}>" + end + + private + + def initialize(default_executor, intended_time) + super Event.new(self, default_executor) + + @IntendedTime = intended_time + + in_seconds = begin + now = Time.now + schedule_time = if @IntendedTime.is_a? Time + @IntendedTime + else + now + @IntendedTime + end + [0, schedule_time.to_f - now.to_f].max + end + + Concurrent.global_timer_set.post(in_seconds) do + @Future.resolve_with RESOLVED + end + end + end + + extend FactoryMethods + + private_constant :AbstractPromise, + :ResolvableEventPromise, + :ResolvableFuturePromise, + :InnerPromise, + :BlockedPromise, + :BlockedTaskPromise, + :ThenPromise, + :RescuePromise, + :ChainPromise, + :ImmediateEventPromise, + :ImmediateFuturePromise, + :AbstractFlatPromise, + :FlatFuturePromise, + :FlatEventPromise, + :RunFuturePromise, + :ZipEventEventPromise, + :ZipFutureEventPromise, + :EventWrapperPromise, + :FutureWrapperPromise, + :ZipFuturesPromise, + :ZipEventsPromise, + :AbstractAnyPromise, + :AnyResolvedFuturePromise, + :AnyFulfilledFuturePromise, + :AnyResolvedEventPromise, + :DelayPromise, + :ScheduledPromise + + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/re_include.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/re_include.rb new file mode 100644 index 00000000..600bc6a5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/re_include.rb @@ -0,0 +1,60 @@ +module Concurrent + + # Methods form module A included to a module B, which is already included into class C, + # will not be visible in the C class. If this module is extended to B then A's methods + # are correctly made visible to C. + # + # @example + # module A + # def a + # :a + # end + # end + # + # module B1 + # end + # + # class C1 + # include B1 + # end + # + # module B2 + # extend Concurrent::ReInclude + # end + # + # class C2 + # include B2 + # end + # + # B1.send :include, A + # B2.send :include, A + # + # C1.new.respond_to? :a # => false + # C2.new.respond_to? :a # => true + # + # @!visibility private + module ReInclude + # @!visibility private + def included(base) + (@re_include_to_bases ||= []) << [:include, base] + super(base) + end + + # @!visibility private + def extended(base) + (@re_include_to_bases ||= []) << [:extend, base] + super(base) + end + + # @!visibility private + def include(*modules) + result = super(*modules) + modules.reverse.each do |module_being_included| + (@re_include_to_bases ||= []).each do |method, mod| + mod.send method, module_being_included + end + end + result + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/scheduled_task.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/scheduled_task.rb new file mode 100644 index 00000000..efe9e193 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/scheduled_task.rb @@ -0,0 +1,331 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/configuration' +require 'concurrent/ivar' +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/utility/monotonic_time' + +require 'concurrent/options' + +module Concurrent + + # `ScheduledTask` is a close relative of `Concurrent::Future` but with one + # important difference: A `Future` is set to execute as soon as possible + # whereas a `ScheduledTask` is set to execute after a specified delay. This + # implementation is loosely based on Java's + # [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html). + # It is a more feature-rich variant of {Concurrent.timer}. + # + # The *intended* schedule time of task execution is set on object construction + # with the `delay` argument. The delay is a numeric (floating point or integer) + # representing a number of seconds in the future. Any other value or a numeric + # equal to or less than zero will result in an exception. The *actual* schedule + # time of task execution is set when the `execute` method is called. + # + # The constructor can also be given zero or more processing options. Currently + # the only supported options are those recognized by the + # [Dereferenceable](Dereferenceable) module. + # + # The final constructor argument is a block representing the task to be performed. + # If no block is given an `ArgumentError` will be raised. + # + # **States** + # + # `ScheduledTask` mixes in the [Obligation](Obligation) module thus giving it + # "future" behavior. This includes the expected lifecycle states. `ScheduledTask` + # has one additional state, however. While the task (block) is being executed the + # state of the object will be `:processing`. This additional state is necessary + # because it has implications for task cancellation. + # + # **Cancellation** + # + # A `:pending` task can be cancelled using the `#cancel` method. A task in any + # other state, including `:processing`, cannot be cancelled. The `#cancel` + # method returns a boolean indicating the success of the cancellation attempt. + # A cancelled `ScheduledTask` cannot be restarted. It is immutable. + # + # **Obligation and Observation** + # + # The result of a `ScheduledTask` can be obtained either synchronously or + # asynchronously. `ScheduledTask` mixes in both the [Obligation](Obligation) + # module and the + # [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html) + # module from the Ruby standard library. With one exception `ScheduledTask` + # behaves identically to [Future](Observable) with regard to these modules. + # + # @!macro copy_options + # + # @example Basic usage + # + # require 'concurrent/scheduled_task' + # require 'csv' + # require 'open-uri' + # + # class Ticker + # def get_year_end_closing(symbol, year, api_key) + # uri = "https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=#{symbol}&apikey=#{api_key}&datatype=csv" + # data = [] + # csv = URI.parse(uri).read + # if csv.include?('call frequency') + # return :rate_limit_exceeded + # end + # CSV.parse(csv, headers: true) do |row| + # data << row['close'].to_f if row['timestamp'].include?(year.to_s) + # end + # year_end = data.first + # year_end + # rescue => e + # p e + # end + # end + # + # api_key = ENV['ALPHAVANTAGE_KEY'] + # abort(error_message) unless api_key + # + # # Future + # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013, api_key) } + # price.state #=> :pending + # price.pending? #=> true + # price.value(0) #=> nil (does not block) + # + # sleep(1) # do other stuff + # + # price.value #=> 63.65 (after blocking if necessary) + # price.state #=> :fulfilled + # price.fulfilled? #=> true + # price.value #=> 63.65 + # + # @example Successful task execution + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } + # task.state #=> :unscheduled + # task.execute + # task.state #=> pending + # + # # wait for it... + # sleep(3) + # + # task.unscheduled? #=> false + # task.pending? #=> false + # task.fulfilled? #=> true + # task.rejected? #=> false + # task.value #=> 'What does the fox say?' + # + # @example One line creation and execution + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }.execute + # task.state #=> pending + # + # task = Concurrent::ScheduledTask.execute(2){ 'What do you get when you multiply 6 by 9?' } + # task.state #=> pending + # + # @example Failed task execution + # + # task = Concurrent::ScheduledTask.execute(2){ raise StandardError.new('Call me maybe?') } + # task.pending? #=> true + # + # # wait for it... + # sleep(3) + # + # task.unscheduled? #=> false + # task.pending? #=> false + # task.fulfilled? #=> false + # task.rejected? #=> true + # task.value #=> nil + # task.reason #=> # + # + # @example Task execution with observation + # + # observer = Class.new{ + # def update(time, value, reason) + # puts "The task completed at #{time} with value '#{value}'" + # end + # }.new + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } + # task.add_observer(observer) + # task.execute + # task.pending? #=> true + # + # # wait for it... + # sleep(3) + # + # #>> The task completed at 2013-11-07 12:26:09 -0500 with value 'What does the fox say?' + # + # @!macro monotonic_clock_warning + # + # @see Concurrent.timer + class ScheduledTask < IVar + include Comparable + + # The executor on which to execute the task. + # @!visibility private + attr_reader :executor + + # Schedule a task for execution at a specified future time. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @yield the task to be performed + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] When no block is given + # @raise [ArgumentError] When given a time that is in the past + def initialize(delay, opts = {}, &task) + raise ArgumentError.new('no block given') unless block_given? + raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0 + + super(NULL, opts, &nil) + + synchronize do + ns_set_state(:unscheduled) + @parent = opts.fetch(:timer_set, Concurrent.global_timer_set) + @args = get_arguments_from(opts) + @delay = delay.to_f + @task = task + @time = nil + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + self.observers = Collection::CopyOnNotifyObserverSet.new + end + end + + # The `delay` value given at instantiation. + # + # @return [Float] the initial delay. + def initial_delay + synchronize { @delay } + end + + # The monotonic time at which the the task is scheduled to be executed. + # + # @return [Float] the schedule time or nil if `unscheduled` + def schedule_time + synchronize { @time } + end + + # Comparator which orders by schedule time. + # + # @!visibility private + def <=>(other) + schedule_time <=> other.schedule_time + end + + # Has the task been cancelled? + # + # @return [Boolean] true if the task is in the given state else false + def cancelled? + synchronize { ns_check_state?(:cancelled) } + end + + # In the task execution in progress? + # + # @return [Boolean] true if the task is in the given state else false + def processing? + synchronize { ns_check_state?(:processing) } + end + + # Cancel this task and prevent it from executing. A task can only be + # cancelled if it is pending or unscheduled. + # + # @return [Boolean] true if successfully cancelled else false + def cancel + if compare_and_set_state(:cancelled, :pending, :unscheduled) + complete(false, nil, CancelledOperationError.new) + # To avoid deadlocks this call must occur outside of #synchronize + # Changing the state above should prevent redundant calls + @parent.send(:remove_task, self) + else + false + end + end + + # Reschedule the task using the original delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @return [Boolean] true if successfully rescheduled else false + def reset + synchronize{ ns_reschedule(@delay) } + end + + # Reschedule the task using the given delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @raise [ArgumentError] When given a time that is in the past + def reschedule(delay) + delay = delay.to_f + raise ArgumentError.new('seconds must be greater than zero') if delay < 0.0 + synchronize{ ns_reschedule(delay) } + end + + # Execute an `:unscheduled` `ScheduledTask`. Immediately sets the state to `:pending` + # and starts counting down toward execution. Does nothing if the `ScheduledTask` is + # in any state other than `:unscheduled`. + # + # @return [ScheduledTask] a reference to `self` + def execute + if compare_and_set_state(:pending, :unscheduled) + synchronize{ ns_schedule(@delay) } + end + self + end + + # Create a new `ScheduledTask` object with the given block, execute it, and return the + # `:pending` object. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @!macro executor_and_deref_options + # + # @return [ScheduledTask] the newly created `ScheduledTask` in the `:pending` state + # + # @raise [ArgumentError] if no block is given + def self.execute(delay, opts = {}, &task) + new(delay, opts, &task).execute + end + + # Execute the task. + # + # @!visibility private + def process_task + safe_execute(@task, @args) + end + + protected :set, :try_set, :fail, :complete + + protected + + # Schedule the task using the given delay and the current time. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @!visibility private + def ns_schedule(delay) + @delay = delay + @time = Concurrent.monotonic_time + @delay + @parent.send(:post_task, self) + end + + # Reschedule the task using the given delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @!visibility private + def ns_reschedule(delay) + return false unless ns_check_state?(:pending) + @parent.send(:remove_task, self) && ns_schedule(delay) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/set.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/set.rb new file mode 100644 index 00000000..eee4effd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/set.rb @@ -0,0 +1,64 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' +require 'set' + +module Concurrent + + # @!macro concurrent_set + # + # A thread-safe subclass of Set. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`. + # + # @note `a += b` is **not** a **thread-safe** operation on + # `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set` + # which is union of `a` and `b`, then it writes the union to `a`. + # The read and write are independent operations they do not form a single atomic + # operation therefore when two `+=` operations are executed concurrently updates + # may be lost. Use `#merge` instead. + # + # @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set` + + # @!macro internal_implementation_note + SetImplementation = case + when Concurrent.on_cruby? + # The CRuby implementation of Set is written in Ruby itself and is + # not thread safe for certain methods. + require 'monitor' + require 'concurrent/thread_safe/util/data_structures' + + class CRubySet < ::Set + end + + ThreadSafe::Util.make_synchronized_on_cruby CRubySet + CRubySet + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubySet < ::Set + include JRuby::Synchronized + end + + JRubySet + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubySet < ::Set + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubySet + TruffleRubySet + + else + warn 'Possibly unsupported Ruby implementation' + ::Set + end + private_constant :SetImplementation + + # @!macro concurrent_set + class Set < SetImplementation + end +end + diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/settable_struct.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/settable_struct.rb new file mode 100644 index 00000000..99b85619 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/settable_struct.rb @@ -0,0 +1,139 @@ +require 'concurrent/errors' +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An thread-safe, write-once variation of Ruby's standard `Struct`. + # Each member can have its value set at most once, either at construction + # or any time thereafter. Attempting to assign a value to a member + # that has already been set will result in a `Concurrent::ImmutabilityError`. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword + module SettableStruct + include Synchronization::AbstractStruct + + # @!macro struct_values + def values + synchronize { ns_values } + end + alias_method :to_a, :values + + # @!macro struct_values_at + def values_at(*indexes) + synchronize { ns_values_at(indexes) } + end + + # @!macro struct_inspect + def inspect + synchronize { ns_inspect } + end + alias_method :to_s, :inspect + + # @!macro struct_merge + def merge(other, &block) + synchronize { ns_merge(other, &block) } + end + + # @!macro struct_to_h + def to_h + synchronize { ns_to_h } + end + + # @!macro struct_get + def [](member) + synchronize { ns_get(member) } + end + + # @!macro struct_equality + def ==(other) + synchronize { ns_equality(other) } + end + + # @!macro struct_each + def each(&block) + return enum_for(:each) unless block_given? + synchronize { ns_each(&block) } + end + + # @!macro struct_each_pair + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + synchronize { ns_each_pair(&block) } + end + + # @!macro struct_select + def select(&block) + return enum_for(:select) unless block_given? + synchronize { ns_select(&block) } + end + + # @!macro struct_set + # + # @raise [Concurrent::ImmutabilityError] if the given member has already been set + def []=(member, value) + if member.is_a? Integer + length = synchronize { @values.length } + if member >= length + raise IndexError.new("offset #{member} too large for struct(size:#{length})") + end + synchronize do + unless @values[member].nil? + raise Concurrent::ImmutabilityError.new('struct member has already been set') + end + @values[member] = value + end + else + send("#{member}=", value) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + private + + # @!visibility private + def initialize_copy(original) + synchronize do + super(original) + ns_initialize_copy + end + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block) + members.each_with_index do |member, index| + clazz.send :remove_method, member if clazz.instance_methods.include? member + clazz.send(:define_method, member) do + synchronize { @values[index] } + end + clazz.send(:define_method, "#{member}=") do |value| + synchronize do + unless @values[index].nil? + raise Concurrent::ImmutabilityError.new('struct member has already been set') + end + @values[index] = value + end + end + end + clazz + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization.rb new file mode 100644 index 00000000..6d8cf4bd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization.rb @@ -0,0 +1,13 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lockable_object' +require 'concurrent/synchronization/condition' +require 'concurrent/synchronization/lock' + +module Concurrent + # @!visibility private + module Synchronization + end +end + diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb new file mode 100644 index 00000000..d9050b31 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb @@ -0,0 +1,102 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first +require 'concurrent/utility/monotonic_time' +require 'concurrent/synchronization/object' + +module Concurrent + module Synchronization + + # @!visibility private + class AbstractLockableObject < Synchronization::Object + + protected + + # @!macro synchronization_object_method_synchronize + # + # @yield runs the block synchronized against this object, + # equivalent of java's `synchronize(this) {}` + # @note can by made public in descendants if required by `public :synchronize` + def synchronize + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_wait_until + # + # Wait until condition is met or timeout passes, + # protects against spurious wake-ups. + # @param [Numeric, nil] timeout in seconds, `nil` means no timeout + # @yield condition to be met + # @yieldreturn [true, false] + # @return [true, false] if condition met + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def wait_until(timeout = nil, &condition) + # synchronize { ns_wait_until(timeout, &condition) } + # end + # ``` + def ns_wait_until(timeout = nil, &condition) + if timeout + wait_until = Concurrent.monotonic_time + timeout + loop do + now = Concurrent.monotonic_time + condition_result = condition.call + return condition_result if now >= wait_until || condition_result + ns_wait wait_until - now + end + else + ns_wait timeout until condition.call + true + end + end + + # @!macro synchronization_object_method_ns_wait + # + # Wait until another thread calls #signal or #broadcast, + # spurious wake-ups can happen. + # + # @param [Numeric, nil] timeout in seconds, `nil` means no timeout + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def wait(timeout = nil) + # synchronize { ns_wait(timeout) } + # end + # ``` + def ns_wait(timeout = nil) + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_signal + # + # Signal one waiting thread. + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def signal + # synchronize { ns_signal } + # end + # ``` + def ns_signal + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_broadcast + # + # Broadcast to all waiting threads. + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def broadcast + # synchronize { ns_broadcast } + # end + # ``` + def ns_broadcast + raise NotImplementedError + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb new file mode 100644 index 00000000..7cd2decf --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb @@ -0,0 +1,22 @@ +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + class AbstractObject + def initialize + # nothing to do + end + + # @!visibility private + # @abstract + def full_memory_barrier + raise NotImplementedError + end + + def self.attr_volatile(*names) + raise NotImplementedError + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb new file mode 100644 index 00000000..28816c51 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb @@ -0,0 +1,171 @@ +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + module AbstractStruct + + # @!visibility private + def initialize(*values) + super() + ns_initialize(*values) + end + + # @!macro struct_length + # + # Returns the number of struct members. + # + # @return [Fixnum] the number of struct members + def length + self.class::MEMBERS.length + end + alias_method :size, :length + + # @!macro struct_members + # + # Returns the struct members as an array of symbols. + # + # @return [Array] the struct members as an array of symbols + def members + self.class::MEMBERS.dup + end + + protected + + # @!macro struct_values + # + # @!visibility private + def ns_values + @values.dup + end + + # @!macro struct_values_at + # + # @!visibility private + def ns_values_at(indexes) + @values.values_at(*indexes) + end + + # @!macro struct_to_h + # + # @!visibility private + def ns_to_h + length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo} + end + + # @!macro struct_get + # + # @!visibility private + def ns_get(member) + if member.is_a? Integer + if member >= @values.length + raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})") + end + @values[member] + else + send(member) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + # @!macro struct_equality + # + # @!visibility private + def ns_equality(other) + self.class == other.class && self.values == other.values + end + + # @!macro struct_each + # + # @!visibility private + def ns_each + values.each{|value| yield value } + end + + # @!macro struct_each_pair + # + # @!visibility private + def ns_each_pair + @values.length.times do |index| + yield self.class::MEMBERS[index], @values[index] + end + end + + # @!macro struct_select + # + # @!visibility private + def ns_select + values.select{|value| yield value } + end + + # @!macro struct_inspect + # + # @!visibility private + def ns_inspect + struct = pr_underscore(self.class.ancestors[1]) + clazz = ((self.class.to_s =~ /^#" + end + + # @!macro struct_merge + # + # @!visibility private + def ns_merge(other, &block) + self.class.new(*self.to_h.merge(other, &block).values) + end + + # @!visibility private + def ns_initialize_copy + @values = @values.map do |val| + begin + val.clone + rescue TypeError + val + end + end + end + + # @!visibility private + def pr_underscore(clazz) + word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229 + word.gsub!(/::/, '/') + word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') + word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + word.tr!("-", "_") + word.downcase! + word + end + + # @!visibility private + def self.define_struct_class(parent, base, name, members, &block) + clazz = Class.new(base || Object) do + include parent + self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze) + def ns_initialize(*values) + raise ArgumentError.new('struct size differs') if values.length > length + @values = values.fill(nil, values.length..length-1) + end + end + unless name.nil? + begin + parent.send :remove_const, name if parent.const_defined?(name, false) + parent.const_set(name, clazz) + clazz + rescue NameError + raise NameError.new("identifier #{name} needs to be constant") + end + end + members.each_with_index do |member, index| + clazz.send :remove_method, member if clazz.instance_methods(false).include? member + clazz.send(:define_method, member) do + @values[index] + end + end + clazz.class_exec(&block) unless block.nil? + clazz.singleton_class.send :alias_method, :[], :new + clazz + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/condition.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/condition.rb new file mode 100644 index 00000000..5daa68be --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/condition.rb @@ -0,0 +1,62 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # TODO (pitr-ch 04-Dec-2016): should be in edge + class Condition < LockableObject + safe_initialization! + + # TODO (pitr 12-Sep-2015): locks two objects, improve + # TODO (pitr 26-Sep-2015): study + # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/concurrent/locks/AbstractQueuedSynchronizer.java#AbstractQueuedSynchronizer.Node + + singleton_class.send :alias_method, :private_new, :new + private_class_method :new + + def initialize(lock) + super() + @Lock = lock + end + + def wait(timeout = nil) + @Lock.synchronize { ns_wait(timeout) } + end + + def ns_wait(timeout = nil) + synchronize { super(timeout) } + end + + def wait_until(timeout = nil, &condition) + @Lock.synchronize { ns_wait_until(timeout, &condition) } + end + + def ns_wait_until(timeout = nil, &condition) + synchronize { super(timeout, &condition) } + end + + def signal + @Lock.synchronize { ns_signal } + end + + def ns_signal + synchronize { super } + end + + def broadcast + @Lock.synchronize { ns_broadcast } + end + + def ns_broadcast + synchronize { super } + end + end + + class LockableObject < LockableObjectImplementation + def new_condition + Condition.private_new(self) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb new file mode 100644 index 00000000..139e08d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb @@ -0,0 +1,29 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +module Concurrent + module Synchronization + case + when Concurrent.on_cruby? + def self.full_memory_barrier + # relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars + # https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211 + end + + when Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + def self.full_memory_barrier + JRubyAttrVolatile.full_memory_barrier + end + + when Concurrent.on_truffleruby? + def self.full_memory_barrier + TruffleRuby.full_memory_barrier + end + + else + warn 'Possibly unsupported Ruby implementation' + def self.full_memory_barrier + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb new file mode 100644 index 00000000..76930461 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb @@ -0,0 +1,15 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +module Concurrent + module Synchronization + + if Concurrent.on_jruby? + + # @!visibility private + # @!macro internal_implementation_note + class JRubyLockableObject < AbstractLockableObject + + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lock.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lock.rb new file mode 100644 index 00000000..f90e0b5f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lock.rb @@ -0,0 +1,38 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # TODO (pitr-ch 04-Dec-2016): should be in edge + class Lock < LockableObject + # TODO use JavaReentrantLock on JRuby + + public :synchronize + + def wait(timeout = nil) + synchronize { ns_wait(timeout) } + end + + public :ns_wait + + def wait_until(timeout = nil, &condition) + synchronize { ns_wait_until(timeout, &condition) } + end + + public :ns_wait_until + + def signal + synchronize { ns_signal } + end + + public :ns_signal + + def broadcast + synchronize { ns_broadcast } + end + + public :ns_broadcast + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb new file mode 100644 index 00000000..08d2ff66 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb @@ -0,0 +1,75 @@ +require 'concurrent/utility/engine' +require 'concurrent/synchronization/abstract_lockable_object' +require 'concurrent/synchronization/mutex_lockable_object' +require 'concurrent/synchronization/jruby_lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + LockableObjectImplementation = case + when Concurrent.on_cruby? + MutexLockableObject + when Concurrent.on_jruby? + JRubyLockableObject + when Concurrent.on_truffleruby? + MutexLockableObject + else + warn 'Possibly unsupported Ruby implementation' + MonitorLockableObject + end + private_constant :LockableObjectImplementation + + # Safe synchronization under any Ruby implementation. + # It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}. + # Provides a single layer which can improve its implementation over time without changes needed to + # the classes using it. Use {Synchronization::Object} not this abstract class. + # + # @note this object does not support usage together with + # [`Thread#wakeup`](http://ruby-doc.org/core/Thread.html#method-i-wakeup) + # and [`Thread#raise`](http://ruby-doc.org/core/Thread.html#method-i-raise). + # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and + # `Thread#wakeup` will not work on all platforms. + # + # @see Event implementation as an example of this class use + # + # @example simple + # class AnClass < Synchronization::Object + # def initialize + # super + # synchronize { @value = 'asd' } + # end + # + # def value + # synchronize { @value } + # end + # end + # + # @!visibility private + class LockableObject < LockableObjectImplementation + + # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing + # TODO (pitr 12-Sep-2015): we inherit too much ourselves :/ + + # @!method initialize(*args, &block) + # @!macro synchronization_object_method_initialize + + # @!method synchronize + # @!macro synchronization_object_method_synchronize + + # @!method wait_until(timeout = nil, &condition) + # @!macro synchronization_object_method_ns_wait_until + + # @!method wait(timeout = nil) + # @!macro synchronization_object_method_ns_wait + + # @!method signal + # @!macro synchronization_object_method_ns_signal + + # @!method broadcast + # @!macro synchronization_object_method_ns_broadcast + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb new file mode 100644 index 00000000..acc9745a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb @@ -0,0 +1,89 @@ +require 'concurrent/synchronization/abstract_lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + module ConditionSignalling + protected + + def ns_signal + @__Condition__.signal + self + end + + def ns_broadcast + @__Condition__.broadcast + self + end + end + + + # @!visibility private + # @!macro internal_implementation_note + class MutexLockableObject < AbstractLockableObject + include ConditionSignalling + + safe_initialization! + + def initialize + super() + @__Lock__ = ::Mutex.new + @__Condition__ = ::ConditionVariable.new + end + + def initialize_copy(other) + super + @__Lock__ = ::Mutex.new + @__Condition__ = ::ConditionVariable.new + end + + protected + + def synchronize + if @__Lock__.owned? + yield + else + @__Lock__.synchronize { yield } + end + end + + def ns_wait(timeout = nil) + @__Condition__.wait @__Lock__, timeout + self + end + end + + # @!visibility private + # @!macro internal_implementation_note + class MonitorLockableObject < AbstractLockableObject + include ConditionSignalling + + safe_initialization! + + def initialize + super() + @__Lock__ = ::Monitor.new + @__Condition__ = @__Lock__.new_cond + end + + def initialize_copy(other) + super + @__Lock__ = ::Monitor.new + @__Condition__ = @__Lock__.new_cond + end + + protected + + def synchronize # TODO may be a problem with lock.synchronize { lock.wait } + @__Lock__.synchronize { yield } + end + + def ns_wait(timeout = nil) + @__Condition__.wait timeout + self + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/object.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/object.rb new file mode 100644 index 00000000..59219070 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/object.rb @@ -0,0 +1,151 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/synchronization/safe_initialization' +require 'concurrent/synchronization/volatile' +require 'concurrent/atomic/atomic_reference' + +module Concurrent + module Synchronization + + # Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions. + # - final instance variables see {Object.safe_initialization!} + # - volatile instance variables see {Object.attr_volatile} + # - volatile instance variables see {Object.attr_atomic} + # @!visibility private + class Object < AbstractObject + include Volatile + + # TODO make it a module if possible + + # @!method self.attr_volatile(*names) + # Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with + # volatile (Java) semantic. The instance variable should be accessed only through generated methods. + # + # @param [::Array] names of the instance variables to be volatile + # @return [::Array] names of defined method names + + # Has to be called by children. + def initialize + super + __initialize_atomic_fields__ + end + + def self.safe_initialization! + extend SafeInitialization unless safe_initialization? + end + + def self.safe_initialization? + self.singleton_class < SafeInitialization + end + + # For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains + # any instance variables with CamelCase names and isn't {.safe_initialization?}. + # @raise when offend found + # @return [true] + def self.ensure_safe_initialization_when_final_fields_are_present + Object.class_eval do + def self.new(*args, &block) + object = super(*args, &block) + ensure + has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ } + if has_final_field && !safe_initialization? + raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!" + end + end + end + true + end + + # Creates methods for reading and writing to a instance variable with + # volatile (Java) semantic as {.attr_volatile} does. + # The instance variable should be accessed only through generated methods. + # This method generates following methods: `value`, `value=(new_value) #=> new_value`, + # `swap_value(new_value) #=> old_value`, + # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`. + # @param [::Array] names of the instance variables to be volatile with CAS. + # @return [::Array] names of defined method names. + # @!macro attr_atomic + # @!method $1 + # @return [Object] The $1. + # @!method $1=(new_$1) + # Set the $1. + # @return [Object] new_$1. + # @!method swap_$1(new_$1) + # Set the $1 to new_$1 and return the old $1. + # @return [Object] old $1 + # @!method compare_and_set_$1(expected_$1, new_$1) + # Sets the $1 to new_$1 if the current $1 is expected_$1 + # @return [true, false] + # @!method update_$1(&block) + # Updates the $1 using the block. + # @yield [Object] Calculate a new $1 using given (old) $1 + # @yieldparam [Object] old $1 + # @return [Object] new $1 + def self.attr_atomic(*names) + @__atomic_fields__ ||= [] + @__atomic_fields__ += names + safe_initialization! + define_initialize_atomic_fields + + names.each do |name| + ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}" + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + #{ivar}.get + end + + def #{name}=(value) + #{ivar}.set value + end + + def swap_#{name}(value) + #{ivar}.swap value + end + + def compare_and_set_#{name}(expected, value) + #{ivar}.compare_and_set expected, value + end + + def update_#{name}(&block) + #{ivar}.update(&block) + end + RUBY + end + names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] } + end + + # @param [true, false] inherited should inherited volatile with CAS fields be returned? + # @return [::Array] Returns defined volatile with CAS fields on this class. + def self.atomic_attributes(inherited = true) + @__atomic_fields__ ||= [] + ((superclass.atomic_attributes if superclass.respond_to?(:atomic_attributes) && inherited) || []) + @__atomic_fields__ + end + + # @return [true, false] is the attribute with name atomic? + def self.atomic_attribute?(name) + atomic_attributes.include? name + end + + private + + def self.define_initialize_atomic_fields + assignments = @__atomic_fields__.map do |name| + "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = Concurrent::AtomicReference.new(nil)" + end.join("\n") + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def __initialize_atomic_fields__ + super + #{assignments} + end + RUBY + end + + private_class_method :define_initialize_atomic_fields + + def __initialize_atomic_fields__ + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb new file mode 100644 index 00000000..f785e352 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb @@ -0,0 +1,36 @@ +require 'concurrent/synchronization/full_memory_barrier' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + # + # By extending this module, a class and all its children are marked to be constructed safely. Meaning that + # all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures + # same behaviour as Java's final fields. + # + # Due to using Kernel#extend, the module is not included again if already present in the ancestors, + # which avoids extra overhead. + # + # @example + # class AClass < Concurrent::Synchronization::Object + # extend Concurrent::Synchronization::SafeInitialization + # + # def initialize + # @AFinalValue = 'value' # published safely, #foo will never return nil + # end + # + # def foo + # @AFinalValue + # end + # end + module SafeInitialization + def new(*args, &block) + super(*args, &block) + ensure + Concurrent::Synchronization.full_memory_barrier + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/volatile.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/volatile.rb new file mode 100644 index 00000000..46e8ba6a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/synchronization/volatile.rb @@ -0,0 +1,101 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first +require 'concurrent/utility/engine' +require 'concurrent/synchronization/full_memory_barrier' + +module Concurrent + module Synchronization + + # Volatile adds the attr_volatile class method when included. + # + # @example + # class Foo + # include Concurrent::Synchronization::Volatile + # + # attr_volatile :bar + # + # def initialize + # self.bar = 1 + # end + # end + # + # foo = Foo.new + # foo.bar + # => 1 + # foo.bar = 2 + # => 2 + # + # @!visibility private + module Volatile + def self.included(base) + base.extend(ClassMethods) + end + + def full_memory_barrier + Synchronization.full_memory_barrier + end + + module ClassMethods + if Concurrent.on_cruby? + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + #{ivar} + end + + def #{name}=(value) + #{ivar} = value + end + RUBY + end + names.map { |n| [n, :"#{n}="] }.flatten + end + + elsif Concurrent.on_jruby? + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + ::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_get_volatile(self, :#{ivar}) + end + + def #{name}=(value) + ::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_set_volatile(self, :#{ivar}, value) + end + RUBY + + end + names.map { |n| [n, :"#{n}="] }.flatten + end + + else + warn 'Possibly unsupported Ruby implementation' unless Concurrent.on_truffleruby? + + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + ::Concurrent::Synchronization.full_memory_barrier + #{ivar} + end + + def #{name}=(value) + #{ivar} = value + ::Concurrent::Synchronization.full_memory_barrier + end + RUBY + end + + names.map { |n| [n, :"#{n}="] }.flatten + end + end + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb new file mode 100644 index 00000000..019d8438 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb @@ -0,0 +1,47 @@ +require 'delegate' +require 'monitor' + +module Concurrent + # This class provides a trivial way to synchronize all calls to a given object + # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls + # around the delegated `#send`. Example: + # + # array = [] # not thread-safe on many impls + # array = SynchronizedDelegator.new([]) # thread-safe + # + # A simple `Monitor` provides a very coarse-grained way to synchronize a given + # object, in that it will cause synchronization for methods that have no need + # for it, but this is a trivial way to get thread-safety where none may exist + # currently on some implementations. + # + # This class is currently being considered for inclusion into stdlib, via + # https://bugs.ruby-lang.org/issues/8556 + # + # @!visibility private + class SynchronizedDelegator < SimpleDelegator + def setup + @old_abort = Thread.abort_on_exception + Thread.abort_on_exception = true + end + + def teardown + Thread.abort_on_exception = @old_abort + end + + def initialize(obj) + __setobj__(obj) + @monitor = Monitor.new + end + + def method_missing(method, *args, &block) + monitor = @monitor + begin + monitor.enter + super + ensure + monitor.exit + end + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util.rb new file mode 100644 index 00000000..c67084a2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util.rb @@ -0,0 +1,16 @@ +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # TODO (pitr-ch 15-Oct-2016): migrate to Utility::NativeInteger + FIXNUM_BIT_SIZE = (0.size * 8) - 2 + MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1 + # TODO (pitr-ch 15-Oct-2016): migrate to Utility::ProcessorCounter + CPU_COUNT = 16 # is there a way to determine this? + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb new file mode 100644 index 00000000..852b403b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb @@ -0,0 +1,74 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/thread_safe/util/striped64' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A Ruby port of the Doug Lea's jsr166e.LongAdder class version 1.8 + # available in public domain. + # + # Original source code available here: + # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8 + # + # One or more variables that together maintain an initially zero + # sum. When updates (method +add+) are contended across threads, + # the set of variables may grow dynamically to reduce contention. + # Method +sum+ returns the current total combined across the + # variables maintaining the sum. + # + # This class is usually preferable to single +Atomic+ reference when + # multiple threads update a common sum that is used for purposes such + # as collecting statistics, not for fine-grained synchronization + # control. Under low update contention, the two classes have similar + # characteristics. But under high contention, expected throughput of + # this class is significantly higher, at the expense of higher space + # consumption. + # + # @!visibility private + class Adder < Striped64 + # Adds the given value. + def add(x) + if (current_cells = cells) || !cas_base_computed {|current_base| current_base + x} + was_uncontended = true + hash = hash_code + unless current_cells && (cell = current_cells.volatile_get_by_hash(hash)) && (was_uncontended = cell.cas_computed {|current_value| current_value + x}) + retry_update(x, hash, was_uncontended) {|current_value| current_value + x} + end + end + end + + def increment + add(1) + end + + def decrement + add(-1) + end + + # Returns the current sum. The returned value is _NOT_ an + # atomic snapshot: Invocation in the absence of concurrent + # updates returns an accurate result, but concurrent updates that + # occur while the sum is being calculated might not be + # incorporated. + def sum + x = base + if current_cells = cells + current_cells.each do |cell| + x += cell.value if cell + end + end + x + end + + def reset + internal_reset(0) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb new file mode 100644 index 00000000..01eb98f4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb @@ -0,0 +1,52 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/utility/engine' + +# Shim for TruffleRuby.synchronized +if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized) + module TruffleRuby + def self.synchronized(object, &block) + Truffle::System.synchronized(object, &block) + end + end +end + +module Concurrent + module ThreadSafe + module Util + def self.make_synchronized_on_cruby(klass) + klass.class_eval do + def initialize(*args, &block) + @_monitor = Monitor.new + super + end + + def initialize_copy(other) + # make sure a copy is not sharing a monitor with the original object! + @_monitor = Monitor.new + super + end + end + + klass.superclass.instance_methods(false).each do |method| + klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + monitor = @_monitor + monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.") + monitor.synchronize { super } + end + RUBY + end + end + + def self.make_synchronized_on_truffleruby(klass) + klass.superclass.instance_methods(false).each do |method| + klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args, &block) + TruffleRuby.synchronized(self) { super(*args, &block) } + end + RUBY + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb new file mode 100644 index 00000000..b54be39c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb @@ -0,0 +1,38 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/tuple' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # @!visibility private + class PowerOfTwoTuple < Concurrent::Tuple + + def initialize(size) + raise ArgumentError, "size must be a power of 2 (#{size.inspect} provided)" unless size > 0 && size & (size - 1) == 0 + super(size) + end + + def hash_to_index(hash) + (size - 1) & hash + end + + def volatile_get_by_hash(hash) + volatile_get(hash_to_index(hash)) + end + + def volatile_set_by_hash(hash, value) + volatile_set(hash_to_index(hash), value) + end + + def next_in_size_table + self.class.new(size << 1) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb new file mode 100644 index 00000000..4169c3d3 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb @@ -0,0 +1,246 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/thread_safe/util/power_of_two_tuple' +require 'concurrent/thread_safe/util/volatile' +require 'concurrent/thread_safe/util/xor_shift_random' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A Ruby port of the Doug Lea's jsr166e.Striped64 class version 1.6 + # available in public domain. + # + # Original source code available here: + # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.6 + # + # Class holding common representation and mechanics for classes supporting + # dynamic striping on 64bit values. + # + # This class maintains a lazily-initialized table of atomically updated + # variables, plus an extra +base+ field. The table size is a power of two. + # Indexing uses masked per-thread hash codes. Nearly all methods on this + # class are private, accessed directly by subclasses. + # + # Table entries are of class +Cell+; a variant of AtomicLong padded to + # reduce cache contention on most processors. Padding is overkill for most + # Atomics because they are usually irregularly scattered in memory and thus + # don't interfere much with each other. But Atomic objects residing in + # arrays will tend to be placed adjacent to each other, and so will most + # often share cache lines (with a huge negative performance impact) without + # this precaution. + # + # In part because +Cell+s are relatively large, we avoid creating them until + # they are needed. When there is no contention, all updates are made to the + # +base+ field. Upon first contention (a failed CAS on +base+ update), the + # table is initialized to size 2. The table size is doubled upon further + # contention until reaching the nearest power of two greater than or equal + # to the number of CPUS. Table slots remain empty (+nil+) until they are + # needed. + # + # A single spinlock (+busy+) is used for initializing and resizing the + # table, as well as populating slots with new +Cell+s. There is no need for + # a blocking lock: When the lock is not available, threads try other slots + # (or the base). During these retries, there is increased contention and + # reduced locality, which is still better than alternatives. + # + # Per-thread hash codes are initialized to random values. Contention and/or + # table collisions are indicated by failed CASes when performing an update + # operation (see method +retry_update+). Upon a collision, if the table size + # is less than the capacity, it is doubled in size unless some other thread + # holds the lock. If a hashed slot is empty, and lock is available, a new + # +Cell+ is created. Otherwise, if the slot exists, a CAS is tried. Retries + # proceed by "double hashing", using a secondary hash (XorShift) to try to + # find a free slot. + # + # The table size is capped because, when there are more threads than CPUs, + # supposing that each thread were bound to a CPU, there would exist a + # perfect hash function mapping threads to slots that eliminates collisions. + # When we reach capacity, we search for this mapping by randomly varying the + # hash codes of colliding threads. Because search is random, and collisions + # only become known via CAS failures, convergence can be slow, and because + # threads are typically not bound to CPUS forever, may not occur at all. + # However, despite these limitations, observed contention rates are + # typically low in these cases. + # + # It is possible for a +Cell+ to become unused when threads that once hashed + # to it terminate, as well as in the case where doubling the table causes no + # thread to hash to it under expanded mask. We do not try to detect or + # remove such cells, under the assumption that for long-running instances, + # observed contention levels will recur, so the cells will eventually be + # needed again; and for short-lived ones, it does not matter. + # + # @!visibility private + class Striped64 + + # Padded variant of AtomicLong supporting only raw accesses plus CAS. + # The +value+ field is placed between pads, hoping that the JVM doesn't + # reorder them. + # + # Optimisation note: It would be possible to use a release-only + # form of CAS here, if it were provided. + # + # @!visibility private + class Cell < Concurrent::AtomicReference + + alias_method :cas, :compare_and_set + + def cas_computed + cas(current_value = value, yield(current_value)) + end + + # @!visibility private + def self.padding + # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot + # TODO (pitr-ch 28-Jul-2018): the padding instance vars may not be created + # hide from yardoc in a method + attr_reader :padding_0, :padding_1, :padding_2, :padding_3, :padding_4, :padding_5, :padding_6, :padding_7, :padding_8, :padding_9, :padding_10, :padding_11 + end + padding + end + + extend Volatile + attr_volatile :cells, # Table of cells. When non-null, size is a power of 2. + :base, # Base value, used mainly when there is no contention, but also as a fallback during table initialization races. Updated via CAS. + :busy # Spinlock (locked via CAS) used when resizing and/or creating Cells. + + alias_method :busy?, :busy + + def initialize + super() + self.busy = false + self.base = 0 + end + + # Handles cases of updates involving initialization, resizing, + # creating new Cells, and/or contention. See above for + # explanation. This method suffers the usual non-modularity + # problems of optimistic retry code, relying on rechecked sets of + # reads. + # + # Arguments: + # [+x+] + # the value + # [+hash_code+] + # hash code used + # [+x+] + # false if CAS failed before call + def retry_update(x, hash_code, was_uncontended) # :yields: current_value + hash = hash_code + collided = false # True if last slot nonempty + while true + if current_cells = cells + if !(cell = current_cells.volatile_get_by_hash(hash)) + if busy? + collided = false + else # Try to attach new Cell + if try_to_install_new_cell(Cell.new(x), hash) # Optimistically create and try to insert new cell + break + else + redo # Slot is now non-empty + end + end + elsif !was_uncontended # CAS already known to fail + was_uncontended = true # Continue after rehash + elsif cell.cas_computed {|current_value| yield current_value} + break + elsif current_cells.size >= CPU_COUNT || cells != current_cells # At max size or stale + collided = false + elsif collided && expand_table_unless_stale(current_cells) + collided = false + redo # Retry with expanded table + else + collided = true + end + hash = XorShiftRandom.xorshift(hash) + + elsif try_initialize_cells(x, hash) || cas_base_computed {|current_base| yield current_base} + break + end + end + self.hash_code = hash + end + + private + # Static per-thread hash code key. Shared across all instances to + # reduce Thread locals pollution and because adjustments due to + # collisions in one table are likely to be appropriate for + # others. + THREAD_LOCAL_KEY = "#{name}.hash_code".to_sym + + # A thread-local hash code accessor. The code is initially + # random, but may be set to a different value upon collisions. + def hash_code + Thread.current[THREAD_LOCAL_KEY] ||= XorShiftRandom.get + end + + def hash_code=(hash) + Thread.current[THREAD_LOCAL_KEY] = hash + end + + # Sets base and all +cells+ to the given value. + def internal_reset(initial_value) + current_cells = cells + self.base = initial_value + if current_cells + current_cells.each do |cell| + cell.value = initial_value if cell + end + end + end + + def cas_base_computed + cas_base(current_base = base, yield(current_base)) + end + + def free? + !busy? + end + + def try_initialize_cells(x, hash) + if free? && !cells + try_in_busy do + unless cells # Recheck under lock + new_cells = PowerOfTwoTuple.new(2) + new_cells.volatile_set_by_hash(hash, Cell.new(x)) + self.cells = new_cells + end + end + end + end + + def expand_table_unless_stale(current_cells) + try_in_busy do + if current_cells == cells # Recheck under lock + new_cells = current_cells.next_in_size_table + current_cells.each_with_index {|x, i| new_cells.volatile_set(i, x)} + self.cells = new_cells + end + end + end + + def try_to_install_new_cell(new_cell, hash) + try_in_busy do + # Recheck under lock + if (current_cells = cells) && !current_cells.volatile_get(i = current_cells.hash_to_index(hash)) + current_cells.volatile_set(i, new_cell) + end + end + end + + def try_in_busy + if cas_busy(false, true) + begin + yield + ensure + self.busy = false + end + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb new file mode 100644 index 00000000..cdac2a39 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb @@ -0,0 +1,75 @@ +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # @!visibility private + module Volatile + + # Provides +volatile+ (in the JVM's sense) attribute accessors implemented + # atop of +Concurrent::AtomicReference+. + # + # Usage: + # class Foo + # extend Concurrent::ThreadSafe::Util::Volatile + # attr_volatile :foo, :bar + # + # def initialize(bar) + # super() # must super() into parent initializers before using the volatile attribute accessors + # self.bar = bar + # end + # + # def hello + # my_foo = foo # volatile read + # self.foo = 1 # volatile write + # cas_foo(1, 2) # => true | a strong CAS + # end + # end + def attr_volatile(*attr_names) + return if attr_names.empty? + include(Module.new do + atomic_ref_setup = attr_names.map {|attr_name| "@__#{attr_name} = Concurrent::AtomicReference.new"} + initialize_copy_setup = attr_names.zip(atomic_ref_setup).map do |attr_name, ref_setup| + "#{ref_setup}(other.instance_variable_get(:@__#{attr_name}).get)" + end + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def initialize(*) + super + #{atomic_ref_setup.join('; ')} + end + + def initialize_copy(other) + super + #{initialize_copy_setup.join('; ')} + end + RUBY_EVAL + + attr_names.each do |attr_name| + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{attr_name} + @__#{attr_name}.get + end + + def #{attr_name}=(value) + @__#{attr_name}.set(value) + end + + def compare_and_set_#{attr_name}(old_value, new_value) + @__#{attr_name}.compare_and_set(old_value, new_value) + end + RUBY_EVAL + + alias_method :"cas_#{attr_name}", :"compare_and_set_#{attr_name}" + alias_method :"lazy_set_#{attr_name}", :"#{attr_name}=" + end + end) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb new file mode 100644 index 00000000..c231d182 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb @@ -0,0 +1,50 @@ +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A xorshift random number (positive +Fixnum+s) generator, provides + # reasonably cheap way to generate thread local random numbers without + # contending for the global +Kernel.rand+. + # + # Usage: + # x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed + # while true + # if (x = XorShiftRandom.xorshift).odd? # thread-locally generate a next random number + # do_something_at_random + # end + # end + module XorShiftRandom + extend self + MAX_XOR_SHIFTABLE_INT = MAX_INT - 1 + + # Generates an initial non-zero positive +Fixnum+ via +Kernel.rand+. + def get + Kernel.rand(MAX_XOR_SHIFTABLE_INT) + 1 # 0 can't be xorshifted + end + + # xorshift based on: http://www.jstatsoft.org/v08/i14/paper + if 0.size == 4 + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (3,1,14) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 3 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 14 + end + else + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (1,1,54) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 1 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 54 + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/timer_task.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/timer_task.rb new file mode 100644 index 00000000..dd2037f6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/timer_task.rb @@ -0,0 +1,361 @@ +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/concern/dereferenceable' +require 'concurrent/concern/observable' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/scheduled_task' + +module Concurrent + + # A very common concurrency pattern is to run a thread that performs a task at + # regular intervals. The thread that performs the task sleeps for the given + # interval then wakes up and performs the task. Lather, rinse, repeat... This + # pattern causes two problems. First, it is difficult to test the business + # logic of the task because the task itself is tightly coupled with the + # concurrency logic. Second, an exception raised while performing the task can + # cause the entire thread to abend. In a long-running application where the + # task thread is intended to run for days/weeks/years a crashed task thread + # can pose a significant problem. `TimerTask` alleviates both problems. + # + # When a `TimerTask` is launched it starts a thread for monitoring the + # execution interval. The `TimerTask` thread does not perform the task, + # however. Instead, the TimerTask launches the task on a separate thread. + # Should the task experience an unrecoverable crash only the task thread will + # crash. This makes the `TimerTask` very fault tolerant. Additionally, the + # `TimerTask` thread can respond to the success or failure of the task, + # performing logging or ancillary operations. + # + # One other advantage of `TimerTask` is that it forces the business logic to + # be completely decoupled from the concurrency logic. The business logic can + # be tested separately then passed to the `TimerTask` for scheduling and + # running. + # + # A `TimerTask` supports two different types of interval calculations. + # A fixed delay will always wait the same amount of time between the + # completion of one task and the start of the next. A fixed rate will + # attempt to maintain a constant rate of execution regardless of the + # duration of the task. For example, if a fixed rate task is scheduled + # to run every 60 seconds but the task itself takes 10 seconds to + # complete, the next task will be scheduled to run 50 seconds after + # the start of the previous task. If the task takes 70 seconds to + # complete, the next task will be start immediately after the previous + # task completes. Tasks will not be executed concurrently. + # + # In some cases it may be necessary for a `TimerTask` to affect its own + # execution cycle. To facilitate this, a reference to the TimerTask instance + # is passed as an argument to the provided block every time the task is + # executed. + # + # The `TimerTask` class includes the `Dereferenceable` mixin module so the + # result of the last execution is always available via the `#value` method. + # Dereferencing options can be passed to the `TimerTask` during construction or + # at any later time using the `#set_deref_options` method. + # + # `TimerTask` supports notification through the Ruby standard library + # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html + # Observable} module. On execution the `TimerTask` will notify the observers + # with three arguments: time of execution, the result of the block (or nil on + # failure), and any raised exceptions (or nil on success). + # + # @!macro copy_options + # + # @example Basic usage + # task = Concurrent::TimerTask.new{ puts 'Boom!' } + # task.execute + # + # task.execution_interval #=> 60 (default) + # + # # wait 60 seconds... + # #=> 'Boom!' + # + # task.shutdown #=> true + # + # @example Configuring `:execution_interval` + # task = Concurrent::TimerTask.new(execution_interval: 5) do + # puts 'Boom!' + # end + # + # task.execution_interval #=> 5 + # + # @example Immediate execution with `:run_now` + # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' } + # task.execute + # + # #=> 'Boom!' + # + # @example Configuring `:interval_type` with either :fixed_delay or :fixed_rate, default is :fixed_delay + # task = Concurrent::TimerTask.new(execution_interval: 5, interval_type: :fixed_rate) do + # puts 'Boom!' + # end + # task.interval_type #=> :fixed_rate + # + # @example Last `#value` and `Dereferenceable` mixin + # task = Concurrent::TimerTask.new( + # dup_on_deref: true, + # execution_interval: 5 + # ){ Time.now } + # + # task.execute + # Time.now #=> 2013-11-07 18:06:50 -0500 + # sleep(10) + # task.value #=> 2013-11-07 18:06:55 -0500 + # + # @example Controlling execution from within the block + # timer_task = Concurrent::TimerTask.new(execution_interval: 1) do |task| + # task.execution_interval.to_i.times{ print 'Boom! ' } + # print "\n" + # task.execution_interval += 1 + # if task.execution_interval > 5 + # puts 'Stopping...' + # task.shutdown + # end + # end + # + # timer_task.execute + # #=> Boom! + # #=> Boom! Boom! + # #=> Boom! Boom! Boom! + # #=> Boom! Boom! Boom! Boom! + # #=> Boom! Boom! Boom! Boom! Boom! + # #=> Stopping... + # + # @example Observation + # class TaskObserver + # def update(time, result, ex) + # if result + # print "(#{time}) Execution successfully returned #{result}\n" + # else + # print "(#{time}) Execution failed with error #{ex}\n" + # end + # end + # end + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ 42 } + # task.add_observer(TaskObserver.new) + # task.execute + # sleep 4 + # + # #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42 + # #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42 + # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42 + # task.shutdown + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep } + # task.add_observer(TaskObserver.new) + # task.execute + # + # #=> (2013-10-13 19:07:25 -0400) Execution timed out + # #=> (2013-10-13 19:07:27 -0400) Execution timed out + # #=> (2013-10-13 19:07:29 -0400) Execution timed out + # task.shutdown + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ raise StandardError } + # task.add_observer(TaskObserver.new) + # task.execute + # + # #=> (2013-10-13 19:09:37 -0400) Execution failed with error StandardError + # #=> (2013-10-13 19:09:38 -0400) Execution failed with error StandardError + # #=> (2013-10-13 19:09:39 -0400) Execution failed with error StandardError + # task.shutdown + # + # @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html + # @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html + class TimerTask < RubyExecutorService + include Concern::Dereferenceable + include Concern::Observable + + # Default `:execution_interval` in seconds. + EXECUTION_INTERVAL = 60 + + # Maintain the interval between the end of one execution and the start of the next execution. + FIXED_DELAY = :fixed_delay + + # Maintain the interval between the start of one execution and the start of the next. + # If execution time exceeds the interval, the next execution will start immediately + # after the previous execution finishes. Executions will not run concurrently. + FIXED_RATE = :fixed_rate + + # Default `:interval_type` + DEFAULT_INTERVAL_TYPE = FIXED_DELAY + + # Create a new TimerTask with the given task and configuration. + # + # @!macro timer_task_initialize + # @param [Hash] opts the options defining task execution. + # @option opts [Float] :execution_interval number of seconds between + # task executions (default: EXECUTION_INTERVAL) + # @option opts [Boolean] :run_now Whether to run the task immediately + # upon instantiation or to wait until the first # execution_interval + # has passed (default: false) + # @options opts [Symbol] :interval_type method to calculate the interval + # between executions, can be either :fixed_rate or :fixed_delay. + # (default: :fixed_delay) + # @option opts [Executor] executor, default is `global_io_executor` + # + # @!macro deref_options + # + # @raise ArgumentError when no block is given. + # + # @yield to the block after :execution_interval seconds have passed since + # the last yield + # @yieldparam task a reference to the `TimerTask` instance so that the + # block can control its own lifecycle. Necessary since `self` will + # refer to the execution context of the block rather than the running + # `TimerTask`. + # + # @return [TimerTask] the new `TimerTask` + def initialize(opts = {}, &task) + raise ArgumentError.new('no block given') unless block_given? + super + set_deref_options opts + end + + # Is the executor running? + # + # @return [Boolean] `true` when running, `false` when shutting down or shutdown + def running? + @running.true? + end + + # Execute a previously created `TimerTask`. + # + # @return [TimerTask] a reference to `self` + # + # @example Instance and execute in separate steps + # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" } + # task.running? #=> false + # task.execute + # task.running? #=> true + # + # @example Instance and execute in one line + # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" }.execute + # task.running? #=> true + def execute + synchronize do + if @running.false? + @running.make_true + schedule_next_task(@run_now ? 0 : @execution_interval) + end + end + self + end + + # Create and execute a new `TimerTask`. + # + # @!macro timer_task_initialize + # + # @example + # task = Concurrent::TimerTask.execute(execution_interval: 10){ print "Hello World\n" } + # task.running? #=> true + def self.execute(opts = {}, &task) + TimerTask.new(opts, &task).execute + end + + # @!attribute [rw] execution_interval + # @return [Fixnum] Number of seconds after the task completes before the + # task is performed again. + def execution_interval + synchronize { @execution_interval } + end + + # @!attribute [rw] execution_interval + # @return [Fixnum] Number of seconds after the task completes before the + # task is performed again. + def execution_interval=(value) + if (value = value.to_f) <= 0.0 + raise ArgumentError.new('must be greater than zero') + else + synchronize { @execution_interval = value } + end + end + + # @!attribute [r] interval_type + # @return [Symbol] method to calculate the interval between executions + attr_reader :interval_type + + # @!attribute [rw] timeout_interval + # @return [Fixnum] Number of seconds the task can run before it is + # considered to have failed. + def timeout_interval + warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly' + end + + # @!attribute [rw] timeout_interval + # @return [Fixnum] Number of seconds the task can run before it is + # considered to have failed. + def timeout_interval=(value) + warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly' + end + + private :post, :<< + + private + + def ns_initialize(opts, &task) + set_deref_options(opts) + + self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL + if opts[:interval_type] && ![FIXED_DELAY, FIXED_RATE].include?(opts[:interval_type]) + raise ArgumentError.new('interval_type must be either :fixed_delay or :fixed_rate') + end + if opts[:timeout] || opts[:timeout_interval] + warn 'TimeTask timeouts are now ignored as these were not able to be implemented correctly' + end + + @run_now = opts[:now] || opts[:run_now] + @interval_type = opts[:interval_type] || DEFAULT_INTERVAL_TYPE + @task = Concurrent::SafeTaskExecutor.new(task) + @executor = opts[:executor] || Concurrent.global_io_executor + @running = Concurrent::AtomicBoolean.new(false) + @value = nil + + self.observers = Collection::CopyOnNotifyObserverSet.new + end + + # @!visibility private + def ns_shutdown_execution + @running.make_false + super + end + + # @!visibility private + def ns_kill_execution + @running.make_false + super + end + + # @!visibility private + def schedule_next_task(interval = execution_interval) + ScheduledTask.execute(interval, executor: @executor, args: [Concurrent::Event.new], &method(:execute_task)) + nil + end + + # @!visibility private + def execute_task(completion) + return nil unless @running.true? + start_time = Concurrent.monotonic_time + _success, value, reason = @task.execute(self) + if completion.try? + self.value = value + schedule_next_task(calculate_next_interval(start_time)) + time = Time.now + observers.notify_observers do + [time, self.value, reason] + end + end + nil + end + + # @!visibility private + def calculate_next_interval(start_time) + if @interval_type == FIXED_RATE + run_time = Concurrent.monotonic_time - start_time + [execution_interval - run_time, 0].max + else # FIXED_DELAY + execution_interval + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tuple.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tuple.rb new file mode 100644 index 00000000..56212cfd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tuple.rb @@ -0,0 +1,82 @@ +require 'concurrent/atomic/atomic_reference' + +module Concurrent + + # A fixed size array with volatile (synchronized, thread safe) getters/setters. + # Mixes in Ruby's `Enumerable` module for enhanced search, sort, and traversal. + # + # @example + # tuple = Concurrent::Tuple.new(16) + # + # tuple.set(0, :foo) #=> :foo | volatile write + # tuple.get(0) #=> :foo | volatile read + # tuple.compare_and_set(0, :foo, :bar) #=> true | strong CAS + # tuple.cas(0, :foo, :baz) #=> false | strong CAS + # tuple.get(0) #=> :bar | volatile read + # + # @see https://en.wikipedia.org/wiki/Tuple Tuple entry at Wikipedia + # @see http://www.erlang.org/doc/reference_manual/data_types.html#id70396 Erlang Tuple + # @see http://ruby-doc.org/core-2.2.2/Enumerable.html Enumerable + class Tuple + include Enumerable + + # The (fixed) size of the tuple. + attr_reader :size + + # Create a new tuple of the given size. + # + # @param [Integer] size the number of elements in the tuple + def initialize(size) + @size = size + @tuple = tuple = ::Array.new(size) + i = 0 + while i < size + tuple[i] = Concurrent::AtomicReference.new + i += 1 + end + end + + # Get the value of the element at the given index. + # + # @param [Integer] i the index from which to retrieve the value + # @return [Object] the value at the given index or nil if the index is out of bounds + def get(i) + return nil if i >= @size || i < 0 + @tuple[i].get + end + alias_method :volatile_get, :get + + # Set the element at the given index to the given value + # + # @param [Integer] i the index for the element to set + # @param [Object] value the value to set at the given index + # + # @return [Object] the new value of the element at the given index or nil if the index is out of bounds + def set(i, value) + return nil if i >= @size || i < 0 + @tuple[i].set(value) + end + alias_method :volatile_set, :set + + # Set the value at the given index to the new value if and only if the current + # value matches the given old value. + # + # @param [Integer] i the index for the element to set + # @param [Object] old_value the value to compare against the current value + # @param [Object] new_value the value to set at the given index + # + # @return [Boolean] true if the value at the given element was set else false + def compare_and_set(i, old_value, new_value) + return false if i >= @size || i < 0 + @tuple[i].compare_and_set(old_value, new_value) + end + alias_method :cas, :compare_and_set + + # Calls the given block once for each element in self, passing that element as a parameter. + # + # @yieldparam [Object] ref the `Concurrent::AtomicReference` object at the current index + def each + @tuple.each {|ref| yield ref.get} + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tvar.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tvar.rb new file mode 100644 index 00000000..5d02ef09 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/tvar.rb @@ -0,0 +1,222 @@ +require 'set' +require 'concurrent/synchronization/object' + +module Concurrent + + # A `TVar` is a transactional variable - a single-element container that + # is used as part of a transaction - see `Concurrent::atomically`. + # + # @!macro thread_safe_variable_comparison + # + # {include:file:docs-source/tvar.md} + class TVar < Synchronization::Object + safe_initialization! + + # Create a new `TVar` with an initial value. + def initialize(value) + @value = value + @lock = Mutex.new + end + + # Get the value of a `TVar`. + def value + Concurrent::atomically do + Transaction::current.read(self) + end + end + + # Set the value of a `TVar`. + def value=(value) + Concurrent::atomically do + Transaction::current.write(self, value) + end + end + + # @!visibility private + def unsafe_value # :nodoc: + @value + end + + # @!visibility private + def unsafe_value=(value) # :nodoc: + @value = value + end + + # @!visibility private + def unsafe_lock # :nodoc: + @lock + end + + end + + # Run a block that reads and writes `TVar`s as a single atomic transaction. + # With respect to the value of `TVar` objects, the transaction is atomic, in + # that it either happens or it does not, consistent, in that the `TVar` + # objects involved will never enter an illegal state, and isolated, in that + # transactions never interfere with each other. You may recognise these + # properties from database transactions. + # + # There are some very important and unusual semantics that you must be aware of: + # + # * Most importantly, the block that you pass to atomically may be executed + # more than once. In most cases your code should be free of + # side-effects, except for via TVar. + # + # * If an exception escapes an atomically block it will abort the transaction. + # + # * It is undefined behaviour to use callcc or Fiber with atomically. + # + # * If you create a new thread within an atomically, it will not be part of + # the transaction. Creating a thread counts as a side-effect. + # + # Transactions within transactions are flattened to a single transaction. + # + # @example + # a = new TVar(100_000) + # b = new TVar(100) + # + # Concurrent::atomically do + # a.value -= 10 + # b.value += 10 + # end + def atomically + raise ArgumentError.new('no block given') unless block_given? + + # Get the current transaction + + transaction = Transaction::current + + # Are we not already in a transaction (not nested)? + + if transaction.nil? + # New transaction + + begin + # Retry loop + + loop do + + # Create a new transaction + + transaction = Transaction.new + Transaction::current = transaction + + # Run the block, aborting on exceptions + + begin + result = yield + rescue Transaction::AbortError => e + transaction.abort + result = Transaction::ABORTED + rescue Transaction::LeaveError => e + transaction.abort + break result + rescue => e + transaction.abort + raise e + end + # If we can commit, break out of the loop + + if result != Transaction::ABORTED + if transaction.commit + break result + end + end + end + ensure + # Clear the current transaction + + Transaction::current = nil + end + else + # Nested transaction - flatten it and just run the block + + yield + end + end + + # Abort a currently running transaction - see `Concurrent::atomically`. + def abort_transaction + raise Transaction::AbortError.new + end + + # Leave a transaction without committing or aborting - see `Concurrent::atomically`. + def leave_transaction + raise Transaction::LeaveError.new + end + + module_function :atomically, :abort_transaction, :leave_transaction + + private + + # @!visibility private + class Transaction + + ABORTED = ::Object.new + + OpenEntry = Struct.new(:value, :modified) + + AbortError = Class.new(StandardError) + LeaveError = Class.new(StandardError) + + def initialize + @open_tvars = {} + end + + def read(tvar) + entry = open(tvar) + entry.value + end + + def write(tvar, value) + entry = open(tvar) + entry.modified = true + entry.value = value + end + + def open(tvar) + entry = @open_tvars[tvar] + + unless entry + unless tvar.unsafe_lock.try_lock + Concurrent::abort_transaction + end + + entry = OpenEntry.new(tvar.unsafe_value, false) + @open_tvars[tvar] = entry + end + + entry + end + + def abort + unlock + end + + def commit + @open_tvars.each do |tvar, entry| + if entry.modified + tvar.unsafe_value = entry.value + end + end + + unlock + end + + def unlock + @open_tvars.each_key do |tvar| + tvar.unsafe_lock.unlock + end + end + + def self.current + Thread.current[:current_tvar_transaction] + end + + def self.current=(transaction) + Thread.current[:current_tvar_transaction] = transaction + end + + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/engine.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/engine.rb new file mode 100644 index 00000000..0c574b2a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/engine.rb @@ -0,0 +1,45 @@ +module Concurrent + # @!visibility private + module Utility + + # @!visibility private + module EngineDetector + def on_cruby? + RUBY_ENGINE == 'ruby' + end + + def on_jruby? + RUBY_ENGINE == 'jruby' + end + + def on_truffleruby? + RUBY_ENGINE == 'truffleruby' + end + + def on_windows? + !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/).nil? + end + + def on_osx? + !(RbConfig::CONFIG['host_os'] =~ /darwin|mac os/).nil? + end + + def on_linux? + !(RbConfig::CONFIG['host_os'] =~ /linux/).nil? + end + + def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch) + result = (version.split('.').map(&:to_i) <=> [major, minor, patch]) + comparisons = { :== => [0], + :>= => [1, 0], + :<= => [-1, 0], + :> => [1], + :< => [-1] } + comparisons.fetch(comparison).include? result + end + end + end + + # @!visibility private + extend Utility::EngineDetector +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb new file mode 100644 index 00000000..1c987d8a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb @@ -0,0 +1,19 @@ +module Concurrent + + # @!macro monotonic_get_time + # + # Returns the current time as tracked by the application monotonic clock. + # + # @param [Symbol] unit the time unit to be returned, can be either + # :float_second, :float_millisecond, :float_microsecond, :second, + # :millisecond, :microsecond, or :nanosecond default to :float_second. + # + # @return [Float] The current monotonic time since some unspecified + # starting point + # + # @!macro monotonic_clock_warning + def monotonic_time(unit = :float_second) + Process.clock_gettime(Process::CLOCK_MONOTONIC, unit) + end + module_function :monotonic_time +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb new file mode 100644 index 00000000..bf7bab35 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb @@ -0,0 +1,77 @@ +require 'concurrent/utility/engine' +# Synchronization::AbstractObject must be defined before loading the extension +require 'concurrent/synchronization/abstract_object' + +module Concurrent + # @!visibility private + module Utility + # @!visibility private + module NativeExtensionLoader + + def allow_c_extensions? + Concurrent.on_cruby? + end + + def c_extensions_loaded? + defined?(@c_extensions_loaded) && @c_extensions_loaded + end + + def load_native_extensions + if Concurrent.on_cruby? && !c_extensions_loaded? + ['concurrent/concurrent_ruby_ext', + "concurrent/#{RUBY_VERSION[0..2]}/concurrent_ruby_ext" + ].each { |p| try_load_c_extension p } + end + + if Concurrent.on_jruby? && !java_extensions_loaded? + begin + require 'concurrent/concurrent_ruby.jar' + set_java_extensions_loaded + rescue LoadError => e + raise e, "Java extensions are required for JRuby.\n" + e.message, e.backtrace + end + end + end + + private + + def load_error_path(error) + if error.respond_to? :path + error.path + else + error.message.split(' -- ').last + end + end + + def set_c_extensions_loaded + @c_extensions_loaded = true + end + + def java_extensions_loaded? + defined?(@java_extensions_loaded) && @java_extensions_loaded + end + + def set_java_extensions_loaded + @java_extensions_loaded = true + end + + def try_load_c_extension(path) + require path + set_c_extensions_loaded + rescue LoadError => e + if load_error_path(e) == path + # move on with pure-Ruby implementations + # TODO (pitr-ch 12-Jul-2018): warning on verbose? + else + raise e + end + end + + end + end + + # @!visibility private + extend Utility::NativeExtensionLoader +end + +Concurrent.load_native_extensions diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_integer.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_integer.rb new file mode 100644 index 00000000..de1cdc30 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/native_integer.rb @@ -0,0 +1,54 @@ +module Concurrent + # @!visibility private + module Utility + # @private + module NativeInteger + # http://stackoverflow.com/questions/535721/ruby-max-integer + MIN_VALUE = -(2**(0.size * 8 - 2)) + MAX_VALUE = (2**(0.size * 8 - 2) - 1) + + def ensure_upper_bound(value) + if value > MAX_VALUE + raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}") + end + value + end + + def ensure_lower_bound(value) + if value < MIN_VALUE + raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}") + end + value + end + + def ensure_integer(value) + unless value.is_a?(Integer) + raise ArgumentError.new("#{value} is not an Integer") + end + value + end + + def ensure_integer_and_bounds(value) + ensure_integer value + ensure_upper_bound value + ensure_lower_bound value + end + + def ensure_positive(value) + if value < 0 + raise ArgumentError.new("#{value} cannot be negative") + end + value + end + + def ensure_positive_and_no_zero(value) + if value < 1 + raise ArgumentError.new("#{value} cannot be negative or zero") + end + value + end + + extend self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/processor_counter.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/processor_counter.rb new file mode 100644 index 00000000..2489cbd7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/utility/processor_counter.rb @@ -0,0 +1,220 @@ +require 'etc' +require 'rbconfig' +require 'concurrent/delay' + +module Concurrent + # @!visibility private + module Utility + + # @!visibility private + class ProcessorCounter + def initialize + @processor_count = Delay.new { compute_processor_count } + @physical_processor_count = Delay.new { compute_physical_processor_count } + @cpu_quota = Delay.new { compute_cpu_quota } + @cpu_shares = Delay.new { compute_cpu_shares } + end + + def processor_count + @processor_count.value + end + + def physical_processor_count + @physical_processor_count.value + end + + def available_processor_count + cpu_count = processor_count.to_f + quota = cpu_quota + + return cpu_count if quota.nil? + + # cgroup cpus quotas have no limits, so they can be set to higher than the + # real count of cores. + if quota > cpu_count + cpu_count + else + quota + end + end + + def cpu_quota + @cpu_quota.value + end + + def cpu_shares + @cpu_shares.value + end + + private + + def compute_processor_count + if Concurrent.on_jruby? + java.lang.Runtime.getRuntime.availableProcessors + else + Etc.nprocessors + end + end + + def compute_physical_processor_count + ppc = case RbConfig::CONFIG["target_os"] + when /darwin\d\d/ + IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i + when /linux/ + cores = {} # unique physical ID / core ID combinations + phy = 0 + IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln| + if ln.start_with?("physical") + phy = ln[/\d+/] + elsif ln.start_with?("core") + cid = phy + ":" + ln[/\d+/] + cores[cid] = true if not cores[cid] + end + end + cores.count + when /mswin|mingw/ + # Get-CimInstance introduced in PowerShell 3 or earlier: https://learn.microsoft.com/en-us/previous-versions/powershell/module/cimcmdlets/get-ciminstance?view=powershell-3.0 + result = run('powershell -command "Get-CimInstance -ClassName Win32_Processor -Property NumberOfCores | Select-Object -Property NumberOfCores"') + if !result || $?.exitstatus != 0 + # fallback to deprecated wmic for older systems + result = run("wmic cpu get NumberOfCores") + end + if !result || $?.exitstatus != 0 + # Bail out if both commands returned something unexpected + processor_count + else + # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n" + # wmic: "NumberOfCores \n\n4 \n\n\n\n" + result.scan(/\d+/).map(&:to_i).reduce(:+) + end + else + processor_count + end + # fall back to logical count if physical info is invalid + ppc > 0 ? ppc : processor_count + rescue + return 1 + end + + def run(command) + IO.popen(command, &:read) + rescue Errno::ENOENT + end + + def compute_cpu_quota + if RbConfig::CONFIG["target_os"].include?("linux") + if File.exist?("/sys/fs/cgroup/cpu.max") + # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files + cpu_max = File.read("/sys/fs/cgroup/cpu.max") + return nil if cpu_max.start_with?("max ") # no limit + max, period = cpu_max.split.map(&:to_f) + max / period + elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us") + # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt + max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i + # If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions + # https://docs.kernel.org/scheduler/sched-bwc.html#management + return nil if max <= 0 + period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f + max / period + end + end + end + + def compute_cpu_shares + if RbConfig::CONFIG["target_os"].include?("linux") + if File.exist?("/sys/fs/cgroup/cpu.weight") + # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files + # Ref: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2254-cgroup-v2#phase-1-convert-from-cgroups-v1-settings-to-v2 + weight = File.read("/sys/fs/cgroup/cpu.weight").to_f + ((((weight - 1) * 262142) / 9999) + 2) / 1024 + elsif File.exist?("/sys/fs/cgroup/cpu/cpu.shares") + # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt + File.read("/sys/fs/cgroup/cpu/cpu.shares").to_f / 1024 + end + end + end + end + end + + # create the default ProcessorCounter on load + @processor_counter = Utility::ProcessorCounter.new + singleton_class.send :attr_reader, :processor_counter + + # Number of processors seen by the OS and used for process scheduling. For + # performance reasons the calculated value will be memoized on the first + # call. + # + # When running under JRuby the Java runtime call + # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According + # to the Java documentation this "value may change during a particular + # invocation of the virtual machine... [applications] should therefore + # occasionally poll this property." We still memoize this value once under + # JRuby. + # + # Otherwise Ruby's Etc.nprocessors will be used. + # + # @return [Integer] number of processors seen by the OS or Java runtime + # + # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors() + def self.processor_count + processor_counter.processor_count + end + + # Number of physical processor cores on the current system. For performance + # reasons the calculated value will be memoized on the first call. + # + # On Windows the Win32 API will be queried for the `NumberOfCores from + # Win32_Processor`. This will return the total number "of cores for the + # current instance of the processor." On Unix-like operating systems either + # the `hwprefs` or `sysctl` utility will be called in a subshell and the + # returned value will be used. In the rare case where none of these methods + # work or an exception is raised the function will simply return 1. + # + # @return [Integer] number physical processor cores on the current system + # + # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb + # + # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx + # @see http://www.unix.com/man-page/osx/1/HWPREFS/ + # @see http://linux.die.net/man/8/sysctl + def self.physical_processor_count + processor_counter.physical_processor_count + end + + # Number of processors cores available for process scheduling. + # This method takes in account the CPU quota if the process is inside a cgroup with a + # dedicated CPU quota (typically Docker). + # Otherwise it returns the same value as #processor_count but as a Float. + # + # For performance reasons the calculated value will be memoized on the first + # call. + # + # @return [Float] number of available processors + def self.available_processor_count + processor_counter.available_processor_count + end + + # The maximum number of processors cores available for process scheduling. + # Returns `nil` if there is no enforced limit, or a `Float` if the + # process is inside a cgroup with a dedicated CPU quota (typically Docker). + # + # Note that nothing prevents setting a CPU quota higher than the actual number of + # cores on the system. + # + # For performance reasons the calculated value will be memoized on the first + # call. + # + # @return [nil, Float] Maximum number of available processors as set by a cgroup CPU quota, or nil if none set + def self.cpu_quota + processor_counter.cpu_quota + end + + # The CPU shares requested by the process. For performance reasons the calculated + # value will be memoized on the first call. + # + # @return [Float, nil] CPU shares requested by the process, or nil if not set + def self.cpu_shares + processor_counter.cpu_shares + end +end diff --git a/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/version.rb b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/version.rb new file mode 100644 index 00000000..f773e44f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/version.rb @@ -0,0 +1,3 @@ +module Concurrent + VERSION = '1.3.5' +end diff --git a/bin/gems/concurrent-ruby-1.3.8/CHANGELOG.md b/bin/gems/concurrent-ruby-1.3.8/CHANGELOG.md new file mode 100644 index 00000000..6461846e --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/CHANGELOG.md @@ -0,0 +1,621 @@ +## Current + +## Release v1.3.8 (19 July 2026) + +concurrent-ruby: + +* See the [release notes on GitHub](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.8). + +## Release v1.3.7 (16 June 2026) + +concurrent-ruby: + +* See the [release notes on GitHub](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.7). + +## Release v1.3.6 (13 December 2025) + +concurrent-ruby: + +* See the [release notes on GitHub](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.6). + +## Release v1.3.5, edge v0.7.2 (15 January 2025) + +concurrent-ruby: + +* (#1062) Remove dependency on logger. + +concurrent-ruby-edge: + +* (#1062) Remove dependency on logger. + +## Release v1.3.4 (10 August 2024) + +* (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1. +* (#1058) Add `Concurrent.cpu_shares` that is cgroups aware. + +## Release v1.3.3 (9 June 2024) + +* (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows. + +## Release v1.3.2, edge v0.7.1 (7 June 2024) + +concurrent-ruby: + +* (#1051) Remove dependency on `win32ole`. + +concurrent-ruby-edge: + +* (#1052) Fix dependency on `concurrent-ruby` to allow the latest release. + +## Release v1.3.1 (29 May 2024) + +* Release 1.3.0 was broken when pushed to RubyGems. 1.3.1 is a packaging fix. + +## Release v1.3.0 (28 May 2024) + +* (#1042) Align Java Executor Service behavior for `shuttingdown?`, `shutdown?` +* (#1038) Add `Concurrent.available_processor_count` that is cgroups aware. + +## Release v1.2.3 (16 Jan 2024) + +* See [the GitHub release](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.2.3) for details. + +## Release v1.2.2 (24 Feb 2023) + +* (#993) Fix arguments passed to `Concurrent::Map`'s `default_proc`. + +## Release v1.2.1 (24 Feb 2023) + +* (#990) Add missing `require 'fiber'` for `FiberLocalVar`. +* (#989) Optimize `Concurrent::Map#[]` on CRuby by letting the backing Hash handle the `default_proc`. + +## Release v1.2.0 (23 Jan 2023) + +* (#962) Fix ReentrantReadWriteLock to use the same granularity for locals as for Mutex it uses. +* (#983) Add FiberLocalVar +* (#934) concurrent-ruby now supports requiring individual classes (public classes listed in the docs), e.g., `require 'concurrent/map'` +* (#976) Let `Promises.any_fulfilled_future` take an `Event` +* Improve documentation of various classes +* (#975) Set the Ruby compatibility version at 2.3 +* (#972) Remove Rubinius-related code + +## Release v1.1.10 (22 Mar 2022) + +concurrent-ruby: + +* (#951) Set the Ruby compatibility version at 2.2 +* (#939, #933) The `caller_runs` fallback policy no longer blocks reads from the job queue by worker threads +* (#938, #761, #652) You can now explicitly `prune_pool` a thread pool (Sylvain Joyeux) +* (#937, #757, #670) We switched the Yahoo stock API for demos to Alpha Vantage (Gustavo Caso) +* (#932, #931) We changed how `SafeTaskExecutor` handles local jump errors (Aaron Jensen) +* (#927) You can use keyword arguments in your initialize when using `Async` (Matt Larraz) +* (#926, #639) We removed timeout from `TimerTask` because it wasn't sound, and now it's a no-op with a warning (Jacob Atzen) +* (#919) If you double-lock a re-entrant read-write lock, we promote to locked for writing (zp yuan) +* (#915) `monotonic_time` now accepts an optional unit parameter, as Ruby's `clock_gettime` (Jean Boussier) + +## Release v1.1.9 (5 Jun 2021) + +concurrent-ruby: + +* (#866) Child promise state not set to :pending immediately after #execute when parent has completed +* (#905, #872) Fix RubyNonConcurrentPriorityQueue#delete method +* (2df0337d) Make sure locks are not shared on shared when objects are dup/cloned +* (#900, #906, #796, #847, #911) Fix Concurrent::Set tread-safety issues on CRuby +* (#907) Add new ConcurrentMap backend for TruffleRuby + +## Release v1.1.8 (20 January 2021) + +concurrent-ruby: + +* (#885) Fix race condition in TVar for stale reads +* (#884) RubyThreadLocalVar: Do not iterate over hash which might conflict with new pair addition + +## Release v1.1.7 (6 August 2020) + +concurrent-ruby: + +* (#879) Consider falsy value on `Concurrent::Map#compute_if_absent` for fast non-blocking path +* (#876) Reset Async queue on forking, makes Async fork-safe +* (#856) Avoid running problematic code in RubyThreadLocalVar on MRI that occasionally results in segfault +* (#853) Introduce ThreadPoolExecutor without a Queue + +## Release v1.1.6, edge v0.6.0 (10 Feb 2020) + +concurrent-ruby: + +* (#841) Concurrent.disable_at_exit_handlers! is no longer needed and was deprecated. +* (#841) AbstractExecutorService#auto_terminate= was deprecated and has no effect. + Set :auto_terminate option instead when executor is initialized. + +## Release v1.1.6.pre1, edge v0.6.0.pre1 (26 Jan 2020) + +concurrent-ruby: + +* (#828) Allow to name executors, the name is also used to name their threads +* (#838) Implement #dup and #clone for structs +* (#821) Safer finalizers for thread local variables +* Documentation fixes +* (#814) Use Ruby's Etc.nprocessors if available +* (#812) Fix directory structure not to mess with packaging tools +* (#840) Fix termination of pools on JRuby + +concurrent-ruby-edge: + +* Add WrappingExecutor (#830) + +## Release v1.1.5, edge v0.5.0 (10 Mar 2019) + +concurrent-ruby: + +* fix potential leak of context on JRuby and Java 7 + +concurrent-ruby-edge: + +* Add finalized Concurrent::Cancellation +* Add finalized Concurrent::Throttle +* Add finalized Concurrent::Promises::Channel +* Add new Concurrent::ErlangActor + +## Release v1.1.4 (14 Dec 2018) + +* (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11 +* (#776) Fix NameError on defining a struct with a name which is already taken in an ancestor + +## Release v1.1.3 (7 Nov 2018) + +* (#775) fix partial require of the gem (although not officially supported) + +## Release v1.1.2 (6 Nov 2018) + +* (#773) more defensive 1.9.3 support + +## Release v1.1.1, edge v0.4.1 (1 Nov 2018) + +* (#768) add support for 1.9.3 back + +## Release v1.1.0, edge v0.4.0 (31 OCt 2018) (yanked) + +* (#768) yanked because of issues with removed 1.9.3 support + +## Release v1.1.0.pre2, edge v0.4.0.pre2 (18 Sep 2018) + +concurrent-ruby: + +* fixed documentation and README links +* fix Set for TruffleRuby and Rubinius +* use properly supported TruffleRuby APIs + +concurrent-ruby-edge: + +* add Promises.zip_futures_over_on + +## Release v1.1.0.pre1, edge v0.4.0.pre1 (15 Aug 2018) + +concurrent-ruby: + +* requires at least Ruby 2.0 +* [Promises](http://ruby-concurrency.github.io/concurrent-ruby/1.1.0/Concurrent/Promises.html) + are moved from `concurrent-ruby-edge` to `concurrent-ruby` +* Add support for TruffleRuby + * (#734) Fix Array/Hash/Set construction broken on TruffleRuby + * AtomicReference fixed +* CI stabilization +* remove sharp dependency edge -> core +* remove warnings +* documentation updates +* Exchanger is no longer documented as edge since it was already available in + `concurrent-ruby` +* (#644) Fix Map#each and #each_pair not returning enumerator outside of MRI +* (#659) Edge promises fail during error handling +* (#741) Raise on recursive Delay#value call +* (#727) #717 fix global IO executor on JRuby +* (#740) Drop support for CRuby 1.9, JRuby 1.7, Rubinius. +* (#737) Move AtomicMarkableReference out of Edge +* (#708) Prefer platform specific memory barriers +* (#735) Fix wrong expected exception in channel spec assertion +* (#729) Allow executor option in `Promise#then` +* (#725) fix timeout check to use timeout_interval +* (#719) update engine detection +* (#660) Add specs for Promise#zip/Promise.zip ordering +* (#654) Promise.zip execution changes +* (#666) Add thread safe set implementation +* (#651) #699 #to_s, #inspect should not output negative object IDs. +* (#685) Avoid RSpec warnings about raise_error +* (#680) Avoid RSpec monkey patching, persist spec results locally, use RSpec + v3.7.0 +* (#665) Initialize the monitor for new subarrays on Rubinius +* (#661) Fix error handling in edge promises + +concurrent-ruby-edge: + +* (#659) Edge promises fail during error handling +* Edge files clearly separated in `lib-edge` +* added ReInclude + +## Release v1.0.5, edge v0.3.1 (26 Feb 2017) + +concurrent-ruby: + +* Documentation for Event and Semaphore +* Use Unsafe#fullFence and #loadFence directly since the shortcuts were removed in JRuby +* Do not depend on org.jruby.util.unsafe.UnsafeHolder + +concurrent-ruby-edge: + +* (#620) Actors on Pool raise an error +* (#624) Delayed promises did not interact correctly with flatting + * Fix arguments yielded by callback methods +* Overridable default executor in promises factory methods +* Asking actor to terminate will always resolve to `true` + +## Release v1.0.4, edge v0.3.0 (27 Dec 2016) + +concurrent-ruby: + +* Nothing + +concurrent-ruby-edge: + +* New promises' API renamed, lots of improvements, edge bumped to 0.3.0 + * **Incompatible** with previous 0.2.3 version + * see https://github.com/ruby-concurrency/concurrent-ruby/pull/522 + +## Release v1.0.3 (17 Dec 2016) + +* Trigger execution of flattened delayed futures +* Avoid forking for processor_count if possible +* Semaphore Mutex and JRuby parity +* Adds Map#each as alias to Map#each_pair +* Fix uninitialized instance variables +* Make Fixnum, Bignum merger ready +* Allows Promise#then to receive an executor +* TimerSet now survives a fork +* Reject promise on any exception +* Allow ThreadLocalVar to be initialized with a block +* Support Alpha with `Concurrent::processor_count` +* Fixes format-security error when compiling ruby_193_compatible.h +* Concurrent::Atom#swap fixed: reraise the exceptions from block + +## Release v1.0.2 (2 May 2016) + +* Fix bug with `Concurrent::Map` MRI backend `#inspect` method +* Fix bug with `Concurrent::Map` MRI backend using `Hash#value?` +* Improved documentation and examples +* Minor updates to Edge + +## Release v1.0.1 (27 February 2016) + +* Fix "uninitialized constant Concurrent::ReentrantReadWriteLock" error. +* Better handling of `autoload` vs. `require`. +* Improved API for Edge `Future` zipping. +* Fix reference leak in Edge `Future` constructor . +* Fix bug which prevented thread pools from surviving a `fork`. +* Fix bug in which `TimerTask` did not correctly specify all its dependencies. +* Improved support for JRuby+Truffle +* Improved error messages. +* Improved documentation. +* Updated README and CONTRIBUTING. + +## Release v1.0.0 (13 November 2015) + +* Rename `attr_volatile_with_cas` to `attr_atomic` +* Add `clear_each` to `LockFreeStack` +* Update `AtomicReference` documentation +* Further updates and improvements to the synchronization layer. +* Performance and memory usage performance with `Actor` logging. +* Fixed `ThreadPoolExecutor` task count methods. +* Improved `Async` performance for both short and long-lived objects. +* Fixed bug in `LockFreeLinkedSet`. +* Fixed bug in which `Agent#await` triggered a validation failure. +* Further `Channel` updates. +* Adopted a project Code of Conduct +* Cleared interpreter warnings +* Fixed bug in `ThreadPoolExecutor` task count methods +* Fixed bug in 'LockFreeLinkedSet' +* Improved Java extension loading +* Handle Exception children in Edge::Future +* Continued improvements to channel +* Removed interpreter warnings. +* Shared constants now in `lib/concurrent/constants.rb` +* Refactored many tests. +* Improved synchronization layer/memory model documentation. +* Bug fix in Edge `Future#flat` +* Brand new `Channel` implementation in Edge gem. +* Simplification of `RubySingleThreadExecutor` +* `Async` improvements + - Each object uses its own `SingleThreadExecutor` instead of the global thread pool. + - No longer supports executor injection + - Much better documentation +* `Atom` updates + - No longer `Dereferenceable` + - Now `Observable` + - Added a `#reset` method +* Brand new `Agent` API and implementation. Now functionally equivalent to Clojure. +* Continued improvements to the synchronization layer +* Merged in the `thread_safe` gem + - `Concurrent::Array` + - `Concurrent::Hash` + - `Concurrent::Map` (formerly ThreadSafe::Cache) + - `Concurrent::Tuple` +* Minor improvements to Concurrent::Map +* Complete rewrite of `Exchanger` +* Removed all deprecated code (classes, methods, constants, etc.) +* Updated Agent, MutexAtomic, and BufferedChannel to inherit from Synchronization::Object. +* Many improved tests +* Some internal reorganization + +## Release v0.9.1 (09 August 2015) + +* Fixed a Rubiniux bug in synchronization object +* Fixed all interpreter warnings (except circular references) +* Fixed require statements when requiring `Atom` alone +* Significantly improved `ThreadLocalVar` on non-JRuby platforms +* Fixed error handling in Edge `Concurrent.zip` +* `AtomicFixnum` methods `#increment` and `#decrement` now support optional delta +* New `AtomicFixnum#update` method +* Minor optimizations in `ReadWriteLock` +* New `ReentrantReadWriteLock` class +* `ThreadLocalVar#bind` method is now public +* Refactored many tests + +## Release v0.9.0 (10 July 2015) + +* Updated `AtomicReference` + - `AtomicReference#try_update` now simply returns instead of raising exception + - `AtomicReference#try_update!` was added to raise exceptions if an update + fails. Note: this is the same behavior as the old `try_update` +* Pure Java implementations of + - `AtomicBoolean` + - `AtomicFixnum` + - `Semaphore` +* Fixed bug when pruning Ruby thread pools +* Fixed bug in time calculations within `ScheduledTask` +* Default `count` in `CountDownLatch` to 1 +* Use monotonic clock for all timers via `Concurrent.monotonic_time` + - Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` when available + - Fallback to `java.lang.System.nanoTime()` on unsupported JRuby versions + - Pure Ruby implementation for everything else + - Effects `Concurrent.timer`, `Concurrent.timeout`, `TimerSet`, `TimerTask`, and `ScheduledTask` +* Deprecated all clock-time based timer scheduling + - Only support scheduling by delay + - Effects `Concurrent.timer`, `TimerSet`, and `ScheduledTask` +* Added new `ReadWriteLock` class +* Consistent `at_exit` behavior for Java and Ruby thread pools. +* Added `at_exit` handler to Ruby thread pools (already in Java thread pools) + - Ruby handler stores the object id and retrieves from `ObjectSpace` + - JRuby disables `ObjectSpace` by default so that handler stores the object reference +* Added a `:stop_on_exit` option to thread pools to enable/disable `at_exit` handler +* Updated thread pool docs to better explain shutting down thread pools +* Simpler `:executor` option syntax for all abstractions which support this option +* Added `Executor#auto_terminate?` predicate method (for thread pools) +* Added `at_exit` handler to `TimerSet` +* Simplified auto-termination of the global executors + - Can now disable auto-termination of global executors + - Added shutdown/kill/wait_for_termination variants for global executors +* Can now disable auto-termination for *all* executors (the nuclear option) +* Simplified auto-termination of the global executors +* Deprecated terms "task pool" and "operation pool" + - New terms are "io executor" and "fast executor" + - New functions added with new names + - Deprecation warnings added to functions referencing old names +* Moved all thread pool related functions from `Concurrent::Configuration` to `Concurrent` + - Old functions still exist with deprecation warnings + - New functions have updated names as appropriate +* All high-level abstractions default to the "io executor" +* Fixed bug in `Actor` causing it to prematurely warm global thread pools on gem load + - This also fixed a `RejectedExecutionError` bug when running with minitest/autorun via JRuby +* Moved global logger up to the `Concurrent` namespace and refactored the code +* Optimized the performance of `Delay` + - Fixed a bug in which no executor option on construction caused block execution on a global thread pool +* Numerous improvements and bug fixes to `TimerSet` +* Fixed deadlock of `Future` when the handler raises Exception +* Added shared specs for more classes +* New concurrency abstractions including: + - `Atom` + - `Maybe` + - `ImmutableStruct` + - `MutableStruct` + - `SettableStruct` +* Created an Edge gem for unstable abstractions including + - `Actor` + - `Agent` + - `Channel` + - `Exchanger` + - `LazyRegister` + - **new Future Framework** - unified + implementation of Futures and Promises which combines Features of previous `Future`, + `Promise`, `IVar`, `Event`, `Probe`, `dataflow`, `Delay`, `TimerTask` into single framework. It uses extensively + new synchronization layer to make all the paths **lock-free** with exception of blocking threads on `#wait`. + It offers better performance and does not block threads when not required. +* Actor framework changes: + - fixed reset loop in Pool + - Pool can use any actor as a worker, abstract worker class is no longer needed. + - Actor events not have format `[:event_name, *payload]` instead of just the Symbol. + - Actor now uses new Future/Promise Framework instead of `IVar` for better interoperability + - Behaviour definition array was simplified to `[BehaviourClass1, [BehaviourClass2, *initialization_args]]` + - Linking behavior responds to :linked message by returning array of linked actors + - Supervised behavior is removed in favour of just Linking + - RestartingContext is supervised by default now, `supervise: true` is not required any more + - Events can be private and public, so far only difference is that Linking will + pass to linked actors only public messages. Adding private :restarting and + :resetting events which are send before the actor restarts or resets allowing + to add callbacks to cleanup current child actors. + - Print also object_id in Reference to_s + - Add AbstractContext#default_executor to be able to override executor class wide + - Add basic IO example + - Documentation somewhat improved + - All messages should have same priority. It's now possible to send `actor << job1 << job2 << :terminate!` and + be sure that both jobs are processed first. +* Refactored `Channel` to use newer synchronization objects +* Added `#reset` and `#cancel` methods to `TimerSet` +* Added `#cancel` method to `Future` and `ScheduledTask` +* Refactored `TimerSet` to use `ScheduledTask` +* Updated `Async` with a factory that initializes the object +* Deprecated `Concurrent.timer` and `Concurrent.timeout` +* Reduced max threads on pure-Ruby thread pools (abends around 14751 threads) +* Moved many private/internal classes/modules into "namespace" modules +* Removed brute-force killing of threads in tests +* Fixed a thread pool bug when the operating system cannot allocate more threads + +## Release v0.8.0 (25 January 2015) + +* C extension for MRI have been extracted into the `concurrent-ruby-ext` companion gem. + Please see the README for more detail. +* Better variable isolation in `Promise` and `Future` via an `:args` option +* Continued to update intermittently failing tests + +## Release v0.7.2 (24 January 2015) + +* New `Semaphore` class based on [java.util.concurrent.Semaphore](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html) +* New `Promise.all?` and `Promise.any?` class methods +* Renamed `:overflow_policy` on thread pools to `:fallback_policy` +* Thread pools still accept the `:overflow_policy` option but display a warning +* Thread pools now implement `fallback_policy` behavior when not running (rather than universally rejecting tasks) +* Fixed minor `set_deref_options` constructor bug in `Promise` class +* Fixed minor `require` bug in `ThreadLocalVar` class +* Fixed race condition bug in `TimerSet` class +* Fixed race condition bug in `TimerSet` class +* Fixed signal bug in `TimerSet#post` method +* Numerous non-functional updates to clear warning when running in debug mode +* Fixed more intermittently failing tests +* Tests now run on new Travis build environment +* Multiple documentation updates + +## Release v0.7.1 (4 December 2014) + +Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/issues/142) for more information on the next planned release. + +* Added `flat_map` method to `Promise` +* Added `zip` method to `Promise` +* Fixed bug with logging in `Actor` +* Improvements to `Promise` tests +* Removed actor-experimental warning +* Added an `IndirectImmediateExecutor` class +* Allow disabling auto termination of global executors +* Fix thread leaking in `ThreadLocalVar` (uses `Ref` gem on non-JRuby systems) +* Fix thread leaking when pruning pure-Ruby thread pools +* Prevent `Actor` from using an `ImmediateExecutor` (causes deadlock) +* Added missing synchronizations to `TimerSet` +* Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask` +* Fixed timing bug in `TimerTask` +* Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero +* Removed confusing warning when not using native extensions +* Improved documentation + +## Release v0.7.0 (13 August 2014) + +* Merge the [atomic](https://github.com/ruby-concurrency/atomic) gem + - Pure Ruby `MutexAtomic` atomic reference class + - Platform native atomic reference classes `CAtomic`, `JavaAtomic`, and `RbxAtomic` + - Automated [build process](https://github.com/ruby-concurrency/rake-compiler-dev-box) + - Fat binary releases for [multiple platforms](https://rubygems.org/gems/concurrent-ruby/versions) including Windows (32/64), Linux (32/64), OS X (64-bit), Solaris (64-bit), and JRuby +* C native `CAtomicBoolean` +* C native `CAtomicFixnum` +* Refactored intermittently failing tests +* Added `dataflow!` and `dataflow_with!` methods to match `Future#value!` method +* Better handling of timeout in `Agent` +* Actor Improvements + - Fine-grained implementation using chain of behaviors. Each behavior is responsible for single aspect like: `Termination`, `Pausing`, `Linking`, `Supervising`, etc. Users can create custom Actors easily based on their needs. + - Supervision was added. `RestartingContext` will pause on error waiting on its supervisor to decide what to do next ( options are `:terminate!`, `:resume!`, `:reset!`, `:restart!`). Supervising behavior also supports strategies `:one_for_one` and `:one_for_all`. + - Linking was added to be able to monitor actor's events like: `:terminated`, `:paused`, `:restarted`, etc. + - Dead letter routing added. Rejected envelopes are collected in a configurable actor (default: `Concurrent::Actor.root.ask!(:dead_letter_routing)`) + - Old `Actor` class removed and replaced by new implementation previously called `Actress`. `Actress` was kept as an alias for `Actor` to keep compatibility. + - `Utils::Broadcast` actor which allows Publish–subscribe pattern. +* More executors for managing serialized operations + - `SerializedExecution` mixin module + - `SerializedExecutionDelegator` for serializing *any* executor +* Updated `Async` with serialized execution +* Updated `ImmediateExecutor` and `PerThreadExecutor` with full executor service lifecycle +* Added a `Delay` to root `Actress` initialization +* Minor bug fixes to thread pools +* Refactored many intermittently failing specs +* Removed Java interop warning `executor.rb:148 warning: ambiguous Java methods found, using submit(java.lang.Runnable)` +* Fixed minor bug in `RubyCachedThreadPool` overflow policy +* Updated tests to use [RSpec 3.0](http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3) +* Removed deprecated `Actor` class +* Better support for Rubinius + +## Release v0.6.1 (14 June 2014) + +* Many improvements to `Concurrent::Actress` +* Bug fixes to `Concurrent::RubyThreadPoolExecutor` +* Fixed several brittle tests +* Moved documentation to http://ruby-concurrency.github.io/concurrent-ruby/frames.html + +## Release v0.6.0 (25 May 2014) + +* Added `Concurrent::Observable` to encapsulate our thread safe observer sets +* Improvements to new `Channel` +* Major improvements to `CachedThreadPool` and `FixedThreadPool` +* Added `SingleThreadExecutor` +* Added `Current::timer` function +* Added `TimerSet` executor +* Added `AtomicBoolean` +* `ScheduledTask` refactoring +* Pure Ruby and JRuby-optimized `PriorityQueue` classes +* Updated `Agent` behavior to more closely match Clojure +* Observer sets support block callbacks to the `add_observer` method +* New algorithm for thread creation in `RubyThreadPoolExecutor` +* Minor API updates to `Event` +* Rewritten `TimerTask` now an `Executor` instead of a `Runnable` +* Fixed many brittle specs +* Renamed `FixedThreadPool` and `CachedThreadPool` to `RubyFixedThreadPool` and `RubyCachedThreadPool` +* Created JRuby optimized `JavaFixedThreadPool` and `JavaCachedThreadPool` +* Consolidated fixed thread pool tests into `spec/concurrent/fixed_thread_pool_shared.rb` and `spec/concurrent/cached_thread_pool_shared.rb` +* `FixedThreadPool` now subclasses `RubyFixedThreadPool` or `JavaFixedThreadPool` as appropriate +* `CachedThreadPool` now subclasses `RubyCachedThreadPool` or `JavaCachedThreadPool` as appropriate +* New `Delay` class +* `Concurrent::processor_count` helper function +* New `Async` module +* Renamed `NullThreadPool` to `PerThreadExecutor` +* Deprecated `Channel` (we are planning a new implementation based on [Go](http://golangtutorials.blogspot.com/2011/06/channels-in-go.html)) +* Added gem-level [configuration](http://robots.thoughtbot.com/mygem-configure-block) +* Deprecated `$GLOBAL_THREAD_POOL` in lieu of gem-level configuration +* Removed support for Ruby [1.9.2](https://www.ruby-lang.org/en/news/2013/12/17/maintenance-of-1-8-7-and-1-9-2/) +* New `RubyThreadPoolExecutor` and `JavaThreadPoolExecutor` classes +* All thread pools now extend the appropriate thread pool executor classes +* All thread pools now support `:overflow_policy` (based on Java's [reject policies](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html)) +* Deprecated `UsesGlobalThreadPool` in lieu of explicit `:executor` option (dependency injection) on `Future`, `Promise`, and `Agent` +* Added `Concurrent::dataflow_with(executor, *inputs)` method to support executor dependency injection for dataflow +* Software transactional memory with `TVar` and `Concurrent::atomically` +* First implementation of [new, high-performance](https://github.com/ruby-concurrency/concurrent-ruby/pull/49) `Channel` +* `Actor` is deprecated in favor of new experimental actor implementation [#73](https://github.com/ruby-concurrency/concurrent-ruby/pull/73). To avoid namespace collision it is living in `Actress` namespace until `Actor` is removed in next release. + +## Release v0.5.0 + +This is the most significant release of this gem since its inception. This release includes many improvements and optimizations. It also includes several bug fixes. The major areas of focus for this release were: + +* Stability improvements on Ruby versions with thread-level parallelism ([JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) +* Creation of new low-level concurrency abstractions +* Internal refactoring to use the new low-level abstractions + +Most of these updates had no effect on the gem API. There are a few notable exceptions which were unavoidable. Please read the [release notes](API-Updates-in-v0.5.0) for more information. + +Specific changes include: + +* New class `IVar` +* New class `MVar` +* New class `ThreadLocalVar` +* New class `AtomicFixnum` +* New class method `dataflow` +* New class `Condition` +* New class `CountDownLatch` +* New class `DependencyCounter` +* New class `SafeTaskExecutor` +* New class `CopyOnNotifyObserverSet` +* New class `CopyOnWriteObserverSet` +* `Future` updated with `execute` API +* `ScheduledTask` updated with `execute` API +* New `Promise` API +* `Future` now extends `IVar` +* `Postable#post?` now returns an `IVar` +* Thread safety fixes to `Dereferenceable` +* Thread safety fixes to `Obligation` +* Thread safety fixes to `Supervisor` +* Thread safety fixes to `Event` +* Various other thread safety (race condition) fixes +* Refactored brittle tests +* Implemented pending tests +* Added JRuby and Rubinius as Travis CI build targets +* Added [CodeClimate](https://codeclimate.com/) code review +* Improved YARD documentation diff --git a/bin/gems/concurrent-ruby-1.3.8/Gemfile b/bin/gems/concurrent-ruby-1.3.8/Gemfile new file mode 100644 index 00000000..1786c8b2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/Gemfile @@ -0,0 +1,36 @@ +source 'https://rubygems.org' + +version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise +edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise + +no_path = ENV['NO_PATH'] +options = no_path ? {} : { path: '.' } + +gem 'concurrent-ruby', version, options +gem 'concurrent-ruby-edge', edge_version, options +gem 'concurrent-ruby-ext', version, options.merge(platform: :mri) + +group :development do + gem 'rake', '~> 13.0' + gem 'rake-compiler', '~> 1.0', '>= 1.0.7', '!= 1.2.4' + gem 'rake-compiler-dock', '~> 1.0' + gem 'pry', '~> 0.11', platforms: :mri +end + +group :documentation, optional: true do + gem 'yard', '~> 0.9.0', require: false + gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown + gem 'md-ruby-eval', '~> 0.6' +end + +group :testing do + gem 'rspec', '~> 3.7' + gem 'timecop', '~> 0.9' + gem 'sigdump', require: false +end + +# made opt-in since it will not install on jruby 1.7 +group :coverage, optional: !ENV['COVERAGE'] do + gem 'simplecov', '~> 0.16.0', require: false + gem 'coveralls', '~> 0.8.2', require: false +end diff --git a/bin/gems/concurrent-ruby-1.3.8/LICENSE.txt b/bin/gems/concurrent-ruby-1.3.8/LICENSE.txt new file mode 100644 index 00000000..1026f28d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright (c) Jerry D'Antonio -- released under the MIT license. + +http://www.opensource.org/licenses/mit-license.php + +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/bin/gems/concurrent-ruby-1.3.8/README.md b/bin/gems/concurrent-ruby-1.3.8/README.md new file mode 100644 index 00000000..daf3eac5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/README.md @@ -0,0 +1,409 @@ +# Concurrent Ruby + +[![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) +[![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) +[![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby) + +Modern concurrency tools for Ruby. Inspired by +[Erlang](http://www.erlang.org/doc/reference_manual/processes.html), +[Clojure](http://clojure.org/concurrent_programming), +[Scala](http://akka.io/), +[Haskell](http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell), +[F#](http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx), +[C#](http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx), +[Java](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html), +and classic concurrency patterns. + + + +The design goals of this gem are: + +* Be an 'unopinionated' toolbox that provides useful utilities without debating which is better + or why +* Remain free of external gem dependencies +* Stay true to the spirit of the languages providing inspiration +* But implement in a way that makes sense for Ruby +* Keep the semantics as idiomatic Ruby as possible +* Support features that make sense in Ruby +* Exclude features that don't make sense in Ruby +* Be small, lean, and loosely coupled +* Thread-safety +* Backward compatibility + +## Contributing + +**This gem depends on +[contributions](https://github.com/ruby-concurrency/concurrent-ruby/graphs/contributors) and we +appreciate your help. Would you like to contribute? Great! Have a look at +[issues with `looking-for-contributor` label](https://github.com/ruby-concurrency/concurrent-ruby/issues?q=is%3Aissue+is%3Aopen+label%3Alooking-for-contributor).** And if you pick something up let us know on the issue. + +You can also get started by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to concurrent-ruby on CodeTriage](https://www.codetriage.com/ruby-concurrency/concurrent-ruby). [![Open Source Helpers](https://www.codetriage.com/ruby-concurrency/concurrent-ruby/badges/users.svg)](https://www.codetriage.com/ruby-concurrency/concurrent-ruby) + +## Thread Safety + +*Concurrent Ruby makes one of the strongest thread safety guarantees of any Ruby concurrency +library, providing consistent behavior and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby).* + +Every abstraction in this library is thread safe. Specific thread safety guarantees are documented +with each abstraction. + +It is critical to remember, however, that Ruby is a language of mutable references. *No* +concurrency library for Ruby can ever prevent the user from making thread safety mistakes (such as +sharing a mutable object between threads and modifying it on both threads) or from creating +deadlocks through incorrect use of locks. All the library can do is provide safe abstractions which +encourage safe practices. Concurrent Ruby provides more safe concurrency abstractions than any +other Ruby library, many of which support the mantra of +["Do not communicate by sharing memory; instead, share memory by communicating"](https://blog.golang.org/share-memory-by-communicating). +Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and +immutable variable types and data structures. + +We've also initiated discussion to document the [memory model](docs-source/synchronization.md) of Ruby which +would provide consistent behaviour and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby). + +## Features & Documentation + +**The primary site for documentation is the automatically generated +[API documentation](http://ruby-concurrency.github.io/concurrent-ruby/index.html) which is up to +date with latest release.** This readme matches the master so may contain new stuff not yet +released. + +We also have a [IRC (gitter)](https://gitter.im/ruby-concurrency/concurrent-ruby). + +### Versioning + +* `concurrent-ruby` uses [Semantic Versioning](http://semver.org/) +* `concurrent-ruby-ext` has always same version as `concurrent-ruby` +* `concurrent-ruby-edge` will always be 0.y.z therefore following + [point 4](http://semver.org/#spec-item-4) applies *"Major version zero + (0.y.z) is for initial development. Anything may change at any time. The + public API should not be considered stable."* However we additionally use + following rules: + * Minor version increment means incompatible changes were made + * Patch version increment means only compatible changes were made + + +#### General-purpose Concurrency Abstractions + +* [Async](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Async.html): + A mixin module that provides simple asynchronous behavior to a class. Loosely based on Erlang's + [gen_server](http://www.erlang.org/doc/man/gen_server.html). +* [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ScheduledTask.html): + Like a Future scheduled for a specific future time. +* [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/TimerTask.html): + A Thread that periodically wakes up to perform work at regular intervals. +* [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html): + Unified implementation of futures and promises which combines features of previous `Future`, + `Promise`, `IVar`, `Event`, `dataflow`, `Delay`, and (partially) `TimerTask` into a single + framework. It extensively uses the new synchronization layer to make all the features + **non-blocking** and **lock-free**, with the exception of obviously blocking operations like + `#wait`, `#value`. It also offers better performance. + +#### Thread-safe Value Objects, Structures, and Collections + +Collection classes that were originally part of the (deprecated) `thread_safe` gem: + +* [Array](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Array.html) A thread-safe + subclass of Ruby's standard [Array](http://ruby-doc.org/core/Array.html). +* [Hash](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Hash.html) A thread-safe + subclass of Ruby's standard [Hash](http://ruby-doc.org/core/Hash.html). +* [Set](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Set.html) A thread-safe + subclass of Ruby's standard [Set](http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html). +* [Map](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Map.html) A hash-like object + that should have much better performance characteristics, especially under high concurrency, + than `Concurrent::Hash`. +* [Tuple](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Tuple.html) A fixed size + array with volatile (synchronized, thread safe) getters/setters. + +Value objects inspired by other languages: + +* [Maybe](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Maybe.html) A thread-safe, + immutable object representing an optional value, based on + [Haskell Data.Maybe](https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html). + +Structure classes derived from Ruby's [Struct](http://ruby-doc.org/core/Struct.html): + +* [ImmutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ImmutableStruct.html) + Immutable struct where values are set at construction and cannot be changed later. +* [MutableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/MutableStruct.html) + Synchronized, mutable struct where values can be safely changed at any time. +* [SettableStruct](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/SettableStruct.html) + Synchronized, write-once struct where values can be set at most once, either at construction + or any time thereafter. + +Thread-safe variables: + +* [Agent](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Agent.html): A way to + manage shared, mutable, *asynchronous*, independent state. Based on Clojure's + [Agent](http://clojure.org/agents). +* [Atom](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Atom.html): A way to manage + shared, mutable, *synchronous*, independent state. Based on Clojure's + [Atom](http://clojure.org/atoms). +* [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicBoolean.html) + A boolean value that can be updated atomically. +* [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicFixnum.html) + A numeric value that can be updated atomically. +* [AtomicReference](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicReference.html) + An object reference that may be updated atomically. +* [Exchanger](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Exchanger.html) + A synchronization point at which threads can pair and swap elements within pairs. Based on + Java's [Exchanger](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html). +* [MVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/MVar.html) A synchronized + single element container. Based on Haskell's + [MVar](https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Concurrent-MVar.html) and + Scala's [MVar](http://docs.typelevel.org/api/scalaz/nightly/index.html#scalaz.concurrent.MVar$). +* [ThreadLocalVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ThreadLocalVar.html) + A variable where the value is different for each thread. +* [TVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/TVar.html) A transactional + variable implementing software transactional memory (STM). Based on Clojure's + [Ref](http://clojure.org/refs). + +#### Java-inspired ThreadPools and Other Executors + +* See the [thread pool](http://ruby-concurrency.github.io/concurrent-ruby/master/file.thread_pools.html) + overview, which also contains a list of other Executors available. + +#### Thread Synchronization Classes and Algorithms + +* [CountDownLatch](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/CountDownLatch.html) + A synchronization object that allows one thread to wait on multiple other threads. +* [CyclicBarrier](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/CyclicBarrier.html) + A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. +* [Event](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Event.html) Old school + kernel-style event. +* [ReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ReadWriteLock.html) + A lock that supports multiple readers but only one writer. +* [ReentrantReadWriteLock](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ReentrantReadWriteLock.html) + A read/write lock with reentrant and upgrade features. +* [Semaphore](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Semaphore.html) + A counting-based locking mechanism that uses permits. +* [AtomicMarkableReference](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/AtomicMarkableReference.html) + +#### Deprecated + +Deprecated features are still available and bugs are being fixed, but new features will not be added. + +* ~~[Future](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Future.html): + An asynchronous operation that produces a value.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). + * ~~[.dataflow](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#dataflow-class_method): + Built on Futures, Dataflow allows you to create a task that will be scheduled when all of + its data dependencies are available.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[Promise](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promise.html): Similar + to Futures, with more features.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[Delay](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Delay.html) Lazy evaluation + of a block yielding an immutable result. Based on Clojure's + [delay](https://clojuredocs.org/clojure.core/delay).~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). +* ~~[IVar](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/IVar.html) Similar to a + "future" but can be manually assigned once, after which it becomes immutable.~~ Replaced by + [Promises](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises.html). + +### Edge Features + +These are available in the `concurrent-ruby-edge` companion gem. + +These features are under active development and may change frequently. They are expected not to +keep backward compatibility (they may also lack tests and documentation). Semantic versions will +be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to +`concurrent-ruby` when final. + +* [Actor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Actor.html): Implements + the Actor Model, where concurrent actors exchange messages. + *Status: Partial documentation and tests; depends on new future/promise framework; stability is good.* +* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Channel.html): + Communicating Sequential Processes ([CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes)). + Functionally equivalent to Go [channels](https://tour.golang.org/concurrency/2) with additional + inspiration from Clojure [core.async](https://clojure.github.io/core.async/). + *Status: Partial documentation and tests.* +* [LazyRegister](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LazyRegister.html) +* [LockFreeLinkedSet](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Edge/LockFreeLinkedSet.html) + *Status: will be moved to core soon.* +* [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LockFreeStack.html) + *Status: missing documentation and tests.* +* [Promises::Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises/Channel.html) + A first in first out channel that accepts messages with push family of methods and returns + messages with pop family of methods. + Pop and push operations can be represented as futures, see `#pop_op` and `#push_op`. + The capacity of the channel can be limited to support back pressure, use capacity option in `#initialize`. + `#pop` method blocks ans `#pop_op` returns pending future if there is no message in the channel. + If the capacity is limited the `#push` method blocks and `#push_op` returns pending future. +* [Cancellation](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Cancellation.html) + The Cancellation abstraction provides cooperative cancellation. + + The standard methods `Thread#raise` of `Thread#kill` available in Ruby + are very dangerous (see linked the blog posts bellow). + Therefore concurrent-ruby provides an alternative. + + * + * + * + + It provides an object which represents a task which can be executed, + the task has to get the reference to the object and periodically cooperatively check that it is not cancelled. + Good practices to make tasks cancellable: + * check cancellation every cycle of a loop which does significant work, + * do all blocking actions in a loop with a timeout then on timeout check cancellation + and if ok block again with the timeout +* [Throttle](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Throttle.html) + A tool managing concurrency level of tasks. +* [ErlangActor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ErlangActor.html) + Actor implementation which precisely matches Erlang actor behaviour. + Requires at least Ruby 2.1 otherwise it's not loaded. +* [WrappingExecutor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/WrappingExecutor.html) + A delegating executor which modifies each task before the task is given to + the target executor it delegates to. + +## Supported Ruby versions + +* MRI 2.3 and above +* Latest JRuby 9000 +* Latest TruffleRuby + +## Usage + +Everything within this gem can be loaded simply by requiring it: + +```ruby +require 'concurrent' +``` + +You can also require a specific abstraction [part of the public documentation](https://ruby-concurrency.github.io/concurrent-ruby/master/index.html) since concurrent-ruby 1.2.0, for example: +```ruby +require 'concurrent/map' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/executor/fixed_thread_pool' +``` + +To use the tools in the Edge gem it must be required separately: + +```ruby +require 'concurrent-edge' +``` + +If the library does not behave as expected, `Concurrent.use_simple_logger(:DEBUG)` could +help to reveal the problem. + +## Installation + +```shell +gem install concurrent-ruby +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby', require: 'concurrent' +``` + +and run `bundle install` from your shell. + +### Edge Gem Installation + +The Edge gem must be installed separately from the core gem: + +```shell +gem install concurrent-ruby-edge +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby-edge', require: 'concurrent-edge' +``` + +and run `bundle install` from your shell. + + +### C Extensions for MRI + +Potential performance improvements may be achieved under MRI by installing optional C extensions. +To minimise installation errors the C extensions are available in the `concurrent-ruby-ext` +extension gem. `concurrent-ruby` and `concurrent-ruby-ext` are always released together with same +version. Simply install the extension gem too: + +```ruby +gem install concurrent-ruby-ext +``` + +or add the following line to Gemfile: + +```ruby +gem 'concurrent-ruby-ext' +``` + +and run `bundle install` from your shell. + +In code it is only necessary to + +```ruby +require 'concurrent' +``` + +The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem +and load the appropriate C extensions. + +#### Note For gem developers + +No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The +best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions. + +## Building the gem + +### Requirements + +* Recent CRuby +* JRuby, `rbenv install jruby-9.2.17.0` +* Set env variable `CONCURRENT_JRUBY_HOME` to point to it, e.g. `/usr/local/opt/rbenv/versions/jruby-9.2.17.0` +* Install Docker or Podman, required for Windows builds +* If `bundle config get path` is set, use `bundle config set --local path.system true` otherwise the `gem name, path: '.'` gems won't be found (Bundler limitation). + +### Publishing the Gem + +* Update `version.rb` +* Update the CHANGELOG +* Add the new version to `docs-source/signpost.md`. Needs to be done only if there are visible changes in the documentation. +* Commit (and push) the changes. +* Use `bundle exec rake release` to release the gem. + It consists of `['release:checks', 'release:build', 'release:test', 'release:publish']` steps. + It will ask at the end before publishing anything. Steps can also be executed individually. + +## Maintainers + +* [Benoit Daloze](https://github.com/eregon) +* [Matthew Draper](https://github.com/matthewd) +* [Rafael França](https://github.com/rafaelfranca) +* [Charles Oliver Nutter](https://github.com/headius) +* [Ben Sheldon](https://github.com/bensheldon) +* [Samuel Williams](https://github.com/ioquatix) +* [Joshua Young](https://github.com/joshuay03) + +### Special Thanks to + +* [Jerry D'Antonio](https://github.com/jdantonio) for creating the gem +* [Brian Durand](https://github.com/bdurand) for the `ref` gem +* [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems +* [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem + +to the past maintainers + +* [Chris Seaton](https://github.com/chrisseaton) +* [Petr Chalupa](https://github.com/pitr-ch) +* [Michele Della Torre](https://github.com/mighe) +* [Paweł Obrok](https://github.com/obrok) +* [Lucas Allan](https://github.com/lucasallan) + +and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project +["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018. + +## License and Copyright + +*Concurrent Ruby* is free software released under the +[MIT License](http://www.opensource.org/licenses/MIT). + +The *Concurrent Ruby* [logo](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/docs-source/logo/concurrent-ruby-logo-300x300.png) was +designed by [David Jones](https://twitter.com/zombyboy). It is Copyright © 2014 +[Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved. diff --git a/bin/gems/concurrent-ruby-1.3.8/Rakefile b/bin/gems/concurrent-ruby-1.3.8/Rakefile new file mode 100644 index 00000000..7c459fd6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/Rakefile @@ -0,0 +1,343 @@ +version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise +edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise + +core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec') +ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec') +edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.gemspec') + +require 'rake/javaextensiontask' + +ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && RUBY_ENGINE != 'jruby' + +Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext| + ext.ext_dir = 'ext/concurrent-ruby' + ext.lib_dir = 'lib/concurrent-ruby/concurrent' + ext.source_version = '8' + ext.target_version = '8' +end + +if RUBY_ENGINE == 'ruby' + require 'rake/extensiontask' + + Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext| + ext.ext_dir = 'ext/concurrent-ruby-ext' + ext.lib_dir = 'lib/concurrent-ruby/concurrent' + ext.source_pattern = '*.{c,h}' + + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] + end +end + +def which?(executable) + !`which #{executable} 2>/dev/null`.empty? +end + +require 'rake_compiler_dock' +namespace :repackage do + desc '* with Windows fat distributions' + task :all do + Dir.chdir(__dir__) do + # store gems in vendor cache for docker + Bundler.with_original_env do + sh 'bundle package' + end + + # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem + Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke + + # build all gem files + rack_compiler_dock_kwargs = {} + if which?('podman') and (!which?('docker') || `docker --version`.include?('podman')) + # podman and only podman available, so RakeCompilerDock will use podman, otherwise it uses docker + rack_compiler_dock_kwargs = { + options: ['--privileged'], # otherwise the directory in the image is empty + runas: false + } + end + %w[x86-mingw32 x64-mingw32].each do |plat| + RakeCompilerDock.sh( + "bundle install --local && bundle exec rake native:#{plat} gem --trace", + platform: plat, + **rack_compiler_dock_kwargs) + end + end + end +end + +require 'rubygems' +require 'rubygems/package_task' + +Gem::PackageTask.new(core_gemspec) {} if core_gemspec +Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby' +Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec + +CLEAN.include( + 'lib/concurrent-ruby/concurrent/concurrent_ruby_ext.*', + 'lib/concurrent-ruby/concurrent/2.*', + 'lib/concurrent-ruby/concurrent/*.jar') + +begin + require 'rspec' + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec) + + namespace :spec do + desc '* Configured for ci' + RSpec::Core::RakeTask.new(:ci) do |t| + options = %w[ --color + --backtrace + --order defined + --format documentation ] + t.rspec_opts = [*options].join(' ') + end + + desc '* test packaged and installed gems instead of local files' + task :installed do + Bundler.with_original_env do + Dir.chdir(__dir__) do + sh "gem install pkg/concurrent-ruby-#{version}.gem" + sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby' + sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem" + ENV['NO_PATH'] = 'true' + sh 'bundle update' + sh 'bundle exec rake spec:ci' + end + end + end + end + + desc 'executed in CI' + task :ci => [:compile, 'spec:ci'] + + desc 'run each spec file in a separate process to help find missing requires' + task 'spec:isolated' do + glob = "#{ENV['DIR'] || 'spec'}/**/*_spec.rb" + from = ENV['FROM'] + env = { 'ISOLATED' => 'true' } + Dir[glob].each do |spec| + next if from and from != spec + from = nil if from == spec + + sh env, 'rspec', spec + end + end + + task :default => [:clobber, :compile, :spec] +rescue LoadError => e + puts 'RSpec is not installed, skipping test task definitions: ' + e.message +end + +current_yard_version_name = version + +begin + require 'yard' + require 'md_ruby_eval' + require_relative 'support/yard_full_types' + + common_yard_options = ['--no-yardopts', + '--no-document', + '--no-private', + '--embed-mixins', + '--markup', 'markdown', + '--title', 'Concurrent Ruby', + '--template', 'default', + '--template-path', 'yard-template', + '--default-return', 'undocumented'] + + desc 'Generate YARD Documentation (signpost, master)' + task :yard => ['yard:signpost', 'yard:master'] + + namespace :yard do + + desc '* eval markdown files' + task :eval_md do + Dir.chdir File.join(__dir__, 'docs-source') do + sh 'bundle exec md-ruby-eval --auto' + end + end + + task :update_readme do + Dir.chdir __dir__ do + content = File.read(File.join('README.md')). + gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_| + case $1 + when 'LockFreeLinkedSet' + "{Concurrent::Edge::#{$1} #{$1}}" + when '.dataflow' + '{Concurrent.dataflow Concurrent.dataflow}' + when 'thread pool' + '{file:thread_pools.md thread pool}' + else + "{Concurrent::#{$1} #{$1}}" + end + end + FileUtils.mkpath 'tmp' + File.write 'tmp/README.md', content + end + end + + define_yard_task = -> name do + output_dir = "docs/#{name}" + + removal_name = "remove.#{name}" + task removal_name do + Dir.chdir __dir__ do + FileUtils.rm_rf output_dir + end + end + + desc "* of #{name} into subdir #{name}" + YARD::Rake::YardocTask.new(name) do |yard| + yard.options.push( + '--output-dir', output_dir, + '--main', 'tmp/README.md', + *common_yard_options) + yard.files = ['./lib/concurrent-ruby/**/*.rb', + './lib/concurrent-ruby-edge/**/*.rb', + './ext/concurrent_ruby_ext/**/*.c', + '-', + 'docs-source/thread_pools.md', + 'docs-source/promises.out.md', + 'docs-source/medium-example.out.rb', + 'LICENSE.txt', + 'CHANGELOG.md'] + end + Rake::Task[name].prerequisites.push removal_name, + # 'yard:eval_md', + 'yard:update_readme' + end + + define_yard_task.call current_yard_version_name + define_yard_task.call 'master' + + desc "* signpost for versions" + YARD::Rake::YardocTask.new(:signpost) do |yard| + yard.options.push( + '--output-dir', 'docs', + '--main', 'docs-source/signpost.md', + *common_yard_options) + yard.files = ['no-lib'] + end + end + +rescue LoadError => e + puts 'YARD is not installed, skipping documentation task definitions: ' + e.message +end + +desc 'build, test, and publish the gem' +task :release => ['release:checks', 'release:build', 'release:test', 'release:publish'] + +namespace :release do + # Depends on environment of @pitr-ch + + task :checks do + raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME'] + + Dir.chdir(__dir__) do + sh 'test -z "$(git status --porcelain)"' do |ok, res| + unless ok + begin + status = `git status --porcelain` + STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + end + end + sh 'git fetch' + sh 'test $(git show-ref --verify --hash refs/heads/master) = ' + + '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res| + unless ok + begin + STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + end + end + end + end + + desc '* build all *.gem files necessary for release' + task :build => [:clobber, 'repackage:all'] + + desc '* test actual installed gems instead of cloned repository on MRI and JRuby' + task :test do + raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME'] + + Dir.chdir(__dir__) do + puts "Testing with the installed gem" + + Bundler.with_original_env do + sh 'ruby -v' + sh 'bundle install' + sh 'bundle exec rake spec:installed' + + env = { "PATH" => "#{ENV.fetch('CONCURRENT_JRUBY_HOME')}/bin:#{ENV['PATH']}" } + sh env, 'ruby -v' + sh env, 'bundle install' + sh env, 'bundle exec rake spec:installed' + end + + puts 'Windows build is untested' + end + end + + desc '* do all nested steps' + task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps'] + + namespace :publish do + publish_base = nil + publish_edge = nil + + task :ask do + begin + STDOUT.puts 'Do you want to publish anything now? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + exit 1 if input == 'n' + + begin + STDOUT.puts 'Do you want to publish `concurrent-ruby`? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + publish_base = input == 'y' + + begin + STDOUT.puts 'Do you want to publish `concurrent-ruby-edge`? (y/n)' + input = STDIN.gets.strip.downcase + end until %w(y n).include?(input) + publish_edge = input == 'y' + end + + desc '** tag HEAD with current version and push to github' + task :tag => :ask do + Dir.chdir(__dir__) do + sh "git tag v#{version}" if publish_base + sh "git push origin v#{version}" if publish_base + sh "git tag edge-v#{edge_version}" if publish_edge + sh "git push origin edge-v#{edge_version}" if publish_edge + end + end + + desc '** push all *.gem files to rubygems' + task :rubygems => :ask do + Dir.chdir(__dir__) do + sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base + sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge + sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base + sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base + sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base + end + end + + desc '** print post release steps' + task :post_steps do + puts + puts 'Manually: create a release on GitHub, use the "Generate release notes" button' + puts 'Manually: tweet' + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/ConcurrentRubyService.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/ConcurrentRubyService.java new file mode 100644 index 00000000..fb6be96d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/ConcurrentRubyService.java @@ -0,0 +1,17 @@ +import org.jruby.Ruby; +import org.jruby.runtime.load.BasicLibraryService; + +import java.io.IOException; + +public class ConcurrentRubyService implements BasicLibraryService { + + public boolean basicLoad(final Ruby runtime) throws IOException { + new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaSemaphoreLibrary().load(runtime, false); + new com.concurrent_ruby.ext.SynchronizationLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JRubyMapBackendLibrary().load(runtime, false); + return true; + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java new file mode 100644 index 00000000..4265b56a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java @@ -0,0 +1,140 @@ +package com.concurrent_ruby.ext; + +import static org.jruby.runtime.Visibility.PRIVATE; + +import java.lang.reflect.Field; +import java.io.IOException; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +/** + * This library adds an atomic reference type to JRuby for use in the atomic + * library. We do a native version to avoid the implicit value coercion that + * normally happens through JI. + * + * @author headius + */ +public class AtomicReferenceLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + try { + sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class); + atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR); + } catch (Exception e) { + // leave it as Java 6/7 version + } + atomicCls.defineAnnotatedMethods(JRubyReference.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference(runtime, klazz); + } + }; + + private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference8(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyReference", parent="Object") + public static class JRubyReference extends RubyObject { + volatile IRubyObject reference; + + static final sun.misc.Unsafe UNSAFE; + static final long referenceOffset; + + static { + try { + UNSAFE = UnsafeHolder.U; + Class k = JRubyReference.class; + referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference")); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public JRubyReference(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + UNSAFE.putObject(this, referenceOffset, context.nil); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + UNSAFE.putObject(this, referenceOffset, value); + return context.nil; + } + + @JRubyMethod(name = {"get", "value"}) + public IRubyObject get() { + return reference; + } + + @JRubyMethod(name = {"set", "value="}) + public IRubyObject set(IRubyObject newValue) { + UNSAFE.putObjectVolatile(this, referenceOffset, newValue); + return newValue; + } + + @JRubyMethod(name = "_compare_and_set", visibility = PRIVATE) + public IRubyObject compare_and_set(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { + Ruby runtime = context.runtime; + return runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, expectedValue, newValue)); + } + + @JRubyMethod(name = {"get_and_set", "swap"}) + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + // less-efficient version for Java 6 and 7 + while (true) { + IRubyObject oldValue = get(); + if (UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)) { + return oldValue; + } + } + } + } + + private static final class UnsafeHolder { + private UnsafeHolder(){} + + public static final sun.misc.Unsafe U = loadUnsafe(); + + private static sun.misc.Unsafe loadUnsafe() { + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + return null; + } + } + } + + public static class JRubyReference8 extends JRubyReference { + public JRubyReference8(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @Override + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + // efficient version for Java 8 + return (IRubyObject)UNSAFE.getAndSetObject(this, referenceOffset, newValue); + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java new file mode 100644 index 00000000..a09f9162 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java @@ -0,0 +1,248 @@ +package com.concurrent_ruby.ext; + +import org.jruby.*; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8; +import com.concurrent_ruby.ext.jsr166e.nounsafe.*; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +import java.io.IOException; +import java.util.Map; + +import static org.jruby.runtime.Visibility.PRIVATE; + +/** + * Native Java implementation to avoid the JI overhead. + * + * @author thedarkone + */ +public class JRubyMapBackendLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyModule thread_safeMod = concurrentMod.defineModuleUnder("Collection"); + RubyClass jrubyRefClass = thread_safeMod.defineClassUnder("JRubyMapBackend", runtime.getObject(), BACKEND_ALLOCATOR); + jrubyRefClass.setAllocator(BACKEND_ALLOCATOR); + jrubyRefClass.defineAnnotatedMethods(JRubyMapBackend.class); + } + + private static final ObjectAllocator BACKEND_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyMapBackend(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyMapBackend", parent="Object") + public static class JRubyMapBackend extends RubyObject { + // Defaults used by the CHM + static final int DEFAULT_INITIAL_CAPACITY = 16; + static final float DEFAULT_LOAD_FACTOR = 0.75f; + + public static final boolean CAN_USE_UNSAFE_CHM = canUseUnsafeCHM(); + + private ConcurrentHashMap map; + + private static ConcurrentHashMap newCHM(int initialCapacity, float loadFactor) { + if (CAN_USE_UNSAFE_CHM) { + return new ConcurrentHashMapV8(initialCapacity, loadFactor); + } else { + return new com.concurrent_ruby.ext.jsr166e.nounsafe.ConcurrentHashMapV8(initialCapacity, loadFactor); + } + } + + private static ConcurrentHashMap newCHM() { + return newCHM(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + private static boolean canUseUnsafeCHM() { + try { + new com.concurrent_ruby.ext.jsr166e.ConcurrentHashMapV8(); // force class load and initialization + return true; + } catch (Throwable t) { // ensuring we really do catch everything + // Doug's Unsafe setup errors always have this "Could not ini.." message + if (isCausedBySecurityException(t)) { + return false; + } + throw (t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t)); + } + } + + private static boolean isCausedBySecurityException(Throwable t) { + while (t != null) { + if ((t.getMessage() != null && t.getMessage().contains("Could not initialize intrinsics")) || t instanceof SecurityException) { + return true; + } + t = t.getCause(); + } + return false; + } + + public JRubyMapBackend(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + map = newCHM(); + return context.getRuntime().getNil(); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject options) { + map = toCHM(context, options); + return context.getRuntime().getNil(); + } + + private ConcurrentHashMap toCHM(ThreadContext context, IRubyObject options) { + Ruby runtime = context.getRuntime(); + if (!options.isNil() && options.respondsTo("[]")) { + IRubyObject rInitialCapacity = options.callMethod(context, "[]", runtime.newSymbol("initial_capacity")); + IRubyObject rLoadFactor = options.callMethod(context, "[]", runtime.newSymbol("load_factor")); + int initialCapacity = !rInitialCapacity.isNil() ? RubyNumeric.num2int(rInitialCapacity.convertToInteger()) : DEFAULT_INITIAL_CAPACITY; + float loadFactor = !rLoadFactor.isNil() ? (float)RubyNumeric.num2dbl(rLoadFactor.convertToFloat()) : DEFAULT_LOAD_FACTOR; + return newCHM(initialCapacity, loadFactor); + } else { + return newCHM(); + } + } + + @JRubyMethod(name = "[]", required = 1) + public IRubyObject op_aref(ThreadContext context, IRubyObject key) { + IRubyObject value; + return ((value = map.get(key)) == null) ? context.getRuntime().getNil() : value; + } + + @JRubyMethod(name = {"[]="}, required = 2) + public IRubyObject op_aset(IRubyObject key, IRubyObject value) { + map.put(key, value); + return value; + } + + @JRubyMethod + public IRubyObject put_if_absent(IRubyObject key, IRubyObject value) { + IRubyObject result = map.putIfAbsent(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute_if_absent(final ThreadContext context, final IRubyObject key, final Block block) { + return map.computeIfAbsent(key, new ConcurrentHashMap.Fun() { + @Override + public IRubyObject apply(IRubyObject key) { + return block.yieldSpecific(context); + } + }); + } + + @JRubyMethod + public IRubyObject compute_if_present(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.computeIfPresent(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject compute(final ThreadContext context, final IRubyObject key, final Block block) { + IRubyObject result = map.compute(key, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject key, IRubyObject oldValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject merge_pair(final ThreadContext context, final IRubyObject key, final IRubyObject value, final Block block) { + IRubyObject result = map.merge(key, value, new ConcurrentHashMap.BiFun() { + @Override + public IRubyObject apply(IRubyObject oldValue, IRubyObject newValue) { + IRubyObject result = block.yieldSpecific(context, oldValue == null ? context.getRuntime().getNil() : oldValue); + return result.isNil() ? null : result; + } + }); + return result == null ? context.getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObject newValue) { + return getRuntime().newBoolean(map.replace(key, oldValue, newValue)); + } + + @JRubyMethod(name = "key?", required = 1) + public RubyBoolean has_key_p(IRubyObject key) { + return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse(); + } + + @JRubyMethod + public IRubyObject key(IRubyObject value) { + final IRubyObject key = map.findKey(value); + return key == null ? getRuntime().getNil() : key; + } + + @JRubyMethod + public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) { + IRubyObject result = map.replace(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject get_and_set(IRubyObject key, IRubyObject value) { + IRubyObject result = map.put(key, value); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public IRubyObject delete(IRubyObject key) { + IRubyObject result = map.remove(key); + return result == null ? getRuntime().getNil() : result; + } + + @JRubyMethod + public RubyBoolean delete_pair(IRubyObject key, IRubyObject value) { + return getRuntime().newBoolean(map.remove(key, value)); + } + + @JRubyMethod + public IRubyObject clear() { + map.clear(); + return this; + } + + @JRubyMethod + public IRubyObject each_pair(ThreadContext context, Block block) { + for (Map.Entry entry : map.entrySet()) { + block.yieldSpecific(context, entry.getKey(), entry.getValue()); + } + return this; + } + + @JRubyMethod + public RubyFixnum size(ThreadContext context) { + return context.getRuntime().newFixnum(map.size()); + } + + @JRubyMethod + public IRubyObject get_or_default(IRubyObject key, IRubyObject defaultValue) { + return map.getValueOrDefault(key, defaultValue); + } + + @JRubyMethod(visibility = PRIVATE) + public JRubyMapBackend initialize_copy(ThreadContext context, IRubyObject other) { + map = newCHM(); + return this; + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java new file mode 100644 index 00000000..b5660762 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java @@ -0,0 +1,93 @@ +package com.concurrent_ruby.ext; + +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyNil; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class JavaAtomicBooleanLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicBoolean", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + atomicCls.defineAnnotatedMethods(JavaAtomicBoolean.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicBoolean(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicBoolean", parent = "Object") + public static class JavaAtomicBoolean extends RubyObject { + + private AtomicBoolean atomicBoolean; + + public JavaAtomicBoolean(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + atomicBoolean = new AtomicBoolean(convertRubyBooleanToJavaBoolean(value)); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + atomicBoolean = new AtomicBoolean(); + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject value() { + return getRuntime().newBoolean(atomicBoolean.get()); + } + + @JRubyMethod(name = "true?") + public IRubyObject isAtomicTrue() { + return getRuntime().newBoolean(atomicBoolean.get()); + } + + @JRubyMethod(name = "false?") + public IRubyObject isAtomicFalse() { + return getRuntime().newBoolean((atomicBoolean.get() == false)); + } + + @JRubyMethod(name = "value=") + public IRubyObject setAtomic(ThreadContext context, IRubyObject newValue) { + atomicBoolean.set(convertRubyBooleanToJavaBoolean(newValue)); + return context.nil; + } + + @JRubyMethod(name = "make_true") + public IRubyObject makeTrue() { + return getRuntime().newBoolean(atomicBoolean.compareAndSet(false, true)); + } + + @JRubyMethod(name = "make_false") + public IRubyObject makeFalse() { + return getRuntime().newBoolean(atomicBoolean.compareAndSet(true, false)); + } + + private boolean convertRubyBooleanToJavaBoolean(IRubyObject newValue) { + if (newValue instanceof RubyBoolean.False || newValue instanceof RubyNil) { + return false; + } else { + return true; + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java new file mode 100644 index 00000000..672bfc04 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java @@ -0,0 +1,113 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyFixnum; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; +import org.jruby.runtime.Block; + +public class JavaAtomicFixnumLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + + atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicFixnum(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicFixnum", parent = "Object") + public static class JavaAtomicFixnum extends RubyObject { + + private AtomicLong atomicLong; + + public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + this.atomicLong = new AtomicLong(0); + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + this.atomicLong = new AtomicLong(rubyFixnumToLong(value)); + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject getValue() { + return getRuntime().newFixnum(atomicLong.get()); + } + + @JRubyMethod(name = "value=") + public IRubyObject setValue(ThreadContext context, IRubyObject newValue) { + atomicLong.set(rubyFixnumToLong(newValue)); + return context.nil; + } + + @JRubyMethod(name = {"increment", "up"}) + public IRubyObject increment() { + return getRuntime().newFixnum(atomicLong.incrementAndGet()); + } + + @JRubyMethod(name = {"increment", "up"}) + public IRubyObject increment(IRubyObject value) { + long delta = rubyFixnumToLong(value); + return getRuntime().newFixnum(atomicLong.addAndGet(delta)); + } + + @JRubyMethod(name = {"decrement", "down"}) + public IRubyObject decrement() { + return getRuntime().newFixnum(atomicLong.decrementAndGet()); + } + + @JRubyMethod(name = {"decrement", "down"}) + public IRubyObject decrement(IRubyObject value) { + long delta = rubyFixnumToLong(value); + return getRuntime().newFixnum(atomicLong.addAndGet(-delta)); + } + + @JRubyMethod(name = "compare_and_set") + public IRubyObject compareAndSet(ThreadContext context, IRubyObject expect, IRubyObject update) { + return getRuntime().newBoolean(atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update))); + } + + @JRubyMethod + public IRubyObject update(ThreadContext context, Block block) { + for (;;) { + long _oldValue = atomicLong.get(); + IRubyObject oldValue = getRuntime().newFixnum(_oldValue); + IRubyObject newValue = block.yield(context, oldValue); + if (atomicLong.compareAndSet(_oldValue, rubyFixnumToLong(newValue))) { + return newValue; + } + } + } + + private long rubyFixnumToLong(IRubyObject value) { + if (value instanceof RubyFixnum) { + RubyFixnum fixNum = (RubyFixnum) value; + return fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError("value must be a Fixnum"); + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java new file mode 100644 index 00000000..d887f250 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java @@ -0,0 +1,189 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +import java.util.concurrent.Semaphore; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyFixnum; +import org.jruby.RubyModule; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +public class JavaSemaphoreLibrary { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaSemaphore", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + + atomicCls.defineAnnotatedMethods(JavaSemaphore.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaSemaphore(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaSemaphore", parent = "Object") + public static class JavaSemaphore extends RubyObject { + + private JRubySemaphore semaphore; + + public JavaSemaphore(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + this.semaphore = new JRubySemaphore(rubyFixnumInt(value, "count")); + return context.nil; + } + + @JRubyMethod + public IRubyObject acquire(ThreadContext context, final Block block) throws InterruptedException { + return this.acquire(context, 1, block); + } + + @JRubyMethod + public IRubyObject acquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException { + return this.acquire(context, rubyFixnumToPositiveInt(permits, "permits"), block); + } + + @JRubyMethod(name = "available_permits") + public IRubyObject availablePermits(ThreadContext context) { + return getRuntime().newFixnum(this.semaphore.availablePermits()); + } + + @JRubyMethod(name = "drain_permits") + public IRubyObject drainPermits(ThreadContext context) { + return getRuntime().newFixnum(this.semaphore.drainPermits()); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, final Block block) throws InterruptedException { + int permitsInt = 1; + boolean acquired = semaphore.tryAcquire(permitsInt); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException { + int permitsInt = rubyFixnumToPositiveInt(permits, "permits"); + boolean acquired = semaphore.tryAcquire(permitsInt); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod(name = "try_acquire") + public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout, final Block block) throws InterruptedException { + int permitsInt = rubyFixnumToPositiveInt(permits, "permits"); + boolean acquired = semaphore.tryAcquire( + permitsInt, + rubyNumericToLong(timeout, "timeout"), + java.util.concurrent.TimeUnit.SECONDS + ); + + return triedAcquire(context, permitsInt, acquired, block); + } + + @JRubyMethod + public IRubyObject release(ThreadContext context) { + this.semaphore.release(1); + return getRuntime().newBoolean(true); + } + + @JRubyMethod + public IRubyObject release(ThreadContext context, IRubyObject permits) { + this.semaphore.release(rubyFixnumToPositiveInt(permits, "permits")); + return getRuntime().newBoolean(true); + } + + @JRubyMethod(name = "reduce_permits") + public IRubyObject reducePermits(ThreadContext context, IRubyObject reduction) throws InterruptedException { + this.semaphore.publicReducePermits(rubyFixnumToNonNegativeInt(reduction, "reduction")); + return context.nil; + } + + private IRubyObject acquire(ThreadContext context, int permits, final Block block) throws InterruptedException { + this.semaphore.acquire(permits); + + if (!block.isGiven()) return context.nil; + + try { + return block.yieldSpecific(context); + } finally { + this.semaphore.release(permits); + } + } + + private IRubyObject triedAcquire(ThreadContext context, int permits, boolean acquired, final Block block) { + if (!block.isGiven()) return getRuntime().newBoolean(acquired); + if (!acquired) return context.nil; + + try { + return block.yieldSpecific(context); + } finally { + this.semaphore.release(permits); + } + } + + private int rubyFixnumInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be integer"); + } + } + + private int rubyFixnumToNonNegativeInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() >= 0) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be a non-negative integer"); + } + } + + private int rubyFixnumToPositiveInt(IRubyObject value, String paramName) { + if (value instanceof RubyFixnum && ((RubyFixnum) value).getLongValue() > 0) { + RubyFixnum fixNum = (RubyFixnum) value; + return (int) fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be an integer greater than zero"); + } + } + + private long rubyNumericToLong(IRubyObject value, String paramName) { + if (value instanceof RubyNumeric && ((RubyNumeric) value).getDoubleValue() > 0) { + RubyNumeric fixNum = (RubyNumeric) value; + return fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError(paramName + " must be a float greater than zero"); + } + } + + class JRubySemaphore extends Semaphore { + + public JRubySemaphore(int permits) { + super(permits); + } + + public JRubySemaphore(int permits, boolean value) { + super(permits, value); + } + + public void publicReducePermits(int i) { + reducePermits(i); + } + + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java new file mode 100644 index 00000000..f0c75ee4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java @@ -0,0 +1,292 @@ +package com.concurrent_ruby.ext; + +import org.jruby.Ruby; +import org.jruby.RubyBasicObject; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.RubyThread; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.Visibility; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; +import sun.misc.Unsafe; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class SynchronizationLibrary implements Library { + + private static final Unsafe UNSAFE = loadUnsafe(); + private static final boolean FULL_FENCE = supportsFences(); + + private static Unsafe loadUnsafe() { + try { + Class ncdfe = Class.forName("sun.misc.Unsafe"); + Field f = ncdfe.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get((java.lang.Object) null); + } catch (Exception var2) { + return null; + } catch (NoClassDefFoundError var3) { + return null; + } + } + + private static boolean supportsFences() { + if (UNSAFE == null) { + return false; + } else { + try { + Method m = UNSAFE.getClass().getDeclaredMethod("fullFence", new Class[0]); + if (m != null) { + return true; + } + } catch (Exception var1) { + // nothing + } + + return false; + } + } + + private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new Object(runtime, klazz); + } + }; + + private static final ObjectAllocator ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new AbstractLockableObject(runtime, klazz); + } + }; + + private static final ObjectAllocator JRUBY_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyLockableObject(runtime, klazz); + } + }; + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule synchronizationModule = runtime. + defineModule("Concurrent"). + defineModuleUnder("Synchronization"); + + RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile"); + jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class); + + defineClass(runtime, synchronizationModule, "AbstractObject", "Object", + Object.class, OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject", + AbstractLockableObject.class, ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "AbstractLockableObject", "JRubyLockableObject", + JRubyLockableObject.class, JRUBY_LOCKABLE_OBJECT_ALLOCATOR); + + defineClass(runtime, synchronizationModule, "Object", "JRuby", + JRuby.class, new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRuby(runtime, klazz); + } + }); + } + + private RubyClass defineClass( + Ruby runtime, + RubyModule namespace, + String parentName, + String name, + Class javaImplementation, + ObjectAllocator allocator) { + final RubyClass parentClass = namespace.getClass(parentName); + + if (parentClass == null) { + System.out.println("not found " + parentName); + throw runtime.newRuntimeError(namespace.toString() + "::" + parentName + " is missing"); + } + + final RubyClass newClass = namespace.defineClassUnder(name, parentClass, allocator); + newClass.defineAnnotatedMethods(javaImplementation); + return newClass; + } + + // Facts: + // - all ivar reads are without any synchronisation of fences see + // https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110 + // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor + // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or + // volatilePut + // TODO (pitr 16-Sep-2015): what do we do in Java 9 ? + + // module JRubyAttrVolatile + public static class JRubyAttrVolatile { + + // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic + // on volatile fields. any volatile field could have been used but using the thread context is an + // attempt to avoid code elimination. + private static volatile int volatileField; + + @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject module) { + // Prevent reordering of ivar writes with publication of this instance + if (!FULL_FENCE) { + // Assuming that following volatile read and write is not eliminated it simulates fullFence. + // If it's eliminated it'll cause problems only on non-x86 platforms. + // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding + final int volatileRead = volatileField; + volatileField = context.getLine(); + } else { + UNSAFE.fullFence(); + } + return context.nil; + } + + @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject instanceVariableGetVolatile( + ThreadContext context, + IRubyObject module, + IRubyObject self, + IRubyObject name) { + // Ensure we ses latest value with loadFence + if (!FULL_FENCE) { + // piggybacking on volatile read, simulating loadFence + final int volatileRead = volatileField; + return ((RubyBasicObject) self).instance_variable_get(context, name); + } else { + UNSAFE.loadFence(); + return ((RubyBasicObject) self).instance_variable_get(context, name); + } + } + + @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject InstanceVariableSetVolatile( + ThreadContext context, + IRubyObject module, + IRubyObject self, + IRubyObject name, + IRubyObject value) { + // Ensure we make last update visible + if (!FULL_FENCE) { + // piggybacking on volatile write, simulating storeFence + final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value); + volatileField = context.getLine(); + return result; + } else { + // JRuby uses StampedVariableAccessor which calls fullFence + // so no additional steps needed. + // See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159 + return ((RubyBasicObject) self).instance_variable_set(name, value); + } + } + } + + @JRubyClass(name = "Object", parent = "AbstractObject") + public static class Object extends RubyObject { + + public Object(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + } + + @JRubyClass(name = "AbstractLockableObject", parent = "Object") + public static class AbstractLockableObject extends Object { + + public AbstractLockableObject(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + } + + @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject") + public static class JRubyLockableObject extends AbstractLockableObject { + + public JRubyLockableObject(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod(name = "synchronize", visibility = Visibility.PROTECTED) + public IRubyObject rubySynchronize(ThreadContext context, Block block) { + synchronized (this) { + return block.yield(context, null); + } + } + + @JRubyMethod(name = "ns_wait", optional = 1, visibility = Visibility.PROTECTED) + public IRubyObject nsWait(ThreadContext context, IRubyObject[] args) { + Ruby runtime = context.runtime; + if (args.length > 1) { + throw runtime.newArgumentError(args.length, 1); + } + Double timeout = null; + if (args.length > 0 && !args[0].isNil()) { + timeout = args[0].convertToFloat().getDoubleValue(); + if (timeout < 0) { + throw runtime.newArgumentError("time interval must be positive"); + } + } + if (Thread.interrupted()) { + throw runtime.newConcurrencyError("thread interrupted"); + } + boolean success = false; + try { + success = context.getThread().wait_timeout(this, timeout); + } catch (InterruptedException ie) { + throw runtime.newConcurrencyError(ie.getLocalizedMessage()); + } finally { + // An interrupt or timeout may have caused us to miss + // a notify that we consumed, so do another notify in + // case someone else is available to pick it up. + if (!success) { + this.notify(); + } + } + return this; + } + + @JRubyMethod(name = "ns_signal", visibility = Visibility.PROTECTED) + public IRubyObject nsSignal(ThreadContext context) { + notify(); + return this; + } + + @JRubyMethod(name = "ns_broadcast", visibility = Visibility.PROTECTED) + public IRubyObject nsBroadcast(ThreadContext context) { + notifyAll(); + return this; + } + } + + @JRubyClass(name = "JRuby") + public static class JRuby extends RubyObject { + public JRuby(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod(name = "sleep_interruptibly", visibility = Visibility.PUBLIC, module = true) + public static IRubyObject sleepInterruptibly(final ThreadContext context, IRubyObject receiver, final Block block) { + try { + context.getThread().executeBlockingTask(new RubyThread.BlockingTask() { + @Override + public void run() throws InterruptedException { + block.call(context); + } + + @Override + public void wakeup() { + context.getThread().getNativeThread().interrupt(); + } + }); + } catch (InterruptedException e) { + throw context.runtime.newThreadError("interrupted in Concurrent::Synchronization::JRuby.sleep_interruptibly"); + } + return context.nil; + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java new file mode 100644 index 00000000..e11e15aa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java @@ -0,0 +1,31 @@ +package com.concurrent_ruby.ext.jsr166e; + +import java.util.Map; +import java.util.Set; + +public interface ConcurrentHashMap { + /** Interface describing a function of one argument */ + public interface Fun { T apply(A a); } + /** Interface describing a function of two arguments */ + public interface BiFun { T apply(A a, B b); } + + public V get(K key); + public V put(K key, V value); + public V putIfAbsent(K key, V value); + public V computeIfAbsent(K key, Fun mf); + public V computeIfPresent(K key, BiFun mf); + public V compute(K key, BiFun mf); + public V merge(K key, V value, BiFun mf); + public boolean replace(K key, V oldVal, V newVal); + public V replace(K key, V value); + public boolean containsKey(K key); + public boolean remove(Object key, Object value); + public V remove(K key); + public void clear(); + public Set> entrySet(); + public int size(); + public V getValueOrDefault(Object key, V defaultValue); + + public boolean containsValue(V value); + public K findKey(V value); +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java new file mode 100644 index 00000000..dc9901fb --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java @@ -0,0 +1,3863 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package com.concurrent_ruby.ext.jsr166e; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

    + *
  • forEach: Perform a given action on each element. + * A variant form applies a given transformation on each element + * before performing the action.
  • + * + *
  • search: Return the first available non-null result of + * applying a given function on each element; skipping further + * search when a result is found.
  • + * + *
  • reduce: Accumulate each element. The supplied reduction + * function cannot rely on ordering (more formally, it should be + * both associative and commutative). There are five variants: + * + *
      + * + *
    • Plain reductions. (There is not a form of this method for + * (key, value) function arguments since there is no corresponding + * return type.)
    • + * + *
    • Mapped reductions that accumulate the results of a given + * function applied to each element.
    • + * + *
    • Reductions to scalar doubles, longs, and ints, using a + * given basis value.
    • + * + * + *
    + *
+ * + *

The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

All arguments to all task methods must be non-null. + * + *

jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

This interface exports a subset of expected JDK8 + * functionality. + * + *

Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

+     * {@code ConcurrentHashMapV8 m = ...
+     * // split as if have 8 * parallelism, for load balance
+     * int n = m.size();
+     * int p = aForkJoinPool.getParallelism() * 8;
+     * int split = (n < p)? n : p;
+     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
+     * // ...
+     * static class SumValues extends RecursiveTask {
+     *   final Spliterator s;
+     *   final int split;             // split while > 1
+     *   final SumValues nextJoin;    // records forked subtasks to join
+     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
+     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
+     *   }
+     *   public Long compute() {
+     *     long sum = 0;
+     *     SumValues subtasks = null; // fork subtasks
+     *     for (int s = split >>> 1; s > 0; s >>>= 1)
+     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
+     *     while (s.hasNext())        // directly process remaining elements
+     *       sum += s.next();
+     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
+     *       sum += t.join();         // collect subtask results
+     *     return sum;
+     *   }
+     * }
+     * }
+ */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments referring to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile Node[] table; + + /** + * The counter maintaining number of elements. + */ + private transient final LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(Node[] tab, int i) { // used by Iter + return (Node)UNSAFE.getObjectVolatile(tab, ((long)i< 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(Node[] tab, int i) { + if (tab != null && i >= 0 && i < tab.length) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + + // Unsafe mechanics for casHash + private static final sun.misc.Unsafe UNSAFE; + private static final long hashOffset; + + static { + try { + UNSAFE = getUnsafe(); + Class k = Node.class; + hashOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("hash")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(Node[] tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (Node[] tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (Node[])ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (Node[])fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (Node[] tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final Node[] initTable() { + Node[] tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + Node[] tab; int n, sc; + while ((tab = table) != null && + (n = tab.length) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + Node[] tab = table; int n; + if (tab == null || (n = tab.length) == 0) { + n = (sc > c) ? sc : c; + if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = new Node[n]; + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final Node[] rebuild(Node[] tab) { + int n = tab.length; + Node[] nextTab = new Node[n << 1]; + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(Node[] nextTab, int i, Node e) { + int bit = nextTab.length >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(Node[] nextTab, int i, TreeBin t) { + int bit = nextTab.length >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + Node[] tab = table; + while (tab != null && i < tab.length) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (Node[])fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + Node[] tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; Node[] t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length; + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + Node[] t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length; + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length; + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (Node[])ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

 {@code
+     * if (map.containsKey(key))
+     *   return map.get(key);
+     * value = mappingFunction.apply(key);
+     * if (value != null)
+     *   map.put(key, value);
+     * return value;}
+ * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
 {@code
+     * map.computeIfAbsent(key, new Fun() {
+     *   public V map(K k) { return new Value(f(k)); }});}
+ * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
 {@code
+     *   if (map.containsKey(key)) {
+     *     value = remappingFunction.apply(key, map.get(key));
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
 {@code
+     *   value = remappingFunction.apply(key, map.get(key));
+     *   if (value != null)
+     *     map.put(key, value);
+     *   else
+     *     map.remove(key);
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
 {@code
+     * Map map = ...;
+     * final String msg = ...;
+     * map.compute(key, new BiFun() {
+     *   public String apply(Key k, String v) {
+     *    return (v == null) ? msg : v + msg;});}}
+ * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
 {@code
+     *   if (!map.containsKey(key))
+     *     map.put(value);
+     *   else {
+     *     newValue = remappingFunction.apply(map.get(key), value);
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + UNSAFE.putObjectVolatile(this, counterOffset, new LongAdder()); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + UNSAFE.compareAndSwapInt(this, sizeCtlOffset, sc, -1)) { + try { + if (table == null) { + init = true; + Node[] tab = new Node[n]; + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + Node[] tab = table; + for (int i = 0; i < tab.length; ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long counterOffset; + private static final long sizeCtlOffset; + private static final long ABASE; + private static final int ASHIFT; + + static { + int ss; + try { + UNSAFE = getUnsafe(); + Class k = ConcurrentHashMapV8.class; + counterOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("counter")); + sizeCtlOffset = UNSAFE.objectFieldOffset + (k.getDeclaredField("sizeCtl")); + Class sc = Node[].class; + ABASE = UNSAFE.arrayBaseOffset(sc); + ss = UNSAFE.arrayIndexScale(sc); + } catch (Exception e) { + throw new Error(e); + } + if ((ss & (ss-1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(ss); + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java new file mode 100644 index 00000000..47a923c8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java @@ -0,0 +1,203 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package com.concurrent_ruby.ext.jsr166e; +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java new file mode 100644 index 00000000..93a277fb --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java @@ -0,0 +1,342 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package com.concurrent_ruby.ext.jsr166e; +import java.util.Random; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long valueOffset; + static { + try { + UNSAFE = getUnsafe(); + Class ak = Cell.class; + valueOffset = UNSAFE.objectFieldOffset + (ak.getDeclaredField("value")); + } catch (Exception e) { + throw new Error(e); + } + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long baseOffset; + private static final long busyOffset; + static { + try { + UNSAFE = getUnsafe(); + Class sk = Striped64.class; + baseOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("base")); + busyOffset = UNSAFE.objectFieldOffset + (sk.getDeclaredField("busy")); + } catch (Exception e) { + throw new Error(e); + } + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + return java.security.AccessController.doPrivileged + (new java.security + .PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + java.lang.reflect.Field f = sun.misc + .Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java new file mode 100644 index 00000000..a4e73ea1 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java @@ -0,0 +1,3800 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on the 1.79 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import org.jruby.RubyClass; +import org.jruby.RubyNumeric; +import org.jruby.RubyObject; +import org.jruby.exceptions.RaiseException; +import com.concurrent_ruby.ext.jsr166e.ConcurrentHashMap; +import com.concurrent_ruby.ext.jsr166y.ThreadLocalRandom; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; + +import java.io.Serializable; + +/** + * A hash table supporting full concurrency of retrievals and + * high expected concurrency for updates. This class obeys the + * same functional specification as {@link java.util.Hashtable}, and + * includes versions of methods corresponding to each method of + * {@code Hashtable}. However, even though all operations are + * thread-safe, retrieval operations do not entail locking, + * and there is not any support for locking the entire table + * in a way that prevents all access. This class is fully + * interoperable with {@code Hashtable} in programs that rely on its + * thread safety but not on its synchronization details. + * + *

Retrieval operations (including {@code get}) generally do not + * block, so may overlap with update operations (including {@code put} + * and {@code remove}). Retrievals reflect the results of the most + * recently completed update operations holding upon their + * onset. (More formally, an update operation for a given key bears a + * happens-before relation with any (non-null) retrieval for + * that key reporting the updated value.) For aggregate operations + * such as {@code putAll} and {@code clear}, concurrent retrievals may + * reflect insertion or removal of only some entries. Similarly, + * Iterators and Enumerations return elements reflecting the state of + * the hash table at some point at or since the creation of the + * iterator/enumeration. They do not throw {@link + * ConcurrentModificationException}. However, iterators are designed + * to be used by only one thread at a time. Bear in mind that the + * results of aggregate status methods including {@code size}, {@code + * isEmpty}, and {@code containsValue} are typically useful only when + * a map is not undergoing concurrent updates in other threads. + * Otherwise the results of these methods reflect transient states + * that may be adequate for monitoring or estimation purposes, but not + * for program control. + * + *

The table is dynamically expanded when there are too many + * collisions (i.e., keys that have distinct hash codes but fall into + * the same slot modulo the table size), with the expected average + * effect of maintaining roughly two bins per mapping (corresponding + * to a 0.75 load factor threshold for resizing). There may be much + * variance around this average as mappings are added and removed, but + * overall, this maintains a commonly accepted time/space tradeoff for + * hash tables. However, resizing this or any other kind of hash + * table may be a relatively slow operation. When possible, it is a + * good idea to provide a size estimate as an optional {@code + * initialCapacity} constructor argument. An additional optional + * {@code loadFactor} constructor argument provides a further means of + * customizing initial table capacity by specifying the table density + * to be used in calculating the amount of space to allocate for the + * given number of elements. Also, for compatibility with previous + * versions of this class, constructors may optionally specify an + * expected {@code concurrencyLevel} as an additional hint for + * internal sizing. Note that using many keys with exactly the same + * {@code hashCode()} is a sure way to slow down performance of any + * hash table. + * + *

A {@link Set} projection of a ConcurrentHashMapV8 may be created + * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed + * (using {@link #keySet(Object)} when only keys are of interest, and the + * mapped values are (perhaps transiently) not used or all take the + * same mapping value. + * + *

A ConcurrentHashMapV8 can be used as scalable frequency map (a + * form of histogram or multiset) by using {@link LongAdder} values + * and initializing via {@link #computeIfAbsent}. For example, to add + * a count to a {@code ConcurrentHashMapV8 freqs}, you + * can use {@code freqs.computeIfAbsent(k -> new + * LongAdder()).increment();} + * + *

This class and its views and iterators implement all of the + * optional methods of the {@link Map} and {@link Iterator} + * interfaces. + * + *

Like {@link Hashtable} but unlike {@link HashMap}, this class + * does not allow {@code null} to be used as a key or value. + * + *

ConcurrentHashMapV8s support parallel operations using the {@link + * ForkJoinPool#commonPool}. (Tasks that may be used in other contexts + * are available in class {@link ForkJoinTasks}). These operations are + * designed to be safely, and often sensibly, applied even with maps + * that are being concurrently updated by other threads; for example, + * when computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and (Key, + * Value) arguments and/or return values. (The first three forms are + * also available via the {@link #keySet()}, {@link #values()} and + * {@link #entrySet()} views). Because the elements of a + * ConcurrentHashMapV8 are not ordered in any particular way, and may be + * processed in different orders in different parallel executions, the + * correctness of supplied functions should not depend on any + * ordering, or on any other objects or values that may transiently + * change while computation is in progress; and except for forEach + * actions, should ideally be side-effect-free. + * + *

+ * + *

The concurrency properties of bulk operations follow + * from those of ConcurrentHashMapV8: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

Parallel speedups for bulk operations compared to sequential + * processing are common but not guaranteed. Operations involving + * brief functions on small maps may execute more slowly than + * sequential loops if the underlying work to parallelize the + * computation is more expensive than the computation itself. + * Similarly, parallelization may not lead to much actual parallelism + * if all processors are busy performing unrelated tasks. + * + *

All arguments to all task methods must be non-null. + * + *

jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Doug Lea + * @param the type of keys maintained by this map + * @param the type of mapped values + */ +public class ConcurrentHashMapV8 + implements ConcurrentMap, Serializable, ConcurrentHashMap { + private static final long serialVersionUID = 7249069246763182397L; + + /** + * A partitionable iterator. A Spliterator can be traversed + * directly, but can also be partitioned (before traversal) by + * creating another Spliterator that covers a non-overlapping + * portion of the elements, and so may be amenable to parallel + * execution. + * + *

This interface exports a subset of expected JDK8 + * functionality. + * + *

Sample usage: Here is one (of the several) ways to compute + * the sum of the values held in a map using the ForkJoin + * framework. As illustrated here, Spliterators are well suited to + * designs in which a task repeatedly splits off half its work + * into forked subtasks until small enough to process directly, + * and then joins these subtasks. Variants of this style can also + * be used in completion-based designs. + * + *

+     * {@code ConcurrentHashMapV8 m = ...
+     * // split as if have 8 * parallelism, for load balance
+     * int n = m.size();
+     * int p = aForkJoinPool.getParallelism() * 8;
+     * int split = (n < p)? n : p;
+     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
+     * // ...
+     * static class SumValues extends RecursiveTask {
+     *   final Spliterator s;
+     *   final int split;             // split while > 1
+     *   final SumValues nextJoin;    // records forked subtasks to join
+     *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
+     *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
+     *   }
+     *   public Long compute() {
+     *     long sum = 0;
+     *     SumValues subtasks = null; // fork subtasks
+     *     for (int s = split >>> 1; s > 0; s >>>= 1)
+     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
+     *     while (s.hasNext())        // directly process remaining elements
+     *       sum += s.next();
+     *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
+     *       sum += t.join();         // collect subtask results
+     *     return sum;
+     *   }
+     * }
+     * }
+ */ + public static interface Spliterator extends Iterator { + /** + * Returns a Spliterator covering approximately half of the + * elements, guaranteed not to overlap with those subsequently + * returned by this Spliterator. After invoking this method, + * the current Spliterator will not produce any of + * the elements of the returned Spliterator, but the two + * Spliterators together will produce all of the elements that + * would have been produced by this Spliterator had this + * method not been called. The exact number of elements + * produced by the returned Spliterator is not guaranteed, and + * may be zero (i.e., with {@code hasNext()} reporting {@code + * false}) if this Spliterator cannot be further split. + * + * @return a Spliterator covering approximately half of the + * elements + * @throws IllegalStateException if this Spliterator has + * already commenced traversing elements + */ + Spliterator split(); + } + + + /* + * Overview: + * + * The primary design goal of this hash table is to maintain + * concurrent readability (typically method get(), but also + * iterators and related methods) while minimizing update + * contention. Secondary goals are to keep space consumption about + * the same or better than java.util.HashMap, and to support high + * initial insertion rates on an empty table by many threads. + * + * Each key-value mapping is held in a Node. Because Node fields + * can contain special values, they are defined using plain Object + * types. Similarly in turn, all internal methods that use them + * work off Object types. And similarly, so do the internal + * methods of auxiliary iterator and view classes. All public + * generic typed methods relay in/out of these internal methods, + * supplying null-checks and casts as needed. This also allows + * many of the public methods to be factored into a smaller number + * of internal methods (although sadly not so for the five + * variants of put-related operations). The validation-based + * approach explained below leads to a lot of code sprawl because + * retry-control precludes factoring into smaller methods. + * + * The table is lazily initialized to a power-of-two size upon the + * first insertion. Each bin in the table normally contains a + * list of Nodes (most often, the list has only zero or one Node). + * Table accesses require volatile/atomic reads, writes, and + * CASes. Because there is no other way to arrange this without + * adding further indirections, we use intrinsics + * (sun.misc.Unsafe) operations. The lists of nodes within bins + * are always accurately traversable under volatile reads, so long + * as lookups check hash code and non-nullness of value before + * checking key equality. + * + * We use the top two bits of Node hash fields for control + * purposes -- they are available anyway because of addressing + * constraints. As explained further below, these top bits are + * used as follows: + * 00 - Normal + * 01 - Locked + * 11 - Locked and may have a thread waiting for lock + * 10 - Node is a forwarding node + * + * The lower 30 bits of each Node's hash field contain a + * transformation of the key's hash code, except for forwarding + * nodes, for which the lower bits are zero (and so always have + * hash field == MOVED). + * + * Insertion (via put or its variants) of the first node in an + * empty bin is performed by just CASing it to the bin. This is + * by far the most common case for put operations under most + * key/hash distributions. Other update operations (insert, + * delete, and replace) require locks. We do not want to waste + * the space required to associate a distinct lock object with + * each bin, so instead use the first node of a bin list itself as + * a lock. Blocking support for these locks relies on the builtin + * "synchronized" monitors. However, we also need a tryLock + * construction, so we overlay these by using bits of the Node + * hash field for lock control (see above), and so normally use + * builtin monitors only for blocking and signalling using + * wait/notifyAll constructions. See Node.tryAwaitLock. + * + * Using the first node of a list as a lock does not by itself + * suffice though: When a node is locked, any update must first + * validate that it is still the first node after locking it, and + * retry if not. Because new nodes are always appended to lists, + * once a node is first in a bin, it remains first until deleted + * or the bin becomes invalidated (upon resizing). However, + * operations that only conditionally update may inspect nodes + * until the point of update. This is a converse of sorts to the + * lazy locking technique described by Herlihy & Shavit. + * + * The main disadvantage of per-bin locks is that other update + * operations on other nodes in a bin list protected by the same + * lock can stall, for example when user equals() or mapping + * functions take a long time. However, statistically, under + * random hash codes, this is not a common problem. Ideally, the + * frequency of nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average, given the resizing threshold + * of 0.75, although with a large variance because of resizing + * granularity. Ignoring variance, the expected occurrences of + * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The + * first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * Lock contention probability for two threads accessing distinct + * elements is roughly 1 / (8 * #elements) under random hashes. + * + * Actual hash code distributions encountered in practice + * sometimes deviate significantly from uniform randomness. This + * includes the case when N > (1<<30), so some keys MUST collide. + * Similarly for dumb or hostile usages in which multiple keys are + * designed to have identical hash codes. Also, although we guard + * against the worst effects of this (see method spread), sets of + * hashes may differ only in bits that do not impact their bin + * index for a given power-of-two mask. So we use a secondary + * strategy that applies when the number of nodes in a bin exceeds + * a threshold, and at least one of the keys implements + * Comparable. These TreeBins use a balanced tree to hold nodes + * (a specialized form of red-black trees), bounding search time + * to O(log N). Each search step in a TreeBin is around twice as + * slow as in a regular list, but given that N cannot exceed + * (1<<64) (before running out of addresses) this bounds search + * steps, lock hold times, etc, to reasonable constants (roughly + * 100 nodes inspected per operation worst case) so long as keys + * are Comparable (which is very common -- String, Long, etc). + * TreeBin nodes (TreeNodes) also maintain the same "next" + * traversal pointers as regular nodes, so can be traversed in + * iterators in the same way. + * + * The table is resized when occupancy exceeds a percentage + * threshold (nominally, 0.75, but see below). Only a single + * thread performs the resize (using field "sizeCtl", to arrange + * exclusion), but the table otherwise remains usable for reads + * and updates. Resizing proceeds by transferring bins, one by + * one, from the table to the next table. Because we are using + * power-of-two expansion, the elements from each bin must either + * stay at same index, or move with a power of two offset. We + * eliminate unnecessary node creation by catching cases where old + * nodes can be reused because their next fields won't change. On + * average, only about one-sixth of them need cloning when a table + * doubles. The nodes they replace will be garbage collectable as + * soon as they are no longer referenced by any reader thread that + * may be in the midst of concurrently traversing table. Upon + * transfer, the old table bin contains only a special forwarding + * node (with hash field "MOVED") that contains the next table as + * its key. On encountering a forwarding node, access and update + * operations restart, using the new table. + * + * Each bin transfer requires its bin lock. However, unlike other + * cases, a transfer can skip a bin if it fails to acquire its + * lock, and revisit it later (unless it is a TreeBin). Method + * rebuild maintains a buffer of TRANSFER_BUFFER_SIZE bins that + * have been skipped because of failure to acquire a lock, and + * blocks only if none are available (i.e., only very rarely). + * The transfer operation must also ensure that all accessible + * bins in both the old and new table are usable by any traversal. + * When there are no lock acquisition failures, this is arranged + * simply by proceeding from the last bin (table.length - 1) up + * towards the first. Upon seeing a forwarding node, traversals + * (see class Iter) arrange to move to the new table + * without revisiting nodes. However, when any node is skipped + * during a transfer, all earlier table bins may have become + * visible, so are initialized with a reverse-forwarding node back + * to the old table until the new ones are established. (This + * sometimes requires transiently locking a forwarding node, which + * is possible under the above encoding.) These more expensive + * mechanics trigger only when necessary. + * + * The traversal scheme also applies to partial traversals of + * ranges of bins (via an alternate Traverser constructor) + * to support partitioned aggregate operations. Also, read-only + * operations give up if ever forwarded to a null table, which + * provides support for shutdown-style clearing, which is also not + * currently implemented. + * + * Lazy table initialization minimizes footprint until first use, + * and also avoids resizings when the first operation is from a + * putAll, constructor with map argument, or deserialization. + * These cases attempt to override the initial capacity settings, + * but harmlessly fail to take effect in cases of races. + * + * The element count is maintained using a LongAdder, which avoids + * contention on updates but can encounter cache thrashing if read + * too frequently during concurrent access. To avoid reading so + * often, resizing is attempted either when a bin lock is + * contended, or upon adding to a bin already holding two or more + * nodes (checked before adding in the xIfAbsent methods, after + * adding in others). Under uniform hash distributions, the + * probability of this occurring at threshold is around 13%, + * meaning that only about 1 in 8 puts check threshold (and after + * resizing, many fewer do so). But this approximation has high + * variance for small table sizes, so we check on any collision + * for sizes <= 64. The bulk putAll operation further reduces + * contention by only committing count updates upon these size + * checks. + * + * Maintaining API and serialization compatibility with previous + * versions of this class introduces several oddities. Mainly: We + * leave untouched but unused constructor arguments referring to + * concurrencyLevel. We accept a loadFactor constructor argument, + * but apply it only to initial table capacity (which is the only + * time that we can guarantee to honor it.) We also declare an + * unused "Segment" class that is instantiated in minimal form + * only when serializing. + */ + + /* ---------------- Constants -------------- */ + + /** + * The largest possible table capacity. This value must be + * exactly 1<<30 to stay within Java array allocation and indexing + * bounds for power of two table sizes, and is further required + * because the top two bits of 32bit hash fields are used for + * control purposes. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The default initial table capacity. Must be a power of 2 + * (i.e., at least 1) and at most MAXIMUM_CAPACITY. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * The largest possible (non-power of two) array size. + * Needed by toArray and related methods. + */ + static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * The default concurrency level for this table. Unused but + * defined for compatibility with previous versions of this class. + */ + private static final int DEFAULT_CONCURRENCY_LEVEL = 16; + + /** + * The load factor for this table. Overrides of this value in + * constructors affect only the initial table capacity. The + * actual floating point value isn't normally used -- it is + * simpler to use expressions such as {@code n - (n >>> 2)} for + * the associated resizing threshold. + */ + private static final float LOAD_FACTOR = 0.75f; + + /** + * The buffer size for skipped bins during transfers. The + * value is arbitrary but should be large enough to avoid + * most locking stalls during resizes. + */ + private static final int TRANSFER_BUFFER_SIZE = 32; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. The value reflects the approximate break-even point for + * using tree-based operations. + * Note that Doug's version defaults to 8, but when dealing with + * Ruby objects it is actually beneficial to avoid TreeNodes + * as long as possible as it usually means going into Ruby land. + */ + private static final int TREE_THRESHOLD = 16; + + /* + * Encodings for special uses of Node hash fields. See above for + * explanation. + */ + static final int MOVED = 0x80000000; // hash field for forwarding nodes + static final int LOCKED = 0x40000000; // set/tested only as a bit + static final int WAITING = 0xc0000000; // both bits set/tested together + static final int HASH_BITS = 0x3fffffff; // usable bits of normal node hash + + /* ---------------- Fields -------------- */ + + /** + * The array of bins. Lazily initialized upon first insertion. + * Size is always a power of two. Accessed directly by iterators. + */ + transient volatile AtomicReferenceArray table; + + /** + * The counter maintaining number of elements. + */ + private transient LongAdder counter; + + /** + * Table initialization and resizing control. When negative, the + * table is being initialized or resized. Otherwise, when table is + * null, holds the initial table size to use upon creation, or 0 + * for default. After initialization, holds the next element count + * value upon which to resize the table. + */ + private transient volatile int sizeCtl; + + // views + private transient KeySetView keySet; + private transient ValuesView values; + private transient EntrySetView entrySet; + + /** For serialization compatibility. Null unless serialized; see below */ + private Segment[] segments; + + static AtomicIntegerFieldUpdater SIZE_CTRL_UPDATER = AtomicIntegerFieldUpdater.newUpdater(ConcurrentHashMapV8.class, "sizeCtl"); + + /* ---------------- Table element access -------------- */ + + /* + * Volatile access methods are used for table elements as well as + * elements of in-progress next table while resizing. Uses are + * null checked by callers, and implicitly bounds-checked, relying + * on the invariants that tab arrays have non-zero size, and all + * indices are masked with (tab.length - 1) which is never + * negative and always less than length. Note that, to be correct + * wrt arbitrary concurrency errors by users, bounds checks must + * operate on local variables, which accounts for some odd-looking + * inline assignments below. + */ + + static final Node tabAt(AtomicReferenceArray tab, int i) { // used by Iter + return tab.get(i); + } + + private static final boolean casTabAt(AtomicReferenceArray tab, int i, Node c, Node v) { + return tab.compareAndSet(i, c, v); + } + + private static final void setTabAt(AtomicReferenceArray tab, int i, Node v) { + tab.set(i, v); + } + + /* ---------------- Nodes -------------- */ + + /** + * Key-value entry. Note that this is never exported out as a + * user-visible Map.Entry (see MapEntry below). Nodes with a hash + * field of MOVED are special, and do not contain user keys or + * values. Otherwise, keys are never null, and null val fields + * indicate that a node is in the process of being deleted or + * created. For purposes of read-only access, a key may be read + * before a val, but can only be used after checking val to be + * non-null. + */ + static class Node { + volatile int hash; + final Object key; + volatile Object val; + volatile Node next; + + static AtomicIntegerFieldUpdater HASH_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Node.class, "hash"); + + Node(int hash, Object key, Object val, Node next) { + this.hash = hash; + this.key = key; + this.val = val; + this.next = next; + } + + /** CompareAndSet the hash field */ + final boolean casHash(int cmp, int val) { + return HASH_UPDATER.compareAndSet(this, cmp, val); + } + + /** The number of spins before blocking for a lock */ + static final int MAX_SPINS = + Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; + + /** + * Spins a while if LOCKED bit set and this node is the first + * of its bin, and then sets WAITING bits on hash field and + * blocks (once) if they are still set. It is OK for this + * method to return even if lock is not available upon exit, + * which enables these simple single-wait mechanics. + * + * The corresponding signalling operation is performed within + * callers: Upon detecting that WAITING has been set when + * unlocking lock (via a failed CAS from non-waiting LOCKED + * state), unlockers acquire the sync lock and perform a + * notifyAll. + * + * The initial sanity check on tab and bounds is not currently + * necessary in the only usages of this method, but enables + * use in other future contexts. + */ + final void tryAwaitLock(AtomicReferenceArray tab, int i) { + if (tab != null && i >= 0 && i < tab.length()) { // sanity check + int r = ThreadLocalRandom.current().nextInt(); // randomize spins + int spins = MAX_SPINS, h; + while (tabAt(tab, i) == this && ((h = hash) & LOCKED) != 0) { + if (spins >= 0) { + r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift + if (r >= 0 && --spins == 0) + Thread.yield(); // yield before block + } + else if (casHash(h, h | WAITING)) { + synchronized (this) { + if (tabAt(tab, i) == this && + (hash & WAITING) == WAITING) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + else + notifyAll(); // possibly won race vs signaller + } + break; + } + } + } + } + } + + /* ---------------- TreeBins -------------- */ + + /** + * Nodes for use in TreeBins + */ + static final class TreeNode extends Node { + TreeNode parent; // red-black tree links + TreeNode left; + TreeNode right; + TreeNode prev; // needed to unlink next upon deletion + boolean red; + + TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) { + super(hash, key, val, next); + this.parent = parent; + } + } + + /** + * A specialized form of red-black tree for use in bins + * whose size exceeds a threshold. + * + * TreeBins use a special form of comparison for search and + * related operations (which is the main reason we cannot use + * existing collections such as TreeMaps). TreeBins contain + * Comparable elements, but may contain others, as well as + * elements that are Comparable but not necessarily Comparable + * for the same T, so we cannot invoke compareTo among them. To + * handle this, the tree is ordered primarily by hash value, then + * by getClass().getName() order, and then by Comparator order + * among elements of the same class. On lookup at a node, if + * elements are not comparable or compare as 0, both left and + * right children may need to be searched in the case of tied hash + * values. (This corresponds to the full list search that would be + * necessary if all elements were non-Comparable and had tied + * hashes.) The red-black balancing code is updated from + * pre-jdk-collections + * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) + * based in turn on Cormen, Leiserson, and Rivest "Introduction to + * Algorithms" (CLR). + * + * TreeBins also maintain a separate locking discipline than + * regular bins. Because they are forwarded via special MOVED + * nodes at bin heads (which can never change once established), + * we cannot use those nodes as locks. Instead, TreeBin + * extends AbstractQueuedSynchronizer to support a simple form of + * read-write lock. For update operations and table validation, + * the exclusive form of lock behaves in the same way as bin-head + * locks. However, lookups use shared read-lock mechanics to allow + * multiple readers in the absence of writers. Additionally, + * these lookups do not ever block: While the lock is not + * available, they proceed along the slow traversal path (via + * next-pointers) until the lock becomes available or the list is + * exhausted, whichever comes first. (These cases are not fast, + * but maximize aggregate expected throughput.) The AQS mechanics + * for doing this are straightforward. The lock state is held as + * AQS getState(). Read counts are negative; the write count (1) + * is positive. There are no signalling preferences among readers + * and writers. Since we don't need to export full Lock API, we + * just override the minimal AQS methods and use them directly. + */ + static final class TreeBin extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 2249069246763182397L; + transient TreeNode root; // root of tree + transient TreeNode first; // head of next-pointer list + + /* AQS overrides */ + public final boolean isHeldExclusively() { return getState() > 0; } + public final boolean tryAcquire(int ignore) { + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + public final boolean tryRelease(int ignore) { + setExclusiveOwnerThread(null); + setState(0); + return true; + } + public final int tryAcquireShared(int ignore) { + for (int c;;) { + if ((c = getState()) > 0) + return -1; + if (compareAndSetState(c, c -1)) + return 1; + } + } + public final boolean tryReleaseShared(int ignore) { + int c; + do {} while (!compareAndSetState(c = getState(), c + 1)); + return c == -1; + } + + /** From CLR */ + private void rotateLeft(TreeNode p) { + if (p != null) { + TreeNode r = p.right, pp, rl; + if ((rl = p.right = r.left) != null) + rl.parent = p; + if ((pp = r.parent = p.parent) == null) + root = r; + else if (pp.left == p) + pp.left = r; + else + pp.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(TreeNode p) { + if (p != null) { + TreeNode l = p.left, pp, lr; + if ((lr = p.left = l.right) != null) + lr.parent = p; + if ((pp = l.parent = p.parent) == null) + root = l; + else if (pp.right == p) + pp.right = l; + else + pp.left = l; + l.right = p; + p.parent = l; + } + } + + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, Object k, TreeNode p) { + return getTreeNode(h, (RubyObject)k, p); + } + + /** + * Returns the TreeNode (or null if not found) for the given key + * starting at given root. + */ + @SuppressWarnings("unchecked") final TreeNode getTreeNode + (int h, RubyObject k, TreeNode p) { + RubyClass c = k.getMetaClass(); boolean kNotComparable = !k.respondsTo("<=>"); + while (p != null) { + int dir, ph; RubyObject pk; RubyClass pc; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = (RubyClass)pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pl, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + // try to continue iterating on the left side + else if ((pl = p.left) != null && h <= pl.hash) + dir = -1; + else // no matching node found + return null; + } + } + } + else + dir = (h < ph) ? -1 : 1; + p = (dir > 0) ? p.right : p.left; + } + return null; + } + + int rubyCompare(RubyObject l, RubyObject r) { + ThreadContext context = l.getMetaClass().getRuntime().getCurrentContext(); + IRubyObject result; + try { + result = l.callMethod(context, "<=>", r); + } catch (RaiseException e) { + // handle objects "lying" about responding to <=>, ie: an Array containing non-comparable keys + if (context.runtime.getNoMethodError().isInstance(e.getException())) { + return 0; + } + throw e; + } + + return result.isNil() ? 0 : RubyNumeric.num2int(result.convertToInteger()); + } + + /** + * Wrapper for getTreeNode used by CHM.get. Tries to obtain + * read-lock to call getTreeNode, but during failure to get + * lock, searches along next links. + */ + final Object getValue(int h, Object k) { + Node r = null; + int c = getState(); // Must read lock state first + for (Node e = first; e != null; e = e.next) { + if (c <= 0 && compareAndSetState(c, c - 1)) { + try { + r = getTreeNode(h, k, root); + } finally { + releaseShared(0); + } + break; + } + else if ((e.hash & HASH_BITS) == h && k.equals(e.key)) { + r = e; + break; + } + else + c = getState(); + } + return r == null ? null : r.val; + } + + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, Object k, Object v) { + return putTreeNode(h, (RubyObject)k, v); + } + + /** + * Finds or adds a node. + * @return null if added + */ + @SuppressWarnings("unchecked") final TreeNode putTreeNode + (int h, RubyObject k, Object v) { + RubyClass c = k.getMetaClass(); + boolean kNotComparable = !k.respondsTo("<=>"); + TreeNode pp = root, p = null; + int dir = 0; + while (pp != null) { // find existing node or leaf to insert at + int ph; RubyObject pk; RubyClass pc; + p = pp; + if ((ph = p.hash) == h) { + if ((pk = (RubyObject)p.key) == k || k.equals(pk)) + return p; + if (c != (pc = pk.getMetaClass()) || + kNotComparable || + (dir = rubyCompare(k, pk)) == 0) { + dir = (c == pc) ? 0 : c.getName().compareTo(pc.getName()); + if (dir == 0) { // if still stuck, need to check both sides + TreeNode r = null, pr; + // try to recurse on the right + if ((pr = p.right) != null && h >= pr.hash && (r = getTreeNode(h, k, pr)) != null) + return r; + else // continue descending down the left subtree + dir = -1; + } + } + } + else + dir = (h < ph) ? -1 : 1; + pp = (dir > 0) ? p.right : p.left; + } + + TreeNode f = first; + TreeNode x = first = new TreeNode(h, (Object)k, v, f, p); + if (p == null) + root = x; + else { // attach and rebalance; adapted from CLR + TreeNode xp, xpp; + if (f != null) + f.prev = x; + if (dir <= 0) + p.left = x; + else + p.right = x; + x.red = true; + while (x != null && (xp = x.parent) != null && xp.red && + (xpp = xp.parent) != null) { + TreeNode xppl = xpp.left; + if (xp == xppl) { + TreeNode y = xpp.right; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.right) { + rotateLeft(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateRight(xpp); + } + } + } + } + else { + TreeNode y = xppl; + if (y != null && y.red) { + y.red = false; + xp.red = false; + xpp.red = true; + x = xpp; + } + else { + if (x == xp.left) { + rotateRight(x = xp); + xpp = (xp = x.parent) == null ? null : xp.parent; + } + if (xp != null) { + xp.red = false; + if (xpp != null) { + xpp.red = true; + rotateLeft(xpp); + } + } + } + } + } + TreeNode r = root; + if (r != null && r.red) + r.red = false; + } + return null; + } + + /** + * Removes the given node, that must be present before this + * call. This is messier than typical red-black deletion code + * because we cannot swap the contents of an interior node + * with a leaf successor that is pinned by "next" pointers + * that are accessible independently of lock. So instead we + * swap the tree linkages. + */ + final void deleteTreeNode(TreeNode p) { + TreeNode next = (TreeNode)p.next; // unlink traversal pointers + TreeNode pred = p.prev; + if (pred == null) + first = next; + else + pred.next = next; + if (next != null) + next.prev = pred; + TreeNode replacement; + TreeNode pl = p.left; + TreeNode pr = p.right; + if (pl != null && pr != null) { + TreeNode s = pr, sl; + while ((sl = s.left) != null) // find successor + s = sl; + boolean c = s.red; s.red = p.red; p.red = c; // swap colors + TreeNode sr = s.right; + TreeNode pp = p.parent; + if (s == pr) { // p was s's direct parent + p.parent = s; + s.right = p; + } + else { + TreeNode sp = s.parent; + if ((p.parent = sp) != null) { + if (s == sp.left) + sp.left = p; + else + sp.right = p; + } + if ((s.right = pr) != null) + pr.parent = s; + } + p.left = null; + if ((p.right = sr) != null) + sr.parent = p; + if ((s.left = pl) != null) + pl.parent = s; + if ((s.parent = pp) == null) + root = s; + else if (p == pp.left) + pp.left = s; + else + pp.right = s; + replacement = sr; + } + else + replacement = (pl != null) ? pl : pr; + TreeNode pp = p.parent; + if (replacement == null) { + if (pp == null) { + root = null; + return; + } + replacement = p; + } + else { + replacement.parent = pp; + if (pp == null) + root = replacement; + else if (p == pp.left) + pp.left = replacement; + else + pp.right = replacement; + p.left = p.right = p.parent = null; + } + if (!p.red) { // rebalance, from CLR + TreeNode x = replacement; + while (x != null) { + TreeNode xp, xpl; + if (x.red || (xp = x.parent) == null) { + x.red = false; + break; + } + if (x == (xpl = xp.left)) { + TreeNode sib = xp.right; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateLeft(xp); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sr == null || !sr.red) && + (sl == null || !sl.red)) { + sib.red = true; + x = xp; + } + else { + if (sr == null || !sr.red) { + if (sl != null) + sl.red = false; + sib.red = true; + rotateRight(sib); + sib = (xp = x.parent) == null ? null : xp.right; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sr = sib.right) != null) + sr.red = false; + } + if (xp != null) { + xp.red = false; + rotateLeft(xp); + } + x = root; + } + } + } + else { // symmetric + TreeNode sib = xpl; + if (sib != null && sib.red) { + sib.red = false; + xp.red = true; + rotateRight(xp); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib == null) + x = xp; + else { + TreeNode sl = sib.left, sr = sib.right; + if ((sl == null || !sl.red) && + (sr == null || !sr.red)) { + sib.red = true; + x = xp; + } + else { + if (sl == null || !sl.red) { + if (sr != null) + sr.red = false; + sib.red = true; + rotateLeft(sib); + sib = (xp = x.parent) == null ? null : xp.left; + } + if (sib != null) { + sib.red = (xp == null) ? false : xp.red; + if ((sl = sib.left) != null) + sl.red = false; + } + if (xp != null) { + xp.red = false; + rotateRight(xp); + } + x = root; + } + } + } + } + } + if (p == replacement && (pp = p.parent) != null) { + if (p == pp.left) // detach pointers + pp.left = null; + else if (p == pp.right) + pp.right = null; + p.parent = null; + } + } + } + + /* ---------------- Collision reduction methods -------------- */ + + /** + * Spreads higher bits to lower, and also forces top 2 bits to 0. + * Because the table uses power-of-two masking, sets of hashes + * that vary only in bits above the current mask will always + * collide. (Among known examples are sets of Float keys holding + * consecutive whole numbers in small tables.) To counter this, + * we apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed across bits (so don't benefit + * from spreading), and because we use trees to handle large sets + * of collisions in bins, we don't need excessively high quality. + */ + private static final int spread(int h) { + h ^= (h >>> 18) ^ (h >>> 12); + return (h ^ (h >>> 10)) & HASH_BITS; + } + + /** + * Replaces a list bin with a tree bin. Call only when locked. + * Fails to replace if the given key is non-comparable or table + * is, or needs, resizing. + */ + private final void replaceWithTreeBin(AtomicReferenceArray tab, int index, Object key) { + if ((key instanceof Comparable) && + (tab.length() >= MAXIMUM_CAPACITY || counter.sum() < (long)sizeCtl)) { + TreeBin t = new TreeBin(); + for (Node e = tabAt(tab, index); e != null; e = e.next) + t.putTreeNode(e.hash & HASH_BITS, e.key, e.val); + setTabAt(tab, index, new Node(MOVED, t, null, null)); + } + } + + /* ---------------- Internal access and update methods -------------- */ + + /** Implementation for get and containsKey */ + private final Object internalGet(Object k) { + int h = spread(k.hashCode()); + retry: for (AtomicReferenceArray tab = table; tab != null;) { + Node e, p; Object ek, ev; int eh; // locals to read fields once + for (e = tabAt(tab, (tab.length() - 1) & h); e != null; e = e.next) { + if ((eh = e.hash) == MOVED) { + if ((ek = e.key) instanceof TreeBin) // search TreeBin + return ((TreeBin)ek).getValue(h, k); + else { // restart with new table + tab = (AtomicReferenceArray)ek; + continue retry; + } + } + else if ((eh & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + } + break; + } + return null; + } + + /** + * Implementation for the four public remove/replace methods: + * Replaces node value with v, conditional upon match of cv if + * non-null. If resulting value is null, delete. + */ + private final Object internalReplace(Object k, Object v, Object cv) { + int h = spread(k.hashCode()); + Object oldVal = null; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null || + (f = tabAt(tab, i = (tab.length() - 1) & h)) == null) + break; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + boolean deleted = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) { + Object pv = p.val; + if (cv == null || cv == pv || cv.equals(pv)) { + oldVal = pv; + if ((p.val = v) == null) { + deleted = true; + t.deleteTreeNode(p); + } + } + } + } + } finally { + t.release(0); + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) != h && f.next == null) // precheck + break; // rules out possible existence + else if ((fh & LOCKED) != 0) { + checkForResize(); // try resizing if can't get lock + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + boolean validated = false; + boolean deleted = false; + try { + if (tabAt(tab, i) == f) { + validated = true; + for (Node e = f, pred = null;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + ((ev = e.val) != null) && + ((ek = e.key) == k || k.equals(ek))) { + if (cv == null || cv == ev || cv.equals(ev)) { + oldVal = ev; + if ((e.val = v) == null) { + deleted = true; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + } + break; + } + pred = e; + if ((e = e.next) == null) + break; + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (validated) { + if (deleted) + counter.add(-1L); + break; + } + } + } + return oldVal; + } + + /* + * Internal versions of the six insertion methods, each a + * little more complicated than the last. All have + * the same basic structure as the first (internalPut): + * 1. If table uninitialized, create + * 2. If bin empty, try to CAS new node + * 3. If bin stale, use new table + * 4. if bin converted to TreeBin, validate and relay to TreeBin methods + * 5. Lock and validate; if valid, scan and add or update + * + * The others interweave other checks and/or alternative actions: + * * Plain put checks for and performs resize after insertion. + * * putIfAbsent prescans for mapping without lock (and fails to add + * if present), which also makes pre-emptive resize checks worthwhile. + * * computeIfAbsent extends form used in putIfAbsent with additional + * mechanics to deal with, calls, potential exceptions and null + * returns from function call. + * * compute uses the same function-call mechanics, but without + * the prescans + * * merge acts as putIfAbsent in the absent case, but invokes the + * update function if present + * * putAll attempts to pre-allocate enough table space + * and more lazily performs count updates and checks. + * + * Someday when details settle down a bit more, it might be worth + * some factoring to reduce sprawl. + */ + + /** Implementation for put */ + private final Object internalPut(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; // no lock when adding to empty bin + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) { + oldVal = p.val; + p.val = v; + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { // needed in case equals() throws + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { // unlock and signal if needed + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for putIfAbsent */ + private final Object internalPutIfAbsent(Object k, Object v) { + int h = spread(k.hashCode()); + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + Object oldVal = null; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 2; + TreeNode p = t.putTreeNode(h, k, v); + if (p != null) + oldVal = p.val; + } + } finally { + t.release(0); + } + if (count != 0) { + if (oldVal != null) + return oldVal; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { // at least 2 nodes -- search and maybe resize + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + Object oldVal = null; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + oldVal = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (oldVal != null) + return oldVal; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + counter.add(1L); + if (count > 1) + checkForResize(); + return null; + } + + /** Implementation for computeIfAbsent */ + private final Object internalComputeIfAbsent(K k, + Fun mf) { + int h = spread(k.hashCode()); + Object val = null; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + count = 1; + try { + if ((val = mf.apply(k)) != null) + node.val = val; + } finally { + if (val == null) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean added = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + val = p.val; + else if ((val = mf.apply(k)) != null) { + added = true; + count = 2; + t.putTreeNode(h, k, val); + } + } + } finally { + t.release(0); + } + if (count != 0) { + if (!added) + return val; + break; + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & HASH_BITS) == h && (fv = f.val) != null && + ((fk = f.key) == k || k.equals(fk))) + return fv; + else { + Node g = f.next; + if (g != null) { + for (Node e = g;;) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) + return ev; + if ((e = e.next) == null) { + checkForResize(); + break; + } + } + } + if (((fh = f.hash) & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) { + boolean added = false; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = ev; + break; + } + Node last = e; + if ((e = e.next) == null) { + if ((val = mf.apply(k)) != null) { + added = true; + last.next = new Node(h, k, val, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (!added) + return val; + if (tab.length() <= 64) + count = 2; + break; + } + } + } + } + if (val != null) { + counter.add(1L); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for compute */ + @SuppressWarnings("unchecked") private final Object internalCompute + (K k, boolean onlyIfPresent, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + Node f; int i, fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (onlyIfPresent) + break; + Node node = new Node(fh = h | LOCKED, k, null, null); + if (casTabAt(tab, i, null, node)) { + try { + count = 1; + if ((val = mf.apply(k, null)) != null) { + node.val = val; + delta = 1; + } + } finally { + if (delta == 0) + setTabAt(tab, i, null); + if (!node.casHash(fh, h)) { + node.hash = h; + synchronized (node) { node.notifyAll(); }; + } + } + } + if (count != 0) + break; + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + Object pv; + if (p == null) { + if (onlyIfPresent) + break; + pv = null; + } else + pv = p.val; + if ((val = mf.apply(k, (V)pv)) != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply(k, (V)ev); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + if (!onlyIfPresent && (val = mf.apply(k, null)) != null) { + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + } + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for merge */ + @SuppressWarnings("unchecked") private final Object internalMerge + (K k, V v, BiFun mf) { + int h = spread(k.hashCode()); + Object val = null; + int delta = 0; + int count = 0; + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk, fv; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) { + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + delta = 1; + val = v; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + count = 1; + TreeNode p = t.getTreeNode(h, k, t.root); + val = (p == null) ? v : mf.apply((V)p.val, v); + if (val != null) { + if (p != null) + p.val = val; + else { + count = 2; + delta = 1; + t.putTreeNode(h, k, val); + } + } + else if (p != null) { + delta = -1; + t.deleteTreeNode(p); + } + } + } finally { + t.release(0); + } + if (count != 0) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f, pred = null;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + val = mf.apply((V)ev, v); + if (val != null) + e.val = val; + else { + delta = -1; + Node en = e.next; + if (pred != null) + pred.next = en; + else + setTabAt(tab, i, en); + } + break; + } + pred = e; + if ((e = e.next) == null) { + val = v; + pred.next = new Node(h, k, val, null); + delta = 1; + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (tab.length() <= 64) + count = 2; + break; + } + } + } + if (delta != 0) { + counter.add((long)delta); + if (count > 1) + checkForResize(); + } + return val; + } + + /** Implementation for putAll */ + private final void internalPutAll(Map m) { + tryPresize(m.size()); + long delta = 0L; // number of uncommitted additions + boolean npe = false; // to throw exception on exit for nulls + try { // to clean up counts on other exceptions + for (Map.Entry entry : m.entrySet()) { + Object k, v; + if (entry == null || (k = entry.getKey()) == null || + (v = entry.getValue()) == null) { + npe = true; + break; + } + int h = spread(k.hashCode()); + for (AtomicReferenceArray tab = table;;) { + int i; Node f; int fh; Object fk; + if (tab == null) + tab = initTable(); + else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null){ + if (casTabAt(tab, i, null, new Node(h, k, v, null))) { + ++delta; + break; + } + } + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + TreeNode p = t.getTreeNode(h, k, t.root); + if (p != null) + p.val = v; + else { + t.putTreeNode(h, k, v); + ++delta; + } + } + } finally { + t.release(0); + } + if (validated) + break; + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); + delta = 0L; + checkForResize(); + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + int count = 0; + try { + if (tabAt(tab, i) == f) { + count = 1; + for (Node e = f;; ++count) { + Object ek, ev; + if ((e.hash & HASH_BITS) == h && + (ev = e.val) != null && + ((ek = e.key) == k || k.equals(ek))) { + e.val = v; + break; + } + Node last = e; + if ((e = e.next) == null) { + ++delta; + last.next = new Node(h, k, v, null); + if (count >= TREE_THRESHOLD) + replaceWithTreeBin(tab, i, k); + break; + } + } + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (count != 0) { + if (count > 1) { + counter.add(delta); + delta = 0L; + checkForResize(); + } + break; + } + } + } + } + } finally { + if (delta != 0) + counter.add(delta); + } + if (npe) + throw new NullPointerException(); + } + + /* ---------------- Table Initialization and Resizing -------------- */ + + /** + * Returns a power of two table size for the given desired capacity. + * See Hackers Delight, sec 3.2 + */ + private static final int tableSizeFor(int c) { + int n = c - 1; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + } + + /** + * Initializes table, using the size recorded in sizeCtl. + */ + private final AtomicReferenceArray initTable() { + AtomicReferenceArray tab; int sc; + while ((tab = table) == null) { + if ((sc = sizeCtl) < 0) + Thread.yield(); // lost initialization race; just spin + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if ((tab = table) == null) { + int n = (sc > 0) ? sc : DEFAULT_CAPACITY; + tab = table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + break; + } + } + return tab; + } + + /** + * If table is too small and not already resizing, creates next + * table and transfers bins. Rechecks occupancy after a transfer + * to see if another resize is already needed because resizings + * are lagging additions. + */ + private final void checkForResize() { + AtomicReferenceArray tab; int n, sc; + while ((tab = table) != null && + (n = tab.length()) < MAXIMUM_CAPACITY && + (sc = sizeCtl) >= 0 && counter.sum() >= (long)sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (tab == table) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + + /** + * Tries to presize table to accommodate the given number of elements. + * + * @param size number of elements (doesn't need to be perfectly accurate) + */ + private final void tryPresize(int size) { + int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : + tableSizeFor(size + (size >>> 1) + 1); + int sc; + while ((sc = sizeCtl) >= 0) { + AtomicReferenceArray tab = table; int n; + if (tab == null || (n = tab.length()) == 0) { + n = (sc > c) ? sc : c; + if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = new AtomicReferenceArray(n); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + } + } + else if (c <= sc || n >= MAXIMUM_CAPACITY) + break; + else if (SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == tab) { + table = rebuild(tab); + sc = (n << 1) - (n >>> 1); + } + } finally { + sizeCtl = sc; + } + } + } + } + + /* + * Moves and/or copies the nodes in each bin to new table. See + * above for explanation. + * + * @return the new table + */ + private static final AtomicReferenceArray rebuild(AtomicReferenceArray tab) { + int n = tab.length(); + AtomicReferenceArray nextTab = new AtomicReferenceArray(n << 1); + Node fwd = new Node(MOVED, nextTab, null, null); + int[] buffer = null; // holds bins to revisit; null until needed + Node rev = null; // reverse forwarder; null until needed + int nbuffered = 0; // the number of bins in buffer list + int bufferIndex = 0; // buffer index of current buffered bin + int bin = n - 1; // current non-buffered bin or -1 if none + + for (int i = bin;;) { // start upwards sweep + int fh; Node f; + if ((f = tabAt(tab, i)) == null) { + if (bin >= 0) { // Unbuffered; no lock needed (or available) + if (!casTabAt(tab, i, f, fwd)) + continue; + } + else { // transiently use a locked forwarding node + Node g = new Node(MOVED|LOCKED, nextTab, null, null); + if (!casTabAt(tab, i, f, g)) + continue; + setTabAt(nextTab, i, null); + setTabAt(nextTab, i + n, null); + setTabAt(tab, i, fwd); + if (!g.casHash(MOVED|LOCKED, MOVED)) { + g.hash = MOVED; + synchronized (g) { g.notifyAll(); } + } + } + } + else if ((fh = f.hash) == MOVED) { + Object fk = f.key; + if (fk instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + boolean validated = false; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + validated = true; + splitTreeBin(nextTab, i, t); + setTabAt(tab, i, fwd); + } + } finally { + t.release(0); + } + if (!validated) + continue; + } + } + else if ((fh & LOCKED) == 0 && f.casHash(fh, fh|LOCKED)) { + boolean validated = false; + try { // split to lo and hi lists; copying as needed + if (tabAt(tab, i) == f) { + validated = true; + splitBin(nextTab, i, f); + setTabAt(tab, i, fwd); + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + if (!validated) + continue; + } + else { + if (buffer == null) // initialize buffer for revisits + buffer = new int[TRANSFER_BUFFER_SIZE]; + if (bin < 0 && bufferIndex > 0) { + int j = buffer[--bufferIndex]; + buffer[bufferIndex] = i; + i = j; // swap with another bin + continue; + } + if (bin < 0 || nbuffered >= TRANSFER_BUFFER_SIZE) { + f.tryAwaitLock(tab, i); + continue; // no other options -- block + } + if (rev == null) // initialize reverse-forwarder + rev = new Node(MOVED, tab, null, null); + if (tabAt(tab, i) != f || (f.hash & LOCKED) == 0) + continue; // recheck before adding to list + buffer[nbuffered++] = i; + setTabAt(nextTab, i, rev); // install place-holders + setTabAt(nextTab, i + n, rev); + } + + if (bin > 0) + i = --bin; + else if (buffer != null && nbuffered > 0) { + bin = -1; + i = buffer[bufferIndex = --nbuffered]; + } + else + return nextTab; + } + } + + /** + * Splits a normal bin with list headed by e into lo and hi parts; + * installs in given table. + */ + private static void splitBin(AtomicReferenceArray nextTab, int i, Node e) { + int bit = nextTab.length() >>> 1; // bit to split on + int runBit = e.hash & bit; + Node lastRun = e, lo = null, hi = null; + for (Node p = e.next; p != null; p = p.next) { + int b = p.hash & bit; + if (b != runBit) { + runBit = b; + lastRun = p; + } + } + if (runBit == 0) + lo = lastRun; + else + hi = lastRun; + for (Node p = e; p != lastRun; p = p.next) { + int ph = p.hash & HASH_BITS; + Object pk = p.key, pv = p.val; + if ((ph & bit) == 0) + lo = new Node(ph, pk, pv, lo); + else + hi = new Node(ph, pk, pv, hi); + } + setTabAt(nextTab, i, lo); + setTabAt(nextTab, i + bit, hi); + } + + /** + * Splits a tree bin into lo and hi parts; installs in given table. + */ + private static void splitTreeBin(AtomicReferenceArray nextTab, int i, TreeBin t) { + int bit = nextTab.length() >>> 1; + TreeBin lt = new TreeBin(); + TreeBin ht = new TreeBin(); + int lc = 0, hc = 0; + for (Node e = t.first; e != null; e = e.next) { + int h = e.hash & HASH_BITS; + Object k = e.key, v = e.val; + if ((h & bit) == 0) { + ++lc; + lt.putTreeNode(h, k, v); + } + else { + ++hc; + ht.putTreeNode(h, k, v); + } + } + Node ln, hn; // throw away trees if too small + if (lc <= (TREE_THRESHOLD >>> 1)) { + ln = null; + for (Node p = lt.first; p != null; p = p.next) + ln = new Node(p.hash, p.key, p.val, ln); + } + else + ln = new Node(MOVED, lt, null, null); + setTabAt(nextTab, i, ln); + if (hc <= (TREE_THRESHOLD >>> 1)) { + hn = null; + for (Node p = ht.first; p != null; p = p.next) + hn = new Node(p.hash, p.key, p.val, hn); + } + else + hn = new Node(MOVED, ht, null, null); + setTabAt(nextTab, i + bit, hn); + } + + /** + * Implementation for clear. Steps through each bin, removing all + * nodes. + */ + private final void internalClear() { + long delta = 0L; // negative number of deletions + int i = 0; + AtomicReferenceArray tab = table; + while (tab != null && i < tab.length()) { + int fh; Object fk; + Node f = tabAt(tab, i); + if (f == null) + ++i; + else if ((fh = f.hash) == MOVED) { + if ((fk = f.key) instanceof TreeBin) { + TreeBin t = (TreeBin)fk; + t.acquire(0); + try { + if (tabAt(tab, i) == f) { + for (Node p = t.first; p != null; p = p.next) { + if (p.val != null) { // (currently always true) + p.val = null; + --delta; + } + } + t.first = null; + t.root = null; + ++i; + } + } finally { + t.release(0); + } + } + else + tab = (AtomicReferenceArray)fk; + } + else if ((fh & LOCKED) != 0) { + counter.add(delta); // opportunistically update count + delta = 0L; + f.tryAwaitLock(tab, i); + } + else if (f.casHash(fh, fh | LOCKED)) { + try { + if (tabAt(tab, i) == f) { + for (Node e = f; e != null; e = e.next) { + if (e.val != null) { // (currently always true) + e.val = null; + --delta; + } + } + setTabAt(tab, i, null); + ++i; + } + } finally { + if (!f.casHash(fh | LOCKED, fh)) { + f.hash = fh; + synchronized (f) { f.notifyAll(); }; + } + } + } + } + if (delta != 0) + counter.add(delta); + } + + /* ----------------Table Traversal -------------- */ + + /** + * Encapsulates traversal for methods such as containsValue; also + * serves as a base class for other iterators and bulk tasks. + * + * At each step, the iterator snapshots the key ("nextKey") and + * value ("nextVal") of a valid node (i.e., one that, at point of + * snapshot, has a non-null user value). Because val fields can + * change (including to null, indicating deletion), field nextVal + * might not be accurate at point of use, but still maintains the + * weak consistency property of holding a value that was once + * valid. To support iterator.remove, the nextKey field is not + * updated (nulled out) when the iterator cannot advance. + * + * Internal traversals directly access these fields, as in: + * {@code while (it.advance() != null) { process(it.nextKey); }} + * + * Exported iterators must track whether the iterator has advanced + * (in hasNext vs next) (by setting/checking/nulling field + * nextVal), and then extract key, value, or key-value pairs as + * return values of next(). + * + * The iterator visits once each still-valid node that was + * reachable upon iterator construction. It might miss some that + * were added to a bin after the bin was visited, which is OK wrt + * consistency guarantees. Maintaining this property in the face + * of possible ongoing resizes requires a fair amount of + * bookkeeping state that is difficult to optimize away amidst + * volatile accesses. Even so, traversal maintains reasonable + * throughput. + * + * Normally, iteration proceeds bin-by-bin traversing lists. + * However, if the table has been resized, then all future steps + * must traverse both the bin at the current index as well as at + * (index + baseSize); and so on for further resizings. To + * paranoically cope with potential sharing by users of iterators + * across threads, iteration terminates if a bounds checks fails + * for a table read. + * + * This class extends ForkJoinTask to streamline parallel + * iteration in bulk operations (see BulkTask). This adds only an + * int of space overhead, which is close enough to negligible in + * cases where it is not needed to not worry about it. Because + * ForkJoinTask is Serializable, but iterators need not be, we + * need to add warning suppressions. + */ + @SuppressWarnings("serial") static class Traverser { + final ConcurrentHashMapV8 map; + Node next; // the next entry to use + K nextKey; // cached key field of next + V nextVal; // cached val field of next + AtomicReferenceArray tab; // current table; updated if resized + int index; // index of bin to use next + int baseIndex; // current index of initial table + int baseLimit; // index bound for initial table + int baseSize; // initial table size + + /** Creates iterator for all entries in the table. */ + Traverser(ConcurrentHashMapV8 map) { + this.map = map; + } + + /** Creates iterator for split() methods */ + Traverser(Traverser it) { + ConcurrentHashMapV8 m; AtomicReferenceArray t; + if ((m = this.map = it.map) == null) + t = null; + else if ((t = it.tab) == null && // force parent tab initialization + (t = it.tab = m.table) != null) + it.baseLimit = it.baseSize = t.length(); + this.tab = t; + this.baseSize = it.baseSize; + it.baseLimit = this.index = this.baseIndex = + ((this.baseLimit = it.baseLimit) + it.baseIndex + 1) >>> 1; + } + + /** + * Advances next; returns nextVal or null if terminated. + * See above for explanation. + */ + final V advance() { + Node e = next; + V ev = null; + outer: do { + if (e != null) // advance past used/skipped node + e = e.next; + while (e == null) { // get to next non-null bin + ConcurrentHashMapV8 m; + AtomicReferenceArray t; int b, i, n; Object ek; // checks must use locals + if ((t = tab) != null) + n = t.length(); + else if ((m = map) != null && (t = tab = m.table) != null) + n = baseLimit = baseSize = t.length(); + else + break outer; + if ((b = baseIndex) >= baseLimit || + (i = index) < 0 || i >= n) + break outer; + if ((e = tabAt(t, i)) != null && e.hash == MOVED) { + if ((ek = e.key) instanceof TreeBin) + e = ((TreeBin)ek).first; + else { + tab = (AtomicReferenceArray)ek; + continue; // restarts due to null val + } + } // visit upper slots if present + index = (i += baseSize) < n ? i : (baseIndex = b + 1); + } + nextKey = (K) e.key; + } while ((ev = (V) e.val) == null); // skip deleted or special nodes + next = e; + return nextVal = ev; + } + + public final void remove() { + Object k = nextKey; + if (k == null && (advance() == null || (k = nextKey) == null)) + throw new IllegalStateException(); + map.internalReplace(k, null, null); + } + + public final boolean hasNext() { + return nextVal != null || advance() != null; + } + + public final boolean hasMoreElements() { return hasNext(); } + public final void setRawResult(Object x) { } + public R getRawResult() { return null; } + public boolean exec() { return true; } + } + + /* ---------------- Public operations -------------- */ + + /** + * Creates a new, empty map with the default initial table size (16). + */ + public ConcurrentHashMapV8() { + this.counter = new LongAdder(); + } + + /** + * Creates a new, empty map with an initial table size + * accommodating the specified number of elements without the need + * to dynamically resize. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + */ + public ConcurrentHashMapV8(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException(); + int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? + MAXIMUM_CAPACITY : + tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new map with the same mappings as the given map. + * + * @param m the map + */ + public ConcurrentHashMapV8(Map m) { + this.counter = new LongAdder(); + this.sizeCtl = DEFAULT_CAPACITY; + internalPutAll(m); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}) and + * initial table density ({@code loadFactor}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @throws IllegalArgumentException if the initial capacity of + * elements is negative or the load factor is nonpositive + * + * @since 1.6 + */ + public ConcurrentHashMapV8(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, 1); + } + + /** + * Creates a new, empty map with an initial table size based on + * the given number of elements ({@code initialCapacity}), table + * density ({@code loadFactor}), and number of concurrently + * updating threads ({@code concurrencyLevel}). + * + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements, + * given the specified load factor. + * @param loadFactor the load factor (table density) for + * establishing the initial table size + * @param concurrencyLevel the estimated number of concurrently + * updating threads. The implementation may use this value as + * a sizing hint. + * @throws IllegalArgumentException if the initial capacity is + * negative or the load factor or concurrencyLevel are + * nonpositive + */ + public ConcurrentHashMapV8(int initialCapacity, + float loadFactor, int concurrencyLevel) { + if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) + throw new IllegalArgumentException(); + if (initialCapacity < concurrencyLevel) // Use at least as many bins + initialCapacity = concurrencyLevel; // as estimated threads + long size = (long)(1.0 + (long)initialCapacity / loadFactor); + int cap = (size >= (long)MAXIMUM_CAPACITY) ? + MAXIMUM_CAPACITY : tableSizeFor((int)size); + this.counter = new LongAdder(); + this.sizeCtl = cap; + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @return the new set + */ + public static KeySetView newKeySet() { + return new KeySetView(new ConcurrentHashMapV8(), + Boolean.TRUE); + } + + /** + * Creates a new {@link Set} backed by a ConcurrentHashMapV8 + * from the given type to {@code Boolean.TRUE}. + * + * @param initialCapacity The implementation performs internal + * sizing to accommodate this many elements. + * @throws IllegalArgumentException if the initial capacity of + * elements is negative + * @return the new set + */ + public static KeySetView newKeySet(int initialCapacity) { + return new KeySetView(new ConcurrentHashMapV8(initialCapacity), + Boolean.TRUE); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return counter.sum() <= 0L; // ignore transient negative values + } + + /** + * {@inheritDoc} + */ + public int size() { + long n = counter.sum(); + return ((n < 0L) ? 0 : + (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : + (int)n); + } + + /** + * Returns the number of mappings. This method should be used + * instead of {@link #size} because a ConcurrentHashMapV8 may + * contain more mappings than can be represented as an int. The + * value returned is a snapshot; the actual count may differ if + * there are ongoing concurrent insertions or removals. + * + * @return the number of mappings + */ + public long mappingCount() { + long n = counter.sum(); + return (n < 0L) ? 0L : n; // ignore transient negative values + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key.equals(k)}, + * then this method returns {@code v}; otherwise it returns + * {@code null}. (There can be at most one such mapping.) + * + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V get(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalGet(key); + } + + /** + * Returns the value to which the specified key is mapped, + * or the given defaultValue if this map contains no mapping for the key. + * + * @param key the key + * @param defaultValue the value to return if this map contains + * no mapping for the given key + * @return the mapping for the key, if present; else the defaultValue + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) { + if (key == null) + throw new NullPointerException(); + V v = (V) internalGet(key); + return v == null ? defaultValue : v; + } + + /** + * Tests if the specified object is a key in this table. + * + * @param key possible key + * @return {@code true} if and only if the specified object + * is a key in this table, as determined by the + * {@code equals} method; {@code false} otherwise + * @throws NullPointerException if the specified key is null + */ + public boolean containsKey(Object key) { + if (key == null) + throw new NullPointerException(); + return internalGet(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. Note: This method may require a full traversal + * of the map, and is much slower than method {@code containsKey}. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if this map maps one or more keys to the + * specified value + * @throws NullPointerException if the specified value is null + */ + public boolean containsValue(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return true; + } + return false; + } + + public K findKey(Object value) { + if (value == null) + throw new NullPointerException(); + Object v; + Traverser it = new Traverser(this); + while ((v = it.advance()) != null) { + if (v == value || value.equals(v)) + return it.nextKey; + } + return null; + } + + /** + * Legacy method testing if some key maps into the specified value + * in this table. This method is identical in functionality to + * {@link #containsValue}, and exists solely to ensure + * full compatibility with class {@link java.util.Hashtable}, + * which supported this method prior to introduction of the + * Java Collections framework. + * + * @param value a value to search for + * @return {@code true} if and only if some key maps to the + * {@code value} argument in this table as + * determined by the {@code equals} method; + * {@code false} otherwise + * @throws NullPointerException if the specified value is null + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Maps the specified key to the specified value in this table. + * Neither the key nor the value can be null. + * + *

The value can be retrieved by calling the {@code get} method + * with a key that is equal to the original key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V put(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPut(key, value); + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalPutIfAbsent(key, value); + } + + /** + * Copies all of the mappings from the specified map to this one. + * These mappings replace any mappings that this map had for any of the + * keys currently in the specified map. + * + * @param m mappings to be stored in this map + */ + public void putAll(Map m) { + internalPutAll(m); + } + + /** + * If the specified key is not already associated with a value, + * computes its value using the given mappingFunction and enters + * it into the map unless null. This is equivalent to + *

 {@code
+     * if (map.containsKey(key))
+     *   return map.get(key);
+     * value = mappingFunction.apply(key);
+     * if (value != null)
+     *   map.put(key, value);
+     * return value;}
+ * + * except that the action is performed atomically. If the + * function returns {@code null} no mapping is recorded. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and no mapping is recorded. Some + * attempted update operations on this map by other threads may be + * blocked while computation is in progress, so the computation + * should be short and simple, and must not attempt to update any + * other mappings of this Map. The most appropriate usage is to + * construct a new object serving as an initial mapped value, or + * memoized result, as in: + * + *
 {@code
+     * map.computeIfAbsent(key, new Fun() {
+     *   public V map(K k) { return new Value(f(k)); }});}
+ * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key or mappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, + * in which case the mapping is left unestablished + */ + @SuppressWarnings("unchecked") public V computeIfAbsent + (K key, Fun mappingFunction) { + if (key == null || mappingFunction == null) + throw new NullPointerException(); + return (V)internalComputeIfAbsent(key, mappingFunction); + } + + /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
 {@code
+     *   if (map.containsKey(key)) {
+     *     value = remappingFunction.apply(key, map.get(key));
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V computeIfPresent + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** + * Computes a new mapping value given a key and + * its current mapped value (or {@code null} if there is no current + * mapping). This is equivalent to + *
 {@code
+     *   value = remappingFunction.apply(key, map.get(key));
+     *   if (value != null)
+     *     map.put(key, value);
+     *   else
+     *     map.remove(key);
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + *
 {@code
+     * Map map = ...;
+     * final String msg = ...;
+     * map.compute(key, new BiFun() {
+     *   public String apply(Key k, String v) {
+     *    return (v == null) ? msg : v + msg;});}}
+ * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + @SuppressWarnings("unchecked") public V compute + (K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
 {@code
+     *   if (!map.containsKey(key))
+     *     map.put(value);
+     *   else {
+     *     newValue = remappingFunction.apply(map.get(key), value);
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + @SuppressWarnings("unchecked") public V merge + (K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); + } + + /** + * Removes the key (and its corresponding value) from this map. + * This method does nothing if the key is not in the map. + * + * @param key the key that needs to be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} + * @throws NullPointerException if the specified key is null + */ + @SuppressWarnings("unchecked") public V remove(Object key) { + if (key == null) + throw new NullPointerException(); + return (V)internalReplace(key, null, null); + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if the specified key is null + */ + public boolean remove(Object key, Object value) { + if (key == null) + throw new NullPointerException(); + if (value == null) + return false; + return internalReplace(key, null, value) != null; + } + + /** + * {@inheritDoc} + * + * @throws NullPointerException if any of the arguments are null + */ + public boolean replace(K key, V oldValue, V newValue) { + if (key == null || oldValue == null || newValue == null) + throw new NullPointerException(); + return internalReplace(key, newValue, oldValue) != null; + } + + /** + * {@inheritDoc} + * + * @return the previous value associated with the specified key, + * or {@code null} if there was no mapping for the key + * @throws NullPointerException if the specified key or value is null + */ + @SuppressWarnings("unchecked") public V replace(K key, V value) { + if (key == null || value == null) + throw new NullPointerException(); + return (V)internalReplace(key, value, null); + } + + /** + * Removes all of the mappings from this map. + */ + public void clear() { + internalClear(); + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. + * + * @return the set view + */ + public KeySetView keySet() { + KeySetView ks = keySet; + return (ks != null) ? ks : (keySet = new KeySetView(this, null)); + } + + /** + * Returns a {@link Set} view of the keys in this map, using the + * given common mapped value for any additions (i.e., {@link + * Collection#add} and {@link Collection#addAll}). This is of + * course only appropriate if it is acceptable to use the same + * value for all additions from this view. + * + * @param mappedValue the mapped value to use for any + * additions. + * @return the set view + * @throws NullPointerException if the mappedValue is null + */ + public KeySetView keySet(V mappedValue) { + if (mappedValue == null) + throw new NullPointerException(); + return new KeySetView(this, mappedValue); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. + */ + public ValuesView values() { + ValuesView vs = values; + return (vs != null) ? vs : (values = new ValuesView(this)); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. The set supports element + * removal, which removes the corresponding mapping from the map, + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Set> entrySet() { + EntrySetView es = entrySet; + return (es != null) ? es : (entrySet = new EntrySetView(this)); + } + + /** + * Returns an enumeration of the keys in this table. + * + * @return an enumeration of the keys in this table + * @see #keySet() + */ + public Enumeration keys() { + return new KeyIterator(this); + } + + /** + * Returns an enumeration of the values in this table. + * + * @return an enumeration of the values in this table + * @see #values() + */ + public Enumeration elements() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the keys in this map. + * + * @return a partitionable iterator of the keys in this map + */ + public Spliterator keySpliterator() { + return new KeyIterator(this); + } + + /** + * Returns a partitionable iterator of the values in this map. + * + * @return a partitionable iterator of the values in this map + */ + public Spliterator valueSpliterator() { + return new ValueIterator(this); + } + + /** + * Returns a partitionable iterator of the entries in this map. + * + * @return a partitionable iterator of the entries in this map + */ + public Spliterator> entrySpliterator() { + return new EntryIterator(this); + } + + /** + * Returns the hash code value for this {@link Map}, i.e., + * the sum of, for each key-value pair in the map, + * {@code key.hashCode() ^ value.hashCode()}. + * + * @return the hash code value for this map + */ + public int hashCode() { + int h = 0; + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + h += it.nextKey.hashCode() ^ v.hashCode(); + } + return h; + } + + /** + * Returns a string representation of this map. The string + * representation consists of a list of key-value mappings (in no + * particular order) enclosed in braces ("{@code {}}"). Adjacent + * mappings are separated by the characters {@code ", "} (comma + * and space). Each key-value mapping is rendered as the key + * followed by an equals sign ("{@code =}") followed by the + * associated value. + * + * @return a string representation of this map + */ + public String toString() { + Traverser it = new Traverser(this); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + Object v; + if ((v = it.advance()) != null) { + for (;;) { + Object k = it.nextKey; + sb.append(k == this ? "(this Map)" : k); + sb.append('='); + sb.append(v == this ? "(this Map)" : v); + if ((v = it.advance()) == null) + break; + sb.append(',').append(' '); + } + } + return sb.append('}').toString(); + } + + /** + * Compares the specified object with this map for equality. + * Returns {@code true} if the given object is a map with the same + * mappings as this map. This operation may return misleading + * results if either map is concurrently modified during execution + * of this method. + * + * @param o object to be compared for equality with this map + * @return {@code true} if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o != this) { + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + Traverser it = new Traverser(this); + Object val; + while ((val = it.advance()) != null) { + Object v = m.get(it.nextKey); + if (v == null || (v != val && !v.equals(val))) + return false; + } + for (Map.Entry e : m.entrySet()) { + Object mk, mv, v; + if ((mk = e.getKey()) == null || + (mv = e.getValue()) == null || + (v = internalGet(mk)) == null || + (mv != v && !mv.equals(v))) + return false; + } + } + return true; + } + + /* ----------------Iterators -------------- */ + + @SuppressWarnings("serial") static final class KeyIterator extends Traverser + implements Spliterator, Enumeration { + KeyIterator(ConcurrentHashMapV8 map) { super(map); } + KeyIterator(Traverser it) { + super(it); + } + public KeyIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new KeyIterator(this); + } + @SuppressWarnings("unchecked") public final K next() { + if (nextVal == null && advance() == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return (K) k; + } + + public final K nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class ValueIterator extends Traverser + implements Spliterator, Enumeration { + ValueIterator(ConcurrentHashMapV8 map) { super(map); } + ValueIterator(Traverser it) { + super(it); + } + public ValueIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new ValueIterator(this); + } + + @SuppressWarnings("unchecked") public final V next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + nextVal = null; + return (V) v; + } + + public final V nextElement() { return next(); } + } + + @SuppressWarnings("serial") static final class EntryIterator extends Traverser + implements Spliterator> { + EntryIterator(ConcurrentHashMapV8 map) { super(map); } + EntryIterator(Traverser it) { + super(it); + } + public EntryIterator split() { + if (nextKey != null) + throw new IllegalStateException(); + return new EntryIterator(this); + } + + @SuppressWarnings("unchecked") public final Map.Entry next() { + Object v; + if ((v = nextVal) == null && (v = advance()) == null) + throw new NoSuchElementException(); + Object k = nextKey; + nextVal = null; + return new MapEntry((K)k, (V)v, map); + } + } + + /** + * Exported Entry for iterators + */ + static final class MapEntry implements Map.Entry { + final K key; // non-null + V val; // non-null + final ConcurrentHashMapV8 map; + MapEntry(K key, V val, ConcurrentHashMapV8 map) { + this.key = key; + this.val = val; + this.map = map; + } + public final K getKey() { return key; } + public final V getValue() { return val; } + public final int hashCode() { return key.hashCode() ^ val.hashCode(); } + public final String toString(){ return key + "=" + val; } + + public final boolean equals(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + (k == key || k.equals(key)) && + (v == val || v.equals(val))); + } + + /** + * Sets our entry's value and writes through to the map. The + * value to return is somewhat arbitrary here. Since we do not + * necessarily track asynchronous changes, the most recent + * "previous" value could be different from what we return (or + * could even have been removed in which case the put will + * re-establish). We do not and cannot guarantee more. + */ + public final V setValue(V value) { + if (value == null) throw new NullPointerException(); + V v = val; + val = value; + map.put(key, value); + return v; + } + } + + /* ---------------- Serialization Support -------------- */ + + /** + * Stripped-down version of helper class used in previous version, + * declared for the sake of serialization compatibility + */ + static class Segment implements Serializable { + private static final long serialVersionUID = 2249069246763182397L; + final float loadFactor; + Segment(float lf) { this.loadFactor = lf; } + } + + /** + * Saves the state of the {@code ConcurrentHashMapV8} instance to a + * stream (i.e., serializes it). + * @param s the stream + * @serialData + * the key (Object) and value (Object) + * for each key-value mapping, followed by a null pair. + * The key-value mappings are emitted in no particular order. + */ + @SuppressWarnings("unchecked") private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + if (segments == null) { // for serialization compatibility + segments = (Segment[]) + new Segment[DEFAULT_CONCURRENCY_LEVEL]; + for (int i = 0; i < segments.length; ++i) + segments[i] = new Segment(LOAD_FACTOR); + } + s.defaultWriteObject(); + Traverser it = new Traverser(this); + Object v; + while ((v = it.advance()) != null) { + s.writeObject(it.nextKey); + s.writeObject(v); + } + s.writeObject(null); + s.writeObject(null); + segments = null; // throw away + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + * @param s the stream + */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + this.segments = null; // unneeded + // initialize transient final field + this.counter = new LongAdder(); + + // Create all nodes, then place in table once size is known + long size = 0L; + Node p = null; + for (;;) { + K k = (K) s.readObject(); + V v = (V) s.readObject(); + if (k != null && v != null) { + int h = spread(k.hashCode()); + p = new Node(h, k, v, p); + ++size; + } + else + break; + } + if (p != null) { + boolean init = false; + int n; + if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) + n = MAXIMUM_CAPACITY; + else { + int sz = (int)size; + n = tableSizeFor(sz + (sz >>> 1) + 1); + } + int sc = sizeCtl; + boolean collide = false; + if (n > sc && + SIZE_CTRL_UPDATER.compareAndSet(this, sc, -1)) { + try { + if (table == null) { + init = true; + AtomicReferenceArray tab = new AtomicReferenceArray(n); + int mask = n - 1; + while (p != null) { + int j = p.hash & mask; + Node next = p.next; + Node q = p.next = tabAt(tab, j); + setTabAt(tab, j, p); + if (!collide && q != null && q.hash == p.hash) + collide = true; + p = next; + } + table = tab; + counter.add(size); + sc = n - (n >>> 2); + } + } finally { + sizeCtl = sc; + } + if (collide) { // rescan and convert to TreeBins + AtomicReferenceArray tab = table; + for (int i = 0; i < tab.length(); ++i) { + int c = 0; + for (Node e = tabAt(tab, i); e != null; e = e.next) { + if (++c > TREE_THRESHOLD && + (e.key instanceof Comparable)) { + replaceWithTreeBin(tab, i, e.key); + break; + } + } + } + } + } + if (!init) { // Can only happen if unsafely published. + while (p != null) { + internalPut(p.key, p.val); + p = p.next; + } + } + } + } + + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + /* ----------------Views -------------- */ + + /** + * Base class for views. + */ + static abstract class CHMView { + final ConcurrentHashMapV8 map; + CHMView(ConcurrentHashMapV8 map) { this.map = map; } + + /** + * Returns the map backing this view. + * + * @return the map backing this view + */ + public ConcurrentHashMapV8 getMap() { return map; } + + public final int size() { return map.size(); } + public final boolean isEmpty() { return map.isEmpty(); } + public final void clear() { map.clear(); } + + // implementations below rely on concrete classes supplying these + abstract public Iterator iterator(); + abstract public boolean contains(Object o); + abstract public boolean remove(Object o); + + private static final String oomeMsg = "Required array size too large"; + + public final Object[] toArray() { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int n = (int)sz; + Object[] r = new Object[n]; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = it.next(); + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + @SuppressWarnings("unchecked") public final T[] toArray(T[] a) { + long sz = map.mappingCount(); + if (sz > (long)(MAX_ARRAY_SIZE)) + throw new OutOfMemoryError(oomeMsg); + int m = (int)sz; + T[] r = (a.length >= m) ? a : + (T[])java.lang.reflect.Array + .newInstance(a.getClass().getComponentType(), m); + int n = r.length; + int i = 0; + Iterator it = iterator(); + while (it.hasNext()) { + if (i == n) { + if (n >= MAX_ARRAY_SIZE) + throw new OutOfMemoryError(oomeMsg); + if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) + n = MAX_ARRAY_SIZE; + else + n += (n >>> 1) + 1; + r = Arrays.copyOf(r, n); + } + r[i++] = (T)it.next(); + } + if (a == r && i < n) { + r[i] = null; // null-terminate + return r; + } + return (i == n) ? r : Arrays.copyOf(r, i); + } + + public final int hashCode() { + int h = 0; + for (Iterator it = iterator(); it.hasNext();) + h += it.next().hashCode(); + return h; + } + + public final String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + Iterator it = iterator(); + if (it.hasNext()) { + for (;;) { + Object e = it.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!it.hasNext()) + break; + sb.append(',').append(' '); + } + } + return sb.append(']').toString(); + } + + public final boolean containsAll(Collection c) { + if (c != this) { + for (Iterator it = c.iterator(); it.hasNext();) { + Object e = it.next(); + if (e == null || !contains(e)) + return false; + } + } + return true; + } + + public final boolean removeAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + public final boolean retainAll(Collection c) { + boolean modified = false; + for (Iterator it = iterator(); it.hasNext();) { + if (!c.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in + * which additions may optionally be enabled by mapping to a + * common value. This class cannot be directly instantiated. See + * {@link #keySet}, {@link #keySet(Object)}, {@link #newKeySet()}, + * {@link #newKeySet(int)}. + */ + public static class KeySetView extends CHMView implements Set, java.io.Serializable { + private static final long serialVersionUID = 7249069246763182397L; + private final V value; + KeySetView(ConcurrentHashMapV8 map, V value) { // non-public + super(map); + this.value = value; + } + + /** + * Returns the default mapped value for additions, + * or {@code null} if additions are not supported. + * + * @return the default mapped value for additions, or {@code null} + * if not supported. + */ + public V getMappedValue() { return value; } + + // implement Set API + + public boolean contains(Object o) { return map.containsKey(o); } + public boolean remove(Object o) { return map.remove(o) != null; } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the keys of this map + */ + public Iterator iterator() { return new KeyIterator(map); } + public boolean add(K e) { + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + if (e == null) + throw new NullPointerException(); + return map.internalPutIfAbsent(e, v) == null; + } + public boolean addAll(Collection c) { + boolean added = false; + V v; + if ((v = value) == null) + throw new UnsupportedOperationException(); + for (K e : c) { + if (e == null) + throw new NullPointerException(); + if (map.internalPutIfAbsent(e, v) == null) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Collection} of + * values, in which additions are disabled. This class cannot be + * directly instantiated. See {@link #values}, + * + *

The view's {@code iterator} is a "weakly consistent" iterator + * that will never throw {@link ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public static final class ValuesView extends CHMView + implements Collection { + ValuesView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { return map.containsValue(o); } + public final boolean remove(Object o) { + if (o != null) { + Iterator it = new ValueIterator(map); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + } + return false; + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the values of this map + */ + public final Iterator iterator() { + return new ValueIterator(map); + } + public final boolean add(V e) { + throw new UnsupportedOperationException(); + } + public final boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + } + + /** + * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value) + * entries. This class cannot be directly instantiated. See + * {@link #entrySet}. + */ + public static final class EntrySetView extends CHMView + implements Set> { + EntrySetView(ConcurrentHashMapV8 map) { super(map); } + public final boolean contains(Object o) { + Object k, v, r; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (r = map.get(k)) != null && + (v = e.getValue()) != null && + (v == r || v.equals(r))); + } + public final boolean remove(Object o) { + Object k, v; Map.Entry e; + return ((o instanceof Map.Entry) && + (k = (e = (Map.Entry)o).getKey()) != null && + (v = e.getValue()) != null && + map.remove(k, v)); + } + + /** + * Returns a "weakly consistent" iterator that will never + * throw {@link ConcurrentModificationException}, and + * guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not + * guaranteed to) reflect any modifications subsequent to + * construction. + * + * @return an iterator over the entries of this map + */ + public final Iterator> iterator() { + return new EntryIterator(map); + } + + public final boolean add(Entry e) { + K key = e.getKey(); + V value = e.getValue(); + if (key == null || value == null) + throw new NullPointerException(); + return map.internalPut(key, value) == null; + } + public final boolean addAll(Collection> c) { + boolean added = false; + for (Entry e : c) { + if (add(e)) + added = true; + } + return added; + } + public boolean equals(Object o) { + Set c; + return ((o instanceof Set) && + ((c = (Set)o) == this || + (containsAll(c) && c.containsAll(this)))); + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java new file mode 100644 index 00000000..ecf552a2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java @@ -0,0 +1,204 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.9 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import java.util.concurrent.atomic.AtomicLong; +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectInputStream; + +/** + * One or more variables that together maintain an initially zero + * {@code long} sum. When updates (method {@link #add}) are contended + * across threads, the set of variables may grow dynamically to reduce + * contention. Method {@link #sum} (or, equivalently, {@link + * #longValue}) returns the current total combined across the + * variables maintaining the sum. + * + *

This class is usually preferable to {@link AtomicLong} when + * multiple threads update a common sum that is used for purposes such + * as collecting statistics, not for fine-grained synchronization + * control. Under low update contention, the two classes have similar + * characteristics. But under high contention, expected throughput of + * this class is significantly higher, at the expense of higher space + * consumption. + * + *

This class extends {@link Number}, but does not define + * methods such as {@code hashCode} and {@code compareTo} because + * instances are expected to be mutated, and so are not useful as + * collection keys. + * + *

jsr166e note: This class is targeted to be placed in + * java.util.concurrent.atomic. + * + * @since 1.8 + * @author Doug Lea + */ +public class LongAdder extends Striped64 implements Serializable { + private static final long serialVersionUID = 7249069246863182397L; + + /** + * Version of plus for use in retryUpdate + */ + final long fn(long v, long x) { return v + x; } + + /** + * Creates a new adder with initial sum of zero. + */ + public LongAdder() { + } + + /** + * Adds the given value. + * + * @param x the value to add + */ + public void add(long x) { + Cell[] as; long b, v; HashCode hc; Cell a; int n; + if ((as = cells) != null || !casBase(b = base, b + x)) { + boolean uncontended = true; + int h = (hc = threadHashCode.get()).code; + if (as == null || (n = as.length) < 1 || + (a = as[(n - 1) & h]) == null || + !(uncontended = a.cas(v = a.value, v + x))) + retryUpdate(x, hc, uncontended); + } + } + + /** + * Equivalent to {@code add(1)}. + */ + public void increment() { + add(1L); + } + + /** + * Equivalent to {@code add(-1)}. + */ + public void decrement() { + add(-1L); + } + + /** + * Returns the current sum. The returned value is NOT an + * atomic snapshot: Invocation in the absence of concurrent + * updates returns an accurate result, but concurrent updates that + * occur while the sum is being calculated might not be + * incorporated. + * + * @return the sum + */ + public long sum() { + long sum = base; + Cell[] as = cells; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + sum += a.value; + } + } + return sum; + } + + /** + * Resets variables maintaining the sum to zero. This method may + * be a useful alternative to creating a new adder, but is only + * effective if there are no concurrent updates. Because this + * method is intrinsically racy, it should only be used when it is + * known that no threads are concurrently updating. + */ + public void reset() { + internalReset(0L); + } + + /** + * Equivalent in effect to {@link #sum} followed by {@link + * #reset}. This method may apply for example during quiescent + * points between multithreaded computations. If there are + * updates concurrent with this method, the returned value is + * not guaranteed to be the final value occurring before + * the reset. + * + * @return the sum + */ + public long sumThenReset() { + long sum = base; + Cell[] as = cells; + base = 0L; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) { + sum += a.value; + a.value = 0L; + } + } + } + return sum; + } + + /** + * Returns the String representation of the {@link #sum}. + * @return the String representation of the {@link #sum} + */ + public String toString() { + return Long.toString(sum()); + } + + /** + * Equivalent to {@link #sum}. + * + * @return the sum + */ + public long longValue() { + return sum(); + } + + /** + * Returns the {@link #sum} as an {@code int} after a narrowing + * primitive conversion. + */ + public int intValue() { + return (int)sum(); + } + + /** + * Returns the {@link #sum} as a {@code float} + * after a widening primitive conversion. + */ + public float floatValue() { + return (float)sum(); + } + + /** + * Returns the {@link #sum} as a {@code double} after a widening + * primitive conversion. + */ + public double doubleValue() { + return (double)sum(); + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeLong(sum()); + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + busy = 0; + cells = null; + base = s.readLong(); + } + +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java new file mode 100644 index 00000000..f5216424 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java @@ -0,0 +1,291 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.5 version. + +package com.concurrent_ruby.ext.jsr166e.nounsafe; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + +/** + * A package-local class holding common representation and mechanics + * for classes supporting dynamic striping on 64bit values. The class + * extends Number so that concrete subclasses must publicly do so. + */ +abstract class Striped64 extends Number { + /* + * This class maintains a lazily-initialized table of atomically + * updated variables, plus an extra "base" field. The table size + * is a power of two. Indexing uses masked per-thread hash codes. + * Nearly all declarations in this class are package-private, + * accessed directly by subclasses. + * + * Table entries are of class Cell; a variant of AtomicLong padded + * to reduce cache contention on most processors. Padding is + * overkill for most Atomics because they are usually irregularly + * scattered in memory and thus don't interfere much with each + * other. But Atomic objects residing in arrays will tend to be + * placed adjacent to each other, and so will most often share + * cache lines (with a huge negative performance impact) without + * this precaution. + * + * In part because Cells are relatively large, we avoid creating + * them until they are needed. When there is no contention, all + * updates are made to the base field. Upon first contention (a + * failed CAS on base update), the table is initialized to size 2. + * The table size is doubled upon further contention until + * reaching the nearest power of two greater than or equal to the + * number of CPUS. Table slots remain empty (null) until they are + * needed. + * + * A single spinlock ("busy") is used for initializing and + * resizing the table, as well as populating slots with new Cells. + * There is no need for a blocking lock: When the lock is not + * available, threads try other slots (or the base). During these + * retries, there is increased contention and reduced locality, + * which is still better than alternatives. + * + * Per-thread hash codes are initialized to random values. + * Contention and/or table collisions are indicated by failed + * CASes when performing an update operation (see method + * retryUpdate). Upon a collision, if the table size is less than + * the capacity, it is doubled in size unless some other thread + * holds the lock. If a hashed slot is empty, and lock is + * available, a new Cell is created. Otherwise, if the slot + * exists, a CAS is tried. Retries proceed by "double hashing", + * using a secondary hash (Marsaglia XorShift) to try to find a + * free slot. + * + * The table size is capped because, when there are more threads + * than CPUs, supposing that each thread were bound to a CPU, + * there would exist a perfect hash function mapping threads to + * slots that eliminates collisions. When we reach capacity, we + * search for this mapping by randomly varying the hash codes of + * colliding threads. Because search is random, and collisions + * only become known via CAS failures, convergence can be slow, + * and because threads are typically not bound to CPUS forever, + * may not occur at all. However, despite these limitations, + * observed contention rates are typically low in these cases. + * + * It is possible for a Cell to become unused when threads that + * once hashed to it terminate, as well as in the case where + * doubling the table causes no thread to hash to it under + * expanded mask. We do not try to detect or remove such cells, + * under the assumption that for long-running instances, observed + * contention levels will recur, so the cells will eventually be + * needed again; and for short-lived ones, it does not matter. + */ + + /** + * Padded variant of AtomicLong supporting only raw accesses plus CAS. + * The value field is placed between pads, hoping that the JVM doesn't + * reorder them. + * + * JVM intrinsics note: It would be possible to use a release-only + * form of CAS here, if it were provided. + */ + static final class Cell { + volatile long p0, p1, p2, p3, p4, p5, p6; + volatile long value; + volatile long q0, q1, q2, q3, q4, q5, q6; + + static AtomicLongFieldUpdater VALUE_UPDATER = AtomicLongFieldUpdater.newUpdater(Cell.class, "value"); + + Cell(long x) { value = x; } + + final boolean cas(long cmp, long val) { + return VALUE_UPDATER.compareAndSet(this, cmp, val); + } + + } + + /** + * Holder for the thread-local hash code. The code is initially + * random, but may be set to a different value upon collisions. + */ + static final class HashCode { + static final Random rng = new Random(); + int code; + HashCode() { + int h = rng.nextInt(); // Avoid zero to allow xorShift rehash + code = (h == 0) ? 1 : h; + } + } + + /** + * The corresponding ThreadLocal class + */ + static final class ThreadHashCode extends ThreadLocal { + public HashCode initialValue() { return new HashCode(); } + } + + /** + * Static per-thread hash codes. Shared across all instances to + * reduce ThreadLocal pollution and because adjustments due to + * collisions in one table are likely to be appropriate for + * others. + */ + static final ThreadHashCode threadHashCode = new ThreadHashCode(); + + /** Number of CPUS, to place bound on table size */ + static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** + * Table of cells. When non-null, size is a power of 2. + */ + transient volatile Cell[] cells; + + /** + * Base value, used mainly when there is no contention, but also as + * a fallback during table initialization races. Updated via CAS. + */ + transient volatile long base; + + /** + * Spinlock (locked via CAS) used when resizing and/or creating Cells. + */ + transient volatile int busy; + + AtomicLongFieldUpdater BASE_UPDATER = AtomicLongFieldUpdater.newUpdater(Striped64.class, "base"); + AtomicIntegerFieldUpdater BUSY_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Striped64.class, "busy"); + + /** + * Package-private default constructor + */ + Striped64() { + } + + /** + * CASes the base field. + */ + final boolean casBase(long cmp, long val) { + return BASE_UPDATER.compareAndSet(this, cmp, val); + } + + /** + * CASes the busy field from 0 to 1 to acquire lock. + */ + final boolean casBusy() { + return BUSY_UPDATER.compareAndSet(this, 0, 1); + } + + /** + * Computes the function of current and new value. Subclasses + * should open-code this update function for most uses, but the + * virtualized form is needed within retryUpdate. + * + * @param currentValue the current value (of either base or a cell) + * @param newValue the argument from a user update call + * @return result of the update function + */ + abstract long fn(long currentValue, long newValue); + + /** + * Handles cases of updates involving initialization, resizing, + * creating new Cells, and/or contention. See above for + * explanation. This method suffers the usual non-modularity + * problems of optimistic retry code, relying on rechecked sets of + * reads. + * + * @param x the value + * @param hc the hash code holder + * @param wasUncontended false if CAS failed before call + */ + final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { + int h = hc.code; + boolean collide = false; // True if last slot nonempty + for (;;) { + Cell[] as; Cell a; int n; long v; + if ((as = cells) != null && (n = as.length) > 0) { + if ((a = as[(n - 1) & h]) == null) { + if (busy == 0) { // Try to attach new Cell + Cell r = new Cell(x); // Optimistically create + if (busy == 0 && casBusy()) { + boolean created = false; + try { // Recheck under lock + Cell[] rs; int m, j; + if ((rs = cells) != null && + (m = rs.length) > 0 && + rs[j = (m - 1) & h] == null) { + rs[j] = r; + created = true; + } + } finally { + busy = 0; + } + if (created) + break; + continue; // Slot is now non-empty + } + } + collide = false; + } + else if (!wasUncontended) // CAS already known to fail + wasUncontended = true; // Continue after rehash + else if (a.cas(v = a.value, fn(v, x))) + break; + else if (n >= NCPU || cells != as) + collide = false; // At max size or stale + else if (!collide) + collide = true; + else if (busy == 0 && casBusy()) { + try { + if (cells == as) { // Expand table unless stale + Cell[] rs = new Cell[n << 1]; + for (int i = 0; i < n; ++i) + rs[i] = as[i]; + cells = rs; + } + } finally { + busy = 0; + } + collide = false; + continue; // Retry with expanded table + } + h ^= h << 13; // Rehash + h ^= h >>> 17; + h ^= h << 5; + } + else if (busy == 0 && cells == as && casBusy()) { + boolean init = false; + try { // Initialize table + if (cells == as) { + Cell[] rs = new Cell[2]; + rs[h & 1] = new Cell(x); + cells = rs; + init = true; + } + } finally { + busy = 0; + } + if (init) + break; + } + else if (casBase(v = base, fn(v, x))) + break; // Fall back on using base + } + hc.code = h; // Record index for next time + } + + + /** + * Sets base and all cells to the given value. + */ + final void internalReset(long initialValue) { + Cell[] as = cells; + base = initialValue; + if (as != null) { + int n = as.length; + for (int i = 0; i < n; ++i) { + Cell a = as[i]; + if (a != null) + a.value = initialValue; + } + } + } +} diff --git a/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java new file mode 100644 index 00000000..3ea409ff --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java @@ -0,0 +1,199 @@ +/* + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This is based on 1.16 version + +package com.concurrent_ruby.ext.jsr166y; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit calls to setSeed to succeed only + * while executing the Random constructor. We can't allow others + * since it would cause setting seed in one part of a program to + * unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal localRandom = + new ThreadLocal() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + */ + ThreadLocalRandom() { + super(); + initialized = true; + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +} diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent-ruby.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent-ruby.rb new file mode 100644 index 00000000..e9a3dea4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent-ruby.rb @@ -0,0 +1,5 @@ +# This file is here so that there is a file with the same name as the gem that +# can be required by Bundler.require. Applications should normally +# require 'concurrent'. + +require_relative "concurrent" diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent.rb new file mode 100644 index 00000000..87de46f1 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent.rb @@ -0,0 +1,134 @@ +require 'concurrent/version' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/configuration' + +require 'concurrent/atomics' +require 'concurrent/executors' +require 'concurrent/synchronization' + +require 'concurrent/atomic/atomic_markable_reference' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/agent' +require 'concurrent/atom' +require 'concurrent/array' +require 'concurrent/hash' +require 'concurrent/set' +require 'concurrent/map' +require 'concurrent/tuple' +require 'concurrent/async' +require 'concurrent/dataflow' +require 'concurrent/delay' +require 'concurrent/exchanger' +require 'concurrent/future' +require 'concurrent/immutable_struct' +require 'concurrent/ivar' +require 'concurrent/maybe' +require 'concurrent/mutable_struct' +require 'concurrent/mvar' +require 'concurrent/promise' +require 'concurrent/scheduled_task' +require 'concurrent/settable_struct' +require 'concurrent/timer_task' +require 'concurrent/tvar' +require 'concurrent/promises' + +require 'concurrent/thread_safe/synchronized_delegator' +require 'concurrent/thread_safe/util' + +require 'concurrent/options' + +# @!macro internal_implementation_note +# +# @note **Private Implementation:** This abstraction is a private, internal +# implementation detail. It should never be used directly. + +# @!macro monotonic_clock_warning +# +# @note Time calculations on all platforms and languages are sensitive to +# changes to the system clock. To alleviate the potential problems +# associated with changing the system clock while an application is running, +# most modern operating systems provide a monotonic clock that operates +# independently of the system clock. A monotonic clock cannot be used to +# determine human-friendly clock times. A monotonic clock is used exclusively +# for calculating time intervals. Not all Ruby platforms provide access to an +# operating system monotonic clock. On these platforms a pure-Ruby monotonic +# clock will be used as a fallback. An operating system monotonic clock is both +# faster and more reliable than the pure-Ruby implementation. The pure-Ruby +# implementation should be fast and reliable enough for most non-realtime +# operations. At this time the common Ruby platforms that provide access to an +# operating system monotonic clock are MRI 2.1 and above and JRuby (all versions). +# +# @see http://linux.die.net/man/3/clock_gettime Linux clock_gettime(3) + +# @!macro copy_options +# +# ## Copy Options +# +# Object references in Ruby are mutable. This can lead to serious +# problems when the {#value} of an object is a mutable reference. Which +# is always the case unless the value is a `Fixnum`, `Symbol`, or similar +# "primitive" data type. Each instance can be configured with a few +# options that can help protect the program from potentially dangerous +# operations. Each of these options can be optionally set when the object +# instance is created: +# +# * `:dup_on_deref` When true the object will call the `#dup` method on +# the `value` object every time the `#value` method is called +# (default: false) +# * `:freeze_on_deref` When true the object will call the `#freeze` +# method on the `value` object every time the `#value` method is called +# (default: false) +# * `:copy_on_deref` When given a `Proc` object the `Proc` will be run +# every time the `#value` method is called. The `Proc` will be given +# the current `value` as its only argument and the result returned by +# the block will be the return value of the `#value` call. When `nil` +# this option will be ignored (default: nil) +# +# When multiple deref options are set the order of operations is strictly defined. +# The order of deref operations is: +# * `:copy_on_deref` +# * `:dup_on_deref` +# * `:freeze_on_deref` +# +# Because of this ordering there is no need to `#freeze` an object created by a +# provided `:copy_on_deref` block. Simply set `:freeze_on_deref` to `true`. +# Setting both `:dup_on_deref` to `true` and `:freeze_on_deref` to `true` is +# as close to the behavior of a "pure" functional language (like Erlang, Clojure, +# or Haskell) as we are likely to get in Ruby. + +# @!macro deref_options +# +# @option opts [Boolean] :dup_on_deref (false) Call `#dup` before +# returning the data from {#value} +# @option opts [Boolean] :freeze_on_deref (false) Call `#freeze` before +# returning the data from {#value} +# @option opts [Proc] :copy_on_deref (nil) When calling the {#value} +# method, call the given proc passing the internal value as the sole +# argument then return the new value returned from the proc. + +# @!macro executor_and_deref_options +# +# @param [Hash] opts the options used to define the behavior at update and deref +# and to specify the executor on which to perform actions +# @option opts [Executor] :executor when set use the given `Executor` instance. +# Three special values are also supported: `:io` returns the global pool for +# long, blocking (IO) tasks, `:fast` returns the global pool for short, fast +# operations, and `:immediate` returns the global `ImmediateExecutor` object. +# @!macro deref_options + +# @!macro warn.edge +# @api Edge +# @note **Edge Features** are under active development and may change frequently. +# +# - Deprecations are not added before incompatible changes. +# - Edge version: _major_ is always 0, _minor_ bump means incompatible change, +# _patch_ bump means compatible change. +# - Edge features may also lack tests and documentation. +# - Features developed in `concurrent-ruby-edge` are expected to move +# to `concurrent-ruby` when finalised. + + +# {include:file:README.md} +module Concurrent +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/agent.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/agent.rb new file mode 100644 index 00000000..dc8a2600 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/agent.rb @@ -0,0 +1,588 @@ +require 'concurrent/configuration' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/atomic/thread_local_var' +require 'concurrent/collection/copy_on_write_observer_set' +require 'concurrent/concern/observable' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # `Agent` is inspired by Clojure's [agent](http://clojure.org/agents) + # function. An agent is a shared, mutable variable providing independent, + # uncoordinated, *asynchronous* change of individual values. Best used when + # the value will undergo frequent, complex updates. Suitable when the result + # of an update does not need to be known immediately. `Agent` is (mostly) + # functionally equivalent to Clojure's agent, except where the runtime + # prevents parity. + # + # Agents are reactive, not autonomous - there is no imperative message loop + # and no blocking receive. The state of an Agent should be itself immutable + # and the `#value` of an Agent is always immediately available for reading by + # any thread without any messages, i.e. observation does not require + # cooperation or coordination. + # + # Agent action dispatches are made using the various `#send` methods. These + # methods always return immediately. At some point later, in another thread, + # the following will happen: + # + # 1. The given `action` will be applied to the state of the Agent and the + # `args`, if any were supplied. + # 2. The return value of `action` will be passed to the validator lambda, + # if one has been set on the Agent. + # 3. If the validator succeeds or if no validator was given, the return value + # of the given `action` will become the new `#value` of the Agent. See + # `#initialize` for details. + # 4. If any observers were added to the Agent, they will be notified. See + # `#add_observer` for details. + # 5. If during the `action` execution any other dispatches are made (directly + # or indirectly), they will be held until after the `#value` of the Agent + # has been changed. + # + # If any exceptions are thrown by an action function, no nested dispatches + # will occur, and the exception will be cached in the Agent itself. When an + # Agent has errors cached, any subsequent interactions will immediately throw + # an exception, until the agent's errors are cleared. Agent errors can be + # examined with `#error` and the agent restarted with `#restart`. + # + # The actions of all Agents get interleaved amongst threads in a thread pool. + # At any point in time, at most one action for each Agent is being executed. + # Actions dispatched to an agent from another single agent or thread will + # occur in the order they were sent, potentially interleaved with actions + # dispatched to the same agent from other sources. The `#send` method should + # be used for actions that are CPU limited, while the `#send_off` method is + # appropriate for actions that may block on IO. + # + # Unlike in Clojure, `Agent` cannot participate in `Concurrent::TVar` transactions. + # + # ## Example + # + # ``` + # def next_fibonacci(set = nil) + # return [0, 1] if set.nil? + # set + [set[-2..-1].reduce{|sum,x| sum + x }] + # end + # + # # create an agent with an initial value + # agent = Concurrent::Agent.new(next_fibonacci) + # + # # send a few update requests + # 5.times do + # agent.send{|set| next_fibonacci(set) } + # end + # + # # wait for them to complete + # agent.await + # + # # get the current value + # agent.value #=> [0, 1, 1, 2, 3, 5, 8] + # ``` + # + # ## Observation + # + # Agents support observers through the {Concurrent::Observable} mixin module. + # Notification of observers occurs every time an action dispatch returns and + # the new value is successfully validated. Observation will *not* occur if the + # action raises an exception, if validation fails, or when a {#restart} occurs. + # + # When notified the observer will receive three arguments: `time`, `old_value`, + # and `new_value`. The `time` argument is the time at which the value change + # occurred. The `old_value` is the value of the Agent when the action began + # processing. The `new_value` is the value to which the Agent was set when the + # action completed. Note that `old_value` and `new_value` may be the same. + # This is not an error. It simply means that the action returned the same + # value. + # + # ## Nested Actions + # + # It is possible for an Agent action to post further actions back to itself. + # The nested actions will be enqueued normally then processed *after* the + # outer action completes, in the order they were sent, possibly interleaved + # with action dispatches from other threads. Nested actions never deadlock + # with one another and a failure in a nested action will never affect the + # outer action. + # + # Nested actions can be called using the Agent reference from the enclosing + # scope or by passing the reference in as a "send" argument. Nested actions + # cannot be post using `self` from within the action block/proc/lambda; `self` + # in this context will not reference the Agent. The preferred method for + # dispatching nested actions is to pass the Agent as an argument. This allows + # Ruby to more effectively manage the closing scope. + # + # Prefer this: + # + # ``` + # agent = Concurrent::Agent.new(0) + # agent.send(agent) do |value, this| + # this.send {|v| v + 42 } + # 3.14 + # end + # agent.value #=> 45.14 + # ``` + # + # Over this: + # + # ``` + # agent = Concurrent::Agent.new(0) + # agent.send do |value| + # agent.send {|v| v + 42 } + # 3.14 + # end + # ``` + # + # @!macro agent_await_warning + # + # **NOTE** Never, *under any circumstances*, call any of the "await" methods + # ({#await}, {#await_for}, {#await_for!}, and {#wait}) from within an action + # block/proc/lambda. The call will block the Agent and will always fail. + # Calling either {#await} or {#wait} (with a timeout of `nil`) will + # hopelessly deadlock the Agent with no possibility of recovery. + # + # @!macro thread_safe_variable_comparison + # + # @see http://clojure.org/Agents Clojure Agents + # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State + class Agent < Synchronization::LockableObject + include Concern::Observable + + ERROR_MODES = [:continue, :fail].freeze + private_constant :ERROR_MODES + + AWAIT_FLAG = ::Object.new + private_constant :AWAIT_FLAG + + AWAIT_ACTION = ->(value, latch) { latch.count_down; AWAIT_FLAG } + private_constant :AWAIT_ACTION + + DEFAULT_ERROR_HANDLER = ->(agent, error) { nil } + private_constant :DEFAULT_ERROR_HANDLER + + DEFAULT_VALIDATOR = ->(value) { true } + private_constant :DEFAULT_VALIDATOR + + Job = Struct.new(:action, :args, :executor, :caller) + private_constant :Job + + # Raised during action processing or any other time in an Agent's lifecycle. + class Error < StandardError + def initialize(message = nil) + message ||= 'agent must be restarted before jobs can post' + super(message) + end + end + + # Raised when a new value obtained during action processing or at `#restart` + # fails validation. + class ValidationError < Error + def initialize(message = nil) + message ||= 'invalid value' + super(message) + end + end + + # The error mode this Agent is operating in. See {#initialize} for details. + attr_reader :error_mode + + # Create a new `Agent` with the given initial value and options. + # + # The `:validator` option must be `nil` or a side-effect free proc/lambda + # which takes one argument. On any intended value change the validator, if + # provided, will be called. If the new value is invalid the validator should + # return `false` or raise an error. + # + # The `:error_handler` option must be `nil` or a proc/lambda which takes two + # arguments. When an action raises an error or validation fails, either by + # returning false or raising an error, the error handler will be called. The + # arguments to the error handler will be a reference to the agent itself and + # the error object which was raised. + # + # The `:error_mode` may be either `:continue` (the default if an error + # handler is given) or `:fail` (the default if error handler nil or not + # given). + # + # If an action being run by the agent throws an error or doesn't pass + # validation the error handler, if present, will be called. After the + # handler executes if the error mode is `:continue` the Agent will continue + # as if neither the action that caused the error nor the error itself ever + # happened. + # + # If the mode is `:fail` the Agent will become {#failed?} and will stop + # accepting new action dispatches. Any previously queued actions will be + # held until {#restart} is called. The {#value} method will still work, + # returning the value of the Agent before the error. + # + # @param [Object] initial the initial value + # @param [Hash] opts the configuration options + # + # @option opts [Symbol] :error_mode either `:continue` or `:fail` + # @option opts [nil, Proc] :error_handler the (optional) error handler + # @option opts [nil, Proc] :validator the (optional) validation procedure + def initialize(initial, opts = {}) + super() + synchronize { ns_initialize(initial, opts) } + end + + # The current value (state) of the Agent, irrespective of any pending or + # in-progress actions. The value is always available and is non-blocking. + # + # @return [Object] the current value + def value + @current.value # TODO (pitr 12-Sep-2015): broken unsafe read? + end + + alias_method :deref, :value + + # When {#failed?} and {#error_mode} is `:fail`, returns the error object + # which caused the failure, else `nil`. When {#error_mode} is `:continue` + # will *always* return `nil`. + # + # @return [nil, Error] the error which caused the failure when {#failed?} + def error + @error.value + end + + alias_method :reason, :error + + # @!macro agent_send + # + # Dispatches an action to the Agent and returns immediately. Subsequently, + # in a thread from a thread pool, the {#value} will be set to the return + # value of the action. Action dispatches are only allowed when the Agent + # is not {#failed?}. + # + # The action must be a block/proc/lambda which takes 1 or more arguments. + # The first argument is the current {#value} of the Agent. Any arguments + # passed to the send method via the `args` parameter will be passed to the + # action as the remaining arguments. The action must return the new value + # of the Agent. + # + # * {#send} and {#send!} should be used for actions that are CPU limited + # * {#send_off}, {#send_off!}, and {#<<} are appropriate for actions that + # may block on IO + # * {#send_via} and {#send_via!} are used when a specific executor is to + # be used for the action + # + # @param [Array] args zero or more arguments to be passed to + # the action + # @param [Proc] action the action dispatch to be enqueued + # + # @yield [agent, value, *args] process the old value and return the new + # @yieldparam [Object] value the current {#value} of the Agent + # @yieldparam [Array] args zero or more arguments to pass to the + # action + # @yieldreturn [Object] the new value of the Agent + # + # @!macro send_return + # @return [Boolean] true if the action is successfully enqueued, false if + # the Agent is {#failed?} + def send(*args, &action) + enqueue_action_job(action, args, Concurrent.global_fast_executor) + end + + # @!macro agent_send + # + # @!macro send_bang_return_and_raise + # @return [Boolean] true if the action is successfully enqueued + # @raise [Concurrent::Agent::Error] if the Agent is {#failed?} + def send!(*args, &action) + raise Error.new unless send(*args, &action) + true + end + + # @!macro agent_send + # @!macro send_return + def send_off(*args, &action) + enqueue_action_job(action, args, Concurrent.global_io_executor) + end + + alias_method :post, :send_off + + # @!macro agent_send + # @!macro send_bang_return_and_raise + def send_off!(*args, &action) + raise Error.new unless send_off(*args, &action) + true + end + + # @!macro agent_send + # @!macro send_return + # @param [Concurrent::ExecutorService] executor the executor on which the + # action is to be dispatched + def send_via(executor, *args, &action) + enqueue_action_job(action, args, executor) + end + + # @!macro agent_send + # @!macro send_bang_return_and_raise + # @param [Concurrent::ExecutorService] executor the executor on which the + # action is to be dispatched + def send_via!(executor, *args, &action) + raise Error.new unless send_via(executor, *args, &action) + true + end + + # Dispatches an action to the Agent and returns immediately. Subsequently, + # in a thread from a thread pool, the {#value} will be set to the return + # value of the action. Appropriate for actions that may block on IO. + # + # @param [Proc] action the action dispatch to be enqueued + # @return [Concurrent::Agent] self + # @see #send_off + def <<(action) + send_off(&action) + self + end + + # Blocks the current thread (indefinitely!) until all actions dispatched + # thus far, from this thread or nested by the Agent, have occurred. Will + # block when {#failed?}. Will never return if a failed Agent is {#restart} + # with `:clear_actions` true. + # + # Returns a reference to `self` to support method chaining: + # + # ``` + # current_value = agent.await.value + # ``` + # + # @return [Boolean] self + # + # @!macro agent_await_warning + def await + wait(nil) + self + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def await_for(timeout) + wait(timeout.to_f) + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout + # + # @raise [Concurrent::TimeoutError] when timeout is reached + # + # @!macro agent_await_warning + def await_for!(timeout) + raise Concurrent::TimeoutError unless wait(timeout.to_f) + true + end + + # Blocks the current thread until all actions dispatched thus far, from this + # thread or nested by the Agent, have occurred, or the timeout (in seconds) + # has elapsed. Will block indefinitely when timeout is nil or not given. + # + # Provided mainly for consistency with other classes in this library. Prefer + # the various `await` methods instead. + # + # @param [Float] timeout the maximum number of seconds to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def wait(timeout = nil) + latch = Concurrent::CountDownLatch.new(1) + enqueue_await_job(latch) + latch.wait(timeout) + end + + # Is the Agent in a failed state? + # + # @see #restart + def failed? + !@error.value.nil? + end + + alias_method :stopped?, :failed? + + # When an Agent is {#failed?}, changes the Agent {#value} to `new_value` + # then un-fails the Agent so that action dispatches are allowed again. If + # the `:clear_actions` option is give and true, any actions queued on the + # Agent that were being held while it was failed will be discarded, + # otherwise those held actions will proceed. The `new_value` must pass the + # validator if any, or `restart` will raise an exception and the Agent will + # remain failed with its old {#value} and {#error}. Observers, if any, will + # not be notified of the new state. + # + # @param [Object] new_value the new value for the Agent once restarted + # @param [Hash] opts the configuration options + # @option opts [Symbol] :clear_actions true if all enqueued but unprocessed + # actions should be discarded on restart, else false (default: false) + # @return [Boolean] true + # + # @raise [Concurrent:AgentError] when not failed + def restart(new_value, opts = {}) + clear_actions = opts.fetch(:clear_actions, false) + synchronize do + raise Error.new('agent is not failed') unless failed? + raise ValidationError unless ns_validate(new_value) + @current.value = new_value + @error.value = nil + @queue.clear if clear_actions + ns_post_next_job unless @queue.empty? + end + true + end + + class << self + + # Blocks the current thread (indefinitely!) until all actions dispatched + # thus far to all the given Agents, from this thread or nested by the + # given Agents, have occurred. Will block when any of the agents are + # failed. Will never return if a failed Agent is restart with + # `:clear_actions` true. + # + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true + # + # @!macro agent_await_warning + def await(*agents) + agents.each { |agent| agent.await } + true + end + + # Blocks the current thread until all actions dispatched thus far to all + # the given Agents, from this thread or nested by the given Agents, have + # occurred, or the timeout (in seconds) has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true if all actions complete before timeout else false + # + # @!macro agent_await_warning + def await_for(timeout, *agents) + end_at = Concurrent.monotonic_time + timeout.to_f + ok = agents.length.times do |i| + break false if (delay = end_at - Concurrent.monotonic_time) < 0 + break false unless agents[i].await_for(delay) + end + !!ok + end + + # Blocks the current thread until all actions dispatched thus far to all + # the given Agents, from this thread or nested by the given Agents, have + # occurred, or the timeout (in seconds) has elapsed. + # + # @param [Float] timeout the maximum number of seconds to wait + # @param [Array] agents the Agents on which to wait + # @return [Boolean] true if all actions complete before timeout + # + # @raise [Concurrent::TimeoutError] when timeout is reached + # @!macro agent_await_warning + def await_for!(timeout, *agents) + raise Concurrent::TimeoutError unless await_for(timeout, *agents) + true + end + end + + private + + def ns_initialize(initial, opts) + @error_mode = opts[:error_mode] + @error_handler = opts[:error_handler] + + if @error_mode && !ERROR_MODES.include?(@error_mode) + raise ArgumentError.new('unrecognized error mode') + elsif @error_mode.nil? + @error_mode = @error_handler ? :continue : :fail + end + + @error_handler ||= DEFAULT_ERROR_HANDLER + @validator = opts.fetch(:validator, DEFAULT_VALIDATOR) + @current = Concurrent::AtomicReference.new(initial) + @error = Concurrent::AtomicReference.new(nil) + @caller = Concurrent::ThreadLocalVar.new(nil) + @queue = [] + + self.observers = Collection::CopyOnNotifyObserverSet.new + end + + def enqueue_action_job(action, args, executor) + raise ArgumentError.new('no action given') unless action + job = Job.new(action, args, executor, @caller.value || Thread.current.object_id) + synchronize { ns_enqueue_job(job) } + end + + def enqueue_await_job(latch) + synchronize do + if (index = ns_find_last_job_for_thread) + job = Job.new(AWAIT_ACTION, [latch], Concurrent.global_immediate_executor, + Thread.current.object_id) + ns_enqueue_job(job, index+1) + else + latch.count_down + true + end + end + end + + def ns_enqueue_job(job, index = nil) + # a non-nil index means this is an await job + return false if index.nil? && failed? + index ||= @queue.length + @queue.insert(index, job) + # if this is the only job, post to executor + ns_post_next_job if @queue.length == 1 + true + end + + def ns_post_next_job + @queue.first.executor.post { execute_next_job } + end + + def execute_next_job + job = synchronize { @queue.first } + old_value = @current.value + + @caller.value = job.caller # for nested actions + new_value = job.action.call(old_value, *job.args) + @caller.value = nil + + return if new_value == AWAIT_FLAG + + if ns_validate(new_value) + @current.value = new_value + observers.notify_observers(Time.now, old_value, new_value) + else + handle_error(ValidationError.new) + end + rescue => error + handle_error(error) + ensure + synchronize do + @queue.shift + unless failed? || @queue.empty? + ns_post_next_job + end + end + end + + def ns_validate(value) + @validator.call(value) + rescue + false + end + + def handle_error(error) + # stop new jobs from posting + @error.value = error if @error_mode == :fail + @error_handler.call(self, error) + rescue + # do nothing + end + + def ns_find_last_job_for_thread + @queue.rindex { |job| job.caller == Thread.current.object_id } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/array.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/array.rb new file mode 100644 index 00000000..c8761af8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/array.rb @@ -0,0 +1,56 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!macro concurrent_array + # + # A thread-safe subclass of Array. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`. + # + # @note `a += b` is **not** a **thread-safe** operation on + # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array` + # which is concatenation of `a` and `b`, then it writes the concatenation to `a`. + # The read and write are independent operations they do not form a single atomic + # operation therefore when two `+=` operations are executed concurrently updates + # may be lost. Use `#concat` instead. + # + # @see http://ruby-doc.org/core/Array.html Ruby standard library `Array` + + # @!macro internal_implementation_note + ArrayImplementation = case + when Concurrent.on_cruby? + # Array is not fully thread-safe on CRuby, see + # https://github.com/ruby-concurrency/concurrent-ruby/issues/929 + # So we will need to add synchronization here + ::Array + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubyArray < ::Array + include JRuby::Synchronized + end + JRubyArray + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubyArray < ::Array + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyArray + TruffleRubyArray + + else + warn 'Possibly unsupported Ruby implementation' + ::Array + end + private_constant :ArrayImplementation + + # @!macro concurrent_array + class Array < ArrayImplementation + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/async.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/async.rb new file mode 100644 index 00000000..97c5a6b2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/async.rb @@ -0,0 +1,449 @@ +require 'concurrent/configuration' +require 'concurrent/ivar' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A mixin module that provides simple asynchronous behavior to a class, + # turning it into a simple actor. Loosely based on Erlang's + # [gen_server](http://www.erlang.org/doc/man/gen_server.html), but without + # supervision or linking. + # + # A more feature-rich {Concurrent::Actor} is also available when the + # capabilities of `Async` are too limited. + # + # ```cucumber + # Feature: + # As a stateful, plain old Ruby class + # I want safe, asynchronous behavior + # So my long-running methods don't block the main thread + # ``` + # + # The `Async` module is a way to mix simple yet powerful asynchronous + # capabilities into any plain old Ruby object or class, turning each object + # into a simple Actor. Method calls are processed on a background thread. The + # caller is free to perform other actions while processing occurs in the + # background. + # + # Method calls to the asynchronous object are made via two proxy methods: + # `async` (alias `cast`) and `await` (alias `call`). These proxy methods post + # the method call to the object's background thread and return a "future" + # which will eventually contain the result of the method call. + # + # This behavior is loosely patterned after Erlang's `gen_server` behavior. + # When an Erlang module implements the `gen_server` behavior it becomes + # inherently asynchronous. The `start` or `start_link` function spawns a + # process (similar to a thread but much more lightweight and efficient) and + # returns the ID of the process. Using the process ID, other processes can + # send messages to the `gen_server` via the `cast` and `call` methods. Unlike + # Erlang's `gen_server`, however, `Async` classes do not support linking or + # supervision trees. + # + # ## Basic Usage + # + # When this module is mixed into a class, objects of the class become inherently + # asynchronous. Each object gets its own background thread on which to post + # asynchronous method calls. Asynchronous method calls are executed in the + # background one at a time in the order they are received. + # + # To create an asynchronous class, simply mix in the `Concurrent::Async` module: + # + # ``` + # class Hello + # include Concurrent::Async + # + # def hello(name) + # "Hello, #{name}!" + # end + # end + # ``` + # + # Mixing this module into a class provides each object two proxy methods: + # `async` and `await`. These methods are thread safe with respect to the + # enclosing object. The former proxy allows methods to be called + # asynchronously by posting to the object's internal thread. The latter proxy + # allows a method to be called synchronously but does so safely with respect + # to any pending asynchronous method calls and ensures proper ordering. Both + # methods return a {Concurrent::IVar} which can be inspected for the result + # of the proxied method call. Calling a method with `async` will return a + # `:pending` `IVar` whereas `await` will return a `:complete` `IVar`. + # + # ``` + # class Echo + # include Concurrent::Async + # + # def echo(msg) + # print "#{msg}\n" + # end + # end + # + # horn = Echo.new + # horn.echo('zero') # synchronous, not thread-safe + # # returns the actual return value of the method + # + # horn.async.echo('one') # asynchronous, non-blocking, thread-safe + # # returns an IVar in the :pending state + # + # horn.await.echo('two') # synchronous, blocking, thread-safe + # # returns an IVar in the :complete state + # ``` + # + # ## Let It Fail + # + # The `async` and `await` proxy methods have built-in error protection based + # on Erlang's famous "let it fail" philosophy. Instance methods should not be + # programmed defensively. When an exception is raised by a delegated method + # the proxy will rescue the exception, expose it to the caller as the `reason` + # attribute of the returned future, then process the next method call. + # + # ## Calling Methods Internally + # + # External method calls should *always* use the `async` and `await` proxy + # methods. When one method calls another method, the `async` proxy should + # rarely be used and the `await` proxy should *never* be used. + # + # When an object calls one of its own methods using the `await` proxy the + # second call will be enqueued *behind* the currently running method call. + # Any attempt to wait on the result will fail as the second call will never + # run until after the current call completes. + # + # Calling a method using the `await` proxy from within a method that was + # itself called using `async` or `await` will irreversibly deadlock the + # object. Do *not* do this, ever. + # + # ## Instance Variables and Attribute Accessors + # + # Instance variables do not need to be thread-safe so long as they are private. + # Asynchronous method calls are processed in the order they are received and + # are processed one at a time. Therefore private instance variables can only + # be accessed by one thread at a time. This is inherently thread-safe. + # + # When using private instance variables within asynchronous methods, the best + # practice is to read the instance variable into a local variable at the start + # of the method then update the instance variable at the *end* of the method. + # This way, should an exception be raised during method execution the internal + # state of the object will not have been changed. + # + # ### Reader Attributes + # + # The use of `attr_reader` is discouraged. Internal state exposed externally, + # when necessary, should be done through accessor methods. The instance + # variables exposed by these methods *must* be thread-safe, or they must be + # called using the `async` and `await` proxy methods. These two approaches are + # subtly different. + # + # When internal state is accessed via the `async` and `await` proxy methods, + # the returned value represents the object's state *at the time the call is + # processed*, which may *not* be the state of the object at the time the call + # is made. + # + # To get the state *at the current* time, irrespective of an enqueued method + # calls, a reader method must be called directly. This is inherently unsafe + # unless the instance variable is itself thread-safe, preferably using one + # of the thread-safe classes within this library. Because the thread-safe + # classes within this library are internally-locking or non-locking, they can + # be safely used from within asynchronous methods without causing deadlocks. + # + # Generally speaking, the best practice is to *not* expose internal state via + # reader methods. The best practice is to simply use the method's return value. + # + # ### Writer Attributes + # + # Writer attributes should never be used with asynchronous classes. Changing + # the state externally, even when done in the thread-safe way, is not logically + # consistent. Changes to state need to be timed with respect to all asynchronous + # method calls which my be in-process or enqueued. The only safe practice is to + # pass all necessary data to each method as arguments and let the method update + # the internal state as necessary. + # + # ## Class Constants, Variables, and Methods + # + # ### Class Constants + # + # Class constants do not need to be thread-safe. Since they are read-only and + # immutable they may be safely read both externally and from within + # asynchronous methods. + # + # ### Class Variables + # + # Class variables should be avoided. Class variables represent shared state. + # Shared state is anathema to concurrency. Should there be a need to share + # state using class variables they *must* be thread-safe, preferably + # using the thread-safe classes within this library. When updating class + # variables, never assign a new value/object to the variable itself. Assignment + # is not thread-safe in Ruby. Instead, use the thread-safe update functions + # of the variable itself to change the value. + # + # The best practice is to *never* use class variables with `Async` classes. + # + # ### Class Methods + # + # Class methods which are pure functions are safe. Class methods which modify + # class variables should be avoided, for all the reasons listed above. + # + # ## An Important Note About Thread Safe Guarantees + # + # > Thread safe guarantees can only be made when asynchronous method calls + # > are not mixed with direct method calls. Use only direct method calls + # > when the object is used exclusively on a single thread. Use only + # > `async` and `await` when the object is shared between threads. Once you + # > call a method using `async` or `await`, you should no longer call methods + # > directly on the object. Use `async` and `await` exclusively from then on. + # + # @example + # + # class Echo + # include Concurrent::Async + # + # def echo(msg) + # print "#{msg}\n" + # end + # end + # + # horn = Echo.new + # horn.echo('zero') # synchronous, not thread-safe + # # returns the actual return value of the method + # + # horn.async.echo('one') # asynchronous, non-blocking, thread-safe + # # returns an IVar in the :pending state + # + # horn.await.echo('two') # synchronous, blocking, thread-safe + # # returns an IVar in the :complete state + # + # @see Concurrent::Actor + # @see https://en.wikipedia.org/wiki/Actor_model "Actor Model" at Wikipedia + # @see http://www.erlang.org/doc/man/gen_server.html Erlang gen_server + # @see http://c2.com/cgi/wiki?LetItCrash "Let It Crash" at http://c2.com/ + module Async + + # @!method self.new(*args, &block) + # + # Instantiate a new object and ensure proper initialization of the + # synchronization mechanisms. + # + # @param [Array] args Zero or more arguments to be passed to the + # object's initializer. + # @param [Proc] block Optional block to pass to the object's initializer. + # @return [Object] A properly initialized object of the asynchronous class. + + # Check for the presence of a method on an object and determine if a given + # set of arguments matches the required arity. + # + # @param [Object] obj the object to check against + # @param [Symbol] method the method to check the object for + # @param [Array] args zero or more arguments for the arity check + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + # + # @note This check is imperfect because of the way Ruby reports the arity of + # methods with a variable number of arguments. It is possible to determine + # if too few arguments are given but impossible to determine if too many + # arguments are given. This check may also fail to recognize dynamic behavior + # of the object, such as methods simulated with `method_missing`. + # + # @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity + # @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to? + # @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing + # + # @!visibility private + def self.validate_argc(obj, method, *args) + argc = args.length + arity = obj.method(method).arity + + if arity >= 0 && argc != arity + raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity})") + elsif arity < 0 && (arity = (arity + 1).abs) > argc + raise ArgumentError.new("wrong number of arguments (#{argc} for #{arity}..*)") + end + end + + # @!visibility private + def self.included(base) + base.singleton_class.send(:alias_method, :original_new, :new) + base.extend(ClassMethods) + super(base) + end + + # @!visibility private + module ClassMethods + def new(*args, &block) + obj = original_new(*args, &block) + obj.send(:init_synchronization) + obj + end + ruby2_keywords :new if respond_to?(:ruby2_keywords, true) + end + private_constant :ClassMethods + + # Delegates asynchronous, thread-safe method calls to the wrapped object. + # + # @!visibility private + class AsyncDelegator < Synchronization::LockableObject + safe_initialization! + + # Create a new delegator object wrapping the given delegate. + # + # @param [Object] delegate the object to wrap and delegate method calls to + def initialize(delegate) + super() + @delegate = delegate + @queue = [] + @executor = Concurrent.global_io_executor + @ruby_pid = $$ + end + + # Delegates method calls to the wrapped object. + # + # @param [Symbol] method the method being called + # @param [Array] args zero or more arguments to the method + # + # @return [IVar] the result of the method call + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + def method_missing(method, *args, &block) + super unless @delegate.respond_to?(method) + Async::validate_argc(@delegate, method, *args) + + ivar = Concurrent::IVar.new + synchronize do + reset_if_forked + @queue.push [ivar, method, args, block] + @executor.post { perform } if @queue.length == 1 + end + + ivar + end + + # Check whether the method is responsive + # + # @param [Symbol] method the method being called + def respond_to_missing?(method, include_private = false) + @delegate.respond_to?(method) || super + end + + # Perform all enqueued tasks. + # + # This method must be called from within the executor. It must not be + # called while already running. It will loop until the queue is empty. + def perform + loop do + ivar, method, args, block = synchronize { @queue.first } + break unless ivar # queue is empty + + begin + ivar.set(@delegate.send(method, *args, &block)) + rescue => error + ivar.fail(error) + end + + synchronize do + @queue.shift + return if @queue.empty? + end + end + end + + def reset_if_forked + if $$ != @ruby_pid + @queue.clear + @ruby_pid = $$ + end + end + end + private_constant :AsyncDelegator + + # Delegates synchronous, thread-safe method calls to the wrapped object. + # + # @!visibility private + class AwaitDelegator + + # Create a new delegator object wrapping the given delegate. + # + # @param [AsyncDelegator] delegate the object to wrap and delegate method calls to + def initialize(delegate) + @delegate = delegate + end + + # Delegates method calls to the wrapped object. + # + # @param [Symbol] method the method being called + # @param [Array] args zero or more arguments to the method + # + # @return [IVar] the result of the method call + # + # @raise [NameError] the object does not respond to `method` method + # @raise [ArgumentError] the given `args` do not match the arity of `method` + def method_missing(method, *args, &block) + ivar = @delegate.send(method, *args, &block) + ivar.wait + ivar + end + + # Check whether the method is responsive + # + # @param [Symbol] method the method being called + def respond_to_missing?(method, include_private = false) + @delegate.respond_to?(method) || super + end + end + private_constant :AwaitDelegator + + # Causes the chained method call to be performed asynchronously on the + # object's thread. The delegated method will return a future in the + # `:pending` state and the method call will have been scheduled on the + # object's thread. The final disposition of the method call can be obtained + # by inspecting the returned future. + # + # @!macro async_thread_safety_warning + # @note The method call is guaranteed to be thread safe with respect to + # all other method calls against the same object that are called with + # either `async` or `await`. The mutable nature of Ruby references + # (and object orientation in general) prevent any other thread safety + # guarantees. Do NOT mix direct method calls with delegated method calls. + # Use *only* delegated method calls when sharing the object between threads. + # + # @return [Concurrent::IVar] the pending result of the asynchronous operation + # + # @raise [NameError] the object does not respond to the requested method + # @raise [ArgumentError] the given `args` do not match the arity of + # the requested method + def async + @__async_delegator__ + end + alias_method :cast, :async + + # Causes the chained method call to be performed synchronously on the + # current thread. The delegated will return a future in either the + # `:fulfilled` or `:rejected` state and the delegated method will have + # completed. The final disposition of the delegated method can be obtained + # by inspecting the returned future. + # + # @!macro async_thread_safety_warning + # + # @return [Concurrent::IVar] the completed result of the synchronous operation + # + # @raise [NameError] the object does not respond to the requested method + # @raise [ArgumentError] the given `args` do not match the arity of the + # requested method + def await + @__await_delegator__ + end + alias_method :call, :await + + # Initialize the internal serializer and other stnchronization mechanisms. + # + # @note This method *must* be called immediately upon object construction. + # This is the only way thread-safe initialization can be guaranteed. + # + # @!visibility private + def init_synchronization + return self if defined?(@__async_initialized__) && @__async_initialized__ + @__async_initialized__ = true + @__async_delegator__ = AsyncDelegator.new(self) + @__await_delegator__ = AwaitDelegator.new(@__async_delegator__) + self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atom.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atom.rb new file mode 100644 index 00000000..f590a23d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atom.rb @@ -0,0 +1,222 @@ +require 'concurrent/atomic/atomic_reference' +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/concern/observable' +require 'concurrent/synchronization/object' + +# @!macro thread_safe_variable_comparison +# +# ## Thread-safe Variable Classes +# +# Each of the thread-safe variable classes is designed to solve a different +# problem. In general: +# +# * *{Concurrent::Agent}:* Shared, mutable variable providing independent, +# uncoordinated, *asynchronous* change of individual values. Best used when +# the value will undergo frequent, complex updates. Suitable when the result +# of an update does not need to be known immediately. +# * *{Concurrent::Atom}:* Shared, mutable variable providing independent, +# uncoordinated, *synchronous* change of individual values. Best used when +# the value will undergo frequent reads but only occasional, though complex, +# updates. Suitable when the result of an update must be known immediately. +# * *{Concurrent::AtomicReference}:* A simple object reference that can be updated +# atomically. Updates are synchronous but fast. Best used when updates a +# simple set operations. Not suitable when updates are complex. +# {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar +# but optimized for the given data type. +# * *{Concurrent::Exchanger}:* Shared, stateless synchronization point. Used +# when two or more threads need to exchange data. The threads will pair then +# block on each other until the exchange is complete. +# * *{Concurrent::MVar}:* Shared synchronization point. Used when one thread +# must give a value to another, which must take the value. The threads will +# block on each other until the exchange is complete. +# * *{Concurrent::ThreadLocalVar}:* Shared, mutable, isolated variable which +# holds a different value for each thread which has access. Often used as +# an instance variable in objects which must maintain different state +# for different threads. +# * *{Concurrent::TVar}:* Shared, mutable variables which provide +# *coordinated*, *synchronous*, change of *many* stated. Used when multiple +# value must change together, in an all-or-nothing transaction. + + +module Concurrent + + # Atoms provide a way to manage shared, synchronous, independent state. + # + # An atom is initialized with an initial value and an optional validation + # proc. At any time the value of the atom can be synchronously and safely + # changed. If a validator is given at construction then any new value + # will be checked against the validator and will be rejected if the + # validator returns false or raises an exception. + # + # There are two ways to change the value of an atom: {#compare_and_set} and + # {#swap}. The former will set the new value if and only if it validates and + # the current value matches the new value. The latter will atomically set the + # new value to the result of running the given block if and only if that + # value validates. + # + # ## Example + # + # ``` + # def next_fibonacci(set = nil) + # return [0, 1] if set.nil? + # set + [set[-2..-1].reduce{|sum,x| sum + x }] + # end + # + # # create an atom with an initial value + # atom = Concurrent::Atom.new(next_fibonacci) + # + # # send a few update requests + # 5.times do + # atom.swap{|set| next_fibonacci(set) } + # end + # + # # get the current value + # atom.value #=> [0, 1, 1, 2, 3, 5, 8] + # ``` + # + # ## Observation + # + # Atoms support observers through the {Concurrent::Observable} mixin module. + # Notification of observers occurs every time the value of the Atom changes. + # When notified the observer will receive three arguments: `time`, `old_value`, + # and `new_value`. The `time` argument is the time at which the value change + # occurred. The `old_value` is the value of the Atom when the change began + # The `new_value` is the value to which the Atom was set when the change + # completed. Note that `old_value` and `new_value` may be the same. This is + # not an error. It simply means that the change operation returned the same + # value. + # + # Unlike in Clojure, `Atom` cannot participate in {Concurrent::TVar} transactions. + # + # @!macro thread_safe_variable_comparison + # + # @see http://clojure.org/atoms Clojure Atoms + # @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State + class Atom < Synchronization::Object + include Concern::Observable + + safe_initialization! + attr_atomic(:value) + private :value=, :swap_value, :compare_and_set_value, :update_value + public :value + alias_method :deref, :value + + # @!method value + # The current value of the atom. + # + # @return [Object] The current value. + + # Create a new atom with the given initial value. + # + # @param [Object] value The initial value + # @param [Hash] opts The options used to configure the atom + # @option opts [Proc] :validator (nil) Optional proc used to validate new + # values. It must accept one and only one argument which will be the + # intended new value. The validator will return true if the new value + # is acceptable else return false (preferably) or raise an exception. + # + # @!macro deref_options + # + # @raise [ArgumentError] if the validator is not a `Proc` (when given) + def initialize(value, opts = {}) + super() + @Validator = opts.fetch(:validator, -> v { true }) + self.observers = Collection::CopyOnNotifyObserverSet.new + self.value = value + end + + # Atomically swaps the value of atom using the given block. The current + # value will be passed to the block, as will any arguments passed as + # arguments to the function. The new value will be validated against the + # (optional) validator proc given at construction. If validation fails the + # value will not be changed. + # + # Internally, {#swap} reads the current value, applies the block to it, and + # attempts to compare-and-set it in. Since another thread may have changed + # the value in the intervening time, it may have to retry, and does so in a + # spin loop. The net effect is that the value will always be the result of + # the application of the supplied block to a current value, atomically. + # However, because the block might be called multiple times, it must be free + # of side effects. + # + # @note The given block may be called multiple times, and thus should be free + # of side effects. + # + # @param [Object] args Zero or more arguments passed to the block. + # + # @yield [value, args] Calculates a new value for the atom based on the + # current value and any supplied arguments. + # @yieldparam value [Object] The current value of the atom. + # @yieldparam args [Object] All arguments passed to the function, in order. + # @yieldreturn [Object] The intended new value of the atom. + # + # @return [Object] The final value of the atom after all operations and + # validations are complete. + # + # @raise [ArgumentError] When no block is given. + def swap(*args) + raise ArgumentError.new('no block given') unless block_given? + + loop do + old_value = value + new_value = yield(old_value, *args) + begin + break old_value unless valid?(new_value) + break new_value if compare_and_set(old_value, new_value) + rescue + break old_value + end + end + end + + # Atomically sets the value of atom to the new value if and only if the + # current value of the atom is identical to the old value and the new + # value successfully validates against the (optional) validator given + # at construction. + # + # @param [Object] old_value The expected current value. + # @param [Object] new_value The intended new value. + # + # @return [Boolean] True if the value is changed else false. + def compare_and_set(old_value, new_value) + if valid?(new_value) && compare_and_set_value(old_value, new_value) + observers.notify_observers(Time.now, old_value, new_value) + true + else + false + end + end + + # Atomically sets the value of atom to the new value without regard for the + # current value so long as the new value successfully validates against the + # (optional) validator given at construction. + # + # @param [Object] new_value The intended new value. + # + # @return [Object] The final value of the atom after all operations and + # validations are complete. + def reset(new_value) + old_value = value + if valid?(new_value) + self.value = new_value + observers.notify_observers(Time.now, old_value, new_value) + new_value + else + old_value + end + end + + private + + # Is the new value valid? + # + # @param [Object] new_value The intended new value. + # @return [Boolean] false if the validator function returns false or raises + # an exception else true + def valid?(new_value) + @Validator.call(new_value) + rescue + false + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb new file mode 100644 index 00000000..f775691a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb @@ -0,0 +1,127 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic/mutex_atomic_boolean' + +module Concurrent + + ################################################################### + + # @!macro atomic_boolean_method_initialize + # + # Creates a new `AtomicBoolean` with the given initial value. + # + # @param [Boolean] initial the initial value + + # @!macro atomic_boolean_method_value_get + # + # Retrieves the current `Boolean` value. + # + # @return [Boolean] the current value + + # @!macro atomic_boolean_method_value_set + # + # Explicitly sets the value. + # + # @param [Boolean] value the new value to be set + # + # @return [Boolean] the current value + + # @!macro atomic_boolean_method_true_question + # + # Is the current value `true` + # + # @return [Boolean] true if the current value is `true`, else false + + # @!macro atomic_boolean_method_false_question + # + # Is the current value `false` + # + # @return [Boolean] true if the current value is `false`, else false + + # @!macro atomic_boolean_method_make_true + # + # Explicitly sets the value to true. + # + # @return [Boolean] true if value has changed, otherwise false + + # @!macro atomic_boolean_method_make_false + # + # Explicitly sets the value to false. + # + # @return [Boolean] true if value has changed, otherwise false + + ################################################################### + + # @!macro atomic_boolean_public_api + # + # @!method initialize(initial = false) + # @!macro atomic_boolean_method_initialize + # + # @!method value + # @!macro atomic_boolean_method_value_get + # + # @!method value=(value) + # @!macro atomic_boolean_method_value_set + # + # @!method true? + # @!macro atomic_boolean_method_true_question + # + # @!method false? + # @!macro atomic_boolean_method_false_question + # + # @!method make_true + # @!macro atomic_boolean_method_make_true + # + # @!method make_false + # @!macro atomic_boolean_method_make_false + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + AtomicBooleanImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + CAtomicBoolean + when Concurrent.on_jruby? + JavaAtomicBoolean + else + MutexAtomicBoolean + end + private_constant :AtomicBooleanImplementation + + # @!macro atomic_boolean + # + # A boolean value that can be updated atomically. Reads and writes to an atomic + # boolean and thread-safe and guaranteed to succeed. Reads and writes may block + # briefly but no explicit locking is required. + # + # @!macro thread_safe_variable_comparison + # + # Performance: + # + # ``` + # Testing with ruby 2.1.2 + # Testing with Concurrent::MutexAtomicBoolean... + # 2.790000 0.000000 2.790000 ( 2.791454) + # Testing with Concurrent::CAtomicBoolean... + # 0.740000 0.000000 0.740000 ( 0.740206) + # + # Testing with jruby 1.9.3 + # Testing with Concurrent::MutexAtomicBoolean... + # 5.240000 2.520000 7.760000 ( 3.683000) + # Testing with Concurrent::JavaAtomicBoolean... + # 3.340000 0.010000 3.350000 ( 0.855000) + # ``` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean + # + # @!macro atomic_boolean_public_api + class AtomicBoolean < AtomicBooleanImplementation + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], value + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb new file mode 100644 index 00000000..26cd05d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb @@ -0,0 +1,144 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic/mutex_atomic_fixnum' + +module Concurrent + + ################################################################### + + # @!macro atomic_fixnum_method_initialize + # + # Creates a new `AtomicFixnum` with the given initial value. + # + # @param [Fixnum] initial the initial value + # @raise [ArgumentError] if the initial value is not a `Fixnum` + + # @!macro atomic_fixnum_method_value_get + # + # Retrieves the current `Fixnum` value. + # + # @return [Fixnum] the current value + + # @!macro atomic_fixnum_method_value_set + # + # Explicitly sets the value. + # + # @param [Fixnum] value the new value to be set + # + # @return [Fixnum] the current value + # + # @raise [ArgumentError] if the new value is not a `Fixnum` + + # @!macro atomic_fixnum_method_increment + # + # Increases the current value by the given amount (defaults to 1). + # + # @param [Fixnum] delta the amount by which to increase the current value + # + # @return [Fixnum] the current value after incrementation + + # @!macro atomic_fixnum_method_decrement + # + # Decreases the current value by the given amount (defaults to 1). + # + # @param [Fixnum] delta the amount by which to decrease the current value + # + # @return [Fixnum] the current value after decrementation + + # @!macro atomic_fixnum_method_compare_and_set + # + # Atomically sets the value to the given updated value if the current + # value == the expected value. + # + # @param [Fixnum] expect the expected value + # @param [Fixnum] update the new value + # + # @return [Boolean] true if the value was updated else false + + # @!macro atomic_fixnum_method_update + # + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # + # @return [Object] the new value + + ################################################################### + + # @!macro atomic_fixnum_public_api + # + # @!method initialize(initial = 0) + # @!macro atomic_fixnum_method_initialize + # + # @!method value + # @!macro atomic_fixnum_method_value_get + # + # @!method value=(value) + # @!macro atomic_fixnum_method_value_set + # + # @!method increment(delta = 1) + # @!macro atomic_fixnum_method_increment + # + # @!method decrement(delta = 1) + # @!macro atomic_fixnum_method_decrement + # + # @!method compare_and_set(expect, update) + # @!macro atomic_fixnum_method_compare_and_set + # + # @!method update + # @!macro atomic_fixnum_method_update + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + AtomicFixnumImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + CAtomicFixnum + when Concurrent.on_jruby? + JavaAtomicFixnum + else + MutexAtomicFixnum + end + private_constant :AtomicFixnumImplementation + + # @!macro atomic_fixnum + # + # A numeric value that can be updated atomically. Reads and writes to an atomic + # fixnum and thread-safe and guaranteed to succeed. Reads and writes may block + # briefly but no explicit locking is required. + # + # @!macro thread_safe_variable_comparison + # + # Performance: + # + # ``` + # Testing with ruby 2.1.2 + # Testing with Concurrent::MutexAtomicFixnum... + # 3.130000 0.000000 3.130000 ( 3.136505) + # Testing with Concurrent::CAtomicFixnum... + # 0.790000 0.000000 0.790000 ( 0.785550) + # + # Testing with jruby 1.9.3 + # Testing with Concurrent::MutexAtomicFixnum... + # 5.460000 2.460000 7.920000 ( 3.715000) + # Testing with Concurrent::JavaAtomicFixnum... + # 4.520000 0.030000 4.550000 ( 1.187000) + # ``` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong + # + # @!macro atomic_fixnum_public_api + class AtomicFixnum < AtomicFixnumImplementation + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], value + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb new file mode 100644 index 00000000..e16be657 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb @@ -0,0 +1,167 @@ +require 'concurrent/errors' +require 'concurrent/synchronization/object' + +module Concurrent + # An atomic reference which maintains an object reference along with a mark bit + # that can be updated atomically. + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html + # java.util.concurrent.atomic.AtomicMarkableReference + class AtomicMarkableReference < ::Concurrent::Synchronization::Object + + attr_atomic(:reference) + private :reference, :reference=, :swap_reference, :compare_and_set_reference, :update_reference + + def initialize(value = nil, mark = false) + super() + self.reference = immutable_array(value, mark) + end + + # Atomically sets the value and mark to the given updated value and + # mark given both: + # - the current value == the expected value && + # - the current mark == the expected mark + # + # @param [Object] expected_val the expected value + # @param [Object] new_val the new value + # @param [Boolean] expected_mark the expected mark + # @param [Boolean] new_mark the new mark + # + # @return [Boolean] `true` if successful. A `false` return indicates + # that the actual value was not equal to the expected value or the + # actual mark was not equal to the expected mark + def compare_and_set(expected_val, new_val, expected_mark, new_mark) + # Memoize a valid reference to the current AtomicReference for + # later comparison. + current = reference + curr_val, curr_mark = current + + # Ensure that that the expected marks match. + return false unless expected_mark == curr_mark + + if expected_val.is_a? Numeric + # If the object is a numeric, we need to ensure we are comparing + # the numerical values + return false unless expected_val == curr_val + else + # Otherwise, we need to ensure we are comparing the object identity. + # Theoretically, this could be incorrect if a user monkey-patched + # `Object#equal?`, but they should know that they are playing with + # fire at that point. + return false unless expected_val.equal? curr_val + end + + prospect = immutable_array(new_val, new_mark) + + compare_and_set_reference current, prospect + end + + alias_method :compare_and_swap, :compare_and_set + + # Gets the current reference and marked values. + # + # @return [Array] the current reference and marked values + def get + reference + end + + # Gets the current value of the reference + # + # @return [Object] the current value of the reference + def value + reference[0] + end + + # Gets the current marked value + # + # @return [Boolean] the current marked value + def mark + reference[1] + end + + alias_method :marked?, :mark + + # _Unconditionally_ sets to the given value of both the reference and + # the mark. + # + # @param [Object] new_val the new value + # @param [Boolean] new_mark the new mark + # + # @return [Array] both the new value and the new mark + def set(new_val, new_mark) + self.reference = immutable_array(new_val, new_mark) + end + + # Pass the current value and marked state to the given block, replacing it + # with the block's results. May retry if the value changes during the + # block's execution. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and new mark + def update + loop do + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + if compare_and_set old_val, new_val, old_mark, new_mark + return immutable_array(new_val, new_mark) + end + end + end + + # Pass the current value to the given block, replacing it + # with the block's result. Raise an exception if the update + # fails. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and marked state + # + # @raise [Concurrent::ConcurrentUpdateError] if the update fails + def try_update! + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + unless compare_and_set old_val, new_val, old_mark, new_mark + fail ::Concurrent::ConcurrentUpdateError, + 'AtomicMarkableReference: Update failed due to race condition.', + 'Note: If you would like to guarantee an update, please use ' + + 'the `AtomicMarkableReference#update` method.' + end + + immutable_array(new_val, new_mark) + end + + # Pass the current value to the given block, replacing it with the + # block's result. Simply return nil if update fails. + # + # @yield [Object] Calculate a new value and marked state for the atomic + # reference using given (old) value and (old) marked + # @yieldparam [Object] old_val the starting value of the atomic reference + # @yieldparam [Boolean] old_mark the starting state of marked + # + # @return [Array] the new value and marked state, or nil if + # the update failed + def try_update + old_val, old_mark = reference + new_val, new_mark = yield old_val, old_mark + + return unless compare_and_set old_val, new_val, old_mark, new_mark + + immutable_array(new_val, new_mark) + end + + private + + def immutable_array(*args) + args.freeze + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb new file mode 100644 index 00000000..0b19b779 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb @@ -0,0 +1,142 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/atomic_reference/atomic_direct_update' +require 'concurrent/atomic_reference/numeric_cas_wrapper' +require 'concurrent/atomic_reference/mutex_atomic' + +# Shim for TruffleRuby::AtomicReference +if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference) + # @!visibility private + module TruffleRuby + AtomicReference = Truffle::AtomicReference + end +end + +module Concurrent + + # @!macro internal_implementation_note + AtomicReferenceImplementation = case + when Concurrent.on_cruby? && Concurrent.c_extensions_loaded? + # @!visibility private + # @!macro internal_implementation_note + class CAtomicReference + include AtomicDirectUpdate + include AtomicNumericCompareAndSetWrapper + end + CAtomicReference + when Concurrent.on_jruby? + # @!visibility private + # @!macro internal_implementation_note + class JavaAtomicReference + include AtomicDirectUpdate + include AtomicNumericCompareAndSetWrapper + end + JavaAtomicReference + when Concurrent.on_truffleruby? + class TruffleRubyAtomicReference < TruffleRuby::AtomicReference + include AtomicDirectUpdate + if private_method_defined?(:compare_and_set_reference) + alias_method :_compare_and_set, :compare_and_set_reference + private :_compare_and_set + include AtomicNumericCompareAndSetWrapper + else + # AtomicNumericCompareAndSetWrapper behavior already in TruffleRuby::AtomicReference + alias_method :compare_and_swap, :compare_and_set + end + alias_method :value, :get + alias_method :value=, :set + alias_method :swap, :get_and_set + end + TruffleRubyAtomicReference + else + MutexAtomicReference + end + private_constant :AtomicReferenceImplementation + + # An object reference that may be updated atomically. All read and write + # operations have java volatile semantic. + # + # @!macro thread_safe_variable_comparison + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html + # + # @!method initialize(value = nil) + # @!macro atomic_reference_method_initialize + # @param [Object] value The initial value. + # + # @!method get + # @!macro atomic_reference_method_get + # Gets the current value. + # @return [Object] the current value + # + # @!method set(new_value) + # @!macro atomic_reference_method_set + # Sets to the given value. + # @param [Object] new_value the new value + # @return [Object] the new value + # + # @!method get_and_set(new_value) + # @!macro atomic_reference_method_get_and_set + # Atomically sets to the given value and returns the old value. + # @param [Object] new_value the new value + # @return [Object] the old value + # + # @!method compare_and_set(old_value, new_value) + # @!macro atomic_reference_method_compare_and_set + # + # Atomically sets the value to the given updated value if + # the current value == the expected value. + # + # @param [Object] old_value the expected value + # @param [Object] new_value the new value + # + # @return [Boolean] `true` if successful. A `false` return indicates + # that the actual value was not equal to the expected value. + # + # @!method update + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @return [Object] the new value + # + # @!method try_update + # Pass the current value to the given block, replacing it + # with the block's result. Return nil if the update fails. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @note This method was altered to avoid raising an exception by default. + # Instead, this method now returns `nil` in case of failure. For more info, + # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 + # @return [Object] the new value, or nil if update failed + # + # @!method try_update! + # Pass the current value to the given block, replacing it + # with the block's result. Raise an exception if the update + # fails. + # + # @yield [Object] Calculate a new value for the atomic reference using + # given (old) value + # @yieldparam [Object] old_value the starting value of the atomic reference + # @note This behavior mimics the behavior of the original + # `AtomicReference#try_update` API. The reason this was changed was to + # avoid raising exceptions (which are inherently slow) by default. For more + # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336 + # @return [Object] the new value + # @raise [Concurrent::ConcurrentUpdateError] if the update fails + class AtomicReference < AtomicReferenceImplementation + + # @return [String] Short string representation. + def to_s + format '%s value:%s>', super[0..-2], get + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb new file mode 100644 index 00000000..d883aed6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb @@ -0,0 +1,100 @@ +require 'concurrent/utility/engine' +require 'concurrent/atomic/mutex_count_down_latch' +require 'concurrent/atomic/java_count_down_latch' + +module Concurrent + + ################################################################### + + # @!macro count_down_latch_method_initialize + # + # Create a new `CountDownLatch` with the initial `count`. + # + # @param [new] count the initial count + # + # @raise [ArgumentError] if `count` is not an integer or is less than zero + + # @!macro count_down_latch_method_wait + # + # Block on the latch until the counter reaches zero or until `timeout` is reached. + # + # @param [Fixnum] timeout the number of seconds to wait for the counter or `nil` + # to block indefinitely + # @return [Boolean] `true` if the `count` reaches zero else false on `timeout` + + # @!macro count_down_latch_method_count_down + # + # Signal the latch to decrement the counter. Will signal all blocked threads when + # the `count` reaches zero. + + # @!macro count_down_latch_method_count + # + # The current value of the counter. + # + # @return [Fixnum] the current value of the counter + + ################################################################### + + # @!macro count_down_latch_public_api + # + # @!method initialize(count = 1) + # @!macro count_down_latch_method_initialize + # + # @!method wait(timeout = nil) + # @!macro count_down_latch_method_wait + # + # @!method count_down + # @!macro count_down_latch_method_count_down + # + # @!method count + # @!macro count_down_latch_method_count + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + CountDownLatchImplementation = case + when Concurrent.on_jruby? + JavaCountDownLatch + else + MutexCountDownLatch + end + private_constant :CountDownLatchImplementation + + # @!macro count_down_latch + # + # A synchronization object that allows one thread to wait on multiple other threads. + # The thread that will wait creates a `CountDownLatch` and sets the initial value + # (normally equal to the number of other threads). The initiating thread passes the + # latch to the other threads then waits for the other threads by calling the `#wait` + # method. Each of the other threads calls `#count_down` when done with its work. + # When the latch counter reaches zero the waiting thread is unblocked and continues + # with its work. A `CountDownLatch` can be used only once. Its value cannot be reset. + # + # @!macro count_down_latch_public_api + # @example Waiter and Decrementer + # latch = Concurrent::CountDownLatch.new(3) + # + # waiter = Thread.new do + # latch.wait() + # puts ("Waiter released") + # end + # + # decrementer = Thread.new do + # sleep(1) + # latch.count_down + # puts latch.count + # + # sleep(1) + # latch.count_down + # puts latch.count + # + # sleep(1) + # latch.count_down + # puts latch.count + # end + # + # [waiter, decrementer].each(&:join) + class CountDownLatch < CountDownLatchImplementation + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb new file mode 100644 index 00000000..9ebe29dd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb @@ -0,0 +1,128 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # A synchronization aid that allows a set of threads to all wait for each + # other to reach a common barrier point. + # @example + # barrier = Concurrent::CyclicBarrier.new(3) + # jobs = Array.new(3) { |i| -> { sleep i; p done: i } } + # process = -> (i) do + # # waiting to start at the same time + # barrier.wait + # # execute job + # jobs[i].call + # # wait for others to finish + # barrier.wait + # end + # threads = 2.times.map do |i| + # Thread.new(i, &process) + # end + # + # # use main as well + # process.call 2 + # + # # here we can be sure that all jobs are processed + class CyclicBarrier < Synchronization::LockableObject + + # @!visibility private + Generation = Struct.new(:status) + private_constant :Generation + + # Create a new `CyclicBarrier` that waits for `parties` threads + # + # @param [Fixnum] parties the number of parties + # @yield an optional block that will be executed that will be executed after + # the last thread arrives and before the others are released + # + # @raise [ArgumentError] if `parties` is not an integer or is less than zero + def initialize(parties, &block) + Utility::NativeInteger.ensure_integer_and_bounds parties + Utility::NativeInteger.ensure_positive_and_no_zero parties + + super(&nil) + synchronize { ns_initialize parties, &block } + end + + # @return [Fixnum] the number of threads needed to pass the barrier + def parties + synchronize { @parties } + end + + # @return [Fixnum] the number of threads currently waiting on the barrier + def number_waiting + synchronize { @number_waiting } + end + + # Blocks on the barrier until the number of waiting threads is equal to + # `parties` or until `timeout` is reached or `reset` is called + # If a block has been passed to the constructor, it will be executed once by + # the last arrived thread before releasing the others + # @param [Fixnum] timeout the number of seconds to wait for the counter or + # `nil` to block indefinitely + # @return [Boolean] `true` if the `count` reaches zero else false on + # `timeout` or on `reset` or if the barrier is broken + def wait(timeout = nil) + synchronize do + + return false unless @generation.status == :waiting + + @number_waiting += 1 + + if @number_waiting == @parties + @action.call if @action + ns_generation_done @generation, :fulfilled + true + else + generation = @generation + if ns_wait_until(timeout) { generation.status != :waiting } + generation.status == :fulfilled + else + ns_generation_done generation, :broken, false + false + end + end + end + end + + # resets the barrier to its initial state + # If there is at least one waiting thread, it will be woken up, the `wait` + # method will return false and the barrier will be broken + # If the barrier is broken, this method restores it to the original state + # + # @return [nil] + def reset + synchronize { ns_generation_done @generation, :reset } + end + + # A barrier can be broken when: + # - a thread called the `reset` method while at least one other thread was waiting + # - at least one thread timed out on `wait` method + # + # A broken barrier can be restored using `reset` it's safer to create a new one + # @return [Boolean] true if the barrier is broken otherwise false + def broken? + synchronize { @generation.status != :waiting } + end + + protected + + def ns_generation_done(generation, status, continue = true) + generation.status = status + ns_next_generation if continue + ns_broadcast + end + + def ns_next_generation + @generation = Generation.new(:waiting) + @number_waiting = 0 + end + + def ns_initialize(parties, &block) + @parties = parties + @action = block + ns_next_generation + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/event.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/event.rb new file mode 100644 index 00000000..ccf84c9d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/event.rb @@ -0,0 +1,109 @@ +require 'thread' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # Old school kernel-style event reminiscent of Win32 programming in C++. + # + # When an `Event` is created it is in the `unset` state. Threads can choose to + # `#wait` on the event, blocking until released by another thread. When one + # thread wants to alert all blocking threads it calls the `#set` method which + # will then wake up all listeners. Once an `Event` has been set it remains set. + # New threads calling `#wait` will return immediately. An `Event` may be + # `#reset` at any time once it has been set. + # + # @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx + # @example + # event = Concurrent::Event.new + # + # t1 = Thread.new do + # puts "t1 is waiting" + # event.wait(1) + # puts "event occurred" + # end + # + # t2 = Thread.new do + # puts "t2 calling set" + # event.set + # end + # + # [t1, t2].each(&:join) + # + # # prints: + # # t1 is waiting + # # t2 calling set + # # event occurred + class Event < Synchronization::LockableObject + + # Creates a new `Event` in the unset state. Threads calling `#wait` on the + # `Event` will block. + def initialize + super + synchronize { ns_initialize } + end + + # Is the object in the set state? + # + # @return [Boolean] indicating whether or not the `Event` has been set + def set? + synchronize { @set } + end + + # Trigger the event, setting the state to `set` and releasing all threads + # waiting on the event. Has no effect if the `Event` has already been set. + # + # @return [Boolean] should always return `true` + def set + synchronize { ns_set } + end + + def try? + synchronize { @set ? false : ns_set } + end + + # Reset a previously set event back to the `unset` state. + # Has no effect if the `Event` has not yet been set. + # + # @return [Boolean] should always return `true` + def reset + synchronize do + if @set + @set = false + @iteration +=1 + end + true + end + end + + # Wait a given number of seconds for the `Event` to be set by another + # thread. Will wait forever when no `timeout` value is given. Returns + # immediately if the `Event` has already been set. + # + # @return [Boolean] true if the `Event` was set before timeout else false + def wait(timeout = nil) + synchronize do + unless @set + iteration = @iteration + ns_wait_until(timeout) { iteration < @iteration || @set } + else + true + end + end + end + + protected + + def ns_set + unless @set + @set = true + ns_broadcast + end + true + end + + def ns_initialize + @set = false + @iteration = 0 + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb new file mode 100644 index 00000000..e90fc24f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb @@ -0,0 +1,109 @@ +require 'concurrent/constants' +require_relative 'locals' + +module Concurrent + + # A `FiberLocalVar` is a variable where the value is different for each fiber. + # Each variable may have a default value, but when you modify the variable only + # the current fiber will ever see that change. + # + # This is similar to Ruby's built-in fiber-local variables (`Thread.current[:name]`), + # but with these major advantages: + # * `FiberLocalVar` has its own identity, it doesn't need a Symbol. + # * Each Ruby's built-in fiber-local variable leaks some memory forever (it's a Symbol held forever on the fiber), + # so it's only OK to create a small amount of them. + # `FiberLocalVar` has no such issue and it is fine to create many of them. + # * Ruby's built-in fiber-local variables leak forever the value set on each fiber (unless set to nil explicitly). + # `FiberLocalVar` automatically removes the mapping for each fiber once the `FiberLocalVar` instance is GC'd. + # + # @example + # v = FiberLocalVar.new(14) + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # + # @example + # v = FiberLocalVar.new(14) + # + # Fiber.new do + # v.value #=> 14 + # v.value = 1 + # v.value #=> 1 + # end.resume + # + # Fiber.new do + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # end.resume + # + # v.value #=> 14 + class FiberLocalVar + LOCALS = FiberLocals.new + + # Creates a fiber local variable. + # + # @param [Object] default the default value when otherwise unset + # @param [Proc] default_block Optional block that gets called to obtain the + # default value for each fiber + def initialize(default = nil, &default_block) + if default && block_given? + raise ArgumentError, "Cannot use both value and block as default value" + end + + if block_given? + @default_block = default_block + @default = nil + else + @default_block = nil + @default = default + end + + @index = LOCALS.next_index(self) + end + + # Returns the value in the current fiber's copy of this fiber-local variable. + # + # @return [Object] the current value + def value + LOCALS.fetch(@index) { default } + end + + # Sets the current fiber's copy of this fiber-local variable to the specified value. + # + # @param [Object] value the value to set + # @return [Object] the new value + def value=(value) + LOCALS.set(@index, value) + end + + # Bind the given value to fiber local storage during + # execution of the given block. + # + # @param [Object] value the value to bind + # @yield the operation to be performed with the bound variable + # @return [Object] the value + def bind(value) + if block_given? + old_value = self.value + self.value = value + begin + yield + ensure + self.value = old_value + end + end + end + + protected + + # @!visibility private + def default + if @default_block + self.value = @default_block.call + else + @default + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb new file mode 100644 index 00000000..3c119bc3 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb @@ -0,0 +1,43 @@ +if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + + module Concurrent + + # @!macro count_down_latch + # @!visibility private + # @!macro internal_implementation_note + class JavaCountDownLatch + + # @!macro count_down_latch_method_initialize + def initialize(count = 1) + Utility::NativeInteger.ensure_integer_and_bounds(count) + Utility::NativeInteger.ensure_positive(count) + @latch = java.util.concurrent.CountDownLatch.new(count) + end + + # @!macro count_down_latch_method_wait + def wait(timeout = nil) + result = nil + if timeout.nil? + Synchronization::JRuby.sleep_interruptibly { @latch.await } + result = true + else + Synchronization::JRuby.sleep_interruptibly do + result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + result + end + + # @!macro count_down_latch_method_count_down + def count_down + @latch.countDown + end + + # @!macro count_down_latch_method_count + def count + @latch.getCount + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/locals.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/locals.rb new file mode 100644 index 00000000..0a276aed --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/locals.rb @@ -0,0 +1,189 @@ +require 'fiber' +require 'concurrent/utility/engine' +require 'concurrent/constants' + +module Concurrent + # @!visibility private + # @!macro internal_implementation_note + # + # An abstract implementation of local storage, with sub-classes for + # per-thread and per-fiber locals. + # + # Each execution context (EC, thread or fiber) has a lazily initialized array + # of local variable values. Each time a new local variable is created, we + # allocate an "index" for it. + # + # For example, if the allocated index is 1, that means slot #1 in EVERY EC's + # locals array will be used for the value of that variable. + # + # The good thing about using a per-EC structure to hold values, rather than + # a global, is that no synchronization is needed when reading and writing + # those values (since the structure is only ever accessed by a single + # thread). + # + # Of course, when a local variable is GC'd, 1) we need to recover its index + # for use by other new local variables (otherwise the locals arrays could + # get bigger and bigger with time), and 2) we need to null out all the + # references held in the now-unused slots (both to avoid blocking GC of those + # objects, and also to prevent "stale" values from being passed on to a new + # local when the index is reused). + # + # Because we need to null out freed slots, we need to keep references to + # ALL the locals arrays, so we can null out the appropriate slots in all of + # them. This is why we need to use a finalizer to clean up the locals array + # when the EC goes out of scope. + class AbstractLocals + def initialize + @free = [] + @lock = Mutex.new + @all_arrays = {} + @next = 0 + end + + def synchronize + @lock.synchronize { yield } + end + + if Concurrent.on_cruby? + def weak_synchronize + yield + end + else + alias_method :weak_synchronize, :synchronize + end + + def next_index(local) + index = synchronize do + if @free.empty? + @next += 1 + else + @free.pop + end + end + + # When the local goes out of scope, we should free the associated index + # and all values stored into it. + ObjectSpace.define_finalizer(local, local_finalizer(index)) + + index + end + + def free_index(index) + weak_synchronize do + # The cost of GC'ing a TLV is linear in the number of ECs using local + # variables. But that is natural! More ECs means more storage is used + # per local variable. So naturally more CPU time is required to free + # more storage. + # + # DO NOT use each_value which might conflict with new pair assignment + # into the hash in #set method. + @all_arrays.values.each do |locals| + locals[index] = nil + end + + # free index has to be published after the arrays are cleared: + @free << index + end + end + + def fetch(index) + locals = self.locals + value = locals ? locals[index] : nil + + if nil == value + yield + elsif NULL.equal?(value) + nil + else + value + end + end + + def set(index, value) + locals = self.locals! + locals[index] = (nil == value ? NULL : value) + + value + end + + private + + # When the local goes out of scope, clean up that slot across all locals currently assigned. + def local_finalizer(index) + proc do + free_index(index) + end + end + + # When a thread/fiber goes out of scope, remove the array from @all_arrays. + def thread_fiber_finalizer(array_object_id) + proc do + weak_synchronize do + @all_arrays.delete(array_object_id) + end + end + end + + # Returns the locals for the current scope, or nil if none exist. + def locals + raise NotImplementedError + end + + # Returns the locals for the current scope, creating them if necessary. + def locals! + raise NotImplementedError + end + end + + # @!visibility private + # @!macro internal_implementation_note + # An array-backed storage of indexed variables per thread. + class ThreadLocals < AbstractLocals + def locals + Thread.current.thread_variable_get(:concurrent_thread_locals) + end + + def locals! + thread = Thread.current + locals = thread.thread_variable_get(:concurrent_thread_locals) + + unless locals + locals = thread.thread_variable_set(:concurrent_thread_locals, []) + weak_synchronize do + @all_arrays[locals.object_id] = locals + end + # When the thread goes out of scope, we should delete the associated locals: + ObjectSpace.define_finalizer(thread, thread_fiber_finalizer(locals.object_id)) + end + + locals + end + end + + # @!visibility private + # @!macro internal_implementation_note + # An array-backed storage of indexed variables per fiber. + class FiberLocals < AbstractLocals + def locals + Thread.current[:concurrent_fiber_locals] + end + + def locals! + thread = Thread.current + locals = thread[:concurrent_fiber_locals] + + unless locals + locals = thread[:concurrent_fiber_locals] = [] + weak_synchronize do + @all_arrays[locals.object_id] = locals + end + # When the fiber goes out of scope, we should delete the associated locals: + ObjectSpace.define_finalizer(Fiber.current, thread_fiber_finalizer(locals.object_id)) + end + + locals + end + end + + private_constant :AbstractLocals, :ThreadLocals, :FiberLocals +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb new file mode 100644 index 00000000..c367d262 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb @@ -0,0 +1,29 @@ +require 'concurrent/utility/engine' +require_relative 'fiber_local_var' +require_relative 'thread_local_var' + +module Concurrent + # @!visibility private + def self.mutex_owned_per_thread? + return false if Concurrent.on_jruby? || Concurrent.on_truffleruby? + return RUBY_VERSION < "3.0" if Concurrent.on_cruby? + + mutex = Mutex.new + # Lock the mutex: + mutex.synchronize do + # Check if the mutex is still owned in a child fiber: + Fiber.new { mutex.owned? }.resume + end + end + + if mutex_owned_per_thread? + LockLocalVar = ThreadLocalVar + else + LockLocalVar = FiberLocalVar + end + + # Either {FiberLocalVar} or {ThreadLocalVar} depending on whether Mutex (and Monitor) + # are held, respectively, per Fiber or per Thread. + class LockLocalVar + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb new file mode 100644 index 00000000..015996b0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb @@ -0,0 +1,68 @@ +require 'concurrent/synchronization/safe_initialization' + +module Concurrent + + # @!macro atomic_boolean + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicBoolean + extend Concurrent::Synchronization::SafeInitialization + + # @!macro atomic_boolean_method_initialize + def initialize(initial = false) + super() + @Lock = ::Mutex.new + @value = !!initial + end + + # @!macro atomic_boolean_method_value_get + def value + synchronize { @value } + end + + # @!macro atomic_boolean_method_value_set + def value=(value) + synchronize { @value = !!value } + end + + # @!macro atomic_boolean_method_true_question + def true? + synchronize { @value } + end + + # @!macro atomic_boolean_method_false_question + def false? + synchronize { !@value } + end + + # @!macro atomic_boolean_method_make_true + def make_true + synchronize { ns_make_value(true) } + end + + # @!macro atomic_boolean_method_make_false + def make_false + synchronize { ns_make_value(false) } + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + + private + + # @!visibility private + def ns_make_value(value) + old = @value + @value = value + old != @value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb new file mode 100644 index 00000000..0ca39557 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb @@ -0,0 +1,81 @@ +require 'concurrent/synchronization/safe_initialization' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro atomic_fixnum + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicFixnum + extend Concurrent::Synchronization::SafeInitialization + + # @!macro atomic_fixnum_method_initialize + def initialize(initial = 0) + super() + @Lock = ::Mutex.new + ns_set(initial) + end + + # @!macro atomic_fixnum_method_value_get + def value + synchronize { @value } + end + + # @!macro atomic_fixnum_method_value_set + def value=(value) + synchronize { ns_set(value) } + end + + # @!macro atomic_fixnum_method_increment + def increment(delta = 1) + synchronize { ns_set(@value + delta.to_i) } + end + + alias_method :up, :increment + + # @!macro atomic_fixnum_method_decrement + def decrement(delta = 1) + synchronize { ns_set(@value - delta.to_i) } + end + + alias_method :down, :decrement + + # @!macro atomic_fixnum_method_compare_and_set + def compare_and_set(expect, update) + synchronize do + if @value == expect.to_i + @value = update.to_i + true + else + false + end + end + end + + # @!macro atomic_fixnum_method_update + def update + synchronize do + @value = yield @value + end + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + + private + + # @!visibility private + def ns_set(value) + Utility::NativeInteger.ensure_integer_and_bounds value + @value = value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb new file mode 100644 index 00000000..29aa1caa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb @@ -0,0 +1,44 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro count_down_latch + # @!visibility private + # @!macro internal_implementation_note + class MutexCountDownLatch < Synchronization::LockableObject + + # @!macro count_down_latch_method_initialize + def initialize(count = 1) + Utility::NativeInteger.ensure_integer_and_bounds count + Utility::NativeInteger.ensure_positive count + + super() + synchronize { ns_initialize count } + end + + # @!macro count_down_latch_method_wait + def wait(timeout = nil) + synchronize { ns_wait_until(timeout) { @count == 0 } } + end + + # @!macro count_down_latch_method_count_down + def count_down + synchronize do + @count -= 1 if @count > 0 + ns_broadcast if @count == 0 + end + end + + # @!macro count_down_latch_method_count + def count + synchronize { @count } + end + + protected + + def ns_initialize(count) + @count = count + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb new file mode 100644 index 00000000..4347289f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb @@ -0,0 +1,131 @@ +require 'concurrent/synchronization/lockable_object' +require 'concurrent/utility/native_integer' + +module Concurrent + + # @!macro semaphore + # @!visibility private + # @!macro internal_implementation_note + class MutexSemaphore < Synchronization::LockableObject + + # @!macro semaphore_method_initialize + def initialize(count) + Utility::NativeInteger.ensure_integer_and_bounds count + + super() + synchronize { ns_initialize count } + end + + # @!macro semaphore_method_acquire + def acquire(permits = 1) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + synchronize do + try_acquire_timed(permits, nil) + end + + return unless block_given? + + begin + yield + ensure + release(permits) + end + end + + # @!macro semaphore_method_available_permits + def available_permits + synchronize { @free } + end + + # @!macro semaphore_method_drain_permits + # + # Acquires and returns all permits that are immediately available. + # + # @return [Integer] + def drain_permits + synchronize do + @free.tap { |_| @free = 0 } + end + end + + # @!macro semaphore_method_try_acquire + def try_acquire(permits = 1, timeout = nil) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + acquired = synchronize do + if timeout.nil? + try_acquire_now(permits) + else + try_acquire_timed(permits, timeout) + end + end + + return acquired unless block_given? + return unless acquired + + begin + yield + ensure + release(permits) + end + end + + # @!macro semaphore_method_release + def release(permits = 1) + Utility::NativeInteger.ensure_integer_and_bounds permits + Utility::NativeInteger.ensure_positive permits + + synchronize do + @free += permits + permits.times { ns_signal } + end + nil + end + + # Shrinks the number of available permits by the indicated reduction. + # + # @param [Fixnum] reduction Number of permits to remove. + # + # @raise [ArgumentError] if `reduction` is not an integer or is negative + # + # @raise [ArgumentError] if `@free` - `@reduction` is less than zero + # + # @return [nil] + # + # @!visibility private + def reduce_permits(reduction) + Utility::NativeInteger.ensure_integer_and_bounds reduction + Utility::NativeInteger.ensure_positive reduction + + synchronize { @free -= reduction } + nil + end + + protected + + # @!visibility private + def ns_initialize(count) + @free = count + end + + private + + # @!visibility private + def try_acquire_now(permits) + if @free >= permits + @free -= permits + true + else + false + end + end + + # @!visibility private + def try_acquire_timed(permits, timeout) + ns_wait_until(timeout) { try_acquire_now(permits) } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb new file mode 100644 index 00000000..a9f0c48c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb @@ -0,0 +1,268 @@ +require 'thread' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/errors' +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lock' + +module Concurrent + + # Ruby read-write lock implementation + # + # Allows any number of concurrent readers, but only one concurrent writer + # (And if the "write" lock is taken, any readers who come along will have to wait) + # + # If readers are already active when a writer comes along, the writer will wait for + # all the readers to finish before going ahead. + # Any additional readers that come when the writer is already waiting, will also + # wait (so writers are not starved). + # + # This implementation is based on `java.util.concurrent.ReentrantReadWriteLock`. + # + # @example + # lock = Concurrent::ReadWriteLock.new + # lock.with_read_lock { data.retrieve } + # lock.with_write_lock { data.modify! } + # + # @note Do **not** try to acquire the write lock while already holding a read lock + # **or** try to acquire the write lock while you already have it. + # This will lead to deadlock + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock + class ReadWriteLock < Synchronization::Object + + # @!visibility private + WAITING_WRITER = 1 << 15 + + # @!visibility private + RUNNING_WRITER = 1 << 29 + + # @!visibility private + MAX_READERS = WAITING_WRITER - 1 + + # @!visibility private + MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 + + safe_initialization! + + # Implementation notes: + # A goal is to make the uncontended path for both readers/writers lock-free + # Only if there is reader-writer or writer-writer contention, should locks be used + # Internal state is represented by a single integer ("counter"), and updated + # using atomic compare-and-swap operations + # When the counter is 0, the lock is free + # Each reader increments the counter by 1 when acquiring a read lock + # (and decrements by 1 when releasing the read lock) + # The counter is increased by (1 << 15) for each writer waiting to acquire the + # write lock, and by (1 << 29) if the write lock is taken + + # Create a new `ReadWriteLock` in the unlocked state. + def initialize + super() + @Counter = AtomicFixnum.new(0) # single integer which represents lock state + @Writer = AtomicReference.new(nil) # the thread currently holding the write lock + @ReadLock = Synchronization::Lock.new + @WriteLock = Synchronization::Lock.new + end + + # Execute a block operation within a read lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_read_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_read_lock + begin + yield + ensure + release_read_lock + end + end + + # Execute a block operation within a write lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_write_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_write_lock + begin + yield + ensure + release_write_lock + end + end + + # Acquire a read lock. If a write lock has been acquired will block until + # it is released. Will not block if other read locks have been acquired. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def acquire_read_lock + while true + c = @Counter.value + raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) + + # If a writer is waiting when we first queue up, we need to wait + if waiting_writer?(c) + @ReadLock.wait_until { !waiting_writer? } + + # after a reader has waited once, they are allowed to "barge" ahead of waiting writers + # but if a writer is *running*, the reader still needs to wait (naturally) + while true + c = @Counter.value + if running_writer?(c) + @ReadLock.wait_until { !running_writer? } + else + return if @Counter.compare_and_set(c, c+1) + end + end + else + break if @Counter.compare_and_set(c, c+1) + end + end + true + end + + # Release a previously acquired read lock. + # + # @return [Boolean] true if the lock is successfully released + # + # @raise [Concurrent::IllegalOperationError] if no read lock is currently held. + def release_read_lock + while true + c = @Counter.value + raise IllegalOperationError, 'Cannot release a read lock which is not held' if running_readers(c) == 0 + + if @Counter.compare_and_set(c, c-1) + # If one or more writers were waiting, and we were the last reader, wake a writer up + if waiting_writer?(c) && running_readers(c) == 1 + @WriteLock.signal + end + break + end + end + true + end + + # Acquire a write lock. Will block and wait for all active readers and writers. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of writers + # is exceeded. + def acquire_write_lock + while true + c = @Counter.value + raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) + + if c == 0 # no readers OR writers running + # if we successfully swap the RUNNING_WRITER bit on, then we can go ahead + break if @Counter.compare_and_set(0, RUNNING_WRITER) + elsif @Counter.compare_and_set(c, c+WAITING_WRITER) + while true + # Now we have successfully incremented, so no more readers will be able to increment + # (they will wait instead) + # However, readers OR writers could decrement right here, OR another writer could increment + @WriteLock.wait_until do + # So we have to do another check inside the synchronized section + # If a writer OR reader is running, then go to sleep + c = @Counter.value + !running_writer?(c) && !running_readers?(c) + end + + # We just came out of a wait + # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, + # Then we are OK to stop waiting and go ahead + # Otherwise go back and wait again + c = @Counter.value + break if !running_writer?(c) && !running_readers?(c) && @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) + end + break + end + end + @Writer.set(Thread.current) + true + end + + # Release a previously acquired write lock. + # + # @return [Boolean] true if the lock is successfully released + # + # @raise [Concurrent::IllegalOperationError] if the write lock is not held + # by the current thread. + def release_write_lock + unless @Writer.compare_and_set(Thread.current, nil) + raise IllegalOperationError, 'Cannot release a write lock which is not held by the current thread' + end + + c = @Counter.update { |counter| counter - RUNNING_WRITER } + @ReadLock.broadcast + @WriteLock.signal if waiting_writers(c) > 0 + true + end + + # Queries if the write lock is held by any thread. + # + # @return [Boolean] true if the write lock is held else false` + def write_locked? + @Counter.value >= RUNNING_WRITER + end + + # Queries whether any threads are waiting to acquire the read or write lock. + # + # @return [Boolean] true if any threads are waiting for a lock else false + def has_waiters? + waiting_writer?(@Counter.value) + end + + private + + # @!visibility private + def running_readers(c = @Counter.value) + c & MAX_READERS + end + + # @!visibility private + def running_readers?(c = @Counter.value) + (c & MAX_READERS) > 0 + end + + # @!visibility private + def running_writer?(c = @Counter.value) + c >= RUNNING_WRITER + end + + # @!visibility private + def waiting_writers(c = @Counter.value) + (c & MAX_WRITERS) / WAITING_WRITER + end + + # @!visibility private + def waiting_writer?(c = @Counter.value) + c >= WAITING_WRITER + end + + # @!visibility private + def max_readers?(c = @Counter.value) + (c & MAX_READERS) == MAX_READERS + end + + # @!visibility private + def max_writers?(c = @Counter.value) + (c & MAX_WRITERS) == MAX_WRITERS + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb new file mode 100644 index 00000000..e2718a48 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb @@ -0,0 +1,386 @@ +require 'thread' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/errors' +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lock' +require 'concurrent/atomic/lock_local_var' + +module Concurrent + + # Re-entrant read-write lock implementation + # + # Allows any number of concurrent readers, but only one concurrent writer + # (And while the "write" lock is taken, no read locks can be obtained either. + # Hence, the write lock can also be called an "exclusive" lock.) + # + # If another thread has taken a read lock, any thread which wants a write lock + # will block until all the readers release their locks. However, once a thread + # starts waiting to obtain a write lock, any additional readers that come along + # will also wait (so writers are not starved). + # + # A thread can acquire both a read and write lock at the same time. A thread can + # also acquire a read lock OR a write lock more than once. Only when the read (or + # write) lock is released as many times as it was acquired, will the thread + # actually let it go, allowing other threads which might have been waiting + # to proceed. Therefore the lock can be upgraded by first acquiring + # read lock and then write lock and that the lock can be downgraded by first + # having both read and write lock a releasing just the write lock. + # + # If both read and write locks are acquired by the same thread, it is not strictly + # necessary to release them in the same order they were acquired. In other words, + # the following code is legal: + # + # @example + # lock = Concurrent::ReentrantReadWriteLock.new + # lock.acquire_write_lock + # lock.acquire_read_lock + # lock.release_write_lock + # # At this point, the current thread is holding only a read lock, not a write + # # lock. So other threads can take read locks, but not a write lock. + # lock.release_read_lock + # # Now the current thread is not holding either a read or write lock, so + # # another thread could potentially acquire a write lock. + # + # This implementation was inspired by `java.util.concurrent.ReentrantReadWriteLock`. + # + # @example + # lock = Concurrent::ReentrantReadWriteLock.new + # lock.with_read_lock { data.retrieve } + # lock.with_write_lock { data.modify! } + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html java.util.concurrent.ReentrantReadWriteLock + class ReentrantReadWriteLock < Synchronization::Object + + # Implementation notes: + # + # A goal is to make the uncontended path for both readers/writers mutex-free + # Only if there is reader-writer or writer-writer contention, should mutexes be used + # Otherwise, a single CAS operation is all we need to acquire/release a lock + # + # Internal state is represented by a single integer ("counter"), and updated + # using atomic compare-and-swap operations + # When the counter is 0, the lock is free + # Each thread which has one OR MORE read locks increments the counter by 1 + # (and decrements by 1 when releasing the read lock) + # The counter is increased by (1 << 15) for each writer waiting to acquire the + # write lock, and by (1 << 29) if the write lock is taken + # + # Additionally, each thread uses a thread-local variable to count how many times + # it has acquired a read lock, AND how many times it has acquired a write lock. + # It uses a similar trick; an increment of 1 means a read lock was taken, and + # an increment of (1 << 15) means a write lock was taken + # This is what makes re-entrancy possible + # + # 2 rules are followed to ensure good liveness properties: + # 1) Once a writer has queued up and is waiting for a write lock, no other thread + # can take a lock without waiting + # 2) When a write lock is released, readers are given the "first chance" to wake + # up and acquire a read lock + # Following these rules means readers and writers tend to "take turns", so neither + # can starve the other, even under heavy contention + + # @!visibility private + READER_BITS = 15 + # @!visibility private + WRITER_BITS = 14 + + # Used with @Counter: + # @!visibility private + WAITING_WRITER = 1 << READER_BITS + # @!visibility private + RUNNING_WRITER = 1 << (READER_BITS + WRITER_BITS) + # @!visibility private + MAX_READERS = WAITING_WRITER - 1 + # @!visibility private + MAX_WRITERS = RUNNING_WRITER - MAX_READERS - 1 + + # Used with @HeldCount: + # @!visibility private + WRITE_LOCK_HELD = 1 << READER_BITS + # @!visibility private + READ_LOCK_MASK = WRITE_LOCK_HELD - 1 + # @!visibility private + WRITE_LOCK_MASK = MAX_WRITERS + + safe_initialization! + + # Create a new `ReentrantReadWriteLock` in the unlocked state. + def initialize + super() + @Counter = AtomicFixnum.new(0) # single integer which represents lock state + @ReadQueue = Synchronization::Lock.new # used to queue waiting readers + @WriteQueue = Synchronization::Lock.new # used to queue waiting writers + @HeldCount = LockLocalVar.new(0) # indicates # of R & W locks held by this thread + end + + # Execute a block operation within a read lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_read_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_read_lock + begin + yield + ensure + release_read_lock + end + end + + # Execute a block operation within a write lock. + # + # @yield the task to be performed within the lock. + # + # @return [Object] the result of the block operation. + # + # @raise [ArgumentError] when no block is given. + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # is exceeded. + def with_write_lock + raise ArgumentError.new('no block given') unless block_given? + acquire_write_lock + begin + yield + ensure + release_write_lock + end + end + + # Acquire a read lock. If a write lock is held by another thread, will block + # until it is released. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of readers + # or per-thread reentrant acquires is exceeded. + def acquire_read_lock + if (held = @HeldCount.value) > 0 + raise ResourceLimitError.new('Too many reader holds on this thread') if (held & READ_LOCK_MASK) == READ_LOCK_MASK + + # If we already have a lock, there's no need to wait + if held & READ_LOCK_MASK == 0 + # But we do need to update the counter, if we were holding a write + # lock but not a read lock + @Counter.update { |c| c + 1 } + end + @HeldCount.value = held + 1 + return true + end + + while true + c = @Counter.value + raise ResourceLimitError.new('Too many reader threads') if max_readers?(c) + + # If a writer is waiting OR running when we first queue up, we need to wait + if waiting_or_running_writer?(c) + # Before going to sleep, check again with the ReadQueue mutex held + @ReadQueue.synchronize do + @ReadQueue.ns_wait if waiting_or_running_writer? + end + # Note: the above 'synchronize' block could have used #wait_until, + # but that waits repeatedly in a loop, checking the wait condition + # each time it wakes up (to protect against spurious wakeups) + # But we are already in a loop, which is only broken when we successfully + # acquire the lock! So we don't care about spurious wakeups, and would + # rather not pay the extra overhead of using #wait_until + + # After a reader has waited once, they are allowed to "barge" ahead of waiting writers + # But if a writer is *running*, the reader still needs to wait (naturally) + while true + c = @Counter.value + if running_writer?(c) + @ReadQueue.synchronize do + @ReadQueue.ns_wait if running_writer? + end + elsif @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + elsif @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + end + + # Try to acquire a read lock and return true if we succeed. If it cannot be + # acquired immediately, return false. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of per-thread + # reentrant acquires is exceeded. + def try_read_lock + if (held = @HeldCount.value) > 0 + raise ResourceLimitError.new('Too many reader holds on this thread') if (held & READ_LOCK_MASK) == READ_LOCK_MASK + + if held & READ_LOCK_MASK == 0 + # If we hold a write lock, but not a read lock... + @Counter.update { |c| c + 1 } + end + @HeldCount.value = held + 1 + return true + else + c = @Counter.value + if !waiting_or_running_writer?(c) && @Counter.compare_and_set(c, c+1) + @HeldCount.value = held + 1 + return true + end + end + false + end + + # Release a previously acquired read lock. + # + # @return [Boolean] true if the lock is successfully released + def release_read_lock + held = @HeldCount.value = @HeldCount.value - 1 + rlocks_held = held & READ_LOCK_MASK + if rlocks_held == 0 + c = @Counter.update { |counter| counter - 1 } + # If one or more writers were waiting, and we were the last reader, wake a writer up + if waiting_or_running_writer?(c) && running_readers(c) == 0 + @WriteQueue.signal + end + elsif rlocks_held == READ_LOCK_MASK + raise IllegalOperationError, "Cannot release a read lock which is not held" + end + true + end + + # Acquire a write lock. Will block and wait for all active readers and writers. + # + # @return [Boolean] true if the lock is successfully acquired + # + # @raise [Concurrent::ResourceLimitError] if the maximum number of writers + # is exceeded. + def acquire_write_lock + if (held = @HeldCount.value) >= WRITE_LOCK_HELD + # if we already have a write (exclusive) lock, there's no need to wait + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + + while true + c = @Counter.value + raise ResourceLimitError.new('Too many writer threads') if max_writers?(c) + + # To go ahead and take the lock without waiting, there must be no writer + # running right now, AND no writers who came before us still waiting to + # acquire the lock + # Additionally, if any read locks have been taken, we must hold all of them + if held > 0 && @Counter.compare_and_set(1, c+RUNNING_WRITER) + # If we are the only one reader and successfully swap the RUNNING_WRITER bit on, then we can go ahead + @HeldCount.value = held + WRITE_LOCK_HELD + return true + elsif @Counter.compare_and_set(c, c+WAITING_WRITER) + while true + # Now we have successfully incremented, so no more readers will be able to increment + # (they will wait instead) + # However, readers OR writers could decrement right here + @WriteQueue.synchronize do + # So we have to do another check inside the synchronized section + # If a writer OR another reader is running, then go to sleep + c = @Counter.value + @WriteQueue.ns_wait if running_writer?(c) || running_readers(c) != held + end + # Note: if you are thinking of replacing the above 'synchronize' block + # with #wait_until, read the comment in #acquire_read_lock first! + + # We just came out of a wait + # If we successfully turn the RUNNING_WRITER bit on with an atomic swap, + # then we are OK to stop waiting and go ahead + # Otherwise go back and wait again + c = @Counter.value + if !running_writer?(c) && + running_readers(c) == held && + @Counter.compare_and_set(c, c+RUNNING_WRITER-WAITING_WRITER) + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + end + end + end + end + + # Try to acquire a write lock and return true if we succeed. If it cannot be + # acquired immediately, return false. + # + # @return [Boolean] true if the lock is successfully acquired + def try_write_lock + if (held = @HeldCount.value) >= WRITE_LOCK_HELD + @HeldCount.value = held + WRITE_LOCK_HELD + return true + else + c = @Counter.value + if !waiting_or_running_writer?(c) && + running_readers(c) == held && + @Counter.compare_and_set(c, c+RUNNING_WRITER) + @HeldCount.value = held + WRITE_LOCK_HELD + return true + end + end + false + end + + # Release a previously acquired write lock. + # + # @return [Boolean] true if the lock is successfully released + def release_write_lock + held = @HeldCount.value = @HeldCount.value - WRITE_LOCK_HELD + wlocks_held = held & WRITE_LOCK_MASK + if wlocks_held == 0 + c = @Counter.update { |counter| counter - RUNNING_WRITER } + @ReadQueue.broadcast + @WriteQueue.signal if waiting_writers(c) > 0 + elsif wlocks_held == WRITE_LOCK_MASK + raise IllegalOperationError, "Cannot release a write lock which is not held" + end + true + end + + private + + # @!visibility private + def running_readers(c = @Counter.value) + c & MAX_READERS + end + + # @!visibility private + def running_readers?(c = @Counter.value) + (c & MAX_READERS) > 0 + end + + # @!visibility private + def running_writer?(c = @Counter.value) + c >= RUNNING_WRITER + end + + # @!visibility private + def waiting_writers(c = @Counter.value) + (c & MAX_WRITERS) >> READER_BITS + end + + # @!visibility private + def waiting_or_running_writer?(c = @Counter.value) + c >= WAITING_WRITER + end + + # @!visibility private + def max_readers?(c = @Counter.value) + (c & MAX_READERS) == MAX_READERS + end + + # @!visibility private + def max_writers?(c = @Counter.value) + (c & MAX_WRITERS) == MAX_WRITERS + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/semaphore.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/semaphore.rb new file mode 100644 index 00000000..f0799f0f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/semaphore.rb @@ -0,0 +1,163 @@ +require 'concurrent/atomic/mutex_semaphore' + +module Concurrent + + ################################################################### + + # @!macro semaphore_method_initialize + # + # Create a new `Semaphore` with the initial `count`. + # + # @param [Fixnum] count the initial count + # + # @raise [ArgumentError] if `count` is not an integer + + # @!macro semaphore_method_acquire + # + # Acquires the given number of permits from this semaphore, + # blocking until all are available. If a block is given, + # yields to it and releases the permits afterwards. + # + # @param [Fixnum] permits Number of permits to acquire + # + # @raise [ArgumentError] if `permits` is not an integer or is less than zero + # + # @return [nil, BasicObject] Without a block, `nil` is returned. If a block + # is given, its return value is returned. + + # @!macro semaphore_method_available_permits + # + # Returns the current number of permits available in this semaphore. + # + # @return [Integer] + + # @!macro semaphore_method_drain_permits + # + # Acquires and returns all permits that are immediately available. + # + # @return [Integer] + + # @!macro semaphore_method_try_acquire + # + # Acquires the given number of permits from this semaphore, + # only if all are available at the time of invocation or within + # `timeout` interval. If a block is given, yields to it if the permits + # were successfully acquired, and releases them afterward, returning the + # block's return value. + # + # @param [Fixnum] permits the number of permits to acquire + # + # @param [Fixnum] timeout the number of seconds to wait for the counter + # or `nil` to return immediately + # + # @raise [ArgumentError] if `permits` is not an integer or is less than zero + # + # @return [true, false, nil, BasicObject] `false` if no permits are + # available, `true` when acquired a permit. If a block is given, the + # block's return value is returned if the permits were acquired; if not, + # `nil` is returned. + + # @!macro semaphore_method_release + # + # Releases the given number of permits, returning them to the semaphore. + # + # @param [Fixnum] permits Number of permits to return to the semaphore. + # + # @raise [ArgumentError] if `permits` is not a number or is less than zero + # + # @return [nil] + + ################################################################### + + # @!macro semaphore_public_api + # + # @!method initialize(count) + # @!macro semaphore_method_initialize + # + # @!method acquire(permits = 1) + # @!macro semaphore_method_acquire + # + # @!method available_permits + # @!macro semaphore_method_available_permits + # + # @!method drain_permits + # @!macro semaphore_method_drain_permits + # + # @!method try_acquire(permits = 1, timeout = nil) + # @!macro semaphore_method_try_acquire + # + # @!method release(permits = 1) + # @!macro semaphore_method_release + + ################################################################### + + # @!visibility private + # @!macro internal_implementation_note + SemaphoreImplementation = if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + JavaSemaphore + else + MutexSemaphore + end + private_constant :SemaphoreImplementation + + # @!macro semaphore + # + # A counting semaphore. Conceptually, a semaphore maintains a set of + # permits. Each {#acquire} blocks if necessary until a permit is + # available, and then takes it. Each {#release} adds a permit, potentially + # releasing a blocking acquirer. + # However, no actual permit objects are used; the Semaphore just keeps a + # count of the number available and acts accordingly. + # Alternatively, permits may be acquired within a block, and automatically + # released after the block finishes executing. + # + # @!macro semaphore_public_api + # @example + # semaphore = Concurrent::Semaphore.new(2) + # + # t1 = Thread.new do + # semaphore.acquire + # puts "Thread 1 acquired semaphore" + # end + # + # t2 = Thread.new do + # semaphore.acquire + # puts "Thread 2 acquired semaphore" + # end + # + # t3 = Thread.new do + # semaphore.acquire + # puts "Thread 3 acquired semaphore" + # end + # + # t4 = Thread.new do + # sleep(2) + # puts "Thread 4 releasing semaphore" + # semaphore.release + # end + # + # [t1, t2, t3, t4].each(&:join) + # + # # prints: + # # Thread 3 acquired semaphore + # # Thread 2 acquired semaphore + # # Thread 4 releasing semaphore + # # Thread 1 acquired semaphore + # + # @example + # semaphore = Concurrent::Semaphore.new(1) + # + # puts semaphore.available_permits + # semaphore.acquire do + # puts semaphore.available_permits + # end + # puts semaphore.available_permits + # + # # prints: + # # 1 + # # 0 + # # 1 + class Semaphore < SemaphoreImplementation + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb new file mode 100644 index 00000000..3b7e12b5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb @@ -0,0 +1,111 @@ +require 'concurrent/constants' +require_relative 'locals' + +module Concurrent + + # A `ThreadLocalVar` is a variable where the value is different for each thread. + # Each variable may have a default value, but when you modify the variable only + # the current thread will ever see that change. + # + # This is similar to Ruby's built-in thread-local variables (`Thread#thread_variable_get`), + # but with these major advantages: + # * `ThreadLocalVar` has its own identity, it doesn't need a Symbol. + # * Each Ruby's built-in thread-local variable leaks some memory forever (it's a Symbol held forever on the thread), + # so it's only OK to create a small amount of them. + # `ThreadLocalVar` has no such issue and it is fine to create many of them. + # * Ruby's built-in thread-local variables leak forever the value set on each thread (unless set to nil explicitly). + # `ThreadLocalVar` automatically removes the mapping for each thread once the `ThreadLocalVar` instance is GC'd. + # + # @!macro thread_safe_variable_comparison + # + # @example + # v = ThreadLocalVar.new(14) + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # + # @example + # v = ThreadLocalVar.new(14) + # + # t1 = Thread.new do + # v.value #=> 14 + # v.value = 1 + # v.value #=> 1 + # end + # + # t2 = Thread.new do + # v.value #=> 14 + # v.value = 2 + # v.value #=> 2 + # end + # + # v.value #=> 14 + class ThreadLocalVar + LOCALS = ThreadLocals.new + + # Creates a thread local variable. + # + # @param [Object] default the default value when otherwise unset + # @param [Proc] default_block Optional block that gets called to obtain the + # default value for each thread + def initialize(default = nil, &default_block) + if default && block_given? + raise ArgumentError, "Cannot use both value and block as default value" + end + + if block_given? + @default_block = default_block + @default = nil + else + @default_block = nil + @default = default + end + + @index = LOCALS.next_index(self) + end + + # Returns the value in the current thread's copy of this thread-local variable. + # + # @return [Object] the current value + def value + LOCALS.fetch(@index) { default } + end + + # Sets the current thread's copy of this thread-local variable to the specified value. + # + # @param [Object] value the value to set + # @return [Object] the new value + def value=(value) + LOCALS.set(@index, value) + end + + # Bind the given value to thread local storage during + # execution of the given block. + # + # @param [Object] value the value to bind + # @yield the operation to be performed with the bound variable + # @return [Object] the value + def bind(value) + if block_given? + old_value = self.value + self.value = value + begin + yield + ensure + self.value = old_value + end + end + end + + protected + + # @!visibility private + def default + if @default_block + self.value = @default_block.call + else + @default + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb new file mode 100644 index 00000000..5d2d7edd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb @@ -0,0 +1,37 @@ +require 'concurrent/errors' + +module Concurrent + + # Define update methods that use direct paths + # + # @!visibility private + # @!macro internal_implementation_note + module AtomicDirectUpdate + def update + true until compare_and_set(old_value = get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = get + new_value = yield old_value + + return unless compare_and_set old_value, new_value + + new_value + end + + def try_update! + old_value = get + new_value = yield old_value + unless compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb new file mode 100644 index 00000000..ecd1695b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb @@ -0,0 +1,66 @@ +require 'concurrent/atomic_reference/atomic_direct_update' +require 'concurrent/atomic_reference/numeric_cas_wrapper' +require 'concurrent/synchronization/safe_initialization' + +module Concurrent + + # @!visibility private + # @!macro internal_implementation_note + class MutexAtomicReference + extend Concurrent::Synchronization::SafeInitialization + include AtomicDirectUpdate + include AtomicNumericCompareAndSetWrapper + + # @!macro atomic_reference_method_initialize + def initialize(value = nil) + super() + @Lock = ::Mutex.new + @value = value + end + + # @!macro atomic_reference_method_get + def get + synchronize { @value } + end + alias_method :value, :get + + # @!macro atomic_reference_method_set + def set(new_value) + synchronize { @value = new_value } + end + alias_method :value=, :set + + # @!macro atomic_reference_method_get_and_set + def get_and_set(new_value) + synchronize do + old_value = @value + @value = new_value + old_value + end + end + alias_method :swap, :get_and_set + + # @!macro atomic_reference_method_compare_and_set + private def _compare_and_set(old_value, new_value) + synchronize do + if @value.equal? old_value + @value = new_value + true + else + false + end + end + end + + protected + + # @!visibility private + def synchronize + if @Lock.owned? + yield + else + @Lock.synchronize { yield } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb new file mode 100644 index 00000000..438592f9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb @@ -0,0 +1,36 @@ +module Concurrent + + # Special "compare and set" handling of numeric values. + # + # @!visibility private + # @!macro internal_implementation_note + module AtomicNumericCompareAndSetWrapper + + # @!macro atomic_reference_method_compare_and_set + def compare_and_set(old_value, new_value) + if old_value.kind_of? Numeric + # NaN is never == to itself; match it explicitly so #update can terminate. + expected_nan = old_value.respond_to?(:nan?) && old_value.nan? + while true + old = get + + return false unless old.kind_of? Numeric + + if expected_nan + return false unless old.respond_to?(:nan?) && old.nan? + else + return false unless old == old_value + end + + result = _compare_and_set(old, new_value) + return result if result + end + else + _compare_and_set(old_value, new_value) + end + end + + alias_method :compare_and_swap, :compare_and_set + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomics.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomics.rb new file mode 100644 index 00000000..16cbe661 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/atomics.rb @@ -0,0 +1,10 @@ +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/atomic/cyclic_barrier' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/atomic/event' +require 'concurrent/atomic/read_write_lock' +require 'concurrent/atomic/reentrant_read_write_lock' +require 'concurrent/atomic/semaphore' +require 'concurrent/atomic/thread_local_var' diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb new file mode 100644 index 00000000..7c700bd7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb @@ -0,0 +1,107 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Collection + + # A thread safe observer set implemented using copy-on-read approach: + # observers are added and removed from a thread safe collection; every time + # a notification is required the internal data structure is copied to + # prevent concurrency issues + # + # @api private + class CopyOnNotifyObserverSet < Synchronization::LockableObject + + def initialize + super() + synchronize { ns_initialize } + end + + # @!macro observable_add_observer + def add_observer(observer = nil, func = :update, &block) + if observer.nil? && block.nil? + raise ArgumentError, 'should pass observer as a first argument or block' + elsif observer && block + raise ArgumentError.new('cannot provide both an observer and a block') + end + + if block + observer = block + func = :call + end + + synchronize do + @observers[observer] = func + observer + end + end + + # @!macro observable_delete_observer + def delete_observer(observer) + synchronize do + @observers.delete(observer) + observer + end + end + + # @!macro observable_delete_observers + def delete_observers + synchronize do + @observers.clear + self + end + end + + # @!macro observable_count_observers + def count_observers + synchronize { @observers.count } + end + + # Notifies all registered observers with optional args + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_observers(*args, &block) + observers = duplicate_observers + notify_to(observers, *args, &block) + self + end + + # Notifies all registered observers with optional args and deletes them. + # + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_and_delete_observers(*args, &block) + observers = duplicate_and_clear_observers + notify_to(observers, *args, &block) + self + end + + protected + + def ns_initialize + @observers = {} + end + + private + + def duplicate_and_clear_observers + synchronize do + observers = @observers.dup + @observers.clear + observers + end + end + + def duplicate_observers + synchronize { @observers.dup } + end + + def notify_to(observers, *args) + raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? + observers.each do |observer, function| + args = yield if block_given? + observer.send(function, *args) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb new file mode 100644 index 00000000..bcb6750d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb @@ -0,0 +1,111 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Collection + + # A thread safe observer set implemented using copy-on-write approach: + # every time an observer is added or removed the whole internal data structure is + # duplicated and replaced with a new one. + # + # @api private + class CopyOnWriteObserverSet < Synchronization::LockableObject + + def initialize + super() + synchronize { ns_initialize } + end + + # @!macro observable_add_observer + def add_observer(observer = nil, func = :update, &block) + if observer.nil? && block.nil? + raise ArgumentError, 'should pass observer as a first argument or block' + elsif observer && block + raise ArgumentError.new('cannot provide both an observer and a block') + end + + if block + observer = block + func = :call + end + + synchronize do + new_observers = @observers.dup + new_observers[observer] = func + @observers = new_observers + observer + end + end + + # @!macro observable_delete_observer + def delete_observer(observer) + synchronize do + new_observers = @observers.dup + new_observers.delete(observer) + @observers = new_observers + observer + end + end + + # @!macro observable_delete_observers + def delete_observers + self.observers = {} + self + end + + # @!macro observable_count_observers + def count_observers + observers.count + end + + # Notifies all registered observers with optional args + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_observers(*args, &block) + notify_to(observers, *args, &block) + self + end + + # Notifies all registered observers with optional args and deletes them. + # + # @param [Object] args arguments to be passed to each observer + # @return [CopyOnWriteObserverSet] self + def notify_and_delete_observers(*args, &block) + old = clear_observers_and_return_old + notify_to(old, *args, &block) + self + end + + protected + + def ns_initialize + @observers = {} + end + + private + + def notify_to(observers, *args) + raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty? + observers.each do |observer, function| + args = yield if block_given? + observer.send(function, *args) + end + end + + def observers + synchronize { @observers } + end + + def observers=(new_set) + synchronize { @observers = new_set } + end + + def clear_observers_and_return_old + synchronize do + old_observers = @observers + @observers = {} + old_observers + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb new file mode 100644 index 00000000..2be9e437 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb @@ -0,0 +1,84 @@ +if Concurrent.on_jruby? + + module Concurrent + module Collection + + + # @!macro priority_queue + # + # @!visibility private + # @!macro internal_implementation_note + class JavaNonConcurrentPriorityQueue + + # @!macro priority_queue_method_initialize + def initialize(opts = {}) + order = opts.fetch(:order, :max) + if [:min, :low].include?(order) + @queue = java.util.PriorityQueue.new(11) # 11 is the default initial capacity + else + @queue = java.util.PriorityQueue.new(11, java.util.Collections.reverseOrder()) + end + end + + # @!macro priority_queue_method_clear + def clear + @queue.clear + true + end + + # @!macro priority_queue_method_delete + def delete(item) + found = false + while @queue.remove(item) do + found = true + end + found + end + + # @!macro priority_queue_method_empty + def empty? + @queue.size == 0 + end + + # @!macro priority_queue_method_include + def include?(item) + @queue.contains(item) + end + alias_method :has_priority?, :include? + + # @!macro priority_queue_method_length + def length + @queue.size + end + alias_method :size, :length + + # @!macro priority_queue_method_peek + def peek + @queue.peek + end + + # @!macro priority_queue_method_pop + def pop + @queue.poll + end + alias_method :deq, :pop + alias_method :shift, :pop + + # @!macro priority_queue_method_push + def push(item) + raise ArgumentError.new('cannot enqueue nil') if item.nil? + @queue.add(item) + end + alias_method :<<, :push + alias_method :enq, :push + + # @!macro priority_queue_method_from_list + def self.from_list(list, opts = {}) + queue = new(opts) + list.each{|item| queue << item } + queue + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb new file mode 100644 index 00000000..3704410b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb @@ -0,0 +1,160 @@ +require 'concurrent/synchronization/object' + +module Concurrent + + # @!macro warn.edge + class LockFreeStack < Synchronization::Object + + safe_initialization! + + class Node + # TODO (pitr-ch 20-Dec-2016): Could be unified with Stack class? + + # @return [Node] + attr_reader :next_node + + # @return [Object] + attr_reader :value + + # @!visibility private + # allow to nil-ify to free GC when the entry is no longer relevant, not synchronised + attr_writer :value + + def initialize(value, next_node) + @value = value + @next_node = next_node + end + + singleton_class.send :alias_method, :[], :new + end + + # The singleton for empty node + EMPTY = Node[nil, nil] + def EMPTY.next_node + self + end + + attr_atomic(:head) + private :head, :head=, :swap_head, :compare_and_set_head, :update_head + + # @!visibility private + def self.of1(value) + new Node[value, EMPTY] + end + + # @!visibility private + def self.of2(value1, value2) + new Node[value1, Node[value2, EMPTY]] + end + + # @param [Node] head + def initialize(head = EMPTY) + super() + self.head = head + end + + # @param [Node] head + # @return [true, false] + def empty?(head = head()) + head.equal? EMPTY + end + + # @param [Node] head + # @param [Object] value + # @return [true, false] + def compare_and_push(head, value) + compare_and_set_head head, Node[value, head] + end + + # @param [Object] value + # @return [self] + def push(value) + while true + current_head = head + return self if compare_and_set_head current_head, Node[value, current_head] + end + end + + # @return [Node] + def peek + head + end + + # @param [Node] head + # @return [true, false] + def compare_and_pop(head) + compare_and_set_head head, head.next_node + end + + # @return [Object] + def pop + while true + current_head = head + return current_head.value if compare_and_set_head current_head, current_head.next_node + end + end + + # @param [Node] head + # @return [true, false] + def compare_and_clear(head) + compare_and_set_head head, EMPTY + end + + include Enumerable + + # @param [Node] head + # @return [self] + def each(head = nil) + return to_enum(:each, head) unless block_given? + it = head || peek + until it.equal?(EMPTY) + yield it.value + it = it.next_node + end + self + end + + # @return [true, false] + def clear + while true + current_head = head + return false if current_head == EMPTY + return true if compare_and_set_head current_head, EMPTY + end + end + + # @param [Node] head + # @return [true, false] + def clear_if(head) + compare_and_set_head head, EMPTY + end + + # @param [Node] head + # @param [Node] new_head + # @return [true, false] + def replace_if(head, new_head) + compare_and_set_head head, new_head + end + + # @return [self] + # @yield over the cleared stack + # @yieldparam [Object] value + def clear_each(&block) + while true + current_head = head + return self if current_head == EMPTY + if compare_and_set_head current_head, EMPTY + each current_head, &block + return self + end + end + end + + # @return [String] Short string representation. + def to_s + format '%s %s>', super[0..-2], to_a.to_s + end + + alias_method :inspect, :to_s + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb new file mode 100644 index 00000000..e0cf9990 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb @@ -0,0 +1,66 @@ +require 'thread' +require 'concurrent/collection/map/non_concurrent_map_backend' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class MriMapBackend < NonConcurrentMapBackend + + def initialize(options = nil, &default_proc) + super(options, &default_proc) + @write_lock = Mutex.new + end + + def []=(key, value) + @write_lock.synchronize { super } + end + + def compute_if_absent(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) # fast non-blocking path for the most likely case + stored_value + else + @write_lock.synchronize { super } + end + end + + def compute_if_present(key) + @write_lock.synchronize { super } + end + + def compute(key) + @write_lock.synchronize { super } + end + + def merge_pair(key, value) + @write_lock.synchronize { super } + end + + def replace_pair(key, old_value, new_value) + @write_lock.synchronize { super } + end + + def replace_if_exists(key, new_value) + @write_lock.synchronize { super } + end + + def get_and_set(key, value) + @write_lock.synchronize { super } + end + + def delete(key) + @write_lock.synchronize { super } + end + + def delete_pair(key, value) + @write_lock.synchronize { super } + end + + def clear + @write_lock.synchronize { super } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb new file mode 100644 index 00000000..ca5fd9b4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb @@ -0,0 +1,148 @@ +require 'concurrent/constants' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class NonConcurrentMapBackend + + # WARNING: all public methods of the class must operate on the @backend + # directly without calling each other. This is important because of the + # SynchronizedMapBackend which uses a non-reentrant mutex for performance + # reasons. + def initialize(options = nil, &default_proc) + validate_options_hash!(options) if options.kind_of?(::Hash) + set_backend(default_proc) + @default_proc = default_proc + end + + def [](key) + @backend[key] + end + + def []=(key, value) + @backend[key] = value + end + + def compute_if_absent(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + stored_value + else + @backend[key] = yield + end + end + + def replace_pair(key, old_value, new_value) + if pair?(key, old_value) + @backend[key] = new_value + true + else + false + end + end + + def replace_if_exists(key, new_value) + if NULL != (stored_value = @backend.fetch(key, NULL)) + @backend[key] = new_value + stored_value + end + end + + def compute_if_present(key) + if NULL != (stored_value = @backend.fetch(key, NULL)) + store_computed_value(key, yield(stored_value)) + end + end + + def compute(key) + store_computed_value(key, yield(get_or_default(key, nil))) + end + + def merge_pair(key, value) + if NULL == (stored_value = @backend.fetch(key, NULL)) + @backend[key] = value + else + store_computed_value(key, yield(stored_value)) + end + end + + def get_and_set(key, value) + stored_value = get_or_default(key, nil) + @backend[key] = value + stored_value + end + + def key?(key) + @backend.key?(key) + end + + def delete(key) + @backend.delete(key) + end + + def delete_pair(key, value) + if pair?(key, value) + @backend.delete(key) + true + else + false + end + end + + def clear + @backend.clear + self + end + + def each_pair + dupped_backend.each_pair do |k, v| + yield k, v + end + self + end + + def size + @backend.size + end + + def get_or_default(key, default_value) + @backend.fetch(key, default_value) + end + + private + + def set_backend(default_proc) + if default_proc + @backend = ::Hash.new { |_h, key| default_proc.call(self, key) } + else + @backend = {} + end + end + + def initialize_copy(other) + super + set_backend(@default_proc) + self + end + + def dupped_backend + @backend.dup + end + + def pair?(key, expected_value) + NULL != (stored_value = @backend.fetch(key, NULL)) && expected_value.equal?(stored_value) + end + + def store_computed_value(key, new_value) + if new_value.nil? + @backend.delete(key) + nil + else + @backend[key] = new_value + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb new file mode 100644 index 00000000..efa161ed --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb @@ -0,0 +1,85 @@ +require 'concurrent/collection/map/non_concurrent_map_backend' + +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class SynchronizedMapBackend < NonConcurrentMapBackend + + def initialize(*args, &block) + super + + # WARNING: Mutex is a non-reentrant lock, so the synchronized methods are + # not allowed to call each other. + @mutex = Mutex.new + end + + def [](key) + @mutex.synchronize { super } + end + + def []=(key, value) + @mutex.synchronize { super } + end + + def compute_if_absent(key) + @mutex.synchronize { super } + end + + def compute_if_present(key) + @mutex.synchronize { super } + end + + def compute(key) + @mutex.synchronize { super } + end + + def merge_pair(key, value) + @mutex.synchronize { super } + end + + def replace_pair(key, old_value, new_value) + @mutex.synchronize { super } + end + + def replace_if_exists(key, new_value) + @mutex.synchronize { super } + end + + def get_and_set(key, value) + @mutex.synchronize { super } + end + + def key?(key) + @mutex.synchronize { super } + end + + def delete(key) + @mutex.synchronize { super } + end + + def delete_pair(key, value) + @mutex.synchronize { super } + end + + def clear + @mutex.synchronize { super } + end + + def size + @mutex.synchronize { super } + end + + def get_or_default(key, default_value) + @mutex.synchronize { super } + end + + private + def dupped_backend + @mutex.synchronize { super } + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb new file mode 100644 index 00000000..68a1b388 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb @@ -0,0 +1,14 @@ +module Concurrent + + # @!visibility private + module Collection + + # @!visibility private + class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap + def initialize(options = nil) + options ||= {} + super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor]) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb new file mode 100644 index 00000000..694cd7ac --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb @@ -0,0 +1,143 @@ +require 'concurrent/utility/engine' +require 'concurrent/collection/java_non_concurrent_priority_queue' +require 'concurrent/collection/ruby_non_concurrent_priority_queue' + +module Concurrent + module Collection + + # @!visibility private + # @!macro internal_implementation_note + NonConcurrentPriorityQueueImplementation = case + when Concurrent.on_jruby? + JavaNonConcurrentPriorityQueue + else + RubyNonConcurrentPriorityQueue + end + private_constant :NonConcurrentPriorityQueueImplementation + + # @!macro priority_queue + # + # A queue collection in which the elements are sorted based on their + # comparison (spaceship) operator `<=>`. Items are added to the queue + # at a position relative to their priority. On removal the element + # with the "highest" priority is removed. By default the sort order is + # from highest to lowest, but a lowest-to-highest sort order can be + # set on construction. + # + # The API is based on the `Queue` class from the Ruby standard library. + # + # The pure Ruby implementation, `RubyNonConcurrentPriorityQueue` uses a heap algorithm + # stored in an array. The algorithm is based on the work of Robert Sedgewick + # and Kevin Wayne. + # + # The JRuby native implementation is a thin wrapper around the standard + # library `java.util.NonConcurrentPriorityQueue`. + # + # When running under JRuby the class `NonConcurrentPriorityQueue` extends `JavaNonConcurrentPriorityQueue`. + # When running under all other interpreters it extends `RubyNonConcurrentPriorityQueue`. + # + # @note This implementation is *not* thread safe. + # + # @see http://en.wikipedia.org/wiki/Priority_queue + # @see http://ruby-doc.org/stdlib-2.0.0/libdoc/thread/rdoc/Queue.html + # + # @see http://algs4.cs.princeton.edu/24pq/index.php#2.6 + # @see http://algs4.cs.princeton.edu/24pq/MaxPQ.java.html + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html + # + # @!visibility private + class NonConcurrentPriorityQueue < NonConcurrentPriorityQueueImplementation + + alias_method :has_priority?, :include? + + alias_method :size, :length + + alias_method :deq, :pop + alias_method :shift, :pop + + alias_method :<<, :push + alias_method :enq, :push + + # @!method initialize(opts = {}) + # @!macro priority_queue_method_initialize + # + # Create a new priority queue with no items. + # + # @param [Hash] opts the options for creating the queue + # @option opts [Symbol] :order (:max) dictates the order in which items are + # stored: from highest to lowest when `:max` or `:high`; from lowest to + # highest when `:min` or `:low` + + # @!method clear + # @!macro priority_queue_method_clear + # + # Removes all of the elements from this priority queue. + + # @!method delete(item) + # @!macro priority_queue_method_delete + # + # Deletes all items from `self` that are equal to `item`. + # + # @param [Object] item the item to be removed from the queue + # @return [Object] true if the item is found else false + + # @!method empty? + # @!macro priority_queue_method_empty + # + # Returns `true` if `self` contains no elements. + # + # @return [Boolean] true if there are no items in the queue else false + + # @!method include?(item) + # @!macro priority_queue_method_include + # + # Returns `true` if the given item is present in `self` (that is, if any + # element == `item`), otherwise returns false. + # + # @param [Object] item the item to search for + # + # @return [Boolean] true if the item is found else false + + # @!method length + # @!macro priority_queue_method_length + # + # The current length of the queue. + # + # @return [Fixnum] the number of items in the queue + + # @!method peek + # @!macro priority_queue_method_peek + # + # Retrieves, but does not remove, the head of this queue, or returns `nil` + # if this queue is empty. + # + # @return [Object] the head of the queue or `nil` when empty + + # @!method pop + # @!macro priority_queue_method_pop + # + # Retrieves and removes the head of this queue, or returns `nil` if this + # queue is empty. + # + # @return [Object] the head of the queue or `nil` when empty + + # @!method push(item) + # @!macro priority_queue_method_push + # + # Inserts the specified element into this priority queue. + # + # @param [Object] item the item to insert onto the queue + + # @!method self.from_list(list, opts = {}) + # @!macro priority_queue_method_from_list + # + # Create a new priority queue from the given list. + # + # @param [Enumerable] list the list to build the queue from + # @param [Hash] opts the options for creating the queue + # + # @return [NonConcurrentPriorityQueue] the newly created and populated queue + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb new file mode 100644 index 00000000..322b4ac2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb @@ -0,0 +1,160 @@ +module Concurrent + module Collection + + # @!macro priority_queue + # + # @!visibility private + # @!macro internal_implementation_note + class RubyNonConcurrentPriorityQueue + + # @!macro priority_queue_method_initialize + def initialize(opts = {}) + order = opts.fetch(:order, :max) + @comparator = [:min, :low].include?(order) ? -1 : 1 + clear + end + + # @!macro priority_queue_method_clear + def clear + @queue = [nil] + @length = 0 + true + end + + # @!macro priority_queue_method_delete + def delete(item) + return false if empty? + original_length = @length + k = 1 + while k <= @length + if @queue[k] == item + swap(k, @length) + @length -= 1 + sink(k) || swim(k) + @queue.pop + else + k += 1 + end + end + @length != original_length + end + + # @!macro priority_queue_method_empty + def empty? + size == 0 + end + + # @!macro priority_queue_method_include + def include?(item) + @queue.include?(item) + end + alias_method :has_priority?, :include? + + # @!macro priority_queue_method_length + def length + @length + end + alias_method :size, :length + + # @!macro priority_queue_method_peek + def peek + empty? ? nil : @queue[1] + end + + # @!macro priority_queue_method_pop + def pop + return nil if empty? + max = @queue[1] + swap(1, @length) + @length -= 1 + sink(1) + @queue.pop + max + end + alias_method :deq, :pop + alias_method :shift, :pop + + # @!macro priority_queue_method_push + def push(item) + raise ArgumentError.new('cannot enqueue nil') if item.nil? + @length += 1 + @queue << item + swim(@length) + true + end + alias_method :<<, :push + alias_method :enq, :push + + # @!macro priority_queue_method_from_list + def self.from_list(list, opts = {}) + queue = new(opts) + list.each{|item| queue << item } + queue + end + + private + + # Exchange the values at the given indexes within the internal array. + # + # @param [Integer] x the first index to swap + # @param [Integer] y the second index to swap + # + # @!visibility private + def swap(x, y) + temp = @queue[x] + @queue[x] = @queue[y] + @queue[y] = temp + end + + # Are the items at the given indexes ordered based on the priority + # order specified at construction? + # + # @param [Integer] x the first index from which to retrieve a comparable value + # @param [Integer] y the second index from which to retrieve a comparable value + # + # @return [Boolean] true if the two elements are in the correct priority order + # else false + # + # @!visibility private + def ordered?(x, y) + (@queue[x] <=> @queue[y]) == @comparator + end + + # Percolate down to maintain heap invariant. + # + # @param [Integer] k the index at which to start the percolation + # + # @!visibility private + def sink(k) + success = false + + while (j = (2 * k)) <= @length do + j += 1 if j < @length && ! ordered?(j, j+1) + break if ordered?(k, j) + swap(k, j) + success = true + k = j + end + + success + end + + # Percolate up to maintain heap invariant. + # + # @param [Integer] k the index at which to start the percolation + # + # @!visibility private + def swim(k) + success = false + + while k > 1 && ! ordered?(k/2, k) do + swap(k, k/2) + k = k/2 + success = true + end + + success + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_timeout_queue.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_timeout_queue.rb new file mode 100644 index 00000000..3cf53718 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/ruby_timeout_queue.rb @@ -0,0 +1,55 @@ +module Concurrent + module Collection + # @!visibility private + # @!macro ruby_timeout_queue + class RubyTimeoutQueue < ::Queue + def initialize(*args) + if RUBY_VERSION >= '3.2' + raise "#{self.class.name} is not needed on Ruby 3.2 or later, use ::Queue instead" + end + + super(*args) + + @mutex = Mutex.new + @cond_var = ConditionVariable.new + end + + def push(obj) + @mutex.synchronize do + super(obj) + @cond_var.signal + end + end + alias_method :enq, :push + alias_method :<<, :push + + def pop(non_block = false, timeout: nil) + if non_block && timeout + raise ArgumentError, "can't set a timeout if non_block is enabled" + end + + if non_block + super(true) + elsif timeout + @mutex.synchronize do + deadline = Concurrent.monotonic_time + timeout + while (now = Concurrent.monotonic_time) < deadline && empty? + @cond_var.wait(@mutex, deadline - now) + end + begin + return super(true) + rescue ThreadError + # still empty + nil + end + end + else + super(false) + end + end + alias_method :deq, :pop + alias_method :shift, :pop + end + private_constant :RubyTimeoutQueue + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/timeout_queue.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/timeout_queue.rb new file mode 100644 index 00000000..7048c4b6 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/collection/timeout_queue.rb @@ -0,0 +1,18 @@ +module Concurrent + module Collection + # @!visibility private + # @!macro internal_implementation_note + TimeoutQueueImplementation = if RUBY_VERSION >= '3.2' + ::Queue + else + require 'concurrent/collection/ruby_timeout_queue' + RubyTimeoutQueue + end + private_constant :TimeoutQueueImplementation + + # @!visibility private + # @!macro timeout_queue + class TimeoutQueue < TimeoutQueueImplementation + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/deprecation.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/deprecation.rb new file mode 100644 index 00000000..35ae4b2c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/deprecation.rb @@ -0,0 +1,34 @@ +require 'concurrent/concern/logging' + +module Concurrent + module Concern + + # @!visibility private + # @!macro internal_implementation_note + module Deprecation + # TODO require additional parameter: a version. Display when it'll be removed based on that. Error if not removed. + include Concern::Logging + + def deprecated(message, strip = 2) + caller_line = caller(strip).first if strip > 0 + klass = if Module === self + self + else + self.class + end + message = if strip > 0 + format("[DEPRECATED] %s\ncalled on: %s", message, caller_line) + else + format('[DEPRECATED] %s', message) + end + log WARN, klass.to_s, message + end + + def deprecated_method(old_name, new_name) + deprecated "`#{old_name}` is deprecated and it'll removed in next release, use `#{new_name}` instead", 3 + end + + extend self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb new file mode 100644 index 00000000..dc172ba7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb @@ -0,0 +1,73 @@ +module Concurrent + module Concern + + # Object references in Ruby are mutable. This can lead to serious problems when + # the `#value` of a concurrent object is a mutable reference. Which is always the + # case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type. + # Most classes in this library that expose a `#value` getter method do so using the + # `Dereferenceable` mixin module. + # + # @!macro copy_options + module Dereferenceable + # NOTE: This module is going away in 2.0. In the mean time we need it to + # play nicely with the synchronization layer. This means that the + # including class SHOULD be synchronized and it MUST implement a + # `#synchronize` method. Not doing so will lead to runtime errors. + + # Return the value this object represents after applying the options specified + # by the `#set_deref_options` method. + # + # @return [Object] the current value of the object + def value + synchronize { apply_deref_options(@value) } + end + alias_method :deref, :value + + protected + + # Set the internal value of this object + # + # @param [Object] value the new value + def value=(value) + synchronize{ @value = value } + end + + # @!macro dereferenceable_set_deref_options + # Set the options which define the operations #value performs before + # returning data to the caller (dereferencing). + # + # @note Most classes that include this module will call `#set_deref_options` + # from within the constructor, thus allowing these options to be set at + # object creation. + # + # @param [Hash] opts the options defining dereference behavior. + # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data + # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data + # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing + # the internal value and returning the value returned from the proc + def set_deref_options(opts = {}) + synchronize{ ns_set_deref_options(opts) } + end + + # @!macro dereferenceable_set_deref_options + # @!visibility private + def ns_set_deref_options(opts) + @dup_on_deref = opts[:dup_on_deref] || opts[:dup] + @freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze] + @copy_on_deref = opts[:copy_on_deref] || opts[:copy] + @do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref) + nil + end + + # @!visibility private + def apply_deref_options(value) + return nil if value.nil? + return value if @do_nothing_on_deref + value = @copy_on_deref.call(value) if @copy_on_deref + value = value.dup if @dup_on_deref + value = value.freeze if @freeze_on_deref + value + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/logging.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/logging.rb new file mode 100644 index 00000000..d1aae81a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/logging.rb @@ -0,0 +1,121 @@ +require 'concurrent/atomic/atomic_reference' + +module Concurrent + module Concern + + # Include where logging is needed + # + # @!visibility private + module Logging + # The same as Logger::Severity but we copy it here to avoid a dependency on the logger gem just for these 7 constants + DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN = 0, 1, 2, 3, 4, 5 + SEV_LABEL = %w[DEBUG INFO WARN ERROR FATAL ANY].freeze + + # Logs through {Concurrent.global_logger}, it can be overridden by setting @logger + # @param [Integer] level one of Concurrent::Concern::Logging constants + # @param [String] progname e.g. a path of an Actor + # @param [String, nil] message when nil block is used to generate the message + # @yieldreturn [String] a message + def log(level, progname, message = nil, &block) + logger = if defined?(@logger) && @logger + @logger + else + Concurrent.global_logger + end + logger.call level, progname, message, &block + rescue => error + $stderr.puts "`Concurrent.global_logger` failed to log #{[level, progname, message, block]}\n" + + "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}" + end + end + end +end + +module Concurrent + extend Concern::Logging + + # Create a simple logger with provided level and output. + def self.create_simple_logger(level = :FATAL, output = $stderr) + level = Concern::Logging.const_get(level) unless level.is_a?(Integer) + + # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking + lambda do |severity, progname, message = nil, &block| + return false if severity < level + + message = block ? block.call : message + formatted_message = case message + when String + message + when Exception + format "%s (%s)\n%s", + message.message, message.class, (message.backtrace || []).join("\n") + else + message.inspect + end + + output.print format "[%s] %5s -- %s: %s\n", + Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'), + Concern::Logging::SEV_LABEL[severity], + progname, + formatted_message + true + end + end + + # Use logger created by #create_simple_logger to log concurrent-ruby messages. + def self.use_simple_logger(level = :FATAL, output = $stderr) + Concurrent.global_logger = create_simple_logger level, output + end + + # Create a stdlib logger with provided level and output. + # If you use this deprecated method you might need to add logger to your Gemfile to avoid warnings from Ruby 3.3.5+. + # @deprecated + def self.create_stdlib_logger(level = :FATAL, output = $stderr) + require 'logger' + logger = Logger.new(output) + logger.level = level + logger.formatter = lambda do |severity, datetime, progname, msg| + formatted_message = case msg + when String + msg + when Exception + format "%s (%s)\n%s", + msg.message, msg.class, (msg.backtrace || []).join("\n") + else + msg.inspect + end + format "[%s] %5s -- %s: %s\n", + datetime.strftime('%Y-%m-%d %H:%M:%S.%L'), + severity, + progname, + formatted_message + end + + lambda do |loglevel, progname, message = nil, &block| + logger.add loglevel, message, progname, &block + end + end + + # Use logger created by #create_stdlib_logger to log concurrent-ruby messages. + # @deprecated + def self.use_stdlib_logger(level = :FATAL, output = $stderr) + Concurrent.global_logger = create_stdlib_logger level, output + end + + # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods + + # Suppresses all output when used for logging. + NULL_LOGGER = lambda { |level, progname, message = nil, &block| } + + # @!visibility private + GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(:WARN)) + private_constant :GLOBAL_LOGGER + + def self.global_logger + GLOBAL_LOGGER.value + end + + def self.global_logger=(value) + GLOBAL_LOGGER.value = value + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/obligation.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/obligation.rb new file mode 100644 index 00000000..2c9ac120 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/obligation.rb @@ -0,0 +1,220 @@ +require 'thread' +require 'timeout' + +require 'concurrent/atomic/event' +require 'concurrent/concern/dereferenceable' + +module Concurrent + module Concern + + module Obligation + include Concern::Dereferenceable + # NOTE: The Dereferenceable module is going away in 2.0. In the mean time + # we need it to place nicely with the synchronization layer. This means + # that the including class SHOULD be synchronized and it MUST implement a + # `#synchronize` method. Not doing so will lead to runtime errors. + + # Has the obligation been fulfilled? + # + # @return [Boolean] + def fulfilled? + state == :fulfilled + end + alias_method :realized?, :fulfilled? + + # Has the obligation been rejected? + # + # @return [Boolean] + def rejected? + state == :rejected + end + + # Is obligation completion still pending? + # + # @return [Boolean] + def pending? + state == :pending + end + + # Is the obligation still unscheduled? + # + # @return [Boolean] + def unscheduled? + state == :unscheduled + end + + # Has the obligation completed processing? + # + # @return [Boolean] + def complete? + [:fulfilled, :rejected].include? state + end + + # Is the obligation still awaiting completion of processing? + # + # @return [Boolean] + def incomplete? + ! complete? + end + + # The current value of the obligation. Will be `nil` while the state is + # pending or the operation has been rejected. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Object] see Dereferenceable#deref + def value(timeout = nil) + wait timeout + deref + end + + # Wait until obligation is complete or the timeout has been reached. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Obligation] self + def wait(timeout = nil) + event.wait(timeout) if timeout != 0 && incomplete? + self + end + + # Wait until obligation is complete or the timeout is reached. Will re-raise + # any exceptions raised during processing (but will not raise an exception + # on timeout). + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Obligation] self + # @raise [Exception] raises the reason when rejected + def wait!(timeout = nil) + wait(timeout).tap { raise self if rejected? } + end + alias_method :no_error!, :wait! + + # The current value of the obligation. Will be `nil` while the state is + # pending or the operation has been rejected. Will re-raise any exceptions + # raised during processing (but will not raise an exception on timeout). + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Object] see Dereferenceable#deref + # @raise [Exception] raises the reason when rejected + def value!(timeout = nil) + wait(timeout) + if rejected? + raise self + else + deref + end + end + + # The current state of the obligation. + # + # @return [Symbol] the current state + def state + synchronize { @state } + end + + # If an exception was raised during processing this will return the + # exception object. Will return `nil` when the state is pending or if + # the obligation has been successfully fulfilled. + # + # @return [Exception] the exception raised during processing or `nil` + def reason + synchronize { @reason } + end + + # @example allows Obligation to be risen + # rejected_ivar = Ivar.new.fail + # raise rejected_ivar + def exception(*args) + raise 'obligation is not rejected' unless rejected? + reason.exception(*args) + end + + protected + + # @!visibility private + def get_arguments_from(opts = {}) + [*opts.fetch(:args, [])] + end + + # @!visibility private + def init_obligation + @event = Event.new + @value = @reason = nil + end + + # @!visibility private + def event + @event + end + + # @!visibility private + def set_state(success, value, reason) + if success + @value = value + @state = :fulfilled + else + @reason = reason + @state = :rejected + end + end + + # @!visibility private + def state=(value) + synchronize { ns_set_state(value) } + end + + # Atomic compare and set operation + # State is set to `next_state` only if `current state == expected_current`. + # + # @param [Symbol] next_state + # @param [Symbol] expected_current + # + # @return [Boolean] true is state is changed, false otherwise + # + # @!visibility private + def compare_and_set_state(next_state, *expected_current) + synchronize do + if expected_current.include? @state + @state = next_state + true + else + false + end + end + end + + # Executes the block within mutex if current state is included in expected_states + # + # @return block value if executed, false otherwise + # + # @!visibility private + def if_state(*expected_states) + synchronize do + raise ArgumentError.new('no block given') unless block_given? + + if expected_states.include? @state + yield + else + false + end + end + end + + protected + + # Am I in the current state? + # + # @param [Symbol] expected The state to check against + # @return [Boolean] true if in the expected state else false + # + # @!visibility private + def ns_check_state?(expected) + @state == expected + end + + # @!visibility private + def ns_set_state(value) + @state = value + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/observable.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/observable.rb new file mode 100644 index 00000000..b5132714 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concern/observable.rb @@ -0,0 +1,110 @@ +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/collection/copy_on_write_observer_set' + +module Concurrent + module Concern + + # The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one + # of the most useful design patterns. + # + # The workflow is very simple: + # - an `observer` can register itself to a `subject` via a callback + # - many `observers` can be registered to the same `subject` + # - the `subject` notifies all registered observers when its status changes + # - an `observer` can deregister itself when is no more interested to receive + # event notifications + # + # In a single threaded environment the whole pattern is very easy: the + # `subject` can use a simple data structure to manage all its subscribed + # `observer`s and every `observer` can react directly to every event without + # caring about synchronization. + # + # In a multi threaded environment things are more complex. The `subject` must + # synchronize the access to its data structure and to do so currently we're + # using two specialized ObserverSet: {Concurrent::Concern::CopyOnWriteObserverSet} + # and {Concurrent::Concern::CopyOnNotifyObserverSet}. + # + # When implementing and `observer` there's a very important rule to remember: + # **there are no guarantees about the thread that will execute the callback** + # + # Let's take this example + # ``` + # class Observer + # def initialize + # @count = 0 + # end + # + # def update + # @count += 1 + # end + # end + # + # obs = Observer.new + # [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) } + # # execute [obj1, obj2, obj3, obj4] + # ``` + # + # `obs` is wrong because the variable `@count` can be accessed by different + # threads at the same time, so it should be synchronized (using either a Mutex + # or an AtomicFixum) + module Observable + + # @!macro observable_add_observer + # + # Adds an observer to this set. If a block is passed, the observer will be + # created by this method and no other params should be passed. + # + # @param [Object] observer the observer to add + # @param [Symbol] func the function to call on the observer during notification. + # Default is :update + # @return [Object] the added observer + def add_observer(observer = nil, func = :update, &block) + observers.add_observer(observer, func, &block) + end + + # As `#add_observer` but can be used for chaining. + # + # @param [Object] observer the observer to add + # @param [Symbol] func the function to call on the observer during notification. + # @return [Observable] self + def with_observer(observer = nil, func = :update, &block) + add_observer(observer, func, &block) + self + end + + # @!macro observable_delete_observer + # + # Remove `observer` as an observer on this object so that it will no + # longer receive notifications. + # + # @param [Object] observer the observer to remove + # @return [Object] the deleted observer + def delete_observer(observer) + observers.delete_observer(observer) + end + + # @!macro observable_delete_observers + # + # Remove all observers associated with this object. + # + # @return [Observable] self + def delete_observers + observers.delete_observers + self + end + + # @!macro observable_count_observers + # + # Return the number of observers associated with this object. + # + # @return [Integer] the observers count + def count_observers + observers.count_observers + end + + protected + + attr_accessor :observers + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concurrent_ruby.jar b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concurrent_ruby.jar new file mode 100644 index 00000000..380bcbda Binary files /dev/null and b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/concurrent_ruby.jar differ diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/configuration.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/configuration.rb new file mode 100644 index 00000000..5571d39b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/configuration.rb @@ -0,0 +1,105 @@ +require 'thread' +require 'concurrent/delay' +require 'concurrent/errors' +require 'concurrent/concern/deprecation' +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/fixed_thread_pool' +require 'concurrent/executor/cached_thread_pool' +require 'concurrent/utility/processor_counter' + +module Concurrent + extend Concern::Deprecation + + autoload :Options, 'concurrent/options' + autoload :TimerSet, 'concurrent/executor/timer_set' + autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor' + + # @!visibility private + GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor } + private_constant :GLOBAL_FAST_EXECUTOR + + # @!visibility private + GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor } + private_constant :GLOBAL_IO_EXECUTOR + + # @!visibility private + GLOBAL_TIMER_SET = Delay.new { TimerSet.new } + private_constant :GLOBAL_TIMER_SET + + # @!visibility private + GLOBAL_IMMEDIATE_EXECUTOR = ImmediateExecutor.new + private_constant :GLOBAL_IMMEDIATE_EXECUTOR + + # Disables AtExit handlers including pool auto-termination handlers. + # When disabled it will be the application programmer's responsibility + # to ensure that the handlers are shutdown properly prior to application + # exit by calling `AtExit.run` method. + # + # @note this option should be needed only because of `at_exit` ordering + # issues which may arise when running some of the testing frameworks. + # E.g. Minitest's test-suite runs itself in `at_exit` callback which + # executes after the pools are already terminated. Then auto termination + # needs to be disabled and called manually after test-suite ends. + # @note This method should *never* be called + # from within a gem. It should *only* be used from within the main + # application and even then it should be used only when necessary. + # @deprecated Has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841. + # + def self.disable_at_exit_handlers! + deprecated "Method #disable_at_exit_handlers! has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841." + end + + # Global thread pool optimized for short, fast *operations*. + # + # @return [ThreadPoolExecutor] the thread pool + def self.global_fast_executor + GLOBAL_FAST_EXECUTOR.value! + end + + # Global thread pool optimized for long, blocking (IO) *tasks*. + # + # @return [ThreadPoolExecutor] the thread pool + def self.global_io_executor + GLOBAL_IO_EXECUTOR.value! + end + + def self.global_immediate_executor + GLOBAL_IMMEDIATE_EXECUTOR + end + + # Global thread pool user for global *timers*. + # + # @return [Concurrent::TimerSet] the thread pool + def self.global_timer_set + GLOBAL_TIMER_SET.value! + end + + # General access point to global executors. + # @param [Symbol, Executor] executor_identifier symbols: + # - :fast - {Concurrent.global_fast_executor} + # - :io - {Concurrent.global_io_executor} + # - :immediate - {Concurrent.global_immediate_executor} + # @return [Executor] + def self.executor(executor_identifier) + Options.executor(executor_identifier) + end + + def self.new_fast_executor(opts = {}) + FixedThreadPool.new( + [2, Concurrent.processor_count].max, + auto_terminate: opts.fetch(:auto_terminate, true), + idletime: 60, # 1 minute + max_queue: 0, # unlimited + fallback_policy: :abort, # shouldn't matter -- 0 max queue + name: "fast" + ) + end + + def self.new_io_executor(opts = {}) + CachedThreadPool.new( + auto_terminate: opts.fetch(:auto_terminate, true), + fallback_policy: :abort, # shouldn't matter -- 0 max queue + name: "io" + ) + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/constants.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/constants.rb new file mode 100644 index 00000000..38e01e6b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/constants.rb @@ -0,0 +1,8 @@ +module Concurrent + + # Various classes within allows for +nil+ values to be stored, + # so a special +NULL+ token is required to indicate the "nil-ness". + # @!visibility private + NULL = ::Object.new.freeze + +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/dataflow.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/dataflow.rb new file mode 100644 index 00000000..d55f19d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/dataflow.rb @@ -0,0 +1,81 @@ +require 'concurrent/future' +require 'concurrent/atomic/atomic_fixnum' + +module Concurrent + + # @!visibility private + class DependencyCounter # :nodoc: + + def initialize(count, &block) + @counter = AtomicFixnum.new(count) + @block = block + end + + def update(time, value, reason) + if @counter.decrement == 0 + @block.call + end + end + end + + # Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available. + # {include:file:docs-source/dataflow.md} + # + # @param [Future] inputs zero or more `Future` operations that this dataflow depends upon + # + # @yield The operation to perform once all the dependencies are met + # @yieldparam [Future] inputs each of the `Future` inputs to the dataflow + # @yieldreturn [Object] the result of the block operation + # + # @return [Object] the result of all the operations + # + # @raise [ArgumentError] if no block is given + # @raise [ArgumentError] if any of the inputs are not `IVar`s + def dataflow(*inputs, &block) + dataflow_with(Concurrent.global_io_executor, *inputs, &block) + end + module_function :dataflow + + def dataflow_with(executor, *inputs, &block) + call_dataflow(:value, executor, *inputs, &block) + end + module_function :dataflow_with + + def dataflow!(*inputs, &block) + dataflow_with!(Concurrent.global_io_executor, *inputs, &block) + end + module_function :dataflow! + + def dataflow_with!(executor, *inputs, &block) + call_dataflow(:value!, executor, *inputs, &block) + end + module_function :dataflow_with! + + private + + def call_dataflow(method, executor, *inputs, &block) + raise ArgumentError.new('an executor must be provided') if executor.nil? + raise ArgumentError.new('no block given') unless block_given? + unless inputs.all? { |input| input.is_a? IVar } + raise ArgumentError.new("Not all dependencies are IVars.\nDependencies: #{ inputs.inspect }") + end + + result = Future.new(executor: executor) do + values = inputs.map { |input| input.send(method) } + block.call(*values) + end + + if inputs.empty? + result.execute + else + counter = DependencyCounter.new(inputs.size) { result.execute } + + inputs.each do |input| + input.add_observer counter + end + end + + result + end + module_function :call_dataflow +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/delay.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/delay.rb new file mode 100644 index 00000000..0d6d91a5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/delay.rb @@ -0,0 +1,199 @@ +require 'thread' +require 'concurrent/concern/obligation' +require 'concurrent/executor/immediate_executor' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # This file has circular require issues. It must be autoloaded here. + autoload :Options, 'concurrent/options' + + # Lazy evaluation of a block yielding an immutable result. Useful for + # expensive operations that may never be needed. It may be non-blocking, + # supports the `Concern::Obligation` interface, and accepts the injection of + # custom executor upon which to execute the block. Processing of + # block will be deferred until the first time `#value` is called. + # At that time the caller can choose to return immediately and let + # the block execute asynchronously, block indefinitely, or block + # with a timeout. + # + # When a `Delay` is created its state is set to `pending`. The value and + # reason are both `nil`. The first time the `#value` method is called the + # enclosed operation will be run and the calling thread will block. Other + # threads attempting to call `#value` will block as well. Once the operation + # is complete the *value* will be set to the result of the operation or the + # *reason* will be set to the raised exception, as appropriate. All threads + # blocked on `#value` will return. Subsequent calls to `#value` will immediately + # return the cached value. The operation will only be run once. This means that + # any side effects created by the operation will only happen once as well. + # + # `Delay` includes the `Concurrent::Concern::Dereferenceable` mixin to support thread + # safety of the reference returned by `#value`. + # + # @!macro copy_options + # + # @!macro delay_note_regarding_blocking + # @note The default behavior of `Delay` is to block indefinitely when + # calling either `value` or `wait`, executing the delayed operation on + # the current thread. This makes the `timeout` value completely + # irrelevant. To enable non-blocking behavior, use the `executor` + # constructor option. This will cause the delayed operation to be + # execute on the given executor, allowing the call to timeout. + # + # @see Concurrent::Concern::Dereferenceable + class Delay < Synchronization::LockableObject + include Concern::Obligation + + # NOTE: Because the global thread pools are lazy-loaded with these objects + # there is a performance hit every time we post a new task to one of these + # thread pools. Subsequently it is critical that `Delay` perform as fast + # as possible post-completion. This class has been highly optimized using + # the benchmark script `examples/lazy_and_delay.rb`. Do NOT attempt to + # DRY-up this class or perform other refactoring with running the + # benchmarks and ensuring that performance is not negatively impacted. + + # Create a new `Delay` in the `:pending` state. + # + # @!macro executor_and_deref_options + # + # @yield the delayed operation to perform + # + # @raise [ArgumentError] if no block is given + def initialize(opts = {}, &block) + raise ArgumentError.new('no block given') unless block_given? + super(&nil) + synchronize { ns_initialize(opts, &block) } + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. If the delayed operation + # raised an exception this method will return nil. The exception object + # can be accessed via the `#reason` method. + # + # @param [Numeric] timeout the maximum number of seconds to wait + # @return [Object] the current value of the object + # + # @!macro delay_note_regarding_blocking + def value(timeout = nil) + if @executor # TODO (pitr 12-Sep-2015): broken unsafe read? + super + else + # this function has been optimized for performance and + # should not be modified without running new benchmarks + synchronize do + execute = @evaluation_started = true unless @evaluation_started + if execute + begin + set_state(true, @task.call, nil) + rescue => ex + set_state(false, nil, ex) + end + elsif incomplete? + raise IllegalOperationError, 'Recursive call to #value during evaluation of the Delay' + end + end + if @do_nothing_on_deref + @value + else + apply_deref_options(@value) + end + end + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. If the delayed operation + # raised an exception, this method will raise that exception (even when) + # the operation has already been executed). + # + # @param [Numeric] timeout the maximum number of seconds to wait + # @return [Object] the current value of the object + # @raise [Exception] when `#rejected?` raises `#reason` + # + # @!macro delay_note_regarding_blocking + def value!(timeout = nil) + if @executor + super + else + result = value + raise @reason if @reason + result + end + end + + # Return the value this object represents after applying the options + # specified by the `#set_deref_options` method. + # + # @param [Integer] timeout (nil) the maximum number of seconds to wait for + # the value to be computed. When `nil` the caller will block indefinitely. + # + # @return [Object] self + # + # @!macro delay_note_regarding_blocking + def wait(timeout = nil) + if @executor + execute_task_once + super(timeout) + else + value + end + self + end + + # Reconfigures the block returning the value if still `#incomplete?` + # + # @yield the delayed operation to perform + # @return [true, false] if success + def reconfigure(&block) + synchronize do + raise ArgumentError.new('no block given') unless block_given? + unless @evaluation_started + @task = block + true + else + false + end + end + end + + protected + + def ns_initialize(opts, &block) + init_obligation + set_deref_options(opts) + @executor = opts[:executor] + + @task = block + @state = :pending + @evaluation_started = false + end + + private + + # @!visibility private + def execute_task_once # :nodoc: + # this function has been optimized for performance and + # should not be modified without running new benchmarks + execute = task = nil + synchronize do + execute = @evaluation_started = true unless @evaluation_started + task = @task + end + + if execute + executor = Options.executor_from_options(executor: @executor) + executor.post do + begin + result = task.call + success = true + rescue => ex + reason = ex + end + synchronize do + set_state(success, result, reason) + event.set + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/errors.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/errors.rb new file mode 100644 index 00000000..74f1fc3d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/errors.rb @@ -0,0 +1,74 @@ +module Concurrent + + Error = Class.new(StandardError) + + # Raised when errors occur during configuration. + ConfigurationError = Class.new(Error) + + # Raised when an asynchronous operation is cancelled before execution. + CancelledOperationError = Class.new(Error) + + # Raised when a lifecycle method (such as `stop`) is called in an improper + # sequence or when the object is in an inappropriate state. + LifecycleError = Class.new(Error) + + # Raised when an attempt is made to violate an immutability guarantee. + ImmutabilityError = Class.new(Error) + + # Raised when an operation is attempted which is not legal given the + # receiver's current state + IllegalOperationError = Class.new(Error) + + # Raised when an object's methods are called when it has not been + # properly initialized. + InitializationError = Class.new(Error) + + # Raised when an object with a start/stop lifecycle has been started an + # excessive number of times. Often used in conjunction with a restart + # policy or strategy. + MaxRestartFrequencyError = Class.new(Error) + + # Raised when an attempt is made to modify an immutable object + # (such as an `IVar`) after its final state has been set. + class MultipleAssignmentError < Error + attr_reader :inspection_data + + def initialize(message = nil, inspection_data = nil) + @inspection_data = inspection_data + super message + end + + def inspect + format '%s %s>', super[0..-2], @inspection_data.inspect + end + end + + # Raised by an `Executor` when it is unable to process a given task, + # possibly because of a reject policy or other internal error. + RejectedExecutionError = Class.new(Error) + + # Raised when any finite resource, such as a lock counter, exceeds its + # maximum limit/threshold. + ResourceLimitError = Class.new(Error) + + # Raised when an operation times out. + TimeoutError = Class.new(Error) + + # Aggregates multiple exceptions. + class MultipleErrors < Error + attr_reader :errors + + def initialize(errors, message = "#{errors.size} errors") + @errors = errors + super [*message, + *errors.map { |e| [format('%s (%s)', e.message, e.class), *e.backtrace] }.flatten(1) + ].join("\n") + end + end + + # @!macro internal_implementation_note + class ConcurrentUpdateError < ThreadError + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/exchanger.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/exchanger.rb new file mode 100644 index 00000000..a5405d25 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/exchanger.rb @@ -0,0 +1,353 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/maybe' +require 'concurrent/atomic/atomic_reference' +require 'concurrent/atomic/count_down_latch' +require 'concurrent/utility/engine' +require 'concurrent/utility/monotonic_time' + +module Concurrent + + # @!macro exchanger + # + # A synchronization point at which threads can pair and swap elements within + # pairs. Each thread presents some object on entry to the exchange method, + # matches with a partner thread, and receives its partner's object on return. + # + # @!macro thread_safe_variable_comparison + # + # This implementation is very simple, using only a single slot for each + # exchanger (unlike more advanced implementations which use an "arena"). + # This approach will work perfectly fine when there are only a few threads + # accessing a single `Exchanger`. Beyond a handful of threads the performance + # will degrade rapidly due to contention on the single slot, but the algorithm + # will remain correct. + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger + # @example + # + # exchanger = Concurrent::Exchanger.new + # + # threads = [ + # Thread.new { puts "first: " << exchanger.exchange('foo', 1) }, #=> "first: bar" + # Thread.new { puts "second: " << exchanger.exchange('bar', 1) } #=> "second: foo" + # ] + # threads.each {|t| t.join(2) } + + # @!visibility private + class AbstractExchanger < Synchronization::Object + + # @!visibility private + CANCEL = ::Object.new + private_constant :CANCEL + + def initialize + super + end + + # @!macro exchanger_method_do_exchange + # + # Waits for another thread to arrive at this exchange point (unless the + # current thread is interrupted), and then transfers the given object to + # it, receiving its object in return. The timeout value indicates the + # approximate number of seconds the method should block while waiting + # for the exchange. When the timeout value is `nil` the method will + # block indefinitely. + # + # @param [Object] value the value to exchange with another thread + # @param [Numeric, nil] timeout in seconds, `nil` blocks indefinitely + # + # @!macro exchanger_method_exchange + # + # In some edge cases when a `timeout` is given a return value of `nil` may be + # ambiguous. Specifically, if `nil` is a valid value in the exchange it will + # be impossible to tell whether `nil` is the actual return value or if it + # signifies timeout. When `nil` is a valid value in the exchange consider + # using {#exchange!} or {#try_exchange} instead. + # + # @return [Object] the value exchanged by the other thread or `nil` on timeout + def exchange(value, timeout = nil) + (value = do_exchange(value, timeout)) == CANCEL ? nil : value + end + + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange_bang + # + # On timeout a {Concurrent::TimeoutError} exception will be raised. + # + # @return [Object] the value exchanged by the other thread + # @raise [Concurrent::TimeoutError] on timeout + def exchange!(value, timeout = nil) + if (value = do_exchange(value, timeout)) == CANCEL + raise Concurrent::TimeoutError + else + value + end + end + + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_try_exchange + # + # The return value will be a {Concurrent::Maybe} set to `Just` on success or + # `Nothing` on timeout. + # + # @return [Concurrent::Maybe] on success a `Just` maybe will be returned with + # the item exchanged by the other thread as `#value`; on timeout a + # `Nothing` maybe will be returned with {Concurrent::TimeoutError} as `#reason` + # + # @example + # + # exchanger = Concurrent::Exchanger.new + # + # result = exchanger.exchange(:foo, 0.5) + # + # if result.just? + # puts result.value #=> :bar + # else + # puts 'timeout' + # end + def try_exchange(value, timeout = nil) + if (value = do_exchange(value, timeout)) == CANCEL + Concurrent::Maybe.nothing(Concurrent::TimeoutError) + else + Concurrent::Maybe.just(value) + end + end + + private + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + raise NotImplementedError + end + end + + # @!macro internal_implementation_note + # @!visibility private + class RubyExchanger < AbstractExchanger + # A simplified version of java.util.concurrent.Exchanger written by + # Doug Lea, Bill Scherer, and Michael Scott with assistance from members + # of JCP JSR-166 Expert Group and released to the public domain. It does + # not include the arena or the multi-processor spin loops. + # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/Exchanger.java + + safe_initialization! + + class Node < Concurrent::Synchronization::Object + attr_atomic :value + safe_initialization! + + def initialize(item) + super() + @Item = item + @Latch = Concurrent::CountDownLatch.new + self.value = nil + end + + def latch + @Latch + end + + def item + @Item + end + end + private_constant :Node + + def initialize + super + end + + private + + attr_atomic(:slot) + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + + # ALGORITHM + # + # From the original Java version: + # + # > The basic idea is to maintain a "slot", which is a reference to + # > a Node containing both an Item to offer and a "hole" waiting to + # > get filled in. If an incoming "occupying" thread sees that the + # > slot is null, it CAS'es (compareAndSets) a Node there and waits + # > for another to invoke exchange. That second "fulfilling" thread + # > sees that the slot is non-null, and so CASes it back to null, + # > also exchanging items by CASing the hole, plus waking up the + # > occupying thread if it is blocked. In each case CAS'es may + # > fail because a slot at first appears non-null but is null upon + # > CAS, or vice-versa. So threads may need to retry these + # > actions. + # + # This version: + # + # An exchange occurs between an "occupier" thread and a "fulfiller" thread. + # The "slot" is used to setup this interaction. The first thread in the + # exchange puts itself into the slot (occupies) and waits for a fulfiller. + # The second thread removes the occupier from the slot and attempts to + # perform the exchange. Removing the occupier also frees the slot for + # another occupier/fulfiller pair. + # + # Because the occupier and the fulfiller are operating independently and + # because there may be contention with other threads, any failed operation + # indicates contention. Both the occupier and the fulfiller operate within + # spin loops. Any failed actions along the happy path will cause the thread + # to repeat the loop and try again. + # + # When a timeout value is given the thread must be cognizant of time spent + # in the spin loop. The remaining time is checked every loop. When the time + # runs out the thread will exit. + # + # A "node" is the data structure used to perform the exchange. Only the + # occupier's node is necessary. It's the node used for the exchange. + # Each node has an "item," a "hole" (self), and a "latch." The item is the + # node's initial value. It never changes. It's what the fulfiller returns on + # success. The occupier's hole is where the fulfiller put its item. It's the + # item that the occupier returns on success. The latch is used for synchronization. + # Because a thread may act as either an occupier or fulfiller (or possibly + # both in periods of high contention) every thread creates a node when + # the exchange method is first called. + # + # The following steps occur within the spin loop. If any actions fail + # the thread will loop and try again, so long as there is time remaining. + # If time runs out the thread will return CANCEL. + # + # Check the slot for an occupier: + # + # * If the slot is empty try to occupy + # * If the slot is full try to fulfill + # + # Attempt to occupy: + # + # * Attempt to CAS myself into the slot + # * Go to sleep and wait to be woken by a fulfiller + # * If the sleep is successful then the fulfiller completed its happy path + # - Return the value from my hole (the value given by the fulfiller) + # * When the sleep fails (time ran out) attempt to cancel the operation + # - Attempt to CAS myself out of the hole + # - If successful there is no contention + # - Return CANCEL + # - On failure, I am competing with a fulfiller + # - Attempt to CAS my hole to CANCEL + # - On success + # - Let the fulfiller deal with my cancel + # - Return CANCEL + # - On failure the fulfiller has completed its happy path + # - Return th value from my hole (the fulfiller's value) + # + # Attempt to fulfill: + # + # * Attempt to CAS the occupier out of the slot + # - On failure loop again + # * Attempt to CAS my item into the occupier's hole + # - On failure the occupier is trying to cancel + # - Loop again + # - On success we are on the happy path + # - Wake the sleeping occupier + # - Return the occupier's item + + value = NULL if value.nil? # The sentinel allows nil to be a valid value + me = Node.new(value) # create my node in case I need to occupy + end_at = Concurrent.monotonic_time + timeout.to_f # The time to give up + + result = loop do + other = slot + if other && compare_and_set_slot(other, nil) + # try to fulfill + if other.compare_and_set_value(nil, value) + # happy path + other.latch.count_down + break other.item + end + elsif other.nil? && compare_and_set_slot(nil, me) + # try to occupy + timeout = end_at - Concurrent.monotonic_time if timeout + if me.latch.wait(timeout) + # happy path + break me.value + else + # attempt to remove myself from the slot + if compare_and_set_slot(me, nil) + break CANCEL + elsif !me.compare_and_set_value(nil, CANCEL) + # I've failed to block the fulfiller + break me.value + end + end + end + break CANCEL if timeout && Concurrent.monotonic_time >= end_at + end + + result == NULL ? nil : result + end + end + + if Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + + # @!macro internal_implementation_note + # @!visibility private + class JavaExchanger < AbstractExchanger + + def initialize + @exchanger = java.util.concurrent.Exchanger.new + end + + private + + # @!macro exchanger_method_do_exchange + # + # @return [Object, CANCEL] the value exchanged by the other thread; {CANCEL} on timeout + def do_exchange(value, timeout) + result = nil + if timeout.nil? + Synchronization::JRuby.sleep_interruptibly do + result = @exchanger.exchange(value) + end + else + Synchronization::JRuby.sleep_interruptibly do + result = @exchanger.exchange(value, 1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + result + rescue java.util.concurrent.TimeoutException + CANCEL + end + end + end + + # @!visibility private + # @!macro internal_implementation_note + ExchangerImplementation = case + when Concurrent.on_jruby? + JavaExchanger + else + RubyExchanger + end + private_constant :ExchangerImplementation + + # @!macro exchanger + class Exchanger < ExchangerImplementation + + # @!method initialize + # Creates exchanger instance + + # @!method exchange(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange + + # @!method exchange!(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_exchange_bang + + # @!method try_exchange(value, timeout = nil) + # @!macro exchanger_method_do_exchange + # @!macro exchanger_method_try_exchange + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb new file mode 100644 index 00000000..ac429531 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb @@ -0,0 +1,131 @@ +require 'concurrent/errors' +require 'concurrent/concern/deprecation' +require 'concurrent/executor/executor_service' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class AbstractExecutorService < Synchronization::LockableObject + include ExecutorService + include Concern::Deprecation + + # The set of possible fallback policies that may be set at thread pool creation. + FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze + + # @!macro executor_service_attr_reader_fallback_policy + attr_reader :fallback_policy + + attr_reader :name + + # Create a new thread pool. + def initialize(opts = {}, &block) + super(&nil) + synchronize do + @auto_terminate = opts.fetch(:auto_terminate, true) + @name = opts.fetch(:name) if opts.key?(:name) + ns_initialize(opts, &block) + end + end + + def to_s + name ? "#{super[0..-2]} name: #{name}>" : super + end + + # @!macro executor_service_method_shutdown + def shutdown + raise NotImplementedError + end + + # @!macro executor_service_method_kill + def kill + raise NotImplementedError + end + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + raise NotImplementedError + end + + # @!macro executor_service_method_running_question + def running? + synchronize { ns_running? } + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + synchronize { ns_shuttingdown? } + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + synchronize { ns_shutdown? } + end + + # @!macro executor_service_method_auto_terminate_question + def auto_terminate? + synchronize { @auto_terminate } + end + + # @!macro executor_service_method_auto_terminate_setter + def auto_terminate=(value) + deprecated "Method #auto_terminate= has no effect. Set :auto_terminate option when executor is initialized." + end + + private + + # Returns an action which executes the `fallback_policy` once the queue + # size reaches `max_queue`. The reason for the indirection of an action + # is so that the work can be deferred outside of synchronization. + # + # @param [Array] args the arguments to the task which is being handled. + # + # @!visibility private + def fallback_action(*args) + case fallback_policy + when :abort + lambda { raise RejectedExecutionError } + when :discard + lambda { false } + when :caller_runs + lambda { + begin + yield(*args) + rescue => ex + # let it fail + log DEBUG, ex + end + true + } + else + lambda { fail "Unknown fallback policy #{fallback_policy}" } + end + end + + def ns_execute(*args, &task) + raise NotImplementedError + end + + # @!macro executor_service_method_ns_shutdown_execution + # + # Callback method called when an orderly shutdown has completed. + # The default behavior is to signal all waiting threads. + def ns_shutdown_execution + # do nothing + end + + # @!macro executor_service_method_ns_kill_execution + # + # Callback method called when the executor has been killed. + # The default behavior is to do nothing. + def ns_kill_execution + # do nothing + end + + def ns_auto_terminate? + @auto_terminate + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb new file mode 100644 index 00000000..de50ed17 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb @@ -0,0 +1,62 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/thread_pool_executor' + +module Concurrent + + # A thread pool that dynamically grows and shrinks to fit the current workload. + # New threads are created as needed, existing threads are reused, and threads + # that remain idle for too long are killed and removed from the pool. These + # pools are particularly suited to applications that perform a high volume of + # short-lived tasks. + # + # On creation a `CachedThreadPool` has zero running threads. New threads are + # created on the pool as new operations are `#post`. The size of the pool + # will grow until `#max_length` threads are in the pool or until the number + # of threads exceeds the number of running and pending operations. When a new + # operation is post to the pool the first available idle thread will be tasked + # with the new operation. + # + # Should a thread crash for any reason the thread will immediately be removed + # from the pool. Similarly, threads which remain idle for an extended period + # of time will be killed and reclaimed. Thus these thread pools are very + # efficient at reclaiming unused resources. + # + # The API and behavior of this class are based on Java's `CachedThreadPool` + # + # @!macro thread_pool_options + class CachedThreadPool < ThreadPoolExecutor + + # @!macro cached_thread_pool_method_initialize + # + # Create a new thread pool. + # + # @param [Hash] opts the options defining pool behavior. + # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy + # + # @raise [ArgumentError] if `fallback_policy` is not a known policy + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool-- + def initialize(opts = {}) + defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT } + overrides = { min_threads: 0, + max_threads: DEFAULT_MAX_POOL_SIZE, + max_queue: DEFAULT_MAX_QUEUE_SIZE } + super(defaults.merge(opts).merge(overrides)) + end + + private + + # @!macro cached_thread_pool_method_initialize + # @!visibility private + def ns_initialize(opts) + super(opts) + if Concurrent.on_jruby? + @max_queue = 0 + @executor = java.util.concurrent.Executors.newCachedThreadPool( + DaemonThreadFactory.new(ns_auto_terminate?)) + @executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new) + @executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/executor_service.rb new file mode 100644 index 00000000..7e344919 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/executor_service.rb @@ -0,0 +1,185 @@ +require 'concurrent/concern/logging' + +module Concurrent + + ################################################################### + + # @!macro executor_service_method_post + # + # Submit a task to the executor for asynchronous processing. + # + # @param [Array] args zero or more arguments to be passed to the task + # + # @yield the asynchronous task to perform + # + # @return [Boolean] `true` if the task is queued, `false` if the executor + # is not running + # + # @raise [ArgumentError] if no task is given + + # @!macro executor_service_method_left_shift + # + # Submit a task to the executor for asynchronous processing. + # + # @param [Proc] task the asynchronous task to perform + # + # @return [self] returns itself + + # @!macro executor_service_method_can_overflow_question + # + # Does the task queue have a maximum size? + # + # @return [Boolean] True if the task queue has a maximum size else false. + + # @!macro executor_service_method_serialized_question + # + # Does this executor guarantee serialization of its operations? + # + # @return [Boolean] True if the executor guarantees that all operations + # will be post in the order they are received and no two operations may + # occur simultaneously. Else false. + + ################################################################### + + # @!macro executor_service_public_api + # + # @!method post(*args, &task) + # @!macro executor_service_method_post + # + # @!method <<(task) + # @!macro executor_service_method_left_shift + # + # @!method can_overflow? + # @!macro executor_service_method_can_overflow_question + # + # @!method serialized? + # @!macro executor_service_method_serialized_question + + ################################################################### + + # @!macro executor_service_attr_reader_fallback_policy + # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`. + + # @!macro executor_service_method_shutdown + # + # Begin an orderly shutdown. Tasks already in the queue will be executed, + # but no new tasks will be accepted. Has no additional effect if the + # thread pool is not running. + + # @!macro executor_service_method_kill + # + # Begin an immediate shutdown. In-progress tasks will be allowed to + # complete but enqueued tasks will be dismissed and no new tasks + # will be accepted. Has no additional effect if the thread pool is + # not running. + + # @!macro executor_service_method_wait_for_termination + # + # Block until executor shutdown is complete or until `timeout` seconds have + # passed. + # + # @note Does not initiate shutdown or termination. Either `shutdown` or `kill` + # must be called before this method (or on another thread). + # + # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete + # + # @return [Boolean] `true` if shutdown complete or false on `timeout` + + # @!macro executor_service_method_running_question + # + # Is the executor running? + # + # @return [Boolean] `true` when running, `false` when shutting down or shutdown + + # @!macro executor_service_method_shuttingdown_question + # + # Is the executor shuttingdown? + # + # @return [Boolean] `true` when not running and not shutdown, else `false` + + # @!macro executor_service_method_shutdown_question + # + # Is the executor shutdown? + # + # @return [Boolean] `true` when shutdown, `false` when shutting down or running + + # @!macro executor_service_method_auto_terminate_question + # + # Is the executor auto-terminate when the application exits? + # + # @return [Boolean] `true` when auto-termination is enabled else `false`. + + # @!macro executor_service_method_auto_terminate_setter + # + # + # Set the auto-terminate behavior for this executor. + # @deprecated Has no effect + # @param [Boolean] value The new auto-terminate value to set for this executor. + # @return [Boolean] `true` when auto-termination is enabled else `false`. + + ################################################################### + + # @!macro abstract_executor_service_public_api + # + # @!macro executor_service_public_api + # + # @!attribute [r] fallback_policy + # @!macro executor_service_attr_reader_fallback_policy + # + # @!method shutdown + # @!macro executor_service_method_shutdown + # + # @!method kill + # @!macro executor_service_method_kill + # + # @!method wait_for_termination(timeout = nil) + # @!macro executor_service_method_wait_for_termination + # + # @!method running? + # @!macro executor_service_method_running_question + # + # @!method shuttingdown? + # @!macro executor_service_method_shuttingdown_question + # + # @!method shutdown? + # @!macro executor_service_method_shutdown_question + # + # @!method auto_terminate? + # @!macro executor_service_method_auto_terminate_question + # + # @!method auto_terminate=(value) + # @!macro executor_service_method_auto_terminate_setter + + ################################################################### + + # @!macro executor_service_public_api + # @!visibility private + module ExecutorService + include Concern::Logging + + # @!macro executor_service_method_post + def post(*args, &task) + raise NotImplementedError + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_can_overflow_question + # + # @note Always returns `false` + def can_overflow? + false + end + + # @!macro executor_service_method_serialized_question + # + # @note Always returns `false` + def serialized? + false + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb new file mode 100644 index 00000000..b73cff87 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb @@ -0,0 +1,222 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/thread_pool_executor' + +module Concurrent + + # @!macro thread_pool_executor_constant_default_max_pool_size + # Default maximum number of threads that will be created in the pool. + + # @!macro thread_pool_executor_constant_default_min_pool_size + # Default minimum number of threads that will be retained in the pool. + + # @!macro thread_pool_executor_constant_default_max_queue_size + # Default maximum number of tasks that may be added to the task queue. + + # @!macro thread_pool_executor_constant_default_thread_timeout + # Default maximum number of seconds a thread in the pool may remain idle + # before being reclaimed. + + # @!macro thread_pool_executor_constant_default_synchronous + # Default value of the :synchronous option. + + # @!macro thread_pool_executor_attr_reader_max_length + # The maximum number of threads that may be created in the pool. + # @return [Integer] The maximum number of threads that may be created in the pool. + + # @!macro thread_pool_executor_attr_reader_min_length + # The minimum number of threads that may be retained in the pool. + # @return [Integer] The minimum number of threads that may be retained in the pool. + + # @!macro thread_pool_executor_attr_reader_largest_length + # The largest number of threads that have been created in the pool since construction. + # @return [Integer] The largest number of threads that have been created in the pool since construction. + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + # The number of tasks that have been scheduled for execution on the pool since construction. + # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction. + + # @!macro thread_pool_executor_attr_reader_completed_task_count + # The number of tasks that have been completed by the pool since construction. + # @return [Integer] The number of tasks that have been completed by the pool since construction. + + # @!macro thread_pool_executor_method_active_count + # The number of threads that are actively executing tasks. + # @return [Integer] The number of threads that are actively executing tasks. + + # @!macro thread_pool_executor_attr_reader_idletime + # The number of seconds that a thread may be idle before being reclaimed. + # @return [Integer] The number of seconds that a thread may be idle before being reclaimed. + + # @!macro thread_pool_executor_attr_reader_synchronous + # Whether or not a value of 0 for :max_queue option means the queue must perform direct hand-off or rather unbounded queue. + # @return [true, false] + + # @!macro thread_pool_executor_attr_reader_max_queue + # The maximum number of tasks that may be waiting in the work queue at any one time. + # When the queue size reaches `max_queue` subsequent tasks will be rejected in + # accordance with the configured `fallback_policy`. + # + # @return [Integer] The maximum number of tasks that may be waiting in the work queue at any one time. + # When the queue size reaches `max_queue` subsequent tasks will be rejected in + # accordance with the configured `fallback_policy`. + + # @!macro thread_pool_executor_attr_reader_length + # The number of threads currently in the pool. + # @return [Integer] The number of threads currently in the pool. + + # @!macro thread_pool_executor_attr_reader_queue_length + # The number of tasks in the queue awaiting execution. + # @return [Integer] The number of tasks in the queue awaiting execution. + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + # Number of tasks that may be enqueued before reaching `max_queue` and rejecting + # new tasks. A value of -1 indicates that the queue may grow without bound. + # + # @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting + # new tasks. A value of -1 indicates that the queue may grow without bound. + + # @!macro thread_pool_executor_method_prune_pool + # Prune the thread pool of unneeded threads + # + # What is being pruned is controlled by the min_threads and idletime + # parameters passed at pool creation time + # + # This is a no-op on all pool implementations as they prune themselves + # automatically, and has been deprecated. + + # @!macro thread_pool_executor_public_api + # + # @!macro abstract_executor_service_public_api + # + # @!attribute [r] max_length + # @!macro thread_pool_executor_attr_reader_max_length + # + # @!attribute [r] min_length + # @!macro thread_pool_executor_attr_reader_min_length + # + # @!attribute [r] largest_length + # @!macro thread_pool_executor_attr_reader_largest_length + # + # @!attribute [r] scheduled_task_count + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + # + # @!attribute [r] completed_task_count + # @!macro thread_pool_executor_attr_reader_completed_task_count + # + # @!attribute [r] idletime + # @!macro thread_pool_executor_attr_reader_idletime + # + # @!attribute [r] max_queue + # @!macro thread_pool_executor_attr_reader_max_queue + # + # @!attribute [r] length + # @!macro thread_pool_executor_attr_reader_length + # + # @!attribute [r] queue_length + # @!macro thread_pool_executor_attr_reader_queue_length + # + # @!attribute [r] remaining_capacity + # @!macro thread_pool_executor_attr_reader_remaining_capacity + # + # @!method can_overflow? + # @!macro executor_service_method_can_overflow_question + # + # @!method prune_pool + # @!macro thread_pool_executor_method_prune_pool + + + + + # @!macro thread_pool_options + # + # **Thread Pool Options** + # + # Thread pools support several configuration options: + # + # * `idletime`: The number of seconds that a thread may be idle before being reclaimed. + # * `name`: The name of the executor (optional). Printed in the executor's `#to_s` output and + # a `-worker-` name is given to its threads if supported by used Ruby + # implementation. `` is uniq for each thread. + # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at + # any one time. When the queue size reaches `max_queue` and no new threads can be created, + # subsequent tasks will be rejected in accordance with the configured `fallback_policy`. + # * `auto_terminate`: When true (default), the threads started will be marked as daemon. + # * `fallback_policy`: The policy defining how rejected tasks are handled. + # + # Three fallback policies are supported: + # + # * `:abort`: Raise a `RejectedExecutionError` exception and discard the task. + # * `:discard`: Discard the task and return false. + # * `:caller_runs`: Execute the task on the calling thread. + # + # **Shutting Down Thread Pools** + # + # Killing a thread pool while tasks are still being processed, either by calling + # the `#kill` method or at application exit, will have unpredictable results. There + # is no way for the thread pool to know what resources are being used by the + # in-progress tasks. When those tasks are killed the impact on those resources + # cannot be predicted. The *best* practice is to explicitly shutdown all thread + # pools using the provided methods: + # + # * Call `#shutdown` to initiate an orderly termination of all in-progress tasks + # * Call `#wait_for_termination` with an appropriate timeout interval an allow + # the orderly shutdown to complete + # * Call `#kill` *only when* the thread pool fails to shutdown in the allotted time + # + # On some runtime platforms (most notably the JVM) the application will not + # exit until all thread pools have been shutdown. To prevent applications from + # "hanging" on exit, all threads can be marked as daemon according to the + # `:auto_terminate` option. + # + # ```ruby + # pool1 = Concurrent::FixedThreadPool.new(5) # threads will be marked as daemon + # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # mark threads as non-daemon + # ``` + # + # @note Failure to properly shutdown a thread pool can lead to unpredictable results. + # Please read *Shutting Down Thread Pools* for more information. + # + # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface + # @see https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDaemon-boolean- + + + + + + # @!macro fixed_thread_pool + # + # A thread pool that reuses a fixed number of threads operating off an unbounded queue. + # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new + # tasks `#post` to the thread pool are enqueued until a thread becomes available. + # Should a thread crash for any reason the thread will immediately be removed + # from the pool and replaced. + # + # The API and behavior of this class are based on Java's `FixedThreadPool` + # + # @!macro thread_pool_options + class FixedThreadPool < ThreadPoolExecutor + + # @!macro fixed_thread_pool_method_initialize + # + # Create a new thread pool. + # + # @param [Integer] num_threads the number of threads to allocate + # @param [Hash] opts the options defining pool behavior. + # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy + # + # @raise [ArgumentError] if `num_threads` is less than or equal to zero + # @raise [ArgumentError] if `fallback_policy` is not a known policy + # + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int- + def initialize(num_threads, opts = {}) + raise ArgumentError.new('number of threads must be greater than zero') if num_threads.to_i < 1 + defaults = { max_queue: DEFAULT_MAX_QUEUE_SIZE, + idletime: DEFAULT_THREAD_IDLETIMEOUT } + overrides = { min_threads: num_threads, + max_threads: num_threads } + super(defaults.merge(opts).merge(overrides)) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb new file mode 100644 index 00000000..282df7a0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb @@ -0,0 +1,66 @@ +require 'concurrent/atomic/event' +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/executor/serial_executor_service' + +module Concurrent + + # An executor service which runs all operations on the current thread, + # blocking as necessary. Operations are performed in the order they are + # received and no two operations can be performed simultaneously. + # + # This executor service exists mainly for testing an debugging. When used + # it immediately runs every `#post` operation on the current thread, blocking + # that thread until the operation is complete. This can be very beneficial + # during testing because it makes all operations deterministic. + # + # @note Intended for use primarily in testing and debugging. + class ImmediateExecutor < AbstractExecutorService + include SerialExecutorService + + # Creates a new executor + def initialize + @stopped = Concurrent::Event.new + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + task.call(*args) + true + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_running_question + def running? + ! shutdown? + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + false + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + @stopped.set? + end + + # @!macro executor_service_method_shutdown + def shutdown + @stopped.set + true + end + alias_method :kill, :shutdown + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + @stopped.wait(timeout) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb new file mode 100644 index 00000000..4f9769fa --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb @@ -0,0 +1,44 @@ +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/simple_executor_service' + +module Concurrent + # An executor service which runs all operations on a new thread, blocking + # until it completes. Operations are performed in the order they are received + # and no two operations can be performed simultaneously. + # + # This executor service exists mainly for testing an debugging. When used it + # immediately runs every `#post` operation on a new thread, blocking the + # current thread until the operation is complete. This is similar to how the + # ImmediateExecutor works, but the operation has the full stack of the new + # thread at its disposal. This can be helpful when the operations will spawn + # more operations on the same executor and so on - such a situation might + # overflow the single stack in case of an ImmediateExecutor, which is + # inconsistent with how it would behave for a threaded executor. + # + # @note Intended for use primarily in testing and debugging. + class IndirectImmediateExecutor < ImmediateExecutor + # Creates a new executor + def initialize + super + @internal_executor = SimpleExecutorService.new + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new("no block given") unless block_given? + return false unless running? + + event = Concurrent::Event.new + @internal_executor.post do + begin + task.call(*args) + ensure + event.set + end + end + event.wait + + true + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb new file mode 100644 index 00000000..96991a78 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb @@ -0,0 +1,101 @@ +require 'concurrent/utility/engine' + +if Concurrent.on_jruby? + require 'concurrent/errors' + require 'concurrent/executor/abstract_executor_service' + + module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class JavaExecutorService < AbstractExecutorService + java_import 'java.lang.Runnable' + + FALLBACK_POLICY_CLASSES = { + abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy, + discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy, + caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy + }.freeze + private_constant :FALLBACK_POLICY_CLASSES + + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return fallback_action(*args, &task).call unless running? + @executor.submit Job.new(args, task) + true + rescue Java::JavaUtilConcurrent::RejectedExecutionException + raise RejectedExecutionError + end + + def wait_for_termination(timeout = nil) + if timeout.nil? + ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok + true + else + @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS) + end + end + + def shutdown + synchronize do + @executor.shutdown + nil + end + end + + def kill + synchronize do + @executor.shutdownNow + wait_for_termination + nil + end + end + + private + + def ns_running? + !(ns_shuttingdown? || ns_shutdown?) + end + + def ns_shuttingdown? + @executor.isShutdown && !@executor.isTerminated + end + + def ns_shutdown? + @executor.isTerminated + end + + class Job + include Runnable + def initialize(args, block) + @args = args + @block = block + end + + def run + @block.call(*@args) + end + end + private_constant :Job + end + + class DaemonThreadFactory + # hide include from YARD + send :include, java.util.concurrent.ThreadFactory + + def initialize(daemonize = true) + @daemonize = daemonize + @java_thread_factory = java.util.concurrent.Executors.defaultThreadFactory + end + + def newThread(runnable) + thread = @java_thread_factory.newThread(runnable) + thread.setDaemon(@daemonize) + return thread + end + end + + private_constant :DaemonThreadFactory + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb new file mode 100644 index 00000000..7aa24f2d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb @@ -0,0 +1,30 @@ +if Concurrent.on_jruby? + + require 'concurrent/executor/java_executor_service' + require 'concurrent/executor/serial_executor_service' + + module Concurrent + + # @!macro single_thread_executor + # @!macro abstract_executor_service_public_api + # @!visibility private + class JavaSingleThreadExecutor < JavaExecutorService + include SerialExecutorService + + # @!macro single_thread_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + private + + def ns_initialize(opts) + @executor = java.util.concurrent.Executors.newSingleThreadExecutor( + DaemonThreadFactory.new(ns_auto_terminate?) + ) + @fallback_policy = opts.fetch(:fallback_policy, :discard) + raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.keys.include?(@fallback_policy) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb new file mode 100644 index 00000000..a89fde27 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb @@ -0,0 +1,147 @@ +if Concurrent.on_jruby? + + require 'concurrent/executor/java_executor_service' + + module Concurrent + + # @!macro thread_pool_executor + # @!macro thread_pool_options + # @!visibility private + class JavaThreadPoolExecutor < JavaExecutorService + include Concern::Deprecation + + # @!macro thread_pool_executor_constant_default_max_pool_size + DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647 + + # @!macro thread_pool_executor_constant_default_min_pool_size + DEFAULT_MIN_POOL_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_max_queue_size + DEFAULT_MAX_QUEUE_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_thread_timeout + DEFAULT_THREAD_IDLETIMEOUT = 60 + + # @!macro thread_pool_executor_constant_default_synchronous + DEFAULT_SYNCHRONOUS = false + + # @!macro thread_pool_executor_attr_reader_max_length + attr_reader :max_length + + # @!macro thread_pool_executor_attr_reader_max_queue + attr_reader :max_queue + + # @!macro thread_pool_executor_attr_reader_synchronous + attr_reader :synchronous + + # @!macro thread_pool_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + # @!macro executor_service_method_can_overflow_question + def can_overflow? + @max_queue != 0 + end + + # @!macro thread_pool_executor_attr_reader_min_length + def min_length + @executor.getCorePoolSize + end + + # @!macro thread_pool_executor_attr_reader_max_length + def max_length + @executor.getMaximumPoolSize + end + + # @!macro thread_pool_executor_attr_reader_length + def length + @executor.getPoolSize + end + + # @!macro thread_pool_executor_attr_reader_largest_length + def largest_length + @executor.getLargestPoolSize + end + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + def scheduled_task_count + @executor.getTaskCount + end + + # @!macro thread_pool_executor_attr_reader_completed_task_count + def completed_task_count + @executor.getCompletedTaskCount + end + + # @!macro thread_pool_executor_method_active_count + def active_count + @executor.getActiveCount + end + + # @!macro thread_pool_executor_attr_reader_idletime + def idletime + @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS) + end + + # @!macro thread_pool_executor_attr_reader_queue_length + def queue_length + @executor.getQueue.size + end + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + def remaining_capacity + @max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity + end + + # @!macro executor_service_method_running_question + def running? + super && !@executor.isTerminating + end + + # @!macro thread_pool_executor_method_prune_pool + def prune_pool + deprecated "#prune_pool has no effect and will be removed in the next release." + end + + private + + def ns_initialize(opts) + min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i + max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i + idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i + @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i + @synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS) + @fallback_policy = opts.fetch(:fallback_policy, :abort) + + raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0 + raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if min_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length + raise ArgumentError.new("#{fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICY_CLASSES.include?(@fallback_policy) + + if @max_queue == 0 + if @synchronous + queue = java.util.concurrent.SynchronousQueue.new + else + queue = java.util.concurrent.LinkedBlockingQueue.new + end + else + queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue) + end + + @executor = java.util.concurrent.ThreadPoolExecutor.new( + min_length, + max_length, + idletime, + java.util.concurrent.TimeUnit::SECONDS, + queue, + DaemonThreadFactory.new(ns_auto_terminate?), + FALLBACK_POLICY_CLASSES[@fallback_policy].new) + + end + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb new file mode 100644 index 00000000..1f7301b9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb @@ -0,0 +1,82 @@ +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/atomic/event' + +module Concurrent + + # @!macro abstract_executor_service_public_api + # @!visibility private + class RubyExecutorService < AbstractExecutorService + safe_initialization! + + def initialize(*args, &block) + super + @StopEvent = Event.new + @StoppedEvent = Event.new + end + + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + deferred_action = synchronize { + if running? + ns_execute(*args, &task) + else + fallback_action(*args, &task) + end + } + if deferred_action + deferred_action.call + else + true + end + end + + def shutdown + synchronize do + break unless running? + stop_event.set + ns_shutdown_execution + end + true + end + + def kill + synchronize do + break if shutdown? + stop_event.set + ns_kill_execution + stopped_event.set + end + true + end + + def wait_for_termination(timeout = nil) + stopped_event.wait(timeout) + end + + private + + def stop_event + @StopEvent + end + + def stopped_event + @StoppedEvent + end + + def ns_shutdown_execution + stopped_event.set + end + + def ns_running? + !stop_event.set? + end + + def ns_shuttingdown? + !(ns_running? || ns_shutdown?) + end + + def ns_shutdown? + stopped_event.set? + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb new file mode 100644 index 00000000..6d9f88c2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb @@ -0,0 +1,23 @@ +require 'concurrent/executor/ruby_thread_pool_executor' +require 'concurrent/executor/serial_executor_service' + +module Concurrent + + # @!macro single_thread_executor + # @!macro abstract_executor_service_public_api + # @!visibility private + class RubySingleThreadExecutor < RubyThreadPoolExecutor + include SerialExecutorService + + # @!macro single_thread_executor_method_initialize + def initialize(opts = {}) + super( + min_threads: 1, + max_threads: 1, + max_queue: 0, + idletime: DEFAULT_THREAD_IDLETIMEOUT, + fallback_policy: opts.fetch(:fallback_policy, :discard), + ) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb new file mode 100644 index 00000000..28bbdcad --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb @@ -0,0 +1,396 @@ +require 'thread' +require 'concurrent/atomic/event' +require 'concurrent/concern/logging' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/utility/monotonic_time' +require 'concurrent/collection/timeout_queue' + +module Concurrent + + # @!macro thread_pool_executor + # @!macro thread_pool_options + # @!visibility private + class RubyThreadPoolExecutor < RubyExecutorService + include Concern::Deprecation + + # @!macro thread_pool_executor_constant_default_max_pool_size + DEFAULT_MAX_POOL_SIZE = 2_147_483_647 # java.lang.Integer::MAX_VALUE + + # @!macro thread_pool_executor_constant_default_min_pool_size + DEFAULT_MIN_POOL_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_max_queue_size + DEFAULT_MAX_QUEUE_SIZE = 0 + + # @!macro thread_pool_executor_constant_default_thread_timeout + DEFAULT_THREAD_IDLETIMEOUT = 60 + + # @!macro thread_pool_executor_constant_default_synchronous + DEFAULT_SYNCHRONOUS = false + + # @!macro thread_pool_executor_attr_reader_max_length + attr_reader :max_length + + # @!macro thread_pool_executor_attr_reader_min_length + attr_reader :min_length + + # @!macro thread_pool_executor_attr_reader_idletime + attr_reader :idletime + + # @!macro thread_pool_executor_attr_reader_max_queue + attr_reader :max_queue + + # @!macro thread_pool_executor_attr_reader_synchronous + attr_reader :synchronous + + # @!macro thread_pool_executor_method_initialize + def initialize(opts = {}) + super(opts) + end + + # @!macro thread_pool_executor_attr_reader_largest_length + def largest_length + synchronize { @largest_length } + end + + # @!macro thread_pool_executor_attr_reader_scheduled_task_count + def scheduled_task_count + synchronize { @scheduled_task_count } + end + + # @!macro thread_pool_executor_attr_reader_completed_task_count + def completed_task_count + synchronize { @completed_task_count } + end + + # @!macro thread_pool_executor_method_active_count + def active_count + synchronize do + @pool.length - @ready.length + end + end + + # @!macro executor_service_method_can_overflow_question + def can_overflow? + synchronize { ns_limited_queue? } + end + + # @!macro thread_pool_executor_attr_reader_length + def length + synchronize { @pool.length } + end + + # @!macro thread_pool_executor_attr_reader_queue_length + def queue_length + synchronize { @queue.length } + end + + # @!macro thread_pool_executor_attr_reader_remaining_capacity + def remaining_capacity + synchronize do + if ns_limited_queue? + @max_queue - @queue.length + else + -1 + end + end + end + + # removes the worker if it can be pruned + # + # @return [true, false] if the worker was pruned + # + # @!visibility private + def prune_worker(worker) + synchronize do + if ns_prunable_capacity > 0 + remove_worker worker + true + else + false + end + end + end + + # @!visibility private + def remove_worker(worker) + synchronize do + ns_remove_ready_worker worker + ns_remove_busy_worker worker + end + end + + # @!visibility private + def ready_worker(worker, last_message) + synchronize { ns_ready_worker worker, last_message } + end + + # @!visibility private + def worker_died(worker) + synchronize { ns_worker_died worker } + end + + # @!visibility private + def worker_task_completed + synchronize { @completed_task_count += 1 } + end + + # @!macro thread_pool_executor_method_prune_pool + def prune_pool + deprecated "#prune_pool has no effect and will be removed in next the release, see https://github.com/ruby-concurrency/concurrent-ruby/pull/1082." + end + + private + + # @!visibility private + def ns_initialize(opts) + @min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i + @max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i + @idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i + @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i + @synchronous = opts.fetch(:synchronous, DEFAULT_SYNCHRONOUS) + @fallback_policy = opts.fetch(:fallback_policy, :abort) + + raise ArgumentError.new("`synchronous` cannot be set unless `max_queue` is 0") if @synchronous && @max_queue > 0 + raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy) + raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @max_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if @max_length > DEFAULT_MAX_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @min_length < DEFAULT_MIN_POOL_SIZE + raise ArgumentError.new("`min_threads` cannot be more than `max_threads`") if min_length > max_length + + @pool = [] # all workers + @ready = [] # used as a stash (most idle worker is at the start) + @queue = [] # used as queue + # @ready or @queue is empty at all times + @scheduled_task_count = 0 + @completed_task_count = 0 + @largest_length = 0 + @workers_counter = 0 + @ruby_pid = $$ # detects if Ruby has forked + end + + # @!visibility private + def ns_limited_queue? + @max_queue != 0 + end + + # @!visibility private + def ns_execute(*args, &task) + ns_reset_if_forked + + if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task) + @scheduled_task_count += 1 + nil + else + fallback_action(*args, &task) + end + end + + # @!visibility private + def ns_shutdown_execution + ns_reset_if_forked + + if @pool.empty? + # nothing to do + stopped_event.set + end + + if @queue.empty? + # no more tasks will be accepted, just stop all workers + @pool.each(&:stop) + end + end + + # @!visibility private + def ns_kill_execution + # TODO log out unprocessed tasks in queue + # TODO try to shutdown first? + @pool.each(&:kill) + @pool.clear + @ready.clear + end + + # tries to assign task to a worker, tries to get one from @ready or to create new one + # @return [true, false] if task is assigned to a worker + # + # @!visibility private + def ns_assign_worker(*args, &task) + # keep growing if the pool is not at the minimum yet + worker, _ = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker + if worker + worker << [task, args] + true + else + false + end + rescue ThreadError + # Raised when the operating system refuses to create the new thread + return false + end + + # tries to enqueue task + # @return [true, false] if enqueued + # + # @!visibility private + def ns_enqueue(*args, &task) + return false if @synchronous + + if !ns_limited_queue? || @queue.size < @max_queue + @queue << [task, args] + true + else + false + end + end + + # @!visibility private + def ns_worker_died(worker) + ns_remove_busy_worker worker + replacement_worker = ns_add_busy_worker + ns_ready_worker replacement_worker, Concurrent.monotonic_time, false if replacement_worker + end + + # creates new worker which has to receive work to do after it's added + # @return [nil, Worker] nil of max capacity is reached + # + # @!visibility private + def ns_add_busy_worker + return if @pool.size >= @max_length + + @workers_counter += 1 + @pool << (worker = Worker.new(self, @workers_counter)) + @largest_length = @pool.length if @pool.length > @largest_length + worker + end + + # handle ready worker, giving it new job or assigning back to @ready + # + # @!visibility private + def ns_ready_worker(worker, last_message, success = true) + task_and_args = @queue.shift + if task_and_args + worker << task_and_args + else + # stop workers when !running?, do not return them to @ready + if running? + raise unless last_message + @ready.push([worker, last_message]) + else + worker.stop + end + end + end + + # removes a worker which is not tracked in @ready + # + # @!visibility private + def ns_remove_busy_worker(worker) + @pool.delete(worker) + stopped_event.set if @pool.empty? && !running? + true + end + + # @!visibility private + def ns_remove_ready_worker(worker) + if index = @ready.index { |rw, _| rw == worker } + @ready.delete_at(index) + end + true + end + + # @return [Integer] number of excess idle workers which can be removed without + # going below min_length, or all workers if not running + # + # @!visibility private + def ns_prunable_capacity + if running? + [@pool.size - @min_length, @ready.size].min + else + @pool.size + end + end + + # @!visibility private + def ns_reset_if_forked + if $$ != @ruby_pid + @queue.clear + @ready.clear + @pool.clear + @scheduled_task_count = 0 + @completed_task_count = 0 + @largest_length = 0 + @workers_counter = 0 + @ruby_pid = $$ + end + end + + # @!visibility private + class Worker + include Concern::Logging + + def initialize(pool, id) + # instance variables accessed only under pool's lock so no need to sync here again + @queue = Collection::TimeoutQueue.new + @pool = pool + @thread = create_worker @queue, pool, pool.idletime + + if @thread.respond_to?(:name=) + @thread.name = [pool.name, 'worker', id].compact.join('-') + end + end + + def <<(message) + @queue << message + end + + def stop + @queue << :stop + end + + def kill + @thread.kill + end + + private + + def create_worker(queue, pool, idletime) + Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime| + catch(:stop) do + prunable = true + + loop do + timeout = prunable && my_pool.running? ? my_idletime : nil + case message = my_queue.pop(timeout: timeout) + when nil + throw :stop if my_pool.prune_worker(self) + prunable = false + when :stop + my_pool.remove_worker(self) + throw :stop + else + task, args = message + run_task my_pool, task, args + my_pool.ready_worker(self, Concurrent.monotonic_time) + prunable = true + end + end + end + end + end + + def run_task(pool, task, args) + task.call(*args) + pool.worker_task_completed + rescue => ex + # let it fail + log DEBUG, ex + rescue Exception => ex + log ERROR, ex + pool.worker_died(self) + throw :stop + end + end + + private_constant :Worker + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb new file mode 100644 index 00000000..f796b857 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb @@ -0,0 +1,35 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A simple utility class that executes a callable and returns and array of three elements: + # success - indicating if the callable has been executed without errors + # value - filled by the callable result if it has been executed without errors, nil otherwise + # reason - the error risen by the callable if it has been executed with errors, nil otherwise + class SafeTaskExecutor < Synchronization::LockableObject + + def initialize(task, opts = {}) + @task = task + @exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError + super() # ensures visibility + end + + # @return [Array] + def execute(*args) + success = true + value = reason = nil + + synchronize do + begin + value = @task.call(*args) + success = true + rescue @exception_class => ex + reason = ex + success = false + end + end + + [success, value, reason] + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb new file mode 100644 index 00000000..f1c38ecf --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb @@ -0,0 +1,34 @@ +require 'concurrent/executor/executor_service' + +module Concurrent + + # Indicates that the including `ExecutorService` guarantees + # that all operations will occur in the order they are post and that no + # two operations may occur simultaneously. This module provides no + # functionality and provides no guarantees. That is the responsibility + # of the including class. This module exists solely to allow the including + # object to be interrogated for its serialization status. + # + # @example + # class Foo + # include Concurrent::SerialExecutor + # end + # + # foo = Foo.new + # + # foo.is_a? Concurrent::ExecutorService #=> true + # foo.is_a? Concurrent::SerialExecutor #=> true + # foo.serialized? #=> true + # + # @!visibility private + module SerialExecutorService + include ExecutorService + + # @!macro executor_service_method_serialized_question + # + # @note Always returns `true` + def serialized? + true + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb new file mode 100644 index 00000000..4db7c7f0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb @@ -0,0 +1,107 @@ +require 'concurrent/errors' +require 'concurrent/concern/logging' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # Ensures passed jobs in a serialized order never running at the same time. + class SerializedExecution < Synchronization::LockableObject + include Concern::Logging + + def initialize() + super() + synchronize { ns_initialize } + end + + Job = Struct.new(:executor, :args, :block) do + def call + block.call(*args) + end + end + + # Submit a task to the executor for asynchronous processing. + # + # @param [Executor] executor to be used for this job + # + # @param [Array] args zero or more arguments to be passed to the task + # + # @yield the asynchronous task to perform + # + # @return [Boolean] `true` if the task is queued, `false` if the executor + # is not running + # + # @raise [ArgumentError] if no task is given + def post(executor, *args, &task) + posts [[executor, args, task]] + true + end + + # As {#post} but allows to submit multiple tasks at once, it's guaranteed that they will not + # be interleaved by other tasks. + # + # @param [Array, Proc)>] posts array of triplets where + # first is a {ExecutorService}, second is array of args for task, third is a task (Proc) + def posts(posts) + # if can_overflow? + # raise ArgumentError, 'SerializedExecution does not support thread-pools which can overflow' + # end + + return nil if posts.empty? + + jobs = posts.map { |executor, args, task| Job.new executor, args, task } + + job_to_post = synchronize do + if @being_executed + @stash.push(*jobs) + nil + else + @being_executed = true + @stash.push(*jobs[1..-1]) + jobs.first + end + end + + call_job job_to_post if job_to_post + true + end + + private + + def ns_initialize + @being_executed = false + @stash = [] + end + + def call_job(job) + did_it_run = begin + job.executor.post { work(job) } + true + rescue RejectedExecutionError => ex + false + end + + # TODO not the best idea to run it myself + unless did_it_run + begin + work job + rescue => ex + # let it fail + log DEBUG, ex + end + end + end + + # ensures next job is executed if any is stashed + def work(job) + job.call + ensure + synchronize do + job = @stash.shift || (@being_executed = false) + end + + # TODO maybe be able to tell caching pool to just enqueue this job, because the current one end at the end + # of this block + call_job job if job + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb new file mode 100644 index 00000000..8197781b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb @@ -0,0 +1,28 @@ +require 'delegate' +require 'concurrent/executor/serial_executor_service' +require 'concurrent/executor/serialized_execution' + +module Concurrent + + # A wrapper/delegator for any `ExecutorService` that + # guarantees serialized execution of tasks. + # + # @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html) + # @see Concurrent::SerializedExecution + class SerializedExecutionDelegator < SimpleDelegator + include SerialExecutorService + + def initialize(executor) + @executor = executor + @serializer = SerializedExecution.new + super(executor) + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + @serializer.post(@executor, *args, &task) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb new file mode 100644 index 00000000..0bc62afd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb @@ -0,0 +1,103 @@ +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/atomic/event' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/ruby_executor_service' + +module Concurrent + + # An executor service in which every operation spawns a new, + # independently operating thread. + # + # This is perhaps the most inefficient executor service in this + # library. It exists mainly for testing an debugging. Thread creation + # and management is expensive in Ruby and this executor performs no + # resource pooling. This can be very beneficial during testing and + # debugging because it decouples the using code from the underlying + # executor implementation. In production this executor will likely + # lead to suboptimal performance. + # + # @note Intended for use primarily in testing and debugging. + class SimpleExecutorService < RubyExecutorService + + # @!macro executor_service_method_post + def self.post(*args) + raise ArgumentError.new('no block given') unless block_given? + Thread.new(*args) do + Thread.current.abort_on_exception = false + yield(*args) + end + true + end + + # @!macro executor_service_method_left_shift + def self.<<(task) + post(&task) + self + end + + # @!macro executor_service_method_post + def post(*args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + @count.increment + Thread.new(*args) do + Thread.current.abort_on_exception = false + begin + yield(*args) + ensure + @count.decrement + @stopped.set if @running.false? && @count.value == 0 + end + end + end + + # @!macro executor_service_method_left_shift + def <<(task) + post(&task) + self + end + + # @!macro executor_service_method_running_question + def running? + @running.true? + end + + # @!macro executor_service_method_shuttingdown_question + def shuttingdown? + @running.false? && ! @stopped.set? + end + + # @!macro executor_service_method_shutdown_question + def shutdown? + @stopped.set? + end + + # @!macro executor_service_method_shutdown + def shutdown + @running.make_false + @stopped.set if @count.value == 0 + true + end + + # @!macro executor_service_method_kill + def kill + @running.make_false + @stopped.set + true + end + + # @!macro executor_service_method_wait_for_termination + def wait_for_termination(timeout = nil) + @stopped.wait(timeout) + end + + private + + def ns_initialize(*args) + @running = Concurrent::AtomicBoolean.new(true) + @stopped = Concurrent::Event.new + @count = Concurrent::AtomicFixnum.new(0) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb new file mode 100644 index 00000000..220eb0ff --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb @@ -0,0 +1,57 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/ruby_single_thread_executor' + +module Concurrent + + if Concurrent.on_jruby? + require 'concurrent/executor/java_single_thread_executor' + end + + SingleThreadExecutorImplementation = case + when Concurrent.on_jruby? + JavaSingleThreadExecutor + else + RubySingleThreadExecutor + end + private_constant :SingleThreadExecutorImplementation + + # @!macro single_thread_executor + # + # A thread pool with a single thread an unlimited queue. Should the thread + # die for any reason it will be removed and replaced, thus ensuring that + # the executor will always remain viable and available to process jobs. + # + # A common pattern for background processing is to create a single thread + # on which an infinite loop is run. The thread's loop blocks on an input + # source (perhaps blocking I/O or a queue) and processes each input as it + # is received. This pattern has several issues. The thread itself is highly + # susceptible to errors during processing. Also, the thread itself must be + # constantly monitored and restarted should it die. `SingleThreadExecutor` + # encapsulates all these behaviors. The task processor is highly resilient + # to errors from within tasks. Also, should the thread die it will + # automatically be restarted. + # + # The API and behavior of this class are based on Java's `SingleThreadExecutor`. + # + # @!macro abstract_executor_service_public_api + class SingleThreadExecutor < SingleThreadExecutorImplementation + + # @!macro single_thread_executor_method_initialize + # + # Create a new thread pool. + # + # @option opts [Symbol] :fallback_policy (:discard) the policy for handling new + # tasks that are received when the queue size has reached + # `max_queue` or the executor has shut down + # + # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified + # in `FALLBACK_POLICIES` + # + # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html + # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html + + # @!method initialize(opts = {}) + # @!macro single_thread_executor_method_initialize + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb new file mode 100644 index 00000000..253d46a9 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb @@ -0,0 +1,88 @@ +require 'concurrent/utility/engine' +require 'concurrent/executor/ruby_thread_pool_executor' + +module Concurrent + + if Concurrent.on_jruby? + require 'concurrent/executor/java_thread_pool_executor' + end + + ThreadPoolExecutorImplementation = case + when Concurrent.on_jruby? + JavaThreadPoolExecutor + else + RubyThreadPoolExecutor + end + private_constant :ThreadPoolExecutorImplementation + + # @!macro thread_pool_executor + # + # An abstraction composed of one or more threads and a task queue. Tasks + # (blocks or `proc` objects) are submitted to the pool and added to the queue. + # The threads in the pool remove the tasks and execute them in the order + # they were received. + # + # A `ThreadPoolExecutor` will automatically adjust the pool size according + # to the bounds set by `min-threads` and `max-threads`. When a new task is + # submitted and fewer than `min-threads` threads are running, a new thread + # is created to handle the request, even if other worker threads are idle. + # If there are more than `min-threads` but less than `max-threads` threads + # running, a new thread will be created only if the queue is full. + # + # Threads that are idle for too long will be garbage collected, down to the + # configured minimum options. Should a thread crash it, too, will be garbage collected. + # + # `ThreadPoolExecutor` is based on the Java class of the same name. From + # the official Java documentation; + # + # > Thread pools address two different problems: they usually provide + # > improved performance when executing large numbers of asynchronous tasks, + # > due to reduced per-task invocation overhead, and they provide a means + # > of bounding and managing the resources, including threads, consumed + # > when executing a collection of tasks. Each ThreadPoolExecutor also + # > maintains some basic statistics, such as the number of completed tasks. + # > + # > To be useful across a wide range of contexts, this class provides many + # > adjustable parameters and extensibility hooks. However, programmers are + # > urged to use the more convenient Executors factory methods + # > [CachedThreadPool] (unbounded thread pool, with automatic thread reclamation), + # > [FixedThreadPool] (fixed size thread pool) and [SingleThreadExecutor] (single + # > background thread), that preconfigure settings for the most common usage + # > scenarios. + # + # @!macro thread_pool_options + # + # @!macro thread_pool_executor_public_api + class ThreadPoolExecutor < ThreadPoolExecutorImplementation + + # @!macro thread_pool_executor_method_initialize + # + # Create a new thread pool. + # + # @param [Hash] opts the options which configure the thread pool. + # + # @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum + # number of threads to be created + # @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) When a new task is submitted + # and fewer than `min_threads` are running, a new thread is created + # @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum + # number of seconds a thread may be idle before being reclaimed + # @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum + # number of tasks allowed in the work queue at any one time; a value of + # zero means the queue may grow without bound + # @option opts [Symbol] :fallback_policy (:abort) the policy for handling new + # tasks that are received when the queue size has reached + # `max_queue` or the executor has shut down + # @option opts [Boolean] :synchronous (DEFAULT_SYNCHRONOUS) whether or not a value of 0 + # for :max_queue means the queue must perform direct hand-off rather than unbounded. + # @raise [ArgumentError] if `:max_threads` is less than one + # @raise [ArgumentError] if `:min_threads` is less than zero + # @raise [ArgumentError] if `:fallback_policy` is not one of the values specified + # in `FALLBACK_POLICIES` + # + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html + + # @!method initialize(opts = {}) + # @!macro thread_pool_executor_method_initialize + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/timer_set.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/timer_set.rb new file mode 100644 index 00000000..b936c7b2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executor/timer_set.rb @@ -0,0 +1,179 @@ +require 'concurrent/scheduled_task' +require 'concurrent/atomic/event' +require 'concurrent/collection/non_concurrent_priority_queue' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/single_thread_executor' +require 'concurrent/errors' +require 'concurrent/options' + +module Concurrent + + # Executes a collection of tasks, each after a given delay. A master task + # monitors the set and schedules each task for execution at the appropriate + # time. Tasks are run on the global thread pool or on the supplied executor. + # Each task is represented as a `ScheduledTask`. + # + # @see Concurrent::ScheduledTask + # + # @!macro monotonic_clock_warning + class TimerSet < RubyExecutorService + + # Create a new set of timed tasks. + # + # @!macro executor_options + # + # @param [Hash] opts the options used to specify the executor on which to perform actions + # @option opts [Executor] :executor when set use the given `Executor` instance. + # Three special values are also supported: `:task` returns the global task pool, + # `:operation` returns the global operation pool, and `:immediate` returns a new + # `ImmediateExecutor` object. + def initialize(opts = {}) + super(opts) + end + + # Post a task to be execute run after a given delay (in seconds). If the + # delay is less than 1/100th of a second the task will be immediately post + # to the executor. + # + # @param [Float] delay the number of seconds to wait for before executing the task. + # @param [Array] args the arguments passed to the task on execution. + # + # @yield the task to be performed. + # + # @return [Concurrent::ScheduledTask, false] IVar representing the task if the post + # is successful; false after shutdown. + # + # @raise [ArgumentError] if the intended execution time is not in the future. + # @raise [ArgumentError] if no block is given. + def post(delay, *args, &task) + raise ArgumentError.new('no block given') unless block_given? + return false unless running? + opts = { executor: @task_executor, + args: args, + timer_set: self } + task = ScheduledTask.execute(delay, opts, &task) # may raise exception + task.unscheduled? ? false : task + end + + # Begin an immediate shutdown. In-progress tasks will be allowed to + # complete but enqueued tasks will be dismissed and no new tasks + # will be accepted. Has no additional effect if the thread pool is + # not running. + def kill + shutdown + @timer_executor.kill + end + + private :<< + + private + + # Initialize the object. + # + # @param [Hash] opts the options to create the object with. + # @!visibility private + def ns_initialize(opts) + @queue = Collection::NonConcurrentPriorityQueue.new(order: :min) + @task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @timer_executor = SingleThreadExecutor.new + @condition = Event.new + @ruby_pid = $$ # detects if Ruby has forked + end + + # Post the task to the internal queue. + # + # @note This is intended as a callback method from ScheduledTask + # only. It is not intended to be used directly. Post a task + # by using the `SchedulesTask#execute` method. + # + # @!visibility private + def post_task(task) + synchronize { ns_post_task(task) } + end + + # @!visibility private + def ns_post_task(task) + return false unless ns_running? + ns_reset_if_forked + if (task.initial_delay) <= 0.01 + task.executor.post { task.process_task } + else + @queue.push(task) + # only post the process method when the queue is empty + @timer_executor.post(&method(:process_tasks)) if @queue.length == 1 + @condition.set + end + true + end + + # Remove the given task from the queue. + # + # @note This is intended as a callback method from `ScheduledTask` + # only. It is not intended to be used directly. Cancel a task + # by using the `ScheduledTask#cancel` method. + # + # @!visibility private + def remove_task(task) + synchronize { @queue.delete(task) } + end + + # `ExecutorService` callback called during shutdown. + # + # @!visibility private + def ns_shutdown_execution + ns_reset_if_forked + @queue.clear + @condition.set + @condition.reset + @timer_executor.shutdown + stopped_event.set + end + + def ns_reset_if_forked + if $$ != @ruby_pid + @queue.clear + @condition.reset + @ruby_pid = $$ + end + end + + # Run a loop and execute tasks in the scheduled order and at the approximate + # scheduled time. If no tasks remain the thread will exit gracefully so that + # garbage collection can occur. If there are no ready tasks it will sleep + # for up to 60 seconds waiting for the next scheduled task. + # + # @!visibility private + def process_tasks + loop do + task = synchronize { @condition.reset; @queue.peek } + break unless task + + now = Concurrent.monotonic_time + diff = task.schedule_time - now + + if diff <= 0 + # We need to remove the task from the queue before passing + # it to the executor, to avoid race conditions where we pass + # the peek'ed task to the executor and then pop a different + # one that's been added in the meantime. + # + # Note that there's no race condition between the peek and + # this pop - this pop could retrieve a different task from + # the peek, but that task would be due to fire now anyway + # (because @queue is a priority queue, and this thread is + # the only reader, so whatever timer is at the head of the + # queue now must have the same pop time, or a closer one, as + # when we peeked). + task = synchronize { @queue.pop } + begin + task.executor.post { task.process_task } + rescue RejectedExecutionError + # ignore and continue + end + else + @condition.wait([diff, 60].min) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executors.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executors.rb new file mode 100644 index 00000000..5d5cd391 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/executors.rb @@ -0,0 +1,19 @@ +require 'concurrent/executor/abstract_executor_service' +require 'concurrent/executor/cached_thread_pool' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/fixed_thread_pool' +require 'concurrent/executor/immediate_executor' +require 'concurrent/executor/indirect_immediate_executor' +require 'concurrent/executor/java_executor_service' +require 'concurrent/executor/java_single_thread_executor' +require 'concurrent/executor/java_thread_pool_executor' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/executor/ruby_single_thread_executor' +require 'concurrent/executor/ruby_thread_pool_executor' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/executor/serial_executor_service' +require 'concurrent/executor/serialized_execution' +require 'concurrent/executor/serialized_execution_delegator' +require 'concurrent/executor/single_thread_executor' +require 'concurrent/executor/thread_pool_executor' +require 'concurrent/executor/timer_set' diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/future.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/future.rb new file mode 100644 index 00000000..1af182ec --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/future.rb @@ -0,0 +1,141 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/ivar' +require 'concurrent/executor/safe_task_executor' + +require 'concurrent/options' + +# TODO (pitr-ch 14-Mar-2017): deprecate, Future, Promise, etc. + + +module Concurrent + + # {include:file:docs-source/future.md} + # + # @!macro copy_options + # + # @see http://ruby-doc.org/stdlib-2.1.1/libdoc/observer/rdoc/Observable.html Ruby Observable module + # @see http://clojuredocs.org/clojure_core/clojure.core/future Clojure's future function + # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html java.util.concurrent.Future + class Future < IVar + + # Create a new `Future` in the `:unscheduled` state. + # + # @yield the asynchronous operation to perform + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] if no block is given + def initialize(opts = {}, &block) + raise ArgumentError.new('no block given') unless block_given? + super(NULL, opts.merge(__task_from_block__: block), &nil) + end + + # Execute an `:unscheduled` `Future`. Immediately sets the state to `:pending` and + # passes the block to a new thread/thread pool for eventual execution. + # Does nothing if the `Future` is in any state other than `:unscheduled`. + # + # @return [Future] a reference to `self` + # + # @example Instance and execute in separate steps + # future = Concurrent::Future.new{ sleep(1); 42 } + # future.state #=> :unscheduled + # future.execute + # future.state #=> :pending + # + # @example Instance and execute in one line + # future = Concurrent::Future.new{ sleep(1); 42 }.execute + # future.state #=> :pending + def execute + if compare_and_set_state(:pending, :unscheduled) + @executor.post{ safe_execute(@task, @args) } + self + end + end + + # Create a new `Future` object with the given block, execute it, and return the + # `:pending` object. + # + # @yield the asynchronous operation to perform + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] if no block is given + # + # @return [Future] the newly created `Future` in the `:pending` state + # + # @example + # future = Concurrent::Future.execute{ sleep(1); 42 } + # future.state #=> :pending + def self.execute(opts = {}, &block) + Future.new(opts, &block).execute + end + + # @!macro ivar_set_method + def set(value = NULL, &block) + check_for_block_or_value!(block_given?, value) + synchronize do + if @state != :unscheduled + raise MultipleAssignmentError + else + @task = block || Proc.new { value } + end + end + execute + end + + # Attempt to cancel the operation if it has not already processed. + # The operation can only be cancelled while still `pending`. It cannot + # be cancelled once it has begun processing or has completed. + # + # @return [Boolean] was the operation successfully cancelled. + def cancel + if compare_and_set_state(:cancelled, :pending) + complete(false, nil, CancelledOperationError.new) + true + else + false + end + end + + # Has the operation been successfully cancelled? + # + # @return [Boolean] + def cancelled? + state == :cancelled + end + + # Wait the given number of seconds for the operation to complete. + # On timeout attempt to cancel the operation. + # + # @param [Numeric] timeout the maximum time in seconds to wait. + # @return [Boolean] true if the operation completed before the timeout + # else false + def wait_or_cancel(timeout) + wait(timeout) + if complete? + true + else + cancel + false + end + end + + protected + + def ns_initialize(value, opts) + super + @state = :unscheduled + @task = opts[:__task_from_block__] + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @args = get_arguments_from(opts) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/hash.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/hash.rb new file mode 100644 index 00000000..db0208e0 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/hash.rb @@ -0,0 +1,52 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!macro concurrent_hash + # + # A thread-safe subclass of Hash. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`, + # which takes the lock repeatedly when reading an item. + # + # @see http://ruby-doc.org/core/Hash.html Ruby standard library `Hash` + + # @!macro internal_implementation_note + HashImplementation = case + when Concurrent.on_cruby? + # Hash is not fully thread-safe on CRuby, see + # https://bugs.ruby-lang.org/issues/19237 + # https://github.com/ruby/ruby/commit/ffd52412ab + # https://github.com/ruby-concurrency/concurrent-ruby/issues/929 + # So we will need to add synchronization here (similar to Concurrent::Map). + ::Hash + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubyHash < ::Hash + include JRuby::Synchronized + end + JRubyHash + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubyHash < ::Hash + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubyHash + TruffleRubyHash + + else + warn 'Possibly unsupported Ruby implementation' + ::Hash + end + private_constant :HashImplementation + + # @!macro concurrent_hash + class Hash < HashImplementation + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/immutable_struct.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/immutable_struct.rb new file mode 100644 index 00000000..48462e83 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/immutable_struct.rb @@ -0,0 +1,101 @@ +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # A thread-safe, immutable variation of Ruby's standard `Struct`. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + module ImmutableStruct + include Synchronization::AbstractStruct + + def self.included(base) + base.safe_initialization! + end + + # @!macro struct_values + def values + ns_values + end + + alias_method :to_a, :values + + # @!macro struct_values_at + def values_at(*indexes) + ns_values_at(indexes) + end + + # @!macro struct_inspect + def inspect + ns_inspect + end + + alias_method :to_s, :inspect + + # @!macro struct_merge + def merge(other, &block) + ns_merge(other, &block) + end + + # @!macro struct_to_h + def to_h + ns_to_h + end + + # @!macro struct_get + def [](member) + ns_get(member) + end + + # @!macro struct_equality + def ==(other) + ns_equality(other) + end + + # @!macro struct_each + def each(&block) + return enum_for(:each) unless block_given? + ns_each(&block) + end + + # @!macro struct_each_pair + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + ns_each_pair(&block) + end + + # @!macro struct_select + def select(&block) + return enum_for(:select) unless block_given? + ns_select(&block) + end + + private + + # @!visibility private + def initialize_copy(original) + super(original) + ns_initialize_copy + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + Synchronization::AbstractStruct.define_struct_class(ImmutableStruct, Synchronization::Object, name, members, &block) + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/ivar.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/ivar.rb new file mode 100644 index 00000000..4165038f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/ivar.rb @@ -0,0 +1,208 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/collection/copy_on_write_observer_set' +require 'concurrent/concern/obligation' +require 'concurrent/concern/observable' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An `IVar` is like a future that you can assign. As a future is a value that + # is being computed that you can wait on, an `IVar` is a value that is waiting + # to be assigned, that you can wait on. `IVars` are single assignment and + # deterministic. + # + # Then, express futures as an asynchronous computation that assigns an `IVar`. + # The `IVar` becomes the primitive on which [futures](Future) and + # [dataflow](Dataflow) are built. + # + # An `IVar` is a single-element container that is normally created empty, and + # can only be set once. The I in `IVar` stands for immutable. Reading an + # `IVar` normally blocks until it is set. It is safe to set and read an `IVar` + # from different threads. + # + # If you want to have some parallel task set the value in an `IVar`, you want + # a `Future`. If you want to create a graph of parallel tasks all executed + # when the values they depend on are ready you want `dataflow`. `IVar` is + # generally a low-level primitive. + # + # ## Examples + # + # Create, set and get an `IVar` + # + # ```ruby + # ivar = Concurrent::IVar.new + # ivar.set 14 + # ivar.value #=> 14 + # ivar.set 2 # would now be an error + # ``` + # + # ## See Also + # + # 1. For the theory: Arvind, R. Nikhil, and K. Pingali. + # [I-Structures: Data structures for parallel computing](http://dl.acm.org/citation.cfm?id=69562). + # In Proceedings of Workshop on Graph Reduction, 1986. + # 2. For recent application: + # [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html). + class IVar < Synchronization::LockableObject + include Concern::Obligation + include Concern::Observable + + # Create a new `IVar` in the `:pending` state with the (optional) initial value. + # + # @param [Object] value the initial value + # @param [Hash] opts the options to create a message with + # @option opts [String] :dup_on_deref (false) call `#dup` before returning + # the data + # @option opts [String] :freeze_on_deref (false) call `#freeze` before + # returning the data + # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing + # the internal value and returning the value returned from the proc + def initialize(value = NULL, opts = {}, &block) + if value != NULL && block_given? + raise ArgumentError.new('provide only a value or a block') + end + super(&nil) + synchronize { ns_initialize(value, opts, &block) } + end + + # Add an observer on this object that will receive notification on update. + # + # Upon completion the `IVar` will notify all observers in a thread-safe way. + # The `func` method of the observer will be called with three arguments: the + # `Time` at which the `Future` completed the asynchronous operation, the + # final `value` (or `nil` on rejection), and the final `reason` (or `nil` on + # fulfillment). + # + # @param [Object] observer the object that will be notified of changes + # @param [Symbol] func symbol naming the method to call when this + # `Observable` has changes` + def add_observer(observer = nil, func = :update, &block) + raise ArgumentError.new('cannot provide both an observer and a block') if observer && block + direct_notification = false + + if block + observer = block + func = :call + end + + synchronize do + if event.set? + direct_notification = true + else + observers.add_observer(observer, func) + end + end + + observer.send(func, Time.now, self.value, reason) if direct_notification + observer + end + + # @!macro ivar_set_method + # Set the `IVar` to a value and wake or notify all threads waiting on it. + # + # @!macro ivar_set_parameters_and_exceptions + # @param [Object] value the value to store in the `IVar` + # @yield A block operation to use for setting the value + # @raise [ArgumentError] if both a value and a block are given + # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already + # been set or otherwise completed + # + # @return [IVar] self + def set(value = NULL) + check_for_block_or_value!(block_given?, value) + raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending) + + begin + value = yield if block_given? + complete_without_notification(true, value, nil) + rescue => ex + complete_without_notification(false, nil, ex) + end + + notify_observers(self.value, reason) + self + end + + # @!macro ivar_fail_method + # Set the `IVar` to failed due to some error and wake or notify all threads waiting on it. + # + # @param [Object] reason for the failure + # @raise [Concurrent::MultipleAssignmentError] if the `IVar` has already + # been set or otherwise completed + # @return [IVar] self + def fail(reason = StandardError.new) + complete(false, nil, reason) + end + + # Attempt to set the `IVar` with the given value or block. Return a + # boolean indicating the success or failure of the set operation. + # + # @!macro ivar_set_parameters_and_exceptions + # + # @return [Boolean] true if the value was set else false + def try_set(value = NULL, &block) + set(value, &block) + true + rescue MultipleAssignmentError + false + end + + protected + + # @!visibility private + def ns_initialize(value, opts) + value = yield if block_given? + init_obligation + self.observers = Collection::CopyOnWriteObserverSet.new + set_deref_options(opts) + + @state = :pending + if value != NULL + ns_complete_without_notification(true, value, nil) + end + end + + # @!visibility private + def safe_execute(task, args = []) + if compare_and_set_state(:processing, :pending) + success, val, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) + complete(success, val, reason) + yield(success, val, reason) if block_given? + end + end + + # @!visibility private + def complete(success, value, reason) + complete_without_notification(success, value, reason) + notify_observers(self.value, reason) + self + end + + # @!visibility private + def complete_without_notification(success, value, reason) + synchronize { ns_complete_without_notification(success, value, reason) } + self + end + + # @!visibility private + def notify_observers(value, reason) + observers.notify_and_delete_observers{ [Time.now, value, reason] } + end + + # @!visibility private + def ns_complete_without_notification(success, value, reason) + raise MultipleAssignmentError if [:fulfilled, :rejected].include? @state + set_state(success, value, reason) + event.set + end + + # @!visibility private + def check_for_block_or_value!(block_given, value) # :nodoc: + if (block_given && value != NULL) || (! block_given && value == NULL) + raise ArgumentError.new('must set with either a value or a block') + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/map.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/map.rb new file mode 100644 index 00000000..b263f83d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/map.rb @@ -0,0 +1,350 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/utility/engine' + +module Concurrent + # @!visibility private + module Collection + + # @!visibility private + MapImplementation = case + when Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + # noinspection RubyResolve + JRubyMapBackend + when Concurrent.on_cruby? + require 'concurrent/collection/map/mri_map_backend' + MriMapBackend + when Concurrent.on_truffleruby? + if defined?(::TruffleRuby::ConcurrentMap) + require 'concurrent/collection/map/truffleruby_map_backend' + TruffleRubyMapBackend + else + require 'concurrent/collection/map/synchronized_map_backend' + SynchronizedMapBackend + end + else + warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' + require 'concurrent/collection/map/synchronized_map_backend' + SynchronizedMapBackend + end + end + + # `Concurrent::Map` is a hash-like object and should have much better performance + # characteristics, especially under high concurrency, than `Concurrent::Hash`. + # However, `Concurrent::Map `is not strictly semantically equivalent to a ruby `Hash` + # -- for instance, it does not necessarily retain ordering by insertion time as `Hash` + # does. For most uses it should do fine though, and we recommend you consider + # `Concurrent::Map` instead of `Concurrent::Hash` for your concurrency-safe hash needs. + class Map < Collection::MapImplementation + + # @!macro map.atomic_method + # This method is atomic. + + # @!macro map.atomic_method_with_block + # This method is atomic. + # @note Atomic methods taking a block do not allow the `self` instance + # to be used within the block. Doing so will cause a deadlock. + + # @!method []=(key, value) + # Set a value with key + # @param [Object] key + # @param [Object] value + # @return [Object] the new value + + # @!method compute_if_absent(key) + # Compute and store new value for key if the key is absent. + # @param [Object] key + # @yield new value + # @yieldreturn [Object] new value + # @return [Object] new value or current value + # @!macro map.atomic_method_with_block + + # @!method compute_if_present(key) + # Compute and store new value for key if the key is present. + # @param [Object] key + # @yield new value + # @yieldparam old_value [Object] + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method compute(key) + # Compute and store new value for key. + # @param [Object] key + # @yield compute new value from old one + # @yieldparam old_value [Object, nil] old_value, or nil when key is absent + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method merge_pair(key, value) + # If the key is absent, the value is stored, otherwise new value is + # computed with a block. + # @param [Object] key + # @param [Object] value + # @yield compute new value from old one + # @yieldparam old_value [Object] old value + # @yieldreturn [Object, nil] new value, when nil the key is removed + # @return [Object, nil] new value or nil + # @!macro map.atomic_method_with_block + + # @!method replace_pair(key, old_value, new_value) + # Replaces old_value with new_value if key exists and current value + # matches old_value + # @param [Object] key + # @param [Object] old_value + # @param [Object] new_value + # @return [true, false] true if replaced + # @!macro map.atomic_method + + # @!method replace_if_exists(key, new_value) + # Replaces current value with new_value if key exists + # @param [Object] key + # @param [Object] new_value + # @return [Object, nil] old value or nil + # @!macro map.atomic_method + + # @!method get_and_set(key, value) + # Get the current value under key and set new value. + # @param [Object] key + # @param [Object] value + # @return [Object, nil] old value or nil when the key was absent + # @!macro map.atomic_method + + # @!method delete(key) + # Delete key and its value. + # @param [Object] key + # @return [Object, nil] old value or nil when the key was absent + # @!macro map.atomic_method + + # @!method delete_pair(key, value) + # Delete pair and its value if current value equals the provided value. + # @param [Object] key + # @param [Object] value + # @return [true, false] true if deleted + # @!macro map.atomic_method + + # NonConcurrentMapBackend handles default_proc natively + unless defined?(Collection::NonConcurrentMapBackend) and self < Collection::NonConcurrentMapBackend + + # @param [Hash, nil] options options to set the :initial_capacity or :load_factor. Ignored on some Rubies. + # @param [Proc] default_proc Optional block to compute the default value if the key is not set, like `Hash#default_proc` + def initialize(options = nil, &default_proc) + if options.kind_of?(::Hash) + validate_options_hash!(options) + else + options = nil + end + + super(options) + @default_proc = default_proc + end + + # Get a value with key + # @param [Object] key + # @return [Object] the value + def [](key) + if value = super # non-falsy value is an existing mapping, return it right away + value + # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call + # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrect +nil+ value + # would be returned) + # note: nil == value check is not technically necessary + elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL)) + @default_proc.call(self, key) + else + value + end + end + end + + alias_method :get, :[] + alias_method :put, :[]= + + # Get a value with key, or default_value when key is absent, + # or fail when no default_value is given. + # @param [Object] key + # @param [Object] default_value + # @yield default value for a key + # @yieldparam key [Object] + # @yieldreturn [Object] default value + # @return [Object] the value or default value + # @raise [KeyError] when key is missing and no default_value is provided + # @!macro map_method_not_atomic + # @note The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended + # to be use as a concurrency primitive with strong happens-before + # guarantees. It is not intended to be used as a high-level abstraction + # supporting complex operations. All read and write operations are + # thread safe, but no guarantees are made regarding race conditions + # between the fetch operation and yielding to the block. Additionally, + # this method does not support recursion. This is due to internal + # constraints that are very unlikely to change in the near future. + def fetch(key, default_value = NULL) + if NULL != (value = get_or_default(key, NULL)) + value + elsif block_given? + yield key + elsif NULL != default_value + default_value + else + raise_fetch_no_key + end + end + + # Fetch value with key, or store default value when key is absent, + # or fail when no default_value is given. This is a two step operation, + # therefore not atomic. The store can overwrite other concurrently + # stored value. + # @param [Object] key + # @param [Object] default_value + # @yield default value for a key + # @yieldparam key [Object] + # @yieldreturn [Object] default value + # @return [Object] the value or default value + def fetch_or_store(key, default_value = NULL) + fetch(key) do + put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value)) + end + end + + # Insert value into map with key if key is absent in one atomic step. + # @param [Object] key + # @param [Object] value + # @return [Object, nil] the previous value when key was present or nil when there was no key + def put_if_absent(key, value) + computed = false + result = compute_if_absent(key) do + computed = true + value + end + computed ? nil : result + end unless method_defined?(:put_if_absent) + + # Is the value stored in the map. Iterates over all values. + # @param [Object] value + # @return [true, false] + def value?(value) + each_value do |v| + return true if value.equal?(v) + end + false + end + + # All keys + # @return [::Array] keys + def keys + arr = [] + each_pair { |k, v| arr << k } + arr + end unless method_defined?(:keys) + + # All values + # @return [::Array] values + def values + arr = [] + each_pair { |k, v| arr << v } + arr + end unless method_defined?(:values) + + # Iterates over each key. + # @yield for each key in the map + # @yieldparam key [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_key + each_pair { |k, v| yield k } + end unless method_defined?(:each_key) + + # Iterates over each value. + # @yield for each value in the map + # @yieldparam value [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_value + each_pair { |k, v| yield v } + end unless method_defined?(:each_value) + + # Iterates over each key value pair. + # @yield for each key value pair in the map + # @yieldparam key [Object] + # @yieldparam value [Object] + # @return [self] + # @!macro map.atomic_method_with_block + def each_pair + return enum_for :each_pair unless block_given? + super + end + + alias_method :each, :each_pair unless method_defined?(:each) + + # Find key of a value. + # @param [Object] value + # @return [Object, nil] key or nil when not found + def key(value) + each_pair { |k, v| return k if v == value } + nil + end unless method_defined?(:key) + + # Is map empty? + # @return [true, false] + def empty? + each_pair { |k, v| return false } + true + end unless method_defined?(:empty?) + + # The size of map. + # @return [Integer] size + def size + count = 0 + each_pair { |k, v| count += 1 } + count + end unless method_defined?(:size) + + # @!visibility private + def marshal_dump + raise TypeError, "can't dump hash with default proc" if @default_proc + h = {} + each_pair { |k, v| h[k] = v } + h + end + + # @!visibility private + def marshal_load(hash) + initialize + populate_from(hash) + end + + undef :freeze + + # @!visibility private + def inspect + format '%s entries=%d default_proc=%s>', to_s[0..-2], size.to_s, @default_proc.inspect + end + + private + + def raise_fetch_no_key + raise KeyError, 'key not found' + end + + def initialize_copy(other) + super + populate_from(other) + end + + def populate_from(hash) + hash.each_pair { |k, v| self[k] = v } + self + end + + def validate_options_hash!(options) + if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0) + raise ArgumentError, ":initial_capacity must be a positive Integer" + end + if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1) + raise ArgumentError, ":load_factor must be a number between 0 and 1" + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/maybe.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/maybe.rb new file mode 100644 index 00000000..317c82b8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/maybe.rb @@ -0,0 +1,229 @@ +require 'concurrent/synchronization/object' + +module Concurrent + + # A `Maybe` encapsulates an optional value. A `Maybe` either contains a value + # of (represented as `Just`), or it is empty (represented as `Nothing`). Using + # `Maybe` is a good way to deal with errors or exceptional cases without + # resorting to drastic measures such as exceptions. + # + # `Maybe` is a replacement for the use of `nil` with better type checking. + # + # For compatibility with {Concurrent::Concern::Obligation} the predicate and + # accessor methods are aliased as `fulfilled?`, `rejected?`, `value`, and + # `reason`. + # + # ## Motivation + # + # A common pattern in languages with pattern matching, such as Erlang and + # Haskell, is to return *either* a value *or* an error from a function + # Consider this Erlang code: + # + # ```erlang + # case file:consult("data.dat") of + # {ok, Terms} -> do_something_useful(Terms); + # {error, Reason} -> lager:error(Reason) + # end. + # ``` + # + # In this example the standard library function `file:consult` returns a + # [tuple](http://erlang.org/doc/reference_manual/data_types.html#id69044) + # with two elements: an [atom](http://erlang.org/doc/reference_manual/data_types.html#id64134) + # (similar to a ruby symbol) and a variable containing ancillary data. On + # success it returns the atom `ok` and the data from the file. On failure it + # returns `error` and a string with an explanation of the problem. With this + # pattern there is no ambiguity regarding success or failure. If the file is + # empty the return value cannot be misinterpreted as an error. And when an + # error occurs the return value provides useful information. + # + # In Ruby we tend to return `nil` when an error occurs or else we raise an + # exception. Both of these idioms are problematic. Returning `nil` is + # ambiguous because `nil` may also be a valid value. It also lacks + # information pertaining to the nature of the error. Raising an exception + # is both expensive and usurps the normal flow of control. All of these + # problems can be solved with the use of a `Maybe`. + # + # A `Maybe` is unambiguous with regard to whether or not it contains a value. + # When `Just` it contains a value, when `Nothing` it does not. When `Just` + # the value it contains may be `nil`, which is perfectly valid. When + # `Nothing` the reason for the lack of a value is contained as well. The + # previous Erlang example can be duplicated in Ruby in a principled way by + # having functions return `Maybe` objects: + # + # ```ruby + # result = MyFileUtils.consult("data.dat") # returns a Maybe + # if result.just? + # do_something_useful(result.value) # or result.just + # else + # logger.error(result.reason) # or result.nothing + # end + # ``` + # + # @example Returning a Maybe from a Function + # module MyFileUtils + # def self.consult(path) + # file = File.open(path, 'r') + # Concurrent::Maybe.just(file.read) + # rescue => ex + # return Concurrent::Maybe.nothing(ex) + # ensure + # file.close if file + # end + # end + # + # maybe = MyFileUtils.consult('bogus.file') + # maybe.just? #=> false + # maybe.nothing? #=> true + # maybe.reason #=> # + # + # maybe = MyFileUtils.consult('README.md') + # maybe.just? #=> true + # maybe.nothing? #=> false + # maybe.value #=> "# Concurrent Ruby\n[![Gem Version..." + # + # @example Using Maybe with a Block + # result = Concurrent::Maybe.from do + # Client.find(10) # Client is an ActiveRecord model + # end + # + # # -- if the record was found + # result.just? #=> true + # result.value #=> # + # + # # -- if the record was not found + # result.just? #=> false + # result.reason #=> ActiveRecord::RecordNotFound + # + # @example Using Maybe with the Null Object Pattern + # # In a Rails controller... + # result = ClientService.new(10).find # returns a Maybe + # render json: result.or(NullClient.new) + # + # @see https://hackage.haskell.org/package/base-4.2.0.1/docs/Data-Maybe.html Haskell Data.Maybe + # @see https://github.com/purescript/purescript-maybe/blob/master/docs/Data.Maybe.md PureScript Data.Maybe + class Maybe < Synchronization::Object + include Comparable + safe_initialization! + + # Indicates that the given attribute has not been set. + # When `Just` the {#nothing} getter will return `NONE`. + # When `Nothing` the {#just} getter will return `NONE`. + NONE = ::Object.new.freeze + + # The value of a `Maybe` when `Just`. Will be `NONE` when `Nothing`. + attr_reader :just + + # The reason for the `Maybe` when `Nothing`. Will be `NONE` when `Just`. + attr_reader :nothing + + private_class_method :new + + # Create a new `Maybe` using the given block. + # + # Runs the given block passing all function arguments to the block as block + # arguments. If the block runs to completion without raising an exception + # a new `Just` is created with the value set to the return value of the + # block. If the block raises an exception a new `Nothing` is created with + # the reason being set to the raised exception. + # + # @param [Array] args Zero or more arguments to pass to the block. + # @yield The block from which to create a new `Maybe`. + # @yieldparam [Array] args Zero or more block arguments passed as + # arguments to the function. + # + # @return [Maybe] The newly created object. + # + # @raise [ArgumentError] when no block given. + def self.from(*args) + raise ArgumentError.new('no block given') unless block_given? + begin + value = yield(*args) + return new(value, NONE) + rescue => ex + return new(NONE, ex) + end + end + + # Create a new `Just` with the given value. + # + # @param [Object] value The value to set for the new `Maybe` object. + # + # @return [Maybe] The newly created object. + def self.just(value) + return new(value, NONE) + end + + # Create a new `Nothing` with the given (optional) reason. + # + # @param [Exception] error The reason to set for the new `Maybe` object. + # When given a string a new `StandardError` will be created with the + # argument as the message. When no argument is given a new + # `StandardError` with an empty message will be created. + # + # @return [Maybe] The newly created object. + def self.nothing(error = '') + if error.is_a?(Exception) + nothing = error + else + nothing = StandardError.new(error.to_s) + end + return new(NONE, nothing) + end + + # Is this `Maybe` a `Just` (successfully fulfilled with a value)? + # + # @return [Boolean] True if `Just` or false if `Nothing`. + def just? + ! nothing? + end + alias :fulfilled? :just? + + # Is this `Maybe` a `nothing` (rejected with an exception upon fulfillment)? + # + # @return [Boolean] True if `Nothing` or false if `Just`. + def nothing? + @nothing != NONE + end + alias :rejected? :nothing? + + alias :value :just + + alias :reason :nothing + + # Comparison operator. + # + # @return [Integer] 0 if self and other are both `Nothing`; + # -1 if self is `Nothing` and other is `Just`; + # 1 if self is `Just` and other is nothing; + # `self.just <=> other.just` if both self and other are `Just`. + def <=>(other) + if nothing? + other.nothing? ? 0 : -1 + else + other.nothing? ? 1 : just <=> other.just + end + end + + # Return either the value of self or the given default value. + # + # @return [Object] The value of self when `Just`; else the given default. + def or(other) + just? ? just : other + end + + private + + # Create a new `Maybe` with the given attributes. + # + # @param [Object] just The value when `Just` else `NONE`. + # @param [Exception, Object] nothing The exception when `Nothing` else `NONE`. + # + # @return [Maybe] The new `Maybe`. + # + # @!visibility private + def initialize(just, nothing) + @just = just + @nothing = nothing + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mutable_struct.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mutable_struct.rb new file mode 100644 index 00000000..5d0e9b9a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mutable_struct.rb @@ -0,0 +1,239 @@ +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An thread-safe variation of Ruby's standard `Struct`. Values can be set at + # construction or safely changed at any time during the object's lifecycle. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + module MutableStruct + include Synchronization::AbstractStruct + + # @!macro struct_new + # + # Factory for creating new struct classes. + # + # ``` + # new([class_name] [, member_name]+>) -> StructClass click to toggle source + # new([class_name] [, member_name]+>) {|StructClass| block } -> StructClass + # new(value, ...) -> obj + # StructClass[value, ...] -> obj + # ``` + # + # The first two forms are used to create a new struct subclass `class_name` + # that can contain a value for each member_name . This subclass can be + # used to create instances of the structure like any other Class . + # + # If the `class_name` is omitted an anonymous struct class will be created. + # Otherwise, the name of this struct will appear as a constant in the struct class, + # so it must be unique for all structs under this base class and must start with a + # capital letter. Assigning a struct class to a constant also gives the class + # the name of the constant. + # + # If a block is given it will be evaluated in the context of `StructClass`, passing + # the created class as a parameter. This is the recommended way to customize a struct. + # Subclassing an anonymous struct creates an extra anonymous class that will never be used. + # + # The last two forms create a new instance of a struct subclass. The number of value + # parameters must be less than or equal to the number of attributes defined for the + # struct. Unset parameters default to nil. Passing more parameters than number of attributes + # will raise an `ArgumentError`. + # + # @see http://ruby-doc.org/core/Struct.html#method-c-new Ruby standard library `Struct#new` + + # @!macro struct_values + # + # Returns the values for this struct as an Array. + # + # @return [Array] the values for this struct + # + def values + synchronize { ns_values } + end + alias_method :to_a, :values + + # @!macro struct_values_at + # + # Returns the struct member values for each selector as an Array. + # + # A selector may be either an Integer offset or a Range of offsets (as in `Array#values_at`). + # + # @param [Fixnum, Range] indexes the index(es) from which to obatin the values (in order) + def values_at(*indexes) + synchronize { ns_values_at(indexes) } + end + + # @!macro struct_inspect + # + # Describe the contents of this struct in a string. + # + # @return [String] the contents of this struct in a string + def inspect + synchronize { ns_inspect } + end + alias_method :to_s, :inspect + + # @!macro struct_merge + # + # Returns a new struct containing the contents of `other` and the contents + # of `self`. If no block is specified, the value for entries with duplicate + # keys will be that of `other`. Otherwise the value for each duplicate key + # is determined by calling the block with the key, its value in `self` and + # its value in `other`. + # + # @param [Hash] other the hash from which to set the new values + # @yield an options block for resolving duplicate keys + # @yieldparam [String, Symbol] member the name of the member which is duplicated + # @yieldparam [Object] selfvalue the value of the member in `self` + # @yieldparam [Object] othervalue the value of the member in `other` + # + # @return [Synchronization::AbstractStruct] a new struct with the new values + # + # @raise [ArgumentError] of given a member that is not defined in the struct + def merge(other, &block) + synchronize { ns_merge(other, &block) } + end + + # @!macro struct_to_h + # + # Returns a hash containing the names and values for the struct’s members. + # + # @return [Hash] the names and values for the struct’s members + def to_h + synchronize { ns_to_h } + end + + # @!macro struct_get + # + # Attribute Reference + # + # @param [Symbol, String, Integer] member the string or symbol name of the member + # for which to obtain the value or the member's index + # + # @return [Object] the value of the given struct member or the member at the given index. + # + # @raise [NameError] if the member does not exist + # @raise [IndexError] if the index is out of range. + def [](member) + synchronize { ns_get(member) } + end + + # @!macro struct_equality + # + # Equality + # + # @return [Boolean] true if other has the same struct subclass and has + # equal member values (according to `Object#==`) + def ==(other) + synchronize { ns_equality(other) } + end + + # @!macro struct_each + # + # Yields the value of each struct member in order. If no block is given + # an enumerator is returned. + # + # @yield the operation to be performed on each struct member + # @yieldparam [Object] value each struct value (in order) + def each(&block) + return enum_for(:each) unless block_given? + synchronize { ns_each(&block) } + end + + # @!macro struct_each_pair + # + # Yields the name and value of each struct member in order. If no block is + # given an enumerator is returned. + # + # @yield the operation to be performed on each struct member/value pair + # @yieldparam [Object] member each struct member (in order) + # @yieldparam [Object] value each struct value (in order) + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + synchronize { ns_each_pair(&block) } + end + + # @!macro struct_select + # + # Yields each member value from the struct to the block and returns an Array + # containing the member values from the struct for which the given block + # returns a true value (equivalent to `Enumerable#select`). + # + # @yield the operation to be performed on each struct member + # @yieldparam [Object] value each struct value (in order) + # + # @return [Array] an array containing each value for which the block returns true + def select(&block) + return enum_for(:select) unless block_given? + synchronize { ns_select(&block) } + end + + # @!macro struct_set + # + # Attribute Assignment + # + # Sets the value of the given struct member or the member at the given index. + # + # @param [Symbol, String, Integer] member the string or symbol name of the member + # for which to obtain the value or the member's index + # + # @return [Object] the value of the given struct member or the member at the given index. + # + # @raise [NameError] if the name does not exist + # @raise [IndexError] if the index is out of range. + def []=(member, value) + if member.is_a? Integer + length = synchronize { @values.length } + if member >= length + raise IndexError.new("offset #{member} too large for struct(size:#{length})") + end + synchronize { @values[member] = value } + else + send("#{member}=", value) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + private + + # @!visibility private + def initialize_copy(original) + synchronize do + super(original) + ns_initialize_copy + end + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + clazz = Synchronization::AbstractStruct.define_struct_class(MutableStruct, Synchronization::LockableObject, name, members, &block) + members.each_with_index do |member, index| + clazz.send :remove_method, member + clazz.send(:define_method, member) do + synchronize { @values[index] } + end + clazz.send(:define_method, "#{member}=") do |value| + synchronize { @values[index] = value } + end + end + clazz + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mvar.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mvar.rb new file mode 100644 index 00000000..9777ba34 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/mvar.rb @@ -0,0 +1,242 @@ +require 'concurrent/concern/dereferenceable' +require 'concurrent/synchronization/object' + +module Concurrent + + # An `MVar` is a synchronized single element container. They are empty or + # contain one item. Taking a value from an empty `MVar` blocks, as does + # putting a value into a full one. You can either think of them as blocking + # queue of length one, or a special kind of mutable variable. + # + # On top of the fundamental `#put` and `#take` operations, we also provide a + # `#modify` that is atomic with respect to operations on the same instance. + # These operations all support timeouts. + # + # We also support non-blocking operations `#try_put!` and `#try_take!`, a + # `#set!` that ignores existing values, a `#value` that returns the value + # without removing it or returns `MVar::EMPTY`, and a `#modify!` that yields + # `MVar::EMPTY` if the `MVar` is empty and can be used to set `MVar::EMPTY`. + # You shouldn't use these operations in the first instance. + # + # `MVar` is a [Dereferenceable](Dereferenceable). + # + # `MVar` is related to M-structures in Id, `MVar` in Haskell and `SyncVar` in Scala. + # + # Note that unlike the original Haskell paper, our `#take` is blocking. This is how + # Haskell and Scala do it today. + # + # @!macro copy_options + # + # ## See Also + # + # 1. P. Barth, R. Nikhil, and Arvind. [M-Structures: Extending a parallel, non- strict, functional language with state](http://dl.acm.org/citation.cfm?id=652538). In Proceedings of the 5th + # ACM Conference on Functional Programming Languages and Computer Architecture (FPCA), 1991. + # + # 2. S. Peyton Jones, A. Gordon, and S. Finne. [Concurrent Haskell](http://dl.acm.org/citation.cfm?id=237794). + # In Proceedings of the 23rd Symposium on Principles of Programming Languages + # (PoPL), 1996. + class MVar < Synchronization::Object + include Concern::Dereferenceable + safe_initialization! + + # Unique value that represents that an `MVar` was empty + EMPTY = ::Object.new + + # Unique value that represents that an `MVar` timed out before it was able + # to produce a value. + TIMEOUT = ::Object.new + + # Create a new `MVar`, either empty or with an initial value. + # + # @param [Hash] opts the options controlling how the future will be processed + # + # @!macro deref_options + def initialize(value = EMPTY, opts = {}) + @value = value + @mutex = Mutex.new + @empty_condition = ConditionVariable.new + @full_condition = ConditionVariable.new + set_deref_options(opts) + end + + # Remove the value from an `MVar`, leaving it empty, and blocking if there + # isn't a value. A timeout can be set to limit the time spent blocked, in + # which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value that was taken, or `TIMEOUT` + def take(timeout = nil) + @mutex.synchronize do + wait_for_full(timeout) + + # If we timed out we'll still be empty + if unlocked_full? + value = @value + @value = EMPTY + @empty_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # acquires lock on the from an `MVAR`, yields the value to provided block, + # and release lock. A timeout can be set to limit the time spent blocked, + # in which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value returned by the block, or `TIMEOUT` + def borrow(timeout = nil) + @mutex.synchronize do + wait_for_full(timeout) + + # If we timed out we'll still be empty + if unlocked_full? + yield @value + else + TIMEOUT + end + end + end + + # Put a value into an `MVar`, blocking if there is already a value until + # it is empty. A timeout can be set to limit the time spent blocked, in + # which case it returns `TIMEOUT` if the time is exceeded. + # @return [Object] the value that was put, or `TIMEOUT` + def put(value, timeout = nil) + @mutex.synchronize do + wait_for_empty(timeout) + + # If we timed out we won't be empty + if unlocked_empty? + @value = value + @full_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # Atomically `take`, yield the value to a block for transformation, and then + # `put` the transformed value. Returns the pre-transform value. A timeout can + # be set to limit the time spent blocked, in which case it returns `TIMEOUT` + # if the time is exceeded. + # @return [Object] the pre-transform value, or `TIMEOUT` + def modify(timeout = nil) + raise ArgumentError.new('no block given') unless block_given? + + @mutex.synchronize do + wait_for_full(timeout) + + # If we timed out we'll still be empty + if unlocked_full? + value = @value + @value = yield value + @full_condition.signal + apply_deref_options(value) + else + TIMEOUT + end + end + end + + # Non-blocking version of `take`, that returns `EMPTY` instead of blocking. + def try_take! + @mutex.synchronize do + if unlocked_full? + value = @value + @value = EMPTY + @empty_condition.signal + apply_deref_options(value) + else + EMPTY + end + end + end + + # Non-blocking version of `put`, that returns whether or not it was successful. + def try_put!(value) + @mutex.synchronize do + if unlocked_empty? + @value = value + @full_condition.signal + true + else + false + end + end + end + + # Non-blocking version of `put` that will overwrite an existing value. + def set!(value) + @mutex.synchronize do + old_value = @value + @value = value + @full_condition.signal + apply_deref_options(old_value) + end + end + + # Non-blocking version of `modify` that will yield with `EMPTY` if there is no value yet. + def modify! + raise ArgumentError.new('no block given') unless block_given? + + @mutex.synchronize do + value = @value + @value = yield value + if unlocked_empty? + @empty_condition.signal + else + @full_condition.signal + end + apply_deref_options(value) + end + end + + # Returns if the `MVar` is currently empty. + def empty? + @mutex.synchronize { @value == EMPTY } + end + + # Returns if the `MVar` currently contains a value. + def full? + !empty? + end + + protected + + def synchronize(&block) + @mutex.synchronize(&block) + end + + private + + def unlocked_empty? + @value == EMPTY + end + + def unlocked_full? + ! unlocked_empty? + end + + def wait_for_full(timeout) + wait_while(@full_condition, timeout) { unlocked_empty? } + end + + def wait_for_empty(timeout) + wait_while(@empty_condition, timeout) { unlocked_full? } + end + + def wait_while(condition, timeout) + if timeout.nil? + while yield + condition.wait(@mutex) + end + else + stop = Concurrent.monotonic_time + timeout + while yield && timeout > 0.0 + condition.wait(@mutex, timeout) + timeout = stop - Concurrent.monotonic_time + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/options.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/options.rb new file mode 100644 index 00000000..bdd22a9d --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/options.rb @@ -0,0 +1,42 @@ +require 'concurrent/configuration' + +module Concurrent + + # @!visibility private + module Options + + # Get the requested `Executor` based on the values set in the options hash. + # + # @param [Hash] opts the options defining the requested executor + # @option opts [Executor] :executor when set use the given `Executor` instance. + # Three special values are also supported: `:fast` returns the global fast executor, + # `:io` returns the global io executor, and `:immediate` returns a new + # `ImmediateExecutor` object. + # + # @return [Executor, nil] the requested thread pool, or nil when no option specified + # + # @!visibility private + def self.executor_from_options(opts = {}) # :nodoc: + if identifier = opts.fetch(:executor, nil) + executor(identifier) + else + nil + end + end + + def self.executor(executor_identifier) + case executor_identifier + when :fast + Concurrent.global_fast_executor + when :io + Concurrent.global_io_executor + when :immediate + Concurrent.global_immediate_executor + when Concurrent::ExecutorService + executor_identifier + else + raise ArgumentError, "executor not recognized by '#{executor_identifier}'" + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promise.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promise.rb new file mode 100644 index 00000000..8df80b0c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promise.rb @@ -0,0 +1,580 @@ +require 'thread' +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/ivar' +require 'concurrent/executor/safe_task_executor' + +require 'concurrent/options' + +module Concurrent + + PromiseExecutionError = Class.new(StandardError) + + # Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) + # and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications. + # + # > A promise represents the eventual value returned from the single + # > completion of an operation. + # + # Promises are similar to futures and share many of the same behaviours. + # Promises are far more robust, however. Promises can be chained in a tree + # structure where each promise may have zero or more children. Promises are + # chained using the `then` method. The result of a call to `then` is always + # another promise. Promises are resolved asynchronously (with respect to the + # main thread) but in a strict order: parents are guaranteed to be resolved + # before their children, children before their younger siblings. The `then` + # method takes two parameters: an optional block to be executed upon parent + # resolution and an optional callable to be executed upon parent failure. The + # result of each promise is passed to each of its children upon resolution. + # When a promise is rejected all its children will be summarily rejected and + # will receive the reason. + # + # Promises have several possible states: *:unscheduled*, *:pending*, + # *:processing*, *:rejected*, or *:fulfilled*. These are also aggregated as + # `#incomplete?` and `#complete?`. When a Promise is created it is set to + # *:unscheduled*. Once the `#execute` method is called the state becomes + # *:pending*. Once a job is pulled from the thread pool's queue and is given + # to a thread for processing (often immediately upon `#post`) the state + # becomes *:processing*. The future will remain in this state until processing + # is complete. A future that is in the *:unscheduled*, *:pending*, or + # *:processing* is considered `#incomplete?`. A `#complete?` Promise is either + # *:rejected*, indicating that an exception was thrown during processing, or + # *:fulfilled*, indicating success. If a Promise is *:fulfilled* its `#value` + # will be updated to reflect the result of the operation. If *:rejected* the + # `reason` will be updated with a reference to the thrown exception. The + # predicate methods `#unscheduled?`, `#pending?`, `#rejected?`, and + # `#fulfilled?` can be called at any time to obtain the state of the Promise, + # as can the `#state` method, which returns a symbol. + # + # Retrieving the value of a promise is done through the `value` (alias: + # `deref`) method. Obtaining the value of a promise is a potentially blocking + # operation. When a promise is *rejected* a call to `value` will return `nil` + # immediately. When a promise is *fulfilled* a call to `value` will + # immediately return the current value. When a promise is *pending* a call to + # `value` will block until the promise is either *rejected* or *fulfilled*. A + # *timeout* value can be passed to `value` to limit how long the call will + # block. If `nil` the call will block indefinitely. If `0` the call will not + # block. Any other integer or float value will indicate the maximum number of + # seconds to block. + # + # Promises run on the global thread pool. + # + # @!macro copy_options + # + # ### Examples + # + # Start by requiring promises + # + # ```ruby + # require 'concurrent/promise' + # ``` + # + # Then create one + # + # ```ruby + # p = Concurrent::Promise.execute do + # # do something + # 42 + # end + # ``` + # + # Promises can be chained using the `then` method. The `then` method accepts a + # block and an executor, to be executed on fulfillment, and a callable argument to be executed + # on rejection. The result of the each promise is passed as the block argument + # to chained promises. + # + # ```ruby + # p = Concurrent::Promise.new{10}.then{|x| x * 2}.then{|result| result - 10 }.execute + # ``` + # + # And so on, and so on, and so on... + # + # ```ruby + # p = Concurrent::Promise.fulfill(20). + # then{|result| result - 10 }. + # then{|result| result * 3 }. + # then(executor: different_executor){|result| result % 5 }.execute + # ``` + # + # The initial state of a newly created Promise depends on the state of its parent: + # - if parent is *unscheduled* the child will be *unscheduled* + # - if parent is *pending* the child will be *pending* + # - if parent is *fulfilled* the child will be *pending* + # - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*) + # + # Promises are executed asynchronously from the main thread. By the time a + # child Promise finishes initialization it may be in a different state than its + # parent (by the time a child is created its parent may have completed + # execution and changed state). Despite being asynchronous, however, the order + # of execution of Promise objects in a chain (or tree) is strictly defined. + # + # There are multiple ways to create and execute a new `Promise`. Both ways + # provide identical behavior: + # + # ```ruby + # # create, operate, then execute + # p1 = Concurrent::Promise.new{ "Hello World!" } + # p1.state #=> :unscheduled + # p1.execute + # + # # create and immediately execute + # p2 = Concurrent::Promise.new{ "Hello World!" }.execute + # + # # execute during creation + # p3 = Concurrent::Promise.execute{ "Hello World!" } + # ``` + # + # Once the `execute` method is called a `Promise` becomes `pending`: + # + # ```ruby + # p = Concurrent::Promise.execute{ "Hello, world!" } + # p.state #=> :pending + # p.pending? #=> true + # ``` + # + # Wait a little bit, and the promise will resolve and provide a value: + # + # ```ruby + # p = Concurrent::Promise.execute{ "Hello, world!" } + # sleep(0.1) + # + # p.state #=> :fulfilled + # p.fulfilled? #=> true + # p.value #=> "Hello, world!" + # ``` + # + # If an exception occurs, the promise will be rejected and will provide + # a reason for the rejection: + # + # ```ruby + # p = Concurrent::Promise.execute{ raise StandardError.new("Here comes the Boom!") } + # sleep(0.1) + # + # p.state #=> :rejected + # p.rejected? #=> true + # p.reason #=> "#" + # ``` + # + # #### Rejection + # + # When a promise is rejected all its children will be rejected and will + # receive the rejection `reason` as the rejection callable parameter: + # + # ```ruby + # p = Concurrent::Promise.execute { Thread.pass; raise StandardError } + # + # c1 = p.then(-> reason { 42 }) + # c2 = p.then(-> reason { raise 'Boom!' }) + # + # c1.wait.state #=> :fulfilled + # c1.value #=> 42 + # c2.wait.state #=> :rejected + # c2.reason #=> # + # ``` + # + # Once a promise is rejected it will continue to accept children that will + # receive immediately rejection (they will be executed asynchronously). + # + # #### Aliases + # + # The `then` method is the most generic alias: it accepts a block to be + # executed upon parent fulfillment and a callable to be executed upon parent + # rejection. At least one of them should be passed. The default block is `{ + # |result| result }` that fulfills the child with the parent value. The + # default callable is `{ |reason| raise reason }` that rejects the child with + # the parent reason. + # + # - `on_success { |result| ... }` is the same as `then {|result| ... }` + # - `rescue { |reason| ... }` is the same as `then(Proc.new { |reason| ... } )` + # - `rescue` is aliased by `catch` and `on_error` + class Promise < IVar + + # Initialize a new Promise with the provided options. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @option opts [Promise] :parent the parent `Promise` when building a chain/tree + # @option opts [Proc] :on_fulfill fulfillment handler + # @option opts [Proc] :on_reject rejection handler + # @option opts [object, Array] :args zero or more arguments to be passed + # the task block on execution + # + # @yield The block operation to be performed asynchronously. + # + # @raise [ArgumentError] if no block is given + # + # @see http://wiki.commonjs.org/wiki/Promises/A + # @see http://promises-aplus.github.io/promises-spec/ + def initialize(opts = {}, &block) + opts.delete_if { |k, v| v.nil? } + super(NULL, opts.merge(__promise_body_from_block__: block), &nil) + end + + # Create a new `Promise` and fulfill it immediately. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @raise [ArgumentError] if no block is given + # + # @return [Promise] the newly created `Promise` + def self.fulfill(value, opts = {}) + Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, true, value, nil) } + end + + # Create a new `Promise` and reject it immediately. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @raise [ArgumentError] if no block is given + # + # @return [Promise] the newly created `Promise` + def self.reject(reason, opts = {}) + Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, false, nil, reason) } + end + + # Execute an `:unscheduled` `Promise`. Immediately sets the state to `:pending` and + # passes the block to a new thread/thread pool for eventual execution. + # Does nothing if the `Promise` is in any state other than `:unscheduled`. + # + # @return [Promise] a reference to `self` + def execute + if root? + if compare_and_set_state(:pending, :unscheduled) + set_pending + realize(@promise_body) + end + else + compare_and_set_state(:pending, :unscheduled) + @parent.execute + end + self + end + + # @!macro ivar_set_method + # + # @raise [Concurrent::PromiseExecutionError] if not the root promise + def set(value = NULL, &block) + raise PromiseExecutionError.new('supported only on root promise') unless root? + check_for_block_or_value!(block_given?, value) + synchronize do + if @state != :unscheduled + raise MultipleAssignmentError + else + @promise_body = block || Proc.new { |result| value } + end + end + execute + end + + # @!macro ivar_fail_method + # + # @raise [Concurrent::PromiseExecutionError] if not the root promise + def fail(reason = StandardError.new) + set { raise reason } + end + + # Create a new `Promise` object with the given block, execute it, and return the + # `:pending` object. + # + # @!macro executor_and_deref_options + # + # @!macro promise_init_options + # + # @return [Promise] the newly created `Promise` in the `:pending` state + # + # @raise [ArgumentError] if no block is given + # + # @example + # promise = Concurrent::Promise.execute{ sleep(1); 42 } + # promise.state #=> :pending + def self.execute(opts = {}, &block) + new(opts, &block).execute + end + + # Chain a new promise off the current promise. + # + # @return [Promise] the new promise + # @yield The block operation to be performed asynchronously. + # @overload then(rescuer, executor, &block) + # @param [Proc] rescuer An optional rescue block to be executed if the + # promise is rejected. + # @param [ThreadPool] executor An optional thread pool executor to be used + # in the new Promise + # @overload then(rescuer, executor: executor, &block) + # @param [Proc] rescuer An optional rescue block to be executed if the + # promise is rejected. + # @param [ThreadPool] executor An optional thread pool executor to be used + # in the new Promise + def then(*args, &block) + if args.last.is_a?(::Hash) + executor = args.pop[:executor] + rescuer = args.first + else + rescuer, executor = args + end + + executor ||= @executor + + raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given? + block = Proc.new { |result| result } unless block_given? + child = Promise.new( + parent: self, + executor: executor, + on_fulfill: block, + on_reject: rescuer + ) + + synchronize do + child.state = :pending if @state == :pending + child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled + child.on_reject(@reason) if @state == :rejected + @children << child + end + + child + end + + # Chain onto this promise an action to be undertaken on success + # (fulfillment). + # + # @yield The block to execute + # + # @return [Promise] self + def on_success(&block) + raise ArgumentError.new('no block given') unless block_given? + self.then(&block) + end + + # Chain onto this promise an action to be undertaken on failure + # (rejection). + # + # @yield The block to execute + # + # @return [Promise] self + def rescue(&block) + self.then(block) + end + + alias_method :catch, :rescue + alias_method :on_error, :rescue + + # Yield the successful result to the block that returns a promise. If that + # promise is also successful the result is the result of the yielded promise. + # If either part fails the whole also fails. + # + # @example + # Promise.execute { 1 }.flat_map { |v| Promise.execute { v + 2 } }.value! #=> 3 + # + # @return [Promise] + def flat_map(&block) + child = Promise.new( + parent: self, + executor: ImmediateExecutor.new, + ) + + on_error { |e| child.on_reject(e) } + on_success do |result1| + begin + inner = block.call(result1) + inner.execute + inner.on_success { |result2| child.on_fulfill(result2) } + inner.on_error { |e| child.on_reject(e) } + rescue => e + child.on_reject(e) + end + end + + child + end + + # Builds a promise that produces the result of promises in an Array + # and fails if any of them fails. + # + # @overload zip(*promises) + # @param [Array] promises + # + # @overload zip(*promises, opts) + # @param [Array] promises + # @param [Hash] opts the configuration options + # @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance. + # @option opts [Boolean] :execute (true) execute promise before returning + # + # @return [Promise] + def self.zip(*promises) + opts = promises.last.is_a?(::Hash) ? promises.pop.dup : {} + opts[:executor] ||= ImmediateExecutor.new + zero = if !opts.key?(:execute) || opts.delete(:execute) + fulfill([], opts) + else + Promise.new(opts) { [] } + end + + promises.reduce(zero) do |p1, p2| + p1.flat_map do |results| + p2.then do |next_result| + results << next_result + end + end + end + end + + # Builds a promise that produces the result of self and others in an Array + # and fails if any of them fails. + # + # @overload zip(*promises) + # @param [Array] others + # + # @overload zip(*promises, opts) + # @param [Array] others + # @param [Hash] opts the configuration options + # @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance. + # @option opts [Boolean] :execute (true) execute promise before returning + # + # @return [Promise] + def zip(*others) + self.class.zip(self, *others) + end + + # Aggregates a collection of promises and executes the `then` condition + # if all aggregated promises succeed. Executes the `rescue` handler with + # a `Concurrent::PromiseExecutionError` if any of the aggregated promises + # fail. Upon execution will execute any of the aggregate promises that + # were not already executed. + # + # @!macro promise_self_aggregate + # + # The returned promise will not yet have been executed. Additional `#then` + # and `#rescue` handlers may still be provided. Once the returned promise + # is execute the aggregate promises will be also be executed (if they have + # not been executed already). The results of the aggregate promises will + # be checked upon completion. The necessary `#then` and `#rescue` blocks + # on the aggregating promise will then be executed as appropriate. If the + # `#rescue` handlers are executed the raises exception will be + # `Concurrent::PromiseExecutionError`. + # + # @param [Array] promises Zero or more promises to aggregate + # @return [Promise] an unscheduled (not executed) promise that aggregates + # the promises given as arguments + def self.all?(*promises) + aggregate(:all?, *promises) + end + + # Aggregates a collection of promises and executes the `then` condition + # if any aggregated promises succeed. Executes the `rescue` handler with + # a `Concurrent::PromiseExecutionError` if any of the aggregated promises + # fail. Upon execution will execute any of the aggregate promises that + # were not already executed. + # + # @!macro promise_self_aggregate + def self.any?(*promises) + aggregate(:any?, *promises) + end + + protected + + def ns_initialize(value, opts) + super + + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + @args = get_arguments_from(opts) + + @parent = opts.fetch(:parent) { nil } + @on_fulfill = opts.fetch(:on_fulfill) { Proc.new { |result| result } } + @on_reject = opts.fetch(:on_reject) { Proc.new { |reason| raise reason } } + + @promise_body = opts[:__promise_body_from_block__] || Proc.new { |result| result } + @state = :unscheduled + @children = [] + end + + # Aggregate a collection of zero or more promises under a composite promise, + # execute the aggregated promises and collect them into a standard Ruby array, + # call the given Ruby `Ennnumerable` predicate (such as `any?`, `all?`, `none?`, + # or `one?`) on the collection checking for the success or failure of each, + # then executing the composite's `#then` handlers if the predicate returns + # `true` or executing the composite's `#rescue` handlers if the predicate + # returns false. + # + # @!macro promise_self_aggregate + def self.aggregate(method, *promises) + composite = Promise.new do + completed = promises.collect do |promise| + promise.execute if promise.unscheduled? + promise.wait + promise + end + unless completed.empty? || completed.send(method){|promise| promise.fulfilled? } + raise PromiseExecutionError + end + end + composite + end + + # @!visibility private + def set_pending + synchronize do + @state = :pending + @children.each { |c| c.set_pending } + end + end + + # @!visibility private + def root? # :nodoc: + @parent.nil? + end + + # @!visibility private + def on_fulfill(result) + realize Proc.new { @on_fulfill.call(result) } + nil + end + + # @!visibility private + def on_reject(reason) + realize Proc.new { @on_reject.call(reason) } + nil + end + + # @!visibility private + def notify_child(child) + if_state(:fulfilled) { child.on_fulfill(apply_deref_options(@value)) } + if_state(:rejected) { child.on_reject(@reason) } + end + + # @!visibility private + def complete(success, value, reason) + children_to_notify = synchronize do + set_state!(success, value, reason) + @children.dup + end + + children_to_notify.each { |child| notify_child(child) } + observers.notify_and_delete_observers{ [Time.now, self.value, reason] } + end + + # @!visibility private + def realize(task) + @executor.post do + success, value, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args) + complete(success, value, reason) + end + end + + # @!visibility private + def set_state!(success, value, reason) + set_state(success, value, reason) + event.set + end + + # @!visibility private + def synchronized_set_state!(success, value, reason) + synchronize { set_state!(success, value, reason) } + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promises.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promises.rb new file mode 100644 index 00000000..baad27d7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/promises.rb @@ -0,0 +1,2184 @@ +require 'concurrent/synchronization/object' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/collection/lock_free_stack' +require 'concurrent/configuration' +require 'concurrent/errors' +require 'concurrent/re_include' +require 'concurrent/utility/monotonic_time' + +module Concurrent + + # {include:file:docs-source/promises-main.md} + module Promises + + # @!macro promises.param.default_executor + # @param [Executor, :io, :fast] default_executor Instance of an executor or a name of the + # global executor. Default executor propagates to chained futures unless overridden with + # executor parameter or changed with {AbstractEventFuture#with_default_executor}. + # + # @!macro promises.param.executor + # @param [Executor, :io, :fast] executor Instance of an executor or a name of the + # global executor. The task is executed on it, default executor remains unchanged. + # + # @!macro promises.param.args + # @param [Object] args arguments which are passed to the task when it's executed. + # (It might be prepended with other arguments, see the @yield section). + # + # @!macro promises.shortcut.on + # Shortcut of {#$0_on} with default `:io` executor supplied. + # @see #$0_on + # + # @!macro promises.shortcut.using + # Shortcut of {#$0_using} with default `:io` executor supplied. + # @see #$0_using + # + # @!macro promise.param.task-future + # @yieldreturn will become result of the returned Future. + # Its returned value becomes {Future#value} fulfilling it, + # raised exception becomes {Future#reason} rejecting it. + # + # @!macro promise.param.callback + # @yieldreturn is forgotten. + + # Container of all {Future}, {Event} factory methods. They are never constructed directly with + # new. + module FactoryMethods + extend ReInclude + extend self + + module Configuration + # @return [Executor, :io, :fast] the executor which is used when none is supplied + # to a factory method. The method can be overridden in the receivers of + # `include FactoryMethod` + def default_executor + :io + end + end + + include Configuration + + # @!macro promises.shortcut.on + # @return [ResolvableEvent] + def resolvable_event + resolvable_event_on default_executor + end + + # Creates a resolvable event, user is responsible for resolving the event once + # by calling {Promises::ResolvableEvent#resolve}. + # + # @!macro promises.param.default_executor + # @return [ResolvableEvent] + def resolvable_event_on(default_executor = self.default_executor) + ResolvableEventPromise.new(default_executor).future + end + + # @!macro promises.shortcut.on + # @return [ResolvableFuture] + def resolvable_future + resolvable_future_on default_executor + end + + # Creates resolvable future, user is responsible for resolving the future once by + # {Promises::ResolvableFuture#resolve}, {Promises::ResolvableFuture#fulfill}, + # or {Promises::ResolvableFuture#reject} + # + # @!macro promises.param.default_executor + # @return [ResolvableFuture] + def resolvable_future_on(default_executor = self.default_executor) + ResolvableFuturePromise.new(default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def future(*args, &task) + future_on(default_executor, *args, &task) + end + + # Constructs a new Future which will be resolved after block is evaluated on default executor. + # Evaluation begins immediately. + # + # @!macro promises.param.default_executor + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + def future_on(default_executor, *args, &task) + ImmediateEventPromise.new(default_executor).future.then(*args, &task) + end + + # Creates a resolved future with will be either fulfilled with the given value or rejected with + # the given reason. + # + # @param [true, false] fulfilled + # @param [Object] value + # @param [Object] reason + # @!macro promises.param.default_executor + # @return [Future] + def resolved_future(fulfilled, value, reason, default_executor = self.default_executor) + ImmediateFuturePromise.new(default_executor, fulfilled, value, reason).future + end + + # Creates a resolved future which will be fulfilled with the given value. + # + # @!macro promises.param.default_executor + # @param [Object] value + # @return [Future] + def fulfilled_future(value, default_executor = self.default_executor) + resolved_future true, value, nil, default_executor + end + + # Creates a resolved future which will be rejected with the given reason. + # + # @!macro promises.param.default_executor + # @param [Object] reason + # @return [Future] + def rejected_future(reason, default_executor = self.default_executor) + resolved_future false, nil, reason, default_executor + end + + # Creates resolved event. + # + # @!macro promises.param.default_executor + # @return [Event] + def resolved_event(default_executor = self.default_executor) + ImmediateEventPromise.new(default_executor).event + end + + # General constructor. Behaves differently based on the argument's type. It's provided for convenience + # but it's better to be explicit. + # + # @see rejected_future, resolved_event, fulfilled_future + # @!macro promises.param.default_executor + # @return [Event, Future] + # + # @overload make_future(nil, default_executor = self.default_executor) + # @param [nil] nil + # @return [Event] resolved event. + # + # @overload make_future(a_future, default_executor = self.default_executor) + # @param [Future] a_future + # @return [Future] a future which will be resolved when a_future is. + # + # @overload make_future(an_event, default_executor = self.default_executor) + # @param [Event] an_event + # @return [Event] an event which will be resolved when an_event is. + # + # @overload make_future(exception, default_executor = self.default_executor) + # @param [Exception] exception + # @return [Future] a rejected future with the exception as its reason. + # + # @overload make_future(value, default_executor = self.default_executor) + # @param [Object] value when none of the above overloads fits + # @return [Future] a fulfilled future with the value. + def make_future(argument = nil, default_executor = self.default_executor) + case argument + when AbstractEventFuture + # returning wrapper would change nothing + argument + when Exception + rejected_future argument, default_executor + when nil + resolved_event default_executor + else + fulfilled_future argument, default_executor + end + end + + # @!macro promises.shortcut.on + # @return [Future, Event] + def delay(*args, &task) + delay_on default_executor, *args, &task + end + + # Creates a new event or future which is resolved only after it is touched, + # see {Concurrent::AbstractEventFuture#touch}. + # + # @!macro promises.param.default_executor + # @overload delay_on(default_executor, *args, &task) + # If task is provided it returns a {Future} representing the result of the task. + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + # @overload delay_on(default_executor) + # If no task is provided, it returns an {Event} + # @return [Event] + def delay_on(default_executor, *args, &task) + event = DelayPromise.new(default_executor).event + task ? event.chain(*args, &task) : event + end + + # @!macro promises.shortcut.on + # @return [Future, Event] + def schedule(intended_time, *args, &task) + schedule_on default_executor, intended_time, *args, &task + end + + # Creates a new event or future which is resolved in intended_time. + # + # @!macro promises.param.default_executor + # @!macro promises.param.intended_time + # @param [Numeric, Time] intended_time `Numeric` means to run in `intended_time` seconds. + # `Time` means to run on `intended_time`. + # @overload schedule_on(default_executor, intended_time, *args, &task) + # If task is provided it returns a {Future} representing the result of the task. + # @!macro promises.param.args + # @yield [*args] to the task. + # @!macro promise.param.task-future + # @return [Future] + # @overload schedule_on(default_executor, intended_time) + # If no task is provided, it returns an {Event} + # @return [Event] + def schedule_on(default_executor, intended_time, *args, &task) + event = ScheduledPromise.new(default_executor, intended_time).event + task ? event.chain(*args, &task) : event + end + + # @!macro promises.shortcut.on + # @return [Future] + def zip_futures(*futures_and_or_events) + zip_futures_on default_executor, *futures_and_or_events + end + + # Creates a new future which is resolved after all futures_and_or_events are resolved. + # Its value is an array of zipped future values. Its reason is an array of reasons for rejection. + # If there is an error it rejects. + # @!macro promises.event-conversion + # If event is supplied, which does not have value and can be only resolved, it's + # represented as `:fulfilled` with value `nil`. + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def zip_futures_on(default_executor, *futures_and_or_events) + ZipFuturesPromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + alias_method :zip, :zip_futures + + # @!macro promises.shortcut.on + # @return [Event] + def zip_events(*futures_and_or_events) + zip_events_on default_executor, *futures_and_or_events + end + + # Creates a new event which is resolved after all futures_and_or_events are resolved. + # (Future is resolved when fulfilled or rejected.) + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Event] + def zip_events_on(default_executor, *futures_and_or_events) + ZipEventsPromise.new_blocked_by(futures_and_or_events, default_executor).event + end + + # @!macro promises.shortcut.on + # @return [Future] + def any_resolved_future(*futures_and_or_events) + any_resolved_future_on default_executor, *futures_and_or_events + end + + alias_method :any, :any_resolved_future + + # Creates a new future which is resolved after the first futures_and_or_events is resolved. + # Its result equals the result of the first resolved future. + # @!macro promises.any-touch + # If resolved it does not propagate {Concurrent::AbstractEventFuture#touch}, leaving delayed + # futures un-executed if they are not required any more. + # @!macro promises.event-conversion + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def any_resolved_future_on(default_executor, *futures_and_or_events) + AnyResolvedFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def any_fulfilled_future(*futures_and_or_events) + any_fulfilled_future_on default_executor, *futures_and_or_events + end + + # Creates a new future which is resolved after the first futures_and_or_events is fulfilled. + # Its result equals the result of the first resolved future or if all futures_and_or_events reject, + # it has reason of the last rejected future. + # @!macro promises.any-touch + # @!macro promises.event-conversion + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Future] + def any_fulfilled_future_on(default_executor, *futures_and_or_events) + AnyFulfilledFuturePromise.new_blocked_by(futures_and_or_events, default_executor).future + end + + # @!macro promises.shortcut.on + # @return [Event] + def any_event(*futures_and_or_events) + any_event_on default_executor, *futures_and_or_events + end + + # Creates a new event which becomes resolved after the first futures_and_or_events resolves. + # @!macro promises.any-touch + # + # @!macro promises.param.default_executor + # @param [AbstractEventFuture] futures_and_or_events + # @return [Event] + def any_event_on(default_executor, *futures_and_or_events) + AnyResolvedEventPromise.new_blocked_by(futures_and_or_events, default_executor).event + end + + # TODO consider adding first(count, *futures) + # TODO consider adding zip_by(slice, *futures) processing futures in slices + # TODO or rather a generic aggregator taking a function + end + + module InternalStates + # @!visibility private + class State + def resolved? + raise NotImplementedError + end + + def to_sym + raise NotImplementedError + end + end + + # @!visibility private + class Pending < State + def resolved? + false + end + + def to_sym + :pending + end + end + + # @!visibility private + class Reserved < Pending + end + + # @!visibility private + class ResolvedWithResult < State + def resolved? + true + end + + def to_sym + :resolved + end + + def result + [fulfilled?, value, reason] + end + + def fulfilled? + raise NotImplementedError + end + + def value + raise NotImplementedError + end + + def reason + raise NotImplementedError + end + + def apply + raise NotImplementedError + end + end + + # @!visibility private + class Fulfilled < ResolvedWithResult + + def initialize(value) + @Value = value + end + + def fulfilled? + true + end + + def apply(args, block) + block.call value, *args + end + + def value + @Value + end + + def reason + nil + end + + def to_sym + :fulfilled + end + end + + # @!visibility private + class FulfilledArray < Fulfilled + def apply(args, block) + block.call(*value, *args) + end + end + + # @!visibility private + class Rejected < ResolvedWithResult + def initialize(reason) + @Reason = reason + end + + def fulfilled? + false + end + + def value + nil + end + + def reason + @Reason + end + + def to_sym + :rejected + end + + def apply(args, block) + block.call reason, *args + end + end + + # @!visibility private + class PartiallyRejected < ResolvedWithResult + def initialize(value, reason) + super() + @Value = value + @Reason = reason + end + + def fulfilled? + false + end + + def to_sym + :rejected + end + + def value + @Value + end + + def reason + @Reason + end + + def apply(args, block) + block.call(*reason, *args) + end + end + + # @!visibility private + PENDING = Pending.new + # @!visibility private + RESERVED = Reserved.new + # @!visibility private + RESOLVED = Fulfilled.new(nil) + + def RESOLVED.to_sym + :resolved + end + end + + private_constant :InternalStates + + # @!macro promises.shortcut.event-future + # @see Event#$0 + # @see Future#$0 + + # @!macro promises.param.timeout + # @param [Numeric] timeout the maximum time in second to wait. + + # @!macro promises.warn.blocks + # @note This function potentially blocks current thread until the Future is resolved. + # Be careful it can deadlock. Try to chain instead. + + # Common ancestor of {Event} and {Future} classes, many shared methods are defined here. + class AbstractEventFuture < Synchronization::Object + safe_initialization! + attr_atomic(:internal_state) + private :internal_state=, :swap_internal_state, :compare_and_set_internal_state, :update_internal_state + # @!method internal_state + # @!visibility private + + include InternalStates + + def initialize(promise, default_executor) + super() + @Lock = Mutex.new + @Condition = ConditionVariable.new + @Promise = promise + @DefaultExecutor = default_executor + @Callbacks = LockFreeStack.new + @Waiters = AtomicFixnum.new 0 + self.internal_state = PENDING + end + + private :initialize + + # Returns its state. + # @return [Symbol] + # + # @overload an_event.state + # @return [:pending, :resolved] + # @overload a_future.state + # Both :fulfilled, :rejected implies :resolved. + # @return [:pending, :fulfilled, :rejected] + def state + internal_state.to_sym + end + + # Is it in pending state? + # @return [Boolean] + def pending? + !internal_state.resolved? + end + + # Is it in resolved state? + # @return [Boolean] + def resolved? + internal_state.resolved? + end + + # Propagates touch. Requests all the delayed futures, which it depends on, to be + # executed. This method is called by any other method requiring resolved state, like {#wait}. + # @return [self] + def touch + @Promise.touch + self + end + + # @!macro promises.touches + # Calls {Concurrent::AbstractEventFuture#touch}. + + # @!macro promises.method.wait + # Wait (block the Thread) until receiver is {#resolved?}. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.param.timeout + # @return [self, true, false] self implies timeout was not used, true implies timeout was used + # and it was resolved, false implies it was not resolved within timeout. + def wait(timeout = nil) + result = wait_until_resolved(timeout) + timeout ? result : self + end + + # Returns default executor. + # @return [Executor] default executor + # @see #with_default_executor + # @see FactoryMethods#future_on + # @see FactoryMethods#resolvable_future + # @see FactoryMethods#any_fulfilled_future_on + # @see similar + def default_executor + @DefaultExecutor + end + + # @!macro promises.shortcut.on + # @return [Future] + def chain(*args, &task) + chain_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it is resolved. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @return [Future] + # @!macro promise.param.task-future + # + # @overload an_event.chain_on(executor, *args, &task) + # @yield [*args] to the task. + # @overload a_future.chain_on(executor, *args, &task) + # @yield [fulfilled, value, reason, *args] to the task. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def chain_on(executor, *args, &task) + ChainPromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @return [String] Short string representation. + def to_s + format '%s %s>', super[0..-2], state + end + + alias_method :inspect, :to_s + + # Resolves the resolvable when receiver is resolved. + # + # @param [Resolvable] resolvable + # @return [self] + def chain_resolvable(resolvable) + on_resolution! { resolvable.resolve_with internal_state } + end + + alias_method :tangle, :chain_resolvable + + # @!macro promises.shortcut.using + # @return [self] + def on_resolution(*args, &callback) + on_resolution_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # resolved. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # + # @overload an_event.on_resolution!(*args, &callback) + # @yield [*args] to the callback. + # @overload a_future.on_resolution!(*args, &callback) + # @yield [fulfilled, value, reason, *args] to the callback. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def on_resolution!(*args, &callback) + add_callback :callback_on_resolution, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is resolved. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # + # @overload an_event.on_resolution_using(executor, *args, &callback) + # @yield [*args] to the callback. + # @overload a_future.on_resolution_using(executor, *args, &callback) + # @yield [fulfilled, value, reason, *args] to the callback. + # @yieldparam [true, false] fulfilled + # @yieldparam [Object] value + # @yieldparam [Object] reason + def on_resolution_using(executor, *args, &callback) + add_callback :async_callback_on_resolution, executor, args, callback + end + + # @!macro promises.method.with_default_executor + # Crates new object with same class with the executor set as its new default executor. + # Any futures depending on it will use the new default executor. + # @!macro promises.shortcut.event-future + # @abstract + # @return [AbstractEventFuture] + def with_default_executor(executor) + raise NotImplementedError + end + + # @!visibility private + def resolve_with(state, raise_on_reassign = true, reserved = false) + if compare_and_set_internal_state(reserved ? RESERVED : PENDING, state) + # go to synchronized block only if there were waiting threads + @Lock.synchronize { @Condition.broadcast } unless @Waiters.value == 0 + call_callbacks state + else + return rejected_resolution(raise_on_reassign, state) + end + self + end + + # For inspection. + # @!visibility private + # @return [Array] + def blocks + @Callbacks.each_with_object([]) do |(method, args), promises| + promises.push(args[0]) if method == :callback_notify_blocked + end + end + + # For inspection. + # @!visibility private + def callbacks + @Callbacks.each.to_a + end + + # For inspection. + # @!visibility private + def promise + @Promise + end + + # For inspection. + # @!visibility private + def touched? + promise.touched? + end + + # For inspection. + # @!visibility private + def waiting_threads + @Waiters.each.to_a + end + + # @!visibility private + def add_callback_notify_blocked(promise, index) + add_callback :callback_notify_blocked, promise, index + end + + # @!visibility private + def add_callback_clear_delayed_node(node) + add_callback(:callback_clear_delayed_node, node) + end + + # @!visibility private + def with_hidden_resolvable + # TODO (pitr-ch 10-Dec-2018): documentation, better name if in edge + self + end + + private + + def add_callback(method, *args) + state = internal_state + if state.resolved? + call_callback method, state, args + else + @Callbacks.push [method, args] + state = internal_state + # take back if it was resolved in the meanwhile + call_callbacks state if state.resolved? + end + self + end + + def callback_clear_delayed_node(state, node) + node.value = nil + end + + # @return [Boolean] + def wait_until_resolved(timeout) + return true if resolved? + + touch + + @Lock.synchronize do + @Waiters.increment + begin + if timeout + start = Concurrent.monotonic_time + until resolved? + break if @Condition.wait(@Lock, timeout) == nil # nil means timeout + timeout -= (Concurrent.monotonic_time - start) + break if timeout <= 0 + end + else + until resolved? + @Condition.wait(@Lock, timeout) + end + end + ensure + # JRuby may raise ConcurrencyError + @Waiters.decrement + end + end + resolved? + end + + def call_callback(method, state, args) + self.send method, state, *args + end + + def call_callbacks(state) + method, args = @Callbacks.pop + while method + call_callback method, state, args + method, args = @Callbacks.pop + end + end + + def with_async(executor, *args, &block) + Concurrent.executor(executor).post(*args, &block) + end + + def async_callback_on_resolution(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_resolution st, ar, cb + end + end + + def callback_notify_blocked(state, promise, index) + promise.on_blocker_resolution self, index + end + end + + # Represents an event which will happen in future (will be resolved). The event is either + # pending or resolved. It should be always resolved. Use {Future} to communicate rejections and + # cancellation. + class Event < AbstractEventFuture + + alias_method :then, :chain + + + # @!macro promises.method.zip + # Creates a new event or a future which will be resolved when receiver and other are. + # Returns an event if receiver and other are events, otherwise returns a future. + # If just one of the parties is Future then the result + # of the returned future is equal to the result of the supplied future. If both are futures + # then the result is as described in {FactoryMethods#zip_futures_on}. + # + # @return [Future, Event] + def zip(other) + if other.is_a?(Future) + ZipFutureEventPromise.new_blocked_by2(other, self, @DefaultExecutor).future + else + ZipEventEventPromise.new_blocked_by2(self, other, @DefaultExecutor).event + end + end + + alias_method :&, :zip + + # Creates a new event which will be resolved when the first of receiver, `event_or_future` + # resolves. + # + # @return [Event] + def any(event_or_future) + AnyResolvedEventPromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).event + end + + alias_method :|, :any + + # Creates new event dependent on receiver which will not evaluate until touched, see {#touch}. + # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. + # + # @return [Event] + def delay + event = DelayPromise.new(@DefaultExecutor).event + ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event + end + + # @!macro promise.method.schedule + # Creates new event dependent on receiver scheduled to execute on/in intended_time. + # In time is interpreted from the moment the receiver is resolved, therefore it inserts + # delay into the chain. + # + # @!macro promises.param.intended_time + # @return [Event] + def schedule(intended_time) + chain do + event = ScheduledPromise.new(@DefaultExecutor, intended_time).event + ZipEventEventPromise.new_blocked_by2(self, event, @DefaultExecutor).event + end.flat_event + end + + # Converts event to a future. The future is fulfilled when the event is resolved, the future may never fail. + # + # @return [Future] + def to_future + future = Promises.resolvable_future + ensure + chain_resolvable(future) + end + + # Returns self, since this is event + # @return [Event] + def to_event + self + end + + # @!macro promises.method.with_default_executor + # @return [Event] + def with_default_executor(executor) + EventWrapperPromise.new_blocked_by1(self, executor).event + end + + private + + def rejected_resolution(raise_on_reassign, state) + raise Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign + return false + end + + def callback_on_resolution(state, args, callback) + callback.call(*args) + end + end + + # Represents a value which will become available in future. May reject with a reason instead, + # e.g. when the tasks raises an exception. + class Future < AbstractEventFuture + SET_BACKTRACE_LOCATIONS_SUPPORTED = RUBY_VERSION >= '3.4' + + # Is it in fulfilled state? + # @return [Boolean] + def fulfilled? + state = internal_state + state.resolved? && state.fulfilled? + end + + # Is it in rejected state? + # @return [Boolean] + def rejected? + state = internal_state + state.resolved? && !state.fulfilled? + end + + # @!macro promises.warn.nil + # @note Make sure returned `nil` is not confused with timeout, no value when rejected, + # no reason when fulfilled, etc. + # Use more exact methods if needed, like {#wait}, {#value!}, {#result}, etc. + + # @!macro promises.method.value + # Return value of the future. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.warn.nil + # @!macro promises.param.timeout + # @!macro promises.param.timeout_value + # @param [Object] timeout_value a value returned by the method when it times out + # @return [Object, nil, timeout_value] the value of the Future when fulfilled, + # timeout_value on timeout, + # nil on rejection. + def value(timeout = nil, timeout_value = nil) + if wait_until_resolved timeout + internal_state.value + else + timeout_value + end + end + + # Returns reason of future's rejection. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.warn.nil + # @!macro promises.param.timeout + # @!macro promises.param.timeout_value + # @return [Object, timeout_value] the reason, or timeout_value on timeout, or nil on fulfillment. + def reason(timeout = nil, timeout_value = nil) + if wait_until_resolved timeout + internal_state.reason + else + timeout_value + end + end + + # Returns triplet fulfilled?, value, reason. + # @!macro promises.touches + # + # @!macro promises.warn.blocks + # @!macro promises.param.timeout + # @return [Array(Boolean, Object, Object), nil] triplet of fulfilled?, value, reason, or nil + # on timeout. + def result(timeout = nil) + internal_state.result if wait_until_resolved timeout + end + + # @!macro promises.method.wait + # @raise [Exception] {#reason} on rejection + def wait!(timeout = nil) + result = wait_until_resolved!(timeout) + timeout ? result : self + end + + # @!macro promises.method.value + # @return [Object, nil, timeout_value] the value of the Future when fulfilled, + # or nil on rejection, + # or timeout_value on timeout. + # @raise [Exception] {#reason} on rejection + def value!(timeout = nil, timeout_value = nil) + if wait_until_resolved! timeout + internal_state.value + else + timeout_value + end + end + + # Allows rejected Future to be risen with `raise` method. + # If the reason is not an exception `Runtime.new(reason)` is returned. + # + # @example + # raise Promises.rejected_future(StandardError.new("boom")) + # raise Promises.rejected_future("or just boom") + # @raise [Concurrent::Error] when raising not rejected future + # @return [Exception] + def exception(*args) + raise Concurrent::Error, 'it is not rejected' unless rejected? + raise ArgumentError unless args.size <= 1 + reason = Array(internal_state.reason).flatten.compact + callsites = SET_BACKTRACE_LOCATIONS_SUPPORTED ? caller_locations : caller + if reason.size > 1 + ex = Concurrent::MultipleErrors.new reason + ex.set_backtrace(callsites) + ex + else + ex = if reason[0].respond_to? :exception + reason[0].exception(*args) + else + RuntimeError.new(reason[0]).exception(*args) + end + if SET_BACKTRACE_LOCATIONS_SUPPORTED && (locations = ex.backtrace_locations) + ex.set_backtrace locations + callsites + else + ex.set_backtrace Array(ex.backtrace) + callsites.map(&:to_s) + end + ex + end + end + + # @!macro promises.shortcut.on + # @return [Future] + def then(*args, &task) + then_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it fulfills. Does not run + # the task if it rejects. It will resolve though, triggering any dependent futures. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.task-future + # @return [Future] + # @yield [value, *args] to the task. + def then_on(executor, *args, &task) + ThenPromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @!macro promises.shortcut.on + # @return [Future] + def rescue(*args, &task) + rescue_on @DefaultExecutor, *args, &task + end + + # Chains the task to be executed asynchronously on executor after it rejects. Does not run + # the task if it fulfills. It will resolve though, triggering any dependent futures. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.task-future + # @return [Future] + # @yield [reason, *args] to the task. + def rescue_on(executor, *args, &task) + RescuePromise.new_blocked_by1(self, executor, executor, args, &task).future + end + + # @!macro promises.method.zip + # @return [Future] + def zip(other) + if other.is_a?(Future) + ZipFuturesPromise.new_blocked_by2(self, other, @DefaultExecutor).future + else + ZipFutureEventPromise.new_blocked_by2(self, other, @DefaultExecutor).future + end + end + + alias_method :&, :zip + + # Creates a new event which will be resolved when the first of receiver, `event_or_future` + # resolves. Returning future will have value nil if event_or_future is event and resolves + # first. + # + # @return [Future] + def any(event_or_future) + AnyResolvedFuturePromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).future + end + + alias_method :|, :any + + # Creates new future dependent on receiver which will not evaluate until touched, see {#touch}. + # In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated. + # + # @return [Future] + def delay + event = DelayPromise.new(@DefaultExecutor).event + ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future + end + + # @!macro promise.method.schedule + # @return [Future] + def schedule(intended_time) + chain do + event = ScheduledPromise.new(@DefaultExecutor, intended_time).event + ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future + end.flat + end + + # @!macro promises.method.with_default_executor + # @return [Future] + def with_default_executor(executor) + FutureWrapperPromise.new_blocked_by1(self, executor).future + end + + # Creates new future which will have result of the future returned by receiver. If receiver + # rejects it will have its rejection. + # + # @param [Integer] level how many levels of futures should flatten + # @return [Future] + def flat_future(level = 1) + FlatFuturePromise.new_blocked_by1(self, level, @DefaultExecutor).future + end + + alias_method :flat, :flat_future + + # Creates new event which will be resolved when the returned event by receiver is. + # Be careful if the receiver rejects it will just resolve since Event does not hold reason. + # + # @return [Event] + def flat_event + FlatEventPromise.new_blocked_by1(self, @DefaultExecutor).event + end + + # @!macro promises.shortcut.using + # @return [self] + def on_fulfillment(*args, &callback) + on_fulfillment_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # fulfilled. Does nothing on rejection. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [value, *args] to the callback. + def on_fulfillment!(*args, &callback) + add_callback :callback_on_fulfillment, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is + # fulfilled. Does nothing on rejection. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [value, *args] to the callback. + def on_fulfillment_using(executor, *args, &callback) + add_callback :async_callback_on_fulfillment, executor, args, callback + end + + # @!macro promises.shortcut.using + # @return [self] + def on_rejection(*args, &callback) + on_rejection_using @DefaultExecutor, *args, &callback + end + + # Stores the callback to be executed synchronously on resolving thread after it is + # rejected. Does nothing on fulfillment. + # + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [reason, *args] to the callback. + def on_rejection!(*args, &callback) + add_callback :callback_on_rejection, args, callback + end + + # Stores the callback to be executed asynchronously on executor after it is + # rejected. Does nothing on fulfillment. + # + # @!macro promises.param.executor + # @!macro promises.param.args + # @!macro promise.param.callback + # @return [self] + # @yield [reason, *args] to the callback. + def on_rejection_using(executor, *args, &callback) + add_callback :async_callback_on_rejection, executor, args, callback + end + + # Allows to use futures as green threads. The receiver has to evaluate to a future which + # represents what should be done next. It basically flattens indefinitely until non Future + # values is returned which becomes result of the returned future. Any encountered exception + # will become reason of the returned future. + # + # @return [Future] + # @param [#call(value)] run_test + # an object which when called returns either Future to keep running with + # or nil, then the run completes with the value. + # The run_test can be used to extract the Future from deeper structure, + # or to distinguish Future which is a resulting value from a future + # which is suppose to continue running. + # @example + # body = lambda do |v| + # v += 1 + # v < 5 ? Promises.future(v, &body) : v + # end + # Promises.future(0, &body).run.value! # => 5 + def run(run_test = method(:run_test)) + RunFuturePromise.new_blocked_by1(self, @DefaultExecutor, run_test).future + end + + # @!visibility private + def apply(args, block) + internal_state.apply args, block + end + + # Converts future to event which is resolved when future is resolved by fulfillment or rejection. + # + # @return [Event] + def to_event + event = Promises.resolvable_event + ensure + chain_resolvable(event) + end + + # Returns self, since this is a future + # @return [Future] + def to_future + self + end + + # @return [String] Short string representation. + def to_s + if resolved? + format '%s with %s>', super[0..-2], (fulfilled? ? value : reason).inspect + else + super + end + end + + alias_method :inspect, :to_s + + private + + def run_test(v) + v if v.is_a?(Future) + end + + def rejected_resolution(raise_on_reassign, state) + if raise_on_reassign + if internal_state == RESERVED + raise Concurrent::MultipleAssignmentError.new( + "Future can be resolved only once. It is already reserved.") + else + raise Concurrent::MultipleAssignmentError.new( + "Future can be resolved only once. It's #{result}, trying to set #{state.result}.", + current_result: result, + new_result: state.result) + end + end + return false + end + + def wait_until_resolved!(timeout = nil) + result = wait_until_resolved(timeout) + raise self if rejected? + result + end + + def async_callback_on_fulfillment(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_fulfillment st, ar, cb + end + end + + def async_callback_on_rejection(state, executor, args, callback) + with_async(executor, state, args, callback) do |st, ar, cb| + callback_on_rejection st, ar, cb + end + end + + def callback_on_fulfillment(state, args, callback) + state.apply args, callback if state.fulfilled? + end + + def callback_on_rejection(state, args, callback) + state.apply args, callback unless state.fulfilled? + end + + def callback_on_resolution(state, args, callback) + callback.call(*state.result, *args) + end + + end + + # Marker module of Future, Event resolved manually. + module Resolvable + include InternalStates + end + + # A Event which can be resolved by user. + class ResolvableEvent < Event + include Resolvable + + # @!macro raise_on_reassign + # @raise [MultipleAssignmentError] when already resolved and raise_on_reassign is true. + + # @!macro promise.param.raise_on_reassign + # @param [Boolean] raise_on_reassign should method raise exception if already resolved + # @return [self, false] false is returned when raise_on_reassign is false and the receiver + # is already resolved. + # + + # Makes the event resolved, which triggers all dependent futures. + # + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + # @param [true, false] reserved + # Set to true if the resolvable is {#reserve}d by you, + # marks resolution of reserved resolvable events and futures explicitly. + # Advanced feature, ignore unless you use {Resolvable#reserve} from edge. + def resolve(raise_on_reassign = true, reserved = false) + resolve_with RESOLVED, raise_on_reassign, reserved + end + + # Creates new event wrapping receiver, effectively hiding the resolve method. + # + # @return [Event] + def with_hidden_resolvable + @with_hidden_resolvable ||= EventWrapperPromise.new_blocked_by1(self, @DefaultExecutor).event + end + + # Behaves as {AbstractEventFuture#wait} but has one additional optional argument + # resolve_on_timeout. + # + # @param [true, false] resolve_on_timeout + # If it times out and the argument is true it will also resolve the event. + # @return [self, true, false] + # @see AbstractEventFuture#wait + def wait(timeout = nil, resolve_on_timeout = false) + super(timeout) or if resolve_on_timeout + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + !resolve(false) + else + false + end + end + end + + # A Future which can be resolved by user. + class ResolvableFuture < Future + include Resolvable + + # Makes the future resolved with result of triplet `fulfilled?`, `value`, `reason`, + # which triggers all dependent futures. + # + # @param [true, false] fulfilled + # @param [Object] value + # @param [Object] reason + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def resolve(fulfilled = true, value = nil, reason = nil, raise_on_reassign = true, reserved = false) + resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason), raise_on_reassign, reserved) + end + + # Makes the future fulfilled with `value`, + # which triggers all dependent futures. + # + # @param [Object] value + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def fulfill(value, raise_on_reassign = true, reserved = false) + resolve_with Fulfilled.new(value), raise_on_reassign, reserved + end + + # Makes the future rejected with `reason`, + # which triggers all dependent futures. + # + # @param [Object] reason + # @!macro promise.param.raise_on_reassign + # @!macro promise.param.reserved + def reject(reason, raise_on_reassign = true, reserved = false) + resolve_with Rejected.new(reason), raise_on_reassign, reserved + end + + # Evaluates the block and sets its result as future's value fulfilling, if the block raises + # an exception the future rejects with it. + # + # @yield [*args] to the block. + # @yieldreturn [Object] value + # @return [self] + def evaluate_to(*args, &block) + promise.evaluate_to(*args, block) + end + + # Evaluates the block and sets its result as future's value fulfilling, if the block raises + # an exception the future rejects with it. + # + # @yield [*args] to the block. + # @yieldreturn [Object] value + # @return [self] + # @raise [Exception] also raise reason on rejection. + def evaluate_to!(*args, &block) + promise.evaluate_to(*args, block).wait! + end + + # @!macro promises.resolvable.resolve_on_timeout + # @param [::Array(true, Object, nil), ::Array(false, nil, Exception), nil] resolve_on_timeout + # If it times out and the argument is not nil it will also resolve the future + # to the provided resolution. + + # Behaves as {AbstractEventFuture#wait} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [self, true, false] + # @see AbstractEventFuture#wait + def wait(timeout = nil, resolve_on_timeout = nil) + super(timeout) or if resolve_on_timeout + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + !resolve(*resolve_on_timeout, false) + else + false + end + end + + # Behaves as {Future#wait!} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [self, true, false] + # @raise [Exception] {#reason} on rejection + # @see Future#wait! + def wait!(timeout = nil, resolve_on_timeout = nil) + super(timeout) or if resolve_on_timeout + if resolve(*resolve_on_timeout, false) + false + else + # if it fails to resolve it was resolved in the meantime + # so return true as if there was no timeout + raise self if rejected? + true + end + else + false + end + end + + # Behaves as {Future#value} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Object, timeout_value, nil] + # @see Future#value + def value(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.value + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + return internal_state.value + end + end + timeout_value + end + end + + # Behaves as {Future#value!} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Object, timeout_value, nil] + # @raise [Exception] {#reason} on rejection + # @see Future#value! + def value!(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved! timeout + internal_state.value + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + raise self if rejected? + return internal_state.value + end + end + timeout_value + end + end + + # Behaves as {Future#reason} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [Exception, timeout_value, nil] + # @see Future#reason + def reason(timeout = nil, timeout_value = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.reason + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + return internal_state.reason + end + end + timeout_value + end + end + + # Behaves as {Future#result} but has one additional optional argument + # resolve_on_timeout. + # + # @!macro promises.resolvable.resolve_on_timeout + # @return [::Array(Boolean, Object, Exception), nil] + # @see Future#result + def result(timeout = nil, resolve_on_timeout = nil) + if wait_until_resolved timeout + internal_state.result + else + if resolve_on_timeout + unless resolve(*resolve_on_timeout, false) + # if it fails to resolve it was resolved in the meantime + # so return value as if there was no timeout + internal_state.result + end + end + # otherwise returns nil + end + end + + # Creates new future wrapping receiver, effectively hiding the resolve method and similar. + # + # @return [Future] + def with_hidden_resolvable + @with_hidden_resolvable ||= FutureWrapperPromise.new_blocked_by1(self, @DefaultExecutor).future + end + end + + # @abstract + # @private + class AbstractPromise < Synchronization::Object + safe_initialization! + include InternalStates + + def initialize(future) + super() + @Future = future + end + + def future + @Future + end + + alias_method :event, :future + + def default_executor + future.default_executor + end + + def state + future.state + end + + def touch + end + + def to_s + format '%s %s>', super[0..-2], @Future + end + + alias_method :inspect, :to_s + + def delayed_because + nil + end + + private + + def resolve_with(new_state, raise_on_reassign = true) + @Future.resolve_with(new_state, raise_on_reassign) + end + + # @return [Future] + def evaluate_to(*args, block) + resolve_with Fulfilled.new(block.call(*args)) + rescue Exception => error + resolve_with Rejected.new(error) + raise error unless error.is_a?(StandardError) + end + end + + class ResolvableEventPromise < AbstractPromise + def initialize(default_executor) + super ResolvableEvent.new(self, default_executor) + end + end + + class ResolvableFuturePromise < AbstractPromise + def initialize(default_executor) + super ResolvableFuture.new(self, default_executor) + end + + public :evaluate_to + end + + # @abstract + class InnerPromise < AbstractPromise + end + + # @abstract + class BlockedPromise < InnerPromise + + private_class_method :new + + def self.new_blocked_by1(blocker, *args, &block) + blocker_delayed = blocker.promise.delayed_because + promise = new(blocker_delayed, 1, *args, &block) + blocker.add_callback_notify_blocked promise, 0 + promise + end + + def self.new_blocked_by2(blocker1, blocker2, *args, &block) + blocker_delayed1 = blocker1.promise.delayed_because + blocker_delayed2 = blocker2.promise.delayed_because + delayed = if blocker_delayed1 && blocker_delayed2 + # TODO (pitr-ch 23-Dec-2016): use arrays when we know it will not grow (only flat adds delay) + LockFreeStack.of2(blocker_delayed1, blocker_delayed2) + else + blocker_delayed1 || blocker_delayed2 + end + promise = new(delayed, 2, *args, &block) + blocker1.add_callback_notify_blocked promise, 0 + blocker2.add_callback_notify_blocked promise, 1 + promise + end + + def self.new_blocked_by(blockers, *args, &block) + delayed = blockers.reduce(nil) { |d, f| add_delayed d, f.promise.delayed_because } + promise = new(delayed, blockers.size, *args, &block) + blockers.each_with_index { |f, i| f.add_callback_notify_blocked promise, i } + promise + end + + def self.add_delayed(delayed1, delayed2) + if delayed1 && delayed2 + delayed1.push delayed2 + delayed1 + else + delayed1 || delayed2 + end + end + + def initialize(delayed, blockers_count, future) + super(future) + @Delayed = delayed + @Countdown = AtomicFixnum.new blockers_count + end + + def on_blocker_resolution(future, index) + countdown = process_on_blocker_resolution(future, index) + resolvable = resolvable?(countdown, future, index) + + on_resolvable(future, index) if resolvable + end + + def delayed_because + @Delayed + end + + def touch + clear_and_propagate_touch + end + + # for inspection only + def blocked_by + blocked_by = [] + ObjectSpace.each_object(AbstractEventFuture) { |o| blocked_by.push o if o.blocks.include? self } + blocked_by + end + + private + + def clear_and_propagate_touch(stack_or_element = @Delayed) + return if stack_or_element.nil? + + if stack_or_element.is_a? LockFreeStack + stack_or_element.clear_each { |element| clear_and_propagate_touch element } + else + stack_or_element.touch unless stack_or_element.nil? # if still present + end + end + + # @return [true,false] if resolvable + def resolvable?(countdown, future, index) + countdown.zero? + end + + def process_on_blocker_resolution(future, index) + @Countdown.decrement + end + + def on_resolvable(resolved_future, index) + raise NotImplementedError + end + end + + # @abstract + class BlockedTaskPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + raise ArgumentError, 'no block given' unless block_given? + super delayed, 1, Future.new(self, default_executor) + @Executor = executor + @Task = task + @Args = args + end + + def executor + @Executor + end + end + + class ThenPromise < BlockedTaskPromise + private + + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + super delayed, blockers_count, default_executor, executor, args, &task + end + + def on_resolvable(resolved_future, index) + if resolved_future.fulfilled? + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to lambda { future.apply args, task } + end + else + resolve_with resolved_future.internal_state + end + end + end + + class RescuePromise < BlockedTaskPromise + private + + def initialize(delayed, blockers_count, default_executor, executor, args, &task) + super delayed, blockers_count, default_executor, executor, args, &task + end + + def on_resolvable(resolved_future, index) + if resolved_future.rejected? + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to lambda { future.apply args, task } + end + else + resolve_with resolved_future.internal_state + end + end + end + + class ChainPromise < BlockedTaskPromise + private + + def on_resolvable(resolved_future, index) + if Future === resolved_future + Concurrent.executor(@Executor).post(resolved_future, @Args, @Task) do |future, args, task| + evaluate_to(*future.result, *args, task) + end + else + Concurrent.executor(@Executor).post(@Args, @Task) do |args, task| + evaluate_to(*args, task) + end + end + end + end + + # will be immediately resolved + class ImmediateEventPromise < InnerPromise + def initialize(default_executor) + super Event.new(self, default_executor).resolve_with(RESOLVED) + end + end + + class ImmediateFuturePromise < InnerPromise + def initialize(default_executor, fulfilled, value, reason) + super Future.new(self, default_executor). + resolve_with(fulfilled ? Fulfilled.new(value) : Rejected.new(reason)) + end + end + + class AbstractFlatPromise < BlockedPromise + + def initialize(delayed_because, blockers_count, event_or_future) + delayed = LockFreeStack.of1(self) + super(delayed, blockers_count, event_or_future) + # noinspection RubyArgCount + @Touched = AtomicBoolean.new false + @DelayedBecause = delayed_because || LockFreeStack.new + + event_or_future.add_callback_clear_delayed_node delayed.peek + end + + def touch + if @Touched.make_true + clear_and_propagate_touch @DelayedBecause + end + end + + private + + def touched? + @Touched.value + end + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state + end + + def resolvable?(countdown, future, index) + !@Future.internal_state.resolved? && super(countdown, future, index) + end + + def add_delayed_of(future) + delayed = future.promise.delayed_because + if touched? + clear_and_propagate_touch delayed + else + BlockedPromise.add_delayed @DelayedBecause, delayed + clear_and_propagate_touch @DelayedBecause if touched? + end + end + + end + + class FlatEventPromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Event.new(self, default_executor) + end + + def process_on_blocker_resolution(future, index) + countdown = super(future, index) + if countdown.nonzero? + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with RESOLVED + return countdown + end + + value = internal_state.value + case value + when AbstractEventFuture + add_delayed_of value + value.add_callback_notify_blocked self, nil + countdown + else + resolve_with RESOLVED + end + end + countdown + end + + end + + class FlatFuturePromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, levels, default_executor) + raise ArgumentError, 'levels has to be higher than 0' if levels < 1 + # flat promise may result to a future having delayed futures, therefore we have to have empty stack + # to be able to add new delayed futures + super delayed || LockFreeStack.new, 1 + levels, Future.new(self, default_executor) + end + + def process_on_blocker_resolution(future, index) + countdown = super(future, index) + if countdown.nonzero? + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with internal_state + return countdown + end + + value = internal_state.value + case value + when AbstractEventFuture + add_delayed_of value + value.add_callback_notify_blocked self, nil + countdown + else + evaluate_to(lambda { raise TypeError, "returned value #{value.inspect} is not a Future" }) + end + end + countdown + end + + end + + class RunFuturePromise < AbstractFlatPromise + + private + + def initialize(delayed, blockers_count, default_executor, run_test) + super delayed, 1, Future.new(self, default_executor) + @RunTest = run_test + end + + def process_on_blocker_resolution(future, index) + internal_state = future.internal_state + + unless internal_state.fulfilled? + resolve_with internal_state + return 0 + end + + value = internal_state.value + continuation_future = @RunTest.call value + + if continuation_future + add_delayed_of continuation_future + continuation_future.add_callback_notify_blocked self, nil + else + resolve_with internal_state + end + + 1 + end + end + + class ZipEventEventPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Event.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + class ZipFutureEventPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 2, Future.new(self, default_executor) + @result = nil + end + + private + + def process_on_blocker_resolution(future, index) + # first blocking is future, take its result + @result = future.internal_state if index == 0 + # super has to be called after above to piggyback on volatile @Countdown + super future, index + end + + def on_resolvable(resolved_future, index) + resolve_with @result + end + end + + class EventWrapperPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 1, Event.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + class FutureWrapperPromise < BlockedPromise + def initialize(delayed, blockers_count, default_executor) + super delayed, 1, Future.new(self, default_executor) + end + + private + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state + end + end + + class ZipFuturesPromise < BlockedPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super(delayed, blockers_count, Future.new(self, default_executor)) + @Resolutions = ::Array.new(blockers_count, nil) + + on_resolvable nil, nil if blockers_count == 0 + end + + def process_on_blocker_resolution(future, index) + # TODO (pitr-ch 18-Dec-2016): Can we assume that array will never break under parallel access when never re-sized? + @Resolutions[index] = future.internal_state # has to be set before countdown in super + super future, index + end + + def on_resolvable(resolved_future, index) + all_fulfilled = true + values = ::Array.new(@Resolutions.size) + reasons = ::Array.new(@Resolutions.size) + + @Resolutions.each_with_index do |internal_state, i| + fulfilled, values[i], reasons[i] = internal_state.result + all_fulfilled &&= fulfilled + end + + if all_fulfilled + resolve_with FulfilledArray.new(values) + else + resolve_with PartiallyRejected.new(values, reasons) + end + end + end + + class ZipEventsPromise < BlockedPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Event.new(self, default_executor) + + on_resolvable nil, nil if blockers_count == 0 + end + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED + end + end + + # @abstract + class AbstractAnyPromise < BlockedPromise + end + + class AnyResolvedEventPromise < AbstractAnyPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Event.new(self, default_executor) + end + + def resolvable?(countdown, future, index) + true + end + + def on_resolvable(resolved_future, index) + resolve_with RESOLVED, false + end + end + + class AnyResolvedFuturePromise < AbstractAnyPromise + + private + + def initialize(delayed, blockers_count, default_executor) + super delayed, blockers_count, Future.new(self, default_executor) + end + + def resolvable?(countdown, future, index) + true + end + + def on_resolvable(resolved_future, index) + resolve_with resolved_future.internal_state, false + end + end + + class AnyFulfilledFuturePromise < AnyResolvedFuturePromise + + private + + def resolvable?(countdown, event_or_future, index) + (event_or_future.is_a?(Event) ? event_or_future.resolved? : event_or_future.fulfilled?) || + # inlined super from BlockedPromise + countdown.zero? + end + end + + class DelayPromise < InnerPromise + + def initialize(default_executor) + event = Event.new(self, default_executor) + @Delayed = LockFreeStack.of1(self) + super event + event.add_callback_clear_delayed_node @Delayed.peek + end + + def touch + @Future.resolve_with RESOLVED + end + + def delayed_because + @Delayed + end + + end + + class ScheduledPromise < InnerPromise + def intended_time + @IntendedTime + end + + def inspect + "#{to_s[0..-2]} intended_time: #{@IntendedTime}>" + end + + private + + def initialize(default_executor, intended_time) + super Event.new(self, default_executor) + + @IntendedTime = intended_time + + in_seconds = begin + now = Time.now + schedule_time = if @IntendedTime.is_a? Time + @IntendedTime + else + now + @IntendedTime + end + [0, schedule_time.to_f - now.to_f].max + end + + Concurrent.global_timer_set.post(in_seconds) do + @Future.resolve_with RESOLVED + end + end + end + + extend FactoryMethods + + private_constant :AbstractPromise, + :ResolvableEventPromise, + :ResolvableFuturePromise, + :InnerPromise, + :BlockedPromise, + :BlockedTaskPromise, + :ThenPromise, + :RescuePromise, + :ChainPromise, + :ImmediateEventPromise, + :ImmediateFuturePromise, + :AbstractFlatPromise, + :FlatFuturePromise, + :FlatEventPromise, + :RunFuturePromise, + :ZipEventEventPromise, + :ZipFutureEventPromise, + :EventWrapperPromise, + :FutureWrapperPromise, + :ZipFuturesPromise, + :ZipEventsPromise, + :AbstractAnyPromise, + :AnyResolvedFuturePromise, + :AnyFulfilledFuturePromise, + :AnyResolvedEventPromise, + :DelayPromise, + :ScheduledPromise + + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/re_include.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/re_include.rb new file mode 100644 index 00000000..600bc6a5 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/re_include.rb @@ -0,0 +1,60 @@ +module Concurrent + + # Methods form module A included to a module B, which is already included into class C, + # will not be visible in the C class. If this module is extended to B then A's methods + # are correctly made visible to C. + # + # @example + # module A + # def a + # :a + # end + # end + # + # module B1 + # end + # + # class C1 + # include B1 + # end + # + # module B2 + # extend Concurrent::ReInclude + # end + # + # class C2 + # include B2 + # end + # + # B1.send :include, A + # B2.send :include, A + # + # C1.new.respond_to? :a # => false + # C2.new.respond_to? :a # => true + # + # @!visibility private + module ReInclude + # @!visibility private + def included(base) + (@re_include_to_bases ||= []) << [:include, base] + super(base) + end + + # @!visibility private + def extended(base) + (@re_include_to_bases ||= []) << [:extend, base] + super(base) + end + + # @!visibility private + def include(*modules) + result = super(*modules) + modules.reverse.each do |module_being_included| + (@re_include_to_bases ||= []).each do |method, mod| + mod.send method, module_being_included + end + end + result + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/scheduled_task.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/scheduled_task.rb new file mode 100644 index 00000000..efe9e193 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/scheduled_task.rb @@ -0,0 +1,331 @@ +require 'concurrent/constants' +require 'concurrent/errors' +require 'concurrent/configuration' +require 'concurrent/ivar' +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/utility/monotonic_time' + +require 'concurrent/options' + +module Concurrent + + # `ScheduledTask` is a close relative of `Concurrent::Future` but with one + # important difference: A `Future` is set to execute as soon as possible + # whereas a `ScheduledTask` is set to execute after a specified delay. This + # implementation is loosely based on Java's + # [ScheduledExecutorService](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html). + # It is a more feature-rich variant of {Concurrent.timer}. + # + # The *intended* schedule time of task execution is set on object construction + # with the `delay` argument. The delay is a numeric (floating point or integer) + # representing a number of seconds in the future. Any other value or a numeric + # equal to or less than zero will result in an exception. The *actual* schedule + # time of task execution is set when the `execute` method is called. + # + # The constructor can also be given zero or more processing options. Currently + # the only supported options are those recognized by the + # [Dereferenceable](Dereferenceable) module. + # + # The final constructor argument is a block representing the task to be performed. + # If no block is given an `ArgumentError` will be raised. + # + # **States** + # + # `ScheduledTask` mixes in the [Obligation](Obligation) module thus giving it + # "future" behavior. This includes the expected lifecycle states. `ScheduledTask` + # has one additional state, however. While the task (block) is being executed the + # state of the object will be `:processing`. This additional state is necessary + # because it has implications for task cancellation. + # + # **Cancellation** + # + # A `:pending` task can be cancelled using the `#cancel` method. A task in any + # other state, including `:processing`, cannot be cancelled. The `#cancel` + # method returns a boolean indicating the success of the cancellation attempt. + # A cancelled `ScheduledTask` cannot be restarted. It is immutable. + # + # **Obligation and Observation** + # + # The result of a `ScheduledTask` can be obtained either synchronously or + # asynchronously. `ScheduledTask` mixes in both the [Obligation](Obligation) + # module and the + # [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html) + # module from the Ruby standard library. With one exception `ScheduledTask` + # behaves identically to [Future](Observable) with regard to these modules. + # + # @!macro copy_options + # + # @example Basic usage + # + # require 'concurrent/scheduled_task' + # require 'csv' + # require 'open-uri' + # + # class Ticker + # def get_year_end_closing(symbol, year, api_key) + # uri = "https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol=#{symbol}&apikey=#{api_key}&datatype=csv" + # data = [] + # csv = URI.parse(uri).read + # if csv.include?('call frequency') + # return :rate_limit_exceeded + # end + # CSV.parse(csv, headers: true) do |row| + # data << row['close'].to_f if row['timestamp'].include?(year.to_s) + # end + # year_end = data.first + # year_end + # rescue => e + # p e + # end + # end + # + # api_key = ENV['ALPHAVANTAGE_KEY'] + # abort(error_message) unless api_key + # + # # Future + # price = Concurrent::Future.execute{ Ticker.new.get_year_end_closing('TWTR', 2013, api_key) } + # price.state #=> :pending + # price.pending? #=> true + # price.value(0) #=> nil (does not block) + # + # sleep(1) # do other stuff + # + # price.value #=> 63.65 (after blocking if necessary) + # price.state #=> :fulfilled + # price.fulfilled? #=> true + # price.value #=> 63.65 + # + # @example Successful task execution + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } + # task.state #=> :unscheduled + # task.execute + # task.state #=> pending + # + # # wait for it... + # sleep(3) + # + # task.unscheduled? #=> false + # task.pending? #=> false + # task.fulfilled? #=> true + # task.rejected? #=> false + # task.value #=> 'What does the fox say?' + # + # @example One line creation and execution + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' }.execute + # task.state #=> pending + # + # task = Concurrent::ScheduledTask.execute(2){ 'What do you get when you multiply 6 by 9?' } + # task.state #=> pending + # + # @example Failed task execution + # + # task = Concurrent::ScheduledTask.execute(2){ raise StandardError.new('Call me maybe?') } + # task.pending? #=> true + # + # # wait for it... + # sleep(3) + # + # task.unscheduled? #=> false + # task.pending? #=> false + # task.fulfilled? #=> false + # task.rejected? #=> true + # task.value #=> nil + # task.reason #=> # + # + # @example Task execution with observation + # + # observer = Class.new{ + # def update(time, value, reason) + # puts "The task completed at #{time} with value '#{value}'" + # end + # }.new + # + # task = Concurrent::ScheduledTask.new(2){ 'What does the fox say?' } + # task.add_observer(observer) + # task.execute + # task.pending? #=> true + # + # # wait for it... + # sleep(3) + # + # #>> The task completed at 2013-11-07 12:26:09 -0500 with value 'What does the fox say?' + # + # @!macro monotonic_clock_warning + # + # @see Concurrent.timer + class ScheduledTask < IVar + include Comparable + + # The executor on which to execute the task. + # @!visibility private + attr_reader :executor + + # Schedule a task for execution at a specified future time. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @yield the task to be performed + # + # @!macro executor_and_deref_options + # + # @option opts [object, Array] :args zero or more arguments to be passed the task + # block on execution + # + # @raise [ArgumentError] When no block is given + # @raise [ArgumentError] When given a time that is in the past + def initialize(delay, opts = {}, &task) + raise ArgumentError.new('no block given') unless block_given? + raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0 + + super(NULL, opts, &nil) + + synchronize do + ns_set_state(:unscheduled) + @parent = opts.fetch(:timer_set, Concurrent.global_timer_set) + @args = get_arguments_from(opts) + @delay = delay.to_f + @task = task + @time = nil + @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor + self.observers = Collection::CopyOnNotifyObserverSet.new + end + end + + # The `delay` value given at instantiation. + # + # @return [Float] the initial delay. + def initial_delay + synchronize { @delay } + end + + # The monotonic time at which the the task is scheduled to be executed. + # + # @return [Float] the schedule time or nil if `unscheduled` + def schedule_time + synchronize { @time } + end + + # Comparator which orders by schedule time. + # + # @!visibility private + def <=>(other) + schedule_time <=> other.schedule_time + end + + # Has the task been cancelled? + # + # @return [Boolean] true if the task is in the given state else false + def cancelled? + synchronize { ns_check_state?(:cancelled) } + end + + # In the task execution in progress? + # + # @return [Boolean] true if the task is in the given state else false + def processing? + synchronize { ns_check_state?(:processing) } + end + + # Cancel this task and prevent it from executing. A task can only be + # cancelled if it is pending or unscheduled. + # + # @return [Boolean] true if successfully cancelled else false + def cancel + if compare_and_set_state(:cancelled, :pending, :unscheduled) + complete(false, nil, CancelledOperationError.new) + # To avoid deadlocks this call must occur outside of #synchronize + # Changing the state above should prevent redundant calls + @parent.send(:remove_task, self) + else + false + end + end + + # Reschedule the task using the original delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @return [Boolean] true if successfully rescheduled else false + def reset + synchronize{ ns_reschedule(@delay) } + end + + # Reschedule the task using the given delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @raise [ArgumentError] When given a time that is in the past + def reschedule(delay) + delay = delay.to_f + raise ArgumentError.new('seconds must be greater than zero') if delay < 0.0 + synchronize{ ns_reschedule(delay) } + end + + # Execute an `:unscheduled` `ScheduledTask`. Immediately sets the state to `:pending` + # and starts counting down toward execution. Does nothing if the `ScheduledTask` is + # in any state other than `:unscheduled`. + # + # @return [ScheduledTask] a reference to `self` + def execute + if compare_and_set_state(:pending, :unscheduled) + synchronize{ ns_schedule(@delay) } + end + self + end + + # Create a new `ScheduledTask` object with the given block, execute it, and return the + # `:pending` object. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @!macro executor_and_deref_options + # + # @return [ScheduledTask] the newly created `ScheduledTask` in the `:pending` state + # + # @raise [ArgumentError] if no block is given + def self.execute(delay, opts = {}, &task) + new(delay, opts, &task).execute + end + + # Execute the task. + # + # @!visibility private + def process_task + safe_execute(@task, @args) + end + + protected :set, :try_set, :fail, :complete + + protected + + # Schedule the task using the given delay and the current time. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @!visibility private + def ns_schedule(delay) + @delay = delay + @time = Concurrent.monotonic_time + @delay + @parent.send(:post_task, self) + end + + # Reschedule the task using the given delay and the current time. + # A task can only be reset while it is `:pending`. + # + # @param [Float] delay the number of seconds to wait for before executing the task + # + # @return [Boolean] true if successfully rescheduled else false + # + # @!visibility private + def ns_reschedule(delay) + return false unless ns_check_state?(:pending) + @parent.send(:remove_task, self) && ns_schedule(delay) + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/set.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/set.rb new file mode 100644 index 00000000..eee4effd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/set.rb @@ -0,0 +1,64 @@ +require 'concurrent/utility/engine' +require 'concurrent/thread_safe/util' +require 'set' + +module Concurrent + + # @!macro concurrent_set + # + # A thread-safe subclass of Set. This version locks against the object + # itself for every method call, ensuring only one thread can be reading + # or writing at a time. This includes iteration methods like `#each`. + # + # @note `a += b` is **not** a **thread-safe** operation on + # `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set` + # which is union of `a` and `b`, then it writes the union to `a`. + # The read and write are independent operations they do not form a single atomic + # operation therefore when two `+=` operations are executed concurrently updates + # may be lost. Use `#merge` instead. + # + # @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set` + + # @!macro internal_implementation_note + SetImplementation = case + when Concurrent.on_cruby? + # The CRuby implementation of Set is written in Ruby itself and is + # not thread safe for certain methods. + require 'monitor' + require 'concurrent/thread_safe/util/data_structures' + + class CRubySet < ::Set + end + + ThreadSafe::Util.make_synchronized_on_cruby CRubySet + CRubySet + + when Concurrent.on_jruby? + require 'jruby/synchronized' + + class JRubySet < ::Set + include JRuby::Synchronized + end + + JRubySet + + when Concurrent.on_truffleruby? + require 'concurrent/thread_safe/util/data_structures' + + class TruffleRubySet < ::Set + end + + ThreadSafe::Util.make_synchronized_on_truffleruby TruffleRubySet + TruffleRubySet + + else + warn 'Possibly unsupported Ruby implementation' + ::Set + end + private_constant :SetImplementation + + # @!macro concurrent_set + class Set < SetImplementation + end +end + diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/settable_struct.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/settable_struct.rb new file mode 100644 index 00000000..99b85619 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/settable_struct.rb @@ -0,0 +1,139 @@ +require 'concurrent/errors' +require 'concurrent/synchronization/abstract_struct' +require 'concurrent/synchronization/lockable_object' + +module Concurrent + + # An thread-safe, write-once variation of Ruby's standard `Struct`. + # Each member can have its value set at most once, either at construction + # or any time thereafter. Attempting to assign a value to a member + # that has already been set will result in a `Concurrent::ImmutabilityError`. + # + # @see http://ruby-doc.org/core/Struct.html Ruby standard library `Struct` + # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword + module SettableStruct + include Synchronization::AbstractStruct + + # @!macro struct_values + def values + synchronize { ns_values } + end + alias_method :to_a, :values + + # @!macro struct_values_at + def values_at(*indexes) + synchronize { ns_values_at(indexes) } + end + + # @!macro struct_inspect + def inspect + synchronize { ns_inspect } + end + alias_method :to_s, :inspect + + # @!macro struct_merge + def merge(other, &block) + synchronize { ns_merge(other, &block) } + end + + # @!macro struct_to_h + def to_h + synchronize { ns_to_h } + end + + # @!macro struct_get + def [](member) + synchronize { ns_get(member) } + end + + # @!macro struct_equality + def ==(other) + synchronize { ns_equality(other) } + end + + # @!macro struct_each + def each(&block) + return enum_for(:each) unless block_given? + synchronize { ns_each(&block) } + end + + # @!macro struct_each_pair + def each_pair(&block) + return enum_for(:each_pair) unless block_given? + synchronize { ns_each_pair(&block) } + end + + # @!macro struct_select + def select(&block) + return enum_for(:select) unless block_given? + synchronize { ns_select(&block) } + end + + # @!macro struct_set + # + # @raise [Concurrent::ImmutabilityError] if the given member has already been set + def []=(member, value) + if member.is_a? Integer + length = synchronize { @values.length } + if member >= length + raise IndexError.new("offset #{member} too large for struct(size:#{length})") + end + synchronize do + unless @values[member].nil? + raise Concurrent::ImmutabilityError.new('struct member has already been set') + end + @values[member] = value + end + else + send("#{member}=", value) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + private + + # @!visibility private + def initialize_copy(original) + synchronize do + super(original) + ns_initialize_copy + end + end + + # @!macro struct_new + def self.new(*args, &block) + clazz_name = nil + if args.length == 0 + raise ArgumentError.new('wrong number of arguments (0 for 1+)') + elsif args.length > 0 && args.first.is_a?(String) + clazz_name = args.shift + end + FACTORY.define_struct(clazz_name, args, &block) + end + + FACTORY = Class.new(Synchronization::LockableObject) do + def define_struct(name, members, &block) + synchronize do + clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block) + members.each_with_index do |member, index| + clazz.send :remove_method, member if clazz.instance_methods.include? member + clazz.send(:define_method, member) do + synchronize { @values[index] } + end + clazz.send(:define_method, "#{member}=") do |value| + synchronize do + unless @values[index].nil? + raise Concurrent::ImmutabilityError.new('struct member has already been set') + end + @values[index] = value + end + end + end + clazz + end + end + end.new + private_constant :FACTORY + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization.rb new file mode 100644 index 00000000..6d8cf4bd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization.rb @@ -0,0 +1,13 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/synchronization/object' +require 'concurrent/synchronization/lockable_object' +require 'concurrent/synchronization/condition' +require 'concurrent/synchronization/lock' + +module Concurrent + # @!visibility private + module Synchronization + end +end + diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb new file mode 100644 index 00000000..d9050b31 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb @@ -0,0 +1,102 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first +require 'concurrent/utility/monotonic_time' +require 'concurrent/synchronization/object' + +module Concurrent + module Synchronization + + # @!visibility private + class AbstractLockableObject < Synchronization::Object + + protected + + # @!macro synchronization_object_method_synchronize + # + # @yield runs the block synchronized against this object, + # equivalent of java's `synchronize(this) {}` + # @note can by made public in descendants if required by `public :synchronize` + def synchronize + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_wait_until + # + # Wait until condition is met or timeout passes, + # protects against spurious wake-ups. + # @param [Numeric, nil] timeout in seconds, `nil` means no timeout + # @yield condition to be met + # @yieldreturn [true, false] + # @return [true, false] if condition met + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def wait_until(timeout = nil, &condition) + # synchronize { ns_wait_until(timeout, &condition) } + # end + # ``` + def ns_wait_until(timeout = nil, &condition) + if timeout + wait_until = Concurrent.monotonic_time + timeout + loop do + now = Concurrent.monotonic_time + condition_result = condition.call + return condition_result if now >= wait_until || condition_result + ns_wait wait_until - now + end + else + ns_wait timeout until condition.call + true + end + end + + # @!macro synchronization_object_method_ns_wait + # + # Wait until another thread calls #signal or #broadcast, + # spurious wake-ups can happen. + # + # @param [Numeric, nil] timeout in seconds, `nil` means no timeout + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def wait(timeout = nil) + # synchronize { ns_wait(timeout) } + # end + # ``` + def ns_wait(timeout = nil) + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_signal + # + # Signal one waiting thread. + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def signal + # synchronize { ns_signal } + # end + # ``` + def ns_signal + raise NotImplementedError + end + + # @!macro synchronization_object_method_ns_broadcast + # + # Broadcast to all waiting threads. + # @return [self] + # @note only to be used inside synchronized block + # @note to provide direct access to this method in a descendant add method + # ``` + # def broadcast + # synchronize { ns_broadcast } + # end + # ``` + def ns_broadcast + raise NotImplementedError + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb new file mode 100644 index 00000000..7cd2decf --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb @@ -0,0 +1,22 @@ +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + class AbstractObject + def initialize + # nothing to do + end + + # @!visibility private + # @abstract + def full_memory_barrier + raise NotImplementedError + end + + def self.attr_volatile(*names) + raise NotImplementedError + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb new file mode 100644 index 00000000..28816c51 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb @@ -0,0 +1,171 @@ +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + module AbstractStruct + + # @!visibility private + def initialize(*values) + super() + ns_initialize(*values) + end + + # @!macro struct_length + # + # Returns the number of struct members. + # + # @return [Fixnum] the number of struct members + def length + self.class::MEMBERS.length + end + alias_method :size, :length + + # @!macro struct_members + # + # Returns the struct members as an array of symbols. + # + # @return [Array] the struct members as an array of symbols + def members + self.class::MEMBERS.dup + end + + protected + + # @!macro struct_values + # + # @!visibility private + def ns_values + @values.dup + end + + # @!macro struct_values_at + # + # @!visibility private + def ns_values_at(indexes) + @values.values_at(*indexes) + end + + # @!macro struct_to_h + # + # @!visibility private + def ns_to_h + length.times.reduce({}){|memo, i| memo[self.class::MEMBERS[i]] = @values[i]; memo} + end + + # @!macro struct_get + # + # @!visibility private + def ns_get(member) + if member.is_a? Integer + if member >= @values.length + raise IndexError.new("offset #{member} too large for struct(size:#{@values.length})") + end + @values[member] + else + send(member) + end + rescue NoMethodError + raise NameError.new("no member '#{member}' in struct") + end + + # @!macro struct_equality + # + # @!visibility private + def ns_equality(other) + self.class == other.class && self.values == other.values + end + + # @!macro struct_each + # + # @!visibility private + def ns_each + values.each{|value| yield value } + end + + # @!macro struct_each_pair + # + # @!visibility private + def ns_each_pair + @values.length.times do |index| + yield self.class::MEMBERS[index], @values[index] + end + end + + # @!macro struct_select + # + # @!visibility private + def ns_select + values.select{|value| yield value } + end + + # @!macro struct_inspect + # + # @!visibility private + def ns_inspect + struct = pr_underscore(self.class.ancestors[1]) + clazz = ((self.class.to_s =~ /^#" + end + + # @!macro struct_merge + # + # @!visibility private + def ns_merge(other, &block) + self.class.new(*self.to_h.merge(other, &block).values) + end + + # @!visibility private + def ns_initialize_copy + @values = @values.map do |val| + begin + val.clone + rescue TypeError + val + end + end + end + + # @!visibility private + def pr_underscore(clazz) + word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229 + word.gsub!(/::/, '/') + word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') + word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + word.tr!("-", "_") + word.downcase! + word + end + + # @!visibility private + def self.define_struct_class(parent, base, name, members, &block) + clazz = Class.new(base || Object) do + include parent + self.const_set(:MEMBERS, members.collect{|member| member.to_s.to_sym}.freeze) + def ns_initialize(*values) + raise ArgumentError.new('struct size differs') if values.length > length + @values = values.fill(nil, values.length..length-1) + end + end + unless name.nil? + begin + parent.send :remove_const, name if parent.const_defined?(name, false) + parent.const_set(name, clazz) + clazz + rescue NameError + raise NameError.new("identifier #{name} needs to be constant") + end + end + members.each_with_index do |member, index| + clazz.send :remove_method, member if clazz.instance_methods(false).include? member + clazz.send(:define_method, member) do + @values[index] + end + end + clazz.class_exec(&block) unless block.nil? + clazz.singleton_class.send :alias_method, :[], :new + clazz + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/condition.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/condition.rb new file mode 100644 index 00000000..5daa68be --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/condition.rb @@ -0,0 +1,62 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # TODO (pitr-ch 04-Dec-2016): should be in edge + class Condition < LockableObject + safe_initialization! + + # TODO (pitr 12-Sep-2015): locks two objects, improve + # TODO (pitr 26-Sep-2015): study + # http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/concurrent/locks/AbstractQueuedSynchronizer.java#AbstractQueuedSynchronizer.Node + + singleton_class.send :alias_method, :private_new, :new + private_class_method :new + + def initialize(lock) + super() + @Lock = lock + end + + def wait(timeout = nil) + @Lock.synchronize { ns_wait(timeout) } + end + + def ns_wait(timeout = nil) + synchronize { super(timeout) } + end + + def wait_until(timeout = nil, &condition) + @Lock.synchronize { ns_wait_until(timeout, &condition) } + end + + def ns_wait_until(timeout = nil, &condition) + synchronize { super(timeout, &condition) } + end + + def signal + @Lock.synchronize { ns_signal } + end + + def ns_signal + synchronize { super } + end + + def broadcast + @Lock.synchronize { ns_broadcast } + end + + def ns_broadcast + synchronize { super } + end + end + + class LockableObject < LockableObjectImplementation + def new_condition + Condition.private_new(self) + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb new file mode 100644 index 00000000..139e08d8 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb @@ -0,0 +1,29 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +module Concurrent + module Synchronization + case + when Concurrent.on_cruby? + def self.full_memory_barrier + # relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars + # https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211 + end + + when Concurrent.on_jruby? + require 'concurrent/utility/native_extension_loader' + def self.full_memory_barrier + JRubyAttrVolatile.full_memory_barrier + end + + when Concurrent.on_truffleruby? + def self.full_memory_barrier + TruffleRuby.full_memory_barrier + end + + else + warn 'Possibly unsupported Ruby implementation' + def self.full_memory_barrier + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb new file mode 100644 index 00000000..76930461 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb @@ -0,0 +1,15 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +module Concurrent + module Synchronization + + if Concurrent.on_jruby? + + # @!visibility private + # @!macro internal_implementation_note + class JRubyLockableObject < AbstractLockableObject + + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lock.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lock.rb new file mode 100644 index 00000000..f90e0b5f --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lock.rb @@ -0,0 +1,38 @@ +require 'concurrent/synchronization/lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # TODO (pitr-ch 04-Dec-2016): should be in edge + class Lock < LockableObject + # TODO use JavaReentrantLock on JRuby + + public :synchronize + + def wait(timeout = nil) + synchronize { ns_wait(timeout) } + end + + public :ns_wait + + def wait_until(timeout = nil, &condition) + synchronize { ns_wait_until(timeout, &condition) } + end + + public :ns_wait_until + + def signal + synchronize { ns_signal } + end + + public :ns_signal + + def broadcast + synchronize { ns_broadcast } + end + + public :ns_broadcast + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb new file mode 100644 index 00000000..08d2ff66 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb @@ -0,0 +1,75 @@ +require 'concurrent/utility/engine' +require 'concurrent/synchronization/abstract_lockable_object' +require 'concurrent/synchronization/mutex_lockable_object' +require 'concurrent/synchronization/jruby_lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + LockableObjectImplementation = case + when Concurrent.on_cruby? + MutexLockableObject + when Concurrent.on_jruby? + JRubyLockableObject + when Concurrent.on_truffleruby? + MutexLockableObject + else + warn 'Possibly unsupported Ruby implementation' + MonitorLockableObject + end + private_constant :LockableObjectImplementation + + # Safe synchronization under any Ruby implementation. + # It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}. + # Provides a single layer which can improve its implementation over time without changes needed to + # the classes using it. Use {Synchronization::Object} not this abstract class. + # + # @note this object does not support usage together with + # [`Thread#wakeup`](http://ruby-doc.org/core/Thread.html#method-i-wakeup) + # and [`Thread#raise`](http://ruby-doc.org/core/Thread.html#method-i-raise). + # `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and + # `Thread#wakeup` will not work on all platforms. + # + # @see Event implementation as an example of this class use + # + # @example simple + # class AnClass < Synchronization::Object + # def initialize + # super + # synchronize { @value = 'asd' } + # end + # + # def value + # synchronize { @value } + # end + # end + # + # @!visibility private + class LockableObject < LockableObjectImplementation + + # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing + # TODO (pitr 12-Sep-2015): we inherit too much ourselves :/ + + # @!method initialize(*args, &block) + # @!macro synchronization_object_method_initialize + + # @!method synchronize + # @!macro synchronization_object_method_synchronize + + # @!method wait_until(timeout = nil, &condition) + # @!macro synchronization_object_method_ns_wait_until + + # @!method wait(timeout = nil) + # @!macro synchronization_object_method_ns_wait + + # @!method signal + # @!macro synchronization_object_method_ns_signal + + # @!method broadcast + # @!macro synchronization_object_method_ns_broadcast + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb new file mode 100644 index 00000000..acc9745a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb @@ -0,0 +1,89 @@ +require 'concurrent/synchronization/abstract_lockable_object' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + module ConditionSignalling + protected + + def ns_signal + @__Condition__.signal + self + end + + def ns_broadcast + @__Condition__.broadcast + self + end + end + + + # @!visibility private + # @!macro internal_implementation_note + class MutexLockableObject < AbstractLockableObject + include ConditionSignalling + + safe_initialization! + + def initialize + super() + @__Lock__ = ::Mutex.new + @__Condition__ = ::ConditionVariable.new + end + + def initialize_copy(other) + super + @__Lock__ = ::Mutex.new + @__Condition__ = ::ConditionVariable.new + end + + protected + + def synchronize + if @__Lock__.owned? + yield + else + @__Lock__.synchronize { yield } + end + end + + def ns_wait(timeout = nil) + @__Condition__.wait @__Lock__, timeout + self + end + end + + # @!visibility private + # @!macro internal_implementation_note + class MonitorLockableObject < AbstractLockableObject + include ConditionSignalling + + safe_initialization! + + def initialize + super() + @__Lock__ = ::Monitor.new + @__Condition__ = @__Lock__.new_cond + end + + def initialize_copy(other) + super + @__Lock__ = ::Monitor.new + @__Condition__ = @__Lock__.new_cond + end + + protected + + def synchronize # TODO may be a problem with lock.synchronize { lock.wait } + @__Lock__.synchronize { yield } + end + + def ns_wait(timeout = nil) + @__Condition__.wait timeout + self + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/object.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/object.rb new file mode 100644 index 00000000..59219070 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/object.rb @@ -0,0 +1,151 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first + +require 'concurrent/synchronization/safe_initialization' +require 'concurrent/synchronization/volatile' +require 'concurrent/atomic/atomic_reference' + +module Concurrent + module Synchronization + + # Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions. + # - final instance variables see {Object.safe_initialization!} + # - volatile instance variables see {Object.attr_volatile} + # - volatile instance variables see {Object.attr_atomic} + # @!visibility private + class Object < AbstractObject + include Volatile + + # TODO make it a module if possible + + # @!method self.attr_volatile(*names) + # Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with + # volatile (Java) semantic. The instance variable should be accessed only through generated methods. + # + # @param [::Array] names of the instance variables to be volatile + # @return [::Array] names of defined method names + + # Has to be called by children. + def initialize + super + __initialize_atomic_fields__ + end + + def self.safe_initialization! + extend SafeInitialization unless safe_initialization? + end + + def self.safe_initialization? + self.singleton_class < SafeInitialization + end + + # For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains + # any instance variables with CamelCase names and isn't {.safe_initialization?}. + # @raise when offend found + # @return [true] + def self.ensure_safe_initialization_when_final_fields_are_present + Object.class_eval do + def self.new(*args, &block) + object = super(*args, &block) + ensure + has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ } + if has_final_field && !safe_initialization? + raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!" + end + end + end + true + end + + # Creates methods for reading and writing to a instance variable with + # volatile (Java) semantic as {.attr_volatile} does. + # The instance variable should be accessed only through generated methods. + # This method generates following methods: `value`, `value=(new_value) #=> new_value`, + # `swap_value(new_value) #=> old_value`, + # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`. + # @param [::Array] names of the instance variables to be volatile with CAS. + # @return [::Array] names of defined method names. + # @!macro attr_atomic + # @!method $1 + # @return [Object] The $1. + # @!method $1=(new_$1) + # Set the $1. + # @return [Object] new_$1. + # @!method swap_$1(new_$1) + # Set the $1 to new_$1 and return the old $1. + # @return [Object] old $1 + # @!method compare_and_set_$1(expected_$1, new_$1) + # Sets the $1 to new_$1 if the current $1 is expected_$1 + # @return [true, false] + # @!method update_$1(&block) + # Updates the $1 using the block. + # @yield [Object] Calculate a new $1 using given (old) $1 + # @yieldparam [Object] old $1 + # @return [Object] new $1 + def self.attr_atomic(*names) + @__atomic_fields__ ||= [] + @__atomic_fields__ += names + safe_initialization! + define_initialize_atomic_fields + + names.each do |name| + ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}" + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + #{ivar}.get + end + + def #{name}=(value) + #{ivar}.set value + end + + def swap_#{name}(value) + #{ivar}.swap value + end + + def compare_and_set_#{name}(expected, value) + #{ivar}.compare_and_set expected, value + end + + def update_#{name}(&block) + #{ivar}.update(&block) + end + RUBY + end + names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] } + end + + # @param [true, false] inherited should inherited volatile with CAS fields be returned? + # @return [::Array] Returns defined volatile with CAS fields on this class. + def self.atomic_attributes(inherited = true) + @__atomic_fields__ ||= [] + ((superclass.atomic_attributes if superclass.respond_to?(:atomic_attributes) && inherited) || []) + @__atomic_fields__ + end + + # @return [true, false] is the attribute with name atomic? + def self.atomic_attribute?(name) + atomic_attributes.include? name + end + + private + + def self.define_initialize_atomic_fields + assignments = @__atomic_fields__.map do |name| + "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = Concurrent::AtomicReference.new(nil)" + end.join("\n") + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def __initialize_atomic_fields__ + super + #{assignments} + end + RUBY + end + + private_class_method :define_initialize_atomic_fields + + def __initialize_atomic_fields__ + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb new file mode 100644 index 00000000..f785e352 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb @@ -0,0 +1,36 @@ +require 'concurrent/synchronization/full_memory_barrier' + +module Concurrent + module Synchronization + + # @!visibility private + # @!macro internal_implementation_note + # + # By extending this module, a class and all its children are marked to be constructed safely. Meaning that + # all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures + # same behaviour as Java's final fields. + # + # Due to using Kernel#extend, the module is not included again if already present in the ancestors, + # which avoids extra overhead. + # + # @example + # class AClass < Concurrent::Synchronization::Object + # extend Concurrent::Synchronization::SafeInitialization + # + # def initialize + # @AFinalValue = 'value' # published safely, #foo will never return nil + # end + # + # def foo + # @AFinalValue + # end + # end + module SafeInitialization + def new(*args, &block) + super(*args, &block) + ensure + Concurrent::Synchronization.full_memory_barrier + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/volatile.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/volatile.rb new file mode 100644 index 00000000..46e8ba6a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/synchronization/volatile.rb @@ -0,0 +1,101 @@ +require 'concurrent/utility/native_extension_loader' # load native parts first +require 'concurrent/utility/engine' +require 'concurrent/synchronization/full_memory_barrier' + +module Concurrent + module Synchronization + + # Volatile adds the attr_volatile class method when included. + # + # @example + # class Foo + # include Concurrent::Synchronization::Volatile + # + # attr_volatile :bar + # + # def initialize + # self.bar = 1 + # end + # end + # + # foo = Foo.new + # foo.bar + # => 1 + # foo.bar = 2 + # => 2 + # + # @!visibility private + module Volatile + def self.included(base) + base.extend(ClassMethods) + end + + def full_memory_barrier + Synchronization.full_memory_barrier + end + + module ClassMethods + if Concurrent.on_cruby? + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + #{ivar} + end + + def #{name}=(value) + #{ivar} = value + end + RUBY + end + names.map { |n| [n, :"#{n}="] }.flatten + end + + elsif Concurrent.on_jruby? + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + ::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_get_volatile(self, :#{ivar}) + end + + def #{name}=(value) + ::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_set_volatile(self, :#{ivar}, value) + end + RUBY + + end + names.map { |n| [n, :"#{n}="] }.flatten + end + + else + warn 'Possibly unsupported Ruby implementation' unless Concurrent.on_truffleruby? + + def attr_volatile(*names) + names.each do |name| + ivar = :"@volatile_#{name}" + + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{name} + ::Concurrent::Synchronization.full_memory_barrier + #{ivar} + end + + def #{name}=(value) + #{ivar} = value + ::Concurrent::Synchronization.full_memory_barrier + end + RUBY + end + + names.map { |n| [n, :"#{n}="] }.flatten + end + end + end + + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb new file mode 100644 index 00000000..019d8438 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb @@ -0,0 +1,47 @@ +require 'delegate' +require 'monitor' + +module Concurrent + # This class provides a trivial way to synchronize all calls to a given object + # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls + # around the delegated `#send`. Example: + # + # array = [] # not thread-safe on many impls + # array = SynchronizedDelegator.new([]) # thread-safe + # + # A simple `Monitor` provides a very coarse-grained way to synchronize a given + # object, in that it will cause synchronization for methods that have no need + # for it, but this is a trivial way to get thread-safety where none may exist + # currently on some implementations. + # + # This class is currently being considered for inclusion into stdlib, via + # https://bugs.ruby-lang.org/issues/8556 + # + # @!visibility private + class SynchronizedDelegator < SimpleDelegator + def setup + @old_abort = Thread.abort_on_exception + Thread.abort_on_exception = true + end + + def teardown + Thread.abort_on_exception = @old_abort + end + + def initialize(obj) + __setobj__(obj) + @monitor = Monitor.new + end + + def method_missing(method, *args, &block) + monitor = @monitor + begin + monitor.enter + super + ensure + monitor.exit + end + end + + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util.rb new file mode 100644 index 00000000..c67084a2 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util.rb @@ -0,0 +1,16 @@ +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # TODO (pitr-ch 15-Oct-2016): migrate to Utility::NativeInteger + FIXNUM_BIT_SIZE = (0.size * 8) - 2 + MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1 + # TODO (pitr-ch 15-Oct-2016): migrate to Utility::ProcessorCounter + CPU_COUNT = 16 # is there a way to determine this? + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb new file mode 100644 index 00000000..852b403b --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb @@ -0,0 +1,74 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/thread_safe/util/striped64' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A Ruby port of the Doug Lea's jsr166e.LongAdder class version 1.8 + # available in public domain. + # + # Original source code available here: + # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8 + # + # One or more variables that together maintain an initially zero + # sum. When updates (method +add+) are contended across threads, + # the set of variables may grow dynamically to reduce contention. + # Method +sum+ returns the current total combined across the + # variables maintaining the sum. + # + # This class is usually preferable to single +Atomic+ reference when + # multiple threads update a common sum that is used for purposes such + # as collecting statistics, not for fine-grained synchronization + # control. Under low update contention, the two classes have similar + # characteristics. But under high contention, expected throughput of + # this class is significantly higher, at the expense of higher space + # consumption. + # + # @!visibility private + class Adder < Striped64 + # Adds the given value. + def add(x) + if (current_cells = cells) || !cas_base_computed {|current_base| current_base + x} + was_uncontended = true + hash = hash_code + unless current_cells && (cell = current_cells.volatile_get_by_hash(hash)) && (was_uncontended = cell.cas_computed {|current_value| current_value + x}) + retry_update(x, hash, was_uncontended) {|current_value| current_value + x} + end + end + end + + def increment + add(1) + end + + def decrement + add(-1) + end + + # Returns the current sum. The returned value is _NOT_ an + # atomic snapshot: Invocation in the absence of concurrent + # updates returns an accurate result, but concurrent updates that + # occur while the sum is being calculated might not be + # incorporated. + def sum + x = base + if current_cells = cells + current_cells.each do |cell| + x += cell.value if cell + end + end + x + end + + def reset + internal_reset(0) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb new file mode 100644 index 00000000..01eb98f4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb @@ -0,0 +1,52 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/utility/engine' + +# Shim for TruffleRuby.synchronized +if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized) + module TruffleRuby + def self.synchronized(object, &block) + Truffle::System.synchronized(object, &block) + end + end +end + +module Concurrent + module ThreadSafe + module Util + def self.make_synchronized_on_cruby(klass) + klass.class_eval do + def initialize(*args, &block) + @_monitor = Monitor.new + super + end + + def initialize_copy(other) + # make sure a copy is not sharing a monitor with the original object! + @_monitor = Monitor.new + super + end + end + + klass.superclass.instance_methods(false).each do |method| + klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + monitor = @_monitor + monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.") + monitor.synchronize { super } + end + RUBY + end + end + + def self.make_synchronized_on_truffleruby(klass) + klass.superclass.instance_methods(false).each do |method| + klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args, &block) + TruffleRuby.synchronized(self) { super(*args, &block) } + end + RUBY + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb new file mode 100644 index 00000000..b54be39c --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb @@ -0,0 +1,38 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/tuple' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # @!visibility private + class PowerOfTwoTuple < Concurrent::Tuple + + def initialize(size) + raise ArgumentError, "size must be a power of 2 (#{size.inspect} provided)" unless size > 0 && size & (size - 1) == 0 + super(size) + end + + def hash_to_index(hash) + (size - 1) & hash + end + + def volatile_get_by_hash(hash) + volatile_get(hash_to_index(hash)) + end + + def volatile_set_by_hash(hash, value) + volatile_set(hash_to_index(hash), value) + end + + def next_in_size_table + self.class.new(size << 1) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb new file mode 100644 index 00000000..4169c3d3 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb @@ -0,0 +1,246 @@ +require 'concurrent/thread_safe/util' +require 'concurrent/thread_safe/util/power_of_two_tuple' +require 'concurrent/thread_safe/util/volatile' +require 'concurrent/thread_safe/util/xor_shift_random' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A Ruby port of the Doug Lea's jsr166e.Striped64 class version 1.6 + # available in public domain. + # + # Original source code available here: + # http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.6 + # + # Class holding common representation and mechanics for classes supporting + # dynamic striping on 64bit values. + # + # This class maintains a lazily-initialized table of atomically updated + # variables, plus an extra +base+ field. The table size is a power of two. + # Indexing uses masked per-thread hash codes. Nearly all methods on this + # class are private, accessed directly by subclasses. + # + # Table entries are of class +Cell+; a variant of AtomicLong padded to + # reduce cache contention on most processors. Padding is overkill for most + # Atomics because they are usually irregularly scattered in memory and thus + # don't interfere much with each other. But Atomic objects residing in + # arrays will tend to be placed adjacent to each other, and so will most + # often share cache lines (with a huge negative performance impact) without + # this precaution. + # + # In part because +Cell+s are relatively large, we avoid creating them until + # they are needed. When there is no contention, all updates are made to the + # +base+ field. Upon first contention (a failed CAS on +base+ update), the + # table is initialized to size 2. The table size is doubled upon further + # contention until reaching the nearest power of two greater than or equal + # to the number of CPUS. Table slots remain empty (+nil+) until they are + # needed. + # + # A single spinlock (+busy+) is used for initializing and resizing the + # table, as well as populating slots with new +Cell+s. There is no need for + # a blocking lock: When the lock is not available, threads try other slots + # (or the base). During these retries, there is increased contention and + # reduced locality, which is still better than alternatives. + # + # Per-thread hash codes are initialized to random values. Contention and/or + # table collisions are indicated by failed CASes when performing an update + # operation (see method +retry_update+). Upon a collision, if the table size + # is less than the capacity, it is doubled in size unless some other thread + # holds the lock. If a hashed slot is empty, and lock is available, a new + # +Cell+ is created. Otherwise, if the slot exists, a CAS is tried. Retries + # proceed by "double hashing", using a secondary hash (XorShift) to try to + # find a free slot. + # + # The table size is capped because, when there are more threads than CPUs, + # supposing that each thread were bound to a CPU, there would exist a + # perfect hash function mapping threads to slots that eliminates collisions. + # When we reach capacity, we search for this mapping by randomly varying the + # hash codes of colliding threads. Because search is random, and collisions + # only become known via CAS failures, convergence can be slow, and because + # threads are typically not bound to CPUS forever, may not occur at all. + # However, despite these limitations, observed contention rates are + # typically low in these cases. + # + # It is possible for a +Cell+ to become unused when threads that once hashed + # to it terminate, as well as in the case where doubling the table causes no + # thread to hash to it under expanded mask. We do not try to detect or + # remove such cells, under the assumption that for long-running instances, + # observed contention levels will recur, so the cells will eventually be + # needed again; and for short-lived ones, it does not matter. + # + # @!visibility private + class Striped64 + + # Padded variant of AtomicLong supporting only raw accesses plus CAS. + # The +value+ field is placed between pads, hoping that the JVM doesn't + # reorder them. + # + # Optimisation note: It would be possible to use a release-only + # form of CAS here, if it were provided. + # + # @!visibility private + class Cell < Concurrent::AtomicReference + + alias_method :cas, :compare_and_set + + def cas_computed + cas(current_value = value, yield(current_value)) + end + + # @!visibility private + def self.padding + # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot + # TODO (pitr-ch 28-Jul-2018): the padding instance vars may not be created + # hide from yardoc in a method + attr_reader :padding_0, :padding_1, :padding_2, :padding_3, :padding_4, :padding_5, :padding_6, :padding_7, :padding_8, :padding_9, :padding_10, :padding_11 + end + padding + end + + extend Volatile + attr_volatile :cells, # Table of cells. When non-null, size is a power of 2. + :base, # Base value, used mainly when there is no contention, but also as a fallback during table initialization races. Updated via CAS. + :busy # Spinlock (locked via CAS) used when resizing and/or creating Cells. + + alias_method :busy?, :busy + + def initialize + super() + self.busy = false + self.base = 0 + end + + # Handles cases of updates involving initialization, resizing, + # creating new Cells, and/or contention. See above for + # explanation. This method suffers the usual non-modularity + # problems of optimistic retry code, relying on rechecked sets of + # reads. + # + # Arguments: + # [+x+] + # the value + # [+hash_code+] + # hash code used + # [+x+] + # false if CAS failed before call + def retry_update(x, hash_code, was_uncontended) # :yields: current_value + hash = hash_code + collided = false # True if last slot nonempty + while true + if current_cells = cells + if !(cell = current_cells.volatile_get_by_hash(hash)) + if busy? + collided = false + else # Try to attach new Cell + if try_to_install_new_cell(Cell.new(x), hash) # Optimistically create and try to insert new cell + break + else + redo # Slot is now non-empty + end + end + elsif !was_uncontended # CAS already known to fail + was_uncontended = true # Continue after rehash + elsif cell.cas_computed {|current_value| yield current_value} + break + elsif current_cells.size >= CPU_COUNT || cells != current_cells # At max size or stale + collided = false + elsif collided && expand_table_unless_stale(current_cells) + collided = false + redo # Retry with expanded table + else + collided = true + end + hash = XorShiftRandom.xorshift(hash) + + elsif try_initialize_cells(x, hash) || cas_base_computed {|current_base| yield current_base} + break + end + end + self.hash_code = hash + end + + private + # Static per-thread hash code key. Shared across all instances to + # reduce Thread locals pollution and because adjustments due to + # collisions in one table are likely to be appropriate for + # others. + THREAD_LOCAL_KEY = "#{name}.hash_code".to_sym + + # A thread-local hash code accessor. The code is initially + # random, but may be set to a different value upon collisions. + def hash_code + Thread.current[THREAD_LOCAL_KEY] ||= XorShiftRandom.get + end + + def hash_code=(hash) + Thread.current[THREAD_LOCAL_KEY] = hash + end + + # Sets base and all +cells+ to the given value. + def internal_reset(initial_value) + current_cells = cells + self.base = initial_value + if current_cells + current_cells.each do |cell| + cell.value = initial_value if cell + end + end + end + + def cas_base_computed + cas_base(current_base = base, yield(current_base)) + end + + def free? + !busy? + end + + def try_initialize_cells(x, hash) + if free? && !cells + try_in_busy do + unless cells # Recheck under lock + new_cells = PowerOfTwoTuple.new(2) + new_cells.volatile_set_by_hash(hash, Cell.new(x)) + self.cells = new_cells + end + end + end + end + + def expand_table_unless_stale(current_cells) + try_in_busy do + if current_cells == cells # Recheck under lock + new_cells = current_cells.next_in_size_table + current_cells.each_with_index {|x, i| new_cells.volatile_set(i, x)} + self.cells = new_cells + end + end + end + + def try_to_install_new_cell(new_cell, hash) + try_in_busy do + # Recheck under lock + if (current_cells = cells) && !current_cells.volatile_get(i = current_cells.hash_to_index(hash)) + current_cells.volatile_set(i, new_cell) + end + end + end + + def try_in_busy + if cas_busy(false, true) + begin + yield + ensure + self.busy = false + end + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb new file mode 100644 index 00000000..cdac2a39 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb @@ -0,0 +1,75 @@ +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # @!visibility private + module Volatile + + # Provides +volatile+ (in the JVM's sense) attribute accessors implemented + # atop of +Concurrent::AtomicReference+. + # + # Usage: + # class Foo + # extend Concurrent::ThreadSafe::Util::Volatile + # attr_volatile :foo, :bar + # + # def initialize(bar) + # super() # must super() into parent initializers before using the volatile attribute accessors + # self.bar = bar + # end + # + # def hello + # my_foo = foo # volatile read + # self.foo = 1 # volatile write + # cas_foo(1, 2) # => true | a strong CAS + # end + # end + def attr_volatile(*attr_names) + return if attr_names.empty? + include(Module.new do + atomic_ref_setup = attr_names.map {|attr_name| "@__#{attr_name} = Concurrent::AtomicReference.new"} + initialize_copy_setup = attr_names.zip(atomic_ref_setup).map do |attr_name, ref_setup| + "#{ref_setup}(other.instance_variable_get(:@__#{attr_name}).get)" + end + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def initialize(*) + super + #{atomic_ref_setup.join('; ')} + end + + def initialize_copy(other) + super + #{initialize_copy_setup.join('; ')} + end + RUBY_EVAL + + attr_names.each do |attr_name| + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{attr_name} + @__#{attr_name}.get + end + + def #{attr_name}=(value) + @__#{attr_name}.set(value) + end + + def compare_and_set_#{attr_name}(old_value, new_value) + @__#{attr_name}.compare_and_set(old_value, new_value) + end + RUBY_EVAL + + alias_method :"cas_#{attr_name}", :"compare_and_set_#{attr_name}" + alias_method :"lazy_set_#{attr_name}", :"#{attr_name}=" + end + end) + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb new file mode 100644 index 00000000..c231d182 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb @@ -0,0 +1,50 @@ +require 'concurrent/thread_safe/util' + +module Concurrent + + # @!visibility private + module ThreadSafe + + # @!visibility private + module Util + + # A xorshift random number (positive +Fixnum+s) generator, provides + # reasonably cheap way to generate thread local random numbers without + # contending for the global +Kernel.rand+. + # + # Usage: + # x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed + # while true + # if (x = XorShiftRandom.xorshift).odd? # thread-locally generate a next random number + # do_something_at_random + # end + # end + module XorShiftRandom + extend self + MAX_XOR_SHIFTABLE_INT = MAX_INT - 1 + + # Generates an initial non-zero positive +Fixnum+ via +Kernel.rand+. + def get + Kernel.rand(MAX_XOR_SHIFTABLE_INT) + 1 # 0 can't be xorshifted + end + + # xorshift based on: http://www.jstatsoft.org/v08/i14/paper + if 0.size == 4 + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (3,1,14) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 3 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 14 + end + else + # using the "yˆ=y>>a; yˆ=y<>c;" transform with the (a,b,c) tuple with values (1,1,54) to minimise Bignum overflows + def xorshift(x) + x ^= x >> 1 + x ^= (x << 1) & MAX_INT # cut-off Bignum overflow + x ^= x >> 54 + end + end + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/timer_task.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/timer_task.rb new file mode 100644 index 00000000..d1eb5569 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/timer_task.rb @@ -0,0 +1,366 @@ +require 'concurrent/collection/copy_on_notify_observer_set' +require 'concurrent/concern/dereferenceable' +require 'concurrent/concern/observable' +require 'concurrent/atomic/atomic_boolean' +require 'concurrent/atomic/atomic_fixnum' +require 'concurrent/executor/executor_service' +require 'concurrent/executor/ruby_executor_service' +require 'concurrent/executor/safe_task_executor' +require 'concurrent/scheduled_task' + +module Concurrent + + # A very common concurrency pattern is to run a thread that performs a task at + # regular intervals. The thread that performs the task sleeps for the given + # interval then wakes up and performs the task. Lather, rinse, repeat... This + # pattern causes two problems. First, it is difficult to test the business + # logic of the task because the task itself is tightly coupled with the + # concurrency logic. Second, an exception raised while performing the task can + # cause the entire thread to abend. In a long-running application where the + # task thread is intended to run for days/weeks/years a crashed task thread + # can pose a significant problem. `TimerTask` alleviates both problems. + # + # When a `TimerTask` is launched it starts a thread for monitoring the + # execution interval. The `TimerTask` thread does not perform the task, + # however. Instead, the TimerTask launches the task on a separate thread. + # Should the task experience an unrecoverable crash only the task thread will + # crash. This makes the `TimerTask` very fault tolerant. Additionally, the + # `TimerTask` thread can respond to the success or failure of the task, + # performing logging or ancillary operations. + # + # One other advantage of `TimerTask` is that it forces the business logic to + # be completely decoupled from the concurrency logic. The business logic can + # be tested separately then passed to the `TimerTask` for scheduling and + # running. + # + # A `TimerTask` supports two different types of interval calculations. + # A fixed delay will always wait the same amount of time between the + # completion of one task and the start of the next. A fixed rate will + # attempt to maintain a constant rate of execution regardless of the + # duration of the task. For example, if a fixed rate task is scheduled + # to run every 60 seconds but the task itself takes 10 seconds to + # complete, the next task will be scheduled to run 50 seconds after + # the start of the previous task. If the task takes 70 seconds to + # complete, the next task will be start immediately after the previous + # task completes. Tasks will not be executed concurrently. + # + # In some cases it may be necessary for a `TimerTask` to affect its own + # execution cycle. To facilitate this, a reference to the TimerTask instance + # is passed as an argument to the provided block every time the task is + # executed. + # + # The `TimerTask` class includes the `Dereferenceable` mixin module so the + # result of the last execution is always available via the `#value` method. + # Dereferencing options can be passed to the `TimerTask` during construction or + # at any later time using the `#set_deref_options` method. + # + # `TimerTask` supports notification through the Ruby standard library + # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html + # Observable} module. On execution the `TimerTask` will notify the observers + # with three arguments: time of execution, the result of the block (or nil on + # failure), and any raised exceptions (or nil on success). + # + # @!macro copy_options + # + # @example Basic usage + # task = Concurrent::TimerTask.new{ puts 'Boom!' } + # task.execute + # + # task.execution_interval #=> 60 (default) + # + # # wait 60 seconds... + # #=> 'Boom!' + # + # task.shutdown #=> true + # + # @example Configuring `:execution_interval` + # task = Concurrent::TimerTask.new(execution_interval: 5) do + # puts 'Boom!' + # end + # + # task.execution_interval #=> 5 + # + # @example Immediate execution with `:run_now` + # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' } + # task.execute + # + # #=> 'Boom!' + # + # @example Configuring `:interval_type` with either :fixed_delay or :fixed_rate, default is :fixed_delay + # task = Concurrent::TimerTask.new(execution_interval: 5, interval_type: :fixed_rate) do + # puts 'Boom!' + # end + # task.interval_type #=> :fixed_rate + # + # @example Last `#value` and `Dereferenceable` mixin + # task = Concurrent::TimerTask.new( + # dup_on_deref: true, + # execution_interval: 5 + # ){ Time.now } + # + # task.execute + # Time.now #=> 2013-11-07 18:06:50 -0500 + # sleep(10) + # task.value #=> 2013-11-07 18:06:55 -0500 + # + # @example Controlling execution from within the block + # timer_task = Concurrent::TimerTask.new(execution_interval: 1) do |task| + # task.execution_interval.to_i.times{ print 'Boom! ' } + # print "\n" + # task.execution_interval += 1 + # if task.execution_interval > 5 + # puts 'Stopping...' + # task.shutdown + # end + # end + # + # timer_task.execute + # #=> Boom! + # #=> Boom! Boom! + # #=> Boom! Boom! Boom! + # #=> Boom! Boom! Boom! Boom! + # #=> Boom! Boom! Boom! Boom! Boom! + # #=> Stopping... + # + # @example Observation + # class TaskObserver + # def update(time, result, ex) + # if result + # print "(#{time}) Execution successfully returned #{result}\n" + # else + # print "(#{time}) Execution failed with error #{ex}\n" + # end + # end + # end + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ 42 } + # task.add_observer(TaskObserver.new) + # task.execute + # sleep 4 + # + # #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42 + # #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42 + # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42 + # task.shutdown + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep } + # task.add_observer(TaskObserver.new) + # task.execute + # + # #=> (2013-10-13 19:07:25 -0400) Execution timed out + # #=> (2013-10-13 19:07:27 -0400) Execution timed out + # #=> (2013-10-13 19:07:29 -0400) Execution timed out + # task.shutdown + # + # task = Concurrent::TimerTask.new(execution_interval: 1){ raise StandardError } + # task.add_observer(TaskObserver.new) + # task.execute + # + # #=> (2013-10-13 19:09:37 -0400) Execution failed with error StandardError + # #=> (2013-10-13 19:09:38 -0400) Execution failed with error StandardError + # #=> (2013-10-13 19:09:39 -0400) Execution failed with error StandardError + # task.shutdown + # + # @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html + # @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html + class TimerTask < RubyExecutorService + include Concern::Dereferenceable + include Concern::Observable + + # Default `:execution_interval` in seconds. + EXECUTION_INTERVAL = 60 + + # Maintain the interval between the end of one execution and the start of the next execution. + FIXED_DELAY = :fixed_delay + + # Maintain the interval between the start of one execution and the start of the next. + # If execution time exceeds the interval, the next execution will start immediately + # after the previous execution finishes. Executions will not run concurrently. + FIXED_RATE = :fixed_rate + + # Default `:interval_type` + DEFAULT_INTERVAL_TYPE = FIXED_DELAY + + # Create a new TimerTask with the given task and configuration. + # + # @!macro timer_task_initialize + # @param [Hash] opts the options defining task execution. + # @option opts [Float] :execution_interval number of seconds between + # task executions (default: EXECUTION_INTERVAL) + # @option opts [Boolean] :run_now Whether to run the task immediately + # upon instantiation or to wait until the first # execution_interval + # has passed (default: false) + # @options opts [Symbol] :interval_type method to calculate the interval + # between executions, can be either :fixed_rate or :fixed_delay. + # (default: :fixed_delay) + # @option opts [Executor] executor, default is `global_io_executor` + # + # @!macro deref_options + # + # @raise ArgumentError when no block is given. + # + # @yield to the block after :execution_interval seconds have passed since + # the last yield + # @yieldparam task a reference to the `TimerTask` instance so that the + # block can control its own lifecycle. Necessary since `self` will + # refer to the execution context of the block rather than the running + # `TimerTask`. + # + # @return [TimerTask] the new `TimerTask` + def initialize(opts = {}, &task) + raise ArgumentError.new('no block given') unless block_given? + super + set_deref_options opts + end + + # Is the executor running? + # + # @return [Boolean] `true` when running, `false` when shutting down or shutdown + def running? + @running.true? + end + + # Execute a previously created `TimerTask`. + # + # @return [TimerTask] a reference to `self` + # + # @example Instance and execute in separate steps + # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" } + # task.running? #=> false + # task.execute + # task.running? #=> true + # + # @example Instance and execute in one line + # task = Concurrent::TimerTask.new(execution_interval: 10){ print "Hello World\n" }.execute + # task.running? #=> true + def execute + synchronize do + if @running.false? + @running.make_true + @age.increment + schedule_next_task(@run_now ? 0 : @execution_interval) + end + end + self + end + + # Create and execute a new `TimerTask`. + # + # @!macro timer_task_initialize + # + # @example + # task = Concurrent::TimerTask.execute(execution_interval: 10){ print "Hello World\n" } + # task.running? #=> true + def self.execute(opts = {}, &task) + TimerTask.new(opts, &task).execute + end + + # @!attribute [rw] execution_interval + # @return [Fixnum] Number of seconds after the task completes before the + # task is performed again. + def execution_interval + synchronize { @execution_interval } + end + + # @!attribute [rw] execution_interval + # @return [Fixnum] Number of seconds after the task completes before the + # task is performed again. + def execution_interval=(value) + if (value = value.to_f) <= 0.0 + raise ArgumentError.new('must be greater than zero') + else + synchronize { @execution_interval = value } + end + end + + # @!attribute [r] interval_type + # @return [Symbol] method to calculate the interval between executions + attr_reader :interval_type + + # @!attribute [rw] timeout_interval + # @return [Fixnum] Number of seconds the task can run before it is + # considered to have failed. + def timeout_interval + warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly' + end + + # @!attribute [rw] timeout_interval + # @return [Fixnum] Number of seconds the task can run before it is + # considered to have failed. + def timeout_interval=(value) + warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly' + end + + private :post, :<< + + private + + def ns_initialize(opts, &task) + set_deref_options(opts) + + self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL + if opts[:interval_type] && ![FIXED_DELAY, FIXED_RATE].include?(opts[:interval_type]) + raise ArgumentError.new('interval_type must be either :fixed_delay or :fixed_rate') + end + if opts[:timeout] || opts[:timeout_interval] + warn 'TimeTask timeouts are now ignored as these were not able to be implemented correctly' + end + + @run_now = opts[:now] || opts[:run_now] + @interval_type = opts[:interval_type] || DEFAULT_INTERVAL_TYPE + @task = Concurrent::SafeTaskExecutor.new(task) + @executor = opts[:executor] || Concurrent.global_io_executor + @running = Concurrent::AtomicBoolean.new(false) + @age = Concurrent::AtomicFixnum.new(0) + @value = nil + + self.observers = Collection::CopyOnNotifyObserverSet.new + end + + # @!visibility private + def ns_shutdown_execution + @running.make_false + super + end + + # @!visibility private + def ns_kill_execution + @running.make_false + super + end + + # @!visibility private + def schedule_next_task(interval = execution_interval) + ScheduledTask.execute(interval, executor: @executor, args: [Concurrent::Event.new, @age.value], &method(:execute_task)) + nil + end + + # @!visibility private + def execute_task(completion, age_when_scheduled) + return nil unless @running.true? + return nil unless @age.value == age_when_scheduled + + start_time = Concurrent.monotonic_time + _success, value, reason = @task.execute(self) + if completion.try? + self.value = value + schedule_next_task(calculate_next_interval(start_time)) + time = Time.now + observers.notify_observers do + [time, self.value, reason] + end + end + nil + end + + # @!visibility private + def calculate_next_interval(start_time) + if @interval_type == FIXED_RATE + run_time = Concurrent.monotonic_time - start_time + [execution_interval - run_time, 0].max + else # FIXED_DELAY + execution_interval + end + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tuple.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tuple.rb new file mode 100644 index 00000000..56212cfd --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tuple.rb @@ -0,0 +1,82 @@ +require 'concurrent/atomic/atomic_reference' + +module Concurrent + + # A fixed size array with volatile (synchronized, thread safe) getters/setters. + # Mixes in Ruby's `Enumerable` module for enhanced search, sort, and traversal. + # + # @example + # tuple = Concurrent::Tuple.new(16) + # + # tuple.set(0, :foo) #=> :foo | volatile write + # tuple.get(0) #=> :foo | volatile read + # tuple.compare_and_set(0, :foo, :bar) #=> true | strong CAS + # tuple.cas(0, :foo, :baz) #=> false | strong CAS + # tuple.get(0) #=> :bar | volatile read + # + # @see https://en.wikipedia.org/wiki/Tuple Tuple entry at Wikipedia + # @see http://www.erlang.org/doc/reference_manual/data_types.html#id70396 Erlang Tuple + # @see http://ruby-doc.org/core-2.2.2/Enumerable.html Enumerable + class Tuple + include Enumerable + + # The (fixed) size of the tuple. + attr_reader :size + + # Create a new tuple of the given size. + # + # @param [Integer] size the number of elements in the tuple + def initialize(size) + @size = size + @tuple = tuple = ::Array.new(size) + i = 0 + while i < size + tuple[i] = Concurrent::AtomicReference.new + i += 1 + end + end + + # Get the value of the element at the given index. + # + # @param [Integer] i the index from which to retrieve the value + # @return [Object] the value at the given index or nil if the index is out of bounds + def get(i) + return nil if i >= @size || i < 0 + @tuple[i].get + end + alias_method :volatile_get, :get + + # Set the element at the given index to the given value + # + # @param [Integer] i the index for the element to set + # @param [Object] value the value to set at the given index + # + # @return [Object] the new value of the element at the given index or nil if the index is out of bounds + def set(i, value) + return nil if i >= @size || i < 0 + @tuple[i].set(value) + end + alias_method :volatile_set, :set + + # Set the value at the given index to the new value if and only if the current + # value matches the given old value. + # + # @param [Integer] i the index for the element to set + # @param [Object] old_value the value to compare against the current value + # @param [Object] new_value the value to set at the given index + # + # @return [Boolean] true if the value at the given element was set else false + def compare_and_set(i, old_value, new_value) + return false if i >= @size || i < 0 + @tuple[i].compare_and_set(old_value, new_value) + end + alias_method :cas, :compare_and_set + + # Calls the given block once for each element in self, passing that element as a parameter. + # + # @yieldparam [Object] ref the `Concurrent::AtomicReference` object at the current index + def each + @tuple.each {|ref| yield ref.get} + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tvar.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tvar.rb new file mode 100644 index 00000000..5d02ef09 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/tvar.rb @@ -0,0 +1,222 @@ +require 'set' +require 'concurrent/synchronization/object' + +module Concurrent + + # A `TVar` is a transactional variable - a single-element container that + # is used as part of a transaction - see `Concurrent::atomically`. + # + # @!macro thread_safe_variable_comparison + # + # {include:file:docs-source/tvar.md} + class TVar < Synchronization::Object + safe_initialization! + + # Create a new `TVar` with an initial value. + def initialize(value) + @value = value + @lock = Mutex.new + end + + # Get the value of a `TVar`. + def value + Concurrent::atomically do + Transaction::current.read(self) + end + end + + # Set the value of a `TVar`. + def value=(value) + Concurrent::atomically do + Transaction::current.write(self, value) + end + end + + # @!visibility private + def unsafe_value # :nodoc: + @value + end + + # @!visibility private + def unsafe_value=(value) # :nodoc: + @value = value + end + + # @!visibility private + def unsafe_lock # :nodoc: + @lock + end + + end + + # Run a block that reads and writes `TVar`s as a single atomic transaction. + # With respect to the value of `TVar` objects, the transaction is atomic, in + # that it either happens or it does not, consistent, in that the `TVar` + # objects involved will never enter an illegal state, and isolated, in that + # transactions never interfere with each other. You may recognise these + # properties from database transactions. + # + # There are some very important and unusual semantics that you must be aware of: + # + # * Most importantly, the block that you pass to atomically may be executed + # more than once. In most cases your code should be free of + # side-effects, except for via TVar. + # + # * If an exception escapes an atomically block it will abort the transaction. + # + # * It is undefined behaviour to use callcc or Fiber with atomically. + # + # * If you create a new thread within an atomically, it will not be part of + # the transaction. Creating a thread counts as a side-effect. + # + # Transactions within transactions are flattened to a single transaction. + # + # @example + # a = new TVar(100_000) + # b = new TVar(100) + # + # Concurrent::atomically do + # a.value -= 10 + # b.value += 10 + # end + def atomically + raise ArgumentError.new('no block given') unless block_given? + + # Get the current transaction + + transaction = Transaction::current + + # Are we not already in a transaction (not nested)? + + if transaction.nil? + # New transaction + + begin + # Retry loop + + loop do + + # Create a new transaction + + transaction = Transaction.new + Transaction::current = transaction + + # Run the block, aborting on exceptions + + begin + result = yield + rescue Transaction::AbortError => e + transaction.abort + result = Transaction::ABORTED + rescue Transaction::LeaveError => e + transaction.abort + break result + rescue => e + transaction.abort + raise e + end + # If we can commit, break out of the loop + + if result != Transaction::ABORTED + if transaction.commit + break result + end + end + end + ensure + # Clear the current transaction + + Transaction::current = nil + end + else + # Nested transaction - flatten it and just run the block + + yield + end + end + + # Abort a currently running transaction - see `Concurrent::atomically`. + def abort_transaction + raise Transaction::AbortError.new + end + + # Leave a transaction without committing or aborting - see `Concurrent::atomically`. + def leave_transaction + raise Transaction::LeaveError.new + end + + module_function :atomically, :abort_transaction, :leave_transaction + + private + + # @!visibility private + class Transaction + + ABORTED = ::Object.new + + OpenEntry = Struct.new(:value, :modified) + + AbortError = Class.new(StandardError) + LeaveError = Class.new(StandardError) + + def initialize + @open_tvars = {} + end + + def read(tvar) + entry = open(tvar) + entry.value + end + + def write(tvar, value) + entry = open(tvar) + entry.modified = true + entry.value = value + end + + def open(tvar) + entry = @open_tvars[tvar] + + unless entry + unless tvar.unsafe_lock.try_lock + Concurrent::abort_transaction + end + + entry = OpenEntry.new(tvar.unsafe_value, false) + @open_tvars[tvar] = entry + end + + entry + end + + def abort + unlock + end + + def commit + @open_tvars.each do |tvar, entry| + if entry.modified + tvar.unsafe_value = entry.value + end + end + + unlock + end + + def unlock + @open_tvars.each_key do |tvar| + tvar.unsafe_lock.unlock + end + end + + def self.current + Thread.current[:current_tvar_transaction] + end + + def self.current=(transaction) + Thread.current[:current_tvar_transaction] = transaction + end + + end + +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/engine.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/engine.rb new file mode 100644 index 00000000..0c574b2a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/engine.rb @@ -0,0 +1,45 @@ +module Concurrent + # @!visibility private + module Utility + + # @!visibility private + module EngineDetector + def on_cruby? + RUBY_ENGINE == 'ruby' + end + + def on_jruby? + RUBY_ENGINE == 'jruby' + end + + def on_truffleruby? + RUBY_ENGINE == 'truffleruby' + end + + def on_windows? + !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/).nil? + end + + def on_osx? + !(RbConfig::CONFIG['host_os'] =~ /darwin|mac os/).nil? + end + + def on_linux? + !(RbConfig::CONFIG['host_os'] =~ /linux/).nil? + end + + def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch) + result = (version.split('.').map(&:to_i) <=> [major, minor, patch]) + comparisons = { :== => [0], + :>= => [1, 0], + :<= => [-1, 0], + :> => [1], + :< => [-1] } + comparisons.fetch(comparison).include? result + end + end + end + + # @!visibility private + extend Utility::EngineDetector +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb new file mode 100644 index 00000000..1c987d8a --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb @@ -0,0 +1,19 @@ +module Concurrent + + # @!macro monotonic_get_time + # + # Returns the current time as tracked by the application monotonic clock. + # + # @param [Symbol] unit the time unit to be returned, can be either + # :float_second, :float_millisecond, :float_microsecond, :second, + # :millisecond, :microsecond, or :nanosecond default to :float_second. + # + # @return [Float] The current monotonic time since some unspecified + # starting point + # + # @!macro monotonic_clock_warning + def monotonic_time(unit = :float_second) + Process.clock_gettime(Process::CLOCK_MONOTONIC, unit) + end + module_function :monotonic_time +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb new file mode 100644 index 00000000..bf7bab35 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb @@ -0,0 +1,77 @@ +require 'concurrent/utility/engine' +# Synchronization::AbstractObject must be defined before loading the extension +require 'concurrent/synchronization/abstract_object' + +module Concurrent + # @!visibility private + module Utility + # @!visibility private + module NativeExtensionLoader + + def allow_c_extensions? + Concurrent.on_cruby? + end + + def c_extensions_loaded? + defined?(@c_extensions_loaded) && @c_extensions_loaded + end + + def load_native_extensions + if Concurrent.on_cruby? && !c_extensions_loaded? + ['concurrent/concurrent_ruby_ext', + "concurrent/#{RUBY_VERSION[0..2]}/concurrent_ruby_ext" + ].each { |p| try_load_c_extension p } + end + + if Concurrent.on_jruby? && !java_extensions_loaded? + begin + require 'concurrent/concurrent_ruby.jar' + set_java_extensions_loaded + rescue LoadError => e + raise e, "Java extensions are required for JRuby.\n" + e.message, e.backtrace + end + end + end + + private + + def load_error_path(error) + if error.respond_to? :path + error.path + else + error.message.split(' -- ').last + end + end + + def set_c_extensions_loaded + @c_extensions_loaded = true + end + + def java_extensions_loaded? + defined?(@java_extensions_loaded) && @java_extensions_loaded + end + + def set_java_extensions_loaded + @java_extensions_loaded = true + end + + def try_load_c_extension(path) + require path + set_c_extensions_loaded + rescue LoadError => e + if load_error_path(e) == path + # move on with pure-Ruby implementations + # TODO (pitr-ch 12-Jul-2018): warning on verbose? + else + raise e + end + end + + end + end + + # @!visibility private + extend Utility::NativeExtensionLoader +end + +Concurrent.load_native_extensions diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_integer.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_integer.rb new file mode 100644 index 00000000..de1cdc30 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/native_integer.rb @@ -0,0 +1,54 @@ +module Concurrent + # @!visibility private + module Utility + # @private + module NativeInteger + # http://stackoverflow.com/questions/535721/ruby-max-integer + MIN_VALUE = -(2**(0.size * 8 - 2)) + MAX_VALUE = (2**(0.size * 8 - 2) - 1) + + def ensure_upper_bound(value) + if value > MAX_VALUE + raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}") + end + value + end + + def ensure_lower_bound(value) + if value < MIN_VALUE + raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}") + end + value + end + + def ensure_integer(value) + unless value.is_a?(Integer) + raise ArgumentError.new("#{value} is not an Integer") + end + value + end + + def ensure_integer_and_bounds(value) + ensure_integer value + ensure_upper_bound value + ensure_lower_bound value + end + + def ensure_positive(value) + if value < 0 + raise ArgumentError.new("#{value} cannot be negative") + end + value + end + + def ensure_positive_and_no_zero(value) + if value < 1 + raise ArgumentError.new("#{value} cannot be negative or zero") + end + value + end + + extend self + end + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/processor_counter.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/processor_counter.rb new file mode 100644 index 00000000..2489cbd7 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/utility/processor_counter.rb @@ -0,0 +1,220 @@ +require 'etc' +require 'rbconfig' +require 'concurrent/delay' + +module Concurrent + # @!visibility private + module Utility + + # @!visibility private + class ProcessorCounter + def initialize + @processor_count = Delay.new { compute_processor_count } + @physical_processor_count = Delay.new { compute_physical_processor_count } + @cpu_quota = Delay.new { compute_cpu_quota } + @cpu_shares = Delay.new { compute_cpu_shares } + end + + def processor_count + @processor_count.value + end + + def physical_processor_count + @physical_processor_count.value + end + + def available_processor_count + cpu_count = processor_count.to_f + quota = cpu_quota + + return cpu_count if quota.nil? + + # cgroup cpus quotas have no limits, so they can be set to higher than the + # real count of cores. + if quota > cpu_count + cpu_count + else + quota + end + end + + def cpu_quota + @cpu_quota.value + end + + def cpu_shares + @cpu_shares.value + end + + private + + def compute_processor_count + if Concurrent.on_jruby? + java.lang.Runtime.getRuntime.availableProcessors + else + Etc.nprocessors + end + end + + def compute_physical_processor_count + ppc = case RbConfig::CONFIG["target_os"] + when /darwin\d\d/ + IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i + when /linux/ + cores = {} # unique physical ID / core ID combinations + phy = 0 + IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln| + if ln.start_with?("physical") + phy = ln[/\d+/] + elsif ln.start_with?("core") + cid = phy + ":" + ln[/\d+/] + cores[cid] = true if not cores[cid] + end + end + cores.count + when /mswin|mingw/ + # Get-CimInstance introduced in PowerShell 3 or earlier: https://learn.microsoft.com/en-us/previous-versions/powershell/module/cimcmdlets/get-ciminstance?view=powershell-3.0 + result = run('powershell -command "Get-CimInstance -ClassName Win32_Processor -Property NumberOfCores | Select-Object -Property NumberOfCores"') + if !result || $?.exitstatus != 0 + # fallback to deprecated wmic for older systems + result = run("wmic cpu get NumberOfCores") + end + if !result || $?.exitstatus != 0 + # Bail out if both commands returned something unexpected + processor_count + else + # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n" + # wmic: "NumberOfCores \n\n4 \n\n\n\n" + result.scan(/\d+/).map(&:to_i).reduce(:+) + end + else + processor_count + end + # fall back to logical count if physical info is invalid + ppc > 0 ? ppc : processor_count + rescue + return 1 + end + + def run(command) + IO.popen(command, &:read) + rescue Errno::ENOENT + end + + def compute_cpu_quota + if RbConfig::CONFIG["target_os"].include?("linux") + if File.exist?("/sys/fs/cgroup/cpu.max") + # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files + cpu_max = File.read("/sys/fs/cgroup/cpu.max") + return nil if cpu_max.start_with?("max ") # no limit + max, period = cpu_max.split.map(&:to_f) + max / period + elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us") + # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt + max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i + # If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions + # https://docs.kernel.org/scheduler/sched-bwc.html#management + return nil if max <= 0 + period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f + max / period + end + end + end + + def compute_cpu_shares + if RbConfig::CONFIG["target_os"].include?("linux") + if File.exist?("/sys/fs/cgroup/cpu.weight") + # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files + # Ref: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2254-cgroup-v2#phase-1-convert-from-cgroups-v1-settings-to-v2 + weight = File.read("/sys/fs/cgroup/cpu.weight").to_f + ((((weight - 1) * 262142) / 9999) + 2) / 1024 + elsif File.exist?("/sys/fs/cgroup/cpu/cpu.shares") + # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt + File.read("/sys/fs/cgroup/cpu/cpu.shares").to_f / 1024 + end + end + end + end + end + + # create the default ProcessorCounter on load + @processor_counter = Utility::ProcessorCounter.new + singleton_class.send :attr_reader, :processor_counter + + # Number of processors seen by the OS and used for process scheduling. For + # performance reasons the calculated value will be memoized on the first + # call. + # + # When running under JRuby the Java runtime call + # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According + # to the Java documentation this "value may change during a particular + # invocation of the virtual machine... [applications] should therefore + # occasionally poll this property." We still memoize this value once under + # JRuby. + # + # Otherwise Ruby's Etc.nprocessors will be used. + # + # @return [Integer] number of processors seen by the OS or Java runtime + # + # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors() + def self.processor_count + processor_counter.processor_count + end + + # Number of physical processor cores on the current system. For performance + # reasons the calculated value will be memoized on the first call. + # + # On Windows the Win32 API will be queried for the `NumberOfCores from + # Win32_Processor`. This will return the total number "of cores for the + # current instance of the processor." On Unix-like operating systems either + # the `hwprefs` or `sysctl` utility will be called in a subshell and the + # returned value will be used. In the rare case where none of these methods + # work or an exception is raised the function will simply return 1. + # + # @return [Integer] number physical processor cores on the current system + # + # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb + # + # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx + # @see http://www.unix.com/man-page/osx/1/HWPREFS/ + # @see http://linux.die.net/man/8/sysctl + def self.physical_processor_count + processor_counter.physical_processor_count + end + + # Number of processors cores available for process scheduling. + # This method takes in account the CPU quota if the process is inside a cgroup with a + # dedicated CPU quota (typically Docker). + # Otherwise it returns the same value as #processor_count but as a Float. + # + # For performance reasons the calculated value will be memoized on the first + # call. + # + # @return [Float] number of available processors + def self.available_processor_count + processor_counter.available_processor_count + end + + # The maximum number of processors cores available for process scheduling. + # Returns `nil` if there is no enforced limit, or a `Float` if the + # process is inside a cgroup with a dedicated CPU quota (typically Docker). + # + # Note that nothing prevents setting a CPU quota higher than the actual number of + # cores on the system. + # + # For performance reasons the calculated value will be memoized on the first + # call. + # + # @return [nil, Float] Maximum number of available processors as set by a cgroup CPU quota, or nil if none set + def self.cpu_quota + processor_counter.cpu_quota + end + + # The CPU shares requested by the process. For performance reasons the calculated + # value will be memoized on the first call. + # + # @return [Float, nil] CPU shares requested by the process, or nil if not set + def self.cpu_shares + processor_counter.cpu_shares + end +end diff --git a/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/version.rb b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/version.rb new file mode 100644 index 00000000..a4cd88a4 --- /dev/null +++ b/bin/gems/concurrent-ruby-1.3.8/lib/concurrent-ruby/concurrent/version.rb @@ -0,0 +1,3 @@ +module Concurrent + VERSION = '1.3.8' +end diff --git a/bin/gems/console-1.29.3/bake/console.rb b/bin/gems/console-1.29.3/bake/console.rb new file mode 100644 index 00000000..6f045d80 --- /dev/null +++ b/bin/gems/console-1.29.3/bake/console.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. + +# Increase the verbosity of the logger to info. +def info + require_relative "../lib/console" + + Console.logger.info! +end + +# Increase the verbosity of the logger to debug. +def debug + require_relative "../lib/console" + + Console.logger.debug! +end diff --git a/bin/gems/console-1.29.3/lib/console.rb b/bin/gems/console-1.29.3/lib/console.rb new file mode 100644 index 00000000..2ddf3b39 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2019, by Bryan Powell. +# Copyright, 2020, by Michael Adams. +# Copyright, 2021, by Cédric Boutillier. + +require_relative "console/version" +require_relative "console/interface" + +module Console + Console.extend(Interface) +end diff --git a/bin/gems/console-1.29.3/lib/console/adapter.rb b/bin/gems/console-1.29.3/lib/console/adapter.rb new file mode 100644 index 00000000..b483ae18 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/adapter.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023-2024, by Samuel Williams. + +module Console + # This namespace is reserved for logging adapters provided by other gems. + module Adapter + end +end diff --git a/bin/gems/console-1.29.3/lib/console/capture.rb b/bin/gems/console-1.29.3/lib/console/capture.rb new file mode 100644 index 00000000..10afc437 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/capture.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "filter" +require_relative "output/failure" + +module Console + # A general sink which captures all events into a buffer. + class Capture + def initialize + @records = [] + @verbose = false + end + + attr :records + + # @deprecated Use {#records} instead of {#buffer}. + alias buffer records + + alias to_a records + + attr :verbose + + def include?(pattern) + @records.any? do |record| + record[:subject].to_s&.match?(pattern) or record[:message].to_s&.match?(pattern) + end + end + + def each(&block) + @records.each(&block) + end + + include Enumerable + + def first + @records.first + end + + def last + @records.last + end + + def clear + @records.clear + end + + def empty? + @records.empty? + end + + def verbose!(value = true) + @verbose = value + end + + def verbose? + @verbose + end + + def call(subject = nil, *arguments, severity: UNKNOWN, event: nil, **options, &block) + record = { + time: ::Time.now.iso8601, + severity: severity, + **options, + } + + if subject + record[:subject] = subject + end + + if event + record[:event] = event.to_hash + end + + if arguments.any? + record[:arguments] = arguments + end + + if annotation = Fiber.current.annotation + record[:annotation] = annotation + end + + if block_given? + if block.arity.zero? + record[:message] = yield + else + buffer = StringIO.new + yield buffer + record[:message] = buffer.string + end + else + record[:message] = arguments.join(" ") + end + + @records << record + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/clock.rb b/bin/gems/console-1.29.3/lib/console/clock.rb new file mode 100644 index 00000000..608ac500 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/clock.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2022, by Samuel Williams. + +module Console + module Clock + def self.formatted_duration(duration) + if duration < 60.0 + return "#{duration.round(2)}s" + end + + duration /= 60.0 + + if duration < 60.0 + return "#{duration.floor}m" + end + + duration /= 60.0 + + if duration < 24.0 + return "#{duration.floor}h" + end + + duration /= 24.0 + + return "#{duration.floor}d" + end + + # Get the current elapsed monotonic time. + def self.now + ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/compatible/logger.rb b/bin/gems/console-1.29.3/lib/console/compatible/logger.rb new file mode 100644 index 00000000..05e01995 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/compatible/logger.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. + +require "logger" + +module Console + module Compatible + # A compatible interface for {::Logger} which can be used with {Console}. + class Logger < ::Logger + class LogDevice + def initialize(subject, output) + @subject = subject + @output = output + end + + def write(message) + @output.call(@subject, message) + end + + def call(*arguments, **options) + @output.call(*arguments, **options) + end + + def reopen + end + + def close + end + end + + def initialize(subject, output = Console) + super(nil) + + @progname = subject + @logdev = LogDevice.new(subject, output) + end + + def add(severity, message = nil, progname = nil) + severity ||= UNKNOWN + + if @logdev.nil? or severity < level + return true + end + + if progname.nil? + progname = @progname + end + + if message.nil? + if block_given? + message = yield + else + message = progname + progname = @progname + end + end + + @logdev.call( + progname, message, + severity: format_severity(severity) + ) + + return true + end + + def format_severity(value) + super.downcase.to_sym + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/event.rb b/bin/gems/console-1.29.3/lib/console/event.rb new file mode 100644 index 00000000..5d904f73 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/event.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "event/spawn" +require_relative "event/failure" diff --git a/bin/gems/console-1.29.3/lib/console/event/failure.rb b/bin/gems/console-1.29.3/lib/console/event/failure.rb new file mode 100644 index 00000000..62bce169 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/event/failure.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2021, by Robert Schulze. +# Copyright, 2024, by Patrik Wenger. + +require_relative "generic" + +module Console + module Event + # Represents a failure event. + # + # ```ruby + # Console::Event::Failure.for(exception).emit(self) + # ``` + class Failure < Generic + def self.default_root + Dir.getwd + rescue # e.g. Errno::EMFILE + nil + end + + def self.for(exception) + self.new(exception, self.default_root) + end + + def self.log(subject, exception, **options) + Console.error(subject, **self.for(exception).to_hash, **options) + end + + attr_reader :exception + + def initialize(exception, root = Dir.getwd) + @exception = exception + @root = root + end + + def to_hash + Hash.new.tap do |hash| + hash[:type] = :failure + hash[:root] = @root if @root + extract(@exception, hash) + end + end + + def emit(*arguments, **options) + options[:severity] ||= :error + + super + end + + private + + def extract(exception, hash) + hash[:class] = exception.class.name + + if exception.respond_to?(:detailed_message) + message = exception.detailed_message + + # We want to remove the trailling exception class as we format it differently: + message.sub!(/\s*\(.*?\)$/, "") + + hash[:message] = message + else + hash[:message] = exception.message + end + + hash[:backtrace] = exception.backtrace + + if cause = exception.cause + hash[:cause] = Hash.new.tap do |cause_hash| + extract(cause, cause_hash) + end + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/event/generic.rb b/bin/gems/console-1.29.3/lib/console/event/generic.rb new file mode 100644 index 00000000..0dccfc88 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/event/generic.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +module Console + module Event + class Generic + def as_json(...) + to_hash + end + + def to_json(...) + JSON.generate(as_json, ...) + end + + def to_s + to_json + end + + def emit(*arguments, **options) + Console.call(*arguments, event: self, **options) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/event/spawn.rb b/bin/gems/console-1.29.3/lib/console/event/spawn.rb new file mode 100644 index 00000000..5b458e11 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/event/spawn.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "generic" +require_relative "../clock" + +module Console + module Event + # Represents a spawn event. + # + # ```ruby + # Console.info(self, **Console::Event::Spawn.for("ls", "-l")) + # + # event = Console::Event::Spawn.for("ls", "-l") + # event.status = Process.wait + # ``` + class Spawn < Generic + def self.for(*arguments, **options) + # Extract out the command environment: + if arguments.first.is_a?(Hash) + environment = arguments.shift + self.new(environment, arguments, options) + else + self.new(nil, arguments, options) + end + end + + def initialize(environment, arguments, options) + @environment = environment + @arguments = arguments + @options = options + + @start_time = Clock.now + + @end_time = nil + @status = nil + end + + def duration + if @end_time + @end_time - @start_time + end + end + + def to_hash + Hash.new.tap do |hash| + hash[:type] = :spawn + hash[:environment] = @environment if @environment&.any? + hash[:arguments] = @arguments if @arguments&.any? + hash[:options] = @options if @options&.any? + + hash[:status] = @status.to_i if @status + + if duration = self.duration + hash[:duration] = duration + end + end + end + + def emit(*arguments, **options) + options[:severity] ||= :info + super + end + + def status=(status) + @end_time = Time.now + @status = status + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/filter.rb b/bin/gems/console-1.29.3/lib/console/filter.rb new file mode 100644 index 00000000..5fb240b9 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/filter.rb @@ -0,0 +1,159 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2019, by Bryan Powell. +# Copyright, 2020, by Michael Adams. +# Copyright, 2021, by Robert Schulze. + +module Console + UNKNOWN = :unknown + + class Filter + if Object.const_defined?(:Ractor) and RUBY_VERSION >= "3.1" + def self.define_immutable_method(name, &block) + block = Ractor.make_shareable(block) + self.define_method(name, &block) + end + else + def self.define_immutable_method(name, &block) + define_method(name, &block) + end + end + + def self.[] **levels + klass = Class.new(self) + minimum_level, maximum_level = levels.values.minmax + + klass.instance_exec do + const_set(:LEVELS, levels.freeze) + const_set(:MINIMUM_LEVEL, minimum_level) + const_set(:MAXIMUM_LEVEL, maximum_level) + + levels.each do |name, level| + const_set(name.to_s.upcase, level) + + define_immutable_method(name) do |subject = nil, *arguments, **options, &block| + if self.enabled?(subject, level) + @output.call(subject, *arguments, severity: name, **@options, **options, &block) + end + + return nil + end + + define_immutable_method("#{name}!") do + @level = level + end + + define_immutable_method("#{name}?") do + @level <= level + end + end + end + + return klass + end + + def initialize(output, verbose: true, level: self.class::DEFAULT_LEVEL, **options) + @output = output + @verbose = verbose + @level = level + + @subjects = {} + + @options = options + end + + def with(level: @level, verbose: @verbose, **options) + dup.tap do |logger| + logger.level = level + logger.verbose! if verbose + logger.options = @options.merge(options) + end + end + + attr_accessor :output + attr :verbose + attr :level + + attr :subjects + + attr_accessor :options + + def level= level + if level.is_a? Symbol + @level = self.class::LEVELS[level] + else + @level = level + end + end + + def verbose!(value = true) + @verbose = value + @output.verbose!(value) + end + + def off! + @level = self.class::MAXIMUM_LEVEL + 1 + end + + def all! + @level = self.class::MINIMUM_LEVEL - 1 + end + + def filter(subject, level) + unless subject.is_a?(Module) + raise ArgumentError, "Expected a class, got #{subject.inspect}" + end + + @subjects[subject] = level + end + + # You can enable and disable logging for classes. This function checks if logging for a given subject is enabled. + # @param subject [Object] the subject to check. + def enabled?(subject, level = self.class::MINIMUM_LEVEL) + subject = subject.class unless subject.is_a?(Module) + + if specific_level = @subjects[subject] + return level >= specific_level + end + + if level >= @level + return true + end + end + + # Enable specific log level for the given class. + # @parameter name [Module] The class to enable. + def enable(subject, level = self.class::MINIMUM_LEVEL) + # Set the filter level of logging for a given subject which passes all log messages: + filter(subject, level) + end + + def disable(subject) + # Set the filter level of the logging for a given subject which filters all log messages: + filter(subject, self.class::MAXIMUM_LEVEL + 1) + end + + # Clear any specific filters for the given class. + # @parameter name [Module] The class to disable. + def clear(subject) + unless subject.is_a?(Module) + raise ArgumentError, "Expected a class, got #{subject.inspect}" + end + + @subjects.delete(subject) + end + + def call(subject, *arguments, **options, &block) + severity = options[:severity] || UNKNOWN + level = self.class::LEVELS[severity] + + if self.enabled?(subject, level) + @output.call(subject, *arguments, **options, &block) + end + + return nil + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/format.rb b/bin/gems/console-1.29.3/lib/console/format.rb new file mode 100644 index 00000000..432e8227 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/format.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023-2024, by Samuel Williams. + +require_relative "format/safe" + +module Console + module Format + def self.default + Safe.new(format: ::JSON) + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/format/safe.rb b/bin/gems/console-1.29.3/lib/console/format/safe.rb new file mode 100644 index 00000000..43f4cf29 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/format/safe.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023-2024, by Samuel Williams. + +require "json" + +module Console + module Format + # This class is used to safely dump objects. + # It will attempt to dump the object using the given format, but if it fails, it will generate a safe version of the object. + class Safe + def initialize(format: ::JSON, limit: 8, encoding: ::Encoding::UTF_8) + @format = format + @limit = limit + @encoding = encoding + end + + def dump(object) + @format.dump(object, @limit) + rescue SystemStackError, StandardError => error + @format.dump(safe_dump(object, error)) + end + + private + + def filter_backtrace(error) + frames = error.backtrace + filtered = {} + filtered_count = nil + skipped = nil + + frames = frames.filter_map do |frame| + if filtered[frame] + if filtered_count == nil + filtered_count = 1 + skipped = frame.dup + else + filtered_count += 1 + nil + end + else + if skipped + if filtered_count > 1 + skipped.replace("[... #{filtered_count} frames skipped ...]") + end + + filtered_count = nil + skipped = nil + end + + filtered[frame] = true + frame + end + end + + if skipped && filtered_count > 1 + skipped.replace("[... #{filtered_count} frames skipped ...]") + end + + return frames + end + + def safe_dump(object, error) + object = safe_dump_recurse(object) + + object[:truncated] = true + object[:error] = { + class: safe_dump_recurse(error.class.name), + message: safe_dump_recurse(error.message), + backtrace: safe_dump_recurse(filter_backtrace(error)), + } + + return object + end + + def replacement_for(object) + case object + when Array + "[...]" + when Hash + "{...}" + else + "..." + end + end + + def default_objects + Hash.new.compare_by_identity + end + + # This will recursively generate a safe version of the object. + # Nested hashes and arrays will be transformed recursively. + # Strings will be encoded with the given encoding. + # Primitive values will be returned as-is. + # Other values will be converted using `as_json` if available, otherwise `to_s`. + def safe_dump_recurse(object, limit = @limit, objects = default_objects) + if limit <= 0 || objects[object] + return replacement_for(object) + end + + case object + when Hash + objects[object] = true + + object.to_h do |key, value| + [ + String(key).encode(@encoding, invalid: :replace, undef: :replace), + safe_dump_recurse(value, limit - 1, objects) + ] + end + when Array + objects[object] = true + + object.map do |value| + safe_dump_recurse(value, limit - 1, objects) + end + when String + object.encode(@encoding, invalid: :replace, undef: :replace) + when Numeric, TrueClass, FalseClass, NilClass + object + else + objects[object] = true + + # We could do something like this but the chance `as_json` will blow up. + # We'd need to be extremely careful about it. + # if object.respond_to?(:as_json) + # safe_dump_recurse(object.as_json, limit - 1, objects) + # else + + safe_dump_recurse(object.to_s, limit - 1, objects) + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/interface.rb b/bin/gems/console-1.29.3/lib/console/interface.rb new file mode 100644 index 00000000..966d3c80 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/interface.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024-2025, by Samuel Williams. + +require_relative "logger" + +module Console + # The public logger interface. + module Interface + # Get the current logger instance. + def logger + Logger.instance + end + + # Set the current logger instance. + # + # The current logger instance is assigned per-fiber. + def logger= instance + Logger.instance= instance + end + + # Emit a debug log message. + def debug(...) + Logger.instance.debug(...) + end + + # Emit an informational log message. + def info(...) + Logger.instance.info(...) + end + + # Emit a warning log message. + def warn(...) + Logger.instance.warn(...) + end + + # Emit an error log message. + def error(...) + Logger.instance.error(...) + end + + # Emit a fatal log message. + def fatal(...) + Logger.instance.fatal(...) + end + + # Emit a log message with arbitrary arguments and options. + def call(...) + Logger.instance.call(...) + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/logger.rb b/bin/gems/console-1.29.3/lib/console/logger.rb new file mode 100644 index 00000000..8d0ea028 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/logger.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2021, by Bryan Powell. +# Copyright, 2021, by Robert Schulze. + +require_relative "output" +require_relative "output/failure" + +require_relative "filter" +require_relative "event" +require_relative "resolver" +require_relative "progress" + +require "fiber/local" + +module Console + class Logger < Filter[debug: 0, info: 1, warn: 2, error: 3, fatal: 4] + extend Fiber::Local + + # Set the default log level based on `$DEBUG` and `$VERBOSE`. + # You can also specify CONSOLE_LEVEL=debug or CONSOLE_LEVEL=info in environment. + # https://mislav.net/2011/06/ruby-verbose-mode/ has more details about how it all fits together. + def self.default_log_level(env = ENV) + if level = env["CONSOLE_LEVEL"] + LEVELS[level.to_sym] || level.to_i + elsif $DEBUG + DEBUG + elsif $VERBOSE.nil? + WARN + else + INFO + end + end + + # Controls verbose output using `$VERBOSE`. + def self.verbose?(env = ENV) + !$VERBOSE.nil? || env["CONSOLE_VERBOSE"] + end + + def self.default_logger(output = $stderr, env = ENV, **options) + if options[:verbose].nil? + options[:verbose] = self.verbose?(env) + end + + if options[:level].nil? + options[:level] = self.default_log_level(env) + end + + output = Output.new(output, env, **options) + + logger = self.new(output, **options) + + Resolver.default_resolver(logger) + + return logger + end + + def self.local + self.default_logger + end + + DEFAULT_LEVEL = 1 + + def initialize(output, **options) + # This is the expected default behaviour, but it may be nice to have a way to override it. + output = Output::Failure.new(output, **options) + + super(output, **options) + end + + def progress(subject, total, **options) + options[:severity] ||= :info + + Progress.new(subject, total, **options) + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output.rb b/bin/gems/console-1.29.3/lib/console/output.rb new file mode 100644 index 00000000..cef7e490 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +require_relative "output/default" +require_relative "output/serialized" +require_relative "output/terminal" +require_relative "output/null" + +module Console + module Output + def self.new(output = nil, env = ENV, **options) + if names = env["CONSOLE_OUTPUT"] + names = names.split(",").reverse + + names.inject(output) do |output, name| + Output.const_get(name).new(output, **options) + end + else + return Output::Default.new(output, **options) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/default.rb b/bin/gems/console-1.29.3/lib/console/output/default.rb new file mode 100644 index 00000000..a4de2641 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/default.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +require_relative "terminal" +require_relative "serialized" +require_relative "failure" + +module Console + module Output + module Default + def self.new(output, **options) + output ||= $stderr + + if output.tty? + output = Terminal.new(output, **options) + else + output = Serialized.new(output, **options) + end + + return output + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/failure.rb b/bin/gems/console-1.29.3/lib/console/output/failure.rb new file mode 100644 index 00000000..3d0364a8 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/failure.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024-2025, by Samuel Williams. + +require_relative "wrapper" +require_relative "../event/failure" + +module Console + module Output + # A wrapper for outputting failure messages, which can include exceptions. + class Failure < Wrapper + def initialize(output, **options) + super(output, **options) + end + + # The exception must be either the last argument or passed as an option. + def call(subject = nil, *arguments, exception: nil, **options, &block) + if exception.nil? + last = arguments.last + if last.is_a?(Exception) + options[:event] = Event::Failure.for(last) + end + elsif exception.is_a?(Exception) + options[:event] = Event::Failure.for(exception) + else + # We don't know what this is, so we just pass it through: + options[:exception] = exception + end + + super(subject, *arguments, **options) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/null.rb b/bin/gems/console-1.29.3/lib/console/output/null.rb new file mode 100644 index 00000000..b1839a58 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/null.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023-2024, by Samuel Williams. + +module Console + module Output + class Null + def initialize(...) + end + + def last_output + self + end + + def call(...) + # Do nothing. + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/sensitive.rb b/bin/gems/console-1.29.3/lib/console/output/sensitive.rb new file mode 100644 index 00000000..976add89 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/sensitive.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +require_relative "wrapper" + +module Console + module Output + class Sensitive < Wrapper + REDACT = / + phone + | email + | full_?name + | first_?name + | last_?name + + | device_name + | user_agent + + | zip + | address + | location + | latitude + | longitude + + | ip + | gps + + | sex + | gender + + | token + | password + /xi + + def initialize(output, redact: REDACT, **options) + super(output, **options) + + @redact = redact + end + + def redact?(text) + text.match?(@redact) + end + + def redact_hash(arguments, filter) + arguments.transform_values do |value| + redact(value, filter) + end + end + + def redact_array(array, filter) + array.map do |value| + redact(value, filter) + end + end + + def redact(argument, filter) + case argument + when String + if filter + filter.call(argument) + elsif redact?(argument) + "[REDACTED]" + else + argument + end + when Array + redact_array(argument, filter) + when Hash + redact_hash(argument, filter) + else + redact(argument.to_s, filter) + end + end + + class Filter + def initialize(substitutions) + @substitutions = substitutions + @pattern = Regexp.union(substitutions.keys) + end + + def call(text) + text.gsub(@pattern, @substitutions) + end + end + + def call(subject = nil, *arguments, sensitive: true, **options, &block) + if sensitive + if sensitive.respond_to?(:call) + filter = sensitive + elsif sensitive.is_a?(Hash) + filter = Filter.new(sensitive) + end + + subject = redact(subject, filter) + arguments = redact_array(arguments, filter) + end + + super(subject, *arguments, **options) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/serialized.rb b/bin/gems/console-1.29.3/lib/console/output/serialized.rb new file mode 100644 index 00000000..14485f67 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/serialized.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2025, by Samuel Williams. + +require_relative "../format" +require "time" +require "fiber/annotation" + +module Console + module Output + class Serialized + def initialize(io, format: Format.default, **options) + @io = io + @format = format + end + + # This a final output that then writes to an IO object. + def last_output + self + end + + attr :io + attr :format + + def dump(record) + @format.dump(record) + end + + def call(subject = nil, *arguments, severity: UNKNOWN, **options, &block) + record = { + time: Time.now.iso8601, + severity: severity, + oid: subject.object_id, + pid: Process.pid, + } + + # We want to log just a brief subject: + if subject.is_a?(String) + record[:subject] = subject + elsif subject.is_a?(Module) + record[:subject] = subject.name + else + record[:subject] = subject.class.name + end + + if annotation = Fiber.current.annotation + record[:annotation] = annotation + end + + message = arguments + + if block_given? + if block.arity.zero? + message << yield + else + buffer = StringIO.new + yield buffer + message << buffer.string + end + end + + if message.size == 1 + record[:message] = message.first + elsif message.any? + record[:message] = message + end + + record.update(options) + + @io.write(self.dump(record) << "\n") + end + end + + JSON = Serialized + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/split.rb b/bin/gems/console-1.29.3/lib/console/output/split.rb new file mode 100644 index 00000000..d3c3691d --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/split.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. + +module Console + module Output + class Split + def self.[](*outputs) + self.new(outputs) + end + + def initialize(outputs) + @outputs = outputs + end + + def verbose!(value = true) + @outputs.each{|output| output.verbose!(value)} + end + + def call(...) + @outputs.each do |output| + output.call(...) + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/terminal.rb b/bin/gems/console-1.29.3/lib/console/output/terminal.rb new file mode 100644 index 00000000..2e297d9c --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/terminal.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2021, by Robert Schulze. + +require_relative "../clock" +require_relative "../terminal" + +require "json" +require "fiber" +require "fiber/annotation" +require "stringio" + +module Console + module Output + class Terminal + class Buffer < StringIO + def initialize(prefix = nil) + @prefix = prefix + + super() + end + + attr :prefix + + def puts(*args, prefix: @prefix) + args.each do |arg| + self.write(prefix) if prefix + super(arg) + end + end + + alias << puts + end + + # This, and all related methods, is considered private. + CONSOLE_START_AT = "CONSOLE_START_AT" + + # Exports CONSOLE_START which can be used to synchronize the start times of all child processes when they log using delta time. + def self.start_at!(environment = ENV) + if time_string = environment[CONSOLE_START_AT] + start_at = Time.parse(time_string) rescue nil + end + + unless start_at + start_at = Time.now + environment[CONSOLE_START_AT] = start_at.to_s + end + + return start_at + end + + def initialize(output, verbose: nil, start_at: Terminal.start_at!, format: nil, **options) + @io = output + @start_at = start_at + + @terminal = format.nil? ? Console::Terminal.for(@io) : format.new(@io) + + if verbose.nil? + @verbose = !@terminal.colors? + else + @verbose = verbose + end + + @terminal[:logger_suffix] ||= @terminal.style(:white, nil, :faint) + @terminal[:subject] ||= @terminal.style(nil, nil, :bold) + @terminal[:debug] = @terminal.style(:cyan) + @terminal[:info] = @terminal.style(:green) + @terminal[:warn] = @terminal.style(:yellow) + @terminal[:error] = @terminal.style(:red) + @terminal[:fatal] = @terminal[:error] + + @terminal[:annotation] = @terminal.reset + @terminal[:value] = @terminal.style(:blue) + + @formatters = {} + self.register_formatters + end + + # This a final output that then writes to an IO object. + def last_output + self + end + + attr :io + + attr_accessor :verbose + + attr :start + attr :terminal + + def verbose!(value = true) + @verbose = value + end + + def register_formatters(namespace = Console::Terminal::Formatter) + namespace.constants.each do |name| + formatter = namespace.const_get(name) + @formatters[formatter::KEY] = formatter.new(@terminal) + end + end + + UNKNOWN = :unknown + + def call(subject = nil, *arguments, name: nil, severity: UNKNOWN, event: nil, **options, &block) + width = @terminal.width + + prefix = build_prefix(name || severity.to_s) + indent = " " * prefix.size + + buffer = Buffer.new("#{indent}| ") + indent_size = buffer.prefix.size + + format_subject(severity, prefix, subject, buffer) + + arguments.each do |argument| + format_argument(argument, buffer) + end + + if block_given? + if block.arity.zero? + format_argument(yield, buffer) + else + yield(buffer, @terminal) + end + end + + if event + format_event(event, buffer, width - indent_size) + end + + if options&.any? + format_options(options, buffer) + end + + @io.write buffer.string + end + + protected + + def format_event(event, buffer, width) + event = event.to_hash + type = event[:type] + + if formatter = @formatters[type] + formatter.format(event, buffer, verbose: @verbose, width: width) + else + format_value(::JSON.pretty_generate(event), buffer) + end + end + + def format_options(options, output) + format_value(::JSON.pretty_generate(options), output) + end + + def format_argument(argument, output) + argument.to_s.each_line do |line| + output.puts line + end + end + + def format_subject(severity, prefix, subject, buffer) + if subject.is_a?(String) + format_string_subject(severity, prefix, subject, buffer) + elsif subject.is_a?(Module) + format_string_subject(severity, prefix, subject.to_s, buffer) + else + format_object_subject(severity, prefix, subject, buffer) + end + end + + def default_suffix(object = nil) + buffer = +"" + + if @verbose + if annotation = Fiber.current.annotation + # While typically annotations should be strings, that is not always the case. + annotation = annotation.to_s + + # If the annotation is empty, we don't want to print it, as it will look like a formatting bug. + if annotation.size > 0 + buffer << ": #{@terminal[:annotation]}#{annotation}#{@terminal.reset}" + end + end + end + + buffer << " #{@terminal[:logger_suffix]}" + + if object + buffer << "[oid=0x#{object.object_id.to_s(16)}] " + end + + buffer << "[ec=0x#{Fiber.current.object_id.to_s(16)}] [pid=#{Process.pid}] [#{::Time.now}]#{@terminal.reset}" + + return buffer + end + + def format_object_subject(severity, prefix, subject, output) + prefix_style = @terminal[severity] + + if @verbose + suffix = default_suffix(subject) + end + + prefix = "#{prefix_style}#{prefix}:#{@terminal.reset} " + + output.puts "#{@terminal[:subject]}#{subject.class}#{@terminal.reset}#{suffix}", prefix: prefix + end + + def format_string_subject(severity, prefix, subject, output) + prefix_style = @terminal[severity] + + if @verbose + suffix = default_suffix + end + + prefix = "#{prefix_style}#{prefix}:#{@terminal.reset} " + + output.puts "#{@terminal[:subject]}#{subject}#{@terminal.reset}#{suffix}", prefix: prefix + end + + def format_value(value, output) + string = value.to_s + + string.each_line do |line| + line.chomp! + output.puts "#{@terminal[:value]}#{line}#{@terminal.reset}" + end + end + + def time_offset_prefix + Clock.formatted_duration(Time.now - @start_at).rjust(6) + end + + def build_prefix(name) + if @verbose + "#{time_offset_prefix} #{name.rjust(8)}" + else + time_offset_prefix + end + end + end + + module Text + def self.new(output, **options) + Terminal.new(output, format: Console::Terminal::Text, **options) + end + end + + module XTerm + def self.new(output, **options) + Terminal.new(output, format: Console::Terminal::XTerm, **options) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/output/wrapper.rb b/bin/gems/console-1.29.3/lib/console/output/wrapper.rb new file mode 100644 index 00000000..8082573b --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/output/wrapper.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +module Console + module Output + class Wrapper + def initialize(delegate, **options) + @delegate = delegate + end + + attr :delegate + + def last_output + @delegate.last_output + end + + def verbose!(value = true) + @delegate.verbose!(value) + end + + def call(...) + @delegate.call(...) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/progress.rb b/bin/gems/console-1.29.3/lib/console/progress.rb new file mode 100644 index 00000000..9f45b779 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/progress.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. +# Copyright, 2022, by Anton Sozontov. + +require_relative "clock" + +module Console + class Progress + def self.now + Process.clock_gettime(Process::CLOCK_MONOTONIC) + end + + def initialize(subject, total = 0, minimum_output_duration: 0.1, **options) + @subject = subject + @options = options + + @start_time = Progress.now + + @last_output_time = nil + @minimum_output_duration = minimum_output_duration + + @current = 0 + @total = total + end + + attr :subject + attr :current + attr :total + + def duration + Progress.now - @start_time + end + + def ratio + Rational(@current.to_f, @total.to_f) + end + + def remaining + @total - @current + end + + def average_duration + if @current > 0 + duration / @current + end + end + + def estimated_remaining_time + if average_duration = self.average_duration + average_duration * remaining + end + end + + def to_hash + Hash.new.tap do |hash| + hash[:type] = :progress + hash[:current] = @current + hash[:total] = @total + + hash[:duration] = self.duration + hash[:estimated_remaining_time] = self.estimated_remaining_time + end + end + + def increment(amount = 1) + @current += amount + + if output? + Console.call(@subject, self.to_s, event: self.to_hash, **@options) + @last_output_time = Progress.now + end + + return self + end + + def resize(total) + @total = total + + Console.call(@subject, self.to_s, event: self.to_hash, **@options) + @last_output_time = Progress.now + + return self + end + + def mark(*arguments, **options) + Console.call(@subject, *arguments, **options, **@options) + end + + def to_s + if estimated_remaining_time = self.estimated_remaining_time + "#{@current}/#{@total} completed in #{Clock.formatted_duration(self.duration)}, #{Clock.formatted_duration(estimated_remaining_time)} remaining." + else + "#{@current}/#{@total} completed, waiting for estimate..." + end + end + + private + + def duration_since_last_output + if @last_output_time + Progress.now - @last_output_time + end + end + + def output? + if remaining.zero? + return true + elsif duration = duration_since_last_output + return duration > @minimum_output_duration + else + return true + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/resolver.rb b/bin/gems/console-1.29.3/lib/console/resolver.rb new file mode 100644 index 00000000..7215f806 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/resolver.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. +# Copyright, 2021, by Robert Schulze. + +require_relative "filter" + +module Console + class Resolver + # You can change the log level for different classes using CONSOLE_$LEVEL env vars. + # + # e.g. `CONSOLE_WARN=Acorn,Banana CONSOLE_DEBUG=Cat` will set the log level for the classes Acorn and Banana to `warn` and Cat to `debug`. This overrides the default log level. + # + # You can enable all log levels for a given class by using `CONSOLE_ON=MyClass`. Similarly you can disable all logging using `CONSOLE_OFF=MyClass`. + # + # @parameter logger [Logger] A logger instance to set the logging levels on. + # @parameter env [Hash] The environment to read levels from. + # + # @returns [Nil] If there were no custom logging levels specified in the environment. + # @returns [Resolver] If there were custom logging levels, then the created resolver is returned. + def self.default_resolver(logger, env = ENV) + # Find all CONSOLE_$LEVEL variables from environment: + levels = logger.class::LEVELS + .map{|label, level| [level, env["CONSOLE_#{label.upcase}"]&.split(",")]} + .to_h + .compact + + off_klasses = env["CONSOLE_OFF"]&.split(",") + on_klasses = env["CONSOLE_ON"]&.split(",") + + resolver = nil + + # If we have any levels, then create a class resolver, and each time a class is resolved, set the log level for that class to the specified level: + if on_klasses&.any? + resolver ||= Resolver.new + + resolver.bind(on_klasses) do |klass| + logger.enable(klass, logger.class::MINIMUM_LEVEL - 1) + end + end + + if off_klasses&.any? + resolver ||= Resolver.new + + resolver.bind(off_klasses) do |klass| + logger.disable(klass) + end + end + + levels.each do |level, names| + resolver ||= Resolver.new + + resolver.bind(names) do |klass| + logger.enable(klass, level) + end + end + + return resolver + end + + def initialize + @names = {} + + @trace_point = TracePoint.new(:class, &self.method(:resolve)) + end + + def bind(names, &block) + names.each do |name| + if klass = Object.const_get(name) rescue nil + yield klass + else + @names[name] = block + end + end + + if @names.any? + @trace_point.enable + else + @trace_point.disable + end + end + + def waiting? + @trace_point.enabled? + end + + def resolve(trace_point) + if block = @names.delete(trace_point.self.to_s) + block.call(trace_point.self) + end + + if @names.empty? + @trace_point.disable + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal.rb b/bin/gems/console-1.29.3/lib/console/terminal.rb new file mode 100644 index 00000000..4e1fcd2e --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require_relative "terminal/text" +require_relative "terminal/xterm" + +require_relative "terminal/formatter/progress" +require_relative "terminal/formatter/failure" +require_relative "terminal/formatter/spawn" + +module Console + module Terminal + def self.for(io) + if io.tty? + XTerm.new(io) + else + Text.new(io) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal/formatter/failure.rb b/bin/gems/console-1.29.3/lib/console/terminal/formatter/failure.rb new file mode 100644 index 00000000..14c2a2ff --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal/formatter/failure.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +module Console + module Terminal + module Formatter + class Failure + KEY = :failure + + def initialize(terminal) + @terminal = terminal + + @terminal[:exception_title] ||= @terminal.style(:red, nil, :bold) + @terminal[:exception_detail] ||= @terminal.style(:yellow) + @terminal[:exception_backtrace] ||= @terminal.style(:red) + @terminal[:exception_backtrace_other] ||= @terminal.style(:red, nil, :faint) + @terminal[:exception_message] ||= @terminal.style(:default) + end + + def format(event, output, prefix: nil, verbose: false, width: 80) + title = event[:class] + message = event[:message] + backtrace = event[:backtrace] + root = event[:root] + + lines = message.lines.map(&:chomp) + + output.puts " #{prefix}#{@terminal[:exception_title]}#{title}#{@terminal.reset}: #{lines.shift}" + + lines.each do |line| + output.puts " #{@terminal[:exception_detail]}#{line}#{@terminal.reset}" + end + + root_pattern = /^#{root}\// if root + + backtrace&.each_with_index do |line, index| + path, offset, message = line.split(":", 3) + style = :exception_backtrace + + # Make the path a bit more readable: + if root_pattern and path.sub!(root_pattern, "").nil? + style = :exception_backtrace_other + end + + output.puts " #{index == 0 ? "→" : " "} #{@terminal[style]}#{path}:#{offset}#{@terminal[:exception_message]} #{message}#{@terminal.reset}" + end + + if cause = event[:cause] + format(cause, output, prefix: "Caused by ", verbose: verbose, width: width) + end + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal/formatter/progress.rb b/bin/gems/console-1.29.3/lib/console/terminal/formatter/progress.rb new file mode 100644 index 00000000..deec1682 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal/formatter/progress.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. + +module Console + module Terminal + module Formatter + class Progress + KEY = :progress + + BLOCK = [ + " ", + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + "█", + ] + + def initialize(terminal) + @terminal = terminal + @terminal[:progress_bar] ||= terminal.style(:blue, :white) + end + + def format(event, output, verbose: false, width: 80) + current = event[:current].to_f + total = event[:total].to_f + value = current / total + + # Clamp value to 1.0 to avoid rendering issues: + if value > 1.0 + value = 1.0 + end + + output.puts "#{@terminal[:progress_bar]}#{self.bar(value, width-10)}#{@terminal.reset} #{sprintf('%6.2f', value * 100)}%" + end + + private + + def bar(value, width) + blocks = width * value + full_blocks = blocks.floor + partial_block = ((blocks - full_blocks) * BLOCK.size).floor + + if partial_block.zero? + BLOCK.last * full_blocks + else + "#{BLOCK.last * full_blocks}#{BLOCK[partial_block]}" + end.ljust(width) + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal/formatter/spawn.rb b/bin/gems/console-1.29.3/lib/console/terminal/formatter/spawn.rb new file mode 100644 index 00000000..5374995b --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal/formatter/spawn.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +module Console + module Terminal + module Formatter + # Format spawn events. + class Spawn + KEY = :spawn + + def initialize(terminal) + @terminal = terminal + @terminal[:spawn_command] ||= @terminal.style(:blue, nil, :bold) + end + + def format(event, output, verbose: false, width: 80) + environment, arguments, options = event.values_at(:environment, :arguments, :options) + + arguments = arguments.flatten.collect(&:to_s) + + output.puts "#{@terminal[:spawn_command]}#{arguments.join(' ')}#{@terminal.reset}#{chdir_string(options)}" + + if verbose and environment + environment.each do |key, value| + output.puts "export #{key}=#{value}" + end + end + end + + private + + def chdir_string(options) + if options and chdir = options[:chdir] + " in #{chdir}" + end + end + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal/text.rb b/bin/gems/console-1.29.3/lib/console/terminal/text.rb new file mode 100644 index 00000000..c22849a4 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal/text.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require "io/console" + +module Console + # Styled terminal output. + module Terminal + class Text + def initialize(output) + @output = output + @styles = {reset: self.reset} + end + + def [] key + @styles[key] + end + + def []= key, value + @styles[key] = value + end + + def colors? + false + end + + def width + 80 + end + + def style(foreground, background = nil, *attributes) + end + + def reset + end + + def write(*arguments, style: nil) + if style and prefix = self[style] + @output.write(prefix) + @output.write(*arguments) + @output.write(self.reset) + else + @output.write(*arguments) + end + end + + def puts(*arguments, style: nil) + if style and prefix = self[style] + @output.write(prefix) + @output.puts(*arguments) + @output.write(self.reset) + else + @output.puts(*arguments) + end + end + + # Print out the given arguments. + # When the argument is a symbol, look up the style and inject it into the output stream. + # When the argument is a proc/lambda, call it with self as the argument. + # When the argument is anything else, write it directly to the output. + def print(*arguments) + arguments.each do |argument| + case argument + when Symbol + @output.write(self[argument]) + when Proc + argument.call(self) + else + @output.write(argument) + end + end + end + + # Print out the arguments as per {#print}, followed by the reset sequence and a newline. + def print_line(*arguments) + print(*arguments) + @output.puts(self.reset) + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/terminal/xterm.rb b/bin/gems/console-1.29.3/lib/console/terminal/xterm.rb new file mode 100644 index 00000000..2c0dd36d --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/terminal/xterm.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require "io/console" + +require_relative "text" + +module Console + # Styled terminal output. + module Terminal + class XTerm < Text + COLORS = { + black: 0, + red: 1, + green: 2, + yellow: 3, + blue: 4, + magenta: 5, + cyan: 6, + white: 7, + default: 9, + }.freeze + + ATTRIBUTES = { + normal: 0, + bold: 1, + bright: 1, + faint: 2, + italic: 3, + underline: 4, + blink: 5, + reverse: 7, + hidden: 8, + }.freeze + + def colors? + true + end + + def size + @output.winsize + rescue Errno::ENOTTY + # Fake it... + [24, 80] + end + + def width + size.last + end + + def style(foreground, background = nil, *attributes) + tokens = [] + + if foreground + tokens << 30 + COLORS.fetch(foreground) + end + + if background + tokens << 40 + COLORS.fetch(background) + end + + attributes.each do |attribute| + tokens << ATTRIBUTES.fetch(attribute){attribute.to_i} + end + + return "\e[#{tokens.join(';')}m" + end + + def reset + "\e[0m" + end + end + end +end diff --git a/bin/gems/console-1.29.3/lib/console/version.rb b/bin/gems/console-1.29.3/lib/console/version.rb new file mode 100644 index 00000000..b8365824 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/version.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +module Console + VERSION = "1.29.3" +end diff --git a/bin/gems/console-1.29.3/lib/console/warn.rb b/bin/gems/console-1.29.3/lib/console/warn.rb new file mode 100644 index 00000000..79ed25e2 --- /dev/null +++ b/bin/gems/console-1.29.3/lib/console/warn.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2024, by Samuel Williams. + +require_relative "logger" + +module Console + # Whether the current fiber is emitting a warning. + Fiber.attr_accessor :console_warn + + # Redirect warnings to Console.warn. + module Warn + # Redirect warnings to {Console.warn}. + def warn(message, **options) + fiber = Fiber.current + + # We do this to be extra pendantic about avoiding infinite recursion. + return super if fiber.console_warn + + begin + fiber.console_warn = true + message.chomp! + + Console::Logger.instance.warn(message, **options) + ensure + fiber.console_warn = false + end + end + end + + ::Warning.extend(Warn) +end diff --git a/bin/gems/console-1.29.3/license.md b/bin/gems/console-1.29.3/license.md new file mode 100644 index 00000000..3f1ba66c --- /dev/null +++ b/bin/gems/console-1.29.3/license.md @@ -0,0 +1,31 @@ +# MIT License + +Copyright, 2019-2025, by Samuel Williams. +Copyright, 2019-2021, by Bryan Powell. +Copyright, 2019, by Cyril Roelandt. +Copyright, 2020, by Olle Jonsson. +Copyright, 2020, by Michael Adams. +Copyright, 2021, by Cédric Boutillier. +Copyright, 2021, by Robert Schulze. +Copyright, 2022, by Anton Sozontov. +Copyright, 2022, by William T. Nelson. +Copyright, 2023, by Felix Yan. +Copyright, 2024, by Patrik Wenger. + +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/bin/gems/console-1.29.3/readme.md b/bin/gems/console-1.29.3/readme.md new file mode 100644 index 00000000..93608112 --- /dev/null +++ b/bin/gems/console-1.29.3/readme.md @@ -0,0 +1,80 @@ +# Console + +Provides beautiful console logging for Ruby applications. Implements fast, buffered log output. + +[![Development Status](https://github.com/socketry/console/workflows/Test/badge.svg)](https://github.com/socketry/console/actions?workflow=Test) + +## Motivation + +When Ruby decided to reverse the order of exception backtraces, I finally gave up using the built in logging and decided restore sanity to the output of my programs once and for all\! + +## Features + + - Thread safe global logger with per-fiber context. + - Carry along context with nested loggers. + - Enable/disable log levels per-class. + - Detailed logging of exceptions. + - Beautiful logging to the terminal or structured logging using JSON. + +## Usage + +Please see the [project documentation](https://socketry.github.io/console/) for more details. + + - [Getting Started](https://socketry.github.io/console/guides/getting-started/index) - This guide explains how to use `console` for logging. + + - [Command Line](https://socketry.github.io/console/guides/command-line/index) - This guide explains how the `console` gem can be controlled using environment variables. + + - [Integration](https://socketry.github.io/console/guides/integration/index) - This guide explains how to integrate the `console` output into different systems. + + - [Events](https://socketry.github.io/console/guides/events/index) - This guide explains how to log structured events with a well-defined schema. + +## Releases + +Please see the [project releases](https://socketry.github.io/console/releases/index) for all releases. + +### v1.29.3 + + - Serialized output now uses `IO#write` with a single string to reduce the chance of interleaved output. + +### v1.29.2 + + - Always return `nil` from `Console::Filter` logging methods. + +### v1.29.1 + + - Fix logging `exception:` keyword argument when the value was not an exception. + +### v1.29.0 + + - Don't make `Kernel#warn` redirection to `Console.warn` the default behavior, you must `require 'console/warn'` to enable it. + - Remove deprecated `Console::Logger#failure`. + - [Consistent Handling of Exceptions](https://socketry.github.io/console/releases/index#consistent-handling-of-exceptions) + +### v1.28.0 + + - Add support for `Kernel#warn` redirection to `Console.warn`. + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +### Developer Certificate of Origin + +In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. + +### Community Guidelines + +This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers. + +## See Also + + - [console-adapter-rails](https://github.com/socketry/console-adapter-rails) + - [console-adapter-sidekiq](https://github.com/socketry/console-adapter-sidekiq) + - [console-output-datadog](https://github.com/socketry/console-output-datadog) + - [sus-fixtures-console](https://github.com/sus-rb/sus-fixtures-console) diff --git a/bin/gems/console-1.29.3/releases.md b/bin/gems/console-1.29.3/releases.md new file mode 100644 index 00000000..7326fc12 --- /dev/null +++ b/bin/gems/console-1.29.3/releases.md @@ -0,0 +1,37 @@ +# Releases + +## v1.29.3 + + - Serialized output now uses `IO#write` with a single string to reduce the chance of interleaved output. + +## v1.29.2 + + - Always return `nil` from `Console::Filter` logging methods. + +## v1.29.1 + + - Fix logging `exception:` keyword argument when the value was not an exception. + +## v1.29.0 + + - Don't make `Kernel#warn` redirection to `Console.warn` the default behavior, you must `require 'console/warn'` to enable it. + - Remove deprecated `Console::Logger#failure`. + +### Consistent Handling of Exceptions + +`Console.call` and all wrapper methods will now consistently handle exceptions that are the last positional argument or keyword argument. This means that the following code will work as expected: + +``` ruby +begin +rescue => error + # Last positional argument: + Console.warn(self, "There may be an issue", error) + + # Keyword argument (preferable): + Console.error(self, "There is an issue", exception: error) +end +``` + +## v1.28.0 + + - Add support for `Kernel#warn` redirection to `Console.warn`. diff --git a/bin/gems/csv-3.3.2/LICENSE.txt b/bin/gems/csv-3.3.2/LICENSE.txt new file mode 100644 index 00000000..07b1b7fe --- /dev/null +++ b/bin/gems/csv-3.3.2/LICENSE.txt @@ -0,0 +1,33 @@ +Copyright (C) 2005-2016 James Edward Gray II. All rights reserved. +Copyright (C) 2007-2017 Yukihiro Matsumoto. All rights reserved. +Copyright (C) 2017 SHIBATA Hiroshi. All rights reserved. +Copyright (C) 2017 Olivier Lacan. All rights reserved. +Copyright (C) 2017 Espartaco Palma. All rights reserved. +Copyright (C) 2017 Marcus Stollsteimer. All rights reserved. +Copyright (C) 2017 pavel. All rights reserved. +Copyright (C) 2017-2018 Steven Daniels. All rights reserved. +Copyright (C) 2018 Tomohiro Ogoke. All rights reserved. +Copyright (C) 2018 Kouhei Sutou. All rights reserved. +Copyright (C) 2018 Mitsutaka Mimura. All rights reserved. +Copyright (C) 2018 Vladislav. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/bin/gems/csv-3.3.2/NEWS.md b/bin/gems/csv-3.3.2/NEWS.md new file mode 100644 index 00000000..c3936727 --- /dev/null +++ b/bin/gems/csv-3.3.2/NEWS.md @@ -0,0 +1,965 @@ +# News + +## 3.3.2 - 2024-12-21 + +### Fixes + + * Fixed a parse bug with a quoted line with `col_sep` and an empty + line. This was introduced in 3.3.1. + * GH-324 + * Reported by stoodfarback + +### Thanks + + * stoodfarback + +## 3.3.1 - 2024-12-15 + +### Improvements + + * `CSV.open`: Changed to detect BOM by default. Note that this isn't + enabled on Windows because Ruby may have a bug. See also: + https://bugs.ruby-lang.org/issues/20526 + * GH-301 + * Reported by Junichi Ito + + * Improved performance. + * GH-311 + * GH-312 + * Patch by Vladimir Kochnev + + * `CSV.open`: Added support for `StringIO` as an input. + * GH-300 + * GH-302 + * Patch by Marcelo + + * Added a built-in time converter. You can use it by `converters: + :time`. + * GH-313 + * Patch by Bart de Water + + * Added `CSV::TSV` for tab-separated values. + * GH-272 + * GH-319 + * Reported by kojix2 + * Patch by Jas + +### Thanks + + * Junichi Ito + + * Vladimir Kochnev + + * Marcelo + + * Bart de Water + + * kojix2 + + * Jas + +## 3.3.0 - 2024-03-22 + +### Fixes + + * Fixed a regression parse bug in 3.2.9 that parsing with + `:skip_lines` may cause wrong result. + +## 3.2.9 - 2024-03-22 + +### Fixes + + * Fixed a parse bug that wrong result may be happen when: + + * `:skip_lines` is used + * `:row_separator` is `"\r\n"` + * There is a line that includes `\n` as a column value + + Reported by Ryo Tsukamoto. + + GH-296 + +### Thanks + + * Ryo Tsukamoto + +## 3.2.8 - 2023-11-08 + +### Improvements + + * Added `CSV::InvalidEncodingError`. + + Patch by Kosuke Shibata. + + GH-287 + +### Thanks + + * Kosuke Shibata + +## 3.2.7 - 2023-06-26 + +### Improvements + + * Removed an unused internal variable. + [GH-273](https://github.com/ruby/csv/issues/273) + [Patch by Mau Magnaguagno] + + * Changed to use `https://` instead of `http://` in documents. + [GH-274](https://github.com/ruby/csv/issues/274) + [Patch by Vivek Bharath Akupatni] + + * Added prefix to a helper module in test. + [GH-278](https://github.com/ruby/csv/issues/278) + [Patch by Luke Gruber] + + * Added a documentation for `liberal_parsing: {backslash_quotes: true}`. + [GH-280](https://github.com/ruby/csv/issues/280) + [Patch by Mark Schneider] + +### Fixes + + * Fixed a wrong execution result in documents. + [GH-276](https://github.com/ruby/csv/issues/276) + [Patch by Yuki Tsujimoto] + + * Fixed a bug that the same line is used multiple times. + [GH-279](https://github.com/ruby/csv/issues/279) + [Reported by Gabriel Nagy] + +### Thanks + + * Mau Magnaguagno + + * Vivek Bharath Akupatni + + * Yuki Tsujimoto + + * Luke Gruber + + * Mark Schneider + + * Gabriel Nagy + +## 3.2.6 - 2022-12-08 + +### Improvements + + * `CSV#read` consumes the same lines with other methods like + `CSV#shift`. + [[GitHub#258](https://github.com/ruby/csv/issues/258)] + [Reported by Lhoussaine Ghallou] + + * All `Enumerable` based methods consume the same lines with other + methods. This may have a performance penalty. + [[GitHub#260](https://github.com/ruby/csv/issues/260)] + [Reported by Lhoussaine Ghallou] + + * Simplify some implementations. + [[GitHub#262](https://github.com/ruby/csv/pull/262)] + [[GitHub#263](https://github.com/ruby/csv/pull/263)] + [Patch by Mau Magnaguagno] + +### Fixes + + * Fixed `CSV.generate_lines` document. + [[GitHub#257](https://github.com/ruby/csv/pull/257)] + [Patch by Sampat Badhe] + +### Thanks + + * Sampat Badhe + + * Lhoussaine Ghallou + + * Mau Magnaguagno + +## 3.2.5 - 2022-08-26 + +### Improvements + + * Added `CSV.generate_lines`. + [[GitHub#255](https://github.com/ruby/csv/issues/255)] + [Reported by OKURA Masafumi] + [[GitHub#256](https://github.com/ruby/csv/pull/256)] + [Patch by Eriko Sugiyama] + +### Thanks + + * OKURA Masafumi + + * Eriko Sugiyama + +## 3.2.4 - 2022-08-22 + +### Improvements + + * Cleaned up internal implementations. + [[GitHub#249](https://github.com/ruby/csv/pull/249)] + [[GitHub#250](https://github.com/ruby/csv/pull/250)] + [[GitHub#251](https://github.com/ruby/csv/pull/251)] + [Patch by Mau Magnaguagno] + + * Added support for RFC 3339 style time. + [[GitHub#248](https://github.com/ruby/csv/pull/248)] + [Patch by Thierry Lambert] + + * Added support for transcoding String CSV. Syntax is + `from-encoding:to-encoding`. + [[GitHub#254](https://github.com/ruby/csv/issues/254)] + [Reported by Richard Stueven] + + * Added quoted information to `CSV::FieldInfo`. + [[GitHub#254](https://github.com/ruby/csv/pull/253)] + [Reported by Hirokazu SUZUKI] + +### Fixes + + * Fixed a link in documents. + [[GitHub#244](https://github.com/ruby/csv/pull/244)] + [Patch by Peter Zhu] + +### Thanks + + * Peter Zhu + + * Mau Magnaguagno + + * Thierry Lambert + + * Richard Stueven + + * Hirokazu SUZUKI + +## 3.2.3 - 2022-04-09 + +### Improvements + + * Added contents summary to `CSV::Table#inspect`. + [GitHub#229][Patch by Eriko Sugiyama] + [GitHub#235][Patch by Sampat Badhe] + + * Suppressed `$INPUT_RECORD_SEPARATOR` deprecation warning by + `Warning.warn`. + [GitHub#233][Reported by Jean byroot Boussier] + + * Improved error message for liberal parsing with quoted values. + [GitHub#231][Patch by Nikolay Rys] + + * Fixed typos in documentation. + [GitHub#236][Patch by Sampat Badhe] + + * Added `:max_field_size` option and deprecated `:field_size_limit` option. + [GitHub#238][Reported by Dan Buettner] + + * Added `:symbol_raw` to built-in header converters. + [GitHub#237][Reported by taki] + [GitHub#239][Patch by Eriko Sugiyama] + +### Fixes + + * Fixed a bug that some texts may be dropped unexpectedly. + [Bug #18245][ruby-core:105587][Reported by Hassan Abdul Rehman] + + * Fixed a bug that `:field_size_limit` doesn't work with not complex row. + [GitHub#238][Reported by Dan Buettner] + +### Thanks + + * Hassan Abdul Rehman + + * Eriko Sugiyama + + * Jean byroot Boussier + + * Nikolay Rys + + * Sampat Badhe + + * Dan Buettner + + * taki + +## 3.2.2 - 2021-12-24 + +### Improvements + + * Added a validation for invalid option combination. + [GitHub#225][Patch by adamroyjones] + + * Improved documentation for developers. + [GitHub#227][Patch by Eriko Sugiyama] + +### Fixes + + * Fixed a bug that all of `ARGF` contents may not be consumed. + [GitHub#228][Reported by Rafael Navaza] + +### Thanks + + * adamroyjones + + * Eriko Sugiyama + + * Rafael Navaza + +## 3.2.1 - 2021-10-23 + +### Improvements + + * doc: Fixed wrong class name. + [GitHub#217][Patch by Vince] + + * Changed to always use `"\n"` for the default row separator on Ruby + 3.0 or later because `$INPUT_RECORD_SEPARATOR` was deprecated + since Ruby 3.0. + + * Added support for Ractor. + [GitHub#218][Patch by rm155] + + * Users who want to use the built-in converters in non-main + Ractors need to call `Ractor.make_shareable(CSV::Converters)` + and/or `Ractor.make_shareable(CSV::HeaderConverters)` before + creating non-main Ractors. + +### Thanks + + * Vince + + * Joakim Antman + + * rm155 + +## 3.2.0 - 2021-06-06 + +### Improvements + + * `CSV.open`: Added support for `:newline` option. + [GitHub#198][Patch by Nobuyoshi Nakada] + + * `CSV::Table#each`: Added support for column mode with duplicated + headers. + [GitHub#206][Reported by Yaroslav Berezovskiy] + + * `Object#CSV`: Added support for Ruby 3.0. + + * `CSV::Row`: Added support for pattern matching. + [GitHub#207][Patch by Kevin Newton] + +### Fixes + + * Fixed typos in documentation. + [GitHub#196][GitHub#205][Patch by Sampat Badhe] + +### Thanks + + * Sampat Badhe + + * Nobuyoshi Nakada + + * Yaroslav Berezovskiy + + * Kevin Newton + +## 3.1.9 - 2020-11-23 + +### Fixes + + * Fixed a compatibility bug that the line to be processed by + `skip_lines:` has a row separator. + [GitHub#194][Reported by Josef Šimánek] + +### Thanks + + * Josef Šimánek + +## 3.1.8 - 2020-11-18 + +### Improvements + + * Improved documentation. + [Patch by Burdette Lamar] + +### Thanks + + * Burdette Lamar + +## 3.1.7 - 2020-08-04 + +### Improvements + + * Improved document. + [GitHub#158][GitHub#160][GitHub#161] + [Patch by Burdette Lamar] + + * Updated required Ruby version to 2.5.0 or later. + [GitHub#159] + [Patch by Gabriel Nagy] + + * Removed stringio 0.1.3 or later dependency. + +### Thanks + + * Burdette Lamar + + * Gabriel Nagy + +## 3.1.6 - 2020-07-20 + +### Improvements + + * Improved document. + [GitHub#127][GitHub#135][GitHub#136][GitHub#137][GitHub#139][GitHub#140] + [GitHub#141][GitHub#142][GitHub#143][GitHub#145][GitHub#146][GitHub#148] + [GitHub#148][GitHub#151][GitHub#152][GitHub#154][GitHub#155][GitHub#157] + [Patch by Burdette Lamar] + + * `CSV.open`: Added support for `undef: :replace`. + [GitHub#129][Patch by Koichi ITO] + + * `CSV.open`: Added support for `invalid: :replace`. + [GitHub#129][Patch by Koichi ITO] + + * Don't run quotable check for invalid encoding field values. + [GitHub#131][Patch by Koichi ITO] + + * Added support for specifying the target indexes and names to + `force_quotes:`. + [GitHub#153][Reported by Aleksandr] + + * `CSV.generate`: Changed to use the encoding of the first non-ASCII + field rather than the encoding of ASCII only field. + + * Changed to require the stringio gem 0.1.3 or later. + +### Thanks + + * Burdette Lamar + + * Koichi ITO + + * Aleksandr + +## 3.1.5 - 2020-05-18 + +### Improvements + + * Improved document. + [GitHub#124][Patch by Burdette Lamar] + +### Fixes + + * Added missing document files. + [GitHub#125][Reported by joast] + +### Thanks + + * Burdette Lamar + + * joast + +## 3.1.4 - 2020-05-17 + +### Improvements + + * Improved document. + [GitHub#122][Patch by Burdette Lamar] + + * Stopped to dropping stack trace for exception caused by + `CSV.parse_line`. + [GitHub#120][Reported by Kyle d'Oliveira] + +### Fixes + + * Fixed a bug that `:write_nil_value` or `:write_empty_value` don't + work with non `String` objects. + [GitHub#123][Reported by asm256] + +### Thanks + + * Burdette Lamar + + * asm256 + + * Kyle d'Oliveira + +## 3.1.3 - 2020-05-09 + +### Improvements + + * `CSV::Row#dup`: Copied deeply. + [GitHub#108][Patch by Jim Kane] + +### Fixes + + * Fixed a infinite loop bug for zero length match `skip_lines`. + [GitHub#110][Patch by Mike MacDonald] + + * `CSV.generate`: Fixed a bug that encoding isn't set correctly. + [GitHub#110][Patch by Seiei Miyagi] + + * Fixed document for the `:strip` option. + [GitHub#114][Patch by TOMITA Masahiro] + + * Fixed a parse bug when split charcter exists in middle of column + value. + [GitHub#115][Reported by TOMITA Masahiro] + +### Thanks + + * Jim Kane + + * Mike MacDonald + + * Seiei Miyagi + + * TOMITA Masahiro + +## 3.1.2 - 2019-10-12 + +### Improvements + + * Added `:col_sep` check. + [GitHub#94][Reported by Florent Beaurain] + + * Suppressed warnings. + [GitHub#96][Patch by Nobuyoshi Nakada] + + * Improved documentation. + [GitHub#101][GitHub#102][Patch by Vitor Oliveira] + +### Fixes + + * Fixed a typo in documentation. + [GitHub#95][Patch by Yuji Yaginuma] + + * Fixed a multibyte character handling bug. + [GitHub#97][Patch by koshigoe] + + * Fixed typos in documentation. + [GitHub#100][Patch by Vitor Oliveira] + + * Fixed a bug that seeked `StringIO` isn't accepted. + [GitHub#98][Patch by MATSUMOTO Katsuyoshi] + + * Fixed a bug that `CSV.generate_line` doesn't work with + `Encoding.default_internal`. + [GitHub#105][Reported by David Rodríguez] + +### Thanks + + * Florent Beaurain + + * Yuji Yaginuma + + * Nobuyoshi Nakada + + * koshigoe + + * Vitor Oliveira + + * MATSUMOTO Katsuyoshi + + * David Rodríguez + +## 3.1.1 - 2019-04-26 + +### Improvements + + * Added documentation for `strip` option. + [GitHub#88][Patch by hayashiyoshino] + + * Added documentation for `write_converters`, `write_nil_value` and + `write_empty_value` options. + [GitHub#87][Patch by Masafumi Koba] + + * Added documentation for `quote_empty` option. + [GitHub#89][Patch by kawa\_tech] + +### Fixes + + * Fixed a bug that `strip; true` removes a newline. + +### Thanks + + * hayashiyoshino + + * Masafumi Koba + + * kawa\_tech + +## 3.1.0 - 2019-04-17 + +### Fixes + + * Fixed a backward incompatibility bug that `CSV#eof?` may raises an + error. + [GitHub#86][Reported by krororo] + +### Thanks + + * krororo + +## 3.0.9 - 2019-04-15 + +### Fixes + + * Fixed a test for Windows. + +## 3.0.8 - 2019-04-11 + +### Fixes + + * Fixed a bug that `strip: String` doesn't work. + +## 3.0.7 - 2019-04-08 + +### Improvements + + * Improve parse performance 1.5x by introducing loose parser. + +### Fixes + + * Fix performance regression in 3.0.5. + + * Fix a bug that `CSV#line` returns wrong value when you + use `quote_char: nil`. + +## 3.0.6 - 2019-03-30 + +### Improvements + + * `CSV.foreach`: Added support for `mode`. + +## 3.0.5 - 2019-03-24 + +### Improvements + + * Added `:liberal_parsing => {backslash_quote: true}` option. + [GitHub#74][Patch by 284km] + + * Added `:write_converters` option. + [GitHub#73][Patch by Danillo Souza] + + * Added `:write_nil_value` option. + + * Added `:write_empty_value` option. + + * Improved invalid byte line number detection. + [GitHub#78][Patch by Alyssa Ross] + + * Added `quote_char: nil` optimization. + [GitHub#79][Patch by 284km] + + * Improved error message. + [GitHub#81][Patch by Andrés Torres] + + * Improved IO-like implementation for `StringIO` data. + [GitHub#80][Patch by Genadi Samokovarov] + + * Added `:strip` option. + [GitHub#58] + +### Fixes + + * Fixed a compatibility bug that `CSV#each` doesn't care `CSV#shift`. + [GitHub#76][Patch by Alyssa Ross] + + * Fixed a compatibility bug that `CSV#eof?` doesn't care `CSV#each` + and `CSV#shift`. + [GitHub#77][Reported by Chi Leung] + + * Fixed a compatibility bug that invalid line isn't ignored. + [GitHub#82][Reported by krororo] + + * Fixed a bug that `:skip_lines` doesn't work with multibyte characters data. + [GitHub#83][Reported by ff2248] + +### Thanks + + * Alyssa Ross + + * 284km + + * Chi Leung + + * Danillo Souza + + * Andrés Torres + + * Genadi Samokovarov + + * krororo + + * ff2248 + +## 3.0.4 - 2019-01-25 + +### Improvements + + * Removed duplicated `CSV::Row#include?` implementations. + [GitHub#69][Patch by Max Schwenk] + + * Removed duplicated `CSV::Row#header?` implementations. + [GitHub#70][Patch by Max Schwenk] + +### Fixes + + * Fixed a typo in document. + [GitHub#72][Patch by Artur Beljajev] + + * Fixed a compatibility bug when row headers are changed. + [GitHub#71][Reported by tomoyuki kosaka] + +### Thanks + + * Max Schwenk + + * Artur Beljajev + + * tomoyuki kosaka + +## 3.0.3 - 2019-01-12 + +### Improvements + + * Migrated benchmark tool to benchmark-driver from benchmark-ips. + [GitHub#57][Patch by 284km] + + * Added `liberal_parsing: {double_quote_outside_quote: true}` parse + option. + [GitHub#66][Reported by Watson] + + * Added `quote_empty:` write option. + [GitHub#35][Reported by Dave Myron] + +### Fixes + + * Fixed a compatibility bug that `CSV.generate` always return + `ASCII-8BIT` encoding string. + [GitHub#63][Patch by Watson] + + * Fixed a compatibility bug that `CSV.parse("", headers: true)` + doesn't return `CSV::Table`. + [GitHub#64][Reported by Watson][Patch by 284km] + + * Fixed a compatibility bug that multiple-characters column + separator doesn't work. + [GitHub#67][Reported by Jesse Reiss] + + * Fixed a compatibility bug that double `#each` parse twice. + [GitHub#68][Reported by Max Schwenk] + +### Thanks + + * Watson + + * 284km + + * Jesse Reiss + + * Dave Myron + + * Max Schwenk + +## 3.0.2 - 2018-12-23 + +### Improvements + + * Changed to use strscan in parser. + [GitHub#52][Patch by 284km] + + * Improves CSV write performance. + 3.0.2 will be about 2 times faster than 3.0.1. + + * Improves CSV parse performance for complex case. + 3.0.2 will be about 2 times faster than 3.0.1. + +### Fixes + + * Fixed a parse error bug for new line only input with `headers` option. + [GitHub#53][Reported by Chris Beer] + + * Fixed some typos in document. + [GitHub#54][Patch by Victor Shepelev] + +### Thanks + + * 284km + + * Chris Beer + + * Victor Shepelev + +## 3.0.1 - 2018-12-07 + +### Improvements + + * Added a test. + [GitHub#38][Patch by 284km] + + * `CSV::Row#dup`: Changed to duplicate internal data. + [GitHub#39][Reported by André Guimarães Sakata] + + * Documented `:nil_value` and `:empty_value` options. + [GitHub#41][Patch by OwlWorks] + + * Added support for separator detection for non-seekable inputs. + [GitHub#45][Patch by Ilmari Karonen] + + * Removed needless code. + [GitHub#48][Patch by Espartaco Palma] + + * Added support for parsing header only CSV with `headers: true`. + [GitHub#47][Patch by Kazuma Shibasaka] + + * Added support for coverage report in CI. + [GitHub#48][Patch by Espartaco Palma] + + * Improved auto CR row separator detection. + [GitHub#51][Reported by Yuki Kurihara] + +### Fixes + + * Fixed a typo in document. + [GitHub#40][Patch by Marcus Stollsteimer] + +### Thanks + + * 284km + + * André Guimarães Sakata + + * Marcus Stollsteimer + + * OwlWorks + + * Ilmari Karonen + + * Espartaco Palma + + * Kazuma Shibasaka + + * Yuki Kurihara + +## 3.0.0 - 2018-06-06 + +### Fixes + + * Fixed a bug that header isn't returned for empty row. + [GitHub#37][Patch by Grace Lee] + +### Thanks + + * Grace Lee + +## 1.0.2 - 2018-05-03 + +### Improvements + + * Split file for CSV::VERSION + + * Code cleanup: Split csv.rb into a more manageable structure + [GitHub#19][Patch by Espartaco Palma] + [GitHub#20][Patch by Steven Daniels] + + * Use CSV::MalformedCSVError for invalid encoding line + [GitHub#26][Reported by deepj] + + * Support implicit Row <-> Array conversion + [Bug #10013][ruby-core:63582][Reported by Dawid Janczak] + + * Update class docs + [GitHub#32][Patch by zverok] + + * Add `Row#each_pair` + [GitHub#33][Patch by zverok] + + * Improve CSV performance + [GitHub#30][Patch by Watson] + + * Add :nil_value and :empty_value option + +### Fixes + + * Fix a bug that "bom|utf-8" doesn't work + [GitHub#23][Reported by Pavel Lobashov] + + * `CSV::Row#to_h`, `#to_hash`: uses the same value as `Row#[]` + [Bug #14482][Reported by tomoya ishida] + + * Make row separator detection more robust + [GitHub#25][Reported by deepj] + + * Fix a bug that too much separator when col_sep is `" "` + [Bug #8784][ruby-core:63582][Reported by Sylvain Laperche] + +### Thanks + + * Espartaco Palma + + * Steven Daniels + + * deepj + + * Dawid Janczak + + * zverok + + * Watson + + * Pavel Lobashov + + * tomoya ishida + + * Sylvain Laperche + + * Ryunosuke Sato + +## 1.0.1 - 2018-02-09 + +### Improvements + + * `CSV::Table#delete`: Added bulk delete support. You can delete + multiple rows and columns at once. + [GitHub#4][Patch by Vladislav] + + * Updated Gem description. + [GitHub#11][Patch by Marcus Stollsteimer] + + * Code cleanup. + [GitHub#12][Patch by Marcus Stollsteimer] + [GitHub#14][Patch by Steven Daniels] + [GitHub#18][Patch by takkanm] + + * `CSV::Table#dig`: Added. + [GitHub#15][Patch by Tomohiro Ogoke] + + * `CSV::Row#dig`: Added. + [GitHub#15][Patch by Tomohiro Ogoke] + + * Added ISO 8601 support to date time converter. + [GitHub#16] + +### Fixes + + * Fixed wrong `CSV::VERSION`. + [GitHub#10][Reported by Marcus Stollsteimer] + + * `CSV.generate`: Fixed a regression bug that `String` argument is + ignored. + [GitHub#13][Patch by pavel] + +### Thanks + + * Vladislav + + * Marcus Stollsteimer + + * Steven Daniels + + * takkanm + + * Tomohiro Ogoke + + * pavel diff --git a/bin/gems/csv-3.3.2/README.md b/bin/gems/csv-3.3.2/README.md new file mode 100644 index 00000000..cf61a358 --- /dev/null +++ b/bin/gems/csv-3.3.2/README.md @@ -0,0 +1,55 @@ +# CSV + +This library provides a complete interface to CSV files and data. It offers tools to enable you to read and write to and from Strings or IO objects, as needed. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'csv' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install csv + +## Usage + +```ruby +require "csv" + +CSV.foreach("path/to/file.csv") do |row| + # use row here... +end +``` + +## Documentation + +- [API](https://ruby.github.io/csv/): all classes, methods, and constants. +- [Recipes](https://ruby.github.io/csv/doc/csv/recipes/recipes_rdoc.html): specific code for specific tasks. + +## Development + +After checking out the repo, run `ruby run-test.rb` to check if your changes can pass the test. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/csv. + +### NOTE: About RuboCop + +We don't use RuboCop because we can manage our coding style by ourselves. We want to accept small fluctuations in our coding style because we use Ruby. +Please do not submit issues and PRs that aim to introduce RuboCop in this repository. + +## License + +The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). + +See LICENSE.txt for details. diff --git a/bin/gems/csv-3.3.2/doc/csv/arguments/io.rdoc b/bin/gems/csv-3.3.2/doc/csv/arguments/io.rdoc new file mode 100644 index 00000000..f5fe1d19 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/arguments/io.rdoc @@ -0,0 +1,5 @@ +* Argument +io+ should be an IO object that is: + * Open for reading; on return, the IO object will be closed. + * Positioned at the beginning. + To position at the end, for appending, use method CSV.generate. + For any other positioning, pass a preset \StringIO object instead. diff --git a/bin/gems/csv-3.3.2/doc/csv/options/common/col_sep.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/common/col_sep.rdoc new file mode 100644 index 00000000..b8be8699 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/common/col_sep.rdoc @@ -0,0 +1,57 @@ +====== Option +col_sep+ + +Specifies the \String column separator to be used +for both parsing and generating. +The \String will be transcoded into the data's \Encoding before use. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma) + +Using the default (comma): + str = CSV.generate do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0\nbar,1\nbaz,2\n" + ary = CSV.parse(str) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using +:+ (colon): + col_sep = ':' + str = CSV.generate(col_sep: col_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo:0\nbar:1\nbaz:2\n" + ary = CSV.parse(str, col_sep: col_sep) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using +::+ (two colons): + col_sep = '::' + str = CSV.generate(col_sep: col_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo::0\nbar::1\nbaz::2\n" + ary = CSV.parse(str, col_sep: col_sep) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using '' (empty string): + col_sep = '' + str = CSV.generate(col_sep: col_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo0\nbar1\nbaz2\n" + +--- + +Raises an exception if parsing with the empty \String: + col_sep = '' + # Raises ArgumentError (:col_sep must be 1 or more characters: "") + CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep) + diff --git a/bin/gems/csv-3.3.2/doc/csv/options/common/quote_char.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/common/quote_char.rdoc new file mode 100644 index 00000000..67fd3af6 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/common/quote_char.rdoc @@ -0,0 +1,42 @@ +====== Option +quote_char+ + +Specifies the character (\String of length 1) used used to quote fields +in both parsing and generating. +This String will be transcoded into the data's \Encoding before use. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote) + +This is useful for an application that incorrectly uses ' (single-quote) +to quote fields, instead of the correct " (double-quote). + +Using the default (double quote): + str = CSV.generate do |csv| + csv << ['foo', 0] + csv << ["'bar'", 1] + csv << ['"baz"', 2] + end + str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n" + ary = CSV.parse(str) + ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]] + +Using ' (single-quote): + quote_char = "'" + str = CSV.generate(quote_char: quote_char) do |csv| + csv << ['foo', 0] + csv << ["'bar'", 1] + csv << ['"baz"', 2] + end + str # => "foo,0\n'''bar''',1\n\"baz\",2\n" + ary = CSV.parse(str, quote_char: quote_char) + ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]] + +--- + +Raises an exception if the \String length is greater than 1: + # Raises ArgumentError (:quote_char has to be nil or a single character String) + CSV.new('', quote_char: 'xx') + +Raises an exception if the value is not a \String: + # Raises ArgumentError (:quote_char has to be nil or a single character String) + CSV.new('', quote_char: :foo) diff --git a/bin/gems/csv-3.3.2/doc/csv/options/common/row_sep.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/common/row_sep.rdoc new file mode 100644 index 00000000..eae15b4a --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/common/row_sep.rdoc @@ -0,0 +1,91 @@ +====== Option +row_sep+ + +Specifies the row separator, a \String or the \Symbol :auto (see below), +to be used for both parsing and generating. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto + +--- + +When +row_sep+ is a \String, that \String becomes the row separator. +The String will be transcoded into the data's Encoding before use. + +Using "\n": + row_sep = "\n" + str = CSV.generate(row_sep: row_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0\nbar,1\nbaz,2\n" + ary = CSV.parse(str) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using | (pipe): + row_sep = '|' + str = CSV.generate(row_sep: row_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0|bar,1|baz,2|" + ary = CSV.parse(str, row_sep: row_sep) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using -- (two hyphens): + row_sep = '--' + str = CSV.generate(row_sep: row_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0--bar,1--baz,2--" + ary = CSV.parse(str, row_sep: row_sep) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using '' (empty string): + row_sep = '' + str = CSV.generate(row_sep: row_sep) do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0bar,1baz,2" + ary = CSV.parse(str, row_sep: row_sep) + ary # => [["foo", "0bar", "1baz", "2"]] + +--- + +When +row_sep+ is the \Symbol +:auto+ (the default), +generating uses "\n" as the row separator: + str = CSV.generate do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0\nbar,1\nbaz,2\n" + +Parsing, on the other hand, invokes auto-discovery of the row separator. + +Auto-discovery reads ahead in the data looking for the next \r\n, +\n+, or +\r+ sequence. +The sequence will be selected even if it occurs in a quoted field, +assuming that you would have the same line endings there. + +Example: + str = CSV.generate do |csv| + csv << [:foo, 0] + csv << [:bar, 1] + csv << [:baz, 2] + end + str # => "foo,0\nbar,1\nbaz,2\n" + ary = CSV.parse(str) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +The default $INPUT_RECORD_SEPARATOR ($/) is used +if any of the following is true: +* None of those sequences is found. +* Data is +ARGF+, +STDIN+, +STDOUT+, or +STDERR+. +* The stream is only available for output. + +Obviously, discovery takes a little time. Set manually if speed is important. Also note that IO objects should be opened in binary mode on Windows if this feature will be used as the line-ending translation can cause problems with resetting the document position to where it was before the read ahead. diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/force_quotes.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/force_quotes.rdoc new file mode 100644 index 00000000..11afd1a1 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/force_quotes.rdoc @@ -0,0 +1,17 @@ +====== Option +force_quotes+ + +Specifies the boolean that determines whether each output field is to be double-quoted. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false + +For examples in this section: + ary = ['foo', 0, nil] + +Using the default, +false+: + str = CSV.generate_line(ary) + str # => "foo,0,\n" + +Using +true+: + str = CSV.generate_line(ary, force_quotes: true) + str # => "\"foo\",\"0\",\"\"\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/quote_empty.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/quote_empty.rdoc new file mode 100644 index 00000000..4c5645c6 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/quote_empty.rdoc @@ -0,0 +1,12 @@ +====== Option +quote_empty+ + +Specifies the boolean that determines whether an empty value is to be double-quoted. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true + +With the default +true+: + CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n" + +With +false+: + CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/write_converters.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_converters.rdoc new file mode 100644 index 00000000..d1a9cc74 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_converters.rdoc @@ -0,0 +1,25 @@ +====== Option +write_converters+ + +Specifies converters to be used in generating fields. +See {Write Converters}[#class-CSV-label-Write+Converters] + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil + +With no write converter: + str = CSV.generate_line(["\na\n", "\tb\t", " c "]) + str # => "\"\na\n\",\tb\t, c \n" + +With a write converter: + strip_converter = proc {|field| field.strip } + str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter) + str # => "a,b,c\n" + +With two write converters (called in order): + upcase_converter = proc {|field| field.upcase } + downcase_converter = proc {|field| field.downcase } + write_converters = [upcase_converter, downcase_converter] + str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters) + str # => "a,b,c\n" + +See also {Write Converters}[#class-CSV-label-Write+Converters] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/write_empty_value.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_empty_value.rdoc new file mode 100644 index 00000000..67be5662 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_empty_value.rdoc @@ -0,0 +1,15 @@ +====== Option +write_empty_value+ + +Specifies the object that is to be substituted for each field +that has an empty \String. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => "" + +Without the option: + str = CSV.generate_line(['a', '', 'c', '']) + str # => "a,\"\",c,\"\"\n" + +With the option: + str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x") + str # => "a,x,c,x\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/write_headers.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_headers.rdoc new file mode 100644 index 00000000..c56aa48a --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_headers.rdoc @@ -0,0 +1,29 @@ +====== Option +write_headers+ + +Specifies the boolean that determines whether a header row is included in the output; +ignored if there are no headers. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil + +Without +write_headers+: + file_path = 't.csv' + CSV.open(file_path,'w', + :headers => ['Name','Value'] + ) do |csv| + csv << ['foo', '0'] + end + CSV.open(file_path) do |csv| + csv.shift + end # => ["foo", "0"] + +With +write_headers+": + CSV.open(file_path,'w', + :write_headers => true, + :headers => ['Name','Value'] + ) do |csv| + csv << ['foo', '0'] + end + CSV.open(file_path) do |csv| + csv.shift + end # => ["Name", "Value"] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/generating/write_nil_value.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_nil_value.rdoc new file mode 100644 index 00000000..65d33ff5 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/generating/write_nil_value.rdoc @@ -0,0 +1,14 @@ +====== Option +write_nil_value+ + +Specifies the object that is to be substituted for each +nil+-valued field. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil + +Without the option: + str = CSV.generate_line(['a', nil, 'c', nil]) + str # => "a,,c,\n" + +With the option: + str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x") + str # => "a,x,c,x\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/converters.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/converters.rdoc new file mode 100644 index 00000000..211fa48d --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/converters.rdoc @@ -0,0 +1,46 @@ +====== Option +converters+ + +Specifies converters to be used in parsing fields. +See {Field Converters}[#class-CSV-label-Field+Converters] + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil + +The value may be a field converter name +(see {Stored Converters}[#class-CSV-label-Stored+Converters]): + str = '1,2,3' + # Without a converter + array = CSV.parse_line(str) + array # => ["1", "2", "3"] + # With built-in converter :integer + array = CSV.parse_line(str, converters: :integer) + array # => [1, 2, 3] + +The value may be a converter list +(see {Converter Lists}[#class-CSV-label-Converter+Lists]): + str = '1,3.14159' + # Without converters + array = CSV.parse_line(str) + array # => ["1", "3.14159"] + # With built-in converters + array = CSV.parse_line(str, converters: [:integer, :float]) + array # => [1, 3.14159] + +The value may be a \Proc custom converter: +(see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]): + str = ' foo , bar , baz ' + # Without a converter + array = CSV.parse_line(str) + array # => [" foo ", " bar ", " baz "] + # With a custom converter + array = CSV.parse_line(str, converters: proc {|field| field.strip }) + array # => ["foo", "bar", "baz"] + +See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters] + +--- + +Raises an exception if the converter is not a converter name or a \Proc: + str = 'foo,0' + # Raises NoMethodError (undefined method `arity' for nil:NilClass) + CSV.parse(str, converters: :foo) diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/empty_value.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/empty_value.rdoc new file mode 100644 index 00000000..7d3bcc07 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/empty_value.rdoc @@ -0,0 +1,13 @@ +====== Option +empty_value+ + +Specifies the object that is to be substituted +for each field that has an empty \String. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string) + +With the default, "": + CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"] + +With a different object: + CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/field_size_limit.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/field_size_limit.rdoc new file mode 100644 index 00000000..797c5776 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/field_size_limit.rdoc @@ -0,0 +1,39 @@ +====== Option +field_size_limit+ + +Specifies the \Integer field size limit. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil + +This is a maximum size CSV will read ahead looking for the closing quote for a field. +(In truth, it reads to the first line ending beyond this size.) +If a quote cannot be found within the limit CSV will raise a MalformedCSVError, +assuming the data is faulty. +You can use this limit to prevent what are effectively DoS attacks on the parser. +However, this limit can cause a legitimate parse to fail; +therefore the default value is +nil+ (no limit). + +For the examples in this section: + str = <<~EOT + "a","b" + " + 2345 + ","" + EOT + str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n" + +Using the default +nil+: + ary = CSV.parse(str) + ary # => [["a", "b"], ["\n2345\n", ""]] + +Using 50: + field_size_limit = 50 + ary = CSV.parse(str, field_size_limit: field_size_limit) + ary # => [["a", "b"], ["\n2345\n", ""]] + +--- + +Raises an exception if a field is too long: + big_str = "123456789\n" * 1024 + # Raises CSV::MalformedCSVError (Field size exceeded in line 1.) + CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048) diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/header_converters.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/header_converters.rdoc new file mode 100644 index 00000000..30918080 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/header_converters.rdoc @@ -0,0 +1,43 @@ +====== Option +header_converters+ + +Specifies converters to be used in parsing headers. +See {Header Converters}[#class-CSV-label-Header+Converters] + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil + +Identical in functionality to option {converters}[#class-CSV-label-Option+converters] +except that: +- The converters apply only to the header row. +- The built-in header converters are +:downcase+ and +:symbol+. + +This section assumes prior execution of: + str = <<-EOT + Name,Value + foo,0 + bar,1 + baz,2 + EOT + # With no header converter + table = CSV.parse(str, headers: true) + table.headers # => ["Name", "Value"] + +The value may be a header converter name +(see {Stored Converters}[#class-CSV-label-Stored+Converters]): + table = CSV.parse(str, headers: true, header_converters: :downcase) + table.headers # => ["name", "value"] + +The value may be a converter list +(see {Converter Lists}[#class-CSV-label-Converter+Lists]): + header_converters = [:downcase, :symbol] + table = CSV.parse(str, headers: true, header_converters: header_converters) + table.headers # => [:name, :value] + +The value may be a \Proc custom converter +(see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]): + upcase_converter = proc {|field| field.upcase } + table = CSV.parse(str, headers: true, header_converters: upcase_converter) + table.headers # => ["NAME", "VALUE"] + +See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters] + diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/headers.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/headers.rdoc new file mode 100644 index 00000000..0ea151f2 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/headers.rdoc @@ -0,0 +1,63 @@ +====== Option +headers+ + +Specifies a boolean, \Symbol, \Array, or \String to be used +to define column headers. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:headers) # => false + +--- + +Without +headers+: + str = <<-EOT + Name,Count + foo,0 + bar,1 + bax,2 + EOT + csv = CSV.new(str) + csv # => # + csv.headers # => nil + csv.shift # => ["Name", "Count"] + +--- + +If set to +true+ or the \Symbol +:first_row+, +the first row of the data is treated as a row of headers: + str = <<-EOT + Name,Count + foo,0 + bar,1 + bax,2 + EOT + csv = CSV.new(str, headers: true) + csv # => # + csv.headers # => ["Name", "Count"] + csv.shift # => # + +--- + +If set to an \Array, the \Array elements are treated as headers: + str = <<-EOT + foo,0 + bar,1 + bax,2 + EOT + csv = CSV.new(str, headers: ['Name', 'Count']) + csv + csv.headers # => ["Name", "Count"] + csv.shift # => # + +--- + +If set to a \String +str+, method CSV::parse_line(str, options) is called +with the current +options+, and the returned \Array is treated as headers: + str = <<-EOT + foo,0 + bar,1 + bax,2 + EOT + csv = CSV.new(str, headers: 'Name,Count') + csv + csv.headers # => ["Name", "Count"] + csv.shift # => # diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/liberal_parsing.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/liberal_parsing.rdoc new file mode 100644 index 00000000..603de286 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/liberal_parsing.rdoc @@ -0,0 +1,38 @@ +====== Option +liberal_parsing+ + +Specifies the boolean or hash value that determines whether +CSV will attempt to parse input not conformant with RFC 4180, +such as double quotes in unquoted fields. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false + +For the next two examples: + str = 'is,this "three, or four",fields' + +Without +liberal_parsing+: + # Raises CSV::MalformedCSVError (Illegal quoting in str 1.) + CSV.parse_line(str) + +With +liberal_parsing+: + ary = CSV.parse_line(str, liberal_parsing: true) + ary # => ["is", "this \"three", " or four\"", "fields"] + +Use the +backslash_quote+ sub-option to parse values that use +a backslash to escape a double-quote character. This +causes the parser to treat \" as if it were +"". + +For the next two examples: + str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"' + +With +liberal_parsing+, but without the +backslash_quote+ sub-option: + # Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator. + ary = CSV.parse_line(str, liberal_parsing: true) + ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"] + puts ary[1] # => "Harry \"Handcuff\" Houdini + +With +liberal_parsing+ and its +backslash_quote+ sub-option: + ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true }) + ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"] + puts ary[1] # => Harry "Handcuff" Houdini, the one and only diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/nil_value.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/nil_value.rdoc new file mode 100644 index 00000000..412e8795 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/nil_value.rdoc @@ -0,0 +1,12 @@ +====== Option +nil_value+ + +Specifies the object that is to be substituted for each null (no-text) field. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil + +With the default, +nil+: + CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"] + +With a different object: + CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/return_headers.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/return_headers.rdoc new file mode 100644 index 00000000..45d2e3f3 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/return_headers.rdoc @@ -0,0 +1,22 @@ +====== Option +return_headers+ + +Specifies the boolean that determines whether method #shift +returns or ignores the header row. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false + +Examples: + str = <<-EOT + Name,Count + foo,0 + bar,1 + bax,2 + EOT + # Without return_headers first row is str. + csv = CSV.new(str, headers: true) + csv.shift # => # + # With return_headers first row is headers. + csv = CSV.new(str, headers: true, return_headers: true) + csv.shift # => # + diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_blanks.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_blanks.rdoc new file mode 100644 index 00000000..2c8f7b7b --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_blanks.rdoc @@ -0,0 +1,31 @@ +====== Option +skip_blanks+ + +Specifies a boolean that determines whether blank lines in the input will be ignored; +a line that contains a column separator is not considered to be blank. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false + +See also option {skiplines}[#class-CSV-label-Option+skip_lines]. + +For examples in this section: + str = <<-EOT + foo,0 + + bar,1 + baz,2 + + , + EOT + +Using the default, +false+: + ary = CSV.parse(str) + ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]] + +Using +true+: + ary = CSV.parse(str, skip_blanks: true) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]] + +Using a truthy value: + ary = CSV.parse(str, skip_blanks: :foo) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_lines.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_lines.rdoc new file mode 100644 index 00000000..1481c40a --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/skip_lines.rdoc @@ -0,0 +1,37 @@ +====== Option +skip_lines+ + +Specifies an object to use in identifying comment lines in the input that are to be ignored: +* If a \Regexp, ignores lines that match it. +* If a \String, converts it to a \Regexp, ignores lines that match it. +* If +nil+, no lines are considered to be comments. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil + +For examples in this section: + str = <<-EOT + # Comment + foo,0 + bar,1 + baz,2 + # Another comment + EOT + str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n" + +Using the default, +nil+: + ary = CSV.parse(str) + ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]] + +Using a \Regexp: + ary = CSV.parse(str, skip_lines: /^#/) + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Using a \String: + ary = CSV.parse(str, skip_lines: '#') + ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +--- + +Raises an exception if given an object that is not a \Regexp, a \String, or +nil+: + # Raises ArgumentError (:skip_lines has to respond to #match: 0) + CSV.parse(str, skip_lines: 0) diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/strip.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/strip.rdoc new file mode 100644 index 00000000..56ae4310 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/strip.rdoc @@ -0,0 +1,15 @@ +====== Option +strip+ + +Specifies the boolean value that determines whether +whitespace is stripped from each input field. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:strip) # => false + +With default value +false+: + ary = CSV.parse_line(' a , b ') + ary # => [" a ", " b "] + +With value +true+: + ary = CSV.parse_line(' a , b ', strip: true) + ary # => ["a", "b"] diff --git a/bin/gems/csv-3.3.2/doc/csv/options/parsing/unconverted_fields.rdoc b/bin/gems/csv-3.3.2/doc/csv/options/parsing/unconverted_fields.rdoc new file mode 100644 index 00000000..3e7f839d --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/options/parsing/unconverted_fields.rdoc @@ -0,0 +1,27 @@ +====== Option +unconverted_fields+ + +Specifies the boolean that determines whether unconverted field values are to be available. + +Default value: + CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil + +The unconverted field values are those found in the source data, +prior to any conversions performed via option +converters+. + +When option +unconverted_fields+ is +true+, +each returned row (\Array or \CSV::Row) has an added method, ++unconverted_fields+, that returns the unconverted field values: + str = <<-EOT + foo,0 + bar,1 + baz,2 + EOT + # Without unconverted_fields + csv = CSV.parse(str, converters: :integer) + csv # => [["foo", 0], ["bar", 1], ["baz", 2]] + csv.first.respond_to?(:unconverted_fields) # => false + # With unconverted_fields + csv = CSV.parse(str, converters: :integer, unconverted_fields: true) + csv # => [["foo", 0], ["bar", 1], ["baz", 2]] + csv.first.respond_to?(:unconverted_fields) # => true + csv.first.unconverted_fields # => ["foo", "0"] diff --git a/bin/gems/csv-3.3.2/doc/csv/recipes/filtering.rdoc b/bin/gems/csv-3.3.2/doc/csv/recipes/filtering.rdoc new file mode 100644 index 00000000..d92afb72 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/recipes/filtering.rdoc @@ -0,0 +1,226 @@ +== Recipes for Filtering \CSV + +These recipes are specific code examples for specific \CSV filtering tasks. + +For other recipes, see {Recipes for CSV}[./recipes_rdoc.html]. + +All code snippets on this page assume that the following has been executed: + require 'csv' + +=== Contents + +- {Source and Output Formats}[#label-Source+and+Output+Formats] + - {Filtering String to String}[#label-Filtering+String+to+String] + - {Recipe: Filter String to String parsing Headers}[#label-Recipe-3A+Filter+String+to+String+parsing+Headers] + - {Recipe: Filter String to String parsing and writing Headers}[#label-Recipe-3A+Filter+String+to+String+parsing+and+writing+Headers] + - {Recipe: Filter String to String Without Headers}[#label-Recipe-3A+Filter+String+to+String+Without+Headers] + - {Filtering String to IO Stream}[#label-Filtering+String+to+IO+Stream] + - {Recipe: Filter String to IO Stream parsing Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+parsing+Headers] + - {Recipe: Filter String to IO Stream parsing and writing Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+parsing+and+writing+Headers] + - {Recipe: Filter String to IO Stream Without Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+Without+Headers] + - {Filtering IO Stream to String}[#label-Filtering+IO+Stream+to+String] + - {Recipe: Filter IO Stream to String parsing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+parsing+Headers] + - {Recipe: Filter IO Stream to String parsing and writing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+parsing+and+writing+Headers] + - {Recipe: Filter IO Stream to String Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+Without+Headers] + - {Filtering IO Stream to IO Stream}[#label-Filtering+IO+Stream+to+IO+Stream] + - {Recipe: Filter IO Stream to IO Stream parsing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+parsing+Headers] + - {Recipe: Filter IO Stream to IO Stream parsing and writing Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+parsing+and+writing+Headers] + - {Recipe: Filter IO Stream to IO Stream Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+Without+Headers] + +=== Source and Output Formats + +You can use a Unix-style "filter" for \CSV data. +The filter reads source \CSV data and writes output \CSV data as modified by the filter. +The input and output \CSV data may be any mixture of \Strings and \IO streams. + +==== Filtering \String to \String + +You can filter one \String to another, with or without headers. + +===== Recipe: Filter \String to \String parsing Headers + +Use class method CSV.filter with option +headers+ to filter a \String to another \String: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + out_string = '' + CSV.filter(in_string, out_string, headers: true) do |row| + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \String to \String parsing and writing Headers + +Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter a \String to another \String including header row: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + out_string = '' + CSV.filter(in_string, out_string, headers: true, out_write_headers: true) do |row| + unless row.is_a?(Array) + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \String to \String Without Headers + +Use class method CSV.filter without option +headers+ to filter a \String to another \String: + in_string = "foo,0\nbar,1\nbaz,2\n" + out_string = '' + CSV.filter(in_string, out_string) do |row| + row[0] = row[0].upcase + row[1] *= 4 + end + out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +==== Filtering \String to \IO Stream + +You can filter a \String to an \IO stream, with or without headers. + +===== Recipe: Filter \String to \IO Stream parsing Headers + +Use class method CSV.filter with option +headers+ to filter a \String to an \IO stream: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.open(path, 'w') do |out_io| + CSV.filter(in_string, out_io, headers: true) do |row| + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \String to \IO Stream parsing and writing Headers + +Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter a \String to an \IO stream including header row: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.open(path, 'w') do |out_io| + CSV.filter(in_string, out_io, headers: true, out_write_headers: true ) do |row| + unless row.is_a?(Array) + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + end + p File.read(path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \String to \IO Stream Without Headers + +Use class method CSV.filter without option +headers+ to filter a \String to an \IO stream: + in_string = "foo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.open(path, 'w') do |out_io| + CSV.filter(in_string, out_io) do |row| + row[0] = row[0].upcase + row[1] *= 4 + end + end + p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +==== Filtering \IO Stream to \String + +You can filter an \IO stream to a \String, with or without headers. + +===== Recipe: Filter \IO Stream to \String parsing Headers + +Use class method CSV.filter with option +headers+ to filter an \IO stream to a \String: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, in_string) + out_string = '' + File.open(path) do |in_io| + CSV.filter(in_io, out_string, headers: true) do |row| + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \IO Stream to \String parsing and writing Headers + +Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter an \IO stream to a \String including header row: + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, in_string) + out_string = '' + File.open(path) do |in_io| + CSV.filter(in_io, out_string, headers: true, out_write_headers: true) do |row| + unless row.is_a?(Array) + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + end + out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \IO Stream to \String Without Headers + +Use class method CSV.filter without option +headers+ to filter an \IO stream to a \String: + in_string = "foo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, in_string) + out_string = '' + File.open(path) do |in_io| + CSV.filter(in_io, out_string) do |row| + row[0] = row[0].upcase + row[1] *= 4 + end + end + out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +==== Filtering \IO Stream to \IO Stream + +You can filter an \IO stream to another \IO stream, with or without headers. + +===== Recipe: Filter \IO Stream to \IO Stream parsing Headers + +Use class method CSV.filter with option +headers+ to filter an \IO stream to another \IO stream: + in_path = 't.csv' + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + File.write(in_path, in_string) + out_path = 'u.csv' + File.open(in_path) do |in_io| + File.open(out_path, 'w') do |out_io| + CSV.filter(in_io, out_io, headers: true) do |row| + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + end + p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \IO Stream to \IO Stream parsing and writing Headers + +Use class method CSV.filter with option +headers+ and +out_write_headers+ to filter an \IO stream to another \IO stream including header row: + in_path = 't.csv' + in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + File.write(in_path, in_string) + out_path = 'u.csv' + File.open(in_path) do |in_io| + File.open(out_path, 'w') do |out_io| + CSV.filter(in_io, out_io, headers: true, out_write_headers: true) do |row| + unless row.is_a?(Array) + row['Name'] = row['Name'].upcase + row['Value'] *= 4 + end + end + end + end + p File.read(out_path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n" + +===== Recipe: Filter \IO Stream to \IO Stream Without Headers + +Use class method CSV.filter without option +headers+ to filter an \IO stream to another \IO stream: + in_path = 't.csv' + in_string = "foo,0\nbar,1\nbaz,2\n" + File.write(in_path, in_string) + out_path = 'u.csv' + File.open(in_path) do |in_io| + File.open(out_path, 'w') do |out_io| + CSV.filter(in_io, out_io) do |row| + row[0] = row[0].upcase + row[1] *= 4 + end + end + end + p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/recipes/generating.rdoc b/bin/gems/csv-3.3.2/doc/csv/recipes/generating.rdoc new file mode 100644 index 00000000..d96ff85c --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/recipes/generating.rdoc @@ -0,0 +1,298 @@ +== Recipes for Generating \CSV + +These recipes are specific code examples for specific \CSV generating tasks. + +For other recipes, see {Recipes for CSV}[./recipes_rdoc.html]. + +All code snippets on this page assume that the following has been executed: + require 'csv' + +=== Contents + +- {Output Formats}[#label-Output+Formats] + - {Generating to a String}[#label-Generating+to+a+String] + - {Recipe: Generate to String with Headers}[#label-Recipe-3A+Generate+to+String+with+Headers] + - {Recipe: Generate to String Without Headers}[#label-Recipe-3A+Generate+to+String+Without+Headers] + - {Generating to a File}[#label-Generating+to+a+File] + - {Recipe: Generate to File with Headers}[#label-Recipe-3A+Generate+to+File+with+Headers] + - {Recipe: Generate to File Without Headers}[#label-Recipe-3A+Generate+to+File+Without+Headers] + - {Generating to IO an Stream}[#label-Generating+to+an+IO+Stream] + - {Recipe: Generate to IO Stream with Headers}[#label-Recipe-3A+Generate+to+IO+Stream+with+Headers] + - {Recipe: Generate to IO Stream Without Headers}[#label-Recipe-3A+Generate+to+IO+Stream+Without+Headers] +- {Converting Fields}[#label-Converting+Fields] + - {Recipe: Filter Generated Field Strings}[#label-Recipe-3A+Filter+Generated+Field+Strings] + - {Recipe: Specify Multiple Write Converters}[#label-Recipe-3A+Specify+Multiple+Write+Converters] +- {RFC 4180 Compliance}[#label-RFC+4180+Compliance] + - {Row Separator}[#label-Row+Separator] + - {Recipe: Generate Compliant Row Separator}[#label-Recipe-3A+Generate+Compliant+Row+Separator] + - {Recipe: Generate Non-Compliant Row Separator}[#label-Recipe-3A+Generate+Non-Compliant+Row+Separator] + - {Column Separator}[#label-Column+Separator] + - {Recipe: Generate Compliant Column Separator}[#label-Recipe-3A+Generate+Compliant+Column+Separator] + - {Recipe: Generate Non-Compliant Column Separator}[#label-Recipe-3A+Generate+Non-Compliant+Column+Separator] + - {Quotes}[#label-Quotes] + - {Recipe: Quote All Fields}[#label-Recipe-3A+Quote+All+Fields] + - {Recipe: Quote Empty Fields}[#label-Recipe-3A+Quote+Empty+Fields] + - {Recipe: Generate Compliant Quote Character}[#label-Recipe-3A+Generate+Compliant+Quote+Character] + - {Recipe: Generate Non-Compliant Quote Character}[#label-Recipe-3A+Generate+Non-Compliant+Quote+Character] + +=== Output Formats + +You can generate \CSV output to a \String, to a \File (via its path), or to an \IO stream. + +==== Generating to a \String + +You can generate \CSV output to a \String, with or without headers. + +===== Recipe: Generate to \String with Headers + +Use class method CSV.generate with option +headers+ to generate to a \String. + +This example uses method CSV#<< to append the rows +that are to be generated: + output_string = CSV.generate('', headers: ['Name', 'Value'], write_headers: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n" + +===== Recipe: Generate to \String Without Headers + +Use class method CSV.generate without option +headers+ to generate to a \String. + +This example uses method CSV#<< to append the rows +that are to be generated: + output_string = CSV.generate do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Foo,0\nBar,1\nBaz,2\n" + +==== Generating to a \File + +You can generate /CSV data to a \File, with or without headers. + +===== Recipe: Generate to \File with Headers + +Use class method CSV.open with option +headers+ generate to a \File. + +This example uses method CSV#<< to append the rows +that are to be generated: + path = 't.csv' + CSV.open(path, 'w', headers: ['Name', 'Value'], write_headers: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n" + +===== Recipe: Generate to \File Without Headers + +Use class method CSV.open without option +headers+ to generate to a \File. + +This example uses method CSV#<< to append the rows +that are to be generated: + path = 't.csv' + CSV.open(path, 'w') do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n" + +==== Generating to an \IO Stream + +You can generate \CSV data to an \IO stream, with or without headers. + +==== Recipe: Generate to \IO Stream with Headers + +Use class method CSV.new with option +headers+ to generate \CSV data to an \IO stream: + path = 't.csv' + File.open(path, 'w') do |file| + csv = CSV.new(file, headers: ['Name', 'Value'], write_headers: true) + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n" + +===== Recipe: Generate to \IO Stream Without Headers + +Use class method CSV.new without option +headers+ to generate \CSV data to an \IO stream: + path = 't.csv' + File.open(path, 'w') do |file| + csv = CSV.new(file) + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n" + +=== Converting Fields + +You can use _write_ _converters_ to convert fields when generating \CSV. + +==== Recipe: Filter Generated Field Strings + +Use option :write_converters and a custom converter to convert field values when generating \CSV. + +This example defines and uses a custom write converter to strip whitespace from generated fields: + strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field } + output_string = CSV.generate(write_converters: strip_converter) do |csv| + csv << [' foo ', 0] + csv << [' bar ', 1] + csv << [' baz ', 2] + end + output_string # => "foo,0\nbar,1\nbaz,2\n" + +==== Recipe: Specify Multiple Write Converters + +Use option :write_converters and multiple custom converters +to convert field values when generating \CSV. + +This example defines and uses two custom write converters to strip and upcase generated fields: + strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field } + upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field } + converters = [strip_converter, upcase_converter] + output_string = CSV.generate(write_converters: converters) do |csv| + csv << [' foo ', 0] + csv << [' bar ', 1] + csv << [' baz ', 2] + end + output_string # => "FOO,0\nBAR,1\nBAZ,2\n" + +=== RFC 4180 Compliance + +By default, \CSV generates data that is compliant with +{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180] +with respect to: +- Column separator. +- Quote character. + +==== Row Separator + +RFC 4180 specifies the row separator CRLF (Ruby "\r\n"). + +===== Recipe: Generate Compliant Row Separator + +For strict compliance, use option +:row_sep+ to specify row separator "\r\n": + output_string = CSV.generate('', row_sep: "\r\n") do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Foo,0\r\nBar,1\r\nBaz,2\r\n" + +===== Recipe: Generate Non-Compliant Row Separator + +For data with non-compliant row separators, use option +:row_sep+ with a different value: +This example source uses semicolon (";') as its row separator: + output_string = CSV.generate('', row_sep: ";") do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Foo,0;Bar,1;Baz,2;" + +==== Column Separator + +RFC 4180 specifies column separator COMMA (Ruby ","). + +===== Recipe: Generate Compliant Column Separator + +Because the \CSV default comma separator is ",", +you need not specify option +:col_sep+ for compliant data: + output_string = CSV.generate('') do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Foo,0\nBar,1\nBaz,2\n" + +===== Recipe: Generate Non-Compliant Column Separator + +For data with non-compliant column separators, use option +:col_sep+. +This example source uses TAB ("\t") as its column separator: + output_string = CSV.generate('', col_sep: "\t") do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "Foo\t0\nBar\t1\nBaz\t2\n" + +==== Quotes + +IFC 4180 allows most fields to be quoted or not. +By default, \CSV does not quote most fields. + +However, a field containing the current row separator, column separator, +or quote character is automatically quoted, producing IFC 4180 compliance: + # Field contains row separator. + output_string = CSV.generate('') do |csv| + row_sep = csv.row_sep + csv << ["Foo#{row_sep}Foo", 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "\"Foo\nFoo\",0\nBar,1\nBaz,2\n" + # Field contains column separator. + output_string = CSV.generate('') do |csv| + col_sep = csv.col_sep + csv << ["Foo#{col_sep}Foo", 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "\"Foo,Foo\",0\nBar,1\nBaz,2\n" + # Field contains quote character. + output_string = CSV.generate('') do |csv| + quote_char = csv.quote_char + csv << ["Foo#{quote_char}Foo", 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "\"Foo\"\"Foo\",0\nBar,1\nBaz,2\n" + +===== Recipe: Quote All Fields + +Use option +:force_quotes+ to force quoted fields: + output_string = CSV.generate('', force_quotes: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n" + +===== Recipe: Quote Empty Fields + +Use option +:quote_empty+ to force quoting for empty fields: + output_string = CSV.generate('', quote_empty: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['', 2] + end + output_string # => "Foo,0\nBar,1\n\"\",2\n" + +===== Recipe: Generate Compliant Quote Character + +RFC 4180 specifies quote character DQUOTE (Ruby "\""). + +Because the \CSV default quote character is also "\"", +you need not specify option +:quote_char+ for compliant data: + output_string = CSV.generate('', force_quotes: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n" + +===== Recipe: Generate Non-Compliant Quote Character + +For data with non-compliant quote characters, use option +:quote_char+. +This example source uses SQUOTE ("'") as its quote character: + output_string = CSV.generate('', quote_char: "'", force_quotes: true) do |csv| + csv << ['Foo', 0] + csv << ['Bar', 1] + csv << ['Baz', 2] + end + output_string # => "'Foo','0'\n'Bar','1'\n'Baz','2'\n" diff --git a/bin/gems/csv-3.3.2/doc/csv/recipes/parsing.rdoc b/bin/gems/csv-3.3.2/doc/csv/recipes/parsing.rdoc new file mode 100644 index 00000000..63673072 --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/recipes/parsing.rdoc @@ -0,0 +1,554 @@ +== Recipes for Parsing \CSV + +These recipes are specific code examples for specific \CSV parsing tasks. + +For other recipes, see {Recipes for CSV}[./recipes_rdoc.html]. + +All code snippets on this page assume that the following has been executed: + require 'csv' + +=== Contents + +- {Source Formats}[#label-Source+Formats] + - {Parsing from a String}[#label-Parsing+from+a+String] + - {Recipe: Parse from String with Headers}[#label-Recipe-3A+Parse+from+String+with+Headers] + - {Recipe: Parse from String Without Headers}[#label-Recipe-3A+Parse+from+String+Without+Headers] + - {Parsing from a File}[#label-Parsing+from+a+File] + - {Recipe: Parse from File with Headers}[#label-Recipe-3A+Parse+from+File+with+Headers] + - {Recipe: Parse from File Without Headers}[#label-Recipe-3A+Parse+from+File+Without+Headers] + - {Parsing from an IO Stream}[#label-Parsing+from+an+IO+Stream] + - {Recipe: Parse from IO Stream with Headers}[#label-Recipe-3A+Parse+from+IO+Stream+with+Headers] + - {Recipe: Parse from IO Stream Without Headers}[#label-Recipe-3A+Parse+from+IO+Stream+Without+Headers] +- {RFC 4180 Compliance}[#label-RFC+4180+Compliance] + - {Row Separator}[#label-Row+Separator] + - {Recipe: Handle Compliant Row Separator}[#label-Recipe-3A+Handle+Compliant+Row+Separator] + - {Recipe: Handle Non-Compliant Row Separator}[#label-Recipe-3A+Handle+Non-Compliant+Row+Separator] + - {Column Separator}[#label-Column+Separator] + - {Recipe: Handle Compliant Column Separator}[#label-Recipe-3A+Handle+Compliant+Column+Separator] + - {Recipe: Handle Non-Compliant Column Separator}[#label-Recipe-3A+Handle+Non-Compliant+Column+Separator] + - {Quote Character}[#label-Quote+Character] + - {Recipe: Handle Compliant Quote Character}[#label-Recipe-3A+Handle+Compliant+Quote+Character] + - {Recipe: Handle Non-Compliant Quote Character}[#label-Recipe-3A+Handle+Non-Compliant+Quote+Character] + - {Recipe: Allow Liberal Parsing}[#label-Recipe-3A+Allow+Liberal+Parsing] +- {Special Handling}[#label-Special+Handling] + - {Special Line Handling}[#label-Special+Line+Handling] + - {Recipe: Ignore Blank Lines}[#label-Recipe-3A+Ignore+Blank+Lines] + - {Recipe: Ignore Selected Lines}[#label-Recipe-3A+Ignore+Selected+Lines] + - {Special Field Handling}[#label-Special+Field+Handling] + - {Recipe: Strip Fields}[#label-Recipe-3A+Strip+Fields] + - {Recipe: Handle Null Fields}[#label-Recipe-3A+Handle+Null+Fields] + - {Recipe: Handle Empty Fields}[#label-Recipe-3A+Handle+Empty+Fields] +- {Converting Fields}[#label-Converting+Fields] + - {Converting Fields to Objects}[#label-Converting+Fields+to+Objects] + - {Recipe: Convert Fields to Integers}[#label-Recipe-3A+Convert+Fields+to+Integers] + - {Recipe: Convert Fields to Floats}[#label-Recipe-3A+Convert+Fields+to+Floats] + - {Recipe: Convert Fields to Numerics}[#label-Recipe-3A+Convert+Fields+to+Numerics] + - {Recipe: Convert Fields to Dates}[#label-Recipe-3A+Convert+Fields+to+Dates] + - {Recipe: Convert Fields to DateTimes}[#label-Recipe-3A+Convert+Fields+to+DateTimes] + - {Recipe: Convert Fields to Times}[#label-Recipe-3A+Convert+Fields+to+Times] + - {Recipe: Convert Assorted Fields to Objects}[#label-Recipe-3A+Convert+Assorted+Fields+to+Objects] + - {Recipe: Convert Fields to Other Objects}[#label-Recipe-3A+Convert+Fields+to+Other+Objects] + - {Recipe: Filter Field Strings}[#label-Recipe-3A+Filter+Field+Strings] + - {Recipe: Register Field Converters}[#label-Recipe-3A+Register+Field+Converters] + - {Using Multiple Field Converters}[#label-Using+Multiple+Field+Converters] + - {Recipe: Specify Multiple Field Converters in Option :converters}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+Option+-3Aconverters] + - {Recipe: Specify Multiple Field Converters in a Custom Converter List}[#label-Recipe-3A+Specify+Multiple+Field+Converters+in+a+Custom+Converter+List] +- {Converting Headers}[#label-Converting+Headers] + - {Recipe: Convert Headers to Lowercase}[#label-Recipe-3A+Convert+Headers+to+Lowercase] + - {Recipe: Convert Headers to Symbols}[#label-Recipe-3A+Convert+Headers+to+Symbols] + - {Recipe: Filter Header Strings}[#label-Recipe-3A+Filter+Header+Strings] + - {Recipe: Register Header Converters}[#label-Recipe-3A+Register+Header+Converters] + - {Using Multiple Header Converters}[#label-Using+Multiple+Header+Converters] + - {Recipe: Specify Multiple Header Converters in Option :header_converters}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+Option+-3Aheader_converters] + - {Recipe: Specify Multiple Header Converters in a Custom Header Converter List}[#label-Recipe-3A+Specify+Multiple+Header+Converters+in+a+Custom+Header+Converter+List] +- {Diagnostics}[#label-Diagnostics] + - {Recipe: Capture Unconverted Fields}[#label-Recipe-3A+Capture+Unconverted+Fields] + - {Recipe: Capture Field Info}[#label-Recipe-3A+Capture+Field+Info] + +=== Source Formats + +You can parse \CSV data from a \String, from a \File (via its path), or from an \IO stream. + +==== Parsing from a \String + +You can parse \CSV data from a \String, with or without headers. + +===== Recipe: Parse from \String with Headers + +Use class method CSV.parse with option +headers+ to read a source \String all at once +(may have memory resource implications): + string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + CSV.parse(string, headers: true) # => # + +Use instance method CSV#each with option +headers+ to read a source \String one row at a time: + CSV.new(string, headers: true).each do |row| + p row + end +Output: + # + # + # + +===== Recipe: Parse from \String Without Headers + +Use class method CSV.parse without option +headers+ to read a source \String all at once +(may have memory resource implications): + string = "foo,0\nbar,1\nbaz,2\n" + CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Use instance method CSV#each without option +headers+ to read a source \String one row at a time: + CSV.new(string).each do |row| + p row + end +Output: + ["foo", "0"] + ["bar", "1"] + ["baz", "2"] + +==== Parsing from a \File + +You can parse \CSV data from a \File, with or without headers. + +===== Recipe: Parse from \File with Headers + +Use class method CSV.read with option +headers+ to read a file all at once: + string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, string) + CSV.read(path, headers: true) # => # + +Use class method CSV.foreach with option +headers+ to read one row at a time: + CSV.foreach(path, headers: true) do |row| + p row + end +Output: + # + # + # + +===== Recipe: Parse from \File Without Headers + +Use class method CSV.read without option +headers+ to read a file all at once: + string = "foo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, string) + CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Use class method CSV.foreach without option +headers+ to read one row at a time: + CSV.foreach(path) do |row| + p row + end +Output: + ["foo", "0"] + ["bar", "1"] + ["baz", "2"] + +==== Parsing from an \IO Stream + +You can parse \CSV data from an \IO stream, with or without headers. + +===== Recipe: Parse from \IO Stream with Headers + +Use class method CSV.parse with option +headers+ to read an \IO stream all at once: + string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, string) + File.open(path) do |file| + CSV.parse(file, headers: true) + end # => # + +Use class method CSV.foreach with option +headers+ to read one row at a time: + File.open(path) do |file| + CSV.foreach(file, headers: true) do |row| + p row + end + end +Output: + # + # + # + +===== Recipe: Parse from \IO Stream Without Headers + +Use class method CSV.parse without option +headers+ to read an \IO stream all at once: + string = "foo,0\nbar,1\nbaz,2\n" + path = 't.csv' + File.write(path, string) + File.open(path) do |file| + CSV.parse(file) + end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +Use class method CSV.foreach without option +headers+ to read one row at a time: + File.open(path) do |file| + CSV.foreach(file) do |row| + p row + end + end +Output: + ["foo", "0"] + ["bar", "1"] + ["baz", "2"] + +=== RFC 4180 Compliance + +By default, \CSV parses data that is compliant with +{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180] +with respect to: +- Row separator. +- Column separator. +- Quote character. + +==== Row Separator + +RFC 4180 specifies the row separator CRLF (Ruby "\r\n"). + +Although the \CSV default row separator is "\n", +the parser also by default handles row separator "\r" and the RFC-compliant "\r\n". + +===== Recipe: Handle Compliant Row Separator + +For strict compliance, use option +:row_sep+ to specify row separator "\r\n", +which allows the compliant row separator: + source = "foo,1\r\nbar,1\r\nbaz,2\r\n" + CSV.parse(source, row_sep: "\r\n") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] +But rejects other row separators: + source = "foo,1\nbar,1\nbaz,2\n" + CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError + source = "foo,1\rbar,1\rbaz,2\r" + CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError + source = "foo,1\n\rbar,1\n\rbaz,2\n\r" + CSV.parse(source, row_sep: "\r\n") # Raised MalformedCSVError + +===== Recipe: Handle Non-Compliant Row Separator + +For data with non-compliant row separators, use option +:row_sep+. +This example source uses semicolon (";") as its row separator: + source = "foo,1;bar,1;baz,2;" + CSV.parse(source, row_sep: ';') # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] + +==== Column Separator + +RFC 4180 specifies column separator COMMA (Ruby ","). + +===== Recipe: Handle Compliant Column Separator + +Because the \CSV default comma separator is ',', +you need not specify option +:col_sep+ for compliant data: + source = "foo,1\nbar,1\nbaz,2\n" + CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] + +===== Recipe: Handle Non-Compliant Column Separator + +For data with non-compliant column separators, use option +:col_sep+. +This example source uses TAB ("\t") as its column separator: + source = "foo,1\tbar,1\tbaz,2" + CSV.parse(source, col_sep: "\t") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] + +==== Quote Character + +RFC 4180 specifies quote character DQUOTE (Ruby "\""). + +===== Recipe: Handle Compliant Quote Character + +Because the \CSV default quote character is "\"", +you need not specify option +:quote_char+ for compliant data: + source = "\"foo\",\"1\"\n\"bar\",\"1\"\n\"baz\",\"2\"\n" + CSV.parse(source) # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] + +===== Recipe: Handle Non-Compliant Quote Character + +For data with non-compliant quote characters, use option +:quote_char+. +This example source uses SQUOTE ("'") as its quote character: + source = "'foo','1'\n'bar','1'\n'baz','2'\n" + CSV.parse(source, quote_char: "'") # => [["foo", "1"], ["bar", "1"], ["baz", "2"]] + +==== Recipe: Allow Liberal Parsing + +Use option +:liberal_parsing+ to specify that \CSV should +attempt to parse input not conformant with RFC 4180, such as double quotes in unquoted fields: + source = 'is,this "three, or four",fields' + CSV.parse(source) # Raises MalformedCSVError + CSV.parse(source, liberal_parsing: true) # => [["is", "this \"three", " or four\"", "fields"]] + +=== Special Handling + +You can use parsing options to specify special handling for certain lines and fields. + +==== Special Line Handling + +Use parsing options to specify special handling for blank lines, or for other selected lines. + +===== Recipe: Ignore Blank Lines + +Use option +:skip_blanks+ to ignore blank lines: + source = <<-EOT + foo,0 + + bar,1 + baz,2 + + , + EOT + parsed = CSV.parse(source, skip_blanks: true) + parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]] + +===== Recipe: Ignore Selected Lines + +Use option +:skip_lines+ to ignore selected lines. + source = <<-EOT + # Comment + foo,0 + bar,1 + baz,2 + # Another comment + EOT + parsed = CSV.parse(source, skip_lines: /^#/) + parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + +==== Special Field Handling + +Use parsing options to specify special handling for certain field values. + +===== Recipe: Strip Fields + +Use option +:strip+ to strip parsed field values: + CSV.parse_line(' a , b ', strip: true) # => ["a", "b"] + +===== Recipe: Handle Null Fields + +Use option +:nil_value+ to specify a value that will replace each field +that is null (no text): + CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"] + +===== Recipe: Handle Empty Fields + +Use option +:empty_value+ to specify a value that will replace each field +that is empty (\String of length 0); + CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"] + +=== Converting Fields + +You can use field converters to change parsed \String fields into other objects, +or to otherwise modify the \String fields. + +==== Converting Fields to Objects + +Use field converters to change parsed \String objects into other, more specific, objects. + +There are built-in field converters for converting to objects of certain classes: +- \Float +- \Integer +- \Date +- \DateTime +- \Time + +Other built-in field converters include: +- +:numeric+: converts to \Integer and \Float. +- +:all+: converts to \DateTime, \Integer, \Float. + +You can also define field converters to convert to objects of other classes. + +===== Recipe: Convert Fields to Integers + +Convert fields to \Integer objects using built-in converter +:integer+: + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, converters: :integer) + parsed.map {|row| row['Value'].class} # => [Integer, Integer, Integer] + +===== Recipe: Convert Fields to Floats + +Convert fields to \Float objects using built-in converter +:float+: + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, converters: :float) + parsed.map {|row| row['Value'].class} # => [Float, Float, Float] + +===== Recipe: Convert Fields to Numerics + +Convert fields to \Integer and \Float objects using built-in converter +:numeric+: + source = "Name,Value\nfoo,0\nbar,1.1\nbaz,2.2\n" + parsed = CSV.parse(source, headers: true, converters: :numeric) + parsed.map {|row| row['Value'].class} # => [Integer, Float, Float] + +===== Recipe: Convert Fields to Dates + +Convert fields to \Date objects using built-in converter +:date+: + source = "Name,Date\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2001-02-03\n" + parsed = CSV.parse(source, headers: true, converters: :date) + parsed.map {|row| row['Date'].class} # => [Date, Date, Date] + +===== Recipe: Convert Fields to DateTimes + +Convert fields to \DateTime objects using built-in converter +:date_time+: + source = "Name,DateTime\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n" + parsed = CSV.parse(source, headers: true, converters: :date_time) + parsed.map {|row| row['DateTime'].class} # => [DateTime, DateTime, DateTime] + +===== Recipe: Convert Fields to Times + +Convert fields to \Time objects using built-in converter +:time+: + source = "Name,Time\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n" + parsed = CSV.parse(source, headers: true, converters: :time) + parsed.map {|row| row['Time'].class} # => [Time, Time, Time] + +===== Recipe: Convert Assorted Fields to Objects + +Convert assorted fields to objects using built-in converter +:all+: + source = "Type,Value\nInteger,0\nFloat,1.0\nDateTime,2001-02-04\n" + parsed = CSV.parse(source, headers: true, converters: :all) + parsed.map {|row| row['Value'].class} # => [Integer, Float, DateTime] + +===== Recipe: Convert Fields to Other Objects + +Define a custom field converter to convert \String fields into other objects. +This example defines and uses a custom field converter +that converts each column-1 value to a \Rational object: + rational_converter = proc do |field, field_context| + field_context.index == 1 ? field.to_r : field + end + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, converters: rational_converter) + parsed.map {|row| row['Value'].class} # => [Rational, Rational, Rational] + +==== Recipe: Filter Field Strings + +Define a custom field converter to modify \String fields. +This example defines and uses a custom field converter +that strips whitespace from each field value: + strip_converter = proc {|field| field.strip } + source = "Name,Value\n foo , 0 \n bar , 1 \n baz , 2 \n" + parsed = CSV.parse(source, headers: true, converters: strip_converter) + parsed['Name'] # => ["foo", "bar", "baz"] + parsed['Value'] # => ["0", "1", "2"] + +==== Recipe: Register Field Converters + +Register a custom field converter, assigning it a name; +then refer to the converter by its name: + rational_converter = proc do |field, field_context| + field_context.index == 1 ? field.to_r : field + end + CSV::Converters[:rational] = rational_converter + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, converters: :rational) + parsed['Value'] # => [(0/1), (1/1), (2/1)] + +==== Using Multiple Field Converters + +You can use multiple field converters in either of these ways: +- Specify converters in option +:converters+. +- Specify converters in a custom converter list. + +===== Recipe: Specify Multiple Field Converters in Option +:converters+ + +Apply multiple field converters by specifying them in option +:converters+: + source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n" + parsed = CSV.parse(source, headers: true, converters: [:integer, :float]) + parsed['Value'] # => [0, 1.0, 2.0] + +===== Recipe: Specify Multiple Field Converters in a Custom Converter List + +Apply multiple field converters by defining and registering a custom converter list: + strip_converter = proc {|field| field.strip } + CSV::Converters[:strip] = strip_converter + CSV::Converters[:my_converters] = [:integer, :float, :strip] + source = "Name,Value\n foo , 0 \n bar , 1.0 \n baz , 2.0 \n" + parsed = CSV.parse(source, headers: true, converters: :my_converters) + parsed['Name'] # => ["foo", "bar", "baz"] + parsed['Value'] # => [0, 1.0, 2.0] + +=== Converting Headers + +You can use header converters to modify parsed \String headers. + +Built-in header converters include: +- +:symbol+: converts \String header to \Symbol. +- +:downcase+: converts \String header to lowercase. + +You can also define header converters to otherwise modify header \Strings. + +==== Recipe: Convert Headers to Lowercase + +Convert headers to lowercase using built-in converter +:downcase+: + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, header_converters: :downcase) + parsed.headers # => ["name", "value"] + +==== Recipe: Convert Headers to Symbols + +Convert headers to downcased Symbols using built-in converter +:symbol+: + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, header_converters: :symbol) + parsed.headers # => [:name, :value] + parsed.headers.map {|header| header.class} # => [Symbol, Symbol] + +==== Recipe: Filter Header Strings + +Define a custom header converter to modify \String fields. +This example defines and uses a custom header converter +that capitalizes each header \String: + capitalize_converter = proc {|header| header.capitalize } + source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, header_converters: capitalize_converter) + parsed.headers # => ["Name", "Value"] + +==== Recipe: Register Header Converters + +Register a custom header converter, assigning it a name; +then refer to the converter by its name: + capitalize_converter = proc {|header| header.capitalize } + CSV::HeaderConverters[:capitalize] = capitalize_converter + source = "NAME,VALUE\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, headers: true, header_converters: :capitalize) + parsed.headers # => ["Name", "Value"] + +==== Using Multiple Header Converters + +You can use multiple header converters in either of these ways: +- Specify header converters in option +:header_converters+. +- Specify header converters in a custom header converter list. + +===== Recipe: Specify Multiple Header Converters in Option :header_converters + +Apply multiple header converters by specifying them in option +:header_converters+: + source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n" + parsed = CSV.parse(source, headers: true, header_converters: [:downcase, :symbol]) + parsed.headers # => [:name, :value] + +===== Recipe: Specify Multiple Header Converters in a Custom Header Converter List + +Apply multiple header converters by defining and registering a custom header converter list: + CSV::HeaderConverters[:my_header_converters] = [:symbol, :downcase] + source = "NAME,VALUE\nfoo,0\nbar,1.0\nbaz,2.0\n" + parsed = CSV.parse(source, headers: true, header_converters: :my_header_converters) + parsed.headers # => [:name, :value] + +=== Diagnostics + +==== Recipe: Capture Unconverted Fields + +To capture unconverted field values, use option +:unconverted_fields+: + source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + parsed = CSV.parse(source, converters: :integer, unconverted_fields: true) + parsed # => [["Name", "Value"], ["foo", 0], ["bar", 1], ["baz", 2]] + parsed.each {|row| p row.unconverted_fields } +Output: + ["Name", "Value"] + ["foo", "0"] + ["bar", "1"] + ["baz", "2"] + +==== Recipe: Capture Field Info + +To capture field info in a custom converter, accept two block arguments. +The first is the field value; the second is a +CSV::FieldInfo+ object: + strip_converter = proc {|field, field_info| p field_info; field.strip } + source = " foo , 0 \n bar , 1 \n baz , 2 \n" + parsed = CSV.parse(source, converters: strip_converter) + parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +Output: + # + # + # + # + # + # diff --git a/bin/gems/csv-3.3.2/doc/csv/recipes/recipes.rdoc b/bin/gems/csv-3.3.2/doc/csv/recipes/recipes.rdoc new file mode 100644 index 00000000..9bf7885b --- /dev/null +++ b/bin/gems/csv-3.3.2/doc/csv/recipes/recipes.rdoc @@ -0,0 +1,6 @@ +== Recipes for \CSV + +The recipes are specific code examples for specific tasks. See: +- {Recipes for Parsing CSV}[./parsing_rdoc.html] +- {Recipes for Generating CSV}[./generating_rdoc.html] +- {Recipes for Filtering CSV}[./filtering_rdoc.html] diff --git a/bin/gems/csv-3.3.2/lib/csv.rb b/bin/gems/csv-3.3.2/lib/csv.rb new file mode 100644 index 00000000..cfe42911 --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv.rb @@ -0,0 +1,3017 @@ +# encoding: US-ASCII +# frozen_string_literal: true +# = csv.rb -- CSV Reading and Writing +# +# Created by James Edward Gray II on 2005-10-31. +# +# See CSV for documentation. +# +# == Description +# +# Welcome to the new and improved CSV. +# +# This version of the CSV library began its life as FasterCSV. FasterCSV was +# intended as a replacement to Ruby's then standard CSV library. It was +# designed to address concerns users of that library had and it had three +# primary goals: +# +# 1. Be significantly faster than CSV while remaining a pure Ruby library. +# 2. Use a smaller and easier to maintain code base. (FasterCSV eventually +# grew larger, was also but considerably richer in features. The parsing +# core remains quite small.) +# 3. Improve on the CSV interface. +# +# Obviously, the last one is subjective. I did try to defer to the original +# interface whenever I didn't have a compelling reason to change it though, so +# hopefully this won't be too radically different. +# +# We must have met our goals because FasterCSV was renamed to CSV and replaced +# the original library as of Ruby 1.9. If you are migrating code from 1.8 or +# earlier, you may have to change your code to comply with the new interface. +# +# == What's the Different From the Old CSV? +# +# I'm sure I'll miss something, but I'll try to mention most of the major +# differences I am aware of, to help others quickly get up to speed: +# +# === \CSV Parsing +# +# * This parser is m17n aware. See CSV for full details. +# * This library has a stricter parser and will throw MalformedCSVErrors on +# problematic data. +# * This library has a less liberal idea of a line ending than CSV. What you +# set as the :row_sep is law. It can auto-detect your line endings +# though. +# * The old library returned empty lines as [nil]. This library calls +# them []. +# * This library has a much faster parser. +# +# === Interface +# +# * CSV now uses keyword parameters to set options. +# * CSV no longer has generate_row() or parse_row(). +# * The old CSV's Reader and Writer classes have been dropped. +# * CSV::open() is now more like Ruby's open(). +# * CSV objects now support most standard IO methods. +# * CSV now has a new() method used to wrap objects like String and IO for +# reading and writing. +# * CSV::generate() is different from the old method. +# * CSV no longer supports partial reads. It works line-by-line. +# * CSV no longer allows the instance methods to override the separators for +# performance reasons. They must be set in the constructor. +# +# If you use this library and find yourself missing any functionality I have +# trimmed, please {let me know}[mailto:james@grayproductions.net]. +# +# == Documentation +# +# See CSV for documentation. +# +# == What is CSV, really? +# +# CSV maintains a pretty strict definition of CSV taken directly from +# {the RFC}[https://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one +# place and that is to make using this library easier. CSV will parse all valid +# CSV. +# +# What you don't want to do is to feed CSV invalid data. Because of the way the +# CSV format works, it's common for a parser to need to read until the end of +# the file to be sure a field is invalid. This consumes a lot of time and memory. +# +# Luckily, when working with invalid CSV, Ruby's built-in methods will almost +# always be superior in every way. For example, parsing non-quoted fields is as +# easy as: +# +# data.split(",") +# +# == Questions and/or Comments +# +# Feel free to email {James Edward Gray II}[mailto:james@grayproductions.net] +# with any questions. + +require "forwardable" +require "date" +require "time" +require "stringio" + +require_relative "csv/fields_converter" +require_relative "csv/input_record_separator" +require_relative "csv/parser" +require_relative "csv/row" +require_relative "csv/table" +require_relative "csv/writer" + +# == \CSV +# +# === \CSV Data +# +# \CSV (comma-separated values) data is a text representation of a table: +# - A _row_ _separator_ delimits table rows. +# A common row separator is the newline character "\n". +# - A _column_ _separator_ delimits fields in a row. +# A common column separator is the comma character ",". +# +# This \CSV \String, with row separator "\n" +# and column separator ",", +# has three rows and two columns: +# "foo,0\nbar,1\nbaz,2\n" +# +# Despite the name \CSV, a \CSV representation can use different separators. +# +# For more about tables, see the Wikipedia article +# "{Table (information)}[https://en.wikipedia.org/wiki/Table_(information)]", +# especially its section +# "{Simple table}[https://en.wikipedia.org/wiki/Table_(information)#Simple_table]" +# +# == \Class \CSV +# +# Class \CSV provides methods for: +# - Parsing \CSV data from a \String object, a \File (via its file path), or an \IO object. +# - Generating \CSV data to a \String object. +# +# To make \CSV available: +# require 'csv' +# +# All examples here assume that this has been done. +# +# == Keeping It Simple +# +# A \CSV object has dozens of instance methods that offer fine-grained control +# of parsing and generating \CSV data. +# For many needs, though, simpler approaches will do. +# +# This section summarizes the singleton methods in \CSV +# that allow you to parse and generate without explicitly +# creating \CSV objects. +# For details, follow the links. +# +# === Simple Parsing +# +# Parsing methods commonly return either of: +# - An \Array of Arrays of Strings: +# - The outer \Array is the entire "table". +# - Each inner \Array is a row. +# - Each \String is a field. +# - A CSV::Table object. For details, see +# {\CSV with Headers}[#class-CSV-label-CSV+with+Headers]. +# +# ==== Parsing a \String +# +# The input to be parsed can be a string: +# string = "foo,0\nbar,1\nbaz,2\n" +# +# \Method CSV.parse returns the entire \CSV data: +# CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# \Method CSV.parse_line returns only the first row: +# CSV.parse_line(string) # => ["foo", "0"] +# +# \CSV extends class \String with instance method String#parse_csv, +# which also returns only the first row: +# string.parse_csv # => ["foo", "0"] +# +# ==== Parsing Via a \File Path +# +# The input to be parsed can be in a file: +# string = "foo,0\nbar,1\nbaz,2\n" +# path = 't.csv' +# File.write(path, string) +# +# \Method CSV.read returns the entire \CSV data: +# CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# \Method CSV.foreach iterates, passing each row to the given block: +# CSV.foreach(path) do |row| +# p row +# end +# Output: +# ["foo", "0"] +# ["bar", "1"] +# ["baz", "2"] +# +# \Method CSV.table returns the entire \CSV data as a CSV::Table object: +# CSV.table(path) # => # +# +# ==== Parsing from an Open \IO Stream +# +# The input to be parsed can be in an open \IO stream: +# +# \Method CSV.read returns the entire \CSV data: +# File.open(path) do |file| +# CSV.read(file) +# end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# As does method CSV.parse: +# File.open(path) do |file| +# CSV.parse(file) +# end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# \Method CSV.parse_line returns only the first row: +# File.open(path) do |file| +# CSV.parse_line(file) +# end # => ["foo", "0"] +# +# \Method CSV.foreach iterates, passing each row to the given block: +# File.open(path) do |file| +# CSV.foreach(file) do |row| +# p row +# end +# end +# Output: +# ["foo", "0"] +# ["bar", "1"] +# ["baz", "2"] +# +# \Method CSV.table returns the entire \CSV data as a CSV::Table object: +# File.open(path) do |file| +# CSV.table(file) +# end # => # +# +# === Simple Generating +# +# \Method CSV.generate returns a \String; +# this example uses method CSV#<< to append the rows +# that are to be generated: +# output_string = CSV.generate do |csv| +# csv << ['foo', 0] +# csv << ['bar', 1] +# csv << ['baz', 2] +# end +# output_string # => "foo,0\nbar,1\nbaz,2\n" +# +# \Method CSV.generate_line returns a \String containing the single row +# constructed from an \Array: +# CSV.generate_line(['foo', '0']) # => "foo,0\n" +# +# \CSV extends class \Array with instance method Array#to_csv, +# which forms an \Array into a \String: +# ['foo', '0'].to_csv # => "foo,0\n" +# +# === "Filtering" \CSV +# +# \Method CSV.filter provides a Unix-style filter for \CSV data. +# The input data is processed to form the output data: +# in_string = "foo,0\nbar,1\nbaz,2\n" +# out_string = '' +# CSV.filter(in_string, out_string) do |row| +# row[0] = row[0].upcase +# row[1] *= 4 +# end +# out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n" +# +# == \CSV Objects +# +# There are three ways to create a \CSV object: +# - \Method CSV.new returns a new \CSV object. +# - \Method CSV.instance returns a new or cached \CSV object. +# - \Method \CSV() also returns a new or cached \CSV object. +# +# === Instance Methods +# +# \CSV has three groups of instance methods: +# - Its own internally defined instance methods. +# - Methods included by module Enumerable. +# - Methods delegated to class IO. See below. +# +# ==== Delegated Methods +# +# For convenience, a CSV object will delegate to many methods in class IO. +# (A few have wrapper "guard code" in \CSV.) You may call: +# * IO#binmode +# * #binmode? +# * IO#close +# * IO#close_read +# * IO#close_write +# * IO#closed? +# * #eof +# * #eof? +# * IO#external_encoding +# * IO#fcntl +# * IO#fileno +# * #flock +# * IO#flush +# * IO#fsync +# * IO#internal_encoding +# * #ioctl +# * IO#isatty +# * #path +# * IO#pid +# * IO#pos +# * IO#pos= +# * IO#reopen +# * #rewind +# * IO#seek +# * #stat +# * IO#string +# * IO#sync +# * IO#sync= +# * IO#tell +# * #to_i +# * #to_io +# * IO#truncate +# * IO#tty? +# +# === Options +# +# The default values for options are: +# DEFAULT_OPTIONS = { +# # For both parsing and generating. +# col_sep: ",", +# row_sep: :auto, +# quote_char: '"', +# # For parsing. +# field_size_limit: nil, +# converters: nil, +# unconverted_fields: nil, +# headers: false, +# return_headers: false, +# header_converters: nil, +# skip_blanks: false, +# skip_lines: nil, +# liberal_parsing: false, +# nil_value: nil, +# empty_value: "", +# strip: false, +# # For generating. +# write_headers: nil, +# quote_empty: true, +# force_quotes: false, +# write_converters: nil, +# write_nil_value: nil, +# write_empty_value: "", +# } +# +# ==== Options for Parsing +# +# Options for parsing, described in detail below, include: +# - +row_sep+: Specifies the row separator; used to delimit rows. +# - +col_sep+: Specifies the column separator; used to delimit fields. +# - +quote_char+: Specifies the quote character; used to quote fields. +# - +field_size_limit+: Specifies the maximum field size + 1 allowed. +# Deprecated since 3.2.3. Use +max_field_size+ instead. +# - +max_field_size+: Specifies the maximum field size allowed. +# - +converters+: Specifies the field converters to be used. +# - +unconverted_fields+: Specifies whether unconverted fields are to be available. +# - +headers+: Specifies whether data contains headers, +# or specifies the headers themselves. +# - +return_headers+: Specifies whether headers are to be returned. +# - +header_converters+: Specifies the header converters to be used. +# - +skip_blanks+: Specifies whether blanks lines are to be ignored. +# - +skip_lines+: Specifies how comments lines are to be recognized. +# - +strip+: Specifies whether leading and trailing whitespace are to be +# stripped from fields. This must be compatible with +col_sep+; if it is not, +# then an +ArgumentError+ exception will be raised. +# - +liberal_parsing+: Specifies whether \CSV should attempt to parse +# non-compliant data. +# - +nil_value+: Specifies the object that is to be substituted for each null (no-text) field. +# - +empty_value+: Specifies the object that is to be substituted for each empty field. +# +# :include: ../doc/csv/options/common/row_sep.rdoc +# +# :include: ../doc/csv/options/common/col_sep.rdoc +# +# :include: ../doc/csv/options/common/quote_char.rdoc +# +# :include: ../doc/csv/options/parsing/field_size_limit.rdoc +# +# :include: ../doc/csv/options/parsing/converters.rdoc +# +# :include: ../doc/csv/options/parsing/unconverted_fields.rdoc +# +# :include: ../doc/csv/options/parsing/headers.rdoc +# +# :include: ../doc/csv/options/parsing/return_headers.rdoc +# +# :include: ../doc/csv/options/parsing/header_converters.rdoc +# +# :include: ../doc/csv/options/parsing/skip_blanks.rdoc +# +# :include: ../doc/csv/options/parsing/skip_lines.rdoc +# +# :include: ../doc/csv/options/parsing/strip.rdoc +# +# :include: ../doc/csv/options/parsing/liberal_parsing.rdoc +# +# :include: ../doc/csv/options/parsing/nil_value.rdoc +# +# :include: ../doc/csv/options/parsing/empty_value.rdoc +# +# ==== Options for Generating +# +# Options for generating, described in detail below, include: +# - +row_sep+: Specifies the row separator; used to delimit rows. +# - +col_sep+: Specifies the column separator; used to delimit fields. +# - +quote_char+: Specifies the quote character; used to quote fields. +# - +write_headers+: Specifies whether headers are to be written. +# - +force_quotes+: Specifies whether each output field is to be quoted. +# - +quote_empty+: Specifies whether each empty output field is to be quoted. +# - +write_converters+: Specifies the field converters to be used in writing. +# - +write_nil_value+: Specifies the object that is to be substituted for each +nil+-valued field. +# - +write_empty_value+: Specifies the object that is to be substituted for each empty field. +# +# :include: ../doc/csv/options/common/row_sep.rdoc +# +# :include: ../doc/csv/options/common/col_sep.rdoc +# +# :include: ../doc/csv/options/common/quote_char.rdoc +# +# :include: ../doc/csv/options/generating/write_headers.rdoc +# +# :include: ../doc/csv/options/generating/force_quotes.rdoc +# +# :include: ../doc/csv/options/generating/quote_empty.rdoc +# +# :include: ../doc/csv/options/generating/write_converters.rdoc +# +# :include: ../doc/csv/options/generating/write_nil_value.rdoc +# +# :include: ../doc/csv/options/generating/write_empty_value.rdoc +# +# === \CSV with Headers +# +# CSV allows to specify column names of CSV file, whether they are in data, or +# provided separately. If headers are specified, reading methods return an instance +# of CSV::Table, consisting of CSV::Row. +# +# # Headers are part of data +# data = CSV.parse(<<~ROWS, headers: true) +# Name,Department,Salary +# Bob,Engineering,1000 +# Jane,Sales,2000 +# John,Management,5000 +# ROWS +# +# data.class #=> CSV::Table +# data.first #=> # +# data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"} +# +# # Headers provided by developer +# data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary]) +# data.first #=> # +# +# === \Converters +# +# By default, each value (field or header) parsed by \CSV is formed into a \String. +# You can use a _field_ _converter_ or _header_ _converter_ +# to intercept and modify the parsed values: +# - See {Field Converters}[#class-CSV-label-Field+Converters]. +# - See {Header Converters}[#class-CSV-label-Header+Converters]. +# +# Also by default, each value to be written during generation is written 'as-is'. +# You can use a _write_ _converter_ to modify values before writing. +# - See {Write Converters}[#class-CSV-label-Write+Converters]. +# +# ==== Specifying \Converters +# +# You can specify converters for parsing or generating in the +options+ +# argument to various \CSV methods: +# - Option +converters+ for converting parsed field values. +# - Option +header_converters+ for converting parsed header values. +# - Option +write_converters+ for converting values to be written (generated). +# +# There are three forms for specifying converters: +# - A converter proc: executable code to be used for conversion. +# - A converter name: the name of a stored converter. +# - A converter list: an array of converter procs, converter names, and converter lists. +# +# ===== Converter Procs +# +# This converter proc, +strip_converter+, accepts a value +field+ +# and returns field.strip: +# strip_converter = proc {|field| field.strip } +# In this call to CSV.parse, +# the keyword argument converters: string_converter +# specifies that: +# - \Proc +string_converter+ is to be called for each parsed field. +# - The converter's return value is to replace the +field+ value. +# Example: +# string = " foo , 0 \n bar , 1 \n baz , 2 \n" +# array = CSV.parse(string, converters: strip_converter) +# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# A converter proc can receive a second argument, +field_info+, +# that contains details about the field. +# This modified +strip_converter+ displays its arguments: +# strip_converter = proc do |field, field_info| +# p [field, field_info] +# field.strip +# end +# string = " foo , 0 \n bar , 1 \n baz , 2 \n" +# array = CSV.parse(string, converters: strip_converter) +# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# Output: +# [" foo ", #] +# [" 0 ", #] +# [" bar ", #] +# [" 1 ", #] +# [" baz ", #] +# [" 2 ", #] +# Each CSV::FieldInfo object shows: +# - The 0-based field index. +# - The 1-based line index. +# - The field header, if any. +# +# ===== Stored \Converters +# +# A converter may be given a name and stored in a structure where +# the parsing methods can find it by name. +# +# The storage structure for field converters is the \Hash CSV::Converters. +# It has several built-in converter procs: +# - :integer: converts each \String-embedded integer into a true \Integer. +# - :float: converts each \String-embedded float into a true \Float. +# - :date: converts each \String-embedded date into a true \Date. +# - :date_time: converts each \String-embedded date-time into a true \DateTime +# - :time: converts each \String-embedded time into a true \Time +# . +# This example creates a converter proc, then stores it: +# strip_converter = proc {|field| field.strip } +# CSV::Converters[:strip] = strip_converter +# Then the parsing method call can refer to the converter +# by its name, :strip: +# string = " foo , 0 \n bar , 1 \n baz , 2 \n" +# array = CSV.parse(string, converters: :strip) +# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# The storage structure for header converters is the \Hash CSV::HeaderConverters, +# which works in the same way. +# It also has built-in converter procs: +# - :downcase: Downcases each header. +# - :symbol: Converts each header to a \Symbol. +# +# There is no such storage structure for write headers. +# +# In order for the parsing methods to access stored converters in non-main-Ractors, the +# storage structure must be made shareable first. +# Therefore, Ractor.make_shareable(CSV::Converters) and +# Ractor.make_shareable(CSV::HeaderConverters) must be called before the creation +# of Ractors that use the converters stored in these structures. (Since making the storage +# structures shareable involves freezing them, any custom converters that are to be used +# must be added first.) +# +# ===== Converter Lists +# +# A _converter_ _list_ is an \Array that may include any assortment of: +# - Converter procs. +# - Names of stored converters. +# - Nested converter lists. +# +# Examples: +# numeric_converters = [:integer, :float] +# date_converters = [:date, :date_time] +# [numeric_converters, strip_converter] +# [strip_converter, date_converters, :float] +# +# Like a converter proc, a converter list may be named and stored in either +# \CSV::Converters or CSV::HeaderConverters: +# CSV::Converters[:custom] = [strip_converter, date_converters, :float] +# CSV::HeaderConverters[:custom] = [:downcase, :symbol] +# +# There are two built-in converter lists: +# CSV::Converters[:numeric] # => [:integer, :float] +# CSV::Converters[:all] # => [:date_time, :numeric] +# +# ==== Field \Converters +# +# With no conversion, all parsed fields in all rows become Strings: +# string = "foo,0\nbar,1\nbaz,2\n" +# ary = CSV.parse(string) +# ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# When you specify a field converter, each parsed field is passed to the converter; +# its return value becomes the stored value for the field. +# A converter might, for example, convert an integer embedded in a \String +# into a true \Integer. +# (In fact, that's what built-in field converter +:integer+ does.) +# +# There are three ways to use field \converters. +# +# - Using option {converters}[#class-CSV-label-Option+converters] with a parsing method: +# ary = CSV.parse(string, converters: :integer) +# ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]] +# - Using option {converters}[#class-CSV-label-Option+converters] with a new \CSV instance: +# csv = CSV.new(string, converters: :integer) +# # Field converters in effect: +# csv.converters # => [:integer] +# csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]] +# - Using method #convert to add a field converter to a \CSV instance: +# csv = CSV.new(string) +# # Add a converter. +# csv.convert(:integer) +# csv.converters # => [:integer] +# csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]] +# +# Installing a field converter does not affect already-read rows: +# csv = CSV.new(string) +# csv.shift # => ["foo", "0"] +# # Add a converter. +# csv.convert(:integer) +# csv.converters # => [:integer] +# csv.read # => [["bar", 1], ["baz", 2]] +# +# There are additional built-in \converters, and custom \converters are also supported. +# +# ===== Built-In Field \Converters +# +# The built-in field converters are in \Hash CSV::Converters: +# - Each key is a field converter name. +# - Each value is one of: +# - A \Proc field converter. +# - An \Array of field converter names. +# +# Display: +# CSV::Converters.each_pair do |name, value| +# if value.kind_of?(Proc) +# p [name, value.class] +# else +# p [name, value] +# end +# end +# Output: +# [:integer, Proc] +# [:float, Proc] +# [:numeric, [:integer, :float]] +# [:date, Proc] +# [:date_time, Proc] +# [:time, Proc] +# [:all, [:date_time, :numeric]] +# +# Each of these converters transcodes values to UTF-8 before attempting conversion. +# If a value cannot be transcoded to UTF-8 the conversion will +# fail and the value will remain unconverted. +# +# Converter +:integer+ converts each field that Integer() accepts: +# data = '0,1,2,x' +# # Without the converter +# csv = CSV.parse_line(data) +# csv # => ["0", "1", "2", "x"] +# # With the converter +# csv = CSV.parse_line(data, converters: :integer) +# csv # => [0, 1, 2, "x"] +# +# Converter +:float+ converts each field that Float() accepts: +# data = '1.0,3.14159,x' +# # Without the converter +# csv = CSV.parse_line(data) +# csv # => ["1.0", "3.14159", "x"] +# # With the converter +# csv = CSV.parse_line(data, converters: :float) +# csv # => [1.0, 3.14159, "x"] +# +# Converter +:numeric+ converts with both +:integer+ and +:float+.. +# +# Converter +:date+ converts each field that Date::parse accepts: +# data = '2001-02-03,x' +# # Without the converter +# csv = CSV.parse_line(data) +# csv # => ["2001-02-03", "x"] +# # With the converter +# csv = CSV.parse_line(data, converters: :date) +# csv # => [#, "x"] +# +# Converter +:date_time+ converts each field that DateTime::parse accepts: +# data = '2020-05-07T14:59:00-05:00,x' +# # Without the converter +# csv = CSV.parse_line(data) +# csv # => ["2020-05-07T14:59:00-05:00", "x"] +# # With the converter +# csv = CSV.parse_line(data, converters: :date_time) +# csv # => [#, "x"] +# +# Converter +time+ converts each field that Time::parse accepts: +# data = '2020-05-07T14:59:00-05:00,x' +# # Without the converter +# csv = CSV.parse_line(data) +# csv # => ["2020-05-07T14:59:00-05:00", "x"] +# # With the converter +# csv = CSV.parse_line(data, converters: :time) +# csv # => [2020-05-07 14:59:00 -0500, "x"] +# +# Converter +:numeric+ converts with both +:date_time+ and +:numeric+.. +# +# As seen above, method #convert adds \converters to a \CSV instance, +# and method #converters returns an \Array of the \converters in effect: +# csv = CSV.new('0,1,2') +# csv.converters # => [] +# csv.convert(:integer) +# csv.converters # => [:integer] +# csv.convert(:date) +# csv.converters # => [:integer, :date] +# +# ===== Custom Field \Converters +# +# You can define a custom field converter: +# strip_converter = proc {|field| field.strip } +# string = " foo , 0 \n bar , 1 \n baz , 2 \n" +# array = CSV.parse(string, converters: strip_converter) +# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# You can register the converter in \Converters \Hash, +# which allows you to refer to it by name: +# CSV::Converters[:strip] = strip_converter +# string = " foo , 0 \n bar , 1 \n baz , 2 \n" +# array = CSV.parse(string, converters: :strip) +# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] +# +# ==== Header \Converters +# +# Header converters operate only on headers (and not on other rows). +# +# There are three ways to use header \converters; +# these examples use built-in header converter +:downcase+, +# which downcases each parsed header. +# +# - Option +header_converters+ with a singleton parsing method: +# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" +# tbl = CSV.parse(string, headers: true, header_converters: :downcase) +# tbl.class # => CSV::Table +# tbl.headers # => ["name", "count"] +# +# - Option +header_converters+ with a new \CSV instance: +# csv = CSV.new(string, header_converters: :downcase) +# # Header converters in effect: +# csv.header_converters # => [:downcase] +# tbl = CSV.parse(string, headers: true) +# tbl.headers # => ["Name", "Count"] +# +# - Method #header_convert adds a header converter to a \CSV instance: +# csv = CSV.new(string) +# # Add a header converter. +# csv.header_convert(:downcase) +# csv.header_converters # => [:downcase] +# tbl = CSV.parse(string, headers: true) +# tbl.headers # => ["Name", "Count"] +# +# ===== Built-In Header \Converters +# +# The built-in header \converters are in \Hash CSV::HeaderConverters. +# The keys there are the names of the \converters: +# CSV::HeaderConverters.keys # => [:downcase, :symbol] +# +# Converter +:downcase+ converts each header by downcasing it: +# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" +# tbl = CSV.parse(string, headers: true, header_converters: :downcase) +# tbl.class # => CSV::Table +# tbl.headers # => ["name", "count"] +# +# Converter +:symbol+ converts each header by making it into a \Symbol: +# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2" +# tbl = CSV.parse(string, headers: true, header_converters: :symbol) +# tbl.headers # => [:name, :count] +# Details: +# - Strips leading and trailing whitespace. +# - Downcases the header. +# - Replaces embedded spaces with underscores. +# - Removes non-word characters. +# - Makes the string into a \Symbol. +# +# ===== Custom Header \Converters +# +# You can define a custom header converter: +# upcase_converter = proc {|header| header.upcase } +# string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" +# table = CSV.parse(string, headers: true, header_converters: upcase_converter) +# table # => # +# table.headers # => ["NAME", "VALUE"] +# You can register the converter in \HeaderConverters \Hash, +# which allows you to refer to it by name: +# CSV::HeaderConverters[:upcase] = upcase_converter +# table = CSV.parse(string, headers: true, header_converters: :upcase) +# table # => # +# table.headers # => ["NAME", "VALUE"] +# +# ===== Write \Converters +# +# When you specify a write converter for generating \CSV, +# each field to be written is passed to the converter; +# its return value becomes the new value for the field. +# A converter might, for example, strip whitespace from a field. +# +# Using no write converter (all fields unmodified): +# output_string = CSV.generate do |csv| +# csv << [' foo ', 0] +# csv << [' bar ', 1] +# csv << [' baz ', 2] +# end +# output_string # => " foo ,0\n bar ,1\n baz ,2\n" +# Using option +write_converters+ with two custom write converters: +# strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field } +# upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field } +# write_converters = [strip_converter, upcase_converter] +# output_string = CSV.generate(write_converters: write_converters) do |csv| +# csv << [' foo ', 0] +# csv << [' bar ', 1] +# csv << [' baz ', 2] +# end +# output_string # => "FOO,0\nBAR,1\nBAZ,2\n" +# +# === Character Encodings (M17n or Multilingualization) +# +# This new CSV parser is m17n savvy. The parser works in the Encoding of the IO +# or String object being read from or written to. Your data is never transcoded +# (unless you ask Ruby to transcode it for you) and will literally be parsed in +# the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the +# Encoding of your data. This is accomplished by transcoding the parser itself +# into your Encoding. +# +# Some transcoding must take place, of course, to accomplish this multiencoding +# support. For example, :col_sep, :row_sep, and +# :quote_char must be transcoded to match your data. Hopefully this +# makes the entire process feel transparent, since CSV's defaults should just +# magically work for your data. However, you can set these values manually in +# the target Encoding to avoid the translation. +# +# It's also important to note that while all of CSV's core parser is now +# Encoding agnostic, some features are not. For example, the built-in +# converters will try to transcode data to UTF-8 before making conversions. +# Again, you can provide custom converters that are aware of your Encodings to +# avoid this translation. It's just too hard for me to support native +# conversions in all of Ruby's Encodings. +# +# Anyway, the practical side of this is simple: make sure IO and String objects +# passed into CSV have the proper Encoding set and everything should just work. +# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(), +# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding. +# +# One minor exception comes when generating CSV into a String with an Encoding +# that is not ASCII compatible. There's no existing data for CSV to use to +# prepare itself and thus you will probably need to manually specify the desired +# Encoding for most of those cases. It will try to guess using the fields in a +# row of output though, when using CSV::generate_line() or Array#to_csv(). +# +# I try to point out any other Encoding issues in the documentation of methods +# as they come up. +# +# This has been tested to the best of my ability with all non-"dummy" Encodings +# Ruby ships with. However, it is brave new code and may have some bugs. +# Please feel free to {report}[mailto:james@grayproductions.net] any issues you +# find with it. +# +class CSV + + # The error thrown when the parser encounters illegal CSV formatting. + class MalformedCSVError < RuntimeError + attr_reader :line_number + alias_method :lineno, :line_number + def initialize(message, line_number) + @line_number = line_number + super("#{message} in line #{line_number}.") + end + end + + # The error thrown when the parser encounters invalid encoding in CSV. + class InvalidEncodingError < MalformedCSVError + attr_reader :encoding + def initialize(encoding, line_number) + @encoding = encoding + super("Invalid byte sequence in #{encoding}", line_number) + end + end + + # + # A FieldInfo Struct contains details about a field's position in the data + # source it was read from. CSV will pass this Struct to some blocks that make + # decisions based on field structure. See CSV.convert_fields() for an + # example. + # + # index:: The zero-based index of the field in its row. + # line:: The line of the data source this row is from. + # header:: The header for the column, when available. + # quoted?:: True or false, whether the original value is quoted or not. + # + FieldInfo = Struct.new(:index, :line, :header, :quoted?) + + # A Regexp used to find and convert some common Date formats. + DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} | + \d{4}-\d{2}-\d{2} )\z /x + # A Regexp used to find and convert some common (Date)Time formats. + DateTimeMatcher = + / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} | + # ISO-8601 and RFC-3339 (space instead of T) recognized by (Date)Time.parse + \d{4}-\d{2}-\d{2} + (?:[T\s]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?(?:[+-]\d{2}(?::\d{2})|Z)?)?)? + )\z /x + + # The encoding used by all converters. + ConverterEncoding = Encoding.find("UTF-8") + + # A \Hash containing the names and \Procs for the built-in field converters. + # See {Built-In Field Converters}[#class-CSV-label-Built-In+Field+Converters]. + # + # This \Hash is intentionally left unfrozen, and may be extended with + # custom field converters. + # See {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]. + Converters = { + integer: lambda { |f| + Integer(f.encode(ConverterEncoding)) rescue f + }, + float: lambda { |f| + Float(f.encode(ConverterEncoding)) rescue f + }, + numeric: [:integer, :float], + date: lambda { |f| + begin + e = f.encode(ConverterEncoding) + e.match?(DateMatcher) ? Date.parse(e) : f + rescue # encoding conversion or date parse errors + f + end + }, + date_time: lambda { |f| + begin + e = f.encode(ConverterEncoding) + e.match?(DateTimeMatcher) ? DateTime.parse(e) : f + rescue # encoding conversion or date parse errors + f + end + }, + time: lambda { |f| + begin + e = f.encode(ConverterEncoding) + e.match?(DateTimeMatcher) ? Time.parse(e) : f + rescue # encoding conversion or parse errors + f + end + }, + all: [:date_time, :numeric], + } + + # A \Hash containing the names and \Procs for the built-in header converters. + # See {Built-In Header Converters}[#class-CSV-label-Built-In+Header+Converters]. + # + # This \Hash is intentionally left unfrozen, and may be extended with + # custom field converters. + # See {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]. + HeaderConverters = { + downcase: lambda { |h| h.encode(ConverterEncoding).downcase }, + symbol: lambda { |h| + h.encode(ConverterEncoding).downcase.gsub(/[^\s\w]+/, "").strip. + gsub(/\s+/, "_").to_sym + }, + symbol_raw: lambda { |h| h.encode(ConverterEncoding).to_sym } + } + + # Default values for method options. + DEFAULT_OPTIONS = { + # For both parsing and generating. + col_sep: ",", + row_sep: :auto, + quote_char: '"', + # For parsing. + field_size_limit: nil, + max_field_size: nil, + converters: nil, + unconverted_fields: nil, + headers: false, + return_headers: false, + header_converters: nil, + skip_blanks: false, + skip_lines: nil, + liberal_parsing: false, + nil_value: nil, + empty_value: "", + strip: false, + # For generating. + write_headers: nil, + quote_empty: true, + force_quotes: false, + write_converters: nil, + write_nil_value: nil, + write_empty_value: "", + }.freeze + + class << self + # :call-seq: + # instance(string, **options) + # instance(io = $stdout, **options) + # instance(string, **options) {|csv| ... } + # instance(io = $stdout, **options) {|csv| ... } + # + # Creates or retrieves cached \CSV objects. + # For arguments and options, see CSV.new. + # + # This API is not Ractor-safe. + # + # --- + # + # With no block given, returns a \CSV object. + # + # The first call to +instance+ creates and caches a \CSV object: + # s0 = 's0' + # csv0 = CSV.instance(s0) + # csv0.class # => CSV + # + # Subsequent calls to +instance+ with that _same_ +string+ or +io+ + # retrieve that same cached object: + # csv1 = CSV.instance(s0) + # csv1.class # => CSV + # csv1.equal?(csv0) # => true # Same CSV object + # + # A subsequent call to +instance+ with a _different_ +string+ or +io+ + # creates and caches a _different_ \CSV object. + # s1 = 's1' + # csv2 = CSV.instance(s1) + # csv2.equal?(csv0) # => false # Different CSV object + # + # All the cached objects remains available: + # csv3 = CSV.instance(s0) + # csv3.equal?(csv0) # true # Same CSV object + # csv4 = CSV.instance(s1) + # csv4.equal?(csv2) # true # Same CSV object + # + # --- + # + # When a block is given, calls the block with the created or retrieved + # \CSV object; returns the block's return value: + # CSV.instance(s0) {|csv| :foo } # => :foo + def instance(data = $stdout, **options) + # create a _signature_ for this method call, data object and options + sig = [data.object_id] + + options.values_at(*DEFAULT_OPTIONS.keys) + + # fetch or create the instance for this signature + @@instances ||= Hash.new + instance = (@@instances[sig] ||= new(data, **options)) + + if block_given? + yield instance # run block, if given, returning result + else + instance # or return the instance + end + end + + # :call-seq: + # filter(in_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table + # filter(in_string_or_io, out_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table + # filter(**options) {|row| ... } -> array_of_arrays or csv_table + # + # - Parses \CSV from a source (\String, \IO stream, or ARGF). + # - Calls the given block with each parsed row: + # - Without headers, each row is an \Array. + # - With headers, each row is a CSV::Row. + # - Generates \CSV to an output (\String, \IO stream, or STDOUT). + # - Returns the parsed source: + # - Without headers, an \Array of \Arrays. + # - With headers, a CSV::Table. + # + # When +in_string_or_io+ is given, but not +out_string_or_io+, + # parses from the given +in_string_or_io+ + # and generates to STDOUT. + # + # \String input without headers: + # + # in_string = "foo,0\nbar,1\nbaz,2" + # CSV.filter(in_string) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]] + # + # Output (to STDOUT): + # + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # \String input with headers: + # + # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2" + # CSV.filter(in_string, headers: true) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end # => # + # + # Output (to STDOUT): + # + # Name,Value + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # \IO stream input without headers: + # + # File.write('t.csv', "foo,0\nbar,1\nbaz,2") + # File.open('t.csv') do |in_io| + # CSV.filter(in_io) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]] + # + # Output (to STDOUT): + # + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # \IO stream input with headers: + # + # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2") + # File.open('t.csv') do |in_io| + # CSV.filter(in_io, headers: true) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # end # => # + # + # Output (to STDOUT): + # + # Name,Value + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # When both +in_string_or_io+ and +out_string_or_io+ are given, + # parses from +in_string_or_io+ and generates to +out_string_or_io+. + # + # \String output without headers: + # + # in_string = "foo,0\nbar,1\nbaz,2" + # out_string = '' + # CSV.filter(in_string, out_string) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]] + # out_string # => "FOO,0\nBAR,-1\nBAZ,-2\n" + # + # \String output with headers: + # + # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2" + # out_string = '' + # CSV.filter(in_string, out_string, headers: true) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end # => # + # out_string # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n" + # + # \IO stream output without headers: + # + # in_string = "foo,0\nbar,1\nbaz,2" + # File.open('t.csv', 'w') do |out_io| + # CSV.filter(in_string, out_io) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]] + # File.read('t.csv') # => "FOO,0\nBAR,-1\nBAZ,-2\n" + # + # \IO stream output with headers: + # + # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2" + # File.open('t.csv', 'w') do |out_io| + # CSV.filter(in_string, out_io, headers: true) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # end # => # + # File.read('t.csv') # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n" + # + # When neither +in_string_or_io+ nor +out_string_or_io+ given, + # parses from {ARGF}[rdoc-ref:ARGF] + # and generates to STDOUT. + # + # Without headers: + # + # # Put Ruby code into a file. + # ruby = <<-EOT + # require 'csv' + # CSV.filter do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # EOT + # File.write('t.rb', ruby) + # # Put some CSV into a file. + # File.write('t.csv', "foo,0\nbar,1\nbaz,2") + # # Run the Ruby code with CSV filename as argument. + # system(Gem.ruby, "t.rb", "t.csv") + # + # Output (to STDOUT): + # + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # With headers: + # + # # Put Ruby code into a file. + # ruby = <<-EOT + # require 'csv' + # CSV.filter(headers: true) do |row| + # row[0].upcase! + # row[1] = - row[1].to_i + # end + # EOT + # File.write('t.rb', ruby) + # # Put some CSV into a file. + # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2") + # # Run the Ruby code with CSV filename as argument. + # system(Gem.ruby, "t.rb", "t.csv") + # + # Output (to STDOUT): + # + # Name,Value + # FOO,0 + # BAR,-1 + # BAZ,-2 + # + # Arguments: + # + # * Argument +in_string_or_io+ must be a \String or an \IO stream. + # * Argument +out_string_or_io+ must be a \String or an \IO stream. + # * Arguments **options must be keyword options. + # + # - Each option defined as an {option for parsing}[#class-CSV-label-Options+for+Parsing] + # is used for parsing the filter input. + # - Each option defined as an {option for generating}[#class-CSV-label-Options+for+Generating] + # is used for generator the filter input. + # + # However, there are three options that may be used for both parsing and generating: + # +col_sep+, +quote_char+, and +row_sep+. + # + # Therefore for method +filter+ (and method +filter+ only), + # there are special options that allow these parsing and generating options + # to be specified separately: + # + # - Options +input_col_sep+ and +output_col_sep+ + # (and their aliases +in_col_sep+ and +out_col_sep+) + # specify the column separators for parsing and generating. + # - Options +input_quote_char+ and +output_quote_char+ + # (and their aliases +in_quote_char+ and +out_quote_char+) + # specify the quote characters for parsing and generting. + # - Options +input_row_sep+ and +output_row_sep+ + # (and their aliases +in_row_sep+ and +out_row_sep+) + # specify the row separators for parsing and generating. + # + # Example options (for column separators): + # + # CSV.filter # Default for both parsing and generating. + # CSV.filter(in_col_sep: ';') # ';' for parsing, default for generating. + # CSV.filter(out_col_sep: '|') # Default for parsing, '|' for generating. + # CSV.filter(in_col_sep: ';', out_col_sep: '|') # ';' for parsing, '|' for generating. + # + # Note that for a special option (e.g., +input_col_sep+) + # and its corresponding "regular" option (e.g., +col_sep+), + # the two are mutually overriding. + # + # Another example (possibly surprising): + # + # CSV.filter(in_col_sep: ';', col_sep: '|') # '|' for both parsing(!) and generating. + # + def filter(input=nil, output=nil, **options) + # parse options for input, output, or both + in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value} + options.each do |key, value| + case key + when /\Ain(?:put)?_(.+)\Z/ + in_options[$1.to_sym] = value + when /\Aout(?:put)?_(.+)\Z/ + out_options[$1.to_sym] = value + else + in_options[key] = value + out_options[key] = value + end + end + + # build input and output wrappers + input = new(input || ARGF, **in_options) + output = new(output || $stdout, **out_options) + + # process headers + need_manual_header_output = + (in_options[:headers] and + out_options[:headers] == true and + out_options[:write_headers]) + if need_manual_header_output + first_row = input.shift + if first_row + if first_row.is_a?(Row) + headers = first_row.headers + yield headers + output << headers + end + yield first_row + output << first_row + end + end + + # read, yield, write + input.each do |row| + yield row + output << row + end + end + + # + # :call-seq: + # foreach(path_or_io, mode='r', **options) {|row| ... ) + # foreach(path_or_io, mode='r', **options) -> new_enumerator + # + # Calls the block with each row read from source +path_or_io+. + # + # \Path input without headers: + # + # string = "foo,0\nbar,1\nbaz,2\n" + # in_path = 't.csv' + # File.write(in_path, string) + # CSV.foreach(in_path) {|row| p row } + # + # Output: + # + # ["foo", "0"] + # ["bar", "1"] + # ["baz", "2"] + # + # \Path input with headers: + # + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # in_path = 't.csv' + # File.write(in_path, string) + # CSV.foreach(in_path, headers: true) {|row| p row } + # + # Output: + # + # + # + # + # + # \IO stream input without headers: + # + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # File.open('t.csv') do |in_io| + # CSV.foreach(in_io) {|row| p row } + # end + # + # Output: + # + # ["foo", "0"] + # ["bar", "1"] + # ["baz", "2"] + # + # \IO stream input with headers: + # + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # File.open('t.csv') do |in_io| + # CSV.foreach(in_io, headers: true) {|row| p row } + # end + # + # Output: + # + # + # + # + # + # With no block given, returns an \Enumerator: + # + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.foreach(path) # => # + # + # Arguments: + # * Argument +path_or_io+ must be a file path or an \IO stream. + # * Argument +mode+, if given, must be a \File mode. + # See {Access Modes}[https://docs.ruby-lang.org/en/master/File.html#class-File-label-Access+Modes]. + # * Arguments **options must be keyword options. + # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]. + # * This method optionally accepts an additional :encoding option + # that you can use to specify the Encoding of the data read from +path+ or +io+. + # You must provide this unless your data is in the encoding + # given by Encoding::default_external. + # Parsing will use this to determine how to parse the data. + # You may provide a second Encoding to + # have the data transcoded as it is read. For example, + # encoding: 'UTF-32BE:UTF-8' + # would read +UTF-32BE+ data from the file + # but transcode it to +UTF-8+ before parsing. + def foreach(path, mode="r", **options, &block) + return to_enum(__method__, path, mode, **options) unless block_given? + open(path, mode, **options) do |csv| + csv.each(&block) + end + end + + # + # :call-seq: + # generate(csv_string, **options) {|csv| ... } + # generate(**options) {|csv| ... } + # + # * Argument +csv_string+, if given, must be a \String object; + # defaults to a new empty \String. + # * Arguments +options+, if given, should be generating options. + # See {Options for Generating}[#class-CSV-label-Options+for+Generating]. + # + # --- + # + # Creates a new \CSV object via CSV.new(csv_string, **options); + # calls the block with the \CSV object, which the block may modify; + # returns the \String generated from the \CSV object. + # + # Note that a passed \String *is* modified by this method. + # Pass csv_string.dup if the \String must be preserved. + # + # This method has one additional option: :encoding, + # which sets the base Encoding for the output if no no +str+ is specified. + # CSV needs this hint if you plan to output non-ASCII compatible data. + # + # --- + # + # Add lines: + # input_string = "foo,0\nbar,1\nbaz,2\n" + # output_string = CSV.generate(input_string) do |csv| + # csv << ['bat', 3] + # csv << ['bam', 4] + # end + # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" + # input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" + # output_string.equal?(input_string) # => true # Same string, modified + # + # Add lines into new string, preserving old string: + # input_string = "foo,0\nbar,1\nbaz,2\n" + # output_string = CSV.generate(input_string.dup) do |csv| + # csv << ['bat', 3] + # csv << ['bam', 4] + # end + # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n" + # input_string # => "foo,0\nbar,1\nbaz,2\n" + # output_string.equal?(input_string) # => false # Different strings + # + # Create lines from nothing: + # output_string = CSV.generate do |csv| + # csv << ['foo', 0] + # csv << ['bar', 1] + # csv << ['baz', 2] + # end + # output_string # => "foo,0\nbar,1\nbaz,2\n" + # + # --- + # + # Raises an exception if +csv_string+ is not a \String object: + # # Raises TypeError (no implicit conversion of Integer into String) + # CSV.generate(0) + # + def generate(str=nil, **options) + encoding = options[:encoding] + # add a default empty String, if none was given + if str + str = StringIO.new(str) + str.seek(0, IO::SEEK_END) + str.set_encoding(encoding) if encoding + else + str = +"" + str.force_encoding(encoding) if encoding + end + csv = new(str, **options) # wrap + yield csv # yield for appending + csv.string # return final String + end + + # :call-seq: + # CSV.generate_line(ary) + # CSV.generate_line(ary, **options) + # + # Returns the \String created by generating \CSV from +ary+ + # using the specified +options+. + # + # Argument +ary+ must be an \Array. + # + # Special options: + # * Option :row_sep defaults to "\n"> on Ruby 3.0 or later + # and $INPUT_RECORD_SEPARATOR ($/) otherwise.: + # $INPUT_RECORD_SEPARATOR # => "\n" + # * This method accepts an additional option, :encoding, which sets the base + # Encoding for the output. This method will try to guess your Encoding from + # the first non-+nil+ field in +row+, if possible, but you may need to use + # this parameter as a backup plan. + # + # For other +options+, + # see {Options for Generating}[#class-CSV-label-Options+for+Generating]. + # + # --- + # + # Returns the \String generated from an \Array: + # CSV.generate_line(['foo', '0']) # => "foo,0\n" + # + # --- + # + # Raises an exception if +ary+ is not an \Array: + # # Raises NoMethodError (undefined method `find' for :foo:Symbol) + # CSV.generate_line(:foo) + # + def generate_line(row, **options) + options = {row_sep: InputRecordSeparator.value}.merge(options) + str = +"" + if options[:encoding] + str.force_encoding(options[:encoding]) + else + fallback_encoding = nil + output_encoding = nil + row.each do |field| + next unless field.is_a?(String) + fallback_encoding ||= field.encoding + next if field.ascii_only? + output_encoding = field.encoding + break + end + output_encoding ||= fallback_encoding + if output_encoding + str.force_encoding(output_encoding) + end + end + (new(str, **options) << row).string + end + + # :call-seq: + # CSV.generate_lines(rows) + # CSV.generate_lines(rows, **options) + # + # Returns the \String created by generating \CSV from + # using the specified +options+. + # + # Argument +rows+ must be an \Array of row. Row is \Array of \String or \CSV::Row. + # + # Special options: + # * Option :row_sep defaults to "\n" on Ruby 3.0 or later + # and $INPUT_RECORD_SEPARATOR ($/) otherwise.: + # $INPUT_RECORD_SEPARATOR # => "\n" + # * This method accepts an additional option, :encoding, which sets the base + # Encoding for the output. This method will try to guess your Encoding from + # the first non-+nil+ field in +row+, if possible, but you may need to use + # this parameter as a backup plan. + # + # For other +options+, + # see {Options for Generating}[#class-CSV-label-Options+for+Generating]. + # + # --- + # + # Returns the \String generated from an + # CSV.generate_lines([['foo', '0'], ['bar', '1'], ['baz', '2']]) # => "foo,0\nbar,1\nbaz,2\n" + # + # --- + # + # Raises an exception + # # Raises NoMethodError (undefined method `each' for :foo:Symbol) + # CSV.generate_lines(:foo) + # + def generate_lines(rows, **options) + self.generate(**options) do |csv| + rows.each do |row| + csv << row + end + end + end + + # + # :call-seq: + # open(path_or_io, mode = "rb", **options ) -> new_csv + # open(path_or_io, mode = "rb", **options ) { |csv| ... } -> object + # + # possible options elements: + # keyword form: + # :invalid => nil # raise error on invalid byte sequence (default) + # :invalid => :replace # replace invalid byte sequence + # :undef => :replace # replace undefined conversion + # :replace => string # replacement string ("?" or "\uFFFD" if not specified) + # + # * Argument +path_or_io+, must be a file path or an \IO stream. + # :include: ../doc/csv/arguments/io.rdoc + # * Argument +mode+, if given, must be a \File mode. + # See {Access Modes}[https://docs.ruby-lang.org/en/master/File.html#class-File-label-Access+Modes]. + # * Arguments **options must be keyword options. + # See {Options for Generating}[#class-CSV-label-Options+for+Generating]. + # * This method optionally accepts an additional :encoding option + # that you can use to specify the Encoding of the data read from +path+ or +io+. + # You must provide this unless your data is in the encoding + # given by Encoding::default_external. + # Parsing will use this to determine how to parse the data. + # You may provide a second Encoding to + # have the data transcoded as it is read. For example, + # encoding: 'UTF-32BE:UTF-8' + # would read +UTF-32BE+ data from the file + # but transcode it to +UTF-8+ before parsing. + # + # --- + # + # These examples assume prior execution of: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # string_io = StringIO.new + # string_io << "foo,0\nbar,1\nbaz,2\n" + # + # --- + # + # With no block given, returns a new \CSV object. + # + # Create a \CSV object using a file path: + # csv = CSV.open(path) + # csv # => # + # + # Create a \CSV object using an open \File: + # csv = CSV.open(File.open(path)) + # csv # => # + # + # Create a \CSV object using a \StringIO: + # csv = CSV.open(string_io) + # csv # => # + # --- + # + # With a block given, calls the block with the created \CSV object; + # returns the block's return value: + # + # Using a file path: + # csv = CSV.open(path) {|csv| p csv} + # csv # => # + # Output: + # # + # + # Using an open \File: + # csv = CSV.open(File.open(path)) {|csv| p csv} + # csv # => # + # Output: + # # + # + # Using a \StringIO: + # csv = CSV.open(string_io) {|csv| p csv} + # csv # => # + # Output: + # # + # --- + # + # Raises an exception if the argument is not a \String object or \IO object: + # # Raises TypeError (no implicit conversion of Symbol into String) + # CSV.open(:foo) + def open(filename_or_io, mode="r", **options) + # wrap a File opened with the remaining +args+ with no newline + # decorator + file_opts = {} + may_enable_bom_detection_automatically(filename_or_io, + mode, + options, + file_opts) + file_opts.merge!(options) + unless file_opts.key?(:newline) + file_opts[:universal_newline] ||= false + end + options.delete(:invalid) + options.delete(:undef) + options.delete(:replace) + options.delete_if {|k, _| /newline\z/.match?(k)} + + if filename_or_io.is_a?(StringIO) + f = create_stringio(filename_or_io.string, mode, **file_opts) + else + begin + f = File.open(filename_or_io, mode, **file_opts) + rescue ArgumentError => e + raise unless /needs binmode/.match?(e.message) and mode == "r" + mode = "rb" + file_opts = {encoding: Encoding.default_external}.merge(file_opts) + retry + end + end + + begin + csv = new(f, **options) + rescue Exception + f.close + raise + end + + # handle blocks like Ruby's open(), not like the CSV library + if block_given? + begin + yield csv + ensure + csv.close + end + else + csv + end + end + + # + # :call-seq: + # parse(string) -> array_of_arrays + # parse(io) -> array_of_arrays + # parse(string, headers: ..., **options) -> csv_table + # parse(io, headers: ..., **options) -> csv_table + # parse(string, **options) {|row| ... } + # parse(io, **options) {|row| ... } + # + # Parses +string+ or +io+ using the specified +options+. + # + # - Argument +string+ should be a \String object; + # it will be put into a new StringIO object positioned at the beginning. + # :include: ../doc/csv/arguments/io.rdoc + # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing] + # + # ====== Without Option +headers+ + # + # Without {option +headers+}[#class-CSV-label-Option+headers] case. + # + # These examples assume prior execution of: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # --- + # + # With no block given, returns an \Array of Arrays formed from the source. + # + # Parse a \String: + # a_of_a = CSV.parse(string) + # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # Parse an open \File: + # a_of_a = File.open(path) do |file| + # CSV.parse(file) + # end + # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # --- + # + # With a block given, calls the block with each parsed row: + # + # Parse a \String: + # CSV.parse(string) {|row| p row } + # + # Output: + # ["foo", "0"] + # ["bar", "1"] + # ["baz", "2"] + # + # Parse an open \File: + # File.open(path) do |file| + # CSV.parse(file) {|row| p row } + # end + # + # Output: + # ["foo", "0"] + # ["bar", "1"] + # ["baz", "2"] + # + # ====== With Option +headers+ + # + # With {option +headers+}[#class-CSV-label-Option+headers] case. + # + # These examples assume prior execution of: + # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # --- + # + # With no block given, returns a CSV::Table object formed from the source. + # + # Parse a \String: + # csv_table = CSV.parse(string, headers: ['Name', 'Count']) + # csv_table # => # + # + # Parse an open \File: + # csv_table = File.open(path) do |file| + # CSV.parse(file, headers: ['Name', 'Count']) + # end + # csv_table # => # + # + # --- + # + # With a block given, calls the block with each parsed row, + # which has been formed into a CSV::Row object: + # + # Parse a \String: + # CSV.parse(string, headers: ['Name', 'Count']) {|row| p row } + # + # Output: + # # + # # + # # + # + # Parse an open \File: + # File.open(path) do |file| + # CSV.parse(file, headers: ['Name', 'Count']) {|row| p row } + # end + # + # Output: + # # + # # + # # + # + # --- + # + # Raises an exception if the argument is not a \String object or \IO object: + # # Raises NoMethodError (undefined method `close' for :foo:Symbol) + # CSV.parse(:foo) + # + # --- + # + # Please make sure if your text contains \BOM or not. CSV.parse will not remove + # \BOM automatically. You might want to remove \BOM before calling CSV.parse : + # # remove BOM on calling File.open + # File.open(path, encoding: 'bom|utf-8') do |file| + # CSV.parse(file, headers: true) do |row| + # # you can get value by column name because BOM is removed + # p row['Name'] + # end + # end + # + # Output: + # # "foo" + # # "bar" + # # "baz" + def parse(str, **options, &block) + csv = new(str, **options) + + return csv.each(&block) if block_given? + + # slurp contents, if no block is given + begin + csv.read + ensure + csv.close + end + end + + # :call-seq: + # CSV.parse_line(string) -> new_array or nil + # CSV.parse_line(io) -> new_array or nil + # CSV.parse_line(string, **options) -> new_array or nil + # CSV.parse_line(io, **options) -> new_array or nil + # CSV.parse_line(string, headers: true, **options) -> csv_row or nil + # CSV.parse_line(io, headers: true, **options) -> csv_row or nil + # + # Returns the data created by parsing the first line of +string+ or +io+ + # using the specified +options+. + # + # - Argument +string+ should be a \String object; + # it will be put into a new StringIO object positioned at the beginning. + # :include: ../doc/csv/arguments/io.rdoc + # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing] + # + # ====== Without Option +headers+ + # + # Without option +headers+, returns the first row as a new \Array. + # + # These examples assume prior execution of: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # Parse the first line from a \String object: + # CSV.parse_line(string) # => ["foo", "0"] + # + # Parse the first line from a File object: + # File.open(path) do |file| + # CSV.parse_line(file) # => ["foo", "0"] + # end # => ["foo", "0"] + # + # Returns +nil+ if the argument is an empty \String: + # CSV.parse_line('') # => nil + # + # ====== With Option +headers+ + # + # With {option +headers+}[#class-CSV-label-Option+headers], + # returns the first row as a CSV::Row object. + # + # These examples assume prior execution of: + # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # Parse the first line from a \String object: + # CSV.parse_line(string, headers: true) # => # + # + # Parse the first line from a File object: + # File.open(path) do |file| + # CSV.parse_line(file, headers: true) + # end # => # + # + # --- + # + # Raises an exception if the argument is +nil+: + # # Raises ArgumentError (Cannot parse nil as CSV): + # CSV.parse_line(nil) + # + def parse_line(line, **options) + new(line, **options).each.first + end + + # + # :call-seq: + # read(source, **options) -> array_of_arrays + # read(source, headers: true, **options) -> csv_table + # + # Opens the given +source+ with the given +options+ (see CSV.open), + # reads the source (see CSV#read), and returns the result, + # which will be either an \Array of Arrays or a CSV::Table. + # + # Without headers: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # With headers: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.read(path, headers: true) # => # + def read(path, **options) + open(path, **options) { |csv| csv.read } + end + + # :call-seq: + # CSV.readlines(source, **options) + # + # Alias for CSV.read. + def readlines(path, **options) + read(path, **options) + end + + # :call-seq: + # CSV.table(source, **options) + # + # Calls CSV.read with +source+, +options+, and certain default options: + # - +headers+: +true+ + # - +converters+: +:numeric+ + # - +header_converters+: +:symbol+ + # + # Returns a CSV::Table object. + # + # Example: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.table(path) # => # + def table(path, **options) + default_options = { + headers: true, + converters: :numeric, + header_converters: :symbol, + } + options = default_options.merge(options) + read(path, **options) + end + + ON_WINDOWS = /mingw|mswin/.match?(RUBY_PLATFORM) + private_constant :ON_WINDOWS + + private + def may_enable_bom_detection_automatically(filename_or_io, + mode, + options, + file_opts) + if filename_or_io.is_a?(StringIO) + # Support to StringIO was dropped for Ruby 2.6 and earlier without BOM support: + # https://github.com/ruby/stringio/pull/47 + return if RUBY_VERSION < "2.7" + else + # "bom|utf-8" may be buggy on Windows: + # https://bugs.ruby-lang.org/issues/20526 + return if ON_WINDOWS + end + return unless Encoding.default_external == Encoding::UTF_8 + return if options.key?(:encoding) + return if options.key?(:external_encoding) + return if mode.include?(":") + file_opts[:encoding] = "bom|utf-8" + end + + if RUBY_VERSION < "2.7" + def create_stringio(str, mode, opts) + opts.delete_if {|k, _| k == :universal_newline or DEFAULT_OPTIONS.key?(k)} + raise ArgumentError, "Unsupported options parsing StringIO: #{opts.keys}" unless opts.empty? + StringIO.new(str, mode) + end + else + def create_stringio(str, mode, opts) + StringIO.new(str, mode, **opts) + end + end + end + + # :call-seq: + # CSV.new(string) + # CSV.new(io) + # CSV.new(string, **options) + # CSV.new(io, **options) + # + # Returns the new \CSV object created using +string+ or +io+ + # and the specified +options+. + # + # - Argument +string+ should be a \String object; + # it will be put into a new StringIO object positioned at the beginning. + # :include: ../doc/csv/arguments/io.rdoc + # - Argument +options+: See: + # * {Options for Parsing}[#class-CSV-label-Options+for+Parsing] + # * {Options for Generating}[#class-CSV-label-Options+for+Generating] + # For performance reasons, the options cannot be overridden + # in a \CSV object, so those specified here will endure. + # + # In addition to the \CSV instance methods, several \IO methods are delegated. + # See {Delegated Methods}[#class-CSV-label-Delegated+Methods]. + # + # --- + # + # Create a \CSV object from a \String object: + # csv = CSV.new('foo,0') + # csv # => # + # + # Create a \CSV object from a \File object: + # File.write('t.csv', 'foo,0') + # csv = CSV.new(File.open('t.csv')) + # csv # => # + # + # --- + # + # Raises an exception if the argument is +nil+: + # # Raises ArgumentError (Cannot parse nil as CSV): + # CSV.new(nil) + # + def initialize(data, + col_sep: ",", + row_sep: :auto, + quote_char: '"', + field_size_limit: nil, + max_field_size: nil, + converters: nil, + unconverted_fields: nil, + headers: false, + return_headers: false, + write_headers: nil, + header_converters: nil, + skip_blanks: false, + force_quotes: false, + skip_lines: nil, + liberal_parsing: false, + internal_encoding: nil, + external_encoding: nil, + encoding: nil, + nil_value: nil, + empty_value: "", + strip: false, + quote_empty: true, + write_converters: nil, + write_nil_value: nil, + write_empty_value: "") + raise ArgumentError.new("Cannot parse nil as CSV") if data.nil? + + if data.is_a?(String) + if encoding + if encoding.is_a?(String) + data_external_encoding, data_internal_encoding = encoding.split(":", 2) + if data_internal_encoding + data = data.encode(data_internal_encoding, data_external_encoding) + else + data = data.dup.force_encoding(data_external_encoding) + end + else + data = data.dup.force_encoding(encoding) + end + end + @io = StringIO.new(data) + else + @io = data + end + @encoding = determine_encoding(encoding, internal_encoding) + + @base_fields_converter_options = { + nil_value: nil_value, + empty_value: empty_value, + } + @write_fields_converter_options = { + nil_value: write_nil_value, + empty_value: write_empty_value, + } + @initial_converters = converters + @initial_header_converters = header_converters + @initial_write_converters = write_converters + + if max_field_size.nil? and field_size_limit + max_field_size = field_size_limit - 1 + end + @parser_options = { + column_separator: col_sep, + row_separator: row_sep, + quote_character: quote_char, + max_field_size: max_field_size, + unconverted_fields: unconverted_fields, + headers: headers, + return_headers: return_headers, + skip_blanks: skip_blanks, + skip_lines: skip_lines, + liberal_parsing: liberal_parsing, + encoding: @encoding, + nil_value: nil_value, + empty_value: empty_value, + strip: strip, + } + @parser = nil + @parser_enumerator = nil + @eof_error = nil + + @writer_options = { + encoding: @encoding, + force_encoding: (not encoding.nil?), + force_quotes: force_quotes, + headers: headers, + write_headers: write_headers, + column_separator: col_sep, + row_separator: row_sep, + quote_character: quote_char, + quote_empty: quote_empty, + } + + @writer = nil + writer if @writer_options[:write_headers] + end + + class TSV < CSV + def initialize(data, **options) + super(data, **({col_sep: "\t"}.merge(options))) + end + end + + # :call-seq: + # csv.col_sep -> string + # + # Returns the encoded column separator; used for parsing and writing; + # see {Option +col_sep+}[#class-CSV-label-Option+col_sep]: + # CSV.new('').col_sep # => "," + def col_sep + parser.column_separator + end + + # :call-seq: + # csv.row_sep -> string + # + # Returns the encoded row separator; used for parsing and writing; + # see {Option +row_sep+}[#class-CSV-label-Option+row_sep]: + # CSV.new('').row_sep # => "\n" + def row_sep + parser.row_separator + end + + # :call-seq: + # csv.quote_char -> character + # + # Returns the encoded quote character; used for parsing and writing; + # see {Option +quote_char+}[#class-CSV-label-Option+quote_char]: + # CSV.new('').quote_char # => "\"" + def quote_char + parser.quote_character + end + + # :call-seq: + # csv.field_size_limit -> integer or nil + # + # Returns the limit for field size; used for parsing; + # see {Option +field_size_limit+}[#class-CSV-label-Option+field_size_limit]: + # CSV.new('').field_size_limit # => nil + # + # Deprecated since 3.2.3. Use +max_field_size+ instead. + def field_size_limit + parser.field_size_limit + end + + # :call-seq: + # csv.max_field_size -> integer or nil + # + # Returns the limit for field size; used for parsing; + # see {Option +max_field_size+}[#class-CSV-label-Option+max_field_size]: + # CSV.new('').max_field_size # => nil + # + # Since 3.2.3. + def max_field_size + parser.max_field_size + end + + # :call-seq: + # csv.skip_lines -> regexp or nil + # + # Returns the \Regexp used to identify comment lines; used for parsing; + # see {Option +skip_lines+}[#class-CSV-label-Option+skip_lines]: + # CSV.new('').skip_lines # => nil + def skip_lines + parser.skip_lines + end + + # :call-seq: + # csv.converters -> array + # + # Returns an \Array containing field converters; + # see {Field Converters}[#class-CSV-label-Field+Converters]: + # csv = CSV.new('') + # csv.converters # => [] + # csv.convert(:integer) + # csv.converters # => [:integer] + # csv.convert(proc {|x| x.to_s }) + # csv.converters + # + # Notes that you need to call + # +Ractor.make_shareable(CSV::Converters)+ on the main Ractor to use + # this method. + def converters + parser_fields_converter.map do |converter| + name = Converters.rassoc(converter) + name ? name.first : converter + end + end + + # :call-seq: + # csv.unconverted_fields? -> object + # + # Returns the value that determines whether unconverted fields are to be + # available; used for parsing; + # see {Option +unconverted_fields+}[#class-CSV-label-Option+unconverted_fields]: + # CSV.new('').unconverted_fields? # => nil + def unconverted_fields? + parser.unconverted_fields? + end + + # :call-seq: + # csv.headers -> object + # + # Returns the value that determines whether headers are used; used for parsing; + # see {Option +headers+}[#class-CSV-label-Option+headers]: + # CSV.new('').headers # => nil + def headers + if @writer + @writer.headers + else + parsed_headers = parser.headers + return parsed_headers if parsed_headers + raw_headers = @parser_options[:headers] + raw_headers = nil if raw_headers == false + raw_headers + end + end + + # :call-seq: + # csv.return_headers? -> true or false + # + # Returns the value that determines whether headers are to be returned; used for parsing; + # see {Option +return_headers+}[#class-CSV-label-Option+return_headers]: + # CSV.new('').return_headers? # => false + def return_headers? + parser.return_headers? + end + + # :call-seq: + # csv.write_headers? -> true or false + # + # Returns the value that determines whether headers are to be written; used for generating; + # see {Option +write_headers+}[#class-CSV-label-Option+write_headers]: + # CSV.new('').write_headers? # => nil + def write_headers? + @writer_options[:write_headers] + end + + # :call-seq: + # csv.header_converters -> array + # + # Returns an \Array containing header converters; used for parsing; + # see {Header Converters}[#class-CSV-label-Header+Converters]: + # CSV.new('').header_converters # => [] + # + # Notes that you need to call + # +Ractor.make_shareable(CSV::HeaderConverters)+ on the main Ractor + # to use this method. + def header_converters + header_fields_converter.map do |converter| + name = HeaderConverters.rassoc(converter) + name ? name.first : converter + end + end + + # :call-seq: + # csv.skip_blanks? -> true or false + # + # Returns the value that determines whether blank lines are to be ignored; used for parsing; + # see {Option +skip_blanks+}[#class-CSV-label-Option+skip_blanks]: + # CSV.new('').skip_blanks? # => false + def skip_blanks? + parser.skip_blanks? + end + + # :call-seq: + # csv.force_quotes? -> true or false + # + # Returns the value that determines whether all output fields are to be quoted; + # used for generating; + # see {Option +force_quotes+}[#class-CSV-label-Option+force_quotes]: + # CSV.new('').force_quotes? # => false + def force_quotes? + @writer_options[:force_quotes] + end + + # :call-seq: + # csv.liberal_parsing? -> true or false + # + # Returns the value that determines whether illegal input is to be handled; used for parsing; + # see {Option +liberal_parsing+}[#class-CSV-label-Option+liberal_parsing]: + # CSV.new('').liberal_parsing? # => false + def liberal_parsing? + parser.liberal_parsing? + end + + # :call-seq: + # csv.encoding -> encoding + # + # Returns the encoding used for parsing and generating; + # see {Character Encodings (M17n or Multilingualization)}[#class-CSV-label-Character+Encodings+-28M17n+or+Multilingualization-29]: + # CSV.new('').encoding # => # + attr_reader :encoding + + # :call-seq: + # csv.line_no -> integer + # + # Returns the count of the rows parsed or generated. + # + # Parsing: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.open(path) do |csv| + # csv.each do |row| + # p [csv.lineno, row] + # end + # end + # Output: + # [1, ["foo", "0"]] + # [2, ["bar", "1"]] + # [3, ["baz", "2"]] + # + # Generating: + # CSV.generate do |csv| + # p csv.lineno; csv << ['foo', 0] + # p csv.lineno; csv << ['bar', 1] + # p csv.lineno; csv << ['baz', 2] + # end + # Output: + # 0 + # 1 + # 2 + def lineno + if @writer + @writer.lineno + else + parser.lineno + end + end + + # :call-seq: + # csv.line -> array + # + # Returns the line most recently read: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # CSV.open(path) do |csv| + # csv.each do |row| + # p [csv.lineno, csv.line] + # end + # end + # Output: + # [1, "foo,0\n"] + # [2, "bar,1\n"] + # [3, "baz,2\n"] + def line + parser.line + end + + ### IO and StringIO Delegation ### + + extend Forwardable + def_delegators :@io, :binmode, :close, :close_read, :close_write, + :closed?, :external_encoding, :fcntl, + :fileno, :flush, :fsync, :internal_encoding, + :isatty, :pid, :pos, :pos=, :reopen, + :seek, :string, :sync, :sync=, :tell, + :truncate, :tty? + + def binmode? + if @io.respond_to?(:binmode?) + @io.binmode? + else + false + end + end + + def flock(*args) + raise NotImplementedError unless @io.respond_to?(:flock) + @io.flock(*args) + end + + def ioctl(*args) + raise NotImplementedError unless @io.respond_to?(:ioctl) + @io.ioctl(*args) + end + + def path + @io.path if @io.respond_to?(:path) + end + + def stat(*args) + raise NotImplementedError unless @io.respond_to?(:stat) + @io.stat(*args) + end + + def to_i + raise NotImplementedError unless @io.respond_to?(:to_i) + @io.to_i + end + + def to_io + @io.respond_to?(:to_io) ? @io.to_io : @io + end + + def eof? + return false if @eof_error + begin + parser_enumerator.peek + false + rescue MalformedCSVError => error + @eof_error = error + false + rescue StopIteration + true + end + end + alias_method :eof, :eof? + + # Rewinds the underlying IO object and resets CSV's lineno() counter. + def rewind + @parser = nil + @parser_enumerator = nil + @eof_error = nil + @writer.rewind if @writer + @io.rewind + end + + ### End Delegation ### + + # :call-seq: + # csv << row -> self + # + # Appends a row to +self+. + # + # - Argument +row+ must be an \Array object or a CSV::Row object. + # - The output stream must be open for writing. + # + # --- + # + # Append Arrays: + # CSV.generate do |csv| + # csv << ['foo', 0] + # csv << ['bar', 1] + # csv << ['baz', 2] + # end # => "foo,0\nbar,1\nbaz,2\n" + # + # Append CSV::Rows: + # headers = [] + # CSV.generate do |csv| + # csv << CSV::Row.new(headers, ['foo', 0]) + # csv << CSV::Row.new(headers, ['bar', 1]) + # csv << CSV::Row.new(headers, ['baz', 2]) + # end # => "foo,0\nbar,1\nbaz,2\n" + # + # Headers in CSV::Row objects are not appended: + # headers = ['Name', 'Count'] + # CSV.generate do |csv| + # csv << CSV::Row.new(headers, ['foo', 0]) + # csv << CSV::Row.new(headers, ['bar', 1]) + # csv << CSV::Row.new(headers, ['baz', 2]) + # end # => "foo,0\nbar,1\nbaz,2\n" + # + # --- + # + # Raises an exception if +row+ is not an \Array or \CSV::Row: + # CSV.generate do |csv| + # # Raises NoMethodError (undefined method `collect' for :foo:Symbol) + # csv << :foo + # end + # + # Raises an exception if the output stream is not opened for writing: + # path = 't.csv' + # File.write(path, '') + # File.open(path) do |file| + # CSV.open(file) do |csv| + # # Raises IOError (not opened for writing) + # csv << ['foo', 0] + # end + # end + def <<(row) + writer << row + self + end + alias_method :add_row, :<< + alias_method :puts, :<< + + # :call-seq: + # convert(converter_name) -> array_of_procs + # convert {|field, field_info| ... } -> array_of_procs + # + # - With no block, installs a field converter (a \Proc). + # - With a block, defines and installs a custom field converter. + # - Returns the \Array of installed field converters. + # + # - Argument +converter_name+, if given, should be the name + # of an existing field converter. + # + # See {Field Converters}[#class-CSV-label-Field+Converters]. + # --- + # + # With no block, installs a field converter: + # csv = CSV.new('') + # csv.convert(:integer) + # csv.convert(:float) + # csv.convert(:date) + # csv.converters # => [:integer, :float, :date] + # + # --- + # + # The block, if given, is called for each field: + # - Argument +field+ is the field value. + # - Argument +field_info+ is a CSV::FieldInfo object + # containing details about the field. + # + # The examples here assume the prior execution of: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # Example giving a block: + # csv = CSV.open(path) + # csv.convert {|field, field_info| p [field, field_info]; field.upcase } + # csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]] + # + # Output: + # ["foo", #] + # ["0", #] + # ["bar", #] + # ["1", #] + # ["baz", #] + # ["2", #] + # + # The block need not return a \String object: + # csv = CSV.open(path) + # csv.convert {|field, field_info| field.to_sym } + # csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]] + # + # If +converter_name+ is given, the block is not called: + # csv = CSV.open(path) + # csv.convert(:integer) {|field, field_info| fail 'Cannot happen' } + # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]] + # + # --- + # + # Raises a parse-time exception if +converter_name+ is not the name of a built-in + # field converter: + # csv = CSV.open(path) + # csv.convert(:nosuch) => [nil] + # # Raises NoMethodError (undefined method `arity' for nil:NilClass) + # csv.read + def convert(name = nil, &converter) + parser_fields_converter.add_converter(name, &converter) + end + + # :call-seq: + # header_convert(converter_name) -> array_of_procs + # header_convert {|header, field_info| ... } -> array_of_procs + # + # - With no block, installs a header converter (a \Proc). + # - With a block, defines and installs a custom header converter. + # - Returns the \Array of installed header converters. + # + # - Argument +converter_name+, if given, should be the name + # of an existing header converter. + # + # See {Header Converters}[#class-CSV-label-Header+Converters]. + # --- + # + # With no block, installs a header converter: + # csv = CSV.new('') + # csv.header_convert(:symbol) + # csv.header_convert(:downcase) + # csv.header_converters # => [:symbol, :downcase] + # + # --- + # + # The block, if given, is called for each header: + # - Argument +header+ is the header value. + # - Argument +field_info+ is a CSV::FieldInfo object + # containing details about the header. + # + # The examples here assume the prior execution of: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # + # Example giving a block: + # csv = CSV.open(path, headers: true) + # csv.header_convert {|header, field_info| p [header, field_info]; header.upcase } + # table = csv.read + # table # => # + # table.headers # => ["NAME", "VALUE"] + # + # Output: + # ["Name", #] + # ["Value", #] + + # The block need not return a \String object: + # csv = CSV.open(path, headers: true) + # csv.header_convert {|header, field_info| header.to_sym } + # table = csv.read + # table.headers # => [:Name, :Value] + # + # If +converter_name+ is given, the block is not called: + # csv = CSV.open(path, headers: true) + # csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' } + # table = csv.read + # table.headers # => ["name", "value"] + # --- + # + # Raises a parse-time exception if +converter_name+ is not the name of a built-in + # field converter: + # csv = CSV.open(path, headers: true) + # csv.header_convert(:nosuch) + # # Raises NoMethodError (undefined method `arity' for nil:NilClass) + # csv.read + def header_convert(name = nil, &converter) + header_fields_converter.add_converter(name, &converter) + end + + include Enumerable + + # :call-seq: + # csv.each -> enumerator + # csv.each {|row| ...} + # + # Calls the block with each successive row. + # The data source must be opened for reading. + # + # Without headers: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.each do |row| + # p row + # end + # Output: + # ["foo", "0"] + # ["bar", "1"] + # ["baz", "2"] + # + # With headers: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string, headers: true) + # csv.each do |row| + # p row + # end + # Output: + # + # + # + # + # --- + # + # Raises an exception if the source is not opened for reading: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.close + # # Raises IOError (not opened for reading) + # csv.each do |row| + # p row + # end + def each(&block) + return to_enum(__method__) unless block_given? + begin + while true + yield(parser_enumerator.next) + end + rescue StopIteration + end + end + + # :call-seq: + # csv.read -> array or csv_table + # + # Forms the remaining rows from +self+ into: + # - A CSV::Table object, if headers are in use. + # - An \Array of Arrays, otherwise. + # + # The data source must be opened for reading. + # + # Without headers: + # string = "foo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # csv = CSV.open(path) + # csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # With headers: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # path = 't.csv' + # File.write(path, string) + # csv = CSV.open(path, headers: true) + # csv.read # => # + # + # --- + # + # Raises an exception if the source is not opened for reading: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.close + # # Raises IOError (not opened for reading) + # csv.read + def read + rows = to_a + if parser.use_headers? + Table.new(rows, headers: parser.headers) + else + rows + end + end + alias_method :readlines, :read + + # :call-seq: + # csv.header_row? -> true or false + # + # Returns +true+ if the next row to be read is a header row\; + # +false+ otherwise. + # + # Without headers: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.header_row? # => false + # + # With headers: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string, headers: true) + # csv.header_row? # => true + # csv.shift # => # + # csv.header_row? # => false + # + # --- + # + # Raises an exception if the source is not opened for reading: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.close + # # Raises IOError (not opened for reading) + # csv.header_row? + def header_row? + parser.header_row? + end + + # :call-seq: + # csv.shift -> array, csv_row, or nil + # + # Returns the next row of data as: + # - An \Array if no headers are used. + # - A CSV::Row object if headers are used. + # + # The data source must be opened for reading. + # + # Without headers: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.shift # => ["foo", "0"] + # csv.shift # => ["bar", "1"] + # csv.shift # => ["baz", "2"] + # csv.shift # => nil + # + # With headers: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string, headers: true) + # csv.shift # => # + # csv.shift # => # + # csv.shift # => # + # csv.shift # => nil + # + # --- + # + # Raises an exception if the source is not opened for reading: + # string = "foo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string) + # csv.close + # # Raises IOError (not opened for reading) + # csv.shift + def shift + if @eof_error + eof_error, @eof_error = @eof_error, nil + raise eof_error + end + begin + parser_enumerator.next + rescue StopIteration + nil + end + end + alias_method :gets, :shift + alias_method :readline, :shift + + # :call-seq: + # csv.inspect -> string + # + # Returns a \String showing certain properties of +self+: + # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # csv = CSV.new(string, headers: true) + # s = csv.inspect + # s # => "#" + def inspect + str = ["#<", self.class.to_s, " io_type:"] + # show type of wrapped IO + if @io == $stdout then str << "$stdout" + elsif @io == $stdin then str << "$stdin" + elsif @io == $stderr then str << "$stderr" + else str << @io.class.to_s + end + # show IO.path(), if available + if @io.respond_to?(:path) and (p = @io.path) + str << " io_path:" << p.inspect + end + # show encoding + str << " encoding:" << @encoding.name + # show other attributes + ["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name| + if a = __send__(attr_name) + str << " " << attr_name << ":" << a.inspect + end + end + ["skip_blanks", "liberal_parsing"].each do |attr_name| + if a = __send__("#{attr_name}?") + str << " " << attr_name << ":" << a.inspect + end + end + _headers = headers + str << " headers:" << _headers.inspect if _headers + str << ">" + begin + str.join('') + rescue # any encoding error + str.map do |s| + e = Encoding::Converter.asciicompat_encoding(s.encoding) + e ? s.encode(e) : s.force_encoding("ASCII-8BIT") + end.join('') + end + end + + private + + def determine_encoding(encoding, internal_encoding) + # honor the IO encoding if we can, otherwise default to ASCII-8BIT + io_encoding = raw_encoding + return io_encoding if io_encoding + + return Encoding.find(internal_encoding) if internal_encoding + + if encoding + encoding, = encoding.split(":", 2) if encoding.is_a?(String) + return Encoding.find(encoding) + end + + Encoding.default_internal || Encoding.default_external + end + + def normalize_converters(converters) + converters ||= [] + unless converters.is_a?(Array) + converters = [converters] + end + converters.collect do |converter| + case converter + when Proc # custom code block + [nil, converter] + else # by name + [converter, nil] + end + end + end + + # + # Processes +fields+ with @converters, or @header_converters + # if +headers+ is passed as +true+, returning the converted field set. Any + # converter that changes the field into something other than a String halts + # the pipeline of conversion for that field. This is primarily an efficiency + # shortcut. + # + def convert_fields(fields, headers = false) + if headers + header_fields_converter.convert(fields, nil, 0) + else + parser_fields_converter.convert(fields, @headers, lineno) + end + end + + # + # Returns the encoding of the internal IO object. + # + def raw_encoding + if @io.respond_to? :internal_encoding + @io.internal_encoding || @io.external_encoding + elsif @io.respond_to? :encoding + @io.encoding + else + nil + end + end + + def parser_fields_converter + @parser_fields_converter ||= build_parser_fields_converter + end + + def build_parser_fields_converter + specific_options = { + builtin_converters_name: :Converters, + } + options = @base_fields_converter_options.merge(specific_options) + build_fields_converter(@initial_converters, options) + end + + def header_fields_converter + @header_fields_converter ||= build_header_fields_converter + end + + def build_header_fields_converter + specific_options = { + builtin_converters_name: :HeaderConverters, + accept_nil: true, + } + options = @base_fields_converter_options.merge(specific_options) + build_fields_converter(@initial_header_converters, options) + end + + def writer_fields_converter + @writer_fields_converter ||= build_writer_fields_converter + end + + def build_writer_fields_converter + build_fields_converter(@initial_write_converters, + @write_fields_converter_options) + end + + def build_fields_converter(initial_converters, options) + fields_converter = FieldsConverter.new(options) + normalize_converters(initial_converters).each do |name, converter| + fields_converter.add_converter(name, &converter) + end + fields_converter + end + + def parser + @parser ||= Parser.new(@io, parser_options) + end + + def parser_options + @parser_options.merge(header_fields_converter: header_fields_converter, + fields_converter: parser_fields_converter) + end + + def parser_enumerator + @parser_enumerator ||= parser.parse + end + + def writer + @writer ||= Writer.new(@io, writer_options) + end + + def writer_options + @writer_options.merge(header_fields_converter: header_fields_converter, + fields_converter: writer_fields_converter) + end +end + +# Passes +args+ to CSV::instance. +# +# CSV("CSV,data").read +# #=> [["CSV", "data"]] +# +# If a block is given, the instance is passed the block and the return value +# becomes the return value of the block. +# +# CSV("CSV,data") { |c| +# c.read.any? { |a| a.include?("data") } +# } #=> true +# +# CSV("CSV,data") { |c| +# c.read.any? { |a| a.include?("zombies") } +# } #=> false +# +# CSV options may also be given. +# +# io = StringIO.new +# CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] } +# +# This API is not Ractor-safe. +# +def CSV(*args, **options, &block) + CSV.instance(*args, **options, &block) +end + +require_relative "csv/version" +require_relative "csv/core_ext/array" +require_relative "csv/core_ext/string" diff --git a/bin/gems/csv-3.3.2/lib/csv/core_ext/array.rb b/bin/gems/csv-3.3.2/lib/csv/core_ext/array.rb new file mode 100644 index 00000000..ad1b881b --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/core_ext/array.rb @@ -0,0 +1,9 @@ +class Array + # Equivalent to CSV::generate_line(self, options) + # + # ["CSV", "data"].to_csv + # #=> "CSV,data\n" + def to_csv(**options) + CSV.generate_line(self, **options) + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/core_ext/string.rb b/bin/gems/csv-3.3.2/lib/csv/core_ext/string.rb new file mode 100644 index 00000000..61286d0f --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/core_ext/string.rb @@ -0,0 +1,9 @@ +class String + # Equivalent to CSV::parse_line(self, options) + # + # "CSV,data".parse_csv + # #=> ["CSV", "data"] + def parse_csv(**options) + CSV.parse_line(self, **options) + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/fields_converter.rb b/bin/gems/csv-3.3.2/lib/csv/fields_converter.rb new file mode 100644 index 00000000..8ea13408 --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/fields_converter.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +class CSV + # Note: Don't use this class directly. This is an internal class. + class FieldsConverter + include Enumerable + + NO_QUOTED_FIELDS = [] # :nodoc: + def NO_QUOTED_FIELDS.[](_index) + false + end + NO_QUOTED_FIELDS.freeze + + # + # A CSV::FieldsConverter is a data structure for storing the + # fields converter properties to be passed as a parameter + # when parsing a new file (e.g. CSV::Parser.new(@io, parser_options)) + # + + def initialize(options={}) + @converters = [] + @nil_value = options[:nil_value] + @empty_value = options[:empty_value] + @empty_value_is_empty_string = (@empty_value == "") + @accept_nil = options[:accept_nil] + @builtin_converters_name = options[:builtin_converters_name] + @need_static_convert = need_static_convert? + end + + def add_converter(name=nil, &converter) + if name.nil? # custom converter + @converters << converter + else # named converter + combo = builtin_converters[name] + case combo + when Array # combo converter + combo.each do |sub_name| + add_converter(sub_name) + end + else # individual named converter + @converters << combo + end + end + end + + def each(&block) + @converters.each(&block) + end + + def empty? + @converters.empty? + end + + def convert(fields, headers, lineno, quoted_fields=NO_QUOTED_FIELDS) + return fields unless need_convert? + + fields.collect.with_index do |field, index| + if field.nil? + field = @nil_value + elsif field.is_a?(String) and field.empty? + field = @empty_value unless @empty_value_is_empty_string + end + @converters.each do |converter| + break if field.nil? and @accept_nil + if converter.arity == 1 # straight field converter + field = converter[field] + else # FieldInfo converter + if headers + header = headers[index] + else + header = nil + end + quoted = quoted_fields[index] + field = converter[field, FieldInfo.new(index, lineno, header, quoted)] + end + break unless field.is_a?(String) # short-circuit pipeline for speed + end + field # final state of each field, converted or original + end + end + + private + def need_static_convert? + not (@nil_value.nil? and @empty_value_is_empty_string) + end + + def need_convert? + @need_static_convert or + (not @converters.empty?) + end + + def builtin_converters + @builtin_converters ||= ::CSV.const_get(@builtin_converters_name) + end + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/input_record_separator.rb b/bin/gems/csv-3.3.2/lib/csv/input_record_separator.rb new file mode 100644 index 00000000..7a99343c --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/input_record_separator.rb @@ -0,0 +1,18 @@ +require "English" +require "stringio" + +class CSV + module InputRecordSeparator + class << self + if RUBY_VERSION >= "3.0.0" + def value + "\n" + end + else + def value + $INPUT_RECORD_SEPARATOR + end + end + end + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/parser.rb b/bin/gems/csv-3.3.2/lib/csv/parser.rb new file mode 100644 index 00000000..977ec235 --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/parser.rb @@ -0,0 +1,1292 @@ +# frozen_string_literal: true + +require "strscan" + +require_relative "input_record_separator" +require_relative "row" +require_relative "table" + +class CSV + # Note: Don't use this class directly. This is an internal class. + class Parser + # + # A CSV::Parser is m17n aware. The parser works in the Encoding of the IO + # or String object being read from or written to. Your data is never transcoded + # (unless you ask Ruby to transcode it for you) and will literally be parsed in + # the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the + # Encoding of your data. This is accomplished by transcoding the parser itself + # into your Encoding. + # + + # Raised when encoding is invalid. + class InvalidEncoding < StandardError + end + + # Raised when unexpected case is happen. + class UnexpectedError < StandardError + end + + # + # CSV::Scanner receives a CSV output, scans it and return the content. + # It also controls the life cycle of the object with its methods +keep_start+, + # +keep_end+, +keep_back+, +keep_drop+. + # + # Uses StringScanner (the official strscan gem). Strscan provides lexical + # scanning operations on a String. We inherit its object and take advantage + # on the methods. For more information, please visit: + # https://ruby-doc.org/stdlib-2.6.1/libdoc/strscan/rdoc/StringScanner.html + # + class Scanner < StringScanner + alias_method :scan_all, :scan + + def initialize(*args) + super + @keeps = [] + end + + def each_line(row_separator) + position = pos + rest.each_line(row_separator) do |line| + position += line.bytesize + self.pos = position + yield(line) + end + end + + def keep_start + @keeps.push(pos) + end + + def keep_end + start = @keeps.pop + string.byteslice(start, pos - start) + end + + def keep_back + self.pos = @keeps.pop + end + + def keep_drop + @keeps.pop + end + end + + # + # CSV::InputsScanner receives IO inputs, encoding and the chunk_size. + # It also controls the life cycle of the object with its methods +keep_start+, + # +keep_end+, +keep_back+, +keep_drop+. + # + # CSV::InputsScanner.scan() tries to match with pattern at the current position. + # If there's a match, the scanner advances the "scan pointer" and returns the matched string. + # Otherwise, the scanner returns nil. + # + # CSV::InputsScanner.rest() returns the "rest" of the string (i.e. everything after the scan pointer). + # If there is no more data (eos? = true), it returns "". + # + class InputsScanner + def initialize(inputs, encoding, row_separator, chunk_size: 8192) + @inputs = inputs.dup + @encoding = encoding + @row_separator = row_separator + @chunk_size = chunk_size + @last_scanner = @inputs.empty? + @keeps = [] + read_chunk + end + + def each_line(row_separator) + return enum_for(__method__, row_separator) unless block_given? + buffer = nil + input = @scanner.rest + position = @scanner.pos + offset = 0 + n_row_separator_chars = row_separator.size + # trace(__method__, :start, input) + while true + input.each_line(row_separator) do |line| + @scanner.pos += line.bytesize + if buffer + if n_row_separator_chars == 2 and + buffer.end_with?(row_separator[0]) and + line.start_with?(row_separator[1]) + buffer << line[0] + line = line[1..-1] + position += buffer.bytesize + offset + @scanner.pos = position + offset = 0 + yield(buffer) + buffer = nil + next if line.empty? + else + buffer << line + line = buffer + buffer = nil + end + end + if line.end_with?(row_separator) + position += line.bytesize + offset + @scanner.pos = position + offset = 0 + yield(line) + else + buffer = line + end + end + break unless read_chunk + input = @scanner.rest + position = @scanner.pos + offset = -buffer.bytesize if buffer + end + yield(buffer) if buffer + end + + def scan(pattern) + # trace(__method__, pattern, :start) + value = @scanner.scan(pattern) + # trace(__method__, pattern, :done, :last, value) if @last_scanner + return value if @last_scanner + + read_chunk if value and @scanner.eos? + # trace(__method__, pattern, :done, value) + value + end + + def scan_all(pattern) + # trace(__method__, pattern, :start) + value = @scanner.scan(pattern) + # trace(__method__, pattern, :done, :last, value) if @last_scanner + return value if @last_scanner + + # trace(__method__, pattern, :done, :nil) if value.nil? + return nil if value.nil? + while @scanner.eos? and read_chunk and (sub_value = @scanner.scan(pattern)) + # trace(__method__, pattern, :sub, sub_value) + value << sub_value + end + # trace(__method__, pattern, :done, value) + value + end + + def eos? + @scanner.eos? + end + + def keep_start + # trace(__method__, :start) + adjust_last_keep + @keeps.push([@scanner, @scanner.pos, nil]) + # trace(__method__, :done) + end + + def keep_end + # trace(__method__, :start) + scanner, start, buffer = @keeps.pop + if scanner == @scanner + keep = @scanner.string.byteslice(start, @scanner.pos - start) + else + keep = @scanner.string.byteslice(0, @scanner.pos) + end + if buffer + buffer << keep + keep = buffer + end + # trace(__method__, :done, keep) + keep + end + + def keep_back + # trace(__method__, :start) + scanner, start, buffer = @keeps.pop + if buffer + # trace(__method__, :rescan, start, buffer) + string = @scanner.string + if scanner == @scanner + keep = string.byteslice(start, + string.bytesize - @scanner.pos - start) + else + keep = string + end + if keep and not keep.empty? + @inputs.unshift(StringIO.new(keep)) + @last_scanner = false + end + @scanner = StringScanner.new(buffer) + else + if @scanner != scanner + message = "scanners are different but no buffer: " + message += "#{@scanner.inspect}(#{@scanner.object_id}): " + message += "#{scanner.inspect}(#{scanner.object_id})" + raise UnexpectedError, message + end + # trace(__method__, :repos, start, buffer) + @scanner.pos = start + last_scanner, last_start, last_buffer = @keeps.last + # Drop the last buffer when the last buffer is the same data + # in the last keep. If we keep it, we have duplicated data + # by the next keep_back. + if last_scanner == @scanner and + last_buffer and + last_buffer == last_scanner.string.byteslice(last_start, start) + @keeps.last[2] = nil + end + end + read_chunk if @scanner.eos? + end + + def keep_drop + _, _, buffer = @keeps.pop + # trace(__method__, :done, :empty) unless buffer + return unless buffer + + last_keep = @keeps.last + # trace(__method__, :done, :no_last_keep) unless last_keep + return unless last_keep + + if last_keep[2] + last_keep[2] << buffer + else + last_keep[2] = buffer + end + # trace(__method__, :done) + end + + def rest + @scanner.rest + end + + def check(pattern) + @scanner.check(pattern) + end + + private + def trace(*args) + pp([*args, @scanner, @scanner&.string, @scanner&.pos, @keeps]) + end + + def adjust_last_keep + # trace(__method__, :start) + + keep = @keeps.last + # trace(__method__, :done, :empty) if keep.nil? + return if keep.nil? + + scanner, start, buffer = keep + string = @scanner.string + if @scanner != scanner + start = 0 + end + if start == 0 and @scanner.eos? + keep_data = string + else + keep_data = string.byteslice(start, @scanner.pos - start) + end + if keep_data + if buffer + buffer << keep_data + else + keep[2] = keep_data.dup + end + end + + # trace(__method__, :done) + end + + def read_chunk + return false if @last_scanner + + adjust_last_keep + + input = @inputs.first + case input + when StringIO + string = input.read + raise InvalidEncoding unless string.valid_encoding? + # trace(__method__, :stringio, string) + @scanner = StringScanner.new(string) + @inputs.shift + @last_scanner = @inputs.empty? + true + else + chunk = input.gets(@row_separator, @chunk_size) + if chunk + raise InvalidEncoding unless chunk.valid_encoding? + # trace(__method__, :chunk, chunk) + @scanner = StringScanner.new(chunk) + if input.respond_to?(:eof?) and input.eof? + @inputs.shift + @last_scanner = @inputs.empty? + end + true + else + # trace(__method__, :no_chunk) + @scanner = StringScanner.new("".encode(@encoding)) + @inputs.shift + @last_scanner = @inputs.empty? + if @last_scanner + false + else + read_chunk + end + end + end + end + end + + def initialize(input, options) + @input = input + @options = options + @samples = [] + + prepare + end + + def column_separator + @column_separator + end + + def row_separator + @row_separator + end + + def quote_character + @quote_character + end + + def field_size_limit + @max_field_size&.succ + end + + def max_field_size + @max_field_size + end + + def skip_lines + @skip_lines + end + + def unconverted_fields? + @unconverted_fields + end + + def headers + @headers + end + + def header_row? + @use_headers and @headers.nil? + end + + def return_headers? + @return_headers + end + + def skip_blanks? + @skip_blanks + end + + def liberal_parsing? + @liberal_parsing + end + + def lineno + @lineno + end + + def line + last_line + end + + def parse(&block) + return to_enum(__method__) unless block_given? + + if @return_headers and @headers and @raw_headers + headers = Row.new(@headers, @raw_headers, true) + if @unconverted_fields + headers = add_unconverted_fields(headers, []) + end + yield headers + end + + begin + @scanner ||= build_scanner + __send__(@parse_method, &block) + rescue InvalidEncoding + if @scanner + ignore_broken_line + lineno = @lineno + else + lineno = @lineno + 1 + end + raise InvalidEncodingError.new(@encoding, lineno) + rescue UnexpectedError => error + if @scanner + ignore_broken_line + lineno = @lineno + else + lineno = @lineno + 1 + end + message = "This should not be happen: #{error.message}: " + message += "Please report this to https://github.com/ruby/csv/issues" + raise MalformedCSVError.new(message, lineno) + end + end + + def use_headers? + @use_headers + end + + private + # A set of tasks to prepare the file in order to parse it + def prepare + prepare_variable + prepare_quote_character + prepare_backslash + prepare_skip_lines + prepare_strip + prepare_separators + validate_strip_and_col_sep_options + prepare_quoted + prepare_unquoted + prepare_line + prepare_header + prepare_parser + end + + def prepare_variable + @encoding = @options[:encoding] + liberal_parsing = @options[:liberal_parsing] + if liberal_parsing + @liberal_parsing = true + if liberal_parsing.is_a?(Hash) + @double_quote_outside_quote = + liberal_parsing[:double_quote_outside_quote] + @backslash_quote = liberal_parsing[:backslash_quote] + else + @double_quote_outside_quote = false + @backslash_quote = false + end + else + @liberal_parsing = false + @backslash_quote = false + end + @unconverted_fields = @options[:unconverted_fields] + @max_field_size = @options[:max_field_size] + @skip_blanks = @options[:skip_blanks] + @fields_converter = @options[:fields_converter] + @header_fields_converter = @options[:header_fields_converter] + end + + def prepare_quote_character + @quote_character = @options[:quote_character] + if @quote_character.nil? + @escaped_quote_character = nil + @escaped_quote = nil + else + @quote_character = @quote_character.to_s.encode(@encoding) + if @quote_character.length != 1 + message = ":quote_char has to be nil or a single character String" + raise ArgumentError, message + end + @escaped_quote_character = Regexp.escape(@quote_character) + @escaped_quote = Regexp.new(@escaped_quote_character) + end + end + + def prepare_backslash + return unless @backslash_quote + + @backslash_character = "\\".encode(@encoding) + + @escaped_backslash_character = Regexp.escape(@backslash_character) + @escaped_backslash = Regexp.new(@escaped_backslash_character) + if @quote_character.nil? + @backslash_quote_character = nil + else + @backslash_quote_character = + @backslash_character + @escaped_quote_character + end + end + + def prepare_skip_lines + skip_lines = @options[:skip_lines] + case skip_lines + when String + @skip_lines = skip_lines.encode(@encoding) + when Regexp, nil + @skip_lines = skip_lines + else + unless skip_lines.respond_to?(:match) + message = + ":skip_lines has to respond to \#match: #{skip_lines.inspect}" + raise ArgumentError, message + end + @skip_lines = skip_lines + end + end + + def prepare_strip + @strip = @options[:strip] + @escaped_strip = nil + @strip_value = nil + @rstrip_value = nil + if @strip.is_a?(String) + case @strip.length + when 0 + raise ArgumentError, ":strip must not be an empty String" + when 1 + # ok + else + raise ArgumentError, ":strip doesn't support 2 or more characters yet" + end + @strip = @strip.encode(@encoding) + @escaped_strip = Regexp.escape(@strip) + if @quote_character + @strip_value = Regexp.new(@escaped_strip + + "+".encode(@encoding)) + @rstrip_value = Regexp.new(@escaped_strip + + "+\\z".encode(@encoding)) + end + elsif @strip + strip_values = " \t\f\v" + @escaped_strip = strip_values.encode(@encoding) + if @quote_character + @strip_value = Regexp.new("[#{strip_values}]+".encode(@encoding)) + @rstrip_value = Regexp.new("[#{strip_values}]+\\z".encode(@encoding)) + end + end + end + + begin + StringScanner.new("x").scan("x") + rescue TypeError + STRING_SCANNER_SCAN_ACCEPT_STRING = false + else + STRING_SCANNER_SCAN_ACCEPT_STRING = true + end + + def prepare_separators + column_separator = @options[:column_separator] + @column_separator = column_separator.to_s.encode(@encoding) + if @column_separator.size < 1 + message = ":col_sep must be 1 or more characters: " + message += column_separator.inspect + raise ArgumentError, message + end + @row_separator = + resolve_row_separator(@options[:row_separator]).encode(@encoding) + + @escaped_column_separator = Regexp.escape(@column_separator) + @escaped_first_column_separator = Regexp.escape(@column_separator[0]) + if @column_separator.size > 1 + @column_end = Regexp.new(@escaped_column_separator) + @column_ends = @column_separator.each_char.collect do |char| + Regexp.new(Regexp.escape(char)) + end + @first_column_separators = Regexp.new(@escaped_first_column_separator + + "+".encode(@encoding)) + else + if STRING_SCANNER_SCAN_ACCEPT_STRING + @column_end = @column_separator + else + @column_end = Regexp.new(@escaped_column_separator) + end + @column_ends = nil + @first_column_separators = nil + end + + escaped_row_separator = Regexp.escape(@row_separator) + @row_end = Regexp.new(escaped_row_separator) + if @row_separator.size > 1 + @row_ends = @row_separator.each_char.collect do |char| + Regexp.new(Regexp.escape(char)) + end + else + @row_ends = nil + end + + @cr = "\r".encode(@encoding) + @lf = "\n".encode(@encoding) + @line_end = Regexp.new("\r\n|\n|\r".encode(@encoding)) + @not_line_end = Regexp.new("[^\r\n]+".encode(@encoding)) + end + + # This method verifies that there are no (obvious) ambiguities with the + # provided +col_sep+ and +strip+ parsing options. For example, if +col_sep+ + # and +strip+ were both equal to +\t+, then there would be no clear way to + # parse the input. + def validate_strip_and_col_sep_options + return unless @strip + + if @strip.is_a?(String) + if @column_separator.start_with?(@strip) || @column_separator.end_with?(@strip) + raise ArgumentError, + "The provided strip (#{@escaped_strip}) and " \ + "col_sep (#{@escaped_column_separator}) options are incompatible." + end + else + if Regexp.new("\\A[#{@escaped_strip}]|[#{@escaped_strip}]\\z").match?(@column_separator) + raise ArgumentError, + "The provided strip (true) and " \ + "col_sep (#{@escaped_column_separator}) options are incompatible." + end + end + end + + def prepare_quoted + if @quote_character + @quotes = Regexp.new(@escaped_quote_character + + "+".encode(@encoding)) + no_quoted_values = @escaped_quote_character.dup + if @backslash_quote + no_quoted_values << @escaped_backslash_character + end + @quoted_value = Regexp.new("[^".encode(@encoding) + + no_quoted_values + + "]+".encode(@encoding)) + end + if @escaped_strip + @split_column_separator = Regexp.new(@escaped_strip + + "*".encode(@encoding) + + @escaped_column_separator + + @escaped_strip + + "*".encode(@encoding)) + else + if @column_separator == " ".encode(@encoding) + @split_column_separator = Regexp.new(@escaped_column_separator) + else + @split_column_separator = @column_separator + end + end + end + + def prepare_unquoted + return if @quote_character.nil? + + no_unquoted_values = "\r\n".encode(@encoding) + no_unquoted_values << @escaped_first_column_separator + unless @liberal_parsing + no_unquoted_values << @escaped_quote_character + end + @unquoted_value = Regexp.new("[^".encode(@encoding) + + no_unquoted_values + + "]+".encode(@encoding)) + end + + def resolve_row_separator(separator) + if separator == :auto + cr = "\r".encode(@encoding) + lf = "\n".encode(@encoding) + if @input.is_a?(StringIO) + pos = @input.pos + separator = detect_row_separator(@input.read, cr, lf) + @input.seek(pos) + elsif @input.respond_to?(:gets) + if @input.is_a?(File) + chunk_size = 32 * 1024 + else + chunk_size = 1024 + end + begin + while separator == :auto + # + # if we run out of data, it's probably a single line + # (ensure will set default value) + # + break unless sample = @input.gets(nil, chunk_size) + + # extend sample if we're unsure of the line ending + if sample.end_with?(cr) + sample << (@input.gets(nil, 1) || "") + end + + @samples << sample + + separator = detect_row_separator(sample, cr, lf) + end + rescue IOError + # do nothing: ensure will set default + end + end + separator = InputRecordSeparator.value if separator == :auto + end + separator.to_s.encode(@encoding) + end + + def detect_row_separator(sample, cr, lf) + lf_index = sample.index(lf) + if lf_index + cr_index = sample[0, lf_index].index(cr) + else + cr_index = sample.index(cr) + end + if cr_index and lf_index + if cr_index + 1 == lf_index + cr + lf + elsif cr_index < lf_index + cr + else + lf + end + elsif cr_index + cr + elsif lf_index + lf + else + :auto + end + end + + def prepare_line + @lineno = 0 + @last_line = nil + @scanner = nil + end + + def last_line + if @scanner + @last_line ||= @scanner.keep_end + else + @last_line + end + end + + def prepare_header + @return_headers = @options[:return_headers] + + headers = @options[:headers] + case headers + when Array + @raw_headers = headers + quoted_fields = FieldsConverter::NO_QUOTED_FIELDS + @use_headers = true + when String + @raw_headers, quoted_fields = parse_headers(headers) + @use_headers = true + when nil, false + @raw_headers = nil + @use_headers = false + else + @raw_headers = nil + @use_headers = true + end + if @raw_headers + @headers = adjust_headers(@raw_headers, quoted_fields) + else + @headers = nil + end + end + + def parse_headers(row) + quoted_fields = [] + converter = lambda do |field, info| + quoted_fields << info.quoted? + field + end + headers = CSV.parse_line(row, + col_sep: @column_separator, + row_sep: @row_separator, + quote_char: @quote_character, + converters: [converter]) + [headers, quoted_fields] + end + + def adjust_headers(headers, quoted_fields) + adjusted_headers = @header_fields_converter.convert(headers, nil, @lineno, quoted_fields) + adjusted_headers.each {|h| h.freeze if h.is_a? String} + adjusted_headers + end + + def prepare_parser + @may_quoted = may_quoted? + if @quote_character.nil? + @parse_method = :parse_no_quote + elsif @liberal_parsing or @strip + @parse_method = :parse_quotable_robust + else + @parse_method = :parse_quotable_loose + end + end + + def may_quoted? + return false if @quote_character.nil? + + if @input.is_a?(StringIO) + pos = @input.pos + sample = @input.read + @input.seek(pos) + else + return false if @samples.empty? + sample = @samples.first + end + sample[0, 128].index(@quote_character) + end + + class UnoptimizedStringIO # :nodoc: + def initialize(string) + @io = StringIO.new(string, "rb:#{string.encoding}") + end + + def gets(*args) + @io.gets(*args) + end + + def each_line(*args, &block) + @io.each_line(*args, &block) + end + + def eof? + @io.eof? + end + end + + SCANNER_TEST = (ENV["CSV_PARSER_SCANNER_TEST"] == "yes") + if SCANNER_TEST + SCANNER_TEST_CHUNK_SIZE_NAME = "CSV_PARSER_SCANNER_TEST_CHUNK_SIZE" + SCANNER_TEST_CHUNK_SIZE_VALUE = ENV[SCANNER_TEST_CHUNK_SIZE_NAME] + def build_scanner + inputs = @samples.collect do |sample| + UnoptimizedStringIO.new(sample) + end + if @input.is_a?(StringIO) + inputs << UnoptimizedStringIO.new(@input.read) + else + inputs << @input + end + begin + chunk_size_value = ENV[SCANNER_TEST_CHUNK_SIZE_NAME] + rescue # Ractor::IsolationError + # Ractor on Ruby 3.0 can't read ENV value. + chunk_size_value = SCANNER_TEST_CHUNK_SIZE_VALUE + end + chunk_size = Integer((chunk_size_value || "1"), 10) + InputsScanner.new(inputs, + @encoding, + @row_separator, + chunk_size: chunk_size) + end + else + def build_scanner + string = nil + if @samples.empty? and @input.is_a?(StringIO) + string = @input.read + elsif @samples.size == 1 and + @input != ARGF and + @input.respond_to?(:eof?) and + @input.eof? + string = @samples[0] + end + if string + unless string.valid_encoding? + index = string.lines(@row_separator).index do |line| + !line.valid_encoding? + end + if index + raise InvalidEncodingError.new(@encoding, @lineno + index + 1) + end + end + Scanner.new(string) + else + inputs = @samples.collect do |sample| + StringIO.new(sample) + end + inputs << @input + InputsScanner.new(inputs, @encoding, @row_separator) + end + end + end + + def skip_needless_lines + return unless @skip_lines + + until @scanner.eos? + @scanner.keep_start + line = @scanner.scan_all(@not_line_end) || "".encode(@encoding) + line << @row_separator if parse_row_end + if skip_line?(line) + @lineno += 1 + @scanner.keep_drop + else + @scanner.keep_back + return + end + end + end + + def skip_line?(line) + line = line.delete_suffix(@row_separator) + case @skip_lines + when String + line.include?(@skip_lines) + when Regexp + @skip_lines.match?(line) + else + @skip_lines.match(line) + end + end + + def validate_field_size(field) + return unless @max_field_size + return if field.size <= @max_field_size + ignore_broken_line + message = "Field size exceeded: #{field.size} > #{@max_field_size}" + raise MalformedCSVError.new(message, @lineno) + end + + def parse_no_quote(&block) + @scanner.each_line(@row_separator) do |line| + next if @skip_lines and skip_line?(line) + original_line = line + line = line.delete_suffix(@row_separator) + + if line.empty? + next if @skip_blanks + row = [] + else + line = strip_value(line) + row = line.split(@split_column_separator, -1) + if @max_field_size + row.each do |column| + validate_field_size(column) + end + end + n_columns = row.size + i = 0 + while i < n_columns + row[i] = nil if row[i].empty? + i += 1 + end + end + @last_line = original_line + emit_row(row, &block) + end + end + + def parse_quotable_loose(&block) + @scanner.keep_start + @scanner.each_line(@row_separator) do |line| + if @skip_lines and skip_line?(line) + @scanner.keep_drop + @scanner.keep_start + next + end + original_line = line + line = line.delete_suffix(@row_separator) + + if line.empty? + if @skip_blanks + @scanner.keep_drop + @scanner.keep_start + next + end + row = [] + quoted_fields = FieldsConverter::NO_QUOTED_FIELDS + elsif line.include?(@cr) or line.include?(@lf) + @scanner.keep_back + @parse_method = :parse_quotable_robust + return parse_quotable_robust(&block) + else + row = line.split(@split_column_separator, -1) + quoted_fields = [] + n_columns = row.size + i = 0 + while i < n_columns + column = row[i] + if column.empty? + quoted_fields << false + row[i] = nil + else + n_quotes = column.count(@quote_character) + if n_quotes.zero? + quoted_fields << false + # no quote + elsif n_quotes == 2 and + column.start_with?(@quote_character) and + column.end_with?(@quote_character) + quoted_fields << true + row[i] = column[1..-2] + else + @scanner.keep_back + @parse_method = :parse_quotable_robust + return parse_quotable_robust(&block) + end + validate_field_size(row[i]) + end + i += 1 + end + end + @scanner.keep_drop + @scanner.keep_start + @last_line = original_line + emit_row(row, quoted_fields, &block) + end + @scanner.keep_drop + end + + def parse_quotable_robust(&block) + row = [] + quoted_fields = [] + skip_needless_lines + start_row + while true + @quoted_column_value = false + @unquoted_column_value = false + @scanner.scan_all(@strip_value) if @strip_value + value = parse_column_value + if value + @scanner.scan_all(@strip_value) if @strip_value + validate_field_size(value) + end + if parse_column_end + row << value + quoted_fields << @quoted_column_value + elsif parse_row_end + if row.empty? and value.nil? + emit_row([], &block) unless @skip_blanks + else + row << value + quoted_fields << @quoted_column_value + emit_row(row, quoted_fields, &block) + row = [] + quoted_fields.clear + end + skip_needless_lines + start_row + elsif @scanner.eos? + break if row.empty? and value.nil? + row << value + quoted_fields << @quoted_column_value + emit_row(row, quoted_fields, &block) + break + else + if @quoted_column_value + if liberal_parsing? and (new_line = @scanner.check(@line_end)) + message = + "Illegal end-of-line sequence outside of a quoted field " + + "<#{new_line.inspect}>" + else + message = "Any value after quoted field isn't allowed" + end + ignore_broken_line + raise MalformedCSVError.new(message, @lineno) + elsif @unquoted_column_value and + (new_line = @scanner.scan(@line_end)) + ignore_broken_line + message = "Unquoted fields do not allow new line " + + "<#{new_line.inspect}>" + raise MalformedCSVError.new(message, @lineno) + elsif @scanner.rest.start_with?(@quote_character) + ignore_broken_line + message = "Illegal quoting" + raise MalformedCSVError.new(message, @lineno) + elsif (new_line = @scanner.scan(@line_end)) + ignore_broken_line + message = "New line must be <#{@row_separator.inspect}> " + + "not <#{new_line.inspect}>" + raise MalformedCSVError.new(message, @lineno) + else + ignore_broken_line + raise MalformedCSVError.new("TODO: Meaningful message", + @lineno) + end + end + end + end + + def parse_column_value + if @liberal_parsing + quoted_value = parse_quoted_column_value + if quoted_value + @scanner.scan_all(@strip_value) if @strip_value + unquoted_value = parse_unquoted_column_value + if unquoted_value + if @double_quote_outside_quote + unquoted_value = unquoted_value.gsub(@quote_character * 2, + @quote_character) + if quoted_value.empty? # %Q{""...} case + return @quote_character + unquoted_value + end + end + @quote_character + quoted_value + @quote_character + unquoted_value + else + quoted_value + end + else + parse_unquoted_column_value + end + elsif @may_quoted + parse_quoted_column_value || + parse_unquoted_column_value + else + parse_unquoted_column_value || + parse_quoted_column_value + end + end + + def parse_unquoted_column_value + value = @scanner.scan_all(@unquoted_value) + return nil unless value + + @unquoted_column_value = true + if @first_column_separators + while true + @scanner.keep_start + is_column_end = @column_ends.all? do |column_end| + @scanner.scan(column_end) + end + @scanner.keep_back + break if is_column_end + sub_separator = @scanner.scan_all(@first_column_separators) + break if sub_separator.nil? + value << sub_separator + sub_value = @scanner.scan_all(@unquoted_value) + break if sub_value.nil? + value << sub_value + end + end + value.gsub!(@backslash_quote_character, @quote_character) if @backslash_quote + if @rstrip_value + value.gsub!(@rstrip_value, "") + end + value + end + + def parse_quoted_column_value + quotes = @scanner.scan_all(@quotes) + return nil unless quotes + + @quoted_column_value = true + n_quotes = quotes.size + if (n_quotes % 2).zero? + quotes[0, (n_quotes - 2) / 2] + else + value = quotes[0, n_quotes / 2] + while true + quoted_value = @scanner.scan_all(@quoted_value) + value << quoted_value if quoted_value + if @backslash_quote + if @scanner.scan(@escaped_backslash) + if @scanner.scan(@escaped_quote) + value << @quote_character + else + value << @backslash_character + end + next + end + end + + quotes = @scanner.scan_all(@quotes) + unless quotes + ignore_broken_line + message = "Unclosed quoted field" + raise MalformedCSVError.new(message, @lineno) + end + n_quotes = quotes.size + if n_quotes == 1 + break + else + value << quotes[0, n_quotes / 2] + break if (n_quotes % 2) == 1 + end + end + value + end + end + + def parse_column_end + return true if @scanner.scan(@column_end) + return false unless @column_ends + + @scanner.keep_start + if @column_ends.all? {|column_end| @scanner.scan(column_end)} + @scanner.keep_drop + true + else + @scanner.keep_back + false + end + end + + def parse_row_end + return true if @scanner.scan(@row_end) + return false unless @row_ends + @scanner.keep_start + if @row_ends.all? {|row_end| @scanner.scan(row_end)} + @scanner.keep_drop + true + else + @scanner.keep_back + false + end + end + + def strip_value(value) + return value unless @strip + return value if value.nil? + + case @strip + when String + while value.delete_prefix!(@strip) + # do nothing + end + while value.delete_suffix!(@strip) + # do nothing + end + else + value.strip! + end + value + end + + def ignore_broken_line + @scanner.scan_all(@not_line_end) + @scanner.scan_all(@line_end) + @lineno += 1 + end + + def start_row + if @last_line + @last_line = nil + else + @scanner.keep_drop + end + @scanner.keep_start + end + + def emit_row(row, quoted_fields=FieldsConverter::NO_QUOTED_FIELDS, &block) + @lineno += 1 + + raw_row = row + if @use_headers + if @headers.nil? + @headers = adjust_headers(row, quoted_fields) + return unless @return_headers + row = Row.new(@headers, row, true) + else + row = Row.new(@headers, + @fields_converter.convert(raw_row, @headers, @lineno, quoted_fields)) + end + else + # convert fields, if needed... + row = @fields_converter.convert(raw_row, nil, @lineno, quoted_fields) + end + + # inject unconverted fields and accessor, if requested... + if @unconverted_fields and not row.respond_to?(:unconverted_fields) + add_unconverted_fields(row, raw_row) + end + + yield(row) + end + + # This method injects an instance variable unconverted_fields into + # +row+ and an accessor method for +row+ called unconverted_fields(). The + # variable is set to the contents of +fields+. + def add_unconverted_fields(row, fields) + class << row + attr_reader :unconverted_fields + end + row.instance_variable_set(:@unconverted_fields, fields) + row + end + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/row.rb b/bin/gems/csv-3.3.2/lib/csv/row.rb new file mode 100644 index 00000000..86323f7d --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/row.rb @@ -0,0 +1,757 @@ +# frozen_string_literal: true + +require "forwardable" + +class CSV + # = \CSV::Row + # A \CSV::Row instance represents a \CSV table row. + # (see {class CSV}[../CSV.html]). + # + # The instance may have: + # - Fields: each is an object, not necessarily a \String. + # - Headers: each serves a key, and also need not be a \String. + # + # === Instance Methods + # + # \CSV::Row has three groups of instance methods: + # - Its own internally defined instance methods. + # - Methods included by module Enumerable. + # - Methods delegated to class Array.: + # * Array#empty? + # * Array#length + # * Array#size + # + # == Creating a \CSV::Row Instance + # + # Commonly, a new \CSV::Row instance is created by parsing \CSV source + # that has headers: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.each {|row| p row } + # Output: + # # + # # + # # + # + # You can also create a row directly. See ::new. + # + # == Headers + # + # Like a \CSV::Table, a \CSV::Row has headers. + # + # A \CSV::Row that was created by parsing \CSV source + # inherits its headers from the table: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table.first + # row.headers # => ["Name", "Value"] + # + # You can also create a new row with headers; + # like the keys in a \Hash, the headers need not be Strings: + # row = CSV::Row.new([:name, :value], ['foo', 0]) + # row.headers # => [:name, :value] + # + # The new row retains its headers even if added to a table + # that has headers: + # table << row # => # + # row.headers # => [:name, :value] + # row[:name] # => "foo" + # row['Name'] # => nil + # + # + # + # == Accessing Fields + # + # You may access a field in a \CSV::Row with either its \Integer index + # (\Array-style) or its header (\Hash-style). + # + # Fetch a field using method #[]: + # row = CSV::Row.new(['Name', 'Value'], ['foo', 0]) + # row[1] # => 0 + # row['Value'] # => 0 + # + # Set a field using method #[]=: + # row = CSV::Row.new(['Name', 'Value'], ['foo', 0]) + # row # => # + # row[0] = 'bar' + # row['Value'] = 1 + # row # => # + # + class Row + # :call-seq: + # CSV::Row.new(headers, fields, header_row = false) -> csv_row + # + # Returns the new \CSV::Row instance constructed from + # arguments +headers+ and +fields+; both should be Arrays; + # note that the fields need not be Strings: + # row = CSV::Row.new(['Name', 'Value'], ['foo', 0]) + # row # => # + # + # If the \Array lengths are different, the shorter is +nil+-filled: + # row = CSV::Row.new(['Name', 'Value', 'Date', 'Size'], ['foo', 0]) + # row # => # + # + # Each \CSV::Row object is either a field row or a header row; + # by default, a new row is a field row; for the row created above: + # row.field_row? # => true + # row.header_row? # => false + # + # If the optional argument +header_row+ is given as +true+, + # the created row is a header row: + # row = CSV::Row.new(['Name', 'Value'], ['foo', 0], header_row = true) + # row # => # + # row.field_row? # => false + # row.header_row? # => true + def initialize(headers, fields, header_row = false) + @header_row = header_row + headers.each { |h| h.freeze if h.is_a? String } + + # handle extra headers or fields + @row = if headers.size >= fields.size + headers.zip(fields) + else + fields.zip(headers).each(&:reverse!) + end + end + + # Internal data format used to compare equality. + attr_reader :row + protected :row + + ### Array Delegation ### + + extend Forwardable + def_delegators :@row, :empty?, :length, :size + + # :call-seq: + # row.initialize_copy(other_row) -> self + # + # Calls superclass method. + def initialize_copy(other) + super_return_value = super + @row = @row.collect(&:dup) + super_return_value + end + + # :call-seq: + # row.header_row? -> true or false + # + # Returns +true+ if this is a header row, +false+ otherwise. + def header_row? + @header_row + end + + # :call-seq: + # row.field_row? -> true or false + # + # Returns +true+ if this is a field row, +false+ otherwise. + def field_row? + not header_row? + end + + # :call-seq: + # row.headers -> array_of_headers + # + # Returns the headers for this row: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table.first + # row.headers # => ["Name", "Value"] + def headers + @row.map(&:first) + end + + # :call-seq: + # field(index) -> value + # field(header) -> value + # field(header, offset) -> value + # + # Returns the field value for the given +index+ or +header+. + # + # --- + # + # Fetch field value by \Integer index: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.field(0) # => "foo" + # row.field(1) # => "bar" + # + # Counts backward from the last column if +index+ is negative: + # row.field(-1) # => "0" + # row.field(-2) # => "foo" + # + # Returns +nil+ if +index+ is out of range: + # row.field(2) # => nil + # row.field(-3) # => nil + # + # --- + # + # Fetch field value by header (first found): + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.field('Name') # => "Foo" + # + # Fetch field value by header, ignoring +offset+ leading fields: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.field('Name', 2) # => "Baz" + # + # Returns +nil+ if the header does not exist. + def field(header_or_index, minimum_index = 0) + # locate the pair + finder = (header_or_index.is_a?(Integer) || header_or_index.is_a?(Range)) ? :[] : :assoc + pair = @row[minimum_index..-1].public_send(finder, header_or_index) + + # return the field if we have a pair + if pair.nil? + nil + else + header_or_index.is_a?(Range) ? pair.map(&:last) : pair.last + end + end + alias_method :[], :field + + # + # :call-seq: + # fetch(header) -> value + # fetch(header, default) -> value + # fetch(header) {|row| ... } -> value + # + # Returns the field value as specified by +header+. + # + # --- + # + # With the single argument +header+, returns the field value + # for that header (first found): + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.fetch('Name') # => "Foo" + # + # Raises exception +KeyError+ if the header does not exist. + # + # --- + # + # With arguments +header+ and +default+ given, + # returns the field value for the header (first found) + # if the header exists, otherwise returns +default+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.fetch('Name', '') # => "Foo" + # row.fetch(:nosuch, '') # => "" + # + # --- + # + # With argument +header+ and a block given, + # returns the field value for the header (first found) + # if the header exists; otherwise calls the block + # and returns its return value: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.fetch('Name') {|header| fail 'Cannot happen' } # => "Foo" + # row.fetch(:nosuch) {|header| "Header '#{header} not found'" } # => "Header 'nosuch not found'" + def fetch(header, *varargs) + raise ArgumentError, "Too many arguments" if varargs.length > 1 + pair = @row.assoc(header) + if pair + pair.last + else + if block_given? + yield header + elsif varargs.empty? + raise KeyError, "key not found: #{header}" + else + varargs.first + end + end + end + + # :call-seq: + # row.has_key?(header) -> true or false + # + # Returns +true+ if there is a field with the given +header+, + # +false+ otherwise. + def has_key?(header) + !!@row.assoc(header) + end + alias_method :include?, :has_key? + alias_method :key?, :has_key? + alias_method :member?, :has_key? + alias_method :header?, :has_key? + + # + # :call-seq: + # row[index] = value -> value + # row[header, offset] = value -> value + # row[header] = value -> value + # + # Assigns the field value for the given +index+ or +header+; + # returns +value+. + # + # --- + # + # Assign field value by \Integer index: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row[0] = 'Bat' + # row[1] = 3 + # row # => # + # + # Counts backward from the last column if +index+ is negative: + # row[-1] = 4 + # row[-2] = 'Bam' + # row # => # + # + # Extends the row with nil:nil if positive +index+ is not in the row: + # row[4] = 5 + # row # => # + # + # Raises IndexError if negative +index+ is too small (too far from zero). + # + # --- + # + # Assign field value by header (first found): + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row['Name'] = 'Bat' + # row # => # + # + # Assign field value by header, ignoring +offset+ leading fields: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row['Name', 2] = 4 + # row # => # + # + # Append new field by (new) header: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row['New'] = 6 + # row# => # + def []=(*args) + value = args.pop + + if args.first.is_a? Integer + if @row[args.first].nil? # extending past the end with index + @row[args.first] = [nil, value] + @row.map! { |pair| pair.nil? ? [nil, nil] : pair } + else # normal index assignment + @row[args.first][1] = value + end + else + index = index(*args) + if index.nil? # appending a field + self << [args.first, value] + else # normal header assignment + @row[index][1] = value + end + end + end + + # + # :call-seq: + # row << [header, value] -> self + # row << hash -> self + # row << value -> self + # + # Adds a field to +self+; returns +self+: + # + # If the argument is a 2-element \Array [header, value], + # a field is added with the given +header+ and +value+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row << ['NAME', 'Bat'] + # row # => # + # + # If the argument is a \Hash, each key-value pair is added + # as a field with header +key+ and value +value+. + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row << {NAME: 'Bat', name: 'Bam'} + # row # => # + # + # Otherwise, the given +value+ is added as a field with no header. + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row << 'Bag' + # row # => # + def <<(arg) + if arg.is_a?(Array) and arg.size == 2 # appending a header and name + @row << arg + elsif arg.is_a?(Hash) # append header and name pairs + arg.each { |pair| @row << pair } + else # append field value + @row << [nil, arg] + end + + self # for chaining + end + + # :call-seq: + # row.push(*values) -> self + # + # Appends each of the given +values+ to +self+ as a field; returns +self+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.push('Bat', 'Bam') + # row # => # + def push(*args) + args.each { |arg| self << arg } + + self # for chaining + end + + # + # :call-seq: + # delete(index) -> [header, value] or nil + # delete(header) -> [header, value] or empty_array + # delete(header, offset) -> [header, value] or empty_array + # + # Removes a specified field from +self+; returns the 2-element \Array + # [header, value] if the field exists. + # + # If an \Integer argument +index+ is given, + # removes and returns the field at offset +index+, + # or returns +nil+ if the field does not exist: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.delete(1) # => ["Name", "Bar"] + # row.delete(50) # => nil + # + # Otherwise, if the single argument +header+ is given, + # removes and returns the first-found field with the given header, + # of returns a new empty \Array if the field does not exist: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.delete('Name') # => ["Name", "Foo"] + # row.delete('NAME') # => [] + # + # If argument +header+ and \Integer argument +offset+ are given, + # removes and returns the first-found field with the given header + # whose +index+ is at least as large as +offset+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.delete('Name', 1) # => ["Name", "Bar"] + # row.delete('NAME', 1) # => [] + def delete(header_or_index, minimum_index = 0) + if header_or_index.is_a? Integer # by index + @row.delete_at(header_or_index) + elsif i = index(header_or_index, minimum_index) # by header + @row.delete_at(i) + else + [ ] + end + end + + # :call-seq: + # row.delete_if {|header, value| ... } -> self + # + # Removes fields from +self+ as selected by the block; returns +self+. + # + # Removes each field for which the block returns a truthy value: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.delete_if {|header, value| value.start_with?('B') } # => true + # row # => # + # row.delete_if {|header, value| header.start_with?('B') } # => false + # + # If no block is given, returns a new Enumerator: + # row.delete_if # => #:delete_if> + def delete_if(&block) + return enum_for(__method__) { size } unless block_given? + + @row.delete_if(&block) + + self # for chaining + end + + # :call-seq: + # self.fields(*specifiers) -> array_of_fields + # + # Returns field values per the given +specifiers+, which may be any mixture of: + # - \Integer index. + # - \Range of \Integer indexes. + # - 2-element \Array containing a header and offset. + # - Header. + # - \Range of headers. + # + # For +specifier+ in one of the first four cases above, + # returns the result of self.field(specifier); see #field. + # + # Although there may be any number of +specifiers+, + # the examples here will illustrate one at a time. + # + # When the specifier is an \Integer +index+, + # returns self.field(index)L + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.fields(1) # => ["Bar"] + # + # When the specifier is a \Range of \Integers +range+, + # returns self.field(range): + # row.fields(1..2) # => ["Bar", "Baz"] + # + # When the specifier is a 2-element \Array +array+, + # returns self.field(array)L + # row.fields('Name', 1) # => ["Foo", "Bar"] + # + # When the specifier is a header +header+, + # returns self.field(header)L + # row.fields('Name') # => ["Foo"] + # + # When the specifier is a \Range of headers +range+, + # forms a new \Range +new_range+ from the indexes of + # range.start and range.end, + # and returns self.field(new_range): + # source = "Name,NAME,name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.fields('Name'..'NAME') # => ["Foo", "Bar"] + # + # Returns all fields if no argument given: + # row.fields # => ["Foo", "Bar", "Baz"] + def fields(*headers_and_or_indices) + if headers_and_or_indices.empty? # return all fields--no arguments + @row.map(&:last) + else # or work like values_at() + all = [] + headers_and_or_indices.each do |h_or_i| + if h_or_i.is_a? Range + index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin : + index(h_or_i.begin) + index_end = h_or_i.end.is_a?(Integer) ? h_or_i.end : + index(h_or_i.end) + new_range = h_or_i.exclude_end? ? (index_begin...index_end) : + (index_begin..index_end) + all.concat(fields.values_at(new_range)) + else + all << field(*Array(h_or_i)) + end + end + return all + end + end + alias_method :values_at, :fields + + # :call-seq: + # index(header) -> index + # index(header, offset) -> index + # + # Returns the index for the given header, if it exists; + # otherwise returns +nil+. + # + # With the single argument +header+, returns the index + # of the first-found field with the given +header+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.index('Name') # => 0 + # row.index('NAME') # => nil + # + # With arguments +header+ and +offset+, + # returns the index of the first-found field with given +header+, + # but ignoring the first +offset+ fields: + # row.index('Name', 1) # => 1 + # row.index('Name', 3) # => nil + def index(header, minimum_index = 0) + # find the pair + index = headers[minimum_index..-1].index(header) + # return the index at the right offset, if we found one + index.nil? ? nil : index + minimum_index + end + + # :call-seq: + # row.field?(value) -> true or false + # + # Returns +true+ if +value+ is a field in this row, +false+ otherwise: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.field?('Bar') # => true + # row.field?('BAR') # => false + def field?(data) + fields.include? data + end + + include Enumerable + + # :call-seq: + # row.each {|header, value| ... } -> self + # + # Calls the block with each header-value pair; returns +self+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.each {|header, value| p [header, value] } + # Output: + # ["Name", "Foo"] + # ["Name", "Bar"] + # ["Name", "Baz"] + # + # If no block is given, returns a new Enumerator: + # row.each # => #:each> + def each(&block) + return enum_for(__method__) { size } unless block_given? + + @row.each(&block) + + self # for chaining + end + + alias_method :each_pair, :each + + # :call-seq: + # row == other -> true or false + # + # Returns +true+ if +other+ is a /CSV::Row that has the same + # fields (headers and values) in the same order as +self+; + # otherwise returns +false+: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # other_row = table[0] + # row == other_row # => true + # other_row = table[1] + # row == other_row # => false + def ==(other) + return @row == other.row if other.is_a? CSV::Row + @row == other + end + + # :call-seq: + # row.to_h -> hash + # + # Returns the new \Hash formed by adding each header-value pair in +self+ + # as a key-value pair in the \Hash. + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.to_h # => {"Name"=>"foo", "Value"=>"0"} + # + # Header order is preserved, but repeated headers are ignored: + # source = "Name,Name,Name\nFoo,Bar,Baz\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.to_h # => {"Name"=>"Foo"} + def to_h + hash = {} + each do |key, _value| + hash[key] = self[key] unless hash.key?(key) + end + hash + end + alias_method :to_hash, :to_h + + # :call-seq: + # row.deconstruct_keys(keys) -> hash + # + # Returns the new \Hash suitable for pattern matching containing only the + # keys specified as an argument. + def deconstruct_keys(keys) + if keys.nil? + to_h + else + keys.to_h { |key| [key, self[key]] } + end + end + + alias_method :to_ary, :to_a + + # :call-seq: + # row.deconstruct -> array + # + # Returns the new \Array suitable for pattern matching containing the values + # of the row. + def deconstruct + fields + end + + # :call-seq: + # row.to_csv -> csv_string + # + # Returns the row as a \CSV String. Headers are not included: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.to_csv # => "foo,0\n" + def to_csv(**options) + fields.to_csv(**options) + end + alias_method :to_s, :to_csv + + # :call-seq: + # row.dig(index_or_header, *identifiers) -> object + # + # Finds and returns the object in nested object that is specified + # by +index_or_header+ and +specifiers+. + # + # The nested objects may be instances of various classes. + # See {Dig Methods}[rdoc-ref:dig_methods.rdoc]. + # + # Examples: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.dig(1) # => "0" + # row.dig('Value') # => "0" + # row.dig(5) # => nil + def dig(index_or_header, *indexes) + value = field(index_or_header) + if value.nil? + nil + elsif indexes.empty? + value + else + unless value.respond_to?(:dig) + raise TypeError, "#{value.class} does not have \#dig method" + end + value.dig(*indexes) + end + end + + # :call-seq: + # row.inspect -> string + # + # Returns an ASCII-compatible \String showing: + # - Class \CSV::Row. + # - Header-value pairs. + # Example: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # row = table[0] + # row.inspect # => "#" + def inspect + str = ["#<", self.class.to_s] + each do |header, field| + str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) << + ":" << field.inspect + end + str << ">" + begin + str.join('') + rescue # any encoding error + str.map do |s| + e = Encoding::Converter.asciicompat_encoding(s.encoding) + e ? s.encode(e) : s.force_encoding("ASCII-8BIT") + end.join('') + end + end + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/table.rb b/bin/gems/csv-3.3.2/lib/csv/table.rb new file mode 100644 index 00000000..fb19f545 --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/table.rb @@ -0,0 +1,1055 @@ +# frozen_string_literal: true + +require "forwardable" + +class CSV + # = \CSV::Table + # A \CSV::Table instance represents \CSV data. + # (see {class CSV}[../CSV.html]). + # + # The instance may have: + # - Rows: each is a Table::Row object. + # - Headers: names for the columns. + # + # === Instance Methods + # + # \CSV::Table has three groups of instance methods: + # - Its own internally defined instance methods. + # - Methods included by module Enumerable. + # - Methods delegated to class Array.: + # * Array#empty? + # * Array#length + # * Array#size + # + # == Creating a \CSV::Table Instance + # + # Commonly, a new \CSV::Table instance is created by parsing \CSV source + # using headers: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.class # => CSV::Table + # + # You can also create an instance directly. See ::new. + # + # == Headers + # + # If a table has headers, the headers serve as labels for the columns of data. + # Each header serves as the label for its column. + # + # The headers for a \CSV::Table object are stored as an \Array of Strings. + # + # Commonly, headers are defined in the first row of \CSV source: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.headers # => ["Name", "Value"] + # + # If no headers are defined, the \Array is empty: + # table = CSV::Table.new([]) + # table.headers # => [] + # + # == Access Modes + # + # \CSV::Table provides three modes for accessing table data: + # - \Row mode. + # - Column mode. + # - Mixed mode (the default for a new table). + # + # The access mode for a\CSV::Table instance affects the behavior + # of some of its instance methods: + # - #[] + # - #[]= + # - #delete + # - #delete_if + # - #each + # - #values_at + # + # === \Row Mode + # + # Set a table to row mode with method #by_row!: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_row! # => # + # + # Specify a single row by an \Integer index: + # # Get a row. + # table[1] # => # + # # Set a row, then get it. + # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3]) + # table[1] # => # + # + # Specify a sequence of rows by a \Range: + # # Get rows. + # table[1..2] # => [#, #] + # # Set rows, then get them. + # table[1..2] = [ + # CSV::Row.new(['Name', 'Value'], ['bat', 4]), + # CSV::Row.new(['Name', 'Value'], ['bad', 5]), + # ] + # table[1..2] # => [["Name", #], ["Value", #]] + # + # === Column Mode + # + # Set a table to column mode with method #by_col!: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col! # => # + # + # Specify a column by an \Integer index: + # # Get a column. + # table[0] + # # Set a column, then get it. + # table[0] = ['FOO', 'BAR', 'BAZ'] + # table[0] # => ["FOO", "BAR", "BAZ"] + # + # Specify a column by its \String header: + # # Get a column. + # table['Name'] # => ["FOO", "BAR", "BAZ"] + # # Set a column, then get it. + # table['Name'] = ['Foo', 'Bar', 'Baz'] + # table['Name'] # => ["Foo", "Bar", "Baz"] + # + # === Mixed Mode + # + # In mixed mode, you can refer to either rows or columns: + # - An \Integer index refers to a row. + # - A \Range index refers to multiple rows. + # - A \String index refers to a column. + # + # Set a table to mixed mode with method #by_col_or_row!: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col_or_row! # => # + # + # Specify a single row by an \Integer index: + # # Get a row. + # table[1] # => # + # # Set a row, then get it. + # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3]) + # table[1] # => # + # + # Specify a sequence of rows by a \Range: + # # Get rows. + # table[1..2] # => [#, #] + # # Set rows, then get them. + # table[1] = CSV::Row.new(['Name', 'Value'], ['bat', 4]) + # table[2] = CSV::Row.new(['Name', 'Value'], ['bad', 5]) + # table[1..2] # => [["Name", #], ["Value", #]] + # + # Specify a column by its \String header: + # # Get a column. + # table['Name'] # => ["foo", "bat", "bad"] + # # Set a column, then get it. + # table['Name'] = ['Foo', 'Bar', 'Baz'] + # table['Name'] # => ["Foo", "Bar", "Baz"] + class Table + # :call-seq: + # CSV::Table.new(array_of_rows, headers = nil) -> csv_table + # + # Returns a new \CSV::Table object. + # + # - Argument +array_of_rows+ must be an \Array of CSV::Row objects. + # - Argument +headers+, if given, may be an \Array of Strings. + # + # --- + # + # Create an empty \CSV::Table object: + # table = CSV::Table.new([]) + # table # => # + # + # Create a non-empty \CSV::Table object: + # rows = [ + # CSV::Row.new([], []), + # CSV::Row.new([], []), + # CSV::Row.new([], []), + # ] + # table = CSV::Table.new(rows) + # table # => # + # + # --- + # + # If argument +headers+ is an \Array of Strings, + # those Strings become the table's headers: + # table = CSV::Table.new([], headers: ['Name', 'Age']) + # table.headers # => ["Name", "Age"] + # + # If argument +headers+ is not given and the table has rows, + # the headers are taken from the first row: + # rows = [ + # CSV::Row.new(['Foo', 'Bar'], []), + # CSV::Row.new(['foo', 'bar'], []), + # CSV::Row.new(['FOO', 'BAR'], []), + # ] + # table = CSV::Table.new(rows) + # table.headers # => ["Foo", "Bar"] + # + # If argument +headers+ is not given and the table is empty (has no rows), + # the headers are also empty: + # table = CSV::Table.new([]) + # table.headers # => [] + # + # --- + # + # Raises an exception if argument +array_of_rows+ is not an \Array object: + # # Raises NoMethodError (undefined method `first' for :foo:Symbol): + # CSV::Table.new(:foo) + # + # Raises an exception if an element of +array_of_rows+ is not a \CSV::Table object: + # # Raises NoMethodError (undefined method `headers' for :foo:Symbol): + # CSV::Table.new([:foo]) + def initialize(array_of_rows, headers: nil) + @table = array_of_rows + @headers = headers + unless @headers + if @table.empty? + @headers = [] + else + @headers = @table.first.headers + end + end + + @mode = :col_or_row + end + + # The current access mode for indexing and iteration. + attr_reader :mode + + # Internal data format used to compare equality. + attr_reader :table + protected :table + + ### Array Delegation ### + + extend Forwardable + def_delegators :@table, :empty?, :length, :size + + # :call-seq: + # table.by_col -> table_dup + # + # Returns a duplicate of +self+, in column mode + # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]): + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.mode # => :col_or_row + # dup_table = table.by_col + # dup_table.mode # => :col + # dup_table.equal?(table) # => false # It's a dup + # + # This may be used to chain method calls without changing the mode + # (but also will affect performance and memory usage): + # dup_table.by_col['Name'] + # + # Also note that changes to the duplicate table will not affect the original. + def by_col + self.class.new(@table.dup).by_col! + end + + # :call-seq: + # table.by_col! -> self + # + # Sets the mode for +self+ to column mode + # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]); returns +self+: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.mode # => :col_or_row + # table1 = table.by_col! + # table.mode # => :col + # table1.equal?(table) # => true # Returned self + def by_col! + @mode = :col + + self + end + + # :call-seq: + # table.by_col_or_row -> table_dup + # + # Returns a duplicate of +self+, in mixed mode + # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]): + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true).by_col! + # table.mode # => :col + # dup_table = table.by_col_or_row + # dup_table.mode # => :col_or_row + # dup_table.equal?(table) # => false # It's a dup + # + # This may be used to chain method calls without changing the mode + # (but also will affect performance and memory usage): + # dup_table.by_col_or_row['Name'] + # + # Also note that changes to the duplicate table will not affect the original. + def by_col_or_row + self.class.new(@table.dup).by_col_or_row! + end + + # :call-seq: + # table.by_col_or_row! -> self + # + # Sets the mode for +self+ to mixed mode + # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]); returns +self+: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true).by_col! + # table.mode # => :col + # table1 = table.by_col_or_row! + # table.mode # => :col_or_row + # table1.equal?(table) # => true # Returned self + def by_col_or_row! + @mode = :col_or_row + + self + end + + # :call-seq: + # table.by_row -> table_dup + # + # Returns a duplicate of +self+, in row mode + # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]): + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.mode # => :col_or_row + # dup_table = table.by_row + # dup_table.mode # => :row + # dup_table.equal?(table) # => false # It's a dup + # + # This may be used to chain method calls without changing the mode + # (but also will affect performance and memory usage): + # dup_table.by_row[1] + # + # Also note that changes to the duplicate table will not affect the original. + def by_row + self.class.new(@table.dup).by_row! + end + + # :call-seq: + # table.by_row! -> self + # + # Sets the mode for +self+ to row mode + # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]); returns +self+: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.mode # => :col_or_row + # table1 = table.by_row! + # table.mode # => :row + # table1.equal?(table) # => true # Returned self + def by_row! + @mode = :row + + self + end + + # :call-seq: + # table.headers -> array_of_headers + # + # Returns a new \Array containing the \String headers for the table. + # + # If the table is not empty, returns the headers from the first row: + # rows = [ + # CSV::Row.new(['Foo', 'Bar'], []), + # CSV::Row.new(['FOO', 'BAR'], []), + # CSV::Row.new(['foo', 'bar'], []), + # ] + # table = CSV::Table.new(rows) + # table.headers # => ["Foo", "Bar"] + # table.delete(0) + # table.headers # => ["FOO", "BAR"] + # table.delete(0) + # table.headers # => ["foo", "bar"] + # + # If the table is empty, returns a copy of the headers in the table itself: + # table.delete(0) + # table.headers # => ["Foo", "Bar"] + def headers + if @table.empty? + @headers.dup + else + @table.first.headers + end + end + + # :call-seq: + # table[n] -> row or column_data + # table[range] -> array_of_rows or array_of_column_data + # table[header] -> array_of_column_data + # + # Returns data from the table; does not modify the table. + # + # --- + # + # Fetch a \Row by Its \Integer Index:: + # - Form: table[n], +n+ an integer. + # - Access mode: :row or :col_or_row. + # - Return value: _nth_ row of the table, if that row exists; + # otherwise +nil+. + # + # Returns the _nth_ row of the table if that row exists: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_row! # => # + # table[1] # => # + # table.by_col_or_row! # => # + # table[1] # => # + # + # Counts backward from the last row if +n+ is negative: + # table[-1] # => # + # + # Returns +nil+ if +n+ is too large or too small: + # table[4] # => nil + # table[-4] # => nil + # + # Raises an exception if the access mode is :row + # and +n+ is not an \Integer: + # table.by_row! # => # + # # Raises TypeError (no implicit conversion of String into Integer): + # table['Name'] + # + # --- + # + # Fetch a Column by Its \Integer Index:: + # - Form: table[n], +n+ an \Integer. + # - Access mode: :col. + # - Return value: _nth_ column of the table, if that column exists; + # otherwise an \Array of +nil+ fields of length self.size. + # + # Returns the _nth_ column of the table if that column exists: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col! # => # + # table[1] # => ["0", "1", "2"] + # + # Counts backward from the last column if +n+ is negative: + # table[-2] # => ["foo", "bar", "baz"] + # + # Returns an \Array of +nil+ fields if +n+ is too large or too small: + # table[4] # => [nil, nil, nil] + # table[-4] # => [nil, nil, nil] + # + # --- + # + # Fetch Rows by \Range:: + # - Form: table[range], +range+ a \Range object. + # - Access mode: :row or :col_or_row. + # - Return value: rows from the table, beginning at row range.start, + # if those rows exists. + # + # Returns rows from the table, beginning at row range.first, + # if those rows exist: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_row! # => # + # rows = table[1..2] # => # + # rows # => [#, #] + # table.by_col_or_row! # => # + # rows = table[1..2] # => # + # rows # => [#, #] + # + # If there are too few rows, returns all from range.start to the end: + # rows = table[1..50] # => # + # rows # => [#, #] + # + # Special case: if range.start == table.size, returns an empty \Array: + # table[table.size..50] # => [] + # + # If range.end is negative, calculates the ending index from the end: + # rows = table[0..-1] + # rows # => [#, #, #] + # + # If range.start is negative, calculates the starting index from the end: + # rows = table[-1..2] + # rows # => [#] + # + # If range.start is larger than table.size, returns +nil+: + # table[4..4] # => nil + # + # --- + # + # Fetch Columns by \Range:: + # - Form: table[range], +range+ a \Range object. + # - Access mode: :col. + # - Return value: column data from the table, beginning at column range.start, + # if those columns exist. + # + # Returns column values from the table, if the column exists; + # the values are arranged by row: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col! + # table[0..1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # Special case: if range.start == headers.size, + # returns an \Array (size: table.size) of empty \Arrays: + # table[table.headers.size..50] # => [[], [], []] + # + # If range.end is negative, calculates the ending index from the end: + # table[0..-1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # If range.start is negative, calculates the starting index from the end: + # table[-2..2] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]] + # + # If range.start is larger than table.size, + # returns an \Array of +nil+ values: + # table[4..4] # => [nil, nil, nil] + # + # --- + # + # Fetch a Column by Its \String Header:: + # - Form: table[header], +header+ a \String header. + # - Access mode: :col or :col_or_row + # - Return value: column data from the table, if that +header+ exists. + # + # Returns column values from the table, if the column exists: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col! # => # + # table['Name'] # => ["foo", "bar", "baz"] + # table.by_col_or_row! # => # + # col = table['Name'] + # col # => ["foo", "bar", "baz"] + # + # Modifying the returned column values does not modify the table: + # col[0] = 'bat' + # col # => ["bat", "bar", "baz"] + # table['Name'] # => ["foo", "bar", "baz"] + # + # Returns an \Array of +nil+ values if there is no such column: + # table['Nosuch'] # => [nil, nil, nil] + def [](index_or_header) + if @mode == :row or # by index + (@mode == :col_or_row and (index_or_header.is_a?(Integer) or index_or_header.is_a?(Range))) + @table[index_or_header] + else # by header + @table.map { |row| row[index_or_header] } + end + end + + # :call-seq: + # table[n] = row -> row + # table[n] = field_or_array_of_fields -> field_or_array_of_fields + # table[header] = field_or_array_of_fields -> field_or_array_of_fields + # + # Puts data onto the table. + # + # --- + # + # Set a \Row by Its \Integer Index:: + # - Form: table[n] = row, +n+ an \Integer, + # +row+ a \CSV::Row instance or an \Array of fields. + # - Access mode: :row or :col_or_row. + # - Return value: +row+. + # + # If the row exists, it is replaced: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # new_row = CSV::Row.new(['Name', 'Value'], ['bat', 3]) + # table.by_row! # => # + # return_value = table[0] = new_row + # return_value.equal?(new_row) # => true # Returned the row + # table[0].to_h # => {"Name"=>"bat", "Value"=>3} + # + # With access mode :col_or_row: + # table.by_col_or_row! # => # + # table[0] = CSV::Row.new(['Name', 'Value'], ['bam', 4]) + # table[0].to_h # => {"Name"=>"bam", "Value"=>4} + # + # With an \Array instead of a \CSV::Row, inherits headers from the table: + # array = ['bad', 5] + # return_value = table[0] = array + # return_value.equal?(array) # => true # Returned the array + # table[0].to_h # => {"Name"=>"bad", "Value"=>5} + # + # If the row does not exist, extends the table by adding rows: + # assigns rows with +nil+ as needed: + # table.size # => 3 + # table[5] = ['bag', 6] + # table.size # => 6 + # table[3] # => nil + # table[4]# => nil + # table[5].to_h # => {"Name"=>"bag", "Value"=>6} + # + # Note that the +nil+ rows are actually +nil+, not a row of +nil+ fields. + # + # --- + # + # Set a Column by Its \Integer Index:: + # - Form: table[n] = array_of_fields, +n+ an \Integer, + # +array_of_fields+ an \Array of \String fields. + # - Access mode: :col. + # - Return value: +array_of_fields+. + # + # If the column exists, it is replaced: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # new_col = [3, 4, 5] + # table.by_col! # => # + # return_value = table[1] = new_col + # return_value.equal?(new_col) # => true # Returned the column + # table[1] # => [3, 4, 5] + # # The rows, as revised: + # table.by_row! # => # + # table[0].to_h # => {"Name"=>"foo", "Value"=>3} + # table[1].to_h # => {"Name"=>"bar", "Value"=>4} + # table[2].to_h # => {"Name"=>"baz", "Value"=>5} + # table.by_col! # => # + # + # If there are too few values, fills with +nil+ values: + # table[1] = [0] + # table[1] # => [0, nil, nil] + # + # If there are too many values, ignores the extra values: + # table[1] = [0, 1, 2, 3, 4] + # table[1] # => [0, 1, 2] + # + # If a single value is given, replaces all fields in the column with that value: + # table[1] = 'bat' + # table[1] # => ["bat", "bat", "bat"] + # + # --- + # + # Set a Column by Its \String Header:: + # - Form: table[header] = field_or_array_of_fields, + # +header+ a \String header, +field_or_array_of_fields+ a field value + # or an \Array of \String fields. + # - Access mode: :col or :col_or_row. + # - Return value: +field_or_array_of_fields+. + # + # If the column exists, it is replaced: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # new_col = [3, 4, 5] + # table.by_col! # => # + # return_value = table['Value'] = new_col + # return_value.equal?(new_col) # => true # Returned the column + # table['Value'] # => [3, 4, 5] + # # The rows, as revised: + # table.by_row! # => # + # table[0].to_h # => {"Name"=>"foo", "Value"=>3} + # table[1].to_h # => {"Name"=>"bar", "Value"=>4} + # table[2].to_h # => {"Name"=>"baz", "Value"=>5} + # table.by_col! # => # + # + # If there are too few values, fills with +nil+ values: + # table['Value'] = [0] + # table['Value'] # => [0, nil, nil] + # + # If there are too many values, ignores the extra values: + # table['Value'] = [0, 1, 2, 3, 4] + # table['Value'] # => [0, 1, 2] + # + # If the column does not exist, extends the table by adding columns: + # table['Note'] = ['x', 'y', 'z'] + # table['Note'] # => ["x", "y", "z"] + # # The rows, as revised: + # table.by_row! + # table[0].to_h # => {"Name"=>"foo", "Value"=>0, "Note"=>"x"} + # table[1].to_h # => {"Name"=>"bar", "Value"=>1, "Note"=>"y"} + # table[2].to_h # => {"Name"=>"baz", "Value"=>2, "Note"=>"z"} + # table.by_col! + # + # If a single value is given, replaces all fields in the column with that value: + # table['Value'] = 'bat' + # table['Value'] # => ["bat", "bat", "bat"] + def []=(index_or_header, value) + if @mode == :row or # by index + (@mode == :col_or_row and index_or_header.is_a? Integer) + if value.is_a? Array + @table[index_or_header] = Row.new(headers, value) + else + @table[index_or_header] = value + end + else # set column + unless index_or_header.is_a? Integer + index = @headers.index(index_or_header) || @headers.size + @headers[index] = index_or_header + end + if value.is_a? Array # multiple values + @table.each_with_index do |row, i| + if row.header_row? + row[index_or_header] = index_or_header + else + row[index_or_header] = value[i] + end + end + else # repeated value + @table.each do |row| + if row.header_row? + row[index_or_header] = index_or_header + else + row[index_or_header] = value + end + end + end + end + end + + # :call-seq: + # table.values_at(*indexes) -> array_of_rows + # table.values_at(*headers) -> array_of_columns_data + # + # If the access mode is :row or :col_or_row, + # and each argument is either an \Integer or a \Range, + # returns rows. + # Otherwise, returns columns data. + # + # In either case, the returned values are in the order + # specified by the arguments. Arguments may be repeated. + # + # --- + # + # Returns rows as an \Array of \CSV::Row objects. + # + # No argument: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.values_at # => [] + # + # One index: + # values = table.values_at(0) + # values # => [#] + # + # Two indexes: + # values = table.values_at(2, 0) + # values # => [#, #] + # + # One \Range: + # values = table.values_at(1..2) + # values # => [#, #] + # + # \Ranges and indexes: + # values = table.values_at(0..1, 1..2, 0, 2) + # pp values + # Output: + # [#, + # #, + # #, + # #, + # #, + # #] + # + # --- + # + # Returns columns data as row Arrays, + # each consisting of the specified columns data for that row: + # values = table.values_at('Name') + # values # => [["foo"], ["bar"], ["baz"]] + # values = table.values_at('Value', 'Name') + # values # => [["0", "foo"], ["1", "bar"], ["2", "baz"]] + def values_at(*indices_or_headers) + if @mode == :row or # by indices + ( @mode == :col_or_row and indices_or_headers.all? do |index| + index.is_a?(Integer) or + ( index.is_a?(Range) and + index.first.is_a?(Integer) and + index.last.is_a?(Integer) ) + end ) + @table.values_at(*indices_or_headers) + else # by headers + @table.map { |row| row.values_at(*indices_or_headers) } + end + end + + # :call-seq: + # table << row_or_array -> self + # + # If +row_or_array+ is a \CSV::Row object, + # it is appended to the table: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table << CSV::Row.new(table.headers, ['bat', 3]) + # table[3] # => # + # + # If +row_or_array+ is an \Array, it is used to create a new + # \CSV::Row object which is then appended to the table: + # table << ['bam', 4] + # table[4] # => # + def <<(row_or_array) + if row_or_array.is_a? Array # append Array + @table << Row.new(headers, row_or_array) + else # append Row + @table << row_or_array + end + + self # for chaining + end + + # + # :call-seq: + # table.push(*rows_or_arrays) -> self + # + # A shortcut for appending multiple rows. Equivalent to: + # rows.each {|row| self << row } + # + # Each argument may be either a \CSV::Row object or an \Array: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # rows = [ + # CSV::Row.new(table.headers, ['bat', 3]), + # ['bam', 4] + # ] + # table.push(*rows) + # table[3..4] # => [#, #] + def push(*rows) + rows.each { |row| self << row } + + self # for chaining + end + + # :call-seq: + # table.delete(*indexes) -> deleted_values + # table.delete(*headers) -> deleted_values + # + # If the access mode is :row or :col_or_row, + # and each argument is either an \Integer or a \Range, + # returns deleted rows. + # Otherwise, returns deleted columns data. + # + # In either case, the returned values are in the order + # specified by the arguments. Arguments may be repeated. + # + # --- + # + # Returns rows as an \Array of \CSV::Row objects. + # + # One index: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # deleted_values = table.delete(0) + # deleted_values # => [#] + # + # Two indexes: + # table = CSV.parse(source, headers: true) + # deleted_values = table.delete(2, 0) + # deleted_values # => [#, #] + # + # --- + # + # Returns columns data as column Arrays. + # + # One header: + # table = CSV.parse(source, headers: true) + # deleted_values = table.delete('Name') + # deleted_values # => ["foo", "bar", "baz"] + # + # Two headers: + # table = CSV.parse(source, headers: true) + # deleted_values = table.delete('Value', 'Name') + # deleted_values # => [["0", "1", "2"], ["foo", "bar", "baz"]] + def delete(*indexes_or_headers) + if indexes_or_headers.empty? + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" + end + deleted_values = indexes_or_headers.map do |index_or_header| + if @mode == :row or # by index + (@mode == :col_or_row and index_or_header.is_a? Integer) + @table.delete_at(index_or_header) + else # by header + if index_or_header.is_a? Integer + @headers.delete_at(index_or_header) + else + @headers.delete(index_or_header) + end + @table.map { |row| row.delete(index_or_header).last } + end + end + if indexes_or_headers.size == 1 + deleted_values[0] + else + deleted_values + end + end + + # :call-seq: + # table.delete_if {|row_or_column| ... } -> self + # + # Removes rows or columns for which the block returns a truthy value; + # returns +self+. + # + # Removes rows when the access mode is :row or :col_or_row; + # calls the block with each \CSV::Row object: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_row! # => # + # table.size # => 3 + # table.delete_if {|row| row['Name'].start_with?('b') } + # table.size # => 1 + # + # Removes columns when the access mode is :col; + # calls the block with each column as a 2-element array + # containing the header and an \Array of column fields: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_col! # => # + # table.headers.size # => 2 + # table.delete_if {|column_data| column_data[1].include?('2') } + # table.headers.size # => 1 + # + # Returns a new \Enumerator if no block is given: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.delete_if # => #:delete_if> + def delete_if(&block) + return enum_for(__method__) { @mode == :row or @mode == :col_or_row ? size : headers.size } unless block_given? + + if @mode == :row or @mode == :col_or_row # by index + @table.delete_if(&block) + else # by header + headers.each do |header| + delete(header) if yield([header, self[header]]) + end + end + + self # for chaining + end + + include Enumerable + + # :call-seq: + # table.each {|row_or_column| ... ) -> self + # + # Calls the block with each row or column; returns +self+. + # + # When the access mode is :row or :col_or_row, + # calls the block with each \CSV::Row object: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.by_row! # => # + # table.each {|row| p row } + # Output: + # # + # # + # # + # + # When the access mode is :col, + # calls the block with each column as a 2-element array + # containing the header and an \Array of column fields: + # table.by_col! # => # + # table.each {|column_data| p column_data } + # Output: + # ["Name", ["foo", "bar", "baz"]] + # ["Value", ["0", "1", "2"]] + # + # Returns a new \Enumerator if no block is given: + # table.each # => #:each> + def each(&block) + return enum_for(__method__) { @mode == :col ? headers.size : size } unless block_given? + + if @mode == :col + headers.each.with_index do |header, i| + yield([header, @table.map {|row| row[header, i]}]) + end + else + @table.each(&block) + end + + self # for chaining + end + + # :call-seq: + # table == other_table -> true or false + # + # Returns +true+ if all each row of +self+ == + # the corresponding row of +other_table+, otherwise, +false+. + # + # The access mode does no affect the result. + # + # Equal tables: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # other_table = CSV.parse(source, headers: true) + # table == other_table # => true + # + # Different row count: + # other_table.delete(2) + # table == other_table # => false + # + # Different last row: + # other_table << ['bat', 3] + # table == other_table # => false + def ==(other) + return @table == other.table if other.is_a? CSV::Table + @table == other + end + + # :call-seq: + # table.to_a -> array_of_arrays + # + # Returns the table as an \Array of \Arrays; + # the headers are in the first row: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.to_a # => [["Name", "Value"], ["foo", "0"], ["bar", "1"], ["baz", "2"]] + def to_a + array = [headers] + @table.each do |row| + array.push(row.fields) unless row.header_row? + end + + array + end + + # :call-seq: + # table.to_csv(**options) -> csv_string + # + # Returns the table as \CSV string. + # See {Options for Generating}[../CSV.html#class-CSV-label-Options+for+Generating]. + # + # Defaults option +write_headers+ to +true+: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.to_csv # => "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # + # Omits the headers if option +write_headers+ is given as +false+ + # (see {Option +write_headers+}[../CSV.html#class-CSV-label-Option+write_headers]): + # table.to_csv(write_headers: false) # => "foo,0\nbar,1\nbaz,2\n" + # + # Limit rows if option +limit+ is given like +2+: + # table.to_csv(limit: 2) # => "Name,Value\nfoo,0\nbar,1\n" + def to_csv(write_headers: true, limit: nil, **options) + array = write_headers ? [headers.to_csv(**options)] : [] + limit ||= @table.size + limit = @table.size + 1 + limit if limit < 0 + limit = 0 if limit < 0 + @table.first(limit).each do |row| + array.push(row.fields.to_csv(**options)) unless row.header_row? + end + + array.join("") + end + alias_method :to_s, :to_csv + + # + # Extracts the nested value specified by the sequence of +index+ or +header+ objects by calling dig at each step, + # returning nil if any intermediate step is nil. + # + def dig(index_or_header, *index_or_headers) + value = self[index_or_header] + if value.nil? + nil + elsif index_or_headers.empty? + value + else + unless value.respond_to?(:dig) + raise TypeError, "#{value.class} does not have \#dig method" + end + value.dig(*index_or_headers) + end + end + + # :call-seq: + # table.inspect => string + # + # Returns a US-ASCII-encoded \String showing table: + # - Class: CSV::Table. + # - Access mode: :row, :col, or :col_or_row. + # - Size: Row count, including the header row. + # + # Example: + # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n" + # table = CSV.parse(source, headers: true) + # table.inspect # => "#\nName,Value\nfoo,0\nbar,1\nbaz,2\n" + # + def inspect + inspected = +"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>" + summary = to_csv(limit: 5) + inspected << "\n" << summary if summary.encoding.ascii_compatible? + inspected + end + end +end diff --git a/bin/gems/csv-3.3.2/lib/csv/version.rb b/bin/gems/csv-3.3.2/lib/csv/version.rb new file mode 100644 index 00000000..925d605a --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class CSV + # The version of the installed library. + VERSION = "3.3.2" +end diff --git a/bin/gems/csv-3.3.2/lib/csv/writer.rb b/bin/gems/csv-3.3.2/lib/csv/writer.rb new file mode 100644 index 00000000..b59f111e --- /dev/null +++ b/bin/gems/csv-3.3.2/lib/csv/writer.rb @@ -0,0 +1,209 @@ +# frozen_string_literal: true + +require_relative "input_record_separator" +require_relative "row" + +class CSV + # Note: Don't use this class directly. This is an internal class. + class Writer + # + # A CSV::Writer receives an output, prepares the header, format and output. + # It allows us to write new rows in the object and rewind it. + # + attr_reader :lineno + attr_reader :headers + + def initialize(output, options) + @output = output + @options = options + @lineno = 0 + @fields_converter = nil + prepare + if @options[:write_headers] and @headers + self << @headers + end + @fields_converter = @options[:fields_converter] + end + + # + # Adds a new row + # + def <<(row) + case row + when Row + row = row.fields + when Hash + row = @headers.collect {|header| row[header]} + end + + @headers ||= row if @use_headers + @lineno += 1 + + if @fields_converter + row = @fields_converter.convert(row, nil, lineno) + end + + i = -1 + converted_row = row.collect do |field| + i += 1 + quote(field, i) + end + line = converted_row.join(@column_separator) + @row_separator + if @output_encoding + line = line.encode(@output_encoding) + end + @output << line + + self + end + + # + # Winds back to the beginning + # + def rewind + @lineno = 0 + @headers = nil if @options[:headers].nil? + end + + private + def prepare + @encoding = @options[:encoding] + + prepare_header + prepare_format + prepare_output + end + + def prepare_header + headers = @options[:headers] + case headers + when Array + @headers = headers + @use_headers = true + when String + @headers = CSV.parse_line(headers, + col_sep: @options[:column_separator], + row_sep: @options[:row_separator], + quote_char: @options[:quote_character]) + @use_headers = true + when true + @headers = nil + @use_headers = true + else + @headers = nil + @use_headers = false + end + return unless @headers + + converter = @options[:header_fields_converter] + @headers = converter.convert(@headers, nil, 0, []) + @headers.each do |header| + header.freeze if header.is_a?(String) + end + end + + def prepare_force_quotes_fields(force_quotes) + @force_quotes_fields = {} + force_quotes.each do |name_or_index| + case name_or_index + when Integer + index = name_or_index + @force_quotes_fields[index] = true + when String, Symbol + name = name_or_index.to_s + if @headers.nil? + message = ":headers is required when you use field name " + + "in :force_quotes: " + + "#{name_or_index.inspect}: #{force_quotes.inspect}" + raise ArgumentError, message + end + index = @headers.index(name) + next if index.nil? + @force_quotes_fields[index] = true + else + message = ":force_quotes element must be " + + "field index or field name: " + + "#{name_or_index.inspect}: #{force_quotes.inspect}" + raise ArgumentError, message + end + end + end + + def prepare_format + @column_separator = @options[:column_separator].to_s.encode(@encoding) + row_separator = @options[:row_separator] + if row_separator == :auto + @row_separator = InputRecordSeparator.value.encode(@encoding) + else + @row_separator = row_separator.to_s.encode(@encoding) + end + @quote_character = @options[:quote_character] + force_quotes = @options[:force_quotes] + if force_quotes.is_a?(Array) + prepare_force_quotes_fields(force_quotes) + @force_quotes = false + elsif force_quotes + @force_quotes_fields = nil + @force_quotes = true + else + @force_quotes_fields = nil + @force_quotes = false + end + unless @force_quotes + @quotable_pattern = + Regexp.new("[\r\n".encode(@encoding) + + Regexp.escape(@column_separator) + + Regexp.escape(@quote_character.encode(@encoding)) + + "]".encode(@encoding)) + end + @quote_empty = @options.fetch(:quote_empty, true) + end + + def prepare_output + @output_encoding = nil + return unless @output.is_a?(StringIO) + + output_encoding = @output.internal_encoding || @output.external_encoding + if @encoding != output_encoding + if @options[:force_encoding] + @output_encoding = output_encoding + else + compatible_encoding = Encoding.compatible?(@encoding, output_encoding) + if compatible_encoding + @output.set_encoding(compatible_encoding) + @output.seek(0, IO::SEEK_END) + end + end + end + end + + def quote_field(field) + field = String(field) + encoded_quote_character = @quote_character.encode(field.encoding) + encoded_quote_character + + field.gsub(encoded_quote_character, + encoded_quote_character * 2) + + encoded_quote_character + end + + def quote(field, i) + if @force_quotes + quote_field(field) + elsif @force_quotes_fields and @force_quotes_fields[i] + quote_field(field) + else + if field.nil? # represent +nil+ fields as empty unquoted fields + "" + else + field = String(field) # Stringify fields + # represent empty fields as empty quoted fields + if (@quote_empty and field.empty?) or (field.valid_encoding? and @quotable_pattern.match?(field)) + quote_field(field) + else + field # unquoted field + end + end + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/.gitignore b/bin/gems/em-websocket-0.5.3/.gitignore new file mode 100644 index 00000000..616915ca --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/.gitignore @@ -0,0 +1,3 @@ +*.gemspec +pkg +Gemfile.lock diff --git a/bin/gems/em-websocket-0.5.3/CHANGELOG.rdoc b/bin/gems/em-websocket-0.5.3/CHANGELOG.rdoc new file mode 100644 index 00000000..f7dd9fb3 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/CHANGELOG.rdoc @@ -0,0 +1,149 @@ += Changelog + +== 0.5.1 / 2014-04-23 + +- new features: + - Support for receiving binary messages + +- changed: + - Allow additional close codes to be sent by apps + - Raise better errors on missing Sec-WebSocket-Key2 + - Updated http_parser.rb dependency to 0.6.0 + +- bug fixes: + - Abort if HTTP request URI is invalid + - Force close connections that have been sent a close handshake after a timeout + +- improved spec compliance on: + - Missing continuation frames + - Fragmented control frames + - Close behaviour after protocol errors + +== 0.5.0 / 2013-03-05 + +- new features: + - onclose handler is now passed a hash containing was_clean (set to true in drafts 03 and above when a connection is closed with a closing handshake, either by the server or the client), the close code, and reason (drafts 06 and above). Close code 1005 indicates that no code was supplied, and 1006 that the connection was closed abnormally. + - use Connection#support_close_codes? to easily check whether close codes are supported by the WebSocket protocol (drafts 06 and above) + - closes connection with 1007 close code if text frame contains invalid UTF8 + - added Handshake#secure? for checking whether the connection is secure (either ssl or behind an ssl proxy) + +- changed: + - Defaults to sending no close code rather than 1000 (consistent with browsers) + - Allows sending a 3xxx close code + - Renamed Connection#close_websocket to Connection#close (again for consistency with browsers). Old method is available till 0.6. + - Sends reasons with internally generated closure (previously only sent code) + - Echos close code when replying to close handshake + +== 0.4.0 / 2013-01-22 + +- new features: + - on_open handler is now passed a handshake object which exposes the request headers, path, and query parameters + - Easily access the protocol version via Handshake#protocol_version + - Easily access the origin via Handshake#origin + +- changed: + - Removed Connection#request - change to using handshake passed to on_open + +- internals: + - Uses the http_parser.rb gem + +== 0.3.8 / 2012-07-12 + +- bug fixes: + - Fixed support for Ruby 1.8.7 which was broken in 0.3.7 + +== 0.3.7 / 2012-07-11 + +- new features: + - Supports sending 1009 error code when incoming frame is too large to handle, and added associated exception class WSMessageTooBigError [Martyn Loughran] + - Supports overriding the maximum frame size by setting the max_frame_size accessor on the connection object (in bytes). Default unchanged at 10MB. [Martyn Loughran] + +- bug fixes: + - Fixes some encoding issues on Ruby 1.9 [Dingding Ye] + - Raises a HandshakeError if WS header is empty [Markus Fenske] + - Connection#send would mutate passed string to BINARY encoding. The fix still mutates the string by forcing the encoding back to UTF-8 before returning, but if the passed string was encoded as UTF-8 this is equivalent [Martyn Loughran] + +== 0.3.6 / 2011-12-23 + +- new features: + - Supports sending ping & pong messages + - Supports binding to received ping & pong messages + +== 0.3.5 / 2011-10-24 + +- new features: + - Support WebSocket draft 13 + +== 0.3.2 / 2011-10-09 + +- bugfixes: + - Handling of messages with > 2 frames + - Encode string passed to onmessage handler as UTF-8 on Ruby 1.9 + - Add 10MB frame length limit to all draft versions + +== 0.3.1 / 2011-07-28 + +- new features: + - Support WebSocket drafts 07 & 08 + +== 0.3.0 / 2011-05-06 + +- new features: + - Support WebSocket drafts 05 & 06 +- changes: + - Accept request headers in a case insensitive manner + - Change handling of errors. Previously some application errors were caught + internally and were invisible unless an onerror callback was supplied. See + readme for details + +== 0.2.1 / 2011-03-01 + +- bugfixes: + - Performance improvements to draft 76 framing + - Limit frame lengths for draft 76 + - Better error handling for draft 76 handshake + - Ruby 1.9 support + +== 0.2.0 / 2010-11-23 + +- new features: + - Support for WebSocket draft 03 +- bugfixes: + - Handle case when handshake split into two receive_data calls + - Stricter regexp matching of frames + +== 0.1.4 / 2010-08-23 + +- new features: + - Allow custom ssl certificate to be used by passing :tls_options + - Protect against errors caused by non limited frame lengths + - Use custom exceptions rather than RuntimeError +- bugfixes: + - Handle invalid HTTP request with HandshakeError + +== 0.1.3 / 2010-07-18 + +- new features: + - onerror callback +- bugfixes: + - proper handling of zero spaces in key1 or key2(prevent ZeroDivisionError) + - convert received data to utf-8 to prevent ruby 1.9 errors + - fix handling of null bytes within a frame + +== 0.1.2 / 2010-06-16 + +- new features: + - none +- bugfixes: + - allow $ character inside header key + +== 0.1.1 / 2010-06-13 + +- new features: + - wss/ssl support +- bugfixes: + - can't & strings + +== 0.1.0 / 2010-06-12 + +- initial release \ No newline at end of file diff --git a/bin/gems/em-websocket-0.5.3/Gemfile b/bin/gems/em-websocket-0.5.3/Gemfile new file mode 100644 index 00000000..633ac0cb --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/Gemfile @@ -0,0 +1,9 @@ +source "http://rubygems.org" + +gemspec + +gem "em-websocket-client", git: "git@github.com:movitto/em-websocket-client.git", branch: "expose-websocket-api" +gem "em-spec", "~> 0.2.6" +gem "em-http-request", "~> 1.1.1" +gem "rspec", "~> 3.5.0" +gem "rake" diff --git a/bin/gems/em-websocket-0.5.3/LICENCE b/bin/gems/em-websocket-0.5.3/LICENCE new file mode 100644 index 00000000..d4df7ada --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/LICENCE @@ -0,0 +1,7 @@ +Copyright (c) 2009-2014 Ilya Grigorik, Martyn Loughran + +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/bin/gems/em-websocket-0.5.3/README.md b/bin/gems/em-websocket-0.5.3/README.md new file mode 100644 index 00000000..d1127160 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/README.md @@ -0,0 +1,146 @@ +# EM-WebSocket + +[![Gem Version](https://badge.fury.io/rb/em-websocket.png)](http://rubygems.org/gems/em-websocket) +[![Analytics](https://ga-beacon.appspot.com/UA-71196-10/em-websocket/readme)](https://github.com/igrigorik/ga-beacon) + +EventMachine based, async, Ruby WebSocket server. Take a look at examples directory, or check out the blog post: [Ruby & Websockets: TCP for the Web](http://www.igvita.com/2009/12/22/ruby-websockets-tcp-for-the-browser/). + +## Simple server example + +```ruby +require 'em-websocket' + +EM.run { + EM::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws| + ws.onopen { |handshake| + puts "WebSocket connection open" + + # Access properties on the EM::WebSocket::Handshake object, e.g. + # path, query_string, origin, headers + + # Publish message to the client + ws.send "Hello Client, you connected to #{handshake.path}" + } + + ws.onclose { puts "Connection closed" } + + ws.onmessage { |msg| + puts "Recieved message: #{msg}" + ws.send "Pong: #{msg}" + } + end +} +``` + +## Protocols supported, and protocol specific functionality + +Supports all WebSocket protocols in use in the wild (and a few that are not): drafts 75, 76, 1-17, rfc. + +While some of the changes between protocols are unimportant from the point of view of application developers, a few drafts did introduce new functionality. It's possible to easily test for this functionality by using + +### Ping & pong supported + +Call `ws.pingable?` to check whether ping & pong is supported by the protocol in use. + +It's possible to send a ping frame (`ws.ping(body = '')`), which the client must respond to with a pong, or the server can send an unsolicited pong frame (`ws.pong(body = '')`) which the client should not respond to. These methods can be used regardless of protocol version; they return true if the protocol supports ping&pong or false otherwise. + +When receiving a ping, the server will automatically respond with a pong as the spec requires (so you should _not_ write an onping handler that replies with a pong), however it is possible to bind to ping & pong events if desired by using the `onping` and `onpong` methods. + +### Healthchecks + +It's possible to send a regular `HTTP GET` request to the `/healthcheck` endpoint and receive a `200` response from the server. + +### Close codes and reasons + +A WebSocket connection can be closed cleanly, regardless of protocol, by calling `ws.close(code = nil, body = nil)`. + +Early protocols just close the TCP connection, draft 3 introduced a close handshake, and draft 6 added close codes and reasons to the close handshake. Call `ws.supports_close_codes?` to check whether close codes are supported (i.e. the protocol version is 6 or above). + +The `onclose` callback is passed a hash which may contain following keys (depending on the protocol version): + +* `was_clean`: boolean indicating whether the connection was closed via the close handshake. +* `code`: the close code. There are two special close codes which the server may set (as defined in the WebSocket spec): + * 1005: no code was supplied + * 1006: abnormal closure (the same as `was_clean: false`) +* `reason`: the close reason + +Acceptable close codes are defined in the WebSocket rfc (). The following codes can be supplies when calling `ws.close(code)`: + +* 1000: a generic normal close +* range 3xxx: reserved for libraries, frameworks, and applications (and can be registered with IANA) +* range 4xxx: for private use + +If unsure use a code in the 4xxx range. em-websocket may also close a connection with one of the following close codes: + +* 1002: WebSocket protocol error. +* 1009: Message too big to process. By default em-websocket will accept frames up to 10MB in size. If a frame is larger than this the connection will be closed without reading the frame data. The limit can be overriden globally (`EM::WebSocket.max_frame_size = bytes`) or on a specific connection (`ws.max_frame_size = bytes`). + +## Secure server + +It is possible to accept secure `wss://` connections by passing `:secure => true` when opening the connection. Pass a `:tls_options` hash containing keys as described in http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine/Connection:start_tls + +**Warning**: Safari 5 does not currently support prompting on untrusted SSL certificates therefore using a self signed certificate may leave you scratching your head. + +```ruby +EM::WebSocket.start({ + :host => "0.0.0.0", + :port => 443, + :secure => true, + :tls_options => { + :private_key_file => "/private/key", + :cert_chain_file => "/ssl/certificate" + } +}) do |ws| + # ... +end +``` + +It's possible to check whether an incoming connection is secure by reading `handshake.secure?` in the onopen callback. + +## Running behind an SSL Proxy/Terminator, like Stunnel + +The `:secure_proxy => true` option makes it possible to use em-websocket behind a secure SSL proxy/terminator like [Stunnel](http://www.stunnel.org/) which does the actual encryption & decryption. + +Note that this option is only required to support drafts 75 & 76 correctly (e.g. Safari 5.1.x & earlier, and Safari on iOS 5.x & earlier). + +```ruby +EM::WebSocket.start({ + :host => "0.0.0.0", + :port => 8080, + :secure_proxy => true +}) do |ws| + # ... +end +``` + +## Handling errors + +There are two kinds of errors that need to be handled -- WebSocket protocol errors and errors in application code. + +WebSocket protocol errors (for example invalid data in the handshake or invalid message frames) raise errors which descend from `EM::WebSocket::WebSocketError`. Such errors are rescued internally and the WebSocket connection will be closed immediately or an error code sent to the browser in accordance to the WebSocket specification. It is possible to be notified in application code of such errors by including an `onerror` callback. + +```ruby +ws.onerror { |error| + if error.kind_of?(EM::WebSocket::WebSocketError) + # ... + end +} +``` + +Application errors are treated differently. If no `onerror` callback has been defined these errors will propagate to the EventMachine reactor, typically causing your program to terminate. If you wish to handle exceptions, simply supply an `onerror callback` and check for exceptions which are not descendant from `EM::WebSocket::WebSocketError`. + +It is also possible to log all errors when developing by including the `:debug => true` option when initialising the WebSocket server. + +## Emulating WebSockets in older browsers + +It is possible to emulate WebSockets in older browsers using flash emulation. For example take a look at the [web-socket-js](https://github.com/gimite/web-socket-js) project. + +Using flash emulation does require some minimal support from em-websocket which is enabled by default. If flash connects to the WebSocket port and requests a policy file (which it will do if it fails to receive a policy file on port 843 after a timeout), em-websocket will return one. Also see for an example policy file server which you can run on port 843. + +## Examples & Projects using em-websocket + +* [Pusher](http://pusher.com) - Realtime Messaging Service +* [Livereload](https://github.com/mockko/livereload) - LiveReload applies CSS/JS changes to Safari or Chrome w/o reloading +* [Twitter AMQP WebSocket Example](http://github.com/rubenfonseca/twitter-amqp-websocket-example) +* examples/multicast.rb - broadcast all ruby tweets to all subscribers +* examples/echo.rb - server <> client exchange via a websocket diff --git a/bin/gems/em-websocket-0.5.3/Rakefile b/bin/gems/em-websocket-0.5.3/Rakefile new file mode 100644 index 00000000..0bd27180 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/Rakefile @@ -0,0 +1,11 @@ +require 'bundler' +Bundler::GemHelper.install_tasks + +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new do |t| + t.rspec_opts = ["-c", "-f progress", "-r ./spec/helper.rb"] + t.pattern = 'spec/**/*_spec.rb' +end + +task :default => :spec diff --git a/bin/gems/em-websocket-0.5.3/examples/echo.rb b/bin/gems/em-websocket-0.5.3/examples/echo.rb new file mode 100644 index 00000000..4e648860 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/examples/echo.rb @@ -0,0 +1,24 @@ +require File.expand_path('../../lib/em-websocket', __FILE__) + +EM.run { + EM::WebSocket.run(:host => "0.0.0.0", :port => 8080, :debug => false) do |ws| + ws.onopen { |handshake| + puts "WebSocket opened #{{ + :path => handshake.path, + :query => handshake.query, + :origin => handshake.origin, + }}" + + ws.send "Hello Client!" + } + ws.onmessage { |msg| + ws.send "Pong: #{msg}" + } + ws.onclose { + puts "WebSocket closed" + } + ws.onerror { |e| + puts "Error: #{e.message}" + } + end +} diff --git a/bin/gems/em-websocket-0.5.3/examples/multicast.rb b/bin/gems/em-websocket-0.5.3/examples/multicast.rb new file mode 100644 index 00000000..b1692d56 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/examples/multicast.rb @@ -0,0 +1,47 @@ +require 'em-websocket' +# requires the twitter-stream gem +require 'twitter/json_stream' +require 'json' + +# +# broadcast all ruby related tweets to all connected users! +# + +username = ARGV.shift +password = ARGV.shift +raise "need username and password" if !username or !password + +EventMachine.run { + @channel = EM::Channel.new + + @twitter = Twitter::JSONStream.connect( + :path => '/1/statuses/filter.json?track=ruby', + :auth => "#{username}:#{password}", + :ssl => true + ) + + @twitter.each_item do |status| + status = JSON.parse(status) + @channel.push "#{status['user']['screen_name']}: #{status['text']}" + end + + + EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do |ws| + + ws.onopen { + sid = @channel.subscribe { |msg| ws.send msg } + @channel.push "#{sid} connected!" + + ws.onmessage { |msg| + @channel.push "<#{sid}>: #{msg}" + } + + ws.onclose { + @channel.unsubscribe(sid) + } + } + + end + + puts "Server started" +} diff --git a/bin/gems/em-websocket-0.5.3/examples/ping.rb b/bin/gems/em-websocket-0.5.3/examples/ping.rb new file mode 100644 index 00000000..fe569c3b --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/examples/ping.rb @@ -0,0 +1,24 @@ +require File.expand_path('../../lib/em-websocket', __FILE__) + +EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => false) do |ws| + timer = nil + ws.onopen { + puts "Ping supported: #{ws.pingable?}" + timer = EM.add_periodic_timer(1) { + p ["Sent ping", ws.ping('hello')] + } + } + ws.onpong { |value| + puts "Received pong: #{value}" + } + ws.onping { |value| + puts "Received ping: #{value}" + } + ws.onclose { + EM.cancel_timer(timer) + puts "WebSocket closed" + } + ws.onerror { |e| + puts "Error: #{e.message}" + } +end diff --git a/bin/gems/em-websocket-0.5.3/examples/test.html b/bin/gems/em-websocket-0.5.3/examples/test.html new file mode 100644 index 00000000..07d4636b --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/examples/test.html @@ -0,0 +1,29 @@ + + + + + +
+ + diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket.rb new file mode 100644 index 00000000..3eaa105b --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket.rb @@ -0,0 +1,24 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib') + +require "eventmachine" + +%w[ + debugger websocket connection + handshake + handshake75 handshake76 handshake04 + framing76 framing03 framing04 framing05 framing07 + close75 close03 close05 close06 + masking04 + message_processor_03 message_processor_06 + handler handler75 handler76 handler03 handler05 handler06 handler07 handler08 handler13 +].each do |file| + require "em-websocket/#{file}" +end + +unless ''.respond_to?(:getbyte) + class String + def getbyte(i) + self[i] + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/close03.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close03.rb new file mode 100644 index 00000000..8981776f --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close03.rb @@ -0,0 +1,14 @@ +module EventMachine + module WebSocket + module Close03 + def close_websocket(code, body) + # TODO: Ideally send body data and check that it matches in ack + send_frame(:close, '') + @state = :closing + start_close_timeout + end + + def supports_close_codes?; false; end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/close05.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close05.rb new file mode 100644 index 00000000..8f8c1508 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close05.rb @@ -0,0 +1,14 @@ +module EventMachine + module WebSocket + module Close05 + def close_websocket(code, body) + # TODO: Ideally send body data and check that it matches in ack + send_frame(:close, "\x53") + @state = :closing + start_close_timeout + end + + def supports_close_codes?; false; end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/close06.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close06.rb new file mode 100644 index 00000000..14cc80ec --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close06.rb @@ -0,0 +1,19 @@ +module EventMachine + module WebSocket + module Close06 + def close_websocket(code, body) + if code + close_data = [code].pack('n') + close_data << body if body + send_frame(:close, close_data) + else + send_frame(:close, '') + end + @state = :closing + start_close_timeout + end + + def supports_close_codes?; true; end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/close75.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close75.rb new file mode 100644 index 00000000..9d6ba020 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/close75.rb @@ -0,0 +1,11 @@ +module EventMachine + module WebSocket + module Close75 + def close_websocket(code, body) + @connection.close_connection_after_writing + end + + def supports_close_codes?; false; end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/connection.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/connection.rb new file mode 100644 index 00000000..a55881df --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/connection.rb @@ -0,0 +1,349 @@ +module EventMachine + module WebSocket + class Connection < EventMachine::Connection + include Debugger + + attr_writer :max_frame_size + + # define WebSocket callbacks + def onopen(&blk); @onopen = blk; end + def onclose(&blk); @onclose = blk; end + def onerror(&blk); @onerror = blk; end + def onmessage(&blk); @onmessage = blk; end + def onbinary(&blk); @onbinary = blk; end + def onping(&blk); @onping = blk; end + def onpong(&blk); @onpong = blk; end + + def trigger_on_message(msg) + @onmessage.call(msg) if defined? @onmessage + end + def trigger_on_binary(msg) + @onbinary.call(msg) if defined? @onbinary + end + def trigger_on_open(handshake) + @onopen.call(handshake) if defined? @onopen + end + def trigger_on_close(event = {}) + @onclose.call(event) if defined? @onclose + end + def trigger_on_ping(data) + @onping.call(data) if defined? @onping + end + def trigger_on_pong(data) + @onpong.call(data) if defined? @onpong + end + def trigger_on_error(reason) + return false unless defined? @onerror + @onerror.call(reason) + true + end + + def initialize(options) + @options = options + @debug = options[:debug] || false + @secure = options[:secure] || false + @secure_proxy = options[:secure_proxy] || false + @tls_options = options[:tls_options] || {} + @close_timeout = options[:close_timeout] + @outbound_limit = options[:outbound_limit] || 0 + + @handler = nil + + debug [:initialize] + end + + # Use this method to close the websocket connection cleanly + # This sends a close frame and waits for acknowlegement before closing + # the connection + def close(code = nil, body = nil) + if code && !acceptable_close_code?(code) + raise "Application code may only use codes from 1000, 3000-4999" + end + + close_websocket_private(code, body) + end + + # Deprecated, to be removed in version 0.6 + alias :close_websocket :close + + def post_init + start_tls(@tls_options) if @secure + end + + def receive_data(data) + debug [:receive_data, data] + + if @handler + @handler.receive_data(data) + else + dispatch(data) + end + rescue => e + debug [:error, e] + + # There is no code defined for application errors, so use 3000 + # (which is reserved for frameworks) + close_websocket_private(3000, "Application error") + + # These are application errors - raise unless onerror defined + trigger_on_error(e) || raise(e) + end + + def send_data(data) + if @outbound_limit > 0 && + get_outbound_data_size + data.bytesize > @outbound_limit + abort(:outbound_limit_reached) + return 0 + end + + super(data) + end + + def unbind + debug [:unbind, :connection] + + @handler.unbind if @handler + rescue => e + debug [:error, e] + # These are application errors - raise unless onerror defined + trigger_on_error(e) || raise(e) + end + + def dispatch(data) + if data.match(%r|^GET /healthcheck|) + send_healthcheck_response + elsif data.match(/\A/) + send_flash_cross_domain_file + else + @handshake ||= begin + handshake = Handshake.new(@secure || @secure_proxy) + + handshake.callback { |upgrade_response, handler_klass| + debug [:accepting_ws_version, handshake.protocol_version] + debug [:upgrade_response, upgrade_response] + self.send_data(upgrade_response) + @handler = handler_klass.new(self, @debug) + @handshake = nil + trigger_on_open(handshake) + } + + handshake.errback { |e| + debug [:error, e] + trigger_on_error(e) + # Handshake errors require the connection to be aborted + abort(:handshake_error) + } + + handshake + end + + @handshake.receive_data(data) + end + end + + def send_healthcheck_response + debug [:healthcheck, 'OK'] + + healthcheck_res = ["HTTP/1.1 200 OK"] + healthcheck_res << "Content-Type: text/plain" + healthcheck_res << "Content-Length: 2" + + healthcheck_res = healthcheck_res.join("\r\n") + "\r\n\r\nOK" + + send_data healthcheck_res + + # handle the healthcheck request transparently + # no need to notify the user about this connection + @onclose = nil + close_connection_after_writing + end + + def send_flash_cross_domain_file + file = '' + debug [:cross_domain, file] + send_data file + + # handle the cross-domain request transparently + # no need to notify the user about this connection + @onclose = nil + close_connection_after_writing + end + + # Cache encodings since it's moderately expensive to look them up each time + ENCODING_SUPPORTED = "string".respond_to?(:force_encoding) + UTF8 = Encoding.find("UTF-8") if ENCODING_SUPPORTED + BINARY = Encoding.find("BINARY") if ENCODING_SUPPORTED + + # Send a WebSocket text frame. + # + # A WebSocketError may be raised if the connection is in an opening or a + # closing state, or if the passed in data is not valid UTF-8 + # + def send_text(data) + # If we're using Ruby 1.9, be pedantic about encodings + if ENCODING_SUPPORTED + # Also accept ascii only data in other encodings for convenience + unless (data.encoding == UTF8 && data.valid_encoding?) || data.ascii_only? + raise WebSocketError, "Data sent to WebSocket must be valid UTF-8 but was #{data.encoding} (valid: #{data.valid_encoding?})" + end + # This labels the encoding as binary so that it can be combined with + # the BINARY framing + data.force_encoding(BINARY) + else + # TODO: Check that data is valid UTF-8 + end + + if @handler + @handler.send_text_frame(data) + else + raise WebSocketError, "Cannot send data before onopen callback" + end + + # Revert data back to the original encoding (which we assume is UTF-8) + # Doing this to avoid duping the string - there may be a better way + data.force_encoding(UTF8) if ENCODING_SUPPORTED + return nil + end + + alias :send :send_text + + # Send a WebSocket binary frame. + # + def send_binary(data) + if @handler + @handler.send_frame(:binary, data) + else + raise WebSocketError, "Cannot send binary before onopen callback" + end + end + + # Send a ping to the client. The client must respond with a pong. + # + # In the case that the client is running a WebSocket draft < 01, false + # is returned since ping & pong are not supported + # + def ping(body = '') + if @handler + @handler.pingable? ? @handler.send_frame(:ping, body) && true : false + else + raise WebSocketError, "Cannot ping before onopen callback" + end + end + + # Send an unsolicited pong message, as allowed by the protocol. The + # client is not expected to respond to this message. + # + # em-websocket automatically takes care of sending pong replies to + # incoming ping messages, as the protocol demands. + # + def pong(body = '') + if @handler + @handler.pingable? ? @handler.send_frame(:pong, body) && true : false + else + raise WebSocketError, "Cannot ping before onopen callback" + end + end + + # Test whether the connection is pingable (i.e. the WebSocket draft in + # use is >= 01) + def pingable? + if @handler + @handler.pingable? + else + raise WebSocketError, "Cannot test whether pingable before onopen callback" + end + end + + def supports_close_codes? + if @handler + @handler.supports_close_codes? + else + raise WebSocketError, "Cannot test before onopen callback" + end + end + + def state + @handler ? @handler.state : :handshake + end + + # Returns the IP address for the remote peer + def remote_ip + get_peername[2,6].unpack('nC4')[1..4].join('.') + end + + # Returns the maximum frame size which this connection is configured to + # accept. This can be set globally or on a per connection basis, and + # defaults to a value of 10MB if not set. + # + # The behaviour when a too large frame is received varies by protocol, + # but in the newest protocols the connection will be closed with the + # correct close code (1009) immediately after receiving the frame header + # + def max_frame_size + defined?(@max_frame_size) ? @max_frame_size : WebSocket.max_frame_size + end + + def close_timeout + @close_timeout || WebSocket.close_timeout + end + + private + + # As definited in draft 06 7.2.2, some failures require that the server + # abort the websocket connection rather than close cleanly + def abort(reason) + debug [:abort, reason] + close_connection + end + + def close_websocket_private(code, body) + if @handler + debug [:closing, code] + @handler.close_websocket(code, body) + else + # The handshake hasn't completed - should be safe to terminate + abort(:handshake_incomplete) + end + end + + # Allow applications to close with 1000, 1003, 1008, 1011, 3xxx or 4xxx. + # + # em-websocket uses a few other codes internally which should not be + # used by applications + # + # Browsers generally allow connections to be closed with code 1000, + # 3xxx, and 4xxx. em-websocket allows closing with a few other codes + # which seem reasonable (for discussion see + # https://github.com/igrigorik/em-websocket/issues/98) + # + # Usage from the rfc: + # + # 1000 indicates a normal closure + # + # 1003 indicates that an endpoint is terminating the connection + # because it has received a type of data it cannot accept + # + # 1008 indicates that an endpoint is terminating the connection because + # it has received a message that violates its policy + # + # 1011 indicates that a server is terminating the connection because it + # encountered an unexpected condition that prevented it from fulfilling + # the request + # + # Status codes in the range 3000-3999 are reserved for use by libraries, + # frameworks, and applications + # + # Status codes in the range 4000-4999 are reserved for private use and + # thus can't be registered + # + def acceptable_close_code?(code) + case code + when 1000, 1003, 1008, 1011, (3000..4999) + true + else + false + end + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/debugger.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/debugger.rb new file mode 100644 index 00000000..a5b32668 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/debugger.rb @@ -0,0 +1,17 @@ +module EventMachine + module WebSocket + module Debugger + + private + + def debug(*data) + if @debug + require 'pp' + pp data + puts + end + end + + end + end +end \ No newline at end of file diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing03.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing03.rb new file mode 100644 index 00000000..61e6ab8b --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing03.rb @@ -0,0 +1,162 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + module Framing03 + def initialize_framing + @data = '' + @application_data_buffer = '' # Used for MORE frames + @frame_type = nil + end + + def process_data + error = false + + while !error && @data.size > 1 + pointer = 0 + + more = ((@data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin + # Ignoring rsv1-3 for now + opcode = @data.getbyte(0) & 0b00001111 + pointer += 1 + + # Ignoring rsv4 + length = @data.getbyte(pointer) & 0b01111111 + pointer += 1 + + payload_length = case length + when 127 # Length defined by 8 bytes + # Check buffer size + if @data.getbyte(pointer+8-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Only using the last 4 bytes for now, till I work out how to + # unpack 8 bytes. I'm sure 4GB frames will do for now :) + l = @data[(pointer+4)..(pointer+7)].unpack('N').first + pointer += 8 + l + when 126 # Length defined by 2 bytes + # Check buffer size + if @data.getbyte(pointer+2-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + l = @data[pointer..(pointer+1)].unpack('n').first + pointer += 2 + l + else + length + end + + if payload_length > @connection.max_frame_size + raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)" + end + + # Check buffer size + if @data.getbyte(pointer+payload_length-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Throw away data up to pointer + @data.slice!(0...pointer) + + # Read application data + application_data = @data.slice!(0...payload_length) + + frame_type = opcode_to_type(opcode) + + if frame_type == :continuation && !@frame_type + raise WSProtocolError, 'Continuation frame not expected' + end + + if more + debug [:moreframe, frame_type, application_data] + @application_data_buffer << application_data + # The message type is passed in the first frame + @frame_type ||= frame_type + else + # Message is complete + if frame_type == :continuation + @application_data_buffer << application_data + message(@frame_type, '', @application_data_buffer) + @application_data_buffer = '' + @frame_type = nil + else + message(frame_type, '', application_data) + end + end + end # end while + end + + def send_frame(frame_type, application_data) + debug [:sending_frame, frame_type, application_data] + + if @state == :closing && data_frame?(frame_type) + raise WebSocketError, "Cannot send data frame since connection is closing" + end + + frame = '' + + opcode = type_to_opcode(frame_type) + byte1 = opcode # since more, rsv1-3 are 0 + frame << byte1 + + length = application_data.size + if length <= 125 + byte2 = length # since rsv4 is 0 + frame << byte2 + elsif length < 65536 # write 2 byte length + frame << 126 + frame << [length].pack('n') + else # write 8 byte length + frame << 127 + frame << [length >> 32, length & 0xFFFFFFFF].pack("NN") + end + + frame << application_data + + @connection.send_data(frame) + end + + def send_text_frame(data) + send_frame(:text, data) + end + + private + + # This allows flipping the more bit to fin for draft 04 + def fin; false; end + + FRAME_TYPES = { + :continuation => 0, + :close => 1, + :ping => 2, + :pong => 3, + :text => 4, + :binary => 5 + } + FRAME_TYPES_INVERSE = FRAME_TYPES.invert + # Frames are either data frames or control frames + DATA_FRAMES = [:text, :binary, :continuation] + + def type_to_opcode(frame_type) + FRAME_TYPES[frame_type] || raise("Unknown frame type") + end + + def opcode_to_type(opcode) + FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}") + end + + def data_frame?(type) + DATA_FRAMES.include?(type) + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing04.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing04.rb new file mode 100644 index 00000000..41352e63 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing04.rb @@ -0,0 +1,15 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + # The only difference between draft 03 framing and draft 04 framing is + # that the MORE bit has been changed to a FIN bit + module Framing04 + include Framing03 + + private + + def fin; true; end + end + end +end \ No newline at end of file diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing05.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing05.rb new file mode 100644 index 00000000..636336aa --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing05.rb @@ -0,0 +1,163 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + module Framing05 + def initialize_framing + @data = MaskedString.new + @application_data_buffer = '' # Used for MORE frames + @frame_type = nil + end + + def process_data + error = false + + while !error && @data.size > 5 # mask plus first byte present + pointer = 0 + + @data.read_mask + pointer += 4 + + fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000 + # Ignoring rsv1-3 for now + opcode = @data.getbyte(pointer) & 0b00001111 + pointer += 1 + + # Ignoring rsv4 + length = @data.getbyte(pointer) & 0b01111111 + pointer += 1 + + payload_length = case length + when 127 # Length defined by 8 bytes + # Check buffer size + if @data.getbyte(pointer+8-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Only using the last 4 bytes for now, till I work out how to + # unpack 8 bytes. I'm sure 4GB frames will do for now :) + l = @data.getbytes(pointer+4, 4).unpack('N').first + pointer += 8 + l + when 126 # Length defined by 2 bytes + # Check buffer size + if @data.getbyte(pointer+2-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + l = @data.getbytes(pointer, 2).unpack('n').first + pointer += 2 + l + else + length + end + + if payload_length > @connection.max_frame_size + raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)" + end + + # Check buffer size + if @data.getbyte(pointer+payload_length-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Read application data + application_data = @data.getbytes(pointer, payload_length) + pointer += payload_length + + # Throw away data up to pointer + @data.unset_mask + @data.slice!(0...pointer) + + frame_type = opcode_to_type(opcode) + + if frame_type == :continuation && !@frame_type + raise WSProtocolError, 'Continuation frame not expected' + end + + if !fin + debug [:moreframe, frame_type, application_data] + @application_data_buffer << application_data + @frame_type = frame_type + else + # Message is complete + if frame_type == :continuation + @application_data_buffer << application_data + message(@frame_type, '', @application_data_buffer) + @application_data_buffer = '' + @frame_type = nil + else + message(frame_type, '', application_data) + end + end + end # end while + end + + def send_frame(frame_type, application_data) + debug [:sending_frame, frame_type, application_data] + + if @state == :closing && data_frame?(frame_type) + raise WebSocketError, "Cannot send data frame since connection is closing" + end + + frame = '' + + opcode = type_to_opcode(frame_type) + byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0 + frame << byte1 + + length = application_data.size + if length <= 125 + byte2 = length # since rsv4 is 0 + frame << byte2 + elsif length < 65536 # write 2 byte length + frame << 126 + frame << [length].pack('n') + else # write 8 byte length + frame << 127 + frame << [length >> 32, length & 0xFFFFFFFF].pack("NN") + end + + frame << application_data + + @connection.send_data(frame) + end + + def send_text_frame(data) + send_frame(:text, data) + end + + private + + FRAME_TYPES = { + :continuation => 0, + :close => 1, + :ping => 2, + :pong => 3, + :text => 4, + :binary => 5 + } + FRAME_TYPES_INVERSE = FRAME_TYPES.invert + # Frames are either data frames or control frames + DATA_FRAMES = [:text, :binary, :continuation] + + def type_to_opcode(frame_type) + FRAME_TYPES[frame_type] || raise("Unknown frame type") + end + + def opcode_to_type(opcode) + FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}") + end + + def data_frame?(type) + DATA_FRAMES.include?(type) + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing07.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing07.rb new file mode 100644 index 00000000..58318e41 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing07.rb @@ -0,0 +1,185 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + module Framing07 + + def initialize_framing + @data = MaskedString.new + @application_data_buffer = '' # Used for MORE frames + @frame_type = nil + end + + def process_data + error = false + + while !error && @data.size >= 2 + pointer = 0 + + fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000 + # Ignoring rsv1-3 for now + opcode = @data.getbyte(pointer) & 0b00001111 + pointer += 1 + + mask = (@data.getbyte(pointer) & 0b10000000) == 0b10000000 + length = @data.getbyte(pointer) & 0b01111111 + pointer += 1 + + # raise WebSocketError, 'Data from client must be masked' unless mask + + payload_length = case length + when 127 # Length defined by 8 bytes + # Check buffer size + if @data.getbyte(pointer+8-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Only using the last 4 bytes for now, till I work out how to + # unpack 8 bytes. I'm sure 4GB frames will do for now :) + l = @data.getbytes(pointer+4, 4).unpack('N').first + pointer += 8 + l + when 126 # Length defined by 2 bytes + # Check buffer size + if @data.getbyte(pointer+2-1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + l = @data.getbytes(pointer, 2).unpack('n').first + pointer += 2 + l + else + length + end + + # Compute the expected frame length + frame_length = pointer + payload_length + frame_length += 4 if mask + + if frame_length > @connection.max_frame_size + raise WSMessageTooBigError, "Frame length too long (#{frame_length} bytes)" + end + + # Check buffer size + if @data.getbyte(frame_length - 1) == nil + debug [:buffer_incomplete, @data] + error = true + next + end + + # Remove frame header + @data.slice!(0...pointer) + pointer = 0 + + # Read application data (unmasked if required) + @data.read_mask if mask + pointer += 4 if mask + application_data = @data.getbytes(pointer, payload_length) + pointer += payload_length + @data.unset_mask if mask + + # Throw away data up to pointer + @data.slice!(0...pointer) + + frame_type = opcode_to_type(opcode) + + if frame_type == :continuation + if !@frame_type + raise WSProtocolError, 'Continuation frame not expected' + end + else # Not a continuation frame + if @frame_type && data_frame?(frame_type) + raise WSProtocolError, "Continuation frame expected" + end + end + + # Validate that control frames are not fragmented + if !fin && !data_frame?(frame_type) + raise WSProtocolError, 'Control frames must not be fragmented' + end + + if !fin + debug [:moreframe, frame_type, application_data] + @application_data_buffer << application_data + # The message type is passed in the first frame + @frame_type ||= frame_type + else + # Message is complete + if frame_type == :continuation + @application_data_buffer << application_data + message(@frame_type, '', @application_data_buffer) + @application_data_buffer = '' + @frame_type = nil + else + message(frame_type, '', application_data) + end + end + end # end while + end + + def send_frame(frame_type, application_data) + debug [:sending_frame, frame_type, application_data] + + if @state == :closing && data_frame?(frame_type) + raise WebSocketError, "Cannot send data frame since connection is closing" + end + + frame = '' + + opcode = type_to_opcode(frame_type) + byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0 + frame << byte1 + + length = application_data.size + if length <= 125 + byte2 = length # since rsv4 is 0 + frame << byte2 + elsif length < 65536 # write 2 byte length + frame << 126 + frame << [length].pack('n') + else # write 8 byte length + frame << 127 + frame << [length >> 32, length & 0xFFFFFFFF].pack("NN") + end + + frame << application_data + + @connection.send_data(frame) + end + + def send_text_frame(data) + send_frame(:text, data) + end + + private + + FRAME_TYPES = { + :continuation => 0, + :text => 1, + :binary => 2, + :close => 8, + :ping => 9, + :pong => 10, + } + FRAME_TYPES_INVERSE = FRAME_TYPES.invert + # Frames are either data frames or control frames + DATA_FRAMES = [:text, :binary, :continuation] + + def type_to_opcode(frame_type) + FRAME_TYPES[frame_type] || raise("Unknown frame type") + end + + def opcode_to_type(opcode) + FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}") + end + + def data_frame?(type) + DATA_FRAMES.include?(type) + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing76.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing76.rb new file mode 100644 index 00000000..55982ffa --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/framing76.rb @@ -0,0 +1,105 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + module Framing76 + def initialize_framing + @data = '' + end + + def process_data + debug [:message, @data] + + # This algorithm comes straight from the spec + # http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-5.3 + + error = false + + while !error + return if @data.size == 0 + + pointer = 0 + frame_type = @data.getbyte(pointer) + pointer += 1 + + if (frame_type & 0x80) == 0x80 + # If the high-order bit of the /frame type/ byte is set + length = 0 + + loop do + return false if !@data.getbyte(pointer) + b = @data.getbyte(pointer) + pointer += 1 + b_v = b & 0x7F + length = length * 128 + b_v + break unless (b & 0x80) == 0x80 + end + + if length > @connection.max_frame_size + raise WSMessageTooBigError, "Frame length too long (#{length} bytes)" + end + + if @data.getbyte(pointer+length-1) == nil + debug [:buffer_incomplete, @data] + # Incomplete data - leave @data to accumulate + error = true + else + # Straight from spec - I'm sure this isn't crazy... + # 6. Read /length/ bytes. + # 7. Discard the read bytes. + @data = @data[(pointer+length)..-1] + + # If the /frame type/ is 0xFF and the /length/ was 0, then close + if length == 0 + @connection.send_data("\xff\x00") + @state = :closing + @connection.close_connection_after_writing + else + error = true + end + end + else + # If the high-order bit of the /frame type/ byte is _not_ set + + if @data.getbyte(0) != 0x00 + # Close the connection since this buffer can never match + raise WSProtocolError, "Invalid frame received" + end + + # Addition to the spec to protect against malicious requests + if @data.size > @connection.max_frame_size + raise WSMessageTooBigError, "Frame length too long (#{@data.size} bytes)" + end + + msg = @data.slice!(/\A\x00[^\xff]*\xff/) + if msg + msg.gsub!(/\A\x00|\xff\z/, '') + if @state == :closing + debug [:ignored_message, msg] + else + msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding) + @connection.trigger_on_message(msg) + end + else + error = true + end + end + end + + false + end + + # frames need to start with 0x00-0x7f byte and end with + # an 0xFF byte. Per spec, we can also set the first + # byte to a value betweent 0x80 and 0xFF, followed by + # a leading length indicator + def send_text_frame(data) + debug [:sending_text_frame, data] + ary = ["\x00", data, "\xff"] + ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) } + @connection.send_data(ary.join) + end + + end + end +end \ No newline at end of file diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler.rb new file mode 100644 index 00000000..98cdd4ea --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler.rb @@ -0,0 +1,97 @@ +module EventMachine + module WebSocket + class Handler + def self.klass_factory(version) + case version + when 75 + Handler75 + when 76 + Handler76 + when 1..3 + # We'll use handler03 - I believe they're all compatible + Handler03 + when 5 + Handler05 + when 6 + Handler06 + when 7 + Handler07 + when 8 + # drafts 9, 10, 11 and 12 should never change the version + # number as they are all the same as version 08. + Handler08 + when 13 + # drafts 13 to 17 all identify as version 13 as they are + # only minor changes or text changes. + Handler13 + else + # According to spec should abort the connection + raise HandshakeError, "Protocol version #{version} not supported" + end + end + + include Debugger + + attr_reader :request, :state + + def initialize(connection, debug = false) + @connection = connection + @debug = debug + @state = :connected + @close_timer = nil + initialize_framing + end + + def receive_data(data) + @data << data + process_data + rescue WSProtocolError => e + fail_websocket(e) + end + + def close_websocket(code, body) + # Implemented in subclass + end + + # Used to avoid un-acked and unclosed remaining open indefinitely + def start_close_timeout + @close_timer = EM::Timer.new(@connection.close_timeout) { + @connection.close_connection + e = WSProtocolError.new("Close handshake un-acked after #{@connection.close_timeout}s, closing tcp connection") + @connection.trigger_on_error(e) + } + end + + # This corresponds to "Fail the WebSocket Connection" in the spec. + def fail_websocket(e) + debug [:error, e] + close_websocket(e.code, e.message) + @connection.close_connection_after_writing + @connection.trigger_on_error(e) + end + + def unbind + @state = :closed + + @close_timer.cancel if @close_timer + + @close_info = defined?(@close_info) ? @close_info : { + :code => 1006, + :was_clean => false, + } + + @connection.trigger_on_close(@close_info) + end + + def ping + # Overridden in subclass + false + end + + def pingable? + # Also Overridden + false + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler03.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler03.rb new file mode 100644 index 00000000..ac4b3ac4 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler03.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler03 < Handler + include Framing03 + include MessageProcessor03 + include Close03 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler05.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler05.rb new file mode 100644 index 00000000..4e48e152 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler05.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler05 < Handler + include Framing05 + include MessageProcessor03 + include Close05 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler06.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler06.rb new file mode 100644 index 00000000..ad55ef71 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler06.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler06 < Handler + include Framing05 + include MessageProcessor06 + include Close06 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler07.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler07.rb new file mode 100644 index 00000000..d080cf59 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler07.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler07 < Handler + include Framing07 + include MessageProcessor06 + include Close06 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler08.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler08.rb new file mode 100644 index 00000000..632057f3 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler08.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler08 < Handler + include Framing07 + include MessageProcessor06 + include Close06 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler13.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler13.rb new file mode 100644 index 00000000..1dc465d8 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler13.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler13 < Handler + include Framing07 + include MessageProcessor06 + include Close06 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler75.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler75.rb new file mode 100644 index 00000000..d9a90d37 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler75.rb @@ -0,0 +1,9 @@ +module EventMachine + module WebSocket + class Handler75 < Handler + include Handshake75 + include Framing76 + include Close75 + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler76.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler76.rb new file mode 100644 index 00000000..c4aaa377 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handler76.rb @@ -0,0 +1,14 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + class Handler76 < Handler + include Handshake76 + include Framing76 + include Close75 + + # "\377\000" is octet version and "\xff\x00" is hex version + TERMINATE_STRING = "\xff\x00" + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake.rb new file mode 100644 index 00000000..12b79044 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake.rb @@ -0,0 +1,156 @@ +require "http/parser" +require "uri" + +module EventMachine + module WebSocket + + # Resposible for creating the server handshake response + class Handshake + include EM::Deferrable + + attr_reader :parser, :protocol_version + + # Unfortunately drafts 75 & 76 require knowledge of whether the + # connection is being terminated as ws/wss in order to generate the + # correct handshake response + def initialize(secure) + @parser = Http::Parser.new + @secure = secure + + @parser.on_headers_complete = proc { |headers| + @headers = Hash[headers.map { |k,v| [k.downcase, v] }] + } + end + + def receive_data(data) + @parser << data + + if defined? @headers + process(@headers, @parser.upgrade_data) + end + rescue HTTP::Parser::Error => e + fail(HandshakeError.new("Invalid HTTP header: #{e.message}")) + end + + # Returns the WebSocket upgrade headers as a hash. + # + # Keys are strings, unmodified from the request. + # + def headers + @parser.headers + end + + # The same as headers, except that the hash keys are downcased + # + def headers_downcased + @headers + end + + # Returns the request path (excluding any query params) + # + def path + @path + end + + # Returns the query params as a string foo=bar&baz=... + def query_string + @query_string + end + + def query + Hash[query_string.split('&').map { |c| c.split('=', 2) }] + end + + # Returns the WebSocket origin header if provided + # + def origin + @headers["origin"] || @headers["sec-websocket-origin"] || nil + end + + def secure? + @secure + end + + private + + def process(headers, remains) + unless @parser.http_method == "GET" + raise HandshakeError, "Must be GET request" + end + + # Validate request path + # + # According to http://tools.ietf.org/search/rfc2616#section-5.1.2, an + # invalid Request-URI should result in a 400 status code, but + # HandshakeError's currently result in a WebSocket abort. It's not + # clear which should take precedence, but an abort will do just fine. + begin + uri = URI.parse(@parser.request_url) + @path = uri.path + @query_string = uri.query || "" + rescue URI::InvalidURIError + raise HandshakeError, "Invalid request URI: #{@parser.request_url}" + end + + # Validate Upgrade + unless @parser.upgrade? + raise HandshakeError, "Not an upgrade request" + end + upgrade = @headers['upgrade'] + unless upgrade.kind_of?(String) && upgrade.downcase == 'websocket' + raise HandshakeError, "Invalid upgrade header: #{upgrade.inspect}" + end + + # Determine version heuristically + version = if @headers['sec-websocket-version'] + # Used from drafts 04 onwards + @headers['sec-websocket-version'].to_i + elsif @headers['sec-websocket-draft'] + # Used in drafts 01 - 03 + @headers['sec-websocket-draft'].to_i + elsif @headers['sec-websocket-key1'] + 76 + else + 75 + end + + # Additional handling of bytes after the header if required + case version + when 75 + if !remains.empty? + raise HandshakeError, "Extra bytes after header" + end + when 76, 1..3 + if remains.length < 8 + # The whole third-key has not been received yet. + return nil + elsif remains.length > 8 + raise HandshakeError, "Extra bytes after third key" + end + @headers['third-key'] = remains + end + + handshake_klass = case version + when 75 + Handshake75 + when 76, 1..3 + Handshake76 + when 5, 6, 7, 8, 13 + Handshake04 + else + # According to spec should abort the connection + raise HandshakeError, "Protocol version #{version} not supported" + end + + upgrade_response = handshake_klass.handshake(@headers, @parser.request_url, @secure) + + handler_klass = Handler.klass_factory(version) + + @protocol_version = version + succeed(upgrade_response, handler_klass) + rescue HandshakeError => e + fail(e) + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake04.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake04.rb new file mode 100644 index 00000000..76007876 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake04.rb @@ -0,0 +1,37 @@ +require 'digest/sha1' +require 'base64' + +module EventMachine + module WebSocket + module Handshake04 + def self.handshake(headers, _, __) + # Required + unless key = headers['sec-websocket-key'] + raise HandshakeError, "sec-websocket-key header is required" + end + + string_to_sign = "#{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + signature = Base64.encode64(Digest::SHA1.digest(string_to_sign)).chomp + + upgrade = ["HTTP/1.1 101 Switching Protocols"] + upgrade << "Upgrade: websocket" + upgrade << "Connection: Upgrade" + upgrade << "Sec-WebSocket-Accept: #{signature}" + if protocol = headers['sec-websocket-protocol'] + validate_protocol!(protocol) + upgrade << "Sec-WebSocket-Protocol: #{protocol}" + end + + # TODO: Support sec-websocket-protocol selection + # TODO: sec-websocket-extensions + + return upgrade.join("\r\n") + "\r\n\r\n" + end + + def self.validate_protocol!(protocol) + raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty? + # TODO: Validate characters + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake75.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake75.rb new file mode 100644 index 00000000..65b744fc --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake75.rb @@ -0,0 +1,28 @@ +module EventMachine + module WebSocket + module Handshake75 + def self.handshake(headers, path, secure) + scheme = (secure ? "wss" : "ws") + location = "#{scheme}://#{headers['host']}#{path}" + + upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" + upgrade << "Upgrade: WebSocket\r\n" + upgrade << "Connection: Upgrade\r\n" + upgrade << "WebSocket-Origin: #{headers['origin']}\r\n" + upgrade << "WebSocket-Location: #{location}\r\n" + if protocol = headers['sec-websocket-protocol'] + validate_protocol!(protocol) + upgrade << "Sec-WebSocket-Protocol: #{protocol}\r\n" + end + upgrade << "\r\n" + + return upgrade + end + + def self.validate_protocol!(protocol) + raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty? + # TODO: Validate characters + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake76.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake76.rb new file mode 100644 index 00000000..c18260de --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/handshake76.rb @@ -0,0 +1,72 @@ +require 'digest/md5' + +module EventMachine::WebSocket + module Handshake76 + class << self + def handshake(headers, path, secure) + challenge_response = solve_challenge( + headers['sec-websocket-key1'], + headers['sec-websocket-key2'], + headers['third-key'] + ) + + scheme = (secure ? "wss" : "ws") + location = "#{scheme}://#{headers['host']}#{path}" + + upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" + upgrade << "Upgrade: WebSocket\r\n" + upgrade << "Connection: Upgrade\r\n" + upgrade << "Sec-WebSocket-Location: #{location}\r\n" + upgrade << "Sec-WebSocket-Origin: #{headers['origin']}\r\n" + if protocol = headers['sec-websocket-protocol'] + validate_protocol!(protocol) + upgrade << "Sec-WebSocket-Protocol: #{protocol}\r\n" + end + upgrade << "\r\n" + upgrade << challenge_response + + return upgrade + end + + private + + def solve_challenge(first, second, third) + # Refer to 5.2 4-9 of the draft 76 + sum = [numbers_over_spaces(first)].pack("N*") + + [numbers_over_spaces(second)].pack("N*") + + third + Digest::MD5.digest(sum) + end + + def numbers_over_spaces(string) + unless string + raise HandshakeError, "WebSocket key1 or key2 is missing" + end + + numbers = string.scan(/[0-9]/).join.to_i + + spaces = string.scan(/ /).size + # As per 5.2.5, abort the connection if spaces are zero. + raise HandshakeError, "Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack" if spaces == 0 + + # As per 5.2.6, abort if numbers is not an integral multiple of spaces + if numbers % spaces != 0 + raise HandshakeError, "Invalid Key #{string.inspect}" + end + + quotient = numbers / spaces + + if quotient > 2**32-1 + raise HandshakeError, "Challenge computation out of range for key #{string.inspect}" + end + + return quotient + end + + def validate_protocol!(protocol) + raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty? + # TODO: Validate characters + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/masking04.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/masking04.rb new file mode 100644 index 00000000..ad050e9a --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/masking04.rb @@ -0,0 +1,37 @@ +module EventMachine + module WebSocket + class MaskedString < String + # Read a 4 bit XOR mask - further requested bytes will be unmasked + def read_mask + if respond_to?(:encoding) && encoding.name != "ASCII-8BIT" + raise "MaskedString only operates on BINARY strings" + end + raise "Too short" if bytesize < 4 # TODO - change + @masking_key = String.new(self[0..3]) + end + + # Removes the mask, behaves like a normal string again + def unset_mask + @masking_key = nil + end + + def getbyte(index) + if defined?(@masking_key) && @masking_key + masked_char = super + masked_char ? masked_char ^ @masking_key.getbyte(index % 4) : nil + else + super + end + end + + def getbytes(start_index, count) + data = '' + data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding) + count.times do |i| + data << getbyte(start_index + i) + end + data + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_03.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_03.rb new file mode 100644 index 00000000..c5dec700 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_03.rb @@ -0,0 +1,47 @@ +# encoding: BINARY + +module EventMachine + module WebSocket + module MessageProcessor03 + def message(message_type, extension_data, application_data) + case message_type + when :close + @close_info = { + :code => 1005, + :reason => "", + :was_clean => true, + } + if @state == :closing + # TODO: Check that message body matches sent data + # We can close connection immediately since there is no more data + # is allowed to be sent or received on this connection + @connection.close_connection + else + # Acknowlege close + # The connection is considered closed + send_frame(:close, application_data) + @connection.close_connection_after_writing + end + when :ping + # Pong back the same data + send_frame(:pong, application_data) + @connection.trigger_on_ping(application_data) + when :pong + @connection.trigger_on_pong(application_data) + when :text + if application_data.respond_to?(:force_encoding) + application_data.force_encoding("UTF-8") + end + @connection.trigger_on_message(application_data) + when :binary + @connection.trigger_on_binary(application_data) + end + end + + # Ping & Pong supported + def pingable? + true + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_06.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_06.rb new file mode 100644 index 00000000..25ca5d2d --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/message_processor_06.rb @@ -0,0 +1,78 @@ +module EventMachine + module WebSocket + module MessageProcessor06 + def message(message_type, extension_data, application_data) + debug [:message_received, message_type, application_data] + + case message_type + when :close + status_code = case application_data.length + when 0 + # close messages MAY contain a body + nil + when 1 + # Illegal close frame + raise WSProtocolError, "Close frames with a body must contain a 2 byte status code" + else + application_data.slice!(0, 2).unpack('n').first + end + + debug [:close_frame_received, status_code, application_data] + + @close_info = { + :code => status_code || 1005, + :reason => application_data, + :was_clean => true, + } + + if @state == :closing + # We can close connection immediately since no more data may be + # sent or received on this connection + @connection.close_connection + elsif @state == :connected + # Acknowlege close & echo status back to client + # The connection is considered closed + close_data = [status_code || 1000].pack('n') + send_frame(:close, close_data) + @connection.close_connection_after_writing + end + when :ping + # There are a couple of protections here against malicious/broken WebSocket abusing ping frames. + # + # 1. Delay 200ms before replying. This reduces the number of pings from WebSocket clients behaving as + # `for (;;) { send_ping(conn); rcv_pong(conn); }`. The spec says we "SHOULD respond with Pong frame as soon + # as is practical". + # 2. Reply at most every 200ms. This reduces the number of pong frames sent to WebSocket clients behaving as + # `for (;;) { send_ping(conn); }`. The spec says "If an endpoint receives a Ping frame and has not yet sent + # Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only + # the most recently processed Ping frame." + @most_recent_pong_application_data = application_data + if @pong_timer == nil then + @pong_timer = EventMachine.add_timer(0.2) do + @pong_timer = nil + send_frame(:pong, @most_recent_pong_application_data) + end + end + @connection.trigger_on_ping(application_data) + when :pong + @connection.trigger_on_pong(application_data) + when :text + if application_data.respond_to?(:force_encoding) + application_data.force_encoding("UTF-8") + unless application_data.valid_encoding? + raise InvalidDataError, "Invalid UTF8 data" + end + end + @connection.trigger_on_message(application_data) + when :binary + @connection.trigger_on_binary(application_data) + end + end + + # Ping & Pong supported + def pingable? + true + end + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/version.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/version.rb new file mode 100644 index 00000000..ecdedbe4 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/version.rb @@ -0,0 +1,5 @@ +module EventMachine + module Websocket + VERSION = "0.5.3" + end +end diff --git a/bin/gems/em-websocket-0.5.3/lib/em-websocket/websocket.rb b/bin/gems/em-websocket-0.5.3/lib/em-websocket/websocket.rb new file mode 100644 index 00000000..02e4d86f --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/lib/em-websocket/websocket.rb @@ -0,0 +1,56 @@ +module EventMachine + module WebSocket + class << self + attr_accessor :max_frame_size + attr_accessor :close_timeout + end + @max_frame_size = 10 * 1024 * 1024 # 10MB + # Connections are given 60s to close after being sent a close handshake + @close_timeout = 60 + + # All errors raised by em-websocket should descend from this class + class WebSocketError < RuntimeError; end + + # Used for errors that occur during WebSocket handshake + class HandshakeError < WebSocketError; end + + # Used for errors which should cause the connection to close. + # See RFC6455 §7.4.1 for a full description of meanings + class WSProtocolError < WebSocketError + def code; 1002; end + end + + class InvalidDataError < WSProtocolError + def code; 1007; end + end + + # 1009: Message too big to process + class WSMessageTooBigError < WSProtocolError + def code; 1009; end + end + + # Start WebSocket server, including starting eventmachine run loop + def self.start(options, &blk) + EM.epoll + EM.run { + trap("TERM") { stop } + trap("INT") { stop } + + run(options, &blk) + } + end + + # Start WebSocket server inside eventmachine run loop + def self.run(options) + host, port = options.values_at(:host, :port) + EM.start_server(host, port, Connection, options) do |c| + yield c + end + end + + def self.stop + puts "Terminating WebSocket Server" + EM.stop + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/helper.rb b/bin/gems/em-websocket-0.5.3/spec/helper.rb new file mode 100644 index 00000000..76e45b56 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/helper.rb @@ -0,0 +1,173 @@ +# encoding: BINARY + +require 'rubygems' +require 'rspec' +require 'em-spec/rspec' +require 'em-http' + +require 'em-websocket' +require 'em-websocket-client' + +require 'integration/shared_examples' +require 'integration/gte_03_examples' + +RSpec.configure do |c| + c.mock_with :rspec +end + +class FakeWebSocketClient < EM::Connection + attr_reader :handshake_response, :packets + + def onopen(&blk); @onopen = blk; end + def onclose(&blk); @onclose = blk; end + def onerror(&blk); @onerror = blk; end + def onmessage(&blk); @onmessage = blk; end + + def initialize + @state = :new + @packets = [] + end + + def receive_data(data) + # puts "RECEIVE DATA #{data}" + if @state == :new + @handshake_response = data + @onopen.call if defined? @onopen + @state = :open + else + @onmessage.call(data) if defined? @onmessage + @packets << data + end + end + + def send(application_data) + send_frame(:text, application_data) + end + + def send_frame(type, application_data) + send_data construct_frame(type, application_data) + end + + def unbind + @onclose.call if defined? @onclose + end + + private + + def construct_frame(type, data) + "\x00#{data}\xff" + end +end + +class Draft03FakeWebSocketClient < FakeWebSocketClient + private + + def construct_frame(type, data) + frame = "" + frame << EM::WebSocket::Framing03::FRAME_TYPES[type] + frame << encoded_length(data.size) + frame << data + end + + def encoded_length(length) + if length <= 125 + [length].pack('C') # since rsv4 is 0 + elsif length < 65536 # write 2 byte length + "\126#{[length].pack('n')}" + else # write 8 byte length + "\127#{[length >> 32, length & 0xFFFFFFFF].pack("NN")}" + end + end +end + +class Draft05FakeWebSocketClient < Draft03FakeWebSocketClient + private + + def construct_frame(type, data) + frame = "" + frame << "\x00\x00\x00\x00" # Mask with nothing for simplicity + frame << (EM::WebSocket::Framing05::FRAME_TYPES[type] | 0b10000000) + frame << encoded_length(data.size) + frame << data + end +end + +class Draft07FakeWebSocketClient < Draft05FakeWebSocketClient + private + + def construct_frame(type, data) + frame = "" + frame << (EM::WebSocket::Framing07::FRAME_TYPES[type] | 0b10000000) + # Should probably mask the data, but I get away without bothering since + # the server doesn't enforce that incoming frames are masked + frame << encoded_length(data.size) + frame << data + end +end + +# Wrapper around em-websocket-client +class Draft75WebSocketClient + def onopen(&blk); @onopen = blk; end + def onclose(&blk); @onclose = blk; end + def onerror(&blk); @onerror = blk; end + def onmessage(&blk); @onmessage = blk; end + + def initialize + @ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/', + :version => 75, + :origin => 'http://example.com') + @ws.errback { |err| @onerror.call if defined? @onerror } + @ws.callback { @onopen.call if defined? @onopen } + @ws.stream { |msg| @onmessage.call(msg) if defined? @onmessage } + @ws.disconnect { @onclose.call if defined? @onclose } + end + + def send(message) + @ws.send_msg(message) + end + + def close_connection + @ws.close_connection + end +end + +def start_server(opts = {}) + EM::WebSocket.run({:host => "0.0.0.0", :port => 12345}.merge(opts)) { |ws| + yield ws if block_given? + } +end + +def format_request(r) + data = "#{r[:method]} #{r[:path]} HTTP/1.1\r\n" + header_lines = r[:headers].map { |k,v| "#{k}: #{v}" } + data << [header_lines, '', r[:body]].join("\r\n") + data +end + +def format_response(r) + data = r[:protocol] || "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" + header_lines = r[:headers].map { |k,v| "#{k}: #{v}" } + data << [header_lines, '', r[:body]].join("\r\n") + data +end + +RSpec::Matchers.define :succeed_with_upgrade do |response| + match do |actual| + success = nil + actual.callback { |upgrade_response, handler_klass| + success = (upgrade_response.lines.sort == format_response(response).lines.sort) + } + success + end +end + +RSpec::Matchers.define :fail_with_error do |error_klass, error_message| + match do |actual| + success = nil + actual.errback { |e| + success = (e.class == error_klass) + success &= (e.message == error_message) if error_message + } + success + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/common_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/common_spec.rb new file mode 100644 index 00000000..c89f871c --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/common_spec.rb @@ -0,0 +1,138 @@ +require 'helper' + +# These tests are not specific to any particular draft of the specification +# +describe "WebSocket server" do + include EM::SpecHelper + default_timeout 1 + + it "should fail on non WebSocket requests" do + em { + EM.add_timer(0.1) do + http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0 + http.errback { done } + http.callback { fail } + end + + start_server + } + end + + it "should expose the WebSocket request headers, path and query params" do + em { + EM.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/', + :origin => 'http://example.com') + ws.errback { fail } + ws.callback { ws.close_connection } + ws.stream { |msg| } + end + + start_server do |ws| + ws.onopen { |handshake| + headers = handshake.headers + headers["Connection"].should == "Upgrade" + headers["Upgrade"].should == "websocket" + headers["Host"].to_s.should == "127.0.0.1:12345" + handshake.path.should == "/" + handshake.query.should == {} + handshake.origin.should == 'http://example.com' + } + ws.onclose { + ws.state.should == :closed + done + } + end + } + end + + it "should expose the WebSocket path and query params when nonempty" do + em { + EM.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/hello?foo=bar&baz=qux') + ws.errback { fail } + ws.callback { + ws.close_connection + } + ws.stream { |msg| } + end + + start_server do |ws| + ws.onopen { |handshake| + handshake.path.should == '/hello' + handshake.query_string.split('&').sort. + should == ["baz=qux", "foo=bar"] + handshake.query.should == {"foo"=>"bar", "baz"=>"qux"} + } + ws.onclose { + ws.state.should == :closed + done + } + end + } + end + + it "should raise an exception if frame sent before handshake complete" do + em { + # 1. Start WebSocket server + start_server { |ws| + # 3. Try to send a message to the socket + lambda { + ws.send('early message') + }.should raise_error('Cannot send data before onopen callback') + done + } + + # 2. Connect a dumb TCP connection (will not send handshake) + EM.connect('0.0.0.0', 12345, EM::Connection) + } + end + + it "should allow the server to be started inside an existing EM" do + em { + EM.add_timer(0.1) do + http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0 + http.errback { |e| done } + http.callback { fail } + end + + start_server do |ws| + ws.onopen { |handshake| + headers = handshake.headers + headers["Host"].to_s.should == "127.0.0.1:12345" + } + ws.onclose { + ws.state.should == :closed + done + } + end + } + end + + context "outbound limit set" do + it "should close the connection if the limit is reached" do + em { + start_server(:outbound_limit => 150) do |ws| + # Increase the message size by one on each loop + ws.onmessage{|msg| ws.send(msg + "x") } + ws.onclose{|status| + status[:code].should == 1006 # Unclean + status[:was_clean].should be false + } + end + + EM.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/') + ws.callback { ws.send_msg "hello" } + ws.disconnect { done } # Server closed the connection + ws.stream { |msg| + # minus frame size ? (getting 146 max here) + msg.data.size.should <= 150 + # Return back the message + ws.send_msg(msg.data) + } + end + } + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb new file mode 100644 index 00000000..f299ab6d --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb @@ -0,0 +1,298 @@ +require 'helper' + +describe "draft03" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00', + 'Sec-WebSocket-Protocol' => 'sample', + 'Upgrade' => 'WebSocket', + 'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5', + 'Origin' => 'http://example.com', + 'Sec-WebSocket-Draft' => '3' + }, + :body => '^n:ds[4U' + } + + @response = { + :headers => { + "Upgrade" => "WebSocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Location" => "ws://example.com/demo", + "Sec-WebSocket-Origin" => "http://example.com", + "Sec-WebSocket-Protocol" => "sample" + }, + :body => "8jKS\'y:G*Co,Wxa-" + } + end + + def start_client + client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 3 } + end + + it_behaves_like "a WebSocket server drafts 3 and above" do + let(:version) { 3 } + end + + # These examples are straight from the spec + # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6 + describe "examples from the spec" do + it "should accept a single-frame text message" do + em { + start_server { |ws| + ws.onmessage { |msg| + msg.should == 'Hello' + done + } + } + start_client { |client| + client.onopen { + client.send_data("\x04\x05Hello") + } + } + } + end + + it "should accept a fragmented text message" do + em { + start_server { |ws| + ws.onmessage { |msg| + msg.should == 'Hello' + done + } + } + + connection = start_client + + # Send frame + connection.onopen { + connection.send_data("\x84\x03Hel") + connection.send_data("\x00\x02lo") + } + } + end + + it "should accept a ping request and respond with the same body" do + em { + start_server + + connection = start_client + + # Send frame + connection.onopen { + connection.send_data("\x02\x05Hello") + } + + connection.onmessage { |frame| + next if frame.nil? + frame.should == "\x03\x05Hello" + done + } + } + end + + it "should accept a 256 bytes binary message in a single frame" do + em { + data = "a" * 256 + + start_server { |ws| + ws.onbinary { |msg| + msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding) + msg.should == data + done + } + } + + connection = start_client + + # Send frame + connection.onopen { + connection.send_data("\x05\x7E\x01\x00" + data) + } + } + end + + it "should accept a 64KiB binary message in a single frame" do + em { + data = "a" * 65536 + + start_server { |ws| + ws.onbinary { |msg| + msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding) + msg.should == data + done + } + } + + connection = start_client + + # Send frame + connection.onopen { + connection.send_data("\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data) + } + } + end + end + + describe "close handling" do + it "should respond to a new close frame with a close frame" do + em { + start_server + + connection = start_client + + # Send close frame + connection.onopen { + connection.send_data("\x01\x00") + } + + # Check that close ack received + connection.onmessage { |frame| + frame.should == "\x01\x00" + done + } + } + end + + it "should close the connection on receiving a close acknowlegement and call onclose with close code 1005 and was_clean=true (initiated by server)" do + em { + ack_received = false + + start_server { |ws| + ws.onopen { + # 2. Send a close frame + EM.next_tick { + ws.close + } + } + + # 5. Onclose event on server + ws.onclose { |event| + event.should == { + :code => 1005, + :reason => "", + :was_clean => true, + } + done + } + } + + # 1. Create a fake client which sends draft 76 handshake + connection = start_client + + # 3. Check that close frame recieved and acknowlege it + connection.onmessage { |frame| + frame.should == "\x01\x00" + ack_received = true + connection.send_data("\x01\x00") + } + + # 4. Check that connection is closed _after_ the ack + connection.onclose { + ack_received.should == true + } + } + end + + # it "should repur" + # + it "should return close code 1005 and was_clean=true after closing handshake (initiated by client)" do + em { + start_server { |ws| + ws.onclose { |event| + event.should == { + :code => 1005, + :reason => "", + :was_clean => true, + } + done + } + } + start_client { |client| + client.onopen { + client.send_data("\x01\x00") + } + } + } + end + + it "should not allow data frame to be sent after close frame sent" do + em { + start_server { |ws| + ws.onopen { + # 2. Send a close frame + EM.next_tick { + ws.close + } + + # 3. Check that exception raised if I attempt to send more data + EM.add_timer(0.1) { + lambda { + ws.send('hello world') + }.should raise_error(EM::WebSocket::WebSocketError, 'Cannot send data frame since connection is closing') + done + } + } + } + + # 1. Create a fake client which sends draft 76 handshake + start_client + } + end + + it "should still respond to control frames after close frame sent" do + em { + start_server { |ws| + ws.onopen { + # 2. Send a close frame + EM.next_tick { + ws.close + } + } + } + + # 1. Create a fake client which sends draft 76 handshake + connection = start_client + + connection.onmessage { |frame| + if frame == "\x01\x00" + # 3. After the close frame is received send a ping frame, but + # don't respond with a close ack + connection.send_data("\x02\x05Hello") + else + # 4. Check that the pong is received + frame.should == "\x03\x05Hello" + done + end + } + } + end + + it "should report that close codes are not supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == false + done + } + } + start_client + } + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb new file mode 100644 index 00000000..e07ea282 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb @@ -0,0 +1,50 @@ +require 'helper' + +describe "draft05" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Upgrade' => 'websocket', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Protocol' => 'sample', + 'Sec-WebSocket-Origin' => 'http://example.com', + 'Sec-WebSocket-Version' => '5' + } + } + end + + def start_client + client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 5 } + end + + it_behaves_like "a WebSocket server drafts 3 and above" do + let(:version) { 5 } + end + + it "should report that close codes are not supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == false + done + } + } + start_client + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb new file mode 100644 index 00000000..ae213cba --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb @@ -0,0 +1,145 @@ +require 'helper' + +describe "draft06" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Upgrade' => 'websocket', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Protocol' => 'sample', + 'Sec-WebSocket-Origin' => 'http://example.com', + 'Sec-WebSocket-Version' => '6' + } + } + + @response = { + :protocol => "HTTP/1.1 101 Switching Protocols\r\n", + :headers => { + "Upgrade" => "websocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", + "Sec-WebSocket-Protocol" => "sample", + } + } + end + + def start_client + client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 6 } + end + + it_behaves_like "a WebSocket server drafts 3 and above" do + let(:version) { 6 } + end + + it "should open connection" do + em { + start_server { |server| + server.onopen { + server.instance_variable_get(:@handler).class.should == EventMachine::WebSocket::Handler06 + } + } + + start_client { |client| + client.onopen { + client.handshake_response.lines.sort. + should == format_response(@response).lines.sort + done + } + } + } + end + + it "should accept a single-frame text message (masked)" do + em { + start_server { |server| + server.onmessage { |msg| + msg.should == 'Hello' + if msg.respond_to?(:encoding) + msg.encoding.should == Encoding.find("UTF-8") + end + done + } + server.onerror { + fail + } + } + + start_client { |client| + client.onopen { + client.send_data("\x00\x00\x01\x00\x84\x05Ielln") + } + } + } + end + + it "should return close code and reason if closed via handshake" do + em { + start_server { |ws| + ws.onclose { |event| + # 2. Receive close event in server + event.should == { + :code => 4004, + :reason => "close reason", + :was_clean => true, + } + done + } + } + start_client { |client| + client.onopen { + # 1: Send close handshake + close_data = [4004].pack('n') + close_data << "close reason" + client.send_frame(:close, close_data) + } + } + } + end + + it "should return close code 1005 if no code was specified" do + em { + start_server { |ws| + ws.onclose { |event| + event.should == { + :code => 1005, + :reason => "", + :was_clean => true, + } + done + } + } + start_client { |client| + client.onopen { + client.send_frame(:close, '') + } + } + } + end + + it "should report that close codes are supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == true + done + } + } + start_client + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb new file mode 100644 index 00000000..10dc2a33 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb @@ -0,0 +1,105 @@ +# encoding: BINARY + +require 'helper' + +describe "draft13" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Upgrade' => 'websocket', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Protocol' => 'sample', + 'Sec-WebSocket-Origin' => 'http://example.com', + 'Sec-WebSocket-Version' => '13' + } + } + + @response = { + :protocol => "HTTP/1.1 101 Switching Protocols\r\n", + :headers => { + "Upgrade" => "websocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", + "Sec-WebSocket-Protocol" => "sample", + } + } + end + + def start_client + client = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 13 } + end + + it_behaves_like "a WebSocket server drafts 3 and above" do + let(:version) { 13 } + end + + it "should send back the correct handshake response" do + em { + start_server + + connection = start_client + + connection.onopen { + connection.handshake_response.lines.sort. + should == format_response(@response).lines.sort + done + } + } + end + + # TODO: This test would be much nicer with a real websocket client... + it "should support sending pings and binding to onpong" do + em { + start_server { |ws| + ws.onopen { + ws.should be_pingable + EM.next_tick { + ws.ping('hello').should == true + } + + } + ws.onpong { |data| + data.should == 'hello' + done + } + } + + connection = start_client + + # Confusing, fake onmessage means any data after the handshake + connection.onmessage { |data| + # This is what a ping looks like + data.should == "\x89\x05hello" + # This is what a pong looks like + connection.send_data("\x8a\x05hello") + } + } + end + + it "should report that close codes are supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == true + done + } + } + start_client + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb new file mode 100644 index 00000000..8d9faec4 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb @@ -0,0 +1,123 @@ +require 'helper' + +# These integration tests are older and use a different testing style to the +# integration tests for newer drafts. They use EM::HttpRequest which happens +# to currently estabish a websocket connection using the draft75 protocol. +# +describe "WebSocket server draft75" do + include EM::SpecHelper + default_timeout 1 + + def start_client + client = Draft75WebSocketClient.new + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 75 } + end + + it "should automatically complete WebSocket handshake" do + em { + MSG = "Hello World!" + EventMachine.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/') + ws.errback { fail } + ws.callback { } + + ws.stream { |msg| + msg.data.should == MSG + EventMachine.stop + } + end + + start_server { |ws| + ws.onopen { + ws.send MSG + } + } + } + end + + it "should split multiple messages into separate callbacks" do + em { + messages = %w[1 2] + received = [] + + EventMachine.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/') + ws.errback { fail } + ws.stream {|msg|} + ws.callback { + ws.send_msg messages[0] + ws.send_msg messages[1] + } + end + + start_server { |ws| + ws.onopen {} + ws.onclose {} + ws.onmessage {|msg| + msg.should == messages[received.size] + received.push msg + + EventMachine.stop if received.size == messages.size + } + } + } + end + + it "should call onclose callback when client closes connection" do + em { + EventMachine.add_timer(0.1) do + ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/') + ws.errback { fail } + ws.callback { + ws.close_connection + } + ws.stream{|msg|} + end + + start_server { |ws| + ws.onopen {} + ws.onclose { + ws.state.should == :closed + EventMachine.stop + } + } + } + end + + it "should call onerror callback with raised exception and close connection on bad handshake" do + em { + EventMachine.add_timer(0.1) do + http = EM::HttpRequest.new('http://127.0.0.1:12345/').get + http.errback { } + http.callback { fail } + end + + start_server { |ws| + ws.onopen { fail } + ws.onclose { EventMachine.stop } + ws.onerror {|e| + e.should be_an_instance_of EventMachine::WebSocket::HandshakeError + e.message.should match('Not an upgrade request') + EventMachine.stop + } + } + } + end + + it "should report that close codes are not supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == false + done + } + } + start_client + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb b/bin/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb new file mode 100644 index 00000000..f1a14e60 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb @@ -0,0 +1,234 @@ +# encoding: BINARY + +require 'helper' + +describe "WebSocket server draft76" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00', + 'Sec-WebSocket-Protocol' => 'sample', + 'Upgrade' => 'WebSocket', + 'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5', + 'Origin' => 'http://example.com' + }, + :body => '^n:ds[4U' + } + + @response = { + :headers => { + "Upgrade" => "WebSocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Location" => "ws://example.com/demo", + "Sec-WebSocket-Origin" => "http://example.com", + "Sec-WebSocket-Protocol" => "sample" + }, + :body => "8jKS\'y:G*Co,Wxa-" + } + end + + def start_client + client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + return client + end + + it_behaves_like "a websocket server" do + let(:version) { 76 } + end + + it "should send back the correct handshake response" do + em { + start_server + + start_client { |connection| + connection.onopen { + connection.handshake_response.lines.sort. + should == format_response(@response).lines.sort + done + } + } + } + end + + it "should send closing frame back and close the connection after recieving closing frame" do + em { + start_server + + connection = start_client + + # Send closing frame after handshake complete + connection.onopen { + connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING) + } + + # Check that this causes a termination string to be returned and the + # connection close + connection.onclose { + connection.packets[0].should == + EM::WebSocket::Handler76::TERMINATE_STRING + done + } + } + end + + it "should ignore any data received after the closing frame" do + em { + start_server { |ws| + # Fail if foobar message is received + ws.onmessage { |msg| + fail + } + } + + connection = start_client + + # Send closing frame after handshake complete, followed by another msg + connection.onopen { + connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING) + connection.send('foobar') + } + + connection.onclose { + done + } + } + end + + it "should accept null bytes within the frame after a line return" do + em { + start_server { |ws| + ws.onmessage { |msg| + msg.should == "\n\000" + } + } + + connection = start_client + + # Send closing frame after handshake complete + connection.onopen { + connection.send_data("\000\n\000\377") + connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING) + } + + connection.onclose { + done + } + } + end + + it "should handle unreasonable frame lengths by calling onerror callback" do + em { + start_server { |server| + server.onerror { |error| + error.should be_an_instance_of EM::WebSocket::WSMessageTooBigError + error.message.should == "Frame length too long (1180591620717411303296 bytes)" + done + } + } + + client = start_client + + # This particular frame indicates a message length of + # 1180591620717411303296 bytes. Such a message would previously cause + # a "bignum too big to convert into `long'" error. + # However it is clearly unreasonable and should be rejected. + client.onopen { + client.send_data("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00") + } + } + end + + it "should handle impossible frames by calling onerror callback" do + em { + start_server { |server| + server.onerror { |error| + error.should be_an_instance_of EM::WebSocket::WSProtocolError + error.message.should == "Invalid frame received" + done + } + } + + client = start_client + + client.onopen { + client.send_data("foobar") # Does not start with \x00 or \xff + } + } + end + + it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do + em { + start_server { |server| + server.onerror { |error| + error.should be_an_instance_of EM::WebSocket::HandshakeError + error.message.should == "Invalid HTTP header: Could not parse data entirely (1 != 29)" + done + } + } + + client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) + client.send_data("This is not a HTTP header\r\n\r\n") + } + end + + it "should handle handshake request split into two TCP packets" do + em { + start_server + + # Create a fake client which sends draft 76 handshake + connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) + data = format_request(@request) + # Sends first half of the request + connection.send_data(data[0...(data.length / 2)]) + + connection.onopen { + connection.handshake_response.lines.sort. + should == format_response(@response).lines.sort + done + } + + EM.add_timer(0.1) do + # Sends second half of the request + connection.send_data(data[(data.length / 2)..-1]) + end + } + end + + it "should report that close codes are not supported" do + em { + start_server { |ws| + ws.onopen { + ws.supports_close_codes?.should == false + done + } + } + start_client + } + end + + it "should call onclose when the server closes the connection [antiregression]" do + em { + start_server { |ws| + ws.onopen { + EM.add_timer(0.1) { + ws.close() + } + } + ws.onclose { + done + } + } + start_client + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb b/bin/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb new file mode 100644 index 00000000..f8416185 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb @@ -0,0 +1,42 @@ +shared_examples_for "a WebSocket server drafts 3 and above" do + it "should force close connections after a timeout if close handshake is not sent by the client" do + em { + server_onerror_fired = false + server_onclose_fired = false + client_got_close_handshake = false + + start_server(:close_timeout => 0.1) { |ws| + ws.onopen { + # 1: Send close handshake to client + EM.next_tick { ws.close(4999, "Close message") } + } + + ws.onerror { |e| + # 3: Client should receive onerror + e.class.should == EM::WebSocket::WSProtocolError + e.message.should == "Close handshake un-acked after 0.1s, closing tcp connection" + server_onerror_fired = true + } + + ws.onclose { + server_onclose_fired = true + } + } + start_client { |client| + client.onmessage { |msg| + # 2: Client does not respond to close handshake (the fake client + # doesn't understand them at all hence this is in onmessage) + msg.should =~ /Close message/ if version >= 6 + client_got_close_handshake = true + } + + client.onclose { + server_onerror_fired.should == true + server_onclose_fired.should == true + client_got_close_handshake.should == true + done + } + } + } + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb b/bin/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb new file mode 100644 index 00000000..0cd6b424 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb @@ -0,0 +1,265 @@ +# encoding: UTF-8 + +# These tests are run against all draft versions +# +shared_examples_for "a websocket server" do + it "should expose the protocol version" do + em { + start_server { |ws| + ws.onopen { |handshake| + handshake.protocol_version.should == version + done + } + } + + start_client + } + end + + it "should expose the origin header" do + em { + start_server { |ws| + ws.onopen { |handshake| + handshake.origin.should == 'http://example.com' + done + } + } + + start_client + } + end + + it "should expose the remote IP address" do + em { + start_server { |ws| + ws.onopen { + ws.remote_ip.should == "127.0.0.1" + done + } + } + + start_client + } + end + + it "should send messages successfully" do + em { + start_server { |ws| + ws.onmessage { |message| + message.should == "hello server" + done + } + } + + start_client { |client| + client.onopen { + client.send("hello server") + } + } + } + end + + it "should allow connection to be closed with valid close code" do + em { + start_server { |ws| + ws.onopen { + ws.close(4004, "Bye bye") + done + } + } + + start_client + # TODO: Use a real client which understands how to respond to closing + # handshakes, sending the handshake currently untested + } + end + + it "should raise error if if invalid close code is used" do + em { + start_server { |ws| + ws.onopen { + lambda { + ws.close(2000) + }.should raise_error("Application code may only use codes from 1000, 3000-4999") + done + } + } + + start_client + } + end + + it "should call onclose with was_clean set to false if connection closed without closing handshake by server" do + em { + start_server { |ws| + ws.onopen { + # Close tcp connection (no close handshake) + ws.close_connection + } + ws.onclose { |event| + event.should == {:code => 1006, :was_clean => false} + done + } + } + start_client + } + end + + it "should call onclose with was_clean set to false if connection closed without closing handshake by client" do + em { + start_server { |ws| + ws.onclose { |event| + event.should == {:code => 1006, :was_clean => false} + done + } + } + start_client { |client| + client.onopen { + # Close tcp connection (no close handshake) + client.close_connection + } + } + } + end + + it "should call onerror if an application error raised in onopen" do + em { + start_server { |ws| + ws.onopen { + raise "application error" + } + + ws.onerror { |e| + e.message.should == "application error" + done + } + } + + start_client + } + end + + it "should call onerror if an application error raised in onmessage" do + em { + start_server { |server| + server.onmessage { + raise "application error" + } + + server.onerror { |e| + e.message.should == "application error" + done + } + } + + start_client { |client| + client.onopen { + client.send('a message') + } + } + } + end + + it "should call onerror in an application error raised in onclose" do + em { + start_server { |server| + server.onclose { + raise "application error" + } + + server.onerror { |e| + e.message.should == "application error" + done + } + } + + start_client { |client| + client.onopen { + EM.add_timer(0.1) { + client.close_connection + } + } + } + } + end + + it "should close the connection when a too long frame is sent" do + em { + start_server { |server| + server.max_frame_size = 20 + + server.onerror { |e| + # 3: Error should be reported to server + e.class.should == EventMachine::WebSocket::WSMessageTooBigError + e.message.should =~ /Frame length too long/ + } + } + + start_client { |client| + client.onopen { + EM.next_tick { + client.send("This message is longer than 20 characters") + } + + } + + client.onmessage { |msg| + # 4: This is actually the close message. Really need to use a real + # WebSocket client in these tests... + done + } + + client.onclose { + # 4: Drafts 75 & 76 don't send a close message, they just close the + # connection + done + } + } + } + end + + # Only run these tests on ruby 1.9 + if "a".respond_to?(:force_encoding) + it "should raise error if you try to send non utf8 text data to ws" do + em { + start_server { |server| + server.onopen { + # Create a string which claims to be UTF-8 but which is not + s = "ê" # utf-8 string + s.encode!("ISO-8859-1") + s.force_encoding("UTF-8") + s.valid_encoding?.should == false # now invalid utf8 + + # Send non utf8 encoded data + server.send(s) + } + server.onerror { |error| + error.class.should == EventMachine::WebSocket::WebSocketError + error.message.should == "Data sent to WebSocket must be valid UTF-8 but was UTF-8 (valid: false)" + done + } + } + + start_client { } + } + end + + it "should not change the encoding of strings sent to send [antiregression]" do + em { + start_server { |server| + server.onopen { + s = "example string" + s.force_encoding("UTF-8") + + server.send(s) + + s.encoding.should == Encoding.find("UTF-8") + done + } + } + + start_client { } + } + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb b/bin/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb new file mode 100644 index 00000000..b2a8d33b --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb @@ -0,0 +1,298 @@ +# encoding: BINARY + +require 'helper' + +describe EM::WebSocket::Framing03 do + class FramingContainer + include EM::WebSocket::Framing03 + + def initialize + @connection = Object.new + def @connection.max_frame_size + 1000000 + end + end + + def <<(data) + @data << data + process_data + end + + def debug(*args); end + end + + before :each do + @f = FramingContainer.new + @f.initialize_framing + end + + describe "basic examples" do + it "connection close" do + @f.should_receive(:message).with(:close, '', '') + @f << 0b00000001 + @f << 0b00000000 + end + + it "ping" do + @f.should_receive(:message).with(:ping, '', '') + @f << 0b00000010 + @f << 0b00000000 + end + + it "pong" do + @f.should_receive(:message).with(:pong, '', '') + @f << 0b00000011 + @f << 0b00000000 + end + + it "text" do + @f.should_receive(:message).with(:text, '', 'foo') + @f << 0b00000100 + @f << 0b00000011 + @f << 'foo' + end + + it "Text in two frames" do + @f.should_receive(:message).with(:text, '', 'hello world') + @f << 0b10000100 + @f << 0b00000110 + @f << "hello " + @f << 0b00000000 + @f << 0b00000101 + @f << "world" + end + + it "2 byte extended payload length text frame" do + data = 'a' * 256 + @f.should_receive(:message).with(:text, '', data) + @f << 0b00000100 # Single frame, text + @f << 0b01111110 # Length 126 (so read 2 bytes) + @f << 0b00000001 # Two bytes in network byte order (256) + @f << 0b00000000 + @f << data + end + end + + # These examples are straight from the spec + # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6 + describe "examples from the spec" do + it "a single-frame text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x04\x05Hello" + end + + it "a fragmented text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x84\x03Hel" + @f << "\x00\x02lo" + end + + it "Ping request and response" do + @f.should_receive(:message).with(:ping, '', 'Hello') + @f << "\x02\x05Hello" + end + + it "256 bytes binary message in a single frame" do + data = "a"*256 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x05\x7E\x01\x00" + data + end + + it "64KiB binary message in a single frame" do + data = "a"*65536 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data + end + end + + describe "other tests" do + it "should accept a fragmented unmasked text message in 3 frames" do + @f.should_receive(:message).with(:text, '', 'Hello world') + @f << "\x84\x03Hel" + @f << "\x80\x02lo" + @f << "\x00\x06 world" + end + end + + describe "error cases" do + it "should raise an exception on continuation frame without preceeding more frame" do + lambda { + @f << 0b00000000 # Single frame, continuation + @f << 0b00000001 # Length 1 + @f << 'f' + }.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame not expected') + end + end +end + +# These examples are straight from the spec +# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6 +describe EM::WebSocket::Framing04 do + class FramingContainer04 + include EM::WebSocket::Framing04 + + def initialize + @connection = Object.new + def @connection.max_frame_size + 1000000 + end + end + + def <<(data) + @data << data + process_data + end + + def debug(*args); end + end + + before :each do + @f = FramingContainer04.new + @f.initialize_framing + end + + describe "examples from the spec" do + it "a single-frame text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x84\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello" + end + + it "a fragmented text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x04\x03Hel" + @f << "\x80\x02lo" + end + + it "Ping request" do + @f.should_receive(:message).with(:ping, '', 'Hello') + @f << "\x82\x05Hello" + end + + it "a pong response" do + @f.should_receive(:message).with(:pong, '', 'Hello') + @f << "\x83\x05Hello" + end + + it "256 bytes binary message in a single frame" do + data = "a"*256 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x85\x7E\x01\x00" + data + end + + it "64KiB binary message in a single frame" do + data = "a"*65536 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x85\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data + end + end + + describe "other tests" do + it "should accept a fragmented unmasked text message in 3 frames" do + @f.should_receive(:message).with(:text, '', 'Hello world') + @f << "\x04\x03Hel" + @f << "\x00\x02lo" + @f << "\x80\x06 world" + end + end +end + +describe EM::WebSocket::Framing07 do + class FramingContainer07 + include EM::WebSocket::Framing07 + + def initialize + @connection = Object.new + def @connection.max_frame_size + 1000000 + end + end + + def <<(data) + @data << data + process_data + end + + def debug(*args); end + end + + before :each do + @f = FramingContainer07.new + @f.initialize_framing + end + + # These examples are straight from the spec + # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07#section-4.6 + describe "examples from the spec" do + it "a single-frame unmakedtext message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x81\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello" + end + + it "a single-frame masked text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58" # "\x84\x05Hello" + end + + it "a fragmented unmasked text message" do + @f.should_receive(:message).with(:text, '', 'Hello') + @f << "\x01\x03Hel" + @f << "\x80\x02lo" + end + + it "Ping request" do + @f.should_receive(:message).with(:ping, '', 'Hello') + @f << "\x89\x05Hello" + end + + it "a pong response" do + @f.should_receive(:message).with(:pong, '', 'Hello') + @f << "\x8a\x05Hello" + end + + it "256 bytes binary message in a single unmasked frame" do + data = "a"*256 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x82\x7E\x01\x00" + data + end + + it "64KiB binary message in a single unmasked frame" do + data = "a"*65536 + @f.should_receive(:message).with(:binary, '', data) + @f << "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data + end + end + + describe "other tests" do + it "should raise a WSProtocolError if an invalid frame type is requested" do + lambda { + # Opcode 3 is not supported by this draft + @f << "\x83\x05Hello" + }.should raise_error(EventMachine::WebSocket::WSProtocolError, "Unknown opcode 3") + end + + it "should accept a fragmented unmasked text message in 3 frames" do + @f.should_receive(:message).with(:text, '', 'Hello world') + @f << "\x01\x03Hel" + @f << "\x00\x02lo" + @f << "\x80\x06 world" + end + + it "should raise if non-fin frame is followed by a non-continuation data frame (continuation frame would be expected)" do + lambda { + @f << 0b00000001 # Not fin, text + @f << 0b00000001 # Length 1 + @f << 'f' + @f << 0b10000001 # fin, text (continutation expected) + @f << 0b00000001 # Length 1 + @f << 'b' + }.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame expected') + end + + it "should raise on non-fin control frames (control frames must not be fragmented)" do + lambda { + @f << 0b00001010 # Not fin, pong (opcode 10) + @f << 0b00000000 # Length 1 + }.should raise_error(EM::WebSocket::WebSocketError, 'Control frames must not be fragmented') + end + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb b/bin/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb new file mode 100644 index 00000000..2754ba76 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb @@ -0,0 +1,216 @@ +require 'helper' + +describe EM::WebSocket::Handshake do + def handshake(request, secure = false) + handshake = EM::WebSocket::Handshake.new(secure) + handshake.receive_data(format_request(request)) + handshake + end + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00', + 'Sec-WebSocket-Protocol' => 'sample', + 'Upgrade' => 'WebSocket', + 'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5', + 'Origin' => 'http://example.com' + }, + :body => '^n:ds[4U' + } + @secure_request = @request.merge(:port => 443) + + @response = { + :headers => { + "Upgrade" => "WebSocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Location" => "ws://example.com/demo", + "Sec-WebSocket-Origin" => "http://example.com", + "Sec-WebSocket-Protocol" => "sample" + }, + :body => "8jKS\'y:G*Co,Wxa-" + } + @secure_response = @response.merge(:headers => @response[:headers].merge('Sec-WebSocket-Location' => "wss://example.com/demo")) + end + + it "should handle good request" do + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should handle good request to secure default port if secure mode is enabled" do + handshake(@secure_request, true). + should succeed_with_upgrade(@secure_response) + end + + it "should not handle good request to secure default port if secure mode is disabled" do + handshake(@secure_request, false). + should_not succeed_with_upgrade(@secure_response) + end + + it "should handle good request on nondefault port" do + @request[:port] = 8081 + @request[:headers]['Host'] = 'example.com:8081' + @response[:headers]['Sec-WebSocket-Location'] = + 'ws://example.com:8081/demo' + + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should handle good request to secure nondefault port" do + @secure_request[:port] = 8081 + @secure_request[:headers]['Host'] = 'example.com:8081' + @secure_response[:headers]['Sec-WebSocket-Location'] = 'wss://example.com:8081/demo' + + handshake(@secure_request, true). + should succeed_with_upgrade(@secure_response) + end + + it "should handle good request with no protocol" do + @request[:headers].delete('Sec-WebSocket-Protocol') + @response[:headers].delete("Sec-WebSocket-Protocol") + + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should handle extra headers by simply ignoring them" do + @request[:headers]['EmptyValue'] = "" + @request[:headers]['AKey'] = "AValue" + + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should raise error on HTTP request" do + @request[:headers] = { + 'Host' => 'www.google.com', + 'User-Agent' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB6 GTBA', + 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language' => 'en-us,en;q=0.5', + 'Accept-Encoding' => 'gzip,deflate', + 'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', + 'Keep-Alive' => '300', + 'Connection' => 'keep-alive', + } + + handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError) + end + + it "should raise error on wrong method" do + @request[:method] = 'POST' + + handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError) + end + + it "should raise error if upgrade header incorrect" do + @request[:headers]['Upgrade'] = 'NonWebSocket' + + handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError) + end + + it "should raise error if Sec-WebSocket-Protocol is empty" do + @request[:headers]['Sec-WebSocket-Protocol'] = '' + + handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError) + end + + %w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header| + it "should raise error if #{header} has zero spaces" do + @request[:headers][header] = 'nospaces' + + handshake(@request). + should fail_with_error(EM::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack') + end + end + + it "should raise error if Sec-WebSocket-Key1 is missing" do + @request[:headers].delete("Sec-WebSocket-Key1") + + # The error message isn't correct since key1 is used to heuristically + # determine the protocol version in use, however this test at least checks + # that the handshake does correctly fail + handshake(@request). + should fail_with_error(EM::WebSocket::HandshakeError, 'Extra bytes after header') + end + + it "should raise error if Sec-WebSocket-Key2 is missing" do + @request[:headers].delete("Sec-WebSocket-Key2") + + handshake(@request). + should fail_with_error(EM::WebSocket::HandshakeError, 'WebSocket key1 or key2 is missing') + end + + it "should raise error if spaces do not divide numbers in Sec-WebSocket-Key* " do + @request[:headers]['Sec-WebSocket-Key2'] = '12998 5 Y3 1.P00' + + handshake(@request). + should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid Key "12998 5 Y3 1.P00"') + end + + it "should raise error if the HTTP header is empty" do + handshake = EM::WebSocket::Handshake.new(false) + handshake.receive_data("\r\n\r\nfoobar") + + handshake. + should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid HTTP header: Could not parse data entirely (4 != 10)') + end + + # This might seems crazy, but very occasionally we saw multiple "Upgrade: + # WebSocket" headers in the wild. RFC 4.2.1 isn't particularly clear on this + # point, so for now I have decided not to accept --@mloughran + it "should raise error on multiple upgrade headers" do + handshake = EM::WebSocket::Handshake.new(false) + + # Add a duplicate upgrade header + headers = format_request(@request) + upgrade_header = "Upgrade: WebSocket\r\n" + headers.gsub!(upgrade_header, "#{upgrade_header}#{upgrade_header}") + + handshake.receive_data(headers) + + handshake.errback { |e| + e.class.should == EM::WebSocket::HandshakeError + e.message.should == 'Invalid upgrade header: ["WebSocket", "WebSocket"]' + } + end + + it "should cope with requests where the header is split" do + request = format_request(@request) + incomplete_request = request[0...(request.length / 2)] + rest = request[(request.length / 2)..-1] + handshake = EM::WebSocket::Handshake.new(false) + handshake.receive_data(incomplete_request) + + handshake.instance_variable_get(:@deferred_status).should == nil + + # Send the remaining header + handshake.receive_data(rest) + + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should cope with requests where the third key is split" do + request = format_request(@request) + # Removes last two bytes of the third key + incomplete_request = request[0..-3] + rest = request[-2..-1] + handshake = EM::WebSocket::Handshake.new(false) + handshake.receive_data(incomplete_request) + + handshake.instance_variable_get(:@deferred_status).should == nil + + # Send the remaining third key + handshake.receive_data(rest) + + handshake(@request).should succeed_with_upgrade(@response) + end + + it "should fail if the request URI is invalid" do + @request[:path] = "/%" + handshake(@request).should \ + fail_with_error(EM::WebSocket::HandshakeError, 'Invalid request URI: /%') + end +end diff --git a/bin/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb b/bin/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb new file mode 100644 index 00000000..065aa955 --- /dev/null +++ b/bin/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb @@ -0,0 +1,29 @@ +# encoding: BINARY + +require 'helper' + +describe EM::WebSocket::MaskedString do + it "should allow reading 4 byte mask and unmasking byte / bytes" do + t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x01\x00\x01\x00\x01") + t.read_mask + t.getbyte(3).should == 0x00 + t.getbytes(4, 4).should == "\x00\x01\x00\x00" + t.getbytes(5, 3).should == "\x01\x00\x00" + end + + it "should return nil from getbyte if index requested is out of range" do + t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x00\x53") + t.read_mask + t.getbyte(4).should == 0x53 + t.getbyte(5).should == nil + end + + it "should allow switching masking on and off" do + t = EM::WebSocket::MaskedString.new("\x02\x00\x00\x00\x03") + t.getbyte(4).should == 0x03 + t.read_mask + t.getbyte(4).should == 0x01 + t.unset_mask + t.getbyte(4).should == 0x03 + end +end diff --git a/bin/gems/ethon-0.16.0/.github/workflows/ruby.yml b/bin/gems/ethon-0.16.0/.github/workflows/ruby.yml new file mode 100644 index 00000000..d35c1887 --- /dev/null +++ b/bin/gems/ethon-0.16.0/.github/workflows/ruby.yml @@ -0,0 +1,41 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby + +name: Ruby + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu, macos] + ruby-version: [2.5, 2.6, 2.7, 3.0, head, debug, truffleruby] + continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }} + steps: + - uses: actions/checkout@v2 + - name: Install libcurl header + run: | + if ${{ matrix.os == 'macos' }} + then + brew install curl + else + sudo apt update && sudo apt install -y --no-install-recommends libcurl4-openssl-dev + fi + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Run tests + run: bundle exec rake diff --git a/bin/gems/ethon-0.16.0/.gitignore b/bin/gems/ethon-0.16.0/.gitignore new file mode 100644 index 00000000..75a08dc6 --- /dev/null +++ b/bin/gems/ethon-0.16.0/.gitignore @@ -0,0 +1,8 @@ +*.gem +.bundle +Gemfile.lock +.DS_Store +.yardoc +doc +coverage +.idea diff --git a/bin/gems/ethon-0.16.0/.rspec b/bin/gems/ethon-0.16.0/.rspec new file mode 100644 index 00000000..7d8b8b7f --- /dev/null +++ b/bin/gems/ethon-0.16.0/.rspec @@ -0,0 +1,3 @@ +--tty +--color +--format documentation diff --git a/bin/gems/ethon-0.16.0/CHANGELOG.md b/bin/gems/ethon-0.16.0/CHANGELOG.md new file mode 100644 index 00000000..80597998 --- /dev/null +++ b/bin/gems/ethon-0.16.0/CHANGELOG.md @@ -0,0 +1,375 @@ +# Changelog + +## Master + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.15.0...master) + +* Added `redirect_url` value to available informations and `Easy::Mirror`. + ([Adrien Rey-Jarthon](https://github.com/jarthod) + +## 0.15.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.14.0...v0.15.0) + +## 0.12.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.11.0...v0.12.0) + +- Removed deprecated `CURLE_SSL_CACERT` pinned in curl v7.62.0 ([@arku](https://github.com/arku) in [#158](https://github.com/typhoeus/ethon/pull/158)) + + +## 0.11.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.10.1...v0.11.0) + +## 0.10.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.10.0...v0.10.1) + +## 0.10.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.9.1...v0.10.0) + +## 0.9.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.9.0...v0.9.1) + +## 0.9.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.8.1...v0.9.0) + +## 0.8.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.8.0...v0.8.1) + +* Support optional escaping of params. + ([Tasos Laskos](https://github.com/zapotek) +* `Easy::Mirror`: Reduced object allocations and method calls during info handling. + ([Tasos Laskos](https://github.com/zapotek) + +## 0.8.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.3...v0.7.4) + +* `Easy::Mirror`: Reduced object allocations and method calls during info handling. + ([Tasos Laskos](https://github.com/zapotek) + +## 0.7.4 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.3...v0.7.4) + +* Support different array encodings for params. + ([Marcello Barnaba](https://github.com/ifad), [\#104](https://github.com/typhoeus/ethon/pull/104)) +* Programtic access to version infos. + ([Jonas Wagner](https://github.com/jwagner), [\#90](https://github.com/typhoeus/ethon/pull/90)) + + +## 0.7.3 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.2...v0.7.3) + +* `Ethon::Curl::FDSet` + * Set `:fd_array` size to the current MS Windows `FD_SETSIZE` (2048). + ([Tasos Laskos](https://github.com/zapotek) + +* Added `redirect_time` value to available informations and `Easy::Mirror`. + ([Adrien Jarthon](https://github.com/jarthod) + +## 0.7.2 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.1...v0.7.2) + +* FFI data-types updated to be more correct. + +## 0.7.1 + +* MS Windows determination delegated to `Gem.windows?` for better accuracy. +* FFI data-types updated to work on MS Windows. + +## 0.7.0 + +Not backwards compatible changes: + +* `mime-types` are no longer a dependency. The gem will be still used if available to determine the mime type of a file which is uploaded. That means you have to have take care of the gem installation yourself. + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.6.3...v0.7.0) + +## 0.6.3 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.6.2...v0.6.3) + +## 0.6.2 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.6.1...v0.6.2) + +## 0.6.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.6.0...v0.6.1) + +The changelog entries are coming soon! + +## 0.6.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.12...v0.6.0) + +The changelog entries are coming soon! + +Bugfixes: + + * URL-encode nullbytes in parameters instead of escaping them to `\\0`. + ([Tasos Laskos](https://github.com/zapotek) + +## 0.5.12 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.11...v0.5.12) + +Enhancements: + +* Performance optimizations. + ([Kyle Oppenheim](https://github.com/koppenheim) and [Richie Vos](https://github.com/richievos), [\#48](https://github.com/typhoeus/ethon/pull/48)) +* Reuse memory pointer. + ([Richie Vos](https://github.com/richievos), [\#49](https://github.com/typhoeus/ethon/pull/49)) + +Bugfixes: + +* Fix windows install. + ([Derik Olsson](https://github.com/derikolsson), [\#47](https://github.com/typhoeus/ethon/pull/47)) +* Handle urls that already contain query params. + ([Turner King](https://github.com/turnerking ), [\#45](https://github.com/typhoeus/ethon/pull/45)) + +## 0.5.11 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.10...v0.5.11) + +Enhancements: + +* Add support for postredirs, unrestricted_auth. +* Add support for cookie, cookiejar, cookiefile. + ([erwanlr](https://github.com/erwanlr), [\#46](https://github.com/typhoeus/ethon/pull/46)) +* Relax ffi requirements. + ([voxik](https://github.com/voxik), [\#40](https://github.com/typhoeus/ethon/pull/40)) +* Various documentation improvements. + ([Craig Little](https://github.com/craiglittle)) + +Bugfixes: + +* Fix the memory leaks. + ([Richie Vos](https://github.com/richievos), [\#45](https://github.com/typhoeus/ethon/pull/45)) + +## 0.5.10 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.9...v0.5.10) + +Enhancements: + +* Allow custom requests. + ([Nathan Sutton](https://github.com/nate), [\#36](https://github.com/typhoeus/ethon/pull/36)) +* Use updated version of FFI. + +Bugfixes: + +* Fix windows install issue. + ([brainsucker](https://github.com/brainsucker), [\#38](https://github.com/typhoeus/ethon/pull/38)) + +## 0.5.9 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.8...v0.5.9) + +Enhancements: + +* Allow to set multiple protocols. + +## 0.5.8 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.7...v0.5.8) + +Enhancements: + +* Add support for protocols and redir_protocols( + [libcurl SASL buffer overflow vulnerability](http://curl.haxx.se/docs/adv_20130206.html)). +* Add max_send_speed_large and max_recv_speed_large([Paul Schuegraf](https://github.com/pschuegr), [\#33](https://github.com/typhoeus/ethon/pull/33)) + +## 0.5.7 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.6...v0.5.7) + +Enhancements: + +* Use new version of ffi. + +## 0.5.6 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.4...v0.5.6) + +Bugfixes: + +* Easy#reset resets on_complete callbacks. + +## 0.5.4 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.3...v0.5.4) + +Enhancements: + +* Use Libc#getdtablesize to get the FDSet size. +* New libcurl option accept_encoding. +* Documentation updates. + +## 0.5.3 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.2...v0.5.3) + +Enhancements: + +* Deprecate Easy#prepare. It is no longer necessary. +* Unroll metaprogramming for easy and multi options. +* More specs. + +Bugfixes: + +* Correct size for FDSets +* Add proxytypes to enums. + +## 0.5.2 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.1...v0.5.2) + +Enhancements: + +* New libcurl option keypasswd. + +Bugfixes: + +* Correct request logging when using multi interface. +* Remove invalid libcurl option sslcertpasswd. + +## 0.5.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.5.0...v0.5.1) + +Bugfixes: + +* Mark Curl.select and Curl.easy_perform as blocking so that the GIL is + released by ffi. + +## 0.5.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.4.4...v0.5.0) + +Enhancements: + +* New libcurl option proxyuserpwd +* Rename response_header to response_headers + +Bugfixes: + +* Mark Curl.select and Curl.easy_perform as blocking so that the GIL is + released by ffi. + +## 0.4.4 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.4.3...v0.4.4) + +Enhancements: + +* Prepare multi explicit like easy + +## 0.4.3 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.4.2...v0.4.3) + +Enhancements: + +* Remove deprecated libcurl option put +* More documentation +* New libcurl option connecttimeout_ms and timeout_ms +* Support multi options + +Bugfixes: + +* Handle nil values in query params + +## 0.4.2 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.4.1...v0.4.2) + +Enhancements: + +* New libcurl option forbid_reuse +* Use libcurls escape instead of CGI::escape + +## 0.4.1 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.4.0...v0.4.1) + +Bugfixes: + +* Handle nested hash in an array in params correct + ( [\#201](https://github.com/typhoeus/typhoeus/issues/201) ) + +## 0.4.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.3.0...v0.4.0) + +Enhancements: + +* ruby 1.8.7 compatible +* Ethon.logger +* Deal with string param/body +* More documentation + +Bugfixes: + +* Add multi_cleanup to curl + +## 0.3.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.2.0...v0.3.0) + +Enhancements: + +* New libcurl option proxyport +* Raise invalid value error when providing a wrong key for sslversion or httpauth + +Bugfixes: + +* Libcurl option sslversion is handled correct + +## 0.2.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.1.0...v0.2.0) + +Enhancements: + +* GET requests are using custom requests only when there is a request body +* Easy#on_complete takes multiple callbacks +* raise Errors::GlobalInit when libcurls global_init failed instead of + runtime error +* raise Errors::InvalidOption if option is invalid + +## 0.1.0 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.0.2...v0.1.0) + +Enhancements: + +* Documentation + ( [Alex P](https://github.com/ifesdjeen), [\#13](https://github.com/typhoeus/ethon/issues/13) ) +* New libcurl option dns_cache_timeout + ( [Chris Heald](https://github.com/cheald), [\#192](https://github.com/typhoeus/typhoeus/pull/192) ) + +Bugfixes: + +* Libcurl option ssl_verifyhost takes an integer. +* Add space between header key and value. + +## 0.0.2 + +[Full Changelog](https://github.com/typhoeus/ethon/compare/v0.0.1...v0.0.2) + +Bugfixes: + +* Add libcurl.so.4 to ffi_lib in order to load correct lib on Debian. +* Escape zero bytes. + +## 0.0.1 Initial version diff --git a/bin/gems/ethon-0.16.0/Gemfile b/bin/gems/ethon-0.16.0/Gemfile new file mode 100644 index 00000000..a2f41e1c --- /dev/null +++ b/bin/gems/ethon-0.16.0/Gemfile @@ -0,0 +1,43 @@ +# frozen_string_literal: true +source "https://rubygems.org" +gemspec + +if Gem.ruby_version < Gem::Version.new("1.9.3") + gem "rake", "< 11" +else + gem "rake" +end + +group :development, :test do + gem "rspec", "~> 3.4" + + gem "sinatra" + + if Gem.ruby_version < Gem::Version.new("2.0.0") + gem "json", "< 2" + else + gem "json" + end + + if Gem.ruby_version >= Gem::Version.new("2.0.0") + gem "mime-types", "~> 1.18" + end + + if Gem.ruby_version >= Gem::Version.new("2.2.0") + gem "mustermann" + elsif Gem.ruby_version >= Gem::Version.new("2.1.0") + gem "mustermann", "0.4.0" + elsif Gem.ruby_version >= Gem::Version.new("2.0.0") + gem "mustermann", "0.3.1" + end + + if Gem.ruby_version >= Gem::Version.new("3.0.0") + gem "webrick" + end +end + +group :perf do + gem "benchmark-ips" + gem "patron" + gem "curb" +end diff --git a/bin/gems/ethon-0.16.0/Guardfile b/bin/gems/ethon-0.16.0/Guardfile new file mode 100644 index 00000000..37d79f0b --- /dev/null +++ b/bin/gems/ethon-0.16.0/Guardfile @@ -0,0 +1,10 @@ +# frozen_string_literal: true +# vim:set filetype=ruby: +guard( + "rspec", + :all_after_pass => false, + :cli => "--fail-fast --tty --format documentation --colour") do + + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |match| "spec/#{match[1]}_spec.rb" } +end diff --git a/bin/gems/ethon-0.16.0/LICENSE b/bin/gems/ethon-0.16.0/LICENSE new file mode 100644 index 00000000..f064c17b --- /dev/null +++ b/bin/gems/ethon-0.16.0/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-2016 Hans Hasselberg + +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/bin/gems/ethon-0.16.0/README.md b/bin/gems/ethon-0.16.0/README.md new file mode 100644 index 00000000..9f9f567b --- /dev/null +++ b/bin/gems/ethon-0.16.0/README.md @@ -0,0 +1,118 @@ +[![Gem Version](https://badge.fury.io/rb/ethon.svg)](https://badge.fury.io/rb/ethon) +[![Build Status](https://github.com/typhoeus/ethon/workflows/Ruby/badge.svg)](https://github.com/typhoeus/ethon/actions/workflows/ruby.yml) + +# Ethon + +In Greek mythology, Ethon, the son of Typhoeus and Echidna, is a gigantic eagle. So much for the history. +In the modern world, Ethon is a very basic libcurl wrapper using ffi. + +* [Documentation](http://rubydoc.info/github/typhoeus/ethon/frames/Ethon) +* [Website](http://typhoeus.github.com/) +* [Mailing list](http://groups.google.com/group/typhoeus) + +## Installation + +With bundler: + + gem "ethon" + +With rubygems: + + gem install ethon + +## Usage + +Making the first request is simple: + +```ruby +easy = Ethon::Easy.new(url: "www.example.com") +easy.perform +#=> :ok +``` + +You have access to various options, such as following redirects: + +```ruby +easy = Ethon::Easy.new(url: "www.example.com", followlocation: true) +easy.perform +#=> :ok +``` + +Once you're done you can inspect the response code and body: + +```ruby +easy = Ethon::Easy.new(url: "www.example.com", followlocation: true) +easy.perform +easy.response_code +#=> 200 +easy.response_body +#=> " :ok +``` + +```ruby +easy = Ethon::Easy.new +easy.http_request("www.example.com", :post, { params: { a: 1 }, body: { b: 2 } }) +easy.perform +#=> :ok +``` + +This is really handy when making requests since you don't have to care about setting +everything up correctly. + +## Http2 +Standard http2 servers require the client to connect once and create a session (multi) and then add simple requests to the multi handler. +The `perform` method then takes all the requests in the multi handler and sends them to the server. + +See the following example +```ruby +multi = Ethon::Multi.new +easy = Ethon::Easy.new + +easy.http_request("www.example.com/get", :get, { http_version: :httpv2_0 }) + +# Sending a request with http version 2 will send an Upgrade header to the server, which many older servers will not support +# See below for more info: https://everything.curl.dev/http/http2 +# If this is a problem, send the below: +easy.http_request("www.example.com/get", :get, { http_version: :httpv2_prior_knowledge }) + +# To set the server to use http2 with https and http1 with http, send the following: +easy.http_request("www.example.com/get", :get, { http_version: :httpv2_tls } + +multi.add(easy) +multi.perform +``` + +## LICENSE + +(The MIT License) + +Copyright © 2012-2016 [Hans Hasselberg](http://www.hans.io) + +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/bin/gems/ethon-0.16.0/Rakefile b/bin/gems/ethon-0.16.0/Rakefile new file mode 100644 index 00000000..a5bc61b0 --- /dev/null +++ b/bin/gems/ethon-0.16.0/Rakefile @@ -0,0 +1,40 @@ +# frozen_string_literal: true +require "bundler" +Bundler.setup + +require "rake" +require "rspec/core/rake_task" +$LOAD_PATH.unshift File.expand_path("../lib", __FILE__) +require "ethon/version" + +task :gem => :build +task :build do + system "gem build ethon.gemspec" +end + +task :install => :build do + system "gem install ethon-#{Ethon::VERSION}.gem" +end + +task :release => :build do + system "git tag -a v#{Ethon::VERSION} -m 'Tagging #{Ethon::VERSION}'" + system "git push --tags" + system "gem push ethon-#{Ethon::VERSION}.gem" +end + +RSpec::Core::RakeTask.new(:spec) do |t| + t.verbose = false + t.ruby_opts = "-W -I./spec -rspec_helper" +end + +desc "Start up the test servers" +task :start do + require_relative 'spec/support/boot' + begin + Boot.start_servers(:rake) + rescue Exception + end +end + +task :default => :spec + diff --git a/bin/gems/ethon-0.16.0/ethon.gemspec b/bin/gems/ethon-0.16.0/ethon.gemspec new file mode 100644 index 00000000..561330b4 --- /dev/null +++ b/bin/gems/ethon-0.16.0/ethon.gemspec @@ -0,0 +1,26 @@ +# encoding: utf-8 +# frozen_string_literal: true +lib = File.expand_path('../lib/', __FILE__) +$:.unshift lib unless $:.include?(lib) + +require 'ethon/version' + +Gem::Specification.new do |s| + s.name = "ethon" + s.version = Ethon::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Hans Hasselberg"] + s.email = ["me@hans.io"] + s.homepage = "https://github.com/typhoeus/ethon" + s.summary = "Libcurl wrapper." + s.description = "Very lightweight libcurl wrapper." + + s.required_rubygems_version = ">= 1.3.6" + s.license = 'MIT' + + s.add_dependency('ffi', ['>= 1.15.0']) + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- spec/*`.split("\n") + s.require_path = 'lib' +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon.rb b/bin/gems/ethon-0.16.0/lib/ethon.rb new file mode 100644 index 00000000..461b4c36 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +require 'logger' +require 'ffi' +require 'thread' +begin + require 'mime/types/columnar' +rescue LoadError + begin + require 'mime/types' + rescue LoadError + end +end +require 'tempfile' + +require 'ethon/libc' +require 'ethon/curl' +require 'ethon/easy' +require 'ethon/errors' +require 'ethon/loggable' +require 'ethon/multi' +require 'ethon/version' + +# Ethon is a very simple libcurl. +# It provides direct access to libcurl functionality +# as well as some helpers for doing http requests. +# +# Ethon was extracted from Typhoeus. If you want to +# see how others use Ethon look at the Typhoeus code. +# +# @see https://www.github.com/typhoeus/typhoeus Typhoeus +# +# @note Please update to the latest libcurl version in order +# to benefit from all features and bugfixes. +# http://curl.haxx.se/download.html +module Ethon +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curl.rb b/bin/gems/ethon-0.16.0/lib/ethon/curl.rb new file mode 100644 index 00000000..f9194c7d --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curl.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true +require 'ethon/curls/codes' +require 'ethon/curls/options' +require 'ethon/curls/infos' +require 'ethon/curls/form_options' +require 'ethon/curls/messages' +require 'ethon/curls/functions' + +module Ethon + + # FFI Wrapper module for Curl. Holds constants and required initializers. + # + # @api private + module Curl + extend ::FFI::Library + extend Ethon::Curls::Codes + extend Ethon::Curls::Options + extend Ethon::Curls::Infos + extend Ethon::Curls::FormOptions + extend Ethon::Curls::Messages + + # :nodoc: + def self.windows? + Libc.windows? + end + + require 'ethon/curls/constants' + require 'ethon/curls/settings' + require 'ethon/curls/classes' + extend Ethon::Curls::Functions + + @blocking = true + + @@initialized = false + @@curl_mutex = Mutex.new + + class << self + # This function sets up the program environment that libcurl needs. + # Think of it as an extension of the library loader. + # + # This function must be called at least once within a program (a program is all the + # code that shares a memory space) before the program calls any other function in libcurl. + # The environment it sets up is constant for the life of the program and is the same for + # every program, so multiple calls have the same effect as one call. + # + # The flags option is a bit pattern that tells libcurl exactly what features to init, + # as described below. Set the desired bits by ORing the values together. In normal + # operation, you must specify CURL_GLOBAL_ALL. Don't use any other value unless + # you are familiar with it and mean to control internal operations of libcurl. + # + # This function is not thread safe. You must not call it when any other thread in + # the program (i.e. a thread sharing the same memory) is running. This doesn't just + # mean no other thread that is using libcurl. Because curl_global_init() calls + # functions of other libraries that are similarly thread unsafe, it could conflict with + # any other thread that uses these other libraries. + # + # @raise [ Ethon::Errors::GlobalInit ] If Curl.global_init fails. + def init + @@curl_mutex.synchronize { + if not @@initialized + raise Errors::GlobalInit.new if Curl.global_init(GLOBAL_ALL) != 0 + @@initialized = true + Ethon.logger.debug("ETHON: Libcurl initialized") if Ethon.logger + end + } + end + + # This function releases resources acquired by curl_global_init. + # You should call curl_global_cleanup once for each call you make to + # curl_global_init, after you are done using libcurl. + # This function is not thread safe. You must not call it when any other thread in the + # program (i.e. a thread sharing the same memory) is running. This doesn't just + # mean no other thread that is using libcurl. Because curl_global_cleanup calls functions of other + # libraries that are similarly thread unsafe, it could conflict with + # any other thread that uses these other libraries. + # See the description in libcurl of global environment requirements + # for details of how to use this function. + def cleanup + @@curl_mutex.synchronize { + if @@initialized + Curl.global_cleanup() + @@initialized = false + Ethon.logger.debug("ETHON: Libcurl cleanup") if Ethon.logger + end + } + end + + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/classes.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/classes.rb new file mode 100644 index 00000000..e663ac8c --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/classes.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +module Ethon + module Curl + # :nodoc: + class MsgData < ::FFI::Union + layout :whatever, :pointer, :code, :easy_code + end + + # :nodoc: + class Msg < ::FFI::Struct + layout :code, :msg_code, :easy_handle, :pointer, :data, MsgData + end + + class VersionInfoData < ::FFI::Struct + layout :curl_version, :uint8, + :version, :string, + :version_num, :int, + :host, :string, + :features, :int, + :ssl_version, :string, + :ssl_version_num, :long, + :libz_version, :string, + :protocols, :pointer + end + + # :nodoc: + class FDSet < ::FFI::Struct + if Curl.windows? + layout :fd_count, :uint, + # TODO: Make it future proof by dynamically grabbing FD_SETSIZE. + :fd_array, [:uint, 2048] + + def clear; self[:fd_count] = 0; end + else + # https://github.com/typhoeus/ethon/issues/182 + FD_SETSIZE = begin + # Allow to override the (new) default cap + if ENV['ETHON_FD_SIZE'] + ENV['ETHON_FD_SIZE'] + + # auto-detect ulimit, but cap at 2^16 + else + [::Ethon::Libc.getdtablesize, 65_536].min + end + end + + layout :fds_bits, [:long, FD_SETSIZE / ::FFI::Type::LONG.size] + + # :nodoc: + def clear; super; end + end + end + + # :nodoc: + class Timeval < ::FFI::Struct + if Curl.windows? + layout :sec, :long, + :usec, :long + else + layout :sec, :time_t, + :usec, :suseconds_t + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/codes.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/codes.rb new file mode 100644 index 00000000..4b53096a --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/codes.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true +module Ethon + module Curls # :nodoc: + + # This module contains all easy and + # multi return codes. + module Codes + + # Libcurl error codes, refer + # https://github.com/bagder/curl/blob/master/include/curl/curl.h for details + def easy_codes + [ + :ok, + :unsupported_protocol, + :failed_init, + :url_malformat, + :not_built_in, + :couldnt_resolve_proxy, + :couldnt_resolve_host, + :couldnt_connect, + :ftp_weird_server_reply, + :remote_access_denied, + :ftp_accept_failed, + :ftp_weird_pass_reply, + :ftp_accept_timeout, + :ftp_weird_pasv_reply, + :ftp_weird_227_format, + :ftp_cant_get_host, + :obsolete16, + :ftp_couldnt_set_type, + :partial_file, + :ftp_couldnt_retr_file, + :obsolete20, + :quote_error, + :http_returned_error, + :write_error, + :obsolete24, + :upload_failed, + :read_error, + :out_of_memory, + :operation_timedout, + :obsolete29, + :ftp_port_failed, + :ftp_couldnt_use_rest, + :obsolete32, + :range_error, + :http_post_error, + :ssl_connect_error, + :bad_download_resume, + :file_couldnt_read_file, + :ldap_cannot_bind, + :ldap_search_failed, + :obsolete40, + :function_not_found, + :aborted_by_callback, + :bad_function_argument, + :obsolete44, + :interface_failed, + :obsolete46, + :too_many_redirects , + :unknown_option, + :telnet_option_syntax , + :obsolete50, + :peer_failed_verification, + :got_nothing, + :ssl_engine_notfound, + :ssl_engine_setfailed, + :send_error, + :recv_error, + :obsolete57, + :ssl_certproblem, + :ssl_cipher, + :bad_content_encoding, + :ldap_invalid_url, + :filesize_exceeded, + :use_ssl_failed, + :send_fail_rewind, + :ssl_engine_initfailed, + :login_denied, + :tftp_notfound, + :tftp_perm, + :remote_disk_full, + :tftp_illegal, + :tftp_unknownid, + :remote_file_exists, + :tftp_nosuchuser, + :conv_failed, + :conv_reqd, + :ssl_cacert_badfile, + :remote_file_not_found, + :ssh, + :ssl_shutdown_failed, + :again, + :ssl_crl_badfile, + :ssl_issuer_error, + :ftp_pret_failed, + :rtsp_cseq_error, + :rtsp_session_error, + :ftp_bad_file_list, + :chunk_failed, + :last + ] + end + + # Curl-Multi socket error codes, refer + # https://github.com/bagder/curl/blob/master/include/curl/multi.h for details + def multi_codes + [ + :call_multi_perform, -1, + :ok, + :bad_handle, + :bad_easy_handle, + :out_of_memory, + :internal_error, + :bad_socket, + :unknown_option, + :last + ] + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/constants.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/constants.rb new file mode 100644 index 00000000..3c7c32d9 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/constants.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true +module Ethon + module Curl + # :nodoc: + VERSION_NOW = 3 + + # Flag. Initialize SSL. + GLOBAL_SSL = 0x01 + # Flag. Initialize win32 socket libraries. + GLOBAL_WIN32 = 0x02 + # Flag. Initialize everything possible. + GLOBAL_ALL = (GLOBAL_SSL | GLOBAL_WIN32) + # Flag. Initialize everything by default. + GLOBAL_DEFAULT = GLOBAL_ALL + + # :nodoc: + EasyCode = enum(:easy_code, easy_codes) + # :nodoc: + MultiCode = enum(:multi_code, multi_codes) + + # :nodoc: + EasyOption = enum(:easy_option, easy_options(:enum).to_a.flatten) + # :nodoc: + MultiOption = enum(:multi_option, multi_options(:enum).to_a.flatten) + + # Used by curl_debug_callback when setting CURLOPT_DEBUGFUNCTION + # https://github.com/bagder/curl/blob/master/include/curl/curl.h#L378 for details + DebugInfoType = enum(:debug_info_type, debug_info_types) + + # :nodoc: + InfoType = enum(info_types.to_a.flatten) + + # Info details, refer + # https://github.com/bagder/curl/blob/master/src/tool_writeout.c#L66 for details + Info = enum(:info, infos.to_a.flatten) + + # Form options, used by FormAdd for temporary storage, refer + # https://github.com/bagder/curl/blob/master/lib/formdata.h#L51 for details + FormOption = enum(:form_option, form_options) + + # :nodoc: + MsgCode = enum(:msg_code, msg_codes) + + VERSION_IPV6 = (1<<0) # IPv6-enabled + VERSION_KERBEROS4 = (1<<1) # kerberos auth is supported + VERSION_SSL = (1<<2) # SSL options are present + VERSION_LIBZ = (1<<3) # libz features are present + VERSION_NTLM = (1<<4) # NTLM auth is supported + VERSION_GSSNEGOTIATE = (1<<5) # Negotiate auth supp + VERSION_DEBUG = (1<<6) # built with debug capabilities + VERSION_ASYNCHDNS = (1<<7) # asynchronous dns resolves + VERSION_SPNEGO = (1<<8) # SPNEGO auth is supported + VERSION_LARGEFILE = (1<<9) # supports files bigger than 2GB + VERSION_IDN = (1<<10) # International Domain Names support + VERSION_SSPI = (1<<11) # SSPI is supported + VERSION_CONV = (1<<12) # character conversions supported + VERSION_CURLDEBUG = (1<<13) # debug memory tracking supported + VERSION_TLSAUTH_SRP = (1<<14) # TLS-SRP auth is supported + VERSION_NTLM_WB = (1<<15) # NTLM delegating to winbind helper + VERSION_HTTP2 = (1<<16) # HTTP2 support built + VERSION_GSSAPI = (1<<17) # GSS-API is supported + + SOCKET_BAD = -1 + SOCKET_TIMEOUT = SOCKET_BAD + + PollAction = enum(:poll_action, [ + :none, + :in, + :out, + :inout, + :remove + ]) + + SocketReadiness = bitmask(:socket_readiness, [ + :in, # CURL_CSELECT_IN - 0x01 (bit 0) + :out, # CURL_CSELECT_OUT - 0x02 (bit 1) + :err, # CURL_CSELECT_ERR - 0x04 (bit 2) + ]) + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/form_options.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/form_options.rb new file mode 100644 index 00000000..ce5f0793 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/form_options.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +module Ethon + module Curls + + # This module contains the available options for forms. + module FormOptions + + # Form options, used by FormAdd for temporary storage, refer + # https://github.com/bagder/curl/blob/master/lib/formdata.h#L51 for details + def form_options + [ + :none, + :copyname, + :ptrname, + :namelength, + :copycontents, + :ptrcontents, + :contentslength, + :filecontent, + :array, + :obsolete, + :file, + :buffer, + :bufferptr, + :bufferlength, + :contenttype, + :contentheader, + :filename, + :end, + :obsolete2, + :stream, + :last + ] + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/functions.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/functions.rb new file mode 100644 index 00000000..2c01bea4 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/functions.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true +module Ethon + module Curls + + # This module contains the functions to be attached in order to work with + # libcurl. + module Functions + + # :nodoc: + def self.extended(base) + base.attach_function :global_init, :curl_global_init, [:long], :int + base.attach_function :global_cleanup, :curl_global_cleanup, [], :void + base.attach_function :free, :curl_free, [:pointer], :void + + base.attach_function :easy_init, :curl_easy_init, [], :pointer + base.attach_function :easy_cleanup, :curl_easy_cleanup, [:pointer], :void + base.attach_function :easy_getinfo, :curl_easy_getinfo, [:pointer, :info, :varargs], :easy_code + base.attach_function :easy_setopt, :curl_easy_setopt, [:pointer, :easy_option, :varargs], :easy_code + base.instance_variable_set(:@blocking, true) + base.attach_function :easy_perform, :curl_easy_perform, [:pointer], :easy_code + base.attach_function :easy_strerror, :curl_easy_strerror, [:easy_code], :string + base.attach_function :easy_escape, :curl_easy_escape, [:pointer, :pointer, :int], :pointer + base.attach_function :easy_reset, :curl_easy_reset, [:pointer], :void + base.attach_function :easy_duphandle, :curl_easy_duphandle, [:pointer], :pointer + + base.attach_function :formadd, :curl_formadd, [:pointer, :pointer, :varargs], :int + base.attach_function :formfree, :curl_formfree, [:pointer], :void + + base.attach_function :multi_init, :curl_multi_init, [], :pointer + base.attach_function :multi_cleanup, :curl_multi_cleanup, [:pointer], :void + base.attach_function :multi_add_handle, :curl_multi_add_handle, [:pointer, :pointer], :multi_code + base.attach_function :multi_remove_handle, :curl_multi_remove_handle, [:pointer, :pointer], :multi_code + base.attach_function :multi_info_read, :curl_multi_info_read, [:pointer, :pointer], Curl::Msg.ptr + base.attach_function :multi_perform, :curl_multi_perform, [:pointer, :pointer], :multi_code + base.attach_function :multi_timeout, :curl_multi_timeout, [:pointer, :pointer], :multi_code + base.attach_function :multi_fdset, :curl_multi_fdset, [:pointer, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::FDSet.ptr, :pointer], :multi_code + base.attach_function :multi_strerror, :curl_multi_strerror, [:int], :string + base.attach_function :multi_setopt, :curl_multi_setopt, [:pointer, :multi_option, :varargs], :multi_code + base.attach_function :multi_socket_action, :curl_multi_socket_action, [:pointer, :int, :socket_readiness, :pointer], :multi_code + + base.attach_function :version, :curl_version, [], :string + base.attach_function :version_info, :curl_version_info, [], Curl::VersionInfoData.ptr + + base.attach_function :slist_append, :curl_slist_append, [:pointer, :string], :pointer + base.attach_function :slist_free_all, :curl_slist_free_all, [:pointer], :void + base.instance_variable_set(:@blocking, true) + + if Curl.windows? + base.ffi_lib 'ws2_32' + else + base.ffi_lib ::FFI::Library::LIBC + end + + base.attach_function :select, [:int, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::Timeval.ptr], :int + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/infos.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/infos.rb new file mode 100644 index 00000000..d285f5b9 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/infos.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true +module Ethon + module Curls + + # This module contains logic for the available informations + # on an easy, eg.: connect_time. + module Infos + + # Return info types. + # + # @example Return info types. + # Ethon::Curl.info_types + # + # @return [ Hash ] The info types. + def info_types + { + :string =>0x100000, + :long => 0x200000, + :double =>0x300000, + :slist => 0x400000 + } + end + + # http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTDEBUGFUNCTION + # https://github.com/bagder/curl/blob/master/include/curl/curl.h#L378 + # + # @example Return debug info types. + # Ethon::Curl.debug_info_types + # + # @return [ Hash ] The info types available to curl_debug_callback. + def debug_info_types + [ + :text, 0, + :header_in, + :header_out, + :data_in, + :data_out, + :ssl_data_in, + :ssl_data_out + ] + end + + # Return Info details, refer + # https://github.com/bagder/curl/blob/master/src/tool_writeout.c#L66 for details + # + # @example Return infos. + # Ethon::Curl.infos + # + # @return [ Hash ] The infos. + def infos + { + :effective_url => info_types[:string] + 1, + :response_code => info_types[:long] + 2, + :total_time => info_types[:double] + 3, + :namelookup_time => info_types[:double] + 4, + :connect_time => info_types[:double] + 5, + :pretransfer_time => info_types[:double] + 6, + :size_upload => info_types[:double] + 7, + :size_download => info_types[:double] + 8, + :speed_download => info_types[:double] + 9, + :speed_upload => info_types[:double] + 10, + :header_size => info_types[:long] + 11, + :request_size => info_types[:long] + 12, + :ssl_verifyresult => info_types[:long] + 13, + :filetime => info_types[:long] + 14, + :content_length_download =>info_types[:double] + 15, + :content_length_upload => info_types[:double] + 16, + :starttransfer_time => info_types[:double] + 17, + :content_type => info_types[:string] + 18, + :redirect_time => info_types[:double] + 19, + :redirect_count => info_types[:long] + 20, + :private => info_types[:string] + 21, + :http_connectcode => info_types[:long] + 22, + :httpauth_avail => info_types[:long] + 23, + :proxyauth_avail => info_types[:long] + 24, + :os_errno => info_types[:long] + 25, + :num_connects => info_types[:long] + 26, + :ssl_engines => info_types[:slist] + 27, + :cookielist => info_types[:slist] + 28, + :lastsocket => info_types[:long] + 29, + :ftp_entry_path => info_types[:string] + 30, + :redirect_url => info_types[:string] + 31, + :primary_ip => info_types[:string] + 32, + :appconnect_time => info_types[:double] + 33, + :certinfo => info_types[:slist] + 34, + :condition_unmet => info_types[:long] + 35, + :rtsp_session_id => info_types[:string] + 36, + :rtsp_client_cseq => info_types[:long] + 37, + :rtsp_server_cseq => info_types[:long] + 38, + :rtsp_cseq_recv => info_types[:long] + 39, + :primary_port => info_types[:long] + 40, + :local_ip => info_types[:string] + 41, + :local_port => info_types[:long] + 42, + :last =>42 + } + end + + # Return info as string. + # + # @example Return info. + # Curl.get_info_string(:primary_ip, easy) + # + # @param [ Symbol ] option The option name. + # @param [ ::FFI::Pointer ] handle The easy handle. + # + # @return [ String ] The info. + def get_info_string(option, handle) + string_ptr = ::FFI::MemoryPointer.new(:pointer) + + if easy_getinfo(handle, option, :pointer, string_ptr) == :ok + ptr=string_ptr.read_pointer + ptr.null? ? nil : ptr.read_string + end + end + + # Return info as integer. + # + # @example Return info. + # Curl.get_info_long(:response_code, easy) + # + # @param [ Symbol ] option The option name. + # @param [ ::FFI::Pointer ] handle The easy handle. + # + # @return [ Integer ] The info. + def get_info_long(option, handle) + long_ptr = ::FFI::MemoryPointer.new(:long) + + if easy_getinfo(handle, option, :pointer, long_ptr) == :ok + long_ptr.read_long + end + end + + # Return info as float + # + # @example Return info. + # Curl.get_info_double(:response_code, easy) + # + # @param [ Symbol ] option The option name. + # @param [ ::FFI::Pointer ] handle The easy handle. + # + # @return [ Float ] The info. + def get_info_double(option, handle) + double_ptr = ::FFI::MemoryPointer.new(:double) + + if easy_getinfo(handle, option, :pointer, double_ptr) == :ok + double_ptr.read_double + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/messages.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/messages.rb new file mode 100644 index 00000000..72bc54d5 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/messages.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +module Ethon + module Curls + + # This module contains available message codes. + module Messages + + # Return message codes. + # + # @example Return message codes. + # Ethon::Curl.msg_codes + # + # @return [ Array ] The messages codes. + def msg_codes + [:none, :done, :last] + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/options.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/options.rb new file mode 100644 index 00000000..0c391d44 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/options.rb @@ -0,0 +1,503 @@ +# frozen_string_literal: true +module Ethon + module Curls + + # This module contains logic for setting options on + # easy or multi interface. + module Options + + OPTION_STRINGS = { :easy => 'easy_options', :multi => 'multi_options' }.freeze + FOPTION_STRINGS = { :easy => 'EASY_OPTIONS', :multi => 'MULTI_OPTIONS' }.freeze + FUNCS = { :easy => 'easy_setopt', :multi => 'multi_setopt' }.freeze + # Sets appropriate option for easy, depending on value type. + def set_option(option, value, handle, type = :easy) + type = type.to_sym unless type.is_a?(Symbol) + raise NameError, "Ethon::Curls::Options unknown type #{type}." unless respond_to?(OPTION_STRINGS[type]) + opthash=send(OPTION_STRINGS[type], nil) + raise Errors::InvalidOption.new(option) unless opthash.include?(option) + + case opthash[option][:type] + when :none + return if value.nil? + value=1 + va_type=:long + when :int + return if value.nil? + va_type=:long + value=value.to_i + when :bool + return if value.nil? + va_type=:long + value=(value&&value!=0) ? 1 : 0 + when :time + return if value.nil? + va_type=:long + value=value.to_i + when :enum + return if value.nil? + va_type=:long + value = case value + when Symbol + opthash[option][:opts][value] + when String + opthash[option][:opts][value.to_sym] + else + value + end.to_i + when :bitmask + return if value.nil? + va_type=:long + value = case value + when Symbol + opthash[option][:opts][value] + when Array + value.inject(0) { |res,v| res|opthash[option][:opts][v] } + else + value + end.to_i + when :string + va_type=:string + value=value.to_s unless value.nil? + when :string_as_pointer + va_type = :pointer + s = '' + s = value.to_s unless value.nil? + value = FFI::MemoryPointer.new(:char, s.bytesize) + value.put_bytes(0, s) + when :string_escape_null + va_type=:string + value=Util.escape_zero_byte(value) unless value.nil? + when :ffipointer + va_type=:pointer + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer + when :curl_slist + va_type=:pointer + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer + when :buffer + raise NotImplementedError, "Ethon::Curls::Options option #{option} buffer type not implemented." + when :dontuse_object + raise NotImplementedError, "Ethon::Curls::Options option #{option} type not implemented." + when :cbdata + raise NotImplementedError, "Ethon::Curls::Options option #{option} callback data type not implemented. Use Ruby closures." + when :callback + va_type=:callback + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc + when :socket_callback + va_type=:socket_callback + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc + when :timer_callback + va_type=:timer_callback + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc + when :debug_callback + va_type=:debug_callback + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc + when :progress_callback + va_type=:progress_callback + raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc + when :off_t + return if value.nil? + va_type=:int64 + value=value.to_i + end + + if va_type==:long or va_type==:int64 then + bits=FFI.type_size(va_type)*8 + tv=((value<0) ? value.abs-1 : value) + raise Errors::InvalidValue.new(option,value) unless tv<(1< 0, + :objectpoint => 10000, + :functionpoint => 20000, + :off_t => 30000 + } + OPTION_TYPE_MAP = { + :none => :long, + :int => :long, + :bool => :long, + :time => :long, + :enum => :long, # Two ways to specify values (as opts parameter): + # * Array of symbols, these will number sequentially + # starting at 0. Skip elements with nil. (see :netrc) + # * Hash of :symbol => enum_value (See :proxytype) + :bitmask => :long, # Three ways to specify values (as opts parameter): + # * Hash of :symbol => bitmask_value or Array. + # An Array can be an array of already defined + # Symbols, which represents a bitwise or of those + # symbols. (See :httpauth) + # * Array of symbols, these will number the bits + # sequentially (i.e. 0, 1, 2, 4, etc.). Skip + # elements with nil. The last element can be a + # Hash, which will be interpreted as above. + # (See :protocols) + # :all defaults to all bits set + :string => :objectpoint, + :string_escape_null => :objectpoint, + :string_as_pointer => :objectpoint, + :ffipointer => :objectpoint, # FFI::Pointer + :curl_slist => :objectpoint, + :buffer => :objectpoint, # A memory buffer of size defined in the options + :dontuse_object => :objectpoint, # An object we don't support (e.g. FILE*) + :cbdata => :objectpoint, + :callback => :functionpoint, + :socket_callback => :functionpoint, + :timer_callback => :functionpoint, + :debug_callback => :functionpoint, + :progress_callback => :functionpoint, + :off_t => :off_t, + } + + def self.option(ftype,name,type,num,opts=nil) + case type + when :enum + if opts.is_a? Array then + opts=Hash[opts.each_with_index.to_a] + elsif not opts.is_a? Hash then + raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." + end + + when :bitmask + if opts.is_a? Array then + if opts.last.is_a? Hash then + hopts=opts.pop + else + hopts={} + end + opts.each_with_index do |v,i| + next if v.nil? + if i==0 then + hopts[v]=0 + else + hopts[v]=1<<(i-1) + end + end + opts=hopts + elsif not opts.is_a? Hash then + raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." + end + opts[:all]=-1 unless opts.include? :all + opts.each do |k,v| + if v.is_a? Array then + opts[k]=v.map { |b| opts[b] }.inject :| + end + end + + when :buffer + raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." unless opts.is_a? Integer + + else + raise ArgumentError, "Ethon::Curls::Options #{ftype} #{name} Expected no opts." unless opts.nil? + end + opthash=const_get(FOPTION_STRINGS[ftype]) + opthash[name] = { :type => type, + :opt => OPTION_TYPE_BASE[OPTION_TYPE_MAP[type]] + num, + :opts => opts } + end + + def self.option_alias(ftype,name,*aliases) + opthash=const_get(FOPTION_STRINGS[ftype]) + aliases.each { |a| opthash[a]=opthash[name] } + end + + def self.option_type(type) + cname = FOPTION_STRINGS[type] + const_set(cname, {}) + define_method(OPTION_STRINGS[type]) do |rt| + return Ethon::Curls::Options.const_get(cname).map { |k, v| [k, v[:opt]] } if rt == :enum + Ethon::Curls::Options.const_get(cname) + end + end + + # Curl multi options, refer + # Defined @ https://github.com/bagder/curl/blob/master/include/curl/multi.h + # Documentation @ http://curl.haxx.se/libcurl/c/curl_multi_setopt.html + option_type :multi + + option :multi, :socketfunction, :socket_callback, 1 + option :multi, :socketdata, :cbdata, 2 + option :multi, :pipelining, :int, 3 + option :multi, :timerfunction, :timer_callback, 4 + option :multi, :timerdata, :cbdata, 5 + option :multi, :maxconnects, :int, 6 + option :multi, :max_host_connections, :int, 7 + option :multi, :max_pipeline_length, :int, 8 + option :multi, :content_length_penalty_size, :off_t, 9 + option :multi, :chunk_length_penalty_size, :off_t, 10 + option :multi, :pipelining_site_bl, :dontuse_object, 11 + option :multi, :pipelining_server_bl, :dontuse_object, 12 + option :multi, :max_total_connections, :int, 3 + + # Curl easy options + # Defined @ https://github.com/bagder/curl/blob/master/include/curl/curl.h + # Documentation @ http://curl.haxx.se/libcurl/c/curl_easy_setopt.html + ## BEHAVIOR OPTIONS + option_type :easy + + option :easy, :verbose, :bool, 41 + option :easy, :header, :bool, 42 + option :easy, :noprogress, :bool, 43 + option :easy, :nosignal, :bool, 99 + option :easy, :wildcardmatch, :bool, 197 + ## CALLBACK OPTIONS + option :easy, :writefunction, :callback, 11 + option :easy, :file, :cbdata, 1 + option_alias :easy, :file, :writedata + option :easy, :readfunction, :callback, 12 + option :easy, :infile, :cbdata, 9 + option_alias :easy, :infile, :readdata + option :easy, :ioctlfunction, :callback, 130 + option :easy, :ioctldata, :cbdata, 131 + option :easy, :seekfunction, :callback, 167 + option :easy, :seekdata, :cbdata, 168 + option :easy, :sockoptfunction, :callback, 148 + option :easy, :sockoptdata, :cbdata, 149 + option :easy, :opensocketfunction, :callback, 163 + option :easy, :opensocketdata, :cbdata, 164 + option :easy, :closesocketfunction, :callback, 208 + option :easy, :closesocketdata, :cbdata, 209 + option :easy, :path_as_is, :bool, 234 + option :easy, :progressfunction, :progress_callback, 56 + option :easy, :progressdata, :cbdata, 57 + option :easy, :headerfunction, :callback, 79 + option :easy, :writeheader, :cbdata, 29 + option_alias :easy, :writeheader, :headerdata + option :easy, :debugfunction, :debug_callback, 94 + option :easy, :debugdata, :cbdata, 95 + option :easy, :ssl_ctx_function, :callback, 108 + option :easy, :ssl_ctx_data, :cbdata, 109 + option :easy, :conv_to_network_function, :callback, 143 + option :easy, :conv_from_network_function, :callback, 142 + option :easy, :conv_from_utf8_function, :callback, 144 + option :easy, :interleavefunction, :callback, 196 + option :easy, :interleavedata, :cbdata, 195 + option :easy, :chunk_bgn_function, :callback, 198 + option :easy, :chunk_end_function, :callback, 199 + option :easy, :chunk_data, :cbdata, 201 + option :easy, :fnmatch_function, :callback, 200 + option :easy, :fnmatch_data, :cbdata, 202 + option :easy, :xferinfofunction, :progress_callback, 219 + option :easy, :xferinfodata, :cbdata, 57 + ## ERROR OPTIONS + option :easy, :errorbuffer, :buffer, 10, 256 + option :easy, :stderr, :dontuse_object, 37 + option :easy, :failonerror, :bool, 45 + ## NETWORK OPTIONS + option :easy, :url, :string, 2 + option :easy, :protocols, :bitmask, 181, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher] + option :easy, :redir_protocols, :bitmask, 182, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher] + option :easy, :proxy, :string, 4 + option :easy, :proxyport, :int, 59 + option :easy, :proxytype, :enum, 101, [:http, :http_1_0, :https, nil, :socks4, :socks5, :socks4a, :socks5_hostname] + option :easy, :noproxy, :string, 177 + option :easy, :httpproxytunnel, :bool, 61 + option :easy, :socks5_gssapi_service, :string, 179 + option :easy, :socks5_gssapi_nec, :bool, 180 + option :easy, :interface, :string, 62 + option :easy, :localport, :int, 139 + option :easy, :localportrange, :int, 140 + option :easy, :dns_cache_timeout, :int, 92 + option :easy, :dns_use_global_cache, :bool, 91 # Obsolete + option :easy, :dns_interface, :string, 221 + option :easy, :dns_local_ip4, :string, 222 + option :easy, :dns_shuffle_addresses, :bool, 275 + option :easy, :buffersize, :int, 98 + option :easy, :port, :int, 3 + option :easy, :tcp_nodelay, :bool, 121 + option :easy, :address_scope, :int, 171 + option :easy, :tcp_fastopen, :bool, 212 + option :easy, :tcp_keepalive, :bool, 213 + option :easy, :tcp_keepidle, :int, 214 + option :easy, :tcp_keepintvl, :int, 215 + ## NAMES and PASSWORDS OPTIONS (Authentication) + option :easy, :netrc, :enum, 51, [:ignored, :optional, :required] + option :easy, :netrc_file, :string, 118 + option :easy, :userpwd, :string, 5 + option :easy, :proxyuserpwd, :string, 6 + option :easy, :username, :string, 173 + option :easy, :password, :string, 174 + option :easy, :proxyusername, :string, 175 + option :easy, :proxypassword, :string, 176 + option :easy, :httpauth, :bitmask, 107, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}] + option :easy, :tlsauth_type, :enum, 206, [:none, :srp] + option :easy, :tlsauth_username, :string, 204 + option :easy, :tlsauth_password, :string, 205 + option :easy, :proxyauth, :bitmask, 111, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}] + option :easy, :sasl_ir, :bool, 218 + ## HTTP OPTIONS + option :easy, :autoreferer, :bool, 58 + option :easy, :accept_encoding, :string, 102 + option_alias :easy, :accept_encoding, :encoding + option :easy, :transfer_encoding, :bool, 207 + option :easy, :followlocation, :bool, 52 + option :easy, :unrestricted_auth, :bool, 105 + option :easy, :maxredirs, :int, 68 + option :easy, :postredir, :bitmask, 161, [:get_all, :post_301, :post_302, :post_303, {:post_all => [:post_301, :post_302, :post_303]}] + option_alias :easy, :postredir, :post301 + option :easy, :put, :bool, 54 + option :easy, :post, :bool, 47 + option :easy, :postfields, :string, 15 + option :easy, :postfieldsize, :int, 60 + option :easy, :postfieldsize_large, :off_t, 120 + option :easy, :copypostfields, :string_as_pointer, 165 + option :easy, :httppost, :ffipointer, 24 + option :easy, :referer, :string, 16 + option :easy, :useragent, :string, 18 + option :easy, :httpheader, :curl_slist, 23 + option :easy, :http200aliases, :curl_slist, 104 + option :easy, :cookie, :string, 22 + option :easy, :cookiefile, :string, 31 + option :easy, :cookiejar, :string, 82 + option :easy, :cookiesession, :bool, 96 + option :easy, :cookielist, :string, 135 + option :easy, :httpget, :bool, 80 + option :easy, :http_version, :enum, 84, [:none, :httpv1_0, :httpv1_1, :httpv2_0, :httpv2_tls, :httpv2_prior_knowledge] + option :easy, :ignore_content_length, :bool, 136 + option :easy, :http_content_decoding, :bool, 158 + option :easy, :http_transfer_decoding, :bool, 157 + ## SMTP OPTIONS + option :easy, :mail_from, :string, 186 + option :easy, :mail_rcpt, :curl_slist, 187 + option :easy, :mail_auth, :string, 217 + ## TFTP OPTIONS + option :easy, :tftp_blksize, :int, 178 + ## FTP OPTIONS + option :easy, :ftpport, :string, 17 + option :easy, :quote, :curl_slist, 28 + option :easy, :postquote, :curl_slist, 39 + option :easy, :prequote, :curl_slist, 93 + option :easy, :dirlistonly, :bool, 48 + option_alias :easy, :dirlistonly, :ftplistonly + option :easy, :append, :bool, 50 + option_alias :easy, :append, :ftpappend + option :easy, :ftp_use_eprt, :bool, 106 + option :easy, :ftp_use_epsv, :bool, 85 + option :easy, :ftp_use_pret, :bool, 188 + option :easy, :ftp_create_missing_dirs, :bool, 110 + option :easy, :ftp_response_timeout, :int, 112 + option_alias :easy, :ftp_response_timeout, :server_response_timeout + option :easy, :ftp_alternative_to_user, :string, 147 + option :easy, :ftp_skip_pasv_ip, :bool, 137 + option :easy, :ftpsslauth, :enum, 129, [:default, :ssl, :tls] + option :easy, :ftp_ssl_ccc, :enum, 154, [:none, :passive, :active] + option :easy, :ftp_account, :string, 134 + option :easy, :ftp_filemethod, :enum, 138, [:default, :multicwd, :nocwd, :singlecwd] + ## RTSP OPTIONS + option :easy, :rtsp_request, :enum, 189, [:none, :options, :describe, :announce, :setup, :play, :pause, :teardown, :get_parameter, :set_parameter, :record, :receive] + option :easy, :rtsp_session_id, :string, 190 + option :easy, :rtsp_stream_uri, :string, 191 + option :easy, :rtsp_transport, :string, 192 + option_alias :easy, :httpheader, :rtspheader + option :easy, :rtsp_client_cseq, :int, 193 + option :easy, :rtsp_server_cseq, :int, 194 + ## PROTOCOL OPTIONS + option :easy, :transfertext, :bool, 53 + option :easy, :proxy_transfer_mode, :bool, 166 + option :easy, :crlf, :bool, 27 + option :easy, :range, :string, 7 + option :easy, :resume_from, :int, 21 + option :easy, :resume_from_large, :off_t, 116 + option :easy, :customrequest, :string, 36 + option :easy, :filetime, :bool, 69 + option :easy, :nobody, :bool, 44 + option :easy, :infilesize, :int, 14 + option :easy, :infilesize_large, :off_t, 115 + option :easy, :upload, :bool, 46 + option :easy, :maxfilesize, :int, 114 + option :easy, :maxfilesize_large, :off_t, 117 + option :easy, :timecondition, :enum, 33, [:none, :ifmodsince, :ifunmodsince, :lastmod] + option :easy, :timevalue, :time, 34 + ## CONNECTION OPTIONS + option :easy, :timeout, :int, 13 + option :easy, :timeout_ms, :int, 155 + option :easy, :low_speed_limit, :int, 19 + option :easy, :low_speed_time, :int, 20 + option :easy, :max_send_speed_large, :off_t, 145 + option :easy, :max_recv_speed_large, :off_t, 146 + option :easy, :maxconnects, :int, 71 + option :easy, :fresh_connect, :bool, 74 + option :easy, :forbid_reuse, :bool, 75 + option :easy, :connecttimeout, :int, 78 + option :easy, :connecttimeout_ms, :int, 156 + option :easy, :ipresolve, :enum, 113, [:whatever, :v4, :v6] + option :easy, :connect_only, :bool, 141 + option :easy, :use_ssl, :enum, 119, [:none, :try, :control, :all] + option_alias :easy, :use_ssl, :ftp_ssl + option :easy, :resolve, :curl_slist, 203 + option :easy, :dns_servers, :string, 211 + option :easy, :accepttimeout_ms, :int, 212 + option :easy, :unix_socket_path, :string, 231 + option :easy, :pipewait, :bool, 237 + option_alias :easy, :unix_socket_path, :unix_socket + ## SSL and SECURITY OPTIONS + option :easy, :sslcert, :string, 25 + option :easy, :sslcerttype, :string, 86 + option :easy, :sslkey, :string, 87 + option :easy, :sslkeytype, :string, 88 + option :easy, :keypasswd, :string, 26 + option_alias :easy, :keypasswd, :sslcertpasswd + option_alias :easy, :keypasswd, :sslkeypasswd + option :easy, :sslengine, :string, 89 + option :easy, :sslengine_default, :none, 90 + option :easy, :sslversion, :enum, 32, [:default, :tlsv1, :sslv2, :sslv3, :tlsv1_0, :tlsv1_1, :tlsv1_2, :tlsv1_3] + option :easy, :ssl_verifypeer, :bool, 64 + option :easy, :cainfo, :string, 65 + option :easy, :issuercert, :string, 170 + option :easy, :capath, :string, 97 + option :easy, :crlfile, :string, 169 + option :easy, :ssl_verifyhost, :int, 81 + option :easy, :certinfo, :bool, 172 + option :easy, :random_file, :string, 76 + option :easy, :egdsocket, :string, 77 + option :easy, :ssl_cipher_list, :string, 83 + option :easy, :ssl_sessionid_cache, :bool, 150 + option :easy, :ssl_options, :bitmask, 216, [nil, :allow_beast] + option :easy, :krblevel, :string, 63 + option_alias :easy, :krblevel, :krb4level + option :easy, :gssapi_delegation, :bitmask, 210, [:none, :policy_flag, :flag] + option :easy, :pinnedpublickey, :string, 230 + option_alias :easy, :pinnedpublickey, :pinned_public_key + ## PROXY SSL OPTIONS + option :easy, :proxy_cainfo, :string, 246 + option :easy, :proxy_capath, :string, 247 + option :easy, :proxy_ssl_verifypeer, :bool, 248 + option :easy, :proxy_ssl_verifyhost, :int, 249 + option :easy, :proxy_sslversion, :enum, 250, [:default, :tlsv1, :sslv2, :sslv3, :tlsv1_0, :tlsv1_1, :tlsv1_2, :tlsv1_3] + option :easy, :proxy_tlsauth_username, :string, 251 + option :easy, :proxy_tlsauth_password, :string, 252 + option :easy, :proxy_tlsauth_type, :enum, 253, [:none, :srp] + option :easy, :proxy_sslcert, :string, 254 + option :easy, :proxy_sslcerttype, :string, 255 + option :easy, :proxy_sslkey, :string, 256 + option :easy, :proxy_sslkeytype, :string, 257 + option :easy, :proxy_keypasswd, :string, 258 + option_alias :easy, :proxy_keypasswd, :proxy_sslcertpasswd + option_alias :easy, :proxy_keypasswd, :proxy_sslkeypasswd + option :easy, :proxy_ssl_cipher_list, :string, 259 + option :easy, :proxy_crlfile, :string, 260 + option :easy, :proxy_ssl_options, :bitmask, 261, [nil, :allow_beast] + option :easy, :pre_proxy, :string, 262 + option :easy, :proxy_pinnedpublickey, :string, 263 + option_alias :easy, :proxy_pinnedpublickey, :proxy_pinned_public_key + option :easy, :proxy_issuercert, :string, 296 + ## SSH OPTIONS + option :easy, :ssh_auth_types, :bitmask, 151, [:none, :publickey, :password, :host, :keyboard, :agent, {:any => [:all], :default => [:any]}] + option :easy, :ssh_host_public_key_md5, :string, 162 + option :easy, :ssh_public_keyfile, :string, 152 + option :easy, :ssh_private_keyfile, :string, 153 + option :easy, :ssh_knownhosts, :string, 183 + option :easy, :ssh_keyfunction, :callback, 184 + option :easy, :khstat, :enum, -1, [:fine_add_to_file, :fine, :reject, :defer] # Kludge to make this enum available... Access via CurL::EASY_OPTIONS[:khstat][:opt] + option :easy, :ssh_keydata, :cbdata, 185 + ## OTHER OPTIONS + option :easy, :private, :cbdata, 103 + option :easy, :share, :dontuse_object, 100 + option :easy, :new_file_perms, :int, 159 + option :easy, :new_directory_perms, :int, 160 + ## TELNET OPTIONS + option :easy, :telnetoptions, :curl_slist, 70 + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/curls/settings.rb b/bin/gems/ethon-0.16.0/lib/ethon/curls/settings.rb new file mode 100644 index 00000000..8c0161b4 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/curls/settings.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +module Ethon + module Curl + callback :callback, [:pointer, :size_t, :size_t, :pointer], :size_t + callback :socket_callback, [:pointer, :int, :poll_action, :pointer, :pointer], :multi_code + callback :timer_callback, [:pointer, :long, :pointer], :multi_code + callback :debug_callback, [:pointer, :debug_info_type, :pointer, :size_t, :pointer], :int + callback :progress_callback, [:pointer, :long_long, :long_long, :long_long, :long_long], :int + ffi_lib_flags :now, :global + ffi_lib ['libcurl', 'libcurl.so.4'] + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy.rb new file mode 100644 index 00000000..355a5194 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy.rb @@ -0,0 +1,315 @@ +# frozen_string_literal: true +require 'ethon/easy/informations' +require 'ethon/easy/features' +require 'ethon/easy/callbacks' +require 'ethon/easy/options' +require 'ethon/easy/header' +require 'ethon/easy/util' +require 'ethon/easy/params' +require 'ethon/easy/form' +require 'ethon/easy/http' +require 'ethon/easy/operations' +require 'ethon/easy/response_callbacks' +require 'ethon/easy/debug_info' +require 'ethon/easy/mirror' + +module Ethon + + # This is the class representing the libcurl easy interface + # See http://curl.haxx.se/libcurl/c/libcurl-easy.html for more informations. + # + # @example You can access the libcurl easy interface through this class, every request is based on it. The simplest setup looks like that: + # + # e = Ethon::Easy.new(url: "www.example.com") + # e.perform + # #=> :ok + # + # @example You can the reuse this Easy for the next request: + # + # e.reset # reset easy handle + # e.url = "www.google.com" + # e.followlocation = true + # e.perform + # #=> :ok + # + # @see initialize + class Easy + include Ethon::Easy::Informations + include Ethon::Easy::Callbacks + include Ethon::Easy::Options + include Ethon::Easy::Header + include Ethon::Easy::Http + include Ethon::Easy::Operations + include Ethon::Easy::ResponseCallbacks + extend Ethon::Easy::Features + + # Returns the curl return code. + # + # @return [ Symbol ] The return code. + # * :ok: All fine. Proceed as usual. + # * :unsupported_protocol: The URL you passed to libcurl used a + # protocol that this libcurl does not support. The support + # might be a compile-time option that you didn't use, it can + # be a misspelled protocol string or just a protocol + # libcurl has no code for. + # * :failed_init: Very early initialization code failed. This + # is likely to be an internal error or problem, or a + # resource problem where something fundamental couldn't + # get done at init time. + # * :url_malformat: The URL was not properly formatted. + # * :not_built_in: A requested feature, protocol or option + # was not found built-in in this libcurl due to a build-time + # decision. This means that a feature or option was not enabled + # or explicitly disabled when libcurl was built and in + # order to get it to function you have to get a rebuilt libcurl. + # * :couldnt_resolve_proxy: Couldn't resolve proxy. The given + # proxy host could not be resolved. + # * :couldnt_resolve_host: Couldn't resolve host. The given remote + # host was not resolved. + # * :couldnt_connect: Failed to connect() to host or proxy. + # * :ftp_weird_server_reply: After connecting to a FTP server, + # libcurl expects to get a certain reply back. This error + # code implies that it got a strange or bad reply. The given + # remote server is probably not an OK FTP server. + # * :remote_access_denied: We were denied access to the resource + # given in the URL. For FTP, this occurs while trying to + # change to the remote directory. + # * :ftp_accept_failed: While waiting for the server to connect + # back when an active FTP session is used, an error code was + # sent over the control connection or similar. + # * :ftp_weird_pass_reply: After having sent the FTP password to + # the server, libcurl expects a proper reply. This error code + # indicates that an unexpected code was returned. + # * :ftp_accept_timeout: During an active FTP session while + # waiting for the server to connect, the CURLOPT_ACCEPTTIMOUT_MS + # (or the internal default) timeout expired. + # * :ftp_weird_pasv_reply: libcurl failed to get a sensible result + # back from the server as a response to either a PASV or a + # EPSV command. The server is flawed. + # * :ftp_weird_227_format: FTP servers return a 227-line as a response + # to a PASV command. If libcurl fails to parse that line, + # this return code is passed back. + # * :ftp_cant_get_host: An internal failure to lookup the host used + # for the new connection. + # * :ftp_couldnt_set_type: Received an error when trying to set + # the transfer mode to binary or ASCII. + # * :partial_file: A file transfer was shorter or larger than + # expected. This happens when the server first reports an expected + # transfer size, and then delivers data that doesn't match the + # previously given size. + # * :ftp_couldnt_retr_file: This was either a weird reply to a + # 'RETR' command or a zero byte transfer complete. + # * :quote_error: When sending custom "QUOTE" commands to the + # remote server, one of the commands returned an error code that + # was 400 or higher (for FTP) or otherwise indicated unsuccessful + # completion of the command. + # * :http_returned_error: This is returned if CURLOPT_FAILONERROR is + # set TRUE and the HTTP server returns an error code that is >= 400. + # * :write_error: An error occurred when writing received data to a + # local file, or an error was returned to libcurl from a write callback. + # * :upload_failed: Failed starting the upload. For FTP, the server + # typically denied the STOR command. The error buffer usually + # contains the server's explanation for this. + # * :read_error: There was a problem reading a local file or an error + # returned by the read callback. + # * :out_of_memory: A memory allocation request failed. This is serious + # badness and things are severely screwed up if this ever occurs. + # * :operation_timedout: Operation timeout. The specified time-out + # period was reached according to the conditions. + # * :ftp_port_failed: The FTP PORT command returned error. This mostly + # happens when you haven't specified a good enough address for + # libcurl to use. See CURLOPT_FTPPORT. + # * :ftp_couldnt_use_rest: The FTP REST command returned error. This + # should never happen if the server is sane. + # * :range_error: The server does not support or accept range requests. + # * :http_post_error: This is an odd error that mainly occurs due to + # internal confusion. + # * :ssl_connect_error: A problem occurred somewhere in the SSL/TLS + # handshake. You really want the error buffer and read the message + # there as it pinpoints the problem slightly more. Could be + # certificates (file formats, paths, permissions), passwords, and others. + # * :bad_download_resume: The download could not be resumed because + # the specified offset was out of the file boundary. + # * :file_couldnt_read_file: A file given with FILE:// couldn't be + # opened. Most likely because the file path doesn't identify an + # existing file. Did you check file permissions? + # * :ldap_cannot_bind: LDAP cannot bind. LDAP bind operation failed. + # * :ldap_search_failed: LDAP search failed. + # * :function_not_found: Function not found. A required zlib function was not found. + # * :aborted_by_callback: Aborted by callback. A callback returned + # "abort" to libcurl. + # * :bad_function_argument: Internal error. A function was called with + # a bad parameter. + # * :interface_failed: Interface error. A specified outgoing interface + # could not be used. Set which interface to use for outgoing + # connections' source IP address with CURLOPT_INTERFACE. + # * :too_many_redirects: Too many redirects. When following redirects, + # libcurl hit the maximum amount. Set your limit with CURLOPT_MAXREDIRS. + # * :unknown_option: An option passed to libcurl is not recognized/known. + # Refer to the appropriate documentation. This is most likely a + # problem in the program that uses libcurl. The error buffer might + # contain more specific information about which exact option it concerns. + # * :telnet_option_syntax: A telnet option string was Illegally formatted. + # * :peer_failed_verification: The remote server's SSL certificate or + # SSH md5 fingerprint was deemed not OK. + # * :got_nothing: Nothing was returned from the server, and under the + # circumstances, getting nothing is considered an error. + # * :ssl_engine_notfound: The specified crypto engine wasn't found. + # * :ssl_engine_setfailed: Failed setting the selected SSL crypto engine as default! + # * :send_error: Failed sending network data. + # * :recv_error: Failure with receiving network data. + # * :ssl_certproblem: problem with the local client certificate. + # * :ssl_cipher: Couldn't use specified cipher. + # * :bad_content_encoding: Unrecognized transfer encoding. + # * :ldap_invalid_url: Invalid LDAP URL. + # * :filesize_exceeded: Maximum file size exceeded. + # * :use_ssl_failed: Requested FTP SSL level failed. + # * :send_fail_rewind: When doing a send operation curl had to rewind the data to + # retransmit, but the rewinding operation failed. + # * :ssl_engine_initfailed: Initiating the SSL Engine failed. + # * :login_denied: The remote server denied curl to login + # * :tftp_notfound: File not found on TFTP server. + # * :tftp_perm: Permission problem on TFTP server. + # * :remote_disk_full: Out of disk space on the server. + # * :tftp_illegal: Illegal TFTP operation. + # * :tftp_unknownid: Unknown TFTP transfer ID. + # * :remote_file_exists: File already exists and will not be overwritten. + # * :tftp_nosuchuser: This error should never be returned by a properly + # functioning TFTP server. + # * :conv_failed: Character conversion failed. + # * :conv_reqd: Caller must register conversion callbacks. + # * :ssl_cacert_badfile: Problem with reading the SSL CA cert (path? access rights?): + # * :remote_file_not_found: The resource referenced in the URL does not exist. + # * :ssh: An unspecified error occurred during the SSH session. + # * :ssl_shutdown_failed: Failed to shut down the SSL connection. + # * :again: Socket is not ready for send/recv wait till it's ready and try again. + # This return code is only returned from curl_easy_recv(3) and curl_easy_send(3) + # * :ssl_crl_badfile: Failed to load CRL file + # * :ssl_issuer_error: Issuer check failed + # * :ftp_pret_failed: The FTP server does not understand the PRET command at + # all or does not support the given argument. Be careful when + # using CURLOPT_CUSTOMREQUEST, a custom LIST command will be sent with PRET CMD + # before PASV as well. + # * :rtsp_cseq_error: Mismatch of RTSP CSeq numbers. + # * :rtsp_session_error: Mismatch of RTSP Session Identifiers. + # * :ftp_bad_file_list: Unable to parse FTP file list (during FTP wildcard downloading). + # * :chunk_failed: Chunk callback reported error. + # * :obsolete: These error codes will never be returned. They were used in an old + # libcurl version and are currently unused. + # + # @see http://curl.haxx.se/libcurl/c/libcurl-errors.html + attr_accessor :return_code + + # Initialize a new Easy. + # It initializes curl, if not already done and applies the provided options. + # Look into {Ethon::Easy::Options Options} to see what you can provide in the + # options hash. + # + # @example Create a new Easy. + # Easy.new(url: "www.google.de") + # + # @param [ Hash ] options The options to set. + # @option options :headers [ Hash ] Request headers. + # + # @return [ Easy ] A new Easy. + # + # @see Ethon::Easy::Options + # @see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html + def initialize(options = {}) + Curl.init + set_attributes(options) + set_callbacks + end + + # Set given options. + # + # @example Set options. + # easy.set_attributes(options) + # + # @param [ Hash ] options The options. + # + # @raise InvalidOption + # + # @see initialize + def set_attributes(options) + options.each_pair do |key, value| + method = "#{key}=" + unless respond_to?(method) + raise Errors::InvalidOption.new(key) + end + send(method, value) + end + end + + # Reset easy. This means resetting all options and instance variables. + # Also the easy handle is resetted. + # + # @example Reset. + # easy.reset + def reset + @url = nil + @escape = nil + @hash = nil + @on_complete = nil + @on_headers = nil + @on_body = nil + @on_progress = nil + @procs = nil + @mirror = nil + Curl.easy_reset(handle) + set_callbacks + end + + # Clones libcurl session handle. This means that all options that is set in + # the current handle will be set on duplicated handle. + def dup + e = super + e.handle = Curl.easy_duphandle(handle) + e.instance_variable_set(:@body_write_callback, nil) + e.instance_variable_set(:@header_write_callback, nil) + e.instance_variable_set(:@debug_callback, nil) + e.instance_variable_set(:@progress_callback, nil) + e.set_callbacks + e + end + # Url escapes the value. + # + # @example Url escape. + # easy.escape(value) + # + # @param [ String ] value The value to escape. + # + # @return [ String ] The escaped value. + # + # @api private + def escape(value) + string_pointer = Curl.easy_escape(handle, value, value.bytesize) + returned_string = string_pointer.read_string + Curl.free(string_pointer) + returned_string + end + + # Returns the informations available through libcurl as + # a hash. + # + # @return [ Hash ] The informations hash. + def to_hash + Kernel.warn("Ethon: Easy#to_hash is deprecated and will be removed, please use #mirror.") + mirror.to_hash + end + + def mirror + @mirror ||= Mirror.from_easy(self) + end + + # Return pretty log out. + # + # @example Return log out. + # easy.log_inspect + # + # @return [ String ] The log out. + def log_inspect + "EASY #{mirror.log_informations.map{|k, v| "#{k}=#{v}"}.flatten.join(' ')}" + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/callbacks.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/callbacks.rb new file mode 100644 index 00000000..73f2f210 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/callbacks.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains all the logic around the callbacks, + # which are needed to interact with libcurl. + # + # @api private + module Callbacks + + # :nodoc: + def self.included(base) + base.send(:attr_accessor, *[:response_body, :response_headers, :debug_info]) + end + + # Set writefunction and headerfunction callback. + # They are called by libcurl in order to provide the header and + # the body from the request. + # + # @example Set callbacks. + # easy.set_callbacks + def set_callbacks + Curl.set_option(:writefunction, body_write_callback, handle) + Curl.set_option(:headerfunction, header_write_callback, handle) + Curl.set_option(:debugfunction, debug_callback, handle) + @response_body = String.new + @response_headers = String.new + @headers_called = false + @debug_info = Ethon::Easy::DebugInfo.new + end + + # Returns the body write callback. + # + # @example Return the callback. + # easy.body_write_callback + # + # @return [ Proc ] The callback. + def body_write_callback + @body_write_callback ||= proc do |stream, size, num, object| + headers + result = body(chunk = stream.read_string(size * num)) + @response_body << chunk if result == :unyielded + result != :abort ? size * num : -1 + end + end + + # Returns the header write callback. + # + # @example Return the callback. + # easy.header_write_callback + # + # @return [ Proc ] The callback. + def header_write_callback + @header_write_callback ||= proc {|stream, size, num, object| + result = headers + @response_headers << stream.read_string(size * num) + result != :abort ? size * num : -1 + } + end + + # Returns the debug callback. This callback is currently used + # write the raw http request headers. + # + # @example Return the callback. + # easy.debug_callback + # + # @return [ Proc ] The callback. + def debug_callback + @debug_callback ||= proc {|handle, type, data, size, udata| + message = data.read_string(size) + @debug_info.add type, message + print message unless [:data_in, :data_out].include?(type) + 0 + } + end + + def set_progress_callback + if Curl.version_info[:version] >= "7.32.0" + Curl.set_option(:xferinfofunction, progress_callback, handle) + else + Curl.set_option(:progressfunction, progress_callback, handle) + end + end + + # Returns the progress callback. + # + # @example Return the callback. + # easy.progress_callback + # + # @return [ Proc ] The callback. + def progress_callback + @progress_callback ||= proc { |_, dltotal, dlnow, ultotal, ulnow| + progress(dltotal, dlnow, ultotal, ulnow) + 0 + } + end + + # Set the read callback. This callback is used by libcurl to + # read data when performing a PUT request. + # + # @example Set the callback. + # easy.set_read_callback("a=1") + # + # @param [ String ] body The body. + def set_read_callback(body) + @request_body_read = 0 + readfunction do |stream, size, num, object| + size = size * num + body_size = if body.respond_to?(:bytesize) + body.bytesize + elsif body.respond_to?(:size) + body.size + elsif body.is_a?(File) + File.size(body.path) + end + + left = body_size - @request_body_read + size = left if size > left + + if size > 0 + chunk = if body.respond_to?(:byteslice) + body.byteslice(@request_body_read, size) + elsif body.respond_to?(:read) + body.read(size) + else + body[@request_body_read, size] + end + + stream.write_string( + chunk, size + ) + @request_body_read += size + end + size + end + end + + # Returns the body read callback. + # + # @example Return the callback. + # easy.read_callback + # + # @return [ Proc ] The callback. + def read_callback + @read_callback + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/debug_info.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/debug_info.rb new file mode 100644 index 00000000..d8f15edb --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/debug_info.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This class is used to store and retreive debug information, + # which is only saved when verbose is set to true. + # + # @api private + class DebugInfo + + MESSAGE_TYPES = Ethon::Curl::DebugInfoType.to_h.keys + + class Message + attr_reader :type, :message + + def initialize(type, message) + @type = type + @message = message + end + end + + def initialize + @messages = [] + end + + def add(type, message) + @messages << Message.new(type, message) + end + + def messages_for(type) + @messages.select {|m| m.type == type }.map(&:message) + end + + MESSAGE_TYPES.each do |type| + eval %Q|def #{type}; messages_for(:#{type}); end| + end + + def to_a + @messages.map(&:message) + end + + def to_h + Hash[MESSAGE_TYPES.map {|k| [k, send(k)] }] + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/features.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/features.rb new file mode 100644 index 00000000..c4a8962e --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/features.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains class methods for feature checks + module Features + # Returns true if this curl version supports zlib. + # + # @example Return wether zlib is supported. + # Ethon::Easy.supports_zlib? + # + # @return [ Boolean ] True if supported, else false. + def supports_zlib? + !!(Curl.version_info[:features] & Curl::VERSION_LIBZ) + end + + # Returns true if this curl version supports AsynchDNS. + # + # @example + # Ethon::Easy.supports_asynch_dns? + # + # @return [ Boolean ] True if supported, else false. + def supports_asynch_dns? + !!(Curl.version_info[:features] & Curl::VERSION_ASYNCHDNS) + end + + alias :supports_timeout_ms? :supports_asynch_dns? + + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/form.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/form.rb new file mode 100644 index 00000000..681d0f9d --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/form.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true +require 'ethon/easy/util' +require 'ethon/easy/queryable' + +module Ethon + class Easy + + # This class represents a form and is used to send a payload in the + # request body via POST/PUT. + # It handles multipart forms, too. + # + # @api private + class Form + include Ethon::Easy::Util + include Ethon::Easy::Queryable + + # Return a new Form. + # + # @example Return a new Form. + # Form.new({}) + # + # @param [ Hash ] params The parameter with which to initialize the form. + # + # @return [ Form ] A new Form. + def initialize(easy, params, multipart = nil) + @easy = easy + @params = params || {} + @multipart = multipart + end + + # Return a pointer to the first form element in libcurl. + # + # @example Return the first form element. + # form.first + # + # @return [ FFI::Pointer ] The first element. + def first + @first ||= FFI::MemoryPointer.new(:pointer) + end + + # Return a pointer to the last form element in libcurl. + # + # @example Return the last form element. + # form.last + # + # @return [ FFI::Pointer ] The last element. + def last + @last ||= FFI::MemoryPointer.new(:pointer) + end + + # Return if form is multipart. The form is multipart + # when it contains a file or multipart option is set on the form during creation. + # + # @example Return if form is multipart. + # form.multipart? + # + # @return [ Boolean ] True if form is multipart, else false. + def multipart? + return true if @multipart + query_pairs.any?{|pair| pair.respond_to?(:last) && pair.last.is_a?(Array)} + end + + # Add form elements to libcurl. + # + # @example Add form to libcurl. + # form.materialize + def materialize + query_pairs.each { |pair| form_add(pair.first.to_s, pair.last) } + end + + private + + def form_add(name, content) + case content + when Array + Curl.formadd(first, last, + :form_option, :copyname, :pointer, name, + :form_option, :namelength, :long, name.bytesize, + :form_option, :file, :string, content[2], + :form_option, :filename, :string, content[0], + :form_option, :contenttype, :string, content[1], + :form_option, :end + ) + else + Curl.formadd(first, last, + :form_option, :copyname, :pointer, name, + :form_option, :namelength, :long, name.bytesize, + :form_option, :copycontents, :pointer, content.to_s, + :form_option, :contentslength, :long, content ? content.to_s.bytesize : 0, + :form_option, :end + ) + end + + setup_garbage_collection + end + + def setup_garbage_collection + # first is a pointer to a pointer. Since it's a MemoryPointer it will + # auto clean itself up, but we need to clean up the object it points + # to. So this results in (pseudo-c): + # form_data_cleanup_handler = *first + # curl_form_free(form_data_cleanup_handler) + @form_data_cleanup_handler ||= FFI::AutoPointer.new(@first.get_pointer(0), Curl.method(:formfree)) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/header.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/header.rb new file mode 100644 index 00000000..8984a249 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/header.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true +module Ethon + class Easy + # This module contains the logic around adding headers to libcurl. + # + # @api private + module Header + # Return headers, return empty hash if none. + # + # @example Return the headers. + # easy.headers + # + # @return [ Hash ] The headers. + def headers + @headers ||= {} + end + + # Set the headers. + # + # @example Set the headers. + # easy.headers = {'User-Agent' => 'ethon'} + # + # @param [ Hash ] headers The headers. + def headers=(headers) + headers ||= {} + header_list = nil + headers.each do |k, v| + header_list = Curl.slist_append(header_list, compose_header(k,v)) + end + Curl.set_option(:httpheader, header_list, handle) + + @header_list = header_list && FFI::AutoPointer.new(header_list, Curl.method(:slist_free_all)) + end + + # Return header_list. + # + # @example Return header_list. + # easy.header_list + # + # @return [ FFI::Pointer ] The header list. + def header_list + @header_list + end + + # Compose libcurl header string from key and value. + # Also replaces null bytes, because libcurl will complain + # otherwise. + # + # @example Compose header. + # easy.compose_header('User-Agent', 'Ethon') + # + # @param [ String ] key The header name. + # @param [ String ] value The header value. + # + # @return [ String ] The composed header. + def compose_header(key, value) + Util.escape_zero_byte("#{key}: #{value}") + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http.rb new file mode 100644 index 00000000..43598305 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true +require 'ethon/easy/http/actionable' +require 'ethon/easy/http/post' +require 'ethon/easy/http/get' +require 'ethon/easy/http/head' +require 'ethon/easy/http/put' +require 'ethon/easy/http/delete' +require 'ethon/easy/http/patch' +require 'ethon/easy/http/options' +require 'ethon/easy/http/custom' + +module Ethon + class Easy + + # This module contains logic about making valid HTTP requests. + module Http + + # Set specified options in order to make a HTTP request. + # Look at {Ethon::Easy::Options Options} to see what you can + # provide in the options hash. + # + # @example Set options for HTTP request. + # easy.http_request("www.google.com", :get, {}) + # + # @param [ String ] url The url. + # @param [ String ] action_name The HTTP action name. + # @param [ Hash ] options The options hash. + # + # @option options :params [ Hash ] Params hash which + # is attached to the url. + # @option options :body [ Hash ] Body hash which + # becomes the request body. It is a PUT body for + # PUT requests and a POST for everything else. + # @option options :headers [ Hash ] Request headers. + # + # @return [ void ] + # + # @see Ethon::Easy::Options + def http_request(url, action_name, options = {}) + fabricate(url, action_name, options).setup(self) + end + + private + + # Return the corresponding action class. + # + # @example Return the action. + # Action.fabricate(:get) + # Action.fabricate(:smash) + # + # @param [ String ] url The url. + # @param [ String ] action_name The HTTP action name. + # @param [ Hash ] options The option hash. + # + # @return [ Easy::Ethon::Actionable ] The request instance. + def fabricate(url, action_name, options) + constant_name = action_name.to_s.capitalize + + if Ethon::Easy::Http.const_defined?(constant_name) + Ethon::Easy::Http.const_get(constant_name).new(url, options) + else + Ethon::Easy::Http::Custom.new(constant_name.upcase, url, options) + end + end + + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/actionable.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/actionable.rb new file mode 100644 index 00000000..374a21ce --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/actionable.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true +require 'ethon/easy/http/putable' +require 'ethon/easy/http/postable' + +module Ethon + class Easy + module Http + # This module represents a Http Action and is a factory + # for more real actions like GET, HEAD, POST and PUT. + module Actionable + + QUERY_OPTIONS = [ :params, :body, :params_encoding ] + + # Create a new action. + # + # @example Create a new action. + # Action.new("www.example.com", {}) + # + # @param [ String ] url The url. + # @param [ Hash ] options The options. + # + # @return [ Action ] A new action. + def initialize(url, options) + @url = url + @options, @query_options = parse_options(options) + end + + # Return the url. + # + # @example Return url. + # action.url + # + # @return [ String ] The url. + def url + @url + end + + # Return the options hash. + # + # @example Return options. + # action.options + # + # @return [ Hash ] The options. + def options + @options + end + + # Returns the query options hash. + # + # @example Return query options. + # action.query_options + # + # @return [ Hash ] The query options. + def query_options + @query_options + end + + # Return the params. + # + # @example Return params. + # action.params + # + # @return [ Params ] The params. + def params + @params ||= Params.new(@easy, query_options.fetch(:params, nil)) + end + + # Return the form. + # + # @example Return form. + # action.form + # + # @return [ Form ] The form. + def form + @form ||= Form.new(@easy, query_options.fetch(:body, nil), options.fetch(:multipart, nil)) + end + + # Get the requested array encoding. By default it's + # :typhoeus, but it can also be set to :rack. + # + # @example Get encoding from options + # action.params_encoding + # + def params_encoding + @params_encoding ||= query_options.fetch(:params_encoding, :typhoeus) + end + + # Setup everything necessary for a proper request. + # + # @example setup. + # action.setup(easy) + # + # @param [ easy ] easy the easy to setup. + def setup(easy) + @easy = easy + + # Order is important, @easy will be used to provide access to options + # relevant to the following operations (like whether or not to escape + # values). + easy.set_attributes(options) + + set_form(easy) unless form.empty? + + if params.empty? + easy.url = url + else + set_params(easy) + end + end + + # Setup request with params. + # + # @example Setup nothing. + # action.set_params(easy) + # + # @param [ Easy ] easy The easy to setup. + def set_params(easy) + params.escape = easy.escape? + params.params_encoding = params_encoding + + base_url, base_params = url.split('?') + base_url << '?' + base_url << base_params.to_s + base_url << '&' if base_params + base_url << params.to_s + + easy.url = base_url + end + + # Setup request with form. + # + # @example Setup nothing. + # action.set_form(easy) + # + # @param [ Easy ] easy The easy to setup. + def set_form(easy) + end + + private + + def parse_options(options) + query_options = {} + options = options.dup + + QUERY_OPTIONS.each do |query_option| + if options.key?(query_option) + query_options[query_option] = options.delete(query_option) + end + end + + return options, query_options + end + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/custom.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/custom.rb new file mode 100644 index 00000000..a00f3e34 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/custom.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making requests for custom HTTP verbs. + class Custom + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + def initialize(verb, url, options) + @verb = verb + super(url, options) + end + + # Setup easy to make a request. + # + # @example Setup. + # custom.set_params(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.customrequest = @verb + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/delete.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/delete.rb new file mode 100644 index 00000000..9cc22263 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/delete.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making DELETE requests. + class Delete + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a DELETE request. + # + # @example Setup customrequest. + # delete.setup(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.customrequest = "DELETE" + end + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/get.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/get.rb new file mode 100644 index 00000000..6175e429 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/get.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making GET requests. + class Get + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a GET request. + # + # @example Setup. + # get.set_params(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.customrequest = "GET" unless form.empty? + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/head.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/head.rb new file mode 100644 index 00000000..d9bdbd28 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/head.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making HEAD requests. + class Head + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a HEAD request. + # + # @example Setup. + # get.set_params(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.nobody = true + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/options.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/options.rb new file mode 100644 index 00000000..6e12c29c --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/options.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making OPTIONS requests. + class Options + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a OPTIONS request. + # + # @example Setup. + # options.setup(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.customrequest = "OPTIONS" + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/patch.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/patch.rb new file mode 100644 index 00000000..e6163830 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/patch.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making PATCH requests. + class Patch + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a PATCH request. + # + # @example Setup. + # patch.setup(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + easy.customrequest = "PATCH" + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/post.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/post.rb new file mode 100644 index 00000000..f773f790 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/post.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + # This class knows everything about making POST requests. + class Post + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Postable + + # Setup easy to make a POST request. + # + # @example Setup. + # post.setup(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + if form.empty? + easy.postfieldsize = 0 + easy.copypostfields = "" + end + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/postable.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/postable.rb new file mode 100644 index 00000000..bd42f63f --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/postable.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This module contains logic for setting up a [multipart] POST body. + module Postable + + # Set things up when form is provided. + # Deals with multipart forms. + # + # @example Setup. + # post.set_form(easy) + # + # @param [ Easy ] easy The easy to setup. + def set_form(easy) + easy.url ||= url + form.params_encoding = params_encoding + if form.multipart? + form.escape = false + form.materialize + easy.httppost = form.first.read_pointer + else + form.escape = easy.escape? + easy.postfieldsize = form.to_s.bytesize + easy.copypostfields = form.to_s + end + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/put.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/put.rb new file mode 100644 index 00000000..202cbeed --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/put.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This class knows everything about making PUT requests. + class Put + include Ethon::Easy::Http::Actionable + include Ethon::Easy::Http::Putable + + # Setup easy to make a PUT request. + # + # @example Setup. + # put.setup(easy) + # + # @param [ Easy ] easy The easy to setup. + def setup(easy) + super + if form.empty? + easy.upload = true + easy.infilesize = 0 + end + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/http/putable.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/putable.rb new file mode 100644 index 00000000..a639f06d --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/http/putable.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +module Ethon + class Easy + module Http + + # This module contains logic about setting up a PUT body. + module Putable + # Set things up when form is provided. + # Deals with multipart forms. + # + # @example Setup. + # put.set_form(easy) + # + # @param [ Easy ] easy The easy to setup. + def set_form(easy) + easy.upload = true + form.escape = true + form.params_encoding = params_encoding + easy.infilesize = form.to_s.bytesize + easy.set_read_callback(form.to_s) + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/informations.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/informations.rb new file mode 100644 index 00000000..cac62a36 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/informations.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains the methods to return informations + # from the easy handle. See http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html + # for more information. + module Informations + + # Holds available informations and their type, which is needed to + # request the informations from libcurl. + AVAILABLE_INFORMATIONS = { + # Return the available HTTP auth methods. + :httpauth_avail => :long, + + # Return the total time in seconds for the previous + # transfer, including name resolution, TCP connection, etc. + :total_time => :double, + + # Return the time, in seconds, it took from the start + # until the first byte was received by libcurl. This + # includes pre-transfer time and also the time the + # server needs to calculate the result. + :starttransfer_time => :double, + + # Return the time, in seconds, it took from the start + # until the SSL/SSH connect/handshake to the remote + # host was completed. This time is most often very near + # to the pre-transfer time, except for cases such as HTTP + # pipelining where the pre-transfer time can be delayed + # due to waits in line for the pipeline and more. + :appconnect_time => :double, + + # Return the time, in seconds, it took from the start + # until the file transfer was just about to begin. This + # includes all pre-transfer commands and negotiations + # that are specific to the particular protocol(s) involved. + # It does not involve the sending of the protocol- + # specific request that triggers a transfer. + :pretransfer_time => :double, + + # Return the time, in seconds, it took from the start + # until the connect to the remote host (or proxy) was completed. + :connect_time => :double, + + # Return the time, in seconds, it took from the + # start until the name resolution was completed. + :namelookup_time => :double, + + # Return the time, in seconds, it took for all redirection steps + # include name lookup, connect, pretransfer and transfer before the + # final transaction was started. time_redirect shows the complete + # execution time for multiple redirections. (Added in 7.12.3) + :redirect_time => :double, + + # Return the last used effective url. + :effective_url => :string, + + # Return the string holding the IP address of the most recent + # connection done with this curl handle. This string + # may be IPv6 if that's enabled. + :primary_ip => :string, + + # Return the last received HTTP, FTP or SMTP response code. + # The value will be zero if no server response code has + # been received. Note that a proxy's CONNECT response should + # be read with http_connect_code and not this. + :response_code => :long, + + :request_size => :long, + + # Return the total number of redirections that were + # actually followed. + :redirect_count => :long, + + # URL a redirect would take you to, had you enabled redirects (Added in 7.18.2) + :redirect_url => :string, + + # Return the bytes, the total amount of bytes that were uploaded + :size_upload => :double, + + # Return the bytes, the total amount of bytes that were downloaded. + # The amount is only for the latest transfer and will be reset again + # for each new transfer. This counts actual payload data, what's + # also commonly called body. All meta and header data are excluded + # and will not be counted in this number. + :size_download => :double, + + # Return the bytes/second, the average upload speed that curl + # measured for the complete upload + :speed_upload => :double, + + # Return the bytes/second, the average download speed that curl + # measured for the complete download + :speed_download => :double + } + + AVAILABLE_INFORMATIONS.each do |name, type| + eval %Q|def #{name}; Curl.send(:get_info_#{type}, :#{name}, handle); end| + end + + # Returns true if this curl version supports zlib. + # + # @example Return wether zlib is supported. + # easy.supports_zlib? + # + # @return [ Boolean ] True if supported, else false. + # @deprecated Please use the static version instead + def supports_zlib? + Kernel.warn("Ethon: Easy#supports_zlib? is deprecated and will be removed, please use Easy#.") + Easy.supports_zlib? + end + + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/mirror.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/mirror.rb new file mode 100644 index 00000000..f485c9f7 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/mirror.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +module Ethon + class Easy + class Mirror + attr_reader :options + alias_method :to_hash, :options + + INFORMATIONS_TO_MIRROR = Informations::AVAILABLE_INFORMATIONS.keys + + [:return_code, :response_headers, :response_body, :debug_info] + + INFORMATIONS_TO_LOG = [:effective_url, :response_code, :return_code, :total_time] + + def self.from_easy(easy) + options = {} + INFORMATIONS_TO_MIRROR.each do |info| + options[info] = easy.send(info) + end + new(options) + end + + def initialize(options = {}) + @options = options + end + + def log_informations + Hash[*INFORMATIONS_TO_LOG.map do |info| + [info, options[info]] + end.flatten] + end + + INFORMATIONS_TO_MIRROR.each do |info| + eval %Q|def #{info}; options[#{info}]; end| + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/operations.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/operations.rb new file mode 100644 index 00000000..ad5397d8 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/operations.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +module Ethon + class Easy + # This module contains the logic to prepare and perform + # an easy. + module Operations + # Returns a pointer to the curl easy handle. + # + # @example Return the handle. + # easy.handle + # + # @return [ FFI::Pointer ] A pointer to the curl easy handle. + def handle + @handle ||= FFI::AutoPointer.new(Curl.easy_init, Curl.method(:easy_cleanup)) + end + + # Sets a pointer to the curl easy handle. + # @param [ ::FFI::Pointer ] Easy handle that will be assigned. + def handle=(h) + @handle = h + end + + # Perform the easy request. + # + # @example Perform the request. + # easy.perform + # + # @return [ Integer ] The return code. + def perform + @return_code = Curl.easy_perform(handle) + if Ethon.logger.debug? + Ethon.logger.debug { "ETHON: performed #{log_inspect}" } + end + complete + @return_code + end + + # Clean up the easy. + # + # @example Perform clean up. + # easy.cleanup + # + # @return the result of the free which is nil + def cleanup + handle.free + end + + # Prepare the easy. Options, headers and callbacks + # were set. + # + # @example Prepare easy. + # easy.prepare + # + # @deprecated It is no longer necessary to call prepare. + def prepare + Ethon.logger.warn( + "ETHON: It is no longer necessary to call "+ + "Easy#prepare. It's going to be removed "+ + "in future versions." + ) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/options.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/options.rb new file mode 100644 index 00000000..30c4df6a --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/options.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains the logic and knowledge about the + # available options on easy. + module Options + attr_reader :url + + def url=(value) + @url = value + Curl.set_option(:url, value, handle) + end + + def escape=( b ) + @escape = b + end + + def escape? + return true if !defined?(@escape) || @escape.nil? + @escape + end + + def multipart=(b) + @multipart = b + end + + def multipart? + !!@multipart + end + + Curl.easy_options(nil).each do |opt, props| + method_name = "#{opt}=".freeze + unless method_defined? method_name + define_method(method_name) do |value| + Curl.set_option(opt, value, handle) + value + end + end + next if props[:type] != :callback || method_defined?(opt) + define_method(opt) do |&block| + @procs ||= {} + @procs[opt.to_sym] = block + Curl.set_option(opt, block, handle) + nil + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/params.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/params.rb new file mode 100644 index 00000000..41dad8b4 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/params.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +require 'ethon/easy/util' +require 'ethon/easy/queryable' + +module Ethon + class Easy + + # This class represents HTTP request parameters. + # + # @api private + class Params + include Ethon::Easy::Util + include Ethon::Easy::Queryable + + # Create a new Params. + # + # @example Create a new Params. + # Params.new({}) + # + # @param [ Hash ] params The params to use. + # + # @return [ Params ] A new Params. + def initialize(easy, params) + @easy = easy + @params = params || {} + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/queryable.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/queryable.rb new file mode 100644 index 00000000..47f79014 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/queryable.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains logic about building + # query parameters for url or form. + module Queryable + + # :nodoc: + def self.included(base) + base.send(:attr_accessor, :escape) + base.send(:attr_accessor, :params_encoding) + end + + # Return wether there are elements in params or not. + # + # @example Return if params is empty. + # form.empty? + # + # @return [ Boolean ] True if params is empty, else false. + def empty? + @params.empty? + end + + # Return the string representation of params. + # + # @example Return string representation. + # params.to_s + # + # @return [ String ] The string representation. + def to_s + @to_s ||= query_pairs.map{ |pair| + return pair if pair.is_a?(String) + + if escape && @easy + pair.map{ |e| @easy.escape(e.to_s) }.join("=") + else + pair.join("=") + end + }.join('&') + end + + # Return the query pairs. + # + # @example Return the query pairs. + # params.query_pairs + # + # @return [ Array ] The query pairs. + def query_pairs + @query_pairs ||= build_query_pairs(@params) + end + + # Return query pairs build from a hash. + # + # @example Build query pairs. + # action.build_query_pairs({a: 1, b: 2}) + # #=> [[:a, 1], [:b, 2]] + # + # @param [ Hash ] hash The hash to go through. + # + # @return [ Array ] The array of query pairs. + def build_query_pairs(hash) + return [hash] if hash.is_a?(String) + + pairs = [] + recursively_generate_pairs(hash, nil, pairs) + pairs + end + + # Return file info for a file. + # + # @example Return file info. + # action.file_info(File.open('fubar', 'r')) + # + # @param [ File ] file The file to handle. + # + # @return [ Array ] Array of informations. + def file_info(file) + filename = File.basename(file.path) + [ + filename, + mime_type(filename), + File.expand_path(file.path) + ] + end + + private + + def mime_type(filename) + if defined?(MIME) && t = MIME::Types.type_for(filename).first + t.to_s + else + 'application/octet-stream' + end + end + + def recursively_generate_pairs(h, prefix, pairs) + case h + when Hash + encode_hash_pairs(h, prefix, pairs) + when Array + if params_encoding == :rack + encode_rack_array_pairs(h, prefix, pairs) + elsif params_encoding == :multi + encode_multi_array_pairs(h, prefix, pairs) + elsif params_encoding == :none + pairs << [prefix, h] + else + encode_indexed_array_pairs(h, prefix, pairs) + end + end + end + + def encode_hash_pairs(h, prefix, pairs) + h.each_pair do |k,v| + key = prefix.nil? ? k : "#{prefix}[#{k}]" + pairs_for(v, key, pairs) + end + end + + def encode_indexed_array_pairs(h, prefix, pairs) + h.each_with_index do |v, i| + key = "#{prefix}[#{i}]" + pairs_for(v, key, pairs) + end + end + + def encode_rack_array_pairs(h, prefix, pairs) + h.each do |v| + key = "#{prefix}[]" + pairs_for(v, key, pairs) + end + end + + def encode_multi_array_pairs(h, prefix, pairs) + h.each_with_index do |v, i| + key = prefix + pairs_for(v, key, pairs) + end + end + + def pairs_for(v, key, pairs) + case v + when Hash, Array + recursively_generate_pairs(v, key, pairs) + when File, Tempfile + pairs << [key, file_info(v)] + else + pairs << [key, v] + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/response_callbacks.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/response_callbacks.rb new file mode 100644 index 00000000..c5dd1a79 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/response_callbacks.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true +module Ethon + class Easy + + # This module contains the logic for the response callbacks. + # The on_complete callback is the only one at the moment. + # + # You can set multiple callbacks, which are then executed + # in the same order. + # + # easy.on_complete { p 1 } + # easy.on_complete { p 2 } + # easy.complete + # #=> 1 + # #=> 2 + # + # You can clear the callbacks: + # + # easy.on_complete { p 1 } + # easy.on_complete { p 2 } + # easy.on_complete.clear + # easy.on_complete + # #=> [] + module ResponseCallbacks + + # Set on_headers callback. + # + # @example Set on_headers. + # request.on_headers { p "yay" } + # + # @param [ Block ] block The block to execute. + def on_headers(&block) + @on_headers ||= [] + @on_headers << block if block_given? + @on_headers + end + + # Execute on_headers callbacks. + # + # @example Execute on_headers. + # request.headers + def headers + return if @headers_called + @headers_called = true + if defined?(@on_headers) and not @on_headers.nil? + result = nil + @on_headers.each do |callback| + result = callback.call(self) + break if result == :abort + end + result + end + end + + # Set on_complete callback. + # + # @example Set on_complete. + # request.on_complete { p "yay" } + # + # @param [ Block ] block The block to execute. + def on_complete(&block) + @on_complete ||= [] + @on_complete << block if block_given? + @on_complete + end + + # Execute on_complete callbacks. + # + # @example Execute on_completes. + # request.complete + def complete + headers unless @response_headers.empty? + if defined?(@on_complete) and not @on_complete.nil? + @on_complete.each{ |callback| callback.call(self) } + end + end + + # Set on_progress callback. + # + # @example Set on_progress. + # request.on_progress {|dltotal, dlnow, ultotal, ulnow| p "#{dltotal} #{dlnow} #{ultotal} #{ulnow}" } + # + # @param [ Block ] block The block to execute. + def on_progress(&block) + @on_progress ||= [] + if block_given? + @on_progress << block + set_progress_callback + self.noprogress = 0 + end + @on_progress + end + + # Execute on_progress callbacks. + # + # @example Execute on_progress. + # request.body(1, 1, 1, 1) + def progress(dltotal, dlnow, ultotal, ulnow) + if defined?(@on_progress) and not @on_progress.nil? + @on_progress.each{ |callback| callback.call(dltotal, dlnow, ultotal, ulnow) } + end + end + + # Set on_body callback. + # + # @example Set on_body. + # request.on_body { |chunk| p "yay" } + # + # @param [ Block ] block The block to execute. + def on_body(&block) + @on_body ||= [] + @on_body << block if block_given? + @on_body + end + + # Execute on_body callbacks. + # + # @example Execute on_body. + # request.body("This data came from HTTP.") + # + # @return [ Object ] If there are no on_body callbacks, returns the symbol :unyielded. + def body(chunk) + if defined?(@on_body) and not @on_body.nil? + result = nil + @on_body.each do |callback| + result = callback.call(chunk, self) + break if result == :abort + end + result + else + :unyielded + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/easy/util.rb b/bin/gems/ethon-0.16.0/lib/ethon/easy/util.rb new file mode 100644 index 00000000..7649782e --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/easy/util.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +module Ethon + class Easy # :nodoc: + + # This module contains small helpers. + # + # @api private + module Util + + # Escapes zero bytes in strings. + # + # @example Escape zero bytes. + # Util.escape_zero_byte("1\0") + # #=> "1\\0" + # + # @param [ Object ] value The value to escape. + # + # @return [ String, Object ] Escaped String if + # zero byte found, original object if not. + def escape_zero_byte(value) + return value unless value.to_s.include?(0.chr) + value.to_s.gsub(0.chr, '\\\0') + end + + extend self + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors.rb new file mode 100644 index 00000000..17eecadf --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +require 'ethon/errors/ethon_error' +require 'ethon/errors/global_init' +require 'ethon/errors/multi_timeout' +require 'ethon/errors/multi_fdset' +require 'ethon/errors/multi_add' +require 'ethon/errors/multi_remove' +require 'ethon/errors/select' +require 'ethon/errors/invalid_option' +require 'ethon/errors/invalid_value' + +module Ethon + + # This namespace contains all errors raised by ethon. + module Errors + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/ethon_error.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/ethon_error.rb new file mode 100644 index 00000000..84dbf6c5 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/ethon_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Default Ethon error class for all custom errors. + class EthonError < StandardError + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/global_init.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/global_init.rb new file mode 100644 index 00000000..816b7749 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/global_init.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when global_init failed. + class GlobalInit < EthonError + def initialize + super("An error occured initializing curl.") + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_option.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_option.rb new file mode 100644 index 00000000..4e558f5c --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_option.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when option is invalid. + class InvalidOption < EthonError + def initialize(option) + super("The option: #{option} is invalid.") + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_value.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_value.rb new file mode 100644 index 00000000..aedb1096 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/invalid_value.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when option is invalid. + class InvalidValue < EthonError + def initialize(option, value) + super("The value: #{value} is invalid for option: #{option}.") + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_add.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_add.rb new file mode 100644 index 00000000..a569a31a --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_add.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when multi_add_handle failed. + class MultiAdd < EthonError + def initialize(code, easy) + super("An error occured adding the easy handle: #{easy} to the multi: #{code}") + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_fdset.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_fdset.rb new file mode 100644 index 00000000..e84be729 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_fdset.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when multi_fdset failed. + class MultiFdset < EthonError + def initialize(code) + super("An error occured getting the fdset: #{code}") + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_remove.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_remove.rb new file mode 100644 index 00000000..36074b3c --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_remove.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raises when multi_remove_handle failed. + class MultiRemove < EthonError + def initialize(code, easy) + super("An error occured removing the easy handle: #{easy} from the multi: #{code}") + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_timeout.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_timeout.rb new file mode 100644 index 00000000..79be3a7f --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/multi_timeout.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raised when multi_timeout failed. + class MultiTimeout < EthonError + def initialize(code) + super("An error occured getting the timeout: #{code}") + # "An error occured getting the timeout: #{code}: #{Curl.multi_strerror(code)}" + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/errors/select.rb b/bin/gems/ethon-0.16.0/lib/ethon/errors/select.rb new file mode 100644 index 00000000..464a43b7 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/errors/select.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Ethon + module Errors + + # Raised when select failed. + class Select < EthonError + def initialize(errno) + super("An error occured on select: #{errno}") + end + end + end +end + diff --git a/bin/gems/ethon-0.16.0/lib/ethon/libc.rb b/bin/gems/ethon-0.16.0/lib/ethon/libc.rb new file mode 100644 index 00000000..1fddb8ac --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/libc.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +module Ethon + + # FFI Wrapper module for Libc. + # + # @api private + module Libc + extend FFI::Library + ffi_lib 'c' + + # :nodoc: + def self.windows? + Gem.win_platform? + end + + unless windows? + attach_function :getdtablesize, [], :int + attach_function :free, [:pointer], :void + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/loggable.rb b/bin/gems/ethon-0.16.0/lib/ethon/loggable.rb new file mode 100644 index 00000000..02b74781 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/loggable.rb @@ -0,0 +1,59 @@ +# encoding: utf-8 +# frozen_string_literal: true +module Ethon + + # Contains logging behaviour. + module Loggable + + # Get the logger. + # + # @note Will try to grab Rails' logger first before creating a new logger + # with stdout. + # + # @example Get the logger. + # Loggable.logger + # + # @return [ Logger ] The logger. + def logger + return @logger if defined?(@logger) + @logger = rails_logger || default_logger + end + + # Set the logger. + # + # @example Set the logger. + # Loggable.logger = Logger.new($stdout) + # + # @param [ Logger ] logger The logger to set. + # + # @return [ Logger ] The new logger. + def logger=(logger) + @logger = logger + end + + private + + # Gets the default Ethon logger - stdout. + # + # @example Get the default logger. + # Loggable.default_logger + # + # @return [ Logger ] The default logger. + def default_logger + logger = Logger.new($stdout) + logger.level = Logger::INFO + logger + end + + # Get the Rails logger if it's defined. + # + # @example Get Rails' logger. + # Loggable.rails_logger + # + # @return [ Logger ] The Rails logger. + def rails_logger + defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger + end + end + extend Loggable +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/multi.rb b/bin/gems/ethon-0.16.0/lib/ethon/multi.rb new file mode 100644 index 00000000..0919583b --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/multi.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true +require 'ethon/easy/util' +require 'ethon/multi/stack' +require 'ethon/multi/operations' +require 'ethon/multi/options' + +module Ethon + + # This class represents libcurl multi. + class Multi + include Ethon::Multi::Stack + include Ethon::Multi::Operations + include Ethon::Multi::Options + + # Create a new multi. Initialize curl in case + # it didn't happen before. + # + # @example Create a new Multi. + # Multi.new + # + # @param [ Hash ] options The options. + # + # @option options :socketdata [String] + # Pass a pointer to whatever you want passed to the + # curl_socket_callback's forth argument, the userp pointer. This is not + # used by libcurl but only passed-thru as-is. Set the callback pointer + # with CURLMOPT_SOCKETFUNCTION. + # @option options :pipelining [Boolean] + # Pass a long set to 1 to enable or 0 to disable. Enabling pipelining + # on a multi handle will make it attempt to perform HTTP Pipelining as + # far as possible for transfers using this handle. This means that if + # you add a second request that can use an already existing connection, + # the second request will be "piped" on the same connection rather than + # being executed in parallel. (Added in 7.16.0) + # @option options :timerfunction [Proc] + # Pass a pointer to a function matching the curl_multi_timer_callback + # prototype. This function will then be called when the timeout value + # changes. The timeout value is at what latest time the application + # should call one of the "performing" functions of the multi interface + # (curl_multi_socket_action(3) and curl_multi_perform(3)) - to allow + # libcurl to keep timeouts and retries etc to work. A timeout value of + # -1 means that there is no timeout at all, and 0 means that the + # timeout is already reached. Libcurl attempts to limit calling this + # only when the fixed future timeout time actually changes. See also + # CURLMOPT_TIMERDATA. This callback can be used instead of, or in + # addition to, curl_multi_timeout(3). (Added in 7.16.0) + # @option options :timerdata [String] + # Pass a pointer to whatever you want passed to the + # curl_multi_timer_callback's third argument, the userp pointer. This + # is not used by libcurl but only passed-thru as-is. Set the callback + # pointer with CURLMOPT_TIMERFUNCTION. (Added in 7.16.0) + # @option options :maxconnects [Integer] + # Pass a long. The set number will be used as the maximum amount of + # simultaneously open connections that libcurl may cache. Default is + # 10, and libcurl will enlarge the size for each added easy handle to + # make it fit 4 times the number of added easy handles. + # By setting this option, you can prevent the cache size from growing + # beyond the limit set by you. + # When the cache is full, curl closes the oldest one in the cache to + # prevent the number of open connections from increasing. + # This option is for the multi handle's use only, when using the easy + # interface you should instead use the CURLOPT_MAXCONNECTS option. + # (Added in 7.16.3) + # @option options :max_total_connections [Integer] + # Pass a long. The set number will be used as the maximum amount of + # simultaneously open connections in total. For each new session, + # libcurl will open a new connection up to the limit set by + # CURLMOPT_MAX_TOTAL_CONNECTIONS. When the limit is reached, the + # sessions will be pending until there are available connections. + # If CURLMOPT_PIPELINING is 1, libcurl will try to pipeline if the host + # is capable of it. + # The default value is 0, which means that there is no limit. However, + # for backwards compatibility, setting it to 0 when CURLMOPT_PIPELINING + # is 1 will not be treated as unlimited. Instead it will open only 1 + # connection and try to pipeline on it. + # (Added in 7.30.0) + # @option options :execution_mode [Boolean] + # Either :perform (default) or :socket_action, specifies the usage + # method that will be used on this multi object. The default :perform + # mode provides a #perform function that uses curl_multi_perform + # behind the scenes to automatically continue execution until all + # requests have completed. The :socket_action mode provides an API + # that allows the {Multi} object to be integrated into an external + # IO loop, by calling #socket_action and responding to the + # socketfunction and timerfunction callbacks, using the underlying + # curl_multi_socket_action semantics. + # + # @return [ Multi ] The new multi. + def initialize(options = {}) + Curl.init + @execution_mode = options.delete(:execution_mode) || :perform + set_attributes(options) + init_vars + end + + # Set given options. + # + # @example Set options. + # multi.set_attributes(options) + # + # @raise InvalidOption + # + # @see initialize + # + # @api private + def set_attributes(options) + options.each_pair do |key, value| + unless respond_to?("#{key}=") + raise Errors::InvalidOption.new(key) + end + method("#{key}=").call(value) + end + end + + private + + # Internal function to gate functions to a specific execution mode + # + # @raise ArgumentError + # + # @api private + def ensure_execution_mode(expected_mode) + raise ArgumentError, "Expected the Multi to be in #{expected_mode} but it was in #{@execution_mode}" if expected_mode != @execution_mode + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/multi/operations.rb b/bin/gems/ethon-0.16.0/lib/ethon/multi/operations.rb new file mode 100644 index 00000000..b5c27969 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/multi/operations.rb @@ -0,0 +1,228 @@ +# frozen_string_literal: true +module Ethon + class Multi # :nodoc + # This module contains logic to run a multi. + module Operations + STARTED_MULTI = "ETHON: started MULTI" + PERFORMED_MULTI = "ETHON: performed MULTI" + + # Return the multi handle. Inititialize multi handle, + # in case it didn't happened already. + # + # @example Return multi handle. + # multi.handle + # + # @return [ FFI::Pointer ] The multi handle. + def handle + @handle ||= FFI::AutoPointer.new(Curl.multi_init, Curl.method(:multi_cleanup)) + end + + # Initialize variables. + # + # @example Initialize variables. + # multi.init_vars + # + # @return [ void ] + def init_vars + if @execution_mode == :perform + @timeout = ::FFI::MemoryPointer.new(:long) + @timeval = Curl::Timeval.new + @fd_read = Curl::FDSet.new + @fd_write = Curl::FDSet.new + @fd_excep = Curl::FDSet.new + @max_fd = ::FFI::MemoryPointer.new(:int) + elsif @execution_mode == :socket_action + @running_count_pointer = FFI::MemoryPointer.new(:int) + end + end + + # Perform multi. + # + # @return [ nil ] + # + # @example Perform multi. + # multi.perform + def perform + ensure_execution_mode(:perform) + + Ethon.logger.debug(STARTED_MULTI) + while ongoing? + run + timeout = get_timeout + next if timeout == 0 + reset_fds + set_fds(timeout) + end + Ethon.logger.debug(PERFORMED_MULTI) + nil + end + + # Prepare multi. + # + # @return [ nil ] + # + # @example Prepare multi. + # multi.prepare + # + # @deprecated It is no longer necessary to call prepare. + def prepare + Ethon.logger.warn( + "ETHON: It is no longer necessay to call "+ + "Multi#prepare. Its going to be removed "+ + "in future versions." + ) + end + + # Continue execution with an external IO loop. + # + # @example When no sockets are ready yet, or to begin. + # multi.socket_action + # + # @example When a socket is readable + # multi.socket_action(io_object, [:in]) + # + # @example When a socket is readable and writable + # multi.socket_action(io_object, [:in, :out]) + # + # @return [ Symbol ] The Curl.multi_socket_action return code. + def socket_action(io = nil, readiness = 0) + ensure_execution_mode(:socket_action) + + fd = if io.nil? + ::Ethon::Curl::SOCKET_TIMEOUT + elsif io.is_a?(Integer) + io + else + io.fileno + end + + code = Curl.multi_socket_action(handle, fd, readiness, @running_count_pointer) + @running_count = @running_count_pointer.read_int + + check + + code + end + + # Return whether the multi still contains requests or not. + # + # @example Return if ongoing. + # multi.ongoing? + # + # @return [ Boolean ] True if ongoing, else false. + def ongoing? + easy_handles.size > 0 || (!defined?(@running_count) || running_count > 0) + end + + private + + # Get timeout. + # + # @example Get timeout. + # multi.get_timeout + # + # @return [ Integer ] The timeout. + # + # @raise [ Ethon::Errors::MultiTimeout ] If getting the timeout fails. + def get_timeout + code = Curl.multi_timeout(handle, @timeout) + raise Errors::MultiTimeout.new(code) unless code == :ok + timeout = @timeout.read_long + timeout = 1 if timeout < 0 + timeout + end + + # Reset file describtors. + # + # @example Reset fds. + # multi.reset_fds + # + # @return [ void ] + def reset_fds + @fd_read.clear + @fd_write.clear + @fd_excep.clear + end + + # Set fds. + # + # @example Set fds. + # multi.set_fds + # + # @return [ void ] + # + # @raise [ Ethon::Errors::MultiFdset ] If setting the file descriptors fails. + # @raise [ Ethon::Errors::Select ] If select fails. + def set_fds(timeout) + code = Curl.multi_fdset(handle, @fd_read, @fd_write, @fd_excep, @max_fd) + raise Errors::MultiFdset.new(code) unless code == :ok + max_fd = @max_fd.read_int + if max_fd == -1 + sleep(0.001) + else + @timeval[:sec] = timeout / 1000 + @timeval[:usec] = (timeout * 1000) % 1000000 + loop do + code = Curl.select(max_fd + 1, @fd_read, @fd_write, @fd_excep, @timeval) + break unless code < 0 && ::FFI.errno == Errno::EINTR::Errno + end + raise Errors::Select.new(::FFI.errno) if code < 0 + end + end + + # Check. + # + # @example Check. + # multi.check + # + # @return [ void ] + def check + msgs_left = ::FFI::MemoryPointer.new(:int) + while true + msg = Curl.multi_info_read(handle, msgs_left) + break if msg.null? + next if msg[:code] != :done + easy = easy_handles.find{ |e| e.handle == msg[:easy_handle] } + easy.return_code = msg[:data][:code] + Ethon.logger.debug { "ETHON: performed #{easy.log_inspect}" } + delete(easy) + easy.complete + end + end + + # Run. + # + # @example Run + # multi.run + # + # @return [ void ] + def run + running_count_pointer = FFI::MemoryPointer.new(:int) + begin code = trigger(running_count_pointer) end while code == :call_multi_perform + check + end + + # Trigger. + # + # @example Trigger. + # multi.trigger + # + # @return [ Symbol ] The Curl.multi_perform return code. + def trigger(running_count_pointer) + code = Curl.multi_perform(handle, running_count_pointer) + @running_count = running_count_pointer.read_int + code + end + + # Return number of running requests. + # + # @example Return count. + # multi.running_count + # + # @return [ Integer ] Number running requests. + def running_count + @running_count ||= nil + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/multi/options.rb b/bin/gems/ethon-0.16.0/lib/ethon/multi/options.rb new file mode 100644 index 00000000..08a3c03e --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/multi/options.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true +module Ethon + class Multi + + # This module contains the logic and knowledge about the + # available options on multi. + module Options + + # Sets max_total_connections option. + # + # @example Set max_total_connections option. + # multi.max_total_conections = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def max_total_connections=(value) + Curl.set_option(:max_total_connections, value_for(value, :int), handle, :multi) + end + + # Sets maxconnects option. + # + # @example Set maxconnects option. + # multi.maxconnects = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def maxconnects=(value) + Curl.set_option(:maxconnects, value_for(value, :int), handle, :multi) + end + + # Sets pipelining option. + # + # @example Set pipelining option. + # multi.pipelining = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def pipelining=(value) + Curl.set_option(:pipelining, value_for(value, :int), handle, :multi) + end + + # Sets socketdata option. + # + # @example Set socketdata option. + # multi.socketdata = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def socketdata=(value) + Curl.set_option(:socketdata, value_for(value, :string), handle, :multi) + end + + # Sets socketfunction option. + # + # @example Set socketfunction option. + # multi.socketfunction = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def socketfunction=(value) + Curl.set_option(:socketfunction, value_for(value, :string), handle, :multi) + end + + # Sets timerdata option. + # + # @example Set timerdata option. + # multi.timerdata = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def timerdata=(value) + Curl.set_option(:timerdata, value_for(value, :string), handle, :multi) + end + + # Sets timerfunction option. + # + # @example Set timerfunction option. + # multi.timerfunction = $value + # + # @param [ String ] value The value to set. + # + # @return [ void ] + def timerfunction=(value) + Curl.set_option(:timerfunction, value_for(value, :string), handle, :multi) + end + + private + + # Return the value to set to multi handle. It is converted with the help + # of bool_options, enum_options and int_options. + # + # @example Return casted the value. + # multi.value_for(:verbose) + # + # @return [ Object ] The casted value. + def value_for(value, type, option = nil) + return nil if value.nil? + + if type == :bool + value ? 1 : 0 + elsif type == :int + value.to_i + elsif value.is_a?(String) + Ethon::Easy::Util.escape_zero_byte(value) + else + value + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/multi/stack.rb b/bin/gems/ethon-0.16.0/lib/ethon/multi/stack.rb new file mode 100644 index 00000000..4c6381c1 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/multi/stack.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +module Ethon + class Multi + + # This module provides the multi stack behaviour. + module Stack + + # Return easy handles. + # + # @example Return easy handles. + # multi.easy_handles + # + # @return [ Array ] The easy handles. + def easy_handles + @easy_handles ||= [] + end + + # Add an easy to the stack. + # + # @example Add easy. + # multi.add(easy) + # + # @param [ Easy ] easy The easy to add. + # + # @raise [ Ethon::Errors::MultiAdd ] If adding an easy failed. + def add(easy) + return nil if easy_handles.include?(easy) + + code = Curl.multi_add_handle(handle, easy.handle) + raise Errors::MultiAdd.new(code, easy) unless code == :ok + easy_handles << easy + end + + # Delete an easy from stack. + # + # @example Delete easy from stack. + # + # @param [ Easy ] easy The easy to delete. + # + # @raise [ Ethon::Errors::MultiRemove ] If removing an easy failed. + def delete(easy) + if easy_handles.delete(easy) + code = Curl.multi_remove_handle(handle, easy.handle) + raise Errors::MultiRemove.new(code, handle) unless code == :ok + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/lib/ethon/version.rb b/bin/gems/ethon-0.16.0/lib/ethon/version.rb new file mode 100644 index 00000000..640f68d3 --- /dev/null +++ b/bin/gems/ethon-0.16.0/lib/ethon/version.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +module Ethon + + # Ethon version. + VERSION = '0.16.0' +end diff --git a/bin/gems/ethon-0.16.0/profile/benchmarks.rb b/bin/gems/ethon-0.16.0/profile/benchmarks.rb new file mode 100644 index 00000000..6cd68ca0 --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/benchmarks.rb @@ -0,0 +1,104 @@ +# encoding: utf-8 +# frozen_string_literal: true +require 'ethon' +require 'open-uri' +require 'patron' +require 'curb' +require 'net/http' +require 'cgi' +require 'benchmark/ips' + +require_relative '../spec/support/server' +require_relative '../spec/support/localhost_server' + +LocalhostServer.new(TESTSERVER.new, 3000) +LocalhostServer.new(TESTSERVER.new, 3001) +LocalhostServer.new(TESTSERVER.new, 3002) + +url = 'http://localhost:3000/'.freeze +uri = URI.parse('http://localhost:3000/').freeze +ethon = Ethon::Easy.new(url: url) +patron = Patron::Session.new +patron_url = Patron::Session.new(base_url: url) +curb = Curl::Easy.new(url) + +puts '[Creation]' +Benchmark.ips do |x| + x.report('String.new') { '' } + x.report('Easy.new') { Ethon::Easy.new } +end + +puts '[Escape]' +Benchmark.ips do |x| + x.report('CGI.escape') { CGI.escape("まつもと") } + x.report('Easy.escape') { ethon.escape("まつもと") } +end + +puts '[Requests]' +Benchmark.ips do |x| + x.report('net/http') { Net::HTTP.get_response(uri) } + x.report('open-uri') { open url } + + x.report('patron') do + patron.base_url = url + patron.get('/') + end + + x.report('patron reuse') { patron_url.get('/') } + + x.report('curb') do + curb.url = url + curb.perform + end + + x.report('curb reuse') { curb.perform } + + x.report('Easy.perform') do + ethon.url = url + ethon.perform + end + + x.report('Easy.perform reuse') { ethon.perform } +end + +puts "[ 4 delayed Requests ]" +Benchmark.ips do |x| + x.report('net/http') do + 3.times do |i| + uri = URI.parse("http://localhost:300#{i}/?delay=1") + Net::HTTP.get_response(uri) + end + end + + x.report("open-uri") do + 3.times do |i| + open("http://localhost:300#{i}/?delay=1") + end + end + + x.report("patron") do + sess = Patron::Session.new + 3.times do |i| + sess.base_url = "http://localhost:300#{i}/?delay=1" + sess.get("/") + end + end + + x.report("Easy.perform") do + easy = Ethon::Easy.new + 3.times do |i| + easy.url = "http://localhost:300#{i}/?delay=1" + easy.perform + end + end + + x.report("Multi.perform") do + multi = Ethon::Multi.new + 3.times do |i| + easy = Ethon::Easy.new + easy.url = "http://localhost:300#{i}/?delay=1" + multi.add(easy) + end + multi.perform + end +end diff --git a/bin/gems/ethon-0.16.0/profile/memory_leaks.rb b/bin/gems/ethon-0.16.0/profile/memory_leaks.rb new file mode 100644 index 00000000..32000b80 --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/memory_leaks.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true +require 'ethon' +require 'ethon/easy' + +require_relative 'perf_spec_helper' +require 'rspec/autorun' + +describe "low-level interactions with libcurl" do + describe Ethon::Multi do + memory_leak_test("init") do + Ethon::Multi.new + end + + memory_leak_test("handle") do + Ethon::Multi.new.handle + end + end + + describe Ethon::Easy do + memory_leak_test("init") do + Ethon::Easy.new + end + + memory_leak_test("handle") do + Ethon::Easy.new.handle + end + + memory_leak_test("headers") do + Ethon::Easy.new.headers = { "a" => 1, "b" => 2, "c" => 3, "d" => 4} + end + + memory_leak_test("escape") do + Ethon::Easy.new.escape("the_sky&is_blue") + end + end + + + describe Ethon::Easy::Form do + memory_leak_test("init") do + Ethon::Easy::Form.new(nil, {}) + end + + memory_leak_test("first") do + Ethon::Easy::Form.new(nil, {}).first + end + + memory_leak_test("last") do + Ethon::Easy::Form.new(nil, {}).last + end + + memory_leak_test("materialized with some params") do + form = Ethon::Easy::Form.new(nil, { "a" => "1" }) + form.materialize + end + + memory_leak_test("materialized with a file") do + File.open(__FILE__, "r") do |file| + form = Ethon::Easy::Form.new(nil, { "a" => file }) + form.materialize + end + end + end +end + +describe "higher level operations" do + memory_leak_test("a simple request") do + Ethon::Easy.new(:url => "http://localhost:3001/", + :forbid_reuse => true).perform + end + + memory_leak_test("a request with headers") do + Ethon::Easy.new(:url => "http://localhost:3001/", + :headers => { "Content-Type" => "application/json", + "Something" => "1", + "Else" => "qwerty", + "Long-String" => "aassddffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"}, + :forbid_reuse => true).perform + end + + memory_leak_test("a request with headers and params") do + easy = Ethon::Easy.new(:url => "http://localhost:3001/", + :headers => { "Content-Type" => "application/json", + "Something" => "1", + "Else" => "qwerty", + "Long-String" => "aassddffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"}, + :forbid_reuse => true) + easy.http_request("http://localhost:3001/", + :get, + :params => { "param1" => "value1", + "param2" => "value2", + "param3" => "value3", + "param4" => "value4"}) + end + + memory_leak_test("a request with headers, params, and body") do + easy = Ethon::Easy.new(:url => "http://localhost:3001/", + :headers => { "Content-Type" => "application/json", + "Something" => "1", + "Else" => "qwerty", + "Long-String" => "aassddffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"}, + :forbid_reuse => true) + easy.http_request("http://localhost:3001/", + :get, + :params => { "param1" => "value1", + "param2" => "value2", + "param3" => "value3", + "param4" => "value4"}, + :body => { + "body1" => "value1", + "body2" => "value2", + "body3" => "value3" + }) + end +end diff --git a/bin/gems/ethon-0.16.0/profile/perf_spec_helper.rb b/bin/gems/ethon-0.16.0/profile/perf_spec_helper.rb new file mode 100644 index 00000000..35fd623d --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/perf_spec_helper.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +#### SETUP +require 'bundler' +Bundler.setup +require 'rspec' + +require 'support/localhost_server' +require 'support/server' +require_relative 'support/memory_test_helpers' + +require 'logger' + +if ENV['VERBOSE'] + Ethon.logger = Logger.new($stdout) + Ethon.logger.level = Logger::DEBUG +end + +RSpec.configure do |config| + config.before(:suite) do + LocalhostServer.new(TESTSERVER.new, 3001) + end + config.include(MemoryTestHelpers) + config.extend(MemoryTestHelpers::TestMethods) +end + +MemoryTestHelpers.setup +MemoryTestHelpers.logger = Logger.new($stdout) +MemoryTestHelpers.logger.level = Logger::INFO +MemoryTestHelpers.logger.formatter = proc do |severity, datetime, progname, msg| + "\t\t#{msg}\n" +end + +if ENV['VERBOSE'] + MemoryTestHelpers.logger.level = Logger::DEBUG +end + +MemoryTestHelpers.iterations = ENV.fetch("ITERATIONS", 10_000).to_i diff --git a/bin/gems/ethon-0.16.0/profile/support/memory_test_helpers.rb b/bin/gems/ethon-0.16.0/profile/support/memory_test_helpers.rb new file mode 100644 index 00000000..bfb6ff47 --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/support/memory_test_helpers.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +require_relative 'ruby_object_leak_tracker' +require_relative 'os_memory_leak_tracker' + +module MemoryTestHelpers + class << self + attr_accessor :gc_proc, :iterations, :logger + + def setup + if RUBY_PLATFORM == "java" + # for leak detection + JRuby.objectspace = true if defined?(JRuby) + # for gc + require 'java' + java_import 'java.lang.System' + self.gc_proc = proc { System.gc } + else + self.gc_proc = proc { GC.start } + end + end + end + + module TestMethods + def memory_leak_test(description, &block) + context(description) do + it "doesn't leak ruby objects" do + object_leak_tracker = RubyObjectLeakTracker.new + track_memory_usage(object_leak_tracker, &block) + object_leak_tracker.total_difference_between_runs.should be <= 10 + end + + it "doesn't leak OS memory (C interop check)" do + os_memory_leak_tracker = OSMemoryLeakTracker.new + track_memory_usage(os_memory_leak_tracker, &block) + os_memory_leak_tracker.total_difference_between_runs.should be <= 10 + end + end + end + end + + def track_memory_usage(tracker) + # Intentionally do all this setup before we do any testing + logger = MemoryTestHelpers.logger + iterations = MemoryTestHelpers.iterations + + checkpoint_frequency = (iterations / 10.0).to_i + gc_frequency = 20 + + warmup_iterations = [(iterations / 3.0).to_i, 500].min + logger.info "Performing #{warmup_iterations} warmup iterations" + warmup_iterations.times do + yield + MemoryTestHelpers.gc_proc.call + end + tracker.capture_initial_memory_usage + + logger.info "Performing #{iterations} iterations (checkpoint every #{checkpoint_frequency})" + + iterations.times do |i| + yield + + last_iteration = (i == iterations - 1) + checkpoint = last_iteration || (i % checkpoint_frequency == 0) + + if checkpoint || (i % gc_frequency == 0) + MemoryTestHelpers.gc_proc.call + end + + if checkpoint + logger.info "Iteration #{i} checkpoint" + tracker.capture_memory_usage + tracker.dump_status(logger) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/profile/support/os_memory_leak_tracker.rb b/bin/gems/ethon-0.16.0/profile/support/os_memory_leak_tracker.rb new file mode 100644 index 00000000..d9e62d4b --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/support/os_memory_leak_tracker.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +class OSMemoryLeakTracker + attr_reader :current_run + + def initialize + @previous_run = @current_run = 0 + end + + def difference_between_runs(basis=@previous_run) + @current_run - basis + end + + def total_difference_between_runs + difference_between_runs(@initial_count_run) + end + + def capture_initial_memory_usage + capture_memory_usage + @initial_count_run = @current_run + end + + def capture_memory_usage + @previous_run = @current_run + @current_run = rss_bytes + end + + def dump_status(logger) + delta = difference_between_runs + logger.add(log_level(delta), sprintf("\tTotal memory usage (kb): %d (%+d)", current_run, delta)) + end + + private + # amount of memory the current process "is using", in RAM + # (doesn't include any swap memory that it may be using, just that in actual RAM) + # Code loosely based on https://github.com/rdp/os/blob/master/lib/os.rb + # returns 0 on windows + def rss_bytes + if ENV['OS'] == 'Windows_NT' + 0 + else + `ps -o rss= -p #{Process.pid}`.to_i # in kilobytes + end + end + + def log_level(delta) + delta > 0 ? Logger::WARN : Logger::DEBUG + end +end \ No newline at end of file diff --git a/bin/gems/ethon-0.16.0/profile/support/ruby_object_leak_tracker.rb b/bin/gems/ethon-0.16.0/profile/support/ruby_object_leak_tracker.rb new file mode 100644 index 00000000..afcce5a8 --- /dev/null +++ b/bin/gems/ethon-0.16.0/profile/support/ruby_object_leak_tracker.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +class RubyObjectLeakTracker + attr_reader :previous_count_hash, :current_count_hash + + def initialize + @previous_count_hash = @current_count_hash = {} + end + + def difference_between_runs(basis=@previous_count_hash) + @difference_between_runs ||= Hash[@current_count_hash.map do |object_class, count| + [object_class, count - (basis[object_class] || 0)] + end] + end + + def total_difference_between_runs + difference_between_runs(@initial_count_hash).values.inject(0) { |sum, count| sum + count } + end + + def capture_initial_memory_usage + capture_memory_usage + @initial_count_hash = @current_count_hash + end + + def capture_memory_usage + @difference_between_runs = nil + @previous_count_hash = @current_count_hash + + class_to_count = Hash.new { |hash, key| hash[key] = 0 } + ObjectSpace.each_object { |obj| class_to_count[obj.class] += 1 } + + sorted_class_to_count = class_to_count.sort_by { |k, v| -v } + @current_count_hash = Hash[sorted_class_to_count] + end + + def dump_status(logger) + diff = difference_between_runs + most_used_objects = current_count_hash.to_a.sort_by(&:last).reverse[0, 20] + + most_used_objects.each do |object_class, count| + delta = diff[object_class] + logger.add(log_level(delta), sprintf("\t%s: %d (%+d)", object_class, count, delta)) + end + end + + private + def log_level(delta) + delta > 0 ? Logger::WARN : Logger::DEBUG + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/curl_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/curl_spec.rb new file mode 100644 index 00000000..24d37263 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/curl_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Curl do + describe ".init" do + before { Ethon::Curl.send(:class_variable_set, :@@initialized, false) } + + context "when global_init fails" do + it "raises global init error" do + expect(Ethon::Curl).to receive(:global_init).and_return(1) + expect{ Ethon::Curl.init }.to raise_error(Ethon::Errors::GlobalInit) + end + end + + context "when global_init works" do + before { expect(Ethon::Curl).to receive(:global_init).and_return(0) } + + it "doesn't raises global init error" do + expect{ Ethon::Curl.init }.to_not raise_error + end + + it "logs" do + expect(Ethon.logger).to receive(:debug) + Ethon::Curl.init + end + end + + context "when global_cleanup is called" do + before { expect(Ethon::Curl).to receive(:global_cleanup) } + + it "logs" do + expect(Ethon.logger).to receive(:debug).twice + Ethon::Curl.init + Ethon::Curl.cleanup + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/callbacks_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/callbacks_spec.rb new file mode 100644 index 00000000..2fa75da9 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/callbacks_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Callbacks do + let!(:easy) { Ethon::Easy.new } + + describe "#set_callbacks" do + before do + expect(Ethon::Curl).to receive(:set_option).exactly(3).times + end + + it "sets write-, debug-, and headerfunction" do + easy.set_callbacks + end + + it "resets @response_body" do + easy.set_callbacks + expect(easy.instance_variable_get(:@response_body)).to eq("") + end + + it "resets @response_headers" do + easy.set_callbacks + expect(easy.instance_variable_get(:@response_headers)).to eq("") + end + + it "resets @debug_info" do + easy.set_callbacks + expect(easy.instance_variable_get(:@debug_info).to_a).to eq([]) + end + end + + describe "#progress_callback" do + it "returns 0" do + expect(easy.progress_callback.call(0,1,1,1,1)).to be(0) + end + end + + describe "#body_write_callback" do + let(:body_write_callback) { easy.instance_variable_get(:@body_write_callback) } + let(:stream) { double(:read_string => "") } + context "when body returns not :abort" do + it "returns number bigger than 0" do + expect(body_write_callback.call(stream, 1, 1, nil) > 0).to be(true) + end + end + + context "when body returns :abort" do + before do + easy.on_body.clear + easy.on_body { :abort } + end + let(:body_write_callback) { easy.instance_variable_get(:@body_write_callback) } + + it "returns -1 to indicate abort to libcurl" do + expect(body_write_callback.call(stream, 1, 1, nil)).to eq(-1) + end + end + end + + describe "#header_write_callback" do + let(:header_write_callback) { easy.instance_variable_get(:@header_write_callback) } + let(:stream) { double(:read_string => "") } + context "when header returns not :abort" do + it "returns number bigger than 0" do + expect(header_write_callback.call(stream, 1, 1, nil) > 0).to be(true) + end + end + + context "when header returns :abort" do + before do + easy.on_headers.clear + easy.on_headers { :abort } + end + let(:header_write_callback) { easy.instance_variable_get(:@header_write_callback) } + + it "returns -1 to indicate abort to libcurl" do + expect(header_write_callback.call(stream, 1, 1, nil)).to eq(-1) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/debug_info_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/debug_info_spec.rb new file mode 100644 index 00000000..8dccc388 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/debug_info_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::DebugInfo do + let(:easy) { Ethon::Easy.new } + + before do + easy.url = "http://localhost:3001/" + easy.perform + end + + describe "#debug_info" do + context "when verbose is not set to true" do + it "does not save any debug info after a request" do + expect(easy.debug_info.to_a.length).to eq(0) + expect(easy.debug_info.to_h.values.flatten.length).to eq(0) + end + end + + context "when verbose is set to true" do + before do + easy.verbose = true + easy.perform + end + + after do + easy.verbose = false + easy.reset + end + + it "saves debug info after a request" do + expect(easy.debug_info.to_a.length).to be > 0 + end + + it "saves request headers" do + expect(easy.debug_info.header_out.join).to include('GET / HTTP/1.1') + end + + it "saves response headers" do + expect(easy.debug_info.header_in.length).to be > 0 + expect(easy.response_headers).to include(easy.debug_info.header_in.join) + end + + it "saves incoming data" do + expect(easy.debug_info.data_in.length).to be > 0 + expect(easy.response_body).to include(easy.debug_info.data_in.join) + end + + it "saves debug text" do + expect(easy.debug_info.text.length).to be > 0 + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/features_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/features_spec.rb new file mode 100644 index 00000000..b174948f --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/features_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Informations do + + describe "#supports_asynch_dns?" do + it "returns boolean" do + expect([true, false].include? Ethon::Easy.supports_asynch_dns?).to be_truthy + end + end + + describe "#supports_zlib?" do + it "returns boolean" do + expect([true, false].include? Ethon::Easy.supports_zlib?).to be_truthy + end + end + + describe "#supports_timeout_ms?" do + it "returns boolean" do + expect([true, false].include? Ethon::Easy.supports_timeout_ms?).to be_truthy + end + end + +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/form_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/form_spec.rb new file mode 100644 index 00000000..4cd34d96 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/form_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Form do + let(:hash) { {} } + let!(:easy) { Ethon::Easy.new } + let(:form) { Ethon::Easy::Form.new(easy, hash) } + + describe ".new" do + it "assigns attribute to @params" do + expect(form.instance_variable_get(:@params)).to eq(hash) + end + end + + describe "#first" do + it "returns a pointer" do + expect(form.first).to be_a(FFI::Pointer) + end + end + + describe "#last" do + it "returns a pointer" do + expect(form.first).to be_a(FFI::Pointer) + end + end + + describe "#multipart?" do + before { form.instance_variable_set(:@query_pairs, pairs) } + + context "when query_pairs contains string values" do + let(:pairs) { [['a', '1'], ['b', '2']] } + + it "returns false" do + expect(form.multipart?).to be_falsey + end + end + + context "when query_pairs contains file" do + let(:pairs) { [['a', '1'], ['b', ['path', 'encoding', 'abs_path']]] } + + it "returns true" do + expect(form.multipart?).to be_truthy + end + end + + context "when options contains multipart=true" do + before { form.instance_variable_set(:@multipart, true) } + let(:pairs) { [['a', '1'], ['b', '2']] } + + it "returns true" do + expect(form.multipart?).to be_truthy + end + end + end + + describe "#materialize" do + before { form.instance_variable_set(:@query_pairs, pairs) } + + context "when query_pairs contains string values" do + let(:pairs) { [['a', '1']] } + + it "adds params to form" do + expect(Ethon::Curl).to receive(:formadd) + form.materialize + end + end + + context "when query_pairs contains nil" do + let(:pairs) { [['a', nil]] } + + it "adds params to form" do + expect(Ethon::Curl).to receive(:formadd) + form.materialize + end + end + + context "when query_pairs contains file" do + let(:pairs) { [['a', ["file", "type", "path/file"]]] } + + it "adds file to form" do + expect(Ethon::Curl).to receive(:formadd) + form.materialize + end + end + + context "when query_pairs contains file and string values" do + let(:pairs) { [['a', ["file", "type", "path/file"]], ['b', '1']] } + + it "adds file to form" do + expect(Ethon::Curl).to receive(:formadd).twice + form.materialize + end + end + + context "when query_pairs contains file, string and int values" do + let(:pairs) { [['a', ["file", "type", "path/file"]], ['b', '1'], ['c', 1]] } + + it "adds file to form" do + expect(Ethon::Curl).to receive(:formadd).exactly(3).times + form.materialize + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/header_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/header_spec.rb new file mode 100644 index 00000000..4931fc75 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/header_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Header do + let(:easy) { Ethon::Easy.new } + + describe "#headers=" do + let(:headers) { { 'User-Agent' => 'Ethon' } } + + it "sets header" do + expect_any_instance_of(Ethon::Easy).to receive(:set_callbacks) + expect(Ethon::Curl).to receive(:set_option) + easy.headers = headers + end + + context "when requesting" do + before do + easy.headers = headers + easy.url = "http://localhost:3001" + easy.perform + end + + it "sends" do + expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon"') + end + + context "when header value contains null byte" do + let(:headers) { { 'User-Agent' => "Ethon\0" } } + + it "escapes" do + expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon\\\\0"') + end + end + + context "when header value has leading whitespace" do + let(:headers) { { 'User-Agent' => " Ethon" } } + + it "removes" do + expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon"') + end + end + + context "when header value has traiing whitespace" do + let(:headers) { { 'User-Agent' => "Ethon " } } + + it "removes" do + expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon"') + end + end + end + end + + describe "#compose_header" do + it "has space in between" do + expect(easy.compose_header('a', 'b')).to eq('a: b') + end + + context "when value is a symbol" do + it "works" do + expect{ easy.compose_header('a', :b) }.to_not raise_error + end + end + end + + describe "#header_list" do + context "when no set_headers" do + it "returns nil" do + expect(easy.header_list).to eq(nil) + end + end + + context "when set_headers" do + it "returns pointer to header list" do + easy.headers = {'User-Agent' => 'Custom'} + expect(easy.header_list).to be_a(FFI::Pointer) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/custom_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/custom_spec.rb new file mode 100644 index 00000000..ba0978b8 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/custom_spec.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Custom do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:custom) { described_class.new("PURGE", url, {:params => params, :body => form}) } + + describe "#setup" do + context "when nothing" do + it "sets url" do + custom.setup(easy) + expect(easy.url).to eq(url) + end + + it "makes a custom request" do + custom.setup(easy) + easy.perform + expect(easy.response_body).to include('"REQUEST_METHOD":"PURGE"') + end + end + + context "when params" do + let(:params) { {:a => "1&"} } + + it "attaches escaped to url" do + custom.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + custom.setup(easy) + easy.perform + end + + it "is a custom verb" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PURGE"') + end + + it "does not use application/x-www-form-urlencoded content type" do + expect(easy.response_body).to_not include('"CONTENT_TYPE":"application/x-www-form-urlencoded"') + end + + it "requests parameterized url" do + expect(easy.response_body).to include('"REQUEST_URI":"http://localhost:3001/?a=1%26"') + end + end + end + + context "when body" do + context "when multipart" do + let(:form) { {:a => File.open(__FILE__, 'r')} } + + it "sets httppost" do + expect(easy).to receive(:httppost=) + custom.setup(easy) + end + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + custom.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a custom verb" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PURGE"') + end + + it "uses multipart/form-data content type" do + expect(easy.response_body).to include('"CONTENT_TYPE":"multipart/form-data') + end + + it "submits a body" do + expect(easy.response_body).to match('"body":".+"') + end + + it "submits the data" do + expect(easy.response_body).to include('"filename":"custom_spec.rb"') + end + end + end + + context "when not multipart" do + let(:form) { {:a => "1&b=2"} } + let(:encoded) { "a=1%26b%3D2" } + + it "sets escaped copypostfields" do + expect(easy).to receive(:copypostfields=).with(encoded) + custom.setup(easy) + end + + it "sets postfieldsize" do + expect(easy).to receive(:postfieldsize=).with(encoded.bytesize) + custom.setup(easy) + end + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + custom.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a custom verb" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PURGE"') + end + + it "uses multipart/form-data content type" do + expect(easy.response_body).to include('"CONTENT_TYPE":"application/x-www-form-urlencoded') + end + + it "submits a body" do + expect(easy.response_body).to match('"body":"a=1%26b%3D2"') + end + + it "submits the data" do + expect(easy.response_body).to include('"rack.request.form_hash":{"a":"1&b=2"}') + end + end + end + + context "when string" do + let(:form) { "{a: 1}" } + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + custom.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "sends string" do + expect(easy.response_body).to include('"body":"{a: 1}"') + end + end + end + end + + context "when params and body" do + let(:form) { {:a => "1"} } + let(:params) { {:b => "2"} } + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + custom.setup(easy) + easy.perform + end + + it "url contains params" do + expect(easy.response_body).to include('"REQUEST_URI":"http://localhost:3001/?b=2"') + end + + it "body contains form" do + expect(easy.response_body).to include('"body":"a=1"') + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/delete_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/delete_spec.rb new file mode 100644 index 00000000..fe7e55e5 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/delete_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Delete do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:delete) { described_class.new(url, {:params => params, :body => form}) } + + context "when requesting" do + before do + delete.setup(easy) + easy.perform + end + + it "makes a delete request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"DELETE"') + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/get_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/get_spec.rb new file mode 100644 index 00000000..e3a7e4fa --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/get_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Get do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:options) { {} } + let(:get) { described_class.new(url, {:params => params, :body => form}.merge(options)) } + + describe "#setup" do + it "sets url" do + get.setup(easy) + expect(easy.url).to eq(url) + end + + context "when body" do + let(:form) { { :a => 1 } } + + it "sets customrequest" do + expect(easy).to receive(:customrequest=).with("GET") + get.setup(easy) + end + end + + context "when no body" do + it "doesn't set customrequest" do + expect(easy).to receive(:customrequest=).never + get.setup(easy) + end + end + + context "when requesting" do + before do + get.setup(easy) + easy.perform + end + + context "when url already contains params" do + let(:url) { "http://localhost:3001/?query=here" } + let(:params) { {:a => "1&b=2"} } + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a get request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"GET"') + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?query=here&a=1%26b%3D2") + end + end + + context "when params and no body" do + let(:params) { {:a => "1&b=2"} } + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a get request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"GET"') + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?a=1%26b%3D2") + end + end + + context "when params and body" do + let(:params) { {:a => "1&b=2"} } + let(:form) { {:b => "2"} } + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a get request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"GET"') + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?a=1%26b%3D2") + end + end + + context "with :escape" do + let(:params) { {:a => "1&b=2"} } + + context 'missing' do + it "escapes values" do + expect(easy.url).to eq("#{url}?a=1%26b%3D2") + end + end + + context 'nil' do + let(:options) { {:escape => nil} } + + it "escapes values" do + expect(easy.url).to eq("#{url}?a=1%26b%3D2") + end + end + + context 'true' do + let(:options) { {:escape => true} } + + it "escapes values" do + expect(easy.url).to eq("#{url}?a=1%26b%3D2") + end + end + + context 'false' do + let(:options) { {:escape => false} } + + it "sends raw values" do + expect(easy.url).to eq("#{url}?a=1&b=2") + end + end + end + + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/head_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/head_spec.rb new file mode 100644 index 00000000..5a04f062 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/head_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Head do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:head) { described_class.new(url, {:params => params, :body => form}) } + + describe "#setup" do + context "when nothing" do + it "sets nobody" do + expect(easy).to receive(:nobody=).with(true) + head.setup(easy) + end + + it "sets url" do + head.setup(easy) + expect(easy.url).to eq(url) + end + end + + context "when params" do + let(:params) { {:a => "1&b=2"} } + + it "sets nobody" do + expect(easy).to receive(:nobody=).with(true) + head.setup(easy) + end + + it "attaches escaped to url" do + head.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26b%3D2") + end + + context "when requesting" do + before do + head.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "has no body" do + expect(easy.response_body).to be_empty + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?a=1%26b%3D2") + end + + context "when url already contains params" do + let(:url) { "http://localhost:3001/?query=here" } + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?query=here&a=1%26b%3D2") + end + end + end + end + + context "when body" do + let(:form) { {:a => 1} } + + context "when requesting" do + before do + head.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/options_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/options_spec.rb new file mode 100644 index 00000000..99ca96fc --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/options_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Options do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:options) { described_class.new(url, {:params => params, :body => form}) } + + describe "#setup" do + it "sets customrequest" do + expect(easy).to receive(:customrequest=).with("OPTIONS") + options.setup(easy) + end + + it "sets url" do + options.setup(easy) + expect(easy.url).to eq(url) + end + + context "when requesting" do + let(:params) { {:a => "1&b=2"} } + + before do + options.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a options request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"OPTIONS"') + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?a=1%26b%3D2") + end + + context "when url already contains params" do + let(:url) { "http://localhost:3001/?query=here" } + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?query=here&a=1%26b%3D2") + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/patch_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/patch_spec.rb new file mode 100644 index 00000000..a74cec7a --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/patch_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Patch do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:patch) { described_class.new(url, {:params => params, :body => form}) } + + describe "#setup" do + it "sets customrequest" do + expect(easy).to receive(:customrequest=).with("PATCH") + patch.setup(easy) + end + + it "sets url" do + patch.setup(easy) + expect(easy.url).to eq(url) + end + + context "when requesting" do + let(:params) { {:a => "1&b=2"} } + + before do + patch.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a patch request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PATCH"') + end + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?a=1%26b%3D2") + end + + context "when url already contains params" do + let(:url) { "http://localhost:3001/?query=here" } + + it "requests parameterized url" do + expect(easy.effective_url).to eq("http://localhost:3001/?query=here&a=1%26b%3D2") + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/post_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/post_spec.rb new file mode 100644 index 00000000..a65ceff0 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/post_spec.rb @@ -0,0 +1,317 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Post do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:options) { Hash.new } + let(:post) { described_class.new(url, options.merge({:params => params, :body => form})) } + + describe "#setup" do + context "when nothing" do + it "sets url" do + post.setup(easy) + expect(easy.url).to eq(url) + end + + it "sets postfield_size" do + expect(easy).to receive(:postfieldsize=).with(0) + post.setup(easy) + end + + it "sets copy_postfields" do + expect(easy).to receive(:copypostfields=).with("") + post.setup(easy) + end + + it "makes a post request" do + post.setup(easy) + easy.perform + expect(easy.response_body).to include('"REQUEST_METHOD":"POST"') + end + end + + context "when params" do + let(:params) { {:a => "1&"} } + + it "attaches escaped to url" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + + context "with arrays" do + let(:params) { {:a => %w( foo bar )} } + + context "by default" do + it "encodes them with indexes" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a%5B0%5D=foo&a%5B1%5D=bar") + end + end + + context "when params_encoding is :rack" do + let(:options) { {:params_encoding => :rack} } + it "encodes them without indexes" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a%5B%5D=foo&a%5B%5D=bar") + end + end + end + + context "with :escape" do + context 'missing' do + it "escapes values" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + end + + context 'nil' do + let(:options) { {:escape => nil} } + + it "escapes values" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + end + + context 'true' do + let(:options) { {:escape => true} } + + it "escapes values" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + end + + context 'false' do + let(:options) { {:escape => false} } + + it "sends raw values" do + post.setup(easy) + expect(easy.url).to eq("#{url}?a=1&") + end + end + end + + it "sets postfieldsize" do + expect(easy).to receive(:postfieldsize=).with(0) + post.setup(easy) + end + + it "sets copypostfields" do + expect(easy).to receive(:copypostfields=).with("") + post.setup(easy) + end + + context "when requesting" do + let(:postredir) { nil } + + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.postredir = postredir + easy.followlocation = true + easy.perform + end + + it "is a post" do + expect(easy.response_body).to include('"REQUEST_METHOD":"POST"') + end + + it "uses application/x-www-form-urlencoded content type" do + expect(easy.response_body).to include('"CONTENT_TYPE":"application/x-www-form-urlencoded"') + end + + it "requests parameterized url" do + expect(easy.response_body).to include('"REQUEST_URI":"http://localhost:3001/?a=1%26"') + end + + context "when redirection" do + let(:url) { "localhost:3001/redirect" } + + context "when no postredirs" do + it "is a get" do + expect(easy.response_body).to include('"REQUEST_METHOD":"GET"') + end + end + + unless ENV['TRAVIS'] + context "when postredirs" do + let(:postredir) { :post_all } + + it "is a post" do + expect(easy.response_body).to include('"REQUEST_METHOD":"POST"') + end + end + end + end + end + end + + context "when body" do + context "when multipart" do + let(:form) { {:a => File.open(__FILE__, 'r')} } + + it "sets httppost" do + expect(easy).to receive(:httppost=) + post.setup(easy) + end + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a post" do + expect(easy.response_body).to include('"REQUEST_METHOD":"POST"') + end + + it "uses multipart/form-data content type" do + expect(easy.response_body).to include('"CONTENT_TYPE":"multipart/form-data') + end + + it "submits a body" do + expect(easy.response_body).to match('"body":".+"') + end + + it "submits the data" do + expect(easy.response_body).to include('"filename":"post_spec.rb"') + end + end + end + + context "when not multipart" do + let(:form) { {:a => "1&b=2"} } + let(:encoded) { "a=1%26b%3D2" } + + it "sets escaped copypostfields" do + expect(easy).to receive(:copypostfields=).with(encoded) + post.setup(easy) + end + + it "sets postfieldsize" do + expect(easy).to receive(:postfieldsize=).with(encoded.bytesize) + post.setup(easy) + end + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "is a post" do + expect(easy.response_body).to include('"REQUEST_METHOD":"POST"') + end + + it "uses multipart/form-data content type" do + expect(easy.response_body).to include('"CONTENT_TYPE":"application/x-www-form-urlencoded') + end + + it "submits a body" do + expect(easy.response_body).to match('"body":"a=1%26b%3D2"') + end + + it "submits the data" do + expect(easy.response_body).to include('"rack.request.form_hash":{"a":"1&b=2"}') + end + end + end + + context "when string" do + let(:form) { "{a: 1}" } + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "sends string" do + expect(easy.response_body).to include('"body":"{a: 1}"') + end + end + end + + context "when binary with null bytes" do + let(:form) { [1, 0, 1].pack('c*') } + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.perform + end + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "sends binary data" do + expect(easy.response_body).to include('"body":"\\u0001\\u0000\\u0001"') + end + end + end + + context "when arrays" do + let(:form) { {:a => %w( foo bar )} } + + context "by default" do + it "sets copypostfields with indexed, escaped representation" do + expect(easy).to receive(:copypostfields=).with('a%5B0%5D=foo&a%5B1%5D=bar') + post.setup(easy) + end + end + + context "when params_encoding is :rack" do + let(:options) { {:params_encoding => :rack} } + + it "sets copypostfields with non-indexed, escaped representation" do + expect(easy).to receive(:copypostfields=).with('a%5B%5D=foo&a%5B%5D=bar') + post.setup(easy) + end + end + end + end + + context "when params and body" do + let(:form) { {:a => "1"} } + let(:params) { {:b => "2"} } + + context "when requesting" do + before do + easy.headers = { 'Expect' => '' } + post.setup(easy) + easy.perform + end + + it "url contains params" do + expect(easy.response_body).to include('"REQUEST_URI":"http://localhost:3001/?b=2"') + end + + it "body contains form" do + expect(easy.response_body).to include('"body":"a=1"') + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http/put_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/put_spec.rb new file mode 100644 index 00000000..f294c371 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http/put_spec.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http::Put do + let(:easy) { Ethon::Easy.new } + let(:url) { "http://localhost:3001/" } + let(:params) { nil } + let(:form) { nil } + let(:options) { Hash.new } + let(:put) { described_class.new(url, options.merge({:params => params, :body => form})) } + + describe "#setup" do + context "when nothing" do + it "sets url" do + put.setup(easy) + expect(easy.url).to eq(url) + end + + it "sets upload" do + expect(easy).to receive(:upload=).with(true) + put.setup(easy) + end + + it "sets infilesize" do + expect(easy).to receive(:infilesize=).with(0) + put.setup(easy) + end + + context "when requesting" do + it "makes a put request" do + put.setup(easy) + easy.perform + expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"') + end + end + end + + context "when params" do + let(:params) { {:a => "1&"} } + + it "attaches escaped to url" do + put.setup(easy) + expect(easy.url).to eq("#{url}?a=1%26") + end + + context "with arrays" do + let(:params) { {:a => %w( foo bar )} } + + context "by default" do + it "encodes them with indexes" do + put.setup(easy) + expect(easy.url).to eq("#{url}?a%5B0%5D=foo&a%5B1%5D=bar") + end + end + + context "when params_encoding is :rack" do + let(:options) { {:params_encoding => :rack} } + it "encodes them without indexes" do + put.setup(easy) + expect(easy.url).to eq("#{url}?a%5B%5D=foo&a%5B%5D=bar") + end + end + end + + it "sets upload" do + expect(easy).to receive(:upload=).with(true) + put.setup(easy) + end + + it "sets infilesize" do + expect(easy).to receive(:infilesize=).with(0) + put.setup(easy) + end + + context "when requesting" do + before do + put.setup(easy) + easy.perform + end + + it "makes a put request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"') + end + end + end + + context "when body" do + let(:form) { {:a => "1&b=2"} } + + it "sets infilesize" do + expect(easy).to receive(:infilesize=).with(11) + put.setup(easy) + end + + it "sets readfunction" do + expect(easy).to receive(:readfunction) + put.setup(easy) + end + + it "sets upload" do + expect(easy).to receive(:upload=).with(true) + put.setup(easy) + end + + context "when requesting" do + context "sending string body" do + before do + easy.headers = { 'Expect' => '' } + put.setup(easy) + easy.perform + end + + it "makes a put request" do + expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"') + end + + it "submits a body" do + expect(easy.response_body).to include('"body":"a=1%26b%3D2"') + end + end + + context "when injecting a file as body" do + let(:file) { File.open(__FILE__) } + let(:easy) do + e = Ethon::Easy.new(:url => url, :upload => true) + e.set_read_callback(file) + e.infilesize = File.size(file.path) + e + end + + before do + easy.headers = { 'Expect' => '' } + easy.perform + end + + it "submits file" do + expect(easy.response_body).to include("injecting") + end + end + end + + context "when arrays" do + let(:form) { {:a => %w( foo bar )} } + + before do + put.setup(easy) + easy.perform + end + + context "by default" do + it "submits an indexed, escaped representation" do + expect(easy.response_body).to include('"body":"a%5B0%5D=foo&a%5B1%5D=bar"') + end + end + + context "when params_encoding is :rack" do + let(:options) { {:params_encoding => :rack} } + + it "submits an non-indexed, escaped representation" do + expect(easy.response_body).to include('"body":"a%5B%5D=foo&a%5B%5D=bar"') + end + end + end + end + + context "when params and body" + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/http_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/http_spec.rb new file mode 100644 index 00000000..b74a2df7 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/http_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Http do + let(:easy) { Ethon::Easy.new } + + describe "#http_request" do + let(:url) { "http://localhost:3001/" } + let(:action_name) { :get } + let(:options) { {} } + + let(:get) { double(:setup) } + let(:get_class) { Ethon::Easy::Http::Get } + + it "instanciates action" do + expect(get).to receive(:setup) + expect(get_class).to receive(:new).and_return(get) + easy.http_request(url, action_name, options) + end + + context "when requesting" do + [ :get, :post, :put, :delete, :head, :patch, :options ].map do |action| + it "returns ok" do + easy.http_request(url, action, options) + easy.perform + expect(easy.return_code).to be(:ok) + end + + unless action == :head + it "makes a #{action.to_s.upcase} request" do + easy.http_request(url, action, options) + easy.perform + expect(easy.response_body).to include("\"REQUEST_METHOD\":\"#{action.to_s.upcase}\"") + end + + it "streams the response body from the #{action.to_s.upcase} request" do + bytes_read = 0 + easy.on_body { |chunk, response| bytes_read += chunk.bytesize } + easy.http_request(url, action, options) + easy.perform + content_length = ((easy.response_headers =~ /Content-Length: (\d+)/) && $1.to_i) + expect(bytes_read).to eq(content_length) + expect(easy.response_body).to eq("") + end + + it "notifies when headers are ready" do + headers = [] + easy.on_headers { |r| headers << r.response_headers } + easy.http_request(url, action, options) + easy.perform + expect(headers).to eq([easy.response_headers]) + expect(headers.first).to match(/Content-Length: (\d+)/) + end + end + end + + it "makes requests with custom HTTP verbs" do + easy.http_request(url, :purge, options) + easy.perform + expect(easy.response_body).to include(%{"REQUEST_METHOD":"PURGE"}) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/informations_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/informations_spec.rb new file mode 100644 index 00000000..3526847a --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/informations_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Informations do + let(:easy) { Ethon::Easy.new } + + before do + easy.url = "http://localhost:3001" + easy.perform + end + + describe "#httpauth_avail" do + it "returns" do + expect(easy.httpauth_avail).to be + end + end + + describe "#total_time" do + it "returns float" do + expect(easy.total_time).to be_a(Float) + end + end + + describe "#starttransfer_time" do + it "returns float" do + expect(easy.starttransfer_time).to be_a(Float) + end + end + + describe "#appconnect_time" do + it "returns float" do + expect(easy.appconnect_time).to be_a(Float) + end + end + + describe "#pretransfer_time" do + it "returns float" do + expect(easy.pretransfer_time).to be_a(Float) + end + end + + describe "#connect_time" do + it "returns float" do + expect(easy.connect_time).to be_a(Float) + end + end + + describe "#namelookup_time" do + it "returns float" do + expect(easy.namelookup_time).to be_a(Float) + end + end + + describe "#redirect_time" do + it "returns float" do + expect(easy.redirect_time).to be_a(Float) + end + end + + describe "#effective_url" do + it "returns url" do + expect(easy.effective_url).to match(/^http:\/\/localhost:3001\/?/) + end + end + + describe "#primary_ip" do + it "returns localhost" do + expect(easy.primary_ip).to match(/::1|127\.0\.0\.1/) + end + end + + describe "#response_code" do + it "returns 200" do + expect(easy.response_code).to eq(200) + end + end + + describe "#redirect_count" do + it "returns 0" do + expect(easy.redirect_count).to eq(0) + end + end + + describe "#redirect_url" do + it "returns nil as there is no redirect" do + expect(easy.redirect_url).to be(nil) + end + end + + describe "#request_size" do + it "returns 53" do + expect(easy.request_size).to eq(53) + end + end + + describe "#supports_zlib?" do + it "returns true" do + expect(Kernel).to receive(:warn) + expect(easy.supports_zlib?).to be_truthy + end + end + + describe "#size_upload" do + it "returns float" do + expect(easy.size_upload).to be_a(Float) + end + end + + describe "#size_download" do + it "returns float" do + expect(easy.size_download).to be_a(Float) + end + end + + describe "#speed_upload" do + it "returns float" do + expect(easy.speed_upload).to be_a(Float) + end + end + + describe "#speed_download" do + it "returns float" do + expect(easy.speed_download).to be_a(Float) + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/mirror_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/mirror_spec.rb new file mode 100644 index 00000000..29d150d1 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/mirror_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Mirror do + let(:options) { nil } + let(:mirror) { described_class.new(options) } + + describe "::INFORMATIONS_TO_LOG" do + [ + :return_code, :response_code, :response_body, :response_headers, + :total_time, :starttransfer_time, :appconnect_time, + :pretransfer_time, :connect_time, :namelookup_time, :redirect_time, + :size_upload, :size_download, :speed_upload, :speed_upload, + :effective_url, :primary_ip, :redirect_count, :redirect_url, :debug_info + ].each do |name| + it "contains #{name}" do + expect(described_class::INFORMATIONS_TO_MIRROR).to include(name) + end + end + end + + describe "#to_hash" do + let(:options) { {:return_code => 1} } + + it "returns mirror as hash" do + expect(mirror.to_hash).to eq(options) + end + end + + describe "#log_informations" do + let(:options) { {:return_code => 1} } + + it "returns hash" do + expect(mirror.log_informations).to be_a(Hash) + end + + it "only calls methods that exist" do + described_class::INFORMATIONS_TO_LOG.each do |method_name| + expect(mirror.respond_to? method_name).to eql(true) + end + end + + it "includes return code" do + expect(mirror.log_informations).to include(options) + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/operations_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/operations_spec.rb new file mode 100644 index 00000000..a3ddc86b --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/operations_spec.rb @@ -0,0 +1,271 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Operations do + let(:easy) { Ethon::Easy.new } + + describe "#handle" do + it "returns a pointer" do + expect(easy.handle).to be_a(FFI::Pointer) + end + end + + + describe "#perform" do + let(:url) { nil } + let(:timeout) { nil } + let(:connect_timeout) { nil } + let(:follow_location) { nil } + let(:max_redirs) { nil } + let(:user_pwd) { nil } + let(:http_auth) { nil } + let(:headers) { nil } + let(:protocols) { nil } + let(:redir_protocols) { nil } + let(:username) { nil } + let(:password) { nil } + + before do + Ethon.logger.level = Logger::DEBUG + easy.url = url + easy.timeout = timeout + easy.connecttimeout = connect_timeout + easy.followlocation = follow_location + easy.maxredirs = max_redirs + easy.httpauth = http_auth + easy.headers = headers + easy.protocols = protocols + easy.redir_protocols = redir_protocols + + if user_pwd + easy.userpwd = user_pwd + else + easy.username = username + easy.password = password + end + + easy.perform + end + + it "calls Curl.easy_perform" do + expect(Ethon::Curl).to receive(:easy_perform) + easy.perform + end + + it "calls Curl.easy_cleanup" do + expect_any_instance_of(FFI::AutoPointer).to receive(:free) + easy.cleanup + end + + it "logs" do + expect(Ethon.logger).to receive(:debug) + easy.perform + end + + it "doesn't log after completing because completing could reset" do + easy.on_complete{ expect(Ethon.logger).to receive(:debug).never } + easy.perform + end + + context "when url" do + let(:url) { "http://localhost:3001/" } + + it "returns ok" do + expect(easy.return_code).to eq(:ok) + end + + it "sets response body" do + expect(easy.response_body).to be + end + + it "sets response headers" do + expect(easy.response_headers).to be + end + + context "when request timed out" do + let(:url) { "http://localhost:3001/?delay=1" } + let(:timeout) { 1 } + + it "returns operation_timedout" do + expect(easy.return_code).to eq(:operation_timedout) + end + end + + context "when connection timed out" do + let(:url) { "http://localhost:3009" } + let(:connect_timeout) { 1 } + + it "returns couldnt_connect" do + expect(easy.return_code).to eq(:couldnt_connect) + end + end + + context "when no follow location" do + let(:url) { "http://localhost:3001/redirect" } + let(:follow_location) { false } + + it "doesn't follow" do + expect(easy.response_code).to eq(302) + expect(easy.redirect_url).to eq("http://localhost:3001/") + end + end + + context "when follow location" do + let(:url) { "http://localhost:3001/redirect" } + let(:follow_location) { true } + + it "follows" do + expect(easy.response_code).to eq(200) + expect(easy.redirect_url).to eq(nil) + end + + context "when infinite redirect loop" do + let(:url) { "http://localhost:3001/bad_redirect" } + let(:max_redirs) { 5 } + + context "when max redirect set" do + it "follows only x times" do + expect(easy.response_code).to eq(302) + expect(easy.redirect_url).to eq("http://localhost:3001/bad_redirect") + end + end + end + end + + context "when user agent" do + let(:headers) { { 'User-Agent' => 'Ethon' } } + + it "sets" do + expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon"') + end + end + end + + context "when auth url" do + before { easy.url = url } + + context "when basic auth" do + let(:url) { "http://localhost:3001/auth_basic/username/password" } + + context "when no user_pwd" do + it "returns 401" do + expect(easy.response_code).to eq(401) + end + end + + context "when invalid user_pwd" do + let(:user_pwd) { "invalid:invalid" } + + it "returns 401" do + expect(easy.response_code).to eq(401) + end + end + + context "when valid user_pwd" do + let(:user_pwd) { "username:password" } + + it "returns 200" do + expect(easy.response_code).to eq(200) + end + end + + context "when user and password" do + let(:username) { "username" } + let(:password) { "password" } + + it "returns 200" do + expect(easy.response_code).to eq(200) + end + end + end + + context "when ntlm" do + let(:url) { "http://localhost:3001/auth_ntlm" } + let(:http_auth) { :ntlm } + + context "when no user_pwd" do + it "returns 401" do + expect(easy.response_code).to eq(401) + end + end + + context "when user_pwd" do + let(:user_pwd) { "username:password" } + + it "returns 200" do + expect(easy.response_code).to eq(200) + end + end + end + end + + context "when protocols" do + context "when asking for a allowed url" do + let(:url) { "http://localhost:3001" } + let(:protocols) { :http } + + it "returns ok" do + expect(easy.return_code).to be(:ok) + end + end + + context "when asking for a not allowed url" do + let(:url) { "http://localhost:3001" } + let(:protocols) { :https } + + it "returns unsupported_protocol" do + expect(easy.return_code).to be(:unsupported_protocol) + end + end + end + + context "when multiple protocols" do + context "when asking for a allowed url" do + let(:protocols) { [:http, :https] } + + context "when http" do + let(:url) { "http://localhost:3001" } + + it "returns ok for http" do + expect(easy.return_code).to be(:ok) + end + end + + context "when https" do + let(:url) { "https://localhost:3001" } + + it "returns ssl_connect_error for https" do + expect(easy.return_code).to be(:ssl_connect_error) + end + end + end + + context "when asking for a not allowed url" do + let(:url) { "ssh://localhost" } + let(:protocols) { [:https, :http] } + + it "returns unsupported_protocol" do + expect(easy.return_code).to be(:unsupported_protocol) + end + end + end + + context "when redir_protocols" do + context "when redirecting to a not allowed url" do + let(:url) { "http://localhost:3001/redirect" } + let(:follow_location) { true } + let(:redir_protocols) { :https } + + it "returns unsupported_protocol" do + expect(easy.return_code).to be(:unsupported_protocol) + end + end + end + + context "when no url" do + it "returns url_malformat" do + expect(easy.perform).to eq(:url_malformat) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/options_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/options_spec.rb new file mode 100644 index 00000000..e135bd99 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/options_spec.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Options do + let(:easy) { Ethon::Easy.new } + + [ + :accept_encoding, :cainfo, :capath, :connecttimeout, :connecttimeout_ms, :cookie, + :cookiejar, :cookiefile, :copypostfields, :customrequest, :dns_cache_timeout, + :followlocation, :forbid_reuse, :http_version, :httpauth, :httpget, :httppost, + :infilesize, :interface, :keypasswd, :maxredirs, :nobody, :nosignal, + :postfieldsize, :postredir, :protocols, :proxy, :proxyauth, :proxyport, :proxytype, + :proxyuserpwd, :readdata, :readfunction, :redir_protocols, :ssl_verifyhost, + :ssl_verifypeer, :sslcert, :sslcerttype, :sslkey, :sslkeytype, :sslversion, + :timeout, :timeout_ms, :unrestricted_auth, :upload, :url, :useragent, + :userpwd, :verbose, :pipewait, :dns_shuffle_addresses, :path_as_is + ].each do |name| + describe "#{name}=" do + it "responds_to" do + expect(easy).to respond_to("#{name}=") + end + + it "sets option" do + expect_any_instance_of(Ethon::Easy).to receive(:set_callbacks) + expect(Ethon::Curl).to receive(:set_option).with(name, anything, anything) + value = case name + when :http_version + :httpv1_0 + when :httpauth + :basic + when :protocols, :redir_protocols + :http + when :postredir + :post_301 + when :proxytype + :http + when :sslversion + :default + when :httppost + FFI::Pointer::NULL + else + 1 + end + easy.method("#{name}=").call(value) + end + end + end + + describe '#escape?' do + context 'by default' do + it 'returns true' do + expect(easy.escape?).to be_truthy + end + end + + context 'when #escape=nil' do + it 'returns true' do + easy.escape = nil + expect(easy.escape?).to be_truthy + end + end + + context 'when #escape=true' do + it 'returns true' do + easy.escape = true + expect(easy.escape?).to be_truthy + end + end + + context 'when #escape=false' do + it 'returns true' do + easy.escape = false + expect(easy.escape?).to be_falsey + end + end + end + + describe '#multipart?' do + context 'by default' do + it 'returns false' do + expect(easy.multipart?).to be_falsey + end + end + + context 'when #multipart=nil' do + it 'returns false' do + easy.multipart = nil + expect(easy.multipart?).to be_falsey + end + end + + context 'when #multipart=true' do + it 'returns true' do + easy.multipart = true + expect(easy.multipart?).to be_truthy + end + end + + context 'when #multipart=false' do + it 'returns false' do + easy.multipart = false + expect(easy.multipart?).to be_falsey + end + end + end + + describe "#httppost=" do + it "raises unless given a FFI::Pointer" do + expect{ easy.httppost = 1 }.to raise_error(Ethon::Errors::InvalidValue) + end + end + + context "when requesting" do + let(:url) { "localhost:3001" } + let(:timeout) { nil } + let(:timeout_ms) { nil } + let(:connecttimeout) { nil } + let(:connecttimeout_ms) { nil } + let(:userpwd) { nil } + + before do + easy.url = url + easy.timeout = timeout + easy.timeout_ms = timeout_ms + easy.connecttimeout = connecttimeout + easy.connecttimeout_ms = connecttimeout_ms + easy.userpwd = userpwd + easy.perform + end + + context "when userpwd" do + context "when contains /" do + let(:url) { "localhost:3001/auth_basic/test/te%2Fst" } + let(:userpwd) { "test:te/st" } + + it "works" do + expect(easy.response_code).to eq(200) + end + end + end + + context "when timeout" do + let(:timeout) { 1 } + + context "when request takes longer" do + let(:url) { "localhost:3001?delay=2" } + + it "times out" do + expect(easy.return_code).to eq(:operation_timedout) + end + end + end + + context "when connecttimeout" do + let(:connecttimeout) { 1 } + + context "when cannot connect" do + let(:url) { "localhost:3002" } + + it "times out" do + expect(easy.return_code).to eq(:couldnt_connect) + end + end + end + + if Ethon::Easy.supports_timeout_ms? + context "when timeout_ms" do + let(:timeout_ms) { 100 } + + context "when request takes longer" do + let(:url) { "localhost:3001?delay=1" } + + it "times out" do + expect(easy.return_code).to eq(:operation_timedout) + end + end + end + + context "when connecttimeout_ms" do + let(:connecttimeout_ms) { 100 } + + context "when cannot connect" do + let(:url) { "localhost:3002" } + + it "times out" do + # this can either lead to a timeout or couldnt connect depending on which happens first + expect([:couldnt_connect, :operation_timedout]).to include(easy.return_code) + end + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/queryable_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/queryable_spec.rb new file mode 100644 index 00000000..89c4d115 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/queryable_spec.rb @@ -0,0 +1,235 @@ +# encoding: utf-8 +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Queryable do + let(:hash) { {} } + let!(:easy) { Ethon::Easy.new } + let(:params) { Ethon::Easy::Params.new(easy, hash) } + + describe "#to_s" do + context "when query_pairs empty" do + before { params.instance_variable_set(:@query_pairs, []) } + + it "returns empty string" do + expect(params.to_s).to eq("") + end + end + + context "when query_pairs not empty" do + context "when escape" do + before do + params.escape = true + end + + { + '!' => '%21', '*' => '%2A', "'" => '%27', '(' => '%28', + ')' => '%29', ';' => '%3B', ':' => '%3A', '@' => '%40', + '&' => '%26', '=' => '%3D', '+' => '%2B', '$' => '%24', + ',' => '%2C', '/' => '%2F', '?' => '%3F', '#' => '%23', + '[' => '%5B', ']' => '%5D', + + '<' => '%3C', '>' => '%3E', '"' => '%22', '{' => '%7B', + '}' => '%7D', '|' => '%7C', '\\' => '%5C', '`' => '%60', + '^' => '%5E', '%' => '%25', ' ' => '%20', "\0" => '%00', + + 'まつもと' => '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8', + }.each do |value, percent| + it "turns #{value.inspect} into #{percent}" do + params.instance_variable_set(:@query_pairs, [[:a, value]]) + expect(params.to_s).to eq("a=#{percent}") + end + end + + { + '.' => '%2E', '-' => '%2D', '_' => '%5F', '~' => '%7E', + }.each do |value, percent| + it "leaves #{value.inspect} instead of turning into #{percent}" do + params.instance_variable_set(:@query_pairs, [[:a, value]]) + expect(params.to_s).to eq("a=#{value}") + end + end + end + + context "when no escape" do + before { params.instance_variable_set(:@query_pairs, [[:a, 1], [:b, 2]]) } + + it "returns concatenated query string" do + expect(params.to_s).to eq("a=1&b=2") + end + end + end + + context "when query_pairs contains a string" do + before { params.instance_variable_set(:@query_pairs, ["{a: 1}"]) } + + it "returns correct string" do + expect(params.to_s).to eq("{a: 1}") + end + end + end + + describe "#build_query_pairs" do + let(:pairs) { params.method(:build_query_pairs).call(hash) } + + context "when params is empty" do + it "returns empty array" do + expect(pairs).to eq([]) + end + end + + context "when params is string" do + let(:hash) { "{a: 1}" } + + it "wraps it in an array" do + expect(pairs).to eq([hash]) + end + end + + context "when params is simple hash" do + let(:hash) { {:a => 1, :b => 2} } + + it "transforms" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include([:b, 2]) + end + end + + context "when params is a nested hash" do + let(:hash) { {:a => 1, :b => {:c => 2}} } + + it "transforms" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include(["b[c]", 2]) + end + end + + context "when params contains an array" do + let(:hash) { {:a => 1, :b => [2, 3]} } + + context "by default" do + it "transforms" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include(["b[0]", 2]) + expect(pairs).to include(["b[1]", 3]) + end + end + + context "when params_encoding is :rack" do + before { params.params_encoding = :rack } + it "transforms without indexes" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include(["b[]", 2]) + expect(pairs).to include(["b[]", 3]) + end + end + + context "when params_encoding is :none" do + before { params.params_encoding = :none } + it "does no transformation" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include([:b, [2, 3]]) + end + end + end + + context "when params contains something nested in an array" do + context "when string" do + let(:hash) { {:a => {:b => ["hello", "world"]}} } + + it "transforms" do + expect(pairs).to eq([["a[b][0]", "hello"], ["a[b][1]", "world"]]) + end + end + + context "when hash" do + let(:hash) { {:a => {:b => [{:c =>1}, {:d => 2}]}} } + + it "transforms" do + expect(pairs).to eq([["a[b][0][c]", 1], ["a[b][1][d]", 2]]) + end + end + + context "when file" do + let(:file) { File.open("spec/spec_helper.rb") } + let(:file_info) { params.method(:file_info).call(file) } + let(:hash) { {:a => {:b => [file]}} } + let(:mime_type) { file_info[1] } + + it "transforms" do + expect(pairs).to eq([["a[b][0]", file_info]]) + end + + context "when MIME" do + if defined?(MIME) + context "when mime type" do + it "sets mime type to text" do + expect(mime_type).to eq("application/x-ruby") + end + end + end + + context "when no mime type" do + let(:file) { Tempfile.new("fubar") } + + it "sets mime type to default application/octet-stream" do + expect(mime_type).to eq("application/octet-stream") + end + end + end + + context "when no MIME" do + before { hide_const("MIME") } + + it "sets mime type to default application/octet-stream" do + expect(mime_type).to eq("application/octet-stream") + end + end + end + end + + + context "when params contains file" do + let(:file) { Tempfile.new("fubar") } + let(:file_info) { params.method(:file_info).call(file) } + let(:hash) { {:a => 1, :b => file} } + + it "transforms" do + expect(pairs).to include([:a, 1]) + expect(pairs).to include([:b, file_info]) + end + end + + context "when params key contains a null byte" do + let(:hash) { {:a => "1\0" } } + + it "preserves" do + expect(pairs).to eq([[:a, "1\0"]]) + end + end + + context "when params value contains a null byte" do + let(:hash) { {"a\0" => 1 } } + + it "preserves" do + expect(pairs).to eq([["a\0", 1]]) + end + end + end + + describe "#empty?" do + context "when params empty" do + it "returns true" do + expect(params.empty?).to be_truthy + end + end + + context "when params not empty" do + let(:hash) { {:a => 1} } + + it "returns false" do + expect(params.empty?).to be_falsey + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/response_callbacks_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/response_callbacks_spec.rb new file mode 100644 index 00000000..f142fad7 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/response_callbacks_spec.rb @@ -0,0 +1,152 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::ResponseCallbacks do + let(:easy) { Ethon::Easy.new } + + [:on_complete, :on_headers, :on_body, :on_progress].each do |callback_type| + describe "##{callback_type}" do + it "responds" do + expect(easy).to respond_to("#{callback_type}") + end + + context "when no block given" do + it "returns @#{callback_type}" do + expect(easy.send("#{callback_type}")).to eq([]) + end + end + + context "when block given" do + it "stores" do + easy.send(callback_type) { p 1 } + expect(easy.instance_variable_get("@#{callback_type}").size).to eq(1) + end + end + + context "when multiple blocks given" do + it "stores" do + easy.send(callback_type) { p 1 } + easy.send(callback_type) { p 2 } + expect(easy.instance_variable_get("@#{callback_type}").size).to eq(2) + end + end + end + end + + describe "#complete" do + before do + easy.on_complete {|r| String.new(r.url) } + end + + it "executes blocks and passes self" do + expect(String).to receive(:new).with(easy.url) + easy.complete + end + + context "when @on_complete nil" do + it "doesn't raise" do + easy.instance_variable_set(:@on_complete, nil) + expect{ easy.complete }.to_not raise_error + end + end + end + + describe "#headers" do + before do + easy.on_headers {|r| String.new(r.url) } + end + + it "executes blocks and passes self" do + expect(String).to receive(:new).with(easy.url) + easy.headers + end + + context "when @on_headers nil" do + it "doesn't raise" do + easy.instance_variable_set(:@on_headers, nil) + expect{ easy.headers }.to_not raise_error + end + end + end + + describe "#progress" do + context "when requesting for realz" do + it "executes callback" do + post = Ethon::Easy::Http::Post.new("http://localhost:3001", {:body => "bar=fu"}) + post.setup(easy) + @called = false + @has_dltotal = false + @has_ultotal = false + easy.on_progress { @called = true } + easy.on_progress { |dltotal, _, _, _| @has_dltotal ||= true } + easy.on_progress { |_, _, ultotal, _| @has_ultotal ||= true } + easy.perform + expect(@called).to be true + expect(@has_dltotal).to be true + expect(@has_ultotal).to be true + end + end + + context "when pretending" do + before do + @dltotal = nil + @dlnow = nil + @ultotal = nil + @ulnow = nil + easy.on_progress { |dltotal, dlnow, ultotal, ulnow| @dltotal = dltotal ; @dlnow = dlnow; @ultotal = ultotal; @ulnow = ulnow } + end + + it "executes blocks and passes dltotal" do + easy.progress(1, 2, 3, 4) + expect(@dltotal).to eq(1) + end + + it "executes blocks and passes dlnow" do + easy.progress(1, 2, 3, 4) + expect(@dlnow).to eq(2) + end + + it "executes blocks and passes ultotal" do + easy.progress(1, 2, 3, 4) + expect(@ultotal).to eq(3) + end + + it "executes blocks and passes ulnow" do + easy.progress(1, 2, 3, 4) + expect(@ulnow).to eq(4) + end + + context "when @on_progress nil" do + it "doesn't raise" do + easy.instance_variable_set(:@on_progress, nil) + expect{ easy.progress(1, 2, 3, 4) }.to_not raise_error + end + end + end + end + + describe "#body" do + before do + @chunk = nil + @r = nil + easy.on_body { |chunk, r| @chunk = chunk ; @r = r } + end + + it "executes blocks and passes self" do + easy.body("the chunk") + expect(@r).to be(easy) + end + + it "executes blocks and passes chunk" do + easy.body("the chunk") + expect(@chunk).to eq("the chunk") + end + + context "when @on_body nil" do + it "doesn't raise" do + easy.instance_variable_set(:@on_body, nil) + expect{ easy.body("the chunk") }.to_not raise_error + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy/util_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy/util_spec.rb new file mode 100644 index 00000000..048c5bdf --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy/util_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy::Util do + class Dummy + include Ethon::Easy::Util + end + + let(:klass) { Dummy.new } + + describe "escape_zero_byte" do + context "when value has no zero byte" do + let(:value) { "hello world" } + + it "returns same value" do + expect(klass.escape_zero_byte(value)).to be(value) + end + end + + context "when value has zero byte" do + let(:value) { "hello \0world" } + + it "returns escaped" do + expect(klass.escape_zero_byte(value)).to eq("hello \\0world") + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/easy_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/easy_spec.rb new file mode 100644 index 00000000..c0e95655 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/easy_spec.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Easy do + let(:easy) { Ethon::Easy.new } + + describe ".new" do + it "inits curl" do + expect(Ethon::Curl).to receive(:init) + easy + end + + context "when options are empty" do + it "sets only callbacks" do + expect_any_instance_of(Ethon::Easy).to receive(:set_callbacks) + expect(Ethon::Easy).to receive(:set_option).never + easy + end + end + + context "when options not empty" do + context "when followlocation is set" do + let(:options) { { :followlocation => true } } + let(:easy) { Ethon::Easy.new(options) } + + it "sets followlocation" do + expect_any_instance_of(Ethon::Easy).to receive(:set_callbacks) + expect(Ethon::Curl).to receive(:set_option).with(:followlocation, true, anything) + easy + end + end + end + end + + describe "#set_attributes" do + context "when options are empty" do + it "sets only callbacks" do + expect_any_instance_of(Ethon::Easy).to receive(:set_callbacks) + expect(Ethon::Easy).to receive(:set_option).never + easy + end + end + + context "when options aren't empty" do + context "when valid key" do + it "sets" do + expect(easy).to receive(:verbose=).with(true) + easy.set_attributes({:verbose => true}) + end + end + + context "when invalid key" do + it "raises invalid option error" do + expect{ easy.set_attributes({:fubar => 1}) }.to raise_error(Ethon::Errors::InvalidOption) + end + end + end + end + + describe "#reset" do + before { easy.url = "www.example.com" } + + it "resets url" do + easy.reset + expect(easy.url).to be_nil + end + + it "resets escape?" do + easy.escape = false + easy.reset + expect(easy.escape?).to be_truthy + end + + it "resets hash" do + easy.reset + expect(easy.instance_variable_get(:@hash)).to be_nil + end + + it "resets easy handle" do + expect(Ethon::Curl).to receive(:easy_reset) + easy.reset + end + + it "resets on_complete" do + easy.on_complete { p 1 } + easy.reset + expect(easy.on_complete).to be_empty + end + + it "resets on_headers" do + easy.on_headers { p 1 } + easy.reset + expect(easy.on_headers).to be_empty + end + + it "resets on_body" do + easy.on_body { p 1 } + easy.reset + expect(easy.on_body).to be_empty + end + end + + describe "#dup" do + let!(:easy) do + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/" + easy.on_complete { 'on_complete' } + easy.on_headers { 'on_headers' } + easy.on_progress { 'on_progress' } + easy.response_body = String.new('test_body') + easy.response_headers = String.new('test_headers') + easy + end + let!(:e) { easy.dup } + + it "sets a new handle" do + expect(e.handle).not_to eq(easy.handle) + end + + it "preserves url" do + expect(e.url).to eq(easy.url) + end + + it "preserves on_complete callback" do + expect(e.on_complete).to be(easy.on_complete) + end + + it "preserves on_headers callback" do + expect(e.on_headers).to be(easy.on_headers) + end + + it 'preserves body_write_callback of original handle' do + expect { easy.perform }.to change { easy.response_body } + expect { easy.perform }.not_to change { e.response_body } + end + + it "preserves on_progress callback" do + expect(e.on_progress).to be(easy.on_progress) + end + + it 'sets new body_write_callback of duplicated handle' do + expect { e.perform }.to change { e.response_body } + expect { e.perform }.not_to change { easy.response_body } + end + + it 'preserves headers_write_callback of original handle' do + expect { easy.perform }.to change { easy.response_headers } + expect { easy.perform }.not_to change { e.response_headers } + end + + it 'sets new headers_write_callback of duplicated handle' do + expect { e.perform }.to change { e.response_headers } + expect { e.perform }.not_to change { easy.response_headers } + end + + it "resets response_body" do + expect(e.response_body).to be_empty + end + + it "resets response_headers" do + expect(e.response_headers).to be_empty + end + + it "sets response_body for duplicated Easy" do + e.perform + expect(e.response_body).not_to be_empty + end + + it "sets response_headers for duplicated Easy" do + e.perform + expect(e.response_headers).not_to be_empty + end + + it "preserves response_body for original Easy" do + e.perform + expect(easy.response_body).to eq('test_body') + end + + it "preserves response_headers for original Easy" do + e.perform + expect(easy.response_headers).to eq('test_headers') + end + end + + describe "#mirror" do + it "returns a Mirror" do + expect(easy.mirror).to be_a(Ethon::Easy::Mirror) + end + + it "builds from easy" do + expect(Ethon::Easy::Mirror).to receive(:from_easy).with(easy) + easy.mirror + end + end + + describe "#log_inspect" do + [ :url, :response_code, :return_code, :total_time ].each do |name| + it "contains #{name}" do + expect(easy.log_inspect).to match name.to_s + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/libc_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/libc_spec.rb new file mode 100644 index 00000000..a323151e --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/libc_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Libc do + describe "#getdtablesize", :if => !Ethon::Curl.windows? do + it "returns an integer" do + expect(Ethon::Libc.getdtablesize).to be_a(Integer) + end + + it "returns bigger zero", :if => !Ethon::Curl.windows? do + expect(Ethon::Libc.getdtablesize).to_not be_zero + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/loggable_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/loggable_spec.rb new file mode 100644 index 00000000..117cba3b --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/loggable_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +require "spec_helper" + +describe Ethon::Loggable do + + describe "#logger=" do + + let(:logger) do + Logger.new($stdout).tap do |log| + log.level = Logger::INFO + end + end + + before do + Ethon.logger = logger + end + + it "sets the logger" do + expect(Ethon.logger).to eq(logger) + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/multi/operations_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/multi/operations_spec.rb new file mode 100644 index 00000000..781b62aa --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/multi/operations_spec.rb @@ -0,0 +1,298 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Multi::Operations do + let(:multi) { Ethon::Multi.new } + let(:easy) { Ethon::Easy.new } + let(:pointer) { FFI::MemoryPointer.new(:int) } + + describe "#handle" do + it "returns a pointer" do + expect(multi.handle).to be_a(FFI::Pointer) + end + end + + describe "#running_count" do + context "when hydra has no easy" do + it "returns nil" do + expect(multi.send(:running_count)).to be_nil + end + end + + context "when hydra has easy" do + before do + easy.url = "http://localhost:3001/" + multi.add(easy) + multi.send(:trigger, pointer) + end + + it "returns 1" do + expect(multi.send(:running_count)).to eq(1) + end + end + + context "when hydra has more easys" do + let(:another_easy) { Ethon::Easy.new } + + before do + easy.url = "http://localhost:3001/" + another_easy.url = "http://localhost:3001/" + multi.add(easy) + multi.add(another_easy) + multi.send(:trigger, pointer) + end + + it "returns 2" do + expect(multi.send(:running_count)).to eq(2) + end + end + end + + describe "#get_timeout" do + context "when code ok" do + let(:timeout) { 1 } + + before do + expect(Ethon::Curl).to receive(:multi_timeout).and_return(:ok) + multi.instance_variable_set(:@timeout, double(:read_long => timeout)) + end + + it "doesn't raise" do + expect{ multi.send(:get_timeout) }.to_not raise_error + end + + context "when timeout smaller zero" do + let(:timeout) { -1 } + + it "returns 1" do + expect(multi.send(:get_timeout)).to eq(1) + end + end + + context "when timeout bigger or equal zero" do + let(:timeout) { 2 } + + it "returns timeout" do + expect(multi.send(:get_timeout)).to eq(timeout) + end + end + end + + context "when code not ok" do + before { expect(Ethon::Curl).to receive(:multi_timeout).and_return(:not_ok) } + + it "raises MultiTimeout error" do + expect{ multi.send(:get_timeout) }.to raise_error(Ethon::Errors::MultiTimeout) + end + end + end + + describe "#set_fds" do + let(:timeout) { 1 } + let(:max_fd) { 1 } + + context "when code ok" do + before { expect(Ethon::Curl).to receive(:multi_fdset).and_return(:ok) } + + it "doesn't raise" do + expect{ multi.method(:set_fds).call(timeout) }.to_not raise_error + end + + context "when max_fd -1" do + let(:max_fd) { -1 } + + before do + multi.instance_variable_set(:@max_fd, double(:read_int => max_fd)) + expect(multi).to receive(:sleep).with(0.001) + end + + it "waits 100ms" do + multi.method(:set_fds).call(timeout) + end + end + + context "when max_fd not -1" do + context "when code smaller zero" do + before { expect(Ethon::Curl).to receive(:select).and_return(-1) } + + it "raises Select error" do + expect{ multi.method(:set_fds).call(timeout) }.to raise_error(Ethon::Errors::Select) + end + end + + context "when code bigger or equal zero" do + before { expect(Ethon::Curl).to receive(:select).and_return(0) } + + it "doesn't raise" do + expect{ multi.method(:set_fds).call(timeout) }.to_not raise_error + end + end + end + end + + context "when code not ok" do + before { expect(Ethon::Curl).to receive(:multi_fdset).and_return(:not_ok) } + + it "raises MultiFdset error" do + expect{ multi.method(:set_fds).call(timeout) }.to raise_error(Ethon::Errors::MultiFdset) + end + end + end + + describe "#perform" do + context "when no easy handles" do + it "returns nil" do + expect(multi.perform).to be_nil + end + + it "logs" do + expect(Ethon.logger).to receive(:debug).twice + multi.perform + end + end + + context "when easy handle" do + before do + easy.url = "http://localhost:3001/" + multi.add(easy) + end + + it "requests" do + multi.perform + end + + it "sets easy" do + multi.perform + expect(easy.response_code).to eq(200) + end + end + + context "when four easy handles" do + let(:easies) do + ary = [] + 4.times do + ary << another_easy = Ethon::Easy.new + another_easy.url = "http://localhost:3001/" + end + ary + end + + before do + easies.each { |e| multi.add(e) } + multi.perform + end + + it "sets response codes" do + expect(easies.all?{ |e| e.response_code == 200 }).to be_truthy + end + end + end + + describe "#ongoing?" do + context "when easy_handles" do + before { multi.easy_handles << 1 } + + context "when running_count not greater 0" do + before { multi.instance_variable_set(:@running_count, 0) } + + it "returns true" do + expect(multi.method(:ongoing?).call).to be_truthy + end + end + + context "when running_count greater 0" do + before { multi.instance_variable_set(:@running_count, 1) } + + it "returns true" do + expect(multi.method(:ongoing?).call).to be_truthy + end + end + end + + context "when no easy_handles" do + context "when running_count not greater 0" do + before { multi.instance_variable_set(:@running_count, 0) } + + it "returns false" do + expect(multi.method(:ongoing?).call).to be_falsey + end + end + + context "when running_count greater 0" do + before { multi.instance_variable_set(:@running_count, 1) } + + it "returns true" do + expect(multi.method(:ongoing?).call).to be_truthy + end + end + end + end + + describe "#init_vars" do + it "sets @timeout" do + expect(multi.instance_variable_get(:@timeout)).to be_a(FFI::MemoryPointer) + end + + it "sets @timeval" do + expect(multi.instance_variable_get(:@timeval)).to be_a(Ethon::Curl::Timeval) + end + + it "sets @fd_read" do + expect(multi.instance_variable_get(:@fd_read)).to be_a(Ethon::Curl::FDSet) + end + + it "sets @fd_write" do + expect(multi.instance_variable_get(:@fd_write)).to be_a(Ethon::Curl::FDSet) + end + + it "sets @fd_excep" do + expect(multi.instance_variable_get(:@fd_excep)).to be_a(Ethon::Curl::FDSet) + end + + it "sets @max_fd" do + expect(multi.instance_variable_get(:@max_fd)).to be_a(FFI::MemoryPointer) + end + end + + describe "#reset_fds" do + after { multi.method(:reset_fds).call } + + it "resets @fd_read" do + expect(multi.instance_variable_get(:@fd_read)).to receive(:clear) + end + + it "resets @fd_write" do + expect(multi.instance_variable_get(:@fd_write)).to receive(:clear) + end + + it "resets @fd_excep" do + expect(multi.instance_variable_get(:@fd_excep)).to receive(:clear) + end + end + + describe "#check" do + it { skip("untested") } + end + + describe "#run" do + it { skip("untested") } + end + + describe "#trigger" do + it "calls multi perform" do + expect(Ethon::Curl).to receive(:multi_perform) + multi.send(:trigger, pointer) + end + + it "sets running count" do + multi.instance_variable_set(:@running_count, nil) + multi.send(:trigger, pointer) + expect(multi.instance_variable_get(:@running_count)).to_not be_nil + end + + it "returns multi perform code" do + expect(Ethon::Curl).to receive(:multi_perform).and_return(:ok) + expect(multi.send(:trigger, pointer)).to eq(:ok) + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/multi/options_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/multi/options_spec.rb new file mode 100644 index 00000000..b4832c68 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/multi/options_spec.rb @@ -0,0 +1,182 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Multi::Options do + let(:multi) { Ethon::Multi.new } + + [ + :maxconnects, :pipelining, :socketdata, :socketfunction, + :timerdata, :timerfunction, :max_total_connections + ].each do |name| + describe "#{name}=" do + it "responds_to" do + expect(multi).to respond_to("#{name}=") + end + + it "sets option" do + expect(Ethon::Curl).to receive(:set_option).with(name, anything, anything, anything) + multi.method("#{name}=").call(1) + end + end + end + + context "socket_action mode" do + let(:multi) { Ethon::Multi.new(execution_mode: :socket_action) } + + describe "#socketfunction callbacks" do + it "allows multi_code return values" do + calls = [] + multi.socketfunction = proc do |handle, sock, what, userp, socketp| + calls << what + :ok + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + expect(calls).to eq([]) + 5.times do + multi.socket_action + break unless calls.empty? + sleep 0.1 + end + expect(calls.last).to eq(:in).or(eq(:out)) + multi.delete(easy) + expect(calls.last).to eq(:remove) + end + + it "allows integer return values (compatibility)" do + called = false + multi.socketfunction = proc do |handle, sock, what, userp, socketp| + called = true + 0 + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + 5.times do + multi.socket_action + break if called + sleep 0.1 + end + multi.delete(easy) + + expect(called).to be_truthy + end + + it "errors on invalid return codes" do + called = false + multi.socketfunction = proc do |handle, sock, what, userp, socketp| + called = true + "hi" + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + expect { + 5.times do + multi.socket_action + break if called + sleep 0.1 + end + }.to raise_error(ArgumentError) + expect { multi.delete(easy) }.to raise_error(ArgumentError) + end + end + + describe "#timerfunction callbacks" do + it "allows multi_code return values" do + calls = [] + multi.timerfunction = proc do |handle, timeout_ms, userp| + calls << timeout_ms + :ok + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + expect(calls.last).to be >= 0 # adds an immediate timeout + + multi.delete(easy) + expect(calls.last).to eq(-1) # cancels the timer + end + + it "allows integer return values (compatibility)" do + called = false + multi.timerfunction = proc do |handle, timeout_ms, userp| + called = true + 0 + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + multi.socket_action + multi.delete(easy) + + expect(called).to be_truthy + end + + it "errors on invalid return codes" do + called = false + multi.timerfunction = proc do |handle, timeout_ms, userp| + called = true + "hi" + end + + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + expect { multi.add(easy) }.to raise_error(ArgumentError) + end + end + end + + describe "#value_for" do + context "when option in bool" do + context "when value true" do + let(:value) { true } + + it "returns 1" do + expect(multi.method(:value_for).call(value, :bool)).to eq(1) + end + end + + context "when value false" do + let(:value) { false } + + it "returns 0" do + expect(multi.method(:value_for).call(value, :bool)).to eq(0) + end + end + end + + + context "when value in int" do + let(:value) { "2" } + + it "returns value casted to int" do + expect(multi.method(:value_for).call(value, :int)).to eq(2) + end + end + + context "when value in unspecific_options" do + context "when value a string" do + let(:value) { "www.example.\0com" } + + it "returns zero byte escaped string" do + expect(multi.method(:value_for).call(value, nil)).to eq("www.example.\\0com") + end + end + + context "when value not a string" do + let(:value) { 1 } + + it "returns value" do + expect(multi.method(:value_for).call(value, nil)).to eq(1) + end + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/multi/stack_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/multi/stack_spec.rb new file mode 100644 index 00000000..5eb5900c --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/multi/stack_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Multi::Stack do + let(:multi) { Ethon::Multi.new } + let(:easy) { Ethon::Easy.new } + + describe "#add" do + context "when easy already added" do + before { multi.add(easy) } + + it "returns nil" do + expect(multi.add(easy)).to be_nil + end + end + + context "when easy new" do + it "adds easy to multi" do + expect(Ethon::Curl).to receive(:multi_add_handle).and_return(:ok) + multi.add(easy) + end + + it "adds easy to easy_handles" do + multi.add(easy) + expect(multi.easy_handles).to include(easy) + end + end + + context "when multi_add_handle fails" do + it "raises multi add error" do + expect(Ethon::Curl).to receive(:multi_add_handle).and_return(:bad_easy_handle) + expect{ multi.add(easy) }.to raise_error(Ethon::Errors::MultiAdd) + end + end + + context "when multi cleaned up before" do + it "raises multi add error" do + Ethon::Curl.multi_cleanup(multi.handle) + expect{ multi.add(easy) }.to raise_error(Ethon::Errors::MultiAdd) + end + end + end + + describe "#delete" do + context "when easy in easy_handles" do + before { multi.add(easy) } + + it "deletes easy from multi" do + expect(Ethon::Curl).to receive(:multi_remove_handle).and_return(:ok) + multi.delete(easy) + end + + it "deletes easy from easy_handles" do + multi.delete(easy) + expect(multi.easy_handles).to_not include(easy) + end + end + + context "when easy is not in easy_handles" do + it "does nothing" do + expect(Ethon::Curl).to receive(:multi_add_handle).and_return(:ok) + multi.add(easy) + end + + it "adds easy to easy_handles" do + multi.add(easy) + expect(multi.easy_handles).to include(easy) + end + end + + context "when multi_remove_handle fails" do + before { multi.add(easy) } + + it "raises multi remove error" do + expect(Ethon::Curl).to receive(:multi_remove_handle).and_return(:bad_easy_handle) + expect{ multi.delete(easy) }.to raise_error(Ethon::Errors::MultiRemove) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/ethon/multi_spec.rb b/bin/gems/ethon-0.16.0/spec/ethon/multi_spec.rb new file mode 100644 index 00000000..a483357c --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/ethon/multi_spec.rb @@ -0,0 +1,152 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ethon::Multi do + describe ".new" do + it "inits curl" do + expect(Ethon::Curl).to receive(:init) + Ethon::Multi.new + end + + context "with default options" do + it "allows running #perform with the default execution_mode" do + Ethon::Multi.new.perform + end + + it "refuses to run #socket_action" do + expect { Ethon::Multi.new.socket_action }.to raise_error(ArgumentError) + end + end + + context "when options not empty" do + context "when pipelining is set" do + let(:options) { { :pipelining => true } } + + it "sets pipelining" do + expect_any_instance_of(Ethon::Multi).to receive(:pipelining=).with(true) + Ethon::Multi.new(options) + end + end + + context "when execution_mode option is :socket_action" do + let(:options) { { :execution_mode => :socket_action } } + let(:multi) { Ethon::Multi.new(options) } + + it "refuses to run #perform" do + expect { multi.perform }.to raise_error(ArgumentError) + end + + it "allows running #socket_action" do + multi.socket_action + end + end + end + end + + describe "#socket_action" do + let(:options) { { :execution_mode => :socket_action } } + let(:select_state) { { :readers => [], :writers => [], :timeout => 0 } } + let(:multi) { + multi = Ethon::Multi.new(options) + multi.timerfunction = proc do |handle, timeout_ms, userp| + timeout_ms = nil if timeout_ms == -1 + select_state[:timeout] = timeout_ms + :ok + end + multi.socketfunction = proc do |handle, sock, what, userp, socketp| + case what + when :remove + select_state[:readers].delete(sock) + select_state[:writers].delete(sock) + when :in + select_state[:readers].push(sock) unless select_state[:readers].include? sock + select_state[:writers].delete(sock) + when :out + select_state[:readers].delete(sock) + select_state[:writers].push(sock) unless select_state[:writers].include? sock + when :inout + select_state[:readers].push(sock) unless select_state[:readers].include? sock + select_state[:writers].push(sock) unless select_state[:writers].include? sock + else + raise ArgumentError, "invalid value for 'what' in socketfunction callback" + end + :ok + end + multi + } + + def fds_to_ios(fds) + fds.map do |fd| + IO.for_fd(fd).tap { |io| io.autoclose = false } + end + end + + def perform_socket_action_until_complete + multi.socket_action # start things off + + while multi.ongoing? + readers, writers, _ = IO.select( + fds_to_ios(select_state[:readers]), + fds_to_ios(select_state[:writers]), + [], + select_state[:timeout] + ) + + to_notify = Hash.new { |hash, key| hash[key] = [] } + unless readers.nil? + readers.each do |reader| + to_notify[reader] << :in + end + end + unless writers.nil? + writers.each do |writer| + to_notify[writer] << :out + end + end + + to_notify.each do |io, readiness| + multi.socket_action(io, readiness) + end + + # if we didn't have anything to notify, then we timed out + multi.socket_action if to_notify.empty? + end + ensure + multi.easy_handles.dup.each do |h| + multi.delete(h) + end + end + + it "supports an end-to-end request" do + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/" + multi.add(easy) + + perform_socket_action_until_complete + + expect(multi.ongoing?).to eq(false) + end + + it "supports multiple concurrent requests" do + handles = [] + 10.times do + easy = Ethon::Easy.new + easy.url = "http://localhost:3001/?delay=1" + multi.add(easy) + handles << easy + end + + start = Time.now + perform_socket_action_until_complete + duration = Time.now - start + + # these should have happened concurrently + expect(duration).to be < 2 + expect(multi.ongoing?).to eq(false) + + handles.each do |handle| + expect(handle.response_code).to eq(200) + end + end + end +end diff --git a/bin/gems/ethon-0.16.0/spec/spec_helper.rb b/bin/gems/ethon-0.16.0/spec/spec_helper.rb new file mode 100644 index 00000000..55bc9ecb --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/spec_helper.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +$LOAD_PATH.unshift(File.dirname(__FILE__)) +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib")) + +require 'bundler' +Bundler.setup +require "ethon" +require 'rspec' + +if defined? require_relative + require_relative 'support/localhost_server' + require_relative 'support/server' +else + require 'support/localhost_server' + require 'support/server' +end + +# Ethon.logger = Logger.new($stdout).tap do |log| +# log.level = Logger::DEBUG +# end + +RSpec.configure do |config| + # config.order = :rand + + config.before(:suite) do + LocalhostServer.new(TESTSERVER.new, 3001) + end +end diff --git a/bin/gems/ethon-0.16.0/spec/support/localhost_server.rb b/bin/gems/ethon-0.16.0/spec/support/localhost_server.rb new file mode 100644 index 00000000..a7b119a2 --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/support/localhost_server.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true +require 'rack' +require 'rack/handler/webrick' +require 'net/http' + +# The code for this is inspired by Capybara's server: +# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb +class LocalhostServer + READY_MESSAGE = "Server ready" + + class Identify + def initialize(app) + @app = app + end + + def call(env) + if env["PATH_INFO"] == "/__identify__" + [200, {}, [LocalhostServer::READY_MESSAGE]] + else + @app.call(env) + end + end + end + + attr_reader :port + + def initialize(rack_app, port = nil) + @port = port || find_available_port + @rack_app = rack_app + concurrently { boot } + wait_until(10, "Boot failed.") { booted? } + end + + private + + def find_available_port + server = TCPServer.new('127.0.0.1', 0) + server.addr[1] + ensure + server.close if server + end + + def boot + # Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters. + options = { :Port => port } + options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER'] + Rack::Handler::WEBrick.run(Identify.new(@rack_app), **options) + end + + def booted? + res = ::Net::HTTP.get_response("localhost", '/__identify__', port) + if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection) + return res.body == READY_MESSAGE + end + rescue Errno::ECONNREFUSED, Errno::EBADF + return false + end + + def concurrently + if should_use_subprocess? + pid = Process.fork do + trap(:INT) { ::Rack::Handler::WEBrick.shutdown } + yield + exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet. + end + + at_exit do + Process.kill('INT', pid) + begin + Process.wait(pid) + rescue Errno::ECHILD + # ignore this error...I think it means the child process has already exited. + end + end + else + Thread.new { yield } + end + end + + def should_use_subprocess? + # !ENV['THREADED'] + false + end + + def wait_until(timeout, error_message, &block) + start_time = Time.now + + while true + return if yield + raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout + sleep(0.05) + end + end +end + diff --git a/bin/gems/ethon-0.16.0/spec/support/server.rb b/bin/gems/ethon-0.16.0/spec/support/server.rb new file mode 100644 index 00000000..ab8ffd3f --- /dev/null +++ b/bin/gems/ethon-0.16.0/spec/support/server.rb @@ -0,0 +1,115 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true +require 'json' +require 'zlib' +require 'sinatra/base' + +TESTSERVER = Sinatra.new do + set :logging, nil + + fail_count = 0 + + post '/file' do + { + 'content-type' => params[:file][:type], + 'filename' => params[:file][:filename], + 'content' => params[:file][:tempfile].read, + 'request-content-type' => request.env['CONTENT_TYPE'] + }.to_json + end + + get '/multiple-headers' do + [200, { 'Set-Cookie' => %w[ foo bar ], 'Content-Type' => 'text/plain' }, ['']] + end + + get '/fail/:number' do + if fail_count >= params[:number].to_i + "ok" + else + fail_count += 1 + error 500, "oh noes!" + end + end + + get '/fail_forever' do + error 500, "oh noes!" + end + + get '/redirect' do + redirect '/' + end + + post '/redirect' do + redirect '/' + end + + get '/bad_redirect' do + redirect '/bad_redirect' + end + + get '/auth_basic/:username/:password' do + @auth ||= Rack::Auth::Basic::Request.new(request.env) + # Check that we've got a basic auth, and that it's credentials match the ones + # provided in the request + if @auth.provided? && @auth.basic? && @auth.credentials == [ params[:username], params[:password] ] + # auth is valid - confirm it + true + else + # invalid auth - request the authentication + response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") + throw(:halt, [401, "Not authorized\n"]) + end + end + + get '/auth_ntlm' do + # we're just checking for the existence if NTLM auth header here. It's validation + # is too troublesome and really doesn't bother is much, it's up to libcurl to make + # it valid + response['WWW-Authenticate'] = 'NTLM' + is_ntlm_auth = /^NTLM/ =~ request.env['HTTP_AUTHORIZATION'] + true if is_ntlm_auth + throw(:halt, [401, "Not authorized\n"]) if !is_ntlm_auth + end + + get '/gzipped' do + req_env = request.env.to_json + z = Zlib::Deflate.new + gzipped_env = z.deflate(req_env, Zlib::FINISH) + z.close + response['Content-Encoding'] = 'gzip' + gzipped_env + end + + get '/**' do + sleep params["delay"].to_i if params.has_key?("delay") + request.env.merge!(:body => request.body.read).to_json + end + + head '/**' do + sleep params["delay"].to_i if params.has_key?("delay") + end + + put '/**' do + request.env.merge!(:body => request.body.read).to_json + end + + post '/**' do + request.env.merge!(:body => request.body.read).to_json + end + + delete '/**' do + request.env.merge!(:body => request.body.read).to_json + end + + patch '/**' do + request.env.merge!(:body => request.body.read).to_json + end + + options '/**' do + request.env.merge!(:body => request.body.read).to_json + end + + route 'PURGE', '/**' do + request.env.merge!(:body => request.body.read).to_json + end +end diff --git a/bin/gems/eventmachine-1.2.7/CHANGELOG.md b/bin/gems/eventmachine-1.2.7/CHANGELOG.md new file mode 100644 index 00000000..cd42c39f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/CHANGELOG.md @@ -0,0 +1,179 @@ +# Changelog + +## 1.2.7 (May 12, 2018) +* Fix segfault on large numbers of connections [#843] + +## 1.2.6 (April 30, 2018) +* *Fix segfault when an Exception is raised from unbind callback (for real this time!)* +* Fix race condition while initializing the machine [#756] +* Fix for newer compilers where bind() and std::bind() conflict [#830, #831] +* Be verbose about SSL connection errors [#807] +* Avoid explicitly calling class methods when in class scope +* Java: Add EM_PROTO_SSL/TLS definitions [#773, #791] +* Java: return zero when sending data to a closed connection [#475, #804] +* Pure Ruby: Connection::error? calls report_connection_error_status [#801] + +## 1.2.5 (July 27, 2017) +* Java: Use long for larger values in oneshot timer intervals [#784, #794] + +## 1.2.4 (July 27, 2017) +* Java: Add EM_PROTO_SSL/TLS definitions [#773, #791] +* Fix IPv6 UDP get_peername [#788] +* Allow for larger values in oneshot timer intervals [#784, #793] +* Update extconf.rb to allow MinGW builds with OpenSSL 1.1.0 [#785] + +## 1.2.3 (February 22, 2017) +* Pure Ruby: Add get_sockname [#308, #772] +* Fix segfault when an Exception is raised from unbind callback [#765, #766] +* Allow destructors to throw when compiling in >= C++11 [#767] + +## 1.2.2 (January 23, 2017) +* Java: Fix Fixnum deprecated warning in Ruby 2.4+ [#759] +* Fix uncaught C++ exception in file watcher and raise InvalidSignature [#512, #757] +* Fix connection count off-by-one for epoll and kqueue [#750] +* Fix uninitialized variable warning in EM::P::HttpClient [#749] +* Fix missing initial value for EventableDescriptor NextHeartbeat [#748] +* Fix hostname resolution on Solaris, Ilumos, SmartOS, et al [#745, #746] +* Improve reliability of tests, reduce public Internet accesses in tests [#656, #666, #749] + +## 1.2.1 (November 15, 2016) +* Throw strerror(errno) when getsockname or getpeername fail [#683] +* Use a single concrete implementation of getpeername/getsockname, the rest pure virtuals [#683] +* Use gai_strerror to get the failure string from getaddrinfo [#744] +* Fix deregistering descriptor when using KQUEUE [#728] +* Fix to enable to work an example code in EM::Pool [#731] +* LineText2: Add regular expression delimiter support [#706] +* Pure Ruby: EM rescue ECONNREFUSED on initial TCP connect [#741] +* Pure Ruby: EM SSL (working start_tls) [#712] +* Pure Ruby: EM fixes [#707] +* Java: Use Acceptors to get peer and sock names if not present in Connections [#743] + +## 1.2.0.1 (March 15, 2016) +* Fix crash when accepting IPv6 connections due to struct sockaddr_in [#698, #699] + +## 1.2.0 (March 15, 2016) +* Integrate work from the EventMachine-LE 1.1.x versions [#570] +* Add start_tls options :ecdh_curve, :dhparam, :fail_if_no_peer_cert [#195, #275, #399, #665] +* Add start_tls option :ssl_version for choosing SSL/TLS versions and ciphers [#359, #348, #603, #654] +* Add start_tls option :sni_hostname to be passed to TLS params [#593] +* Add method EM::Channel#num_subscribers to get the number of subscribers to a channel [#640] +* Add support for proc-sources in EM::Iterator [#639] +* Factor out method cleanup_machine to cleanup code from EM.run [#650] +* Replace Exception class with StandardError [#637] +* Close socket on close_connection even after close_connection_after_writing [#694] +* Allow reusing of datagram socket/setting bind device [#662] +* Handle deferred exceptions in reactor thread [#486] +* Reimplement Queue to avoid shift/push performance problem [#311] +* Windows: Switch from gethostbyname to getaddrinfo, support IPv6 addresses [#303, #630] +* Windows: Use rake-compiler-dock to cross-compile gems [#627] +* Windows: Add AppVeyor configuration for Windows CI testing [#578] +* Windows: Bump rake-compiler to version 0.9.x [#542] +* Fix compilation on AIX (w/ XLC) [#693] +* Fix build on OpenBSD [#690] +* Fix OpenSSL compile issue on AIX 7.1 [#678] +* Fix EventMachine.fork_reactor keeps the threadpool of the original process [#425] +* Fix to prevent event machine from stopping when a raise is done in an unbind [#327] + +## 1.0.9.1 (January 14, 2016) +* Fix EPROTO not defined on Windows [#676] +* Fix missing cast to struct sockaddr * [#671] +* Fix bug in OpenSSL path detection [#675] + +## 1.0.9 (January 13, 2016) +* Try more ways to detect OpenSSL [#602, #643, #661, #663, #668, #669] +* Use WSAGetLastError in pipe.cpp same as ed.cpp [#659] +* Test compiler flags with the C++ compiler and add them to CXXFLAGS [#634, #651] +* Restore silent-fail on unsupported EM.epoll and EM.kqueue [#638, #649] +* getDescriptorByFileno deprecated in JRuby 1.7.x, removed in JRuby 9000 [#642, #648] +* Add -Wno-address always-true because on Windows rb_fd_select [#578] +* Remove the WITHOUT_SSL constant [#578] +* Fix SSL error when the server replies a TLS Alert to our ClientHello [#544, #653] +* Use WSAStringToAddress in lieu of inet_pton for IPv6 address detection on Windows [#595, #632] +* Fix nasty TCP/IPv6 bug [#595, #632] +* Use select_large_fdset on Solaris [#611, #625] +* Detect the Solaris Studio compiler [#611, #625] +* Throw a message with strerror included [#136, #621] + +## 1.0.8 (August 6, 2015) +* fix kqueue assertion failed, postpone ArmKqueueWriter until all events are processed [#51, #176, #372, #401, #619] +* fix Rubinius GC, crank the machine from Ruby space when running Rubinius [#201, #202, #617] +* test to show that LineText2 preserves whitespace and newlines [#32, #622] +* bump up compiler warnings and resolve them [#616] +* fix Windows x64 use uintptr_t instead of unsigned long for binding pointers [#612, #615] +* fix linetext2 unroll tail recursion to avoid stack level too deep [#609] +* fix for compilation with SSL on windows [#601] +* open file descriptors and sockets with O_CLOEXEC where possible [#298, #488, #591] +* fix SmtpClient: send second EHLO after STARTTLS. [#589] +* fix nul-terminated strings in C, use StringValueCStr instead of StringValuePtr + +## 1.0.7 (February 10, 2015) +* fix delay in kqueue/epoll reactor shutdown when timers exist [#587] +* fix memory leak introduced in v1.0.5 [#586] +* expose EM.set_simultaneous_accept_count [#420] +* fix busy loop when EM.run and EM.next_tick are invoked from exception handler [#452] + +## 1.0.6 (February 3, 2015) +* add support for Rubinius Process::Status [#568] +* small bugfixes for SmtpServer [#449] +* update buftok.rb [#547] +* fix assertion on Write() [#525] +* work around mkmf.rb bug preventing gem installation [#574] +* add pause/resume support to jruby reactor [#556] +* fix pure ruby reactor to use 127.0.0.1 instead of localhost [#439] +* fix compilation under macruby [#243] +* add chunked encoding to http client [#111] +* fix errors on win32 when dealing with pipes [1ea45498] [#105] + +## 1.0.5 (February 2, 2015) +* use monotonic clocks on Linux, OS X, Solaris, and Windows [#563] +* use the rb_fd_* API to get autosized fd_sets [#502] +* add basic tests that the DNS resolver isn't leaking timers [#571] +* update to test-unit 2.x and improve various unit tests [#551] +* remove EventMachine_t::Popen code marked by ifdef OBSOLETE [#551] +* ruby 2.0 may fail at Queue.pop, so rescue and complain to $stderr [#551] +* set file handle to INVALID_HANDLE_VALUE after closing the file [#565] +* use `defined?` instead of rescuing NameError for flow control [#535] +* fix closing files and sockets on Windows [#564] +* fix file uploads in Windows [#562] +* catch failure to fork [#539] +* use chunks for SSL write [#545] + +## 1.0.4 (December 19, 2014) +* add starttls_options to smtp server [#552] +* fix closesocket on windows [#497] +* fix build on ruby 2.2 [#503] +* fix build error on ruby 1.9 [#508] +* fix timer leak during dns resolution [#489] +* add concurrency validation to EM::Iterator [#468] +* add get_file_descriptor to get fd for a signature [#467] +* add EM.attach_server and EM.attach_socket_server [#465, #466] +* calling pause from receive_data takes effect immediately [#464] +* reactor_running? returns false after fork [#455] +* fix infinite loop on double close [edc4d0e6, #441, #445] +* fix compilation issue on llvm [#433] +* fix socket error codes on win32 [ff811a81] +* fix EM.stop latency when timers exist [8b613d05, #426] +* fix infinite loop when system time changes [1427a2c80, #428] +* fix crash when callin attach/detach in the same tick [#427] +* fix compilation issue on solaris [#416] + +## 1.0.3 (March 8, 2013) +* EM.system was broken in 1.0.2 release [#413] + +## 1.0.2 (March 8, 2013) +* binary win32 gems now include fastfilereader shim [#222] +* fix long-standing connection timeout issues [27fdd5b, igrigorik/em-http-request#222] +* http and line protocol cleanups [#193, #151] +* reactor return value cleanup [#225] +* fix double require from gemspec [#284] +* fix smtp server reset behavior [#351] +* fix EM.system argument handling [#322] +* ruby 1.9 compat in smtp server and stomp protocols [#349, #315] +* fix pause from post_init [#380] + +## 1.0.1 (February 27, 2013) +* use rb_wait_for_single_fd() on ruby 2.0 to fix rb_thread_select() deprecation [#363] +* fix epoll/kqueue mode in ruby 2.0 by removing calls to rb_enable_interrupt() [#248, #389] +* fix memory leak when verifying ssl cerificates [#403] +* fix initial connection delay [#393, #374] +* fix build on windows [#371] diff --git a/bin/gems/eventmachine-1.2.7/GNU b/bin/gems/eventmachine-1.2.7/GNU new file mode 100644 index 00000000..3b70c5be --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/GNU @@ -0,0 +1,281 @@ +. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Lesser General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + diff --git a/bin/gems/eventmachine-1.2.7/LICENSE b/bin/gems/eventmachine-1.2.7/LICENSE new file mode 100644 index 00000000..fbe8c83b --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/LICENSE @@ -0,0 +1,60 @@ +EventMachine is copyrighted free software owned by Francis Cianfrocca +(blackhedd ... gmail.com). The Owner of this software permits you to +redistribute and/or modify the software under either the terms of the GPL +version 2 (see the file GPL), or the conditions below ("Ruby License"): + + 1. You may make and give away verbatim copies of the source form of this + software without restriction, provided that you retain ALL of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the Owner. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in a manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the Owner. + + 4. You may modify and include parts of the software into any other + software (possibly commercial), provided you comply with the terms in + Sections 1, 2, and 3 above. But some files in the distribution + are not written by the Owner, so they may be made available to you + under different terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whoever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + diff --git a/bin/gems/eventmachine-1.2.7/README.md b/bin/gems/eventmachine-1.2.7/README.md new file mode 100644 index 00000000..4b17cb4a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/README.md @@ -0,0 +1,110 @@ +# About EventMachine [![Build Status](https://travis-ci.org/eventmachine/eventmachine.svg?branch=master)](https://travis-ci.org/eventmachine/eventmachine) [![Code Climate Maintainability](https://api.codeclimate.com/v1/badges/e9b0603462905d5b9118/maintainability)](https://codeclimate.com/github/eventmachine/eventmachine/maintainability) + + +## What is EventMachine ## + +EventMachine is an event-driven I/O and lightweight concurrency library for Ruby. +It provides event-driven I/O using the [Reactor pattern](http://en.wikipedia.org/wiki/Reactor_pattern), +much like [JBoss Netty](http://www.jboss.org/netty), [Apache MINA](http://mina.apache.org/), +Python's [Twisted](http://twistedmatrix.com), [Node.js](http://nodejs.org), libevent and libev. + +EventMachine is designed to simultaneously meet two key needs: + + * Extremely high scalability, performance and stability for the most demanding production environments. + * An API that eliminates the complexities of high-performance threaded network programming, + allowing engineers to concentrate on their application logic. + +This unique combination makes EventMachine a premier choice for designers of critical networked +applications, including Web servers and proxies, email and IM production systems, authentication/authorization +processors, and many more. + +EventMachine has been around since the early 2000s and is a mature and battle-tested library. + + +## What EventMachine is good for? ## + + * Scalable event-driven servers. Examples: [Thin](http://code.macournoyer.com/thin/) or [Goliath](https://github.com/postrank-labs/goliath/). + * Scalable asynchronous clients for various protocols, RESTful APIs and so on. Examples: [em-http-request](https://github.com/igrigorik/em-http-request) or [amqp gem](https://github.com/ruby-amqp/amqp). + * Efficient network proxies with custom logic. Examples: [Proxymachine](https://github.com/mojombo/proxymachine/). + * File and network monitoring tools. Examples: [eventmachine-tail](https://github.com/jordansissel/eventmachine-tail) and [logstash](https://github.com/logstash/logstash). + + + +## What platforms are supported by EventMachine? ## + +EventMachine supports Ruby 1.8.7 through 2.6, REE, JRuby and **works well on Windows** as well +as many operating systems from the Unix family (Linux, Mac OS X, BSD flavors). + + + +## Install the gem ## + +Install it with [RubyGems](https://rubygems.org/) + + gem install eventmachine + +or add this to your Gemfile if you use [Bundler](http://gembundler.com/): + + gem "eventmachine" + + + +## Getting started ## + +For an introduction to EventMachine, check out: + + * [blog post about EventMachine by Ilya Grigorik](http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/). + * [EventMachine Introductions by Dan Sinclair](http://everburning.com/news/eventmachine-introductions.html). + + +### Server example: Echo server ### + +Here's a fully-functional echo server written with EventMachine: + +```ruby + require 'eventmachine' + + module EchoServer + def post_init + puts "-- someone connected to the echo server!" + end + + def receive_data data + send_data ">>>you sent: #{data}" + close_connection if data =~ /quit/i + end + + def unbind + puts "-- someone disconnected from the echo server!" + end +end + +# Note that this will block current thread. +EventMachine.run { + EventMachine.start_server "127.0.0.1", 8081, EchoServer +} +``` + + +## EventMachine documentation ## + +Currently we only have [reference documentation](http://rdoc.info/github/eventmachine/eventmachine/frames) and a [wiki](https://github.com/eventmachine/eventmachine/wiki). + + +## Community and where to get help ## + + * Join the [mailing list](http://groups.google.com/group/eventmachine) (Google Group) + * Join IRC channel #eventmachine on irc.freenode.net + + +## License and copyright ## + +EventMachine is copyrighted free software made available under the terms +of either the GPL or Ruby's License. + +Copyright: (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + + +## Alternatives ## + +If you are unhappy with EventMachine and want to use Ruby, check out [Celluloid](https://celluloid.io/). diff --git a/bin/gems/eventmachine-1.2.7/docs/DocumentationGuidesIndex.md b/bin/gems/eventmachine-1.2.7/docs/DocumentationGuidesIndex.md new file mode 100644 index 00000000..b8ce5a2a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/DocumentationGuidesIndex.md @@ -0,0 +1,27 @@ +# EventMachine documentation guides # + +Welcome to the documentation guides for [EventMachine](http://github.com/eventmachine/eventmachine), +a fast and simple event-processing library for Ruby programs (à la JBoss Netty, Twisted, Node.js +and so on). + +## Guide list ## + + * {file:docs/GettingStarted.md Getting started with EventMachine} + * {file:docs/EventDrivenServers.md Writing event-driven servers} + * {file:docs/EventDrivenClients.md Writing event-driven clients} + * {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery} + * {file:docs/TLS.md TLS (aka SSL)} + * {file:docs/Ecosystem.md EventMachine ecosystem}: Thin, Goliath, em-http-request, em-websockets, Proxymachine and beyond + * {file:docs/BlockingEventLoop.md On blocking the event loop: why it is harmful for performance and how to avoid it} + * {file:docs/LightweightConcurrency.md Lightweight concurrency with EventMachine} + * {file:docs/Deferrables.md Deferrables} + * {file:docs/ModernKernelInputOutputAPIs.md Brief introduction to epoll, kqueue, select} + * {file:docs/WorkingWithOtherIOSources.md Working with other IO sources such as the keyboard} + + +## Tell us what you think! ## + +Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3) +or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered? +Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is +key to making documentation better. diff --git a/bin/gems/eventmachine-1.2.7/docs/GettingStarted.md b/bin/gems/eventmachine-1.2.7/docs/GettingStarted.md new file mode 100644 index 00000000..63acbb78 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/GettingStarted.md @@ -0,0 +1,521 @@ +# @title Getting Started with Ruby EventMachine +# @markup markdown +# @author Michael S. Klishin, Dan Sinclair + +# Getting started with Ruby EventMachine # + + +## About this guide ## + +This guide is a quick tutorial that helps you to get started with EventMachine for writing event-driven +servers, clients and using it as a lightweight concurrency library. +It should take about 20 minutes to read and study the provided code examples. This guide covers + + * Installing EventMachine via [Rubygems](http://rubygems.org) and [Bundler](http://gembundler.com). + * Building an Echo server, the "Hello, world"-like code example of network servers. + * Building a simple chat, both server and client. + * Building a very small asynchronous Websockets client. + + +## Covered versions ## + +This guide covers EventMachine v0.12.10 and 1.0 (including betas). + + +## Level ## + +This guide assumes you are comfortable (but not necessary a guru) with the command line. On Microsoft Windows™, +we recommend you to use [JRuby](http://jruby.org) when running these examples. + + +## Installing EventMachine ## + +### Make sure you have Ruby installed ### + +This guide assumes you have one of the supported Ruby implementations installed: + + * Ruby 1.8.7 + * Ruby 1.9.2 + * [JRuby](http://jruby.org) (we recommend 1.6) + * [Rubinius](http://rubini.us) 1.2 or higher + * [Ruby Enterprise Edition](http://www.rubyenterpriseedition.com) + +EventMachine works on Microsoft Windows™. + + +### With Rubygems ### + +To install the EventMachine gem do + + gem install eventmachine + + +### With Bundler ### + + gem "eventmachine" + + +### Verifying your installation ### + +Lets verify your installation with this quick IRB session: + + irb -rubygems + + ruby-1.9.2-p180 :001 > require "eventmachine" + => true + ruby-1.9.2-p180 :002 > EventMachine::VERSION + => "1.0.0.beta.3" + + +## An Echo Server Example ## + +Lets begin with the classic "Hello, world"-like example, an echo server. The echo server responds clients with the +same data that was provided. First, here's the code: + +{include:file:examples/guides/getting\_started/01\_eventmachine\_echo_server.rb} + + +When run, the server binds to port 10000. We can connect using Telnet and verify it's working: + + telnet localhost 10000 + +On my machine the output looks like: + + ~ telnet localhost 10000 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + +Let's send something to our server. Type in "Hello, EventMachine" and hit Enter. The server will respond with +the same string: + + ~ telnet localhost 10000 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + Hello, EventMachine + # (here we hit Enter) + Hello, EventMachine + # (this ^^^ is our echo server reply) + +It works! Congratulations, you now can tell your Node.js-loving friends that you "have done some event-driven programming, too". +Oh, and to stop Telnet, hit Control + Shift + ] and then Control + C. + +Lets walk this example line by line and see what's going on. These lines + + require 'rubygems' # or use Bundler.setup + require 'eventmachine' + +probably look familiar: you use [RubyGems](http://rubygems.org) (or [Bundler](http://gembundler.com/)) for dependencies and then require EventMachine gem. Boring. + +Next: + + class EchoServer < EventMachine::Connection + def receive_data(data) + send_data(data) + end + end + +Is the implementation of our echo server. We define a class that inherits from {EventMachine::Connection} +and a handler (aka callback) for one event: when we receive data from a client. + +EventMachine handles the connection setup, receiving data and passing it to our handler, {EventMachine::Connection#receive_data}. + +Then we implement our protocol logic, which in the case of Echo is pretty trivial: we send back whatever we receive. +To do so, we're using {EventMachine::Connection#send_data}. + +Lets modify the example to recognize `exit` command: + +{include:file:examples/guides/getting\_started/02\_eventmachine\_echo_server\_that\_recognizes\_exit\_command.rb} + +Our `receive\_data` changed slightly and now looks like this: + + def receive_data(data) + if data.strip =~ /exit$/i + EventMachine.stop_event_loop + else + send_data(data) + end + end + +Because incoming data has trailing newline character, we strip it off before matching it against a simple regular +expression. If the data ends in `exit`, we stop EventMachine event loop with {EventMachine.stop_event_loop}. This unblocks +main thread and it finishes execution, and our little program exits as the result. + +To summarize this first example: + + * Subclass {EventMachine::Connection} and override {EventMachine::Connection#send_data} to handle incoming data. + * Use {EventMachine.run} to start EventMachine event loop and then bind echo server with {EventMachine.start_server}. + * To stop the event loop, use {EventMachine.stop_event_loop} (aliased as {EventMachine.stop}) + +Lets move on to a slightly more sophisticated example that will introduce several more features and methods +EventMachine has to offer. + + +## A Simple Chat Server Example ## + +Next we will write a simple chat. Initially clients will still use telnet to connect, but then we will add little +client application that will serve as a proxy between telnet and the chat server. This example is certainly longer +(~ 150 lines with whitespace and comments) so instead of looking at the final version and going through it line by line, +we will instead begin with a very simple version that only keeps track of connected clients and then add features +as we go. + +To set some expectations about our example: + + * It will keep track of connected clients + * It will support a couple of commands, à la IRC + * It will support direct messages using Twitter-like @usernames + * It won't use MongoDB, fibers or distributed map/reduce for anything but will be totally [Web Scale™](http://bit.ly/webscaletm) nonetheless. Maybe even [ROFLscale](http://bit.ly/roflscalevideo). + +### Step one: detecting connections and disconnectons ### + +First step looks like this: + +{include:file:examples/guides/getting\_started/04\_simple\_chat\_server\_step\_one.rb} + +We see familiar {EventMachine.run} and {EventMachine.start_server}, but also {EventMachine::Connection#post_init} and {EventMachine::Connection#unbind} we haven't +met yet. We don't use them in this code, so when are they run? Like {EventMachine::Connection#receive_data}, these methods are callbacks. EventMachine calls them +when certain events happen: + + * {EventMachine#post_init} is called by the event loop immediately after the network connection has been established. + In the chat server example case, this is when a new client connects. + * {EventMachine#unbind} is called when client disconnects, connection is closed or is lost (because of a network issue, for example). + +All our chat server does so far is logging connections or disconnections. What we want it to do next is to keep track of connected clients. + + +### Step two: keep track of connected clients ### + +Next iteration of the code looks like this: + +{include:file:examples/guides/getting\_started/05\_simple\_chat\_server\_step\_two.rb} + +While the code we added is very straightforward, we have to clarify one this first: subclasses of {EventMachine::Connection} are instantiated by +EventMachine for every new connected peer. So for 10 connected chat clients, there will be 10 separate `SimpleChatServer` instances in our +server process. Like any other objects, they can be stored in a collection, can provide public API other objects use, can instantiate or inject +dependencies and in general live a happy life all Ruby objects live until garbage collection happens. + +In the example above we use a @@class_variable to keep track of connected clients. In Ruby, @@class variables are accessible from instance +methods so we can add new connections to the list from `SimpleChatServer#post_init` and remove them in `SimpleChatServer#unbind`. We can also +filter connections by some criteria, as `SimpleChatServer#other_peers demonstrates`. + +So, we keep track of connections but how do we identify them? For a chat app, it's pretty common to use usernames for that. Lets ask our clients +to enter usernames when they connect. + + +### Step three: adding usernames ## + +To add usernames, we need to add a few things: + + * We need to invite newly connected clients to enter their username. + * A reader (getter) method on our {EventMachine::Connection} subclass. + * An idea of connection state (keeping track of whether a particular participant had entered username before). + +Here is one way to do it: + +{include:file:examples/guides/getting\_started/06\_simple\_chat\_server\_step\_three.rb} + +This is quite an update so lets take a look at each method individually. First, `SimpleChatServer#post_init`: + + def post_init + @username = nil + puts "A client has connected..." + ask_username + end + +To keep track of username we ask chat participants for, we add @username instance variable to our connection class. Connection +instances are just Ruby objects associated with a particular connected peer, so using @ivars is very natural. To make username +value accessible to other objects, we added a reader method that was not shown on the snippet above. + +Lets dig into `SimpleChatServer#ask_username`: + + def ask_username + self.send_line("[info] Enter your username:") + end # ask_username + + # ... + + def send_line(line) + self.send_data("#{line}\n") + end # send_line(line) + +Nothing new here, we are using {EventMachine::Connection#send_data} which we have seen before. + + +In `SimpleChatServer#receive_data` we now have to check if the username was entered or we need +to ask for it: + + def receive_data(data) + if entered_username? + handle_chat_message(data.strip) + else + handle_username(data.strip) + end + end + + # ... + + def entered_username? + !@username.nil? && !@username.empty? + end # entered_username? + +Finally, handler of chat messages is not yet implemented: + + def handle_chat_message(msg) + raise NotImplementedError + end + +Lets try this example out using Telnet: + + ~ telnet localhost 10000 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + [info] Enter your username: + antares_ + [info] Ohai, antares_ + +and the server output: + + A client has connected... + antares_ has joined + +This version requires you to remember how to terminate your Telnet session (Ctrl + Shift + ], then Ctrl + C). +It is annoying, so why don't we add the same `exit` command to our chat server? + + +### Step four: adding exit command and delivering chat messages #### + +{include:file:examples/guides/getting\_started/07\_simple\_chat\_server\_step\_four.rb} + +TBD + +Lets test-drive this version. Client A: + + ~ telnet localhost 10000 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + [info] Enter your username: + michael + [info] Ohai, michael + Hi everyone + michael: Hi everyone + joe has joined the room + # here ^^^ client B connects, lets greet him + hi joe + michael: hi joe + joe: hey michael + # ^^^ client B replies + exit + # ^^^ out command in action + Connection closed by foreign host. + +Client B: + + ~ telnet localhost 10000 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + [info] Enter your username: + joe + [info] Ohai, joe + michael: hi joe + # ^^^ client A greets us, lets reply + hey michael + joe: hey michael + exit + # ^^^ out command in action + Connection closed by foreign host. + +And finally, the server output: + + A client has connected... + michael has joined + A client has connected... + _antares has joined + [info] _antares has left + [info] michael has left + +Our little char server now supports usernames, sending messages and the `exit` command. Next up, private (aka direct) messages. + + +### Step five: adding direct messages and one more command ### + +To add direct messages, we come up with a simple convention: private messages begin with @username and may have optional colon before +message text, like this: + + @joe: hey, how do you like eventmachine? + +This convention makes parsing of messages simple so that we can concentrate on delivering them to a particular client connection. +Remember when we added `username` reader on our connection class? That tiny change makes this step possible: when a new direct +message comes in, we extract username and message text and then find then connection for @username in question: + + # + # Message handling + # + + def handle_chat_message(msg) + if command?(msg) + self.handle_command(msg) + else + if direct_message?(msg) + self.handle_direct_message(msg) + else + self.announce(msg, "#{@username}:") + end + end + end # handle_chat_message(msg) + + def direct_message?(input) + input =~ DM_REGEXP + end # direct_message?(input) + + def handle_direct_message(input) + username, message = parse_direct_message(input) + + if connection = @@connected_clients.find { |c| c.username == username } + puts "[dm] @#{@username} => @#{username}" + connection.send_line("[dm] @#{@username}: #{message}") + else + send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}" + end + end # handle_direct_message(input) + + def parse_direct_message(input) + return [$1, $2] if input =~ DM_REGEXP + end # parse_direct_message(input) + +This snippet demonstrates how one connection instance can obtain another connection instance and send data to it. +This is a very powerful feature, consider just a few use cases: + + * Peer-to-peer protocols + * Content-aware routing + * Efficient streaming with optional filtering + +Less common use cases include extending C++ core of EventMachine to provide access to hardware that streams events that +can be re-broadcasted to any interested parties connected via TCP, UDP or something like AMQP or WebSockets. With this, +sky is the limit. Actually, EventMachine has several features for efficient proxying data between connections. +We will not cover them in this guide. + +One last feature that we are going to add to our chat server is the `status` command that tells you current server time and how many people +are there in the chat room: + + # + # Commands handling + # + + def command?(input) + input =~ /(exit|status)$/i + end # command?(input) + + def handle_command(cmd) + case cmd + when /exit$/i then self.close_connection + when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room") + end + end # handle_command(cmd) + +Hopefully this piece of code is easy to follow. Try adding a few more commands, for example, the `whoishere` command that lists people +currently in the chat room. + +In the end, our chat server looks like this: + +{include:file:examples/guides/getting\_started/08\_simple\_chat\_server\_step\_five.rb} + +We are almost done with the server but there are some closing thoughts. + + +### Step six: final version ### + +Just in case, here is the final version of the chat server code we have built: + +{include:file:examples/guides/getting\_started/03\_simple\_chat\_server.rb} + + +### Step seven: future directions and some closing thoughts ### + +The chat server is just about 150 lines of Ruby including empty lines and comments, yet it has a few features most of chat server +examples never add. We did not, however, implement many other features that popular IRC clients like [Colloquy](http://colloquy.info) have: + + * Chat moderation + * Multiple rooms + * Connection timeout detection + +How would one go about implementing them? We thought it is worth discussing what else EventMachine has to offer and what ecosystem projects +one can use to build a really feature-rich Web-based IRC chat client. + +With multiple rooms it's more or less straightforward, just add one more hash and a bunch of commands and use the information about which rooms participant +is in when you are delivering messages. There is nothing in EventMachine itself that can make the job much easier for developer. + +To implement chat moderation feature you may want to do a few things: + + * Work with client IP addresses. Maybe we want to consider everyone who connects from certain IPs a moderator. + * Access persistent data about usernames of moderators and their credentials. + +Does EventMachine have anything to offer here? It does. To obtain peer IP address, take a look at {EventMachine::Connection#get_peername}. The name of this method is +a little bit misleading and originates from low-level socket programming APIs. + +#### A whirlwind tour of the EventMachine ecosystem #### + +To work with data stores you can use several database drivers that ship with EventMachine itself, however, quite often there are some 3rd party projects in +the EventMachine ecosystem that have more features, are faster or just better maintained. So we figured it will be helpful to provide a few pointers +to some of those projects: + + * For MySQL, check out [em-mysql](https://github.com/eventmachine/em-mysql) project. + * For PostgreSQL, have a look at Mike Perham's [EventMachine-based PostgreSQL driver](https://github.com/mperham/em_postgresql). + * For Redis, there is a young but already popular [em-hiredis](https://github.com/mloughran/em-hiredis) library that combines EventMachine's non-blocking I/O with + extreme performance of the official Redis C client, [hiredis](https://github.com/antirez/hiredis). + * For MongoDB, see [em-mongo](https://github.com/bcg/em-mongo) + * For Cassandra, Mike Perham [added transport agnosticism feature](http://www.mikeperham.com/2010/02/09/cassandra-and-eventmachine/) to the [cassandra gem](https://rubygems.org/gems/cassandra). + +[Riak](http://www.basho.com/products_riak_overview.php) and CouchDB talk HTTP so it's possible to use [em-http-request](https://github.com/igrigorik/em-http-request). +If you are aware of EventMachine-based non-blocking drivers for these databases, as well as for HBase, let us know on the [EventMachine mailing list](http://groups.google.com/group/eventmachine). +Also, EventMachine supports TLS (aka SSL) and works well on [JRuby](http://jruby.org) and Windows. + +Learn more in our {file:docs/Ecosystem.md EventMachine ecosystem} and {file:docs/TLS.md TLS (aka SSL)} guides. + + +#### Connection loss detection #### + +Finally, connection loss detection. When our chat participant closes her laptop lid, how do we know that she is no longer active? The answer is, when EventMachine +detects TCP connectin closure, it calls {EventMachine::Connection#unbind}. Version 1.0.beta3 and later also pass an optional argument to that method. The argument +indicates what error (if any) caused the connection to be closed. + +Learn more in our {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery} guide. + + +#### What the Chat Server Example doesn't demonstrate #### + +This chat server also leaves out something production quality clients and servers must take care of: buffering. We intentionally did not include any buffering in +our chat server example: it would only distract you from learning what you really came here to learn: how to use EventMachine to build blazing fast asynchronous +networking programs quickly. However, {EventMachine::Connection#receive_data} does not offer any guarantees that you will be receiving "whole messages" all the time, +largely because the underlying transport (UDP or TCP) does not offer such guarantees. Many protocols, for example, AMQP, mandate that large content chunks are +split into smaller _frames_ of certain size. This means that [amq-client](https://github.com/ruby-amqp/amq-client) library, for instance, that has EventMachine-based driver, +has to deal with figuring out when exactly we received "the whole message". To do so, it uses buffering and employs various checks to detect _frame boundaries_. +So **don't be deceived by the simplicity of this chat example**: it intentionally leaves framing out, but real world protocols usually require it. + + + +## A (Proxying) Chat Client Example ## + +TBD + + +## Wrapping up ## + +This tutorial ends here. Congratulations! You have learned quite a bit about EventMachine. + + +## What to read next ## + +The documentation is organized as a {file:docs/DocumentationGuidesIndex.md number of guides}, covering all kinds of +topics. TBD + + +## Tell us what you think! ## + +Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3) +or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered? +Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is +key to making documentation better. diff --git a/bin/gems/eventmachine-1.2.7/docs/old/ChangeLog b/bin/gems/eventmachine-1.2.7/docs/old/ChangeLog new file mode 100644 index 00000000..c7a6c48e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/ChangeLog @@ -0,0 +1,211 @@ +01Oct06: Replaced EventMachine#open_datagram_server with a version that can + take a Class or a Module, instead of just a Module. Thanks to Tobias + Gustafsson for pointing out the missing case. +04Oct06: Supported subsecond timer resolutions, per request by Jason Roelofs. +05Oct06: Added EventMachine#set_quantum, which sets the timer resolution. +15Nov06: Added Connection#set_comm_inactivity_timeout. +15Nov06: Checked in a Line-and-Text Protocol Handler. +18Nov06: Checked in a Header-and-Body Protocol Handler. +22Nov06: Changed EventMachine#reconnect: no longer excepts when called on an + already-connected handler. +28Nov06: Supported a binary-unix gem. +19Dec06: Added EventMachine#set_effective_user. +05Jan07: Upped max outstanding timers to 1000. +15May07: Applied Solaris patches from Brett Eisenberg +22May07: Cleaned up the license text in all the source files. +22May07: Released version 0.7.2 + +23May07: Per suggestion from Bill Kelly, fixed a bug with the initialization + of the network libraries under Windows. The goal is to enable EM to + be used without Ruby. +28May07: Applied patch from Bill Kelly, refactors the declarations of + event names to make EM easier to use from C programs without Ruby. +31May07: Added a preliminary implementation of EventMachine#popen. +01Jun07: Added EM, a "pseudo-alias" for EventMachine. +01Jun07: Added EM#next_tick. +01Jun07: Added EM::Connection#get_outbound_data_size +05Jun07: Removed the code which loads a pure-Ruby EM library in case the + compiled extension is unavailable. Suggested by Moshe Litvin. +06Jun07: Preliminary epoll implementation. +12Jun07: Added an evented popen implementation that, like Ruby's, is + full-duplex and makes the subprocess PID available to the caller. +06Jul07: Performance-tweaked the callback dispatcher in eventmachine.rb. +10Jul07: Released version 0.8.0. +12Jul07: Applied patches from Tim Pease to fix Solaris build problems. +15Jul07: Created a new provisional source branch, experiments/jruby-1. + This is a preliminary implementation of the EM reactor in Java, + suitable for use with JRuby. +17Jul07: Added EventMachine#stop_server, per request from Kirk Haines, + and associated unit tests. +22Jul07: Added EventMachine#stream_file_data. This is a very fast and scalable + way of sending data from static files over network connections. It + has separate implementations for small files and large file, and + has tunings to minimize memory consumption. +26Jul07: Added some patches by Kirk Haines to improve the behavior of + EM::Connection#send_file_data_to_connection. +26Jul07: Added a C++ module for directly integrating EM into C++ programs + with no Ruby dependencies. Needs example code. +29Jul07: Added EventMachine::Protocols::LineText2. +29Jul07: Added EventMachine::Protocols::Stomp. +30Jul07: Added sys/stat.h to project.h to fix compilation bug on Darwin. +13Aug07: Added EventMachine#reactor_running? +15Aug07: Added parameters for EventMachine::Connection:start_tls that can be + used to specify client-side private keys and certificates. +17Aug07: Added EventMachine#run_block, a sugaring for a common use case. +24Aug07: Added a preliminary keyboard handler. Needs docs and testing on + windows. +26Aug07: Created EventMachine::Spawnable, an implementation of Erlang-like + processes. +27Aug07: Silenced some -w warnings, requested by James Edward Gray II. +30Aug07: Added cookies to EM::HttpClient#request. +04Sep07: Added an initial implementation of an evented SMTP client. +04Sep07: Added an initial implementation of an evented SMTP server. +10Sep07: Changed EM#spawn to run spawned blocks in the context of the + SpawnedProcess object, not of whatever was the active object at the + time of the spawn. +14Sep07: Heartbeats weren't working with EPOLL. Noticed by Brian Candler. +15Sep07: Added some features, tests and documents to Deferrable. +16Sep07: Added [:content] parameter to EM::Protocols::SmtpClient#send. +16Sep07: Bumped version to 0.9.0 in anticipation of a release. +18Sep07: Released version 0.9.0. +19Sep07: Added #receive_reset to EM::Protocols::SmtpServer. +19Sep07: User overrides of EM::Protocols::SmtpServer#receive_recipient can now + return a Deferrable. Also fixed bug: SmtpClient now raises a protocol + error if none of its RCPT TO: commands are accepted by the server. +26Sep07: Fixed missing keyboard support for Windows. +03Oct07: Added a default handler for RuntimeErrors emitted from user-written + code. Suggested by Brian Candler. +19Oct07: Set the SO_BROADCAST option automatically on all UDP sockets. +10Nov07: Forced integer conversion of send_datagram's port parameter. +Suggested by Matthieu Riou. +12Nov07: Added saslauth.rb, a protocol module to replace the Cyrus SASL +daemons saslauthd and pwcheck. +15Nov07: Fixed bug reported by Mark Zvillius. We were failing to dispatch + zero-length datagrams under certain conditions. +19Nov07: Added EventMachine#set_max_timers. Requested by Matthieu Riou and + others. +19Nov07: Fixed bug with EM::Connection#start_tls. Was not working with server + connections. Reported by Michael S. Fischer. +26Nov07: Supported a hack for EventMachine#popen so it can return an exit + status from subprocesses. Requested by Michael S. Fischer. +30Nov07: Changed Pipe descriptors so that the child-side of the socketpair is + NOT set nonblocking. Suggested by Duane Johnson. +05Dec07: Re-enabled the pure-Ruby implementation. +06Dec07: Released Version 0.10.0. +13Dec07: Added EM::DeferrableChildProcess +24Dec07: Added a SASL client for simple password authentication. +27Dec07: Removed the hookable error handler. No one was using it and it significantly + degraded performance. +30Dec07: Implemented Kqueue support for OSX and BSD. +04Jan08: Fixed bug in epoll ("Bad file descriptor"), patch supplied by Chris + Heath. +04Jan08: Fixed bug reported by Michael S. Fischer. We were terminating + SSL connections that sent data before the handshake was complete. +08Jan08: Added an OpenBSD branch for extconf.rb, contributed by Guillaume + Sellier. +19Jan08: Added EM::Connection::get_sockname per request by Michael Fischer. +19Jan08: Supported IPv6 addresses. +30Apr08: Set the NODELAY option on sockets that we connect to other servers. + Omission noted by Roger Pack. +14May08: Generated a 0.12 release. +15May08: Supported EM#get_sockname for acceptors (TCP server sockets). + Requested by Roger Pack. +15May08; Accepted a patch from Dan Aquino that allows the interval of a + PeriodicTimer to be changed on the fly. +15Jun08: Supported nested calls to EM#run. Many people contributed ideas to + this, notably raggi and tmm1. +20Jul08: Accepted patch from tmm1 for EM#fork_reactor. +28Jul08: Added a Postgres3 implementation, written by FCianfrocca. +14Aug08: Added a patch by Mike Murphy to support basic auth in the http +client. +28Aug08: Added a patch by tmm1 to fix a longstanding problem with Java +data-sends. +13Sep08: Added LineText2#set_binary_mode, a back-compatibility alias. +13Sep08: Modified the load order of protocol libraries in eventmachine.rb + to permit a modification of HeaderAndContentProtocol. +13Sep08: Modified HeaderAndContent to use LineText2, which is less buggy + than LineAndTextProtocol. This change may be reversed if we can fix + the bugs in buftok. +13Sep08: Improved the password handling in the Postgres protocol handler. +15Sep08: Added attach/detach, contributed by Aman Gupta (tmm1) and Riham Aldakkak, + to support working with file descriptors not created in the reactor. +16Sep08: Added an optional version string to the HTTP client. This is a hack + that allows a client to specify a version 1.0 request, which + keeps the server from sending a chunked response. The right way to + solve this, of course, is to support chunked responses. +23Sep08: ChangeLog Summary for Merge of branches/raggi +Most notable work and patches by Aman Gupta, Roger Pack, and James Tucker. +Patches / Tickets also submitted by: Jeremy Evans, aanand, darix, mmmurf, +danielaquino, macournoyer. + - Moved docs into docs/ dir + - Major refactor of rakefile, added generic rakefile helpers in tasks + - Added example CPP build rakefile in tasks/cpp.rake + - Moved rake tests out to tasks/tests.rake + - Added svn ignores where appropriate + - Fixed jruby build on older java platforms + - Gem now builds from Rakefile rather than directly via extconf + - Gem unified for jruby, C++ and pure ruby. + - Correction for pure C++ build, removing ruby dependency + - Fix for CYGWIN builds on ipv6 + - Major refactor for extconf.rb + - Working mingw builds + - extconf optionally uses pkg_config over manual configuration + - extconf builds for 1.9 on any system that has 1.9 + - extconf no longer links pthread explicitly + - looks for kqueue on all *nix systems + - better error output on std::runtime_error, now says where it came from + - Fixed some tests on jruby + - Added test for general send_data flaw, required for a bugfix in jruby build + - Added timeout to epoll tests + - Added fixes for java reactor ruby api + - Small addition of some docs in httpclient.rb and httpcli2.rb + - Some refactor and fixes in smtpserver.rb + - Added parenthesis where possible to avoid excess ruby warnings + - Refactor of $eventmachine_library logic for accuracy and maintenance, jruby + - EM::start_server now supports unix sockets + - EM::connect now supports unix sockets + - EM::defer @threadqueue now handled more gracefully + - Added better messages on exceptions raised + - Fix edge case in timer fires + - Explicitly require buftok.rb + - Add protocols to autoload, rather than require them all immediately + - Fix a bug in pr_eventmachine for outbound_q + - Refactors to take some of the use of defer out of tests. + - Fixes in EM.defer under start/stop conditions. Reduced scope of threads. +23Sep08: Added patch from tmm1 to avoid popen errors on exit. +30Sep08: Added File.exists? checks in the args for start_tls, as suggested by + Brian Lopez (brianmario). +10Nov08: ruby 1.9 compatibility enhancements +28Nov08: Allow for older ruby builds where RARRAY_LEN is not defined +03Dec08: allow passing arguments to popen handlers +13Jan09: SSL support for httpclient2 (David Smalley) +22Jan09: Fixed errors on OSX with the kqueue reactor, fixed errors in the pure + ruby reactor. Added EM.current_time. Added EM.epoll? and EM.kqueue? +27Jan09: Reactor errors are now raised as ruby RuntimeErrors. +28Jan09: Documentation patch from alloy +29Jan09: (Late sign-off) Use a longer timeout for connect_server (Ilya + Grigorik) +07Feb09: Fix signal handling issues with threads+epoll +07Feb09: Use rb_thread_schedule in the epoll reactor +07Feb09: Use TRAP_BEG/END and rb_thread_schedule in kqueue reactor +08Feb09: Added fastfilereader from swiftiply +08Feb09: 1.9 fix for rb_trap_immediate +08Feb09: Enable rb_thread_blocking_region for 1.9.0 and 1.9.1 +10Feb09: Support win32 builds for fastfilereader +10Feb09: Added a new event to indicate completion of SSL handshake on TCP + connections +10Feb09: Working get_peer_cert method. Returns the certificate as a Ruby + String in PEM format. (Jake Douglas) +10Feb09: Added EM.get_max_timers +11Feb09: Fix compile options for sun compiler (Alasdairrr) +11Feb09: get_status returns a Process::Status object +12Feb09: Add EM::Protocols::Memcache with simple get/set functionality +19Feb09: Add catch-all EM.error_handler +20Feb09: Support miniunit (1.9) +20Feb09: Return success on content-length = 0 instead of start waiting forever + (Ugo Riboni) +25Feb09: Allow next_tick to be used to pre-schedule reactor operations before + EM.run +26Feb09: Added EM.get_connection_count +01Mar09: Switch back to extconf for compiling gem extensions +01Mar09: fixed a small bug with basic auth (mmmurf) diff --git a/bin/gems/eventmachine-1.2.7/docs/old/DEFERRABLES b/bin/gems/eventmachine-1.2.7/docs/old/DEFERRABLES new file mode 100644 index 00000000..6e8856cc --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/DEFERRABLES @@ -0,0 +1,246 @@ +EventMachine (EM) adds two different formalisms for lightweight concurrency +to the Ruby programmer's toolbox: spawned processes and deferrables. This +note will show you how to use deferrables. For more information, see the +separate document LIGHTWEIGHT_CONCURRENCY. + +=== What are Deferrables? + +EventMachine's Deferrable borrows heavily from the "deferred" object in +Python's "Twisted" event-handling framework. Here's a minimal example that +illustrates Deferrable: + + require 'eventmachine' + + class MyClass + include EM::Deferrable + + def print_value x + puts "MyClass instance received #{x}" + end + end + + EM.run { + df = MyClass.new + df.callback {|x| + df.print_value(x) + EM.stop + } + + EM::Timer.new(2) { + df.set_deferred_status :succeeded, 100 + } + } + + +This program will spin for two seconds, print out the string "MyClass +instance received 100" and then exit. The Deferrable pattern relies on +an unusual metaphor that may be unfamiliar to you, unless you've used +Python's Twisted. You may need to read the following material through +more than once before you get the idea. + +EventMachine::Deferrable is simply a Ruby Module that you can include +in your own classes. (There also is a class named +EventMachine::DefaultDeferrable for when you want to create one without +including it in code of your own.) + +An object that includes EventMachine::Deferrable is like any other Ruby +object: it can be created whenever you want, returned from your functions, +or passed as an argument to other functions. + +The Deferrable pattern allows you to specify any number of Ruby code +blocks (callbacks or errbacks) that will be executed at some future time +when the status of the Deferrable object changes. + +How might that be useful? Well, imagine that you're implementing an HTTP +server, but you need to make a call to some other server in order to fulfill +a client request. + +When you receive a request from one of your clients, you can create and +return a Deferrable object. Some other section of your program can add a +callback to the Deferrable that will cause the client's request to be +fulfilled. Simultaneously, you initiate an event-driven or threaded client +request to some different server. And then your EM program will continue to +process other events and service other client requests. + +When your client request to the other server completes some time later, you +will call the #set_deferred_status method on the Deferrable object, passing +either a success or failure status, and an arbitrary number of parameters +(which might include the data you received from the other server). + +At that point, the status of the Deferrable object becomes known, and its +callback or errback methods are immediately executed. Callbacks and errbacks +are code blocks that are attached to Deferrable objects at any time through +the methods #callback and #errback. + +The deep beauty of this pattern is that it decouples the disposition of one +operation (such as a client request to an outboard server) from the +subsequent operations that depend on that disposition (which may include +responding to a different client or any other operation). + +The code which invokes the deferred operation (that will eventually result +in a success or failure status together with associated data) is completely +separate from the code which depends on that status and data. This achieves +one of the primary goals for which threading is typically used in +sophisticated applications, with none of the nondeterminacy or debugging +difficulties of threads. + +As soon as the deferred status of a Deferrable becomes known by way of a call +to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its +callbacks or errbacks in the order in which they were added to the Deferrable. + +Callbacks and errbacks can be added to a Deferrable object at any time, not +just when the object is created. They can even be added after the status of +the object has been determined! (In this case, they will be executed +immediately when they are added.) + +A call to Deferrable#set_deferred_status takes :succeeded or :failed as its +first argument. (This determines whether the object will call its callbacks +or its errbacks.) #set_deferred_status also takes zero or more additional +parameters, that will in turn be passed as parameters to the callbacks or +errbacks. + +In general, you can only call #set_deferred_status ONCE on a Deferrable +object. A call to #set_deferred_status will not return until all of the +associated callbacks or errbacks have been called. If you add callbacks or +errbacks AFTER making a call to #set_deferred_status, those additional +callbacks or errbacks will execute IMMEDIATELY. Any given callback or +errback will be executed AT MOST once. + +It's possible to call #set_deferred_status AGAIN, during the execution a +callback or errback. This makes it possible to change the parameters which +will be sent to the callbacks or errbacks farther down the chain, enabling +some extremely elegant use-cases. You can transform the data returned from +a deferred operation in arbitrary ways as needed by subsequent users, without +changing any of the code that generated the original data. + +A call to #set_deferred_status will not return until all of the associated +callbacks or errbacks have been called. If you add callbacks or errbacks +AFTER making a call to #set_deferred_status, those additional callbacks or +errbacks will execute IMMEDIATELY. + +Let's look at some more sample code. It turns out that many of the internal +protocol implementations in the EventMachine package rely on Deferrable. One +of these is EM::Protocols::HttpClient. + +To make an evented HTTP request, use the module function +EM::Protocols::HttpClient#request, which returns a Deferrable object. +Here's how: + + require 'eventmachine' + + EM.run { + df = EM::Protocols::HttpClient.request( :host=>"www.example.com", + :request=>"/index.html" ) + + df.callback {|response| + puts "Succeeded: #{response[:content]}" + EM.stop + } + + df.errback {|response| + puts "ERROR: #{response[:status]}" + EM.stop + } + } + +(See the documentation of EventMachine::Protocols::HttpClient for information +on the object returned by #request.) + +In this code, we make a call to HttpClient#request, which immediately returns +a Deferrable object. In the background, an HTTP client request is being made +to www.example.com, although your code will continue to run concurrently. + +At some future point, the HTTP client request will complete, and the code in +EM::Protocols::HttpClient will process either a valid HTTP response (including +returned content), or an error. + +At that point, EM::Protocols::HttpClient will call +EM::Deferrable#set_deferred_status on the Deferrable object that was returned +to your program, as the return value from EM::Protocols::HttpClient.request. +You don't have to do anything to make this happen. All you have to do is tell +the Deferrable what to do in case of either success, failure, or both. + +In our code sample, we set one callback and one errback. The former will be +called if the HTTP call succeeds, and the latter if it fails. (For +simplicity, we have both of them calling EM#stop to end the program, although +real programs would be very unlikely to do this.) + +Setting callbacks and errbacks is optional. They are handlers to defined +events in the lifecycle of the Deferrable event. It's not an error if you +fail to set either a callback, an errback, or both. But of course your +program will then fail to receive those notifications. + +If through some bug it turns out that #set_deferred_status is never called +on a Deferrable object, then that object's callbacks or errbacks will NEVER +be called. It's also possible to set a timeout on a Deferrable. If the +timeout elapses before any other call to #set_deferred_status, the Deferrable +object will behave as is you had called set_deferred_status(:failed) on it. + + +Now let's modify the example to illustrate some additional points: + + require 'eventmachine' + + EM.run { + df = EM::Protocols::HttpClient.request( :host=>"www.example.com", + :request=>"/index.html" ) + + df.callback {|response| + df.set_deferred_status :succeeded, response[:content] + } + + df.callback {|string| + puts "Succeeded: #{string}" + EM.stop + } + + df.errback {|response| + puts "ERROR: #{response[:status]}" + EM.stop + } + } + + +Just for the sake of illustration, we've now set two callbacks instead of +one. If the deferrable operation (the HTTP client-request) succeeds, then +both of the callbacks will be executed in order. + +But notice that we've also made our own call to #set_deferred_status in the +first callback. This isn't required, because the HttpClient implementation +already made a call to #set_deferred_status. (Otherwise, of course, the +callback would not be executing.) + +But we used #set_deferred_status in the first callback in order to change the +parameters that will be sent to subsequent callbacks in the chain. In this +way, you can construct powerful sequences of layered functionality. If you +want, you can even change the status of the Deferrable from :succeeded to +:failed, which would abort the chain of callback calls, and invoke the chain +of errbacks instead. + +Now of course it's somewhat trivial to define two callbacks in the same +method, even with the parameter-changing effect we just described. It would +be much more interesting to pass the Deferrable to some other function (for +example, a function defined in another module or a different gem), that would +in turn add callbacks and/or errbacks of its own. That would illustrate the +true power of the Deferrable pattern: to isolate the HTTP client-request +from other functions that use the data that it returns without caring where +those data came from. + +Remember that you can add a callback or an errback to a Deferrable at any +point in time, regardless of whether the status of the deferred operation is +known (more precisely, regardless of when #set_deferred_status is called on +the object). Even hours or days later. + +When you add a callback or errback to a Deferrable object on which +#set_deferred_status has not yet been called, the callback/errback is queued +up for future execution, inside the Deferrable object. When you add a +callback or errback to a Deferrable on which #set_deferred_status has +already been called, the callback/errback will be executed immediately. +Your code doesn't have to worry about the ordering, and there are no timing +issues, as there would be with a threaded approach. + +For more information on Deferrables and their typical usage patterns, look +in the EM unit tests. There are also quite a few sugarings (including +EM::Deferrable#future) that make typical Deferrable usages syntactically +easier to work with. + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/EPOLL b/bin/gems/eventmachine-1.2.7/docs/old/EPOLL new file mode 100644 index 00000000..13cea8f4 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/EPOLL @@ -0,0 +1,141 @@ +EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs. + +Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels. +It features significantly greater performance than the standard select(2) mechanism, when used in +applications that require very large numbers of open I/O descriptors. + +EventMachine has always used select(2) because its behavior is well standardized and broadly supported. +But select becomes unreasonably slow when a program has a +very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit +of 1024 descriptors per process, but heavily loaded processes will start to show performance +degradation even after only a few hundred descriptors are in use. + +Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs +based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands +of connectors, with no significant impact on performance. + +(Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its +variants.) + + + +This note shows you how to use epoll in your programs. + +=== Compiling EventMachine to use epoll. + +You don't have to do anything to get epoll support in EventMachine. +When you compile EventMachine on a platform that supports epoll, EM will +automatically generate a Makefile that includes epoll. (At this writing, this will only work +on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will +be omitted from the Makefile, and EM will work just as it always has. + +=== Using epoll in your programs. + +First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement +will be removed in a future EventMachine version). Second, you need to prepare your program to use +more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably +want your process to drop the superuser privileges after you increase your process's descriptor limit. + +=== Using EventMachine#epoll + +Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will +automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because +it compiles to a no-op on platforms that don't support epoll. + + require 'rubygems' + require 'eventmachine' + + EM.epoll + EM.run { + ... + } + + +EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing +programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op, +and run epoll by default on platforms that support it. + +=== Using EventMachine#set_descriptor_table_size + +In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum +number of file and socket descriptors you may have open at any given time. The size of this table is +generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits. + +If you want your EventMachine program to support more than 1024 total descriptors, you must use +EventMachine#set_descriptor_table_size, as follows: + + require 'rubygems' + require 'eventmachine' + + new_size = EM.set_descriptor_table_size( 60000 ) + $>.puts "New descriptor-table size is #{new_size}" + + EM.run { + ... + } + +If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000. +Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current +size of the descriptor table. + +Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used +by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the +number of descriptors that Ruby's own I/O functions can use. + +#set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a +table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number. + + +=== Using EventMachine#set_effective_user + +In general, you must run your program with elevated or superuser privileges if you want to increase +your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the +sample program given above, that increases the descriptor limit to 60,000. You will probably find that +the table size will not be increased if you don't run your program as root or with elevated privileges. + +But of course network servers, especially long-running ones, should not run with elevated privileges. +You will want to drop superuser privileges as soon as possible after initialization. To do this, +use EventMachine#set_effective_user: + + require 'rubygems' + require 'eventmachine' + + # (Here, program is running as superuser) + + EM.set_descriptor_table_size( 60000 ) + EM.set_effective_user( "nobody" ) + # (Here, program is running as nobody) + + EM.run { + ... + } + +Of course, you will need to replace "nobody" in the example with the name of an unprivileged user +that is valid on your system. What if you want to drop privileges after opening a server socket +on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets: + + require 'rubygems' + require 'eventmachine' + + # (Here, program is running as superuser) + + EM.set_descriptor_table_size( 60000 ) + + EM.run { + EM.start_server( "0.0.0.0", 80, MyHttpServer ) + EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer ) + + EM.set_effective_user( "nobody" ) + # (Here, program is running as nobody) + + ... + } + + +Because EventMachine#set_effective_user is used to enforce security +requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user, +#set_effective_user will abort your program, rather than continue to run with elevated privileges. + +EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows. + + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/INSTALL b/bin/gems/eventmachine-1.2.7/docs/old/INSTALL new file mode 100644 index 00000000..dee2e429 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/INSTALL @@ -0,0 +1,13 @@ +If you have obtained an EventMachine source-tarball (.tar.gz): +unzip and untar the tarball, and enter the directory that is +created. In that directory, say: +ruby setup.rb +(You may need to be root to execute this command.) + +To create documentation for EventMachine, simply type: +rake rdoc +in the distro directory. Rdocs will be created in subdirectory rdoc. + +If you have obtained a gem version of EventMachine, install it in the +usual way (gem install eventmachine). You may need superuser privileges +to execute this command. diff --git a/bin/gems/eventmachine-1.2.7/docs/old/KEYBOARD b/bin/gems/eventmachine-1.2.7/docs/old/KEYBOARD new file mode 100644 index 00000000..6c699e49 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/KEYBOARD @@ -0,0 +1,42 @@ +EventMachine (EM) can respond to keyboard events. This gives your event-driven +programs the ability to respond to input from local users. + +Programming EM to handle keyboard input in Ruby is simplicity itself. Just use +EventMachine#open_keyboard, and supply the name of a Ruby module or class that +will receive the input: + + require 'rubygems' + require 'eventmachine' + + module MyKeyboardHandler + def receive_data keystrokes + puts "I received the following data from the keyboard: #{keystrokes}" + end + end + + EM.run { + EM.open_keyboard(MyKeyboardHandler) + } + +If you want EM to send line-buffered keyboard input to your program, just +include the LineText2 protocol module in your handler class or module: + + require 'rubygems' + require 'eventmachine' + + module MyKeyboardHandler + include EM::Protocols::LineText2 + def receive_line data + puts "I received the following line from the keyboard: #{data}" + end + end + + EM.run { + EM.open_keyboard(MyKeyboardHandler) + } + +As we said, simplicity itself. You can call EventMachine#open_keyboard at any +time while the EM reactor loop is running. In other words, the method +invocation may appear anywhere in an EventMachine#run block, or in any code +invoked in the #run block. + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/LEGAL b/bin/gems/eventmachine-1.2.7/docs/old/LEGAL new file mode 100644 index 00000000..ee018255 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/LEGAL @@ -0,0 +1,25 @@ +LEGAL NOTICE INFORMATION +------------------------ + +EventMachine is Copyright (C) 2006-07 by Francis Cianfrocca. + +EventMachine is copyrighted software owned by Francis Cianfrocca +(blackhedd ... gmail.com). You may redistribute and/or modify this +software as long as you comply with either the terms of the GPL +(see the file GPL), or Ruby's license (see the file COPYING). + +Your use of all the files in this distribution is controlled by these +license terms, except for those files specifically mentioned below: + + + +setup.rb + This file is Copyright (C) 2000-2005 by Minero Aoki + You can distribute/modify this file under the terms of + the GNU LGPL, Lesser General Public License version 2.1. + + +lib/em/buftok.rb + This file is Copyright (C) 2007 by Tony Arcieri. This file is + covered by the terms of Ruby's License (see the file COPYING). + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/LIGHTWEIGHT_CONCURRENCY b/bin/gems/eventmachine-1.2.7/docs/old/LIGHTWEIGHT_CONCURRENCY new file mode 100644 index 00000000..3c2cfa03 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/LIGHTWEIGHT_CONCURRENCY @@ -0,0 +1,130 @@ +EventMachine (EM) adds two different formalisms for lightweight concurrency to +the Ruby programmer's toolbox: spawned processes and deferrables. This note +will show you how to use them. + + +=== What is Lightweight Concurrency? + +We use the term "Lightweight Concurrency" (LC) to refer to concurrency +mechanisms that are lighter than Ruby threads. By "lighter," we mean: less +resource-intensive in one or more dimensions, usually including memory and +CPU usage. In general, you turn to LC in the hope of improving the +performance and scalability of your programs. + +In addition to the two EventMachine mechanisms we will discuss here, Ruby +has at least one other LC construct: Fibers, which are currently under +development in Ruby 1.9. + +The technical feature that makes all of these LC mechanisms different from +standard Ruby threads is that they are not scheduled automatically. + +When you create and run Ruby threads, you can assume (within certain +constraints) that your threads will all be scheduled fairly by Ruby's runtime. +Ruby itself is responsible for giving each of your threads its own share of +the total runtime. + +But with LC, your program is responsible for causing different execution +paths to run. In effect, your program has to act as a "thread scheduler." +Scheduled entities in LC run to completion and are never preempted. The +runtime system has far less work to do since it has no need to interrupt +threads or to schedule them fairly. This is what makes LC lighter and faster. + +You'll learn exactly how LC scheduling works in practice as we work through +specific examples. + + +=== EventMachine Lightweight Concurrency + +Recall that EM provides a reactor loop that must be running in order for +your programs to perform event-driven logic. An EM program typically has a +structure like this: + + require 'eventmachine' + + # your initializations + + EM.run { + # perform event-driven I/O here, including network clients, + # servers, timers, and thread-pool operations. + } + + # your cleanup + # end of the program + + +EventMachine#run executes the reactor loop, which causes your code to be +called as events of interest to your program occur. The block you pass to +EventMachine#run is executed right after the reactor loop starts, and is +the right place to start socket acceptors, etc. + +Because the reactor loop runs constantly in an EM program (until it is +stopped by a call to EventMachine#stop), it has the ability to schedule +blocks of code for asynchronous execution. Unlike a pre-emptive thread +scheduler, it's NOT able to interrupt code blocks while they execute. But +the scheduling capability it does have is enough to enable lightweight +concurrency. + + +For information on Spawned Processes, see the separate document +SPAWNED_PROCESSES. + +For information on Deferrables, see the separate document DEFERRABLES. + + +=== [SIDEBAR]: I Heard That EventMachine Doesn't Work With Ruby Threads. + +This is incorrect. EM is fully interoperable with all versions of Ruby +threads, and has been since its earliest releases. + +It's very true that EM encourages an "evented" (non-threaded) programming +style. The specific benefits of event-driven programming are far better +performance and scalability for well-written programs, and far easier +debugging. + +The benefit of using threads for similar applications is a possibly more +intuitive programming model, as well as the fact that threads are already +familiar to most programmers. Also, bugs in threaded programs often fail +to show up until programs go into production. These factors create the +illusion that threaded programs are easier to write. + +However, some operations that occur frequently in professional-caliber +applications simply can't be done without threads. (The classic example +is making calls to database client-libraries that block on network I/O +until they complete.) + +EventMachine not only allows the use of Ruby threads in these cases, but +it even provides a built-in thread-pool object to make them easier to +work with. + +You may have heard a persistent criticism that evented I/O is fundamentally +incompatible with Ruby threads. It is true that some well-publicized attempts +to incorporate event-handling libraries into Ruby were not successful. But +EventMachine was designed from the ground up with Ruby compatibility in mind, +so EM never suffered from the problems that defeated the earlier attempts. + + +=== [SIDEBAR]: I Heard That EventMachine Doesn't Work Very Well On Windows. + +This too is incorrect. EventMachine is an extension written in C++ and Java, +and therefore it requires compilation. Many Windows computers (and some Unix +computers, especially in production environments) don't have a build stack. +Attempting to install EventMachine on a machine without a compiler usually +produces a confusing error. + +In addition, Ruby has a much-debated issue with Windows compiler versions. +Ruby on Windows works best with Visual Studio 6, a compiler version that is +long out-of-print, no longer supported by Microsoft, and difficult to obtain. +(This problem is not specific to EventMachine.) + +Shortly after EventMachine was first released, the compiler issues led to +criticism that EM was incompatible with Windows. Since that time, every +EventMachine release has been supplied in a precompiled binary form for +Windows users, that does not require you to compile the code yourself. EM +binary Gems for Windows are compiled using Visual Studio 6. + +EventMachine does supply some advanced features (such as Linux EPOLL support, +reduced-privilege operation, UNIX-domain sockets, etc.) that have no +meaningful implementation on Windows. Apart from these special cases, all EM +functionality (including lightweight concurrency) works perfectly well on +Windows. + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/PURE_RUBY b/bin/gems/eventmachine-1.2.7/docs/old/PURE_RUBY new file mode 100644 index 00000000..157d59eb --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/PURE_RUBY @@ -0,0 +1,75 @@ +EventMachine is supplied in three alternative versions. + +1) A version that includes a Ruby extension written in C++. This version requires compilation; +2) A version for JRuby that contains a precompiled JAR file written in Java; +3) A pure Ruby version that has no external dependencies and can run in any Ruby environment. + +The Java version of EventMachine is packaged in a distinct manner and must be installed using a +special procedure. This version is described fully in a different document, and not considered +further here. + +The C++ and pure-Ruby versions, however, are shipped in the same distribution. You use the same +files (either tarball or Ruby gem) to install both of these versions. + +If you intend to use the C++ version, you must successfully compile EventMachine after you install it. +(The gem installation attempts to perform this step automatically.) + +If you choose not to compile the EventMachine C++ extension, or if your compilation fails for any +reason, you still have a fully-functional installation of the pure-Ruby version of EM. + +However, for technical reasons, a default EM installation (whether or not the compilation succeeds) +will always assume that the compiled ("extension") implementation should be used. + +If you want your EM program to use the pure Ruby version, you must specifically request it. There +are two ways to do this: by setting either a Ruby global variable, or an environment string. + +The following code will invoke the pure-Ruby implementation of EM: + + $eventmachine_library = :pure_ruby + require 'eventmachine' + + EM.library_type #=> "pure_ruby" + +Notice that this requires a code change and is not the preferred way to select pure Ruby, unless +for some reason you are absolutely sure you will never want the compiled implementation. + +Setting the following environment string has the same effect: + + export EVENTMACHINE_LIBRARY="pure_ruby" + +This technique gives you the flexibility to select either version at runtime with no code changes. + +Support + +The EventMachine development team has committed to support precisely the same APIs for all the +various implementations of EM. + +This means that you can expect any EM program to behave identically, whether you use pure Ruby, +the compiled C++ extension, or JRuby. Deviations from this behavior are to be considered bugs +and should be reported as such. + +There is a small number of exceptions to this rule, which arise from underlying platform +distinctions. Notably, EM#epoll is a silent no-op in the pure Ruby implementation. + + +When Should You Use the Pure-Ruby Implementation of EM? + + +Use the pure Ruby implementation of EM when you must support a platform for which no C++ compiler +is available, or on which the standard EM C++ code can't be compiled. + +Keep in mind that you don't need a C++ compiler in order to deploy EM applications that rely on +the compiled version, so long as appropriate C++ runtime libraries are available on the target platform. + +In extreme cases, you may find that you can develop software with the compiled EM version, but are +not allowed to install required runtime libraries on the deployment system(s). This would be another +case in which the pure Ruby implementation can be useful. + +In general you should avoid the pure Ruby version of EM when performance and scalability are important. +EM in pure Ruby will necessarily run slower than the compiled version. Depending on your application +this may or may not be a key issue. + +Also, since EPOLL is not supported in pure Ruby, your applications will be affected by Ruby's built-in +limit of 1024 file and socket descriptors that may be open in a single process. For maximum scalability +and performance, always use EPOLL if possible. + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/RELEASE_NOTES b/bin/gems/eventmachine-1.2.7/docs/old/RELEASE_NOTES new file mode 100644 index 00000000..6110820a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/RELEASE_NOTES @@ -0,0 +1,94 @@ +RUBY/EventMachine RELEASE NOTES + +-------------------------------------------------- +Version: 0.9.0, released xxXXX07 +Added Erlang-like distributed-computing features + +-------------------------------------------------- +Version: 0.8.0, released 23Jun07 +Added an epoll implementation for Linux 2.6 kernels. +Added evented #popen. + +-------------------------------------------------- +Version: 0.7.3, released 22May07 +Added a large variety of small features. See the ChangeLog. + +-------------------------------------------------- +Version: 0.7.1, released xxNov06 +Added protocol handlers for line-oriented protocols. +Various bug fixes. + +-------------------------------------------------- +Version: 0.7.0, released 20Nov06 +Added a fix in em.cpp/ConnectToServer to fix a fatal exception that +occurred in FreeBSD when connecting successfully to a remote server. + +-------------------------------------------------- +Version: 0.6.0, released xxJul06 +Added deferred operations, suggested by Don Stocks, amillionhitpoints@yahoo.com. + +-------------------------------------------------- +Version: 0.5.4, released xxJun06 +Added get_peername support for streams and datagrams. + +-------------------------------------------------- +Version: 0.5.3, released 17May06 +Fixed bugs in extconf.rb, thanks to Daniel Harple, dharple@generalconsumption.org. +Added proper setup.rb and rake tasks, thanks to Austin Ziegler. +Fixed a handful of reported problems with builds on various platforms. + +-------------------------------------------------- +Version: 0.5.2, released 05May06 +Made several nonvisible improvements to the Windows +implementation. +Added an exception-handling patch contributed by Jeff Rose, jeff@rosejn.net. +Added a dir-config patch contributed anonymously. +Supported builds on Solaris. + +-------------------------------------------------- +Version: 0.5.1, released 05May06 +Made it possible to pass a Class rather than a Module +to a protocol handler. +Added Windows port. + +-------------------------------------------------- +Version: 0.5.0, released 30Apr06 +Added a preliminary SSL/TLS extension. This will probably +change over the next few releases. + +-------------------------------------------------- +Version: 0.4.5, released 29Apr06 +Changed ext files so the ruby.h is installed after unistd.h +otherwise it doesn't compile on gcc 4.1 + +-------------------------------------------------- +Version: 0.4.2, released 19Apr06 +Changed the Ruby-glue so the extension will play nicer +in the sandbox with Ruby threads. +Added an EventMachine::run_without_threads API to +switch off the thread-awareness for better performance +in programs that do not spin any Ruby threads. + +-------------------------------------------------- +Version: 0.4.1, released 15Apr06 +Reworked the shared-object interface to make it easier to +use EventMachine from languages other than Ruby. + +-------------------------------------------------- +Version: 0.3.2, released 12Apr06 +Added support for a user-supplied block in EventMachine#connect. + +-------------------------------------------------- +Version: 0.3.1, released 11Apr06 +Fixed bug that prevented EventMachine from being run multiple +times in a single process. + +-------------------------------------------------- +Version: 0.3.0, released 10Apr06 +Added method EventHandler::Connection::post_init + +-------------------------------------------------- +Version: 0.2.0, released 10Apr06 +Added method EventHandler::stop + + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/SMTP b/bin/gems/eventmachine-1.2.7/docs/old/SMTP new file mode 100644 index 00000000..92bf3110 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/SMTP @@ -0,0 +1,4 @@ +This note details the usage of EventMachine's built-in support for SMTP. EM +supports both client and server connections, which will be described in +separate sections. + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/SPAWNED_PROCESSES b/bin/gems/eventmachine-1.2.7/docs/old/SPAWNED_PROCESSES new file mode 100644 index 00000000..ee68e3e8 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/SPAWNED_PROCESSES @@ -0,0 +1,148 @@ +EventMachine (EM) adds two different formalisms for lightweight concurrency +to the Ruby programmer's toolbox: spawned processes and deferrables. This +note will show you how to use spawned processes. For more information, see +the separate document LIGHTWEIGHT_CONCURRENCY. + + +=== What are Spawned Processes? + +Spawned Processes in EventMachine are inspired directly by the "processes" +found in the Erlang programming language. EM deliberately borrows much (but +not all) of Erlang's terminology. However, EM's spawned processes differ from +Erlang's in ways that reflect not only Ruby style, but also the fact that +Ruby is not a functional language like Erlang. + +Let's proceed with a complete, working code sample that we will analyze line +by line. Here's an EM implementation of the "ping-pong" program that also +appears in the Erlang tutorial: + + + require 'eventmachine' + + EM.run { + pong = EM.spawn {|x, ping| + puts "Pong received #{x}" + ping.notify( x-1 ) + } + + ping = EM.spawn {|x| + if x > 0 + puts "Pinging #{x}" + pong.notify x, self + else + EM.stop + end + } + + ping.notify 3 + } + +If you run this program, you'll see the following output: + + Pinging 3 + Pong received 3 + Pinging 2 + Pong received 2 + Pinging 1 + Pong received 1 + +Let's take it step by step. + +EventMachine#spawn works very much like the built-in function spawn in +Erlang. It returns a reference to a Ruby object of class +EventMachine::SpawnedProcess, which is actually a schedulable entity. In +Erlang, the value returned from spawn is called a "process identifier" or +"pid." But we'll refer to the Ruby object returned from EM#spawn simply as a +"spawned process." + +You pass a Ruby block with zero or more parameters to EventMachine#spawn. +Like all Ruby blocks, this one is a closure, so it can refer to variables +defined in the local context when you call EM#spawn. + +However, the code block passed to EM#spawn does NOT execute immediately by +default. Rather, it will execute only when the Spawned Object is "notified." +In Erlang, this process is called "message passing," and is done with the +operator !, but in Ruby it's done simply by calling the #notify method of a +spawned-process object. The parameters you pass to #notify must match those +defined in the block that was originally passed to EM#spawn. + +When you call the #notify method of a spawned-process object, EM's reactor +core will execute the code block originally passed to EM#spawn, at some point +in the future. (#notify itself merely adds a notification to the object's +message queue and ALWAYS returns immediately.) + +When a SpawnedProcess object executes a notification, it does so in the +context of the SpawnedProcess object itself. The notified code block can see +local context from the point at which EM#spawn was called. However, the value +of "self" inside the notified code block is a reference to the SpawnedProcesss +object itself. + +An EM spawned process is nothing more than a Ruby object with a message +queue attached to it. You can have any number of spawned processes in your +program without compromising scalability. You can notify a spawned process +any number of times, and each notification will cause a "message" to be +placed in the queue of the spawned process. Spawned processes with non-empty +message queues are scheduled for execution automatically by the EM reactor. +Spawned processes with no visible references are garbage-collected like any +other Ruby object. + +Back to our code sample: + + pong = EM.spawn {|x, ping| + puts "Pong received #{x}" + ping.notify( x-1 ) + } + +This simply creates a spawned process and assigns it to the local variable +pong. You can see that the spawned code block takes a numeric parameter and a +reference to another spawned process. When pong is notified, it expects to +receive arguments corresponding to these two parameters. It simply prints out +the number it receives as the first argument. Then it notifies the spawned +process referenced by the second argument, passing it the first argument +minus 1. + +And then the block ends, which is crucial because otherwise nothing else +can run. (Remember that in LC, scheduled entities run to completion and are +never preempted.) + +On to the next bit of the code sample: + + ping = EM.spawn {|x| + if x > 0 + puts "Pinging #{x}" + pong.notify x, self + else + EM.stop + end + } + +Here, we're spawning a process that takes a single (numeric) parameter. If +the parameter is greater than zero, the block writes it to the console. It +then notifies the spawned process referenced by the pong local variable, +passing as arguments its number argument, and a reference to itself. The +latter reference, as you saw above, is used by pong to send a return +notification. + +If the ping process receives a zero value, it will stop the reactor loop and +end the program. + +Now we've created a pair of spawned processes, but nothing else has happened. +If we stop now, the program will spin in the EM reactor loop, doing nothing +at all. Our spawned processes will never be scheduled for execution. + +But look at the next line in the code sample: + + ping.notify 3 + +This line gets the ping-pong ball rolling. We call ping's #notify method, +passing the argument 3. This causes a message to be sent to the ping spawned +process. The message contains the single argument, and it causes the EM +reactor to schedule the ping process. And this in turn results in the +execution of the Ruby code block passed to EM#spawn when ping was created. +Everything else proceeds as a result of the messages that are subsequently +passed to each other by the spawned processes. + +[TODO, present the outbound network i/o use case, and clarify that spawned +processes are interleaved with normal i/o operations and don't interfere +with them at all. Also, blame Erlang for the confusing term "process"] + diff --git a/bin/gems/eventmachine-1.2.7/docs/old/TODO b/bin/gems/eventmachine-1.2.7/docs/old/TODO new file mode 100644 index 00000000..686a0d53 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/docs/old/TODO @@ -0,0 +1,8 @@ +TODO List: + +12Aug06: Noticed by Don Stocks. A TCP connect-request that results +in a failed DNS resolution fires a fatal error back to user code. +Uuuuuugly. We should probably cause an unbind event to get fired +instead, and add some parameterization so the caller can detect +the nature of the failure. + diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/01_eventmachine_echo_server.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/01_eventmachine_echo_server.rb new file mode 100644 index 00000000..51c5c7db --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/01_eventmachine_echo_server.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class EchoServer < EM::Connection + def receive_data(data) + send_data(data) + end +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, EchoServer) +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb new file mode 100644 index 00000000..4cfff19b --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class EchoServer < EM::Connection + def receive_data(data) + if data.strip =~ /exit$/i + EventMachine.stop + else + send_data(data) + end + end +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, EchoServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/03_simple_chat_server.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/03_simple_chat_server.rb new file mode 100644 index 00000000..3352551e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/03_simple_chat_server.rb @@ -0,0 +1,149 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + @@connected_clients = Array.new + DM_REGEXP = /^@([a-zA-Z0-9]+)\s*:?\s*(.+)/.freeze + + attr_reader :username + + + # + # EventMachine handlers + # + + def post_init + @username = nil + + puts "A client has connected..." + ask_username + end + + def unbind + @@connected_clients.delete(self) + puts "[info] #{@username} has left" if entered_username? + end + + def receive_data(data) + if entered_username? + handle_chat_message(data.strip) + else + handle_username(data.strip) + end + end + + + # + # Username handling + # + + def entered_username? + !@username.nil? && !@username.empty? + end # entered_username? + + def handle_username(input) + if input.empty? + send_line("Blank usernames are not allowed. Try again.") + ask_username + else + @username = input + @@connected_clients.push(self) + self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") } + puts "#{@username} has joined" + + self.send_line("[info] Ohai, #{@username}") + end + end # handle_username(input) + + def ask_username + self.send_line("[info] Enter your username:") + end # ask_username + + + # + # Message handling + # + + def handle_chat_message(msg) + if command?(msg) + self.handle_command(msg) + else + if direct_message?(msg) + self.handle_direct_message(msg) + else + self.announce(msg, "#{@username}:") + end + end + end # handle_chat_message(msg) + + def direct_message?(input) + input =~ DM_REGEXP + end # direct_message?(input) + + def handle_direct_message(input) + username, message = parse_direct_message(input) + + if connection = @@connected_clients.find { |c| c.username == username } + puts "[dm] @#{@username} => @#{username}" + connection.send_line("[dm] @#{@username}: #{message}") + else + send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}" + end + end # handle_direct_message(input) + + def parse_direct_message(input) + return [$1, $2] if input =~ DM_REGEXP + end # parse_direct_message(input) + + + # + # Commands handling + # + + def command?(input) + input =~ /(exit|status)$/i + end # command?(input) + + def handle_command(cmd) + case cmd + when /exit$/i then self.close_connection + when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room") + end + end # handle_command(cmd) + + + # + # Helpers + # + + def announce(msg = nil, prefix = "[chat server]") + @@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty? + end # announce(msg) + + def number_of_connected_clients + @@connected_clients.size + end # number_of_connected_clients + + def other_peers + @@connected_clients.reject { |c| self == c } + end # other_peers + + def send_line(line) + self.send_data("#{line}\n") + end # send_line(line) + + def usernames + @@connected_clients.map { |c| c.username } + end # usernames +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/04_simple_chat_server_step_one.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/04_simple_chat_server_step_one.rb new file mode 100644 index 00000000..bb283a7a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/04_simple_chat_server_step_one.rb @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + # + # EventMachine handlers + # + + def post_init + puts "A client has connected..." + end + + def unbind + puts "A client has left..." + end +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/05_simple_chat_server_step_two.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/05_simple_chat_server_step_two.rb new file mode 100644 index 00000000..1361c5da --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/05_simple_chat_server_step_two.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + @@connected_clients = Array.new + + + # + # EventMachine handlers + # + + def post_init + @@connected_clients.push(self) + puts "A client has connected..." + end + + def unbind + @@connected_clients.delete(self) + puts "A client has left..." + end + + + + + # + # Helpers + # + + def other_peers + @@connected_clients.reject { |c| self == c } + end # other_peers +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/06_simple_chat_server_step_three.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/06_simple_chat_server_step_three.rb new file mode 100644 index 00000000..d9b85e21 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/06_simple_chat_server_step_three.rb @@ -0,0 +1,98 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + @@connected_clients = Array.new + + + attr_reader :username + + + # + # EventMachine handlers + # + + def post_init + @username = nil + + puts "A client has connected..." + ask_username + end + + def unbind + @@connected_clients.delete(self) + puts "A client has left..." + end + + def receive_data(data) + if entered_username? + handle_chat_message(data.strip) + else + handle_username(data.strip) + end + end + + + + + # + # Username handling + # + + def entered_username? + !@username.nil? && !@username.empty? + end # entered_username? + + def handle_username(input) + if input.empty? + send_line("Blank usernames are not allowed. Try again.") + ask_username + else + @username = input + @@connected_clients.push(self) + self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") } + puts "#{@username} has joined" + + self.send_line("[info] Ohai, #{@username}") + end + end # handle_username(input) + + def ask_username + self.send_line("[info] Enter your username:") + end # ask_username + + + + # + # Message handling + # + + def handle_chat_message(msg) + raise NotImplementedError + end + + + + # + # Helpers + # + + def other_peers + @@connected_clients.reject { |c| self == c } + end # other_peers + + def send_line(line) + self.send_data("#{line}\n") + end # send_line(line) +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/07_simple_chat_server_step_four.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/07_simple_chat_server_step_four.rb new file mode 100644 index 00000000..d4948af8 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/07_simple_chat_server_step_four.rb @@ -0,0 +1,121 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + @@connected_clients = Array.new + + + attr_reader :username + + + # + # EventMachine handlers + # + + def post_init + @username = nil + + puts "A client has connected..." + ask_username + end + + def unbind + @@connected_clients.delete(self) + puts "[info] #{@username} has left" if entered_username? + end + + def receive_data(data) + if entered_username? + handle_chat_message(data.strip) + else + handle_username(data.strip) + end + end + + + + + # + # Username handling + # + + def entered_username? + !@username.nil? && !@username.empty? + end # entered_username? + + def handle_username(input) + if input.empty? + send_line("Blank usernames are not allowed. Try again.") + ask_username + else + @username = input + @@connected_clients.push(self) + self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") } + puts "#{@username} has joined" + + self.send_line("[info] Ohai, #{@username}") + end + end # handle_username(input) + + def ask_username + self.send_line("[info] Enter your username:") + end # ask_username + + + + # + # Message handling + # + + def handle_chat_message(msg) + if command?(msg) + self.handle_command(msg) + else + self.announce(msg, "#{@username}:") + end + end + + + # + # Commands handling + # + + def command?(input) + input =~ /exit$/i + end # command?(input) + + def handle_command(cmd) + case cmd + when /exit$/i then self.close_connection + end + end # handle_command(cmd) + + + + # + # Helpers + # + + def announce(msg = nil, prefix = "[chat server]") + @@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty? + end # announce(msg) + + def other_peers + @@connected_clients.reject { |c| self == c } + end # other_peers + + def send_line(line) + self.send_data("#{line}\n") + end # send_line(line) +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/08_simple_chat_server_step_five.rb b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/08_simple_chat_server_step_five.rb new file mode 100644 index 00000000..03da66bf --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/guides/getting_started/08_simple_chat_server_step_five.rb @@ -0,0 +1,141 @@ +#!/usr/bin/env ruby + +require 'rubygems' # or use Bundler.setup +require 'eventmachine' + +class SimpleChatServer < EM::Connection + + @@connected_clients = Array.new + DM_REGEXP = /^@([a-zA-Z0-9]+)\s*:?\s+(.+)/.freeze + + attr_reader :username + + + # + # EventMachine handlers + # + + def post_init + @username = nil + + puts "A client has connected..." + ask_username + end + + def unbind + @@connected_clients.delete(self) + puts "[info] #{@username} has left" if entered_username? + end + + def receive_data(data) + if entered_username? + handle_chat_message(data.strip) + else + handle_username(data.strip) + end + end + + + # + # Username handling + # + + def entered_username? + !@username.nil? && !@username.empty? + end # entered_username? + + def handle_username(input) + if input.empty? + send_line("Blank usernames are not allowed. Try again.") + ask_username + else + @username = input + @@connected_clients.push(self) + self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") } + puts "#{@username} has joined" + + self.send_line("[info] Ohai, #{@username}") + end + end # handle_username(input) + + def ask_username + self.send_line("[info] Enter your username:") + end # ask_username + + + # + # Message handling + # + + def handle_chat_message(msg) + if command?(msg) + self.handle_command(msg) + else + if direct_message?(msg) + self.handle_direct_message(msg) + else + self.announce(msg, "#{@username}:") + end + end + end # handle_chat_message(msg) + + def direct_message?(input) + input =~ DM_REGEXP + end # direct_message?(input) + + def handle_direct_message(input) + username, message = parse_direct_message(input) + + if connection = @@connected_clients.find { |c| c.username == username } + puts "[dm] @#{@username} => @#{username}" + connection.send_line("[dm] @#{@username}: #{message}") + else + send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}" + end + end # handle_direct_message(input) + + def parse_direct_message(input) + return [$1, $2] if input =~ DM_REGEXP + end # parse_direct_message(input) + + + # + # Commands handling + # + + def command?(input) + input =~ /(exit|status)$/i + end # command?(input) + + def handle_command(cmd) + case cmd + when /exit$/i then self.close_connection + when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room") + end + end # handle_command(cmd) + + + # + # Helpers + # + + def announce(msg = nil, prefix = "[chat server]") + @@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty? + end # announce(msg) + + def other_peers + @@connected_clients.reject { |c| self == c } + end # other_peers + + def send_line(line) + self.send_data("#{line}\n") + end # send_line(line) +end + +EventMachine.run do + # hit Control + C to stop + Signal.trap("INT") { EventMachine.stop } + Signal.trap("TERM") { EventMachine.stop } + + EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer) +end diff --git a/bin/gems/eventmachine-1.2.7/examples/old/ex_channel.rb b/bin/gems/eventmachine-1.2.7/examples/old/ex_channel.rb new file mode 100644 index 00000000..16e8d083 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/old/ex_channel.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/helper' + +EM.run do + + # Create a channel to push data to, this could be stocks... + RandChannel = EM::Channel.new + + # The server simply subscribes client connections to the channel on connect, + # and unsubscribes them on disconnect. + class Server < EM::Connection + def self.start(host = '127.0.0.1', port = 8000) + EM.start_server(host, port, self) + end + + def post_init + @sid = RandChannel.subscribe { |m| send_data "#{m.inspect}\n" } + end + + def unbind + RandChannel.unsubscribe @sid + end + end + Server.start + + # Two client connections, that just print what they receive. + 2.times do + EM.connect('127.0.0.1', 8000) do |c| + c.extend EM::P::LineText2 + def c.receive_line(line) + puts "Subscriber: #{signature} got #{line}" + end + EM.add_timer(2) { c.close_connection } + end + end + + # This part of the example is more fake, but imagine sleep was in fact a + # long running calculation to achieve the value. + 40.times do + EM.defer lambda { v = sleep(rand * 2); RandChannel << [Time.now, v] } + end + + EM.add_timer(5) { EM.stop } +end diff --git a/bin/gems/eventmachine-1.2.7/examples/old/ex_queue.rb b/bin/gems/eventmachine-1.2.7/examples/old/ex_queue.rb new file mode 100644 index 00000000..761ea764 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/old/ex_queue.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/helper' + diff --git a/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_array.rb b/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_array.rb new file mode 100644 index 00000000..81b0ae3e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_array.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/helper' + +EM.run do + array = (1..100).to_a + + tickloop = EM.tick_loop do + if array.empty? + :stop + else + puts array.shift + end + end + + tickloop.on_stop { EM.stop } +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_counter.rb b/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_counter.rb new file mode 100644 index 00000000..58e51ffd --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/old/ex_tick_loop_counter.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/helper' + +class TickCounter + attr_reader :start_time, :count + + def initialize + reset + @tick_loop = EM.tick_loop(method(:tick)) + end + + def reset + @count = 0 + @start_time = EM.current_time + end + + def tick + @count += 1 + end + + def rate + @count / (EM.current_time - @start_time) + end +end + +period = 5 +EM.run do + counter = TickCounter.new + EM.add_periodic_timer(period) do + puts "Ticks per second: #{counter.rate} (mean of last #{period}s)" + counter.reset + end +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/examples/old/helper.rb b/bin/gems/eventmachine-1.2.7/examples/old/helper.rb new file mode 100644 index 00000000..835ded27 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/examples/old/helper.rb @@ -0,0 +1,2 @@ +$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') +require 'eventmachine' \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/ext/Makefile b/bin/gems/eventmachine-1.2.7/ext/Makefile new file mode 100644 index 00000000..77f37c87 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/Makefile @@ -0,0 +1,269 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = . +topdir = /usr/include/ruby-3.2.0 +hdrdir = $(topdir) +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR)/etc +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ +LIBRUBY = $(LIBRUBY_SO) +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = -fPIC +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = +CPPFLAGS = -DHAVE_OPENSSL_SSL_H -DHAVE_OPENSSL_ERR_H -DWITH_SSL -DBUILD_FOR_RUBY -DHAVE_RB_THREAD_CALL_WITHOUT_GVL -DHAVE_RB_THREAD_FD_SELECT -DHAVE_TYPE_RB_FDSET_T -DHAVE_RB_WAIT_FOR_SINGLE_FD -DHAVE_RB_TIME_NEW -DHAVE_INOTIFY_INIT -DHAVE_INOTIFY -DHAVE_WRITEV -DHAVE_PIPE2 -DHAVE_ACCEPT4 -DHAVE_CONST_SOCK_CLOEXEC -DOS_UNIX -DHAVE_EPOLL_CREATE -DHAVE_EPOLL -DHAVE_CLOCK_GETTIME -DHAVE_CONST_CLOCK_MONOTONIC_RAW -DHAVE_CONST_CLOCK_MONOTONIC -DHAVE_MAKE_PAIR -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CXX) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-linux-gnu-gcc-ar +EXEEXT = + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 +RUBYW_INSTALL_NAME = +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x86_64-linux-gnu +sitearch = $(arch) +ruby_version = 3.2.0 +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 +RUBY = $(ruby) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h + +RM = rm -f +RM_RF = rm -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) +DEFFILE = + +CLEANFILES = mkmf.log +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lssl -lcrypto -lcrypto -lssl -lm -lpthread -lc +ORIG_SRCS = binder.cpp cmain.cpp ed.cpp em.cpp kb.cpp page.cpp pipe.cpp rubymain.cpp ssl.cpp +SRCS = $(ORIG_SRCS) +OBJS = binder.o cmain.o ed.o em.o kb.o page.o pipe.o rubymain.o ssl.o +HDRS = $(srcdir)/binder.h $(srcdir)/ed.h $(srcdir)/em.h $(srcdir)/eventmachine.h $(srcdir)/page.h $(srcdir)/project.h $(srcdir)/ssl.h +LOCAL_HDRS = +TARGET = rubyeventmachine +TARGET_NAME = rubyeventmachine +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = $(OBJS) *.bak +TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP) + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + -$(Q)$(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TARGET_SO_DIR_TIMESTAMP): + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(OBJS) Makefile + $(ECHO) linking shared-object $(DLLIB) + -$(Q)$(RM) $(@) + $(Q) $(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) + + + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/bin/gems/eventmachine-1.2.7/ext/binder.cpp b/bin/gems/eventmachine-1.2.7/ext/binder.cpp new file mode 100644 index 00000000..5b90876e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/binder.cpp @@ -0,0 +1,124 @@ +/***************************************************************************** + +$Id$ + +File: binder.cpp +Date: 07Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" + +#define DEV_URANDOM "/dev/urandom" + + +std::map Bindable_t::BindingBag; + + +/******************************** +STATIC Bindable_t::CreateBinding +********************************/ + +uintptr_t Bindable_t::CreateBinding() +{ + static uintptr_t num = 0; + while(BindingBag[++num]) {} + return num; +} + +#if 0 +string Bindable_t::CreateBinding() +{ + static int index = 0; + static string seed; + + if ((index >= 1000000) || (seed.length() == 0)) { + #ifdef OS_UNIX + int fd = open (DEV_URANDOM, O_RDONLY); + if (fd < 0) + throw std::runtime_error ("No entropy device"); + + unsigned char u[16]; + size_t r = read (fd, u, sizeof(u)); + if (r < sizeof(u)) + throw std::runtime_error ("Unable to read entropy device"); + + unsigned char *u1 = (unsigned char*)u; + char u2 [sizeof(u) * 2 + 1]; + + for (size_t i=0; i < sizeof(u); i++) + sprintf (u2 + (i * 2), "%02x", u1[i]); + + seed = string (u2); + #endif + + + #ifdef OS_WIN32 + UUID uuid; + UuidCreate (&uuid); + unsigned char *uuidstring = NULL; + UuidToString (&uuid, &uuidstring); + if (!uuidstring) + throw std::runtime_error ("Unable to read uuid"); + seed = string ((const char*)uuidstring); + + RpcStringFree (&uuidstring); + #endif + + index = 0; + + + } + + stringstream ss; + ss << seed << (++index); + return ss.str(); +} +#endif + +/***************************** +STATIC: Bindable_t::GetObject +*****************************/ + +Bindable_t *Bindable_t::GetObject (const uintptr_t binding) +{ + std::map::const_iterator i = BindingBag.find (binding); + if (i != BindingBag.end()) + return i->second; + else + return NULL; +} + + +/********************** +Bindable_t::Bindable_t +**********************/ + +Bindable_t::Bindable_t() +{ + Binding = Bindable_t::CreateBinding(); + BindingBag [Binding] = this; +} + + + +/*********************** +Bindable_t::~Bindable_t +***********************/ + +Bindable_t::~Bindable_t() NO_EXCEPT_FALSE +{ + BindingBag.erase (Binding); +} + + diff --git a/bin/gems/eventmachine-1.2.7/ext/binder.h b/bin/gems/eventmachine-1.2.7/ext/binder.h new file mode 100644 index 00000000..dd32c8d4 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/binder.h @@ -0,0 +1,52 @@ +/***************************************************************************** + +$Id$ + +File: binder.h +Date: 07Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#ifndef __ObjectBindings__H_ +#define __ObjectBindings__H_ + + +#if __cplusplus >= 201103L +#define NO_EXCEPT_FALSE noexcept(false) +#else +#define NO_EXCEPT_FALSE +#endif + +class Bindable_t +{ + public: + static uintptr_t CreateBinding(); + static Bindable_t *GetObject (const uintptr_t); + static std::map BindingBag; + + public: + Bindable_t(); + virtual ~Bindable_t() NO_EXCEPT_FALSE; + + const uintptr_t GetBinding() {return Binding;} + + private: + uintptr_t Binding; +}; + + + + + +#endif // __ObjectBindings__H_ + diff --git a/bin/gems/eventmachine-1.2.7/ext/cmain.cpp b/bin/gems/eventmachine-1.2.7/ext/cmain.cpp new file mode 100644 index 00000000..f58c2cde --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/cmain.cpp @@ -0,0 +1,988 @@ +/***************************************************************************** + +$Id$ + +File: cmain.cpp +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" + +/* 21Sep09: ruby 1.9 defines macros for common i/o functions that point to rb_w32_* implementations. + We need to undef the stat to fix a build failure in evma_send_file_data_to_connection. + See http://groups.google.com/group/eventmachine/browse_thread/thread/fc60d9bb738ffc71 +*/ +#if defined(BUILD_FOR_RUBY) && defined(OS_WIN32) +#undef stat +#undef fstat +#endif + +static EventMachine_t *EventMachine; +static Poller_t Poller = Poller_Default; + +extern "C" void ensure_eventmachine (const char *caller = "unknown caller") +{ + if (!EventMachine) { + const int err_size = 128; + char err_string[err_size]; + snprintf (err_string, err_size, "eventmachine not initialized: %s", caller); + #ifdef BUILD_FOR_RUBY + rb_raise(rb_eRuntimeError, "%s", err_string); + #else + throw std::runtime_error (err_string); + #endif + } +} + +/*********************** +evma_initialize_library +***********************/ + +extern "C" void evma_initialize_library (EMCallback cb) +{ + if (EventMachine) + #ifdef BUILD_FOR_RUBY + rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_initialize_library"); + #else + throw std::runtime_error ("eventmachine already initialized: evma_initialize_library"); + #endif + + EventMachine = new EventMachine_t (cb, Poller); +} + + +/******************** +evma_release_library +********************/ + +extern "C" void evma_release_library() +{ + ensure_eventmachine("evma_release_library"); + delete EventMachine; + EventMachine = NULL; +} + + +/********************* +evma_run_machine_once +*********************/ + +extern "C" bool evma_run_machine_once() +{ + ensure_eventmachine("evma_run_machine_once"); + return EventMachine->RunOnce(); +} + + +/**************** +evma_run_machine +****************/ + +extern "C" void evma_run_machine() +{ + ensure_eventmachine("evma_run_machine"); + EventMachine->Run(); +} + + +/************************** +evma_install_oneshot_timer +**************************/ + +extern "C" const uintptr_t evma_install_oneshot_timer (uint64_t milliseconds) +{ + ensure_eventmachine("evma_install_oneshot_timer"); + return EventMachine->InstallOneshotTimer (milliseconds); +} + + +/********************** +evma_connect_to_server +**********************/ + +extern "C" const uintptr_t evma_connect_to_server (const char *bind_addr, int bind_port, const char *server, int port) +{ + ensure_eventmachine("evma_connect_to_server"); + return EventMachine->ConnectToServer (bind_addr, bind_port, server, port); +} + +/*************************** +evma_connect_to_unix_server +***************************/ + +extern "C" const uintptr_t evma_connect_to_unix_server (const char *server) +{ + ensure_eventmachine("evma_connect_to_unix_server"); + return EventMachine->ConnectToUnixServer (server); +} + +/************** +evma_attach_fd +**************/ + +extern "C" const uintptr_t evma_attach_fd (int file_descriptor, int watch_mode) +{ + ensure_eventmachine("evma_attach_fd"); + return EventMachine->AttachFD (file_descriptor, watch_mode ? true : false); +} + +/************** +evma_detach_fd +**************/ + +extern "C" int evma_detach_fd (const uintptr_t binding) +{ + ensure_eventmachine("evma_detach_fd"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return EventMachine->DetachFD (ed); + else + #ifdef BUILD_FOR_RUBY + rb_raise(rb_eRuntimeError, "invalid binding to detach"); + #else + throw std::runtime_error ("invalid binding to detach"); + #endif + return -1; +} + +/************************ +evma_get_file_descriptor +************************/ + +extern "C" int evma_get_file_descriptor (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_file_descriptor"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetSocket(); + else + #ifdef BUILD_FOR_RUBY + rb_raise(rb_eRuntimeError, "invalid binding to get_fd"); + #else + throw std::runtime_error ("invalid binding to get_fd"); + #endif + return -1; +} + +/*********************** +evma_is_notify_readable +***********************/ + +extern "C" int evma_is_notify_readable (const uintptr_t binding) +{ + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + return cd->IsNotifyReadable() ? 1 : 0; + return -1; +} + +/************************ +evma_set_notify_readable +************************/ + +extern "C" void evma_set_notify_readable (const uintptr_t binding, int mode) +{ + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + cd->SetNotifyReadable (mode ? true : false); +} + +/*********************** +evma_is_notify_writable +***********************/ + +extern "C" int evma_is_notify_writable (const uintptr_t binding) +{ + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + return cd->IsNotifyWritable() ? 1 : 0; + return -1; +} + +/************************ +evma_set_notify_writable +************************/ + +extern "C" void evma_set_notify_writable (const uintptr_t binding, int mode) +{ + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + cd->SetNotifyWritable (mode ? true : false); +} + +/********** +evma_pause +**********/ + +extern "C" int evma_pause (const uintptr_t binding) +{ + EventableDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + return cd->Pause() ? 1 : 0; + + return 0; +} + +/*********** +evma_resume +***********/ + +extern "C" int evma_resume (const uintptr_t binding) +{ + EventableDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + return cd->Resume() ? 1 : 0; + + return 0; +} + +/************** +evma_is_paused +**************/ + +extern "C" int evma_is_paused (const uintptr_t binding) +{ + EventableDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + return cd->IsPaused() ? 1 : 0; + + return 0; +} + +/************************ +evma_num_close_scheduled +************************/ + +extern "C" int evma_num_close_scheduled () +{ + ensure_eventmachine("evma_num_close_scheduled"); + return EventMachine->NumCloseScheduled; +} + +/********************** +evma_create_tcp_server +**********************/ + +extern "C" const uintptr_t evma_create_tcp_server (const char *address, int port) +{ + ensure_eventmachine("evma_create_tcp_server"); + return EventMachine->CreateTcpServer (address, port); +} + +/****************************** +evma_create_unix_domain_server +******************************/ + +extern "C" const uintptr_t evma_create_unix_domain_server (const char *filename) +{ + ensure_eventmachine("evma_create_unix_domain_server"); + return EventMachine->CreateUnixDomainServer (filename); +} + +/*********************** +evma_attach_sd +************************/ + +extern "C" const uintptr_t evma_attach_sd (int sd) +{ + ensure_eventmachine("evma_attach_sd"); + return EventMachine->AttachSD (sd); +} + +/************************* +evma_open_datagram_socket +*************************/ + +extern "C" const uintptr_t evma_open_datagram_socket (const char *address, int port) +{ + ensure_eventmachine("evma_open_datagram_socket"); + return EventMachine->OpenDatagramSocket (address, port); +} + +/****************** +evma_open_keyboard +******************/ + +extern "C" const uintptr_t evma_open_keyboard() +{ + ensure_eventmachine("evma_open_keyboard"); + return EventMachine->OpenKeyboard(); +} + +/******************* +evma_watch_filename +*******************/ + +extern "C" const uintptr_t evma_watch_filename (const char *fname) +{ + ensure_eventmachine("evma_watch_filename"); + return EventMachine->WatchFile(fname); +} + +/********************* +evma_unwatch_filename +*********************/ + +extern "C" void evma_unwatch_filename (const uintptr_t sig) +{ + ensure_eventmachine("evma_unwatch_file"); + EventMachine->UnwatchFile(sig); +} + +/************** +evma_watch_pid +**************/ + +extern "C" const uintptr_t evma_watch_pid (int pid) +{ + ensure_eventmachine("evma_watch_pid"); + return EventMachine->WatchPid(pid); +} + +/**************** +evma_unwatch_pid +****************/ + +extern "C" void evma_unwatch_pid (const uintptr_t sig) +{ + ensure_eventmachine("evma_unwatch_pid"); + EventMachine->UnwatchPid(sig); +} + +/**************************** +evma_send_data_to_connection +****************************/ + +extern "C" int evma_send_data_to_connection (const uintptr_t binding, const char *data, int data_length) +{ + ensure_eventmachine("evma_send_data_to_connection"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->SendOutboundData(data, data_length); + return -1; +} + +/****************** +evma_send_datagram +******************/ + +extern "C" int evma_send_datagram (const uintptr_t binding, const char *data, int data_length, const char *address, int port) +{ + ensure_eventmachine("evma_send_datagram"); + DatagramDescriptor *dd = dynamic_cast (Bindable_t::GetObject (binding)); + if (dd) + return dd->SendOutboundDatagram(data, data_length, address, port); + return -1; +} + + +/********************* +evma_close_connection +*********************/ + +extern "C" void evma_close_connection (const uintptr_t binding, int after_writing) +{ + ensure_eventmachine("evma_close_connection"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + ed->ScheduleClose (after_writing ? true : false); +} + +/*********************************** +evma_report_connection_error_status +***********************************/ + +extern "C" int evma_report_connection_error_status (const uintptr_t binding) +{ + ensure_eventmachine("evma_report_connection_error_status"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->ReportErrorStatus(); + return -1; +} + +/******************** +evma_stop_tcp_server +********************/ + +extern "C" void evma_stop_tcp_server (const uintptr_t binding) +{ + ensure_eventmachine("evma_stop_tcp_server"); + AcceptorDescriptor::StopAcceptor (binding); +} + + +/***************** +evma_stop_machine +*****************/ + +extern "C" void evma_stop_machine() +{ + ensure_eventmachine("evma_stop_machine"); + EventMachine->ScheduleHalt(); +} + +/***************** +evma_stopping +*****************/ + +extern "C" bool evma_stopping() +{ + ensure_eventmachine("evma_stopping"); + return EventMachine->Stopping(); +} + +/************** +evma_start_tls +**************/ + +extern "C" void evma_start_tls (const uintptr_t binding) +{ + ensure_eventmachine("evma_start_tls"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + ed->StartTls(); +} + +/****************** +evma_set_tls_parms +******************/ + +extern "C" void evma_set_tls_parms (const uintptr_t binding, const char *privatekey_filename, const char *certchain_filename, int verify_peer, int fail_if_no_peer_cert, const char *sni_hostname, const char *cipherlist, const char *ecdh_curve, const char *dhparam, int ssl_version) +{ + ensure_eventmachine("evma_set_tls_parms"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + ed->SetTlsParms (privatekey_filename, certchain_filename, (verify_peer == 1 ? true : false), (fail_if_no_peer_cert == 1 ? true : false), sni_hostname, cipherlist, ecdh_curve, dhparam, ssl_version); +} + +/****************** +evma_get_peer_cert +******************/ + +#ifdef WITH_SSL +extern "C" X509 *evma_get_peer_cert (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_peer_cert"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetPeerCert(); + return NULL; +} +#endif + +/****************** +evma_get_cipher_bits +******************/ + +#ifdef WITH_SSL +extern "C" int evma_get_cipher_bits (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_cipher_bits"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetCipherBits(); + return -1; +} +#endif + +/****************** +evma_get_cipher_name +******************/ + +#ifdef WITH_SSL +extern "C" const char *evma_get_cipher_name (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_cipher_name"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetCipherName(); + return NULL; +} +#endif + +/****************** +evma_get_cipher_protocol +******************/ + +#ifdef WITH_SSL +extern "C" const char *evma_get_cipher_protocol (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_cipher_protocol"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetCipherProtocol(); + return NULL; +} +#endif + +/****************** +evma_get_sni_hostname +******************/ + +#ifdef WITH_SSL +extern "C" const char *evma_get_sni_hostname (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_sni_hostname"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) + return ed->GetSNIHostname(); + return NULL; +} +#endif + +/******************** +evma_accept_ssl_peer +********************/ + +#ifdef WITH_SSL +extern "C" void evma_accept_ssl_peer (const uintptr_t binding) +{ + ensure_eventmachine("evma_accept_ssl_peer"); + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject (binding)); + if (cd) + cd->AcceptSslPeer(); +} +#endif + +/***************** +evma_get_peername +*****************/ + +extern "C" int evma_get_peername (const uintptr_t binding, struct sockaddr *sa, socklen_t *len) +{ + ensure_eventmachine("evma_get_peername"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ed->GetPeername (sa, len) ? 1 : 0; + } + else + return 0; +} + +/***************** +evma_get_sockname +*****************/ + +extern "C" int evma_get_sockname (const uintptr_t binding, struct sockaddr *sa, socklen_t *len) +{ + ensure_eventmachine("evma_get_sockname"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ed->GetSockname (sa, len) ? 1 : 0; + } + else + return 0; +} + +/*********************** +evma_get_subprocess_pid +***********************/ + +#ifdef OS_UNIX +extern "C" int evma_get_subprocess_pid (const uintptr_t binding, pid_t *pid) +{ + ensure_eventmachine("evma_get_subprocess_pid"); + PipeDescriptor *pd = dynamic_cast (Bindable_t::GetObject (binding)); + if (pd) { + return pd->GetSubprocessPid (pid) ? 1 : 0; + } + else if (pid && EventMachine->SubprocessPid) { + *pid = EventMachine->SubprocessPid; + return 1; + } + else + return 0; +} +#else +extern "C" int evma_get_subprocess_pid (const uintptr_t binding UNUSED, pid_t *pid UNUSED) +{ + return 0; +} +#endif + +/************************** +evma_get_subprocess_status +**************************/ + +extern "C" int evma_get_subprocess_status (const uintptr_t binding UNUSED, int *status) +{ + ensure_eventmachine("evma_get_subprocess_status"); + if (status) { + *status = EventMachine->SubprocessExitStatus; + return 1; + } + else + return 0; +} + +/************************* +evma_get_connection_count +*************************/ + +extern "C" int evma_get_connection_count() +{ + ensure_eventmachine("evma_get_connection_count"); + return EventMachine->GetConnectionCount(); +} + +/********************* +evma_signal_loopbreak +*********************/ + +extern "C" void evma_signal_loopbreak() +{ + ensure_eventmachine("evma_signal_loopbreak"); + EventMachine->SignalLoopBreaker(); +} + + + +/******************************** +evma_get_comm_inactivity_timeout +********************************/ + +extern "C" float evma_get_comm_inactivity_timeout (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_comm_inactivity_timeout"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ((float)ed->GetCommInactivityTimeout() / 1000); + } + else + return 0.0; //Perhaps this should be an exception. Access to an unknown binding. +} + +/******************************** +evma_set_comm_inactivity_timeout +********************************/ + +extern "C" int evma_set_comm_inactivity_timeout (const uintptr_t binding, float value) +{ + ensure_eventmachine("evma_set_comm_inactivity_timeout"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ed->SetCommInactivityTimeout ((uint64_t)(value * 1000)); + } + else + return 0; //Perhaps this should be an exception. Access to an unknown binding. +} + + +/******************************** +evma_get_pending_connect_timeout +********************************/ + +extern "C" float evma_get_pending_connect_timeout (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_pending_connect_timeout"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ((float)ed->GetPendingConnectTimeout() / 1000); + } + else + return 0.0; +} + + +/******************************** +evma_set_pending_connect_timeout +********************************/ + +extern "C" int evma_set_pending_connect_timeout (const uintptr_t binding, float value) +{ + ensure_eventmachine("evma_set_pending_connect_timeout"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + if (ed) { + return ed->SetPendingConnectTimeout ((uint64_t)(value * 1000)); + } + else + return 0; +} + + +/********************** +evma_set_timer_quantum +**********************/ + +extern "C" void evma_set_timer_quantum (int interval) +{ + ensure_eventmachine("evma_set_timer_quantum"); + EventMachine->SetTimerQuantum (interval); +} + + +/************************ +evma_get_max_timer_count +************************/ + +extern "C" int evma_get_max_timer_count() +{ + return EventMachine_t::GetMaxTimerCount(); +} + +/************************ +evma_set_max_timer_count +************************/ + +extern "C" void evma_set_max_timer_count (int ct) +{ + // This may only be called if the reactor is not running. + + if (EventMachine) + #ifdef BUILD_FOR_RUBY + rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_set_max_timer_count"); + #else + throw std::runtime_error ("eventmachine already initialized: evma_set_max_timer_count"); + #endif + EventMachine_t::SetMaxTimerCount (ct); +} + +/****************** +evma_get/set_simultaneous_accept_count +******************/ + +extern "C" void evma_set_simultaneous_accept_count (int count) +{ + EventMachine_t::SetSimultaneousAcceptCount(count); +} + +extern "C" int evma_get_simultaneous_accept_count() +{ + return EventMachine_t::GetSimultaneousAcceptCount(); +} + + +/****************** +evma_setuid_string +******************/ + +extern "C" void evma_setuid_string (const char *username) +{ + // We do NOT need to be running an EM instance because this method is static. + EventMachine_t::SetuidString (username); +} + + +/********** +evma_popen +**********/ + +extern "C" const uintptr_t evma_popen (char * const*cmd_strings) +{ + ensure_eventmachine("evma_popen"); + return EventMachine->Socketpair (cmd_strings); +} + + +/*************************** +evma_get_outbound_data_size +***************************/ + +extern "C" int evma_get_outbound_data_size (const uintptr_t binding) +{ + ensure_eventmachine("evma_get_outbound_data_size"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (binding)); + return ed ? ed->GetOutboundDataSize() : 0; +} + + +/************** +evma_set_epoll +**************/ + +extern "C" void evma_set_epoll (int use) +{ + if (use) + Poller = Poller_Epoll; + else + Poller = Poller_Default; +} + +/*************** +evma_set_kqueue +***************/ + +extern "C" void evma_set_kqueue (int use) +{ + if (use) + Poller = Poller_Kqueue; + else + Poller = Poller_Default; +} + + +/********************** +evma_set_rlimit_nofile +**********************/ + +extern "C" int evma_set_rlimit_nofile (int nofiles) +{ + return EventMachine_t::SetRlimitNofile (nofiles); +} + + +/********************************* +evma_send_file_data_to_connection +*********************************/ + +extern "C" int evma_send_file_data_to_connection (const uintptr_t binding, const char *filename) +{ + /* This is a sugaring over send_data_to_connection that reads a file into a + * locally-allocated buffer, and sends the file data to the remote peer. + * Return the number of bytes written to the caller. + * TODO, needs to impose a limit on the file size. This is intended only for + * small files. (I don't know, maybe 8K or less.) For larger files, use interleaved + * I/O to avoid slowing the rest of the system down. + * TODO: we should return a code rather than barf, in case of file-not-found. + * TODO, does this compile on Windows? + * TODO, given that we want this to work only with small files, how about allocating + * the buffer on the stack rather than the heap? + * + * Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive + * errno in case of other errors. + * + * Contributed by Kirk Haines. + */ + + char data[32*1024]; + int r; + + ensure_eventmachine("evma_send_file_data_to_connection"); + +#if defined(OS_WIN32) + int Fd = open (filename, O_RDONLY|O_BINARY); +#else + int Fd = open (filename, O_RDONLY); +#endif + if (Fd < 0) + return errno; + // From here on, all early returns MUST close Fd. + + struct stat st; + if (fstat (Fd, &st)) { + int e = errno; + close (Fd); + return e; + } + + off_t filesize = st.st_size; + if (filesize <= 0) { + close (Fd); + return 0; + } + else if (filesize > (off_t) sizeof(data)) { + close (Fd); + return -1; + } + + r = read (Fd, data, filesize); + if (r != filesize) { + int e = errno; + close (Fd); + return e; + } + evma_send_data_to_connection (binding, data, r); + close (Fd); + + return 0; +} + + +/**************** +evma_start_proxy +*****************/ + +extern "C" void evma_start_proxy (const uintptr_t from, const uintptr_t to, const unsigned long bufsize, const unsigned long length) +{ + ensure_eventmachine("evma_start_proxy"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (from)); + if (ed) + ed->StartProxy(to, bufsize, length); +} + + +/*************** +evma_stop_proxy +****************/ + +extern "C" void evma_stop_proxy (const uintptr_t from) +{ + ensure_eventmachine("evma_stop_proxy"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (from)); + if (ed) + ed->StopProxy(); +} + +/****************** +evma_proxied_bytes +*******************/ + +extern "C" unsigned long evma_proxied_bytes (const uintptr_t from) +{ + ensure_eventmachine("evma_proxied_bytes"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (from)); + if (ed) + return ed->GetProxiedBytes(); + else + return 0; +} + + +/*************************** +evma_get_last_activity_time +****************************/ + +extern "C" uint64_t evma_get_last_activity_time(const uintptr_t from) +{ + ensure_eventmachine("evma_get_last_activity_time"); + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (from)); + if (ed) + return ed->GetLastActivity(); + else + return 0; +} + + +/*************************** +evma_get_heartbeat_interval +****************************/ + +extern "C" float evma_get_heartbeat_interval() +{ + ensure_eventmachine("evma_get_heartbeat_interval"); + return EventMachine->GetHeartbeatInterval(); +} + + +/*************************** +evma_set_heartbeat_interval +****************************/ + +extern "C" int evma_set_heartbeat_interval(float interval) +{ + ensure_eventmachine("evma_set_heartbeat_interval"); + return EventMachine->SetHeartbeatInterval(interval); +} + + +/************************** +evma_get_current_loop_time +***************************/ + +extern "C" uint64_t evma_get_current_loop_time() +{ + ensure_eventmachine("evma_get_current_loop_time"); + return EventMachine->GetCurrentLoopTime(); +} diff --git a/bin/gems/eventmachine-1.2.7/ext/ed.cpp b/bin/gems/eventmachine-1.2.7/ext/ed.cpp new file mode 100644 index 00000000..a469dff0 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/ed.cpp @@ -0,0 +1,2096 @@ +/***************************************************************************** + +$Id$ + +File: ed.cpp +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" + + + +/******************** +SetSocketNonblocking +********************/ + +bool SetSocketNonblocking (SOCKET sd) +{ + #ifdef OS_UNIX + int val = fcntl (sd, F_GETFL, 0); + return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false; + #endif + + #ifdef OS_WIN32 + #ifdef BUILD_FOR_RUBY + // 14Jun09 Ruby provides its own wrappers for ioctlsocket. On 1.8 this is a simple wrapper, + // however, 1.9 keeps its own state about the socket. + // NOTE: F_GETFL is not supported + return (fcntl (sd, F_SETFL, O_NONBLOCK) == 0) ? true : false; + #else + unsigned long one = 1; + return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false; + #endif + #endif +} + +/************ +SetFdCloexec +************/ + +#ifdef OS_UNIX +bool SetFdCloexec (int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + assert (flags >= 0); + flags |= FD_CLOEXEC; + return (fcntl(fd, F_SETFD, FD_CLOEXEC) == 0) ? true : false; +} +#else +bool SetFdCloexec (int fd UNUSED) +{ + return true; +} +#endif + +/**************************************** +EventableDescriptor::EventableDescriptor +****************************************/ + +EventableDescriptor::EventableDescriptor (SOCKET sd, EventMachine_t *em): + bCloseNow (false), + bCloseAfterWriting (false), + MySocket (sd), + bAttached (false), + bWatchOnly (false), + EventCallback (NULL), + bCallbackUnbind (true), + UnbindReasonCode (0), + ProxyTarget(NULL), + ProxiedFrom(NULL), + ProxiedBytes(0), + MaxOutboundBufSize(0), + MyEventMachine (em), + PendingConnectTimeout(20000000), + InactivityTimeout (0), + NextHeartbeat (0), + bPaused (false) +{ + /* There are three ways to close a socket, all of which should + * automatically signal to the event machine that this object + * should be removed from the polling scheduler. + * First is a hard close, intended for bad errors or possible + * security violations. It immediately closes the connection + * and puts this object into an error state. + * Second is to set bCloseNow, which will cause the event machine + * to delete this object (and thus close the connection in our + * destructor) the next chance it gets. bCloseNow also inhibits + * the writing of new data on the socket (but not necessarily + * the reading of new data). + * The third way is to set bCloseAfterWriting, which inhibits + * the writing of new data and converts to bCloseNow as soon + * as everything in the outbound queue has been written. + * bCloseAfterWriting is really for use only by protocol handlers + * (for example, HTTP writes an HTML page and then closes the + * connection). All of the error states we generate internally + * cause an immediate close to be scheduled, which may have the + * effect of discarding outbound data. + */ + + if (sd == INVALID_SOCKET) + throw std::runtime_error ("bad eventable descriptor"); + if (MyEventMachine == NULL) + throw std::runtime_error ("bad em in eventable descriptor"); + CreatedAt = MyEventMachine->GetCurrentLoopTime(); + LastActivity = MyEventMachine->GetCurrentLoopTime(); + + #ifdef HAVE_EPOLL + EpollEvent.events = 0; + EpollEvent.data.ptr = this; + #endif +} + + +/***************************************** +EventableDescriptor::~EventableDescriptor +*****************************************/ + +EventableDescriptor::~EventableDescriptor() NO_EXCEPT_FALSE +{ + if (NextHeartbeat) + MyEventMachine->ClearHeartbeat(NextHeartbeat, this); + if (EventCallback && bCallbackUnbind) + (*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode); + if (ProxiedFrom) { + (*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0); + ProxiedFrom->StopProxy(); + } + MyEventMachine->NumCloseScheduled--; + StopProxy(); + Close(); +} + + +/************************************* +EventableDescriptor::SetEventCallback +*************************************/ + +void EventableDescriptor::SetEventCallback (EMCallback cb) +{ + EventCallback = cb; +} + + +/************************** +EventableDescriptor::Close +**************************/ + +void EventableDescriptor::Close() +{ + /* EventMachine relies on the fact that when close(fd) + * is called that the fd is removed from any + * epoll event queues. + * + * However, this is not *always* the behavior of close(fd) + * + * See man 4 epoll Q6/A6 and then consider what happens + * when using pipes with eventmachine. + * (As is often done when communicating with a subprocess) + * + * The pipes end up looking like: + * + * ls -l /proc//fd + * ... + * lr-x------ 1 root root 64 2011-08-19 21:31 3 -> pipe:[940970] + * l-wx------ 1 root root 64 2011-08-19 21:31 4 -> pipe:[940970] + * + * This meets the critera from man 4 epoll Q6/A4 for not + * removing fds from epoll event queues until all fds + * that reference the underlying file have been removed. + * + * If the EventableDescriptor associated with fd 3 is deleted, + * its dtor will call EventableDescriptor::Close(), + * which will call ::close(int fd). + * + * However, unless the EventableDescriptor associated with fd 4 is + * also deleted before the next call to epoll_wait, events may fire + * for fd 3 that were registered with an already deleted + * EventableDescriptor. + * + * Therefore, it is necessary to notify EventMachine that + * the fd associated with this EventableDescriptor is + * closing. + * + * EventMachine also never closes fds for STDIN, STDOUT and + * STDERR (0, 1 & 2) + */ + + // Close the socket right now. Intended for emergencies. + if (MySocket != INVALID_SOCKET) { + MyEventMachine->Deregister (this); + + // Do not close STDIN, STDOUT, STDERR + if (MySocket > 2 && !bAttached) { + shutdown (MySocket, 1); + close (MySocket); + } + + MySocket = INVALID_SOCKET; + } +} + + +/********************************* +EventableDescriptor::ShouldDelete +*********************************/ + +bool EventableDescriptor::ShouldDelete() +{ + /* For use by a socket manager, which needs to know if this object + * should be removed from scheduling events and deleted. + * Has an immediate close been scheduled, or are we already closed? + * If either of these are the case, return true. In theory, the manager will + * then delete us, which in turn will make sure the socket is closed. + * Note, if bCloseAfterWriting is true, we check a virtual method to see + * if there is outbound data to write, and only request a close if there is none. + */ + + return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0))); +} + + +/********************************** +EventableDescriptor::ScheduleClose +**********************************/ + +void EventableDescriptor::ScheduleClose (bool after_writing) +{ + if (IsCloseScheduled()) { + if (!after_writing) { + // If closing has become more urgent, then upgrade the scheduled + // after_writing close to one NOW. + bCloseNow = true; + } + return; + } + MyEventMachine->NumCloseScheduled++; + // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled. + if (after_writing) + bCloseAfterWriting = true; + else + bCloseNow = true; +} + + +/************************************* +EventableDescriptor::IsCloseScheduled +*************************************/ + +bool EventableDescriptor::IsCloseScheduled() +{ + // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose. + return (bCloseNow || bCloseAfterWriting); +} + + +/******************************* +EventableDescriptor::StartProxy +*******************************/ + +void EventableDescriptor::StartProxy(const uintptr_t to, const unsigned long bufsize, const unsigned long length) +{ + EventableDescriptor *ed = dynamic_cast (Bindable_t::GetObject (to)); + if (ed) { + StopProxy(); + ProxyTarget = ed; + BytesToProxy = length; + ProxiedBytes = 0; + ed->SetProxiedFrom(this, bufsize); + return; + } + throw std::runtime_error ("Tried to proxy to an invalid descriptor"); +} + + +/****************************** +EventableDescriptor::StopProxy +******************************/ + +void EventableDescriptor::StopProxy() +{ + if (ProxyTarget) { + ProxyTarget->SetProxiedFrom(NULL, 0); + ProxyTarget = NULL; + } +} + + +/*********************************** +EventableDescriptor::SetProxiedFrom +***********************************/ + +void EventableDescriptor::SetProxiedFrom(EventableDescriptor *from, const unsigned long bufsize) +{ + if (from != NULL && ProxiedFrom != NULL) + throw std::runtime_error ("Tried to proxy to a busy target"); + + ProxiedFrom = from; + MaxOutboundBufSize = bufsize; +} + + +/******************************************** +EventableDescriptor::_GenericInboundDispatch +********************************************/ + +void EventableDescriptor::_GenericInboundDispatch(const char *buf, unsigned long size) +{ + assert(EventCallback); + + if (ProxyTarget) { + if (BytesToProxy > 0) { + unsigned long proxied = std::min(BytesToProxy, size); + ProxyTarget->SendOutboundData(buf, proxied); + ProxiedBytes += (unsigned long) proxied; + BytesToProxy -= proxied; + if (BytesToProxy == 0) { + StopProxy(); + (*EventCallback)(GetBinding(), EM_PROXY_COMPLETED, NULL, 0); + if (proxied < size) { + (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf + proxied, size - proxied); + } + } + } else { + ProxyTarget->SendOutboundData(buf, size); + ProxiedBytes += size; + } + } else { + (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size); + } +} + + +/********************************* +EventableDescriptor::_GenericGetPeername +*********************************/ + +bool EventableDescriptor::_GenericGetPeername (struct sockaddr *s, socklen_t *len) +{ + if (!s) + return false; + + int gp = getpeername (GetSocket(), s, len); + if (gp == -1) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "unable to get peer name: %s", strerror(errno)); + throw std::runtime_error (buf); + } + + return true; +} + +/********************************* +EventableDescriptor::_GenericGetSockname +*********************************/ + +bool EventableDescriptor::_GenericGetSockname (struct sockaddr *s, socklen_t *len) +{ + if (!s) + return false; + + int gp = getsockname (GetSocket(), s, len); + if (gp == -1) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "unable to get sock name: %s", strerror(errno)); + throw std::runtime_error (buf); + } + + return true; +} + + +/********************************************* +EventableDescriptor::GetPendingConnectTimeout +*********************************************/ + +uint64_t EventableDescriptor::GetPendingConnectTimeout() +{ + return PendingConnectTimeout / 1000; +} + + +/********************************************* +EventableDescriptor::SetPendingConnectTimeout +*********************************************/ + +int EventableDescriptor::SetPendingConnectTimeout (uint64_t value) +{ + if (value > 0) { + PendingConnectTimeout = value * 1000; + MyEventMachine->QueueHeartbeat(this); + return 1; + } + return 0; +} + + +/************************************* +EventableDescriptor::GetNextHeartbeat +*************************************/ + +uint64_t EventableDescriptor::GetNextHeartbeat() +{ + if (NextHeartbeat) + MyEventMachine->ClearHeartbeat(NextHeartbeat, this); + + NextHeartbeat = 0; + + if (!ShouldDelete()) { + uint64_t time_til_next = InactivityTimeout; + if (IsConnectPending()) { + if (time_til_next == 0 || PendingConnectTimeout < time_til_next) + time_til_next = PendingConnectTimeout; + } + if (time_til_next == 0) + return 0; + NextHeartbeat = time_til_next + MyEventMachine->GetRealTime(); + } + + return NextHeartbeat; +} + + +/****************************************** +ConnectionDescriptor::ConnectionDescriptor +******************************************/ + +ConnectionDescriptor::ConnectionDescriptor (SOCKET sd, EventMachine_t *em): + EventableDescriptor (sd, em), + bConnectPending (false), + bNotifyReadable (false), + bNotifyWritable (false), + bReadAttemptedAfterClose (false), + bWriteAttemptedAfterClose (false), + OutboundDataSize (0), + #ifdef WITH_SSL + SslBox (NULL), + bHandshakeSignaled (false), + bSslVerifyPeer (false), + bSslPeerAccepted(false), + #endif + #ifdef HAVE_KQUEUE + bGotExtraKqueueEvent(false), + #endif + bIsServer (false) +{ + // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData() + // 5May09: Moved EPOLLOUT into SetConnectPending() so it doesn't happen for attached read pipes +} + + +/******************************************* +ConnectionDescriptor::~ConnectionDescriptor +*******************************************/ + +ConnectionDescriptor::~ConnectionDescriptor() +{ + // Run down any stranded outbound data. + for (size_t i=0; i < OutboundPages.size(); i++) + OutboundPages[i].Free(); + + #ifdef WITH_SSL + if (SslBox) + delete SslBox; + #endif +} + + +/*********************************** +ConnectionDescriptor::_UpdateEvents +************************************/ + +void ConnectionDescriptor::_UpdateEvents() +{ + _UpdateEvents(true, true); +} + +void ConnectionDescriptor::_UpdateEvents(bool read, bool write) +{ + if (MySocket == INVALID_SOCKET) + return; + + if (!read && !write) + return; + + #ifdef HAVE_EPOLL + unsigned int old = EpollEvent.events; + + if (read) { + if (SelectForRead()) + EpollEvent.events |= EPOLLIN; + else + EpollEvent.events &= ~EPOLLIN; + } + + if (write) { + if (SelectForWrite()) + EpollEvent.events |= EPOLLOUT; + else + EpollEvent.events &= ~EPOLLOUT; + } + + if (old != EpollEvent.events) + MyEventMachine->Modify (this); + #endif + + #ifdef HAVE_KQUEUE + if (read && SelectForRead()) + MyEventMachine->ArmKqueueReader (this); + bKqueueArmWrite = SelectForWrite(); + if (write && bKqueueArmWrite) + MyEventMachine->Modify (this); + #endif +} + +/*************************************** +ConnectionDescriptor::SetConnectPending +****************************************/ + +void ConnectionDescriptor::SetConnectPending(bool f) +{ + bConnectPending = f; + MyEventMachine->QueueHeartbeat(this); + _UpdateEvents(); +} + + +/********************************** +ConnectionDescriptor::SetAttached +***********************************/ + +void ConnectionDescriptor::SetAttached(bool state) +{ + bAttached = state; +} + + +/********************************** +ConnectionDescriptor::SetWatchOnly +***********************************/ + +void ConnectionDescriptor::SetWatchOnly(bool watching) +{ + bWatchOnly = watching; + _UpdateEvents(); +} + + +/********************************* +ConnectionDescriptor::HandleError +*********************************/ + +void ConnectionDescriptor::HandleError() +{ + if (bWatchOnly) { + // An EPOLLHUP | EPOLLIN condition will call Read() before HandleError(), in which case the + // socket is already detached and invalid, so we don't need to do anything. + if (MySocket == INVALID_SOCKET) return; + + // HandleError() is called on WatchOnly descriptors by the epoll reactor + // when it gets a EPOLLERR | EPOLLHUP. Usually this would show up as a readable and + // writable event on other reactors, so we have to fire those events ourselves. + if (bNotifyReadable) Read(); + if (bNotifyWritable) Write(); + } else { + ScheduleClose (false); + } +} + + +/*********************************** +ConnectionDescriptor::ScheduleClose +***********************************/ + +void ConnectionDescriptor::ScheduleClose (bool after_writing) +{ + if (bWatchOnly) + throw std::runtime_error ("cannot close 'watch only' connections"); + + EventableDescriptor::ScheduleClose(after_writing); +} + + +/*************************************** +ConnectionDescriptor::SetNotifyReadable +****************************************/ + +void ConnectionDescriptor::SetNotifyReadable(bool readable) +{ + if (!bWatchOnly) + throw std::runtime_error ("notify_readable must be on 'watch only' connections"); + + bNotifyReadable = readable; + _UpdateEvents(true, false); +} + + +/*************************************** +ConnectionDescriptor::SetNotifyWritable +****************************************/ + +void ConnectionDescriptor::SetNotifyWritable(bool writable) +{ + if (!bWatchOnly) + throw std::runtime_error ("notify_writable must be on 'watch only' connections"); + + bNotifyWritable = writable; + _UpdateEvents(false, true); +} + + +/************************************** +ConnectionDescriptor::SendOutboundData +**************************************/ + +int ConnectionDescriptor::SendOutboundData (const char *data, unsigned long length) +{ + if (bWatchOnly) + throw std::runtime_error ("cannot send data on a 'watch only' connection"); + + if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)(GetOutboundDataSize() + length) > MaxOutboundBufSize) + ProxiedFrom->Pause(); + + #ifdef WITH_SSL + if (SslBox) { + if (length > 0) { + unsigned long writed = 0; + char *p = (char*)data; + + while (writed < length) { + int to_write = SSLBOX_INPUT_CHUNKSIZE; + int remaining = length - writed; + + if (remaining < SSLBOX_INPUT_CHUNKSIZE) + to_write = remaining; + + int w = SslBox->PutPlaintext (p, to_write); + if (w < 0) { + ScheduleClose (false); + }else + _DispatchCiphertext(); + + p += to_write; + writed += to_write; + } + } + // TODO: What's the correct return value? + return 1; // That's a wild guess, almost certainly wrong. + } + else + #endif + return _SendRawOutboundData (data, length); +} + + + +/****************************************** +ConnectionDescriptor::_SendRawOutboundData +******************************************/ + +int ConnectionDescriptor::_SendRawOutboundData (const char *data, unsigned long length) +{ + /* This internal method is called to schedule bytes that + * will be sent out to the remote peer. + * It's not directly accessed by the caller, who hits ::SendOutboundData, + * which may or may not filter or encrypt the caller's data before + * sending it here. + */ + + // Highly naive and incomplete implementation. + // There's no throttle for runaways (which should abort only this connection + // and not the whole process), and no coalescing of small pages. + // (Well, not so bad, small pages are coalesced in ::Write) + + if (IsCloseScheduled()) + return 0; + // 25Mar10: Ignore 0 length packets as they are not meaningful in TCP (as opposed to UDP) + // and can cause the assert(nbytes>0) to fail when OutboundPages has a bunch of 0 length pages. + if (length == 0) + return 0; + + if (!data && (length > 0)) + throw std::runtime_error ("bad outbound data"); + char *buffer = (char *) malloc (length + 1); + if (!buffer) + throw std::runtime_error ("no allocation for outbound data"); + + memcpy (buffer, data, length); + buffer [length] = 0; + OutboundPages.push_back (OutboundPage (buffer, length)); + OutboundDataSize += length; + + _UpdateEvents(false, true); + + return length; +} + + + +/*********************************** +ConnectionDescriptor::SelectForRead +***********************************/ + +bool ConnectionDescriptor::SelectForRead() +{ + /* A connection descriptor is always scheduled for read, + * UNLESS it's in a pending-connect state. + * On Linux, unlike Unix, a nonblocking socket on which + * connect has been called, does NOT necessarily select + * both readable and writable in case of error. + * The socket will select writable when the disposition + * of the connect is known. On the other hand, a socket + * which successfully connects and selects writable may + * indeed have some data available on it, so it will + * select readable in that case, violating expectations! + * So we will not poll for readability until the socket + * is known to be in a connected state. + */ + + if (bPaused) + return false; + else if (bConnectPending) + return false; + else if (bWatchOnly) + return bNotifyReadable ? true : false; + else + return true; +} + + +/************************************ +ConnectionDescriptor::SelectForWrite +************************************/ + +bool ConnectionDescriptor::SelectForWrite() +{ + /* Cf the notes under SelectForRead. + * In a pending-connect state, we ALWAYS select for writable. + * In a normal state, we only select for writable when we + * have outgoing data to send. + */ + + if (bPaused) + return false; + else if (bConnectPending) + return true; + else if (bWatchOnly) + return bNotifyWritable ? true : false; + else + return (GetOutboundDataSize() > 0); +} + +/*************************** +ConnectionDescriptor::Pause +***************************/ + +bool ConnectionDescriptor::Pause() +{ + if (bWatchOnly) + throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead"); + + bool old = bPaused; + bPaused = true; + _UpdateEvents(); + return old == false; +} + +/**************************** +ConnectionDescriptor::Resume +****************************/ + +bool ConnectionDescriptor::Resume() +{ + if (bWatchOnly) + throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead"); + + bool old = bPaused; + bPaused = false; + _UpdateEvents(); + return old == true; +} + +/************************** +ConnectionDescriptor::Read +**************************/ + +void ConnectionDescriptor::Read() +{ + /* Read and dispatch data on a socket that has selected readable. + * It's theoretically possible to get and dispatch incoming data on + * a socket that has already been scheduled for closing or close-after-writing. + * In those cases, we'll leave it up the to protocol handler to "do the + * right thing" (which probably means to ignore the incoming data). + * + * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come + * here with the socket already closed, after the process receives + * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application + * was one in which network connections were doing a lot of interleaved reads + * and writes. + * Since we always write before reading (in order to keep the outbound queues + * as light as possible), I think what happened is that an interrupt caused + * the socket to be closed in ConnectionDescriptor::Write. We'll then + * come here in the same pass through the main event loop, and won't get + * cleaned up until immediately after. + * We originally asserted that the socket was valid when we got here. + * To deal properly with the possibility that we are closed when we get here, + * I removed the assert. HOWEVER, the potential for an infinite loop scares me, + * so even though this is really clunky, I added a flag to assert that we never + * come here more than once after being closed. (FCianfrocca) + */ + + SOCKET sd = GetSocket(); + //assert (sd != INVALID_SOCKET); (original, removed 22Aug06) + if (sd == INVALID_SOCKET) { + assert (!bReadAttemptedAfterClose); + bReadAttemptedAfterClose = true; + return; + } + + if (bWatchOnly) { + if (bNotifyReadable && EventCallback) + (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0); + return; + } + + LastActivity = MyEventMachine->GetCurrentLoopTime(); + + int total_bytes_read = 0; + char readbuffer [16 * 1024 + 1]; + + for (int i=0; i < 10; i++) { + // Don't read just one buffer and then move on. This is faster + // if there is a lot of incoming. + // But don't read indefinitely. Give other sockets a chance to run. + // NOTICE, we're reading one less than the buffer size. + // That's so we can put a guard byte at the end of what we send + // to user code. + + + int r = read (sd, readbuffer, sizeof(readbuffer) - 1); +#ifdef OS_WIN32 + int e = WSAGetLastError(); +#else + int e = errno; +#endif + //cerr << ""; + + if (r > 0) { + total_bytes_read += r; + + // Add a null-terminator at the the end of the buffer + // that we will send to the callback. + // DO NOT EVER CHANGE THIS. We want to explicitly allow users + // to be able to depend on this behavior, so they will have + // the option to do some things faster. Additionally it's + // a security guard against buffer overflows. + readbuffer [r] = 0; + _DispatchInboundData (readbuffer, r); + if (bPaused) + break; + } + else if (r == 0) { + break; + } + else { + #ifdef OS_UNIX + if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EAGAIN) && (e != EINTR)) { + #endif + #ifdef OS_WIN32 + if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) { + #endif + // 26Mar11: Previously, all read errors were assumed to be EWOULDBLOCK and ignored. + // Now, instead, we call Close() on errors like ECONNRESET and ENOTCONN. + UnbindReasonCode = e; + Close(); + break; + } else { + // Basically a would-block, meaning we've read everything there is to read. + break; + } + } + + } + + + if (total_bytes_read == 0) { + // If we read no data on a socket that selected readable, + // it generally means the other end closed the connection gracefully. + ScheduleClose (false); + //bCloseNow = true; + } + +} + + + +/****************************************** +ConnectionDescriptor::_DispatchInboundData +******************************************/ + +#ifdef WITH_SSL +void ConnectionDescriptor::_DispatchInboundData (const char *buffer, unsigned long size) +{ + if (SslBox) { + SslBox->PutCiphertext (buffer, size); + + int s; + char B [2048]; + while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) { + _CheckHandshakeStatus(); + B [s] = 0; + _GenericInboundDispatch(B, s); + } + + // If our SSL handshake had a problem, shut down the connection. + if (s == -2) { + #ifndef EPROTO // OpenBSD does not have EPROTO + #define EPROTO EINTR + #endif + #ifdef OS_UNIX + UnbindReasonCode = EPROTO; + #endif + #ifdef OS_WIN32 + UnbindReasonCode = WSAECONNABORTED; + #endif + ScheduleClose(false); + return; + } + + _CheckHandshakeStatus(); + _DispatchCiphertext(); + } + else { + _GenericInboundDispatch(buffer, size); + } +} +#else +void ConnectionDescriptor::_DispatchInboundData (const char *buffer, unsigned long size) +{ + _GenericInboundDispatch(buffer, size); +} +#endif + + + +/******************************************* +ConnectionDescriptor::_CheckHandshakeStatus +*******************************************/ + +void ConnectionDescriptor::_CheckHandshakeStatus() +{ + #ifdef WITH_SSL + if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) { + bHandshakeSignaled = true; + if (EventCallback) + (*EventCallback)(GetBinding(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0); + } + #endif +} + + + +/*************************** +ConnectionDescriptor::Write +***************************/ + +void ConnectionDescriptor::Write() +{ + /* A socket which is in a pending-connect state will select + * writable when the disposition of the connect is known. + * At that point, check to be sure there are no errors, + * and if none, then promote the socket out of the pending + * state. + * TODO: I haven't figured out how Windows signals errors on + * unconnected sockets. Maybe it does the untraditional but + * logical thing and makes the socket selectable for error. + * If so, it's unsupported here for the time being, and connect + * errors will have to be caught by the timeout mechanism. + */ + + if (bConnectPending) { + int error; + socklen_t len; + len = sizeof(error); + #ifdef OS_UNIX + int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len); + #endif + #ifdef OS_WIN32 + int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len); + #endif + if ((o == 0) && (error == 0)) { + if (EventCallback) + (*EventCallback)(GetBinding(), EM_CONNECTION_COMPLETED, "", 0); + + // 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called + // from EventMachine_t::AttachFD as well. + SetConnectPending (false); + } + else { + if (o == 0) + UnbindReasonCode = error; + ScheduleClose (false); + //bCloseNow = true; + } + } + else { + + if (bNotifyWritable) { + if (EventCallback) + (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0); + + _UpdateEvents(false, true); + return; + } + + assert(!bWatchOnly); + + /* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using + EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again, + we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause + ::Write to be called in a busy-loop. + */ + #ifdef HAVE_KQUEUE + if (MyEventMachine->GetPoller() == Poller_Kqueue) { + if (OutboundDataSize == 0 && !bGotExtraKqueueEvent) { + bGotExtraKqueueEvent = true; + return; + } else if (OutboundDataSize > 0) { + bGotExtraKqueueEvent = false; + } + } + #endif + + _WriteOutboundData(); + } +} + + +/**************************************** +ConnectionDescriptor::_WriteOutboundData +****************************************/ + +void ConnectionDescriptor::_WriteOutboundData() +{ + /* This is a helper function called by ::Write. + * It's possible for a socket to select writable and then no longer + * be writable by the time we get around to writing. The kernel might + * have used up its available output buffers between the select call + * and when we get here. So this condition is not an error. + * + * 20Jul07, added the same kind of protection against an invalid socket + * that is at the top of ::Read. Not entirely how this could happen in + * real life (connection-reset from the remote peer, perhaps?), but I'm + * doing it to address some reports of crashing under heavy loads. + */ + + SOCKET sd = GetSocket(); + //assert (sd != INVALID_SOCKET); + if (sd == INVALID_SOCKET) { + assert (!bWriteAttemptedAfterClose); + bWriteAttemptedAfterClose = true; + return; + } + + LastActivity = MyEventMachine->GetCurrentLoopTime(); + size_t nbytes = 0; + + #ifdef HAVE_WRITEV + int iovcnt = OutboundPages.size(); + // Max of 16 outbound pages at a time + if (iovcnt > 16) iovcnt = 16; + + iovec iov[16]; + + for(int i = 0; i < iovcnt; i++){ + OutboundPage *op = &(OutboundPages[i]); + #ifdef CC_SUNWspro + // TODO: The void * cast works fine on Solaris 11, but + // I don't know at what point that changed from older Solaris. + iov[i].iov_base = (char *)(op->Buffer + op->Offset); + #else + iov[i].iov_base = (void *)(op->Buffer + op->Offset); + #endif + iov[i].iov_len = op->Length - op->Offset; + + nbytes += iov[i].iov_len; + } + #else + char output_buffer [16 * 1024]; + + while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) { + OutboundPage *op = &(OutboundPages[0]); + if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) { + memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset); + nbytes += (op->Length - op->Offset); + op->Free(); + OutboundPages.pop_front(); + } + else { + int len = sizeof(output_buffer) - nbytes; + memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len); + op->Offset += len; + nbytes += len; + } + } + #endif + + // We should never have gotten here if there were no data to write, + // so assert that as a sanity check. + // Don't bother to make sure nbytes is less than output_buffer because + // if it were we probably would have crashed already. + assert (nbytes > 0); + + assert (GetSocket() != INVALID_SOCKET); + #ifdef HAVE_WRITEV + int bytes_written = writev (GetSocket(), iov, iovcnt); + #else + int bytes_written = write (GetSocket(), output_buffer, nbytes); + #endif + + bool err = false; +#ifdef OS_WIN32 + int e = WSAGetLastError(); +#else + int e = errno; +#endif + if (bytes_written < 0) { + err = true; + bytes_written = 0; + } + + assert (bytes_written >= 0); + OutboundDataSize -= bytes_written; + + if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused()) + ProxiedFrom->Resume(); + + #ifdef HAVE_WRITEV + if (!err) { + unsigned int sent = bytes_written; + std::deque::iterator op = OutboundPages.begin(); + + for (int i = 0; i < iovcnt; i++) { + if (iov[i].iov_len <= sent) { + // Sent this page in full, free it. + op->Free(); + OutboundPages.pop_front(); + + sent -= iov[i].iov_len; + } else { + // Sent part (or none) of this page, increment offset to send the remainder + op->Offset += sent; + break; + } + + // Shouldn't be possible run out of pages before the loop ends + assert(op != OutboundPages.end()); + *op++; + } + } + #else + if ((size_t)bytes_written < nbytes) { + int len = nbytes - bytes_written; + char *buffer = (char*) malloc (len + 1); + if (!buffer) + throw std::runtime_error ("bad alloc throwing back data"); + memcpy (buffer, output_buffer + bytes_written, len); + buffer [len] = 0; + OutboundPages.push_front (OutboundPage (buffer, len)); + } + #endif + + _UpdateEvents(false, true); + + if (err) { + #ifdef OS_UNIX + if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) { + #endif + #ifdef OS_WIN32 + if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) { + #endif + UnbindReasonCode = e; + Close(); + } + } +} + + +/*************************************** +ConnectionDescriptor::ReportErrorStatus +***************************************/ + +int ConnectionDescriptor::ReportErrorStatus() +{ + if (MySocket == INVALID_SOCKET) { + return -1; + } + + int error; + socklen_t len; + len = sizeof(error); + #ifdef OS_UNIX + int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len); + #endif + #ifdef OS_WIN32 + int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len); + #endif + if ((o == 0) && (error == 0)) + return 0; + else if (o == 0) + return error; + else + return -1; +} + + +/****************************** +ConnectionDescriptor::StartTls +******************************/ + +#ifdef WITH_SSL +void ConnectionDescriptor::StartTls() +{ + if (SslBox) + throw std::runtime_error ("SSL/TLS already running on connection"); + + SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, bSslFailIfNoPeerCert, SniHostName, CipherList, EcdhCurve, DhParam, Protocols, GetBinding()); + _DispatchCiphertext(); + +} +#else +void ConnectionDescriptor::StartTls() +{ + throw std::runtime_error ("Encryption not available on this event-machine"); +} +#endif + + +/********************************* +ConnectionDescriptor::SetTlsParms +*********************************/ + +#ifdef WITH_SSL +void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer, bool fail_if_no_peer_cert, const char *sni_hostname, const char *cipherlist, const char *ecdh_curve, const char *dhparam, int protocols) +{ + if (SslBox) + throw std::runtime_error ("call SetTlsParms before calling StartTls"); + if (privkey_filename && *privkey_filename) + PrivateKeyFilename = privkey_filename; + if (certchain_filename && *certchain_filename) + CertChainFilename = certchain_filename; + bSslVerifyPeer = verify_peer; + bSslFailIfNoPeerCert = fail_if_no_peer_cert; + + if (sni_hostname && *sni_hostname) + SniHostName = sni_hostname; + if (cipherlist && *cipherlist) + CipherList = cipherlist; + if (ecdh_curve && *ecdh_curve) + EcdhCurve = ecdh_curve; + if (dhparam && *dhparam) + DhParam = dhparam; + + Protocols = protocols; +} +#else +void ConnectionDescriptor::SetTlsParms (const char *privkey_filename UNUSED, const char *certchain_filename UNUSED, bool verify_peer UNUSED, bool fail_if_no_peer_cert UNUSED, const char *sni_hostname UNUSED, const char *cipherlist UNUSED, const char *ecdh_curve UNUSED, const char *dhparam UNUSED, int protocols UNUSED) +{ + throw std::runtime_error ("Encryption not available on this event-machine"); +} +#endif + + +/********************************* +ConnectionDescriptor::GetPeerCert +*********************************/ + +#ifdef WITH_SSL +X509 *ConnectionDescriptor::GetPeerCert() +{ + if (!SslBox) + throw std::runtime_error ("SSL/TLS not running on this connection"); + return SslBox->GetPeerCert(); +} +#endif + + +/********************************* +ConnectionDescriptor::GetCipherBits +*********************************/ + +#ifdef WITH_SSL +int ConnectionDescriptor::GetCipherBits() +{ + if (!SslBox) + throw std::runtime_error ("SSL/TLS not running on this connection"); + return SslBox->GetCipherBits(); +} +#endif + + +/********************************* +ConnectionDescriptor::GetCipherName +*********************************/ + +#ifdef WITH_SSL +const char *ConnectionDescriptor::GetCipherName() +{ + if (!SslBox) + throw std::runtime_error ("SSL/TLS not running on this connection"); + return SslBox->GetCipherName(); +} +#endif + + +/********************************* +ConnectionDescriptor::GetCipherProtocol +*********************************/ + +#ifdef WITH_SSL +const char *ConnectionDescriptor::GetCipherProtocol() +{ + if (!SslBox) + throw std::runtime_error ("SSL/TLS not running on this connection"); + return SslBox->GetCipherProtocol(); +} +#endif + + +/********************************* +ConnectionDescriptor::GetSNIHostname +*********************************/ + +#ifdef WITH_SSL +const char *ConnectionDescriptor::GetSNIHostname() +{ + if (!SslBox) + throw std::runtime_error ("SSL/TLS not running on this connection"); + return SslBox->GetSNIHostname(); +} +#endif + + +/*********************************** +ConnectionDescriptor::VerifySslPeer +***********************************/ + +#ifdef WITH_SSL +bool ConnectionDescriptor::VerifySslPeer(const char *cert) +{ + bSslPeerAccepted = false; + + if (EventCallback) + (*EventCallback)(GetBinding(), EM_SSL_VERIFY, cert, strlen(cert)); + + return bSslPeerAccepted; +} +#endif + + +/*********************************** +ConnectionDescriptor::AcceptSslPeer +***********************************/ + +#ifdef WITH_SSL +void ConnectionDescriptor::AcceptSslPeer() +{ + bSslPeerAccepted = true; +} +#endif + + +/***************************************** +ConnectionDescriptor::_DispatchCiphertext +*****************************************/ + +#ifdef WITH_SSL +void ConnectionDescriptor::_DispatchCiphertext() +{ + assert (SslBox); + + + char BigBuf [SSLBOX_OUTPUT_CHUNKSIZE]; + bool did_work; + + do { + did_work = false; + + // try to drain ciphertext + while (SslBox->CanGetCiphertext()) { + int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf)); + assert (r > 0); + _SendRawOutboundData (BigBuf, r); + did_work = true; + } + + // Pump the SslBox, in case it has queued outgoing plaintext + // This will return >0 if data was written, + // 0 if no data was written, and <0 if there was a fatal error. + bool pump; + do { + pump = false; + int w = SslBox->PutPlaintext (NULL, 0); + if (w > 0) { + did_work = true; + pump = true; + } + else if (w < 0) + ScheduleClose (false); + } while (pump); + + // try to put plaintext. INCOMPLETE, doesn't belong here? + // In SendOutboundData, we're spooling plaintext directly + // into SslBox. That may be wrong, we may need to buffer it + // up here! + /* + const char *ptr; + int ptr_length; + while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) { + assert (ptr && (ptr_length > 0)); + int w = SslMachine.PutPlaintext (ptr, ptr_length); + if (w > 0) { + OutboundPlaintext.DiscardBytes (w); + did_work = true; + } + else + break; + } + */ + + } while (did_work); + +} +#endif + + + +/******************************* +ConnectionDescriptor::Heartbeat +*******************************/ + +void ConnectionDescriptor::Heartbeat() +{ + /* Only allow a certain amount of time to go by while waiting + * for a pending connect. If it expires, then kill the socket. + * For a connected socket, close it if its inactivity timer + * has expired. + */ + + if (bConnectPending) { + if ((MyEventMachine->GetCurrentLoopTime() - CreatedAt) >= PendingConnectTimeout) { + UnbindReasonCode = ETIMEDOUT; + ScheduleClose (false); + //bCloseNow = true; + } + } + else { + if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) { + UnbindReasonCode = ETIMEDOUT; + ScheduleClose (false); + //bCloseNow = true; + } + } +} + + +/**************************************** +LoopbreakDescriptor::LoopbreakDescriptor +****************************************/ + +LoopbreakDescriptor::LoopbreakDescriptor (SOCKET sd, EventMachine_t *parent_em): + EventableDescriptor (sd, parent_em) +{ + /* This is really bad and ugly. Change someday if possible. + * We have to know about an event-machine (probably the one that owns us), + * so we can pass newly-created connections to it. + */ + + bCallbackUnbind = false; + + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + #ifdef HAVE_KQUEUE + MyEventMachine->ArmKqueueReader (this); + #endif +} + + + + +/************************* +LoopbreakDescriptor::Read +*************************/ + +void LoopbreakDescriptor::Read() +{ + // TODO, refactor, this code is probably in the wrong place. + assert (MyEventMachine); + MyEventMachine->_ReadLoopBreaker(); +} + + +/************************** +LoopbreakDescriptor::Write +**************************/ + +void LoopbreakDescriptor::Write() +{ + // Why are we here? + throw std::runtime_error ("bad code path in loopbreak"); +} + +/************************************** +AcceptorDescriptor::AcceptorDescriptor +**************************************/ + +AcceptorDescriptor::AcceptorDescriptor (SOCKET sd, EventMachine_t *parent_em): + EventableDescriptor (sd, parent_em) +{ + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + #ifdef HAVE_KQUEUE + MyEventMachine->ArmKqueueReader (this); + #endif +} + + +/*************************************** +AcceptorDescriptor::~AcceptorDescriptor +***************************************/ + +AcceptorDescriptor::~AcceptorDescriptor() +{ +} + +/**************************************** +STATIC: AcceptorDescriptor::StopAcceptor +****************************************/ + +void AcceptorDescriptor::StopAcceptor (const uintptr_t binding) +{ + // TODO: This is something of a hack, or at least it's a static method of the wrong class. + AcceptorDescriptor *ad = dynamic_cast (Bindable_t::GetObject (binding)); + if (ad) + ad->ScheduleClose (false); + else + throw std::runtime_error ("failed to close nonexistent acceptor"); +} + + +/************************ +AcceptorDescriptor::Read +************************/ + +void AcceptorDescriptor::Read() +{ + /* Accept up to a certain number of sockets on the listening connection. + * Don't try to accept all that are present, because this would allow a DoS attack + * in which no data were ever read or written. We should accept more than one, + * if available, to keep the partially accepted sockets from backing up in the kernel. + */ + + /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it + * for readability. According to Stevens UNP, it's possible for an acceptor to select readable + * and then block when we call accept. For example, the other end resets the connection after + * the socket selects readable and before we call accept. The kernel will remove the dead + * socket from the accept queue. If the accept queue is now empty, accept will block. + */ + + + struct sockaddr_in6 pin; + socklen_t addrlen = sizeof (pin); + int accept_count = EventMachine_t::GetSimultaneousAcceptCount(); + + for (int i=0; i < accept_count; i++) { +#if defined(HAVE_CONST_SOCK_CLOEXEC) && defined(HAVE_ACCEPT4) + SOCKET sd = accept4 (GetSocket(), (struct sockaddr*)&pin, &addrlen, SOCK_CLOEXEC); + if (sd == INVALID_SOCKET) { + // We may be running in a kernel where + // SOCK_CLOEXEC is not supported - fall back: + sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen); + } +#else + SOCKET sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen); +#endif + if (sd == INVALID_SOCKET) { + // This breaks the loop when we've accepted everything on the kernel queue, + // up to 10 new connections. But what if the *first* accept fails? + // Does that mean anything serious is happening, beyond the situation + // described in the note above? + break; + } + + // Set the newly-accepted socket non-blocking and to close on exec. + // On Windows, this may fail because, weirdly, Windows inherits the non-blocking + // attribute that we applied to the acceptor socket into the accepted one. + if (!SetFdCloexec(sd) || !SetSocketNonblocking (sd)) { + //int val = fcntl (sd, F_GETFL, 0); + //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) { + shutdown (sd, 1); + close (sd); + continue; + } + + // Disable slow-start (Nagle algorithm). Eventually make this configurable. + int one = 1; + setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one)); + + + ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine); + if (!cd) + throw std::runtime_error ("no newly accepted connection"); + cd->SetServerMode(); + if (EventCallback) { + (*EventCallback) (GetBinding(), EM_CONNECTION_ACCEPTED, NULL, cd->GetBinding()); + } + #ifdef HAVE_EPOLL + cd->GetEpollEvent()->events = 0; + if (cd->SelectForRead()) + cd->GetEpollEvent()->events |= EPOLLIN; + if (cd->SelectForWrite()) + cd->GetEpollEvent()->events |= EPOLLOUT; + #endif + assert (MyEventMachine); + MyEventMachine->Add (cd); + #ifdef HAVE_KQUEUE + bKqueueArmWrite = cd->SelectForWrite(); + if (bKqueueArmWrite) + MyEventMachine->Modify (cd); + if (cd->SelectForRead()) + MyEventMachine->ArmKqueueReader (cd); + #endif + } + +} + + +/************************* +AcceptorDescriptor::Write +*************************/ + +void AcceptorDescriptor::Write() +{ + // Why are we here? + throw std::runtime_error ("bad code path in acceptor"); +} + + +/***************************** +AcceptorDescriptor::Heartbeat +*****************************/ + +void AcceptorDescriptor::Heartbeat() +{ + // No-op +} + + +/************************************** +DatagramDescriptor::DatagramDescriptor +**************************************/ + +DatagramDescriptor::DatagramDescriptor (SOCKET sd, EventMachine_t *parent_em): + EventableDescriptor (sd, parent_em), + OutboundDataSize (0) +{ + memset (&ReturnAddress, 0, sizeof(ReturnAddress)); + + /* Provisionally added 19Oct07. All datagram sockets support broadcasting. + * Until now, sending to a broadcast address would give EACCES (permission denied) + * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order + * to accept a packet to a broadcast address. Solaris doesn't require it. I think + * Windows DOES require it but I'm not sure. + * + * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST + * on a UDP socket in order to enable broadcasting. The reason for requiring the option + * in the first place is so that applications don't send broadcast datagrams by mistake. + * I imagine that could happen if a user of an application typed in an address that happened + * to be a broadcast address on that particular subnet. + * + * This is provisional because someone may eventually come up with a good reason not to + * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API + * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T + * EXPLICITLY SET THE OPTION. + */ + + int oval = 1; + setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval)); + + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + #ifdef HAVE_KQUEUE + MyEventMachine->ArmKqueueReader (this); + #endif +} + + +/*************************************** +DatagramDescriptor::~DatagramDescriptor +***************************************/ + +DatagramDescriptor::~DatagramDescriptor() +{ + // Run down any stranded outbound data. + for (size_t i=0; i < OutboundPages.size(); i++) + OutboundPages[i].Free(); +} + + +/***************************** +DatagramDescriptor::Heartbeat +*****************************/ + +void DatagramDescriptor::Heartbeat() +{ + // Close it if its inactivity timer has expired. + + if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) + ScheduleClose (false); + //bCloseNow = true; +} + + +/************************ +DatagramDescriptor::Read +************************/ + +void DatagramDescriptor::Read() +{ + SOCKET sd = GetSocket(); + assert (sd != INVALID_SOCKET); + LastActivity = MyEventMachine->GetCurrentLoopTime(); + + // This is an extremely large read buffer. + // In many cases you wouldn't expect to get any more than 4K. + char readbuffer [16 * 1024]; + + for (int i=0; i < 10; i++) { + // Don't read just one buffer and then move on. This is faster + // if there is a lot of incoming. + // But don't read indefinitely. Give other sockets a chance to run. + // NOTICE, we're reading one less than the buffer size. + // That's so we can put a guard byte at the end of what we send + // to user code. + + struct sockaddr_in6 sin; + socklen_t slen = sizeof (sin); + memset (&sin, 0, slen); + + int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen); + //cerr << ""; + + // In UDP, a zero-length packet is perfectly legal. + if (r >= 0) { + + // Add a null-terminator at the the end of the buffer + // that we will send to the callback. + // DO NOT EVER CHANGE THIS. We want to explicitly allow users + // to be able to depend on this behavior, so they will have + // the option to do some things faster. Additionally it's + // a security guard against buffer overflows. + readbuffer [r] = 0; + + + // Set up a "temporary" return address so that callers can "reply" to us + // from within the callback we are about to invoke. That means that ordinary + // calls to "send_data_to_connection" (which is of course misnamed in this + // case) will result in packets being sent back to the same place that sent + // us this one. + // There is a different call (evma_send_datagram) for cases where the caller + // actually wants to send a packet somewhere else. + + memset (&ReturnAddress, 0, sizeof(ReturnAddress)); + memcpy (&ReturnAddress, &sin, slen); + + _GenericInboundDispatch(readbuffer, r); + + } + else { + // Basically a would-block, meaning we've read everything there is to read. + break; + } + + } + + +} + + +/************************* +DatagramDescriptor::Write +*************************/ + +void DatagramDescriptor::Write() +{ + /* It's possible for a socket to select writable and then no longer + * be writable by the time we get around to writing. The kernel might + * have used up its available output buffers between the select call + * and when we get here. So this condition is not an error. + * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData, + * but differs in the that the outbound data pages (received from the + * user) are _message-structured._ That is, we send each of them out + * one message at a time. + * TODO, we are currently suppressing the EMSGSIZE error!!! + */ + + SOCKET sd = GetSocket(); + assert (sd != INVALID_SOCKET); + LastActivity = MyEventMachine->GetCurrentLoopTime(); + + assert (OutboundPages.size() > 0); + + // Send out up to 10 packets, then cycle the machine. + for (int i = 0; i < 10; i++) { + if (OutboundPages.size() <= 0) + break; + OutboundPage *op = &(OutboundPages[0]); + + // The nasty cast to (char*) is needed because Windows is brain-dead. + int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), + (op->From.sin6_family == AF_INET6 ? sizeof (struct sockaddr_in6) : sizeof (struct sockaddr_in))); +#ifdef OS_WIN32 + int e = WSAGetLastError(); +#else + int e = errno; +#endif + + OutboundDataSize -= op->Length; + op->Free(); + OutboundPages.pop_front(); + + if (s == SOCKET_ERROR) { + #ifdef OS_UNIX + if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) { + #endif + #ifdef OS_WIN32 + if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) { + #endif + UnbindReasonCode = e; + Close(); + break; + } + } + } + + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + if (SelectForWrite()) + EpollEvent.events |= EPOLLOUT; + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + #ifdef HAVE_KQUEUE + bKqueueArmWrite = SelectForWrite(); + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif +} + + +/********************************** +DatagramDescriptor::SelectForWrite +**********************************/ + +bool DatagramDescriptor::SelectForWrite() +{ + /* Changed 15Nov07, per bug report by Mark Zvillius. + * The outbound data size will be zero if there are zero-length outbound packets, + * so we now select writable in case the outbound page buffer is not empty. + * Note that the superclass ShouldDelete method still checks for outbound data size, + * which may be wrong. + */ + //return (GetOutboundDataSize() > 0); (Original) + return (OutboundPages.size() > 0); +} + + +/************************************ +DatagramDescriptor::SendOutboundData +************************************/ + +int DatagramDescriptor::SendOutboundData (const char *data, unsigned long length) +{ + // This is almost an exact clone of ConnectionDescriptor::_SendRawOutboundData. + // That means most of it could be factored to a common ancestor. Note that + // empty datagrams are meaningful, which isn't the case for TCP streams. + + if (IsCloseScheduled()) + return 0; + + if (!data && (length > 0)) + throw std::runtime_error ("bad outbound data"); + char *buffer = (char *) malloc (length + 1); + if (!buffer) + throw std::runtime_error ("no allocation for outbound data"); + memcpy (buffer, data, length); + buffer [length] = 0; + OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress)); + OutboundDataSize += length; + + #ifdef HAVE_EPOLL + EpollEvent.events = (EPOLLIN | EPOLLOUT); + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + #ifdef HAVE_KQUEUE + bKqueueArmWrite = true; + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + + return length; +} + + +/**************************************** +DatagramDescriptor::SendOutboundDatagram +****************************************/ + +int DatagramDescriptor::SendOutboundDatagram (const char *data, unsigned long length, const char *address, int port) +{ + // This is an exact clone of ConnectionDescriptor::SendOutboundData. + // That means it needs to move to a common ancestor. + // TODO: Refactor this so there's no overlap with SendOutboundData. + + if (IsCloseScheduled()) + //if (bCloseNow || bCloseAfterWriting) + return 0; + + if (!address || !*address || !port) + return 0; + + struct sockaddr_in6 addr_here; + size_t addr_here_len = sizeof addr_here; + if (0 != EventMachine_t::name2address (address, port, SOCK_DGRAM, (struct sockaddr *)&addr_here, &addr_here_len)) + return -1; + + if (!data && (length > 0)) + throw std::runtime_error ("bad outbound data"); + char *buffer = (char *) malloc (length + 1); + if (!buffer) + throw std::runtime_error ("no allocation for outbound data"); + memcpy (buffer, data, length); + buffer [length] = 0; + OutboundPages.push_back (OutboundPage (buffer, length, addr_here)); + OutboundDataSize += length; + + #ifdef HAVE_EPOLL + EpollEvent.events = (EPOLLIN | EPOLLOUT); + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + #ifdef HAVE_KQUEUE + bKqueueArmWrite = true; + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + + return length; +} + + +/********************************************** +ConnectionDescriptor::GetCommInactivityTimeout +**********************************************/ + +uint64_t ConnectionDescriptor::GetCommInactivityTimeout() +{ + return InactivityTimeout / 1000; +} + + +/********************************************** +ConnectionDescriptor::SetCommInactivityTimeout +**********************************************/ + +int ConnectionDescriptor::SetCommInactivityTimeout (uint64_t value) +{ + InactivityTimeout = value * 1000; + MyEventMachine->QueueHeartbeat(this); + return 1; +} + +/******************************* +DatagramDescriptor::GetPeername +*******************************/ + +bool DatagramDescriptor::GetPeername (struct sockaddr *s, socklen_t *len) +{ + bool ok = false; + if (s) { + *len = sizeof(ReturnAddress); + memset (s, 0, sizeof(ReturnAddress)); + memcpy (s, &ReturnAddress, sizeof(ReturnAddress)); + ok = true; + } + return ok; +} + + +/******************************************** +DatagramDescriptor::GetCommInactivityTimeout +********************************************/ + +uint64_t DatagramDescriptor::GetCommInactivityTimeout() +{ + return InactivityTimeout / 1000; +} + +/******************************************** +DatagramDescriptor::SetCommInactivityTimeout +********************************************/ + +int DatagramDescriptor::SetCommInactivityTimeout (uint64_t value) +{ + if (value > 0) { + InactivityTimeout = value * 1000; + MyEventMachine->QueueHeartbeat(this); + return 1; + } + return 0; +} + + +/************************************ +InotifyDescriptor::InotifyDescriptor +*************************************/ + +InotifyDescriptor::InotifyDescriptor (EventMachine_t *em): + EventableDescriptor(0, em) +{ + bCallbackUnbind = false; + + #ifndef HAVE_INOTIFY + throw std::runtime_error("no inotify support on this system"); + #else + + int fd = inotify_init(); + if (fd == -1) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "unable to create inotify descriptor: %s", strerror(errno)); + throw std::runtime_error (buf); + } + + MySocket = fd; + SetSocketNonblocking(MySocket); + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + + #endif +} + + +/************************************* +InotifyDescriptor::~InotifyDescriptor +**************************************/ + +InotifyDescriptor::~InotifyDescriptor() +{ + close(MySocket); + MySocket = INVALID_SOCKET; +} + +/*********************** +InotifyDescriptor::Read +************************/ + +void InotifyDescriptor::Read() +{ + assert (MyEventMachine); + MyEventMachine->_ReadInotifyEvents(); +} + + +/************************ +InotifyDescriptor::Write +*************************/ + +void InotifyDescriptor::Write() +{ + throw std::runtime_error("bad code path in inotify"); +} diff --git a/bin/gems/eventmachine-1.2.7/ext/ed.h b/bin/gems/eventmachine-1.2.7/ext/ed.h new file mode 100644 index 00000000..4d7f7d4e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/ed.h @@ -0,0 +1,457 @@ +/***************************************************************************** + +$Id$ + +File: ed.h +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#ifndef __EventableDescriptor__H_ +#define __EventableDescriptor__H_ + + +class EventMachine_t; // forward reference +#ifdef WITH_SSL +class SslBox_t; // forward reference +#endif + +bool SetSocketNonblocking (SOCKET); +bool SetFdCloexec (int); + +/************************* +class EventableDescriptor +*************************/ + +class EventableDescriptor: public Bindable_t +{ + public: + EventableDescriptor (SOCKET, EventMachine_t*); + virtual ~EventableDescriptor() NO_EXCEPT_FALSE; + + SOCKET GetSocket() {return MySocket;} + void SetSocketInvalid() { MySocket = INVALID_SOCKET; } + void Close(); + + virtual void Read() = 0; + virtual void Write() = 0; + virtual void Heartbeat() = 0; + + // These methods tell us whether the descriptor + // should be selected or polled for read/write. + virtual bool SelectForRead() = 0; + virtual bool SelectForWrite() = 0; + + // are we scheduled for a close, or in an error state, or already closed? + bool ShouldDelete(); + // Do we have any data to write? This is used by ShouldDelete. + virtual int GetOutboundDataSize() {return 0;} + virtual bool IsWatchOnly(){ return bWatchOnly; } + + virtual void ScheduleClose (bool after_writing); + bool IsCloseScheduled(); + virtual void HandleError(){ ScheduleClose (false); } + + void SetEventCallback (EMCallback); + + virtual bool GetPeername (struct sockaddr*, socklen_t*) = 0; + virtual bool GetSockname (struct sockaddr*, socklen_t*) = 0; + virtual bool GetSubprocessPid (pid_t*) {return false;} + + virtual void StartTls() {} + virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int) {} + + #ifdef WITH_SSL + virtual X509 *GetPeerCert() {return NULL;} + virtual int GetCipherBits() {return -1;} + virtual const char *GetCipherName() {return NULL;} + virtual const char *GetCipherProtocol() {return NULL;} + virtual const char *GetSNIHostname() {return NULL;} + #endif + + virtual uint64_t GetCommInactivityTimeout() {return 0;} + virtual int SetCommInactivityTimeout (uint64_t) {return 0;} + uint64_t GetPendingConnectTimeout(); + int SetPendingConnectTimeout (uint64_t value); + uint64_t GetLastActivity() { return LastActivity; } + + #ifdef HAVE_EPOLL + struct epoll_event *GetEpollEvent() { return &EpollEvent; } + #endif + + #ifdef HAVE_KQUEUE + bool GetKqueueArmWrite() { return bKqueueArmWrite; } + #endif + + virtual void StartProxy(const uintptr_t, const unsigned long, const unsigned long); + virtual void StopProxy(); + virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; }; + virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long); + virtual int SendOutboundData(const char*,unsigned long){ return -1; } + virtual bool IsPaused(){ return bPaused; } + virtual bool Pause(){ bPaused = true; return bPaused; } + virtual bool Resume(){ bPaused = false; return bPaused; } + + void SetUnbindReasonCode(int code){ UnbindReasonCode = code; } + virtual int ReportErrorStatus(){ return 0; } + virtual bool IsConnectPending(){ return false; } + virtual uint64_t GetNextHeartbeat(); + + private: + bool bCloseNow; + bool bCloseAfterWriting; + + protected: + SOCKET MySocket; + bool bAttached; + bool bWatchOnly; + + EMCallback EventCallback; + void _GenericInboundDispatch (const char *buffer, unsigned long size); + bool _GenericGetPeername (struct sockaddr*, socklen_t*); + bool _GenericGetSockname (struct sockaddr*, socklen_t*); + + uint64_t CreatedAt; + bool bCallbackUnbind; + int UnbindReasonCode; + + unsigned long BytesToProxy; + EventableDescriptor *ProxyTarget; + EventableDescriptor *ProxiedFrom; + unsigned long ProxiedBytes; + + unsigned long MaxOutboundBufSize; + + #ifdef HAVE_EPOLL + struct epoll_event EpollEvent; + #endif + + #ifdef HAVE_KQUEUE + bool bKqueueArmWrite; + #endif + + EventMachine_t *MyEventMachine; + uint64_t PendingConnectTimeout; + uint64_t InactivityTimeout; + uint64_t LastActivity; + uint64_t NextHeartbeat; + bool bPaused; +}; + + + +/************************* +class LoopbreakDescriptor +*************************/ + +class LoopbreakDescriptor: public EventableDescriptor +{ + public: + LoopbreakDescriptor (SOCKET, EventMachine_t*); + virtual ~LoopbreakDescriptor() {} + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat() {} + + virtual bool SelectForRead() {return true;} + virtual bool SelectForWrite() {return false;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } +}; + + +/************************** +class ConnectionDescriptor +**************************/ + +class ConnectionDescriptor: public EventableDescriptor +{ + public: + ConnectionDescriptor (SOCKET, EventMachine_t*); + virtual ~ConnectionDescriptor(); + + int SendOutboundData (const char*, unsigned long); + + void SetConnectPending (bool f); + virtual void ScheduleClose (bool after_writing); + virtual void HandleError(); + + void SetNotifyReadable (bool); + void SetNotifyWritable (bool); + void SetAttached (bool); + void SetWatchOnly (bool); + + bool Pause(); + bool Resume(); + + bool IsNotifyReadable(){ return bNotifyReadable; } + bool IsNotifyWritable(){ return bNotifyWritable; } + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat(); + + virtual bool SelectForRead(); + virtual bool SelectForWrite(); + + // Do we have any data to write? This is used by ShouldDelete. + virtual int GetOutboundDataSize() {return OutboundDataSize;} + + virtual void StartTls(); + virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int); + + #ifdef WITH_SSL + virtual X509 *GetPeerCert(); + virtual int GetCipherBits(); + virtual const char *GetCipherName(); + virtual const char *GetCipherProtocol(); + virtual const char *GetSNIHostname(); + virtual bool VerifySslPeer(const char*); + virtual void AcceptSslPeer(); + #endif + + void SetServerMode() {bIsServer = true;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } + + virtual uint64_t GetCommInactivityTimeout(); + virtual int SetCommInactivityTimeout (uint64_t value); + + virtual int ReportErrorStatus(); + virtual bool IsConnectPending(){ return bConnectPending; } + + protected: + struct OutboundPage { + OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {} + void Free() {if (Buffer) free (const_cast(Buffer)); } + const char *Buffer; + int Length; + int Offset; + }; + + protected: + bool bConnectPending; + + bool bNotifyReadable; + bool bNotifyWritable; + + bool bReadAttemptedAfterClose; + bool bWriteAttemptedAfterClose; + + std::deque OutboundPages; + int OutboundDataSize; + + #ifdef WITH_SSL + SslBox_t *SslBox; + std::string CertChainFilename; + std::string PrivateKeyFilename; + std::string CipherList; + std::string EcdhCurve; + std::string DhParam; + int Protocols; + bool bHandshakeSignaled; + bool bSslVerifyPeer; + bool bSslFailIfNoPeerCert; + std::string SniHostName; + bool bSslPeerAccepted; + #endif + + #ifdef HAVE_KQUEUE + bool bGotExtraKqueueEvent; + #endif + + bool bIsServer; + + private: + void _UpdateEvents(); + void _UpdateEvents(bool, bool); + void _WriteOutboundData(); + void _DispatchInboundData (const char *buffer, unsigned long size); + void _DispatchCiphertext(); + int _SendRawOutboundData (const char *buffer, unsigned long size); + void _CheckHandshakeStatus(); + +}; + + +/************************ +class DatagramDescriptor +************************/ + +class DatagramDescriptor: public EventableDescriptor +{ + public: + DatagramDescriptor (SOCKET, EventMachine_t*); + virtual ~DatagramDescriptor(); + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat(); + + virtual bool SelectForRead() {return true;} + virtual bool SelectForWrite(); + + int SendOutboundData (const char*, unsigned long); + int SendOutboundDatagram (const char*, unsigned long, const char*, int); + + // Do we have any data to write? This is used by ShouldDelete. + virtual int GetOutboundDataSize() {return OutboundDataSize;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len); + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); }; + + virtual uint64_t GetCommInactivityTimeout(); + virtual int SetCommInactivityTimeout (uint64_t value); + + protected: + struct OutboundPage { + OutboundPage (const char *b, int l, struct sockaddr_in6 f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {} + void Free() {if (Buffer) free (const_cast(Buffer)); } + const char *Buffer; + int Length; + int Offset; + struct sockaddr_in6 From; + }; + + std::deque OutboundPages; + int OutboundDataSize; + + struct sockaddr_in6 ReturnAddress; +}; + + +/************************ +class AcceptorDescriptor +************************/ + +class AcceptorDescriptor: public EventableDescriptor +{ + public: + AcceptorDescriptor (SOCKET, EventMachine_t*); + virtual ~AcceptorDescriptor(); + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat(); + + virtual bool SelectForRead() {return true;} + virtual bool SelectForWrite() {return false;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); }; + + static void StopAcceptor (const uintptr_t binding); +}; + +/******************** +class PipeDescriptor +********************/ + +#ifdef OS_UNIX +class PipeDescriptor: public EventableDescriptor +{ + public: + PipeDescriptor (SOCKET, pid_t, EventMachine_t*); + virtual ~PipeDescriptor() NO_EXCEPT_FALSE; + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat(); + + virtual bool SelectForRead(); + virtual bool SelectForWrite(); + + int SendOutboundData (const char*, unsigned long); + virtual int GetOutboundDataSize() {return OutboundDataSize;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } + + virtual bool GetSubprocessPid (pid_t*); + + protected: + struct OutboundPage { + OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {} + void Free() {if (Buffer) free (const_cast(Buffer)); } + const char *Buffer; + int Length; + int Offset; + }; + + protected: + bool bReadAttemptedAfterClose; + + std::deque OutboundPages; + int OutboundDataSize; + + pid_t SubprocessPid; + + private: + void _DispatchInboundData (const char *buffer, int size); +}; +#endif // OS_UNIX + + +/************************ +class KeyboardDescriptor +************************/ + +class KeyboardDescriptor: public EventableDescriptor +{ + public: + KeyboardDescriptor (EventMachine_t*); + virtual ~KeyboardDescriptor(); + + virtual void Read(); + virtual void Write(); + virtual void Heartbeat(); + + virtual bool SelectForRead() {return true;} + virtual bool SelectForWrite() {return false;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } + + protected: + bool bReadAttemptedAfterClose; + + private: + void _DispatchInboundData (const char *buffer, int size); +}; + + +/*********************** +class InotifyDescriptor +************************/ + +class InotifyDescriptor: public EventableDescriptor +{ + public: + InotifyDescriptor (EventMachine_t*); + virtual ~InotifyDescriptor(); + + void Read(); + void Write(); + + virtual void Heartbeat() {} + virtual bool SelectForRead() {return true;} + virtual bool SelectForWrite() {return false;} + + virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return false; } + virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return false; } +}; + +#endif // __EventableDescriptor__H_ diff --git a/bin/gems/eventmachine-1.2.7/ext/em.cpp b/bin/gems/eventmachine-1.2.7/ext/em.cpp new file mode 100644 index 00000000..29074850 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/em.cpp @@ -0,0 +1,2396 @@ +/***************************************************************************** + +$Id$ + +File: em.cpp +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +// THIS ENTIRE FILE WILL EVENTUALLY BE FOR UNIX BUILDS ONLY. +//#ifdef OS_UNIX + +#include "project.h" + +/* The numer of max outstanding timers was once a const enum defined in em.h. + * Now we define it here so that users can change its value if necessary. + */ +static unsigned int MaxOutstandingTimers = 100000; + +/* The number of accept() done at once in a single tick when the acceptor + * socket becomes readable. + */ +static unsigned int SimultaneousAcceptCount = 10; + +/* Internal helper to create a socket with SOCK_CLOEXEC set, and fall + * back to fcntl'ing it if the headers/runtime don't support it. + */ +SOCKET EmSocket (int domain, int type, int protocol) +{ + SOCKET sd; +#ifdef HAVE_SOCKET_CLOEXEC + sd = socket (domain, type | SOCK_CLOEXEC, protocol); + if (sd == INVALID_SOCKET) { + sd = socket (domain, type, protocol); + if (sd < 0) { + return sd; + } + SetFdCloexec(sd); + } +#else + sd = socket (domain, type, protocol); + if (sd == INVALID_SOCKET) { + return sd; + } + SetFdCloexec(sd); +#endif + return sd; +} + + +/*************************************** +STATIC EventMachine_t::GetMaxTimerCount +***************************************/ + +int EventMachine_t::GetMaxTimerCount() +{ + return MaxOutstandingTimers; +} + + +/*************************************** +STATIC EventMachine_t::SetMaxTimerCount +***************************************/ + +void EventMachine_t::SetMaxTimerCount (int count) +{ + /* Allow a user to increase the maximum number of outstanding timers. + * If this gets "too high" (a metric that is of course platform dependent), + * bad things will happen like performance problems and possible overuse + * of memory. + * The actual timer mechanism is very efficient so it's hard to know what + * the practical max, but 100,000 shouldn't be too problematical. + */ + if (count < 100) + count = 100; + MaxOutstandingTimers = count; +} + +int EventMachine_t::GetSimultaneousAcceptCount() +{ + return SimultaneousAcceptCount; +} + +void EventMachine_t::SetSimultaneousAcceptCount (int count) +{ + if (count < 1) + count = 1; + SimultaneousAcceptCount = count; +} + + +/****************************** +EventMachine_t::EventMachine_t +******************************/ + +EventMachine_t::EventMachine_t (EMCallback event_callback, Poller_t poller): + NumCloseScheduled (0), + HeartbeatInterval(2000000), + EventCallback (event_callback), + LoopBreakerReader (INVALID_SOCKET), + LoopBreakerWriter (INVALID_SOCKET), + bTerminateSignalReceived (false), + Poller (poller), + epfd (-1), + kqfd (-1) + #ifdef HAVE_INOTIFY + , inotify (NULL) + #endif +{ + // Default time-slice is just smaller than one hundred mills. + Quantum.tv_sec = 0; + Quantum.tv_usec = 90000; + + // Override the requested poller back to default if needed. + #if !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE) + Poller = Poller_Default; + #endif + + /* Initialize monotonic timekeeping on OS X before the first call to GetRealTime */ + #ifdef OS_DARWIN + (void) mach_timebase_info(&mach_timebase); + #endif + + #ifdef OS_WIN32 + TickCountTickover = 0; + LastTickCount = 0; + #endif + + // Make sure the current loop time is sane, in case we do any initializations of + // objects before we start running. + _UpdateTime(); + + /* We initialize the network library here (only on Windows of course) + * and initialize "loop breakers." Our destructor also does some network-level + * cleanup. There's thus an implicit assumption that any given instance of EventMachine_t + * will only call ::Run once. Is that a good assumption? Should we move some of these + * inits and de-inits into ::Run? + */ + #ifdef OS_WIN32 + WSADATA w; + WSAStartup (MAKEWORD (1, 1), &w); + #endif + + _InitializeLoopBreaker(); + SelectData = new SelectData_t(); +} + + +/******************************* +EventMachine_t::~EventMachine_t +*******************************/ + +EventMachine_t::~EventMachine_t() +{ + // Run down descriptors + size_t i; + for (i = 0; i < NewDescriptors.size(); i++) + delete NewDescriptors[i]; + for (i = 0; i < Descriptors.size(); i++) + delete Descriptors[i]; + + close (LoopBreakerReader); + close (LoopBreakerWriter); + + // Remove any file watch descriptors + while(!Files.empty()) { + std::map::iterator f = Files.begin(); + UnwatchFile (f->first); + } + + if (epfd != -1) + close (epfd); + if (kqfd != -1) + close (kqfd); + + delete SelectData; +} + + +/**************************** +EventMachine_t::ScheduleHalt +****************************/ + +void EventMachine_t::ScheduleHalt() +{ + /* This is how we stop the machine. + * This can be called by clients. Signal handlers will probably + * set the global flag. + * For now this means there can only be one EventMachine ever running at a time. + * + * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here, + * because it may be called from signal handlers invoked from code that we don't + * control. At this writing (20Sep06), EM does NOT install any signal handlers of + * its own. + * + * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens? + * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler. + */ + bTerminateSignalReceived = true; + + /* Signal the loopbreaker so we break out of long-running select/epoll/kqueue and + * notice the halt boolean is set. Signalling the loopbreaker also uses a single + * signal-safe syscall. + */ + SignalLoopBreaker(); +} + +bool EventMachine_t::Stopping() +{ + return bTerminateSignalReceived; +} + +/******************************* +EventMachine_t::SetTimerQuantum +*******************************/ + +void EventMachine_t::SetTimerQuantum (int interval) +{ + /* We get a timer-quantum expressed in milliseconds. + */ + + if ((interval < 5) || (interval > 5*60*1000)) + throw std::runtime_error ("invalid timer-quantum"); + + Quantum.tv_sec = interval / 1000; + Quantum.tv_usec = (interval % 1000) * 1000; +} + + +/************************************* +(STATIC) EventMachine_t::SetuidString +*************************************/ + +#ifdef OS_UNIX +void EventMachine_t::SetuidString (const char *username) +{ + /* This method takes a caller-supplied username and tries to setuid + * to that user. There is no meaningful implementation (and no error) + * on Windows. On Unix, a failure to setuid the caller-supplied string + * causes a fatal abort, because presumably the program is calling here + * in order to fulfill a security requirement. If we fail silently, + * the user may continue to run with too much privilege. + * + * TODO, we need to decide on and document a way of generating C++ level errors + * that can be wrapped in documented Ruby exceptions, so users can catch + * and handle them. And distinguish it from errors that we WON'T let the Ruby + * user catch (like security-violations and resource-overallocation). + * A setuid failure here would be in the latter category. + */ + + if (!username || !*username) + throw std::runtime_error ("setuid_string failed: no username specified"); + + errno = 0; + struct passwd *p = getpwnam (username); + if (!p) { + if (errno) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "setuid_string failed: %s", strerror(errno)); + throw std::runtime_error (buf); + } else { + throw std::runtime_error ("setuid_string failed: unknown username"); + } + } + + if (setuid (p->pw_uid) != 0) + throw std::runtime_error ("setuid_string failed: no setuid"); + + // Success. +} +#else +void EventMachine_t::SetuidString (const char *username UNUSED) { } +#endif + +/**************************************** +(STATIC) EventMachine_t::SetRlimitNofile +****************************************/ + +#ifdef OS_UNIX +int EventMachine_t::SetRlimitNofile (int nofiles) +{ + struct rlimit rlim; + getrlimit (RLIMIT_NOFILE, &rlim); + if (nofiles >= 0) { + rlim.rlim_cur = nofiles; + if ((unsigned int)nofiles > rlim.rlim_max) + rlim.rlim_max = nofiles; + setrlimit (RLIMIT_NOFILE, &rlim); + // ignore the error return, for now at least. + // TODO, emit an error message someday when we have proper debug levels. + } + getrlimit (RLIMIT_NOFILE, &rlim); + return rlim.rlim_cur; +} +#else +int EventMachine_t::SetRlimitNofile (int nofiles UNUSED) { return 0; } +#endif + +/********************************* +EventMachine_t::SignalLoopBreaker +*********************************/ + +void EventMachine_t::SignalLoopBreaker() +{ + #ifdef OS_UNIX + (void)write (LoopBreakerWriter, "", 1); + #endif + #ifdef OS_WIN32 + sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget)); + #endif +} + + +/************************************** +EventMachine_t::_InitializeLoopBreaker +**************************************/ + +void EventMachine_t::_InitializeLoopBreaker() +{ + /* A "loop-breaker" is a socket-descriptor that we can write to in order + * to break the main select loop. Primarily useful for things running on + * threads other than the main EM thread, so they can trigger processing + * of events that arise exogenously to the EM. + * Keep the loop-breaker pipe out of the main descriptor set, otherwise + * its events will get passed on to user code. + */ + + #ifdef OS_UNIX + int fd[2]; +#if defined (HAVE_CLOEXEC) && defined (HAVE_PIPE2) + int pipestatus = pipe2(fd, O_CLOEXEC); + if (pipestatus < 0) { + if (pipe(fd)) + throw std::runtime_error (strerror(errno)); + } +#else + if (pipe (fd)) + throw std::runtime_error (strerror(errno)); +#endif + if (!SetFdCloexec(fd[0]) || !SetFdCloexec(fd[1])) + throw std::runtime_error (strerror(errno)); + + LoopBreakerWriter = fd[1]; + LoopBreakerReader = fd[0]; + + /* 16Jan11: Make sure the pipe is non-blocking, so more than 65k loopbreaks + * in one tick do not fill up the pipe and block the process on write() */ + SetSocketNonblocking (LoopBreakerWriter); + #endif + + #ifdef OS_WIN32 + SOCKET sd = EmSocket (AF_INET, SOCK_DGRAM, 0); + if (sd == INVALID_SOCKET) + throw std::runtime_error ("no loop breaker socket"); + SetSocketNonblocking (sd); + + memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget)); + LoopBreakerTarget.sin_family = AF_INET; + LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1"); + + srand ((int)time(NULL)); + int i; + for (i=0; i < 100; i++) { + int r = (rand() % 10000) + 20000; + LoopBreakerTarget.sin_port = htons (r); + if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0) + break; + } + + if (i == 100) + throw std::runtime_error ("no loop breaker"); + LoopBreakerReader = sd; + #endif + + #ifdef HAVE_EPOLL + if (Poller == Poller_Epoll) { + epfd = epoll_create (MaxEpollDescriptors); + if (epfd == -1) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno)); + throw std::runtime_error (buf); + } + int cloexec = fcntl (epfd, F_GETFD, 0); + assert (cloexec >= 0); + cloexec |= FD_CLOEXEC; + fcntl (epfd, F_SETFD, cloexec); + + assert (LoopBreakerReader >= 0); + LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this); + assert (ld); + Add (ld); + } + #endif + + #ifdef HAVE_KQUEUE + if (Poller == Poller_Kqueue) { + kqfd = kqueue(); + if (kqfd == -1) { + char buf[200]; + snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno)); + throw std::runtime_error (buf); + } + // cloexec not needed. By definition, kqueues are not carried across forks. + + assert (LoopBreakerReader >= 0); + LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this); + assert (ld); + Add (ld); + } + #endif +} + +/*************************** +EventMachine_t::_UpdateTime +***************************/ + +void EventMachine_t::_UpdateTime() +{ + MyCurrentLoopTime = GetRealTime(); +} + +/*************************** +EventMachine_t::GetRealTime +***************************/ + +// Two great writeups of cross-platform monotonic time are at: +// http://www.python.org/dev/peps/pep-0418 +// http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking +// Uncomment the #pragma messages to confirm which compile-time option was used +uint64_t EventMachine_t::GetRealTime() +{ + uint64_t current_time; + + #if defined(HAVE_CONST_CLOCK_MONOTONIC_RAW) + // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC_RAW" + // Linux 2.6.28 and above + struct timespec tv; + clock_gettime (CLOCK_MONOTONIC_RAW, &tv); + current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000)); + + #elif defined(HAVE_CONST_CLOCK_MONOTONIC) + // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC" + // Linux, FreeBSD 5.0 and above, Solaris 8 and above, OpenBSD, NetBSD, DragonflyBSD + struct timespec tv; + clock_gettime (CLOCK_MONOTONIC, &tv); + current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000)); + + #elif defined(HAVE_GETHRTIME) + // #pragma message "GetRealTime: gethrtime" + // Solaris and HP-UX + current_time = (uint64_t)gethrtime() / 1000; + + #elif defined(OS_DARWIN) + // #pragma message "GetRealTime: mach_absolute_time" + // Mac OS X + // https://developer.apple.com/library/mac/qa/qa1398/_index.html + current_time = mach_absolute_time() * mach_timebase.numer / mach_timebase.denom / 1000; + + #elif defined(OS_UNIX) + // #pragma message "GetRealTime: gettimeofday" + // Unix fallback + struct timeval tv; + gettimeofday (&tv, NULL); + current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec)); + + #elif defined(OS_WIN32) + // #pragma message "GetRealTime: GetTickCount" + // Future improvement: use GetTickCount64 in Windows Vista / Server 2008 + unsigned tick = GetTickCount(); + if (tick < LastTickCount) + TickCountTickover += 1; + LastTickCount = tick; + current_time = ((uint64_t)TickCountTickover << 32) + (uint64_t)tick; + current_time *= 1000; // convert to microseconds + + #else + // #pragma message "GetRealTime: time" + // Universal fallback + current_time = (uint64_t)time(NULL) * 1000000LL; + #endif + + return current_time; +} + +/*********************************** +EventMachine_t::_DispatchHeartbeats +***********************************/ + +void EventMachine_t::_DispatchHeartbeats() +{ + // Store the first processed heartbeat descriptor and bail out if + // we see it again. This fixes an infinite loop in case the system time + // is changed out from underneath MyCurrentLoopTime. + const EventableDescriptor *head = NULL; + + while (true) { + std::multimap::iterator i = Heartbeats.begin(); + if (i == Heartbeats.end()) + break; + if (i->first > MyCurrentLoopTime) + break; + + EventableDescriptor *ed = i->second; + if (ed == head) + break; + + ed->Heartbeat(); + QueueHeartbeat(ed); + + if (head == NULL) + head = ed; + } +} + +/****************************** +EventMachine_t::QueueHeartbeat +******************************/ + +void EventMachine_t::QueueHeartbeat(EventableDescriptor *ed) +{ + uint64_t heartbeat = ed->GetNextHeartbeat(); + + if (heartbeat) { + #ifndef HAVE_MAKE_PAIR + Heartbeats.insert (std::multimap::value_type (heartbeat, ed)); + #else + Heartbeats.insert (std::make_pair (heartbeat, ed)); + #endif + } +} + +/****************************** +EventMachine_t::ClearHeartbeat +******************************/ + +void EventMachine_t::ClearHeartbeat(uint64_t key, EventableDescriptor* ed) +{ + std::multimap::iterator it; + std::pair::iterator,std::multimap::iterator> ret; + ret = Heartbeats.equal_range (key); + for (it = ret.first; it != ret.second; ++it) { + if (it->second == ed) { + Heartbeats.erase (it); + break; + } + } +} + +/******************* +EventMachine_t::Run +*******************/ + +void EventMachine_t::Run() +{ + while (RunOnce()) ; +} + +/*********************** +EventMachine_t::RunOnce +***********************/ + +bool EventMachine_t::RunOnce() +{ + _UpdateTime(); + _RunTimers(); + + /* _Add must precede _Modify because the same descriptor might + * be on both lists during the same pass through the machine, + * and to modify a descriptor before adding it would fail. + */ + _AddNewDescriptors(); + _ModifyDescriptors(); + + switch (Poller) { + case Poller_Epoll: + _RunEpollOnce(); + break; + case Poller_Kqueue: + _RunKqueueOnce(); + break; + case Poller_Default: + _RunSelectOnce(); + break; + } + + _DispatchHeartbeats(); + _CleanupSockets(); + + if (bTerminateSignalReceived) + return false; + + return true; +} + + +/***************************** +EventMachine_t::_RunEpollOnce +*****************************/ + +void EventMachine_t::_RunEpollOnce() +{ + #ifdef HAVE_EPOLL + assert (epfd != -1); + int s; + + timeval tv = _TimeTilNextEvent(); + + #ifdef BUILD_FOR_RUBY + int ret = 0; + + #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD + if ((ret = rb_wait_for_single_fd(epfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) { + #else + fd_set fdreads; + + FD_ZERO(&fdreads); + FD_SET(epfd, &fdreads); + + if ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) { + #endif + if (ret == -1) { + assert(errno != EINVAL); + assert(errno != EBADF); + } + return; + } + + TRAP_BEG; + s = epoll_wait (epfd, epoll_events, MaxEvents, 0); + TRAP_END; + #else + int duration = 0; + duration = duration + (tv.tv_sec * 1000); + duration = duration + (tv.tv_usec / 1000); + s = epoll_wait (epfd, epoll_events, MaxEvents, duration); + #endif + + if (s > 0) { + for (int i=0; i < s; i++) { + EventableDescriptor *ed = (EventableDescriptor*) epoll_events[i].data.ptr; + + if (ed->IsWatchOnly() && ed->GetSocket() == INVALID_SOCKET) + continue; + + assert(ed->GetSocket() != INVALID_SOCKET); + + if (epoll_events[i].events & EPOLLIN) + ed->Read(); + if (epoll_events[i].events & EPOLLOUT) + ed->Write(); + if (epoll_events[i].events & (EPOLLERR | EPOLLHUP)) + ed->HandleError(); + } + } + else if (s < 0) { + // epoll_wait can fail on error in a handful of ways. + // If this happens, then wait for a little while to avoid busy-looping. + // If the error was EINTR, we probably caught SIGCHLD or something, + // so keep the wait short. + timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000}; + EmSelect (0, NULL, NULL, NULL, &tv); + } + #else + throw std::runtime_error ("epoll is not implemented on this platform"); + #endif +} + + +/****************************** +EventMachine_t::_RunKqueueOnce +******************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::_RunKqueueOnce() +{ + assert (kqfd != -1); + int k; + + timeval tv = _TimeTilNextEvent(); + + struct timespec ts; + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + + #ifdef BUILD_FOR_RUBY + int ret = 0; + + #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD + if ((ret = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) { + #else + fd_set fdreads; + + FD_ZERO(&fdreads); + FD_SET(kqfd, &fdreads); + + if ((ret = rb_thread_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) { + #endif + if (ret == -1) { + assert(errno != EINVAL); + assert(errno != EBADF); + } + return; + } + + TRAP_BEG; + ts.tv_sec = ts.tv_nsec = 0; + k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts); + TRAP_END; + #else + k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts); + #endif + + struct kevent *ke = Karray; + while (k > 0) { + switch (ke->filter) + { + case EVFILT_VNODE: + _HandleKqueueFileEvent (ke); + break; + + case EVFILT_PROC: + _HandleKqueuePidEvent (ke); + break; + + case EVFILT_READ: + case EVFILT_WRITE: + EventableDescriptor *ed = (EventableDescriptor*) (ke->udata); + assert (ed); + + if (ed->IsWatchOnly() && ed->GetSocket() == INVALID_SOCKET) + break; + + if (ke->filter == EVFILT_READ) + ed->Read(); + else if (ke->filter == EVFILT_WRITE) + ed->Write(); + else + std::cerr << "Discarding unknown kqueue event " << ke->filter << std::endl; + + break; + } + + --k; + ++ke; + } + + // TODO, replace this with rb_thread_blocking_region for 1.9 builds. + #ifdef BUILD_FOR_RUBY + if (!rb_thread_alone()) { + rb_thread_schedule(); + } + #endif +} +#else +void EventMachine_t::_RunKqueueOnce() +{ + throw std::runtime_error ("kqueue is not implemented on this platform"); +} +#endif + + +/********************************* +EventMachine_t::_TimeTilNextEvent +*********************************/ + +timeval EventMachine_t::_TimeTilNextEvent() +{ + // 29jul11: Changed calculation base from MyCurrentLoopTime to the + // real time. As MyCurrentLoopTime is set at the beginning of an + // iteration and this calculation is done at the end, evenmachine + // will potentially oversleep by the amount of time the iteration + // took to execute. + uint64_t next_event = 0; + uint64_t current_time = GetRealTime(); + + if (!Heartbeats.empty()) { + std::multimap::iterator heartbeats = Heartbeats.begin(); + next_event = heartbeats->first; + } + + if (!Timers.empty()) { + std::multimap::iterator timers = Timers.begin(); + if (next_event == 0 || timers->first < next_event) + next_event = timers->first; + } + + if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) { + next_event = current_time; + } + + timeval tv; + + if (NumCloseScheduled > 0 || bTerminateSignalReceived) { + tv.tv_sec = tv.tv_usec = 0; + } else if (next_event == 0) { + tv = Quantum; + } else { + if (next_event > current_time) { + uint64_t duration = next_event - current_time; + tv.tv_sec = duration / 1000000; + tv.tv_usec = duration % 1000000; + } else { + tv.tv_sec = tv.tv_usec = 0; + } + } + + return tv; +} + +/******************************* +EventMachine_t::_CleanupSockets +*******************************/ + +void EventMachine_t::_CleanupSockets() +{ + // TODO, rip this out and only delete the descriptors we know have died, + // rather than traversing the whole list. + // Modified 05Jan08 per suggestions by Chris Heath. It's possible that + // an EventableDescriptor will have a descriptor value of -1. That will + // happen if EventableDescriptor::Close was called on it. In that case, + // don't call epoll_ctl to remove the socket's filters from the epoll set. + // According to the epoll docs, this happens automatically when the + // descriptor is closed anyway. This is different from the case where + // the socket has already been closed but the descriptor in the ED object + // hasn't yet been set to INVALID_SOCKET. + // In kqueue, closing a descriptor automatically removes its event filters. + int i, j; + int nSockets = Descriptors.size(); + for (i=0, j=0; i < nSockets; i++) { + EventableDescriptor *ed = Descriptors[i]; + assert (ed); + if (ed->ShouldDelete()) { + #ifdef HAVE_EPOLL + if (Poller == Poller_Epoll) { + assert (epfd != -1); + if (ed->GetSocket() != INVALID_SOCKET) { + int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent()); + // ENOENT or EBADF are not errors because the socket may be already closed when we get here. + if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno)); + throw std::runtime_error (buf); + } + } + ModifiedDescriptors.erase(ed); + } + #endif + delete ed; + } + else + Descriptors [j++] = ed; + } + while ((size_t)j < Descriptors.size()) + Descriptors.pop_back(); +} + +/********************************* +EventMachine_t::_ModifyEpollEvent +*********************************/ + +#ifdef HAVE_EPOLL +void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed) +{ + if (Poller == Poller_Epoll) { + assert (epfd != -1); + assert (ed); + assert (ed->GetSocket() != INVALID_SOCKET); + int e = epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent()); + if (e) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to modify epoll event: %s", strerror(errno)); + throw std::runtime_error (buf); + } + } +} +#else +void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed UNUSED) { } +#endif + + +/************************** +SelectData_t::SelectData_t +**************************/ + +SelectData_t::SelectData_t() +{ + maxsocket = 0; + rb_fd_init (&fdreads); + rb_fd_init (&fdwrites); + rb_fd_init (&fderrors); +} + +SelectData_t::~SelectData_t() +{ + rb_fd_term (&fdreads); + rb_fd_term (&fdwrites); + rb_fd_term (&fderrors); +} + +#ifdef BUILD_FOR_RUBY +/***************** +_SelectDataSelect +*****************/ + +#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) +static VALUE _SelectDataSelect (void *v) +{ + SelectData_t *sd = (SelectData_t*)v; + sd->nSockets = rb_fd_select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); + return Qnil; +} +#endif + +/********************* +SelectData_t::_Select +*********************/ + +int SelectData_t::_Select() +{ + #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) + // added in ruby 1.9.3 + rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0); + return nSockets; + #elif defined(HAVE_TBR) + // added in ruby 1.9.1, deprecated in ruby 2.0.0 + rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0); + return nSockets; + #else + return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv); + #endif +} +#endif + +void SelectData_t::_Clear() +{ + maxsocket = 0; + rb_fd_zero (&fdreads); + rb_fd_zero (&fdwrites); + rb_fd_zero (&fderrors); +} + +/****************************** +EventMachine_t::_RunSelectOnce +******************************/ + +void EventMachine_t::_RunSelectOnce() +{ + // Crank the event machine once. + // If there are no descriptors to process, then sleep + // for a few hundred mills to avoid busy-looping. + // This is based on a select loop. Alternately provide epoll + // if we know we're running on a 2.6 kernel. + // epoll will be effective if we provide it as an alternative, + // however it has the same problem interoperating with Ruby + // threads that select does. + + // Get ready for select() + SelectData->_Clear(); + + // Always read the loop-breaker reader. + // Changed 23Aug06, provisionally implemented for Windows with a UDP socket + // running on localhost with a randomly-chosen port. (*Puke*) + // Windows has a version of the Unix pipe() library function, but it doesn't + // give you back descriptors that are selectable. + rb_fd_set (LoopBreakerReader, &(SelectData->fdreads)); + if (SelectData->maxsocket < LoopBreakerReader) + SelectData->maxsocket = LoopBreakerReader; + + // prepare the sockets for reading and writing + size_t i; + for (i = 0; i < Descriptors.size(); i++) { + EventableDescriptor *ed = Descriptors[i]; + assert (ed); + SOCKET sd = ed->GetSocket(); + if (ed->IsWatchOnly() && sd == INVALID_SOCKET) + continue; + assert (sd != INVALID_SOCKET); + + if (ed->SelectForRead()) + rb_fd_set (sd, &(SelectData->fdreads)); + if (ed->SelectForWrite()) + rb_fd_set (sd, &(SelectData->fdwrites)); + + #ifdef OS_WIN32 + /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable. + Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html + */ + if (ed->IsConnectPending()) + rb_fd_set (sd, &(SelectData->fderrors)); + #endif + + if (SelectData->maxsocket < sd) + SelectData->maxsocket = sd; + } + + + { // read and write the sockets + //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000. + //timeval tv = Quantum; + SelectData->tv = _TimeTilNextEvent(); + int s = SelectData->_Select(); + //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0); + //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv)); + //int s = SelectData.nSockets; + if (s > 0) { + /* Changed 01Jun07. We used to handle the Loop-breaker right here. + * Now we do it AFTER all the regular descriptors. There's an + * incredibly important and subtle reason for this. Code on + * loop breakers is sometimes used to cause the reactor core to + * cycle (for example, to allow outbound network buffers to drain). + * If a loop-breaker handler reschedules itself (say, after determining + * that the write buffers are still too full), then it will execute + * IMMEDIATELY if _ReadLoopBreaker is done here instead of after + * the other descriptors are processed. That defeats the whole purpose. + */ + for (i=0; i < Descriptors.size(); i++) { + EventableDescriptor *ed = Descriptors[i]; + assert (ed); + SOCKET sd = ed->GetSocket(); + if (ed->IsWatchOnly() && sd == INVALID_SOCKET) + continue; + assert (sd != INVALID_SOCKET); + + if (rb_fd_isset (sd, &(SelectData->fdwrites))) { + // Double-check SelectForWrite() still returns true. If not, one of the callbacks must have + // modified some value since we checked SelectForWrite() earlier in this method. + if (ed->SelectForWrite()) + ed->Write(); + } + if (rb_fd_isset (sd, &(SelectData->fdreads))) + ed->Read(); + if (rb_fd_isset (sd, &(SelectData->fderrors))) + ed->HandleError(); + } + + if (rb_fd_isset (LoopBreakerReader, &(SelectData->fdreads))) + _ReadLoopBreaker(); + } + else if (s < 0) { + switch (errno) { + case EBADF: + _CleanBadDescriptors(); + break; + case EINVAL: + throw std::runtime_error ("Somehow EM passed an invalid nfds or invalid timeout to select(2), please report this!"); + break; + default: + // select can fail on error in a handful of ways. + // If this happens, then wait for a little while to avoid busy-looping. + // If the error was EINTR, we probably caught SIGCHLD or something, + // so keep the wait short. + timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000}; + EmSelect (0, NULL, NULL, NULL, &tv); + } + } + } +} + +void EventMachine_t::_CleanBadDescriptors() +{ + size_t i; + + for (i = 0; i < Descriptors.size(); i++) { + EventableDescriptor *ed = Descriptors[i]; + if (ed->ShouldDelete()) + continue; + + SOCKET sd = ed->GetSocket(); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(sd, &fds); + + int ret = rb_fd_select(sd + 1, &fds, NULL, NULL, &tv); + rb_fd_term(&fds); + + if (ret == -1) { + if (errno == EBADF) + ed->ScheduleClose(false); + } + } +} + +/******************************** +EventMachine_t::_ReadLoopBreaker +********************************/ + +void EventMachine_t::_ReadLoopBreaker() +{ + /* The loop breaker has selected readable. + * Read it ONCE (it may block if we try to read it twice) + * and send a loop-break event back to user code. + */ + char buffer [1024]; + (void)read (LoopBreakerReader, buffer, sizeof(buffer)); + if (EventCallback) + (*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0); +} + + +/************************** +EventMachine_t::_RunTimers +**************************/ + +void EventMachine_t::_RunTimers() +{ + // These are caller-defined timer handlers. + // We rely on the fact that multimaps sort by their keys to avoid + // inspecting the whole list every time we come here. + // Just keep inspecting and processing the list head until we hit + // one that hasn't expired yet. + + while (true) { + std::multimap::iterator i = Timers.begin(); + if (i == Timers.end()) + break; + if (i->first > MyCurrentLoopTime) + break; + if (EventCallback) + (*EventCallback) (0, EM_TIMER_FIRED, NULL, i->second.GetBinding()); + Timers.erase (i); + } +} + + + +/*********************************** +EventMachine_t::InstallOneshotTimer +***********************************/ + +const uintptr_t EventMachine_t::InstallOneshotTimer (uint64_t milliseconds) +{ + if (Timers.size() > MaxOutstandingTimers) + return false; + + uint64_t fire_at = GetRealTime(); + fire_at += ((uint64_t)milliseconds) * 1000LL; + + Timer_t t; + #ifndef HAVE_MAKE_PAIR + std::multimap::iterator i = Timers.insert (std::multimap::value_type (fire_at, t)); + #else + std::multimap::iterator i = Timers.insert (std::make_pair (fire_at, t)); + #endif + return i->second.GetBinding(); +} + + +/******************************* +EventMachine_t::ConnectToServer +*******************************/ + +const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port) +{ + /* We want to spend no more than a few seconds waiting for a connection + * to a remote host. So we use a nonblocking connect. + * Linux disobeys the usual rules for nonblocking connects. + * Per Stevens (UNP p.410), you expect a nonblocking connect to select + * both readable and writable on error, and not to return EINPROGRESS + * if the connect can be fulfilled immediately. Linux violates both + * of these expectations. + * Any kind of nonblocking connect on Linux returns EINPROGRESS. + * The socket will then return writable when the disposition of the + * connect is known, but it will not also be readable in case of + * error! Weirdly, it will be readable in case there is data to read!!! + * (Which can happen with protocols like SSH and SMTP.) + * I suppose if you were so inclined you could consider this logical, + * but it's not the way Unix has historically done it. + * So we ignore the readable flag and read getsockopt to see if there + * was an error connecting. A select timeout works as expected. + * In regard to getsockopt: Linux does the Berkeley-style thing, + * not the Solaris-style, and returns zero with the error code in + * the error parameter. + * Return the binding-text of the newly-created pending connection, + * or NULL if there was a problem. + */ + + if (!server || !*server || !port) + throw std::runtime_error ("invalid server or port"); + + struct sockaddr_storage bind_as; + size_t bind_as_len = sizeof bind_as; + int gai = name2address (server, port, SOCK_STREAM, (struct sockaddr *)&bind_as, &bind_as_len); + if (gai != 0) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to resolve address: %s", gai_strerror(gai)); + throw std::runtime_error (buf); + } + + SOCKET sd = EmSocket (bind_as.ss_family, SOCK_STREAM, 0); + if (sd == INVALID_SOCKET) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno)); + throw std::runtime_error (buf); + } + + // From here on, ALL error returns must close the socket. + // Set the new socket nonblocking. + if (!SetSocketNonblocking (sd)) { + close (sd); + throw std::runtime_error ("unable to set socket as non-blocking"); + } + // Disable slow-start (Nagle algorithm). + int one = 1; + setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one)); + // Set reuseaddr to improve performance on restarts + setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one)); + + if (bind_addr) { + struct sockaddr_storage bind_to; + size_t bind_to_len = sizeof bind_to; + gai = name2address (bind_addr, bind_port, SOCK_STREAM, (struct sockaddr *)&bind_to, &bind_to_len); + if (gai != 0) { + close (sd); + char buf [200]; + snprintf (buf, sizeof(buf)-1, "invalid bind address: %s", gai_strerror(gai)); + throw std::runtime_error (buf); + } + if (bind (sd, (struct sockaddr *)&bind_to, bind_to_len) < 0) { + close (sd); + throw std::runtime_error ("couldn't bind to address"); + } + } + + uintptr_t out = 0; + + #ifdef OS_UNIX + int e_reason = 0; + if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) { + // This is a connect success, which Linux appears + // never to give when the socket is nonblocking, + // even if the connection is intramachine or to + // localhost. + + /* Changed this branch 08Aug06. Evidently some kernels + * (FreeBSD for example) will actually return success from + * a nonblocking connect. This is a pretty simple case, + * just set up the new connection and clear the pending flag. + * Thanks to Chris Ochs for helping track this down. + * This branch never gets taken on Linux or (oddly) OSX. + * The original behavior was to throw an unimplemented, + * which the user saw as a fatal exception. Very unfriendly. + * + * Tweaked 10Aug06. Even though the connect disposition is + * known, we still set the connect-pending flag. That way + * some needed initialization will happen in the ConnectionDescriptor. + * (To wit, the ConnectionCompleted event gets sent to the client.) + */ + ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + cd->SetConnectPending (true); + Add (cd); + out = cd->GetBinding(); + } + else if (errno == EINPROGRESS) { + // Errno will generally always be EINPROGRESS, but on Linux + // we have to look at getsockopt to be sure what really happened. + int error = 0; + socklen_t len; + len = sizeof(error); + int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len); + if ((o == 0) && (error == 0)) { + // Here, there's no disposition. + // Put the connection on the stack and wait for it to complete + // or time out. + ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + cd->SetConnectPending (true); + Add (cd); + out = cd->GetBinding(); + } else { + // Fall through to the !out case below. + e_reason = error; + } + } + else { + // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc). + // Fall through to the !out case below + e_reason = errno; + } + + if (!out) { + /* This could be connection refused or some such thing. + * We will come here on Linux if a localhost connection fails. + * Changed 16Jul06: Originally this branch was a no-op, and + * we'd drop down to the end of the method, close the socket, + * and return NULL, which would cause the caller to GET A + * FATAL EXCEPTION. Now we keep the socket around but schedule an + * immediate close on it, so the caller will get a close-event + * scheduled on it. This was only an issue for localhost connections + * to non-listening ports. We may eventually need to revise this + * revised behavior, in case it causes problems like making it hard + * for people to know that a failure occurred. + */ + ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + cd->SetUnbindReasonCode (e_reason); + cd->ScheduleClose (false); + Add (cd); + out = cd->GetBinding(); + } + #endif + + #ifdef OS_WIN32 + if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) { + // This is a connect success, which Windows appears + // never to give when the socket is nonblocking, + // even if the connection is intramachine or to + // localhost. + throw std::runtime_error ("unimplemented"); + } + else if (WSAGetLastError() == WSAEWOULDBLOCK) { + // Here, there's no disposition. + // Windows appears not to surface refused connections or + // such stuff at this point. + // Put the connection on the stack and wait for it to complete + // or time out. + ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + cd->SetConnectPending (true); + Add (cd); + out = cd->GetBinding(); + } + else { + // The error from connect was something other then WSAEWOULDBLOCK. + } + + #endif + + if (!out) + close (sd); + return out; +} + +/*********************************** +EventMachine_t::ConnectToUnixServer +***********************************/ + +#ifdef OS_UNIX +const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server) +{ + /* Connect to a Unix-domain server, which by definition is running + * on the same host. + * There is no meaningful implementation on Windows. + * There's no need to do a nonblocking connect, since the connection + * is always local and can always be fulfilled immediately. + */ + + uintptr_t out = 0; + + if (!server || !*server) + return 0; + + sockaddr_un pun; + memset (&pun, 0, sizeof(pun)); + pun.sun_family = AF_LOCAL; + + // You ordinarily expect the server name field to be at least 1024 bytes long, + // but on Linux it can be MUCH shorter. + if (strlen(server) >= sizeof(pun.sun_path)) + throw std::runtime_error ("unix-domain server name is too long"); + + + strcpy (pun.sun_path, server); + + SOCKET fd = EmSocket (AF_LOCAL, SOCK_STREAM, 0); + if (fd == INVALID_SOCKET) + return 0; + + // From here on, ALL error returns must close the socket. + // NOTE: At this point, the socket is still a blocking socket. + if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) { + close (fd); + return 0; + } + + // Set the newly-connected socket nonblocking. + if (!SetSocketNonblocking (fd)) { + close (fd); + return 0; + } + + // Set up a connection descriptor and add it to the event-machine. + // Observe, even though we know the connection status is connect-success, + // we still set the "pending" flag, so some needed initializations take + // place. + ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + cd->SetConnectPending (true); + Add (cd); + out = cd->GetBinding(); + + if (!out) + close (fd); + + return out; +} +#else +const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server UNUSED) +{ + throw std::runtime_error ("unix-domain connection unavailable on this platform"); +} +#endif + +/************************ +EventMachine_t::AttachFD +************************/ + +const uintptr_t EventMachine_t::AttachFD (SOCKET fd, bool watch_mode) +{ + #ifdef OS_UNIX + if (fcntl(fd, F_GETFL, 0) < 0) { + if (errno) { + throw std::runtime_error (strerror(errno)); + } else { + throw std::runtime_error ("invalid file descriptor"); + } + } + #endif + + #ifdef OS_WIN32 + // TODO: add better check for invalid file descriptors (see ioctlsocket or getsockopt) + if (fd == INVALID_SOCKET) + throw std::runtime_error ("invalid file descriptor"); + #endif + + {// Check for duplicate descriptors + size_t i; + for (i = 0; i < Descriptors.size(); i++) { + EventableDescriptor *ed = Descriptors[i]; + assert (ed); + if (ed->GetSocket() == fd) + throw std::runtime_error ("adding existing descriptor"); + } + + for (i = 0; i < NewDescriptors.size(); i++) { + EventableDescriptor *ed = NewDescriptors[i]; + assert (ed); + if (ed->GetSocket() == fd) + throw std::runtime_error ("adding existing new descriptor"); + } + } + + if (!watch_mode) + SetSocketNonblocking(fd); + + ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this); + if (!cd) + throw std::runtime_error ("no connection allocated"); + + cd->SetAttached(true); + cd->SetWatchOnly(watch_mode); + cd->SetConnectPending (false); + + Add (cd); + + const uintptr_t out = cd->GetBinding(); + return out; +} + +/************************ +EventMachine_t::DetachFD +************************/ + +int EventMachine_t::DetachFD (EventableDescriptor *ed) +{ + if (!ed) + throw std::runtime_error ("detaching bad descriptor"); + + SOCKET fd = ed->GetSocket(); + + #ifdef HAVE_EPOLL + if (Poller == Poller_Epoll) { + if (ed->GetSocket() != INVALID_SOCKET) { + assert (epfd != -1); + int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent()); + // ENOENT or EBADF are not errors because the socket may be already closed when we get here. + if (e && (errno != ENOENT) && (errno != EBADF)) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno)); + throw std::runtime_error (buf); + } + } + } + #endif + + #ifdef HAVE_KQUEUE + if (Poller == Poller_Kqueue) { + // remove any read/write events for this fd + struct kevent k; +#ifdef __NetBSD__ + EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t)ed); +#else + EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, ed); +#endif + int t = kevent (kqfd, &k, 1, NULL, 0, NULL); + if (t < 0 && (errno != ENOENT) && (errno != EBADF)) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to delete kqueue event: %s", strerror(errno)); + throw std::runtime_error (buf); + } + } + #endif + + // Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick + ModifiedDescriptors.erase (ed); + + // Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD + for (size_t i = 0; i < NewDescriptors.size(); i++) { + if (ed == NewDescriptors[i]) { + NewDescriptors.erase(NewDescriptors.begin() + i); + break; + } + } + + // Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed), + // and also to prevent anyone from calling close() on the detached fd + ed->SetSocketInvalid(); + + return fd; +} + +/************ +name2address +************/ + +int EventMachine_t::name2address (const char *server, int port, int socktype, struct sockaddr *addr, size_t *addr_len) +{ + if (!server || !*server) + server = "0.0.0.0"; + + struct addrinfo *ai; + struct addrinfo hints; + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = socktype; + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG; + + char portstr[12]; + snprintf(portstr, sizeof(portstr), "%u", port); + + int gai = getaddrinfo (server, portstr, &hints, &ai); + if (gai == 0) { + assert (ai->ai_addrlen <= *addr_len); + memcpy (addr, ai->ai_addr, ai->ai_addrlen); + *addr_len = ai->ai_addrlen; + freeaddrinfo(ai); + } + + return gai; +} + + +/******************************* +EventMachine_t::CreateTcpServer +*******************************/ + +const uintptr_t EventMachine_t::CreateTcpServer (const char *server, int port) +{ + /* Create a TCP-acceptor (server) socket and add it to the event machine. + * Return the binding of the new acceptor to the caller. + * This binding will be referenced when the new acceptor sends events + * to indicate accepted connections. + */ + + + struct sockaddr_storage bind_here; + size_t bind_here_len = sizeof bind_here; + if (0 != name2address (server, port, SOCK_STREAM, (struct sockaddr *)&bind_here, &bind_here_len)) + return 0; + + SOCKET sd_accept = EmSocket (bind_here.ss_family, SOCK_STREAM, 0); + if (sd_accept == INVALID_SOCKET) { + goto fail; + } + + { // set reuseaddr to improve performance on restarts. + int oval = 1; + if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) { + //__warning ("setsockopt failed while creating listener",""); + goto fail; + } + } + + { // set CLOEXEC. Only makes sense on Unix + #ifdef OS_UNIX + int cloexec = fcntl (sd_accept, F_GETFD, 0); + assert (cloexec >= 0); + cloexec |= FD_CLOEXEC; + fcntl (sd_accept, F_SETFD, cloexec); + #endif + } + + + if (bind (sd_accept, (struct sockaddr *)&bind_here, bind_here_len)) { + //__warning ("binding failed"); + goto fail; + } + + if (listen (sd_accept, 100)) { + //__warning ("listen failed"); + goto fail; + } + + return AttachSD(sd_accept); + + fail: + if (sd_accept != INVALID_SOCKET) + close (sd_accept); + return 0; +} + + +/********************************** +EventMachine_t::OpenDatagramSocket +**********************************/ + +const uintptr_t EventMachine_t::OpenDatagramSocket (const char *address, int port) +{ + uintptr_t output_binding = 0; + + struct sockaddr_storage bind_here; + size_t bind_here_len = sizeof bind_here; + if (0 != name2address (address, port, SOCK_DGRAM, (struct sockaddr *)&bind_here, &bind_here_len)) + return 0; + + // from here on, early returns must close the socket! + SOCKET sd = EmSocket (bind_here.ss_family, SOCK_DGRAM, 0); + if (sd == INVALID_SOCKET) + goto fail; + + { // set the SO_REUSEADDR on the socket before we bind, otherwise it won't work for a second one + int oval = 1; + if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) + goto fail; + } + + // Set the new socket nonblocking. + if (!SetSocketNonblocking (sd)) + goto fail; + + if (bind (sd, (struct sockaddr *)&bind_here, bind_here_len) != 0) + goto fail; + + { // Looking good. + DatagramDescriptor *ds = new DatagramDescriptor (sd, this); + if (!ds) + throw std::runtime_error ("unable to allocate datagram-socket"); + Add (ds); + output_binding = ds->GetBinding(); + } + + return output_binding; + + fail: + if (sd != INVALID_SOCKET) + close (sd); + return 0; +} + + + +/******************* +EventMachine_t::Add +*******************/ + +void EventMachine_t::Add (EventableDescriptor *ed) +{ + if (!ed) + throw std::runtime_error ("added bad descriptor"); + ed->SetEventCallback (EventCallback); + NewDescriptors.push_back (ed); +} + + +/******************************* +EventMachine_t::ArmKqueueWriter +*******************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed) +{ + if (Poller == Poller_Kqueue) { + if (!ed) + throw std::runtime_error ("added bad descriptor"); + struct kevent k; +#ifdef __NetBSD__ + EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, (intptr_t)ed); +#else + EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed); +#endif + int t = kevent (kqfd, &k, 1, NULL, 0, NULL); + if (t < 0) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "arm kqueue writer failed on %d: %s", ed->GetSocket(), strerror(errno)); + throw std::runtime_error (buf); + } + } +} +#else +void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed UNUSED) { } +#endif + +/******************************* +EventMachine_t::ArmKqueueReader +*******************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed) +{ + if (Poller == Poller_Kqueue) { + if (!ed) + throw std::runtime_error ("added bad descriptor"); + struct kevent k; +#ifdef __NetBSD__ + EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed); +#else + EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed); +#endif + int t = kevent (kqfd, &k, 1, NULL, 0, NULL); + if (t < 0) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "arm kqueue reader failed on %d: %s", ed->GetSocket(), strerror(errno)); + throw std::runtime_error (buf); + } + } +} +#else +void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed UNUSED) { } +#endif + +/********************************** +EventMachine_t::_AddNewDescriptors +**********************************/ + +void EventMachine_t::_AddNewDescriptors() +{ + /* Avoid adding descriptors to the main descriptor list + * while we're actually traversing the list. + * Any descriptors that are added as a result of processing timers + * or acceptors should go on a temporary queue and then added + * while we're not traversing the main list. + * Also, it (rarely) happens that a newly-created descriptor + * is immediately scheduled to close. It might be a good + * idea not to bother scheduling these for I/O but if + * we do that, we might bypass some important processing. + */ + + for (size_t i = 0; i < NewDescriptors.size(); i++) { + EventableDescriptor *ed = NewDescriptors[i]; + if (ed == NULL) + throw std::runtime_error ("adding bad descriptor"); + + #if HAVE_EPOLL + if (Poller == Poller_Epoll) { + assert (epfd != -1); + int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent()); + if (e) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to add new descriptor: %s", strerror(errno)); + throw std::runtime_error (buf); + } + } + #endif + + #if HAVE_KQUEUE + /* + if (Poller == Poller_Kqueue) { + // INCOMPLETE. Some descriptors don't want to be readable. + assert (kqfd != -1); + struct kevent k; +#ifdef __NetBSD__ + EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed); +#else + EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed); +#endif + int t = kevent (kqfd, &k, 1, NULL, 0, NULL); + assert (t == 0); + } + */ + #endif + + QueueHeartbeat(ed); + Descriptors.push_back (ed); + } + NewDescriptors.clear(); +} + + +/********************************** +EventMachine_t::_ModifyDescriptors +**********************************/ + +void EventMachine_t::_ModifyDescriptors() +{ + /* For implementations which don't level check every descriptor on + * every pass through the machine, as select does. + * If we're not selecting, then descriptors need a way to signal to the + * machine that their readable or writable status has changed. + * That's what the ::Modify call is for. We do it this way to avoid + * modifying descriptors during the loop traversal, where it can easily + * happen that an object (like a UDP socket) gets data written on it by + * the application during #post_init. That would take place BEFORE the + * descriptor even gets added to the epoll descriptor, so the modify + * operation will crash messily. + * Another really messy possibility is for a descriptor to put itself + * on the Modified list, and then get deleted before we get here. + * Remember, deletes happen after the I/O traversal and before the + * next pass through here. So we have to make sure when we delete a + * descriptor to remove it from the Modified list. + */ + + #ifdef HAVE_EPOLL + if (Poller == Poller_Epoll) { + std::set::iterator i = ModifiedDescriptors.begin(); + while (i != ModifiedDescriptors.end()) { + assert (*i); + _ModifyEpollEvent (*i); + ++i; + } + } + #endif + + #ifdef HAVE_KQUEUE + if (Poller == Poller_Kqueue) { + std::set::iterator i = ModifiedDescriptors.begin(); + while (i != ModifiedDescriptors.end()) { + assert (*i); + if ((*i)->GetKqueueArmWrite()) + ArmKqueueWriter (*i); + ++i; + } + } + #endif + + ModifiedDescriptors.clear(); +} + + +/********************** +EventMachine_t::Modify +**********************/ + +void EventMachine_t::Modify (EventableDescriptor *ed) +{ + if (!ed) + throw std::runtime_error ("modified bad descriptor"); + ModifiedDescriptors.insert (ed); +} + + +/*********************** +EventMachine_t::Deregister +***********************/ + +void EventMachine_t::Deregister (EventableDescriptor *ed) +{ + if (!ed) + throw std::runtime_error ("modified bad descriptor"); + #ifdef HAVE_EPOLL + // cut/paste from _CleanupSockets(). The error handling could be + // refactored out of there, but it is cut/paste all over the + // file already. + if (Poller == Poller_Epoll) { + assert (epfd != -1); + assert (ed->GetSocket() != INVALID_SOCKET); + int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent()); + // ENOENT or EBADF are not errors because the socket may be already closed when we get here. + if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno)); + throw std::runtime_error (buf); + } + ModifiedDescriptors.erase(ed); + } + #endif + + #ifdef HAVE_KQUEUE + if (Poller == Poller_Kqueue) { + assert (ed->GetSocket() != INVALID_SOCKET); + + ModifiedDescriptors.erase(ed); + } + #endif +} + + +/************************************** +EventMachine_t::CreateUnixDomainServer +**************************************/ + +#ifdef OS_UNIX +const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename) +{ + /* Create a UNIX-domain acceptor (server) socket and add it to the event machine. + * Return the binding of the new acceptor to the caller. + * This binding will be referenced when the new acceptor sends events + * to indicate accepted connections. + * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS. + */ + + struct sockaddr_un s_sun; + + SOCKET sd_accept = EmSocket (AF_LOCAL, SOCK_STREAM, 0); + if (sd_accept == INVALID_SOCKET) { + goto fail; + } + + if (!filename || !*filename) + goto fail; + unlink (filename); + + bzero (&s_sun, sizeof(s_sun)); + s_sun.sun_family = AF_LOCAL; + strncpy (s_sun.sun_path, filename, sizeof(s_sun.sun_path)-1); + + // don't bother with reuseaddr for a local socket. + + { // set CLOEXEC. Only makes sense on Unix + #ifdef OS_UNIX + int cloexec = fcntl (sd_accept, F_GETFD, 0); + assert (cloexec >= 0); + cloexec |= FD_CLOEXEC; + fcntl (sd_accept, F_SETFD, cloexec); + #endif + } + + if (bind (sd_accept, (struct sockaddr*)&s_sun, sizeof(s_sun))) { + //__warning ("binding failed"); + goto fail; + } + + if (listen (sd_accept, 100)) { + //__warning ("listen failed"); + goto fail; + } + + return AttachSD(sd_accept); + + fail: + if (sd_accept != INVALID_SOCKET) + close (sd_accept); + return 0; +} +#else +const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename UNUSED) +{ + throw std::runtime_error ("unix-domain server unavailable on this platform"); +} +#endif + + +/************************************** +EventMachine_t::AttachSD +**************************************/ + +const uintptr_t EventMachine_t::AttachSD (SOCKET sd_accept) +{ + uintptr_t output_binding = 0; + + { + // Set the acceptor non-blocking. + // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop. + if (!SetSocketNonblocking (sd_accept)) { + //int val = fcntl (sd_accept, F_GETFL, 0); + //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) { + goto fail; + } + } + + { // Looking good. + AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this); + if (!ad) + throw std::runtime_error ("unable to allocate acceptor"); + Add (ad); + output_binding = ad->GetBinding(); + } + + return output_binding; + + fail: + if (sd_accept != INVALID_SOCKET) + close (sd_accept); + return 0; +} + + +/************************** +EventMachine_t::Socketpair +**************************/ + +#ifdef OS_UNIX +const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings) +{ + // Make sure the incoming array of command strings is sane. + if (!cmd_strings) + return 0; + int j; + for (j=0; j < 2048 && cmd_strings[j]; j++) + ; + if ((j==0) || (j==2048)) + return 0; + + uintptr_t output_binding = 0; + + int sv[2]; + if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0) + return 0; + // from here, all early returns must close the pair of sockets. + + // Set the parent side of the socketpair nonblocking. + // We don't care about the child side, and most child processes will expect their + // stdout to be blocking. Thanks to Duane Johnson and Bill Kelly for pointing this out. + // Obviously DON'T set CLOEXEC. + if (!SetSocketNonblocking (sv[0])) { + close (sv[0]); + close (sv[1]); + return 0; + } + + pid_t f = fork(); + if (f > 0) { + close (sv[1]); + PipeDescriptor *pd = new PipeDescriptor (sv[0], f, this); + if (!pd) + throw std::runtime_error ("unable to allocate pipe"); + Add (pd); + output_binding = pd->GetBinding(); + } + else if (f == 0) { + close (sv[0]); + dup2 (sv[1], STDIN_FILENO); + close (sv[1]); + dup2 (STDIN_FILENO, STDOUT_FILENO); + execvp (cmd_strings[0], cmd_strings+1); + exit (-1); // end the child process if the exec doesn't work. + } + else + throw std::runtime_error ("no fork"); + + return output_binding; +} +#else +const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings UNUSED) +{ + throw std::runtime_error ("socketpair is currently unavailable on this platform"); +} +#endif + + + +/**************************** +EventMachine_t::OpenKeyboard +****************************/ + +const uintptr_t EventMachine_t::OpenKeyboard() +{ + KeyboardDescriptor *kd = new KeyboardDescriptor (this); + if (!kd) + throw std::runtime_error ("no keyboard-object allocated"); + Add (kd); + return kd->GetBinding(); +} + + +/********************************** +EventMachine_t::GetConnectionCount +**********************************/ + +int EventMachine_t::GetConnectionCount () +{ + int i = 0; + // Subtract one for epoll or kqueue because of the LoopbreakDescriptor + if (Poller == Poller_Epoll || Poller == Poller_Kqueue) + i = 1; + + return Descriptors.size() + NewDescriptors.size() - i; +} + + +/************************ +EventMachine_t::WatchPid +************************/ + +#ifdef HAVE_KQUEUE +const uintptr_t EventMachine_t::WatchPid (int pid) +{ + if (Poller != Poller_Kqueue) + throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support"); + + struct kevent event; + int kqres; + + EV_SET(&event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT | NOTE_FORK, 0, 0); + + // Attempt to register the event + kqres = kevent(kqfd, &event, 1, NULL, 0, NULL); + if (kqres == -1) { + char errbuf[200]; + sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno)); + throw std::runtime_error(errbuf); + } + Bindable_t* b = new Bindable_t(); + Pids.insert(std::make_pair (pid, b)); + + return b->GetBinding(); +} +#else +const uintptr_t EventMachine_t::WatchPid (int pid UNUSED) +{ + throw std::runtime_error("no pid watching support on this system"); +} +#endif + +/************************** +EventMachine_t::UnwatchPid +**************************/ + +void EventMachine_t::UnwatchPid (int pid) +{ + Bindable_t *b = Pids[pid]; + assert(b); + Pids.erase(pid); + + #ifdef HAVE_KQUEUE + struct kevent k; + + EV_SET(&k, pid, EVFILT_PROC, EV_DELETE, 0, 0, 0); + /*int t =*/ kevent (kqfd, &k, 1, NULL, 0, NULL); + // t==-1 if the process already exited; ignore this for now + #endif + + if (EventCallback) + (*EventCallback)(b->GetBinding(), EM_CONNECTION_UNBOUND, NULL, 0); + + delete b; +} + +void EventMachine_t::UnwatchPid (const uintptr_t sig) +{ + for(std::map::iterator i=Pids.begin(); i != Pids.end(); i++) + { + if (i->second->GetBinding() == sig) { + UnwatchPid (i->first); + return; + } + } + + throw std::runtime_error("attempted to remove invalid pid signature"); +} + + +/************************* +EventMachine_t::WatchFile +*************************/ + +const uintptr_t EventMachine_t::WatchFile (const char *fpath) +{ + struct stat sb; + int sres; + int wd = -1; + + sres = stat(fpath, &sb); + + if (sres == -1) { + char errbuf[300]; + sprintf(errbuf, "error registering file %s for watching: %s", fpath, strerror(errno)); + throw std::runtime_error(errbuf); + } + + #ifdef HAVE_INOTIFY + if (!inotify) { + inotify = new InotifyDescriptor(this); + assert (inotify); + Add(inotify); + } + + wd = inotify_add_watch(inotify->GetSocket(), fpath, + IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_MOVE) ; + if (wd == -1) { + char errbuf[300]; + sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno)); + throw std::runtime_error(errbuf); + } + #endif + + #ifdef HAVE_KQUEUE + if (Poller != Poller_Kqueue) + throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support"); + + // With kqueue we have to open the file first and use the resulting fd to register for events + wd = open(fpath, O_RDONLY); + if (wd == -1) { + char errbuf[300]; + sprintf(errbuf, "failed to open file %s for registering with kqueue: %s", fpath, strerror(errno)); + throw std::runtime_error(errbuf); + } + _RegisterKqueueFileEvent(wd); + #endif + + if (wd != -1) { + Bindable_t* b = new Bindable_t(); + Files.insert(std::make_pair (wd, b)); + + return b->GetBinding(); + } + + throw std::runtime_error("no file watching support on this system"); // is this the right thing to do? +} + + +/*************************** +EventMachine_t::UnwatchFile +***************************/ + +void EventMachine_t::UnwatchFile (int wd) +{ + Bindable_t *b = Files[wd]; + assert(b); + Files.erase(wd); + + #ifdef HAVE_INOTIFY + inotify_rm_watch(inotify->GetSocket(), wd); + #elif HAVE_KQUEUE + // With kqueue, closing the monitored fd automatically clears all registered events for it + close(wd); + #endif + + if (EventCallback) + (*EventCallback)(b->GetBinding(), EM_CONNECTION_UNBOUND, NULL, 0); + + delete b; +} + +void EventMachine_t::UnwatchFile (const uintptr_t sig) +{ + for(std::map::iterator i=Files.begin(); i != Files.end(); i++) + { + if (i->second->GetBinding() == sig) { + UnwatchFile (i->first); + return; + } + } + throw std::runtime_error("attempted to remove invalid watch signature"); +} + + +/*********************************** +EventMachine_t::_ReadInotify_Events +************************************/ + +void EventMachine_t::_ReadInotifyEvents() +{ + #ifdef HAVE_INOTIFY + char buffer[1024]; + + assert(EventCallback); + + for (;;) { + int returned = read(inotify->GetSocket(), buffer, sizeof(buffer)); + assert(!(returned == 0 || (returned == -1 && errno == EINVAL))); + if (returned <= 0) { + break; + } + int current = 0; + while (current < returned) { + struct inotify_event* event = (struct inotify_event*)(buffer+current); + std::map::const_iterator bindable = Files.find(event->wd); + if (bindable != Files.end()) { + if (event->mask & (IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE)){ + (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "modified", 8); + } + if (event->mask & IN_MOVE_SELF){ + (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "moved", 5); + } + if (event->mask & IN_DELETE_SELF) { + (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "deleted", 7); + UnwatchFile ((int)event->wd); + } + } + current += sizeof(struct inotify_event) + event->len; + } + } + #endif +} + + +/************************************* +EventMachine_t::_HandleKqueuePidEvent +*************************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::_HandleKqueuePidEvent(struct kevent *event) +{ + assert(EventCallback); + + if (event->fflags & NOTE_FORK) + (*EventCallback)(Pids [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "fork", 4); + if (event->fflags & NOTE_EXIT) { + (*EventCallback)(Pids [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "exit", 4); + // stop watching the pid if it died + UnwatchPid ((int)event->ident); + } +} +#endif + + +/************************************** +EventMachine_t::_HandleKqueueFileEvent +***************************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::_HandleKqueueFileEvent(struct kevent *event) +{ + assert(EventCallback); + + if (event->fflags & NOTE_WRITE) + (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "modified", 8); + if (event->fflags & NOTE_RENAME) + (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "moved", 5); + if (event->fflags & NOTE_DELETE) { + (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "deleted", 7); + UnwatchFile ((int)event->ident); + } +} +#endif + + +/**************************************** +EventMachine_t::_RegisterKqueueFileEvent +*****************************************/ + +#ifdef HAVE_KQUEUE +void EventMachine_t::_RegisterKqueueFileEvent(int fd) +{ + struct kevent newevent; + int kqres; + + // Setup the event with our fd and proper flags + EV_SET(&newevent, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_WRITE, 0, 0); + + // Attempt to register the event + kqres = kevent(kqfd, &newevent, 1, NULL, 0, NULL); + if (kqres == -1) { + char errbuf[200]; + sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno)); + close(fd); + throw std::runtime_error(errbuf); + } +} +#endif + + +/************************************ +EventMachine_t::GetHeartbeatInterval +*************************************/ + +float EventMachine_t::GetHeartbeatInterval() +{ + return ((float)HeartbeatInterval / 1000000); +} + + +/************************************ +EventMachine_t::SetHeartbeatInterval +*************************************/ + +int EventMachine_t::SetHeartbeatInterval(float interval) +{ + int iv = (int)(interval * 1000000); + if (iv > 0) { + HeartbeatInterval = iv; + return 1; + } + return 0; +} +//#endif // OS_UNIX diff --git a/bin/gems/eventmachine-1.2.7/ext/em.h b/bin/gems/eventmachine-1.2.7/ext/em.h new file mode 100644 index 00000000..874a1278 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/em.h @@ -0,0 +1,308 @@ +/***************************************************************************** + +$Id$ + +File: em.h +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#ifndef __EventMachine__H_ +#define __EventMachine__H_ + +#ifdef BUILD_FOR_RUBY + #include + #ifdef HAVE_RB_THREAD_FD_SELECT + #define EmSelect rb_thread_fd_select + #else + // ruby 1.9.1 and below + #define EmSelect rb_thread_select + #endif + + #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL + #include + #endif + + #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD + #include + #endif + + #if defined(HAVE_RB_TRAP_IMMEDIATE) + #include + #elif defined(HAVE_RB_ENABLE_INTERRUPT) + extern "C" { + void rb_enable_interrupt(void); + void rb_disable_interrupt(void); + } + + #define TRAP_BEG rb_enable_interrupt() + #define TRAP_END do { rb_disable_interrupt(); rb_thread_check_ints(); } while(0) + #else + #define TRAP_BEG + #define TRAP_END + #endif + + // 1.9.0 compat + #ifndef RUBY_UBF_IO + #define RUBY_UBF_IO RB_UBF_DFL + #endif + #ifndef RSTRING_PTR + #define RSTRING_PTR(str) RSTRING(str)->ptr + #endif + #ifndef RSTRING_LEN + #define RSTRING_LEN(str) RSTRING(str)->len + #endif + #ifndef RSTRING_LENINT + #define RSTRING_LENINT(str) RSTRING_LEN(str) + #endif +#else + #define EmSelect select +#endif + +#if !defined(HAVE_TYPE_RB_FDSET_T) +#define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n))) +// These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3, +// with this change: any macros that read or write the nth element of an +// fdset first call fd_check to make sure n is in bounds. +typedef fd_set rb_fdset_t; +#define rb_fd_zero(f) FD_ZERO(f) +#define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0) +#define rb_fd_clr(n, f) do { if (fd_check(n)) FD_CLR((n), (f)); } while(0) +#define rb_fd_isset(n, f) (fd_check(n) ? FD_ISSET((n), (f)) : 0) +#define rb_fd_copy(d, s, n) (*(d) = *(s)) +#define rb_fd_dup(d, s) (*(d) = *(s)) +#define rb_fd_resize(n, f) ((void)(f)) +#define rb_fd_ptr(f) (f) +#define rb_fd_init(f) FD_ZERO(f) +#define rb_fd_init_copy(d, s) (*(d) = *(s)) +#define rb_fd_term(f) ((void)(f)) +#define rb_fd_max(f) FD_SETSIZE +#define rb_fd_select(n, rfds, wfds, efds, timeout) \ + select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout)) +#define rb_thread_fd_select(n, rfds, wfds, efds, timeout) \ + rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout)) +#endif + + +// This Solaris fix is adapted from eval_intern.h in Ruby 1.9.3: +// Solaris sys/select.h switches select to select_large_fdset to support larger +// file descriptors if FD_SETSIZE is larger than 1024 on 32bit environment. +// But Ruby doesn't change FD_SETSIZE because fd_set is allocated dynamically. +// So following definition is required to use select_large_fdset. +#ifdef HAVE_SELECT_LARGE_FDSET +#define select(n, r, w, e, t) select_large_fdset((n), (r), (w), (e), (t)) +extern "C" { + int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval *); +} +#endif + +class EventableDescriptor; +class InotifyDescriptor; +struct SelectData_t; + +/************* +enum Poller_t +*************/ +enum Poller_t { + Poller_Default, // typically Select + Poller_Epoll, + Poller_Kqueue +}; + + +/******************** +class EventMachine_t +********************/ + +class EventMachine_t +{ + public: + static int GetMaxTimerCount(); + static void SetMaxTimerCount (int); + + static int GetSimultaneousAcceptCount(); + static void SetSimultaneousAcceptCount (int); + + public: + EventMachine_t (EMCallback, Poller_t); + virtual ~EventMachine_t(); + + bool RunOnce(); + void Run(); + void ScheduleHalt(); + bool Stopping(); + void SignalLoopBreaker(); + const uintptr_t InstallOneshotTimer (uint64_t); + const uintptr_t ConnectToServer (const char *, int, const char *, int); + const uintptr_t ConnectToUnixServer (const char *); + + const uintptr_t CreateTcpServer (const char *, int); + const uintptr_t OpenDatagramSocket (const char *, int); + const uintptr_t CreateUnixDomainServer (const char*); + const uintptr_t AttachSD (SOCKET); + const uintptr_t OpenKeyboard(); + //const char *Popen (const char*, const char*); + const uintptr_t Socketpair (char* const*); + + void Add (EventableDescriptor*); + void Modify (EventableDescriptor*); + void Deregister (EventableDescriptor*); + + const uintptr_t AttachFD (SOCKET, bool); + int DetachFD (EventableDescriptor*); + + void ArmKqueueWriter (EventableDescriptor*); + void ArmKqueueReader (EventableDescriptor*); + + void SetTimerQuantum (int); + static void SetuidString (const char*); + static int SetRlimitNofile (int); + + pid_t SubprocessPid; + int SubprocessExitStatus; + + int GetConnectionCount(); + float GetHeartbeatInterval(); + int SetHeartbeatInterval(float); + + const uintptr_t WatchFile (const char*); + void UnwatchFile (int); + void UnwatchFile (const uintptr_t); + + #ifdef HAVE_KQUEUE + void _HandleKqueueFileEvent (struct kevent*); + void _RegisterKqueueFileEvent(int); + #endif + + const uintptr_t WatchPid (int); + void UnwatchPid (int); + void UnwatchPid (const uintptr_t); + + #ifdef HAVE_KQUEUE + void _HandleKqueuePidEvent (struct kevent*); + #endif + + uint64_t GetCurrentLoopTime() { return MyCurrentLoopTime; } + + void QueueHeartbeat(EventableDescriptor*); + void ClearHeartbeat(uint64_t, EventableDescriptor*); + + uint64_t GetRealTime(); + + Poller_t GetPoller() { return Poller; } + + static int name2address (const char *server, int port, int socktype, struct sockaddr *addr, size_t *addr_len); + + private: + void _RunTimers(); + void _UpdateTime(); + void _AddNewDescriptors(); + void _ModifyDescriptors(); + void _InitializeLoopBreaker(); + void _CleanupSockets(); + + void _RunSelectOnce(); + void _RunEpollOnce(); + void _RunKqueueOnce(); + + void _ModifyEpollEvent (EventableDescriptor*); + void _DispatchHeartbeats(); + timeval _TimeTilNextEvent(); + void _CleanBadDescriptors(); + + public: + void _ReadLoopBreaker(); + void _ReadInotifyEvents(); + int NumCloseScheduled; + + private: + enum { + MaxEpollDescriptors = 64*1024, + MaxEvents = 4096 + }; + int HeartbeatInterval; + EMCallback EventCallback; + + class Timer_t: public Bindable_t { + }; + + std::multimap Timers; + std::multimap Heartbeats; + std::map Files; + std::map Pids; + std::vector Descriptors; + std::vector NewDescriptors; + std::set ModifiedDescriptors; + + SOCKET LoopBreakerReader; + SOCKET LoopBreakerWriter; + #ifdef OS_WIN32 + struct sockaddr_in LoopBreakerTarget; + #endif + + timeval Quantum; + + uint64_t MyCurrentLoopTime; + + #ifdef OS_WIN32 + unsigned TickCountTickover; + unsigned LastTickCount; + #endif + + #ifdef OS_DARWIN + mach_timebase_info_data_t mach_timebase; + #endif + + private: + bool bTerminateSignalReceived; + SelectData_t *SelectData; + + Poller_t Poller; + + int epfd; // Epoll file-descriptor + #ifdef HAVE_EPOLL + struct epoll_event epoll_events [MaxEvents]; + #endif + + int kqfd; // Kqueue file-descriptor + #ifdef HAVE_KQUEUE + struct kevent Karray [MaxEvents]; + #endif + + #ifdef HAVE_INOTIFY + InotifyDescriptor *inotify; // pollable descriptor for our inotify instance + #endif +}; + + +/******************* +struct SelectData_t +*******************/ + +struct SelectData_t +{ + SelectData_t(); + ~SelectData_t(); + + int _Select(); + void _Clear(); + + SOCKET maxsocket; + rb_fdset_t fdreads; + rb_fdset_t fdwrites; + rb_fdset_t fderrors; + timeval tv; + int nSockets; +}; + +#endif // __EventMachine__H_ diff --git a/bin/gems/eventmachine-1.2.7/ext/eventmachine.h b/bin/gems/eventmachine-1.2.7/ext/eventmachine.h new file mode 100644 index 00000000..5100e20d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/eventmachine.h @@ -0,0 +1,143 @@ +/***************************************************************************** + +$Id$ + +File: eventmachine.h +Date: 15Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#ifndef __EVMA_EventMachine__H_ +#define __EVMA_EventMachine__H_ + +#if __cplusplus +extern "C" { +#endif + + enum { // Event names + EM_TIMER_FIRED = 100, + EM_CONNECTION_READ = 101, + EM_CONNECTION_UNBOUND = 102, + EM_CONNECTION_ACCEPTED = 103, + EM_CONNECTION_COMPLETED = 104, + EM_LOOPBREAK_SIGNAL = 105, + EM_CONNECTION_NOTIFY_READABLE = 106, + EM_CONNECTION_NOTIFY_WRITABLE = 107, + EM_SSL_HANDSHAKE_COMPLETED = 108, + EM_SSL_VERIFY = 109, + EM_PROXY_TARGET_UNBOUND = 110, + EM_PROXY_COMPLETED = 111 + }; + + enum { // SSL/TLS Protocols + EM_PROTO_SSLv2 = 2, + EM_PROTO_SSLv3 = 4, + EM_PROTO_TLSv1 = 8, + EM_PROTO_TLSv1_1 = 16, + EM_PROTO_TLSv1_2 = 32 + }; + + void evma_initialize_library (EMCallback); + bool evma_run_machine_once(); + void evma_run_machine(); + void evma_release_library(); + const uintptr_t evma_install_oneshot_timer (uint64_t milliseconds); + const uintptr_t evma_connect_to_server (const char *bind_addr, int bind_port, const char *server, int port); + const uintptr_t evma_connect_to_unix_server (const char *server); + + const uintptr_t evma_attach_fd (int file_descriptor, int watch_mode); + int evma_detach_fd (const uintptr_t binding); + int evma_get_file_descriptor (const uintptr_t binding); + int evma_is_notify_readable (const uintptr_t binding); + void evma_set_notify_readable (const uintptr_t binding, int mode); + int evma_is_notify_writable (const uintptr_t binding); + void evma_set_notify_writable (const uintptr_t binding, int mode); + + int evma_pause(const uintptr_t binding); + int evma_is_paused(const uintptr_t binding); + int evma_resume(const uintptr_t binding); + + int evma_num_close_scheduled(); + + void evma_stop_tcp_server (const uintptr_t binding); + const uintptr_t evma_create_tcp_server (const char *address, int port); + const uintptr_t evma_create_unix_domain_server (const char *filename); + const uintptr_t evma_attach_sd (int sd); + const uintptr_t evma_open_datagram_socket (const char *server, int port); + const uintptr_t evma_open_keyboard(); + void evma_set_tls_parms (const uintptr_t binding, const char *privatekey_filename, const char *certchain_filenane, int verify_peer, int fail_if_no_peer_cert, const char *sni_hostname, const char *cipherlist, const char *ecdh_curve, const char *dhparam, int protocols); + void evma_start_tls (const uintptr_t binding); + + #ifdef WITH_SSL + X509 *evma_get_peer_cert (const uintptr_t binding); + int evma_get_cipher_bits (const uintptr_t binding); + const char *evma_get_cipher_name (const uintptr_t binding); + const char *evma_get_cipher_protocol (const uintptr_t binding); + const char *evma_get_sni_hostname (const uintptr_t binding); + void evma_accept_ssl_peer (const uintptr_t binding); + #endif + + int evma_get_peername (const uintptr_t binding, struct sockaddr*, socklen_t*); + int evma_get_sockname (const uintptr_t binding, struct sockaddr*, socklen_t*); + int evma_get_subprocess_pid (const uintptr_t binding, pid_t*); + int evma_get_subprocess_status (const uintptr_t binding, int*); + int evma_get_connection_count(); + int evma_send_data_to_connection (const uintptr_t binding, const char *data, int data_length); + int evma_send_datagram (const uintptr_t binding, const char *data, int data_length, const char *address, int port); + float evma_get_comm_inactivity_timeout (const uintptr_t binding); + int evma_set_comm_inactivity_timeout (const uintptr_t binding, float value); + float evma_get_pending_connect_timeout (const uintptr_t binding); + int evma_set_pending_connect_timeout (const uintptr_t binding, float value); + int evma_get_outbound_data_size (const uintptr_t binding); + uint64_t evma_get_last_activity_time (const uintptr_t binding); + int evma_send_file_data_to_connection (const uintptr_t binding, const char *filename); + + void evma_close_connection (const uintptr_t binding, int after_writing); + int evma_report_connection_error_status (const uintptr_t binding); + void evma_signal_loopbreak(); + void evma_set_timer_quantum (int); + int evma_get_max_timer_count(); + void evma_set_max_timer_count (int); + int evma_get_simultaneous_accept_count(); + void evma_set_simultaneous_accept_count (int); + void evma_setuid_string (const char *username); + void evma_stop_machine(); + bool evma_stopping(); + float evma_get_heartbeat_interval(); + int evma_set_heartbeat_interval(float); + + const uintptr_t evma_popen (char * const*cmd_strings); + + const uintptr_t evma_watch_filename (const char *fname); + void evma_unwatch_filename (const uintptr_t binding); + + const uintptr_t evma_watch_pid (int); + void evma_unwatch_pid (const uintptr_t binding); + + void evma_start_proxy(const uintptr_t from, const uintptr_t to, const unsigned long bufsize, const unsigned long length); + void evma_stop_proxy(const uintptr_t from); + unsigned long evma_proxied_bytes(const uintptr_t from); + + int evma_set_rlimit_nofile (int n_files); + + void evma_set_epoll (int use); + void evma_set_kqueue (int use); + + uint64_t evma_get_current_loop_time(); +#if __cplusplus +} +#endif + + +#endif // __EventMachine__H_ + diff --git a/bin/gems/eventmachine-1.2.7/ext/extconf.rb b/bin/gems/eventmachine-1.2.7/ext/extconf.rb new file mode 100644 index 00000000..676b4c42 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/extconf.rb @@ -0,0 +1,270 @@ +require 'fileutils' +require 'mkmf' + +# Eager check devs tools +have_devel? if respond_to?(:have_devel?) + +def check_libs libs = [], fatal = false + libs.all? { |lib| have_library(lib) || (abort("could not find library: #{lib}") if fatal) } +end + +def check_heads heads = [], fatal = false + heads.all? { |head| have_header(head) || (abort("could not find header: #{head}") if fatal)} +end + +def add_define(name) + $defs.push("-D#{name}") +end + +## +# OpenSSL: + +# override append_library, so it actually appends (instead of prepending) +# this fixes issues with linking ssl, since libcrypto depends on symbols in libssl +def append_library(libs, lib) + libs + " " + format(LIBARG, lib) +end + +SSL_HEADS = %w(openssl/ssl.h openssl/err.h) +SSL_LIBS = %w(crypto ssl) +# OpenSSL 1.1.0 and above for Windows use the Unix library names +# OpenSSL 0.9.8 and 1.0.x for Windows use the *eay32 library names +SSL_LIBS_WIN = RUBY_PLATFORM =~ /mswin|mingw|bccwin/ ? %w(ssleay32 libeay32) : [] + +def dir_config_wrapper(pretty_name, name, idefault=nil, ldefault=nil) + inc, lib = dir_config(name, idefault, ldefault) + if inc && lib + # TODO: Remove when 2.0.0 is the minimum supported version + # Ruby versions not incorporating the mkmf fix at + # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717 + # do not properly search for lib directories, and must be corrected + unless lib && lib[-3, 3] == 'lib' + @libdir_basename = 'lib' + inc, lib = dir_config(name, idefault, ldefault) + end + unless idefault && ldefault + abort "-----\nCannot find #{pretty_name} include path #{inc}\n-----" unless inc && inc.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } + abort "-----\nCannot find #{pretty_name} library path #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } + warn "-----\nUsing #{pretty_name} in path #{File.dirname inc}\n-----" + end + true + end +end + +def dir_config_search(pretty_name, name, paths, &b) + paths.each do |p| + if dir_config_wrapper('OpenSSL', 'ssl', p + '/include', p + '/lib') && yield + warn "-----\nFound #{pretty_name} in path #{p}\n-----" + return true + end + end + false +end + +def pkg_config_wrapper(pretty_name, name) + cflags, ldflags, libs = pkg_config(name) + unless [cflags, ldflags, libs].any?(&:nil?) || [cflags, ldflags, libs].any?(&:empty?) + warn "-----\nUsing #{pretty_name} from pkg-config #{cflags} && #{ldflags} && #{libs}\n-----" + true + end +end + +if ENV['CROSS_COMPILING'] + openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.2e") + openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/") + if File.exist?(openssl_dir) + FileUtils.mkdir_p Dir.pwd+"/openssl/" + FileUtils.cp Dir[openssl_dir+"/include/openssl/*.h"], Dir.pwd+"/openssl/", :verbose => true + FileUtils.cp Dir[openssl_dir+"/lib*.a"], Dir.pwd, :verbose => true + $INCFLAGS << " -I#{Dir.pwd}" # for the openssl headers + add_define "WITH_SSL" + else + STDERR.puts + STDERR.puts "**************************************************************************************" + STDERR.puts "**** Cross-compiled OpenSSL not found" + STDERR.puts "**** Run: hg clone http://bitbucket.org/ged/ruby-pg && cd ruby-pg && rake openssl_libs" + STDERR.puts "**************************************************************************************" + STDERR.puts + end +elsif dir_config_wrapper('OpenSSL', 'ssl') + # If the user has provided a --with-ssl-dir argument, we must respect it or fail. + add_define 'WITH_SSL' if (check_libs(SSL_LIBS) || check_libs(SSL_LIBS_WIN)) && check_heads(SSL_HEADS) +elsif pkg_config_wrapper('OpenSSL', 'openssl') + # If we can detect OpenSSL by pkg-config, use it as the next-best option + add_define 'WITH_SSL' if (check_libs(SSL_LIBS) || check_libs(SSL_LIBS_WIN)) && check_heads(SSL_HEADS) +elsif (check_libs(SSL_LIBS) || check_libs(SSL_LIBS_WIN)) && check_heads(SSL_HEADS) + # If we don't even need any options to find a usable OpenSSL, go with it + add_define 'WITH_SSL' +elsif dir_config_search('OpenSSL', 'ssl', ['/usr/local', '/opt/local', '/usr/local/opt/openssl']) do + (check_libs(SSL_LIBS) || check_libs(SSL_LIBS_WIN)) && check_heads(SSL_HEADS) + end + # Finally, look for OpenSSL in alternate locations including MacPorts and HomeBrew + add_define 'WITH_SSL' +end + +add_define 'BUILD_FOR_RUBY' + +# Ruby features: + +have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h']) +have_func('rb_thread_blocking_region') +have_func('rb_thread_call_without_gvl', 'ruby/thread.h') +have_func('rb_thread_fd_select') +have_type('rb_fdset_t', 'ruby/intern.h') +have_func('rb_wait_for_single_fd') +have_func('rb_enable_interrupt') +have_func('rb_time_new') + +# System features: + +add_define('HAVE_INOTIFY') if inotify = have_func('inotify_init', 'sys/inotify.h') +add_define('HAVE_OLD_INOTIFY') if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h') +have_func('writev', 'sys/uio.h') +have_func('pipe2', 'unistd.h') +have_func('accept4', 'sys/socket.h') +have_const('SOCK_CLOEXEC', 'sys/socket.h') + +# Minor platform details between *nix and Windows: + +if RUBY_PLATFORM =~ /(mswin|mingw|bccwin)/ + GNU_CHAIN = ENV['CROSS_COMPILING'] || $1 == 'mingw' + OS_WIN32 = true + add_define "OS_WIN32" +else + GNU_CHAIN = true + OS_UNIX = true + add_define 'OS_UNIX' + + add_define "HAVE_KQUEUE" if have_header("sys/event.h") && have_header("sys/queue.h") +end + +# Adjust number of file descriptors (FD) on Windows + +if RbConfig::CONFIG["host_os"] =~ /mingw/ + found = RbConfig::CONFIG.values_at("CFLAGS", "CPPFLAGS"). + any? { |v| v.include?("FD_SETSIZE") } + + add_define "FD_SETSIZE=32767" unless found +end + +# Main platform invariances: + +case RUBY_PLATFORM +when /mswin32/, /mingw32/, /bccwin32/ + check_heads(%w[windows.h winsock.h], true) + check_libs(%w[kernel32 rpcrt4 gdi32], true) + + if GNU_CHAIN + CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++" + else + $defs.push "-EHs" + $defs.push "-GR" + end + + # Newer versions of Ruby already define _WIN32_WINNT, which is needed + # to get access to newer POSIX networking functions (e.g. getaddrinfo) + add_define '_WIN32_WINNT=0x0501' unless have_func('getaddrinfo') + +when /solaris/ + add_define 'OS_SOLARIS8' + check_libs(%w[nsl socket], true) + + # If Ruby was compiled for 32-bits, then select() can only handle 1024 fds + # There is an alternate function, select_large_fdset, that supports more. + have_func('select_large_fdset', 'sys/select.h') + + if CONFIG['CC'] == 'cc' && ( + `cc -flags 2>&1` =~ /Sun/ || # detect SUNWspro compiler + `cc -V 2>&1` =~ /Sun/ # detect Solaris Studio compiler + ) + # SUN CHAIN + add_define 'CC_SUNWspro' + $preload = ["\nCXX = CC"] # hack a CXX= line into the makefile + $CFLAGS = CONFIG['CFLAGS'] = "-KPIC" + CONFIG['CCDLFLAGS'] = "-KPIC" + CONFIG['LDSHARED'] = "$(CXX) -G -KPIC -lCstd" + CONFIG['LDSHAREDXX'] = "$(CXX) -G -KPIC -lCstd" + else + # GNU CHAIN + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + end + +when /openbsd/ + # OpenBSD branch contributed by Guillaume Sellier. + + # on Unix we need a g++ link, not gcc. On OpenBSD, linking against libstdc++ have to be explicitly done for shared libs + CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++ -fPIC" + CONFIG['LDSHAREDXX'] = "$(CXX) -shared -lstdc++ -fPIC" + +when /darwin/ + add_define 'OS_DARWIN' + + # on Unix we need a g++ link, not gcc. + # Ff line contributed by Daniel Harple. + CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ') + +when /linux/ + add_define 'HAVE_EPOLL' if have_func('epoll_create', 'sys/epoll.h') + + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + +when /aix/ + CONFIG['LDSHARED'] = "$(CXX) -Wl,-bstatic -Wl,-bdynamic -Wl,-G -Wl,-brtl" + +when /cygwin/ + # For rubies built with Cygwin, CXX may be set to CC, which is just + # a wrapper for gcc. + # This will compile, but it will not link to the C++ std library. + # Explicitly set CXX to use g++. + CONFIG['CXX'] = "g++" + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + +else + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" +end + +# Platform-specific time functions +if have_func('clock_gettime') + # clock_gettime is POSIX, but the monotonic clocks are not + have_const('CLOCK_MONOTONIC_RAW', 'time.h') # Linux + have_const('CLOCK_MONOTONIC', 'time.h') # Linux, Solaris, BSDs +else + have_func('gethrtime') # Older Solaris and HP-UX +end + +# Hack so that try_link will test with a C++ compiler instead of a C compiler +TRY_LINK.sub!('$(CC)', '$(CXX)') + +# This is our wishlist. We use whichever flags work on the host. +# In the future, add -Werror to make sure all warnings are resolved. +# deprecated-declarations are used in OS X OpenSSL +# ignored-qualifiers are used by the Bindings (would-be void *) +# unused-result because GCC 4.6 no longer silences (void) ignore_this(function) +# address because on Windows, rb_fd_select checks if &fds is non-NULL, which it cannot be +%w( + -Wall + -Wextra + -Wno-deprecated-declarations + -Wno-ignored-qualifiers + -Wno-unused-result + -Wno-address +).select do |flag| + try_link('int main() {return 0;}', flag) +end.each do |flag| + CONFIG['CXXFLAGS'] << ' ' << flag +end +puts "CXXFLAGS=#{CONFIG['CXXFLAGS']}" + +# Solaris C++ compiler doesn't have make_pair() +add_define 'HAVE_MAKE_PAIR' if try_link(< + using namespace std; + int main(){ pair tuple = make_pair(1,2); } +SRC +TRY_LINK.sub!('$(CXX)', '$(CC)') + +create_makefile "rubyeventmachine" diff --git a/bin/gems/eventmachine-1.2.7/ext/fastfilereader/Makefile b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/Makefile new file mode 100644 index 00000000..391ea152 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/Makefile @@ -0,0 +1,269 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = . +topdir = /usr/include/ruby-3.2.0 +hdrdir = $(topdir) +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR)/etc +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ +LIBRUBY = $(LIBRUBY_SO) +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = -fPIC +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = +CPPFLAGS = -DBUILD_FOR_RUBY -DOS_UNIX -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CXX) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-linux-gnu-gcc-ar +EXEEXT = + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 +RUBYW_INSTALL_NAME = +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x86_64-linux-gnu +sitearch = $(arch) +ruby_version = 3.2.0 +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 +RUBY = $(ruby) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h + +RM = rm -f +RM_RF = rm -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) +DEFFILE = + +CLEANFILES = mkmf.log +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc +ORIG_SRCS = mapper.cpp rubymain.cpp +SRCS = $(ORIG_SRCS) +OBJS = mapper.o rubymain.o +HDRS = $(srcdir)/mapper.h +LOCAL_HDRS = +TARGET = fastfilereaderext +TARGET_NAME = fastfilereaderext +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = $(OBJS) *.bak +TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.time + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP) + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + -$(Q)$(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TARGET_SO_DIR_TIMESTAMP): + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(OBJS) Makefile + $(ECHO) linking shared-object $(DLLIB) + -$(Q)$(RM) $(@) + $(Q) $(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) + + + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/bin/gems/eventmachine-1.2.7/ext/fastfilereader/extconf.rb b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/extconf.rb new file mode 100644 index 00000000..e4d64e4a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/extconf.rb @@ -0,0 +1,109 @@ +require 'mkmf' + +def check_libs libs = [], fatal = false + libs.all? { |lib| have_library(lib) || (abort("could not find library: #{lib}") if fatal) } +end + +def check_heads heads = [], fatal = false + heads.all? { |head| have_header(head) || (abort("could not find header: #{head}") if fatal)} +end + +def add_define(name) + $defs.push("-D#{name}") +end + +# Eager check devs tools +have_devel? if respond_to?(:have_devel?) + +add_define 'BUILD_FOR_RUBY' + +# Minor platform details between *nix and Windows: + +if RUBY_PLATFORM =~ /(mswin|mingw|bccwin)/ + GNU_CHAIN = ENV['CROSS_COMPILING'] || $1 == 'mingw' + OS_WIN32 = true + add_define "OS_WIN32" +else + GNU_CHAIN = true + OS_UNIX = true + add_define 'OS_UNIX' +end + +# Adjust number of file descriptors (FD) on Windows + +if RbConfig::CONFIG["host_os"] =~ /mingw/ + found = RbConfig::CONFIG.values_at("CFLAGS", "CPPFLAGS"). + any? { |v| v.include?("FD_SETSIZE") } + + add_define "FD_SETSIZE=32767" unless found +end + +# Main platform invariances: + +case RUBY_PLATFORM +when /mswin32/, /mingw32/, /bccwin32/ + check_heads(%w[windows.h winsock.h], true) + check_libs(%w[kernel32 rpcrt4 gdi32], true) + + if GNU_CHAIN + CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++" + else + $defs.push "-EHs" + $defs.push "-GR" + end + +when /solaris/ + add_define 'OS_SOLARIS8' + check_libs(%w[nsl socket], true) + + if CONFIG['CC'] == 'cc' && ( + `cc -flags 2>&1` =~ /Sun/ || # detect SUNWspro compiler + `cc -V 2>&1` =~ /Sun/ # detect Solaris Studio compiler + ) + # SUN CHAIN + add_define 'CC_SUNWspro' + $preload = ["\nCXX = CC"] # hack a CXX= line into the makefile + $CFLAGS = CONFIG['CFLAGS'] = "-KPIC" + CONFIG['CCDLFLAGS'] = "-KPIC" + CONFIG['LDSHARED'] = "$(CXX) -G -KPIC -lCstd" + CONFIG['LDSHAREDXX'] = "$(CXX) -G -KPIC -lCstd" + else + # GNU CHAIN + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + end + +when /openbsd/ + # OpenBSD branch contributed by Guillaume Sellier. + + # on Unix we need a g++ link, not gcc. On OpenBSD, linking against libstdc++ have to be explicitly done for shared libs + CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++ -fPIC" + CONFIG['LDSHAREDXX'] = "$(CXX) -shared -lstdc++ -fPIC" + +when /darwin/ + # on Unix we need a g++ link, not gcc. + # Ff line contributed by Daniel Harple. + CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ') + +when /linux/ + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + +when /aix/ + CONFIG['LDSHARED'] = "$(CXX) -Wl,-bstatic -Wl,-bdynamic -Wl,-G -Wl,-brtl" + +when /cygwin/ + # For rubies built with Cygwin, CXX may be set to CC, which is just + # a wrapper for gcc. + # This will compile, but it will not link to the C++ std library. + # Explicitly set CXX to use g++. + CONFIG['CXX'] = "g++" + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" + +else + # on Unix we need a g++ link, not gcc. + CONFIG['LDSHARED'] = "$(CXX) -shared" +end + +create_makefile "fastfilereaderext" diff --git a/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.cpp b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.cpp new file mode 100644 index 00000000..f226f2d5 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.cpp @@ -0,0 +1,214 @@ +/***************************************************************************** + +$Id: mapper.cpp 4527 2007-07-04 10:21:34Z francis $ + +File: mapper.cpp +Date: 02Jul07 + +Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved. +Gmail: garbagecat10 + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +////////////////////////////////////////////////////////////////////// +// UNIX implementation +////////////////////////////////////////////////////////////////////// + + +#ifdef OS_UNIX + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mapper.h" + +/****************** +Mapper_t::Mapper_t +******************/ + +Mapper_t::Mapper_t (const std::string &filename) +{ + /* We ASSUME we can open the file. + * (More precisely, we assume someone else checked before we got here.) + */ + + Fd = open (filename.c_str(), O_RDONLY); + if (Fd < 0) + throw std::runtime_error (strerror (errno)); + + struct stat st; + if (fstat (Fd, &st)) + throw std::runtime_error (strerror (errno)); + FileSize = st.st_size; + + #ifdef OS_WIN32 + MapPoint = (char*) mmap (0, FileSize, PROT_READ, MAP_SHARED, Fd, 0); + #else + MapPoint = (const char*) mmap (0, FileSize, PROT_READ, MAP_SHARED, Fd, 0); + #endif + if (MapPoint == MAP_FAILED) + throw std::runtime_error (strerror (errno)); +} + + +/******************* +Mapper_t::~Mapper_t +*******************/ + +Mapper_t::~Mapper_t() +{ + Close(); +} + + +/*************** +Mapper_t::Close +***************/ + +void Mapper_t::Close() +{ + // Can be called multiple times. + // Calls to GetChunk are invalid after a call to Close. + if (MapPoint) { + #ifdef CC_SUNWspro + // TODO: The void * cast works fine on Solaris 11, but + // I don't know at what point that changed from older Solaris. + munmap ((char*)MapPoint, FileSize); + #else + munmap ((void*)MapPoint, FileSize); + #endif + MapPoint = NULL; + } + if (Fd >= 0) { + close (Fd); + Fd = -1; + } +} + +/****************** +Mapper_t::GetChunk +******************/ + +const char *Mapper_t::GetChunk (unsigned start) +{ + return MapPoint + start; +} + + + +#endif // OS_UNIX + + +////////////////////////////////////////////////////////////////////// +// WINDOWS implementation +////////////////////////////////////////////////////////////////////// + +#ifdef OS_WIN32 + +#include + +#include +#include +#include + +#include "mapper.h" + +/****************** +Mapper_t::Mapper_t +******************/ + +Mapper_t::Mapper_t (const std::string &filename) +{ + /* We ASSUME we can open the file. + * (More precisely, we assume someone else checked before we got here.) + */ + + hFile = INVALID_HANDLE_VALUE; + hMapping = NULL; + MapPoint = NULL; + FileSize = 0; + + hFile = CreateFile (filename.c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + throw std::runtime_error ("File not found"); + + BY_HANDLE_FILE_INFORMATION i; + if (GetFileInformationByHandle (hFile, &i)) + FileSize = i.nFileSizeLow; + + hMapping = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, 0, NULL); + if (!hMapping) + throw std::runtime_error ("File not mapped"); + + #ifdef OS_WIN32 + MapPoint = (char*) MapViewOfFile (hMapping, FILE_MAP_WRITE, 0, 0, 0); + #else + MapPoint = (const char*) MapViewOfFile (hMapping, FILE_MAP_WRITE, 0, 0, 0); + #endif + if (!MapPoint) + throw std::runtime_error ("Mappoint not read"); +} + + +/******************* +Mapper_t::~Mapper_t +*******************/ + +Mapper_t::~Mapper_t() +{ + Close(); +} + +/*************** +Mapper_t::Close +***************/ + +void Mapper_t::Close() +{ + // Can be called multiple times. + // Calls to GetChunk are invalid after a call to Close. + if (MapPoint) { + UnmapViewOfFile (MapPoint); + MapPoint = NULL; + } + if (hMapping != NULL) { + CloseHandle (hMapping); + hMapping = NULL; + } + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle (hFile); + hFile = INVALID_HANDLE_VALUE; + } +} + + +/****************** +Mapper_t::GetChunk +******************/ + +const char *Mapper_t::GetChunk (unsigned start) +{ + return MapPoint + start; +} + + + +#endif // OS_WINDOWS diff --git a/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.h b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.h new file mode 100644 index 00000000..3db0eead --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/mapper.h @@ -0,0 +1,59 @@ +/***************************************************************************** + +$Id: mapper.h 4529 2007-07-04 11:32:22Z francis $ + +File: mapper.h +Date: 02Jul07 + +Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved. +Gmail: garbagecat10 + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#ifndef __Mapper__H_ +#define __Mapper__H_ + + +/************** +class Mapper_t +**************/ + +class Mapper_t +{ + public: + Mapper_t (const std::string&); + virtual ~Mapper_t(); + + const char *GetChunk (unsigned); + void Close(); + size_t GetFileSize() {return FileSize;} + + private: + size_t FileSize; + + #ifdef OS_UNIX + private: + int Fd; + const char *MapPoint; + #endif // OS_UNIX + + #ifdef OS_WIN32 + private: + HANDLE hFile; + HANDLE hMapping; + char *MapPoint; + #endif // OS_WIN32 + +}; + + +#endif // __Mapper__H_ + diff --git a/bin/gems/eventmachine-1.2.7/ext/fastfilereader/rubymain.cpp b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/rubymain.cpp new file mode 100644 index 00000000..b962bf02 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/fastfilereader/rubymain.cpp @@ -0,0 +1,126 @@ +/***************************************************************************** + +$Id: rubymain.cpp 4529 2007-07-04 11:32:22Z francis $ + +File: rubymain.cpp +Date: 02Jul07 + +Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved. +Gmail: garbagecat10 + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + + +#include +#include + +#include +#include "mapper.h" + +static VALUE EmModule; +static VALUE FastFileReader; +static VALUE Mapper; + + + +/********* +mapper_dt +*********/ + +static void mapper_dt (void *ptr) +{ + if (ptr) + delete (Mapper_t*) ptr; +} + +/********** +mapper_new +**********/ + +static VALUE mapper_new (VALUE self, VALUE filename) +{ + Mapper_t *m = new Mapper_t (StringValueCStr (filename)); + if (!m) + rb_raise (rb_eStandardError, "No Mapper Object"); + VALUE v = Data_Wrap_Struct (Mapper, 0, mapper_dt, (void*)m); + return v; +} + + +/**************** +mapper_get_chunk +****************/ + +static VALUE mapper_get_chunk (VALUE self, VALUE start, VALUE length) +{ + Mapper_t *m = NULL; + Data_Get_Struct (self, Mapper_t, m); + if (!m) + rb_raise (rb_eStandardError, "No Mapper Object"); + + // TODO, what if some moron sends us a negative start value? + unsigned _start = NUM2INT (start); + unsigned _length = NUM2INT (length); + if ((_start + _length) > m->GetFileSize()) + rb_raise (rb_eStandardError, "Mapper Range Error"); + + const char *chunk = m->GetChunk (_start); + if (!chunk) + rb_raise (rb_eStandardError, "No Mapper Chunk"); + return rb_str_new (chunk, _length); +} + +/************ +mapper_close +************/ + +static VALUE mapper_close (VALUE self) +{ + Mapper_t *m = NULL; + Data_Get_Struct (self, Mapper_t, m); + if (!m) + rb_raise (rb_eStandardError, "No Mapper Object"); + m->Close(); + return Qnil; +} + +/*********** +mapper_size +***********/ + +static VALUE mapper_size (VALUE self) +{ + Mapper_t *m = NULL; + Data_Get_Struct (self, Mapper_t, m); + if (!m) + rb_raise (rb_eStandardError, "No Mapper Object"); + return INT2NUM (m->GetFileSize()); +} + + +/********************** +Init_fastfilereaderext +**********************/ + +extern "C" void Init_fastfilereaderext() +{ + EmModule = rb_define_module ("EventMachine"); + FastFileReader = rb_define_class_under (EmModule, "FastFileReader", rb_cObject); + Mapper = rb_define_class_under (FastFileReader, "Mapper", rb_cObject); + + rb_define_module_function (Mapper, "new", (VALUE(*)(...))mapper_new, 1); + rb_define_method (Mapper, "size", (VALUE(*)(...))mapper_size, 0); + rb_define_method (Mapper, "close", (VALUE(*)(...))mapper_close, 0); + rb_define_method (Mapper, "get_chunk", (VALUE(*)(...))mapper_get_chunk, 2); +} + + + diff --git a/bin/gems/eventmachine-1.2.7/ext/kb.cpp b/bin/gems/eventmachine-1.2.7/ext/kb.cpp new file mode 100644 index 00000000..2187ae22 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/kb.cpp @@ -0,0 +1,79 @@ +/***************************************************************************** + +$Id$ + +File: kb.cpp +Date: 24Aug07 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" + + +/************************************** +KeyboardDescriptor::KeyboardDescriptor +**************************************/ + +KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em): + EventableDescriptor (0, parent_em), + bReadAttemptedAfterClose (false) +{ + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + #ifdef HAVE_KQUEUE + MyEventMachine->ArmKqueueReader (this); + #endif +} + + +/*************************************** +KeyboardDescriptor::~KeyboardDescriptor +***************************************/ + +KeyboardDescriptor::~KeyboardDescriptor() +{ +} + + +/************************* +KeyboardDescriptor::Write +*************************/ + +void KeyboardDescriptor::Write() +{ + // Why are we here? + throw std::runtime_error ("bad code path in keyboard handler"); +} + + +/***************************** +KeyboardDescriptor::Heartbeat +*****************************/ + +void KeyboardDescriptor::Heartbeat() +{ + // no-op +} + + +/************************ +KeyboardDescriptor::Read +************************/ + +void KeyboardDescriptor::Read() +{ + char c; + (void)read (GetSocket(), &c, 1); + _GenericInboundDispatch(&c, 1); +} diff --git a/bin/gems/eventmachine-1.2.7/ext/page.cpp b/bin/gems/eventmachine-1.2.7/ext/page.cpp new file mode 100644 index 00000000..a3a23400 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/page.cpp @@ -0,0 +1,107 @@ +/***************************************************************************** + +$Id$ + +File: page.cpp +Date: 30Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#include "project.h" + + +/****************** +PageList::PageList +******************/ + +PageList::PageList() +{ +} + + +/******************* +PageList::~PageList +*******************/ + +PageList::~PageList() +{ + while (HasPages()) + PopFront(); +} + + +/*************** +PageList::Front +***************/ + +void PageList::Front (const char **page, int *length) +{ + assert (page && length); + + if (HasPages()) { + Page p = Pages.front(); + *page = p.Buffer; + *length = p.Size; + } + else { + *page = NULL; + *length = 0; + } +} + + +/****************** +PageList::PopFront +******************/ + +void PageList::PopFront() +{ + if (HasPages()) { + Page p = Pages.front(); + Pages.pop_front(); + if (p.Buffer) + free ((void*)p.Buffer); + } +} + + +/****************** +PageList::HasPages +******************/ + +bool PageList::HasPages() +{ + return (Pages.size() > 0) ? true : false; +} + + +/************** +PageList::Push +**************/ + +void PageList::Push (const char *buf, int size) +{ + if (buf && (size > 0)) { + char *copy = (char*) malloc (size); + if (!copy) + throw std::runtime_error ("no memory in pagelist"); + memcpy (copy, buf, size); + Pages.push_back (Page (copy, size)); + } +} + + + + + diff --git a/bin/gems/eventmachine-1.2.7/ext/page.h b/bin/gems/eventmachine-1.2.7/ext/page.h new file mode 100644 index 00000000..969fc916 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/page.h @@ -0,0 +1,51 @@ +/***************************************************************************** + +$Id$ + +File: page.h +Date: 30Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#ifndef __PageManager__H_ +#define __PageManager__H_ + + +/************** +class PageList +**************/ + +class PageList +{ + struct Page { + Page (const char *b, size_t s): Buffer(b), Size(s) {} + const char *Buffer; + size_t Size; + }; + + public: + PageList(); + virtual ~PageList(); + + void Push (const char*, int); + bool HasPages(); + void Front (const char**, int*); + void PopFront(); + + private: + std::deque Pages; +}; + + +#endif // __PageManager__H_ diff --git a/bin/gems/eventmachine-1.2.7/ext/pipe.cpp b/bin/gems/eventmachine-1.2.7/ext/pipe.cpp new file mode 100644 index 00000000..a5f0d9f1 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/pipe.cpp @@ -0,0 +1,354 @@ +/***************************************************************************** + +$Id$ + +File: pipe.cpp +Date: 30May07 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" + + +#ifdef OS_UNIX +// THIS ENTIRE FILE IS ONLY COMPILED ON UNIX-LIKE SYSTEMS. + +/****************************** +PipeDescriptor::PipeDescriptor +******************************/ + +PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em): + EventableDescriptor (fd, parent_em), + bReadAttemptedAfterClose (false), + OutboundDataSize (0), + SubprocessPid (subpid) +{ + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + #endif + #ifdef HAVE_KQUEUE + MyEventMachine->ArmKqueueReader (this); + #endif +} + + +/******************************* +PipeDescriptor::~PipeDescriptor +*******************************/ + +PipeDescriptor::~PipeDescriptor() NO_EXCEPT_FALSE +{ + // Run down any stranded outbound data. + for (size_t i=0; i < OutboundPages.size(); i++) + OutboundPages[i].Free(); + + /* As a virtual destructor, we come here before the base-class + * destructor that closes our file-descriptor. + * We have to make sure the subprocess goes down (if it's not + * already down) and we have to reap the zombie. + * + * This implementation is PROVISIONAL and will surely be improved. + * The intention here is that we never block, hence the highly + * undesirable sleeps. But if we can't reap the subprocess even + * after sending it SIGKILL, then something is wrong and we + * throw a fatal exception, which is also not something we should + * be doing. + * + * Eventually the right thing to do will be to have the reactor + * core respond to SIGCHLD by chaining a handler on top of the + * one Ruby may have installed, and dealing with a list of dead + * children that are pending cleanup. + * + * Since we want to have a signal processor integrated into the + * client-visible API, let's wait until that is done before cleaning + * this up. + * + * Added a very ugly hack to support passing the subprocess's exit + * status to the user. It only makes logical sense for user code to access + * the subprocess exit status in the unbind callback. But unbind is called + * back during the EventableDescriptor destructor. So by that time there's + * no way to call back this object through an object binding, because it's + * already been cleaned up. We might have added a parameter to the unbind + * callback, but that would probably break a huge amount of existing code. + * So the hack-solution is to define an instance variable in the EventMachine + * object and stick the exit status in there, where it can easily be accessed + * with an accessor visible to user code. + * User code should ONLY access the exit status from within the unbind callback. + * Otherwise there's no guarantee it'll be valid. + * This hack won't make it impossible to run multiple EventMachines in a single + * process, but it will make it impossible to reliably nest unbind calls + * within other unbind calls. (Not sure if that's even possible.) + */ + + assert (MyEventMachine); + + /* Another hack to make the SubprocessPid available to get_subprocess_status */ + MyEventMachine->SubprocessPid = SubprocessPid; + + /* 01Mar09: Updated to use a small nanosleep in a loop. When nanosleep is interrupted by SIGCHLD, + * it resumes the system call after processing the signal (resulting in unnecessary latency). + * Calling nanosleep in a loop avoids this problem. + */ + struct timespec req = {0, 50000000}; // 0.05s + int n; + + // wait 0.5s for the process to die + for (n=0; n<10; n++) { + if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return; + nanosleep (&req, NULL); + } + + // send SIGTERM and wait another 1s + kill (SubprocessPid, SIGTERM); + for (n=0; n<20; n++) { + nanosleep (&req, NULL); + if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return; + } + + // send SIGKILL and wait another 5s + kill (SubprocessPid, SIGKILL); + for (n=0; n<100; n++) { + nanosleep (&req, NULL); + if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return; + } + + // still not dead, give up! + throw std::runtime_error ("unable to reap subprocess"); +} + + + +/******************** +PipeDescriptor::Read +********************/ + +void PipeDescriptor::Read() +{ + int sd = GetSocket(); + if (sd == INVALID_SOCKET) { + assert (!bReadAttemptedAfterClose); + bReadAttemptedAfterClose = true; + return; + } + + LastActivity = MyEventMachine->GetCurrentLoopTime(); + + int total_bytes_read = 0; + char readbuffer [16 * 1024]; + + for (int i=0; i < 10; i++) { + // Don't read just one buffer and then move on. This is faster + // if there is a lot of incoming. + // But don't read indefinitely. Give other sockets a chance to run. + // NOTICE, we're reading one less than the buffer size. + // That's so we can put a guard byte at the end of what we send + // to user code. + // Use read instead of recv, which on Linux gives a "socket operation + // on nonsocket" error. + + + int r = read (sd, readbuffer, sizeof(readbuffer) - 1); + //cerr << ""; + + if (r > 0) { + total_bytes_read += r; + + // Add a null-terminator at the the end of the buffer + // that we will send to the callback. + // DO NOT EVER CHANGE THIS. We want to explicitly allow users + // to be able to depend on this behavior, so they will have + // the option to do some things faster. Additionally it's + // a security guard against buffer overflows. + readbuffer [r] = 0; + _GenericInboundDispatch(readbuffer, r); + } + else if (r == 0) { + break; + } + else { + // Basically a would-block, meaning we've read everything there is to read. + break; + } + + } + + + if (total_bytes_read == 0) { + // If we read no data on a socket that selected readable, + // it generally means the other end closed the connection gracefully. + ScheduleClose (false); + //bCloseNow = true; + } + +} + +/********************* +PipeDescriptor::Write +*********************/ + +void PipeDescriptor::Write() +{ + int sd = GetSocket(); + assert (sd != INVALID_SOCKET); + + LastActivity = MyEventMachine->GetCurrentLoopTime(); + char output_buffer [16 * 1024]; + size_t nbytes = 0; + + while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) { + OutboundPage *op = &(OutboundPages[0]); + if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) { + memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset); + nbytes += (op->Length - op->Offset); + op->Free(); + OutboundPages.pop_front(); + } + else { + int len = sizeof(output_buffer) - nbytes; + memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len); + op->Offset += len; + nbytes += len; + } + } + + // We should never have gotten here if there were no data to write, + // so assert that as a sanity check. + // Don't bother to make sure nbytes is less than output_buffer because + // if it were we probably would have crashed already. + assert (nbytes > 0); + + assert (GetSocket() != INVALID_SOCKET); + int bytes_written = write (GetSocket(), output_buffer, nbytes); +#ifdef OS_WIN32 + int e = WSAGetLastError(); +#else + int e = errno; +#endif + + if (bytes_written > 0) { + OutboundDataSize -= bytes_written; + if ((size_t)bytes_written < nbytes) { + int len = nbytes - bytes_written; + char *buffer = (char*) malloc (len + 1); + if (!buffer) + throw std::runtime_error ("bad alloc throwing back data"); + memcpy (buffer, output_buffer + bytes_written, len); + buffer [len] = 0; + OutboundPages.push_front (OutboundPage (buffer, len)); + } + #ifdef HAVE_EPOLL + EpollEvent.events = EPOLLIN; + if (SelectForWrite()) + EpollEvent.events |= EPOLLOUT; + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + } + else { + #ifdef OS_UNIX + if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) + #endif + #ifdef OS_WIN32 + if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) + #endif + Close(); + } +} + + +/************************* +PipeDescriptor::Heartbeat +*************************/ + +void PipeDescriptor::Heartbeat() +{ + // If an inactivity timeout is defined, then check for it. + if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) + ScheduleClose (false); + //bCloseNow = true; +} + + +/***************************** +PipeDescriptor::SelectForRead +*****************************/ + +bool PipeDescriptor::SelectForRead() +{ + /* Pipe descriptors, being local by definition, don't have + * a pending state, so this is simpler than for the + * ConnectionDescriptor object. + */ + return bPaused ? false : true; +} + +/****************************** +PipeDescriptor::SelectForWrite +******************************/ + +bool PipeDescriptor::SelectForWrite() +{ + /* Pipe descriptors, being local by definition, don't have + * a pending state, so this is simpler than for the + * ConnectionDescriptor object. + */ + return (GetOutboundDataSize() > 0) && !bPaused ? true : false; +} + + + + +/******************************** +PipeDescriptor::SendOutboundData +********************************/ + +int PipeDescriptor::SendOutboundData (const char *data, unsigned long length) +{ + //if (bCloseNow || bCloseAfterWriting) + if (IsCloseScheduled()) + return 0; + + if (!data && (length > 0)) + throw std::runtime_error ("bad outbound data"); + char *buffer = (char *) malloc (length + 1); + if (!buffer) + throw std::runtime_error ("no allocation for outbound data"); + memcpy (buffer, data, length); + buffer [length] = 0; + OutboundPages.push_back (OutboundPage (buffer, length)); + OutboundDataSize += length; + #ifdef HAVE_EPOLL + EpollEvent.events = (EPOLLIN | EPOLLOUT); + assert (MyEventMachine); + MyEventMachine->Modify (this); + #endif + return length; +} + +/******************************** +PipeDescriptor::GetSubprocessPid +********************************/ + +bool PipeDescriptor::GetSubprocessPid (pid_t *pid) +{ + bool ok = false; + if (pid && (SubprocessPid > 0)) { + *pid = SubprocessPid; + ok = true; + } + return ok; +} + + +#endif // OS_UNIX + diff --git a/bin/gems/eventmachine-1.2.7/ext/project.h b/bin/gems/eventmachine-1.2.7/ext/project.h new file mode 100644 index 00000000..757f7011 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/project.h @@ -0,0 +1,174 @@ +/***************************************************************************** + +$Id$ + +File: project.h +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#ifndef __Project__H_ +#define __Project__H_ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef OS_UNIX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +typedef int SOCKET; +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#ifdef OS_SOLARIS8 +#include +#include +#ifndef AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif +// INADDR_NONE is undefined on Solaris < 8. Thanks to Brett Eisenberg and Tim Pease. +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long)-1) +#endif +#endif /* OS_SOLARIS8 */ + +#ifdef _AIX +#include +#ifndef AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif +#endif /* _AIX */ + +#ifdef OS_DARWIN +#include +#include +#endif /* OS_DARWIN */ + +#endif /* OS_UNIX */ + +#ifdef OS_WIN32 +// 21Sep09: windows limits select() to 64 sockets by default, we increase it to 1024 here (before including winsock2.h) +// 18Jun12: fd_setsize must be changed in the ruby binary (not in this extension). redefining it also causes segvs, see eventmachine/eventmachine#333 +//#define FD_SETSIZE 1024 + +// WIN32_LEAN_AND_MEAN excludes APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets. +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include + +// Older versions of MinGW in the Ruby Dev Kit do not provide the getaddrinfo hint flags +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0x0400 +#endif + +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV 0x0008 +#endif + +// Use the Win32 wrapper library that Ruby owns to be able to close sockets with the close() function +#define RUBY_EXPORT +#include +#include +#endif /* OS_WIN32 */ + +#if !defined(_MSC_VER) || _MSC_VER > 1500 +#include +#endif + +#ifdef WITH_SSL +#include +#include +#endif + +#ifdef HAVE_EPOLL +#include +#endif + +#ifdef HAVE_KQUEUE +#include +#include +#endif + +#ifdef HAVE_INOTIFY +#include +#endif + +#ifdef HAVE_OLD_INOTIFY +#include +#include +static inline int inotify_init (void) { return syscall (__NR_inotify_init); } +static inline int inotify_add_watch (int fd, const char *name, __u32 mask) { return syscall (__NR_inotify_add_watch, fd, name, mask); } +static inline int inotify_rm_watch (int fd, __u32 wd) { return syscall (__NR_inotify_rm_watch, fd, wd); } +#define HAVE_INOTIFY 1 +#endif + +#ifdef HAVE_INOTIFY +#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event)) +#endif + +#ifdef HAVE_WRITEV +#include +#endif + +#if __cplusplus +extern "C" { +#endif + typedef void (*EMCallback)(const unsigned long, int, const char*, const unsigned long); +#if __cplusplus +} +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#endif + +#include "binder.h" +#include "em.h" +#include "ed.h" +#include "page.h" +#include "ssl.h" +#include "eventmachine.h" + +#endif // __Project__H_ diff --git a/bin/gems/eventmachine-1.2.7/ext/rubymain.cpp b/bin/gems/eventmachine-1.2.7/ext/rubymain.cpp new file mode 100644 index 00000000..305f9cbd --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/rubymain.cpp @@ -0,0 +1,1515 @@ +/***************************************************************************** + +$Id$ + +File: rubymain.cpp +Date: 06Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + +#include "project.h" +#include "eventmachine.h" +#include + +#ifndef RFLOAT_VALUE +#define RFLOAT_VALUE(arg) RFLOAT(arg)->value +#endif + +/* Adapted from NUM2BSIG / BSIG2NUM in ext/fiddle/conversions.h, + * we'll call it a BSIG for Binding Signature here. */ +#if SIZEOF_VOIDP == SIZEOF_LONG +# define BSIG2NUM(x) (ULONG2NUM((unsigned long)(x))) +# define NUM2BSIG(x) (NUM2ULONG(x)) +# ifdef OS_WIN32 +# define PRIFBSIG "I32u" +# else +# define PRIFBSIG "lu" +# endif +#else +# define BSIG2NUM(x) (ULL2NUM((unsigned long long)(x))) +# define NUM2BSIG(x) (NUM2ULL(x)) +# ifdef OS_WIN32 +# define PRIFBSIG "I64u" +# else +# define PRIFBSIG "llu" +# endif +#endif + +/******* +Statics +*******/ + +static VALUE EmModule; +static VALUE EmConnection; +static VALUE EmConnsHash; +static VALUE EmTimersHash; + +static VALUE EM_eConnectionError; +static VALUE EM_eUnknownTimerFired; +static VALUE EM_eConnectionNotBound; +static VALUE EM_eUnsupported; +static VALUE EM_eInvalidSignature; + +static VALUE Intern_at_signature; +static VALUE Intern_at_timers; +static VALUE Intern_at_conns; +static VALUE Intern_at_error_handler; +static VALUE Intern_event_callback; +static VALUE Intern_run_deferred_callbacks; +static VALUE Intern_delete; +static VALUE Intern_call; +static VALUE Intern_at; +static VALUE Intern_receive_data; +static VALUE Intern_ssl_handshake_completed; +static VALUE Intern_ssl_verify_peer; +static VALUE Intern_notify_readable; +static VALUE Intern_notify_writable; +static VALUE Intern_proxy_target_unbound; +static VALUE Intern_proxy_completed; +static VALUE Intern_connection_completed; + +static VALUE rb_cProcStatus; + +struct em_event { + uintptr_t signature; + int event; + const char *data_str; + unsigned long data_num; +}; + +static inline VALUE ensure_conn(const uintptr_t signature) +{ + VALUE conn = rb_hash_aref (EmConnsHash, BSIG2NUM (signature)); + if (conn == Qnil) + rb_raise (EM_eConnectionNotBound, "unknown connection: %" PRIFBSIG, signature); + return conn; +} + + +/**************** +t_event_callback +****************/ + +static inline void event_callback (struct em_event* e) +{ + const uintptr_t signature = e->signature; + int event = e->event; + const char *data_str = e->data_str; + const unsigned long data_num = e->data_num; + + switch (event) { + case EM_CONNECTION_READ: + { + VALUE conn = rb_hash_aref (EmConnsHash, BSIG2NUM (signature)); + if (conn == Qnil) + rb_raise (EM_eConnectionNotBound, "received %lu bytes of data for unknown signature: %" PRIFBSIG, data_num, signature); + rb_funcall (conn, Intern_receive_data, 1, rb_str_new (data_str, data_num)); + return; + } + case EM_CONNECTION_ACCEPTED: + { + rb_funcall (EmModule, Intern_event_callback, 3, BSIG2NUM(signature), INT2FIX(event), ULONG2NUM(data_num)); + return; + } + case EM_CONNECTION_UNBOUND: + { + rb_funcall (EmModule, Intern_event_callback, 3, BSIG2NUM(signature), INT2FIX(event), ULONG2NUM(data_num)); + return; + } + case EM_CONNECTION_COMPLETED: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_connection_completed, 0); + return; + } + case EM_CONNECTION_NOTIFY_READABLE: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_notify_readable, 0); + return; + } + case EM_CONNECTION_NOTIFY_WRITABLE: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_notify_writable, 0); + return; + } + case EM_LOOPBREAK_SIGNAL: + { + rb_funcall (EmModule, Intern_run_deferred_callbacks, 0); + return; + } + case EM_TIMER_FIRED: + { + VALUE timer = rb_funcall (EmTimersHash, Intern_delete, 1, ULONG2NUM (data_num)); + if (timer == Qnil) { + rb_raise (EM_eUnknownTimerFired, "no such timer: %lu", data_num); + } else if (timer == Qfalse) { + /* Timer Canceled */ + } else { + rb_funcall (timer, Intern_call, 0); + } + return; + } + #ifdef WITH_SSL + case EM_SSL_HANDSHAKE_COMPLETED: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_ssl_handshake_completed, 0); + return; + } + case EM_SSL_VERIFY: + { + VALUE conn = ensure_conn(signature); + VALUE should_accept = rb_funcall (conn, Intern_ssl_verify_peer, 1, rb_str_new(data_str, data_num)); + if (RTEST(should_accept)) + evma_accept_ssl_peer (signature); + return; + } + #endif + case EM_PROXY_TARGET_UNBOUND: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_proxy_target_unbound, 0); + return; + } + case EM_PROXY_COMPLETED: + { + VALUE conn = ensure_conn(signature); + rb_funcall (conn, Intern_proxy_completed, 0); + return; + } + } +} + +/******************* +event_error_handler +*******************/ + +static void event_error_handler(VALUE self UNUSED, VALUE err) +{ + VALUE error_handler = rb_ivar_get(EmModule, Intern_at_error_handler); + rb_funcall (error_handler, Intern_call, 1, err); +} + +/********************** +event_callback_wrapper +**********************/ + +static void event_callback_wrapper (const uintptr_t signature, int event, const char *data_str, const unsigned long data_num) +{ + struct em_event e; + e.signature = signature; + e.event = event; + e.data_str = data_str; + e.data_num = data_num; + + if (!rb_ivar_defined(EmModule, Intern_at_error_handler)) + event_callback(&e); + else + rb_rescue((VALUE (*)(ANYARGS))event_callback, (VALUE)&e, (VALUE (*)(ANYARGS))event_error_handler, Qnil); +} + +/************************** +t_initialize_event_machine +**************************/ + +static VALUE t_initialize_event_machine (VALUE self UNUSED) +{ + EmConnsHash = rb_ivar_get (EmModule, Intern_at_conns); + EmTimersHash = rb_ivar_get (EmModule, Intern_at_timers); + assert(EmConnsHash != Qnil); + assert(EmTimersHash != Qnil); + evma_initialize_library ((EMCallback)event_callback_wrapper); + return Qnil; +} + + +/****************** +t_run_machine_once +******************/ + +static VALUE t_run_machine_once (VALUE self UNUSED) +{ + return evma_run_machine_once () ? Qtrue : Qfalse; +} + + +/************* +t_run_machine +*************/ + +static VALUE t_run_machine (VALUE self UNUSED) +{ + evma_run_machine(); + return Qnil; +} + + +/******************* +t_add_oneshot_timer +*******************/ + +static VALUE t_add_oneshot_timer (VALUE self UNUSED, VALUE interval) +{ + const uintptr_t f = evma_install_oneshot_timer (FIX2LONG (interval)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "ran out of timers; use #set_max_timers to increase limit"); + return BSIG2NUM (f); +} + + +/************** +t_start_server +**************/ + +static VALUE t_start_server (VALUE self UNUSED, VALUE server, VALUE port) +{ + const uintptr_t f = evma_create_tcp_server (StringValueCStr(server), FIX2INT(port)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no acceptor (port is in use or requires root privileges)"); + return BSIG2NUM (f); +} + +/************* +t_stop_server +*************/ + +static VALUE t_stop_server (VALUE self UNUSED, VALUE signature) +{ + evma_stop_tcp_server (NUM2BSIG (signature)); + return Qnil; +} + + +/******************* +t_start_unix_server +*******************/ + +static VALUE t_start_unix_server (VALUE self UNUSED, VALUE filename) +{ + const uintptr_t f = evma_create_unix_domain_server (StringValueCStr(filename)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no unix-domain acceptor"); + return BSIG2NUM (f); +} + +/******************** +t_attach_sd +********************/ + +static VALUE t_attach_sd(VALUE self UNUSED, VALUE sd) +{ + const uintptr_t f = evma_attach_sd(FIX2INT(sd)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no socket descriptor acceptor"); + return BSIG2NUM (f); +} + + +/*********** +t_send_data +***********/ + +static VALUE t_send_data (VALUE self UNUSED, VALUE signature, VALUE data, VALUE data_length) +{ + int b = evma_send_data_to_connection (NUM2BSIG (signature), StringValuePtr (data), FIX2INT (data_length)); + return INT2NUM (b); +} + + +/*********** +t_start_tls +***********/ + +static VALUE t_start_tls (VALUE self UNUSED, VALUE signature) +{ + evma_start_tls (NUM2BSIG (signature)); + return Qnil; +} + +/*************** +t_set_tls_parms +***************/ + +static VALUE t_set_tls_parms (VALUE self UNUSED, VALUE signature, VALUE privkeyfile, VALUE certchainfile, VALUE verify_peer, VALUE fail_if_no_peer_cert, VALUE snihostname, VALUE cipherlist, VALUE ecdh_curve, VALUE dhparam, VALUE ssl_version) +{ + /* set_tls_parms takes a series of positional arguments for specifying such things + * as private keys and certificate chains. + * It's expected that the parameter list will grow as we add more supported features. + * ALL of these parameters are optional, and can be specified as empty or NULL strings. + */ + evma_set_tls_parms (NUM2BSIG (signature), StringValueCStr (privkeyfile), StringValueCStr (certchainfile), (verify_peer == Qtrue ? 1 : 0), (fail_if_no_peer_cert == Qtrue ? 1 : 0), StringValueCStr (snihostname), StringValueCStr (cipherlist), StringValueCStr (ecdh_curve), StringValueCStr (dhparam), NUM2INT (ssl_version)); + return Qnil; +} + +/*************** +t_get_peer_cert +***************/ + +#ifdef WITH_SSL +static VALUE t_get_peer_cert (VALUE self UNUSED, VALUE signature) +{ + VALUE ret = Qnil; + + X509 *cert = NULL; + BUF_MEM *buf; + BIO *out; + + cert = evma_get_peer_cert (NUM2BSIG (signature)); + + if (cert != NULL) { + out = BIO_new(BIO_s_mem()); + PEM_write_bio_X509(out, cert); + BIO_get_mem_ptr(out, &buf); + ret = rb_str_new(buf->data, buf->length); + X509_free(cert); + BIO_free(out); + } + + return ret; +} +#else +static VALUE t_get_peer_cert (VALUE self UNUSED, VALUE signature UNUSED) +{ + return Qnil; +} +#endif + +/*************** +t_get_cipher_bits +***************/ + +#ifdef WITH_SSL +static VALUE t_get_cipher_bits (VALUE self UNUSED, VALUE signature) +{ + int bits = evma_get_cipher_bits (NUM2BSIG (signature)); + if (bits == -1) + return Qnil; + return INT2NUM (bits); +} +#else +static VALUE t_get_cipher_bits (VALUE self UNUSED, VALUE signature UNUSED) +{ + return Qnil; +} +#endif + +/*************** +t_get_cipher_name +***************/ + +#ifdef WITH_SSL +static VALUE t_get_cipher_name (VALUE self UNUSED, VALUE signature) +{ + const char *protocol = evma_get_cipher_name (NUM2BSIG (signature)); + if (protocol) + return rb_str_new2 (protocol); + + return Qnil; +} +#else +static VALUE t_get_cipher_name (VALUE self UNUSED, VALUE signature UNUSED) +{ + return Qnil; +} +#endif + +/*************** +t_get_cipher_protocol +***************/ + +#ifdef WITH_SSL +static VALUE t_get_cipher_protocol (VALUE self UNUSED, VALUE signature) +{ + const char *cipher = evma_get_cipher_protocol (NUM2BSIG (signature)); + if (cipher) + return rb_str_new2 (cipher); + + return Qnil; +} +#else +static VALUE t_get_cipher_protocol (VALUE self UNUSED, VALUE signature UNUSED) +{ + return Qnil; +} +#endif + +/*************** +t_get_sni_hostname +***************/ + +#ifdef WITH_SSL +static VALUE t_get_sni_hostname (VALUE self UNUSED, VALUE signature) +{ + const char *sni_hostname = evma_get_sni_hostname (NUM2BSIG (signature)); + if (sni_hostname) + return rb_str_new2 (sni_hostname); + + return Qnil; +} +#else +static VALUE t_get_sni_hostname (VALUE self UNUSED, VALUE signature UNUSED) +{ + return Qnil; +} +#endif + +/************** +t_get_peername +**************/ + +static VALUE t_get_peername (VALUE self UNUSED, VALUE signature) +{ + char buf[1024]; + socklen_t len = sizeof buf; + try { + if (evma_get_peername (NUM2BSIG (signature), (struct sockaddr*)buf, &len)) { + return rb_str_new (buf, len); + } + } catch (std::runtime_error e) { + rb_raise (rb_eRuntimeError, "%s", e.what()); + } + + return Qnil; +} + +/************** +t_get_sockname +**************/ + +static VALUE t_get_sockname (VALUE self UNUSED, VALUE signature) +{ + char buf[1024]; + socklen_t len = sizeof buf; + try { + if (evma_get_sockname (NUM2BSIG (signature), (struct sockaddr*)buf, &len)) { + return rb_str_new (buf, len); + } + } catch (std::runtime_error e) { + rb_raise (rb_eRuntimeError, "%s", e.what()); + } + + return Qnil; +} + +/******************** +t_get_subprocess_pid +********************/ + +static VALUE t_get_subprocess_pid (VALUE self UNUSED, VALUE signature) +{ + pid_t pid; + if (evma_get_subprocess_pid (NUM2BSIG (signature), &pid)) { + return INT2NUM (pid); + } + + return Qnil; +} + +/*********************** +t_get_subprocess_status +***********************/ + +static VALUE t_get_subprocess_status (VALUE self UNUSED, VALUE signature) +{ + VALUE proc_status = Qnil; + + int status; + pid_t pid; + + if (evma_get_subprocess_status (NUM2BSIG (signature), &status)) { + if (evma_get_subprocess_pid (NUM2BSIG (signature), &pid)) { + proc_status = rb_obj_alloc(rb_cProcStatus); + + /* MRI Ruby uses hidden instance vars */ + rb_iv_set(proc_status, "status", INT2FIX(status)); + rb_iv_set(proc_status, "pid", INT2FIX(pid)); + +#ifdef RUBINIUS + /* Rubinius uses standard instance vars */ + rb_iv_set(proc_status, "@pid", INT2FIX(pid)); + if (WIFEXITED(status)) { + rb_iv_set(proc_status, "@status", INT2FIX(WEXITSTATUS(status))); + } else if (WIFSIGNALED(status)) { + rb_iv_set(proc_status, "@termsig", INT2FIX(WTERMSIG(status))); + } else if (WIFSTOPPED(status)) { + rb_iv_set(proc_status, "@stopsig", INT2FIX(WSTOPSIG(status))); + } +#endif + } + } + + return proc_status; +} + +/********************** +t_get_connection_count +**********************/ + +static VALUE t_get_connection_count (VALUE self UNUSED) +{ + return INT2NUM(evma_get_connection_count()); +} + +/***************************** +t_get_comm_inactivity_timeout +*****************************/ + +static VALUE t_get_comm_inactivity_timeout (VALUE self UNUSED, VALUE signature) +{ + return rb_float_new(evma_get_comm_inactivity_timeout(NUM2BSIG (signature))); +} + +/***************************** +t_set_comm_inactivity_timeout +*****************************/ + +static VALUE t_set_comm_inactivity_timeout (VALUE self UNUSED, VALUE signature, VALUE timeout) +{ + float ti = RFLOAT_VALUE(timeout); + if (evma_set_comm_inactivity_timeout(NUM2BSIG(signature), ti)) { + return Qtrue; + } + return Qfalse; +} + +/***************************** +t_get_pending_connect_timeout +*****************************/ + +static VALUE t_get_pending_connect_timeout (VALUE self UNUSED, VALUE signature) +{ + return rb_float_new(evma_get_pending_connect_timeout(NUM2BSIG (signature))); +} + +/***************************** +t_set_pending_connect_timeout +*****************************/ + +static VALUE t_set_pending_connect_timeout (VALUE self UNUSED, VALUE signature, VALUE timeout) +{ + float ti = RFLOAT_VALUE(timeout); + if (evma_set_pending_connect_timeout(NUM2BSIG(signature), ti)) { + return Qtrue; + } + return Qfalse; +} + +/*************** +t_send_datagram +***************/ + +static VALUE t_send_datagram (VALUE self UNUSED, VALUE signature, VALUE data, VALUE data_length, VALUE address, VALUE port) +{ + int b = evma_send_datagram (NUM2BSIG (signature), StringValuePtr (data), FIX2INT (data_length), StringValueCStr(address), FIX2INT(port)); + if (b < 0) + rb_raise (EM_eConnectionError, "%s", "error in sending datagram"); // FIXME: this could be more specific. + return INT2NUM (b); +} + + +/****************** +t_close_connection +******************/ + +static VALUE t_close_connection (VALUE self UNUSED, VALUE signature, VALUE after_writing) +{ + evma_close_connection (NUM2BSIG (signature), ((after_writing == Qtrue) ? 1 : 0)); + return Qnil; +} + +/******************************** +t_report_connection_error_status +********************************/ + +static VALUE t_report_connection_error_status (VALUE self UNUSED, VALUE signature) +{ + int b = evma_report_connection_error_status (NUM2BSIG (signature)); + return INT2NUM (b); +} + + + +/**************** +t_connect_server +****************/ + +static VALUE t_connect_server (VALUE self UNUSED, VALUE server, VALUE port) +{ + // Avoid FIX2INT in this case, because it doesn't deal with type errors properly. + // Specifically, if the value of port comes in as a string rather than an integer, + // NUM2INT will throw a type error, but FIX2INT will generate garbage. + + try { + const uintptr_t f = evma_connect_to_server (NULL, 0, StringValueCStr(server), NUM2INT(port)); + if (!f) + rb_raise (EM_eConnectionError, "%s", "no connection"); + return BSIG2NUM (f); + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + +/********************* +t_bind_connect_server +*********************/ + +static VALUE t_bind_connect_server (VALUE self UNUSED, VALUE bind_addr, VALUE bind_port, VALUE server, VALUE port) +{ + // Avoid FIX2INT in this case, because it doesn't deal with type errors properly. + // Specifically, if the value of port comes in as a string rather than an integer, + // NUM2INT will throw a type error, but FIX2INT will generate garbage. + + try { + const uintptr_t f = evma_connect_to_server (StringValueCStr(bind_addr), NUM2INT(bind_port), StringValueCStr(server), NUM2INT(port)); + if (!f) + rb_raise (EM_eConnectionError, "%s", "no connection"); + return BSIG2NUM (f); + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + +/********************* +t_connect_unix_server +*********************/ + +static VALUE t_connect_unix_server (VALUE self UNUSED, VALUE serversocket) +{ + const uintptr_t f = evma_connect_to_unix_server (StringValueCStr(serversocket)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no connection"); + return BSIG2NUM (f); +} + +/*********** +t_attach_fd +***********/ + +static VALUE t_attach_fd (VALUE self UNUSED, VALUE file_descriptor, VALUE watch_mode) +{ + const uintptr_t f = evma_attach_fd (NUM2INT(file_descriptor), watch_mode == Qtrue); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no connection"); + return BSIG2NUM (f); +} + +/*********** +t_detach_fd +***********/ + +static VALUE t_detach_fd (VALUE self UNUSED, VALUE signature) +{ + return INT2NUM(evma_detach_fd (NUM2BSIG (signature))); +} + +/********************* +t_get_file_descriptor +*********************/ +static VALUE t_get_file_descriptor (VALUE self UNUSED, VALUE signature) +{ + return INT2NUM(evma_get_file_descriptor (NUM2BSIG (signature))); +} + +/************** +t_get_sock_opt +**************/ + +static VALUE t_get_sock_opt (VALUE self UNUSED, VALUE signature, VALUE lev, VALUE optname) +{ + int fd = evma_get_file_descriptor (NUM2BSIG (signature)); + int level = NUM2INT(lev), option = NUM2INT(optname); + socklen_t len = 128; + char buf[128]; + + if (getsockopt(fd, level, option, buf, &len) < 0) + rb_sys_fail("getsockopt"); + + return rb_str_new(buf, len); +} + +/************** +t_set_sock_opt +**************/ + +static VALUE t_set_sock_opt (VALUE self UNUSED, VALUE signature, VALUE lev, VALUE optname, VALUE optval) +{ + int fd = evma_get_file_descriptor (NUM2BSIG (signature)); + int level = NUM2INT(lev), option = NUM2INT(optname); + int i; + const void *v; + socklen_t len; + + switch (TYPE(optval)) { + case T_FIXNUM: + i = FIX2INT(optval); + goto numval; + case T_FALSE: + i = 0; + goto numval; + case T_TRUE: + i = 1; + numval: + v = (void*)&i; len = sizeof(i); + break; + default: + StringValue(optval); + v = RSTRING_PTR(optval); + len = RSTRING_LENINT(optval); + break; + } + + + if (setsockopt(fd, level, option, (char *)v, len) < 0) + rb_sys_fail("setsockopt"); + + return INT2FIX(0); +} + +/******************** +t_is_notify_readable +********************/ + +static VALUE t_is_notify_readable (VALUE self UNUSED, VALUE signature) +{ + return evma_is_notify_readable(NUM2BSIG (signature)) ? Qtrue : Qfalse; +} + +/********************* +t_set_notify_readable +*********************/ + +static VALUE t_set_notify_readable (VALUE self UNUSED, VALUE signature, VALUE mode) +{ + evma_set_notify_readable(NUM2BSIG(signature), mode == Qtrue); + return Qnil; +} + +/******************** +t_is_notify_readable +********************/ + +static VALUE t_is_notify_writable (VALUE self UNUSED, VALUE signature) +{ + return evma_is_notify_writable(NUM2BSIG (signature)) ? Qtrue : Qfalse; +} + +/********************* +t_set_notify_writable +*********************/ + +static VALUE t_set_notify_writable (VALUE self UNUSED, VALUE signature, VALUE mode) +{ + evma_set_notify_writable(NUM2BSIG (signature), mode == Qtrue); + return Qnil; +} + +/******* +t_pause +*******/ + +static VALUE t_pause (VALUE self UNUSED, VALUE signature) +{ + return evma_pause(NUM2BSIG (signature)) ? Qtrue : Qfalse; +} + +/******** +t_resume +********/ + +static VALUE t_resume (VALUE self UNUSED, VALUE signature) +{ + return evma_resume(NUM2BSIG (signature)) ? Qtrue : Qfalse; +} + +/********** +t_paused_p +**********/ + +static VALUE t_paused_p (VALUE self UNUSED, VALUE signature) +{ + return evma_is_paused(NUM2BSIG (signature)) ? Qtrue : Qfalse; +} + +/********************* +t_num_close_scheduled +*********************/ + +static VALUE t_num_close_scheduled (VALUE self UNUSED) +{ + return INT2FIX(evma_num_close_scheduled()); +} + +/***************** +t_open_udp_socket +*****************/ + +static VALUE t_open_udp_socket (VALUE self UNUSED, VALUE server, VALUE port) +{ + const uintptr_t f = evma_open_datagram_socket (StringValueCStr(server), FIX2INT(port)); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no datagram socket"); + return BSIG2NUM(f); +} + + + +/***************** +t_release_machine +*****************/ + +static VALUE t_release_machine (VALUE self UNUSED) +{ + evma_release_library(); + return Qnil; +} + + +/****** +t_stop +******/ + +static VALUE t_stop (VALUE self UNUSED) +{ + evma_stop_machine(); + return Qnil; +} + +/****************** +t_signal_loopbreak +******************/ + +static VALUE t_signal_loopbreak (VALUE self UNUSED) +{ + evma_signal_loopbreak(); + return Qnil; +} + +/************** +t_library_type +**************/ + +static VALUE t_library_type (VALUE self UNUSED) +{ + return rb_eval_string (":extension"); +} + + + +/******************* +t_set_timer_quantum +*******************/ + +static VALUE t_set_timer_quantum (VALUE self UNUSED, VALUE interval) +{ + evma_set_timer_quantum (FIX2INT (interval)); + return Qnil; +} + +/******************** +t_get_max_timer_count +********************/ + +static VALUE t_get_max_timer_count (VALUE self UNUSED) +{ + return INT2FIX (evma_get_max_timer_count()); +} + +/******************** +t_set_max_timer_count +********************/ + +static VALUE t_set_max_timer_count (VALUE self UNUSED, VALUE ct) +{ + evma_set_max_timer_count (FIX2INT (ct)); + return Qnil; +} + +/******************** +t_get/set_simultaneous_accept_count +********************/ + +static VALUE t_get_simultaneous_accept_count (VALUE self UNUSED) +{ + return INT2FIX (evma_get_simultaneous_accept_count()); +} + +static VALUE t_set_simultaneous_accept_count (VALUE self UNUSED, VALUE ct) +{ + evma_set_simultaneous_accept_count (FIX2INT (ct)); + return Qnil; +} + +/*************** +t_setuid_string +***************/ + +static VALUE t_setuid_string (VALUE self UNUSED, VALUE username) +{ + evma_setuid_string (StringValueCStr (username)); + return Qnil; +} + + + +/************** +t_invoke_popen +**************/ + +static VALUE t_invoke_popen (VALUE self UNUSED, VALUE cmd) +{ + #ifdef OS_WIN32 + rb_raise (EM_eUnsupported, "popen is not available on this platform"); + #endif + + int len = RARRAY_LEN(cmd); + if (len >= 2048) + rb_raise (rb_eRuntimeError, "%s", "too many arguments to popen"); + char *strings [2048]; + for (int i=0; i < len; i++) { + VALUE ix = INT2FIX (i); + VALUE s = rb_ary_aref (1, &ix, cmd); + strings[i] = StringValueCStr (s); + } + strings[len] = NULL; + + uintptr_t f = 0; + try { + f = evma_popen (strings); + } catch (std::runtime_error e) { + rb_raise (rb_eRuntimeError, "%s", e.what()); + } + if (!f) { + char *err = strerror (errno); + char buf[100]; + memset (buf, 0, sizeof(buf)); + snprintf (buf, sizeof(buf)-1, "no popen: %s", (err?err:"???")); + rb_raise (rb_eRuntimeError, "%s", buf); + } + return BSIG2NUM (f); +} + + +/*************** +t_read_keyboard +***************/ + +static VALUE t_read_keyboard (VALUE self UNUSED) +{ + const uintptr_t f = evma_open_keyboard(); + if (!f) + rb_raise (rb_eRuntimeError, "%s", "no keyboard reader"); + return BSIG2NUM (f); +} + + +/**************** +t_watch_filename +****************/ + +static VALUE t_watch_filename (VALUE self UNUSED, VALUE fname) +{ + try { + return BSIG2NUM(evma_watch_filename(StringValueCStr(fname))); + } catch (std::runtime_error e) { + rb_raise (EM_eUnsupported, "%s", e.what()); + } + return Qnil; +} + + +/****************** +t_unwatch_filename +******************/ + +static VALUE t_unwatch_filename (VALUE self UNUSED, VALUE sig) +{ + try { + evma_unwatch_filename(NUM2BSIG (sig)); + } catch (std::runtime_error e) { + rb_raise (EM_eInvalidSignature, "%s", e.what()); + } + + return Qnil; +} + + +/*********** +t_watch_pid +***********/ + +static VALUE t_watch_pid (VALUE self UNUSED, VALUE pid) +{ + try { + return BSIG2NUM(evma_watch_pid(NUM2INT(pid))); + } catch (std::runtime_error e) { + rb_raise (EM_eUnsupported, "%s", e.what()); + } + return Qnil; +} + + +/************* +t_unwatch_pid +*************/ + +static VALUE t_unwatch_pid (VALUE self UNUSED, VALUE sig) +{ + evma_unwatch_pid(NUM2BSIG (sig)); + return Qnil; +} + + +/********** +t__epoll_p +**********/ + +static VALUE t__epoll_p (VALUE self UNUSED) +{ + #ifdef HAVE_EPOLL + return Qtrue; + #else + return Qfalse; + #endif +} + +/******** +t__epoll +********/ + +static VALUE t__epoll (VALUE self UNUSED) +{ + if (t__epoll_p(self) == Qfalse) + return Qfalse; + + evma_set_epoll (1); + return Qtrue; +} + +/*********** +t__epoll_set +***********/ + +static VALUE t__epoll_set (VALUE self, VALUE val) +{ + if (t__epoll_p(self) == Qfalse && val == Qtrue) + rb_raise (EM_eUnsupported, "%s", "epoll is not supported on this platform"); + + evma_set_epoll (val == Qtrue ? 1 : 0); + return val; +} + + +/*********** +t__kqueue_p +***********/ + +static VALUE t__kqueue_p (VALUE self UNUSED) +{ + #ifdef HAVE_KQUEUE + return Qtrue; + #else + return Qfalse; + #endif +} + +/********* +t__kqueue +*********/ + +static VALUE t__kqueue (VALUE self UNUSED) +{ + if (t__kqueue_p(self) == Qfalse) + return Qfalse; + + evma_set_kqueue (1); + return Qtrue; +} + +/************* +t__kqueue_set +*************/ + +static VALUE t__kqueue_set (VALUE self, VALUE val) +{ + if (t__kqueue_p(self) == Qfalse && val == Qtrue) + rb_raise (EM_eUnsupported, "%s", "kqueue is not supported on this platform"); + + evma_set_kqueue (val == Qtrue ? 1 : 0); + return val; +} + + +/******** +t__ssl_p +********/ + +static VALUE t__ssl_p (VALUE self UNUSED) +{ + #ifdef WITH_SSL + return Qtrue; + #else + return Qfalse; + #endif +} + +/******** +t_stopping +********/ + +static VALUE t_stopping () +{ + if (evma_stopping()) { + return Qtrue; + } else { + return Qfalse; + } +} + + +/**************** +t_send_file_data +****************/ + +static VALUE t_send_file_data (VALUE self UNUSED, VALUE signature, VALUE filename) +{ + + /* The current implementation of evma_send_file_data_to_connection enforces a strict + * upper limit on the file size it will transmit (currently 32K). The function returns + * zero on success, -1 if the requested file exceeds its size limit, and a positive + * number for other errors. + * TODO: Positive return values are actually errno's, which is probably the wrong way to + * do this. For one thing it's ugly. For another, we can't be sure zero is never a real errno. + */ + + int b = evma_send_file_data_to_connection (NUM2BSIG (signature), StringValueCStr(filename)); + if (b == -1) + rb_raise(rb_eRuntimeError, "%s", "File too large. send_file_data() supports files under 32k."); + if (b > 0) { + char *err = strerror (b); + char buf[1024]; + memset (buf, 0, sizeof(buf)); + snprintf (buf, sizeof(buf)-1, ": %s %s", StringValueCStr(filename),(err?err:"???")); + + rb_raise (rb_eIOError, "%s", buf); + } + + return INT2NUM (0); +} + + +/******************* +t_set_rlimit_nofile +*******************/ + +static VALUE t_set_rlimit_nofile (VALUE self UNUSED, VALUE arg) +{ + arg = (NIL_P(arg)) ? -1 : NUM2INT (arg); + return INT2NUM (evma_set_rlimit_nofile (arg)); +} + +/*************************** +conn_get_outbound_data_size +***************************/ + +static VALUE conn_get_outbound_data_size (VALUE self) +{ + VALUE sig = rb_ivar_get (self, Intern_at_signature); + return INT2NUM (evma_get_outbound_data_size (NUM2BSIG (sig))); +} + + +/****************************** +conn_associate_callback_target +******************************/ + +static VALUE conn_associate_callback_target (VALUE self UNUSED, VALUE sig UNUSED) +{ + // No-op for the time being. + return Qnil; +} + + +/*************** +t_get_loop_time +****************/ + +static VALUE t_get_loop_time (VALUE self UNUSED) +{ + uint64_t current_time = evma_get_current_loop_time(); + if (current_time == 0) { + return Qnil; + } + + // Generally the industry has moved to 64-bit time_t, this is just in case we're 32-bit time_t. + if (sizeof(time_t) < 8 && current_time > INT_MAX) { + return rb_funcall(rb_cTime, Intern_at, 2, INT2NUM(current_time / 1000000), INT2NUM(current_time % 1000000)); + } else { + return rb_time_new(current_time / 1000000, current_time % 1000000); + } +} + + +/************* +t_start_proxy +**************/ + +static VALUE t_start_proxy (VALUE self UNUSED, VALUE from, VALUE to, VALUE bufsize, VALUE length) +{ + try { + evma_start_proxy(NUM2BSIG (from), NUM2BSIG (to), NUM2ULONG(bufsize), NUM2ULONG(length)); + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + + +/************ +t_stop_proxy +*************/ + +static VALUE t_stop_proxy (VALUE self UNUSED, VALUE from) +{ + try{ + evma_stop_proxy(NUM2BSIG (from)); + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + +/*************** +t_proxied_bytes +****************/ + +static VALUE t_proxied_bytes (VALUE self UNUSED, VALUE from) +{ + try{ + return BSIG2NUM(evma_proxied_bytes(NUM2BSIG (from))); + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + +/*************** +t_get_idle_time +****************/ + +static VALUE t_get_idle_time (VALUE self UNUSED, VALUE from) +{ + try{ + uint64_t current_time = evma_get_current_loop_time(); + uint64_t time = evma_get_last_activity_time(NUM2BSIG (from)); + if (current_time != 0 && time != 0) { + if (time >= current_time) + return BSIG2NUM(0); + else { + uint64_t diff = current_time - time; + float seconds = diff / (1000.0*1000.0); + return rb_float_new(seconds); + } + return Qnil; + } + } catch (std::runtime_error e) { + rb_raise (EM_eConnectionError, "%s", e.what()); + } + return Qnil; +} + +/************************ +t_get_heartbeat_interval +*************************/ + +static VALUE t_get_heartbeat_interval (VALUE self UNUSED) +{ + return rb_float_new(evma_get_heartbeat_interval()); +} + + +/************************ +t_set_heartbeat_interval +*************************/ + +static VALUE t_set_heartbeat_interval (VALUE self UNUSED, VALUE interval) +{ + float iv = RFLOAT_VALUE(interval); + if (evma_set_heartbeat_interval(iv)) + return Qtrue; + return Qfalse; +} + + +/********************* +Init_rubyeventmachine +*********************/ + +extern "C" void Init_rubyeventmachine() +{ + // Lookup Process::Status for get_subprocess_status + VALUE rb_mProcess = rb_const_get(rb_cObject, rb_intern("Process")); + rb_cProcStatus = rb_const_get(rb_mProcess, rb_intern("Status")); + + // Tuck away some symbol values so we don't have to look 'em up every time we need 'em. + Intern_at_signature = rb_intern ("@signature"); + Intern_at_timers = rb_intern ("@timers"); + Intern_at_conns = rb_intern ("@conns"); + Intern_at_error_handler = rb_intern("@error_handler"); + + Intern_event_callback = rb_intern ("event_callback"); + Intern_run_deferred_callbacks = rb_intern ("run_deferred_callbacks"); + Intern_delete = rb_intern ("delete"); + Intern_call = rb_intern ("call"); + Intern_at = rb_intern("at"); + Intern_receive_data = rb_intern ("receive_data"); + Intern_ssl_handshake_completed = rb_intern ("ssl_handshake_completed"); + Intern_ssl_verify_peer = rb_intern ("ssl_verify_peer"); + Intern_notify_readable = rb_intern ("notify_readable"); + Intern_notify_writable = rb_intern ("notify_writable"); + Intern_proxy_target_unbound = rb_intern ("proxy_target_unbound"); + Intern_proxy_completed = rb_intern ("proxy_completed"); + Intern_connection_completed = rb_intern ("connection_completed"); + + // INCOMPLETE, we need to define class Connections inside module EventMachine + // run_machine and run_machine_without_threads are now identical. + // Must deprecate the without_threads variant. + EmModule = rb_define_module ("EventMachine"); + EmConnection = rb_define_class_under (EmModule, "Connection", rb_cObject); + + rb_define_class_under (EmModule, "NoHandlerForAcceptedConnection", rb_eRuntimeError); + EM_eConnectionError = rb_define_class_under (EmModule, "ConnectionError", rb_eRuntimeError); + EM_eConnectionNotBound = rb_define_class_under (EmModule, "ConnectionNotBound", rb_eRuntimeError); + EM_eUnknownTimerFired = rb_define_class_under (EmModule, "UnknownTimerFired", rb_eRuntimeError); + EM_eUnsupported = rb_define_class_under (EmModule, "Unsupported", rb_eRuntimeError); + EM_eInvalidSignature = rb_define_class_under (EmModule, "InvalidSignature", rb_eRuntimeError); + + rb_define_module_function (EmModule, "initialize_event_machine", (VALUE(*)(...))t_initialize_event_machine, 0); + rb_define_module_function (EmModule, "run_machine_once", (VALUE(*)(...))t_run_machine_once, 0); + rb_define_module_function (EmModule, "run_machine", (VALUE(*)(...))t_run_machine, 0); + rb_define_module_function (EmModule, "run_machine_without_threads", (VALUE(*)(...))t_run_machine, 0); + rb_define_module_function (EmModule, "add_oneshot_timer", (VALUE(*)(...))t_add_oneshot_timer, 1); + rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2); + rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1); + rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1); + rb_define_module_function (EmModule, "attach_sd", (VALUE(*)(...))t_attach_sd, 1); + rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 10); + rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1); + rb_define_module_function (EmModule, "get_peer_cert", (VALUE(*)(...))t_get_peer_cert, 1); + rb_define_module_function (EmModule, "get_cipher_bits", (VALUE(*)(...))t_get_cipher_bits, 1); + rb_define_module_function (EmModule, "get_cipher_name", (VALUE(*)(...))t_get_cipher_name, 1); + rb_define_module_function (EmModule, "get_cipher_protocol", (VALUE(*)(...))t_get_cipher_protocol, 1); + rb_define_module_function (EmModule, "get_sni_hostname", (VALUE(*)(...))t_get_sni_hostname, 1); + rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3); + rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5); + rb_define_module_function (EmModule, "close_connection", (VALUE(*)(...))t_close_connection, 2); + rb_define_module_function (EmModule, "report_connection_error_status", (VALUE(*)(...))t_report_connection_error_status, 1); + rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2); + rb_define_module_function (EmModule, "bind_connect_server", (VALUE(*)(...))t_bind_connect_server, 4); + rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1); + + rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2); + rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1); + rb_define_module_function (EmModule, "get_file_descriptor", (VALUE (*)(...))t_get_file_descriptor, 1); + rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3); + rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4); + rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2); + rb_define_module_function (EmModule, "set_notify_writable", (VALUE (*)(...))t_set_notify_writable, 2); + rb_define_module_function (EmModule, "is_notify_readable", (VALUE (*)(...))t_is_notify_readable, 1); + rb_define_module_function (EmModule, "is_notify_writable", (VALUE (*)(...))t_is_notify_writable, 1); + + rb_define_module_function (EmModule, "pause_connection", (VALUE (*)(...))t_pause, 1); + rb_define_module_function (EmModule, "resume_connection", (VALUE (*)(...))t_resume, 1); + rb_define_module_function (EmModule, "connection_paused?", (VALUE (*)(...))t_paused_p, 1); + rb_define_module_function (EmModule, "num_close_scheduled", (VALUE (*)(...))t_num_close_scheduled, 0); + + rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 4); + rb_define_module_function (EmModule, "stop_proxy", (VALUE (*)(...))t_stop_proxy, 1); + rb_define_module_function (EmModule, "get_proxied_bytes", (VALUE (*)(...))t_proxied_bytes, 1); + + rb_define_module_function (EmModule, "watch_filename", (VALUE (*)(...))t_watch_filename, 1); + rb_define_module_function (EmModule, "unwatch_filename", (VALUE (*)(...))t_unwatch_filename, 1); + + rb_define_module_function (EmModule, "watch_pid", (VALUE (*)(...))t_watch_pid, 1); + rb_define_module_function (EmModule, "unwatch_pid", (VALUE (*)(...))t_unwatch_pid, 1); + + rb_define_module_function (EmModule, "current_time", (VALUE(*)(...))t_get_loop_time, 0); + + rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2); + rb_define_module_function (EmModule, "read_keyboard", (VALUE(*)(...))t_read_keyboard, 0); + rb_define_module_function (EmModule, "release_machine", (VALUE(*)(...))t_release_machine, 0); + rb_define_module_function (EmModule, "stop", (VALUE(*)(...))t_stop, 0); + rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0); + rb_define_module_function (EmModule, "library_type", (VALUE(*)(...))t_library_type, 0); + rb_define_module_function (EmModule, "set_timer_quantum", (VALUE(*)(...))t_set_timer_quantum, 1); + rb_define_module_function (EmModule, "get_max_timer_count", (VALUE(*)(...))t_get_max_timer_count, 0); + rb_define_module_function (EmModule, "set_max_timer_count", (VALUE(*)(...))t_set_max_timer_count, 1); + rb_define_module_function (EmModule, "get_simultaneous_accept_count", (VALUE(*)(...))t_get_simultaneous_accept_count, 0); + rb_define_module_function (EmModule, "set_simultaneous_accept_count", (VALUE(*)(...))t_set_simultaneous_accept_count, 1); + rb_define_module_function (EmModule, "setuid_string", (VALUE(*)(...))t_setuid_string, 1); + rb_define_module_function (EmModule, "invoke_popen", (VALUE(*)(...))t_invoke_popen, 1); + rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2); + rb_define_module_function (EmModule, "get_heartbeat_interval", (VALUE(*)(...))t_get_heartbeat_interval, 0); + rb_define_module_function (EmModule, "set_heartbeat_interval", (VALUE(*)(...))t_set_heartbeat_interval, 1); + rb_define_module_function (EmModule, "get_idle_time", (VALUE(*)(...))t_get_idle_time, 1); + + rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1); + rb_define_module_function (EmModule, "get_sockname", (VALUE(*)(...))t_get_sockname, 1); + rb_define_module_function (EmModule, "get_subprocess_pid", (VALUE(*)(...))t_get_subprocess_pid, 1); + rb_define_module_function (EmModule, "get_subprocess_status", (VALUE(*)(...))t_get_subprocess_status, 1); + rb_define_module_function (EmModule, "get_comm_inactivity_timeout", (VALUE(*)(...))t_get_comm_inactivity_timeout, 1); + rb_define_module_function (EmModule, "set_comm_inactivity_timeout", (VALUE(*)(...))t_set_comm_inactivity_timeout, 2); + rb_define_module_function (EmModule, "get_pending_connect_timeout", (VALUE(*)(...))t_get_pending_connect_timeout, 1); + rb_define_module_function (EmModule, "set_pending_connect_timeout", (VALUE(*)(...))t_set_pending_connect_timeout, 2); + rb_define_module_function (EmModule, "set_rlimit_nofile", (VALUE(*)(...))t_set_rlimit_nofile, 1); + rb_define_module_function (EmModule, "get_connection_count", (VALUE(*)(...))t_get_connection_count, 0); + + rb_define_module_function (EmModule, "epoll", (VALUE(*)(...))t__epoll, 0); + rb_define_module_function (EmModule, "epoll=", (VALUE(*)(...))t__epoll_set, 1); + rb_define_module_function (EmModule, "epoll?", (VALUE(*)(...))t__epoll_p, 0); + + rb_define_module_function (EmModule, "kqueue", (VALUE(*)(...))t__kqueue, 0); + rb_define_module_function (EmModule, "kqueue=", (VALUE(*)(...))t__kqueue_set, 1); + rb_define_module_function (EmModule, "kqueue?", (VALUE(*)(...))t__kqueue_p, 0); + + rb_define_module_function (EmModule, "ssl?", (VALUE(*)(...))t__ssl_p, 0); + rb_define_module_function(EmModule, "stopping?",(VALUE(*)(...))t_stopping, 0); + + rb_define_method (EmConnection, "get_outbound_data_size", (VALUE(*)(...))conn_get_outbound_data_size, 0); + rb_define_method (EmConnection, "associate_callback_target", (VALUE(*)(...))conn_associate_callback_target, 1); + + // Connection states + rb_define_const (EmModule, "TimerFired", INT2NUM(EM_TIMER_FIRED )); + rb_define_const (EmModule, "ConnectionData", INT2NUM(EM_CONNECTION_READ )); + rb_define_const (EmModule, "ConnectionUnbound", INT2NUM(EM_CONNECTION_UNBOUND )); + rb_define_const (EmModule, "ConnectionAccepted", INT2NUM(EM_CONNECTION_ACCEPTED )); + rb_define_const (EmModule, "ConnectionCompleted", INT2NUM(EM_CONNECTION_COMPLETED )); + rb_define_const (EmModule, "LoopbreakSignalled", INT2NUM(EM_LOOPBREAK_SIGNAL )); + rb_define_const (EmModule, "ConnectionNotifyReadable", INT2NUM(EM_CONNECTION_NOTIFY_READABLE)); + rb_define_const (EmModule, "ConnectionNotifyWritable", INT2NUM(EM_CONNECTION_NOTIFY_WRITABLE)); + rb_define_const (EmModule, "SslHandshakeCompleted", INT2NUM(EM_SSL_HANDSHAKE_COMPLETED )); + rb_define_const (EmModule, "SslVerify", INT2NUM(EM_SSL_VERIFY )); + // EM_PROXY_TARGET_UNBOUND = 110, + // EM_PROXY_COMPLETED = 111 + + // SSL Protocols + rb_define_const (EmModule, "EM_PROTO_SSLv2", INT2NUM(EM_PROTO_SSLv2 )); + rb_define_const (EmModule, "EM_PROTO_SSLv3", INT2NUM(EM_PROTO_SSLv3 )); + rb_define_const (EmModule, "EM_PROTO_TLSv1", INT2NUM(EM_PROTO_TLSv1 )); + rb_define_const (EmModule, "EM_PROTO_TLSv1_1", INT2NUM(EM_PROTO_TLSv1_1)); + rb_define_const (EmModule, "EM_PROTO_TLSv1_2", INT2NUM(EM_PROTO_TLSv1_2)); +} + diff --git a/bin/gems/eventmachine-1.2.7/ext/ssl.cpp b/bin/gems/eventmachine-1.2.7/ext/ssl.cpp new file mode 100644 index 00000000..8d5e038a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/ssl.cpp @@ -0,0 +1,619 @@ +/***************************************************************************** + +$Id$ + +File: ssl.cpp +Date: 30Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#ifdef WITH_SSL + +#include "project.h" + + +bool SslContext_t::bLibraryInitialized = false; + + + +static void InitializeDefaultCredentials(); +static EVP_PKEY *DefaultPrivateKey = NULL; +static X509 *DefaultCertificate = NULL; + +static char PrivateMaterials[] = { +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV\n" +"Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/\n" +"AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQIDAQAB\n" +"AoGALA89gIFcr6BIBo8N5fL3aNHpZXjAICtGav+kTUpuxSiaym9cAeTHuAVv8Xgk\n" +"H2Wbq11uz+6JMLpkQJH/WZ7EV59DPOicXrp0Imr73F3EXBfR7t2EQDYHPMthOA1D\n" +"I9EtCzvV608Ze90hiJ7E3guGrGppZfJ+eUWCPgy8CZH1vRECQQDv67rwV/oU1aDo\n" +"6/+d5nqjeW6mWkGqTnUU96jXap8EIw6B+0cUKskwx6mHJv+tEMM2748ZY7b0yBlg\n" +"w4KDghbFAkEAz2h8PjSJG55LwqmXih1RONSgdN9hjB12LwXL1CaDh7/lkEhq0PlK\n" +"PCAUwQSdM17Sl0Xxm2CZiekTSlwmHrtqXQJAF3+8QJwtV2sRJp8u2zVe37IeH1cJ\n" +"xXeHyjTzqZ2803fnjN2iuZvzNr7noOA1/Kp+pFvUZUU5/0G2Ep8zolPUjQJAFA7k\n" +"xRdLkzIx3XeNQjwnmLlncyYPRv+qaE3FMpUu7zftuZBnVCJnvXzUxP3vPgKTlzGa\n" +"dg5XivDRfsV+okY5uQJBAMV4FesUuLQVEKb6lMs7rzZwpeGQhFDRfywJzfom2TLn\n" +"2RdJQQ3dcgnhdVDgt5o1qkmsqQh8uJrJ9SdyLIaZQIc=\n" +"-----END RSA PRIVATE KEY-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID6TCCA1KgAwIBAgIJANm4W/Tzs+s+MA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD\n" +"VQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYw\n" +"FAYDVQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsG\n" +"A1UEAxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2lu\n" +"ZWVyaW5nQHN0ZWFtaGVhdC5uZXQwHhcNMDYwNTA1MTcwNjAzWhcNMjQwMjIwMTcw\n" +"NjAzWjCBqjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQH\n" +"EwhOZXcgWW9yazEWMBQGA1UEChMNU3RlYW1oZWF0Lm5ldDEUMBIGA1UECxMLRW5n\n" +"aW5lZXJpbmcxHTAbBgNVBAMTFG9wZW5jYS5zdGVhbWhlYXQubmV0MSgwJgYJKoZI\n" +"hvcNAQkBFhllbmdpbmVlcmluZ0BzdGVhbWhlYXQubmV0MIGfMA0GCSqGSIb3DQEB\n" +"AQUAA4GNADCBiQKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxw\n" +"VDWVIgdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t3\n" +"9hJ/AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQID\n" +"AQABo4IBEzCCAQ8wHQYDVR0OBBYEFPJvPd1Fcmd8o/Tm88r+NjYPICCkMIHfBgNV\n" +"HSMEgdcwgdSAFPJvPd1Fcmd8o/Tm88r+NjYPICCkoYGwpIGtMIGqMQswCQYDVQQG\n" +"EwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYwFAYD\n" +"VQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsGA1UE\n" +"AxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2luZWVy\n" +"aW5nQHN0ZWFtaGVhdC5uZXSCCQDZuFv087PrPjAMBgNVHRMEBTADAQH/MA0GCSqG\n" +"SIb3DQEBBQUAA4GBAC1CXey/4UoLgJiwcEMDxOvW74plks23090iziFIlGgcIhk0\n" +"Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j\n" +"uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy\n" +"-----END CERTIFICATE-----\n"}; + +/* These private materials were made with: + * openssl req -new -x509 -keyout cakey.pem -out cacert.pem -nodes -days 6500 + * TODO: We need a full-blown capability to work with user-supplied + * keypairs and properly-signed certificates. + */ + + +/***************** +builtin_passwd_cb +*****************/ + +extern "C" int builtin_passwd_cb (char *buf UNUSED, int bufsize UNUSED, int rwflag UNUSED, void *userdata UNUSED) +{ + strcpy (buf, "kittycat"); + return 8; +} + +/**************************** +InitializeDefaultCredentials +****************************/ + +static void InitializeDefaultCredentials() +{ + BIO *bio = BIO_new_mem_buf (PrivateMaterials, -1); + assert (bio); + + if (DefaultPrivateKey) { + // we may come here in a restart. + EVP_PKEY_free (DefaultPrivateKey); + DefaultPrivateKey = NULL; + } + PEM_read_bio_PrivateKey (bio, &DefaultPrivateKey, builtin_passwd_cb, 0); + + if (DefaultCertificate) { + // we may come here in a restart. + X509_free (DefaultCertificate); + DefaultCertificate = NULL; + } + PEM_read_bio_X509 (bio, &DefaultCertificate, NULL, 0); + + BIO_free (bio); +} + + + +/************************** +SslContext_t::SslContext_t +**************************/ + +SslContext_t::SslContext_t (bool is_server, const std::string &privkeyfile, const std::string &certchainfile, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version) : + bIsServer (is_server), + pCtx (NULL), + PrivateKey (NULL), + Certificate (NULL) +{ + /* TODO: the usage of the specified private-key and cert-chain filenames only applies to + * client-side connections at this point. Server connections currently use the default materials. + * That needs to be fixed asap. + * Also, in this implementation, server-side connections use statically defined X-509 defaults. + * One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY + * objects when we call our destructor, or whether just calling SSL_CTX_free is enough. + */ + + if (!bLibraryInitialized) { + bLibraryInitialized = true; + SSL_library_init(); + OpenSSL_add_ssl_algorithms(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); + + InitializeDefaultCredentials(); + } + + pCtx = SSL_CTX_new (bIsServer ? SSLv23_server_method() : SSLv23_client_method()); + if (!pCtx) + throw std::runtime_error ("no SSL context"); + + SSL_CTX_set_options (pCtx, SSL_OP_ALL); + + #ifdef SSL_CTRL_CLEAR_OPTIONS + SSL_CTX_clear_options (pCtx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1); + # ifdef SSL_OP_NO_TLSv1_1 + SSL_CTX_clear_options (pCtx, SSL_OP_NO_TLSv1_1); + # endif + # ifdef SSL_OP_NO_TLSv1_2 + SSL_CTX_clear_options (pCtx, SSL_OP_NO_TLSv1_2); + # endif + #endif + + if (!(ssl_version & EM_PROTO_SSLv2)) + SSL_CTX_set_options (pCtx, SSL_OP_NO_SSLv2); + + if (!(ssl_version & EM_PROTO_SSLv3)) + SSL_CTX_set_options (pCtx, SSL_OP_NO_SSLv3); + + if (!(ssl_version & EM_PROTO_TLSv1)) + SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1); + + #ifdef SSL_OP_NO_TLSv1_1 + if (!(ssl_version & EM_PROTO_TLSv1_1)) + SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1_1); + #endif + + #ifdef SSL_OP_NO_TLSv1_2 + if (!(ssl_version & EM_PROTO_TLSv1_2)) + SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1_2); + #endif + + #ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS); + #endif + + if (bIsServer) { + + // The SSL_CTX calls here do NOT allocate memory. + int e; + if (privkeyfile.length() > 0) + e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); + else + e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey); + if (e <= 0) ERR_print_errors_fp(stderr); + assert (e > 0); + + if (certchainfile.length() > 0) + e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); + else + e = SSL_CTX_use_certificate (pCtx, DefaultCertificate); + if (e <= 0) ERR_print_errors_fp(stderr); + assert (e > 0); + + if (dhparam.length() > 0) { + DH *dh; + BIO *bio; + + bio = BIO_new_file(dhparam.c_str(), "r"); + if (bio == NULL) { + char buf [500]; + snprintf (buf, sizeof(buf)-1, "dhparam: BIO_new_file(%s) failed", dhparam.c_str()); + throw std::runtime_error (buf); + } + + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + + if (dh == NULL) { + BIO_free(bio); + char buf [500]; + snprintf (buf, sizeof(buf)-1, "dhparam: PEM_read_bio_DHparams(%s) failed", dhparam.c_str()); + throw std::runtime_error (buf); + } + + SSL_CTX_set_tmp_dh(pCtx, dh); + + DH_free(dh); + BIO_free(bio); + } + + if (ecdh_curve.length() > 0) { + #if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH) + int nid; + EC_KEY *ecdh; + + nid = OBJ_sn2nid((const char *) ecdh_curve.c_str()); + if (nid == 0) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "ecdh_curve: Unknown curve name: %s", ecdh_curve.c_str()); + throw std::runtime_error (buf); + } + + ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) { + char buf [200]; + snprintf (buf, sizeof(buf)-1, "ecdh_curve: Unable to create: %s", ecdh_curve.c_str()); + throw std::runtime_error (buf); + } + + SSL_CTX_set_options(pCtx, SSL_OP_SINGLE_ECDH_USE); + + SSL_CTX_set_tmp_ecdh(pCtx, ecdh); + + EC_KEY_free(ecdh); + #else + throw std::runtime_error ("No openssl ECDH support"); + #endif + } + } + + if (cipherlist.length() > 0) + SSL_CTX_set_cipher_list (pCtx, cipherlist.c_str()); + else + SSL_CTX_set_cipher_list (pCtx, "ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH"); + + if (bIsServer) { + SSL_CTX_sess_set_cache_size (pCtx, 128); + SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12); + } + else { + int e; + if (privkeyfile.length() > 0) { + e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); + if (e <= 0) ERR_print_errors_fp(stderr); + assert (e > 0); + } + if (certchainfile.length() > 0) { + e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); + if (e <= 0) ERR_print_errors_fp(stderr); + assert (e > 0); + } + } +} + + + +/*************************** +SslContext_t::~SslContext_t +***************************/ + +SslContext_t::~SslContext_t() +{ + if (pCtx) + SSL_CTX_free (pCtx); + if (PrivateKey) + EVP_PKEY_free (PrivateKey); + if (Certificate) + X509_free (Certificate); +} + + + +/****************** +SslBox_t::SslBox_t +******************/ + +SslBox_t::SslBox_t (bool is_server, const std::string &privkeyfile, const std::string &certchainfile, bool verify_peer, bool fail_if_no_peer_cert, const std::string &snihostname, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version, const uintptr_t binding): + bIsServer (is_server), + bHandshakeCompleted (false), + bVerifyPeer (verify_peer), + bFailIfNoPeerCert (fail_if_no_peer_cert), + pSSL (NULL), + pbioRead (NULL), + pbioWrite (NULL) +{ + /* TODO someday: make it possible to re-use SSL contexts so we don't have to create + * a new one every time we come here. + */ + + Context = new SslContext_t (bIsServer, privkeyfile, certchainfile, cipherlist, ecdh_curve, dhparam, ssl_version); + assert (Context); + + pbioRead = BIO_new (BIO_s_mem()); + assert (pbioRead); + + pbioWrite = BIO_new (BIO_s_mem()); + assert (pbioWrite); + + pSSL = SSL_new (Context->pCtx); + assert (pSSL); + + if (snihostname.length() > 0) { + SSL_set_tlsext_host_name (pSSL, snihostname.c_str()); + } + + SSL_set_bio (pSSL, pbioRead, pbioWrite); + + // Store a pointer to the binding signature in the SSL object so we can retrieve it later + SSL_set_ex_data(pSSL, 0, (void*) binding); + + if (bVerifyPeer) { + int mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; + if (bFailIfNoPeerCert) + mode = mode | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + SSL_set_verify(pSSL, mode, ssl_verify_wrapper); + } + + if (!bIsServer) { + int e = SSL_connect (pSSL); + if (e != 1) + ERR_print_errors_fp(stderr); + } +} + + + +/******************* +SslBox_t::~SslBox_t +*******************/ + +SslBox_t::~SslBox_t() +{ + // Freeing pSSL will also free the associated BIOs, so DON'T free them separately. + if (pSSL) { + if (SSL_get_shutdown (pSSL) & SSL_RECEIVED_SHUTDOWN) + SSL_shutdown (pSSL); + else + SSL_clear (pSSL); + SSL_free (pSSL); + } + + delete Context; +} + + + +/*********************** +SslBox_t::PutCiphertext +***********************/ + +bool SslBox_t::PutCiphertext (const char *buf, int bufsize) +{ + assert (buf && (bufsize > 0)); + + assert (pbioRead); + int n = BIO_write (pbioRead, buf, bufsize); + + return (n == bufsize) ? true : false; +} + + +/********************** +SslBox_t::GetPlaintext +**********************/ + +int SslBox_t::GetPlaintext (char *buf, int bufsize) +{ + if (!SSL_is_init_finished (pSSL)) { + int e = bIsServer ? SSL_accept (pSSL) : SSL_connect (pSSL); + if (e != 1) { + int er = SSL_get_error (pSSL, e); + if (er != SSL_ERROR_WANT_READ) { + ERR_print_errors_fp(stderr); + // Return -1 for a nonfatal error, -2 for an error that should force the connection down. + return (er == SSL_ERROR_SSL) ? (-2) : (-1); + } + else + return 0; + } + bHandshakeCompleted = true; + // If handshake finished, FALL THROUGH and return the available plaintext. + } + + if (!SSL_is_init_finished (pSSL)) { + // We can get here if a browser abandons a handshake. + // The user can see a warning dialog and abort the connection. + //cerr << ""; + return 0; + } + + //cerr << "CIPH: " << SSL_get_cipher (pSSL) << endl; + + int n = SSL_read (pSSL, buf, bufsize); + if (n >= 0) { + return n; + } + else { + if (SSL_get_error (pSSL, n) == SSL_ERROR_WANT_READ) { + return 0; + } + else { + return -1; + } + } + + return 0; +} + + + +/************************** +SslBox_t::CanGetCiphertext +**************************/ + +bool SslBox_t::CanGetCiphertext() +{ + assert (pbioWrite); + return BIO_pending (pbioWrite) ? true : false; +} + + + +/*********************** +SslBox_t::GetCiphertext +***********************/ + +int SslBox_t::GetCiphertext (char *buf, int bufsize) +{ + assert (pbioWrite); + assert (buf && (bufsize > 0)); + + return BIO_read (pbioWrite, buf, bufsize); +} + + + +/********************** +SslBox_t::PutPlaintext +**********************/ + +int SslBox_t::PutPlaintext (const char *buf, int bufsize) +{ + // The caller will interpret the return value as the number of bytes written. + // WARNING WARNING WARNING, are there any situations in which a 0 or -1 return + // from SSL_write means we should immediately retry? The socket-machine loop + // will probably wait for a time-out cycle (perhaps a second) before re-trying. + // THIS WOULD CAUSE A PERCEPTIBLE DELAY! + + /* We internally queue any outbound plaintext that can't be dispatched + * because we're in the middle of a handshake or something. + * When we get called, try to send any queued data first, and then + * send the caller's data (or queue it). We may get called with no outbound + * data, which means we try to send the outbound queue and that's all. + * + * Return >0 if we wrote any data, 0 if we didn't, and <0 for a fatal error. + * Note that if we return 0, the connection is still considered live + * and we are signalling that we have accepted the outbound data (if any). + */ + + OutboundQ.Push (buf, bufsize); + + if (!SSL_is_init_finished (pSSL)) + return 0; + + bool fatal = false; + bool did_work = false; + int pending = BIO_pending(pbioWrite); + + while (OutboundQ.HasPages() && pending < SSLBOX_WRITE_BUFFER_SIZE) { + const char *page; + int length; + OutboundQ.Front (&page, &length); + assert (page && (length > 0)); + int n = SSL_write (pSSL, page, length); + pending = BIO_pending(pbioWrite); + + if (n > 0) { + did_work = true; + OutboundQ.PopFront(); + } + else { + int er = SSL_get_error (pSSL, n); + if ((er != SSL_ERROR_WANT_READ) && (er != SSL_ERROR_WANT_WRITE)) + fatal = true; + break; + } + } + + + if (did_work) + return 1; + else if (fatal) + return -1; + else + return 0; +} + +/********************** +SslBox_t::GetPeerCert +**********************/ + +X509 *SslBox_t::GetPeerCert() +{ + X509 *cert = NULL; + + if (pSSL) + cert = SSL_get_peer_certificate(pSSL); + + return cert; +} + +/********************** +SslBox_t::GetCipherBits +**********************/ + +int SslBox_t::GetCipherBits() +{ + int bits = -1; + if (pSSL) + SSL_get_cipher_bits(pSSL, &bits); + return bits; +} + +/********************** +SslBox_t::GetCipherName +**********************/ + +const char *SslBox_t::GetCipherName() +{ + if (pSSL) + return SSL_get_cipher_name(pSSL); + return NULL; +} + +/********************** +SslBox_t::GetCipherProtocol +**********************/ + +const char *SslBox_t::GetCipherProtocol() +{ + if (pSSL) + return SSL_get_cipher_version(pSSL); + return NULL; +} + +/********************** +SslBox_t::GetSNIHostname +**********************/ + +const char *SslBox_t::GetSNIHostname() +{ + #ifdef TLSEXT_NAMETYPE_host_name + if (pSSL) + return SSL_get_servername (pSSL, TLSEXT_NAMETYPE_host_name); + #endif + return NULL; +} + +/****************** +ssl_verify_wrapper +*******************/ + +extern "C" int ssl_verify_wrapper(int preverify_ok UNUSED, X509_STORE_CTX *ctx) +{ + uintptr_t binding; + X509 *cert; + SSL *ssl; + BUF_MEM *buf; + BIO *out; + int result; + + cert = X509_STORE_CTX_get_current_cert(ctx); + ssl = (SSL*) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + binding = (uintptr_t) SSL_get_ex_data(ssl, 0); + + out = BIO_new(BIO_s_mem()); + PEM_write_bio_X509(out, cert); + BIO_write(out, "\0", 1); + BIO_get_mem_ptr(out, &buf); + + ConnectionDescriptor *cd = dynamic_cast (Bindable_t::GetObject(binding)); + result = (cd->VerifySslPeer(buf->data) == true ? 1 : 0); + BIO_free(out); + + return result; +} + +#endif // WITH_SSL + diff --git a/bin/gems/eventmachine-1.2.7/ext/ssl.h b/bin/gems/eventmachine-1.2.7/ext/ssl.h new file mode 100644 index 00000000..64ff6e18 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/ext/ssl.h @@ -0,0 +1,103 @@ +/***************************************************************************** + +$Id$ + +File: ssl.h +Date: 30Apr06 + +Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +Gmail: blackhedd + +This program is free software; you can redistribute it and/or modify +it under the terms of either: 1) the GNU General Public License +as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version; or 2) Ruby's License. + +See the file COPYING for complete licensing information. + +*****************************************************************************/ + + +#ifndef __SslBox__H_ +#define __SslBox__H_ + + + + +#ifdef WITH_SSL + +/****************** +class SslContext_t +******************/ + +class SslContext_t +{ + public: + SslContext_t (bool is_server, const std::string &privkeyfile, const std::string &certchainfile, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version); + virtual ~SslContext_t(); + + private: + static bool bLibraryInitialized; + + private: + bool bIsServer; + SSL_CTX *pCtx; + + EVP_PKEY *PrivateKey; + X509 *Certificate; + + friend class SslBox_t; +}; + + +/************** +class SslBox_t +**************/ + +#define SSLBOX_INPUT_CHUNKSIZE 2019 +#define SSLBOX_OUTPUT_CHUNKSIZE 2048 +#define SSLBOX_WRITE_BUFFER_SIZE 8192 // (SSLBOX_OUTPUT_CHUNKSIZE * 4) + +class SslBox_t +{ + public: + SslBox_t (bool is_server, const std::string &privkeyfile, const std::string &certchainfile, bool verify_peer, bool fail_if_no_peer_cert, const std::string &snihostname, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version, const uintptr_t binding); + virtual ~SslBox_t(); + + int PutPlaintext (const char*, int); + int GetPlaintext (char*, int); + + bool PutCiphertext (const char*, int); + bool CanGetCiphertext(); + int GetCiphertext (char*, int); + bool IsHandshakeCompleted() {return bHandshakeCompleted;} + + X509 *GetPeerCert(); + int GetCipherBits(); + const char *GetCipherName(); + const char *GetCipherProtocol(); + const char *GetSNIHostname(); + + void Shutdown(); + + protected: + SslContext_t *Context; + + bool bIsServer; + bool bHandshakeCompleted; + bool bVerifyPeer; + bool bFailIfNoPeerCert; + SSL *pSSL; + BIO *pbioRead; + BIO *pbioWrite; + + PageList OutboundQ; +}; + +extern "C" int ssl_verify_wrapper(int, X509_STORE_CTX*); + +#endif // WITH_SSL + + +#endif // __SslBox__H_ + diff --git a/bin/gems/eventmachine-1.2.7/java/.classpath b/bin/gems/eventmachine-1.2.7/java/.classpath new file mode 100644 index 00000000..11672ddd --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/bin/gems/eventmachine-1.2.7/java/.project b/bin/gems/eventmachine-1.2.7/java/.project new file mode 100644 index 00000000..c7766db5 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/.project @@ -0,0 +1,17 @@ + + + em_reactor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactor.java b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactor.java new file mode 100644 index 00000000..31642f3f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactor.java @@ -0,0 +1,613 @@ +/** + * $Id$ + * + * Author:: Francis Cianfrocca (gmail: blackhedd) + * Homepage:: http://rubyeventmachine.com + * Date:: 15 Jul 2007 + * + * See EventMachine and EventMachine::Connection for documentation and + * usage examples. + * + * + *---------------------------------------------------------------------------- + * + * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + * Gmail: blackhedd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of either: 1) the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version; or 2) Ruby's License. + * + * See the file COPYING for complete licensing information. + * + *--------------------------------------------------------------------------- + * + * + */ + +package com.rubyeventmachine; + +import java.io.*; +import java.nio.channels.*; +import java.util.*; +import java.nio.*; +import java.net.*; +import java.util.concurrent.atomic.*; +import java.security.*; + +public class EmReactor { + public final int EM_TIMER_FIRED = 100; + public final int EM_CONNECTION_READ = 101; + public final int EM_CONNECTION_UNBOUND = 102; + public final int EM_CONNECTION_ACCEPTED = 103; + public final int EM_CONNECTION_COMPLETED = 104; + public final int EM_LOOPBREAK_SIGNAL = 105; + public final int EM_CONNECTION_NOTIFY_READABLE = 106; + public final int EM_CONNECTION_NOTIFY_WRITABLE = 107; + public final int EM_SSL_HANDSHAKE_COMPLETED = 108; + public final int EM_SSL_VERIFY = 109; + public final int EM_PROXY_TARGET_UNBOUND = 110; + public final int EM_PROXY_COMPLETED = 111; + + public final int EM_PROTO_SSLv2 = 2; + public final int EM_PROTO_SSLv3 = 4; + public final int EM_PROTO_TLSv1 = 8; + public final int EM_PROTO_TLSv1_1 = 16; + public final int EM_PROTO_TLSv1_2 = 32; + + private Selector mySelector; + private TreeMap> Timers; + private HashMap Connections; + private HashMap Acceptors; + private ArrayList NewConnections; + private ArrayList UnboundConnections; + private ArrayList DetachedConnections; + + private boolean bRunReactor; + private long BindingIndex; + private AtomicBoolean loopBreaker; + private ByteBuffer myReadBuffer; + private int timerQuantum; + + public EmReactor() { + Timers = new TreeMap>(); + Connections = new HashMap(); + Acceptors = new HashMap(); + NewConnections = new ArrayList(); + UnboundConnections = new ArrayList(); + DetachedConnections = new ArrayList(); + + BindingIndex = 0; + loopBreaker = new AtomicBoolean(); + loopBreaker.set(false); + myReadBuffer = ByteBuffer.allocate(32*1024); // don't use a direct buffer. Ruby doesn't seem to like them. + timerQuantum = 98; + } + + /** + * This is a no-op stub, intended to be overridden in user code. + */ + public void eventCallback (long sig, int eventType, ByteBuffer data, long data2) { + System.out.println ("Default callback: "+sig+" "+eventType+" "+data+" "+data2); + } + public void eventCallback (long sig, int eventType, ByteBuffer data) { + eventCallback (sig, eventType, data, 0); + } + + + public void run() { + try { + mySelector = Selector.open(); + bRunReactor = true; + } catch (IOException e) { + throw new RuntimeException ("Could not open selector", e); + } + + while (bRunReactor) { + runLoopbreaks(); + if (!bRunReactor) break; + + runTimers(); + if (!bRunReactor) break; + + removeUnboundConnections(); + checkIO(); + addNewConnections(); + processIO(); + } + + close(); + } + + void addNewConnections() { + ListIterator iter = DetachedConnections.listIterator(0); + while (iter.hasNext()) { + EventableSocketChannel ec = iter.next(); + ec.cleanup(); + } + DetachedConnections.clear(); + + ListIterator iter2 = NewConnections.listIterator(0); + while (iter2.hasNext()) { + long b = iter2.next(); + + EventableChannel ec = Connections.get(b); + if (ec != null) { + try { + ec.register(); + } catch (ClosedChannelException e) { + UnboundConnections.add (ec.getBinding()); + } + } + } + NewConnections.clear(); + } + + void removeUnboundConnections() { + ListIterator iter = UnboundConnections.listIterator(0); + while (iter.hasNext()) { + long b = iter.next(); + + EventableChannel ec = Connections.remove(b); + if (ec != null) { + eventCallback (b, EM_CONNECTION_UNBOUND, null); + ec.close(); + + EventableSocketChannel sc = (EventableSocketChannel) ec; + if (sc != null && sc.isAttached()) + DetachedConnections.add (sc); + } + } + UnboundConnections.clear(); + } + + void checkIO() { + long timeout; + + if (NewConnections.size() > 0) { + timeout = -1; + } else if (!Timers.isEmpty()) { + long now = new Date().getTime(); + long k = Timers.firstKey(); + long diff = k-now; + + if (diff <= 0) + timeout = -1; // don't wait, just poll once + else + timeout = diff; + } else { + timeout = 0; // wait indefinitely + } + + try { + if (timeout == -1) + mySelector.selectNow(); + else + mySelector.select(timeout); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void processIO() { + Iterator it = mySelector.selectedKeys().iterator(); + while (it.hasNext()) { + SelectionKey k = it.next(); + it.remove(); + + if (k.isConnectable()) + isConnectable(k); + + else if (k.isAcceptable()) + isAcceptable(k); + + else { + if (k.isWritable()) + isWritable(k); + + if (k.isReadable()) + isReadable(k); + } + } + } + + void isAcceptable (SelectionKey k) { + ServerSocketChannel ss = (ServerSocketChannel) k.channel(); + SocketChannel sn; + long b; + + for (int n = 0; n < 10; n++) { + try { + sn = ss.accept(); + if (sn == null) + break; + } catch (IOException e) { + e.printStackTrace(); + k.cancel(); + + ServerSocketChannel server = Acceptors.remove(k.attachment()); + if (server != null) + try{ server.close(); } catch (IOException ex) {}; + break; + } + + try { + sn.configureBlocking(false); + } catch (IOException e) { + e.printStackTrace(); + continue; + } + + b = createBinding(); + EventableSocketChannel ec = new EventableSocketChannel (sn, b, mySelector); + Connections.put (b, ec); + NewConnections.add (b); + + eventCallback (((Long)k.attachment()).longValue(), EM_CONNECTION_ACCEPTED, null, b); + } + } + + void isReadable (SelectionKey k) { + EventableChannel ec = (EventableChannel) k.attachment(); + long b = ec.getBinding(); + + if (ec.isWatchOnly()) { + if (ec.isNotifyReadable()) + eventCallback (b, EM_CONNECTION_NOTIFY_READABLE, null); + } else { + myReadBuffer.clear(); + + try { + ec.readInboundData (myReadBuffer); + myReadBuffer.flip(); + if (myReadBuffer.limit() > 0) + eventCallback (b, EM_CONNECTION_READ, myReadBuffer); + } catch (IOException e) { + UnboundConnections.add (b); + } + } + } + + void isWritable (SelectionKey k) { + EventableChannel ec = (EventableChannel) k.attachment(); + long b = ec.getBinding(); + + if (ec.isWatchOnly()) { + if (ec.isNotifyWritable()) + eventCallback (b, EM_CONNECTION_NOTIFY_WRITABLE, null); + } + else { + try { + if (!ec.writeOutboundData()) + UnboundConnections.add (b); + } catch (IOException e) { + UnboundConnections.add (b); + } + } + } + + void isConnectable (SelectionKey k) { + EventableSocketChannel ec = (EventableSocketChannel) k.attachment(); + long b = ec.getBinding(); + + try { + if (ec.finishConnecting()) + eventCallback (b, EM_CONNECTION_COMPLETED, null); + else + UnboundConnections.add (b); + } catch (IOException e) { + UnboundConnections.add (b); + } + } + + void close() { + try { + if (mySelector != null) + mySelector.close(); + } catch (IOException e) {} + mySelector = null; + + // run down open connections and sockets. + Iterator i = Acceptors.values().iterator(); + while (i.hasNext()) { + try { + i.next().close(); + } catch (IOException e) {} + } + + // 29Sep09: We create an ArrayList of the existing connections, then iterate over + // that to call unbind on them. This is because an unbind can trigger a reconnect, + // which will add to the Connections HashMap, causing a ConcurrentModificationException. + // XXX: The correct behavior here would be to latch the various reactor methods to return + // immediately if the reactor is shutting down. + ArrayList conns = new ArrayList(); + Iterator i2 = Connections.values().iterator(); + while (i2.hasNext()) { + EventableChannel ec = i2.next(); + if (ec != null) { + conns.add (ec); + } + } + Connections.clear(); + + ListIterator i3 = conns.listIterator(0); + while (i3.hasNext()) { + EventableChannel ec = i3.next(); + eventCallback (ec.getBinding(), EM_CONNECTION_UNBOUND, null); + ec.close(); + + EventableSocketChannel sc = (EventableSocketChannel) ec; + if (sc != null && sc.isAttached()) + DetachedConnections.add (sc); + } + + ListIterator i4 = DetachedConnections.listIterator(0); + while (i4.hasNext()) { + EventableSocketChannel ec = i4.next(); + ec.cleanup(); + } + DetachedConnections.clear(); + } + + void runLoopbreaks() { + if (loopBreaker.getAndSet(false)) { + eventCallback (0, EM_LOOPBREAK_SIGNAL, null); + } + } + + public void stop() { + bRunReactor = false; + signalLoopbreak(); + } + + void runTimers() { + long now = new Date().getTime(); + while (!Timers.isEmpty()) { + long k = Timers.firstKey(); + if (k > now) + break; + + ArrayList callbacks = Timers.get(k); + Timers.remove(k); + + // Fire all timers at this timestamp + ListIterator iter = callbacks.listIterator(0); + while (iter.hasNext()) { + eventCallback (0, EM_TIMER_FIRED, null, iter.next().longValue()); + } + } + } + + public long installOneshotTimer (long milliseconds) { + long s = createBinding(); + long deadline = new Date().getTime() + milliseconds; + + if (Timers.containsKey(deadline)) { + Timers.get(deadline).add(s); + } else { + ArrayList callbacks = new ArrayList(); + callbacks.add(s); + Timers.put(deadline, callbacks); + } + + return s; + } + + public long startTcpServer (SocketAddress sa) throws EmReactorException { + try { + ServerSocketChannel server = ServerSocketChannel.open(); + server.configureBlocking(false); + server.socket().bind (sa); + long s = createBinding(); + Acceptors.put(s, server); + server.register(mySelector, SelectionKey.OP_ACCEPT, s); + return s; + } catch (IOException e) { + throw new EmReactorException ("unable to open socket acceptor: " + e.toString()); + } + } + + public long startTcpServer (String address, int port) throws EmReactorException { + return startTcpServer (new InetSocketAddress (address, port)); + } + + public void stopTcpServer (long signature) throws IOException { + ServerSocketChannel server = Acceptors.remove(signature); + if (server != null) + server.close(); + else + throw new RuntimeException ("failed to close unknown acceptor"); + } + + public long openUdpSocket (InetSocketAddress address) throws IOException { + // TODO, don't throw an exception out of here. + DatagramChannel dg = DatagramChannel.open(); + dg.configureBlocking(false); + dg.socket().bind(address); + long b = createBinding(); + EventableChannel ec = new EventableDatagramChannel (dg, b, mySelector); + dg.register(mySelector, SelectionKey.OP_READ, ec); + Connections.put(b, ec); + return b; + } + + public long openUdpSocket (String address, int port) throws IOException { + return openUdpSocket (new InetSocketAddress (address, port)); + } + + public void sendData (long sig, ByteBuffer bb) throws IOException { + Connections.get(sig).scheduleOutboundData( bb ); + } + + public void sendData (long sig, byte[] data) throws IOException { + sendData (sig, ByteBuffer.wrap(data)); + } + + public void setCommInactivityTimeout (long sig, long mills) { + Connections.get(sig).setCommInactivityTimeout (mills); + } + + public void sendDatagram (long sig, byte[] data, int length, String recipAddress, int recipPort) { + sendDatagram (sig, ByteBuffer.wrap(data), recipAddress, recipPort); + } + + public void sendDatagram (long sig, ByteBuffer bb, String recipAddress, int recipPort) { + (Connections.get(sig)).scheduleOutboundDatagram( bb, recipAddress, recipPort); + } + + public long connectTcpServer (String address, int port) { + return connectTcpServer(null, 0, address, port); + } + + public long connectTcpServer (String bindAddr, int bindPort, String address, int port) { + long b = createBinding(); + + try { + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + if (bindAddr != null) + sc.socket().bind(new InetSocketAddress (bindAddr, bindPort)); + + EventableSocketChannel ec = new EventableSocketChannel (sc, b, mySelector); + + if (sc.connect (new InetSocketAddress (address, port))) { + // Connection returned immediately. Can happen with localhost connections. + // WARNING, this code is untested due to lack of available test conditions. + // Ought to be be able to come here from a localhost connection, but that + // doesn't happen on Linux. (Maybe on FreeBSD?) + // The reason for not handling this until we can test it is that we + // really need to return from this function WITHOUT triggering any EM events. + // That's because until the user code has seen the signature we generated here, + // it won't be able to properly dispatch them. The C++ EM deals with this + // by setting pending mode as a flag in ALL eventable descriptors and making + // the descriptor select for writable. Then, it can send UNBOUND and + // CONNECTION_COMPLETED on the next pass through the loop, because writable will + // fire. + throw new RuntimeException ("immediate-connect unimplemented"); + } + else { + ec.setConnectPending(); + Connections.put (b, ec); + NewConnections.add (b); + } + } catch (IOException e) { + // Can theoretically come here if a connect failure can be determined immediately. + // I don't know how to make that happen for testing purposes. + throw new RuntimeException ("immediate-connect unimplemented: " + e.toString()); + } + return b; + } + + public void closeConnection (long sig, boolean afterWriting) { + EventableChannel ec = Connections.get(sig); + if (ec != null) + if (ec.scheduleClose (afterWriting)) + UnboundConnections.add (sig); + } + + long createBinding() { + return ++BindingIndex; + } + + public void signalLoopbreak() { + loopBreaker.set(true); + if (mySelector != null) + mySelector.wakeup(); + } + + public void startTls (long sig) throws NoSuchAlgorithmException, KeyManagementException { + Connections.get(sig).startTls(); + } + + public void setTimerQuantum (int mills) { + if (mills < 5 || mills > 2500) + throw new RuntimeException ("attempt to set invalid timer-quantum value: "+mills); + timerQuantum = mills; + } + + public Object[] getPeerName (long sig) { + EventableChannel channel = Connections.get(sig); + if (channel != null) { + return Connections.get(sig).getPeerName(); + } + else { + ServerSocketChannel acceptor = Acceptors.get(sig); + return new Object[] { acceptor.socket().getLocalPort(), + acceptor.socket().getInetAddress().getHostAddress() }; + } + } + + public Object[] getSockName (long sig) { + EventableChannel channel = Connections.get(sig); + if (channel != null) { + return Connections.get(sig).getSockName(); + } + else { + ServerSocketChannel acceptor = Acceptors.get(sig); + return new Object[] { acceptor.socket().getLocalPort(), + acceptor.socket().getInetAddress().getHostAddress() }; + } + } + + public long attachChannel (SocketChannel sc, boolean watch_mode) { + long b = createBinding(); + + EventableSocketChannel ec = new EventableSocketChannel (sc, b, mySelector); + + ec.setAttached(); + if (watch_mode) + ec.setWatchOnly(); + + Connections.put (b, ec); + NewConnections.add (b); + + return b; + } + + public SocketChannel detachChannel (long sig) { + EventableSocketChannel ec = (EventableSocketChannel) Connections.get (sig); + if (ec != null) { + UnboundConnections.add (sig); + return ec.getChannel(); + } else { + return null; + } + } + + public void setNotifyReadable (long sig, boolean mode) { + ((EventableSocketChannel) Connections.get(sig)).setNotifyReadable(mode); + } + + public void setNotifyWritable (long sig, boolean mode) { + ((EventableSocketChannel) Connections.get(sig)).setNotifyWritable(mode); + } + + public boolean isNotifyReadable (long sig) { + return Connections.get(sig).isNotifyReadable(); + } + + public boolean isNotifyWritable (long sig) { + return Connections.get(sig).isNotifyWritable(); + } + + public boolean pauseConnection (long sig) { + return ((EventableSocketChannel) Connections.get(sig)).pause(); + } + + public boolean resumeConnection (long sig) { + return ((EventableSocketChannel) Connections.get(sig)).resume(); + } + + public boolean isConnectionPaused (long sig) { + return ((EventableSocketChannel) Connections.get(sig)).isPaused(); + } + + public long getOutboundDataSize (long sig) { + return Connections.get(sig).getOutboundDataSize(); + } + + public int getConnectionCount() { + return Connections.size() + Acceptors.size(); + } +} diff --git a/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactorException.java b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactorException.java new file mode 100644 index 00000000..69efaa3a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EmReactorException.java @@ -0,0 +1,40 @@ +/** + * $Id$ + * + * Author:: Francis Cianfrocca (gmail: blackhedd) + * Homepage:: http://rubyeventmachine.com + * Date:: 15 Jul 2007 + * + * See EventMachine and EventMachine::Connection for documentation and + * usage examples. + * + * + *---------------------------------------------------------------------------- + * + * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + * Gmail: blackhedd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of either: 1) the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version; or 2) Ruby's License. + * + * See the file COPYING for complete licensing information. + * + *--------------------------------------------------------------------------- + * + * + */ + +package com.rubyeventmachine; + +/** + * @author francis + * + */ +public class EmReactorException extends Exception { + static final long serialVersionUID = 0; + public EmReactorException (String msg) { + super (msg); + } +} diff --git a/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableChannel.java b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableChannel.java new file mode 100644 index 00000000..3d4f5fd0 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableChannel.java @@ -0,0 +1,72 @@ +/** + * $Id$ + * + * Author:: Francis Cianfrocca (gmail: blackhedd) + * Homepage:: http://rubyeventmachine.com + * Date:: 15 Jul 2007 + * + * See EventMachine and EventMachine::Connection for documentation and + * usage examples. + * + * + *---------------------------------------------------------------------------- + * + * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + * Gmail: blackhedd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of either: 1) the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version; or 2) Ruby's License. + * + * See the file COPYING for complete licensing information. + * + *--------------------------------------------------------------------------- + * + * + */ + + +package com.rubyeventmachine; + +import java.nio.ByteBuffer; +import java.io.IOException; +import java.nio.channels.ClosedChannelException; + +public interface EventableChannel { + + public void scheduleOutboundData (ByteBuffer bb); + + public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort); + + public boolean scheduleClose (boolean afterWriting); + + public void startTls(); + + public long getBinding(); + + public void readInboundData (ByteBuffer dst) throws IOException; + + public void register() throws ClosedChannelException; + + /** + * This is called by the reactor after it finishes running. + * The idea is to free network resources. + */ + public void close(); + + public boolean writeOutboundData() throws IOException; + + public long getOutboundDataSize(); + + public void setCommInactivityTimeout (long seconds); + + public Object[] getPeerName(); + public Object[] getSockName(); + + public boolean isWatchOnly(); + + public boolean isNotifyReadable(); + public boolean isNotifyWritable(); + +} diff --git a/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableDatagramChannel.java b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableDatagramChannel.java new file mode 100644 index 00000000..df1c9fd2 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableDatagramChannel.java @@ -0,0 +1,201 @@ +/** + * $Id$ + * + * Author:: Francis Cianfrocca (gmail: blackhedd) + * Homepage:: http://rubyeventmachine.com + * Date:: 15 Jul 2007 + * + * See EventMachine and EventMachine::Connection for documentation and + * usage examples. + * + * + *---------------------------------------------------------------------------- + * + * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + * Gmail: blackhedd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of either: 1) the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version; or 2) Ruby's License. + * + * See the file COPYING for complete licensing information. + * + *--------------------------------------------------------------------------- + * + * + */ + + +package com.rubyeventmachine; + +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.DatagramChannel; +import java.util.LinkedList; +import java.io.*; +import java.net.*; + +public class EventableDatagramChannel implements EventableChannel { + + class Packet { + public ByteBuffer bb; + public SocketAddress recipient; + public Packet (ByteBuffer _bb, SocketAddress _recipient) { + bb = _bb; + recipient = _recipient; + } + } + + DatagramChannel channel; + long binding; + Selector selector; + boolean bCloseScheduled; + LinkedList outboundQ; + long outboundS; + SocketAddress returnAddress; + + + public EventableDatagramChannel (DatagramChannel dc, long _binding, Selector sel) throws ClosedChannelException { + channel = dc; + binding = _binding; + selector = sel; + bCloseScheduled = false; + outboundQ = new LinkedList(); + outboundS = 0; + + dc.register(selector, SelectionKey.OP_READ, this); + } + + public void scheduleOutboundData (ByteBuffer bb) { + try { + if ((!bCloseScheduled) && (bb.remaining() > 0)) { + outboundQ.addLast(new Packet(bb, returnAddress)); + outboundS += bb.remaining(); + channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this); + } + } catch (ClosedChannelException e) { + throw new RuntimeException ("no outbound data"); + } + } + + public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort) { + try { + if ((!bCloseScheduled) && (bb.remaining() > 0)) { + outboundQ.addLast(new Packet (bb, new InetSocketAddress (recipAddress, recipPort))); + outboundS += bb.remaining(); + channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this); + } + } catch (ClosedChannelException e) { + throw new RuntimeException ("no outbound data"); + } + } + + public boolean scheduleClose (boolean afterWriting) { + System.out.println ("NOT SCHEDULING CLOSE ON DATAGRAM"); + return false; + } + + public void startTls() { + throw new RuntimeException ("TLS is unimplemented on this Channel"); + } + + public long getBinding() { + return binding; + } + + public void register() throws ClosedChannelException { + // TODO + } + + /** + * Terminate with extreme prejudice. Don't assume there will be another pass through + * the reactor core. + */ + public void close() { + try { + channel.close(); + } catch (IOException e) { + } + } + + public void readInboundData (ByteBuffer dst) { + returnAddress = null; + try { + // If there is no datagram available (we're nonblocking after all), + // then channel.receive returns null. + returnAddress = channel.receive(dst); + } catch (IOException e) { + // probably a no-op. The caller will see the empty (or even partial) buffer + // and presumably do the right thing. + } + } + + public boolean writeOutboundData() { + while (!outboundQ.isEmpty()) { + Packet p = outboundQ.getFirst(); + int written = 0; + try { + // With a datagram socket, it's ok to send an empty buffer. + written = channel.send(p.bb, p.recipient); + outboundS -= written; + } + catch (IOException e) { + return false; + } + + /* Did we consume the whole outbound buffer? If yes, pop it off and + * keep looping. If no, the outbound network buffers are full, so break + * out of here. There's a flaw that affects outbound buffers that are intentionally + * empty. We can tell whether they got sent or not. So we assume they were. + * TODO: As implemented, this ALWAYS discards packets if they were at least + * partially written. This matches the behavior of the C++ EM. My judgment + * is that this is less surprising than fragmenting the data and sending multiple + * packets would be. I could be wrong, so this is subject to change. + */ + + if ((written > 0) || (p.bb.remaining() == 0)) + outboundQ.removeFirst(); + else + break; + } + + if (outboundQ.isEmpty()) { + try { + channel.register(selector, SelectionKey.OP_READ, this); + } catch (ClosedChannelException e) {} + } + + // ALWAYS drain the outbound queue before triggering a connection close. + // If anyone wants to close immediately, they're responsible for clearing + // the outbound queue. + return (bCloseScheduled && outboundQ.isEmpty()) ? false : true; + } + + public void setCommInactivityTimeout (long seconds) { + // TODO + System.out.println ("DATAGRAM: SET COMM INACTIVITY UNIMPLEMENTED " + seconds); + } + + public Object[] getPeerName () { + if (returnAddress != null) { + InetSocketAddress inetAddr = (InetSocketAddress) returnAddress; + return new Object[]{ inetAddr.getPort(), inetAddr.getHostName() }; + } else { + return null; + } + } + + public Object[] getSockName () { + DatagramSocket socket = channel.socket(); + return new Object[]{ socket.getLocalPort(), + socket.getLocalAddress().getHostAddress() }; + } + + public boolean isWatchOnly() { return false; } + public boolean isNotifyReadable() { return false; } + public boolean isNotifyWritable() { return false; } + public long getOutboundDataSize() { return outboundS; } +} diff --git a/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableSocketChannel.java b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableSocketChannel.java new file mode 100644 index 00000000..2905ec6c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/java/src/com/rubyeventmachine/EventableSocketChannel.java @@ -0,0 +1,415 @@ +/** + * $Id$ + * + * Author:: Francis Cianfrocca (gmail: blackhedd) + * Homepage:: http://rubyeventmachine.com + * Date:: 15 Jul 2007 + * + * See EventMachine and EventMachine::Connection for documentation and + * usage examples. + * + * + *---------------------------------------------------------------------------- + * + * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. + * Gmail: blackhedd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of either: 1) the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version; or 2) Ruby's License. + * + * See the file COPYING for complete licensing information. + * + *--------------------------------------------------------------------------- + * + * + */ + +/** + * + */ +package com.rubyeventmachine; + +/** + * @author francis + * + */ + +import java.nio.channels.*; +import java.nio.*; +import java.util.*; +import java.io.*; +import java.net.Socket; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; +import java.lang.reflect.Field; + +import java.security.*; + +public class EventableSocketChannel implements EventableChannel { + Selector selector; + SelectionKey channelKey; + SocketChannel channel; + + long binding; + LinkedList outboundQ; + long outboundS; + + boolean bCloseScheduled; + boolean bConnectPending; + boolean bWatchOnly; + boolean bAttached; + boolean bNotifyReadable; + boolean bNotifyWritable; + boolean bPaused; + + SSLEngine sslEngine; + SSLContext sslContext; + + public EventableSocketChannel (SocketChannel sc, long _binding, Selector sel) { + channel = sc; + binding = _binding; + selector = sel; + bCloseScheduled = false; + bConnectPending = false; + bWatchOnly = false; + bAttached = false; + bNotifyReadable = false; + bNotifyWritable = false; + outboundQ = new LinkedList(); + outboundS = 0; + } + + public long getBinding() { + return binding; + } + + public SocketChannel getChannel() { + return channel; + } + + public void register() throws ClosedChannelException { + if (channelKey == null) { + int events = currentEvents(); + channelKey = channel.register(selector, events, this); + } + } + + /** + * Terminate with extreme prejudice. Don't assume there will be another pass through + * the reactor core. + */ + public void close() { + if (channelKey != null) { + channelKey.cancel(); + channelKey = null; + } + + if (bAttached) { + // attached channels are copies, so reset the file descriptor to prevent java from close()ing it + Field f; + FileDescriptor fd; + + try { + /* do _NOT_ clobber fdVal here, it will break epoll/kqueue on jdk6! + * channelKey.cancel() above does not occur until the next call to select + * and if fdVal is gone, we will continue to get events for this fd. + * + * instead, remove fdVal in cleanup(), which is processed via DetachedConnections, + * after UnboundConnections but before NewConnections. + */ + + f = channel.getClass().getDeclaredField("fd"); + f.setAccessible(true); + fd = (FileDescriptor) f.get(channel); + + f = fd.getClass().getDeclaredField("fd"); + f.setAccessible(true); + f.set(fd, -1); + } catch (java.lang.NoSuchFieldException e) { + e.printStackTrace(); + } catch (java.lang.IllegalAccessException e) { + e.printStackTrace(); + } + + return; + } + + try { + channel.close(); + } catch (IOException e) { + } + } + + public void cleanup() { + if (bAttached) { + Field f; + try { + f = channel.getClass().getDeclaredField("fdVal"); + f.setAccessible(true); + f.set(channel, -1); + } catch (java.lang.NoSuchFieldException e) { + e.printStackTrace(); + } catch (java.lang.IllegalAccessException e) { + e.printStackTrace(); + } + } + + channel = null; + } + + public void scheduleOutboundData (ByteBuffer bb) { + if (!bCloseScheduled && bb.remaining() > 0) { + if (sslEngine != null) { + try { + ByteBuffer b = ByteBuffer.allocate(32*1024); // TODO, preallocate this buffer. + sslEngine.wrap(bb, b); + b.flip(); + outboundQ.addLast(b); + outboundS += b.remaining(); + } catch (SSLException e) { + throw new RuntimeException ("ssl error"); + } + } + else { + outboundQ.addLast(bb); + outboundS += bb.remaining(); + } + + updateEvents(); + } + } + + public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort) { + throw new RuntimeException ("datagram sends not supported on this channel"); + } + + /** + * Called by the reactor when we have selected readable. + */ + public void readInboundData (ByteBuffer bb) throws IOException { + if (channel.read(bb) == -1) + throw new IOException ("eof"); + } + + public long getOutboundDataSize() { return outboundS; } + + /** + * Called by the reactor when we have selected writable. + * Return false to indicate an error that should cause the connection to close. + * TODO, VERY IMPORTANT: we're here because we selected writable, but it's always + * possible to become unwritable between the poll and when we get here. The way + * this code is written, we're depending on a nonblocking write NOT TO CONSUME + * the whole outbound buffer in this case, rather than firing an exception. + * We should somehow verify that this is indeed Java's defined behavior. + * @return + */ + public boolean writeOutboundData() throws IOException { + ByteBuffer[] bufs = new ByteBuffer[64]; + int i; + long written, toWrite; + while (!outboundQ.isEmpty()) { + i = 0; + toWrite = 0; + written = 0; + while (i < 64 && !outboundQ.isEmpty()) { + bufs[i] = outboundQ.removeFirst(); + toWrite += bufs[i].remaining(); + i++; + } + if (toWrite > 0) + written = channel.write(bufs, 0, i); + + outboundS -= written; + // Did we consume the whole outbound buffer? If yes, + // pop it off and keep looping. If no, the outbound network + // buffers are full, so break out of here. + if (written < toWrite) { + while (i > 0 && bufs[i-1].remaining() > 0) { + outboundQ.addFirst(bufs[i-1]); + i--; + } + break; + } + } + + if (outboundQ.isEmpty() && !bCloseScheduled) { + updateEvents(); + } + + // ALWAYS drain the outbound queue before triggering a connection close. + // If anyone wants to close immediately, they're responsible for clearing + // the outbound queue. + return (bCloseScheduled && outboundQ.isEmpty()) ? false : true; + } + + public void setConnectPending() { + bConnectPending = true; + updateEvents(); + } + + /** + * Called by the reactor when we have selected connectable. + * Return false to indicate an error that should cause the connection to close. + */ + public boolean finishConnecting() throws IOException { + channel.finishConnect(); + + bConnectPending = false; + updateEvents(); + return true; + } + + public boolean scheduleClose (boolean afterWriting) { + // TODO: What the hell happens here if bConnectPending is set? + if (!afterWriting) { + outboundQ.clear(); + outboundS = 0; + } + + if (outboundQ.isEmpty()) + return true; + else { + updateEvents(); + bCloseScheduled = true; + return false; + } + } + + public void startTls() { + if (sslEngine == null) { + try { + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, null); // TODO, fill in the parameters. + sslEngine = sslContext.createSSLEngine(); // TODO, should use the parameterized version, to get Kerb stuff and session re-use. + sslEngine.setUseClientMode(false); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException ("unable to start TLS"); // TODO, get rid of this. + } catch (KeyManagementException e) { + throw new RuntimeException ("unable to start TLS"); // TODO, get rid of this. + } + } + System.out.println ("Starting TLS"); + } + + public ByteBuffer dispatchInboundData (ByteBuffer bb) throws SSLException { + if (sslEngine != null) { + if (true) throw new RuntimeException ("TLS currently unimplemented"); + System.setProperty("javax.net.debug", "all"); + ByteBuffer w = ByteBuffer.allocate(32*1024); // TODO, WRONG, preallocate this buffer. + SSLEngineResult res = sslEngine.unwrap(bb, w); + if (res.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable r; + while ((r = sslEngine.getDelegatedTask()) != null) { + r.run(); + } + } + System.out.println (bb); + w.flip(); + return w; + } + else + return bb; + } + + public void setCommInactivityTimeout (long seconds) { + // TODO + System.out.println ("SOCKET: SET COMM INACTIVITY UNIMPLEMENTED " + seconds); + } + + public Object[] getPeerName () { + Socket sock = channel.socket(); + return new Object[]{ sock.getPort(), sock.getInetAddress().getHostAddress() }; + } + + public Object[] getSockName () { + Socket sock = channel.socket(); + return new Object[]{ sock.getLocalPort(), + sock.getLocalAddress().getHostAddress() }; + } + + public void setWatchOnly() { + bWatchOnly = true; + updateEvents(); + } + public boolean isWatchOnly() { return bWatchOnly; } + + public void setAttached() { + bAttached = true; + } + public boolean isAttached() { return bAttached; } + + public void setNotifyReadable (boolean mode) { + bNotifyReadable = mode; + updateEvents(); + } + public boolean isNotifyReadable() { return bNotifyReadable; } + + public void setNotifyWritable (boolean mode) { + bNotifyWritable = mode; + updateEvents(); + } + public boolean isNotifyWritable() { return bNotifyWritable; } + + public boolean pause() { + if (bWatchOnly) { + throw new RuntimeException ("cannot pause/resume 'watch only' connections, set notify readable/writable instead"); + } + boolean old = bPaused; + bPaused = true; + updateEvents(); + return !old; + } + + public boolean resume() { + if (bWatchOnly) { + throw new RuntimeException ("cannot pause/resume 'watch only' connections, set notify readable/writable instead"); + } + boolean old = bPaused; + bPaused = false; + updateEvents(); + return old; + } + + public boolean isPaused() { + return bPaused; + } + + private void updateEvents() { + if (channelKey == null) + return; + + int events = currentEvents(); + + if (channelKey.interestOps() != events) { + channelKey.interestOps(events); + } + } + + private int currentEvents() { + int events = 0; + + if (bWatchOnly) + { + if (bNotifyReadable) + events |= SelectionKey.OP_READ; + + if (bNotifyWritable) + events |= SelectionKey.OP_WRITE; + } + else if (!bPaused) + { + if (bConnectPending) + events |= SelectionKey.OP_CONNECT; + else { + events |= SelectionKey.OP_READ; + + if (!outboundQ.isEmpty()) + events |= SelectionKey.OP_WRITE; + } + } + + return events; + } +} diff --git a/bin/gems/eventmachine-1.2.7/lib/em/buftok.rb b/bin/gems/eventmachine-1.2.7/lib/em/buftok.rb new file mode 100644 index 00000000..caf4f770 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/buftok.rb @@ -0,0 +1,59 @@ +# BufferedTokenizer takes a delimiter upon instantiation, or acts line-based +# by default. It allows input to be spoon-fed from some outside source which +# receives arbitrary length datagrams which may-or-may-not contain the token +# by which entities are delimited. In this respect it's ideally paired with +# something like EventMachine (http://rubyeventmachine.com/). +class BufferedTokenizer + # New BufferedTokenizers will operate on lines delimited by a delimiter, + # which is by default the global input delimiter $/ ("\n"). + # + # The input buffer is stored as an array. This is by far the most efficient + # approach given language constraints (in C a linked list would be a more + # appropriate data structure). Segments of input data are stored in a list + # which is only joined when a token is reached, substantially reducing the + # number of objects required for the operation. + def initialize(delimiter = $/) + @delimiter = delimiter + @input = [] + @tail = '' + @trim = @delimiter.length - 1 + end + + # Extract takes an arbitrary string of input data and returns an array of + # tokenized entities, provided there were any available to extract. This + # makes for easy processing of datagrams using a pattern like: + # + # tokenizer.extract(data).map { |entity| Decode(entity) }.each do ... + # + # Using -1 makes split to return "" if the token is at the end of + # the string, meaning the last element is the start of the next chunk. + def extract(data) + if @trim > 0 + tail_end = @tail.slice!(-@trim, @trim) # returns nil if string is too short + data = tail_end + data if tail_end + end + + @input << @tail + entities = data.split(@delimiter, -1) + @tail = entities.shift + + unless entities.empty? + @input << @tail + entities.unshift @input.join + @input.clear + @tail = entities.pop + end + + entities + end + + # Flush the contents of the input buffer, i.e. return the input buffer even though + # a token has not yet been encountered + def flush + @input << @tail + buffer = @input.join + @input.clear + @tail = "" # @tail.clear is slightly faster, but not supported on 1.8.7 + buffer + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/callback.rb b/bin/gems/eventmachine-1.2.7/lib/em/callback.rb new file mode 100644 index 00000000..4928febc --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/callback.rb @@ -0,0 +1,58 @@ +module EventMachine + # Utility method for coercing arguments to an object that responds to :call. + # Accepts an object and a method name to send to, or a block, or an object + # that responds to :call. + # + # @example EventMachine.Callback used with a block. Returns that block. + # + # cb = EventMachine.Callback do |msg| + # puts(msg) + # end + # # returned object is a callable + # cb.call('hello world') + # + # + # @example EventMachine.Callback used with an object (to be more specific, class object) and a method name, returns an object that responds to #call + # + # cb = EventMachine.Callback(Object, :puts) + # # returned object is a callable that delegates to Kernel#puts (in this case Object.puts) + # cb.call('hello world') + # + # + # @example EventMachine.Callback used with an object that responds to #call. Returns the argument. + # + # cb = EventMachine.Callback(proc{ |msg| puts(msg) }) + # # returned object is a callable + # cb.call('hello world') + # + # + # @overload Callback(object, method) + # Wraps `method` invocation on `object` into an object that responds to #call that proxies all the arguments to that method + # @param [Object] Object to invoke method on + # @param [Symbol] Method name + # @return [<#call>] An object that responds to #call that takes any number of arguments and invokes method on object with those arguments + # + # @overload Callback(object) + # Returns callable object as is, without any coercion + # @param [<#call>] An object that responds to #call + # @return [<#call>] Its argument + # + # @overload Callback(&block) + # Returns block passed to it without any coercion + # @return [<#call>] Block passed to this method + # + # @raise [ArgumentError] When argument doesn't respond to #call, method name is missing or when invoked without arguments and block isn't given + # + # @return [<#call>] + def self.Callback(object = nil, method = nil, &blk) + if object && method + lambda { |*args| object.__send__ method, *args } + else + if object.respond_to? :call + object + else + blk || raise(ArgumentError) + end # if + end # if + end # self.Callback +end # EventMachine diff --git a/bin/gems/eventmachine-1.2.7/lib/em/channel.rb b/bin/gems/eventmachine-1.2.7/lib/em/channel.rb new file mode 100644 index 00000000..a919adff --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/channel.rb @@ -0,0 +1,69 @@ +module EventMachine + # Provides a simple thread-safe way to transfer data between (typically) long running + # tasks in {EventMachine.defer} and event loop thread. + # + # @example + # + # channel = EventMachine::Channel.new + # sid = channel.subscribe { |msg| p [:got, msg] } + # + # channel.push('hello world') + # channel.unsubscribe(sid) + # + # + class Channel + def initialize + @subs = {} + @uid = 0 + end + + # Return the number of current subscribers. + def num_subscribers + return @subs.size + end + + # Takes any arguments suitable for EM::Callback() and returns a subscriber + # id for use when unsubscribing. + # + # @return [Integer] Subscribe identifier + # @see #unsubscribe + def subscribe(*a, &b) + name = gen_id + EM.schedule { @subs[name] = EM::Callback(*a, &b) } + + name + end + + # Removes subscriber from the list. + # + # @param [Integer] Subscriber identifier + # @see #subscribe + def unsubscribe(name) + EM.schedule { @subs.delete name } + end + + # Add items to the channel, which are pushed out to all subscribers. + def push(*items) + items = items.dup + EM.schedule { items.each { |i| @subs.values.each { |s| s.call i } } } + end + alias << push + + # Fetches one message from the channel. + def pop(*a, &b) + EM.schedule { + name = subscribe do |*args| + unsubscribe(name) + EM::Callback(*a, &b).call(*args) + end + } + end + + private + + # @private + def gen_id + @uid += 1 + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/completion.rb b/bin/gems/eventmachine-1.2.7/lib/em/completion.rb new file mode 100644 index 00000000..926535fd --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/completion.rb @@ -0,0 +1,304 @@ +# = EM::Completion +# +# A completion is a callback container for various states of completion. In +# its most basic form it has a start state and a finish state. +# +# This implementation includes some hold-back from the EM::Deferrable +# interface in order to be compatible - but it has a much cleaner +# implementation. +# +# In general it is preferred that this implementation be used as a state +# callback container than EM::DefaultDeferrable or other classes including +# EM::Deferrable. This is because it is generally more sane to keep this level +# of state in a dedicated state-back container. This generally leads to more +# malleable interfaces and software designs, as well as eradicating nasty bugs +# that result from abstraction leakage. +# +# == Basic Usage +# +# As already mentioned, the basic usage of a Completion is simply for its two +# final states, :succeeded and :failed. +# +# An asynchronous operation will complete at some future point in time, and +# users often want to react to this event. API authors will want to expose +# some common interface to react to these events. +# +# In the following example, the user wants to know when a short lived +# connection has completed its exchange with the remote server. The simple +# protocol just waits for an ack to its message. +# +# class Protocol < EM::Connection +# include EM::P::LineText2 +# +# def initialize(message, completion) +# @message, @completion = message, completion +# @completion.completion { close_connection } +# @completion.timeout(1, :timeout) +# end +# +# def post_init +# send_data(@message) +# end +# +# def receive_line(line) +# case line +# when /ACK/i +# @completion.succeed line +# when /ERR/i +# @completion.fail :error, line +# else +# @completion.fail :unknown, line +# end +# end +# +# def unbind +# @completion.fail :disconnected unless @completion.completed? +# end +# end +# +# class API +# attr_reader :host, :port +# +# def initialize(host = 'example.org', port = 8000) +# @host, @port = host, port +# end +# +# def request(message) +# completion = EM::Deferrable::Completion.new +# EM.connect(host, port, Protocol, message, completion) +# completion +# end +# end +# +# api = API.new +# completion = api.request('stuff') +# completion.callback do |line| +# puts "API responded with: #{line}" +# end +# completion.errback do |type, line| +# case type +# when :error +# puts "API error: #{line}" +# when :unknown +# puts "API returned unknown response: #{line}" +# when :disconnected +# puts "API server disconnected prematurely" +# when :timeout +# puts "API server did not respond in a timely fashion" +# end +# end +# +# == Advanced Usage +# +# This completion implementation also supports more state callbacks and +# arbitrary states (unlike the original Deferrable API). This allows for basic +# stateful process encapsulation. One might use this to setup state callbacks +# for various states in an exchange like in the basic usage example, except +# where the applicaiton could be made to react to "connected" and +# "disconnected" states additionally. +# +# class Protocol < EM::Connection +# def initialize(completion) +# @response = [] +# @completion = completion +# @completion.stateback(:disconnected) do +# @completion.succeed @response.join +# end +# end +# +# def connection_completed +# @host, @port = Socket.unpack_sockaddr_in get_peername +# @completion.change_state(:connected, @host, @port) +# send_data("GET http://example.org/ HTTP/1.0\r\n\r\n") +# end +# +# def receive_data(data) +# @response << data +# end +# +# def unbind +# @completion.change_state(:disconnected, @host, @port) +# end +# end +# +# completion = EM::Deferrable::Completion.new +# completion.stateback(:connected) do |host, port| +# puts "Connected to #{host}:#{port}" +# end +# completion.stateback(:disconnected) do |host, port| +# puts "Disconnected from #{host}:#{port}" +# end +# completion.callback do |response| +# puts response +# end +# +# EM.connect('example.org', 80, Protocol, completion) +# +# == Timeout +# +# The Completion also has a timeout. The timeout is global and is not aware of +# states apart from completion states. The timeout is only engaged if #timeout +# is called, and it will call fail if it is reached. +# +# == Completion states +# +# By default there are two completion states, :succeeded and :failed. These +# states can be modified by subclassing and overrding the #completion_states +# method. Completion states are special, in that callbacks for all completion +# states are explcitly cleared when a completion state is entered. This +# prevents errors that could arise from accidental unterminated timeouts, and +# other such user errors. +# +# == Other notes +# +# Several APIs have been carried over from EM::Deferrable for compatibility +# reasons during a transitionary period. Specifically cancel_errback and +# cancel_callback are implemented, but their usage is to be strongly +# discouraged. Due to the already complex nature of reaction systems, dynamic +# callback deletion only makes the problem much worse. It is always better to +# add correct conditionals to the callback code, or use more states, than to +# address such implementaiton issues with conditional callbacks. + +module EventMachine + + class Completion + # This is totally not used (re-implemented), it's here in case people check + # for kind_of? + include EventMachine::Deferrable + + attr_reader :state, :value + + def initialize + @state = :unknown + @callbacks = Hash.new { |h,k| h[k] = [] } + @value = [] + @timeout_timer = nil + end + + # Enter the :succeeded state, setting the result value if given. + def succeed(*args) + change_state(:succeeded, *args) + end + # The old EM method: + alias set_deferred_success succeed + + # Enter the :failed state, setting the result value if given. + def fail(*args) + change_state(:failed, *args) + end + # The old EM method: + alias set_deferred_failure fail + + # Statebacks are called when you enter (or are in) the named state. + def stateback(state, *a, &b) + # The following is quite unfortunate special casing for :completed + # statebacks, but it's a necessary evil for latent completion + # definitions. + + if :completed == state || !completed? || @state == state + @callbacks[state] << EM::Callback(*a, &b) + end + execute_callbacks + self + end + + # Callbacks are called when you enter (or are in) a :succeeded state. + def callback(*a, &b) + stateback(:succeeded, *a, &b) + end + + # Errbacks are called when you enter (or are in) a :failed state. + def errback(*a, &b) + stateback(:failed, *a, &b) + end + + # Completions are called when you enter (or are in) either a :failed or a + # :succeeded state. They are stored as a special (reserved) state called + # :completed. + def completion(*a, &b) + stateback(:completed, *a, &b) + end + + # Enter a new state, setting the result value if given. If the state is one + # of :succeeded or :failed, then :completed callbacks will also be called. + def change_state(state, *args) + @value = args + @state = state + + EM.schedule { execute_callbacks } + end + + # The old EM method: + alias set_deferred_status change_state + + # Indicates that we've reached some kind of completion state, by default + # this is :succeeded or :failed. Due to these semantics, the :completed + # state is reserved for internal use. + def completed? + completion_states.any? { |s| state == s } + end + + # Completion states simply returns a list of completion states, by default + # this is :succeeded and :failed. + def completion_states + [:succeeded, :failed] + end + + # Schedule a time which if passes before we enter a completion state, this + # deferrable will be failed with the given arguments. + def timeout(time, *args) + cancel_timeout + @timeout_timer = EM::Timer.new(time) do + fail(*args) unless completed? + end + end + + # Disable the timeout + def cancel_timeout + if @timeout_timer + @timeout_timer.cancel + @timeout_timer = nil + end + end + + # Remove an errback. N.B. Some errbacks cannot be deleted. Usage is NOT + # recommended, this is an anti-pattern. + def cancel_errback(*a, &b) + @callbacks[:failed].delete(EM::Callback(*a, &b)) + end + + # Remove a callback. N.B. Some callbacks cannot be deleted. Usage is NOT + # recommended, this is an anti-pattern. + def cancel_callback(*a, &b) + @callbacks[:succeeded].delete(EM::Callback(*a, &b)) + end + + private + # Execute all callbacks for the current state. If in a completed state, then + # call any statebacks associated with the completed state. + def execute_callbacks + execute_state_callbacks(state) + if completed? + execute_state_callbacks(:completed) + clear_dead_callbacks + cancel_timeout + end + end + + # Iterate all callbacks for a given state, and remove then call them. + def execute_state_callbacks(state) + while callback = @callbacks[state].shift + callback.call(*value) + end + end + + # If we enter a completion state, clear other completion states after all + # callback chains are completed. This means that operation specific + # callbacks can't be dual-called, which is most common user error. + def clear_dead_callbacks + completion_states.each do |state| + @callbacks[state].clear + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/connection.rb b/bin/gems/eventmachine-1.2.7/lib/em/connection.rb new file mode 100644 index 00000000..267aec2d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/connection.rb @@ -0,0 +1,770 @@ +module EventMachine + class FileNotFoundException < Exception + end + + # EventMachine::Connection is a class that is instantiated + # by EventMachine's processing loop whenever a new connection + # is created. (New connections can be either initiated locally + # to a remote server or accepted locally from a remote client.) + # When a Connection object is instantiated, it mixes in + # the functionality contained in the user-defined module + # specified in calls to {EventMachine.connect} or {EventMachine.start_server}. + # User-defined handler modules may redefine any or all of the standard + # methods defined here, as well as add arbitrary additional code + # that will also be mixed in. + # + # EventMachine manages one object inherited from EventMachine::Connection + # (and containing the mixed-in user code) for every network connection + # that is active at any given time. + # The event loop will automatically call methods on EventMachine::Connection + # objects whenever specific events occur on the corresponding connections, + # as described below. + # + # This class is never instantiated by user code, and does not publish an + # initialize method. The instance methods of EventMachine::Connection + # which may be called by the event loop are: + # + # * {#post_init} + # * {#connection_completed} + # * {#receive_data} + # * {#unbind} + # * {#ssl_verify_peer} (if TLS is used) + # * {#ssl_handshake_completed} + # + # All of the other instance methods defined here are called only by user code. + # + # @see file:docs/GettingStarted.md EventMachine tutorial + class Connection + # @private + attr_accessor :signature + + # @private + alias original_method method + + # Override .new so subclasses don't have to call super and can ignore + # connection-specific arguments + # + # @private + def self.new(sig, *args) + allocate.instance_eval do + # Store signature + @signature = sig + # associate_callback_target sig + + # Call a superclass's #initialize if it has one + initialize(*args) + + # post initialize callback + post_init + + self + end + end + + # Stubbed initialize so legacy superclasses can safely call super + # + # @private + def initialize(*args) + end + + # Called by the event loop immediately after the network connection has been established, + # and before resumption of the network loop. + # This method is generally not called by user code, but is called automatically + # by the event loop. The base-class implementation is a no-op. + # This is a very good place to initialize instance variables that will + # be used throughout the lifetime of the network connection. + # + # @see #connection_completed + # @see #unbind + # @see #send_data + # @see #receive_data + def post_init + end + + # Called by the event loop whenever data has been received by the network connection. + # It is never called by user code. {#receive_data} is called with a single parameter, a String containing + # the network protocol data, which may of course be binary. You will + # generally redefine this method to perform your own processing of the incoming data. + # + # Here's a key point which is essential to understanding the event-driven + # programming model: EventMachine knows absolutely nothing about the protocol + # which your code implements. You must not make any assumptions about + # the size of the incoming data packets, or about their alignment on any + # particular intra-message or PDU boundaries (such as line breaks). + # receive_data can and will send you arbitrary chunks of data, with the + # only guarantee being that the data is presented to your code in the order + # it was collected from the network. Don't even assume that the chunks of + # data will correspond to network packets, as EventMachine can and will coalesce + # several incoming packets into one, to improve performance. The implication for your + # code is that you generally will need to implement some kind of a state machine + # in your redefined implementation of receive_data. For a better understanding + # of this, read through the examples of specific protocol handlers in EventMachine::Protocols + # + # The base-class implementation (which will be invoked only if you didn't override it in your protocol handler) + # simply prints incoming data packet size to stdout. + # + # @param [String] data Opaque incoming data. + # @note Depending on the protocol, buffer sizes and OS networking stack configuration, incoming data may or may not be "a complete message". + # It is up to this handler to detect content boundaries to determine whether all the content (for example, full HTTP request) + # has been received and can be processed. + # + # @see #post_init + # @see #connection_completed + # @see #unbind + # @see #send_data + # @see file:docs/GettingStarted.md EventMachine tutorial + def receive_data data + puts "............>>>#{data.length}" + end + + # Called by EventMachine when the SSL/TLS handshake has + # been completed, as a result of calling #start_tls to initiate SSL/TLS on the connection. + # + # This callback exists because {#post_init} and {#connection_completed} are **not** reliable + # for indicating when an SSL/TLS connection is ready to have its certificate queried for. + # + # @see #get_peer_cert + def ssl_handshake_completed + end + + # Called by EventMachine when :verify_peer => true has been passed to {#start_tls}. + # It will be called with each certificate in the certificate chain provided by the remote peer. + # + # The cert will be passed as a String in PEM format, the same as in {#get_peer_cert}. It is up to user defined + # code to perform a check on the certificates. The return value from this callback is used to accept or deny the peer. + # A return value that is not nil or false triggers acceptance. If the peer is not accepted, the connection + # will be subsequently closed. + # + # @example This server always accepts all peers + # + # module AcceptServer + # def post_init + # start_tls(:verify_peer => true) + # end + # + # def ssl_verify_peer(cert) + # true + # end + # + # def ssl_handshake_completed + # $server_handshake_completed = true + # end + # end + # + # + # @example This server never accepts any peers + # + # module DenyServer + # def post_init + # start_tls(:verify_peer => true) + # end + # + # def ssl_verify_peer(cert) + # # Do not accept the peer. This should now cause the connection to shut down + # # without the SSL handshake being completed. + # false + # end + # + # def ssl_handshake_completed + # $server_handshake_completed = true + # end + # end + # + # @see #start_tls + def ssl_verify_peer(cert) + end + + # called by the framework whenever a connection (either a server or client connection) is closed. + # The close can occur because your code intentionally closes it (using {#close_connection} and {#close_connection_after_writing}), + # because the remote peer closed the connection, or because of a network error. + # You may not assume that the network connection is still open and able to send or + # receive data when the callback to unbind is made. This is intended only to give + # you a chance to clean up associations your code may have made to the connection + # object while it was open. + # + # If you want to detect which peer has closed the connection, you can override {#close_connection} in your protocol handler + # and set an @ivar. + # + # @example Overriding Connection#close_connection to distinguish connections closed on our side + # + # class MyProtocolHandler < EventMachine::Connection + # + # # ... + # + # def close_connection(*args) + # @intentionally_closed_connection = true + # super(*args) + # end + # + # def unbind + # if @intentionally_closed_connection + # # ... + # end + # end + # + # # ... + # + # end + # + # @see #post_init + # @see #connection_completed + # @see file:docs/GettingStarted.md EventMachine tutorial + def unbind + end + + # Called by the reactor after attempting to relay incoming data to a descriptor (set as a proxy target descriptor with + # {EventMachine.enable_proxy}) that has already been closed. + # + # @see EventMachine.enable_proxy + def proxy_target_unbound + end + + # called when the reactor finished proxying all + # of the requested bytes. + def proxy_completed + end + + # EventMachine::Connection#proxy_incoming_to is called only by user code. It sets up + # a low-level proxy relay for all data inbound for this connection, to the connection given + # as the argument. This is essentially just a helper method for enable_proxy. + # + # @see EventMachine.enable_proxy + def proxy_incoming_to(conn,bufsize=0) + EventMachine::enable_proxy(self, conn, bufsize) + end + + # A helper method for {EventMachine.disable_proxy} + def stop_proxying + EventMachine::disable_proxy(self) + end + + # The number of bytes proxied to another connection. Reset to zero when + # EventMachine::Connection#proxy_incoming_to is called, and incremented whenever data is proxied. + def get_proxied_bytes + EventMachine::get_proxied_bytes(@signature) + end + + # EventMachine::Connection#close_connection is called only by user code, and never + # by the event loop. You may call this method against a connection object in any + # callback handler, whether or not the callback was made against the connection + # you want to close. close_connection schedules the connection to be closed + # at the next available opportunity within the event loop. You may not assume that + # the connection is closed when close_connection returns. In particular, the framework + # will callback the unbind method for the particular connection at a point shortly + # after you call close_connection. You may assume that the unbind callback will + # take place sometime after your call to close_connection completes. In other words, + # the unbind callback will not re-enter your code "inside" of your call to close_connection. + # However, it's not guaranteed that a future version of EventMachine will not change + # this behavior. + # + # {#close_connection} will *silently discard* any outbound data which you have + # sent to the connection using {EventMachine::Connection#send_data} but which has not + # yet been sent across the network. If you want to avoid this behavior, use + # {EventMachine::Connection#close_connection_after_writing}. + # + def close_connection after_writing = false + EventMachine::close_connection @signature, after_writing + end + + # Removes given connection from the event loop. + # The connection's socket remains open and its file descriptor number is returned. + def detach + EventMachine::detach_fd @signature + end + + def get_sock_opt level, option + EventMachine::get_sock_opt @signature, level, option + end + + def set_sock_opt level, optname, optval + EventMachine::set_sock_opt @signature, level, optname, optval + end + + # A variant of {#close_connection}. + # All of the descriptive comments given for close_connection also apply to + # close_connection_after_writing, *with one exception*: if the connection has + # outbound data sent using send_dat but which has not yet been sent across the network, + # close_connection_after_writing will schedule the connection to be closed *after* + # all of the outbound data has been safely written to the remote peer. + # + # Depending on the amount of outgoing data and the speed of the network, + # considerable time may elapse between your call to close_connection_after_writing + # and the actual closing of the socket (at which time the unbind callback will be called + # by the event loop). During this time, you *may not* call send_data to transmit + # additional data (that is, the connection is closed for further writes). In very + # rare cases, you may experience a receive_data callback after your call to {#close_connection_after_writing}, + # depending on whether incoming data was in the process of being received on the connection + # at the moment when you called {#close_connection_after_writing}. Your protocol handler must + # be prepared to properly deal with such data (probably by ignoring it). + # + # @see #close_connection + # @see #send_data + def close_connection_after_writing + close_connection true + end + + # Call this method to send data to the remote end of the network connection. It takes a single String argument, + # which may contain binary data. Data is buffered to be sent at the end of this event loop tick (cycle). + # + # When used in a method that is event handler (for example, {#post_init} or {#connection_completed}, it will send + # data to the other end of the connection that generated the event. + # You can also call {#send_data} to write to other connections. For more information see The Chat Server Example in the + # {file:docs/GettingStarted.md EventMachine tutorial}. + # + # If you want to send some data and then immediately close the connection, make sure to use {#close_connection_after_writing} + # instead of {#close_connection}. + # + # + # @param [String] data Data to send asynchronously + # + # @see file:docs/GettingStarted.md EventMachine tutorial + # @see Connection#receive_data + # @see Connection#post_init + # @see Connection#unbind + def send_data data + data = data.to_s + size = data.bytesize if data.respond_to?(:bytesize) + size ||= data.size + EventMachine::send_data @signature, data, size + end + + # Returns true if the connection is in an error state, false otherwise. + # + # In general, you can detect the occurrence of communication errors or unexpected + # disconnection by the remote peer by handing the {#unbind} method. In some cases, however, + # it's useful to check the status of the connection using {#error?} before attempting to send data. + # This function is synchronous but it will return immediately without blocking. + # + # @return [Boolean] true if the connection is in an error state, false otherwise + def error? + errno = EventMachine::report_connection_error_status(@signature) + case errno + when 0 + false + when -1 + true + else + EventMachine::ERRNOS[errno] + end + end + + # Called by the event loop when a remote TCP connection attempt completes successfully. + # You can expect to get this notification after calls to {EventMachine.connect}. Remember that EventMachine makes remote connections + # asynchronously, just as with any other kind of network event. This method + # is intended primarily to assist with network diagnostics. For normal protocol + # handling, use #post_init to perform initial work on a new connection (such as sending initial set of data). + # {Connection#post_init} will always be called. This method will only be called in case of a successful completion. + # A connection attempt which fails will result a call to {Connection#unbind} after the failure. + # + # @see Connection#post_init + # @see Connection#unbind + # @see file:docs/GettingStarted.md EventMachine tutorial + def connection_completed + end + + # Call {#start_tls} at any point to initiate TLS encryption on connected streams. + # The method is smart enough to know whether it should perform a server-side + # or a client-side handshake. An appropriate place to call {#start_tls} is in + # your redefined {#post_init} method, or in the {#connection_completed} handler for + # an outbound connection. + # + # + # @option args [String] :cert_chain_file (nil) local path of a readable file that contants a chain of X509 certificates in + # the [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail), + # with the most-resolved certificate at the top of the file, successive intermediate + # certs in the middle, and the root (or CA) cert at the bottom. + # + # @option args [String] :private_key_file (nil) local path of a readable file that must contain a private key in the [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail). + # + # @option args [Boolean] :verify_peer (false) indicates whether a server should request a certificate from a peer, to be verified by user code. + # If true, the {#ssl_verify_peer} callback on the {EventMachine::Connection} object is called with each certificate + # in the certificate chain provided by the peer. See documentation on {#ssl_verify_peer} for how to use this. + # + # @option args [Boolean] :fail_if_no_peer_cert (false) Used in conjunction with verify_peer. If set the SSL handshake will be terminated if the peer does not provide a certificate. + # + # + # @option args [String] :cipher_list ("ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH") indicates the available SSL cipher values. Default value is "ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH". Check the format of the OpenSSL cipher string at http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT. + # + # @option args [String] :ecdh_curve (nil) The curve for ECDHE ciphers. See available ciphers with 'openssl ecparam -list_curves' + # + # @option args [String] :dhparam (nil) The local path of a file containing DH parameters for EDH ciphers in [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail) See: 'openssl dhparam' + # + # @option args [Array] :ssl_version (TLSv1 TLSv1_1 TLSv1_2) indicates the allowed SSL/TLS versions. Possible values are: {SSLv2}, {SSLv3}, {TLSv1}, {TLSv1_1}, {TLSv1_2}. + # + # @example Using TLS with EventMachine + # + # require 'rubygems' + # require 'eventmachine' + # + # module Handler + # def post_init + # start_tls(:private_key_file => '/tmp/server.key', :cert_chain_file => '/tmp/server.crt', :verify_peer => false) + # end + # end + # + # EventMachine.run do + # EventMachine.start_server("127.0.0.1", 9999, Handler) + # end + # + # @param [Hash] args + # + # @todo support passing an encryption parameter, which can be string or Proc, to get a passphrase + # for encrypted private keys. + # @todo support passing key material via raw strings or Procs that return strings instead of + # just filenames. + # + # @see #ssl_verify_peer + def start_tls args={} + priv_key = args[:private_key_file] + cert_chain = args[:cert_chain_file] + verify_peer = args[:verify_peer] + sni_hostname = args[:sni_hostname] + cipher_list = args[:cipher_list] + ssl_version = args[:ssl_version] + ecdh_curve = args[:ecdh_curve] + dhparam = args[:dhparam] + fail_if_no_peer_cert = args[:fail_if_no_peer_cert] + + [priv_key, cert_chain].each do |file| + next if file.nil? or file.empty? + raise FileNotFoundException, + "Could not find #{file} for start_tls" unless File.exist? file + end + + protocols_bitmask = 0 + if ssl_version.nil? + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1 + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1_1 + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1_2 + else + [ssl_version].flatten.each do |p| + case p.to_s.downcase + when 'sslv2' + protocols_bitmask |= EventMachine::EM_PROTO_SSLv2 + when 'sslv3' + protocols_bitmask |= EventMachine::EM_PROTO_SSLv3 + when 'tlsv1' + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1 + when 'tlsv1_1' + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1_1 + when 'tlsv1_2' + protocols_bitmask |= EventMachine::EM_PROTO_TLSv1_2 + else + raise("Unrecognized SSL/TLS Protocol: #{p}") + end + end + end + + EventMachine::set_tls_parms(@signature, priv_key || '', cert_chain || '', verify_peer, fail_if_no_peer_cert, sni_hostname || '', cipher_list || '', ecdh_curve || '', dhparam || '', protocols_bitmask) + EventMachine::start_tls @signature + end + + # If [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security) is active on the connection, returns the remote [X509 certificate](http://en.wikipedia.org/wiki/X.509) + # as a string, in the popular [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail). This can then be used for arbitrary validation + # of a peer's certificate in your code. + # + # This should be called in/after the {#ssl_handshake_completed} callback, which indicates + # that SSL/TLS is active. Using this callback is important, because the certificate may not + # be available until the time it is executed. Using #post_init or #connection_completed is + # not adequate, because the SSL handshake may still be taking place. + # + # This method will return `nil` if: + # + # * EventMachine is not built with [OpenSSL](http://www.openssl.org) support + # * [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security) is not active on the connection + # * TLS handshake is not yet complete + # * Remote peer for any other reason has not presented a certificate + # + # + # @example Getting peer TLS certificate information in EventMachine + # + # module Handler + # def post_init + # puts "Starting TLS" + # start_tls + # end + # + # def ssl_handshake_completed + # puts get_peer_cert + # close_connection + # end + # + # def unbind + # EventMachine::stop_event_loop + # end + # end + # + # EventMachine.run do + # EventMachine.connect "mail.google.com", 443, Handler + # end + # + # # Will output: + # # -----BEGIN CERTIFICATE----- + # # MIIDIjCCAougAwIBAgIQbldpChBPqv+BdPg4iwgN8TANBgkqhkiG9w0BAQUFADBM + # # MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg + # # THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wODA1MDIxNjMyNTRaFw0w + # # OTA1MDIxNjMyNTRaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh + # # MRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRgw + # # FgYDVQQDEw9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ + # # AoGBALlkxdh2QXegdElukCSOV2+8PKiONIS+8Tu9K7MQsYpqtLNC860zwOPQ2NLI + # # 3Zp4jwuXVTrtzGuiqf5Jioh35Ig3CqDXtLyZoypjZUQcq4mlLzHlhIQ4EhSjDmA7 + # # Ffw9y3ckSOQgdBQWNLbquHh9AbEUjmhkrYxIqKXeCnRKhv6nAgMBAAGjgecwgeQw + # # KAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwNgYDVR0f + # # BC8wLTAroCmgJ4YlaHR0cDovL2NybC50aGF3dGUuY29tL1RoYXd0ZVNHQ0NBLmNy + # # bDByBggrBgEFBQcBAQRmMGQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0 + # # ZS5jb20wPgYIKwYBBQUHMAKGMmh0dHA6Ly93d3cudGhhd3RlLmNvbS9yZXBvc2l0 + # # b3J5L1RoYXd0ZV9TR0NfQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEF + # # BQADgYEAsRwpLg1dgCR1gYDK185MFGukXMeQFUvhGqF8eT/CjpdvezyKVuz84gSu + # # 6ccMXgcPQZGQN/F4Xug+Q01eccJjRSVfdvR5qwpqCj+6BFl5oiKDBsveSkrmL5dz + # # s2bn7TdTSYKcLeBkjXxDLHGBqLJ6TNCJ3c4/cbbG5JhGvoema94= + # # -----END CERTIFICATE----- + # + # You can do whatever you want with the certificate String, such as load it + # as a certificate object using the OpenSSL library, and check its fields. + # + # @return [String] the remote [X509 certificate](http://en.wikipedia.org/wiki/X.509), in the popular [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail), + # if TLS is active on the connection + # + # @see Connection#start_tls + # @see Connection#ssl_handshake_completed + def get_peer_cert + EventMachine::get_peer_cert @signature + end + + def get_cipher_bits + EventMachine::get_cipher_bits @signature + end + + def get_cipher_name + EventMachine::get_cipher_name @signature + end + + def get_cipher_protocol + EventMachine::get_cipher_protocol @signature + end + + def get_sni_hostname + EventMachine::get_sni_hostname @signature + end + + # Sends UDP messages. + # + # This method may be called from any Connection object that refers + # to an open datagram socket (see EventMachine#open_datagram_socket). + # The method sends a UDP (datagram) packet containing the data you specify, + # to a remote peer specified by the IP address and port that you give + # as parameters to the method. + # Observe that you may send a zero-length packet (empty string). + # However, you may not send an arbitrarily-large data packet because + # your operating system will enforce a platform-specific limit on + # the size of the outbound packet. (Your kernel + # will respond in a platform-specific way if you send an overlarge + # packet: some will send a truncated packet, some will complain, and + # some will silently drop your request). + # On LANs, it's usually OK to send datagrams up to about 4000 bytes in length, + # but to be really safe, send messages smaller than the Ethernet-packet + # size (typically about 1400 bytes). Some very restrictive WANs + # will either drop or truncate packets larger than about 500 bytes. + # + # @param [String] data Data to send asynchronously + # @param [String] recipient_address IP address of the recipient + # @param [String] recipient_port Port of the recipient + def send_datagram data, recipient_address, recipient_port + data = data.to_s + size = data.bytesize if data.respond_to?(:bytesize) + size ||= data.size + EventMachine::send_datagram @signature, data, size, recipient_address, Integer(recipient_port) + end + + + # This method is used with stream-connections to obtain the identity + # of the remotely-connected peer. If a peername is available, this method + # returns a sockaddr structure. The method returns nil if no peername is available. + # You can use Socket.unpack_sockaddr_in and its variants to obtain the + # values contained in the peername structure returned from #get_peername. + # + # @example How to get peer IP address and port with EventMachine + # + # require 'socket' + # + # module Handler + # def receive_data data + # port, ip = Socket.unpack_sockaddr_in(get_peername) + # puts "got #{data.inspect} from #{ip}:#{port}" + # end + # end + def get_peername + EventMachine::get_peername @signature + end + + # Used with stream-connections to obtain the identity + # of the local side of the connection. If a local name is available, this method + # returns a sockaddr structure. The method returns nil if no local name is available. + # You can use {Socket.unpack_sockaddr_in} and its variants to obtain the + # values contained in the local-name structure returned from this method. + # + # @example + # + # require 'socket' + # + # module Handler + # def receive_data data + # port, ip = Socket.unpack_sockaddr_in(get_sockname) + # puts "got #{data.inspect}" + # end + # end + def get_sockname + EventMachine::get_sockname @signature + end + + # Returns the PID (kernel process identifier) of a subprocess + # associated with this Connection object. For use with {EventMachine.popen} + # and similar methods. Returns nil when there is no meaningful subprocess. + # + # @return [Integer] + def get_pid + EventMachine::get_subprocess_pid @signature + end + + # Returns a subprocess exit status. Only useful for {EventMachine.popen}. Call it in your + # {#unbind} handler. + # + # @return [Integer] + def get_status + EventMachine::get_subprocess_status @signature + end + + # The number of seconds since the last send/receive activity on this connection. + def get_idle_time + EventMachine::get_idle_time @signature + end + + # comm_inactivity_timeout returns the current value (float in seconds) of the inactivity-timeout + # property of network-connection and datagram-socket objects. A nonzero value + # indicates that the connection or socket will automatically be closed if no read or write + # activity takes place for at least that number of seconds. + # A zero value (the default) specifies that no automatic timeout will take place. + def comm_inactivity_timeout + EventMachine::get_comm_inactivity_timeout @signature + end + + # Allows you to set the inactivity-timeout property for + # a network connection or datagram socket. Specify a non-negative float value in seconds. + # If the value is greater than zero, the connection or socket will automatically be closed + # if no read or write activity takes place for at least that number of seconds. + # Specify a value of zero to indicate that no automatic timeout should take place. + # Zero is the default value. + def comm_inactivity_timeout= value + EventMachine::set_comm_inactivity_timeout @signature, value.to_f + end + alias set_comm_inactivity_timeout comm_inactivity_timeout= + + # The duration after which a TCP connection in the connecting state will fail. + # It is important to distinguish this value from {EventMachine::Connection#comm_inactivity_timeout}, + # which looks at how long since data was passed on an already established connection. + # The value is a float in seconds. + # + # @return [Float] The duration after which a TCP connection in the connecting state will fail, in seconds. + def pending_connect_timeout + EventMachine::get_pending_connect_timeout @signature + end + + # Sets the duration after which a TCP connection in a + # connecting state will fail. + # + # @param [Float, #to_f] value Connection timeout in seconds + def pending_connect_timeout= value + EventMachine::set_pending_connect_timeout @signature, value.to_f + end + alias set_pending_connect_timeout pending_connect_timeout= + + # Reconnect to a given host/port with the current instance + # + # @param [String] server Hostname or IP address + # @param [Integer] port Port to reconnect to + def reconnect server, port + EventMachine::reconnect server, port, self + end + + + # Like {EventMachine::Connection#send_data}, this sends data to the remote end of + # the network connection. {EventMachine::Connection#send_file_data} takes a + # filename as an argument, though, and sends the contents of the file, in one + # chunk. + # + # @param [String] filename Local path of the file to send + # + # @see #send_data + # @author Kirk Haines + def send_file_data filename + EventMachine::send_file_data @signature, filename + end + + # Open a file on the filesystem and send it to the remote peer. This returns an + # object of type {EventMachine::Deferrable}. The object's callbacks will be executed + # on the reactor main thread when the file has been completely scheduled for + # transmission to the remote peer. Its errbacks will be called in case of an error (such as file-not-found). + # This method employs various strategies to achieve the fastest possible performance, + # balanced against minimum consumption of memory. + # + # Warning: this feature has an implicit dependency on an outboard extension, + # evma_fastfilereader. You must install this extension in order to use {#stream_file_data} + # with files larger than a certain size (currently 8192 bytes). + # + # @option args [Boolean] :http_chunks (false) If true, this method will stream the file data in a format + # compatible with the HTTP chunked-transfer encoding + # + # @param [String] filename Local path of the file to stream + # @param [Hash] args Options + # + # @return [EventMachine::Deferrable] + def stream_file_data filename, args={} + EventMachine::FileStreamer.new( self, filename, args ) + end + + # Watches connection for readability. Only possible if the connection was created + # using {EventMachine.attach} and had {EventMachine.notify_readable}/{EventMachine.notify_writable} defined on the handler. + # + # @see #notify_readable? + def notify_readable= mode + EventMachine::set_notify_readable @signature, mode + end + + # @return [Boolean] true if the connection is being watched for readability. + def notify_readable? + EventMachine::is_notify_readable @signature + end + + # Watches connection for writeability. Only possible if the connection was created + # using {EventMachine.attach} and had {EventMachine.notify_readable}/{EventMachine.notify_writable} defined on the handler. + # + # @see #notify_writable? + def notify_writable= mode + EventMachine::set_notify_writable @signature, mode + end + + # Returns true if the connection is being watched for writability. + def notify_writable? + EventMachine::is_notify_writable @signature + end + + # Pause a connection so that {#send_data} and {#receive_data} events are not fired until {#resume} is called. + # @see #resume + def pause + EventMachine::pause_connection @signature + end + + # Resume a connection's {#send_data} and {#receive_data} events. + # @see #pause + def resume + EventMachine::resume_connection @signature + end + + # @return [Boolean] true if the connect was paused using {EventMachine::Connection#pause}. + # @see #pause + # @see #resume + def paused? + EventMachine::connection_paused? @signature + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/deferrable.rb b/bin/gems/eventmachine-1.2.7/lib/em/deferrable.rb new file mode 100644 index 00000000..18a6d316 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/deferrable.rb @@ -0,0 +1,210 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 Jul 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Deferrable + autoload :Pool, 'em/deferrable/pool' + + # Specify a block to be executed if and when the Deferrable object receives + # a status of :succeeded. See #set_deferred_status for more information. + # + # Calling this method on a Deferrable object whose status is not yet known + # will cause the callback block to be stored on an internal list. + # If you call this method on a Deferrable whose status is :succeeded, the + # block will be executed immediately, receiving the parameters given to the + # prior #set_deferred_status call. + # + #-- + # If there is no status, add a callback to an internal list. + # If status is succeeded, execute the callback immediately. + # If status is failed, do nothing. + # + def callback &block + return unless block + @deferred_status ||= :unknown + if @deferred_status == :succeeded + block.call(*@deferred_args) + elsif @deferred_status != :failed + @callbacks ||= [] + @callbacks.unshift block # << block + end + self + end + + # Cancels an outstanding callback to &block if any. Undoes the action of #callback. + # + def cancel_callback block + @callbacks ||= [] + @callbacks.delete block + end + + # Specify a block to be executed if and when the Deferrable object receives + # a status of :failed. See #set_deferred_status for more information. + #-- + # If there is no status, add an errback to an internal list. + # If status is failed, execute the errback immediately. + # If status is succeeded, do nothing. + # + def errback &block + return unless block + @deferred_status ||= :unknown + if @deferred_status == :failed + block.call(*@deferred_args) + elsif @deferred_status != :succeeded + @errbacks ||= [] + @errbacks.unshift block # << block + end + self + end + + # Cancels an outstanding errback to &block if any. Undoes the action of #errback. + # + def cancel_errback block + @errbacks ||= [] + @errbacks.delete block + end + + # Sets the "disposition" (status) of the Deferrable object. See also the large set of + # sugarings for this method. + # Note that if you call this method without arguments, + # no arguments will be passed to the callback/errback. + # If the user has coded these with arguments, then the + # user code will throw an argument exception. + # Implementors of deferrable classes must + # document the arguments they will supply to user callbacks. + # + # OBSERVE SOMETHING VERY SPECIAL here: you may call this method even + # on the INSIDE of a callback. This is very useful when a previously-registered + # callback wants to change the parameters that will be passed to subsequently-registered + # ones. + # + # You may give either :succeeded or :failed as the status argument. + # + # If you pass :succeeded, then all of the blocks passed to the object using the #callback + # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks + # passed to the object using #errback will be discarded. + # + # If you pass :failed, then all of the blocks passed to the object using the #errback + # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks + # passed to the object using # callback will be discarded. + # + # If you pass any arguments to #set_deferred_status in addition to the status argument, + # they will be passed as arguments to any callbacks or errbacks that are executed. + # It's your responsibility to ensure that the argument lists specified in your callbacks and + # errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise + # an ArgumentError. + # + #-- + # We're shifting callbacks off and discarding them as we execute them. + # This is valid because by definition callbacks are executed no more than + # once. It also has the magic effect of permitting recursive calls, which + # means that a callback can call #set_deferred_status and change the parameters + # that will be sent to subsequent callbacks down the chain. + # + # Changed @callbacks and @errbacks from push/shift to unshift/pop, per suggestion + # by Kirk Haines, to work around the memory leak bug that still exists in many Ruby + # versions. + # + # Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of + # handlers. This gets us a little closer to the behavior of Twisted's "deferred," + # which only allows status to be set once. Prior to making this change, it was possible + # to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it, + # triggering its errbacks! That is clearly undesirable, but it's just as undesirable + # to raise an exception is status is set more than once on a Deferrable. The latter + # behavior would invalidate the idiom of resetting arguments by setting status from + # within a callback or errback, but more seriously it would cause spurious errors + # if a Deferrable was timed out and then an attempt was made to succeed it. See the + # comments under the new method #timeout. + # + def set_deferred_status status, *args + cancel_timeout + @errbacks ||= nil + @callbacks ||= nil + @deferred_status = status + @deferred_args = args + case @deferred_status + when :succeeded + if @callbacks + while cb = @callbacks.pop + cb.call(*@deferred_args) + end + end + @errbacks.clear if @errbacks + when :failed + if @errbacks + while eb = @errbacks.pop + eb.call(*@deferred_args) + end + end + @callbacks.clear if @callbacks + end + end + + + # Setting a timeout on a Deferrable causes it to go into the failed state after + # the Timeout expires (passing no arguments to the object's errbacks). + # Setting the status at any time prior to a call to the expiration of the timeout + # will cause the timer to be cancelled. + def timeout seconds, *args + cancel_timeout + me = self + @deferred_timeout = EventMachine::Timer.new(seconds) {me.fail(*args)} + self + end + + # Cancels an outstanding timeout if any. Undoes the action of #timeout. + # + def cancel_timeout + @deferred_timeout ||= nil + if @deferred_timeout + @deferred_timeout.cancel + @deferred_timeout = nil + end + end + + + # Sugar for set_deferred_status(:succeeded, ...) + # + def succeed *args + set_deferred_status :succeeded, *args + end + alias set_deferred_success succeed + + # Sugar for set_deferred_status(:failed, ...) + # + def fail *args + set_deferred_status :failed, *args + end + alias set_deferred_failure fail + end + + + # DefaultDeferrable is an otherwise empty class that includes Deferrable. + # This is very useful when you just need to return a Deferrable object + # as a way of communicating deferred status to some other part of a program. + class DefaultDeferrable + include Deferrable + end +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/lib/em/deferrable/pool.rb b/bin/gems/eventmachine-1.2.7/lib/em/deferrable/pool.rb new file mode 100644 index 00000000..3c278eeb --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/deferrable/pool.rb @@ -0,0 +1,2 @@ +warn "EM::Deferrable::Pool is deprecated, please use EM::Pool" +EM::Deferrable::Pool = EM::Pool \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/lib/em/file_watch.rb b/bin/gems/eventmachine-1.2.7/lib/em/file_watch.rb new file mode 100644 index 00000000..074ffedc --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/file_watch.rb @@ -0,0 +1,73 @@ +module EventMachine + # Utility class that is useful for file monitoring. Supported events are + # + # * File is modified + # * File is deleted + # * File is moved + # + # @note On Mac OS X, file watching only works when kqueue is enabled + # + # @see EventMachine.watch_file + class FileWatch < Connection + # @private + Cmodified = 'modified'.freeze + # @private + Cdeleted = 'deleted'.freeze + # @private + Cmoved = 'moved'.freeze + + + # @private + def receive_data(data) + case data + when Cmodified + file_modified + when Cdeleted + file_deleted + when Cmoved + file_moved + end + end + + # Returns the path that is being monitored. + # + # @note Current implementation does not pick up on the new filename after a rename occurs. + # + # @return [String] + # @see EventMachine.watch_file + def path + @path + end + + # Will be called when the file is modified. Supposed to be redefined by subclasses. + # + # @abstract + def file_modified + end + + # Will be called when the file is deleted. Supposed to be redefined by subclasses. + # When the file is deleted, stop_watching will be called after this to make sure everything is + # cleaned up correctly. + # + # @note On Linux (with {http://en.wikipedia.org/wiki/Inotify inotify}), this method will not be called until *all* open file descriptors to + # the file have been closed. + # + # @abstract + def file_deleted + end + + # Will be called when the file is moved or renamed. Supposed to be redefined by subclasses. + # + # @abstract + def file_moved + end + + # Discontinue monitoring of the file. + # + # This involves cleaning up the underlying monitoring details with kqueue/inotify, and in turn firing {EventMachine::Connection#unbind}. + # This will be called automatically when a file is deleted. User code may call it as well. + def stop_watching + EventMachine::unwatch_filename(@signature) + end # stop_watching + end # FileWatch +end # EventMachine diff --git a/bin/gems/eventmachine-1.2.7/lib/em/future.rb b/bin/gems/eventmachine-1.2.7/lib/em/future.rb new file mode 100644 index 00000000..4affbf51 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/future.rb @@ -0,0 +1,61 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 Jul 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +#-- +# This defines EventMachine::Deferrable#future, which requires +# that the rest of EventMachine::Deferrable has already been seen. +# (It's in deferrable.rb.) + +module EventMachine + module Deferrable + + # A future is a sugaring of a typical deferrable usage. + #-- + # Evaluate arg (which may be an expression or a block). + # What's the class of arg? + # If arg is an ordinary expression, then return it. + # If arg is deferrable (responds to :set_deferred_status), + # then look at the arguments. If either callback or errback + # are defined, then use them. If neither are defined, then + # use the supplied block (if any) as the callback. + # Then return arg. + def self.future arg, cb=nil, eb=nil, &blk + arg = arg.call if arg.respond_to?(:call) + + if arg.respond_to?(:set_deferred_status) + if cb || eb + arg.callback(&cb) if cb + arg.errback(&eb) if eb + else + arg.callback(&blk) if blk + end + end + + arg + end + + end +end + diff --git a/bin/gems/eventmachine-1.2.7/lib/em/iterator.rb b/bin/gems/eventmachine-1.2.7/lib/em/iterator.rb new file mode 100644 index 00000000..a30b9dd7 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/iterator.rb @@ -0,0 +1,252 @@ +module EventMachine + # A simple iterator for concurrent asynchronous work. + # + # Unlike ruby's built-in iterators, the end of the current iteration cycle is signaled manually, + # instead of happening automatically after the yielded block finishes executing. For example: + # + # (0..10).each{ |num| } + # + # becomes: + # + # EM::Iterator.new(0..10).each{ |num,iter| iter.next } + # + # This is especially useful when doing asynchronous work via reactor libraries and + # functions. For example, given a sync and async http api: + # + # response = sync_http_get(url); ... + # async_http_get(url){ |response| ... } + # + # a synchronous iterator such as: + # + # responses = urls.map{ |url| sync_http_get(url) } + # ... + # puts 'all done!' + # + # could be written as: + # + # EM::Iterator.new(urls).map(proc{ |url,iter| + # async_http_get(url){ |res| + # iter.return(res) + # } + # }, proc{ |responses| + # ... + # puts 'all done!' + # }) + # + # Now, you can take advantage of the asynchronous api to issue requests in parallel. For example, + # to fetch 10 urls at a time, simply pass in a concurrency of 10: + # + # EM::Iterator.new(urls, 10).each do |url,iter| + # async_http_get(url){ iter.next } + # end + # + class Iterator + Stop = "EM::Stop" + # Create a new parallel async iterator with specified concurrency. + # + # i = EM::Iterator.new(1..100, 10) + # + # will create an iterator over the range that processes 10 items at a time. Iteration + # is started via #each, #map or #inject + # + # The list may either be an array-like object, or a proc that returns a new object + # to be processed each time it is called. If a proc is used, it must return + # EventMachine::Iterator::Stop to signal the end of the iterations. + # + def initialize(list, concurrency = 1) + raise ArgumentError, 'concurrency must be bigger than zero' unless (concurrency > 0) + if list.respond_to?(:call) + @list = nil + @list_proc = list + elsif list.respond_to?(:to_a) + @list = list.to_a.dup + @list_proc = nil + else + raise ArgumentError, 'argument must be a proc or an array' + end + @concurrency = concurrency + + @started = false + @ended = false + end + + # Change the concurrency of this iterator. Workers will automatically be spawned or destroyed + # to accomodate the new concurrency level. + # + def concurrency=(val) + old = @concurrency + @concurrency = val + + spawn_workers if val > old and @started and !@ended + end + attr_reader :concurrency + + # Iterate over a set of items using the specified block or proc. + # + # EM::Iterator.new(1..100).each do |num, iter| + # puts num + # iter.next + # end + # + # An optional second proc is invoked after the iteration is complete. + # + # EM::Iterator.new(1..100).each( + # proc{ |num,iter| iter.next }, + # proc{ puts 'all done' } + # ) + # + def each(foreach=nil, after=nil, &blk) + raise ArgumentError, 'proc or block required for iteration' unless foreach ||= blk + raise RuntimeError, 'cannot iterate over an iterator more than once' if @started or @ended + + @started = true + @pending = 0 + @workers = 0 + + all_done = proc{ + after.call if after and @ended and @pending == 0 + } + + @process_next = proc{ + # p [:process_next, :pending=, @pending, :workers=, @workers, :ended=, @ended, :concurrency=, @concurrency, :list=, @list] + unless @ended or @workers > @concurrency + item = next_item() + if item.equal?(Stop) + @ended = true + @workers -= 1 + all_done.call + else + @pending += 1 + + is_done = false + on_done = proc{ + raise RuntimeError, 'already completed this iteration' if is_done + is_done = true + + @pending -= 1 + + if @ended + all_done.call + else + EM.next_tick(@process_next) + end + } + class << on_done + alias :next :call + end + + foreach.call(item, on_done) + end + else + @workers -= 1 + end + } + + spawn_workers + + self + end + + # Collect the results of an asynchronous iteration into an array. + # + # EM::Iterator.new(%w[ pwd uptime uname date ], 2).map(proc{ |cmd,iter| + # EM.system(cmd){ |output,status| + # iter.return(output) + # } + # }, proc{ |results| + # p results + # }) + # + def map(foreach, after) + index = 0 + + inject([], proc{ |results,item,iter| + i = index + index += 1 + + is_done = false + on_done = proc{ |res| + raise RuntimeError, 'already returned a value for this iteration' if is_done + is_done = true + + results[i] = res + iter.return(results) + } + class << on_done + alias :return :call + def next + raise NoMethodError, 'must call #return on a map iterator' + end + end + + foreach.call(item, on_done) + }, proc{ |results| + after.call(results) + }) + end + + # Inject the results of an asynchronous iteration onto a given object. + # + # EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter| + # EM.system(cmd){ |output,status| + # hash[cmd] = status.exitstatus == 0 ? output.strip : nil + # iter.return(hash) + # } + # }, proc{ |results| + # p results + # }) + # + def inject(obj, foreach, after) + each(proc{ |item,iter| + is_done = false + on_done = proc{ |res| + raise RuntimeError, 'already returned a value for this iteration' if is_done + is_done = true + + obj = res + iter.next + } + class << on_done + alias :return :call + def next + raise NoMethodError, 'must call #return on an inject iterator' + end + end + + foreach.call(obj, item, on_done) + }, proc{ + after.call(obj) + }) + end + + private + + # Spawn workers to consume items from the iterator's enumerator based on the current concurrency level. + # + def spawn_workers + EM.next_tick(start_worker = proc{ + if @workers < @concurrency and !@ended + # p [:spawning_worker, :workers=, @workers, :concurrency=, @concurrency, :ended=, @ended] + @workers += 1 + @process_next.call + EM.next_tick(start_worker) + end + }) + nil + end + + # Return the next item from @list or @list_proc. + # Once items have run out, will return EM::Iterator::Stop. Procs must supply this themselves + def next_item + if @list_proc + @list_proc.call + else + @list.empty? ? Stop : @list.shift + end + end + end +end + +# TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next } +# TODO: support iter.pause/resume/stop/break/continue? +# TODO: create some exceptions instead of using RuntimeError diff --git a/bin/gems/eventmachine-1.2.7/lib/em/messages.rb b/bin/gems/eventmachine-1.2.7/lib/em/messages.rb new file mode 100644 index 00000000..9a51c390 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/messages.rb @@ -0,0 +1,66 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 Jul 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +=begin + +Message Routing in EventMachine. + +The goal here is to enable "routing points," objects that can send and receive +"messages," which are delimited streams of bytes. The boundaries of a message +are preserved as it passes through the reactor system. + +There will be several module methods defined in EventMachine to create route-point +objects (which will probably have a base class of EventMachine::MessageRouter +until someone suggests a better name). + +As with I/O objects, routing objects will receive events by having the router +core call methods on them. And of course user code can and will define handlers +to deal with events of interest. + +The message router base class only really needs a receive_message method. There will +be an EM module-method to send messages, in addition to the module methods to create +the various kinds of message receivers. + +The simplest kind of message receiver object can receive messages by being named +explicitly in a parameter to EM#send_message. More sophisticated receivers can define +pub-sub selectors and message-queue names. And they can also define channels for +route-points in other processes or even on other machines. + +A message is NOT a marshallable entity. Rather, it's a chunk of flat content more like +an Erlang message. Initially, all content submitted for transmission as a message will +have the to_s method called on it. Eventually, we'll be able to transmit certain structured +data types (XML and YAML documents, Structs within limits) and have them reconstructed +on the other end. + +A fundamental goal of the message-routing capability is to interoperate seamlessly with +external systems, including non-Ruby systems like ActiveMQ. We will define various protocol +handlers for things like Stomp and possibly AMQP, but these will be wrapped up and hidden +from the users of the basic routing capability. + +As with Erlang, a critical goal is for programs that are built to use message-passing to work +WITHOUT CHANGE when the code is re-based on a multi-process system. + +=end + diff --git a/bin/gems/eventmachine-1.2.7/lib/em/pool.rb b/bin/gems/eventmachine-1.2.7/lib/em/pool.rb new file mode 100644 index 00000000..2cb3662d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/pool.rb @@ -0,0 +1,151 @@ +module EventMachine + # A simple async resource pool based on a resource and work queue. Resources + # are enqueued and work waits for resources to become available. + # + # @example + # require 'em-http-request' + # + # EM.run do + # pool = EM::Pool.new + # spawn = lambda { pool.add EM::HttpRequest.new('http://example.org') } + # 10.times { spawn[] } + # done, scheduled = 0, 0 + # + # check = lambda do + # done += 1 + # if done >= scheduled + # EM.stop + # end + # end + # + # pool.on_error { |conn| spawn[] } + # + # 100.times do |i| + # scheduled += 1 + # pool.perform do |conn| + # req = conn.get :path => '/', :keepalive => true + # + # req.callback do + # p [:success, conn.object_id, i, req.response.size] + # check[] + # end + # + # req.errback { check[] } + # + # req + # end + # end + # end + # + # Resources are expected to be controlled by an object responding to a + # deferrable/completion style API with callback and errback blocks. + # + class Pool + + def initialize + @resources = EM::Queue.new + @removed = [] + @contents = [] + @on_error = nil + end + + def add resource + @contents << resource + requeue resource + end + + def remove resource + @contents.delete resource + @removed << resource + end + + # Returns a list for introspection purposes only. You should *NEVER* call + # modification or work oriented methods on objects in this list. A good + # example use case is periodic statistics collection against a set of + # connection resources. + # + # @example + # pool.contents.inject(0) { |sum, connection| connection.num_bytes } + def contents + @contents.dup + end + + # Define a default catch-all for when the deferrables returned by work + # blocks enter a failed state. By default all that happens is that the + # resource is returned to the pool. If on_error is defined, this block is + # responsible for re-adding the resource to the pool if it is still usable. + # In other words, it is generally assumed that on_error blocks explicitly + # handle the rest of the lifetime of the resource. + def on_error *a, &b + @on_error = EM::Callback(*a, &b) + end + + # Perform a given #call-able object or block. The callable object will be + # called with a resource from the pool as soon as one is available, and is + # expected to return a deferrable. + # + # The deferrable will have callback and errback added such that when the + # deferrable enters a finished state, the object is returned to the pool. + # + # If on_error is defined, then objects are not automatically returned to the + # pool. + def perform(*a, &b) + work = EM::Callback(*a, &b) + + @resources.pop do |resource| + if removed? resource + @removed.delete resource + reschedule work + else + process work, resource + end + end + end + alias reschedule perform + + # A peek at the number of enqueued jobs waiting for resources + def num_waiting + @resources.num_waiting + end + + # Removed will show resources in a partial pruned state. Resources in the + # removed list may not appear in the contents list if they are currently in + # use. + def removed? resource + @removed.include? resource + end + + protected + def requeue resource + @resources.push resource + end + + def failure resource + if @on_error + @contents.delete resource + @on_error.call resource + # Prevent users from calling a leak. + @removed.delete resource + else + requeue resource + end + end + + def completion deferrable, resource + deferrable.callback { requeue resource } + deferrable.errback { failure resource } + end + + def process work, resource + deferrable = work.call resource + if deferrable.kind_of?(EM::Deferrable) + completion deferrable, resource + else + raise ArgumentError, "deferrable expected from work" + end + rescue + failure resource + raise + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/process_watch.rb b/bin/gems/eventmachine-1.2.7/lib/em/process_watch.rb new file mode 100644 index 00000000..66e89438 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/process_watch.rb @@ -0,0 +1,45 @@ +module EventMachine + + # This is subclassed from EventMachine::Connection for use with the process monitoring API. Read the + # documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_process. + class ProcessWatch < Connection + # @private + Cfork = 'fork'.freeze + # @private + Cexit = 'exit'.freeze + + # @private + def receive_data(data) + case data + when Cfork + process_forked + when Cexit + process_exited + end + end + + # Returns the pid that EventMachine::watch_process was originally called with. + def pid + @pid + end + + # Should be redefined with the user's custom callback that will be fired when the prcess is forked. + # + # There is currently not an easy way to get the pid of the forked child. + def process_forked + end + + # Should be redefined with the user's custom callback that will be fired when the process exits. + # + # stop_watching is called automatically after this callback + def process_exited + end + + # Discontinue monitoring of the process. + # This will be called automatically when a process dies. User code may call it as well. + def stop_watching + EventMachine::unwatch_pid(@signature) + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/processes.rb b/bin/gems/eventmachine-1.2.7/lib/em/processes.rb new file mode 100644 index 00000000..4bbc14f6 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/processes.rb @@ -0,0 +1,123 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 13 Dec 07 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-08 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + + +module EventMachine + + # EM::DeferrableChildProcess is a sugaring of a common use-case + # involving EM::popen. + # Call the #open method on EM::DeferrableChildProcess, passing + # a command-string. #open immediately returns an EM::Deferrable + # object. It also schedules the forking of a child process, which + # will execute the command passed to #open. + # When the forked child terminates, the Deferrable will be signalled + # and execute its callbacks, passing the data that the child process + # wrote to stdout. + # + class DeferrableChildProcess < EventMachine::Connection + include EventMachine::Deferrable + + # @private + def initialize + super + @data = [] + end + + # Sugars a common use-case involving forked child processes. + # #open takes a String argument containing an shell command + # string (including arguments if desired). #open immediately + # returns an EventMachine::Deferrable object, without blocking. + # + # It also invokes EventMachine#popen to run the passed-in + # command in a forked child process. + # + # When the forked child terminates, the Deferrable that + # #open calls its callbacks, passing the data returned + # from the child process. + # + def self.open cmd + EventMachine.popen( cmd, DeferrableChildProcess ) + end + + # @private + def receive_data data + @data << data + end + + # @private + def unbind + succeed( @data.join ) + end + end + + # @private + class SystemCmd < EventMachine::Connection + def initialize cb + @cb = cb + @output = [] + end + def receive_data data + @output << data + end + def unbind + @cb.call @output.join(''), get_status if @cb + end + end + + # EM::system is a simple wrapper for EM::popen. It is similar to Kernel::system, but requires a + # single string argument for the command and performs no shell expansion. + # + # The block or proc passed to EM::system is called with two arguments: the output generated by the command, + # and a Process::Status that contains information about the command's execution. + # + # EM.run{ + # EM.system('ls'){ |output,status| puts output if status.exitstatus == 0 } + # } + # + # You can also supply an additional proc to send some data to the process: + # + # EM.run{ + # EM.system('sh', proc{ |process| + # process.send_data("echo hello\n") + # process.send_data("exit\n") + # }, proc{ |out,status| + # puts(out) + # }) + # } + # + # Like EventMachine.popen, EventMachine.system currently does not work on windows. + # It returns the pid of the spawned process. + def EventMachine::system cmd, *args, &cb + cb ||= args.pop if args.last.is_a? Proc + init = args.pop if args.last.is_a? Proc + + # merge remaining arguments into the command + cmd = [cmd, *args] if args.any? + + EM.get_subprocess_pid(EM.popen(cmd, SystemCmd, cb) do |c| + init[c] if init + end.signature) + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols.rb new file mode 100644 index 00000000..0c179064 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols.rb @@ -0,0 +1,37 @@ +module EventMachine + # This module contains various protocol implementations, including: + # - HttpClient and HttpClient2 + # - Stomp + # - Memcache + # - SmtpClient and SmtpServer + # - SASLauth and SASLauthclient + # - LineProtocol, LineAndTextProtocol and LineText2 + # - HeaderAndContentProtocol + # - Postgres3 + # - ObjectProtocol + # + # The protocol implementations live in separate files in the protocols/ subdirectory, + # but are auto-loaded when they are first referenced in your application. + # + # EventMachine::Protocols is also aliased to EM::P for easier usage. + # + module Protocols + # TODO : various autotools are completely useless with the lack of naming + # convention, we need to correct that! + autoload :TcpConnectTester, 'em/protocols/tcptest' + autoload :HttpClient, 'em/protocols/httpclient' + autoload :HttpClient2, 'em/protocols/httpclient2' + autoload :LineAndTextProtocol, 'em/protocols/line_and_text' + autoload :HeaderAndContentProtocol, 'em/protocols/header_and_content' + autoload :LineText2, 'em/protocols/linetext2' + autoload :Stomp, 'em/protocols/stomp' + autoload :SmtpClient, 'em/protocols/smtpclient' + autoload :SmtpServer, 'em/protocols/smtpserver' + autoload :SASLauth, 'em/protocols/saslauth' + autoload :Memcache, 'em/protocols/memcache' + autoload :Postgres3, 'em/protocols/postgres3' + autoload :ObjectProtocol, 'em/protocols/object_protocol' + autoload :Socks4, 'em/protocols/socks4' + autoload :LineProtocol, 'em/protocols/line_protocol' + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/header_and_content.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/header_and_content.rb new file mode 100644 index 00000000..b5a465aa --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/header_and_content.rb @@ -0,0 +1,138 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 Nov 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Protocols + + # === Usage + # + # class RequestHandler < EM::P::HeaderAndContentProtocol + # def receive_request headers, content + # p [:request, headers, content] + # end + # end + # + # EM.run{ + # EM.start_server 'localhost', 80, RequestHandler + # } + # + #-- + # Originally, this subclassed LineAndTextProtocol, which in + # turn relies on BufferedTokenizer, which doesn't gracefully + # handle the transitions between lines and binary text. + # Changed 13Sep08 by FCianfrocca. + class HeaderAndContentProtocol < Connection + include LineText2 + + ContentLengthPattern = /Content-length:\s*(\d+)/i + + def initialize *args + super + init_for_request + end + + def receive_line line + case @hc_mode + when :discard_blanks + unless line == "" + @hc_mode = :headers + receive_line line + end + when :headers + if line == "" + raise "unrecognized state" unless @hc_headers.length > 0 + if respond_to?(:receive_headers) + receive_headers @hc_headers + end + # @hc_content_length will be nil, not 0, if there was no content-length header. + if @hc_content_length.to_i > 0 + set_binary_mode @hc_content_length + else + dispatch_request + end + else + @hc_headers << line + if ContentLengthPattern =~ line + # There are some attacks that rely on sending multiple content-length + # headers. This is a crude protection, but needs to become tunable. + raise "extraneous content-length header" if @hc_content_length + @hc_content_length = $1.to_i + end + if @hc_headers.length == 1 and respond_to?(:receive_first_header_line) + receive_first_header_line line + end + end + else + raise "internal error, unsupported mode" + end + end + + def receive_binary_data text + @hc_content = text + dispatch_request + end + + def dispatch_request + if respond_to?(:receive_request) + receive_request @hc_headers, @hc_content + end + init_for_request + end + private :dispatch_request + + def init_for_request + @hc_mode = :discard_blanks + @hc_headers = [] + # originally was @hc_headers ||= []; @hc_headers.clear to get a performance + # boost, but it's counterproductive because a subclassed handler will have to + # call dup to use the header array we pass in receive_headers. + + @hc_content_length = nil + @hc_content = "" + end + private :init_for_request + + # Basically a convenience method. We might create a subclass that does this + # automatically. But it's such a performance killer. + def headers_2_hash hdrs + self.class.headers_2_hash hdrs + end + + class << self + def headers_2_hash hdrs + hash = {} + hdrs.each {|h| + if /\A([^\s:]+)\s*:\s*/ =~ h + tail = $'.dup + hash[ $1.downcase.gsub(/-/,"_").intern ] = tail + end + } + hash + end + end + + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient.rb new file mode 100644 index 00000000..38b175ce --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient.rb @@ -0,0 +1,300 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 July 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Protocols + + # Note: This class is deprecated and will be removed. Please use EM-HTTP-Request instead. + # + # @example + # EventMachine.run { + # http = EventMachine::Protocols::HttpClient.request( + # :host => server, + # :port => 80, + # :request => "/index.html", + # :query_string => "parm1=value1&parm2=value2" + # ) + # http.callback {|response| + # puts response[:status] + # puts response[:headers] + # puts response[:content] + # } + # } + #-- + # TODO: + # Add streaming so we can support enormous POSTs. Current max is 20meg. + # Timeout for connections that run too long or hang somewhere in the middle. + # Persistent connections (HTTP/1.1), may need a associated delegate object. + # DNS: Some way to cache DNS lookups for hostnames we connect to. Ruby's + # DNS lookups are unbelievably slow. + # HEAD requests. + # Convenience methods for requests. get, post, url, etc. + # SSL. + # Handle status codes like 304, 100, etc. + # Refactor this code so that protocol errors all get handled one way (an exception?), + # instead of sprinkling set_deferred_status :failed calls everywhere. + class HttpClient < Connection + include EventMachine::Deferrable + + MaxPostContentLength = 20 * 1024 * 1024 + + def initialize + warn "HttpClient is deprecated and will be removed. EM-Http-Request should be used instead." + @connected = false + end + + # @param args [Hash] The request arguments + # @option args [String] :host The host IP/DNS name + # @option args [Integer] :port The port to connect too + # @option args [String] :verb The request type [GET | POST | DELETE | PUT] + # @option args [String] :request The request path + # @option args [Hash] :basic_auth The basic auth credentials (:username and :password) + # @option args [String] :content The request content + # @option args [String] :contenttype The content type (e.g. text/plain) + # @option args [String] :query_string The query string + # @option args [String] :host_header The host header to set + # @option args [String] :cookie Cookies to set + def self.request( args = {} ) + args[:port] ||= 80 + EventMachine.connect( args[:host], args[:port], self ) {|c| + # According to the docs, we will get here AFTER post_init is called. + c.instance_eval {@args = args} + } + end + + def post_init + @start_time = Time.now + @data = "" + @read_state = :base + end + + # We send the request when we get a connection. + # AND, we set an instance variable to indicate we passed through here. + # That allows #unbind to know whether there was a successful connection. + # NB: This naive technique won't work when we have to support multiple + # requests on a single connection. + def connection_completed + @connected = true + send_request @args + end + + def send_request args + args[:verb] ||= args[:method] # Support :method as an alternative to :verb. + args[:verb] ||= :get # IS THIS A GOOD IDEA, to default to GET if nothing was specified? + + verb = args[:verb].to_s.upcase + unless ["GET", "POST", "PUT", "DELETE", "HEAD"].include?(verb) + set_deferred_status :failed, {:status => 0} # TODO, not signalling the error type + return # NOTE THE EARLY RETURN, we're not sending any data. + end + + request = args[:request] || "/" + unless request[0,1] == "/" + request = "/" + request + end + + qs = args[:query_string] || "" + if qs.length > 0 and qs[0,1] != '?' + qs = "?" + qs + end + + version = args[:version] || "1.1" + + # Allow an override for the host header if it's not the connect-string. + host = args[:host_header] || args[:host] || "_" + # For now, ALWAYS tuck in the port string, although we may want to omit it if it's the default. + port = args[:port].to_i != 80 ? ":#{args[:port]}" : "" + + # POST items. + postcontenttype = args[:contenttype] || "application/octet-stream" + postcontent = args[:content] || "" + raise "oversized content in HTTP POST" if postcontent.length > MaxPostContentLength + + # ESSENTIAL for the request's line-endings to be CRLF, not LF. Some servers misbehave otherwise. + # TODO: We ASSUME the caller wants to send a 1.1 request. May not be a good assumption. + req = [ + "#{verb} #{request}#{qs} HTTP/#{version}", + "Host: #{host}#{port}", + "User-agent: Ruby EventMachine", + ] + + if verb == "POST" || verb == "PUT" + req << "Content-type: #{postcontenttype}" + req << "Content-length: #{postcontent.length}" + end + + # TODO, this cookie handler assumes it's getting a single, semicolon-delimited string. + # Eventually we will want to deal intelligently with arrays and hashes. + if args[:cookie] + req << "Cookie: #{args[:cookie]}" + end + + # Allow custom HTTP headers, e.g. SOAPAction + args[:custom_headers].each do |k,v| + req << "#{k}: #{v}" + end if args[:custom_headers] + + # Basic-auth stanza contributed by Matt Murphy. + if args[:basic_auth] + basic_auth_string = ["#{args[:basic_auth][:username]}:#{args[:basic_auth][:password]}"].pack('m').strip.gsub(/\n/,'') + req << "Authorization: Basic #{basic_auth_string}" + end + + req << "" + reqstring = req.map {|l| "#{l}\r\n"}.join + send_data reqstring + + if verb == "POST" || verb == "PUT" + send_data postcontent + end + end + + + def receive_data data + while data and data.length > 0 + case @read_state + when :base + # Perform any per-request initialization here and don't consume any data. + @data = "" + @headers = [] + @content_length = nil # not zero + @content = "" + @status = nil + @chunked = false + @chunk_length = nil + @read_state = :header + @connection_close = nil + when :header + ary = data.split( /\r?\n/m, 2 ) + if ary.length == 2 + data = ary.last + if ary.first == "" + if (@content_length and @content_length > 0) || @chunked || @connection_close + @read_state = :content + else + dispatch_response + @read_state = :base + end + else + @headers << ary.first + if @headers.length == 1 + parse_response_line + elsif ary.first =~ /\Acontent-length:\s*/i + # Only take the FIRST content-length header that appears, + # which we can distinguish because @content_length is nil. + # TODO, it's actually a fatal error if there is more than one + # content-length header, because the caller is presumptively + # a bad guy. (There is an exploit that depends on multiple + # content-length headers.) + @content_length ||= $'.to_i + elsif ary.first =~ /\Aconnection:\s*close/i + @connection_close = true + elsif ary.first =~ /\Atransfer-encoding:\s*chunked/i + @chunked = true + end + end + else + @data << data + data = "" + end + when :content + if @chunked && @chunk_length + bytes_needed = @chunk_length - @chunk_read + new_data = data[0, bytes_needed] + @chunk_read += new_data.length + @content += new_data + data = data[bytes_needed..-1] || "" + if @chunk_length == @chunk_read && data[0,2] == "\r\n" + @chunk_length = nil + data = data[2..-1] + end + elsif @chunked + if (m = data.match(/\A(\S*)\r\n/m)) + data = data[m[0].length..-1] + @chunk_length = m[1].to_i(16) + @chunk_read = 0 + if @chunk_length == 0 + dispatch_response + @read_state = :base + end + end + elsif @content_length + # If there was no content-length header, we have to wait until the connection + # closes. Everything we get until that point is content. + # TODO: Must impose a content-size limit, and also must implement chunking. + # Also, must support either temporary files for large content, or calling + # a content-consumer block supplied by the user. + bytes_needed = @content_length - @content.length + @content += data[0, bytes_needed] + data = data[bytes_needed..-1] || "" + if @content_length == @content.length + dispatch_response + @read_state = :base + end + else + @content << data + data = "" + end + end + end + end + + + # We get called here when we have received an HTTP response line. + # It's an opportunity to throw an exception or trigger other exceptional + # handling. + def parse_response_line + if @headers.first =~ /\AHTTP\/1\.[01] ([\d]{3})/ + @status = $1.to_i + else + set_deferred_status :failed, { + :status => 0 # crappy way of signifying an unrecognized response. TODO, find a better way to do this. + } + close_connection + end + end + private :parse_response_line + + def dispatch_response + @read_state = :base + set_deferred_status :succeeded, { + :content => @content, + :headers => @headers, + :status => @status + } + # TODO, we close the connection for now, but this is wrong for persistent clients. + close_connection + end + + def unbind + if !@connected + set_deferred_status :failed, {:status => 0} # YECCCCH. Find a better way to signal no-connect/network error. + elsif (@read_state == :content and @content_length == nil) + dispatch_response + end + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient2.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient2.rb new file mode 100644 index 00000000..0fb64e80 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/httpclient2.rb @@ -0,0 +1,600 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 July 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Protocols + + # Note: This class is deprecated and will be removed. Please use EM-HTTP-Request instead. + # + # === Usage + # + # EM.run{ + # conn = EM::Protocols::HttpClient2.connect 'google.com', 80 + # + # req = conn.get('/') + # req.callback{ |response| + # p(response.status) + # p(response.headers) + # p(response.content) + # } + # } + class HttpClient2 < Connection + include LineText2 + + def initialize + warn "HttpClient2 is deprecated and will be removed. EM-Http-Request should be used instead." + + @authorization = nil + @closed = nil + @requests = nil + end + + # @private + class Request + include Deferrable + + attr_reader :version + attr_reader :status + attr_reader :header_lines + attr_reader :headers + attr_reader :content + attr_reader :internal_error + + def initialize conn, args + @conn = conn + @args = args + @header_lines = [] + @headers = {} + @blanks = 0 + @chunk_trailer = nil + @chunking = nil + end + + def send_request + az = @args[:authorization] and az = "Authorization: #{az}\r\n" + + r = [ + "#{@args[:verb]} #{@args[:uri]} HTTP/#{@args[:version] || "1.1"}\r\n", + "Host: #{@args[:host_header] || "_"}\r\n", + az || "", + "\r\n" + ] + @conn.send_data r.join + end + + + #-- + # + def receive_line ln + if @chunk_trailer + receive_chunk_trailer(ln) + elsif @chunking + receive_chunk_header(ln) + else + receive_header_line(ln) + end + end + + #-- + # + def receive_chunk_trailer ln + if ln.length == 0 + @conn.pop_request + succeed(self) + else + p "Received chunk trailer line" + end + end + + #-- + # Allow up to ten blank lines before we get a real response line. + # Allow no more than 100 lines in the header. + # + def receive_header_line ln + if ln.length == 0 + if @header_lines.length > 0 + process_header + else + @blanks += 1 + if @blanks > 10 + @conn.close_connection + end + end + else + @header_lines << ln + if @header_lines.length > 100 + @internal_error = :bad_header + @conn.close_connection + end + end + end + + #-- + # Cf RFC 2616 pgh 3.6.1 for the format of HTTP chunks. + # + def receive_chunk_header ln + if ln.length > 0 + chunksize = ln.to_i(16) + if chunksize > 0 + @conn.set_text_mode(ln.to_i(16)) + else + @content = @content ? @content.join : '' + @chunk_trailer = true + end + else + # We correctly come here after each chunk gets read. + # p "Got A BLANK chunk line" + end + + end + + + #-- + # We get a single chunk. Append it to the incoming content and switch back to line mode. + # + def receive_chunked_text text + # p "RECEIVED #{text.length} CHUNK" + (@content ||= []) << text + end + + + #-- + # TODO, inefficient how we're handling this. Part of it is done so as to + # make sure we don't have problems in detecting chunked-encoding, content-length, + # etc. + # + HttpResponseRE = /\AHTTP\/(1.[01]) ([\d]{3})/i + ClenRE = /\AContent-length:\s*(\d+)/i + ChunkedRE = /\ATransfer-encoding:\s*chunked/i + ColonRE = /\:\s*/ + + def process_header + unless @header_lines.first =~ HttpResponseRE + @conn.close_connection + @internal_error = :bad_request + end + @version = $1.dup + @status = $2.dup.to_i + + clen = nil + chunks = nil + @header_lines.each_with_index do |e,ix| + if ix > 0 + hdr,val = e.split(ColonRE,2) + (@headers[hdr.downcase] ||= []) << val + end + + if clen == nil and e =~ ClenRE + clen = $1.dup.to_i + end + if e =~ ChunkedRE + chunks = true + end + end + + if clen + # If the content length is zero we should not call set_text_mode, + # because a value of zero will make it wait forever, hanging the + # connection. Just return success instead, with empty content. + if clen == 0 then + @content = "" + @conn.pop_request + succeed(self) + else + @conn.set_text_mode clen + end + elsif chunks + @chunking = true + else + # Chunked transfer, multipart, or end-of-connection. + # For end-of-connection, we need to go the unbind + # method and suppress its desire to fail us. + p "NO CLEN" + p @args[:uri] + p @header_lines + @internal_error = :unsupported_clen + @conn.close_connection + end + end + private :process_header + + + def receive_text text + @chunking ? receive_chunked_text(text) : receive_sized_text(text) + end + + #-- + # At the present time, we only handle contents that have a length + # specified by the content-length header. + # + def receive_sized_text text + @content = text + @conn.pop_request + succeed(self) + end + end + + # Make a connection to a remote HTTP server. + # Can take either a pair of arguments (which will be interpreted as + # a hostname/ip-address and a port), or a hash. + # If the arguments are a hash, then supported values include: + # :host => a hostname or ip-address + # :port => a port number + # :ssl => true to enable ssl + def self.connect *args + if args.length == 2 + args = {:host=>args[0], :port=>args[1]} + else + args = args.first + end + + h,prt,ssl = args[:host], Integer(args[:port]), (args[:tls] || args[:ssl]) + conn = EM.connect( h, prt, self ) + conn.start_tls if ssl + conn.set_default_host_header( h, prt, ssl ) + conn + end + + # Get a url + # + # req = conn.get(:uri => '/') + # req.callback{|response| puts response.content } + # + def get args + if args.is_a?(String) + args = {:uri=>args} + end + args[:verb] = "GET" + request args + end + + # Post to a url + # + # req = conn.post('/data') + # req.callback{|response| puts response.content } + #-- + # XXX there's no way to supply a POST body.. wtf? + def post args + if args.is_a?(String) + args = {:uri=>args} + end + args[:verb] = "POST" + request args + end + + + #-- + # Compute and remember a string to be used as the host header in HTTP requests + # unless the user overrides it with an argument to #request. + # + # @private + def set_default_host_header host, port, ssl + if (ssl and port != 443) or (!ssl and port != 80) + @host_header = "#{host}:#{port}" + else + @host_header = host + end + end + + + # @private + def post_init + super + @connected = EM::DefaultDeferrable.new + end + + # @private + def connection_completed + super + @connected.succeed + end + + #-- + # All pending requests, if any, must fail. + # We might come here without ever passing through connection_completed + # in case we can't connect to the server. We'll also get here when the + # connection closes (either because the server closes it, or we close it + # due to detecting an internal error or security violation). + # In either case, run down all pending requests, if any, and signal failure + # on them. + # + # Set and remember a flag (@closed) so we can immediately fail any + # subsequent requests. + # + # @private + def unbind + super + @closed = true + (@requests || []).each {|r| r.fail} + end + + # @private + def request args + args[:host_header] = @host_header unless args.has_key?(:host_header) + args[:authorization] = @authorization unless args.has_key?(:authorization) + r = Request.new self, args + if @closed + r.fail + else + (@requests ||= []).unshift r + @connected.callback {r.send_request} + end + r + end + + # @private + def receive_line ln + if req = @requests.last + req.receive_line ln + else + p "??????????" + p ln + end + end + + # @private + def receive_binary_data text + @requests.last.receive_text text + end + + #-- + # Called by a Request object when it completes. + # + # @private + def pop_request + @requests.pop + end + end + + +=begin + class HttpClient2x < Connection + include LineText2 + + # TODO: Make this behave appropriate in case a #connect fails. + # Currently, this produces no errors. + + # Make a connection to a remote HTTP server. + # Can take either a pair of arguments (which will be interpreted as + # a hostname/ip-address and a port), or a hash. + # If the arguments are a hash, then supported values include: + # :host => a hostname or ip-address; + # :port => a port number + #-- + # TODO, support optional encryption arguments like :ssl + def self.connect *args + if args.length == 2 + args = {:host=>args[0], :port=>args[1]} + else + args = args.first + end + + h,prt = args[:host],Integer(args[:port]) + EM.connect( h, prt, self, h, prt ) + end + + + #-- + # Sugars a connection that makes a single request and then + # closes the connection. Matches the behavior and the arguments + # of the original implementation of class HttpClient. + # + # Intended primarily for back compatibility, but the idiom + # is probably useful so it's not deprecated. + # We return a Deferrable, as did the original implementation. + # + # Because we're improving the way we deal with errors and exceptions + # (specifically, HTTP response codes other than 2xx will trigger the + # errback rather than the callback), this may break some existing code. + # + def self.request args + c = connect args + end + + #-- + # Requests can be pipelined. When we get a request, add it to the + # front of a queue as an array. The last element of the @requests + # array is always the oldest request received. Each element of the + # @requests array is a two-element array consisting of a hash with + # the original caller's arguments, and an initially-empty Ostruct + # containing the data we retrieve from the server's response. + # Maintain the instance variable @current_response, which is the response + # of the oldest pending request. That's just to make other code a little + # easier. If the variable doesn't exist when we come here, we're + # obviously the first request being made on the connection. + # + # The reason for keeping this method private (and requiring use of the + # convenience methods #get, #post, #head, etc) is to avoid the small + # performance penalty of canonicalizing the verb. + # + def request args + d = EventMachine::DefaultDeferrable.new + + if @closed + d.fail + return d + end + + o = OpenStruct.new + o.deferrable = d + (@requests ||= []).unshift [args, o] + @current_response ||= @requests.last.last + @connected.callback { + az = args[:authorization] and az = "Authorization: #{az}\r\n" + + r = [ + "#{args[:verb]} #{args[:uri]} HTTP/#{args[:version] || "1.1"}\r\n", + "Host: #{args[:host_header] || @host_header}\r\n", + az || "", + "\r\n" + ] + p r + send_data r.join + } + o.deferrable + end + private :request + + def get args + if args.is_a?(String) + args = {:uri=>args} + end + args[:verb] = "GET" + request args + end + + def initialize host, port + super + @host_header = "#{host}:#{port}" + end + def post_init + super + @connected = EM::DefaultDeferrable.new + end + + + def connection_completed + super + @connected.succeed + end + + #-- + # Make sure to throw away any leftover incoming data if we've + # been closed due to recognizing an error. + # + # Generate an internal error if we get an unreasonable number of + # header lines. It could be malicious. + # + def receive_line ln + p ln + return if @closed + + if ln.length > 0 + (@current_response.headers ||= []).push ln + abort_connection if @current_response.headers.length > 100 + else + process_received_headers + end + end + + #-- + # We come here when we've seen all the headers for a particular request. + # What we do next depends on the response line (which should be the + # first line in the header set), and whether there is content to read. + # We may transition into a text-reading state to read content, or + # we may abort the connection, or we may go right back into parsing + # responses for the next response in the chain. + # + # We make an ASSUMPTION that the first line is an HTTP response. + # Anything else produces an error that aborts the connection. + # This may not be enough, because it may be that responses to pipelined + # requests will come with a blank-line delimiter. + # + # Any non-2xx response will be treated as a fatal error, and abort the + # connection. We will set up the status and other response parameters. + # TODO: we will want to properly support 1xx responses, which some versions + # of IIS copiously generate. + # TODO: We need to give the option of not aborting the connection with certain + # non-200 responses, in order to work with NTLM and other authentication + # schemes that work at the level of individual connections. + # + # Some error responses will get sugarings. For example, we'll return the + # Location header in the response in case of a 301/302 response. + # + # Possible dispositions here: + # 1) No content to read (either content-length is zero or it's a HEAD request); + # 2) Switch to text mode to read a specific number of bytes; + # 3) Read a chunked or multipart response; + # 4) Read till the server closes the connection. + # + # Our reponse to the client can be either to wait till all the content + # has been read and then to signal caller's deferrable, or else to signal + # it when we finish the processing the headers and then expect the caller + # to have given us a block to call as the content comes in. And of course + # the latter gets stickier with chunks and multiparts. + # + HttpResponseRE = /\AHTTP\/(1.[01]) ([\d]{3})/i + ClenRE = /\AContent-length:\s*(\d+)/i + def process_received_headers + abort_connection unless @current_response.headers.first =~ HttpResponseRE + @current_response.version = $1.dup + st = $2.dup + @current_response.status = st.to_i + abort_connection unless st[0,1] == "2" + + clen = nil + @current_response.headers.each do |e| + if clen == nil and e =~ ClenRE + clen = $1.dup.to_i + end + end + + if clen + set_text_mode clen + end + end + private :process_received_headers + + + def receive_binary_data text + @current_response.content = text + @current_response.deferrable.succeed @current_response + @requests.pop + @current_response = (@requests.last || []).last + set_line_mode + end + + + + # We've received either a server error or an internal error. + # Close the connection and abort any pending requests. + #-- + # When should we call close_connection? It will cause #unbind + # to be fired. Should the user expect to see #unbind before + # we call #receive_http_error, or the other way around? + # + # Set instance variable @closed. That's used to inhibit further + # processing of any inbound data after an error has been recognized. + # + # We shouldn't have to worry about any leftover outbound data, + # because we call close_connection (not close_connection_after_writing). + # That ensures that any pipelined requests received after an error + # DO NOT get streamed out to the server on this connection. + # Very important. TODO, write a unit-test to establish that behavior. + # + def abort_connection + close_connection + @closed = true + @current_response.deferrable.fail( @current_response ) + end + + + #------------------------ + # Below here are user-overridable methods. + + end +=end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_and_text.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_and_text.rb new file mode 100644 index 00000000..784daf2f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_and_text.rb @@ -0,0 +1,125 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 November 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# +# + +module EventMachine + module Protocols + # A protocol that handles line-oriented data with interspersed binary text. + # + # This version is optimized for performance. See EventMachine::Protocols::LineText2 + # for a version which is optimized for correctness with regard to binary text blocks + # that can switch back to line mode. + class LineAndTextProtocol < Connection + MaxBinaryLength = 32*1024*1024 + + def initialize *args + super + lbp_init_line_state + end + + def receive_data data + if @lbp_mode == :lines + begin + @lpb_buffer.extract(data).each do |line| + receive_line(line.chomp) if respond_to?(:receive_line) + end + rescue + receive_error('overlength line') if respond_to?(:receive_error) + close_connection + return + end + else + if @lbp_binary_limit > 0 + wanted = @lbp_binary_limit - @lbp_binary_bytes_received + chunk = nil + if data.length > wanted + chunk = data.slice!(0...wanted) + else + chunk = data + data = "" + end + @lbp_binary_buffer[@lbp_binary_bytes_received...(@lbp_binary_bytes_received+chunk.length)] = chunk + @lbp_binary_bytes_received += chunk.length + if @lbp_binary_bytes_received == @lbp_binary_limit + receive_binary_data(@lbp_binary_buffer) if respond_to?(:receive_binary_data) + lbp_init_line_state + end + receive_data(data) if data.length > 0 + else + receive_binary_data(data) if respond_to?(:receive_binary_data) + data = "" + end + end + end + + def unbind + if @lbp_mode == :binary and @lbp_binary_limit > 0 + if respond_to?(:receive_binary_data) + receive_binary_data( @lbp_binary_buffer[0...@lbp_binary_bytes_received] ) + end + end + end + + # Set up to read the supplied number of binary bytes. + # This recycles all the data currently waiting in the line buffer, if any. + # If the limit is nil, then ALL subsequent data will be treated as binary + # data and passed to the upstream protocol handler as we receive it. + # If a limit is given, we'll hold the incoming binary data and not + # pass it upstream until we've seen it all, or until there is an unbind + # (in which case we'll pass up a partial). + # Specifying nil for the limit (the default) means there is no limit. + # Specifiyng zero for the limit will cause an immediate transition back to line mode. + # + def set_binary_mode size = nil + if @lbp_mode == :lines + if size == 0 + receive_binary_data("") if respond_to?(:receive_binary_data) + # Do no more work here. Stay in line mode and keep consuming data. + else + @lbp_binary_limit = size.to_i # (nil will be stored as zero) + if @lbp_binary_limit > 0 + raise "Overlength" if @lbp_binary_limit > MaxBinaryLength # arbitrary sanity check + @lbp_binary_buffer = "\0" * @lbp_binary_limit + @lbp_binary_bytes_received = 0 + end + + @lbp_mode = :binary + receive_data @lpb_buffer.flush + end + else + raise "invalid operation" + end + end + + #-- + # For internal use, establish protocol baseline for handling lines. + def lbp_init_line_state + @lpb_buffer = BufferedTokenizer.new("\n") + @lbp_mode = :lines + end + private :lbp_init_line_state + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_protocol.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_protocol.rb new file mode 100644 index 00000000..dfddae8c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/line_protocol.rb @@ -0,0 +1,29 @@ +module EventMachine + module Protocols + # LineProtocol will parse out newline terminated strings from a receive_data stream + # + # module Server + # include EM::P::LineProtocol + # + # def receive_line(line) + # send_data("you said: #{line}") + # end + # end + # + module LineProtocol + # @private + def receive_data data + (@buf ||= '') << data + + while @buf.slice!(/(.*?)\r?\n/) + receive_line($1) + end + end + + # Invoked with lines received over the network + def receive_line(line) + # stub + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/linetext2.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/linetext2.rb new file mode 100644 index 00000000..9fdf28bd --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/linetext2.rb @@ -0,0 +1,179 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 November 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Protocols + # In the grand, time-honored tradition of re-inventing the wheel, we offer + # here YET ANOTHER protocol that handles line-oriented data with interspersed + # binary text. This one trades away some of the performance optimizations of + # EventMachine::Protocols::LineAndTextProtocol in order to get better correctness + # with regard to binary text blocks that can switch back to line mode. It also + # permits the line-delimiter to change in midstream. + # This was originally written to support Stomp. + module LineText2 + # TODO! We're not enforcing the limits on header lengths and text-lengths. + # When we get around to that, call #receive_error if the user defined it, otherwise + # throw exceptions. + + MaxBinaryLength = 32*1024*1024 + + #-- + # Will loop internally until there's no data left to read. + # That way the user-defined handlers we call can modify the + # handling characteristics on a per-token basis. + # + def receive_data data + return unless (data and data.length > 0) + + # Do this stuff in lieu of a constructor. + @lt2_mode ||= :lines + @lt2_delimiter ||= "\n" + @lt2_linebuffer ||= [] + + remaining_data = data + + while remaining_data.length > 0 + if @lt2_mode == :lines + delimiter_string = case @lt2_delimiter + when Regexp + remaining_data.slice(@lt2_delimiter) + else + @lt2_delimiter + end + ix = remaining_data.index(delimiter_string) if delimiter_string + if ix + @lt2_linebuffer << remaining_data[0...ix] + ln = @lt2_linebuffer.join + @lt2_linebuffer.clear + if @lt2_delimiter == "\n" + ln.chomp! + end + receive_line ln + remaining_data = remaining_data[(ix+delimiter_string.length)..-1] + else + @lt2_linebuffer << remaining_data + remaining_data = "" + end + elsif @lt2_mode == :text + if @lt2_textsize + needed = @lt2_textsize - @lt2_textpos + will_take = if remaining_data.length > needed + needed + else + remaining_data.length + end + + @lt2_textbuffer << remaining_data[0...will_take] + tail = remaining_data[will_take..-1] + + @lt2_textpos += will_take + if @lt2_textpos >= @lt2_textsize + # Reset line mode (the default behavior) BEFORE calling the + # receive_binary_data. This makes it possible for user code + # to call set_text_mode, enabling chains of text blocks + # (which can possibly be of different sizes). + set_line_mode + receive_binary_data @lt2_textbuffer.join + receive_end_of_binary_data + end + + remaining_data = tail + else + receive_binary_data remaining_data + remaining_data = "" + end + end + end + end + + # The line delimiter may be a regular expression or a string. Anything + # passed to set_delimiter other than a regular expression will be + # converted to a string. + def set_delimiter delim + @lt2_delimiter = case delim + when Regexp + delim + else + delim.to_s + end + end + + # Called internally but also exposed to user code, for the case in which + # processing of binary data creates a need to transition back to line mode. + # We support an optional parameter to "throw back" some data, which might + # be an umprocessed chunk of the transmitted binary data, or something else + # entirely. + def set_line_mode data="" + @lt2_mode = :lines + (@lt2_linebuffer ||= []).clear + receive_data data.to_s + end + + def set_text_mode size=nil + if size == 0 + set_line_mode + else + @lt2_mode = :text + (@lt2_textbuffer ||= []).clear + @lt2_textsize = size # which can be nil, signifying no limit + @lt2_textpos = 0 + end + end + + # Alias for #set_text_mode, added for back-compatibility with LineAndTextProtocol. + def set_binary_mode size=nil + set_text_mode size + end + + # In case of a dropped connection, we'll send a partial buffer to user code + # when in sized text mode. User overrides of #receive_binary_data need to + # be aware that they may get a short buffer. + def unbind + @lt2_mode ||= nil + if @lt2_mode == :text and @lt2_textpos > 0 + receive_binary_data @lt2_textbuffer.join + end + end + + # Stub. Should be subclassed by user code. + def receive_line ln + # no-op + end + + # Stub. Should be subclassed by user code. + def receive_binary_data data + # no-op + end + + # Stub. Should be subclassed by user code. + # This is called when transitioning internally from text mode + # back to line mode. Useful when client code doesn't want + # to keep track of how much data it's received. + def receive_end_of_binary_data + # no-op + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/memcache.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/memcache.rb new file mode 100644 index 00000000..1f81aaf9 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/memcache.rb @@ -0,0 +1,331 @@ +module EventMachine + module Protocols + # Implements the Memcache protocol (http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt). + # Requires memcached >= 1.2.4 w/ noreply support + # + # == Usage example + # + # EM.run{ + # cache = EM::P::Memcache.connect 'localhost', 11211 + # + # cache.set :a, 'hello' + # cache.set :b, 'hi' + # cache.set :c, 'how are you?' + # cache.set :d, '' + # + # cache.get(:a){ |v| p v } + # cache.get_hash(:a, :b, :c, :d){ |v| p v } + # cache.get(:a,:b,:c,:d){ |a,b,c,d| p [a,b,c,d] } + # + # cache.get(:a,:z,:b,:y,:d){ |a,z,b,y,d| p [a,z,b,y,d] } + # + # cache.get(:missing){ |m| p [:missing=, m] } + # cache.set(:missing, 'abc'){ p :stored } + # cache.get(:missing){ |m| p [:missing=, m] } + # cache.del(:missing){ p :deleted } + # cache.get(:missing){ |m| p [:missing=, m] } + # } + # + module Memcache + include EM::Deferrable + + ## + # constants + + unless defined? Cempty + # @private + Cstored = 'STORED'.freeze + # @private + Cend = 'END'.freeze + # @private + Cdeleted = 'DELETED'.freeze + # @private + Cunknown = 'NOT_FOUND'.freeze + # @private + Cerror = 'ERROR'.freeze + + # @private + Cempty = ''.freeze + # @private + Cdelimiter = "\r\n".freeze + end + + ## + # commands + + # Get the value associated with one or multiple keys + # + # cache.get(:a){ |v| p v } + # cache.get(:a,:b,:c,:d){ |a,b,c,d| p [a,b,c,d] } + # + def get *keys + raise ArgumentError unless block_given? + + callback{ + keys = keys.map{|k| k.to_s.gsub(/\s/,'_') } + send_data "get #{keys.join(' ')}\r\n" + @get_cbs << [keys, proc{ |values| + yield *keys.map{ |k| values[k] } + }] + } + end + + # Set the value for a given key + # + # cache.set :a, 'hello' + # cache.set(:missing, 'abc'){ puts "stored the value!" } + # + def set key, val, exptime = 0, &cb + callback{ + val = val.to_s + send_cmd :set, key, 0, exptime, val.respond_to?(:bytesize) ? val.bytesize : val.size, !block_given? + send_data val + send_data Cdelimiter + @set_cbs << cb if cb + } + end + + # Gets multiple values as a hash + # + # cache.get_hash(:a, :b, :c, :d){ |h| puts h[:a] } + # + def get_hash *keys + raise ArgumentError unless block_given? + + get *keys do |*values| + yield keys.inject({}){ |hash, k| hash.update k => values[keys.index(k)] } + end + end + + # Delete the value associated with a key + # + # cache.del :a + # cache.del(:b){ puts "deleted the value!" } + # + def delete key, expires = 0, &cb + callback{ + send_data "delete #{key} #{expires}#{cb ? '' : ' noreply'}\r\n" + @del_cbs << cb if cb + } + end + alias del delete + + # Connect to a memcached server (must support NOREPLY, memcached >= 1.2.4) + def self.connect host = 'localhost', port = 11211 + EM.connect host, port, self, host, port + end + + def send_cmd cmd, key, flags = 0, exptime = 0, bytes = 0, noreply = false + send_data "#{cmd} #{key} #{flags} #{exptime} #{bytes}#{noreply ? ' noreply' : ''}\r\n" + end + private :send_cmd + + ## + # errors + + # @private + class ParserError < StandardError + end + + ## + # em hooks + + # @private + def initialize host, port = 11211 + @host, @port = host, port + end + + # @private + def connection_completed + @get_cbs = [] + @set_cbs = [] + @del_cbs = [] + + @values = {} + + @reconnecting = false + @connected = true + succeed + # set_delimiter "\r\n" + # set_line_mode + end + + #-- + # 19Feb09 Switched to a custom parser, LineText2 is recursive and can cause + # stack overflows when there is too much data. + # include EM::P::LineText2 + # @private + def receive_data data + (@buffer||='') << data + + while index = @buffer.index(Cdelimiter) + begin + line = @buffer.slice!(0,index+2) + process_cmd line + rescue ParserError + @buffer[0...0] = line + break + end + end + end + + #-- + # def receive_line line + # @private + def process_cmd line + case line.strip + when /^VALUE\s+(.+?)\s+(\d+)\s+(\d+)/ # VALUE + bytes = Integer($3) + # set_binary_mode bytes+2 + # @cur_key = $1 + if @buffer.size >= bytes + 2 + @values[$1] = @buffer.slice!(0,bytes) + @buffer.slice!(0,2) # \r\n + else + raise ParserError + end + + when Cend # END + if entry = @get_cbs.shift + keys, cb = entry + cb.call(@values) + end + @values = {} + + when Cstored # STORED + if cb = @set_cbs.shift + cb.call(true) + end + + when Cdeleted # DELETED + if cb = @del_cbs.shift + cb.call(true) + end + + when Cunknown # NOT_FOUND + if cb = @del_cbs.shift + cb.call(false) + end + + else + p [:MEMCACHE_UNKNOWN, line] + end + end + + #-- + # def receive_binary_data data + # @values[@cur_key] = data[0..-3] + # end + + # @private + def unbind + if @connected or @reconnecting + EM.add_timer(1){ reconnect @host, @port } + @connected = false + @reconnecting = true + @deferred_status = nil + else + raise 'Unable to connect to memcached server' + end + end + end + end +end + +if __FILE__ == $0 + # ruby -I ext:lib -r eventmachine -rubygems lib/protocols/memcache.rb + require 'em/spec' + + # @private + class TestConnection + include EM::P::Memcache + def send_data data + sent_data << data + end + def sent_data + @sent_data ||= '' + end + + def initialize + connection_completed + end + end + + EM.describe EM::Protocols::Memcache do + + before{ + @c = TestConnection.new + } + + should 'send get requests' do + @c.get('a'){} + @c.sent_data.should == "get a\r\n" + done + end + + should 'send set requests' do + @c.set('a', 1){} + @c.sent_data.should == "set a 0 0 1\r\n1\r\n" + done + end + + should 'use noreply on set without block' do + @c.set('a', 1) + @c.sent_data.should == "set a 0 0 1 noreply\r\n1\r\n" + done + end + + should 'send delete requests' do + @c.del('a') + @c.sent_data.should == "delete a 0 noreply\r\n" + done + end + + should 'work when get returns no values' do + @c.get('a'){ |a| + a.should.be.nil + done + } + + @c.receive_data "END\r\n" + end + + should 'invoke block on set' do + @c.set('a', 1){ + done + } + + @c.receive_data "STORED\r\n" + end + + should 'invoke block on delete' do + @c.delete('a'){ |found| + found.should.be.false + } + @c.delete('b'){ |found| + found.should.be.true + done + } + + @c.receive_data "NOT_FOUND\r\n" + @c.receive_data "DELETED\r\n" + end + + should 'parse split responses' do + @c.get('a'){ |a| + a.should == 'abc' + done + } + + @c.receive_data "VAL" + @c.receive_data "UE a 0 " + @c.receive_data "3\r\n" + @c.receive_data "ab" + @c.receive_data "c" + @c.receive_data "\r\n" + @c.receive_data "EN" + @c.receive_data "D\r\n" + end + + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/object_protocol.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/object_protocol.rb new file mode 100644 index 00000000..ec79cb4a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/object_protocol.rb @@ -0,0 +1,46 @@ +module EventMachine + module Protocols + # ObjectProtocol allows for easy communication using marshaled ruby objects + # + # module RubyServer + # include EM::P::ObjectProtocol + # + # def receive_object obj + # send_object({'you said' => obj}) + # end + # end + # + module ObjectProtocol + # By default returns Marshal, override to return JSON or YAML, or any + # other serializer/deserializer responding to #dump and #load. + def serializer + Marshal + end + + # @private + def receive_data data + (@buf ||= '') << data + + while @buf.size >= 4 + if @buf.size >= 4+(size=@buf.unpack('N').first) + @buf.slice!(0,4) + receive_object serializer.load(@buf.slice!(0,size)) + else + break + end + end + end + + # Invoked with ruby objects received over the network + def receive_object obj + # stub + end + + # Sends a ruby object over the network + def send_object obj + data = serializer.dump(obj) + send_data [data.respond_to?(:bytesize) ? data.bytesize : data.size, data].pack('Na*') + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/postgres3.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/postgres3.rb new file mode 100644 index 00000000..7d87505c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/postgres3.rb @@ -0,0 +1,246 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 November 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-08 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# +# + +require 'postgres-pr/message' +require 'postgres-pr/connection' +require 'stringio' + +# @private +class StringIO + # Reads exactly +n+ bytes. + # + # If the data read is nil an EOFError is raised. + # + # If the data read is too short an IOError is raised + def readbytes(n) + str = read(n) + if str == nil + raise EOFError, "End of file reached" + end + if str.size < n + raise IOError, "data truncated" + end + str + end + alias read_exactly_n_bytes readbytes +end + + +module EventMachine + module Protocols + # PROVISIONAL IMPLEMENTATION of an evented Postgres client. + # This implements version 3 of the Postgres wire protocol, which will work + # with any Postgres version from roughly 7.4 onward. + # + # Objective: we want to access Postgres databases without requiring threads. + # Until now this has been a problem because the Postgres client implementations + # have all made use of blocking I/O calls, which is incompatible with a + # thread-free evented model. + # + # But rather than re-implement the Postgres Wire3 protocol, we're taking advantage + # of the existing postgres-pr library, which was originally written by Michael + # Neumann but (at this writing) appears to be no longer maintained. Still, it's + # in basically a production-ready state, and the wire protocol isn't that complicated + # anyway. + # + # We're tucking in a bunch of require statements that may not be present in garden-variety + # EM installations. Until we find a good way to only require these if a program + # requires postgres, this file will need to be required explicitly. + # + # We need to monkeypatch StringIO because it lacks the #readbytes method needed + # by postgres-pr. + # The StringIO monkeypatch is lifted from the standard library readbytes.rb, + # which adds method #readbytes directly to class IO. But StringIO is not a subclass of IO. + # It is modified to raise an IOError instead of TruncatedDataException since the exception is unused. + # + # We cloned the handling of postgres messages from lib/postgres-pr/connection.rb + # in the postgres-pr library, and modified it for event-handling. + # + # TODO: The password handling in dispatch_conn_message is totally incomplete. + # + # + # We return Deferrables from the user-level operations surfaced by this interface. + # Experimentally, we're using the pattern of always returning a boolean value as the + # first argument of a deferrable callback to indicate success or failure. This is + # instead of the traditional pattern of calling Deferrable#succeed or #fail, and + # requiring the user to define both a callback and an errback function. + # + # === Usage + # EM.run { + # db = EM.connect_unix_domain( "/tmp/.s.PGSQL.5432", EM::P::Postgres3 ) + # db.connect( dbname, username, psw ).callback do |status| + # if status + # db.query( "select * from some_table" ).callback do |status, result, errors| + # if status + # result.rows.each do |row| + # p row + # end + # end + # end + # end + # end + # } + class Postgres3 < EventMachine::Connection + include PostgresPR + + def initialize + @data = "" + @params = {} + end + + def connect db, user, psw=nil + d = EM::DefaultDeferrable.new + d.timeout 15 + + if @pending_query || @pending_conn + d.succeed false, "Operation already in progress" + else + @pending_conn = d + prms = {"user"=>user, "database"=>db} + @user = user + if psw + @password = psw + #prms["password"] = psw + end + send_data PostgresPR::StartupMessage.new( 3 << 16, prms ).dump + end + + d + end + + def query sql + d = EM::DefaultDeferrable.new + d.timeout 15 + + if @pending_query || @pending_conn + d.succeed false, "Operation already in progress" + else + @r = PostgresPR::Connection::Result.new + @e = [] + @pending_query = d + send_data PostgresPR::Query.dump(sql) + end + + d + end + + + def receive_data data + @data << data + while @data.length >= 5 + pktlen = @data[1...5].unpack("N").first + if @data.length >= (1 + pktlen) + pkt = @data.slice!(0...(1+pktlen)) + m = StringIO.open( pkt, "r" ) {|io| PostgresPR::Message.read( io ) } + if @pending_conn + dispatch_conn_message m + elsif @pending_query + dispatch_query_message m + else + raise "Unexpected message from database" + end + else + break # very important, break out of the while + end + end + end + + + def unbind + if o = (@pending_query || @pending_conn) + o.succeed false, "lost connection" + end + end + + # Cloned and modified from the postgres-pr. + def dispatch_conn_message msg + case msg + when AuthentificationClearTextPassword + raise ArgumentError, "no password specified" if @password.nil? + send_data PasswordMessage.new(@password).dump + + when AuthentificationCryptPassword + raise ArgumentError, "no password specified" if @password.nil? + send_data PasswordMessage.new(@password.crypt(msg.salt)).dump + + when AuthentificationMD5Password + raise ArgumentError, "no password specified" if @password.nil? + require 'digest/md5' + + m = Digest::MD5.hexdigest(@password + @user) + m = Digest::MD5.hexdigest(m + msg.salt) + m = 'md5' + m + send_data PasswordMessage.new(m).dump + + when AuthentificationKerberosV4, AuthentificationKerberosV5, AuthentificationSCMCredential + raise "unsupported authentification" + + when AuthentificationOk + when ErrorResponse + raise msg.field_values.join("\t") + when NoticeResponse + @notice_processor.call(msg) if @notice_processor + when ParameterStatus + @params[msg.key] = msg.value + when BackendKeyData + # TODO + #p msg + when ReadyForQuery + # TODO: use transaction status + pc,@pending_conn = @pending_conn,nil + pc.succeed true + else + raise "unhandled message type" + end + end + + # Cloned and modified from the postgres-pr. + def dispatch_query_message msg + case msg + when DataRow + @r.rows << msg.columns + when CommandComplete + @r.cmd_tag = msg.cmd_tag + when ReadyForQuery + pq,@pending_query = @pending_query,nil + pq.succeed true, @r, @e + when RowDescription + @r.fields = msg.fields + when CopyInResponse + when CopyOutResponse + when EmptyQueryResponse + when ErrorResponse + # TODO + @e << msg + when NoticeResponse + @notice_processor.call(msg) if @notice_processor + else + # TODO + end + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/saslauth.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/saslauth.rb new file mode 100644 index 00000000..9cabc518 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/saslauth.rb @@ -0,0 +1,175 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 November 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# +# + +module EventMachine + module Protocols + + # Implements SASL authd. + # This is a very, very simple protocol that mimics the one used + # by saslauthd and pwcheck, two outboard daemons included in the + # standard SASL library distro. + # The only thing this is really suitable for is SASL PLAIN + # (user+password) authentication, but the SASL libs that are + # linked into standard servers (like imapd and sendmail) implement + # the other ones. + # + # SASL-auth is intended for reasonably fast operation inside a + # single machine, so it has no transport-security (although there + # have been multi-machine extensions incorporating transport-layer + # encryption). + # + # The standard saslauthd module generally runs privileged and does + # its work by referring to the system-account files. + # + # This feature was added to EventMachine to enable the development + # of custom authentication/authorization engines for standard servers. + # + # To use SASLauth, include it in a class that subclasses EM::Connection, + # and reimplement the validate method. + # + # The typical way to incorporate this module into an authentication + # daemon would be to set it as the handler for a UNIX-domain socket. + # The code might look like this: + # + # EM.start_unix_domain_server( "/var/run/saslauthd/mux", MyHandler ) + # File.chmod( 0777, "/var/run/saslauthd/mux") + # + # The chmod is probably needed to ensure that unprivileged clients can + # access the UNIX-domain socket. + # + # It's also a very good idea to drop superuser privileges (if any), after + # the UNIX-domain socket has been opened. + #-- + # Implementation details: assume the client can send us pipelined requests, + # and that the client will close the connection. + # + # The client sends us four values, each encoded as a two-byte length field in + # network order followed by the specified number of octets. + # The fields specify the username, password, service name (such as imap), + # and the "realm" name. We send back the barest minimum reply, a single + # field also encoded as a two-octet length in network order, followed by + # either "NO" or "OK" - simplicity itself. + # + # We enforce a maximum field size just as a sanity check. + # We do NOT automatically time out the connection. + # + # The code we use to parse out the values is ugly and probably slow. + # Improvements welcome. + # + module SASLauth + + MaxFieldSize = 128*1024 + def post_init + super + @sasl_data = "" + @sasl_values = [] + end + + def receive_data data + @sasl_data << data + while @sasl_data.length >= 2 + len = (@sasl_data[0,2].unpack("n")).first + raise "SASL Max Field Length exceeded" if len > MaxFieldSize + if @sasl_data.length >= (len + 2) + @sasl_values << @sasl_data[2,len] + @sasl_data.slice!(0...(2+len)) + if @sasl_values.length == 4 + send_data( validate(*@sasl_values) ? "\0\002OK" : "\0\002NO" ) + @sasl_values.clear + end + else + break + end + end + end + + def validate username, psw, sysname, realm + p username + p psw + p sysname + p realm + true + end + end + + # Implements the SASL authd client protocol. + # This is a very, very simple protocol that mimics the one used + # by saslauthd and pwcheck, two outboard daemons included in the + # standard SASL library distro. + # The only thing this is really suitable for is SASL PLAIN + # (user+password) authentication, but the SASL libs that are + # linked into standard servers (like imapd and sendmail) implement + # the other ones. + # + # You can use this module directly as a handler for EM Connections, + # or include it in a module or handler class of your own. + # + # First connect to a SASL server (it's probably a TCP server, or more + # likely a Unix-domain socket). Then call the #validate? method, + # passing at least a username and a password. #validate? returns + # a Deferrable which will either succeed or fail, depending + # on the status of the authentication operation. + # + module SASLauthclient + MaxFieldSize = 128*1024 + + def validate? username, psw, sysname=nil, realm=nil + + str = [username, psw, sysname, realm].map {|m| + [(m || "").length, (m || "")] + }.flatten.pack( "nA*" * 4 ) + send_data str + + d = EM::DefaultDeferrable.new + @queries.unshift d + d + end + + def post_init + @sasl_data = "" + @queries = [] + end + + def receive_data data + @sasl_data << data + + while @sasl_data.length > 2 + len = (@sasl_data[0,2].unpack("n")).first + raise "SASL Max Field Length exceeded" if len > MaxFieldSize + if @sasl_data.length >= (len + 2) + val = @sasl_data[2,len] + @sasl_data.slice!(0...(2+len)) + q = @queries.pop + (val == "NO") ? q.fail : q.succeed + else + break + end + end + end + end + + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpclient.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpclient.rb new file mode 100644 index 00000000..25ad17a5 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpclient.rb @@ -0,0 +1,394 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 July 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +require 'ostruct' + +module EventMachine + module Protocols + + # Simple SMTP client + # + # @example + # email = EM::Protocols::SmtpClient.send( + # :domain=>"example.com", + # :host=>'localhost', + # :port=>25, # optional, defaults 25 + # :starttls=>true, # use ssl + # :from=>"sender@example.com", + # :to=> ["to_1@example.com", "to_2@example.com"], + # :header=> {"Subject" => "This is a subject line"}, + # :body=> "This is the body of the email" + # ) + # email.callback{ + # puts 'Email sent!' + # } + # email.errback{ |e| + # puts 'Email failed!' + # } + # + # Sending generated emails (using Mail) + # + # mail = Mail.new do + # from 'alice@example.com' + # to 'bob@example.com' + # subject 'This is a test email' + # body 'Hello, world!' + # end + # + # email = EM::P::SmtpClient.send( + # :domain=>'example.com', + # :from=>mail.from.first, + # :to=>mail.to, + # :message=>mail.to_s + # ) + # + class SmtpClient < Connection + include EventMachine::Deferrable + include EventMachine::Protocols::LineText2 + + def initialize + @succeeded = nil + @responder = nil + @code = nil + @msg = nil + end + + # :host => required String + # a string containing the IP address or host name of the SMTP server to connect to. + # :port => optional + # defaults to 25. + # :domain => required String + # This is passed as the argument to the EHLO command. + # :starttls => optional Boolean + # If it evaluates true, then the client will initiate STARTTLS with + # the server, and abort the connection if the negotiation doesn't succeed. + # TODO, need to be able to pass certificate parameters with this option. + # :auth => optional Hash of auth parameters + # If not given, then no auth will be attempted. + # (In that case, the connection will be aborted if the server requires auth.) + # Specify the hash value :type to determine the auth type, along with additional parameters + # depending on the type. + # Currently only :type => :plain is supported. Pass additional parameters :username (String), + # and :password (either a String or a Proc that will be called at auth-time). + # + # @example + # :auth => {:type=>:plain, :username=>"mickey@disney.com", :password=>"mouse"} + # + # :from => required String + # Specifies the sender of the message. Will be passed as the argument + # to the MAIL FROM. Do NOT enclose the argument in angle-bracket (<>) characters. + # The connection will abort if the server rejects the value. + # :to => required String or Array of Strings + # The recipient(s) of the message. Do NOT enclose + # any of the values in angle-brackets (<>) characters. It's NOT a fatal error if one or more + # recipients are rejected by the server. (Of course, if ALL of them are, the server will most + # likely trigger an error when we try to send data.) An array of codes containing the status + # of each requested recipient is available after the call completes. TODO, we should define + # an overridable stub that will be called on rejection of a recipient or a sender, giving + # user code the chance to try again or abort the connection. + # + # One of either :message, :content, or :header and :body is required: + # + # :message => String + # A valid RFC2822 Internet Message. + # :content => String + # Raw data which MUST be in correct SMTP body format, with escaped leading dots and a trailing + # dot line. + # :header => String or Hash of values to be transmitted in the header of the message. + # The hash keys are the names of the headers (do NOT append a trailing colon), and the values + # are strings containing the header values. TODO, support Arrays of header values, which would + # cause us to send that specific header line more than once. + # + # @example + # :header => {"Subject" => "Bogus", "CC" => "myboss@example.com"} + # + # :body => Optional String or Array of Strings, defaults blank. + # This will be passed as the body of the email message. + # TODO, this needs to be significantly beefed up. As currently written, this requires the caller + # to properly format the input into CRLF-delimited lines of 7-bit characters in the standard + # SMTP transmission format. We need to be able to automatically convert binary data, and add + # correct line-breaks to text data. + # + # :verbose => Optional. + # If true, will cause a lot of information (including the server-side of the + # conversation) to be dumped to $>. + # + def self.send args={} + args[:port] ||= 25 + args[:body] ||= "" + +=begin + (I don't think it's possible for EM#connect to throw an exception under normal + circumstances, so this original code is stubbed out. A connect-failure will result + in the #unbind method being called without calling #connection_completed.) + begin + EventMachine.connect( args[:host], args[:port], self) {|c| + # According to the EM docs, we will get here AFTER post_init is called. + c.args = args + c.set_comm_inactivity_timeout 60 + } + rescue + # We'll get here on a connect error. This code mimics the effect + # of a call to invoke_internal_error. Would be great to DRY this up. + # (Actually, it may be that we never get here, if EM#connect catches + # its errors internally.) + d = EM::DefaultDeferrable.new + d.set_deferred_status(:failed, {:error=>[:connect, 500, "unable to connect to server"]}) + d + end +=end + EventMachine.connect( args[:host], args[:port], self) {|c| + # According to the EM docs, we will get here AFTER post_init is called. + c.args = args + c.set_comm_inactivity_timeout 60 + } + end + + attr_writer :args + + # @private + def post_init + @return_values = OpenStruct.new + @return_values.start_time = Time.now + end + + # @private + def connection_completed + @responder = :receive_signon + @msg = [] + end + + # We can get here in a variety of ways, all of them being failures unless + # the @succeeded flag is set. If a protocol success was recorded, then don't + # set a deferred success because the caller will already have done it + # (no need to wait until the connection closes to invoke the callbacks). + # + # @private + def unbind + unless @succeeded + @return_values.elapsed_time = Time.now - @return_values.start_time + @return_values.responder = @responder + @return_values.code = @code + @return_values.message = @msg + set_deferred_status(:failed, @return_values) + end + end + + # @private + def receive_line ln + $>.puts ln if @args[:verbose] + @range = ln[0...1].to_i + @code = ln[0...3].to_i + @msg << ln[4..-1] + unless ln[3...4] == '-' + $>.puts @responder if @args[:verbose] + send @responder + @msg.clear + end + end + + private + + # We encountered an error from the server and will close the connection. + # Use the error and message the server returned. + # + def invoke_error + @return_values.elapsed_time = Time.now - @return_values.start_time + @return_values.responder = @responder + @return_values.code = @code + @return_values.message = @msg + set_deferred_status :failed, @return_values + send_data "QUIT\r\n" + close_connection_after_writing + end + + # We encountered an error on our side of the protocol and will close the connection. + # Use an extra-protocol error code (900) and use the message from the caller. + # + def invoke_internal_error msg = "???" + @return_values.elapsed_time = Time.now - @return_values.start_time + @return_values.responder = @responder + @return_values.code = 900 + @return_values.message = msg + set_deferred_status :failed, @return_values + send_data "QUIT\r\n" + close_connection_after_writing + end + + def send_ehlo + send_data "EHLO #{@args[:domain]}\r\n" + end + + def receive_signon + return invoke_error unless @range == 2 + send_ehlo + @responder = :receive_ehlo_response + end + def receive_ehlo_response + return invoke_error unless @range == 2 + @server_caps = @msg + invoke_starttls + end + + def invoke_starttls + if @args[:starttls] + # It would be more sociable to first ask if @server_caps contains + # the string "STARTTLS" before we invoke it, but hey, life's too short. + send_data "STARTTLS\r\n" + @responder = :receive_starttls_response + else + invoke_auth + end + end + def receive_starttls_response + return invoke_error unless @range == 2 + start_tls + invoke_ehlo_over_tls + end + + def invoke_ehlo_over_tls + send_ehlo + @responder = :receive_ehlo_over_tls_response + end + def receive_ehlo_over_tls_response + return invoke_error unless @range == 2 + invoke_auth + end + + # Perform an authentication. If the caller didn't request one, then fall through + # to the mail-from state. + def invoke_auth + if @args[:auth] + if @args[:auth][:type] == :plain + psw = @args[:auth][:password] + if psw.respond_to?(:call) + psw = psw.call + end + #str = Base64::encode64("\0#{@args[:auth][:username]}\0#{psw}").chomp + str = ["\0#{@args[:auth][:username]}\0#{psw}"].pack("m").gsub(/\n/, '') + send_data "AUTH PLAIN #{str}\r\n" + @responder = :receive_auth_response + else + return invoke_internal_error("unsupported auth type") + end + else + invoke_mail_from + end + end + def receive_auth_response + return invoke_error unless @range == 2 + invoke_mail_from + end + + def invoke_mail_from + send_data "MAIL FROM: <#{@args[:from]}>\r\n" + @responder = :receive_mail_from_response + end + def receive_mail_from_response + return invoke_error unless @range == 2 + invoke_rcpt_to + end + + def invoke_rcpt_to + @rcpt_responses ||= [] + l = @rcpt_responses.length + to = @args[:to].is_a?(Array) ? @args[:to] : [@args[:to].to_s] + if l < to.length + send_data "RCPT TO: <#{to[l]}>\r\n" + @responder = :receive_rcpt_to_response + else + e = @rcpt_responses.select {|rr| rr.last == 2} + if e and e.length > 0 + invoke_data + else + invoke_error + end + end + end + def receive_rcpt_to_response + @rcpt_responses << [@code, @msg, @range] + invoke_rcpt_to + end + + def escape_leading_dots(s) + s.gsub(/^\./, '..') + end + + def invoke_data + send_data "DATA\r\n" + @responder = :receive_data_response + end + def receive_data_response + return invoke_error unless @range == 3 + + # The data to send can be given in either @args[:message], @args[:content], or the + # combination of @args[:header] and @args[:body]. + # + # - @args[:message] (String) MUST be a valid RFC2822 Internet Message + # + # - @args[:content] (String) MUST be in correct SMTP body format, with escaped + # leading dots and a trailing dot line + # + # - @args[:header] (Hash or String) + # - @args[:body] (Array or String) + if @args[:message] + send_data escape_leading_dots(@args[:message].to_s) + send_data "\r\n.\r\n" + elsif @args[:content] + send_data @args[:content].to_s + else + # The header can be a hash or an array. + if @args[:header].is_a?(Hash) + (@args[:header] || {}).each {|k,v| send_data escape_leading_dots("#{k}: #{v}\r\n") } + else + send_data escape_leading_dots(@args[:header].to_s) + end + send_data "\r\n" + + if @args[:body].is_a?(Array) + @args[:body].each {|e| send_data escape_leading_dots(e)} + else + send_data escape_leading_dots(@args[:body].to_s) + end + + send_data "\r\n.\r\n" + end + + @responder = :receive_message_response + end + def receive_message_response + return invoke_error unless @range == 2 + send_data "QUIT\r\n" + close_connection_after_writing + @succeeded = true + @return_values.elapsed_time = Time.now - @return_values.start_time + @return_values.responder = @responder + @return_values.code = @code + @return_values.message = @msg + set_deferred_status :succeeded, @return_values + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpserver.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpserver.rb new file mode 100644 index 00000000..e0f1f05d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/smtpserver.rb @@ -0,0 +1,666 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 July 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + module Protocols + + # This is a protocol handler for the server side of SMTP. + # It's NOT a complete SMTP server obeying all the semantics of servers conforming to + # RFC2821. Rather, it uses overridable method stubs to communicate protocol states + # and data to user code. User code is responsible for doing the right things with the + # data in order to get complete and correct SMTP server behavior. + # + # Simple SMTP server example: + # + # class EmailServer < EM::P::SmtpServer + # def receive_plain_auth(user, pass) + # true + # end + # + # def get_server_domain + # "mock.smtp.server.local" + # end + # + # def get_server_greeting + # "mock smtp server greets you with impunity" + # end + # + # def receive_sender(sender) + # current.sender = sender + # true + # end + # + # def receive_recipient(recipient) + # current.recipient = recipient + # true + # end + # + # def receive_message + # current.received = true + # current.completed_at = Time.now + # + # p [:received_email, current] + # @current = OpenStruct.new + # true + # end + # + # def receive_ehlo_domain(domain) + # @ehlo_domain = domain + # true + # end + # + # def receive_data_command + # current.data = "" + # true + # end + # + # def receive_data_chunk(data) + # current.data << data.join("\n") + # true + # end + # + # def receive_transaction + # if @ehlo_domain + # current.ehlo_domain = @ehlo_domain + # @ehlo_domain = nil + # end + # true + # end + # + # def current + # @current ||= OpenStruct.new + # end + # + # def self.start(host = 'localhost', port = 1025) + # require 'ostruct' + # @server = EM.start_server host, port, self + # end + # + # def self.stop + # if @server + # EM.stop_server @server + # @server = nil + # end + # end + # + # def self.running? + # !!@server + # end + # end + # + # EM.run{ EmailServer.start } + # + #-- + # Useful paragraphs in RFC-2821: + # 4.3.2: Concise list of command-reply sequences, in essence a text representation + # of the command state-machine. + # + # STARTTLS is defined in RFC2487. + # Observe that there are important rules governing whether a publicly-referenced server + # (meaning one whose Internet address appears in public MX records) may require the + # non-optional use of TLS. + # Non-optional TLS does not apply to EHLO, NOOP, QUIT or STARTTLS. + class SmtpServer < EventMachine::Connection + include Protocols::LineText2 + + HeloRegex = /\AHELO\s*/i + EhloRegex = /\AEHLO\s*/i + QuitRegex = /\AQUIT/i + MailFromRegex = /\AMAIL FROM:\s*/i + RcptToRegex = /\ARCPT TO:\s*/i + DataRegex = /\ADATA/i + NoopRegex = /\ANOOP/i + RsetRegex = /\ARSET/i + VrfyRegex = /\AVRFY\s+/i + ExpnRegex = /\AEXPN\s+/i + HelpRegex = /\AHELP/i + StarttlsRegex = /\ASTARTTLS/i + AuthRegex = /\AAUTH\s+/i + + + # Class variable containing default parameters that can be overridden + # in application code. + # Individual objects of this class will make an instance-local copy of + # the class variable, so that they can be reconfigured on a per-instance + # basis. + # + # Chunksize is the number of data lines we'll buffer before + # sending them to the application. TODO, make this user-configurable. + # + @@parms = { + :chunksize => 4000, + :verbose => false + } + def self.parms= parms={} + @@parms.merge!(parms) + end + + + + def initialize *args + super + @parms = @@parms + init_protocol_state + end + + def parms= parms={} + @parms.merge!(parms) + end + + # In SMTP, the server talks first. But by a (perhaps flawed) axiom in EM, + # #post_init will execute BEFORE the block passed to #start_server, for any + # given accepted connection. Since in this class we'll probably be getting + # a lot of initialization parameters, we want the guts of post_init to + # run AFTER the application has initialized the connection object. So we + # use a spawn to schedule the post_init to run later. + # It's a little weird, I admit. A reasonable alternative would be to set + # parameters as a class variable and to do that before accepting any connections. + # + # OBSOLETE, now we have @@parms. But the spawn is nice to keep as an illustration. + # + def post_init + #send_data "220 #{get_server_greeting}\r\n" (ORIGINAL) + #(EM.spawn {|x| x.send_data "220 #{x.get_server_greeting}\r\n"}).notify(self) + (EM.spawn {|x| x.send_server_greeting}).notify(self) + end + + def send_server_greeting + send_data "220 #{get_server_greeting}\r\n" + end + + def receive_line ln + @@parms[:verbose] and $>.puts ">>> #{ln}" + + return process_data_line(ln) if @state.include?(:data) + return process_auth_line(ln) if @state.include?(:auth_incomplete) + + case ln + when EhloRegex + process_ehlo $'.dup + when HeloRegex + process_helo $'.dup + when MailFromRegex + process_mail_from $'.dup + when RcptToRegex + process_rcpt_to $'.dup + when DataRegex + process_data + when RsetRegex + process_rset + when VrfyRegex + process_vrfy + when ExpnRegex + process_expn + when HelpRegex + process_help + when NoopRegex + process_noop + when QuitRegex + process_quit + when StarttlsRegex + process_starttls + when AuthRegex + process_auth $'.dup + else + process_unknown + end + end + + # TODO - implement this properly, the implementation is a stub! + def process_help + send_data "250 Ok, but unimplemented\r\n" + end + + # RFC2821, 3.5.3 Meaning of VRFY or EXPN Success Response: + # A server MUST NOT return a 250 code in response to a VRFY or EXPN + # command unless it has actually verified the address. In particular, + # a server MUST NOT return 250 if all it has done is to verify that the + # syntax given is valid. In that case, 502 (Command not implemented) + # or 500 (Syntax error, command unrecognized) SHOULD be returned. + # + # TODO - implement this properly, the implementation is a stub! + def process_vrfy + send_data "502 Command not implemented\r\n" + end + # TODO - implement this properly, the implementation is a stub! + def process_expn + send_data "502 Command not implemented\r\n" + end + + #-- + # This is called at several points to restore the protocol state + # to a pre-transaction state. In essence, we "forget" having seen + # any valid command except EHLO and STARTTLS. + # We also have to callback user code, in case they're keeping track + # of senders, recipients, and whatnot. + # + # We try to follow the convention of avoiding the verb "receive" for + # internal method names except receive_line (which we inherit), and + # using only receive_xxx for user-overridable stubs. + # + # init_protocol_state is called when we initialize the connection as + # well as during reset_protocol_state. It does NOT call the user + # override method. This enables us to promise the users that they + # won't see the overridable fire except after EHLO and RSET, and + # after a message has been received. Although the latter may be wrong. + # The standard may allow multiple DATA segments with the same set of + # senders and recipients. + # + def reset_protocol_state + init_protocol_state + s,@state = @state,[] + @state << :starttls if s.include?(:starttls) + @state << :ehlo if s.include?(:ehlo) + receive_transaction + end + def init_protocol_state + @state ||= [] + end + + + #-- + # EHLO/HELO is always legal, per the standard. On success + # it always clears buffers and initiates a mail "transaction." + # Which means that a MAIL FROM must follow. + # + # Per the standard, an EHLO/HELO or a RSET "initiates" an email + # transaction. Thereafter, MAIL FROM must be received before + # RCPT TO, before DATA. Not sure what this specific ordering + # achieves semantically, but it does make it easier to + # implement. We also support user-specified requirements for + # STARTTLS and AUTH. We make it impossible to proceed to MAIL FROM + # without fulfilling tls and/or auth, if the user specified either + # or both as required. We need to check the extension standard + # for auth to see if a credential is discarded after a RSET along + # with all the rest of the state. We'll behave as if it is. + # Now clearly, we can't discard tls after its been negotiated + # without dropping the connection, so that flag doesn't get cleared. + # + def process_ehlo domain + if receive_ehlo_domain domain + send_data "250-#{get_server_domain}\r\n" + if @@parms[:starttls] + send_data "250-STARTTLS\r\n" + end + if @@parms[:auth] + send_data "250-AUTH PLAIN\r\n" + end + send_data "250-NO-SOLICITING\r\n" + # TODO, size needs to be configurable. + send_data "250 SIZE 20000000\r\n" + reset_protocol_state + @state << :ehlo + else + send_data "550 Requested action not taken\r\n" + end + end + + def process_helo domain + if receive_ehlo_domain domain.dup + send_data "250 #{get_server_domain}\r\n" + reset_protocol_state + @state << :ehlo + else + send_data "550 Requested action not taken\r\n" + end + end + + def process_quit + send_data "221 Ok\r\n" + close_connection_after_writing + end + + def process_noop + send_data "250 Ok\r\n" + end + + def process_unknown + send_data "500 Unknown command\r\n" + end + + #-- + # So far, only AUTH PLAIN is supported but we should do at least LOGIN as well. + # TODO, support clients that send AUTH PLAIN with no parameter, expecting a 3xx + # response and a continuation of the auth conversation. + # + def process_auth str + if @state.include?(:auth) + send_data "503 auth already issued\r\n" + elsif str =~ /\APLAIN\s?/i + if $'.length == 0 + # we got a partial response, so let the client know to send the rest + @state << :auth_incomplete + send_data("334 \r\n") + else + # we got the initial response, so go ahead & process it + process_auth_line($') + end + #elsif str =~ /\ALOGIN\s+/i + else + send_data "504 auth mechanism not available\r\n" + end + end + + def process_auth_line(line) + plain = line.unpack("m").first + _,user,psw = plain.split("\000") + + succeeded = proc { + send_data "235 authentication ok\r\n" + @state << :auth + } + failed = proc { + send_data "535 invalid authentication\r\n" + } + auth = receive_plain_auth user,psw + + if auth.respond_to?(:callback) + auth.callback(&succeeded) + auth.errback(&failed) + else + (auth ? succeeded : failed).call + end + + @state.delete :auth_incomplete + end + + #-- + # Unusually, we can deal with a Deferrable returned from the user application. + # This was added to deal with a special case in a particular application, but + # it would be a nice idea to add it to the other user-code callbacks. + # + def process_data + unless @state.include?(:rcpt) + send_data "503 Operation sequence error\r\n" + else + succeeded = proc { + send_data "354 Send it\r\n" + @state << :data + @databuffer = [] + } + failed = proc { + send_data "550 Operation failed\r\n" + } + + d = receive_data_command + + if d.respond_to?(:callback) + d.callback(&succeeded) + d.errback(&failed) + else + (d ? succeeded : failed).call + end + end + end + + def process_rset + reset_protocol_state + receive_reset + send_data "250 Ok\r\n" + end + + def unbind + connection_ended + end + + #-- + # STARTTLS may not be issued before EHLO, or unless the user has chosen + # to support it. + # + # If :starttls_options is present and :starttls is set in the parms + # pass the options in :starttls_options to start_tls. Do this if you want to use + # your own certificate + # e.g. {:cert_chain_file => "/etc/ssl/cert.pem", :private_key_file => "/etc/ssl/private/cert.key"} + + def process_starttls + if @@parms[:starttls] + if @state.include?(:starttls) + send_data "503 TLS Already negotiated\r\n" + elsif ! @state.include?(:ehlo) + send_data "503 EHLO required before STARTTLS\r\n" + else + send_data "220 Start TLS negotiation\r\n" + start_tls(@@parms[:starttls_options] || {}) + @state << :starttls + end + else + process_unknown + end + end + + + #-- + # Requiring TLS is touchy, cf RFC2784. + # Requiring AUTH seems to be much more reasonable. + # We don't currently support any notion of deriving an authentication from the TLS + # negotiation, although that would certainly be reasonable. + # We DON'T allow MAIL FROM to be given twice. + # We DON'T enforce all the various rules for validating the sender or + # the reverse-path (like whether it should be null), and notifying the reverse + # path in case of delivery problems. All of that is left to the calling application. + # + def process_mail_from sender + if (@@parms[:starttls]==:required and !@state.include?(:starttls)) + send_data "550 This server requires STARTTLS before MAIL FROM\r\n" + elsif (@@parms[:auth]==:required and !@state.include?(:auth)) + send_data "550 This server requires authentication before MAIL FROM\r\n" + elsif @state.include?(:mail_from) + send_data "503 MAIL already given\r\n" + else + unless receive_sender sender + send_data "550 sender is unacceptable\r\n" + else + send_data "250 Ok\r\n" + @state << :mail_from + end + end + end + + #-- + # Since we require :mail_from to have been seen before we process RCPT TO, + # we don't need to repeat the tests for TLS and AUTH. + # Note that we don't remember or do anything else with the recipients. + # All of that is on the user code. + # TODO: we should enforce user-definable limits on the total number of + # recipients per transaction. + # We might want to make sure that a given recipient is only seen once, but + # for now we'll let that be the user's problem. + # + # User-written code can return a deferrable from receive_recipient. + # + def process_rcpt_to rcpt + unless @state.include?(:mail_from) + send_data "503 MAIL is required before RCPT\r\n" + else + succeeded = proc { + send_data "250 Ok\r\n" + @state << :rcpt unless @state.include?(:rcpt) + } + failed = proc { + send_data "550 recipient is unacceptable\r\n" + } + + d = receive_recipient rcpt + + if d.respond_to?(:set_deferred_status) + d.callback(&succeeded) + d.errback(&failed) + else + (d ? succeeded : failed).call + end + +=begin + unless receive_recipient rcpt + send_data "550 recipient is unacceptable\r\n" + else + send_data "250 Ok\r\n" + @state << :rcpt unless @state.include?(:rcpt) + end +=end + end + end + + + # Send the incoming data to the application one chunk at a time, rather than + # one line at a time. That lets the application be a little more flexible about + # storing to disk, etc. + # Since we clear the chunk array every time we submit it, the caller needs to be + # aware to do things like dup it if he wants to keep it around across calls. + # + # Resets the transaction upon disposition of the incoming message. + # RFC5321 says this about the MAIL FROM command: + # "This command tells the SMTP-receiver that a new mail transaction is + # starting and to reset all its state tables and buffers, including any + # recipients or mail data." + # + # Equivalent behaviour is implemented by resetting after a completed transaction. + # + # User-written code can return a Deferrable as a response from receive_message. + # + def process_data_line ln + if ln == "." + if @databuffer.length > 0 + receive_data_chunk @databuffer + @databuffer.clear + end + + + succeeded = proc { + send_data "250 Message accepted\r\n" + reset_protocol_state + } + failed = proc { + send_data "550 Message rejected\r\n" + reset_protocol_state + } + d = receive_message + + if d.respond_to?(:set_deferred_status) + d.callback(&succeeded) + d.errback(&failed) + else + (d ? succeeded : failed).call + end + + @state.delete :data + else + # slice off leading . if any + ln.slice!(0...1) if ln[0] == ?. + @databuffer << ln + if @databuffer.length > @@parms[:chunksize] + receive_data_chunk @databuffer + @databuffer.clear + end + end + end + + + #------------------------------------------ + # Everything from here on can be overridden in user code. + + # The greeting returned in the initial connection message to the client. + def get_server_greeting + "EventMachine SMTP Server" + end + # The domain name returned in the first line of the response to a + # successful EHLO or HELO command. + def get_server_domain + "Ok EventMachine SMTP Server" + end + + # A false response from this user-overridable method will cause a + # 550 error to be returned to the remote client. + # + def receive_ehlo_domain domain + true + end + + # Return true or false to indicate that the authentication is acceptable. + def receive_plain_auth user, password + true + end + + # Receives the argument of the MAIL FROM command. Return false to + # indicate to the remote client that the sender is not accepted. + # This can only be successfully called once per transaction. + # + def receive_sender sender + true + end + + # Receives the argument of a RCPT TO command. Can be given multiple + # times per transaction. Return false to reject the recipient. + # + def receive_recipient rcpt + true + end + + # Sent when the remote peer issues the RSET command. + # Since RSET is not allowed to fail (according to the protocol), + # we ignore any return value from user overrides of this method. + # + def receive_reset + end + + # Sent when the remote peer has ended the connection. + # + def connection_ended + end + + # Called when the remote peer sends the DATA command. + # Returning false will cause us to send a 550 error to the peer. + # This can be useful for dealing with problems that arise from processing + # the whole set of sender and recipients. + # + def receive_data_command + true + end + + # Sent when data from the remote peer is available. The size can be controlled + # by setting the :chunksize parameter. This call can be made multiple times. + # The goal is to strike a balance between sending the data to the application one + # line at a time, and holding all of a very large message in memory. + # + def receive_data_chunk data + @smtps_msg_size ||= 0 + @smtps_msg_size += data.join.length + STDERR.write "<#{@smtps_msg_size}>" + end + + # Sent after a message has been completely received. User code + # must return true or false to indicate whether the message has + # been accepted for delivery. + def receive_message + @@parms[:verbose] and $>.puts "Received complete message" + true + end + + # This is called when the protocol state is reset. It happens + # when the remote client calls EHLO/HELO or RSET. + def receive_transaction + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/socks4.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/socks4.rb new file mode 100644 index 00000000..132f3209 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/socks4.rb @@ -0,0 +1,66 @@ +module EventMachine + module Protocols + # Basic SOCKS v4 client implementation + # + # Use as you would any regular connection: + # + # class MyConn < EM::P::Socks4 + # def post_init + # send_data("sup") + # end + # + # def receive_data(data) + # send_data("you said: #{data}") + # end + # end + # + # EM.connect socks_host, socks_port, MyConn, host, port + # + class Socks4 < Connection + def initialize(host, port) + @host = Socket.gethostbyname(host).last + @port = port + @socks_error_code = nil + @buffer = '' + setup_methods + end + + def setup_methods + class << self + def post_init; socks_post_init; end + def receive_data(*a); socks_receive_data(*a); end + end + end + + def restore_methods + class << self + remove_method :post_init + remove_method :receive_data + end + end + + def socks_post_init + header = [4, 1, @port, @host, 0].flatten.pack("CCnA4C") + send_data(header) + end + + def socks_receive_data(data) + @buffer << data + return if @buffer.size < 8 + + header_resp = @buffer.slice! 0, 8 + _, r = header_resp.unpack("cc") + if r != 90 + @socks_error_code = r + close_connection + return + end + + restore_methods + + post_init + receive_data(@buffer) unless @buffer.empty? + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/stomp.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/stomp.rb new file mode 100644 index 00000000..ca6f078e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/stomp.rb @@ -0,0 +1,205 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 15 November 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# +# + +module EventMachine + module Protocols + + # Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol). + # + # == Usage example + # + # module StompClient + # include EM::Protocols::Stomp + # + # def connection_completed + # connect :login => 'guest', :passcode => 'guest' + # end + # + # def receive_msg msg + # if msg.command == "CONNECTED" + # subscribe '/some/topic' + # else + # p ['got a message', msg] + # puts msg.body + # end + # end + # end + # + # EM.run{ + # EM.connect 'localhost', 61613, StompClient + # } + # + module Stomp + include LineText2 + + class Message + # The command associated with the message, usually 'CONNECTED' or 'MESSAGE' + attr_accessor :command + # Hash containing headers such as destination and message-id + attr_accessor :header + alias :headers :header + # Body of the message + attr_accessor :body + + # @private + def initialize + @header = {} + @state = :precommand + @content_length = nil + end + # @private + def consume_line line + if @state == :precommand + unless line =~ /\A\s*\Z/ + @command = line + @state = :headers + end + elsif @state == :headers + if line == "" + if @content_length + yield( [:sized_text, @content_length+1] ) + else + @state = :body + yield( [:unsized_text] ) + end + elsif line =~ /\A([^:]+):(.+)\Z/ + k = $1.dup.strip + v = $2.dup.strip + @header[k] = v + if k == "content-length" + @content_length = v.to_i + end + else + # This is a protocol error. How to signal it? + end + elsif @state == :body + @body = line + yield( [:dispatch] ) + end + end + end + + # @private + def send_frame verb, headers={}, body="" + body = body.to_s + ary = [verb, "\n"] + body_bytesize = body.bytesize if body.respond_to? :bytesize + body_bytesize ||= body.size + headers.each {|k,v| ary << "#{k}:#{v}\n" } + ary << "content-length: #{body_bytesize}\n" + ary << "content-type: text/plain; charset=UTF-8\n" unless headers.has_key? 'content-type' + ary << "\n" + ary << body + ary << "\0" + send_data ary.join + end + + # @private + def receive_line line + @stomp_initialized || init_message_reader + @stomp_message.consume_line(line) {|outcome| + if outcome.first == :sized_text + set_text_mode outcome[1] + elsif outcome.first == :unsized_text + set_delimiter "\0" + elsif outcome.first == :dispatch + receive_msg(@stomp_message) if respond_to?(:receive_msg) + init_message_reader + end + } + end + + # @private + def receive_binary_data data + @stomp_message.body = data[0..-2] + receive_msg(@stomp_message) if respond_to?(:receive_msg) + init_message_reader + end + + # @private + def init_message_reader + @stomp_initialized = true + set_delimiter "\n" + set_line_mode + @stomp_message = Message.new + end + + # Invoked with an incoming Stomp::Message received from the STOMP server + def receive_msg msg + # stub, overwrite this in your handler + end + + # CONNECT command, for authentication + # + # connect :login => 'guest', :passcode => 'guest' + # + def connect parms={} + send_frame "CONNECT", parms + end + + # SEND command, for publishing messages to a topic + # + # send '/topic/name', 'some message here' + # + def send destination, body, parms={} + send_frame "SEND", parms.merge( :destination=>destination ), body.to_s + end + + # SUBSCRIBE command, for subscribing to topics + # + # subscribe '/topic/name', false + # + def subscribe dest, ack=false + send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")} + end + + # ACK command, for acknowledging receipt of messages + # + # module StompClient + # include EM::P::Stomp + # + # def connection_completed + # connect :login => 'guest', :passcode => 'guest' + # # subscribe with ack mode + # subscribe '/some/topic', true + # end + # + # def receive_msg msg + # if msg.command == "MESSAGE" + # ack msg.headers['message-id'] + # puts msg.body + # end + # end + # end + # + def ack msgid + send_frame "ACK", 'message-id'=> msgid + end + + end + end +end + diff --git a/bin/gems/eventmachine-1.2.7/lib/em/protocols/tcptest.rb b/bin/gems/eventmachine-1.2.7/lib/em/protocols/tcptest.rb new file mode 100644 index 00000000..31878930 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/protocols/tcptest.rb @@ -0,0 +1,54 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 16 July 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# +# + +module EventMachine + module Protocols + + # @private + class TcpConnectTester < Connection + include EventMachine::Deferrable + + def self.test( host, port ) + EventMachine.connect( host, port, self ) + end + + def post_init + @start_time = Time.now + end + + def connection_completed + @completed = true + set_deferred_status :succeeded, (Time.now - @start_time) + close_connection + end + + def unbind + set_deferred_status :failed, (Time.now - @start_time) unless @completed + end + end + + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/pure_ruby.rb b/bin/gems/eventmachine-1.2.7/lib/em/pure_ruby.rb new file mode 100644 index 00000000..94fd1754 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/pure_ruby.rb @@ -0,0 +1,1284 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 8 Apr 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#------------------------------------------------------------------- +# +# + +# TODO List: +# TCP-connects currently assume non-blocking connect is available- need to +# degrade automatically on versions of Ruby prior to June 2006. +# + +require 'singleton' +require 'forwardable' +require 'socket' +require 'fcntl' +require 'set' +require 'openssl' + +module EventMachine + # @private + class Error < Exception; end + # @private + class UnknownTimerFired < RuntimeError; end + # @private + class Unsupported < RuntimeError; end + # @private + class ConnectionError < RuntimeError; end + # @private + class ConnectionNotBound < RuntimeError; end + + # Older versions of Ruby may not provide the SSLErrorWaitReadable + # OpenSSL class. Create an error class to act as a "proxy". + if defined?(OpenSSL::SSL::SSLErrorWaitReadable) + SSLConnectionWaitReadable = OpenSSL::SSL::SSLErrorWaitReadable + else + SSLConnectionWaitReadable = IO::WaitReadable + end + + # Older versions of Ruby may not provide the SSLErrorWaitWritable + # OpenSSL class. Create an error class to act as a "proxy". + if defined?(OpenSSL::SSL::SSLErrorWaitWritable) + SSLConnectionWaitWritable = OpenSSL::SSL::SSLErrorWaitWritable + else + SSLConnectionWaitWritable = IO::WaitWritable + end +end + +module EventMachine + class CertificateCreator + attr_reader :cert, :key + + def initialize + @key = OpenSSL::PKey::RSA.new(1024) + public_key = @key.public_key + subject = "/C=EventMachine/O=EventMachine/OU=EventMachine/CN=EventMachine" + @cert = OpenSSL::X509::Certificate.new + @cert.subject = @cert.issuer = OpenSSL::X509::Name.parse(subject) + @cert.not_before = Time.now + @cert.not_after = Time.now + 365 * 24 * 60 * 60 + @cert.public_key = public_key + @cert.serial = 0x0 + @cert.version = 2 + factory = OpenSSL::X509::ExtensionFactory.new + factory.subject_certificate = @cert + factory.issuer_certificate = @cert + @cert.extensions = [ + factory.create_extension("basicConstraints","CA:TRUE", true), + factory.create_extension("subjectKeyIdentifier", "hash") + ] + @cert.add_extension factory.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") + @cert.sign(@key, OpenSSL::Digest::SHA1.new) + end + end + + # @private + DefaultCertificate = CertificateCreator.new + + # @private + DefaultDHKey1024 = OpenSSL::PKey::DH.new <<-_end_of_pem_ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ +AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR +T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC +-----END DH PARAMETERS----- + _end_of_pem_ + + # @private + DefaultDHKey2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY +JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab +VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6 +YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3 +1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD +7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg== +-----END DH PARAMETERS----- + _end_of_pem_ +end + +# @private +module EventMachine + class << self + # This is mostly useful for automated tests. + # Return a distinctive symbol so the caller knows whether he's dealing + # with an extension or with a pure-Ruby library. + # @private + def library_type + :pure_ruby + end + + # @private + def initialize_event_machine + Reactor.instance.initialize_for_run + end + + # Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby + # processor still wants them in seconds. + # @private + def add_oneshot_timer interval + Reactor.instance.install_oneshot_timer(interval / 1000) + end + + # @private + def run_machine + Reactor.instance.run + end + + # @private + def release_machine + end + + + def stopping? + return Reactor.instance.stop_scheduled + end + + # @private + def stop + Reactor.instance.stop + end + + # @private + def connect_server host, port + bind_connect_server nil, nil, host, port + end + + # @private + def bind_connect_server bind_addr, bind_port, host, port + EvmaTCPClient.connect(bind_addr, bind_port, host, port).uuid + end + + # @private + def send_data target, data, datalength + selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target" + selectable.send_data data + end + + # @private + def close_connection target, after_writing + selectable = Reactor.instance.get_selectable( target ) + selectable.schedule_close after_writing if selectable + end + + # @private + def start_tcp_server host, port + (s = EvmaTCPServer.start_server host, port) or raise "no acceptor" + s.uuid + end + + # @private + def stop_tcp_server sig + s = Reactor.instance.get_selectable(sig) + s.schedule_close + end + + # @private + def start_unix_server chain + (s = EvmaUNIXServer.start_server chain) or raise "no acceptor" + s.uuid + end + + # @private + def connect_unix_server chain + EvmaUNIXClient.connect(chain).uuid + end + + # @private + def signal_loopbreak + Reactor.instance.signal_loopbreak + end + + # @private + def get_peername sig + selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target" + selectable.get_peername + end + + # @private + def get_sockname sig + selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_sockname target" + selectable.get_sockname + end + + # @private + def open_udp_socket host, port + EvmaUDPSocket.create(host, port).uuid + end + + # This is currently only for UDP! + # We need to make it work with unix-domain sockets as well. + # @private + def send_datagram target, data, datalength, host, port + selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target" + selectable.send_datagram data, Socket::pack_sockaddr_in(port, host) + end + + + # Sets reactor quantum in milliseconds. The underlying Reactor function wants a (possibly + # fractional) number of seconds. + # @private + def set_timer_quantum interval + Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0) + end + + # This method is a harmless no-op in the pure-Ruby implementation. This is intended to ensure + # that user code behaves properly across different EM implementations. + # @private + def epoll + end + + # @private + def ssl? + true + end + + def tls_parm_set?(parm) + !(parm.nil? || parm.empty?) + end + + # This method takes a series of positional arguments for specifying such + # things as private keys and certificate chains. It's expected that the + # parameter list will grow as we add more supported features. ALL of these + # parameters are optional, and can be specified as empty or nil strings. + # @private + def set_tls_parms signature, priv_key, cert_chain, verify_peer, fail_if_no_peer_cert, sni_hostname, cipher_list, ecdh_curve, dhparam, protocols_bitmask + bitmask = protocols_bitmask + ssl_options = OpenSSL::SSL::OP_ALL + ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) && EM_PROTO_SSLv2 & bitmask == 0 + ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3) && EM_PROTO_SSLv3 & bitmask == 0 + ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1) && EM_PROTO_TLSv1 & bitmask == 0 + ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) && EM_PROTO_TLSv1_1 & bitmask == 0 + ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_2 if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) && EM_PROTO_TLSv1_2 & bitmask == 0 + @tls_parms ||= {} + @tls_parms[signature] = { + :verify_peer => verify_peer, + :fail_if_no_peer_cert => fail_if_no_peer_cert, + :ssl_options => ssl_options + } + @tls_parms[signature][:priv_key] = File.read(priv_key) if tls_parm_set?(priv_key) + @tls_parms[signature][:cert_chain] = File.read(cert_chain) if tls_parm_set?(cert_chain) + @tls_parms[signature][:sni_hostname] = sni_hostname if tls_parm_set?(sni_hostname) + @tls_parms[signature][:cipher_list] = cipher_list.gsub(/,\s*/, ':') if tls_parm_set?(cipher_list) + @tls_parms[signature][:dhparam] = File.read(dhparam) if tls_parm_set?(dhparam) + @tls_parms[signature][:ecdh_curve] = ecdh_curve if tls_parm_set?(ecdh_curve) + end + + def start_tls signature + selectable = Reactor.instance.get_selectable(signature) or raise "unknown io selectable for start_tls" + tls_parms = @tls_parms[signature] + ctx = OpenSSL::SSL::SSLContext.new + ctx.options = tls_parms[:ssl_options] + ctx.cert = DefaultCertificate.cert + ctx.key = DefaultCertificate.key + ctx.cert_store = OpenSSL::X509::Store.new + ctx.cert_store.set_default_paths + ctx.cert = OpenSSL::X509::Certificate.new(tls_parms[:cert_chain]) if tls_parms[:cert_chain] + ctx.key = OpenSSL::PKey::RSA.new(tls_parms[:priv_key]) if tls_parms[:priv_key] + verify_mode = OpenSSL::SSL::VERIFY_NONE + if tls_parms[:verify_peer] + verify_mode |= OpenSSL::SSL::VERIFY_PEER + end + if tls_parms[:fail_if_no_peer_cert] + verify_mode |= OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + end + ctx.verify_mode = verify_mode + ctx.servername_cb = Proc.new do |_, server_name| + tls_parms[:server_name] = server_name + nil + end + ctx.ciphers = tls_parms[:cipher_list] if tls_parms[:cipher_list] + if selectable.is_server + ctx.tmp_dh_callback = Proc.new do |_, _, key_length| + if tls_parms[:dhparam] + OpenSSL::PKey::DH.new(tls_parms[:dhparam]) + else + case key_length + when 1024 then DefaultDHKey1024 + when 2048 then DefaultDHKey2048 + else + nil + end + end + end + if tls_parms[:ecdh_curve] && ctx.respond_to?(:tmp_ecdh_callback) + ctx.tmp_ecdh_callback = Proc.new do + OpenSSL::PKey::EC.new(tls_parms[:ecdh_curve]) + end + end + end + ssl_io = OpenSSL::SSL::SSLSocket.new(selectable, ctx) + ssl_io.sync_close = true + if tls_parms[:sni_hostname] + ssl_io.hostname = tls_parms[:sni_hostname] if ssl_io.respond_to?(:hostname=) + end + begin + selectable.is_server ? ssl_io.accept_nonblock : ssl_io.connect_nonblock + rescue; end + selectable.io = ssl_io + end + + def get_peer_cert signature + selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_peer_cert target" + if selectable.io.respond_to?(:peer_cert) && selectable.io.peer_cert + selectable.io.peer_cert.to_pem + else + nil + end + end + + def get_cipher_name signature + selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_name target" + selectable.io.respond_to?(:cipher) ? selectable.io.cipher[0] : nil + end + + def get_cipher_protocol signature + selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_protocol target" + selectable.io.respond_to?(:cipher) ? selectable.io.cipher[1] : nil + end + + def get_cipher_bits signature + selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_bits target" + selectable.io.respond_to?(:cipher) ? selectable.io.cipher[2] : nil + end + + def get_sni_hostname signature + @tls_parms ||= {} + if @tls_parms[signature] + @tls_parms[signature][:server_name] + else + nil + end + end + + # This method is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in + # per-process file-descriptor limit. + # @private + def set_rlimit_nofile n + 1024 + end + + # This method is a harmless no-op in pure Ruby, which doesn't have a built-in limit + # on the number of available timers. + # @private + def set_max_timer_count n + end + + # @private + def get_sock_opt signature, level, optname + selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_sock_opt target" + selectable.getsockopt level, optname + end + + # @private + def set_sock_opt signature, level, optname, optval + selectable = Reactor.instance.get_selectable( signature ) or raise "unknown set_sock_opt target" + selectable.setsockopt level, optname, optval + end + + # @private + def send_file_data sig, filename + sz = File.size(filename) + raise "file too large" if sz > 32*1024 + data = + begin + File.read filename + rescue + "" + end + send_data sig, data, data.length + end + + # @private + def get_outbound_data_size sig + r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target" + r.get_outbound_data_size + end + + # @private + def read_keyboard + EvmaKeyboard.open.uuid + end + + # @private + def set_comm_inactivity_timeout sig, tm + r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target" + r.set_inactivity_timeout tm + end + + # @private + def set_pending_connect_timeout sig, tm + # Needs to be implemented. Currently a no-op stub to allow + # certain software to operate with the EM pure-ruby. + end + + # @private + def report_connection_error_status signature + get_sock_opt(signature, Socket::SOL_SOCKET, Socket::SO_ERROR).int + end + end +end + +module EventMachine + # @private + class Connection + # @private + def get_outbound_data_size + EventMachine::get_outbound_data_size @signature + end + end +end + +module EventMachine + + # Factored out so we can substitute other implementations + # here if desired, such as the one in ActiveRBAC. + # @private + module UuidGenerator + def self.generate + @ix ||= 0 + @ix += 1 + end + end +end + + +module EventMachine + # @private + TimerFired = 100 + # @private + ConnectionData = 101 + # @private + ConnectionUnbound = 102 + # @private + ConnectionAccepted = 103 + # @private + ConnectionCompleted = 104 + # @private + LoopbreakSignalled = 105 + # @private + ConnectionNotifyReadable = 106 + # @private + ConnectionNotifyWritable = 107 + # @private + SslHandshakeCompleted = 108 + # @private + SslVerify = 109 + # @private + EM_PROTO_SSLv2 = 2 + # @private + EM_PROTO_SSLv3 = 4 + # @private + EM_PROTO_TLSv1 = 8 + # @private + EM_PROTO_TLSv1_1 = 16 + # @private + EM_PROTO_TLSv1_2 = 32 +end + +module EventMachine + # @private + class Reactor + include Singleton + + HeartbeatInterval = 2 + + attr_reader :current_loop_time, :stop_scheduled + + def initialize + initialize_for_run + end + + def install_oneshot_timer interval + uuid = UuidGenerator::generate + #@timers << [Time.now + interval, uuid] + #@timers.sort! {|a,b| a.first <=> b.first} + @timers.add([Time.now + interval, uuid]) + uuid + end + + # Called before run, this is a good place to clear out arrays + # with cruft that may be left over from a previous run. + # @private + def initialize_for_run + @running = false + @stop_scheduled = false + @selectables ||= {}; @selectables.clear + @timers = SortedSet.new # [] + set_timer_quantum(0.1) + @current_loop_time = Time.now + @next_heartbeat = @current_loop_time + HeartbeatInterval + end + + def add_selectable io + @selectables[io.uuid] = io + end + + def get_selectable uuid + @selectables[uuid] + end + + def run + raise Error.new( "already running" ) if @running + @running = true + + begin + open_loopbreaker + + loop { + @current_loop_time = Time.now + + break if @stop_scheduled + run_timers + break if @stop_scheduled + crank_selectables + break if @stop_scheduled + run_heartbeats + } + ensure + close_loopbreaker + @selectables.each {|k, io| io.close} + @selectables.clear + + @running = false + end + + end + + def run_timers + @timers.each {|t| + if t.first <= @current_loop_time + @timers.delete t + EventMachine::event_callback "", TimerFired, t.last + else + break + end + } + #while @timers.length > 0 and @timers.first.first <= now + # t = @timers.shift + # EventMachine::event_callback "", TimerFired, t.last + #end + end + + def run_heartbeats + if @next_heartbeat <= @current_loop_time + @next_heartbeat = @current_loop_time + HeartbeatInterval + @selectables.each {|k,io| io.heartbeat} + end + end + + def crank_selectables + #$stderr.write 'R' + + readers = @selectables.values.select {|io| io.select_for_reading?} + writers = @selectables.values.select {|io| io.select_for_writing?} + + s = select( readers, writers, nil, @timer_quantum) + + s and s[1] and s[1].each {|w| w.eventable_write } + s and s[0] and s[0].each {|r| r.eventable_read } + + @selectables.delete_if {|k,io| + if io.close_scheduled? + io.close + begin + EventMachine::event_callback io.uuid, ConnectionUnbound, nil + rescue ConnectionNotBound; end + true + end + } + end + + # #stop + def stop + raise Error.new( "not running") unless @running + @stop_scheduled = true + end + + def open_loopbreaker + # Can't use an IO.pipe because they can't be set nonselectable in Windows. + # Pick a random localhost UDP port. + #@loopbreak_writer.close if @loopbreak_writer + #rd,@loopbreak_writer = IO.pipe + @loopbreak_reader = UDPSocket.new + @loopbreak_writer = UDPSocket.new + bound = false + 100.times { + @loopbreak_port = rand(10000) + 40000 + begin + @loopbreak_reader.bind "127.0.0.1", @loopbreak_port + bound = true + break + rescue + end + } + raise "Unable to bind Loopbreaker" unless bound + LoopbreakReader.new(@loopbreak_reader) + end + + def close_loopbreaker + @loopbreak_writer.close + @loopbreak_writer = nil + end + + def signal_loopbreak + begin + @loopbreak_writer.send('+',0,"127.0.0.1",@loopbreak_port) if @loopbreak_writer + rescue IOError; end + end + + def set_timer_quantum interval_in_seconds + @timer_quantum = interval_in_seconds + end + + end + +end + +# @private +class IO + extend Forwardable + def_delegator :@my_selectable, :close_scheduled? + def_delegator :@my_selectable, :select_for_reading? + def_delegator :@my_selectable, :select_for_writing? + def_delegator :@my_selectable, :eventable_read + def_delegator :@my_selectable, :eventable_write + def_delegator :@my_selectable, :uuid + def_delegator :@my_selectable, :is_server + def_delegator :@my_selectable, :is_server= + def_delegator :@my_selectable, :send_data + def_delegator :@my_selectable, :schedule_close + def_delegator :@my_selectable, :get_peername + def_delegator :@my_selectable, :get_sockname + def_delegator :@my_selectable, :send_datagram + def_delegator :@my_selectable, :get_outbound_data_size + def_delegator :@my_selectable, :set_inactivity_timeout + def_delegator :@my_selectable, :heartbeat + def_delegator :@my_selectable, :io + def_delegator :@my_selectable, :io= +end + +module EventMachine + # @private + class Selectable + + attr_accessor :io, :is_server + attr_reader :uuid + + def initialize io + @io = io + @uuid = UuidGenerator.generate + @is_server = false + @last_activity = Reactor.instance.current_loop_time + + if defined?(Fcntl::F_GETFL) + m = @io.fcntl(Fcntl::F_GETFL, 0) + @io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m) + else + # Windows doesn't define F_GETFL. + # It's not very reliable about setting descriptors nonblocking either. + begin + s = Socket.for_fd(@io.fileno) + s.fcntl( Fcntl::F_SETFL, Fcntl::O_NONBLOCK ) + rescue Errno::EINVAL, Errno::EBADF + warn "Serious error: unable to set descriptor non-blocking" + end + end + # TODO, should set CLOEXEC on Unix? + + @close_scheduled = false + @close_requested = false + + se = self; @io.instance_eval { @my_selectable = se } + Reactor.instance.add_selectable @io + end + + def close_scheduled? + @close_scheduled + end + + def select_for_reading? + false + end + + def select_for_writing? + false + end + + def get_peername + nil + end + + def get_sockname + nil + end + + def set_inactivity_timeout tm + @inactivity_timeout = tm + end + + def heartbeat + end + + def schedule_close(after_writing=false) + if after_writing + @close_requested = true + else + @close_scheduled = true + end + end + end + +end + +module EventMachine + # @private + class StreamObject < Selectable + def initialize io + super io + @outbound_q = [] + end + + # If we have to close, or a close-after-writing has been requested, + # then don't read any more data. + def select_for_reading? + true unless (@close_scheduled || @close_requested) + end + + # If we have to close, don't select for writing. + # Otherwise, see if the protocol is ready to close. + # If not, see if he has data to send. + # If a close-after-writing has been requested and the outbound queue + # is empty, convert the status to close_scheduled. + def select_for_writing? + unless @close_scheduled + if @outbound_q.empty? + @close_scheduled = true if @close_requested + false + else + true + end + end + end + + # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006. + # If we have it, then we can read multiple times safely to improve + # performance. + # The last-activity clock ASSUMES that we only come here when we + # have selected readable. + # TODO, coalesce multiple reads into a single event. + # TODO, do the function check somewhere else and cache it. + def eventable_read + @last_activity = Reactor.instance.current_loop_time + begin + if io.respond_to?(:read_nonblock) + 10.times { + data = io.read_nonblock(4096) + EventMachine::event_callback uuid, ConnectionData, data + } + else + data = io.sysread(4096) + EventMachine::event_callback uuid, ConnectionData, data + end + rescue Errno::EAGAIN, Errno::EWOULDBLOCK, SSLConnectionWaitReadable + # no-op + rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError, Errno::EPIPE, OpenSSL::SSL::SSLError + @close_scheduled = true + EventMachine::event_callback uuid, ConnectionUnbound, nil + end + + end + + # Provisional implementation. Will be re-implemented in subclasses. + # TODO: Complete this implementation. As it stands, this only writes + # a single packet per cycle. Highly inefficient, but required unless + # we're running on a Ruby with proper nonblocking I/O (Ruby 1.8.4 + # built from sources from May 25, 2006 or newer). + # We need to improve the loop so it writes multiple times, however + # not more than a certain number of bytes per cycle, otherwise + # one busy connection could hog output buffers and slow down other + # connections. Also we should coalesce small writes. + # URGENT TODO: Coalesce small writes. They are a performance killer. + # The last-activity recorder ASSUMES we'll only come here if we've + # selected writable. + def eventable_write + # coalesce the outbound array here, perhaps + @last_activity = Reactor.instance.current_loop_time + while data = @outbound_q.shift do + begin + data = data.to_s + w = if io.respond_to?(:write_nonblock) + io.write_nonblock data + else + io.syswrite data + end + + if w < data.length + @outbound_q.unshift data[w..-1] + break + end + rescue Errno::EAGAIN, SSLConnectionWaitReadable, SSLConnectionWaitWritable + @outbound_q.unshift data + break + rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EPIPE, OpenSSL::SSL::SSLError + @close_scheduled = true + @outbound_q.clear + end + end + + end + + # #send_data + def send_data data + # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last? + unless @close_scheduled or @close_requested or !data or data.length <= 0 + @outbound_q << data.to_s + end + end + + # #get_peername + # This is defined in the normal way on connected stream objects. + # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants. + # We could also use a convenience method that did the unpacking automatically. + def get_peername + io.getpeername + end + + # #get_sockname + # This is defined in the normal way on connected stream objects. + # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants. + # We could also use a convenience method that did the unpacking automatically. + def get_sockname + io.getsockname + end + + # #get_outbound_data_size + def get_outbound_data_size + @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length} + end + + def heartbeat + if @inactivity_timeout and @inactivity_timeout > 0 and (@last_activity + @inactivity_timeout) < Reactor.instance.current_loop_time + schedule_close true + end + end + end + + +end + + +#-------------------------------------------------------------- + + + +module EventMachine + # @private + class EvmaTCPClient < StreamObject + + def self.connect bind_addr, bind_port, host, port + sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 ) + sd.bind( Socket.pack_sockaddr_in( bind_port, bind_addr )) if bind_addr + + begin + # TODO, this assumes a current Ruby snapshot. + # We need to degrade to a nonblocking connect otherwise. + sd.connect_nonblock( Socket.pack_sockaddr_in( port, host )) + rescue Errno::ECONNREFUSED, Errno::EINPROGRESS + end + EvmaTCPClient.new sd + end + + def initialize io + super + @pending = true + @handshake_complete = false + end + + def ready? + if RUBY_PLATFORM =~ /linux/ + io.getsockopt(Socket::SOL_TCP, Socket::TCP_INFO).unpack("i").first == 1 # TCP_ESTABLISHED + else + io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first == 0 # NO ERROR + end + end + + def handshake_complete? + if !@handshake_complete && io.respond_to?(:state) + if io.state =~ /^SSLOK/ + @handshake_complete = true + EventMachine::event_callback uuid, SslHandshakeCompleted, "" + EventMachine::event_callback uuid, SslVerify, io.peer_cert.to_pem if io.peer_cert + end + else + @handshake_complete = true + end + @handshake_complete + end + + def pending? + handshake_complete? + if @pending + if ready? + @pending = false + EventMachine::event_callback uuid, ConnectionCompleted, "" + end + end + @pending + end + + def select_for_writing? + pending? + super + end + + def select_for_reading? + pending? + super + end + end +end + + + +module EventMachine + # @private + class EvmaKeyboard < StreamObject + + def self.open + EvmaKeyboard.new STDIN + end + + + def initialize io + super + end + + + def select_for_writing? + false + end + + def select_for_reading? + true + end + + + end +end + + + +module EventMachine + # @private + class EvmaUNIXClient < StreamObject + + def self.connect chain + sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 ) + begin + # TODO, this assumes a current Ruby snapshot. + # We need to degrade to a nonblocking connect otherwise. + sd.connect_nonblock( Socket.pack_sockaddr_un( chain )) + rescue Errno::EINPROGRESS + end + EvmaUNIXClient.new sd + end + + + def initialize io + super + @pending = true + end + + + def select_for_writing? + @pending ? true : super + end + + def select_for_reading? + @pending ? false : super + end + + def eventable_write + if @pending + @pending = false + if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first + EventMachine::event_callback uuid, ConnectionCompleted, "" + end + else + super + end + end + + + + end +end + + +#-------------------------------------------------------------- + +module EventMachine + # @private + class EvmaTCPServer < Selectable + + # TODO, refactor and unify with EvmaUNIXServer. + + class << self + # Versions of ruby 1.8.4 later than May 26 2006 will work properly + # with an object of type TCPServer. Prior versions won't so we + # play it safe and just build a socket. + # + def start_server host, port + sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 ) + sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true ) + sd.bind( Socket.pack_sockaddr_in( port, host )) + sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough. + EvmaTCPServer.new sd + end + end + + def initialize io + super io + end + + + def select_for_reading? + true + end + + #-- + # accept_nonblock returns an array consisting of the accepted + # socket and a sockaddr_in which names the peer. + # Don't accept more than 10 at a time. + def eventable_read + begin + 10.times { + descriptor,peername = io.accept_nonblock + sd = EvmaTCPClient.new descriptor + sd.is_server = true + EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid + } + rescue Errno::EWOULDBLOCK, Errno::EAGAIN + end + end + + #-- + # + def schedule_close + @close_scheduled = true + end + + end +end + + +#-------------------------------------------------------------- + +module EventMachine + # @private + class EvmaUNIXServer < Selectable + + # TODO, refactor and unify with EvmaTCPServer. + + class << self + # Versions of ruby 1.8.4 later than May 26 2006 will work properly + # with an object of type TCPServer. Prior versions won't so we + # play it safe and just build a socket. + # + def start_server chain + sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 ) + sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true ) + sd.bind( Socket.pack_sockaddr_un( chain )) + sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough. + EvmaUNIXServer.new sd + end + end + + def initialize io + super io + end + + + def select_for_reading? + true + end + + #-- + # accept_nonblock returns an array consisting of the accepted + # socket and a sockaddr_in which names the peer. + # Don't accept more than 10 at a time. + def eventable_read + begin + 10.times { + descriptor,peername = io.accept_nonblock + sd = StreamObject.new descriptor + EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid + } + rescue Errno::EWOULDBLOCK, Errno::EAGAIN + end + end + + #-- + # + def schedule_close + @close_scheduled = true + end + + end +end + + + +#-------------------------------------------------------------- + +module EventMachine + # @private + class LoopbreakReader < Selectable + + def select_for_reading? + true + end + + def eventable_read + io.sysread(128) + EventMachine::event_callback "", LoopbreakSignalled, "" + end + + end +end + + + +# @private +module EventMachine + # @private + class DatagramObject < Selectable + def initialize io + super io + @outbound_q = [] + end + + # #send_datagram + def send_datagram data, target + # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last? + unless @close_scheduled or @close_requested + @outbound_q << [data.to_s, target] + end + end + + # #select_for_writing? + def select_for_writing? + unless @close_scheduled + if @outbound_q.empty? + @close_scheduled = true if @close_requested + false + else + true + end + end + end + + # #select_for_reading? + def select_for_reading? + true + end + + # #get_outbound_data_size + def get_outbound_data_size + @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length} + end + + + end + + +end + + +module EventMachine + # @private + class EvmaUDPSocket < DatagramObject + + class << self + def create host, port + sd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 ) + sd.bind Socket::pack_sockaddr_in( port, host ) + EvmaUDPSocket.new sd + end + end + + # #eventable_write + # This really belongs in DatagramObject, but there is some UDP-specific stuff. + def eventable_write + 40.times { + break if @outbound_q.empty? + begin + data,target = @outbound_q.first + + # This damn better be nonblocking. + io.send data.to_s, 0, target + + @outbound_q.shift + rescue Errno::EAGAIN + # It's not been observed in testing that we ever get here. + # True to the definition, packets will be accepted and quietly dropped + # if the system is under pressure. + break + rescue EOFError, Errno::ECONNRESET + @close_scheduled = true + @outbound_q.clear + end + } + end + + # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006. + # If we have it, then we can read multiple times safely to improve + # performance. + def eventable_read + begin + if io.respond_to?(:recvfrom_nonblock) + 40.times { + data,@return_address = io.recvfrom_nonblock(16384) + EventMachine::event_callback uuid, ConnectionData, data + @return_address = nil + } + else + raise "unimplemented datagram-read operation on this Ruby" + end + rescue Errno::EAGAIN + # no-op + rescue Errno::ECONNRESET, EOFError + @close_scheduled = true + EventMachine::event_callback uuid, ConnectionUnbound, nil + end + end + + def send_data data + send_datagram data, @return_address + end + end +end + +# load base EM api on top, now that we have the underlying pure ruby +# implementation defined +require 'eventmachine' diff --git a/bin/gems/eventmachine-1.2.7/lib/em/queue.rb b/bin/gems/eventmachine-1.2.7/lib/em/queue.rb new file mode 100644 index 00000000..9096ed02 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/queue.rb @@ -0,0 +1,80 @@ +module EventMachine + # A cross thread, reactor scheduled, linear queue. + # + # This class provides a simple queue abstraction on top of the reactor + # scheduler. It services two primary purposes: + # + # * API sugar for stateful protocols + # * Pushing processing onto the reactor thread + # + # @example + # + # q = EM::Queue.new + # q.push('one', 'two', 'three') + # 3.times do + # q.pop { |msg| puts(msg) } + # end + # + class Queue + def initialize + @sink = [] + @drain = [] + @popq = [] + end + + # Pop items off the queue, running the block on the reactor thread. The pop + # will not happen immediately, but at some point in the future, either in + # the next tick, if the queue has data, or when the queue is populated. + # + # @return [NilClass] nil + def pop(*a, &b) + cb = EM::Callback(*a, &b) + EM.schedule do + if @drain.empty? + @drain = @sink + @sink = [] + end + if @drain.empty? + @popq << cb + else + cb.call @drain.shift + end + end + nil # Always returns nil + end + + # Push items onto the queue in the reactor thread. The items will not appear + # in the queue immediately, but will be scheduled for addition during the + # next reactor tick. + def push(*items) + EM.schedule do + @sink.push(*items) + unless @popq.empty? + @drain = @sink + @sink = [] + @popq.shift.call @drain.shift until @drain.empty? || @popq.empty? + end + end + end + alias :<< :push + + # @return [Boolean] + # @note This is a peek, it's not thread safe, and may only tend toward accuracy. + def empty? + @drain.empty? && @sink.empty? + end + + # @return [Integer] Queue size + # @note This is a peek, it's not thread safe, and may only tend toward accuracy. + def size + @drain.size + @sink.size + end + + # @return [Integer] Waiting size + # @note This is a peek at the number of jobs that are currently waiting on the Queue + def num_waiting + @popq.size + end + + end # Queue +end # EventMachine diff --git a/bin/gems/eventmachine-1.2.7/lib/em/resolver.rb b/bin/gems/eventmachine-1.2.7/lib/em/resolver.rb new file mode 100644 index 00000000..1d2d7aa0 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/resolver.rb @@ -0,0 +1,232 @@ +module EventMachine + module DNS + class Resolver + + def self.windows? + if RUBY_PLATFORM =~ /mswin32|cygwin|mingw|bccwin/ + require 'win32/resolv' + true + else + false + end + end + + HOSTS_FILE = windows? ? Win32::Resolv.get_hosts_path : '/etc/hosts' + + @hosts = nil + @nameservers = nil + @socket = nil + + def self.resolve(hostname) + Request.new(socket, hostname) + end + + def self.socket + if @socket && @socket.error? + @socket = Socket.open + else + @socket ||= Socket.open + end + end + + def self.nameservers=(ns) + @nameservers = ns + end + + def self.nameservers + return @nameservers if @nameservers + + if windows? + _, ns = Win32::Resolv.get_resolv_info + return @nameservers = ns || [] + end + + @nameservers = [] + IO.readlines('/etc/resolv.conf').each do |line| + if line =~ /^nameserver (.+)$/ + @nameservers << $1.split(/\s+/).first + end + end + + @nameservers + rescue + @nameservers = [] + end + + def self.nameserver + nameservers.shuffle.first + end + + def self.hosts + return @hosts if @hosts + + @hosts = {} + IO.readlines(HOSTS_FILE).each do |line| + next if line =~ /^#/ + addr, host = line.split(/\s+/) + + next unless addr && host + @hosts[host] ||= [] + @hosts[host] << addr + end + + @hosts + rescue + @hosts = {} + end + end + + class RequestIdAlreadyUsed < RuntimeError; end + + class Socket < EventMachine::Connection + def self.open + EventMachine::open_datagram_socket('0.0.0.0', 0, self) + end + + def initialize + @nameserver = nil + end + + def post_init + @requests = {} + end + + def start_timer + @timer ||= EM.add_periodic_timer(0.1, &method(:tick)) + end + + def stop_timer + EM.cancel_timer(@timer) + @timer = nil + end + + def unbind + end + + def tick + @requests.each do |id,req| + req.tick + end + end + + def register_request(id, req) + if @requests.has_key?(id) + raise RequestIdAlreadyUsed + else + @requests[id] = req + end + + start_timer + end + + def deregister_request(id, req) + @requests.delete(id) + stop_timer if @requests.length == 0 + end + + def send_packet(pkt) + send_datagram(pkt, nameserver, 53) + end + + def nameserver=(ns) + @nameserver = ns + end + + def nameserver + @nameserver || Resolver.nameserver + end + + # Decodes the packet, looks for the request and passes the + # response over to the requester + def receive_data(data) + msg = nil + begin + msg = Resolv::DNS::Message.decode data + rescue + else + req = @requests[msg.id] + if req + @requests.delete(msg.id) + stop_timer if @requests.length == 0 + req.receive_answer(msg) + end + end + end + end + + class Request + include Deferrable + attr_accessor :retry_interval, :max_tries + + def initialize(socket, hostname) + @socket = socket + @hostname = hostname + @tries = 0 + @last_send = Time.at(0) + @retry_interval = 3 + @max_tries = 5 + + if addrs = Resolver.hosts[hostname] + succeed addrs + else + EM.next_tick { tick } + end + end + + def tick + # Break early if nothing to do + return if @last_send + @retry_interval > Time.now + if @tries < @max_tries + send + else + @socket.deregister_request(@id, self) + fail 'retries exceeded' + end + end + + def receive_answer(msg) + addrs = [] + msg.each_answer do |name,ttl,data| + if data.kind_of?(Resolv::DNS::Resource::IN::A) || + data.kind_of?(Resolv::DNS::Resource::IN::AAAA) + addrs << data.address.to_s + end + end + + if addrs.empty? + fail "rcode=#{msg.rcode}" + else + succeed addrs + end + end + + private + + def send + @tries += 1 + @last_send = Time.now + @socket.send_packet(packet.encode) + end + + def id + begin + @id = rand(65535) + @socket.register_request(@id, self) + rescue RequestIdAlreadyUsed + retry + end unless defined?(@id) + + @id + end + + def packet + msg = Resolv::DNS::Message.new + msg.id = id + msg.rd = 1 + msg.add_question @hostname, Resolv::DNS::Resource::IN::A + msg + end + + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/spawnable.rb b/bin/gems/eventmachine-1.2.7/lib/em/spawnable.rb new file mode 100644 index 00000000..35c087d0 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/spawnable.rb @@ -0,0 +1,84 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 25 Aug 2007 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +module EventMachine + # Support for Erlang-style processes. + # + class SpawnedProcess + # Send a message to the spawned process + def notify *x + me = self + EM.next_tick { + # A notification executes in the context of this + # SpawnedProcess object. That makes self and notify + # work as one would expect. + # + y = me.call(*x) + if y and y.respond_to?(:pull_out_yield_block) + a,b = y.pull_out_yield_block + set_receiver a + self.notify if b + end + } + end + alias_method :resume, :notify + alias_method :run, :notify # for formulations like (EM.spawn {xxx}).run + + def set_receiver blk + (class << self ; self ; end).class_eval do + remove_method :call if method_defined? :call + define_method :call, blk + end + end + + end + + # @private + class YieldBlockFromSpawnedProcess + def initialize block, notify + @block = [block,notify] + end + def pull_out_yield_block + @block + end + end + + # Spawn an erlang-style process + def self.spawn &block + s = SpawnedProcess.new + s.set_receiver block + s + end + + # @private + def self.yield &block + return YieldBlockFromSpawnedProcess.new( block, false ) + end + + # @private + def self.yield_and_notify &block + return YieldBlockFromSpawnedProcess.new( block, true ) + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/streamer.rb b/bin/gems/eventmachine-1.2.7/lib/em/streamer.rb new file mode 100644 index 00000000..cf49c883 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/streamer.rb @@ -0,0 +1,118 @@ +module EventMachine + # Streams a file over a given connection. Streaming begins once the object is + # instantiated. Typically FileStreamer instances are not reused. + # + # Streaming uses buffering for files larger than 16K and uses so-called fast file reader (a C++ extension) + # if available (it is part of eventmachine gem itself). + # + # @example + # + # module FileSender + # def post_init + # streamer = EventMachine::FileStreamer.new(self, '/tmp/bigfile.tar') + # streamer.callback{ + # # file was sent successfully + # close_connection_after_writing + # } + # end + # end + # + # + # @author Francis Cianfrocca + class FileStreamer + include Deferrable + + # Use mapped streamer for files bigger than 16k + MappingThreshold = 16384 + # Wait until next tick to send more data when 50k is still in the outgoing buffer + BackpressureLevel = 50000 + # Send 16k chunks at a time + ChunkSize = 16384 + + # @param [EventMachine::Connection] connection + # @param [String] filename File path + # + # @option args [Boolean] :http_chunks (false) Use HTTP 1.1 style chunked-encoding semantics. + def initialize connection, filename, args = {} + @connection = connection + @http_chunks = args[:http_chunks] + + if File.exist?(filename) + @size = File.size(filename) + if @size <= MappingThreshold + stream_without_mapping filename + else + stream_with_mapping filename + end + else + fail "file not found" + end + end + + # @private + def stream_without_mapping filename + if @http_chunks + @connection.send_data "#{@size.to_s(16)}\r\n" + @connection.send_file_data filename + @connection.send_data "\r\n0\r\n\r\n" + else + @connection.send_file_data filename + end + succeed + end + private :stream_without_mapping + + # @private + def stream_with_mapping filename + ensure_mapping_extension_is_present + + @position = 0 + @mapping = EventMachine::FastFileReader::Mapper.new filename + stream_one_chunk + end + private :stream_with_mapping + + # Used internally to stream one chunk at a time over multiple reactor ticks + # @private + def stream_one_chunk + loop { + if @position < @size + if @connection.get_outbound_data_size > BackpressureLevel + EventMachine::next_tick {stream_one_chunk} + break + else + len = @size - @position + len = ChunkSize if (len > ChunkSize) + + @connection.send_data( "#{len.to_s(16)}\r\n" ) if @http_chunks + @connection.send_data( @mapping.get_chunk( @position, len )) + @connection.send_data("\r\n") if @http_chunks + + @position += len + end + else + @connection.send_data "0\r\n\r\n" if @http_chunks + @mapping.close + succeed + break + end + } + end + + # + # We use an outboard extension class to get memory-mapped files. + # It's outboard to avoid polluting the core distro, but that means + # there's a "hidden" dependency on it. The first time we get here in + # any run, try to load up the dependency extension. User code will see + # a LoadError if it's not available, but code that doesn't require + # mapped files will work fine without it. This is a somewhat difficult + # compromise between usability and proper modularization. + # + # @private + def ensure_mapping_extension_is_present + @@fastfilereader ||= (require 'fastfilereaderext') + end + private :ensure_mapping_extension_is_present + + end # FileStreamer +end # EventMachine diff --git a/bin/gems/eventmachine-1.2.7/lib/em/threaded_resource.rb b/bin/gems/eventmachine-1.2.7/lib/em/threaded_resource.rb new file mode 100644 index 00000000..87704d5f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/threaded_resource.rb @@ -0,0 +1,90 @@ +module EventMachine + # = EventMachine::ThreadedResource + # + # A threaded resource is a "quick and dirty" wrapper around the concept of + # wiring up synchronous code into a standard EM::Pool. This is useful to keep + # interfaces coherent and provide a simple approach at "making an interface + # async-ish". + # + # General usage is to wrap libraries that do not support EventMachine, or to + # have a specific number of dedicated high-cpu worker resources. + # + # == Basic Usage example + # + # This example requires the cassandra gem. The cassandra gem contains an + # EventMachine interface, but it's sadly Fiber based and thus only works on + # 1.9. It also requires (potentially) complex stack switching logic to reach + # completion of nested operations. By contrast this approach provides a block + # in which normal synchronous code can occur, but makes no attempt to wire the + # IO into EventMachines C++ IO implementations, instead relying on the reactor + # pattern in rb_thread_select. + # + # cassandra_dispatcher = ThreadedResource.new do + # Cassandra.new('allthethings', '127.0.0.1:9160') + # end + # + # pool = EM::Pool.new + # + # pool.add cassandra_dispatcher + # + # # If we don't care about the result: + # pool.perform do |dispatcher| + # # The following block executes inside a dedicated thread, and should not + # # access EventMachine things: + # dispatcher.dispatch do |cassandra| + # cassandra.insert(:Things, '10', 'stuff' => 'things') + # end + # end + # + # # Example where we care about the result: + # pool.perform do |dispatcher| + # # The dispatch block is executed in the resources thread. + # completion = dispatcher.dispatch do |cassandra| + # cassandra.get(:Things, '10', 'stuff') + # end + # + # # This block will be yielded on the EM thread: + # completion.callback do |result| + # EM.do_something_with(result) + # end + # + # completion + # end + class ThreadedResource + + # The block should return the resource that will be yielded in a dispatch. + def initialize + @resource = yield + + @running = true + @queue = ::Queue.new + @thread = Thread.new do + @queue.pop.call while @running + end + end + + # Called on the EM thread, generally in a perform block to return a + # completion for the work. + def dispatch + completion = EM::Completion.new + @queue << lambda do + begin + result = yield @resource + completion.succeed result + rescue => e + completion.fail e + end + end + completion + end + + # Kill the internal thread. should only be used to cleanup - generally + # only required for tests. + def shutdown + @running = false + @queue << lambda {} + @thread.join + end + + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/tick_loop.rb b/bin/gems/eventmachine-1.2.7/lib/em/tick_loop.rb new file mode 100644 index 00000000..a95d5161 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/tick_loop.rb @@ -0,0 +1,85 @@ +module EventMachine + # Creates and immediately starts an EventMachine::TickLoop + def self.tick_loop(*a, &b) + TickLoop.new(*a, &b).start + end + + # A TickLoop is useful when one needs to distribute amounts of work + # throughout ticks in order to maintain response times. It is also useful for + # simple repeated checks and metrics. + # @example + # # Here we run through an array one item per tick until it is empty, + # # printing each element. + # # When the array is empty, we return :stop from the callback, and the + # # loop will terminate. + # # When the loop terminates, the on_stop callbacks will be called. + # EM.run do + # array = (1..100).to_a + # + # tickloop = EM.tick_loop do + # if array.empty? + # :stop + # else + # puts array.shift + # end + # end + # + # tickloop.on_stop { EM.stop } + # end + # + class TickLoop + + # Arguments: A callback (EM::Callback) to call each tick. If the call + # returns +:stop+ then the loop will be stopped. Any other value is + # ignored. + def initialize(*a, &b) + @work = EM::Callback(*a, &b) + @stops = [] + @stopped = true + end + + # Arguments: A callback (EM::Callback) to call once on the next stop (or + # immediately if already stopped). + def on_stop(*a, &b) + if @stopped + EM::Callback(*a, &b).call + else + @stops << EM::Callback(*a, &b) + end + end + + # Stop the tick loop immediately, and call it's on_stop callbacks. + def stop + @stopped = true + until @stops.empty? + @stops.shift.call + end + end + + # Query if the loop is stopped. + def stopped? + @stopped + end + + # Start the tick loop, will raise argument error if the loop is already + # running. + def start + raise ArgumentError, "double start" unless @stopped + @stopped = false + schedule + end + + private + def schedule + EM.next_tick do + next if @stopped + if @work.call == :stop + stop + else + schedule + end + end + self + end + end +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/lib/em/timers.rb b/bin/gems/eventmachine-1.2.7/lib/em/timers.rb new file mode 100644 index 00000000..41cd9595 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/timers.rb @@ -0,0 +1,61 @@ +module EventMachine + # Creates a one-time timer + # + # timer = EventMachine::Timer.new(5) do + # # this will never fire because we cancel it + # end + # timer.cancel + # + class Timer + # Create a new timer that fires after a given number of seconds + def initialize interval, callback=nil, &block + @signature = EventMachine::add_timer(interval, callback || block) + end + + # Cancel the timer + def cancel + EventMachine.send :cancel_timer, @signature + end + end + + # Creates a periodic timer + # + # @example + # n = 0 + # timer = EventMachine::PeriodicTimer.new(5) do + # puts "the time is #{Time.now}" + # timer.cancel if (n+=1) > 5 + # end + # + class PeriodicTimer + # Create a new periodic timer that executes every interval seconds + def initialize interval, callback=nil, &block + @interval = interval + @code = callback || block + @cancelled = false + @work = method(:fire) + schedule + end + + # Cancel the periodic timer + def cancel + @cancelled = true + end + + # Fire the timer every interval seconds + attr_accessor :interval + + # @private + def schedule + EventMachine::add_timer @interval, @work + end + + # @private + def fire + unless @cancelled + @code.call + schedule + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/lib/em/version.rb b/bin/gems/eventmachine-1.2.7/lib/em/version.rb new file mode 100644 index 00000000..ffc43103 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/em/version.rb @@ -0,0 +1,3 @@ +module EventMachine + VERSION = "1.2.7" +end diff --git a/bin/gems/eventmachine-1.2.7/lib/eventmachine.rb b/bin/gems/eventmachine-1.2.7/lib/eventmachine.rb new file mode 100644 index 00000000..08737476 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/eventmachine.rb @@ -0,0 +1,1601 @@ +if defined?(EventMachine.library_type) and EventMachine.library_type == :pure_ruby + # assume 'em/pure_ruby' was loaded already +elsif RUBY_PLATFORM =~ /java/ + require 'java' + require 'jeventmachine' +else + begin + require 'rubyeventmachine' + rescue LoadError + warn "Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'" + raise + end +end + +require 'em/version' +require 'em/pool' +require 'em/deferrable' +require 'em/future' +require 'em/streamer' +require 'em/spawnable' +require 'em/processes' +require 'em/iterator' +require 'em/buftok' +require 'em/timers' +require 'em/protocols' +require 'em/connection' +require 'em/callback' +require 'em/queue' +require 'em/channel' +require 'em/file_watch' +require 'em/process_watch' +require 'em/tick_loop' +require 'em/resolver' +require 'em/completion' +require 'em/threaded_resource' + +require 'shellwords' +require 'thread' +require 'resolv' + +# Top-level EventMachine namespace. If you are looking for EventMachine examples, see {file:docs/GettingStarted.md EventMachine tutorial}. +# +# ## Key methods ## +# ### Starting and stopping the event loop ### +# +# * {EventMachine.run} +# * {EventMachine.stop_event_loop} +# +# ### Implementing clients ### +# +# * {EventMachine.connect} +# +# ### Implementing servers ### +# +# * {EventMachine.start_server} +# +# ### Working with timers ### +# +# * {EventMachine.add_timer} +# * {EventMachine.add_periodic_timer} +# * {EventMachine.cancel_timer} +# +# ### Working with blocking tasks ### +# +# * {EventMachine.defer} +# * {EventMachine.next_tick} +# +# ### Efficient proxying ### +# +# * {EventMachine.enable_proxy} +# * {EventMachine.disable_proxy} +module EventMachine + class << self + # Exposed to allow joining on the thread, when run in a multithreaded + # environment. Performing other actions on the thread has undefined + # semantics (read: a dangerous endevor). + # + # @return [Thread] + attr_reader :reactor_thread + end + @next_tick_mutex = Mutex.new + @reactor_running = false + @next_tick_queue = [] + @tails = [] + @threadpool = @threadqueue = @resultqueue = nil + @all_threads_spawned = false + + # System errnos + # @private + ERRNOS = Errno::constants.grep(/^E/).inject(Hash.new(:unknown)) { |hash, name| + errno = Errno.__send__(:const_get, name) + hash[errno::Errno] = errno + hash + } + + # Initializes and runs an event loop. This method only returns if code inside the block passed to this method + # calls {EventMachine.stop_event_loop}. The block is executed after initializing its internal event loop but *before* running the loop, + # therefore this block is the right place to call any code that needs event loop to run, for example, {EventMachine.start_server}, + # {EventMachine.connect} or similar methods of libraries that use EventMachine under the hood + # (like `EventMachine::HttpRequest.new` or `AMQP.start`). + # + # Programs that are run for long periods of time (e.g. servers) usually start event loop by calling {EventMachine.run}, and let it + # run "forever". It's also possible to use {EventMachine.run} to make a single client-connection to a remote server, + # process the data flow from that single connection, and then call {EventMachine.stop_event_loop} to stop, in other words, + # to run event loop for a short period of time (necessary to complete some operation) and then shut it down. + # + # Once event loop is running, it is perfectly possible to start multiple servers and clients simultaneously: content-aware + # proxies like [Proxymachine](https://github.com/mojombo/proxymachine) do just that. + # + # ## Using EventMachine with Ruby on Rails and other Web application frameworks ## + # + # Standalone applications often run event loop on the main thread, thus blocking for their entire lifespan. In case of Web applications, + # if you are running an EventMachine-based app server such as [Thin](http://code.macournoyer.com/thin/) or [Goliath](https://github.com/postrank-labs/goliath/), + # they start event loop for you. Servers like Unicorn, Apache Passenger or Mongrel occupy main Ruby thread to serve HTTP(S) requests. This means + # that calling {EventMachine.run} on the same thread is not an option (it will result in Web server never binding to the socket). + # In that case, start event loop in a separate thread as demonstrated below. + # + # + # @example Starting EventMachine event loop in the current thread to run the "Hello, world"-like Echo server example + # + # #!/usr/bin/env ruby + # + # require 'rubygems' # or use Bundler.setup + # require 'eventmachine' + # + # class EchoServer < EM::Connection + # def receive_data(data) + # send_data(data) + # end + # end + # + # EventMachine.run do + # EventMachine.start_server("0.0.0.0", 10000, EchoServer) + # end + # + # + # @example Starting EventMachine event loop in a separate thread + # + # # doesn't block current thread, can be used with Ruby on Rails, Sinatra, Merb, Rack + # # and any other application server that occupies main Ruby thread. + # Thread.new { EventMachine.run } + # + # + # @note This method blocks calling thread. If you need to start EventMachine event loop from a Web app + # running on a non event-driven server (Unicorn, Apache Passenger, Mongrel), do it in a separate thread like demonstrated + # in one of the examples. + # @see file:docs/GettingStarted.md Getting started with EventMachine + # @see EventMachine.stop_event_loop + def self.run blk=nil, tail=nil, &block + # Obsoleted the use_threads mechanism. + # 25Nov06: Added the begin/ensure block. We need to be sure that release_machine + # gets called even if an exception gets thrown within any of the user code + # that the event loop runs. The best way to see this is to run a unit + # test with two functions, each of which calls {EventMachine.run} and each of + # which throws something inside of #run. Without the ensure, the second test + # will start without release_machine being called and will immediately throw + + # + if @reactor_running and @reactor_pid != Process.pid + # Reactor was started in a different parent, meaning we have forked. + # Clean up reactor state so a new reactor boots up in this child. + stop_event_loop + release_machine + cleanup_machine + @reactor_running = false + end + + tail and @tails.unshift(tail) + + if reactor_running? + (b = blk || block) and b.call # next_tick(b) + else + @conns = {} + @acceptors = {} + @timers = {} + @wrapped_exception = nil + @next_tick_queue ||= [] + @tails ||= [] + begin + initialize_event_machine + @reactor_pid = Process.pid + @reactor_thread = Thread.current + @reactor_running = true + + (b = blk || block) and add_timer(0, b) + if @next_tick_queue && !@next_tick_queue.empty? + add_timer(0) { signal_loopbreak } + end + + # Rubinius needs to come back into "Ruby space" for GC to work, + # so we'll crank the machine here. + if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx" + while run_machine_once; end + else + run_machine + end + + ensure + until @tails.empty? + @tails.pop.call + end + + release_machine + cleanup_machine + @reactor_running = false + @reactor_thread = nil + end + + raise @wrapped_exception if @wrapped_exception + end + end + + # Sugars a common use case. Will pass the given block to #run, but will terminate + # the reactor loop and exit the function as soon as the code in the block completes. + # (Normally, {EventMachine.run} keeps running indefinitely, even after the block supplied to it + # finishes running, until user code calls {EventMachine.stop}) + # + def self.run_block &block + pr = proc { + block.call + EventMachine::stop + } + run(&pr) + end + + # @return [Boolean] true if the calling thread is the same thread as the reactor. + def self.reactor_thread? + Thread.current == @reactor_thread + end + + # Runs the given callback on the reactor thread, or immediately if called + # from the reactor thread. Accepts the same arguments as {EventMachine::Callback} + def self.schedule(*a, &b) + cb = Callback(*a, &b) + if reactor_running? && reactor_thread? + cb.call + else + next_tick { cb.call } + end + end + + # Forks a new process, properly stops the reactor and then calls {EventMachine.run} inside of it again, passing your block. + def self.fork_reactor &block + # This implementation is subject to change, especially if we clean up the relationship + # of EM#run to @reactor_running. + # Original patch by Aman Gupta. + # + Kernel.fork do + if reactor_running? + stop_event_loop + release_machine + cleanup_machine + @reactor_running = false + @reactor_thread = nil + end + run block + end + end + + # Clean up Ruby space following a release_machine + def self.cleanup_machine + if @threadpool && !@threadpool.empty? + # Tell the threads to stop + @threadpool.each { |t| t.exit } + # Join the threads or bump the stragglers one more time + @threadpool.each { |t| t.join 0.01 || t.exit } + end + @threadpool = nil + @threadqueue = nil + @resultqueue = nil + @all_threads_spawned = false + @next_tick_queue = [] + end + + # Adds a block to call as the reactor is shutting down. + # + # These callbacks are called in the _reverse_ order to which they are added. + # + # @example Scheduling operations to be run when EventMachine event loop is stopped + # + # EventMachine.run do + # EventMachine.add_shutdown_hook { puts "b" } + # EventMachine.add_shutdown_hook { puts "a" } + # EventMachine.stop + # end + # + # # Outputs: + # # a + # # b + # + def self.add_shutdown_hook &block + @tails << block + end + + # Adds a one-shot timer to the event loop. + # Call it with one or two parameters. The first parameters is a delay-time + # expressed in *seconds* (not milliseconds). The second parameter, if + # present, must be an object that responds to :call. If 2nd parameter is not given, then you + # can also simply pass a block to the method call. + # + # This method may be called from the block passed to {EventMachine.run} + # or from any callback method. It schedules execution of the proc or block + # passed to it, after the passage of an interval of time equal to + # *at least* the number of seconds specified in the first parameter to + # the call. + # + # {EventMachine.add_timer} is a non-blocking method. Callbacks can and will + # be called during the interval of time that the timer is in effect. + # There is no built-in limit to the number of timers that can be outstanding at + # any given time. + # + # @example Setting a one-shot timer with EventMachine + # + # EventMachine.run { + # puts "Starting the run now: #{Time.now}" + # EventMachine.add_timer 5, proc { puts "Executing timer event: #{Time.now}" } + # EventMachine.add_timer(10) { puts "Executing timer event: #{Time.now}" } + # } + # + # @param [Integer] delay Delay in seconds + # @see EventMachine::Timer + # @see EventMachine.add_periodic_timer + def self.add_timer *args, &block + interval = args.shift + code = args.shift || block + if code + # check too many timers! + s = add_oneshot_timer((interval.to_f * 1000).to_i) + @timers[s] = code + s + end + end + + # Adds a periodic timer to the event loop. + # It takes the same parameters as the one-shot timer method, {EventMachine.add_timer}. + # This method schedules execution of the given block repeatedly, at intervals + # of time *at least* as great as the number of seconds given in the first + # parameter to the call. + # + # @example Write a dollar-sign to stderr every five seconds, without blocking + # + # EventMachine.run { + # EventMachine.add_periodic_timer( 5 ) { $stderr.write "$" } + # } + # + # @param [Integer] delay Delay in seconds + # + # @see EventMachine::PeriodicTimer + # @see EventMachine.add_timer + # + def self.add_periodic_timer *args, &block + interval = args.shift + code = args.shift || block + + EventMachine::PeriodicTimer.new(interval, code) + end + + + # Cancel a timer (can be a callback or an {EventMachine::Timer} instance). + # + # @param [#cancel, #call] timer_or_sig A timer to cancel + # @see EventMachine::Timer#cancel + def self.cancel_timer timer_or_sig + if timer_or_sig.respond_to? :cancel + timer_or_sig.cancel + else + @timers[timer_or_sig] = false if @timers.has_key?(timer_or_sig) + end + end + + + # Causes the processing loop to stop executing, which will cause all open connections and accepting servers + # to be run down and closed. Connection termination callbacks added using {EventMachine.add_shutdown_hook} + # will be called as part of running this method. + # + # When all of this processing is complete, the call to {EventMachine.run} which started the processing loop + # will return and program flow will resume from the statement following {EventMachine.run} call. + # + # @example Stopping a running EventMachine event loop + # + # require 'rubygems' + # require 'eventmachine' + # + # module Redmond + # def post_init + # puts "We're sending a dumb HTTP request to the remote peer." + # send_data "GET / HTTP/1.1\r\nHost: www.microsoft.com\r\n\r\n" + # end + # + # def receive_data data + # puts "We received #{data.length} bytes from the remote peer." + # puts "We're going to stop the event loop now." + # EventMachine::stop_event_loop + # end + # + # def unbind + # puts "A connection has terminated." + # end + # end + # + # puts "We're starting the event loop now." + # EventMachine.run { + # EventMachine.connect "www.microsoft.com", 80, Redmond + # } + # puts "The event loop has stopped." + # + # # This program will produce approximately the following output: + # # + # # We're starting the event loop now. + # # We're sending a dumb HTTP request to the remote peer. + # # We received 1440 bytes from the remote peer. + # # We're going to stop the event loop now. + # # A connection has terminated. + # # The event loop has stopped. + # + # + def self.stop_event_loop + EventMachine::stop + end + + # Initiates a TCP server (socket acceptor) on the specified IP address and port. + # + # The IP address must be valid on the machine where the program + # runs, and the process must be privileged enough to listen + # on the specified port (on Unix-like systems, superuser privileges + # are usually required to listen on any port lower than 1024). + # Only one listener may be running on any given address/port + # combination. start_server will fail if the given address and port + # are already listening on the machine, either because of a prior call + # to {.start_server} or some unrelated process running on the machine. + # If {.start_server} succeeds, the new network listener becomes active + # immediately and starts accepting connections from remote peers, + # and these connections generate callback events that are processed + # by the code specified in the handler parameter to {.start_server}. + # + # The optional handler which is passed to this method is the key + # to EventMachine's ability to handle particular network protocols. + # The handler parameter passed to start_server must be a Ruby Module + # that you must define. When the network server that is started by + # start_server accepts a new connection, it instantiates a new + # object of an anonymous class that is inherited from {EventMachine::Connection}, + # *into which your handler module have been included*. Arguments passed into start_server + # after the class name are passed into the constructor during the instantiation. + # + # Your handler module may override any of the methods in {EventMachine::Connection}, + # such as {EventMachine::Connection#receive_data}, in order to implement the specific behavior + # of the network protocol. + # + # Callbacks invoked in response to network events *always* take place + # within the execution context of the object derived from {EventMachine::Connection} + # extended by your handler module. There is one object per connection, and + # all of the callbacks invoked for a particular connection take the form + # of instance methods called against the corresponding {EventMachine::Connection} + # object. Therefore, you are free to define whatever instance variables you + # wish, in order to contain the per-connection state required by the network protocol you are + # implementing. + # + # {EventMachine.start_server} is usually called inside the block passed to {EventMachine.run}, + # but it can be called from any EventMachine callback. {EventMachine.start_server} will fail + # unless the EventMachine event loop is currently running (which is why + # it's often called in the block suppled to {EventMachine.run}). + # + # You may call start_server any number of times to start up network + # listeners on different address/port combinations. The servers will + # all run simultaneously. More interestingly, each individual call to start_server + # can specify a different handler module and thus implement a different + # network protocol from all the others. + # + # @example + # + # require 'rubygems' + # require 'eventmachine' + # + # # Here is an example of a server that counts lines of input from the remote + # # peer and sends back the total number of lines received, after each line. + # # Try the example with more than one client connection opened via telnet, + # # and you will see that the line count increments independently on each + # # of the client connections. Also very important to note, is that the + # # handler for the receive_data function, which our handler redefines, may + # # not assume that the data it receives observes any kind of message boundaries. + # # Also, to use this example, be sure to change the server and port parameters + # # to the start_server call to values appropriate for your environment. + # module LineCounter + # MaxLinesPerConnection = 10 + # + # def post_init + # puts "Received a new connection" + # @data_received = "" + # @line_count = 0 + # end + # + # def receive_data data + # @data_received << data + # while @data_received.slice!( /^[^\n]*[\n]/m ) + # @line_count += 1 + # send_data "received #{@line_count} lines so far\r\n" + # @line_count == MaxLinesPerConnection and close_connection_after_writing + # end + # end + # end + # + # EventMachine.run { + # host, port = "192.168.0.100", 8090 + # EventMachine.start_server host, port, LineCounter + # puts "Now accepting connections on address #{host}, port #{port}..." + # EventMachine.add_periodic_timer(10) { $stderr.write "*" } + # } + # + # @param [String] server Host to bind to. + # @param [Integer] port Port to bind to. + # @param [Module, Class] handler A module or class that implements connection callbacks + # + # @note Don't forget that in order to bind to ports < 1024 on Linux, *BSD and Mac OS X your process must have superuser privileges. + # + # @see file:docs/GettingStarted.md EventMachine tutorial + # @see EventMachine.stop_server + def self.start_server server, port=nil, handler=nil, *args, &block + begin + port = Integer(port) + rescue ArgumentError, TypeError + # there was no port, so server must be a unix domain socket + # the port argument is actually the handler, and the handler is one of the args + args.unshift handler if handler + handler = port + port = nil + end if port + + klass = klass_from_handler(Connection, handler, *args) + + s = if port + start_tcp_server server, port + else + start_unix_server server + end + @acceptors[s] = [klass,args,block] + s + end + + # Attach to an existing socket's file descriptor. The socket may have been + # started with {EventMachine.start_server}. + def self.attach_server sock, handler=nil, *args, &block + klass = klass_from_handler(Connection, handler, *args) + sd = sock.respond_to?(:fileno) ? sock.fileno : sock + s = attach_sd(sd) + @acceptors[s] = [klass,args,block,sock] + s + end + + # Stop a TCP server socket that was started with {EventMachine.start_server}. + # @see EventMachine.start_server + def self.stop_server signature + EventMachine::stop_tcp_server signature + end + + # Start a Unix-domain server. + # + # Note that this is an alias for {EventMachine.start_server}, which can be used to start both + # TCP and Unix-domain servers. + # + # @see EventMachine.start_server + def self.start_unix_domain_server filename, *args, &block + start_server filename, *args, &block + end + + # Initiates a TCP connection to a remote server and sets up event handling for the connection. + # {EventMachine.connect} requires event loop to be running (see {EventMachine.run}). + # + # {EventMachine.connect} takes the IP address (or hostname) and + # port of the remote server you want to connect to. + # It also takes an optional handler (a module or a subclass of {EventMachine::Connection}) which you must define, that + # contains the callbacks that will be invoked by the event loop on behalf of the connection. + # + # Learn more about connection lifecycle callbacks in the {file:docs/GettingStarted.md EventMachine tutorial} and + # {file:docs/ConnectionLifecycleCallbacks.md Connection lifecycle guide}. + # + # + # @example + # + # # Here's a program which connects to a web server, sends a naive + # # request, parses the HTTP header of the response, and then + # # (antisocially) ends the event loop, which automatically drops the connection + # # (and incidentally calls the connection's unbind method). + # module DumbHttpClient + # def post_init + # send_data "GET / HTTP/1.1\r\nHost: _\r\n\r\n" + # @data = "" + # @parsed = false + # end + # + # def receive_data data + # @data << data + # if !@parsed and @data =~ /[\n][\r]*[\n]/m + # @parsed = true + # puts "RECEIVED HTTP HEADER:" + # $`.each {|line| puts ">>> #{line}" } + # + # puts "Now we'll terminate the loop, which will also close the connection" + # EventMachine::stop_event_loop + # end + # end + # + # def unbind + # puts "A connection has terminated" + # end + # end + # + # EventMachine.run { + # EventMachine.connect "www.bayshorenetworks.com", 80, DumbHttpClient + # } + # puts "The event loop has ended" + # + # + # @example Defining protocol handler as a class + # + # class MyProtocolHandler < EventMachine::Connection + # def initialize *args + # super + # # whatever else you want to do here + # end + # + # # ... + # end + # + # + # @param [String] server Host to connect to + # @param [Integer] port Port to connect to + # @param [Module, Class] handler A module or class that implements connection lifecycle callbacks + # + # @see EventMachine.start_server + # @see file:docs/GettingStarted.md EventMachine tutorial + def self.connect server, port=nil, handler=nil, *args, &blk + # EventMachine::connect initiates a TCP connection to a remote + # server and sets up event-handling for the connection. + # It internally creates an object that should not be handled + # by the caller. HOWEVER, it's often convenient to get the + # object to set up interfacing to other objects in the system. + # We return the newly-created anonymous-class object to the caller. + # It's expected that a considerable amount of code will depend + # on this behavior, so don't change it. + # + # Ok, added support for a user-defined block, 13Apr06. + # This leads us to an interesting choice because of the + # presence of the post_init call, which happens in the + # initialize method of the new object. We call the user's + # block and pass the new object to it. This is a great + # way to do protocol-specific initiation. It happens + # AFTER post_init has been called on the object, which I + # certainly hope is the right choice. + # Don't change this lightly, because accepted connections + # are different from connected ones and we don't want + # to have them behave differently with respect to post_init + # if at all possible. + + bind_connect nil, nil, server, port, handler, *args, &blk + end + + # This method is like {EventMachine.connect}, but allows for a local address/port + # to bind the connection to. + # + # @see EventMachine.connect + def self.bind_connect bind_addr, bind_port, server, port=nil, handler=nil, *args + begin + port = Integer(port) + rescue ArgumentError, TypeError + # there was no port, so server must be a unix domain socket + # the port argument is actually the handler, and the handler is one of the args + args.unshift handler if handler + handler = port + port = nil + end if port + + klass = klass_from_handler(Connection, handler, *args) + + s = if port + if bind_addr + bind_connect_server bind_addr, bind_port.to_i, server, port + else + connect_server server, port + end + else + connect_unix_server server + end + + c = klass.new s, *args + @conns[s] = c + block_given? and yield c + c + end + + # {EventMachine.watch} registers a given file descriptor or IO object with the eventloop. The + # file descriptor will not be modified (it will remain blocking or non-blocking). + # + # The eventloop can be used to process readable and writable events on the file descriptor, using + # {EventMachine::Connection#notify_readable=} and {EventMachine::Connection#notify_writable=} + # + # {EventMachine::Connection#notify_readable?} and {EventMachine::Connection#notify_writable?} can be used + # to check what events are enabled on the connection. + # + # To detach the file descriptor, use {EventMachine::Connection#detach} + # + # @example + # + # module SimpleHttpClient + # def notify_readable + # header = @io.readline + # + # if header == "\r\n" + # # detach returns the file descriptor number (fd == @io.fileno) + # fd = detach + # end + # rescue EOFError + # detach + # end + # + # def unbind + # EM.next_tick do + # # socket is detached from the eventloop, but still open + # data = @io.read + # end + # end + # end + # + # EventMachine.run { + # sock = TCPSocket.new('site.com', 80) + # sock.write("GET / HTTP/1.0\r\n\r\n") + # conn = EventMachine.watch(sock, SimpleHttpClient) + # conn.notify_readable = true + # } + # + # @author Riham Aldakkak (eSpace Technologies) + def EventMachine::watch io, handler=nil, *args, &blk + attach_io io, true, handler, *args, &blk + end + + # Attaches an IO object or file descriptor to the eventloop as a regular connection. + # The file descriptor will be set as non-blocking, and EventMachine will process + # receive_data and send_data events on it as it would for any other connection. + # + # To watch a fd instead, use {EventMachine.watch}, which will not alter the state of the socket + # and fire notify_readable and notify_writable events instead. + def EventMachine::attach io, handler=nil, *args, &blk + attach_io io, false, handler, *args, &blk + end + + # @private + def EventMachine::attach_io io, watch_mode, handler=nil, *args + klass = klass_from_handler(Connection, handler, *args) + + if !watch_mode and klass.public_instance_methods.any?{|m| [:notify_readable, :notify_writable].include? m.to_sym } + raise ArgumentError, "notify_readable/writable with EM.attach is not supported. Use EM.watch(io){ |c| c.notify_readable = true }" + end + + if io.respond_to?(:fileno) + # getDescriptorByFileno deprecated in JRuby 1.7.x, removed in JRuby 9000 + if defined?(JRuby) && JRuby.runtime.respond_to?(:getDescriptorByFileno) + fd = JRuby.runtime.getDescriptorByFileno(io.fileno).getChannel + else + fd = io.fileno + end + else + fd = io + end + + s = attach_fd fd, watch_mode + c = klass.new s, *args + + c.instance_variable_set(:@io, io) + c.instance_variable_set(:@watch_mode, watch_mode) + c.instance_variable_set(:@fd, fd) + + @conns[s] = c + block_given? and yield c + c + end + + + # Connect to a given host/port and re-use the provided {EventMachine::Connection} instance. + # Consider also {EventMachine::Connection#reconnect}. + # + # @see EventMachine::Connection#reconnect + def self.reconnect server, port, handler + # Observe, the test for already-connected FAILS if we call a reconnect inside post_init, + # because we haven't set up the connection in @conns by that point. + # RESIST THE TEMPTATION to "fix" this problem by redefining the behavior of post_init. + # + # Changed 22Nov06: if called on an already-connected handler, just return the + # handler and do nothing more. Originally this condition raised an exception. + # We may want to change it yet again and call the block, if any. + + raise "invalid handler" unless handler.respond_to?(:connection_completed) + #raise "still connected" if @conns.has_key?(handler.signature) + return handler if @conns.has_key?(handler.signature) + + s = if port + connect_server server, port + else + connect_unix_server server + end + handler.signature = s + @conns[s] = handler + block_given? and yield handler + handler + end + + + # Make a connection to a Unix-domain socket. This method is simply an alias for {.connect}, + # which can connect to both TCP and Unix-domain sockets. Make sure that your process has sufficient + # permissions to open the socket it is given. + # + # @param [String] socketname Unix domain socket (local fully-qualified path) you want to connect to. + # + # @note UNIX sockets, as the name suggests, are not available on Microsoft Windows. + def self.connect_unix_domain socketname, *args, &blk + connect socketname, *args, &blk + end + + + # Used for UDP-based protocols. Its usage is similar to that of {EventMachine.start_server}. + # + # This method will create a new UDP (datagram) socket and + # bind it to the address and port that you specify. + # The normal callbacks (see {EventMachine.start_server}) will + # be called as events of interest occur on the newly-created + # socket, but there are some differences in how they behave. + # + # {Connection#receive_data} will be called when a datagram packet + # is received on the socket, but unlike TCP sockets, the message + # boundaries of the received data will be respected. In other words, + # if the remote peer sent you a datagram of a particular size, + # you may rely on {Connection#receive_data} to give you the + # exact data in the packet, with the original data length. + # Also observe that Connection#receive_data may be called with a + # *zero-length* data payload, since empty datagrams are permitted in UDP. + # + # {Connection#send_data} is available with UDP packets as with TCP, + # but there is an important difference. Because UDP communications + # are *connectionless*, there is no implicit recipient for the packets you + # send. Ordinarily you must specify the recipient for each packet you send. + # However, EventMachine provides for the typical pattern of receiving a UDP datagram + # from a remote peer, performing some operation, and then sending + # one or more packets in response to the same remote peer. + # To support this model easily, just use {Connection#send_data} + # in the code that you supply for {Connection#receive_data}. + # + # EventMachine will provide an implicit return address for any messages sent to + # {Connection#send_data} within the context of a {Connection#receive_data} callback, + # and your response will automatically go to the correct remote peer. + # + # Observe that the port number that you supply to {EventMachine.open_datagram_socket} + # may be zero. In this case, EventMachine will create a UDP socket + # that is bound to an [ephemeral port](http://en.wikipedia.org/wiki/Ephemeral_port). + # This is not appropriate for servers that must publish a well-known + # port to which remote peers may send datagrams. But it can be useful + # for clients that send datagrams to other servers. + # If you do this, you will receive any responses from the remote + # servers through the normal {Connection#receive_data} callback. + # Observe that you will probably have issues with firewalls blocking + # the ephemeral port numbers, so this technique is most appropriate for LANs. + # + # If you wish to send datagrams to arbitrary remote peers (not + # necessarily ones that have sent data to which you are responding), + # then see {Connection#send_datagram}. + # + # DO NOT call send_data from a datagram socket outside of a {Connection#receive_data} method. Use {Connection#send_datagram}. + # If you do use {Connection#send_data} outside of a {Connection#receive_data} method, you'll get a confusing error + # because there is no "peer," as #send_data requires (inside of {EventMachine::Connection#receive_data}, + # {EventMachine::Connection#send_data} "fakes" the peer as described above). + # + # @param [String] address IP address + # @param [String] port Port + # @param [Class, Module] handler A class or a module that implements connection lifecycle callbacks. + def self.open_datagram_socket address, port, handler=nil, *args + # Replaced the implementation on 01Oct06. Thanks to Tobias Gustafsson for pointing + # out that this originally did not take a class but only a module. + + + klass = klass_from_handler(Connection, handler, *args) + s = open_udp_socket address, port.to_i + c = klass.new s, *args + @conns[s] = c + block_given? and yield c + c + end + + + # For advanced users. This function sets the default timer granularity, which by default is + # slightly smaller than 100 milliseconds. Call this function to set a higher or lower granularity. + # The function affects the behavior of {EventMachine.add_timer} and {EventMachine.add_periodic_timer}. + # Most applications will not need to call this function. + # + # Avoid setting the quantum to very low values because that may reduce performance under some extreme conditions. + # We recommend that you not use values lower than 10. + # + # This method only can be used if event loop is running. + # + # @param [Integer] mills New timer granularity, in milliseconds + # + # @see EventMachine.add_timer + # @see EventMachine.add_periodic_timer + # @see EventMachine::Timer + # @see EventMachine.run + def self.set_quantum mills + set_timer_quantum mills.to_i + end + + # Sets the maximum number of timers and periodic timers that may be outstanding at any + # given time. You only need to call {.set_max_timers} if you need more than the default + # number of timers, which on most platforms is 1000. + # + # @note This method has to be used *before* event loop is started. + # + # @param [Integer] ct Maximum number of timers that may be outstanding at any given time + # + # @see EventMachine.add_timer + # @see EventMachine.add_periodic_timer + # @see EventMachine::Timer + def self.set_max_timers ct + set_max_timer_count ct + end + + # Gets the current maximum number of allowed timers + # + # @return [Integer] Maximum number of timers that may be outstanding at any given time + def self.get_max_timers + get_max_timer_count + end + + # Returns the total number of connections (file descriptors) currently held by the reactor. + # Note that a tick must pass after the 'initiation' of a connection for this number to increment. + # It's usually accurate, but don't rely on the exact precision of this number unless you really know EM internals. + # + # @example + # + # EventMachine.run { + # EventMachine.connect("rubyeventmachine.com", 80) + # # count will be 0 in this case, because connection is not + # # established yet + # count = EventMachine.connection_count + # } + # + # + # @example + # + # EventMachine.run { + # EventMachine.connect("rubyeventmachine.com", 80) + # + # EventMachine.next_tick { + # # In this example, count will be 1 since the connection has been established in + # # the next loop of the reactor. + # count = EventMachine.connection_count + # } + # } + # + # @return [Integer] Number of connections currently held by the reactor. + def self.connection_count + self.get_connection_count + end + + # The is the responder for the loopback-signalled event. + # It can be fired either by code running on a separate thread ({EventMachine.defer}) or on + # the main thread ({EventMachine.next_tick}). + # It will often happen that a next_tick handler will reschedule itself. We + # consume a copy of the tick queue so that tick events scheduled by tick events + # have to wait for the next pass through the reactor core. + # + # @private + def self.run_deferred_callbacks + until (@resultqueue ||= []).empty? + result,cback = @resultqueue.pop + cback.call result if cback + end + + # Capture the size at the start of this tick... + size = @next_tick_mutex.synchronize { @next_tick_queue.size } + size.times do |i| + callback = @next_tick_mutex.synchronize { @next_tick_queue.shift } + begin + callback.call + rescue + exception_raised = true + raise + ensure + # This is a little nasty. The problem is, if an exception occurs during + # the callback, then we need to send a signal to the reactor to actually + # do some work during the next_tick. The only mechanism we have from the + # ruby side is next_tick itself, although ideally, we'd just drop a byte + # on the loopback descriptor. + next_tick {} if exception_raised + end + end + end + + + # EventMachine.defer is used for integrating blocking operations into EventMachine's control flow. + # The action of {.defer} is to take the block specified in the first parameter (the "operation") + # and schedule it for asynchronous execution on an internal thread pool maintained by EventMachine. + # When the operation completes, it will pass the result computed by the block (if any) back to the + # EventMachine reactor. Then, EventMachine calls the block specified in the second parameter to + # {.defer} (the "callback"), as part of its normal event handling loop. The result computed by the + # operation block is passed as a parameter to the callback. You may omit the callback parameter if + # you don't need to execute any code after the operation completes. If the operation raises an + # unhandled exception, the exception will be passed to the third parameter to {.defer} (the + # "errback"), as part of its normal event handling loop. If no errback is provided, the exception + # will be allowed to blow through to the main thread immediately. + # + # ## Caveats ## + # + # Note carefully that the code in your deferred operation will be executed on a separate + # thread from the main EventMachine processing and all other Ruby threads that may exist in + # your program. Also, multiple deferred operations may be running at once! Therefore, you + # are responsible for ensuring that your operation code is threadsafe. + # + # Don't write a deferred operation that will block forever. If so, the current implementation will + # not detect the problem, and the thread will never be returned to the pool. EventMachine limits + # the number of threads in its pool, so if you do this enough times, your subsequent deferred + # operations won't get a chance to run. + # + # The threads within the EventMachine's thread pool have abort_on_exception set to true. As a result, + # if an unhandled exception is raised by the deferred operation and an errback is not provided, it + # will blow through to the main thread immediately. If the main thread is within an indiscriminate + # rescue block at that time, the exception could be handled improperly by the main thread. + # + # @example + # + # operation = proc { + # # perform a long-running operation here, such as a database query. + # "result" # as usual, the last expression evaluated in the block will be the return value. + # } + # callback = proc {|result| + # # do something with result here, such as send it back to a network client. + # } + # errback = proc {|error| + # # do something with error here, such as re-raising or logging. + # } + # + # EventMachine.defer(operation, callback, errback) + # + # @param [#call] op An operation you want to offload to EventMachine thread pool + # @param [#call] callback A callback that will be run on the event loop thread after `operation` finishes. + # @param [#call] errback An errback that will be run on the event loop thread after `operation` raises an exception. + # + # @see EventMachine.threadpool_size + def self.defer op = nil, callback = nil, errback = nil, &blk + # OBSERVE that #next_tick hacks into this mechanism, so don't make any changes here + # without syncing there. + # + # Running with $VERBOSE set to true gives a warning unless all ivars are defined when + # they appear in rvalues. But we DON'T ever want to initialize @threadqueue unless we + # need it, because the Ruby threads are so heavyweight. We end up with this bizarre + # way of initializing @threadqueue because EventMachine is a Module, not a Class, and + # has no constructor. + + unless @threadpool + @threadpool = [] + @threadqueue = ::Queue.new + @resultqueue = ::Queue.new + spawn_threadpool + end + + @threadqueue << [op||blk,callback,errback] + end + + + # @private + def self.spawn_threadpool + until @threadpool.size == @threadpool_size.to_i + thread = Thread.new do + Thread.current.abort_on_exception = true + while true + begin + op, cback, eback = *@threadqueue.pop + rescue ThreadError + $stderr.puts $!.message + break # Ruby 2.0 may fail at Queue.pop + end + begin + result = op.call + @resultqueue << [result, cback] + rescue Exception => error + raise error unless eback + @resultqueue << [error, eback] + end + signal_loopbreak + end + end + @threadpool << thread + end + @all_threads_spawned = true + end + + ## + # Returns +true+ if all deferred actions are done executing and their + # callbacks have been fired. + # + def self.defers_finished? + return false if @threadpool and !@all_threads_spawned + return false if @threadqueue and not @threadqueue.empty? + return false if @resultqueue and not @resultqueue.empty? + return false if @threadpool and @threadqueue.num_waiting != @threadpool.size + return true + end + + class << self + # @private + attr_reader :threadpool + + # Size of the EventMachine.defer threadpool (defaults to 20) + # @return [Number] + attr_accessor :threadpool_size + EventMachine.threadpool_size = 20 + end + + # Schedules a proc for execution immediately after the next "turn" through the reactor + # core. An advanced technique, this can be useful for improving memory management and/or + # application responsiveness, especially when scheduling large amounts of data for + # writing to a network connection. + # + # This method takes either a single argument (which must be a callable object) or a block. + # + # @param [#call] pr A callable object to run + def self.next_tick pr=nil, &block + # This works by adding to the @resultqueue that's used for #defer. + # The general idea is that next_tick is used when we want to give the reactor a chance + # to let other operations run, either to balance the load out more evenly, or to let + # outbound network buffers drain, or both. So we probably do NOT want to block, and + # we probably do NOT want to be spinning any threads. A program that uses next_tick + # but not #defer shouldn't suffer the penalty of having Ruby threads running. They're + # extremely expensive even if they're just sleeping. + + raise ArgumentError, "no proc or block given" unless ((pr && pr.respond_to?(:call)) or block) + @next_tick_mutex.synchronize do + @next_tick_queue << ( pr || block ) + end + signal_loopbreak if reactor_running? + end + + # A wrapper over the setuid system call. Particularly useful when opening a network + # server on a privileged port because you can use this call to drop privileges + # after opening the port. Also very useful after a call to {.set_descriptor_table_size}, + # which generally requires that you start your process with root privileges. + # + # This method is intended for use in enforcing security requirements, consequently + # it will throw a fatal error and end your program if it fails. + # + # @param [String] username The effective name of the user whose privilege-level your process should attain. + # + # @note This method has no effective implementation on Windows or in the pure-Ruby + # implementation of EventMachine + def self.set_effective_user username + EventMachine::setuid_string username + end + + + # Sets the maximum number of file or socket descriptors that your process may open. + # If you call this method with no arguments, it will simply return + # the current size of the descriptor table without attempting to change it. + # + # The new limit on open descriptors **only** applies to sockets and other descriptors + # that belong to EventMachine. It has **no effect** on the number of descriptors + # you can create in ordinary Ruby code. + # + # Not available on all platforms. Increasing the number of descriptors beyond its + # default limit usually requires superuser privileges. (See {.set_effective_user} + # for a way to drop superuser privileges while your program is running.) + # + # @param [Integer] n_descriptors The maximum number of file or socket descriptors that your process may open + # @return [Integer] The new descriptor table size. + def self.set_descriptor_table_size n_descriptors=nil + EventMachine::set_rlimit_nofile n_descriptors + end + + + + # Runs an external process. + # + # @example + # + # module RubyCounter + # def post_init + # # count up to 5 + # send_data "5\n" + # end + # def receive_data data + # puts "ruby sent me: #{data}" + # end + # def unbind + # puts "ruby died with exit status: #{get_status.exitstatus}" + # end + # end + # + # EventMachine.run { + # EventMachine.popen("ruby -e' $stdout.sync = true; gets.to_i.times{ |i| puts i+1; sleep 1 } '", RubyCounter) + # } + # + # @note This method is not supported on Microsoft Windows + # @see EventMachine::DeferrableChildProcess + # @see EventMachine.system + def self.popen cmd, handler=nil, *args + # At this moment, it's only available on Unix. + # Perhaps misnamed since the underlying function uses socketpair and is full-duplex. + + klass = klass_from_handler(Connection, handler, *args) + w = case cmd + when Array + cmd + when String + Shellwords::shellwords( cmd ) + end + w.unshift( w.first ) if w.first + s = invoke_popen( w ) + c = klass.new s, *args + @conns[s] = c + yield(c) if block_given? + c + end + + + # Tells you whether the EventMachine reactor loop is currently running. + # + # Useful when writing libraries that want to run event-driven code, but may + # be running in programs that are already event-driven. In such cases, if {EventMachine.reactor_running?} + # returns false, your code can invoke {EventMachine.run} and run your application code inside + # the block passed to that method. If this method returns true, just + # execute your event-aware code. + # + # @return [Boolean] true if the EventMachine reactor loop is currently running + def self.reactor_running? + @reactor_running && Process.pid == @reactor_pid + end + + + # (Experimental) + # + # @private + def self.open_keyboard handler=nil, *args + klass = klass_from_handler(Connection, handler, *args) + + s = read_keyboard + c = klass.new s, *args + @conns[s] = c + block_given? and yield c + c + end + + # EventMachine's file monitoring API. Currently supported are the following events + # on individual files, using inotify on Linux systems, and kqueue for *BSD and Mac OS X: + # + # * File modified (written to) + # * File moved/renamed + # * File deleted + # + # EventMachine::watch_file takes a filename and a handler Module containing your custom callback methods. + # This will setup the low level monitoring on the specified file, and create a new EventMachine::FileWatch + # object with your Module mixed in. FileWatch is a subclass of {EventMachine::Connection}, so callbacks on this object + # work in the familiar way. The callbacks that will be fired by EventMachine are: + # + # * file_modified + # * file_moved + # * file_deleted + # + # You can access the filename being monitored from within this object using {FileWatch#path}. + # + # When a file is deleted, {FileWatch#stop_watching} will be called after your file_deleted callback, + # to clean up the underlying monitoring and remove EventMachine's reference to the now-useless {FileWatch} instance. + # This will in turn call unbind, if you wish to use it. + # + # The corresponding system-level Errno will be raised when attempting to monitor non-existent files, + # files with wrong permissions, or if an error occurs dealing with inotify/kqueue. + # + # @example + # + # # Before running this example, make sure we have a file to monitor: + # # $ echo "bar" > /tmp/foo + # + # module Handler + # def file_modified + # puts "#{path} modified" + # end + # + # def file_moved + # puts "#{path} moved" + # end + # + # def file_deleted + # puts "#{path} deleted" + # end + # + # def unbind + # puts "#{path} monitoring ceased" + # end + # end + # + # # for efficient file watching, use kqueue on Mac OS X + # EventMachine.kqueue = true if EventMachine.kqueue? + # + # EventMachine.run { + # EventMachine.watch_file("/tmp/foo", Handler) + # } + # + # # $ echo "baz" >> /tmp/foo => "/tmp/foo modified" + # # $ mv /tmp/foo /tmp/oof => "/tmp/foo moved" + # # $ rm /tmp/oof => "/tmp/foo deleted" + # + # @note The ability to pick up on the new filename after a rename is not yet supported. + # Calling #path will always return the filename you originally used. + # + # @param [String] filename Local path to the file to watch. + # @param [Class, Module] handler A class or module that implements event handlers associated with the file. + def self.watch_file(filename, handler=nil, *args) + klass = klass_from_handler(FileWatch, handler, *args) + + s = EM::watch_filename(filename) + c = klass.new s, *args + # we have to set the path like this because of how Connection.new works + c.instance_variable_set("@path", filename) + @conns[s] = c + block_given? and yield c + c + end + + # EventMachine's process monitoring API. On Mac OS X and *BSD this method is implemented using kqueue. + # + # @example + # + # module ProcessWatcher + # def process_exited + # put 'the forked child died!' + # end + # end + # + # pid = fork{ sleep } + # + # EventMachine.run { + # EventMachine.watch_process(pid, ProcessWatcher) + # EventMachine.add_timer(1){ Process.kill('TERM', pid) } + # } + # + # @param [Integer] pid PID of the process to watch. + # @param [Class, Module] handler A class or module that implements event handlers associated with the file. + def self.watch_process(pid, handler=nil, *args) + pid = pid.to_i + + klass = klass_from_handler(ProcessWatch, handler, *args) + + s = EM::watch_pid(pid) + c = klass.new s, *args + # we have to set the path like this because of how Connection.new works + c.instance_variable_set("@pid", pid) + @conns[s] = c + block_given? and yield c + c + end + + # Catch-all for errors raised during event loop callbacks. + # + # @example + # + # EventMachine.error_handler{ |e| + # puts "Error raised during event loop: #{e.message}" + # } + # + # @param [#call] cb Global catch-all errback + def self.error_handler cb = nil, &blk + if cb or blk + @error_handler = cb || blk + elsif instance_variable_defined? :@error_handler + remove_instance_variable :@error_handler + end + end + + # This method allows for direct writing of incoming data back out to another descriptor, at the C++ level in the reactor. + # This is very efficient and especially useful for proxies where high performance is required. Propogating data from a server response + # all the way up to Ruby, and then back down to the reactor to be sent back to the client, is often unnecessary and + # incurs a significant performance decrease. + # + # The two arguments are instance of {EventMachine::Connection} subclasses, 'from' and 'to'. 'from' is the connection whose inbound data you want + # relayed back out. 'to' is the connection to write it to. + # + # Once you call this method, the 'from' connection will no longer get receive_data callbacks from the reactor, + # except in the case that 'to' connection has already closed when attempting to write to it. You can see + # in the example, that proxy_target_unbound will be called when this occurs. After that, further incoming + # data will be passed into receive_data as normal. + # + # Note also that this feature supports different types of descriptors: TCP, UDP, and pipes. You can relay + # data from one kind to another, for example, feed a pipe from a UDP stream. + # + # @example + # + # module ProxyConnection + # def initialize(client, request) + # @client, @request = client, request + # end + # + # def post_init + # EM::enable_proxy(self, @client) + # end + # + # def connection_completed + # send_data @request + # end + # + # def proxy_target_unbound + # close_connection + # end + # + # def unbind + # @client.close_connection_after_writing + # end + # end + # + # module ProxyServer + # def receive_data(data) + # (@buf ||= "") << data + # if @buf =~ /\r\n\r\n/ # all http headers received + # EventMachine.connect("10.0.0.15", 80, ProxyConnection, self, data) + # end + # end + # end + # + # EventMachine.run { + # EventMachine.start_server("127.0.0.1", 8080, ProxyServer) + # } + # + # @param [EventMachine::Connection] from Source of data to be proxies/streamed. + # @param [EventMachine::Connection] to Destination of data to be proxies/streamed. + # @param [Integer] bufsize Buffer size to use + # @param [Integer] length Maximum number of bytes to proxy. + # + # @see EventMachine.disable_proxy + def self.enable_proxy(from, to, bufsize=0, length=0) + EM::start_proxy(from.signature, to.signature, bufsize, length) + end + + # Takes just one argument, a {Connection} that has proxying enabled via {EventMachine.enable_proxy}. + # Calling this method will remove that functionality and your connection will begin receiving + # data via {Connection#receive_data} again. + # + # @param [EventMachine::Connection] from Source of data that is being proxied + # @see EventMachine.enable_proxy + def self.disable_proxy(from) + EM::stop_proxy(from.signature) + end + + # Retrieve the heartbeat interval. This is how often EventMachine will check for dead connections + # that have had an inactivity timeout set via {Connection#set_comm_inactivity_timeout}. + # Default is 2 seconds. + # + # @return [Integer] Heartbeat interval, in seconds + def self.heartbeat_interval + EM::get_heartbeat_interval + end + + # Set the heartbeat interval. This is how often EventMachine will check for dead connections + # that have had an inactivity timeout set via {Connection#set_comm_inactivity_timeout}. + # Takes a Numeric number of seconds. Default is 2. + # + # @param [Integer] time Heartbeat interval, in seconds + def self.heartbeat_interval=(time) + EM::set_heartbeat_interval time.to_f + end + + # @private + def self.event_callback conn_binding, opcode, data + # + # Changed 27Dec07: Eliminated the hookable error handling. + # No one was using it, and it degraded performance significantly. + # It's in original_event_callback, which is dead code. + # + # Changed 25Jul08: Added a partial solution to the problem of exceptions + # raised in user-written event-handlers. If such exceptions are not caught, + # we must cause the reactor to stop, and then re-raise the exception. + # Otherwise, the reactor doesn't stop and it's left on the call stack. + # This is partial because we only added it to #unbind, where it's critical + # (to keep unbind handlers from being re-entered when a stopping reactor + # runs down open connections). It should go on the other calls to user + # code, but the performance impact may be too large. + # + if opcode == ConnectionUnbound + if c = @conns.delete( conn_binding ) + begin + if c.original_method(:unbind).arity != 0 + c.unbind(data == 0 ? nil : EventMachine::ERRNOS[data]) + else + c.unbind + end + # If this is an attached (but not watched) connection, close the underlying io object. + if c.instance_variable_defined?(:@io) and !c.instance_variable_get(:@watch_mode) + io = c.instance_variable_get(:@io) + begin + io.close + rescue Errno::EBADF, IOError + end + end + # As noted above, unbind absolutely must not raise an exception or the reactor will crash. + # If there is no EM.error_handler, or if the error_handler retrows, then stop the reactor, + # stash the exception in $wrapped_exception, and the exception will be raised after the + # reactor is cleaned up (see the last line of self.run). + rescue Exception => error + if instance_variable_defined? :@error_handler + begin + @error_handler.call error + # No need to stop unless error_handler rethrows + rescue Exception => error + @wrapped_exception = error + stop + end + else + @wrapped_exception = error + stop + end + end + elsif c = @acceptors.delete( conn_binding ) + # no-op + else + if $! # Bubble user generated errors. + @wrapped_exception = $! + stop + else + raise ConnectionNotBound, "received ConnectionUnbound for an unknown signature: #{conn_binding}" + end + end + elsif opcode == ConnectionAccepted + accep,args,blk = @acceptors[conn_binding] + raise NoHandlerForAcceptedConnection unless accep + c = accep.new data, *args + @conns[data] = c + blk and blk.call(c) + c # (needed?) + ## + # The remaining code is a fallback for the pure ruby and java reactors. + # In the C++ reactor, these events are handled in the C event_callback() in rubymain.cpp + elsif opcode == ConnectionCompleted + c = @conns[conn_binding] or raise ConnectionNotBound, "received ConnectionCompleted for unknown signature: #{conn_binding}" + c.connection_completed + elsif opcode == SslHandshakeCompleted + c = @conns[conn_binding] or raise ConnectionNotBound, "received SslHandshakeCompleted for unknown signature: #{conn_binding}" + c.ssl_handshake_completed + elsif opcode == SslVerify + c = @conns[conn_binding] or raise ConnectionNotBound, "received SslVerify for unknown signature: #{conn_binding}" + c.close_connection if c.ssl_verify_peer(data) == false + elsif opcode == TimerFired + t = @timers.delete( data ) + return if t == false # timer cancelled + t or raise UnknownTimerFired, "timer data: #{data}" + t.call + elsif opcode == ConnectionData + c = @conns[conn_binding] or raise ConnectionNotBound, "received data #{data} for unknown signature: #{conn_binding}" + c.receive_data data + elsif opcode == LoopbreakSignalled + run_deferred_callbacks + elsif opcode == ConnectionNotifyReadable + c = @conns[conn_binding] or raise ConnectionNotBound + c.notify_readable + elsif opcode == ConnectionNotifyWritable + c = @conns[conn_binding] or raise ConnectionNotBound + c.notify_writable + end + end + + # + # + # @private + def self._open_file_for_writing filename, handler=nil + klass = klass_from_handler(Connection, handler) + + s = _write_file filename + c = klass.new s + @conns[s] = c + block_given? and yield c + c + end + + # @private + def self.klass_from_handler(klass = Connection, handler = nil, *args) + klass = if handler and handler.is_a?(Class) + raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler + handler + elsif handler + if defined?(handler::EM_CONNECTION_CLASS) + handler::EM_CONNECTION_CLASS + else + handler::const_set(:EM_CONNECTION_CLASS, Class.new(klass) {include handler}) + end + else + klass + end + + arity = klass.instance_method(:initialize).arity + expected = arity >= 0 ? arity : -(arity + 1) + if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected) + raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})" + end + + klass + end +end # module EventMachine + +# Alias for {EventMachine} +EM = EventMachine +# Alias for {EventMachine::Protocols} +EM::P = EventMachine::Protocols diff --git a/bin/gems/eventmachine-1.2.7/lib/fastfilereaderext.so b/bin/gems/eventmachine-1.2.7/lib/fastfilereaderext.so new file mode 100755 index 00000000..cd6e6f8e Binary files /dev/null and b/bin/gems/eventmachine-1.2.7/lib/fastfilereaderext.so differ diff --git a/bin/gems/eventmachine-1.2.7/lib/jeventmachine.rb b/bin/gems/eventmachine-1.2.7/lib/jeventmachine.rb new file mode 100644 index 00000000..21a267d7 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/lib/jeventmachine.rb @@ -0,0 +1,316 @@ +#-- +# +# Author:: Francis Cianfrocca (gmail: blackhedd) +# Homepage:: http://rubyeventmachine.com +# Date:: 8 Apr 2006 +# +# See EventMachine and EventMachine::Connection for documentation and +# usage examples. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. +# Gmail: blackhedd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: 1) the GNU General Public License +# as published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version; or 2) Ruby's License. +# +# See the file COPYING for complete licensing information. +# +#--------------------------------------------------------------------------- +# +# + +# This module provides "glue" for the Java version of the EventMachine reactor core. +# For C++ EventMachines, the analogous functionality is found in ext/rubymain.cpp, +# which is a garden-variety Ruby-extension glue module. + +require 'java' +require 'rubyeventmachine' +require 'socket' + +java_import java.io.FileDescriptor +java_import java.nio.channels.SocketChannel +java_import java.lang.reflect.Field + +module JavaFields + def set_field(key, value) + field = getClass.getDeclaredField(key) + field.setAccessible(true) + if field.getType.toString == 'int' + field.setInt(self, value) + else + field.set(self, value) + end + end + + def get_field(key) + field = getClass.getDeclaredField(key) + field.setAccessible(true) + field.get(self) + end +end + +FileDescriptor.send :include, JavaFields +SocketChannel.send :include, JavaFields + +module EventMachine + # TODO: These event numbers are defined in way too many places. + # DRY them up. + # @private + TimerFired = 100 + # @private + ConnectionData = 101 + # @private + ConnectionUnbound = 102 + # @private + ConnectionAccepted = 103 + # @private + ConnectionCompleted = 104 + # @private + LoopbreakSignalled = 105 + # @private + ConnectionNotifyReadable = 106 + # @private + ConnectionNotifyWritable = 107 + # @private + SslHandshakeCompleted = 108 + # @private + SslVerify = 109 + + # @private + EM_PROTO_SSLv2 = 2 + # @private + EM_PROTO_SSLv3 = 4 + # @private + EM_PROTO_TLSv1 = 8 + # @private + EM_PROTO_TLSv1_1 = 16 + # @private + EM_PROTO_TLSv1_2 = 32 + + # Exceptions that are defined in rubymain.cpp + class ConnectionError < RuntimeError; end + class ConnectionNotBound < RuntimeError; end + class UnknownTimerFired < RuntimeError; end + class Unsupported < RuntimeError; end + + # This thunk class used to be called EM, but that caused conflicts with + # the alias "EM" for module EventMachine. (FC, 20Jun08) + class JEM < com.rubyeventmachine.EmReactor + def eventCallback a1, a2, a3, a4 + s = String.from_java_bytes(a3.array[a3.position...a3.limit]) if a3 + EventMachine::event_callback a1, a2, s || a4 + nil + end + end + # class Connection < com.rubyeventmachine.Connection + # def associate_callback_target sig + # # No-op for the time being. + # end + # end + def self.initialize_event_machine + @em = JEM.new + end + def self.release_machine + @em = nil + end + def self.add_oneshot_timer interval + @em.installOneshotTimer interval + end + def self.run_machine + @em.run + end + def self.stop + @em.stop + end + def self.start_tcp_server server, port + @em.startTcpServer server, port + end + def self.stop_tcp_server sig + @em.stopTcpServer sig + end + def self.start_unix_server filename + # TEMPORARILY unsupported until someone figures out how to do it. + raise "unsupported on this platform" + end + def self.send_data sig, data, length + @em.sendData sig, data.to_java_bytes + rescue java.lang.NullPointerException + 0 + end + def self.send_datagram sig, data, length, address, port + @em.sendDatagram sig, data.to_java_bytes, length, address, port + end + def self.connect_server server, port + bind_connect_server nil, nil, server, port + end + def self.bind_connect_server bind_addr, bind_port, server, port + @em.connectTcpServer bind_addr, bind_port.to_i, server, port + end + def self.close_connection sig, after_writing + @em.closeConnection sig, after_writing + end + def self.set_comm_inactivity_timeout sig, interval + @em.setCommInactivityTimeout sig, interval + end + def self.set_pending_connect_timeout sig, val + end + def self.set_heartbeat_interval val + end + def self.start_tls sig + @em.startTls sig + end + def self.ssl? + false + end + def self.signal_loopbreak + @em.signalLoopbreak + end + def self.set_timer_quantum q + @em.setTimerQuantum q + end + def self.epoll + # Epoll is a no-op for Java. + # The latest Java versions run epoll when possible in NIO. + end + def self.epoll= val + end + def self.kqueue + end + def self.kqueue= val + end + def self.epoll? + false + end + def self.kqueue? + false + end + def self.set_rlimit_nofile n_descriptors + # Currently a no-op for Java. + end + def self.open_udp_socket server, port + @em.openUdpSocket server, port + end + def self.invoke_popen cmd + # TEMPORARILY unsupported until someone figures out how to do it. + raise "unsupported on this platform" + end + def self.read_keyboard + # TEMPORARILY unsupported until someone figures out how to do it. + raise "temporarily unsupported on this platform" + end + def self.set_max_timer_count num + # harmless no-op in Java. There's no built-in timer limit. + @max_timer_count = num + end + def self.get_max_timer_count + # harmless no-op in Java. There's no built-in timer limit. + @max_timer_count || 100_000 + end + def self.library_type + :java + end + def self.get_peername sig + if peer = @em.getPeerName(sig) + Socket.pack_sockaddr_in(*peer) + end + end + def self.get_sockname sig + if sockName = @em.getSockName(sig) + Socket.pack_sockaddr_in(*sockName) + end + end + # @private + def self.attach_fd fileno, watch_mode + # 3Aug09: We could pass in the actual SocketChannel, but then it would be modified (set as non-blocking), and + # we would need some logic to make sure detach_fd below didn't clobber it. For now, we just always make a new + # SocketChannel for the underlying file descriptor + # if fileno.java_kind_of? SocketChannel + # ch = fileno + # ch.configureBlocking(false) + # fileno = nil + # elsif fileno.java_kind_of? java.nio.channels.Channel + + if fileno.java_kind_of? java.nio.channels.Channel + field = fileno.getClass.getDeclaredField('fdVal') + field.setAccessible(true) + fileno = field.get(fileno) + else + raise ArgumentError, 'attach_fd requires Java Channel or POSIX fileno' unless fileno.is_a? Integer + end + + if fileno == 0 + raise "can't open STDIN as selectable in Java =(" + elsif fileno.is_a? Integer + # 8Aug09: The following code is specific to the sun jvm's SocketChannelImpl. Is there a cross-platform + # way of implementing this? If so, also remember to update EventableSocketChannel#close and #cleanup + fd = FileDescriptor.new + fd.set_field 'fd', fileno + + ch = SocketChannel.open + ch.configureBlocking(false) + ch.kill + ch.set_field 'fd', fd + ch.set_field 'fdVal', fileno + ch.set_field 'state', ch.get_field('ST_CONNECTED') + end + + @em.attachChannel(ch,watch_mode) + end + def self.detach_fd sig + if ch = @em.detachChannel(sig) + ch.get_field 'fdVal' + end + end + + def self.set_notify_readable sig, mode + @em.setNotifyReadable(sig, mode) + end + def self.set_notify_writable sig, mode + @em.setNotifyWritable(sig, mode) + end + + def self.is_notify_readable sig + @em.isNotifyReadable(sig) + end + def self.is_notify_writable sig + @em.isNotifyWritable(sig) + end + def self.get_connection_count + @em.getConnectionCount + end + + def self.pause_connection(sig) + @em.pauseConnection(sig) + end + def self.resume_connection(sig) + @em.resumeConnection(sig) + end + def self.connection_paused?(sig) + @em.isConnectionPaused(sig) + end + def self._get_outbound_data_size(sig) + @em.getOutboundDataSize(sig) + end + + + def self.set_tls_parms(sig, params) + end + def self.start_tls(sig) + end + def self.send_file_data(sig, filename) + end + + class Connection + def associate_callback_target sig + # No-op for the time being + end + def get_outbound_data_size + EM._get_outbound_data_size @signature + end + end +end + diff --git a/bin/gems/eventmachine-1.2.7/lib/rubyeventmachine.so b/bin/gems/eventmachine-1.2.7/lib/rubyeventmachine.so new file mode 100755 index 00000000..62a89c50 Binary files /dev/null and b/bin/gems/eventmachine-1.2.7/lib/rubyeventmachine.so differ diff --git a/bin/gems/eventmachine-1.2.7/rakelib/package.rake b/bin/gems/eventmachine-1.2.7/rakelib/package.rake new file mode 100644 index 00000000..00419d0b --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/rakelib/package.rake @@ -0,0 +1,120 @@ +require 'rubygems' +require 'rubygems/package_task' + +begin + require 'rake/extensiontask' + require 'rake/javaextensiontask' +rescue LoadError => e + puts <<-MSG +rake-compiler gem seems to be missing. Please install it with + + gem install rake-compiler + +(add sudo if necessary). + MSG +end + +Gem::PackageTask.new(GEMSPEC) do |pkg| +end + +if RUBY_PLATFORM =~ /java/ + Rake::JavaExtensionTask.new("rubyeventmachine", GEMSPEC) do |ext| + ext.ext_dir = 'java/src' + end +else + def setup_cross_compilation(ext) + unless RUBY_PLATFORM =~ /mswin|mingw/ + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] + end + end + def hack_cross_compilation(ext) + # inject 1.8/1.9 pure-ruby entry point + # HACK: add these dependencies to the task instead of using cross_compiling + if ext.cross_platform.is_a?(Array) + ext.cross_platform.each do |platform| + task = "native:#{GEMSPEC.name}:#{platform}" + if Rake::Task.task_defined?(task) + Rake::Task[task].prerequisites.unshift "lib/#{ext.name}.rb" + end + end + end + end + + em = Rake::ExtensionTask.new("rubyeventmachine", GEMSPEC) do |ext| + ext.ext_dir = 'ext' + ext.source_pattern = '*.{h,c,cpp}' + setup_cross_compilation(ext) + end + hack_cross_compilation em + + ff = Rake::ExtensionTask.new("fastfilereaderext", GEMSPEC) do |ext| + ext.ext_dir = 'ext/fastfilereader' + ext.source_pattern = '*.{h,c,cpp}' + setup_cross_compilation(ext) + end + hack_cross_compilation ff +end + +# Setup shim files that require 1.8 vs 1.9 extensions in win32 bin gems +%w[ rubyeventmachine fastfilereaderext ].each do |filename| + file("lib/#{filename}.rb") do |t| + File.open(t.name, 'wb') do |f| + f.write <<-eoruby + RUBY_VERSION =~ /(\\d+.\\d+)/ + require "\#{$1}/#{File.basename(t.name, '.rb')}" + eoruby + end + at_exit{ FileUtils.rm t.name if File.exist?(t.name) } + end +end + +task :cross_cxx do + ENV['CROSS_COMPILING'] = 'yes' + require 'rake/extensioncompiler' + ENV['CXX'] = "#{Rake::ExtensionCompiler.mingw_host}-g++" +end + +if Rake::Task.task_defined?(:cross) + task :cross => 'lib/rubyeventmachine.rb' + task :cross => 'lib/fastfilereaderext.rb' + task :cross => :cross_cxx +end + +def windows?; RUBY_PLATFORM =~ /mswin|mingw/; end +def sudo(cmd) + if windows? || (require 'etc'; Etc.getpwuid.uid == 0) + sh cmd + else + sh "sudo #{cmd}" + end +end +def gem_cmd(action, name, *args) + rb = Gem.ruby rescue nil + rb ||= (require 'rbconfig'; File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])) + sudo "#{rb} -r rubygems -e 'require %{rubygems/gem_runner}; Gem::GemRunner.new.run(%w{#{action} #{name} #{args.join(' ')}})'" +end + +Rake::Task[:clean].enhance [:clobber_package] + +# DevKit task following the example of Luis Lavena's test-ruby-c-extension +task :devkit do + begin + require "devkit" + rescue LoadError => e + abort "Failed to activate RubyInstaller's DevKit required for compilation." + end +end + +if RUBY_PLATFORM =~ /mingw|mswin/ + Rake::Task['compile'].prerequisites.unshift 'devkit' +end + +desc "Build binary gems for Windows with rake-compiler-dock" +task 'gem:windows' do + require 'rake_compiler_dock' + RakeCompilerDock.sh <<-EOT + RUBY_CC_VERSION="${RUBY_CC_VERSION//1.8.7/}" + bundle && rake cross native gem + EOT +end diff --git a/bin/gems/eventmachine-1.2.7/rakelib/test.rake b/bin/gems/eventmachine-1.2.7/rakelib/test.rake new file mode 100644 index 00000000..1185ac70 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/rakelib/test.rake @@ -0,0 +1,8 @@ +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << "tests" + t.libs << "lib" + t.pattern = 'tests/**/test_*.rb' + t.warning = true +end diff --git a/bin/gems/eventmachine-1.2.7/rakelib/test_pure.rake b/bin/gems/eventmachine-1.2.7/rakelib/test_pure.rake new file mode 100644 index 00000000..5a84ded2 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/rakelib/test_pure.rake @@ -0,0 +1,13 @@ +require 'rake/testtask' + +Rake::TestTask.new(:test_pure) do |t| + t.libs << 'tests' + t.libs << 'lib' + t.test_files = Dir.glob('tests/**/test_pure*.rb') + Dir.glob('tests/**/test_ssl*.rb') + t.warning = true +end + +task :test_em_pure_ruby do + ENV['EM_PURE_RUBY'] = 'true' + Rake::Task['test_pure'].execute +end diff --git a/bin/gems/eventmachine-1.2.7/tests/client.crt b/bin/gems/eventmachine-1.2.7/tests/client.crt new file mode 100644 index 00000000..1919d976 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/client.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFRDCCAywCAQEwDQYJKoZIhvcNAQEFBQAwaDELMAkGA1UEBhMCRU0xFTATBgNV +BAgTDEV2ZW50TWFjaGluZTEVMBMGA1UEChMMRXZlbnRNYWNoaW5lMRQwEgYDVQQL +EwtEZXZlbG9wbWVudDEVMBMGA1UEAxMMRXZlbnRNYWNoaW5lMB4XDTA5MDMyOTAy +MzE0NloXDTEwMDMyOTAyMzE0NlowaDELMAkGA1UEBhMCRU0xFTATBgNVBAgTDEV2 +ZW50TWFjaGluZTEVMBMGA1UEChMMRXZlbnRNYWNoaW5lMRQwEgYDVQQLEwtEZXZl +bG9wbWVudDEVMBMGA1UEAxMMRXZlbnRNYWNoaW5lMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAv1FSOIX1z7CQtVBFlrB0A3/V29T+22STKKmiRWYkKL5b ++hkrp9IZ5J4phZHgUVM2VDPOO2Oc2PU6dlGGZISg+UPERunTogxQKezCV0vcE9cK +OwzxCFDRvv5rK8aKMscfBLbNKocAXywuRRQmdxPiVRzbyPrl+qCr/EDLXAX3D77l +S8n2AwDg19VyI+IgFUE+Dy5e1eLoY6nV+Mq+vNXdn3ttF3t+ngac5pj5Q9h+pD5p +67baDHSnf/7cy2fa/LKrLolVHQR9G2K6cEfeM99NtcsMbkoPs4iI3FA05OVTQHXg +C8C8cRxrb9APl95I/ep65OIaCJgcdYxJ3QD3qOtQo6/NQsGnjbyiUxaEpjfqyT1N +uzWD81Q8uXGNS8yD6dDynt/lseBjyp2nfC3uQ5fY18VdIcu0MJ9pezBUKrNuhlsy +XXEZ2DXj4sY8QOvIcBqSB/zmS1nGEK55xrtkaiaNrY8fe8wRVpcPLxy+P225NFw+ +B69FJRA0Lj6Jt9BM4hV/3MSIEWwTVhuw4E02ywDYTzz1wq3ITf0tsbIPn0hXQMxD +ohhAoKioM6u+yHtqsxD0eYaAWmHTVn5oDvOSGpvCpBfWHyA7FP5UQak0fKABEAgK +iQYEnb294AXwXymJttfGTIV/Ne4tLN5dIpNma8UO8rlThlcr6xnTQDbR3gkTDRsC +AwEAATANBgkqhkiG9w0BAQUFAAOCAgEAj7J8fy1LUWoVWnrXDAC9jwJ1nI/YjoSU +6ywke3o04+nZC5S+dPnuVy+HAwsU940CoNvP6RStI/bH6JL+NIqEFmwM3M8xIEWV +MYVPkfvQUxxGvDnaY7vv93u+6Q77HV3qlhAQBHChyuXyO7TG3+WzsiT9AnBNtAP0 +4jClt5kCAQXLO/p0SFEZQ8Ru9SM8d1i73Z0VDVzs8jYWlBhiherSgbw1xK4wBOpJ +43XmjZsBSrDpiAXd07Ak3UL2GjfT7eStgebL3UIe39ThE/s/+l43bh0M6WbOBvyQ +i/rZ50kd1GvN0xnZhtv07hIJWO85FGWi7Oet8AzdUZJ17v1Md/f2vdhPVTFN9q+w +mQ6LxjackqCvaJaQfBEbqsn2Tklxk4tZuDioiQbOElT2e6vljQVJWIfNx38Ny2LM +aiXQPQu+4CI7meAh5gXM5nyJGbZvRPsxj89CqYzyHCYs5HBP3AsviBvn26ziOF+c +544VmHd9HkIv8UTC29hh+R64RlgMQQQdaXFaUrFPTs/do0k8n/c2bPc0iTdfi5Q2 +gq6Vi8q6Ay5wGgTtRRbn/mWKuCFjEh94z6pF9Xr06NX0PuEOdf+Ls9vI5vz6G0w6 +0Li7devEN7EKBY+7Mcjg918yq9i5tEiMkUgT68788t3fTC+4iUQ5fDtdrHsaOlIR +8bs/XQVNE/s= +-----END CERTIFICATE----- diff --git a/bin/gems/eventmachine-1.2.7/tests/client.key b/bin/gems/eventmachine-1.2.7/tests/client.key new file mode 100644 index 00000000..87a25311 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/client.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAv1FSOIX1z7CQtVBFlrB0A3/V29T+22STKKmiRWYkKL5b+hkr +p9IZ5J4phZHgUVM2VDPOO2Oc2PU6dlGGZISg+UPERunTogxQKezCV0vcE9cKOwzx +CFDRvv5rK8aKMscfBLbNKocAXywuRRQmdxPiVRzbyPrl+qCr/EDLXAX3D77lS8n2 +AwDg19VyI+IgFUE+Dy5e1eLoY6nV+Mq+vNXdn3ttF3t+ngac5pj5Q9h+pD5p67ba +DHSnf/7cy2fa/LKrLolVHQR9G2K6cEfeM99NtcsMbkoPs4iI3FA05OVTQHXgC8C8 +cRxrb9APl95I/ep65OIaCJgcdYxJ3QD3qOtQo6/NQsGnjbyiUxaEpjfqyT1NuzWD +81Q8uXGNS8yD6dDynt/lseBjyp2nfC3uQ5fY18VdIcu0MJ9pezBUKrNuhlsyXXEZ +2DXj4sY8QOvIcBqSB/zmS1nGEK55xrtkaiaNrY8fe8wRVpcPLxy+P225NFw+B69F +JRA0Lj6Jt9BM4hV/3MSIEWwTVhuw4E02ywDYTzz1wq3ITf0tsbIPn0hXQMxDohhA +oKioM6u+yHtqsxD0eYaAWmHTVn5oDvOSGpvCpBfWHyA7FP5UQak0fKABEAgKiQYE +nb294AXwXymJttfGTIV/Ne4tLN5dIpNma8UO8rlThlcr6xnTQDbR3gkTDRsCAwEA +AQKCAgB495RDRQB9x6hX3F+DviI8rDGug+h5FAiwJ0IBG2o1kNdbNVsTC5dvpEmg +uPHaugCaEP+PMZbU34mNklKlb+7QbPbH18UGqz5so9TlmYOXz9oaKD6nAWL9nqRo +02pCXQDR3DuxbhbgFnFTIECJ/jqXkl2toGaVp83W+6kZkHP8srkMyLASihWgosc+ +xRWAGvaAZtNz7br+eT5fxuH/SEKPOl1qAZ23kXrXm1XQfizk8MnMTptkUMYv+hfl +TM98BASUsiTs6g+opy43HFn09naOQcqkWZO/8s6Gbvhi2lVfZqi5Ba6g3lVYJ3gU +kGoako4N9qB7WqJz+LYjVR9C4TbkkJ9OD6ArwGAx5IIzC3XKSxCyY/pUn4YumPhY +fjvY/km54TBtx/isS1TAgjSgDUxbzrfbkh7afOXSOniy9bWJMgNqHF61dqxWxmUg +F5Tch9zH3qFFVkXpYzDU/R8ZV+CRouCvhn0eZYDh8IqIAwjH0VjkxjPyQtrdrMd3 +gDKMVKoY31EOMLZzv8a0prjpr15A+uw30tT336qb3fofks4pZKUJw8ru9jJVir2p ++RML6iUHCmIeceF7/N1meooSMLPJe0xgKeMb9M4Wtd/et2UNVtP8nCDG622rf2a0 +F/EudXuFgc3FB8nXRw9TCkw9xKQff38edG5xPFUEgqObbVl5YQKCAQEA5DDKGOmp +EO5Zuf/kZfG6/AMMYwAuv1HrYTV2w/HnI3tyQ34Xkeqo+I/OqmRk68Ztxw4Kx1So +SRavkotrlWhhDpl2+Yn1BjkHktSoOdf9gJ9z9llkLmbOkBjmupig1NUB7fq/4y2k +MdqJXDy3uVKHJ97gxdIheMTyHiKuMJPnuT5lZtlT210Ig82P7sLQb/sgCfKVFTr0 +Z3haQ5/tBNKjq+igT4nMBWupOTD1q2GeZLIZACnmnUIhvu+3/bm0l+wiCB0DqF0T +Wy9tlL3fqQSCqzevL7/k5Lg6tJTaP/XYePB73TsOtAXgIaoltXgRBsBUeE1eaODx +kMT6E1PPtn7EqQKCAQEA1qImmTWGqhKICrwje40awPufFtZ/qXKVCN/V+zYsrJV1 +EnZpUDM+zfitlQCugnrQVHSpgfekI6mmVkmogO3fkNjUFTq+neg7IHOUHnqotx+3 +NMqIsyFInGstu9mfPd26fzZjUtx5wKF38LDTIJJAEJ83U3UpPBfpwKmiOGDXOa54 +2i4em/bb/hrQR6JySruZYLi0fXnGI5ZOfpkHgC/KOFkKNKAg2oh4B9qo7ACyiSNk +yojb2mmn6g1OLPxi7wGUSrkS1HQq4an6RZ+eUO0HXVWag0QStdQ91M9IrIHgSBBG +0e86Ar6jtD579gqsbz4ySpI/FqEI9obTC+E1/b0aIwKCAQAGz334qGCnZLXA22ZR +tJlEFEM2YTcD9snzqMjWqE2hvXl3kjfZ3wsUABbG9yAb+VwlaMHhmSE8rTSoRwj6 ++JaM/P+UCw4JFYKoWzh6IXwrbpbjb1+SEvdvTY71WsDSGVlpZOZ9PUt9QWyAGD/T +hCcMhZZn0RG2rQoc5CQWxxNPcBFOtIXQMkKizGvTUHUwImqeYWMZsxzASdNH2WoV +jsPbyaGfPhmcv83ZKyDp8IvtrXMZkiaT4vlm3Xi8VeKR9jY9z7/gMob1XcEDg3c9 +cCkGOy87WZrXSLhX02mAJzJCycqom66gqNw7pPxjIiY/8VWUEZsTvkL3cymTkhjM +9ZOhAoIBAGUaNqJe01NTrV+ZJgGyAxM6s8LXQYV5IvjuL2bJKxwUvvP2cT9FFGWD +qYiRrKJr5ayS07IUC+58oIzu33/0DSa27JgfduD9HrT3nKMK1mSEfRFSAjiXChQc +bIubRGapBoub/AdxMazqoovvT1R9b84kobQfcVAMV6DYh0CVZWyXYfgsV2DSVOiK +iufjfoDzg5lLCEI+1XW3/LunrB/W4yPN1X/amf8234ublYyt+2ucD4NUGnP05xLa +N6P7M0MwdEEKkvMe0YBBSFH5kWK/dIOjqkgBDes20fVnuuz/tL1dZW7IiIP4dzaV +ZGEOwBEatCfqYetv6b/u3IUxDfS7Wg8CggEBALoOwkn5LGdQg+bpdZAKJspGnJWL +Kyr9Al2tvgc69rxfpZqS5eDLkYYCzWPpspSt0Axm1O7xOUDQDt42luaLNGJzHZ2Q +Hn0ZNMhyHpe8d8mIQngRjD+nuLI/uFUglPzabDOCOln2aycjg1mA6ecXP1XMEVbu +0RB/0IE36XTMfZ+u9+TRjkBLpmUaX1FdIQQWfwUou/LfaXotoQlhSGAcprLrncuJ +T44UATYEgO/q9pMM33bdE3eBYZHoT9mSvqoLCN4s0LuwOYItIxLKUj0GulL0VQOI +SZi+0A1c8cVDXgApkBrWPDQIR9JS4de0gW4hnDoUvHtUc2TYPRnz6N9MtFY= +-----END RSA PRIVATE KEY----- diff --git a/bin/gems/eventmachine-1.2.7/tests/dhparam.pem b/bin/gems/eventmachine-1.2.7/tests/dhparam.pem new file mode 100644 index 00000000..b6464ab8 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/dhparam.pem @@ -0,0 +1,13 @@ +-----BEGIN DH PARAMETERS----- +MIICCAKCAgEAikiatXa5aAteOtd6hOO33npjCvJByD3dwuM8rWzz0DFZdUH9nFJi +b0VvTVweVECb6XZBsrDNLqGQykCrm43swSk5D9XQCGJLxFERD6yk3b90xaeCm3/a +b0Ek5ZVvV73Cc/YbVmpBiOHoTFpUFJLZ7pLMQUSn8y3qUlNcY9/88HuwFi1s1lRM +ovihSRyZMYAuYWOD4yuOuIcroKVjD6gWFrsW9XrALWny6vUXQrhk8Q3rj+wM6ZtE +5afcB0b6ZJtphrDfk3dFjOVG/zVT37VWgrY8GABrpo2ey0W0WIQJ7rDKLaPaI4kc +voOgC2K8Z3kSARZK+jULnwmBeYECz4EH/FF6FEp3GOKtkL4mqEkvh1n5EAesDOGl +iiX+RZXcUrZliSeifSXBTMJWWFVC0fkGIMb9PTZfZHyAC54lpuxzVki0HIyQG9Fs +41zBJ5e8eEoXXlfUYtduUC35YGy2IxSzYLAJE76rctAZSWghha9xLOCDFoLjMr8h +FosKeHKJcBQ0bc8ymOpRIfrYLWhc0Pz2zkpJ/4eYw9t7NYg7S+jP19IE0gUnuM9v +SpoYMtS28tP9nEdokdwuBKD0D3bJEBBefDlHgfXoMgvy9Hivc9PBGGNTNpyFPpwF +sWVAkfhoNMJMC5V7LZsze+lftiDtzVoLSPDa9bO4BK7b/MgwCxfOhGsCAQI= +-----END DH PARAMETERS----- diff --git a/bin/gems/eventmachine-1.2.7/tests/em_test_helper.rb b/bin/gems/eventmachine-1.2.7/tests/em_test_helper.rb new file mode 100644 index 00000000..20a3e59a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/em_test_helper.rb @@ -0,0 +1,154 @@ +require 'em/pure_ruby' if ENV['EM_PURE_RUBY'] +require 'eventmachine' +require 'test/unit' +require 'rbconfig' +require 'socket' + +puts "EM Library Type: #{EM.library_type}" + +class Test::Unit::TestCase + class EMTestTimeout < StandardError ; end + + def setup_timeout(timeout = TIMEOUT_INTERVAL) + EM.schedule { + EM.add_timer(timeout) { + raise EMTestTimeout, "Test was cancelled after #{timeout} seconds." + } + } + end + + def port_in_use?(port, host="127.0.0.1") + s = TCPSocket.new(host, port) + s.close + s + rescue Errno::ECONNREFUSED + false + end + + def next_port + @@port ||= 9000 + begin + @@port += 1 + end while port_in_use?(@@port) + + @@port + end + + # Returns true if the host have a localhost 127.0.0.1 IPv4. + def self.local_ipv4? + return @@has_local_ipv4 if defined?(@@has_local_ipv4) + begin + get_my_ipv4_address "127.0.0.1" + @@has_local_ipv4 = true + rescue + @@has_local_ipv4 = false + end + end + + # Returns true if the host have a public IPv4 and stores it in + # @@public_ipv4. + def self.public_ipv4? + return @@has_public_ipv4 if defined?(@@has_public_ipv4) + begin + @@public_ipv4 = get_my_ipv4_address "1.2.3.4" + @@has_public_ipv4 = true + rescue + @@has_public_ipv4 = false + end + end + + # Returns true if the host have a localhost ::1 IPv6. + def self.local_ipv6? + return @@has_local_ipv6 if defined?(@@has_local_ipv6) + begin + get_my_ipv6_address "::1" + @@has_local_ipv6 = true + rescue + @@has_local_ipv6 = false + end + end + + # Returns true if the host have a public IPv6 and stores it in + # @@public_ipv6. + def self.public_ipv6? + return @@has_public_ipv6 if defined?(@@has_public_ipv6) + begin + @@public_ipv6 = get_my_ipv6_address "2001::1" + @@has_public_ipv6 = true + rescue + @@has_public_ipv6 = false + end + end + + # Returns an array with the localhost addresses (IPv4 and/or IPv6). + def local_ips + return @@local_ips if defined?(@@local_ips) + @@local_ips = [] + @@local_ips << "127.0.0.1" if self.class.local_ipv4? + @@local_ips << "::1" if self.class.local_ipv6? + @@local_ips + end + + def exception_class + jruby? ? NativeException : RuntimeError + end + + module PlatformHelper + # http://blog.emptyway.com/2009/11/03/proper-way-to-detect-windows-platform-in-ruby/ + def windows? + RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + end + + def solaris? + RUBY_PLATFORM =~ /solaris/ + end + + # http://stackoverflow.com/questions/1342535/how-can-i-tell-if-im-running-from-jruby-vs-ruby/1685970#1685970 + def jruby? + defined? JRUBY_VERSION + end + + def rbx? + defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' + end + end + + include PlatformHelper + extend PlatformHelper + + # Tests run significantly slower on windows. YMMV + TIMEOUT_INTERVAL = windows? ? 1 : 0.25 + + def silent + backup, $VERBOSE = $VERBOSE, nil + begin + yield + ensure + $VERBOSE = backup + end + end + + + private + + def self.get_my_ipv4_address ip + orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily + UDPSocket.open(Socket::AF_INET) do |s| + s.connect ip, 1 + s.addr.last + end + ensure + Socket.do_not_reverse_lookup = orig + end + + def self.get_my_ipv6_address ip + orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily + UDPSocket.open(Socket::AF_INET6) do |s| + s.connect ip, 1 + s.addr.last + end + ensure + Socket.do_not_reverse_lookup = orig + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_attach.rb b/bin/gems/eventmachine-1.2.7/tests/test_attach.rb new file mode 100644 index 00000000..4a55017c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_attach.rb @@ -0,0 +1,151 @@ +require 'em_test_helper' +require 'socket' + +class TestAttach < Test::Unit::TestCase + class EchoServer < EM::Connection + def receive_data data + $received_data << data + send_data data + end + end + + class EchoClient < EM::Connection + def initialize socket + self.notify_readable = true + @socket = socket + @socket.write("abc\n") + end + + def notify_readable + $read = @socket.readline + $fd = detach + end + + def unbind + EM.next_tick do + @socket.write("def\n") + EM.add_timer(0.1) { EM.stop } + end + end + end + + def setup + @port = next_port + $read, $r, $w, $fd = nil + $received_data = "" + end + + def teardown + [$r, $w].each do |io| + io.close rescue nil + end + $received_data = nil + end + + def test_attach + socket = nil + + EM.run { + EM.start_server "127.0.0.1", @port, EchoServer + socket = TCPSocket.new "127.0.0.1", @port + EM.watch socket, EchoClient, socket + } + + assert_equal $read, "abc\n" + unless jruby? # jruby filenos are not real + assert_equal $fd, socket.fileno + end + assert_equal false, socket.closed? + assert_equal socket.readline, "def\n" + end + + module PipeWatch + def notify_readable + $read = $r.readline + EM.stop + end + end + + def test_attach_server + omit_if(jruby?) + $before = TCPServer.new("127.0.0.1", @port) + sig = nil + EM.run { + sig = EM.attach_server $before, EchoServer + + handler = Class.new(EM::Connection) do + def initialize + send_data "hello world" + close_connection_after_writing + EM.add_timer(0.1) { EM.stop } + end + end + EM.connect("127.0.0.1", @port, handler) + } + + assert_equal false, $before.closed? + assert_equal "hello world", $received_data + assert sig.is_a?(Integer) + end + + def test_attach_pipe + EM.run{ + $r, $w = IO.pipe + EM.watch $r, PipeWatch do |c| + c.notify_readable = true + end + $w.write("ghi\n") + } + + assert_equal $read, "ghi\n" + end + + def test_set_readable + before, after = nil + + EM.run{ + $r, $w = IO.pipe + c = EM.watch $r, PipeWatch do |con| + con.notify_readable = false + end + + EM.next_tick{ + before = c.notify_readable? + c.notify_readable = true + after = c.notify_readable? + } + + $w.write("jkl\n") + } + + assert !before + assert after + assert_equal $read, "jkl\n" + end + + def test_read_write_pipe + result = nil + + pipe_reader = Module.new do + define_method :receive_data do |data| + result = data + EM.stop + end + end + + r,w = IO.pipe + + EM.run { + EM.attach r, pipe_reader + writer = EM.attach(w) + writer.send_data 'ghi' + + # XXX: Process will hang in Windows without this line + writer.close_connection_after_writing + } + + assert_equal "ghi", result + ensure + [r,w].each {|io| io.close rescue nil } + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_basic.rb b/bin/gems/eventmachine-1.2.7/tests/test_basic.rb new file mode 100644 index 00000000..4d725240 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_basic.rb @@ -0,0 +1,321 @@ +require 'em_test_helper' +require 'socket' + +class TestBasic < Test::Unit::TestCase + def setup + @port = next_port + end + + def test_connection_class_cache + mod = Module.new + a, b = nil, nil + EM.run { + EM.start_server '127.0.0.1', @port, mod + a = EM.connect '127.0.0.1', @port, mod + b = EM.connect '127.0.0.1', @port, mod + EM.stop + } + assert_equal a.class, b.class + assert_kind_of EM::Connection, a + end + + #------------------------------------- + + + def test_em + assert_nothing_raised do + EM.run { + setup_timeout + EM.add_timer 0 do + EM.stop + end + } + end + end + + #------------------------------------- + + def test_timer + assert_nothing_raised do + EM.run { + setup_timeout + n = 0 + EM.add_periodic_timer(0.1) { + n += 1 + EM.stop if n == 2 + } + } + end + end + + #------------------------------------- + + # This test once threw an already-running exception. + module Trivial + def post_init + EM.stop + end + end + + def test_server + assert_nothing_raised do + EM.run { + setup_timeout + EM.start_server "127.0.0.1", @port, Trivial + EM.connect "127.0.0.1", @port + } + end + end + + #-------------------------------------- + + # EM#run_block starts the reactor loop, runs the supplied block, and then STOPS + # the loop automatically. Contrast with EM#run, which keeps running the reactor + # even after the supplied block completes. + def test_run_block + assert !EM.reactor_running? + a = nil + EM.run_block { a = "Worked" } + assert a + assert !EM.reactor_running? + end + + class UnbindError < EM::Connection + ERR = Class.new(StandardError) + def initialize *args + super + end + def connection_completed + close_connection_after_writing + end + def unbind + raise ERR + end + end + + def test_unbind_error_during_stop + assert_raises( UnbindError::ERR ) { + EM.run { + EM.start_server "127.0.0.1", @port + EM.connect "127.0.0.1", @port, UnbindError do + EM.stop + end + } + } + end + + def test_unbind_error + EM.run { + EM.error_handler do |e| + assert(e.is_a?(UnbindError::ERR)) + EM.stop + end + EM.start_server "127.0.0.1", @port + EM.connect "127.0.0.1", @port, UnbindError + } + + # Remove the error handler before the next test + EM.error_handler(nil) + end + + module BrsTestSrv + def receive_data data + $received << data + end + def unbind + EM.stop + end + end + module BrsTestCli + def post_init + send_data $sent + close_connection_after_writing + end + end + + # From ticket #50 + def test_byte_range_send + $received = '' + $sent = (0..255).to_a.pack('C*') + EM::run { + EM::start_server "127.0.0.1", @port, BrsTestSrv + EM::connect "127.0.0.1", @port, BrsTestCli + + setup_timeout + } + assert_equal($sent, $received) + end + + def test_bind_connect + pend('FIXME: this test is broken on Windows') if windows? + + local_ip = UDPSocket.open {|s| s.connect('localhost', 80); s.addr.last } + + bind_port = next_port + + port, ip = nil + bound_server = Module.new do + define_method :post_init do + begin + port, ip = Socket.unpack_sockaddr_in(get_peername) + ensure + EM.stop + end + end + end + + EM.run do + setup_timeout + EM.start_server "127.0.0.1", @port, bound_server + EM.bind_connect local_ip, bind_port, "127.0.0.1", @port + end + + assert_equal bind_port, port + assert_equal local_ip, ip + end + + def test_invalid_address_bind_connect_dst + e = nil + EM.run do + begin + EM.bind_connect('localhost', nil, 'invalid.invalid', 80) + rescue Exception => e + # capture the exception + ensure + EM.stop + end + end + + assert_kind_of(EventMachine::ConnectionError, e) + assert_match(/unable to resolve address:.*not known/, e.message) + end + + def test_invalid_address_bind_connect_src + e = nil + EM.run do + begin + EM.bind_connect('invalid.invalid', nil, 'localhost', 80) + rescue Exception => e + # capture the exception + ensure + EM.stop + end + end + + assert_kind_of(EventMachine::ConnectionError, e) + assert_match(/invalid bind address:.*not known/, e.message) + end + + def test_reactor_thread? + assert !EM.reactor_thread? + EM.run { assert EM.reactor_thread?; EM.stop } + assert !EM.reactor_thread? + end + + def test_schedule_on_reactor_thread + x = false + EM.run do + EM.schedule { x = true } + EM.stop + end + assert x + end + + def test_schedule_from_thread + x = false + EM.run do + Thread.new { EM.schedule { x = true; EM.stop } }.join + end + assert x + end + + def test_set_heartbeat_interval + omit_if(jruby?) + interval = 0.5 + EM.run { + EM.set_heartbeat_interval interval + $interval = EM.get_heartbeat_interval + EM.stop + } + assert_equal(interval, $interval) + end + + module PostInitRaiser + ERR = Class.new(StandardError) + def post_init + raise ERR + end + end + + def test_bubble_errors_from_post_init + assert_raises(PostInitRaiser::ERR) do + EM.run do + EM.start_server "127.0.0.1", @port + EM.connect "127.0.0.1", @port, PostInitRaiser + end + end + end + + module InitializeRaiser + ERR = Class.new(StandardError) + def initialize + raise ERR + end + end + + def test_bubble_errors_from_initialize + assert_raises(InitializeRaiser::ERR) do + EM.run do + EM.start_server "127.0.0.1", @port + EM.connect "127.0.0.1", @port, InitializeRaiser + end + end + end + + def test_schedule_close + omit_if(jruby?) + localhost, port = '127.0.0.1', 9000 + timer_ran = false + num_close_scheduled = nil + EM.run do + assert_equal 0, EM.num_close_scheduled + EM.add_timer(1) { timer_ran = true; EM.stop } + EM.start_server localhost, port do |s| + s.close_connection + num_close_scheduled = EM.num_close_scheduled + end + EM.connect localhost, port do |c| + def c.unbind + EM.stop + end + end + end + assert !timer_ran + assert_equal 1, num_close_scheduled + end + + def test_error_handler_idempotent # issue 185 + errors = [] + ticks = [] + EM.error_handler do |e| + errors << e + end + + EM.run do + EM.next_tick do + ticks << :first + raise + end + EM.next_tick do + ticks << :second + end + EM.add_timer(0.001) { EM.stop } + end + + # Remove the error handler before the next test + EM.error_handler(nil) + + assert_equal 1, errors.size + assert_equal [:first, :second], ticks + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_channel.rb b/bin/gems/eventmachine-1.2.7/tests/test_channel.rb new file mode 100644 index 00000000..c54bf1da --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_channel.rb @@ -0,0 +1,75 @@ +require 'em_test_helper' + +class TestEMChannel < Test::Unit::TestCase + def test_channel_subscribe + s = 0 + EM.run do + c = EM::Channel.new + c.subscribe { |v| s = v; EM.stop } + c << 1 + end + assert_equal 1, s + end + + def test_channel_unsubscribe + s = 0 + EM.run do + c = EM::Channel.new + subscription = c.subscribe { |v| s = v } + c.unsubscribe(subscription) + c << 1 + EM.next_tick { EM.stop } + end + assert_not_equal 1, s + end + + def test_channel_pop + s = 0 + EM.run do + c = EM::Channel.new + c.pop{ |v| s = v } + c.push(1,2,3) + c << 4 + c << 5 + EM.next_tick { EM.stop } + end + assert_equal 1, s + end + + def test_channel_reactor_thread_push + out = [] + c = EM::Channel.new + c.subscribe { |v| out << v } + Thread.new { c.push(1,2,3) }.join + assert out.empty? + + EM.run { EM.next_tick { EM.stop } } + + assert_equal [1,2,3], out + end + + def test_channel_reactor_thread_callback + out = [] + c = EM::Channel.new + Thread.new { c.subscribe { |v| out << v } }.join + c.push(1,2,3) + assert out.empty? + + EM.run { EM.next_tick { EM.stop } } + + assert_equal [1,2,3], out + end + + def test_channel_num_subscribers + subs = 0 + EM.run do + c = EM::Channel.new + c.subscribe { |v| s = v } + c.subscribe { |v| s = v } + EM.next_tick { EM.stop } + subs = c.num_subscribers + end + + assert_equal subs, 2 + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_completion.rb b/bin/gems/eventmachine-1.2.7/tests/test_completion.rb new file mode 100644 index 00000000..1bd9a8f4 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_completion.rb @@ -0,0 +1,178 @@ +require 'em_test_helper' +require 'em/completion' + +class TestCompletion < Test::Unit::TestCase + def completion + @completion ||= EM::Completion.new + end + + def crank + # This is a slow solution, but this just executes the next tick queue + # once. It's the easiest way for now. + EM.run { EM.stop } + end + + def results + @results ||= [] + end + + def test_state + assert_equal :unknown, completion.state + end + + def test_succeed + completion.callback { |val| results << val } + completion.succeed :object + crank + assert_equal :succeeded, completion.state + assert_equal [:object], results + end + + def test_fail + completion.errback { |val| results << val } + completion.fail :object + crank + assert_equal :failed, completion.state + assert_equal [:object], results + end + + def test_callback + completion.callback { results << :callback } + completion.errback { results << :errback } + completion.succeed + crank + assert_equal [:callback], results + end + + def test_errback + completion.callback { results << :callback } + completion.errback { results << :errback } + completion.fail + crank + assert_equal [:errback], results + end + + def test_stateback + completion.stateback(:magic) { results << :stateback } + completion.change_state(:magic) + crank + assert_equal [:stateback], results + end + + def test_does_not_enqueue_when_completed + completion.callback { results << :callback } + completion.succeed + completion.errback { results << :errback } + completion.fail + crank + assert_equal [:callback], results + end + + def test_completed + assert_equal false, completion.completed? + completion.succeed + assert_equal true, completion.completed? + completion.fail + assert_equal true, completion.completed? + completion.change_state :magic + assert_equal false, completion.completed? + end + + def test_recursive_callbacks + completion.callback do |val| + results << val + completion.succeed :two + end + completion.callback do |val| + results << val + completion.succeed :three + end + completion.callback do |val| + results << val + end + completion.succeed :one + crank + assert_equal [:one, :two, :three], results + end + + def test_late_defined_callbacks + completion.callback { results << :one } + completion.succeed + crank + assert_equal [:one], results + completion.callback { results << :two } + crank + assert_equal [:one, :two], results + end + + def test_cleared_completions + completion.callback { results << :callback } + completion.errback { results << :errback } + + completion.succeed + crank + completion.fail + crank + completion.succeed + crank + + assert_equal [:callback], results + end + + def test_skip_completed_callbacks + completion.callback { results << :callback } + completion.succeed + crank + + completion.errback { results << :errback } + completion.fail + crank + + assert_equal [:callback], results + end + + def test_completions + completion.completion { results << :completion } + completion.succeed + crank + assert_equal [:completion], results + + completion.change_state(:unknown) + results.clear + + completion.completion { results << :completion } + completion.fail + crank + assert_equal [:completion], results + end + + def test_latent_completion + completion.completion { results << :completion } + completion.succeed + crank + completion.completion { results << :completion } + crank + assert_equal [:completion, :completion], results + end + + def test_timeout + args = [1, 2, 3] + EM.run do + completion.timeout(0.0001, *args) + completion.errback { |*errargs| results << errargs } + completion.completion { EM.stop } + EM.add_timer(0.1) { flunk 'test timed out' } + end + assert_equal [[1,2,3]], results + end + + def test_timeout_gets_cancelled + EM.run do + completion.timeout(0.0001, :timeout) + completion.errback { results << :errback } + completion.succeed + EM.add_timer(0.0002) { EM.stop } + end + assert_equal [], results + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_connection_count.rb b/bin/gems/eventmachine-1.2.7/tests/test_connection_count.rb new file mode 100644 index 00000000..350c4177 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_connection_count.rb @@ -0,0 +1,83 @@ +require 'em_test_helper' + +class TestConnectionCount < Test::Unit::TestCase + def teardown + EM.epoll = false + EM.kqueue = false + end + + def test_idle_connection_count + count = nil + EM.run { + count = EM.connection_count + EM.stop_event_loop + } + assert_equal(0, count) + end + + # Run this again with epoll enabled (if available) + def test_idle_connection_count_epoll + EM.epoll if EM.epoll? + + count = nil + EM.run { + count = EM.connection_count + EM.stop_event_loop + } + assert_equal(0, count) + end + + # Run this again with kqueue enabled (if available) + def test_idle_connection_count_kqueue + EM.kqueue if EM.kqueue? + + count = nil + EM.run { + count = EM.connection_count + EM.stop_event_loop + } + assert_equal(0, count) + end + + module Client + def connection_completed + $client_conns += 1 + EM.stop if $client_conns == 3 + end + end + + def test_with_some_connections + EM.run { + $client_conns = 0 + $initial_conns = EM.connection_count + EM.start_server("127.0.0.1", 9999) + $server_conns = EM.connection_count + 3.times { EM.connect("127.0.0.1", 9999, Client) } + } + + assert_equal(0, $initial_conns) + assert_equal(1, $server_conns) + assert_equal(4, $client_conns + $server_conns) + end + + module DoubleCloseClient + def unbind + close_connection + $num_close_scheduled_1 = EM.num_close_scheduled + EM.next_tick do + $num_close_scheduled_2 = EM.num_close_scheduled + EM.stop + end + end + end + + def test_num_close_scheduled + omit_if(jruby?) + EM.run { + assert_equal(0, EM.num_close_scheduled) + EM.connect("127.0.0.1", 9999, DoubleCloseClient) # nothing listening on 9999 + } + assert_equal(1, $num_close_scheduled_1) + assert_equal(0, $num_close_scheduled_2) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_connection_write.rb b/bin/gems/eventmachine-1.2.7/tests/test_connection_write.rb new file mode 100644 index 00000000..35533b52 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_connection_write.rb @@ -0,0 +1,35 @@ +require 'em_test_helper' + +class TestConnectionWrite < Test::Unit::TestCase + + # This test takes advantage of the fact that EM::_RunSelectOnce iterates over the connections twice: + # - once to determine which ones to call Write() on + # - and once to call Write() on each of them. + # + # But state may change in the meantime before Write() is finally called. + # And that is what we try to exploit to get Write() to be called when bWatchOnly is true, and bNotifyWritable is false, + # to cause an assertion failure. + + module SimpleClient + def notify_writable + $conn2.notify_writable = false # Being naughty in callback + # If this doesn't crash anything, the test passed! + end + end + + def test_with_naughty_callback + EM.run do + r1, _ = IO.pipe + r2, _ = IO.pipe + + # Adding EM.watches + $conn1 = EM.watch(r1, SimpleClient) + $conn2 = EM.watch(r2, SimpleClient) + + $conn1.notify_writable = true + $conn2.notify_writable = true + + EM.stop + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_defer.rb b/bin/gems/eventmachine-1.2.7/tests/test_defer.rb new file mode 100644 index 00000000..aeca127d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_defer.rb @@ -0,0 +1,35 @@ +require 'em_test_helper' + +class TestDefer < Test::Unit::TestCase + + def test_defers + n = 0 + n_times = 20 + EM.run { + n_times.times { + work_proc = proc { n += 1 } + callback = proc { EM.stop if n == n_times } + EM.defer work_proc, callback + } + } + assert_equal( n, n_times ) + end + + def test_errbacks + iterations = 20 + callback_parameter = rand(100) + callback_parameters = [] + callback_op = proc { callback_parameter } + callback = proc { |result| callback_parameters << result } + errback_parameter = Exception.new + errback_parameters = [] + errback_op = proc { raise errback_parameter } + errback = proc { |error| errback_parameters << error } + EventMachine.run do + (1..iterations).each { |index| EventMachine.defer(index.even? ? callback_op : errback_op, callback, errback) } + EventMachine.add_periodic_timer(0.1) { EventMachine.stop if EventMachine.defers_finished? } + end + assert_equal(callback_parameters.select { |parameter| parameter == callback_parameter }.length, iterations * 0.5) + assert_equal(errback_parameters.select{ |parameter| parameter == errback_parameter }.length, iterations * 0.5) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_deferrable.rb b/bin/gems/eventmachine-1.2.7/tests/test_deferrable.rb new file mode 100644 index 00000000..5f286a77 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_deferrable.rb @@ -0,0 +1,35 @@ +require 'em_test_helper' + +class TestDeferrable < Test::Unit::TestCase + class Later + include EM::Deferrable + end + + def test_timeout_without_args + assert_nothing_raised do + EM.run { + df = Later.new + df.timeout(0) + df.errback { EM.stop } + EM.add_timer(0.01) { flunk "Deferrable was not timed out." } + } + end + end + + def test_timeout_with_args + args = nil + + EM.run { + df = Later.new + df.timeout(0, :timeout, :foo) + df.errback do |type, name| + args = [type, name] + EM.stop + end + + EM.add_timer(0.01) { flunk "Deferrable was not timed out." } + } + + assert_equal [:timeout, :foo], args + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_epoll.rb b/bin/gems/eventmachine-1.2.7/tests/test_epoll.rb new file mode 100644 index 00000000..36f5609a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_epoll.rb @@ -0,0 +1,142 @@ +require 'em_test_helper' + + +class TestEpoll < Test::Unit::TestCase + + module TestEchoServer + def receive_data data + send_data data + close_connection_after_writing + end + end + + module TestEchoClient + def connection_completed + send_data "ABCDE" + $max += 1 + end + def receive_data data + raise "bad response" unless data == "ABCDE" + end + def unbind + $n -= 1 + EM.stop if $n == 0 + end + end + + + # We can set the rlimit/nofile of a process but we can only set it + # higher if we're running as root. + # On most systems, the default value is 1024. + def test_rlimit + omit_if(windows? || jruby?) + unless EM.set_descriptor_table_size >= 1024 + a = EM.set_descriptor_table_size + assert( a <= 1024 ) + a = EM.set_descriptor_table_size( 1024 ) + assert( a == 1024 ) + end + end + + # Run a high-volume version of this test by kicking the number of connections + # up past 512. (Each connection uses two sockets, a client and a server.) + # (Will require running the test as root) + # This test exercises TCP clients and servers. + # + # XXX this test causes all sort of weird issues on OSX (when run as part of the suite) + def _test_descriptors + EM.epoll + EM.set_descriptor_table_size 60000 + EM.run { + EM.start_server "127.0.0.1", 9800, TestEchoServer + $n = 0 + $max = 0 + 100.times { + EM.connect("127.0.0.1", 9800, TestEchoClient) {$n += 1} + } + } + assert_equal(0, $n) + assert_equal(100, $max) + end + + def setup + @port = next_port + end + + module TestDatagramServer + def receive_data dgm + $in = dgm + send_data "abcdefghij" + end + end + module TestDatagramClient + def initialize port + @port = port + end + + def post_init + send_datagram "1234567890", "127.0.0.1", @port + end + + def receive_data dgm + $out = dgm + EM.stop + end + end + + def test_datagrams + $in = $out = "" + EM.run { + EM.open_datagram_socket "127.0.0.1", @port, TestDatagramServer + EM.open_datagram_socket "127.0.0.1", 0, TestDatagramClient, @port + } + assert_equal( "1234567890", $in ) + assert_equal( "abcdefghij", $out ) + end + + # XXX this test fails randomly... + def _test_unix_domain + fn = "/tmp/xxx.chain" + EM.epoll + EM.set_descriptor_table_size 60000 + EM.run { + # The pure-Ruby version won't let us open the socket if the node already exists. + # Not sure, that actually may be correct and the compiled version is wrong. + # Pure Ruby also oddly won't let us make that many connections. This test used + # to run 100 times. Not sure where that lower connection-limit is coming from in + # pure Ruby. + # Let's not sweat the Unix-ness of the filename, since this test can't possibly + # work on Windows anyway. + # + File.unlink(fn) if File.exist?(fn) + EM.start_unix_domain_server fn, TestEchoServer + $n = 0 + $max = 0 + 50.times { + EM.connect_unix_domain(fn, TestEchoClient) {$n += 1} + } + EM::add_timer(1) { $stderr.puts("test_unix_domain timed out!"); EM::stop } + } + assert_equal(0, $n) + assert_equal(50, $max) + ensure + File.unlink(fn) if File.exist?(fn) + end + + def test_attach_detach + EM.epoll + EM.run { + EM.add_timer(0.01) { EM.stop } + + r, _ = IO.pipe + + # This tests a regression where detach in the same tick as attach crashes EM + EM.watch(r) do |connection| + connection.detach + end + } + + assert true + end +end + diff --git a/bin/gems/eventmachine-1.2.7/tests/test_error_handler.rb b/bin/gems/eventmachine-1.2.7/tests/test_error_handler.rb new file mode 100644 index 00000000..23c23f74 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_error_handler.rb @@ -0,0 +1,38 @@ +require 'em_test_helper' + +class TestErrorHandler < Test::Unit::TestCase + def setup + @exception = Class.new(StandardError) + end + + def test_error_handler + error = nil + + EM.error_handler{ |e| + error = e + EM.error_handler(nil) + EM.stop + } + + assert_nothing_raised do + EM.run{ + EM.add_timer(0){ + raise @exception, 'test' + } + } + end + + assert_equal error.class, @exception + assert_equal error.message, 'test' + end + + def test_without_error_handler + assert_raise @exception do + EM.run{ + EM.add_timer(0){ + raise @exception, 'test' + } + } + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_exc.rb b/bin/gems/eventmachine-1.2.7/tests/test_exc.rb new file mode 100644 index 00000000..d9c860ae --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_exc.rb @@ -0,0 +1,43 @@ +require 'em_test_helper' + +class TestSomeExceptions < Test::Unit::TestCase + class DoomedConnectionError < StandardError + end + class DoomedConnection < EventMachine::Connection + def unbind + raise DoomedConnectionError + end + end + + # Read the commentary in EM#run. + # This test exercises the ensure block in #run that makes sure + # EM#release_machine gets called even if an exception is + # thrown within the user code. Without the ensured call to release_machine, + # the second call to EM#run will fail with a C++ exception + # because the machine wasn't cleaned up properly. + + def test_a + assert_raises(RuntimeError) { + EM.run { + raise "some exception" + } + } + end + + def test_b + assert_raises(RuntimeError) { + EM.run { + raise "some exception" + } + } + end + + def test_exception_on_unbind + assert_raises(DoomedConnectionError) { + EM.run { + EM.connect("localhost", 8888, DoomedConnection) + } + } + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_file_watch.rb b/bin/gems/eventmachine-1.2.7/tests/test_file_watch.rb new file mode 100644 index 00000000..56020717 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_file_watch.rb @@ -0,0 +1,85 @@ +require 'em_test_helper' +require 'tempfile' + +class TestFileWatch < Test::Unit::TestCase + if windows? + def test_watch_file_raises_unsupported_error + assert_raises(EM::Unsupported) do + EM.run do + file = Tempfile.new("fake_file") + EM.watch_file(file.path) + end + end + end + elsif EM.respond_to? :watch_filename + module FileWatcher + def file_modified + $modified = true + end + def file_deleted + $deleted = true + end + def unbind + $unbind = true + EM.stop + end + end + + def setup + EM.kqueue = true if EM.kqueue? + end + + def teardown + EM.kqueue = false if EM.kqueue? + end + + def test_events + omit_if(solaris?) + EM.run{ + file = Tempfile.new('em-watch') + $tmp_path = file.path + + # watch it + watch = EM.watch_file(file.path, FileWatcher) + $path = watch.path + + # modify it + File.open(file.path, 'w'){ |f| f.puts 'hi' } + + # delete it + EM.add_timer(0.01){ file.close; file.delete } + } + + assert_equal($path, $tmp_path) + assert($modified) + assert($deleted) + assert($unbind) + end + + # Refer: https://github.com/eventmachine/eventmachine/issues/512 + def test_invalid_signature + # This works fine with kqueue, only fails with linux inotify. + omit_if(EM.kqueue?) + + EM.run { + file = Tempfile.new('foo') + + w1 = EventMachine.watch_file(file.path) + w2 = EventMachine.watch_file(file.path) + + assert_raise EventMachine::InvalidSignature do + w2.stop_watching + end + + EM.stop + } + end + else + warn "EM.watch_file not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_watch_file_unsupported + assert true + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_fork.rb b/bin/gems/eventmachine-1.2.7/tests/test_fork.rb new file mode 100644 index 00000000..8b15bb58 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_fork.rb @@ -0,0 +1,75 @@ +require 'em_test_helper' + +class TestFork < Test::Unit::TestCase + + def test_fork_safe + omit_if(jruby?) + omit_if(windows?) + + fork_pid = nil + read, write = IO.pipe + EM.run do + fork_pid = fork do + write.puts "forked" + EM.run do + EM.next_tick do + write.puts "EM ran" + EM.stop + end + end + end + EM.stop + end + + sleep 0.1 + begin + Timeout::timeout 1 do + assert_equal "forked\n", read.readline + assert_equal "EM ran\n", read.readline + end + rescue Timeout::Error + Process.kill 'TERM', fork_pid + flunk "Timeout waiting for next_tick in new fork reactor" + end + ensure + read.close rescue nil + write.close rescue nil + end + + def test_fork_reactor + omit_if(jruby?) + omit_if(windows?) + + fork_pid = nil + read, write = IO.pipe + EM.run do + EM.defer do + write.puts Process.pid + EM.defer do + EM.stop + end + end + fork_pid = EM.fork_reactor do + EM.defer do + write.puts Process.pid + EM.stop + end + end + end + + sleep 0.1 + begin + Timeout::timeout 1 do + assert_equal Process.pid.to_s, read.readline.chomp + assert_equal fork_pid.to_s, read.readline.chomp + end + rescue Timeout::Error + Process.kill 'TERM', fork_pid + flunk "Timeout waiting for deferred block in fork_reactor" + end + ensure + read.close rescue nil + write.close rescue nil + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_futures.rb b/bin/gems/eventmachine-1.2.7/tests/test_futures.rb new file mode 100644 index 00000000..b4948567 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_futures.rb @@ -0,0 +1,170 @@ +require 'em_test_helper' + +class TestFutures < Test::Unit::TestCase + + def setup + end + + def teardown + end + + def test_future + assert_equal(100, EM::Deferrable.future(100) ) + + p1 = proc { 100 + 1 } + assert_equal(101, EM::Deferrable.future(p1) ) + end + + class MyFuture + include EM::Deferrable + def initialize *args + super + set_deferred_status :succeeded, 40 + end + end + + class MyErrorFuture + include EM::Deferrable + def initialize *args + super + set_deferred_status :failed, 41 + end + end + + + def test_future_1 + # Call future with one additional argument and it will be treated as a callback. + def my_future + MyFuture.new + end + + value = nil + EM::Deferrable.future my_future, proc {|v| value=v} + assert_equal( 40, value ) + end + + + def test_future_2 + # Call future with two additional arguments and they will be treated as a callback + # and an errback. + value = nil + EM::Deferrable.future MyErrorFuture.new, nil, proc {|v| value=v} + assert_equal( 41, value ) + end + + + def test_future_3 + # Call future with no additional arguments but with a block, and the block will be + # treated as a callback. + value = nil + EM::Deferrable.future MyFuture.new do |v| + value=v + end + assert_equal( 40, value ) + end + + + class RecursiveCallback + include EM::Deferrable + end + + # A Deferrable callback can call #set_deferred_status to change the values + # passed to subsequent callbacks. + # + def test_recursive_callbacks + n = 0 # counter assures that all the tests actually run. + rc = RecursiveCallback.new + rc.callback {|a| + assert_equal(100, a) + n += 1 + rc.set_deferred_status :succeeded, 101, 101 + } + rc.callback {|a,b| + assert_equal(101, a) + assert_equal(101, b) + n += 1 + rc.set_deferred_status :succeeded, 102, 102, 102 + } + rc.callback {|a,b,c| + assert_equal(102, a) + assert_equal(102, b) + assert_equal(102, c) + n += 1 + } + rc.set_deferred_status :succeeded, 100 + assert_equal(3, n) + end + + def test_syntactic_sugar + rc = RecursiveCallback.new + rc.set_deferred_success 100 + rc.set_deferred_failure 200 + end + + # It doesn't raise an error to set deferred status more than once. + # In fact, this is a desired and useful idiom when it happens INSIDE + # a callback or errback. + # However, it's less useful otherwise, and in fact would generally be + # indicative of a programming error. However, we would like to be resistant + # to such errors. So whenever we set deferred status, we also clear BOTH + # stacks of handlers. + # + def test_double_calls + s = 0 + e = 0 + + d = EM::DefaultDeferrable.new + d.callback {s += 1} + d.errback {e += 1} + + d.succeed # We expect the callback to be called, and the errback to be DISCARDED. + d.fail # Presumably an error. We expect the errback NOT to be called. + d.succeed # We expect the callback to have been discarded and NOT to be called again. + + assert_equal(1, s) + assert_equal(0, e) + end + + # Adding a callback to a Deferrable that is already in a success state executes the callback + # immediately. The same applies to a an errback added to an already-failed Deferrable. + # HOWEVER, we expect NOT to be able to add errbacks to succeeded Deferrables, or callbacks + # to failed ones. + # + # We illustrate this with a rather contrived test. The test calls #fail after #succeed, + # which ordinarily would not happen in a real program. + # + # What we're NOT attempting to specify is what happens if a Deferrable is succeeded and then + # failed (or vice-versa). Should we then be able to add callbacks/errbacks of the appropriate + # type for immediate execution? For now at least, the official answer is "don't do that." + # + def test_delayed_callbacks + s1 = 0 + s2 = 0 + e = 0 + + d = EM::DefaultDeferrable.new + d.callback {s1 += 1} + + d.succeed # Triggers and discards the callback. + + d.callback {s2 += 1} # This callback is executed immediately and discarded. + + d.errback {e += 1} # This errback should be DISCARDED and never execute. + d.fail # To prove it, fail and assert e is 0 + + assert_equal( [1,1], [s1,s2] ) + assert_equal( 0, e ) + end + + def test_timeout + n = 0 + EM.run { + d = EM::DefaultDeferrable.new + d.callback {n = 1; EM.stop} + d.errback {n = 2; EM.stop} + d.timeout(0.01) + } + assert_equal( 2, n ) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_handler_check.rb b/bin/gems/eventmachine-1.2.7/tests/test_handler_check.rb new file mode 100644 index 00000000..c4176941 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_handler_check.rb @@ -0,0 +1,35 @@ +require 'em_test_helper' + +class TestHandlerCheck < Test::Unit::TestCase + + class Foo < EM::Connection; end; + module TestModule; end; + + def test_with_correct_class + assert_nothing_raised do + EM.run { + EM.connect("127.0.0.1", 80, Foo) + EM.stop_event_loop + } + end + end + + def test_with_incorrect_class + assert_raise(ArgumentError) do + EM.run { + EM.connect("127.0.0.1", 80, String) + EM.stop_event_loop + } + end + end + + def test_with_module + assert_nothing_raised do + EM.run { + EM.connect("127.0.0.1", 80, TestModule) + EM.stop_event_loop + } + end + end + +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/tests/test_hc.rb b/bin/gems/eventmachine-1.2.7/tests/test_hc.rb new file mode 100644 index 00000000..28e32c9c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_hc.rb @@ -0,0 +1,155 @@ +require 'em_test_helper' + +class TestHeaderAndContentProtocol < Test::Unit::TestCase + + class SimpleTest < EM::P::HeaderAndContentProtocol + attr_reader :first_header, :my_headers, :request + + def receive_first_header_line hdr + @first_header ||= [] + @first_header << hdr + end + def receive_headers hdrs + @my_headers ||= [] + @my_headers << hdrs + end + def receive_request hdrs, content + @request ||= [] + @request << [hdrs, content] + end + end + + class StopOnUnbind < EM::Connection + def unbind + EM.add_timer(0.01) { EM.stop } + end + end + + def setup + @port = next_port + end + + def test_no_content + the_connection = nil + EM.run { + EM.start_server( "127.0.0.1", @port, SimpleTest ) do |conn| + the_connection = conn + end + setup_timeout + + EM.connect "127.0.0.1", @port, StopOnUnbind do |c| + c.send_data [ "aaa\n", "bbb\r\n", "ccc\n", "\n" ].join + c.close_connection_after_writing + end + } + assert_equal( ["aaa"], the_connection.first_header ) + assert_equal( [%w(aaa bbb ccc)], the_connection.my_headers ) + assert_equal( [[%w(aaa bbb ccc), ""]], the_connection.request ) + end + + def test_content + the_connection = nil + content = "A" * 50 + headers = ["aaa", "bbb", "Content-length: #{content.length}", "ccc"] + EM.run { + EM.start_server( "127.0.0.1", @port, SimpleTest ) do |conn| + the_connection = conn + end + setup_timeout + + EM.connect "127.0.0.1", @port, StopOnUnbind do |c| + headers.each { |h| c.send_data "#{h}\r\n" } + c.send_data "\n" + c.send_data content + c.close_connection_after_writing + end + } + assert_equal( ["aaa"], the_connection.first_header ) + assert_equal( [headers], the_connection.my_headers ) + assert_equal( [[headers, content]], the_connection.request ) + end + + def test_several_requests + the_connection = nil + content = "A" * 50 + headers = ["aaa", "bbb", "Content-length: #{content.length}", "ccc"] + EM.run { + EM.start_server( "127.0.0.1", @port, SimpleTest ) do |conn| + the_connection = conn + end + setup_timeout + + EM.connect( "127.0.0.1", @port, StopOnUnbind ) do |c| + 5.times do + headers.each { |h| c.send_data "#{h}\r\n" } + c.send_data "\n" + c.send_data content + end + c.close_connection_after_writing + end + } + assert_equal( ["aaa"] * 5, the_connection.first_header ) + assert_equal( [headers] * 5, the_connection.my_headers ) + assert_equal( [[headers, content]] * 5, the_connection.request ) + end + + + # def x_test_multiple_content_length_headers + # # This is supposed to throw a RuntimeError but it throws a C++ exception instead. + # the_connection = nil + # content = "A" * 50 + # headers = ["aaa", "bbb", ["Content-length: #{content.length}"]*2, "ccc"].flatten + # EM.run { + # EM.start_server( "127.0.0.1", @port, SimpleTest ) do |conn| + # the_connection = conn + # end + # EM.add_timer(4) {raise "test timed out"} + # test_proc = proc { + # t = TCPSocket.new "127.0.0.1", @port + # headers.each {|h| t.write "#{h}\r\n" } + # t.write "\n" + # t.write content + # t.close + # } + # EM.defer test_proc, proc { + # EM.stop + # } + # } + # end + + def test_interpret_headers + the_connection = nil + content = "A" * 50 + headers = [ + "GET / HTTP/1.0", + "Accept: aaa", + "User-Agent: bbb", + "Host: ccc", + "x-tempest-header:ddd" + ] + + EM.run { + EM.start_server( "127.0.0.1", @port, SimpleTest ) do |conn| + the_connection = conn + end + setup_timeout + + EM.connect( "127.0.0.1", @port, StopOnUnbind ) do |c| + headers.each { |h| c.send_data "#{h}\r\n" } + c.send_data "\n" + c.send_data content + c.close_connection_after_writing + end + } + + hsh = the_connection.headers_2_hash( the_connection.my_headers.shift ) + expect = { + :accept => "aaa", + :user_agent => "bbb", + :host => "ccc", + :x_tempest_header => "ddd" + } + assert_equal(expect, hsh) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_httpclient.rb b/bin/gems/eventmachine-1.2.7/tests/test_httpclient.rb new file mode 100644 index 00000000..572a8022 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_httpclient.rb @@ -0,0 +1,238 @@ +require 'em_test_helper' + +class TestHttpClient < Test::Unit::TestCase + + def setup + @port = next_port + end + + #------------------------------------- + + def test_http_client + ok = false + EM.run { + c = silent { EM::P::HttpClient.send :request, :host => "www.google.com", :port => 80 } + c.callback { + ok = true + c.close_connection + EM.stop + } + c.errback {EM.stop} # necessary, otherwise a failure blocks the test suite forever. + } + assert ok + end + + #------------------------------------- + + def test_http_client_1 + ok = false + EM.run { + c = silent { EM::P::HttpClient.send :request, :host => "www.google.com", :port => 80 } + c.callback { + ok = true + c.close_connection + EM.stop + } + c.errback {EM.stop} + } + assert ok + end + + #------------------------------------- + + def test_http_client_2 + ok = false + EM.run { + c = silent { EM::P::HttpClient.send :request, :host => "www.google.com", :port => 80 } + c.callback { + ok = true + c.close_connection + EM.stop + } + c.errback {EM.stop} + } + assert ok + end + + + #----------------------------------------- + + # Test a server that returns a page with a zero content-length. + # This caused an early version of the HTTP client not to generate a response, + # causing this test to hang. Observe, there was no problem with responses + # lacking a content-length, just when the content-length was zero. + # + class EmptyContent < EM::Connection + def initialize *args + super + end + def receive_data data + send_data "HTTP/1.0 404 ...\r\nContent-length: 0\r\n\r\n" + close_connection_after_writing + end + end + + def test_http_empty_content + ok = false + EM.run { + EM.start_server "127.0.0.1", @port, EmptyContent + c = silent { EM::P::HttpClient.send :request, :host => "127.0.0.1", :port => @port } + c.callback { + ok = true + c.close_connection + EM.stop + } + } + assert ok + end + + + #--------------------------------------- + + class PostContent < EM::P::LineAndTextProtocol + def initialize *args + super + @lines = [] + end + def receive_line line + if line.length > 0 + @lines << line + else + process_headers + end + end + def receive_binary_data data + @post_content = data + send_response + end + def process_headers + if @lines.first =~ /\APOST ([^\s]+) HTTP\/1.1\Z/ + @uri = $1.dup + else + raise "bad request" + end + + @lines.each {|line| + if line =~ /\AContent-length:\s*(\d+)\Z/i + @content_length = $1.dup.to_i + elsif line =~ /\AContent-type:\s*(\d+)\Z/i + @content_type = $1.dup + end + } + + raise "invalid content length" unless @content_length + set_binary_mode @content_length + end + def send_response + send_data "HTTP/1.1 200 ...\r\nConnection: close\r\nContent-length: 10\r\nContent-type: text/html\r\n\r\n0123456789" + close_connection_after_writing + end + end + + # TODO, this is WRONG. The handler is asserting an HTTP 1.1 request, but the client + # is sending a 1.0 request. Gotta fix the client + def test_post + response = nil + EM.run { + EM.start_server '127.0.0.1', @port, PostContent + setup_timeout(2) + c = silent { EM::P::HttpClient.request( + :host => '127.0.0.1', + :port => @port, + :method => :post, + :request => "/aaa", + :content => "XYZ", + :content_type => "text/plain" + )} + c.callback {|r| + response = r + EM.stop + } + } + + assert_equal( 200, response[:status] ) + assert_equal( "0123456789", response[:content] ) + end + + + # TODO, need a more intelligent cookie tester. + # In fact, this whole test-harness needs a beefier server implementation. + def test_cookie + ok = false + EM.run { + c = silent { EM::Protocols::HttpClient.send :request, :host => "www.google.com", :port => 80, :cookie=>"aaa=bbb" } + c.callback { + ok = true + c.close_connection + EM.stop + } + c.errback {EM.stop} + } + assert ok + end + + # We can tell the client to send an HTTP/1.0 request (default is 1.1). + # This is useful for suppressing chunked responses until those are working. + def test_version_1_0 + ok = false + EM.run { + c = silent { EM::P::HttpClient.request( + :host => "www.google.com", + :port => 80, + :version => "1.0" + )} + c.callback { + ok = true + c.close_connection + EM.stop + } + c.errback {EM.stop} + } + assert ok + end + + #----------------------------------------- + + # Test a server that returns chunked encoding + # + class ChunkedEncodingContent < EventMachine::Connection + def initialize *args + super + end + def receive_data data + send_data ["HTTP/1.1 200 OK", + "Server: nginx/0.7.67", + "Date: Sat, 23 Oct 2010 16:41:32 GMT", + "Content-Type: application/json", + "Transfer-Encoding: chunked", + "Connection: keep-alive", + "", + "1800", + "chunk1" * 1024, + "5a", + "chunk2" * 15, + "0", + ""].join("\r\n") + close_connection_after_writing + end + end + + def test_http_chunked_encoding_content + ok = false + EM.run { + EM.start_server "127.0.0.1", @port, ChunkedEncodingContent + c = silent { EM::P::HttpClient.send :request, :host => "127.0.0.1", :port => @port } + c.callback { |result| + if result[:content] == "chunk1" * 1024 + "chunk2" * 15 + ok = true + end + c.close_connection + EM.stop + } + } + assert ok + end + +end + + diff --git a/bin/gems/eventmachine-1.2.7/tests/test_httpclient2.rb b/bin/gems/eventmachine-1.2.7/tests/test_httpclient2.rb new file mode 100644 index 00000000..a00fcbcb --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_httpclient2.rb @@ -0,0 +1,128 @@ +require 'em_test_helper' + +class TestHttpClient2 < Test::Unit::TestCase + class TestServer < EM::Connection + end + + def setup + @port = next_port + end + + # #connect returns an object which has made a connection to an HTTP server + # and exposes methods for making HTTP requests on that connection. + # #connect can take either a pair of parameters (a host and a port), + # or a single parameter which is a Hash. + # + def test_connect + EM.run { + setup_timeout(1) + EM.start_server '127.0.0.1', @port, TestServer + silent do + EM::P::HttpClient2.connect '127.0.0.1', @port + EM::P::HttpClient2.connect( :host=>'127.0.0.1', :port=>@port ) + end + EM.stop + } + end + + def test_bad_port + EM.run { + setup_timeout(1) + EM.start_server '127.0.0.1', @port, TestServer + assert_raises( ArgumentError ) { + silent { EM::P::HttpClient2.connect '127.0.0.1', "xxx" } + } + EM.stop + } + end + + def test_bad_server + err = nil + EM.run { + setup_timeout(1) + http = silent { EM::P::HttpClient2.connect '127.0.0.1', 9999 } + d = http.get "/" + d.errback { err = true; d.internal_error; EM.stop } + } + assert(err) + end + + def test_get + content = nil + EM.run { + setup_timeout(1) + http = silent { EM::P::HttpClient2.connect :host => "google.com", :port => 80, :version => '1.0' } + d = http.get "/" + d.callback { + content = d.content + EM.stop + } + } + assert(content) + end + + # Not a pipelined request because we wait for one response before we request the next. + # XXX this test is broken because it sends the second request to the first connection + # XXX right before the connection closes + def _test_get_multiple + content = nil + EM.run { + setup_timeout(1) + http = silent { EM::P::HttpClient2.connect "google.com", :version => '1.0' } + d = http.get "/" + d.callback { + e = http.get "/" + e.callback { + content = e.content + EM.stop + } + } + } + assert(content) + end + + def test_get_pipeline + headers, headers2 = nil, nil + EM.run { + setup_timeout(1) + http = silent { EM::P::HttpClient2.connect "google.com", 80 } + d = http.get("/") + d.callback { + headers = d.headers + } + e = http.get("/") + e.callback { + headers2 = e.headers + } + EM.tick_loop { EM.stop if headers && headers2 } + EM.add_timer(1) { EM.stop } + } + assert(headers) + assert(headers2) + end + + def test_authheader + EM.run { + setup_timeout(1) + EM.start_server '127.0.0.1', @port, TestServer + http = silent { EM::P::HttpClient2.connect '127.0.0.1', 18842 } + d = http.get :url=>"/", :authorization=>"Basic xxx" + d.callback {EM.stop} + d.errback {EM.stop} + } + end + + def test_https_get + omit_unless(EM.ssl?) + d = nil + EM.run { + setup_timeout(1) + http = silent { EM::P::HttpClient2.connect :host => 'www.google.com', :port => 443, :ssl => true, :version => '1.0' } + d = http.get "/" + d.callback {EM.stop} + d.errback {EM.stop} + } + assert_equal(200, d.status) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_idle_connection.rb b/bin/gems/eventmachine-1.2.7/tests/test_idle_connection.rb new file mode 100644 index 00000000..bfc57cd9 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_idle_connection.rb @@ -0,0 +1,31 @@ +require 'em_test_helper' + +class TestIdleConnection < Test::Unit::TestCase + def setup + @port = next_port + end + + def test_idle_time + omit_if(!EM.respond_to?(:get_idle_time)) + + a, b = nil, nil + EM.run do + EM.start_server '127.0.0.1', @port, Module.new + conn = EM.connect '127.0.0.1', @port + EM.add_timer(0.3) do + a = conn.get_idle_time + conn.send_data 'a' + EM.next_tick do + EM.next_tick do + b = conn.get_idle_time + conn.close_connection + EM.stop + end + end + end + end + + assert_in_delta 0.3, a, 0.1 + assert_in_delta 0, b, 0.1 + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_inactivity_timeout.rb b/bin/gems/eventmachine-1.2.7/tests/test_inactivity_timeout.rb new file mode 100644 index 00000000..15e39a2f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_inactivity_timeout.rb @@ -0,0 +1,54 @@ +require 'em_test_helper' + +class TestInactivityTimeout < Test::Unit::TestCase + + if EM.respond_to? :get_comm_inactivity_timeout + def test_default + EM.run { + c = EM.connect("127.0.0.1", 54321) + assert_equal 0.0, c.comm_inactivity_timeout + EM.stop + } + end + + def test_set_and_get + EM.run { + c = EM.connect("127.0.0.1", 54321) + c.comm_inactivity_timeout = 2.5 + assert_equal 2.5, c.comm_inactivity_timeout + EM.stop + } + end + + def test_for_real + start, finish = nil + + timeout_handler = Module.new do + define_method :unbind do + finish = Time.now + EM.stop + end + end + + EM.run { + setup_timeout + EM.heartbeat_interval = 0.01 + EM.start_server("127.0.0.1", 12345) + EM.add_timer(0.01) { + start = Time.now + c = EM.connect("127.0.0.1", 12345, timeout_handler) + c.comm_inactivity_timeout = 0.02 + } + } + + assert_in_delta(0.02, (finish - start), 0.02) + end + else + warn "EM.comm_inactivity_timeout not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_comm_inactivity_timeout_not_implemented + assert true + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ipv4.rb b/bin/gems/eventmachine-1.2.7/tests/test_ipv4.rb new file mode 100644 index 00000000..bd11bbfe --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ipv4.rb @@ -0,0 +1,95 @@ +require 'em_test_helper' + +class TestIPv4 < Test::Unit::TestCase + # Runs a TCP server in the local IPv4 address, connects to it and sends a specific data. + # Timeout in 2 seconds. + def test_ipv4_tcp_local_server + omit_if(!Test::Unit::TestCase.public_ipv4?) + + @@received_data = nil + @local_port = next_port + setup_timeout(2) + + EM.run do + EM::start_server(@@public_ipv4, @local_port) do |s| + def s.receive_data data + @@received_data = data + EM.stop + end + end + + EM::connect(@@public_ipv4, @local_port) do |c| + c.send_data "ipv4/tcp" + end + end + + assert_equal "ipv4/tcp", @@received_data + end + + # Runs a UDP server in the local IPv4 address, connects to it and sends a specific data. + # Timeout in 2 seconds. + def test_ipv4_udp_local_server + omit_if(!Test::Unit::TestCase.public_ipv4?) + + @@received_data = nil + @local_port = next_port + setup_timeout(2) + + EM.run do + EM::open_datagram_socket(@@public_ipv4, @local_port) do |s| + def s.receive_data data + @@received_data = data + EM.stop + end + end + + EM::open_datagram_socket(@@public_ipv4, next_port) do |c| + c.send_datagram "ipv4/udp", @@public_ipv4, @local_port + end + end + + assert_equal "ipv4/udp", @@received_data + end + + # Try to connect via TCP to an invalid IPv4. EM.connect should raise + # EM::ConnectionError. + def test_tcp_connect_to_invalid_ipv4 + omit_if(!Test::Unit::TestCase.public_ipv4?) + + invalid_ipv4 = "9.9:9" + + EM.run do + begin + error = nil + EM.connect(invalid_ipv4, 1234) + rescue => e + error = e + ensure + EM.stop + assert_equal EM::ConnectionError, (error && error.class) + end + end + end + + # Try to send a UDP datagram to an invalid IPv4. EM.send_datagram should raise + # EM::ConnectionError. + def test_udp_send_datagram_to_invalid_ipv4 + omit_if(!Test::Unit::TestCase.public_ipv4?) + + invalid_ipv4 = "9.9:9" + + EM.run do + begin + error = nil + EM.open_datagram_socket(@@public_ipv4, next_port) do |c| + c.send_datagram "hello", invalid_ipv4, 1234 + end + rescue => e + error = e + ensure + EM.stop + assert_equal EM::ConnectionError, (error && error.class) + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ipv6.rb b/bin/gems/eventmachine-1.2.7/tests/test_ipv6.rb new file mode 100644 index 00000000..b52fef1f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ipv6.rb @@ -0,0 +1,107 @@ +require 'em_test_helper' + +class TestIPv6 < Test::Unit::TestCase + + if Test::Unit::TestCase.public_ipv6? + + # Runs a TCP server in the local IPv6 address, connects to it and sends a specific data. + # Timeout in 2 seconds. + def test_ipv6_tcp_local_server + @@received_data = nil + @local_port = next_port + setup_timeout(2) + + EM.run do + EM.start_server(@@public_ipv6, @local_port) do |s| + def s.receive_data data + @@received_data = data + EM.stop + end + end + + EM::connect(@@public_ipv6, @local_port) do |c| + def c.unbind(reason) + warn "unbind: #{reason.inspect}" if reason # XXX at least find out why it failed + end + c.send_data "ipv6/tcp" + end + end + + assert_equal "ipv6/tcp", @@received_data + end + + # Runs a UDP server in the local IPv6 address, connects to it and sends a specific data. + # Timeout in 2 seconds. + def test_ipv6_udp_local_server + @@received_data = nil + @local_port = next_port + @@remote_ip = nil + setup_timeout(2) + + EM.run do + EM.open_datagram_socket(@@public_ipv6, @local_port) do |s| + def s.receive_data data + _port, @@remote_ip = Socket.unpack_sockaddr_in(get_peername) + @@received_data = data + EM.stop + end + end + + EM.open_datagram_socket(@@public_ipv6, next_port) do |c| + c.send_datagram "ipv6/udp", @@public_ipv6, @local_port + end + end + assert_equal @@remote_ip, @@public_ipv6 + assert_equal "ipv6/udp", @@received_data + end + + # Try to connect via TCP to an invalid IPv6. EM.connect should raise + # EM::ConnectionError. + def test_tcp_connect_to_invalid_ipv6 + invalid_ipv6 = "1:A" + + EM.run do + begin + error = nil + EM.connect(invalid_ipv6, 1234) + rescue => e + error = e + ensure + EM.stop + assert_equal EM::ConnectionError, (error && error.class) + end + end + end + + # Try to send a UDP datagram to an invalid IPv6. EM.send_datagram should raise + # EM::ConnectionError. + def test_udp_send_datagram_to_invalid_ipv6 + invalid_ipv6 = "1:A" + + EM.run do + begin + error = nil + EM.open_datagram_socket(@@public_ipv6, next_port) do |c| + c.send_datagram "hello", invalid_ipv6, 1234 + end + rescue => e + error = e + ensure + EM.stop + assert_equal EM::ConnectionError, (error && error.class) + end + end + end + + + else + warn "no IPv6 in this host, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests. + def test_ipv6_unavailable + assert true + end + + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_iterator.rb b/bin/gems/eventmachine-1.2.7/tests/test_iterator.rb new file mode 100644 index 00000000..6ec4e464 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_iterator.rb @@ -0,0 +1,118 @@ +require 'em_test_helper' + +class TestIterator < Test::Unit::TestCase + + # By default, format the time with tenths-of-seconds. + # Some tests should ask for extra decimal places to ensure + # that delays between iterations will receive a changed time. + def get_time(n=1) + time = EM.current_time + time.strftime('%H:%M:%S.') + time.tv_usec.to_s[0, n] + end + + def test_default_concurrency + items = {} + list = 1..10 + EM.run { + EM::Iterator.new(list).each( proc {|num,iter| + time = get_time(3) + items[time] ||= [] + items[time] << num + EM::Timer.new(0.02) {iter.next} + }, proc {EM.stop}) + } + assert_equal(10, items.keys.size) + assert_equal(list.to_a.sort, items.values.flatten.sort) + end + + def test_default_concurrency_with_a_proc + items = {} + list = (1..10).to_a + original_list = list.dup + EM.run { + EM::Iterator.new(proc{list.pop || EM::Iterator::Stop}).each( proc {|num,iter| + time = get_time(3) + items[time] ||= [] + items[time] << num + EM::Timer.new(0.02) {iter.next} + }, proc {EM.stop}) + } + assert_equal(10, items.keys.size) + assert_equal(original_list.to_a.sort, items.values.flatten.sort) + end + + def test_concurrency_bigger_than_list_size + items = {} + list = [1,2,3] + EM.run { + EM::Iterator.new(list,10).each(proc {|num,iter| + time = get_time + items[time] ||= [] + items[time] << num + EM::Timer.new(1) {iter.next} + }, proc {EM.stop}) + } + assert_equal(1, items.keys.size) + assert_equal(list.to_a.sort, items.values.flatten.sort) + end + + def test_changing_concurrency_affects_active_iteration + items = {} + list = 1..25 + seen = 0 + EM.run { + i = EM::Iterator.new(list,1) + i.each(proc {|num,iter| + time = get_time + items[time] ||= [] + items[time] << num + if (seen += 1) == 5 + # The first 5 items will be distinct times + # The next 20 items will happen in 2 bursts + i.concurrency = 10 + end + EM::Timer.new(0.2) {iter.next} + }, proc {EM.stop}) + } + assert_in_delta(7, items.keys.size, 1) + assert_equal(list.to_a.sort, items.values.flatten.sort) + end + + def test_map + list = 100..150 + EM.run { + EM::Iterator.new(list).map(proc{ |num,iter| + EM.add_timer(0.01){ iter.return(num) } + }, proc{ |results| + assert_equal(list.to_a.size, results.size) + EM.stop + }) + } + end + + def test_inject + omit_if(windows?) + + list = %w[ pwd uptime uname date ] + EM.run { + EM::Iterator.new(list, 2).inject({}, proc{ |hash,cmd,iter| + EM.system(cmd){ |output,status| + hash[cmd] = status.exitstatus == 0 ? output.strip : nil + iter.return(hash) + } + }, proc{ |results| + assert_equal(results.keys.sort, list.sort) + EM.stop + }) + } + end + + def test_concurrency_is_0 + EM.run { + assert_raise ArgumentError do + EM::Iterator.new(1..5,0) + end + EM.stop + } + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_kb.rb b/bin/gems/eventmachine-1.2.7/tests/test_kb.rb new file mode 100644 index 00000000..9c31f5fb --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_kb.rb @@ -0,0 +1,28 @@ +require 'em_test_helper' + +class TestKeyboardEvents < Test::Unit::TestCase + + module KbHandler + include EM::Protocols::LineText2 + def receive_line d + EM::stop if d == "STOP" + end + end + + # This test doesn't actually do anything useful but is here to + # illustrate the usage. If you removed the timer and ran this test + # by itself on a console, and then typed into the console, it would + # work. + # I don't know how to get the test harness to simulate actual keystrokes. + # When someone figures that out, then we can make this a real test. + # + def test_kb + omit_if(jruby?) + omit_if(!$stdout.tty?) # don't run the test unless it stands a chance of validity. + EM.run do + EM.open_keyboard KbHandler + EM::Timer.new(1) { EM.stop } + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_line_protocol.rb b/bin/gems/eventmachine-1.2.7/tests/test_line_protocol.rb new file mode 100644 index 00000000..2067a72e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_line_protocol.rb @@ -0,0 +1,33 @@ +require 'em_test_helper' + +class TestLineProtocol < Test::Unit::TestCase + class LineProtocolTestClass + include EM::Protocols::LineProtocol + + def lines + @lines ||= [] + end + + def receive_line(line) + lines << line + end + end + + def setup + @proto = LineProtocolTestClass.new + end + + def test_simple_split_line + @proto.receive_data("this is") + assert_equal([], @proto.lines) + + @proto.receive_data(" a test\n") + assert_equal(["this is a test"], @proto.lines) + end + + def test_simple_lines + @proto.receive_data("aaa\nbbb\r\nccc\nddd") + assert_equal(%w(aaa bbb ccc), @proto.lines) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ltp.rb b/bin/gems/eventmachine-1.2.7/tests/test_ltp.rb new file mode 100644 index 00000000..06c26851 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ltp.rb @@ -0,0 +1,155 @@ +require 'em_test_helper' + +class TestLineAndTextProtocol < Test::Unit::TestCase + + class TLP_LineBuffer < EM::P::LineAndTextProtocol + attr_reader :line_buffer + + def initialize + super + @line_buffer = [] + end + + def receive_line line + @line_buffer << line + end + end + + module StopClient + def set_receive_data(&blk) + @rdb = blk + end + + def receive_data data + @rdb.call(data) if @rdb + end + + def unbind + EM.add_timer(0.1) { EM.stop } + end + end + + def setup + @port = next_port + end + + def test_simple_lines + conn = nil + EM.run { + EM.start_server( "127.0.0.1", @port, TLP_LineBuffer ) do |c| + conn = c + end + setup_timeout + + EM.connect "127.0.0.1", @port, StopClient do |c| + c.send_data "aaa\nbbb\r\nccc\n" + c.close_connection_after_writing + end + } + assert_equal( %w(aaa bbb ccc), conn.line_buffer) + end + + #-------------------------------------------------------------------- + + class TLP_ErrorMessage < EM::P::LineAndTextProtocol + attr_reader :error_message + + def initialize + super + @error_message = [] + end + + def receive_line text + raise + end + + def receive_error text + @error_message << text + end + end + + def test_overlength_lines + conn = nil + EM.run { + EM.start_server( "127.0.0.1", @port, TLP_ErrorMessage ) do |c| + conn = c + end + setup_timeout + EM.connect "127.0.0.1", @port, StopClient do |c| + c.send_data "a" * (16*1024 + 1) + c.send_data "\n" + c.close_connection_after_writing + end + + } + assert_equal( ["overlength line"], conn.error_message ) + end + + + #-------------------------------------------------------------------- + + class LineAndTextTest < EM::P::LineAndTextProtocol + def receive_line line + if line =~ /content-length:\s*(\d+)/i + @content_length = $1.to_i + elsif line.length == 0 + set_binary_mode @content_length + end + end + def receive_binary_data text + send_data "received #{text.length} bytes" + close_connection_after_writing + end + end + + def test_lines_and_text + output = '' + EM.run { + EM.start_server( "127.0.0.1", @port, LineAndTextTest ) + setup_timeout + + EM.connect "127.0.0.1", @port, StopClient do |c| + c.set_receive_data { |data| output << data } + c.send_data "Content-length: 400\n" + c.send_data "\n" + c.send_data "A" * 400 + EM.add_timer(0.1) { c.close_connection_after_writing } + end + } + assert_equal( "received 400 bytes", output ) + end + + #-------------------------------------------------------------------- + + + class BinaryTextTest < EM::P::LineAndTextProtocol + def receive_line line + if line =~ /content-length:\s*(\d+)/i + set_binary_mode $1.to_i + else + raise "protocol error" + end + end + def receive_binary_data text + send_data "received #{text.length} bytes" + close_connection_after_writing + end + end + + def test_binary_text + output = '' + EM.run { + EM.start_server( "127.0.0.1", @port, BinaryTextTest ) + setup_timeout + + EM.connect "127.0.0.1", @port, StopClient do |c| + c.set_receive_data { |data| output << data } + c.send_data "Content-length: 10000\n" + c.send_data "A" * 10000 + EM.add_timer(0.1) { c.close_connection_after_writing } + end + } + assert_equal( "received 10000 bytes", output ) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ltp2.rb b/bin/gems/eventmachine-1.2.7/tests/test_ltp2.rb new file mode 100644 index 00000000..220fcbe1 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ltp2.rb @@ -0,0 +1,332 @@ +require 'em_test_helper' + +# TODO!!! Need tests for overlength headers and text bodies. + +class TestLineText2 < Test::Unit::TestCase + + # Run each of these tests two ways: passing in the whole test-dataset in one chunk, + # and passing it in one character at a time. + + class Basic + include EM::Protocols::LineText2 + attr_reader :lines + def receive_line line + (@lines ||= []) << line + end + end + def test_basic + testdata = "Line 1\nLine 2\r\nLine 3\n" + + a = Basic.new + a.receive_data testdata + assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines ) + + a = Basic.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines ) + end + + # The basic test above shows that extra newlines are chomped + # This test shows that newlines are preserved if the delimiter isn't \n + class PreserveNewlines + include EM::Protocols::LineText2 + attr_reader :lines + def initialize *args + super + @delim = "|" + set_delimiter @delim + end + def receive_line line + (@lines ||= []) << line + end + end + def test_preserve_newlines + a = PreserveNewlines.new + a.receive_data "aaa|bbb|ccc|\n|\r\n| \t ||" + assert_equal( ["aaa", "bbb", "ccc", "\n", "\r\n", " \t ", ""], a.lines ) + end + + class ChangeDelimiter + include EM::Protocols::LineText2 + attr_reader :lines + def initialize *args + super + @delim = "A" + set_delimiter @delim + end + def receive_line line + (@lines ||= []) << line + set_delimiter( @delim.succ! ) + end + end + + def test_change_delimiter + testdata = %Q(LineaALinebBLinecCLinedD) + + a = ChangeDelimiter.new + a.receive_data testdata + assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines ) + + a = ChangeDelimiter.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines ) + end + + class RegexDelimiter + include EM::Protocols::LineText2 + attr_reader :lines + def initialize *args + super + @delim = /[A-D]/ + set_delimiter @delim + end + def receive_line line + (@lines ||= []) << line + end + end + + def test_regex_delimiter + testdata = %Q(LineaALinebBLinecCLinedD) + + a = RegexDelimiter.new + a.receive_data testdata + assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines ) + + a = RegexDelimiter.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines ) + end + + #-- + # Test two lines followed by an empty line, ten bytes of binary data, then + # two more lines. + + class Binary + include EM::Protocols::LineText2 + attr_reader :lines, :body + def initialize *args + super + @lines = [] + @body = nil + end + def receive_line ln + if ln == "" + set_text_mode 10 + else + @lines << ln + end + end + def receive_binary_data data + @body = data + end + end + + def test_binary + testdata = %Q(Line 1 +Line 2 + +0000000000Line 3 +Line 4 +) + + a = Binary.new + a.receive_data testdata + assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines) + assert_equal( "0000000000", a.body ) + + a = Binary.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines) + assert_equal( "0000000000", a.body ) + end + + + # Test unsized binary data. The expectation is that each chunk of it + # will be passed to us as it it received. + class UnsizedBinary + include EM::Protocols::LineText2 + attr_reader :n_calls, :body + def initialize *args + super + set_text_mode + end + def receive_binary_data data + @n_calls ||= 0 + @n_calls += 1 + (@body ||= "") << data + end + end + + def test_unsized_binary + testdata = "X\0" * 1000 + + a = UnsizedBinary.new + a.receive_data testdata + assert_equal( 1, a.n_calls ) + assert_equal( testdata, a.body ) + + a = UnsizedBinary.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( 2000, a.n_calls ) + assert_equal( testdata, a.body ) + end + + + # Test binary data with a "throw back" into line-mode. + class ThrowBack + include EM::Protocols::LineText2 + attr_reader :headers + def initialize *args + super + @headers = [] + @n_bytes = 0 + set_text_mode + end + def receive_binary_data data + wanted = 25 - @n_bytes + will_take = if data.length > wanted + data.length - wanted + else + data.length + end + @n_bytes += will_take + + if @n_bytes == 25 + set_line_mode( data[will_take..-1] ) + end + end + def receive_line ln + @headers << ln + end + end + def test_throw_back + testdata = "Line\n" * 10 + + a = ThrowBack.new + a.receive_data testdata + assert_equal( ["Line"] * 5, a.headers ) + + a = ThrowBack.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( ["Line"] * 5, a.headers ) + end + + # Test multi-character line delimiters. + # Also note that the test data has a "tail" with no delimiter, that will be + # discarded, but cf. the BinaryTail test. + # TODO!!! This test doesn't work in the byte-by-byte case. + class Multichar + include EM::Protocols::LineText2 + attr_reader :lines + def initialize *args + super + @lines = [] + set_delimiter "012" + end + def receive_line ln + @lines << ln + end + end + def test_multichar + testdata = "Line012Line012Line012Line" + + a = Multichar.new + a.receive_data testdata + assert_equal( ["Line"]*3, a.lines ) + + a = Multichar.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + # DOESN'T WORK in this case. Multi-character delimiters are broken. + #assert_equal( ["Line"]*3, a.lines ) + end + + # Test a binary "tail," when a sized binary transfer doesn't complete because + # of an unbind. We get a partial result. + class BinaryTail + include EM::Protocols::LineText2 + attr_reader :data + def initialize *args + super + @data = "" + set_text_mode 1000 + end + def receive_binary_data data + # we expect to get all the data in one chunk, even in the byte-by-byte case, + # because sized transfers by definition give us exactly one call to + # #receive_binary_data. + @data = data + end + end + def test_binary_tail + testdata = "0" * 500 + + a = BinaryTail.new + a.receive_data testdata + a.unbind + assert_equal( "0" * 500, a.data ) + + a = BinaryTail.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + a.unbind + assert_equal( "0" * 500, a.data ) + end + + + # Test an end-of-binary call. Arrange to receive binary data but don't bother counting it + # as it comes. Rely on getting receive_end_of_binary_data to signal the transition back to + # line mode. + # At the present time, this isn't strictly necessary with sized binary chunks because by + # definition we accumulate them and make exactly one call to receive_binary_data, but + # we may want to support a mode in the future that would break up large chunks into multiple + # calls. + class LazyBinary + include EM::Protocols::LineText2 + attr_reader :data, :end + def initialize *args + super + @data = "" + set_text_mode 1000 + end + def receive_binary_data data + # we expect to get all the data in one chunk, even in the byte-by-byte case, + # because sized transfers by definition give us exactly one call to + # #receive_binary_data. + @data = data + end + def receive_end_of_binary_data + @end = true + end + end + def test_receive_end_of_binary_data + testdata = "_" * 1000 + a = LazyBinary.new + testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) } + assert_equal( "_" * 1000, a.data ) + assert( a.end ) + end + + + # This tests a bug fix in which calling set_text_mode failed when called + # inside receive_binary_data. + # + class BinaryPair + include EM::Protocols::LineText2 + attr_reader :sizes + def initialize *args + super + set_text_mode 1 + @sizes = [] + end + def receive_binary_data dt + @sizes << dt.length + set_text_mode( (dt.length == 1) ? 2 : 1 ) + end + end + def test_binary_pairs + test_data = "123" * 5 + a = BinaryPair.new + a.receive_data test_data + assert_equal( [1,2,1,2,1,2,1,2,1,2], a.sizes ) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_many_fds.rb b/bin/gems/eventmachine-1.2.7/tests/test_many_fds.rb new file mode 100644 index 00000000..7c126dcc --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_many_fds.rb @@ -0,0 +1,22 @@ +require 'em_test_helper' +require 'socket' + +class TestManyFDs < Test::Unit::TestCase + def setup + @port = next_port + end + + def test_connection_class_cache + mod = Module.new + a = nil + Process.setrlimit(Process::RLIMIT_NOFILE, 4096) rescue nil + EM.run { + EM.start_server '127.0.0.1', @port, mod + 1100.times do + a = EM.connect '127.0.0.1', @port, mod + assert_kind_of EM::Connection, a + end + EM.stop + } + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_next_tick.rb b/bin/gems/eventmachine-1.2.7/tests/test_next_tick.rb new file mode 100644 index 00000000..9b60359c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_next_tick.rb @@ -0,0 +1,104 @@ +require 'em_test_helper' + +class TestNextTick < Test::Unit::TestCase + + def test_tick_arg + pr = proc {EM.stop} + EM.run { + EM.next_tick pr + } + assert true + end + + def test_tick_block + EM.run { + EM.next_tick {EM.stop} + } + assert true + end + + # This illustrates the solution to a long-standing problem. + # It's now possible to correctly nest calls to EM#run. + # See the source code commentary for EM#run for more info. + # + def test_run_run + EM.run { + EM.run { + EM.next_tick {EM.stop} + } + } + end + + def test_pre_run_queue + x = false + EM.next_tick { EM.stop; x = true } + EM.run { EM.add_timer(0.01) { EM.stop } } + assert x + end + + def test_cleanup_after_stop + x = true + EM.run{ + EM.next_tick{ + EM.stop + EM.next_tick{ x=false } + } + } + EM.run{ + EM.next_tick{ EM.stop } + } + assert x + end + + # We now support an additional parameter for EM#run. + # You can pass two procs to EM#run now. The first is executed as the normal + # run block. The second (if given) is scheduled for execution after the + # reactor loop completes. + # The reason for supporting this is subtle. There has always been an expectation + # that EM#run doesn't return until after the reactor loop ends. But now it's + # possible to nest calls to EM#run, which means that a nested call WILL + # RETURN. In order to write code that will run correctly either way, it's + # recommended to put any code which must execute after the reactor completes + # in the second parameter. + # + def test_run_run_2 + a = proc {EM.stop} + b = proc {assert true} + EM.run a, b + end + + + # This illustrates that EM#run returns when it's called nested. + # This isn't a feature, rather it's something to be wary of when writing code + # that must run correctly even if EM#run is called while a reactor is already + # running. + def test_run_run_3 + a = [] + EM.run { + EM.run proc {EM.stop}, proc {a << 2} + a << 1 + } + assert_equal( [1,2], a ) + end + + + def test_schedule_on_reactor_thread + x = false + EM.run do + EM.schedule { x = true } + EM.stop + end + assert x + end + + def test_schedule_from_thread + x = false + EM.run do + Thread.new { EM.schedule { x = true } }.join + assert !x + EM.next_tick { EM.stop } + end + assert x + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_object_protocol.rb b/bin/gems/eventmachine-1.2.7/tests/test_object_protocol.rb new file mode 100644 index 00000000..b1287ea8 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_object_protocol.rb @@ -0,0 +1,36 @@ +require 'em_test_helper' + +class TestObjectProtocol < Test::Unit::TestCase + module Server + include EM::P::ObjectProtocol + def post_init + send_object :hello=>'world' + end + def receive_object obj + $server = obj + EM.stop + end + end + + module Client + include EM::P::ObjectProtocol + def receive_object obj + $client = obj + send_object 'you_said'=>obj + end + end + + def setup + @port = next_port + end + + def test_send_receive + EM.run{ + EM.start_server "127.0.0.1", @port, Server + EM.connect "127.0.0.1", @port, Client + } + + assert($client == {:hello=>'world'}) + assert($server == {'you_said'=>{:hello=>'world'}}) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_pause.rb b/bin/gems/eventmachine-1.2.7/tests/test_pause.rb new file mode 100644 index 00000000..d078a77f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_pause.rb @@ -0,0 +1,107 @@ +require 'em_test_helper' + +class TestPause < Test::Unit::TestCase + if EM.respond_to? :pause_connection + def setup + @port = next_port + end + + def teardown + assert(!EM.reactor_running?) + end + + def test_pause_resume + server = nil + + s_rx = c_rx = 0 + + test_server = Module.new do + define_method :post_init do + server = self + end + + define_method :receive_data do |data| + s_rx += 1 + + EM.add_periodic_timer(0.01) { send_data 'hi' } + send_data 'hi' + + # pause server, now no outgoing data will actually + # be sent and no more incoming data will be received + pause + end + end + + test_client = Module.new do + def post_init + EM.add_periodic_timer(0.01) do + send_data 'hello' + end + end + + define_method :receive_data do |data| + c_rx += 1 + end + end + + EM.run do + EM.start_server "127.0.0.1", @port, test_server + EM.connect "127.0.0.1", @port, test_client + + EM.add_timer(0.05) do + assert_equal 1, s_rx + assert_equal 0, c_rx + assert server.paused? + + # resume server, queued outgoing and incoming data will be flushed + server.resume + + assert !server.paused? + + EM.add_timer(0.05) do + assert server.paused? + assert s_rx > 1 + assert c_rx > 0 + EM.stop + end + end + end + end + + def test_pause_in_receive_data + incoming = [] + + test_server = Module.new do + define_method(:receive_data) do |data| + incoming << data + pause + EM.add_timer(0.5){ close_connection } + end + define_method(:unbind) do + EM.stop + end + end + + buf = 'a' * 1024 + + EM.run do + EM.start_server "127.0.0.1", @port, test_server + cli = EM.connect "127.0.0.1", @port + 128.times do + cli.send_data buf + end + end + + assert_equal 1, incoming.size + assert incoming[0].bytesize > buf.bytesize + assert incoming[0].bytesize < buf.bytesize * 128 + end + else + warn "EM.pause_connection not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_pause_connection_not_implemented + assert true + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_pending_connect_timeout.rb b/bin/gems/eventmachine-1.2.7/tests/test_pending_connect_timeout.rb new file mode 100644 index 00000000..a3f7fa4d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_pending_connect_timeout.rb @@ -0,0 +1,52 @@ +require 'em_test_helper' + +class TestPendingConnectTimeout < Test::Unit::TestCase + + if EM.respond_to? :get_pending_connect_timeout + def test_default + EM.run { + c = EM.connect("127.0.0.1", 54321) + assert_equal 20.0, c.pending_connect_timeout + EM.stop + } + end + + def test_set_and_get + EM.run { + c = EM.connect("127.0.0.1", 54321) + c.pending_connect_timeout = 2.5 + assert_equal 2.5, c.pending_connect_timeout + EM.stop + } + end + + def test_for_real + start, finish = nil + + timeout_handler = Module.new do + define_method :unbind do + finish = EM.current_time + EM.stop + end + end + + EM.run { + setup_timeout + EM.heartbeat_interval = 0.1 + start = EM.current_time + c = EM.connect('192.0.2.0', 54321, timeout_handler) + c.pending_connect_timeout = 0.2 + } + + assert_in_delta(0.2, (finish - start), 0.1) + end + else + warn "EM.pending_connect_timeout not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_pending_connect_timeout_not_implemented + assert true + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_pool.rb b/bin/gems/eventmachine-1.2.7/tests/test_pool.rb new file mode 100644 index 00000000..f859a9d1 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_pool.rb @@ -0,0 +1,196 @@ +require 'em_test_helper' + +class TestPool < Test::Unit::TestCase + def pool + @pool ||= EM::Pool.new + end + + def go + EM.run { yield } + end + + def stop + EM.stop + end + + def deferrable + @deferrable ||= EM::DefaultDeferrable.new + end + + def test_supports_more_work_than_resources + ran = false + go do + pool.perform do + ran = true + deferrable + end + stop + end + assert_equal false, ran + go do + pool.add :resource + stop + end + assert_equal true, ran + end + + def test_reques_resources_on_error + pooled_res, pooled_res2 = nil + pool.add :res + go do + pool.perform do |res| + pooled_res = res + deferrable + end + stop + end + deferrable.fail + go do + pool.perform do |res| + pooled_res2 = res + deferrable + end + stop + end + assert_equal :res, pooled_res + assert_equal pooled_res, pooled_res2 + end + + def test_supports_custom_on_error + eres = nil + pool.on_error do |res| + eres = res + end + performs = [] + pool.add :res + go do + pool.perform do |res| + performs << res + deferrable + end + pool.perform do |res| + performs << res + deferrable + end + deferrable.fail + stop + end + assert_equal :res, eres + # manual requeues required when error handler is installed: + assert_equal 1, performs.size + assert_equal :res, performs.first + end + + def test_catches_successful_deferrables + performs = [] + pool.add :res + go do + pool.perform { |res| performs << res; deferrable } + pool.perform { |res| performs << res; deferrable } + stop + end + assert_equal [:res], performs + deferrable.succeed + go { stop } + assert_equal [:res, :res], performs + end + + def test_prunes_locked_and_removed_resources + performs = [] + pool.add :res + deferrable.succeed + go do + pool.perform { |res| performs << res; pool.remove res; deferrable } + pool.perform { |res| performs << res; pool.remove res; deferrable } + stop + end + assert_equal [:res], performs + end + + # Contents is only to be used for inspection of the pool! + def test_contents + pool.add :res + assert_equal [:res], pool.contents + # Assert that modifying the contents list does not affect the pools + # contents. + pool.contents.delete(:res) + assert_equal [:res], pool.contents + end + + def test_contents_when_perform_errors_and_on_error_is_not_set + pool.add :res + assert_equal [:res], pool.contents + + pool.perform do |r| + d = EM::DefaultDeferrable.new + d.fail + d + end + + EM.run { EM.next_tick { EM.stop } } + + assert_equal [:res], pool.contents + end + + def test_contents_when_perform_errors_and_on_error_is_set + pool.add :res + res = nil + pool.on_error do |r| + res = r + end + assert_equal [:res], pool.contents + + pool.perform do |r| + d = EM::DefaultDeferrable.new + d.fail 'foo' + d + end + + EM.run { EM.next_tick { EM.stop } } + + assert_equal :res, res + assert_equal [], pool.contents + end + + def test_num_waiting + pool.add :res + assert_equal 0, pool.num_waiting + pool.perform { |r| EM::DefaultDeferrable.new } + assert_equal 0, pool.num_waiting + 10.times { pool.perform { |r| EM::DefaultDeferrable.new } } + EM.run { EM.next_tick { EM.stop } } + assert_equal 10, pool.num_waiting + end + + def test_exceptions_in_the_work_block_bubble_up_raise_and_fail_the_resource + pool.add :res + + res = nil + pool.on_error { |r| res = r } + pool.perform { raise 'boom' } + + assert_raises(RuntimeError) do + EM.run { EM.next_tick { EM.stop } } + end + + assert_equal [], pool.contents + assert_equal :res, res + end + + def test_removed_list_does_not_leak_on_errors + pool.add :res + + pool.on_error do |r| + # This is actually the wrong thing to do, and not required, but some users + # might do it. When they do, they would find that @removed would cause a + # slow leak. + pool.remove r + end + + pool.perform { d = EM::DefaultDeferrable.new; d.fail; d } + + EM.run { EM.next_tick { EM.stop } } + assert_equal [], pool.instance_variable_get(:@removed) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_process_watch.rb b/bin/gems/eventmachine-1.2.7/tests/test_process_watch.rb new file mode 100644 index 00000000..6e0c49a7 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_process_watch.rb @@ -0,0 +1,50 @@ +require 'em_test_helper' + +if EM.kqueue? + class TestProcessWatch < Test::Unit::TestCase + module ParentProcessWatcher + def process_forked + $forked = true + end + end + + module ChildProcessWatcher + def process_exited + $exited = true + end + def unbind + $unbind = true + EM.stop + end + end + + def setup + EM.kqueue = true + end + + def teardown + EM.kqueue = false + end + + def test_events + omit_if(rbx?) + omit_if(jruby?) + EM.run{ + # watch ourselves for a fork notification + EM.watch_process(Process.pid, ParentProcessWatcher) + $fork_pid = fork{ sleep } + child = EM.watch_process($fork_pid, ChildProcessWatcher) + $pid = child.pid + + EM.add_timer(0.2){ + Process.kill('TERM', $fork_pid) + } + } + + assert_equal($pid, $fork_pid) + assert($forked) + assert($exited) + assert($unbind) + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_processes.rb b/bin/gems/eventmachine-1.2.7/tests/test_processes.rb new file mode 100644 index 00000000..dd03cf02 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_processes.rb @@ -0,0 +1,128 @@ +require 'em_test_helper' + +class TestProcesses < Test::Unit::TestCase + + if !windows? && !jruby? + + # EM::DeferrableChildProcess is a sugaring of a common use-case + # involving EM::popen. + # Call the #open method on EM::DeferrableChildProcess, passing + # a command-string. #open immediately returns an EM::Deferrable + # object. It also schedules the forking of a child process, which + # will execute the command passed to #open. + # When the forked child terminates, the Deferrable will be signalled + # and execute its callbacks, passing the data that the child process + # wrote to stdout. + # + def test_deferrable_child_process + ls = "" + EM.run { + d = EM::DeferrableChildProcess.open( "ls -ltr" ) + d.callback {|data_from_child| + ls = data_from_child + EM.stop + } + } + assert( ls.length > 0) + end + + def setup + $out = nil + $status = nil + end + + def test_em_system + EM.run{ + EM.system('ls'){ |out,status| $out, $status = out, status; EM.stop } + } + + assert( $out.length > 0 ) + assert_equal(0, $status.exitstatus) + assert_kind_of(Process::Status, $status) + end + + def test_em_system_pid + $pids = [] + + EM.run{ + $pids << EM.system('echo hi', proc{ |out,status|$pids << status.pid; EM.stop }) + } + + assert_equal $pids[0], $pids[1] + end + + def test_em_system_with_proc + EM.run{ + EM.system('ls', proc{ |out,status| $out, $status = out, status; EM.stop }) + } + + assert( $out.length > 0 ) + assert_equal(0, $status.exitstatus) + assert_kind_of(Process::Status, $status) + end + + def test_em_system_with_two_procs + EM.run{ + EM.system('sh', proc{ |process| + process.send_data("echo hello\n") + process.send_data("exit\n") + }, proc{ |out,status| + $out = out + $status = status + EM.stop + }) + } + + assert_equal("hello\n", $out) + end + + def test_em_system_cmd_arguments + EM.run{ + EM.system('echo', '1', '2', 'version', proc{ |process| + }, proc{ |out,status| + $out = out + $status = status + EM.stop + }) + } + + assert_match(/1 2 version/i, $out) + end + + def test_em_system_spaced_arguments + EM.run{ + EM.system('ruby', '-e', 'puts "hello"', proc{ |out,status| + $out = out + EM.stop + }) + } + + assert_equal("hello\n", $out) + end + + def test_em_popen_pause_resume + c_rx = 0 + + test_client = Module.new do + define_method :receive_data do |data| + c_rx += 1 + pause + EM.add_timer(0.5) { EM.stop } + end + end + + EM.run do + EM.popen('echo 1', test_client) + end + + assert_equal 1, c_rx + end + else + warn "EM.popen not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_popen_unsupported + assert true + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_proxy_connection.rb b/bin/gems/eventmachine-1.2.7/tests/test_proxy_connection.rb new file mode 100644 index 00000000..11c0fb41 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_proxy_connection.rb @@ -0,0 +1,180 @@ +require 'em_test_helper' + +class TestProxyConnection < Test::Unit::TestCase + + if EM.respond_to?(:start_proxy) + module ProxyConnection + def initialize(client, request) + @client, @request = client, request + end + + def post_init + EM::enable_proxy(self, @client) + end + + def connection_completed + EM.next_tick { + send_data @request + } + end + + def proxy_target_unbound + $unbound_early = true + EM.stop + end + + def unbind + $proxied_bytes = self.get_proxied_bytes + @client.close_connection_after_writing + end + end + + module PartialProxyConnection + def initialize(client, request, length) + @client, @request, @length = client, request, length + end + + def post_init + EM::enable_proxy(self, @client, 0, @length) + end + + def receive_data(data) + $unproxied_data = data + @client.send_data(data) + end + + def connection_completed + EM.next_tick { + send_data @request + } + end + + def proxy_target_unbound + $unbound_early = true + EM.stop + end + + def proxy_completed + $proxy_completed = true + end + + def unbind + @client.close_connection_after_writing + end + end + + module Client + def connection_completed + send_data "EM rocks!" + end + + def receive_data(data) + $client_data = data + end + + def unbind + EM.stop + end + end + + module Client2 + include Client + def unbind; end + end + + module Server + def receive_data(data) + send_data "I know!" if data == "EM rocks!" + close_connection_after_writing + end + end + + module ProxyServer + def initialize port + @port = port + end + + def receive_data(data) + @proxy = EM.connect("127.0.0.1", @port, ProxyConnection, self, data) + end + end + + module PartialProxyServer + def initialize port + @port = port + end + + def receive_data(data) + EM.connect("127.0.0.1", @port, PartialProxyConnection, self, data, 1) + end + end + + module EarlyClosingProxy + def initialize port + @port = port + end + + def receive_data(data) + EM.connect("127.0.0.1", @port, ProxyConnection, self, data) + close_connection + end + end + + def setup + @port = next_port + @proxy_port = next_port + end + + def test_proxy_connection + EM.run { + EM.start_server("127.0.0.1", @port, Server) + EM.start_server("127.0.0.1", @proxy_port, ProxyServer, @port) + EM.connect("127.0.0.1", @proxy_port, Client) + } + + assert_equal("I know!", $client_data) + end + + def test_proxied_bytes + EM.run { + EM.start_server("127.0.0.1", @port, Server) + EM.start_server("127.0.0.1", @proxy_port, ProxyServer, @port) + EM.connect("127.0.0.1", @proxy_port, Client) + } + + assert_equal("I know!", $client_data) + assert_equal("I know!".bytesize, $proxied_bytes) + end + + def test_partial_proxy_connection + EM.run { + EM.start_server("127.0.0.1", @port, Server) + EM.start_server("127.0.0.1", @proxy_port, PartialProxyServer, @port) + EM.connect("127.0.0.1", @proxy_port, Client) + } + + assert_equal("I know!", $client_data) + assert_equal(" know!", $unproxied_data) + assert($proxy_completed) + end + + def test_early_close + $client_data = nil + EM.run { + EM.start_server("127.0.0.1", @port, Server) + EM.start_server("127.0.0.1", @proxy_port, EarlyClosingProxy, @port) + EM.connect("127.0.0.1", @proxy_port, Client2) + } + + assert($unbound_early) + end + else + warn "EM.start_proxy not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_start_proxy_not_implemented + assert !EM.respond_to?(:start_proxy) + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_pure.rb b/bin/gems/eventmachine-1.2.7/tests/test_pure.rb new file mode 100644 index 00000000..8863a8d1 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_pure.rb @@ -0,0 +1,139 @@ +require 'em_test_helper' + +class TestPure < Test::Unit::TestCase + + def setup + @port = next_port + end + + # These tests are intended to exercise problems that come up in the + # pure-Ruby implementation. However, we DON'T constrain them such that + # they only run in pure-Ruby. These tests need to work identically in + # any implementation. + + #------------------------------------- + + # The EM reactor needs to run down open connections and release other resources + # when it stops running. Make sure this happens even if user code throws a Ruby + # exception. + # If exception handling is incorrect, the second test will fail with a no-bind error + # because the TCP server opened in the first test will not have been closed. + + def test_exception_handling_releases_resources + exception = Class.new(StandardError) + + 2.times do + assert_raises(exception) do + EM.run do + EM.start_server "127.0.0.1", @port + raise exception + end + end + end + end + + # Under some circumstances, the pure Ruby library would emit an Errno::ECONNREFUSED + # exception on certain kinds of TCP connect-errors. + # It's always been something of an open question whether EM should throw an exception + # in these cases but the defined answer has always been to catch it the unbind method. + # With a connect failure, the latter will always fire, but connection_completed will + # never fire. So even though the point is arguable, it's incorrect for the pure Ruby + # version to throw an exception. + module TestConnrefused + def unbind + EM.stop + end + def connection_completed + raise "should never get here" + end + end + + def test_connrefused + assert_nothing_raised do + EM.run { + setup_timeout(2) + EM.connect "127.0.0.1", @port, TestConnrefused + } + end + end + + # Make sure connection_completed gets called as expected with TCP clients. This is the + # opposite of test_connrefused. + # If the test fails, it will hang because EM.stop never gets called. + # + module TestConnaccepted + def connection_completed + EM.stop + end + end + def test_connaccepted + assert_nothing_raised do + EM.run { + EM.start_server "127.0.0.1", @port + EM.connect "127.0.0.1", @port, TestConnaccepted + setup_timeout(1) + } + end + end + + def test_reactor_running + a = false + EM.run { + a = EM.reactor_running? + EM.next_tick {EM.stop} + } + assert a + end + + module TLSServer + def post_init + start_tls + end + + def ssl_handshake_completed + $server_handshake_completed = true + end + + def receive_data(data) + $server_received_data = data + send_data(data) + end + end + + module TLSClient + def post_init + start_tls + end + + def ssl_handshake_completed + $client_handshake_completed = true + end + + def connection_completed + send_data('Hello World!') + end + + def receive_data(data) + $client_received_data = data + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + def test_start_tls + $client_handshake_completed, $server_handshake_completed = false, false + $client_received_data, $server_received_data = nil, nil + EM.run do + EM.start_server("127.0.0.1", 16789, TLSServer) + EM.connect("127.0.0.1", 16789, TLSClient) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + assert($client_received_data == "Hello World!") + assert($server_received_data == "Hello World!") + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_queue.rb b/bin/gems/eventmachine-1.2.7/tests/test_queue.rb new file mode 100644 index 00000000..34278c05 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_queue.rb @@ -0,0 +1,64 @@ +require 'em_test_helper' + +class TestEMQueue < Test::Unit::TestCase + def test_queue_push + s = 0 + EM.run do + q = EM::Queue.new + q.push(1) + EM.next_tick { s = q.size; EM.stop } + end + assert_equal 1, s + end + + def test_queue_pop + x,y,z = nil + EM.run do + q = EM::Queue.new + q.push(1,2,3) + q.pop { |v| x = v } + q.pop { |v| y = v } + q.pop { |v| z = v; EM.stop } + end + assert_equal 1, x + assert_equal 2, y + assert_equal 3, z + end + + def test_queue_reactor_thread + q = EM::Queue.new + + Thread.new { q.push(1,2,3) }.join + assert q.empty? + EM.run { EM.next_tick { EM.stop } } + assert_equal 3, q.size + + x = nil + Thread.new { q.pop { |v| x = v } }.join + assert_equal nil, x + EM.run { EM.next_tick { EM.stop } } + assert_equal 1, x + end + + def test_num_waiting + q = EM::Queue.new + many = 3 + many.times { q.pop {} } + EM.run { EM.next_tick { EM.stop } } + assert_equal many, q.num_waiting + end + + def test_big_queue + EM.run do + q = EM::Queue.new + 2000.times do |i| + q.push(*0..1000) + q.pop { |v| assert_equal v, i % 1001 } + end + q.pop do + assert_equal 1_999_999, q.size + EM.stop + end + end + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_resolver.rb b/bin/gems/eventmachine-1.2.7/tests/test_resolver.rb new file mode 100644 index 00000000..58ed5f57 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_resolver.rb @@ -0,0 +1,105 @@ +require 'em_test_helper' + +class TestResolver < Test::Unit::TestCase + def test_nameserver + assert_kind_of(String, EM::DNS::Resolver.nameserver) + end + + def test_nameservers + assert_kind_of(Array, EM::DNS::Resolver.nameservers) + end + + def test_hosts + assert_kind_of(Hash, EM::DNS::Resolver.hosts) + + # Make sure that blank or comment lines are skipped + refute(EM::DNS::Resolver.hosts.include? nil) + end + + def test_a + pend('FIXME: this test is broken on Windows') if windows? + + EM.run { + d = EM::DNS::Resolver.resolve "example.com" + d.errback { assert false } + d.callback { |r| + assert r + EM.stop + } + } + end + + def test_bad_host + EM.run { + d = EM::DNS::Resolver.resolve "asdfasasdf" + d.callback { assert false } + d.errback { assert true; EM.stop } + } + end + + def test_garbage + assert_raises( ArgumentError ) { + EM.run { + EM::DNS::Resolver.resolve 123 + } + } + end + + # There isn't a public DNS entry like 'example.com' with an A rrset + def test_a_pair + pend('FIXME: this test is broken on Windows') if windows? + + EM.run { + d = EM::DNS::Resolver.resolve "yahoo.com" + d.errback { |err| assert false, "failed to resolve yahoo.com: #{err}" } + d.callback { |r| + assert_kind_of(Array, r) + assert r.size > 1, "returned #{r.size} results: #{r.inspect}" + EM.stop + } + } + end + + def test_localhost + pend('FIXME: this test is broken on Windows') if windows? + + EM.run { + d = EM::DNS::Resolver.resolve "localhost" + d.errback { assert false } + d.callback { |r| + assert_include(["127.0.0.1", "::1"], r.first) + assert_kind_of(Array, r) + + EM.stop + } + } + end + + def test_timer_cleanup + pend('FIXME: this test is broken on Windows') if windows? + + EM.run { + d = EM::DNS::Resolver.resolve "example.com" + d.errback { |err| assert false, "failed to resolve example.com: #{err}" } + d.callback { |r| + # This isn't a great test, but it's hard to get more canonical + # confirmation that the timer is cancelled + assert_nil(EM::DNS::Resolver.socket.instance_variable_get(:@timer)) + + EM.stop + } + } + end + + def test_failure_timer_cleanup + EM.run { + d = EM::DNS::Resolver.resolve "asdfasdf" + d.callback { assert false } + d.errback { + assert_nil(EM::DNS::Resolver.socket.instance_variable_get(:@timer)) + + EM.stop + } + } + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_running.rb b/bin/gems/eventmachine-1.2.7/tests/test_running.rb new file mode 100644 index 00000000..693b3901 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_running.rb @@ -0,0 +1,14 @@ +require 'em_test_helper' + +class TestRunning < Test::Unit::TestCase + def test_running + assert_equal( false, EM::reactor_running? ) + r = false + EM.run { + r = EM::reactor_running? + EM.stop + } + assert_equal( true, r ) + end +end + diff --git a/bin/gems/eventmachine-1.2.7/tests/test_sasl.rb b/bin/gems/eventmachine-1.2.7/tests/test_sasl.rb new file mode 100644 index 00000000..e80f6571 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_sasl.rb @@ -0,0 +1,47 @@ +require 'em_test_helper' + + +class TestSASL < Test::Unit::TestCase + + # SASL authentication is usually done with UNIX-domain sockets, but + # we'll use TCP so this test will work on Windows. As far as the + # protocol handlers are concerned, there's no difference. + + TestUser,TestPsw = "someone", "password" + + class SaslServer < EM::Connection + include EM::Protocols::SASLauth + def validate usr, psw, sys, realm + usr == TestUser and psw == TestPsw + end + end + + class SaslClient < EM::Connection + include EM::Protocols::SASLauthclient + end + + def setup + @port = next_port + end + + def test_sasl + resp = nil + EM.run { + EM.start_server( "127.0.0.1", @port, SaslServer ) + + c = EM.connect( "127.0.0.1", @port, SaslClient ) + d = c.validate?( TestUser, TestPsw ) + d.timeout 1 + d.callback { + resp = true + EM.stop + } + d.errback { + resp = false + EM.stop + } + } + assert_equal( true, resp ) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_send_file.rb b/bin/gems/eventmachine-1.2.7/tests/test_send_file.rb new file mode 100644 index 00000000..a784b505 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_send_file.rb @@ -0,0 +1,217 @@ +require 'em_test_helper' +require 'tempfile' + +class TestSendFile < Test::Unit::TestCase + + if EM.respond_to?(:send_file_data) + module TestModule + def initialize filename + @filename = filename + end + + def post_init + send_file_data @filename + close_connection_after_writing + end + end + + module TestClient + def data_to(&blk) + @data_to = blk + end + + def receive_data(data) + @data_to.call(data) if @data_to + end + + def unbind + EM.stop + end + end + + def setup + @file = Tempfile.new("em_test_file") + @filename = @file.path + @port = next_port + end + + def test_send_file + File.open( @filename, "w" ) {|f| + f << ("A" * 5000) + } + + data = '' + + EM.run { + EM.start_server "127.0.0.1", @port, TestModule, @filename + setup_timeout + + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + assert_equal( "A" * 5000, data ) + end + + # EM::Connection#send_file_data has a strict upper limit on the filesize it will work with. + def test_send_large_file + File.open( @filename, "w" ) {|f| + f << ("A" * 1000000) + } + + data = '' + + assert_raises(RuntimeError) { + EM.run { + EM.start_server "127.0.0.1", @port, TestModule, @filename + setup_timeout + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + } + end + + module StreamTestModule + def initialize filename + @filename = filename + end + + def post_init + EM::Deferrable.future( stream_file_data(@filename)) { + close_connection_after_writing + } + end + end + + module ChunkStreamTestModule + def initialize filename + @filename = filename + end + + def post_init + EM::Deferrable.future( stream_file_data(@filename, :http_chunks=>true)) { + close_connection_after_writing + } + end + end + + def test_stream_file_data + File.open( @filename, "w" ) {|f| + f << ("A" * 1000) + } + + data = '' + + EM.run { + EM.start_server "127.0.0.1", @port, StreamTestModule, @filename + setup_timeout + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + assert_equal( "A" * 1000, data ) + end + + def test_stream_chunked_file_data + File.open( @filename, "w" ) {|f| + f << ("A" * 1000) + } + + data = '' + + EM.run { + EM.start_server "127.0.0.1", @port, ChunkStreamTestModule, @filename + setup_timeout + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + assert_equal( "3e8\r\n#{"A" * 1000}\r\n0\r\n\r\n", data ) + end + + module BadFileTestModule + def initialize filename + @filename = filename + end + + def post_init + de = stream_file_data( @filename+".wrong" ) + de.errback {|msg| + send_data msg + close_connection_after_writing + } + end + end + def test_stream_bad_file + data = '' + EM.run { + EM.start_server "127.0.0.1", @port, BadFileTestModule, @filename + setup_timeout(5) + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + assert_equal( "file not found", data ) + end + else + warn "EM.send_file_data not implemented, skipping tests in #{__FILE__}" + + # Because some rubies will complain if a TestCase class has no tests + def test_em_send_file_data_not_implemented + assert !EM.respond_to?(:send_file_data) + end + end + + begin + require 'fastfilereaderext' + + def test_stream_large_file_data + File.open( @filename, "w" ) {|f| + f << ("A" * 10000) + } + + data = '' + + EM.run { + EM.start_server "127.0.0.1", @port, StreamTestModule, @filename + setup_timeout + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + assert_equal( "A" * 10000, data ) + end + + def test_stream_large_chunked_file_data + File.open( @filename, "w" ) {|f| + f << ("A" * 100000) + } + + data = '' + + EM.run { + EM.start_server "127.0.0.1", @port, ChunkStreamTestModule, @filename + setup_timeout + EM.connect "127.0.0.1", @port, TestClient do |c| + c.data_to { |d| data << d } + end + } + + expected = [ + "4000\r\n#{"A" * 16384}\r\n" * 6, + "6a0\r\n#{"A" * 0x6a0}\r\n", + "0\r\n\r\n" + ].join + assert_equal( expected, data ) + end + rescue LoadError + warn "require 'fastfilereaderext' failed, skipping tests in #{__FILE__}" + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_servers.rb b/bin/gems/eventmachine-1.2.7/tests/test_servers.rb new file mode 100644 index 00000000..2a170504 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_servers.rb @@ -0,0 +1,33 @@ +require 'em_test_helper' +require 'socket' + +class TestServers < Test::Unit::TestCase + + def setup + @port = next_port + end + + def server_alive? + port_in_use?(@port) + end + + def run_test_stop_server + EM.run { + sig = EM.start_server("127.0.0.1", @port) + assert server_alive?, "Server didn't start" + EM.stop_server sig + # Give the server some time to shutdown. + EM.add_timer(0.1) { + assert !server_alive?, "Server didn't stop" + EM.stop + } + } + end + + def test_stop_server + assert !server_alive?, "Port already in use" + 2.times { run_test_stop_server } + assert !server_alive?, "Servers didn't stop" + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_shutdown_hooks.rb b/bin/gems/eventmachine-1.2.7/tests/test_shutdown_hooks.rb new file mode 100644 index 00000000..b0e0c5cc --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_shutdown_hooks.rb @@ -0,0 +1,23 @@ +require 'em_test_helper' + +class TestShutdownHooks < Test::Unit::TestCase + def test_shutdown_hooks + r = false + EM.run { + EM.add_shutdown_hook { r = true } + EM.stop + } + assert_equal( true, r ) + end + + def test_hook_order + r = [] + EM.run { + EM.add_shutdown_hook { r << 2 } + EM.add_shutdown_hook { r << 1 } + EM.stop + } + assert_equal( [1, 2], r ) + end +end + diff --git a/bin/gems/eventmachine-1.2.7/tests/test_smtpclient.rb b/bin/gems/eventmachine-1.2.7/tests/test_smtpclient.rb new file mode 100644 index 00000000..71ed5844 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_smtpclient.rb @@ -0,0 +1,75 @@ +require 'em_test_helper' + +class TestSmtpClient < Test::Unit::TestCase + + Localhost = "127.0.0.1" + Localport = 9801 + + def setup + end + + def teardown + end + + def test_a + # No real tests until we have a server implementation to test against. + # This is what the call looks like, though: + err = nil + EM.run { + d = EM::Protocols::SmtpClient.send :domain=>"example.com", + :host=>Localhost, + :port=>Localport, # optional, defaults 25 + :starttls=>true, + :from=>"sender@example.com", + :to=> ["to_1@example.com", "to_2@example.com"], + :header=> {"Subject" => "This is a subject line"}, + :body=> "This is the body of the email", + :verbose=>true + d.errback {|e| + err = e + EM.stop + } + } + assert(err) + end + + def test_content + err = nil + EM.run { + d = EM::Protocols::SmtpClient.send :domain=>"example.com", + :host=>Localhost, + :port=>Localport, # optional, defaults 25 + :starttls=>true, + :from=>"sender@example.com", + :to=> ["to_1@example.com", "to_2@example.com"], + :content => ["Subject: xxx\r\n\r\ndata\r\n.\r\n"], + :verbose=>true + d.errback {|e| + err = e + EM.stop + } + } + assert(err) + end + + + EM::Protocols::SmtpClient.__send__(:public, :escape_leading_dots) + + def test_escaping + smtp = EM::Protocols::SmtpClient.new :domain => "example.com" + + expectations = { + "Hello\r\n" => "Hello\r\n", + "\r\n.whatever\r\n" => "\r\n..whatever\r\n", + "\r\n.\r\n" => "\r\n..\r\n", + "\r\n.\r\n." => "\r\n..\r\n..", + ".\r\n.\r\n" => "..\r\n..\r\n", + "..\r\n" => "...\r\n" + } + + expectations.each do |input, output| + assert_equal output, smtp.escape_leading_dots(input) + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_smtpserver.rb b/bin/gems/eventmachine-1.2.7/tests/test_smtpserver.rb new file mode 100644 index 00000000..18c50feb --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_smtpserver.rb @@ -0,0 +1,57 @@ +require 'em_test_helper' + +class TestSmtpServer < Test::Unit::TestCase + + # Don't test on port 25. It requires superuser and there's probably + # a mail server already running there anyway. + Localhost = "127.0.0.1" + Localport = 25001 + + # This class is an example of what you need to write in order + # to implement a mail server. You override the methods you are + # interested in. Some, but not all, of these are illustrated here. + # + class Mailserver < EM::Protocols::SmtpServer + + attr_reader :my_msg_body, :my_sender, :my_recipients + + def initialize *args + super + end + def receive_sender sender + @my_sender = sender + #p sender + true + end + def receive_recipient rcpt + @my_recipients ||= [] + @my_recipients << rcpt + true + end + def receive_data_chunk c + @my_msg_body = c.last + end + def connection_ended + EM.stop + end + end + + def test_mail + c = nil + EM.run { + EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn} + EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error + EM::Protocols::SmtpClient.send :host=>Localhost, + :port=>Localport, + :domain=>"bogus", + :from=>"me@example.com", + :to=>"you@example.com", + :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"}, + :body=>"Not much of interest here." + + } + assert_equal( "Not much of interest here.", c.my_msg_body ) + assert_equal( "", c.my_sender ) + assert_equal( [""], c.my_recipients ) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_sock_opt.rb b/bin/gems/eventmachine-1.2.7/tests/test_sock_opt.rb new file mode 100644 index 00000000..60fba351 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_sock_opt.rb @@ -0,0 +1,54 @@ +require 'em_test_helper' +require 'socket' + +class TestSockOpt < Test::Unit::TestCase + def setup + assert(!EM.reactor_running?) + @port = next_port + end + + def teardown + assert(!EM.reactor_running?) + end + + def test_set_sock_opt + omit_if(windows?) + omit_if(!EM.respond_to?(:set_sock_opt)) + + val = nil + test_module = Module.new do + define_method :post_init do + val = set_sock_opt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true + EM.stop + end + end + + EM.run do + EM.start_server '127.0.0.1', @port + EM.connect '127.0.0.1', @port, test_module + end + + assert_equal 0, val + end + + def test_get_sock_opt + omit_if(windows?) + omit_if(!EM.respond_to?(:set_sock_opt)) + + val = nil + test_module = Module.new do + define_method :connection_completed do + val = get_sock_opt Socket::SOL_SOCKET, Socket::SO_ERROR + EM.stop + end + end + + EM.run do + EM.start_server '127.0.0.1', @port + EM.connect '127.0.0.1', @port, test_module + end + + assert_equal "\0\0\0\0", val + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_spawn.rb b/bin/gems/eventmachine-1.2.7/tests/test_spawn.rb new file mode 100644 index 00000000..ab0a92f7 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_spawn.rb @@ -0,0 +1,293 @@ + +require 'em_test_helper' + + + +class TestSpawn < Test::Unit::TestCase + + # Spawn a process that simply stops the reactor. + # Assert that the notification runs after the block that calls it. + # + def test_stop + x = nil + EM.run { + s = EM.spawn {EM.stop} + s.notify + x = true + } + assert x + end + + + # Pass a parameter to a spawned process. + # + def test_parms + val = 5 + EM.run { + s = EM.spawn {|v| val *= v; EM.stop} + s.notify 3 + } + assert_equal( 15, val ) + end + + # Pass multiple parameters to a spawned process. + # + def test_multiparms + val = 5 + EM.run { + s = EM.spawn {|v1,v2| val *= (v1 + v2); EM.stop} + s.notify 3,4 + } + assert_equal( 35, val ) + end + + + # This test demonstrates that a notification does not happen immediately, + # but rather is scheduled sometime after the current code path completes. + # + def test_race + x = 0 + EM.run { + s = EM.spawn {x *= 2; EM.stop} + s.notify + x = 2 + } + assert_equal( 4, x) + end + + + # Spawn a process and notify it 25 times to run fibonacci + # on a pair of global variables. + # + def test_fibonacci + x = 1 + y = 1 + EM.run { + s = EM.spawn {x,y = y,x+y} + 25.times {s.notify} + + t = EM.spawn {EM.stop} + t.notify + } + assert_equal( 121393, x) + assert_equal( 196418, y) + end + + # This one spawns 25 distinct processes, and notifies each one once, + # rather than notifying a single process 25 times. + # + def test_another_fibonacci + x = 1 + y = 1 + EM.run { + 25.times { + s = EM.spawn {x,y = y,x+y} + s.notify + } + + t = EM.spawn {EM.stop} + t.notify + } + assert_equal( 121393, x) + assert_equal( 196418, y) + end + + + # Make a chain of processes that notify each other in turn + # with intermediate fibonacci results. The final process in + # the chain stops the loop and returns the result. + # + def test_fibonacci_chain + a,b = nil + + EM.run { + nextpid = EM.spawn {|x,y| + a,b = x,y + EM.stop + } + + 25.times { + n = nextpid + nextpid = EM.spawn {|x,y| n.notify( y, x+y )} + } + + nextpid.notify( 1, 1 ) + } + + assert_equal( 121393, a) + assert_equal( 196418, b) + end + + + # EM#yield gives a spawed process to yield control to other processes + # (in other words, to stop running), and to specify a different code block + # that will run on its next notification. + # + def test_yield + a = 0 + EM.run { + n = EM.spawn { + a += 10 + EM.yield { + a += 20 + EM.yield { + a += 30 + EM.stop + } + } + } + n.notify + n.notify + n.notify + } + assert_equal( 60, a ) + end + + # EM#yield_and_notify behaves like EM#yield, except that it also notifies the + # yielding process. This may sound trivial, since the yield block will run very + # shortly after with no action by the program, but this actually can be very useful, + # because it causes the reactor core to execute once before the yielding process + # gets control back. So it can be used to allow heavily-used network connections + # to clear buffers, or allow other processes to process their notifications. + # + # Notice in this test code that only a simple notify is needed at the bottom + # of the initial block. Even so, all of the yielded blocks will execute. + # + def test_yield_and_notify + a = 0 + EM.run { + n = EM.spawn { + a += 10 + EM.yield_and_notify { + a += 20 + EM.yield_and_notify { + a += 30 + EM.stop + } + } + } + n.notify + } + assert_equal( 60, a ) + end + + # resume is an alias for notify. + # + def test_resume + EM.run { + n = EM.spawn {EM.stop} + n.resume + } + assert true + end + + # run is an idiomatic alias for notify. + # + def test_run + EM.run { + (EM.spawn {EM.stop}).run + } + assert true + end + + + # Clones the ping-pong example from the Erlang tutorial, in much less code. + # Illustrates that a spawned block executes in the context of a SpawnableObject. + # (Meaning, we can pass self as a parameter to another process that can then + # notify us.) + # + def test_ping_pong + n_pongs = 0 + EM.run { + pong = EM.spawn {|x, ping| + n_pongs += 1 + ping.notify( x-1 ) + } + ping = EM.spawn {|x| + if x > 0 + pong.notify x, self + else + EM.stop + end + } + ping.notify 3 + } + assert_equal( 3, n_pongs ) + end + + # Illustrates that you can call notify inside a notification, and it will cause + # the currently-executing process to be re-notified. Of course, the new notification + # won't run until sometime after the current one completes. + # + def test_self_notify + n = 0 + EM.run { + pid = EM.spawn {|x| + if x > 0 + n += x + notify( x-1 ) + else + EM.stop + end + } + pid.notify 3 + } + assert_equal( 6, n ) + end + + + # Illustrates that the block passed to #spawn executes in the context of a + # SpawnedProcess object, NOT in the local context. This can often be deceptive. + # + class BlockScopeTest + attr_reader :var + def run + # The following line correctly raises a NameError. + # The problem is that the programmer expected the spawned block to + # execute in the local context, but it doesn't. + # + # (EM.spawn { do_something }).notify ### NO! BAD! + + + + # The following line correctly passes self as a parameter to the + # notified process. + # + (EM.spawn {|obj| obj.do_something }).notify(self) + + + + # Here's another way to do it. This works because "myself" is bound + # in the local scope, unlike "self," so the spawned block sees it. + # + myself = self + (EM.spawn { myself.do_something }).notify + + + + # And we end the loop. + # This is a tangential point, but observe that #notify never blocks. + # It merely appends a message to the internal queue of a spawned process + # and returns. As it turns out, the reactor processes notifications for ALL + # spawned processes in the order that #notify is called. So there is a + # reasonable expectation that the process which stops the reactor will + # execute after the previous ones in this method. HOWEVER, this is NOT + # a documented behavior and is subject to change. + # + (EM.spawn {EM.stop}).notify + end + def do_something + @var ||= 0 + @var += 100 + end + end + + def test_block_scope + bs = BlockScopeTest.new + EM.run { + bs.run + } + assert_equal( 200, bs.var ) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_args.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_args.rb new file mode 100644 index 00000000..d337628c --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_args.rb @@ -0,0 +1,78 @@ +require "test/unit" +require 'tempfile' + +require 'em_test_helper' + +module EM + def self._set_mocks + class < priv_file) + end + assert_raises(EM::FileNotFoundException) do + conn.start_tls(:cert_chain_file => cert_file) + end + assert_raises(EM::FileNotFoundException) do + conn.start_tls(:private_key_file => priv_file, :cert_chain_file => cert_file) + end + end + + def test_tls_params_file_does_exist + priv_file = Tempfile.new('em_test') + cert_file = Tempfile.new('em_test') + priv_file_path = priv_file.path + cert_file_path = cert_file.path + conn = EM::Connection.new('foo') + params = {:private_key_file => priv_file_path, :cert_chain_file => cert_file_path} + begin + conn.start_tls params + rescue Object + assert(false, 'should not have raised an exception') + end + end +end if EM.ssl? diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_dhparam.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_dhparam.rb new file mode 100644 index 00000000..85f52d2f --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_dhparam.rb @@ -0,0 +1,84 @@ +require 'em_test_helper' + +class TestSslDhParam < Test::Unit::TestCase + def setup + $dir = File.dirname(File.expand_path(__FILE__)) + '/' + $dhparam_file = File.join($dir, 'dhparam.pem') + end + + module Client + def post_init + start_tls + end + + def ssl_handshake_completed + $client_handshake_completed = true + $client_cipher_name = get_cipher_name + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + module Server + def post_init + start_tls(:dhparam => $dhparam_file, :cipher_list => "DHE,EDH") + end + + def ssl_handshake_completed + $server_handshake_completed = true + $server_cipher_name = get_cipher_name + end + end + + module NoDhServer + def post_init + start_tls(:cipher_list => "DHE,EDH") + end + + def ssl_handshake_completed + $server_handshake_completed = true + $server_cipher_name = get_cipher_name + end + end + + def test_no_dhparam + omit_unless(EM.ssl?) + omit_if(EM.library_type == :pure_ruby) # DH will work with defaults + omit_if(rbx?) + + $client_handshake_completed, $server_handshake_completed = false, false + $server_cipher_name, $client_cipher_name = nil, nil + + EM.run { + EM.start_server("127.0.0.1", 16784, NoDhServer) + EM.connect("127.0.0.1", 16784, Client) + } + + assert(!$client_handshake_completed) + assert(!$server_handshake_completed) + end + + def test_dhparam + omit_unless(EM.ssl?) + omit_if(rbx?) + + $client_handshake_completed, $server_handshake_completed = false, false + $server_cipher_name, $client_cipher_name = nil, nil + + EM.run { + EM.start_server("127.0.0.1", 16784, Server) + EM.connect("127.0.0.1", 16784, Client) + } + + assert($client_handshake_completed) + assert($server_handshake_completed) + + assert($client_cipher_name.length > 0) + assert_equal($client_cipher_name, $server_cipher_name) + + assert_match(/^(DHE|EDH)/, $client_cipher_name) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_ecdh_curve.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_ecdh_curve.rb new file mode 100644 index 00000000..8dc167b6 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_ecdh_curve.rb @@ -0,0 +1,80 @@ +require 'em_test_helper' + +class TestSslEcdhCurve < Test::Unit::TestCase + module Client + def post_init + start_tls + end + + def ssl_handshake_completed + $client_handshake_completed = true + $client_cipher_name = get_cipher_name + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + module Server + def post_init + start_tls(:ecdh_curve => "prime256v1", :cipher_list => "ECDH") + end + + def ssl_handshake_completed + $server_handshake_completed = true + $server_cipher_name = get_cipher_name + end + end + + module NoCurveServer + def post_init + start_tls(:cipher_list => "ECDH") + end + + def ssl_handshake_completed + $server_handshake_completed = true + $server_cipher_name = get_cipher_name + end + end + + def test_no_ecdh_curve + omit_unless(EM.ssl?) + omit_if(rbx?) + + $client_handshake_completed, $server_handshake_completed = false, false + + EM.run { + EM.start_server("127.0.0.1", 16784, NoCurveServer) + EM.connect("127.0.0.1", 16784, Client) + } + + assert(!$client_handshake_completed) + assert(!$server_handshake_completed) + end + + def test_ecdh_curve + omit_unless(EM.ssl?) + omit_if(EM.library_type == :pure_ruby && RUBY_VERSION < "2.3.0") + omit_if(rbx?) + + $client_handshake_completed, $server_handshake_completed = false, false + $server_cipher_name, $client_cipher_name = nil, nil + + EM.run { + EM.start_server("127.0.0.1", 16784, Server) + EM.connect("127.0.0.1", 16784, Client) + } + + assert($client_handshake_completed) + assert($server_handshake_completed) + + assert($client_cipher_name.length > 0) + assert_equal($client_cipher_name, $server_cipher_name) + + assert_match(/^(AECDH|ECDHE)/, $client_cipher_name) + end + + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_extensions.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_extensions.rb new file mode 100644 index 00000000..0610ba88 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_extensions.rb @@ -0,0 +1,49 @@ +require 'em_test_helper' + +require 'socket' +require 'openssl' + +if EM.ssl? + class TestSslExtensions < Test::Unit::TestCase + + module Client + def ssl_handshake_completed + $client_handshake_completed = true + close_connection + end + + def unbind + EM.stop_event_loop + end + + def post_init + start_tls(:ssl_version => :tlsv1, :sni_hostname => 'example.com') + end + end + + module Server + def ssl_handshake_completed + $server_handshake_completed = true + $server_sni_hostname = get_sni_hostname + end + + def post_init + start_tls(:ssl_version => :TLSv1) + end + end + + def test_tlsext_sni_hostname + $server_handshake_completed = false + + EM.run do + EM.start_server("127.0.0.1", 16784, Server) + EM.connect("127.0.0.1", 16784, Client) + end + + assert($server_handshake_completed) + assert_equal('example.com', $server_sni_hostname) + end + end +else + warn "EM built without SSL support, skipping tests in #{__FILE__}" +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_methods.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_methods.rb new file mode 100644 index 00000000..c2e5744d --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_methods.rb @@ -0,0 +1,65 @@ +require 'em_test_helper' + +class TestSSLMethods < Test::Unit::TestCase + + module ServerHandler + def post_init + start_tls + end + + def ssl_handshake_completed + $server_called_back = true + $server_cert_value = get_peer_cert + $server_cipher_bits = get_cipher_bits + $server_cipher_name = get_cipher_name + $server_cipher_protocol = get_cipher_protocol + end + end + + module ClientHandler + def post_init + start_tls + end + + def ssl_handshake_completed + $client_called_back = true + $client_cert_value = get_peer_cert + $client_cipher_bits = get_cipher_bits + $client_cipher_name = get_cipher_name + $client_cipher_protocol = get_cipher_protocol + EM.stop_event_loop + end + end + + def test_ssl_methods + omit_unless(EM.ssl?) + omit_if(rbx?) + $server_called_back, $client_called_back = false, false + $server_cert_value, $client_cert_value = nil, nil + $server_cipher_bits, $client_cipher_bits = nil, nil + $server_cipher_name, $client_cipher_name = nil, nil + $server_cipher_protocol, $client_cipher_protocol = nil, nil + + EM.run { + EM.start_server("127.0.0.1", 9999, ServerHandler) + EM.connect("127.0.0.1", 9999, ClientHandler) + } + + assert($server_called_back) + assert($client_called_back) + + assert($server_cert_value.is_a?(NilClass)) + assert($client_cert_value.is_a?(String)) + + assert($client_cipher_bits > 0) + assert_equal($client_cipher_bits, $server_cipher_bits) + + assert($client_cipher_name.length > 0) + assert_match(/AES/, $client_cipher_name) + assert_equal($client_cipher_name, $server_cipher_name) + + assert_match(/TLS/, $client_cipher_protocol) + assert_equal($client_cipher_protocol, $server_cipher_protocol) + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_protocols.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_protocols.rb new file mode 100644 index 00000000..bcb68246 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_protocols.rb @@ -0,0 +1,246 @@ +require 'em_test_helper' + +require 'socket' +require 'openssl' + +if EM.ssl? + class TestSslProtocols < Test::Unit::TestCase + + module Client + def ssl_handshake_completed + $client_handshake_completed = true + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + module Server + def ssl_handshake_completed + $server_handshake_completed = true + end + end + + module ClientAny + include Client + def post_init + start_tls(:ssl_version => %w(sslv2 sslv3 tlsv1 tlsv1_1 tlsv1_2)) + end + end + + module ClientDefault + include Client + def post_init + start_tls + end + end + + module ClientSSLv3 + include Client + def post_init + start_tls(:ssl_version => %w(SSLv3)) + end + end + + module ServerSSLv3 + include Server + def post_init + start_tls(:ssl_version => %w(SSLv3)) + end + end + + module ServerTLSv1CaseInsensitive + include Server + def post_init + start_tls(:ssl_version => %w(tlsv1)) + end + end + + module ServerAny + include Server + def post_init + start_tls(:ssl_version => %w(sslv2 sslv3 tlsv1 tlsv1_1 tlsv1_2)) + end + end + + module ServerDefault + include Server + def post_init + start_tls + end + end + + module InvalidProtocol + include Client + def post_init + start_tls(:ssl_version => %w(tlsv1 badinput)) + end + end + + def test_invalid_ssl_version + assert_raises(RuntimeError, "Unrecognized SSL/TLS Version: badinput") do + EM.run do + EM.start_server("127.0.0.1", 16784, InvalidProtocol) + EM.connect("127.0.0.1", 16784, InvalidProtocol) + end + end + end + + def test_any_to_v3 + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerSSLv3) + EM.connect("127.0.0.1", 16784, ClientAny) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_case_insensitivity + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerTLSv1CaseInsensitive) + EM.connect("127.0.0.1", 16784, ClientAny) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_v3_to_any + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerAny) + EM.connect("127.0.0.1", 16784, ClientSSLv3) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_v3_to_v3 + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerSSLv3) + EM.connect("127.0.0.1", 16784, ClientSSLv3) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_any_to_any + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerAny) + EM.connect("127.0.0.1", 16784, ClientAny) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_default_to_default + $client_handshake_completed, $server_handshake_completed = false, false + EM.run do + EM.start_server("127.0.0.1", 16784, ServerDefault) + EM.connect("127.0.0.1", 16784, ClientDefault) + end + + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + module ServerV3StopAfterHandshake + def post_init + start_tls(:ssl_version => %w(SSLv3)) + end + + def ssl_handshake_completed + $server_handshake_completed = true + EM.stop_event_loop + end + end + + module ServerTLSv1StopAfterHandshake + def post_init + start_tls(:ssl_version => %w(TLSv1)) + end + + def ssl_handshake_completed + $server_handshake_completed = true + EM.stop_event_loop + end + end + + def test_v3_with_external_client + $server_handshake_completed = false + EM.run do + setup_timeout(2) + EM.start_server("127.0.0.1", 16784, ServerV3StopAfterHandshake) + EM.defer do + sock = TCPSocket.new("127.0.0.1", 16784) + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :SSLv3_client + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.connect + ssl.close rescue nil + sock.close rescue nil + end + end + + assert($server_handshake_completed) + end + + def test_tlsv1_with_external_client + $server_handshake_completed = false + EM.run do + setup_timeout(2) + EM.start_server("127.0.0.1", 16784, ServerTLSv1StopAfterHandshake) + EM.defer do + sock = TCPSocket.new("127.0.0.1", 16784) + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_client + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.connect + ssl.close rescue nil + sock.close rescue nil + end + end + + assert($server_handshake_completed) + end + + def test_tlsv1_required_with_external_client + $server_handshake_completed = false + + EM.run do + n = 0 + EM.add_periodic_timer(0.5) do + n += 1 + (EM.stop rescue nil) if n == 2 + end + EM.start_server("127.0.0.1", 16784, ServerTLSv1StopAfterHandshake) + EM.defer do + sock = TCPSocket.new("127.0.0.1", 16784) + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :SSLv3_client + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + assert_raise OpenSSL::SSL::SSLError do + ssl.connect + end + ssl.close rescue nil + sock.close rescue nil + EM.stop rescue nil + end + end + + assert(!$server_handshake_completed) + end + end +else + warn "EM built without SSL support, skipping tests in #{__FILE__}" +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ssl_verify.rb b/bin/gems/eventmachine-1.2.7/tests/test_ssl_verify.rb new file mode 100644 index 00000000..a6d8fca7 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ssl_verify.rb @@ -0,0 +1,128 @@ +require 'em_test_helper' + +class TestSslVerify < Test::Unit::TestCase + def setup + $dir = File.dirname(File.expand_path(__FILE__)) + '/' + $cert_from_file = File.read($dir+'client.crt') + end + + module ClientNoCert + def connection_completed + start_tls() + end + + def ssl_handshake_completed + $client_handshake_completed = true + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + module Client + def connection_completed + start_tls(:private_key_file => $dir+'client.key', :cert_chain_file => $dir+'client.crt') + end + + def ssl_handshake_completed + $client_handshake_completed = true + close_connection + end + + def unbind + EM.stop_event_loop + end + end + + module AcceptServer + def post_init + start_tls(:verify_peer => true) + end + + def ssl_verify_peer(cert) + $cert_from_server = cert + true + end + + def ssl_handshake_completed + $server_handshake_completed = true + end + end + + module DenyServer + def post_init + start_tls(:verify_peer => true) + end + + def ssl_verify_peer(cert) + $cert_from_server = cert + # Do not accept the peer. This should now cause the connection to shut down without the SSL handshake being completed. + false + end + + def ssl_handshake_completed + $server_handshake_completed = true + end + end + + module FailServerNoPeerCert + def post_init + start_tls(:verify_peer => true, :fail_if_no_peer_cert => true) + end + + def ssl_verify_peer(cert) + raise "Verify peer should not get called for a client without a certificate" + end + + def ssl_handshake_completed + $server_handshake_completed = true + end + end + + def test_fail_no_peer_cert + omit_unless(EM.ssl?) + omit_if(rbx?) + + $client_handshake_completed, $server_handshake_completed = false, false + + EM.run { + EM.start_server("127.0.0.1", 16784, FailServerNoPeerCert) + EM.connect("127.0.0.1", 16784, ClientNoCert) + } + + assert(!$client_handshake_completed) + assert(!$server_handshake_completed) + end + + def test_accept_server + omit_unless(EM.ssl?) + omit_if(EM.library_type == :pure_ruby) # Server has a default cert chain + omit_if(rbx?) + $client_handshake_completed, $server_handshake_completed = false, false + EM.run { + EM.start_server("127.0.0.1", 16784, AcceptServer) + EM.connect("127.0.0.1", 16784, Client).instance_variable_get("@signature") + } + + assert_equal($cert_from_file, $cert_from_server) + assert($client_handshake_completed) + assert($server_handshake_completed) + end + + def test_deny_server + omit_unless(EM.ssl?) + omit_if(EM.library_type == :pure_ruby) # Server has a default cert chain + omit_if(rbx?) + $client_handshake_completed, $server_handshake_completed = false, false + EM.run { + EM.start_server("127.0.0.1", 16784, DenyServer) + EM.connect("127.0.0.1", 16784, Client) + } + + assert_equal($cert_from_file, $cert_from_server) + assert(!$client_handshake_completed) + assert(!$server_handshake_completed) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_stomp.rb b/bin/gems/eventmachine-1.2.7/tests/test_stomp.rb new file mode 100644 index 00000000..53c0502a --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_stomp.rb @@ -0,0 +1,38 @@ +require 'em_test_helper' + +class TestStomp < Test::Unit::TestCase + CONTENT_LENGTH_REGEX = /^content-length: (\d+)$/ + + def bytesize(str) + str = str.to_s + size = str.bytesize if str.respond_to?(:bytesize) # bytesize added in 1.9 + size || str.size + end + + class TStomp + include EM::P::Stomp + + def last_sent_content_length + @sent && Integer(@sent[CONTENT_LENGTH_REGEX, 1]) + end + + def send_data(string) + @sent = string + end + end + + def test_content_length_in_bytes + connection = TStomp.new + + queue = "queue" + failure_message = "header content-length is not the byte size of last sent body" + + body = "test" + connection.send queue, body + assert_equal bytesize(body), connection.last_sent_content_length, failure_message + + body = "test\u221A" + connection.send queue, body + assert_equal bytesize(body), connection.last_sent_content_length, failure_message + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_system.rb b/bin/gems/eventmachine-1.2.7/tests/test_system.rb new file mode 100644 index 00000000..fbbe2c9e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_system.rb @@ -0,0 +1,46 @@ +# coding: utf-8 +require 'em_test_helper' + +class TestSystem < Test::Unit::TestCase + def setup + @filename = File.expand_path("../я манал dump.txt", __FILE__) + @test_data = 'a' * 100 + File.open(@filename, 'w'){|f| f.write(@test_data)} + end + + def test_system + omit_if(windows?) + + result = nil + status = nil + EM.run { + EM.system('cat', @filename){|out, state| + result = out + status = state.exitstatus + EM.stop + } + } + assert_equal(0, status) + assert_equal(@test_data, result) + end + + def test_system_with_string + omit_if(windows?) + + result = nil + status = nil + EM.run { + EM.system("cat '#@filename'"){|out, state| + result = out + status = state.exitstatus + EM.stop + } + } + assert_equal(0, status) + assert_equal(@test_data, result) + end + + def teardown + File.unlink(@filename) + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_threaded_resource.rb b/bin/gems/eventmachine-1.2.7/tests/test_threaded_resource.rb new file mode 100644 index 00000000..9bb39c6e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_threaded_resource.rb @@ -0,0 +1,63 @@ +require 'em_test_helper' + +class TestThreadedResource < Test::Unit::TestCase + def object + @object ||= {} + end + + def resource + @resource = EM::ThreadedResource.new do + object + end + end + + def teardown + resource.shutdown + end + + def test_dispatch_completion + EM.run do + EM.add_timer(3) do + EM.stop + fail 'Resource dispatch timed out' + end + completion = resource.dispatch do |o| + o[:foo] = :bar + :foo + end + completion.callback do |result| + assert_equal :foo, result + EM.stop + end + completion.errback do |error| + EM.stop + fail "Unexpected error: #{error.message}" + end + end + assert_equal :bar, object[:foo] + end + + def test_dispatch_failure + completion = resource.dispatch do |o| + raise 'boom' + end + completion.errback do |error| + assert_kind_of RuntimeError, error + assert_equal 'boom', error.message + end + end + + def test_dispatch_threading + main = Thread.current + resource.dispatch do |o| + o[:dispatch_thread] = Thread.current + end + assert_not_equal main, object[:dispatch_thread] + end + + def test_shutdown + # This test should get improved sometime. The method returning thread is + # NOT an api that will be maintained. + assert !resource.shutdown.alive? + end +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_tick_loop.rb b/bin/gems/eventmachine-1.2.7/tests/test_tick_loop.rb new file mode 100644 index 00000000..39d86b54 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_tick_loop.rb @@ -0,0 +1,59 @@ +require "test/unit" +require 'em_test_helper' + +class TestEmTickLoop < Test::Unit::TestCase + def test_em_tick_loop + i = 0 + EM.tick_loop { i += 1; EM.stop if i == 10 } + EM.run { EM.add_timer(1) { EM.stop } } + assert_equal i, 10 + end + + def test_tick_loop_on_stop + t = nil + tick_loop = EM.tick_loop { :stop } + tick_loop.on_stop { t = true } + EM.run { EM.next_tick { EM.stop } } + assert t + end + + def test_start_twice + i = 0 + s = 0 + tick_loop = EM.tick_loop { i += 1; :stop } + tick_loop.on_stop { s += 1; EM.stop } + EM.run { EM.next_tick { EM.stop } } + assert_equal 1, i + assert_equal 1, s + tick_loop.start + EM.run { EM.next_tick { EM.stop } } + assert_equal 2, i + assert_equal 1, s # stop callbacks are only called once + end + + def test_stop + i, s = 0, 0 + tick_loop = EM.tick_loop { i += 1 } + tick_loop.on_stop { s += 1 } + EM.run { EM.next_tick { tick_loop.stop; EM.next_tick { EM.stop } } } + assert tick_loop.stopped? + assert_equal 1, i + assert_equal 1, s + end + + def test_immediate_stops + s = 0 + tick_loop = EM::TickLoop.new { } + tick_loop.on_stop { s += 1 } + tick_loop.on_stop { s += 1 } + assert_equal 2, s + end + + def test_stopped + tick_loop = EM::TickLoop.new { } + assert tick_loop.stopped? + tick_loop.start + assert !tick_loop.stopped? + end + +end \ No newline at end of file diff --git a/bin/gems/eventmachine-1.2.7/tests/test_timers.rb b/bin/gems/eventmachine-1.2.7/tests/test_timers.rb new file mode 100644 index 00000000..88b3b781 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_timers.rb @@ -0,0 +1,130 @@ +require 'em_test_helper' + +class TestTimers < Test::Unit::TestCase + + def test_timer_with_block + x = false + EM.run { + EM::Timer.new(0) { + x = true + EM.stop + } + } + assert x + end + + def test_timer_with_proc + x = false + EM.run { + EM::Timer.new(0, proc { + x = true + EM.stop + }) + } + assert x + end + + def test_timer_cancel + assert_nothing_raised do + EM.run { + timer = EM::Timer.new(0.01) { flunk "Timer was not cancelled." } + timer.cancel + + EM.add_timer(0.02) { EM.stop } + } + end + end + + def test_periodic_timer + x = 0 + EM.run { + EM::PeriodicTimer.new(0.01) do + x += 1 + EM.stop if x == 4 + end + } + + assert_equal 4, x + end + + def test_add_periodic_timer + x = 0 + EM.run { + t = EM.add_periodic_timer(0.01) do + x += 1 + EM.stop if x == 4 + end + assert t.respond_to?(:cancel) + } + assert_equal 4, x + end + + def test_periodic_timer_cancel + x = 0 + EM.run { + pt = EM::PeriodicTimer.new(0.01) { x += 1 } + pt.cancel + EM::Timer.new(0.02) { EM.stop } + } + assert_equal 0, x + end + + def test_add_periodic_timer_cancel + x = 0 + EM.run { + pt = EM.add_periodic_timer(0.01) { x += 1 } + EM.cancel_timer(pt) + EM.add_timer(0.02) { EM.stop } + } + assert_equal 0, x + end + + def test_periodic_timer_self_cancel + x = 0 + EM.run { + pt = EM::PeriodicTimer.new(0) { + x += 1 + if x == 4 + pt.cancel + EM.stop + end + } + } + assert_equal 4, x + end + + def test_oneshot_timer_large_future_value + large_value = 11948602000 + EM.run { + EM.add_timer(large_value) { EM.stop } + EM.add_timer(0.02) { EM.stop } + } + end + + # This test is only applicable to compiled versions of the reactor. + # Pure ruby and java versions have no built-in limit on the number of outstanding timers. + unless [:pure_ruby, :java].include? EM.library_type + def test_timer_change_max_outstanding + defaults = EM.get_max_timers + EM.set_max_timers(100) + + one_hundred_one_timers = lambda do + 101.times { EM.add_timer(0.01) {} } + EM.stop + end + + assert_raises(RuntimeError) do + EM.run( &one_hundred_one_timers ) + end + + EM.set_max_timers( 101 ) + + assert_nothing_raised do + EM.run( &one_hundred_one_timers ) + end + ensure + EM.set_max_timers(defaults) + end + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_ud.rb b/bin/gems/eventmachine-1.2.7/tests/test_ud.rb new file mode 100644 index 00000000..3559756e --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_ud.rb @@ -0,0 +1,8 @@ +require 'em_test_helper' + +class TestUserDefinedEvents < Test::Unit::TestCase + + def test_a + end + +end diff --git a/bin/gems/eventmachine-1.2.7/tests/test_unbind_reason.rb b/bin/gems/eventmachine-1.2.7/tests/test_unbind_reason.rb new file mode 100644 index 00000000..ff9193e0 --- /dev/null +++ b/bin/gems/eventmachine-1.2.7/tests/test_unbind_reason.rb @@ -0,0 +1,40 @@ +require 'em_test_helper' + +class TestUnbindReason < Test::Unit::TestCase + + class StubConnection < EM::Connection + attr_reader :error + def unbind(reason = nil) + @error = reason + EM.stop + end + end + + # RFC 5737 Address Blocks Reserved for Documentation + def test_connect_timeout + conn = nil + EM.run do + conn = EM.connect '192.0.2.0', 80, StubConnection + conn.pending_connect_timeout = 1 + end + assert_equal Errno::ETIMEDOUT, conn.error + end + + def test_connect_refused + pend('FIXME: this test is broken on Windows') if windows? + conn = nil + EM.run do + conn = EM.connect '127.0.0.1', 12388, StubConnection + end + assert_equal Errno::ECONNREFUSED, conn.error + end + + def test_optional_argument + pend('FIXME: this test is broken on Windows') if windows? + conn = nil + EM.run do + conn = EM.connect '127.0.0.1', 12388, StubConnection + end + assert_equal Errno::ECONNREFUSED, conn.error + end +end diff --git a/bin/gems/facets-3.1.0/.index b/bin/gems/facets-3.1.0/.index new file mode 100644 index 00000000..b935324c --- /dev/null +++ b/bin/gems/facets-3.1.0/.index @@ -0,0 +1,80 @@ +--- +revision: 2013 +type: ruby +sources: +- Indexfile +- Gemfile +authors: +- name: Thomas Sawyer + email: transfire@gmail.com +organizations: +- name: Rubyworks +requirements: +- groups: + - test + version: ">= 0" + name: lemon +- groups: + - test + version: ">= 0" + name: qed +- groups: + - test + version: ">= 0" + name: rubytest-cli +- groups: + - test + version: ">= 0" + name: rake +- groups: + - test + version: ">= 0" + name: simplecov +- groups: + - guard + version: ">= 0" + name: guard +conflicts: [] +alternatives: [] +resources: +- type: home + uri: http://rubyworks.github.com/facets + label: Homepage +- type: code + uri: http://github.com/rubyworks/facets + label: Source Code +- type: docs + uri: http://rubyworks.github.com/facets/learn.html + label: Documentation +- type: wiki + uri: http://wiki.github.com/rubyworks/facets + label: User Guide +- type: talk + uri: http://groups.google.com/group/facets-universal +repositories: +- name: upstream + scm: git + uri: git@github.com:rubyworks/facets.git +categories: [] +copyrights: +- holder: Rubyworks + year: '2004' + license: BSD-2-Clause +customs: [] +paths: + load: + - lib/core + - lib/standard +name: facets +title: Ruby Facets +version: 3.1.0 +summary: The orginal well curated collection of extension methods for Ruby. +slogan: ALL YOUR BASE ARE BELONG TO RUBY! +description: Facets is the premier collection of extension methods for the Ruby programming + language. Facets extensions are unique by virtue of thier atomicity. They are stored + in individual files allowing for highly granular control of requirements. In addition, + Facets includes a few additional classes and mixins suitable to wide variety of + applications. +scm_uri: https://github.com/rubyworks/facets/tree/master +created: '2004-12-16' +date: '2016-05-09' diff --git a/bin/gems/facets-3.1.0/.yardopts b/bin/gems/facets-3.1.0/.yardopts new file mode 100644 index 00000000..e786e852 --- /dev/null +++ b/bin/gems/facets-3.1.0/.yardopts @@ -0,0 +1,10 @@ +--title "Ruby Facets" +--readme README.rdoc +--protected +--private +--tag uncommon:Uncommon +--tag standard:Standard +lib/core +lib/standard +- +[A-Z]*.* diff --git a/bin/gems/facets-3.1.0/CONTRIBUTING.md b/bin/gems/facets-3.1.0/CONTRIBUTING.md new file mode 100644 index 00000000..77a1faa4 --- /dev/null +++ b/bin/gems/facets-3.1.0/CONTRIBUTING.md @@ -0,0 +1,112 @@ +# CONTRIBUTING TO FACETS + +## General Rules + +* Facets methods must have no external dependencies. (The only possible + exception to this is if the functor gets spun-off as a separate gem along + with related methods, but for now that hasn't happened.) + +* Each method must be in it's own file of the same name. If the method ends + with `=` or `?` just leave it off the file name. + +* On rare occasion two or more methods can be very tightly related. In these + cases the methods can all go in a single file under the name of the method + considered most significant. Usually files for the other methods should + still be created that simply require the main file. + +* Methods must be tested both via a Lemon unit test and as a QED demo. + The Lemon unit tests are for testing a method in detail whereas the QED + demos are for demonstrating usage. + +* Facets is divided into two parts, *core* and *standard* libraries. + Almost all of the core library can be loaded at once using `require 'facets'` + The standard library (also called the *more* library) must be required + per-script. + +* Some core methods are included on a *trial* basis, and these are not + necessary loaded automatically with `require 'facets'`. These should be + documented as such in the method comments. + +* Standard libraries that are not extensions of existing standard libraries + do not have to be divvied up into individual method files. But note that + full classes and/or modules are less likely to make it into Facets, as + these sorts of additions to Facets are only for very basic sorts of things. + Otherwise they'd deserve their own gem. + +* When submitting new methods for consideration, it is best if each method + (or *tightly related* set of methods) is in it's own pull request. If you + have only one method to submit then a simple commit will do the trick. If + you have more than one it best to use separate branches. Let me emphasizes + this point because it makes it *much more likely* that your pull request + will be merged. If you submit a bunch of methods in a single pull request, + it is very likely that it will not be merged even if methods you submitted + are accepted!!! + +* Don't be discouraged when you get feedback about a method that isn't + all sunshine and roses. Facets has been around long enough now that + it needs to maintain a certain degree of quality control, and that means + serious discernment about what goes into the library. That includes + having in depth discussions the merits of methods, even about the best + name for a method --even if the functionality has been accepted the name + may not. + + +## Versioning + +Facets tries to follow a semantic versioning system, but with a slightly +differt scheme than most projects. For Facets the version number represents: + + gestault.major.minor + +Techinically there can be a fouth `build` number, but we never use it for +releases. + + +## Commit Tags + +When making a commit, it is helpful to add a *commit tag* to the end of the +first line of commit message. Commit tags are single words wrapped in colons. + +* If the commit is only a documentation change, then and `:doc:`. +* If it is only a change to tests then add `:test:`. +* If the change only effects project build or config files then add `:admin:`. +* If the change fixes a bug that was reported via the issue system be sure + to reference the issue number in the message using `#` and add a `:bug:` tag. +* For actual code changes, if the change is *very minor* and not something + anyone would notice, you can use `:tweak:`, if you want. +* If the change would require a minor version change than use `:minor:`. +* But if a change is a significant change to the API, and thus will require + a major version change, then end the message with `:major:`. + +These are all rules of thumb, and no one expects them to be applied perfectly. + + +## Documentation + +Facets started when the only choice for API documentation was RDoc. So originally +that's how methods were documented. Since then both YARD and Tomdoc have come +along. And some of these documentation styles have crept into a number of +methods. So right now, things are a bit messy. But going forward it looks like we +are going to settle on Tomdoc as the official documentation style (but using +the tomparse gem's extensions). Using Tomdoc will give us reasonable +interoperability with both RDoc and YARD, both of which now have support for +Tomdoc (albeit support is not 100% the same, but hopefully it's close enough). + +Officially we publish documentation via rubydoc.info, which is the YARD server, +and via the Facets website in Shomen JSON format. + +When writing documentation for a method it is best to give a simple summary +explanation, followed by some basic examples. Follow that up with deeper +explanation if needed, including *when* and *why* the method could be useful. + + +## Testing + +* Methods in `lib/core/facets/{class}/{method}.rb` will be tested in `test/foo/{class}/test_{method}.rb`. +* If `lib/core/facets/{class}/{method}.rb` consists only of a require statement, no test file is expected. +* If `lib/core/facets/{class}/{method}.rb` consists only of a require and an alias, then `test/foo/{class}/{method}.rb`, only needs to test the existence of the alias and not the underlying code. But it's okay if the alias is tested further. +* Methods in `lib/core/facets/{class}/{method}.rb` will be demoed in `demo/core/{class}/{method}.md`. +* Require only files will have a full demo of it's method or methods. Code in a single file may be split into multiple demos, named after the method. This is to promote discoverability in the documentation. +* Demos of aliases will have a simple demo, and a reference to the file it aliases + + diff --git a/bin/gems/facets-3.1.0/HISTORY.md b/bin/gems/facets-3.1.0/HISTORY.md new file mode 100644 index 00000000..f86d186a --- /dev/null +++ b/bin/gems/facets-3.1.0/HISTORY.md @@ -0,0 +1,2497 @@ +# Facets Release History + +## 3.1.0 / 2016-05-10 + +More or less a minor release, but there are some backward incompatabilites +such as `Hash#except!` which no longer returns the rejected entries (use +`Hash#remove!` for old behavior). + +Special thanks to Scott Parrish for all his help getting Facets in tip-top +shape. + +Changes: + +* New Features + + * Add `Hash#remove!` for old `except!` behavior. + * Add `Array#standard_deviation`. + * Add `Array#variance`. + * Add `Array#average`. + * Add `Numeric#delimit`. + +* Improved Features + + * Change `Hash#except!` to not return rejected entries. + * Improve definition of Character Set in `String.random`. + * Add one to denominator of `String#similarity` score. + * Enhanced download methods. + * Improvements on compatability with ActiveSupport. + * Enumerable#from and #thru return empty set when index is out of bounds. + +* Bug Fixes + + * Fix `Enumerable#key_by`. + * Fix `Enumerable#sum` to take initial value. + + +## 3.0.0 / 2014-11-11 + +This major release has been a long time in coming --too long in fact. As with +any "Point Oh" release, please expect a few hiccups and report them so we can +get a solid 3.1 release out as soon as possible. + +This release is tailored for Ruby 2.0 and above. Ruby 1.9.x and older is no +longer supported. If you still need to use Facets with Ruby 1.9.x or older +then the excellent Backports project can be used to fill in the gaps. + +Changes: + +* New Features + + * Add Array#arrange + * Add Array#intersection + * Add Array#missing + * Add Array#uniqe_permutation + * Add Dir.lookup method + * Add Enumerator::Lazy#squeeze + * Add Hash#fetch_nested + * Add Hash#deep_rekey and Hash#deep_rekey! + * Add Kernel#instance_extract + * Add Math#EC for Euler's constant + * Add Module#alias_class_method + * Add Pathname#chdir + * Add Pathname#readline + * Add Proc.wrap (may become `Kernel#Proc()`) + * Add Range#- and Range#+ + * Add Regexp#to_proc + * Add String#each_match as alias for #mscan + * Add Time.current + +* Improved Features + + * Enumerable#sum argument is initial value. + * Generalize Enumerable#sum to duck-type on `#+`. + * Hash#collate can take multiple arguments. + * Hash#collate no longer flattens automatically. + * Time#past? and #future? use Time.current. + * Better ActiveSupport compatibility. + +* Renamed Features + + * Rename Object#replace to Object#instance_replace. + * Rename Range#to_r to Range#to_rng, since #to_r is now for Rational. + * Rename Kernel#eigen to #meta. + +* Bug Fixes + + * Fix Platform#inspect. + +* Deprecated Features Now in Ruby + + * Deprecate Array#combination (now in Ruby). + * Deprecate Array#index (now in Ruby). + * Deprecate Array#permutation (now in Ruby). + * Deprecate Array#product (now in Ruby). + * Deprecate Array#rotate (now in Ruby). + * Deprecate Array#rotate! (now in Ruby). + * Deprecate Array#select! (now in Ruby). + * Deprecate Binding#eval (now in Ruby). + * Deprecate Float#round_at (now in Ruby as #round). + * Deprecate Hash#select! (now in Ruby). + * Deprecate Integer#even? (now in Ruby). + * Deprecate Integer#odd? (now in Ruby). + * Deprecate Kernel#__callee__ (now in Ruby). + * Deprecate Kernel#__method__ (now in Ruby). + * Deprecate Kernel#source_location (now in Ruby). + * Deprecate NilClass#to_f (now in Ruby). + * Deprecate NilClass#to_h (now in Ruby). + * Deprecate Numeric#round_at (now in Ruby as #round). + * Deprecate Proc#curry (now in Ruby). + * Deprecate String#bytes (now in Ruby). + * Deprecate String#each_char (now in Ruby). + * Deprecate String#end_with (now in Ruby). + * Deprecate String#lines (now in Ruby). + * Deprecate String#start_with (now in Ruby). + * Deprecate Symbol#to_proc (now in Ruby). + * Deprecate UnboundMethod#name (now in Ruby). + + +## 2.9.3 / 2011-12-31 + +Happy New Year! Ruby Facets kicks off the year with a 2.9.x release. +This release adds a number of new methods, a few general improvements +and bug fixes, a couple of deprecations and finally settles the +project down to a two-part core/standard project organization. + +Changes: + +* New Features + + * Add Hash#url_params. (Matt Kirk) + * Add Enumerable#hashify. (Ronen Barzel) + * Add String#briefcase, similar to #titlecase. + * Add Kernel#hierarchical_send (better replacement for preinitialize.rb). + * Add Class#hierarchically, which supports #hierarchical_send. + * Add Array#median, to get the sorted middle of an array. + * Add Math#percentile and Math#median. + * Add Instantiable mixin (returns from Mixers spin-off project). + * Add Equitable mixin (returns from Mixers spin-off project). + * Add Cloneable mixin (returns from Mixers spin-off project). + * Add Array#each_pair and #each_value. + * Add Numeric#positive? and #numeric?. + * Add Method#* and #^ composition methods. (Mike Burns) + * Add back Fixnum::MAX and MIN constants. + * Add Binding#with. + +* Improved Features + + * Improve FileUtils#amass to be more robust. + * Improve String#snakecase to convert spaces to underscores. + * Improve String#camelcase to convert spaces to "camels". + * Improve String#snakecase to not handle path names (use #pathize). + * Improve String#camelcase to not handle module names (ise #modulize). + * Improve Numeric#approx? bu using ratio. + +* Renamed Features + + * Rename Enumerable#has? to #incase?. + +* Bug Fixes + + * Fix Hash#rekey to keep default_proc. + * Fix Binding#self to not be defined for Rubinius. + +* Deprecations + + * Deprecate Preinitializable mixin. + * Deprecate main.rb, spun-off to `main_like_module` gem. + +* Implementation Details + + * Reconsolidated library into just two parts, `core` and `standard`. + * The term "more" is just a synonym for "standard" now. + * Relative requires are being used more extensively. + * Collection scripts, e.g. `require 'facets'`, are static. + + +## 2.9.2 / 2011-08-23 + +The main purpose of this release is a fix for Module#redefine_method, +so it will not conflict with ActiveSupport. Beyond that a handful of new +methods have been added. This release also marks the start of using +a src/ directory to generate the lib/ directory. + +Changes: + +* New Features + + * Add Enumerable#map_with and alias #zip_map. + * Hash#delete_values returns removed keys (#12). + * Add clap-like command-line parser to Shellwords. + * Add Module#let, akin to RSpec's method. + * Add uncommon Module#method_clash method. + * Add uncommon Class#singleton? method. + +* Bug Fixes + + * Fix Module#redefine_method to use #remove_method. + * Fix Kernel#object_hexid, or at least try to do so again. + * Fix Exception#detail to not return backtrace if nil. + + +## 2.9.1 / 2011-01-30 + +Primarily this release fixes a couple of small issues. But also a handful of +new methods have been added. + +Changes: + +* New Features: + + * Add FileTest#absolute? and #relative? + * Add FileTest#contains? + * Add FileTest#safe? + * Add FileUtils#amass + * Add FileUtils#outofdate + * Add FileUtils#stage + * Add Kernel#yes? and Kernel#no? + * Add Enumerable#has? (TOUR library) + * Add Digest#salted_digest, etc. + * Add Digest#base64digest (1.9.2 method) + * Add String#random_binary + +* Improved Features + + * Better OS detection in Platform class and RBConfig module + * Moved CPU byte order methods from RBConfig to Platform class + * General improvements to Platform class API + +* Bug Fixes + + * Module#redefine_method need not check pre-existence of method + * Fix string/unquote.rb recursive require + * Kernel#object_hexid varies on CPU arch, not Ruby version. + + +## 2.9.0 / 2010-09-01 + +This release is fairly extensive as it was originally intended to be v3.0. +After further consideration it was decided to reserve v3.0 for the +polish of real world feedback and more progressive changes. The primary +focus of this release has been the completion of migrating Facets into a true +extensions library. With this release almost all add-on classes and mixins +have now been spun-off to other projects. Only the most general purposes +add-on classes and mixins remain. + +A new TOUR library division has also been added to complement CORE and MORE. +This division houses purely optional extensions. The new division serves +a couple of useful purposes. In particular, it helps separates the standard +library extensions from optional core extension in the RDocs and thus makes +the perfect place to vet new extension ideas. + +One important change that will effect anyone using Facets along side +ActiveSupport is that Facets no longer tries to conditionally avoid +method overlaps with ActiveSupport. This is fine for the upcoming +ActiveSupport 3.0 library which extends core classes directly instead of +using mixins. One need only require 'facets' in the Rails config/preinitializer.rb +file and ActiveSupport will take precedence over Facets. For older versions +of ActiveSupport, the best approach is to cherry pick from Facets just the +extensions you want, thus avoiding any conflicts. There are actually only a +dozen or so overlaps and all are intended to compatible, but it doesn't hurt +to be sure. + +Lastly, it is worth mentioning that this release has been more thuroughly +tested than any version of Facets to date. Thanks to RVM this release runs +green on Ruby 1.8.6, 1.8.7 and 1.9.2. + +Changes: + +* New Features + + * Add Kernel#temporarily, set variables temporarily and eval block + * Add Kernel#deep_clone, a better alternative to #deep_copy + * Add Kernel#present? and Kernel#presence + * Add Kernel#not and #not? + * Add Array#extract_options!, for pulling options off argument list + * Add Regexp#|, operator for Regexp#union + * Add Array#percentile and Array#median + * Add Module#memo, for instance level memoization + * Add YAML.read method + * Add Pathname#include? + * Add Module#anonymous? + * Add Module#copy_inheritor + * Add Indexable#from and Indexable#upto + * Add Array#from and Array#thru + * Add NA class via na.rb + * Add Memoizable in memoizable.rb for a more robust memoization system + * Add Module#safe_memo in thread.rb for thread safe memoization + * Add Kernel#sandbox in thread.rb for threaded $SAFE=4 evaluation + * Add Hash#subset + * Add Kernel#Y to tour library + * Add numerous Math extensions + +* Deprecations + + * Deprecate Module#attr_toggler as a YAGNI + * Deprecate Kernel#class_eval b/c of it's confusing behavior + * Deprecate Module#once is no longer an alias for #memoize + * Deprecate Integer#succ(n) (for compatibility reasons) + * Deprecate Stackable, it's method were moved to CORE + * Deprecate Kernel#populate and #set_from (use #assign and #assign_from) + * Deprecate Kernel#non_nil? since #not_nil? is enough + * Deprecate #__HERE__ b/c implementation was unreliable + * Deprecate Time#since, use #less instead + * Deprecate Time#advance, use #shift instead + * Deprecate Kernel#super_as (no good way to get callers method name) + * Deprecate Integer#clear_bit, use #bit_clear instead + * Deprecate Kernel#resc, use String#to_re or #to_rx instead + * Deprecate Module#modspace + * Deprecate Kernel#__ and class X for Proc#partial, use NA instead + * Deprecate autoreload.rb has been spun-off to a separate project + * Deprecate Module#nesting, b/c redundant and overlap with Module.nesting + +* Renamed Features + + * Rename Module#parent to Module#enclosure + * Rename Module#parents to Module#enclosures + * Rename Module#parent_name to Module#modname + * Rename Array#recurisvely to Array#recurse + * Rename Hash#recurisvely to Hash#recurse + * Rename Enumerable#recursive to Enumerable#recursively + * Rename Array#recursive to Array#recursively + * Rename Hash#recursive to Hash#recursively + * Rename Kernel#silence_warnings to Kernel#disable_warnings + * Rename Hash#recursive_merge to Hash#deep_merge + * Rename Class#prepend to Class#preallocate + * Rename File#atomic_write to FileUtils#atomic_write + * Rename Module#conflict to Module#method_clash + * Rename Class#inheritor to Module#class_inheritor + * Rename Symbol#re_s to Symbol#as_s + * Rename String#chars to String#characters + * Rename String#outdent to String#unindent + * Rename Time#round to Time#round_to + * Rename Time#hence to Time#shift (but keep aliases) + * Rename Hash#zipnew to Hash#zip + +* Moved Libraries + + * Move roman.rb to integer/roman and string/roman.rb + * Move blank.rb to kernel/blank.rb + * Move facets-live.rb to facets/auto_core.rb + * Move cattr.rb to MORE library + * Move duplicable.rb to kernel/dup.rb + * Move bitmask.rb to integer/bitmask.rb + * Move enumerable/divide.rb to array/divide.rb + * Move enumerable/split.rb to array/split.rb + * Move enumerable/entropy.rb to array/entropy.rb + * Move enumerable/probability.rb to array/probability.rb + * Move enumerable/duplicates.rb array/duplicates.rb + * Move module/enclosure.rb to optional TOUR libs + * Move kernel/instance_exec to option TOUR libs + +* Bug Fixes + + * Fix Fixed Hash#rekey! from clobbering previous keys + * Fix Exception#raised? is a class method + * Fix Enumerator#fx should use #map instead of #each + * Fix String#splice needs String#store + * Fix Kernel#blank? empty condition was faulty + * Fix Comparable#bound needs clip.rb, not cap.rb + * Fix String#file needs to pass block + * Fix String#edit_distance use new encodings for Ruby 1.9 + +* Improved Features + + * New lib/tour division of libraries + * Module#class_extend dynamically creates append_features method + * Kernel#require_all is only for relative requires + * __DIR__ can take subdirectory arguments + * Hash#join has more sensible default separator (' ') + * Some OpEsc escapes have been renamed + * Kernel#assign does not accept a block + * Kernel#try is now like ActiveSupport's + * Improved #respond (which is like old #try) + * Remove all `if defined?(ActiveSupport)` conditions + * Use #random_range to support specialized Range#at_rand functionality + * Use Comparable.[] instead of Comparable() + * Array#rotate rotates in opposite direction than before (b/c or Ruby 1.9) + + +## 2.8.4 / 2010-04-27 + +A minor point release just to get a few improvements out there before +endeavering into more extensive work for the next major release. + +* New Features + + * Added #glob_relative to Pathname + +* Deprecations + + * Deprecated BlankSlate (use BasicObject) + * Deprecate hashbuilder.rb + * Removed casting_hash.rb, moved to new library + * Removed opencollection.rb, moved to new library + * Removed ansicode.rb, use ansi gem + +* Bug Fixes + + * changed Numeric#length to return self, not to_s.self + * Fix mispelling of Class#descendants + +* Other Improvements + + * Range#at_rand has been optimized + * Kernel#singleton_class no longer can take a block + * Hash#to_proc takes response argument replacing #to_proc_with_response + * OpenHash becomes more like OpenObject and OpenObject becomes bare bones + * Range#at_rand optimized for Fixnum/Bignum instead of Integer + + +## 2.8.3 / 2010-04-10 + +New release which makes a few adjustments in Kernel core extensions, +adds a few new extensions and additions, plus other small improvements. +The biggest change is the addition of Recusor, which is created via +Enumerable#recursive. This class is somewhat like Enumerator and +provides a number of recursive methods. + +Changes: + +* 9 New Core Extensions + + * Enumerable#recursive provides a number of other recursive methods. + * Enumerable#visit can be used to recursively iterate any Enumerable. + * Module#set has been added (from Sinatra). + * Symbol#/ is added to be like String#/. + * Struct#to_h is added and will ultimately replace Struct#attributes. + * ObjectSpace#reflect routes method calls to Kernel context. + * Hash#to_module converts a hash to mixin module (Jay Fields). + * Kernel#dup! is same as #try_dup from extlib. + * Add File#ext which is a useful variation of #extname (Lavir the Whiolet). + +* 3 Core Extensions Renamed + + * Renamed #set_from to #assign_from (alias remains until Kernel#set is considerd). + * Renamed #populate to #assign and improve. + * Kernel#instance_vars is now Kernel#instance and also more useful. + +* 1 Core Deprecation + + * Removed #instance_eval hack. + +* 2 Core Bug Fixes + + * #map_with_index now uses #each_with_index. + * #to_proc_with_response spelling correction. + +* 1 Core Adjustment + + * Aliased #metadef to #meta_def. + +* 3 New More Libraries + + * casting_hash.rb provides CastingHash class, a hash with flexible keys and values. + * prepend.rb allows for AOP-like inclusion of modules. + * roman.rb provides simple roman numeral extensions to String and Integer. + +* 5 More Improvements + + * Pathname#visit for iterating all entries beneath a path (chikamichi). + * Pathname#to_str, b/c Pathname is basically a type of String (from extlib). + * Range#at_rand in random.rb handles Float ranges (Lavir the Whiolet). + * FileUtils#cp_rx provides controlled copies. + * Stash class in stash.rb is improved and is now available as a stand-alone library. + * ioredirect.rb has been removed as IORedirect no longer worked. + * plugin_manager.rb has been removed. Use 'plugin' gem instead. + + +## 2.8.2 / 2010-02-22 + +This release fixes a bug by removing Numeric#size. Turns out that was a +core method already. It includes an "auditing" of the core enumerable +method which has led to a few modifications most noteable amoung them +renaming #map_detect to #find_yield and #compact_map to #purge. + +Changes: + +* 7 New Core Extensions + + * Add Enumerable#each_with_object. + * Add #collapse which is a shortcut for flatten.compact. + * Add Numeric#spacing (Mr. Groff) + * Add Array#uniq_by! to complement Enumerable#uniq_by. + * Add String#exclude? as opposite of #include? + * Add Enumerable#exclude? as opposite of #include? + * Add Proc#bind_to + +* 2 Extensions Renamed + + * Rename Enumerable#compact_map to #purge. + * Rename Enumerable#map_detect to #find_yield. + +* 4 Deprecations + + * Deprecate #inject!/#injecting in favor of #filter. + * Deprecate Array#** as alias of #product. + * Remove Numeric#size, as it was already used by core. + * Spun tracepoint.rb off as a seprate library. + +* 3 Other Changes + + * Integer#multiple? handles zero as an argument. + * facets.rb is now dynamically loaded instead of code generated. + * General imporvements to date.rb. + + +## 2.8.1 / 2009-12-25 + +This release simply fixes a few minor issues. + +Changes: + +* 1 New Standard Extension + + * Added Pathname#glob_relative to pathanme.rb. + +* 3 Adjustments + + * Loading string/tab.rb no longer loads margin.rb or expand_tab.rb. + * Fixed FileList method delegations. + * Numeric#length and #size return +self+, not +to_s.length+. + + +## 2.8.0 / 2009-11-05 + +Facets 2.8 effectively completes the MORE library clean-up which peaked +with the previous 2.7 release. Another eight libraries have been deprecated, +a few of them spun-off to a separate project. However, this verison also +reverts a few of the deprecations made in the last version. These libs +will remain in Facets's MORE library for the forseeable future. + +This version effectively concludes the MORE library clean-up. The next, and +last version before Facets 3.0, will focus on "auditing" the CORE library. + +Changes: + +* 6 Libraries "Undeprecated": + + * ini.rb + * linkedlist.rb + * matcher.rb + * memoizer.rb + * roman.rb + * semaphore.rb + +* 5 Libraries Deprecated: + + * fileable.rb (too esoteric) + * ioredirect.rb (needs better implementation) + * coroutine.rb (because of Fiber) + * capsule.rb (may be spun-off) + * recorder.rb (may be spun-off) + +* 3 Libraries Spun-Off and Deprecated: + + * ansicode.rb ansi + * progressbar.rb ansi + * logger.rb ansi + +* Additonal Enhancements: + + * Kernel#extend can now take a block + * Fixed kernel#d so it is useable + * Added Range#at_rand (thanks to Tyler Rick) + * Added Enumerable#map_detect (thanks to Scott Taylor) + * String#/ calls File.join + * Added String#newlines and String#cleanlines + * String#titlecase includes apostrophe in words + * BasicObject/BlankSlate is more compliant with 1.9.1 design + * Enumerable#count can take multiple items, treats as logical Or + * Class#class_extend extends class level, not class_eval + * Integer#succ(n) becomes Fixnum#succ(n), succ.rb + * Complete rewrite of Inheritor + * Shellwords extensions have been reworked + * Added String#similarity + * Added Levenshtein String#edit_distance method + * And other minor improvements (some thanks to ccjr) + + +## 2.7.0 / 2009-08-01 + +Facets 2.7 is the biggest release of Facets since 2.4. Rather then trickle-release these +changes over the course of the 2.6.x series, I made the decision to let 2.7 have them +all at once. In so doing this release nearly completes the process of trimming down +the MORE library to its essentials. Over 40 high-level libraries have been spun-off +as separate gems and/or deprecated. No doubt this is a big change for Facets, and the +transition may be a bit bumpy over the short-term, but I am certain that in the long-run +everyone involved will be better served. To help, I have listed the effected libraries +and the alternate gems availble to take their place. + +A few other changes have also been made in the release that may also effect your code. +In particular you should note that #class_extension has been renamed to #class_extend +(require 'facets/class_extend'). In addition we have added a few new core methods such +as Exception#raised? and Symbol#thrown?. + +Changes: + +* Spun-Off Projects + +These libraries have been deprectated from Facets entirely, but are available +as separate gems (or soon will be). + + LIBRARY GEM + -------------------- ------------------------------ + overload.rb overload + binreadable.rb binaryio + downloader.rb downloader + xoxo.rb xoxo + bicrypt.rb bicrypt + typecast.rb typecast + association.rb association + syncarray.rb sync + synchash.rb sync + paramix.rb paramix + crypt.rb crypt3 + lrucache.rb lrucache + net/smtp_tls.rb smtp_tls + advisable.rb advisable + buildable.rb buildable + memoizer.rb memoizer + harray.rb sparray + sparse_array.rb sparray + iteration.rb iteration + interval.rb stick + infinity.rb stick + pool.rb pool + linkedlist.rb linkedlist + semaphore.rb semaphore + pqueue.rb pqueue + censor.rb language + matcher.rb language + basex.rb radix + minitar.rb archive-tar-minitar -or- folio + +* Spun-Off But Still Available + +These libraries have been spun-off into stand-alone gems, but remain +available via Facets too. Ultimately some of these will be removed +from Facets too (in particular the ansi libraries). + + LIBRARY GEM + -------------------- ------------------------------ + ansicode.rb ansi + progressbar.rb ansi + logger.rb ansi + tracepoint.rb tracepoint + dictionary.rb dictionary + recorder.rb recorder + ostructable.rb ostructable -or- openhash + openobject.rb openhash + opencollection.rb openhash + opencascade.rb openhash + openhash.rb openhash + openmodule.rb openmodule + fileable.rb fileable + enumerablepass.rb enumargs + +* Deprecations Without Current Replacement + +The libraries have been deprecated but do not yet have replacements. +Seperate gems for these are planned though. + + bbcode.rb + ini.rb + settings.rb + xmlhash.rb + +* Deprecations Merged Into CORE + +These libraries have been deprecated because their functionality was merged into +the CORE library and/or made available in some another way. + + 1stclassmethod.rb #method! and #instance_method! are now part of CORE. + elementor.rb #per has been added to CORE. + elementwise.rb #ewise has been added to CORE. + consoleutils.rb #ask is in CORE, for the rest see Ansi or Clio project. + attr.rb Added Module#attr_setter to CORE, and separated the rest in MORE. + +* General Deprecations + +These libraries have simply been deprecated because they were found lacking in +some significant fashion. + + nilstatus.rb Poved rather useless, not to mention trivial. + heap.rb Heap was just an alias for PQueue anyway. Use 'pqueue' instead. + dependency.rb Other solutions exist that are much better (like Advisable). + classmethods.rb #class_extend solution is more robust. + ziputils.rb Have a look at Folio (gem install folio) for replacement. + unheritable.rb Implementation is trivial and usefulness questionable. + instantise.rb Replaced by instance_function.rb. + +* Other Enhancements + + * Fixed Proc#curry to work with #define_method (Thanks to R.Potter) + * Module#class_extension has been renamed to #class_extend (require 'facets/class_extend'). + * kernel#instance is no longer in core; now it is an extra monkey patch for #instance_eval. + * Kernel#this has been removed. It is equivalent to 'method(__method__)'. + * BlankSlate is now an alias for BasicObject, and will be deprecated in the future. + * Kernel#method! and Module#instance_method! now use a global variable for their cache. + * #object_state (old name was #state) has been added to core. + + +## 2.6.0 / 2009-07-03 + +Facets 2.6.0 removes htmlfilter.rb and cssfilter.rb due to licensing +incompatability. These scripts are now available as a separate package +called 'htmlfilter'. Also removed are a few MORE libs that were too +expiremental and/or not robust enough. Effectively this finishes up +the "spring cleaning" of the MORE lib mentioned a few releases back. + +But it also marks a new start in trimming MORE down further. We have +decided to do this for three reasons 1) Some of the MORE libs would +be better served as separate projects. 2) Facets will become a tighter +library, primarily focused on extensions. And 3) all libraries involved +will become easier to maintain and thus more robust in the long run. + +This release also fixes an important arity bug with the recently added +Module#extend method --one of the very few actual core overrides in Facets. + +Changes: + +* 7 Major Enhancements + + * Removed htmlfilter.rb due to licensing issues. + * Also removed cssfilter.rb ('gem install htmlfilter' now) + * Removed rwdelegator.rb, simply not a robust solution. + * Removed buildable.rb, api is too confusing. + * Removed meta.rb which was not very useful and too expiremental anyway. + * Removed prototype.rb, which needs it's own project. + +* 3 Minor Enhancements + + * Removed Kernel#__HERE__ as it simply cannot work. + (Ruby 1.9.2 will offer #source_location for the same, btw) + * Returned binding/opvars to core. + * Added Integer#length as suggested by Victor H. Goff III. + +* 1 Bug Fix + + * Fixed arity issue with Module#extend. + + +## 2.5.2 / 2009-04-07 + +Facets 2.5.2 is a simple maintentance release which fixed a few issues +in the new to_hash.rb library. This release also added String#lowercase +and String#uppercae. + +Changes: + +* 1 Major Enhancement + + * added string/uppercase and lowercase + +* 1 Minor Enhancement + + * adjustments to to_hash.rb + + +## 2.5.1 / 2009-03-05 + +Facets 2.5.1 fixes a few bugs, makes some small but nice additions +and improves 1.9 compatibility. + +The most important addition to make note of is Object#extend, which has +been overridden to allow a block parameter. This is one of only two or three +actual "monkey patches" in all of Facets. The block, when provided, +is used to create an annonymous module which then extends the reciever. +This is a "good practice" way to extend objects, rather than using class_eval +on the singleton class. + +Special thanks to Erik Veenstra, Pit Capitan and especially Sandor Szücs +for their contributions to this release. + +Changes: + +* 7 Major Enhancements + + * added Hash#group_by_value (thanks to Erik Veenstra) + * added String#file + * added Hash#new_with (Pit Capitan) + * added module/extend.rb, now can take a block. + * added hook.rb + * added to_h_auto + * overhauled to_hash.rb, now has multiple methods + +* 10 Bug Fixes + + * corrected ostruct.rb to test for frozen state on updates + * fixed String#left_align + * fixed conflict between test_name.rb and test_arguments.rb + * fixed Enumreable#split when reciever is empty array + * fixed coruption of reciever by Hash#collate (thanks to Tilo Sloboda) + * fixed Array#to_h, h={} was not initialized + * fixed test of Module#conflict according ruby19 + * fixed Hash#dearray_singluar_values + * association.rb stores reference when using #new + * changed Array#product to make it compatible to ruby 19, deleted block parameter + +* 5 Minor Enhancements + + * split enumerable/collect into map_with_index and compact_map + * improved Array#to_h for 1.9 using flatten(1) + * Dictionary#replace can take regular Hash too + * move test_to_hash.rb from more to core + * Doc'd that UnboundMethod#name returns Symbol in 1.9, but String in 1.8 + + +## 2.5.0 / 2008-11-23 + +Facets 2.5.0 is an important milestone in the development of Facets. + +This release has been tested against Rails' ActiveSupport library. +As long as Facets is loaded after ActiveSupport, everything +should work fine. Of course, there's no counting for real world +trials, but all ActiveSupport testcases pass under this scenario. + +Secondly, this release is the first of two (or three) down-scaling +releases intended to remove all the remaining "excess" from the +library. This is being done for a variety of reasons. Some scripts +are substantial enough to be one their own and have been spun-off +into separate largely compatible projects. In this release: + + If you were using... Use this project instead... + + annotations.rb Anise + + bytes.rb RichUnits + times.rb + + command.rb Clio + consoleutils.rb + +A few others scripts have been deprecated, without an alternative +recourse, simply because they were too weak, such as uploadutils.rb, +or highly experimental, such as chain.rb and eventhook.rb. + +Although this release constitutes an over all slimming down of Facets, +two excellent new libraries have been added. + +1) *ini.rb* by Jeena Paradies. While YAML is frequently used by +Rubyists for configuration files, a full-on serializer like YAML +is often overkill. INI files provide a lightweight solution +specifically geared for configuration. + +2) *filter.rb* by Brian Candler offers lazy evaluation chains of +Enumerable methods. This is an elegant way to optimize contiguous +maps, selections, etc. --effective even on infinite enumerators. +(Note, the name of this library may be changed in the next release.) + +While work remains to be done, I am happy to say, Facets is +finally beginning to approach the level of solidity I set out to +achieve just over a year ago. Thank the Maker! + +Special thanks to Brian Candler, Jeena Paradies and Tyler Rick. + +Changes: + +* 9 Major Changes + + * added Brian Candler's Enumerator::Filter + * added sparse_array.rb (was old harray.rb) + * added Jeena Paradies' ini.rb + * renamed CacheDelegator to Memoizer + * renamed DictionaryMatcher to just Matcher + * deprecated bytes.rb and times.rb (use RichUnits instead) + * deprecated uploadutils.rb; ziputils.rb will be (use Folio) + * deprecated annotations.rb (use Anise instead) + * deprecated command.rb and consoleutils.rb (use Clio instead) + +* 5 Minor Changes + + * deprecated chain.rb (very expiremental) + * deprecated eventhook.rb (moved to ToadCode project) + * deprecated tagiter.rb (moved to ToadCode project) + * moved Hash#symolize_keys and #stringify_keys to core lib + (still recommend #rekey instead though) + * switched to git as of 2.4.5 + +* 4 Bug Fixes + + * memoize.rb, cache was at class-level, now at instance-level + * binding/caller.rb, fixed require for callstack.rb + * fixed missing require in string/tabto.rb + * Fixed some bugs with Time#ago/Time#hence not changing years + correctly when you changed months. + (For example, Time.utc(2008, 1, 1).ago(12, :months) incorrectly + returned 2009-01-01 instead of 2007-01-01.) + Changed Time#ago/Time#hence to still work if passed negative number. + + +## 2.4.5 / 2008-10-02 + +Facets 2.4.5 is a maintaince release. This release is notable however in that +it will likely be the last that to use SVN. Facets will be switching to Git. +Also, some libraries that have been flagged "to be deprecated" for some time +will finally be so. + +Changes: + +* 8 Major Enhancements + + * Re-added date.rb to lore library, and removed from core. (#r1014) + * Much improved date.rb extension now in Lore library. (#r1027) + * Deprecated kernel/suppress. Use Exception.suppress from now on. (#r1040) + * Deprecated string/style.rb. Use English project instead. (#r1074) + * Console namespace is no longer supported (for Ansicode). (#r1077) + * enumerable/mode.rb, Enumerable#mode returns array since there can be more than one. (#r1079) + * OpenCascade automatically creates nodes, use foo? to query. (#r1056) + * Change #index_of to #index which now takes a block. + +* 14 Minor Enhancements + + * OpenStruct.new can now take a default block, like Hash.new. + * Moved variablize methods out of metaid.rb and into separate files (string/ and symbol/). (#r1042) + * Added Time#advance. (#r1046) + * Speed up of Integer odd/even methods. (#r1057) + * Array#index now takes a block (this is a core override). (#r1059) + * Spilt file/write.rb into separate method files (append, create, writelines). (#r1073) + * Modified Enumerable#split to behave like String#split. (#r1076) + * hash/op.rb, split into separate method files. (#r1081) + * Added string/modulize. string/methodize handles path names now too. (#r1085) + * Class#cattr is now part of core. (#r1089) + * Modified Enumerable#split to behave like String#split. [minor] + * Removed Rope class. If anything this will have a separate project. + * Added doc/news.html and doc/authors.html to website (temporarily?). + * Added zlib.rb to Lore library. + +* 7 Bug Fixes + + * OpenStruct#to_h dups internal table. (#r1015) + * Fixed require of string/xor in bicrypt.rb. (#r1039) + * integer/odd.rb, fixed Ruby 1.9 condition. (#r1080) + * class/cattr_*.rb fix require bug + * opencascade.rb, fixed bug when accessing sub-hash. + * typecast.rb, fixed require for string/methodize. + * Fixed Pathname#glob to ensure use of ::File. + + +## 2.4.4 / 2008-09-01 + +Facets 2.4.4 includes a major bug fix that caused Facets not to load properly, +having to do with a Time extension. The problem has been fixed. In addition, +this release put Facets only a few pending adjustments away from full +Rails/ActiveSupport compatibility. + +Changes: + +* 10 Major Enhancements + + * Added string/mask providing powerful string manipulation. (#997) + * BasicObject is now just a synonm for BlankSlate unless Ruby 1.9. (#1000) + * Added Symbol#plain?, Symbol#query? and Symbol#setter? (#1011) + * Removed Time#to_date. + * Due to clobberd RI Docs (!) this should have been in Lore lib date.rb + * Moved to Lore date.rb. (#1012) + * Re-added date.rb to lore library, and removed from core. (#1014) + * Much improved date.rb extension now in Lore library. (#1027) + * Deprecated kernel/suppress. Use Exception.suppress from now on. (#1040) + * Improved date.rb and moved to LORE library, and removed from CORE. [major] + * Deprecated kernel/suppress. Use Exception.suppress from now on. [major] + * Deprecated String#to_time. + * This method reqiures the loading of a number of other standard libs. + * We can reconsider adding it again if we decide these other libs should be core. + * Or if we find a more suitable way to define the method. + +* 17 Minor Enhancements + + * Moved style.rb to string/stylize.rb (#998) + * Renamed string/subtract to string/op_sub. + Old name will remain for time being for compatability. (#1002) + * Module#instance_method_define? now only applies to public methods. (#1003) + * Array#index accepts a block (one of the few core overrides). (#1004) + * Moved Hash#<< from hash/update.rb to hash/op_push.rb (#1005) + * Add facets class files (eg. facets/string) have been made dynamic. (#1013) + * Moved variablize methods out of metaid.rb and into separate files (string/ and symbol/). (#1042) + * Added Time#advance. (#1046) + * Added qua_class.rb. Yea. It really is my favorite. + * Added simple functional test that loads all of Facets. + * Added a benchmark for measuring how fast Facets loads. (Core < 1sec!) + * Made Module#alias_method_chain a public method (for better Rails support). + * Wrapped Nilclass#to_f in 1.9 condition. + * float/round.rb redirects to numeric/round.rb. + * numeric/float.rb holds rounding methods for all classed Numeric, Integer and Float. + * Replaced Kernel#instance_exec with Mauricio's version. + * Improved String#each_char to work like Ruby 1.9. + * This loads strscan.rb. + * It is wrapped in a 1.9 condition. + +* 8 Bug Fixes + + * Hash#<< now returns self (#1001) + * OpenStruct#to_h dups internal table. (#1015) + * Fixed require of string/xor in bicrypt.rb. (#1039) + * Fixed facets.rb to use relative paths. + * Fixed cgi.rb (CGI is a class not a module). + * OpenStruct#to_h dups internal table. [bug] + * Fixed require of string/xor in bicrypt.rb. [bug] + * date.rb (stamp) fixed ref to constant FORMAT. + + +## 2.4.3 / 2008-08-14 + +Facets is almost fully interoperable with ActiveSupport and Ruby 1.9. +We will continue to improve this interoperability in upcoming releases. + +As a REMINDER, Facets 2.4+ now encourages: + + require 'facets' + +This is better than cherry-picking methods. It may seem counter-intuitive, +but it actually proves more advantages to do this for the sake of +improved interoperability. The practice of cherry-picking can become +problematic if other dependent libraries have cherry-picked different +methods. In those cases these distinctions go unaccounted and untested. + +Note that this release does not include a setup.rb script. We are working +on a new version of this script, which we plan to include in the next release. + +This release give special thanks to the following people for their contributions: +Ken Bloom, Nick Caruso, Evgeniy Dolzhenko, Andy Freeman, Tomasz Muras and Dave Myron. +And of course, to anyone else I failed to mention that has contributed. + +(NOTE: 2.4.3's changes may actually be long to 2.4.2. Notice the releases are +only two days apart. There was an issue with 2.4.2 and it had to be replaced +immediately. So take the distinct with a grain of salt.) + +Changes: + +* Additions + + * Add Time#trunc and Time#round to Core. + * Add Array#recursively and fixed bug in Hash#recursively. + * Add Kernel#instance method which provides a fluent interface to private object space. + * Add Symbol#plain?, Symbol#query? and Symbol#setter? + * Add Hash#symbolize_keys and #stringify_keys. + * Add File#split_root. + * Add #glob and #glob_first as extensions to Pathname. + * Add NilClass#ergo whic points back to kernel/ergo. + * Add #bump method to VersionNumber class. + * Add String#mask providing powerful string manipulation. + * Add Ken Bloom's DictionaryMatcher class (will be renamed in future version) + +* Deprecations + + * Deprecate Hash#keys_to_s and Hash#keys_to_sym. + * These are the original versions of these methods. + * But now we can use #rekey(:to_s) and #rekey(:to_sym) instead. + * Deprecat ruby.rb, which was a sort 1.9 compatibility layer. + +* 22 Major Enhancements + + * Changed File#rewrite to not use the in-place change of the string. + * Renamed Class#to_pathname and #to_methodname to #pathize and #methodize. + * Removed Console:: namespace for ANSICode. + * Moved Mentalguy's lazy.rb to core! + * Added Indexable and Stackable to core. + * BasicObject is now just a synonm for BlankSlate unless Ruby 1.9. [major] + * Moved Indexable and Stackable to core. + * Renamed arguments.rb and CLI::Arguments to argvector.rb and Argvector. + * Added optional argument to Dictionary#first and #last. + * Moved binding/opvars from core to more. + +* 19 Minor Enhancements + + * Improved File#rootname --it is now more robust. + * Made FileUtils#whereis a module_function again. + * Created Lore library to house extensions to Ruby's standard library. + * Re-added facets class files (eg. facets/string) and are now dynamic. + * Added block to Array#index. + * This is one of the few core overrides in Facets. + * It is a feature already in Ruby 1.9. + * Added Jim Weirich's BlankSlate class. + * This is a temporary measure be compatible w/ AcitveSupport's BasicObject. + * Split kernel/load.rb into require_all.rb and require_local.rb. + * Split module/alias.rb up into alias_accessor, alias_module_function and alias_method_chain. + * Renamed string/subtract to string/op_sub. + Old name will remain for time being for compatability. [minor] + * Moved style.rb to string/stylize.rb [minor] + * Added warning to bytes to use RichUnits instead. + * Updated warn line fore eventual deprecation of fileshell and arguments.* + * Added facets-load.rb to allow old school cherry picking.* + * Between 2.0 and 2.4 require 'facets' simply added core to LOAD_PATH. + * Starting with 2.4 it loads all of core automatically instead. + * facets-load.rb provides a way to use the old behavior. + require 'facets-load.rb + require 'kernel/with' + require 'symbol/to_proc' + * This adds the path to the end of LOAD_PATH to prevent any load conflicts. + +* 5 Bug Fixes + + * Fixed Time#hence changed years when changing months. + * Fixed Time#hence to flip year correctly when adding months. + * Hash#<< returns self + * Fixed String#pathize. + * Module#instance_method_defined? now only applies to public methods. + +* Administrative Enhancements + + * While not perceptible to an end user, there are now 3 divisions: lib/core, lib/lore, lib/more. + * Modified script/test to display $LOAD_PATH before running tests. + +## 2.4.2 / 2008-08-12 + +Just some more of those great old work your ass off changes. + +Changes: + +* Major Enhancements + + * Added Ken Bloom's DictionaryMatcher class from Ruby Quiz #103. + (Note this class will probably be renamed in the future.) + * Changed File#rewrite to not use the inplace change of the string. + * If you were using the function, change your code to use File#rewrite! instead. + * Or, modify your code ot use the new behavior. + * This change can make for a slippery bug, so be sure to check for it! + * Moved live.rb to facets-live.rb. + * Added kernel/instance method which provides a fluent interface to private object space. + +* 5 Minor Enhancements + + * Added sow generation forms. + * Spilt Time#trunc into separate file. + * Remove old log files --shouldn't version control these. + * Added note to FileList to add glob options parameter. + * Added optional argument to Dictionary#first and #last. + +* Other Enhancements + + * Move "lore" tests to test/lore (lore are extensions to Ruby's standard lib). + * Added test/core, test/lore and test/more. + * Added time/test_round.rb + * Added array/recursively. + * Added time/round. + * Time#to_date makes the public (it already existed in Ruby!) + * Fixed Time#hence to flip year correctly when adding months. + * Work on documentation using new Sow system. + * Moved meta.rb to more/kernel/meta.rb and merged facets/core.rb into facets.rb. + * Added more/kernel directory --hey not every extension can be core. + * Adjusted loadpath and moved lazy.rb to core! + * Moved remaing files to subdirectory locations. + * Moved most core libs to core/. + * Move most more files to the more directory. + * Added lore and more directories. + * Added facets/core directory. Yes, I'm spiliting the lib again. + * Loadpath will be used, so user inteface will stay the same. + * Setup.rb will be adjusted to recognaize loadpath. + * Removed Rope class. If anything this will have a separate project. + * Moved setup.rb to script/setup. + * This will either be replaced with configure/install scripts. + * Or, depend on a separate ruby setup.rb project. + * Added recorder.rb to consider in work directory. + * Added admin directory. + * Added "TO BE DEPRECATED" message to ruby.rb. + * Added all methods from ruby.rb as individual core methods. + * These are the methods that overlap with 1.9. + * They are encased in 'unless RUBY_VERSION' caluses. + * Imporved file/rootname --now much more robust. + * Added Kernel#to_yamlfrag to yaml.rb as way to output yaml w/o the "---" header. + * Perhaps not the most robust solution, but okay for now. + * Maybe a poor name for the method, but you got a better one? + * Made FileUtils#whereis a module_function again like it used to be. Because: + (1) that seems to be the way most other FileUtils methods are (cd, mkdir, cp, ...) and the most + obvious way that users would WANT to use FileUtils: FileUtils.whereis("ruby"). + (2) I see module_function used in other comparible parts of Facets: UploadUtils, ConsoleUtils, + ZipUtils, FileUtils#safe_ln, ... + (3) My code that relied on the old module_function behavior was breaking + What were you thinking changing it?? ;) + + +## 2.4.1 / 2008-04-03 + +This release takes aim at improving compatability with ActiveSupport. +It also reintroduces an improved paramix.rb. + +Changes: + +* 4 Major Enhancements + + * A much improved paramix.rb has been returned to the library. + * There a no longer capitialize module methods at all. + * Use Module#[] and mixin_params[] instead. + * Deprecated behavior.rb. It was not robust. + * Added basex.rb, for working in any encoding base using any character set (base62 is the default). + +* 3 Minor Enhancements + + * Comparing to ActiveSupport, found 63 extension clashes, but most are due to 1.9 features. + The rest should be compatible. + * Reatomized a number of Kernel and String methods. Reatomization is nearly complete. + * Continued work on reatomizing core extensions (nearly complete now). + + +## 2.4.0 / 2008-03-24 + +Facets 2.4 is a major step forward for Facets. It is perhaps the release +that 2.0 should have been, but of course it took the actual 2.0 release +to make 2.4 possible. Some annoyances you may have encountered in updating +your code to 2.0 are now fixed. And from 2.4 on, Facets will now be +settling down into simple refinement release cycles for a while. + +The main change under the hood is to bring everything up to the top +lib/facets/ directory. No longer are the libraries sorted by category. +I had done so for a long time to make it easier to track the various libs, +but in the end it was only making it more diffcult to deal with build tools +and packaging. + +For the end-user, the largest change is a new emphisis on: + + require 'facets' + +This is better than cherry-picking methods. It may seem counter- +intuitive, but it actually proves more advantantages to do this +for the sake of interoperability than the practice of cherry-picking. +The reason is simply because others may have cherry-picked different +methods, and those distinctions go unaccounted and untested. + +Also with this release, to bolster the use of require 'facets', +some lack-luster extensions have been deprecated and namespace usage +has been improved. In addition, we are getting very close to full +ActiveSupport, and Ruby 1.9, interoperability. Expect this +to be complete in the next minor release or two. + +Changes: + +* Enhancements + + * String#to_re and String#to_rx have swapped default behaviors. #to_rx escapes, #to_re does not. + * The Console namespace is being deprecated. command.rb and arguments.rb now use CLI naemspace. + * #compare_on and #equate_on are now "mixin methods" Comparable() and Equateable(). + * Enumerable#product, #combintations and #permutations have change to be Ruby 1.9 compatible. + * thread.rb, map_send, et al, block is passed to send instead of yielding on result. + * namespace.rb has been renamed to methodspace.rb. + * Ruby 1.9 defined a new Proc#curry method, so Facets version has been made compatible. + * The old curry method is now called #partial, as in "partial application". + * Deprecated interface.rb. Perhaps a better approach but nonetheless extraneous. + * Deprecated paramix.rb. A better way is to use a capitialized methods. (Perhaps a lib for that?) + * Brought back a few web related libs, htmlfilter.rb and cssfilter.rb in particular. + * camelcase and snakecase are core extensions. For specialized styles use String#style in style.rb. + * Renamed ArgVector to CLI::Arguments + * Moved one_nine.rb to ruby.rb + * Moved test/test_one_nine.rb to test/test_ruby.rb. + * Updated requires for "one_nine" to just "ruby" b/c of backports to 1.8.7. + * Added warning to Rick Kilmers's unit system. + * Moving Rich Kilmers's units system to it's own package. + * Three are alternate unit systems available and Facets should work with any of them. + * Will keep a fair amount of the Time extensions though. + * Moved nil/status.rb to nilstatus.rb + * Got rid of Method#curry and Method#partial since they just convert to Procs. + * Made op_esc.rb a separate module rather thanan extension. + * Deprecated with_reader, with_writer and with_accessor for attr_singleton_reader, &c. + * Deprecated Hash#pairs_at. Use Hash#slice instead from core. + * Fixed the namespaces of some extensions. + * Added prime directory and files. + * Removed all "prime" extension files. + * Move mattr to module. + * Fixed require bug in time methods. + * Reverted memomize.rb back to original code --will come back to later. + * Added stylizer.rb to replace stylize.rb + * Array #recursively is not only called #traverse. + * Added case/stylize methods to more/facets/string. + * Renamed more/string/facets/titlecase to captialize_all. + * Added uri and xoxo tests. + * Progressive work on memoize and elementor. + * Functor no longer privatizes =, == and =~. + * Properly split conversion.rb. + * Some string methods extracted from stylize.rb. + * Moved random.rb to more/. + * Renamed namespace.eb to methodspace.rb. + * Moved autoreload to more/facets/kernel. + * Removed old curry.rb. + * Added cgi.rb with some standard extensions. + * Deprecated paramix.rb. + * Added xmlhash.rb and returned uri.rb extensions to the library. + * Added #method_name to Date class. + * Remove cut-bases AOP, now in it's own library. + * Converted compare_on.rb to Paramtric Mixins. + * Split fileutils up into individual methods. + * Renamed console.rb to what it should be consoleutils.rb. + * Update to command.rb integrating MasterCommand and Command into a single class. + * Added options back into multiglob_r. + * Improved cloneable.rb to be a true deep dup/clone mixin using Ken Bloom's suggestion. + * Added tasksystem.rb. + * Added enumerable/combinations. + * Added openhash and tracepoint. + +* Bug Fixes + + * Fixed bug with #peek in stackable. + * Fixed bug in Kernel#object_hexid. + * Fixed bug in multiglob_r so it will NOT follow symlinks. + * Fixed test_keyize.rb. + +* Adminstrative Changes + + * This was a fairly large and fast-paced update, so unfortunately not all changes are listed this time. + * Added ri generation to setup.rb. + * Updated README and allowed doc/ to be included in package. + * Finally completed removal of all embedded tests. + * Organized all libs between core, more, class and mixin. + + +## 2.3.0 / 2008-02-01 + +Amoung other changes with this release, cloneable.rb is now a true deep +dup/clone mixin; tracepoint.rb returns to the library. + +Changes: + +* 4 Major Enhancements + + * Cloneable provides true deep cloning. + * Moved hash_keyize.rb to CORE as hash/keyize.rb. + * Added tracepoint.rb back to the library. + * Added hash/collate. + +* 3 Bug Fixes + + * Fixed multiglob_r bug, so it will NOT follow symlinks. + * Added a couple of missing binding requires. + * Fixed test_keyize.rb. + +* 6 Admistrative Changes + + * Reorganized library into smaller groups: core, more, class and mixin. + * Remove admin/svn subdir. + * Remove admin/log. + * Add admin tasks. + * Moved admin tasks to admin directory. + * Added admin directory. + + + +## 2.2.1 / 2007-12-22 + +This release get rid of the underlying methods subdir. +All method redirects are now in core, to ensure there +are no more name clashes. + +Changes: + +* Method Renames + + * Moved string/format.rb to string/wrap.rb. + * Updated String#brief. + * Moved binding/cflow.rb to caller.rb. + * Moved core hash/keyize to more. + +* Other Enhancements + + * Fixed up binding extensions. + +* Administrative Adjustments + + * Got rid of methods subdir. All method redirects are in core/. + * Moved doc/wiki to apiwiki b/c of Rubyforge's wiki. + * Removed doc/api dir. + * Added wiki. + * Renamed a couple test tasks. + * Update per-module/class files. + * Moved methods and groups task to trash. + * Added test class/remove_descendents.rb. + * Added all remaining per-method require libs from methods/ (will need to wrok through these over time). + * Added trash work directory. + * Adjust text according to per-method file changes. + * All hash method, but the conversion methods, are now represented in core/facets/hash. + * Added a few more Hash per-method files. + * Add per-method libs for hash. + * Updated facets/string.rb. + * Renamed ROLLRC to facets.roll. + + +## 2.2.0 / 2007-12-13 + +This release provides improved rdocs and prepares facets for use with Ruby 1.9. +It also adds Matthew Harris' duration.rb library. Bug thanks to Matthew! + +Changes: + +* Additions + + * Added Matthew Harris' Duration class. + * Added Hash#slice and Hash#except (didn't we have this before?) + * Added registerable.rb, updated history. + * Added #include_as to facets/namespace.rb. + * Added op.rb to string.rb. + * Added String/op.rb with String#- method. + +* Method Renames and Reorganizations + + * The name Array#unzip didn't makes sense, it was renamed to #modulate (though #collate seems better?) + * Renamed Enumerable#collate to #mash (Map hASH); #collate and #graph remain aliases for the time being. + * Renamed accessor #attributes to #instance_attributes. + * Renamed Enumerable #collate to #mash. (old name, along with graph, will be an alias for time being) + * Divided enumerable/collect into split.rb and each.rb as well. + * Moved mapsend.rb to thread.rb. + * Updated mapsend.rb to focus on threads. + * Moved continuation extensions to more lib. + +* Deprecations + + * Deprecated Module#include_and_extend. Just use both silly. + * More lib pp_s.rb has been removed. Use #pretty_inspect instead. + * Removed continuation from core. + * Removed pp_s.rb (use pretty_inspect) add continuation.rb. + * Remove kernel/require_esc.rb. + +* Other Enhancements + + * integer/bitmask.rb has changed a bit --pun intended ;) Deprecated some methods and now use "~" instead of "-" to clear bits. + * Split binding extensions up a bit more finely --eval.rb sprouted here.rb, self.rb and defined.rb. + * Move Time#stamp out of conversion.rb and into time/ dir, and remove to_s alias. + * Preliminary addition of Matthew Harris' excellent duration.rb lib (will integrate with times.rb better in future). + * Minor edit to basicobject.rb in light of 1.9. + * Minor adjustments to lazy.rb to fix warnings by Ruby 1.9. + * Added if clauses to handle upcoming Ruby 1.9 gracefully. Facets should now be just about ready for use with 1.9. + +* Documentation Enhancements + + * A lot of rdoc updates to core extensions --as promised ;) + * Just about every method now has at least a brief explinaiton and an example. + +* Administrative Adjustments + + * Moved task/config.yaml to meta/ per new Ratch. + * Moved task/special to task/doc. + * Updated todo list (in dev/). + * Copied log/history.rd to CHANGES. + * Removed log/history.rd and log/todo.rd + * Fixed stylize.rb for use with 1.9 (fixed case statement). + * Separated kernel/returning, now that #tap will be in 1.9. + * Updated facets.rb for use with 1.9. + * Separated time/stamp.rb. + * Divided binding up into a few more pieces. + * Fixed kernel/instance to play nice with 1.9. + * Added test for string/op.rb. + * Added test_collect.rb split-offs and test_mash inplace of test_collate. + * Cleanup test headers. + * Added 1.9 check in continuation/create.rb. + * Add a couple new task for rdoc gen. + * Added nbsp to quickopts task. + * Work on website using siteparts. + + +## 2.1.3 / 2007-11-28 + +This release fixes four bugs --one being fairly serious, as it prevented +require 'facets' from working at all. + +Changes: + +* 4 Bug Fixes + + * Fixed oddity in Enumerable/collate. + * Fixed issue that prevented loading of facets.rb. + * Array#to_h used flatten, but it needed to be flatten(1). + * Move core/main.rb back to core/facets.rb as it conflicts with lib in more/. + + +## 2.1.2 / 2007-11-22 + +Changes: + +* Additions + + * Added Exception#details. + +* General Enhancements + + * Dir::multiglob no longer handels -/+ modifiers. Use FileList instead. + +* Administrative Adjustments + + * Fixed task/install script. + * Improved task/changes. + + +## 2.1.1 / 2007-11-16 + +Changes: + +* Additions + + * Added kernel/ergo.rb. + * Added pp_s.rb (Questionable addition, but we'll leave it for now.) + * Added validation.rb. This is here for Nitro's sake --better techinques may replace it in the future. + * Added Console::Logger to logger.rb (may be separated in future). + * Added option arity to command.rb. + +* Deprecations + + * Removed tracepoint.rb. + +* Bug Fixes + + * Fixed bug in command.rb that clobbered options. + * Fixed options bug in command.rb. + + +## 2.1.0 / 2007-11-10 + +Major changes include a new and much-improved command.rb, a new BiCrypt +class for simple two-way crypotgraphy, as well as attr_reader!, +attr_writer! and attr_accessor! for flag attributes, plus +alias_xxx methods for all attr_xxx methods. + +Changes: + +* Additions + + * Added BiCrypt class for simple two-way encryption. + * module/attr.rb now has attr_reader!, attr_writer! and attr_accessor! + * All attr_xxx methods have coresponding alias_xxx methods. + * Added UniversalOptions module. + * Added "tester" attribues attr_xxx!. Also added alias_xxx for all attr_xxx methods. + +* Enhancements + + * command.rb has been completely rewritten. The API has changed completely! + * There is no longer a Commmand::Optoins class. Use Console::Arguments instead. + * Moved common alias methods from attr.rb to alias.rb. + * MasterCommand now passes (args, opts), until 1.9 is main stream. + * Cleaned up enumerable/permutation.rb + * Added -q option to zip method in ZipUtils. + * Ok. #p is back. This will in fact be in 1.9, so we're good. + +* Bug Fixes + + * Fixed bug in Enumerable#cluster_by which returned nil instead of []. + * Fixed minor bug in arguments.rb that prevented proper repeat parameters. + * Fixed bug in to_console. + * Fixed bug in enumerable/cluster_by (returned nil instead of []). + * Fixed bug in Hash#- Thanks to Xavier Shay. + * Fixed to_h in Command::Options + +* Admin Changes + + * Added dev/test + * Renamed RELEASE to WHATSNEW + * Added injecting test and cleaned up. + * Added comment for potential future #is. + * Added top-level log directory. + * Remove #q reference from RELEASE. + * Cleanup of test_initializer.rb. + + +## 2.0.5 / 2007-11-07 + +Minor release that fixes a couple of bugs and adds the last of +adopted methods from Gavin Sinclair's Extensions project. + +Also, renamed #p to #q, because of multiple args problem. +I don't know how Ruby 1.9 plans to handle multiple args. +Will deprecate for 1.9 anyway so doesn't matter much. + +Changes: + +* Additions + + * Added final methods Gavin Sinclair's Extensions project. (Noah Gibbs) + +* General Improvements + + * Made #alias_method_chain compatible with current ActiveSupport version. + * Rename #p to #q, because of multiple args problem. + * Allow Class#initializer to return the attribute names. + +* Bug Fixes + + * Fixe return bug in hash/op.rb. + * Fixe bug with Dictionary#initialize. + * Fixe bug with Hash#-. (Xavier Shay) + +* Admin Adjustments + + * Fixed package name in icli.yaml. + * Added name field to meta/icli.yaml. + * Added meta/icli.yaml. + * Added a RELEASE file to hold current release notes. + * Added log task. + * Added changelog file in doc/log/. + + +## 2.0.4 / 2007-11-04 + +Changes: + +* Unsorted Changes + + * Up'd version to 2.0.4. + * Update task/groups. + * Removed extest task. We will no longer need it. + * Minor update to rdoc.yaml. + * Renamed old changelogs. + + +## 2.0.3 / 2007-11-02 + +Changes: + +* Unsorted Changes + + * Touch up to methods task. + * Update rsync filter + * Minor updates fixing issues highlighted by running crosstest. + * Many minor bug fixes after running against crosstest. + * Added usage support for __foo options. + * Fixed a many a test after running against crosstest. + * Removed load task. It did not isolate the libs, so wasn't effective. + * Added a number of new tasks. + * Rename SMTP_TLS to Smtp_tls for Rdocs. + * Moved rdoc.yaml to config/. + * moved task/config to task/config/general. + * Update tasks. + + * Added array/only, symbol/to_proc (where did it go?) and hash/select. + + * Update roll file. + * Moved test_command_options to test_command. + * Update dictionary test to check dup and autohash. + * Fixed autohash and dup bugs. + * Verbatim support for Rails' version of #alias_method_chain. + * Remove site/ directory. + * Moved rsync filter up too. + * Moved doc/site/ up to doc/. + * Added javascript directory to doc/. + + * Updates across the board. + * Updates to stylize and command.rb. + * Made facets.rb a shortcut to facets/facets.rb (this is for Rolls, better way?) + * Oh smack. Lots of stuff fixed. + + * Remove version.txt. No longer needed. + * Removed meta/project.yaml, replaced by facets roll file. + + * Modifications to command.rb, snapshot and rbsystem. + * Merged command.rb and command_options.rb into command.rb. + * Added to_data aliases to snapshot.rb + * Minor additions to rbsystem. Rather than System, maybe Ruby? + + * Removed embedded test from overload.rb. + * Allow OpenStruct#initialize to take a setter block. + * Downloader needs 'wb' flag rather then just 'w'. + * Fixed typo and removed embedded test. + * Fixed bug in command_options.rb, putting the class back in the Console namespace. + + * improved module/traits.rb + + +## 2.0.2 / 2007-10-08 + +Changes: + +* Administrative Changes + + * Cleaned up some test and updated version to 2.0.2 + * Update methods to eleminate duplicate file names between lib/core and lib/methods + + +## 2.0.1 / 2007-10-06 + +Changes: + +* Unsorted Changes + + * updated version to 2.0.1 + * minor bugs fixes + * update methods task to display each file as it process it + * added benchmarks for some enumerable methods. + * moved demo/bench/bench_factorial to an demo/bench/integer subclass + * added Erik Veenstra to AUTHORS for work on enumerable/group_by and cluster_by + * minor improvement to test task to specifically read test_*.rb files + * removed enumerable/partition.rb + * move enumerable/partition.rb methods to collect.rb. + * Improved Integer#of. + * Minor improvements to collect.rb and partition.rb + * Deprecated nonuniq!, bug fixed cluster_by and aliased group_by and partition_by. + * Renamed Enumerable#partition_by to group_by (like Ruby 1.9) and fixed bug in cluster_by. + + +## 2.0.0 / 2007-10-02 + +Changes: + +* General Enhancements + + * Added Oliver Renaud to the AUTHORS list (oops!) + +* Bug Fixes + + * Fix requires in `cut.rb` and `attributes.rb`. + * Fix `String#brief` in `format.rb`. + +* Unsorted Changes + + * removed 1stClassMethod from "more" docs + * removed 1stClassMethod as a rdoc target (now in Core target) + * update install and rdoc tasks + * moved string/test_index.rb to string/test_nchar.rb + * updated indexable tests + * update string.rb to include string/nchar.rb + * moved index.rb to nchar.rb + * clean up string/index.rb + * moved facets.rb to fore directory + * add comment to groups task + * added groups task + * updated all extrension group files (array.rb, binding.rb, etc.) + * uncapitalize meta files + * update methods task a bit more, plus related configuration + * updated methods task + * removed lib/core --this is generated content (may be renamed too) + * added load and stats tasks + * update install task --this replaces setup b/c of Facets' special install needs + * update project file + * removed lib/facets + * moved remaining libs to fore (will later consider an additional subdivision) + * move facets/fore to fore/facets + * move facets/more to more/facets + * added ;ob/core, more and fore + * move memorize + * removed io and net directories + * moved io/redirect.rb to more/ioredirect.rb and net/smtp_tls.rb and net/uploadutils.rb libs to more too. + * few more libs moved to more/ directory + * moved all the most obvious more libs to the more directory + * moved fore "grouping" libs to fore directory + * moved "fore" libs to fore directory + * create for and more directories (yes, you know what's coming ;) + * renamed remain.rb (was main_as_module.rb) to just main.rb + * improved rdoc task and project.yaml file + * better docs for OpenObject + * improved method hiding + * documentation touch ups + * fixes for conversion.rb rather than conversions.rb + * updated to website docs + * moved demos to demo/sample + * added bench and sample dir to demo + * moved spy.html to light.html + * menum change to webpage, fixed core doc link + * moved metadata files to meta/ (info/ or box/ would be better?) + * updated test_conversion.rb for to_h/to_hash + * reverse_each instead of each for after advice in advice.rb + * final fix to to_h/to_hash discrepency + * added a Path and Root features to Pathname (good idea?) + * update advice.rb test and moved old cut test to dev/scrap + * updated advice; removed preinitialize.rb to trinkets project (it was too expiremental) + * command_filter.rb needs to considered/developed; moved to dev/new/ + * fixed interface.rb fo singelton methods + * updates to tests + * whole lot of small bug fixes + * add tests to revision control + * removed old cut test (moved to dev/scrap) + * working on tests + * added read.rb (taken from readwrite.rb) + * split readwrite.rb into read.rb and write.rb + * remove string/unpack.rb, offset can be had using '@' format instead + * renamed conversions.rb to conversion.rb, fixed some requires + * improved attr.rb + * some cleanup of enumerable extensions + * setup annotations demo + * add non-embedded tests + * finally brough over toadcode prototype.rb and cleaned it up enough to be useful + * removed annotations subdir + * moved annotations/ann.rb and attr.rb to annotations.rb and attributes.rb + * remove annotations.rb + * moved annotations/settings.rb up a dir + * remove settings.rb + * chnaged multiton_id(e) to multiton_id(*e,&b) + * updated test task + * added Christoph Rippel to authors lists + * added doc header to new multiton class + * update to new version of multiton + * playing around with multiton2.rb + * renamed dev/try to dev/new + * created dev/old to temporarily house old versions of libs that have been replaced. + * fixed quick.html documentation + * used old wiki.gif as email.gif instead + * fixed config.yaml publish entry + * some minor updates to index.html + * moved site to doc/site + * update to publish task + * updates of tasks + * added kernel/report.rb to hold debug/warn extensions. + * renamed reporting.rb to silence.rb + * update reporting.rb (created report.rb from it) + * task work + * clean up dev finis + * cleanup dev just a bit more + * continue cleanup of dev directory + * moved dev/twiki to misc/ + * removed dev/core + * moved require_directory.rb to misc/ + * added dev/misc for code scraps that might be useful but are not straight lib or task code + * more dev changes + * organize dev better + * cleanup of dev continues + * cleanup of dev dir + * clean up dev dir more + * some cleanup of dev directory + * almost completed advice lib + * added comment about possible update + * deprecate instance_send and instance_map + * work on rdoc task + * work on rdoc task + * added dev/cut dir + * no reason to track .config + * clean up trunk + * added todo comment + * added advice.rb to replace old aspects.rb + * removed aspects.rb (sucked), added prototype.rb (infancy) and adjusted to class_extension.rb + * removed #to_roman (now part of the English project) + * cont. work on aop and cuts + * fixed IMG tag bug + * added yaml.rb + * move #here convenience method to binding/eval (separate?) + * added in order to remove kernel/misc.rb + * consolidate string/regesc + * added module/methods + * updates to include and attr + * fixed Range#umbrella + * more organization of docs + * orginizing docs + * update val.rb + * added proc/fn.rb (from kernel/misc.rb) and fixed typo in compose.rb + * moved misc.rb to val.rb + * better organization of some kernel methods + * moved #here alias to eval.rb + * minor updates and some bug fixes (modspace what broke) + * removed file/yaml.rb in favor or just yaml.rb + * moved this to facets/yaml.rb + * work on aop system + * Added aop.rb, and cut.r and recursive.rb + * moved cut.rb to dev (old version will be deprecated) + * added to_hash to Dictionary, and minor mods to others + * oops, no need for enumerator directory + * moved threaded_send.rb to mapsend.rb + * moved threaded_send out of enumerable/ dir + * updates to elementor.rb + * merged instance_map into threaded_send + * removed map_send + * merging map_send with threaded_send + * cont work on elementwise methods + * divide elementwise functions betwee two libs + * uniq.rb is merged into count.rb + * removed count.rb (uniq.rb will become count.rb) + * continued refinement of enumerable extensions + * general improvements to the organization of enumerable extensions + * removed facets/cli dir + * moved all cli libs from facets/cli to facets/ + * moved cli support files to facets locations + * moved cli lib to facets main (also modified functor) + * renamed hash/reverse to hash/merge (it contains #reverse_merge) + * remove instance_intercept (moced to Trinkets project) + * continued modification of those tasky tools + * removed lib/more (this is it!) + * moved M-Z of more/facets to facets (this is it!) + * moved A-L of more/facets to facets (this is it!) + * removed lib/core (this is it!) + * moved lib/core/facets.rb to lib/facets.rb (this is it!) + * moved lib/core/facets to lib/facets (this is it!) + * added file/yaml.rb + * added a list of libraries considered "core" + * continued work on build tools + * change tools for core/more convergence (so help us god!) + * added conversion requirement to some core libs + * update methods task + * update quick.html to mirror rdoc changes --still needs work though + * remove old rdoc task + * added rdoc section (minimal) to tool/config.yaml + * nope. remove site/rdoc + * add rdoc dir, should we? + * remove site/rdoc in preperation for new way + * facets.rb belongs to core/ + * renamed some doc files + * removed src/core + * move src/core/lin to lib/core + * added kernel/constant + * remove src/core/web + * moving more of core to top-level (svn sucks!) + * moving core support files to top-level + * removed src/more + * move src/more/lib to lib/more + * made lib dir (to replace src) + * added settings.rb which points to annotations/settings.rb + * moved svn to annotations/ subdir + * moved dev files to top-level as part of more transition + * temporarily removed dev/more + * moved annotations demo to demo dir + * added demo folder + * add dev/more + * remove struct again! (stupid svn) + * moved file to top-level doc as part of more transisiton + * bullshit svn crap + * ann moved back to more (strongly considering annotations for it's own project) + * build moved back to more + * aop moved back to more + * cast moved back to more + * crypt moved back to more + * exts moved back to more + * file moved back to more + * meta moved back to more + * misc moved back to more + * model moved back to more + * struct moved to back to more + * moved sync back to more + * moved commandoptions.rb to command_options.rb + * rewrote command and command options libs + * initial Subversion import + + +## 1.8.54 / 2007-03-21 + +The following list of changes also includes changes from intrim releases, +`1.8.51 / 2007-02-19`, `1.8.49 / 2007-02-16`, `1.8.20 / 2007-02-06` and +`1.8.8 / 2007-01-31`. Unfortuantely the transition form darcs to git, +led to some information loss in this regard. + +Changes: + +* Unsorted Changes: + + * added reqiure to ostruct.rb test + * fix to command.rb's initializer + * fixed bug with times.rb beginning_of_year and beginning_of_month + * replaced pqueue and heap with new working class (thanks to Olivier Renaud) + * fixed bug in ormsupport.rb (this will be moved out of facets in next release) + * added empty? to dictionary (removed old subclass of Hash) + * significant improvements to command.rb thanks to Tyler Rick + * added tests to elementwise and tap + * fixed test for elementwise and op_tilde_self + * added enumerable/map_send + * added thread_map and thread_map_send thanks to greg + * added operator "~@" for enumerable/elementwise + * added more/consoleutils.rb + * added string/cleave + * added capitalize_all thanks to Richard Laugesen + * cartesian_product is an alias of enumerable/cart + * added array pad thanks to Richard Laugesen + * added kernel/tap + * fixed test/unit load issues + * converted facet/ requires to facets/core or facets/more as needed + * further improvements to arguments.rb (looking good!) + * improved symbol/self/generate + * bug fix kernel/autoreload arguments needed to be in opposite order + * add to_xoxo + * removed bad character codes in multiplier.rb + * used yaml to allow json.rb to work for all object in general + * improvements to functor (note: is to_a and to_proc okay?) + * add test to string/bytes.rb + * bug fix to nilclass/op_cmp + * fixed enumerable/op_pow to use enumerable/cart + * added array/op_div + * adjustments to xmlbuilder and htmlbuilder dur to buildingblock changes + * improved buildingblock.rb + * simplified interface of arguments.rb (still a little more to do) + * improvements/simplifications to Dir.multiglob + * added new authors to list + * fixed misspelling of behavior.rb (was bahvior.rb) + * removed #own from base list in facets.rb (really need a standard for "singleton class") + * minor adjustments to uploadutils + * fixed bug in aspects.rb that would not handle args of wrapped method + * Symbol#to_s optimization, had to remove freeze + * updates to fileutils/stage (stage worth keeping?) + * update to credits + * fix bug in kernel/ask, returns more than one character + * cleanup of enumerbale/graph (no effective change) + * new super fast enumerable/cart by Thomas Hafner (replaces #cross) + * improved multiglob rountines (accept '+' and '-' prefixes) + * No longer will track project file via scm until it settles + * fixed bug in attr_tester, thanks Dov! + * added weekdays to times.rb thanks to Ryan Platte and Dave Hoover + * improvements to dictionary.rb (no longer a subclass of Hash) thanks Jan! + * re-replace openhash with openobject + * improvements to ann.rb and ann_attr.rb. works, yea! + * fixed bug in string/singular.rb + * changed enumerable/cross into enumerable/cart and cartesian_product + * openobject returns (openhash was a bad name, thanks george) + * moved enumerable/cross to enumerable/cart (cartesian_product) + + +## 1.8.0 / 2007-01-24 + +The list of changes also includes intrim releases `1.7.46 September 8, 2006`, +`1.7.38 August 31, 2006`, and `1.7.30 August 23, 2006`. + +Changes: + +* Additions + + * Add facets/automatic.rb, very cool, albiet experimental, way to load core methods automatically! + * added hash/insert; like store but only if key isn't already present + * added module/include_and_extend + * added File::mulitglob_sum; accumulates file patterns, and accepts '+' and '-' prefixes + * added module/module_method; like module_function but makes method public + * added module/include_function_module; attempts to properly include one function_module into another + * kernel/yaml convenience method for YAML::load + * added kernel/supress; supress errors while executing a block (nice DHH!) + * added symbol/chomp, like string#chomp + * added proc/to_h; converts an assignment proc into a hash + * proc/bind; bind a proc to an object, returning a method + * added module/prepend; provides dyanamic method wraps for modules, and static wraps for classes + * added module/new; use a module as if it were a class + * added module/alias_accessor + * kernel/instance_class; yet anouther meta_class name, but a more sensicle name this one + * added kernel/populate; populates an object's inst. vars from a hash or assingment block + * added kernel/daemonize; one last thanks to DHH! + * added enumerable/injecting; like inject but automatically returns the memo from the block + * added kernel/object_send, a true public-only send method + * added kernel/silence_stream; output to null device; thanks DHH! + * added kernel/instance_values, thanks DHH! + * added Config:inspect for rbconfig + * added hash/pairs_at (aking to values_at) + * added _why's metaid methods (meta_class, meta_eval, etc.) + * added kernel/enable_warnings to complement silence_warinings + * added integer/to_roman + * added logical operators for hash (and/or) + * array/to_path convert ans array to a path string + * array/index takes a block + * added fileutils/compress; very simple convenience methods for archiving folders + * added fileutils/stage adn staged, a means of transfering files accoring to preset rules + * added kernel/ask, simply command to get console input + * added populate.rb, mixin for classes that need on a basic initializer + * added version_number.rb (a specialized tuple) + * added uploadutils.rb + * added Joel VanderWerf's great script.rb script + * added Austin's minitar.rb --it's just too damn useful! + * added htmlfilter.rb very nice html escape class + * added dependency.rb, allwos method to have dependend execution (like rake tasks) + * added arguments.rb this is for parsing console command arguments + * add new version of annotations: ann.rb and ann_attr.rb + * added File::yaml? to roughly detect if a file is a yaml file + +* Renamed Features + + * Rename #superior to #super_at. + * OpenObject = OpenHash (OpenObject will eventually be deprecated) + * renamed quaclass to qua_class + * renamed openobject to openhash !!! + +* Deprecations + + * had to remove taskable.rb for now (implementation won't work as toplevel include) + * deprecated (yored) kernel/own, yet another term for the singleton class + * removed dataobject.rb (was never used) + * deprecated (yored!) module/inject; what a silly method + * deprecated kernel/require_facet (no longer needed) + +* Bug Fixes + + * Fix enumerable/partition_by. + * memoize should now work at toplevel + * minor bug fix to httpaccess + +* General Enhancments + + * Add buildingblock.rb, replacing builderobject.rb. + * HtmlBuilder and XMLBuilder aer now based on BuildingBlock + * adjust require for "yored" files + * minor improvements to basic object (object_self to access kernel methods) + * ostuct adjustment, use #instance_delegate to get underneth the open access + * module/include_as is now based on module/namespace (thanks Pit!) + * minor adjustments to methods for (class< nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +== ActiveSupport + +Copyright:: (c) 2005-2011 David Heinemeier Hansson +License:: MIT +Website:: http://rails.org + + Copyright (c) 2005-2011 David Heinemeier Hansson + + 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. + + +== Ruby Treasures + +Copyright:: (c) 2001 Paul Brannan +License:: Ruby License + + Ruby Treasures 0.1 + Copyright (c) 2001 Paul Brannan + + You may distribute this software under the same terms as Ruby (see the file + RUBY.txt that was distributed with this library). + + +== Metaid + +Copyright:: (c) why the lucky stiff + + Copyright (c) why the lucky stiff + + +== CLAP + +Copyright:: (c) 2010 Michel Martens +License:: MIT +Website:: https://github.com/soveran/clap + + Copyright (c) 2010 Michel Martens + + 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. + + +== String#natcmp + +Copyright:: (c) 2003 by Alan Davies +License:: Custom + + String#natcmp is based on Martin Pool's "Natural Order String Comparison" + originally written in C. (see http://sourcefrog.net/projects/natsort/) + + This implementation is Copyright (C) 2003 by Alan Davies + + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + diff --git a/bin/gems/facets-3.1.0/README.md b/bin/gems/facets-3.1.0/README.md new file mode 100644 index 00000000..ff65f4ae --- /dev/null +++ b/bin/gems/facets-3.1.0/README.md @@ -0,0 +1,260 @@ +# Ruby Facets + +[![Gem Version](https://badge.fury.io/rb/facets.png)](http://badge.fury.io/rb/facets) +[![Build Status](https://secure.travis-ci.org/rubyworks/facets.png)](http://travis-ci.org/rubyworks/facets)     +[![Flattr Me](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/324911/Rubyworks-Ruby-Development-Fund) + + +*"ALL YOUR BASE ARE BELONG TO RUBY"* + + +## Introduction + +Ruby Facets is the premiere collection of general purpose method +extensions and standard additions for the Ruby programming language. + +Facets houses the largest single collection of methods available for +extending the core capabilities of Ruby's built-in classes and modules. +This collection of extension methods are unique by virtue of their atomicity. +The methods are stored in individual files so that each can be required +independently. This gives developers the potential for much finer control over +which extra methods to bring into their code. + +In addition Facets provides a collection of extensions to Ruby standard library +plus a small collection of add-on classes and modules. Together these +libraries constitute an reliable source of reusable components, suitable +to a wide variety of usecases. + + +## Resources + +* Homepage: http://rubyworks.github.com/facets +* Report Bugs: http://github.com/rubyworks/facets/issues +* Mailing List: http://groups.google.com/group/facets-universal/topics +* Wiki Pages: http://wiki.github.com/rubyworks/facets +* Source Code: http://github.com/rubyworks/facets + + +## Documentation + +Facets has special documentation needs due to its extensive breadth. +The documentation generated when installing via RubyGems, or the YARD +docs provided by rubydoc.info can be somewhat unwieldy because it +combines all of Facets in one large set. When using these resources, +it is important to remain aware of the source location of particular +methods. + +For better organized online documentation, generated to separate core +extensions from standard libraries, see the [Learn Facets](http://rubyworks.github.com/facets/learn.html) page on the website for links to available documentation. + + +## Installation + +### Bundler + +If you are using Bundler with your project, add the facets gem to the project's +Gemfile. Unless you want all of facets loaded be sure to add the `:require => false` +option. + + gem "facets", require: false + +### RubyGems + +The easiest way to install is via RubyGems. + + $ gem install facets + +### Setup.rb + +Facets can be installed the old-fashioned way using [Setup.rb](http://rubyworks.github.com/setup). +Download and unpack the .tar.gz package and run setup.rb, like so: + + $ tar -xvzf facets-2.x.x.tar.gz + $ cd facets-2.x.x + $ sudo setup.rb + +Facets 2.8+ requires Ruby 1.8.7 or higher. Facets 3.0+ requires Ruby 2.0.0 or higher. + + +## Mission + +Facets holds to the notion that the more we can *reasonably* integrate into +a common foundation, directed toward general needs, the better that foundation +will be able to serve the community. There are a number of advantages here: + +* Better Code-reuse +* Collaborative Improvements +* Greater Name Consistency +* One-stop Shop and Installation + + +## Usage + +### CORE Library + +At the heart of Ruby Facets is the CORE extensions library. CORE provides +a sizable collection of generally useful methods, along with a few supporting +classes, that extend the functionality of Ruby's core classes and modules. + +With the exception of a few *uncommon* extensions, CORE contains anything that +will load automatically when issuing: + + require 'facets' + +This loads all the CORE functionality at once. If you plan to use more then a +handful of Facets core methods it is recommended that you require the library in +this way. However, you can also "cherry pick" the CORE library as you prefer. +And for uncommon extensions this must be done. The general require statement for +a core extension library is: + + require 'facets//' + +For example: + + require 'facets/time/stamp' + +Most "atoms" contain only one method, but exceptions occur when methods +are closely tied together. + +You can load per-class or per-module groups of core methods by requiring the +class or module by name. For example" + + require 'facets/time' + +Will require all the core Time method extensions. + +Note that some methods that were part of CORE in 1.8 and earlier are now part +of MORE libraries. A good example is 'random.rb'. There were separated because +they had more specialized use cases, where as CORE extensions are intended as +general purpose. + +#### Method File Names + +Operator method redirect files are stored using English names. For instance +`Proc#*` is `proc/op_mul`. + +For reference, here is the chart. + + +@ => op_plus + -@ => op_minus + + => op_add + - => op_sub + ** => op_pow + * => op_mul + / => op_div + % => op_mod + ~ => op_tilde + <=> => op_cmp + << => op_lshift + >> => op_rshift + < => op_lt + > => op_gt + === => op_case + == => op_equal + =~ => op_apply + <= => op_lt_eq + >= => op_gt_eq + | => op_or + & => op_and + ^ => op_xor + []= => op_store + [] => op_fetch + +Facets simply takes the '*' and translates it into a string acceptable to all +file systems. Also, if a method ends in '=', '?' or '!' it is simply removed. + + +### MORE Library (aka Standard Library) + +On top of the extensive CORE library, Facets provides extensions for Ruby's +standard library, as well as a small collection of additional modules and +classes to supplement it. + +Use this library like you would any other 3rd party library. +The only difference between Facet's Standard library and other libraries +is the lack of any enclosing `Facets::` namespace. + +When using Facets extended versions of Ruby's standard libraries, +the libraries have to loaded individually. However you do not need +to load Ruby's library first, as the Facets' library will do that +automatically. + +For example, normally one load Ruby's OpenStruct class via: + + require 'ostruct' + +To load 'ostruct.rb' plus Facets extensions for it simply use: + + require 'facets/ostruct' + +For details pertaining to the functionality of each feature, +please see the API documentation. + + +## Contribute + +This project thrives on contribution! + +If you have any extension methods, classes or modules that you think have +very general applicability and would like to see them included in +this project, don't hesitiate to submit. Also, if you have better versions +of any thing already included or simply have a patch, they are more than +welcome. We want Ruby Facets to be of the highest quality. + + +## Development + +Facets uses the [Lemon](http://rubyworks.github.com/lemon) testing framework +to handle unit testing, while [QED](http://rubyworks.github.com/qed) specifications +provide tested documentation. + +Facets uses [Detroit](http://detroit.github.com) and [Rulebow](http://rubyworks.github.com/rulebow) +build tools. Detroit is a life-cycle tool and Rulebow is continuous integrations tool. The build +scripts (`Assembly` and `Rulebook` respectively), sometimes use other tools such as +[Mast](http://rubyworks.github.com/mast) and [Indexer](http://rubyworks.github.com/indexer). + + +## Authors + +Much of this collection was written and/or inspired by a variety of great Ruby +developers. Fortunately nearly all utilized works were copyrighted under the same +open licenses, the Ruby License or the more liberal BSD and MIT licenses. In the +one or two exceptions the copyright notice has been included with the source code. +Any code file not specifically labeled othewise shall fall under the current Ruby +License (which is BSD 2-clause). + +In all cases, every effort has been made to give credit where credit is due. +You will find these acknowledgments embedded in the source code. You can see +them in "CREDIT:" and/or "@author" lines. +Also see the [Contibutors page](https://github.com/rubyworks/facets/wiki/Contributors) +on the Wiki for a list of all contributing Rubyists. If anyone is missing from +the list, please let us know so we can correct right away. Thanks. + +This collection was put together by, and much of it written by [trans](https://github.com/trans). +If need be, he can be reached via email at transfire at gmail.com. + + +## License + +The collection PER COLLECTION is licensed as follows: + + Ruby Facets + Copyright (c) 2004,2010 Rubyworks + + Distributed under the terms of the Ruby license. + +The Ruby license is a dual license that also provides for use of the GPL. +Complete texts of both licenses accompany this document (see LICENSE). + +Acknowledgments and Copyrights for particular snippets of borrowed code +are given in their respective source. All licenses are either compatible +with the Ruby license or the original author has given permission for +inclusion of their code under such license. + + +"ALL YOUR BASE ARE BELONG TO RUBY!" + +Ruby Facets, Copyright (c)2005,2011 Rubyworks + +Do you Ruby? (http://ruby-lang.org) + diff --git a/bin/gems/facets-3.1.0/demo/applique/assertion_framework.rb b/bin/gems/facets-3.1.0/demo/applique/assertion_framework.rb new file mode 100644 index 00000000..84ae3d24 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/applique/assertion_framework.rb @@ -0,0 +1 @@ +require 'ae' diff --git a/bin/gems/facets-3.1.0/demo/applique/file_helpers.rb b/bin/gems/facets-3.1.0/demo/applique/file_helpers.rb new file mode 100644 index 00000000..78833b45 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/applique/file_helpers.rb @@ -0,0 +1,34 @@ +require 'fileutils' +require 'pathname' + +def temporary_directory + @temporary_directory ||= 'tmp' +end + +Before :document do + if File.exist?(temporary_directory) + FileUtils.rm_r(temporary_directory) + end + FileUtils.mkdir(temporary_directory) +end + +When /Given a directory '(.*?)' containing/ do |dir, text| + #abort unless /^#{temporary_directory}/ =~ dir + text.lines.each do |file| + next if file =~ /^\s*$/ + file = File.join(dir, file.strip) + path = File.dirname(file) + FileUtils.mkdir_p(path) + File.open(file, 'w'){ |f| f << "SPINICH" } + end +end + +# Return project root directory by looking for +lib+ directory. +def root_directory + @root_directory ||= ( + Pathname.new(Dir.pwd).ascend do |root| + break root if root.join('lib').directory? + end + ) +end + diff --git a/bin/gems/facets-3.1.0/demo/core/array/after.md b/bin/gems/facets-3.1.0/demo/core/array/after.md new file mode 100644 index 00000000..4bdd2b6c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/after.md @@ -0,0 +1,13 @@ +## Array#after + + require 'facets/array/after' + +`Array#after` returns the first value that comes after a given value. The +value after the last is the first. Returns `nil` if the given value is not +in the array. + + sequence = ['a', 'b', 'c'] + sequence.after('a').assert == 'b' + sequence.after('b').assert == 'c' + sequence.after('c').assert == 'a' + sequence.after('d').assert == nil diff --git a/bin/gems/facets-3.1.0/demo/core/array/arrange.md b/bin/gems/facets-3.1.0/demo/core/array/arrange.md new file mode 100644 index 00000000..950be8e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/arrange.md @@ -0,0 +1,17 @@ +## Array#arrange + + require 'facets/array/arrange' + +The `arrange` method produces appropriate ranges from the objects in the array. +It assumes inclusive ranges (i.e. `1..4`) and `range.first <= range.last`. + +Works with integers, dates and strings. However, all the objects in the array must +be of the same class. + + [1,2,3,6,7,8].arrange.assert == [1..3, 6..8] + + [10..15, 16..20, 21, 22].arrange.assert == [10..22] + + a = %w{a b c g h i j k m o} + a.arrange.assert == ['a'..'c','g'..'k', 'm' , 'o'] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/before.md b/bin/gems/facets-3.1.0/demo/core/array/before.md new file mode 100644 index 00000000..ef61d7ca --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/before.md @@ -0,0 +1,14 @@ +## Array#before + + require 'facets/array/before' + +Returns the value prior to the given value. The value previous +to the first is the last. Returns nil if the given value is not +in the array. + + sequence = ['a', 'b', 'c'] + sequence.before('a').assert == 'c' + sequence.before('b').assert == 'a' + sequence.before('c').assert == 'b' + sequence.before('d').assert == nil + diff --git a/bin/gems/facets-3.1.0/demo/core/array/collapse.md b/bin/gems/facets-3.1.0/demo/core/array/collapse.md new file mode 100644 index 00000000..6ad2d681 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/collapse.md @@ -0,0 +1,15 @@ +## Array#collapse + + require 'facets/array/collapse' + +Simplify an array by flattening it then compacting it. + + [1,[2,nil,[3]],nil,4].collapse.assert == [1,2,3,4] + +## Array#collapse! + +Simplify an array by flattening it in place then compacting it in place. + + a = [1, nil, [1, 2], nil, [[3]]] + a.collapse! + a.assert == [1, 1, 2, 3] diff --git a/bin/gems/facets-3.1.0/demo/core/array/collisions.md b/bin/gems/facets-3.1.0/demo/core/array/collisions.md new file mode 100644 index 00000000..9b2bd42a --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/collisions.md @@ -0,0 +1,30 @@ +## Array#collisions + +_alias for Array#commonality_. + + require 'facets/array/collisions' + +Get a list of all items that have something in common in terms of the +supplied block. If no block is given objects are considered to be in +common if they return the same value for Object#hash and if obj1 == obj2. + +This can be useful, for instance, in determining all persons that share +their last name with another person. + + Person = Struct.new(:name) + persons = %w{Wayne Pennyworth Grayson Wayne Pennyworth}.map{|n| Person.new(n)} + persons.collisions { |person| person.name }.keys.assert == ["Wayne","Pennyworth"] + +The method is similar to #group_by which is a standard Ruby method as of 1.9. +To get effectively the same results with #group_by use `select{ |k,v| v.size > 1 }`. + + expected = { 2 => [2, 2], 4 => [4, 4] } + + [1, 2, 2, 3, 4, 4].group_by{ |e| e }. + select{ |k,v| v.size > 1 }.assert == expected + + [1, 2, 2, 3, 4, 4].collisions.assert == expected + + %w{foo bar baz}.collisions{|str| str[0]}.assert == {'b' =>["bar", "baz"] } + +Returns a Hash mapping common attribute to those elements. diff --git a/bin/gems/facets-3.1.0/demo/core/array/commonality.md b/bin/gems/facets-3.1.0/demo/core/array/commonality.md new file mode 100644 index 00000000..f7996cfd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/commonality.md @@ -0,0 +1,31 @@ +## Array#commonality + + require 'facets/array/commonality' + +Get a list of all items that have something in common in terms of the +supplied block. If no block is given objects are considered to be in +common if they return the same value for Object#hash and if obj1 == obj2. + +This can be useful, for instance, in determining all persons that share +their last name with another person. + + Person = Struct.new(:name) + persons = %w{Wayne Pennyworth Grayson Wayne Pennyworth}.map{|n| Person.new(n)} + persons.commonality { |person| person.name }.keys # => ["Wayne","Pennyworth"] + +The method is similar to #group_by which is a standard Ruby method as of 1.9. +To get effectively the same results with #group_by use `select{ |k,v| v.size > 1 }`. + + expected = { 2 => [2, 2], 4 => [4, 4] } + + [1, 2, 2, 3, 4, 4].group_by{ |e| e }. + select{ |k,v| v.size > 1 }.assert == expected + + [1, 2, 2, 3, 4, 4].commonality.assert == expected + + + %w{foo bar baz}.commonality{|str| str[0]}.assert == {'b' =>["bar", "baz"] } + +Returns a Hash mapping common attribute to those elements. + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/conjoin.md b/bin/gems/facets-3.1.0/demo/core/array/conjoin.md new file mode 100644 index 00000000..0980be4e --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/conjoin.md @@ -0,0 +1,47 @@ +## Array#conjoin + + require 'facets/array/conjoin' + +This is more advanced form of #join. It allows for fine control +of separators. + +NOTE: The old version used to default its separator to ", " and +default the terminating separator to " and ". This is no longer +the case. You must specifically provide these parameters. + +If no parameters are given, it acts like #join but will a space +separator. + + [1,2,3].conjoin.assert == "1 2 3" + +Use comma+space and 'and' on tail. + + [1,2,3].conjoin(', ', ' and ').assert == "1, 2 and 3" + +Use comma+space and 'or' on tail using :last option. + + [1,2,3].conjoin(', ', :last => ' or ').assert == "1, 2 or 3" + +Use semicolon+space and ampersand on tail using index. + + [1,2,3].conjoin('; ', -1 => ' & ').assert == "1; 2 & 3" + +Can take a block to determine separator. + + [1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' }.assert == "1.2-3.4" + +This makes very esoteric transformation possible. + + [1,1,2,2].conjoin{ |i, a, b| a == b ? '=' : ' != ' }.assert == "1=1 != 2=2" + + [1,2,3,4].conjoin{ |i, x, y| "<#{i} #{x} #{y}>" }.assert == "1<0 1 2>2<1 2 3>3<2 3 4>4" + +There are also spacing options. Providing the :space option +pads the separators. + + [1,2,3].conjoin(',', '&', :space=>2).assert == "1 , 2 & 3" + +And the :spacer option can set an alternate spacing string. + + [1,2,3].conjoin('|', '>', :space=>2, :spacer=>'-').assert == "1--|--2-->--3" + diff --git a/bin/gems/facets-3.1.0/demo/core/array/contains.md b/bin/gems/facets-3.1.0/demo/core/array/contains.md new file mode 100644 index 00000000..9dc1b71c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/contains.md @@ -0,0 +1,9 @@ +## Array#contains? + +_alias of Array#include? _ + + require 'facets/array/contains' + + [1,2,3,4].assert.contains?(2) + [1,2,3,4].refute.contains?(9) + diff --git a/bin/gems/facets-3.1.0/demo/core/array/delete_unless.md b/bin/gems/facets-3.1.0/demo/core/array/delete_unless.md new file mode 100644 index 00000000..97237078 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/delete_unless.md @@ -0,0 +1,13 @@ +## Array#delete_unless + + require 'facets/array/delete_unless' + +The method `#delete_unless` is the inverse of `#delete_if`. + + a = [1,2,3] + a.delete_unless{ |e| e == 2 } + a.assert == [2] + + [1,2,3].delete_unless{ |x| x < 2 }.assert == [1] + [1,2,3].delete_unless(&:even?).assert == [2] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/delete_values.md b/bin/gems/facets-3.1.0/demo/core/array/delete_values.md new file mode 100644 index 00000000..a08db175 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/delete_values.md @@ -0,0 +1,10 @@ +## Array#delete_values + + require 'facets/array/delete_values' + +Delete multiple values from array. + + a = [1,2,3,4] + a.delete_values(1,2) #=> [1,2] + a #=> [3,4] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/delete_values_at.md b/bin/gems/facets-3.1.0/demo/core/array/delete_values_at.md new file mode 100644 index 00000000..d6cb9671 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/delete_values_at.md @@ -0,0 +1,15 @@ +## Array#delete_values_at + + require 'facets/array/delete_values_at' + +Delete multiple values from array given +indexes or index range. + + a = [1,2,3,4] + a.delete_values_at(1,2).assert == [2,3] + a.assert == [1,4] + + a = [1,2,3,4] + a.delete_values_at(0..2).assert == [1,2,3] + a.assert == [4] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/divide.md b/bin/gems/facets-3.1.0/demo/core/array/divide.md new file mode 100644 index 00000000..e82c5e10 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/divide.md @@ -0,0 +1,14 @@ +## Array#divide + + require 'facets/array/divide' + +Divide into sub arrays at elemetns matching given pattern + + r = ['a1','b1','a2','b2'].divide(/^a/) + r.assert == [['a1','b1'],['a2','b2']] + + r = ['a1','b1','a2','b2'].divide(/^b/) + r.assert == [['a1'],['b1','a2'],['b2']] + + r = ['a1','b1','a2','b2'].divide(/c/) + r.assert = [['a1','b1','a2','b2']] diff --git a/bin/gems/facets-3.1.0/demo/core/array/duplicates.md b/bin/gems/facets-3.1.0/demo/core/array/duplicates.md new file mode 100644 index 00000000..8293d57c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/duplicates.md @@ -0,0 +1,14 @@ +## Array#duplicates + + require 'facets/array/duplicates' + +Return list of duplicate elements. + + [1,1,2,3].duplicates #=> [1] + +Return list of those duplicated min times. + + [1,1,2,3,2,4,5,4,2].duplicates(3) #=> [2] + + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/each_overlap.md b/bin/gems/facets-3.1.0/demo/core/array/each_overlap.md new file mode 100644 index 00000000..4d8f9378 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/each_overlap.md @@ -0,0 +1,12 @@ +## Array#each_overlap + + require 'facets/array/each_overlap' + +Iterate over each slice where the last n values of a preceding slice +overlap with the first n values of the following slice. The value of n +is specified by the second `overlap` argument. + + a, r = [1,2,3,4,5], [] + a.each_overlap(2,1) { |x,y| r << [x,y] } + r.assert == [[1,2],[2,3],[3,4],[4,5]] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/each_pair.md b/bin/gems/facets-3.1.0/demo/core/array/each_pair.md new file mode 100644 index 00000000..80c51014 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/each_pair.md @@ -0,0 +1,13 @@ +## Array#each_pair + + require 'facets/array/each_pair' + +Iterate over an array yielding with index and value. + + result = {} + a = [:a,:b,:c,:d] + a.each_pair{|i,e| result[e] = i + 1} + result.assert == {a: 1, b: 2, c: 3, d: 4} + +*NOTE* this is the inverse of `Array#each_with_index`, and is intended to provide +polymorphism with `Hash#each_pair`. diff --git a/bin/gems/facets-3.1.0/demo/core/array/each_value.md b/bin/gems/facets-3.1.0/demo/core/array/each_value.md new file mode 100644 index 00000000..2250ecd2 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/each_value.md @@ -0,0 +1,12 @@ +## Array#each_value + + require 'facets/array/each_value' + +This is an alias of Alias#each, and is provided to provide polymorphism with +Hash#each_value. + + a = [ "a", "b", "c" ] + out = '' + a.each_value {|x| out += "#{x} -- " } + out.assert == 'a -- b -- c -- ' + diff --git a/bin/gems/facets-3.1.0/demo/core/array/entropy.md b/bin/gems/facets-3.1.0/demo/core/array/entropy.md new file mode 100644 index 00000000..4eda95b3 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/entropy.md @@ -0,0 +1,13 @@ +## Array#entropy + + require 'facets/array/entropy' + +Shannon's entropy for an array - returns the average +bits per symbol required to encode the array. +Lower values mean less "entropy" - i.e. less unique +information in the array. + + e = %w{ a b c d e e e }.entropy + + ("%.3f" % e) #=> "2.128" + diff --git a/bin/gems/facets-3.1.0/demo/core/array/extract_options.md b/bin/gems/facets-3.1.0/demo/core/array/extract_options.md new file mode 100644 index 00000000..3b70eda5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/extract_options.md @@ -0,0 +1,13 @@ +## Array#extract_options! + + require 'facets/array/extract_options' + +Extracts options from a set of arguments. Removes and returns the last +element in the array if it's a hash, otherwise returns a blank hash. + + def options(*args) + args.extract_options! + end + + options(1, 2).assert == {} + options(1, 2, :a => :b).assert == {:a=>:b} diff --git a/bin/gems/facets-3.1.0/demo/core/array/first.md b/bin/gems/facets-3.1.0/demo/core/array/first.md new file mode 100644 index 00000000..96f9b080 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/first.md @@ -0,0 +1,11 @@ +## Array#first! + + require 'facets/array/indexable' + +Alias for shift, which removes and returns the first element in an array + + a = ['a','y','z'] + a.first!.assert == 'a' + a.assert ['y','z'] + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/from.md b/bin/gems/facets-3.1.0/demo/core/array/from.md new file mode 100644 index 00000000..74330e38 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/from.md @@ -0,0 +1,11 @@ +## Array#thru + + require 'facets/array/from' + +Returns elements from index i until the end. + + %w{W o r l d}.from(3).assert == %w{l d} + +Returns entire array for i > length + + %w{W o r l d}.from(7).assert == nil diff --git a/bin/gems/facets-3.1.0/demo/core/array/ideal_entropy.md b/bin/gems/facets-3.1.0/demo/core/array/ideal_entropy.md new file mode 100644 index 00000000..a6a5a389 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/ideal_entropy.md @@ -0,0 +1,11 @@ +## Array#ideal_entropy + + require 'facets/array/entropy' + +Returns the maximum possible Shannon entropy of the array +with given size assuming that it is an "order-0" source +(each element is selected independently of the next). + + %w{ a b }.ideal_entropy.assert == 1.0 + %w{ a a b b }.ideal_entropy.assert == 2.0 + diff --git a/bin/gems/facets-3.1.0/demo/core/array/intersection.md b/bin/gems/facets-3.1.0/demo/core/array/intersection.md new file mode 100644 index 00000000..e44ceab3 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/intersection.md @@ -0,0 +1,11 @@ +## Array#intersection + + require 'facets/array/intersection' + +Returns the values in common for an array set (nil, single value/object, or range). + + [1,2].intersection.assert == nil + [1..10,11..20].intersection.assert == nil + [10,1..10].intersection.assert == 10 + [1..10,5,5..8,4..8].intersection.assert == 5 + [1..10, 5..8, 5..10 ].intersection.assert == (5..8) \ No newline at end of file diff --git a/bin/gems/facets-3.1.0/demo/core/array/last.md b/bin/gems/facets-3.1.0/demo/core/array/last.md new file mode 100644 index 00000000..09d232ce --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/last.md @@ -0,0 +1,11 @@ +## Array#last! + + require 'facets/array/indexable' + +Alias for pop, which removes and returns the last element in an +array. + + a = [1,2,3] + a.last!.assert == 3 + a.assert == [1,2] + \ No newline at end of file diff --git a/bin/gems/facets-3.1.0/demo/core/array/median.md b/bin/gems/facets-3.1.0/demo/core/array/median.md new file mode 100644 index 00000000..caeb8ea9 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/median.md @@ -0,0 +1,23 @@ +# Array#median + + require 'facets/array/median' + +Determines the _sorted_ middle element. + + a = %w{a a b b c c c} + a.median #=> "b" + +When there are an even number of elements, the greater +of the two middle elements is given. + + a = %w{a a b b c c c d} + a.median #=> "c" + +An offset can be supplied to get an element relative +to the middle. + + a = %w{a a b b c c c d} + a.median(-1) #=> "b" + +The the array is empty, +nil+ is returned. + diff --git a/bin/gems/facets-3.1.0/demo/core/array/merge.md b/bin/gems/facets-3.1.0/demo/core/array/merge.md new file mode 100644 index 00000000..a51d8ce2 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/merge.md @@ -0,0 +1,15 @@ +## Array#merge + + require 'facets/array/merge' + + a = [1,2,3] + b = [3,4,5] + a.merge(b).assert == [1,2,3,4,5] + +## Array#merge! + + a = [1,2,3] + b = [3,4,5] + a.merge!(b) + a.assert == [1,2,3,4,5] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/missing.md b/bin/gems/facets-3.1.0/demo/core/array/missing.md new file mode 100644 index 00000000..3665f8d0 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/missing.md @@ -0,0 +1,10 @@ +## Array#missing + + require 'facets/array/missing' + +Determine the 'holes' in the values of an array. Returns the missing elements +in an array set. + + [1,3..3].missing.assert == [2] + [1..5,10..12].missing.assert == [6..9] + [100, 9..11, 14, 1..5, 16, 10..12, 17..17].missing.assert == [6..8, 13, 15, 18..99] diff --git a/bin/gems/facets-3.1.0/demo/core/array/mode.md b/bin/gems/facets-3.1.0/demo/core/array/mode.md new file mode 100644 index 00000000..12dde4ba --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/mode.md @@ -0,0 +1,9 @@ +## Array#mode + + require 'facets/array/mode' + +In Statistics, mode is the value that occurs most frequently in a given set of +data. This method returns an array in case there is a tie. + + [1, 1, 2, 3].mode.assert == [1] + [1, 1, 2, 2, 3].mode.assert == [1,2] diff --git a/bin/gems/facets-3.1.0/demo/core/array/nonuniq.md b/bin/gems/facets-3.1.0/demo/core/array/nonuniq.md new file mode 100644 index 00000000..69ef9473 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/nonuniq.md @@ -0,0 +1,16 @@ +## Array#nonuniq + + require 'facets/array/nonuniq' + +Returns a list of non uniq elements. + + a = [1, 1, 2, 2, 3, 4, 5] + a.nonuniq.sort.assert == [1, 2] + +## Array#nonuniq! + +Same as #nonuniq but acts in place. + + a = [1, 1, 2, 2, 3, 4, 5] + a.nonuniq! + a.sort.assert == [1,2] diff --git a/bin/gems/facets-3.1.0/demo/core/array/not_empty.md b/bin/gems/facets-3.1.0/demo/core/array/not_empty.md new file mode 100644 index 00000000..5043de67 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/not_empty.md @@ -0,0 +1,8 @@ +## Array#not_empty? + + require 'facets/array/not_empty' + +Array is not empty? + + [1,2].assert.not_empty? + [].refute.not_empty? diff --git a/bin/gems/facets-3.1.0/demo/core/array/occur.md b/bin/gems/facets-3.1.0/demo/core/array/occur.md new file mode 100644 index 00000000..0c958fac --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/occur.md @@ -0,0 +1,18 @@ +## Array#occur + + require 'facets/array/occur' + +Returns a list of elements that occur +n+ times. + +If +n+ is a Range then returns elements that occur a number +of time within the range. + + a = [:a,:b,:a] + a.occur(1).assert == [:b] + a.occur(2).assert == [:a] + + a = [:a,:b,:a] + a.occur(1..2).assert == [:a,:b] + + a = [:a,:b,:a] + a.occur{ |n| n % 2 == 0 }.assert == [:a] diff --git a/bin/gems/facets-3.1.0/demo/core/array/occurrence.md b/bin/gems/facets-3.1.0/demo/core/array/occurrence.md new file mode 100644 index 00000000..99ff493b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/occurrence.md @@ -0,0 +1,13 @@ +## Array#occurrence + + require 'facets/array/occurrence' + +Create a hash of each uniq element of the array +and how many time each appears. + + r = [:a,:a,:b,:c,:c,:c].occurrence + r.assert == { :a => 2, :b => 1, :c => 3 } + + r = [2,2,3,4,4,4].occurrence{|i| i % 2} + r.assert == { 0 => 5, 1 => 1 } + diff --git a/bin/gems/facets-3.1.0/demo/core/array/only.md b/bin/gems/facets-3.1.0/demo/core/array/only.md new file mode 100644 index 00000000..7c15e1c5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/only.md @@ -0,0 +1,9 @@ +## Array#only + + require 'facets/array/only' + + [5].only.assert == 5 + [nil].only.assert == nil + expect(IndexError){ [].only } + expect(IndexError){ [1,2,3].only } + diff --git a/bin/gems/facets-3.1.0/demo/core/array/op_pow.md b/bin/gems/facets-3.1.0/demo/core/array/op_pow.md new file mode 100644 index 00000000..5c51faa4 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/op_pow.md @@ -0,0 +1,10 @@ +## Array#** + + require 'facets/array/op_pow' + +Alias for Array#product + +NOTE: This method is not a common core extension and is not loaded automatically +when using ```require 'facets'``` + + ([1,2] ** [3,4]).assert == [[1, 3], [1, 4], [2, 3], [2, 4]] diff --git a/bin/gems/facets-3.1.0/demo/core/array/pad.md b/bin/gems/facets-3.1.0/demo/core/array/pad.md new file mode 100644 index 00000000..f60aa27b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/pad.md @@ -0,0 +1,28 @@ +## Array#pad + + require 'facets/array/pad' + + r = [0,1,2,3].pad(7,"x") + x = [0,1,2,3,"x","x","x"] + r.assert == x + +negative index + + r = [0,1,2,3].pad(-7,"n") + x = ["n","n","n",0,1,2,3] + r.assert == x + +## Array#pad! + + a = [0,1,2,3] + r = a.pad!(6,"y") + x = [0,1,2,3,"y","y"] + r.assert == x + +negative index + + a = [0,1,2,3] + r = a.pad!(-6,"q") + x = ["q","q",0,1,2,3] + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/array/peek.md b/bin/gems/facets-3.1.0/demo/core/array/peek.md new file mode 100644 index 00000000..c19d8f07 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/peek.md @@ -0,0 +1,10 @@ +## Array#peek + + require 'facets/array/peek' + +Provide an index to inspect the array from back to front. + + [1,2,3].peek .assert == 3 + [1,2,3].peek(1) .assert == 2 + [1,2,3].peek(-1).assert == 1 + diff --git a/bin/gems/facets-3.1.0/demo/core/array/poke.md b/bin/gems/facets-3.1.0/demo/core/array/poke.md new file mode 100644 index 00000000..0df7addd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/poke.md @@ -0,0 +1,15 @@ +## Array#poke + + require 'facets/array/poke' + +Put an object on the bottom of the stack (front of the array). + + a = [2,3] + a.poke(1) + a.assert == [1,2,3] + +Or supply an index and #poke works like insert. + + a = [1,3] + a.poke(2,1) + a.assert == [1,2,3] diff --git a/bin/gems/facets-3.1.0/demo/core/array/probability b/bin/gems/facets-3.1.0/demo/core/array/probability new file mode 100644 index 00000000..554ba69d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/probability @@ -0,0 +1,8 @@ +## Array#probability + + require 'facets/array/probability' + +Generates a hash mapping each unique element in the array to the relative +frequency, i.e. the probability, of it's appearance. + + [:a, :b, :c, :c].probability.assert == {a: 0.25, b: 0.25, c: 0.50} diff --git a/bin/gems/facets-3.1.0/demo/core/array/pull.md b/bin/gems/facets-3.1.0/demo/core/array/pull.md new file mode 100644 index 00000000..230e1a5e --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/pull.md @@ -0,0 +1,10 @@ +## Array#pull + + require 'facets/array/pull' + +Alias for Array#shift which removes an object off the first slot of an array. +This is the opposite of pop. + + a = [1,2,3] + a.pull.assert == 1 + a.assert == [2,3] diff --git a/bin/gems/facets-3.1.0/demo/core/array/recurse.md b/bin/gems/facets-3.1.0/demo/core/array/recurse.md new file mode 100644 index 00000000..a2130fc5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/recurse.md @@ -0,0 +1,10 @@ +## Array#recurse + + require 'facets/array/recurse' + +Apply a block to array, and recursively apply that block to each sub-array +or +type+. + + a = ["a", ["b", "c", nil], nil] + r = a.recurse{|a| a.compact!} + r.assert == ["a", ["b", "c"]] diff --git a/bin/gems/facets-3.1.0/demo/core/array/recursively.md b/bin/gems/facets-3.1.0/demo/core/array/recursively.md new file mode 100644 index 00000000..b3b6a41d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/recursively.md @@ -0,0 +1,20 @@ +## Array#recursively + + require 'facets/array/recursively' + +Apply a method to array, and recursively apply that method to each sub-array +or given +types+. + +By default the sub-types are passed through unaffected. Passing a block +to #recursively can be used to change this. + +each + + r = [] + [1,2,['a','b'], 3].recursively.each{|v| r << v} + r.assert = [1,2,'a','b', 3] + +map + + arr = ['foo','bar',['a','b']] + arr.recursively.map{|v| v.to_sym}.assert == [:foo,:bar,[:a,:b]] diff --git a/bin/gems/facets-3.1.0/demo/core/array/reject_values.md b/bin/gems/facets-3.1.0/demo/core/array/reject_values.md new file mode 100644 index 00000000..93a4f76b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/reject_values.md @@ -0,0 +1,10 @@ +## Array#reject_values + + require 'facets/array/reject_values' + +Non-destructive form of Array#delete_values. Unlike delete_values this method +returns a new array. + + a = [1,2,3,4,5] + a.reject_values(2,4).assert == [1,3,5] + a.assert [1,2,3,4,5] diff --git a/bin/gems/facets-3.1.0/demo/core/array/splice.md b/bin/gems/facets-3.1.0/demo/core/array/splice.md new file mode 100644 index 00000000..698f5e67 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/splice.md @@ -0,0 +1,14 @@ +## Array#splice + + require 'facets/array/splice' + +Splice acts as a combination of #slice! and #store. If one argument is given it +calls #slice!, if two are given it calls #store. + + a = [1,2,3] + a.splice(1).assert == 2 + a.assert == [1,3] + + b = [1,2,3] + b.splice(1,4).assert == 4 + b.assert == [1,4,3] diff --git a/bin/gems/facets-3.1.0/demo/core/array/split.md b/bin/gems/facets-3.1.0/demo/core/array/split.md new file mode 100644 index 00000000..36247502 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/split.md @@ -0,0 +1,13 @@ +## Array#split + + require 'facets/array/split' + +Split on matching pattern. Unlike #divide, this does not include matching +elements. + + ['a','b','c'].split('b').assert == [['a'],['c']] + + a = ['a1','a2','b1','a3','b2','a4'] + a.split(/^b/).assert == [['a1','a2'],['a3'],['a4']] + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/squeeze.md b/bin/gems/facets-3.1.0/demo/core/array/squeeze.md new file mode 100644 index 00000000..5890eb45 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/squeeze.md @@ -0,0 +1,14 @@ +## Array#squeeze! + + require 'facets/array/squeeze' + +Destructive version of Enumerable#squeeze. + + a = [1,2,2,3,3,2,1] + a.squeeze! + a.assert == [1,2,3,2,1] + + a = [1,2,2,3,3,2,1] + a.squeeze!(3) + a.assert == [1,2,2,3,2,1] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/step.md b/bin/gems/facets-3.1.0/demo/core/array/step.md new file mode 100644 index 00000000..ba9137e4 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/step.md @@ -0,0 +1,16 @@ +## Array#step + + require 'facets/array/step' + +Iterate over every nth element of an array. Without a block, it returns an +Enumerator. + + r = [] + [:a, :b, :c, :d].step(2) { |x| r << x } + r.assert == [:b, :d] + + [:a, :b, :c, :d].step(1).to_a.assert == [:a, :b, :c, :d] + [:a, :b, :c, :d].step(2).to_a.assert == [:b, :d] + [:a, :b, :c, :d].step(3).to_a.assert == [:c] + [:a, :b, :c, :d].step(4).to_a.assert == [:d] + [:a, :b, :c, :d].step(5).to_a.assert == [] diff --git a/bin/gems/facets-3.1.0/demo/core/array/store.md b/bin/gems/facets-3.1.0/demo/core/array/store.md new file mode 100644 index 00000000..0a8e4f9d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/store.md @@ -0,0 +1,9 @@ +## Array#store + + require 'facets/array/store' + +Store a value at a given index. Store is an alias for #[]= + + a = [] + a.store(1,"A") + a[1].assert == "A" diff --git a/bin/gems/facets-3.1.0/demo/core/array/thru.md b/bin/gems/facets-3.1.0/demo/core/array/thru.md new file mode 100644 index 00000000..47ef04c8 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/thru.md @@ -0,0 +1,12 @@ +## Array#thru + + require 'facets/array/thru' + +Fetch Values from a start index thru an end index. + + [1,2,3,4,5].thru(0,2) #=> [1,2,3] + [1,2,3,4,5].thru(2,4) #=> [3,4,5] + + [1,2,3,4,5].thru(2) #=> [1,2,3] + [1,2,3,4,5].thru(4) #=> [1,2,3,4,5] + diff --git a/bin/gems/facets-3.1.0/demo/core/array/to_h.md b/bin/gems/facets-3.1.0/demo/core/array/to_h.md new file mode 100644 index 00000000..6e6d9515 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/to_h.md @@ -0,0 +1,11 @@ +## Array#to_h + + require 'facets/array/to_h' + +Convert an associative array to a Hash. Each element of the associative array +should be a 1 or 2 element array + +Note this is built into ruby as of 2.1.0 + + arr = [[:a, 1], [:b, 2]] + arr.to_h.assert == {:a => 1, :b => 2} diff --git a/bin/gems/facets-3.1.0/demo/core/array/traverse.md b/bin/gems/facets-3.1.0/demo/core/array/traverse.md new file mode 100644 index 00000000..8ec6ce8f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/traverse.md @@ -0,0 +1,20 @@ +## Array#traverse + + require 'facets/array/traverse' + +Construct a new array created by traversing the array and its sub-arrays, +executing the given block on the elements. + + h = ['A', 'B', ['X', 'Y']] + g = h.traverse{ |e| e.downcase } + g.assert = ['a','b',['x', 'y']] + +## Array#traverse! + +Like #traverse, but will change the array in place. + + h = ['A', 'B', ['X', 'Y']] + h.traverse!{ |e| e.downcase } + h.assert = ['a','b',['x', 'y']] + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/uniq_by.md b/bin/gems/facets-3.1.0/demo/core/array/uniq_by.md new file mode 100644 index 00000000..f34d9667 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/uniq_by.md @@ -0,0 +1,16 @@ +## Array#uniq_by! + + require 'facets/array/uniq_by' + +Like #uniq, but determines uniqueness based on a given block. +As can be seen from the examples, order is significant. + + r = (-5..5).to_a + r.uniq_by!{ |i| i*i } + r.assert == [-5, -4, -3, -2, -1, 0] + + r = (-5..5).to_a.reverse + r.uniq_by!{ |i| i*i } + r.assert == [5, 4, 3, 2, 1, 0] + + diff --git a/bin/gems/facets-3.1.0/demo/core/array/unique_permutation.md b/bin/gems/facets-3.1.0/demo/core/array/unique_permutation.md new file mode 100644 index 00000000..9e6d0f03 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/unique_permutation.md @@ -0,0 +1,14 @@ +## Array#unique_permutation + + require 'facets/array/unique_permutation' + +Enumerates permutation of Array. Unlike Array#permutation, there are no +duplicates in generated permutations. Instead elements must be comparable + + p = [1,1,2,2,3].unique_permutation(2).to_a + e = [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2]] + p.assert == e + + [1,1,2,3].unique_permutation.to_a.assert != [1,1,2,3].permutation.to_a + + [1,1,2,3].unique_permutation.to_a.assert == [1,1,2,3].permutation.to_a.uniq diff --git a/bin/gems/facets-3.1.0/demo/core/array/zip.md b/bin/gems/facets-3.1.0/demo/core/array/zip.md new file mode 100644 index 00000000..679e8a51 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/array/zip.md @@ -0,0 +1,8 @@ +## Array::zip + + require 'facets/array/zip' + +Class level rendition of Array#zip + + Array.zip([1,2], [3,4]).assert == [[1,3],[2,4]] + diff --git a/bin/gems/facets-3.1.0/demo/core/binding/caller.md b/bin/gems/facets-3.1.0/demo/core/binding/caller.md new file mode 100644 index 00000000..56b600c3 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/binding/caller.md @@ -0,0 +1,57 @@ +The caller.rb script includes a few related methods. +We will use the following code to demonstrate their use. + + require 'facets/binding/caller' + + a = 1 + b = 2 + x = "hello" + + @bind = binding + @line = __LINE__ # the line number must be updated if it moves + @file = __FILE__ # why does it equal basename only? + +## Binding#caller + + @bind.caller + +## Binding#callstack + + @bind.callstack.assert.is_a?(Array) + +## Binding#__LINE__ + + @bind.__LINE__.assert == @line - 1 + +## Binding#__FILE__ + + @bind.__FILE__.assert == @file + +## Binding#__DIR__ + + @bind.__DIR__.assert == File.dirname(@file) + +## Binding#__callee__ + +This only works for certain versions. + + def alternate_callee + binding + end + + unless RUBY_VERSION < "1.9" + alternate_callee.__callee__.assert == :alternate_callee + end + +## Binding#__method__ + +This only works for certain versions. + + def alternate_method + binding + end + + unless RUBY_VERSION < "1.8.7" + alternate_method.__method__.assert == :alternate_method + end + diff --git a/bin/gems/facets-3.1.0/demo/core/binding/defined.md b/bin/gems/facets-3.1.0/demo/core/binding/defined.md new file mode 100644 index 00000000..cdb47660 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/binding/defined.md @@ -0,0 +1,10 @@ +## Binding#defined? + + require 'facets/binding/defined' + + a = 1 + b = 2 + x = "hello" + + binding.assert.defined?("x") + diff --git a/bin/gems/facets-3.1.0/demo/core/binding/opvars.md b/bin/gems/facets-3.1.0/demo/core/binding/opvars.md new file mode 100644 index 00000000..dc3f16de --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/binding/opvars.md @@ -0,0 +1,16 @@ +## Binding#[] + + require 'facets/binding/op' + + a = 1 + b = 2 + x = "hello" + + binding["x"].assert == "hello" + +## Binding#[]= + + binding["x"] = "goodbye" + + binding["x"].assert == "goodbye" + diff --git a/bin/gems/facets-3.1.0/demo/core/binding/self.md b/bin/gems/facets-3.1.0/demo/core/binding/self.md new file mode 100644 index 00000000..f1128b6f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/binding/self.md @@ -0,0 +1,6 @@ +## Binding#self + + require 'facets/binding/self' + + binding.self == self + diff --git a/bin/gems/facets-3.1.0/demo/core/class/descendants.md b/bin/gems/facets-3.1.0/demo/core/class/descendants.md new file mode 100644 index 00000000..8eca1783 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/class/descendants.md @@ -0,0 +1,13 @@ +## Class#descendants + + require 'facets/class/descendants' + +The `Class#descendants` method returns a list of classes that are subclasses +of a class. + + a = Class.new + b = Class.new(a) + c = Class.new(b) + + a.descendants.assert == [b,c] + diff --git a/bin/gems/facets-3.1.0/demo/core/class/to_proc.md b/bin/gems/facets-3.1.0/demo/core/class/to_proc.md new file mode 100644 index 00000000..2410b755 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/class/to_proc.md @@ -0,0 +1,11 @@ +## Class#to_proc + + require 'facets/class/to_proc' + +The `Class#to_proc` method provides a convenient way to create new +instances from a set of initialization data. + + person = Struct.new(:name) + people = ["joe"].map(&person) + people[0].name.assert == "joe" + diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/at_least.md b/bin/gems/facets-3.1.0/demo/core/comparable/at_least.md new file mode 100644 index 00000000..8cefaf53 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/at_least.md @@ -0,0 +1,11 @@ +## Comparable#at_least + + require 'facets/comparable/at_least' + +Limits a number to at least a given amount. + + 3.at_least(4).assert == 4 + 4.at_least(4).assert == 4 + 5.at_least(4).assert == 5 + +This is similar to `#clip`. diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/at_most.md b/bin/gems/facets-3.1.0/demo/core/comparable/at_most.md new file mode 100644 index 00000000..111333b6 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/at_most.md @@ -0,0 +1,11 @@ +## Comparable#at_most + + require 'facets/comparable/at_most' + +Limits a number to at most a given amount. + + 3.at_most(4).assert == 3 + 4.at_most(4).assert == 4 + 5.at_most(4).assert == 4 + +This is similar to `#cap`. diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/bound.md b/bin/gems/facets-3.1.0/demo/core/comparable/bound.md new file mode 100644 index 00000000..8496dbdc --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/bound.md @@ -0,0 +1,13 @@ +## Comparable#bound + + require 'facets/comparable/bound' + +The `#bound` method is an alias for `#clip`. It is the original name +of the method before the `clip`/`cap` duo was decided upon. + + 3.bound(4).assert == 4 + + 4.bound(3,5).assert == 4 + + 'd'.bound('c','e').assert == 'd' + diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/cap.md b/bin/gems/facets-3.1.0/demo/core/comparable/cap.md new file mode 100644 index 00000000..046311e5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/cap.md @@ -0,0 +1,11 @@ +## Comparable#cap + + require 'facets/comparable/cap' + +Put a cap on what a number can be. + + 3.cap(4).assert == 3 + 4.cap(4).assert == 4 + 5.cap(4).assert == 4 + +This is very similar to `#at_most`. diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/clip.md b/bin/gems/facets-3.1.0/demo/core/comparable/clip.md new file mode 100644 index 00000000..7ba967dd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/clip.md @@ -0,0 +1,29 @@ +## Comparable#clip + + require 'facets/comparable/clip' + +Given a single argument `#clip` behaves like `#at_least`. + + 3.clip(4).assert == 4 + 4.clip(4).assert == 4 + 5.clip(4).assert == 5 + +With two arguments `#clip` puts both a lower and an upper limit +on the return value. + + 4.clip(3,5).assert == 4 + 3.clip(3,5).assert == 3 + 5.clip(3,5).assert == 5 + 2.clip(3,5).assert == 3 + 6.clip(3,5).assert == 5 + +This almost works on characters (using ASCII order). + + 'd'.clip('c','e').assert == 'd' + 'c'.clip('c','e').assert == 'c' + 'e'.clip('c','e').assert == 'e' + 'b'.clip('c','e').assert == 'c' + 'f'.clip('c','e').assert == 'e' + +This method is aliases as `bound`. + diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/cmp.md b/bin/gems/facets-3.1.0/demo/core/comparable/cmp.md new file mode 100644 index 00000000..cd9f681b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/cmp.md @@ -0,0 +1,18 @@ +## Comparable#cmp + + require 'facets/comparable/cmp' + +On integers + + 3.cmp(4).assert == -1 + 3.cmp(3).assert == 0 + 3.cmp(2).assert == 1 + +On strings + + "abc".cmp("abc").assert == 0 + "abc".cmp("abcd").assert == -1 + "abcd".cmp("abc").assert == 1 + "abc".cmp("bcd").assert == -1 + "bcd".cmp("abc").assert == 1 + diff --git a/bin/gems/facets-3.1.0/demo/core/comparable/op_get.md b/bin/gems/facets-3.1.0/demo/core/comparable/op_get.md new file mode 100644 index 00000000..4a37d3a5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/comparable/op_get.md @@ -0,0 +1,32 @@ +## Comparable.[] + + require 'facets/comparable/op_get' + +Allows `Comparable` to be included as a *parmetric mixin*. This makes it easy to define +a class as comparable on a limited set of attributes. + + c = Class.new do + include Comparable[:a,:b] + + attr_accessor :a, :b + + def initialize(a,b) + @a=a; @b=b + end + end + + a = [c.new(10,20),c.new(10,30)] + a.sort.assert == a + + a = [c.new(10,30),c.new(10,20)] + a.sort.assert == a.reverse + + a = [c.new(10,10),c.new(20,10)] + a.sort.assert == a + + a = [c.new(20,10),c.new(10,10)] + a.sort.assert == a.reverse + + a = [c.new(10,30),c.new(20,10)] + a.sort.assert == a + diff --git a/bin/gems/facets-3.1.0/demo/core/dir/ascend.md b/bin/gems/facets-3.1.0/demo/core/dir/ascend.md new file mode 100644 index 00000000..3383f28f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/dir/ascend.md @@ -0,0 +1,24 @@ +## Dir#ascend + + require 'facets/dir/ascend' + + path = 'A/B/C' + + tmp = [] + + Dir.ascend(path) do |d| + tmp << d + end + + tmp.assert == %w{A/B/C A/B A} + +Exclude current path. + + tmp = [] + + Dir.ascend(path, false) do |d| + tmp << d + end + + tmp.assert == %w{A/B A} + diff --git a/bin/gems/facets-3.1.0/demo/core/dir/descend.md b/bin/gems/facets-3.1.0/demo/core/dir/descend.md new file mode 100644 index 00000000..006d23cd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/dir/descend.md @@ -0,0 +1,16 @@ +## Dir#descend + + require 'facets/dir/descend' + +Descend thru a file path. + + path = 'A/B/C' + + tmp = [] + + Dir.descend(path) do |d| + tmp << d + end + + tmp.assert == %w{A A/B A/B/C} + diff --git a/bin/gems/facets-3.1.0/demo/core/dir/multiglob.md b/bin/gems/facets-3.1.0/demo/core/dir/multiglob.md new file mode 100644 index 00000000..3627f2d3 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/dir/multiglob.md @@ -0,0 +1,41 @@ +## Dir#multiglob + +Dir#multglob is like Dir#glob but it can handle more than one match +parameter at a time. + +Given a directory 'multiglob' containing: + + A.txt + A/B.txt + A/B/C.txt + +We can use #multglob to find multiple matches. + + require 'facets/dir/multiglob' + + x = %w{ + multiglob/A + multiglob/A.txt + } + + r = Dir.multiglob('multiglob/A', 'multiglob/A.*').sort + + r.assert == x + +## Dir#multiglob_r + +Dir#multiglob_r is like #multiglob but automatically searches +directories recrusively. + + x = %w{ + multiglob/A + multiglob/A/B + multiglob/A.txt + multiglob/A/B.txt + multiglob/A/B/C.txt + }.sort + + r = Dir.multiglob_r('multiglob/*').sort + + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/dir/parent.md b/bin/gems/facets-3.1.0/demo/core/dir/parent.md new file mode 100644 index 00000000..b7d236e9 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/dir/parent.md @@ -0,0 +1,6 @@ +## Dir#parent + + require 'facets/dir/parent' + + Dir.assert.parent?("a/b/c", "a/b/c/d") + diff --git a/bin/gems/facets-3.1.0/demo/core/dir/recurse.md b/bin/gems/facets-3.1.0/demo/core/dir/recurse.md new file mode 100644 index 00000000..ea73f321 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/dir/recurse.md @@ -0,0 +1,41 @@ +## Dir#recurse + +Given a directory 'recurse' containing: + + A.txt + A/B.txt + A/B/C.txt + +We can use #recurse to gather a complete recursive +list of all the entries. + + require 'facets/dir/recurse' + + x = %w{ + recurse/A + recurse/A.txt + recurse/A/B + recurse/A/B.txt + recurse/A/B/C.txt + }.sort + + r = Dir.recurse('recurse').sort + + r.assert == x + +## Dir#ls_r + +Dir#ls_r is an alias for #recurse which can also be used to gather +a complete recursive list of all the entries. + + x = %w{ + recurse/A + recurse/A.txt + recurse/A/B + recurse/A/B.txt + recurse/A/B/C.txt + }.sort + + r = Dir.ls_r('recurse').sort + + r.assert == x diff --git a/bin/gems/facets-3.1.0/demo/core/exception/detail.md b/bin/gems/facets-3.1.0/demo/core/exception/detail.md new file mode 100644 index 00000000..26b93058 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/exception/detail.md @@ -0,0 +1,19 @@ +## Exception#detail + + require 'facets/exception/detail' + +Provides a more detailed error message. + + begin + raise ArgumentError + rescue ArgumentError => err + r = err.detail + r.assert.include?('ArgumentError') + end + +The output of `#detail` looks something like this: + + ArgumentError: ArgumentError + example.rb:4:in `
' + LOGGED FROM: example.rb:6:in `rescue in
' + diff --git a/bin/gems/facets-3.1.0/demo/core/facets.md b/bin/gems/facets-3.1.0/demo/core/facets.md new file mode 100644 index 00000000..cb7af56c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/facets.md @@ -0,0 +1,6 @@ +# Requiring Facets + +We should be able to require all the core libraries by simply calling, + + require 'facets' + diff --git a/bin/gems/facets-3.1.0/demo/core/filetest/root.md b/bin/gems/facets-3.1.0/demo/core/filetest/root.md new file mode 100644 index 00000000..7deb4324 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/filetest/root.md @@ -0,0 +1,13 @@ +## FileTest#root? + + require 'facets/filetest/root' + +Returns true if the given directory is the file system root. +Obviously on a Linux system them means `/`. + + FileTest.assert.root?('/') + +Anything else will return false. + + FileTest.refute.root?('/home') + diff --git a/bin/gems/facets-3.1.0/demo/core/hash/recursively.md b/bin/gems/facets-3.1.0/demo/core/hash/recursively.md new file mode 100644 index 00000000..fa7fd706 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/hash/recursively.md @@ -0,0 +1,21 @@ +## Hash#recursively + + require 'facets/hash/recursively' + + h = {:a=>1, :b=>{:c=>3}} + +Without a block passed to the `#recursively` method, the block passed to the +enumeratig method will be used for both recursive and non-recursive yields. + + r = h.recursively.map{ |k,v| [k.to_s, v] } + + r.assert == [['a', 1], ['b', [['c', 3]]]] + +But if we pass a block to `#recursively` we can treat the recusive yield +separately, which in turn allows us to manipulate the non-recursive +yields with a different procedure. + + r = h.recursively{ |k,v| [k.to_s, v] }.map{ |k,v| [k.to_s,v.to_s] } + + r.assert == [['a','1'], ['b', [['c', '3']]]] + diff --git a/bin/gems/facets-3.1.0/demo/core/indexable.md b/bin/gems/facets-3.1.0/demo/core/indexable.md new file mode 100644 index 00000000..9903519d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/indexable.md @@ -0,0 +1,95 @@ +# Indexable + +Indexable it a module, like Enumerable, but provides methods specific +to an indexable collection. The Indexable module can be used independently, +but Facets can also automatically use it to extend Array. + + require 'facets/array/indexable' + +## Indexable#head + + a = [1,2,3,4,5] + a.head.assert = [1] + +## Indexable#tail + + a = [1,2,3,4,5] + a.tail.assert = [2,3,4,5] + +## Indexable#foot + + a = [1,2,3,4,5] + a.foot.assert = [5] + +## Indexable#body + + a = [1,2,3,4,5] + a.body.assert = [1,2,3,4] + +## Indexable#mid + + a = [1,2,3,4,5] + b = [1,2,3,4,5,6] + a.mid.assert = 3 + b.mid.assert = 4 + a.mid(1).assert = 4 + b.mid(1).assert = 5 + b.mid(2).assert = 6 + b.mid(-1).assert = 3 + +## Indexable#middle + + a = [1,2,3,4,5] + b = [1,2,3,4,5,6] + a.middle.assert = [3] + b.middle.assert = [3,4] + +## Indexable#thru + + [0,1,2,3,4,5].thru(2,4).assert = [2,3,4] + [0,1,2,3,4,5].thru(0,1).assert = [0,1] + +## Indexable#first= + + a = [1,2] + a.first = 0 + a.assert = [0,2] + +## Indexable#last= + + a = [1,2] + a.last = 3 + a.assert = [1,3] + +## Indexable#ends + + [1,2,3,4,5].ends.assert = 4 + +## Indexable#pos + + a = [1,2,3,4,5] + a.pos(1).assert = 0 + a.pos(-1).assert = 4 + +## Indexable#range + + a = [1,2,3,4,5] + b = [1,2,3,4,5,6] + a.range.assert = (0..4) + b.range.assert = (0..5) + a.range(2,4).assert = (1..3) + b.range(2,3).assert = (1..2) + b.range(4,2).assert = (3..1) + +## Indexable#first! + + a = [1,2,3] + a.first!.assert = 1 + a.assert = [2,3] + +## Indexable#last! + + a = [1,2,3] + a.last!.assert = 3 + a.assert = [1,2] + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/bitmask.md b/bin/gems/facets-3.1.0/demo/core/integer/bitmask.md new file mode 100644 index 00000000..60bd0cd1 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/bitmask.md @@ -0,0 +1,46 @@ +## Integer#bit + + require 'facets/integer/bitmask' + + 0.bit(0).assert == 1 + 0.bit(1).assert == 2 + 0.bit(2).assert == 4 + 0.bit(3).assert == 8 + +Negate + + 1.bit(~0).assert == 0 + 2.bit(~1).assert == 0 + 4.bit(~2).assert == 0 + 8.bit(~3).assert == 0 + +## Integer#bit? + + a = 8 + assert(! a.bit?(0)) + assert(! a.bit?(1)) + assert(! a.bit?(2)) + assert( a.bit?(3)) + assert(! a.bit?(4)) + assert(! a.bit?(5)) + +## Integer#bit_clear + + 1.bit_clear(0).assert == 0 + 2.bit_clear(1).assert == 0 + 4.bit_clear(2).assert == 0 + 8.bit_clear(3).assert == 0 + +## Integer#bitmask + + a = 1 + m = Bit(4) + a = a.bitmask(m) + a.assert == 17 + assert( a.bitmask?(m) ) + +## Kernel#Bit + + n = Bit(4) + n.assert == 16 + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/factorial.md b/bin/gems/facets-3.1.0/demo/core/integer/factorial.md new file mode 100644 index 00000000..c76f6321 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/factorial.md @@ -0,0 +1,10 @@ +## Integer#factorial + + require 'facets/integer/factorial' + + 0.factorial.assert == 1 + 1.factorial.assert == 1 + 2.factorial.assert == 2 + 3.factorial.assert == 6 + 4.factorial.assert == 24 + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/length.md b/bin/gems/facets-3.1.0/demo/core/integer/length.md new file mode 100644 index 00000000..57cb1e68 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/length.md @@ -0,0 +1,7 @@ +## Numeric#length + + require 'facets/numeric/length' + + 10.length.assert == 10 + 10.0.length.assert == 10 + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/multiple.md b/bin/gems/facets-3.1.0/demo/core/integer/multiple.md new file mode 100644 index 00000000..7e15a23e --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/multiple.md @@ -0,0 +1,12 @@ +## Integer#multiple? + + require 'facets/integer/multiple' + +Is a number an even multiple of another? + + 1.multiple?(2) #=> false + 5.multiple?(3) #=> false + + 2.multiple?(2) #=> true + 6.multiple?(3) #=> true + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/of.md b/bin/gems/facets-3.1.0/demo/core/integer/of.md new file mode 100644 index 00000000..d72d97e1 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/of.md @@ -0,0 +1,11 @@ +## Integer#of + + require 'facets/integer/of' + +Similar to `Enumerable#map` and `Enumerable#collect` but for a number +of times. + + a = 4 + b = a.of{ |i| i*2 } + b.assert == [0,2,4,6] + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/ordinal.md b/bin/gems/facets-3.1.0/demo/core/integer/ordinal.md new file mode 100644 index 00000000..17df7cdb --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/ordinal.md @@ -0,0 +1,11 @@ +## Integer#ordinal + + require 'facets/integer/ordinal' + +Produce the ordinal name of a number. + + 1.ordinal.assert == '1st' + 2.ordinal.assert == '2nd' + 3.ordinal.assert == '3rd' + 4.ordinal.assert == '4th' + diff --git a/bin/gems/facets-3.1.0/demo/core/integer/times_collect.md b/bin/gems/facets-3.1.0/demo/core/integer/times_collect.md new file mode 100644 index 00000000..ff1b71bf --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/integer/times_collect.md @@ -0,0 +1,9 @@ +## Integer#times_collect + + require 'facets/integer/of' + + a = 4 + b = a.times_collect{ |i| i*2 } + b.assert == [0,2,4,6] + +See `Integer#of` which is an alias. diff --git a/bin/gems/facets-3.1.0/demo/core/matchdata/match.md b/bin/gems/facets-3.1.0/demo/core/matchdata/match.md new file mode 100644 index 00000000..777d578c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/matchdata/match.md @@ -0,0 +1,7 @@ +## MatchData#match + + require 'facets/matchdata/match' + + md = /X(a)(b)(c)X/.match("YXabcXY") + md.match.assert == "XabcX" + diff --git a/bin/gems/facets-3.1.0/demo/core/matchdata/matchset.md b/bin/gems/facets-3.1.0/demo/core/matchdata/matchset.md new file mode 100644 index 00000000..5650c2f8 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/matchdata/matchset.md @@ -0,0 +1,7 @@ +## MatchData#matchset + + require 'facets/matchdata/matchset' + + md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchset.assert == ["XXaa", [["bb"], ["cc", ["dd"]], ["ee"]], "ffXX"] + diff --git a/bin/gems/facets-3.1.0/demo/core/matchdata/matchtree.md b/bin/gems/facets-3.1.0/demo/core/matchdata/matchtree.md new file mode 100644 index 00000000..203fb8d2 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/matchdata/matchtree.md @@ -0,0 +1,10 @@ +## MatchData#matchtree + + require 'facets/matchdata/matchtree' + + md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchtree.assert == [["bb"], ["cc", ["dd"]], ["ee"]] + + md = /(bb)c(c(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchtree.assert == [["bb"], "c", ["c", ["dd"]], ["ee"]] + diff --git a/bin/gems/facets-3.1.0/demo/core/module/cattr.md b/bin/gems/facets-3.1.0/demo/core/module/cattr.md new file mode 100644 index 00000000..7aa615b9 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/cattr.md @@ -0,0 +1,43 @@ +## Class#cattr + + require 'facets/module/cattr' + + class CAttrMockObject + def initialize + @@a = 10 + end + def b ; @@b ; end + end + + Exception.refute.raised? do + CAttrMockObject.class_eval{ cattr :a } + end + t = CAttrMockObject.new + t.a.assert == 10 + +## Class#cattr_reader + + Exception.refute.raised? do + CAttrMockObject.class_eval { cattr_reader :a } + end + t = CAttrMockObject.new + t.a.assert == 10 + +## Class#cattr_writer + + Exception.refute.raised? do + CAttrMockObject.class_eval { cattr_writer :b } + end + t = CAttrMockObject.new + t.b = 5 + t.b.assert == 5 + +## Class#cattr_accessor + + Exception.refute.raised? do + CAttrMockObject.class_eval { cattr_accessor :c } + end + t = CAttrMockObject.new + t.c = 50 + t.c.assert == 50 + diff --git a/bin/gems/facets-3.1.0/demo/core/module/class_extend.md b/bin/gems/facets-3.1.0/demo/core/module/class_extend.md new file mode 100644 index 00000000..e19258aa --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/class_extend.md @@ -0,0 +1,64 @@ +## Module#class_extend + + require 'facets/module/class_extend' + +Module using class_extend + + mix = Module.new do + def i ; end + class_extend do + def n ; 42 ; end + def s ; self ; end + end + end + +Extends module + + mix.n.assert == 42 + mix.s.assert == mix + +Has expected methods + + mix.instance_methods.map{ |m| m.to_s }.assert == ['i'] + +transfers class methods to including class + + mod = Module.new do + include mix + end + mod.n.assert == 42 + mod.s.assert == mod + +Doesn't overwrite instance methods + + c = Class.new do + include mix + def n ; 11 ; end + end + c.new.n.assert == 11 + +Is overridable via including module + + mod = Module.new do + include mix + class_extend do + def n ; super + 1 ; end + end + end + mod.n.assert == 43 # notice the difference! + mod.s.assert == mod + +Transfers class methods thru multiple levels of include + + alt = Module.new do + include mix + class_extend do + def n ; super + 1 ; end + end + end + mod = Module.new do + include alt + end + mod.n.assert == 43 + mod.s.assert == mod + diff --git a/bin/gems/facets-3.1.0/demo/core/module/class_inheritor.md b/bin/gems/facets-3.1.0/demo/core/module/class_inheritor.md new file mode 100644 index 00000000..31cedad0 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/class_inheritor.md @@ -0,0 +1,126 @@ +## Module#class_inheritor + + require 'facets/module/class_inheritor' + +Subclass with inheritor + + c = Class.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + + d = Class.new(c) do + class_inheritor :koko, [], :+ + koko! << 2 + end + +We can see that + + c.koko!.assert == [1] + c.koko.assert == [1] + + d.koko!.assert == [2] + d.koko.assert == [1,2] + +Subclass without class_inheritor + + c = Class.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + + d = Class.new(c) + +Likewise + + c.koko!.assert == [1] + c.koko.assert == [1] + + d.koko!.assert == [] + d.koko.assert == [1] + + +Include module with class_inheritor + + c = Class.new do + class_inheritor :x, {}, :merge + x![:a] = 1 + end + + m = Module.new do + class_inheritor :x, {}, :merge + x![:b] = 2 + end + + d = Class.new(c) do + include m + class_inheritor :x, {}, :merge + x![:c] = 3 + end + +Then + + c.x.assert == {:a=>1} + + m.x[:b].assert == 2 + + d.x.assert == {:a=>1,:b=>2,:c=>3} + + c.x[:a].assert == 1 + c.x[:b].assert == nil + c.x[:c].assert == nil + + d.x[:a].assert == 1 + d.x[:b].assert == 2 + d.x[:c].assert == 3 + +And + + d.x![:d] = 4 + d.x[:d].assert == 4 + + +Using #concat as the class_inheritor operator + + c = Class.new do + class_inheritor :relations, [], :concat + end + + d = Class.new(c) do + #class_inheritor :relations, [], :concat + end + + c.relations! << 1 + c.relations! << 2 + d.relations! << 3 + +Notice + + c.relations.assert == [1,2] + d.relations.assert == [1,2,3] + + +On Module + + m = Module.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + + c1 = Class.new do + include m + #class_inheritor :koko, [], :+ + koko! << 2 + koko! << 3 + end + + c2 = Class.new do + include m + #class_inheritor :koko, [], :+ + koko! << 4 + end + + m.koko.assert == [1] + c1.koko.assert == [1,2,3] + c2.koko.assert == [1,4] + diff --git a/bin/gems/facets-3.1.0/demo/core/module/copy_inheritor.md b/bin/gems/facets-3.1.0/demo/core/module/copy_inheritor.md new file mode 100644 index 00000000..d5d4a2b2 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/copy_inheritor.md @@ -0,0 +1,30 @@ +## Module#copy_inheritor + + require 'facets/module/copy_inheritor' + +We see `#copy_inheritor` in action. + + m = Module.new do + copy_inheritor :koko, [] + koko << 1 + end + + c1 = Class.new do + include m + #inheritor :koko, [], :+ + koko << 2 + koko << 3 + end + + c2 = Class.new do + include m + #inheritor :koko, [], :+ + koko << 4 + end + +And the result. + + m.koko.assert == [1] + c1.koko.assert == [1,2,3] + c2.koko.assert == [1,4] + diff --git a/bin/gems/facets-3.1.0/demo/core/module/include_as.md b/bin/gems/facets-3.1.0/demo/core/module/include_as.md new file mode 100644 index 00000000..8d9c0e98 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/include_as.md @@ -0,0 +1,31 @@ +## Module#include_as + + require 'facets/module/include_as' + +Module#include_as utilizes #method_space to allow modules to be included +within a separated namespace. + + module T + def t ; "Tt" ; end + def r ; "Tr" ; end + def q ; super ; end + end + + class N + def q ; "Nq" ; end + end + + class X < N + include_as :test => T + + def n ; test.inspect ; end + def m ; test.t ; end + def o ; test.r ; end + end + + x = X.new + + x.m.assert == "Tt" + x.o.assert == "Tr" + x.q.assert == "Nq" + diff --git a/bin/gems/facets-3.1.0/demo/core/module/method_space.md b/bin/gems/facets-3.1.0/demo/core/module/method_space.md new file mode 100644 index 00000000..d949e8fa --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/module/method_space.md @@ -0,0 +1,24 @@ +## Module#method_space + + require 'facets/module/method_space' + + class A + attr_writer :x + method_space :inside do + def x; @x; end + end + end + + a = A.new + a.x = 10 + +We can see that the `inside` method space has access to the instance space. + + a.inside.x #=> 10 + +But there is no reader in the instance space. + + expect NoMethodError do + a.x + end + diff --git a/bin/gems/facets-3.1.0/demo/core/string/acronym.md b/bin/gems/facets-3.1.0/demo/core/string/acronym.md new file mode 100644 index 00000000..942d4eb3 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/acronym.md @@ -0,0 +1,9 @@ +## String#acronym + + require 'facets/string/acronym' + +Transform a string into an acronym. + + 'abc'.acronym.assert == 'a' + 'abc def'.acronym.assert == 'ad' + 'abc def ghi'.acronym.assert == 'adg' diff --git a/bin/gems/facets-3.1.0/demo/core/string/align.md b/bin/gems/facets-3.1.0/demo/core/string/align.md new file mode 100644 index 00000000..0dbf720b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/align.md @@ -0,0 +1,34 @@ +## String#align + + require 'facets/string/align' + +Align a string to a given position. This method simply delegates +to the other three more specific align methods. + + "xxx".align(:right, 9).assert == " xxx" + "xxx".align(:left, 9).assert == "xxx " + +## String#align_right + +Align a string to the right. The default alignment separation is +a newline ("\n"). This can be changed as can be the padding string +which defaults to a single space (' '). + + "xxx".align_right(9).assert == " xxx" + +## String#align_left + +Align a string to the left. The default alignment separation is a +newline ("\n"). This can be changed as can be the padding string +which defaults to a single space (' '). + + "xxx".align_left(9).assert == "xxx " + +## String#align_center + +Centers each line of a string. The default alignment separation is +a new line ("\n"). This can be changed as can be the padding string +which defaults to a single space (' '). + + "xxx".align_center(9).assert == " xxx " + diff --git a/bin/gems/facets-3.1.0/demo/core/string/ascii_only.md b/bin/gems/facets-3.1.0/demo/core/string/ascii_only.md new file mode 100644 index 00000000..7733034f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/ascii_only.md @@ -0,0 +1,37 @@ +## String#ascii_only + + require 'facets/string/ascii_only' + +Return a new string with non-ASCII characters removed. + + 'abc'.ascii_only.assert == 'abc' + '中文123'.ascii_only.assert == '123' + +Return a new string with non-ASCII characters replaced. + + '中文123'.ascii_only('!').assert == '!!123' + +## String#ascii_only! + +Modifiy string with non-ASCII chracters removed. + + s = 'abc' + s.ascii_only! + s.assert == 'abc' + + s = '中文123' + s.ascii_only! + s.assert == '123' + + +Modifiy string with non-ASCII chracters replaced. + + s = 'abc' + s.ascii_only!('!') + s.assert == 'abc' + + s = '中文123' + s.ascii_only!('!') + s.assert == '!!123' + + diff --git a/bin/gems/facets-3.1.0/demo/core/string/bracket.md b/bin/gems/facets-3.1.0/demo/core/string/bracket.md new file mode 100644 index 00000000..b104c84a --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/bracket.md @@ -0,0 +1,35 @@ +## String#bracket + + require 'facets/string/bracket' + + 'X'.bracket('#').assert == '#X#' + 'X'.bracket('x','!').assert == 'xX!' + 'X'.bracket('{','}').assert == '{X}' + 'X'.bracket('<').assert == '' + 'X'.bracket('(').assert == '(X)' + 'X'.bracket('[').assert == '[X]' + 'X'.bracket('{').assert == '{X}' + +## String#bracket! + + a = 'X' ; a.bracket!('#') + a.assert == '#X#' + + a = 'X' ; a.bracket!('x','!') + a.assert == 'xX!' + + a = 'X' ; a.bracket!('{','}') + a.assert == '{X}' + + a = 'X' ; a.bracket!('<') + a.assert == '' + + a = 'X' ; a.bracket!('(') + a.assert == '(X)' + + a = 'X' ; a.bracket!('[') + a.assert == '[X]' + + a = 'X' ; a.bracket!('{') + a.assert == '{X}' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/camelcase.md b/bin/gems/facets-3.1.0/demo/core/string/camelcase.md new file mode 100644 index 00000000..824cc3a1 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/camelcase.md @@ -0,0 +1,47 @@ +## String#Camelcase + + require 'facets/string/camelcase' + +The `camelcase` method converts snakecase strings into camelcase strings. + + "abc_xyz".camelcase.assert == "abcXyz" + +Continious underscore characters are treated as if a single underscore +character. + + "abc____xyz".camelcase.assert == "abcXyz" + +Without an argument the first character is left alone. + + "Camel_case".camelcase.assert == "CamelCase" + +Passing +:upper+ or +true+ to #camelcase captializes the first letter. +This is known as upper-camelcase. + + "Abc_xyz".camelcase(true).assert == "AbcXyz" + "Abc____xyz".camelcase(:upper).assert == "AbcXyz" + +Where as passing +false+ or +:lower+ downcases the first character, +known as lower-camelcase. + + "abc_xyz".camelcase(false).assert == "abcXyz" + "abc____xyz".camelcase(false).assert == "abcXyz" + "Abc_xyz".camelcase(:lower).assert == "abcXyz" + "Abc____xyz".camelcase(:lower).assert == "abcXyz" + +By passing a match string to the method we can make +camelcase+ +apply to each word in a string. + + "abc xyz".camelcase(' ').assert == "abcXyz" + "abc xyz".camelcase(/\s/).assert == "abcXyz" + "abc\txyz".camelcase(/\s/).assert == "abcXyz" + "abc\nxyz".camelcase(/\s/).assert == "abcXyz" + +## String#lower_camelcase + + "abc_xyz".lower_camelcase.assert == "abcXyz" + +## String#upper_camelcase + + "abc_xyz".upper_camelcase.assert == "AbcXyz" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/capitalized.md b/bin/gems/facets-3.1.0/demo/core/string/capitalized.md new file mode 100644 index 00000000..fce4a3ab --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/capitalized.md @@ -0,0 +1,27 @@ +## String#capitalized? + +String#capitalized? return true if a string begins with a capitalized +letter, false otherwise. + + require 'facets/string/capitalized' + + 'Abc'.assert.capitalized? + +## String#downcase? + +In addition String#downcase? is provided which checks to see if the +whole string is composed of lowercase letters. + + 'abc'.assert.downcase? + + #'abc'.assert.lowercase? + +## String#upcase? + +And String#upcase? which checks to see if the whole string is composed +of uppercase letters. + + 'ABC'.assert.upcase? + + #'ABC'.assert.uppercase? + diff --git a/bin/gems/facets-3.1.0/demo/core/string/characters.md b/bin/gems/facets-3.1.0/demo/core/string/characters.md new file mode 100644 index 00000000..85d75a6b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/characters.md @@ -0,0 +1,11 @@ +## String#characters + +The String#chars methods simply splits a string into +an Array of character strings. + + require 'facets/string/characters' + + "abc".characters.assert == ["a","b","c"] + + "ab\nc".characters.assert == ["a","b","\n","c"] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/cleanlines.md b/bin/gems/facets-3.1.0/demo/core/string/cleanlines.md new file mode 100644 index 00000000..706ae937 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/cleanlines.md @@ -0,0 +1,10 @@ +## String#cleanlines + +Thre String#cleanlines method works essentially the same as String#lines, +returning an Array of line strings, but it also removes trailing whitespace +from each line. + + require 'facets/string/cleanlines' + + "a \n b \nc".cleanlines.to_a.assert == ["a","b","c"] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/cleave.md b/bin/gems/facets-3.1.0/demo/core/string/cleave.md new file mode 100644 index 00000000..bac7aed4 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/cleave.md @@ -0,0 +1,49 @@ +## String#cleave + + require 'facets/string/cleave' + +no spaces short word + + s, x = 'whole', ['whole', ''] + s.cleave.assert == x + +no spaces long word + + s, x = 'Supercalifragilisticexpialidocious' , ['Supercalifragilisticexpialidocious', ''] + s.cleave.assert == x + +exact middle two words + + s, x = 'fancy split', ['fancy', 'split'] + s.cleave.assert == x + +exact middle many words + + s, x = 'All good Rubyists know how to party', ['All good Rubyists', 'know how to party'] + s.cleave.assert == x + +closer to start + + s, x = 'short splitter', ['short', 'splitter'] + s.cleave.assert == x + +closer to start + + s, x = 'Four score and seven years ago...', ['Four score and', 'seven years ago...'] + s.cleave.assert == x + +closer to start + + s, x = 'abc def ghijklm nop', ['abc def', 'ghijklm nop'] + s.cleave.assert == x + +closer to end + + s, x = 'extended split', ['extended', 'split'] + s.cleave.assert == x + +closer to end + + s, x = 'abc defghi jklm nop', [ 'abc defghi', 'jklm nop'] + s.cleave.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/string/compress_lines.md b/bin/gems/facets-3.1.0/demo/core/string/compress_lines.md new file mode 100644 index 00000000..46f78f2b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/compress_lines.md @@ -0,0 +1,22 @@ +## String#compress_lines + + require 'facets/string/compress_lines' + +Matches any whitespace (including newline) at beginning and end of lines, +and replaces with a single space. + + string = <<-QUERY.compress_lines + SELECT name + FROM users + QUERY + string.assert == "SELECT name FROM users" + +Matches any whitespace (including newline) at beginning and end of lines, +and removes it. + + string = <<-QUERY.compress_lines(false) + SELECT name + FROM users + QUERY + string.assert == "SELECT nameFROM users" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/crypt.md b/bin/gems/facets-3.1.0/demo/core/string/crypt.md new file mode 100644 index 00000000..0453e3b8 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/crypt.md @@ -0,0 +1,15 @@ +## String#crypt + + require 'facets/string/crypt' + +Adds a default salt to the built-in crypt method. + +NOTE: This method is not a common core extension and is not +loaded automatically when using require 'facets'. + + "abc".crypt('ZZ').assert.start_with?('ZZ') + + encrypted = "abc".crypt + salt = encrypted[0..1] + "abc".crypt(salt).assert == encrypted + diff --git a/bin/gems/facets-3.1.0/demo/core/string/divide.md b/bin/gems/facets-3.1.0/demo/core/string/divide.md new file mode 100644 index 00000000..e1fddcac --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/divide.md @@ -0,0 +1,9 @@ +## String#divide + + require 'facets/string/divide' + + s = "

Thisisa test.

" + d = s.divide(/<.*?>/) + e = ["

This", "is", "a test.", "

"] + d.assert == e + diff --git a/bin/gems/facets-3.1.0/demo/core/string/each_word.md b/bin/gems/facets-3.1.0/demo/core/string/each_word.md new file mode 100644 index 00000000..03abacb7 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/each_word.md @@ -0,0 +1,11 @@ +## String#each_word + + require 'facets/string/each_word' + + a = [] + i = "this is a test" + + i.each_word{ |w| a << w } + + a.assert == ['this', 'is', 'a', 'test'] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/edit_distance.md b/bin/gems/facets-3.1.0/demo/core/string/edit_distance.md new file mode 100644 index 00000000..ace30bbc --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/edit_distance.md @@ -0,0 +1,15 @@ +## String#edit_distance + + require 'facets/string/edit_distance' + +Levenshtein distance algorithm implementation for Ruby, with UTF-8 support. + +The Levenshtein distance is a measure of how similar two strings s and t are, +calculated as the number of deletions/insertions/substitutions needed to +transform s into t. The greater the distance, the more the strings differ. + + d = "pretzel".edit_distance('pretzil') + d.assert = 1 + + d = "zretzel".edit_distance('pretzil') + d.assert = 2 diff --git a/bin/gems/facets-3.1.0/demo/core/string/exclude.md b/bin/gems/facets-3.1.0/demo/core/string/exclude.md new file mode 100644 index 00000000..7ace5e20 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/exclude.md @@ -0,0 +1,15 @@ +## String#exclude? + + require 'facets/string/exclude' + +The inverse of include?. + + "aaaa".assert.exclude?('bb') + "aaab".assert.exclude?('bb') + "aaba".assert.exclude?('bb') + "baaa".assert.exclude?('bb') + + "abba".refute.exclude?('bb') + "aabb".refute.exclude?('bb') + "bbaa".refute.exclude?('bb') + diff --git a/bin/gems/facets-3.1.0/demo/core/string/expand_tabs.md b/bin/gems/facets-3.1.0/demo/core/string/expand_tabs.md new file mode 100644 index 00000000..cb8bee5f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/expand_tabs.md @@ -0,0 +1,69 @@ +## String#expand_tab + + require 'facets/string/expand_tab' + +We will use this string as a basis for demonstration. + + tabs = <<-EOF.gsub(/^\s+\|/, '') + | + |\tOne tab + | \tOne space and one tab + | \t Six spaces, a tab, and a space + EOF + +Expanding tabs 0. + + expected = <<-EOF.gsub(/^\s+\|/, '') + | + |One tab + | One space and one tab + | Six spaces, a tab, and a space + EOF + + tabs.expand_tabs(0).assert == expected + +Expanding tabs 1. + + expected = <<-EOF.gsub(/^\s+\|/, '') + | + | One tab + | One space and one tab + | Six spaces, a tab, and a space + EOF + + tabs.expand_tabs(1).assert == expected + +Expanding tabs 4. + + expected = <<-EOF.gsub(/^\s+\|/, '') + | + | One tab + | One space and one tab + | Six spaces, a tab, and a space + EOF + + tabs.expand_tabs(4).assert == expected + +Expanding tabs 8. + + expected = <<-EOF.gsub(/^\s+\|/, '') + | + | One tab + | One space and one tab + | Six spaces, a tab, and a space + EOF + + tabs.expand_tabs.assert == expected + tabs.expand_tabs(8).assert == expected + +Expanding tabs 16. + + expected = <<-EOF.gsub(/^\s+\|/, '') + | + | One tab + | One space and one tab + | Six spaces, a tab, and a space + EOF + + tabs.expand_tabs(16).assert == expected + diff --git a/bin/gems/facets-3.1.0/demo/core/string/fold.md b/bin/gems/facets-3.1.0/demo/core/string/fold.md new file mode 100644 index 00000000..f6731a64 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/fold.md @@ -0,0 +1,14 @@ +## String#fold + + require 'facets/string/fold' + + s = "This is\na test.\n\nIt clumps\nlines of text." + o = "This is a test.\n\nIt clumps lines of text." + s.fold.assert == o + +leave spaces + + s = "This is\na test.\n\n This is pre.\n Leave alone.\n\nIt clumps\nlines of text." + o = "This is a test.\n\n This is pre.\n Leave alone.\n\nIt clumps lines of text." + s.fold(true).assert == o + diff --git a/bin/gems/facets-3.1.0/demo/core/string/indent.md b/bin/gems/facets-3.1.0/demo/core/string/indent.md new file mode 100644 index 00000000..7ac44089 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/indent.md @@ -0,0 +1,65 @@ +## String#indent + + require 'facets/string/indent' + +positive + + "xyz".indent(4).assert == ' xyz' + " xyz".indent(2).assert == ' xyz' + +multiline positive + + "abc\nxyz".indent(2).assert == " abc\n xyz" + +zero + + 'xyz'.indent(0).assert == 'xyz' + +negative + + ' xyz'.indent(-2).assert == ' xyz' + ' xyz'. indent(-2).assert == 'xyz' + +multiline negative + + " abc\n xyz".indent(-2).assert == " abc\n xyz" + +negative more than is possible + + ' xyz'.indent(-3).assert == 'xyz' + +non-space positive + + "xyz".indent(4, '-').assert == '----xyz' + +non-space zero + + 'xyz'.indent(0, '-').assert == 'xyz' + +non-space negative non-matching character + + ' xyz'.indent(-2, '-').assert == ' xyz' + ' xyz'. indent(-2, '-').assert == ' xyz' + +non-space negative + + '----xyz'.indent(-2, '-').assert == '--xyz' + '--xyz'.indent(-2, '-').assert == 'xyz' + +Special regular expresion characters are escaped. + +Ensure '.' is treated literally and not as wildcard + + ' xyz'.indent(-2, '.').assert == ' xyz' + '..xyz'.indent(-2, '.').assert == 'xyz' + +Ensure '*' is treated literally and not as wildcard + + ' xyz'.indent(-2, '*').assert == ' xyz' + '**xyz'.indent(-2, '*').assert == 'xyz' + +Ensure '^' is treated literally and not as line start + + ' xyz'.indent(-2, '^').assert == ' xyz' + '^^xyz'.indent(-2, '^').assert == 'xyz' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/index_all.md b/bin/gems/facets-3.1.0/demo/core/string/index_all.md new file mode 100644 index 00000000..8d4d664e --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/index_all.md @@ -0,0 +1,14 @@ +## String#index_all + + require 'facets/string/index_all' + +Returns an array of all index locations. the reuse flag allows the trailing +portion of a match to be resued for subsequent matches. + + "abcabcabc".index_all('a') #=> [0,3,6] + + "a123a567a9".index_all(/a/) #=> [0,4,8] + + "bbb".index_all('bb', false) #=> [0] + "bbb".index_all('bb', true) #=> [0,1] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/interpolate.md b/bin/gems/facets-3.1.0/demo/core/string/interpolate.md new file mode 100644 index 00000000..27bae2b5 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/interpolate.md @@ -0,0 +1,8 @@ +## String#interpolate + + require 'facets/string/interpolate' + + a = 1 + + String.interpolate{ 'this is #{a}' }.assert == 'this is 1' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/lchomp.md b/bin/gems/facets-3.1.0/demo/core/string/lchomp.md new file mode 100644 index 00000000..2f482a55 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/lchomp.md @@ -0,0 +1,14 @@ +## String#lchomp + + require 'facets/string/lchomp' + + s = "xxboo" + r = s.lchomp("xx") + r.assert == "boo" + +## String#lchomp! + + s = "xxboo" + s.lchomp!("xx") + s.assert == "boo" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/line_wrap.md b/bin/gems/facets-3.1.0/demo/core/string/line_wrap.md new file mode 100644 index 00000000..1724c371 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/line_wrap.md @@ -0,0 +1,7 @@ +## String#line_wrap + + require 'facets/string/line_wrap' + + "abc123".line_wrap(3).assert == "abc\n123\n" + "abcd123".line_wrap(4).assert == "abcd\n123\n" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/lowercase.md b/bin/gems/facets-3.1.0/demo/core/string/lowercase.md new file mode 100644 index 00000000..fb1bde11 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/lowercase.md @@ -0,0 +1,12 @@ +## String#lowercase + + require 'facets/string/lowercase' + +Downcase the first letter. + + s = 'Abc' + s.lowercase.assert == 'abc' + + s = 'ABC' + s.lowercase.assert == 'aBC' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/methodize.md b/bin/gems/facets-3.1.0/demo/core/string/methodize.md new file mode 100644 index 00000000..0c9307e7 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/methodize.md @@ -0,0 +1,22 @@ +## String#methodize + + require 'facets/string/methodize' + +module name + + a = "FooBase" + r = "foo_base" + a.methodize.assert == r + +path name + + a = "foo/base" + r = "foo__base" + a.methodize.assert == r + +name space + + a = "Foo::Base" + r = "foo__base" + a.methodize.assert == r + diff --git a/bin/gems/facets-3.1.0/demo/core/string/modulize.md b/bin/gems/facets-3.1.0/demo/core/string/modulize.md new file mode 100644 index 00000000..309ed653 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/modulize.md @@ -0,0 +1,22 @@ +## String#modulize + + require 'facets/string/modulize' + +snakecase + + a = "foo_bar" + r = "FooBar" + a.modulize.assert == r + +path name + + a = "foo/bar" + r = "Foo::Bar" + a.modulize.assert == r + +on methodized string + + a = "foo__bar" + r = "Foo::Bar" + a.modulize.assert == r + diff --git a/bin/gems/facets-3.1.0/demo/core/string/mscan.md b/bin/gems/facets-3.1.0/demo/core/string/mscan.md new file mode 100644 index 00000000..6d8c497f --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/mscan.md @@ -0,0 +1,10 @@ +## String#mscan + + require 'facets/string/mscan' + + r = 'abc,def,gh'.mscan(/[,]/) + assert( r.all?{ |md| MatchData === md } ) + r.to_a.length.assert == 2 + r[0][0].assert == ',' + r[1][0].assert == ',' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/natcmp.md b/bin/gems/facets-3.1.0/demo/core/string/natcmp.md new file mode 100644 index 00000000..f6428552 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/natcmp.md @@ -0,0 +1,10 @@ +## String#natcmp + + require 'facets/string/natcmp' + + "my_prog_v1.1.0".natcmp( "my_prog_v1.2.0").assert == -1 + "my_prog_v1.2.0".natcmp("my_prog_v1.10.0").assert == -1 + "my_prog_v1.2.0".natcmp( "my_prog_v1.1.0").assert == 1 + "my_prog_v1.10.0".natcmp("my_prog_v1.2.0").assert == 1 + "my_prog_v1.0.0".natcmp( "my_prog_v1.0.0").assert == 0 + diff --git a/bin/gems/facets-3.1.0/demo/core/string/nchar.md b/bin/gems/facets-3.1.0/demo/core/string/nchar.md new file mode 100644 index 00000000..eb977116 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/nchar.md @@ -0,0 +1,9 @@ +## String#nchar + + require 'facets/string/nchar' + + "abcxyz".nchar(3).assert == "abc" + "abcxyz".nchar(-3).assert == "xyz" + "abcxyz".nchar(3, 'HI').assert == "HIxyz" + "abcxyz".nchar(-3, 'HI').assert == "abcHI" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/newlines.md b/bin/gems/facets-3.1.0/demo/core/string/newlines.md new file mode 100644 index 00000000..e1e278ce --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/newlines.md @@ -0,0 +1,9 @@ +## String#newlines + +Since Ruby 1.9 defined #lines to keep the newline character, +we have defined #newlines to leave them out. + + require 'facets/string/newlines' + + "a\nb\nc".newlines.to_a.assert == ["a","b","c"] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/number.md b/bin/gems/facets-3.1.0/demo/core/string/number.md new file mode 100644 index 00000000..50f3302c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/number.md @@ -0,0 +1,27 @@ +## String#number? + + require 'facets/string/number' + +Returns true if its a decimal number + + x = "1.23\n" + x.number?.assert == true + + x = "123_456_789_123_456_789.123_456_000_111\n" + x.number?.assert == true + + x = ".123\n" + x.number?.assert == false + + x = "123_\n" + x.number?.assert == false + + x = "_123\n" + x.number?.assert == false + + x = "23_456_789_123_456_.245\n" + x.number?.assert == false + + x = "23_456_789_123_456._245\n" + x.number?.assert == false + diff --git a/bin/gems/facets-3.1.0/demo/core/string/op_div.md b/bin/gems/facets-3.1.0/demo/core/string/op_div.md new file mode 100644 index 00000000..61955c7d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/op_div.md @@ -0,0 +1,10 @@ +## String#op_div + + require 'facets/string/op_div' + +Treats +self+ and +path+ as representations of pathnames, joining thme together +as a single path. + + ('merb' / 'string').assert == "merb/string" + ('merb' / :symbol).assert == "merb/symbol" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/op_sub.md b/bin/gems/facets-3.1.0/demo/core/string/op_sub.md new file mode 100644 index 00000000..eb127618 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/op_sub.md @@ -0,0 +1,7 @@ +## String#- + + require 'facets/string/op_sub' + + s = "xxbooxxfoo" + (s - "xx").assert == "boofoo" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/pathize.md b/bin/gems/facets-3.1.0/demo/core/string/pathize.md new file mode 100644 index 00000000..dfc67cad --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/pathize.md @@ -0,0 +1,22 @@ +## String#pathize + + require 'facets/string/pathize' + +module name + + a = "Foo::Base" + x = "foo/base" + a.pathize.assert == x + +path name + + a = "foo/base" + x = "foo/base" + a.pathize.assert == x + +name space + + a = "foo__base" + x = "foo/base" + a.pathize.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/string/quote.md b/bin/gems/facets-3.1.0/demo/core/string/quote.md new file mode 100644 index 00000000..29401326 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/quote.md @@ -0,0 +1,20 @@ +## String#quote + + require 'facets/string/quote' + +The default is single quotes. + + 'hi'.quote.assert == %{"hi"} + +The type of quotes can be specified by name. + + 'hi'.quote(:single).assert == %{'hi'} + 'hi'.quote(:double).assert == %{"hi"} + 'hi'.quote(:back).assert == %{`hi`} + +They can also be specified by the first character of the name. + + 'hi'.quote(:s).assert == %{'hi'} + 'hi'.quote(:d).assert == %{"hi"} + 'hi'.quote(:b).assert == %{`hi`} + diff --git a/bin/gems/facets-3.1.0/demo/core/string/random.md b/bin/gems/facets-3.1.0/demo/core/string/random.md new file mode 100644 index 00000000..bf5db08b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/random.md @@ -0,0 +1,25 @@ +## String#random + + require 'facets/string/random' + +Generates a random string of given length, using given character set + + s = String.random + # "D9DxFIaqR3dr8Ct1AfmFxHxqGsmA4Oz3" + s.assert =~ /^[0-9a-zA-Z]{32}$/ + + s = String.random(10) + # "t8BIna341S" + s.assert =~ /^[0-9a-zA-Z]{10}$/ + + s = String.random(10, ['a'..'z']) + # "nstpvixfri" + s.assert =~ /^[a-z]{10}$/ + + s = String.random(10, ['0'..'9'] ) + # "0982541042" + s.assert =~ /^[0-9]{10}$/ + + s = String.random(10, ['0'..'9','A'..'F'] ) + # "3EBF48AD3D" + s.assert =~ /^[0-9A-F]{10}$/ diff --git a/bin/gems/facets-3.1.0/demo/core/string/range.md b/bin/gems/facets-3.1.0/demo/core/string/range.md new file mode 100644 index 00000000..a9819291 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/range.md @@ -0,0 +1,19 @@ +## String#range + + require 'facets/string/range' + + "a123a567a9".range(/123/).assert == (1..3) + "a123a567a9".range(/a/).assert == (0..0) + +## String#range_all + + "a123a123a9".range_all(/123/).assert == [ (1..3), (5..7) ] + "a123a567a9".range_all(/a/).assert == [ (0..0), (4..4), (8..8) ] + +## String#range_of_line + + a = "0123\n456\n78" + x = [0..4, 5..8, 9..10] + r = a.range_of_line + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/string/remove.md b/bin/gems/facets-3.1.0/demo/core/string/remove.md new file mode 100644 index 00000000..158a6927 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/remove.md @@ -0,0 +1,33 @@ +## String#remove + + require 'facets/string/remove' + +Removes all occurances of a string or pattern from a string. + + s = 'xxbooxxfoo' + s.remove('xx').assert == 'boofoo' + + s = 'xxbooxxfoo' + s.remove(/x{1,2}/).assert == 'boofoo' + +## String#remove! + + s = 'xxbooxxfoo' + s.remove!('xx') + s.assert == 'boofoo' + + s = 'xxbooxxfoo' + s.remove!(/x{1,2}/) + s.assert == 'boofoo' + + +## String#op_minus (-) + + s = 'xxbooxxfoo' + (s - 'xx').assert == 'boofoo' + + s = 'xxbooxxfoo' + (s - /x{1,2}/).assert == 'boofoo' + + + diff --git a/bin/gems/facets-3.1.0/demo/core/string/rewrite.md b/bin/gems/facets-3.1.0/demo/core/string/rewrite.md new file mode 100644 index 00000000..45a84d60 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/rewrite.md @@ -0,0 +1,9 @@ +## String#rewrite + + require 'facets/string/rewrite' + + s = "HELLO TOMMY!" + rules = [[ /TOMMY/, 'MAN' ]] + r = s.rewrite(rules) + r.assert == "HELLO MAN!" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/shatter.md b/bin/gems/facets-3.1.0/demo/core/string/shatter.md new file mode 100644 index 00000000..c472f66c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/shatter.md @@ -0,0 +1,9 @@ +## String#shatter + + require 'facets/string/shatter' + + s = "

Thisisa test.

" + r = s.shatter( /<.*?>/ ) + x = ["

", "This", "", "is", "", "a test.", "

"] + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/string/similarity.md b/bin/gems/facets-3.1.0/demo/core/string/similarity.md new file mode 100644 index 00000000..72ce7a39 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/similarity.md @@ -0,0 +1,12 @@ +## String#similarity + + require 'facets/string/similarity' + +A fuzzy matching mechanism. Returns a score from 0-1, based on the number of +shared edges. To be effective, the strings must be of length 2 or greater. + + "Alexsander".similarity("Aleksander").assert == 0.9 + + "Alexander".similarity("Alexander").assert == 1.0 + + "Alexander".similarity("").assert == 0.0 diff --git a/bin/gems/facets-3.1.0/demo/core/string/snakecase.md b/bin/gems/facets-3.1.0/demo/core/string/snakecase.md new file mode 100644 index 00000000..0c9bd4ca --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/snakecase.md @@ -0,0 +1,14 @@ +## String#snakecase + + require 'facets/string/snakecase' + +Underscore a string such that camelcase, dashes and spaces are +replaced by underscores. This is the reverse of {#camelcase}, +albeit not an exact inverse. + + 'my_name'.snakecase.assert == 'my_name' + + 'MyName'.snakecase.assert == 'my_name' + + 'URI'.snakecase.assert == 'uri' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/splice.md b/bin/gems/facets-3.1.0/demo/core/string/splice.md new file mode 100644 index 00000000..692559f8 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/splice.md @@ -0,0 +1,28 @@ +## String#splice + + require 'facets/string/splice' + + a = "HELLO" + a.splice(1).assert == "E" + a.assert == "HLLO" + +range + + a = "HELLO" + a.splice(1..2).assert == "EL" + a.assert == "HLO" + +store + + a = "HELLO" + a.splice(1, "X") + a.assert == "HXLLO" + +This could be done if class of 2nd arg is checked. + + #Unit :splice_length + # a = "HELLO" + # a.splice(1,2).assert == "EL" + # a.assert == "HLO" + #end + diff --git a/bin/gems/facets-3.1.0/demo/core/string/squish.md b/bin/gems/facets-3.1.0/demo/core/string/squish.md new file mode 100644 index 00000000..344395fb --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/squish.md @@ -0,0 +1,27 @@ +## String#squish + + require 'facets/string/squish' + +Returns the string, first removing all whitespace on both ends of the string, +and then changing remaining consecutive whitespace groups into one space each. + + r = %{ Multi-line + string }.squish + r.assert == "Multi-line string" + + r = " foo bar \n \t boo".squish + r.assert == "foo bar boo" + +## String#squish! + +Performs a destructive squish. See String#squish. + + r = %{ Multi-line + string } + r.squish! + r.assert == "Multi-line string" + + r = " foo bar \n \t boo" + r.squish! + r.assert == "foo bar boo" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/store.md b/bin/gems/facets-3.1.0/demo/core/string/store.md new file mode 100644 index 00000000..d4f5cb60 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/store.md @@ -0,0 +1,10 @@ +## String#store + + require 'facets/string/store' + +Alias for []= + + a = "HELLO" + a.store(1, "X") + a.assert == "HXLLO" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/subtract.md b/bin/gems/facets-3.1.0/demo/core/string/subtract.md new file mode 100644 index 00000000..4e5f1590 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/subtract.md @@ -0,0 +1,8 @@ +## String#- + + require 'facets/string/subtract' + + ("foobar" - "oo").assert == "fbar" + ("pizza pizza!" - "zz").assert == "pia pia!" + ("letters" - /[a-z]+/).assert == "" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/titlecase.md b/bin/gems/facets-3.1.0/demo/core/string/titlecase.md new file mode 100644 index 00000000..fcc93f12 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/titlecase.md @@ -0,0 +1,8 @@ +## String#titlecase + + require 'facets/string/titlecase' + + r = "try this out".titlecase + x = "Try This Out" + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/core/string/to_re.md b/bin/gems/facets-3.1.0/demo/core/string/to_re.md new file mode 100644 index 00000000..a21ab50b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/to_re.md @@ -0,0 +1,22 @@ +## String#to_re + + require 'facets/string/to_re' + + "abc".to_re.assert == /abc/ + "a+bc".to_re.assert == /a+bc/ + "a+bc".to_re(false).assert == /a+bc/ + "a+bc".to_re(true).assert == /a\+bc/ + +escaped characters + + a = "?" + b = /#{a.to_rx}/ + assert( b =~ "?" ) + +## String#to_rx + + "abc".to_rx.assert == /abc/ + "a+bc".to_rx.assert == /a\+bc/ + "a+bc".to_rx(false).assert == /a+bc/ + "a+bc".to_rx(true).assert == /a\+bc/ + diff --git a/bin/gems/facets-3.1.0/demo/core/string/trim.md b/bin/gems/facets-3.1.0/demo/core/string/trim.md new file mode 100644 index 00000000..dec12487 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/trim.md @@ -0,0 +1,92 @@ +## String#trim + + require 'facets/string/trim' + + s = %q{ + |ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + + s = %q{ + |ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + + s = %q{|ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + + s = %q{ + |ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + + s = %q{|ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + + s = %q{ |ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + + s = %q{ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + +spacing + + s = %q{ + | ABC + | 123 + | TEST + }.trim + s.assert == " ABC\n 123\n TEST" + + s = %q{ + |ABC + |123 + |TEST + }.trim(1) + s.assert == " ABC\n 123\n TEST" + + s = %q{ + |ABC + |123 + |TEST + }.trim(2) + s.assert == " ABC\n 123\n TEST" + + s = %q{ ABC + - 123 + - TEST + }.trim + s.assert == " ABC\n 123\n TEST" + +random placement + + @volly = {} + 100.times{ |n| + k = [] + a = [] + 5.times{ |i| + k << ( ( ' ' * Integer(rand*10) ) + '|' + i.to_s ) + a << ( i.to_s ) + } + @volly[k.join("\n")] = a.join("\n") + } + + @volly.each{ |k,v| + k.trim.assert == v + } + diff --git a/bin/gems/facets-3.1.0/demo/core/string/unbracket.md b/bin/gems/facets-3.1.0/demo/core/string/unbracket.md new file mode 100644 index 00000000..e59a276a --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/unbracket.md @@ -0,0 +1,24 @@ +## String#unbracket + + require 'facets/string/unbracket' + +Remove matched paits of brackets from a string + + s = "{unwrap me}" + z = s.unbracket('{') + z.assert == "unwrap me" + + s = "--unwrap me!" + z = s.unbracket('--','!') + z.assert == "unwrap me" + +## String#unbracket! + + s = "{unwrap me}" + s.unbracket!('{') + s.assert == "unwrap me" + + s = "--unwrap me!" + s.unbracket!('--','!') + s.assert == "unwrap me" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/underscore.md b/bin/gems/facets-3.1.0/demo/core/string/underscore.md new file mode 100644 index 00000000..5d59e04d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/underscore.md @@ -0,0 +1,17 @@ +## String#underscore + + require 'facets/string/underscore' + +Underscore a string such that camelcase, dashes and spaces are +replaced by underscores. This is the reverse of {#camelcase}, +albeit not an exact inverse. + +Note, this method no longer converts `::` to `/`, in that case +use the {#pathize} method instead. + + 'my_name'.underscore.assert == 'my_name' + + 'MyName'.underscore.assert == 'my_name' + + 'URI'.underscore.assert == 'uri' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/unfold.md b/bin/gems/facets-3.1.0/demo/core/string/unfold.md new file mode 100644 index 00000000..59e9c8d8 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/unfold.md @@ -0,0 +1,9 @@ +## String#unfold + + require 'facets/string/unfold' + + str = "This is a test of\nparagraph folding." + res = str.unfold + exp = "This is a test of paragraph folding." + res.assert == exp + diff --git a/bin/gems/facets-3.1.0/demo/core/string/unindent.md b/bin/gems/facets-3.1.0/demo/core/string/unindent.md new file mode 100644 index 00000000..c935d93b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/unindent.md @@ -0,0 +1,65 @@ +## String#unindent + + require 'facets/string/unindent' + +We will use these two strings as a common basis for demonstration. + + ex1 = <<-EOF.gsub(/^\s*\|/,'') + | I must go down to the seas again + | The lonely sea and the sky + | And all I want is a tall ship + | And a star to steer her by + EOF + + ex2 = <<-EOF.gsub(/^\s*\|/,'') + | "Eek!" + | She cried + | As the mouse quietly scurried + |by. + EOF + +simple examples + + " xyz".unindent(-1).assert == " xyz" + " xyz".unindent(0).assert == " xyz" + " xyz".unindent(1).assert == " xyz" + " xyz".unindent(2).assert == " xyz" + " xyz".unindent(3).assert == "xyz" + " xyz".unindent(4).assert == "xyz" + +large example unindented one space + + expected = <<-EOF.gsub(/^\s*\|/,'') + | I must go down to the seas again + | The lonely sea and the sky + | And all I want is a tall ship + | And a star to steer her by + EOF + + actual = ex1.unindent(1) + actual.assert == expected + +large example unindented four spaces + + expected = <<-EOF.gsub(/^\s*\|/,'') + |I must go down to the seas again + | The lonely sea and the sky + |And all I want is a tall ship + | And a star to steer her by + EOF + + actual = ex1.unindent(4) + actual.assert == expected + +unindent larger than current indention + + expected = <<-EOF.gsub(/^\s*\|/,'') + |"Eek!" + |She cried + |As the mouse quietly scurried + |by. + EOF + + actual = ex2.unindent(100) + actual.assert == expected + diff --git a/bin/gems/facets-3.1.0/demo/core/string/unquote.md b/bin/gems/facets-3.1.0/demo/core/string/unquote.md new file mode 100644 index 00000000..26e86b3d --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/unquote.md @@ -0,0 +1,6 @@ +## String#unquote + + require 'facets/string/unquote' + + "'this'".unquote.assert == "this" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/uppercase.md b/bin/gems/facets-3.1.0/demo/core/string/uppercase.md new file mode 100644 index 00000000..83560287 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/uppercase.md @@ -0,0 +1,15 @@ +## String#uppercase + + require 'facets/string/uppercase' + +Upcase the first letter. + + s = 'bob' + s.uppercase.assert == 'Bob' + + s = 'boB' + s.uppercase.assert == 'BoB' + + s = 'BoB' + s.uppercase.assert == 'BoB' + diff --git a/bin/gems/facets-3.1.0/demo/core/string/variablize.md b/bin/gems/facets-3.1.0/demo/core/string/variablize.md new file mode 100644 index 00000000..849fa38b --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/variablize.md @@ -0,0 +1,7 @@ +## String#variablize + + require 'facets/string/variablize' + + s = "a" + s.variablize.assert == "@a" + diff --git a/bin/gems/facets-3.1.0/demo/core/string/word_wrap.md b/bin/gems/facets-3.1.0/demo/core/string/word_wrap.md new file mode 100644 index 00000000..a0a1e5cd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/word_wrap.md @@ -0,0 +1,54 @@ +## String#word_wrap + + require 'facets/string/word_wrap' + + e = "abcde\n12345\nxyzwu\n" + r = "abcde 12345 xyzwu".word_wrap(5) + r.assert == e + + e = "abcd\n1234\nxyzw\n" + r = "abcd 1234 xyzw".word_wrap(4) + r.assert == e + + e = "abc\n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + + e = "abc \n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + + e = "abc \n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + +## String#word_wrap! + + w = "abcde 12345 xyzwu" + w.word_wrap!(5) + w.assert == "abcde\n12345\nxyzwu\n" + + w = "abcd 1234 xyzw" + w.word_wrap!(4) + w.assert == "abcd\n1234\nxyzw\n" + + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc\n123\n" + + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc \n123\n" + + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc \n123\n" + + # Unit :word_wrap do + # assert_equal "abcde-\n12345-\nxyzwu\n", "abcde12345xyzwu".word_wrap(6,2) + # assert_equal "abcd-\n1234-\nxyzw\n", "abcd1234xyzw".word_wrap(5,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # end + diff --git a/bin/gems/facets-3.1.0/demo/core/string/words.md b/bin/gems/facets-3.1.0/demo/core/string/words.md new file mode 100644 index 00000000..037d61f6 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/words.md @@ -0,0 +1,13 @@ +## String#words + + require 'facets/string/words' + + x = "a b c\nd e" + x.words.assert == ['a','b','c','d','e'] + + x = "ab cd\nef" + x.words.assert == ['ab','cd','ef'] + + x = "ab cd \n ef-gh" + x.words.assert == ['ab','cd','ef-gh'] + diff --git a/bin/gems/facets-3.1.0/demo/core/string/xor.md b/bin/gems/facets-3.1.0/demo/core/string/xor.md new file mode 100644 index 00000000..720f78f9 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/core/string/xor.md @@ -0,0 +1,8 @@ +## String#^ + + require 'facets/string/xor' + + r = "try this out" ^ "puddingsnacks" + x = "\004\a\035D\035\006\016\000N\016\026\037" + r.assert == x + diff --git a/bin/gems/facets-3.1.0/demo/standard/02_cloneable.rdoc b/bin/gems/facets-3.1.0/demo/standard/02_cloneable.rdoc new file mode 100644 index 00000000..b2c3b4d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/02_cloneable.rdoc @@ -0,0 +1,46 @@ += Cloneable + +Require the library. + + require 'facets/cloneable' + +We'll use this dummy class. + + class Foo + include Cloneable + def initialize + @bar=[] + end + def bar_id + @bar.object_id + end + end + +Try #dup. + + a = Foo.new + b = a.dup + b.bar_id.refute == a.bar_id + + a.taint + b = a.dup + b.assert.tainted? + + a.freeze + b = a.dup + b.refute.frozen? + +Note try #clone. + + a = Foo.new + b = a.clone + b.bar_id.refute == a.bar_id + + a.taint + b = a.dup + b.assert.tainted? + + a.freeze + b = a.clone + b.assert.frozen? + diff --git a/bin/gems/facets-3.1.0/demo/standard/03_enumargs.rdoc b/bin/gems/facets-3.1.0/demo/standard/03_enumargs.rdoc new file mode 100644 index 00000000..c215dfdd --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/03_enumargs.rdoc @@ -0,0 +1,75 @@ += Enumerable::Arguments + +Require the library. + + require 'facets/enumargs' + +This will serve as our example class. + + class PlusArray + include Enumerable::Arguments + + def initialize(arr) + @arr = arr + end + + def each(n=0) + @arr.each{ |e| yield(e+n) } + end + end + +Now Enumerable methods such as #map and #collect +take an argument as well. + + t = PlusArray.new([1,2,3]) + t.collect(4){ |e| e }.assert == [5,6,7] + +Filtering methods such as #select and reject work +as well. + + t = PlusArray.new([1,2,3]) + t.select(4){ |x| x == 6 }.assert == [6] + + t = PlusArray.new([1,2,3]) + t.reject(4){ |x| x == 6 }.assert == [5,7] + +We can covert to an array using #to_a with an argument. + + t = PlusArray.new([1,2,3]) + t.to_a(4).assert == [5,6,7] + +We can get the minimum value using #min. + + t = PlusArray.new([1,2,3]) + t.min(4).assert == 5 + +And get the maximum value using #min. + + t = PlusArray.new([1,2,3]) + t.max(4).assert == 7 + +Methods that already take and argument, now take two +such as #include? + + t = PlusArray.new([1,2,3]) + t.assert.include?(7,4) + +And #each_slice. + + t = PlusArray.new([1,2,3,4]) + a = [] + t.each_slice(2,4){ |e,f| a << [e,f] } + a.assert == [[5,6],[7,8]] + +The #find method has a slightly different interface +than the original Enumerable. + + t = PlusArray.new([1,2,3,4]) + f = t.find(2, :ifnone=>lambda{:NOPE}) { |a| a == 10 } + f.assert == :NOPE + +The #grep method should also work. + + t = PlusArray.new(['a1','b2','a3','b4']) + t.grep(/^b/, 'x').assert == ['b2x','b4x'] + diff --git a/bin/gems/facets-3.1.0/demo/standard/04_equitable.rdoc b/bin/gems/facets-3.1.0/demo/standard/04_equitable.rdoc new file mode 100644 index 00000000..11c2722c --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/04_equitable.rdoc @@ -0,0 +1,35 @@ += Equitqable + +Require the library. + + require 'facets/equitable' + +We will use this simple class as an example. + + class C + include Equitable(:a,:b) + + attr_accessor :a, :b + + def initialize(a,b) + @a = a + @b = b + end + end + +Now, if two instance of our sample class +C+ have +equal attributes +@a+ and +@b+ then they will +be equal. + + c1 = C.new(10,20) + c2 = C.new(10,20) + c2.assert == c1 + +Otherwise they will not be equal. + + c1 = C.new(10, 10) + c2 = C.new(10, 20) + c2.refute == c1 + + + diff --git a/bin/gems/facets-3.1.0/demo/standard/05_instantiable.rdoc b/bin/gems/facets-3.1.0/demo/standard/05_instantiable.rdoc new file mode 100644 index 00000000..6c73fffc --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/05_instantiable.rdoc @@ -0,0 +1,42 @@ += Instantiable + +Require the library. + + require 'facets/instantiable' + +We will use this module as an example. + + module M + include Instantiable + + attr :a + + def initialize(a) + @a = a + end + end + +As we can see M is now fully instantiable, as any +class would be. + + m = M.new(1) + m.a.assert == 1 + +We can also use #extend rather than #include and +get the same result. + + module N + extend Instantiable + + attr :a + + def initialize( a ) + @a = a + end + end + +As we saw with +M+ so too with +N+. + + n = N.new( 1 ) + n.a.assert == 1 + diff --git a/bin/gems/facets-3.1.0/demo/standard/basic_object.rdoc b/bin/gems/facets-3.1.0/demo/standard/basic_object.rdoc new file mode 100644 index 00000000..9e3aa7d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/basic_object.rdoc @@ -0,0 +1,22 @@ +== BasicObject + + require 'facets/basicobject' + + o = Class.new(BasicObject).new + +Should ignore new kernel methods. + + Kernel.module_eval { def xxx ; end } + + expect NoMethodError do + o.xxx + end + +Should ignore new object methods. + + Object.class_eval { def yyy ; end } + + expect NoMethodError do + o.yyy + end + diff --git a/bin/gems/facets-3.1.0/demo/standard/memoizable.rdoc b/bin/gems/facets-3.1.0/demo/standard/memoizable.rdoc new file mode 100644 index 00000000..51ef2850 --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/memoizable.rdoc @@ -0,0 +1,134 @@ += Memoizable + +Memoizable allows + + require 'facets/memoizable' + +The classic example is calculating the Fibonacci sequence. + + class Fibonacci + include Memoizable + + def fib( num ) + return num if num < 2 + fib(num - 1) + fib(num - 2) + end + + memoize :fib + end + +The first time will take a moment to calculate. + + f = Fibonacci.new + f.fib(100) + +The second time will be returned almost instantly. + + f = Fibonacci.new + f.fib(100) + +The following example makes if very clear what memoize is doing. + + class MemoExample + include Memoizable + attr_accessor :a + memoize :a + end + + m = MemoExample.new + m.a = 10 + m.a #=> 10 + m.a = 20 + m.a #=> 10 + +Even though @a is assigned to 20, the method #a continues to return 10. + +Memoizable is designed to handle a number of typically problematic aspects +of memoization implementations. First a memoizable object can be frozen. + + f = Fibonacci.new + f.freeze + f.fib(100) + +Memoizable objects are freezable because it does not use an instance variable +to store the memoized return values. Instead it uses a global class instance +variable in +Memoizable.cache+. + +However, this also means the memoization cache is not preserved when an object +is duplicated. If this behavior is desired an aditional module is provided +called `Memoizable::Copy`. When the `Memoiazble::Copy` module is included into +a class it not only adds the #memoize class methods but also includes +an #initialize_copy method, which copies the appropriate cache entries when +#dup or #clone is used. Keep this in mind. It is important to call #super if you +override the #initialize_copy method in a class that uses `Memoizable::Copy`. + + class MemoExample2 + include Memoizable::Copy + attr_accessor :a + memoize :a + end + + m = MemoExample2.new + m.a = 10 + m.a #=> 10 + + n = m.dup + n.a = 20 + n.a #=> 10 + +The `#memoize` method also accepts a few options that can be used to modify +the behvior of the memoizaiton. To memoize a method across all objects +of the same class and not just per-object, set the `:class` option to true. + + class MemoExample3 + include Memoizable + attr_accessor :a + memoize :a, :class=>true + end + + m = MemoExample3.new + m.a = 10 + m.a #=> 10 + + n = MemoExample3.new + n.a #=> 10 + +Memoization is indexed based on arguments passed to the method, as can be seen +in the Fibonacci example. Methods can also be memoized by name only, forgoing +any indexing based on arguments passed. To do this, set the `:arguments` +option to +false+. + + class MemoExample4 + include Memoizable + def f(n) + n + n + end + memoize :f, :arguments=>false + end + + m = MemoExample4.new + m.f(1) + m.f(2) #=> 2 + m.f(3) #=> 2 + +Blocks passed to a method normally have only a present vs. non-present effect +on the memoization index. In other words the return value of a method will be +cached under one key if a block is passed to it and under a different index +if not. It doesn't matter if blocks passed in actually differ, since +the only way to compare blocks is by their +object_id+ and it is very rare +for the exact same block object to be reused. + +Finally, the `:freeze` option can be used to freeze the memoized results. + + class MemoExample5 + include Memoizable + def f(n) + (n + n).to_s + end + memoize :f, :freeze=>true + end + + m = MemoExample5.new + m.f(1).frozen? #=> true + m.f(2).frozen? #=> true + diff --git a/bin/gems/facets-3.1.0/demo/standard/mulititon.rdoc b/bin/gems/facets-3.1.0/demo/standard/mulititon.rdoc new file mode 100644 index 00000000..17db2ffe --- /dev/null +++ b/bin/gems/facets-3.1.0/demo/standard/mulititon.rdoc @@ -0,0 +1,156 @@ += Multiton + +The Multion pattern is essentially the same as the Singleton pattern, but +unlike it's fully unique brethren Multiton's are identical if their +initialization parameters are identical. + +To demontrate we first need to load the Facets multiton.rb script. + + require 'facets/multiton' + +Now for the various exmples. + + +== EXAMPLE A - STANDARD USAGE + + class SomeMultitonClass + include Multiton + + attr :arg + def initialize(arg) + @arg = arg + end + end + + a = SomeMultitonClass.instance(4) + b = SomeMultitonClass.instance(4) # a and b are same object + c = SomeMultitonClass.instance(2) # c is a different object + + a.assert == b + + x = [a.arg, b.arg].max * 10 + c.arg + x.assert == 42 + + +== EXAMPLE B - MODIFY AN EXISTING CLASS + +We can modify an existing class (if we are so bold), for example we can +add shared filehandles to the File class. + + class ::File + include Multiton + end + + lineno = __LINE__ + # HERE1 + # HERE2 + + a = File.instance(__FILE__) + b = File.instance(__FILE__) + + b.assert == a + + lineno.times{ a.gets } + + a.gets.strip.assert == "# HERE1" + b.gets.strip.assert == "# HERE2" + + +== EXAMPLE C - INHERITENCE + + class A < String + include Multiton + end + + # B is also a multiton - with it's OWN object cache + class B < A; end + + # w is the same object as x, y is the same object as z + w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B') + + x.object_id.assert == w.object_id + z.object_id.assert == y.object_id + + a = B.instance('A') + b = B.instance('A') + + w.object_id.refute == a.object_id # (each class has it's own pool) + b.object_id.assert == a.object_id + + +== EXAMPLE D - MULTIPLE MODULE INCLUSION (does nothing) + + class A < String + include Multiton + end + + # B is also a multiton - with it's OWN object cache + class B < A; end + + + # w is the same object as x, y is the same object as z + w,x,y,z = A.instance('A'), A.instance('A'), B.instance('B'), B.instance('B') + + yz_id = y.object_id || z.object_id + +If we include Multiton again, it will have to effect. + + B.class_eval { + include Multiton + } + + # y is not only the same object as z, but they are both the same object(s) + # as from EXAMPLE C + + y,z = B.instance('B'), B.instance('B') + + yz_id.assert == y.object_id + yz_id.assert == z.object_id + + +== EXAMPLE E - SO YOU WANNA USE NEW INSTEAD OF INSTANCE + + module K + # use an inner class which is itself a multiton + class K < String; include Multiton; end + + # define a new which returns a mutltion using #instance... + class << self + def new(*args, &block) + K.instance(*args, &block) + end + end + end + + the = K.new '4' + answer = K.new '2' + + x = sprintf( "%s%s", the, answer ) + x.assert == "42" + the.class.assert == K::K + + +== EXAMPLE F - using Klass.multiton_id + + class Klass + include Multiton + + def initialize( important, not_important ) + @important, @not_important = important, not_important + end + + def Klass.multiton_id(*args, &block) + # we consider only the first arg + important, not_important = *args + important + end + end + + a = Klass.instance( :a, :b ) + b = Klass.instance( :a, :c ) + c = Klass.instance( :b, :b ) + + a.assert == b + c.refute == a + c.refute == b + diff --git a/bin/gems/facets-3.1.0/lib/core/facets.rb b/bin/gems/facets-3.1.0/lib/core/facets.rb new file mode 100644 index 00000000..79f88c57 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets.rb @@ -0,0 +1,40 @@ +require 'facets/version.rb' + +require 'facets/array.rb' +require 'facets/binding.rb' +require 'facets/boolean.rb' +require 'facets/class.rb' +require 'facets/comparable.rb' +require 'facets/denumerable.rb' +require 'facets/dir.rb' +require 'facets/enumerable.rb' +require 'facets/enumerator.rb' +require 'facets/exception.rb' +require 'facets/file.rb' +require 'facets/filetest.rb' +require 'facets/float.rb' +require 'facets/functor.rb' +require 'facets/hash.rb' +require 'facets/indexable.rb' +require 'facets/integer.rb' +require 'facets/kernel.rb' +require 'facets/lazy.rb' +require 'facets/matchdata.rb' +require 'facets/method.rb' +require 'facets/module.rb' +require 'facets/na.rb' +require 'facets/nilclass.rb' +require 'facets/numeric.rb' +require 'facets/object.rb' +require 'facets/objectspace.rb' +require 'facets/proc.rb' +require 'facets/process.rb' +require 'facets/range.rb' +require 'facets/regexp.rb' +require 'facets/string.rb' +require 'facets/struct.rb' +require 'facets/symbol.rb' +require 'facets/time.rb' +#require 'facets/to_hash.rb' +require 'facets/unboundmethod.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets.yml b/bin/gems/facets-3.1.0/lib/core/facets.yml new file mode 100644 index 00000000..b935324c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets.yml @@ -0,0 +1,80 @@ +--- +revision: 2013 +type: ruby +sources: +- Indexfile +- Gemfile +authors: +- name: Thomas Sawyer + email: transfire@gmail.com +organizations: +- name: Rubyworks +requirements: +- groups: + - test + version: ">= 0" + name: lemon +- groups: + - test + version: ">= 0" + name: qed +- groups: + - test + version: ">= 0" + name: rubytest-cli +- groups: + - test + version: ">= 0" + name: rake +- groups: + - test + version: ">= 0" + name: simplecov +- groups: + - guard + version: ">= 0" + name: guard +conflicts: [] +alternatives: [] +resources: +- type: home + uri: http://rubyworks.github.com/facets + label: Homepage +- type: code + uri: http://github.com/rubyworks/facets + label: Source Code +- type: docs + uri: http://rubyworks.github.com/facets/learn.html + label: Documentation +- type: wiki + uri: http://wiki.github.com/rubyworks/facets + label: User Guide +- type: talk + uri: http://groups.google.com/group/facets-universal +repositories: +- name: upstream + scm: git + uri: git@github.com:rubyworks/facets.git +categories: [] +copyrights: +- holder: Rubyworks + year: '2004' + license: BSD-2-Clause +customs: [] +paths: + load: + - lib/core + - lib/standard +name: facets +title: Ruby Facets +version: 3.1.0 +summary: The orginal well curated collection of extension methods for Ruby. +slogan: ALL YOUR BASE ARE BELONG TO RUBY! +description: Facets is the premier collection of extension methods for the Ruby programming + language. Facets extensions are unique by virtue of thier atomicity. They are stored + in individual files allowing for highly granular control of requirements. In addition, + Facets includes a few additional classes and mixins suitable to wide variety of + applications. +scm_uri: https://github.com/rubyworks/facets/tree/master +created: '2004-12-16' +date: '2016-05-09' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/applique/file_helpers.rb b/bin/gems/facets-3.1.0/lib/core/facets/applique/file_helpers.rb new file mode 100644 index 00000000..75345b92 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/applique/file_helpers.rb @@ -0,0 +1,33 @@ +# +def temporary_directory + @temporary_directory ||= 'tmp' +end + +When /Given a directory '(.*?)' containing/ do |dir, text| + @temporary_directory = File.join(@temporary_directory, dir) + text.lines.each do |file| + next if file =~ /^\s*$/ + file = File.join(@temporary_directory, file.strip) + dir = File.dirname(file) + FileUtils.mkdir_p(dir) + File.open(file, 'w'){ |f| f << "SPINICH" } + end +end + +Before :all do + if File.exist?(temporary_directory) + FileUtils.rm_r(temporary_directory) + end + FileUtils.mkdir_p(temporary_directory) +end + +# Used for File extensions +When "had a file '(((.*?)))'" do |name| + name = name.sub(/^tmp\//, '') # b/c QED now runs from tmp/qed + File.open(name, 'w'){|f| f << "Hello World"} +end + +When "had a binary file '(((.*?)))'" do |name| + name = name.sub(/^tmp\//, '') # b/c QED now runs from tmp/qed + File.open(name, 'wb'){|f| f << "Hello\nWorld\n"} +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array.rb b/bin/gems/facets-3.1.0/lib/core/facets/array.rb new file mode 100644 index 00000000..0813e1e4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array.rb @@ -0,0 +1,49 @@ +require_relative 'array/after.rb' +#require_relative 'array/arrange.rb' # too new +require_relative 'array/average.rb' +require_relative 'array/before.rb' +require_relative 'array/collapse.rb' +require_relative 'array/collisions.rb' +require_relative 'array/commonality.rb' +require_relative 'array/conjoin.rb' +require_relative 'array/contains.rb' +require_relative 'array/delete.rb' +require_relative 'array/delete_unless.rb' +require_relative 'array/delete_values.rb' +require_relative 'array/divide.rb' +require_relative 'array/duplicates.rb' +require_relative 'array/each_pair.rb' +require_relative 'array/each_value.rb' +require_relative 'array/entropy.rb' +require_relative 'array/extract_options.rb' +require_relative 'array/from.rb' +require_relative 'array/indexable.rb' +#require_relative 'array/intersection.rb' # too new +#require_relative 'array/median.rb' # uncommon +require_relative 'array/merge.rb' +#require_relative 'array/missing.rb' # too new +require_relative 'array/mode.rb' +require_relative 'array/nonuniq.rb' +require_relative 'array/not_empty.rb' +require_relative 'array/only.rb' +require_relative 'array/pad.rb' +require_relative 'array/peek.rb' +#require_relative 'array/percentile.rb' # uncommon +require_relative 'array/unique_permutation.rb' +require_relative 'array/poke.rb' +require_relative 'array/probability.rb' +require_relative 'array/pull.rb' +require_relative 'array/occurrence.rb' +#require_relative 'array/op_pow.rb' # uncommon +require_relative 'array/recurse.rb' +require_relative 'array/recursively.rb' +require_relative 'array/reject_values.rb' +require_relative 'array/splice.rb' +require_relative 'array/split.rb' +require_relative 'array/squeeze.rb' +require_relative 'array/store.rb' +require_relative 'array/thru.rb' +require_relative 'array/to_h.rb' +require_relative 'array/traverse.rb' +require_relative 'array/uniq_by.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/after.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/after.rb new file mode 100644 index 00000000..3cc3abbf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/after.rb @@ -0,0 +1 @@ +require 'facets/array/before' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/arrange.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/arrange.rb new file mode 100644 index 00000000..11e5873b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/arrange.rb @@ -0,0 +1,42 @@ +class Array + + # The `arrange` method produces appropriate ranges from the objects in the array. + # + # Examples + # + # [1,2,3,6,7,8].arrange #=> [1..3, 6..8] + # + # [10..15, 16..20, 21, 22].arrange #=> [10..22] + # + # Assumes inclusive ranges (ie. 1..4) and range.first <= range.last. + # + # Works with integers, dates and strings. However, all the objects in the array must + # be of the same class. + # + # CREDIT: monocle + + def arrange + array = uniq.sort_by { |e| Range === e ? e.first : e } + array.inject([]) do |c, value| + unless c.empty? + last = c.last + last_value = (Range === last ? last.last : last) + current_value = (Range === value ? value.first : value) + if (last_value.succ <=> current_value) == -1 + c << value + else + first = (Range === last ? last.first : last) + second = [Range === last ? last.last : last, Range === value ? value.last : value].max + c[-1] = [first..second] + c.flatten! + end + else + c << value + end + end + end + + alias rangify arrange + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/average.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/average.rb new file mode 100644 index 00000000..b24af7e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/average.rb @@ -0,0 +1,16 @@ +class Array + + # Calculate the average of an array of numbers + # + # Examples + # + # [].average #=> nil + # [1, 2, 3].average #=> 2 + # [3, 12, 57, 85, 15, 89, 33, 7, 22, 54].average #=> 37.7 + # [1,[2,nil,[3]],nil,4].collapse #=> [1,2,3,4] + # + def average + return nil if empty? + self.reduce(:+)/length.to_f + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/before.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/before.rb new file mode 100644 index 00000000..5b41cdac --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/before.rb @@ -0,0 +1,41 @@ +class Array + + # Returns the value previous to the given value. The value previous + # to the first is the last. Returns nil if the given value is not + # in the array. + # + # Examples + # + # sequence = ['a', 'b', 'c'] + # sequence.before('a') #=> 'c' + # sequence.before('b') #=> 'a' + # sequence.before('c') #=> 'b' + # sequence.before('d') #=> nil + # + # CREDIT: Tyler Rick + + def before(value) + return nil unless include? value + self[(index(value).to_i - 1) % length] + end + + # Returns the value after the given value. The value before the last + # is the first. Returns nil if the given value is not in the array. + # + # Examples + # + # sequence = ['a', 'b', 'c'] + # sequence.after('a') #=> 'b' + # sequence.after('b') #=> 'c' + # sequence.after('c') #=> 'a' + # sequence.after('d') #=> nil + # + # CREDIT: Tyler Rick + + def after(value) + return nil unless include? value + self[(index(value).to_i + 1) % length] + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/collapse.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/collapse.rb new file mode 100644 index 00000000..83bd1727 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/collapse.rb @@ -0,0 +1,18 @@ +class Array + + # Simplify an array by flattening it then compacting it. + # + # Examples + # + # [1,[2,nil,[3]],nil,4].collapse #=> [1,2,3,4] + # + def collapse + flatten.compact + end + + def collapse! + flatten!.compact! + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/collisions.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/collisions.rb new file mode 100644 index 00000000..e42776ff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/collisions.rb @@ -0,0 +1 @@ +require 'facets/array/commonality' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/commonality.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/commonality.rb new file mode 100644 index 00000000..4954192b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/commonality.rb @@ -0,0 +1,49 @@ +class Array + + # Get a list of all items that have something in common in terms of the + # supplied block. If no block is given objects are considered to be in + # common if they return the same value for Object#hash and if obj1 == obj2. + # + # This can be useful, for instance, in determining all persons that share + # their last name with another person. + # + # persons.commonality { |person| person.last_name } + # + # The method is similar to #group_by which is a standard Ruby method as of 1.9. + # To get effectively the same results with #group_by use `select{ |k,v| v.size > 1 }`. + # + # [1, 2, 2, 3, 4, 4].group_by{ |e| e }.select{ |k,v| v.size > 1 } + # #=> { 2 => [2, 2], 4 => [4, 4] } + # + # Examples + # + # [1, 2, 2, 3, 4, 4].commonality #=> { 2 => [2, 2], 4 => [4, 4] } + # + # ["foo", "bar", "baz"].commonality { |str| str[0] } + # #=> { 'b' => ["bar", "baz"] } + # + # Returns [Hash] mapping common attribute to those elements. + # + # CREDIT: Florian Gross + + def commonality(&block) + block ||= lambda { |item| item } + + result = Hash.new { |hash, key| hash[key] = Array.new } + each do |item| + key = block.call(item) + result[key] << item + end + + result.reject! do |key, values| + values.size <= 1 + end + + return result + end + + # Deprecated: Alias for #commonality. + alias collisions commonality + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/conjoin.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/conjoin.rb new file mode 100644 index 00000000..b3fd238a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/conjoin.rb @@ -0,0 +1,89 @@ +class Array + + # This is more advanced form of #join. It allows for fine control + # of separators. + # + # NOTE: The old version used to default its separator to ", " and + # default the terminating separator to " and ". This is no longer + # the case. You must specifically provide these parameters. + # + # If no paramters are given, it acts like #join but will a space + # separator. + # + # [1,2,3].conjoin + # #=> "1 2 3" + # + # Use comma+space and 'and' on tail. + # + # [1,2,3].conjoin(', ', ' and ') + # #=> "1, 2 and 3" + # + # Use comma+space and 'or' on tail using :last option. + # + # [1,2,3].conjoin(', ', :last => ' or ') + # #=> "1, 2 or 3" + # + # Use semicolon+space and ampersand on tail using index. + # + # [1,2,3].conjoin('; ', -1 => ' & ') + # #=> "1; 2 & 3" + # + # Can take a block to determine separator. + # + # [1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' } + # #=> "1.2-3.4" + # + # This makes very esoteric transformation possible. + # + # [1,1,2,2].conjoin{ |i, a, b| a == b ? '=' : ' != ' } + # #=> "1=1 != 2=2" + # + # [1,2,3,4].conjoin{ |i, x, y| "<#{i} #{x} #{y}>" } + # #=> "1<0 1 2>2<1 2 3>3<2 3 4>4" + # + # There are also spacing options. Providing the :space option + # pads the separators. + # + # [1,2,3].conjoin(',', '&', :space=>2) + # #=> "1 , 2 & 3" + # + # And the :spacer option can set an alternate spacing string. + # + # [1,2,3].conjoin('|', '>', :space=>2, :spacer=>'-') + # #=> "1--|--2-->--3" + # + # CREDIT: Trans + + def conjoin(*args, &block) + return first.to_s if size < 2 + + options = (Hash===args.last) ? args.pop : {} + + spacing = options.delete(:space) || 0 + spacer = options.delete(:spacer) || " " + space = spacer * spacing.to_i + + sep = [] + + if block_given? + (size - 1).times do |i| + sep << space + yield(i, *slice(i,2)) + space + end + else + separator = args.shift || " " + options[-1] = args.shift if args.first + + options[0] = options.delete(:first) if options.key?(:first) + options[-1] = options.delete(:last) if options.key?(:last) + + separator = space + separator + space + + sep = [separator] * (size - 1) + + options.each{|i, s| sep[i] = space + s + space} + end + zip(sep).join + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/contains.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/contains.rb new file mode 100644 index 00000000..441a1060 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/contains.rb @@ -0,0 +1,7 @@ +class Array + + # Alias for #include?. + alias_method :contains?, :include? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/delete.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/delete.rb new file mode 100644 index 00000000..a54a6937 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/delete.rb @@ -0,0 +1,4 @@ +# Here for backward compatability. To be deprecated. +require 'facets/array/delete_unless' +require 'facets/array/delete_values' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/delete_unless.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_unless.rb new file mode 100644 index 00000000..14811037 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_unless.rb @@ -0,0 +1,15 @@ +class Array + + # Inverse of #delete_if. + # + # [1,2,3].delete_unless{ |x| x < 2 } + # #=> [1] + # + # CREDIT: Daniel Schierbeck + + def delete_unless(&block) + delete_if { |element| not block.call(element) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values.rb new file mode 100644 index 00000000..b5ca7c25 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values.rb @@ -0,0 +1,50 @@ +class Array + + # Delete multiple values from array. + # + # a = [1,2,3,4] + # a.delete_values(1,2) #=> [1,2] + # a #=> [3,4] + # + # CREDIT: Trans + + def delete_values(*values) + d = [] + values.each{ |v| d << delete(v) } + d + end + + # Delete multiple values from array given + # indexes or index range. + # + # a = [1,2,3,4] + # a.delete_values_at(1,2) #=> [2,3] + # a #=> [1,4] + # a = [1,2,3,4] + # a.delete_values_at(0..2) #=> [1,2,3] + # a #=> [4] + # + # NOTE: It would be nice to see #delete_at incorporate this + # funcitonaility. + # + # CREDIT: Trans + + def delete_values_at(*selectors) + idx = [] + selectors.each{ |i| + case i + when Range + idx.concat( i.to_a ) + else + idx << i.to_i + end + } + idx.uniq! + dvals = values_at(*idx) + idx = (0...size).to_a - idx + self.replace( values_at(*idx) ) + return dvals + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values_at.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values_at.rb new file mode 100644 index 00000000..d279b932 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/delete_values_at.rb @@ -0,0 +1 @@ +require 'facets/array/delete_values' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/divide.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/divide.rb new file mode 100644 index 00000000..d4a73fd6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/divide.rb @@ -0,0 +1,27 @@ +class Array + + # Divide on matching pattern. + # + # ['a1','b1','a2','b2'].divide(/^a/) + # #=> [['a1','b1'],['a2','b2']] + # + # ['a1','b1','a2','b2'].divide(/^b/) + # #=> [['a1',['b1','a2'],[]'b2']] + # + # ['a1','b1','a2','b2'].divide(/^c/) + # #=> [['a1','b1','a2','b2']] + # + # CREDIT: Trans + + def divide(pattern) + memo = [] + memo.push [] unless pattern === first + each do |obj| + memo.push [] if pattern === obj + memo.last << obj + end + memo + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/duplicates.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/duplicates.rb new file mode 100644 index 00000000..f08f084a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/duplicates.rb @@ -0,0 +1,24 @@ +class Array + + # Return list of duplicate elements. + # + # min - The minimum number of duplication necessary for inclusion. [Integer] + # + # Examples: + # + # [1,1,2,3].duplicates #=> [1] + # + # [1,1,2,3,2,4,5,4,2].duplicates(3) #=> [2] + # + # CREDIT: Rebort Dober (current implementation) + # CREDIT: Thibaut Barrère + + def duplicates(min=2) + h = Hash.new( 0 ) + each {|i| + h[i] += 1 + } + h.delete_if{|_,v| v < min}.keys + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/each_overlap.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/each_overlap.rb new file mode 100644 index 00000000..e9fb288e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/each_overlap.rb @@ -0,0 +1,25 @@ +class Array + + # Iterate over each slice where the last n values of a preceding slice + # overlap with the first n values of the following slice. The value of n + # is specified by the second `overlap` argument. + # + # a, r = [1,2,3,4,5], [] + # a.each_overlap(2,1) { |x,y| r << [x,y] } + # r # => [[1,2],[2,3],[3,4],[4,5]] + # + # Returns nothing. + + def each_overlap(slice_size, overlap) + if block_given? + i = 0 + while i + slice_size <= length + yield slice(i...i+slice_size) + i += (slice_size - overlap) + end + else + to_enum(:each_overlap, slice_size, overlap) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/each_pair.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/each_pair.rb new file mode 100644 index 00000000..774ac275 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/each_pair.rb @@ -0,0 +1,11 @@ +class Array + + # Iterate over index and value. The intention of this + # method is to provide polymorphism with Hash. + # + def each_pair #:yield: + each_with_index {|e, i| yield(i,e) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/each_value.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/each_value.rb new file mode 100644 index 00000000..febd4aa7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/each_value.rb @@ -0,0 +1,6 @@ +class Array + # Alias for #each. The intention of this method + # is to provide polymorphism with Hash. + alias :each_value :each +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/entropy.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/entropy.rb new file mode 100644 index 00000000..87e39fdb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/entropy.rb @@ -0,0 +1,39 @@ +require 'facets/array/probability' + +class Array + + # Shannon's entropy for an array - returns the average + # bits per symbol required to encode the array. + # Lower values mean less "entropy" - i.e. less unique + # information in the array. + # + # e = %w{ a b c d e e e }.entropy + # + # ("%.3f" % e) #=> "2.128" + # + # CREDIT: Derek + + def entropy + arr = self + probHash = arr.probability + # -- h is the Shannon entropy of the array + h = -1.to_f * probHash.keys.inject(0.to_f) do |sum, i| + sum + (probHash[i] * (Math.log(probHash[i])/Math.log(2.to_f))) + end + h + end + + # Returns the maximum possible Shannon entropy of the array + # with given size assuming that it is an "order-0" source + # (each element is selected independently of the next). + # + # CREDIT: Derek + + def ideal_entropy + arr = self + unitProb = 1.0.to_f / arr.size.to_f + (-1.to_f * arr.size.to_f * unitProb * Math.log(unitProb)/Math.log(2.to_f)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/extract_options.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/extract_options.rb new file mode 100644 index 00000000..66077a7d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/extract_options.rb @@ -0,0 +1,31 @@ +class Hash + # By default, only instances of Hash itself are extractable. + # Subclasses of Hash may implement this method and return + # true to declare themselves as extractable. If a Hash + # is extractable, Array#extract_options! pops it from + # the Array when it is the last element of the Array. + def extractable_options? + instance_of?(Hash) + end +end + +class Array + # Extracts options from a set of arguments. Removes and returns the last + # element in the array if it's a hash, otherwise returns a blank hash. + # + # def options(*args) + # args.extract_options! + # end + # + # options(1, 2) # => {} + # options(1, 2, :a => :b) # => {:a=>:b} + # + def extract_options! + if Hash === last && last.extractable_options? + pop + else + {} + end + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/first.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/first.rb new file mode 100644 index 00000000..c9532763 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/first.rb @@ -0,0 +1 @@ +require 'facets/array/indexable' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/from.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/from.rb new file mode 100644 index 00000000..bca28fff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/from.rb @@ -0,0 +1,28 @@ +class Array + + # Returns elements from `index` until the end. + # + # %w{W o r l d}.from(3) #=> ["l", "d"] + # %w{W o r l d}.from(9) #=> [] + # + def from(index) + return [] if index >= size + self[index..-1] + end unless method_defined?(:from) + + # Fetch values from a start index thru an end index. + # + # [1,2,3,4,5].thru(2) #=> [1,2,3] + # [1,2,3,4,5].thru(4) #=> [1,2,3,4,5] + # + # [1,2,3,4,5].thru(0,2) #=> [1,2,3] + # [1,2,3,4,5].thru(2,4) #=> [3,4,5] + # + def thru(from, to=nil) + from, to = 0, from unless to + return [] if from >= size + self[from..to] + end unless method_defined?(:thru) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/indexable.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/indexable.rb new file mode 100644 index 00000000..dd5dfd4d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/indexable.rb @@ -0,0 +1,31 @@ +require 'facets/indexable' +require 'facets/array/splice' + +class Array + + include Indexable + + # Alias for shift, which removes and returns + # the first element in an array. + # + # a = ["a","y","z"] + # a.first! #=> "a" + # a #=> ["y","z"] + # + # CREDIT: Trans + + alias_method :first!, :shift + + # Alias for pop, which removes and returns + # the last element in an array. + # + # a = [1,2,3] + # a.last! #=> 3 + # a #=> [1,2] + # + # CREDIT: Trans + + alias_method :last!, :pop + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/intersection.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/intersection.rb new file mode 100644 index 00000000..db253517 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/intersection.rb @@ -0,0 +1,25 @@ +class Array + + # Returns the values in common for an array set (nil, single value/object, or range). + # + # CREDIT: monocle + + def intersection + array = uniq.sort_by { |e| Range === e ? e.first : e } + array.inject() do |c, e| + f = (Range === c ? c.last : c) + v = (Range === e ? e.first : e) + case f <=> v + when -1 then return nil + when 0 then f + else + if Range === e + v..([f, e.last].min) + else + v + end + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/last.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/last.rb new file mode 100644 index 00000000..c9532763 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/last.rb @@ -0,0 +1 @@ +require 'facets/array/indexable' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/median.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/median.rb new file mode 100644 index 00000000..dffa64a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/median.rb @@ -0,0 +1,32 @@ +class Array + + # Determines the _sorted_ middle element. + # + # a = %w{a a b b c c c} + # a.median #=> "b" + # + # When there are an even number of elements, the greater + # of the two middle elements is given. + # + # a = %w{a a b b c c c d} + # a.median #=> "c" + # + # An offset can be supplied to get an element relative + # to the middle. + # + # a = %w{a a b b c c c d} + # a.median(-1) #=> "b" + # + # The the array is empty, +nil+ is returned. + # + # @return [Object] sorted middle element + def median(offset=0) + return nil if self.size == 0 + + tmp = self.sort + mid = (tmp.size / 2).to_i + offset + + tmp[mid] + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/merge.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/merge.rb new file mode 100644 index 00000000..27fcbebf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/merge.rb @@ -0,0 +1,22 @@ +class Array + + # In place #merge. + # + # a = [1,2] + # a.merge! [2,3] + # a #=> [1,2,3] + # + # CREDIT: Trans + + def merge!( other ) + self.replace(self.merge(other)) + end + + # Alias for |. + # + # [1,2].merge([2,3]) #=> [1,2,3] + # + alias_method :merge, :| + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/missing.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/missing.rb new file mode 100644 index 00000000..ad45c27d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/missing.rb @@ -0,0 +1,29 @@ +require 'facets/array/arrange' + +class Array + + # Determine the "holes" in the values of an array. + # + # TODO: Better name? + # + # Returns the missing elements in an array set. + # + # CREDIT: monocle + + def missing + missing, array = [], arrange + i, length = 0, array.size - 1 + while i < length + x0 = array[i] + x1 = array[i+1] + c = (Range === x0 ? x0.last : x0) + n = (Range === x1 ? x1.first : x1) + missing << ( + c.succ.succ == n ? c.succ : ((c.succ)..(n.pred)) + ) + i += 1 + end + return missing + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/mode.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/mode.rb new file mode 100644 index 00000000..b0ef04a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/mode.rb @@ -0,0 +1,22 @@ +class Array + + # In Statistics. mode is the value that occurs most frequently + # in a given set of data. This method returns an array in case + # there is a tie. + # + # [:a, :b, :c, :b, :d].mode #=> [:b] + # [:a, :b, :c, :b, :a].mode #=> [:a, :b] + # + # Returns an Array of most common elements. + # + # @author Robert Klemme + + def mode + max = 0 + c = Hash.new 0 + each {|x| cc = c[x] += 1; max = cc if cc > max} + c.select {|k,v| v == max}.map {|k,v| k} + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/nonuniq.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/nonuniq.rb new file mode 100644 index 00000000..7e600edb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/nonuniq.rb @@ -0,0 +1,28 @@ +class Array + + # Returns a list of non-unique elements. + # + # Examples + # + # [1,1,2,2,3,4,5].nonuniq #=> [1,2] + # + # CREDIT: Martin DeMello + + def nonuniq + h1 = {} + h2 = {} + each {|i| + h2[i] = true if h1[i] + h1[i] = true + } + h2.keys + end + + # Same as `#nonuniq` but acts in place. + + def nonuniq! + self.replace(self.nonuniq) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/not_empty.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/not_empty.rb new file mode 100644 index 00000000..89d5f739 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/not_empty.rb @@ -0,0 +1,13 @@ +class Array + + # Not empty? + # + # [].not_empty? #=> false + # [1,2].not_empty? #=> true + + def not_empty? + !empty? + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/occur.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/occur.rb new file mode 100644 index 00000000..8fd028c5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/occur.rb @@ -0,0 +1,38 @@ +class Array + + # Returns a list of elements that occur +n+ times. + # + # If +n+ is a Range then returns elements that occur a number + # of time within the range. + # + # Examples + # + # [0,1,1,1,3,0,1,2,4].occur(3) #=> [1] + # + # [0,1,1,1,3,0,1,2,4].occur(2..4) #=> [0,1] + # + # Returns [Array] of reoccurring elements. + # + # CREDIT: Robert Dober + + def occur(n=nil) #:yield: + h = Hash.new(0) + + each do |i| + h[i] += 1 + end + + case n + when nil + h.delete_if{ |_,v| ! yield(v) }.keys + when Range + h.delete_if{ |_,v| ! n.include?(v) }.keys + else + h.delete_if{|_,v| v != n}.keys + end + end + + # Plural alias of #occur. + alias :occurs :occur + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/occurrence.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/occurrence.rb new file mode 100644 index 00000000..54acd484 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/occurrence.rb @@ -0,0 +1,29 @@ +class Array + + # Create a hash of each uniq element of the array + # and how many time each appears. + # + # Examples + # + # [:a,:a,:b,:c,:c,:c].occurrence + # #=> { :a => 2, :b => 1, :c => 3 } + # + # [2,2,3,4,4,4].occurrence{|i| i % 2} + # #=> { 0 => 5, 1 => 1 } + # + def occurrence + h = Hash.new(0) + if block_given? + each do |e| + h[yield(e)] += 1 + end + else + each do |e| + h[e] += 1 + end + end + h + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/only.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/only.rb new file mode 100644 index 00000000..300c9dea --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/only.rb @@ -0,0 +1,37 @@ +class Array + + # Returns the _only_ element in the array. Raises an IndexError if + # the array's size is not 1. + # + # [5].only # => 5 + # + # expect IndexError do + # [1,2,3].only + # end + # + # expect IndexError do + # [].only + # end + # + # CREDIT: Gavin Sinclair, Noah Gibbs + + def only + unless size == 1 + raise IndexError, "not the only element of array" + end + first + end + + # Does this Array have only one element? + # + # TODO: While clearly this goes along with the regular #only method, + # the name doesn't seem quite right. Perhaps rename to #lonely. + # + # CREDIT: Lavir the Whiolet + # + def only? + size == 1 + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/op_pow.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/op_pow.rb new file mode 100644 index 00000000..f1ed460e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/op_pow.rb @@ -0,0 +1,12 @@ +class Array + # Array#** is an alias for Array#product. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/array/op_pow' + # + alias_method :**, :product +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/pad.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/pad.rb new file mode 100644 index 00000000..63787c6d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/pad.rb @@ -0,0 +1,41 @@ +class Array + + # Pad an array with a given value up to a given length. + # + # [0,1,2].pad(6,"a") #=> [0,1,2,"a","a","a"] + # + # If length is a negative number padding will be added + # to the beginning of the array. + # + # [0,1,2].pad(-6,"a") #=> ["a","a","a",0,1,2] + # + # CREDIT: Richard Laugesen + + def pad(len, val=nil) + return dup if self.size >= len.abs + if len < 0 + Array.new((len+size).abs,val) + self + else + self + Array.new(len-size,val) + end + end + + # Like #pad but changes the array in place. + # + # a = [0,1,2] + # a.pad!(6,"x") + # a #=> [0,1,2,"x","x","x"] + # + # CREDIT: Richard Laugesen + + def pad!(len, val=nil) + return self if self.size >= len.abs + if len < 0 + replace Array.new((len+size).abs,val) + self + else + concat Array.new(len-size,val) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/peek.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/peek.rb new file mode 100644 index 00000000..3f7b4205 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/peek.rb @@ -0,0 +1 @@ +require 'facets/array/pull' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/poke.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/poke.rb new file mode 100644 index 00000000..3f7b4205 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/poke.rb @@ -0,0 +1 @@ +require 'facets/array/pull' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/probability.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/probability.rb new file mode 100644 index 00000000..828c76d5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/probability.rb @@ -0,0 +1,39 @@ +class Array + + # Generates a hash mapping each unique element in the array to the + # relative frequency, i.e. the probability, of it appearance. + # + # [:a, :b, :c, :c].probability #=> {:a=> 0.25, :b=>0.25, :c=>0.5} + # + # CREDIT: Brian Schröder + + def probability + probs = Hash.new(0.0) + size = 0.0 + each do |e| + probs[e] += 1.0 + size += 1.0 + end + probs.keys.each{ |e| probs[e] /= size } + probs + end + + #-- + # Old Definition ... + # + # def probability + # arr = self.to_a + # probHash = Hash.new + # size = arr.size.to_f + # arr.uniq.each do |i| + # ct = arr.inject(0) do |mem,obj| + # obj.eql?(i) ? (mem+1) : mem + # end + # probHash[i] = ct.to_f/size + # end + # probHash + # end + #++ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/pull.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/pull.rb new file mode 100644 index 00000000..ef92b6a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/pull.rb @@ -0,0 +1,30 @@ +class Array + + # Alias for shift which removes an object off first slot of an array. + # This is the opposite of pop. + alias_method :pull, :shift + + # Peek at the top of the stack (the end of the array). + # + # a = [1, 2, 3] + # a.peek #=> 3 + # a #=> [1, 2, 3] + # + # Or provide an index to inspect the array from back to front. + def peek(i=0) + i = -(i + 1) + fetch(i) + end + + # Put an object on the bottom of the stack (front of the array). + # + # a = [2, 3] + # a.poke(1) + # a #=> [1, 2, 3] + # + # Or supply an index and #poke works like #insert. + def poke(x, i=0) + insert(i,x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/recurse.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/recurse.rb new file mode 100644 index 00000000..94481ade --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/recurse.rb @@ -0,0 +1,29 @@ +class Array + + # Apply a block to array, and recursively apply that block + # to each sub-array or +types+. + # + # arr = ["a", ["b", "c", nil], nil] + # arr.recurse{ |a| a.compact! } + # #=> ["a", ["b", "c"]] + # + def recurse(*types, &block) + types = [self.class] if types.empty? + a = inject([]) do |array, value| + case value + when *types + array << value.recurse(*types, &block) + else + array << value + end + array + end + yield a + end + + # In place form of #recurse. + def recurse!(&block) + replace(recurse(&block)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/recursively.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/recursively.rb new file mode 100644 index 00000000..d5f8779f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/recursively.rb @@ -0,0 +1,53 @@ +require 'facets/functor' +require 'facets/enumerable/recursively' + +class Array + + # Apply a method to array, and recursively apply that method + # to each sub-array or given +types+. + # + # By default the sub-types are passed through unaffected. Passing + # a block to #recursively can be used to change this. + # + # types - List of class types to recurse. [Array] + # block - Optional filter procedure to apply on each recursion. + # + # Examples + # + # arr = ["a", ["b", "c"]] + # arr.recursively.map{ |v| v.to_sym } + # #=> [:a, [:b, :c]] + # + # arr = ["a", ["b", "c"]] + # arr.recursively{ |a| a.reverse }.map{ |v| v.to_sym } + # #=> [:a, [:c, :b]] + # + # Returns [Recursor]. + + def recursively(*types, &block) + Recursor.new(self, *types, &block) + end + + ## TODO: When no longer needing to support 1.8.6 we could get rid of + ## the Recursor class and use: + ## + ## def recursively(*types, &block) + ## types = types.empty? ? [self.class] : types + ## Functor.new do |op, &yld| + ## rec = block || lambda{ |a| a } + ## yld = yld || lambda{ |v| v } # ? to_enum + ## __send__(op) do |v| + ## case v + ## when String # b/c of 1.8 + ## yld.call(v) + ## when *types + ## res = v.recursively(*types, &block).__send__(op,&yld) + ## rec.call(res) + ## else + ## yld.call(v) + ## end + ## end + ## end + ## end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/reject_values.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/reject_values.rb new file mode 100644 index 00000000..d48b116c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/reject_values.rb @@ -0,0 +1,21 @@ +class Array + + # Non-destructive form of `Array#delete_values`. Unlike `delete_values` + # this method returns a new array. + # + # values - List of array elements to reject. + # + # Examples + # + # [1,2,3,4,5].reject_values(2,4) # => [1,3,5] + # + # Returns [Array] + # + # CREDIT: Sean Mackesey + + def reject_values(*values) + reject { |x| values.include?(x) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/splice.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/splice.rb new file mode 100644 index 00000000..0bf49dc9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/splice.rb @@ -0,0 +1,31 @@ +require 'facets/array/store' + +class Array + + # Splice acts as a combination of #slice! and #store. + # If two arguments are given it calls #store. + # If a single argument is given it calls slice!. + # + # Examples + # + # a = [1,2,3] + # a.splice(1) #=> 2 + # a #=> [1,3] + # + # a = [1,2,3] + # a.splice(1,4) #=> 4 + # a #=> [1,4,3] + # + # Returns [Array]. + # + # CREDIT: Trans + + def splice(*args) + if args.size == 1 + slice!(*args) + else + store(*args) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/split.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/split.rb new file mode 100644 index 00000000..03c838e7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/split.rb @@ -0,0 +1,30 @@ +class Array + + # Split on matching pattern. Unlike #divide this does not include matching + # elements. + # + # Examples + # + # ['a1','a2','b1','a3','b2','a4'].split(/^b/) + # #=> [['a1','a2'],['a3'],['a4']] + # + # Returns list of split-up arrays. [Array] + + def split(pattern) + memo = [] + sect = [] + each do |obj| + if pattern === obj + memo << sect + sect = [] + else + sect << obj + end + end + memo << sect + memo.pop while memo.last == [] + memo + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/squeeze.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/squeeze.rb new file mode 100644 index 00000000..ea5d5dcb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/squeeze.rb @@ -0,0 +1,23 @@ +require 'facets/enumerable/squeeze' + +class Array + + # Destructive version of Enumerable#squeeze. + # + # a = [1,2,2,3,3,2,1] + # a.squeeze! + # a #=> [1,2,3,2,1] + # + # a = [1,2,2,3,3,2,1] + # a.squeeze!(*[3]) + # a #=> [1,2,2,3,2,1] + # + # Returns the receiver. [Array] + # + # CREDIT: T. Yamada + + def squeeze!(*limited_to) + replace(squeeze(*limited_to)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/standard_deviation.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/standard_deviation.rb new file mode 100644 index 00000000..c552c26c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/standard_deviation.rb @@ -0,0 +1,23 @@ +require 'facets/array/variance' + +class Array + + # Calculate the standard_deviation of an array of numbers + # + # Examples + # + # [].standard_deviation #=> nil + # [1, 2, 3].standard_deviation #=> 0.816496580927726 + # [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].standard_deviation #=> 24.69331893448104 + # [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].standard_deviation #=> 54.67183918618432 + # [60.7829, 31.2622, 20.626, 78.8907, 61.5328].standard_deviation #=> 21.428815505053002 + # + def standard_deviation + return nil if empty? + Math.sqrt(variance) + end + + alias sd standard_deviation +end + + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/step.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/step.rb new file mode 100644 index 00000000..dc8fa1d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/step.rb @@ -0,0 +1,31 @@ +class Array + + # Iterate over every nth element of an array. + # + # r = [] + # [:a, :b, :c, :d].step(2) { |x| r << x } + # r #=> [:b, :d] + # + # Without a block it returns an Enumerator. + # + # [:a, :b, :c, :d].step(1).to_a #=> [:a, :b, :c, :d] + # [:a, :b, :c, :d].step(2).to_a #=> [:b, :d] + # [:a, :b, :c, :d].step(3).to_a #=> [:c] + # [:a, :b, :c, :d].step(5).to_a #=> [] + # + # CREDIT: Ryan Duryea + + def step(n) #:yield: + if block_given? + ((n - 1)...size).step(n).each do |i| + yield(fetch(i)) + end + else + Enumerator.new(size / n) do |y| + ((n - 1)...self.size).step(n).each { |i| y << fetch(i) } + end + end + end +end + + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/store.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/store.rb new file mode 100644 index 00000000..3816e969 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/store.rb @@ -0,0 +1,16 @@ +class Array + + # Store a value at a given index. Store is an alias for #[]=. + # + # Example: + # + # a = [] + # a.store(1, "A") + # a[1] #=> "A" + # + # Returns the stored object. + + alias_method :store, :[]= + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/thru.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/thru.rb new file mode 100644 index 00000000..0a65ab51 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/thru.rb @@ -0,0 +1 @@ +require 'facets/array/from' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/to_h.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/to_h.rb new file mode 100644 index 00000000..a16c1ce6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/to_h.rb @@ -0,0 +1,19 @@ +class Array + + # Convert an associative array to a Hash. + # + # Examples + # + # [[:a, 1], [:b, 2]].to_h + # #=> {:a=>1, :b=>2} + # + # Returns [Hash]. + # + def to_h + h = {} + each{ |(k,v)| h[k] = v } + h + end unless method_defined?(:to_h) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/traverse.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/traverse.rb new file mode 100644 index 00000000..c551b1f9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/traverse.rb @@ -0,0 +1,50 @@ +class Array + + # Construct a new array created by traversing the array and its + # sub-arrays, executing the given block on the elements. + # + # Examples + # + # h = ["A", "B", ["X", "Y"]] + # g = h.traverse{ |e| e.downcase } + # g #=> ["a", "b", ["x", "y"]] + # + # This is the same as recursive.map and will + # likely be deprecated in the future because of it. + # + # Returns new array. [Array] + # + # CREDIT: Trans + + def traverse(&block) + if block_given? + map do |e| + if e.respond_to?(:to_ary) + e.to_ary.traverse(&block) + else + block.call(e) + end + end + else + to_enum(:traverse) + end + end + + # Like #recursive_map, but will change the array in place. + # + # Examples: + # + # h = ["A", "B", ["X", "Y"]] + # h.traverse!{ |e| e.downcase } + # h #=> ["a", "b", ["x", "y"]] + # + # Returns self. [Array] + # + # CREDIT: Trans + + def traverse!(&block) + replace(traverse(&block)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/uniq_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/uniq_by.rb new file mode 100644 index 00000000..eb692c2f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/uniq_by.rb @@ -0,0 +1,24 @@ +class Array + + # Like #uniq, but determines uniqueness based on a given block. + # As can be seen in the following examples, order is significant. + # + # Examples + # + # a = (-5..5).to_a + # a.uniq_by!{ |i| i*i } + # a #=> [-5, -4, -3, -2, -1, 0] + # + # a = (-5..5).to_a.reverse + # a.uniq_by!{ |i| i*i } + # a #=> [5, 4, 3, 2, 1, 0] + # + # Returns [Array] of unique elements. + # + def uniq_by! #:yield: + h = {} + replace( inject([]){|a,x| h[yield(x)] ||= a << x} ) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/unique_permutation.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/unique_permutation.rb new file mode 100644 index 00000000..3cb74f4f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/unique_permutation.rb @@ -0,0 +1,29 @@ +class Array + + # Enumerates permutation of Array. + # Unlike Array#permutation, there are no duplicates in generated permutations. + # Instead, elements must be comparable. + # + # [1,1,2,2,3].unique_permutation(2).to_a + # #=> [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2]] + # # Note: [1,1,2,2,3].permutation(2).to_a + # #=> [[1, 1], [1, 2], [1, 2], [1, 3], [1, 1], [1, 2], [1, 2], [1, 3], [2, 1], [2, 1], [2, 2], [2, 3], [2, 1], [2, 1], [2, 2], [2, 3], [3, 1], [3, 1], [3, 2], [3, 2]] + # + # CREDIT: T. Yamada + def unique_permutation(n=self.size) + return to_enum(:unique_permutation,n) unless block_given? + return if n<0||self.size nil + # [1, 2, 3].variance #=> 0.6666666666666666 + # [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].variance #=> 609.76 + # [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].variance #=> 2989.0099999999993 + # [60.7829, 31.2622, 20.626, 78.8907, 61.5328].variance #=> 459.1941339495999 + # + def variance + avg = average + map {|n| (n - avg) ** 2 }.average + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/array/zip.rb b/bin/gems/facets-3.1.0/lib/core/facets/array/zip.rb new file mode 100644 index 00000000..0ece788d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/array/zip.rb @@ -0,0 +1,21 @@ +class Array + + # Class level rendition of Array#zip. + # + # arrays - List of arrays to zip. [Array] + # + # Example: + # + # Array.zip([1,2],[3,4]] + # #=> [[1,3],[2,4]] + # + # Returns arranged array of arrays. [Array] + # + # Returns an empty array if no arguments are given. [Array] + + def self.zip(*arrays) + return [] if arrays.empty? + return arrays[0].zip(*arrays[1..-1]) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding.rb new file mode 100644 index 00000000..76993974 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding.rb @@ -0,0 +1,12 @@ +require_relative 'binding/caller.rb' +require_relative 'binding/callstack.rb' +require_relative 'binding/call_stack.rb' +require_relative 'binding/defined.rb' +require_relative 'binding/op.rb' +require_relative 'binding/op_get.rb' +require_relative 'binding/op_set.rb' +require_relative 'binding/self.rb' +require_relative 'binding/with.rb' +require_relative 'binding/__callee__.rb' +require_relative 'binding/__method__.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/__callee__.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/__callee__.rb new file mode 100644 index 00000000..6e564d81 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/__callee__.rb @@ -0,0 +1 @@ +require 'facets/binding/caller' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/__method__.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/__method__.rb new file mode 100644 index 00000000..6e564d81 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/__method__.rb @@ -0,0 +1 @@ +require 'facets/binding/caller' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/call_stack.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/call_stack.rb new file mode 100644 index 00000000..92ac9ae8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/call_stack.rb @@ -0,0 +1 @@ +require 'facets/kernel/callstack' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/caller.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/caller.rb new file mode 100644 index 00000000..76f7093d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/caller.rb @@ -0,0 +1,42 @@ +require 'facets/binding/callstack' + +class Binding + + # Returns the call stack, same format as Kernel#caller() + # + def caller( skip=0 ) + eval("caller(#{skip})") + end + + # Return the line number on which the binding was created. + # + def __LINE__ + Kernel.eval("__LINE__", self) + end + + # Returns file name in which the binding was created. + # + def __FILE__ + Kernel.eval("__FILE__", self) + end + + # Return the directory of the file in which the binding was created. + # + def __DIR__ + File.dirname(self.__FILE__) + end + + # Retreive the current running method. + # + def __method__ + Kernel.eval("__method__", self) + end + + # Retreive the current running method. + # + def __callee__ + Kernel.eval("__callee__", self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/callstack.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/callstack.rb new file mode 100644 index 00000000..92ac9ae8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/callstack.rb @@ -0,0 +1 @@ +require 'facets/kernel/callstack' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/defined.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/defined.rb new file mode 100644 index 00000000..69d4fb12 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/defined.rb @@ -0,0 +1,10 @@ +class Binding + + # Returns the nature of something within the context of the binding. + # Returns nil if that thing is not defined. + def defined?(x) + eval("defined? #{x}") + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/op.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/op.rb new file mode 100644 index 00000000..b70aeb50 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/op.rb @@ -0,0 +1,4 @@ +# This file is here for backward compatibility only. +# It can be deprecated eventually. + +require 'facets/binding/op_get' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/op_get.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/op_get.rb new file mode 100644 index 00000000..dc726f05 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/op_get.rb @@ -0,0 +1,25 @@ +class Binding + + # Returns the value of some variable. + # + # a = 2 + # binding["a"] #=> 2 + # + def []( x ) + eval( x.to_s ) + end + + # Set the value of a local variable. + # + # binding["a"] = 4 + # a #=> 4 + # + # @deprecated No longer wortks in Ruby 1.9+. + # + # @see Binding#with for an alternative. + def []=( l, v ) + eval( "lambda {|v| #{l} = v}").call( v ) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/op_set.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/op_set.rb new file mode 100644 index 00000000..36786bad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/op_set.rb @@ -0,0 +1 @@ +require 'facets/binding/op_get' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/self.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/self.rb new file mode 100644 index 00000000..88f61210 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/self.rb @@ -0,0 +1,15 @@ +class Binding + + # This is already defined by Rubinius: + # Kernel.eval('Rubinius::VariableScope.current.self', self) + unless method_defined?(:self) + + # Returns self of the binding's context. + def self + eval('self') + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/binding/with.rb b/bin/gems/facets-3.1.0/lib/core/facets/binding/with.rb new file mode 100644 index 00000000..b121e141 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/binding/with.rb @@ -0,0 +1,12 @@ +class Binding + + # Returns a new binding with local varaibles set. + # + # CREDIT: Trans + + def with(_local_variables, &_yields) + eval("lambda{ |#{_local_variables.keys.join(',')},&yields| binding }").call(*_local_variables.values, &_yields) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/boolean.rb b/bin/gems/facets-3.1.0/lib/core/facets/boolean.rb new file mode 100644 index 00000000..ec4dae06 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/boolean.rb @@ -0,0 +1,121 @@ +require 'facets/kernel/true' +require 'facets/kernel/false' + +module Kernel + # Boolean conversion for not being nil or false. + # Other classes may redefine this to suite the + # particular need. + # + # "yes".to_b #=> true + # "abc".to_b #=> false + # + # true.to_b #=> true + # false.to_b #=> false + # nil.to_b #=> false + # + # CREDIT: Ara T. Howard, Trans + def to_b + self ? true : false + end + + # All objects except false and nil are "true". + def to_bool + true + end + + # Returns true is an object is class TrueClass + # or FalseClass, otherwise false. + # + # true.bool? #=> true + # false.bool? #=> true + # nil.bool? #=> false + # + def bool? + (true == self or false == self) + end +end + +class TrueClass + def to_bool + self + end +end + +class FalseClass + def to_bool + self + end +end + +class NilClass + def to_bool + false + end +end + +class Numeric + # Provides a boolean interpretation of self. + # If self == 0 then false else true. + # + # 0.to_b #=> false + # 1.to_b #=> true + # 2.3.to_b #=> true + # + def to_b + self == 0 ? false : true + end +end + +class String + # Interpret common affirmative string meanings as true, + # otherwise nil or false. Blank space and case are ignored. + # The following strings that will return true ... + # + # true + # yes + # on + # t + # 1 + # y + # == + # + # The following strings will return nil ... + # + # nil + # null + # + # All other strings return false. + # + # Here are some exmamples. + # + # "true".to_b #=> true + # "yes".to_b #=> true + # "no".to_b #=> false + # "123".to_b #=> false + # + def to_b + case self.downcase.strip + when 'true', 'yes', 'on', 't', '1', 'y', '==' + return true + when 'nil', 'null' + return nil + else + return false + end + end +end + +class Array + # Boolean conversion for not empty? + def to_b + ! self.empty? + end +end + +class Hash + # Boolean conversion for not empty? + def to_b + ! self.empty? + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/cattr.rb b/bin/gems/facets-3.1.0/lib/core/facets/cattr.rb new file mode 100644 index 00000000..03d3c38f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/cattr.rb @@ -0,0 +1 @@ +require 'facets/class/cattr' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class.rb b/bin/gems/facets-3.1.0/lib/core/facets/class.rb new file mode 100644 index 00000000..03f5968d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class.rb @@ -0,0 +1,9 @@ +require_relative 'class/descendants.rb' +#require_relative 'class/hierarchically' # uncommon +require_relative 'class/methodize.rb' +require_relative 'class/pathize.rb' +#require_relative 'class/preallocate.rb' # uncommon +#require_relative 'class/singleton.rb' # uncommon +require_relative 'class/subclasses.rb' +require_relative 'class/to_proc.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/cattr.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/cattr.rb new file mode 100644 index 00000000..9e9cebdb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/cattr.rb @@ -0,0 +1 @@ +require 'facets/module/cattr' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/descendants.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/descendants.rb new file mode 100644 index 00000000..c300f45b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/descendants.rb @@ -0,0 +1,36 @@ +require 'facets/class/subclasses' + +class Class + + # List all descedents of this class. + # + # class A ; end + # class B < A; end + # class C < A; end + # A.descendants #=> [B,C] + # + # You may also limit the generational distance the subclass may be from + # the parent class. + # + # class X ; end + # class Y < X; end + # class Z < Y; end + # X.descendants #=> [Y,Z] + # X.descendants(1) #=> [Y] + # + # NOTE: This is a intensive operation. Do not expect it to be very fast. + # + # @author Roger Pack + def descendants(generations=-1) + descendants = [] + subclasses.each do |k| + descendants << k + if generations != 1 + descendants.concat(k.descendants(generations - 1)) + end + end + descendants + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/hierarchically.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/hierarchically.rb new file mode 100644 index 00000000..5a5378d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/hierarchically.rb @@ -0,0 +1,12 @@ +module Kernel + + # Hierarchically apply a block, passing each ancestor to the block + # starting at the root ancestor and working toward the current object. + # + def hierarchically(&block) + ancestors.reverse_each do |m| + block.call(m) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/methodize.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/methodize.rb new file mode 100644 index 00000000..db09addd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/methodize.rb @@ -0,0 +1,19 @@ +require 'facets/string/methodize' + +class Class + + # Translate a class name to a suitable method name. + # + # module ::Example + # class MethodizeExample + # end + # end + # + # Example::MethodizeExample.methodize #=> "example__methodize_example" + # + def methodize + name.methodize + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/pathize.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/pathize.rb new file mode 100644 index 00000000..8fffd63c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/pathize.rb @@ -0,0 +1,19 @@ +require 'facets/string/pathize' + +class Class + + # Converts a class name to a unix path. + # + # module ::Example + # class PathizeExample + # end + # end + # + # Example::PathizeExample.pathize #=> "example/pathize_example" + # + def pathize + name.pathize + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/preallocate.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/preallocate.rb new file mode 100644 index 00000000..1608d7ca --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/preallocate.rb @@ -0,0 +1,55 @@ +class Class + + # Designate aspect modules to be added to a object at instantiation. + # + # class Firetruck + # def put_out_fire(option) + # "Put out #{option}" + # end + # end + # + # module FastFiretruck + # def put_out_fire(option) + # super("very #{option}!") + # end + # end + # + # Firetruck.preallocate(FastFiretruck) + # + # ft = Firetruck.new + # ft.put_out_fire('fast') #=> "Put out very fast!" + # + # This method is very similar to the idea of #prepend, but it has some + # limitations in that it works by overriding #new and #allocate and extends + # an object with the aspect modules on instantiation. A true #prepend + # implementation would not have to do this --but would be a natural part + # of the class heirarchy instead. For this reason, this method has been + # named #preallocate, rather than #prepend. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Trans + # + # @uncommon + # require 'facets/class/preallocate' + # + def preallocate(aspect) + _new = method(:new) + _allocate = method(:allocate) + (class << self; self; end).class_eval do + define_method(:new) do |*args| + o = _new.call(*args) + o.extend aspect + o + end + define_method(:allocate) do |*args| + o = _allocate.call(*args) + o.extend aspect + o + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/singleton.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/singleton.rb new file mode 100644 index 00000000..8eefd322 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/singleton.rb @@ -0,0 +1 @@ +require 'facets/class/singleton_class' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/singleton_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/singleton_class.rb new file mode 100644 index 00000000..8270d061 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/singleton_class.rb @@ -0,0 +1,16 @@ +class Class + + # Return true if a class is the singleton class of + # an object. + # + # @uncommon + # require 'facets/class/singleton_class' + # + def singleton_class? + ! ancestors.include?( self ) rescue false + end + + # @deprecated + alias :singleton? :singleton_class? + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/subclasses.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/subclasses.rb new file mode 100644 index 00000000..d81da045 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/subclasses.rb @@ -0,0 +1,28 @@ +class Class + + if defined?(Class.__subclasses__) # Rubinius + + # Returns an array with the direct children of +self+. + # + # Integer.subclasses # => [Fixnum, Bignum] + # + alias_method :subclasses, :__subclasses__ + + else + + # Returns an array with the direct children of +self+. + # + # Integer.subclasses # => [Fixnum, Bignum] + # + def subclasses + list = [] + ObjectSpace.each_object(Class) do |c| + list.unshift c if c.superclass == self + end + list.uniq + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/class/to_proc.rb b/bin/gems/facets-3.1.0/lib/core/facets/class/to_proc.rb new file mode 100644 index 00000000..431db7b3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/class/to_proc.rb @@ -0,0 +1,25 @@ +class Class + + # Convert instatiation of a class into a Proc. + # + # class Person + # def initialize(name) + # @name = name + # end + # + # def inspect + # @name.to_str + # end + # end + # + # persons = %w(john bob jane hans).map(&Person) + # + # persons.map{ |p| p.inspect } #=> ['john', 'bob', 'jane', 'hans'] + # + # CREDIT: Daniel Schierbeck + def to_proc + proc{|*args| new(*args)} + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable.rb new file mode 100644 index 00000000..a6167285 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable.rb @@ -0,0 +1,8 @@ +require_relative 'comparable/at_least.rb' +require_relative 'comparable/at_most.rb' +require_relative 'comparable/bound.rb' +require_relative 'comparable/cap.rb' +require_relative 'comparable/clip.rb' +require_relative 'comparable/cmp.rb' +require_relative 'comparable/op_get.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_least.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_least.rb new file mode 100644 index 00000000..9e800d29 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_least.rb @@ -0,0 +1 @@ +require 'facets/comparable/cap' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_most.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_most.rb new file mode 100644 index 00000000..9e800d29 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/at_most.rb @@ -0,0 +1 @@ +require 'facets/comparable/cap' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/bound.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/bound.rb new file mode 100644 index 00000000..7be2f6d0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/bound.rb @@ -0,0 +1 @@ +require 'facets/comparable/clip' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/cap.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/cap.rb new file mode 100644 index 00000000..d7136ba0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/cap.rb @@ -0,0 +1,34 @@ +module Comparable + + # Returns the lower of self or x. + # + # 4.at_least(5) #=> 5 + # 6.at_least(5) #=> 6 + # + # CREDIT: Florian Gross + + def at_least(lower) + (self >= lower) ? self : lower + end + + # Returns the greater of self or x. + # + # 4.at_most(5) #=> 4 + # 6.at_most(5) #=> 5 + # + # CREDIT: Florian Gross + + def at_most(upper) + (self <= upper) ? self : upper + end + + # Returns the greater of self or x. + # + # 4.cap(5) #=> 4 + # 6.cap(5) #=> 5 + # + # CREDIT: Trans + + alias_method :cap, :at_most + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/clip.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/clip.rb new file mode 100644 index 00000000..d4e417c1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/clip.rb @@ -0,0 +1,38 @@ +module Comparable + + # Returns self if above the given lower bound, or + # within the given lower and upper bounds, + # otherwise returns the the bound of which the + # value falls outside. + # + # 4.clip(3) #=> 4 + # 4.clip(5) #=> 5 + # 4.clip(2,7) #=> 4 + # 9.clip(2,7) #=> 7 + # 1.clip(2,7) #=> 2 + # + # CREDIT Florian Gross, Trans + + def clip(lower, upper=nil) + return lower if self < lower + return self unless upper + return upper if self > upper + return self + end + + # Returns self if above the given lower bound, or + # within the given lower and upper bounds, + # otherwise returns the the bound of which the + # value falls outside. + # + # 4.bound(3) #=> 4 + # 4.bound(5) #=> 5 + # 4.bound(2,7) #=> 4 + # 9.bound(2,7) #=> 7 + # 1.bound(2,7) #=> 2 + # + # CREDIT: Florian Gross + + alias_method :bound, :clip + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/cmp.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/cmp.rb new file mode 100644 index 00000000..411fe7ce --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/cmp.rb @@ -0,0 +1,41 @@ +module Comparable + + # Alternate name for comparison operator #<=>. + # + # 3.cmp(1) #=> 1 + # 3.cmp(3) #=> 0 + # 3.cmp(10) #=> -1 + # + # This fundamental compare method is used to keep + # comparison compatible with #succ. + # + # CREDIT: Peter Vanbroekhoven + + def cmp(o) + self<=>o + end + +end + +class String + + # Compare method that takes length into account. + # Unlike #<=>, this is compatible with #succ. + # + # "abc".cmp("abc") #=> 0 + # "abcd".cmp("abc") #=> 1 + # "abc".cmp("abcd") #=> -1 + # "xyz".cmp("abc") #=> 1 + # + # CREDIT: Peter Vanbroekhoven + # + # TODO: Move String#cmp to string/ directory. + + def cmp(other) + return -1 if length < other.length + return 1 if length > other.length + self <=> other # alphabetic compare + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/comparable/op_get.rb b/bin/gems/facets-3.1.0/lib/core/facets/comparable/op_get.rb new file mode 100644 index 00000000..5d2c7f2e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/comparable/op_get.rb @@ -0,0 +1,45 @@ +module Comparable + + # Automatically generate comparitive definitions based on + # attribute fields. + # + # include Comparable[:a, :b] + # + # is equivalent to including a module containing: + # + # def <=>(other) + # cmp = self.a <=> other.a; return cmp unless cmp == 0 + # cmp = self.b <=> other.b; return cmp unless cmp == 0 + # 0 + # end + # + def self.[](*accessors) + Module.new do + include Comparable + define_method(:comparability){ accessors } + define_method(:<=>) do |other| + comparability.each do |a| + cmp = (send(a) <=> other.send(a)) + break cmp unless cmp == 0 + end + end + end + end + +end + +# Would it be nice if we could define comparability for all objects? +# Then Comparable[] method would not be needed. Just: +# +# module Comparable +# +# def <=>(other) +# comparability.each do |field| +# cmp = send(field) <=> other.send(field); return cmp unless cmp == 0 +# end +# end +# +# end +# +# But I fear it might break other code. + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/denumerable.rb b/bin/gems/facets-3.1.0/lib/core/facets/denumerable.rb new file mode 100644 index 00000000..c7ad4e53 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/denumerable.rb @@ -0,0 +1,77 @@ +require 'facets/enumerator' +#require 'facets/enumerable/take' + +# Classes which include Denumerable will get versions of map, +# select, and so on, which return a Denumerator, so that they +# work horizontally without creating intermediate arrays. +# +# @author Brian Candler +# @author Trans + +module Denumerable + + # + def map + Denumerator.new do |output| + each do |*input| + output.yield yield(*input) + end + end + end + alias :collect :map + + # + def select + Denumerator.new do |output| + each do |*input| + output.yield(*input) if yield(*input) + end + end + end + alias :find_all :select + + # + def reject + Denumerator.new do |output| + each do |*input| + output.yield(*input) unless yield(*input) + end + end + end + + # Limit to the first n items in the list + def take(n) + Denumerator.new do |output| + count = 0 + each do |*input| + break if count >= n + output.yield(*input) + count += 1 + end + end + end + + # Skip the first n items in the list + def skip(n) + Denumerator.new do |output| + count = 0 + each do |*input| + output.yield(*input) if count >= n + count += 1 + end + end + end + + # TODO: add more methods, e.g. grep, take_while etc. + +end + + +# = Denumerator +# +# A class like Enumerator, but which has 'lazy' versions of map, select etc. +# +class Denumerator < Enumerator + include Denumerable +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir.rb new file mode 100644 index 00000000..2cc8002a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir.rb @@ -0,0 +1,7 @@ +require_relative 'dir/ascend.rb' +require_relative 'dir/descend.rb' +require_relative 'dir/each_child.rb' +require_relative 'dir/multiglob.rb' +require_relative 'dir/parent.rb' +require_relative 'dir/recurse.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/ascend.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/ascend.rb new file mode 100644 index 00000000..501f82c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/ascend.rb @@ -0,0 +1,56 @@ +class Dir + + # TODO: Make instance method versions ? + + # Ascend a directory path. + # + # a = [] + # + # Dir.ascend("/var/log") do |path| + # a << path + # end + # + # a #=> ['/var/log', '/var', '/'] + # + # CREDIT: Daniel Berger, Jeffrey Schwab + # + # TODO: Make it work with windows too + # use FileTest.root? + + def self.ascend(dir, inclusive=true, &blk) + dir = dir.dup + blk.call(dir) if inclusive + ri = dir.rindex('/') + while ri + dir = dir.slice(0...ri) + if dir == "" + blk.call('/') ; break + end + blk.call( dir ) + ri = dir.rindex('/') + end + end + + # Descend a directory path. + # + # d = [] + # + # Dir.descend("/var/log") do |path| + # d << path + # end + # + # d #=> ['/', '/var', '/var/log'] + # + # CREDIT: Daniel Berger, Jeffrey Schwab + + def self.descend(path) #:yield: + paths = path.split('/') + paths.size.times do |n| + pth = File.join(*paths[0..n]) + pth = "/" if pth == "" + yield(pth) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/descend.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/descend.rb new file mode 100644 index 00000000..69f9694c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/descend.rb @@ -0,0 +1 @@ +require 'facets/dir/ascend' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/each_child.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/each_child.rb new file mode 100644 index 00000000..82b6107c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/each_child.rb @@ -0,0 +1,16 @@ +class Dir + + # Like #each, except the "." and ".." special files are ignored. + # You can use +ignore+ to override '.' and '..' and ignore + # other entries via a exact match or regular expression. + # + # CREDIT: Tyler Rick + def each_child(*ignore) + ignore = ['.', '..'] if ignore.empty? + each do |file| + yield file unless ignore.any?{ |i| i === file } + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/lookup.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/lookup.rb new file mode 100644 index 00000000..ac4a7ad9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/lookup.rb @@ -0,0 +1,20 @@ +class Dir + + # Lookup directory tree for a path. + # + # TODO: Make a non class method version of this? + # + # Returns full path or `nil` if not found. [String,nil] + + def self.lookup(rel_path, parent_path='.') + while true + path = File.expand_path(rel_path, parent_path) + + return path if File.exists?(path) + return nil if path == '/' + + parent_path = File.expand_path('..', parent_path) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/multiglob.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/multiglob.rb new file mode 100644 index 00000000..ebfec4c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/multiglob.rb @@ -0,0 +1,78 @@ +class Dir + + # Like +glob+ but can take multiple patterns. + # + # Dir.multiglob('tmp/*.rb', 'tmp/*.py') + # + # Rather then constants for options multiglob accepts a trailing options + # hash of symbol keys... + # + # :noescape File::FNM_NOESCAPE + # :casefold File::FNM_CASEFOLD + # :pathname File::FNM_PATHNAME + # :dotmatch File::FNM_DOTMATCH + # :strict File::FNM_PATHNAME && File::FNM_DOTMATCH + # + # It also has an option for recurse... + # + # :recurse Recurively include contents of directories. + # + # For example + # + # Dir.multiglob('tmp/*', :recurse => true) + # + # would have the same result as + # + # Dir.multiglob('tmp/**/*') + # + def self.multiglob(*patterns) + options = (Hash === patterns.last ? patterns.pop : {}) + + if options.delete(:recurse) + ##patterns += patterns.collect{ |f| File.join(f, '**', '**') } + multiglob_r(*patterns) + end + + bitflags = 0 + bitflags |= File::FNM_NOESCAPE if options[:noescape] + bitflags |= File::FNM_CASEFOLD if options[:casefold] + bitflags |= File::FNM_PATHNAME if options[:pathname] or options[:strict] + bitflags |= File::FNM_DOTMATCH if options[:dotmatch] or options[:strict] + + patterns = [patterns].flatten.compact + + if options[:recurse] + patterns += patterns.collect{ |f| File.join(f, '**', '**') } + end + + files = [] + files += patterns.collect{ |pattern| Dir.glob(pattern, bitflags) }.flatten.uniq + + return files + end + + # The same as +multiglob+, but recusively includes directories. + # + # Dir.multiglob_r('tmp') + # + # is equivalent to + # + # Dir.multiglob('tmp', :recurse=>true) + # + # The effect of which is + # + # Dir.multiglob('tmp', 'tmp/**/**') + # + def self.multiglob_r(*patterns) + options = Hash === patterns.last ? patterns.pop : {} + matches = multiglob(*patterns) + directories = matches.select{ |m| File.directory?(m) } + matches += directories.map{ |d| multiglob_r(File.join(d, '**'), options) }.flatten + matches.uniq + ##options = (Hash === patterns.last ? patterns.pop : {}) + ##options[:recurse] = true + ##patterns << options + ##multiglob(*patterns) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/parent.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/parent.rb new file mode 100644 index 00000000..76173a3e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/parent.rb @@ -0,0 +1,16 @@ +class Dir + + # Is a path parental to another? + # + # Dir.parent?('parent', 'parent/child') #=> true + # + # TODO: Needs improvement. + # + # TODO: Instance version? + + def self.parent?(parent_path, child_path) + %r|^#{Regexp.escape(parent_path)}| =~ child_path ? true : false + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/dir/recurse.rb b/bin/gems/facets-3.1.0/lib/core/facets/dir/recurse.rb new file mode 100644 index 00000000..71ce2501 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/dir/recurse.rb @@ -0,0 +1,35 @@ +class Dir + + # Recursively scan a directory and pass each file to the given block. + # + # Dir.recurse('.') do |path| + # # ... + # end + # + # CREDIT: George Moschovitis + # + # TODO: If fully compatible, reimplement as alias of Find.find, + # or just copy and paste Find.find code here if it looks more robust. + # + def self.recurse(path='.', &block) + list = [] + stoplist = ['.', '..'] + Dir.foreach(path) do |f| + next if stoplist.include?(f) + filename = (path == '.' ? f : path + '/' + f) + list << filename + block.call(filename) if block + if FileTest.directory?(filename) and not FileTest.symlink?(filename) + list.concat(Dir.recurse(filename, &block)) + end + end + list + end + + # Same as Dir#recurse. + def self.ls_r(path='.', &block) + recurse(path, &block) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable.rb new file mode 100644 index 00000000..d0d7bc87 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable.rb @@ -0,0 +1,40 @@ +require_relative 'enumerable/accumulate.rb' +#require_relative 'enumerable/associate.rb' +require_relative 'enumerable/cluster.rb' +require_relative 'enumerable/collect_with_index.rb' +require_relative 'enumerable/compact_map.rb' +require_relative 'enumerable/defer.rb' +require_relative 'enumerable/each_by.rb' +require_relative 'enumerable/every.rb' +require_relative 'enumerable/ewise.rb' +require_relative 'enumerable/exclude.rb' +require_relative 'enumerable/expand.rb' +require_relative 'enumerable/filter.rb' +require_relative 'enumerable/find_yield.rb' +require_relative 'enumerable/frequency.rb' +require_relative 'enumerable/graph.rb' +#require_relative 'enumerable/hashify.rb' +require_relative 'enumerable/incase.rb' +require_relative 'enumerable/key_by' +require_relative 'enumerable/map_by.rb' +require_relative 'enumerable/map_detect.rb' +require_relative 'enumerable/map_send.rb' +require_relative 'enumerable/map_with.rb' +require_relative 'enumerable/map_with_index.rb' +require_relative 'enumerable/mash.rb' +require_relative 'enumerable/modulate.rb' +require_relative 'enumerable/occur.rb' +require_relative 'enumerable/organize_by.rb' +require_relative 'enumerable/only.rb' +require_relative 'enumerable/pair.rb' +require_relative 'enumerable/per.rb' +require_relative 'enumerable/purge.rb' +require_relative 'enumerable/recursively.rb' +require_relative 'enumerable/squeeze.rb' +require_relative 'enumerable/sum.rb' +require_relative 'enumerable/value_by' +#require_relative 'enumerable/unassociate.rb' +require_relative 'enumerable/uniq_by.rb' +require_relative 'enumerable/visit.rb' +require_relative 'enumerable/zip_map.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/accumulate.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/accumulate.rb new file mode 100644 index 00000000..de7f1d9f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/accumulate.rb @@ -0,0 +1,67 @@ +require 'facets/functor' + +module Enumerable + + # TODO: Should Enumerable#accumuate be moved to a functor gem?" + + # Accumulate a set of a set. For example, in an ORM design + # where `Group has_many User` we might have something + # equivalent to the following. + # + # Group = Struct.new(:users) + # User = Struct.new(:name, :friends) + # + # user1 = User.new('John', []) + # user2 = User.new('Jane', ['Jill']) + # user3 = User.new('Joe' , ['Jack', 'Jim']) + # + # group1 = Group.new([user1, user2]) + # group2 = Group.new([user2, user3]) + # + # groups = [group1, group2] + # + # Now we can *accumulate* the users of all groups. + # + # groups.accumulate.users #=> [user1, user2, user3] + # + # You may pass an argument to perform chains, e.g. the following + # returns the names of users from all groups. + # + # groups.accumulate(2).users.name #=> ['John','Jane','Joe'] + # + # Or we can gather all the friends of all users in groups. + # + # groups.accumulate(2).users.friends #=> ['Jill','Jack','Jim'] + # + # This is more convenient then the equivalent. + # + # groups.accumulate.users.accumulate.friends #=> ['Jill','Jack','Jim'] + # + # CREDIT: George Moshchovitis, Daniel Emirikol, Robert Dober + + def accumulate(iterations=1) + return self if iterations == 0 + + Functor.new do |op, *args| + result = [] + each { |x| result << x.send(op, *args) } + result.flatten.uniq.accumulate(iterations - 1) + end + end + + # Same as #accumulate, but does not apply #uniq to final result. + # + # groups.accumulate_all(2).users.friends #=> ['Jill', 'Jill','Jack','Jim'] + # + def accumulate_all(iterations=1) + return self if iterations == 0 + + Functor.new do |op, *args| + result = [] + each { |x| result << x.send(op, *args) } + result.flatten.accumulate_all(iterations - 1) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/apply.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/apply.rb new file mode 100644 index 00000000..04e7d7a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/apply.rb @@ -0,0 +1,20 @@ +#require 'facets/functor' +require 'facets/enumerable/per' + +module Enumerable + + # Returns an elemental object. This allows + # you to map a method on to every element. + # + # r = [1,2,3].apply.+ + # r #=> 6 + # + def apply + #Functor.new do |sym, *args, &blk| + # inject{ |r, e| r.__send__(sym, e, *args, &blk) } + #end + per(:inject) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/associate.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/associate.rb new file mode 100644 index 00000000..e2c7abe7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/associate.rb @@ -0,0 +1,6 @@ +require 'facets/enumerable/pair' + +module Enumerable + # Alias for #pair. + alias :associate :pair +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/cluster.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/cluster.rb new file mode 100644 index 00000000..7d9e96d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/cluster.rb @@ -0,0 +1,26 @@ +module Enumerable + + # Clusters together adjacent elements into a list of sub-arrays. + # + # [2,2,2,3,3,4,2,2,1].cluster{ |x| x } + # => [[2, 2, 2], [3, 3], [4], [2, 2], [1]] + # + # ["dog", "duck", "cat", "dude"].cluster{ |x| x[0] } + # => [["dog", "duck"], ["cat"], ["dude"]] + # + # @author Oleg K + + def cluster + cluster = [] + each do |element| + if cluster.last && yield(cluster.last.last) == yield(element) + cluster.last << element + else + cluster << [element] + end + end + cluster + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/collect_with_index.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/collect_with_index.rb new file mode 100644 index 00000000..9bd4b598 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/collect_with_index.rb @@ -0,0 +1,2 @@ +require 'facets/enumerable/map_with_index' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/compact_map.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/compact_map.rb new file mode 100644 index 00000000..10f4b148 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/compact_map.rb @@ -0,0 +1,36 @@ +module Enumerable + + # A more versitle #compact method. It can be used to + # collect and filter items out in one single step. + # + # c = [1,2,3].compact_map do |n| + # n < 2 ? nil : n + # end + # + # c #=> [2,3] + # + # CREDIT: Trans + # + # DEPRECATE: This method should probably be removed b/c #purge + # does almost the same thing and enum.map{}.compact works too. + + def compact_map(&block) + y = [] + if block_given? + each do |*a| + r = yield(*a) + y << r unless r.nil? + end + else + each do |r| + y << r unless r.nil? + end + end + y + end + + # + alias_method :compact_collect, :compact_map + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/defer.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/defer.rb new file mode 100644 index 00000000..51a0a64c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/defer.rb @@ -0,0 +1,46 @@ +require 'facets/denumerable' + +module Enumerable + + # Without a block: wrap the Enumerable object in such a way that map, + # select and similar operations are performed "horizontally" across a + # series of blocks, instead of building an array of results at each step. + # This reduces memory usage, allows partial results to be provided + # early, and permits working with infinite series. + # + # a = (1..1_000_000_000).defer.select{ |i| i % 2 == 0 }. + # map{ |i| i + 100 }. + # take(10).to_a + # + # With a block: the block acts as an arbitrary filter on the data. Unlike + # map, it can choose to drop elements from the result, and/or add + # additional ones. The first object passed to the block is the receiver + # of the output. + # + # (1..1_000_000_000). + # defer { |out,i| out << i if i % 2 == 0 }. # like select + # defer { |out,i| out << i + 100 }. # like map + # take(10).to_a + # + # Use a method like to_a or to_h at the end of the chain when you want an + # Array or Hash built with the results, or each{...} if you just want + # to output each result and discard it. + # + def defer(&blk) + if block_given? + Denumerator.new do |output| + each do |*input| + yield(output, *input) + end + end + else + Denumerator.new do |output| + each do |*input| + output.yield(*input) + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/each_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/each_by.rb new file mode 100644 index 00000000..2d01bbc4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/each_by.rb @@ -0,0 +1,33 @@ +require 'facets/enumerator' + +module Enumerable + + # Iterate through slices. If slice +steps+ is not + # given, the arity of the block is used. + # + # x = [] + # [1,2,3,4].each_by{ |a,b| x << [a,b] } + # x #=> [ [1,2], [3,4] ] + # + # x = [] + # [1,2,3,4,5,6].each_by(3){ |a| x << a } + # x #=> [ [1,2,3], [4,5,6] ] + # + # This is just like each_slice, except that it will check + # the arity of the block. If each_slice ever suppots this + # this method can be deprecated. + # + # CREDIT: Trans + + def each_by(steps=nil, &block) + if steps + each_slice(steps, &block) + else + steps = block.arity.abs + each_slice(steps, &block) + #each_slice(steps) {|i| block.call(*i)} + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/every.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/every.rb new file mode 100644 index 00000000..6bd5ceb4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/every.rb @@ -0,0 +1,40 @@ +require 'facets/enumerable/per' + +module Enumerable + + # Returns an elemental object. This allows + # you to map a method on to every element. + # + # r = [1,2,3].every + 3 + # r #=> [4,5,6] + # + def every + per(:map) + end + + # In place version of #every. + # + def every! + raise NoMethodError unless respond_to?(:map!) + per(:map!) + end + + #-- + # These used to be defined via H.O.M. as follows ... + # + # def every + # Functor.new do |op,*args| + # map{ |a| a.send(op,*args) } + # end + # end + # + # def every! + # raise NoMethodError unless respond_to?(:map!) + # Functor.new do |op,*args| + # map!{ |a| a.send(op,*args) } + # end + # end + #++ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/ewise.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/ewise.rb new file mode 100644 index 00000000..89d284fa --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/ewise.rb @@ -0,0 +1,61 @@ +require 'facets/functor' + +module Enumerable + + # TODO: Should Enumerable#ewise be moved to functor gem?" + + # Returns an elementwise Functor designed to make R-like + # elementwise operations possible. This is very much like + # the #every method, but it treats array argument specially. + # + # ([1,2].ewise + 3) #=> [4,5] + # + # Vector to vector + # + # ([1,2].ewise + [4,5]) #=> [5,7] + # + # Special thanks to Martin DeMello for helping to develop this. + + def ewise(count=1) + Functor.new do |op,*args| + if args.empty? + r = self + count.times do + r = r.collect{ |a| a.send(op) } + end + r + else + r = args.collect do |arg| + if Array === arg #arg.kind_of?(Enumerable) + x = self + count.times do + ln = (arg.length > length ? length : arg.length ) + x = x.slice(0...ln) + x = x.zip(arg[0...ln]) + x = x.collect{ |a,b| a.send(op,b) } #x = x.collect{ |a,b| b ? a.send(op,b) : nil } + end + x + else + x = self + count.times do + x = x.collect{ |a| a.send(op,arg) } + end + x + end + end + r.flatten! if args.length == 1 + r + end + end + end + + # Long-term for #ewise. + # + # a = [1,2] + # (a.elementwise + 3) #=> [4,5] + # (a.elementwise + [4,5]) #=> [5,7] + # + alias_method :elementwise, :ewise + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/exclude.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/exclude.rb new file mode 100644 index 00000000..01390102 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/exclude.rb @@ -0,0 +1,16 @@ +module Enumerable + + unless method_defined?(:exclude?) # 1.9 + + # The inverse of #include?. + # + # [:a, :b].exclude?(:c) #=> true + # [:a, :b].exclude?(:a) #=> false + # + def exclude?(object) + !include?(object) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/expand.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/expand.rb new file mode 100644 index 00000000..d93861d9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/expand.rb @@ -0,0 +1,15 @@ +module Enumerable + + # Expand all elements of an Enumerable object. + # + # [0, 2..3, 5..7].expand #=> [0,[2, 3],[5,6,7]] + # + # CREDIT: Trans + def expand + map do |x| + (Enumerable === x ? x.expand : x) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/filter.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/filter.rb new file mode 100644 index 00000000..c484e563 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/filter.rb @@ -0,0 +1,33 @@ +module Enumerable + + # The block acts as an arbitrary filter on the data. Unlike map, + # it can choose to drop elements from the result and/or add + # additional elements. The first object passed to the block is + # the receiver of the output. + # + # x = (1..10000) + # x = x.filter{ |out,i| out << i if i % 2 == 0 } # like select + # x = x.filter{ |out,i| out << i + 100 } # like map + # x = x.take(3) + # + # x #=> [102, 104, 106] + # + # This is very similar to #each_with_object, but #filter handles + # argument better by reversing their order and using the splat + # operator. (This was also once known as #injecting.) + # + # CREDIT: David Black, Louis J Scoras + + def filter(output=[]) #:yeild: + if block_given? + each do |*input| + yield(output, *input) + end + output + else + to_enum(:filter) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/find_yield.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/find_yield.rb new file mode 100644 index 00000000..49f5cd23 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/find_yield.rb @@ -0,0 +1,42 @@ +module Enumerable + + # Yield each element to the block and return the result + # of the block when that result evaluates as true, + # terminating early like #detect and #find. + # + # obj1 = Object.new + # obj2 = Object.new + # + # def obj1.foo?; false; end + # def obj2.foo?; true ; end + # + # def obj1.foo ; "foo1"; end + # def obj2.foo ; "foo2"; end + # + # [obj1, obj2].find_yield{ |obj| obj.foo if obj.foo? } #=> "foo2" + # + # Another example. + # + # [1,2,3,4,5].find_yield{ |i| j = i+1; j if j % 4 == 0 } #=> 4 + # + # If the block is never true, return the object given in the first parameter, + # or nil if none specified. + # + # [1,2,3].find_yield{ |_| false } #=> nil + # [false].find_yield(1){ |_| false } #=> 1 + # + def find_yield(fallback=nil) #:yield: + each do |member| + result = yield(member) + return result if result + end + fallback + end + + # Alias for #find_yield. + # + # DEPRECATE: This has been renamed to #find_yield. + alias_method :map_detect, :find_yield + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/frequency.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/frequency.rb new file mode 100644 index 00000000..e1f671e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/frequency.rb @@ -0,0 +1,24 @@ +module Enumerable + + # Generates a hash mapping each unique symbol in the array + # to the absolute frequency it appears. + # + # [:a,:a,:b,:c,:c,:c].frequency #=> {:a=>2,:b=>1,:c=>3} + # + # CREDIT: Brian Schröder + # + #-- + # NOTE: So why not use #inject here? e.g. ... + # + # inject(Hash.new(0)){|p,v| p[v]+=1; p} + # + # Because it is a fair bit slower than the traditional definition. + #++ + + def frequency + p = Hash.new(0); each{ |v| p[v] += 1 }; p + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/graph.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/graph.rb new file mode 100644 index 00000000..79b00360 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/graph.rb @@ -0,0 +1,34 @@ +module Enumerable + + # Like `#map`/`#collect`, but generates a Hash. The block is expected + # to return two values: the key and the value for the new hash. + # + # numbers = (1..3) + # squares = numbers.graph{ |n| [n, n*n] } # { 1=>1, 2=>4, 3=>9 } + # sq_roots = numbers.graph{ |n| [n*n, n] } # { 1=>1, 4=>2, 9=>3 } + # + # CREDIT: Andrew Dudzik (adudzik), Trans + + def graph(&yld) + if yld + h = {} + each do |*kv| + r = yld[*kv] + case r + when Hash + nk, nv = *r.to_a[0] + when Range + nk, nv = r.first, r.last + else + nk, nv = *r + end + h[nk] = nv + end + h + else + Enumerator.new(self,:graph) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hashify.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hashify.rb new file mode 100644 index 00000000..9533fe06 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hashify.rb @@ -0,0 +1,230 @@ +#require 'facets/enumerator' +require 'facets/hash/dearray_values' +require 'facets/enumerable/value_by' + +module Enumerable + + # The hashify methods is a higher-order message used to + # convert an enumerable object into a hash. Converting an + # enumerable object into a hash is not a one-to-one conversion, + # for this reason #hashify is used to provide variant approches + # for the conversion most suited to the use case at hand. + # Here are some (but not a complete set of) examples. + # + # If the enumerable is a collection of perfect pairs, like that + # which Hash#to_a generates, then #assoc can be used. + # + # a = [ [:a,1], [:b,2] ] + # a.hashify.assoc #=> { :a=>1, :b=>2 } + # + # If it it contains only arrays, but are not perfect pairs, + # then #concat can be used. + # + # a = [ [:a,1,2], [:b,2], [:c], [:d] ] + # a.hashify.concat #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + # + # If the array contains objects other then arrays then + # the #splat method might do the trick. + # + # a = [ [:a,1,2], 2, :b, [:c,3], 9 ] + # a.hashify.splat #=> { [:a,1,2]=>2, :b=>[:c,3], 9=>nil } + # + # Also, the particular dispatch can be left up the Hashify + # using the #auto method. See Hashify#auto for details on this. + # + # TODO: This method takes arguments only for the sake of the old + # method which has been deprecated. These will be removed eventually. + # + # CREDIT: Robert Klemme, Sandor Szücs, Trans + + def hashify(val=nil, &block) + if val + warn "The old Enumerable#hashify method has been be deprecated. Use #value_by instead." + value_by{ val } + end + + if block + warn "The old Enumerable#hashify method has been be deprecated. Use #value_by instead." + value_by(&block) + end + + Hashifier.new(self) + end + + # + class Hashifier + + def initialize(enum) + @enum = enum + end + + # This is equivalent to Hash[*array], but it will pad + # the array with a +nil+ object if there are not an even number + # of elements. + # + # a = [:a,1,:b,2,:c] + # a.to_h_splat #=> { :a=>1, :b=>2, :c=>nil } + def splat + a = @enum.to_a + a << nil if a.size.odd? + Hash[*a] + end + + # This is equivalent to Hash[*array.flatten], but it will pad + # the array with a +nil+ object if there are not an even number + # of elements. + # + # a = [:a,1,[:b,2,:c]] + # a.to_h_flat #=> { :a=>1, :b=>2, :c=>nil } + def flat + a = @enum.to_a.flatten + a << nil if a.size.odd? + Hash[*a] + end + + # When a mixed or multi-element associative array + # is used, the result is as follows: + # + # a = [ [:a,1,2], [:b,2], [:c], :d ] + # a.hashify.assoc #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + # + # If the first entry of any subelements are the same, then + # the value will be set to the last occurring value. + # + # a = [ :x, [:x], [:x,1,2], [:x,3], [:x,4] ] + # a.hashify.assoc #=> { :x=>[4] } + # + def associate + h = {} + each do |k,*v| + h[k] = v + end + h + end + + # Alias for #associate. + alias :assoc :associate + + # Like associate but does force values into an array. + # + def merge + h = {} + each do |k,v| + h[k] = v + end + h + end + + # When a mixed or multi-element associative array + # is used, the result is as follows: + # + # a = [ [:a,1,2], [:b,2], [:c], :d ] + # a.hashify.concat #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + # + # If the first entry of the subelements is the same, then + # the values will be merged using #concat. + # + # a = [ [:a,1,2], [:a,3], [:a,4], [:a], :a ] + # a.hashify.concat #=> { :a=>[1,2,3,4] } + # + def concat + h = {} + each do |k,*v| + h[k] ||= [] + h[k].concat(v) + end + h + end + + # Older name for #concat. + alias :multi :concat + + # Convert enumerable object to Hash using index as keys. + # + # [:a, :b, :c].hashify.by_index #=> {1=>:a, 2=>:b, 3=>:c} + # + def by_index + h = {} + each_with_index do |v, i| + h[i] = v + end + h + end + + # Converts enumerable object into a hash. Converting an array + # into a hash is not a one-to-one conversion, for this + # reason #auto examines the enumerable being converted + # and then dispatches the conversion to the most suitable + # specialized function. There are three possibilities for this. + # + # If the enumerable is a collection of perfect pairs, like that + # which Hash#to_a generates, then conversion is handled by + # #flat. + # + # a = [ [:a,1], [:b,2] ] + # a.hashify.auto #=> { :a=>1, :b=>2 } + # + # If it contains only arrays, but are not perfect pairs, + # then #multi is called. + # + # a = [ [:a,1,2], [:b,2], [:c], [:d] ] + # a.hashify.auto #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + # + # If it contains objects other then arrays then the #splat method + # is called. + # + # a = [ [:a,1,2], 2, :b, [:c,3], 9 ] + # a.hashify.auto #=> { [:a,1,2]=>2, :b=>[:c,3], 9=>nil } + # + # Be aware this is not as efficient as using the underlying methods + # directly because it must perform an initial iteration over the + # enumerable to determine its contents. + + def auto(&block) + pairs, mixed = true, false + + each do |e| + case e + when Array + pairs = false if e.size > 2 + else + mixed = true + end + end + + if mixed + splat(&block) + elsif pairs + flat(&block) + else + multi(&block) + end + end + + # Alias for `#auto`. + alias :automatic :auto + + private + + # + def each(&b) + @enum.each(&b) + end + + # + def each_with_index(&b) + @enum.each_with_index(&b) + end + + end + +end + + +#class Enumerator +# # See `Enumerable#hashify`. +# def hashify +# Hashifier.new(self) +# end +#end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hinge.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hinge.rb new file mode 100644 index 00000000..1227477c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/hinge.rb @@ -0,0 +1,18 @@ +module Enumerable + + # Apply each element of an enumerable ot a hash + # by iterating over each element and yielding + # the hash and element. + # + # [1,2,3].hinge{|h,e| h[e] = e+1 } + # #=> {1=>2, 2=>3, 3=>4} + # + # TODO: Enumerable#hinge will get a new name. + # + def hinge(init={}) + h = init + each{ |v| yield(h,v) } + h + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/incase.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/incase.rb new file mode 100644 index 00000000..ce13c39c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/incase.rb @@ -0,0 +1,19 @@ +module Enumerable + + # The same as #include? but tested using #=== instead of #==. + # + # [1, 2, "a"].incase?(2) #=> true + # [1, 2, "a"].incase?(String) #=> true + # [1, 2, "a"].incase?(3) #=> false + # + # Why the name `incase`? Because the method uses case-equality. + # Along with the alliteration for "in case" and the similarity + # with "include?", it seemed like the perfect fit. + # + # @author Lavir the Whiolet + # + def incase?(what) + any? { |x| what === x } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/key_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/key_by.rb new file mode 100644 index 00000000..8a43feab --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/key_by.rb @@ -0,0 +1,27 @@ +module Enumerable + + # Convert enumerable into a Hash, iterating over each member + # where the provided block must return the key to by used + # to map to the value. + # + # Examples: + # + # [:a,:b,:c].key_by{ |v| v.to_s } + # #=> {'a'=>:a, 'b'=>:b, 'c'=>:c} + # + # TODO: How should this method behave with a Hash? + # + # Returns: Hash + + def key_by + return to_enum(:key_by) unless block_given? + + h = {} + each do |v| + h[yield(v)] = v + end + + return h + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_by.rb new file mode 100644 index 00000000..5822b705 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_by.rb @@ -0,0 +1,35 @@ +module Enumerable + + # Like #group_by, but maps the second value returned from the block. + # + # a = [1,2,3,4,5] + # a.map_by{ |e| [e % 2, e + 1] } + # #=> { 0=>[3,5], 1=>[2,4,6] } + # + # Works well with a hash too. + # + # h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2} + # h.map_by{ |k,v| [v, k.downcase] } + # #=> {1=>["a", "b", "c"], 2=>["d", "e"]} + # + # If a second value is not returned, #map_by acts like #group_by. + # + # h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2} + # h.map_by{ |k,v| v } + # #=> {1=>[["A",1], ["B",1], ["C",1]], 2=>[["D",2], ["E",2]]} + # + def map_by #:yield: + res = {} + each do |a| + k,v = yield(*a) + if v + (res[k] ||= []) << v + else + (res[k] ||= []) << a + end + end + res + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_detect.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_detect.rb new file mode 100644 index 00000000..abb81afd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_detect.rb @@ -0,0 +1 @@ +require 'facets/enumerable/find_yield' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_send.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_send.rb new file mode 100644 index 00000000..e28de7f2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_send.rb @@ -0,0 +1,26 @@ +module Enumerable + + # Send a message to each element and collect the result. + # + # [1,2,3].map_send(:+, 3) #=> [4,5,6] + # + # CREDIT: Sean O'Halpin + + def map_send(meth, *args, &block) + map{|e| e.send(meth, *args, &block)} + end + + #-- + # Old defintion confused me ... + # + # def map_send(meth, *args) #:yield: + # if block_given? + # map{|e| yield(e.send(meth, *args))} + # else + # map{|e| e.send(meth, *args)} + # end + # end + #++ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_to.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_to.rb new file mode 100644 index 00000000..dc3aef6e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_to.rb @@ -0,0 +1,13 @@ +module Enumerable + + # Map each element into another class via class constructor. + # + # @param [#new] to_class + # Generally a class, but any object that repsonds to #new. + # + def map_to(to_class) + map{ |e| to_class.new(e) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with.rb new file mode 100644 index 00000000..8d1780c2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with.rb @@ -0,0 +1,21 @@ +module Enumerable + + # Combines #zip and #map in a single efficient operation. + # + # h = {} + # [1,2,3].map_with [:x,:y,:z] do |n,k| + # h[k] = n + # end + # h #=> {:x=>1, :y=>2, :z=>3} + # + # @return [Hash] + # + # @author Michael Kohl + def map_with(*arrays, &block) + enum_for(:zip, *arrays).map(&block) + end + + # + alias_method :zip_map, :map_with + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with_index.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with_index.rb new file mode 100644 index 00000000..538335a4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/map_with_index.rb @@ -0,0 +1,23 @@ +module Enumerable + + # Same as #collect but with an iteration counter. + # + # a = [1,2,3].collect_with_index { |e,i| e*i } + # a #=> [0,2,6] + # + # CREDIT: Gavin Sinclair + + def map_with_index + r = [] + each_with_index do |e, i| + r << yield(e, i) + end + r + end + + # Alias for map_with_index. + + alias_method :collect_with_index, :map_with_index + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/mash.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/mash.rb new file mode 100644 index 00000000..f612257a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/mash.rb @@ -0,0 +1,34 @@ +module Enumerable + + # Like `#map`/`#collect`, but generates a Hash. The block is expected + # to return two values: the key and the value for the new hash. + # + # numbers = (1..3) + # squares = numbers.mash{ |n| [n, n*n] } # { 1=>1, 2=>4, 3=>9 } + # sq_roots = numbers.mash{ |n| [n*n, n] } # { 1=>1, 4=>2, 9=>3 } + # + # CREDIT: Andrew Dudzik (adudzik), Trans + + def mash(&yld) + if yld + h = {} + each do |*kv| + r = yld[*kv] + case r + when Hash + nk, nv = *r.to_a[0] + when Range + nk, nv = r.first, r.last + else + nk, nv = *r + end + h[nk] = nv + end + h + else + Enumerator.new(self,:graph) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/modulate.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/modulate.rb new file mode 100644 index 00000000..2aa87c2c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/modulate.rb @@ -0,0 +1,22 @@ +module Enumerable + + # Divide an array into groups by modulo of the index. + # + # [2,4,6,8].modulate(2) #=> [[2,6],[4,8]] + # + # CREDIT: Trans + # + # NOTE: Would the better name for this be 'collate'? + + def modulate(modulo) + return to_a if modulo == 1 + raise ArgumentError, 'bad modulo' if size % modulo != 0 + r = Array.new(modulo, []) + (0...size).each do |i| + r[i % modulo] += [self[i]] + end + r + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/occur.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/occur.rb new file mode 100644 index 00000000..68b40d4c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/occur.rb @@ -0,0 +1,41 @@ +module Enumerable + + # Returns an array of elements for the elements that occur n times. + # Or according to the results of a given block. + # + # a = [1,1,2,3,3,4,5,5] + # + # a.occur(1).sort #=> [2,4] + # a.occur(2).sort #=> [1,3,5] + # a.occur(3).sort #=> [] + # + # a.occur(1..1).sort #=> [2,4] + # a.occur(2..3).sort #=> [1,3,5] + # + # a.occur { |n| n == 1 }.sort #=> [2,4] + # a.occur { |n| n > 1 }.sort #=> [1,3,5] + # + def occur(n=nil) #:yield: + result = Hash.new { |hash, key| hash[key] = Array.new } + + each do |item| + key = item + result[key] << item + end + + if block_given? + result.reject! { |key, values| ! yield(values.size) } + else + raise ArgumentError unless n + if Range === n + result.reject! { |key, values| ! n.include?(values.size) } + else + result.reject! { |key, values| values.size != n } + end + end + + return result.values.flatten.uniq + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/only.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/only.rb new file mode 100644 index 00000000..b9d5cceb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/only.rb @@ -0,0 +1,56 @@ +module Enumerable + + # Returns the _only_ element in the enumerable. Raises an IndexError if + # the enumreable has more then one element. + # + # [5].only # => 5 + # + # expect IndexError do + # [1,2,3].only + # end + # + # expect IndexError do + # [].only + # end + # + # CREDIT: Lavir the Whiolet, Gavin Sinclair, Noah Gibbs + # + def only + first = false + first_item = nil + + each do |item| + if first + raise IndexError, "not the only element of enumerable" + else + first = true + first_item = item + end + end + + if first + return first_item + else + raise IndexError, "not the only element of enumerable" + end + end + + # Does this Enumerable have the only element? + # + # It differs from Enumerable#one? in that it does not check the items + # themselves. It checks the quantity only. + # + # CREDIT: Lavir the Whiolet + # + def only? + first = false + + each do |item| + return false if first + first = true + end + + return first + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/organize_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/organize_by.rb new file mode 100644 index 00000000..b7b197f1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/organize_by.rb @@ -0,0 +1,19 @@ +module Enumerable + + # Similar to #group_by but returns an array of the groups. + # Returned elements are sorted by block. + # + # %w{this is a test}.organize_by {|x| x[0]} + # #=> [ ['a'], ['is'], ['this', 'test'] ] + # + # CREDIT: Erik Veenstra + + def organize_by(&b) + group_by(&b).sort.transpose.pop || [] # group_by(&b).values ? + end + + # DEPRECATED: Name changed to avoid confusion with #cluster. + alias cluster_by organize_by + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/pair.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/pair.rb new file mode 100644 index 00000000..edbcbdfd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/pair.rb @@ -0,0 +1,20 @@ +module Enumerable + + # Like `each_slice(2)` but ensures the last + # element has a pair if odd sized. + # + # [:a,1,:b,2,:c,3].pair.to_a #=> [[:a,1],[:b,2],[:c,3]] + # + def pair(missing=nil) + return to_enum(:pair) unless block_given? + + each_slice(2) do |kv| + if kv.size == 1 + yield kv.first, missing + else + yield kv.first, kv.last + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/per.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/per.rb new file mode 100644 index 00000000..b672df21 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/per.rb @@ -0,0 +1,77 @@ +require 'facets/functor' + +module Enumerable + + # TODO: Consider Enumerator methods. + + # TODO: Should Enumerable#pre be moved to functor gem? + + # TODO: Does the `*y` argument make sense? + + # Per element meta-functor. + # + # ([1,2,3].per(:map) + 3) #=> [4,5,6] + # ([1,2,3].per(:select) > 1) #=> [2,3] + # + # Using fluid notation. + # + # ([1,2,3].per.map + 3) #=> [4,5,6] + # ([1,2,3].per.select > 1) #=> [2,3] + # + def per(enum_method=nil, *enum_args) + if enum_method + Functor.new do |op, *args, &blk| + __send__(enum_method || :map, *enum_args){ |x, *y| x.__send__(op, *y, *args, &blk) } + end + else + Functor.new do |enumr_method, *enumr_args| + Functor.new do |op, *args, &blk| + __send__(enumr_method, *enumr_args){ |x, *y| x.__send__(op, *y, *args, &blk) } + end + end + end + end + +=begin + def per(enum_method=nil, *enum_args) + if enum_method + Permeator.new(self, enum_method, *enum_args) + else + Functor.new do |enumr_method, *enumr_args| + Permeator.new(self, enumr_method, *enumr_args) + end + end + end + + # Permeator is a Functor for operating over each element of an Enumearble. + # (Note: This used to be called an Elementor.) + # + # TODO: With Ruby 1.9+ this would not be required, as it can be replaced + # by a generic Functor, becuase then lambda definitions can pass blocks. + # + class Permeator #:nodoc: + private(*instance_methods.select{|x| x !~ /^__/ }) + + def initialize(enum_object, enum_method=nil, *enum_args) + @enum_object = enum_object + @enum_method = enum_method || :map + @enum_args = enum_args + end + + def instance_delegate + @enum_object + end + + def instance_operator + @enum_method + end + + def method_missing(sym, *args, &blk) + #@enum_object.__send__(@enum_method){ |x| x.__send__(sym, *args, &blk) } + @enum_object.__send__(@enum_method){ |x, *y| x.__send__(sym, *y, *args, &blk) } + end + end +=end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/purge.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/purge.rb new file mode 100644 index 00000000..6853c6e4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/purge.rb @@ -0,0 +1,43 @@ +module Enumerable + + # A versitle compaction method. Like #map but used + # to filter out multiple items in a single step. + # + # Without +trash+ arguments +nil+ is assumed. + # + # [1, nil, 2].purge #=> [1,2] + # + # If +trash+ arguments are given, each argument is + # compared for a match using #==. + # + # (1..6).purge(3,4) #=> [1,2,5,6] + # + # If a block is given, the yield is used in the + # matching condition instead of the element itsef. + # + # (1..6).purge(0){ |n| n % 2 } #=> [1,3,5] + # + # NOTE: This could just as well be an override of the + # core #compact method, but to avoid potential issues + # associated with overriding core methods we use the + # alternate name #purge. + # + # CREDIT: Trans + + def purge(*trash, &block) + trash = [nil] if trash.empty? + r = [] + if block_given? + each do |e| + y = yield(e) + r << e unless trash.any?{|t| t == y} + end + else + each do |e| + r << e unless trash.any?{|t| t == e} + end + end + r + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/recursively.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/recursively.rb new file mode 100644 index 00000000..5402c462 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/recursively.rb @@ -0,0 +1,66 @@ +module Enumerable + + # Returns a recursive functor, that allows enumerable methods to iterate + # through enumerable sub-elements. By default it only recurses over + # elements of the same type. + # + def recursively(*types, &block) + Recursor.new(self, *types, &block) + end + + # Recursor is a specialized Functor for recurively iterating over Enumerables. + # + # TODO: Return Enumerator if no +yld+ block is given. + # + # TODO: Add limiting +depth+ option to Enumerable#recursively? + # + class Recursor + instance_methods(true).each{ |m| private m unless /^(__|object_id$)/ =~ m.to_s } + + def initialize(enum, *types, &block) + @enum = enum + @types = types.empty? ? [@enum.class] : types + @block = block + end + + def method_missing(op, &yld) + rec = @block || lambda{ |v| v } + yld = yld || lambda{ |v| v } # ? to_enum + @enum.__send__(op) do |v| + case v + when String # b/c of 1.8 + yld.call(v) + when *@types + res = v.recursively(*@types, &@block).__send__(op,&yld) + rec.call(res) + else + yld.call(v) + end + end + end + end + + ## TODO: When no longer needing to support 1.8.6 we could get rid of + ## the Recursor class and use: + ## # + ## def recursively(*types, &block) + ## types = types.empty? ? [self.class] : types + ## Functor.new do |op, &yld| + ## rec = block || lambda{ |v| v } + ## yld = yld || lambda{ |v| v } # ? to_enum + ## __send__(op) do |v| + ## case v + ## when String # b/c of 1.8 + ## yld.call(v) + ## when *types + ## res = v.recursively(*types, &block).__send__(op,&yld) + ## rec.call(res) + ## else + ## yld.call(v) + ## end + ## end + ## end + ## end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/squeeze.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/squeeze.rb new file mode 100644 index 00000000..488b05dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/squeeze.rb @@ -0,0 +1,36 @@ +module Enumerable + + # Squeeze out the same elements. This behaves like C++ unique(), + # removing equivalent elements that are concomitant to each other. + # To get a similar result with Array#uniq, the array would have to + # be sorted first. + # + # Calculation order is O(n). + # + # Examples + # + # [1,2,2,3,3,2,1].squeeze #=> [1,2,3,2,1] + # [1,2,2,3,3,2,1].sort.squeeze #=> [1,2,3] + # [1,2,2,3,3,2,1].squeeze(*[3]) #=> [1,2,2,3,2,1] + # + # Returns [Array]. + # + # CREDIT: T. Yamada + + def squeeze(*limited_to) + first = true + r = [] # result + c = nil # current + each do |e| + if !limited_to.empty? && !limited_to.include?(e) + r << e + elsif first || c != e + r << e + first = false + c = e + end + end + r + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/sum.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/sum.rb new file mode 100644 index 00000000..246e5d2c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/sum.rb @@ -0,0 +1,40 @@ +module Enumerable + + # Uses #+ to sum the enumerated elements. + # + # [1,2,3].sum #=> 6 + # [3,3,3].sum #=> 9 + # + # Note that Facets' sum method is completely generic -- it can work + # on any objects that respond to #+. + # + # [[1],[2],[3]].sum #=> [1,2,3] + # + # For this reason it is usually a good idea to provide a default + # value. Consider the difference between the two expressions below. + # + # [].sum #=> nil + # [].sum(0) #=> 0 + # + # This default value also acts as an initial value. + # + # [].sum(5) #=> 5 + # [1,2,3].sum(10) #=> 16 + # + # A block can also be passed to coax the elements before summation. + # + # [1.1,2.2,3.3].sum(10.4, &:to_i) #=> 16.4 + # + # Notice the initial value is not effected by the block. + # + # @author Dawid Marcin Grzesiak + + def sum(*identity, &block) + if block_given? + map(&block).sum(*identity) + else + reduce(*identity) { |sum, element| sum + element } + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/unassociate.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/unassociate.rb new file mode 100644 index 00000000..8d29a7b4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/unassociate.rb @@ -0,0 +1,23 @@ +module Enumerable + + # Take an associative array and unassociate it. + # + # [[:a,1], [:b,2]].unassociate.to_a #=> [:a, [1], :b, [2]] + # [[:a,1], [:b,2]].unassociate(1).to_a #=> [:a, 1, :b, 2] + # + def unassociate(index = 1..-1) + return to_enum(:unassociate, index) unless block_given? + + each do |v| + case v + when Array + yield v[0] + yield v[index] + else + yield v + yield nil + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/uniq_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/uniq_by.rb new file mode 100644 index 00000000..afa62c8c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/uniq_by.rb @@ -0,0 +1,13 @@ +module Enumerable + + # Like #uniq, but determines uniqueness based on a given block. + # + # (-5..5).to_a.uniq_by {|i| i*i } + # #=> [-5, -4, -3, -2, -1, 0] + # + def uniq_by #:yield: + h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x} + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/value_by.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/value_by.rb new file mode 100644 index 00000000..bff45dfd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/value_by.rb @@ -0,0 +1,25 @@ +module Enumerable + # Create a hash whose keys are the enumerable's elements, with specified + # values. + # + # If no block is given, the given parameter (default true) is used for + # all values, e.g.: + # + # [1,2,3].value_by{ true } #=> {1=>true, 2=>true, 3=>true} + # [1,2,3].value_by{ "a" } #=> {1=>"a", 2=>"a", 3=>"a"} + # + # If a block is given, each key's value is the result of running the + # block for that key, e.g.: + # + # [1,2,3].value_by{ |n| "a"*n } #=> {1=>"a", 2=>"aa", 3=>"aaa"} + # + # @author Ronen Barzel + # + def value_by + return to_enum(:value_by) unless block_given? + + h = {} + each { |item| h[item] = yield(item) } + h + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/visit.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/visit.rb new file mode 100644 index 00000000..efbd4e43 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/visit.rb @@ -0,0 +1,30 @@ +module Enumerable + + # Recursively iterate over all Enumerable elements, or + # subset given :type=>[type1, type2, ...]. + # + # [1, 2, 8..9].visit{ |x| x.succ } + # # => [2, 3, [9, 10]] + # + def visit(opts={}, &block) + type = opts[:type] ? [opts[:type]].flatten : [Enumerable] + skip = opts[:skip] + + map do |v| + case v + when String # b/c of 1.8 + block.call(v) + when *type + v.visit(opts, &block) + else + if skip && Enumerable === v + v + else + block.call(v) + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerable/zip_map.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/zip_map.rb new file mode 100644 index 00000000..3a607828 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerable/zip_map.rb @@ -0,0 +1 @@ +require 'facets/enumerable/map_with' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerator.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerator.rb new file mode 100644 index 00000000..65238c0c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerator.rb @@ -0,0 +1,75 @@ +if RUBY_VERSION < '1.9' + + require 'enumerator' + + # for Ruby 1.8 -> 1.9 transition + Enumerator = Enumerable::Enumerator unless defined?(::Enumerator) + + class Enumerator + + private + + alias :old_initialize :initialize + + # Provides the ruby-1.9 block form of Enumerator, where you can write: + # + # obj = Enumerator.new do |yielder| + # # ... + # yielder.yield(data) # or: yielder << data + # # ... + # end + # + # When obj.each is called, the block is run once. It should call + # yielder.yield with each item it wishes to generate. + # + # Example: + # + # fib = Enumerator.new { |y| + # a = b = 1 + # loop { + # y << a + # a, b = b, a + b + # } + # } + # + # fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] + # + def initialize(*args, &block) + if block + @body = block + old_initialize(self, :_start) + else + old_initialize(*args) + end + end + + def _start(*args,&receiver) #:nodoc: + @body.call(Yielder.new(&receiver), *args) + end + + # Wrapper to allow yielder.yield(output) or yielder << output + # in the same way as ruby-1.9 + # + # TODO: Why can't Yielder take a block instead of a proc argument? + + class Yielder #:nodoc: + def initialize(&proc) + @proc = proc + end + def yield(*args) + @proc[*args] + end + alias :<< :yield + end + + end + +end + +path = __FILE__.chomp('.rb') +base = File.basename(path) +Dir[File.join(path, '*.rb')].each do |lib| + #require lib # why is this so much slower? + require "facets/#{base}/#{File.basename(lib)}" +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerator/fx.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerator/fx.rb new file mode 100644 index 00000000..5feb0443 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerator/fx.rb @@ -0,0 +1,27 @@ +require 'facets/functor' + +class Enumerator + + # TODO: Should Enumerator#fx be moved to functor gem? + + # + def fx + Functor.new do |op, *a, &b| + map{ |e| e.send(op, *a, &b) } + end + end + +# Old 1.8 version (left temporarily for reference) +# +# def fx +# Functor.new(&method(:fx_send).to_proc) +# end +# +# private +# +# def fx_send(op, *a, &b) +# map{ |e| e.send(op, *a, &b) } +# end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/enumerator/lazy/squeeze.rb b/bin/gems/facets-3.1.0/lib/core/facets/enumerator/lazy/squeeze.rb new file mode 100644 index 00000000..2691cfcd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/enumerator/lazy/squeeze.rb @@ -0,0 +1,33 @@ +if defined?(Enumerator::Lazy) + class Enumerator + class Lazy + + # Enumerator::Lazy version of Enumerable#squeeze. + # Note: you must use Ruby 2.0+ or require 'backports'. + # For now, you have to require 'facets/enumerator/lazy/squeeze' explicitly. + # + # Examples + # + # [1,2,2,3,3,2,1].lazy.squeeze.to_a #=> [1,2,3,2,1] + # [1,2,2,3,3,2,1].lazy.squeeze(*[3]).to_a #=> [1,2,2,3,2,1] + # + # Returns Enumerator::Lazy. + # + # CREDIT: T. Yamada + + def squeeze(*limited_to) + first = true + cur = nil + self.class.new(self) do |y,v| + if !limited_to.empty? && !limited_to.include?(v) + y << v + elsif first || cur != v + y << v + first = false + cur = v + end + end + end + end + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/essentials.rb b/bin/gems/facets-3.1.0/lib/core/facets/essentials.rb new file mode 100644 index 00000000..b2fdb649 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/essentials.rb @@ -0,0 +1,65 @@ +# As suggested by Roger Pack this file is a simple convenience +# for loading a limited set of *essential* core extensions. By +# *essential* we mean, more or less, the extensions we think +# ought to be in Ruby proper anyway. +# +# NOTE: This is very much a work in progress! Please feel frre to +# suggest which extensions you think belong here. + +require_relative 'functor' + +### Kernel +require_relative 'kernel/blank' +#require_relative 'kernel/deep_copy' +#require_relative 'kernel/deep_dup' +require_relative 'kernel/false' +require_relative 'kernel/true' + +### Object +require_relative 'object/itself' + +### Array +require_relative 'array/delete_values' +require_relative 'array/reject_values' +require_relative 'array/uniq_by' + +### Binding +require_relative 'binding/self' + +### Dir +require_relative 'dir/ascend' +require_relative 'dir/descend' +require_relative 'dir/lookup' + +### Enumerable +require_relative 'enumerable/cluster' +require_relative 'enumerable/graph' +require_relative 'enumerable/value_by' + +### File +require_relative 'file/write' + +### Hash +require_relative 'hash/autonew' +require_relative 'hash/compact' +#require_relative 'hash/data' +require_relative 'hash/delete_values' +require_relative 'hash/except' +require_relative 'hash/rekey' +require_relative 'hash/revalue' +require_relative 'hash/slice' + +### Proc +#require_relative 'proc/wrap' + +### Regexp +#require_relative 'regexp/to_proc' + +### String +require_relative 'string/indent' +require_relative 'string/index_all' +require_relative 'string/mscan' +require_relative 'string/trim' +require_relative 'string/unindent' +#require_realtive 'string/word_wrap' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception.rb new file mode 100644 index 00000000..6acb102b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception.rb @@ -0,0 +1,4 @@ +require_relative 'exception/detail.rb' +require_relative 'exception/raised.rb' +require_relative 'exception/suppress.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception/detail.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception/detail.rb new file mode 100644 index 00000000..c24e6f34 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception/detail.rb @@ -0,0 +1,17 @@ +class Exception + + # Pretty string output of exception/error object useful for helpful + # debug messages. + # + # @author George Moschovitis + + def detail + if backtrace + %{#{self.class.name}: #{message}\n #{backtrace.join("\n ")}\n LOGGED FROM: #{caller[0]}} + else + %{#{self.class.name}: #{message}\n LOGGED FROM: #{caller[0]}} + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception/error_print.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception/error_print.rb new file mode 100644 index 00000000..59197394 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception/error_print.rb @@ -0,0 +1,80 @@ +class Exception + + # Formats the Exception so that it looks *familiar*, + # i.e. exactly like your interpreter does it. + # + # Port of MRI native `error_print` function. + # + # @author Evgeniy Dolzhenko + + def self.error_print(e) + warn_print = "" + backtrace = e.backtrace + backtrace = [ backtrace ] if backtrace.is_a?(String) # 1.9 returns single String for SystemStackError + + warn_print << backtrace[0] + if e.is_a?(RuntimeError) && e.message.empty? + warn_print << ": unhandled exception\n" + else + if e.message.empty? + warn_print << ": #{ e.class.name }\n" + else + split_message = e.message.split("\n") + warn_print << ": " + if split_message.size == 1 + warn_print << "#{ e.message } (#{ e.class.name })\n" + else + warn_print << split_message[0] + warn_print << " (#{ e.class.name })\n" + warn_print << split_message[1..-1].join("\n").chomp << "\n" + end + end + end + + len = backtrace.size + + ## int skip = eclass == rb_eSysStackError; + skip = e.is_a?(SystemStackError) + + ## #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) + ## #define TRACE_HEAD 8 + ## #define TRACE_TAIL 5 + trace_head = 8 + trace_tail = 5 + trace_max = (trace_head + trace_tail + 5) + ## + ## for (i = 1; i < len; i++) { + i = 1 + while i < len + ## if (TYPE(ptr[i]) == T_STRING) { + ## warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i])); + ## } + warn_print << "\tfrom %s\n" % e.backtrace[i] + + ## if (skip && i == TRACE_HEAD && len > TRACE_MAX) { + if skip && i == trace_head && len > trace_max + ## warn_printf("\t ... %ld levels...\n", + ## len - TRACE_HEAD - TRACE_TAIL); + warn_print << "\t ... %d levels...\n" % (len - trace_head - trace_tail) + ## i = len - TRACE_TAIL; + i = len - trace_tail + ## } + end + ## } + i += 1 + end + warn_print + end + + # Formats the Exception so that it looks *familiar*, + # i.e. exactly like your interpreter does it. + # + # @author Evgeniy Dolzhenko + # + # @todo Anyone have a better name for this method? + def error_print + Exception.error_print(self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception/raised.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception/raised.rb new file mode 100644 index 00000000..cb2b4f2d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception/raised.rb @@ -0,0 +1,14 @@ +class Exception + + # Does a block raise an a given +exception+. + # + def self.raised? #:yeild: + begin + yield + false + rescue self + true + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception/set_message.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception/set_message.rb new file mode 100644 index 00000000..5d16110d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception/set_message.rb @@ -0,0 +1,10 @@ +class Exception + + # See exception message. + # + def set_message(string) + @mesg = string.to_s + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/exception/suppress.rb b/bin/gems/facets-3.1.0/lib/core/facets/exception/suppress.rb new file mode 100644 index 00000000..e81b4015 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/exception/suppress.rb @@ -0,0 +1,22 @@ +class Exception + + # Supress errors while executing a block, with execptions. + # + # CREDIT: David Heinemeier Hansson, Thomas Sawyer + + def self.suppress(*exception_classes) + exception_classes.each do |e| + unless e < self + raise ArgumentError, "exception #{e} not a subclass of #{self}" + end + end + exception_classes = [self] | exception_classes + begin + yield + rescue Exception => e + raise unless exception_classes.any? { |cls| e.kind_of?(cls) } + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file.rb b/bin/gems/facets-3.1.0/lib/core/facets/file.rb new file mode 100644 index 00000000..7bf51fd3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file.rb @@ -0,0 +1,16 @@ +require_relative 'file/append.rb' +#require_relative 'file/atomic_write.rb' # uncommon +require_relative 'file/common_path.rb' +require_relative 'file/create.rb' +require_relative 'file/ext.rb' +require_relative 'file/null.rb' +require_relative 'file/read_binary.rb' +require_relative 'file/read_list.rb' +require_relative 'file/rewrite.rb' +require_relative 'file/rootname.rb' +require_relative 'file/sanitize.rb' +require_relative 'file/split_all.rb' +require_relative 'file/split_root.rb' +require_relative 'file/write.rb' +require_relative 'file/writelines.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/append.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/append.rb new file mode 100644 index 00000000..9085acca --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/append.rb @@ -0,0 +1,14 @@ +class File + + # Append to a file. + # + # CREDIT: George Moschovitis + + def self.append(file, str) + File.open(file, 'ab') { |f| + f << str + } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_id.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_id.rb new file mode 100644 index 00000000..ae7f720b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_id.rb @@ -0,0 +1,9 @@ +class File + + # + def self.atomic_id + @atomic_id ||= 0 + @atomic_id += 1 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_open.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_open.rb new file mode 100644 index 00000000..804269eb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_open.rb @@ -0,0 +1,26 @@ +require 'tempfile' unless defined?(Tempfile) + +require 'facets/file/atomic_id' + +class File + + # Same as `File.open`, but acts on a temporary copy of named + # file, copying the file back to the original on completion. + # + # @uncommon + # require 'facets/fileutils/atomic_open' + # + def self.atomic_open(file_name, mode="r", temp_dir=nil, &block) + temp_dir = temp_dir || Dir.tmpdir + temp_file = Tempfile.new("#{atomic_id}-" + basename(file_name), temp_dir) + + if File.exist?(file_name) + FileUtils.cp(file_name, temp_file) + end + + open(temp_file, mode, &block) + + FileUtils.cp(temp_file, file_name) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_write.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_write.rb new file mode 100644 index 00000000..99607f36 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/atomic_write.rb @@ -0,0 +1,58 @@ +# This is a precursor to the possibility of a more extensive Atomic File I/O +# system. For now it simply provides a means for atomic file writing. + +require 'thread' unless defined?(Thread) +require 'tempfile' unless defined?(Tempfile) +require 'fileutils' unless defined?(FileUtils) + +class File + + # Write to a file atomically. Useful for situations where you don't + # want other processes or threads to see half-written files. + # + # File.atomic_write("important.txt") do |file| + # file.write("hello") + # end + # + # If your temporary directory is not on the same filesystem as the file you're + # trying to write, you can provide a different temporary directory. + # + # File.atomic_write("important.txt", "tmp") do |file| + # file.write("hello") + # end + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/fileutils/atomic_write' + # + def self.atomic_write(file_name, temp_dir=nil) + temp_dir = temp_dir || Dir.tmpdir + temp_file = Tempfile.new(basename(file_name), temp_dir) + + yield temp_file + temp_file.close + + begin + ## Get original file permissions + old_stat = stat(file_name) + rescue Errno::ENOENT + ## No old permissions, write a temp file to determine the defaults + check_name = join(dirname(file_name), ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}") + open(check_name, "w") { } + old_stat = stat(check_name) + unlink(check_name) + end + + ## Overwrite original file with temp file + FileUtils.mv(temp_file.path, file_name) + + ## Set correct permissions on new file + chown(old_stat.uid, old_stat.gid, file_name) + chmod(old_stat.mode, file_name) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/common_path.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/common_path.rb new file mode 100644 index 00000000..6984f883 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/common_path.rb @@ -0,0 +1,17 @@ +class File + + # Given an array of path strings, find the longest common prefix path. + # + # @author Aaron Gibralter + def self.common_path(*paths) + return paths.first if paths.length <= 1 + + arr = paths.sort + f = arr.first.split('/') + l = arr.last.split('/') + i = 0 + i += 1 while f[i] == l[i] && i <= f.length + f.slice(0, i).join('/') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/create.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/create.rb new file mode 100644 index 00000000..03e5f63e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/create.rb @@ -0,0 +1,21 @@ +class File + + # Creates a new file, or overwrites an existing file, + # and writes a string into it. Can also take a block + # just like File#open, which is yielded _after_ the + # string is writ. + # + # str = 'The content for the file' + # File.create('myfile.txt', str) + # + # CREDIT: George Moschovitis + + def self.create(path, str='', &blk) + open(path, 'wb') do |f| + f << str + blk.call(f) if blk + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/ext.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/ext.rb new file mode 100644 index 00000000..195e7998 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/ext.rb @@ -0,0 +1,36 @@ +class File + + # Takes a file name string and returns or changes its extension. + # + # Without a new extension argument, returns the extension of the + # file name. In this respect #ext is like #extname, but unlike + # #extname it does not include the dot prefix. + # + # With a new extension argument, changes the exension of the file + # name to the new extension and returns it. + # + # Examples + # + # File.ext('file.rb') # => 'rb' + # File.ext('file.rb', 'txt') # => 'file.txt' + # File.ext('file.rb', '.txt') # => 'file.txt' + # File.ext('file.rb', '') # => 'file' + # + # This method can be used with String#file for more object-oriented notation: + # + # 'file.rb'.file.ext('txt') # => 'file.txt' + # + # CREDIT: Lavir the Whiolet + + def self.ext(filename, new_ext=nil) + old_ext = extname(filename) + if new_ext == nil + old_ext.sub(/^\./, '') + else + new_ext = '.' + new_ext unless (new_ext.empty? || new_ext[0,1] == '.') + filename.chomp(old_ext) + new_ext + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/null.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/null.rb new file mode 100644 index 00000000..6f371286 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/null.rb @@ -0,0 +1,21 @@ +class File + + # Platform dependent null device. + # + # CREDIT: Daniel Burger + + def self.null + case RUBY_PLATFORM + when /mswin/i + 'NUL' + when /amiga/i + 'NIL:' + when /openvms/i + 'NL:' + else + '/dev/null' + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/read_binary.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/read_binary.rb new file mode 100644 index 00000000..639d5c6d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/read_binary.rb @@ -0,0 +1,18 @@ +class File + + # Read in a file as binary data. + # + # Assuming we had a binary file 'binary.dat'. + # + # File.read_binary('binary.dat') + # + # CREDIT: George Moschovitis + + def self.read_binary(fname) + open(fname, 'rb') do |f| + return f.read + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/read_list.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/read_list.rb new file mode 100644 index 00000000..ebb20ead --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/read_list.rb @@ -0,0 +1,34 @@ +class File + + # Reads in a file, removes blank lines and removes lines starting + # with '#' and then returns an array of all the remaining lines. + # + # Thr remark indicator can be overridden via the +:omit:+ option, which + # can be a regualar expression or a string that is match against the + # start of a line. + # + # CREDIT: Trans + + def self.read_list(filepath, options={}) + chomp = options[:chomp] + omit = case options[:omit] + when Regexp + omit + when nil + /^\s*\#/ + else + /^\s*#{Regexp.escape(omit)}/ + end + + list = [] + readlines(filepath).each do |line| + line = line.strip.chomp(chomp) + next if line.empty? + next if omit === line + list << line + end + list + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/rewrite.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/rewrite.rb new file mode 100644 index 00000000..8b33c12e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/rewrite.rb @@ -0,0 +1,90 @@ +class File + + # Opens a file as a string and writes back the string to the file at + # the end of the block. + # + # Returns the number of written bytes or +nil+ if the file wasn't + # modified. + # + # Note that the file will even be written back in case the block + # raises an exception. + # + # Mode can either be "b" or "+" and specifies to open the file in + # binary mode (no mapping of the plattform's newlines to "\n" is + # done) or to append to it. + # + # Assuming we had a file 'message.txt' and had a binary file 'binary.dat'. + # + # # Reverse contents of "message.txt" + # File.rewrite("message.txt") { |str| str.reverse } + # + # # Replace "foo" by "bar" in "binary.dat". + # File.rewrite("binary.dat", "b") { |str| str.gsub("foo", "bar") } + # + # IMPORTANT: The old version of this method required in place modification + # of the file string. The new version will write whatever the block + # returns instead!!! + # + # CREDIT: George Moschovitis + # + def self.rewrite(name, mode = "") #:yield: + unless block_given? + raise(ArgumentError, "Need to supply block to File.rewrite") + end + + if mode.is_a?(Numeric) then + flag, mode = mode, "" + mode += "b" if flag & File::Constants::BINARY != 0 + mode += "+" if flag & File::Constants::APPEND != 0 + else + mode.delete!("^b+") + end + + old_str = open(name, "r#{mode}") { |file| file.read } #rescue "" + old_str = old_str.clone + + begin + new_str = yield(old_str) + ensure + if old_str != new_str + open(name, "w#{mode}") { |file| file.write(new_str) } + end + end + end + + # In place version of #rewrite. This version of method requires that the + # string be modified in place within the block. + # + # # Reverse contents of "message" + # File.rewrite("message.txt") { |str| str.reverse! } + # + # # Replace "foo" by "bar" in "binary" + # File.rewrite("binary.dat", "b") { |str| str.gsub!("foo", "bar") } + # + def self.rewrite!(name, mode = "") #:yield: + unless block_given? + raise(ArgumentError, "Need to supply block to File.rewrite") + end + + if mode.is_a?(Numeric) then + flag, mode = mode, "" + mode += "b" if flag & File::Constants::BINARY != 0 + mode += "+" if flag & File::Constants::APPEND != 0 + else + mode.delete!("^b+") + end + + old_str = open(name, "r#{mode}") { |file| file.read } #rescue "" + new_str = old_str.clone + + begin + yield(new_str) + ensure + if old_str != new_str + open(name, "w#{mode}") { |file| file.write(new_str) } + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/rootname.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/rootname.rb new file mode 100644 index 00000000..af639c50 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/rootname.rb @@ -0,0 +1,23 @@ +class File + + # Returns only the first portion of the directory of + # a file path name. + # + # File.rootname('lib/jump.rb') #=> 'lib' + # File.rootname('/jump.rb') #=> '/' + # File.rootname('jump.rb') #=> '.' + # + # CREDIT: Trans + # + def self.rootname(path) + # -- this should be fairly robust + path_re = Regexp.new('[' + Regexp.escape(File::Separator + %q{\/}) + ']') + + head, _ = path.split(path_re, 2) + return '.' if path == head + return '/' if head.empty? + return head + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/sanitize.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/sanitize.rb new file mode 100644 index 00000000..7555497a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/sanitize.rb @@ -0,0 +1,18 @@ +class File + + # Cleans up a filename to ensure it will work on a filesystem. + # + # File.sanitize("yo+baby!") #=> 'yo+baby_' + # File.sanitize(".what&up") #=> '.what_up' + # + # CREDIT: George Moschovitis + + def self.sanitize(filename) + filename = File.basename(filename.gsub("\\", "/")) # work-around for IE + filename.gsub!(/[^a-zA-Z0-9\.\-\+_]/,"_") + filename = "_#{filename}" if filename =~ /^\.+$/ + filename + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/split_all.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/split_all.rb new file mode 100644 index 00000000..13a1b42f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/split_all.rb @@ -0,0 +1,19 @@ +class File + + # Splits a file path into an array of individual path components. + # This differs from File.split, which divides the path into + # only two parts, directory path and basename. + # + # File.split_all("a/b/c") #=> ['a', 'b', 'c'] + # + # CREDIT: Trans + + def self.split_all(path) + head, tail = File.split(path) + return [tail] if head == '.' || tail == '/' + return [head, tail] if head == '/' + return split_all(head) + [tail] + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/split_root.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/split_root.rb new file mode 100644 index 00000000..3f3bef92 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/split_root.rb @@ -0,0 +1,13 @@ +class File + + # Return the head of path from the rest of the path. + # + # File.split_root('etc/xdg/gtk') #=> ['etc', 'xdg/gtk'] + # + def self.split_root(path) + path_re = Regexp.new('[' + Regexp.escape(File::Separator + %q{\/}) + ']') + path.split(path_re, 2) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/write.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/write.rb new file mode 100644 index 00000000..5f61fb7c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/write.rb @@ -0,0 +1,24 @@ +class File + + unless defined?(write) # 1.9+ + + # Writes the given data to the given path and closes the file. This is + # done in binary mode, complementing IO.read in standard Ruby. + # + # str = 'The content for the file' + # File.write('write.txt', str) + # + # Returns the number of bytes written. + # + # CREDIT: Gavin Sinclair + + def self.write(path, data) + File.open(path, "wb") do |file| + return file.write(data) + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/file/writelines.rb b/bin/gems/facets-3.1.0/lib/core/facets/file/writelines.rb new file mode 100644 index 00000000..c30f851f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/file/writelines.rb @@ -0,0 +1,27 @@ +class File + + # Writes the given array of data to the given path and closes the file. + # This is done in binary mode, complementing IO.readlines in + # standard Ruby. + # + # Note that +readlines+ (the standard Ruby method) returns an array of lines + # with newlines intact, whereas +writelines+ uses +puts+, and so + # appends newlines if necessary. In this small way, +readlines+ and + # +writelines+ are not exact opposites. + # + # data = ['The content', ['for the file']] + # File.writelines('writelines.txt', data) + # + # Returns number of lines written. + # + # CREDIT: Noah Gibbs, Gavin Sinclair + + def self.writelines(path, data) + File.open(path, "wb") do |file| + file.puts(data) + end + data.size + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest.rb new file mode 100644 index 00000000..00f6d195 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest.rb @@ -0,0 +1,7 @@ +require_relative 'filetest/absolute.rb' +require_relative 'filetest/contains.rb' +require_relative 'filetest/relative.rb' +require_relative 'filetest/root.rb' +require_relative 'filetest/safe.rb' +require_relative 'filetest/separator_pattern.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/absolute.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/absolute.rb new file mode 100644 index 00000000..e4957aec --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/absolute.rb @@ -0,0 +1 @@ +require 'facets/filetest/relative' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/contains.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/contains.rb new file mode 100644 index 00000000..ab45ab1a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/contains.rb @@ -0,0 +1,12 @@ +module FileTest + + module_function + + # Does the +parent+ contain the +child+? + def contains?(child, parent=Dir.pwd) + parent = File.expand_path(parent) + child = File.expand_path(child) + child.sub(parent,'') != child + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/relative.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/relative.rb new file mode 100644 index 00000000..71c99642 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/relative.rb @@ -0,0 +1,38 @@ +require 'facets/filetest/separator_pattern' + +module FileTest + + module_function + + # Predicate method for testing whether a path is absolute. + # It returns +true+ if the pathname begins with a slash. + def absolute?(path) + !relative?(path) + end + + # The opposite of #absolute? + def relative?(path) + while r = chop_basename(path.to_s) + path, _ = r + end + path == '' + end + + # List File.split, but preserves the file separators. + # + # FileTest.chop_basename('/usr/lib') #=> ['/usr/', 'lib'] + # FileTest.chop_basename('/') #=> nil + # + # Returns Array of `[pre-basename, basename]` or `nil`. + # + # This method is here simply to support the #relative? and #absolute? methods. + def chop_basename(path) + base = File.basename(path) + if /\A#{SEPARATOR_PATTERN}?\z/ =~ base + return nil + else + return path[0, path.rindex(base)], base + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/root.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/root.rb new file mode 100644 index 00000000..540827e0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/root.rb @@ -0,0 +1,17 @@ +module FileTest + + module_function + + # Is the specified directory the root directory? + # + # CREDIT: Jeffrey Schwab + + def root?(dir=nil) + pth = File.expand_path(dir||Dir.pwd) + return true if pth == '/' + return true if pth =~ /^(\w:)?\/$/ + false + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/safe.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/safe.rb new file mode 100644 index 00000000..095128cb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/safe.rb @@ -0,0 +1,24 @@ +require 'facets/filetest/separator_pattern' + +module FileTest + + module_function + + # Is a path considered reasonably "safe"? + # + # Do not mistake this for a perfect solution! + # Please help improve if you know how! + # + # Returns [Boolean] + + def safe?(path) + case path + when /\A(#{SEPARATOR_PATTERN}|\~)(#{SEPARATOR_PATTERN}|\*)+/ + false + else + true + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/filetest/separator_pattern.rb b/bin/gems/facets-3.1.0/lib/core/facets/filetest/separator_pattern.rb new file mode 100644 index 00000000..156eebe0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/filetest/separator_pattern.rb @@ -0,0 +1,19 @@ +module FileTest + + # + SEPARATOR_PATTERN = ( + if File::ALT_SEPARATOR + /[#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}]/ + else + /#{Regexp.quote File::SEPARATOR}/ + end + ).freeze + + #module_function + # + # # + # def separator_pattern + # SEPARATOR_PATTERN + # end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/fixnum.rb b/bin/gems/facets-3.1.0/lib/core/facets/fixnum.rb new file mode 100644 index 00000000..019a42a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/fixnum.rb @@ -0,0 +1,7 @@ +class Fixnum + n_bits = ([42].pack('L!').size * 8) + + MAX = 2 ** (n_bits - 2) - 1 + MIN = -MAX - 1 +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/float.rb b/bin/gems/facets-3.1.0/lib/core/facets/float.rb new file mode 100644 index 00000000..73e7e110 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/float.rb @@ -0,0 +1,2 @@ +require_relative 'float/round_to.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/float/round_to.rb b/bin/gems/facets-3.1.0/lib/core/facets/float/round_to.rb new file mode 100644 index 00000000..d1f62bbc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/float/round_to.rb @@ -0,0 +1 @@ +require 'facets/numeric/round_to' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/functor.rb b/bin/gems/facets-3.1.0/lib/core/facets/functor.rb new file mode 100644 index 00000000..6197b49d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/functor.rb @@ -0,0 +1,92 @@ +# Functor is Ruby's implementation of a Higher-Order-Message. Essentally, +# a Functor can vary its behavior accorrding to the operation applied to it. +# +# Example +# +# f = Functor.new { |op, x| x.send(op, x) } +# (f + 1) #=> 2 +# (f + 2) #=> 4 +# (f + 3) #=> 6 +# (f * 1) #=> 1 +# (f * 2) #=> 4 +# (f * 3) #=> 9 +# +class Functor #< BasicObject + + # Functors can be somewhat inefficient if a new Functor + # is frequently recreated for the same use. So this cache + # can be used to speed things up. + # + # The +key+ will always be an array, wich makes it easier + # to cache Functor for multiple factors. + # + def self.cache(*key, &function) + @cache ||= {} + if function + @cache[key] = new(&function) + else + @cache[key] + end + end + + EXCEPTIONS = [:binding, :inspect, :object_id] + if defined?(::BasicObject) + EXCEPTIONS.concat(::BasicObject.instance_methods) + EXCEPTIONS.uniq! + EXCEPTIONS.map!{ |m| m.to_sym } + end + + # + alias :__class__ :class + + ## If Functor were built-in to Ruby this would not be + ## needed since exceptions could just be added directly. + ##$FUNCTOR_EXCEPTIONS ||= [:binding, :undefine_method] + + ## TODO: This will not work when BasicObject is utilized. How to fix? + ##def self.honor_exceptions + ## $FUNCTOR_EXCEPTIONS.each{ |name| + ## next if method_defined?(name) + ## eval %{ + ## def #{name}(*a,&b) + ## super(*a, &b) + ## end + ## } + ## } + ##end + + # Privatize all methods except vital methods and #binding. + instance_methods(true).each do |m| + next if m.to_s =~ /^__/ + next if EXCEPTIONS.include?(m.to_sym) + undef_method(m) + end + + # + def initialize(&function) + @function = function + end + + # + def to_proc + @function + end + + ##def inspect + ## #"#<#{__class__}:#{object_id} #{method_missing(:inspect)}>" # hex id ? + ## "#{method_missing(:inspect)}" + ##end + + ## Needed? + ##def send(op, *a, &b) + ## method_missing(op, *a, &b) + ##end + + private + + # Any action against the Functor is processesd by the function. + def method_missing(op, *args, &blk) + @function.call(op, *args, &blk) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash.rb new file mode 100644 index 00000000..2b167146 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash.rb @@ -0,0 +1,53 @@ +require_relative 'hash/alias.rb' +require_relative 'hash/argumentize.rb' +require_relative 'hash/at.rb' +require_relative 'hash/autonew.rb' +require_relative 'hash/collate.rb' +require_relative 'hash/count.rb' +require_relative 'hash/dearray_values.rb' +require_relative 'hash/deep_merge.rb' +require_relative 'hash/delete.rb' +require_relative 'hash/delete_at.rb' +require_relative 'hash/delete_unless.rb' +require_relative 'hash/delete_values.rb' +require_relative 'hash/diff.rb' +require_relative 'hash/each_with_key.rb' +require_relative 'hash/except.rb' +require_relative 'hash/fetch_nested.rb' +require_relative 'hash/graph.rb' +require_relative 'hash/insert.rb' +require_relative 'hash/inverse.rb' +require_relative 'hash/join.rb' +require_relative 'hash/keys.rb' +require_relative 'hash/mash.rb' +require_relative 'hash/new_with.rb' +require_relative 'hash/op.rb' +require_relative 'hash/op_add.rb' +require_relative 'hash/op_and.rb' +require_relative 'hash/op_mul.rb' +require_relative 'hash/op_or.rb' +require_relative 'hash/op_push.rb' +require_relative 'hash/op_sub.rb' +require_relative 'hash/recurse.rb' +require_relative 'hash/recursively.rb' +require_relative 'hash/rekey.rb' +require_relative 'hash/replace_each.rb' +require_relative 'hash/reverse_merge.rb' +require_relative 'hash/slice.rb' +require_relative 'hash/stringify_keys.rb' +require_relative 'hash/subset.rb' +require_relative 'hash/swap.rb' +require_relative 'hash/symbolize_keys.rb' +require_relative 'hash/to_mod.rb' +require_relative 'hash/to_options.rb' +require_relative 'hash/to_proc.rb' +require_relative 'hash/to_struct.rb' +require_relative 'hash/traverse.rb' +require_relative 'hash/update.rb' +require_relative 'hash/update_each.rb' +require_relative 'hash/update_keys.rb' +require_relative 'hash/update_values.rb' +#require_relative 'hash/url_params.rb' # uncommon +require_relative 'hash/weave.rb' +require_relative 'hash/zip.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/alias.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/alias.rb new file mode 100644 index 00000000..2c7740ed --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/alias.rb @@ -0,0 +1,31 @@ +class Hash + + # Modifies the receiving Hash so that the value previously referred to by + # _oldkey_ is also referenced by _newkey_; _oldkey_ is retained in the Hash. + # If _oldkey_ does not exist as a key in the Hash, no change is effected. + # + # Returns a reference to the Hash. + # + # foo = { :name=>'Gavin', 'wife'=>:Lisa } + # foo.alias!('name',:name) #=> { :name=>'Gavin', 'name'=>'Gavin', 'wife'=>:Lisa } + # + # foo = { :name=>'Gavin', 'wife'=>:Lisa } + # foo.alias!('spouse','wife') #=> { :name=>'Gavin', 'wife'=>:Lisa, 'spouse'=>:Lisa } + # + # foo = { :name=>'Gavin', 'wife'=>:Lisa } + # foo.alias!('bar','foo') #=> { :name=>'Gavin', 'wife'=>:Lisa } + # + # Note that if the _oldkey_ is reassigned, the reference will no longer exist, + # and the _newkey_ will remain as it was. + # + # CREDIT: Gavin Sinclair + # + # TODO: Rename to #aliaskey or something else. + + def alias!(newkey, oldkey) + self[newkey] = self[oldkey] if self.has_key?(oldkey) + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/argumentize.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/argumentize.rb new file mode 100644 index 00000000..99a96c55 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/argumentize.rb @@ -0,0 +1,28 @@ +class Hash + + # Turn a hash into a method arguments. + # + # h = { :list => [1,2], :base => "HI" } + # + # Without an argument field. + # + # h.argumentize #=> [ { :list => [1,2], :base => "HI" } ] + # + # With an argument field. + # + # h.argumentize(:list) #=> [ 1, 2, { :base => "HI" } ] + # h.argumentize(:base) #=> [ "HI", { :list => [1,2] } ] + # + def argumentize(args_field=nil) + config = dup + if args_field + args = [config.delete(args_field)].flatten.compact + else + args = [] + end + args << config + return args + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/at.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/at.rb new file mode 100644 index 00000000..d72f7f1b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/at.rb @@ -0,0 +1,8 @@ +class Hash + + # Alias for fetch for greater polymorphism with Array. + # + alias_method :at, :[] + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/autonew.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/autonew.rb new file mode 100644 index 00000000..7a670ce4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/autonew.rb @@ -0,0 +1,24 @@ +class Hash + + # Hash which auto initializes it's children. + # + # h = Hash.autonew + # h['s1']['p1'] = 4 + # h['s1']['p2'] = 5 + # h['s1']['p3'] = 2 + # h['s1']['p4'] = 3 + # + # h #=> {"s1"=>{"p1"=>4, "p4"=>3, "p3"=>2, "p2"=>5}} + # + # h['s1'].keys.sort + # #=> ["p1", "p2", "p3", "p4"] + # + # CREDIT: Trans, Jan Molic + + def self.autonew(*args) + leet = lambda{ |hsh, key| hsh[key] = new( &leet ) } + new(*args,&leet) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/collate.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/collate.rb new file mode 100644 index 00000000..f539eeb1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/collate.rb @@ -0,0 +1,49 @@ +class Hash + + # Merge the values of this hash with those from another, setting all values + # to be arrays representing the values from both hashes. + # + # { :a=>1, :b=>2 }.collate(:a=>3, :b=>4, :c=>5) + # #=> { :a=>[1,3], :b=>[2,4], :c=>[5] } + # + # As of v3.0, this method no longer automatically flattens + # the array values. To acheive the same effect add a flat map. + # + # h = { :a=>[1,3], :b=>[2,4], :c=>[5] }.collate(:a=>6, :b=>7, :c=>8) + # h.each_value{ |v| v.flatten! } + # #=> { :a=>[1,3,6], :b=>[2,4,7], :c=>[5,8] } + # + # @author Trans (rewrite) + # @author Tilo Sloboda (bug fixes) + # @author Gavin Kistner (original) + + def collate(*others) + h = {} + keys.each do |k| + h[k] = [] + end + others.each do |other| + other.keys.each do |k| + h[k] = [] + end + end + each do |k, v| + h[k] << v + end + others.each do |other| + other.each do |k, v| + h[k] << v + end + end + h.each{ |k,v| v.flatten! } + h + end + + # The same as #collate, but modifies the receiver in place. + def collate!(other_hash) + result = collate(other_hash) + replace(result) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/count.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/count.rb new file mode 100644 index 00000000..00904c33 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/count.rb @@ -0,0 +1,16 @@ +class Hash + + # Like Enumerable#count, but can count hash values. + # + # {:A=>1, :B=>1}.count(1) #=> 2 + # + def count(*value) + if value.empty? + super() + else + values.count(*value) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/data.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/data.rb new file mode 100644 index 00000000..b8267b45 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/data.rb @@ -0,0 +1,44 @@ +require 'facets/functor' + +class Hash + + # Access to a hash as if it were an OpenStruct. + # + # h = {:a=>1, :b=>2} + # + # h.data.a #=> 1 + # h.data.b #=> 2 + # h.data.c #=> nil + # + # h.data.c = 3 + # h.data.c #=> 3 + # + # h.data.a? #=> true + # h.data.d? #=> false + # + # TODO: Is there a better name for `data` --perhaps `open`? + # + # TODO: Is this method really worth having? + # + # Returns [Functor]. + + def data + this = self + Functor.new do |op, *a| + case op.to_s + when /\=$/ + op = op.to_s.chomp('=') + this[op] = a.first + when /\?$/ + op = op.to_s.chomp('?') + this.key?(op.to_s) || this.key?(op.to_sym) + when /\!$/ + op = op.to_s.chomp('!') + this[op] # ??? + else + this[op.to_s] || this[op.to_sym] + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/dearray_values.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/dearray_values.rb new file mode 100644 index 00000000..2de36576 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/dearray_values.rb @@ -0,0 +1,46 @@ +class Hash + + # Any array values will be replaced with the first element of the array. + # Arrays with no elements will be set to nil. + # + # h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] } + # h.dearray_values #=> { :a=>1, :b=>1, :c=>3, :d=>nil } + # + # CREDIT: Trans + + def dearray_values(index=0) + h = {} + each do |k,v| + case v + when Array + h[k] = v[index] || v[-1] + else + h[k] = v + end + end + h + end + + # Any array values with one or no elements will be set to the element + # or nil. + # + # h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] } + # h.dearray_singular_values #=> { :a=>1, :b=>[1,2], :c=>3, :d=>nil } + # + # CREDIT: Trans + + def dearray_singular_values + h = {} + each do |k,v| + case v + when Array + h[k] = (v.size < 2) ? v[0] : v + else + h[k] = v + end + end + h + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_merge.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_merge.rb new file mode 100644 index 00000000..06dd657e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_merge.rb @@ -0,0 +1,33 @@ +class Hash + + # Same as Hash#merge but recursively merges sub-hashes. + + def deep_merge(other) + hash = self.dup + other.each do |key, value| + myval = self[key] + if value.is_a?(Hash) && myval.is_a?(Hash) + hash[key] = myval.deep_merge(value) + else + hash[key] = value + end + end + hash + end + + # Same as Hash#merge! but recursively merges sub-hashes. + + def deep_merge!(other) + other.each do |key, value| + myval = self[key] + if value.is_a?(Hash) && myval.is_a?(Hash) + myval.deep_merge!(value) + else + self[key] = value + end + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_rekey.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_rekey.rb new file mode 100644 index 00000000..65e67a17 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/deep_rekey.rb @@ -0,0 +1,54 @@ +require 'facets/hash/recurse' +require 'facets/hash/rekey' + +class Hash + + # Rekey a hash and all sub-hashes: + # + # deep_rekey() + # deep_rekey(from_key => to_key, ...) + # deep_rekey{|from_key| to_key} + # deep_rekey{|from_key, value| to_key} + # + # If a key map is given, then the first key is changed to the second key. + # + # foo = { :c=>{ :a=>1, :b=>2 } } + # foo.deep_rekey(:a=>'a') #=> { :c=>{ 'a'=>1, :b=>2 } } + # foo.deep_rekey(:b=>:x) #=> { :c=>{ :a =>1, :x=>2 } } + # foo.deep_rekey('foo'=>'bar') #=> { :c=>{ :a =>1, :b=>2 } } + # + # If a block is given, converts all keys in the Hash accroding to the + # given block procedure. + # + # foo = { :person=>{ :name=>'Gavin', :wife=>:Lisa } } + # foo.deep_rekey{ |k| k.to_s } #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } } + # foo #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } } + # + # If no key map or block is given, then all keys are converted + # to Symbols. + # + # Raises an ArgumentError if both a +key_map+ and a block are given. + # If both are needed just call #deep_rekey twice. + # + # TODO: If `nil` is returned by block should the key be set to `nil` or the orignal key? + # + # CREDIT: Trans, Gavin Kistner, Ryan Duryea + + def deep_rekey(key_map=nil, &block) + recurse do |h| + h.rekey(key_map, &block) + end + end + + # Synonym for Hash#deep_rekey, but modifies the receiver in place (and returns it). + # + # foo = { :person=>{ :name=>'Gavin', :wife=>:Lisa } } + # foo.deep_rekey!{ |k| k.to_s } #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } } + # foo #=> { "person"=>{ "name"=>"Gavin", "wife"=>:Lisa } } + # + # CREDIT: Trans, Gavin Kistner, Ryan Duryea + + def deep_rekey!(key_map=nil, &block) + replace(deep_rekey(key_map, &block)) + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/delete.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete.rb new file mode 100644 index 00000000..7bdbbb8e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete.rb @@ -0,0 +1,4 @@ +# TODO: should we deprecate hash/delete? +require 'facets/hash/delete_at' +require 'facets/hash/delete_values' +require 'facets/hash/delete_unless' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_at.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_at.rb new file mode 100644 index 00000000..981a62ae --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_at.rb @@ -0,0 +1,7 @@ +class Hash + + # Polymorphic with Array#delete_at. + alias_method :delete_at, :delete + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_unless.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_unless.rb new file mode 100644 index 00000000..98ab2b52 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_unless.rb @@ -0,0 +1,17 @@ +class Hash + + # Inverse of #delete_if. + # + # h = { :a => 1, :b => 2, :c => 3 } + # r = h.delete_unless{|k,v| v == 1} + # r #=> { :a => 1 } + # h #=> { :a => 1 } + # + # CREDIT: Daniel Schierbeck + + def delete_unless #:yield: + delete_if{ |key, value| ! yield(key, value) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_values.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_values.rb new file mode 100644 index 00000000..6a76f073 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/delete_values.rb @@ -0,0 +1,41 @@ +class Hash + + # Minor modification to Ruby's Hash#delete method + # allowing it to take multiple keys. + # + # hsh = { :a => 1, :b => 2 } + # hsh.delete_values(1) + # hsh #=> { :b => 2 } + # + # Returns a list of keys of the deleted entries. + # + # CREDIT: Daniel Schierbeck + + def delete_values(*values) + deleted_keys = [] + keys.each do |key| + if values.include?(fetch(key)) + deleted_keys << key + delete(key) + end + end + deleted_keys + end + + # Minor modification to Ruby's Hash#delete method + # allowing it to take multiple keys. + # + # hsh = {:a=>1, :b=>2, :c=>3} + # + # a, b, c = hsh.delete_values_at(:a, :b, :c) + # + # [a, b, c] #=> [1, 2, 3] + # hsh #=> {} + # + # CREDIT: Daniel Schierbeck + + def delete_values_at(*keys, &yld) + keys.map{|key| delete(key, &yld) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/diff.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/diff.rb new file mode 100644 index 00000000..1676de38 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/diff.rb @@ -0,0 +1,17 @@ +class Hash + + # Difference comparison of two hashes. + # + # h1 = {:a=>1,:b=>2} + # h2 = {:a=>1,:b=>3} + # + # h1.diff(h2) #=> {:b=>2} + # h2.diff(h1) #=> {:b=>3} + # + def diff(hash) + h1 = self.dup.delete_if{ |k,v| hash[k] == v } + h2 = hash.dup.delete_if{ |k,v| has_key?(k) } + h1.merge(h2) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/each_with_key.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/each_with_key.rb new file mode 100644 index 00000000..3c115714 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/each_with_key.rb @@ -0,0 +1,12 @@ +class Hash + + # Each with key is like each_pair but reverses the order + # the parameters to [value,key] instead of [key,value]. + # + # CREDIT: Trans + + def each_with_key( &yld ) + each_pair{ |k,v| yld.call(v,k) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/except.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/except.rb new file mode 100644 index 00000000..f511d2a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/except.rb @@ -0,0 +1,37 @@ +class Hash + + # Returns a new hash less the given keys. + def except(*less_keys) + hash = dup + less_keys.each{ |k| hash.delete(k) } + hash + end + + # Replaces hash with new hash less the given keys. + # + # h = {:a=>1, :b=>2, :c=>3} + # h.except!(:a) #=> {:b=>2,:c=>3} + # h #=> {:b=>2,:c=>3} + # + # Returns the hash. + def except!(*rejected) + rejected.each{ |k| delete(k) } + self + end + + # Replaces hash with new hash less the given keys. + # This returns the hash of keys removed. + # + # h = {:a=>1, :b=>2, :c=>3} + # h.except!(:a) #=> {:a=>1} + # h #=> {:b=>2,:c=>3} + # + # Returns a Hash of the removed pairs. + def remove!(*rejected) + removed = {} + rejected.each{ |k| removed[k] = delete(k) } + removed + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/fetch_nested.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/fetch_nested.rb new file mode 100644 index 00000000..87d67daf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/fetch_nested.rb @@ -0,0 +1,20 @@ +class Hash + + # Similar to Hash#fetch but supports nested lookup and is `nil` safe. + # + # {}.fetch_nested('anything','at','all') #=> nil + # + # h = {'hello'=>{'world'=>42}} + # h.fetch_nested(*['hello','world']) #=> 42 + # + # CREDIT: T. Yamada and Sean Mackesey + + def fetch_nested(*keys) + begin + keys.reduce(self){|accum, k| accum.fetch(k)} + rescue (RUBY_VERSION<'1.9' ? IndexError : KeyError) + block_given? ? yield(*keys) : nil + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/graph.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/graph.rb new file mode 100644 index 00000000..c517083d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/graph.rb @@ -0,0 +1,18 @@ +require 'facets/enumerable/mash' + +class Hash + + # In place version of #graph. + # + # NOTE: Hash#graph! is only useful for Hash. + # It is not generally applicable to Enumerable. + + def graph!(&yld) + replace(graph(&yld)) + end + + # Alias for #graph! as an alliteration for "map hash". + alias_method :mash!, :graph! + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/insert.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/insert.rb new file mode 100644 index 00000000..30e57e2e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/insert.rb @@ -0,0 +1,19 @@ +class Hash + + # As with #store but only if the key isn't + # already in the hash. + # + # TODO: Would #store? be a better name? + # + # CREDIT: Trans + + def insert(name, value) + if key?(name) + false + else + store(name,value) + true + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/inverse.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/inverse.rb new file mode 100644 index 00000000..b06e2eb8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/inverse.rb @@ -0,0 +1,30 @@ +class Hash + + # Create a "true" inverse hash by storing mutliple values in Arrays. + # + # h = {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9} + # + # h.invert #=> {2=>"d", 3=>"f", 9=>"g"} + # h.inverse #=> {2=>"d", 3=>["f", "c", "b", "a"], 9=>["g", "e"]} + # h.inverse.inverse #=> {"a"=>3, "b"=>3, "c"=>3, "d"=>2, "e"=>9, "f"=>3, "g"=>9} + # + # Of course the inverse of the inverse should be the same. + # + # (h.inverse.inverse == h) #=> true + # + # CREDIT: Tilo Sloboda + + def inverse + i = Hash.new + self.each_pair{ |k,v| + if (Array === v) + v.each{ |x| i[x] = ( i.has_key?(x) ? [k,i[x]].flatten : k ) } + else + i[v] = ( i.has_key?(v) ? [k,i[v]].flatten : k ) + end + } + return i + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/join.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/join.rb new file mode 100644 index 00000000..3755c016 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/join.rb @@ -0,0 +1,17 @@ +class Hash + + # Like Array#join but specialized to Hash. + # + # NOTE: Without Ruby 1.9 this would be difficult to rely on becuase + # hashes did not have a strict order. + # + # CREDIT: Mauricio Fernandez + + def join(pair_divider='', elem_divider=nil) + elem_divider ||= pair_divider + s = [] + each{ |k,v| s << "#{k}#{pair_divider}#{v}" } + s.join(elem_divider) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/keys.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/keys.rb new file mode 100644 index 00000000..c5179637 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/keys.rb @@ -0,0 +1,36 @@ +class Hash + + # Returns true or false whether the hash + # contains the given keys. + # + # h = { :a => 1, :b => 2 } + # h.has_keys?( :a ) #=> true + # h.has_keys?( :c ) #=> false + # + # CREDIT: Trans + + def keys?(*check_keys) + unknown_keys = check_keys - self.keys + return unknown_keys.empty? + end + + alias_method :has_keys?, :keys? + + # Returns true if the hash contains + # _only_ the given keys, otherwise false. + # + # h = { :a => 1, :b => 2 } + # h.has_only_keys?( :a, :b ) #=> true + # h.has_only_keys?( :a ) #=> false + # + # CREDIT: Trans + + def only_keys?(*check_keys) + unknown_keys = self.keys - check_keys + return unknown_keys.empty? + end + + alias_method :has_only_keys?, :only_keys? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/mash.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/mash.rb new file mode 100644 index 00000000..025ffc87 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/mash.rb @@ -0,0 +1 @@ +require 'facets/hash/graph' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/new_with.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/new_with.rb new file mode 100644 index 00000000..0ee0cdea --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/new_with.rb @@ -0,0 +1,15 @@ +class Hash + + # Instantiate a new hash with a default + # value determined by the block. + # + # Hash.new_with{ [] } + # + # CREDIT: Pit Capitan + + def self.new_with #:yield: + new { |h, k| h[k] = yield } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/only_keys.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/only_keys.rb new file mode 100644 index 00000000..a33ff49a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/only_keys.rb @@ -0,0 +1 @@ +require 'facets/hash/keys' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op.rb new file mode 100644 index 00000000..825e39c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op.rb @@ -0,0 +1,7 @@ +require 'facets/hash/op_and' +require 'facets/hash/op_or' +require 'facets/hash/op_add' +require 'facets/hash/op_sub' +require 'facets/hash/op_mul' +require 'facets/hash/op_push' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_add.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_add.rb new file mode 100644 index 00000000..d8a6da9b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_add.rb @@ -0,0 +1,12 @@ +class Hash + + # Operator for #merge. + # + # CREDIT: Trans + + def +(other) + merge(other) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_and.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_and.rb new file mode 100644 index 00000000..e943c87c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_and.rb @@ -0,0 +1,33 @@ +class Hash + + # Hash intersection. Two hashes intersect + # when their pairs are equal. + # + # ({:a=>1,:b=>2} & {:a=>1,:c=>3}) #=> {:a=>1} + # + # A hash can also be intersected with an array + # to intersect keys only. + # + # ({:a=>1,:b=>2} & [:a,:c]) #=> {:a=>1} + # + # The later form is similar to #pairs_at. The differ only + # in that #pairs_at will return a nil value for a key + # not in the hash, but #& will not. + # + # CREDIT: Trans + + def &(other) + case other + when Array + k = (keys & other) + Hash[*(k.zip(values_at(*k)).flatten)] + else + x = (to_a & other.to_a).inject([]) do |a, kv| + a.concat kv; a + end + Hash[*x] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_mul.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_mul.rb new file mode 100644 index 00000000..76671641 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_mul.rb @@ -0,0 +1,18 @@ +class Hash + + # Like merge operator '+' but merges in reverse order. + # + # h1 = {:a=>1} + # h2 = {:a=>2, :b=>3} + # + # (h1 + h2) #=> { :a=>2, :b=>3 } + # (h1 * h2) #=> { :a=>1, :b=>3 } + # + # CREDIT: Trans + + def *(other) + other.merge(self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_or.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_or.rb new file mode 100644 index 00000000..b926a708 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_or.rb @@ -0,0 +1,12 @@ +class Hash + + # Operator for #reverse_merge. + # + # CREDIT: Trans + + def |(other) + other.merge(self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_push.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_push.rb new file mode 100644 index 00000000..0d533877 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_push.rb @@ -0,0 +1,25 @@ +class Hash + + # Can be used like update, or passed + # as two-element [key,value] array. + # + # CREDIT: Trans + + def <<(other) + if other.respond_to?(:to_ary) + store(*other) + else + update(other) + end + self + end + + #def <<(pairs) + # if Array === pairs + # merge! Hash[*pairs] + # else + # merge! pairs + # end + #end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/op_sub.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_sub.rb new file mode 100644 index 00000000..05077d2e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/op_sub.rb @@ -0,0 +1,27 @@ +class Hash + + # Operator for removing hash pairs. If another hash is given + # the pairs are only removed if both key and value are equal. + # If an array is given then matching keys are removed. + # + # CREDIT: Trans + # CREDIT: Xavier Shay (bug fix) + + def -(other) + h = self.dup + if other.respond_to?(:to_ary) + other.to_ary.each do |k| + h.delete(k) + end + else + other.each do |k,v| + if h.key?(k) + h.delete(k) if v == h[k] + end + end + end + h + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/recurse.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/recurse.rb new file mode 100644 index 00000000..ed143022 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/recurse.rb @@ -0,0 +1,29 @@ +class Hash + + # Apply a block to hash, and recursively apply that block + # to each sub-hash or +types+. + # + # h = {:a=>1, :b=>{:b1=>1, :b2=>2}} + # g = h.recurse{|h| h.inject({}){|h,(k,v)| h[k.to_s] = v; h} } + # g #=> {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}} + # + def recurse(*types, &block) + types = [self.class] if types.empty? + h = inject({}) do |hash, (key, value)| + case value + when *types + hash[key] = value.recurse(*types, &block) + else + hash[key] = value + end + hash + end + yield h + end + + # In place form of #recurse. + def recurse!(&block) + replace(recurse(&block)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/recursively.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/recursively.rb new file mode 100644 index 00000000..9d1c9f48 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/recursively.rb @@ -0,0 +1,61 @@ +require 'facets/functor' +require 'facets/enumerable/recursively' + +class Hash + + # Apply a block to a hash, and recursively apply that block + # to each sub-hash: + # + # h = {:a=>1, :b=>{:x=>1, :y=>2}} + # h.recursively.map{ |k,v| [k.to_s, v] } + # #=> [["a", 1], ["b", [["y", 2], ["x", 1]]]] + # + # The recursive iteration can be treated separately from the non-recursive + # iteration by passing a block to the #recursive method: + # + # h = {:a=>1, :b=>{:x=>1, :y=>2}} + # h.recursively{ |k,v| [k.to_s, v] }.map{ |k,v| [k.to_s, v.to_s] } + # #=> [["a", "1"], ["b", [["y", "2"], ["x", "1"]]]] + # + def recursively(*types, &block) + Recursor.new(self, *types, &block) + end + + class Recursor < Enumerable::Recursor #:nodoc: + def method_missing(op, &yld) + yld = yld || lambda{ |k,v| [k,v] } # ? to_enum + rec = @block || yld #lambda{ |k,v| [k,v] } + @enum.__send__(op) do |k,v| + case v + when String # b/c of 1.8 + yld.call(k,v) + when *@types + res = v.recursively(*@types, &@block).__send__(op,&yld) + rec.call(k, res) + else + yld.call(k,v) + end + end + end + end + +## TODO: When no longer need 1.8.6 support. +=begin + def recursively(*types, &block) + types = types.empty? ? [self.class] : types + Functor.new do |op, &yld| + rec = block || yld + __send__(op) do |k,v| + case v + when *types + rec.call(k, v.recursively(*types, &block).__send__(op,&yld)) + else + yld.call(k,v) + end + end + end + end +=end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/rekey.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/rekey.rb new file mode 100644 index 00000000..bee0a33e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/rekey.rb @@ -0,0 +1,81 @@ +class Hash + + # Rekey a hash: + # + # rekey() + # rekey(from_key => to_key, ...) + # rekey{|from_key| to_key} + # rekey{|from_key, value| to_key} + # + # If a key map is given, then the first key is changed to the second key. + # + # foo = { :a=>1, :b=>2 } + # foo.rekey(:a=>'a') #=> { 'a'=>1, :b=>2 } + # foo.rekey(:b=>:x) #=> { :a =>1, :x=>2 } + # foo.rekey('foo'=>'bar') #=> { :a =>1, :b=>2 } + # + # If a block is given, converts all keys in the Hash accroding to the + # given block procedure. + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.rekey{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo #=> { :name =>"Gavin", :wife=>:Lisa } + # + # If no key map or block is given, then all keys are converted + # to Symbols. + # + # Raises an ArgumentError if both a +key_map+ and a block are given. + # If both are needed just call #rekey twice. + # + # TODO: If `nil` is returned by block should the key be set to `nil` or the orignal key? + # + # CREDIT: Trans, Gavin Kistner + + def rekey(key_map=nil, &block) + raise ArgumentError, "argument or block" if key_map && block + + if !(key_map or block) + block = lambda{|k| k.to_sym} + end + + if block + hash = dup.clear + if block.arity.abs == 1 + each_pair do |k, v| + hash[block[k]] = v #hash[block[k] || k] = v + end + else + each_pair do |k, v| + hash[block[k,v]] = v #hash[block[k,v] || k] = v + end + end + else + #hash = dup.clear # to keep default_proc + #(keys - key_map.keys).each do |key| + # hash[key] = self[key] + #end + #key_map.each do |from, to| + # hash[to] = self[from] if key?(from) + #end + hash = dup # to keep default_proc + key_map.each_pair do |from, to| + hash[to] = hash.delete(from) if hash.key?(from) + end + end + + hash + end + + # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo #=> { "name"=>"Gavin", "wife"=>:Lisa } + # + # CREDIT: Trans, Gavin Kistner + + def rekey!(key_map=nil, &block) + replace(rekey(key_map, &block)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/replace_each.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/replace_each.rb new file mode 100644 index 00000000..daf60ced --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/replace_each.rb @@ -0,0 +1,16 @@ +class Hash + + # Same as #update_each, but deletes the key element first. + # + # CREDIT: Trans + + def replace_each # :yield: + dup.each do |k,v| + delete(k) + update(yield(k,v)) + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/revalue.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/revalue.rb new file mode 100644 index 00000000..71f1a928 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/revalue.rb @@ -0,0 +1,61 @@ +class Hash + + # Generates a new hash where the values are the result of the passed in + # block. The block takes both the key and value of the current entry as + # arguments. + # + # hash = { a: 1, b: 2 } + # hash.revalue { |v| v + 1 } # => { a: 2, b: 3 } + # + # Returns [Hash]. + # + # Credit: Sean Mackesey + + def revalue(val_map=nil, &block) + raise ArgumentError, "argument or block, not both" if val_map && block + + if !(val_map or block) + raise ArgumentError, "must provide Hash arguments or a block" + #block = lambda{|v| v.to_s} + end + + if block + hash = dup.clear # to keep default_proc + if block.arity.abs == 1 + each_pair do |k, v| + hash[k] = block[v] #hash[k] = block[v] || v + end + else + each_pair do |k, v| + hash[k] = block[k,v] #hash[k] = block[k,v] || v + end + end + else + hash = dup.clear # to keep default_proc + each do |k,v| + if val_map.key?(v) + hash[k] = val_map[v] + else + hash[k] = v + end + end + end + + hash + end + + # The in-place version of Hash#revalue. + # + # hash = { a: 1, b: 2 } + # hash.revalue! { |v| v + 1 } + # hash # => { a: 2, b: 3 } + # + # Returns [Hash]. + # + # Credit: Sean Mackesey + + def revalue!(val_map=nil, &block) + replace(revalue(val_map, &block)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/reverse_merge.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/reverse_merge.rb new file mode 100644 index 00000000..7ee81781 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/reverse_merge.rb @@ -0,0 +1,30 @@ +class Hash + + # Allows for reverse merging where its the keys in the + # calling hash that wins over those in the other_hash. + # This is particularly useful for initializing an incoming + # option hash with default values: + # + # def setup(options = {}) + # options.reverse_merge! :size => 25, :velocity => 10 + # end + # + # The default :size and :velocity is only set if the +options+ + # passed in doesn't already have those keys set. + + def reverse_merge(other) + other.merge(self) + end + + # Inplace form of #reverse_merge. + + def reverse_merge!(other) + replace(reverse_merge(other)) + end + + # Obvious alias for reverse_merge! + + alias_method :reverse_update, :reverse_merge! + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/slice.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/slice.rb new file mode 100644 index 00000000..b0c4478e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/slice.rb @@ -0,0 +1,51 @@ +class Hash + + # Returns a new hash with only the given keys. + # + # h = {:a=>1, :b=>2, :c=>3} + # h.slice(:a, :c) #=> {:a=>1, :c=>3} + # h.slice(:a, :d) #=> {:a=>1} + # + def slice(*keep_keys) + if block_given? + each do |k, v| + keep_keys << k if yield(k, v) + end + end + + hash = {} + keep_keys.each do |key| + hash[key] = fetch(key) if key?(key) + end + hash + end + + # Replaces hash with a new hash having only the given keys. + # This return the hash of keys removed. + # + # h = {:a=>1, :b=>2} + # h.slice!(:a) #=> {:b=>2} + # h #=> {:a=>1} + # + # Returns a Hash of the removed pairs. + def slice!(*keep_keys) + if block_given? + each do |k, v| + keep_keys << k if yield(k, v) + end + end + + rejected = keys - keep_keys + removed = {} + rejected.each{ |k| removed[k] = delete(k) } + removed + end + +end + +# NOTE: ActiveSupport defines this method but adds a check for #convert_key. +# If the method is defined, then it converts the keys with it. However +# it doesn't look to be supported by all Hash methods, just +# HashWithIndifferentAccess. I'm not so sure support for this kind of +# thing is appropriate for Facets. + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/stringify_keys.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/stringify_keys.rb new file mode 100644 index 00000000..fa7a2b92 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/stringify_keys.rb @@ -0,0 +1 @@ +require 'facets/hash/symbolize_keys' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/subset.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/subset.rb new file mode 100644 index 00000000..e837c067 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/subset.rb @@ -0,0 +1,27 @@ +class Hash + + # Take a subset of the hash, based on keys given or a block + # that evaluates to true for each hash key. + # + # {'a'=>1, 'b'=>2}.subset('a') #=> {'a'=>1} + # {'a'=>1, 'b'=>2}.subset{|k| k == 'a'} #=> {'a'=>1} + # + # CREDIT: Alexey Petrushin + def subset(*keys, &block) + h = {} + + if block + raise ArgumentError, "subset arguments and block are exclusive parameters" unless keys.empty? + each do |k, v| + h[k] = v if block.call(k) + end + else + each do |k, v| + h[k] = v if keys.include?(k) + end + end + + return h + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/swap.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/swap.rb new file mode 100644 index 00000000..b175b000 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/swap.rb @@ -0,0 +1,17 @@ +class Hash + + # Swap the values of a pair of keys in place. + # + # {:a=>1,:b=>2}.swap!(:a,:b) #=> {:a=>2,:b=>1} + # + # CREDIT: Gavin Sinclair + + def swap!(key1, key2) + tmp = self[key1] + self[key1] = self[key2] + self[key2] = tmp + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/symbolize_keys.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/symbolize_keys.rb new file mode 100644 index 00000000..fb34c8c5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/symbolize_keys.rb @@ -0,0 +1,92 @@ +class Hash + + # NOTE: These are provided because of their prevalence with Rails users. + # We strongly encourage using #rekey instead. + + + # Return a new hash with all keys converted to symbols. With a +select+ block, + # limits conversion to only a certain selection of keys. + # + # foo = { :name=>'Gavin', 'wife'=>:Lisa } + # foo.symbolize_keys #=> { :name=>"Gavin", :wife=>:Lisa } + # foo #=> { :name =>"Gavin", "wife"=>:Lisa } + # + # If the key does not respond to #to_sym, then #to_s will be used first. + # + # For a more versatile method, see #rekey instead. + + def symbolize_keys(&select) + dup.symbolize_keys!(&select) + end + + # Destructively convert all keys to symbols. This is the same as + # Hash#symbolize_keys, but modifies the receiver in place and returns it. + # With a +select+ block, limits conversion to only selected keys. + # + # foo = { 'name'=>'Gavin', 'wife'=>:Lisa } + # foo.symbolize_keys! #=> { :name=>"Gavin", :wife=>:Lisa } + # foo #=> { :name=>"Gavin", :wife=>:Lisa } + # + # If the key does not respond to #to_sym, then #to_s will be used first. + # + # For a more versatile method, see #rekey instead. + + def symbolize_keys!(&select) + if select + keys.each do |key| + if select[key] + new_key = (key.to_sym rescue key.to_s.to_sym) + self[new_key] = delete(key) + end + end + else + keys.each do |key| + new_key = (key.to_sym rescue key.to_s.to_sym) + self[new_key] = delete(key) + end + end + self + end + + # Return a new hash with all keys converted to strings. Converts all keys + # in the Hash to Strings, returning a new Hash. With a +select+ block, + # limits conversion to only a certain selection of keys. + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.stringify_keys #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo #=> { :name =>"Gavin", :wife=>:Lisa } + # + # This method is considered archaic. Use #rekey instead. + + def stringify_keys(&select) + dup.stringify_keys!(&select) + end + + # Destructively convert all keys to strings. This is the same as + # Hash#stringify_keys, but modifies the receiver in place and + # returns it. With a +select+ block, limits conversion to only + # certain keys. + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.stringify_keys! #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo #=> { "name"=>"Gavin", "wife"=>:Lisa } + # + # This method is considered archaic. Use #rekey instead. + + def stringify_keys!(&select) + if select + keys.each do |key| + if select[key] + self[key.to_s] = delete(key) + end + end + else + keys.each do |key| + self[key.to_s] = delete(key) + end + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/to_mod.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_mod.rb new file mode 100644 index 00000000..72452e69 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_mod.rb @@ -0,0 +1,33 @@ +class Hash + + # Convert a hash into a module. + # + # {:a=>1, :b=>2}.to_mod + # + # Can take a block accepting key, value pairs which will be + # evaluated in the context of the module. + # + # h = {:a=>1, :b=>2} + # m = h.to_mod{ |k,v| module_function k } + # m.a #=> 1 + # m.b #=> 2 + # + # CREDIT: Jay Fields + #-- + # TODO: Consider #to_obj? + #++ + + def to_mod(&block) + hash = self + Module.new do + hash.each do |key, value| + define_method key do + value #.to_object + end + instance_exec(key, value, &block) if block + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/to_options.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_options.rb new file mode 100644 index 00000000..fa7a2b92 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_options.rb @@ -0,0 +1 @@ +require 'facets/hash/symbolize_keys' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/to_proc.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_proc.rb new file mode 100644 index 00000000..10e7a44e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_proc.rb @@ -0,0 +1,39 @@ +class Hash + + # Constructs a Proc object from a hash such that the parameter + # of the Proc is assigned the hash keys as attributes. + # + # c = Class.new do + # attr_accessor :a + # end + # + # h = {:a => 1} + # o = c.new + # h.to_proc.call(o) + # o.a #=> 1 + # + # If +response+ is set to +true+, then assignment will only occur + # if receiver responds_to? the writer method. + # + # CREDIT: Trans + + def to_proc(response=false) + if response + lambda do |o| + self.each do |k,v| + ke = "#{k}=" + o.__send__(ke, v) if respond_to?(ke) + end + end + else + lambda do |o| + self.each do |k,v| + ke = "#{k}=" + o.__send__(ke, v) + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/to_struct.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_struct.rb new file mode 100644 index 00000000..daecdd66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/to_struct.rb @@ -0,0 +1,17 @@ +class Hash + + # A method to convert a Hash into a Struct. + # + # h = {:name=>"Dan","age"=>33,"rank"=>"SrA","grade"=>"E4"} + # s = h.to_struct("Foo") + # + # TODO: Is this robust enough considerd hashes aren't ordered? + # + # CREDIT: Daniel Berger + + def to_struct(struct_name) + Struct.new(struct_name,*keys).new(*values) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/traverse.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/traverse.rb new file mode 100644 index 00000000..eb35a737 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/traverse.rb @@ -0,0 +1,47 @@ +class Hash + + # Returns a new hash created by traversing the hash and its subhashes, + # executing the given block on the key and value. The block should + # return a 2-element array of the form +[key, value]+. + # + # h = {"A"=>"A", "B"=>"B", "C"=>{"X"=>"X"}} + # + # g = h.traverse{ |k,v| [k.downcase, v] } + # + # g #=> {"a"=>"A", "b"=>"B", "c"=>{"x"=>"X"}} + # + # NOTE: Hash#traverse is the same as `recursive.graph` and + # might be deprecated in the future (if it ever works!) + # + # CREDIT: Trans + + def traverse(&block) + inject({}) do |h,(k,v)| + if Hash === v + v = v.traverse(&block) + elsif v.respond_to?(:to_hash) + v = v.to_hash.traverse(&block) + end + nk, nv = block.call(k,v) + h[nk] = nv + h + end + end + + # In place version of traverse, which traverses the hash and its + # subhashes, executing the given block on the key and value. + # + # h = { "A"=>"A", "B"=>"B" } + # + # h.traverse!{ |k,v| [k.downcase, v] } + # + # h #=> { "a"=>"A", "b"=>"B" } + # + # CREDIT: Trans + + def traverse!(&block) + replace(traverse(&block)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/update.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/update.rb new file mode 100644 index 00000000..52bc05be --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/update.rb @@ -0,0 +1,6 @@ +# -- for backward compatibility. To be deprecated. +require 'facets/hash/op_push' +require 'facets/hash/update_each' +require 'facets/hash/update_keys' +require 'facets/hash/update_values' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/update_each.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_each.rb new file mode 100644 index 00000000..2c8fe979 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_each.rb @@ -0,0 +1,18 @@ +class Hash + + # Iterates through each pair and updates the hash + # in place. This is formally equivalent to #mash! + # But does not use #mash to accomplish the task. + # Hence #update_each is probably a touch faster. + # + # CREDIT: Trans + + def update_each # :yield: + dup.each do |k,v| + update(yield(k,v)) + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/update_keys.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_keys.rb new file mode 100644 index 00000000..41d4668a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_keys.rb @@ -0,0 +1,21 @@ +class Hash + + # Iterate over hash updating just the keys. + # + # h = {:a=>1, :b=>2} + # h.update_keys{ |k| "#{k}!" } + # h #=> { "a!"=>1, "b!"=>2 } + # + # @author Trans + # @author Evgeniy Dolzhenko (bug fix) + + def update_keys #:yield: + if block_given? + keys.each { |old_key| store(yield(old_key), delete(old_key)) } + else + to_enum(:update_keys) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/update_values.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_values.rb new file mode 100644 index 00000000..84bf1d67 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/update_values.rb @@ -0,0 +1,20 @@ +class Hash + + # Iterate over hash updating just the values. + # + # h = {:a=>1, :b=>2} + # h.update_values{ |v| v + 1 } + # h #=> { :a=>2, :b=>3 } + # + # CREDIT: Trans + + def update_values #:yield: + if block_given? + each{ |k,v| store(k, yield(v)) } + else + to_enum(:update_values) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/weave.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/weave.rb new file mode 100644 index 00000000..9a29e04a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/weave.rb @@ -0,0 +1,76 @@ +class Hash + + # Weave is a very unique hash operator. It is designed + # to merge to complex hashes in according to sensible, + # regular pattern. The effect is akin to inheritance. + # + # Two hashes are weaved together to produce a new hash. + # The two hashes need to be compatible according to the + # following rules for each node: ... + # + # hash, hash => hash (recursive +) + # hash, array => error + # hash, value => error + # array, hash => error + # array, array => array + array + # array, value => array << value + # value, hash => error + # value, array => array.unshift(valueB) + # value1, value2 => value2 + # + # Here is a basic example: + # + # h1 = { :a => 1, :b => [ 1 ], :c => { :x => 1 } } + # h2 = { :a => 2, :b => [ 2 ], :c => { :x => 2 } } + # + # h1.weave(h2) + # #=> {:b=>[1, 2], :c=>{:x=>2}, :a=>2} + # + # Weave follows the most expected pattern of unifying two complex + # hashes. It is especially useful for implementing overridable + # configuration schemes. + # + # CREDIT: Thomas Sawyer + + def weave(h) + raise ArgumentError, "Hash expected" unless h.kind_of?(Hash) + s = self.clone + h.each { |k,node| + node_is_hash = node.kind_of?(Hash) + node_is_array = node.kind_of?(Array) + if s.has_key?(k) + self_node_is_hash = s[k].kind_of?(Hash) + self_node_is_array = s[k].kind_of?(Array) + if self_node_is_hash + if node_is_hash + s[k] = s[k].weave(node) + elsif node_is_array + raise ArgumentError, 'Incompatible hash addition' #self[k] = node + else + raise ArgumentError, 'Incompatible hash addition' #self[k] = node + end + elsif self_node_is_array + if node_is_hash + raise ArgumentError, 'Incompatible hash addition' #self[k] = node + elsif node_is_array + s[k] += node + else + s[k] << node + end + else + if node_is_hash + raise ArgumentError, 'Incompatible hash addition' #self[k] = node + elsif node_is_array + s[k].unshift( node ) + else + s[k] = node + end + end + else + s[k] = node + end + } + s + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/hash/zip.rb b/bin/gems/facets-3.1.0/lib/core/facets/hash/zip.rb new file mode 100644 index 00000000..9abee014 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/hash/zip.rb @@ -0,0 +1,18 @@ +class Hash + + # Creates a new hash from two separate arrays, a +keys+ array and + # a +values+ array. + # + # Hash.zip(["a","b","c"], [1,2,3]) + # # => { "a"=>1, "b"=>2, "c"=>3 } + # + # CREDIT: Trans, Ara T. Howard + + def self.zip(keys,values) # or some better name + h = {} + keys.size.times{ |i| h[ keys[i] ] = values[i] } + h + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/indexable.rb b/bin/gems/facets-3.1.0/lib/core/facets/indexable.rb new file mode 100644 index 00000000..20017368 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/indexable.rb @@ -0,0 +1,268 @@ +# Indexable is a mixin that provides index based methods, +# working solely with four methods: #index, #slice, #splice +# and #size. +# +# These methods work in harmony. Where #index returns a +# position of a given element, #slice returns elements +# for given positions. #splice is like #slice but replaces +# the given position with new values. This method is not +# part of ruby core, but it generally just an alias for #[]=, +# just as #slice is an alias of #[]. #size of course simply +# returns the total length of the indexable object. +# +# NOTE: To test the following methods Indexable needs to be +# included into Array and array must have #splice defined. +# +# require 'facets/array/splice' +# +# class ::Array +# include Indexable +# end +# +# CREDIT: Thomas Sawyer + +module Indexable + + # Like #first but returns the first element + # in a new array. + # + # [1,2,3].head #=> [1] + # + def head + slice(0,1) + end + + # Returns an array from second element to last element. + # + # [1,2,3].tail #=> [2,3] + # + def tail + slice(1,length-1) + end + + # Like #last, returning the last element + # in an array. + # + # [1,2,3].foot #=> [3] + # + def foot + slice(-1,1) + end + + # Returns an array of the first element up to, + # but not including, the last element. + # + # [1,2,3].body #=> [1,2] + # + #-- + # Better name for this? (bulk, perhaps?) + #++ + # + def body + slice(0,size-1) + end + + # Returns the middle element of an array, or the element offset + # from middle if the parameter is given. Even-sized arrays, + # not having an exact middle, return the middle-right element. + # + # [1,2,3,4,5].mid #=> 3 + # [1,2,3,4,5,6].mid #=> 4 + # [1,2,3,4,5,6].mid(-1) #=> 3 + # [1,2,3,4,5,6].mid(-2) #=> 2 + # [1,2,3,4,5,6].mid(1) #=> 5 + # + # In other words, If there are an even number of elements the + # higher-indexed of the two center elements is indexed as + # origin (0). + # + def mid(offset=0) + slice((size / 2) + offset) + end + + # Returns an Array of the middle element(s) of an array. + # Even-sized arrays, not having an exact middle, return + # a two-element array of the two middle elements. + # + # [1,2,3,4,5].middle #=> [3] + # [1,2,3,4,5,6].middle #=> [3,4] + # + # A +birth+ can be give to widen the middle on either side. + # + # [1,2,3,4,5].middle(1) #=> [2,3,4] + # [1,2,3,4,5,6].middle(1) #=> [2,3,4,5] + # + # In contrast to #mid which utilizes an offset. + # + def middle(birth=0) + i = size / 2 - birth + if size % 2 == 0 + slice(i - 1, 2 + (2 * birth)) + else + slice(i, 1 + (2 * birth)) + end + end + + # Fetch values from a start index through an end index. + # + # [1,2,3,4,5].thru(0,2) #=> [1,2,3] + # [1,2,3,4,5].thru(2,4) #=> [3,4,5] + # + # [1,2,3,4,5].thru(2) #=> [1,2,3] + # [1,2,3,4,5].thru(4) #=> [1,2,3,4,5] + # + def thru(from, to=nil) + from, to = 0, from unless to + to = size - 1 if to >= size + a = [] + i = from + while i <= to + a << slice(i) + i += 1 + end + a + end + + # Returns last _n_ elements. + # + # %w{W o r l d}.from(3) #=> %w{l d} + # + def from(i) + return [] if i >= size + slice(i, size - i) #slice(-n..-1) + end + + ## DEPRECATED: use #thru instead + ## Returns first _n_ elements. + ## + ## %w{H e l l o}.upto(3) #=> %w{H e l l} + ## + ##def upto(n) + ## slice(0, n.to_i+1) + ##end + + # Returns first _n_ elements. + # + # %w{H e l l o}.first(3) #=> %w{H e l} + # + def first(n=1) + slice(0, n.to_i) + end + + # Returns last _n_ elements. + # + # %w{H e l l o}.last(3) #=> %w{l l o} + # + def last(n=1) + n = n.to_i + return self if n > size + slice(-n, n) #slice(-n..-1) + end + + # Change the first element. + # + # a = ["a","y","z"] + # a.first = "x" + # a #=> ["x","y","z"] + # + def first=(x) + splice(0,x) + end + + # Change the last element. + # + # a = [1,2,5] + # a.last = 3 + # a #=> [1,2,3] + + def last=(x) + splice(-1,x) + end + + # Remove and return the first element. + # + # a = [1,2,3] + # a.first! #=> 1 + # a #=> [2,3] + # + def first! + splice(0) + end + + # Remove and return the last element. + # + # a = [1,2,3] + # a.last! #=> 3 + # a #=> [1,2] + # + def last! + splice(-1) + end + + # A shorting of "ends at", returns the + # last index of the indexable object. + # Returns nil if there are no elements. + # + # [1,2,3,4,5].ends #=> 4 + # + # This nearly equivalent to +size - 1+. + # + def ends + return nil if size == 0 + size - 1 + end + + # Returns the positive ordinal index given + # a cardinal position, 1 to n or -n to -1. + # + # [1,2,3,4,5].pos(1) #=> 0 + # [1,2,3,4,5].pos(-1) #=> 4 + # + def pos(i) + if i > 0 + return i - 1 + else + size + i + end + end + + # Returns the index of the first element equal to the + # given object or satisfying the block condition. + # + # [1,2,3,4].index{ |e| e == 3 } #=> 2 + # [1,2,3,4].index{ |e| e > 3 } #=> 3 + # + def index(obj=nil, &block) + if block_given? + size.times do |i| + return i if yield(slice(i)) + end + else + size.times do |i| + return i if obj == slice(i) + end + end + nil + end + + # to be deprecated + alias_method :index_of, :index + + # TODO Maybe #range could use a little error catch code (todo). + + # Returns the index range between two elements. If no elements are + # given, returns the range from first to last. + # + # ['a','b','c','d'].range #=> (0..3) + # ['a','b','c','d'].range('b','d') #=> (1..3) + # + def range(a=nil,z=-1) + if a + index(a)..index(z) + else + (0..(size-1)) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer.rb new file mode 100644 index 00000000..460fdba6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer.rb @@ -0,0 +1,8 @@ +require_relative 'integer/bit.rb' +require_relative 'integer/bitmask.rb' +require_relative 'integer/factorial.rb' +require_relative 'integer/multiple.rb' +require_relative 'integer/of.rb' +require_relative 'integer/ordinal.rb' +#require_relative 'integer/roman.rb' # uncommon + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/bit.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/bit.rb new file mode 100644 index 00000000..592901a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/bit.rb @@ -0,0 +1 @@ +require 'facets/integer/bitmask' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/bitmask.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/bitmask.rb new file mode 100644 index 00000000..8a8732bf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/bitmask.rb @@ -0,0 +1,99 @@ +class Integer + + # Set a bit. + # + # 0.bit(4) #=> 16 + # + # Using a negative figure will clear a bit. + # + # 10.bit(-4) #=> 2 + # + # This is more easily seen using binary. + # + # 0b0100.bit(-3) #=> 0 + # + # CREDIT: Thomas Sawyer, George Moschovitis + + def bit(bit) + if bit < 0 + mask = (1 << ~bit) + self & ~mask + else + mask = (1 << bit) + self | mask + end + end + + # Clear bit. + # + # CREDIT: George Moschovitis + + def bit_clear(bit) + mask = (1 << bit) + self & ~mask + end + + # Is a bit set? + # + # 8.bit?(3) #=> true + # 8.bit?(2) #=> false + # + # CREDIT: Thomas Sawyer, George Moschovitis + + def bit?(bit) + mask = (1 << bit) + (self & mask) != 0 + end + + # Apply a bitmask. + # + # 1.bitmask(6) #=> 7 + # + # Using a inverted bitmask clears bits. + # + # 7.bitmask(~2) #=> 5 + # 5.bitmask(~2) #=> 5 + # + # CREDIT: George Moschovitis + + def bitmask(mask) + if mask < 0 + self & mask + else + self | mask + end + end + + # Is bitmask set? + # + # 7.bitmask?(7) #=> true + # 7.bitmask?(5) #=> true + # 8.bitmask?(3) #=> false + # + # CREDIT: George Moschovitis + + def bitmask?(mask) + (self & mask) != 0 + end + +end + + +module Kernel + + # Create a single bit bitmask. + # + # Bit(0) #=> 1 + # Bit(1) #=> 2 + # Bit(2) #=> 4 + # + # This is equivalent to n-shift: "1 << n". + # + # CREDIT: Thomas Sawyer, George Moschovitis + + def Bit(n) + 1 << Integer(n) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/factorial.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/factorial.rb new file mode 100644 index 00000000..f283a8c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/factorial.rb @@ -0,0 +1,21 @@ +class Integer + + # Calculate the factorial of an integer. + # + # 2.factorial #=> 2 + # 3.factorial #=> 6 + # 4.factorial #=> 24 + # + # CREDIT: Malte Milatz + + def factorial + return 1 if zero? + f = 1 + 2.upto(self) { |n| f *= n } + f + end + + alias_method( :fac, :factorial ) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/multiple.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/multiple.rb new file mode 100644 index 00000000..7eb4f237 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/multiple.rb @@ -0,0 +1,19 @@ +class Integer + + # Is +self+ a multiple of a given number? + # + # 7.multiple?(2) #=> false + # 8.multiple?(2) #=> true + # + # CREDIT: Trans + + def multiple?(number) + if number.zero? + zero? ? true : false + else + self % number == 0 + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/of.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/of.rb new file mode 100644 index 00000000..559260fc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/of.rb @@ -0,0 +1,18 @@ +class Integer + + # Like #times but returns a collection of the yield results. + # + # a = 3.of { |i| "#{i+1}" } + # a #=> [ "1", "2", "3" ] + # + + def of(&block) + Array.new(self, &block) + end + + # Time warn aliases for #of. + alias_method :times_collect, :of + alias_method :times_map, :of + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/ordinal.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/ordinal.rb new file mode 100644 index 00000000..1894cd39 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/ordinal.rb @@ -0,0 +1,24 @@ +class Integer + + def ordinal + if [11,12,13].include?(self % 100) + "#{self}th" + else + case (self % 10) + when 1 + "#{self}st" + when 2 + "#{self}nd" + when 3 + "#{self}rd" + else + "#{self}th" + end + end + end + + # Rails term. + alias_method :ordinalize, :ordinal + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/integer/roman.rb b/bin/gems/facets-3.1.0/lib/core/facets/integer/roman.rb new file mode 100644 index 00000000..171cc557 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/integer/roman.rb @@ -0,0 +1 @@ +require 'facets/roman' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel.rb new file mode 100644 index 00000000..55c54466 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel.rb @@ -0,0 +1,76 @@ +require_relative 'kernel/as.rb' +require_relative 'kernel/ask.rb' +require_relative 'kernel/assign.rb' +require_relative 'kernel/assign_from.rb' +require_relative 'kernel/attr_singleton.rb' +require_relative 'kernel/blank.rb' +require_relative 'kernel/callstack.rb' +require_relative 'kernel/call_stack.rb' +require_relative 'kernel/case.rb' +require_relative 'kernel/complete.rb' +require_relative 'kernel/constant.rb' +require_relative 'kernel/d.rb' +require_relative 'kernel/deep_clone.rb' +require_relative 'kernel/deep_copy.rb' +#require_relative 'kernel/demo.rb' # uncommon +require_relative 'kernel/disable_warnings.rb' +require_relative 'kernel/eigen.rb' +#require_relative 'kernel/eigenclass.rb' # uncommon +require_relative 'kernel/enable_warnings.rb' +#require_relative 'kernel/equate.rb' +require_relative 'kernel/ergo.rb' +require_relative 'kernel/extend.rb' +require_relative 'kernel/extension.rb' +require_relative 'kernel/false.rb' +require_relative 'kernel/here.rb' +#require_relative 'kernel/hierarchical_send' # uncommon +require_relative 'kernel/identical.rb' +require_relative 'kernel/in.rb' +require_relative 'kernel/instance_assign.rb' +require_relative 'kernel/instance_class.rb' +#require_relative 'kernel/instance_exec.rb' # uncommon +require_relative 'kernel/instance_extract.rb' +require_relative 'kernel/instance_replace.rb' +require_relative 'kernel/instance_send.rb' +require_relative 'kernel/like.rb' +require_relative 'kernel/load_all.rb' +require_relative 'kernel/load_relative.rb' +require_relative 'kernel/maybe.rb' +#require_relative 'kernel/memo.rb' # uncommon +require_relative 'kernel/meta_alias.rb' +require_relative 'kernel/meta_class.rb' +require_relative 'kernel/meta_def.rb' +require_relative 'kernel/meta_eval.rb' +require_relative 'kernel/method.rb' +require_relative 'kernel/no.rb' +require_relative 'kernel/not.rb' +require_relative 'kernel/not_nil.rb' +require_relative 'kernel/object_class.rb' +require_relative 'kernel/object_hexid.rb' +require_relative 'kernel/object_send.rb' +require_relative 'kernel/p.rb' +require_relative 'kernel/presence.rb' +require_relative 'kernel/present.rb' +require_relative 'kernel/qua_class.rb' +require_relative 'kernel/require_all.rb' +require_relative 'kernel/respond.rb' +require_relative 'kernel/returning.rb' +require_relative 'kernel/silence.rb' +require_relative 'kernel/silence_warnings.rb' +require_relative 'kernel/singleton_class.rb' +require_relative 'kernel/super_method.rb' +require_relative 'kernel/tap.rb' +require_relative 'kernel/temporarily.rb' +#require_relative 'kernel/trap_chain.rb' # uncommon +require_relative 'kernel/true.rb' +require_relative 'kernel/try.rb' +require_relative 'kernel/val.rb' +require_relative 'kernel/with.rb' +require_relative 'kernel/writers.rb' +#require_relative 'kernel/y.rb' # uncommon +require_relative 'kernel/yes.rb' +require_relative 'kernel/__class__.rb' +require_relative 'kernel/__dir__.rb' +require_relative 'kernel/__get__.rb' +require_relative 'kernel/__set__.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/__class__.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__class__.rb new file mode 100644 index 00000000..6c35a2fc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__class__.rb @@ -0,0 +1,9 @@ +module Kernel + + # Defines core method __class__ as an alias of class. + # This allows you to use #class as your own method, without + # loosing the ability to determine the object's class. + + alias_method :__class__, :class + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/__dir__.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__dir__.rb new file mode 100644 index 00000000..937e9e81 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__dir__.rb @@ -0,0 +1,28 @@ +module Kernel + + # Similar to __FILE__, __DIR__ provides the directory + # path to the current executing script. + # + # DEPRECATED: As of Ruby 2.0, which will have #__dir__ method. + # + # CREDIT: Trans + + def __DIR__(*paths) + c = caller.first + return nil unless c.rindex(/:\d+(:in `.*')?$/) + file = $` # File.dirname(c) + return nil if /\A\((.*)\)/ =~ file # eval, etc. + #File.expand_path(File.join(File.dirname(file), paths)) + File.join(File.dirname(file), paths) + end + + #-- + # Old defintion ... + # + # def __DIR__ + # (/^(.+)?:\d+/ =~ caller[0]) ? File.dirname($1) : nil + # end + #++ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/__get__.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__get__.rb new file mode 100644 index 00000000..f63c3b39 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__get__.rb @@ -0,0 +1,15 @@ +module Kernel + + # Shadow method for instance_variable_get. + def __get__(ivar) + #ivar = "@#{ivar}" unless ivar.to_s[0,1] == '@' + instance_variable_get(ivar) + end + + # Shadow method for instance_variable_set. + def __set__(ivar, val) + #ivar = "@#{ivar}" unless ivar.to_s[0,1] == '@' + instance_variable_set(ivar, val) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/__set__.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__set__.rb new file mode 100644 index 00000000..88f27f9b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/__set__.rb @@ -0,0 +1 @@ +require 'facets/kernel/__get__' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/as.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/as.rb new file mode 100644 index 00000000..b77b4b1a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/as.rb @@ -0,0 +1,116 @@ +require 'facets/functor' + +module Kernel + + # Returns a As-functor that allows one to call any + # ancestor's method directly of the given object. + # + # class AsExample1 + # def x ; 1 ; end + # end + # + # class AsExample2 < AsExample1 + # def x ; 2 ; end + # end + # + # class AsExample3 < AsExample2 + # def x ; as(AsExample1).x ; end + # end + # + # AsExample1.new.x #=> 1 + # + def as(ancestor, &blk) + ##this = self + r = As.new(self, ancestor) + ##unless r + ## r = As.cache[self][ancestor] = Functor.new do |op, *a, &b| + ## ancestor.instance_method(op).bind(this).call(*a,&b) + ## end + ##end + r.instance_eval(&blk) if block_given? #yield(r) if block_given? + r + end + + # Call parent class/module methods once bound to self. + # + # TODO: Does this have the proper scope for #send? + def send_as(ancestor, sym, *args, &blk) + ancestor.instance_method(sym).bind(self).call(*args,&blk) + end + + #-- + # Old version ... + # + # def send_as(klass, meth, *args, &blk) + # selfclass = Kernel.instance_method(:class).bind(self).call + # raise ArgumentError if ! selfclass.ancestors.include?(klass) + # klass.instance_method(meth).bind(self).call(*args, &blk) + # end + #++ + + ## DEPRECATED: There's no reliable way to get method name of caller. + ## This needs to have the same knowledge that #super itself has and + ## I do not thin that is possbile in pure Ruby. + ## + ## Like super but skips to a specific ancestor module or class. + ## + ## class SuperAsExample1 + ## def x ; 1 ; end + ## end + ## + ## class SuperAsExample2 < SuperAsExample1 + ## def x ; 2 ; end + ## end + ## + ## class SuperAsExample3 < SuperAsExample2 + ## def x ; super_as(SuperAsExample1) ; end + ## end + ## + ## SuperAsExample3.new.x #=> 1 + ## + ##def super_as(klass=self.class.superclass, *args, &blk) + ## unless self.class.ancestors.include?(klass) + ## raise ArgumentError + ## end + ## #called = /\`([^\']+)\'/.match(caller(1).first)[1].to_sym + ## called = File.basename(caller(1).first) + ## klass.instance_method(called).bind(self).call(*args,&blk) + ##end +end + +# Support class for Kernel#as. +# +# TODO: Deprecate this and use Functor (HigherOrderMessage) instead ? + +class As #:nodoc: + + class << self + alias_method :_new, :new + + def new(subject, ancestor) + cache[subject][ancestor] ||= _new(subject, ancestor) + end + + def cache + @cache ||= Hash.new{|h,k| h[k]={} } + end + + private :_new + private :cache + end + + # Privatize all methods except #binding an operators. + private(*instance_methods.select { |m| m !~ /(^__|^\W|^binding$)/ }) + + def initialize(subject, ancestor) + @subject = subject + @ancestor = ancestor + end + + private + + def method_missing(sym, *args, &blk) + @ancestor.instance_method(sym).bind(@subject).call(*args,&blk) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/ask.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/ask.rb new file mode 100644 index 00000000..4e8756dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/ask.rb @@ -0,0 +1,28 @@ +module Kernel + + module_function + + # Very simple convenience method to get user input + # via the console. A prompt will be sent to $stdout, + # if given, and the input taken from $stdin... + # + # ask "Are you happy? [Yn]" + # + # On the command line one would see... + # + # Are you happy? [Yn] + # + # Responding... + # + # Are you happy? [Yn] Y + # + # The ask method would return "Y". + + def ask(prompt=nil) + $stdout << "#{prompt}" + $stdout.flush + $stdin.gets.chomp! + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign.rb new file mode 100644 index 00000000..31bcd730 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign.rb @@ -0,0 +1,74 @@ +require 'facets/na' + +module Kernel + + # Assign via writer using arguments, hash or associative array. + # + # Using name-value arguments: + # + # object = Object.new + # + # object.assign(:a, 1) + # object.assign(:b, 2) + # + # Using a hash: + # + # object.assign(:a => 1, :b => 2) + # + # Use an associative array: + # + # object.assign([[:a, 1], [:b, 2]]) + # + # These are all equivalent to: + # + # object.a = 1 if object.respond_to?(:a=) + # object.b = 2 if object.respond_to?(:b=) + # + # Using an associative array instead of a hash guarantees order of assignment + # for older versions of Ruby (< 1.8.7). + # + # TODO: Should this be called #set instead? Consider Module#set in this + # question, and also #set_from as the alias of #assign_from. + + def assign(data=nil, value=NA) + return self unless data + + if value==NA + data.each do |(k,v)| + __send__("#{k}=", v) if respond_to?("#{k}=") + end + else + __send__("#{data}=", value) if respond_to?("#{data}=") + end + self + end + + # Set attribute writers using like readers from another object. + # + # class AssignExample + # attr_accessor :a, :b + # def initialize(a, b) + # @a, @b = a, b + # end + # end + # + # obj1 = AssignExample.new(1,2) + # obj2 = AssignExample.new(3,4) + # + # obj2.assign_from(obj1, :a, :b) + # + # obj2.a #=> 1 + # obj2.b #=> 2 + # + # TODO: Should this be called #set_from ? + + def assign_from(obj, *fields) + fields.flatten.each do |k| + send("#{k}=", obj.__send__("#{k}")) #if self.respond_to?("#{k}=") && obj.respond_to?("#{k}") + end + end + + ## DEPRECATED: Original name for #assign_from. + ##alias_method :set_from, :assign_from +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign_from.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign_from.rb new file mode 100644 index 00000000..d52ba249 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/assign_from.rb @@ -0,0 +1 @@ +require 'facets/kernel/assign' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/attr_singleton.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/attr_singleton.rb new file mode 100644 index 00000000..120fd01e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/attr_singleton.rb @@ -0,0 +1,59 @@ +module Kernel + + # Creates singleton attr_readers. + # + # obj = Object.new + # + # obj.attr_singleton_reader :x, :y + # + # attr_singleton_reader :x, :y + # + # CREDIT: Trans + + def attr_singleton_reader(*args) + #h, a = *args.partition{|a| Hash===a} + (class << self ; self ; end).send( :attr_reader, *args ) + #(class << self ; self ; end).send( :attr_reader, *h.keys ) + #h.each { |k,v| instance_variable_set("@#{k}", v) } + end + + # Create singleton attr_writers. + # + # obj = Object.new + # + # obj.attr_singleton_writer :x, :y + # + # obj.x = 3 + # obj.y = 4 + # + # CREDIT: Trans + + def attr_singleton_writer(*args) + #h, a = *args.partition{|a| Hash===a} + (class << self ; self ; end).send( :attr_writer, *args ) + #(class << self ; self ; end).send( :attr_writer, *h.keys ) + #h.each { |k,v| instance_variable_set("@#{k}", v) } + end + + # Create singleton attr_accessors. + # + # obj = Object.new + # + # obj.attr_singleton_accessor :x, :y + # + # obj.x = 3 + # obj.y = 4 + # obj.x #=> 3 + # obj.y #=> 4 + # + # CREDIT: Trans + + def attr_singleton_accessor(*args) + #h, a = *args.partition{|a| Hash===a} + (class << self ; self ; end).send( :attr_accessor, *args ) + #(class << self ; self ; end).send( :attr_accessor, *h.keys ) + #h.each { |k,v| instance_variable_set("@#{k}", v) } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/blank.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/blank.rb new file mode 100644 index 00000000..cd382f9c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/blank.rb @@ -0,0 +1,84 @@ +module Kernel + # An object is blank if it's nil, empty, or a whitespace string. + # For example, "", " ", nil, [], and {} are blank. + # + # This simplifies... + # + # if !address.nil? && !address.empty? + # + # to... + # + # if !address.blank? + # + def blank? + return empty? if respond_to?(:empty?) + !self + end + + # An object is present if it's not blank. + def present? + !blank? + end + + # Returns object if it's #present? otherwise returns nil. + # object.presence is equivalent to object.present? ? object : nil. + # + # This is handy for any representation of objects where blank is the same + # as not present at all. For example, this simplifies a common check for + # HTTP POST/query parameters... + # + # state = params[:state] if params[:state].present? + # country = params[:country] if params[:country].present? + # region = state || country || 'US' + # + # becomes... + # + # region = params[:state].presence || params[:country].presence || 'US' + # + def presence + self if present? + end +end + +class NilClass + def blank? + true + end +end + +class FalseClass + def blank? + true + end +end + +class TrueClass + def blank? + false + end +end + +class Array + alias_method :blank?, :empty? +end + +class Hash + alias_method :blank?, :empty? +end + +class String + # Is this string just whitespace? + # + # "abc".blank? #=> false + # " ".blank? #=> true + def blank? + /\S/ !~ self + end +end + +class Numeric + def blank? + false + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/call_stack.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/call_stack.rb new file mode 100644 index 00000000..92ac9ae8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/call_stack.rb @@ -0,0 +1 @@ +require 'facets/kernel/callstack' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/callstack.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/callstack.rb new file mode 100644 index 00000000..8069ccf0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/callstack.rb @@ -0,0 +1,56 @@ +module Kernel + + alias_method :pp_callstack, :caller + alias_method :pp_call_stack, :caller + + # Parse a caller string and break it into its components, + # returning an array composed of: + # + # * file (String) + # * lineno (Integer) + # * method (Symbol) + # + # For example, from irb + # + # callstack(1) + # + # _produces_ ... + # + # [["(irb)", 2, :irb_binding], + # ["/usr/lib/ruby/1.8/irb/workspace.rb", 52, :irb_binding], + # ["/usr/lib/ruby/1.8/irb/workspace.rb", 52, nil]] + # + # Note: If the user decides to redefine caller() to output data + # in a different format, _prior_ to requiring this, then the + # results will be indeterminate. + # + # CREDIT: Trans + + def callstack(level = 1) + call_str_array = pp_callstack(level) + stack = [] + call_str_array.each{ |call_str| + file, lineno, method = call_str.split(':') + if method =~ /in `(.*)'/ then + method = $1.intern() + end + stack << [file, lineno.to_i, method] + } + stack + end + + alias_method :call_stack, :callstack + +end + + +class Binding + + # Returns the call stack, in array format. + def callstack(level=1) + eval( "callstack( #{level} )" ) + end + + alias_method :call_stack, :callstack +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/case.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/case.rb new file mode 100644 index 00000000..95fe0ac8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/case.rb @@ -0,0 +1,8 @@ +module Kernel + + def case?(*matchers) + matchers.all?{ |m| m === self } + end unless method_defined?(:case?) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/complete.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/complete.rb new file mode 100644 index 00000000..7818f2e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/complete.rb @@ -0,0 +1,26 @@ +module Kernel + + # Repeat loop until it yeilds false or nil. + # + # a = [3, 2, 1] + # b = [] + # + # complete do + # x = a.pop + # b << x + # x + # end + # + # b #=> [1, 2, 3, nil] + # + # Be "aware" when using this method, it easy to accidently + # induce infinite loops. + # + # CREDIT: Trans + + def complete + loop { break unless yield } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/constant.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/constant.rb new file mode 100644 index 00000000..f9b2bd8f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/constant.rb @@ -0,0 +1,22 @@ +module Kernel + + # This is similar to +Module#const_get+ but is accessible at all levels, + # and, unlike +const_get+, can handle module hierarchy. + # + # constant("Fixnum") # => Fixnum + # constant(:Fixnum) # => Fixnum + # + # constant("Process::Sys") # => Process::Sys + # constant("Regexp::MULTILINE") # => 4 + # + # TODO: As of Ruby 2.0, #constant can be deprecated, or aliased to #get_const. + # + # CREDIT: Trans + + def constant(const) + const = const.to_s.dup + base = const.sub!(/^::/, '') ? Object : ( self.kind_of?(Module) ? self : self.class ) + const.split(/::/).inject(base){ |mod, name| mod.const_get(name) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/d.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/d.rb new file mode 100644 index 00000000..8ed4939d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/d.rb @@ -0,0 +1,27 @@ +module Kernel + + # Like #p but gives file and line number... + # + # d("hi") + # + # produces ... + # + # "hi" (/home/dave/projects/foo.rb, 38) + # + def d(*x) + puts "#{x.inspect} #{caller[0]}" + return *x + end + + #-- + # Old definition ... + # + # def d(*x) + # puts "#{__FILE__}, #{__LINE__}" + # x.each{ |e| puts e.inspect } #p(*x) + # x.size > 1 ? x : x.last #x.last + # end + #++ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_clone.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_clone.rb new file mode 100644 index 00000000..a09b535b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_clone.rb @@ -0,0 +1,27 @@ +module Kernel + + # Deep clone an object by deep cloning every instance + # variable as well. + # + # Returns [Object] + + def deep_clone(cache={}) + return cache[self] if cache.key?(self) + + copy = clone() + cache[self] = copy + + copy.instance_variables.each do |var| + val = instance_variable_get(var) + begin + val = val.deep_clone(cache) + rescue TypeError + next + end + copy.instance_variable_set(var, val) + end + + return copy + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_copy.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_copy.rb new file mode 100644 index 00000000..bdd33128 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/deep_copy.rb @@ -0,0 +1,14 @@ +module Kernel + + # Anything that can be marshaled can be copied in totality. + # + # "ABC".deep_copy #=> "ABC" + # + # NOTE: Not sure why we wouldn't just call this #copy, but + # the term +deep_copy+ seems to be the common practive. + def deep_copy + Marshal::load(Marshal::dump(self)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/demo.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/demo.rb new file mode 100644 index 00000000..48080ea7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/demo.rb @@ -0,0 +1,30 @@ +module Kernel + + # TODO: Is there a way to do this without the eval string in block? + # Preferably just a block and no string. + + # For debugging and showing examples. Currently this + # takes an argument of a string in a block... + # + # demo {%{ a = [1,2,3] }} + # demo {%{ a.slice(1,2) }} + # demo {%{ a.map { |x| x**3 } }} + # + # produces ... + # + # a = [1,2,3] #=> [1, 2, 3] + # a.slice(1,2) #=> [2, 3] + # a.map { |x| x**3 } #=> [1, 8, 27] + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/kernel/demo' + # + def demo(out=$stdout,&block) + out << sprintf("%-25s#=> %s\n", expr = block.call, eval(expr, block.binding).inspect) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/disable_warnings.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/disable_warnings.rb new file mode 100644 index 00000000..2300fd82 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/disable_warnings.rb @@ -0,0 +1,26 @@ +module Kernel + + # + # CREDIT: Trans + + def disable_warnings #:yield: + verbose, $VERBOSE = $VERBOSE, nil + yield + ensure + $VERBOSE = verbose + end + + # DEPRECATE: Use #disable_warnings instead. + alias_method :silence_warnings, :disable_warnings + + # + # CREDIT: Trans + + def enable_warnings #:yield: + verbose, $VERBOSE = $VERBOSE, true + yield + ensure + $VERBOSE = verbose + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigen.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigen.rb new file mode 100644 index 00000000..666978a4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigen.rb @@ -0,0 +1,2 @@ +# Deprecated! +require 'facets/kernel/meta' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigenclass.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigenclass.rb new file mode 100644 index 00000000..d1dbe2fd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/eigenclass.rb @@ -0,0 +1,24 @@ +module Kernel + + # During this trying time when no one can get their + # techie catchwords to stick to the refrigerator no + # matter how hard they slap it with the enchanted + # magnetic spatula, it’s good to know that the + # contrived phrases really do fly, graceful and + # unclasped and bearing north toward chilled shrimp. + # I know what my Hallowe’en pumpkin is going to say. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using `require 'facets'`. + # + # CREDIT: WhyTheLuckyStiff + # + # @uncommon + # require 'facets/kernel/eigenclass' + # + def eigenclass + (class << self; self; end) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/enable_warnings.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/enable_warnings.rb new file mode 100644 index 00000000..41c7e2a1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/enable_warnings.rb @@ -0,0 +1 @@ +require 'facets/kernel/disable_warnings' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/ergo.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/ergo.rb new file mode 100644 index 00000000..e3fd9ded --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/ergo.rb @@ -0,0 +1,43 @@ +require 'facets/functor' + +module Kernel + + # Yield self -or- return self. + # + # "a".ergo.upcase #=> "A" + # nil.ergo.foobar #=> nil + # + # "a".ergo{ |o| o.upcase } #=> "A" + # nil.ergo{ |o| o.foobar } #=> nil + # + # This is like #tap, but #tap yields self and returns self, + # where as #ergo yields self but returns the result. + # + # CREDIT: Daniel DeLorme + + def ergo(&b) + if block_given? + b.arity == 1 ? yield(self) : instance_eval(&b) + else + self + end + end + +end + +class NilClass + FUNCTOR = Functor.new{ nil } + + # Compliments Kernel#ergo. + # + # "a".ergo{ |o| o.upcase } #=> "A" + # nil.ergo{ |o| o.bar } #=> nil + # + # CREDIT: Daniel DeLorme + + def ergo + FUNCTOR unless block_given? + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/extend.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/extend.rb new file mode 100644 index 00000000..c8d6c1c4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/extend.rb @@ -0,0 +1,28 @@ +module Kernel + + extend_method = instance_method(:extend) + + # Extend an object with a module. + # + # If a block is given, it will be evaluated into an anonymous + # module and used to extend the object. + # + # obj = Object.new + # + # obj.extend do + # def foo; "foo"; end + # end + # + # obj.foo #=> "foo" + # + # NOTE: This is one of the few core overrides in Facets. + # + # @author Trans + # @author Marco Otte-Witte (bug fix) + define_method :extend do |*mod, &blk| + extend_method.bind(self).call(*mod) unless mod.empty? + extend_method.bind(self).call(Module.new(&blk)) if blk + self + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/extension.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/extension.rb new file mode 100644 index 00000000..70997b19 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/extension.rb @@ -0,0 +1,12 @@ +module Kernel + + # TODO: Must reduce the number of singleton method methods. + + # Don't say it! + # + def extension + class << self; self; end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/false.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/false.rb new file mode 100644 index 00000000..37bb5541 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/false.rb @@ -0,0 +1,2 @@ +require 'facets/kernel/true' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/here.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/here.rb new file mode 100644 index 00000000..5925a4ed --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/here.rb @@ -0,0 +1,11 @@ +module Kernel + + # A shorthand pronoun for binding(). + # + # a = 3 + # eval("a", here) #=> 3 + # + alias_method :here, :binding + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/hierarchical_send.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/hierarchical_send.rb new file mode 100644 index 00000000..acde39e0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/hierarchical_send.rb @@ -0,0 +1,44 @@ +require 'facets/class/hierarchically' + +module Kernel + + # Send a message to each ancestor in an object's class hierarchy. + # The method will only be called if the method is defined for the + # ancestor. + # + # This can be very useful for setting up a `preinitialize` system. + # + # m = Module.new do + # attr :a + # def preinitialize + # @a = 1 + # end + # end + # + # c = Class.new do + # include m + # def initialize + # hierarchical_send(:preinitialize) + # end + # end + # + # c.new.a #=> 1 + # + # @todo Include singleton class? + def hierarchical_send(method_name, *args, &block) + method_name = method_name.to_s if RUBY_VERSION < '1.9' + this = self + self.class.hierarchically do |anc| + ## is there really no better way to check for the method? + if anc.instance_methods(false).include?(method_name) or + anc.public_instance_methods(false).include?(method_name) or + anc.private_instance_methods(false).include?(method_name) or + anc.protected_instance_methods(false).include?(method_name) + im = anc.instance_method(method_name) + ##im.arity == 0 ? im.bind(this).call(&block) : im.bind(this).call(*args, &block) + im.bind(this).call(*args, &block) + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/identical.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/identical.rb new file mode 100644 index 00000000..12160b07 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/identical.rb @@ -0,0 +1,4 @@ +module Kernel + alias_method :identical?, :equal? +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/in.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/in.rb new file mode 100644 index 00000000..3456aea7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/in.rb @@ -0,0 +1,13 @@ +module Kernel + + # Is self included in other? + # + # 5.in?(0..10) #=> true + # 5.in?([0,1,2,3]) #=> false + # + def in?(other) + other.include?(self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_assign.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_assign.rb new file mode 100644 index 00000000..fd01122f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_assign.rb @@ -0,0 +1,22 @@ +module Kernel + + # Set instance variables using a hash. + # + # instance_assign('@a'=>1, '@b'=>2) + # @a #=> 1 + # @b #=> 2 + # + # NOTE: Conceptually a better alternative to this method is `instance.update` + # from the `instance` gem. However, practically this method is probably + # the better choice until such time that Ruby supports anonymous delegators. + # + def instance_assign(hash) + hash.each do |k,v| + k = "@#{k}" if k !~ /^@/ + instance_variable_set(k, v) + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_class.rb new file mode 100644 index 00000000..ce7f936b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_class.rb @@ -0,0 +1,26 @@ +module Kernel + + # Kernel extension prefixed by instance_ which provide + # internal (eg private) access to the object. + # Kernel extension using instance_ prefix which is beneficial + # to separation of metaprogramming from general programming. + # object_ methods, in contrast to the instance_ methods, + # do not access internal state. + + # Easy access to an object qua class, otherwise known + # as the object's metaclass or singleton class. This + # implemnetation alwasy returns the class, even if a + # block is provided to eval against it... + # + # It is what it is. + # But I think I like this one best. + # + # CREDIT: Trans + + def instance_class(&block) + (class << self; self; end).module_eval(&block) if block + (class << self; self; end) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_exec.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_exec.rb new file mode 100644 index 00000000..72a1c7df --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_exec.rb @@ -0,0 +1,47 @@ +class Object #module Kernel + + unless method_defined?(:instance_exec) # 1.9 + + require 'thread' + + module InstanceExecMethods #:nodoc: + end + + include InstanceExecMethods + + # Evaluate the block with the given arguments within the context of + # this object, so self is set to the method receiver. + # + # From Mauricio's http://eigenclass.org/hiki/bounded+space+instance_exec + # + # This version has been borrowed from Rails for compatibility sake. + # + # NOTE: This is not a common core extension (due to the use of thread.rb) + # and is not loaded automatically when using require 'facets'. + # However it is a core method in Ruby 1.9, so this only matters for users + # of Ruby 1.8.x or below. + # + # @uncommon + # require 'facets/kernel/instance_exec' + # + def instance_exec(*args, &block) + begin + old_critical, Thread.critical = Thread.critical, true + n = 0 + n += 1 while respond_to?(method_name = "__instance_exec#{n}") + InstanceExecMethods.module_eval { define_method(method_name, &block) } + ensure + Thread.critical = old_critical + end + + begin + __send__(method_name, *args) + ensure + InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_extract.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_extract.rb new file mode 100644 index 00000000..448f0ced --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_extract.rb @@ -0,0 +1,22 @@ +module Kernel + + # Like `instance_assign`, but only assigns an instance variable if + # it does not already exist. + # + # @a = 9 + # instance_extract('@a'=>1, '@b'=>2) + # @a #=> 9 + # @b #=> 2 + # + # CREDIT: T. Yamada + + def instance_extract(hash) + hash.each do |k,v| + k = "@#{k}" if k !~ /^@/ + instance_variable_set(k, v) unless instance_variable_defined?(k) + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_replace.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_replace.rb new file mode 100644 index 00000000..1b04c524 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_replace.rb @@ -0,0 +1,40 @@ +module Kernel + + # Replace state of object with the state of another object of the + # same class (or superclass). + # + # class ReplaceExample + # attr_reader :a, :b + # def initialize(a,b) + # @a, @b = a, b + # end + # end + # + # obj1 = ReplaceExample.new(1,2) + # obj1.a #=> 1 + # obj1.b #=> 2 + # + # obj2 = ReplaceExample.new(3,4) + # obj2.a #=> 3 + # obj2.b #=> 4 + # + # obj1.instance_replace(obj2) + # obj1.a #=> 3 + # obj1.b #=> 4 + # + # This is very similar to `instance.assign`, but it is limited + # by the class of object, in the same manner as Array#replace. + # + # NOTE: Conceptually a better alternative is `instance.replace` provided + # by the `instance` gem. However, practically this method is probably + # the better choice until such time that Ruby support anonymous delegators. + # + def instance_replace(source) + raise ArgumentError, "not a #{self.class} -- #{source}" unless source.is_a?(self.class) + instance_variables.each do |iv| + instance_variable_set(iv, source.instance_variable_get(iv)) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_send.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_send.rb new file mode 100644 index 00000000..cb759aa0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/instance_send.rb @@ -0,0 +1,7 @@ +module Kernel + + # Private send. + alias_method :instance_send, :__send__ + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/like.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/like.rb new file mode 100644 index 00000000..3e6a52dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/like.rb @@ -0,0 +1,19 @@ +module Kernel + + # Broad equality. Checks to see if the object +x+ is in any + # way equal to the reciever, starting with the identity + # #equal?, then #eql?, then #==, and ending with #===. + # + # 1.like?(1.0) #=> true + # "string".like?("string") #=> true + # String.like?("string") #=> true + # + def like?(x) + equal?(x) || eql?(x) || self == x || self === x + end + + # @deprecated + alias :equate? :like? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_all.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_all.rb new file mode 100644 index 00000000..4fd4dc4b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_all.rb @@ -0,0 +1 @@ +require 'facets/kernel/require_all' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_relative.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_relative.rb new file mode 100644 index 00000000..e7bf4bde --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/load_relative.rb @@ -0,0 +1,25 @@ +module Kernel + + unless private_method_defined?(:load_relative) # Will Ruby ever support out-of-the-box? + + # Load file from same dir as calling script. + # + # load_relative 'myscript' + # + # CREDIT: Paul Brannan, Pragmatic Programmers + # + def load_relative(relative_feature, safe=nil) + c = caller.first + fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/) + file = $` # File.dirname(c) + if /\A\((.*)\)/ =~ file # eval, etc. + raise LoadError, "require_relative is called in #{$1}" + end + absolute = File.expand_path(relative_feature, File.dirname(file)) + load absolute, safe + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/maybe.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/maybe.rb new file mode 100644 index 00000000..f828f98a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/maybe.rb @@ -0,0 +1,19 @@ +module Kernel + + # Random generator that returns true or false. + # Can also take a block that has a 50/50 chance + # to being executed... + # + # maybe #=> true + # maybe #=> false + # + def maybe(chance = 0.5, &block) + if block + yield if rand < chance + else + rand < chance + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/memo.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/memo.rb new file mode 100644 index 00000000..06af2f8a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/memo.rb @@ -0,0 +1,44 @@ +require 'facets/binding/eval' +require 'facets/kernel/__method__' + +module Kernel + + # Global memo cache. + $MEMO ||= {} + + # Memoize a method. + # + # class MemoExample + # attr_accessor :a + # def m + # memo{ @a } + # end + # end + # + # ex = MemoExample.new + # + # ex.a = 10 + # ex.m #=> 10 + # + # ex.a = 20 + # ex.m #=> 10 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/kernel/memo' + # + def memo(*args, &block) + if args.empty? + args = block.binding.eval('[self, __method__]') + end + if $MEMO.key?(args) + $MEMO[args] + else + $MEMO[args] = block.call + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta.rb new file mode 100644 index 00000000..f5aa6ce7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta.rb @@ -0,0 +1,35 @@ +require 'facets/functor' + +module Kernel + + # TODO: Should Kernel#eigen be moved to a functor gem? + + # Call methods on the eigenclass (i.e. the singleton_class). + # + # name = "Tom" + # name.eigen.define_method(:turkey){ self + " Turkey" } + # name.turkey #=> "Tom Turkey" + # + # One of the nice things you can do with #eigen is define class attributes + # without having to open a `class << self` block. + # + # c = Class.new do + # meta.attr_accessor :a + # end + # c.a = 1 + # c.a #=> 1 + # + def meta + Functor.new do |op,*a,&b| + (class << self; self; end).class_eval do + __send__(op,*a,&b) + end + end + end + + def eigen + warn "The `eigen' method is deprecated. Please use `meta' instead." + meta + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_alias.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_alias.rb new file mode 100644 index 00000000..c14f78e1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_alias.rb @@ -0,0 +1,23 @@ +require 'facets/kernel/meta_class' + +module Kernel + + # Alias a method defined in the metaclass (ie. singleton class). + # + # class MetaExample + # def self.y?; "y?" ; end + # end + # + # MetaExample.meta_alias "ynot?", "y?" + # + # MetaExample.ynot? #=> "y?" + # + # CREDIT: Trans + + def meta_alias(*args) + meta_class do + alias_method(*args) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_class.rb new file mode 100644 index 00000000..b175a569 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_class.rb @@ -0,0 +1,17 @@ +module Kernel + + # Easy access to an object's "special" class, otherwise known as it's + # singleton class, eigenclass, adhoc class or object-qua-class. + # + def meta_class(&block) + if block_given? + (class << self; self; end).class_eval(&block) + else + (class << self; self; end) + end + end + + # The non-underscored form of #meta_class if faily common. + alias_method :metaclass, :meta_class + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_def.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_def.rb new file mode 100644 index 00000000..103b5fc5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_def.rb @@ -0,0 +1,24 @@ +require 'facets/kernel/meta_class' + +module Kernel + + # Add method to a meta-class --i.e. a singleton method. + # + # class X; end + # X.meta_def(:x){"x"} + # X.x #=> "x" + # + # CREDIT: WhyTheLuckyStiff + + def meta_def( name, &block ) + meta_class do + define_method( name, &block ) + end + end + + #def meta_def( name, &blk ) + # meta_eval { define_method name, &blk } + #end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_eval.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_eval.rb new file mode 100644 index 00000000..d01ae36b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/meta_eval.rb @@ -0,0 +1,20 @@ +require 'facets/kernel/meta_class' + +module Kernel + + # Evaluate code in a metaclass. This is equivalent to: + # + # meta_class.instance_eval(...) + # + # CREDIT: WhyTheLuckyStiff + + def meta_eval(str=nil, *file_and_line, &blk) + if str + meta_class.instance_eval(str, *file_and_line) + else + meta_class.instance_eval(&blk) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/method.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/method.rb new file mode 100644 index 00000000..75c28e31 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/method.rb @@ -0,0 +1,50 @@ +$FIRST_CLASS_METHODS = Hash.new{ |h,k| h[k] = {} } + +module Kernel + + # Easy access to method as object, and they retain state. + # + # def hello + # puts "Hello World!" + # end + # + # m1 = method!(:hello) + # + # def m1.annotate + # "simple example" + # end + # + # m2 = method!(:hello) + # m2.annotate #=> "simple example" + # + def method!(s) + #( @__methods__ ||= {} )[s.to_sym] ||= method(s) + $FIRST_CLASS_METHODS[self][s.to_sym] ||= method(s) + end + +end + +#-- +# Should 1st Class Methods be part of Ruby proper? +# +# Perhaps the best solution would be using the notation +# ::ameth. This would require some minor changes +# to Ruby, but with few backward incompatabilites if +# parantheticals revert back to the actual method invocation. +# Although this later stipulation means capitalized methods +# would not be accessible in this way b/c they would intefere with +# constant lookup. It's a trade off. ... +# +# Current Proposed Alternate +# ----------------- ------------------ ------------------- +# Foo.Bar() method call method call method call +# Foo.Bar method call method call method call +# Foo.bar() method call method call method call +# Foo.bar method call method call method call +# Foo::Bar() method call method call 1st class method +# Foo::Bar constant lookup constant lookup constant lookup +# Foo::bar() method call method call 1st class method +# Foo::bar method call 1st class method 1st class method +# +# Then again this dosen't address bound versus unbound. +#++ diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/no.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/no.rb new file mode 100644 index 00000000..2cab691f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/no.rb @@ -0,0 +1 @@ +require 'facets/kernel/yes' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/not.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/not.rb new file mode 100644 index 00000000..3d89ea9b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/not.rb @@ -0,0 +1,37 @@ +require 'facets/functor' + +module Kernel + + # Same as using NOT operator '!'. + # + # true.nil?.not? == !true.nil? + # + def not? + !self + end + + # Inversion functor. + # + # true.not.nil? #=> true + # + def not + Functor.new(&method(:not_send).to_proc) + end + + ## TODO: When we no longer need to support 1.8.6 we can use: + ## + ## def not + ## Functor.new do |op, *a, &b| + ## !__send__(op, *a, &b) + ## end + ## end + + private + + # + def not_send(op, *a, &b) + !__send__(op, *a) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/not_nil.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/not_nil.rb new file mode 100644 index 00000000..340a5895 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/not_nil.rb @@ -0,0 +1,18 @@ +module Kernel + + # The opposite of #nil?. + # + # "hello".not_nil? # -> true + # nil.not_nil? # -> false + # + # CREDIT: Gavin Sinclair + + def not_nil? + ! nil? + end + + # DEPRECATED: #not_nil? it enough. + #alias_method :non_nil?, :not_nil? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_class.rb new file mode 100644 index 00000000..d6fa038c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_class.rb @@ -0,0 +1,10 @@ +module Kernel + + # Defines object_classas an alias of class. + # This is an alternative to __class__, akin to + # #object_id. + + alias_method :object_class, :class + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_hexid.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_hexid.rb new file mode 100644 index 00000000..9625a152 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_hexid.rb @@ -0,0 +1,33 @@ +module Kernel + + ARCH_SIZE = (['a'].pack('P').length > 4 ? 64 : 32) + + if RUBY_VERSION < '1.9' + if ARCH_SIZE == 64 + HEXID_TEMPLATE = "0x%012x" + else + HEXID_TEMPLATE = "0x%x" + end + else + if ARCH_SIZE == 64 + HEXID_TEMPLATE = "0x%014x" + else + HEXID_TEMPLATE = "0x%x" + end + end + + # Returns the object id as a string in hexideciaml, + # which is how Ruby reports them with inspect... + # + # "ABC".object_hexid #=> "0x402d359c" + # + def object_hexid + HEXID_TEMPLATE % (__id__ << 1) + end + + # The 1.9.3 definition is as follows: + #def object_hexid + # "0x" + [object_id << 1].pack("L>!").unpack("H*")[0] + #end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_send.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_send.rb new file mode 100644 index 00000000..cbe3a9d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/object_send.rb @@ -0,0 +1,30 @@ +module Kernel + + # Send only to public methods. + # + # class SendExample + # private + # def foo; end + # end + # + # obj = SendExample.new + # + # expect NoMethodError do + # obj.object_send(:foo) + # end + # + # DEPRECATED: Use #public_send instead. + + alias object_send public_send rescue nil + + #def object_send(name, *args, &blk) + # #instance_eval "self.#{name}(*args)" + # if respond_to?(name) + # __send__(name, *args, &blk) + # else + # __send__(:method_missing, name, *args, &blk) + # end + #end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/p.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/p.rb new file mode 100644 index 00000000..c0bb5cd8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/p.rb @@ -0,0 +1,24 @@ +module Kernel + + # Alternate to standard #p method that outputs + # Kernel#inspect to stdout, but also passes through + # the orginal argument(s) ... + # + # x = 1 + # r = 4 + p(1) + # p r + # + # produces ... + # + # 1 + # 5 + # + # TODO: DEPRECATE as of 1.9, _if_ it will do this. + + def p(*x) + x.each{ |e| puts e.inspect } #p(*x) + x.size > 1 ? x : x.last #x.last + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/presence.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/presence.rb new file mode 100644 index 00000000..d307b2b9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/presence.rb @@ -0,0 +1 @@ +require 'facets/kernel/blank' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/present.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/present.rb new file mode 100644 index 00000000..d307b2b9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/present.rb @@ -0,0 +1 @@ +require 'facets/kernel/blank' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/qua_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/qua_class.rb new file mode 100644 index 00000000..f459a57c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/qua_class.rb @@ -0,0 +1,31 @@ +module Kernel + + # Easy access to an object qua class, otherwise known as the object's + # singleton class. #qua_class can also take a block. + # + # string = "Hello World" + # + # string.qua_class do + # def important + # self + "!" + # end + # end + # + # string.important #=> "Hello World!" + # + # Yes, another one. + # + # CREDIT: Trans + + def qua_class(&block) + if block_given? + (class << self; self; end).class_eval(&block) + else + (class << self; self; end) + end + end + + # The +qua_class+ method can also be written +quaclass+. + alias_method :quaclass, :qua_class + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/require_all.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/require_all.rb new file mode 100644 index 00000000..62f962ea --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/require_all.rb @@ -0,0 +1,42 @@ +module Kernel + + # Require a pattern of files relatvie to the current file. + # This makes is easy to require an entire directory, for instance: + # + # require_all 'core_ext/*' + # + # NOTE: This method used to allow glob-based requires from the $LOAD_PATH, + # but this was deprecated in favor of relative requiring only, as it is + # consider the typical usecase, and globbing from the $LOAD_PATH is a + # bit dangerous. Better options exist for globbing the $LOAD_PATH such as + # the +plugins+ gem. + + def require_all(pattern) + c = caller.first + fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/) + file = $` # File.dirname(c) + if /\A\((.*)\)/ =~ file # eval, etc. + raise LoadError, "require_relative is called in #{$1}" + end + glob = File.expand_path(pattern, File.dirname(file)) + Dir.glob(glob).each do |absolute| + require absolute + end + end + + # Same as #require_all, but for #load. + def load_all(pattern, safe=nil) + c = caller.first + fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/) + file = $` # File.dirname(c) + if /\A\((.*)\)/ =~ file # eval, etc. + raise LoadError, "require_relative is called in #{$1}" + end + glob = File.expand_path(pattern, File.dirname(file)) + Dir.glob(glob).each do |absolute| + load absolute, safe + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/respond.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/respond.rb new file mode 100644 index 00000000..fbbe7336 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/respond.rb @@ -0,0 +1,32 @@ +require 'facets/functor' + +module Kernel + + # TODO: Should Kernel#respond be moved to functor gem? + + # Like #respond_to? but returns the result of the call + # if it does indeed respond. + # + # class RespondExample + # def f; "f"; end + # end + # + # x = RespondExample.new + # x.respond(:f) #=> "f" + # x.respond(:g) #=> nil + # + # This method was known as #try until Rails defined #try + # to be something more akin to #ergo. + # + # CREDIT: Chris Wanstrath + + def respond(sym=nil, *args, &blk) + if sym + return nil if not respond_to?(sym) + __send__(sym, *args, &blk) + else + Functor.new(&method(:respond).to_proc) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/returning.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/returning.rb new file mode 100644 index 00000000..9fee04f7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/returning.rb @@ -0,0 +1,27 @@ +module Kernel + + # A Ruby-ized realization of the K combinator. + # + # book_class = Struct.new(:title, :author) + # + # book = returning book_class.new do |book| + # book.title = "Imperium" + # book.author = "Ulick Varange" + # end + # + # book.class #=> book_class + # + # Technically, #returning probably should force the return of + # the stated object irregardless of any return statements that + # might appear within it's block. This might differentiate + # #returning from #with, however it also would require + # implementation in Ruby itself. + # + # CREDIT: Mikael Brockman + + def returning(obj=self) #:yield: + yield obj + obj + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence.rb new file mode 100644 index 00000000..e16ba88f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence.rb @@ -0,0 +1,73 @@ +module Kernel + + # Silence a stream and/or warnings... + # + # silence(:stdout) do + # puts "won't see me" + # end + # + # Supported +streams+ are +stderr+, +stdout+, +verbose+, +debug+, + # and +warnings+, which is the same as +verbose+. You can also + # use the actual streams, STDERR and STDOUT. + def silence(*streams) #:yield: + streams = streams.map do |stream| + case stream + when :stderr + STDERR + when :stdout + STDOUT + else + stream + end + end + + if streams.empty? + yield + else + silence_stream(*streams){ yield } + end + end + + # Just like silence_stream, but will default to + # STDOUT, STDERR if no streams are given. + + def silently(*streams) #:yeild: + streams = [STDOUT, STDERR] if streams.empty? + silence_stream(*streams){ yield } + end + + # Silences any stream for the duration of the block... + # + # silence_stream(STDOUT) do + # puts 'This will never be seen' + # end + # + # puts 'But this will' + # + # CREDIT: David Heinemeier Hansson + + def silence_stream(*streams) #:yeild: + on_hold = streams.collect{ |stream| stream.dup } + streams.each do |stream| + stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') + stream.sync = true + end + yield + ensure + streams.each_with_index do |stream, i| + stream.reopen(on_hold[i]) + end + end + + # Equivalent to `silence_stream(STDERR)`. + def silence_stderr #:yeild: + silence_stream(STDERR) { yield } + end + + # Equivalent to `silence_stream(STDOUT)`. + def silence_stdout #:yeild: + silence_stream(STDOUT) { yield } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence_warnings.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence_warnings.rb new file mode 100644 index 00000000..41c7e2a1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/silence_warnings.rb @@ -0,0 +1 @@ +require 'facets/kernel/disable_warnings' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/singleton_class.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/singleton_class.rb new file mode 100644 index 00000000..d87292fe --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/singleton_class.rb @@ -0,0 +1,10 @@ +module Kernel + + # Easy access to an object's "special" class. + # + # NOTE: This is already defined in Ruby 1.9+. + def singleton_class + (class << self; self; end) + end unless method_defined?(:singleton_class) + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/super_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/super_method.rb new file mode 100644 index 00000000..dc331202 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/super_method.rb @@ -0,0 +1,11 @@ +module Kernel + + # Returns method of a parent class bound to self. + def super_method(klass, meth) + unless self.class.ancestors.include?(klass) + raise ArgumentError, "Not an ancestor for super_method-- #{klass}" + end + klass.instance_method(meth).bind(self) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/tap.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/tap.rb new file mode 100644 index 00000000..48fccf2b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/tap.rb @@ -0,0 +1,36 @@ +require 'facets/functor' + +module Kernel + + # The tap K-Combinator. This yields self -and- returns self. + # + # 'foo.yml'.tap{ |f| YAML.load(f) } #=> 'foo.yml' + # + # Unlike Ruby's definition, this rendition can be used as a higher + # order message. This form allows a single call before returning + # the receiver. + # + # YAML.tap.load_file('foo.yml').load_file('bar.yml') + # + # IMPORTANT: This is one of few core overrides in Facets. + + def tap #:yield: + if block_given? + yield(self) + self + else + Functor.new{ |op,*a,&b| self.send(op, *a, &b); self } + end + end + + # Old Definition: + # + # def tap #:yield: + # if block_given? + # b.arity == 1 ? yield(self) : instance_eval(&b) + # end + # return self + # end + # + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/temporarily.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/temporarily.rb new file mode 100644 index 00000000..78b67a67 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/temporarily.rb @@ -0,0 +1,23 @@ +module Kernel + + # Temporarily set variables while yielding a block, then return the + # variables to their original settings when complete. + # + # temporarily('$VERBOSE'=>false) do + # $VERBOSE.assert == false + # end + # + def temporarily(settings) #:yield: + cache = {} + settings.each do |var, val| + cache[var] = eval("#{var}") + eval("proc{ |v| #{var} = v }").call(val) + end + yield + ensure + cache.each do |var, val| + eval("proc{ |v| #{var} = v }").call(val) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/trap_chain.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/trap_chain.rb new file mode 100644 index 00000000..29fd71f8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/trap_chain.rb @@ -0,0 +1,28 @@ +module Kernel + # Calling Kernel#trap() by itself will replace any previously registered + # handler code. Kernel#trap_chain(), on the other hand, will add the block + # you supply to the existing "list" of registered handler blocks. Similar + # to the way Kernel#at_exit() works, Kernel#trap_chain() will prepend the + # given block to the call chain for the given signal_name. When the signal + # occurs, your block will be executed first and then the previously + # registered handler will be invoked. This can be called repeatedly + # to create a "chain" of handlers. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Tyler Rick + # + # @uncommon + # require 'facets/kernel/trap_chain' + # + def trap_chain(signal_name, *args, &block) + previous_interrupt_handler = trap(signal_name, *args) {} + trap(signal_name, *args) do + block.call + previous_interrupt_handler.call unless previous_interrupt_handler == "DEFAULT" + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/true.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/true.rb new file mode 100644 index 00000000..70b76666 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/true.rb @@ -0,0 +1,26 @@ +module Kernel + + # Returns true is an object is class TrueClass, + # otherwise false. + # + # true.true? #=> true + # false.true? #=> false + # nil.true? #=> false + # + def true? + (true == self) + end + + # Returns true is an object is class FalseClass, + # otherwise false. + # + # true.false? #=> false + # false.false? #=> true + # nil.false? #=> false + # + def false? + (false == self) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/try.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/try.rb new file mode 100644 index 00000000..5f96179d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/try.rb @@ -0,0 +1,58 @@ +require 'facets/functor' + +module Kernel + + # Invokes the method identified by the symbol +method+, passing it any + # arguments and/or the block specified, just like the regular Ruby + # Object#send does. + # + # *Unlike* that method however, a +NoMethodError+ exception will *not* + # be raised and +nil+ will be returned instead, if the receiving object + # is a +nil+ object or NilClass. + # + # For example, without try + # + # @example = Struct.new(:name).new("bob") + # + # @example && @example.name + # + # or: + # + # @example ? @example.name : nil + # + # But with try + # + # @example.try(:name) #=> "bob" + # + # or + # + # @example.try.name #=> "bob" + # + # It also accepts arguments and a block, for the method it is trying: + # + # @people.try(:collect){ |p| p.name } + # + def try(method=nil, *args, &block) + if method + __send__(method, *args, &block) + else + self + end + end + +end + + +class NilClass + + # See Kernel#try. + def try(method=nil, *args) + if method + nil + else + Functor.new{ nil } + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/val.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/val.rb new file mode 100644 index 00000000..a9fab5f3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/val.rb @@ -0,0 +1,19 @@ +module Kernel + + # Tests to see if something has value. An object + # is considered to have value if it is not nil? + # and if it responds to #empty?, is not empty. + # + # nil.val? #=> false + # [].val? #=> false + # 10.val? #=> true + # [nil].val? #=> true + + def val? + return false if nil? + return false if empty? if respond_to?(:empty?) + true + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/with.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/with.rb new file mode 100644 index 00000000..abc585a7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/with.rb @@ -0,0 +1,20 @@ +module Kernel + + # Like returning but exectues the block + # via instance_eval. + # + # def foo + # with values = [] do + # self << 'bar' + # self << 'baz' + # end + # end + # + # foo # => ['bar', 'baz'] + # + def with(obj=self, &block) + obj.instance_eval(&block) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/writers.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/writers.rb new file mode 100644 index 00000000..4a5c6fc2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/writers.rb @@ -0,0 +1,91 @@ +module Kernel + + # Returns an Array of methods ending in '='. + # + # class WritersExample + # attr_reader :a, :b + # attr_accessor :x, :y + # private + # def q=(q); @q=q; end + # end + # + # w = WritersExample.new + # + # syms = w.writers # [:x=, :y=] + # + # syms.include?(:x=) #=> true + # syms.include?(:y=) #=> true + # + # If the +chomp+ option is true, then the trailing '=' will be removed. + # + # syms = w.writers(:chomp=>true) + # + # syms.include?(:x) #=> true + # syms.include?(:y) #=> true + # + # By default #writers only includes public methods. To see private or + # protected methods use the +:access+ option. + # + # w.writers(:access=>:private) #=> [:q=] + # + # Or multiple access options, + # + # syms = w.writers(:access=>[:public,:private]) # [:q=,:x=,:y=] + # + # syms.include?(:q=) #=> true + # syms.include?(:x=) #=> true + # syms.include?(:y=) #=> true + # + # You can simply supply `:all` to get all method regardless accessibility. + # + # Also, by default this method excludes all writers defined in Object + # or Kernel. To include these set +ancestors+ to Object or Kernel. + # + # w.writers(Object) + # + # TODO: Create Module#instance_writers. + + def writers(*ancestors_and_options) + options = (Hash === ancestors_and_options.last ? ancestors_and_options.pop : {}) + chomp = options[:chomp] + access = options[:access] || [] + ancestors = ancestors_and_options.first + + access = [access].flatten + if access.include?(:all) + access.concat([:public, :protected, :private]) + end + access << :public if access.empty? + + writers = [] + + if access.include?(:private) + writers += private_methods(ancestors).select{ |m| /=$/ =~ m.to_s } + end + + if access.include?(:protected) + writers += protected_methods(ancestors).select{ |m| /=$/ =~ m.to_s } + end + + if access.include?(:public) + writers += public_methods(ancestors).select{ |m| /=$/ =~ m.to_s } + end + + if ancestors == Kernel + exclude = nil + elsif ancestors == Object + exclude = Kernel + else + exclude = Object + end + + if exclude + kernel_writers = exclude.instance_methods.select{ |m| /=$/ =~ m.to_s } + writers = writers - kernel_writers + end + + writers = writers.map{ |w| w.to_s.chomp('=') } if chomp + writers.map{ |w| w.to_sym } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/y.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/y.rb new file mode 100644 index 00000000..c9b9aa3d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/y.rb @@ -0,0 +1,23 @@ +module Kernel + + # Y-combinator. + # + # f = Y do |n, acc, &b| + # n < 2 ? acc : b.(n-1, n * acc) + # end + # + # f.call(5, 1) #=> 120 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Michael Fellinger + # + # @uncommon + # require 'facets/kernel/y' + # + def Y(*args, &block) + y = lambda{|*args| block.call(*args, &y) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/kernel/yes.rb b/bin/gems/facets-3.1.0/lib/core/facets/kernel/yes.rb new file mode 100644 index 00000000..b453f985 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/kernel/yes.rb @@ -0,0 +1,25 @@ +require 'facets/kernel/ask' + +module Kernel + + # Ask a question expecting a yes answer. + def yes?(question) + case ask(question).downcase + when 'y', 'yes' + true + else + false + end + end + + # Ask a question expecting a no answer. + def no?(question) + case ask(question).downcase + when 'n', 'no' + true + else + false + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/lazy.rb b/bin/gems/facets-3.1.0/lib/core/facets/lazy.rb new file mode 100644 index 00000000..a761260a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/lazy.rb @@ -0,0 +1,237 @@ +# = Lazy +# +# Everything you need for Lazy evaluation in Ruby. +# +# == Authors +# +# * MenTaLguY +# +# == Copying +# +# Copyright (c) 2005 MenTaLguY +# +# Ruby License +# +# This module is free software. You may use, modify, and/or redistribute this +# software under the same terms as Ruby. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. + +# Everything you need for Lazy evaluation in Ruby. +# +# @author MenTaLguY +module Lazy + + # Raised when a demanded computation diverges (e.g. if it tries to directly + # use its own result) + + class DivergenceError < Exception #:nodoc: + def initialize( message="Computation diverges" ) + super( message ) + end + end + + # Wraps an exception raised by a lazy computation. + # + # The reason we wrap such exceptions in LazyException is that they need to + # be distinguishable from similar exceptions which might normally be raised + # by whatever strict code we happen to be in at the time. + + class LazyException < DivergenceError #:nodoc: + # the original exception + attr_reader :reason + + def initialize( reason ) + @reason = reason + super( "Exception in lazy computation: #{ reason } (#{ reason.class })" ) + set_backtrace( reason.backtrace.dup ) if reason + end + end + + # = Promise + # + # A handle for a promised computation. They are transparent, so that in + # most cases, a promise can be used as a proxy for the computation's result + # object. The one exception is truth testing -- a promise will always look + # true to Ruby, even if the actual result object is nil or false. + # + # If you want to test the result for truth, get the unwrapped result object + # via Kernel.demand. + + class Promise + + alias __class__ class #:nodoc: + instance_methods.each { |m| undef_method m unless m =~ /^(__|object_|instance_)/ } + + def initialize( &computation ) #:nodoc: + @computation = computation + end + def __synchronize__ #:nodoc: + yield + end + + # Create this once here, rather than creating a proc object for every evaluation. + DIVERGES = lambda { raise DivergenceError.new } + + # Differentiate inspection of DIVERGES lambda. + def DIVERGES.inspect + "DIVERGES" + end + + def __result__ #:nodoc: + __synchronize__ do + if @computation + raise LazyException.new( @exception ) if @exception + + computation = @computation + @computation = DIVERGES # trap divergence due to over-eager recursion + + begin + @result = demand( computation.call( self ) ) + @computation = nil + rescue DivergenceError + raise + rescue Exception => exception + # handle exceptions + @exception = exception + raise LazyException.new( @exception ) + end + end + + @result + end + end + + def inspect #:nodoc: + __synchronize__ do + if @computation + "#<#{ __class__ } computation=#{ @computation.inspect }>" + else + @result.inspect + end + end + end + + def respond_to?( message ) #:nodoc: + message = message.to_sym + message == :__result__ or + message == :inspect or + __result__.respond_to? message + end + + def method_missing( *args, &block ) #:nodoc: + __result__.__send__( *args, &block ) + end + end + + # = PromiseSafe + # + # Thread safe version of Promise class. + + class PromiseSafe < Promise + def __synchronize__ #:nodoc: + current = Thread.current + + Thread.critical = true + unless @computation + # fast path for evaluated thunks + Thread.critical = false + yield + else + if @owner == current + Thread.critical = false + raise DivergenceError.new + end + while @owner # spinlock + Thread.critical = false + Thread.pass + Thread.critical = true + end + @owner = current + Thread.critical = false + + begin + yield + ensure + @owner = nil + end + end + end + end + + # = Future + # + # Future class subclasses PromiseSafe. + + class Future < PromiseSafe + def initialize( &computation ) #:nodoc: + result = nil + exception = nil + + thread = Thread.new do + begin + result = computation.call( self ) + rescue Exception => exception + end + end + + super() do + raise DivergenceError.new if Thread.current == thread + thread.join + raise exception if exception + result + end + end + end + +end + + +module Kernel + + # The promise() function is used together with demand() to implement + # lazy evaluation. It returns a promise to evaluate the provided + # block at a future time. Evaluation can be demanded and the block's + # result obtained via the demand() function. + # + # Implicit evaluation is also supported: the first message sent to it will + # demand evaluation, after which that message and any subsequent messages + # will be forwarded to the result object. + # + # As an aid to circular programming, the block will be passed a promise + # for its own result when it is evaluated. Be careful not to force + # that promise during the computation, lest the computation diverge. + # + def promise( &computation ) #:yields: result + Lazy::Promise.new(&computation) + end + + # Forces the result of a promise to be computed (if necessary) and returns + # the bare result object. Once evaluated, the result of the promise will + # be cached. Nested promises will be evaluated together, until the first + # non-promise result. + # + # If called on a value that is not a promise, it will simply return it. + # + def demand( promise ) + if promise.respond_to? :__result__ + promise.__result__ + else # not really a promise + promise + end + end + + # Schedules a computation to be run asynchronously in a background thread + # and returns a promise for its result. An attempt to demand the result of + # the promise will block until the computation finishes. + # + # As with Kernel.promise, this passes the block a promise for its own result. + # Use wisely. + # + def future( &computation ) #:yields: result + Lazy::Future.new(&computation) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/load_path.rb b/bin/gems/facets-3.1.0/lib/core/facets/load_path.rb new file mode 100644 index 00000000..7895f653 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/load_path.rb @@ -0,0 +1 @@ +require_relative 'load_path/search' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/load_path/search.rb b/bin/gems/facets-3.1.0/lib/core/facets/load_path/search.rb new file mode 100644 index 00000000..e2e88d46 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/load_path/search.rb @@ -0,0 +1,16 @@ +class << $LOAD_PATH + + # Search load path for matching patterns. + # + def search(match) + found = [] + uniq.map do |path| + list = Dir.glob(File.join(File.expand_path(path), match)) + list = list.map{ |d| d.chomp('/') } + found.concat(list) + end + found + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/matchdata.rb b/bin/gems/facets-3.1.0/lib/core/facets/matchdata.rb new file mode 100644 index 00000000..6ea71fc7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/matchdata.rb @@ -0,0 +1,3 @@ +require_relative 'matchdata/match.rb' +require_relative 'matchdata/matchset.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/matchdata/match.rb b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/match.rb new file mode 100644 index 00000000..7f626c18 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/match.rb @@ -0,0 +1,15 @@ +class MatchData + + # Return the primary match string. This is equivalent to +md[0]+. + # + # md = /123/.match "123456" + # md.match #=> "123" + # + # CREDIT: Martin DeMello + + def match(index=0) + self[index] + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchset.rb b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchset.rb new file mode 100644 index 00000000..5ae994ef --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchset.rb @@ -0,0 +1,44 @@ +class MatchData + + # Returns [ pre_match, matchtree, post_match ]. (see matchtree) + # + # md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + # md.to_a #=> ["bbccddee", "bb", "ccdd", "dd", "ee"] + # md.matchset #=> ["XXaa", [["bb"], ["cc", ["dd"]], ["ee"]], "ffXX"] + # + # CREDIT: Trans + + def matchset + [pre_match, matchtree, post_match] + end + + # An alternate to #to_a which returns the matches in + # order corresponding with the regular expression. + # + # md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + # md.to_a #=> ["bbccddee", "bb", "ccdd", "dd", "ee"] + # md.matchtree #=> [["bb"], ["cc", ["dd"]], ["ee"]] + # + # CREDIT: Trans + + def matchtree(index=0) + ret=[] + b, e=self.begin(index), self.end(index) + while (index+=1)<=length + if index==length || (bi=self.begin(index))>=e + # we are finished, if something is left, then add it + ret << string[b, e-b] if e>b + break + else + if bi>=b + ret << string[b, bi-b] if bi>b + ret << matchtree(index) + b=self.end(index) + end + end + end + return ret + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchtree.rb b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchtree.rb new file mode 100644 index 00000000..ec428a21 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/matchdata/matchtree.rb @@ -0,0 +1,2 @@ +# Matchdata#matchtree is defined in +require 'facets/matchdata/matchset' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/metaid.rb b/bin/gems/facets-3.1.0/lib/core/facets/metaid.rb new file mode 100644 index 00000000..c864f3ce --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/metaid.rb @@ -0,0 +1,7 @@ +require 'facets/kernel/meta_alias' +require 'facets/kernel/meta_class' +require 'facets/kernel/meta_def' +require 'facets/kernel/meta_eval' + + # in remberence of _why +require 'facets/kernel/eigenclass' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method.rb b/bin/gems/facets-3.1.0/lib/core/facets/method.rb new file mode 100644 index 00000000..7e88d583 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method.rb @@ -0,0 +1,5 @@ +require_relative 'method/composition.rb' +#require_relative 'method/memoize' # uncommon +require_relative 'method/op_mul.rb' +require_relative 'method/op_pow.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/composition.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/composition.rb new file mode 100644 index 00000000..976ba34b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/composition.rb @@ -0,0 +1,96 @@ +class Method + + # TODO: Is it really necessary to have method composition? + # Could we not just convert to Proc and have Proc omposition, + # which doesn't require a special class (albeit #owner and #arity + # and such are not as well supported). + + # Method Composition class acts a proxy for composed methods. + # + # @author Mike Burns + class Composition + + # + def initialize(*f) + @f = f + end + + # + def inspect + x = @f.map{ |f| f.inspect }.join(' * ') + "#" + end + + # + def *(h) + #Composition.new(self, h) + @f << h + end + + # + def ^(n) + raise ArgumentError if n < 0 + + return self if n < 2 + + #Composition.new(self, self ^ (n-1)) + (n - 1).times{ @f = @f.concat(@f) } + end + + # + def owner + @f.last.owner + end + + # + def receiver + @f.first.receiver + end + + # + def arity + @f.last.arity + end + + # + def to_proc + #Proc.new {|x| @f.call(*@g.call(*x)) } + Proc.new { |*x| call(*x) } + end + + # + def call(*x) + r = x + @f.reverse_each do |f| + r = f.call(*r) + end + r + end + + # + def [](*x) + call(*x) + end + + end + + # Method composition. + # + # @author Mike Burns + def *(g) + Composition.new(self, g) + end + + # Method repetition. + # + # @author Mike Burns + def ^(n) + if n < 2 + self + else + #Composition.new(self, self ^ (n-1)) + Composition.new( *([self] * n) ) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/curry.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/curry.rb new file mode 100644 index 00000000..9d3d4d87 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/curry.rb @@ -0,0 +1,13 @@ +require 'facets/proc' + +class Method + # Curry a Method into a new Proc. + + def curry(*args) + to_proc.curry(*args) + end +end + + +# TODO: The question is as to whether to integrate this into Method::Composition, +# or if Composition should be scuttled for just converting to Proc. diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/memoize.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/memoize.rb new file mode 100644 index 00000000..b0c608a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/memoize.rb @@ -0,0 +1,17 @@ +class Method + + # Memoize a method by defining a singleton override. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/method/memoize' + # + def memoize(value) + singleton = (class << receiver; self; end) + singleton.__send__(:define_method, name){ value } + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/op_mul.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/op_mul.rb new file mode 100644 index 00000000..27229f27 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/op_mul.rb @@ -0,0 +1 @@ +require 'facets/method/composition' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/op_pow.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/op_pow.rb new file mode 100644 index 00000000..27229f27 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/op_pow.rb @@ -0,0 +1 @@ +require 'facets/method/composition' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/partial.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/partial.rb new file mode 100644 index 00000000..274008b0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/partial.rb @@ -0,0 +1,10 @@ +require 'facets/proc/partial' + +class Method + # Convert a method into a new partial Proc. + + def partial(*args) + to_proc.partial(*args) + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/method/public.rb b/bin/gems/facets-3.1.0/lib/core/facets/method/public.rb new file mode 100644 index 00000000..131f6437 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/method/public.rb @@ -0,0 +1,33 @@ +class Method + + # + # @return [Boolean] + # Returns true if self encapsulates a public method. + # + # @author Robert Gleeson + # + def public? + receiver.public_methods.include? name + end + + # + # @return [Boolean] + # Returns true if self encapsulates a protected method. + # + # @author Robert Gleeson + # + def protected? + receiver.protected_methods.include? name + end + + # + # @return [Boolean] + # Returns true if self encapsulates a private method. + # + # @author Robert Gleeson + # + def private? + receiver.private_methods.include? name + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module.rb b/bin/gems/facets-3.1.0/lib/core/facets/module.rb new file mode 100644 index 00000000..d60232ff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module.rb @@ -0,0 +1,60 @@ +require_relative 'module/abstract.rb' +require_relative 'module/alias_accessor.rb' +require_relative 'module/alias_method_chain.rb' +require_relative 'module/alias_module_function.rb' +require_relative 'module/all_instance_methods.rb' +require_relative 'module/ancestor.rb' +require_relative 'module/anonymous.rb' +#require_relative 'module/attr_class_accessor.rb' # uncommon +require_relative 'module/attr_setter.rb' +#require_relative 'module/attr_tester.rb' # uncommon +#require_relative 'module/attr_validator.rb' # uncommon +require_relative 'module/basename.rb' +require_relative 'module/can.rb' +#require_relative 'module/cattr.rb' # uncommon +require_relative 'module/class.rb' +#require_relative 'module/class_accessor.rb' # uncommon +require_relative 'module/class_def.rb' +#require_relative 'module/class_extend.rb' # uncommon +#require_relative 'module/class_inheritor.rb' # uncommon +require_relative 'module/class_method_defined.rb' +#require_relative 'module/copy_inheritor.rb' # uncommon +#require_relative 'module/enclosure.rb' # uncommon +#require_relative 'module/enclosures.rb' # uncommon +require_relative 'module/extend.rb' +require_relative 'module/home.rb' +require_relative 'module/homename.rb' +require_relative 'module/housing.rb' +#require_relative 'module/include_as.rb' # uncommon +#require_relative 'module/instance_function.rb' # uncommon +require_relative 'module/include_function_module.rb' +require_relative 'module/instance_method.rb' +require_relative 'module/instance_method_defined.rb' +require_relative 'module/integrate.rb' +require_relative 'module/is.rb' +#require_relative 'module/let.rb' # uncommon +#require_relative 'module/memoize.rb' # uncommon +#require_relative 'module/method_clash.rb' # uncommon +#require_relative 'module/method_space.rb' # uncommon +require_relative 'module/methodize.rb' +require_relative 'module/modname.rb' +require_relative 'module/module_def.rb' +#require_relative 'module/module_load.rb' # uncommon +require_relative 'module/nodef.rb' +require_relative 'module/op.rb' +require_relative 'module/op_add.rb' +require_relative 'module/op_mul.rb' +require_relative 'module/op_sub.rb' +require_relative 'module/pathize.rb' +#require_relative 'module/preextend.rb' # uncommon +require_relative 'module/redefine_method.rb' +require_relative 'module/redirect_method.rb' +require_relative 'module/remove.rb' +require_relative 'module/rename_method.rb' +require_relative 'module/revise.rb' +require_relative 'module/set.rb' +require_relative 'module/singleton_method_defined.rb' +require_relative 'module/spacename.rb' +require_relative 'module/to_obj.rb' +require_relative 'module/wrap_method.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/abstract.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/abstract.rb new file mode 100644 index 00000000..7e316f7e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/abstract.rb @@ -0,0 +1,24 @@ +class Module + + # Create an abstract method. If it is not overridden, it will + # raise a TypeError when called. + # + # class AbstractExample + # abstract :a + # end + # + # c = AbstractExample.new + # + # expect TypeError do + # c.a + # end + # + # CREDIT: Trans + + def abstract(*sym) + sym.each do |s| + define_method(s){ raise TypeError, "undefined abstraction ##{s}" } + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/alias_accessor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_accessor.rb new file mode 100644 index 00000000..cabfeefa --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_accessor.rb @@ -0,0 +1,45 @@ +class Module + + private + + # As with alias_method, but alias both reader and writer. + # + # attr_accessor :x + # self.x = 1 + # alias_accessor :y, :x + # y #=> 1 + # self.y = 2 + # x #=> 2 + # + def alias_accessor(*args) + orig = args.last + args = args - [orig] + args.each do |name| + alias_method(name, orig) + alias_method("#{name}=", "#{orig}=") + end + end + + # As with alias_accessor, but just for the reader. + # This is basically the same as alias_method. + # + def alias_reader(*args) + orig = args.last + args = args - [orig] + args.each do |name| + alias_method(name, orig) + end + end + + # As with alias_method but does the writer instead. + # + def alias_writer(*args) + orig = args.last + args = args - [orig] + args.each do |name| + alias_method("#{name}=", "#{orig}=") + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/alias_class_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_class_method.rb new file mode 100644 index 00000000..9e08f817 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_class_method.rb @@ -0,0 +1,11 @@ +class Module + + # Alias a class method. + # + def alias_class_method(name, target) + class << self + alias_method(name, target) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/alias_method_chain.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_method_chain.rb new file mode 100644 index 00000000..36b0152e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_method_chain.rb @@ -0,0 +1,67 @@ +class Module + + # Encapsulates the common pattern of ... + # + # alias_method :foo_without_feature, :foo + # alias_method :foo, :foo_with_feature + # + # With this, you simply do ... + # + # alias_method_chain :foo, :feature + # + # For example + # + # class AliasMethodChainExample + # def foo + # "foo" + # end + # + # def foo_with_feature + # "foo!" + # end + # + # alias_method_chain :foo, :feature + # end + # + # And both aliases are set up for you. + # + # example = AliasMethodChainExample.new + # example.foo #=> "foo!" + # example.foo_without_feature #=> "foo" + # + # Query and bang methods (foo?, foo!) keep the same punctuation ... + # + # alias_method_chain :foo?, :feature + # + # is equivalent to ... + # + # alias_method :foo_without_feature?, :foo? + # alias_method :foo?, :foo_with_feature? + # + # so you can safely chain foo, foo?, and foo! with the same feature. + # + # CREDIT: Bitsweat, Rails Team + + def alias_method_chain(target, feature) + # Strip out punctuation on predicates or bang methods since + # e.g. target?_without_feature is not a valid method name. + aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 + yield(aliased_target, punctuation) if block_given? + + with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" + + alias_method without_method, target + alias_method target, with_method + + case + when public_method_defined?(without_method) + public target + when protected_method_defined?(without_method) + protected target + when private_method_defined?(without_method) + private target + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/alias_module_function.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_module_function.rb new file mode 100644 index 00000000..6118f7b1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/alias_module_function.rb @@ -0,0 +1,30 @@ +class Module + + private + + # Alias a module function so that the alias is also + # a module function. The typical #alias_method + # does not do this. + # + # module AliasExample + # module_function + # def hello + # "Hello" + # end + # end + # + # AliasExample.hello #=> 'Hello' + # + # module AliasExample + # alias_module_function( :hi , :hello ) + # end + # + # AliasExample.hi #=> 'Hello' + # + def alias_module_function(new, old) + alias_method(new, old) + module_function(new) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/all_instance_methods.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/all_instance_methods.rb new file mode 100644 index 00000000..2ef60263 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/all_instance_methods.rb @@ -0,0 +1,19 @@ +class Module + + # List all instance methods, equivalent to + # + # public_instance_methods + + # protected_instance_methods + + # private_instance_methods + # + # TODO: Better name for #all_instance_methods? + # + # CREDIT: Trans + + def all_instance_methods(include_super=true) + public_instance_methods(include_super) + + protected_instance_methods(include_super) + + private_instance_methods(include_super) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/ancestor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/ancestor.rb new file mode 100644 index 00000000..a8a9efff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/ancestor.rb @@ -0,0 +1,16 @@ +class Module + + # Is a given class or module an ancestor of + # this class or module? + # + # class X ; end + # class Y < X ; end + # + # X.ancestor?(Y) + # + def ancestor?( mod ) + ancestors.include?(mod) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/anonymous.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/anonymous.rb new file mode 100644 index 00000000..13eb1378 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/anonymous.rb @@ -0,0 +1,25 @@ +class Module + + # A module may or may not have a name. + # + # module M; end + # M.name # => "M" + # + # m = Module.new + # m.name # => "" + # + # A module gets a name when it is first assigned to a constant. Either + # via the +module+ or +class+ keyword or by an explicit assignment: + # + # m = Module.new # creates an anonymous module + # M = m # => m gets a name here as a side-effect + # m.name # => "M" + # + def anonymous? + # The name of an anonymous class is an empty + # string in 1.8, and nil in 1.9. + name.nil? || name.empty? + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/attr_class_accessor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_class_accessor.rb new file mode 100644 index 00000000..c3338b6e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_class_accessor.rb @@ -0,0 +1,51 @@ +class Module + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/attr_class_accessor' + # + def attr_class_accessor(name) + attr_class_reader(name) + attr_class_writer(name) + end + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/attr_class_reader' + # + def attr_class_reader(name) + module_eval(<<-EOS, __FILE__, __LINE__) + def self.#{name} + @#{name} + end + def #{name} + self.class.#{name} + end + EOS + end + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/attr_class_writer' + # + def attr_class_writer(name) + module_eval(<<-EOS, __FILE__, __LINE__) + def self.#{name}=(x) + @#{name} = x + end + def #{name}=(x) + self.class.#{name} = x + end + EOS + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/attr_setter.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_setter.rb new file mode 100644 index 00000000..9d517f56 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_setter.rb @@ -0,0 +1,52 @@ +class Module + + # Create an attribute method for both getting + # and setting an instance variable: + # + # attr_setter :a + # + # is equivalent to: + # + # def a(*args) + # if args.size > 0 + # @a = args[0] + # self + # else + # @a + # end + # end + # + # CREDIT: Trans + + def attr_setter(*args) + code, made = '', [] + args.each do |a| + code << %{ + def #{a}(*args) + args.size > 0 ? ( @#{a}=args[0] ; self ) : @#{a} + end + } + made << "#{a}".to_sym + end + module_eval code + made + end + + # Alias an accessor. This create an alias for + # both a reader and a writer. + # + # class AttrSetterExample + # attr_setter :a + # alias_setter :b, :a + # end + # + # x = AttrSetterExample.new + # x.b(1) + # x.a #=> 1 + # + # CREDIT: Trans + + alias_method :alias_setter, :alias_method + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/attr_tester.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_tester.rb new file mode 100644 index 00000000..db658c71 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_tester.rb @@ -0,0 +1,56 @@ +class Module + + # Create an tester attribute. This creates a single method + # used to test the attribute for truth. + # + # attr_tester :a + # + # is equivalent to + # + # def a? + # @a ? true : @a + # end + # + # Note that this method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Trans + # + # @todo This method will probably be deprecated. + # + # @uncommon + # require 'facets/module/attr_tester' + # + def attr_tester(*args) + code, made = '', [] + args.each do |a| + code << %{ + def #{a}?(truth=nil) + @#{a} ? truth || @#{a} : @#{a} + end + } + made << "#{a}?".to_sym + end + module_eval code + made + end + + # Create aliases for flag reader. + # + # Note that this method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Trans + # + # @uncommon + # require 'facets/module/attr_tester' + # + def alias_tester(*args) + orig = args.last + args = args - [orig] + args.each do |name| + alias_method("#{name}?", "#{orig}?") + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/attr_validator.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_validator.rb new file mode 100644 index 00000000..53a6fd3a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/attr_validator.rb @@ -0,0 +1,46 @@ +class Module + + # Like attr_writer, but the writer method validates the + # setting against the given block. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: ? + # + # @uncommon + # require 'facets/module/attr_validator' + # + def attr_validator(*symbols, &validator) + made = [] + symbols.each do |symbol| + define_method "#{symbol}=" do |val| + unless validator.call(val) + raise ArgumentError, "Invalid value provided for #{symbol}" + end + instance_variable_set("@#{symbol}", val) + end + made << "#{symbol}=".to_sym + end + made + end + + # Create aliases for validator attribute methods. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/attr_validator' + # + def alias_validator(*args) + orig = args.last + args = args - [orig] + args.each do |name| + #alias_method(name, orig) + alias_method("#{name}=", "#{orig}=") + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/basename.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/basename.rb new file mode 100644 index 00000000..72af2a94 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/basename.rb @@ -0,0 +1 @@ +require 'facets/module/lastname' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/can.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/can.rb new file mode 100644 index 00000000..163031d9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/can.rb @@ -0,0 +1,20 @@ +class Module + + # An alias for #extend. + # + # module EgCan + # def foo; "foo"; end + # end + # + # class EgCanClass + # can EgCan + # end + # + # EgCanClass.foo #=> 'foo' + # + # BTW, why is Forwardable an -able? It's not a mixin! + + alias_method :can, :extend + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/cattr.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/cattr.rb new file mode 100644 index 00000000..814cfb1c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/cattr.rb @@ -0,0 +1 @@ +require 'facets/module/mattr' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class.rb new file mode 100644 index 00000000..02f6ae77 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class.rb @@ -0,0 +1,12 @@ +class Module + + # Alias for #===. This provides a verbal method + # for inquery. + # + # s = "HELLO" + # String.class?(s) #=> true + # + alias_method :class?, :=== + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class_accessor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class_accessor.rb new file mode 100644 index 00000000..55bc6b49 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class_accessor.rb @@ -0,0 +1,46 @@ +class Module + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/class_accessor' + # + def class_accessor(name) + class_reader(name) + class_writer(name) + end + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/class_reader' + # + def class_reader(name) + module_eval(<<-EOS, __FILE__, __LINE__) + def self.#{name} + @#{name} + end + EOS + end + + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/class_writer' + # + def class_writer(name) + module_eval(<<-EOS, __FILE__, __LINE__) + def self.#{name}=(x) + @#{name} = x + end + EOS + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class_def.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class_def.rb new file mode 100644 index 00000000..2b90e5c1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class_def.rb @@ -0,0 +1,2 @@ +require 'facets/module/module_def' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class_extend.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class_extend.rb new file mode 100644 index 00000000..474bb849 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class_extend.rb @@ -0,0 +1,92 @@ +class Module + + # Normally when including modules, class/module methods are not + # extended. To achieve this behavior requires some clever + # Ruby Karate. Instead #class_extend provides an easy to use + # and clean solution. Simply place the extending class methods + # in a block of the special module method #class_extend. + # + # module Mix + # def inst_meth + # puts 'inst_meth' + # end + # + # class_extend do + # def class_meth + # "Class Method!" + # end + # end + # end + # + # class X + # include Mix + # end + # + # X.class_meth #=> "Class Method!" + # + # NOTE: This old #class_extension version of this method + # did not extend the containing class automatically --it had + # to be done by hand. With #class_extend, that is no longer + # the case. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Daniel Schierbeck, Thomas Sawyer + # + # THANKS: Nobu Nakada, Ulysses + # + # @uncommon + # require 'facets/module/class_extend' + # + def class_extend(*mods, &block) + class_extension = Module.new + + class_extension.__send__(:include, *mods) + class_extension.module_eval(&block) if block_given? + + extend(class_extension) # extend this module too + + append_method = method(:append_features) + + (class << self; self; end).class_eval do + define_method(:append_features) do |mod| + append_method.call(mod) + mod.extend(class_extension) + if mod.instance_of?(Module) + mod.__send__(:class_extend, class_extension) + end + end + end + + class_extensions << class_extension + end + + #private :class_extend + + # + def class_extensions + @class_extensions ||= [] + end + +end + +class Class + + # For Class, Module#class_extend is similar to class_eval. + # + # The alternative is to "undef_method :class_extend", + # but this seems uneccessarily limited. + # + # @uncommon + # require 'facets/module/class_extend' + # + def class_extend(*mods, &block) + class_extension = Module.new + class_extension.__send__(:include, *mods) + class_extension.module_eval(&block) if block + extend(class_extension) + class_extensions << class_extension + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class_inheritor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class_inheritor.rb new file mode 100644 index 00000000..0552bde8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class_inheritor.rb @@ -0,0 +1,80 @@ +require 'facets/module/class_extend' + +class Module + + # = Class Inheritor + # + # Create an dynamic class inheritable attribute. + # + # Inheritor providse a means to store and inherit data via the class + # heirarchy. An inheritor creates two methods one named after the key + # that provides a reader. And one named after key! which provides the + # writer. (Because of the unique nature of inheritor the reader and + # writer can't be the same method.) + # + # The first argument is the inheritor's name. The second argument + # is the archtype object. This object must be duplicable (via #dup). + # The last argument is either the symbolic operator/method or a block + # that specifies how one hierarchical level "integrates" with the next. + # + # class X + # class_inheritor :x, [], :+ + # end + # + # class Y < X + # end + # + # X.x! << :a + # X.x #=> [:a] + # Y.x #=> [:a] + # + # Y.x! << :b + # X.x #=> [:a] + # Y.x #=> [:a, :b] + # + # NOTE: Adding an inheritor directly to Module or Class will probably + # not do what is expected. Thankfully that usecase is likely a YAGNI, + # but in anycase it is even more likely that it is not possible with + # this code. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Thomas Sawyer + # + # @uncommon + # require 'facets/module/class_inheritor' + # + def class_inheritor(key, obj, op=nil, &fop) + raise ArgumentError if op && fop + + if !fop + op = op ? op.to_sym : :+ + fop = lambda{ |o, x| o.__send__(op, x) } + end + + #(class << self; self; end).module_eval do + class_extend do + + define_method(key) do + ancestors.reverse.inject(obj.dup) do |o, a| + if a.respond_to?("#{key}!") + fop.call(o, a.__send__("#{key}!")) + else + o + end + end + end + + define_method("#{key}!") do + if instance_variable_defined?("@#{key}") + instance_variable_get("@#{key}") + else + instance_variable_set("@#{key}", obj.dup) + end + end + + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/class_method_defined.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/class_method_defined.rb new file mode 100644 index 00000000..80bfce93 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/class_method_defined.rb @@ -0,0 +1 @@ +require 'facets/module/instance_method_defined' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/copy_inheritor.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/copy_inheritor.rb new file mode 100644 index 00000000..8bee6959 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/copy_inheritor.rb @@ -0,0 +1,45 @@ +require 'facets/module/class_extend' + +class Module + + # Like #class_inheritor but non-dynamic. The value of the inheritor + # is copied from the ancestor on first read. + # + # c = Class.new do + # def self.x; ['x']; end + # end + # + # d = Class.new(c) do + # copy_inheritor :x + # end + # + # d.x #=> ['x'] + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Thomas Sawyer + # + # @uncommon + # require 'facets/module/copy_inheritor' + # + def copy_inheritor(name, default={}) + class_extend do + define_method(name) do + if instance_variable_defined?("@#{name}") + instance_variable_get("@#{name}") + else + if anc = ancestors[1..-1].find{ |a| a.respond_to?(name) } + value = anc.__send__(name) + value = value.dup rescue value + instance_variable_set("@#{name}", value) + else + instance_variable_set("@#{name}", default) + end + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/enclosure.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/enclosure.rb new file mode 100644 index 00000000..b15533a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/enclosure.rb @@ -0,0 +1,94 @@ +class Module + + # Returns the module which contains this one according to its name. + # + # module ::EncExample + # module M + # module N + # end + # end + # end + # + # EncExample::M::N.enclosure #=> EncExample::M + # + # The enclosure of top-level and anonymous modules is Object. + # + # EncExample.enclosure #=> Object + # Module.new.enclosure #=> Object + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/enclosure' + # + def enclosure + name = /::[^:]+\Z/ =~ self.name ? $` : nil + if name + #base = name.sub!(/^::/, '') ? Object : self + name.split(/::/).inject(self) do |mod, cref| + if /\:(0x.*?)\>$/ =~ cref # TODO: does this ever happen? + #p $1.to_i(16) + ObjectSpace._idref($1.to_i(16)) + else + mod.const_get(cref) + end + end + else + Object + end + end + + # Returns all the namespaces of this module according ordered from + # nearest and moving outwards. The receiver is not contained within + # the result. + # + # module ::EncExample + # module M + # module N + # end + # end + # end + # + # EncExample.enclosures #=> [Object] + # EncExample::M.enclosures #=> [EncExample, Object] + # EncExample::M::N.enclosures #=> [EncExample::M, EncExample, Object] + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/enclosures' + # + def enclosures + n = [] + name.split(/::/).inject(self) do |mod, cref| + c = mod.const_get(cref) ; n.unshift(c) ; c + end + n << Object # ? + n.shift # we really don't need +self+ too. + n + end + + # Enclosure name. + # + # module ::EncExample + # module M + # module N + # end + # end + # end + # + # EncExample::M::N.encname #=> "EncExample::M" + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/enclosure' + # + def encname + /::[^:]+\Z/ =~ self.name ? $` : nil + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/enclosures.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/enclosures.rb new file mode 100644 index 00000000..2d98b085 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/enclosures.rb @@ -0,0 +1 @@ +require 'facets/module/enclosure' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/extend.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/extend.rb new file mode 100644 index 00000000..f6c7d180 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/extend.rb @@ -0,0 +1 @@ +require 'facets/kernel/extend' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/home.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/home.rb new file mode 100644 index 00000000..f63a56c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/home.rb @@ -0,0 +1,90 @@ +class Module + + # Returns the module or class containing the receiver. + # + # module ::HomeExample + # module M + # module N + # end + # end + # end + # + # HomeExample::M::N.home #=> HomeExample::M + # + # The home of a top-level module/class is Object. + # + # HomeExample.home #=> Object + # + # This method is called *home* because techinally a module or class + # is just a constant reference, and as such can reside with multiple + # namespaces, like any variable. For example: + # + # module OtherPlace + # M = ::HomeExample::M + # end + # + # In this example, you might think that +OtherPlace::M+'s home would be + # +OtherPlace+, but +OtherPlace::M+ is the same object as +HomeExample::M+, + # and it can have only one "home" --the original location of it's definition. + def home + #homename = /::[^:]+\Z/ =~ name ? $` : nil + if homename + homename.split(/::/).inject(self) do |mod, cref| + if /\:(0x.*?)\>$/ =~ cref # TODO: does this ever happen? + #p $1.to_i(16) + ObjectSpace._idref($1.to_i(16)) + else + mod.const_get(cref) + end + end + else + Object + end + end + + # Returns the name of module or class containing the receiver. + # + # module ::HomeExample + # module M + # module N + # end + # end + # end + # + # HomeExample::M::N.homename #=> "HomeExample::M" + # + # See also Module#basename. + def homename + /::[^:]+\Z/ =~ name ? $` : nil + end + + # Original name for #homename. + alias_method :modname, :homename + + # Returns all the namespaces of this module according ordered from + # nearest and moving outwards. The receiver is not contained within + # the result. + # + # module ::HouseExample + # module M + # module N + # end + # end + # end + # + # HouseExample.housing #=> [Object] + # HouseExample::M.housing #=> [HouseExample, Object] + # HouseExample::M::N.housing #=> [HouseExample::M, HouseExample, Object] + # + # Compare this to +Module.nesting+. + def housing + n = [] + name.split(/::/).inject(self) do |mod, cref| + c = mod.const_get(cref) ; n.unshift(c) ; c + end + n << Object # ? + n.shift # we really don't need +self+ too. + n + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/homename.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/homename.rb new file mode 100644 index 00000000..ab0d698b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/homename.rb @@ -0,0 +1 @@ +require 'facets/module/home' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/housing.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/housing.rb new file mode 100644 index 00000000..ab0d698b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/housing.rb @@ -0,0 +1 @@ +require 'facets/module/home' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/include_as.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/include_as.rb new file mode 100644 index 00000000..3f616454 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/include_as.rb @@ -0,0 +1 @@ +require 'facets/module/method_space' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/include_function_module.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/include_function_module.rb new file mode 100644 index 00000000..0a01477a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/include_function_module.rb @@ -0,0 +1,25 @@ +class Module + + private + + # Include module and apply module_fuction to the + # included methods. + # + # module Utils + # module_function + # def foo; "foo"; end + # end + # + # module UtilsPlus + # include_function_module Utils + # end + # + # CREDIT: Trans + + def include_function_module *mod + include(*mod) + module_function(*mod.collect{|m| m.private_instance_methods & m.methods(false)}.flatten) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/instance_function.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_function.rb new file mode 100644 index 00000000..4ceb0ff1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_function.rb @@ -0,0 +1,94 @@ +class Module + # Converts module methods into instance methods such that the first parameter + # is passed +self+. This promotes DRY programming when wishing to offer both + # inheritable and module callable procedures. + # + # This method is modeled after +module_function+ which essentially has the the + # opposite effect. Due to implementation limitations, this must use the callback + # #singleton_method_added to emulate +module_function+ when no method names + # are given. + # + # module MyModule + # instance_function + # + # def self.jumble(obj, arg) + # obj + arg + # end + # end + # + # MyModule.jumble("Try", "Me") #=> "TryMe" + # + # s = "Try" + # s.extend MyModule + # s.jumble("Me") #=> "TryMe" + # + # Note: This used to be a module called PromoteSelf and later Instantize, + # before becoming a method. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/instance_function' + # + def instance_function(*meths) + this = self + if meths.empty? + extend InstanceFunction + else + meths.each do |meth| + module_eval do + define_method(meth) do |*args| + this.__send__(meth, self, *args) + end + end + ##class_eval %{ + ## def #{meth}(*args) + ## #{self.name}.#{meth}(self,*args) + ## end + ##} + end + end + end + + module InstanceFunction #:nodoc + # + def singleton_method_added(meth) + this = self + ##module_eval %{ + ## def #{meth}(*args) + ## #{self.name}.#{meth}(self,*args) + ## end + ##} + module_eval do + define_method(meth) do |*args| + this.__send__(meth, self, *args) + end + end + super(meth) + end + end + +end #class Module + + +=begin +module Instantize + + def self.append_features(mod) + mod.extend self + end + + def singleton_method_added( meth ) + d = %{ + def #{meth}(*args) + #{self.name}.#{meth}(self,*args) + end + } + self.class_eval d + super(meth) + end + +end +=end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method.rb new file mode 100644 index 00000000..2073cb12 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method.rb @@ -0,0 +1,25 @@ +$FIRST_CLASS_INSTANCE_METHODS = Hash.new{ |h,k| h[k] = {} } + +# +class Module + + # Access method as a singleton object and retain state. + # + # module ::K + # def hello + # puts "Hello World!" + # end + # end + # + # K.instance_method!(:hello).inspect #=> "#" + # + # NOTE: This is limited to the scope of the current module/class. + + def instance_method!(s) + #( @@__instance_methods__ ||= {} )[s] ||= instance_method(s) # TODO: use class vars for 1.9+ ? + #( @__instance_methods__ ||= {} )[s.to_sym] ||= instance_method(s.to_sym) + $FIRST_CLASS_INSTANCE_METHODS[self][s.to_sym] ||= instance_method(s.to_sym) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method_defined.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method_defined.rb new file mode 100644 index 00000000..a4013802 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/instance_method_defined.rb @@ -0,0 +1,23 @@ +class Module + + # Query whether a public instance method is defined for the module. + # + # CREDIT: Gavin Sinclair, Noah Gibbs + + def instance_method_defined?(meth) + instance_methods(true).find{ |m| m.to_sym == meth.to_sym } + end + + # Query whether a normal (singleton) method is defined for the module. + # + # CREDIT: Gavin Sinclair, Noah Gibbs + + def singleton_method_defined?(meth) + singleton_methods(true).find{ |m| m.to_sym == meth.to_sym } + end + + # + alias_method :module_method_defined?, :singleton_method_defined? + alias_method :class_method_defined?, :singleton_method_defined? + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/integrate.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/integrate.rb new file mode 100644 index 00000000..692b6679 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/integrate.rb @@ -0,0 +1,49 @@ +require 'facets/module/redirect_method' +require 'facets/module/redefine_method' +require 'facets/module/rename_method' +require 'facets/module/wrap_method' +require 'facets/module/nodef' + +class Module + + # Using integrate is just like using include except the + # module included is a reconstruction of the one given + # altered by the commands given in the block. + # + # Convenient commands available are: #rename, #redef, + # #remove, #nodef and #wrap. But any module method + # can be used. + # + # module IntegrateExampleModule + # def q ; "q" ; end + # def y ; "y" ; end + # end + # + # class InegrateExampleClass + # integrate IntegrateExampleModule do + # undef_method :y + # end + # end + # + # x = InegrateExampleClass.new + # x.q #=> "q" + # + # expect NameError do + # x.y + # end + # + # This is like #revisal, but #revisal only + # returns the reconstructred module. It does not + # include it. + # + # CREDIT: Trans + + def integrate(mod, &block) + #include mod.revisal( &blk ) + m = Module.new{ include mod } + m.class_eval(&block) + include m + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/is.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/is.rb new file mode 100644 index 00000000..cb0c3cdf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/is.rb @@ -0,0 +1,57 @@ +class Module + + # Is a given class or module an ancestor of this + # class or module? + # + # class IsX ; end + # class IsY < IsX ; end + # + # IsY.is?(IsX) #=> true + # + # CREDIT: Trans + + def is?(base) + Module===base && ancestors.slice(1..-1).include?(base) + end + + # An alias for #include. + # + # class IsExample + # is Enumerable + # end + # + # CREDIT: Trans + + def is(*mods) + mods.each do |mod| + if mod.const_defined?(:Self) + extend mod::Self + # pass it along if module + if instance_of?(Module) + const_set(:Self, Module.new) unless const_defined?(:Self) + const_get(:Self).send(:include, mod::Self) + end + end + end + include(*mods) + end + + #alias_method :is, :include + + # Expirmental idea for #is. + # + # If the module has #append_feature_function + # defined, this will use that instead of #include ... + # + # def is(*modules) + # module.each do { |m| + # if m.respond_to?(:append_feature_function) + # send(m.append_feature_function,m) + # else + # include m + # end + # end + # end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/lastname.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/lastname.rb new file mode 100644 index 00000000..8037122c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/lastname.rb @@ -0,0 +1,30 @@ +class Module + + # Returns the root name of the module/class. + # + # module ::BaseName + # class Example + # end + # end + # + # BaseName::Example.name #=> "BaseName::Example" + # BaseName::Example.lastname #=> "Example" + # + # Returns nil when module is anonymous. + # + # CREDIT: Trans + + def lastname + if name and not name.empty? + name.gsub(/^.*::/, '') + else + nil #inspect.gsub('#<','').gsub('>','').sub(':', '_') + end + end + + # Original name, but conflicts with File.basename, so is + # mildly deprecated. + alias basename lastname + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/let.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/let.rb new file mode 100644 index 00000000..248fdb62 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/let.rb @@ -0,0 +1,31 @@ +class Module + + # Create a memoized method. This method has been popularized by RSpec. + # + # class LetExample + # let(:seed) { rand } + # end + # + # eg = LetExample.new + # eg.seed == eg.seed + # + # CREDIT: Howard Yeh + # + # @uncommon + # require 'facets/module/let' + # + def let(var,&block) + name = "@#{var}" + self.class_eval do + define_method(var) do + if instance_variable_defined?(name) + instance_variable_get(name) + else + val = self.instance_eval(&block) + instance_variable_set(name,val) + end + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/mattr.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/mattr.rb new file mode 100644 index 00000000..c2f02178 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/mattr.rb @@ -0,0 +1,296 @@ +class Module + + # Creates a class-variable attribute that can + # be accessed both on an instance and class level. + # + # class CARExample + # @@a = 10 + # cattr :a + # end + # + # CARExample.a #=> 10 + # CARExample.new.a #=> 10 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/cattr' + # + def cattr(*syms) + writers, readers = syms.flatten.partition{ |a| a.to_s =~ /=$/ } + writers = writers.map{ |e| e.to_s.chomp('=').to_sym } + ##readers.concat( writers ) # writers also get readers + + cattr_reader(*readers) + cattr_writer(*writers) + + return readers + writers + end + + # Creates a class-variable attr_reader that can + # be accessed both on an instance and class level. + # + # class CARExample + # @@a = 10 + # cattr_reader :a + # end + # + # CARExample.a #=> 10 + # CARExample.new.a #=> 10 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/cattr' + # + def cattr_reader(*syms) + syms.flatten.each do |sym| + module_eval(<<-EOS, __FILE__, __LINE__) + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym} + @@#{sym} + end + + def #{sym} + @@#{sym} + end + EOS + end + return syms + end + + # Creates a class-variable attr_writer that can + # be accessed both on an instance and class level. + # + # class CAWExample + # cattr_writer :a + # def self.a + # @@a + # end + # end + # + # CAWExample.a = 10 + # CAWExample.a #=> 10 + # CAWExample.new.a = 29 + # CAWExample.a #=> 29 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/cattr' + # + def cattr_writer(*syms) + syms.flatten.each do |sym| + module_eval(<<-EOS, __FILE__, __LINE__) + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym}=(obj) + @@#{sym} = obj + end + + def #{sym}=(obj) + @@#{sym}=(obj) + end + EOS + end + return syms + end + + # Creates a class-variable attr_accessor that can + # be accessed both on an instance and class level. + # + # class CAAExample + # cattr_accessor :a + # end + # + # CAAExample.a = 10 + # CAAExample.a #=> 10 + # mc = CAAExample.new + # mc.a #=> 10 + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/cattr' + # + def cattr_accessor(*syms) + cattr_reader(*syms) + cattr_writer(*syms) + end + + # Creates a class-variable attribute that can + # be accessed both on an instance and class level. + # + # c = Class.new do + # mattr :a + # def initialize + # @@a = 10 + # end + # end + # + # c.new.a #=> 10 + # c.a #=> 10 + # + # NOTE: The #mattr methods may not be as useful for modules as the #cattr + # methods are for classes, becuase class-level methods are not "inherited" + # across the metaclass for included modules. + # + # NOTE: This methiod is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/mattr' + # + def mattr(*syms) + writers, readers = syms.flatten.partition{ |a| a.to_s =~ /=$/ } + writers = writers.collect{ |e| e.to_s.chomp('=').to_sym } + ##readers.concat( writers ) # writers also get readers + + mattr_writer( *writers ) + mattr_reader( *readers ) + + return readers + writers + end + + # Creates a class-variable attr_reader that can + # be accessed both on an instance and class level. + # + # c = Class.new do + # @@a = 10 + # mattr_reader :a + # end + # + # c.a #=> 10 + # c.new.a #=> 10 + # + # NOTE: This methiod is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/mattr' + # + def mattr_reader( *syms ) + syms.flatten.each do |sym| + module_eval(<<-EOS, __FILE__, __LINE__) + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym} + @@#{sym} + end + + def #{sym} + @@#{sym} + end + EOS + end + return syms + end + + # Creates a class-variable attr_writer that can + # be accessed both on an instance and class level. + # + # c = Class.new do + # mattr_writer :a + # def self.a + # @@a + # end + # end + # + # c.a = 10 + # c.a #=> 10 + # + # c.new.a = 29 + # c.a #=> 29 + # + # NOTE: This methiod is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/mattr' + # + def mattr_writer(*syms) + syms.flatten.each do |sym| + module_eval(<<-EOS, __FILE__, __LINE__) + unless defined? @@#{sym} + @@#{sym} = nil + end + + def self.#{sym}=(obj) + @@#{sym} = obj + end + + def #{sym}=(obj) + @@#{sym}=(obj) + end + EOS + end + return syms + end + + # Creates a class-variable attr_accessor that can + # be accessed both on an instance and class level. + # + # c = Class.new do + # mattr_accessor :a + # end + # + # c.a = 10 + # c.a #=> 10 + # + # x = c.new + # x.a #=> 10 + # + # NOTE: This methiod is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: David Heinemeier Hansson + # + # @uncommon + # require 'facets/module/mattr' + # + def mattr_accessor(*syms) + mattr_reader(*syms) + mattr_writer(*syms) + end + +end + +# Consider the issue where a module's metaclass is not inherited. +# +# m = Module.new do +# @@a = 10 +# mattr_reader :a +# end +# +# c = Class.new do +# include m +# end +# +# expect NoMethodError do +# c.a +# end +# +# Ideally this would work. diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/memoize.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/memoize.rb new file mode 100644 index 00000000..754c8bf6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/memoize.rb @@ -0,0 +1,16 @@ +require 'facets/memoizable' + +class Module + + # This is here for backward compatibility. + # + # @uncommon + # require 'facets/module/memoize' + # + def memoize(*args) + include Memoizable + Memoizable.instance_method(:memoize).bind(self).call(*args) + #super(*args) # TODO: why is super not working here? + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/method_clash.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/method_clash.rb new file mode 100644 index 00000000..ab11d0e1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/method_clash.rb @@ -0,0 +1,66 @@ +class Module + + # TODO: Should method_clash just be public methods? + + # TODO: Provide an option to select visiblity. + + # Detect method name clash between modules and/or classes, regardless of + # method visibility: + # + # module MethodClashExample + # + # module A + # def c; end + # end + # + # module B + # private + # def c; end + # end + # + # A.method_clash(B) #=> [:c] + # + # end + # + # CREDIT: Thomas Sawyer, Robert Dober + # + # @uncommon + # require 'facets/module/method_clash' + # + def method_clash(other) + common_ancestor = (ancestors & other.ancestors).first + + s = [] + s += public_instance_methods(true) + s += private_instance_methods(true) + s += protected_instance_methods(true) + + o = [] + o += other.public_instance_methods(true) + o += other.private_instance_methods(true) + o += other.protected_instance_methods(true) + + c = s & o + + if common_ancestor + c -= common_ancestor.public_instance_methods(true) + c -= common_ancestor.private_instance_methods(true) + c -= common_ancestor.protected_instance_methods(true) + end + + return c + end + + # Uses #method_clash to return +true+ or +false+ if there + # are method name clashes. + # + # @uncommon + # require 'facets/module/method_clash' + # + def method_clash?(other) + c = method_clash(other) + !c.empty? + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/method_space.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/method_space.rb new file mode 100644 index 00000000..29fb9df8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/method_space.rb @@ -0,0 +1,107 @@ +require 'facets/functor' +require 'facets/module/basename' + +class Module + + # Create method namespaces, allowing for method + # chains but still accessing the object's instance. + # + # class A + # attr_writer :x + # method_space :inside do + # def x; @x; end + # end + # end + # + # a = A.new + # a.x = 10 + # a.inside.x #=> 10 + # + # expect NoMethodError do + # a.x + # end + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Pit Captain + # + # @uncommon + # require 'facets/module/method_space' + # + def method_space(name, mod=nil, &blk) + + ## If block is given then create a module, otherwise + ## get the name of the module. + if block_given? + name = name.to_s + raise ArgumentError if mod + mod = Module.new(&blk) + else + if Module === name + mod = name + name = mod.basename.downcase + end + mod = mod.dup + end + + ## Include the module. This is neccessary, otherwise + ## Ruby won't let us bind the instance methods. + include mod + + ## Save the instance methods of the module and + ## replace them with a "transparent" version. + methods = {} + mod.instance_methods(false).each do |m| + methods[m.to_sym] = mod.instance_method(m) + mod.module_eval %{ + def #{m}(*a,&b) + super(*a,&b) + end + } + ##mod.instance_eval do + ## define_method(m) + ## super + ## end + ##end + end + + ## Add a method for the namespace that delegates + ## via the Functor to the saved instance methods. + define_method(name) do + mtab = methods + Functor.new do |op, *args| + if meth = mtab[op.to_sym] + meth.bind(self).call(*args) + else + #self.__send__(op, *args) + raise NoMethodError, "undefined method `#{m}'" + end + end + end + end + + # Include a module via a specified space. + # + # module T + # def t ; "HERE" ; end + # end + # + # class X + # include_as :test => T + # def t ; test.t ; end + # end + # + # X.new.t #=> "HERE" + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/module/method_space' + # + def include_as(h) + h.each{ |name, mod| method_space(name, mod) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/methodize.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/methodize.rb new file mode 100644 index 00000000..78489662 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/methodize.rb @@ -0,0 +1,20 @@ +require 'facets/string/methodize' + +class Module + + # Translate a module name to a suitable method name. + # + # module ::EgMethodize + # module Eg + # end + # end + # + # EgMethodize.methodize #=> "eg_methodize" + # EgMethodize::Eg.methodize #=> "eg_methodize__eg" + # + def methodize + name.methodize + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/modname.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/modname.rb new file mode 100644 index 00000000..03bc21dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/modname.rb @@ -0,0 +1 @@ +require 'facets/module/homename' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/module_def.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/module_def.rb new file mode 100644 index 00000000..015b89ae --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/module_def.rb @@ -0,0 +1,31 @@ +class Module + + # Defines an instance method within a class/module. + # + # CREDIT: WhyTheLuckyStiff + + def class_def name, &blk + class_eval { define_method name, &blk } + end + + # Defines an instance method within a class/module. + # + # CREDIT: WhyTheLuckyStiff + + def module_def name, &blk + module_eval { define_method name, &blk } + end + + #-- + # TODO: Why are we making these protected, + # and where should these really go in Facets? + #++ + protected :attr + protected :attr_reader + protected :attr_writer + protected :attr_accessor + protected :remove_method + protected :undef_method + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/module_load.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/module_load.rb new file mode 100644 index 00000000..d55666e2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/module_load.rb @@ -0,0 +1,83 @@ +class Module + + # Load file directly into module/class namespace. + # + # Please use this with careful consideration. + # It is best suited to loading plugin-type scripts, + # and should generally not be used as a substitue for + # Ruby's standard load system. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Trans + # + # @uncommon + # require 'facets/module/module_load' + # + def module_load( path ) + if path =~ /^[\/~.]/ + file = File.expand_path(path) + else + $LOAD_PATH.each do |lp| + file = File.join(lp,path) + break if File.exist?(file) + file = nil + end + end + raise LoadError, "no such file to load -- #{path}" unless file + module_eval(File.read(file)) + end + + # Require file into module/class namespace. + # + # Unlike load this keeps a per-module cache and will + # not load the same file into the same module more + # than once despite repeated attempts. + # + # The cache is kept in a global var called +$module_require+. + # + # Please use this with careful consideration. + # It is best suited to loading plugin-type scripts, + # and should generally not be used as a substitue for + # Ruby's standard load system. + # + # NOTE: This method is not a common core extension and is not loaded + # automatically when using require 'facets'. + # + # CREDIT: Trans + # + # @uncommon + # require 'facets/module/module_load' + # + def module_require( path ) + if path =~ /^[\/~.]/ + file = File.expand_path(path) + else + $LOAD_PATH.each do |lp| + file = File.join(lp,path) + break if File.exist?(file) + file += '.rb' + break if File.exist?(file) + file = nil + end + end + raise LoadError, "no such file to load -- #{path}" unless file + # per-module load cache + $module_require ||= {} + $module_require[self] ||= {} + loaded = $module_require[self] + if loaded.key?(file) + false + else + loaded[file] = true + script = File.read(file) + module_eval(script) + true + end + end + + alias_method :class_require, :module_require + alias_method :class_load, :module_load +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/nodef.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/nodef.rb new file mode 100644 index 00000000..0426265d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/nodef.rb @@ -0,0 +1,13 @@ +class Module + + # Alias for undef_method. This has been called "nodef" instead of + # undef to help clarify that it doesn't get rid of the method, but + # rather represses repsonse. + alias_method :nodef, :undef_method + + # Alias for remove_method. This method actually "undefines" a method + # and will raise an error is the method is not defined in receiver. + alias_method :remove, :remove_method + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/op.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/op.rb new file mode 100644 index 00000000..c4bd847a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/op.rb @@ -0,0 +1,107 @@ +class Module + + # Combine modules. + # + # module APlus + # def a; "a"; end + # end + # + # module BPlus + # def b; "b"; end + # end + # + # CPlus = APlus + BPlus + # + # class XPlus; include CPlus; end + # + # XPlus.new.a #=> "a" + # XPlus.new.b #=> "b" + # + # Note that in the old version of traits.rb we cloned + # modules and altered their copies... + # + # def +(other) + # mod1 = other.clone + # mod2 = clone + # mod1.module_eval{ include mod2 } + # end + # + # Later it was realized that this thwarted the main + # benefit that Ruby's concept of modules has over + # traditional traits, inheritance. + # + # CREDIT: Thomas Sawyer, Robert Dober + + def +(other) + base = self + Module.new do + include base + include other + end + end + + # Subtract modules. + # + # module AMinus + # def a; "a"; end + # def b; "b"; end + # end + # + # CMinus = AMinus - [:a] + # + # class XMinus; include CMinus; end + # + # expect NameError do + # XMinus.new.a #=> "a" + # end + # + # XMinus.new.b #=> "b" + # + # TODO: Should this use all instance methods, not just public? + # + # CREDIT: Thomas Sawyer, Robert Dober + + def -(other) + instance_methods = instance_methods(true).map{|m| m.to_sym} + case other + when Array + subtract = instance_methods & other.map{|m| m.to_sym} + when Module + subtract = instance_methods & other.instance_methods(true).map{|m| m.to_sym} # false? + when String, Symbol + subtract = instance_methods & [other.to_sym] + end + base = self + Module.new do + include base + subtract.each{ |x| undef_method x } + end + end + + # Rename methods. + # + # module AStar + # def a; "a"; end + # end + # + # BStar = AStar * { :a => :b } + # + # class XStar; include BStar; end + # + # XStar.new.b #=> "a" + # + # CREDIT: Thomas Sawyer, Robert Dober + + def *(rename_map) + base = self + Module.new do + include base + rename_map.each do |from, to| + alias_method to, from + undef_method from + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/op_add.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/op_add.rb new file mode 100644 index 00000000..85f2a0c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/op_add.rb @@ -0,0 +1 @@ +require 'facets/module/op' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/op_mul.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/op_mul.rb new file mode 100644 index 00000000..85f2a0c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/op_mul.rb @@ -0,0 +1 @@ +require 'facets/module/op' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/op_sub.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/op_sub.rb new file mode 100644 index 00000000..85f2a0c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/op_sub.rb @@ -0,0 +1 @@ +require 'facets/module/op' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/pathize.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/pathize.rb new file mode 100644 index 00000000..7cfb7914 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/pathize.rb @@ -0,0 +1,20 @@ +require 'facets/string/pathize' + +class Module + + # Converts a class name to a unix path. + # + # module ::ExamplePathize + # module Example + # end + # end + # + # ExamplePathize.pathize #=> "example_pathize" + # ExamplePathize::Example.pathize #=> "example_pathize/example" + # + def pathize + name.pathize + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/preextend.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/preextend.rb new file mode 100644 index 00000000..574658a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/preextend.rb @@ -0,0 +1,32 @@ +class Module + + # Prepend an +aspect+ module to a module. + # This only works at the module level. + # + # module ::PreX + # def x; "x"; end + # end + # + # module ::PreU + # def x; '{' + super + '}'; end + # end + # + # PreX.preextend(PreU) + # + # PreX.x # => "{x}" + # + # NOTE: This is not a common core extension and is not loaded + # automatically when using require 'facets'. + # + # CREDIT Trans + # + # @uncommon + # require 'facets/module/preextend' + # + def preextend(aspect) + aspect.__send__(:include, self) + extend aspect + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/redefine_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/redefine_method.rb new file mode 100644 index 00000000..7b6e947d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/redefine_method.rb @@ -0,0 +1,37 @@ +class Module + + private + + # Creates a new method for a pre-existing method. + # + # If _aka_ is given, then the method being redefined will + # first be aliased to this name. + # + # class Greeter + # def hello ; "Hello" ; end + # end + # + # Greeter.new.hello #=> "Hello" + # + # class Greeter + # redefine_method( :hello, :hi ) do + # hi + ", friend!" + # end + # end + # + # Greeter.new.hello #=> "Hello, friend!" + # + # CREDIT: Trans + + def redefine_method(sym, aka=nil, &blk) + alias_method(aka, sym) if aka + ## prevent warning about method overwrite + begin remove_method(sym) rescue NameError end + ## define replacelemt method + define_method(sym, &blk) + end + + # + alias_method :redef, :redefine_method + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/redirect_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/redirect_method.rb new file mode 100644 index 00000000..b7463413 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/redirect_method.rb @@ -0,0 +1,46 @@ +class Module + + private + + # Redirect methods to other methods. This simply + # defines methods by the name of a hash key which + # calls the method with the name of the hash's value. + # + # class RedirectExample + # redirect_method :hi => :hello, :hey => :hello + # def hello(name) + # "Hello, #{name}." + # end + # end + # + # e = RedirectExample.new + # e.hello("Bob") #=> "Hello, Bob." + # e.hi("Bob") #=> "Hello, Bob." + # e.hey("Bob") #=> "Hello, Bob." + # + # The above class definition is equivalent to ... + # + # class RedirectExample + # def hi(*args) + # hello(*args) + # end + # def hey(*args) + # hello(*args) + # end + # def hello + # puts "Hello" + # end + # end + # + # CREDIT: Trans + + def redirect_method( method_hash ) + method_hash.each do |targ,adv| + define_method(targ) { |*args| send(adv,*args) } + end + end + + # + alias_method :redirect, :redirect_method + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/remove.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/remove.rb new file mode 100644 index 00000000..a3e137b9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/remove.rb @@ -0,0 +1 @@ +require 'facets/module/nodef' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/rename_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/rename_method.rb new file mode 100644 index 00000000..0e9df582 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/rename_method.rb @@ -0,0 +1,30 @@ +class Module + + private + + # Aliases a method and undefines the original. + # + # class RenameExample + # def foo; "foo"; end + # rename_method(:bar, :foo) + # end + # + # example = RenameExample.new + # example.bar #=> 'foo' + # + # expect NoMethodError do + # example.foo + # end + # + # CREDIT: Trans + + def rename_method( to_sym, from_sym ) + raise ArgumentError, "method #{from_sym} does not exist" unless method_defined?( from_sym ) + alias_method( to_sym, from_sym ) + undef_method( from_sym ) + end + + alias_method :rename, :rename_method + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/revise.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/revise.rb new file mode 100644 index 00000000..901f3e95 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/revise.rb @@ -0,0 +1,41 @@ +require 'facets/module/redirect_method' +require 'facets/module/redefine_method' +require 'facets/module/rename_method' +require 'facets/module/wrap_method' +require 'facets/module/nodef' + +class Module + + # Return a new module based on another. This includes the original module + # into the new revised module. + # + # module ReviseExample + # def foo; "foo"; end + # end + # + # ReviseExample2 = ReviseExample.revise do + # alias_method :bar, :foo + # end + # + # object = Object.new + # object.extend ReviseExample2 + # object.bar #=> 'foo' + # + # CREDIT: Trans + + def revise(&blk) + base = self + nm = Module.new{ include base } + nm.class_eval(&blk) + nm + end + + alias_method :revisal, :revise +end + +class Class + undef_method :revise + undef_method :revisal +end + + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/set.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/set.rb new file mode 100644 index 00000000..c193ba30 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/set.rb @@ -0,0 +1,36 @@ +class Module + + unless method_defined?(:set) + + # Sets an option to the given value. If the value is a proc, + # the proc will be called every time the option is accessed. + # + # CREDIT: Blake Mizerany (Sinatra) + + def set(option, value=self, &block) + raise ArgumentError if block && value != self + value = block if block + if value.kind_of?(Proc) + if value.arity == 1 + yield self + else + (class << self; self; end).module_eval do + define_method(option, &value) + define_method("#{option}?"){ !!__send__(option) } + define_method("#{option}="){ |val| set(option, Proc.new{val}) } + end + end + elsif value == self + option.each{ |k,v| set(k, v) } + elsif respond_to?("#{option}=") + __send__("#{option}=", value) + else + set(option, Proc.new{value}) + end + self + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/singleton_method_defined.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/singleton_method_defined.rb new file mode 100644 index 00000000..80bfce93 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/singleton_method_defined.rb @@ -0,0 +1 @@ +require 'facets/module/instance_method_defined' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/spacename.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/spacename.rb new file mode 100644 index 00000000..6be8c0a7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/spacename.rb @@ -0,0 +1,25 @@ +class Module + + # Returns the name of module's container module. + # + # module ::SpaceName + # class Example + # end + # end + # + # SpaceName::Example.name #=> "SpaceName::Example" + # SpaceName::Example.spacename #=> "SpaceName" + # + # This used to be called +dirname+. + # + # See also Module#basename. + # + # CREDIT: Trans + + def spacename + name[0...(name.rindex('::') || 0)] + #name.gsub(/::[^:]*$/, '') + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/to_obj.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/to_obj.rb new file mode 100644 index 00000000..c68a83bf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/to_obj.rb @@ -0,0 +1,20 @@ +class Module + + # Create an instance of Object and extend it with +self+. + # + # mod = Module.new do + # def foo; "foo"; end + # end + # + # obj = mod.to_obj + # + # obj.foo #=> "foo" + # + def to_obj + o = Object.new + o.extend self + o + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/module/wrap_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/module/wrap_method.rb new file mode 100644 index 00000000..ef91e9f0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/module/wrap_method.rb @@ -0,0 +1,35 @@ +class Module + + #private # (we'll leave this one public for AOP-like uses). + + # Creates a new method wrapping the previous of the same name. + # Reference to the old method is passed into the new definition + # block as the first parameter. + # + # class WrapExample + # def foo + # "foo" + # end + # + # wrap_method(:foo) do |old_meth, *args| + # old_meth.call + '!' + # end + # end + # + # example = WrapExample.new + # example.foo #=> 'foo!' + # + # Keep in mind that this cannot be used to wrap methods + # that take a block. + # + # CREDIT: Trans + + def wrap_method( sym, &blk ) + old = instance_method(sym) + define_method(sym) { |*args| blk.call(old.bind(self), *args) } + end + + alias_method :wrap, :wrap_method + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/na.rb b/bin/gems/facets-3.1.0/lib/core/facets/na.rb new file mode 100644 index 00000000..7a5fa9a5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/na.rb @@ -0,0 +1,21 @@ +# N/A exception is useful for specifying non-argument defaults when +nil+ +# is a valid value. +# +# def f(x=NA) +# end +# +# NA is also used to represent an argument "slot" for Proc#partial. +# +# NA is an instance of ArgumentError. + +class << NA = ArgumentError.new + def inspect ; 'N/A' ; end + def method_missing(*); self; end +end + +# NA is a subclass of ArgumentError. +#class NA < ArgumentError +# class << self +# def method_missing(*); self; end +# end +#end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/nilclass.rb b/bin/gems/facets-3.1.0/lib/core/facets/nilclass.rb new file mode 100644 index 00000000..437b62a5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/nilclass.rb @@ -0,0 +1,2 @@ +require_relative 'nilclass/ergo.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/nilclass/ergo.rb b/bin/gems/facets-3.1.0/lib/core/facets/nilclass/ergo.rb new file mode 100644 index 00000000..119a2a3c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/nilclass/ergo.rb @@ -0,0 +1 @@ +require 'facets/kernel/ergo' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric.rb new file mode 100644 index 00000000..c5135735 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric.rb @@ -0,0 +1,8 @@ +require_relative 'numeric/approx.rb' +require_relative 'numeric/distance.rb' +require_relative 'numeric/length.rb' +require_relative 'numeric/negative.rb' +require_relative 'numeric/positive.rb' +require_relative 'numeric/round_to.rb' +require_relative 'numeric/spacing.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/approx.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/approx.rb new file mode 100644 index 00000000..76d86ba2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/approx.rb @@ -0,0 +1,39 @@ +class Numeric + + # Determines if another number is approximately equal within a given + # _n_th degree. Defaults to 100ths if the degree is not specified. + # + # Currently defaults to 1/10,000,000 if the degree is not specified. + # But this may change once a "most commonly useful" factor is determined. + # + # This is the same a {#close?} but has a different defualt. + # + # @author Gavin Sinclair + + def approx?(x, n=0.0000001) + close?(x, n) + end + + # Determines if another number is approximately equal + # within a given +epsilon+. + # + # This is the same a {#approx?} but has a different default. + # In this case it is 1/100th. + # + # @author Gavin Sinclair + def close?(number, epsilon=0.01) + return(self == number) if epsilon.zero? + + a, b = self.to_f, number.to_f + if a.zero? or b.zero? + ## There's no scale, so we can only go on difference. + (a - b).abs < epsilon + else + ## We go by ratio. The ratio of two equal numbers is one, so the ratio + ## of two practically-equal floats will be very nearly one. + (a/b - 1).abs < epsilon + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/close.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/close.rb new file mode 100644 index 00000000..0c60efd3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/close.rb @@ -0,0 +1 @@ +require 'facets/numeric/approx' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/delimit.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/delimit.rb new file mode 100644 index 00000000..5b8213ef --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/delimit.rb @@ -0,0 +1,20 @@ +class Numeric + # Returns a string representation of the number e.g. + # 1000.delimit # => "1,000" + # 1000000.delimit # => "1,000,000" + # (1000000.1234).delimit # => "1,000,000.1234" + # + # Can take a hash of options: + # * delimiter - defaults to "," but can be any string + # * separator - defaults to "." but can be any string + # + # 1000.delimit(:delimiter => "_") # => "1_000" + # (1000.00).delimit(:delimiter => ".", :separator => ",") # => "1.000,00" + def delimit(options = {}) + opts = { :delimiter => ',', :separator => '.' }.merge(options) + digits, decimals = self.to_s.split('.') + digits = digits.reverse.chars.each_slice(3).map(&:join).join(opts[:delimiter]).reverse + return digits unless decimals + [digits, decimals].join(opts[:separator]) + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/distance.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/distance.rb new file mode 100644 index 00000000..88aab5d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/distance.rb @@ -0,0 +1,14 @@ +class Numeric + + # Returns the distance between self an another value. + # This is the same as #- but it provides an alternative + # for common naming between variant classes. + # + # 4.distance(3) #=> 1 + # + def distance(other) + self - other + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/length.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/length.rb new file mode 100644 index 00000000..111c6ca1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/length.rb @@ -0,0 +1,10 @@ +class Numeric + + # Returns +self+, useful for polymorphic cases. + # + def length + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/negative.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/negative.rb new file mode 100644 index 00000000..22024d41 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/negative.rb @@ -0,0 +1 @@ +require 'facets/numeric/positive' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/positive.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/positive.rb new file mode 100644 index 00000000..69a991a4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/positive.rb @@ -0,0 +1,15 @@ +class Numeric + + # Is a number greater than zero. + # + def positive? + self > 0 + end + + # Is a number less than zero. + # + def negative? + self < 0 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/range.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/range.rb new file mode 100644 index 00000000..d25faa32 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/range.rb @@ -0,0 +1,12 @@ +class Numeric + + # Create a range from the number plus-or-minus a given value. + # + # Return [Range] + def range(value) + Range.new(self - value, self + value) + end + + alias :plus_or_minus :range + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/round_to.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/round_to.rb new file mode 100644 index 00000000..38070d14 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/round_to.rb @@ -0,0 +1,32 @@ +class Numeric + + # Conceptually, rounding is expected to apply to floating point numbers. + # However it can actually be applied to pretty much any Numeric object. + # For example, one could round an Integer to the nearest kilo. + # + # See Float#round_to. + + def round_to(*args) + to_f.round_to(*args) + end + +end + +class Float + + # Rounds to the nearest _n_th degree. + # + # 4.555.round_to(1) #=> 5.0 + # 4.555.round_to(0.1) #=> 4.6 + # 4.555.round_to(0.01) #=> 4.56 + # 4.555.round_to(0) #=> 4.555 + # + # CREDIT: Trans + + def round_to( n ) #n=1 + return self if n == 0 + (self * (1.0 / n)).round.to_f / (1.0 / n) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/numeric/spacing.rb b/bin/gems/facets-3.1.0/lib/core/facets/numeric/spacing.rb new file mode 100644 index 00000000..1f03c18d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/numeric/spacing.rb @@ -0,0 +1,20 @@ +class Numeric + + # Returns the size of the string representation of + # a numerical value. + # + # 1.spacing #=> 1 + # 10.spacing #=> 2 + # 100.spacing #=> 3 + # -100.spacing #=> 4 + # 1.2.spacing #=> 3 + # + # CREDIT: Victor H. Goff III + + def spacing + to_s.length + end + +end + + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object.rb b/bin/gems/facets-3.1.0/lib/core/facets/object.rb new file mode 100644 index 00000000..ac0f6763 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object.rb @@ -0,0 +1,7 @@ +# TODO: Is there a good reason for these to be here instead of in Kernel module? +require_relative 'object/clone.rb' +require_relative 'object/dup.rb' +require_relative 'object/itself.rb' +require_relative 'object/object_state.rb' +require_relative 'object/try_dup.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object/clone.rb b/bin/gems/facets-3.1.0/lib/core/facets/object/clone.rb new file mode 100644 index 00000000..81c542ff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object/clone.rb @@ -0,0 +1 @@ +require 'facets/object/dup' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object/dup.rb b/bin/gems/facets-3.1.0/lib/core/facets/object/dup.rb new file mode 100644 index 00000000..ad7ae6a6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object/dup.rb @@ -0,0 +1,79 @@ +class Object + # Override this in a child class if it cannot be dup'ed. + # + # obj1 = Object.new + # obj2 = obj1.dup! + # obj2.equal?(obj1) #=> false + # + # CREDIT: Dan Kubb (extlib) + def dup! + dup + end + + # Alternative name for #dup! + def try_dup + dup! + end + + # Can you safely call #dup on this object? + # + # Returns +false+ for +nil+, +false+, +true+, symbols, and numbers; + # +true+ otherwise. + def dup? ; true ; end + def clone? ; true ; end +end + +class NilClass + # Since NilClass is immutable it cannot be duplicated. + # For this reason #try_dup returns +self+. + # + # nil.dup! #=> nil + # + def dup! ; self ; end + def dup? ; false ; end + def clone? ; false ; end +end + +class FalseClass + # Since FalseClass is immutable it cannot be duplicated. + # For this reason #try_dup returns +self+. + # + # false.dup! #=> false + # + def dup! ; self ; end + def dup? ; false ; end + def clone? ; false ; end +end + +class TrueClass + # Since TrueClass is immutable it cannot be duplicated. + # For this reason #try_dup returns +self+. + # + # true.dup! #=> true + # + def dup! ; self ; end + def dup? ; false ; end + def clone? ; false ; end +end + +class Symbol + # Since Symbol is immutable it cannot be duplicated. + # For this reason #try_dup returns +self+. + # + # :a.dup! #=> :a + # + def dup! ; self ; end + def dup? ; false ; end + def clone? ; false ; end +end + +class Numeric + # Since Numeric is immutable it cannot be duplicated. + # For this reason #try_dup returns +self+. + # + # 1.dup! #=> 1 + # + def dup! ; self ; end + def dup? ; false ; end + def clone? ; false ; end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object/itself.rb b/bin/gems/facets-3.1.0/lib/core/facets/object/itself.rb new file mode 100644 index 00000000..ed87b620 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object/itself.rb @@ -0,0 +1,16 @@ +class Object + + # An identity method that provides access to an object's 'self'. + # + # Example + # + # [1,2,3,4,5,1,2,2,3].group_by(&:itself) + # #=> {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]} + # + # CREDIT: Michael Kohl + + def itself + self + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object/object_state.rb b/bin/gems/facets-3.1.0/lib/core/facets/object/object_state.rb new file mode 100644 index 00000000..5ab8ff0b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object/object_state.rb @@ -0,0 +1,77 @@ +class Object + # Get or set state of object. You can think of #object_state as an in-code + # form of marshalling. + # + # class StateExample + # attr_reader :a, :b + # def initialize(a,b) + # @a, @b = a, b + # end + # end + # + # obj = StateExample.new(1,2) + # obj.a #=> 1 + # obj.b #=> 2 + # + # obj.object_state #=> {:a=>1, :b=>2} + # + # obj.object_state(:a=>3, :b=>4) + # obj.a #=> 3 + # obj.b #=> 4 + # + # For most object's this is essentially the same as instance.to_h. + # But for data structures like Array and Hash it returns a snapshot of their + # contents, not the state of their instance variables. + #-- + # TODO: Should this be in module Kernel ? + #++ + def object_state(data=nil) + if data + instance_variables.each do |iv| + name = iv.to_s.sub(/^[@]/, '').to_sym + instance_variable_set(iv, data[name]) + end + else + data = {} + instance_variables.each do |iv| + name = iv.to_s.sub(/^[@]/, '').to_sym + data[name] = instance_variable_get(iv) + end + data + end + end +end + +class Array + # + def object_state(data=nil) + data ? replace(data) : dup + end +end + +class String + # + def object_state(data=nil) + data ? replace(data) : dup + end +end + +class Hash + # + def object_state(data=nil) + data ? replace(data) : dup + end +end + +class Struct + # + def object_state(data=nil) + if data + data.each_pair {|k,v| send(k.to_s + "=", v)} + else + data = {} + each_pair{|k,v| data[k] = v} + data + end + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/object/try_dup.rb b/bin/gems/facets-3.1.0/lib/core/facets/object/try_dup.rb new file mode 100644 index 00000000..81c542ff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/object/try_dup.rb @@ -0,0 +1 @@ +require 'facets/object/dup' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/objectspace.rb b/bin/gems/facets-3.1.0/lib/core/facets/objectspace.rb new file mode 100644 index 00000000..84ae9ab2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/objectspace.rb @@ -0,0 +1,3 @@ +require_relative 'objectspace/classes.rb' +require_relative 'objectspace/op_fetch.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/objectspace/classes.rb b/bin/gems/facets-3.1.0/lib/core/facets/objectspace/classes.rb new file mode 100644 index 00000000..4762f549 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/objectspace/classes.rb @@ -0,0 +1,11 @@ +module ObjectSpace + + # @return All the classes in the object space. + def self.classes + klasses = [] + each_object(Class){|o| klasses << o} + klasses + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/objectspace/op_fetch.rb b/bin/gems/facets-3.1.0/lib/core/facets/objectspace/op_fetch.rb new file mode 100644 index 00000000..68f3a076 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/objectspace/op_fetch.rb @@ -0,0 +1,3 @@ +class << ObjectSpace + alias_method :[], :_id2ref +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc.rb new file mode 100644 index 00000000..40d15d25 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc.rb @@ -0,0 +1,7 @@ +require_relative 'proc/bind.rb' +require_relative 'proc/bind_to.rb' +require_relative 'proc/compose.rb' +require_relative 'proc/partial.rb' +require_relative 'proc/to_method.rb' +require_relative 'proc/update.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/bind.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/bind.rb new file mode 100644 index 00000000..f7fa3a06 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/bind.rb @@ -0,0 +1,24 @@ +require 'facets/kernel/singleton_class' + +class Proc + + # Bind a Proc to an object returning a Method. + # + # NOTE: This version comes from Rails. The old Facets + # version used thread.rb, but I no longer think + # the implementaiton is thread critical. Please + # make a bug report if this proves wrong. + # + def bind(object) + block, time = self, Time.now + method_name = "__bind_#{time.to_i}_#{time.usec}" + object.singleton_class.class_eval do + define_method(method_name, &block) + method = instance_method(method_name) + remove_method(method_name) + method + end.bind(object) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/bind_to.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/bind_to.rb new file mode 100644 index 00000000..69e1a29d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/bind_to.rb @@ -0,0 +1,17 @@ +class Proc + + # Bind a procedure to an object. This works by + # wrapping instance_eval on the Proc object and + # then wrapping this in a new Proc. + # + # a = [1,2,3] + # p1 = Proc.new{ join(' ') } + # p2 = p1.bind_to(a) + # p2.call #=> '1 2 3' + # + def bind_to(object) + Proc.new{object.instance_eval(&self)} + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/compose.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/compose.rb new file mode 100644 index 00000000..d2af2373 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/compose.rb @@ -0,0 +1,42 @@ +class Proc + + # Returns a new proc that is the functional + # composition of two procs, in order. + # + # a = lambda { |x| x + 4 } + # b = lambda { |y| y / 2 } + # + # a.compose(b).call(4) #=> 6 + # b.compose(a).call(4) #=> 4 + # + # CREDIT: Dave + + def compose(g) + raise ArgumentError, "arity count mismatch" unless arity == g.arity + lambda{ |*a| self[ *g[*a] ] } + end + + # Operator for Proc#compose and Integer#times_collect/of. + # + # a = lambda { |x| x + 4 } + # b = lambda { |y| y / 2 } + # + # (a * b).call(4) #=> 6 + # (b * a).call(4) #=> 4 + # + # CREDIT: Dave + + def *(x) + if Integer===x + # collect times + c = [] + x.times{|i| c << call(i)} + c + else + # compose procs + lambda{|*a| self[x[*a]]} + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/partial.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/partial.rb new file mode 100644 index 00000000..b9ba7a23 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/partial.rb @@ -0,0 +1,33 @@ +require 'facets/na' + +class Proc + + # Convert a Proc object into new partial Proc object. + # + # a = proc { |a,b,c| a+b+c } + # b = a.partial(NA,2,NA) + # b[1,3] #=> 6 + # + # Note, the #__ method, which used to be used in stay of NA, + # has been deprecated. + # + #-- + # a = proc { |a,b,c| a+b+c } + # b = a.partial(__,2,__) + # b[1,3] #=> 6 + #++ + # + # This method is similar to Proc#curry. + # + # CREDT Trans + + def partial(*args) + Proc.new do |*spice| + result = args.collect do |a| + NA == a ? spice.pop : a + end + call(*result) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/to_method.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/to_method.rb new file mode 100644 index 00000000..dcdac226 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/to_method.rb @@ -0,0 +1,38 @@ +require 'facets/proc/bind' +require 'facets/kernel/singleton_class' + +class Proc + + # Convert Proc to method. + # + # object = Object.new + # + # function = lambda { |x| x + 1 } + # + # function.to_method(object, 'foo') + # + # object.foo(1) #=> 2 + # + def to_method(object, name=nil) + ##object = object || eval("self", self) + block, time = self, Time.now + method_name = name || "__bind_#{time.to_i}_#{time.usec}" + begin + object.singleton_class.class_eval do + define_method(method_name, &block) + method = instance_method(method_name) + remove_method(method_name) unless name + method + end.bind(object) + rescue TypeError + object.class.class_eval do + define_method(method_name, &block) + method = instance_method(method_name) + remove_method(method_name) unless name + method + end.bind(object) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/update.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/update.rb new file mode 100644 index 00000000..a0eaec81 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/update.rb @@ -0,0 +1,9 @@ +class Proc + + # Use a Proc as an observable. + # + # CREDIT: Tim Pease + + alias_method :update, :call + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/proc/wrap.rb b/bin/gems/facets-3.1.0/lib/core/facets/proc/wrap.rb new file mode 100644 index 00000000..fed8c0d9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/proc/wrap.rb @@ -0,0 +1,17 @@ +class Proc + + # Wrap the argument in a proc. Simply returns the argument if it is + # already a Proc object. + # + # TODO: Would this make more sense as `Kernel#Proc()` method, + # akin to `Integer()` and the like? + # + # Returns [Proc] + # + # Credit: Sean Mackesey + + def self.wrap(arg) + Proc === arg ? arg : Proc.new{ arg } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/process.rb b/bin/gems/facets-3.1.0/lib/core/facets/process.rb new file mode 100644 index 00000000..caa29944 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/process.rb @@ -0,0 +1,2 @@ +require_relative 'process/daemon.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/process/daemon.rb b/bin/gems/facets-3.1.0/lib/core/facets/process/daemon.rb new file mode 100644 index 00000000..a6a0b0c1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/process/daemon.rb @@ -0,0 +1,32 @@ +module Process + + # Turns the current script into a daemon process + # that detaches from the console. It can be shut + # down with a TERM signal. + # + # CREDIT: David Heinemeier Hansson + + def self.daemon(nochdir=nil, noclose=nil) + exit if fork # Parent exits, child continues. + Process.setsid # Become session leader. + exit if fork # Zap session leader. See [1]. + + unless nochdir + Dir.chdir "/" # Release old working directory. + end + + File.umask 0000 # Ensure sensible umask. Adjust as needed. + + unless noclose + STDIN.reopen "/dev/null" # Free file descriptors and + STDOUT.reopen "/dev/null", "a" # point them somewhere sensible. + STDERR.reopen '/dev/null', 'a' + end + + trap("TERM") { exit } + + return 0 + end unless respond_to?(:daemon) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range.rb b/bin/gems/facets-3.1.0/lib/core/facets/range.rb new file mode 100644 index 00000000..fe187b9c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range.rb @@ -0,0 +1,9 @@ +require_relative 'range/combine.rb' +require_relative 'range/overlap.rb' +#require_relative 'range/quantile.rb' # uncommon +#require_relative 'range/op_add.rb' # too new +#require_relative 'range/op_sub.rb' # too new +require_relative 'range/to_rng.rb' +require_relative 'range/umbrella.rb' +require_relative 'range/within.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/combine.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/combine.rb new file mode 100644 index 00000000..bc88bdaa --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/combine.rb @@ -0,0 +1,47 @@ +class Range + + # Combine ranges. + # + # (1..2).combine(2..4) #=> [1..4] + # (1..2).combine(3..4) #=> [1..2, 3..4] + # + # TODO: Incorporate end-sentinal inclusion vs. exclusion. + # + # CREDIT: Trans + + def combine(*intervals) + Range.combine(self, *intervals) + end + + # Combine intervals. + # + # Range.combine(1..2, 2..4) #=> [1..4] + # Range.combine(1..2, 3..4) #=> [1..2, 3..4] + # + # CREDIT: Trans + + def self.combine(*intervals) + intype = intervals.first.class + result = [] + + intervals = intervals.collect do |i| + [i.first, i.last] + end + + intervals.sort.each do |(from, to)| #inject([]) do |result, + if result.empty? or from > result.last[1] + result << [from, to] + elsif to > result.last[1] + result.last[1] = to + end + #result + end + + if intype <= Range + result.collect{ |i| ((i.first)..(i.last)) } + else + result + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/nudge.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/nudge.rb new file mode 100644 index 00000000..a4a95a51 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/nudge.rb @@ -0,0 +1,29 @@ +class Range + + # Nudge range values + # + # (1..5).nudge #=> 2..6 + # (1..5).nudge(2) #=> 3..7 + # (1..5).nudge(-2) #=> -1..3 + # (1..5).nudge(min: 1) #=> 2..5 + # (1..5).nudge(max: 1) #=> 1..6 + # + # CREDIT: Codeindulgence + + def nudge(options_or_number = 1) + if options_or_number.instance_of? Fixnum + {:min => options_or_number, :max => options_or_number} + min = options_or_number + max = options_or_number + else + min = options_or_number[:min].to_i + max = options_or_number[:max].to_i + end + + if exclude_end? + (self.min + min)...((self.max + 1) + max) + else + (self.min + min)..(self.max + max) + end + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/op_add.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/op_add.rb new file mode 100644 index 00000000..791c25eb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/op_add.rb @@ -0,0 +1,15 @@ +require 'facets/array/arrange' + +class Range + + # Add two ranges to create a range array. + # + # Returns [Array] + # + # CREDIT: monocle + + def +(value) + [self, value].arrange + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/op_sub.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/op_sub.rb new file mode 100644 index 00000000..dc561adc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/op_sub.rb @@ -0,0 +1,45 @@ +class Range + + # Subtract one range from another producing a range array. + # + # Examples + # + # (1..10) - (4..6) => [1..3, 7..10] + # + # (1..10) - (9..12) => [1..8] + # + # Returns [Array] + # + # CREDIT: monocle + + def -(value) + if value.class == first.class + minus_obj(value) + else + [minus_obj(value.first)[0], minus_obj(value.last)[1]].compact + end + end + + private + + # TODO: Better name? Maybe make public? + def minus_obj(value) + f = case value <=> first.succ + when -1 then nil + when 0 then first + else + #value < last.succ ? first...value : self + value < last.succ ? first..(value.pred) : self + end + + s = case last <=> value.succ + when -1 then nil + when 0 then last + else + value.succ > first ? (value.succ)..last : self + end + + [f, s] + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/overlap.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/overlap.rb new file mode 100644 index 00000000..9d84a14d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/overlap.rb @@ -0,0 +1,12 @@ +class Range + + # Do two ranges overlap? + # + # CREDIT: Daniel Schierbeck, Brandon Keepers + + def overlap?(other) + include?(other.first) or other.include?(first) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/quantile.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/quantile.rb new file mode 100644 index 00000000..9db8a777 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/quantile.rb @@ -0,0 +1,18 @@ +class Range + + # Calculate the kth n-tile in a range. + # + # If n=4 the quantity is called a quartile, and if n=100 + # it is called a percentile. + # + # @uncommon + # require 'facets/range/quantile' + # + # @return [Integer] the kth n-tile + def quantile(k, n=100) + return 1 if k < first + return n if k >= last + ((k - first) / ((last - first) / n.to_f)).to_i + 1 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/to_rng.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/to_rng.rb new file mode 100644 index 00000000..733ffb7f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/to_rng.rb @@ -0,0 +1,26 @@ +class Range + + # A thing really should know itself. + # This simply returns _self_. + # + # CREDIT: Trans + + def to_rng + self + end + + # A thing really should know itself. + # This simply returns _self_. + # + # Note: This does not internally effect the Ruby + # interpretor such that it can coerce Range-like + # objects into a Range. + # + # CREDIT: Trans + + def to_range + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/umbrella.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/umbrella.rb new file mode 100644 index 00000000..bd8e3a9a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/umbrella.rb @@ -0,0 +1 @@ +require 'facets/range/within' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/range/within.rb b/bin/gems/facets-3.1.0/lib/core/facets/range/within.rb new file mode 100644 index 00000000..12081c49 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/range/within.rb @@ -0,0 +1,64 @@ +class Range + + # Uses the Range#umbrella method to determine + # if another Range is _anywhere_ within this Range. + # + # (1..3).within?(0..4) #=> true + # + # CREDIT: Trans + + def within?(rng) + case rng.umbrella(self) + when [0,0], [-1,0], [0,-1], [-1,-1] + return true + else + return false + end + end + + # Returns a two element array of the relationship + # between two Ranges. + # + # Diagram ... + # + # Relationship Returns + # + # self |-----------| + # r |-----------| [0,0] + # + # self |-----------| + # r |---------| [-1,-1] + # + # self |---------| + # r |-----------| [1,1] + # + # self |-----------| + # r |----------| [-1,0] + # + # self |-----------| + # r |-----------| [-1,1] + # + # etc. + # + # Example: + # + # (0..3).umbrella(1..2) #=> [-1,-1] + # + # CREDIT: Trans, Chris Kappler + + def umbrella(r) + s = first <=> r.first + e = r.last <=> last + + if e == 0 + if r.exclude_end? and exclude_end? + e = r.max <=> max + else + e = (r.exclude_end? ? 0 : 1) <=> (exclude_end? ? 0 : 1) + end + end + + return s,e + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp.rb new file mode 100644 index 00000000..c60b388c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp.rb @@ -0,0 +1,6 @@ +require_relative 'regexp/arity.rb' +require_relative 'regexp/multiline.rb' +require_relative 'regexp/op_add.rb' +require_relative 'regexp/op_or.rb' +require_relative 'regexp/to_re.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/arity.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/arity.rb new file mode 100644 index 00000000..833a079f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/arity.rb @@ -0,0 +1,17 @@ +class Regexp + + # Returns the number of backreferencing subexpressions. + # + # /(a)(b)(c)/.arity #=> 3 + # /(a(b(c)))/.arity #=> 3 + # + # Note that this is not perfect, especially with regards to \x + # and embedded comments. + # + # CREDIT: Trans + + def arity + source.scan( /(?!\\)[(](?!\?[#=:!>-imx])/ ).length + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/multiline.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/multiline.rb new file mode 100644 index 00000000..d3610098 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/multiline.rb @@ -0,0 +1,13 @@ +class Regexp + + # Is a regular expression multiline? + # + # /x/.multiline? #=> false + # /x/m.multiline? #=> true + # + def multiline? + options & MULTILINE == MULTILINE + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_add.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_add.rb new file mode 100644 index 00000000..a0a4d3b2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_add.rb @@ -0,0 +1,18 @@ +class Regexp + + # Add regular expressions. + # + # /a/ + /b/ == /(?-mix:a)(?-mix:b)/ + # + # Functionally equivalent to: + # + # /ab/ + # + # CREDIT: Tyler Rick + def +(other) + other = Regexp.escape(other) if other.is_a?(String) + /#{self}#{other}/ + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_or.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_or.rb new file mode 100644 index 00000000..d45b6f99 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/op_or.rb @@ -0,0 +1,15 @@ +class Regexp + + # Operator form of `Regexp.union`. + # + # /a/ | /b/ #=> /(?-mix:a)|(?-mix:b)/ + # + # If +other+ is not a Regexp it is passed to Regexp.escape. + # + def |(other) + other = Regexp.escape(other) unless Regexp === other + Regexp.union(self, other) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_proc.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_proc.rb new file mode 100644 index 00000000..554f86b6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_proc.rb @@ -0,0 +1,13 @@ +class Regexp + + # Useful to pass a Regexp as a block that will match elements + # + # %w[ joe_the_dog mary_the_cat ].index &/cat/ #=> 1 + # + # Returns [Proc] which passes it's argument to Regexp#match method. + + def to_proc + proc { |x| match(x) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_re.rb b/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_re.rb new file mode 100644 index 00000000..0ae15fa0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/regexp/to_re.rb @@ -0,0 +1,28 @@ +class Regexp + + # Like #to_re, but following Ruby's formal definitions, + # only a Regular expression type object will respond to this. + # + # Note that to be of much real use this should be defined in core Ruby. + # + # CREDIT: Florian Gross + + def to_regexp + self + end + + # Simply returns itself. Helpful when converting + # strings to regular expressions, where regexp + # might occur as well --in the same vien as using + # #to_s on symbols. The parameter is actaully a + # dummy parameter to coincide with String#to_re. + # + # /abc/.to_re #=> /abc/ + # + # CREDIT: Trans + + def to_re(esc=false) + self # Of course, things really should know how to say "I" ;) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/roman.rb b/bin/gems/facets-3.1.0/lib/core/facets/roman.rb new file mode 100644 index 00000000..b35913e5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/roman.rb @@ -0,0 +1,89 @@ +class Integer + + # + ROMAN_MAX = 3999 unless const_defined?(:ROMAN_MAX) + + # + ROMAN_VALUES = [ + ["M", 1000], + ["CM", 900], + ["D", 500], + ["CD", 400], + ["C", 100], + ["XC", 90], + ["L", 50], + ["XL", 40], + ["X", 10], + ["IX", 9], + ["V", 5], + ["IV", 4], + ["I", 1] + ] unless const_defined?(:ROMAN_VALUES) + + # Converts this integer to a roman numeral. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/integer/roman' + # + def roman + int = self + #return nil if integer > ROMAN_MAX + return "-#{(-int).roman}" if int < 0 + return "" if int == 0 + ROMAN_VALUES.each do |(i, v)| + return(i + (int-v).roman) if v <= int + end + end + +end + + +class String + + # Taken from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag. + ROMAN = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i unless const_defined?(:ROMAN) + + ROMAN_VALUES = Integer::ROMAN_VALUES.inject({}) do |h,(r,a)| + h[r] = a; h + end unless const_defined?(:ROMAN_VALUES) + + # Considers string a Roman numeral numeral, + # and converts it to the corresponding integer. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/string/roman' + # + def roman + roman = upcase + raise unless roman? + last = roman[-1,1] + roman.reverse.split('').inject(0) do |result, c| + if ROMAN_VALUES[c] < ROMAN_VALUES[last] + result -= ROMAN_VALUES[c] + else + last = c + result += ROMAN_VALUES[c] + end + end + end + + # Returns true iif the subject is a valid Roman numeral. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/string/roman' + # + def roman? + ROMAN =~ upcase + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string.rb b/bin/gems/facets-3.1.0/lib/core/facets/string.rb new file mode 100644 index 00000000..c5538907 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string.rb @@ -0,0 +1,68 @@ +require_relative 'string/acronym.rb' +require_relative 'string/align.rb' +require_relative 'string/bracket.rb' +require_relative 'string/camelcase.rb' +require_relative 'string/capitalized.rb' +require_relative 'string/characters.rb' +require_relative 'string/cleanlines.rb' +require_relative 'string/cleave.rb' +require_relative 'string/cmp.rb' +require_relative 'string/compress_lines.rb' +#require_relative 'string/crypt.rb' # uncommon +require_relative 'string/divide.rb' +require_relative 'string/each_word.rb' +require_relative 'string/edit_distance.rb' +require_relative 'string/ends_with.rb' +require_relative 'string/exclude.rb' +require_relative 'string/expand_tab.rb' +require_relative 'string/file.rb' +require_relative 'string/fold.rb' +require_relative 'string/indent.rb' +require_relative 'string/index_all.rb' +require_relative 'string/interpolate.rb' +require_relative 'string/lchomp.rb' +require_relative 'string/line_wrap.rb' +require_relative 'string/linear.rb' +require_relative 'string/lowercase.rb' +require_relative 'string/margin.rb' +require_relative 'string/methodize.rb' +require_relative 'string/modulize.rb' +require_relative 'string/mscan.rb' +require_relative 'string/natcmp.rb' +require_relative 'string/nchar.rb' +require_relative 'string/newlines.rb' +require_relative 'string/number.rb' +require_relative 'string/op_div.rb' +require_relative 'string/op_sub.rb' # included in `remove`. +require_relative 'string/outdent.rb' +require_relative 'string/pathize.rb' +require_relative 'string/quote.rb' +require_relative 'string/random.rb' +require_relative 'string/range.rb' +require_relative 'string/range_all.rb' +require_relative 'string/range_of_line.rb' +require_relative 'string/remove.rb' +require_relative 'string/rewrite.rb' +#require_relative 'integer/roman.rb' # uncommon +require_relative 'string/rotate.rb' +require_relative 'string/shatter.rb' +require_relative 'string/similarity.rb' +require_relative 'string/snakecase.rb' +require_relative 'string/splice.rb' +require_relative 'string/squish.rb' +require_relative 'string/starts_with.rb' +require_relative 'string/store.rb' +require_relative 'string/subtract.rb' +require_relative 'string/titlecase.rb' +require_relative 'string/to_re.rb' +require_relative 'string/unbracket.rb' +require_relative 'string/underscore.rb' +require_relative 'string/unfold.rb' +require_relative 'string/unindent.rb' +require_relative 'string/unquote.rb' +require_relative 'string/uppercase.rb' +require_relative 'string/variablize.rb' +require_relative 'string/words.rb' +require_relative 'string/word_wrap.rb' +require_relative 'string/xor.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/acronym.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/acronym.rb new file mode 100644 index 00000000..929738c5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/acronym.rb @@ -0,0 +1,11 @@ +class String + + # Transform a string into an acronym. + # + # CREDIT: Robert Fey + # + def acronym + gsub(/(([a-zA-Z0-9])([a-zA-Z0-9])*)./,"\\2") + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/align.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/align.rb new file mode 100644 index 00000000..e9b2b34f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/align.rb @@ -0,0 +1,125 @@ +class String + + # Alignment method dispatches to #align_right, #align_left + # or #align_center, accorging to the first +direction+ parameter. + # + # s = <<-EOS + # This is a test + # and + # so on + # EOS + # + # s.align(:right, 14) + # + # _produces_ ... + # + # This is a test + # and + # so on + # + # Returns a String aligned right, left or center. + def align(direction, n, sep="\n", c=' ') + case direction + when :right + align_right(n, sep="\n", c=' ') + when :left + align_left(n, sep="\n", c=' ') + when :center + align_center(n, sep="\n", c=' ') + else + raise ArgumentError + end + end + + # Align a string to the right. + # + # The default alignment separation is a new line ("\n"). + # This can be changed as can be the padding string which + # defaults to a single space (' '). + # + # s = <<-EOS + # This is a test + # and + # so on + # EOS + # + # s.align_right(14) + # + # _produces_ ... + # + # This is a test + # and + # so on + # + # CREDIT: Trans + + def align_right(n, sep="\n", c=' ') + return rjust(n.to_i,c.to_s) if sep==nil + q = split(sep.to_s).map do |line| + line.rjust(n.to_i,c.to_s) + end + q.join(sep.to_s) + end + + # Align a string to the left. + # + # The default alignment separation is a new line ("\n"). + # This can be changed as can be the padding string which + # defaults to a single space (' '). + # + # s = <<-EOS + # This is a test + # and + # so on + # EOS + # + # s.align_left(20, "\n", '.') + # + # _produces_ ... + # + # This is a test...... + # and................. + # so on............... + # + # CREDIT: Trans + + def align_left(n, sep="\n", c=' ') + return ljust(n.to_i,c.to_s) if sep==nil + q = split(sep.to_s).map do |line| + line.strip.ljust(n.to_i,c.to_s) + end + q.join(sep.to_s) + end + + # Centers each line of a string. + # + # The default alignment separation is a new line ("\n"). + # This can be changed as can be the padding string which + # defaults to a single space (' '). + # + # s = <<-EOS + # This is a test + # and + # so on + # EOS + # + # s.align_center(14) + # + # _produces_ ... + # + # This is a test + # and + # so on + # + # CREDIT: Trans + + def align_center(n, sep="\n", c=' ') + return center(n.to_i,c.to_s) if sep==nil + q = split(sep.to_s).collect { |line| + line.center(n.to_i,c.to_s) + } + q.join(sep.to_s) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/ascii_only.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/ascii_only.rb new file mode 100644 index 00000000..1edce207 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/ascii_only.rb @@ -0,0 +1,52 @@ +class String + # Get a new string with non-ASCII characters removed. + # + # alt - String to replace non-ASCII characters with. + # Defaults to a blank string (`''`). + # + # Examples + # + # 'abc'.ascii_only #=> 'abc' + # '中文123'.ascii_only #=> '123' + # + # Returns a copy of [String] with ASCII characters only. + # + # CREDIT: Nathan Long + # + # SEE: http://stackoverflow.com/questions/1268289 + def ascii_only(alt='') + encoding_options = { + :invalid => :replace, # Replace invalid byte sequences + :undef => :replace, # Replace anything not defined in ASCII + :replace => alt, # Use a blank for those replacements + :UNIVERSAL_NEWLINE_DECORATOR => true # Always break lines with \n + } + self.encode(Encoding.find('ASCII'), encoding_options) + end + + # Modify string keeping only ASCII characters. + # + # alt - String to replace non-ASCII characters with. + # Defaults to a blank string (`''`). + # + # Examples + # + # 'abc'.ascii_only! #=> 'abc' + # '中文123'.ascii_only! #=> '123' + # + # Returns [String] + # + # CREDIT: Nathan Long + # + # SEE: http://stackoverflow.com/questions/1268289 + def ascii_only!(alt='') + encoding_options = { + :invalid => :replace, # Replace invalid byte sequences + :undef => :replace, # Replace anything not defined in ASCII + :replace => alt, # Use a blank for those replacements + :UNIVERSAL_NEWLINE_DECORATOR => true # Always break lines with \n + } + self.encode!(Encoding.find('ASCII'), encoding_options) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/bracket.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/bracket.rb new file mode 100644 index 00000000..b6214b9d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/bracket.rb @@ -0,0 +1,64 @@ +class String + + BRA2KET = { '['=>']', '('=>')', '{'=>'}', '<'=>'>' } + + # Return a new string embraced by given brackets. + # If only one bracket char is given it will be placed + # on either side. + # + # "wrap me".bracket('{') #=> "{wrap me}" + # "wrap me".bracket('--','!') #=> "--wrap me!" + # + # CREDIT: Trans + + def bracket(bra, ket=nil) + #ket = String.bra2ket[$&] if ! ket && /^[\[({<]$/ =~ bra + ket = BRA2KET[bra] unless ket + "#{bra}#{self}#{ket ? ket : bra}" + end + + # Inplace version of #bracket. + # + # CREDIT: Trans + + def bracket!(bra, ket=nil) + self.replace(bracket(bra, ket)) + end + + # Return a new string with the given brackets removed. + # If only one bracket char is given it will be removed + # from either side. + # + # "{unwrap me}".unbracket('{') #=> "unwrap me" + # "--unwrap me!".unbracket('--','!') #=> "unwrap me" + # + # CREDIT: Trans + + def unbracket(bra=nil, ket=nil) + if bra + ket = BRA2KET[bra] unless ket + ket = ket ? ket : bra + s = self.dup + s.gsub!(%r[^#{Regexp.escape(bra)}], '') + s.gsub!(%r[#{Regexp.escape(ket)}$], '') + return s + else + if m = BRA2KET[ self[0,1] ] + return self.slice(1...-1) if self[-1,1] == m + end + end + return self.dup # if nothing else + end + + # Inplace version of #unbracket. + # + # CREDIT: Trans + + def unbracket!(bra=nil, ket=nil) + self.replace( unbracket(bra, ket) ) + end + + # TODO: rename #bracket to #embrace ? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/briefcase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/briefcase.rb new file mode 100644 index 00000000..0b55a8ae --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/briefcase.rb @@ -0,0 +1 @@ +require 'facets/string/titlecase' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/camelcase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/camelcase.rb new file mode 100644 index 00000000..2db3b93b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/camelcase.rb @@ -0,0 +1,73 @@ +class String + + # Converts a string to camelcase. This method leaves the first character + # as given. This allows other methods to be used first, such as #uppercase + # and #lowercase. + # + # "camel_case".camelcase #=> "camelCase" + # "Camel_case".camelcase #=> "CamelCase" + # + # Custom +separators+ can be used to specify the patterns used to determine + # where capitalization should occur. By default these are underscores (`_`) + # and space characters (`\s`). + # + # "camel/case".camelcase('/') #=> "camelCase" + # + # If the first separator is a symbol, either `:lower` or `:upper`, then + # the first characters of the string will be downcased or upcased respectively. + # + # "camel_case".camelcase(:upper) #=> "CamelCase" + # + # Note that this implementation is different from ActiveSupport's. + # If that is what you are looking for you may want {#modulize}. + # + def camelcase(*separators) + case separators.first + when Symbol, TrueClass, FalseClass, NilClass + first_letter = separators.shift + end + + separators = ['_', '\s'] if separators.empty? + + str = self.dup + + separators.each do |s| + str = str.gsub(/(?:#{s}+)([a-z])/){ $1.upcase } + end + + case first_letter + when :upper, true + str = str.gsub(/(\A|\s)([a-z])/){ $1 + $2.upcase } + when :lower, false + str = str.gsub(/(\A|\s)([A-Z])/){ $1 + $2.downcase } + end + + str + end + + # Same as +#camelcase+ but converts first letter to uppercase. + # + # "camel_case".upper_camelcase #=> "CamelCase" + # "Camel_case".upper_camelcase #=> "CamelCase" + # + # @deprecated + # Use `#camelcase(:upper)` instead. + # + def upper_camelcase(*separators) + camelcase(:upper, *separators) + end + + # Same as +#camelcase+ but converts first letter to lowercase. + # + # "camel_case".lower_camelcase #=> "camelCase" + # "Camel_case".lower_camelcase #=> "camelCase" + # + # @deprecated + # Use `#camelcase(:lower)` instead. + # + def lower_camelcase(*separators) + camelcase(:lower, *separators) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/capitalized.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/capitalized.rb new file mode 100644 index 00000000..091236c2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/capitalized.rb @@ -0,0 +1,49 @@ +class String + + # Return true if the string is capitalized, otherwise false. + # + # "This".capitalized? #=> true + # "THIS".capitalized? #=> false + # "this".capitalized? #=> false + # + # Note Ruby's strange concept of capitalized. See capitalcase + # for the more command conception. + # + # CREDIT: Phil Tomson + + def capitalized? + capitalize == self + end + + # Return true if the string is lowercase (downcase), otherwise false. + # + # "THIS".downcase? #=> false + # "This".downcase? #=> false + # "this".downcase? #=> true + # + # CREDIT: Phil Tomson + + def downcase? + downcase == self + end + + # Alias for #downcase? method. + # alias_method :lowercase?, :downcase? + + # Is the string upcase/uppercase? + # + # "THIS".upcase? #=> true + # "This".upcase? #=> false + # "this".upcase? #=> false + # + # CREDIT: Phil Tomson + + def upcase? + upcase == self + end + + # Alias for #upcase? method. + # alias_method :uppercase?, :upcase? + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/characters.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/characters.rb new file mode 100644 index 00000000..c41ba945 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/characters.rb @@ -0,0 +1,13 @@ +class String + + # Returns an array of characters. + # + # "abc".characters.to_a #=> ["a","b","c"] + # + # TODO: Probably should make this an enumerator. With #scan? + def characters + split(//) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/cleanlines.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/cleanlines.rb new file mode 100644 index 00000000..27002bf2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/cleanlines.rb @@ -0,0 +1,27 @@ +require "facets/enumerator" + +class String + + # Returns an Enumerator for iterating over each + # line of the string, stripped of whitespace on + # either side. + # + # "this\nthat\nother\n".cleanlines.to_a #=> ['this', 'that', 'other'] + # + def cleanlines(&block) + if block + scan(/^.*?$/) do |line| + block.call(line.strip) + end + else + str = self + Enumerator.new do |output| + str.scan(/^.*?$/) do |line| + output.yield(line.strip) + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/cleave.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/cleave.rb new file mode 100644 index 00000000..afd505f3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/cleave.rb @@ -0,0 +1,36 @@ +class String + + # Cleave a string. Break a string in two parts at + # the nearest whitespace. + # + # CREDIT: Trans + + def cleave(threshold=nil, len=nil) + l = (len || size / 2) + t = threshold || size + + h1 = self[0...l] + h2 = self[l..-1] + + i1 = h1.rindex(/\s/) || 0 + d1 = (i1 - l).abs + + d2 = h2.index(/\s/) || l + i2 = d2 + l + + d1 = (i1-l).abs + d2 = (i2-l).abs + + if [d1, d2].min > t + i = t + elsif d1 < d2 + i = i1 + else + i = i2 + end + + #dup.insert(l, "\n").gsub(/^\s+|\s+$/, '') + return self[0..i].to_s.strip, self[i+1..-1].to_s.strip + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/cmp.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/cmp.rb new file mode 100644 index 00000000..5e2fce41 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/cmp.rb @@ -0,0 +1 @@ +require 'facets/comparable/cmp' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/compress_lines.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/compress_lines.rb new file mode 100644 index 00000000..3c5f54e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/compress_lines.rb @@ -0,0 +1,17 @@ +class String + + # Matches any whitespace (including newline) and replaces with a single space + # + # string = <<-QUERY.compress_lines + # SELECT name + # FROM users + # QUERY + # + # string #=> "SELECT name FROM users" + # + def compress_lines(spaced = true) + split($/).map{ |line| line.strip }.join(spaced ? ' ' : '') + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/crypt.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/crypt.rb new file mode 100644 index 00000000..57daabf2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/crypt.rb @@ -0,0 +1,22 @@ +class String + + alias_method :_crypt, :crypt + + # Common Unix cryptography method. + # This adds a default salt to the built-in crypt method. + # + # NOTE: This method is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # @uncommon + # require 'facets/string/crypt' + # + def crypt(salt=nil) + salt ||= ( + (rand(26) + (rand(2) == 0 ? 65 : 97) ).chr + + (rand(26) + (rand(2) == 0 ? 65 : 97) ).chr + ) + _crypt(salt) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/divide.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/divide.rb new file mode 100644 index 00000000..de89d4d2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/divide.rb @@ -0,0 +1,18 @@ +class String + + # Breaks a string up into an array based on a regular expression. + # Similar to scan, but includes the matches. + # + # s = "

Thisisa test.

" + # s.divide( /\<.*?\>/ ) + # #=> ["

This", "is", "a test.", "

"] + # + # CREDIT: Trans + + def divide( re ) + re2 = /#{re}.*?(?=#{re}|\Z)/ + scan(re2) #{re}(?=#{re})/) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/each_match.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/each_match.rb new file mode 100644 index 00000000..4e0174e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/each_match.rb @@ -0,0 +1 @@ +require 'facets/string/mscan' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/each_word.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/each_word.rb new file mode 100644 index 00000000..d4dd7ebc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/each_word.rb @@ -0,0 +1,17 @@ +require 'facets/string/words' + +class String + + # Iterate through each word of a string. + # + # a = [] + # + # "list of words".each_word { |word| a << word } + # + # a #=> ['list', 'of', 'words'] + # + def each_word(&block) + words.each(&block) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/edit_distance.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/edit_distance.rb new file mode 100644 index 00000000..9fb58ad2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/edit_distance.rb @@ -0,0 +1,124 @@ +class String + + # Levenshtein distance algorithm implementation for Ruby, with UTF-8 support. + # + # The Levenshtein distance is a measure of how similar two strings s and t are, + # calculated as the number of deletions/insertions/substitutions needed to + # transform s into t. The greater the distance, the more the strings differ. + # + # The Levenshtein distance is also sometimes referred to as the + # easier-to-pronounce-and-spell 'edit distance'. + # + # Calculate the Levenshtein distance between two strings +self+ and +str2+. + # +self+ and +str2+ should be ASCII, UTF-8, or a one-byte-per character encoding + # such as ISO-8859-*. + # + # The strings will be treated as UTF-8 if $KCODE is set appropriately (i.e. 'u'). + # Otherwise, the comparison will be performed byte-by-byte. There is no specific support + # for Shift-JIS or EUC strings. + # + # When using Unicode text, be aware that this algorithm does not perform normalisation. + # If there is a possibility of different normalised forms being used, normalisation + # should be performed beforehand. + # + # CREDIT: Paul Battley + def edit_distance(str2) + str1 = self + if $KCODE =~ /^U/i + unpack_rule = 'U*' + else + unpack_rule = 'C*' + end + + s = str1.unpack(unpack_rule) + t = str2.unpack(unpack_rule) + + n = s.length + m = t.length + + return m if (0 == n) + return n if (0 == m) + + d = (0..m).to_a + x = nil + + (0...n).each do |i| + e = i+1 + (0...m).each do |j| + cost = (s[i] == t[j]) ? 0 : 1 + x = [ + d[j+1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + d[m] = x + end + + return x + end if RUBY_VERSION < '1.9' + + # Levenshtein distance algorithm implementation for Ruby, with UTF-8 support. + # + # The Levenshtein distance is a measure of how similar two strings s and t are, + # calculated as the number of deletions/insertions/substitutions needed to + # transform s into t. The greater the distance, the more the strings differ. + # + # The Levenshtein distance is also sometimes referred to as the + # easier-to-pronounce-and-spell 'edit distance'. + # + # Calculate the Levenshtein distance between two strings +self+ and +str2+. + # +self+ and +str2+ should be ASCII, UTF-8, or a one-byte-per character encoding + # such as ISO-8859-*. + # + # The strings will be treated as UTF-8 if $KCODE is set appropriately (i.e. 'u'). + # Otherwise, the comparison will be performed byte-by-byte. There is no specific support + # for Shift-JIS or EUC strings. + # + # When using Unicode text, be aware that this algorithm does not perform normalisation. + # If there is a possibility of different normalised forms being used, normalisation + # should be performed beforehand. + # + # CREDIT: Paul Battley + def edit_distance(str2) + str1 = self + + if str2.encoding != str1.encoding + str2 = str2.encode(str1.encoding.name) + end + + s = str1.codepoints.to_a + t = str2.codepoints.to_a + + n = s.length + m = t.length + + return m if (0 == n) + return n if (0 == m) + + d = (0..m).to_a + x = nil + + (0...n).each do |i| + e = i+1 + (0...m).each do |j| + cost = (s[i] == t[j]) ? 0 : 1 + x = [ + d[j+1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + d[m] = x + end + + return x + end if RUBY_VERSION >= '1.9' + +end + + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/ends_with.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/ends_with.rb new file mode 100644 index 00000000..c6deb32b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/ends_with.rb @@ -0,0 +1 @@ +require 'facets/string/starts_with' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/exclude.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/exclude.rb new file mode 100644 index 00000000..dc19adb0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/exclude.rb @@ -0,0 +1,10 @@ +class String + + # The inverse of include?. + # + def exclude?(str) + !include?(str) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/expand_tab.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/expand_tab.rb new file mode 100644 index 00000000..14225b5c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/expand_tab.rb @@ -0,0 +1,35 @@ +class String + + # Expands tabs to +n+ spaces. Non-destructive. If +n+ is 0, + # then tabs are simply removed. Raises an exception if +n+ + # is negative. + # + # "\t\tHey".expand_tabs(2) #=> " Hey" + # + # Thanks to GGaramuno for a more efficient algorithm. Very nice. + # + # CREDIT: Gavin Sinclair, Noah Gibbs, GGaramuno + # + # TODO: Don't much care for the name String#expand_tabs. + # What about a more concise name like #detab? + + def expand_tabs(n=8) + n = n.to_int + raise ArgumentError, "n must be >= 0" if n < 0 + return gsub(/\t/, "") if n == 0 + return gsub(/\t/, " ") if n == 1 + str = self.dup + while + str.gsub!(/^([^\t\n]*)(\t+)/) { |f| + val = ( n * $2.size - ($1.size % n) ) + $1 << (' ' * val) + } + end + str + end + + # Singular form of #expand_tabs. + alias_method :expand_tab, :expand_tabs + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/file.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/file.rb new file mode 100644 index 00000000..b3cb2e1f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/file.rb @@ -0,0 +1,21 @@ +require 'facets/functor' + +class String + + # TODO: Should String#file be moved to functor gem?" + + # Use fluent notation for making file directives. + # + # For instance, if we had a file 'foo.txt', + # + # 'foo.txt'.file.mtime + # + def file + f = self + Functor.new do |op, *a, &b| + File.send(op, f, *a, &b) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/fold.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/fold.rb new file mode 100644 index 00000000..85f08bb2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/fold.rb @@ -0,0 +1,39 @@ +class String + + # Returns a new string with all new lines removed from + # adjacent lines of text. + # + # s = "This is\na test.\n\nIt clumps\nlines of text." + # s.fold + # + # _produces_ + # + # "This is a test.\n\nIt clumps lines of text. " + # + # TODO: One arguable flaw with this that might need a fix: + # if the given string ends in a newline, it is replaced with + # a single space. + # + # CREDIT: Trans + + def fold(ignore_indented=false) + ns = '' + i = 0 + self.scan(/(\n\s*\n|\Z)/m) do |m| + b = $~.begin(1) + e = $~.end(1) + nl = $& + tx = slice(i...b) + if ignore_indented and slice(i...b) =~ /^[ ]+/ + ns << tx + else + ns << tx.gsub(/[ ]*\n+/,' ') + end + ns << nl + i = e + end + ns + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/indent.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/indent.rb new file mode 100644 index 00000000..187eb17f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/indent.rb @@ -0,0 +1,76 @@ +class String + + # Indent left or right by `n` spaces, or `n` number of `c` string. + # + # n - The number of spaces to indent. [Integer] + # c - Character to use, if other then space. [String] + # + # Returns a new string with the indention. [String] + # + # Credit: Gavin Sinclair + # Credit: Trans + # Credit: Tyler Rick + + def indent(n, c=' ') + if n >= 0 + gsub(/^/, c * n) + else + gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "") + end + end + + # Equivalent to String#indent, but modifies the receiver in place. + # + # n - The number of spaces to indent. [Integer] + # c - Character to use, if other then space. [String] + # + # Returns this string with the indention. [String] + + def indent!(n, c=' ') + replace(indent(n,c)) + end + + # Remove excessive indentation. Useful for multi-line strings + # embeded in already indented code. + # + # size - The number of spaces to indent. [Integer] + # + # Examples + # + # <<-END.unindent + # ohaie + # wurld + # END + # #=> "ohaie\n wurld" + # + # Returns a new unindented string. [String] + # + # Credit: Noah Gibbs + # Credit: mynyml + + def unindent(size=nil) + if size + indent(-size) + else + char = ' ' + self.scan(/^[\ \t]*\S/) do |m| + if size.nil? || m.size < size + size = m.size + char = m[0...-1] + end + end + size -= 1 + indent(-size, char) + end + end + + # Equivalent to String#unindent, but modifies the receiver in place. + # + # Returns this string unindented. [String] + # + # Credit: mynyml + + def unindent! + replace(unindent) + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/index_all.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/index_all.rb new file mode 100644 index 00000000..a4823b74 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/index_all.rb @@ -0,0 +1,24 @@ +class String + + # Like index but returns an array of all index locations. + # The reuse flag allows the trailing portion of a match to be + # reused for subsquent matches. + # + # "abcabcabc".index_all('a') #=> [0,3,6] + # + # "bbb".index_all('bb', false) #=> [0] + # "bbb".index_all('bb', true) #=> [0,1] + # + # TODO: Culd probably be defined for Indexable in general too. + + def index_all(s, reuse=false) + s = Regexp.new(Regexp.escape(s)) unless Regexp===s + ia = []; i = 0 + while (i = index(s,i)) + ia << i + i += (reuse ? 1 : $~[0].size) + end + ia + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/indexable.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/indexable.rb new file mode 100644 index 00000000..60f9d409 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/indexable.rb @@ -0,0 +1,7 @@ +require 'facets/indexable' +require 'facets/string/splice' + +class String + include Indexable +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/interpolate.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/interpolate.rb new file mode 100644 index 00000000..06112869 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/interpolate.rb @@ -0,0 +1,23 @@ +class String + + # Interpolate provides a means of externally using Ruby string + # interpolation mechinism. + # + # try = "hello" + # str = "\#{try}!!!" + # String.interpolate{ str } #=> "hello!!!" + # + # Note this uses #eval under the hood. We do not recommend that + # it serve in place of a good templating system. But, it can be + # useful for simple cases. + # + # The block is neccessary in order to get then binding of the caller. + # + # CREDIT: Trans + + def self.interpolate(&str) + eval "%{#{str.call}}", str.binding + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/lchomp.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/lchomp.rb new file mode 100644 index 00000000..7d578c84 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/lchomp.rb @@ -0,0 +1,33 @@ +class String + + # Left chomp. + # + # "help".lchomp("h") #=> "elp" + # "help".lchomp("k") #=> "help" + # + # CREDIT: Trans + + def lchomp(match) + if index(match) == 0 + self[match.size..-1] + else + self.dup + end + end + + # In-place left chomp. + # + # "help".lchomp("h") #=> "elp" + # "help".lchomp("k") #=> "help" + # + # CREDIT: Trans + + def lchomp!(match) + if index(match) == 0 + self[0...match.size] = '' + self + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/line_wrap.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/line_wrap.rb new file mode 100644 index 00000000..2ed6e8dc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/line_wrap.rb @@ -0,0 +1,18 @@ +class String + + # Line wrap at width. + # + # s = "1234567890".line_wrap(5) + # + # s #=> "12345\n67890\n" + # + # CREDIT: Trans + + def line_wrap(width, tabs=4) + s = gsub(/\t/,' ' * tabs) # tabs default to 4 spaces + s = s.gsub(/\n/,' ') + r = s.scan( /.{1,#{width}}/ ) + r.join("\n") << "\n" + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/linear.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/linear.rb new file mode 100644 index 00000000..d03e33a1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/linear.rb @@ -0,0 +1,19 @@ +require 'facets/functor' + +class String + + # TODO: Should String#linear be moved to separate functor gem? + + # Like `#newlines` but returns a Functor instead. + # + # "a \n b \n c".linear.strip #=> "a\nb\nc" + # + def linear + Functor.new do |op, *a, &b| + lines.map { |line| + line.chomp.public_send(op, *a, &b) + }.join("\n") + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/lowercase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/lowercase.rb new file mode 100644 index 00000000..9f3ba16c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/lowercase.rb @@ -0,0 +1 @@ +require 'facets/string/uppercase' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/margin.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/margin.rb new file mode 100644 index 00000000..56b1bc17 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/margin.rb @@ -0,0 +1,55 @@ +require 'facets/string/indent' + +class String + + # Preserve relative tabbing such that the line with the least amount + # of white space ends up with the given number of spaces before non-space + # and all other lines move relative to it. + # + # Because of the nature of this method, leading tab characters (`\t`) must + # be converted to spaces. The size of a tab can be set via the `:tab` option. + # The default size is 2. + # + # If the `:lead` option is set, then the relative margin is determined + # by the first non-blank line, instead of the minimum white-space for all + # lines. + # + # Arguments + # + # num - The size of the desired margin. [Integer] + # opts - Margin options. [Hash] + # + # Options + # + # :tab - Size of tab character in spaces. [Integer] + # :lead - Use first non-blank line as relative marker. [Boolean] + # + # Returns a new String with adjusted margin. [String] + # + # Author: Gavin Sinclair + # Author: Trans + + def margin(num=nil, opts={}) + # TODO: temporary to help people transition + raise ArgumentError, "String#margin has been renamed to #trim." unless num + + tab = opts[:tab] || 2 + str = gsub("\t", " " * tab) # TODO: only leading tabs ? + + if opts[:lead] + if self =~ /^( *)\S/ + indent(num - $1.length) + else + self + end + else + min = [] + str.each_line do |line| + next if line.strip.empty? + min << line.index(/\S/) + end + min = min.min + str.indent(num - min) + end + end +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/methodize.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/methodize.rb new file mode 100644 index 00000000..8e714b04 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/methodize.rb @@ -0,0 +1,26 @@ +class String + + # Translate a class or module name to a suitable method name. + # + # "My::CoolClass".methodize #=> "my__cool_class" + # + def methodize + gsub(/([A-Z]+)([A-Z])/,'\1_\2'). + gsub(/([a-z])([A-Z])/,'\1_\2'). + gsub('/' ,'__'). + gsub('::','__'). + downcase + end + + # Compare to ActiveSupport's definition: + # + # gsub(/\//, '__'). + # gsub(/::/, '__'). + # gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + # gsub(/([a-z\d])([A-Z])/,'\1_\2'). + # tr("-", "_"). + # downcase + # + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/modulize.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/modulize.rb new file mode 100644 index 00000000..3bd8f072 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/modulize.rb @@ -0,0 +1,31 @@ +class String + + # Converts a string to module name representation. + # + # This is essentially #camelcase, but it also converts + # '/' to '::' which is useful for converting paths to + # namespaces. + # + # Examples + # + # "method_name".modulize #=> "MethodName" + # "method/name".modulize #=> "Method::Name" + # + def modulize + #gsub('__','/'). # why was this ever here? + gsub(/__(.?)/){ "::#{$1.upcase}" }. + gsub(/\/(.?)/){ "::#{$1.upcase}" }. + gsub(/(?:_+|-+)([a-z])/){ $1.upcase }. + gsub(/(\A|\s)([a-z])/){ $1 + $2.upcase } + end + + # Compare to ActiveSupport's definition: + # + # gsub(/__(.?)/){ "::#{$1.upcase}" }. + # gsub(/\/(.?)/){ "::#{$1.upcase}" }. + # gsub(/(?:_+)([a-z])/){ $1.upcase }. + # gsub(/(^|\s+)([a-z])/){ $1 + $2.upcase } + # + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/mscan.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/mscan.rb new file mode 100644 index 00000000..9ea814d1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/mscan.rb @@ -0,0 +1,22 @@ +class String + + # Like #scan but returns MatchData ($~) rather + # then matched string ($&). + # + # CREDIT: Trans + + def mscan(re) #:yield: + if block_given? + scan(re) { yield($~) } + else + m = [] + scan(re) { m << $~ } + m + end + end + + # Alias for #mscan. + alias each_match mscan + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/natcmp.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/natcmp.rb new file mode 100644 index 00000000..fd8daddf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/natcmp.rb @@ -0,0 +1,88 @@ +#-- +# Adapted from: +# +# * http://sourcefrog.net/projects/natsort/natcmp.rb +# +# Based on Martin Pool's "Natural Order String Comparison" originally +# written in C. (see http://sourcefrog.net/projects/natsort/) +# +# This implementation is Copyright (C) 2003 by Alan Davies +# +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. +#++ + +# +class String + + # 'Natural order' comparison of strings, e.g. ... + # + # "my_prog_v1.1.0" < "my_prog_v1.2.0" < "my_prog_v1.10.0" + # + # which does not follow alphabetically. A secondary + # parameter, if set to _true_, makes the comparison + # case insensitive. + # + # "Hello.1".natcmp("Hello.10") #=> -1 + # + # TODO: Invert case flag? + # + # @author Alan Davies + # @author Martin Pool + + def natcmp(str2, caseInsensitive=false) + str1 = self.dup + str2 = str2.dup + compareExpression = /^(\D*)(\d*)(.*)$/ + + if caseInsensitive + str1.downcase! + str2.downcase! + end + + # -- remove all whitespace + str1.gsub!(/\s*/, '') + str2.gsub!(/\s*/, '') + + while (str1.length > 0) or (str2.length > 0) do + # -- extract non-digits, digits and rest of string + str1 =~ compareExpression + chars1, num1, str1 = $1.dup, $2.dup, $3.dup + str2 =~ compareExpression + chars2, num2, str2 = $1.dup, $2.dup, $3.dup + # -- compare the non-digits + case (chars1 <=> chars2) + when 0 # Non-digits are the same, compare the digits... + # If either number begins with a zero, then compare alphabetically, + # otherwise compare numerically + if (num1[0] != 48) and (num2[0] != 48) + num1, num2 = num1.to_i, num2.to_i + end + case (num1 <=> num2) + when -1 then return -1 + when 1 then return 1 + end + when -1 then return -1 + when 1 then return 1 + end # case + end # while + + # -- strings are naturally equal + return 0 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/nchar.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/nchar.rb new file mode 100644 index 00000000..02cb0ff2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/nchar.rb @@ -0,0 +1,32 @@ +class String + + # Returns _n_ characters of the string. If _n_ is positive + # the characters are from the beginning of the string. + # If _n_ is negative from the end of the string. + # + # str = "this is text" + # + # str.nchar(4) #=> "this" + # str.nchar(-4) #=> "text" + # + # Alternatively a replacement string can be given, which will + # replace the _n_ characters. + # + # str.nchar(4, 'that') #=> "that is text" + # + # The original string remains unaffected. + # + # str #=> "this is text" + # + def nchar(n, replacement=nil) + if replacement + s = self.dup + n > 0 ? (s[0...n] = replacement) : (s[n..-1] = replacement) + s + else + n > 0 ? self[0...n] : self[n..-1] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/newlines.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/newlines.rb new file mode 100644 index 00000000..2949f543 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/newlines.rb @@ -0,0 +1,32 @@ +require "facets/enumerator" + +class String + + # Returns an Enumerator for iterating over each + # line of the string, void of the termining newline + # character, in contrast to #lines which retains it. + # + # "a\nb\nc".newlines.class.assert == Enumerator + # "a\nb\nc".newlines.to_a.assert == %w{a b c} + # + # a = [] + # "a\nb\nc".newlines{|nl| a << nl} + # a.assert == %w{a b c} + # + def newlines(&block) + if block + scan(/^.*?$/) do |line| + block.call(line.chomp) + end + else + str = self + Enumerator.new do |output| + str.scan(/^.*?$/) do |line| + output.yield(line.chomp) + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/number.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/number.rb new file mode 100644 index 00000000..2942cee2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/number.rb @@ -0,0 +1,14 @@ +class String + + # Returns true if it's a decimal digits. + # + # "123_456_789_123_456_789.123_456_000_111".number? # => true + # "1.23".number? # => true + # "1.23a".number? # => false + # + # CREDIT: u2 + + def number? + !!self.match(/\A[+-]?\d+?(_?\d+?)*?(\.\d+(_?\d+?)*?)?\Z/) + end +end \ No newline at end of file diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/op_div.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/op_div.rb new file mode 100644 index 00000000..6bfe1467 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/op_div.rb @@ -0,0 +1,14 @@ +class String + + # Treats +self+ and +path+ as representations + # of pathnames, joining thme together as a + # single path. + # + # ('home' / 'trans') #=> 'home/trans' + # + def /(path) + File.join(self, path.to_s) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/op_sub.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/op_sub.rb new file mode 100644 index 00000000..a1391f5a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/op_sub.rb @@ -0,0 +1 @@ +require_relative 'remove' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/outdent.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/outdent.rb new file mode 100644 index 00000000..c09c4bdc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/outdent.rb @@ -0,0 +1 @@ +require 'facets/string/indent' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/pathize.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/pathize.rb new file mode 100644 index 00000000..3c54e46e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/pathize.rb @@ -0,0 +1,32 @@ +class String + + # Transforms a namespace, i.e. a class or module name, into a viable + # file path. + # + # "ExamplePathize".pathize #=> "example_pathize" + # "ExamplePathize::Example".pathize #=> "example_pathize/example" + # + # Compare this method to {String#modulize) and {String#methodize). + # + def pathize + gsub(/([A-Z]+)([A-Z])/,'\1_\2'). + gsub(/([a-z])([A-Z])/,'\1_\2'). + gsub('__','/'). + gsub('::','/'). + gsub(/\s+/, ''). # spaces are bad form + gsub(/[?%*:|"<>.]+/, ''). # reserved characters + downcase + end + + # Compare to Rails definition: + # + # gsub(/__/, '/'). + # gsub(/::/, '/'). + # gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + # gsub(/([a-z\d])([A-Z])/,'\1_\2'). + # tr("-", "_"). + # downcase + # + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/quote.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/quote.rb new file mode 100644 index 00000000..a8fff231 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/quote.rb @@ -0,0 +1,93 @@ +class String + + # Return a new string embraced by given +type+ and +count+ + # of quotes. The arguments can be given in any order. + # + # If no type is given, double quotes are assumed. + # + # "quote me".quote #=> '"quote me"' + # + # If no type but a count is given then :mixed is assumed. + # + # "quote me".quote(1) #=> %q{'quote me'} + # "quote me".quote(2) #=> %q{"quote me"} + # "quote me".quote(3) #=> %q{'"quote me"'} + # + # Symbols can be used to describe the type. + # + # "quote me".quote(:single) #=> %q{'quote me'} + # "quote me".quote(:double) #=> %q{"quote me"} + # "quote me".quote(:back) #=> %q{`quote me`} + # "quote me".quote(:bracket) #=> %q{`quote me'} + # + # Or the character itself. + # + # "quote me".quote("'") #=> %q{'quote me'} + # "quote me".quote('"') #=> %q{"quote me"} + # "quote me".quote("`") #=> %q{`quote me`} + # "quote me".quote("`'") #=> %q{`quote me'} + # + # CREDIT: Trans + + def quote(type=:double, count=nil) + if Integer === type + tmp = count + count = type + type = tmp || :mixed + else + count ||= 1 + end + + type = type.to_s unless Integer===type + + case type + when "'", 'single', 's', 1 + f = "'" * count + b = f + when '"', 'double', 'd', 2 + f = '"' * count + b = f + when '`', 'back', 'b', -1 + f = '`' * count + b = f + when "`'", 'bracket', 'sb' + f = "`" * count + b = "'" * count + when "'\"", 'mixed', "m", Integer + c = (count.to_f / 2).to_i + f = '"' * c + b = f + if count % 2 != 0 + f = "'" + f + b = b + "'" + end + else + raise ArgumentError, "unrecognized quote type -- #{type}" + end + "#{f}#{self}#{b}" + end + + # Remove quotes from string. + # + # "'hi'".unquote #=> "hi" + # + # CREDIT: Trans + + def unquote + s = self.dup + + case self[0,1] + when "'", '"', '`' + s[0] = '' + end + + case self[-1,1] + when "'", '"', '`' + s[-1] = '' + end + + return s + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/random.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/random.rb new file mode 100644 index 00000000..a3b98726 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/random.rb @@ -0,0 +1,44 @@ +class String + + # Create a random String of given length, using given character set + # + # Character set is an Array which can contain Ranges, Arrays, Characters + # + # Examples + # + # String.random + # => "D9DxFIaqR3dr8Ct1AfmFxHxqGsmA4Oz3" + # + # String.random(10) + # => "t8BIna341S" + # + # String.random(10, ['a'..'z']) + # => "nstpvixfri" + # + # String.random(10, ['0'..'9'] ) + # => "0982541042" + # + # String.random(10, ['0'..'9','A'..'F'] ) + # => "3EBF48AD3D" + # + # BASE64_CHAR_SET = ["A".."Z", "a".."z", "0".."9", '_', '-'] + # String.random(10, BASE64_CHAR_SET) + # => "xM_1t3qcNn" + # + # SPECIAL_CHARS = ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "=", "+", "|", "/", "?", ".", ",", ";", ":", "~", "`", "[", "]", "{", "}", "<", ">"] + # BASE91_CHAR_SET = ["A".."Z", "a".."z", "0".."9", SPECIAL_CHARS] + # String.random(10, BASE91_CHAR_SET) + # => "S(Z]z,J{v;" + # + # CREDIT: Tilo Sloboda + # + # SEE: https://gist.github.com/tilo/3ee8d94871d30416feba + # + # TODO: Move to random.rb in standard library? + + def self.random(len=32, character_set = ["A".."Z", "a".."z", "0".."9"]) + chars = character_set.map{|x| x.is_a?(Range) ? x.to_a : x }.flatten + Array.new(len){ chars.sample }.join + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/range.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/range.rb new file mode 100644 index 00000000..65489a24 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/range.rb @@ -0,0 +1,60 @@ +class String + + # Like #index but returns a Range. + # + # "This is a test!".range('test') #=> (10..13) + # + # CREDIT: Trans + + def range(pattern, offset=0) + unless Regexp === pattern + pattern = Regexp.new(Regexp.escape(pattern.to_s)) + end + string = self[offset..-1] + if md = pattern.match(string) + return (md.begin(0)+offset)..(md.end(0)+offset-1) + end + nil + end + + # Like #index_all but returns an array of Ranges. + # + # "abc123abc123".range_all('abc') #=> [0..2, 6..8] + # + # TODO: Add offset ? + # + # CREDIT: Trans + + def range_all(pattern, reuse=false) + r = []; i = 0 + while i < self.length + rng = range(pattern, i) + if rng + r << rng + i += reuse ? 1 : rng.end + 1 + else + break + end + end + r.uniq + end + + # Returns an array of ranges mapping + # the characters per line. + # + # "this\nis\na\ntest".range_of_line + # #=> [0..4, 5..7, 8..9, 10..13] + # + # CREDIT: Trans + + def range_of_line + offset=0; charmap = [] + each_line do |line| + charmap << (offset..(offset + line.length - 1)) + offset += line.length + end + charmap + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/range_all.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/range_all.rb new file mode 100644 index 00000000..dcb83064 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/range_all.rb @@ -0,0 +1 @@ +require 'facets/string/range' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/range_of_line.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/range_of_line.rb new file mode 100644 index 00000000..dcb83064 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/range_of_line.rb @@ -0,0 +1 @@ +require 'facets/string/range' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/remove.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/remove.rb new file mode 100644 index 00000000..057633b2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/remove.rb @@ -0,0 +1,30 @@ +class String + + # Removes all occurrences of a pattern in a string. + # + # Returns a new [String] with all occurrences of the pattern removed. + def remove(pattern) + gsub(pattern, '') + end + + # Removes all occurrences of a pattern in a string. + # + # Returns the [String] with all occurrences of the pattern removed. + def remove!(pattern) + gsub!(pattern, '') + end + + # Removes occurances of a string or regexp. This is an operator + # form for the #remove method. + # + # ("HELLO HELLO" - "LL") #=> "HEO HEO" + # ("HELLO PERL" - /L\S/) #=> "HEO PERL" + # + # Returns a new [String] with all pattern matches removed. + # + # CREDIT: Benjamin David Oakes + def -(pattern) + gsub(pattern, '') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/rewrite.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/rewrite.rb new file mode 100644 index 00000000..8b01cced --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/rewrite.rb @@ -0,0 +1,24 @@ +class String + + # Apply a set of rules in the form of regular expression matches + # to the string. + # + # * rules - The array containing rule-pairs (match, write). + # + # Keep in mind that the order of rules is significant. + # + # Returns the rewritten String. + # + # CREDIT: George Moschovitis + + def rewrite(rules) + raise ArgumentError.new('The rules parameter is nil') unless rules + rewritten_string = dup + rules.each do |(match,write)| + rewritten_string.gsub!(match,write) + end + return rewritten_string + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/roman.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/roman.rb new file mode 100644 index 00000000..171cc557 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/roman.rb @@ -0,0 +1 @@ +require 'facets/roman' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/rotate.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/rotate.rb new file mode 100644 index 00000000..df69707e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/rotate.rb @@ -0,0 +1,24 @@ +class String + + # Rotate string to the left with count. + # Specifying negative number indicates rotation to the right. + # + # 'abcdefgh'.rotate(2) #=> 'cdefghab' + # 'abcdefgh'.rotate(-2) #=> 'ghabcdef' + # + # CREDIT: T. Yamada + def rotate(count=1) + count+=self.length if count<0 + self.slice(count,self.length-count)+self.slice(0,count) + end + + # Destructive version of String#rotate + # + # s='abcdefgh' + # s.rotate!(2) + # s.should eq 'cdefghab' + # + # CREDIT: T. Yamada + def rotate!(count=1) replace(rotate(count)) end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/shatter.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/shatter.rb new file mode 100644 index 00000000..01385dab --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/shatter.rb @@ -0,0 +1,22 @@ +class String + + # Breaks a string up into an array based on a regular expression. + # Similar to scan, but includes the matches. + # + # s = "

Thisisa test.

" + # s.shatter( /\<.*?\>/ ) + # + # _produces_ + # + # ["

", "This", "", "is", "", "a test.", "

"] + # + # CREDIT: Trans + + def shatter( re ) + r = self.gsub( re ){ |s| "\1" + s + "\1" } + while r[0,1] == "\1" ; r[0] = '' ; end + while r[-1,1] == "\1" ; r[-1] = '' ; end + r.split("\1") + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/similarity.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/similarity.rb new file mode 100644 index 00000000..02e309b3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/similarity.rb @@ -0,0 +1,90 @@ +class String + + # A fuzzy matching mechanism. Returns a score from 0-1, based + # on the number of shared edges. To be effective, the strings + # must be of length 2 or greater. + # + # "Alexsander".similarity("Aleksander") #=> 0.9 + # + # The way it works: + # + # 1. Converts each string into a "graph like" object, with edges ... + # + # "alexsander" -> [ alexsander, alexsand, alexsan ... lexsand ... san ... an, etc ] + # "aleksander" -> [ aleksander, aleksand ... etc. ] + # + # 2. Perform match, then remove any subsets from this matched set (i.e. a hit + # on "san" is a subset of a hit on "sander") ... + # + # Above example, once reduced -> [ ale, sander ] + # + # 3. See's how many of the matches remain, and calculates a score based + # on how many matches, their length, and compare to the length of the + # larger of the two words. + # + # Still a bit rough. Any suggestions for improvement are welcome. + # + # CREDIT: Derek Lewis + + def similarity(str_in) + return 0 if str_in == nil + return 1 if self == str_in + + # -- make a graph of each word (okay, its not a true graph, but is similar) + graph_A = Array.new + graph_B = Array.new + + # -- "graph" self + last = self.length + (0..last).each do |ff| + #loc = self.length + break if ff == last - 1 + wordB = (1..(last-1)).to_a.reverse! + if (wordB != nil) + wordB.each do |ss| + break if ss == ff + graph_A.push( "#{self[ff..ss]}" ) + end + end + end + + # -- "graph" input string + last = str_in.length + (0..last).each{ |ff| + #loc = str_in.length + break if ff == last - 1 + wordB = (1..(last-1)).to_a.reverse! + wordB.each do |ss| + break if ss == ff + graph_B.push( "#{str_in[ff..ss]}" ) + end + } + + # -- count how many of these "graph edges" we have that are the same + matches = graph_A & graph_B + + #-- + #matches = Array.new + #graph_A.each{ |aa| matches.push(aa) if( graph_B.include?(aa) ) } + #++ + + # -- for eliminating subsets, we want to start with the smallest hits. + matches.sort!{|x,y| x.length <=> y.length} + + # -- eliminate any subsets + mclone = matches.dup + mclone.each_index do |ii| + reg = Regexp.compile( Regexp.escape(mclone[ii]) ) + count = 0.0 + matches.each{|xx| count += 1 if xx =~ reg} + matches.delete(mclone[ii]) if count > 1 + end + + score = 0.0 + matches.each{ |mm| score += mm.length } + self.length > str_in.length ? largest = self.length : largest = str_in.length + return score/(largest+1) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/snakecase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/snakecase.rb new file mode 100644 index 00000000..64adf4dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/snakecase.rb @@ -0,0 +1,31 @@ +class String + + # Underscore a string such that camelcase, dashes and spaces are + # replaced by underscores. This is the reverse of {#camelcase}, + # albeit not an exact inverse. + # + # "SnakeCase".snakecase #=> "snake_case" + # "Snake-Case".snakecase #=> "snake_case" + # "Snake Case".snakecase #=> "snake_case" + # "Snake - Case".snakecase #=> "snake_case" + # + # Note, this method no longer converts `::` to `/`, in that case + # use the {#pathize} method instead. + + def snakecase + #gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + tr('-', '_'). + gsub(/\s/, '_'). + gsub(/__+/, '_'). + downcase + end + + # + alias_method :underscore, :snakecase + + # TODO: Add *separators to #snakecase, like camelcase. + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/splice.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/splice.rb new file mode 100644 index 00000000..514884b7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/splice.rb @@ -0,0 +1,33 @@ +require 'facets/string/store' + +class String + + # String#slice is essentially the same as #store. + # + # a = "HELLO" + # a.splice(1, "X") + # a #=> "HXLLO" + # + # But it acts like #slice! when given a single argument. + # + # a = "HELLO" + # a.splice(1) #=> "E" + # a #=> "HLLO" + # + # CREDIT: Trans + + def splice(idx, sub=nil) + if sub + store(idx, sub) + else + case idx + when Range + slice!(idx) + else + slice!(idx,1) + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/squish.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/squish.rb new file mode 100644 index 00000000..bd9e88d6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/squish.rb @@ -0,0 +1,22 @@ +class String + # Returns the string, first removing all whitespace on both ends of + # the string, and then changing remaining consecutive whitespace + # groups into one space each. + # + # %{ Multi-line + # string }.squish # => "Multi-line string" + # + # " foo bar \n \t boo".squish # => "foo bar boo" + # + def squish + dup.squish! + end + + # Performs a destructive squish. See String#squish. + def squish! + strip! + gsub!(/\s+/, ' ') + self + end +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/starts_with.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/starts_with.rb new file mode 100644 index 00000000..3b405a7d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/starts_with.rb @@ -0,0 +1,5 @@ +class String + alias starts_with? start_with? + alias ends_with? end_with? +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/store.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/store.rb new file mode 100644 index 00000000..38b58488 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/store.rb @@ -0,0 +1,7 @@ +class String + + # Alias for []=. + alias_method :store, :[]= + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/subtract.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/subtract.rb new file mode 100644 index 00000000..893a300d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/subtract.rb @@ -0,0 +1,4 @@ +# TODO: Deprecate string/subtract file. +# +require 'facets/string/op_sub' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/titlecase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/titlecase.rb new file mode 100644 index 00000000..10167c11 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/titlecase.rb @@ -0,0 +1,27 @@ +class String + + # Transform a string into a form that makes for an acceptable title. + # + # "this is a string".titlecase + # #=> "This Is A String" + # + # @author Eliazar Parra + # @author Angelo Lakra (apostrophe fix) + + def titlecase + tr('_', ' '). + gsub(/\s+/, ' '). + gsub(/\b\w/){ $`[-1,1] == "'" ? $& : $&.upcase } + end + + # Transform a string into a sentence like form. + # + # "This Is A String".briefcase + # #=> "This is a string" + # + def briefcase + titlecase.capitalize + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/to_re.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/to_re.rb new file mode 100644 index 00000000..a6dff85f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/to_re.rb @@ -0,0 +1,26 @@ +class String + + # Turns a string into a regular expression. + # + # "a?".to_re #=> /a?/ + # + # CREDIT: Trans + + def to_re(esc=false) + Regexp.new((esc ? Regexp.escape(self) : self)) + end + + # Turns a string into a regular expression. + # By default it will escape all characters. + # Use false argument to turn off escaping. + # + # "[".to_rx #=> /\[/ + # + # CREDIT: Trans + + def to_rx(esc=true) + Regexp.new((esc ? Regexp.escape(self) : self)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/to_rx.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/to_rx.rb new file mode 100644 index 00000000..61048b67 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/to_rx.rb @@ -0,0 +1 @@ +require_relative 'to_re' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/trim.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/trim.rb new file mode 100644 index 00000000..720f2d84 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/trim.rb @@ -0,0 +1,45 @@ +class String + + # Control the margin of a string using a trim character. + # + # The first character of the second line of the string + # is used as the trim character. This method is useful + # when literal multi-line strings are needed in code. + # + # num - Number of extra spaces with which to replace the + # trim character. [Integer] + # + # Examples + # + # x = %Q{ + # | This + # | is + # | trim! + # }.trim + # + # Returns string with the margin trimed-off. + # + # Note: This this method used to be called `margin` prior to Facets 3.0. + # + # Since: 3.0.0 + # Author: Trans + + def trim(num=0) + #d = /\A.*\n\s*(.)/.match( self )[1] + #d = /\A\s*(.)/.match( self)[1] unless d + + md = /\A.*\n\s*(.)/.match(self) || /\A\s*(.)/.match(self) + + d = md[1] + + return '' unless d + + if num == 0 + gsub(/\n\s*\Z/,'').gsub(/^\s*[#{d}]/, '') + else + gsub(/\n\s*\Z/,'').gsub(/^\s*[#{d}]/, ' ' * num) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/unbracket.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/unbracket.rb new file mode 100644 index 00000000..8c8e4151 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/unbracket.rb @@ -0,0 +1 @@ +require 'facets/string/bracket' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/underscore.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/underscore.rb new file mode 100644 index 00000000..7a2a4c5e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/underscore.rb @@ -0,0 +1 @@ +require 'facets/string/snakecase' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/unfold.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/unfold.rb new file mode 100644 index 00000000..9268c331 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/unfold.rb @@ -0,0 +1,32 @@ +class String + + # Unfold paragraphs such that new lines are removed from between + # sentences of the same paragraph. + # + # Note that #rstrip is called on the final result, but this may + # change in the future. + # + # FIXME: Sometimes adds one too many blank lines, which is why we are + # using rstrip. Fix and probably remove the rstrip. + # + def unfold + blank = false + text = '' + split(/\n/).each do |line| + if /\S/ !~ line + text << "\n\n" + blank = true + else + if /^(\s+|[*])/ =~ line + text << (line.rstrip + "\n") + else + text << (line.rstrip + " ") + end + blank = false + end + end + text = text.gsub(/(\n){3,}/,"\n\n") + text.rstrip + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/unindent.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/unindent.rb new file mode 100644 index 00000000..c09c4bdc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/unindent.rb @@ -0,0 +1 @@ +require 'facets/string/indent' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/unquote.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/unquote.rb new file mode 100644 index 00000000..64e40a35 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/unquote.rb @@ -0,0 +1 @@ +require 'facets/string/quote' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/uppercase.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/uppercase.rb new file mode 100644 index 00000000..c66eaa53 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/uppercase.rb @@ -0,0 +1,23 @@ +class String + + # Upcase first letter. + # + # NOTE: One might argue that this method should behave the same as + # +#upcase+ and rather this behavior should be in place of +#captialize+. + # Probably so, but since Matz has already defined +#captialize+ the way + # it is, this name seems most fitting to the missing behavior. + # + def uppercase + str = to_s + str[0,1].upcase + str[1..-1] + end + + # Downcase first letter. + # + def lowercase + str = to_s + str[0,1].downcase + str[1..-1] + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/variablize.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/variablize.rb new file mode 100644 index 00000000..bf7b4dac --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/variablize.rb @@ -0,0 +1,13 @@ +class String + + # Prepend an "@" to the beginning of a string + # to make a instance variable name. This also replaces + # non-valid characters with underscores. + + def variablize + v = gsub(/\W/, '_') + "@#{v}" + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/word_wrap.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/word_wrap.rb new file mode 100644 index 00000000..6c30b22c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/word_wrap.rb @@ -0,0 +1,32 @@ +class String + + # Word wrap a string not exceeding max width. + # + # "this is a test".word_wrap(4) + # + # _produces_ ... + # + # this + # is a + # test + # + # This is basic implementation of word wrap, but smart + # enough to suffice for most use cases. + # + # CREDIT: Gavin Kistner, Dayne Broderson + # + def word_wrap( col_width=80 ) + self.dup.word_wrap!( col_width ) + end + + # As with #word_wrap, but modifies the string in place. + # + # CREDIT: Gavin Kistner, Dayne Broderson + # + def word_wrap!( col_width=80 ) + self.gsub!( /(\S{#{col_width}})(?=\S)/, '\1 ' ) + self.gsub!( /(.{1,#{col_width}})(?:\s+|$)/, "\\1\n" ) + self + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/words.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/words.rb new file mode 100644 index 00000000..bba9daca --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/words.rb @@ -0,0 +1,12 @@ +class String + + # Returns an array of characters. + # + # "abc 123".words #=> ["abc","123"] + # + def words + self.split(/\s+/) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/string/xor.rb b/bin/gems/facets-3.1.0/lib/core/facets/string/xor.rb new file mode 100644 index 00000000..a489c857 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/string/xor.rb @@ -0,0 +1,26 @@ +class String + + # Binary XOR of two strings. + # + # a = "\000\000\001\001" ^ "\000\001\000\001" + # b = "\003\003\003" ^ "\000\001\002" + # + # a #=> "\000\001\001\000" + # b #=> "\003\002\001" + # + def ^(aString) + a = self.unpack('C'*(self.length)) + b = aString.unpack('C'*(aString.length)) + if (b.length < a.length) + (a.length - b.length).times { b << 0 } + end + xor = "" + 0.upto(a.length-1) { |pos| + x = a[pos] ^ b[pos] + xor << x.chr() + } + return(xor) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/struct.rb b/bin/gems/facets-3.1.0/lib/core/facets/struct.rb new file mode 100644 index 00000000..2511a2e2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/struct.rb @@ -0,0 +1,3 @@ +require_relative 'struct/attributes.rb' +require_relative 'struct/replace.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/struct/attributes.rb b/bin/gems/facets-3.1.0/lib/core/facets/struct/attributes.rb new file mode 100644 index 00000000..dfc8f787 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/struct/attributes.rb @@ -0,0 +1,15 @@ +class Struct + + # Returns a hash containing the names and values + # for all instance settings in the Struct. + # + # This will eventually be deprecated in favor of #to_h. + + def attributes + h = {} + each_pair { |k,v| h[k] = v } + h + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/struct/replace.rb b/bin/gems/facets-3.1.0/lib/core/facets/struct/replace.rb new file mode 100644 index 00000000..4e7630af --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/struct/replace.rb @@ -0,0 +1,8 @@ +class Struct + + # Struct#replace can take any +source+ that responds to #each_pair. + def replace(source) + source.each_pair{ |k,v| send(k.to_s + "=", v) } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol.rb new file mode 100644 index 00000000..977f9251 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol.rb @@ -0,0 +1,14 @@ +require_relative 'symbol/as_s.rb' +require_relative 'symbol/bang.rb' +require_relative 'symbol/call.rb' +require_relative 'symbol/chomp.rb' +require_relative 'symbol/generate.rb' +require_relative 'symbol/not.rb' +require_relative 'symbol/op_div.rb' +require_relative 'symbol/plain.rb' +require_relative 'symbol/query.rb' +require_relative 'symbol/setter.rb' +require_relative 'symbol/succ.rb' +require_relative 'symbol/thrown.rb' +require_relative 'symbol/variablize.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/as_s.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/as_s.rb new file mode 100644 index 00000000..16a8b254 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/as_s.rb @@ -0,0 +1,19 @@ +require 'facets/functor' + +class Symbol + + # TODO: Should Symbol#as_s be moved to functor gem? + + # Convert symbol to string, apply string method and convert + # back to symbol via a fluent interface. + # + # :HELLO.as_s.chomp('O') #=> :HELL + # + def as_s + Functor.new do |op, *a| + to_s.send(op, *a).to_sym + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/bang.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/bang.rb new file mode 100644 index 00000000..82c9ee66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/bang.rb @@ -0,0 +1 @@ +require 'facets/symbol/plain' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/call.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/call.rb new file mode 100644 index 00000000..fc816054 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/call.rb @@ -0,0 +1,29 @@ +class Symbol + + # Useful extension for &:symbol which makes it possible + # to pass arguments for method in block + # + # ['abc','','','def','ghi'].tap(&:delete.('')) + # #=> ['abc','def','ghi'] + # + # [1,2,3].map(&:to_s.(2)) + # #=> ['1','10','11'] + # + # ['abc','cdef','xy','z','wwww'].select(&:size.() == 4) + # #=> ['cdef', 'wwww'] + # + # ['abc','aaA','AaA','z'].count(&:upcase.().succ == 'AAB') + # #=> 2 + # + # [%w{1 2 3 4 5},%w{6 7 8 9}].map(&:join.().length) + # #=> [5,4] + # + # CREDIT: Ilya Vorontsov, Nobuyoshi Nakada + + def call(*args, &block) + proc do |recv| + recv.__send__(self, *args, &block) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/chomp.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/chomp.rb new file mode 100644 index 00000000..32ce7e5e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/chomp.rb @@ -0,0 +1,24 @@ +class Symbol + + # Just like String#chomp. + # + # :ab.chomp(:b) #=> :a + # + # CREDIT: Trans + + def chomp(seperator) + to_s.chomp(seperator.to_s).to_sym + end + + # Just like String#lchomp. + # + # :ab.lchomp(:a) #=> :b + # + # CREDIT: Trans + + def lchomp(seperator) + to_s.reverse.chomp(seperator.to_s).reverse.to_sym + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/generate.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/generate.rb new file mode 100644 index 00000000..1ca20683 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/generate.rb @@ -0,0 +1,24 @@ +class Symbol + + # Generate a unique symbol. + # + # Symbol.generate #=> :"-1" + # + # If +key+ is given the new symbol will be prefixed with it. + # + # Symbol.generate(:foo) #=> :"foo-1" + # + # TODO: Is the generated symbol format acceptable? + # + # CREDIT: Trans + + def self.generate(key=nil) + key = key.to_sym if key + @symbol_generate_counter ||= {} + @symbol_generate_counter[key] ||= 0 + num = @symbol_generate_counter[key] += 1 + ("#{key}-%X" % num).to_sym + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/not.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/not.rb new file mode 100644 index 00000000..5dcdc5c4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/not.rb @@ -0,0 +1,29 @@ +class Symbol + + # Does a symbol have a "not" sign? + # + # "friend".to_sym.not? #=> false + # "~friend".to_sym.not? #=> true + # + # CREDIT: Trans + + def not? + self.to_s.slice(0,1) == '~' + end + + # Add a "not" sign to the front of a symbol. + # + # (~:friend) #=> :"~friend" + # + # CREDIT: Trans + + def ~@ + if self.to_s.slice(0,1) == '~' + "#{self.to_s[1..-1]}".to_sym + else + "~#{self}".to_sym + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/op_div.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/op_div.rb new file mode 100644 index 00000000..a7388b6f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/op_div.rb @@ -0,0 +1,21 @@ +require 'facets/string/op_div' + +class Symbol + + # Join with _path_ as a file path. + # + # * path - The path component(s) to append. [#to_s] + # + # Examples + # + # (:merb / "string") #=> "merb/string" + # (:merb / :symbol) #=> "merb/symbol" + # + # Returns String of the receiver (as a path string), concatenated + # with _path_. + def /(path) + File.join(to_s, path.to_s) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/plain.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/plain.rb new file mode 100644 index 00000000..9ee0e403 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/plain.rb @@ -0,0 +1,51 @@ +class Symbol + + # Symbol does not end in `!`, `=`, or `?`. + # + # :a.plain? #=> true + # :a?.plain? #=> false + # :a!.plain? #=> false + # :a=.plain? #=> false + # + def plain? + c = to_s[-1,1] + !(c == '=' || c == '?' || c == '!') + end + + # Alias for `#plain?` method. Likely this should have been the original + # and only name, but such is life. + alias_method :reader?, :plain? + + # Symbol ends in `=`. + # + # :a=.setter? #=> true + # :a.setter? #=> false + # + def setter? + to_s[-1,1] == '=' + end + + # Alias for `#setter?` method. Likely this should have been the original + # and only name, but such is life. + alias_method :writer?, :setter? + + # Symbol ends in `?`. + # + # :a?.query? #=> true + # :a.query? #=> false + # + def query? + to_s[-1,1] == '?' + end + + # Symbol ends in `!`. + # + # :a!.bang? #=> true + # :a.bang? #=> false + # + def bang? + to_s[-1,1] == '!' + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/query.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/query.rb new file mode 100644 index 00000000..82c9ee66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/query.rb @@ -0,0 +1 @@ +require 'facets/symbol/plain' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/reader.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/reader.rb new file mode 100644 index 00000000..82c9ee66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/reader.rb @@ -0,0 +1 @@ +require 'facets/symbol/plain' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/setter.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/setter.rb new file mode 100644 index 00000000..82c9ee66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/setter.rb @@ -0,0 +1 @@ +require 'facets/symbol/plain' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/succ.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/succ.rb new file mode 100644 index 00000000..c6ee2fac --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/succ.rb @@ -0,0 +1,23 @@ +class Symbol + + unless method_defined?(:succ) # 1.9+ TODO: is this right? + + # Successor method for symobol. This simply converts + # the symbol to a string uses String#succ and then + # converts it back to a symbol. + # + # :a.succ #=> :b + # + # TODO: Make this work more like a simple character dial? + + def succ(n=1) + s = self.to_s + n.times do + s = s.succ + end + s.to_sym + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/thrown.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/thrown.rb new file mode 100644 index 00000000..12b1ed46 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/thrown.rb @@ -0,0 +1,22 @@ +class Symbol + + # Returns truew if the given block throws the symbol, otherwise false. + # Note that +throw+ inside the block must be used in one-argument form. + # + # @return [true,false] + def thrown? + thrown = true + catch(self) do + begin + yield + thrown = false + rescue ArgumentError => err # 1.9 exception + thrown = false if err.message.index('uncaught throw') + rescue NameError => err # 1.8 exception + thrown = false if err.message.index('uncaught throw') + end + end + thrown + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/variablize.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/variablize.rb new file mode 100644 index 00000000..3aaadb21 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/variablize.rb @@ -0,0 +1,14 @@ +class Symbol + + # Prepend an "@" to the beginning of a symbol to make a instance + # variable name. This also replaces non-valid characters with underscores. + # + # :a.variablize #=> :"@a" + # + def variablize + name = to_s.gsub(/\W/, '_') + "@#{name}".to_sym + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/symbol/writer.rb b/bin/gems/facets-3.1.0/lib/core/facets/symbol/writer.rb new file mode 100644 index 00000000..82c9ee66 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/symbol/writer.rb @@ -0,0 +1 @@ +require 'facets/symbol/plain' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time.rb b/bin/gems/facets-3.1.0/lib/core/facets/time.rb new file mode 100644 index 00000000..a0ef909a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time.rb @@ -0,0 +1,16 @@ +require_relative 'time/ago.rb' +require_relative 'time/change.rb' +require_relative 'time/dst_adjustment.rb' +require_relative 'time/elapse.rb' +require_relative 'time/future.rb' +require_relative 'time/hence.rb' +require_relative 'time/in.rb' +require_relative 'time/less.rb' +require_relative 'time/past.rb' +require_relative 'time/round_to.rb' +require_relative 'time/set.rb' +require_relative 'time/shift.rb' +require_relative 'time/stamp.rb' +require_relative 'time/to_time.rb' +require_relative 'time/trunc.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/ago.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/ago.rb new file mode 100644 index 00000000..b18019ad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/ago.rb @@ -0,0 +1 @@ +require 'facets/time/shift' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/change.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/change.rb new file mode 100644 index 00000000..e1529c0d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/change.rb @@ -0,0 +1,46 @@ +class Time + + # Returns a new Time where one or more of the elements + # have been changed according to the +options+ parameter. + # The time options (hour, minute, sec, usec) reset + # cascadingly, so if only the hour is passed, then + # minute, sec, and usec is set to 0. If the hour and + # minute is passed, then sec and usec is set to 0. + # + # t1 = Time.at(10000) + # t1.ctime #=> "Wed Dec 31 21:46:40 1969" + # + # t2 = t1.change(:hour => 11) + # t2.ctime #=> "Wed Dec 31 11:00:00 1969" + # + def change(options) + opts=options; #{}; options.each_pair{ |k,v| opts[k] = v.to_i } + self.class.send( + self.utc? ? :utc : :local, + opts[:year] || self.year, + opts[:month] || self.month, + opts[:day] || self.day, + opts[:hour] || self.hour, + opts[:min] || (opts[:hour] ? 0 : self.min), + opts[:sec] || ((opts[:hour] || opts[:min]) ? 0 : self.sec), + opts[:usec] || ((opts[:hour] || opts[:min] || opts[:sec]) ? 0 : self.usec) + ) + end + + # Old Version ... + # + # def change(options) + # ::Time.send( + # self.utc? ? :utc_time : :local_time, + # options[:year] || self.year, + # options[:month] || self.month, + # options[:day] || self.day, + # options[:hour] || self.hour, + # options[:min] || (options[:hour] ? 0 : self.min), + # options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec), + # options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec) + # ) + # end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/dst_adjustment.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/dst_adjustment.rb new file mode 100644 index 00000000..f9095f96 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/dst_adjustment.rb @@ -0,0 +1,24 @@ +class Time + + unless method_defined?(:dst_adjustment) + + # Adjust DST + # + # TODO: Can't seem to get this to pass ActiveSupport tests, + # even though it is essentially identical to the ActiveSupport + # code (see Time#since in time/calculations.rb). It handles + # all but 4 tests. + def dst_adjustment(time) + self_dst = self.dst? ? 1 : 0 + time_dst = time.dst? ? 1 : 0 + seconds = (self - time).abs + if (seconds >= 86400 && self_dst != time_dst) + time + ((self_dst - time_dst) * 60 * 60) + else + time + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/elapse.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/elapse.rb new file mode 100644 index 00000000..cee2d2fe --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/elapse.rb @@ -0,0 +1,18 @@ +class Time + + # Tracks the elapse time of a code block. + # + # e = Time.elapse { sleep 1 } + # + # e.assert > 1 + # + # CREDIT: Hal Fulton + + def self.elapse + raise "Need block" unless block_given? + t0 = now.to_f + yield + now.to_f - t0 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/future.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/future.rb new file mode 100644 index 00000000..5ce4046c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/future.rb @@ -0,0 +1,16 @@ +class Time + + def self.current + now + end + + def past?(other=nil) + self < (other || self.class.current) + end + + def future?(other=nil) + self > (other || self.class.current) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/hence.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/hence.rb new file mode 100644 index 00000000..d2f72785 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/hence.rb @@ -0,0 +1 @@ +require 'facets/time/in' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/in.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/in.rb new file mode 100644 index 00000000..b18019ad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/in.rb @@ -0,0 +1 @@ +require 'facets/time/shift' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/less.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/less.rb new file mode 100644 index 00000000..b18019ad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/less.rb @@ -0,0 +1 @@ +require 'facets/time/shift' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/past.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/past.rb new file mode 100644 index 00000000..d3389a48 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/past.rb @@ -0,0 +1 @@ +require 'facets/time/future' diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/round_to.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/round_to.rb new file mode 100644 index 00000000..14ddfb79 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/round_to.rb @@ -0,0 +1,21 @@ +require 'facets/time/trunc' + +class Time + + # Round time at the nearest range (in seconds). + # + # t1 = Time.now + # t2 = t1.round_to(60*60) + # t2.min #=> 0 + # t2.sec #=> 0 + # + # TODO: What about `round(:minute)`? + # + # TODO: Fractional seconds should round the usec. + # + def round_to(seconds) + (self + seconds / 2.0).trunc(seconds) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/set.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/set.rb new file mode 100644 index 00000000..d5404cea --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/set.rb @@ -0,0 +1,27 @@ +class Time + + # Like change but does not reset earlier times. + # + # NOTE: It would be better, probably if this were called "change". + # and that #change were called "reset". + # + def set(options) + opts={} + options.each_pair do |k,v| + k = :min if k.to_s =~ /^min/ + k = :sec if k.to_s =~ /^sec/ + opts[k] = v.to_i + end + self.class.send( + self.utc? ? :utc : :local, + opts[:year] || self.year, + opts[:month] || self.month, + opts[:day] || self.day, + opts[:hour] || self.hour, + opts[:min] || self.min, + opts[:sec] || self.sec, + opts[:usec] || self.usec + ) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/shift.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/shift.rb new file mode 100644 index 00000000..2004aa7c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/shift.rb @@ -0,0 +1,97 @@ +require 'facets/time/set' +require 'facets/time/dst_adjustment' + +class Time + + # TODO: Deprecate use of #dst-adjustment in Time#shift ? + + # Returns a new Time representing the time shifted by the time-units given. + # Positive number shift the time forward, negative number shift the time + # backward. + # + # t = Time.utc(2010,10,10,0,0,0) + # t.shift( 4, :days) #=> Time.utc(2010,10,14,0,0,0) + # t.shift(-4, :days) #=> Time.utc(2010,10,6,0,0,0) + # + # More than one unit of time can be given. + # + # t.shift(4, :days, 3, :hours) #=> Time.utc(2010,10,14,3,0,0) + # + # The #shift method can also take a hash. + # + # t.shift(:days=>4, :hours=>3) #=> Time.utc(2010,10,14,3,0,0) + # + def shift(*time_units) + time_hash = Hash===time_units.last ? time_units.pop : {} + time_units = time_units.flatten + time_units << :seconds if time_units.size % 2 == 1 + time_hash.each{ |units, number| time_units << number; time_units << units } + + time = self + time_units.each_slice(2) do |number, units| + #next time = time.ago(-number, units) if number < 0 + time = ( + case units.to_s.downcase.to_sym + when :years, :year + time.set( :year=>(year + number) ) + when :months, :month + if number > 0 + new_month = ((month + number - 1) % 12) + 1 + y = (number / 12) + (new_month < month ? 1 : 0) + time.set(:year => (year + y), :month => new_month) + else + number = -number + new_month = ((month - number - 1) % 12) + 1 + y = (number / 12) + (new_month > month ? 1 : 0) + time.set(:year => (year - y), :month => new_month) + end + when :weeks, :week + time + (number * 604800) + when :days, :day + time + (number * 86400) + when :hours, :hour + time + (number * 3600) + when :minutes, :minute, :mins, :min + time + (number * 60) + when :seconds, :second, :secs, :sec, nil + time + number + else + raise ArgumentError, "unrecognized time units -- #{units}" + end + ) + end + dst_adjustment(time) + end + + # Alias for #shift. + alias_method :in, :shift + + # Alias for #shift. + alias_method :hence, :shift unless method_defined?(:hence) + + # Returns a new Time representing the time a number of time-units ago. + # This is just like #shift, but reverses the direction. + # + # t = Time.utc(2010,10,10,0,0,0) + # + # t.less(4, :days) #=> Time.utc(2010,10,6,0,0,0) + # + def less(*time_units) + time_hash = Hash===time_units.last ? time_units.pop : {} + time_units = time_units.flatten + + time_units << :seconds if time_units.size % 2 == 1 + + time_hash.each{ |units, number| time_units << number; time_units << units } + + neg_times = [] + time_units.each_slice(2){ |number, units| neg_times << -number; neg_times << units } + + shift(*neg_times) + end + + # Alias for #less + alias_method :ago, :less unless method_defined?(:ago) + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/stamp.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/stamp.rb new file mode 100644 index 00000000..71a8966a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/stamp.rb @@ -0,0 +1,47 @@ +class Time + + # TODO: Time::Formats need improvement! + unless const_defined?('FORMAT') + FORMAT = { + :utc => "%Y-%m-%d %H:%M:%S", + :utcT => "%Y-%m-%dT%H:%M:%S", + :db => "%Y-%m-%d %H:%M:%S", + :database => "%Y-%m-%d %H:%M:%S", + :number => "%Y%m%d%H%M%S", + :short => "%d %b %H:%M", + :time => "%H:%M", + :long => "%B %d, %Y %H:%M", + :day1st => "%d-%m-%Y %H:%M", + :dmYHM => "%d-%m-%Y %H:%M", + :rfc822 => "%a, %d %b %Y %H:%M:%S %z", + :ruby18 => "%a %b %d %H:%M:%S %z %Y", + nil => "%Y-%m-%d %H:%M:%S %z" + } + end + + # Produce time stamp for Time.now. See #stamp. + # + # CREDIT: Trans + + def self.stamp(*args) + now.stamp(*args) + end + + # Create a time stamp. + # + # t = Time.at(10000) + # t.stamp(:short) #=> "31 Dec 21:46" + # + # Supported formats come from the Time::FORMAT constant. + # + # CREDIT: Trans + + def stamp(fmt = nil) + unless String === fmt + fmt = FORMAT[fmt] + end + strftime(fmt).strip + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/to_time.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/to_time.rb new file mode 100644 index 00000000..3521bc27 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/to_time.rb @@ -0,0 +1,21 @@ +class Time + + unless method_defined?(:to_time) # 1.9 + + # To be able to keep Dates and Times interchangeable + # on conversions. + + def to_time + getlocal + end + + # A method to keep Time, Date and DateTime instances interchangeable + # on conversions. In this case, it simply returns +self+. + #def to_time + # self + #end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/time/trunc.rb b/bin/gems/facets-3.1.0/lib/core/facets/time/trunc.rb new file mode 100644 index 00000000..bb1cbb01 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/time/trunc.rb @@ -0,0 +1,15 @@ +class Time + + # Truncate time at give range (in seconds). + # + # t = Time.now + # t = t.trunc(60*60) + # t.min #=> 0 + # t.sec #=> 0 + # + def trunc(amount) + self - (self.to_i % amount) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod.rb b/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod.rb new file mode 100644 index 00000000..7cbead93 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod.rb @@ -0,0 +1,2 @@ +require_relative 'unboundmethod/arguments.rb' + diff --git a/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod/arguments.rb b/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod/arguments.rb new file mode 100644 index 00000000..5dfc2d95 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/unboundmethod/arguments.rb @@ -0,0 +1,44 @@ +class UnboundMethod + + # Resolves the arguments of the method to have an + # identical signiture --useful for preserving arity. + # + # class X + # def foo(a, b); end + # def bar(a, b=1); end + # end + # + # foo_method = X.instance_method(:foo) + # foo_method.arguments #=> "a0, a1" + # + # bar_method = X.instance_method(:bar) + # bar_method.arguments #=> "a0, *args" + # + # When defaults are used the arguments must end in "*args". + # + # CREDIT: Trans + + def arguments + ar = arity + case ar <=> 0 + when 1 + args = [] + ar.times do |i| + args << "a#{i}" + end + args = args.join(", ") + when 0 + args = "" + else + ar = -ar - 1 + args = [] + ar.times do |i| + args << "a#{i}" + end + args << "*args" + args = args.join(", ") + end + return args + end + +end diff --git a/bin/gems/facets-3.1.0/lib/core/facets/version.rb b/bin/gems/facets-3.1.0/lib/core/facets/version.rb new file mode 100644 index 00000000..ac31cce4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/core/facets/version.rb @@ -0,0 +1,19 @@ +module Facets + # + def self.index + @index ||= ( + require 'yaml' + YAML.load(File.new(File.dirname(__FILE__) + '/facets.yml')) + ) + end + + # + def self.const_missing(name) + key = name.to_s.downcase + index[key] || super(name) + end + + # deprecate + VERSION = '3.0.0' +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/against.rb b/bin/gems/facets-3.1.0/lib/standard/facets/against.rb new file mode 100644 index 00000000..ca676430 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/against.rb @@ -0,0 +1,53 @@ +require 'facets/functor' + +class Object + + # Objectified message or block application. Only a message + # or a block can be given, not both. + # + # msg - method and arguments [Array] + # blk - procedure block [Proc] + # + # Examples + # + # a = [1,2,3,4,5] + # c = a.against(:>, 2) + # c.select #=> [3,4,5] + # + # a = [1,2,3,4,5] + # c = a.against(:>) + # c.select(2) #=> [3,4,5] + # + # Returns [Functor] + # + # TODO: Better name for this method? + + def against(*msg, &blk) + raise ArgumentError, "too many arguments" if blk && !msg.empty? + + this = self + + blk = ::Proc.new{ |x,*a| x.__send__(*msg, *a) } unless blk + + #if blk + Functor.new do |m, *a, &b| + if b + b2 = ::Proc.new{ |*x| blk.call(*b.call(*x), *a) } + else + b2 = blk + end + this.__send__(m, &b2) + end + #else + # Functor.new do |m, *a, &b| + # if b + # b2 = ::Proc.new{ |*x| b.call(*x).__send__(*msg, *a) } + # else + # b2 = ::Proc.new{ |x| x.__send__(*msg, *a) } + # end + # this.__send__(m, &b2) + # end + #end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/argvector.rb b/bin/gems/facets-3.1.0/lib/standard/facets/argvector.rb new file mode 100644 index 00000000..4fad5b9f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/argvector.rb @@ -0,0 +1,343 @@ +# = ArgVector +# +# == Synopsis +# +# ArgVector provides a very simple means of parsing +# command line arguments. +# +# Unlike other more complex libs this provides only +# the most basic and standard parsing functionality. +# In many cases that's all one really needs. +# +# Usage is straight foward. Simply instantiate the +# class and query it for the particular "views" of +# the command line you want. +# +# cargs = ArgVector.new("-a foo -b=2") +# +# cargs.parameters #=> [['foo'],{'a'=>true,'b'=>'2'}] +# cargs.flags #=> ['a'] +# cargs.preoptions #=> {'a'=>true} +# cargs.preflags #=> ['a'] +# cargs.subcommand #=> ['foo', [], {'b'=>'2'}] +# +# == Authors +# +# * Thomas Sawyer +# +# == Copying +# +# Copyright (c) 2006 Thomas Sawyer +# +# Ruby License +# +# This module is free software. You may use, modify, and/or +# redistribute this software under the same terms as Ruby. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. + +require 'shellwords' + +# = Argvector +# +# Argvector provides a very simple means of parsing +# command line arguments. +# +# Unlike other more complex libs this provides only +# the most basic and standard parsing functionality. +# In many cases that's all one really needs. +# +# Usage is straight foward. Simply instantiate the +# class and query it for the particular "views" of +# the command line you want. +# +# cargs = Argvector.new("-a foo -b=2") +# +# cargs.parameters #=> [['foo'],{'a'=>true,'b'=>'2'}] +# cargs.flags #=> ['a'] +# cargs.preoptions #=> {'a'=>true} +# cargs.preflags #=> ['a'] +# cargs.subcommand #=> ['foo', [], {'b'=>'2'}] +# +class Argvector + + def self.parameters(*args) + new.parameters(*args) + end + + attr :line + attr :argv + attr :arity + ##attr :opts + + ##alias :flags :options + + # Takes the command line string (or array) and options. + # Options have flags and end with a hash of option arity. + # + def initialize(line=nil, arity=nil) + @line, @argv = parse_line(line) + @arity = parse_arity(arity||{}) + parse + end + + public + + # Returns operand array. + def operands + @operands + end + + # deprecate alias ? + alias arguments operands + + # Returns options hash. + def options + @options + end + + # Returns [operands, options], which is good for plugging + # directly into a method. + def parameters + return @operands, @options + end + + # Return flags, which are true options. + def flags + f = [] + @options.each do |k, v| + if TrueClass===v or FalseClass===v # not that it's ever false + f << k + end + end + return f + end + + # Assumes the first operand is a "subcommand" and + # returns it and the argments following it as + # parameters. + def subcommand_with_parameters + opts, args = *parse_preoptions(argv) + cmd = args.shift + subargs = self.class.new(args, @arity) + return [cmd, *subargs.parameters] + end + + alias subcommand subcommand_with_parameters + + # + def subcommand_with_preoptions + pre, args = *parse_preoptions(argv) + cmd = args.shift + subargs = self.class.new(args, @arity) + args, opts = *subargs.parameters + return [cmd, args, pre.merge(opts)] + end + + # Assumes the first operand is a "subcommand" and + # returns it and the argments following it as + # another Arguments object. + # + # TODO: This probably should be called 'subcommand'. + # + def subcommand_with_arguments + opts, args = *parse_preoptions(argv) + cmd = args.shift + subargs = self.class.new(args, @arity) + return cmd, subargs + end + + # Returns a hash of options that occur before + # the first operand. This works well with + # subcommand to get the main command's options. + # + # line = "--trace stamp --file VERSION" + # cargs = Argvector.new(line) + # opts = cargs.preoptions + # opts #=> {"trace"=>true} + # + def preoptions + preopts, remainder = *parse_preoptions(argv) + return preopts + end + + # Same as +flags+ but only returns flags in the + # preoptions. + def preflags + preopts, remainder = *parse_preoptions(argv) + f = [] + preopts.each do |k, v| + if TrueClass===v or FalseClass===v # not that it's ever false + f << k + end + end + return f + end + + # Like parameters but without allowing for duplicate options. + def parameters_without_duplicates + opts = {} + @options.each do |k,v| + if Array===v + opts[k] = v[0] + else + opts[k] = v + end + end + return @operands, opts + end + + #private + + # Basic parser partitions the command line into options and + # operands. Options are converted to a hash and the two + # parts are returned. + # + # line = "--trace stamp --file=VERSION" + # argv = Argvector.new(line) + # + # args, keys = *argv.parse + # + # args #=> ["stamp"] + # keys #=> {"trace"=>true, "file"=>"VERSION"} + # + def parse + args = assoc_options(argv) #, *opts_arity) + + opts, opds = args.partition{ |a| Array === a } + + @operands = opds + @options = format_options(opts) + + return @operands, @options + end + + # First pass parser to split the command line into an + # array using Shellwords, if not already so divided. + def parse_line(line=nil) + if line + case line + when String + argv = Shellwords.shellwords(line) + else + argv = line.to_ary.dup + line = argv.join(' ') + end + else + argv = ARGV.dup + line = argv.join(' ') + end + return line, argv + end + + ## Ensure opts are a uniform. + ## + ##def clean_opts( opts ) + ## opts2 = opts.collect{ |o| o.to_sym } + ## opts2 = opts2 & [:simple, :repeat] # valid options only + ## return opts2 + ##end + + # Ensure arity is uniform. + def parse_arity(arity) + arity2 = {} + arity.each{ |k,v| arity2[k.to_s] = v.to_i } + return arity2 + end + + # Parse preoptions. A "preoption" is one that + # occurs before the first operans (if any). + def parse_preoptions(args) + ##args = args.dup + args = multi_flag(args) #unless opts.include?(:simple) + + flags = [] + while args.first =~ /^-/ + key = args.shift + key.sub!(/^-{1,2}/,'') + if key.index('=') + key, val = key.split('=') + elsif a = arity[key] + val = args.slice!(0,a) + val = val.first if a == 1 + else + val = true + end + flags << [key, val] + end + + flags = format_options(flags) + + return flags, args + end + + # Parse flags takes the command line and transforms it such that + # flags (eg. -x and --x) are elemental associative arrays. + # + # line = "--foo hello --try=this" + # argv = Argvector.new(line) + # + # args = line.split(/\s/) + # argv.assoc_options(args) #=> [ ["foo",true], "hello", ["try","this"] ] + # + def assoc_options(args) + ##args = args.dup + args = multi_flag(args) #unless opts.include?(:simple) + i = 0 + while i < args.size + arg = args[i] + case arg + when /^-/ + arg = arg.sub(/^-{1,2}/,'') + if arg.index('=') + key, val = arg.split('=') + args[i] = [key, val||true] + elsif arity.key?(arg) + cnt = arity[arg] + key = arg + val = args[i+1,cnt] + args[i,cnt+1] = [[key, *val]] + i += (cnt - 1) + else + key = arg + args[i] = [key,true] + end + end + i += 1 + end + return args + end + + # Split single letter option groupings into separate options. + # ie. -xyz => -x -y -z + def multi_flag(args=nil) + args ||= argv + args.collect { |arg| + if md = /^-(\w{2,})/.match( arg ) + md[1].split(//).collect { |c| "-#{c}" } + else + arg.dup + end + }.flatten + end + + # Format flag options. This converts the associative array of + # options/flags into a hash. Repeat options will be placed in arrays. + def format_options(assoc_options) + opts = {} + assoc_options.each do |k,v| + if opts.key?(k) + opts[k] = [opts[k]].flatten << v + else + opts[k] = v + end + end + return opts + end + +end + +ArgVector = Argvector diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/basicobject.rb b/bin/gems/facets-3.1.0/lib/standard/facets/basicobject.rb new file mode 100644 index 00000000..65c28f1c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/basicobject.rb @@ -0,0 +1,75 @@ +# Facets' BasicObject is an implementation of Jim Weirich's BlankSlate. +# +# BlankSlate +# Copyright 2004 by Jim Weirich (jim@weirichhouse.org). +# All rights reserved. +# +# Since Ruby 1.9 has a BasicObject class this will of course be +# deprecated as 1.9 goes mainstream. + +unless defined? BasicObject # in case it already exists! + + # BasicObject provides an abstract base class with no predefined + # methods (except for \_\_send__ and \_\_id__). + # BlankSlate is useful as a base class when writing classes that + # depend upon method_missing (e.g. dynamic proxies). + class BasicObject + class << self + # Hide the method named +name+ in the BlankSlate class. Don't + # hide +instance_eval+ or any method beginning with "__". + # + # According to 1.9.1 it should have only these methods: + # + # * #__send__ + # * #instance_eval + # * #instance_exec + # * #equal? + # * #== + # * #! + # * #!= + # * respond_to? + # + # Seems to me it should have #__id__ too. + def hide(name) + undef_method name if + instance_methods.include?(name.to_s) and + name !~ /^(__|respond_to\?|instance_eval$|instance_exec$|equal\?$|\=\=$)/ + end + end + instance_methods.each{ |m| hide(m) } + end + + # Since Ruby is very dynamic, methods added to the ancestors of + # BlankSlate after BlankSlate is defined will show up in the + # list of available BlankSlate methods. We handle this by defining a + # hook in the Object and Kernel classes that will hide any defined + module Kernel #:nodoc: + class << self + alias_method :facets_basic_object_method_added, :method_added + + # Detect method additions to Kernel and remove them in the + # BlankSlate class. + def method_added(name) + facets_basic_object_method_added(name) + return if self != Kernel + BasicObject.hide(name) + end + end + end + + class Object #:nodoc: + class << self + alias_method :facets_basic_object_method_added, :method_added + + # Detect method additions to Object and remove them in the + # BlankSlate class. + def method_added(name) + facets_basic_object_method_added(name) + return if self != Object + BasicObject.hide(name) + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/binding/block_exec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/binding/block_exec.rb new file mode 100644 index 00000000..f60483e1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/binding/block_exec.rb @@ -0,0 +1,44 @@ +class Binding + + # Allows the evaluation of blocks by a Binding in the same way that strings + # can be evaluated. + # + # x = 5 + # $my_binding = binding + # + # class Test # just here to provide a scope gate + # $my_binding.block_exec { x } + # end + # + # # => 5 + # + # NOTE: The implementation of this method uses a method_missing trick. + # Consequently it is a bit of a hack. + # + def block_exec(*args, &block) + BlockEnvironment.new(self, *args, &block).call + end + + # This class is used for evaluating blocks in a particular context. + # It is not really meant to be used independently; instead it is used + # with Binding#block_exec method. + + class BlockEnvironment < BasicObject + + def initialize(context, *args, &block) + @context = context + @args = args + @block = block + end + + def call + instance_exec(*@args, &@block) + end + + def method_missing(name) + eval(name.to_s, @context) rescue super + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/cgi.rb b/bin/gems/facets-3.1.0/lib/standard/facets/cgi.rb new file mode 100644 index 00000000..7d296897 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/cgi.rb @@ -0,0 +1,6 @@ +require 'cgi' + +require 'facets/cgi/marshal' +require 'facets/cgi/escape_html' + + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/cgi/esc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/cgi/esc.rb new file mode 100644 index 00000000..d9e65a84 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/cgi/esc.rb @@ -0,0 +1,11 @@ +require 'facets/cgi/escape_html' + +class CGI + + # Instance level method for {CGI::escape_html}. + + def esc(string, *modes) + self.class.escape_html(string, *modes) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/cgi/escape_html.rb b/bin/gems/facets-3.1.0/lib/standard/facets/cgi/escape_html.rb new file mode 100644 index 00000000..61e931c6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/cgi/escape_html.rb @@ -0,0 +1,63 @@ +require 'cgi' + +class CGI + + # Extends `#escape_html` to support escape modes. By default all strings + # are escaped on `&`, `>` and `<`. Add the `:nonstandard` mode to omit + # this conversion. + # + # If no mode is given then the `:default` mode is used. + # + # Available modes include: + # * `:quote` - escapes single and double quotes + # * `:newlines` - escapes newline characters (\r and \n) + # * `:ampersand` - escapes the ampersand sign + # * `:brackets` - escapes less-than and greater-than signs + # * `:default` - escapes double quotes + # + # @example + # escape_html("") #=> "<tag>" + # escape_html("Example\nString", :newlines) #=> "Example String" + # escape_html("\"QUOTE\"", false) #=> "\"QUOTE\"" + # + def self.escape_html(string, *modes) + modes << :defualt if modes.empty? + + unless modes.include?(:nonstandard) + string = string.gsub(/&/, '&').gsub(/>/, '>').gsub(//, '>').gsub(/\n} + end + + # Create an hidden input field through which an object can can be marshalled. + # This makes it very easy to pass form data between requests. + def marshal_from_cgi(name) + if self.params.has_key?("__#{name}__") + return Marshal.load(CGI.unescape(self["__#{name}__"][0])) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/cli.rb b/bin/gems/facets-3.1.0/lib/standard/facets/cli.rb new file mode 100644 index 00000000..25b58b8d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/cli.rb @@ -0,0 +1,54 @@ +module Kernel + private + # + # CLI is based on Clap library + # Copyright (c) 2010 Michel Martens + # + def cli(*args) + opts = args.pop + argv = (args.first || ARGV).dup + args = [] + + # Split option aliases. + opts = opts.inject({}) do |h,(k,v)| + k.to_s.split(/\s+/).each{|o| h[o]=v}; h + end + + # Convert single dash flags into multiple flags. + argv = argv.inject([]) do |a, v| + if v[0,1] == '-' && v[1,1] != '-' + a.concat(v[1..-1].chars.map{|c| "-#{c}"}) + else + a << v + end + a + end + + while argv.any? + item = argv.shift + flag = opts[item] + + if flag + # Work around lambda semantics in 1.8.7. + arity = [flag.arity, 0].max + + # Raise if there are not enough parameters + # available for the flag. + if argv.size < arity + raise ArgumentError + end + + # Call the lambda with N items from argv, + # where N is the lambda's arity. + flag.call(*argv.shift(arity)) + else + + # Collect the items that don't correspond to + # flags. + args << item + end + end + + args + end +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/cloneable.rb b/bin/gems/facets-3.1.0/lib/standard/facets/cloneable.rb new file mode 100644 index 00000000..760a5757 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/cloneable.rb @@ -0,0 +1,67 @@ +# Clonable provides a standard basis for adding deep cloneablity to a class +# via the standard #dup and #clone methods. +# +# Cloneable was originally ported from Jim Weirich's Rake. +# The current version is the work of Ken Bloom. +# +# DEPRECATED: A better approach is to provide a #deep_dup and and a #deep_clone, +# then if a class needs these for #dup and #clone they can just alias them. +# +# CREDIT: Ken Bloom + +module Cloneable + + def initialize_copy(sibling) + # First duplicate my superclass' state. Note that if it's duplicating + # instance variables, this will be overwritten, but this is important + # because we could be dealing with a C extension with state hidden from + # the Ruby interpreter. + super + + # We want to know if we're being dup'ed or clone'd, because we want to + # preserve the state of our internals the same way our state is being + # preserved. (If we can't figure it out, we'll just use #dup.) + operation = ( + copy_call = caller.find{|x| x !~ /'initialize_copy'/} + copy_match = copy_call.match(/`(dup|clone)'/) + copy_match ? copy_match[1] : :dup + ) + + sibling.instance_variables.each do |ivar| + value = sibling.instance_variable_get(ivar) + + # Set my instance variable to be a #dup or #clone + # or my sibling, depending on what's happening to me right now. + instance_variable_set(ivar, value.send(operation)) + end + end + + # TODO: Is there a more robust means of determining if clone or dup is used? + #def clone + # @_copy_operation = :clone + # super + #end + # + #def dup + # @_copy_operation = :dup + # super + #end + +end + + + +# OLD VERSION + +#module Cloneable +# def clone +# sibling = self.class.new +# instance_variables.each do |ivar| +# value = self.instance_variable_get(ivar) +# sibling.instance_variable_set(ivar, value.dup) #rake_dup) +# end +# sibling +# end +# alias_method :dup, :clone +#end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/continuation.rb b/bin/gems/facets-3.1.0/lib/standard/facets/continuation.rb new file mode 100644 index 00000000..1780dce8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/continuation.rb @@ -0,0 +1,56 @@ +if defined?(Continuation) + + # = Continuation Extension + # + # Creates a continuation in a way that is easier to use than callcc. + # On the initial call this will return the created Continuation and + # the arguments you gave to Continuation.create in an Array. If you + # then issue .call() on the Continuation execution will jump back to + # the point of time where you initially invoked Continuation.create, + # but this time it will return the Continuation and the arguments + # you supplied in an Array. + # + # You can supply a block instead of default arguments which will + # cause that block to be executed once and its result to be returned + # along side the created Continuation, but this form is confusing + # and does only rarely make sense. + # + # # Count from 0 to 10 + # cc, counter = Continuation.create(0) + # counter #~> 0..10 + # cc.call(counter + 1) if counter < 10 + # + # # Implement something similar to Array#inject using Continuations. + # # For simplicity's sake, this is not fully compatible with the real + # # inject. Make sure that you understand Array#inject before you try + # # to understand this. + # class ::Array + # def cc_inject(value = nil) + # copy = self.clone + # cc, result, item = Continuation.create(value, nil) + # next_item = copy.shift + # if result and item + # # Aggregate the result using the block. + # cc.call(yield(result, item), next_item) + # elsif next_item + # # item not yet set and Array is not empty: + # # This means we did not get a value and thus need to use the + # # first item from the Array before we can start using the + # # block to aggregate the result. + # cc.call(next_item, result) + # end + # + # return result + # end + # end + # [1,2,3,4,5].cc_inject { |acc, n| acc + n } # => 15 + # + def Continuation.create(*args, &block) + args = [args] if not args.nil? and not args.is_a? Array # 1.6.8 compatibility + cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?} + result ||= args + return *[cc, *result] + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/date.rb b/bin/gems/facets-3.1.0/lib/standard/facets/date.rb new file mode 100644 index 00000000..47cf3038 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/date.rb @@ -0,0 +1,433 @@ +require 'date' +require 'facets/time/stamp' + +# = Date +# +# This new version of Date extension has been largely improved by +# porting some of the methods used by ActiveSupport. The old version +# already had much in common with the Active Support library, so it +# was decided to take it a step further in that direction for the +# sake of interoparability. +# +# Hopefully most of these methods will find there way into Ruby's +# own standard library eventually. +# +# The biggest difference with ActiveSupport is the lack of many +# of the "English-esque" methods, and that we use #stamp with +# Date::FORMAT, instead of #to_formmated_s with Date::DATE_FORMATS. +# We do not override the standard #to_s method like ActiveSupport does. + +class Date + + FORMAT = { + :short => "%e %b", + :long => "%B %e, %Y", + :db => "%Y-%m-%d", + :number => "%Y%m%d", + :rfc822 => "%e %b %Y", + :default => "%Y-%m-%d", + nil => "%Y-%m-%d" + } + + # Returns a new Date representing the date 1 day ago (i.e. yesterday's date). + def self.yesterday + ::Date.today.yesterday + end + + # Returns a new Date representing the date 1 day after today (i.e. tomorrow's date). + def self.tomorrow + ::Date.today.tomorrow + end + + # Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today. + def self.current + ::Time.zone_default ? ::Time.zone.today : ::Date.today + end + + # A method to keep Time, Date and DateTime instances interchangeable + # on conversions. In this case, it simply returns +self+. + def to_date + self + end unless method_defined?(:to_date) # 1.9+ ? + + # Converts a Date instance to a DateTime, where the time is set to the beginning of the day + # and UTC offset is set to 0. + # + # date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007 + # date.to_datetime # Sat, 10 Nov 2007 00:00:00 0000 + # + def to_datetime + ::DateTime.civil(year, month, day, 0, 0, 0, 0) + end unless method_defined?(:to_datetime) # 1.9+ ? + + # Converts a Date instance to a Time, where the time is set to the beginning of the day. + # The timezone can be either :local or :utc (default :local). + # + # date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007 + # + # date.to_time # Sat Nov 10 00:00:00 0800 2007 + # date.to_time(:local) # Sat Nov 10 00:00:00 0800 2007 + # + # date.to_time(:utc) # Sat Nov 10 00:00:00 UTC 2007 + # + def to_time(form=:local) + ::Time.send(form, year, month, day) + ##::Time.send("#{form}_time", year, month, day) + end + + # + def xmlschema + to_time.xmlschema + end + + # Returns the number of days in the date's month. + # + # Date.new(2004,2).days_in_month #=> 29 + # + # CREDIT: Ken Kunz. + def days_in_month + Date.civil(year, month, -1).day + end + + def days_of_month + (1..days_in_month).to_a + end + + # Get the month name for this date object + # + # CREDIT: Benjamin Oakes + def month_name + MONTHNAMES[self.month] + end + + # Convert to a formatted string. See DATE_FORMATS for predefined formats. + # + # This method is aliased to to_s. + # + # date = Date.new(2007, 11, 10) # Sat, 10 Nov 2007 + # + # date.stamp(:db) # => "2007-11-10" + # date.stamp(:short) # => "10 Nov" + # date.stamp(:long) # => "November 10, 2007" + # date.stamp(:rfc822) # => "10 Nov 2007" + # + # == Adding your own formats to stamp + # You can add your own formats to the Date::FORMAT hash. + # Use the format name as the hash key and a strftime string + # as the value. Eg. + # + # Date::FORMAT[:month_and_year] = "%B %Y" + # + def stamp(format=:default) + if formatter = FORMAT[format] + strftime(formatter) + else + to_s + end + end + + ## Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" + ##def inspect + ## strftime("%a, %d %b %Y") + ##end + + # Provides precise Date calculations for years, months, and days. + # The +options+ parameter takes a hash with any of these keys: + # :years, :months, :weeks, :days. + def advance(options) + d = self + d = d >> options.delete(:years) * 12 if options[:years] + d = d >> options.delete(:months) if options[:months] + d = d + options.delete(:weeks) * 7 if options[:weeks] + d = d + options.delete(:days) if options[:days] + d + end + + # Returns a new Date where one or more of the elements have been changed + # according to the +options+ parameter. + # + # Date.new(2007, 5, 12).change(:day=>1) # Date.new(2007, 5, 1) + # Date.new(2007, 5, 12).change(:year=>2005, :month=>1) # Date.new(2005, 1, 12) + # + def change(options) + ::Date.new( + options[:year] || self.year, + options[:month] || self.month, + options[:day] || self.day + ) + end + + # Converts Date to a Time (or DateTime if necessary) with the time portion + # set to the beginning of the day (0:00) and then subtracts the specified + # number of seconds + def ago(seconds) + to_time.since(-seconds) + end + + # Converts Date to a Time (or DateTime if necessary) with the time portion + # set to the beginning of the day (0:00) and then adds the specified number + # of seconds. + def since(seconds) + to_time.since(seconds) + end + alias :in :since + + # Converts Date to a Time (or DateTime if necessary) with the time portion + # set to the beginning of the day (0:00). + def beginning_of_day + to_time + end + alias :midnight :beginning_of_day + + # Convenience method which returns a new Date/DateTime representing the + # time 1 day ago. + def yesterday + self - 1 + end + + # Convenience method which returns a new Date/DateTime representing + # the time 1 day since the instance time. + def tomorrow + self + 1 + end + +end + + +class DateTime + + # + def self.local_offset + ::Time.local(2007).utc_offset.to_r / 86400 + end + + def future? + self > ::DateTime.current + end + + def past? + self < ::DateTime.current + end + + # Converts self to a Ruby Date object; time portion is discarded + def to_date + ::Date.new(year, month, day) + end + + # Attempts to convert self to a Ruby Time object; returns self if + # out of range of Ruby Time class. If self has an offset other than 0, + # self will just be returned unaltered, since there's no clean way + # to map it to a Time. + def to_time + self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self + end + + # To be able to keep Times, Dates and DateTimes interchangeable on conversions + def to_datetime + self + end + + # Convert to a formatted string. See Time::FORMAT for predefined formats. + # + # This method is aliased to to_s. + # + # datetime = DateTime.civil(2007,12,4,0,0,0,0) # Tue, 04 Dec 2007 00:00:00 +0000 + # + # datetime.stamp(:db) # => "2007-12-04 00:00:00" + # datetime.stamp(:db) # => "2007-12-04 00:00:00" + # datetime.stamp(:number) # => "20071204000000" + # datetime.stamp(:short) # => "04 Dec 00:00" + # datetime.stamp(:long) # => "December 04, 2007 00:00" + # datetime.stamp(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000" + # + # == Adding your own datetime formats to stamp + # + # DateTime formats are shared with Time. You can add your own to the + # Time::FORMAT hash. Use the format name as the hash key and + # a strftime string as the value. Eg. + # + # Time::FORMAT[:month_and_year] = "%B %Y" + # + def stamp(format=:default) + if formatter = ::Time::FORMAT[format] + strftime(formatter) + else + to_s + end + end + + # Seconds since midnight: DateTime.now.seconds_since_midnight + def seconds_since_midnight + self.sec + (self.min * 60) + (self.hour * 3600) + end + + # Returns a new DateTime where one or more of the elements have been + # changed according to the +options+ parameter. The time options + # (hour, minute, sec) reset cascadingly, so if only the hour is + # passed, then minute and sec is set to 0. If the hour and + # minute is passed, then sec is set to 0. + def change(options) + ::DateTime.civil( + options[:year] || self.year, + options[:month] || self.month, + options[:day] || self.day, + options[:hour] || self.hour, + options[:min] || (options[:hour] ? 0 : self.min), + options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec), + options[:offset] || self.offset, + options[:start] || self.start + ) + end + + # Uses Date to provide precise Time calculations for years, months, and days. + # The +options+ parameter takes a hash with any of these keys: :years, + # :months, :weeks, :days, :hours, + # :minutes, :seconds. + def advance(options) + d = to_date.advance(options) + datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) + seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600 + seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance) + end + + # Returns a new DateTime representing the time a number of seconds ago + # Do not use this method in combination with x.months, use months_ago instead! + def ago(seconds) + self.since(-seconds) + end + + # Returns a new DateTime representing the time a number of seconds since the instance time + # Do not use this method in combination with x.months, use months_since instead! + def since(seconds) + self + Rational(seconds.round, 86400) + end + alias :in :since + + # Returns a new DateTime representing the start of the day (0:00) + def beginning_of_day + change(:hour => 0) + end + alias :midnight :beginning_of_day + + # Returns a new DateTime representing the end of the day (23:59:59) + def end_of_day + change(:hour => 23, :min => 59, :sec => 59) + end + + # Adjusts DateTime to UTC by adding its offset value; offset is set to 0 + # + # Example: + # + # DateTime.civil(2005,2,21,10,11,12,Rational(-6, 24)) # Mon, 21 Feb 2005 10:11:12 -0600 + # DateTime.civil(2005,2,21,10,11,12,Rational(-6, 24)).utc # Mon, 21 Feb 2005 16:11:12 +0000 + # + def utc + new_offset(0) + end + alias_method :getutc, :utc + + # Returns true if offset == 0 + def utc? + offset == 0 + end + + # Returns the offset value in seconds + def utc_offset + (offset * 86400).to_i + end + + # Converts datetime to an appropriate format for use in XML + def xmlschema + strftime("%Y-%m-%dT%H:%M:%S%Z") + end unless method_defined?(:xmlschema) # 1.9+ ? + + # Converts self to a floating-point number of seconds since the Unix epoch + def to_f + days_since_unix_epoch = self - ::DateTime.civil(1970) + (days_since_unix_epoch * 86_400).to_f + end + +end + + +class Time + + # + def self.local_time(*args) + time_with_datetime_fallback(:local, *args) + end + + # + def self.utc_time(*args) + time_with_datetime_fallback(:utc, *args) + end + + # + def self.time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0) + ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec) + rescue + offset = utc_or_local.to_sym == :local ? ::DateTime.local_offset : 0 + ::DateTime.civil(year, month, day, hour, min, sec, offset) + end + + public :to_date + public :to_datetime + + # Converts a Time object to a Date, dropping hour, minute, and second precision. + # + # my_time = Time.now # Mon Nov 12 22:59:51 -0500 2007 + # my_time.to_date # Mon, 12 Nov 2007 + # + # your_time = Time.parse("1/13/2009 1:13:03 P.M.") # Tue Jan 13 13:13:03 -0500 2009 + # your_time.to_date # Tue, 13 Jan 2009 + # + def to_date + ::Date.new(year, month, day) + end + + ## # Convert a Time to a Date. Time is a superset of Date. + ## # It is the year, month and day that are carried over. + ## + ## def to_date + ## require 'date' # just in case + ## jd = Date.__send__(:civil_to_jd, year, mon, mday, Date::ITALY) + ## Date.new!(Date.__send__(:jd_to_ajd, jd, 0, 0), 0, Date::ITALY) + ## end + + + # Converts a Time instance to a Ruby DateTime instance, preserving UTC offset. + # + # my_time = Time.now # Mon Nov 12 23:04:21 -0500 2007 + # my_time.to_datetime # Mon, 12 Nov 2007 23:04:21 -0500 + # + # your_time = Time.parse("1/13/2009 1:13:03 P.M.") # Tue Jan 13 13:13:03 -0500 2009 + # your_time.to_datetime # Tue, 13 Jan 2009 13:13:03 -0500 + # + def to_datetime + ::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400)) + end + +end + + +class String + + # + def to_time(form = :utc) + ::Time.__send__("#{form}_time", *::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec).map{|arg| arg || 0 }) + end + + # Convert string to DateTime. + def to_datetime + date = ::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec).map { |arg| arg || 0 } + ::DateTime.civil(*date) + end + + # Parse data from string. + def to_date + #::Date::civil(*ParseDate.parsedate(self)[0..2]) + ::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/digest.rb b/bin/gems/facets-3.1.0/lib/standard/facets/digest.rb new file mode 100644 index 00000000..72a4b3e5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/digest.rb @@ -0,0 +1,2 @@ +require 'facets/digest/base64digest' +require 'facets/digest/salted_digest' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/digest/base64digest.rb b/bin/gems/facets-3.1.0/lib/standard/facets/digest/base64digest.rb new file mode 100644 index 00000000..9d86ece8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/digest/base64digest.rb @@ -0,0 +1,45 @@ +require 'digest' + +module Digest + + module Instance + + # For Ruby < 1.9.2 + + unless instance_methods.include? :base64digest + + # From Ruby 1.9.2 source + def base64digest(str = nil) + [str ? digest(str) : digest].pack('m0') + end + + end + + unless instance_methods.include? :base64digest! + + # From Ruby 1.9.2 source + def base64digest! + [digest!].pack('m0') + end + + end + + end + + class Class + + # For Ruby < 1.9.2 + + unless methods.include? :base64digest + + # From Ruby 1.9.2 source + def self.base64digest(str, *args) + [self.digest(str, *args)].pack('m0') + end + + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/digest/salted_digest.rb b/bin/gems/facets-3.1.0/lib/standard/facets/digest/salted_digest.rb new file mode 100644 index 00000000..175c3a6d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/digest/salted_digest.rb @@ -0,0 +1,44 @@ +require 'digest' +require 'facets/string/random_binary' + +module Digest + + module Instance + # CREDIT: Guido De Rosa + def salted_digest(str='', salt=:auto) + if salt == :auto + salt = String.random_binary(digest_length) + end + digest(str + salt) + salt + end + + # CREDIT: Guido De Rosa + def salted_hexdigest(str, salt) + Digest.hexencode(salted_digest(str, salt)) + end + + # CREDIT: Guido De Rosa + def salted_base64digest(str, salt) + [salted_digest(str, salt)].pack('m0') + end + end + + class Class + # CREDIT: Guido De Rosa + def self.salted_digest(str, salt=:auto, *args) + new(*args).salted_digest(str, salt) + end + + # CREDIT: Guido De Rosa + def self.salted_hexdigest(str, salt=:auto, *args) + new(*args).salted_hexdigest(str, salt) + end + + # CREDIT: Guido De Rosa + def self.salted_base64digest(str, salt=:auto, *args) + new(*args).salted_base64digest(str, salt) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/enumargs.rb b/bin/gems/facets-3.1.0/lib/standard/facets/enumargs.rb new file mode 100644 index 00000000..df267cab --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/enumargs.rb @@ -0,0 +1,191 @@ +module Enumerable + # This is a simple reimplementation of the core Enumerable module + # to allow its methods to take and pass-on arbitrary arguments to the + # underlying #each call. This library uses Enumerator and scans + # Enumerable so it can alwasy stay in sync. + # + # NOTE: Any Enumerable method with a negative arity cannot pass arguments + # due to ambiguity in the argument count. So the methods #inject and #zip + # do NOT work this way, but simply work as they do in Enumerable. However, + # The methods #find and #detect have been made modified to work by removing + # its rarely used optional parameter and providing instead an optional + # keyword parameter (:ifnone => ...). Please keep these difference in mind. + # + # Example + # require 'enumargs' + # + # class T + # include Enumerable::Argumentable + # def initialize(arr) + # @arr = arr + # end + # def each(n) + # arr.each{ |e| yield(e+n) } + # end + # end + # + # t = T.new([1,2,3]) + # t.collect(4) + # #=> [5,6,7] + # + module Argumentable + + # Helper method to wrap Enumerable methods. + def self.wrap_enumerable_method( methodname ) + m = methodname + meth = Enumerable.instance_method(m) + arity = meth.arity + + case arity <=> 0 + when 0 + class_eval %{ + def #{m}( *args, &yld ) + enum_for(:each, *args).#{m}( &yld ) + end + } + when 1 + class_eval %{ + def #{m}( *args, &yld ) + args, each_args = args[0...#{arity}], args[#{arity}..-1] + enum_for(:each, *each_args).#{m}( *args, &yld ) + end + } + else + # this branch is used when the method has a variable number of arguments + # resulting in an arity of -1. Right now this is bugged as it does + # not pass the argument to the each, and always passes the argument + # to the method. This makes methods like .min amdn .max to act + # in an unexpected manner. + class_eval %{ + def #{m}( *args, &yld ) + enum_for(:each).#{m}( *args, &yld ) + end + } + end + end + + # Wrap all Enumerable's public instance methods + Enumerable.instance_methods(false).each do |m| + wrap_enumerable_method( m ) + end + + # Support for #to_a. + # + def to_a(*args) + #map(*args){ |x| x } + enum_for(:each, *args).to_a + end + + # Make exception for #find (a negative arity method) to accept + # keyword argument. + # + # ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... } + # ObjectSpace.find(Class, :ifnone=>lambda{1}) { |e| ... } + # + def find(*args, &yld) # future use **keys ? + if Hash === args.last and args.last.key?(:ifnone) + ifnone = args.last.delete(:ifnone) + args.pop if args.last.empty? + enum_for(:each, *args).find( ifnone, &yld ) + else + enum_for(:each, *args).find( &yld ) + end + end + + alias_method :detect, :find + + end + + # DEPRECATED: Module alias for old name. + Arguments = Argumentable +end + + +=begin OLD CODE + module EnumerableArgs + + def collect(*args) # :yield: + a = [] + each(*args){ |n| a << yield(n) } + a + end + alias_method( :map, :collect ) + + def detect(*args) # :yield: + each(*args){ |n| return n if yield(n) } + nil + end + alias_method( :find, :detect ) + + def each_with_index(*args) + i=0 + each(*args){ |*n| n << i; yield(*n); i+=1 } + self + end + + def to_a(*args) + a = [] + each(*args){ |n| a << n } + a + end + alias_method( :entries, :to_a ) + + # An additional method not part of standard Enumerable. + # The regular version of this method can be found in Facets, + # but it is a bit more advanced then this one. + # At some point they need to be put into sync. + def each_slice(*args, &yld) + a = []; s = [] + ar = yld.arity.abs + each(*args){ |n| + s << n + if s.length >= ar + yld.call(*s) + s = [] + end + } + a + end + alias_method( :each_by, :each_slice ) + + def select(*args) # :yield: + a = [] + each(*args){ |n| a << n if yield(n) } + a + end + alias_method( :find_all, :select ) + + def grep(pattern, *args) + a = [] + each(*args){ |n| a << (block_given? ? yield(n) : n) if pattern === n } + a + end + + def include?(anObj, *args) + each(*args){ |n| return true if anObj == n } + false + end + alias_method( :member?, :include? ) + + def max(*args) + to_a(*args).max + end + + def min(*args) + to_a(*args).min + end + + def reject(*args) + a = [] + each(*args){ |n| a << n if ! yield(n) } + a + end + + def sort(*args) + # TODO + end + + end +=end + +# Copyright (c) 2004 Rubyworks (BSD-2-Clause) diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/equitable.rb b/bin/gems/facets-3.1.0/lib/standard/facets/equitable.rb new file mode 100644 index 00000000..679e2627 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/equitable.rb @@ -0,0 +1,76 @@ +# = Equitable +# +# This mixin provides methods of equality based +# on a single #identity method which must return +# a list of accessors used as the identity keys. +# +# It also provides a "shortcut" for creating the +# #identity method based on given accessors and returns +# the Equitable module for inclusion. +# +# include Equitable(:a, :b) +# +# is equivalent to including a module containing: +# +# def ==(other) +# self.a == other.a && self.b == other.b +# end +# +# def eql?(other) +# self.a.eql?(other.a) && self.b.eql?(other.b) +# end +# +# def hash() +# self.a.hash ^ self.b.hash +# end +# +module Equitable + + def self.identify(base, *accessors) + base.send(:define_method, :identity){ accessors } + self + end + + def ==(o) + identity.all?{ |a| send(a) == o.send(a) } + end + + def eql?(o) + identity.all?{ |a| send(a).eql?(o.send(a)) } + end + + def hash + identity.inject(0){ |memo, a| memo ^ send(a).hash } + end + +end + +class Module + + # This function provided a "shortcut" for creating the + # #identity method based on given accessors and returns + # the Equitable module for inclusion. + # + # include Equitable(:a, :b) + # + # is equivalent to including a module containing: + # + # def ==(other) + # self.a == other.a && self.b == other.b + # end + # + # def eql?(other) + # self.a.eql?(other.a) && self.b.eql?(other.b) + # end + # + # def hash() + # self.a.hash ^ self.b.hash + # end + # + + def Equitable(*accessors) + Equitable.identify(self, *accessors) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/erb.rb b/bin/gems/facets-3.1.0/lib/standard/facets/erb.rb new file mode 100644 index 00000000..eb564a39 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/erb.rb @@ -0,0 +1,66 @@ +require 'erb' + +# = OpenTemplate +# +# The Erb OpenTemplate provides a quick and convenient way to +# create a clean rendering space with the desired responses. +# +# Ruby 1.8.6 or less can't handle object scope methods with blocks. +# +# TODO: This might make a good addon library. Just add +# require 'erb' to the erb_result method? Call it OpenResponse? +# +class ERB::OpenTemplate + + # TODO: Should we do this? Perhaps offer it as an option? + instance_methods.each do |m| + undef_method(m) unless /^(__|instance_|inspect$|extend$|object_id$)/ =~ m.to_s + end + + # + def initialize(*objs_ioc) + ioc = Hash===objs_ioc.last ? objs_ioc.pop : {} + objs = objs_ioc + + mods = [] + + objs.each do |obj| + mod = Module.new + obj.public_methods.each do |m| + mod.module_eval do + #define_method(m){ |*a,&b| obj.__send__(m,*a,&b) } + define_method(m, &obj.method(m).to_proc) + end + end + mods << mod + end + + mod = Module.new + ioc.each do |k,v| + mod.module_eval do + define_method(k){ v } + end + end + mods << mod + + extend *mods.reverse + end + + # + def erb_result(str) + ERB.new(str).result(binding) + end + + ## + ##def method_missing(sym, *args, &block) + ## #if @ioc.key?(sym) + ## # @ioc[sym] + ## if obj = @objs.find{ |o| o.respond_to?(sym) } + ## obj.__send__(sym, *args, &block) + ## else + ## super + ## end + ##end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils.rb new file mode 100644 index 00000000..ce459ebf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils.rb @@ -0,0 +1,13 @@ +# TODO: Deprecate #safe_ln, if #ln has been fixed to do this. + +require 'fileutils' +require 'facets/fileutils/amass' +require 'facets/fileutils/cp_rx' +require 'facets/fileutils/ln_r' +require 'facets/fileutils/outofdate' +require 'facets/fileutils/safe_ln' +require 'facets/fileutils/slice' # includes head and tail +require 'facets/fileutils/stage' +require 'facets/fileutils/wc' +require 'facets/fileutils/whereis' +require 'facets/fileutils/which' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/amass.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/amass.rb new file mode 100644 index 00000000..08e4f3ba --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/amass.rb @@ -0,0 +1,34 @@ +module FileUtils + + module_function + + # An intergrated glob like method that takes a set of include globs, + # exclude globs and ignore globs to produce a collection of paths. + # + # The ignore_globs differ from exclude_globs in that they match by + # the basename of the path rather than the whole pathname. + # + # TODO: Should ignore be based on any portion of the path, not just the basename? + # + def amass(include_globs, exclude_globs=[], ignore=[]) + + include_files = [include_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq + exclude_files = [exclude_globs].flatten.map{ |g| Dir.glob(g) }.flatten.uniq + + include_files = include_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive! + exclude_files = exclude_files.map{ |f| File.directory?(f) ? File.join(f, '**/*') : f } # Recursive! + + include_files = include_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq + exclude_files = exclude_files.flatten.map{ |g| Dir.glob(g) }.flatten.uniq + + files = include_files - exclude_files + + files = files.reject{ |f| [ignore].flatten.any?{ |x| File.fnmatch?(x, File.basename(f)) } } + + files + end + + # Make public (for all submodules too). + public :amass + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/cp_rx.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/cp_rx.rb new file mode 100644 index 00000000..651877f6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/cp_rx.rb @@ -0,0 +1,44 @@ +module FileUtils + + module_function + + # Both of these are modified from the implementations in fileutils.rb from Ruby 1.9.1p378. + + # Like FileUtils.cp_r, but takes a filter proc that can return false to skip a file: + # + # cp_rx "bigDirectoryTree", "dest", {:noop => true} do |name| + # /dontCopyThis$/.match(name) + # end + # + # Note that if the filter rejects a subdirectory then everything within that + # subdirectory is automatically skipped as well. + + def cp_rx(src, dest, options = {}, &filter) + fu_check_options(options, OPT_TABLE['cp_r']) + if options[:verbose] + fu_output_message("cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}") + end + return if options[:noop] + fu_each_src_dest(src, dest) do |s, d| + copy_entryx(s, d, filter, options[:preserve], options[:dereference_root], options[:remove_destination]) + end + end + + # Like FileUtils.copy_entry, but takes a filter proc that can return false to skip a file. + # + # Note that if the filter rejects a subdirectory then everything within that + # subdirectory is automatically skipped as well. + + def copy_entryx(src, dest, filter, preserve = false, dereference_root = false, remove_destination = false) + Entry_.new(src, nil, dereference_root).traverse do |ent| + if filter.call(ent.path) then + destent = Entry_.new(dest, ent.rel, false) + File.unlink destent.path if remove_destination && File.file?(destent.path) + ent.copy destent.path + ent.copy_metadata(destent.path) if preserve + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/head.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/head.rb new file mode 100644 index 00000000..21adb4e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/head.rb @@ -0,0 +1 @@ +require 'facets/fileutils/slice' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/ln_r.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/ln_r.rb new file mode 100644 index 00000000..6a2a93c3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/ln_r.rb @@ -0,0 +1,99 @@ +module FileUtils + + unless method_defined?(:ln_r) + + # + # Options: noop verbose dereference_root remove_destination + # + # Hard link +src+ to +dest+. If +src+ is a directory, this method links + # all its contents recursively. If +dest+ is a directory, links + # +src+ to +dest/src+. + # + # +src+ can be a list of files. + # + # # Installing ruby library "mylib" under the site_ruby + # FileUtils.rm_r site_ruby + '/mylib', :force + # FileUtils.ln_r 'lib/', site_ruby + '/mylib' + # + # # Examples of copying several files to target directory. + # FileUtils.ln_r %w(mail.rb field.rb debug/), site_ruby + '/tmail' + # FileUtils.ln_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true + # + # # If you want to copy all contents of a directory instead of the + # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, + # # use following code. + # FileUtils.ln_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest, + # # but this doesn't. + # + # TODO: Why --remove-destination and not just --force? + def ln_r(src, dest, options = {}) + fu_check_options options, OPT_TABLE['ln_r'] + fu_output_message "ln -r#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] + return if options[:noop] + options = options.dup + options[:dereference_root] = true unless options.key?(:dereference_root) + fu_each_src_dest(src, dest) do |s, d| + link_entry s, d, options[:dereference_root], options[:remove_destination] + end + end + module_function :ln_r + + OPT_TABLE = {} unless const_defined?(:OPT_TABLE) + OPT_TABLE['ln_r'] = [:noop, :verbose, :dereference_root, :remove_destination] + + # + # Hard links a file system entry +src+ to +dest+. + # If +src+ is a directory, this method links its contents recursively. + # + # Both of +src+ and +dest+ must be a path name. + # +src+ must exist, +dest+ must not exist. + # + # If +dereference_root+ is true, this method dereference tree root. + # + # If +remove_destination+ is true, this method removes each destination file before copy. + # + def link_entry(src, dest, dereference_root = false, remove_destination = false) + Entry_.new(src, nil, dereference_root).traverse do |ent| + destent = Entry_.new(dest, ent.rel, false) + File.unlink destent.path if remove_destination && File.file?(destent.path) + ent.link destent.path + end + end + module_function :link_entry + + class Entry_ #:nodoc: + def link(dest) + case + when directory? + if !File.exist?(dest) and descendant_diretory?(dest, path) + raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest] + end + begin + Dir.mkdir dest + rescue + raise unless File.directory?(dest) + end + else file? + File.link path(), dest + end + end + + unless const_defined?(:DIRECTORY_TERM) + if File::ALT_SEPARATOR + DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)".freeze + else + DIRECTORY_TERM = "(?=/|\\z)".freeze + end + SYSCASE = File::FNM_SYSCASE.nonzero? ? "-i" : "" + end + + unless method_defined?(:descendant_diretory?) + def descendant_diretory?(descendant, ascendant) + /\A(?#{SYSCASE}:#{Regexp.quote(ascendant)})#{DIRECTORY_TERM}/ =~ File.dirname(descendant) + end + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/outofdate.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/outofdate.rb new file mode 100644 index 00000000..745737cb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/outofdate.rb @@ -0,0 +1,38 @@ +require 'fileutils' + +module FileUtils + module_function + + # The opposite of #uptodate? + def outofdate?(path, *sources) + #return true unless File.exist?(path) + ! uptodate?(path, sources.flatten) + end + + # Alias for #outofdate? + alias_method :out_of_date?, :outofdate? + + # Alias for #uptodate? + alias_method :up_to_date?, :uptodate? + + # # TODO: Does a path need updating, based on given +sources+? + # # This compares mtimes of give paths. Returns false + # # if the path needs to be updated. + # # + # # DEPRECATE: Is this in any way better than `! uptodate?` ? + # def out_of_date?(path, *sources) + # return true unless File.exist?(path) + # + # sources = sources.collect{ |source| Dir.glob(source) }.flatten + # mtimes = sources.collect{ |file| File.mtime(file) } + # + # return true if mtimes.empty? # TODO: This the way to go here? + # + # File.mtime(path) < mtimes.max + # end + + # Make public (for all submodules too). + public :outofdate? + public :out_of_date? + public :up_to_date? +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/safe_ln.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/safe_ln.rb new file mode 100644 index 00000000..c3fa1513 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/safe_ln.rb @@ -0,0 +1,27 @@ +require 'fileutils' + +module FileUtils + + module_function + + LINKING_SUPPORTED = [true] + + # Attempt to do a normal file link, but fall back + # to a copy if the link fails. + # + # CREDIT: Jim Weirich + def safe_ln(*args) + unless LINKING_SUPPORTED[0] + cp(*args) + else + begin + ln(*args) + rescue Errno::EOPNOTSUPP + LINKING_SUPPORTED[0] = false + cp(*args) + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/slice.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/slice.rb new file mode 100644 index 00000000..89fd6c7e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/slice.rb @@ -0,0 +1,55 @@ +require 'fileutils' + +module FileUtils + + module_function + + # In block form, yields lines +from+-+to+. In non-block form, returns + # an array of lines +from+-+to+: + # + # # Returns lines 8-12 of 'myfile' + # FileUtils.body("myfile",8,12) + # + # CREDIT Shashank Date, via Daniel Berger. + + def slice(filename,from,to) #:yield: + IO.readlines(filename)[from-1..to-1] + end + + # In block form, yields the first number of +lines+ of file +filename+. + # In non-block form, it returns an array of the first number of +lines+: + # + # # Returns first 10 lines of 'myfile' + # FileUtils.head("myfile", 10) + # + def head(filename,lines) #:yield: + a = [] + IO.foreach(filename){|line| + break if lines <= 0 + lines -= 1 + if block_given? + yield line + else + a << line + end + } + return a.empty? ? nil : a + end + + # In block form, yields the last number of +lines+ of file +filename+. + # In non-block form, it returns the lines as an array. + # + # Note that this method slurps the entire file, so I don't recommend it + # for very large files. If you want an advanced form of +tail+, I + # suggest using file-tail, by Florian Frank (available on the RAA): + # + # # Returns last 3 lines of 'myfile' + # FileUtils.tail("myfile",3) + # + # And no tail -f. + def tail(filename,lines) #:yield + IO.readlines(filename).reverse[0..lines-1].reverse + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/stage.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/stage.rb new file mode 100644 index 00000000..bbab7b7f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/stage.rb @@ -0,0 +1,66 @@ +require 'fileutils' + +module FileUtils + module_function + + # Stage by hard linking included files to a stage directory. + # + # stage_directory - Where to stage the files + # source_directory - Where to find files to stage + # files - Files to link in stage relative to source + # + # TODO: Rename to #link_stage or something less likely to name clash? + # TODO: Add options for :verbose, :noop and :dryrun ? + # + def stage(stage_directory, source_directory, files, options={}) + return stage_directory if options[:noop] || options[:dryrun] + + stage_directory, source_directory = stage_directory.to_s, source_directory.to_s + ## ensure existance of staging area + rm_r(stage_directory) if File.directory?(stage_directory) + mkdir_p(stage_directory) + ## link files into staging area + files.each do |f| + src = File.join(source_directory, f) + file = File.join(stage_directory, f) + if File.directory?(src) + mkdir_p(file) unless File.exist?(file) + else + fdir = File.dirname(file) + mkdir_p(fdir) unless File.exist?(fdir) + unless File.exist?(file) and File.mtime(file) >= File.mtime(src) + ln(src, file) #safe_ln ? + end + end + end + return stage_directory + end + + # Make public (for all submodules too). + public :stage + + module NoWrite + module_function + def stage(stage_directory, files, options={}) + options[:noop] = true + FileUtils.stage(stage_directory, files, options={}) + end + end + + module Verbose + module_function + def stage(stage_directory, files, options={}) + options[:verbose] = true + FileUtils.stage(stage_directory, files, options={}) + end + end + + module DryRun + module_function + def stage(stage_directory, files, options={}) + options[:dryrun] = true + FileUtils.stage(stage_directory, files, options={}) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/tail.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/tail.rb new file mode 100644 index 00000000..21adb4e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/tail.rb @@ -0,0 +1 @@ +require 'facets/fileutils/slice' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/wc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/wc.rb new file mode 100644 index 00000000..86966d41 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/wc.rb @@ -0,0 +1,63 @@ +require 'fileutils' + +module FileUtils + + module_function + + # With no arguments, returns a four element array consisting of the number + # of bytes, characters, words and lines in _filename_, respectively. + # + # Valid options are +bytes+, +characters+ (or just 'chars'), + # +words+ and +lines+: + # + # # Return the number of words in 'myfile' + # FileUtils.wc("myfile",'words') + # + # CREDIT: Daniel J. Berger + def wc(filename,option='all') + option.downcase! + valid = %w/all bytes characters chars lines words/ + + unless valid.include?(option) + raise "Invalid option: '#{option}'" + end + + n = 0 + if option == 'lines' + IO.foreach(filename){ n += 1 } + return n + elsif option == 'bytes' + File.open(filename){ |f| + f.each_byte{ n += 1 } + } + return n + elsif option == 'characters' || option == 'chars' + File.open(filename){ |f| + while f.getc + n += 1 + end + } + return n + elsif option == 'words' + IO.foreach(filename){ |line| + n += line.split.length + } + return n + else + bytes,chars,lines,words = 0,0,0,0 + IO.foreach(filename){ |line| + lines += 1 + words += line.split.length + chars += line.split('').length + } + File.open(filename){ |f| + while f.getc + bytes += 1 + end + } + return [bytes,chars,words,lines] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/whereis.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/whereis.rb new file mode 100644 index 00000000..4a9713de --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/whereis.rb @@ -0,0 +1,66 @@ +require 'fileutils' + +module FileUtils + + if const_defined?(:Win32Exts) + Win32Exts.concat %w{.exe .com .bat .cmd} + Win32Exts.uniq! + else + Win32Exts = %w{.exe .com .bat .cmd} + end + + module_function + + # In block form, yields each ((*program*)) within ((*path*)). In non-block + # form, returns an array of each ((*program*)) within ((*path*)). Returns + # (({nil})) if not found. + # + # On the MS Windows platform, it looks for executables ending with .exe, + # .bat and .com, which you may optionally include in the program name: + # + # FileUtils.whereis("ruby") #=> ['/usr/local/bin/ruby','/opt/bin/ruby'] + # + # CREDIT: Daniel J. Berger + + def whereis(prog, path=ENV['PATH']) #:yield: + dirs = [] + path.split(File::PATH_SEPARATOR).each{|dir| + # Windows checks against specific extensions + if File::ALT_SEPARATOR + if prog.include?('.') + f = File.join(dir,prog) + if File.executable?(f) && !File.directory?(f) + if block_given? + yield f.gsub(/\//,'\\') + else + dirs << f.gsub(/\//,'\\') + end + end + else + Win32Exts.find_all{|ext| + f = File.join(dir,prog+ext) + if File.executable?(f) && !File.directory?(f) + if block_given? + yield f.gsub(/\//,'\\') + else + dirs << f.gsub(/\//,'\\') + end + end + } + end + else + f = File.join(dir,prog) + # Avoid /usr/lib/ruby, for example + if File.executable?(f) && !File.directory?(f) + if block_given? + yield f + else + dirs << f + end + end + end + } + dirs.empty? ? nil : dirs + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/which.rb b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/which.rb new file mode 100644 index 00000000..35701b58 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/fileutils/which.rb @@ -0,0 +1,60 @@ +require 'fileutils' + +module FileUtils + + if const_defined?(:Win32Exts) + Win32Exts.concat %w{.exe .com .bat .cmd} + Win32Exts.uniq! + else + Win32Exts = %w{.exe .com .bat .cmd} + end + + module_function + + # Looks for the first occurrence of _program_ within _path_. + # + # On the MS Windows platform, it looks for executables ending with .exe, + # .bat and .com, which you may optionally include in the program name. + # Returns nil if not found. + # + # CREDIT: Daniel J. Berger, Michael Granger + # + #-- + # The which() method was adopted from Daniel J. Berger, via PTools + # which in in turn was adopted fromt the FileWhich code posted by + # Michael Granger on http://www.rubygarden.org. + #++ + def which(prog, path=ENV['PATH']) + path.split(File::PATH_SEPARATOR).each {|dir| + # Windows checks against specific extensions + if File::ALT_SEPARATOR + ext = Win32Exts.find{|ext| + if prog.include?('.') # Assume extension already included + f = File.join(dir,prog) + else + f = File.join(dir,prog+ext) + end + File.executable?(f) && !File.directory?(f) + } + if ext + # Use backslashes, not forward slashes + if prog.include?('.') # Assume extension already included + f = File.join( dir, prog ).gsub(/\//,'\\') + else + f = File.join( dir, prog + ext ).gsub(/\//,'\\') + end + return f + end + else + f = File.join(dir,prog) + # Avoid /usr/lib/ruby, for example + if File.executable?(f) && !File.directory?(f) + return File::join( dir, prog ) + end + end + } + nil + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/find.rb b/bin/gems/facets-3.1.0/lib/standard/facets/find.rb new file mode 100644 index 00000000..56c521a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/find.rb @@ -0,0 +1,2 @@ +require 'facets/find/select' + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/find/select.rb b/bin/gems/facets-3.1.0/lib/standard/facets/find/select.rb new file mode 100644 index 00000000..b313ad7e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/find/select.rb @@ -0,0 +1,16 @@ +require 'facets/enumerator' + +module Find + # Identical to find except select returns the matching files as an array. + # (find returns nil, which is not very useful if you actually wanted an array.) + # Calls the associated block with the name of every file and directory listed + # as arguments, then recursively on their subdirectories, and so on. + # Return a true (non-false) value from the block for every path that + # you want to be returned in the resulting array. You can still use Find.prune. + # + # CREDIT: Tyler Rick + def self.select(*paths, &block) + Enumerator.new(self, :find, *paths).select{|value| yield value} + end +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/gem/search.rb b/bin/gems/facets-3.1.0/lib/standard/facets/gem/search.rb new file mode 100644 index 00000000..39a8a309 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/gem/search.rb @@ -0,0 +1,18 @@ +require 'facets/gem/specification/current_specs' + +module Gem + + # Search RubyGems for matching paths in current gem versions. + def self.search(match, options={}) + matches = [] + Gem::Specification.current_specs.each do |spec| + glob = File.join(spec.lib_dirs_glob, match) + list = Dir[glob] #.map{ |f| f.untaint } + list = list.map{ |d| d.chomp('/') } + matches.concat(list) + end + matches + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/current_specs.rb b/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/current_specs.rb new file mode 100644 index 00000000..7efc49e8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/current_specs.rb @@ -0,0 +1,21 @@ +module Gem + class Specification + + # Return a list of active specs or latest version of spec if not active. + def self.current_specs + named = Hash.new{|h,k| h[k] = [] } + each{ |spec| named[spec.name] << spec } + list = [] + named.each do |name, vers| + if spec = vers.find{ |s| s.activated? } + list << spec + else + spec = vers.max{ |a,b| a.version <=> b.version } + list << spec + end + end + return list + end + + end +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/find_requireable_file.rb b/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/find_requireable_file.rb new file mode 100644 index 00000000..124ba185 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/gem/specification/find_requireable_file.rb @@ -0,0 +1,21 @@ +module Gem + class Specification + + # Return full path of requireable file given relative path. + def find_requireable_file(file) + root = full_gem_path + + require_paths.each do |lib| + base = File.join(root, lib, file) + Gem.suffixes.each do |suf| + path = "#{base}#{suf}" + return path if File.file? path + end + end + + return nil + end + + end +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/getoptlong.rb b/bin/gems/facets-3.1.0/lib/standard/facets/getoptlong.rb new file mode 100644 index 00000000..21521213 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/getoptlong.rb @@ -0,0 +1,59 @@ +require 'getoptlong' + +# = GetoptLong +# +# Ruby's standard GetoptLong class with an added DSL. +# +# opts = GetoptLong.new do +# reqs '--expect', '-x' +# flag '--help', '-h' +# end +# +# See GetoptLong::DSL for details. + +class GetoptLong + + alias :init :initialize + + # + def initialize(*arguments, &block) + if block_given? + raise ArgumentError unless arguments.empty? + arguments = DSL.new(&block).arguments + end + init(*arguments) + end + + # DSL-mode parser. + class DSL + attr :arguments + + def initialize(&block) + @arguments = [] + instance_eval(&block) + end + + # + def flag(*opts) + @arguments << (opts << GetoptLong::NO_ARGUMENT) + end + + # + def required(*opts) + @arguments << (opts << GetoptLong::REQUIRED_ARGUMENT) + end + + # + alias :reqs :required + + # + def optional(*opts) + @arguments << (opts << GetoptLong::OPTIONAL_ARGUMENT) + end + + # + alias :opts :optional + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/hash_builder.rb b/bin/gems/facets-3.1.0/lib/standard/facets/hash_builder.rb new file mode 100644 index 00000000..7cce83b5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/hash_builder.rb @@ -0,0 +1,46 @@ +# HashBuilder takes a procedure and builds a Hash out of it. +# +# The procedure must conform to a set of rules to be useful in this respect. +# They must either take an argument and use that argument to set values, or +# if no argument is taken then `#instance_eval` is used to evaluate the +# procedure such that each method represents a key. +# +class HashBuilder < BasicObject + + # + def initialize(hash={}, &block) + @hash = hash + + case block.arity + when 0 + instance_eval(&block) + else + block.call(self) + end + end + + # + def to_h + @hash + end + + # + def method_missing(s, *a, &b) + m = s.to_s + if a.empty? && !b + @hash[m.to_sym] + else + if b + @hash[m.chomp('=').to_sym] = HashBuilder.new(&b).to_h + else + if a.size > 1 + @hash[m.chomp('=').to_sym] = a + else + @hash[m.chomp('=').to_sym] = a.first + end + end + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/instantiable.rb b/bin/gems/facets-3.1.0/lib/standard/facets/instantiable.rb new file mode 100644 index 00000000..6a9fbf82 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/instantiable.rb @@ -0,0 +1,25 @@ +# = Instantiable +# +# Initialize modules, almost as if they were classes. +# +# Alows a module to be used much like a class, by defining +# a #new method that creates a class on demand. +# +module Instantiable + + def self.append_features(mod) + mod.extend self + end + + # Never use a class again! ;) + + def new(*args,&blk) + mod = self + @instantiable_class ||= Class.new{include mod} + @instantiable_class.new(*args,&blk) + end + +end + + + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/interval.rb b/bin/gems/facets-3.1.0/lib/standard/facets/interval.rb new file mode 100644 index 00000000..67683b2f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/interval.rb @@ -0,0 +1,277 @@ +require 'facets/multiton' +require 'facets/enumargs' +#require 'facets/infinity' + +# TODO: Tie in Infinity with Interval. + +# While Ruby support the Range class out of the box, is does not quite +# fullfil the role od a real Interval class. For instance, it does +# not support excluding the front sentinel. This is because Range also +# tries to do triple duty as a simple sequence and as a simple tuple-pair, +# thus limiting its potential as an Interval. The Interval class remedies +# the situation by commiting to interval behavior, and then extends the class' +# capabilites beyond that of the standard Range in ways that naturally +# fall out of that. +# +# Range depends on two methods: #succ and #<=>. If numeric ranges were the +# only concern, those could just as well be #+ and #<=>, but esoteric forms +# make that unfeasible --the obvious example being a String range. But a +# proper Interval class requires mathematical continuation, thus the Interval +# depends on #+ and #<=>, as well as #- as the inverse of #+. +# +# i = Interval.new(1,5) +# i.to_a #=> [1,2,3,4,5] +# +# i = Interval[0,5] +# i..step(2).to_a #=> [0,2,4] +# +# i = Interval[1,5] +# i.step(-1).to_a #=> [5,4,3,2,1] +# +# i = Interval[1,3] +# i.step(1,2).to_a #=> [1.0,1.5,2.0,2.5,3.0] +# +class Interval + + include Multiton + include Enumerable::Arguments + + # + def self.[]( *args ) + self.new( *args ) + end + + # + def initialize(first, last, exclude_first=false, exclude_last=false ) + raise ArgumentError, "bad value for interval" if first.class != last.class + @first = first + @last = last + @exclude_first = exclude_first + @exclude_last = exclude_last + @direction = (@last <=> @first) + end + + # Returns a two element array of first and last sentinels. + # + # (0..10).sentinels #=> [0,10] + # + def sentinels + return [@first, @last] + end + + # Returns the first or last sentinal of the interval. + def first ; @first ; end + def last ; @last ; end + + # + def exclude_first? ; @exclude_first ; end + def exclude_last? ; @exclude_last ; end + + # (IMHO) these should be deprectated + alias_method( :begin, :first ) + alias_method( :end, :last ) + alias_method( :exclude_begin?, :exclude_first? ) + alias_method( :exclude_end?, :exclude_last? ) + + # Returns +true+ if the start and end sentinels are equal and the interval is closed; otherwise +false+. + def degenerate? ; @direction == 0 and ! (@exclusive_first or @exclusive_last) ; end + + # Returns +true+ if the start and end sentinels are equal and the interval is open; otherwise +false+. + def null? ; @direction == 0 and @exclusive_first and @exclusive_last ; end + + # Returns the direction of the interval indicated by +1, 0 or -1. + # + # (1..5).direction #=> 1 + # (5..1).direction #=> -1 + # (1..1).direction #=> 0 + # + def direction ; @direction ; end + + # Returns a new interval inclusive of of both sentinels. + def closed; Interval.new(@first, @last, true, true) ; end + + # Returns a new interval exclusive of both sentinels. + def opened; Interval.new(@first, @last, true, true) ; end + + # Returns a new interval with either the first or the last sentinel exclusive. + # If the parameter is false, the deafult, then the first sentinel is excluded; + # if the parameter is true, the last sentinel is excluded. + def half_closed(e=false) + e ? Interval.new(@first, @last, true, false) : Interval.new(@first, @last, false, true) + end + + # Returns a new interval with one of the two sentinels opened or closed + def first_closed ; Interval.new(@first, @last, false, true) ; end + def last_closed ; Interval.new(@first, @last, true, false) ; end + def first_opened ; Interval.new(@first, @last, true, false) ; end + def last_opened ; Interval.new(@first, @last, false, true) ; end + + # Unary shorthands. These return a new interval exclusive of first, + # last or both sentinels, repectively. + def +@ ; Interval.new(first, last, true, false) ; end + def -@ ; Interval.new(first, last, false, true) ; end + def ~@ ; Interval.new(first, last, true, true) ; end + + # Returns a new interval with the sentinels reversed. + # + # (0..10).reversed #=> 10..0 + # + def reversed + Interval.new(@last, @first, true, true) + end + + # Returns the length of the interval as the difference between + # the first and last elements. Returns +nil+ if the sentinal objects + # do not support distance comparison (#distance). + # + # TODO: Add +n+ parameter to count segmentations like those produced by #each. + def distance + @last - @first + #if @last.respond_to?( :distance ) + # @last.distance( @first ) + #else + # #self.to_a.length + #end + end + alias_method( :length, :distance ) + alias_method( :size, :distance ) + + # Returns the lesser of the first and last sentinals. + def min + ((@first <=> @last) == -1) ? @first : @last + end + + # Returns the greater of the first and last sentinals. + def max + ((@first <=> @last) == 1) ? @first : @last + end + + # Returns true or false if the element is part of the interval. + def include?(x) + # todo: infinity? + tf = exclude_first? ? 1 : 0 + tl = exclude_last? ? -1 : 0 + (x <=> first) >= tf and (x <=> last) <= tl + end + alias_method( :===, :include? ) + alias_method( :member?, :include? ) + +=begin +# def include?(x) +# tf = exclude_first? ? 1 : 0 +# tl = exclude_last? ? -1 : 0 +# # if other classes handled Infinity in their <=> method +# # (which probably they should) this clause would not be required +# if first.kind_of?(InfinityClass) +# ft = ((first <=> x) <= tf) +# else +# ft = (x <=> first) >= tf +# end +# if last.kind_of?(InfinityClass) +# fl = ((last <=> x) >= tl) +# else +# fl = (x <=> last) <= tl +# end +# ft && fl +# end +=end + + # Iterates over the interval, passing each _n_th element to the block. + # If n is not given then n defaults to 1. Each _n_th step is determined + # by invoking +\++ or +\-+ n, depending on the direction of the interval. + # If n is negative the iteration is preformed in reverse form end sentinal + # to front sentinal. A second parameter, d, can be given in which case + # the applied step is calculated as a fraction of the interval's length + # times n / d. This allows iteration over the whole interval in equal sized + # segments. + # + # 1..5.each { |e| ... } #=> 1 2 3 4 5 + # 1..5.each(2) { |e| ... } #=> 1 3 5 + # 1..5.each(1,2) { |e| ... } #=> 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 + # + # @todo Deprecate arguments and simplify each definition accordingly. + def each(n=nil, d=nil) # :yield: + if n + warn "FACETS: `interval.each(n,d){...}` will be deprecated.\n" + + "Use `interval.step(n,d).each{...}` instead." + else + n = 1 + end + + return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ? + + s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs + raise "Cannot iterate over zero length steps." if s == 0 + s = s * @direction + if n < 0 + e = @exclude_last ? @last - s : @last + #e = @exclude_last ? @last.pred(s) : @last + t = @exclude_last ? 1 : 0 + #while e.cmp(@first) >= t + while (e <=> @first) >= t + yield(e) + e -= s + #e = e.pred(s) + end + else + e = @exclude_first ? @first + s : @first + #e = @exclude_first ? @first.succ(s) : @first + t = @exclude_last ? -1 : 0 + #while e.cmp(@last) <= t + while (e <=> @last) <= t + yield(e) + e += s + #e = e.succ(s) + end + end + end + + # + def step(n=1, d=nil) # :yield: + return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ? + + if block_given? + s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs + raise "Cannot iterate over zero length steps." if s == 0 + s = s * @direction + if n < 0 + e = @exclude_last ? @last - s : @last + #e = @exclude_last ? @last.pred(s) : @last + t = @exclude_last ? 1 : 0 + #while e.cmp(@first) >= t + while (e <=> @first) >= t + yield(e) + e -= s + #e = e.pred(s) + end + else + e = @exclude_first ? @first + s : @first + #e = @exclude_first ? @first.succ(s) : @first + t = @exclude_last ? -1 : 0 + #while e.cmp(@last) <= t + while (e <=> @last) <= t + yield(e) + e += s + #e = e.succ(s) + end + end + else + Enumerator.new(self, :step, n, d) + end + end + + # Should there be a #reverse_each ? + # Since #each can now take a negative argument, this isn't really needed. + # Should it exist anyway and routed to #each? + # Also, alias_method( :reverse_step, :reverse_each ) + + # Compares two intervals to see if they are equal + def eql?(other) + return false unless @first == other.first + return false unless @last == other.last + return false unless @exclude_first == other.exclude_first? + return false unless @exclude_last == other.exclude_last? + true + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/load_monitor.rb b/bin/gems/facets-3.1.0/lib/standard/facets/load_monitor.rb new file mode 100644 index 00000000..3c18099d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/load_monitor.rb @@ -0,0 +1,26 @@ +module ::Kernel + class << self + alias_method :require_without_monitor, :require + alias_method :load_without_monitor, :load + end + + alias_method :require_without_monitor, :require + alias_method :load_without_monitor, :load + + # Require script and print what is being require. + def require(file) + $stderr.puts "monitor require: #{file}\n#{caller.inspect}\n\n" + require_without_monitor(file) + end + + module_function :require + + # Load script and print what is being loaded. + def load(file, wrap=false) + $stderr.puts "monitor load: #{file}\n#{caller.inspect}\n\n" + load_without_monitor(file, wrap) + end + + module_function :load +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math.rb new file mode 100644 index 00000000..3a074278 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math.rb @@ -0,0 +1,58 @@ +require_relative 'math/abs.rb' +require_relative 'math/acot.rb' +require_relative 'math/acoth.rb' +require_relative 'math/acsc.rb' +require_relative 'math/acsch.rb' +require_relative 'math/amd.rb' +require_relative 'math/approx_equal.rb' +require_relative 'math/asec.rb' +require_relative 'math/asech.rb' +require_relative 'math/atkinson_index.rb' +require_relative 'math/beta.rb' +require_relative 'math/cdf.rb' +require_relative 'math/ceil.rb' +require_relative 'math/cot.rb' +require_relative 'math/coth.rb' +require_relative 'math/csc.rb' +require_relative 'math/csch.rb' +require_relative 'math/delta.rb' +require_relative 'math/ec.rb' +require_relative 'math/epsilon.rb' +require_relative 'math/exp2.rb' +require_relative 'math/exp10.rb' +require_relative 'math/factorial.rb' +require_relative 'math/floor.rb' +require_relative 'math/gcd.rb' +require_relative 'math/gini_coefficient.rb' +require_relative 'math/kldivergence.rb' +require_relative 'math/lcm.rb' +require_relative 'math/lgamma.rb' +require_relative 'math/lngamma.rb' +require_relative 'math/linsolve.rb' +require_relative 'math/log2.rb' +require_relative 'math/max.rb' +require_relative 'math/mean.rb' +require_relative 'math/median.rb' +require_relative 'math/min.rb' +require_relative 'math/percentile.rb' +require_relative 'math/pow.rb' +require_relative 'math/pstd.rb' +require_relative 'math/pvariance.rb' +require_relative 'math/rmd.rb' +require_relative 'math/root.rb' +require_relative 'math/round.rb' +require_relative 'math/sec.rb' +require_relative 'math/sech.rb' +require_relative 'math/sign.rb' +require_relative 'math/sinc.rb' +require_relative 'math/sqr.rb' +require_relative 'math/sqsolve.rb' +require_relative 'math/std.rb' +require_relative 'math/stderr.rb' +require_relative 'math/sum.rb' +require_relative 'math/summed_sqdevs.rb' +require_relative 'math/tau.rb' +require_relative 'math/tgamma.rb' +require_relative 'math/theil_index.rb' +require_relative 'math/variance.rb' + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/abs.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/abs.rb new file mode 100644 index 00000000..3a5497e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/abs.rb @@ -0,0 +1,8 @@ +module Math + + # Absolute value of +x+. + def self.abs(x) + x.abs + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/acosec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/acosec.rb new file mode 100644 index 00000000..a815ef72 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/acosec.rb @@ -0,0 +1 @@ +require 'facets/math/acsc' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/acot.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/acot.rb new file mode 100644 index 00000000..df9d8233 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/acot.rb @@ -0,0 +1,8 @@ +module Math + + # Arcus cotangens of +x+ + def self.acot(x) + (PI * 0.5) - atan(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/acoth.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/acoth.rb new file mode 100644 index 00000000..636d8063 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/acoth.rb @@ -0,0 +1,8 @@ +module Math + + # Area cotangens hyperbolicus of +x+ + def self.acoth(x) + 0.5 * log((x + 1.0) / (x - 1.0)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/acsc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/acsc.rb new file mode 100644 index 00000000..5731a06c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/acsc.rb @@ -0,0 +1,13 @@ +module Math + + # Arcus cosecans of `x`. + def self.acsc(x) + asin(1.0 / x) + end + + # Arcus cosecans of `x`. + def self.acosec(x) + asin(1.0 / x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/acsch.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/acsch.rb new file mode 100644 index 00000000..e3f38de3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/acsch.rb @@ -0,0 +1,8 @@ +module Math + + # Area cosecans hyperbolicus of +x+ + def acsch(x) + ::Math.log(1.0 / x + Math.sqrt(1.0 + 1.0 / (x * x))) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/amd.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/amd.rb new file mode 100644 index 00000000..bdccbb98 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/amd.rb @@ -0,0 +1,17 @@ +require 'facets/math/rmd' +require 'facets/math/mean' + +module Math + + # The average absolute difference of two independent values drawn + # from the sample. Equal to the RMD * mean. + def self.amd(array) + rmd(array) * mean(array) + end + + class << self + alias_method :absolute_mean_difference, :amd + #alias_method :md, :mean_difference + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/approx_equal.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/approx_equal.rb new file mode 100644 index 00000000..cdf789ba --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/approx_equal.rb @@ -0,0 +1,15 @@ +module Math + + # + EPSILON = 0.000000001 + + # Approximately equal. + # + # TODO: Use core extension Numeric#approx? instead (?) + def self.approx_equal(a, b, epsilon=EPSILON) + c = a - b + c *= -1.0 if c < 0 + c < epsilon + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/asec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/asec.rb new file mode 100644 index 00000000..f94c2e81 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/asec.rb @@ -0,0 +1,8 @@ +module Math + + # Arcus secans of +x+ + def self.asec(x) + acos(1.0 / x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/asech.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/asech.rb new file mode 100644 index 00000000..a4208450 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/asech.rb @@ -0,0 +1,8 @@ +module Math + + # Area secans hyperbolicus of +x+ + def asech(x) + log((1.0 + sqrt(1.0 - x * x)) / x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/atkinson_index.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/atkinson_index.rb new file mode 100644 index 00000000..71c0401c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/atkinson_index.rb @@ -0,0 +1,16 @@ +require 'facets/math/theil_index' + +module Math + + # Closely related to the Theil index and easily expressible + # in terms of it. + # + # AI = 1-e^{theil_index} + # + # http://en.wikipedia.org/wiki/Atkinson_index + def self.atkinson_index(array) + t = theil_index(array) + (t < 0) ? -1 : 1-Math::E**(-t) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/beta.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/beta.rb new file mode 100644 index 00000000..71b43b80 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/beta.rb @@ -0,0 +1,14 @@ +require 'facets/math/tgamma' + +module Math + + # Beta function of `x` and `y`. + # + # beta(x, y) = tgamma(x) * tgamma(y) / tgamma(x + y) + # + def self.beta(x, y) + #exp(lgamma(x).first + lgamma(y).first - lgamma(x+y).first) + tgamma(x) * tgamma(y) / tgamma(x + y) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/cdf.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/cdf.rb new file mode 100644 index 00000000..c053f0fc --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/cdf.rb @@ -0,0 +1,10 @@ +module Math + + # Returns the Cumulative Density Function of this + # sample (normalised to a fraction of 1.0). + def self.cdf(array, normalised=1.0) + s = sum(array).to_f + array.sort.inject([0.0]) { |c,d| c << c[-1] + normalised*d.to_f/s } + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/ceil.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/ceil.rb new file mode 100644 index 00000000..fd52bbab --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/ceil.rb @@ -0,0 +1,8 @@ +module Math + + # Smallest integer not smaller than +x+. + def self.ceil(x) + x.ceil + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/cosec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/cosec.rb new file mode 100644 index 00000000..53c15e0d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/cosec.rb @@ -0,0 +1 @@ +require 'facets/math/csc' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/cosech.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/cosech.rb new file mode 100644 index 00000000..b3796f9b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/cosech.rb @@ -0,0 +1 @@ +require 'facets/math/csch' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/cot.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/cot.rb new file mode 100644 index 00000000..9e5f2a94 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/cot.rb @@ -0,0 +1,8 @@ +module Math + + # Cotangens of +x+ + def self.cot(x) + tan((PI * 0.5) - x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/coth.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/coth.rb new file mode 100644 index 00000000..516e1562 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/coth.rb @@ -0,0 +1,8 @@ +module Math + + # Cotangens hyperbolicus of +x+ + def self.coth(x) + 1.0 / tanh(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/csc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/csc.rb new file mode 100644 index 00000000..d9ff9ae2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/csc.rb @@ -0,0 +1,13 @@ +module Math + + # Cosecans of `x`. + def self.csc(x) + 1.0 / sin(x) + end + + # Cosecans of `x`. + def self.cosec(x) + 1.0 / sin(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/csch.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/csch.rb new file mode 100644 index 00000000..2435a4a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/csch.rb @@ -0,0 +1,13 @@ +module Math + + # Cosecans hyperbolicus of `x`. + def self.csch(x) + 1.0 / sinh(x) + end + + # Cosecans hyperbolicus of `x`. + def self.cosech(x) + 1.0 / sinh(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/delta.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/delta.rb new file mode 100644 index 00000000..cceeee9b --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/delta.rb @@ -0,0 +1,9 @@ +module Math + + # Kronecker symbol of +i+ and +j+. + # Returns 1 if +i+ and +j+ are equal, 0 otherwise. + def self.delta(i, j) + return Integer(i) == Integer(j) ? 1 : 0 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/distance.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/distance.rb new file mode 100644 index 00000000..ad96ccbd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/distance.rb @@ -0,0 +1,19 @@ +module Math + + # Calculates the Euclidean Distance between points +p+ and +q+. + # + # `p`, `q` is assumed to described coordinates in N-dimensions, e. g.: + # + # Math.distance([1, 1], [2, 2]) # 2D coordinates + # Math.distance([1, 1, 1], [2, 2, 2]) # 3D coordinates + # + # If N is 1, then `::distance` may also be invoked like so: + # + # Math.distance(1, 1) + # + def self.distance(p, q) + p, q = [p].flatten, [q].flatten + sqrt(p.zip(q).inject(0){ |sum, coord| sum + (coord.first - coord.last)**2 }) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/ec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/ec.rb new file mode 100644 index 00000000..e5fa26c4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/ec.rb @@ -0,0 +1,5 @@ +module Math + # Euler's constant. + EC = 0.577_215_664_901_532_861 +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/epsilon.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/epsilon.rb new file mode 100644 index 00000000..2b279c87 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/epsilon.rb @@ -0,0 +1,21 @@ +module Math + + # Levi-Civita symbol of +i+, +j+, and +k+ - 1 if (+i+, +j+, +k+) + # is (1, 2, 3), (2, 3, 1), or (3, 1, 2), -1 if it is (1, 3, 2), + # (2, 1, 3), or (3, 2, 1), 0 as long as +i+, +j+, and +k+ are + # all elements of {1, 2, 3}, otherwise returns nil. + def self.epsilon(i, j, k) + i = Integer(i) + return nil if i < 1 or i > 3 + j = Integer(j) + return nil if j < 1 or j > 3 + k = Integer(k) + return nil if k < 1 or k > 3 + case i * 16 + j * 4 + k + when 27, 45, 54 then return 1 + when 30, 39, 57 then return -1 + end + 0 + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/exp10.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/exp10.rb new file mode 100644 index 00000000..561f01dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/exp10.rb @@ -0,0 +1,8 @@ +module Math + + # 10 to the power +x+ + def self.exp10(x) + 10.0 ** x + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/exp2.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/exp2.rb new file mode 100644 index 00000000..659cdd6f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/exp2.rb @@ -0,0 +1,8 @@ +module Math + + # 2 to the power +x+ + def self.exp2(x) + 2.0 ** x + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/factorial.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/factorial.rb new file mode 100644 index 00000000..d7cb4c88 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/factorial.rb @@ -0,0 +1,37 @@ +module Math + + # First 16 factorials. + FACTORIALS = [ + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5_040, + 40_320, + 362_880, + 3_628_800, + 39_916_800, + 479_001_600, + 6_227_020_800, + 87_178_291_200, + 1_307_674_368_000 + ] + + # 1 * 2 * ... * +n+, nil for negative numbers + def self.factorial(n) + n = Integer(n) + if n < 0 + nil + elsif FACTORIALS.length > n + FACTORIALS[n] + else + h = FACTORIALS.last + (FACTORIALS.length .. n).each { |i| FACTORIALS.push h *= i } + h + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/floor.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/floor.rb new file mode 100644 index 00000000..f849cea0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/floor.rb @@ -0,0 +1,8 @@ +module Math + + # Largest integer not larger than +x+. + def self.floor(x) + x.floor + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/gcd.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/gcd.rb new file mode 100644 index 00000000..176ad362 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/gcd.rb @@ -0,0 +1,23 @@ +module Math + + # Greatest common divisor of +m+ and +n+, +nil+ for non-positive + # numbers - gcd is computed by means of the Euclidian algorithm. + def self.gcd(m, n) + m = Integer(m) + n = Integer(n) + if m <= 0 || n <= 0 + return nil + end + loop { + if m < n + m, n = n, m + end + if (l = m % n) == 0 + break + end + m = l + } + n + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/gini_coefficient.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/gini_coefficient.rb new file mode 100644 index 00000000..b0e4d713 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/gini_coefficient.rb @@ -0,0 +1,33 @@ +require 'facets/math/approx_equal' + +module Math + + # Calculates the Gini Coefficient (a measure of inequality of a distribution + # based on the area between the Lorenz curve and the uniform curve). + # + # http://en.wikipedia.org/wiki/Gini_coefficient + # + # This is a slightly cleaner way of calculating the Gini Coefficient then + # the previous implementationj. + # + # GC = \frac{\sum_{i=1}^N (2i-N-1)x_i}{N^2-\bar{x}} + # + def self.gini_coefficient(array) + return -1 if size <= 0 or any? { |x| x < 0 } + return 0 if size < 2 or all? { |x| approx_equal(x,0) } + s = 0 + sort.each_with_index { |li,i| s += (2*i+1-size)*li } + s.to_f/(size**2*mean).to_f + end + + ## OLD WAY + ## GC = \frac{1}{N} \left ( N+1-2\frac{\sum_{i=1}^N (N+1-i)y_i}{\sum_{i=1}^N y_i} \right ) + ## def self.gini_coefficient2(array) + ## return -1 if size <= 0 or any? { |x| x < 0 } + ## return 0 if size < 2 or all? { |x| Math::float_equal(x,0) } + ## s = 0 + ## sort.each_with_index { |yi,i| s += (size - i)*yi } + ## (size+1-2*(s.to_f/sum.to_f)).to_f/size.to_f + ## end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/kldivergence.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/kldivergence.rb new file mode 100644 index 00000000..95bfbe8e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/kldivergence.rb @@ -0,0 +1,19 @@ +module Math + + # The Kullback-Leibler divergence from this array to that of +q+. + # + # NB: You will possibly want to sort both P and Q before calling this + # depending on what you're actually trying to measure. + # + # http://en.wikipedia.org/wiki/Kullback-Leibler_divergence + # + def self.kldivergence(array, q) + fail "Buggy." + fail "Cannot compare differently sized arrays." unless size = q.size + kld = 0 + each_with_index { |pi,i| kld += pi*Math::log(pi.to_f/q[i].to_f) } + kld + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/lcm.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/lcm.rb new file mode 100644 index 00000000..c071b1cd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/lcm.rb @@ -0,0 +1,15 @@ +module Math + + # Least common multiple of +m+ and +n+, computed by multiplying + # +m+ and +n+ and dividing the product by the gcd of +m+ and +n+, + # +nil+ for non-positive numbers. + def self.lcm(m, n) + m = Integer(m) + n = Integer(n) + if m <= 0 || n <= 0 + return nil + end + m / gcd(m, n) * n + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/lgamma.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/lgamma.rb new file mode 100644 index 00000000..03216d84 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/lgamma.rb @@ -0,0 +1,23 @@ +require 'facets/math/lngamma' + +## This is the old definition by Josef Schugt. +## +## Around v2.0, Ruby finally added it's own `lgamma` +## function. That's good, but unforutnately it returns +## an array that includes the `sign(gamma(x))` too. +# +# def Math.lgamma(x) +# h = x + 5.5 +# h -= (x + 0.5) * log(h) +# +# sum = 1.000_000_000_190_015 +# sum += 76.180_091_729_471_46 / (x + 1.0) +# sum -= 86.505_320_329_416_77 / (x + 2.0) +# sum += 24.014_098_240_830_91 / (x + 3.0) +# sum -= 1.231_739_572_450_155 / (x + 4.0) +# sum += 0.120_865_097_386_617_9e-2 / (x + 5.0) +# sum -= 0.539_523_938_495_3e-5 / (x + 6.0) +# +# -h + log(2.506_628_274_631_000_5 * sum / x) +# end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/linsolve.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/linsolve.rb new file mode 100644 index 00000000..9a2f6d91 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/linsolve.rb @@ -0,0 +1,12 @@ +module Math + + # Returns real solution(s) of +a+x + +b+ = +c+ or +nil+ + # if no or an infinite number of solutions exist. If + # c is missing it is assumed to be 0. + # + # @author Josef Schugt + def self.linsolve(a, b, c = 0.0) + a == 0 ? nil : (c - b) / a + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/lngamma.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/lngamma.rb new file mode 100644 index 00000000..10552bd6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/lngamma.rb @@ -0,0 +1,18 @@ +module Math + + # Logarithmus naturalis of gamma function of `x`. + # + # Notice the use of `ln` prefix to differentiate from + # Ruby's built-in `#lgamma` function which returns an Array. + # + def self.lngamma(x) + lgamma(x).first + end + + # Old name used by Extmath library. + def self.ln_gamma(x) + lgamma(x).first + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/log2.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/log2.rb new file mode 100644 index 00000000..96a2131c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/log2.rb @@ -0,0 +1,14 @@ +module Math + + INVERSE_LN_2 = 1.0 / ::Math.log(2.0) + + unless defined?(log2) + + # Logarithmus dualis of +x+. + def self.log2(x) + Math.log(x) * INVERSE_LN_2 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/max.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/max.rb new file mode 100644 index 00000000..31003803 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/max.rb @@ -0,0 +1 @@ +require 'facets/math/min' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/mean.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/mean.rb new file mode 100644 index 00000000..12297684 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/mean.rb @@ -0,0 +1,16 @@ +require 'facets/math/sum' + +module Math + + # Mean average. + def self.mean(array, &blk) + s = array.size + return 0.0 if s == 0 + sum(array, &blk) / s + end + + class << self + alias_method :mean_average, :mean + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/median.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/median.rb new file mode 100644 index 00000000..4c533da5 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/median.rb @@ -0,0 +1,30 @@ +require 'facets/math/percentile' + +module Math + + # Returns the numerical median for the an array of values; + # or nil if array is empty. + # + def self.median(array) + percentile(array, 50) + end + +# better definition ? +=begin + # + def self.median(array) + return 0 if array.size == 0 + + tmp = array.sort + mid = tmp.size / 2 + + if (tmp.size % 2) == 0 + (tmp[mid-1] + tmp[mid]).to_f / 2 + else + tmp[mid] + end + end +=end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/min.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/min.rb new file mode 100644 index 00000000..e97dfe8f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/min.rb @@ -0,0 +1,35 @@ +module Math + + # + def self.min(array, &block) + if block_given? + if min = array.find{ |i| i } + min = yield(min) + array.each do |i| + j = yield(i) + min = j if min > j + end + min + end + else + array.min + end + end + + # + def self.max(array, block) + if block_given? + if max = find{|i| i} + max = yield(max) + each{|i| + j = yield(i) + max = j if max < j + } + max + end + else + array.max + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/percentile.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/percentile.rb new file mode 100644 index 00000000..57e000ca --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/percentile.rb @@ -0,0 +1,40 @@ +module Math + + # Returns the percentile value for percentile _pcnt_; nil if array is empty. + # + # +pcnt+ should be expressed as an integer, e.g. `percentile(90)` returns + # the 90th percentile of the array. + # + # Algorithm from NIST[http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm] + # + # NOTE: This is not a common core extension and is not + # loaded automatically when using require 'facets'. + # + # CREDIT: Ben Koski + # + # @non-core + # require 'facets/array/precentile' + # + def self.percentile(array, pcnt) + sorted_array = array.sort + + return nil if array.length == 0 + + rank = (pcnt.to_f / 100) * (array.length + 1) + whole = rank.truncate + + # if has fractional part + if whole != rank + s0 = sorted_array[whole - 1] + s1 = sorted_array[whole] + + f = (rank - rank.truncate).abs + + return (f * (s1 - s0)) + s0 + else + return sorted_array[whole - 1] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/pow.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/pow.rb new file mode 100644 index 00000000..06c5dab6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/pow.rb @@ -0,0 +1,13 @@ +module Math + + # `x` to the power `y`. + def self.pow(x, y) + x ** y + end + + # `x` to the power `y`. + def self.pwr(x, y) + x ** y + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/pstd.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/pstd.rb new file mode 100644 index 00000000..bb628b73 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/pstd.rb @@ -0,0 +1 @@ +require 'facets/math/std' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/pvariance.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/pvariance.rb new file mode 100644 index 00000000..8d4b824f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/pvariance.rb @@ -0,0 +1 @@ +require 'facets/math/variance' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/rmd.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/rmd.rb new file mode 100644 index 00000000..76545aa1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/rmd.rb @@ -0,0 +1,16 @@ +require 'facets/math/approx_equal' + +module Math + + # Calculates the relative mean difference of this sample. + # Makes use of the fact that the Gini Coefficient is half the RMD. + def self.rmd(array) + return 0.0 if approx_equal(mean(array), 0.0) + gini_coefficient(array) * 2 + end + + class << self + alias_method :relative_mean_difference, :rmd + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/root.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/root.rb new file mode 100644 index 00000000..80009f33 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/root.rb @@ -0,0 +1,8 @@ +module Math + + # The `y` root of `x`. + def self.root(x, y) + x ** (1.0 / y) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/round.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/round.rb new file mode 100644 index 00000000..9406fff8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/round.rb @@ -0,0 +1,9 @@ +module Math + + # Round number to an integer. + # + def self.round(x) + x.round + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sec.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sec.rb new file mode 100644 index 00000000..624be024 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sec.rb @@ -0,0 +1,8 @@ +module Math + + # Secans of +x+. + def self.sec(x) + 1.0 / cos(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sech.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sech.rb new file mode 100644 index 00000000..5828d32c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sech.rb @@ -0,0 +1,8 @@ +module Math + + # Secans hyperbolicus of +x+ + def self.sech(x) + 1.0 / cosh(x) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sign.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sign.rb new file mode 100644 index 00000000..2078f9ad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sign.rb @@ -0,0 +1,20 @@ +module Math + + # Sign of `x`. This function returns `-1.0` if `x` is negative, + # `+1.0` if `x` is positive `x`, and `0.0` if `x = 0`. + def self.sign(x, zero=0.0) + (x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero) + end + + # Same as `Math.sign`. + def self.sgn(x, zero=0.0) + (x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero) + end + + # The *Heaviside step function*, also called the the *unit step function*. + # This functions works like `Math.sign` but by default returns `1.0` for zero. + def self.unit_step(x, zero=1.0) + (x > 0.0) ? 1.0 : ((x < 0.0) ? -1.0 : zero) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sinc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sinc.rb new file mode 100644 index 00000000..4dea2222 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sinc.rb @@ -0,0 +1,8 @@ +module Math + + # Sinc function of +x+. + def self.sinc(x) + (x == 0.0) ? 1.0 : sin(x) / x + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sqr.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sqr.rb new file mode 100644 index 00000000..8c1d941d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sqr.rb @@ -0,0 +1,8 @@ +module Math + + # Square of number. + def self.sqr(x) + x * x + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sqsolve.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sqsolve.rb new file mode 100644 index 00000000..11c9291f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sqsolve.rb @@ -0,0 +1,55 @@ +require 'facets/math/linsolve' + +module Math + + # Returns array of real solution of ax**2 + bx + c = d + # or nil if no or an infinite number of solutions exist. + # If +d+ is missing it is assumed to be 0. + # + # In order to solve ax**2 + bx + c = d +sqsolve+ identifies several cases: + # * a == 0: + # The equation to be solved is the linear equation bx + c = d. #sqsolve> delegates the computation to + # #linsolve>. If it results in +nil+, +nil+ is returned (not [nil]!). Otherwise a one-element array + # containing result of #linsolve is returned. + # * a != 0: + # The equation to be solved actually is a second order one. + # * c == d + # The equation to be solved is ax**2 + bx = 0. One solution of this equation obviously is + # x = 0, the second one solves ax + b = 0. The solution of the latter is + # delegated to +linsolve+. An array containing both results in ascending order is returned. + # * c != d + # The equation cannot be separated into x times some factor. + # * b == 0 + # The equation to be solved is ax**2 + c = d. This can be written as the linear equation + # ay + c = d with y = x ** 2. The solution of the linear equation is delegated + # to +linsolve+. If the returned value for +y+ is +nil+, that becomes the overall return value. + # Otherwise an array containing the negative and positive squareroot of +y+ is returned + # * b != 0 + # The equation cannot be reduced to simpler cases. We now first have to compute what is called the + # discriminant x = b**2 + 4a(d - c) (that's what we need to compute the square root of). + # If the descriminant is negative no real solution exists and nil is returned. The ternary + # operator checking whether b is negative does ensure better numerical stability --only one + # of the two solutions is computed using the widely know formula for solving second order equations. + # The second one is computed from the fact that the product of both solutions is (c - d) / a. + # Take a look at a book on numerical mathematics if you don't understand why this should be done. + # + # @author Josef Schugt + def self.sqsolve(a, b, c, d = 0.0) + if a == 0.0 + x = linsolve(b, c, d) + return x.nil? ? nil: [ linsolve(b, c, d) ] + else + return [0.0, linsolve(a, b)].sort if c == d + if b == 0.0 + x = linsolve(a, c, d) + x < 0.0 ? nil : [-Math.sqrt(x), Math.sqrt(x)] + else + x = b * b + 4.0 * a * (d - c) + return nil if x < 0.0 + x = b < 0 ? b - Math.sqrt(x) : b + Math.sqrt(x) + [-0.5 * x / a, 2.0 * (d - c) / x].sort + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/std.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/std.rb new file mode 100644 index 00000000..cb1d48e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/std.rb @@ -0,0 +1,27 @@ +require 'facets/math/variance' + +module Math + + # Standard deviation of a sample. + # + def self.std(array, &block) + sqrt(variance(array, &block)) + end + + class << self + alias_method :standard_deviation, :std + end + + # Standard deviation of a population. + # + def self.pstd(array, &block) + Math::sqrt(pvariance(array, &block)) + end + + # Calculates the standard error of a sample. + def self.stderr(array) + return 0.0 if array.size < 2 + std(array) / sqrt(array.size) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/stderr.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/stderr.rb new file mode 100644 index 00000000..bb628b73 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/stderr.rb @@ -0,0 +1 @@ +require 'facets/math/std' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/sum.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/sum.rb new file mode 100644 index 00000000..2f81aa88 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/sum.rb @@ -0,0 +1,16 @@ +module Math + + # Returns sum. When a block is given, summation is taken over the + # each result of block evaluation. + # + def self.sum(array) #:yield: + sum = 0.0 + if block_given? + array.each{|i| sum += yield(i)} + else + array.each{|i| sum += i} + end + sum + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/summed_sqdevs.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/summed_sqdevs.rb new file mode 100644 index 00000000..266a48eb --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/summed_sqdevs.rb @@ -0,0 +1,14 @@ +require 'facets/math/sum' +require 'facets/math/mean' + +module Math + + # The sum of the squared deviations from the mean. + # + def self.summed_sqdevs(array) + return 0 if array.size < 2 + m = mean(array) + sum(array.map{ |x| (x - m) ** 2 }) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/tau.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/tau.rb new file mode 100644 index 00000000..f618697d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/tau.rb @@ -0,0 +1,5 @@ +module Math + # See http://tauday.com/tau-manifesto + TAU = 2 * PI +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/tgamma.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/tgamma.rb new file mode 100644 index 00000000..7eb1438a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/tgamma.rb @@ -0,0 +1,10 @@ +require 'facets/math/lgamma' + +module Math + + # Exp of LGamma. + def self.tgamma(x) + exp(lngamma(x)) #exp(log(gamma(x).abs) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/theil_index.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/theil_index.rb new file mode 100644 index 00000000..29c0230a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/theil_index.rb @@ -0,0 +1,24 @@ +require 'facets/math/sum' +require 'facets/math/mean' +require 'facets/math/approx_equal' + +module Math + + # Calculates the Theil index (a statistic used to measure + # economic inequality). + # + # TI = \sum_{i=1}^N \frac{x_i}{\sum_{j=1}^N x_j} ln \frac{x_i}{\bar{x}} + # + # http://en.wikipedia.org/wiki/Theil_index + # + def self.theil_index(array) + return -1 if array.size <= 0 or any? { |x| x < 0 } + return 0 if array.size < 2 or all? { |x| approx_equal(x, 0) } + m = mean(array) + s = sum(array).to_f + inject(0) do |theil, xi| + theil + ((xi > 0) ? (log(xi.to_f/m) * xi.to_f/s) : 0.0) + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/math/variance.rb b/bin/gems/facets-3.1.0/lib/standard/facets/math/variance.rb new file mode 100644 index 00000000..9d5a3cd7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/math/variance.rb @@ -0,0 +1,31 @@ +require 'facets/math/summed_sqdevs' + +module Math + + # + def self.variance(array, &block) + sum2 = if block_given? + sum(array){ |i| j = block[i]; j*j } + else + sum(array){ |i| i**2 } + end + sum2/array.size - mean(array, &block)**2 + end + + # Variance of the sample. + # Variance of 0 or 1 elements is 0.0. + # + # TODO: Same as #variance? Then choose one. + def self.variance2(array) + return 0.0 if array.size < 2 + summed_sqdevs(array) / (array.size - 1) + end + + # Variance of a population. + # Variance of 0 or 1 elements is 0.0. + def self.pvariance(array) + return 0.0 if array.size < 2 + summed_sqdevs(array) / array.size + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/memoizable.rb b/bin/gems/facets-3.1.0/lib/standard/facets/memoizable.rb new file mode 100644 index 00000000..6193b213 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/memoizable.rb @@ -0,0 +1,141 @@ +# Memoization is an optimization technique used primarily to speed up +# programs by having function calls avoid repeating the calculation +# of results for previously-processed inputs. +# +# When you "memoize" a method/function using Memoizable its results are cached +# so that later calls return results from the cache instead of recalculating +# them. +# +# class T +# include Memoizable +# +# def initialize(a) +# @a = a +# end +# +# def a +# "#{@a ^ 3 + 4}" +# end +# +# memoize :a +# end +# +# t = T.new(10) +# (t.a.__id__ == t.a.__id__) #=> true +# +# This method can also be used at the instance level to cache singleton +# (qua class) methods by including it in the singleton class. +# +#-- +# TODO: It would be very cool if Memoizable could set-up default parameters +# via #[] method, e.g. `include Memoizable[:freeze=>true]`. +#++ + +module Memoizable + + @cache = Hash.new{|h,k|h[k]=Hash.new{|h,k|h[k]={}}} + + # + def self.cache + @cache + end + + # + def self.append_features(base) + Module == base ? super(base) : base.extend(self) + end + + # Directive for making your functions faster by trading space for time. + # When you "memoize" a method/function using #memoize its results are + # cached so that later calls with the same arguments return results from + # the cache instead of recalculating them. + # + # The #memoize method also handles a few options to alter + # behavior of the memoization: + # + # :class => true cache per-class not per-object + # :freeze => true freeze the memoized return values + # :arguments => false do not index cache by arguments + # + def memoize(*method_names) + options = Hash === method_names.last ? method_names.pop : {} + + options[:arguments] = true if options[:arguments].nil? # default to true + + ref = options[:class] ? 'self.class.name' : 'self' + frz = options[:freeze] ? '.freeze' : '' + arg = options[:arguments] ? '[__a__, block_given?]' : 'nil' + + code = "" + method_names.each do |m| + code << <<-code + alias_method '#{ m }:memo', '#{ m }' + private '#{ m }:memo' + def #{ m }(*__a__,&__b__) + c = Memoizable.cache[#{ref}][:'#{ m }'] + k = #{arg} + if c.has_key?(k) + c[k] + else + c[k] = __send__('#{ m }:memo',*__a__,&__b__)#{frz} + end + end + code + end + module_eval(code) + end + + # Remove the memoized value from the memoization cache. + # The next time a memoized methos is called if will be + # remomoized. + def rememoize(*method_names) + if Memoizable.cache[self] + if method_names.empty? + Memoizable.cache.delete(self) + else + method_names.each do |m| + Memoizable.cache[self].delete(m.to_sym) + end + end + end + if Memoizable.cache[self.class.name] + if method_names.empty? + Memoizable.cache.delete(self.class.name) + else + method_names.each do |m| + Memoizable.cache[self.class.name].delete(m.to_sym) + end + end + end + end + + # + def unmemoize(*method_names) + rememoize(*method_names) + method_names.each do |m| + alias_method name, "#{ m }:memo" + end + end + + # Include Memoizable alone with an #initialize_copy method that + # will copy the memoization cache when #dup or #clone is used. + # + # TODO: Is this best approach? Perhaps a method to easily create + # the #initialize_copy method would suffice? + module Copy + + # + def self.included(base) + base.extend(Memoizable) + end + + # + def initialize_copy(original) + if Memoizable.cache.key?(original) + Memoizable.cache[self] = Memoizable.cache[original].dup + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/memoizer.rb b/bin/gems/facets-3.1.0/lib/standard/facets/memoizer.rb new file mode 100644 index 00000000..ac9a34e7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/memoizer.rb @@ -0,0 +1,63 @@ +# Memoizer wraps objects to provide cached method calls. +# +# class X +# def initialize ; @tick = 0 ; end +# def tick; @tick + 1; end +# def memo; @memo ||= Memoizer.new(self) ; end +# end +# +# x = X.new +# x.tick #=> 1 +# x.memo.tick #=> 2 +# x.tick #=> 3 +# x.memo.tick #=> 2 +# x.tick #=> 4 +# x.memo.tick #=> 2 +# +# You can also use to cache collections of objects to gain code speed ups. +# +# points = points.collect{|point| Memoizer.cache(point)} +# +# After our algorithm has finished using points, we want to get rid of +# these Memoizer objects. That's easy: +# +# points = points.collect{|point| point.__self__ } +# +# Or if you prefer (it is ever so slightly safer): +# +# points = points.collect{|point| Memoizer.uncache(point)} +# +# Memoizer is the work of Erik Veenstra +# +# Copyright (c) 2006 Erik Veenstra +# +# See http://javathink.blogspot.com/2008/09/what-is-memoizer-and-why-should-you.html + +class Memoizer + + #private :class, :clone, :display, :type, :method, :to_a, :to_s + private *instance_methods(true).select{ |m| m.to_s !~ /^__/ } + + def initialize(object) + @self = object + @cache = {} + end + + def __self__ ; @self ; end + + # Not thread-safe! Speed is important in caches... ;] + def method_missing(method_name, *args, &block) + @cache[[method_name, args, block]] ||= @self.__send__(method_name, *args, &block) + end + + #def self; @self; end + + def self.cache(object) + new(object) + end + + def self.uncache(cached_object) + cached_object.instance_variable_get('@self') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/multipliers.rb b/bin/gems/facets-3.1.0/lib/standard/facets/multipliers.rb new file mode 100644 index 00000000..74a1b1f8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/multipliers.rb @@ -0,0 +1,65 @@ +class Numeric + + # = Numeric::Multipliers + # + # Adds methods to Numeric to make working with + # magnitudes (kilo, mega, giga, milli, micro, etc.) + # + # 1.kilo #=> 1000 + # 1.milli #=> 0.001 + # 1.kibi #=> 1024 + # + # To display a value in a certain denomination, simply + # perform the inverse operation by placing the + # multiplier called on unit (1) in the denominator. + # + # (1000 / 1.kilo) #=> 1 + # (1024 / 1.kibi) #=> 1 + # + # Thanks to Rich Kilmer and bytes.rb which inspired this library. + + module Multipliers + + # SI Multipliers + + def deka ; self * 10 ; end + def hecto ; self * 100 ; end + def kilo ; self * 1000 ; end + def mega ; self * 1000000 ; end + def giga ; self * 1000000000 ; end + def tera ; self * 1000000000000 ; end + def peta ; self * 1000000000000000 ; end + def exa ; self * 1000000000000000000 ; end + + # SI Fractional + + def deci ; self.to_f / 10 ; end + def centi ; self.to_f / 100 ; end + def milli ; self.to_f / 1000 ; end + def micro ; self.to_f / 1000000 ; end + def nano ; self.to_f / 1000000000 ; end + def pico ; self.to_f / 1000000000000 ; end + def femto ; self.to_f / 1000000000000000 ; end + def atto ; self.to_f / 1000000000000000000 ; end + + # SI Binary + + def kibi ; self * 1024 ; end + def mebi ; self * 1024**2 ; end + def gibi ; self * 1024**3 ; end + def tebi ; self * 1024**4 ; end + def pebi ; self * 1024**5 ; end + def exbi ; self * 1024**6 ; end + + # Bits and Bytes + + #def bit ; self ; end + #def bits ; self ; end + #def byte ; self * 8 ; end + #def bytes ; self * 8 ; end + end + + include Multipliers +end + +# Copyright (c) 2005 Thomas Sawyer diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/multiton.rb b/bin/gems/facets-3.1.0/lib/standard/facets/multiton.rb new file mode 100644 index 00000000..23e56f7e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/multiton.rb @@ -0,0 +1,387 @@ +# = Multiton +# +# == Synopsis +# +# Multiton design pattern ensures only one object is allocated for a given state. +# +# The 'multiton' pattern is similar to a singleton, but instead of only one +# instance, there are several similar instances. It is useful when you want to +# avoid constructing objects many times because of some huge expense (connecting +# to a database for example), require a set of similar but not identical +# objects, and cannot easily control how many times a contructor may be called. +# +# class SomeMultitonClass +# include Multiton +# attr :arg +# def initialize(arg) +# @arg = arg +# end +# end +# +# a = SomeMultitonClass.new(4) +# b = SomeMultitonClass.new(4) # a and b are same object +# c = SomeMultitonClass.new(2) # c is a different object +# +# == Previous Behavior +# +# In previous versions of Multiton the #new method was made +# private and #instance had to be used in its stay --just like Singleton. +# But this is less desirable for Multiton since Multitions can +# have multiple instances, not just one. +# +# So instead Multiton now defines #create as a private alias of +# the original #new method (just in case it is needed) and then +# defines #new to handle the multiton; #instance is provided +# as an alias for it. +# +#-- +# So if you must have the old behavior, all you need do is re-alias +# #new to #create and privatize it. +# +# class SomeMultitonClass +# include Multiton +# alias_method :new, :create +# private :new +# ... +# end +# +# Then only #instance will be available for creating the Multiton. +#++ +# +# == How It Works +# +# A pool of objects is searched for a previously cached object, +# if one is not found we construct one and cache it in the pool +# based on class and the args given to the contructor. +# +# A limitation of this approach is that it is impossible to +# detect if different blocks were given to a contructor (if it takes a +# block). So it is the constructor arguments _only_ which determine +# the uniqueness of an object. To workaround this, define the _class_ +# method ::multiton_id. +# +# def SomeMultitonClass.multiton_id(*args, &block) +# # ... +# end +# +# Which should return a hash key used to identify the object being +# constructed as (not) unique. +# +# == Authors +# +# * Christoph Rippel +# * Thomas Sawyer +# +# = Copying +# +# Copyright (c) 2007 Christoph Rippel, Thomas Sawyer +# +# Ruby License +# +# This module is free software. You may use, modify, and/or redistribute this +# software under the same terms as Ruby. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. + +require 'thread' + +# = Multiton +# +# Multiton design pattern ensures only one object is allocated for a given state. +# +# The 'multiton' pattern is similar to a singleton, but instead of only one +# instance, there are several similar instances. It is useful when you want to +# avoid constructing objects many times because of some huge expense (connecting +# to a database for example), require a set of similar but not identical +# objects, and cannot easily control how many times a contructor may be called. +# +# class SomeMultitonClass +# include Multiton +# attr :arg +# def initialize(arg) +# @arg = arg +# end +# end +# +# a = SomeMultitonClass.new(4) +# b = SomeMultitonClass.new(4) # a and b are same object +# c = SomeMultitonClass.new(2) # c is a different object +# +# == How It Works +# +# A pool of objects is searched for a previously cached object, +# if one is not found we construct one and cache it in the pool +# based on class and the args given to the contructor. +# +# A limitation of this approach is that it is impossible to +# detect if different blocks were given to a contructor (if it takes a +# block). So it is the constructor arguments _only_ which determine +# the uniqueness of an object. To workaround this, define the _class_ +# method ::multiton_id. +# +# def SomeMultitonClass.multiton_id(*args, &block) +# # ... +# end +# +# Which should return a hash key used to identify the object being +# constructed as (not) unique. + +module Multiton + + # Disable build-in copying methods. + + def clone + raise TypeError, "can't clone Multiton #{self}" + ##self + end + + def dup + raise TypeError, "can't dup Multiton #{self}" + ##self + end + + # Default marshalling strategy. + + protected + + def _dump(depth=-1) + Marshal.dump(@multiton_initializer) + end + + # Mutex to safely store multiton instances. + + class InstanceMutex < Hash #:nodoc: + def initialize + @global = Mutex.new + end + + def initialized(arg) + store(arg, DummyMutex) + end + + def (DummyMutex = Object.new).synchronize + yield + end + + def default(arg) + @global.synchronize{ fetch(arg){ store(arg, Mutex.new) } } + end + end + + # Multiton can be included in another module, in which case that module + # effectively becomes a multiton behavior distributor too. This is why we + # propogate #included to the base module by putting it in another module. + # + #-- + # def append_features(mod) + # # help out people counting on transitive mixins + # unless mod.instance_of?(Class) + # raise TypeError, "Inclusion of Multiton in module #{mod}" + # end + # super + # end + #++ + + module Inclusive + private + def included(base) + class << base + ##alias_method(:new!, :new) unless method_defined?(:new!) + ## gracefully handle multiple inclusions of Multiton + unless include?(Multiton::MetaMethods) + alias_method :new!, :new + private :allocate #, :new + include Multiton::MetaMethods + + if method_defined?(:marshal_dump) + undef_method :marshal_dump + warn "warning: marshal_dump was undefined since it is incompatible with the Multiton pattern" + end + end + end + end + end + + extend Inclusive + + # + + module MetaMethods + + include Inclusive + + def instance(*e, &b) + arg = multiton_id(*e, &b) + multiton_instance.fetch(arg) do + multiton_mutex[arg].synchronize do + multiton_instance.fetch(arg) do + val = multiton_instance[arg] = new!(*e, &b) #new(*e, &b) + val.instance_variable_set(:@multiton_initializer, e, &b) + multiton_mutex.initialized(arg) + val + end + end + end + end + alias_method :new, :instance + + def initialized?(*e, &b) + multiton_instance.key?(multiton_id(*e, &b)) + end + + protected + + def multiton_instance + @multiton_instance ||= Hash.new + end + + def multiton_mutex + @multiton_mutex ||= InstanceMutex.new + end + + def reinitialize + multiton_instance.clear + multiton_mutex.clear + end + + def _load(str) + instance(*Marshal.load(str)) + end + + private + + # Default method to to create a key to cache already constructed + # instances. In the use case MultitonClass.new(e), MultiClass.new(f) + # must be semantically equal if multiton_id(e).eql?(multiton_id(f)) + # evaluates to true. + def multiton_id(*e, &b) + e + end + + def singleton_method_added(sym) + super + if (sym == :marshal_dump) & singleton_methods.include?('marshal_dump') + raise TypeError, "Don't use marshal_dump - rely on _dump and _load instead" + end + end + + end + +end + + + + +=begin +# TODO: Convert this into a real test and/or benchmark. + +if $0 == __FILE__ + + ### Simple marshalling test ####### + class A + def initialize(a,*e) + @e = a + end + + include Multiton + begin + def self.marshal_dump(depth = -1) + end + rescue => mes + p mes + class << self; undef marshal_dump end + end + end + + C = Class.new(A.clone) + s = C.instance('a','b') + + raise unless Marshal.load(Marshal.dump(s)) == s + + + ### Interdependent initialization example and threading benchmark ### + + class Regular_SymPlane + def self.multiton_id(*e) + a,b = e + (a+b - 1)*(a+b )/2 + (a > b ? a : b) + end + + def initialize(a,b) + klass = self.class + if a < b + @l = b > 0 ? klass.instance(a,b-1) : nil + @r = a > 0 ? klass.instance(a-1,b) : nil + else + @l = a > 0 ? klass.instance(a-1,b) : nil + @r = b > 0 ? klass.instance(a,b-1) : nil + end + end + + include Multiton + end + + + + def nap + # Thread.pass + sleep(rand(0.01)) + end + + class SymPlane < Regular_SymPlane + @m = Mutex.new + @count = 0 + end + + class << SymPlane + attr_reader :count + def reinitialize + super + @m = Mutex.new + @count = 0 + end + def inherited(sub_class) + super + sub_class.instance_eval { @m = Mutex.new; @count = 0 } + end + + def multiton_id(*e) + nap() + super + end + + def new!(*e) # NOTICE!!! + super + ensure + nap() + @m.synchronize { p @count if (@count += 1) % 15 == 0 } + end + + def run(k) + threads = 0 + max = k * (k+1) / 2 + puts "" + while count() < max + Thread.new { threads+= 1; instance(rand(30),rand(30)) } + end + puts "\nThe simulation created #{threads} threads" + end + end + + + require 'benchmark' + include Benchmark + + bmbm do |x| + x.report('Initialize 465 SymPlane instances') { SymPlane.run(30) } + x.report('Reinitialize ') do + sleep 3 + SymPlane.reinitialize + end + end + +end +=end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/net/http.rb b/bin/gems/facets-3.1.0/lib/standard/facets/net/http.rb new file mode 100644 index 00000000..4f9e90e2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/net/http.rb @@ -0,0 +1,51 @@ +require 'net/http' + +module Net + + # Returns a response object for the given URL or raises + # an exception with the appropriate error status code if unable to + # complete the request + # + # Net.download('http://example.com/') + # Net.download('http://example.com/', 2) # fail after 2 redirects + # + # CREDIT: Daniel Huckstep + def self.download(url, limit = nil) + limit ||= 10 + raise ArgumentError, 'HTTP redirect too deep' if limit.zero? + resp = Net::HTTP.get_response(URI.parse(url)) + case resp + when Net::HTTPSuccess then resp + when Net::HTTPRedirection then download(resp['location'], limit - 1) + else resp.error! + end + end + + # Downloads a given URL and saves it to disk at the specified path. + # If path is not provided or nil, then the last segment in the path of + # the URL is used as the file name. + # + # Takes a third parameters as a hash of options: + # * limit - passed to Net.download to limit number of redirects + # * mode, :open_args, etc - passed to File.write to save the file. + # For details on those options, see File.write + # + # # Saves robots.txt to PWD as robots.txt + # Net.download_and_save('http://example.com/robots.txt') + # + # # Saves robots.txt to PWD as example.txt + # Net.download_and_save('http://example.com/robots.txt', 'example.txt') + # + # # Saves robots.txt to PWD as robots.txt, and writes the result as binary + # Net.download_and_save('http://example.com/robots.txt', nil, mode: 'wb') + # + # CREDIT: Daniel Huckstep + def self.download_and_save(url, path = nil, options = {}) + opts = options.dup + path = File.expand_path(path || url.split('/').last) + raise ArgumentError.new('Save path is a directory') if File.directory?(path) + resp = download(url, opts.delete(:limit)) + File.write(path, resp.body, opts) if resp.is_a?(Net::HTTPSuccess) + end +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/nullclass.rb b/bin/gems/facets-3.1.0/lib/standard/facets/nullclass.rb new file mode 100644 index 00000000..1cf4aaf3 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/nullclass.rb @@ -0,0 +1,38 @@ +# = Nullclass +# +# NullClass is essentially NilClass but it differs in one +# important way. When a method is called against it that it +# deoesn't have, it will simply return null value rather then +# raise an error. +# +# TODO: Perhaps NullClass should be called NackClass? + +class NullClass #< NilClass + class << self + def new + @null ||= NullClass.allocate + end + end + def inspect ; 'null' ; end + def nil? ; true ; end + def null? ; true ; end + def [](key); nil; end + def method_missing(sym, *args) + return nil if sym.to_s[-1,1] == '?' + self + end +end + +module Kernel + def null + NullClass.new + end +end + +class Object + def null? + false + end +end + +# Copyright (c) 2005 Thomas Sawyer diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/opesc.rb b/bin/gems/facets-3.1.0/lib/standard/facets/opesc.rb new file mode 100644 index 00000000..78f6c723 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/opesc.rb @@ -0,0 +1,79 @@ +# = OpEsc +# +# NOTE: As of v3.0 of Facets these have been renamed: +# +# op_plus_self -> op_plus +# op_minus_self -> op_minus +# op_plus -> op_add +# op_minus -> op_sub +# op_case_eq -> op_case +# +# TODO: In the future we might also rename: +# +# op_lshift -> op_push +# op_rshift -> op_pull +# op_store -> op_index +# op_fetch -> op_index (b/c [] and []= in same file) + +module OpEsc + + OPERATORS = %w{ +@ -@ + - ** * / % ~ <=> << >> < > === == =~ <= >= | & ^ []= [] } + OPERATORS_REGEXP = Regexp.new( '(' << OPERATORS.collect{ |k| Regexp.escape(k) }.join('|') << ')' ) + OPERATORS_ESC_TABLE = { + "+@" => "op_plus", + "-@" => "op_minus", + "+" => "op_add", + "-" => "op_sub", + "**" => "op_pow", + "*" => "op_mul", + "/" => "op_div", + "%" => "op_mod", + "~" => "op_tilde", + "<=>" => "op_cmp", + "<<" => "op_lshift", #push? + ">>" => "op_rshift", #pull? + "<" => "op_lt", + ">" => "op_gt", + "===" => "op_case", + "==" => "op_equal", + "=~" => "op_apply", + "<=" => "op_lt_eq", + ">=" => "op_gt_eq", + "|" => "op_or", + "&" => "op_and", + "^" => "op_xor", + "[]=" => "op_store", + "[]" => "op_fetch" + } + + # Applies operator escape's according to OPERATORS_ESCAPE_TABLE. + # + # OpEsc.escape('-') #=> "op_sub" + # + # CREDIT: Trans + + def self.escape(str) + str.to_s.gsub(OPERATORS_REGEXP){ OPERATORS_ESC_TABLE[$1] } + end + + # + def self.method_to_filename(name) + fname = escape(name) + fname = fname[0...-1] if fname =~ /[\!\=\?]$/ + fname + end + + ## Require a file with puncuation marks escaped. + ## + ## require_esc '[].rb' + ## + ## in actuality requires the file 'op_fetch.rb'. + ## + ## def require_esc( fpath ) + ## fdir, fname = File.split(fpath) + ## fname = method_to_filename(fname) + ## path = File.join(fdir, fname) + ## require(path) + ## end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct.rb new file mode 100644 index 00000000..5349c25d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct.rb @@ -0,0 +1,91 @@ +require 'ostruct' +require 'facets/ostruct/initialize' +require 'facets/ostruct/to_h' +require 'facets/ostruct/merge' +require 'facets/ostruct/each' +require 'facets/ostruct/to_ostruct' +require 'facets/ostruct/op_fetch' +require 'facets/ostruct/op_store' + +class OpenStruct + + #-- + # TO BE DEPRECATED + # Must consider that accessing instance_delegate instead can be dangerous. + # Might we us a Functor to ensure the table keys are always symbols? + #++ + + # Provides access to an OpenStruct's inner table. + # + # o = OpenStruct.new + # o.a = 1 + # o.b = 2 + # o.instance_delegate.map { |k, v| "#{k} #{v}" } + # #=> ["a 1", "b 2"] + # + # @deprecated Use `#marshal_dump` instead. + # + def instance_delegate + warn "OpenStruct#instance_delegate is deprecated, use #marshal_dump instead." + @table + end + + # @deprecated Use `#marshal_dump` instead. + alias ostruct_delegate instance_delegate + + # Insert/update hash data on the fly. + # + # o = OpenStruct.new + # o.ostruct_update(:a => 2) + # o.a #=> 2 + # + # @deprecated Use #merge! instead. + # + def ostruct_update(other) + warn "OpenSrtuct#ostruct_update has been deprecated. Use #merge! instead." + merge!(other) + end + + # Insert/update hash data on the fly. + # + # o = OpenStruct.new + # o.ostruct_update(:a => 2) + # o.a #=> 2 + # + # @deprecated Use #merge! instead. + # + def __update__(other) + raise NameError, "OpenSrtuct#__update__ has been deprecated. Use #merge! instead." + #merge!(other) + end + + # TODO: How to handle regular merge, since it lacks punctuation to make it safe. + # Maybe `#update!`? Kind of odd but could work. + + # Merge hash data creating a new OpenStruct object. + # + # o = OpenStruct.new + # x = o.ostruct_merge(:a => 2) + # x.a #=> 2 + # + def ostruct_merge(other) + o = dup + o.merge!(other) + o + end + + # Merge hash data creating a new OpenStruct object. + # + # o = OpenStruct.new + # x = o.__merge__(:a => 2) + # x.a #=> 2 + # + def __merge__(other) + o = dup + o.merge!(other) + o + end + +end + +# Copyright (c) 2005 Thomas Sawyer (Ruby License) diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/each.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/each.rb new file mode 100644 index 00000000..fddaf56a --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/each.rb @@ -0,0 +1,11 @@ +require 'ostruct' + +class OpenStruct + + # Iterate over key-value pairs. + # + def each(&blk) + @table.each(&blk) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/initialize.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/initialize.rb new file mode 100644 index 00000000..e602dc62 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/initialize.rb @@ -0,0 +1,48 @@ +require 'ostruct' + +class OpenStruct + + # Allows the initialization of an OpenStruct with a setter block: + # + # person = OpenStruct.new do |o| + # o.name = 'John Smith' + # o.gender = :M + # o.age = 71 + # end + # + # You can still provide a hash for initialization purposes, and even combine + # the two approaches if you wish. + # + # person = OpenStruct.new(:name => 'John Smith', :age => 31) do |p| + # p.gender = :M + # end + # + # Alternatively you can provide a default block: + # + # stuff = OpenStruct.new{ |o,k| o[k] = [] } + # stuff.place << :a + # stuff.place << :b + # stuff.place #=> [:a, :b] + # + # A setter block versus a defualt block is determined by the arity of + # the block. You cannot provide both at the same time. + # + # CREDIT: Noah Gibbs, Gavin Sinclair + def initialize(hash=nil, &block) + if block && block.arity==2 + @table = Hash.new(&block) + else + @table = {} + end + if hash + for k,v in hash + @table[k.to_sym] = v + new_ostruct_member(k) + end + end + if block && block.arity==1 + yield self + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/merge.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/merge.rb new file mode 100644 index 00000000..68458ad6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/merge.rb @@ -0,0 +1,21 @@ +require 'ostruct' + +class OpenStruct + + # Insert/update hash data on the fly. + # + # o = OpenStruct.new + # o.merge!(:a => 2) + # o.a #=> 2 + # + def merge!(other) + raise TypeError, "can't modify frozen #{self.class}", caller(1) if self.frozen? + ##other = other.to_hash #to_h? + for k,v in other + @table[k.to_sym] = v + end + self + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_fetch.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_fetch.rb new file mode 100644 index 00000000..e6527c83 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_fetch.rb @@ -0,0 +1,29 @@ +require 'ostruct' + +class OpenStruct + + # Access a value in the OpenStruct by key, like a Hash. + # This increases OpenStruct's "duckiness". + # + # o = OpenStruct.new + # o.t = 4 + # o['t'] #=> 4 + # + def [](key) + key = key.to_sym unless key.is_a?(Symbol) + @table[key] + end + + # Set a value in the OpenStruct by key, like a Hash. + # + # o = OpenStruct.new + # o['t'] = 4 + # o.t #=> 4 + # + def []=(key,val) + raise TypeError, "can't modify frozen #{self.class}", caller(1) if self.frozen? + key = key.to_sym unless key.is_a?(Symbol) + @table[key]=val + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_store.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_store.rb new file mode 100644 index 00000000..7981e08f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/op_store.rb @@ -0,0 +1 @@ +require 'facets/ostruct/op_fetch' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_h.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_h.rb new file mode 100644 index 00000000..bafa6e15 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_h.rb @@ -0,0 +1,10 @@ +require 'ostruct' + +class OpenStruct + + # + def to_h + @table.dup + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_ostruct.rb b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_ostruct.rb new file mode 100644 index 00000000..6996046d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/ostruct/to_ostruct.rb @@ -0,0 +1,65 @@ +require 'ostruct' + +class OpenStruct + # + def to_ostruct + self + end +end + +class Hash + # Turns a hash into a generic object using an OpenStruct. + # + # o = {'a' => 1}.to_ostruct + # o.a #=> 1 + # + def to_ostruct + OpenStruct.new(self) + end + + ## Recursively converts a Hash object to an OpenStruct object. + ## + ## Returns a copy of the hash as an OpenStruct. + #def to_ostruct() + # struct = OpenStruct.new(self.clone()) + # each do |k, v| + # struct.__send__("#{k}=", v.to_ostruct()) if v.is_a?(Hash) + # struct.__send__(k).map! {|x| x.is_a?(Hash) ? x.to_ostruct() : x} if v.is_a?(Array) + # end + # return struct + #end + + # Like `#to_ostruct` but recusively objectifies all hash elements as well. + # + # o = {'a' => { 'b' => 1 }}.to_ostruct_recurse + # o.a.b #=> 1 + # + # The `exclude` parameter is used internally to prevent infinite + # recursion and is not intended to be utilized by the end-user. + # But for more advance use, if there is a particular subhash you + # would like to prevent from being converted to an OpoenStruct + # then include it in the `exclude` hash referencing itself. e.g. + # + # h = { 'a' => { 'b' => 1 } } + # o = h.to_ostruct_recurse( { h['a'] => h['a'] } ) + # o.a['b'] #=> 1 + # + # CREDIT: Alison Rowland, Jamie Macey, Mat Schaffer + def to_ostruct_recurse(exclude={}) + return exclude[self] if exclude.key?( self ) + o = exclude[self] = OpenStruct.new + h = self.dup + each_pair do |k,v| + h[k] = v.to_ostruct_recurse( exclude ) if v.respond_to?(:to_ostruct_recurse) + end + o.merge!(h) + end +end + +class NilClass + # Create an empty OpenStruct object. + def to_ostruct + OpenStruct.new + end +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname.rb new file mode 100644 index 00000000..6b2b61d0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname.rb @@ -0,0 +1,56 @@ +require 'pathname' + +require 'facets/pathname/home' +require 'facets/pathname/null' +require 'facets/pathname/op_div' +require 'facets/pathname/op_fetch' +require 'facets/pathname/root' +require 'facets/pathname/work' + +require 'facets/pathname/empty' +require 'facets/pathname/exists' +require 'facets/pathname/glob' +require 'facets/pathname/outofdate' +require 'facets/pathname/readline' +require 'facets/pathname/rootname' +require 'facets/pathname/safe' +require 'facets/pathname/split_root' +require 'facets/pathname/to_str' +require 'facets/pathname/uptodate' +require 'facets/pathname/visit' + +require 'facets/pathname/to_path' + + +## # Already included in 1.8.4+ version of Ruby (except for inclusion flag) +## if not instance_methods.include?(:ascend) +## +## # Calls the _block_ for every successive parent directory of the +## # directory path until the root (absolute path) or +.+ (relative path) +## # is reached. +## def ascend(inclusive=false,&block) # :yield: +## cur_dir = self +## yield( cur_dir.cleanpath ) if inclusive +## until cur_dir.root? or cur_dir == Pathname.new(".") +## cur_dir = cur_dir.parent +## yield cur_dir +## end +## end +## +## end +## +## # Already included in 1.8.4+ version of Ruby +## if ! instance_methods.include?(:descend) +## +## # Calls the _block_ for every successive subdirectory of the +## # directory path from the root (absolute path) until +.+ +## # (relative path) is reached. +## def descend() +## @path.scan(%r{[^/]*/?})[0...-1].inject('') do |path, dir| +## yield Pathname.new(path << dir) +## path +## end +## end +## +## end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/chdir.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/chdir.rb new file mode 100644 index 00000000..dee4ff1e --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/chdir.rb @@ -0,0 +1,15 @@ +class Pathname + + # Change current working directory of the process + # to the given path + # + # See Dir.chdir + # + # CREDIT: Ryan Duryea + + def chdir(&block) + Dir.chdir(self, &block) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/empty.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/empty.rb new file mode 100644 index 00000000..cdc41dd8 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/empty.rb @@ -0,0 +1,10 @@ +class Pathname + + # Is a directory path empty? + # + # Returns [Boolean] + def empty? + Dir.glob(::File.join(to_s, '*')).empty? + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/exists.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/exists.rb new file mode 100644 index 00000000..79846069 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/exists.rb @@ -0,0 +1,6 @@ +class Pathname + + # Pluralized alias for `#exist?` method. + alias :exists? :exist? + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/glob.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/glob.rb new file mode 100644 index 00000000..67694e26 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/glob.rb @@ -0,0 +1,57 @@ +class Pathname + + # Glob pathnames. + def glob(match, *opts) + flags = glob_flags(opts) + Dir.glob(::File.join(self.to_s, match), flags).collect{ |m| self.class.new(m) } + end + + # Return the first glob match. + # + # DEPRECATE: While slightly faster then glob().first, not really worth it + # unless this can be rewritten to shortcut on first match (using fnmatch?). + # In wich case, is there a better name for this method? + def glob_first(match, *opts) + flags = glob_flags(opts) + file = ::Dir.glob(::File.join(self.to_s, match), flags).first + file ? self.class.new(file) : nil + end + + # Return globbed matches with pathnames relative to the current pathname. + def glob_relative(match, *opts) + flags = glob_flags(opts) + files = Dir.glob(::File.join(self.to_s, match), flags) + files = files.map{ |f| f.sub(self.to_s.chomp('/') + '/', '') } + files.collect{ |m| self.class.new(m) } + end + + # Does a directory contain a matching entry? + # Or if the pathname is a file, same as #fnmatch. + # + # TODO: Move to own file? Better name? + # + # Returns [Pathname] + + def include?(pattern,*opts) + if directory? + glob_first(pattern,*opts) + else + fnmatch(pattern,*opts) + end + end + +private + + def glob_flags(opts) + flags = 0 + opts.each do |opt| + case opt when Symbol, String + flags += ::File.const_get("FNM_#{opt}".upcase) + else + flags += opt + end + end + flags + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/home.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/home.rb new file mode 100644 index 00000000..d4dec14f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/home.rb @@ -0,0 +1,12 @@ +class Pathname + + # Home constant for building paths from root directory onward. + # + # TODO: Pathname#home needs to be more robust. + # + # Returns [Pathname] + def self.home + Pathname.new('~') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/null.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/null.rb new file mode 100644 index 00000000..2ad7b5ad --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/null.rb @@ -0,0 +1,20 @@ +class Pathname + + # Platform dependent null device. + # + # CREDIT: Daniel Burger + + def self.null + case RUBY_PLATFORM + when /mswin/i + 'NUL' + when /amiga/i + 'NIL:' + when /openvms/i + 'NL:' + else + '/dev/null' + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_div.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_div.rb new file mode 100644 index 00000000..aa904756 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_div.rb @@ -0,0 +1,15 @@ +class Pathname + + # Start a path. Another alias for #new. + # + # Pathname / 'usr' + # + def self./(path) + new(path) + end + + # Try to get this into standard Pathname class. + alias_method :/, :+ + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_fetch.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_fetch.rb new file mode 100644 index 00000000..501bbdbf --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/op_fetch.rb @@ -0,0 +1,13 @@ +class Pathname + + # Alternate to Pathname#new. + # + # Pathname['/usr/share'] + # + # Returns [Pathname] + + def self.[](path) + new(path) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/outofdate.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/outofdate.rb new file mode 100644 index 00000000..fcc530ff --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/outofdate.rb @@ -0,0 +1,13 @@ +require 'facets/fileutils/outofdate' + +class Pathname + + # Is a path out of date relative a set of source files. + # + # Returns [Boolean] + + def outofdate?(*sources) + ::FileUtils.outofdate?(to_s, sources.flatten) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/readline.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/readline.rb new file mode 100644 index 00000000..e829991f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/readline.rb @@ -0,0 +1,13 @@ +class Pathname + # Reads the first line of the file + # + # Captures the best practice from this post at stack overflow: + # https://stackoverflow.com/questions/1490138/reading-the-first-line-of-a-file-in-ruby + # + # Credit: Ryan Duryea + def readline(*args) + open { |f| f.readline(*args) } + end +end + + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/root.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/root.rb new file mode 100644 index 00000000..0db9cbb7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/root.rb @@ -0,0 +1,10 @@ +class Pathname + + # Root constant for building paths from root directory onward. + # + # Returns [Pathname] + def self.root + Pathname.new('/') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/rootname.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/rootname.rb new file mode 100644 index 00000000..8f34e930 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/rootname.rb @@ -0,0 +1,10 @@ +require 'facets/file/rootname' + +class Pathname + + # + def rootname + self.class.new(File.rootname(to_s)) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/safe.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/safe.rb new file mode 100644 index 00000000..25ae655d --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/safe.rb @@ -0,0 +1,15 @@ +require 'facets/filetest/safe' + +class Pathname + + # Is a path reasonably safe? + # + # Do not mistake this for a perfect solution! + # + # Returns [Boolean] + + def safe? + FileTest.safe?(to_s) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/split_root.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/split_root.rb new file mode 100644 index 00000000..bf608518 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/split_root.rb @@ -0,0 +1,9 @@ +class Pathname + + # + def split_root + head, tail = *::File.split_root(to_s) + [self.class.new(head), self.class.new(tail)] + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_path.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_path.rb new file mode 100644 index 00000000..774657f4 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_path.rb @@ -0,0 +1,28 @@ +# Unfortunately NilClass#to_path causes FileUtils to bomb when testing +# for symlinks. See issue #77. It would be better if Ruby could be changed +# so this would work. But until then we have no choice but to deprecate +# this method. + +#class NilClass +# # Provide platform dependent null path. +# # +# # @standard +# # require 'facets/pathname' +# # +# # @author Daniel Burger +# def to_path +# Pathname.null +# end +#end + +class Array + # Convert array to Pathname instance. + # + # @standard + # require 'facets/pathname' + # + def to_path + Pathname.new(join('/')) + end +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_str.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_str.rb new file mode 100644 index 00000000..8c7d93a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/to_str.rb @@ -0,0 +1,8 @@ +class Pathname + + # Alias #to_s to #to_str when #to_str is not defined. + # + # Returns [String] + alias_method(:to_str, :to_s) unless method_defined?(:to_str) + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/uptodate.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/uptodate.rb new file mode 100644 index 00000000..4badbdb6 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/uptodate.rb @@ -0,0 +1,11 @@ +class Pathname + + # Is a path up to date relative to a set of source files? + # + # Returns [Boolean] + + def uptodate?(*sources) + ::FileUtils.uptodate?(to_s, sources.flatten) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/visit.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/visit.rb new file mode 100644 index 00000000..4c41a2e0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/visit.rb @@ -0,0 +1,38 @@ +class Pathname + + # Recursively visit a directory located by its path, yielding each resource + # as its full matching pathname object. If called on a file, yield the file. + # + # call-seq: + # visit => yield each file + # visit(all: true) => yield visited directories as well + # visit(hidden: true) => yield hidden files and directories as well + # + # Examples + # + # # Locate any file but *.haml within app/**/* + # Pathname.new("app").visit do |f| + # next unless f.to_s =~ /\.haml$/ + # f + # end + # + # TODO: Use #map instead of #each? + # + # CREDIT: Jean-Denis Vauguet + + def visit(options = {:all => false, :hidden => false}) + if self.directory? + children.each do |entry| + next if entry.basename.to_s[0] == "." && !options[:hidden] + yield(entry) unless entry.directory? && !options[:all] + ##entry.visit(:all => options[:all]) { |sub_entry| yield sub_entry } if entry.directory? + entry.visit(:all => options[:all], :hidden => options[:hidden]) do |sub_entry| + yield(sub_entry) + end if entry.directory? + end + else + yield self + end + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/pathname/work.rb b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/work.rb new file mode 100644 index 00000000..7bf73b85 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/pathname/work.rb @@ -0,0 +1,10 @@ +class Pathname + + # Work constant for building paths from root directory onward. + # + # Returns [Pathname] + def self.work + Pathname.new('.') + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/platform.rb b/bin/gems/facets-3.1.0/lib/standard/facets/platform.rb new file mode 100644 index 00000000..f2e1397f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/platform.rb @@ -0,0 +1,377 @@ +require 'facets/rbconfig' + +unless defined?(RUBY_ENGINE) + RUBY_ENGINE = 'ruby' +end + +# Platform class +# +# Original version from RubyGems, Copyright (c) 2007 Eric Hodel +class Platform + + # A pure-ruby gem that may use Gem::Specification#extensions to build + # binary files. + RUBY = 'ruby' + + # A platform-specific gem that is built for the packaging ruby's platform. + # This will be replaced with Gem::Platform::local. + CURRENT = 'current' + + @local = nil + @supported = nil + + # + attr_accessor :cpu + + # + attr_accessor :os + + # + attr_accessor :version + + ##RbConfig = Config unless defined? ::RbConfig + + ##DEPRECATED_CONSTS = [ + ## :DARWIN, + ## :LINUX_586, + ## :MSWIN32, + ## :PPC_DARWIN, + ## :WIN32, + ## :X86_LINUX + ##] + + # Array of supported platforms (ie. pure-Ruby and local platform). + + def self.supported + @suported ||= [Platform::RUBY, Platform.local] + end + + ##def self.const_missing(name) # TODO remove six months from 2007/12 + ## if DEPRECATED_CONSTS.include? name then + ## raise NameError, "#{name} has been removed, use CURRENT instead" + ## else + ## super + ## end + ##end + + # + def self.local + arch = RbConfig::CONFIG['arch'] + arch = "#{arch}_60" if arch =~ /mswin32$/ + @local ||= new(arch) + end + + # + def self.match(platform) + supported.any? do |local_platform| + platform.nil? or local_platform == platform or + (local_platform != Platform::RUBY and local_platform =~ platform) + end + end + + # + def self.new(arch) # :nodoc: + case arch + when Platform::CURRENT then + Platform.local + when Platform::RUBY, nil, '' then + Platform::RUBY + else + super + end + end + + # + def initialize(arch) + case arch + when Array then + @cpu, @os, @version = arch + when String then + arch = arch.split '-' + + if arch.length > 2 and arch.last !~ /\d/ then # reassemble x86-linux-gnu + extra = arch.pop + arch.last << "-#{extra}" + end + + cpu = arch.shift + + @cpu = case cpu + when /i\d86/ then 'x86' + else cpu + end + + if arch.length == 2 and arch.last =~ /^\d+$/ then # for command-line + @os, @version = arch + return + end + + os, = arch + @cpu, os = nil, cpu if os.nil? # legacy jruby + + @os, @version = case os + when /aix(\d+)/ then [ 'aix', $1 ] + when /cygwin/ then [ 'cygwin', nil ] + when /darwin(\d+)?/ then [ 'darwin', $1 ] + when /freebsd(\d+)/ then [ 'freebsd', $1 ] + when /hpux(\d+)/ then [ 'hpux', $1 ] + when /^java$/, /^jruby$/ then [ 'java', nil ] + when /^java([\d.]*)/ then [ 'java', $1 ] + when /linux/ then [ 'linux', $1 ] + when /mingw32/ then [ 'mingw32', nil ] + when /(mswin\d+)(\_(\d+))?/ then + os, version = $1, $3 + @cpu = 'x86' if @cpu.nil? and os =~ /32$/ + [os, version] + when /netbsdelf/ then [ 'netbsdelf', nil ] + when /openbsd(\d+\.\d+)/ then [ 'openbsd', $1 ] + when /solaris(\d+\.\d+)/ then [ 'solaris', $1 ] + # test + when /^(\w+_platform)(\d+)/ then [ $1, $2 ] + else [ 'unknown', nil ] + end + when Platform then + @cpu = arch.cpu + @os = arch.os + @version = arch.version + else + raise ArgumentError, "invalid argument #{arch.inspect}" + end + end + + # + def inspect + "#<%s:0x%x @cpu=%p, @os=%p, @version=%p>" % [self.class, object_id, *to_a] + end + + # + def to_a + [@cpu, @os, @version] + end + + # + def to_s + to_a.compact.join '-' + end + + # + def ==(other) + self.class === other and + @cpu == other.cpu and @os == other.os and @version == other.version + end + + # + def ===(other) + return nil unless Platform === other + + # cpu + (@cpu == 'universal' or other.cpu == 'universal' or @cpu == other.cpu) and + + # os + @os == other.os and + + # version + (@version.nil? or other.version.nil? or @version == other.version) + end + + # + def =~(other) + case other + when Platform then # nop + when String then + # This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007 + other = case other + when /^i686-darwin(\d)/ then ['x86', 'darwin', $1] + when /^i\d86-linux/ then ['x86', 'linux', nil] + when 'java', 'jruby' then [nil, 'java', nil] + when /mswin32(\_(\d+))?/ then ['x86', 'mswin32', $2] + when 'powerpc-darwin' then ['powerpc', 'darwin', nil] + when /powerpc-darwin(\d)/ then ['powerpc', 'darwin', $1] + when /sparc-solaris2.8/ then ['sparc', 'solaris', '2.8'] + when /universal-darwin(\d)/ then ['universal', 'darwin', $1] + else other + end + + other = Platform.new other + else + return nil + end + + self === other + end + + # B Y T E O R D E R + + # Byte order of CPU. Determine byte order of underlying machine. + # + # Examines the byte order of the underlying machine. Returns :big + # if Big Endian and :little if Little Endian. + # + # TODO: This doesn't work well apearently. We need to use a chart for possible + # cpus instead, maybe. + def byte_order + if [0x12345678].pack("L") == "\x12\x34\x56\x78" + :big + else + :little + end + end + + # + alias_method :byteorder, :byte_order + + # + def little_endian? + byte_order == :little + end + + # + def big_endian? + byte_order == :big + end + + # R U B Y E N G I N E + + # Return the name of the ruby interpreter. + def interpreter + @interpreter ||= ( + if RUBY_PLATFORM == 'parrot' + 'cardinal' + elsif RUBY_ENGINE == 'ruby' + if RUBY_DESCRIPTION =~ /Enterprise/i + 'ree' + else + 'mri' + end + else + RUBY_ENGINE.to_s # jruby, rbx, ironruby, macruby, etc. + end + ) + end + + def mri? + 'mri' === interpreter + end + alias official_ruby? mri? + alias ruby? mri? + + def jruby? + 'jruby' === interpreter + end + alias java? jruby? + + def rubinius? + 'rbx' === interpreter + end + alias rbx? rubinius? + + def ree? + 'ree' === interpreter + end + alias enterprise? ree? + + def ironruby? + 'ironruby' === interpreter + end + alias iron_ruby? ironruby? + + def cardinal? + 'cardinal' === interpreter + end + alias parrot? cardinal? + alias perl? cardinal? + + + # O P E R A T I N G S Y S T E M + + def host_os + RbConfig::CONFIG['host_os'] + end + + def linux? + host_os =~ /linux|cygwin/ + end + + def mac? + host_os =~ /mac|darwin/ + end + + def bsd? + host_os =~ /bsd/ + end + + def windows? + host_os =~ /mswin|mingw/ + end + + def solaris? + host_os =~ /solaris|sunos/ + end + + # TODO: who knows what symbian returns? + def symbian? + host_os =~ /symbian/ + end + + # + def posix? + linux? or mac? or bsd? or solaris? or begin + fork do end + true + rescue NotImplementedError, NoMethodError + false + end + end + +end + + +# Current CPU's Byte Order +#BYTE_ORDER = RbConfig.byte_order + +# Current CPU +#CPU = RbConfig.platform.cpu + +# Current Operating System +#OS = RbConfig.platform.os + +# Current Operating System Version +#OS_VERSION = RbConfig.platform.version + + +=begin + # platform + def current_platform + arch = Config::CONFIG['arch'] + #cpu, os = arch.split '-', 2 + return match_platform(arch) + end + + # + def match_platform(arch) + cpu, os = arch.split '-', 2 + cpu, os = nil, cpu if os.nil? # java + + cpu = case cpu + when /i\d86/ then 'x86' + else cpu + end + + os = case os + when /cygwin/ then [ 'cygwin', nil ] + when /darwin(\d+)?/ then [ 'darwin', $1 ] + when /freebsd(\d+)/ then [ 'freebsd', $1 ] + when /^java$/ then [ 'java', nil ] + when /^java([\d.]*)/ then [ 'java', $1 ] + when /linux/ then [ 'linux', $1 ] + when /mingw32/ then [ 'mingw32', nil ] + when /mswin32/ then [ 'mswin32', nil ] + when /openbsd(\d+\.\d+)/ then [ 'openbsd', $1 ] + when /solaris(\d+\.\d+)/ then [ 'solaris', $1 ] + else [ 'unknown', nil ] + end + + [cpu, os].flatten.compact.join("-") + end +=end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/random.rb b/bin/gems/facets-3.1.0/lib/standard/facets/random.rb new file mode 100644 index 00000000..495271ed --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/random.rb @@ -0,0 +1,476 @@ +require 'facets/hash/zip' +require 'facets/string/shatter' +require 'facets/kernel/maybe' + +# = Randomization Extensions +# +# This library extends Array, String, Hash and other classes with randomization +# methods. Most of the methods are of one of two kinds. Either they "pick" a +# random element from the reciever or they randomly "shuffle" the reciever. +# +# The most common example is Array#shuffle, which simply randmomizes the +# order of an array's elements. +# +# [1,2,3].shuffle #~> [2,3,1] +# +# The other methods do similar things for their respective classes. +# +# The classes are all extended via mixins which have been created within +# Ruby's Random class. +# +# Credit for this work is due to: +# +# * Ilmari Heikkinen +# * Christian Neukirchen +# * Thomas Sawyer +# +# NOTE: Inline QED tests are almost pointless here b/c... yea, it's random. +# So indtead of the usual `#=>` we use `#~>` which means approx. equal and +# prevens QED from making a hard assertion. + +class Random + + class << self + # Alias for Kernel#rand. + alias_method :number, :rand + + public :number + end + + ##def self.number(*args) + ## ::Kernel.rand(*args) + ##end + + # Module method to generate a random letter. + # + # Random.letter #~> "q" + # Random.letter #~> "r" + # Random.letter #~> "a" + # + def self.letter + (Random.number(26) + (Random.number(2) == 0 ? 65 : 97) ).chr + end + + # Random extensions for Range class. + # + module RangeExtensions + # Return a random element from the range. + # + # (1..4).at_rand #~> 2 + # (1..4).at_rand #~> 4 + # + # (1.5..2.5).at_rand #~> 2.06309842754533 + # (1.5..2.5).at_rand #~> 1.74976944931541 + # + # ('a'..'z').at_rand #~> 'q' + # ('a'..'z').at_rand #~> 'f' + # + # CREDIT: Lavir the Whiolet, Thomas Sawyer + def at_rand + first, last = first(), last() + if first.respond_to?(:random_delta) # TODO: work on this!!! + begin + first.random_delta(last, exclude_end?) + rescue + to_a.at_rand + end + else + to_a.at_rand + end + ##elsif first.respond_to?(:succ) + ## # optimized algorithm + ## if (Fixnum === first || Bignum === first) && + ## (Fixnum === last || Bignum === last) + ## last -= 1 if exclude_end? + ## return nil if last < first + ## return Random.number(last - first + 1) + first + ## end + ## # standard algorithm + ## return to_a.at_rand + ##elsif Numeric === first && Numeric === last + ## return nil if last < first + ## return nil if exclude_end? && last == first + ## return (last - first) * Random.number + first + ##else + ## return nil + ##end + end + end + + # Random extensions fo Integer class. + # + module IntegerExtensions + # + def random_delta(last, exclude_end) + first = self + last -= 1 if exclude_end + return nil if last < first + return Random.number(last - first + 1) + first + end + end + + # Random extensions for Numeric class. + # + module NumericExtensions + # + def random_delta(last, exclude_end) + first = self + return nil if last < first + return nil if exclude_end && last == first + return (last - first) * Random.number + first + end + end + + # Random extensions for Array class. + # + module ArrayExtensions + # Return a random element from the array. + # + # [1, 2, 3, 4].at_rand #~> 2 + # [1, 2, 3, 4].at_rand #~> 4 + # + def at_rand + at(Random.number(size)) + end + + # Same as #at_rand, but acts in place removing a + # random element from the array. + # + # a = [1,2,3,4] + # a.at_rand! #~> 2 + # a #~> [1,3,4] + # + def at_rand! + return delete_at( Random.number( size ) ) + end + + # Similar to #at_rand, but will return an array of randomly + # picked exclusive elements if given a number. + def pick(n=nil) + if n + a = self.dup + a.pick!(n) + else + at(Random.number(size)) + end + end + + # Similar to #at_rand!, but given a number will return + # an array of exclusive elements. + def pick!(n=nil) + if n + if n > self.size + r = self.dup + self.replace([]) + r + else + r = [] + n.times { r << delete_at(Random.number(size)) } + r + end + else + delete_at(Random.number(size)) + end + end + + # Random index. + # + def rand_index + Random.number(size) + end + + # Returns a random subset of an Array. If a _number_ + # of elements is specified then returns that number of + # elements, otherwise returns a random number of elements + # upto the size of the Array. + # + # By defualt the returned values are exclusive of + # each other, but if _exclusive_ is set to false, + # the same values can be choosen more than once. + # + # When _exclusive_ is true (the default) and the + # _number_ given is greater than the size of the array, + # then all values are returned. + # + # [1, 2, 3, 4].rand_subset(1) #~> [2] + # [1, 2, 3, 4].rand_subset(4) #~> [2, 1, 3, 4] + # [1, 2, 3, 4].rand_subset #~> [1, 3, 4] + # [1, 2, 3, 4].rand_subset #~> [2, 3] + # + def rand_subset(number=nil, exclusive=true) + number = Random.number(size) unless number + number = number.to_int + #return self.dup if (number >= size and exlusive) + return sort_by{rand}.slice(0,number) if exclusive + ri =[]; number.times { |n| ri << Random.number(size) } + return values_at(*ri) + end + + # Generates random subarrays. Uses random numbers and bit- + # fiddling to assure performant uniform distributions even + # for large arrays. + # + # a = *1..5 + # a.rand_subarrays(2) #=> [[3, 4, 5], []] + # a.rand_subarrays(3) #=> [[1], [1, 4, 5], [2, 3]] + # + # CREDIT: Michael Kohl + def rand_subarrays(n=1) + raise ArgumentError, "negative argument" if n < 0 + (1..n).map do + r = rand(2**self.size) + self.select.with_index { |_, i| r[i] == 1 } + end + end + + # Randomize the order of an array. + # + # [1,2,3,4].shuffle #~> [2,4,1,3] + # + def shuffle + dup.shuffle! + #sort_by{Random.number} + end + + # As with #shuffle but modifies the array in place. + # The algorithm used here is known as a Fisher-Yates shuffle. + # + # a = [1,2,3,4] + # a.shuffle! + # + # a #~> [2,4,1,3] + # + # CREDIT Niel Spring + def shuffle! + s = size + each_index do |j| + i = Random.number(s-j) + #self[j], self[j+i] = self[j+i], self[j] + tmp = self[j] + self[j] = self[j+i] + self[j+i] = tmp + end + self + end + + end + + # Random extensions for Hash class. + # + module HashExtensions + # Returns a random key. + # + # {:one => 1, :two => 2, :three => 3}.pick_key #~> :three + # + def rand_key + keys.at(Random.number(keys.size)) + end + + # Delete a random key-value pair, returning the key. + # + # a = {:one => 1, :two => 2, :three => 3} + # a.rand_key! #~> :two + # a #~> {:one => 1, :three => 3} + # + def rand_key! + k,v = rand_pair + delete(k) + return k + end + + alias_method( :pick_key, :rand_key! ) + + # Returns a random key-value pair. + # + # {:one => 1, :two => 2, :three => 3}.pick #~> [:one, 1] + # + def rand_pair + k = rand_key + return k, fetch(k) + end + + # Deletes a random key-value pair and returns that pair. + # + # a = {:one => 1, :two => 2, :three => 3} + # a.rand_pair! #~> [:two, 2] + # a #~> {:one => 1, :three => 3} + # + def rand_pair! + k,v = rand_pair + delete( k ) + return k,v + end + + alias_method( :pick_pair, :rand_pair! ) + + # Returns a random hash value. + # + # {:one => 1, :two => 2, :three => 3}.rand_value #~> 2 + # {:one => 1, :two => 2, :three => 3}.rand_value #~> 1 + # + def rand_value + fetch(rand_key) + end + + # Deletes a random key-value pair and returns the value. + # + # a = {:one => 1, :two => 2, :three => 3} + # a.at_rand! #~> 2 + # a #~> {:one => 1, :three => 3} + # + def rand_value! + k,v = rand_pair + delete( k ) + return v + end + + alias_method( :pick, :rand_value! ) + + alias_method( :at_rand, :rand_value ) + alias_method( :at_rand!, :rand_value! ) + + # Returns a copy of the hash with _values_ arranged + # in new random order. + # + # h = {:a=>1, :b=>2, :c=>3} + # h.shuffle #~> {:b=>2, :c=>1, :a>3} + # + def shuffle + ::Hash.zip( keys.sort_by{Random.number}, values.sort_by{Random.number} ) + end + + # Destructive shuffle_hash. Arrange the values in + # a new random order. + # + # h = {:a => 1, :b => 2, :c => 3} + # h.shuffle! + # h #~> {:b=>2, :c=>1, :a=>3} + # + def shuffle! + self.replace(shuffle) + end + + end + + # Random extensions for String class. + # + module StringExtensions + + # + def self.included(base) + base.extend(Self) + end + + # Class-level methods. + module Self + # Returns a randomly generated string. One possible use is + # password initialization. Takes a max legnth of characters + # (default 8) and an optional valid char Regexp (default /\w\d/). + # + # String.random #~> 'dd4qed4r' + # + # CREDIT George Moschovitis + #-- + # TODO: This is not very efficient. Better way? + #++ + def random(max_length = 8, char_re = /[\w\d]/) + raise ArgumentError.new('second argument must be a regular expression') unless char_re.is_a?(Regexp) + string = "" + while string.length < max_length + ch = Random.number(255).chr + string << ch if ch =~ char_re + end + return string + end + + # Generate a random binary string of +n_bytes+ size. + # + # CREDIT: Guido De Rosa + def random_binary(n_bytes) + ( Array.new(n_bytes){ rand(0x100) } ).pack('c*') + end + end + + # Return a random separation of the string. + # Default separation is by charaacter. + # + # "Ruby rules".at_rand(' ') #~> ["Ruby"] + # + def at_rand( separator=// ) + #separator = self.class.patterns( separator ) + self.split(separator,-1).at_rand + end + + # Return a random separation while removing it + # from the string. Default separation is by character. + # + # s = "Ruby rules" + # s.at_rand!(' ') #~> "Ruby" + # s #~> "rules" + # + def at_rand!( separator=// ) + #separator = self.class.patterns( separator ) + a = self.shatter( separator ) + w = []; a.each_with_index { |s,i| i % 2 == 0 ? w << s : w.last << s } + i = Random.number(w.size) + r = w.delete_at( i ) + self.replace( w.join('') ) + return r + end + + # Return a random byte of _self_. + # + # "Ruby rules".rand_byte #~> 121 + # + def rand_byte + self[Random.number(size)] + end + + # Destructive rand_byte. Delete a random byte of _self_ and return it. + # + # s = "Ruby rules" + # s.rand_byte! #~> 121 + # s #~> "Rub rules" + # + def rand_byte! + i = Random.number(size) + rv = self[i,1] + self[i,1] = '' + rv + end + + # Return a random string index. + # + # "Ruby rules".rand_index #~> 3 + # + def rand_index + Random.number(size) + end + + # Return the string with seperated sections arranged + # in a random order. The default seperation is by character. + # + # "Ruby rules".shuffle #~> "e lybRsuur" + # + def shuffle(separator=//) + split(separator).shuffle.join('') + end + + # In place version of shuffle. + # + def shuffle!(separator=//) + self.replace( shuffle(separator) ) + end + + end + +end + +class Range ; include Random::RangeExtensions ; end +class Array ; include Random::ArrayExtensions ; end +class Hash ; include Random::HashExtensions ; end +class String ; include Random::StringExtensions ; end +class Integer ; include Random::IntegerExtensions ; end +class Numeric ; include Random::NumericExtensions ; end + +# Copyright (c) 2005 Ilmari Heikkinen, Christian Neukirchen, Thomas Sawyer diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/rbconfig.rb b/bin/gems/facets-3.1.0/lib/standard/facets/rbconfig.rb new file mode 100644 index 00000000..686cbb2c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/rbconfig.rb @@ -0,0 +1,78 @@ +# An extended rendition of the Ruby's standard RbConfig module. +module RbConfig + + # + def self.inspect + CONFIG.inspect + end + + # Methodized lookup of config. + def self.method_missing(s,*a,&b) + s = s.to_s + if CONFIG.key?(s) + CONFIG[s] + elsif CONFIG.key?(s.upcase) + CONFIG[s.upcase] + else + super(s,*a,&b) + end + end + + # TODO: parse configure_args into methods too? + + # In case rubygems has already defined it. + unless method_defined?(:datadir) + # Return the path to the data directory associated with the + # given library/package name. Normally this is just + # + # "#{Config::CONFIG['datadir']}/#{name}" + # + # but may be modified by tools like RubyGems to handle + # versioned data directories. + def self.datadir(package_name) + File.join(CONFIG['datadir'], package_name) + end + end + + # + def self.host_os + CONFIG['host_os'] + end + + def linux? + host_os =~ /linux|cygwin/ + end + + def mac? + host_os =~ /mac|darwin/ + end + + def bsd? + host_os =~ /bsd/ + end + + def windows? + host_os =~ /mswin|mingw/ + end + + def solaris? + host_os =~ /solaris|sunos/ + end + + # TODO: who knows what symbian returns? + def symbian? + host_os =~ /symbian/ + end + + # + def posix? + linux? or mac? or bsd? or solaris? or begin + fork do end + true + rescue NotImplementedError, NoMethodError + false + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/set.rb b/bin/gems/facets-3.1.0/lib/standard/facets/set.rb new file mode 100644 index 00000000..690a0780 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/set.rb @@ -0,0 +1,36 @@ +require 'set' + +class Set + + # + # @author Phrogz + def power_set + if empty? + Set[self] + else + any_value = [to_a.first] + subsubs = (self - any_value).power_set + subsubs + subsubs.map{ |subset| subset + any_value } + end + end +end + +class Array + + # TODO: Move to Array extensions. + + # + # @author Phrogz + def power_set + if empty? + [self] + else + subset = dup + value = [ subset.pop ] + subsubs = subset.power_set + subsubs.concat( subsubs.map{ |subset| subset + value } ) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/shellwords.rb b/bin/gems/facets-3.1.0/lib/standard/facets/shellwords.rb new file mode 100644 index 00000000..d105a610 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/shellwords.rb @@ -0,0 +1,115 @@ +require 'shellwords' + +module Shellwords + + module_function + + # Escape special characters used in most unix shells + # to use it, eg. with system(). + # + # This differs from Ruby's #escape in that it does not + # escape shell variables, e.g. $0. + def alt_escape(cmdline) + cmdline.gsub(/([\\\t\| &`<>)('"])/) { |s| '\\' << s } + end + + unless method_defined?(:escape) + def escape(cmdline) + cmdline.gsub(/([\\\t\| &`<>)('"])\$/) { |s| '\\' << s } + end + end + + # Escape special character used in DOS-based shells. + # + # TODO: How to integrate with rest of system? + # 1. Use platform condition? + # 2. Use separate dos_xxx methods? + # 3. Put in separate PowerShellwords module? + # + # CREDIT: Lavir the Whiolet + def dos_escape(cmdline) + '"' + cmdline.gsub(/\\(?=\\*\")/, "\\\\\\").gsub(/\"/, "\\\"").gsub(/\\$/, "\\\\\\").gsub("%", "%%") + '"' + end + + # The coolest little arguments parser in all of Rubyland. + # + # CREDIT: Michel Martens + def parse(argv, opts) + argv = (String === argv ? shellwords(argv) : argv.to_a.dup) + args = [] + while argv.any? + item = argv.shift + flag = opts[item] + if flag + # Work around lambda semantics in 1.8.7. + arity = [flag.arity, 0].max + # Raise if there are not enough parameters + # available for the flag. + if argv.size < arity + raise ArgumentError + end + # Call the lambda with N items from argv, + # where N is the lambda's arity. + flag.call(*argv.shift(arity)) + else + # Collect the items that don't correspond to + # flags. + args << item + end + end + args + end + + # Original name for Shellwords#parse. + alias_method :run, :parse + +end + +class Array + + # Convert an array into command line parameters. + # The array is accepted in the format of Ruby + # method arguments --ie. [arg1, arg2, ..., hash] + # + def shellwords + opts, args = *flatten.partition{ |e| Hash === e } + opts = opts.inject({}){ |m,h| m.update(h); m } + opts.shellwords + args + end + + # + def shelljoin + Shellwords.shelljoin(shellwords) + end + +end + +class Hash + + # + def shellwords + argv = [] + each do |f,v| + m = f.to_s.size == 1 ? '-' : '--' + case v + when false, nil + when Array + v.each do |e| + argv << %[#{m}#{f}="#{e}"] + end + when true + argv << %[#{m}#{f}] + else + argv << %[#{m}#{f}="#{v}"] + end + end + argv + end + + # + def shelljoin + shellwords.shelljoin + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/strscan.rb b/bin/gems/facets-3.1.0/lib/standard/facets/strscan.rb new file mode 100644 index 00000000..68400964 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/strscan.rb @@ -0,0 +1,16 @@ +require 'strscan' + +class StringScanner + + # scans string until +pattern+ is encountered. If +pattern+ will not be + # encountered then it returns _nil_ but if +scan_anyway+ is _true_ then + # it scans until the end of the string. + def scan_before(pattern, scan_anyway = false) + if not check_until(pattern) and not scan_anyway then return nil; end + result = "" + result << getch until check(pattern) or eos? + return result + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/thread.rb b/bin/gems/facets-3.1.0/lib/standard/facets/thread.rb new file mode 100644 index 00000000..09a0a8dd --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/thread.rb @@ -0,0 +1,98 @@ +# = Thread Related Extensions +# +# This a small colleciton of thread-related extensions. + +require 'thread' + +#require 'facets/binding/eval' +#require 'facets/kernel/__method__' + +# This is the non-threaded form of #threaded_map_send. +require 'facets/enumerable/map_send' + +module Kernel + + $MEMO_MUTEX = Mutex.new + + $MEMO ||= {} + + # Thead-safe instance-level memoization. + # + # class MemoExample + # attr_accessor :a + # def m + # safe_memo{ @a } + # end + # end + # + # ex = MemoExample.new + # + # ex.a = 10 + # ex.m #=> 10 + # + # ex.a = 20 + # ex.m #=> 10 + # + def safe_memo(*args, &block) + if args.empty? + args = block.binding.eval('[self, __method__]') + end + $MEMO_MUTEX.synchronize do + if $MEMO.key?(args) + $MEMO[args] + else + $MEMO[args] = block.call + end + end + end + +end + + +module Enumerable + + # Like Enumerable#map but each iteration is processed via + # a separate thread. + # + # CREDIT: Sean O'Halpin + + def threaded_map #:yield: + map{ |e| Thread.new(e){ |t| yield(t) } }.map{ |t| t.value } + end + + # Like Enumerable#map_send but each iteration is processed via + # a separate thread. + # + # CREDIT: Sean O'Halpin + + def threaded_map_send(meth, *args, &block) + map{ |e| Thread.new(e){ |t| t.send(meth, *args, &block) } }.map{ |t| t.value } + end + +end + + +module Kernel + private + + # CREDIT: Zucker + def sandbox(rescueblock_or_default=nil) #:yield: + Thread.start do + $SAFE = 4 + yield + end.value + rescue SecurityError => e + if !rescueblock_or_default.nil? + if rescueblock_or_default.is_a? Proc + rescueblock_or_default.call e + else + rescueblock_or_default + end + else + raise e + end + end + +end + +# Copyright (c) 2006 Sean O'Halpin, Thomas Sawyer diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/timer.rb b/bin/gems/facets-3.1.0/lib/standard/facets/timer.rb new file mode 100644 index 00000000..d070b62f --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/timer.rb @@ -0,0 +1,208 @@ +require 'timeout' # for Timeout::Error + +# = Timer +# +# Provides a strightforward means for controlling time critical execution. +# Can be used as a "stop watch" timer or as a "time bomb" timer: +# +# t = Timer.new(10) { raise Timeout::Error, "timeout!" } +# t.start +# : # done within 10sec timeout +# t.stop +# t.start +# : +# if condition then +# t.reset #--> restart timer +# end +# +# A class method is also provided for easily timing the exectuion of a block. +# +# Timer.time do |timer| +# timer.total_time.round #=> 0 +# +# sleep 1 +# timer.total_time.round #=> 1 +# +# timer.stop +# timer.total_time.round #=> 1 +# +# sleep 1 +# timer.total_time.round #=> 1 +# +# timer.start +# timer.total_time.round #=> 1 +# +# sleep 1 +# timer.total_time.round #=> 2 +# end +# +# Thanks to Paul Brannan for TimeLimit and Minero Aoki for Timer. +# These two libraries served as models for building this class. + +class Timer + + # + def initialize(time_limit=nil, &block) + # standard timer + @start_time = nil + @end_time = nil + @total_time = 0 + @runnning = nil + # for using time limit + @time_limit = time_limit + @on_timeout = block + @current_thread = nil + @timer_thread = nil + end + + # + attr_accessor :time_limit + + # + def start_time + @start_time + end + + # + def end_time + @end_time + end + + # + def on_timeout( &block ) + if block then + @on_timeout = block + true + else + false + end + end + + # Start the timer. + def start + @running = true + @start_time = Time.now + + limit if @time_limit + + self + + ##if block_given? then + ## begin + ## yield( self ) + ## ensure + ## stop + ## end + ##else + ## @time_limit + ##end + end + + # Establish a time limit on execution. + def limit( time_limit=nil ) + if @time_limit || time_limit + @current_thread = Thread.current + @timer_thread = Thread.fork { + sleep @time_limit + if @on_timeout then + @on_timeout.call @time_limit + else + @current_thread.raise Timeout::Error, "#{@time_limit} seconds past" + end + } + end + end + + # Kill time limit thread, if any. + def defuse + if @timer_thread + #Thread.kill @timer_thread + @timer_thread.kill + @timer_thread = nil + end + end + + # Stops timer and returns total time. + # If timer was not running returns false. + def stop + if @running + defuse + # record running time + @end_time = Time.now + @running = false + @total_time += (@end_time - @start_time) + else + nil + end + end + + # Stops and resets the timer. If the timer was running + # returns the total time. If not returns 0. + def reset + if running? + r = stop + else + r = 0 + end + @total_time = 0 + return r + end + + # Resets the time limit. Same as: + # + # t.stop + # t.start + # + def reset_limit + #stop + #start + defuse + limit + end + + # Queries whether the timer is still running. + def running? + return @running + end + + # Queries whether the timer is still not running. + def stopped? + return !@running + end + + # Queries total recorded time of timer. + def total_time + if running? then + return @total_time + (Time.now - @start_time) + else + return @total_time + end + end + + # Takes a block and returns the total time it took to execute. + def self.time + yield( timer = Timer.new.start ) + return timer.total_time + end + + # Timer::Dummy - Dummy Timer (i.e. no real time limit) + #-- + # TODO: Timer::Dummy needs some work. + #++ + class Dummy < self + def start + if block_given? then + yield + else + time_limit() + end + end + + def stop + false + end + end #class Dummy + +end #class Timer + +# Copyright (c) 2004 Rubyworks diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/tuple.rb b/bin/gems/facets-3.1.0/lib/standard/facets/tuple.rb new file mode 100644 index 00000000..e7e3abb1 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/tuple.rb @@ -0,0 +1,282 @@ +require 'facets/multiton' + +# = Tuple +# +# Tuple is essentially an Array, but Comaparable and Immutable. +# +# A tuple can be made using #new or #[] just as one builds an array, +# or using the #to_t method on a string or array. With a string tuple +# remembers the first non-alphanumeric character as the tuple divider. +# +# == Usage +# +# t1 = Tuple[1,2,3] +# t2 = Tuple[2,3,4] +# +# (t1 < t2) #=> true +# (t1 > t2) #=> false +# +# t1 = '1.2.3'.to_t +# t2 = '1-2-3'.to_t +# +# t1.to_s #=> "1.2.3" +# t2.to_s #=> "1.2.3" +# +# (t1 == t2) #=> true +# +# Keep in mind that Tuple[1,2,3] is not the same as Tuple['1','2','3']. +# +#-- +# TODO: The #hash method needs a touch-up. +# +# TODO: There are a few more methods yet to borrow from Array. +# Consider how #+, #-, etc. ought to work. +#++ +class Tuple + + include ::Multiton + include ::Enumerable + include ::Comparable + + def self.multiton_id(arg=0, default=0, &block) + if block_given? + values = [] + arg.times { |i| values << block[i] } + elseif Integer === arg + values = [ default ] * arg + else + values = arg.to_ary + end + values + end + + def initialize(arg=0, default=0, &blk) + if block_given? + @values = [] + arg.times { |i| @values << blk[i] } + elseif Integer === arg + @values = [ default ] * arg + else + @values = arg.to_ary + end + @default = default + ##@divider = '.' + end + + attr_accessor :default + + ##def divider( set=nil ) + ## return @divider unless set + ## @divider = set + ## self + ##end + +protected + + def values() @values end + +public + + SEGMENT_SEPARATOR = '.' + + def inspect() to_a.inspect end + + def to_t() self end + def to_tuple() self end + + def to_a() Array(@values) end + def to_ary() Array(@values) end + + def to_s(divider=nil) + @values.join(divider || SEGMENT_SEPARATOR) + end + + def size() @values.size end + def length() @values.size end + + def empty?() + return true if @values.empty? + return true if @values == [ @default ] * @values.size + false + end + + def each( &block ) + @values.each( &block ) + end + + def each_index( &block ) + @values.each_index( &block ) + end + + def [](i) + @values.fetch(i,@default) + end + + def []=(i,v) + @values[i] = v + end + + def index() @values.index end + def rindex() @values.rindex end + + # Unlike Array, Tuple#<< cannot act in place + # becuase Tuple's are immutable. + def <<( obj ) + self.class.instance( to_a << obj ) + end + + def pop() Tuple.instance( to_a.pop ) end + + def push( obj ) Tuple.instance( to_a.push(obj) ) end + + # Pulls a value off the beginning of a tuple. + # This method is otherwsie known as #shift. + def pull() Tuple.instance( to_a.shift ) end + + # Stands for "Put On Top". This method is the opposite of #pull and is + # otherwise known as #unshift. + def pot( obj ) Tuple.instance( to_a.unshift(obj) ) end + + alias_method :unshift, :pot + alias_method :shift, :pull + + # Returns true if two tuple references are for the + # very same tuple. + def eql?( other ) + return true if object_id == other.object_id + ##return true if values.eql? other.values + end + + # + def <=>( other ) + other = other.to_t + [size, other.size].max.times do |i| + c = self[i] <=> other[i] + return c if c != 0 + end + 0 + end + + # For pessimistic constraint (like '~>' in gems) + def =~( other ) + other = other.to_t + upver = other.dup + upver[0] += 1 + self >= other and self < upver + end + + def first() @values.first end + def last() @values.last end + + # These are useful for using a Tuple as a version. + def major() @values.first end + def minor() @values.at(1) end + def teeny() @values.at(2) end + + # Unique hash value. + def hash + # TODO: This needs to take into account the default + # and maybe the divider too. + to_a.hash + end + + # class-level ----------------------------------------------- + + class << self + + # + def []( *args ) + instance( args ) + end + + # Translates a string in the form on a set of numerical and/or + # alphanumerical characters separated by non-word characters (eg \W+) + # into a Tuple. The values of the tuple will be converted to integers + # if they are purely numerical. + # + # Tuple.cast_from_string('1.2.3a') #=> [1,2,"3a"] + # + # It you would like to control the interpretation of each value + # as it is added to the tuple you can supply a block. + # + # Tuple.cast_from_string('1.2.3a'){ |v| v.upcase } #=> ["1","2","3A"] + # + # This method is called by String#to_t. + def cast_from_string( str, &yld ) + args = str.to_s.split(/\W+/) + div = /\W+/.match( str.to_s )[0] + if block_given? + args = args.collect{ |a| yld[a] } + else + args = args.collect { |i| /^[0-9]+$/ =~ i ? i.to_i : i } + end + self.instance(args) #.divider( div ) + end + + # + def cast_from_array( arr ) + self.instance( arr ) + end + + # Parses a constraint returning the operation as a lambda. + def constraint_to_lambda( constraint, &yld ) + op, val = *parse_constraint( constraint, &yld ) + lambda { |t| t.send(op, val) } + end + + # + def parse_constraint( constraint, &yld ) + constraint = constraint.strip + re = %r{^(=~|~>|<=|>=|==|=|<|>)?\s*(\d+(:?[-.]\d+)*)$} + if md = re.match( constraint ) + if op = md[1] + op = '=~' if op == '~>' + op = '==' if op == '=' + val = cast_from_string( md[2], &yld ) #instance( md[2] ) + else + op = '==' + val = cast_from_string( constraint, &yld ) #instance( constraint ) + end + else + raise ArgumentError, "invalid constraint" + end + return op, val + end + + end + +end + + +class ::String + + # Translates a string in the form on a set of numerical and/or + # alphanumerical characters separated by non-word characters (eg \W+) + # into a Tuple. The values of the tuple will be converted to integers + # if they are purely numerical. + # + # '1.2.3a'.to_t #=> [1,2,"3a"] + # + # It you would like to control the interpretation of each value + # as it is added to the tuple you can supply a block. + # + # '1.2.3a'.to_t { |v| v.upcase } #=> ["1","2","3A"] + # + # This method calls Tuple.cast_from_string. + def to_t( &yld ) + Tuple.cast_from_string( self, &yld ) + end + +end + + +class ::Array + + # Convert an array into a tuple. + def to_t + Tuple.cast_from_array( self ) + end + +end + +# Copyright (c) 2005 Thomas Sawyer (Ruby License) diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri.rb new file mode 100644 index 00000000..0b877e3c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri.rb @@ -0,0 +1,40 @@ +require 'uri' + +require 'facets/uri/cgi_escape.rb' +require 'facets/uri/cgi_unescape.rb' +require 'facets/uri/cgi_parse.rb' +require 'facets/uri/decode.rb' +require 'facets/uri/parameters.rb' +require 'facets/uri/query.rb' + +module URI + + module Kernel + # + def uri(s, w=%r{[^a-zA-Z_0-9./-]}) + URI.escape(s, w) + end + + # + def unuri(s) + URI.unescape(s) + end + end + + module Hash + # + def to_uri + URI.hash_to_query(self) + end + end + +end + +class Object #:nodoc: + include URI::Kernel +end + +class Hash #:nodoc: + include URI::Hash +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_escape.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_escape.rb new file mode 100644 index 00000000..2eaef1a9 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_escape.rb @@ -0,0 +1,46 @@ +require 'uri' + +module URI + + module_function + + # TODO: How does `URI.cgi_escape` compare to `URI.escape`? + + # + # CGI escape + # + def cgi_escape(string) + string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do + '%' + $1.unpack('H2' * $1.size).join('%').upcase + end.tr(' ', '+') + end + + # + # + # + def cgi_unescape(string) + string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do + [$1.delete('%')].pack('H*') + end + end + + # + # + # + def cgi_parse(query) + params = Hash.new([].freeze) + + query.split(/[&;]/n).each do |pairs| + key, value = pairs.split('=',2).collect{|v| cgi_unescape(v) } + if params.has_key?(key) + params[key].push(value) + else + params[key] = [value] + end + end + + params + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_parse.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_parse.rb new file mode 100644 index 00000000..b5d198d7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_parse.rb @@ -0,0 +1 @@ +require 'facets/uri/cgi_escape' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_unescape.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_unescape.rb new file mode 100644 index 00000000..b5d198d7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/cgi_unescape.rb @@ -0,0 +1 @@ +require 'facets/uri/cgi_escape' diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/decode.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/decode.rb new file mode 100644 index 00000000..e70a4392 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/decode.rb @@ -0,0 +1,32 @@ +require 'uri' + +module URI + + module_function + + # Decode the uri components. + # + def decode(uri) + ## gmosx: hmm is this needed? + ## guard against invalid filenames for example pictures with + ## spaces uploaded by users + escaped_uri = uri.gsub(/ /, "+") + + if md = URI::REGEXP::REL_URI.match(escaped_uri) + path = "#{md[5]}#{md[6]}" + type = File.extname(path) + query_string = md[7] + + ## real_path = "#{$root_dir}/#{path}" + + parameters = URI.query_to_hash(query_string) + path.gsub!(/\+/, " ") + + return [path, type, parameters, query_string] + end + + ## this is usefull for uncovering bugs! + raise ArgumentError.new("the parameter '#{uri}' is not a valid uri") + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/parameters.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/parameters.rb new file mode 100644 index 00000000..bb2dcfc0 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/parameters.rb @@ -0,0 +1,63 @@ +require 'uri' + +module URI + + # Allows for taking a hash and turning it into URI/CGI params + # Since 1.8.x does not have ordered hashes the params might not + # be ordered. + # + # @todo URI.parameters needs URI escaping. + # + # @author Matt Kirk + + def self.parameters(hash) + hash.map do |k,v| + if v.respond_to?(:join) + "#{k}=#{v.join(",")}" + else + "#{k}=#{v}" + end + end.join("&") + end + + # We cannot send nested hash as a param in HTTP requests. For example, + # when we would like to send something like this: + # + # {:key => "value", :nested => {:nest => "value"}} + # + # It would be (or should be) mapped like this: + # + # /url/?key=value&nested=%7B%3Anest%3D%3E%5C%22value%5C%22%7D + # + # Doesn’t look to good ;) However there is a simple way to convert a nested + # hash into a params acceptable form. We can convert it to a form, that can + # be mapped into params like this: + # + # /url/?key=value&nested[nest]=value + # + # Here is method to convert any nested hash to a “one level” equivalent: + # + # @author Maciej Mensfeld + + def self.nested_parameters(value, key=nil, hash={}) + case value + when Hash + value.each do |k,v| + akey = key.nil? ? :"#{k}" : :"#{key}[#{k}]" + nested_parameters(v, akey, hash) + end + out_hash + when Array + value.each do |v| + nested_parameters(v, "#{key}[]", hash) + end + hash + when nil then '' + else + hash[key] = value + hash + end + parameters(hash) + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/uri/query.rb b/bin/gems/facets-3.1.0/lib/standard/facets/uri/query.rb new file mode 100644 index 00000000..84bf0286 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/uri/query.rb @@ -0,0 +1,148 @@ +# TODO: URI query methods need work and new consideration. + +require 'uri' +require 'facets/uri/cgi_escape' +require 'facets/module/alias_module_function' + +module URI + + module_function + + # + # + # + KEY_VALUE_SEPARATOR = ";" # "&" + + # + # Given a hash with parameter/value pairs construct a + # standard query string. + # + # URI.hash_to_query(:a => 1, :b => 2) + # #=> "a=1;b=2" + # + def query(parameters) + return '' unless parameters + pairs = [] + parameters.each do |param, value| + pairs << "#{param}=#{cgi_escape(value.to_s)}" + end + return pairs.join(KEY_VALUE_SEPARATOR) + end + + alias_module_function :hash_to_query, :query + alias_module_function :hash_to_query_string, :query + + # + # Extend the basic query string parser provided by the cgi module. + # converts single valued params (the most common case) to + # objects instead of arrays + # + # Returns hash of parameters, contains arrays for multivalued parameters + # (multiselect, checkboxes , etc). + # + # If no query string is provided (nil or "") returns an empty hash. + # + def query_hash(query_string) + return {} unless query_string + + query_parameters = cgi_parse(query_string) + + query_parameters.each { |key, val| + ## replace the array with an object + query_parameters[key] = val[0] if 1 == val.length + } + + ## set default value to nil! cgi sets this to [] + query_parameters.default = nil + + return query_parameters + end + + alias_module_function :query_to_hash, :query_hash + alias_module_function :query_string_to_hash, :query_hash + + # + # This method returns the query string of a uri. + # + # @param [String] uri + # The uri string. + # + # @return [String] + # The query string, or `nil` if no query string. + # + def query_get(uri) + return nil unless uri + # gmosx: INVESTIGATE ruby's URI seems to differently handle + # abs and rel uris. + if md = URI::REGEXP::ABS_URI.match(uri) + return md[8] + elsif md = URI::REGEXP::REL_URI.match(uri) + return md[7] + end + return nil + end + + alias_method :get_query_string, :query_get + + # + # Removes the query string from a +uri+. + # + # Returns the chomped uri. + # + def query_chomp(uri) + return nil unless uri + query_string = self.get_query_string(uri) + return uri.dup.chomp("?#{query_string}") + end + + alias_module_function :chomp_query_string, :query_chomp + + # + # Get a uri and a hash of parameters. Inject the hash values + # as parameters in the query sting path. Returns the full uri. + # + # uri - the uri to filter (String) + # parameter - hash of parameters to update + # + # Returns the full updated query string. + # + # @todo Optimize this method. + # + def query_update(uri, parameters) + query_string = self.query_get(uri) + rest = uri.dup.gsub(/\?#{query_string}/, "") + + hash = self.query_string_to_hash(query_string) + hash.update(parameters) + query_string = self.hash_to_query_string(hash) + + unless query_string.strip.empty? + return "#{rest}?#{query_string}" + else + return rest + end + end + + alias_module_function :update_query_string, :query_update + + # + # Gets the request uri, injects extra parameters in the query string + # and returns a new uri. The request object is not modified. + # There is always a qs string so an extra test is skipped. + # + # TODO: find a better name? + # + def update_request_uri(request, parameters) + hash = request.parameters.dup() + hash.update(parameters) + + ## use this in hash_to_query + query_string = hash.collect { |k, v| + "#{k}=#{v}" + }.join(";") + + ## return "#{request.translated_uri}?#{query_string}" + return "#{request.path}?#{query_string}" + end + +end diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/yaml.rb b/bin/gems/facets-3.1.0/lib/standard/facets/yaml.rb new file mode 100644 index 00000000..f296e343 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/yaml.rb @@ -0,0 +1,6 @@ +require 'yaml' + +require 'facets/yaml/file' +require 'facets/yaml/read' +require 'facets/yaml/kernel' + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/yaml/file.rb b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/file.rb new file mode 100644 index 00000000..a44bd03c --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/file.rb @@ -0,0 +1,41 @@ +require 'yaml' + +module YAML + + # Provides a simplistic way to check if a file is a YAML formatted + # file: + # + # YAML.file?('project.yaml') #=> true + # YAML.file?('project.xml') #=> false + # + # Note this isn't perfect. At present it depends on the use + # use of an initial document separator (eg. '---'). With + # YAML 1.1 the %YAML delaration is supposed to be manditory, + # so in the future this can be adapted to fit that standard. + + def self.file?(file) + File.open(file) do |f| + until f.eof? + line = f.gets + break true if line =~ /^---/ + break false unless line =~ /^(\s*#.*?|\s*)$/ + end + end + end + +end + + +class File + + # Same as `YAML.file?(file)`. + # + # File.yaml?('project.yaml') #=> true + # File.yaml?('project.xml') #=> false + # + def self.yaml?(file) + YAML.file?(file) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/yaml/kernel.rb b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/kernel.rb new file mode 100644 index 00000000..dac3aef7 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/kernel.rb @@ -0,0 +1,29 @@ +require 'yaml' + +module Kernel + + # The Kernel method #yaml is a shortcut to YAML::load. + # + # data = yaml %{ + # a: 1 + # b: 2 + # } + # data #=> {"a"=>1, "b"=>2} + # + def yaml(*args,&blk) + YAML.load(*args,&blk) + end + + # As with #to_yaml but removes the header line (i.e. '---') to create + # a "YAML fragment". + # + # @author Trans + # + def to_yamlfrag + y = to_yaml + y.sub!(/---\ */, '') + y + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/yaml/read.rb b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/read.rb new file mode 100644 index 00000000..3338a363 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/yaml/read.rb @@ -0,0 +1,12 @@ +module YAML + + # Alias for `YAML.load_file` and the same as: + # + # YAML.load(File.new(file)) + # + def self.read(file) + load(File.new(file)) + end + +end + diff --git a/bin/gems/facets-3.1.0/lib/standard/facets/zlib.rb b/bin/gems/facets-3.1.0/lib/standard/facets/zlib.rb new file mode 100644 index 00000000..b73b1c13 --- /dev/null +++ b/bin/gems/facets-3.1.0/lib/standard/facets/zlib.rb @@ -0,0 +1,38 @@ +# A convenient wrapper for the zlib standard library that allows +# compression/decompression of strings with gzip. + +module Zlib + + ##class Stream < StringIO + ## def close; rewind; end + ##end + + # Decompresses a gzipped string. + def self.decompress(source) + GzipReader.new(StringIO.new(source)).read + end + + # Compresses a string using gzip. + def self.compress(source) + output = StringIO.new + class << output + def close; rewind; end + end + gz = GzipWriter.new(output) + gz.write(source) + gz.close + output.string + end + + # Inflate a deflated sting. + def self.inflate(string) + Inflate.inflate(string) + end + + # Deflate a string. + def self.deflate(string, level=DEFAULT_COMPRESSION) + Deflate.deflate(string, level) + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_arrange.rb b/bin/gems/facets-3.1.0/test/core/array/test_arrange.rb new file mode 100644 index 00000000..f6ca5800 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_arrange.rb @@ -0,0 +1,37 @@ +require 'facets/array/arrange' + +test_case Array do + + method :rangify do + test 'Array of consecutive integers should return an array made up of a single range.' do + [1,2,3,4,5].rangify.assert == [1..5] + end + + test 'Array of non-consecutive integers should return the original array.' do + [1,3,5,7].rangify.assert == [1,3,5,7] + end + + test 'Array of ranges should return the correct ranges.' do + arr = [40..45, 1..3, 4..10, 20..30, 24..28, 42..50, 1..6, 1..3, 1..1] + arr.rangify.assert == [1..10, 20..30, 40..50] + end + + test 'Array of ranges and integers should return the correct ranges.' do + arr = [99, 100, 1..3, 101, 4..5, 103, 10..19, 99, 20..20, 31, 32..33, 98, 97] + arr.rangify.assert == [1..5, 10..20, 31..33, 97..101, 103] + end + + test 'Array of non-consecutive integers should return the correct ranges.' do + [1,2,3,6,7,8,10,15].rangify.assert == [1..3, 6..8, 10, 15] + end + + test 'Element order should not affect the result.' do + [8, 1, 15, 2, 6, 3, 7, 10].rangify.assert == [1..3, 6..8, 10, 15] + end + + test 'Duplicate elements should not affect the result.' do + [8, 1, 15, 2, 6, 3, 7, 10, 8, 15, 2, 3, 1, 2].rangify.assert == [1..3, 6..8, 10, 15] + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_average.rb b/bin/gems/facets-3.1.0/test/core/array/test_average.rb new file mode 100644 index 00000000..09630ee7 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_average.rb @@ -0,0 +1,16 @@ +require 'facets/array/average' + +test_case Array do + method :average do + test 'Empty array returns nil' do + [].average.assert == nil + end + + test 'Calculate average of array of numerical values' do + [1, 2, 3].average.assert == 2 + [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].average.assert == 54.2 + [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].average.assert == -6.7 + [60.7829, 31.2622, 20.626, 78.8907, 61.5328].average.assert == 50.61892 + end + end +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_before.rb b/bin/gems/facets-3.1.0/test/core/array/test_before.rb new file mode 100644 index 00000000..436163f9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_before.rb @@ -0,0 +1,48 @@ +covers 'facets/array/before' + +test_case Array do + + method :before do + + setup do + @sequence = ['a', 'b', 'c'] + end + + test "returns the previous element" do + @sequence.before('b').assert == 'a' + @sequence.before('c').assert == 'b' + end + + test "loops around from back to front" do + @sequence.before('a').assert == 'c' + end + + test "non-member elements return nil" do + @sequence.before('d').assert == nil + end + + end + + method :after do + + setup do + @sequence = ['a', 'b', 'c'] + end + + test "returns the following element" do + @sequence.after('a').assert == 'b' + @sequence.after('b').assert == 'c' + end + + test "loops around from back to front" do + @sequence.after('c').assert == 'a' + end + + test "non-member elements return nil" do + @sequence.after('d').assert == nil + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_collapse.rb b/bin/gems/facets-3.1.0/test/core/array/test_collapse.rb new file mode 100644 index 00000000..899190b3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_collapse.rb @@ -0,0 +1,23 @@ +covers 'facets/array/collapse' + +test_case Array do + + method :collapse do + + test do + [1, nil, [1, 2], nil, [[3]]].collapse.assert == [1, 1, 2, 3] + end + + end + + method :collapse! do + + test do + a = [1, nil, [1, 2], nil, [[3]]] + a.collapse! + a.assert == [1, 1, 2, 3] + + end + end +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_commonality.rb b/bin/gems/facets-3.1.0/test/core/array/test_commonality.rb new file mode 100644 index 00000000..a407408d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_commonality.rb @@ -0,0 +1,35 @@ +covers 'facets/array/commonality' + +test_case Array do + + method :commonality do + + test do + a = [1,2,2,3,3,3] + e = { 2 => [2,2], 3 => [3,3,3] } + r = a.commonality + r.assert == e + end + + test "with block" do + a = [1,2,2,3,3,3] + e = {false=>[1, 2, 2], true=>[3, 3, 3]} + r = a.commonality{ |x| x > 2 } + r.assert == e + end + + end + + method :collisions do + + test "alias for commonality" do + a = [1,2,2,3,3,3] + e = { 2 => [2,2], 3 => [3,3,3] } + r = a.collisions + r.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_conjoin.rb b/bin/gems/facets-3.1.0/test/core/array/test_conjoin.rb new file mode 100644 index 00000000..160b0406 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_conjoin.rb @@ -0,0 +1,50 @@ +covers 'facets/array/conjoin' + +test_case Array do + + method :conjoin do + + setup "any array" do + @a = [1,2,3,4] + end + + test "like join but spaced" do + @a.conjoin.assert == "1 2 3 4" + end + + test "comma+space and 'and' on tail" do + @a.conjoin(', ', ' and ').assert = "1, 2, 3 and 4" + end + + test "comma+space and 'or' on tail using :last option" do + @a.conjoin(', ', :last => ' or ').assert == "1, 2, 3 or 4" + end + + test "semicolon+space and ampersand on tail using index" do + @a.conjoin('; ', -1 => ' & ').assert == "1; 2; 3 & 4" + end + + test "with block to determine separator" do + r = @a.conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' } + r.assert == "1.2-3.4" + end + + test "very esoteric transformation" do + r = @a.conjoin{ |i, x, y| "<#{i} #{x} #{y}>" } + r.assert == "1<0 1 2>2<1 2 3>3<2 3 4>4" + end + + test "with :space option" do + r = @a.conjoin(',', '&', :space=>2) + r.assert == "1 , 2 , 3 & 4" + end + + test ":spacer option can set an alternate spacing string" do + r = @a.conjoin('|', '>', :space=>2, :spacer=>'-') + r.assert == "1--|--2--|--3-->--4" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_contains.rb b/bin/gems/facets-3.1.0/test/core/array/test_contains.rb new file mode 100644 index 00000000..43aaa2b1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_contains.rb @@ -0,0 +1,14 @@ +covers 'facets/array/contains' + +test_case Array do + + method :contains? do + + test do + [1,2,3,4].assert.contains?(2) + [1,2,3,4].refute.contains?(9) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_delete.rb b/bin/gems/facets-3.1.0/test/core/array/test_delete.rb new file mode 100644 index 00000000..03019194 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_delete.rb @@ -0,0 +1,42 @@ +covers 'facets/array/delete' + +test_case Array do + + method :delete_unless do + + test do + a = [1,2,3] + a.delete_unless{ |e| e == 2 } + a.assert == [2] + end + + end + + method :delete_values do + + test do + a = [1,2,3,4] + a.delete_values(1,2).assert == [1,2] + a.assert == [3,4] + end + + end + + method :delete_values_at do + + test do + a = [1,2,3,4] + a.delete_values_at(1,2).assert == [2,3] + a.assert == [1,4] + end + + test do + a = [1,2,3,4] + a.delete_values_at(0..2).assert == [1,2,3] + a.assert == [4] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_delete_unless.rb b/bin/gems/facets-3.1.0/test/core/array/test_delete_unless.rb new file mode 100644 index 00000000..12f843f7 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_delete_unless.rb @@ -0,0 +1,17 @@ +covers 'facets/array/delete_unless' + +test_case Array do + + method :delete_unless do + + test 'with an explicit block' do + [1,2,3].delete_unless{ |x| x < 2 }.assert == [1] + end + + test 'with an implicit block' do + [1,2,3].delete_unless(&:even?).assert == [2] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_delete_values.rb b/bin/gems/facets-3.1.0/test/core/array/test_delete_values.rb new file mode 100644 index 00000000..d77dff0b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_delete_values.rb @@ -0,0 +1,31 @@ +covers 'facets/array/delete_values' + +test_case Array do + + method :delete_values do + + test do + a = [1,2,3,4] + a.delete_values(1,2).assert == [1,2] + a.assert == [3,4] + end + + end + + method :delete_values_at do + + test do + a = [1,2,3,4] + a.delete_values_at(1,2).assert == [2,3] + a.assert == [1,4] + end + + test do + a = [1,2,3,4] + a.delete_values_at(0..2).assert == [1,2,3] + a.assert == [4] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_divide.rb b/bin/gems/facets-3.1.0/test/core/array/test_divide.rb new file mode 100644 index 00000000..addbe90e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_divide.rb @@ -0,0 +1,24 @@ +covers 'facets/array/divide' + +test_case Array do + + method :divide do + + test do + r = ['a1','b1','a2','b2'].divide(/^a/) + r.assert == [['a1','b1'],['a2','b2']] + end + + test do + r = ['a1','b1','a2','b2'].divide(/^b/) + r.assert == [['a1'],['b1', 'a2'],['b2']] + end + + test do + r = ['a1','b1','a2','b2'].divide(/c/) + r.assert = [['a1','b1','a2','b2']] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_duplicates.rb b/bin/gems/facets-3.1.0/test/core/array/test_duplicates.rb new file mode 100644 index 00000000..88df458f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_duplicates.rb @@ -0,0 +1,29 @@ +covers 'facets/array/duplicates' + +test_case Array do + + method :duplicates do + + test do + a = [1,1,2,2,3,4,5] + a.duplicates.sort.assert == [1,2] + end + + test "with minimum" do + a = [0,1,2,3,4,5, + 0,1,2,3,4, + 0,1,2,3, + 0,1,2, + 0,1, + 0] + (1..6).each do |m| + d = a.duplicates(m).sort + e = [*0..6-m] + d.assert == e + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_each_overlap.rb b/bin/gems/facets-3.1.0/test/core/array/test_each_overlap.rb new file mode 100644 index 00000000..654e8d29 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_each_overlap.rb @@ -0,0 +1,31 @@ +covers 'facets/array/each_overlap' + +test_case Array do + + method :each_overlap do + + test do + a = [1,2,3,4,5] + r = [] + a.each_overlap(2,1) { |x| r << x } + r.assert == [[1,2],[2,3],[3,4],[4,5]] + end + + test do + a = [1,2,3,4,5,6,7] + r = [] + a.each_overlap(3,1) { |x| r << x } + r.assert == [[1,2,3],[3,4,5],[5,6,7]] + end + + test do + a = [1,2,3,4,5] + r = [] + a.each_overlap(3,2) { |x| r << x } + r.assert == [[1,2,3],[2,3,4],[3,4,5]] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_each_pair.rb b/bin/gems/facets-3.1.0/test/core/array/test_each_pair.rb new file mode 100644 index 00000000..ec031e95 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_each_pair.rb @@ -0,0 +1,16 @@ +covers 'facets/array/each_pair' + +test_case Array do + + method :each_pair do + + test do + result = {} + a = [:a,:b,:c,:d] + a.each_pair{|i,e| result[e] = i + 1} + result.assert == {a: 1, b: 2, c: 3, d: 4} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_each_value.rb b/bin/gems/facets-3.1.0/test/core/array/test_each_value.rb new file mode 100644 index 00000000..976c24da --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_each_value.rb @@ -0,0 +1,16 @@ +covers 'facets/array/each_value' + +test_case Array do + + method :each_value do + + test do + a = [ "a", "b", "c" ] + out = '' + a.each_value {|x| out += "#{x} -- " } + out.assert == 'a -- b -- c -- ' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_entropy.rb b/bin/gems/facets-3.1.0/test/core/array/test_entropy.rb new file mode 100644 index 00000000..bafcb724 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_entropy.rb @@ -0,0 +1,23 @@ +covers 'facets/array/entropy' + +test_case Array do + + method :entropy do + + test do + %w{ a b }.entropy.assert == 1.0 + end + + end + + method :ideal_entropy do + + test do + %w{ a b }.ideal_entropy.assert == 1.0 + %w{ a a b b }.ideal_entropy.assert == 2.0 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_extract_options.rb b/bin/gems/facets-3.1.0/test/core/array/test_extract_options.rb new file mode 100644 index 00000000..310d7606 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_extract_options.rb @@ -0,0 +1,28 @@ +covers 'facets/array/extract_options' + +test_case Array do + + method :extract_options! do + + test do + h = { :x=>1, :y=>1 } + a = [:a, :b, h] + a.extract_options!.assert == h + end + + end + +end + +test_case Hash do + + method :extractable_options? do + + test do + h = { :x=>1, :y=>1 } + h.assert.extractable_options? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_first.rb b/bin/gems/facets-3.1.0/test/core/array/test_first.rb new file mode 100644 index 00000000..de34a42b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_first.rb @@ -0,0 +1,17 @@ +covers 'facets/array/indexable' + +test_case Array do + + method :first! do + + test "alias of shift" do + a = [1,2,3] + r = a.first! + r.assert == 1 + a.assert == [2,3] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_from.rb b/bin/gems/facets-3.1.0/test/core/array/test_from.rb new file mode 100644 index 00000000..5ab0c61f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_from.rb @@ -0,0 +1,42 @@ +covers 'facets/array/from' + +test_case Array do + + method :from do + + test do + %w{W o r l d}.from(3).assert == ['l', 'd'] + %w{W o r l d}.from(8).assert == [] + end + end + + method :thru do + + test do + + [1, 2, 3, 4, 5].thru(2).assert == [1, 2, 3] + [1, 2, 3, 4, 5].thru(7).assert == [1, 2, 3, 4, 5] + + end + + test do + + [1, 2, 3, 4, 5].thru(0, 2).assert == [1, 2, 3] + [1, 2, 3, 4, 5].thru(2, 4).assert == [3, 4, 5] + + end + + test do + + [1, 2, 3, 4, 5].thru(3, 7).assert == [4, 5] + + end + + test do + + [1, 2, 3, 4, 5].thru(6, 7).assert = [] + + end + + end +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_intersection.rb b/bin/gems/facets-3.1.0/test/core/array/test_intersection.rb new file mode 100644 index 00000000..a5cd1ad6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_intersection.rb @@ -0,0 +1,19 @@ +require 'facets/array/intersection' + +test_case Array do + + method :intersection do + test { [1, 2].intersection.assert == nil } + test { [1..10, 11..20].intersection.assert == nil } + test { [1..10, 5..15, 11..20].intersection.assert == nil } + test { [8..8, 1..10, 10 ].intersection.assert == nil } + test { [10, 1..10].intersection.assert == 10 } + test { [1..10, 1].intersection.assert == 1 } + test { [1, 1].intersection.assert == 1 } + test { [1..10, 5, 5..8, 5..10 ].intersection.assert == 5 } + test { [1..10, 5..8, 5..10 ].intersection.assert == (5..8) } + test { [5..10, 1..10, 4..8 ].intersection.assert == (5..8) } + test { [5..10, 1..10, 4..20, 8].intersection.assert == 8 } + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_last.rb b/bin/gems/facets-3.1.0/test/core/array/test_last.rb new file mode 100644 index 00000000..a1091a58 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_last.rb @@ -0,0 +1,17 @@ +covers 'facets/array/indexable' + +test_case Array do + + method :last! do + + test "alias of pop" do + a = [1,2,3] + r = a.last! + r.assert == 3 + a.assert == [1,2] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_median.rb b/bin/gems/facets-3.1.0/test/core/array/test_median.rb new file mode 100644 index 00000000..7db2c031 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_median.rb @@ -0,0 +1,27 @@ +covers 'facets/array/median' + +test_case Array do + + method :median do + test "odd sized" do + r = %w{e a b c d}.median + r.assert == "c" + end + + test "even sized" do + r = %w{f e a b c d}.median + r.assert == "d" + end + + test "with positive offset" do + r = %w{e a b c d}.median(1) + r.assert == "d" + end + + test "with negative offset" do + r = %w{e a b c d}.median(-1) + r.assert == "b" + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_merge.rb b/bin/gems/facets-3.1.0/test/core/array/test_merge.rb new file mode 100644 index 00000000..97881460 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_merge.rb @@ -0,0 +1,27 @@ +covers 'facets/array/merge' + +test_case Array do + + method :merge do + + test do + a = [1,2,3] + b = [3,4,5] + a.merge(b).assert == [1,2,3,4,5] + end + + end + + method :merge! do + + test do + a = [1,2,3] + b = [3,4,5] + a.merge!(b) + a.assert == [1,2,3,4,5] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_missing.rb b/bin/gems/facets-3.1.0/test/core/array/test_missing.rb new file mode 100644 index 00000000..b2bc0828 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_missing.rb @@ -0,0 +1,12 @@ +require 'facets/array/missing' + +test_case Array do + + method :missing do + test { [1,3..3].missing.assert == [2] } + test { [1..5,10..12].missing.assert == [6..9] } + test { [100, 9..11, 14, 1..5, 16, 10..12, 17..17].missing.assert == [6..8, 13, 15, 18..99] } + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_mode.rb b/bin/gems/facets-3.1.0/test/core/array/test_mode.rb new file mode 100644 index 00000000..098f3494 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_mode.rb @@ -0,0 +1,17 @@ +covers 'facets/array/mode' + +test_case Array do + + method :mode do + + test do + [1, 1, 2, 3].mode.assert == [1] + end + + test do + [1, 1, 2, 2, 3].mode.sort.assert == [1,2] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_nonuniq.rb b/bin/gems/facets-3.1.0/test/core/array/test_nonuniq.rb new file mode 100644 index 00000000..b2e2473d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_nonuniq.rb @@ -0,0 +1,25 @@ +covers 'facets/array/nonuniq' + +test_case Array do + + method :nonuniq do + + test do + a = [1,1,2,2,3,4,5] + a.nonuniq.sort.assert == [1,2] + end + + end + + method :nonuniq! do + + test do + a = [1,1,2,2,3,4,5] + a.nonuniq! + a.sort.assert == [1,2] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_not_empty.rb b/bin/gems/facets-3.1.0/test/core/array/test_not_empty.rb new file mode 100644 index 00000000..3ad45b54 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_not_empty.rb @@ -0,0 +1,17 @@ +covers 'facets/array/not_empty' + +test_case Array do + + method :not_empty? do + + test do + [].refute.not_empty? + end + + test do + [1,2].assert.not_empty? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_occur.rb b/bin/gems/facets-3.1.0/test/core/array/test_occur.rb new file mode 100644 index 00000000..f5f7104b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_occur.rb @@ -0,0 +1,52 @@ +covers 'facets/array/occur' + +test_case Array do + + method :occur do + + test "set limit" do + a = [1,2,3,4,5, + 2,3,4,5, + 3,4,5, + 4,5, + 5] + (1..5).each do |m| + d = a.occur(m) + d.assert == [m] + end + end + + test "range" do + a = %w{a b c d e + b c d e + c d e + d e + e} + a.occur(1..2).sort.assert == ['a','b'] + a.occur(1..3).sort.assert == ['a','b','c'] + a.occur(2..3).sort.assert == ['b','c'] + end + + test do + a = [:a,:b,:a] + a.occur(1).assert == [:b] + end + + test do + a = [:a,:b,:a] + a.occur(2).assert == [:a] + end + + test do + a = [:a,:b,:a] + a.occur(1..1).assert == [:b] + end + + test do + a = [:a,:b,:a] + a.occur{ |n| n % 2 == 0 }.assert == [:a] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_occurrence.rb b/bin/gems/facets-3.1.0/test/core/array/test_occurrence.rb new file mode 100644 index 00000000..cd9e446e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_occurrence.rb @@ -0,0 +1,20 @@ +covers 'facets/array/occurrence' + +test_case Array do + + method :occurrence do + + test "no arguments" do + r = [:a,:a,:b,:c,:c,:c].occurrence + r.assert == { :a => 2, :b => 1, :c => 3 } + end + + test "with block" do + r = [2,2,3,4,4,4].occurrence{|i| i % 2} + r.assert == { 0 => 5, 1 => 1 } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_only.rb b/bin/gems/facets-3.1.0/test/core/array/test_only.rb new file mode 100644 index 00000000..34380bfa --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_only.rb @@ -0,0 +1,17 @@ +covers 'facets/array/only.rb' + +test_case Array do + + method :only do + + test do + [5].only.assert == 5 + [nil].only.assert == nil + expect(IndexError){ [].only } + expect(IndexError){ [1,2,3].only } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_op_pow.rb b/bin/gems/facets-3.1.0/test/core/array/test_op_pow.rb new file mode 100644 index 00000000..0c6c1ce3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_op_pow.rb @@ -0,0 +1,13 @@ +covers 'facets/array/op_pow' + +test_case Array do + + method :** do + + test do + ([1,2] ** [3,4]).assert == [[1, 3], [1, 4], [2, 3], [2, 4]] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_pad.rb b/bin/gems/facets-3.1.0/test/core/array/test_pad.rb new file mode 100644 index 00000000..e8ce0d8b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_pad.rb @@ -0,0 +1,40 @@ +covers 'facets/array/pad' + +test_case Array do + + method :pad do + + test do + r = [0,1,2,3].pad(7,"x") + x = [0,1,2,3,"x","x","x"] + r.assert == x + end + + test "negative index" do + r = [0,1,2,3].pad(-7,"n") + x = ["n","n","n",0,1,2,3] + r.assert == x + end + + end + + method :pad! do + + test do + a = [0,1,2,3] + r = a.pad!(6,"y") + x = [0,1,2,3,"y","y"] + r.assert == x + end + + test "negative index" do + a = [0,1,2,3] + r = a.pad!(-6,"q") + x = ["q","q",0,1,2,3] + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_peek.rb b/bin/gems/facets-3.1.0/test/core/array/test_peek.rb new file mode 100644 index 00000000..02eb556c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_peek.rb @@ -0,0 +1,28 @@ +covers 'facets/array/pull' + +test_case Array do + + method :peek do + + test do + a = [1,2,3] + a.peek.assert == 3 + a.assert == [1,2,3] + end + + test do + a = [1,2,3] + a.peek(1).assert == 2 + a.assert == [1,2,3] + end + + test do + a = [1,2,3] + a.peek(-1).assert == 1 + a.assert == [1,2,3] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_poke.rb b/bin/gems/facets-3.1.0/test/core/array/test_poke.rb new file mode 100644 index 00000000..71c65ca6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_poke.rb @@ -0,0 +1,21 @@ +covers 'facets/array/pull' + +test_case Array do + + method :poke do + + test do + a = [1,2,3] + a.poke(9) + a.assert == [9,1,2,3] + end + + test do + a = [2,3] + a.poke(1).assert == [1,2,3] + a.poke(4).assert == [4,1,2,3] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_probability.rb b/bin/gems/facets-3.1.0/test/core/array/test_probability.rb new file mode 100644 index 00000000..c44edb6e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_probability.rb @@ -0,0 +1,18 @@ +covers 'facets/array/probability' + +test_case Array do + + method :probability do + + test do + %w{a b}.probability.assert == {'a'=>0.5, 'b'=>0.5} + end + + test do + %w{a a a b}.probability.assert == {'a'=>0.75, 'b'=>0.25} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_pull.rb b/bin/gems/facets-3.1.0/test/core/array/test_pull.rb new file mode 100644 index 00000000..002d0785 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_pull.rb @@ -0,0 +1,15 @@ +covers 'facets/array/pull' + +test_case Array do + + method :pull do + + test do + a = [1,2,3] + a.pull.assert == 1 + a.assert == [2,3] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_recurse.rb b/bin/gems/facets-3.1.0/test/core/array/test_recurse.rb new file mode 100644 index 00000000..d5ffbb34 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_recurse.rb @@ -0,0 +1,40 @@ +covers 'facets/array/recurse' + +test_case Array do + + method :recurse do + + test do + a = ["a", ["b", "c", nil], nil] + r = a.recurse{|a| a.compact! } + r.assert ["a", ["b", "c"]] + end + + test "with Hashes" do + require 'facets/hash/recurse' + objects = [] + struct = [1, 2, {:a => 3, :b => [4, 5, {:c=>6}]}, [7, 8]] + struct.recurse(Array, Hash){|o| objects << o; o } + + objects.assert.include?( [7, 8] ) + objects.assert.include?( {:c=>6} ) + objects.assert.include?( [4, 5, {:c=>6}] ) + objects.assert.include?( {:a => 3, :b => [4, 5, {:c=>6}]} ) + objects.assert.include?( struct ) + + objects.length.assert == 5 + end + + end + + method :recurse! do + + test do + a = ["a", ["b", "c", nil], nil] + a.recurse!{|a| a.compact! } + a.assert ["a", ["b", "c"]] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_recursively.rb b/bin/gems/facets-3.1.0/test/core/array/test_recursively.rb new file mode 100644 index 00000000..e8939c23 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_recursively.rb @@ -0,0 +1,33 @@ +covers 'facets/array/recursively' + +test_case Array do + + method :recursively do + + test "each" do + r = [] + [1,2,['a','b']].recursively{ |v| v }.each{ |v| r << v } + r.assert == [1,2,'a','b'] + end + + test "map" do + a = [1,2,['a','b']] + r = a.recursively{ |v| v.reverse }.map{ |v| v.succ } + r.assert == [2,3,['c','b']] + end + + test "map!" do + a = [1,2,['a','b']] + a.recursively{ |v| v }.map!{ |v| v.succ } + a.assert == [2,3,['b','c']] + end + + test "with block" do + a = [1,2,['a','b', nil], nil] + r = a.recursively{ |v| v.compact }.map{ |v| v }.compact + r.assert == [1,2,['a','b']] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_reject_values.rb b/bin/gems/facets-3.1.0/test/core/array/test_reject_values.rb new file mode 100644 index 00000000..ed0d6d50 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_reject_values.rb @@ -0,0 +1,17 @@ +covers 'facets/array/reject_values' + +testcase Array do + + method :reject_values do + + test do + a = [1,2,3,4,5] + r = a.reject_values(2,4) + r.assert == [1,3,5] + a.assert = [1,2,3,4,5] # hasn't changed + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_splice.rb b/bin/gems/facets-3.1.0/test/core/array/test_splice.rb new file mode 100644 index 00000000..4d6c7ee9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_splice.rb @@ -0,0 +1,21 @@ +covers 'facets/array/splice' + +test_case Array do + + method :splice do + + test do + a = [1,2,3] + a.splice(1).assert == 2 + a.assert == [1,3] + end + + test do + a = [1,2,3] + a.splice(1,4).assert == 4 + a.assert == [1,4,3] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_split.rb b/bin/gems/facets-3.1.0/test/core/array/test_split.rb new file mode 100644 index 00000000..c3a75029 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_split.rb @@ -0,0 +1,22 @@ +covers 'facets/array/split' + +test_case Array do + + method :split do + + test do + ['a','b','c'].split('b').assert == [['a'], ['c']] + end + + test "empty" do + [].split('a').assert == [] + end + + test "same" do + ['a'].split('a').assert == [] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_squeeze.rb b/bin/gems/facets-3.1.0/test/core/array/test_squeeze.rb new file mode 100644 index 00000000..8b0d6b53 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_squeeze.rb @@ -0,0 +1,22 @@ +covers 'facets/array/squeeze' + +test_case Array do + + method :squeeze! do + + test 'default' do + a = [1,2,2,3,3,2,1] + a.squeeze! + a.assert == [1,2,3,2,1] + end + + test 'with argument' do + a = [1,2,2,3,3,2,1] + a.squeeze!(*[3]) + a.assert == [1,2,2,3,2,1] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_standard_deviation.rb b/bin/gems/facets-3.1.0/test/core/array/test_standard_deviation.rb new file mode 100644 index 00000000..49cfc1a9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_standard_deviation.rb @@ -0,0 +1,18 @@ +require 'facets/array/standard_deviation' + +test_case Array do + method :standard_deviation do + test 'Empty array returns nil' do + [].standard_deviation.assert == nil + end + + test 'Calculate standard_deviation of array of numerical values' do + [1, 2, 3].standard_deviation.assert == 0.816496580927726 + [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].standard_deviation.assert == 24.69331893448104 + [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].standard_deviation.assert == 54.67183918618432 + [60.7829, 31.2622, 20.626, 78.8907, 61.5328].standard_deviation.assert == 21.428815505053002 + end + end +end + + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_step.rb b/bin/gems/facets-3.1.0/test/core/array/test_step.rb new file mode 100644 index 00000000..4fa4d0b6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_step.rb @@ -0,0 +1,28 @@ +covers 'facets/array/step.rb' + +test_case Array do + + method :step do + + test "iteration" do + a = [:a, :b, :c, :d] + r = [] + + a.step(2){ |e| r << e } + + r.assert == [:b, :d] + end + + test "conversion to array" do + a = [:a, :b, :c, :d] + a.step(1).to_a.assert == [:a, :b, :c, :d] + a.step(2).to_a.assert == [:b, :d] + a.step(3).to_a.assert == [:c] + a.step(5).to_a.assert == [] + end + + end + +end + + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_store.rb b/bin/gems/facets-3.1.0/test/core/array/test_store.rb new file mode 100644 index 00000000..9bf46a6e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_store.rb @@ -0,0 +1,22 @@ +covers 'facets/array/store' + +test_case Array do + + method :store do + + test do + a = [1,2,3,4,5] + a.store(0, :A) + a.assert == [:A,2,3,4,5] + end + + test do + a = [1,2,3,4,5] + a.store(-1, :Z) + a.assert == [1,2,3,4,:Z] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_to_h.rb b/bin/gems/facets-3.1.0/test/core/array/test_to_h.rb new file mode 100644 index 00000000..5cdeaf04 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_to_h.rb @@ -0,0 +1,14 @@ +covers 'facets/array/to_h' + +test_case Array do + + method :to_h do + + test do + arr = [[:a, 1], [:b, 2]] + arr.to_h.assert == {:a => 1, :b => 2} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_traverse.rb b/bin/gems/facets-3.1.0/test/core/array/test_traverse.rb new file mode 100644 index 00000000..10d4a722 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_traverse.rb @@ -0,0 +1,26 @@ +covers 'facets/array/traverse' + +test_case Array do + + method :traverse do + + test do + a = ["A", "B", ["X", "Y"]] + g = a.traverse{ |e| e.downcase } + g.assert == ["a", "b", ["x", "y"]] + end + + end + + method :traverse! do + + test do + a = ["A", "B", ["X", "Y"]] + a.traverse!{ |e| e.downcase } + a.assert == ["a", "b", ["x", "y"]] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_uniq_by.rb b/bin/gems/facets-3.1.0/test/core/array/test_uniq_by.rb new file mode 100644 index 00000000..c970179a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_uniq_by.rb @@ -0,0 +1,24 @@ +covers 'facets/array/uniq_by' + +test_case Array do + + method :uniq_by! do + + test do + e = [-5, -4, -3, -2, -1, 0] + r = (-5..5).to_a + r.uniq_by!{ |i| i*i } + r.assert == e + end + + test do + e = [5, 4, 3, 2, 1, 0] + r = (-5..5).to_a.reverse + r.uniq_by!{ |i| i*i } + r.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_unique_permutation.rb b/bin/gems/facets-3.1.0/test/core/array/test_unique_permutation.rb new file mode 100644 index 00000000..22a968f5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_unique_permutation.rb @@ -0,0 +1,23 @@ +covers 'facets/array/unique_permutation' + +test_case Array do + + method :unique_permutation do + + test 'example' do + [1,1,2,2,3].unique_permutation(2).to_a.assert == [ + [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2] + ] + end + + test 'not eq permutation.to_a' do + [1,1,2,3].unique_permutation.to_a.assert != [1,1,2,3].permutation.to_a + end + + test 'eq permutation.to_a.uniq' do + [1,1,2,3].unique_permutation.to_a.assert == [1,1,2,3].permutation.to_a.uniq + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/array/test_variance.rb b/bin/gems/facets-3.1.0/test/core/array/test_variance.rb new file mode 100644 index 00000000..37389c22 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_variance.rb @@ -0,0 +1,17 @@ +require 'facets/array/variance' + +test_case Array do + method :variance do + test 'Empty array returns nil' do + [].variance.assert == nil + end + + test 'Calculate variance of array of numerical values' do + [1, 2, 3].variance.assert == 0.6666666666666666 + [96, 35, 72, 30, 75, 33, 68, 13, 49, 71].variance.assert == 609.76 + [36, -67, -17, 85, -46, -64, -23, -13, 89, -47].variance.assert == 2989.0099999999993 + [60.7829, 31.2622, 20.626, 78.8907, 61.5328].variance.assert == 459.1941339495999 + end + end +end + diff --git a/bin/gems/facets-3.1.0/test/core/array/test_zip.rb b/bin/gems/facets-3.1.0/test/core/array/test_zip.rb new file mode 100644 index 00000000..153841eb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/array/test_zip.rb @@ -0,0 +1,13 @@ +covers 'facets/array/zip' + +test_case Array do + + method :zip do + + test 'example' do + Array.zip([1,2], [3,4]).assert == [[1,3],[2,4]] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/binding/test_caller.rb b/bin/gems/facets-3.1.0/test/core/binding/test_caller.rb new file mode 100644 index 00000000..56e1bb08 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/binding/test_caller.rb @@ -0,0 +1,69 @@ +covers 'facets/binding/caller' + +test_case Binding do + + a = 1 + b = 2 + x = "hello" + + bind = binding + line = __LINE__ # the line number must be updated if it moves + file = __FILE__ # why does it equal basename only? + + method :__LINE__ do + test do + bind.__LINE__.assert == line - 1 + end + end + + method :__FILE__ do + test do + bind.__FILE__.assert == file + end + end + + method :__DIR__ do + test do + bind.__DIR__.assert == File.dirname(file) + end + end + + method :callstack do + test do + bind.callstack.assert.is_a?(Array) + end + end + + method :call_stack do + test do + bind.call_stack.assert.is_a?(Array) + end + end + + method :caller do + test do + Exception.refute.raised? do + bind.caller + end + end + end + + method :__callee__ do + test do + alternate.__callee__.assert == :alternate + end + end + + method :__method__ do + test do + alternate.__method__.assert == :alternate + end + end + + # helper method + def alternate + binding + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/binding/test_defined.rb b/bin/gems/facets-3.1.0/test/core/binding/test_defined.rb new file mode 100644 index 00000000..e4742ead --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/binding/test_defined.rb @@ -0,0 +1,18 @@ +covers 'facets/binding/defined' + +test_case Binding do + + a = 1 + b = 2 + x = "hello" + + bind = binding + + method :defined? do + test do + bind.assert.defined?("x") + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/binding/test_op.rb b/bin/gems/facets-3.1.0/test/core/binding/test_op.rb new file mode 100644 index 00000000..356fb5e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/binding/test_op.rb @@ -0,0 +1,24 @@ +covers 'facets/binding/op' + +test_case Binding do + + a = 1 + b = 2 + x = "hello" + + bind = binding + + method :[] do + test do + bind["x"].assert == "hello" + end + end + + method :[]= do + test do + bind["x"] = "goodbye" + bind["x"].assert == "goodbye" + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/binding/test_self.rb b/bin/gems/facets-3.1.0/test/core/binding/test_self.rb new file mode 100644 index 00000000..cd38546b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/binding/test_self.rb @@ -0,0 +1,16 @@ +covers 'facets/binding/self' + +test_case Binding do + + bind = binding + this = self + + method :self do + + test do + bind.self == this + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/class/test_descendents.rb b/bin/gems/facets-3.1.0/test/core/class/test_descendents.rb new file mode 100644 index 00000000..9e1ade4e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/class/test_descendents.rb @@ -0,0 +1,19 @@ +covers 'facets/class/descendants' + +test_case Class do + + method :descendants do + + a = Class.new + b = Class.new(a) + c = Class.new(b) + + test do + a.descendants.assert.include?(b) + a.descendants.assert.include?(c) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/class/test_preallocate.rb b/bin/gems/facets-3.1.0/test/core/class/test_preallocate.rb new file mode 100644 index 00000000..b60aa23f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/class/test_preallocate.rb @@ -0,0 +1,32 @@ +covers 'facets/class/preallocate' + +test_case Class do + + method :preallocate do + + setup do + @c = Class.new do + def f + "f" + end + end + + @m = Module.new do + def f + '{' + super + '}' + end + end + end + + test do + m = @m + @c.class_eval do + preallocate m + end + x = @c.new + x.f.assert == "{f}" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/class/test_subclasses.rb b/bin/gems/facets-3.1.0/test/core/class/test_subclasses.rb new file mode 100644 index 00000000..8407bd0a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/class/test_subclasses.rb @@ -0,0 +1,20 @@ +covers 'facets/class/subclasses' + +test_case Class do + + method :subclasses do + + # class with a number of subclasses + c = Class.new + x = Class.new(c) + y = Class.new(c) + z = Class.new(c) + + test do + c.subclasses == [x, y, z] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/class/test_to_proc.rb b/bin/gems/facets-3.1.0/test/core/class/test_to_proc.rb new file mode 100644 index 00000000..5d81a695 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/class/test_to_proc.rb @@ -0,0 +1,16 @@ +covers 'facets/class/to_proc' + +test_case Class do + + method :to_proc do + + test do + person = Struct.new(:name) + people = ["joe"].map(&person) + people[0].name.assert == "joe" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/comparable/test_bound.rb b/bin/gems/facets-3.1.0/test/core/comparable/test_bound.rb new file mode 100644 index 00000000..8e596b35 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/comparable/test_bound.rb @@ -0,0 +1,32 @@ +covers 'facets/comparable/bound' + +test_case Comparable do + + method :bound do + + test 'single argument' do + 3.bound(4).assert == 4 + 4.bound(4).assert == 4 + 5.bound(4).assert == 5 + end + + test 'two arguments' do + 4.bound(3,5).assert == 4 + 3.bound(3,5).assert == 3 + 5.bound(3,5).assert == 5 + 2.bound(3,5).assert == 3 + 6.bound(3,5).assert == 5 + end + + test 'on strings' do + 'd'.bound('c','e').assert == 'd' + 'c'.bound('c','e').assert == 'c' + 'e'.bound('c','e').assert == 'e' + 'b'.bound('c','e').assert == 'c' + 'f'.bound('c','e').assert == 'e' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/comparable/test_cap.rb b/bin/gems/facets-3.1.0/test/core/comparable/test_cap.rb new file mode 100644 index 00000000..5bdb1c77 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/comparable/test_cap.rb @@ -0,0 +1,36 @@ +covers 'facets/comparable/cap' + +test_case Comparable do + + method :cap do + + test do + 3.cap(4).assert == 3 + 4.cap(4).assert == 4 + 5.cap(4).assert == 4 + end + + end + + method :at_most do + + test do + 3.at_most(4).assert == 3 + 4.at_most(4).assert == 4 + 5.at_most(4).assert == 4 + end + + end + + method :at_least do + + test do + 3.at_least(4).assert == 4 + 4.at_least(4).assert == 4 + 5.at_least(4).assert == 5 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/comparable/test_clip.rb b/bin/gems/facets-3.1.0/test/core/comparable/test_clip.rb new file mode 100644 index 00000000..40d39290 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/comparable/test_clip.rb @@ -0,0 +1,31 @@ +covers 'facets/comparable/clip' + +test_case Comparable do + + method :clip do + + test 'single argument' do + 3.clip(4).assert == 4 + 4.clip(4).assert == 4 + 5.clip(4).assert == 5 + end + + test 'two arguments' do + 4.clip(3,5).assert == 4 + 3.clip(3,5).assert == 3 + 5.clip(3,5).assert == 5 + 2.clip(3,5).assert == 3 + 6.clip(3,5).assert == 5 + end + + test 'on strings' do + 'd'.clip('c','e').assert == 'd' + 'c'.clip('c','e').assert == 'c' + 'e'.clip('c','e').assert == 'e' + 'b'.clip('c','e').assert == 'c' + 'f'.clip('c','e').assert == 'e' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/comparable/test_cmp.rb b/bin/gems/facets-3.1.0/test/core/comparable/test_cmp.rb new file mode 100644 index 00000000..8b8e7054 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/comparable/test_cmp.rb @@ -0,0 +1,16 @@ +covers 'facets/comparable/cmp' + +test_case Comparable do + + method :cmp do + + test 'on integers' do + 3.cmp(4).assert == -1 + 3.cmp(3).assert == 0 + 3.cmp(2).assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/comparable/test_op_get.rb b/bin/gems/facets-3.1.0/test/core/comparable/test_op_get.rb new file mode 100644 index 00000000..7dad51df --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/comparable/test_op_get.rb @@ -0,0 +1,61 @@ +covers 'facets/comparable/op_get' + +test_case Comparable do + + class_method :[] do + + test do + c = Class.new do + include Comparable[:a,:b] + + attr_accessor :a, :b + + def initialize(a,b) + @a=a; @b=b + end + end + + a = [c.new(10,20),c.new(10,30)] + a.sort.assert == a + + a = [c.new(10,30),c.new(10,20)] + a.sort.assert == a.reverse + + a = [c.new(10,10),c.new(20,10)] + a.sort.assert == a + + a = [c.new(20,10),c.new(10,10)] + a.sort.assert == a.reverse + + a = [c.new(10,30),c.new(20,10)] + a.sort.assert == a + end + +=begin + class_method :sort_on do + test do + c = Class.new + c.class_eval { + def initialize(a,b) + @a=a; @b=b + end + sort_on :a,:b + } + a = [c.new(10,20),c.new(10,30)] + assert_equal( a, a.sort ) + a = [c.new(10,30),c.new(10,20)] + assert_equal( a.reverse, a.sort ) + a = [c.new(10,10),c.new(20,10)] + assert_equal( a, a.sort ) + a = [c.new(20,10),c.new(10,10)] + assert_equal( a.reverse, a.sort ) + a = [c.new(10,30),c.new(20,10)] + assert_equal( a, a.sort ) + end + end +=end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/denumerable_tc.rb b/bin/gems/facets-3.1.0/test/core/denumerable_tc.rb new file mode 100644 index 00000000..7a3a7214 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/denumerable_tc.rb @@ -0,0 +1,194 @@ +covers 'facets/denumerable' +covers 'facets/enumerable/defer' +#require 'facets/enumerable/take' + +test_case Denumerable do + + c = Class.new do + include Denumerable + def initialize(*a) + @a = a + end + def each(&blk) + @a.each(&blk) + end + def size; @a.size; end + end + + method :map do + test do + o = c.new(1,2,3,4) + o.map.assert.is_a?(Denumerator) + o.map{ |x| x + 1 }.assert.is_a?(Denumerator) + o.map{ |x| x + 1 }.to_a.assert == [2,3,4,5] + end + end + + method :collect do + test do + o = c.new(1,2,3,4) + o.collect.assert.is_a?(Denumerator) + o.collect{ |x| x + 1 }.assert.is_a?(Denumerator) + o.collect{ |x| x + 1 }.to_a.assert == [2,3,4,5] + end + end + + method :select do + test do + o = c.new(1,2,3,4) + o.select.assert.is_a?(Denumerator) + o.select{ |x| x > 1 }.assert.is_a?(Denumerator) + o.select{ |x| x > 1 }.to_a.assert == [2,3,4] + end + end + + method :find_all do + test do + o = c.new(1,2,3,4) + o.find_all.assert.is_a?(Denumerator) + o.find_all{ |x| x > 1 }.assert.is_a?(Denumerator) + o.find_all{ |x| x > 1 }.to_a.assert == [2,3,4] + end + end + + method :reject do + test do + o = c.new(1,2,3,4) + o.reject.assert.is_a?(Denumerator) + o.reject{ |x| x > 1 }.assert.is_a?(Denumerator) + o.reject{ |x| x > 1 }.to_a.assert == [1] + end + end + + method :skip do + test do + o = c.new(1,2,3,4) + o.skip(2).assert.is_a?(Denumerator) + o.skip(2).to_a.assert == [3,4] + end + end + + method :take do + test do + o = c.new(1,2,3,4) + o.take(2).assert.is_a?(Denumerator) + o.take(2).to_a.assert == [1,2] + end + end + +end + +test_case Denumerator do + + source = (1..1/0.0) # infinite Enumerable object + + method :each do + test do + res = [] + (1..5).defer.each { |i| res << i } + res.assert == [1,2,3,4,5] + end + end + + method :take do + test do + d = source.defer + d.take(5).to_a.assert == [1,2,3,4,5] + end + end + + method :inject do + test do + d = (1..5).defer + d = d.inject({}) { |h,v| h[v] = v*2; h } + d.assert == {1=>2,2=>4,3=>6,4=>8,5=>10} + end + + # TODO: problem with break in proc + #test do + # d = (1..5).defer + # d = d.inject({}){ |h,v| h[v] = v*2; break h if v>=3; h } + # d.assert == {1=>2,2=>4,3=>6} + #end + end + + method :max do + test do + d = source.defer + d.take(5).max.assert == 5 + end + end + + method :min do + test do + d = source.defer + d.take(5).min.assert == 1 + end + end + + method :sort_by do + test do + d = source.defer + d.take(5).sort_by{ |x| -x }.assert == [5,4,3,2,1] + end + end + + method :map do + test do + d = source.defer + d.map{ |i| i*2 }.take(5).min.assert == 2 + end + end + + method :defer do + test do + d = source.defer.defer{ |out,i| out << i*2 } + d.take(5).to_a.assert == [2,4,6,8,10] + end + + test "chain" do + d = source.defer { |out,i| out.yield(i) if i % 2 == 0 }. + defer { |out,i| out.yield(i + 100) } + d.take(5).to_a.assert == [102,104,106,108,110] + end + end + + method :select do + test do + d = source.defer + d = d.select{ |i| i % 2 == 0 } + d.take(5).to_a.assert == [2,4,6,8,10] + end + end + + method :find_all do + test do + d = source.defer + d = d.find_all{ |i| i % 2 == 0 } + d.take(5).to_a.assert == [2,4,6,8,10] + end + end + + method :reject do + test do + d = source.defer + d = d.reject { |i| i % 3 == 0 } + d.take(5).to_a.assert == [1,2,4,5,7] + end + end + + method :skip do + test do + d = source.defer + d = d.skip(20) + d.take(5).to_a.assert == [21,22,23,24,25] + end + end + + #method :each_cons + # test do + # a = source.defer + # assert_equal [[1,2,3],[2,3,4],[3,4,5],[4,5,6]], a.each_cons(3).take(4) + # end + #end +end diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_ascend.rb b/bin/gems/facets-3.1.0/test/core/dir/test_ascend.rb new file mode 100644 index 00000000..6a841732 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_ascend.rb @@ -0,0 +1,40 @@ +covers 'facets/dir/ascend' + +test_case Dir do + + test_directory = 'test/core/dir' + + class_method :ascend do + + test do + c = [] + Dir.ascend(test_directory) do |path| + c << path + end + rdir = test_directory + c.each do |d| + d.assert == rdir + rdir = File.dirname(rdir) + end + end + + end + + class_method :ascend do + + test "exclude current" do + c = [] + Dir.ascend(test_directory, false) do |path| + c << path + end + rdir = File.dirname(test_directory) + c.each do |d| + d.assert == rdir + rdir = File.dirname(rdir) + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_descend.rb b/bin/gems/facets-3.1.0/test/core/dir/test_descend.rb new file mode 100644 index 00000000..26c8bbac --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_descend.rb @@ -0,0 +1,24 @@ +covers 'facets/dir/ascend' + +test_case Dir do + + test_directory = 'test/core/dir' + + class_method :descend do + + test do + c = [] + Dir.descend(test_directory) do |path| + c << path + end + rdir = test_directory + c.reverse_each do |d| + d.assert == rdir + rdir = File.dirname(rdir) + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_each_child.rb b/bin/gems/facets-3.1.0/test/core/dir/test_each_child.rb new file mode 100644 index 00000000..ce125f75 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_each_child.rb @@ -0,0 +1,22 @@ +covers 'facets/dir/each_child' + +test_case Dir do + + test_directory = 'test' + + method :each_child do + + test do + c = [] + d = Dir.new(test_directory) + d.each_child do |path| + c << path + end + d.close + (['core', 'standard'] - c).assert.empty? + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_multiglob.rb b/bin/gems/facets-3.1.0/test/core/dir/test_multiglob.rb new file mode 100644 index 00000000..38368a29 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_multiglob.rb @@ -0,0 +1,25 @@ +covers 'facets/dir/multiglob' + +test_case Dir do + + class_method :multiglob do + + test do + r = Dir.multiglob('test/c*').sort + r.assert.include?('test/core') + end + + end + + class_method :multiglob_r do + + test do + r = Dir.multiglob_r('test').sort + r.assert.include?('test/core/dir') + r.assert.include?('test/core/dir/test_multiglob.rb') + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_parent.rb b/bin/gems/facets-3.1.0/test/core/dir/test_parent.rb new file mode 100644 index 00000000..4192f5ca --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_parent.rb @@ -0,0 +1,14 @@ +covers 'facets/dir/parent' + +test_case Dir do + + class_method :parent? do + + test do + Dir.assert.parent?("a/b/c", "a/b/c/d") + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/dir/test_recurse.rb b/bin/gems/facets-3.1.0/test/core/dir/test_recurse.rb new file mode 100644 index 00000000..e89f3879 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/dir/test_recurse.rb @@ -0,0 +1,26 @@ +covers 'facets/dir/recurse' + +test_case Dir do + + class_method :recurse do + + test do + r = Dir.recurse('test') + r.assert.include?('test/core/dir') + r.assert.include?('test/core/dir/test_recurse.rb') + end + + end + + class_method :ls_r do + + test do + r = Dir.ls_r('test') + r.assert.include?('test/core/dir') + r.assert.include?('test/core/dir/test_recurse.rb') + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_accumulate.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_accumulate.rb new file mode 100644 index 00000000..2cdb62b2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_accumulate.rb @@ -0,0 +1,44 @@ +covers 'facets/enumerable/accumulate' + +test_case Enumerable do + + method :accumulate do + + test do + a = [1,2,3] + a.accumulate.succ.assert == [2,3,4] + end + + test do + a = [{:ab=>1},{22=>:c}] + a.accumulate.values_at(:ab,22).assert == [1,nil,:c] + end + + test "chained twice" do + a = [1,2,3] + a.accumulate(2).succ.to_s.assert == ['2','3','4'] + end + + test "chained three times" do + a = [{:ab=>1},{22=>:c}] + a.accumulate(3).keys.to_s.split(//).assert == ['a', 'b', '2'] + end + + test "empty receiver" do + a = [] + a.accumulate.succ.assert == [] + end + + end + + method :accumulate_all do + + test "not uniq entries" do + a = [{:ab=>1},{22=>:c}] + a.accumulate_all(3).keys.to_s.split(//).assert == ['a', 'b', '2', '2'] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_cluster.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_cluster.rb new file mode 100644 index 00000000..79e7bbd1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_cluster.rb @@ -0,0 +1,36 @@ +covers 'facets/enumerable/cluster' + +test_case Enumerable do + + method :cluster do + + test "on an array" do + a = [0, 2, 3, 5, 6, 6, 7, 13] + e = [[0, 2], [3, 5], [6, 6], [7, 13]] + r = a.cluster{ |x| x % 2 } + r.assert == e + end + + test "on an array of strings" do + a = ["dog", "duck", "cat", "dude"] + e = [["dog", "duck"], ["cat"], ["dude"]] + r = a.cluster{ |x| x[0] } + r.assert == e + end + + test "on a hash" do + h = {0=>0, 1=>2, 2=>4, 3=>6, 4=>8, 5=>1, 6=>3, 7=>5, 8=>7, 9=>9} + e = [[[0, 0], [1, 2], [2, 4], [3, 6], [4, 8]], [[5, 1], [6, 3], [7, 5], [8, 7], [9, 9]]] + r = h.cluster{ |k, v| v % 2 }.each{|a| a.sort!} + r.assert == e + end + + test "on an empty array" do + r = [].cluster{ |a| a } + r.assert == [] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_compact_map.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_compact_map.rb new file mode 100644 index 00000000..12aacc09 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_compact_map.rb @@ -0,0 +1,32 @@ +covers 'facets/enumerable/compact_map' + +test_case Enumerable do + + method :compact_map do + + test do + r = [1,2,nil,4].compact_map { |e| e } + r.assert == [1,2,4] + end + + end + + method :compact_collect do + + test do + r = [1,2,nil,4].compact_collect { |e| e } + r.assert == [1,2,4] + end + + end + + #method :filter_collect do + # e = [3,4] + # a = [1,2,3,4].filter_collect { |n| + # throw(:skip) if n < 3 + # n + # } + # assert_equal( e, a ) + #end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_defer.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_defer.rb new file mode 100644 index 00000000..3b4c9e68 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_defer.rb @@ -0,0 +1,27 @@ +covers 'facets/enumerable/defer' + +test_case Enumerable do + + method :defer do + + source = (1...1/0.0) + + test do + Denumerator.assert === [1,2,3,4].defer + end + + test "without block" do + a = source.defer + a.class.assert == Denumerator + a.take(5).to_a.assert == [1,2,3,4,5] + end + + test "with block" do + a = source.defer { |out,i| out << i*2 } + a.class.assert == Denumerator + a.take(5).to_a.assert == [2,4,6,8,10] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_each_by.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_each_by.rb new file mode 100644 index 00000000..0e33513e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_each_by.rb @@ -0,0 +1,49 @@ +covers 'facets/enumerable/each_by' + +test_case Enumerable do + + method :each_by do + + test "infer groups of two" do + e = [[1,2], [3,4], [5,6]] + a = [1,2,3,4,5,6] + r = [] + a.each_by{ |a,b| r << [a,b] } + r.assert == e + end + + test "infer groups of three" do + e = [[1,2,3],[4,5,nil]] + a = [1,2,3,4,5] + r = [] + a.each_by{ |a,b,c| r << [a,b,c] } + r.assert == e + end + + test "specify groups of two" do + e = [[1,2],[3,4]] + a = [1,2,3,4] + r = [] + a.each_by(2){ |a,b| r << [a,b] } + r.assert == e + end + + test "specify groups of three with splat argument" do + e = [ [[1,2,3]], [[4,5,6]] ] + a = [1,2,3,4,5,6] + r = [] + a.each_by(3){ |*a| r << a } + r.assert == e + end + + test "specify groups of four with splat argument" do + e = [ [[1,2,3,4]], [[5,6,7,8]] ] + a = [1,2,3,4,5,6,7,8] + r = [] + a.each_by(4){ |*a| r << a } + r.assert == e + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_every.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_every.rb new file mode 100644 index 00000000..ad50024d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_every.rb @@ -0,0 +1,33 @@ +covers 'facets/enumerable/every' + +test_case Enumerable do + + method :every do + + test do + a = [1,2,3] + (a.every + 3 ).assert == [4,5,6] + (a.every - 1).assert == [0,1,2] + (a.every.to_s).assert == ['1','2','3'] + end + + test "on Enumerator" do + e = [1,2,3].to_enum(:map) + r = e.every + 3 + r.assert == [4,5,6] + end + + end + + method :every! do + + test do + a = [1,2,3] + a.every! + 3 + a.assert == [4,5,6] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_ewise.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_ewise.rb new file mode 100644 index 00000000..5f479aaa --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_ewise.rb @@ -0,0 +1,30 @@ +covers 'facets/enumerable/ewise' + +test_case Enumerable do + + method :ewise do + + test do + a = [1,2,3] + (a.ewise + 3).assert == [4,5,6] + (a.ewise + [4,5]).assert == [5,7] + (a.ewise.+([4,5],2)).assert == [[5,7],[3,4,5]] + (a.ewise.+([4,5],3)).assert == [[5,7],[4,5,6]] + end + + end + + method :elementwise do + + test do + a = [1,2,3] + (a.elementwise + 3).assert == [4,5,6] + (a.elementwise + [4,5]).assert == [5,7] + (a.elementwise.+([4,5],2)).assert == [[5,7],[3,4,5]] + (a.elementwise.+([4,5],3)).assert == [[5,7],[4,5,6]] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_exclude.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_exclude.rb new file mode 100644 index 00000000..876a0e70 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_exclude.rb @@ -0,0 +1,15 @@ +covers 'facets/enumerable/exclude' + +test_case Enumerable do + + method :exclude? do + + test do + a = [1,2,2,3] + a.refute.exclude?(2) + a.assert.exclude?(4) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_expand.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_expand.rb new file mode 100644 index 00000000..9d06ba21 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_expand.rb @@ -0,0 +1,15 @@ +covers 'facets/enumerable/expand' + +test_case Enumerable do + + method :expand do + + test do + a = [1,2,2,[1,2]] + r = a.expand + r == [1,2,2,1,2] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_filter.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_filter.rb new file mode 100644 index 00000000..85140a60 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_filter.rb @@ -0,0 +1,19 @@ +covers 'facets/enumerable/filter' + +test_case Enumerable do + + method :filter do + + test do + x = (1..10000) + x = x.filter{ |out,i| out << i if i % 2 == 0 } # like select + x = x.filter{ |out,i| out << i + 100 } # like map + x = x.take(3) + + x.assert == [102, 104, 106] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_find_yield.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_find_yield.rb new file mode 100644 index 00000000..c6bd7b17 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_find_yield.rb @@ -0,0 +1,96 @@ +covers 'facets/enumerable/find_yield' + +test_case Enumerable do + + method :find_yield do + + test "a value" do + r = [true].find_yield { |value| value } + r.assert == true + end + + test "detects correct value" do + r = [1].find_yield { |value| value } + r.assert == 1 + end + + test "returns value of block" do + r = [1].find_yield { |v| v + 3 } + r.assert == 4 + end + + test "detects first truthy value" do + r = [false, false, 1].find_yield { |value| value } + r.assert == 1 + end + + test "returns value when block is true" do + r = [false].find_yield { |value| true } + r.assert == true + end + + test "returns early when block is true" do + v1 = lambda { :something } + v2 = lambda { raise "This shouldn't be called" } + r = [v1, v2].find_yield { |obj| obj.call } + r.assert == :something + end + + test "returns nil when block returns false for all elements" do + r = [1,2,3,4].find_yield { |value| false } + r.assert == nil + end + + test "returns nil when no elements in collection" do + r = [].find_yield { |v| } + r.assert == nil + end + + test "can have return value specified when block isnt true" do + r = [1,2,3].find_yield(:a_value){ |value| false } + r.assert == :a_value + end + + test "documentation correct" do + obj1, obj2 = Object.new, Object.new + + class << obj1 + def foo? + false + end + + def foo + raise + end + end + + class << obj2 + def foo? + true + end + + def foo + "a value" + end + end + + obj1.foo?.assert == false + obj2.foo?.assert == true + obj2.foo.assert == "a value" + + result = [obj1, obj2].find_yield { |obj| obj.foo if obj.foo? } + result.assert == "a value" + end + + end + + method :map_detect do + + test "old alias for #find_yield" do + r = [true].map_detect{ |value| value } + r.assert == true + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_frequency.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_frequency.rb new file mode 100644 index 00000000..989897c9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_frequency.rb @@ -0,0 +1,15 @@ +covers 'facets/enumerable/frequency' + +test_case Enumerable do + + method :frequency do + + test do + %w{a b}.frequency.assert == {'a'=>1,'b'=>1} + %w{a a b}.frequency.assert == {'a'=>2,'b'=>1} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_graph.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_graph.rb new file mode 100644 index 00000000..f5d3954b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_graph.rb @@ -0,0 +1,42 @@ +covers 'facets/enumerable/graph' + +test_case Enumerable do + + method :graph do + + test "returns hash" do + a = { :a => 1, :b => 2, :c => 3 } + e = { :a => 2, :b => 3, :c => 4 } + r = a.graph{ |k,v| {k => v+1} } + r.assert == e + end + + test "hash of array" do + a = { :a => [1,2], :b => [2,3], :c => [3,4] } + e = { :a => 2, :b => 6, :c => 12 } + r = a.graph{ |k,v| [k, v[0]*v[1] ] } + r.assert == e + end + + test "array of array" do + a = [ [1,2], [2,3], [3,4] ] + e = { [1,2] => 2, [2,3] => 6, [3,4] => 12 } + r = a.graph{ |a| [a, a[0]*a[1] ] } + r.assert == e + end + + test "squares" do + numbers = (1..3) + squares = numbers.graph{ |n| [n, n*n] } + squares.assert == {1=>1, 2=>4, 3=>9} + end + + test "roots" do + numbers = (1..3) + sq_roots = numbers.graph{ |n| [n*n, n] } + sq_roots.assert == {1=>1, 4=>2, 9=>3} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_hashify.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_hashify.rb new file mode 100644 index 00000000..0ac8945b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_hashify.rb @@ -0,0 +1,113 @@ +covers 'facets/enumerable/hashify' + +test_case Enumerable do + method :hashify do + test do + a = [ [:a,1], [:b,2] ] + a.hashify.class.assert == Enumerable::Hashifier + end + end +end + +test_case Enumerable::Hashifier do + method :splat do + test do + a = [1,2,3,4] + h = Enumerable::Hashifier.new(a) + h.splat.assert == {1 => 2, 3 => 4} + end + + test do + a = [1,2,3,4,5] + h = Enumerable::Hashifier.new(a) + h.splat.assert == {1 => 2, 3 => 4, 5=> nil} + end + + test do + a = 1..5 + h = Enumerable::Hashifier.new(a) + h.splat.assert == {1 => 2, 3 => 4, 5=> nil} + end + end + + method :flat do + test do + a = [:a,1,[:b,2,:c],4] + h = Enumerable::Hashifier.new(a) + h.flat.assert == {a: 1, b: 2, c: 4} + end + + test do + a = [:a,1,[:b,2,:c]] + h = Enumerable::Hashifier.new(a) + h.flat.assert == {a: 1, b: 2, c: nil} + end + + test do + require 'set' + a = Set.new([:a, 1, [:b, 2, :c]]) + h = Enumerable::Hashifier.new(a) + h.flat.assert == {a: 1, b: 2, c: nil} + end + end + + method :associate do + test do + a = [ [:a,1,2], [:b,2], [:c], [:d] ] + a.hashify.associate.assert == { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + end + + test do + a = [ :x, [:x], [:x,1,2], [:x,3], [:x,4] ] + a.hashify.associate.assert == { :x=>[4] } + end + end + + method :merge do + test do + a = [ [:a,1,2], [:b,2], [:c], [:d] ] + a.hashify.merge.assert == { :a=>1, :b=>2, :c=>nil, :d=>nil } + end + + test do + a = [ :x, [:x], [:x,1,2], [:x,3], [:x,4] ] + a.hashify.merge.assert == { :x=>4 } + end + end + + method :concat do + test do + a = [ [:a,1,2], [:b,2], [:c], [:d] ] + a.hashify.concat.assert == { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + end + + test do + a = [ [:a,1,2], [:a,3], [:a,4], [:a], :a ] + a.hashify.concat.assert == { :a=>[1,2,3,4] } + end + end + + method :by_index do + test do + [:a,:b,:c].hashify.by_index.assert == {0=>:a, 1=>:b, 2=>:c} + end + end + + method :auto do + test do + a = [ [:a,1], [:b,2] ] + a.hashify.auto.assert == { :a=>1, :b=>2 } + end + + test do + a = [ [:a,1,2], [:b,2], [:c], [:d] ] + a.hashify.auto.assert == { :a=>[1,2], :b=>[2], :c=>[], :d=>[] } + end + + test do + a = [ [:a,1,2], 2, :b, [:c,3], 9 ] + a.hashify.auto.assert =={ [:a,1,2]=>2, :b=>[:c,3], 9=>nil } + end + + end +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_key_by.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_key_by.rb new file mode 100644 index 00000000..bd7d0dc0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_key_by.rb @@ -0,0 +1,22 @@ +covers 'facets/enumerable/key_by' + +test_case Enumerable do + + method :key_by do + + test do + a = [:a,:b,:c] + r = a.key_by{ |v| v.to_s } + r.assert == {'a'=>:a, 'b'=>:b, 'c'=>:c} + end + + # Is this how it should behave? + test "works with a hash" do + h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2} + r = h.key_by{ |k,v| k } + r.assert == {"A"=>["A",1], "B"=>["B",1], "C"=>["C",1], "D"=>["D",2], "E"=>["E",2]} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_map_by.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_by.rb new file mode 100644 index 00000000..20b91c5b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_by.rb @@ -0,0 +1,27 @@ +covers 'facets/enumerable/map_by' + +test_case Enumerable do + + method :map_by do + + test do + a = [1,2,3,4,5] + r = a.map_by{ |e| [e % 2, e + 1] } + r.assert == { 0=>[3,5], 1=>[2,4,6] } + end + + test "works well with a hash" do + h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2} + r = h.map_by{ |k,v| [v, k.downcase] } + r.assert == {1=>["a", "b", "c"], 2=>["d", "e"]} + end + + test "if only a scalar is returned, #map_by acts like #group_by" do + h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2} + r = h.map_by{ |k,v| v } + r.assert == {1=>[["A",1], ["B",1], ["C",1]], 2=>[["D",2], ["E",2]]} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_map_send.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_send.rb new file mode 100644 index 00000000..b4a7236b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_send.rb @@ -0,0 +1,26 @@ +covers 'facets/enumerable/map_send' + +test_case Enumerable do + + method :map_send do + + test do + [1,2,3].map_send(:+, 3).assert == [4,5,6] + end + + end + + #method :map_send do + # test do + # r = [1,2,3].map_send(:+, 1) + # assert_equal(r, [2,3,4]) + # end + # + # test "with_block" do + # r = [1,2,3].map_send(:+,1){ |x| x + 1 } + # assert_equal(r, [3,4,5]) + # end + #end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_map_with_index.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_with_index.rb new file mode 100644 index 00000000..826f5c00 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_map_with_index.rb @@ -0,0 +1,23 @@ +covers 'facets/enumerable/map_with_index' + +test_case Enumerable do + + method :map_with_index do + + test do + a = [1,2,3].map_with_index{ |e,i| e*i } + a.assert == [0,2,6] + end + + end + + method :collect_with_index do + + test do + a = [1,2,3].collect_with_index{ |e,i| e*i } + a.assert == [0,2,6] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_mash.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_mash.rb new file mode 100644 index 00000000..cfb4a07e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_mash.rb @@ -0,0 +1,17 @@ +covers 'facets/enumerable/mash' + +test_case Enumerable do + + method :mash do + + test "is an alias for #graph" do + a = { :a => 1, :b => 2, :c => 3 } + e = { :a => 2, :b => 3, :c => 4 } + r = a.mash{ |k,v| {k => v+1} } + r.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_modulate.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_modulate.rb new file mode 100644 index 00000000..a55e092b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_modulate.rb @@ -0,0 +1,17 @@ +covers 'facets/enumerable/modulate' + +test_case Enumerable do + + method :modulate do + + test do + a = [2,4,6,8] + r = a.modulate(2) + x = [[2,6],[4,8]] + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_occur.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_occur.rb new file mode 100644 index 00000000..e2fdfe12 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_occur.rb @@ -0,0 +1,40 @@ +covers 'facets/enumerable/occur' + +test_case Enumerable do + + method :occur do + + # make an Enumerable class to test + eC = Class.new do + include Enumerable + def initialize(*a) + @a = a + end + def each(&b) + @a.each(&b) + end + end + + test do + e = eC.new(:a,:b,:a) + e.occur(1).assert == [:b] + end + + test do + e = eC.new(:a,:b,:a) + e.occur(2).assert == [:a] + end + + test do + e = eC.new(:a,:b,:a) + e.occur(1..1).assert == [:b] + end + + test do + e = eC.new(:a,:b,:a) + e.occur{ |n| n % 2 == 0 }.assert == [:a] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_only.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_only.rb new file mode 100644 index 00000000..3d16cb8e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_only.rb @@ -0,0 +1,40 @@ +covers 'facets/enumerable/only' + +test_case Enumerable do + + # make an Enumerable class to test + eC = Class.new do + include Enumerable + def initialize(*a) + @a = a + end + def each(&b) + @a.each(&b) + end + end + + method :only? do + + test do + e = eC.new(false) + assert e.only? + end + + test do + e = eC.new(1) + assert e.only? + end + + test do + e = eC.new(false, false) + refute e.only? + end + + test do + e = eC.new() + refute e.only? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_per.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_per.rb new file mode 100644 index 00000000..9fcd9533 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_per.rb @@ -0,0 +1,19 @@ +covers 'facets/enumerable/per' + +test_case Enumerable do + + method :per do + + test "map" do + e = [1,2,3].per.map + + (e + 3).assert == [4,5,6] + (e - 1).assert == [0,1,2] + + e.to_s.assert == ['1','2','3'] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_purge.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_purge.rb new file mode 100644 index 00000000..ae98529a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_purge.rb @@ -0,0 +1,22 @@ +covers 'facets/enumerable/purge' + +test_case Enumerable do + + method :purge do + + test do + [1, nil, 2].purge.assert == [1,2] + end + + test "with trash arguments" do + (1..6).purge(3,4).assert == [1,2,5,6] + end + + test "with block" do + (1..6).purge(0){ |n| n % 2 }.assert == [1,3,5] + (1..6).purge(1){ |n| n % 2 }.assert == [2,4,6] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_recursively.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_recursively.rb new file mode 100644 index 00000000..99149e42 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_recursively.rb @@ -0,0 +1,33 @@ +covers 'facets/enumerable/recursively' + +test_case Enumerable do + + method :recursively do + + c = Class.new do + include Enumerable + def initialize(ary) + @ary = ary + end + def each(&b) + @ary.each(&b) + end + end + + test "each" do + e = c.new [1,2,['a','b']] + a = [] + e.recursively(Enumerable).each{ |v| a << v } + a.assert == [1,2,'a','b'] + end + + test "map" do + e = c.new [1,2,['a','b']] + a = e.recursively(Enumerable).map{ |v| v.succ } + a.assert == [2,3,['b','c']] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_squeeze.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_squeeze.rb new file mode 100644 index 00000000..bd6dbf33 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_squeeze.rb @@ -0,0 +1,35 @@ +covers 'facets/enumerable/squeeze' + +test_case Enumerable do + + method :squeeze do + + # make an Enumerable class to test + eC = Class.new do + include Enumerable + def initialize(*a) + @a = a + end + def each(&b) + @a.each(&b) + end + end + + test 'example (default)' do + e = eC.new(1,2,2,3,3,2,1) + e.squeeze.assert == [1,2,3,2,1] + end + + test 'sort.squeeze eq uniq (default)' do + e = eC.new(1,2,2,3,3,2,1) + e.sort.squeeze.assert == [1,2,3] + end + + test 'example (with argument)' do + e = eC.new(1,2,2,3,3,2,1) + e.squeeze(*[3]).assert == [1,2,2,3,2,1] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_sum.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_sum.rb new file mode 100644 index 00000000..283bab87 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_sum.rb @@ -0,0 +1,40 @@ +covers 'facets/enumerable/sum' + +test_case Enumerable do + + method :sum do + + test do + [1,2,3].sum.assert == 6 + end + + test 'with block' do + a = [1.0, 2.1, 3.2].sum(&:to_i) + a.assert == 6 + end + + test 'with identity' do + a = [].sum(9) + a.assert == 9 + + a = [1].sum(9) + a.assert == 10 + end + + test 'with identity and block' do + # notice identity is not effected by the block + a = [].sum(9.1, &:to_i) + a.assert == 9.1 + + a = [1.1].sum(9.1, &:to_i) + a.assert == 10.1 + end + + test 'with non-numeral addition' do + a = [[1],[2],[3]].sum([]) + a.assert == [1,2,3] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_uniq_by.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_uniq_by.rb new file mode 100644 index 00000000..f182f6c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_uniq_by.rb @@ -0,0 +1,25 @@ +covers 'facets/enumerable/uniq_by' + +test_case Enumerable do + + method :uniq_by do + + test do + e = [-5, -4, -3, -2, -1, 0] + r = (-5..5).to_a.uniq_by{ |i| i*i } + r.assert == e + end + + end + + #method :uniq_by! do + # test do + # e = [-5, -4, -3, -2, -1, 0] + # r = (-5..5).to_a + # r.uniq_by!{ |i| i*i } + # r.assert == e + # end + #end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerable/test_visit.rb b/bin/gems/facets-3.1.0/test/core/enumerable/test_visit.rb new file mode 100644 index 00000000..f74c9af2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerable/test_visit.rb @@ -0,0 +1,14 @@ +covers 'facets/enumerable/visit' + +test_case Enumerable do + + method :visit do + + test do + r = [1, 2, 8..9].visit{ |x| x.succ } + r.assert == [2, 3, [9, 10]] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerator/lazy/test_squeeze.rb b/bin/gems/facets-3.1.0/test/core/enumerator/lazy/test_squeeze.rb new file mode 100644 index 00000000..1179652d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerator/lazy/test_squeeze.rb @@ -0,0 +1,33 @@ +if defined?(Enumerator::Lazy) + covers 'facets/enumerator/lazy/squeeze' + + test_case Enumerator::Lazy do + + method :squeeze do + + # make an Enumerable class to test + eC = Class.new do + include Enumerable + def initialize(*a) + @a = a + end + def each(&b) + @a.each(&b) + end + end + + test 'example (default)' do + e = eC.new(1,2,2,3,3,2,1) + e.lazy.squeeze.to_a.assert == [1,2,3,2,1] + end + + test 'example (with argument)' do + e = eC.new(1,2,2,3,3,2,1) + e.lazy.squeeze(*[3]).to_a.assert == [1,2,2,3,2,1] + end + + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerator/test_fx.rb b/bin/gems/facets-3.1.0/test/core/enumerator/test_fx.rb new file mode 100644 index 00000000..b2d49422 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerator/test_fx.rb @@ -0,0 +1,16 @@ +covers 'facets/enumerator/fx' + +test_case Enumerator do + + method :fx do + + test do + e = [1,2,3].to_enum + r = e.fx + 2 + r.assert == [3,4,5] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/enumerator/test_new.rb b/bin/gems/facets-3.1.0/test/core/enumerator/test_new.rb new file mode 100644 index 00000000..f4b7fbf9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerator/test_new.rb @@ -0,0 +1,21 @@ +covers 'facets/enumerator' + +test_case Enumerator do + + class_method :new do + + test "with block" do + # This example taken from ri19 Enumerator.new + fib = Enumerator.new do |y| + a = b = 1 + loop { + y << a + a, b = b, a + b + } + end + fib.take(10).assert == [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/enumerator_tc.rb b/bin/gems/facets-3.1.0/test/core/enumerator_tc.rb new file mode 100644 index 00000000..adacf2c5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/enumerator_tc.rb @@ -0,0 +1,40 @@ +covers 'facets/enumerator' + +test_case Enumerator::Yielder do + + class_method :new do + + test do + y = Enumerator::Yielder.new{ |x| x + 1 } + end + + end + + method :yield do + + test do + y = Enumerator::Yielder.new{ |x| x + 1 } + y.yield(1).assert == 2 + end + + end + + method :<< do + + test do + a = [] + y = Enumerator::Yielder.new{ |x| a << x + 1 } + y << 1 + a.assert == [2] + end + + test do + a = [] + y = Enumerator::Yielder.new{ |x,y| a << x + y } + y.<<(1,2) + a.assert == [3] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/exception/test_detail.rb b/bin/gems/facets-3.1.0/test/core/exception/test_detail.rb new file mode 100644 index 00000000..54ebf82e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/exception/test_detail.rb @@ -0,0 +1,15 @@ +covers 'facets/exception/detail' + +test_case Exception do + + method :detail do + + test "at least it runs" do + err = ArgumentError.new("example error") + err.detail + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/exception/test_raised.rb b/bin/gems/facets-3.1.0/test/core/exception/test_raised.rb new file mode 100644 index 00000000..067dddb3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/exception/test_raised.rb @@ -0,0 +1,15 @@ +covers 'facets/exception/raised' + +test_case Exception do + + class_method :raised? do + + test do + NameError.raised? do + supercalafragalistic + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/exception/test_suppress.rb b/bin/gems/facets-3.1.0/test/core/exception/test_suppress.rb new file mode 100644 index 00000000..ee05c3b8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/exception/test_suppress.rb @@ -0,0 +1,16 @@ +covers 'facets/exception/suppress' + +test_case Exception do + + class_method :suppress do + + test do + NameError.suppress do + supercalafragalistic + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_append.rb b/bin/gems/facets-3.1.0/test/core/file/test_append.rb new file mode 100644 index 00000000..f4d56ea9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_append.rb @@ -0,0 +1,22 @@ +covers 'facets/file/append' + +test_case File do + + class_method :append do + + setup do + require 'fileutils' + @test_file = 'tmp/append.txt' + FileUtils.rm(@test_file) if File.exist?(@test_file) + end + + test do + File.append(@test_file, "line 1\n") + File.read(@test_file).assert == "line 1\n" + File.append(@test_file, "line 2\n") + File.read(@test_file).assert == "line 1\nline 2\n" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_create.rb b/bin/gems/facets-3.1.0/test/core/file/test_create.rb new file mode 100644 index 00000000..98a36a0a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_create.rb @@ -0,0 +1,17 @@ +covers 'facets/file/create' + +test_case File do + + class_method :create do + + test_file = 'tmp/rewrite.txt' + test_data = 'This is a test!' + + test do + File.create(test_file, test_data) + File.read(test_file).assert == test_data + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_ext.rb b/bin/gems/facets-3.1.0/test/core/file/test_ext.rb new file mode 100644 index 00000000..de872444 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_ext.rb @@ -0,0 +1,31 @@ +covers 'facets/file/ext' + +test_case File do + + class_method :ext do + + test "typical filename" do + s = 'file.txt' + File.ext(s).assert == 'txt' + File.ext(s, 'old').assert == 'file.old' + File.ext(s, '').assert == 'file' + end + + test "no extension" do + s = 'file' + File.ext(s).assert == '' + File.ext(s, 'txt').assert == 'file.txt' + File.ext(s, '').assert == 'file' + end + + test "non-standard extensions" do + s = '.profile' + File.ext(s).assert == '' + File.ext(s, 'new').assert == '.profile.new' + File.ext(s, '').assert == '.profile' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_null.rb b/bin/gems/facets-3.1.0/test/core/file/test_null.rb new file mode 100644 index 00000000..1ab4f413 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_null.rb @@ -0,0 +1,14 @@ +covers 'facets/file/null' + +test_case File do + + class_method :null do + + test do + assert File.null + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_read_binary.rb b/bin/gems/facets-3.1.0/test/core/file/test_read_binary.rb new file mode 100644 index 00000000..4b3c8739 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_read_binary.rb @@ -0,0 +1,19 @@ +covers 'facets/file/read_binary' + +test_case File do + + # TODO: Is this even really testable? + class_method :read_binary do + + test_file = 'tmp/read_binary.txt' + test_data = "line 1\nline 2\nline 3" + + test do + File.open(test_file, 'w'){ |f| f << test_data } + File.read_binary(test_file).assert == test_data + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_read_list.rb b/bin/gems/facets-3.1.0/test/core/file/test_read_list.rb new file mode 100644 index 00000000..2fd2b3e1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_read_list.rb @@ -0,0 +1,16 @@ +covers 'facets/file/read_list' + +test_case File do + + class_method :read_list do + + test_file = 'tmp/read_list.txt' + + test do + File.open(test_file, 'w'){ |f| f << "line 1\nline 2\n#line 3" } + File.read_list(test_file).assert == ['line 1', 'line 2'] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_rewrite.rb b/bin/gems/facets-3.1.0/test/core/file/test_rewrite.rb new file mode 100644 index 00000000..658cff3c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_rewrite.rb @@ -0,0 +1,35 @@ +covers 'facets/file/rewrite' + +test_case File do + + test_data = 'This is a test!' + + class_method :rewrite do + + setup do + @test_file = 'tmp/rewrite.txt' + File.open(@test_file, 'w'){ |w| w << test_data } + end + + test do + File.rewrite(@test_file){ |s| s.reverse } + File.read(@test_file).assert == test_data.reverse + end + + end + + class_method :rewrite! do + + setup do + @test_file = 'tmp/rewrite.txt' + File.open(@test_file, 'w'){ |w| w << test_data } + end + + test do + File.rewrite!(@test_file){ |s| s.reverse! } + File.read(@test_file).assert == test_data.reverse + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_rootname.rb b/bin/gems/facets-3.1.0/test/core/file/test_rootname.rb new file mode 100644 index 00000000..9953ad6e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_rootname.rb @@ -0,0 +1,13 @@ +covers 'facets/file/rootname' + +test_case File do + + class_method :rootname do + + test do + File.rootname('test/core/file').assert == 'test' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_sanitize.rb b/bin/gems/facets-3.1.0/test/core/file/test_sanitize.rb new file mode 100644 index 00000000..1e523f83 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_sanitize.rb @@ -0,0 +1,32 @@ +covers 'facets/file/sanitize' + +test_case File do + + # TODO: Write file identity tests. + class_method :sanitize do + + test "spaces become underscores" do + File.sanitize('This is a test').assert == "This_is_a_test" + end + + test "Windows-style path dividers" do + File.sanitize('This\is\test').assert == "test" + end + + test "Unix-style path dividers" do + File.sanitize('This/is/test').assert == "test" + end + + test "non-word characters" do + File.sanitize('This/te#$#@!st').assert == "te_____st" + end + + test "initial dot" do + File.sanitize('.').assert == "_." + File.sanitize('....').assert == "_...." + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_split_all.rb b/bin/gems/facets-3.1.0/test/core/file/test_split_all.rb new file mode 100644 index 00000000..dffab373 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_split_all.rb @@ -0,0 +1,14 @@ +covers 'facets/file/split_all' + +test_case File do + + class_method :split_all do + + test do + fp = "test/core/file" + File.split_all(fp).assert == ['test', 'core', 'file'] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/file/test_write.rb b/bin/gems/facets-3.1.0/test/core/file/test_write.rb new file mode 100644 index 00000000..ff0fe678 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_write.rb @@ -0,0 +1,22 @@ +covers 'facets/file/write' + +test_case File do + + class_method :write do + + test_file = 'tmp/write.txt' + + test do + data = "Test data\n" + + nbytes = File.write(test_file, data) + + out = File.read(test_file) + out.assert == data + out.size.assert == nbytes + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/file/test_writelines.rb b/bin/gems/facets-3.1.0/test/core/file/test_writelines.rb new file mode 100644 index 00000000..a28909a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/file/test_writelines.rb @@ -0,0 +1,21 @@ +covers 'facets/file/writelines' + +#require File.dirname(__FILE__) + '/helpers/mockfile' +test_case File do + + class_method :writelines do + + test_file = 'tmp/writelines.txt' + test_data = %w[one two three four five] + + test do + File.writelines(test_file, test_data) + + out = File.readlines(test_file) + out.map{ |l| l.chomp }.assert == test_data + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/filetest/test_root.rb b/bin/gems/facets-3.1.0/test/core/filetest/test_root.rb new file mode 100644 index 00000000..455f9142 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/filetest/test_root.rb @@ -0,0 +1,14 @@ +covers 'facets/filetest/root' + +test_case FileTest do + + class_method :root? do + + test do + assert FileTest.root?('/') + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/functor_tc.rb b/bin/gems/facets-3.1.0/test/core/functor_tc.rb new file mode 100644 index 00000000..52a05920 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/functor_tc.rb @@ -0,0 +1,41 @@ +covers 'facets/functor' + +test_case Functor do + + class_method :new do + + test do + fc = Functor.new do |op, *a, &b| + [op, a, b] + end + (fc + 1).assert == [:+, [1], nil] + end + + end + + method :__class__ do + + test do + fc = Functor.new do |op, *a, &b| + [op, a, b] + end + fc.__class__.assert == Functor + end + + end + + method :to_proc do + + test do + f = Functor.new do |op, *a| + [op, *a] + end + p = f.to_proc + p.assert.is_a? Proc + p.call(:+,1,2,3).assert == [:+,1,2,3] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_alias.rb b/bin/gems/facets-3.1.0/test/core/hash/test_alias.rb new file mode 100644 index 00000000..1213c168 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_alias.rb @@ -0,0 +1,25 @@ +covers 'facets/hash/alias' + +test_case Hash do + + method :alias! do + + test do + foo = { 'a'=>1, 'b'=>2 } + foo.alias!('c','b').assert == { 'a'=>1, 'b'=>2, 'c'=>2 } + end + + test do + foo = { 'a'=>1, 'b'=>2 } + foo.alias!(:a,'a').assert == { :a=>1, 'a'=>1, 'b'=>2 } + end + + test do + foo = { :a=>1, :b=>2 } + foo.alias!('bar','foo').assert == { :a=>1, :b=>2 } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_argumentize.rb b/bin/gems/facets-3.1.0/test/core/hash/test_argumentize.rb new file mode 100644 index 00000000..4b5979ad --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_argumentize.rb @@ -0,0 +1,23 @@ +covers 'facets/hash/argumentize' + +test_case Hash do + + method :argumentize do + + setup do + @h = { :list => [1,2], :base => "HI" } + end + + test "without an argument field" do + @h.argumentize.assert == [ { :list => [1,2], :base => "HI" } ] + end + + test "with an argument field" do + @h.argumentize(:list).assert == [ 1, 2, { :base => "HI" } ] + @h.argumentize(:base).assert == [ "HI", { :list => [1,2] } ] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_at.rb b/bin/gems/facets-3.1.0/test/core/hash/test_at.rb new file mode 100644 index 00000000..0c83c2dd --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_at.rb @@ -0,0 +1,16 @@ +covers 'facets/hash/at' + +test_case Hash do + + method :at do + + test do + h = { :a=>1, :b=>2 } + h.at(:a).assert == 1 + h.at(:b).assert == 2 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_autonew.rb b/bin/gems/facets-3.1.0/test/core/hash/test_autonew.rb new file mode 100644 index 00000000..53c899eb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_autonew.rb @@ -0,0 +1,22 @@ +covers 'facets/hash/autonew' + +test_case Hash do + + class_method :autonew do + + test do + h = Hash.autonew + h['s1']['p1'] = 4 + h['s1']['p2'] = 5 + h['s1']['p3'] = 2 + h['s1']['p4'] = 3 + + h.assert == {"s1"=>{"p1"=>4, "p4"=>3, "p3"=>2, "p2"=>5}} + + h['s1'].keys.sort.assert == ["p1", "p2", "p3", "p4"] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_collate.rb b/bin/gems/facets-3.1.0/test/core/hash/test_collate.rb new file mode 100644 index 00000000..b1d00e51 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_collate.rb @@ -0,0 +1,61 @@ +covers 'facets/hash/collate' + +test_case Hash do + + setup do + @a = { :a=>1, :b=>2, :z=>26, :all=>%w|a b z|, :stuff1=>%w|foo bar|, :whee=>%w|a b| } + @b = { :a=>1, :b=>4, :c=>9, :all=>%w|a b c|, :stuff2=>%w|jim jam|, :whee=>%w|a b| } + @c = { :a=>1, :b=>8, :c=>27 } + end + + method :collate do + + test do + collated = @a.collate(@b) + + collated.keys.length.assert == 8 + + collated[:a].assert == [1,1] + collated[:b].assert == [2,4] + collated[:c].assert == [9] + collated[:z].assert == [26] + + collated[:all].assert == %w|a b z a b c| + collated[:stuff1].assert == %w|foo bar| + collated[:stuff2].assert == %w|jim jam| + collated[:whee].assert == %w|a b a b| + end + + test "multiple times" do + collated = @a.collate(@b).collate(@c) + + collated[:a].assert == [1,1,1] + collated[:b].assert == [2,4,8] + collated[:c].assert == [9,27] + end + + end + + method :collate! do + + test "in place variant of #collate" do + collated = @a.dup + collated.collate!(@b) + + collated.keys.length.assert == 8 + + collated[:a].assert == [1,1] + collated[:b].assert == [2,4] + collated[:c].assert == [9] + collated[:z].assert == [26] + + collated[:all].assert == %w|a b z a b c| + collated[:stuff1].assert == %w|foo bar| + collated[:stuff2].assert == %w|jim jam| + collated[:whee].assert == %w|a b a b| + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_count.rb b/bin/gems/facets-3.1.0/test/core/hash/test_count.rb new file mode 100644 index 00000000..888bce3a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_count.rb @@ -0,0 +1,23 @@ +covers 'facets/hash/count' + +test_case Hash do + + method :count do + + test do + {:A=>1, :B=>1, :C=>2}.count(1).assert == 2 + {:A=>1, :B=>1, :C=>2}.count(2).assert == 1 + end + + test "no matches" do + {:A=>1, :B=>1, :C=>2}.count(3).assert == 0 + end + + test "still works with Enumerable#count" do + {:A=>1, :B=>1, :C=>2}.count.assert == 3 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_data.rb b/bin/gems/facets-3.1.0/test/core/hash/test_data.rb new file mode 100644 index 00000000..2f2fc3a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_data.rb @@ -0,0 +1,35 @@ +covers 'facets/hash/data' + +test_case Hash do + + method :data do + + test do + h = {:a=>1, :b=>2} + + h.data.a.assert == 1 + h.data.b.assert == 2 + h.data.c.assert == nil + end + + test do + h = {:a=>1, :b=>2} + + h.data.c = 3 + h.data.c.assert == 3 + end + + test do + h = {:a=>1, :b=>2} + + # Note, we can't apply a functor to a functor. + #h.data.assert.a? + #h.data.refute.d? + + h.data.a?.assert == true + h.data.d?.assert == false + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_dearray_values.rb b/bin/gems/facets-3.1.0/test/core/hash/test_dearray_values.rb new file mode 100644 index 00000000..b2ad0c94 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_dearray_values.rb @@ -0,0 +1,26 @@ +covers 'facets/hash/dearray_values' + +test_case Hash do + + method :dearray_values do + + test do + h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] } + x = { :a=>1, :b=>1, :c=>3, :d=>nil } + h.dearray_values.assert == x + end + + end + + method :dearray_singular_values do + + test do + h = { :a=>[1], :b=>[1,2], :c=>3, :d=>[] } + x = { :a=>1, :b=>[1,2], :c=>3, :d=>nil } + h.dearray_singular_values.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_deep_merge.rb b/bin/gems/facets-3.1.0/test/core/hash/test_deep_merge.rb new file mode 100644 index 00000000..a0809813 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_deep_merge.rb @@ -0,0 +1,31 @@ +covers 'facets/hash/deep_merge' + +test_case Hash do + + method :deep_merge do + + test do + h1 = { :a=>1, :c=>{:x=>10} } + h2 = { :b=>2, :c=>{:y=>11} } + + h = h1.deep_merge(h2) + + h.assert == {:a=>1, :b=>2, :c=>{:x=>10, :y=>11}} + end + + end + + method :deep_merge! do + + test do + h1 = { :a=>1, :c=>{:x=>10} } + h2 = { :b=>2, :c=>{:y=>11} } + + h1.deep_merge!(h2) + + h1.assert == {:a=>1, :b=>2, :c=>{:x=>10, :y=>11}} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_deep_rekey.rb b/bin/gems/facets-3.1.0/test/core/hash/test_deep_rekey.rb new file mode 100644 index 00000000..be4d2474 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_deep_rekey.rb @@ -0,0 +1,131 @@ +covers 'facets/hash/deep_rekey' + +test_case Hash do + + method :deep_rekey do + + test "default converts all keys to symbols" do + foo = { "c"=>{ "a"=>1, "b"=>2 } } + foo.deep_rekey.assert == { :c=>{ :a=>1, :b=>2 } } + foo.assert == { "c"=>{ "a"=>1, "b"=>2 } } + end + + test "specific key" do + bar = { :d=>{ :a=>1, :b=>2 } } + foo = bar.deep_rekey(:a=>:c) + foo[:d][:c].assert == 1 + foo[:d][:b].assert == 2 + foo[:d][:a].assert == nil + end + + test "multiple keys" do + bar = { :z=>{ :a=>1, :b=>2, :c=>3 } } + foo = bar.deep_rekey(:a=>:d,:b=>:e) + foo[:z][:d].assert == 1 + foo[:z][:e].assert == 2 + foo[:z][:c].assert == 3 + foo[:z][:a].assert == nil + foo[:z][:b].assert == nil + end + + test "multiple keys, some on same level as other hash" do + bar = { :z=>{ :a=>1, :b=>2, :c=>3 }, :y=>4 } + foo = bar.deep_rekey(:a=>:d,:b=>:e) + foo[:z][:d].assert == 1 + foo[:z][:e].assert == 2 + foo[:z][:c].assert == 3 + foo[:y].assert == 4 + foo[:z][:a].assert == nil + foo[:z][:b].assert == nil + end + + # TODO: Is using Hash#deep_rekey to exhange keys possible? + + #test "exchange keys via dummy key" do + # bar = { :a=>1, :b=>2, :c=>3 } + # foo = bar.deep_rekey(:a=>:d,:c=>:a,:d=>:c) + # foo[:a].assert == 3 + # foo[:b].assert == 2 + # foo[:c].assert == 1 + # foo[:d].assert == nil + #end + + test "with block" do + bar = { :c=>{ :a=>1, :b=>2 } } + foo = bar.deep_rekey{ |k| k.to_s } + foo['c']['a'].assert == 1 + foo['c']['b'].assert == 2 + foo['c'][:a].assert == nil + foo['c'][:b].assert == nil + foo.assert == { 'c'=>{ 'a'=>1, 'b'=>2 } } + end + + test "with block of key, value" do + bar = { :c=>{ :a=>1, :b=>2 } } + foo = bar.deep_rekey{ |k, v| v.to_s } + k = foo.keys.first + foo[k]['1'].assert == 1 + foo[k]['2'].assert == 2 + foo[k][:a].assert == nil + foo[k][:b].assert == nil + foo[k]['a'].assert == nil + foo[k]['b'].assert == nil + foo.assert == { k=>{ '1'=>1, '2'=>2 } } + end + + test "with keys and block" do + expect ArgumentError do + bar = { :c=>{ :a=>1, :b=>2 } } + bar.deep_rekey(:a=>:c){ |k| k.to_s } + end + end + + test "symbol proc" do + foo = { :c=>{ :a=>1, :b=>2 } } + foo.deep_rekey(&:to_s).assert == { "c"=>{ "a"=>1, "b"=>2 } } + foo.assert == { :c=>{ :a =>1, :b=>2 } } + end + + end + + method :deep_rekey! do + + test "default" do + foo = { "c"=>{ "a"=>1, "b"=>2 } } + foo.deep_rekey!.assert == { :c=>{ :a=>1, :b=>2 } } + foo.assert == { :c=>{ :a=>1, :b=>2 } } + end + + test "specific key" do + foo = { :d=>{ :a=>1, :b=>2 } } + foo.deep_rekey!(:a=>:c) + foo[:d][:c].assert == 1 + foo[:d][:b].assert == 2 + foo[:d][:a].assert == nil + end + + test "with block" do + foo = { :c=>{ :a=>1, :b=>2 } } + foo.deep_rekey!{ |k| k.to_s } + foo['c']['a'].assert == 1 + foo['c']['b'].assert == 2 + foo['c'][:a].assert == nil + foo['c'][:b].assert == nil + foo.assert == { 'c'=>{ 'a'=>1, 'b'=>2 } } + end + + test "symbol proc" do + foo = { :c=>{ :a=>1, :b=>2 } } + foo.deep_rekey!(&:to_s).assert == { "c"=>{ "a"=>1, "b"=>2 } } + foo.assert == { "c"=>{ "a"=>1, "b"=>2 } } + end + + test "no conflict between keys" do + r = { 0 => {1 => :a, 2 => :b} }.deep_rekey!{ |k| k + 1 } + r[1].refute = {3 => :a} + r[1].assert = {2 => :a, 3 => :b} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_delete_at.rb b/bin/gems/facets-3.1.0/test/core/hash/test_delete_at.rb new file mode 100644 index 00000000..f973bc9c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_delete_at.rb @@ -0,0 +1,18 @@ +covers 'facets/hash/delete_at' + +test_case Hash do + + method :delete_at do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :b => 2, :c => 3 } + v = a.delete_at(:a) + v.assert == 1 + a.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_delete_unless.rb b/bin/gems/facets-3.1.0/test/core/hash/test_delete_unless.rb new file mode 100644 index 00000000..8a3d130f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_delete_unless.rb @@ -0,0 +1,18 @@ +covers 'facets/hash/delete_unless' + +test_case Hash do + + method :delete_unless do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :a => 1 } + r = a.delete_unless{|k,v| v == 1} + r.assert == x + a.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_delete_values.rb b/bin/gems/facets-3.1.0/test/core/hash/test_delete_values.rb new file mode 100644 index 00000000..db3a1b70 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_delete_values.rb @@ -0,0 +1,30 @@ +covers 'facets/hash/delete_values' + +test_case Hash do + + method :delete_values do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :b => 2, :c => 3 } + r = a.delete_values(1) + #r.assert == x + a.assert == x + end + + end + + method :delete_values_at do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :b => 2, :c => 3 } + r = a.delete_values_at(:a) + r.assert == [1] + a.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_diff.rb b/bin/gems/facets-3.1.0/test/core/hash/test_diff.rb new file mode 100644 index 00000000..97d2ec38 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_diff.rb @@ -0,0 +1,16 @@ +covers "facets/hash/diff" + +test_case Hash do + + method :diff do + + test do + h1 = {:a=>1,:b=>2} + h2 = {:a=>1,:b=>3} + h1.diff(h2).assert == {:b=>2} + h2.diff(h1).assert == {:b=>3} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_each_with_key.rb b/bin/gems/facets-3.1.0/test/core/hash/test_each_with_key.rb new file mode 100644 index 00000000..9e90e63e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_each_with_key.rb @@ -0,0 +1,16 @@ +covers 'facets/hash/each_with_key' + +test_case Hash do + + method :each_with_key do + + test do + h1 = {:a=>1, :b=>2} + h2 = {} + h1.each_with_key { |v,k| h2[v] = k } + h2.assert == {1=>:a, 2=>:b} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_expect.rb b/bin/gems/facets-3.1.0/test/core/hash/test_expect.rb new file mode 100644 index 00000000..d491fe48 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_expect.rb @@ -0,0 +1,34 @@ +covers 'facets/hash/except' + +test_case Hash do + + method :except do + + test do + h = {:a=>1, :b=>2, :c=>3} + h.except(:a).assert == {:b=>2,:c=>3} + end + + end + + method :except! do + + test do + h = {:a=>1, :b=>2, :c=>3} + h.except!(:a).assert == {:b=>2,:c=>3} + h.assert == {:b=>2,:c=>3} + end + + end + + method :remove! do + + test do + h = {:a=>1, :b=>2, :c=>3} + h.remove!(:a).assert == {:a=>1} + h.assert == {:b=>2,:c=>3} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_fetch_nested.rb b/bin/gems/facets-3.1.0/test/core/hash/test_fetch_nested.rb new file mode 100644 index 00000000..4763ec42 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_fetch_nested.rb @@ -0,0 +1,24 @@ +covers 'facets/hash/fetch_nested' + +test_case Hash do + + setup do + @a = {'hello'=>{'world'=>42}} + @b = {} + end + + method :fetch_nested do + + test 'safe case' do + @a['hello']['world'].assert == 42 + @a.fetch_nested(*['hello','world']).assert == 42 + end + + test 'dangerous case' do + expect(NoMethodError){@b['hello']['world']} + @b.fetch_nested(*['hello','world']).assert == nil + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_graph.rb b/bin/gems/facets-3.1.0/test/core/hash/test_graph.rb new file mode 100644 index 00000000..8c976b35 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_graph.rb @@ -0,0 +1,40 @@ +covers 'facets/hash/graph' + +test_case Hash do + + method :graph! do + + test "using a hash" do + a = { :a => 1, :b => 2, :c => 3 } + e = { :a => 2, :b => 3, :c => 4 } + a.graph!{ |k,v| { k => v+1 } } + a.assert == e + end + + test "using an associative array" do + h = {:a=>1,:b=>2,:c=>3} + h.graph!{ |k,v| [v, v*v] } + h.assert == {1=>1, 2=>4, 3=>9} + end + + end + + method :mash! do + + test "using a hash" do + a = { :a => 1, :b => 2, :c => 3 } + e = { :a => 2, :b => 3, :c => 4 } + a.mash!{ |k,v| { k => v+1 } } + a.assert == e + end + + test "using an associative array" do + h = {:a=>1,:b=>2,:c=>3} + h.mash!{ |k,v| [v, v*v] } + h.assert == {1=>1, 2=>4, 3=>9} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_insert.rb b/bin/gems/facets-3.1.0/test/core/hash/test_insert.rb new file mode 100644 index 00000000..021a4328 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_insert.rb @@ -0,0 +1,20 @@ +covers 'facets/hash/insert' + +test_case Hash do + + method :insert do + + test do + h = {:a=>1, :b=>2} + + h.assert.insert(:c,3) + h.assert == {:a=>1, :b=>2, :c=>3} + + h.refute.insert(:a,0) + h.assert == {:a=>1, :b=>2, :c=>3} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_inverse.rb b/bin/gems/facets-3.1.0/test/core/hash/test_inverse.rb new file mode 100644 index 00000000..d23bb0d3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_inverse.rb @@ -0,0 +1,20 @@ +covers 'facets/hash/inverse' + +test_case Hash do + + method :inverse do + + test do + h1 = { :a=>1, :b=>2, :c=>2 } + h2 = h1.inverse + + h2[1].assert == :a + + h2[2].assert.include?(:b) + h2[2].assert.include?(:c) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_join.rb b/bin/gems/facets-3.1.0/test/core/hash/test_join.rb new file mode 100644 index 00000000..ecaffeb5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_join.rb @@ -0,0 +1,32 @@ +covers 'facets/hash/join' + +test_case Hash do + + method :join do + + setup do + @h = {:a=>1, :b=>2} + end + + test do + s = @h.join + s.assert.include?('b2') + s.assert.include?('a1') + end + + test do + s = @h.join(',') + s.assert.include?('a,1') + s.assert.include?('b,2') + end + + test do + s = @h.join(',', ':') + s.assert.include?('a,1') + s.assert.include?('b,2') + s.assert.include?(':') + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_keys.rb b/bin/gems/facets-3.1.0/test/core/hash/test_keys.rb new file mode 100644 index 00000000..b1054b24 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_keys.rb @@ -0,0 +1,41 @@ +covers 'facets/hash/keys' + +test_case Hash do + + method :keys? do + + test do + {:a=>1,:b=>2,:c=>3}.assert.keys?(:a,:b) + {:a=>1,:b=>2,:c=>3 }.refute.keys?(:a,:b,:d) + end + + end + + method :only_keys? do + + test do + {:a=>1,:b=>2,:c=>3}.assert.only_keys?(:a,:b,:c) + {:a=>1,:b=>2,:c=>3}.refute.only_keys?(:a,:b) + end + + end + + method :has_keys? do + + test do + {:a=>1,:b=>2,:c=>3}.assert.has_keys?(:a,:b) + {:a=>1,:b=>2,:c=>3 }.refute.has_keys?(:a,:b,:d) + end + + end + + method :has_only_keys? do + + test do + {:a=>1,:b=>2,:c=>3}.assert.has_only_keys?(:a,:b,:c) + {:a=>1,:b=>2,:c=>3}.refute.has_only_keys?(:a,:b) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_new_with.rb b/bin/gems/facets-3.1.0/test/core/hash/test_new_with.rb new file mode 100644 index 00000000..27347ea9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_new_with.rb @@ -0,0 +1,17 @@ +covers 'facets/hash/new_with' + +test_case Hash do + + class_method :new_with do + + test do + h = Hash.new_with{0} + + h[:ab].assert == 0 + h[100].assert == 0 + h["a"].assert == 0 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_add.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_add.rb new file mode 100644 index 00000000..b8ab1963 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_add.rb @@ -0,0 +1,17 @@ +covers 'facets/hash/op_add' + +test_case Hash do + + method :+ do + + test do + a = { :a => 1, :b => 2 } + b = { :b => 3, :c => 4 } + x = { :a => 1, :b => 3, :c => 4 } + r = a + b + r.assert == x + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_and.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_and.rb new file mode 100644 index 00000000..76839373 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_and.rb @@ -0,0 +1,31 @@ +covers 'facets/hash/op_and' + +test_case Hash do + + method :& do + + test "hash and hash" do + a = { :a => 1, :b => 2 } + b = { :a => 1 } + x = { :a => 1 } + (a & b).assert == x + end + + test "hashes with sub-array" do + a = { :a => [1], :b => [2] } + b = { :a => [1] } + x = { :a => [1] } + (a & b).assert == x + end + + test "hash and array" do + a = { :a => 1, :b => 2 } + b = [ :a ] + x = { :a => 1 } + (a & b).assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_mul.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_mul.rb new file mode 100644 index 00000000..cc0f99b3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_mul.rb @@ -0,0 +1,17 @@ +covers 'facets/hash/op_mul' + +test_case Hash do + + method :* do + + test do + a = { :a => 1, :b => 2 } + b = { :b => 3 } + x = { :a => 1, :b => 2 } + (a * b).assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_or.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_or.rb new file mode 100644 index 00000000..42d05bd8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_or.rb @@ -0,0 +1,17 @@ +covers 'facets/hash/op_or' + +test_case Hash do + + method :| do + + test do + a = { :a => 1, :b => 2 } + b = { :b => 3 } + x = { :a => 1, :b => 2 } + (a | b).assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_push.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_push.rb new file mode 100644 index 00000000..55153df9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_push.rb @@ -0,0 +1,34 @@ +covers 'facets/hash/op_push' + +test_case Hash do + + method :<< do + + test "two element array" do + h = {} + a = [:b, 2] + x = {:b => 2} + (h << a).assert == h + h.assert == x + end + + test "update new entries" do + a = {:a => 1} + b = {:b => 2, :c => 3 } + x = {:a => 1, :b => 2, :c => 3} + (a << b).assert == x + a.assert == x + end + + test "update overwrite" do + a = {:a => 1, :b => 2, :c => 3} + b = {:a => 0, :d => 4} + x = {:a => 0, :b => 2, :c => 3, :d => 4} + (a << b).assert == x + a.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_op_sub.rb b/bin/gems/facets-3.1.0/test/core/hash/test_op_sub.rb new file mode 100644 index 00000000..320f18d1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_op_sub.rb @@ -0,0 +1,28 @@ +covers 'facets/hash/op_sub' + +test_case Hash do + + method :- do + + test "hash minus array" do + a = { :a => 1, :b => 2, :c => 3 } + b = [ :a ] + x = { :b => 2, :c => 3 } + (a - b).assert == x + end + + end + + method :- do + + test "hash minus hash" do + a = { :a => 1, :b => 2, :c => 3 } + b = { :a => 1, :d => 4 } + x = { :b => 2, :c => 3 } + (a - b).assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_recurse.rb b/bin/gems/facets-3.1.0/test/core/hash/test_recurse.rb new file mode 100644 index 00000000..336dfc37 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_recurse.rb @@ -0,0 +1,39 @@ +covers 'facets/hash/recurse' + +test_case Hash do + + method :recurse do + + test do + h = {:a=>1, :b=>{:b1=>1, :b2=>2}} + g = h.recurse{|h| h.inject({}){|h,(k,v)| h[k.to_s] = v; h} } + g.assert == {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}} + end + + test "with Arrays" do + require 'facets/array/recurse' + objects = [] + struct = {:a => 3, :b => [4, 5, {:c=>6}]} + struct.recurse(Array, Hash){|o| objects << o; o } + + objects.assert.include?( {:c=>6} ) + objects.assert.include?( [4, 5, {:c=>6}] ) + objects.assert.include?( struct ) + + objects.length.assert == 3 + end + + end + + method :recurse! do + + test do + h = {:a=>1, :b=>{:b1=>1, :b2=>2}} + h.recurse!{|h| h.inject({}){|h,(k,v)| h[k.to_s] = v; h} } + h.assert == {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_recursively.rb b/bin/gems/facets-3.1.0/test/core/hash/test_recursively.rb new file mode 100644 index 00000000..4fecb1e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_recursively.rb @@ -0,0 +1,71 @@ +covers 'facets/hash/recursively' +covers 'facets/hash/graph' + +test_case Hash do + + method :recursively do + + test "each" do + h = {:a=>1,:b=>{:c=>3}} + r = [] + h.recursively.each{ |k,v| r << [k,v] } + r.assert.include? [:a,1] + r.assert.include? [:b,{:c=>3}] + r.assert.include? [:c,3] + end + + test "map" do + h = {:a=>1,:b=>{:c=>3}} + r = h.recursively{ |k,v| [k,v] }.map{ |k,v| [k, v.succ] } + r.assert.include? [:a,2] + r.assert.include? [:b,[[:c,4]]] + end + + test "map (moot)" do + h = {:a=>1,:b=>{:c=>3}} + a = h.recursively.map{ |k,v| [k, v] } + a.assert.include? [:a,1] + a.assert.include? [:b,[[:c,3]]] + end + + test 'graph' do + h = {:a=>1,:b=>{:c=>3}} + r = h.recursively{ |k,v| [k.to_s, v] }.graph{ |k,v| [k.to_s, v.to_s] } + r.assert == {'a'=>'1','b'=>{'c'=>'3'}} + end + + test 'graph!' do + h = {:a=>1,:b=>{:c=>3}} + h.recursively{ |k,v| [k.to_s, v] }.graph!{ |k,v| [k.to_s, v.to_s] } + h.assert == {'a'=>'1','b'=>{'c'=>'3'}} + end + + test 'mash' do + h = {:a=>1,:b=>{:c=>3}} + r = h.recursively{ |k,v| [k.to_s, v] }.mash{ |k,v| [k.to_s, v.to_s] } + r.assert == {'a'=>'1','b'=>{'c'=>'3'}} + end + + test 'mash!' do + h = {:a=>1,:b=>{:c=>3}} + h.recursively{ |k,v| [k.to_s, v] }.mash!{ |k,v| [k.to_s, v.to_s] } + h.assert == {'a'=>'1','b'=>{'c'=>'3'}} + end + + #test 'merge' do + # h1 = {:a=>1,:b=>{:c=>3}} + # h2 = {:b=>{:d=>4}} + # r = h1.recursively.merge(h2) + # r.assert == {:a=>1,:b=>{:c=>3, :d=>4}} + #end + + #test 'merge!' do + # h1 = {:a=>1,:b=>{:c=>3}} + # h2 = {:b=>{:d=>4}} + # h1.recursively.merge!(h2) + # h1.assert == {:a=>1,:b=>{:c=>3, :d=>4}} + #end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_rekey.rb b/bin/gems/facets-3.1.0/test/core/hash/test_rekey.rb new file mode 100644 index 00000000..c993c7d4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_rekey.rb @@ -0,0 +1,119 @@ +covers 'facets/hash/rekey' + +test_case Hash do + + method :rekey do + + test "default converts all keys to symbols" do + foo = { "a"=>1, "b"=>2 } + foo.rekey.assert == { :a=>1, :b=>2 } + foo.assert == { "a"=>1, "b"=>2 } + end + + test "specific key" do + bar = { :a=>1, :b=>2 } + foo = bar.rekey(:a=>:c) + foo[:c].assert == 1 + foo[:b].assert == 2 + foo[:a].assert == nil + end + + test "multiple keys" do + bar = { :a=>1, :b=>2, :c=>3 } + foo = bar.rekey(:a=>:d,:b=>:e) + foo[:d].assert == 1 + foo[:e].assert == 2 + foo[:c].assert == 3 + foo[:a].assert == nil + foo[:b].assert == nil + end + + # TODO: Is using Hash#rekey to exhange keys possible? + + #test "exchange keys via dummy key" do + # bar = { :a=>1, :b=>2, :c=>3 } + # foo = bar.rekey(:a=>:d,:c=>:a,:d=>:c) + # foo[:a].assert == 3 + # foo[:b].assert == 2 + # foo[:c].assert == 1 + # foo[:d].assert == nil + #end + + test "with block" do + bar = { :a=>1, :b=>2 } + foo = bar.rekey{ |k| k.to_s } + foo['a'].assert == 1 + foo['b'].assert == 2 + foo[:a].assert == nil + foo[:b].assert == nil + foo.assert == { 'a'=>1, 'b'=>2 } + end + + test "with block of key, value" do + bar = { :a=>1, :b=>2 } + foo = bar.rekey{ |k, v| v.to_s } + foo['1'].assert == 1 + foo['2'].assert == 2 + foo[:a].assert == nil + foo[:b].assert == nil + foo['a'].assert == nil + foo['b'].assert == nil + foo.assert == { '1'=>1, '2'=>2 } + end + + test "with keys and block" do + expect ArgumentError do + bar = { :a=>1, :b=>2 } + bar.rekey(:a=>:c){ |k| k.to_s } + end + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.rekey(&:to_s).assert == { "a"=>1, "b"=>2 } + foo.assert == { :a =>1, :b=>2 } + end + + end + + method :rekey! do + + test "default" do + foo = { "a"=>1, "b"=>2 } + foo.rekey!.assert == { :a=>1, :b=>2 } + foo.assert == { :a=>1, :b=>2 } + end + + test "specific key" do + foo = { :a=>1, :b=>2 } + foo.rekey!(:a=>:c) + foo[:c].assert == 1 + foo[:b].assert == 2 + foo[:a].assert == nil + end + + test "with block" do + foo = { :a=>1, :b=>2 } + foo.rekey!{ |k| k.to_s } + foo['a'].assert == 1 + foo['b'].assert == 2 + foo[:a].assert == nil + foo[:b].assert == nil + foo.assert == { 'a'=>1, 'b'=>2 } + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.rekey!(&:to_s).assert == { "a"=>1, "b"=>2 } + foo.assert == { "a"=>1, "b"=>2 } + end + + test "no conflict between keys" do + r = {1 => :a, 2 => :b}.rekey!{ |k| k + 1 } + r.refute = {3 => :a} + r.assert = {2 => :a, 3 => :b} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_replace_each.rb b/bin/gems/facets-3.1.0/test/core/hash/test_replace_each.rb new file mode 100644 index 00000000..b411d42e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_replace_each.rb @@ -0,0 +1,17 @@ +covers 'facets/hash/replace_each' + +test_case Hash do + + method :replace_each do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :a => 2, :b => 3, :c => 4 } + a.replace_each{ |k,v| { k => v+1 } } + a.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_revalue.rb b/bin/gems/facets-3.1.0/test/core/hash/test_revalue.rb new file mode 100644 index 00000000..49611a0e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_revalue.rb @@ -0,0 +1,98 @@ +covers 'facets/hash/revalue' + +test_case Hash do + + method :revalue do + + #test "default converts all keys to symbols" do + # foo = { "a"=>1, "b"=>2 } + # foo.rekey.assert == { :a=>1, :b=>2 } + # foo.assert == { "a"=>1, "b"=>2 } + #end + + test "specific value" do + bar = { :a=>1, :b=>2 } + foo = bar.revalue(2=>3) + foo[:a].assert == 1 + foo[:b].assert == 3 + foo.size.assert == 2 + end + + test "multiple values" do + bar = { :a=>1, :b=>2, :c=>3 } + foo = bar.revalue(1=>4,3=>5) + foo[:a].assert == 4 + foo[:b].assert == 2 + foo[:c].assert == 5 + foo.size.assert == 3 + end + + test "with block" do + bar = { :a=>1, :b=>2 } + foo = bar.revalue{ |v| v.to_s } + foo[:a].assert == "1" + foo[:b].assert == "2" + foo.assert == { :a=>"1", :b=>"2" } + end + + test "with block of key, value" do + bar = { :a=>1, :b=>2 } + foo = bar.revalue{ |k, v| [k,v] } + foo[:a].assert == [:a,1] + foo[:b].assert == [:b,2] + foo.assert == { :a=>[:a,1], :b=>[:b,2] } + end + + test "with values and block" do + expect ArgumentError do + bar = { :a=>1, :b=>2 } + bar.revalue(1=>3){ |v| v.to_s } + end + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.revalue(&:to_s).assert == { :a=>"1", :b=>"2" } + foo.assert == { :a =>1, :b=>2 } + end + + end + + method :revalue! do + + #test "default" do + # foo = { "a"=>1, "b"=>2 } + # foo.revalue!.assert == { :a=>1, :b=>2 } + # foo.assert == { :a=>1, :b=>2 } + #end + + test "specific value" do + foo = { :a=>1, :b=>2 } + foo.revalue!(1=>3) + foo[:a].assert == 3 + foo[:b].assert == 2 + end + + test "with block" do + foo = { :a=>1, :b=>2 } + foo.revalue!{ |v| v.to_s } + foo[:a].assert == "1" + foo[:b].assert == "2" + foo.assert == { :a=>"1", :b=>"2" } + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.revalue!(&:to_s).assert == { :a=>"1", :b=>"2" } + foo.assert == { :a=>"1", :b=>"2" } + end + + test "no conflict between keys" do + r = {:a => 1, :b => 2}.revalue!{ |v| v + 1 } + r.refute = {:a => 3} + r.assert = {:a => 2, :b => 3} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_reverse_merge.rb b/bin/gems/facets-3.1.0/test/core/hash/test_reverse_merge.rb new file mode 100644 index 00000000..2d6cae5c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_reverse_merge.rb @@ -0,0 +1,39 @@ +covers 'facets/hash/reverse_merge' + +test_case Hash do + + method :reverse_merge do + + test do + h1 = { :a=>1, :b=>2, :c=>2 } + h2 = { :c=>3 } + h3 = h1.reverse_merge(h2) + h3[:c].assert == 2 + end + + end + + method :reverse_merge! do + + test do + h1 = { :a=>1, :b=>2, :c=>2 } + h2 = { :c=>3 } + h1.reverse_merge!(h2) + h1[:c].assert == 2 + end + + end + + method :reverse_update do + + test do + h1 = { :a=>1, :b=>2, :c=>2 } + h2 = { :c=>3 } + h1.reverse_update(h2) + h1[:c].assert == 2 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_slice.rb b/bin/gems/facets-3.1.0/test/core/hash/test_slice.rb new file mode 100644 index 00000000..10b8a242 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_slice.rb @@ -0,0 +1,36 @@ +covers 'facets/hash/slice' + +test_case Hash do + + method :slice do + + test 'only existing keys' do + h = {:a=>1,:b=>2,:c=>3} + h.slice(:a, :b).assert == {:b=>2, :a=>1} + end + + test 'with non-existent keys' do + h = {:a=>1,:b=>2,:c=>3} + h.slice(:a, :d).assert == {:a=>1} + end + + end + + method :slice! do + + test do + h = {:a=>1,:b=>2,:c=>3} + h.slice!(:a, :b).assert == {:c=>3} + h.assert == {:a=>1,:b=>2} + end + + test do + h = {:a=>1,:b=>2,:c=>3} + h.slice!(:a, :d).assert == {:c=>3, :b=>2} + h.assert == {:a=>1} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_stringify_keys.rb b/bin/gems/facets-3.1.0/test/core/hash/test_stringify_keys.rb new file mode 100644 index 00000000..07ca2856 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_stringify_keys.rb @@ -0,0 +1,26 @@ +covers 'facets/hash/stringify_keys' + +test_case Hash do + + method :stringify_keys do + + test do + foo = { :a=>1, :b=>2 } + foo.stringify_keys.assert == { "a"=>1, "b"=>2 } + foo.assert == { :a =>1, :b=>2 } + end + + end + + method :stringify_keys! do + + test do + foo = { :a=>1, :b=>2 } + foo.stringify_keys!.assert == { "a"=>1, "b"=>2 } + foo.assert == { "a"=>1, "b"=>2 } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_swap.rb b/bin/gems/facets-3.1.0/test/core/hash/test_swap.rb new file mode 100644 index 00000000..70aee059 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_swap.rb @@ -0,0 +1,15 @@ +covers 'facets/hash/swap' + +test_case Hash do + + method :swap! do + + test do + h = { :a=>1, :b=>2 } + h.swap!(:a, :b).assert == { :a=>2, :b=>1 } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_symbolize_keys.rb b/bin/gems/facets-3.1.0/test/core/hash/test_symbolize_keys.rb new file mode 100644 index 00000000..ca7026e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_symbolize_keys.rb @@ -0,0 +1,26 @@ +covers 'facets/hash/symbolize_keys' + +test_case Hash do + + method :symbolize_keys do + + test do + foo = { 'a'=>1, 'b'=>2 } + foo.symbolize_keys == { :a=>1, :b=>2 } + foo.assert == { "a" =>1, "b"=>2 } + end + + end + + method :symbolize_keys! do + + test do + foo = { 'a'=>1, 'b'=>2 } + foo.symbolize_keys!.assert == { :a=>1, :b=>2 } + foo.assert == { :a=>1, :b=>2 } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_to_mod.rb b/bin/gems/facets-3.1.0/test/core/hash/test_to_mod.rb new file mode 100644 index 00000000..a939667e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_to_mod.rb @@ -0,0 +1,24 @@ +covers 'facets/hash/to_mod' + +test_case Hash do + + method :to_mod do + + test do + h = { :a=>1, :b=>2 } + m = h.to_mod + Module.assert === m + end + + test "check methods" do + h = { :a=>1, :b=>2 } + m = h.to_mod + x = Class.new{ include m }.new + x.a.assert == 1 + x.b.assert == 2 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_to_proc.rb b/bin/gems/facets-3.1.0/test/core/hash/test_to_proc.rb new file mode 100644 index 00000000..c73738d1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_to_proc.rb @@ -0,0 +1,23 @@ +covers 'facets/hash/to_proc' + +test_case Hash do + + method :to_proc do + + test do + c = Class.new do + attr_accessor :a + end + + h = {:a => 1} + o = c.new + + h.to_proc.call(o) + + o.a.assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_to_struct.rb b/bin/gems/facets-3.1.0/test/core/hash/test_to_struct.rb new file mode 100644 index 00000000..68bd66c8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_to_struct.rb @@ -0,0 +1,22 @@ +covers 'facets/hash/to_struct' + +test_case Hash do + + method :to_struct do + + test do + h = {:name=>"Dan","age"=>33,"rank"=>"SrA","grade"=>"E4"} + s = h.to_struct("Foo") + + s.name.assert = "Dan" + s.age.assert = 33 + s.rank.assert = "SrA" + s.grade.assert = "E4" + + #Foo.assert.is_a?(Struct) ? + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_traverse.rb b/bin/gems/facets-3.1.0/test/core/hash/test_traverse.rb new file mode 100644 index 00000000..b1d01069 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_traverse.rb @@ -0,0 +1,29 @@ +covers 'facets/hash/traverse' + +test_case Hash do + + method :traverse do + + test do + h = { "A" => "x", "B" => "y" } + j = h.traverse{ |k,v| [k.downcase, v.upcase] } + x = { "a" => "X", "b" => "Y" } + j.refute == h + j.assert == x + end + + end + + method :traverse! do + + test do + h = { "A" => "x", "B" => "y" } + h.traverse!{ |k,v| [k.downcase, v.upcase] } + x = { "a" => "X", "b" => "Y" } + h.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_update_each.rb b/bin/gems/facets-3.1.0/test/core/hash/test_update_each.rb new file mode 100644 index 00000000..a8d1a159 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_update_each.rb @@ -0,0 +1,16 @@ +covers 'facets/hash/update_each' + +test_case Hash do + + method :update_each do + + test do + a = { :a => 1, :b => 2, :c => 3 } + x = { :a => 2, :b => 3, :c => 4 } + a.update_each{ |k,v| { k => v+1 } } + a.assert == x + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_update_keys.rb b/bin/gems/facets-3.1.0/test/core/hash/test_update_keys.rb new file mode 100644 index 00000000..334f617b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_update_keys.rb @@ -0,0 +1,21 @@ +covers 'facets/hash/update_keys' + +test_case Hash do + + method :update_keys do + + test do + h = { 'A' => 1, 'B' => 2 } + h.update_keys{ |k| k.downcase } + h.assert == {'a' => 1, 'b' => 2} + end + + test do + h = { :a => 1, :b => 2 } + h.update_keys{ |k| "#{k}!" } + h.assert == {'a!' => 1, 'b!' => 2} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_update_values.rb b/bin/gems/facets-3.1.0/test/core/hash/test_update_values.rb new file mode 100644 index 00000000..2758b710 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_update_values.rb @@ -0,0 +1,15 @@ +covers 'facets/hash/update_values' + +test_case Hash do + + method :update_values do + + test do + h = {1 => 'A', 2 => 'B'} + h.update_values{ |v| v.downcase } + h.assert == {1 => 'a', 2 => 'b'} + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_weave.rb b/bin/gems/facets-3.1.0/test/core/hash/test_weave.rb new file mode 100644 index 00000000..7f0769ed --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_weave.rb @@ -0,0 +1,18 @@ +covers 'facets/hash/weave' + +test_case Hash do + + method :weave do + + test do + b = { :a=>1, :b=>[1,2,3], :c=>{ :x=>'X' } } + c = { :a=>2, :b=>[4,5,6], :c=>{ :x=>'A', :y => 'B' } } + x = { :a=>2, :b=>[1,2,3,4,5,6], :c=>{ :x => 'A', :y => 'B' } } + b.weave(c).assert == x + end + + end + +end + + diff --git a/bin/gems/facets-3.1.0/test/core/hash/test_zip.rb b/bin/gems/facets-3.1.0/test/core/hash/test_zip.rb new file mode 100644 index 00000000..035b376e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/hash/test_zip.rb @@ -0,0 +1,16 @@ +covers 'facets/hash/zip' + +test_case Hash do + + class_method :zip do + + test do + a = [1,2,3] + b = [4,5,6] + Hash.zip(a,b).assert == {1=>4,2=>5,3=>6} + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/indexable_tc.rb b/bin/gems/facets-3.1.0/test/core/indexable_tc.rb new file mode 100644 index 00000000..f18eaa20 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/indexable_tc.rb @@ -0,0 +1,226 @@ +covers 'facets/indexable' +covers 'facets/array/indexable' + +test_case Indexable do + + method :head do + test do + [1,2,3].head.assert == [1] + end + end + + method :tail do + test do + [1,2,3].tail.assert == [2,3] + end + end + + method :foot do + test do + [1,2,3].foot.assert == [3] + end + end + + method :body do + test do + [1,2,3].body.assert == [1,2] + end + end + + method :mid do + test do + %w{W o r l d}.mid.assert == 'r' + %w{W o r l d}.mid(1).assert == 'l' + %w{W o r l d}.mid(-1).assert == 'o' + end + end + + method :mid do + test do + a = [1,2,3,4,5] + b = [1,2,3,4,5,6] + a.mid.assert == 3 + b.mid.assert == 4 + a.mid(1).assert == 4 + b.mid(1).assert == 5 + b.mid(2).assert == 6 + b.mid(-1).assert == 3 + end + end + + method :middle do + test do + [1,2,3,4,5].middle.assert == [3] + [1,2,3,4,5,6].middle.assert == [3,4] + end + end + + method :middle do + test do + %w{W o r l d}.middle.assert == ['r'] + %w{W o r l d y}.middle.assert == ['r', 'l'] + end + end + + method :middle do + test do + [1,2,3,4,5].middle(1).assert == [2,3,4] + [1,2,3,4,5,6].middle(1).assert == [2,3,4,5] + end + end + + method :from do + test do + %w{W o r l d}.from(3).assert == %w{l d} + end + end + + method :thru do + test "single parameter" do + a = [1,2,3,4,5] + r = a.thru(3) + r.assert == [1,2,3,4] + end + + test "dual parameter" do + a = [1,2,3,4,5] + r = a.thru(3,4) + r.assert == [4,5] + end + + test do + [0,1,2,3,4,5].thru(2,4).assert == [2,3,4] + [0,1,2,3,4,5].thru(0,1).assert == [0,1] + end + end + + # to be deprecated + method :index_of do + test do + [1,2,3,4].index_of{ |e| e == 3 }.assert == 2 + [1,2,3,4].index_of{ |e| e > 3 }.assert == 3 + end + end + + method :first= do + test do + a = [1,2,3] + a.first = 9 + a.assert == [9,2,3] + end + end + + method :last= do + test do + a = [1,2,3] + a.last = 9 + a.assert == [1,2,9] + end + end + + method :ends do + test do + [1,2,3,4,5].ends.assert == 4 + end + end + + method :pos do + test do + [1,2,3,4,5].pos(1).assert == 0 + [1,2,3,4,5].pos(-1).assert == 4 + end + end + + method :range do + test do + ['a','b','c','d'].range.assert == (0..3) + ['a','b','c','d'].range('b','d').assert == (1..3) + end + end + + method :range do + test do + a = [1,2,3,4,5] + b = [1,2,3,4,5,6] + a.range.assert == (0..4) + b.range.assert == (0..5) + a.range(2,4).assert == (1..3) + b.range(2,3).assert == (1..2) + b.range(4,2).assert == (3..1) + end + end + + # We can't use an Array to test the following methods b/c + # Array handles them specially, either for efficency reasons, + # or becuase the have been added to Ruby as of 1.8.7+. + + setup "special Indexable object" do + @c = Class.new do + include Indexable + def initialize(*a); @a = a; end + def slice(*a) ; @a.slice(*a) ; end + def splice(*a) ; @a.splice(*a) ; end + def size ; @a.size ; end + def to_a ; @a ; end + end + end + + method :first do + test do + a = @c.new(1,2,3,4,5) + r = a.first(3) + r.assert == [1,2,3] + end + end + + method :last do + test do + a = @c.new(1,2,3,4,5) + r = a.last(3) + r.assert == [3,4,5] + end + end + + method :first! do + test do + a = @c.new(1,2,3,4,5) + e = a.first! + e.assert == 1 + a.to_a.assert == [2,3,4,5] + end + end + + method :last! do + test do + a = @c.new(1,2,3,4,5) + e = a.last! + e.assert == 5 + a.to_a.assert == [1,2,3,4] + end + end + + method :index do + test do + @c.new(1,2,3,4).index{ |e| e == 3 }.assert == 2 + @c.new(1,2,3,4).index{ |e| e > 3 }.assert == 3 + end + end + + #method :[] do + # test do + # a = ['a','b','c','d','e','f'] + # assert_equal( ['b','f'], a[[1,-1]] ) + # end + #end + + #method :[]= do + # test do + # a = ['a','o','z'] + # a[[0,2]] = ['A','Z'] + # assert_equal( ['A','o','Z'], a ) + # a[[0,-1]] = ['W','Y'] + # assert_equal( ['W','o','Y'], a ) + # end + #end + +end diff --git a/bin/gems/facets-3.1.0/test/core/integer/test_bitmask.rb b/bin/gems/facets-3.1.0/test/core/integer/test_bitmask.rb new file mode 100644 index 00000000..151e2219 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/integer/test_bitmask.rb @@ -0,0 +1,73 @@ +covers 'facets/integer/bitmask' + +test_case Integer do + + method :bit do + test do + 0.bit(0).assert == 1 + 0.bit(1).assert == 2 + 0.bit(2).assert == 4 + 0.bit(3).assert == 8 + end + end + + method :bit do + test "negate" do + 1.bit(~0).assert == 0 + 2.bit(~1).assert == 0 + 4.bit(~2).assert == 0 + 8.bit(~3).assert == 0 + end + end + + method :bit_clear do + test do + 1.bit_clear(0).assert == 0 + 2.bit_clear(1).assert == 0 + 4.bit_clear(2).assert == 0 + 8.bit_clear(3).assert == 0 + end + end + + method :bit? do + test do + a = 8 + assert(! a.bit?(0)) + assert(! a.bit?(1)) + assert(! a.bit?(2)) + assert( a.bit?(3)) + assert(! a.bit?(4)) + assert(! a.bit?(5)) + end + end + + method :bitmask do + test do + a = 1 + m = Bit(4) + a = a.bitmask(m) + a.assert == 17 + assert( a.bitmask?(m) ) + end + end + + method :bitmask? do + test do + 7.assert.bitmask?(7) + 7.assert.bitmask?(5) + 8.refute.bitmask?(3) + end + end + +end + +test_case Kernel do + + method :Bit do + test do + n = Bit(4) + n.assert == 16 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/integer/test_factorial.rb b/bin/gems/facets-3.1.0/test/core/integer/test_factorial.rb new file mode 100644 index 00000000..987633ec --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/integer/test_factorial.rb @@ -0,0 +1,30 @@ +covers 'facets/integer/factorial' + +test_case Integer do + + method :factorial do + + test do + 0.factorial.assert == 1 + 1.factorial.assert == 1 + 2.factorial.assert == 2 + 3.factorial.assert == 6 + 4.factorial.assert == 24 + end + + end + + method :fac do + + test do + 0.fac.assert == 1 + 1.fac.assert == 1 + 2.fac.assert == 2 + 3.fac.assert == 6 + 4.fac.assert == 24 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/integer/test_multiple.rb b/bin/gems/facets-3.1.0/test/core/integer/test_multiple.rb new file mode 100644 index 00000000..153f1179 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/integer/test_multiple.rb @@ -0,0 +1,16 @@ +covers 'facets/integer/multiple' + +test_case Integer do + + method :multiple? do + + test do + assert( ! 1.multiple?(2) ) + assert( 2.multiple?(2) ) + assert( ! 5.multiple?(3) ) + assert( 6.multiple?(3) ) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/integer/test_of.rb b/bin/gems/facets-3.1.0/test/core/integer/test_of.rb new file mode 100644 index 00000000..9325a57e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/integer/test_of.rb @@ -0,0 +1,36 @@ +covers 'facets/integer/of' + +test_case Integer do + + method :of do + + test do + a = 4 + b = a.of{ |i| i*2 } + b.assert == [0,2,4,6] + end + + end + + method :times_collect do + + test do + a = 4 + b = a.times_collect{ |i| i*2 } + b.assert == [0,2,4,6] + end + + end + + method :times_map do + + test do + a = 4 + b = a.times_map{ |i| i*2 } + b.assert == [0,2,4,6] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/integer/test_ordinal.rb b/bin/gems/facets-3.1.0/test/core/integer/test_ordinal.rb new file mode 100644 index 00000000..8e76c916 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/integer/test_ordinal.rb @@ -0,0 +1,27 @@ +covers 'facets/integer/ordinal' + +test_case Integer do + + method :ordinal do + + test do + 1.ordinal.assert == '1st' + 2.ordinal.assert == '2nd' + 3.ordinal.assert == '3rd' + 4.ordinal.assert == '4th' + end + + end + + method :ordinalize do + + test do + 1.ordinalize.assert == '1st' + 2.ordinalize.assert == '2nd' + 3.ordinalize.assert == '3rd' + 4.ordinalize.assert == '4th' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_as.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_as.rb new file mode 100644 index 00000000..ce9b9724 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_as.rb @@ -0,0 +1,74 @@ +covers 'facets/kernel/as' + +test_case Kernel do + + setup "class heirarchy" do + a = Class.new do + def x; "a.x"; end + def y; "a.y"; end + end + b = Class.new(a) do + def x; "b.x" end + def y; "b.y" end + end + c = Class.new(b) do + def x; "c.x"; end + define_method(:y){ as(a).x } + end + @a, @b, @c = a, b, c + end + + method :as do + + test do + o = @c.new + o.x.assert == "c.x" + o.y.assert == "a.x" + end + + end + + method :send_as do + + test do + s = "a" + def s.class; nil; end + s.class.refute == String + s.send_as(Object, :class).assert == String + end + + end + + #setup "class heirarchy" do + # x = Class.new{ def x ; 1 ; end } + # y = Class.new(x){ def x ; 2 ; end } + # z = Class.new(y){ define_method(:x){ super_as(x) } } + # z + #end + + #method :super_as do |z| + # o = z.new + # o.x.assert == 1 + #end + +end + +test_case As do + + class_method :new do + + setup do + @c = Class.new(String) do + def to_s; "denied"; end + end + end + + test do + o = @c.new("hi") + o.to_s.assert == "denied" + As.new(o, String).to_s.assert == "hi" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_ask.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_ask.rb new file mode 100644 index 00000000..fc72e651 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_ask.rb @@ -0,0 +1,9 @@ +covers 'facets/kernel/ask' + +test_case Kernel do + + # requires user input + method :ask do + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_assign.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_assign.rb new file mode 100644 index 00000000..20a1fc4e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_assign.rb @@ -0,0 +1,61 @@ +covers 'facets/kernel/assign' + +test_case Kernel do + + method :assign do + + setup do + @c = Struct.new(:name, :address, :zip) + end + + test "with arguments" do + bob = @c.new + + bob.assign(:name, "Bob Sawyer") + bob.assign(:address, "123 Maple, Anytown NC") + bob.assign(:zip, 12345) + + bob.name.assert == "Bob Sawyer" + bob.address.assert == "123 Maple, Anytown NC" + bob.zip.assert == 12345 + end + + test "with hash" do + bob = @c.new + + x = { :name => "Bob Sawyer", :address => "123 Maple, Anytown NC", :zip => 12345 } + + bob.assign(x) + + bob.name.assert == x[:name] + bob.address.assert == x[:address] + bob.zip.assert == x[:zip] + end + + test "with associative array" do + bob = @c.new + + x = [[:name, "Bob Sawyer"], [:address, "123 Maple, Anytown NC"], [:zip, 12345]] + + bob.assign(x) + + bob.name.assert == "Bob Sawyer" + bob.address.assert == "123 Maple, Anytown NC" + bob.zip.assert == 12345 + end + + #test "with block" do + # bob = @c.new + # + # x = lambda {|s| s.name = "Bob Sawyer"; s.address = "123 Maple, Anytown NC"; s.zip = 12345 } + # + # bob.assign(&x) + # + # bob.name.assert == "Bob Sawyer" + # bob.address.assert == "123 Maple, Anytown NC" + # bob.zip.assert == 12345 + #end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_assign_from.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_assign_from.rb new file mode 100644 index 00000000..7e3d6015 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_assign_from.rb @@ -0,0 +1,48 @@ +covers 'facets/kernel/assign_from' + +test_case Kernel do + + c = Struct.new(:name, :address, :zip) + + method :assign_from do + + test do + bob = c.new("Bob Sawyer", "123 Maple, Anytown NC", 12345) + joe = c.new("Joe Pitare") + + joe.assign_from(bob, :address, :zip) + + joe.name.assert == "Joe Pitare" + joe.address. == "123 Maple, Anytown NC" + joe.zip.assert == 12345 + end + + end + + method :assign_from do + + c1 = Class.new do + attr_accessor :a + attr_accessor :b + end + + c2 = Class.new do + attr_accessor :a + attr_accessor :b + end + + test do + o1 = c1.new + o1.a = 1 + o1.b = 2 + + o2 = c2.new + o2.assign_from(o1, :a, :b) + + o2.a.assert == 1 + o2.b.assert == 2 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_attr_singleton.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_attr_singleton.rb new file mode 100644 index 00000000..34ae2ee8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_attr_singleton.rb @@ -0,0 +1,51 @@ +covers 'facets/kernel/attr_singleton' + +test_case Kernel do + + c = Class.new do + def initialize + attr_singleton_reader :foo #=> "FOO" + attr_singleton_writer :bar #=> "BAR" + attr_singleton_accessor :baz #=> "BAZ" + @foo = "FOO" + self.bar = "BAR" + self.baz = "BAZ" + end + def get_bar + @bar + end + end + + method :attr_singleton_reader do + + test do + t = c.new + t.foo.assert == "FOO" + end + + end + + method :attr_singleton_writer do + + test do + t = c.new + t.get_bar.assert == "BAR" + t.bar = "BAR2" + t.get_bar.assert == "BAR2" + end + + end + + method :attr_singleton_accessor do + + test do + t = c.new + t.baz.assert == "BAZ" + t.baz = "BAZ2" + t.baz.assert == "BAZ2" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_blank.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_blank.rb new file mode 100644 index 00000000..843de906 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_blank.rb @@ -0,0 +1,103 @@ +covers 'facets/kernel/blank' + +# NOTE: Using x.assert.blank? here caused AE some issues +# b/c of problems with Assertor. Basically Assertor needs +# to subclass BasicObject, but Ruby 1.9 has constant lookup +# issues with BasicObject that need address. So in this case +# we'll just use the old-school `assert foo` syntax. + +test_case Kernel do + + method :blank? do + test do + refute Object.new.blank? + end + end + +end + +test_case NilClass do + + method :blank? do + test do + assert nil.blank? + end + end + +end + +test_case FalseClass do + + method :blank? do + test do + assert false.blank? + end + end + +end + +test_case TrueClass do + + method :blank? do + test do + refute true.blank? + end + end + +end + +test_case Array do + + method :blank? do + test do + assert [].blank? + refute [1].blank? + end + end + +end + +test_case Hash do + + method :blank? do + test do + assert( {}.blank? ) + refute( {:a=>1}.blank? ) + end + end + +end + +test_case String do + + method :blank? do + test do + refute "xyz".blank? + assert " ".blank? + end + end + +end + +test_case Numeric do + + method :blank? do + test do + refute 0.blank? + end + end + + method :blank? do + test do + refute 10.blank? + end + end + + method :blank? do + test do + refute 10.0.blank? + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_callstack.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_callstack.rb new file mode 100644 index 00000000..3c4f06f0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_callstack.rb @@ -0,0 +1,21 @@ +covers 'facets/kernel/callstack' + +test_case Kernel do + + method :call_stack do + + test do + call_stack + end + + end + + method :callstack do + + test do + callstack + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_class.rb new file mode 100644 index 00000000..90f2155a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_class.rb @@ -0,0 +1,14 @@ +covers 'facets/kernel/__class__' + +test_case Kernel do + + method :__class__ do + + test do + o = Object.new + o.__class__.assert == o.class + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_complete.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_complete.rb new file mode 100644 index 00000000..31490b2f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_complete.rb @@ -0,0 +1,19 @@ +covers 'facets/kernel/complete' + +test_case Kernel do + + method :complete do + + test do + a = [] + i = 0 + complete do + i += 1 + i == 3 ? nil : a << i + end + a.assert == [1,2] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_constant.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_constant.rb new file mode 100644 index 00000000..0b68335a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_constant.rb @@ -0,0 +1,18 @@ +covers 'facets/kernel/constant' + +test_case Kernel do + + method :constant do + + test do + c = ::Lemon::TestCase.name + constant(c).assert == ::Lemon::TestCase + + c = "TestCase" + ::Lemon.constant(c).assert == ::Lemon::TestCase + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_d.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_d.rb new file mode 100644 index 00000000..28fa707d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_d.rb @@ -0,0 +1,10 @@ +covers 'facets/kernel/d' + +test_case Kernel do + + # TODO: how to test #d silently? Need to redirect $stderr. + + method :d do + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_deep_clone.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_deep_clone.rb new file mode 100644 index 00000000..b1d53489 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_deep_clone.rb @@ -0,0 +1,31 @@ +covers 'facets/kernel/deep_clone' + +test_case Kernel do + + method :deep_clone do + + setup "a class with reference to another class" do + xC = Class.new do + attr_reader :x + def initialize + @x = 1 + end + end + + @c = Class.new do + attr_reader :y + define_method(:initialize) do + @y = xC.new + end + end + end + + test do + o = @c.new + d = o.deep_clone + d.y.x.assert == 1 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_deep_copy.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_deep_copy.rb new file mode 100644 index 00000000..1d1a6bad --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_deep_copy.rb @@ -0,0 +1,15 @@ +covers 'facets/kernel/deep_copy' + +test_case Kernel do + + method :deep_copy do + + test do + o = "This is a weak test." + d = o.deep_copy + d.assert == "This is a weak test." + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_dir.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_dir.rb new file mode 100644 index 00000000..e67d2ca1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_dir.rb @@ -0,0 +1,24 @@ +covers 'facets/kernel/__dir__' + +test_case Kernel do + + # TODO: can't test b/c somehow Lemon intefers with the call stack + # which __DIR__ uses to locate the current running file. + + method :__DIR__ do + + omit "issue with call stack" do + + test "relative directory" do + __DIR__.assert == File.dirname(__FILE__) + end + + test "relative directory joins with arguments" do + __DIR__('tmp').assert == File.join(File.dirname(__FILE__), 'tmp') + end + + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_disable_warnings.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_disable_warnings.rb new file mode 100644 index 00000000..97122ba0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_disable_warnings.rb @@ -0,0 +1,38 @@ +covers 'facets/kernel/disable_warnings' +covers 'facets/kernel/enable_warnings' +covers 'facets/kernel/silence_warnings' + +test_case Kernel do + + method :disable_warnings do + + test do + disable_warnings do + assert( ! $VERBOSE ) + end + end + + end + + method :silence_warnings do + + test "alias for backward compatibility" do + silence_warnings do + assert( ! $VERBOSE ) + end + end + + end + + method :enable_warnings do + + test :enable_warnings do + enable_warnings do + assert( $VERBOSE ) + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_ergo.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_ergo.rb new file mode 100644 index 00000000..8695b1de --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_ergo.rb @@ -0,0 +1,34 @@ +covers 'facets/kernel/ergo' + +test_case Kernel do + + method :ergo do + + test do + "a".ergo.upcase.assert == "A" + nil.ergo.foobar.assert == nil + + end + + test do + "a".ergo { |o| o.upcase }.assert == "A" + nil.ergo { |o| o.foobar }.assert == nil + end + + end + +end + +test_case NilClass do + + method :ergo do + + test do + "a".ergo { |o| o.upcase }.assert == "A" + nil.ergo { |o| o.bar }.assert == nil + nil.ergo.ergo { |o| o.bar }.assert == nil + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_extension.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_extension.rb new file mode 100644 index 00000000..cf3021ad --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_extension.rb @@ -0,0 +1,18 @@ +covers 'facets/kernel/extension' + +test_case Kernel do + + # DEPRECATE ? + method :extension do + + test do + c = Class.new + o = c.new + x = (class << o; self; end) + o.extension.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_get.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_get.rb new file mode 100644 index 00000000..97477276 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_get.rb @@ -0,0 +1,54 @@ +covers 'facets/kernel/__get__' +covers 'facets/kernel/__set__' + +test_case Kernel do + + method :__get__ do + + setup "an object with an instance variable" do + c = Class.new do + attr :a + def initialize + @a = 1 + end + end + @o = c.new + end + + test do + @o.__get__('@a').assert == 1 + end + + # TODO: support is being considered + #test "wihtout at-sign" do |o| + # o.__get__(:a).assert == 1 + #end + + end + + method :__set__ do + + setup "an object with an instance variable" do + c = Class.new do + attr :a + def initialize + @a = 1 + end + end + @o = c.new + end + + test do + @o.__set__('@a', 2) + @o.a.assert == 2 + end + + # TODO: support is being considered + #test "without at-sign" do + # @o.__set__(:a, 3) + # @o.a.assert == 3 + #end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_here.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_here.rb new file mode 100644 index 00000000..07682f9c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_here.rb @@ -0,0 +1,13 @@ +covers 'facets/kernel/here' + +test_case Kernel do + + method :here do + + test do + here.assert.is_a?(Binding) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_hierarchical_send.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_hierarchical_send.rb new file mode 100644 index 00000000..860ec4f0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_hierarchical_send.rb @@ -0,0 +1,48 @@ +require 'facets/kernel/hierarchical_send' + +test_case Object do + + setup do + m = Module.new do + attr :a + def preinitialize + @a = 10 + end + end + + @x = Class.new do + include m + attr :b + def preinitialize + @b = 20 + end + def initialize + hierarchical_send(:preinitialize) + end + end + + @y = Class.new(@x) do + def initialize + @a = "not 10" + @b = "not 20" + super + end + end + end + + method :hierarchical_send do + test do + x = @x.new + x.a.assert == 10 + x.b.assert == 20 + end + + test 'subclass' do + y = @y.new + y.a.assert == 10 + y.b.assert == 20 + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_in.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_in.rb new file mode 100644 index 00000000..673bef29 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_in.rb @@ -0,0 +1,14 @@ +covers 'facets/kernel/in' + +test_case Kernel do + + method :in? do + + test do + 5.assert.in?(0..10) + 5.assert.in?([1,2,3,4,5]) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_instance_assign.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_assign.rb new file mode 100644 index 00000000..21f9caa0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_assign.rb @@ -0,0 +1,19 @@ +covers 'facets/kernel/instance_assign' + +test_case Kernel do + + method :instance_assign do + + test do + ahash = { "z"=>0, "@a"=>1, "@b"=>2 } #, "@@a"=>3 } + instance_assign(ahash) + @z.assert == 0 + @a.assert == 1 + @b.assert == 2 + #@@a.assert == 3 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_instance_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_class.rb new file mode 100644 index 00000000..c834359d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_class.rb @@ -0,0 +1,15 @@ +covers 'facets/kernel/instance_class' + +test_case Kernel do + + method :instance_class do + + test do + o = Object.new + o.instance_class.assert == (class << o; self; end) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_instance_extract.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_extract.rb new file mode 100644 index 00000000..0d276b5d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_extract.rb @@ -0,0 +1,28 @@ +covers 'facets/kernel/instance_extract' + +test_case Kernel do + + method :instance_extract do + + test "extracts hash into object" do + c = Class.new do + def initialize + @cmd='cls' + end + def cmd + @cmd + end + def page + @page + end + end + + o = c.new + o.instance_extract('cmd'=>'hello','page'=>'frontpage') + o.cmd.assert == 'cls' + o.page.assert == 'frontpage' + end + + end + + end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_instance_replace.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_replace.rb new file mode 100644 index 00000000..1d3700f5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_replace.rb @@ -0,0 +1,47 @@ +covers 'facets/kernel/instance_replace' +test_case Kernel do + + method :instance_replace do + + test "must be the same type" do + c = Class.new do + attr_reader :a, :b + def initialize(a,b) + @a, @b = a, b + end + end + + o = c.new(1,2) + o.a.assert == 1 + o.b.assert == 2 + + # TODO: TypeError ? + expect ArgumentError do + o.instance_replace(:a=>3, :b=>4) + end + end + + test do + c = Class.new do + attr :name + attr :age + def initialize(name, age) + @name, @age = name, age + end + end + + a = c.new('bob', 60) + a.name.assert == 'bob' + a.age.assert == 60 + + b = c.new('tom', 40) + + a.instance_replace(b) + + a.name.assert == 'tom' + a.age.assert == 40 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_instance_send.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_send.rb new file mode 100644 index 00000000..27c560e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_instance_send.rb @@ -0,0 +1,26 @@ +covers 'facets/kernel/instance_send' + +test_case Kernel do + + method :instance_send do + + test "alias for #send" do + c = Class.new do + def x; "x"; end + private + def y; "y"; end + end + + o = c.new + + expect NoMethodError do + o.y + end + + o.instance_send(:x).assert == "x" + o.instance_send(:y).assert == "y" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_maybe.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_maybe.rb new file mode 100644 index 00000000..8566ce76 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_maybe.rb @@ -0,0 +1,13 @@ +covers 'facets/kernel/maybe' + +test_case Kernel do + + method :maybe do + + test do + maybe + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_meta_alias.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_alias.rb new file mode 100644 index 00000000..e46a0322 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_alias.rb @@ -0,0 +1,18 @@ +covers 'facets/kernel/meta_alias' + +test_case Kernel do + + method :meta_alias do + + test do + c = Class.new do + def self.y?; "y?" ; end + end + c.meta_alias "ynot?", "y?" + c.ynot?.assert == "y?" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_meta_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_class.rb new file mode 100644 index 00000000..03cdd9cb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_class.rb @@ -0,0 +1,33 @@ +covers 'facets/kernel/meta_class' + +test_case Kernel do + + method :meta_class do + + test do + x = Class.new + m = (class << x; self; end) + x.meta_class.assert == m + end + + test "class_eval block on meta class" do + c = Class.new + c.meta_class do + def foo; "foo"; end + end + c.foo.assert == "foo" + end + + end + + method :metaclass do + + test do + x = Class.new + m = (class << x; self; end) + x.metaclass.assert == m + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_meta_def.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_def.rb new file mode 100644 index 00000000..0cb5a311 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_def.rb @@ -0,0 +1,15 @@ +covers 'facets/kernel/meta_def' + +test_case Kernel do + + method :meta_def do + + test do + x = Class.new + x.meta_def(:x){"x"} + x.x.assert == "x" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_meta_eval.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_eval.rb new file mode 100644 index 00000000..792ea411 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_meta_eval.rb @@ -0,0 +1,18 @@ +covers 'facets/kernel/meta_eval' + +test_case Kernel do + + method :meta_eval do + + test do + o = Object.new + o.meta_eval do + @y = "y" + end + o.instance_variable_get("@y").refute == "y" + (class << o; self; end).instance_variable_get("@y").assert == "y" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_method.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_method.rb new file mode 100644 index 00000000..591934b4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_method.rb @@ -0,0 +1,20 @@ +covers 'facets/kernel/method' + +test_case Kernel do + + method :method! do + + test do + c = Class.new do + def foo ; 'foo' ; end + end + + ic = c.new + ic.method(:foo).__id__.refute == ic.method(:foo).__id__ + ic.method!(:foo).__id__.assert == ic.method!(:foo).__id__ + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_not.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_not.rb new file mode 100644 index 00000000..875761ad --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_not.rb @@ -0,0 +1,51 @@ +covers 'facets/kernel/not' + +test_case Kernel do + + method :not? do + + test do + b = true + b.not?.assert == !b + end + + test :not? do + b = false + b.not?.assert == !b + end + + test :not? do + b = nil + b.not?.assert == !b + end + + test :not? do + b = Object.new + b.not?.assert == !b + end + + end + + method :not do + + test do + b = true + r = b.not.nil? + r.assert == true + end + + test :not do + b = false + r = b.not.nil? + r.assert == true + end + + test :not do + b = nil + r = b.not.nil? + r.assert == false + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_not_nil.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_not_nil.rb new file mode 100644 index 00000000..271caa73 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_not_nil.rb @@ -0,0 +1,25 @@ +covers 'facets/kernel/not_nil' + +test_case Kernel do + + method :not_nil? do + + test do + 5.assert.not_nil? + end + + test do + :x.assert.not_nil? + end + + test do + false.assert.not_nil? + end + + test do + nil.refute.not_nil? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_object_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_object_class.rb new file mode 100644 index 00000000..ed253bae --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_object_class.rb @@ -0,0 +1,22 @@ +covers 'facets/kernel/object_class' +covers 'facets/kernel/__class__' + +test_case Kernel do + + method :object_class do + + test do + self.object_class.assert == self.class + end + + end + + method :__class__ do + + test do + self.__class__.assert == self.class + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_object_hexid.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_object_hexid.rb new file mode 100644 index 00000000..03be41cc --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_object_hexid.rb @@ -0,0 +1,20 @@ +covers 'facets/kernel/object_hexid' + +test_case Kernel do + + method :object_hexid do + + omit "too inconsitent across platforms" do + + test do + o = Object.new + "#".assert == o.inspect + #assert(o.inspect.index(o.object_hexid)) + end + + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_object_send.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_object_send.rb new file mode 100644 index 00000000..34471c3e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_object_send.rb @@ -0,0 +1,25 @@ +covers 'facets/kernel/object_send' + +test_case Kernel do + + method :object_send do + + test "same as #public_send of Ruby 1.9+" do + c = Class.new do + def x; "x"; end + private + def y; "y"; end + end + + o = c.new + + o.object_send(:x).assert == "x" + + expect NoMethodError do + o.object_send(:y) + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_presence.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_presence.rb new file mode 100644 index 00000000..4bd97058 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_presence.rb @@ -0,0 +1,37 @@ +covers 'facets/kernel/presence' + +test_case Kernel do + + method :presence do + + test do + "a".presence.assert == "a" + [1].presence.assert == [1] + {:a=>1}.presence.assert == {:a=>1} + end + + test do + "".presence.assert == nil + [].presence.assert == nil + {}.presence.assert == nil + end + + end + + method :present? do + + test "non-empty objects are present" do + "a".assert.present? + [1].assert.present? + {:a=>1}.assert.present? + end + + test "empty object are not present" do + "".refute.present? + [].refute.present? + {}.refute.present? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_qua_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_qua_class.rb new file mode 100644 index 00000000..8197b1c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_qua_class.rb @@ -0,0 +1,25 @@ +covers 'facets/kernel/qua_class' + +test_case Kernel do + + method :qua_class do + + test do + o = Object.new + s = (class << o; self; end) + o.qua_class.assert == s + end + + end + + method :quaclass do + + test do + o = Object.new + s = (class << o; self; end) + o.quaclass.assert == s + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_require_all.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_require_all.rb new file mode 100644 index 00000000..a8cf253c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_require_all.rb @@ -0,0 +1,11 @@ +covers 'facets/kernel/require_all' + +test_case Kernel do + + method :require_all do + end + + method :load_all do + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_respond.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_respond.rb new file mode 100644 index 00000000..5c32ef4d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_respond.rb @@ -0,0 +1,38 @@ +covers 'facets/kernel/respond' + +test_case Kernel do + + method :respond do + + test do + c = Class.new do + def f; "f"; end + end + + x = c.new + x.respond(:f).assert == "f" + x.respond(:g).assert == nil + + x.respond.f.assert == "f" + x.respond.g.assert == nil + end + + end + + # + #method :respond_with_value do + # test do + # c = Class.new do + # def f; "f"; end + # end + # + # x = c.new + # x.respond_with_value(:f).assert == "f" + # x.respond_with_value(:g).assert == nil + # + # x.respond_with_value.f.assert == "f" + # x.respond_with_value.g.assert == nil + # end + #end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_returning.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_returning.rb new file mode 100644 index 00000000..89ae859a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_returning.rb @@ -0,0 +1,17 @@ +covers 'facets/kernel/returning' + +test_case Kernel do + + method :returning do + + test do + foo = returning( values = [] ) do + values << 'bar' + values << 'baz' + end + foo.assert == ['bar', 'baz'] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_silence.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_silence.rb new file mode 100644 index 00000000..24556813 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_silence.rb @@ -0,0 +1,24 @@ +covers 'facets/kernel/silence' + +test_case Kernel do + + # TODO: figure out how to test silence methods + + concern "Not straight foward to test since they effect output." + + method :silence do + end + + method :silence_stream do + end + + method :silence_stderr do + end + + method :silence_stdout do + end + + method :silently do + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_singleton_class.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_singleton_class.rb new file mode 100644 index 00000000..2aed8bec --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_singleton_class.rb @@ -0,0 +1,15 @@ +covers 'facets/kernel/singleton_class' + +test_case Kernel do + + method :singleton_class do + + test do + x = Class.new + m = (class << x; self; end) + x.singleton_class.assert == m + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_super_method.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_super_method.rb new file mode 100644 index 00000000..a662c229 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_super_method.rb @@ -0,0 +1,23 @@ +covers 'facets/kernel/super_method' + +test_case Kernel do + + method :super_method do + + setup "class heirarchy" do + @x = Class.new{ def x ; 1 ; end } + @y = Class.new(@x){ def x ; 2 ; end } + @z = Class.new(@y){ def x ; 3 ; end } + end + + test do + x = @x.new + z = @z.new + s0 = x.method(:x) + s1 = z.super_method(@x, :x) + s1.call.assert == s0.call + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_tap.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_tap.rb new file mode 100644 index 00000000..a92338e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_tap.rb @@ -0,0 +1,38 @@ +covers 'facets/kernel/tap' + +test_case Kernel do + + method :tap do + + test do + e = "foo" + r = "foobar".tap{ |x| x.gsub!(/bar/, '') } + r.assert == e + end + + test "check internal value" do + x = [1,2,3] + x.tap{ |a| + a.assert == x + } + end + + test "assign via tap block" do + bob = Struct.new(:name, :address, :zip).new + + x = lambda do |s| + s.name = "Bob Sawyer" + s.address = "123 Maple, Anytown NC" + s.zip = "12345" + end + + bob.tap(&x) + + bob.name.assert == "Bob Sawyer" + bob.address.assert == "123 Maple, Anytown NC" + bob.zip.assert == "12345" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_temporarily.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_temporarily.rb new file mode 100644 index 00000000..117423da --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_temporarily.rb @@ -0,0 +1,25 @@ +covers 'facets/kernel/temporarily' + +test_case Kernel do + + method :temporarily do + + test "global variable" do + $temporary_variable = true + temporarily('$temporary_variable'=>false) do + $temporary_variable.assert == false + end + $temporary_variable.assert == true + end + + test "instance variable" do + @x = 1 + temporarily('@x'=>2) do + @x.assert == 2 + end + @x.assert == 1 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_true.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_true.rb new file mode 100644 index 00000000..bb828785 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_true.rb @@ -0,0 +1,31 @@ +covers 'facets/kernel/true' + +test_case Kernel do + + method :true? do + + test "nothing is true? but true itself" do + true.assert.true? + + nil.refute.true? + false.refute.true? + 1.refute.true? + :a.refute.true? + end + + end + + method :false? do + + test "nothing is false? but false itself" do + false.assert.false? + + nil.refute.false? + true.refute.false? + 1.refute.false? + :a.refute.false? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_try.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_try.rb new file mode 100644 index 00000000..08a41e0a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_try.rb @@ -0,0 +1,35 @@ +covers 'facets/kernel/try' + +test_case Kernel do + + method :try do + + test do + example = Struct.new(:name).new("bob") + example.try(:name).assert == "bob" + end + + test "without argument" do + example = Struct.new(:name).new("bob") + example.try.name.assert == "bob" + end + + end + +end + +test_case NilClass do + + method :try do + + test do + nil.try(:name).assert == nil + end + + test "without argument" do + nil.try.name.assert == nil + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_val.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_val.rb new file mode 100644 index 00000000..f20e31a8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_val.rb @@ -0,0 +1,30 @@ +covers 'facets/kernel/val' + +test_case Kernel do + + method :val? do + + test "of nil" do + f = nil + t = 1 + f.refute.val? + t.assert.val? + end + + test "of empty array" do + f = [] + t = [1] + f.refute.val? + t.assert.val? + end + + test "of empty string" do + f = '' + t = '1' + f.refute.val? + t.assert.val? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_with.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_with.rb new file mode 100644 index 00000000..9fad0fa7 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_with.rb @@ -0,0 +1,18 @@ +covers 'facets/kernel/with' + +test_case Kernel do + + method :with do + + test do + with values = [] do + self << 'bar' + self << 'baz' + end + values.assert == ['bar', 'baz'] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/kernel/test_writers.rb b/bin/gems/facets-3.1.0/test/core/kernel/test_writers.rb new file mode 100644 index 00000000..b5b264d6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/kernel/test_writers.rb @@ -0,0 +1,53 @@ +covers 'facets/kernel/writers' + +test_case Kernel do + + method :writers do + + test do + c = Class.new do + attr_accessor :a + def b=(b); @b=b; end + end + o = c.new + w = o.writers + + w.assert.include?(:a=) + w.assert.include?(:b=) + end + + test do + c = Class.new do + attr_accessor :a + def b=(b); @b=b; end + private + def q=(q); @q=q; end + end + o = c.new + w = o.writers(:access=>:private) + + w.refute.include?(:a=) + w.refute.include?(:b=) + w.assert.include?(:q=) + end + + test do + c = Class.new do + attr_accessor :a + def b=(b); @b=b; end + private + def q=(q); @q=q; end + end + o = c.new + w = o.writers(:access=>:all) + + w.assert.include?(:a=) + w.assert.include?(:b=) + w.assert.include?(:q=) + end + + # TODO: Need to test more options for writers. + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/matchdata/test_match.rb b/bin/gems/facets-3.1.0/test/core/matchdata/test_match.rb new file mode 100644 index 00000000..21d1d089 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/matchdata/test_match.rb @@ -0,0 +1,14 @@ +covers 'facets/matchdata/match' + +test_case MatchData do + + method :match do + + test do + md = /X(a)(b)(c)X/.match("YXabcXY") + md.match.assert == "XabcX" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/matchdata/test_matchset.rb b/bin/gems/facets-3.1.0/test/core/matchdata/test_matchset.rb new file mode 100644 index 00000000..3c3e088c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/matchdata/test_matchset.rb @@ -0,0 +1,29 @@ +covers 'facets/matchdata/matchset' + +test_case MatchData do + + method :matchtree do + + test do + md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchtree.assert == [["bb"], ["cc", ["dd"]], ["ee"]] + end + + test do + md = /(bb)c(c(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchtree.assert == [["bb"], "c", ["c", ["dd"]], ["ee"]] + end + + end + + method :matchset do + + test do + md = /(bb)(cc(dd))(ee)/.match "XXaabbccddeeffXX" + md.matchset.assert == ["XXaa", [["bb"], ["cc", ["dd"]], ["ee"]], "ffXX"] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/method/test_composition.rb b/bin/gems/facets-3.1.0/test/core/method/test_composition.rb new file mode 100644 index 00000000..4e5e4098 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/method/test_composition.rb @@ -0,0 +1,42 @@ +covers 'facets/method/composition' + +test_case Method do + + c = Class.new do + def f(x); x * 3; end + def g(x); x + 1; end + end + + method :* do + + test do + x = c.new + f = x.method(:f) * x.method(:g) + f.call(1).assert == 6 + end + + test do + x = c.new + f = x.method(:g) * x.method(:f) + f.call(1).assert == 4 + end + + end + + method :^ do + + test do + x = c.new + f = x.method(:f) ^ 3 + f.call(1).assert == 27 + end + + test do + x = c.new + f = x.method(:g) ^ 3 + f.call(1).assert == 4 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_abstract.rb b/bin/gems/facets-3.1.0/test/core/module/test_abstract.rb new file mode 100644 index 00000000..27abda00 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_abstract.rb @@ -0,0 +1,24 @@ +covers 'facets/module/abstract' + +test_case Module do + + method :abstract do + + test "in a module" do + m = Module.new{ abstract :q } + c = Class.new{ include m } + x = c.new + TypeError.assert.raised?{ x.q } + end + + test "in a class" do + c = Class.new{ abstract :q } + #c.pry.abstract :q + x = c.new + TypeError.assert.raised?{ x.q } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_alias_accessor.rb b/bin/gems/facets-3.1.0/test/core/module/test_alias_accessor.rb new file mode 100644 index 00000000..338fc4c4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_alias_accessor.rb @@ -0,0 +1,27 @@ +covers 'facets/module/alias_accessor' + +test_case Module do + + method :alias_accessor do + + test do + c = Class.new do + attr_accessor :x + alias_accessor :y, :x + end + + x = c.new + + x.x = 10 + x.x.assert == 10 + x.y.assert == 10 + + x.y = 20 + x.x.assert == 20 + x.y.assert == 20 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_alias_method_chain.rb b/bin/gems/facets-3.1.0/test/core/module/test_alias_method_chain.rb new file mode 100644 index 00000000..cb13469a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_alias_method_chain.rb @@ -0,0 +1,34 @@ +covers 'facets/module/alias_method_chain' + +test_case Module do + + method :alias_method_chain do + + test do + x = Module.new do + def self.included(base) + base.module_eval { + alias_method_chain :foo, :feature + } + end + def foo_with_feature + foo_without_feature + '!' + end + end + + y = Class.new do + def foo + "FOO" + end + include x + end + + iy = y.new + + iy.foo.assert == "FOO!" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_alias_module_function.rb b/bin/gems/facets-3.1.0/test/core/module/test_alias_module_function.rb new file mode 100644 index 00000000..eb413d9b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_alias_module_function.rb @@ -0,0 +1,24 @@ +covers 'facets/module/alias_module_function' + +test_case Module do + + method :alias_module_function do + + test do + m = Module.new do + def x ; 33 ; end + + module_function :x + + alias_module_function :y, :x + end + + m.y.assert == 33 + + # use send b/c private? + #@m.send(:y).assert == 33 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_all_instance_methods.rb b/bin/gems/facets-3.1.0/test/core/module/test_all_instance_methods.rb new file mode 100644 index 00000000..2fba7a7f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_all_instance_methods.rb @@ -0,0 +1,27 @@ +covers 'facets/module/all_instance_methods' + +test_case Module do + + method :all_instance_methods do + + test do + c = Class.new do + def x; "x"; end + private + def y; "y"; end + protected + def z; "z"; end + end + + list = c.all_instance_methods(false) + + list.map!{ |m| m.to_sym } # b/c of diff in 1.8 vs 1.9 + + list.assert.include?(:x) + list.assert.include?(:y) + list.assert.include?(:z) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_ancestor.rb b/bin/gems/facets-3.1.0/test/core/module/test_ancestor.rb new file mode 100644 index 00000000..beb3d327 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_ancestor.rb @@ -0,0 +1,16 @@ +covers 'facets/module/ancestor' + +test_case Module do + + method :ancestor? do + + test do + c1 = Class.new + c2 = Class.new(c1) + c2.assert.ancestor?(c1) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_anonymous.rb b/bin/gems/facets-3.1.0/test/core/module/test_anonymous.rb new file mode 100644 index 00000000..9f7c74b4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_anonymous.rb @@ -0,0 +1,18 @@ +covers 'facets/module/anonymous' + +test_case Module do + + method :anonymous? do + + test do + m = Module.new + m.assert.anonymous? + end + + test do + Lemon.refute.anonymous? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_attr_setter.rb b/bin/gems/facets-3.1.0/test/core/module/test_attr_setter.rb new file mode 100644 index 00000000..e7412e67 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_attr_setter.rb @@ -0,0 +1,28 @@ +covers 'facets/module/attr_setter' + +test_case Module do + + method :attr_setter do + + test do + c = Class.new do + attr_setter :a + end + x = c.new + x.a(1) + x.a.assert == 1 + end + + test do + c = Class.new do + attr_setter :a + alias_setter :b, :a + end + x = c.new + x.b(1) + x.a.assert == 1 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_basename.rb b/bin/gems/facets-3.1.0/test/core/module/test_basename.rb new file mode 100644 index 00000000..ce379f46 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_basename.rb @@ -0,0 +1,14 @@ +covers 'facets/module/basename' + +test_case Module do + + method :basename do + + test do + Lemon::TestCase.basename.assert == "TestCase" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_can.rb b/bin/gems/facets-3.1.0/test/core/module/test_can.rb new file mode 100644 index 00000000..83709a08 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_can.rb @@ -0,0 +1,22 @@ +covers 'facets/module/can' + +test_case Module do + + method :can do + + test do + m = Module.new do + def x; "x"; end + end + + c = Class.new do + can m + end + + c.x.assert == "x" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_class.rb b/bin/gems/facets-3.1.0/test/core/module/test_class.rb new file mode 100644 index 00000000..c14718c9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_class.rb @@ -0,0 +1,22 @@ +covers 'facets/module/class' + +test_case Module do + + method :class? do + + test do + x_class = Class.new + y_class = Class.new(x_class) + + x = x_class.new + y = y_class.new + + x_class.assert.class?(x) + y_class.assert.class?(y) + y_class.assert.class?(y) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_class_def.rb b/bin/gems/facets-3.1.0/test/core/module/test_class_def.rb new file mode 100644 index 00000000..b959e55e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_class_def.rb @@ -0,0 +1,22 @@ +covers 'facets/module/class_def' + +test_case Module do + + method :class_def do + + test do + m = Module.new + m.class_def(:x){"x"} + c = Class.new{ include m } + c.new.x.assert == "x" + end + + test do + c = Class.new + c.class_def(:x){"x"} + c.new.x.assert == "x" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_class_extend.rb b/bin/gems/facets-3.1.0/test/core/module/test_class_extend.rb new file mode 100644 index 00000000..46a2133d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_class_extend.rb @@ -0,0 +1,73 @@ +covers 'facets/module/class_extend' + +test_case Module do + + method :class_extend do + + setup "module using class_extend" do + @mod = Module.new do + def i ; end + class_extend do + def n ; 42 ; end + def s ; self ; end + end + end + end + + test "extends module" do + @mod.n.assert == 42 + @mod.s.assert == @mod + end + + test "has expected methods" do + @mod.instance_methods.map{ |m| m.to_s }.assert == ['i'] + end + + test "transfers class methods to including class" do + mod = @mod + mod = Module.new do + include mod + end + mod.n.assert == 42 + mod.s.assert == mod + end + + test "doesn't overwrite instance methods" do + mod = @mod + c = Class.new do + include mod + def n ; 11 ; end + end + c.new.n.assert == 11 + end + + test "is overridable via including module" do + mod = @mod + m = Module.new do + include mod + class_extend do + def n ; super + 1 ; end + end + end + m.n.assert == 43 # notice the difference! + m.s.assert == m + end + + test "transfers class methods thru multiple levels of include" do + mod = @mod + a = Module.new do + include mod + class_extend do + def n ; super + 1 ; end + end + end + m = Module.new do + include a + end + m.n.assert == 43 + m.s.assert == m + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_class_inheritor.rb b/bin/gems/facets-3.1.0/test/core/module/test_class_inheritor.rb new file mode 100644 index 00000000..af49eef9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_class_inheritor.rb @@ -0,0 +1,135 @@ +covers 'facets/module/class_inheritor' + +test_case Class do + + method :class_inheritor do + + test "subclass with inheritor" do + c1 = Class.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + c2 = Class.new(c1) do + class_inheritor :koko, [], :+ + koko! << 2 + end + + c1.koko!.assert == [1] + c1.koko.assert == [1] + c2.koko!.assert == [2] + c2.koko.assert == [1,2] + end + + test "subclass without inheritor" do + c1 = Class.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + c2 = Class.new(c1) + + c1.koko!.assert == [1] + c1.koko.assert == [1] + c2.koko!.assert == [] + c2.koko.assert == [1] + end + + test "include module with inheritor" do + c1 = Class.new do + class_inheritor :x, {}, :merge + x![:a] = 1 + end + m1 = Module.new do + class_inheritor :x, {}, :merge + x![:b] = 2 + end + c2 = Class.new(c1) do + include m1 + class_inheritor :x, {}, :merge + x![:c] = 3 + end + + c1.x.assert == {:a=>1} + + m1.x[:b].assert == 2 + + c2.x.assert == {:a=>1,:b=>2,:c=>3} + + c1.x[:a].assert == 1 + c1.x[:b].assert == nil + c1.x[:c].assert == nil + + c2.x[:a].assert == 1 + c2.x[:b].assert == 2 + c2.x[:c].assert == 3 + + c2.x![:d] = 4 + c2.x[:d].assert == 4 + end + + test "using #concat as the inheritor operator" do + c1 = Class.new do + class_inheritor :relations, [], :concat + end + c2 = Class.new(c1) do + #class_inheritor :relations, [], :concat + end + c1.relations! << 1 + c1.relations! << 2 + c2.relations! << 3 + + c1.relations.assert == [1,2] + c2.relations.assert == [1,2,3] + end + + end + +end + +test_case Module do + + method :class_inheritor do + + test do + m1 = Module.new do + class_inheritor :koko, [], :+ + koko! << 1 + end + c1 = Class.new do + include m1 + #inheritor :koko, [], :+ + koko! << 2 + koko! << 3 + end + c2 = Class.new do + include m1 + #inheritor :koko, [], :+ + koko! << 4 + end + + m1.koko.assert == [1] + c1.koko.assert == [1,2,3] + c2.koko.assert == [1,4] + end + + end + +end + +=begin +Test.class Inheritor do + setup do + a = [1] + @i = Inheritor.new(a, [2], :+) + end + method :== do + test do + @i.assert == [2] + end + end + method :inheritance do + test do + @i.inheritance == [1,2] + end + end +end +=end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_copy_inheritor.rb b/bin/gems/facets-3.1.0/test/core/module/test_copy_inheritor.rb new file mode 100644 index 00000000..9f906a1f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_copy_inheritor.rb @@ -0,0 +1,35 @@ +covers 'facets/module/copy_inheritor' + +test_case Module do + + method :copy_inheritor do + + setup do + m1 = Module.new do + copy_inheritor :koko, [] + koko << 1 + end + c1 = Class.new do + include m1 + #inheritor :koko, [], :+ + koko << 2 + koko << 3 + end + c2 = Class.new do + include m1 + #inheritor :koko, [], :+ + koko << 4 + end + @m1, @c1, @c2 = m1, c1, c2 + end + + test do + @m1.koko.assert == [1] + @c1.koko.assert == [1,2,3] + @c2.koko.assert == [1,4] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_enclosure.rb b/bin/gems/facets-3.1.0/test/core/module/test_enclosure.rb new file mode 100644 index 00000000..671494cf --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_enclosure.rb @@ -0,0 +1,24 @@ +covers 'facets/module/enclosure' +covers 'facets/module/enclosures' + +test_case Module do + + method :enclosure do + test do + Lemon::TestCase.enclosure.assert == Lemon + end + + test "anonymous module" do + m = Module.new + m.enclosure.assert == Object + end + end + + method :enclosures do + test do + Lemon::TestCase.enclosures.assert == [Lemon, Object] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_instance_function.rb b/bin/gems/facets-3.1.0/test/core/module/test_instance_function.rb new file mode 100644 index 00000000..6a4bf22c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_instance_function.rb @@ -0,0 +1,30 @@ +covers 'facets/module/instance_function' + +test_case Module do + + method :instance_function do + + setup "using instance_function" do + @m = Module.new do + instance_function + def self.jumble(obj, arg) + obj + arg + end + end + end + + test "class method" do + r = @m.jumble('Try', 'Me') + r.assert == 'TryMe' + end + + test "instance method" do + s = 'Try' + s.extend @m + r = s.jumble('Me') + r.assert == 'TryMe' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_instance_method.rb b/bin/gems/facets-3.1.0/test/core/module/test_instance_method.rb new file mode 100644 index 00000000..7fc0ce23 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_instance_method.rb @@ -0,0 +1,20 @@ +covers 'facets/module/instance_method' + +test_case Module do + + method :instance_method! do + + test do + c = Class.new do + def x; "x"; end + end + + x1 = c.instance_method!(:x) + x2 = c.instance_method!(:x) + + x1.object_id.assert == x2.object_id + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_instance_method_defined.rb b/bin/gems/facets-3.1.0/test/core/module/test_instance_method_defined.rb new file mode 100644 index 00000000..3c97420e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_instance_method_defined.rb @@ -0,0 +1,38 @@ +covers 'facets/module/instance_method_defined' + +test_case Module do + + method :instance_method_defined? do + + test do + c = Class.new do + def x; "x"; end + end + c.assert.instance_method_defined?(:x) + end + + end + + method :singleton_method_defined? do + + test do + c = Class.new do + def self.x; "x"; end + end + c.assert.singleton_method_defined?(:x) + end + + end + + method :module_method_defined? do + + test "alias for #singleton_method_defined" do + c = Class.new do + def self.x; "x"; end + end + c.assert.module_method_defined?(:x) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_integrate.rb b/bin/gems/facets-3.1.0/test/core/module/test_integrate.rb new file mode 100644 index 00000000..b6de291d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_integrate.rb @@ -0,0 +1,28 @@ +covers 'facets/module/integrate' + +test_case Module do + + method :integrate do + + test do + m = Module.new do + def x ; 1 ; end + end + + c = Class.new do + integrate m do + rename :y, :x + end + end + + ic = c.new + + NoMethodError.assert.raised?{ ic.x } + + ic.y.assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_is.rb b/bin/gems/facets-3.1.0/test/core/module/test_is.rb new file mode 100644 index 00000000..2a23349b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_is.rb @@ -0,0 +1,50 @@ +covers 'facets/module/is' + +test_case Module do + + method :is? do + + test do + m = Module.new + x = Class.new + y = Class.new(x) do + is m + end + + y.assert.is?(x) + y.assert.is?(m) + end + + end + + method :is do + + test do + m = Module.new do + def q; "q"; end + end + x = Class.new do + is m + end + x.new.q.assert == "q" + end + + # Note, we dynamically set the Self constant to avoid a named module + # showing up as an uncovered namespace in the Lemon coverage report. + test do + m = Module.new do + s = Module.new do + def q; "q"; end + end + const_set('Self', s) + end + x = Class.new do + is m + end + x.q.assert == "q" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_memoize.rb b/bin/gems/facets-3.1.0/test/core/module/test_memoize.rb new file mode 100644 index 00000000..429f066e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_memoize.rb @@ -0,0 +1,33 @@ +covers 'facets/module/memoize' + +test_case Module do + + method :memoize do + + test do + tc = Class.new do + def initialize(a) + @a = a + end + def a + "#{@a ^ 3 + 4}" + end + memoize :a + end + + t1 = tc.new(1) + t2 = tc.new(2) + t3 = tc.new(3) + + t1.a.assert == "6" + t2.a.assert == "5" + t3.a.assert == "4" + + t1.a.__id__.assert == t1.a.__id__ + t2.a.__id__.assert == t2.a.__id__ + t3.a.__id__.assert == t3.a.__id__ + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_method_clash.rb b/bin/gems/facets-3.1.0/test/core/module/test_method_clash.rb new file mode 100644 index 00000000..8d002fd8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_method_clash.rb @@ -0,0 +1,59 @@ +covers 'facets/module/method_clash' + +test_case Module do + + setup do + @x = Class.new do + def q1; "q1"; end + def x1; "x1"; end + def r1; "r1"; end + private + def q2; "q2"; end + def x2; "x1"; end + protected + def q3; "q3"; end + def x3; "x3"; end + end + + @y = Class.new do + def q1; "q1"; end + def y1; "y1"; end + private + def q2; "q2"; end + def y2; "y2"; end + def r1; "r1"; end + protected + def q3; "q3"; end + def y3; "y3"; end + end + + @z = Class.new + end + + method :method_clash? do + + test do + @x.assert.method_clash?(@y) + @y.assert.method_clash?(@x) + @z.refute.method_clash?(@x) + @x.refute.method_clash?(@z) + end + + end + + method :method_clash do + + test do + c = @x.method_clash(@y) + c.map!{ |m| m.to_s } + %w{r1 q1 q2 q3}.each do |x| + c.assert.include?(x) + end + %w{x1 x2 x3 y1 y2 y3}.each do |x| + c.refute.include?(x) + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_method_space.rb b/bin/gems/facets-3.1.0/test/core/module/test_method_space.rb new file mode 100644 index 00000000..5cab6bf8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_method_space.rb @@ -0,0 +1,72 @@ +covers 'facets/module/method_space' + +test_case Class do + + method :method_space do + + test "via a block" do + c = Class.new do + def x; "x"; end + method_space :s do + def x; "sx"; end + end + end + o = c.new + o.x.assert == 'x' + o.s.x.assert == 'sx' + end + + test "via module" do + M = Module.new do + def x; "mx"; end + end + c = Class.new do + def x; "x"; end + method_space M + end + o = c.new + o.x.assert == 'x' + o.m.x.assert == 'mx' + end + + test "instance method is not defined" do + c = Class.new do + method_space :s do + def x; "sx"; end + end + end + o = c.new + expect(NoMethodError){ c.x } + end + + end + + method :include_as do + + setup do + m = Module.new do + def x; "x"; end + def y; @y; end + end + @c = Class.new do + include_as :m => m + def initialize + @y = "y" + end + end + end + + test "provides method space" do + o = @c.new + o.m.x.assert == "x" + end + + test "has access to instance scope" do + o = @c.new + o.m.y.assert == "y" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_methodize.rb b/bin/gems/facets-3.1.0/test/core/module/test_methodize.rb new file mode 100644 index 00000000..ef56f5dd --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_methodize.rb @@ -0,0 +1,26 @@ +covers 'facets/module/methodize' + +test_case Module do + + method :methodize do + + test do + Lemon.methodize.assert == 'lemon' + end + + end + +end + +test_case Class do + + method :methodize do + + test do + Lemon::TestCase.methodize.assert == 'lemon__test_case' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_modname.rb b/bin/gems/facets-3.1.0/test/core/module/test_modname.rb new file mode 100644 index 00000000..d1882f61 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_modname.rb @@ -0,0 +1,13 @@ +covers 'facets/module/modname' + +test_case Module do + + method :modname do + + test do + Lemon::TestCase.modname.assert == "Lemon" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_module_def.rb b/bin/gems/facets-3.1.0/test/core/module/test_module_def.rb new file mode 100644 index 00000000..b5e91d15 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_module_def.rb @@ -0,0 +1,22 @@ +covers 'facets/module/module_def' + +test_case Module do + + method :module_def do + + test do + m = Module.new + m.module_def(:x){"x"} + c = Class.new{ include m } + c.new.x.assert == "x" + end + + test do + c = Class.new + c.module_def(:x){"x"} + c.new.x.assert == "x" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_module_load.rb b/bin/gems/facets-3.1.0/test/core/module/test_module_load.rb new file mode 100644 index 00000000..4cc13fbc --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_module_load.rb @@ -0,0 +1,23 @@ +covers 'facets/module/module_load' + +test_case Module do + + # TODO: write tests for module_load + + skip "need to use a ruby fixture file to test module_load.rb" do + + method :module_load do + end + + method :module_require do + end + + method :class_load do + end + + method :class_require do + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_nodef.rb b/bin/gems/facets-3.1.0/test/core/module/test_nodef.rb new file mode 100644 index 00000000..2dac598b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_nodef.rb @@ -0,0 +1,19 @@ +covers 'facets/module/nodef' + +test_case Module do + + method :nodef do + + test do + c = Class.new do + def the_undefined_method ; 'not here' ; end + nodef :the_undefined_method + end + + c.new.refute.respond_to?(:the_undefined_method) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_op.rb b/bin/gems/facets-3.1.0/test/core/module/test_op.rb new file mode 100644 index 00000000..3a58f52b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_op.rb @@ -0,0 +1,56 @@ +covers 'facets/module/op.rb' + +test_case Module do + + setup do + @a = Module.new do + def x; "x"; end + def z; "zA"; end + end + + @b = Module.new do + def y; "y"; end + def z; "zB"; end + end + end + + method :+ do + + test do + q = @a + @b + q.extend q + + q.x.assert == "x" + q.y.assert == "y" + q.z.assert == "zB" + end + + end + + method :- do + + test do + r = @a - @b + r.extend r + + r.x.assert == "x" + NoMethodError.assert.raised?{ r.z } + end + + end + + method :* do + + test do + z = @a * { :x => :y } + z.extend z + + z.y.assert == "x" + z.z.assert == "zA" + NoMethodError.assert.raised?{ z.x } + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_pathize.rb b/bin/gems/facets-3.1.0/test/core/module/test_pathize.rb new file mode 100644 index 00000000..51657add --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_pathize.rb @@ -0,0 +1,25 @@ +covers 'facets/module/pathize' + +test_case Module do + + method :pathize do + + test do + Lemon.pathize.assert == 'lemon' + end + + end + +end + +test_case Class do + + method :pathize do + + test do + Lemon::TestCase.pathize.assert == 'lemon/test_case' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_preextend.rb b/bin/gems/facets-3.1.0/test/core/module/test_preextend.rb new file mode 100644 index 00000000..bc552b2d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_preextend.rb @@ -0,0 +1,26 @@ +covers 'facets/module/preextend' + +test_case Module do + + method :preextend do + + test "module method" do + m = Module.new do + def q; "qm"; end + end + + n = Module.new do + preextend m + def q; "qn"; end + end + + x = Class.new do + include n + end + + n.q.assert == "qm" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_redefine_method.rb b/bin/gems/facets-3.1.0/test/core/module/test_redefine_method.rb new file mode 100644 index 00000000..cb1b9655 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_redefine_method.rb @@ -0,0 +1,30 @@ +covers 'facets/module/redefine_method' + +test_case Module do + + method :redefine_method do + + test do + c = Class.new do + def a; "a"; end + redefine_method(:a){ nil } + end + c.new.a.assert == nil + end + + end + + method :redef do + + test do + c = Class.new do + def b; "b"; end + redef(:b){ "x" } + end + c.new.b.assert == "x" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_redirect_method.rb b/bin/gems/facets-3.1.0/test/core/module/test_redirect_method.rb new file mode 100644 index 00000000..df557490 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_redirect_method.rb @@ -0,0 +1,32 @@ +covers 'facets/module/redirect_method' + +test_case Module do + + method :redirect_method do + + test do + c = Class.new do + def a1 ; 1 ; end + redirect_method :a2 => :a1 + end + + c.new.a2.assert == 1 + end + + end + + method :redirect do + + test do + c = Class.new do + def b1 ; 1 ; end + redirect :b2 => :b1 + end + + c.new.b2.assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_remove.rb b/bin/gems/facets-3.1.0/test/core/module/test_remove.rb new file mode 100644 index 00000000..641e20ca --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_remove.rb @@ -0,0 +1,18 @@ +covers 'facets/module/remove' + +test_case Module do + + method :remove do + + test do + c = Class.new do + def the_removed_method ; 'not here' ; end + remove :the_removed_method + end + + c.new.refute.respond_to?(:the_removed_method) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_rename_method.rb b/bin/gems/facets-3.1.0/test/core/module/test_rename_method.rb new file mode 100644 index 00000000..4c21a0cf --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_rename_method.rb @@ -0,0 +1,34 @@ +covers 'facets/module/rename_method' + +test_case Module do + + method :rename_method do + + test do + c = Class.new do + def a; "A" ; end + rename_method :b, :a + end + + c.new.refute.respond_to?(:a) + c.new.assert.respond_to?(:b) + end + + end + + method :rename do + + test do + c = Class.new do + def c; "C" ; end + rename :d, :c + end + + c.new.refute.respond_to?(:c) + c.new.assert.respond_to?(:d) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_revise.rb b/bin/gems/facets-3.1.0/test/core/module/test_revise.rb new file mode 100644 index 00000000..48bd8001 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_revise.rb @@ -0,0 +1,61 @@ +covers 'facets/module/revise' + +test_case Module do + + method :revisal do + + test do + m = Module.new do + def x ; 1 ; end + end + + c = Class.new do + include m.revisal { + rename :y, :x + } + end + + ic = c.new + + ic.y.assert == 1 + NoMethodError.assert.raised?{ ic.x } + end + + end + + method :revise do + + test do + m = Module.new do + def x ; 1 ; end + end + + c = Class.new do + include m.revise { + rename :y, :x + } + end + + ic = c.new + + ic.y.assert == 1 + NoMethodError.assert.raised?{ ic.x } + end + + end + + method :remove do + + test do + c = Class.new do + def the_removed_method ; 'not here' ; end + remove :the_removed_method + end + + c.new.refute.respond_to?(:the_removed_method) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_set.rb b/bin/gems/facets-3.1.0/test/core/module/test_set.rb new file mode 100644 index 00000000..502de658 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_set.rb @@ -0,0 +1,30 @@ +covers 'facets/module/set' + +test_case Module do + + method :set do + + test do + c = Class.new do + set :x, 10 + end + + c.x.assert == 10 + end + + test do + h = 1 + c = Class.new do + set :x do + h += 1 + end + end + + c.x.assert == 2 + c.x.assert == 3 + c.x.assert == 4 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/module/test_spacename.rb b/bin/gems/facets-3.1.0/test/core/module/test_spacename.rb new file mode 100644 index 00000000..eac9cb08 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_spacename.rb @@ -0,0 +1,15 @@ +covers 'facets/module/spacename' + +test_case Module do + + method :spacename do + + test do + Lemon::TestCase.spacename.assert == 'Lemon' + Lemon.spacename.assert == '' # should this be nil ? + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_to_obj.rb b/bin/gems/facets-3.1.0/test/core/module/test_to_obj.rb new file mode 100644 index 00000000..67059fd0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_to_obj.rb @@ -0,0 +1,20 @@ +covers 'facets/module/to_obj' + +test_case Module do + + method :to_obj do + + test do + m = Module.new do + def x; "x"; end + def y; "y"; end + end + o = m.to_obj + o.x.assert == "x" + o.y.assert == "y" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/module/test_wrap_method.rb b/bin/gems/facets-3.1.0/test/core/module/test_wrap_method.rb new file mode 100644 index 00000000..86cce386 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/module/test_wrap_method.rb @@ -0,0 +1,32 @@ +covers 'facets/module/wrap_method' + +test_case Module do + + method :wrap_method do + + test do + c = Class.new do + def a; "A"; end + wrap_method(:a) { |old| old.call + "B" } + end + + c.new.a.assert == "AB" + end + + end + + method :wrap do + + test do + c = Class.new do + def b; "B"; end + wrap(:b) { |old| old.call + "C" } + end + + c.new.b.assert == "BC" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_approx.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_approx.rb new file mode 100644 index 00000000..fe3be8e6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_approx.rb @@ -0,0 +1,26 @@ +covers 'facets/numeric/approx' + +test_case Numeric do + + method :approx? do + + test do + f = 10.006 + assert( f.approx?(10, 0.1) ) + assert( 100.4.approx?(100.6, 1) ) + end + + end + + method :close? do + + test do + f = 10.006 + assert( f.close?(10, 0.1) ) + assert( 100.4.close?(100.6, 1) ) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_delimit.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_delimit.rb new file mode 100644 index 00000000..9b324442 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_delimit.rb @@ -0,0 +1,68 @@ +covers 'facets/numeric/delimit' + +test_case Numeric do + + f0 = [ 0, 100, 1_000, 1_000_000 ] + + method :delimit do + + test "commas are default" do + fr = f0.map { |f| f.delimit } + fr.assert == %w( 0 100 1,000 1,000,000 ) + end + + test "delimiter can be anything" do + fr = f0.map { |f| f.delimit(:delimiter => "_") } + fr.assert == %w( 0 100 1_000 1_000_000 ) + end + + test "separator defaults to dot" do + fr = f0.map { |f| ( f + 0.1 ).delimit } + fr.assert == %w( 0.1 100.1 1,000.1 1,000,000.1 ) + end + + test "separator can be anything" do + fr = f0.map { |f| ( f + 0.1 ).delimit(:separator => "!") } + fr.assert == %w( 0!1 100!1 1,000!1 1,000,000!1 ) + end + + + end + +end + +=begin +test_case Float do + + f1 = [ 10.1, 10.01, 10.9, 10.09, 10.5, 10.05, 10.49 ] + + # method :round_at do + # + # test "1" do + # fr = f1.collect { |f| f.round_at(1) } + # fr.assert == [10.1,10.0,10.9,10.1,10.5,10.1,10.5] + # end + # + # test "2" do + # fr = f1.collect { |f| f.round_at(2) } + # fr.assert == [10.1,10.01,10.9,10.09,10.5,10.05,10.49] + # end + # + # end + + method :round_to do + + test "0.1" do + fr = f1.collect { |f| f.round_to(0.1) } + fr.assert == [10.1,10.0,10.9,10.1,10.5,10.1,10.5] + end + + test "10" do + fr = f1.collect { |f| f.round_to(10) } + fr.assert == [10,10,10,10,10,10,10] + end + + end + +end +=end diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_distance.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_distance.rb new file mode 100644 index 00000000..a741668c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_distance.rb @@ -0,0 +1,16 @@ +covers 'facets/numeric/distance' + +test_case Numeric do + + method :distance do + + test do + 10.distance(6).assert == 4 + 10.distance(8).assert == 2 + 7.distance(9).assert == -2 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_length.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_length.rb new file mode 100644 index 00000000..9608b6ce --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_length.rb @@ -0,0 +1,16 @@ +covers 'facets/numeric/length' + +test_case Numeric do + + method :length do + + test do + (0..10).each do |power| + power.length.assert == power + end + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_round_to.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_round_to.rb new file mode 100644 index 00000000..38713938 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_round_to.rb @@ -0,0 +1,76 @@ +covers 'facets/numeric/round_to' + +test_case Numeric do + + f0 = [ 0, 10, 15, 105 ] + + # method :round_at do + # + # test "1" do + # fr = f0.collect{ |f| f.round_at(1) } + # fr.assert == [0,10,15,105] + # end + # + # test "2" do + # fr = f0.collect { |f| f.round_at(2) } + # fr.assert == [0,10,15,105] + # end + # + # end + + method :round_to do + + test "0.1" do + fr = f0.collect { |f| f.round_to(0.1) } + fr.assert == [0,10,15,105] + end + + test "10" do + fr = f0.collect { |f| f.round_to(10) } + fr.assert == [0,10,20,110] + end + + end + + #method :round_off do + # test do + # 1.2.round_off.assert == 1.0 + # 1.8.round_off.assert == 2.0 + # end + #end + +end + +test_case Float do + + f1 = [ 10.1, 10.01, 10.9, 10.09, 10.5, 10.05, 10.49 ] + + # method :round_at do + # + # test "1" do + # fr = f1.collect { |f| f.round_at(1) } + # fr.assert == [10.1,10.0,10.9,10.1,10.5,10.1,10.5] + # end + # + # test "2" do + # fr = f1.collect { |f| f.round_at(2) } + # fr.assert == [10.1,10.01,10.9,10.09,10.5,10.05,10.49] + # end + # + # end + + method :round_to do + + test "0.1" do + fr = f1.collect { |f| f.round_to(0.1) } + fr.assert == [10.1,10.0,10.9,10.1,10.5,10.1,10.5] + end + + test "10" do + fr = f1.collect { |f| f.round_to(10) } + fr.assert == [10,10,10,10,10,10,10] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/numeric/test_spacing.rb b/bin/gems/facets-3.1.0/test/core/numeric/test_spacing.rb new file mode 100644 index 00000000..0b9f185c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/numeric/test_spacing.rb @@ -0,0 +1,17 @@ +covers 'facets/numeric/spacing' + +test_case Numeric do + + method :spacing do + + test do + samples = [-10.5, -3, 3, 1.0e14, 10000, 14.5e10] + samples.each do |numeric_item| + numeric_item.spacing.assert == numeric_item.to_s.size + numeric_item.spacing.assert.kind_of?(Integer) + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/object/test_dup.rb b/bin/gems/facets-3.1.0/test/core/object/test_dup.rb new file mode 100644 index 00000000..0e77361f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/object/test_dup.rb @@ -0,0 +1,115 @@ +covers 'facets/object/dup' + +# TODO: Improve object/dup tests. + +test_case Object do + setup "ordinary object" do + @o = Object.new + end + + method :dup? do + test { assert @o.dup? } + end + + method :clone? do + test { assert @o.clone? } + end + + method :dup! do + test { assert @o.dup! } + end + + method :try_dup do |o| + test { assert @o.try_dup } + end +end + +test_case TrueClass do + method :dup? do + test { refute true.dup? } + end + + method :clone? do + test { refute true.clone? } + end + + method :dup! do + test { assert true.dup! } + end + + method :try_dup do + test { assert true.try_dup } + end +end + +test_case FalseClass do + method :dup? do + test { refute false.dup? } + end + + method :clone? do + test { refute false.clone? } + end + + method :dup! do + test { false.dup!.assert == false } + end + + method :try_dup do + test { false.try_dup.assert == false } + end +end + +test_case NilClass do + method :dup? do + test { refute nil.dup? } + end + + method :clone? do + test { refute nil.clone? } + end + + method :dup! do + test { nil.dup!.assert == nil } + end + + method :try_dup do + test { nil.try_dup.assert == nil } + end +end + +test_case Symbol do + method :dup? do + test { refute :a.dup? } + end + + method :clone? do + test { refute :a.clone? } + end + + method :dup! do + test { :a.dup!.assert == :a } + end + + method :try_dup do + test { :a.try_dup.assert == :a } + end +end + +test_case Numeric do + method :dup? do + test { refute 1.dup? } + end + + method :clone? do + test { refute 1.clone? } + end + + method :dup! do + test { 1.dup!.assert == 1 } + end + + method :try_dup do + test { 1.try_dup.assert == 1 } + end +end diff --git a/bin/gems/facets-3.1.0/test/core/object/test_object_state.rb b/bin/gems/facets-3.1.0/test/core/object/test_object_state.rb new file mode 100644 index 00000000..c4f9733f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/object/test_object_state.rb @@ -0,0 +1,75 @@ +covers 'facets/object/object_state' + +test_case Object do + method :object_state do + test do + c = Class.new do + def initialize(a,b) + @a, @b = a, b + end + end + o = c.new(1,2) + s = o.object_state + s.assert == {:a=>1, :b=>2} + end + end +end + +test_case Struct do + method :object_state do + test do + c = Struct.new(:a, :b) + o = c.new(1,2) + s = o.object_state + s.assert == {:a=>1, :b=>2} + end + end +end + +test_case Array do + method :object_state do + test do + a = [1,2,3,4] + s = a.object_state + s.assert == a + end + end +end + +test_case Hash do + method :object_state do + test do + h = {:a=>1,:b=>2,:c=>3} + s = h.object_state + s.assert == h + end + end +end + +test_case String do + method :object_state do + test do + t = "test string" + s = t.object_state + s.assert == t + end + end +end + +#test_case Kernel do +# +# method :object_state do +# test do +# c = Class.new do +# def initialize(a,b) +# @a, @b = a, b +# end +# end +# o = c.new(1,2) +# s = o.object_state +# s.assert == {:a=>1, :b=>2} +# end +# end +# +#end + diff --git a/bin/gems/facets-3.1.0/test/core/object/test_try_dup.rb b/bin/gems/facets-3.1.0/test/core/object/test_try_dup.rb new file mode 100644 index 00000000..b81a3e5a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/object/test_try_dup.rb @@ -0,0 +1,59 @@ +covers 'facets/object/try_dup' + +test_case Object do + method :try_dup do + test do + obj1 = Object.new + obj2 = obj1.try_dup + obj2.equal?(obj1).assert == false + end + end + + method :dup! do + test "is an alias for #try_dup" do + obj1 = Object.new + obj2 = obj1.dup! + obj2.equal?(obj1).assert == false + end + end +end + +test_case TrueClass do + method :try_dup do + test do + true.try_dup.assert == true + end + end +end + +test_case FalseClass do + method :try_dup do + test do + false.try_dup.assert == false + end + end +end + +test_case NilClass do + method :try_dup do + test do + nil.try_dup.assert == nil + end + end +end + +test_case Numeric do + method :try_dup do + test do + 10.try_dup.assert == 10 + end + end +end + +test_case Symbol do + method :try_dup do + test do + :A.try_dup.assert == :A + end + end +end diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_bind.rb b/bin/gems/facets-3.1.0/test/core/proc/test_bind.rb new file mode 100644 index 00000000..2858c852 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_bind.rb @@ -0,0 +1,29 @@ +covers 'facets/proc/bind' + +test_case Proc do + + # Not sure why this is thread critical? + method :bind do + test "thread critial" do + a = 2 + tproc = lambda { |x| x + a } + 99.times { + tmethod = tproc.bind(self) #to_method + tmethod.call(1).assert == 3 + } + + meths = ( + Object.instance_methods + + Object.public_instance_methods + + Object.private_instance_methods + + Object.protected_instance_methods + ) + meths = meths.select{ |s| s.to_s =~ /^_bind_/ } + #meths = Symbol.all_symbols.select { |s| s.to_s =~ /^_bind_/ } # why? + + meths.size.assert == 0 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_bind_to.rb b/bin/gems/facets-3.1.0/test/core/proc/test_bind_to.rb new file mode 100644 index 00000000..fd43a3c0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_bind_to.rb @@ -0,0 +1,17 @@ +covers 'facets/proc/bind_to' + +test_case Proc do + + method :bind_to do + + test do + a = [1,2,3] + p1 = Proc.new{ join(' ') } + p2 = p1.bind_to(a) + p2.call.assert == '1 2 3' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_compose.rb b/bin/gems/facets-3.1.0/test/core/proc/test_compose.rb new file mode 100644 index 00000000..d205518a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_compose.rb @@ -0,0 +1,27 @@ +covers 'facets/proc/compose' + +test_case Proc do + + method :compose do + + test do + a = lambda { |x| x + 4 } + b = lambda { |y| y / 2 } + (a.compose(b)).call(4).assert == 6 + (b.compose(a)).call(4).assert == 4 + end + + end + + method :* do + + test do + a = lambda { |x| x + 4 } + b = lambda { |y| y / 2 } + (a * b).call(4).assert == 6 + (b * a).call(4).assert == 4 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_partial.rb b/bin/gems/facets-3.1.0/test/core/proc/test_partial.rb new file mode 100644 index 00000000..f2dd66a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_partial.rb @@ -0,0 +1,27 @@ +covers 'facets/proc/partial' + +test_case Proc do + + method :partial do + + test "first argument" do + f = Proc.new{ |a,b,c| a + b + c } + n = f.partial(NA,2,3) + n[1].assert == 6 + end + + test "second argument" do + f = Proc.new{ |a,b,c| a + b + c } + n = f.partial(1,NA,3) + n[2].assert == 6 + end + + test "third argument" do + f = Proc.new{ |a,b,c| a + b + c } + n = f.partial(1,2,NA) + n[3].assert == 6 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_to_method.rb b/bin/gems/facets-3.1.0/test/core/proc/test_to_method.rb new file mode 100644 index 00000000..6cb411d5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_to_method.rb @@ -0,0 +1,43 @@ +covers 'facets/proc/to_method' + +test_case Proc do + + method :to_method do + + test do + o = Object.new + tproc = proc { |x| x + 2 } + + tmeth = tproc.to_method(o, :tryit) + + tmeth.call(1).assert == 3 + o.assert.respond_to?(:tryit) + o.tryit(1).assert == 3 + end + + test "with immutable object" do + o = :foo + tproc = proc{ self } + + tmeth = tproc.to_method(o, :tryit) + + tmeth.call.assert == :foo + o.assert.respond_to?(:tryit) + o.tryit.assert == :foo + end + + test "ensure method is in object scope" do + o = Struct.new(:a).new(1) + tproc = proc{ a } + + tmeth = tproc.to_method(o, :tryit) + + tmeth.call.assert == 1 + o.assert.respond_to?(:tryit) + o.tryit.assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/proc/test_update.rb b/bin/gems/facets-3.1.0/test/core/proc/test_update.rb new file mode 100644 index 00000000..e123fc14 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/proc/test_update.rb @@ -0,0 +1,15 @@ +covers 'facets/proc/update' + +test_case Proc do + + method :update do + + test do + p1 = Proc.new{ 'here' } + p1.update.assert == 'here' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/range/test_combine.rb b/bin/gems/facets-3.1.0/test/core/range/test_combine.rb new file mode 100644 index 00000000..6e59f310 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_combine.rb @@ -0,0 +1,32 @@ +covers 'facets/range/combine' + +test_case Range do + + method :combine do + + test do + r = 0..4 + r = r.combine(2..6, 6..10, 13..17, 12..19) + x = [0..10, 12..19] + r.assert == x + end + + end + + class_method :combine do + + test do + r = Range.combine(0..4, 2..6, 6..10, 13..17, 12..19) + x = [0..10, 12..19] + r.assert == x + end + + test "arrays as intervals" do + r = Range.combine([0, 4], [2, 6], [6, 10], [13, 17], [12, 19]) + x = [[0, 10], [12, 19]] + r.assert == x + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/range/test_nudge.rb b/bin/gems/facets-3.1.0/test/core/range/test_nudge.rb new file mode 100644 index 00000000..84c0407b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_nudge.rb @@ -0,0 +1,32 @@ +covers 'facets/range/nudge' + +test_case Range do + method :nudge do + test 'default nudge' do + (17..32).nudge.assert == (18..33) + (17..32).nudge.nudge.assert == (19..34) + (17...32).nudge.assert == (18...33) + end + + test 'positive nudge' do + (1..9).nudge(2).assert == (3..11) + (1...9).nudge(2).assert == (3...11) + end + + test 'negative nudge' do + (5..6).nudge(-2).assert == (3..4) + (5...6).nudge(-2).assert == (3...4) + end + + test 'min nudge' do + (5..9).nudge(:min => 2).assert == (7..9) + (5...9).nudge(:min => 2).assert == (7...9) + end + + test 'max nudge' do + (8..16).nudge(:max => 10).assert == (8..26) + (8...16).nudge(:max => 10).assert == (8...26) + end + end +end + diff --git a/bin/gems/facets-3.1.0/test/core/range/test_op_add.rb b/bin/gems/facets-3.1.0/test/core/range/test_op_add.rb new file mode 100644 index 00000000..ca81bcfb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_op_add.rb @@ -0,0 +1,24 @@ +require 'facets/range/op_add' + +test_case Range do + + method :+ do + #test { lambda{ (1..10) + 'a' }.assert raise_error } + + test { ((1..10) + (11..11)).assert == [1..11] } + test { ((1..10) + 12).assert == [1..10, 12] } + test { ((1..10) + (10..12)).assert == [1..12] } + test { ((1..10) + (11..12)).assert == [1..12] } + test { ((1..10) + (9..12)).assert == [1..12] } + test { ((1..10) + (1..12)).assert == [1..12] } + test { ((1..10) + (12..20)).assert == [1..10, 12..20] } + test { ((1..10) + 0).assert == [0..10] } + test { ((1..10) + -1).assert == [-1, 1..10] } + test { ((1..10) + (-10..-1)).assert == [-10..-1, 1..10] } + test { ((1..10) + (-10..0)).assert == [-10..10] } + test { ((1..10) + (-10..1)).assert == [-10..10] } + test { ((1..10) + (-10..2)).assert == [-10..10] } + test { ((1..10) + (-10..20)).assert == [-10..20]} + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/range/test_op_sub.rb b/bin/gems/facets-3.1.0/test/core/range/test_op_sub.rb new file mode 100644 index 00000000..51720b98 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_op_sub.rb @@ -0,0 +1,34 @@ +require 'facets/range/op_sub' + +test_case Range do + + method :- do + #test { lambda{ (1..10) - 'a' }.assert raise_error } + + test { ((1..10) - (5..5)).assert == [1..4, 6..10] } + test { ((1..10) - 2).assert == [1, 3..10] } + test { ((1..10) - 9).assert == [1..8, 10] } + test { ((1..10) - 10).assert == [1..9, nil] } + test { ((1..10) - 1).assert == [nil, 2..10] } + test { ((1..10) - 11).assert == [1..10, nil] } + test { ((1..10) - 12).assert == [1..10, nil] } + test { ((1..10) - 0).assert == [nil, 1..10] } + test { ((1..10) - -1).assert == [nil, 1..10] } + + test { ((1..10) - (4..6)).assert == [1..3, 7..10] } + test { ((1..10) - (2..6)).assert == [1, 7..10] } + test { ((1..10) - (4..9)).assert == [1..3, 10] } + test { ((1..10) - (2..9)).assert == [1, 10] } + test { ((1..10) - (2..11)).assert == [1] } + test { ((1..10) - (0..9)).assert == [10] } + test { ((1..10) - (4..10)).assert == [1..3] } + test { ((1..10) - (4..12)).assert == [1..3] } + test { ((1..10) - (1..6)).assert == [7..10] } + test { ((1..10) - (-2..6)).assert == [7..10] } + test { ((1..10) - (11..20)).assert == [1..10] } + test { ((1..10) - (-10..0)).assert == [1..10] } + test { ((1..10) - (-10..20)).assert == [] } + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/range/test_overlap.rb b/bin/gems/facets-3.1.0/test/core/range/test_overlap.rb new file mode 100644 index 00000000..469cebc8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_overlap.rb @@ -0,0 +1,15 @@ +covers 'facets/range/overlap' + +test_case Range do + + method :overlap? do + + test do + assert( (4..5).overlap?(3..6) ) + assert(! (7..9).overlap?(3..6) ) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/range/test_to_rng.rb b/bin/gems/facets-3.1.0/test/core/range/test_to_rng.rb new file mode 100644 index 00000000..67eabf69 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_to_rng.rb @@ -0,0 +1,20 @@ +covers 'facets/range/to_rng' + +test_case Range do + + method :to_rng do + test do + a = (0..10) + a.to_rng.assert == a + end + end + + method :to_range do + test do + a = (0..10) + a.to_range.assert == a + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/range/test_umbrella.rb b/bin/gems/facets-3.1.0/test/core/range/test_umbrella.rb new file mode 100644 index 00000000..de021e50 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_umbrella.rb @@ -0,0 +1,32 @@ +covers 'facets/range/umbrella' + +test_case Range do + + method :umbrella do + + test do + (3..6).umbrella(3..6).assert == [0,0] + (3...6).umbrella(3...6).assert == [0,0] + end + + test "partially aligned" do + (3..6).umbrella(2..6).assert == [1,0] + (3..6).umbrella(3..7).assert == [0,1] + (3..6).umbrella(4..6).assert == [-1,0] + (3..6).umbrella(3..5).assert == [0,-1] + end + + test "offset" do + (3..6).umbrella(2..7).assert == [1,1] + (3..6).umbrella(4..7).assert == [-1,1] + (3..6).umbrella(2..5).assert == [1,-1] + (3..6).umbrella(4..5).assert == [-1,-1] + end + + test "offset by exclusion" do + (10...20).umbrella(10..20).assert == [0,1] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/range/test_within.rb b/bin/gems/facets-3.1.0/test/core/range/test_within.rb new file mode 100644 index 00000000..d6fd3b48 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/range/test_within.rb @@ -0,0 +1,25 @@ +covers 'facets/range/within' + +test_case Range do + + method :within? do + + test "wholy within range" do + assert( (4..5).within?(3..6) ) + end + + test "sentinals are equal" do + assert( (3..6).within?(3..6) ) + end + + test "lower sentinal out of range" do + assert(! (2..5).within?(3..6) ) + end + + test "upper sentinal out of range" do + assert(! (5..7).within?(3..6) ) + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/regexp/test_arity.rb b/bin/gems/facets-3.1.0/test/core/regexp/test_arity.rb new file mode 100644 index 00000000..312baf6c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/regexp/test_arity.rb @@ -0,0 +1,30 @@ +covers 'facets/regexp/arity' + +test_case Regexp do + + method :arity do + + test do + r = /(1)(2)(3)/ + r.arity.assert == 3 + end + + test do + r = /(1)(2)(3)(4)/ + r.arity.assert == 4 + end + + test do + r = /(1)(2)((a)3)/ + r.arity.assert == 4 + end + + test do + r = /(?#nothing)(1)(2)(3)(?=3)/ + r.arity.assert == 3 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/regexp/test_multiline.rb b/bin/gems/facets-3.1.0/test/core/regexp/test_multiline.rb new file mode 100644 index 00000000..1f0dcb24 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/regexp/test_multiline.rb @@ -0,0 +1,19 @@ +covers 'facets/regexp/multiline' + +test_case Regexp do + + method :multiline? do + + test do + re = /x/m + re.assert.multiline? + end + + test do + re = /x/ + re.refute.multiline? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/regexp/test_op_add.rb b/bin/gems/facets-3.1.0/test/core/regexp/test_op_add.rb new file mode 100644 index 00000000..1d648d4f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/regexp/test_op_add.rb @@ -0,0 +1,15 @@ +covers 'facets/regexp/op_add' + +test_case Regexp do + + method :+ do + + test do + r = /a/ + /b/ + r.assert == /(?-mix:a)(?-mix:b)/ + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/regexp/test_op_or.rb b/bin/gems/facets-3.1.0/test/core/regexp/test_op_or.rb new file mode 100644 index 00000000..1f295fe8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/regexp/test_op_or.rb @@ -0,0 +1,16 @@ +covers 'facets/regexp/op_or' + +test_case Regexp do + + method :| do + + test do + re = /a/ | /b/ + re.assert =~ "a" + re.assert =~ "b" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/regexp/test_to_re.rb b/bin/gems/facets-3.1.0/test/core/regexp/test_to_re.rb new file mode 100644 index 00000000..02486382 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/regexp/test_to_re.rb @@ -0,0 +1,24 @@ +covers 'facets/regexp/to_re' + +test_case Regexp do + + method :to_re do + + test do + r = /0..10/ + r.to_re.assert == r.to_re + end + + end + + method :to_regexp do + + test do + r = /0..10/ + r.to_regexp.assert == r + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_acronym.rb b/bin/gems/facets-3.1.0/test/core/string/test_acronym.rb new file mode 100644 index 00000000..0492b58f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_acronym.rb @@ -0,0 +1,14 @@ +covers 'facets/string/acronym' + +test_case String do + + method :acronym do + test do + 'abc'.acronym.assert == 'a' + 'abc def'.acronym.assert == 'ad' + 'abc def ghi'.acronym.assert == 'adg' + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_align.rb b/bin/gems/facets-3.1.0/test/core/string/test_align.rb new file mode 100644 index 00000000..0d13450b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_align.rb @@ -0,0 +1,32 @@ +covers 'facets/string/align' + +test_case String do + + method :align do + test do + "xxx".align(:right, 9) == " xxx" + "xxx".align(:left, 9).assert == "xxx " + "xxx".align(:center, 9).assert == " xxx " + end + end + + method :align_right do + test do + "xxx".align_right(9) == " xxx" + end + end + + method :align_left do + test do + "xxx".align_left(9).assert == "xxx " + end + end + + method :align_center do + test do + "xxx".align_center(9).assert == " xxx " + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_ascii_only.rb b/bin/gems/facets-3.1.0/test/core/string/test_ascii_only.rb new file mode 100644 index 00000000..e34f2070 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_ascii_only.rb @@ -0,0 +1,51 @@ +covers 'facets/string/ascii_only' + +test_case String do + + method :ascii_only do + test 'without any non-ascii' do + 'abc'.ascii_only.assert == 'abc' + end + + test 'with non-ascii' do + '中文123'.ascii_only.assert == '123' + end + + test 'with non-ascii when passed alt' do + 'abc'.ascii_only('!').assert == 'abc' + end + + test 'with non-ascii when passed alt' do + '中文123'.ascii_only('!').assert == '!!123' + end + end + + method :ascii_only! do + test 'without any non-ascii' do + s = 'abc' + s.ascii_only! + s.assert == 'abc' + end + + test 'with non-ascii' do + s = '中文123' + s.ascii_only! + s.assert == '123' + end + + test 'without any non-ascii' do + s = 'abc' + s.ascii_only!('!') + s.assert == 'abc' + end + + test 'with non-ascii' do + s = '中文123' + s.ascii_only!('!') + s.assert == '!!123' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_bracket.rb b/bin/gems/facets-3.1.0/test/core/string/test_bracket.rb new file mode 100644 index 00000000..d33231db --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_bracket.rb @@ -0,0 +1,37 @@ +covers 'facets/string/bracket' + +test_case String do + + method :bracket do + test do + 'X'.bracket('#').assert == '#X#' + 'X'.bracket('x','!').assert == 'xX!' + 'X'.bracket('{','}').assert == '{X}' + 'X'.bracket('<').assert == '' + 'X'.bracket('(').assert == '(X)' + 'X'.bracket('[').assert == '[X]' + 'X'.bracket('{').assert == '{X}' + end + end + + method :bracket! do + test do + a = 'X' ; a.bracket!('#') + a.assert == '#X#' + a = 'X' ; a.bracket!('x','!') + a.assert == 'xX!' + a = 'X' ; a.bracket!('{','}') + a.assert == '{X}' + a = 'X' ; a.bracket!('<') + a.assert == '' + a = 'X' ; a.bracket!('(') + a.assert == '(X)' + a = 'X' ; a.bracket!('[') + a.assert == '[X]' + a = 'X' ; a.bracket!('{') + a.assert == '{X}' + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_camelcase.rb b/bin/gems/facets-3.1.0/test/core/string/test_camelcase.rb new file mode 100644 index 00000000..f2531ccc --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_camelcase.rb @@ -0,0 +1,59 @@ +covers 'facets/string/camelcase' + +test_case String do + + method :camelcase do + + test do + "Camel_case".camelcase.assert == "CamelCase" + end + + test "converts underscore to captialized" do + "abc_xyz".camelcase.assert == "abcXyz" + "abc____xyz".camelcase.assert == "abcXyz" + end + + test "can captialize at spaces" do + "abc xyz".camelcase(' ').assert == "abcXyz" + "abc xyz".camelcase(' ').assert == "abcXyz" + end + + test "can capitalize at arbitrary string" do + "abc;xyz".camelcase(';').assert == "abcXyz" + "abc//xyz".camelcase('//').assert == "abcXyz" + end + + test "can captialize at regexp" do + "abc\nxyz".camelcase(/\s/).assert == "abcXyz" + "abc\txyz".camelcase(/\s/).assert == "abcXyz" + end + + # this functionality is in String#modulize instead + test "does not convert paths to module names" do + 'my_module/my_class'.camelcase.refute == 'MyModule::MyClass' + '/my_module/my_class'.camelcase.refute == '::MyModule::MyClass' + end + + # this functionality is in String#modulize instead + test "does not convert methods to module names" do + 'My_module__my_class'.camelcase.refute == 'MyModule::MyClass' + '__My_module__my_class'.camelcase.refute == '::MyModule::MyClass' + end + + end + + method :lower_camelcase do + test do + "abc_xyz".lower_camelcase.assert == "abcXyz" + "Abc_xyz".lower_camelcase.assert == "abcXyz" + end + end + + method :upper_camelcase do + test do + "abc_xyz".upper_camelcase.assert == "AbcXyz" + "Abc_xyz".upper_camelcase.assert == "AbcXyz" + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_capitalized.rb b/bin/gems/facets-3.1.0/test/core/string/test_capitalized.rb new file mode 100644 index 00000000..606dec01 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_capitalized.rb @@ -0,0 +1,36 @@ +covers 'facets/string/capitalized' + +test_case String do + + method :capitalized? do + test do + 'Abc'.assert.capitalized? + end + end + + method :downcase? do + test do + 'abc'.assert.downcase? + end + end + + method :upcase? do + test do + 'ABC'.assert.upcase? + end + end + + #method :lowercase? do + # test do + # 'abc'.assert.lowercase? + # end + #end + + #method :uppercase? do + # test do + # 'ABC'.assert.uppercase? + # end + #end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_characters.rb b/bin/gems/facets-3.1.0/test/core/string/test_characters.rb new file mode 100644 index 00000000..f2a42d34 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_characters.rb @@ -0,0 +1,13 @@ +covers 'facets/string/characters' + +test_case String do + + method :characters do + test do + "abc".characters.assert == ["a","b","c"] + "ab\nc".characters.assert == ["a","b","\n","c"] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_cleanlines.rb b/bin/gems/facets-3.1.0/test/core/string/test_cleanlines.rb new file mode 100644 index 00000000..676eb713 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_cleanlines.rb @@ -0,0 +1,12 @@ +covers 'facets/string/cleanlines' + +test_case String do + + method :cleanlines do + test do + "a \n b \nc".cleanlines.to_a.assert == ["a","b","c"] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_cleave.rb b/bin/gems/facets-3.1.0/test/core/string/test_cleave.rb new file mode 100644 index 00000000..99c9463c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_cleave.rb @@ -0,0 +1,27 @@ +covers 'facets/string/cleave' + +test_case String do + + method :cleave do + + table = [ + [ 'no spaces short word' , 'whole' , ['whole', ''] ], + [ 'no spaces long word' , 'Supercalifragilisticexpialidocious' , ['Supercalifragilisticexpialidocious', ''] ], + [ 'exact middle two words' , 'fancy split' , ['fancy', 'split'] ], + [ 'exact middle many words' , 'All good Rubyists know how to party', ['All good Rubyists', 'know how to party'] ], + [ 'closer to start' , 'short splitter' , ['short', 'splitter'] ], + [ 'closer to start' , 'Four score and seven years ago...' , ['Four score and', 'seven years ago...'] ], + [ 'closer to start' , 'abc def ghijklm nop' , ['abc def', 'ghijklm nop'] ], + [ 'closer to end' , 'extended split' , ['extended', 'split'] ], + [ 'closer to end' , 'abc defghi jklm nop' , [ 'abc defghi', 'jklm nop'] ] + ] + + table.each do |d, s, x| + test d do + s.cleave.assert == x + end + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_cmp.rb b/bin/gems/facets-3.1.0/test/core/string/test_cmp.rb new file mode 100644 index 00000000..8eded600 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_cmp.rb @@ -0,0 +1,18 @@ +covers 'facets/string/cmp' + +test_case String do + + method :cmp do + + test 'on strings' do + "abc".cmp("abc").assert == 0 + "abc".cmp("abcd").assert == -1 + "abcd".cmp("abc").assert == 1 + "abc".cmp("bcd").assert == -1 + "bcd".cmp("abc").assert == 1 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_compress_lines.rb b/bin/gems/facets-3.1.0/test/core/string/test_compress_lines.rb new file mode 100644 index 00000000..fc94e75c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_compress_lines.rb @@ -0,0 +1,27 @@ +covers 'facets/string/compress_lines' + +test_case String do + + method :compress_lines do + + test do + string = <<-QUERY.compress_lines + SELECT name + FROM users + QUERY + + string.assert == "SELECT name FROM users" + end + + test do + string = <<-QUERY.compress_lines(false) + SELECT name + FROM users + QUERY + + string.assert == "SELECT nameFROM users" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_crypt.rb b/bin/gems/facets-3.1.0/test/core/string/test_crypt.rb new file mode 100644 index 00000000..24202f87 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_crypt.rb @@ -0,0 +1,17 @@ +covers 'facets/string/crypt' + +test_case String do + + method :crypt do + test do + "abc".crypt('ZZ').assert.start_with?('ZZ') + end + + test do + encrypted = "abc".crypt + salt = encrypted[0..1] + "abc".crypt(salt).assert == encrypted + end + end +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_divide.rb b/bin/gems/facets-3.1.0/test/core/string/test_divide.rb new file mode 100644 index 00000000..4201fe7f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_divide.rb @@ -0,0 +1,17 @@ +covers 'facets/string/divide' + +test_case String do + + method :divide do + + test do + s = "

Thisisa test.

" + d = s.divide( /<.*?>/ ) + e = ["

This", "is", "a test.", "

"] + d.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_each_word.rb b/bin/gems/facets-3.1.0/test/core/string/test_each_word.rb new file mode 100644 index 00000000..7bc76234 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_each_word.rb @@ -0,0 +1,17 @@ +covers 'facets/string/each_word.rb' + +test_case String do + + method :each_word do + + test do + a = [] + i = "this is a test" + i.each_word{ |w| a << w } + a.assert == ['this', 'is', 'a', 'test'] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_edit_distance.rb b/bin/gems/facets-3.1.0/test/core/string/test_edit_distance.rb new file mode 100644 index 00000000..f672d090 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_edit_distance.rb @@ -0,0 +1,20 @@ +covers 'facets/string/edit_distance' + +test_case String do + + method :edit_distance do + + test do + d = "pretzel".edit_distance('pretzil') + d.assert = 1 + end + + test do + d = "zretzel".edit_distance('pretzil') + d.assert = 2 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_exclude.rb b/bin/gems/facets-3.1.0/test/core/string/test_exclude.rb new file mode 100644 index 00000000..05935500 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_exclude.rb @@ -0,0 +1,23 @@ +covers 'facets/string/exclude' + +test_case String do + + method :exclude? do + + test do + "aaaa".assert.exclude?('bb') + "aaab".assert.exclude?('bb') + "aaba".assert.exclude?('bb') + "baaa".assert.exclude?('bb') + end + + test do + "abba".refute.exclude?('bb') + "aabb".refute.exclude?('bb') + "bbaa".refute.exclude?('bb') + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_expand_tabs.rb b/bin/gems/facets-3.1.0/test/core/string/test_expand_tabs.rb new file mode 100644 index 00000000..7316c455 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_expand_tabs.rb @@ -0,0 +1,83 @@ +covers 'facets/string/expand_tab' + +test_case String do + + setup do + @tabs = <<-EOF + +\tOne tab + \tOne space and one tab + \t Six spaces, a tab, and a space + EOF + end + + method :expand_tabs do + + test "0" do + expected = <<-EOF + +One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tabs(0).assert == expected + end + + test "1" do + expected = <<-EOF + + One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tabs(1).assert == expected + end + + test "4" do + expected = <<-EOF + + One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tabs(4).assert == expected + end + + test "8" do + expected = <<-EOF + + One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tabs.assert == expected + @tabs.expand_tabs(8).assert == expected + end + + test "16" do + expected = <<-EOF + + One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tabs(16).assert == expected + end + + end + + method :expand_tab do + + test "0 (alias for #expand_tabs)" do + expected = <<-EOF + +One tab + One space and one tab + Six spaces, a tab, and a space + EOF + @tabs.expand_tab(0).assert == expected + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_file.rb b/bin/gems/facets-3.1.0/test/core/string/test_file.rb new file mode 100644 index 00000000..52e49cd9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_file.rb @@ -0,0 +1,15 @@ +covers 'facets/string/file' + +test_case String do + + method :file do + + test do + "home/trans".file.dirname.assert == "home" + "home/trans".file.basename.assert == "trans" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_fold.rb b/bin/gems/facets-3.1.0/test/core/string/test_fold.rb new file mode 100644 index 00000000..ac55b5d2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_fold.rb @@ -0,0 +1,21 @@ +covers 'facets/string/fold' + +test_case String do + + method :fold do + + test do + s = "This is\na test.\n\nIt clumps\nlines of text." + o = "This is a test.\n\nIt clumps lines of text." + s.fold.assert == o + end + + test "leave spaces" do + s = "This is\na test.\n\n This is pre.\n Leave alone.\n\nIt clumps\nlines of text." + o = "This is a test.\n\n This is pre.\n Leave alone.\n\nIt clumps lines of text." + s.fold(true).assert == o + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_indent.rb b/bin/gems/facets-3.1.0/test/core/string/test_indent.rb new file mode 100644 index 00000000..88ca8c5f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_indent.rb @@ -0,0 +1,90 @@ +covers 'facets/string/indent' + +test_case String do + + method :indent do + + test "positive" do + "xyz".indent(4).assert == ' xyz' + " xyz".indent(2).assert == ' xyz' + end + + test "multiline positive" do + "abc\nxyz".indent(2).assert == " abc\n xyz" + end + + test "zero" do + 'xyz'.indent(0).assert == 'xyz' + end + + test "negative" do + ' xyz'.indent(-2).assert == ' xyz' + ' xyz'. indent(-2).assert == 'xyz' + end + + test "multiline negative" do + " abc\n xyz".indent(-2).assert == " abc\n xyz" + end + + test "negative more than is possible" do + ' xyz'.indent(-3).assert == 'xyz' + end + + test "non-space positive" do + "xyz".indent(4, '-').assert == '----xyz' + end + + test "non-space zero" do + 'xyz'.indent(0, '-').assert == 'xyz' + end + + test "non-space negative non-matching character" do + ' xyz'.indent(-2, '-').assert == ' xyz' + ' xyz'. indent(-2, '-').assert == ' xyz' + end + + test "non-space negative" do + '----xyz'.indent(-2, '-').assert == '--xyz' + '--xyz'.indent(-2, '-').assert == 'xyz' + end + + Concern "Special regular expresion characters are escaped." + + test "ensure '.' is treated literally and not as wildcard" do + ' xyz'.indent(-2, '.').assert == ' xyz' + '..xyz'.indent(-2, '.').assert == 'xyz' + end + + test "ensure '*' is treated literally and not as wildcard" do + ' xyz'.indent(-2, '*').assert == ' xyz' + '**xyz'.indent(-2, '*').assert == 'xyz' + end + + test "ensure '^' is treated literally and not as line start" do + ' xyz'.indent(-2, '^').assert == ' xyz' + '^^xyz'.indent(-2, '^').assert == 'xyz' + end + + end + + method :indent! do + + test "in place rendition of #unindent" do + s = "xyz" + s.indent!(4) + s.assert == ' xyz' + + s = " xyz" + s.indent!(2) + s.assert == ' xyz' + end + + end + + #method :unindent do + # test "is an alias for negative indent" do + # ' xyz'.unindent(2).assert == 'xyz' + # end + #end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_index_all.rb b/bin/gems/facets-3.1.0/test/core/string/test_index_all.rb new file mode 100644 index 00000000..4a219037 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_index_all.rb @@ -0,0 +1,22 @@ +covers 'facets/string/index_all' + +test_case String do + + method :index_all do + + test "with string argument" do + "axxxaxxxa".index_all('a').assert == [0,4,8] + end + + test "with regexp argument" do + "a123a567a9".index_all(/a/).assert == [0,4,8] + end + + test "with resue flag as true" do + "bbb".index_all('bb', false).assert == ([0]) + "bbb".index_all('bb', true).assert == ([0,1]) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_interpolate.rb b/bin/gems/facets-3.1.0/test/core/string/test_interpolate.rb new file mode 100644 index 00000000..2721a342 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_interpolate.rb @@ -0,0 +1,16 @@ +covers 'facets/string/interpolate' + +test_case String do + + class_method :interpolate do + + test do + a = 1 + String.interpolate{ 'this is #{a}' }.assert == 'this is 1' + end + + end + +end + + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_lchomp.rb b/bin/gems/facets-3.1.0/test/core/string/test_lchomp.rb new file mode 100644 index 00000000..07cd6774 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_lchomp.rb @@ -0,0 +1,25 @@ +covers 'facets/string/lchomp' + +test_case String do + + method :lchomp do + + test do + s = "xxboo" + r = s.lchomp("xx") + r.assert == "boo" + end + + end + + method :lchomp! do + + test do + s = "xxboo" + s.lchomp!("xx") + s.assert == "boo" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_line_wrap.rb b/bin/gems/facets-3.1.0/test/core/string/test_line_wrap.rb new file mode 100644 index 00000000..7c73014c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_line_wrap.rb @@ -0,0 +1,15 @@ +covers 'facets/string/line_wrap' + +test_case String do + + method :line_wrap do + + test do + "abc123".line_wrap(3).assert == "abc\n123\n" + "abcd123".line_wrap(4).assert == "abcd\n123\n" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_lowercase.rb b/bin/gems/facets-3.1.0/test/core/string/test_lowercase.rb new file mode 100644 index 00000000..fffed694 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_lowercase.rb @@ -0,0 +1,18 @@ +covers 'facets/string/lowercase' + +test_case String do + + method :lowercase do + + test do + "Bob".lowercase.assert == "bob" + end + + test do + "BOB".lowercase.assert == "bOB" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_margin.rb b/bin/gems/facets-3.1.0/test/core/string/test_margin.rb new file mode 100644 index 00000000..d082df95 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_margin.rb @@ -0,0 +1,16 @@ +covers 'facets/string/margin' + +test_case String do + + # TODO: Need to expand margin tests + method :margin do + + test do + a = "xyz".margin(4) + a[0..3].assert == ' ' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_methodize.rb b/bin/gems/facets-3.1.0/test/core/string/test_methodize.rb new file mode 100644 index 00000000..7ffce10a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_methodize.rb @@ -0,0 +1,28 @@ +covers 'facets/string/methodize' + +test_case String do + + method :methodize do + + test "module name" do + a = "FooBase" + r = "foo_base" + a.methodize.assert == r + end + + test "path name" do + a = "foo/base" + r = "foo__base" + a.methodize.assert == r + end + + test "name space" do + a = "Foo::Base" + r = "foo__base" + a.methodize.assert == r + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_modulize.rb b/bin/gems/facets-3.1.0/test/core/string/test_modulize.rb new file mode 100644 index 00000000..04ecb08b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_modulize.rb @@ -0,0 +1,28 @@ +covers 'facets/string/modulize' + +test_case String do + + method :modulize do + + test "snakecase" do + a = "foo_bar" + r = "FooBar" + a.modulize.assert == r + end + + test "path name" do + a = "foo/bar" + r = "Foo::Bar" + a.modulize.assert == r + end + + test "on methodized string" do + a = "foo__bar" + r = "Foo::Bar" + a.modulize.assert == r + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_mscan.rb b/bin/gems/facets-3.1.0/test/core/string/test_mscan.rb new file mode 100644 index 00000000..a1a4f0f3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_mscan.rb @@ -0,0 +1,18 @@ +covers 'facets/string/mscan' + +test_case String do + + method :mscan do + + test do + r = 'abc,def,gh'.mscan(/[,]/) + assert( r.all?{ |md| MatchData === md } ) + r.to_a.length.assert == 2 + r[0][0].assert == ',' + r[1][0].assert == ',' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_natcmp.rb b/bin/gems/facets-3.1.0/test/core/string/test_natcmp.rb new file mode 100644 index 00000000..ca55b752 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_natcmp.rb @@ -0,0 +1,17 @@ +covers 'facets/string/natcmp' + +test_case String do + + method :natcmp do + + test do + "my_prog_v1.1.0".natcmp( "my_prog_v1.2.0").assert == -1 + "my_prog_v1.2.0".natcmp("my_prog_v1.10.0").assert == -1 + "my_prog_v1.2.0".natcmp( "my_prog_v1.1.0").assert == 1 + "my_prog_v1.10.0".natcmp("my_prog_v1.2.0").assert == 1 + "my_prog_v1.0.0".natcmp( "my_prog_v1.0.0").assert == 0 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_nchar.rb b/bin/gems/facets-3.1.0/test/core/string/test_nchar.rb new file mode 100644 index 00000000..f858af5a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_nchar.rb @@ -0,0 +1,17 @@ +covers 'facets/string/nchar' + +test_case String do + + method :nchar do + + test do + "abcxyz".nchar(3).assert == "abc" + "abcxyz".nchar(-3).assert == "xyz" + "abcxyz".nchar(3, 'HI').assert == "HIxyz" + "abcxyz".nchar(-3, 'HI').assert == "abcHI" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_newlines.rb b/bin/gems/facets-3.1.0/test/core/string/test_newlines.rb new file mode 100644 index 00000000..9233b2f4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_newlines.rb @@ -0,0 +1,14 @@ +covers 'facets/string/newlines' + +test_case String do + + # Since Ruby 1.9 defined #lines to keep the newline character, + # we have defined #newlines to leave them out. + method :newlines do + test do + "a\nb\nc".newlines.to_a.assert == ["a","b","c"] + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_number.rb b/bin/gems/facets-3.1.0/test/core/string/test_number.rb new file mode 100644 index 00000000..2d7b9bdd --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_number.rb @@ -0,0 +1,44 @@ +covers 'facets/string/number' + +test_case String do + + method :number? do + + test do + x = "1.23\n" + x.number?.assert == true + end + + test do + x = "123_456_789_123_456_789.123_456_000_111\n" + x.number?.assert == true + end + + test do + x = ".123\n" + x.number?.assert == false + end + + test do + x = "123_\n" + x.number?.assert == false + end + + test do + x = "_123\n" + x.number?.assert == false + end + + test do + x = "23_456_789_123_456_.245\n" + x.number?.assert == false + end + + test do + x = "23_456_789_123_456._245\n" + x.number?.assert == false + end + + end + +end \ No newline at end of file diff --git a/bin/gems/facets-3.1.0/test/core/string/test_op_div.rb b/bin/gems/facets-3.1.0/test/core/string/test_op_div.rb new file mode 100644 index 00000000..d1e4dc5d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_op_div.rb @@ -0,0 +1,15 @@ +covers 'facets/string/op_div' + +test_case String do + + method :/ do + + test do + ('merb' / 'string').assert == "merb/string" + ('merb' / :symbol).assert == "merb/symbol" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_op_sub.rb b/bin/gems/facets-3.1.0/test/core/string/test_op_sub.rb new file mode 100644 index 00000000..fbca66c2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_op_sub.rb @@ -0,0 +1,15 @@ +covers 'facets/string/op_sub' + +test_case String do + + method :"-" do + + test do + s = "xxbooxxfoo" + (s - "xx").assert == "boofoo" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_pathize.rb b/bin/gems/facets-3.1.0/test/core/string/test_pathize.rb new file mode 100644 index 00000000..8d1aa332 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_pathize.rb @@ -0,0 +1,31 @@ +covers 'facets/string/pathize' + +test_case String do + + method :pathize do + + test "module name" do + a = "Foo::Base" + x = "foo/base" + a.pathize.assert == x + end + + test "path name" do + a = "foo/base" + x = "foo/base" + a.pathize.assert == x + end + + test "name space" do + a = "foo__base" + x = "foo/base" + a.pathize.assert == x + end + + test 'transforms initial double colon' do + '::MyClass'.pathize.assert == '/my_class' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_quote.rb b/bin/gems/facets-3.1.0/test/core/string/test_quote.rb new file mode 100644 index 00000000..a29c8699 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_quote.rb @@ -0,0 +1,41 @@ +covers 'facets/string/quote' + +test_case String do + + method :quote do + + test "counting quotes" do + 'hi'.quote(1).assert == %{'hi'} + 'hi'.quote(2).assert == %{"hi"} + 'hi'.quote(3).assert == %{'"hi"'} + 'hi'.quote(4).assert == %{""hi""} + 'hi'.quote(5).assert == %{'""hi""'} + end + + test "default double quotes" do + 'hi'.quote.assert == %{"hi"} + end + + test "single quotes" do + 'hi'.quote(:s).assert == %{'hi'} + 'hi'.quote(:single).assert == %{'hi'} + end + + test "double quotes" do + 'hi'.quote(:d).assert == %{"hi"} + 'hi'.quote(:double).assert == %{"hi"} + end + + test "back quotes" do + 'hi'.quote(:b).assert == %{`hi`} + 'hi'.quote(:back).assert == %{`hi`} + end + + test "bracket quotes" do + 'hi'.quote(:sb).assert == "`hi'" + 'hi'.quote(:bracket).assert == "`hi'" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_random.rb b/bin/gems/facets-3.1.0/test/core/string/test_random.rb new file mode 100644 index 00000000..3fab88b4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_random.rb @@ -0,0 +1,25 @@ +covers 'facets/string/random' + +test_case String do + class_method :random do + test do + r = /^[0-9a-zA-Z]{32}$/ + a = String.random + r.assert =~ a + end + + test 'control the length' do + r = /^[0-9a-zA-Z]{17}$/ + a = String.random(17) + r.assert =~ a + end + + test 'control the character_set' do + r = /^[IAMBatman]{12}$/ + + a = String.random(12, ['IAMBatman'.chars]) + r.assert =~ a + end + end +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_range.rb b/bin/gems/facets-3.1.0/test/core/string/test_range.rb new file mode 100644 index 00000000..f5092b54 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_range.rb @@ -0,0 +1,35 @@ +covers 'facets/string/range' + +test_case String do + + method :range do + + test do + "a123a567a9".range(/123/).assert == (1..3) + "a123a567a9".range(/a/).assert == (0..0) + end + + end + + method :range_all do + + test do + "a123a123a9".range_all(/123/).assert == [ (1..3), (5..7) ] + "a123a567a9".range_all(/a/).assert == [ (0..0), (4..4), (8..8) ] + end + + end + + method :range_of_line do + + test do + a = "0123\n456\n78" + x = [0..4, 5..8, 9..10] + r = a.range_of_line + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_remove.rb b/bin/gems/facets-3.1.0/test/core/string/test_remove.rb new file mode 100644 index 00000000..5558a8e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_remove.rb @@ -0,0 +1,50 @@ +covers 'facets/string/remove' + +test_case String do + + method :remove do + + test "remove string" do + s = "xxbooxxfoo" + s.remove("xx").assert == "boofoo" + end + + test "remove regex" do + s = "xbooxxfoox" + s.remove(/x{1,2}/).assert == "boofoo" + end + + end + + method :remove! do + + test "remove string" do + s = "xxbooxxfoo" + s.remove!("xx") + s.assert == "boofoo" + end + + test "remove regex" do + s = "xbooxxfoox" + s.remove!(/x{1,2}/) + s.assert == "boofoo" + end + + end + + method :- do + + test "remove string" do + s = "xxbooxxfoo" + (s - "xx").assert == "boofoo" + end + + test "remove regex" do + s = "xbooxxfoox" + (s - /x{1,2}/).assert == "boofoo" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_rewrite.rb b/bin/gems/facets-3.1.0/test/core/string/test_rewrite.rb new file mode 100644 index 00000000..707f42f3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_rewrite.rb @@ -0,0 +1,17 @@ +covers 'facets/string/rewrite' + +test_case String do + + method :rewrite do + + test do + s = "HELLO TOMMY!" + rules = [[ /TOMMY/, 'MAN' ]] + r = s.rewrite(rules) + r.assert == "HELLO MAN!" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_rotate.rb b/bin/gems/facets-3.1.0/test/core/string/test_rotate.rb new file mode 100644 index 00000000..6d6fac59 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_rotate.rb @@ -0,0 +1,31 @@ +covers 'facets/string/rotate' + +test_case String do + + method :rotate do + + test 'rotates left' do + 'abcdefgh'.rotate(2).assert == 'cdefghab' + end + test 'rotates right' do + 'abcdefgh'.rotate(-2).assert == 'ghabcdef' + end + + end + + method :rotate! do + + test 'rotates left' do + s='abcdefgh' + s.rotate!(2) + s.assert == 'cdefghab' + end + test 'rotates right' do + s='abcdefgh' + s.rotate!(-2) + s.assert == 'ghabcdef' + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_shatter.rb b/bin/gems/facets-3.1.0/test/core/string/test_shatter.rb new file mode 100644 index 00000000..2943b0da --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_shatter.rb @@ -0,0 +1,17 @@ +covers 'facets/string/shatter' + +test_case String do + + method :shatter do + + test do + s = "

Thisisa test.

" + r = s.shatter( /<.*?>/ ) + x = ["

", "This", "", "is", "", "a test.", "

"] + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_similarity.rb b/bin/gems/facets-3.1.0/test/core/string/test_similarity.rb new file mode 100644 index 00000000..0e9825e3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_similarity.rb @@ -0,0 +1,22 @@ +covers 'facets/string/similarity' + +test_case String do + + method :similarity do + + test do + "Alexsanders".similarity("Aleksander").assert == 0.75 + end + + test do + "Alexander".similarity("Alexander").assert == 1.0 + end + + test do + "Alexander".similarity("").assert == 0.0 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_snakecase.rb b/bin/gems/facets-3.1.0/test/core/string/test_snakecase.rb new file mode 100644 index 00000000..d0f0f53d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_snakecase.rb @@ -0,0 +1,22 @@ +covers 'facets/string/snakecase' + +test_case String do + + method :snakecase do + + test 'dowcases' do + 'URI'.snakecase.assert == 'uri' + end + + test 'converts spaces' do + 'MyStuff HisStuff'.snakecase.assert == 'my_stuff_his_stuff' + end + + test 'does not alter path dividers' do + '/my_module/my_class/'.snakecase.assert == '/my_module/my_class/' + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_splice.rb b/bin/gems/facets-3.1.0/test/core/string/test_splice.rb new file mode 100644 index 00000000..59cc226d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_splice.rb @@ -0,0 +1,37 @@ +covers 'facets/string/splice' + +test_case String do + + method :splice do + + test do + a = "HELLO" + a.splice(1).assert == "E" + a.assert == "HLLO" + end + + test "range" do + a = "HELLO" + a.splice(1..2).assert == "EL" + a.assert == "HLO" + end + + test "store" do + a = "HELLO" + a.splice(1, "X") + a.assert == "HXLLO" + end + + end + + # This could be done if class of 2nd arg is checked. + #method :splice_length + # test do + # a = "HELLO" + # a.splice(1,2).assert == "EL" + # a.assert == "HLO" + # end + #end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_squish.rb b/bin/gems/facets-3.1.0/test/core/string/test_squish.rb new file mode 100644 index 00000000..82c0beeb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_squish.rb @@ -0,0 +1,31 @@ +covers 'facets/string/squish' + +test_case String do + + method :squish do + + test do + r = %{ Multi-line + string }.squish + r.assert == "Multi-line string" + end + + test do + r = " foo bar \n \t boo".squish + r.assert == "foo bar boo" + end + + end + + method :squish! do + + test do + s = " foo bar \n \t boo" + s.squish! + s.assert == "foo bar boo" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_store.rb b/bin/gems/facets-3.1.0/test/core/string/test_store.rb new file mode 100644 index 00000000..f2bd73a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_store.rb @@ -0,0 +1,16 @@ +covers 'facets/string/store' + +test_case String do + + method :store do + + test do + a = "HELLO" + a.store(1, "X") + a.assert == "HXLLO" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_subtract.rb b/bin/gems/facets-3.1.0/test/core/string/test_subtract.rb new file mode 100644 index 00000000..197645d9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_subtract.rb @@ -0,0 +1,16 @@ +covers 'facets/string/subtract' + +test_case String do + + method :- do + + test do + ("foobar" - "oo").assert == "fbar" + ("pizza pizza!" - "zz").assert == "pia pia!" + ("letters" - /[a-z]+/).assert == "" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_titlecase.rb b/bin/gems/facets-3.1.0/test/core/string/test_titlecase.rb new file mode 100644 index 00000000..9f9f4822 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_titlecase.rb @@ -0,0 +1,16 @@ +covers 'facets/string/titlecase' + +test_case String do + + method :titlecase do + + test do + r = "try this out".titlecase + x = "Try This Out" + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_to_re.rb b/bin/gems/facets-3.1.0/test/core/string/test_to_re.rb new file mode 100644 index 00000000..b518af16 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_to_re.rb @@ -0,0 +1,35 @@ +covers 'facets/string/to_re' + +test_case String do + + method :to_re do + + test do + "abc".to_re.assert == /abc/ + "a+bc".to_re.assert == /a+bc/ + "a+bc".to_re(false).assert == /a+bc/ + "a+bc".to_re(true).assert == /a\+bc/ + end + + end + + method :to_rx do + + test do + "abc".to_rx.assert == /abc/ + "a+bc".to_rx.assert == /a\+bc/ + "a+bc".to_rx(false).assert == /a+bc/ + "a+bc".to_rx(true).assert == /a\+bc/ + end + + test "escaped characters" do + a = "?" + b = /#{a.to_rx}/ + b.assert =~ "?" + b.refute =~ "X" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_trim.rb b/bin/gems/facets-3.1.0/test/core/string/test_trim.rb new file mode 100644 index 00000000..2a55dccb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_trim.rb @@ -0,0 +1,116 @@ +covers 'facets/string/trim' + +test_case String do + + method :trim do + + test do + s = %q{ + |ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{ + |ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{|ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{ + |ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{|ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{ |ABC + |123 + |TEST}.trim + s.assert == "ABC\n123\nTEST" + end + + test do + s = %q{ABC + |123 + |TEST + }.trim + s.assert == "ABC\n123\nTEST" + end + + test "spacing" do + s = %q{ + | ABC + | 123 + | TEST + }.trim + s.assert == " ABC\n 123\n TEST" + end + + test "spacing" do + s = %q{ + |ABC + |123 + |TEST + }.trim(1) + s.assert == " ABC\n 123\n TEST" + end + + test "spacing" do + s = %q{ + |ABC + |123 + |TEST + }.trim(2) + s.assert == " ABC\n 123\n TEST" + end + + test "spacing" do + s = %q{ ABC + - 123 + - TEST + }.trim + s.assert == " ABC\n 123\n TEST" + end + + test "random placement" do + volly = {} + 100.times{ |n| + k = [] + a = [] + 5.times{ |i| + k << ( ( ' ' * Integer(rand*10) ) + '|' + i.to_s ) + a << ( i.to_s ) + } + volly[k.join("\n")] = a.join("\n") + } + volly.each{ |k,v| + k.trim.assert == v + } + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_unbracket.rb b/bin/gems/facets-3.1.0/test/core/string/test_unbracket.rb new file mode 100644 index 00000000..f5d3cc0d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_unbracket.rb @@ -0,0 +1,38 @@ +covers 'facets/string/unbracket' + +test_case String do + + method :unbracket do + + test do + s = "{unwrap me}" + z = s.unbracket('{') + z.assert == "unwrap me" + end + + test do + s = "--unwrap me!" + z = s.unbracket('--','!') + z.assert == "unwrap me" + end + + end + + method :unbracket! do + + test do + s = "{unwrap me}" + s.unbracket!('{') + s.assert == "unwrap me" + end + + test do + s = "--unwrap me!" + s.unbracket!('--','!') + s.assert == "unwrap me" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_underscore.rb b/bin/gems/facets-3.1.0/test/core/string/test_underscore.rb new file mode 100644 index 00000000..66c71807 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_underscore.rb @@ -0,0 +1,21 @@ +covers 'facets/string/underscore' + +test_case String do + + method :underscore do + + test "from camelcase" do + "SnakeCase".underscore.assert == "snake_case" + end + + test "containing a dash" do + "Snake-Case".underscore.assert == "snake_case" + end + + test "containing spaces" do + "Snake Case".underscore.assert == "snake_case" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_unfold.rb b/bin/gems/facets-3.1.0/test/core/string/test_unfold.rb new file mode 100644 index 00000000..a01b01f1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_unfold.rb @@ -0,0 +1,17 @@ +covers 'facets/string/unfold' + +test_case String do + + method :unfold do + + test do + str = "This is a test of\nparagraph folding." + res = str.unfold + exp = "This is a test of paragraph folding." + res.assert == exp + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_unindent.rb b/bin/gems/facets-3.1.0/test/core/string/test_unindent.rb new file mode 100644 index 00000000..7270c8a4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_unindent.rb @@ -0,0 +1,105 @@ +covers 'facets/string/unindent' + +test_case String do + + method :unindent do + + Concern "Single-line indentation" + + test "removes space indentation" do + "\s\sabc".unindent.assert == "abc" + end + + test "removes_tab_indentation" do + "\tabc".unindent.assert == "abc" + end + + test "removes space and tab indentation" do + "\t\sabc".unindent.assert == "abc" + end + + Concern "Multi-line indentation" + + test "removes indentation" do + "\tabc\n\tabc".unindent.assert == "abc\nabc" + end + + test "keeps relative indentation" do + "\tabc\n\t\tabc".unindent.assert == "abc\n\tabc" + end + + test "ignores blank lines for indent calculation" do + "\n\tabc\n\n\t\tabc\n".unindent.assert == "\nabc\n\n\tabc\n" + end + + Concern "Complex examples" + + ex1 = <<-EOF + I must go down to the seas again + The lonely sea and the sky + And all I want is a tall ship + And a star to steer her by + EOF + + ex2 = <<-EOF + "Eek!" + She cried + As the mouse quietly scurried +by. + EOF + + test "simple examples" do + " xyz".unindent(-1).assert == " xyz" + " xyz".unindent(0).assert == " xyz" + " xyz".unindent(1).assert == " xyz" + " xyz".unindent(2).assert == " xyz" + " xyz".unindent(3).assert == "xyz" + " xyz".unindent(4).assert == "xyz" + end + + test "large example unindented one space" do + expected = <<-EOF + I must go down to the seas again + The lonely sea and the sky + And all I want is a tall ship + And a star to steer her by + EOF + actual = ex1.unindent(1) + actual.assert == expected + end + + test "large example unindented four spaces" do + expected = <<-EOF +I must go down to the seas again + The lonely sea and the sky +And all I want is a tall ship + And a star to steer her by + EOF + actual = ex1.unindent(4) + actual.assert == expected + end + + test "unindent larger than current indention" do + expected = <<-EOF +"Eek!" +She cried +As the mouse quietly scurried +by. + EOF + actual = ex2.unindent(100) + actual.assert == expected + end + + end + + method :unindent! do + + test "modifies string in place" do + str = "\s\sabc" + str.unindent! + str.assert == "abc" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_unquote.rb b/bin/gems/facets-3.1.0/test/core/string/test_unquote.rb new file mode 100644 index 00000000..cca7b0c2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_unquote.rb @@ -0,0 +1,13 @@ +covers 'facets/string/unquote' + +test_case String do + + method :unquote do + + test do + "'here'".unquote.assert == "here" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_uppercase.rb b/bin/gems/facets-3.1.0/test/core/string/test_uppercase.rb new file mode 100644 index 00000000..f2de9d55 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_uppercase.rb @@ -0,0 +1,22 @@ +covers 'facets/string/uppercase' + +test_case String do + + method :uppercase do + + test do + "bob".uppercase.assert == "Bob" + end + + test do + "boB".uppercase.assert == "BoB" + end + + test do + "BoB".uppercase.assert == "BoB" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_variablize.rb b/bin/gems/facets-3.1.0/test/core/string/test_variablize.rb new file mode 100644 index 00000000..cc56d035 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_variablize.rb @@ -0,0 +1,15 @@ +covers 'facets/string/variablize' + +test_case String do + + method :variablize do + + test do + s = "a" + s.variablize.assert == "@a" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/string/test_word_wrap.rb b/bin/gems/facets-3.1.0/test/core/string/test_word_wrap.rb new file mode 100644 index 00000000..3f3bc5e5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_word_wrap.rb @@ -0,0 +1,80 @@ +covers 'facets/string/word_wrap' + +test_case String do + + method :word_wrap do + + test do + e = "abcde\n12345\nxyzwu\n" + r = "abcde 12345 xyzwu".word_wrap(5) + r.assert == e + end + + test do + e = "abcd\n1234\nxyzw\n" + r = "abcd 1234 xyzw".word_wrap(4) + r.assert == e + end + + test do + e = "abc\n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + end + + test do + e = "abc \n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + end + + test do + e = "abc \n123\n" + r = "abc 123".word_wrap(4) + r.assert == e + end + + # test do + # assert_equal "abcde-\n12345-\nxyzwu\n", "abcde12345xyzwu".word_wrap(6,2) + # assert_equal "abcd-\n1234-\nxyzw\n", "abcd1234xyzw".word_wrap(5,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # assert_equal "abc \n123\n", "abc 123".word_wrap(4,2) + # end + end + + method :word_wrap! do + + test do + w = "abcde 12345 xyzwu" + w.word_wrap!(5) + w.assert == "abcde\n12345\nxyzwu\n" + end + + test do + w = "abcd 1234 xyzw" + w.word_wrap!(4) + w.assert == "abcd\n1234\nxyzw\n" + end + + test do + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc\n123\n" + end + + test do + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc \n123\n" + end + + test do + w = "abc 123" + w.word_wrap!(4) + w.assert == "abc \n123\n" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_words.rb b/bin/gems/facets-3.1.0/test/core/string/test_words.rb new file mode 100644 index 00000000..2b9febfc --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_words.rb @@ -0,0 +1,24 @@ +covers 'facets/string/words' + +test_case String do + + method :words do + + test do + x = "a b c\nd e" + x.words.assert == ['a','b','c','d','e'] + end + + test do + x = "ab cd\nef" + x.words.assert == ['ab','cd','ef'] + end + + test do + x = "ab cd \n ef-gh" + x.words.assert == ['ab','cd','ef-gh'] + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/string/test_xor.rb b/bin/gems/facets-3.1.0/test/core/string/test_xor.rb new file mode 100644 index 00000000..b7ae6494 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/string/test_xor.rb @@ -0,0 +1,16 @@ +covers 'facets/string/xor' + +test_case String do + + method :'^' do + + test do + r = "try this out" ^ "puddingsnacks" + x = "\004\a\035D\035\006\016\000N\016\026\037" + r.assert == x + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/struct/test_replace.rb b/bin/gems/facets-3.1.0/test/core/struct/test_replace.rb new file mode 100644 index 00000000..a93b2c09 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/struct/test_replace.rb @@ -0,0 +1,18 @@ +covers 'facets/struct/replace' + +test_case Struct do + method :replace do + test do + s = Struct.new(:name, :age) + + o = s.new('bob', 60) + o.name.assert == 'bob' + o.age.assert == 60 + + o.replace(:name=>'tom', :age=>40) + + o.name.assert == 'tom' + o.age.assert == 40 + end + end +end diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_as_s.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_as_s.rb new file mode 100644 index 00000000..2c044e34 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_as_s.rb @@ -0,0 +1,15 @@ +covers 'facets/symbol/as_s' + +test_case Symbol do + + method :as_s do + + test do + s = :foo.as_s.sub('f','g') + s.assert == :goo + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_bang.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_bang.rb new file mode 100644 index 00000000..9bbcfdaa --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_bang.rb @@ -0,0 +1,15 @@ +covers 'facets/symbol/bang' + +test_case Symbol do + + method :bang? do + + test do + :a.refute.bang? + :a?.refute.bang? + :a!.assert.bang? + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_chomp.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_chomp.rb new file mode 100644 index 00000000..d07ea162 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_chomp.rb @@ -0,0 +1,22 @@ +covers 'facets/symbol/chomp' + +test_case Symbol do + + method :chomp do + + test do + :ab.chomp(:b).assert == :a + end + + end + + method :lchomp do + + test do + :ab.lchomp(:a).assert == :b + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_generate.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_generate.rb new file mode 100644 index 00000000..8035ed37 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_generate.rb @@ -0,0 +1,20 @@ +covers 'facets/symbol/generate' + +test_case Symbol do + + class_method :generate do + test "without key" do + Symbol.generate.assert == :'-1' + Symbol.generate.assert == :'-2' + end + end + + class_method :generate do + test "with prefix key" do + Symbol.generate('orange').assert == :'orange-1' + Symbol.generate('orange').assert == :'orange-2' + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_not.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_not.rb new file mode 100644 index 00000000..dfadc963 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_not.rb @@ -0,0 +1,19 @@ +covers 'facets/symbol/not' + +test_case Symbol do + + method :~@ do + test do + ~:a.assert == :"~a" + end + end + + method :not? do + test do + a = :a + n = ~a + assert( n.not? ) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_op_div.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_op_div.rb new file mode 100644 index 00000000..213d21b5 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_op_div.rb @@ -0,0 +1,15 @@ +covers 'facets/symbol/op_div' + +test_case Symbol do + + method :/ do + + test do + (:merb / "string").assert == "merb/string" + (:merb / :symbol).assert == "merb/symbol" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_plain.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_plain.rb new file mode 100644 index 00000000..49f492b7 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_plain.rb @@ -0,0 +1,19 @@ +covers 'facets/symbol/plain' + +test_case Symbol do + + method :plain? do + + test do + assert( :try.plain? ) + end + + test do + assert( ! :try=.plain? ) + assert( ! :try?.plain? ) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_query.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_query.rb new file mode 100644 index 00000000..dc10f921 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_query.rb @@ -0,0 +1,19 @@ +covers 'facets/symbol/query' + +test_case Symbol do + + method :query? do + + test do + assert( :try?.query? ) + end + + test do + assert( ! :try.query? ) + assert( ! :try=.query? ) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_setter.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_setter.rb new file mode 100644 index 00000000..06c78ac9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_setter.rb @@ -0,0 +1,17 @@ +covers 'facets/symbol/setter' + +test_case Symbol do + + method :setter? do + test do + assert( :try=.setter? ) + end + + test do + assert( ! :try.setter? ) + assert( ! :try?.setter? ) + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_succ.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_succ.rb new file mode 100644 index 00000000..3a58495e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_succ.rb @@ -0,0 +1,16 @@ +covers 'facets/symbol/succ' + +test_case Symbol do + + method :succ do + + test do + :a.succ.assert == :b + :aaa.succ.assert == :aab + :"1".succ.assert == :"2" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_thrown.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_thrown.rb new file mode 100644 index 00000000..f6182612 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_thrown.rb @@ -0,0 +1,22 @@ +covers 'facets/symbol/thrown' + +test_case Symbol do + + method :thrown? do + + test "throws what is expected" do + assert( :a.thrown? { throw :a } ) + end + + test "throws something else" do + refute( :a.thrown? { throw :b } ) + end + + test "throws nothing at all" do + refute( :a.thrown? { } ) + refute( :a.thrown? { true } ) # to exclude block's return value usage. + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/symbol/test_variablize.rb b/bin/gems/facets-3.1.0/test/core/symbol/test_variablize.rb new file mode 100644 index 00000000..7b591bc9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/symbol/test_variablize.rb @@ -0,0 +1,14 @@ +covers 'facets/symbol/variablize' + +test_case Symbol do + + method :variablize do + + test do + :a.variablize.assert == "@a".to_sym + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_ago.rb b/bin/gems/facets-3.1.0/test/core/time/test_ago.rb new file mode 100644 index 00000000..45c4f280 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_ago.rb @@ -0,0 +1,18 @@ +covers 'facets/time/ago' + +test_case Time do + + # We do not need to test #ago b/c it is an alias for #less. + # One test is provided to add to coverage report. + method :ago do + + test "is an alias of #less" do + t = Time.utc(2010,01,20,12,00,00) + t.ago(1, :year).year.assert = 2009 + t.ago(2, :years).year.assert = 2008 + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_change.rb b/bin/gems/facets-3.1.0/test/core/time/test_change.rb new file mode 100644 index 00000000..daf1197d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_change.rb @@ -0,0 +1,17 @@ +covers 'facets/time/change' + +test_case Time do + + method :change do + + test do + t = Time.local(2006,04,20,15,37) + n = Time.now + n = n.change(:month=>4, :day=>20, :hour=>15, :min=>37, :year=>2006) + n.assert == t + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_dst_adjustment.rb b/bin/gems/facets-3.1.0/test/core/time/test_dst_adjustment.rb new file mode 100644 index 00000000..cde720a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_dst_adjustment.rb @@ -0,0 +1,19 @@ +covers 'facets/time/dst_adjustment' + +test_case Time do + + # TODO: Is Time#dst_adjustment test correct? + method :dst_adjustment do + test do + t0 = Time.utc(2010,01,20,12,00,00) + t1 = Time.utc(2010,06,20,12,00,00) + + tt = t1.dst_adjustment(t0) + tt.assert == t0 + + tt = t0.dst_adjustment(t1) + tt.assert == t1 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/time/test_elapse.rb b/bin/gems/facets-3.1.0/test/core/time/test_elapse.rb new file mode 100644 index 00000000..72a7f268 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_elapse.rb @@ -0,0 +1,15 @@ +covers 'facets/time/elapse' + +test_case Time do + + class_method :elapse do + + test do + t = Time.elapse { sleep 1 } + assert( (t > 0.9) && (t < 2.1 )) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_future.rb b/bin/gems/facets-3.1.0/test/core/time/test_future.rb new file mode 100644 index 00000000..ae52ed17 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_future.rb @@ -0,0 +1,32 @@ +covers 'facets/time/future' + +test_case Time do + + method :future? do + + test do + t = Time.now + 1000 + t.assert.future? + end + + test do + n = Time.now - 1000 + n.refute.future? + end + + test do + n = Time.now + 1001 + t = Time.now + 1000 + n.assert.future?(t) + end + + test do + n = Time.now + 999 + t = Time.now + 1000 + n.refute.future?(t) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_hence.rb b/bin/gems/facets-3.1.0/test/core/time/test_hence.rb new file mode 100644 index 00000000..426c1c4c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_hence.rb @@ -0,0 +1,18 @@ +covers 'facets/time/hence' + +test_case Time do + + # We do not need to test #hence b/c it is an alias for #shift. + # One test is provided to add to coverage report. + method :hence do + + test do + e = Time.utc(2008,11, 1, 18,30,57) + r = Time.utc(2007,11, 1, 18,30,57).hence(1, :years) + r.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_in.rb b/bin/gems/facets-3.1.0/test/core/time/test_in.rb new file mode 100644 index 00000000..03f82655 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_in.rb @@ -0,0 +1,18 @@ +covers 'facets/time/ago' + +test_case Time do + + # We do not need to test #in b/c it is an alias for #shift. + # One test is provided to add to coverage report. + method :in do + + test do + e = Time.utc(2008,11, 1, 18,30,57) + r = Time.utc(2007,11, 1, 18,30,57).in(1, :years) + r.assert == e + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_less.rb b/bin/gems/facets-3.1.0/test/core/time/test_less.rb new file mode 100644 index 00000000..91d8a371 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_less.rb @@ -0,0 +1,139 @@ +covers 'facets/time/less' + +test_case Time do + + method :less do + + setup "January 20th 2010 at Noon" do + @t = Time.utc(2010,01,20,12,00,00) + end + + test 'years' do + @t.less(1, :year).year.assert = 2009 + @t.less(2, :years).year.assert = 2008 + end + + test 'weeks' do + @t.less(1, :week).day.assert == 13 + @t.less(2, :weeks).day.assert == 6 + end + + test 'days' do + @t.less(1, :day).day.assert == 19 + @t.less(2, :days).day.assert == 18 + end + + test 'hours' do + @t.less(1, :hour).hour.assert == 11 + @t.less(2, :hours).hour.assert == 10 + @t.less(12, :hours).hour.assert == 0 + end + + test 'minutes' do + @t.less(1, :minute).min.assert == 59 + @t.less(2, :minutes).min.assert == 58 + @t.less(60, :minutes).min.assert == 0 + end + + test 'seconds' do + @t.less(1, :second).sec.assert == 59 + @t.less(2, :seconds).sec.assert == 58 + @t.less(60, :seconds).sec.assert == 0 + end + + end + + method :less do + + concern "verify via dates" + + test "change years" do + e = Time.utc(2007,11, 1, 18,30,57) + r = Time.utc(2008,11, 1, 18,30,57).less(1, :years) + r.assert == e + end + + test "change weeks" do + e = Time.utc(2008,11,24, 18,30,57) + r = Time.utc(2008,12, 1, 18,30,57).less(1, :weeks) + r.assert == e + end + + test "change days" do + e = Time.utc(2008,11,30, 18,30,57) + r = Time.utc(2008,12, 1, 18,30,57).less(1, :days) + r.assert == e + end + + test "change hours" do + e = Time.utc(2008,11,30, 23,30,57) + r = Time.utc(2008,12, 1, 0,30,57).less(1, :hours) + r.assert == e + end + + test "change minutes" do + e = Time.utc(2008,11,30, 23,58,57) + r = Time.utc(2008,12, 1, 0, 0,57).less(2, :minutes) + r.assert == e + end + + test "change seconds" do + e = Time.utc(2008,11,30, 23,59,57) + r = Time.utc(2008,12, 1, 0, 0, 1).less(4, :seconds) + r.assert == e + end + + end + + method :less do + + concern "months do not have a fixed duration" + + test "change month no year wrap" do + e = Time.utc(2008,11, 1) + r = Time.utc(2008,12, 1).less(1, :months) + r.assert == e + end + + test "change month with year wrap due to month" do + e = Time.utc(2007,12, 1) + r = Time.utc(2008, 1, 1).less(1, :months) + r.assert == e + end + + test "change month with 12 or more converts extra months into a year adjustment" do + e = Time.utc(2007, 1, 1) + r = Time.utc(2008, 1, 1).less(12, :months) + r.assert == e + + e = Time.utc(2006,11, 1) + r = Time.utc(2008,12, 1).less(25, :months) + r.assert == e + end + + # 13 months = 1 year + 1 month AND month changing from 12 to 1, + # when going backward, means going back 1 extra year. + test "change month with 12 or more AND year wrap due to month" do + e = Time.utc(2006,12, 1) + r = Time.utc(2008, 1, 1).less(13, :months) + r.assert == e + end + + test "smaller units should remain unchanged" do + e = Time.utc(2005, 8,20, 15,37,59) + r = Time.utc(2006, 1,20, 15,37,59).less(5, :months) + r.assert == e + end + + test "passing a negative number to #less should be same as a positive number to #shift" do + e = Time.utc(2008, 1, 1) + r = Time.utc(2006,12, 1).less(-13, :months) + r.assert == e + + r = Time.utc(2006,12, 1).shift(13, :months) + r.assert == e + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/time/test_past.rb b/bin/gems/facets-3.1.0/test/core/time/test_past.rb new file mode 100644 index 00000000..81e8e15c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_past.rb @@ -0,0 +1,32 @@ +covers 'facets/time/past' + +test_case Time do + + method :past? do + + test do + t = Time.now - 1000 + t.assert.past? + end + + test do + n = Time.now + 1000 + n.refute.past? + end + + test do + n = Time.now - 1001 + t = Time.now - 1000 + n.assert.past?(t) + end + + test do + n = Time.now - 999 + t = Time.now - 1000 + n.refute.past?(t) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_round_to.rb b/bin/gems/facets-3.1.0/test/core/time/test_round_to.rb new file mode 100644 index 00000000..942fc457 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_round_to.rb @@ -0,0 +1,34 @@ +covers 'facets/time/round_to' + +test_case Time do + + method :round_to do + + setup do + @t = Time.local(2000,03,03,3,37,23) + end + + test "hour" do + @t.round_to(60 * 60).assert == Time.local(2000,03,03,4, 0) + end + + #test "month" do + # @t.round_to(1.month).assert == Time.local(2000,03,03,3, 0) + #end + + test "15 minutes" do + @t.round_to(15 * 60).assert == Time.local(2000,03,03,3,30) + end + + test "10 minutes" do + @t.round_to(10 * 60).assert == Time.local(2000,03,03,3,40) + end + + test "5 minutes" do + @t.round_to(5 * 60).assert == Time.local(2000,03,03,3,35) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_set.rb b/bin/gems/facets-3.1.0/test/core/time/test_set.rb new file mode 100644 index 00000000..99a3f685 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_set.rb @@ -0,0 +1,43 @@ +covers 'facets/time/set' + +test_case Time do + + method :set do + + setup do + @t = Time.utc(2010,10,01,12,15,0) + end + + test 'year' do + x = @t.set(:year=>2020) + x.year.assert == 2020 + end + + test 'month' do + x = @t.set(:month=>11) + x.month.assert == 11 + end + + test 'day' do + x = @t.set(:day=>15) + x.day.assert == 15 + end + + test 'hours' do + x = @t.set(:hour=>12) + x.hour.assert == 12 + end + + test 'minutes' do + x = @t.set(:minutes=>12) + x.min.assert == 12 + end + + test 'seconds' do + x = @t.set(:seconds=>9) + x.sec.assert == 9 + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/time/test_shift.rb b/bin/gems/facets-3.1.0/test/core/time/test_shift.rb new file mode 100644 index 00000000..ee5fac6b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_shift.rb @@ -0,0 +1,135 @@ +covers 'facets/time/shift' + +test_case Time do + + method :shift do + + setup "January 1st 2010 at Noon" do + @t = Time.utc(2010,01,01, 12,00,00) + end + + test 'years' do + @t.shift(1, :year).year.assert = 2011 + @t.shift(2, :years).year.assert = 2012 + end + + test 'weeks' do + @t.shift(1, :week).day.assert == 8 + @t.shift(2, :weeks).day.assert == 15 + end + + test 'days' do + @t.shift(1, :day).day.assert == 2 + @t.shift(2, :days).day.assert == 3 + end + + test 'hours' do + @t.shift(1, :hour).hour.assert == 13 + @t.shift(2, :hours).hour.assert == 14 + @t.shift(12, :hours).hour.assert == 0 + end + + test 'minutes' do + @t.shift(1, :minute).min.assert == 1 + @t.shift(2, :minutes).min.assert == 2 + @t.shift(60, :minutes).min.assert == 0 + end + + test 'seconds' do + @t.shift(1, :second).sec.assert == 1 + @t.shift(2, :seconds).sec.assert == 2 + @t.shift(60, :seconds).sec.assert == 0 + end + + end + + method :shift do + + test "change years" do + e = Time.utc(2008,11, 1, 18,30,57) + r = Time.utc(2007,11, 1, 18,30,57).shift(1, :years) + r.assert == e + end + + test "change weeks" do + e = Time.utc(2008,12, 1, 18,30,57) + r = Time.utc(2008,11,24, 18,30,57).shift(1, :weeks) + r.assert == e + end + + test "change days" do + e = Time.utc(2008,12, 1, 18,30,57) + r = Time.utc(2008,11,30, 18,30,57).shift(1, :days) + r.assert == e + end + + test "change hours" do + e = Time.utc(2008,12, 1, 0,30,57) + r = Time.utc(2008,11,30, 23,30,57).shift(1, :hours) + r.assert == e + end + + test "change minutes" do + e = Time.utc(2008,12, 1, 0, 0,57) + r = Time.utc(2008,11,30, 23,58,57).shift(2, :minutes) + r.assert == e + end + + test "change seconds" do + e = Time.utc(2008,12, 1, 0, 0, 1) + r = Time.utc(2008,11,30, 23,59,57).shift(4, :seconds) + r.assert == e + end + + end + + # months are more difficult, so they get their own section + + method :shift do + + test "change month no year wrap" do + e = Time.utc(2008,12, 1) + r = Time.utc(2008,11, 1).shift(1, :months) + r.assert == e + end + + test "change month with year wrap due to month" do + e = Time.utc(2008, 1, 1) + r = Time.utc(2007,12, 1).shift(1, :months) + r.assert == e + end + + test "change month with 12 or more converts extra months into a year adjustment" do + e = Time.utc(2008, 1, 1) + r = Time.utc(2007, 1, 1).shift(12, :months) + r.assert == e + + e = Time.utc(2008,12, 1) + r = Time.utc(2006,11, 1).shift(25, :months) + r.assert == e + end + + test "change month with 12 or more AND year wrap due to month" do + e = Time.utc(2008, 1, 1) + r = Time.utc(2006,12, 1).shift(13, :months) + r.assert == e + end + + test "smaller units should remain unchanged" do + e = Time.utc(2006, 1,20, 15,37,59) + r = Time.utc(2005, 8,20, 15,37,59).shift(5, :months) + r.assert == e + end + + test "passing a negative number to #shift should be same as a positive number to #ago" do + e = Time.utc(2005, 8,20) + r = Time.utc(2006, 1,20).shift(-5, :months) + r.assert == e + + r = Time.utc(2006, 1,20).ago(5, :months) + r.assert == e + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/core/time/test_stamp.rb b/bin/gems/facets-3.1.0/test/core/time/test_stamp.rb new file mode 100644 index 00000000..f2aa0992 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_stamp.rb @@ -0,0 +1,42 @@ +covers 'facets/time/stamp' + +test_case Time do + + method :stamp do + + test "default" do + t = Time.utc(2005,4,20,15,37) + t.stamp.assert == "2005-04-20 15:37:00 +0000" + end + + test "ruby18" do + t = Time.utc(2005,4,20,15,37) + t.stamp(:ruby18).assert == "Wed Apr 20 15:37:00 +0000 2005" + end + + test "long format" do + t = Time.utc(2005,4,20,15,37) + t.stamp(:long).assert == "April 20, 2005 15:37" + end + + test "short format" do + t = Time.utc(2005,4,20,15,37) + t.stamp(:short).assert == "20 Apr 15:37" + end + + end + + class_method :stamp do + + test "long format" do + Time.stamp(:long) + end + + test "short format" do + Time.stamp(:short) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_to_time.rb b/bin/gems/facets-3.1.0/test/core/time/test_to_time.rb new file mode 100644 index 00000000..fff1585e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_to_time.rb @@ -0,0 +1,15 @@ +covers 'facets/time/to_time' + +test_case Time do + + method :to_time do + + test do + t = Time.now + t.to_time.assert.is_a?(Time) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/time/test_trunc.rb b/bin/gems/facets-3.1.0/test/core/time/test_trunc.rb new file mode 100644 index 00000000..4be01992 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/time/test_trunc.rb @@ -0,0 +1,34 @@ +covers 'facets/time/trunc' + +test_case Time do + + method :trunc do + + setup do + @t = Time.local(2000,03,03,3,37,23) + end + + test "hour" do + @t.trunc(60 * 60).assert == Time.local(2000,03,03,3, 0) + end + + #test "month" do + # @t.trunc(1.month).assert == Time.local(2000,03,01,0, 0) + #end + + test "15 minutes" do + @t.trunc(15 * 60).assert == Time.local(2000,03,03,3,30) + end + + test "10 minutes" do + @t.trunc(10 * 60).assert == Time.local(2000,03,03,3,30) + end + + test "05 minutes" do + @t.trunc(5 * 60).assert == Time.local(2000,03,03,3,35) + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/core/unboundmethod/test_arguments.rb b/bin/gems/facets-3.1.0/test/core/unboundmethod/test_arguments.rb new file mode 100644 index 00000000..3d26b451 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/core/unboundmethod/test_arguments.rb @@ -0,0 +1,25 @@ +covers 'facets/unboundmethod/arguments' + +test_case UnboundMethod do + + method :arguments do + + test do + x = Class.new do + def foo(a, b); end + def bar(a, b=1); end + end + + foomethod = x.instance_method(:foo) + arguments = foomethod.arguments + arguments.assert == "a0, a1" + + barmethod = x.instance_method(:bar) + arguments = barmethod.arguments + arguments.assert == "a0, *args" + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/binding/test_block_exec.rb b/bin/gems/facets-3.1.0/test/standard/binding/test_block_exec.rb new file mode 100644 index 00000000..47507c6a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/binding/test_block_exec.rb @@ -0,0 +1,21 @@ +covers "facets/binding/block_exec" + +testcase Binding do + + # TODO: How do we test this? + + method :block_exec do + + #setup do + # c = Class.new + # $block_exec_binding = binding + #end + + #test do + # q = $block_exec_binding.block_exec { x } + # q.assert == 5 + #end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_abs.rb b/bin/gems/facets-3.1.0/test/standard/math/test_abs.rb new file mode 100644 index 00000000..e7560d54 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_abs.rb @@ -0,0 +1,13 @@ +require 'facets/math/abs' + +test_case Math do + + class_method :abs do + test do + Math.abs(-3.1).assert == 3.1 + Math.abs( 0.0).assert == 0.0 + Math.abs( 3.1).assert == 3.1 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_acot.rb b/bin/gems/facets-3.1.0/test/standard/math/test_acot.rb new file mode 100644 index 00000000..6247c39c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_acot.rb @@ -0,0 +1,23 @@ +require 'facets/math/acot' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :acot do + test do + Math.acot(-1.0).range(1.0e-6).assert === 0.5 * Math::PI - Math.atan(-1.0) + Math.acot( 1.0).range(1.0e-6).assert === 0.5 * Math::PI - Math.atan( 1.0) + end + end + + # TODO: Check complementarity of acot and cot + #assert_equal_float(1.0, Math.acot(Math.cot(1.0)), 1.0e-6) + #assert_equal_float(1.0, Math.cot(Math.acot(1.0)), 1.0e-6) + #assert_equal_float(2.0, Math.acot(Math.cot(2.0)), 1.0e-6) + #assert_equal_float(2.0, Math.cot(Math.acot(2.0)), 1.0e-6) + + # TODO: Check consistency of atan2 and acot + #assert_equal_float(Math.atan2(1.0, 1.0), Math.acot(1.0), 1.0e-6) + #assert_equal_float(Math.atan2(1.0, 2.0), Math.acot(2.0), 1.0e-6) + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_acoth.rb b/bin/gems/facets-3.1.0/test/standard/math/test_acoth.rb new file mode 100644 index 00000000..6ee6bc8a --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_acoth.rb @@ -0,0 +1,22 @@ +require 'facets/math/acoth' +require 'facets/math/coth' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :acoth do + test do + Math.acoth(1.5).range(1.0e-6).assert === 0.5 * Math.log(5.0) + Math.acoth(5.0).range(1.0e-6).assert === 0.5 * Math.log(1.5) + end + + # 1.0e-6 + test "check complementarity of acoth and coth" do + Math.acoth(Math.coth( 1.5)).range(1.0e-6).assert === 1.5 + Math.coth(Math.acoth( 1.5)).range(1.0e-6).assert === 1.5 + Math.acoth(Math.coth(-1.5)).range(1.0e-6).assert === -1.5 + Math.coth(Math.acoth(-1.5)).range(1.0e-6).assert === -1.5 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_beta.rb b/bin/gems/facets-3.1.0/test/standard/math/test_beta.rb new file mode 100644 index 00000000..a5f218a2 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_beta.rb @@ -0,0 +1,19 @@ +require 'facets/math/beta' + +test_case Math do + + class_method :beta do + test do + Math.beta(1.0, 1.0).range(1.0e-6).assert === 1.0 + Math.beta(1.0, 2.0).range(1.0e-6).assert === 0.5 + Math.beta(1.0, 3.0).range(1.0e-6).assert === 1.0 / 3.0 + Math.beta(2.0, 1.0).range(1.0e-6).assert === 0.5 + Math.beta(2.0, 2.0).range(1.0e-6).assert === 1.0 / 6.0 + Math.beta(2.0, 3.0).range(1.0e-6).assert === 1.0 / 12.0 + Math.beta(3.0, 1.0).range(1.0e-6).assert === 1.0 / 3.0 + Math.beta(3.0, 2.0).range(1.0e-6).assert === 1.0 / 12.0 + Math.beta(3.0, 3.0).range(1.0e-6).assert === 1.0 / 30.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_ceil.rb b/bin/gems/facets-3.1.0/test/standard/math/test_ceil.rb new file mode 100644 index 00000000..e9882630 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_ceil.rb @@ -0,0 +1,22 @@ +require 'facets/math/ceil' + +test_case Math do + + class_method :ceil do + test do + Math.ceil( 1.99999).assert == 2 + Math.ceil( 1.5 ).assert == 2 + Math.ceil( 1.00001).assert == 2 + Math.ceil( 0.99999).assert == 1 + Math.ceil( 0.5 ).assert == 1 + Math.ceil( 0.00001).assert == 1 + Math.ceil(-0.00001).assert == 0 + Math.ceil(-0.5 ).assert == 0 + Math.ceil(-0.99999).assert == 0 + Math.ceil(-1.00001).assert == -1 + Math.ceil(-1.5 ).assert == -1 + Math.ceil(-1.99999).assert == -1 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_cosec.rb b/bin/gems/facets-3.1.0/test/standard/math/test_cosec.rb new file mode 100644 index 00000000..190605e4 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_cosec.rb @@ -0,0 +1,19 @@ +require 'facets/math/cosec' + +test_case Math do + + class_method :cosec do + test do + Math.cosec(-1.0).assert == 1.0 / Math.sin(-1.0) + Math.cosec( 1.0).assert == 1.0 / Math.sin( 1.0) + end + end + + # TODO: Check complementarity of cosec and sin + #assert_equal_float(1.0, Math.cosec(-2.0) * Math.sin(-2.0), 1.0e-6) + #assert_equal_float(1.0, Math.cosec(-1.0) * Math.sin(-1.0), 1.0e-6) + #assert_equal_float(1.0, Math.cosec( 1.0) * Math.sin( 1.0), 1.0e-6) + #assert_equal_float(1.0, Math.cosec( 2.0) * Math.sin( 2.0), 1.0e-6) + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_cosech.rb b/bin/gems/facets-3.1.0/test/standard/math/test_cosech.rb new file mode 100644 index 00000000..7eced223 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_cosech.rb @@ -0,0 +1,19 @@ +require 'facets/math/cosech' + +test_case Math do + + class_method :cosech do + test do + Math.cosech(-1.0).assert == 1.0 / Math.sinh(-1.0) + Math.cosech( 1.0).assert == 1.0 / Math.sinh( 1.0) + end + + test "check complementarity of cosech and sinh" do + (Math.cosech(-2.0) * Math.sinh(-2.0)).assert == 1.0 + (Math.cosech(-1.0) * Math.sinh(-1.0)).assert == 1.0 + (Math.cosech( 1.0) * Math.sinh( 1.0)).assert == 1.0 + (Math.cosech( 2.0) * Math.sinh( 2.0)).assert == 1 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_cot.rb b/bin/gems/facets-3.1.0/test/standard/math/test_cot.rb new file mode 100644 index 00000000..f0634ca6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_cot.rb @@ -0,0 +1,13 @@ +require 'facets/math/cot' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :cot do + test do + Math.cot(1.0).range(1.0e-6).assert === 1.0 / Math.tan(1.0) + Math.cot(2.0).range(1.0e-6).assert === 1.0 / Math.tan(2.0) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_coth.rb b/bin/gems/facets-3.1.0/test/standard/math/test_coth.rb new file mode 100644 index 00000000..ab5ef1d3 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_coth.rb @@ -0,0 +1,13 @@ +require 'facets/math/coth' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :coth do + test do + Math.coth(1.0).range(1.0e-6).assert === 1.0 / Math.tanh(1.0) + Math.coth(2.0).range(1.0e-6).assert === 1.0 / Math.tanh(2.0) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_distance.rb b/bin/gems/facets-3.1.0/test/standard/math/test_distance.rb new file mode 100644 index 00000000..3a45f7be --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_distance.rb @@ -0,0 +1,16 @@ +require 'facets/math/distance' + +test_case Math do + + class_method :distance do + test do + Math.distance(1, 2).assert == 1.0 + Math.distance([1,2], [3,4]).assert >= 2.828427 + Math.distance([1,2], [3,4]).assert <= 2.8284271247461903 + Math.distance([1,2,3], [4,5,6]).assert >= 5.196152 + Math.distance([1,2,3], [4,5,6]).assert <= 5.196152422706632 + Math.distance([1,2,3,4], [5,6,7,8]).assert == 8.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_exp10.rb b/bin/gems/facets-3.1.0/test/standard/math/test_exp10.rb new file mode 100644 index 00000000..ef2fb54e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_exp10.rb @@ -0,0 +1,14 @@ +require 'facets/math/exp10' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :exp10 do + test do + Math.exp10(0.0).range(1.0e-6).assert === 1.0 + Math.exp10(0.5).range(1.0e-6).assert === Math.sqrt(10.0) + Math.exp10(1.0).range(1.0e-6).assert === 10.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_exp2.rb b/bin/gems/facets-3.1.0/test/standard/math/test_exp2.rb new file mode 100644 index 00000000..07d4da00 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_exp2.rb @@ -0,0 +1,14 @@ +require 'facets/math/exp2' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :exp2 do + test do + Math.exp2(0.0).range(1.0e-6).assert === 1.0 + Math.exp2(0.5).range(1.0e-6).assert === Math.sqrt(2.0) + Math.exp2(1.0).range(1.0e-6).assert === 2.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_factorial.rb b/bin/gems/facets-3.1.0/test/standard/math/test_factorial.rb new file mode 100644 index 00000000..9dedc8ea --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_factorial.rb @@ -0,0 +1,13 @@ +require 'facets/math/factorial' + +test_case Math do + + class_method :factorial do + fac = 1 + 1.upto(100) do |i| + fac *= i + Math.factorial(i).assert == fac + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_floor.rb b/bin/gems/facets-3.1.0/test/standard/math/test_floor.rb new file mode 100644 index 00000000..e4b4f6d6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_floor.rb @@ -0,0 +1,23 @@ +require 'facets/math/floor' + +test_case Math do + + class_method :floor do + test do + Math.floor( 1.99999).assert == 1 + Math.floor( 1.5 ).assert == 1 + Math.floor( 1.00001).assert == 1 + Math.floor( 0.99999).assert == 0 + Math.floor( 0.5 ).assert == 0 + Math.floor( 0.00001).assert == 0 + Math.floor(-0.00001).assert == -1 + Math.floor(-0.5 ).assert == -1 + Math.floor(-0.99999).assert == -1 + Math.floor(-1.00001).assert == -2 + Math.floor(-1.5 ).assert == -2 + Math.floor(-1.99999).assert == -2 + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_gcd.rb b/bin/gems/facets-3.1.0/test/standard/math/test_gcd.rb new file mode 100644 index 00000000..e081a179 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_gcd.rb @@ -0,0 +1,18 @@ +require 'facets/math/gcd' +require 'facets/math/factorial' + +test_case Math do + + class_method :gcd do + test do + Math.gcd(4732, 4700).assert == 4 + Math.gcd(3651, 5023).assert == 1 + Math.gcd(612221610, 67461255771).assert == 5565651 + end + + test "on a factorial" do + Math.factorial(47).assert == Math.gcd(Math.factorial(90), Math.factorial(47)) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_lcm.rb b/bin/gems/facets-3.1.0/test/standard/math/test_lcm.rb new file mode 100644 index 00000000..63a71a24 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_lcm.rb @@ -0,0 +1,13 @@ +require 'facets/math/lcm' + +test_case Math do + + class_method :lcm do + test do + Math.lcm( 77, 221).assert == 17017 + Math.lcm(143, 187).assert == 2431 + Math.lcm( 91, 119).assert == 1547 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_median.rb b/bin/gems/facets-3.1.0/test/standard/math/test_median.rb new file mode 100644 index 00000000..efe28b8b --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_median.rb @@ -0,0 +1,17 @@ +covers 'facets/math/median' + +test_case Math do + + class_method :median do + test "fractional" do + r = Math.median [1, 2, 3, 3, 6, 11, 20, 20] + r.assert == 4.5 + end + + test "whole value" do + r = Math.median [1, 2, 4, 6, 8] + r.assert == 4 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_percentile.rb b/bin/gems/facets-3.1.0/test/standard/math/test_percentile.rb new file mode 100644 index 00000000..ac72aa76 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_percentile.rb @@ -0,0 +1,13 @@ +covers 'facets/math/percentile' + +test_case Math do + + class_method :percentile do + test do + a = [1,1,2,2,3,3,3,4] + r = Math.percentile(a,75) + r.assert == 3.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_pow.rb b/bin/gems/facets-3.1.0/test/standard/math/test_pow.rb new file mode 100644 index 00000000..1fdfed07 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_pow.rb @@ -0,0 +1,30 @@ +require 'facets/math/pow' +require 'facets/numeric/range' + +test_case Math do + + class_method :pow do + test do + Math.pow( 4.0, 3.0).range(1.0e-6).assert === 64.0 + Math.pow( 0.9, 3.0).range(1.0e-6).assert === 0.729 + Math.pow( 0.25, -0.5).range(1.0e-6).assert === 2.0 + Math.pow( 64.0, -1.0/3).range(1.0e-6).assert === 0.25 + end + end + + class_method :pwr do + test do + Math.pwr( 4.0, 3.0).range(1.0e-6).assert === 64.0 + Math.pwr( 0.9, 3.0).range(1.0e-6).assert === 0.729 + Math.pwr( 0.25, -0.5).range(1.0e-6).assert === 2.0 + Math.pwr( 64.0, -1.0/3).range(1.0e-6).assert === 0.25 + end + end + + # TODO: Check complementarity of pwr and root + # assert_equal_float( 4.0, Math.root(Math.pwr(2.0, 6.0), 3.0), 1.0e-6) + # assert_equal_float( 2.0, Math.root(Math.pwr(4.0, 4.0), 8.0), 1.0e-6) + # assert_equal_float(Math.sqrt(2.0), Math.pwr(Math.root(2.0, 6.0), 3.0), 1.0e-6) + # assert_equal_float( 16.0, Math.pwr(Math.root(4.0, 4.0), 8.0), 1.0e-6) + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_root.rb b/bin/gems/facets-3.1.0/test/standard/math/test_root.rb new file mode 100644 index 00000000..d5a73b4d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_root.rb @@ -0,0 +1,15 @@ +require 'facets/math/root' +require 'facets/numeric/range' + +test_case Math do + + class_method :root do + test do + Math.root( 64.0, 3.0).range(1.0e-6).assert === 4.0 + Math.root( 0.729, 3.0).range(1.0e-6).assert === 0.9 + Math.root( 2.0, -0.5).range(1.0e-6).assert === 0.25 + Math.root( 0.25, -1.0/3).range(1.0e-6).assert === 64.0 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_sec.rb b/bin/gems/facets-3.1.0/test/standard/math/test_sec.rb new file mode 100644 index 00000000..5941ec6e --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_sec.rb @@ -0,0 +1,19 @@ +require 'facets/math/sec' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :sec do + test do + Math.sec(1.0).range(1.0e-6).assert === 1.0 / Math.cos(1.0) + Math.sec(2.0).range(1.0e-6).assert === 1.0 / Math.cos(2.0) + end + end + + # TODO: Check complementarity of cos and sec + #assert_equal_float(1.0, Math.sec(-2.0) * Math.cos(-2.0), 1.0e-6) + #assert_equal_float(1.0, Math.sec(-1.0) * Math.cos(-1.0), 1.0e-6) + #assert_equal_float(1.0, Math.sec( 1.0) * Math.cos( 1.0), 1.0e-6) + #assert_equal_float(1.0, Math.sec( 2.0) * Math.cos( 2.0), 1.0e-6) + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_sech.rb b/bin/gems/facets-3.1.0/test/standard/math/test_sech.rb new file mode 100644 index 00000000..155847df --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_sech.rb @@ -0,0 +1,19 @@ +require 'facets/math/sech' +require 'facets/numeric/range' # used to test within a precision + +test_case Math do + + class_method :sech do + test do + Math.sech(1.0).range(1.0e-6).assert === 1.0 / Math.cosh(1.0) + Math.sech(2.0).range(1.0e-6).assert === 1.0 / Math.cosh(2.0) + end + end + + # TODO: Check complementarity of cosh and sech + #assert_equal_float(1.0, Math.sech(-2.0) * Math.cosh(-2.0), 1.0e-6) + #assert_equal_float(1.0, Math.sech(-1.0) * Math.cosh(-1.0), 1.0e-6) + #assert_equal_float(1.0, Math.sech( 1.0) * Math.cosh( 1.0), 1.0e-6) + #assert_equal_float(1.0, Math.sech( 2.0) * Math.cosh( 2.0), 1.0e-6) + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_sign.rb b/bin/gems/facets-3.1.0/test/standard/math/test_sign.rb new file mode 100644 index 00000000..b33fe0be --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_sign.rb @@ -0,0 +1,20 @@ +require 'facets/math/sign' + +test_case Math do + + class_method :sign do + test do + Math.sign(-3.1).assert == -1.0 + Math.sign( 0.0).assert == 0.0 + Math.sign( 3.1).assert == 1.0 + end + + # Check complementarity of abs and sign + #assert_equal_float(-2.0, Math.abs(-2.0) * Math.sign(-2.0), 1e-6) + #assert_equal_float( 0.0, Math.abs( 0.0) * Math.sign( 0.0), 1e-6) + #assert_equal_float( 3.0, Math.abs( 3.0) * Math.sign( 3.0), 1e-6) + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_sinc.rb b/bin/gems/facets-3.1.0/test/standard/math/test_sinc.rb new file mode 100644 index 00000000..5dae1eaf --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_sinc.rb @@ -0,0 +1,15 @@ +require 'facets/math/sinc' + +test_case Math do + + class_method :sinc do + test do + Math.sinc( 0.0).assert == 1.0 + Math.sinc( 1.0).assert == Math.sin(1.0) + Math.sinc(-1.0).assert == Math.sin(1.0) + Math.sinc( 2.0).assert == 0.5 * Math.sin(2.0) + Math.sinc(-2.0).assert == 0.5 * Math.sin(2.0) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/math/test_srq.rb b/bin/gems/facets-3.1.0/test/standard/math/test_srq.rb new file mode 100644 index 00000000..8cdd04f1 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/math/test_srq.rb @@ -0,0 +1,20 @@ +require 'facets/math/sqr' +require 'facets/numeric/range' + +test_case Math do + + class_method :sqr do + test do + Math.sqr(-0.9).range(1.0e-6).assert === 0.81 + Math.sqr(-0.7).range(1.0e-6).assert === 0.49 + Math.sqr(-0.7).range(1.0e-6).assert === 0.49 + Math.sqr( 0.9).range(1.0e-6).assert === 0.81 + end + end + + # TODO: Check complementarity of sqrt and sqr + # assert_equal_float(0.3, Math.sqrt(Math.sqr( 0.3)), 1.0e-6) + # assert_equal_float(0.3, Math.sqrt(Math.sqr(-0.3)), 1.0e-6) + # assert_equal_float(0.3, Math.sqr(Math.sqrt( 0.3)), 1.0e-6) + +end diff --git a/bin/gems/facets-3.1.0/test/standard/pathname/test_chdir.rb b/bin/gems/facets-3.1.0/test/standard/pathname/test_chdir.rb new file mode 100644 index 00000000..e2c66c11 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/pathname/test_chdir.rb @@ -0,0 +1,16 @@ +covers 'facets/pathname/chdir' + +test_case Pathname do + + method :chdir do + + test do + Pathname.pwd.basename.to_s.assert != 'tmp' + Pathname.new('tmp').chdir do + Pathname.pwd.basename.to_s.assert == 'tmp' + end + end + + end +end + diff --git a/bin/gems/facets-3.1.0/test/standard/pathname/test_readline.rb b/bin/gems/facets-3.1.0/test/standard/pathname/test_readline.rb new file mode 100644 index 00000000..d86cefdb --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/pathname/test_readline.rb @@ -0,0 +1,23 @@ +require 'pathname' + +covers 'facets/pathname/readline' + +test_case Pathname do + + method :readline do + + setup do + @test_file = Pathname.new('tmp/test_file') + File.open(@test_file, "w") { |f| f << "line1\nline2" } + end + + test do + @test_file.readline.assert == "line1\n" + end + + end +end + + + + diff --git a/bin/gems/facets-3.1.0/test/standard/test_argvector.rb b/bin/gems/facets-3.1.0/test/standard/test_argvector.rb new file mode 100644 index 00000000..5a81ff5c --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_argvector.rb @@ -0,0 +1,64 @@ +covers 'facets/argvector' + +test_case Argvector do + + method :parameters do + + test do + line = "-x baz --foo=8 bar" + cargs = Argvector.new(line) + args, keys = cargs.parameters + args.assert == ['baz','bar'] + keys.assert == {'foo'=>'8','x'=>true} + end + + test "with arity" do + line = "-g a -x b -x c" + cargs = Argvector.new(line, :g=>1, :x=>1) + args, keys = cargs.parameters + keys.assert == {'g'=>'a','x'=>['b','c']} + args.assert == [] + end + + test "repeated option" do + line = "-x baz --foo=1 --foo=2 bar" + cargs = Argvector.new(line) + args, keys = cargs.parameters + args.assert == ['baz','bar'] + keys.assert == {'x'=>true,'foo'=>['1','2']} + end + + test do + line = "-q baz --aq 5 bar" + cargs = Argvector.new(line,'aq'=>1) + words, flags = cargs.parameters + words.assert == ['baz','bar'] + flags.assert == {'q'=>true,'aq'=>'5'} + end + + end + + method :preoptions do + + test do + line = "-x --foo=7 baz -y bar" + cargs = Argvector.new(line) + flags = cargs.preoptions + flags.assert == {'x'=>true,'foo'=>'7'} + end + + end + + method :flags do + + test do + line = "-x baz --foo=8 bar" + cargs = Argvector.new(line) + flags = cargs.flags + flags.assert == ['x'] + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/test_cloneable.rb b/bin/gems/facets-3.1.0/test/standard/test_cloneable.rb new file mode 100644 index 00000000..7a50218f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_cloneable.rb @@ -0,0 +1,60 @@ +require 'facets/cloneable' + +test_case Cloneable do + + foo = Class.new do + include Cloneable + def initialize + @bar=[] + end + def bar_id + @bar.object_id + end + end + + method :dup do + test do + a = foo.new + b = a.dup + a.bar_id.refute == b.bar_id + end + + test "tainted" do + a = foo.new + a.taint + b = a.dup + b.assert.tainted? + end + + test "frozen" do + a = foo.new + a.freeze + b = a.dup + b.refute.frozen? + end + end + + method :clone do + test do + a = foo.new + b = a.clone + assert(a.bar_id != b.bar_id, "should not be equal") + end + + test "tainted" do + a = foo.new + a.taint + b = a.clone + assert b.tainted?, "b should be tainted" + end + + test "frozen" do + a = foo.new + a.freeze + b = a.clone + assert b.frozen?, "b should be frozen" + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_date.rb b/bin/gems/facets-3.1.0/test/standard/test_date.rb new file mode 100644 index 00000000..cb73ac8f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_date.rb @@ -0,0 +1,82 @@ +covers 'facets/date' + +test_case Date do + + setup "Date 2005-05-20" do + @d = Date.civil(2005, 04, 20) + end + + method :to_date do + test do + @d.to_date.assert.instance_of?(::Date) + end + end + + method :to_time do + test do + @d.to_time.assert.instance_of?(::Time) + end + end + + method :to_s do + test do + @d.to_s.assert == "2005-04-20" + end + end + + method :stamp do + test do + @d.stamp.assert == "2005-04-20" + end + end + + method :stamp do + test do + @d.stamp(:short).assert == "20 Apr" + end + end + + method :stamp do + test do + @d.stamp(:long).assert == "April 20, 2005" + end + end + + method :days_in_month do + test do + @d.days_in_month.assert == 30 + end + end + + method :days_of_month do + test do + @d.days_of_month.assert == (1..(@d.days_in_month)).to_a + end + end + +end + +test_case String do + + method :to_date do + test do + s = "2005-10-31" + d = s.to_date + d.day.assert == 31 + d.month.assert == 10 + d.year.assert == 2005 + end + end + +end + +test_case Time do + + method :to_date do + test do + t = Time.now #parse('4/20/2005 15:37') + t.to_date.assert.instance_of?(::Date) + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_enumargs.rb b/bin/gems/facets-3.1.0/test/standard/test_enumargs.rb new file mode 100644 index 00000000..997c811d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_enumargs.rb @@ -0,0 +1,105 @@ +covers 'facets/enumargs' + +test_case Enumerable::Arguments do + + setup do + @PlusArray = Class.new do + include Enumerable::Argumentable + def initialize(arr) + @arr = arr + end + def each(n=0) + @arr.each{ |e| yield(e+n) } + end + end + end + + method :collect do + test do + t = @PlusArray.new([1,2,3]) + r = t.collect(4){ |e| e } + r.assert == [5,6,7] + end + end + + #method :each_slice do + # test do + # t = PlusArray.new([1,2,3,4]) + # a = [] + # t.each_slice(2,4){ |e,f| a << [e,f] } + # a.assert == [[5,6],[7,8]] + # end + #end + + #method :find do + # test do + # t = PlusArray.new([1,2,3,4]) + # f = t.find(2, :ifnone=>lambda{:NOPE}) { |a| a == 10 } + # f.assert == :NOPE + # end + #end + + method :grep do + end + + method :to_a do + test do + t = @PlusArray.new([1,2,3]) + t.to_a(4).assert == [5,6,7] + end + end + + # TODO: These two methods have issues! Any way to fix? + skip do + method :min do + test do + t = @PlusArray.new([1,2,3]) + + # test is failing. min has a variable number + # of arguments which makes it's .arity = -1. + # given the way this works for arity -1 + # the method always passes the single argument to + # the min method, and passes nothing to the each + # resulting it taking the X smallest values of the + # given and unchanged array + t.min(4).assert = 5 # returning [1,2,3] + end + end + + method :max do + # test is failing. max has a variable number of arguments which makes it + # .arity = -1. given the way this works for arity -1 the method + # always passes the single argument to the max method, and passes nothing + # to the each resulting it taking the X largest values of the given and + # unchanged array + test do + t = @PlusArray.new([1,2,3]) + t.max(4).assert == 7 + end + end + end + + method :include? do + test do + t = @PlusArray.new([1,2,3]) + t.assert.include?(7,4) + end + end + + method :select do + test do + t = @PlusArray.new([1,2,3]) + r = t.select(4){ |x| x == 6 } + r.assert == [6] + end + end + + method :reject do + test do + t = @PlusArray.new([1,2,3]) + r = t.reject(4){ |x| x == 6 } + r.assert == [5,7] + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_equitable.rb b/bin/gems/facets-3.1.0/test/standard/test_equitable.rb new file mode 100644 index 00000000..626af5d9 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_equitable.rb @@ -0,0 +1,46 @@ +require 'facets/equitable' + +test_case Equitable do + + c = Class.new + c.class_eval { + include Equitable(:a,:b) + attr_accessor :a, :b + } + + method :== do + test "equatable with arguments" do + c1,c2 = c.new,c.new + c1.a = 10; c1.b = 20 + c2.a = 10; c2.b = 20 + assert(c1 == c2) + + c1.a = 10; c1.b = 10 + c2.a = 10; c2.b = 20 + refute(c1 == c2) + + c1.a = 10; c1.b = 20 + c2.a = 20; c2.b = 20 + refute(c1 == c2) + end + end + +=begin + def test_equate_on_old + c = Class.new + c.class_eval { attr_accessor :a, :b ; equate_on :a,:b } + c1,c2 = c.new,c.new + c1.a = 10; c1.b = 20 + c2.a = 10; c2.b = 20 + assert_equal( c1, c2 ) + c1.a = 10; c1.b = 10 + c2.a = 10; c2.b = 20 + assert_not_equal( c1, c2 ) + c1.a = 10; c1.b = 20 + c2.a = 20; c2.b = 20 + assert_not_equal( c1, c2 ) + end +=end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/test_instantiable.rb b/bin/gems/facets-3.1.0/test/standard/test_instantiable.rb new file mode 100644 index 00000000..26979ead --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_instantiable.rb @@ -0,0 +1,40 @@ +require 'facets/instantiable' + +test_case Instantiable do + + setup do + @m = Module.new do + extend Instantiable + + attr :a + + def initialize( a ) + @a = a + end + end + + @n = Module.new do + include Instantiable + + attr :a + + def initialize( a ) + @a = a + end + end + end + + method :new do + test do + m = @m.new(1) + 1.assert == m.a + end + + test do + m = @n.new(1) + 1.assert == m.a + end + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/test_math.rb b/bin/gems/facets-3.1.0/test/standard/test_math.rb new file mode 100644 index 00000000..72f5959f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_math.rb @@ -0,0 +1,3 @@ +# test the math require +require 'facets/math' + diff --git a/bin/gems/facets-3.1.0/test/standard/test_memoizable.rb b/bin/gems/facets-3.1.0/test/standard/test_memoizable.rb new file mode 100644 index 00000000..93d9b2a0 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_memoizable.rb @@ -0,0 +1,42 @@ +covers 'facets/memoizable' + +test_case Memoizable do + + method :memoize do + + test "returns expected values" do + c = Class.new do + include Memoizable + def initialize(a) + @a = a + end + attr_accessor :a + memoize :a + end + + o = c.new("A") + o.a.assert == "A" + o.a = "B" + o.a.assert == "A" + end + + test "returns identical objects" do + c = Class.new do + include Memoizable + def initialize(a) + @a = a + end + attr_accessor :a + memoize :a + end + + o = c.new("A") + o.a.__id__.assert == o.a.__id__ + o.a = "B" + o.a.__id__.assert == o.a.__id__ + end + + end + +end + diff --git a/bin/gems/facets-3.1.0/test/standard/test_multipliers.rb b/bin/gems/facets-3.1.0/test/standard/test_multipliers.rb new file mode 100644 index 00000000..3dd2f91d --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_multipliers.rb @@ -0,0 +1,141 @@ +covers 'facets/multipliers' + +test_case Fixnum do + + method :deka do + test do + 1.deka.assert == 10 + end + end + + method :hecto do + test do + 1.hecto.assert == 100 + end + end + + method :kilo do + test do + 1.kilo.assert == 1000 + end + end + + method :mega do + test do + 1.mega.assert == 1000000 + end + end + + method :giga do + test do + 1.giga.assert == 1000000000 + end + end + + method :tera do + test do + 1.tera.assert == 1000000000000 + end + end + + method :peta do + test do + 1.peta.assert == 1000000000000000 + end + end + + method :exa do + test do + 1.exa.assert == 1000000000000000000 + end + end + + # Fractional + + method :deci do + test do + 1.deci.assert == 0.1 + end + end + + method :centi do + test do + 1.centi.assert == 0.01 + end + end + + method :milli do + test do + 1.milli.assert == 0.001 + end + end + + method :micro do + test do + 1.micro.assert == 0.000001 + end + end + + method :nano do + test do + 1.nano.assert == 0.000000001 + end + end + + method :pico do + test do + 1.pico.assert == 0.000000000001 + end + end + + method :femto do + test do + 1.femto.assert == 0.000000000000001 + end + end + + method :atto do + test do + 1.atto.assert == 0.000000000000000001 + end + end + + # SI Binary + + method :kibi do + test do + 1.kibi.assert == 1024 + end + end + + method :mebi do + test do + 1.mebi.assert == 1024**2 + end + end + + method :gibi do + test do + 1.gibi.assert == 1024**3 + end + end + + method :tebi do + test do + 1.tebi.assert == 1024**4 + end + end + + method :pebi do + test do + 1.pebi.assert == 1024**5 + end + end + + method :exbi do + test do + 1.exbi.assert == 1024**6 + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_ostruct.rb b/bin/gems/facets-3.1.0/test/standard/test_ostruct.rb new file mode 100644 index 00000000..5682522f --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_ostruct.rb @@ -0,0 +1,191 @@ +covers 'facets/ostruct' + +test_case OpenStruct do + + method :merge! do + test do + o = OpenStruct.new(:a => 1) + h = { :b => 2 } + o.merge!(h) + o.b.assert == 2 + end + + test do + o = OpenStruct.new( { :a => 1 } ) + h = { :b => 2 } + o.merge!(h) + o.b.assert == 2 + end + end + + method :__merge__ do + test do + o = OpenStruct.new( { :a => 1 } ) + h = { :b => 2 } + q = o.__merge__( h ) + q.a.assert == 1 + q.b.assert == 2 + end + + test do + o1 = OpenStruct.new( { :a => 1 } ) + o2 = OpenStruct.new( { :b => 2 } ) + q = o1.__merge__( o2 ) + q.a.assert == 1 + q.b.assert == 2 + end + + test "with_hash" do + o = OpenStruct.new( { :a => 1 } ) + h = { :b => 2 } + q = o.__merge__(h) + q.a.assert == 1 + q.b.assert == 2 + end + + test "two open structs" do + o1 = OpenStruct.new( { :a => 1 } ) + o2 = OpenStruct.new( { :b => 2 } ) + q = o1.__merge__(o2) + q.a.assert == 1 + q.b.assert == 2 + end + end + + # @deprecated + #method :instance_delegate do + # test "store" do + # o = OpenStruct.new(:a => 1) + # o.instance_delegate.store(:a,1) + # o.a.assert == 1 + # end + # + # test "update" do + # o = OpenStruct.new + # o.instance_delegate.update(:a=>1) + # o.a.assert == 1 + # end + #end + + method :[] do + test do + o = OpenStruct.new( { :a => 1 } ) + o[:a].assert == 1 + end + end + + method :[]= do + test do + o = OpenStruct.new( { :a => 1 } ) + o[:b] = 2 + o.b.assert == 2 + end + end + + class_method :new do + test "old functionality" do + o = OpenStruct.new + o.foo.assert.nil? + o.foo = :bar + o.foo.assert ==:bar + o.delete_field(:foo) + o.foo.assert.nil? + + o1 = OpenStruct.new(:x => 1, :z => 2) + o1.x.assert == 1 + o1.z.assert == 2 + + o2 = OpenStruct.new(:x => 1, :z => 2) + o1.assert == o2 + end + + test "via block" do + person = OpenStruct.new do |p| + p.name = 'John Smith' + p.gender = :M + p.age = 71 + end + person.name.assert == 'John Smith' + person.gender.assert ==:M + person.age.assert == 71 + person.address.assert ==nil + end + + test "via hash and block" do + person = OpenStruct.new(:gender => :M, :age => 71) do |p| + p.name = 'John Smith' + end + person.name.assert == 'John Smith' + person.gender.assert == :M + person.age.assert == 71 + person.address.assert == nil + end + + test "subclass via block" do + person_class = Class.new(OpenStruct) + person = person_class.new do |p| + p.name = 'John Smith' + p.gender = :M + p.age = 71 + end + person.name.assert == 'John Smith' + person.gender.assert == :M + person.age.assert == 71 + person.address.assert == nil + end + + test "subclass via hash and block" do + person_class = Class.new(OpenStruct) + person = person_class.new(:gender => :M, :age => 71) do |p| + p.name = 'John Smith' + end + person.name.assert == 'John Smith' + person.gender.assert == :M + person.age.assert == 71 + person.address.assert ==nil + end + end + +end + +test_case Hash do + + method :to_ostruct do + + test do + a = { :a => 1, :b => 2, :c => 3 } + ao = a.to_ostruct + ao.a.assert == a[:a] + ao.b.assert == a[:b] + ao.c.assert == a[:c] + end + + end + + method :to_ostruct_recurse do + + test do + a = { :a => 1, :b => 2, :c => { :x => 4 } } + ao = a.to_ostruct_recurse + ao.a.assert == a[:a] + ao.b.assert == a[:b] + ao.c.x.assert == a[:c][:x] + end + + test "with recursion" do + a = {} + a[:a] = a + ao = a.to_ostruct_recurse + ao.a.assert == ao + end + + test "advanced usage" do + h = { 'a' => { 'b' => 1 } } + o = h.to_ostruct_recurse( { h['a'] => h['a'] } ) + o.a['b'].assert == 1 + Hash.assert === o.a + end + + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_random.rb b/bin/gems/facets-3.1.0/test/standard/test_random.rb new file mode 100644 index 00000000..c0fabc63 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_random.rb @@ -0,0 +1,241 @@ +covers 'facets/random' + +test_case Random do + + class_method :letter do + test do + 100.times { |i| /[a-zA-z]/.assert =~ Random.letter } + end + end + +end + +test_case Range do + + # helper method + def assert_at_rand_table(table) + table.each do |x, y| + 20.times do + x.at_rand.assert == y + end + end + end + + # helper method + def assert_random_range(range) + 20.times do + range.assert.include?( range.at_rand ) + end + end + + method :at_rand do + + test "within range" do + list = [ 1..4, 1...4, 1.5..2.5, 1.5...2.5, -4..-1, -4...-1, + -2.5..-1.5, -2.5...-1.5, 'a'..'d', 'a'...'d' ] + list.each{ |rng| assert_random_range(rng) } + end + + test "within range special cases" do + assert_at_rand_table( + (5..5) => 5, + (5...5) => nil, + (5..-1) => nil, + (5.0..5.0) => 5.0, + (5.0...5.0) => nil, + (5.0...-1.0) => nil + ) + end + + test "reverse ranges" do + assert_at_rand_table( + (4..1) => nil, + (4...1) => nil, + (-1..-4) => nil, + (-1...-4) => nil + ) + #assert((1..4).include?((4..1).at_rand)) + #assert((-4...-1).include?((-1...-4).at_rand)) + #assert((-4..-1).include?((-1..-4).at_rand)) + end + + # I'd rather it return the first sentinel than +nil+. + # Really, ruby should be raising an error as an invalid range value. + test "exclusive range" do + (5...5).at_rand.assert == nil + #expect RangeError do + # (5...5).at_rand + #end + end + + end + +end + +test_case Array do + + method :at_rand do + test do + a = [1,2,3,4,5] + 20.times{ a.assert.include?( a.at_rand ) } + end + end + + method :at_rand! do + test do + a = ['a','b','c'] + a.at_rand!.length.assert == 1 + a.length.assert == 2 + end + end + + method :pick do + test do + a = ['a','b','c'] + a.pick(3).length.assert == 3 + a.length.assert == 3 + a = ['a','b','c'] + a.pick(4).length.assert == 3 + a.length.assert == 3 + end + end + + method :pick! do + test do + a = ['a','b','c'] + a.pick!(3).length.assert == 3 + a.length.assert == 0 + a = ['a','b','c'] + a.pick!(4).length.assert == 3 + a.length.assert == 0 + end + end + + method :rand_index do + test do + 10.times { + i = [1,2,3].rand_index + (0..2).assert.include?(i) + } + end + end + + method :rand_subset do + test do + 10.times { + a = [1,2,3,4].rand_subset + a.size.assert <= 4 + } + end + end + + method :shuffle do + test do + a = [1,2,3,4,5] + b = a.shuffle + b.sort.assert == a + end + end + + method :shuffle! do + test do + a = [1,2,3,4,5] + b = a.dup + b.shuffle! + b.sort.assert == a + end + end + +end + +test_case Hash do + + method :rand_key do + test do + h = { :a=>1, :b=>2, :c=>3 } + 10.times { h.keys.assert.include?( h.rand_key ) } + end + end + + method :rand_pair do + test do + h = { :a=>1, :b=>2, :c=>3 } + 10.times { k,v = *h.rand_pair; h[k].assert == v } + end + end + + method :rand_value do + test do + h = { :a=>1, :b=>2, :c=>3 } + 10.times { h.values.assert.include?( h.rand_value ) } + end + end + + method :shuffle do + test do + h = {:a=>1, :b=>2, :c=>3 } + h.shuffle + end + end + + method :shuffle! do + test do + h = {:a=>1, :b=>2, :c=>3 } + h.shuffle! + end + end + +end + +test_case String do + + method :at_rand do + test do + a = '12345' + 20.times{ a.assert.include?( a.at_rand ) } + end + end + + method :at_rand! do + test do + x = 'ab' + r = x.at_rand! + assert( r == 'a' || r == 'b' ) + assert( x == 'a' || x == 'b' ) + end + end + + method :rand_index do + test do + 10.times{ (0..2).assert.include?( 'abc'.rand_index ) } + end + end + + method :rand_byte do + test do + 2.times do + s = 'ab' + r = s.rand_byte + if RUBY_VERSION > '1.9' + assert( r == 'a' || r == 'b' ) + else + assert( r == 97 || r == 98 ) + end + end + end + end + + method :shuffle do + test do + "abc 123".shuffle + #"abc 123".shuffle! + end + end + + method :shuffle! do + test do + "abc 123".shuffle! + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_shellwords.rb b/bin/gems/facets-3.1.0/test/standard/test_shellwords.rb new file mode 100644 index 00000000..1776b616 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_shellwords.rb @@ -0,0 +1,74 @@ +covers 'facets/shellwords' + +test_case Shellwords do + + class_method :shellwords do + + test do + cmd = "ruby my_prog.rb | less" + Shellwords.shellwords(cmd).assert.instance_of?(Array) + Shellwords.shellwords(cmd).length.assert == 4 + end + + test "unmatched double quote" do + bad_cmd = 'one two "three' + expect ArgumentError do + Shellwords.shellwords(bad_cmd) + end + end + + test "unmatched single quote" do + bad_cmd = "one two 'three" + expect ArgumentError do + Shellwords.shellwords(bad_cmd) + end + end + + test "unmatched quotes" do + bad_cmd = "one '"'"''""'"" + expect ArgumentError do + Shellwords.shellwords(bad_cmd) + end + end + + end + +end + +test_case Array do + + method :shellwords do + test do + e = ["a", "b"] + a = ["a", "b"].shellwords + a.assert == e + end + + test do + e = ["-d", "a", "b"] + a = ["a", "b", {:d=>true}].shellwords + a.assert == e + end + end + +end + +test_case Hash do + + method :shellwords do + test do + e = ['--debug'] + a = {:debug=>true}.shellwords + a.assert == e + end + + test do + e = ['--name="jim"', '--debug'] + a = {:debug=>true, :name=>"jim"}.shellwords + a.each do |x| + e.assert.include?(x) + end + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_thread.rb b/bin/gems/facets-3.1.0/test/standard/test_thread.rb new file mode 100644 index 00000000..0aab4cc8 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_thread.rb @@ -0,0 +1,24 @@ +covers 'facets/thread.rb' + +test_case Array do + + method :threaded_map do + test do + r = [1,2,3].threaded_map{ |e| e + 1 } + r.assert == [2,3,4] + end + end + + method :threaded_map_send do + test do + r = [1,2,3].threaded_map_send(:+, 1) + r.assert == [2,3,4] + end + + test "with_block" do + r = [[1,2,3],[2,3,4],[3,4,5]].threaded_map_send(:select){ |x| x > 2 } + r.assert == [[3],[3,4],[3,4,5]] + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_timer.rb b/bin/gems/facets-3.1.0/test/standard/test_timer.rb new file mode 100644 index 00000000..a0186732 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_timer.rb @@ -0,0 +1,62 @@ +covers 'facets/timer' + +test_case Timer do + + class_method :time do + test "can keep time of a block" do + Timer.time do |timer| + timer.total_time.round.assert == 0 + sleep 1 + timer.total_time.round.assert == 1 + end + end + + test "can be stopped" do + Timer.time do |timer| + sleep 0.4 + timer.stop + sleep 0.6 + timer.total_time.round.assert == 0 + end + end + + test "timer can be started again" do + Timer.time do |timer| + timer.stop + sleep 0.5 + timer.total_time.round.assert == 0 + timer.start + sleep 1 + timer.total_time.round.assert == 1 + end + end + end + + method :start do + test "out of time" do + t = Timer.new(0.5) + expect Timeout::Error do + t.start + sleep 1 + t.stop + end + end + + test "in time" do + t = Timer.new(2) + t.start + sleep 0.5 + t.stop + end + end + + method :stop do + test "in time" do + t = Timer.new(2) + t.start + sleep 0.5 + t.stop + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_tuple.rb b/bin/gems/facets-3.1.0/test/standard/test_tuple.rb new file mode 100644 index 00000000..d5c0bdba --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_tuple.rb @@ -0,0 +1,68 @@ +covers 'facets/tuple' + +test_case Tuple do + + class_method :[] do + test "tuples with same content are the same object" do + t1 = Tuple[1,2,3] + t2 = Tuple[1,2,3] + t1.object_id.assert == t2.object_id + end + end + + method :< do + test do + t1 = Tuple[1,2,3] + t2 = Tuple[2,4,5] + t1.assert < t2 + end + end + + method :> do + test do + t1 = Tuple[1,2,3] + t2 = Tuple[2,4,5] + t2.assert > t1 + end + end + + method :to_a do + test do + t1 = Tuple[1,2,3] + a1 = t1.to_a + assert( Array === a1 ) + end + end + + method :<< do + test do + t1 = Tuple[1,2,3] + t1 = t1 << 4 + t1.assert.is_a? Tuple + t2 = Tuple[1,2,3,4] + t1.object_id.assert == t2.object_id + end + end + +end + +test_case String do + + method :to_t do + test do + t1 = "1.2.3".to_t + t1.assert.is_a? Tuple + t2 = Tuple[1,2,3] + t1.object_id.assert == t2.object_id + end + + test do + t1 = "1.2.3a".to_t + t1.assert.is_a? Tuple + t2 = Tuple[1,2,'3a'] + t1.assert == t2 + t1.object_id.assert == t2.object_id + end + end + +end diff --git a/bin/gems/facets-3.1.0/test/standard/test_uri.rb b/bin/gems/facets-3.1.0/test/standard/test_uri.rb new file mode 100644 index 00000000..8584d3b6 --- /dev/null +++ b/bin/gems/facets-3.1.0/test/standard/test_uri.rb @@ -0,0 +1,50 @@ +covers 'facets/uri' + +test_case URI do + + class_method :query do + test do + h = { :a=>1, :b=>2 } + r = URI.query(h) + assert(r == "a=1;b=2" || r == "b=2;a=1") + end + end + + # this is an alias of the above + class_method :hash_to_query do + test do + h = { :a=>1, :b=>2 } + r = URI.hash_to_query(h) + assert(r == "a=1;b=2" || r == "b=2;a=1") + end + end + +end + +test_case Object do + + method :uri do + test do + "abc%3Fxyz".assert == uri("abc?xyz") + end + end + + method :unuri do + test do + "abc?xyz".assert == unuri("abc%3Fxyz") + end + end + +end + +test_case Hash do + + method :to_uri do + test do + h = { :a=>1, :b=>2 } + r = h.to_uri + assert(r == "a=1;b=2" || r == "b=2;a=1") + end + end + +end diff --git a/bin/gems/faraday-2.9.0/CHANGELOG.md b/bin/gems/faraday-2.9.0/CHANGELOG.md new file mode 100644 index 00000000..c9bc56f9 --- /dev/null +++ b/bin/gems/faraday-2.9.0/CHANGELOG.md @@ -0,0 +1,574 @@ +# Faraday Changelog + +## The changelog has moved! + +This file is not being updated anymore. Instead, please check the [Releases](https://github.com/lostisland/faraday/releases) page. + +## [2.2.0](https://github.com/lostisland/faraday/compare/v2.1.0...v2.2.0) (2022-02-03) + +* Reintroduce the possibility to register middleware with symbols, strings or procs in [#1391](https://github.com/lostisland/faraday/pull/1391) + +## [2.1.0](https://github.com/lostisland/faraday/compare/v2.0.1...v2.1.0) (2022-01-15) + +* Fix test adapter thread safety by @iMacTia in [#1380](https://github.com/lostisland/faraday/pull/1380) +* Add default adapter options by @hirasawayuki in [#1382](https://github.com/lostisland/faraday/pull/1382) +* CI: Add Ruby 3.1 to matrix by @petergoldstein in [#1374](https://github.com/lostisland/faraday/pull/1374) +* docs: fix regex pattern in logger.md examples by @hirasawayuki in [#1378](https://github.com/lostisland/faraday/pull/1378) + +## [2.0.1](https://github.com/lostisland/faraday/compare/v2.0.0...v2.0.1) (2022-01-05) + +* Re-add `faraday-net_http` as default adapter by @iMacTia in [#1366](https://github.com/lostisland/faraday/pull/1366) +* Updated sample format in UPGRADING.md by @vimutter in [#1361](https://github.com/lostisland/faraday/pull/1361) +* docs: Make UPGRADING examples more copyable by @olleolleolle in [#1363](https://github.com/lostisland/faraday/pull/1363) + +## [2.0.0](https://github.com/lostisland/faraday/compare/v1.8.0...v2.0.0) (2022-01-04) + +The next major release is here, and it comes almost 2 years after the release of v1.0! + +This release changes the way you use Faraday and embraces a new paradigm of Faraday as an ecosystem, rather than a library. + +What does that mean? It means that Faraday is less of a bundled tool and more of a framework for the community to build on top of. + +As a result, all adapters and some middleware have moved out and are now shipped as standalone gems 🙌! + +But this doesn't mean that upgrading from Faraday 1.x to Faraday 2.0 should be hard, in fact we've listed everything you need to do in the [UPGRADING.md](https://github.com/lostisland/faraday/blob/main/UPGRADING.md) doc. + +Moreover, we've setup a new [awesome-faraday](https://github.com/lostisland/awesome-faraday) repository that will showcase a curated list of adapters and middleware 😎. + +This release was the result of the efforts of the core team and all the contributors, new and old, that have helped achieve this milestone 👏. + +## What's Changed + +* Autoloading, dependency loading and middleware registry cleanup by @iMacTia in [#1301](https://github.com/lostisland/faraday/pull/1301) +* Move JSON middleware (request and response) from faraday_middleware by @iMacTia in [#1300](https://github.com/lostisland/faraday/pull/1300) +* Remove deprecated `Faraday::Request#method` by @olleolleolle in [#1303](https://github.com/lostisland/faraday/pull/1303) +* Remove deprecated `Faraday::UploadIO` by @iMacTia in [#1307](https://github.com/lostisland/faraday/pull/1307) +* [1.x] Deprecate Authorization helpers in `Faraday::Connection` by @iMacTia in [#1306](https://github.com/lostisland/faraday/pull/1306) +* Drop deprecated auth helpers from Connection and refactor auth middleware by @iMacTia in [#1308](https://github.com/lostisland/faraday/pull/1308) +* Add Faraday 1.x examples in authentication.md docs by @iMacTia in [#1320](https://github.com/lostisland/faraday/pull/1320) +* Fix passing a URL with embedded basic auth by @iMacTia in [#1324](https://github.com/lostisland/faraday/pull/1324) +* Register JSON middleware by @mollerhoj in [#1331](https://github.com/lostisland/faraday/pull/1331) +* Retry middleware should handle string exception class name consistently by @jrochkind in [#1334](https://github.com/lostisland/faraday/pull/1334) +* Improve request info in exceptions raised by RaiseError Middleware by @willianzocolau in [#1335](https://github.com/lostisland/faraday/pull/1335) +* Remove net-http adapter and update docs by @iMacTia in [#1336](https://github.com/lostisland/faraday/pull/1336) +* Explain plan for faraday_middleware in UPGRADING.md by @iMacTia in [#1339](https://github.com/lostisland/faraday/pull/1339) +* Scripts folder cleanup by @iMacTia in [#1340](https://github.com/lostisland/faraday/pull/1340) +* Replace `Hash#merge` with `Utils#deep_merge` for connection options by @xkwd in [#1343](https://github.com/lostisland/faraday/pull/1343) +* Callable authorizers by @sled in [#1345](https://github.com/lostisland/faraday/pull/1345) +* Default value for exc error by @DariuszMusielak in [#1351](https://github.com/lostisland/faraday/pull/1351) +* Don't call `retry_block` unless a retry is going to happen by @jrochkind in [#1350](https://github.com/lostisland/faraday/pull/1350) +* Improve documentation for v2 by @iMacTia in [#1353](https://github.com/lostisland/faraday/pull/1353) +* Remove default `default_adapter` (yes, you read that right) by @iMacTia in [#1354](https://github.com/lostisland/faraday/pull/1354) +* Remove retry middleware by @iMacTia in [#1356](https://github.com/lostisland/faraday/pull/1356) +* Remove multipart middleware and all its documentation and tests by @iMacTia in [#1357](https://github.com/lostisland/faraday/pull/1357) + +## [1.9.3](https://github.com/lostisland/faraday/compare/v1.9.2...v1.9.3) (2022-01-06) + +* Re-add support for Ruby 2.4+ by @iMacTia in [#1371](https://github.com/lostisland/faraday/pull/1371) + +## [1.9.2](https://github.com/lostisland/faraday/compare/v1.9.1...v1.9.2) (2022-01-06) + +* Add alias with legacy name to gemified middleware by @iMacTia in [#1372](https://github.com/lostisland/faraday/pull/1372) + +## [1.9.1](https://github.com/lostisland/faraday/compare/v1.9.0...v1.9.1) (2022-01-06) + +* Update adapter dependencies in Gemspec by @iMacTia in [#1370](https://github.com/lostisland/faraday/pull/1370) + +## [1.9.0](https://github.com/lostisland/faraday/compare/v1.8.0...v1.9.0) (2022-01-06) + +* Use external multipart and retry middleware by @iMacTia in [#1367](https://github.com/lostisland/faraday/pull/1367) + +## [1.8.0](https://github.com/lostisland/faraday/releases/tag/v1.8.0) (2021-09-18) + +### Features + +* Backport authorization procs (#1322, @jarl-dk) + +## [v1.7.0](https://github.com/lostisland/faraday/releases/tag/v1.7.0) (2021-08-09) + +### Features + +* Add strict_mode to Test::Stubs (#1298, @yykamei) + +## [v1.6.0](https://github.com/lostisland/faraday/releases/tag/v1.6.0) (2021-08-01) + +### Misc + +* Use external Rack adapter (#1296, @iMacTia) + +## [v1.5.1](https://github.com/lostisland/faraday/releases/tag/v1.5.1) (2021-07-11) + +### Fixes + +* Fix JRuby incompatibility after moving out EM adapters (#1294, @ahorek) + +### Documentation + +* Update YARD to follow RackBuilder (#1292, @kachick) + +## [v1.5.0](https://github.com/lostisland/faraday/releases/tag/v1.5.0) (2021-07-04) + +### Misc + +* Use external httpclient adapter (#1289, @iMacTia) +* Use external patron adapter (#1290, @iMacTia) + +## [v1.4.3](https://github.com/lostisland/faraday/releases/tag/v1.4.3) (2021-06-24) + +### Fixes + +* Silence warning (#1286, @gurgeous) +* Always dup url_prefix in Connection#build_exclusive_url (#1288, @alexeyds) + +## [v1.4.2](https://github.com/lostisland/faraday/releases/tag/v1.4.2) (2021-05-22) + +### Fixes +* Add proxy setting when url_prefix is changed (#1276, @ci) +* Default proxy scheme to http:// if necessary, fixes #1282 (#1283, @gurgeous) + +### Documentation +* Improve introduction page (#1273, @gurgeous) +* Docs: add more middleware examples (#1277, @gurgeous) + +### Misc +* Use external `em_http` and `em_synchrony` adapters (#1274, @iMacTia) + +## [v1.4.1](https://github.com/lostisland/faraday/releases/tag/v1.4.1) (2021-04-18) + +### Fixes + +* Fix dependencies from external adapter gems (#1269, @iMacTia) + +## [v1.4.0](https://github.com/lostisland/faraday/releases/tag/v1.4.0) (2021-04-16) + +### Highlights + +With this release, we continue the work of gradually moving out adapters into their own gems 🎉 +Thanks to @MikeRogers0 for helping the Faraday team in progressing with this quest 👏 + +And thanks to @olleolleolle efforts, Faraday is becoming more inclusive than ever 🤗 +Faraday's `master` branch has been renamed into `main`, we have an official policy on inclusive language and even a rubocop plugin to check for non-inclusive words ❤️! +Checkout the "Misc" section below for more details 🙌 ! + +### Fixes + +* Fix NoMethodError undefined method 'coverage' (#1255, @Maroo-b) + +### Documentation + +* Some docs on EventMachine adapters. (#1232, @damau) +* CONTRIBUTING: Fix grammar and layout (#1261, @olleolleolle) + +### Misc + +* Replacing Net::HTTP::Persistent with faraday-net_http_persistent (#1250, @MikeRogers0) +* CI: Configure the regenerated Coveralls token (#1256, @olleolleolle) +* Replace Excon adapter with Faraday::Excon gem, and fix autoloading issue with Faraday::NetHttpPersistent (#1257, @iMacTia) +* Drop CodeClimate (#1259, @olleolleolle) +* CI: Rename default branch to main (#1263, @olleolleolle) +* Drop RDoc support file .document (#1264, @olleolleolle, @iMacTia) +* CONTRIBUTING: add a policy on inclusive language (#1262, @olleolleolle) +* Add rubocop-inclusivity (#1267, @olleolleolle, @iMacTia) + +## [v1.3.1](https://github.com/lostisland/faraday/releases/tag/v1.3.1) (2021-04-16) + +### Fixes + +* Escape colon in path segment (#1237, @yarafan) +* Handle IPv6 address String on Faraday::Connection#proxy_from_env (#1252, @cosmo0920) + +### Documentation + +* Fix broken Rubydoc.info links (#1236, @nickcampbell18) +* Add httpx to list of external adapters (#1246, @HoneyryderChuck) + +### Misc + +* Refactor CI to remove duplicated line (#1230, @tricknotes) +* Gemspec: Pick a good ruby2_keywords release (#1241, @olleolleolle) + +## [v1.3.0](https://github.com/lostisland/faraday/releases/tag/v1.3.0) (2020-12-31) + +### Highlights +Faraday v1.3.0 is the first release to officially support Ruby 3.0 in the CI pipeline 🎉 🍾! + +This is also the first release with a previously "included" adapter (Net::HTTP) being isolated into a [separate gem](https://github.com/lostisland/faraday-net_http) 🎊! +The new adapter is added to Faraday as a dependency for now, so that means full backwards-compatibility, but just to be safe be careful when upgrading! + +This is a huge step towards are Faraday v2.0 objective of pushing adapters and middleware into separate gems. +Many thanks to the Faraday Team, @JanDintel and everyone who attended the [ROSS Conf remote event](https://www.rossconf.io/event/remote/) + +### Features + +* Improves consistency with Faraday::Error and Faraday::RaiseError (#1229, @qsona, @iMacTia) + +### Fixes + +* Don't assign to global ::Timer (#1227, @bpo) + +### Documentation + +* CHANGELOG: add releases after 1.0 (#1225, @olleolleolle) +* Improves retry middleware documentation. (#1228, @iMacTia) + +### Misc + +* Move out Net::HTTP adapter (#1222, @JanDintel, @iMacTia) +* Adds Ruby 3.0 to CI Matrix (#1226, @iMacTia) + + +## [v1.2.0](https://github.com/lostisland/faraday/releases/tag/v1.2.0) (2020-12-23) + +### Features + +* Introduces `on_request` and `on_complete` methods in `Faraday::Middleware`. (#1194, @iMacTia) + +### Fixes + +* Require 'date' to avoid retry exception (#1206, @rustygeldmacher) +* Fix rdebug recursion issue (#1205, @native-api) +* Update call to `em_http_ssl_patch` (#1202, @kylekeesling) +* `EmHttp` adapter: drop superfluous loaded? check (#1213, @olleolleolle) +* Avoid 1 use of keyword hackery (#1211, @grosser) +* Fix #1219 `Net::HTTP` still uses env proxy (#1221, @iMacTia) + +### Documentation + +* Add comment in gemspec to explain exposure of `examples` and `spec` folders. (#1192, @iMacTia) +* Adapters, how to create them (#1193, @olleolleolle) +* Update documentation on using the logger (#1196, @tijmenb) +* Adjust the retry documentation and spec to align with implementation (#1198, @nbeyer) + +### Misc + +* Test against ruby head (#1208, @grosser) + +## [v1.1.0](https://github.com/lostisland/faraday/releases/tag/v1.1.0) (2020-10-17) + +### Features + +* Makes parameters sorting configurable (#1162 @wishdev) +* Introduces `flat_encode` option for multipart adapter. (#1163 @iMacTia) +* Include request info in exceptions raised by RaiseError Middleware (#1181 @SandroDamilano) + +### Fixes + +* Avoid `last arg as keyword param` warning when building user middleware on Ruby 2.7 (#1153 @dgholz) +* Limits net-http-persistent version to < 4.0 (#1156 @iMacTia) +* Update `typhoeus` to new stable version (`1.4`) (#1159 @AlexWayfer) +* Properly fix test failure with Rack 2.1+. (#1171 @voxik) + +### Documentation + +* Improves documentation on how to contribute to the site by using Docker. (#1175 @iMacTia) +* Remove retry_change_requests from documentation (#1185 @stim371) + +### Misc + +* Link from GitHub Actions badge to CI workflow (#1141 @olleolleolle) +* Return tests of `Test` adapter (#1147 @AlexWayfer) +* Add 1.0 release to wording in CONTRIBUTING (#1155 @olleolleolle) +* Fix linting bumping Rubocop to 0.90.0 (#1182 @iMacTia) +* Drop `git ls-files` in gemspec (#1183 @utkarsh2102) +* Upgrade CI to ruby/setup-ruby (#1187 @gogainda) + +## [v1.0.1](https://github.com/lostisland/faraday/releases/tag/v1.0.1) (2020-03-29) + +### Fixes + +* Use Net::HTTP#start(&block) to ensure closed TCP connections (#1117) +* Fully qualify constants to be checked (#1122) +* Allows `parse` method to be private/protected in response middleware (#1123) +* Encode Spaces in Query Strings as '%20' Instead of '+' (#1125) +* Limits rack to v2.0.x (#1127) +* Adapter Registry reads also use mutex (#1136) + +### Documentation + +* Retry middleware documentation fix (#1109) +* Docs(retry): precise usage of retry-after (#1111) +* README: Link the logo to the website (#1112) +* Website: add search bar (#1116) +* Fix request/response mix-up in docs text (#1132) + +## [v1.0](https://github.com/lostisland/faraday/releases/tag/v1.0.0) (2020-01-22) + +Features: + +* Add #trace support to Faraday::Connection #861 (@technoweenie) +* Add the log formatter that is easy to override and safe to inherit #889 (@prikha) +* Support standalone adapters #941 (@iMacTia) +* Introduce Faraday::ConflictError for 409 response code #979 (@lucasmoreno) +* Add support for setting `read_timeout` option separately #1003 (@springerigor) +* Refactor and cleanup timeout settings across adapters #1022 (@technoweenie) +* Create ParamPart class to allow multipart posts with JSON content and file upload at the same time #1017 (@jeremy-israel) +* Copy UploadIO const -> FilePart for consistency with ParamPart #1018, #1021 (@technoweenie) +* Implement streaming responses in the Excon adapter #1026 (@technoweenie) +* Add default implementation of `Middleware#close`. #1069 (@ioquatix) +* Add `Adapter#close` so that derived classes can call super. #1091 (@ioquatix) +* Add log_level option to logger default formatter #1079 (@amrrbakry) +* Fix empty array for FlatParamsEncoder `{key: []} -> "key="` #1084 (@mrexox) + +Bugs: + +* Explicitly require date for DateTime library in Retry middleware #844 (@nickpresta) +* Refactor Adapter as final endpoints #846 (@iMacTia) +* Separate Request and Response bodies in Faraday::Env #847 (@iMacTia) +* Implement Faraday::Connection#options to make HTTP requests with the OPTIONS verb. #857 (@technoweenie) +* Multipart: Drop Ruby 1.8 String behavior compat #892 (@olleolleolle) +* Fix Ruby warnings in Faraday::Options.memoized #962 (@technoweenie) +* Allow setting min/max SSL version for a Net::HTTP::Persistent connection #972, #973 (@bdewater, @olleolleolle) +* Fix instances of frozen empty string literals #1040 (@BobbyMcWho) +* remove temp_proxy and improve proxy tests #1063 (@technoweenie) +* improve error initializer consistency #1095 (@technoweenie) + +Misc: + +* Convert minitest suite to RSpec #832 (@iMacTia, with help from @gaynetdinov, @Insti, @technoweenie) +* Major effort to update code to RuboCop standards. #854 (@olleolleolle, @iMacTia, @technoweenie, @htwroclau, @jherdman, @Drenmi, @Insti) +* Rubocop #1044, #1047 (@BobbyMcWho, @olleolleolle) +* Documentation tweaks (@adsteel, @Hubro, @iMacTia, @olleolleolle, @technoweenie) +* Update license year #981 (@Kevin-Kawai) +* Configure Jekyll plugin jekyll-remote-theme to support Docker usage #999 (@Lewiscowles1986) +* Fix Ruby 2.7 warnings #1009 (@tenderlove) +* Cleanup adapter connections #1023 (@technoweenie) +* Describe clearing cached stubs #1045 (@viraptor) +* Add project metadata to the gemspec #1046 (@orien) + +## v0.17.4 + +Fixes: + +* NetHttp adapter: wrap Errno::EADDRNOTAVAIL (#1114, @embs) +* Fix === for subclasses of deprecated classes (#1243, @mervync) + +## v0.17.3 + +Fixes: + +* Reverts changes in error classes hierarchy. #1092 (@iMacTia) +* Fix Ruby 1.9 syntax errors and improve Error class testing #1094 (@BanzaiMan, + @mrexox, @technoweenie) + +Misc: + +* Stops using `&Proc.new` for block forwarding. #1083 (@olleolleolle) +* Update CI to test against ruby 2.0-2.7 #1087, #1099 (@iMacTia, @olleolleolle, + @technoweenie) +* require FARADAY_DEPRECATE=warn to show Faraday v1.0 deprecation warnings + #1098 (@technoweenie) + +## v0.17.1 + +Final release before Faraday v1.0, with important fixes for Ruby 2.7. + +Fixes: + +* RaiseError response middleware raises exception if HTTP client returns a nil + status. #1042 (@jonnyom, @BobbyMcWho) + +Misc: + +* Fix Ruby 2.7 warnings (#1009) +* Add `Faraday::Deprecate` to warn about upcoming v1.0 changes. (#1054, #1059, + #1076, #1077) +* Add release notes up to current in CHANGELOG.md (#1066) +* Port minimal rspec suite from main branch to run backported tests. (#1058) + +## v0.17.0 + +This release is the same as v0.15.4. It was pushed to cover up releases +v0.16.0-v0.16.2. + +## v0.15.4 + +* Expose `pool_size` as a option for the NetHttpPersistent adapter (#834) + +## v0.15.3 + +* Make Faraday::Request serialisable with Marshal. (#803) +* Add DEFAULT_EXCEPTIONS constant to Request::Retry (#814) +* Add support for Ruby 2.6 Net::HTTP write_timeout (#824) + +## v0.15.2 + +* Prevents `Net::HTTP` adapters to retry request internally by setting `max_retries` to 0 if available (Ruby 2.5+). (#799) +* Fixes `NestedParamsEncoder` handling of empty array values (#801) + +## v0.15.1 + +* NetHttpPersistent adapter better reuse of SSL connections (#793) +* Refactor: inline cached_connection (#797) +* Logger middleware: use $stdout instead of STDOUT (#794) +* Fix: do not memoize/reuse Patron session (#796) + +Also in this release: + +* Allow setting min/max ssl version for Net::HTTP (#792) +* Allow setting min/max ssl version for Excon (#795) + +## v0.15.0 + +Features: + +* Added retry block option to retry middleware. (#770) +* Retry middleware improvements (honour Retry-After header, retry statuses) (#773) +* Improve response logger middleware output (#784) + +Fixes: + +* Remove unused class error (#767) +* Fix minor typo in README (#760) +* Reuse persistent connections when using net-http-persistent (#778) +* Fix Retry middleware documentation (#781) +* Returns the http response when giving up on retrying by status (#783) + +## v0.14.0 + +Features: + +* Allow overriding env proxy #754 (@iMacTia) +* Remove legacy Typhoeus adapter #715 (@olleolleolle) +* External Typhoeus Adapter Compatibility #748 (@iMacTia) +* Warn about missing adapter when making a request #743 (@antstorm) +* Faraday::Adapter::Test stubs now support entire urls (with host) #741 (@erik-escobedo) + +Fixes: + +* If proxy is manually provided, this takes priority over `find_proxy` #724 (@iMacTia) +* Fixes the behaviour for Excon's open_timeout (not setting write_timeout anymore) #731 (@apachelogger) +* Handle all connection timeout messages in Patron #687 (@stayhero) + +## v0.13.1 + +* Fixes an incompatibility with Addressable::URI being used as uri_parser + +## v0.13.0 + +Features: + +* Dynamically reloads the proxy when performing a request on an absolute domain (#701) +* Adapter support for Net::HTTP::Persistent v3.0.0 (#619) + +Fixes: + +* Prefer #hostname over #host. (#714) +* Fixes an edge-case issue with response headers parsing (missing HTTP header) (#719) + +## v0.12.2 + +* Parse headers from aggregated proxy requests/responses (#681) +* Guard against invalid middleware configuration with warning (#685) +* Do not use :insecure option by default in Patron (#691) +* Fixes an issue with HTTPClient not raising a `Faraday::ConnectionFailed` (#702) +* Fixes YAML serialization/deserialization for `Faraday::Utils::Headers` (#690) +* Fixes an issue with Options having a nil value (#694) +* Fixes an issue with Faraday.default_connection not using Faraday.default_connection_options (#698) +* Fixes an issue with Options.merge! and Faraday instrumentation middleware (#710) + +## v0.12.1 + +* Fix an issue with Patron tests failing on jruby +* Fix an issue with new `rewind_files` feature that was causing an exception when the body was not an Hash +* Expose wrapped_exception in all client errors +* Add Authentication Section to the ReadMe + +## v0.12.0.1 + +* Hotfix release to address an issue with TravisCI deploy on Rubygems + +## v0.12.0 + +Features: + +* Proxy feature now relies on Ruby `URI::Generic#find_proxy` and can use `no_proxy` ENV variable (not compatible with ruby < 2.0) +* Adds support for `context` request option to pass arbitrary information to middlewares + +Fixes: + +* Fix an issue with options that was causing new options to override defaults ones unexpectedly +* Rewind `UploadIO`s on retry to fix a compatibility issue +* Make multipart boundary unique +* Improvements in `README.md` + +## v0.11.0 + +Features: + +* Add `filter` method to Logger middleware +* Add support for Ruby2.4 and Minitest 6 +* Introduce block syntax to customise the adapter + +Fixes: + +* Fix an issue that was allowing to override `default_connection_options` from a connection instance +* Fix a bug that was causing newline escape characters ("\n") to be used when building the Authorization header + +## v0.10.1 + +- Fix an issue with HTTPClient adapter that was causing the SSL to be reset on every request +- Rescue `IOError` instead of specific subclass +- `Faraday::Utils::Headers` can now be successfully serialised in YAML +- Handle `default_connection_options` set with hash + +## v0.10.0 + +Breaking changes: +- Drop support for Ruby 1.8 + +Features: +- Include wrapped exception/reponse in ClientErrors +- Add `response.reason_phrase` +- Provide option to selectively skip logging request/response headers +- Add regex support for pattern matching in `test` adapter + +Fixes: +- Add `Faraday.respond_to?` to find methods managed by `method_missing` +- em-http: `request.host` instead of `connection.host` should be taken for SSL validations +- Allow `default_connection_options` to be merged when options are passed as url parameter +- Improve splitting key-value pairs in raw HTTP headers + +## v0.9.2 + +Adapters: +- Enable gzip compression for httpclient +- Fixes default certificate store for httpclient not having default paths. +- Make excon adapter compatible with 0.44 excon version +- Add compatibility with Patron 0.4.20 +- Determine default port numbers in Net::HTTP adapters (Addressable compatibility) +- em-http: wrap "connection closed by server" as ConnectionFailed type +- Wrap Errno::ETIMEDOUT in Faraday::Error::TimeoutError + +Utils: +- Add Rack-compatible support for parsing `a[][b]=c` nested queries +- Encode nil values in queries different than empty strings. Before: `a=`; now: `a`. +- Have `Faraday::Utils::Headers#replace` clear internal key cache +- Dup the internal key cache when a Headers hash is copied + +Env and middleware: +- Ensure `env` stored on middleware response has reference to the response +- Ensure that Response properties are initialized during `on_complete` (VCR compatibility) +- Copy request options in Faraday::Connection#dup +- Env custom members should be copied by Env.from(env) +- Honour per-request `request.options.params_encoder` +- Fix `interval_randomness` data type for Retry middleware +- Add maximum interval option for Retry middleware + +## v0.9.1 + +* Refactor Net:HTTP adapter so that with_net_http_connection can be overridden to allow pooled connections. (@Ben-M) +* Add configurable methods that bypass `retry_if` in the Retry request middleware. (@mike-bourgeous) + +## v0.9.0 + +* Add HTTPClient adapter (@hakanensari) +* Improve Retry handler (@mislav) +* Remove autoloading by default (@technoweenie) +* Improve internal docs (@technoweenie, @mislav) +* Respect user/password in http proxy string (@mislav) +* Adapter options are structs. Reinforces consistent options across adapters + (@technoweenie) +* Stop stripping trailing / off base URLs in a Faraday::Connection. (@technoweenie) +* Add a configurable URI parser. (@technoweenie) +* Remove need to manually autoload when using the authorization header helpers on `Faraday::Connection`. (@technoweenie) +* `Faraday::Adapter::Test` respects the `Faraday::RequestOptions#params_encoder` option. (@technoweenie) diff --git a/bin/gems/faraday-2.9.0/LICENSE.md b/bin/gems/faraday-2.9.0/LICENSE.md new file mode 100644 index 00000000..38776159 --- /dev/null +++ b/bin/gems/faraday-2.9.0/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2009-2023 Rick Olson, Zack Hobson + +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/bin/gems/faraday-2.9.0/README.md b/bin/gems/faraday-2.9.0/README.md new file mode 100644 index 00000000..0cca6db8 --- /dev/null +++ b/bin/gems/faraday-2.9.0/README.md @@ -0,0 +1,67 @@ +# [![Faraday](./docs/_media/home-logo.svg)][website] + +[![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday) +[![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI) +[![GitHub Discussions](https://img.shields.io/github/discussions/lostisland/faraday?logo=github)](https://github.com/lostisland/faraday/discussions) + +Faraday is an HTTP client library abstraction layer that provides a common interface over many +adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle. +Take a look at [Awesome Faraday][awesome] for a list of available adapters and middleware. + +## Why use Faraday? + +Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses, +making it easier to build sophisticated API clients or web service libraries that abstract away +the details of how HTTP requests are made. + +Faraday comes with a lot of features out of the box, such as: +* Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more) +* Persistent connections (keep-alive) +* Parallel requests +* Automatic response parsing (JSON, XML, YAML) +* Customization of the request/response cycle with middleware +* Support for streaming responses +* Support for uploading files +* And much more! + +## Getting Started + +The best starting point is the [Faraday Website][website], with its introduction and explanation. + +Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally, or take a look at [Advanced techniques for calling HTTP APIs in Ruby](https://mattbrictson.com/blog/advanced-http-techniques-in-ruby) blog post from [@mattbrictson](https://github.com/mattbrictson) 🚀 + +## Supported Ruby versions + +This library aims to support and is [tested against][actions] the currently officially supported Ruby +implementations. This means that, even without a major release, we could add or drop support for Ruby versions, +following their [EOL](https://endoflife.date/ruby). +Currently that means we support Ruby 3.0+ + +If something doesn't work on one of these Ruby versions, it's a bug. + +This library may inadvertently work (or seem to work) on other Ruby +implementations and versions, however support will only be provided for the versions listed +above. + +If you would like this library to support another Ruby version, you may +volunteer to be a maintainer. Being a maintainer entails making sure all tests +run and pass on that implementation. When something breaks on your +implementation, you will be responsible for providing patches in a timely +fashion. If critical issues for a particular implementation exist at the time +of a major release, support for that Ruby version may be dropped. + +## Contribute + +Do you want to contribute to Faraday? +Open the issues page and check for the `help wanted` label! +But before you start coding, please read our [Contributing Guide][contributing] + +## Copyright + +© 2009 - 2023, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design). + +[awesome]: https://github.com/lostisland/awesome-faraday/#adapters +[website]: https://lostisland.github.io/faraday +[contributing]: https://github.com/lostisland/faraday/blob/main/.github/CONTRIBUTING.md +[apidoc]: https://www.rubydoc.info/github/lostisland/faraday +[actions]: https://github.com/lostisland/faraday/actions diff --git a/bin/gems/faraday-2.9.0/Rakefile b/bin/gems/faraday-2.9.0/Rakefile new file mode 100644 index 00000000..4339ceee --- /dev/null +++ b/bin/gems/faraday-2.9.0/Rakefile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) do |task| + task.ruby_opts = %w[-W] +end + +task default: :spec diff --git a/bin/gems/faraday-2.9.0/examples/client_spec.rb b/bin/gems/faraday-2.9.0/examples/client_spec.rb new file mode 100644 index 00000000..e30d86f7 --- /dev/null +++ b/bin/gems/faraday-2.9.0/examples/client_spec.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +# Requires Ruby with rspec and faraday gems. +# rspec client_spec.rb + +require 'faraday' +require 'json' + +# Example API client +class Client + def initialize(conn) + @conn = conn + end + + def httpbingo(jname, params: {}) + res = @conn.get("/#{jname}", params) + data = JSON.parse(res.body) + data['origin'] + end + + def foo(params) + res = @conn.post('/foo', JSON.dump(params)) + res.status + end +end + +RSpec.describe Client do + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } } + let(:client) { Client.new(conn) } + + it 'parses origin' do + stubs.get('/ip') do |env| + # optional: you can inspect the Faraday::Env + expect(env.url.path).to eq('/ip') + [ + 200, + { 'Content-Type': 'application/javascript' }, + '{"origin": "127.0.0.1"}' + ] + end + + # uncomment to trigger stubs.verify_stubbed_calls failure + # stubs.get('/unused') { [404, {}, ''] } + + expect(client.httpbingo('ip')).to eq('127.0.0.1') + stubs.verify_stubbed_calls + end + + it 'handles 404' do + stubs.get('/api') do + [ + 404, + { 'Content-Type': 'application/javascript' }, + '{}' + ] + end + expect(client.httpbingo('api')).to be_nil + stubs.verify_stubbed_calls + end + + it 'handles exception' do + stubs.get('/api') do + raise Faraday::ConnectionFailed + end + + expect { client.httpbingo('api') }.to raise_error(Faraday::ConnectionFailed) + stubs.verify_stubbed_calls + end + + context 'When the test stub is run in strict_mode' do + let(:stubs) { Faraday::Adapter::Test::Stubs.new(strict_mode: true) } + + it 'verifies the all parameter values are identical' do + stubs.get('/api?abc=123') do + [ + 200, + { 'Content-Type': 'application/javascript' }, + '{"origin": "127.0.0.1"}' + ] + end + + # uncomment to raise Stubs::NotFound + # expect(client.httpbingo('api', params: { abc: 123, foo: 'Kappa' })).to eq('127.0.0.1') + expect(client.httpbingo('api', params: { abc: 123 })).to eq('127.0.0.1') + stubs.verify_stubbed_calls + end + end + + context 'When the Faraday connection is configured with FlatParamsEncoder' do + let(:conn) { Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) { |b| b.adapter(:test, stubs) } } + + it 'handles the same multiple URL parameters' do + stubs.get('/api?a=x&a=y&a=z') { [200, { 'Content-Type' => 'application/json' }, '{"origin": "127.0.0.1"}'] } + + # uncomment to raise Stubs::NotFound + # expect(client.httpbingo('api', params: { a: %w[x y] })).to eq('127.0.0.1') + expect(client.httpbingo('api', params: { a: %w[x y z] })).to eq('127.0.0.1') + stubs.verify_stubbed_calls + end + end + + context 'When you want to test the body, you can use a proc as well as string' do + it 'tests with a string' do + stubs.post('/foo', '{"name":"YK"}') { [200, {}, ''] } + + expect(client.foo(name: 'YK')).to eq 200 + stubs.verify_stubbed_calls + end + + it 'tests with a proc' do + check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } } + stubs.post('/foo', check) { [200, {}, ''] } + + expect(client.foo(name: 'YK', created_at: Time.now)).to eq 200 + stubs.verify_stubbed_calls + end + end +end diff --git a/bin/gems/faraday-2.9.0/examples/client_test.rb b/bin/gems/faraday-2.9.0/examples/client_test.rb new file mode 100644 index 00000000..3aad9576 --- /dev/null +++ b/bin/gems/faraday-2.9.0/examples/client_test.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +# Requires Ruby with test-unit and faraday gems. +# ruby client_test.rb + +require 'faraday' +require 'json' +require 'test/unit' + +# Example API client +class Client + def initialize(conn) + @conn = conn + end + + def httpbingo(jname, params: {}) + res = @conn.get("/#{jname}", params) + data = JSON.parse(res.body) + data['origin'] + end + + def foo(params) + res = @conn.post('/foo', JSON.dump(params)) + res.status + end +end + +# Example API client test +class ClientTest < Test::Unit::TestCase + def test_httpbingo_name + stubs = Faraday::Adapter::Test::Stubs.new + stubs.get('/api') do |env| + # optional: you can inspect the Faraday::Env + assert_equal '/api', env.url.path + [ + 200, + { 'Content-Type': 'application/javascript' }, + '{"origin": "127.0.0.1"}' + ] + end + + # uncomment to trigger stubs.verify_stubbed_calls failure + # stubs.get('/unused') { [404, {}, ''] } + + cli = client(stubs) + assert_equal '127.0.0.1', cli.httpbingo('api') + stubs.verify_stubbed_calls + end + + def test_httpbingo_not_found + stubs = Faraday::Adapter::Test::Stubs.new + stubs.get('/api') do + [ + 404, + { 'Content-Type': 'application/javascript' }, + '{}' + ] + end + + cli = client(stubs) + assert_nil cli.httpbingo('api') + stubs.verify_stubbed_calls + end + + def test_httpbingo_exception + stubs = Faraday::Adapter::Test::Stubs.new + stubs.get('/api') do + raise Faraday::ConnectionFailed + end + + cli = client(stubs) + assert_raise Faraday::ConnectionFailed do + cli.httpbingo('api') + end + stubs.verify_stubbed_calls + end + + def test_strict_mode + stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true) + stubs.get('/api?abc=123') do + [ + 200, + { 'Content-Type': 'application/javascript' }, + '{"origin": "127.0.0.1"}' + ] + end + + cli = client(stubs) + assert_equal '127.0.0.1', cli.httpbingo('api', params: { abc: 123 }) + + # uncomment to raise Stubs::NotFound + # assert_equal '127.0.0.1', cli.httpbingo('api', params: { abc: 123, foo: 'Kappa' }) + stubs.verify_stubbed_calls + end + + def test_non_default_params_encoder + stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true) + stubs.get('/api?a=x&a=y&a=z') do + [ + 200, + { 'Content-Type': 'application/javascript' }, + '{"origin": "127.0.0.1"}' + ] + end + conn = Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder| + builder.adapter :test, stubs + end + + cli = Client.new(conn) + assert_equal '127.0.0.1', cli.httpbingo('api', params: { a: %w[x y z] }) + + # uncomment to raise Stubs::NotFound + # assert_equal '127.0.0.1', cli.httpbingo('api', params: { a: %w[x y] }) + stubs.verify_stubbed_calls + end + + def test_with_string_body + stubs = Faraday::Adapter::Test::Stubs.new do |stub| + stub.post('/foo', '{"name":"YK"}') { [200, {}, ''] } + end + cli = client(stubs) + assert_equal 200, cli.foo(name: 'YK') + + stubs.verify_stubbed_calls + end + + def test_with_proc_body + stubs = Faraday::Adapter::Test::Stubs.new do |stub| + check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } } + stub.post('/foo', check) { [200, {}, ''] } + end + cli = client(stubs) + assert_equal 200, cli.foo(name: 'YK', created_at: Time.now) + + stubs.verify_stubbed_calls + end + + def client(stubs) + conn = Faraday.new do |builder| + builder.adapter :test, stubs + end + Client.new(conn) + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday.rb b/bin/gems/faraday-2.9.0/lib/faraday.rb new file mode 100644 index 00000000..758a08de --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true + +require 'cgi' +require 'date' +require 'set' +require 'forwardable' +require 'faraday/version' +require 'faraday/methods' +require 'faraday/error' +require 'faraday/middleware_registry' +require 'faraday/utils' +require 'faraday/options' +require 'faraday/connection' +require 'faraday/rack_builder' +require 'faraday/parameters' +require 'faraday/middleware' +require 'faraday/adapter' +require 'faraday/request' +require 'faraday/response' +require 'faraday/net_http' +# This is the main namespace for Faraday. +# +# It provides methods to create {Connection} objects, and HTTP-related +# methods to use directly. +# +# @example Helpful class methods for easy usage +# Faraday.get "http://faraday.com" +# +# @example Helpful class method `.new` to create {Connection} objects. +# conn = Faraday.new "http://faraday.com" +# conn.get '/' +# +module Faraday + CONTENT_TYPE = 'Content-Type' + + class << self + # The root path that Faraday is being loaded from. + # + # This is the root from where the libraries are auto-loaded. + # + # @return [String] + attr_accessor :root_path + + # Gets or sets the path that the Faraday libs are loaded from. + # @return [String] + attr_accessor :lib_path + + # @overload default_adapter + # Gets the Symbol key identifying a default Adapter to use + # for the default {Faraday::Connection}. Defaults to `:net_http`. + # @return [Symbol] the default adapter + # @overload default_adapter=(adapter) + # Updates default adapter while resetting {.default_connection}. + # @return [Symbol] the new default_adapter. + attr_reader :default_adapter + + # Option for the default_adapter + # @return [Hash] default_adapter options + attr_accessor :default_adapter_options + + # Documented below, see default_connection + attr_writer :default_connection + + # Tells Faraday to ignore the environment proxy (http_proxy). + # Defaults to `false`. + # @return [Boolean] + attr_accessor :ignore_env_proxy + + # Initializes a new {Connection}. + # + # @param url [String,Hash] The optional String base URL to use as a prefix + # for all requests. Can also be the options Hash. Any of these + # values will be set on every request made, unless overridden + # for a specific request. + # @param options [Hash] + # @option options [String] :url Base URL + # @option options [Hash] :params Hash of unencoded URI query params. + # @option options [Hash] :headers Hash of unencoded HTTP headers. + # @option options [Hash] :request Hash of request options. + # @option options [Hash] :ssl Hash of SSL options. + # @option options [Hash] :proxy Hash of Proxy options. + # @return [Faraday::Connection] + # + # @example With an URL argument + # Faraday.new 'http://faraday.com' + # # => Faraday::Connection to http://faraday.com + # + # @example With an URL argument and an options hash + # Faraday.new 'http://faraday.com', params: { page: 1 } + # # => Faraday::Connection to http://faraday.com?page=1 + # + # @example With everything in an options hash + # Faraday.new url: 'http://faraday.com', + # params: { page: 1 } + # # => Faraday::Connection to http://faraday.com?page=1 + def new(url = nil, options = {}, &block) + options = Utils.deep_merge(default_connection_options, options) + Faraday::Connection.new(url, options, &block) + end + + # Documented elsewhere, see default_adapter reader + def default_adapter=(adapter) + @default_connection = nil + @default_adapter = adapter + end + + def respond_to_missing?(symbol, include_private = false) + default_connection.respond_to?(symbol, include_private) || super + end + + # @overload default_connection + # Gets the default connection used for simple scripts. + # @return [Faraday::Connection] a connection configured with + # the default_adapter. + # @overload default_connection=(connection) + # @param connection [Faraday::Connection] + # Sets the default {Faraday::Connection} for simple scripts that + # access the Faraday constant directly, such as + # Faraday.get "https://faraday.com". + def default_connection + @default_connection ||= Connection.new(default_connection_options) + end + + # Gets the default connection options used when calling {Faraday#new}. + # + # @return [Faraday::ConnectionOptions] + def default_connection_options + @default_connection_options ||= ConnectionOptions.new + end + + # Sets the default options used when calling {Faraday#new}. + # + # @param options [Hash, Faraday::ConnectionOptions] + def default_connection_options=(options) + @default_connection = nil + @default_connection_options = ConnectionOptions.from(options) + end + + private + + # Internal: Proxies method calls on the Faraday constant to + # .default_connection. + def method_missing(name, *args, &block) + if default_connection.respond_to?(name) + default_connection.send(name, *args, &block) + else + super + end + end + end + + self.ignore_env_proxy = false + self.root_path = File.expand_path __dir__ + self.lib_path = File.expand_path 'faraday', __dir__ + self.default_adapter = :net_http + self.default_adapter_options = {} +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/adapter.rb b/bin/gems/faraday-2.9.0/lib/faraday/adapter.rb new file mode 100644 index 00000000..a581166c --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/adapter.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +module Faraday + # Base class for all Faraday adapters. Adapters are + # responsible for fulfilling a Faraday request. + class Adapter + extend MiddlewareRegistry + + CONTENT_LENGTH = 'Content-Length' + + # This module marks an Adapter as supporting parallel requests. + module Parallelism + attr_writer :supports_parallel + + def supports_parallel? + @supports_parallel + end + + def inherited(subclass) + super + subclass.supports_parallel = supports_parallel? + end + end + + extend Parallelism + self.supports_parallel = false + + def initialize(_app = nil, opts = {}, &block) + @app = ->(env) { env.response } + @connection_options = opts + @config_block = block + end + + # Yields or returns an adapter's configured connection. Depends on + # #build_connection being defined on this adapter. + # + # @param env [Faraday::Env, Hash] The env object for a faraday request. + # + # @return The return value of the given block, or the HTTP connection object + # if no block is given. + def connection(env) + conn = build_connection(env) + return conn unless block_given? + + yield conn + end + + # Close any persistent connections. The adapter should still be usable + # after calling close. + def close + # Possible implementation: + # @app.close if @app.respond_to?(:close) + end + + def call(env) + env.clear_body if env.needs_body? + env.response = Response.new + end + + private + + def save_response(env, status, body, headers = nil, reason_phrase = nil, finished: true) + env.status = status + env.body = body + env.reason_phrase = reason_phrase&.to_s&.strip + env.response_headers = Utils::Headers.new.tap do |response_headers| + response_headers.update headers unless headers.nil? + yield(response_headers) if block_given? + end + + env.response.finish(env) unless env.parallel? || !finished + env.response + end + + # Fetches either a read, write, or open timeout setting. Defaults to the + # :timeout value if a more specific one is not given. + # + # @param type [Symbol] Describes which timeout setting to get: :read, + # :write, or :open. + # @param options [Hash] Hash containing Symbol keys like :timeout, + # :read_timeout, :write_timeout, or :open_timeout + # + # @return [Integer, nil] Timeout duration in seconds, or nil if no timeout + # has been set. + def request_timeout(type, options) + key = TIMEOUT_KEYS.fetch(type) do + msg = "Expected :read, :write, :open. Got #{type.inspect} :(" + raise ArgumentError, msg + end + options[key] || options[:timeout] + end + + TIMEOUT_KEYS = { + read: :read_timeout, + open: :open_timeout, + write: :write_timeout + }.freeze + end +end + +require 'faraday/adapter/test' diff --git a/bin/gems/faraday-2.9.0/lib/faraday/adapter/test.rb b/bin/gems/faraday-2.9.0/lib/faraday/adapter/test.rb new file mode 100644 index 00000000..c637d139 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/adapter/test.rb @@ -0,0 +1,311 @@ +# frozen_string_literal: true + +require 'timeout' + +module Faraday + class Adapter + # @example + # test = Faraday::Connection.new do + # use Faraday::Adapter::Test do |stub| + # # Define matcher to match the request + # stub.get '/resource.json' do + # # return static content + # [200, {'Content-Type' => 'application/json'}, 'hi world'] + # end + # + # # response with content generated based on request + # stub.get '/showget' do |env| + # [200, {'Content-Type' => 'text/plain'}, env[:method].to_s] + # end + # + # # A regular expression can be used as matching filter + # stub.get /\A\/items\/(\d+)\z/ do |env, meta| + # # in case regular expression is used, an instance of MatchData + # # can be received + # [200, + # {'Content-Type' => 'text/plain'}, + # "showing item: #{meta[:match_data][1]}" + # ] + # end + # + # # Test the request body is the same as the stubbed body + # stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] } + # + # # You can pass a proc as a stubbed body and check the request body in your way. + # # In this case, the proc should return true or false. + # stub.post('/foo', ->(request_body) do + # JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, ''] + # end + # + # # You can set strict_mode to exactly match the stubbed requests. + # stub.strict_mode = true + # end + # end + # + # resp = test.get '/resource.json' + # resp.body # => 'hi world' + # + # resp = test.get '/showget' + # resp.body # => 'get' + # + # resp = test.get '/items/1' + # resp.body # => 'showing item: 1' + # + # resp = test.get '/items/2' + # resp.body # => 'showing item: 2' + # + # resp = test.post '/bar', 'name=YK&word=call' + # resp.status # => 200 + # + # resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now) + # resp.status # => 200 + class Test < Faraday::Adapter + attr_accessor :stubs + + # A stack of Stubs + class Stubs + class NotFound < StandardError + end + + def initialize(strict_mode: false) + # { get: [Stub, Stub] } + @stack = {} + @consumed = {} + @strict_mode = strict_mode + @stubs_mutex = Monitor.new + yield(self) if block_given? + end + + def empty? + @stack.empty? + end + + # @param env [Faraday::Env] + def match(env) + request_method = env[:method] + return false unless @stack.key?(request_method) + + stack = @stack[request_method] + consumed = (@consumed[request_method] ||= []) + + @stubs_mutex.synchronize do + stub, meta = matches?(stack, env) + if stub + removed = stack.delete(stub) + consumed << removed unless removed.nil? + return stub, meta + end + end + matches?(consumed, env) + end + + def get(path, headers = {}, &block) + new_stub(:get, path, headers, &block) + end + + def head(path, headers = {}, &block) + new_stub(:head, path, headers, &block) + end + + def post(path, body = nil, headers = {}, &block) + new_stub(:post, path, headers, body, &block) + end + + def put(path, body = nil, headers = {}, &block) + new_stub(:put, path, headers, body, &block) + end + + def patch(path, body = nil, headers = {}, &block) + new_stub(:patch, path, headers, body, &block) + end + + def delete(path, headers = {}, &block) + new_stub(:delete, path, headers, &block) + end + + def options(path, headers = {}, &block) + new_stub(:options, path, headers, &block) + end + + # Raises an error if any of the stubbed calls have not been made. + def verify_stubbed_calls + failed_stubs = [] + @stack.each do |method, stubs| + next if stubs.empty? + + failed_stubs.concat( + stubs.map do |stub| + "Expected #{method} #{stub}." + end + ) + end + raise failed_stubs.join(' ') unless failed_stubs.empty? + end + + # Set strict_mode. If the value is true, this adapter tries to find matched requests strictly, + # which means that all of a path, parameters, and headers must be the same as an actual request. + def strict_mode=(value) + @strict_mode = value + @stack.each_value do |stubs| + stubs.each do |stub| + stub.strict_mode = value + end + end + end + + protected + + def new_stub(request_method, path, headers = {}, body = nil, &block) + normalized_path, host = + if path.is_a?(Regexp) + path + else + [ + Faraday::Utils.normalize_path(path), + Faraday::Utils.URI(path).host + ] + end + path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path + headers = Utils::Headers.new(headers) + + stub = Stub.new(host, path, query, headers, body, @strict_mode, block) + (@stack[request_method] ||= []) << stub + end + + # @param stack [Hash] + # @param env [Faraday::Env] + def matches?(stack, env) + stack.each do |stub| + match_result, meta = stub.matches?(env) + return stub, meta if match_result + end + nil + end + end + + # Stub request + Stub = Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) do + # @param env [Faraday::Env] + def matches?(env) + request_host = env[:url].host + request_path = Faraday::Utils.normalize_path(env[:url].path) + request_headers = env.request_headers + request_body = env[:body] + + # meta is a hash used as carrier + # that will be yielded to consumer block + meta = {} + [(host.nil? || host == request_host) && + path_match?(request_path, meta) && + params_match?(env) && + body_match?(request_body) && + headers_match?(request_headers), meta] + end + + def path_match?(request_path, meta) + if path.is_a?(Regexp) + !!(meta[:match_data] = path.match(request_path)) + else + path == request_path + end + end + + # @param env [Faraday::Env] + def params_match?(env) + request_params = env[:params] + params = env.params_encoder.decode(query) || {} + + if strict_mode + return Set.new(params) == Set.new(request_params) + end + + params.keys.all? do |key| + request_params[key] == params[key] + end + end + + def headers_match?(request_headers) + if strict_mode + headers_with_user_agent = headers.dup.tap do |hs| + # NOTE: Set User-Agent in case it's not set when creating Stubs. + # Users would not want to set Faraday's User-Agent explicitly. + hs[:user_agent] ||= Connection::USER_AGENT + end + return Set.new(headers_with_user_agent) == Set.new(request_headers) + end + + headers.keys.all? do |key| + request_headers[key] == headers[key] + end + end + + def body_match?(request_body) + return true if body.to_s.empty? + + case body + when Proc + body.call(request_body) + else + request_body == body + end + end + + def to_s + "#{path} #{body}" + end + end + + def initialize(app, stubs = nil, &block) + super(app) + @stubs = stubs || Stubs.new + configure(&block) if block + end + + def configure + yield(stubs) + end + + # @param env [Faraday::Env] + def call(env) + super + + env.request.params_encoder ||= Faraday::Utils.default_params_encoder + env[:params] = env.params_encoder.decode(env[:url].query) || {} + stub, meta = stubs.match(env) + + unless stub + raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \ + "#{env[:url]} #{env[:body]} #{env[:headers]}" + end + + block_arity = stub.block.arity + params = if block_arity >= 0 + [env, meta].take(block_arity) + else + [env, meta] + end + + timeout = request_timeout(:open, env[:request]) + timeout ||= request_timeout(:read, env[:request]) + + status, headers, body = + if timeout + ::Timeout.timeout(timeout, Faraday::TimeoutError) do + stub.block.call(*params) + end + else + stub.block.call(*params) + end + + # We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts. + # See https://github.com/lostisland/faraday/issues/1444 + # TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version + save_response(env, status, body, headers, nil) + + @app.call(env) + end + end + end +end + +Faraday::Adapter.register_middleware(test: Faraday::Adapter::Test) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/adapter_registry.rb b/bin/gems/faraday-2.9.0/lib/faraday/adapter_registry.rb new file mode 100644 index 00000000..1cd1e7e1 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/adapter_registry.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'monitor' + +module Faraday + # AdapterRegistry registers adapter class names so they can be looked up by a + # String or Symbol name. + class AdapterRegistry + def initialize + @lock = Monitor.new + @constants = {} + end + + def get(name) + klass = @lock.synchronize do + @constants[name] + end + return klass if klass + + Object.const_get(name).tap { |c| set(c, name) } + end + + def set(klass, name = nil) + name ||= klass.to_s + @lock.synchronize do + @constants[name] = klass + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/connection.rb b/bin/gems/faraday-2.9.0/lib/faraday/connection.rb new file mode 100644 index 00000000..0196945e --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/connection.rb @@ -0,0 +1,555 @@ +# frozen_string_literal: true + +module Faraday + # Connection objects manage the default properties and the middleware + # stack for fulfilling an HTTP request. + # + # @example + # + # conn = Faraday::Connection.new 'http://httpbingo.org' + # + # # GET http://httpbingo.org/nigiri + # conn.get 'nigiri' + # # => # + # + class Connection + # A Set of allowed HTTP verbs. + METHODS = Set.new %i[get post put delete head patch options trace] + USER_AGENT = "Faraday v#{VERSION}".freeze + + # @return [Hash] URI query unencoded key/value pairs. + attr_reader :params + + # @return [Hash] unencoded HTTP header key/value pairs. + attr_reader :headers + + # @return [String] a URI with the prefix used for all requests from this + # Connection. This includes a default host name, scheme, port, and path. + attr_reader :url_prefix + + # @return [Faraday::RackBuilder] Builder for this Connection. + attr_reader :builder + + # @return [Hash] SSL options. + attr_reader :ssl + + # @return [Object] the parallel manager for this Connection. + attr_reader :parallel_manager + + # Sets the default parallel manager for this connection. + attr_writer :default_parallel_manager + + # @return [Hash] proxy options. + attr_reader :proxy + + # Initializes a new Faraday::Connection. + # + # @param url [URI, String] URI or String base URL to use as a prefix for all + # requests (optional). + # @param options [Hash, Faraday::ConnectionOptions] + # @option options [URI, String] :url ('http:/') URI or String base URL + # @option options [Hash String>] :params URI query unencoded + # key/value pairs. + # @option options [Hash String>] :headers Hash of unencoded HTTP + # header key/value pairs. + # @option options [Hash] :request Hash of request options. + # @option options [Hash] :ssl Hash of SSL options. + # @option options [Hash, URI, String] :proxy proxy options, either as a URL + # or as a Hash + # @option options [URI, String] :proxy[:uri] + # @option options [String] :proxy[:user] + # @option options [String] :proxy[:password] + # @yield [self] after all setup has been done + def initialize(url = nil, options = nil) + options = ConnectionOptions.from(options) + + if url.is_a?(Hash) || url.is_a?(ConnectionOptions) + options = Utils.deep_merge(options, url) + url = options.url + end + + @parallel_manager = nil + @headers = Utils::Headers.new + @params = Utils::ParamsHash.new + @options = options.request + @ssl = options.ssl + @default_parallel_manager = options.parallel_manager + @manual_proxy = nil + + @builder = options.builder || begin + # pass an empty block to Builder so it doesn't assume default middleware + options.new_builder(block_given? ? proc { |b| } : nil) + end + + self.url_prefix = url || 'http:/' + + @params.update(options.params) if options.params + @headers.update(options.headers) if options.headers + + initialize_proxy(url, options) + + yield(self) if block_given? + + @headers[:user_agent] ||= USER_AGENT + end + + def initialize_proxy(url, options) + @manual_proxy = !!options.proxy + @proxy = + if options.proxy + ProxyOptions.from(options.proxy) + else + proxy_from_env(url) + end + end + + # Sets the Hash of URI query unencoded key/value pairs. + # @param hash [Hash] + def params=(hash) + @params.replace hash + end + + # Sets the Hash of unencoded HTTP header key/value pairs. + # @param hash [Hash] + def headers=(hash) + @headers.replace hash + end + + extend Forwardable + + def_delegators :builder, :use, :request, :response, :adapter, :app + + # Closes the underlying resources and/or connections. In the case of + # persistent connections, this closes all currently open connections + # but does not prevent new connections from being made. + def close + app.close + end + + # @!method get(url = nil, params = nil, headers = nil) + # Makes a GET HTTP request without a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param params [Hash, nil] Hash of URI query unencoded key/value pairs. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.get '/items', { page: 1 }, :accept => 'application/json' + # + # # ElasticSearch example sending a body with GET. + # conn.get '/twitter/tweet/_search' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(query: {...}) + # end + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!method head(url = nil, params = nil, headers = nil) + # Makes a HEAD HTTP request without a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param params [Hash, nil] Hash of URI query unencoded key/value pairs. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.head '/items/1' + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!method delete(url = nil, params = nil, headers = nil) + # Makes a DELETE HTTP request without a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param params [Hash, nil] Hash of URI query unencoded key/value pairs. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.delete '/items/1' + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!method trace(url = nil, params = nil, headers = nil) + # Makes a TRACE HTTP request without a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param params [Hash, nil] Hash of URI query unencoded key/value pairs. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.connect '/items/1' + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!visibility private + METHODS_WITH_QUERY.each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, params = nil, headers = nil) + run_request(:#{method}, url, nil, headers) do |request| + request.params.update(params) if params + yield request if block_given? + end + end + RUBY + end + + # @overload options() + # Returns current Connection options. + # + # @overload options(url, params = nil, headers = nil) + # Makes an OPTIONS HTTP request to the given URL. + # @param url [String, URI, nil] String base URL to sue as a prefix for all requests. + # @param params [Hash, nil] Hash of URI query unencoded key/value pairs. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.options '/items/1' + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + def options(*args) + return @options if args.empty? + + url, params, headers = *args + run_request(:options, url, nil, headers) do |request| + request.params.update(params) if params + yield request if block_given? + end + end + + # @!method post(url = nil, body = nil, headers = nil) + # Makes a POST HTTP request with a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param body [String, nil] body for the request. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.post '/items', data, content_type: 'application/json' + # + # # Simple ElasticSearch indexing sample. + # conn.post '/twitter/tweet' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(user: 'kimchy', ...) + # end + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!method put(url = nil, body = nil, headers = nil) + # Makes a PUT HTTP request with a body. + # @!scope class + # + # @param url [String, URI, nil] The optional String base URL to use as a prefix for + # all requests. Can also be the options Hash. + # @param body [String, nil] body for the request. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @example + # conn.put '/products/123', data, content_type: 'application/json' + # + # # Star a gist. + # conn.put 'https://api.github.com/gists/GIST_ID/star' do |req| + # req.headers['Accept'] = 'application/vnd.github+json' + # req.headers['Authorization'] = 'Bearer ' + # req.headers['X-GitHub-Api-Version'] = '2022-11-28' + # end + # + # @yield [Faraday::Request] for further request customizations + # @return [Faraday::Response] + + # @!visibility private + METHODS_WITH_BODY.each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, body = nil, headers = nil, &block) + run_request(:#{method}, url, body, headers, &block) + end + RUBY + end + + # Check if the adapter is parallel-capable. + # + # @yield if the adapter isn't parallel-capable, or if no adapter is set yet. + # + # @return [Object, nil] a parallel manager or nil if yielded + # @api private + def default_parallel_manager + @default_parallel_manager ||= begin + adapter = @builder.adapter.klass if @builder.adapter + + if support_parallel?(adapter) + adapter.setup_parallel_manager + elsif block_given? + yield + end + end + end + + # Determine if this Faraday::Connection can make parallel requests. + # + # @return [Boolean] + def in_parallel? + !!@parallel_manager + end + + # Sets up the parallel manager to make a set of requests. + # + # @param manager [Object] The parallel manager that this Connection's + # Adapter uses. + # + # @yield a block to execute multiple requests. + # @return [void] + def in_parallel(manager = nil) + @parallel_manager = manager || default_parallel_manager do + warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \ + 'on Faraday stack' + warn caller[2, 10].join("\n") + nil + end + yield + @parallel_manager&.run + ensure + @parallel_manager = nil + end + + # Sets the Hash proxy options. + # + # @param new_value [Object] + def proxy=(new_value) + @manual_proxy = true + @proxy = new_value ? ProxyOptions.from(new_value) : nil + end + + def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port= + def_delegator :url_prefix, :path, :path_prefix + + # Parses the given URL with URI and stores the individual + # components in this connection. These components serve as defaults for + # requests made by this connection. + # + # @param url [String, URI] + # @param encoder [Object] + # + # @example + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://httpbingo.org/api" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.get("nigiri?page=2") # accesses https://httpbingo.org/api/nigiri + def url_prefix=(url, encoder = nil) + uri = @url_prefix = Utils.URI(url) + self.path_prefix = uri.path + + params.merge_query(uri.query, encoder) + uri.query = nil + + with_uri_credentials(uri) do |user, password| + set_basic_auth(user, password) + uri.user = uri.password = nil + end + + @proxy = proxy_from_env(url) unless @manual_proxy + end + + def set_basic_auth(user, password) + header = Faraday::Utils.basic_header_from(user, password) + headers[Faraday::Request::Authorization::KEY] = header + end + + # Sets the path prefix and ensures that it always has a leading + # slash. + # + # @param value [String] + # + # @return [String] the new path prefix + def path_prefix=(value) + url_prefix.path = if value + value = "/#{value}" unless value[0, 1] == '/' + value + end + end + + # Takes a relative url for a request and combines it with the defaults + # set on the connection instance. + # + # @param url [String, URI, nil] + # @param extra_params [Hash] + # + # @example + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://httpbingo.org/api?token=abc" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.build_url("nigiri?page=2") + # # => https://httpbingo.org/api/nigiri?token=abc&page=2 + # + # conn.build_url("nigiri", page: 2) + # # => https://httpbingo.org/api/nigiri?token=abc&page=2 + # + def build_url(url = nil, extra_params = nil) + uri = build_exclusive_url(url) + + query_values = params.dup.merge_query(uri.query, options.params_encoder) + query_values.update(extra_params) if extra_params + uri.query = + if query_values.empty? + nil + else + query_values.to_query(options.params_encoder) + end + + uri + end + + # Builds and runs the Faraday::Request. + # + # @param method [Symbol] HTTP method. + # @param url [String, URI, nil] String or URI to access. + # @param body [String, nil] The request body that will eventually be converted to + # a string. + # @param headers [Hash, nil] unencoded HTTP header key/value pairs. + # + # @return [Faraday::Response] + def run_request(method, url, body, headers) + unless METHODS.include?(method) + raise ArgumentError, "unknown http method: #{method}" + end + + request = build_request(method) do |req| + req.options.proxy = proxy_for_request(url) + req.url(url) if url + req.headers.update(headers) if headers + req.body = body if body + yield(req) if block_given? + end + + builder.build_response(self, request) + end + + # Creates and configures the request object. + # + # @param method [Symbol] + # + # @yield [Faraday::Request] if block given + # @return [Faraday::Request] + def build_request(method) + Request.create(method) do |req| + req.params = params.dup + req.headers = headers.dup + req.options = options.dup + yield(req) if block_given? + end + end + + # Build an absolute URL based on url_prefix. + # + # @param url [String, URI, nil] + # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to + # replace the query values + # of the resulting url (default: nil). + # + # @return [URI] + def build_exclusive_url(url = nil, params = nil, params_encoder = nil) + url = nil if url.respond_to?(:empty?) && url.empty? + base = url_prefix.dup + if url && !base.path.end_with?('/') + base.path = "#{base.path}/" # ensure trailing slash + end + url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque + uri = url ? base + url : base + if params + uri.query = params.to_query(params_encoder || options.params_encoder) + end + uri.query = nil if uri.query && uri.query.empty? + uri + end + + # Creates a duplicate of this Faraday::Connection. + # + # @api private + # + # @return [Faraday::Connection] + def dup + self.class.new(build_exclusive_url, + headers: headers.dup, + params: params.dup, + builder: builder.dup, + ssl: ssl.dup, + request: options.dup) + end + + # Yields username and password extracted from a URI if they both exist. + # + # @param uri [URI] + # @yield [username, password] any username and password + # @yieldparam username [String] any username from URI + # @yieldparam password [String] any password from URI + # @return [void] + # @api private + def with_uri_credentials(uri) + return unless uri.user && uri.password + + yield(Utils.unescape(uri.user), Utils.unescape(uri.password)) + end + + def proxy_from_env(url) + return if Faraday.ignore_env_proxy + + uri = nil + case url + when String + uri = Utils.URI(url) + uri = if uri.host.nil? + find_default_proxy + else + URI.parse("#{uri.scheme}://#{uri.host}").find_proxy + end + when URI + uri = url.find_proxy + when nil + uri = find_default_proxy + end + ProxyOptions.from(uri) if uri + end + + def find_default_proxy + uri = ENV.fetch('http_proxy', nil) + return unless uri && !uri.empty? + + uri = "http://#{uri}" unless uri.match?(/^http/i) + uri + end + + def proxy_for_request(url) + return proxy if @manual_proxy + + if url && Utils.URI(url).absolute? + proxy_from_env(url) + else + proxy + end + end + + def support_parallel?(adapter) + adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel? + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/encoders/flat_params_encoder.rb b/bin/gems/faraday-2.9.0/lib/faraday/encoders/flat_params_encoder.rb new file mode 100644 index 00000000..bc10c8b9 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/encoders/flat_params_encoder.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +module Faraday + # FlatParamsEncoder manages URI params as a flat hash. Any Array values repeat + # the parameter multiple times. + module FlatParamsEncoder + class << self + extend Forwardable + def_delegators :'Faraday::Utils', :escape, :unescape + end + + # Encode converts the given param into a URI querystring. Keys and values + # will converted to strings and appropriately escaped for the URI. + # + # @param params [Hash] query arguments to convert. + # + # @example + # + # encode({a: %w[one two three], b: true, c: "C"}) + # # => 'a=one&a=two&a=three&b=true&c=C' + # + # @return [String] the URI querystring (without the leading '?') + def self.encode(params) + return nil if params.nil? + + unless params.is_a?(Array) + unless params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.is_a?(Symbol) + [key, value] + end + + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! if @sort_params + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = +'' + params.each do |key, value| + encoded_key = escape(key) + if value.nil? + buffer << "#{encoded_key}&" + elsif value.is_a?(Array) + if value.empty? + buffer << "#{encoded_key}=&" + else + value.each do |sub_value| + encoded_value = escape(sub_value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + else + encoded_value = escape(value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + buffer.chop + end + + # Decode converts the given URI querystring into a hash. + # + # @param query [String] query arguments to parse. + # + # @example + # + # decode('a=one&a=two&a=three&b=true&c=C') + # # => {"a"=>["one", "two", "three"], "b"=>"true", "c"=>"C"} + # + # @return [Hash] parsed keys and value strings from the querystring. + def self.decode(query) + return nil if query.nil? + + empty_accumulator = {} + + split_query = (query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact + split_query.each_with_object(empty_accumulator.dup) do |pair, accu| + pair[0] = unescape(pair[0]) + pair[1] = true if pair[1].nil? + if pair[1].respond_to?(:to_str) + pair[1] = unescape(pair[1].to_str.tr('+', ' ')) + end + if accu[pair[0]].is_a?(Array) + accu[pair[0]] << pair[1] + elsif accu[pair[0]] + accu[pair[0]] = [accu[pair[0]], pair[1]] + else + accu[pair[0]] = pair[1] + end + end + end + + class << self + attr_accessor :sort_params + end + + # Useful default for OAuth and caching. + @sort_params = true + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/encoders/nested_params_encoder.rb b/bin/gems/faraday-2.9.0/lib/faraday/encoders/nested_params_encoder.rb new file mode 100644 index 00000000..3ca3e73e --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/encoders/nested_params_encoder.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +module Faraday + # Sub-module for encoding parameters into query-string. + module EncodeMethods + # @param params [nil, Array, #to_hash] parameters to be encoded + # + # @return [String] the encoded params + # + # @raise [TypeError] if params can not be converted to a Hash + def encode(params) + return nil if params.nil? + + unless params.is_a?(Array) + unless params.respond_to?(:to_hash) + raise TypeError, "Can't convert #{params.class} into Hash." + end + + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.is_a?(Symbol) + [key, value] + end + + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! if @sort_params + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = +'' + params.each do |parent, value| + encoded_parent = escape(parent) + buffer << "#{encode_pair(encoded_parent, value)}&" + end + buffer.chop + end + + protected + + def encode_pair(parent, value) + if value.is_a?(Hash) + encode_hash(parent, value) + elsif value.is_a?(Array) + encode_array(parent, value) + elsif value.nil? + parent + else + encoded_value = escape(value) + "#{parent}=#{encoded_value}" + end + end + + def encode_hash(parent, value) + value = value.map { |key, val| [escape(key), val] }.sort + + buffer = +'' + value.each do |key, val| + new_parent = "#{parent}%5B#{key}%5D" + buffer << "#{encode_pair(new_parent, val)}&" + end + buffer.chop + end + + def encode_array(parent, value) + return "#{parent}%5B%5D" if value.empty? + + buffer = +'' + value.each_with_index do |val, index| + new_parent = if @array_indices + "#{parent}%5B#{index}%5D" + else + "#{parent}%5B%5D" + end + buffer << "#{encode_pair(new_parent, val)}&" + end + buffer.chop + end + end + + # Sub-module for decoding query-string into parameters. + module DecodeMethods + # @param query [nil, String] + # + # @return [Array] the decoded params + # + # @raise [TypeError] if the nesting is incorrect + def decode(query) + return nil if query.nil? + + params = {} + query.split('&').each do |pair| + next if pair.empty? + + key, value = pair.split('=', 2) + key = unescape(key) + value = unescape(value.tr('+', ' ')) if value + decode_pair(key, value, params) + end + + dehash(params, 0) + end + + protected + + SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/ + + def decode_pair(key, value, context) + subkeys = key.scan(SUBKEYS_REGEX) + subkeys.each_with_index do |subkey, i| + is_array = subkey =~ /[\[\]]+\Z/ + subkey = Regexp.last_match.pre_match if is_array + last_subkey = i == subkeys.length - 1 + + context = prepare_context(context, subkey, is_array, last_subkey) + add_to_context(is_array, context, value, subkey) if last_subkey + end + end + + def prepare_context(context, subkey, is_array, last_subkey) + if !last_subkey || is_array + context = new_context(subkey, is_array, context) + end + if context.is_a?(Array) && !is_array + context = match_context(context, subkey) + end + context + end + + def new_context(subkey, is_array, context) + value_type = is_array ? Array : Hash + if context[subkey] && !context[subkey].is_a?(value_type) + raise TypeError, "expected #{value_type.name} " \ + "(got #{context[subkey].class.name}) for param `#{subkey}'" + end + + context[subkey] ||= value_type.new + end + + def match_context(context, subkey) + context << {} if !context.last.is_a?(Hash) || context.last.key?(subkey) + context.last + end + + def add_to_context(is_array, context, value, subkey) + is_array ? context << value : context[subkey] = value + end + + # Internal: convert a nested hash with purely numeric keys into an array. + # FIXME: this is not compatible with Rack::Utils.parse_nested_query + # @!visibility private + def dehash(hash, depth) + hash.each do |key, value| + hash[key] = dehash(value, depth + 1) if value.is_a?(Hash) + end + + if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ } + hash.sort.map(&:last) + else + hash + end + end + end + + # This is the default encoder for Faraday requests. + # Using this encoder, parameters will be encoded respecting their structure, + # so you can send objects such as Arrays or Hashes as parameters + # for your requests. + module NestedParamsEncoder + class << self + attr_accessor :sort_params, :array_indices + + extend Forwardable + def_delegators :'Faraday::Utils', :escape, :unescape + end + + # Useful default for OAuth and caching. + @sort_params = true + @array_indices = false + + extend EncodeMethods + extend DecodeMethods + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/error.rb b/bin/gems/faraday-2.9.0/lib/faraday/error.rb new file mode 100644 index 00000000..61d19a6d --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/error.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +# Faraday namespace. +module Faraday + # Faraday error base class. + class Error < StandardError + attr_reader :response, :wrapped_exception + + def initialize(exc = nil, response = nil) + @wrapped_exception = nil unless defined?(@wrapped_exception) + @response = nil unless defined?(@response) + super(exc_msg_and_response!(exc, response)) + end + + def backtrace + if @wrapped_exception + @wrapped_exception.backtrace + else + super + end + end + + def inspect + inner = +'' + inner << " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception + inner << " response=#{@response.inspect}" if @response + inner << " #{super}" if inner.empty? + %(#<#{self.class}#{inner}>) + end + + def response_status + return unless @response + + @response.is_a?(Faraday::Response) ? @response.status : @response[:status] + end + + def response_headers + return unless @response + + @response.is_a?(Faraday::Response) ? @response.headers : @response[:headers] + end + + def response_body + return unless @response + + @response.is_a?(Faraday::Response) ? @response.body : @response[:body] + end + + protected + + # Pulls out potential parent exception and response hash, storing them in + # instance variables. + # exc - Either an Exception, a string message, or a response hash. + # response - Hash + # :status - Optional integer HTTP response status + # :headers - String key/value hash of HTTP response header + # values. + # :body - Optional string HTTP response body. + # :request - Hash + # :method - Symbol with the request HTTP method. + # :url - URI object with the url requested. + # :url_path - String with the url path requested. + # :params - String key/value hash of query params + # present in the request. + # :headers - String key/value hash of HTTP request + # header values. + # :body - String HTTP request body. + # + # If a subclass has to call this, then it should pass a string message + # to `super`. See NilStatusError. + def exc_msg_and_response!(exc, response = nil) + if @response.nil? && @wrapped_exception.nil? + @wrapped_exception, msg, @response = exc_msg_and_response(exc, response) + return msg + end + + exc.to_s + end + + # Pulls out potential parent exception and response hash. + def exc_msg_and_response(exc, response = nil) + return [exc, exc.message, response] if exc.respond_to?(:backtrace) + + return [nil, "the server responded with status #{exc[:status]}", exc] \ + if exc.respond_to?(:each_key) + + [nil, exc.to_s, response] + end + end + + # Faraday client error class. Represents 4xx status responses. + class ClientError < Error + end + + # Raised by Faraday::Response::RaiseError in case of a 400 response. + class BadRequestError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 401 response. + class UnauthorizedError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 403 response. + class ForbiddenError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 404 response. + class ResourceNotFound < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 407 response. + class ProxyAuthError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 408 response. + class RequestTimeoutError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 409 response. + class ConflictError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 422 response. + class UnprocessableEntityError < ClientError + end + + # Raised by Faraday::Response::RaiseError in case of a 429 response. + class TooManyRequestsError < ClientError + end + + # Faraday server error class. Represents 5xx status responses. + class ServerError < Error + end + + # A unified client error for timeouts. + class TimeoutError < ServerError + def initialize(exc = 'timeout', response = nil) + super(exc, response) + end + end + + # Raised by Faraday::Response::RaiseError in case of a nil status in response. + class NilStatusError < ServerError + def initialize(exc, response = nil) + exc_msg_and_response!(exc, response) + super('http status could not be derived from the server response') + end + end + + # A unified error for failed connections. + class ConnectionFailed < Error + end + + # A unified client error for SSL errors. + class SSLError < Error + end + + # Raised by middlewares that parse the response, like the JSON response middleware. + class ParsingError < Error + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/logging/formatter.rb b/bin/gems/faraday-2.9.0/lib/faraday/logging/formatter.rb new file mode 100644 index 00000000..633afaad --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/logging/formatter.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'pp' # This require is necessary for Hash#pretty_inspect to work, do not remove it, people rely on it. + +module Faraday + module Logging + # Serves as an integration point to customize logging + class Formatter + extend Forwardable + + DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false, + log_level: :info }.freeze + + def initialize(logger:, options:) + @logger = logger + @options = DEFAULT_OPTIONS.merge(options) + unless %i[debug info warn error fatal].include?(@options[:log_level]) + @options[:log_level] = :info + end + @filter = [] + end + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + def request(env) + public_send(log_level, 'request') do + "#{env.method.upcase} #{apply_filters(env.url.to_s)}" + end + + log_headers('request', env.request_headers) if log_headers?(:request) + log_body('request', env[:body]) if env[:body] && log_body?(:request) + end + + def response(env) + public_send(log_level, 'response') { "Status #{env.status}" } + + log_headers('response', env.response_headers) if log_headers?(:response) + log_body('response', env[:body]) if env[:body] && log_body?(:response) + end + + def exception(exc) + return unless log_errors? + + public_send(log_level, 'error') { exc.full_message } + + log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error) + return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error) + + log_body('error', exc.response_body) + end + + def filter(filter_word, filter_replacement) + @filter.push([filter_word, filter_replacement]) + end + + private + + def dump_headers(headers) + return if headers.nil? + + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n") + end + + def dump_body(body) + if body.respond_to?(:to_str) + body.to_str + else + pretty_inspect(body) + end + end + + def pretty_inspect(body) + body.pretty_inspect + end + + def log_headers?(type) + case @options[:headers] + when Hash + @options[:headers][type] + else + @options[:headers] + end + end + + def log_body?(type) + case @options[:bodies] + when Hash + @options[:bodies][type] + else + @options[:bodies] + end + end + + def log_errors? + @options[:errors] + end + + def apply_filters(output) + @filter.each do |pattern, replacement| + output = output.to_s.gsub(pattern, replacement) + end + output + end + + def log_level + @options[:log_level] + end + + def log_headers(type, headers) + public_send(log_level, type) { apply_filters(dump_headers(headers)) } + end + + def log_body(type, body) + public_send(log_level, type) { apply_filters(dump_body(body)) } + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/methods.rb b/bin/gems/faraday-2.9.0/lib/faraday/methods.rb new file mode 100644 index 00000000..53e39037 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/methods.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module Faraday + METHODS_WITH_QUERY = %w[get head delete trace].freeze + METHODS_WITH_BODY = %w[post put patch].freeze +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/middleware.rb b/bin/gems/faraday-2.9.0/lib/faraday/middleware.rb new file mode 100644 index 00000000..0631ca24 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/middleware.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Faraday + # Middleware is the basic base class of any Faraday middleware. + class Middleware + extend MiddlewareRegistry + + attr_reader :app, :options + + def initialize(app = nil, options = {}) + @app = app + @options = options + end + + def call(env) + on_request(env) if respond_to?(:on_request) + app.call(env).on_complete do |environment| + on_complete(environment) if respond_to?(:on_complete) + end + rescue StandardError => e + on_error(e) if respond_to?(:on_error) + raise + end + + def close + if app.respond_to?(:close) + app.close + else + warn "#{app} does not implement \#close!" + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/middleware_registry.rb b/bin/gems/faraday-2.9.0/lib/faraday/middleware_registry.rb new file mode 100644 index 00000000..fc70e2b8 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/middleware_registry.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'monitor' + +module Faraday + # Adds the ability for other modules to register and lookup + # middleware classes. + module MiddlewareRegistry + def registered_middleware + @registered_middleware ||= {} + end + + # Register middleware class(es) on the current module. + # + # @param mappings [Hash] Middleware mappings from a lookup symbol to a middleware class. + # @return [void] + # + # @example Lookup by a constant + # + # module Faraday + # class Whatever < Middleware + # # Middleware looked up by :foo returns Faraday::Whatever::Foo. + # register_middleware(foo: Whatever) + # end + # end + def register_middleware(**mappings) + middleware_mutex do + registered_middleware.update(mappings) + end + end + + # Unregister a previously registered middleware class. + # + # @param key [Symbol] key for the registered middleware. + def unregister_middleware(key) + registered_middleware.delete(key) + end + + # Lookup middleware class with a registered Symbol shortcut. + # + # @param key [Symbol] key for the registered middleware. + # @return [Class] a middleware Class. + # @raise [Faraday::Error] if given key is not registered + # + # @example + # + # module Faraday + # class Whatever < Middleware + # register_middleware(foo: Whatever) + # end + # end + # + # Faraday::Middleware.lookup_middleware(:foo) + # # => Faraday::Whatever + def lookup_middleware(key) + load_middleware(key) || + raise(Faraday::Error, "#{key.inspect} is not registered on #{self}") + end + + private + + def middleware_mutex(&block) + @middleware_mutex ||= Monitor.new + @middleware_mutex.synchronize(&block) + end + + def load_middleware(key) + value = registered_middleware[key] + case value + when Module + value + when Symbol, String + middleware_mutex do + @registered_middleware[key] = const_get(value) + end + when Proc + middleware_mutex do + @registered_middleware[key] = value.call + end + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options.rb b/bin/gems/faraday-2.9.0/lib/faraday/options.rb new file mode 100644 index 00000000..b3e0dea1 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options.rb @@ -0,0 +1,219 @@ +# frozen_string_literal: true + +module Faraday + # Subclasses Struct with some special helpers for converting from a Hash to + # a Struct. + class Options < Struct + # Public + def self.from(value) + value ? new.update(value) : new + end + + # Public + def each + return to_enum(:each) unless block_given? + + members.each do |key| + yield(key.to_sym, send(key)) + end + end + + # Public + def update(obj) + obj.each do |key, value| + sub_options = self.class.options_for(key) + if sub_options + new_value = sub_options.from(value) if value + elsif value.is_a?(Hash) + new_value = value.dup + else + new_value = value + end + + send(:"#{key}=", new_value) unless new_value.nil? + end + self + end + + # Public + def delete(key) + value = send(key) + send(:"#{key}=", nil) + value + end + + # Public + def clear + members.each { |member| delete(member) } + end + + # Public + def merge!(other) + other.each do |key, other_value| + self_value = send(key) + sub_options = self.class.options_for(key) + new_value = if self_value && sub_options && other_value + self_value.merge(other_value) + else + other_value + end + send(:"#{key}=", new_value) unless new_value.nil? + end + self + end + + # Public + def merge(other) + dup.merge!(other) + end + + # Public + def deep_dup + self.class.from(self) + end + + # Public + def fetch(key, *args) + unless symbolized_key_set.include?(key.to_sym) + key_setter = "#{key}=" + if !args.empty? + send(key_setter, args.first) + elsif block_given? + send(key_setter, yield(key)) + else + raise self.class.fetch_error_class, "key not found: #{key.inspect}" + end + end + send(key) + end + + # Public + def values_at(*keys) + keys.map { |key| send(key) } + end + + # Public + def keys + members.reject { |member| send(member).nil? } + end + + # Public + def empty? + keys.empty? + end + + # Public + def each_key(&block) + return to_enum(:each_key) unless block + + keys.each(&block) + end + + # Public + def key?(key) + keys.include?(key) + end + + alias has_key? key? + + # Public + def each_value(&block) + return to_enum(:each_value) unless block + + values.each(&block) + end + + # Public + def value?(value) + values.include?(value) + end + + alias has_value? value? + + # Public + def to_hash + hash = {} + members.each do |key| + value = send(key) + hash[key.to_sym] = value unless value.nil? + end + hash + end + + # Internal + def inspect + values = [] + members.each do |member| + value = send(member) + values << "#{member}=#{value.inspect}" if value + end + values = values.empty? ? '(empty)' : values.join(', ') + + %(#<#{self.class} #{values}>) + end + + # Internal + def self.options(mapping) + attribute_options.update(mapping) + end + + # Internal + def self.options_for(key) + attribute_options[key] + end + + # Internal + def self.attribute_options + @attribute_options ||= {} + end + + def self.memoized(key, &block) + unless block + raise ArgumentError, '#memoized must be called with a block' + end + + memoized_attributes[key.to_sym] = block + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + remove_method(key) if method_defined?(key, false) + def #{key}() self[:#{key}]; end + RUBY + end + + def self.memoized_attributes + @memoized_attributes ||= {} + end + + def [](key) + key = key.to_sym + if (method = self.class.memoized_attributes[key]) + super(key) || (self[key] = instance_eval(&method)) + else + super + end + end + + def symbolized_key_set + @symbolized_key_set ||= Set.new(keys.map(&:to_sym)) + end + + def self.inherited(subclass) + super + subclass.attribute_options.update(attribute_options) + subclass.memoized_attributes.update(memoized_attributes) + end + + def self.fetch_error_class + @fetch_error_class ||= if Object.const_defined?(:KeyError) + ::KeyError + else + ::IndexError + end + end + end +end + +require 'faraday/options/request_options' +require 'faraday/options/ssl_options' +require 'faraday/options/proxy_options' +require 'faraday/options/connection_options' +require 'faraday/options/env' diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options/connection_options.rb b/bin/gems/faraday-2.9.0/lib/faraday/options/connection_options.rb new file mode 100644 index 00000000..0698940b --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options/connection_options.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Faraday + # @!parse + # # ConnectionOptions contains the configurable properties for a Faraday + # # connection object. + # class ConnectionOptions < Options; end + ConnectionOptions = Options.new(:request, :proxy, :ssl, :builder, :url, + :parallel_manager, :params, :headers, + :builder_class) do + options request: RequestOptions, ssl: SSLOptions + + memoized(:request) { self.class.options_for(:request).new } + + memoized(:ssl) { self.class.options_for(:ssl).new } + + memoized(:builder_class) { RackBuilder } + + def new_builder(block) + builder_class.new(&block) + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options/env.rb b/bin/gems/faraday-2.9.0/lib/faraday/options/env.rb new file mode 100644 index 00000000..fb04b117 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options/env.rb @@ -0,0 +1,204 @@ +# frozen_string_literal: true + +module Faraday + # @!parse + # # @!attribute method + # # @return [Symbol] HTTP method (`:get`, `:post`) + # # + # # @!attribute body + # # @return [String] The request body that will eventually be converted to a + # # string. + # # + # # @!attribute url + # # @return [URI] URI instance for the current request. + # # + # # @!attribute request + # # @return [Hash] options for configuring the request. + # # Options for configuring the request. + # # + # # - `:timeout` - time limit for the entire request (Integer in + # # seconds) + # # - `:open_timeout` - time limit for just the connection phase (e.g. + # # handshake) (Integer in seconds) + # # - `:read_timeout` - time limit for the first response byte received from + # # the server (Integer in seconds) + # # - `:write_timeout` - time limit for the client to send the request to the + # # server (Integer in seconds) + # # - `:on_data` - Proc for streaming + # # - `:proxy` - Hash of proxy options + # # - `:uri` - Proxy server URI + # # - `:user` - Proxy server username + # # - `:password` - Proxy server password + # # + # # @!attribute request_headers + # # @return [Hash] HTTP Headers to be sent to the server. + # # + # # @!attribute ssl + # # @return [Hash] options for configuring SSL requests + # # + # # @!attribute parallel_manager + # # @return [Object] sent if the connection is in parallel mode + # # + # # @!attribute params + # # @return [Hash] + # # + # # @!attribute response + # # @return [Response] + # # + # # @!attribute response_headers + # # @return [Hash] HTTP headers from the server + # # + # # @!attribute status + # # @return [Integer] HTTP response status code + # # + # # @!attribute reason_phrase + # # @return [String] + # class Env < Options; end + Env = Options.new(:method, :request_body, :url, :request, + :request_headers, :ssl, :parallel_manager, :params, + :response, :response_headers, :status, + :reason_phrase, :response_body) do + const_set(:ContentLength, 'Content-Length') + const_set(:StatusesWithoutBody, Set.new([204, 304])) + const_set(:SuccessfulStatuses, (200..299)) + + # A Set of HTTP verbs that typically send a body. If no body is set for + # these requests, the Content-Length header is set to 0. + const_set(:MethodsWithBodies, Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym))) + + options request: RequestOptions, + request_headers: Utils::Headers, response_headers: Utils::Headers + + extend Forwardable + + def_delegators :request, :params_encoder + + # Build a new Env from given value. Respects and updates `custom_members`. + # + # @param value [Object] a value fitting Option.from(v). + # @return [Env] from given value + def self.from(value) + env = super(value) + if value.respond_to?(:custom_members) + env.custom_members.update(value.custom_members) + end + env + end + + # @param key [Object] + def [](key) + return self[current_body] if key == :body + + if in_member_set?(key) + super(key) + else + custom_members[key] + end + end + + # @param key [Object] + # @param value [Object] + def []=(key, value) + if key == :body + super(current_body, value) + return + end + + if in_member_set?(key) + super(key, value) + else + custom_members[key] = value + end + end + + def current_body + !!status ? :response_body : :request_body + end + + def body + self[:body] + end + + def body=(value) + self[:body] = value + end + + # @return [Boolean] true if status is in the set of {SuccessfulStatuses}. + def success? + Env::SuccessfulStatuses.include?(status) + end + + # @return [Boolean] true if there's no body yet, and the method is in the + # set of {Env::MethodsWithBodies}. + def needs_body? + !body && Env::MethodsWithBodies.include?(method) + end + + # Sets content length to zero and the body to the empty string. + def clear_body + request_headers[Env::ContentLength] = '0' + self.body = +'' + end + + # @return [Boolean] true if the status isn't in the set of + # {Env::StatusesWithoutBody}. + def parse_body? + !Env::StatusesWithoutBody.include?(status) + end + + # @return [Boolean] true if there is a parallel_manager + def parallel? + !!parallel_manager + end + + def inspect + attrs = [nil] + members.each do |mem| + if (value = send(mem)) + attrs << "@#{mem}=#{value.inspect}" + end + end + attrs << "@custom=#{custom_members.inspect}" unless custom_members.empty? + %(#<#{self.class}#{attrs.join(' ')}>) + end + + def stream_response? + request.stream_response? + end + + def stream_response(&block) + size = 0 + yielded = false + block_result = block.call do |chunk| # rubocop:disable Performance/RedundantBlockCall + if chunk.bytesize.positive? || size.positive? + yielded = true + size += chunk.bytesize + request.on_data.call(chunk, size, self) + end + end + request.on_data.call(+'', 0, self) unless yielded + block_result + end + + # @private + def custom_members + @custom_members ||= {} + end + + # @private + if members.first.is_a?(Symbol) + def in_member_set?(key) + self.class.member_set.include?(key.to_sym) + end + else + def in_member_set?(key) + self.class.member_set.include?(key.to_s) + end + end + + # @private + def self.member_set + @member_set ||= Set.new(members) + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options/proxy_options.rb b/bin/gems/faraday-2.9.0/lib/faraday/options/proxy_options.rb new file mode 100644 index 00000000..8d8b0238 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options/proxy_options.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Faraday + # @!parse + # # ProxyOptions contains the configurable properties for the proxy + # # configuration used when making an HTTP request. + # class ProxyOptions < Options; end + ProxyOptions = Options.new(:uri, :user, :password) do + extend Forwardable + def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, + :path, :path= + + def self.from(value) + case value + when '' + value = nil + when String + # URIs without a scheme should default to http (like 'example:123'). + # This fixes #1282 and prevents a silent failure in some adapters. + value = "http://#{value}" unless value.include?('://') + value = { uri: Utils.URI(value) } + when URI + value = { uri: value } + when Hash, Options + if (uri = value.delete(:uri)) + value[:uri] = Utils.URI(uri) + end + end + + super(value) + end + + memoized(:user) { uri&.user && Utils.unescape(uri.user) } + memoized(:password) { uri&.password && Utils.unescape(uri.password) } + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options/request_options.rb b/bin/gems/faraday-2.9.0/lib/faraday/options/request_options.rb new file mode 100644 index 00000000..3bb67c8e --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options/request_options.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Faraday + # @!parse + # # RequestOptions contains the configurable properties for a Faraday request. + # class RequestOptions < Options; end + RequestOptions = Options.new(:params_encoder, :proxy, :bind, + :timeout, :open_timeout, :read_timeout, + :write_timeout, :boundary, :oauth, + :context, :on_data) do + def []=(key, value) + if key && key.to_sym == :proxy + super(key, value ? ProxyOptions.from(value) : nil) + else + super(key, value) + end + end + + def stream_response? + on_data.is_a?(Proc) + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/options/ssl_options.rb b/bin/gems/faraday-2.9.0/lib/faraday/options/ssl_options.rb new file mode 100644 index 00000000..2a04ea17 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/options/ssl_options.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Faraday + # @!parse + # # SSL-related options. + # # + # # @!attribute verify + # # @return [Boolean] whether to verify SSL certificates or not + # # + # # @!attribute verify_hostname + # # @return [Boolean] whether to enable hostname verification on server certificates + # # during the handshake or not (see https://github.com/ruby/openssl/pull/60) + # # + # # @!attribute ca_file + # # @return [String] CA file + # # + # # @!attribute ca_path + # # @return [String] CA path + # # + # # @!attribute verify_mode + # # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html) + # # + # # @!attribute cert_store + # # @return [OpenSSL::X509::Store] certificate store + # # + # # @!attribute client_cert + # # @return [String, OpenSSL::X509::Certificate] client certificate + # # + # # @!attribute client_key + # # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key + # # + # # @!attribute certificate + # # @return [OpenSSL::X509::Certificate] certificate (Excon only) + # # + # # @!attribute private_key + # # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only) + # # + # # @!attribute verify_depth + # # @return [Integer] maximum depth for the certificate chain verification + # # + # # @!attribute version + # # @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D) + # # + # # @!attribute min_version + # # @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D) + # # + # # @!attribute max_version + # # @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D) + # class SSLOptions < Options; end + SSLOptions = Options.new(:verify, :verify_hostname, + :ca_file, :ca_path, :verify_mode, + :cert_store, :client_cert, :client_key, + :certificate, :private_key, :verify_depth, + :version, :min_version, :max_version) do + # @return [Boolean] true if should verify + def verify? + verify != false + end + + # @return [Boolean] true if should not verify + def disable? + !verify? + end + + # @return [Boolean] true if should verify_hostname + def verify_hostname? + verify_hostname != false + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/parameters.rb b/bin/gems/faraday-2.9.0/lib/faraday/parameters.rb new file mode 100644 index 00000000..cfb35d08 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/parameters.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require 'forwardable' +require 'faraday/encoders/nested_params_encoder' +require 'faraday/encoders/flat_params_encoder' diff --git a/bin/gems/faraday-2.9.0/lib/faraday/rack_builder.rb b/bin/gems/faraday-2.9.0/lib/faraday/rack_builder.rb new file mode 100644 index 00000000..e8e62082 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/rack_builder.rb @@ -0,0 +1,251 @@ +# frozen_string_literal: true + +require 'faraday/adapter_registry' + +module Faraday + # A Builder that processes requests into responses by passing through an inner + # middleware stack (heavily inspired by Rack). + # + # @example + # Faraday::Connection.new(url: 'http://httpbingo.org') do |builder| + # builder.request :url_encoded # Faraday::Request::UrlEncoded + # builder.adapter :net_http # Faraday::Adapter::NetHttp + # end + class RackBuilder + # Used to detect missing arguments + NO_ARGUMENT = Object.new + + attr_accessor :handlers + + # Error raised when trying to modify the stack after calling `lock!` + class StackLocked < RuntimeError; end + + # borrowed from ActiveSupport::Dependencies::Reference & + # ActionDispatch::MiddlewareStack::Middleware + class Handler + REGISTRY = Faraday::AdapterRegistry.new + + attr_reader :name + + ruby2_keywords def initialize(klass, *args, &block) + @name = klass.to_s + REGISTRY.set(klass) if klass.respond_to?(:name) + @args = args + @block = block + end + + def klass + REGISTRY.get(@name) + end + + def inspect + @name + end + + def ==(other) + if other.is_a? Handler + name == other.name + elsif other.respond_to? :name + klass == other + else + @name == other.to_s + end + end + + def build(app = nil) + klass.new(app, *@args, &@block) + end + end + + def initialize(&block) + @adapter = nil + @handlers = [] + build(&block) + end + + def initialize_dup(original) + super + @adapter = original.adapter + @handlers = original.handlers.dup + end + + def build + raise_if_locked + block_given? ? yield(self) : request(:url_encoded) + adapter(Faraday.default_adapter, **Faraday.default_adapter_options) unless @adapter + end + + def [](idx) + @handlers[idx] + end + + # Locks the middleware stack to ensure no further modifications are made. + def lock! + @handlers.freeze + end + + def locked? + @handlers.frozen? + end + + ruby2_keywords def use(klass, *args, &block) + if klass.is_a? Symbol + use_symbol(Faraday::Middleware, klass, *args, &block) + else + raise_if_locked + raise_if_adapter(klass) + @handlers << self.class::Handler.new(klass, *args, &block) + end + end + + ruby2_keywords def request(key, *args, &block) + use_symbol(Faraday::Request, key, *args, &block) + end + + ruby2_keywords def response(key, *args, &block) + use_symbol(Faraday::Response, key, *args, &block) + end + + ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block) + return @adapter if klass == NO_ARGUMENT || klass.nil? + + klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol) + @adapter = self.class::Handler.new(klass, *args, &block) + end + + ## methods to push onto the various positions in the stack: + + ruby2_keywords def insert(index, *args, &block) + raise_if_locked + index = assert_index(index) + handler = self.class::Handler.new(*args, &block) + @handlers.insert(index, handler) + end + + alias insert_before insert + + ruby2_keywords def insert_after(index, *args, &block) + index = assert_index(index) + insert(index + 1, *args, &block) + end + + ruby2_keywords def swap(index, *args, &block) + raise_if_locked + index = assert_index(index) + @handlers.delete_at(index) + insert(index, *args, &block) + end + + def delete(handler) + raise_if_locked + @handlers.delete(handler) + end + + # Processes a Request into a Response by passing it through this Builder's + # middleware stack. + # + # @param connection [Faraday::Connection] + # @param request [Faraday::Request] + # + # @return [Faraday::Response] + def build_response(connection, request) + app.call(build_env(connection, request)) + end + + # The "rack app" wrapped in middleware. All requests are sent here. + # + # The builder is responsible for creating the app object. After this, + # the builder gets locked to ensure no further modifications are made + # to the middleware stack. + # + # Returns an object that responds to `call` and returns a Response. + def app + @app ||= begin + lock! + ensure_adapter! + to_app + end + end + + def to_app + # last added handler is the deepest and thus closest to the inner app + # adapter is always the last one + @handlers.reverse.inject(@adapter.build) do |app, handler| + handler.build(app) + end + end + + def ==(other) + other.is_a?(self.class) && + @handlers == other.handlers && + @adapter == other.adapter + end + + # ENV Keys + # :http_method - a symbolized request HTTP method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def build_env(connection, request) + exclusive_url = connection.build_exclusive_url( + request.path, request.params, + request.options.params_encoder + ) + + Env.new(request.http_method, request.body, exclusive_url, + request.options, request.headers, connection.ssl, + connection.parallel_manager) + end + + private + + LOCK_ERR = "can't modify middleware stack after making a request" + MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \ + "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \ + 'For more info, check https://lostisland.github.io/faraday/usage/.' + + def raise_if_locked + raise StackLocked, LOCK_ERR if locked? + end + + def raise_if_adapter(klass) + return unless is_adapter?(klass) + + raise 'Adapter should be set using the `adapter` method, not `use`' + end + + def ensure_adapter! + raise MISSING_ADAPTER_ERROR unless @adapter + end + + def adapter_set? + !@adapter.nil? + end + + def is_adapter?(klass) # rubocop:disable Naming/PredicateName + klass <= Faraday::Adapter + end + + ruby2_keywords def use_symbol(mod, key, *args, &block) + use(mod.lookup_middleware(key), *args, &block) + end + + def assert_index(index) + idx = index.is_a?(Integer) ? index : @handlers.index(index) + raise "No such handler: #{index.inspect}" unless idx + + idx + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/request.rb b/bin/gems/faraday-2.9.0/lib/faraday/request.rb new file mode 100644 index 00000000..8c5bf952 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/request.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +module Faraday + # Used to setup URLs, params, headers, and the request body in a sane manner. + # + # @example + # @connection.post do |req| + # req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1' + # req.headers['b'] = '2' # Header + # req.params['c'] = '3' # GET Param + # req['b'] = '2' # also Header + # req.body = 'abc' + # end + # + # @!attribute http_method + # @return [Symbol] the HTTP method of the Request + # @!attribute path + # @return [URI, String] the path + # @!attribute params + # @return [Hash] query parameters + # @!attribute headers + # @return [Faraday::Utils::Headers] headers + # @!attribute body + # @return [String] body + # @!attribute options + # @return [RequestOptions] options + Request = Struct.new(:http_method, :path, :params, :headers, :body, :options) do + extend MiddlewareRegistry + + alias_method :member_get, :[] + private :member_get + alias_method :member_set, :[]= + private :member_set + + # @param request_method [String] + # @yield [request] for block customization, if block given + # @yieldparam request [Request] + # @return [Request] + def self.create(request_method) + new(request_method).tap do |request| + yield(request) if block_given? + end + end + + remove_method :params= + # Replace params, preserving the existing hash type. + # + # @param hash [Hash] new params + def params=(hash) + if params + params.replace hash + else + member_set(:params, hash) + end + end + + remove_method :headers= + # Replace request headers, preserving the existing hash type. + # + # @param hash [Hash] new headers + def headers=(hash) + if headers + headers.replace hash + else + member_set(:headers, hash) + end + end + + # Update path and params. + # + # @param path [URI, String] + # @param params [Hash, nil] + # @return [void] + def url(path, params = nil) + if path.respond_to? :query + if (query = path.query) + path = path.dup + path.query = nil + end + else + anchor_index = path.index('#') + path = path.slice(0, anchor_index) unless anchor_index.nil? + path, query = path.split('?', 2) + end + self.path = path + self.params.merge_query query, options.params_encoder + self.params.update(params) if params + end + + # @param key [Object] key to look up in headers + # @return [Object] value of the given header name + def [](key) + headers[key] + end + + # @param key [Object] key of header to write + # @param value [Object] value of header + def []=(key, value) + headers[key] = value + end + + # Marshal serialization support. + # + # @return [Hash] the hash ready to be serialized in Marshal. + def marshal_dump + { + http_method: http_method, + body: body, + headers: headers, + path: path, + params: params, + options: options + } + end + + # Marshal serialization support. + # Restores the instance variables according to the +serialised+. + # @param serialised [Hash] the serialised object. + def marshal_load(serialised) + self.http_method = serialised[:http_method] + self.body = serialised[:body] + self.headers = serialised[:headers] + self.path = serialised[:path] + self.params = serialised[:params] + self.options = serialised[:options] + end + + # @return [Env] the Env for this Request + def to_env(connection) + Env.new(http_method, body, connection.build_exclusive_url(path, params), + options, headers, connection.ssl, connection.parallel_manager) + end + end +end + +require 'faraday/request/authorization' +require 'faraday/request/instrumentation' +require 'faraday/request/json' +require 'faraday/request/url_encoded' diff --git a/bin/gems/faraday-2.9.0/lib/faraday/request/authorization.rb b/bin/gems/faraday-2.9.0/lib/faraday/request/authorization.rb new file mode 100644 index 00000000..43732432 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/request/authorization.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Faraday + class Request + # Request middleware for the Authorization HTTP header + class Authorization < Faraday::Middleware + KEY = 'Authorization' + + # @param app [#call] + # @param type [String, Symbol] Type of Authorization + # @param params [Array] parameters to build the Authorization header. + # If the type is `:basic`, then these can be a login and password pair. + # Otherwise, a single value is expected that will be appended after the type. + # This value can be a proc or an object responding to `.call`, in which case + # it will be invoked on each request. + def initialize(app, type, *params) + @type = type + @params = params + super(app) + end + + # @param env [Faraday::Env] + def on_request(env) + return if env.request_headers[KEY] + + env.request_headers[KEY] = header_from(@type, env, *@params) + end + + private + + # @param type [String, Symbol] + # @param env [Faraday::Env] + # @param params [Array] + # @return [String] a header value + def header_from(type, env, *params) + if type.to_s.casecmp('basic').zero? && params.size == 2 + Utils.basic_header_from(*params) + elsif params.size != 1 + raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)" + else + value = params.first + if (value.is_a?(Proc) && value.arity == 1) || (value.respond_to?(:call) && value.method(:call).arity == 1) + value = value.call(env) + elsif value.is_a?(Proc) || value.respond_to?(:call) + value = value.call + end + "#{type} #{value}" + end + end + end + end +end + +Faraday::Request.register_middleware(authorization: Faraday::Request::Authorization) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/request/instrumentation.rb b/bin/gems/faraday-2.9.0/lib/faraday/request/instrumentation.rb new file mode 100644 index 00000000..a5020598 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/request/instrumentation.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Faraday + class Request + # Middleware for instrumenting Requests. + class Instrumentation < Faraday::Middleware + # Options class used in Request::Instrumentation class. + Options = Faraday::Options.new(:name, :instrumenter) do + remove_method :name + # @return [String] + def name + self[:name] ||= 'request.faraday' + end + + remove_method :instrumenter + # @return [Class] + def instrumenter + self[:instrumenter] ||= ActiveSupport::Notifications + end + end + + # Instruments requests using Active Support. + # + # Measures time spent only for synchronous requests. + # + # @example Using ActiveSupport::Notifications to measure time spent + # for Faraday requests. + # ActiveSupport::Notifications + # .subscribe('request.faraday') do |name, starts, ends, _, env| + # url = env[:url] + # http_method = env[:method].to_s.upcase + # duration = ends - starts + # $stderr.puts '[%s] %s %s (%.3f s)' % + # [url.host, http_method, url.request_uri, duration] + # end + # @param app [#call] + # @param options [nil, Hash] Options hash + # @option options [String] :name ('request.faraday') + # Name of the instrumenter + # @option options [Class] :instrumenter (ActiveSupport::Notifications) + # Active Support instrumenter class. + def initialize(app, options = nil) + super(app) + @name, @instrumenter = Options.from(options) + .values_at(:name, :instrumenter) + end + + # @param env [Faraday::Env] + def call(env) + @instrumenter.instrument(@name, env) do + @app.call(env) + end + end + end + end +end + +Faraday::Request.register_middleware(instrumentation: Faraday::Request::Instrumentation) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/request/json.rb b/bin/gems/faraday-2.9.0/lib/faraday/request/json.rb new file mode 100644 index 00000000..f12ebe29 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/request/json.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'json' + +module Faraday + class Request + # Request middleware that encodes the body as JSON. + # + # Processes only requests with matching Content-type or those without a type. + # If a request doesn't have a type but has a body, it sets the Content-type + # to JSON MIME-type. + # + # Doesn't try to encode bodies that already are in string form. + class Json < Middleware + MIME_TYPE = 'application/json' + MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?json$} + + def on_request(env) + match_content_type(env) do |data| + env[:body] = encode(data) + end + end + + private + + def encode(data) + if options[:encoder].is_a?(Array) && options[:encoder].size >= 2 + options[:encoder][0].public_send(options[:encoder][1], data) + elsif options[:encoder].respond_to?(:dump) + options[:encoder].dump(data) + else + ::JSON.generate(data) + end + end + + def match_content_type(env) + return unless process_request?(env) + + env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE + yield env[:body] unless env[:body].respond_to?(:to_str) + end + + def process_request?(env) + type = request_type(env) + body?(env) && (type.empty? || type.match?(MIME_TYPE_REGEX)) + end + + def body?(env) + body = env[:body] + case body + when true, false + true + when nil + # NOTE: nil can be converted to `"null"`, but this middleware doesn't process `nil` for the compatibility. + false + else + !(body.respond_to?(:to_str) && body.empty?) + end + end + + def request_type(env) + type = env[:request_headers][CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + end + end +end + +Faraday::Request.register_middleware(json: Faraday::Request::Json) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/request/url_encoded.rb b/bin/gems/faraday-2.9.0/lib/faraday/request/url_encoded.rb new file mode 100644 index 00000000..5ac7dcb3 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/request/url_encoded.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Faraday + class Request + # Middleware for supporting urlencoded requests. + class UrlEncoded < Faraday::Middleware + unless defined?(::Faraday::Request::UrlEncoded::CONTENT_TYPE) + CONTENT_TYPE = 'Content-Type' + end + + class << self + attr_accessor :mime_type + end + self.mime_type = 'application/x-www-form-urlencoded' + + # Encodes as "application/x-www-form-urlencoded" if not already encoded or + # of another type. + # + # @param env [Faraday::Env] + def call(env) + match_content_type(env) do |data| + params = Faraday::Utils::ParamsHash[data] + env.body = params.to_query(env.params_encoder) + end + @app.call env + end + + # @param env [Faraday::Env] + # @yield [request_body] Body of the request + def match_content_type(env) + return unless process_request?(env) + + env.request_headers[CONTENT_TYPE] ||= self.class.mime_type + return if env.body.respond_to?(:to_str) || env.body.respond_to?(:read) + + yield(env.body) + end + + # @param env [Faraday::Env] + # + # @return [Boolean] True if the request has a body and its Content-Type is + # urlencoded. + def process_request?(env) + type = request_type(env) + env.body && (type.empty? || (type == self.class.mime_type)) + end + + # @param env [Faraday::Env] + # + # @return [String] + def request_type(env) + type = env.request_headers[CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + end + end +end + +Faraday::Request.register_middleware(url_encoded: Faraday::Request::UrlEncoded) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/response.rb b/bin/gems/faraday-2.9.0/lib/faraday/response.rb new file mode 100644 index 00000000..d1fa9320 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/response.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'forwardable' + +module Faraday + # Response represents an HTTP response from making an HTTP request. + class Response + extend Forwardable + extend MiddlewareRegistry + + def initialize(env = nil) + @env = Env.from(env) if env + @on_complete_callbacks = [] + end + + attr_reader :env + + def status + finished? ? env.status : nil + end + + def reason_phrase + finished? ? env.reason_phrase : nil + end + + def headers + finished? ? env.response_headers : {} + end + + def_delegator :headers, :[] + + def body + finished? ? env.body : nil + end + + def finished? + !!env + end + + def on_complete(&block) + if finished? + yield(env) + else + @on_complete_callbacks << block + end + self + end + + def finish(env) + raise 'response already finished' if finished? + + @env = env.is_a?(Env) ? env : Env.from(env) + @on_complete_callbacks.each { |callback| callback.call(@env) } + self + end + + def success? + finished? && env.success? + end + + def to_hash + { + status: env.status, body: env.body, + response_headers: env.response_headers, + url: env.url + } + end + + # because @on_complete_callbacks cannot be marshalled + def marshal_dump + finished? ? to_hash : nil + end + + def marshal_load(env) + @env = Env.from(env) + end + + # Expand the env with more properties, without overriding existing ones. + # Useful for applying request params after restoring a marshalled Response. + def apply_request(request_env) + raise "response didn't finish yet" unless finished? + + @env = Env.from(request_env).update(@env) + self + end + end +end + +require 'faraday/response/json' +require 'faraday/response/logger' +require 'faraday/response/raise_error' diff --git a/bin/gems/faraday-2.9.0/lib/faraday/response/json.rb b/bin/gems/faraday-2.9.0/lib/faraday/response/json.rb new file mode 100644 index 00000000..eaae6bc2 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/response/json.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'json' + +module Faraday + class Response + # Parse response bodies as JSON. + class Json < Middleware + def initialize(app = nil, parser_options: nil, content_type: /\bjson$/, preserve_raw: false) + super(app) + @parser_options = parser_options + @content_types = Array(content_type) + @preserve_raw = preserve_raw + + process_parser_options + end + + def on_complete(env) + process_response(env) if parse_response?(env) + end + + private + + def process_response(env) + env[:raw_body] = env[:body] if @preserve_raw + env[:body] = parse(env[:body]) + rescue StandardError, SyntaxError => e + raise Faraday::ParsingError.new(e, env[:response]) + end + + def parse(body) + return if body.strip.empty? + + decoder, method_name = @decoder_options + + decoder.public_send(method_name, body, @parser_options || {}) + end + + def parse_response?(env) + process_response_type?(env) && + env[:body].respond_to?(:to_str) + end + + def process_response_type?(env) + type = response_type(env) + @content_types.empty? || @content_types.any? do |pattern| + pattern.is_a?(Regexp) ? type.match?(pattern) : type == pattern + end + end + + def response_type(env) + type = env[:response_headers][CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + + def process_parser_options + @decoder_options = @parser_options&.delete(:decoder) + + @decoder_options = + if @decoder_options.is_a?(Array) && @decoder_options.size >= 2 + @decoder_options.slice(0, 2) + elsif @decoder_options.respond_to?(:load) + [@decoder_options, :load] + else + [::JSON, :parse] + end + end + end + end +end + +Faraday::Response.register_middleware(json: Faraday::Response::Json) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/response/logger.rb b/bin/gems/faraday-2.9.0/lib/faraday/response/logger.rb new file mode 100644 index 00000000..d4641462 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/response/logger.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'forwardable' +require 'logger' +require 'faraday/logging/formatter' + +module Faraday + class Response + # Logger is a middleware that logs internal events in the HTTP request + # lifecycle to a given Logger object. By default, this logs to STDOUT. See + # Faraday::Logging::Formatter to see specifically what is logged. + class Logger < Middleware + def initialize(app, logger = nil, options = {}) + super(app) + logger ||= ::Logger.new($stdout) + formatter_class = options.delete(:formatter) || Logging::Formatter + @formatter = formatter_class.new(logger: logger, options: options) + yield @formatter if block_given? + end + + def call(env) + @formatter.request(env) + super + end + + def on_complete(env) + @formatter.response(env) + end + + def on_error(exc) + @formatter.exception(exc) if @formatter.respond_to?(:exception) + end + end + end +end + +Faraday::Response.register_middleware(logger: Faraday::Response::Logger) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/response/raise_error.rb b/bin/gems/faraday-2.9.0/lib/faraday/response/raise_error.rb new file mode 100644 index 00000000..76de80bb --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/response/raise_error.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module Faraday + class Response + # RaiseError is a Faraday middleware that raises exceptions on common HTTP + # client or server error responses. + class RaiseError < Middleware + # rubocop:disable Naming/ConstantName + ClientErrorStatuses = (400...500) + ServerErrorStatuses = (500...600) + # rubocop:enable Naming/ConstantName + + def on_complete(env) + case env[:status] + when 400 + raise Faraday::BadRequestError, response_values(env) + when 401 + raise Faraday::UnauthorizedError, response_values(env) + when 403 + raise Faraday::ForbiddenError, response_values(env) + when 404 + raise Faraday::ResourceNotFound, response_values(env) + when 407 + # mimic the behavior that we get with proxy requests with HTTPS + msg = %(407 "Proxy Authentication Required") + raise Faraday::ProxyAuthError.new(msg, response_values(env)) + when 408 + raise Faraday::RequestTimeoutError, response_values(env) + when 409 + raise Faraday::ConflictError, response_values(env) + when 422 + raise Faraday::UnprocessableEntityError, response_values(env) + when 429 + raise Faraday::TooManyRequestsError, response_values(env) + when ClientErrorStatuses + raise Faraday::ClientError, response_values(env) + when ServerErrorStatuses + raise Faraday::ServerError, response_values(env) + when nil + raise Faraday::NilStatusError, response_values(env) + end + end + + # Returns a hash of response data with the following keys: + # - status + # - headers + # - body + # - request + # + # The `request` key is omitted when the middleware is explicitly + # configured with the option `include_request: false`. + def response_values(env) + response = { + status: env.status, + headers: env.response_headers, + body: env.body + } + + # Include the request data by default. If the middleware was explicitly + # configured to _not_ include request data, then omit it. + return response unless options.fetch(:include_request, true) + + response.merge( + request: { + method: env.method, + url: env.url, + url_path: env.url.path, + params: query_params(env), + headers: env.request_headers, + body: env.request_body + } + ) + end + + def query_params(env) + env.request.params_encoder ||= Faraday::Utils.default_params_encoder + env.params_encoder.decode(env.url.query) + end + end + end +end + +Faraday::Response.register_middleware(raise_error: Faraday::Response::RaiseError) diff --git a/bin/gems/faraday-2.9.0/lib/faraday/utils.rb b/bin/gems/faraday-2.9.0/lib/faraday/utils.rb new file mode 100644 index 00000000..809b3a88 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/utils.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require 'uri' +require 'faraday/utils/headers' +require 'faraday/utils/params_hash' + +module Faraday + # Utils contains various static helper methods. + module Utils + module_function + + def build_query(params) + FlatParamsEncoder.encode(params) + end + + def build_nested_query(params) + NestedParamsEncoder.encode(params) + end + + def default_space_encoding + @default_space_encoding ||= '+' + end + + class << self + attr_writer :default_space_encoding + end + + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def escape(str) + str.to_s.gsub(ESCAPE_RE) do |match| + "%#{match.unpack('H2' * match.bytesize).join('%').upcase}" + end.gsub(' ', default_space_encoding) + end + + def unescape(str) + CGI.unescape str.to_s + end + + DEFAULT_SEP = /[&;] */n + + # Adapted from Rack + def parse_query(query) + FlatParamsEncoder.decode(query) + end + + def parse_nested_query(query) + NestedParamsEncoder.decode(query) + end + + def default_params_encoder + @default_params_encoder ||= NestedParamsEncoder + end + + def basic_header_from(login, pass) + value = ["#{login}:#{pass}"].pack('m') # Base64 encoding + value.delete!("\n") + "Basic #{value}" + end + + class << self + attr_writer :default_params_encoder + end + + # Normalize URI() behavior across Ruby versions + # + # url - A String or URI. + # + # Returns a parsed URI. + def URI(url) # rubocop:disable Naming/MethodName + if url.respond_to?(:host) + url + elsif url.respond_to?(:to_str) + default_uri_parser.call(url) + else + raise ArgumentError, 'bad argument (expected URI object or URI string)' + end + end + + def default_uri_parser + @default_uri_parser ||= Kernel.method(:URI) + end + + def default_uri_parser=(parser) + @default_uri_parser = if parser.respond_to?(:call) || parser.nil? + parser + else + parser.method(:parse) + end + end + + # Receives a String or URI and returns just + # the path with the query string sorted. + def normalize_path(url) + url = URI(url) + (url.path.start_with?('/') ? url.path : "/#{url.path}") + + (url.query ? "?#{sort_query_params(url.query)}" : '') + end + + # Recursive hash update + def deep_merge!(target, hash) + hash.each do |key, value| + target[key] = if value.is_a?(Hash) && (target[key].is_a?(Hash) || target[key].is_a?(Options)) + deep_merge(target[key], value) + else + value + end + end + target + end + + # Recursive hash merge + def deep_merge(source, hash) + deep_merge!(source.dup, hash) + end + + def sort_query_params(query) + query.split('&').sort.join('&') + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/utils/headers.rb b/bin/gems/faraday-2.9.0/lib/faraday/utils/headers.rb new file mode 100644 index 00000000..90b8be24 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/utils/headers.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +module Faraday + module Utils + # A case-insensitive Hash that preserves the original case of a header + # when set. + # + # Adapted from Rack::Utils::HeaderHash + class Headers < ::Hash + def self.from(value) + new(value) + end + + def self.allocate + new_self = super + new_self.initialize_names + new_self + end + + def initialize(hash = nil) + super() + @names = {} + update(hash || {}) + end + + def initialize_names + @names = {} + end + + # on dup/clone, we need to duplicate @names hash + def initialize_copy(other) + super + @names = other.names.dup + end + + # need to synchronize concurrent writes to the shared KeyMap + keymap_mutex = Mutex.new + + # symbol -> string mapper + cache + KeyMap = Hash.new do |map, key| + value = if key.respond_to?(:to_str) + key + else + key.to_s.split('_') # user_agent: %w(user agent) + .each(&:capitalize!) # => %w(User Agent) + .join('-') # => "User-Agent" + end + keymap_mutex.synchronize { map[key] = value } + end + KeyMap[:etag] = 'ETag' + + def [](key) + key = KeyMap[key] + super(key) || super(@names[key.downcase]) + end + + def []=(key, val) + key = KeyMap[key] + key = (@names[key.downcase] ||= key) + # join multiple values with a comma + val = val.to_ary.join(', ') if val.respond_to?(:to_ary) + super(key, val) + end + + def fetch(key, *args, &block) + key = KeyMap[key] + key = @names.fetch(key.downcase, key) + super(key, *args, &block) + end + + def delete(key) + key = KeyMap[key] + key = @names[key.downcase] + return unless key + + @names.delete key.downcase + super(key) + end + + def include?(key) + @names.include? key.downcase + end + + alias has_key? include? + alias member? include? + alias key? include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + + alias update merge! + + def merge(other) + hash = dup + hash.merge! other + end + + def replace(other) + clear + @names.clear + update other + self + end + + def to_hash + {}.update(self) + end + + def parse(header_string) + return unless header_string && !header_string.empty? + + headers = header_string.split("\r\n") + + # Find the last set of response headers. + start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0 + last_response = headers.slice(start_index, headers.size) + + last_response + .tap { |a| a.shift if a.first.start_with?('HTTP/') } + .map { |h| h.split(/:\s*/, 2) } # split key and value + .reject { |p| p[0].nil? } # ignore blank lines + .each { |key, value| add_parsed(key, value) } + end + + protected + + attr_reader :names + + private + + # Join multiple values with a comma. + def add_parsed(key, value) + if key?(key) + self[key] = self[key].to_s + self[key] << ', ' << value + else + self[key] = value + end + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/utils/params_hash.rb b/bin/gems/faraday-2.9.0/lib/faraday/utils/params_hash.rb new file mode 100644 index 00000000..0e16d935 --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/utils/params_hash.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Faraday + module Utils + # A hash with stringified keys. + class ParamsHash < Hash + def [](key) + super(convert_key(key)) + end + + def []=(key, value) + super(convert_key(key), value) + end + + def delete(key) + super(convert_key(key)) + end + + def include?(key) + super(convert_key(key)) + end + + alias has_key? include? + alias member? include? + alias key? include? + + def update(params) + params.each do |key, value| + self[key] = value + end + self + end + alias merge! update + + def merge(params) + dup.update(params) + end + + def replace(other) + clear + update(other) + end + + def merge_query(query, encoder = nil) + return self unless query && !query.empty? + + update((encoder || Utils.default_params_encoder).decode(query)) + end + + def to_query(encoder = nil) + (encoder || Utils.default_params_encoder).encode(self) + end + + private + + def convert_key(key) + key.to_s + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/lib/faraday/version.rb b/bin/gems/faraday-2.9.0/lib/faraday/version.rb new file mode 100644 index 00000000..9b45758d --- /dev/null +++ b/bin/gems/faraday-2.9.0/lib/faraday/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Faraday + VERSION = '2.9.0' +end diff --git a/bin/gems/faraday-2.9.0/spec/external_adapters/faraday_specs_setup.rb b/bin/gems/faraday-2.9.0/spec/external_adapters/faraday_specs_setup.rb new file mode 100644 index 00000000..ac7f7b64 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/external_adapters/faraday_specs_setup.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'webmock/rspec' +WebMock.disable_net_connect!(allow_localhost: true) + +require_relative '../support/helper_methods' +require_relative '../support/disabling_stub' +require_relative '../support/streaming_response_checker' +require_relative '../support/shared_examples/adapter' +require_relative '../support/shared_examples/request_method' + +RSpec.configure do |config| + config.include Faraday::HelperMethods +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/adapter/test_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/adapter/test_spec.rb new file mode 100644 index 00000000..117bb789 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/adapter/test_spec.rb @@ -0,0 +1,442 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Adapter::Test do + let(:stubs) do + described_class::Stubs.new do |stub| + stub.get('http://domain.test/hello') do + [200, { 'Content-Type' => 'text/html' }, 'domain: hello'] + end + + stub.get('http://wrong.test/hello') do + [200, { 'Content-Type' => 'text/html' }, 'wrong: hello'] + end + + stub.get('http://wrong.test/bait') do + [404, { 'Content-Type' => 'text/html' }] + end + + stub.get('/hello') do + [200, { 'Content-Type' => 'text/html' }, 'hello'] + end + + stub.get('/method-echo') do |env| + [200, { 'Content-Type' => 'text/html' }, env[:method].to_s] + end + + stub.get(%r{\A/resources/\d+(?:\?|\z)}) do + [200, { 'Content-Type' => 'text/html' }, 'show'] + end + + stub.get(%r{\A/resources/(specified)\z}) do |_env, meta| + [200, { 'Content-Type' => 'text/html' }, "show #{meta[:match_data][1]}"] + end + end + end + + let(:connection) do + Faraday.new do |builder| + builder.adapter :test, stubs + end + end + + let(:response) { connection.get('/hello') } + + context 'with simple path sets status' do + subject { response.status } + + it { is_expected.to eq 200 } + end + + context 'with simple path sets headers' do + subject { response.headers['Content-Type'] } + + it { is_expected.to eq 'text/html' } + end + + context 'with simple path sets body' do + subject { response.body } + + it { is_expected.to eq 'hello' } + end + + context 'with host points to the right stub' do + subject { connection.get('http://domain.test/hello').body } + + it { is_expected.to eq 'domain: hello' } + end + + describe 'can be called several times' do + subject { connection.get('/hello').body } + + it { is_expected.to eq 'hello' } + end + + describe 'can handle regular expression path' do + subject { connection.get('/resources/1').body } + + it { is_expected.to eq 'show' } + end + + describe 'can handle single parameter block' do + subject { connection.get('/method-echo').body } + + it { is_expected.to eq 'get' } + end + + describe 'can handle regular expression path with captured result' do + subject { connection.get('/resources/specified').body } + + it { is_expected.to eq 'show specified' } + end + + context 'with get params' do + subject { connection.get('/param?a=1').body } + + before do + stubs.get('/param?a=1') { [200, {}, 'a'] } + end + + it { is_expected.to eq 'a' } + end + + describe 'ignoring unspecified get params' do + before do + stubs.get('/optional?a=1') { [200, {}, 'a'] } + end + + context 'with multiple params' do + subject { connection.get('/optional?a=1&b=1').body } + + it { is_expected.to eq 'a' } + end + + context 'with single param' do + subject { connection.get('/optional?a=1').body } + + it { is_expected.to eq 'a' } + end + + context 'without params' do + subject(:request) { connection.get('/optional') } + + it do + expect { request }.to raise_error( + Faraday::Adapter::Test::Stubs::NotFound + ) + end + end + end + + context 'with http headers' do + before do + stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] } + stubs.get('/yo') { [200, {}, 'b'] } + end + + context 'with header' do + subject do + connection.get('/yo') { |env| env.headers['X-HELLO'] = 'hello' }.body + end + + it { is_expected.to eq 'a' } + end + + context 'without header' do + subject do + connection.get('/yo').body + end + + it { is_expected.to eq 'b' } + end + end + + describe 'different outcomes for the same request' do + def make_request + connection.get('/foo') + end + + subject(:request) { make_request.body } + + before do + stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'hello'] } + stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'world'] } + end + + context 'the first request' do + it { is_expected.to eq 'hello' } + end + + context 'the second request' do + before do + make_request + end + + it { is_expected.to eq 'world' } + end + end + + describe 'yielding env to stubs' do + subject { connection.get('http://foo.com/foo?a=1').body } + + before do + stubs.get '/foo' do |env| + expect(env[:url].path).to eq '/foo' + expect(env[:url].host).to eq 'foo.com' + expect(env[:params]['a']).to eq '1' + expect(env[:request_headers]['Accept']).to eq 'text/plain' + [200, {}, 'a'] + end + + connection.headers['Accept'] = 'text/plain' + end + + it { is_expected.to eq 'a' } + end + + describe 'params parsing' do + subject { connection.get('http://foo.com/foo?a[b]=1').body } + + context 'with default encoder' do + before do + stubs.get '/foo' do |env| + expect(env[:params]['a']['b']).to eq '1' + [200, {}, 'a'] + end + end + + it { is_expected.to eq 'a' } + end + + context 'with nested encoder' do + before do + stubs.get '/foo' do |env| + expect(env[:params]['a']['b']).to eq '1' + [200, {}, 'a'] + end + + connection.options.params_encoder = Faraday::NestedParamsEncoder + end + + it { is_expected.to eq 'a' } + end + + context 'with flat encoder' do + before do + stubs.get '/foo' do |env| + expect(env[:params]['a[b]']).to eq '1' + [200, {}, 'a'] + end + + connection.options.params_encoder = Faraday::FlatParamsEncoder + end + + it { is_expected.to eq 'a' } + end + end + + describe 'raising an error if no stub was found' do + describe 'for request' do + subject(:request) { connection.get('/invalid') { [200, {}, []] } } + + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + + describe 'for specified host' do + subject(:request) { connection.get('http://domain.test/bait') } + + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + + describe 'for request without specified header' do + subject(:request) { connection.get('/yo') } + + before do + stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] } + end + + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + end + + describe 'for request with non default params encoder' do + let(:connection) do + Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder| + builder.adapter :test, stubs + end + end + let(:stubs) do + described_class::Stubs.new do |stubs| + stubs.get('/path?a=x&a=y&a=z') { [200, {}, 'a'] } + end + end + + context 'when all flat param values are correctly set' do + subject(:request) { connection.get('/path?a=x&a=y&a=z') } + + it { expect(request.status).to eq 200 } + end + + shared_examples 'raise NotFound when params do not satisfy the flat param values' do |params| + subject(:request) { connection.get('/path', params) } + + context "with #{params.inspect}" do + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + end + + it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x] } + it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x y] } + it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x z y] } # NOTE: The order of the value is also compared. + it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { b: %w[x y z] } + end + + describe 'strict_mode' do + let(:stubs) do + described_class::Stubs.new(strict_mode: true) do |stubs| + stubs.get('/strict?a=12&b=xy', 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello') { [200, {}, 'a'] } + stubs.get('/with_user_agent?a=12&b=xy', authorization: 'Bearer m_ck', 'User-Agent' => 'My Agent') { [200, {}, 'a'] } + end + end + + context 'when params and headers are exactly set' do + subject(:request) { connection.get('/strict', { a: '12', b: 'xy' }, { authorization: 'Bearer m_ck', x_c: 'hello' }) } + + it { expect(request.status).to eq 200 } + end + + context 'when params and headers are exactly set with a custom user agent' do + subject(:request) { connection.get('/with_user_agent', { a: '12', b: 'xy' }, { authorization: 'Bearer m_ck', 'User-Agent' => 'My Agent' }) } + + it { expect(request.status).to eq 200 } + end + + shared_examples 'raise NotFound when params do not satisfy the strict check' do |params| + subject(:request) { connection.get('/strict', params, { 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello' }) } + + context "with #{params.inspect}" do + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + end + + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12' } + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { b: 'xy' } + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '123', b: 'xy' } + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12', b: 'xyz' } + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12', b: 'xy', c: 'hello' } + it_behaves_like 'raise NotFound when params do not satisfy the strict check', { additional: 'special', a: '12', b: 'xy', c: 'hello' } + + shared_examples 'raise NotFound when headers do not satisfy the strict check' do |path, headers| + subject(:request) { connection.get(path, { a: 12, b: 'xy' }, headers) } + + context "with #{headers.inspect}" do + it { expect { request }.to raise_error described_class::Stubs::NotFound } + end + end + + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { 'X-C' => 'hello' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'Hi' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Basic m_ck', 'x-c': 'hello' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', x_special: 'special' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'Unknown' } + it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' } + + context 'when strict_mode is disabled' do + before do + stubs.strict_mode = false + end + + shared_examples 'does not raise NotFound even when params do not satisfy the strict check' do |params| + subject(:request) { connection.get('/strict', params, { 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello' }) } + + context "with #{params.inspect}" do + it { expect(request.status).to eq 200 } + end + end + + it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { a: '12', b: 'xy' } + it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { a: '12', b: 'xy', c: 'hello' } + it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { additional: 'special', a: '12', b: 'xy', c: 'hello' } + + shared_examples 'does not raise NotFound even when headers do not satisfy the strict check' do |path, headers| + subject(:request) { connection.get(path, { a: 12, b: 'xy' }, headers) } + + context "with #{headers.inspect}" do + it { expect(request.status).to eq 200 } + end + end + + it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello' } + it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', x_special: 'special' } + it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', user_agent: 'Special Agent' } + it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent' } + it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' } + end + + describe 'body_match?' do + let(:stubs) do + described_class::Stubs.new do |stubs| + stubs.post('/no_check') { [200, {}, 'ok'] } + stubs.post('/with_string', 'abc') { [200, {}, 'ok'] } + stubs.post( + '/with_proc', + ->(request_body) { JSON.parse(request_body, symbolize_names: true) == { x: '!', a: [{ m: [{ a: true }], n: 123 }] } }, + { content_type: 'application/json' } + ) do + [200, {}, 'ok'] + end + end + end + + context 'when trying without any args for body' do + subject(:without_body) { connection.post('/no_check') } + + it { expect(without_body.status).to eq 200 } + end + + context 'when trying with string body stubs' do + subject(:with_string) { connection.post('/with_string', 'abc') } + + it { expect(with_string.status).to eq 200 } + end + + context 'when trying with proc body stubs' do + subject(:with_proc) do + connection.post('/with_proc', JSON.dump(a: [{ n: 123, m: [{ a: true }] }], x: '!'), { 'Content-Type' => 'application/json' }) + end + + it { expect(with_proc.status).to eq 200 } + end + end + end + + describe 'request timeout' do + subject(:request) do + connection.get('/sleep') do |req| + req.options.timeout = timeout + end + end + + before do + stubs.get('/sleep') do + sleep(0.01) + [200, {}, ''] + end + end + + context 'when request is within timeout' do + let(:timeout) { 1 } + + it { expect(request.status).to eq 200 } + end + + context 'when request is too slow' do + let(:timeout) { 0.001 } + + it 'raises an exception' do + expect { request }.to raise_error(Faraday::TimeoutError) + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/adapter_registry_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/adapter_registry_spec.rb new file mode 100644 index 00000000..222e65ef --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/adapter_registry_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::AdapterRegistry do + describe '#initialize' do + subject(:registry) { described_class.new } + + it { expect { registry.get(:FinFangFoom) }.to raise_error(NameError) } + it { expect { registry.get('FinFangFoom') }.to raise_error(NameError) } + + it 'looks up class by string name' do + expect(registry.get('Faraday::Connection')).to eq(Faraday::Connection) + end + + it 'looks up class by symbol name' do + expect(registry.get(:Faraday)).to eq(Faraday) + end + + it 'caches lookups with implicit name' do + registry.set :symbol + expect(registry.get('symbol')).to eq(:symbol) + end + + it 'caches lookups with explicit name' do + registry.set 'string', :name + expect(registry.get(:name)).to eq('string') + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/adapter_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/adapter_spec.rb new file mode 100644 index 00000000..22ef1d14 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/adapter_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Adapter do + let(:adapter) { Faraday::Adapter.new } + let(:request) { {} } + + context '#request_timeout' do + it 'gets :read timeout' do + expect(timeout(:read)).to eq(nil) + + request[:timeout] = 5 + request[:write_timeout] = 1 + + expect(timeout(:read)).to eq(5) + + request[:read_timeout] = 2 + + expect(timeout(:read)).to eq(2) + end + + it 'gets :open timeout' do + expect(timeout(:open)).to eq(nil) + + request[:timeout] = 5 + request[:write_timeout] = 1 + + expect(timeout(:open)).to eq(5) + + request[:open_timeout] = 2 + + expect(timeout(:open)).to eq(2) + end + + it 'gets :write timeout' do + expect(timeout(:write)).to eq(nil) + + request[:timeout] = 5 + request[:read_timeout] = 1 + + expect(timeout(:write)).to eq(5) + + request[:write_timeout] = 2 + + expect(timeout(:write)).to eq(2) + end + + it 'attempts unknown timeout type' do + expect { timeout(:unknown) }.to raise_error(ArgumentError) + end + + def timeout(type) + adapter.send(:request_timeout, type, request) + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/connection_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/connection_spec.rb new file mode 100644 index 00000000..d4ccb23d --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/connection_spec.rb @@ -0,0 +1,808 @@ +# frozen_string_literal: true + +class CustomEncoder + def encode(params) + params.map { |k, v| "#{k.upcase}-#{v.to_s.upcase}" }.join(',') + end + + def decode(params) + params.split(',').to_h { |pair| pair.split('-') } + end +end + +shared_examples 'initializer with url' do + context 'with simple url' do + let(:address) { 'http://httpbingo.org' } + + it { expect(subject.host).to eq('httpbingo.org') } + it { expect(subject.port).to eq(80) } + it { expect(subject.scheme).to eq('http') } + it { expect(subject.path_prefix).to eq('/') } + it { expect(subject.params).to eq({}) } + end + + context 'with complex url' do + let(:address) { 'http://httpbingo.org:815/fish?a=1' } + + it { expect(subject.port).to eq(815) } + it { expect(subject.path_prefix).to eq('/fish') } + it { expect(subject.params).to eq('a' => '1') } + end + + context 'with IPv6 address' do + let(:address) { 'http://[::1]:85/' } + + it { expect(subject.host).to eq('[::1]') } + it { expect(subject.port).to eq(85) } + end +end + +shared_examples 'default connection options' do + after { Faraday.default_connection_options = nil } + + it 'works with implicit url' do + conn = Faraday.new 'http://httpbingo.org/foo' + expect(conn.options.timeout).to eq(10) + end + + it 'works with option url' do + conn = Faraday.new url: 'http://httpbingo.org/foo' + expect(conn.options.timeout).to eq(10) + end + + it 'works with instance connection options' do + conn = Faraday.new 'http://httpbingo.org/foo', request: { open_timeout: 1 } + expect(conn.options.timeout).to eq(10) + expect(conn.options.open_timeout).to eq(1) + end + + it 'default connection options persist with an instance overriding' do + conn = Faraday.new 'http://nigiri.com/bar' + conn.options.timeout = 1 + expect(Faraday.default_connection_options.request.timeout).to eq(10) + + other = Faraday.new url: 'https://httpbingo.org/foo' + other.options.timeout = 1 + + expect(Faraday.default_connection_options.request.timeout).to eq(10) + end + + it 'default connection uses default connection options' do + expect(Faraday.default_connection.options.timeout).to eq(10) + end +end + +RSpec.describe Faraday::Connection do + let(:conn) { Faraday::Connection.new(url, options) } + let(:url) { nil } + let(:options) { nil } + + describe '.new' do + subject { conn } + + context 'with implicit url param' do + # Faraday::Connection.new('http://httpbingo.org') + let(:url) { address } + + it_behaves_like 'initializer with url' + end + + context 'with explicit url param' do + # Faraday::Connection.new(url: 'http://httpbingo.org') + let(:url) { { url: address } } + + it_behaves_like 'initializer with url' + end + + context 'with custom builder' do + let(:custom_builder) { Faraday::RackBuilder.new } + let(:options) { { builder: custom_builder } } + + it { expect(subject.builder).to eq(custom_builder) } + end + + context 'with custom params' do + let(:options) { { params: { a: 1 } } } + + it { expect(subject.params).to eq('a' => 1) } + end + + context 'with custom params and params in url' do + let(:url) { 'http://httpbingo.org/fish?a=1&b=2' } + let(:options) { { params: { a: 3 } } } + it { expect(subject.params).to eq('a' => 3, 'b' => '2') } + end + + context 'with basic_auth in url' do + let(:url) { 'http://Aladdin:open%20sesame@httpbingo.org/fish' } + + it { expect(subject.headers['Authorization']).to eq('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') } + end + + context 'with custom headers' do + let(:options) { { headers: { user_agent: 'Faraday' } } } + + it { expect(subject.headers['User-agent']).to eq('Faraday') } + end + + context 'with ssl false' do + let(:options) { { ssl: { verify: false } } } + + it { expect(subject.ssl.verify?).to be_falsey } + end + + context 'with verify_hostname false' do + let(:options) { { ssl: { verify_hostname: false } } } + + it { expect(subject.ssl.verify_hostname?).to be_falsey } + end + + context 'with empty block' do + let(:conn) { Faraday::Connection.new {} } + + it { expect(conn.builder.handlers.size).to eq(0) } + end + + context 'with block' do + let(:conn) do + Faraday::Connection.new(params: { 'a' => '1' }) do |faraday| + faraday.adapter :test + faraday.url_prefix = 'http://httpbingo.org/omnom' + end + end + + it { expect(conn.builder.handlers.size).to eq(0) } + it { expect(conn.path_prefix).to eq('/omnom') } + end + end + + describe '#close' do + before { Faraday.default_adapter = :test } + after { Faraday.default_adapter = nil } + + it 'can close underlying app' do + expect(conn.app).to receive(:close) + conn.close + end + end + + describe '#build_exclusive_url' do + context 'with relative path' do + subject { conn.build_exclusive_url('sake.html') } + + it 'uses connection host as default host' do + conn.host = 'httpbingo.org' + expect(subject.host).to eq('httpbingo.org') + expect(subject.scheme).to eq('http') + end + + it do + conn.path_prefix = '/fish' + expect(subject.path).to eq('/fish/sake.html') + end + + it do + conn.path_prefix = '/' + expect(subject.path).to eq('/sake.html') + end + + it do + conn.path_prefix = 'fish' + expect(subject.path).to eq('/fish/sake.html') + end + + it do + conn.path_prefix = '/fish/' + expect(subject.path).to eq('/fish/sake.html') + end + end + + context 'with absolute path' do + subject { conn.build_exclusive_url('/sake.html') } + + after { expect(subject.path).to eq('/sake.html') } + + it { conn.path_prefix = '/fish' } + it { conn.path_prefix = '/' } + it { conn.path_prefix = 'fish' } + it { conn.path_prefix = '/fish/' } + end + + context 'with complete url' do + subject { conn.build_exclusive_url('http://httpbingo.org/sake.html?a=1') } + + it { expect(subject.scheme).to eq('http') } + it { expect(subject.host).to eq('httpbingo.org') } + it { expect(subject.port).to eq(80) } + it { expect(subject.path).to eq('/sake.html') } + it { expect(subject.query).to eq('a=1') } + end + + it 'overrides connection port for absolute url' do + conn.port = 23 + uri = conn.build_exclusive_url('http://httpbingo.org') + expect(uri.port).to eq(80) + end + + it 'does not add ending slash given nil url' do + conn.url_prefix = 'http://httpbingo.org/nigiri' + uri = conn.build_exclusive_url + expect(uri.path).to eq('/nigiri') + end + + it 'does not add ending slash given empty url' do + conn.url_prefix = 'http://httpbingo.org/nigiri' + uri = conn.build_exclusive_url('') + expect(uri.path).to eq('/nigiri') + end + + it 'does not use connection params' do + conn.url_prefix = 'http://httpbingo.org/nigiri' + conn.params = { a: 1 } + expect(conn.build_exclusive_url.to_s).to eq('http://httpbingo.org/nigiri') + end + + it 'allows to provide params argument' do + conn.url_prefix = 'http://httpbingo.org/nigiri' + conn.params = { a: 1 } + params = Faraday::Utils::ParamsHash.new + params[:a] = 2 + uri = conn.build_exclusive_url(nil, params) + expect(uri.to_s).to eq('http://httpbingo.org/nigiri?a=2') + end + + it 'handles uri instances' do + uri = conn.build_exclusive_url(URI('/sake.html')) + expect(uri.path).to eq('/sake.html') + end + + it 'always returns new URI instance' do + conn.url_prefix = 'http://httpbingo.org' + uri1 = conn.build_exclusive_url(nil) + uri2 = conn.build_exclusive_url(nil) + expect(uri1).not_to equal(uri2) + end + + context 'with url_prefixed connection' do + let(:url) { 'http://httpbingo.org/get/' } + + it 'parses url and changes scheme' do + conn.scheme = 'https' + uri = conn.build_exclusive_url('sake.html') + expect(uri.to_s).to eq('https://httpbingo.org/get/sake.html') + end + + it 'joins url to base with ending slash' do + uri = conn.build_exclusive_url('sake.html') + expect(uri.to_s).to eq('http://httpbingo.org/get/sake.html') + end + + it 'used default base with ending slash' do + uri = conn.build_exclusive_url + expect(uri.to_s).to eq('http://httpbingo.org/get/') + end + + it 'overrides base' do + uri = conn.build_exclusive_url('/sake/') + expect(uri.to_s).to eq('http://httpbingo.org/sake/') + end + end + + context 'with colon in path' do + let(:url) { 'http://service.com' } + + it 'joins url to base when used absolute path' do + conn = Faraday.new(url: url) + uri = conn.build_exclusive_url('/service:search?limit=400') + expect(uri.to_s).to eq('http://service.com/service:search?limit=400') + end + + it 'joins url to base when used relative path' do + conn = Faraday.new(url: url) + uri = conn.build_exclusive_url('service:search?limit=400') + expect(uri.to_s).to eq('http://service.com/service%3Asearch?limit=400') + end + + it 'joins url to base when used with path prefix' do + conn = Faraday.new(url: url) + conn.path_prefix = '/api' + uri = conn.build_exclusive_url('service:search?limit=400') + expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400') + end + end + + context 'with a custom `default_uri_parser`' do + let(:url) { 'http://httpbingo.org' } + let(:parser) { Addressable::URI } + + around do |example| + with_default_uri_parser(parser) do + example.run + end + end + + it 'does not raise error' do + expect { conn.build_exclusive_url('/nigiri') }.not_to raise_error + end + end + end + + describe '#build_url' do + let(:url) { 'http://httpbingo.org/nigiri' } + + it 'uses params' do + conn.params = { a: 1, b: 1 } + expect(conn.build_url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=1') + end + + it 'merges params' do + conn.params = { a: 1, b: 1 } + url = conn.build_url(nil, b: 2, c: 3) + expect(url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=2&c=3') + end + end + + describe '#build_request' do + let(:url) { 'https://ahttpbingo.org/sake.html' } + let(:request) { conn.build_request(:get) } + + before do + conn.headers = { 'Authorization' => 'token abc123' } + request.headers.delete('Authorization') + end + + it { expect(conn.headers.keys).to eq(['Authorization']) } + it { expect(conn.headers.include?('Authorization')).to be_truthy } + it { expect(request.headers.keys).to be_empty } + it { expect(request.headers.include?('Authorization')).to be_falsey } + end + + describe '#to_env' do + subject { conn.build_request(:get).to_env(conn).url } + + let(:url) { 'http://httpbingo.org/sake.html' } + let(:options) { { params: @params } } + + it 'parses url params into query' do + @params = { 'a[b]' => '1 + 2' } + expect(subject.query).to eq('a%5Bb%5D=1+%2B+2') + end + + it 'escapes per spec' do + @params = { 'a' => '1+2 foo~bar.-baz' } + expect(subject.query).to eq('a=1%2B2+foo~bar.-baz') + end + + it 'bracketizes nested params in query' do + @params = { 'a' => { 'b' => 'c' } } + expect(subject.query).to eq('a%5Bb%5D=c') + end + + it 'bracketizes repeated params in query' do + @params = { 'a' => [1, 2] } + expect(subject.query).to eq('a%5B%5D=1&a%5B%5D=2') + end + + it 'without braketizing repeated params in query' do + @params = { 'a' => [1, 2] } + conn.options.params_encoder = Faraday::FlatParamsEncoder + expect(subject.query).to eq('a=1&a=2') + end + end + + describe 'proxy support' do + it 'accepts string' do + with_env 'http_proxy' => 'http://env-proxy.com:80' do + conn.proxy = 'http://proxy.com' + expect(conn.proxy.host).to eq('proxy.com') + end + end + + it 'accepts uri' do + with_env 'http_proxy' => 'http://env-proxy.com:80' do + conn.proxy = URI.parse('http://proxy.com') + expect(conn.proxy.host).to eq('proxy.com') + end + end + + it 'accepts hash with string uri' do + with_env 'http_proxy' => 'http://env-proxy.com:80' do + conn.proxy = { uri: 'http://proxy.com', user: 'rick' } + expect(conn.proxy.host).to eq('proxy.com') + expect(conn.proxy.user).to eq('rick') + end + end + + it 'accepts hash' do + with_env 'http_proxy' => 'http://env-proxy.com:80' do + conn.proxy = { uri: URI.parse('http://proxy.com'), user: 'rick' } + expect(conn.proxy.host).to eq('proxy.com') + expect(conn.proxy.user).to eq('rick') + end + end + + it 'accepts http env' do + with_env 'http_proxy' => 'http://env-proxy.com:80' do + expect(conn.proxy.host).to eq('env-proxy.com') + end + end + + it 'accepts http env with auth' do + with_env 'http_proxy' => 'http://a%40b:my%20pass@proxy.com:80' do + expect(conn.proxy.user).to eq('a@b') + expect(conn.proxy.password).to eq('my pass') + end + end + + it 'accepts env without scheme' do + with_env 'http_proxy' => 'localhost:8888' do + uri = conn.proxy[:uri] + expect(uri.host).to eq('localhost') + expect(uri.port).to eq(8888) + end + end + + it 'fetches no proxy from nil env' do + with_env 'http_proxy' => nil do + expect(conn.proxy).to be_nil + end + end + + it 'fetches no proxy from blank env' do + with_env 'http_proxy' => '' do + expect(conn.proxy).to be_nil + end + end + + it 'does not accept uppercase env' do + with_env 'HTTP_PROXY' => 'http://localhost:8888/' do + expect(conn.proxy).to be_nil + end + end + + it 'allows when url in no proxy list' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do + conn = Faraday::Connection.new('http://example.com') + expect(conn.proxy).to be_nil + end + end + + it 'allows when url in no proxy list with url_prefix' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do + conn = Faraday::Connection.new + conn.url_prefix = 'http://example.com' + expect(conn.proxy).to be_nil + end + end + + it 'allows when prefixed url is not in no proxy list' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do + conn = Faraday::Connection.new('http://prefixedexample.com') + expect(conn.proxy.host).to eq('proxy.com') + end + end + + it 'allows when subdomain url is in no proxy list' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do + conn = Faraday::Connection.new('http://subdomain.example.com') + expect(conn.proxy).to be_nil + end + end + + it 'allows when url not in no proxy list' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example2.com' do + conn = Faraday::Connection.new('http://example.com') + expect(conn.proxy.host).to eq('proxy.com') + end + end + + it 'allows when ip address is not in no proxy list but url is' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'localhost' do + conn = Faraday::Connection.new('http://127.0.0.1') + expect(conn.proxy).to be_nil + end + end + + it 'allows when url is not in no proxy list but ip address is' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => '127.0.0.1' do + conn = Faraday::Connection.new('http://localhost') + expect(conn.proxy).to be_nil + end + end + + it 'allows in multi element no proxy list' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example0.com,example.com,example1.com' do + expect(Faraday::Connection.new('http://example0.com').proxy).to be_nil + expect(Faraday::Connection.new('http://example.com').proxy).to be_nil + expect(Faraday::Connection.new('http://example1.com').proxy).to be_nil + expect(Faraday::Connection.new('http://example2.com').proxy.host).to eq('proxy.com') + end + end + + it 'test proxy requires uri' do + expect { conn.proxy = { uri: :bad_uri, user: 'rick' } }.to raise_error(ArgumentError) + end + + it 'uses env http_proxy' do + with_env 'http_proxy' => 'http://proxy.com' do + conn = Faraday.new + expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey + expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com') + end + end + + it 'uses processes no_proxy before http_proxy' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do + conn = Faraday.new + expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey + expect(conn.proxy_for_request('http://google.co.uk')).to be_nil + end + end + + it 'uses env https_proxy' do + with_env 'https_proxy' => 'https://proxy.com' do + conn = Faraday.new + expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey + expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com') + end + end + + it 'uses processes no_proxy before https_proxy' do + with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do + conn = Faraday.new + expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey + expect(conn.proxy_for_request('https://google.co.uk')).to be_nil + end + end + + it 'gives priority to manually set proxy' do + with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do + conn = Faraday.new + conn.proxy = 'http://proxy2.com' + + expect(conn.instance_variable_get(:@manual_proxy)).to be_truthy + expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com') + end + end + + it 'ignores env proxy if set that way' do + with_env_proxy_disabled do + with_env 'http_proxy' => 'http://duncan.proxy.com:80' do + expect(conn.proxy).to be_nil + end + end + end + + context 'performing a request' do + let(:url) { 'http://example.com' } + let(:conn) do + Faraday.new do |f| + f.adapter :test do |stubs| + stubs.get(url) do + [200, {}, 'ok'] + end + end + end + end + + it 'dynamically checks proxy' do + with_env 'http_proxy' => 'http://proxy.com:80' do + expect(conn.proxy.uri.host).to eq('proxy.com') + + conn.get(url) do |req| + expect(req.options.proxy.uri.host).to eq('proxy.com') + end + end + + conn.get(url) + expect(conn.instance_variable_get(:@temp_proxy)).to be_nil + end + + it 'dynamically check no proxy' do + with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do + expect(conn.proxy.uri.host).to eq('proxy.com') + + conn.get('http://example.com') do |req| + expect(req.options.proxy).to be_nil + end + end + end + end + end + + describe '#dup' do + subject { conn.dup } + + let(:url) { 'http://httpbingo.org/foo' } + let(:options) do + { + ssl: { verify: :none }, + headers: { 'content-type' => 'text/plain' }, + params: { 'a' => '1' }, + request: { timeout: 5 } + } + end + + it { expect(subject.build_exclusive_url).to eq(conn.build_exclusive_url) } + it { expect(subject.headers['content-type']).to eq('text/plain') } + it { expect(subject.params['a']).to eq('1') } + + context 'after manual changes' do + before do + subject.headers['content-length'] = 12 + subject.params['b'] = '2' + subject.options[:open_timeout] = 10 + end + + it { expect(subject.builder.handlers.size).to eq(1) } + it { expect(conn.builder.handlers.size).to eq(1) } + it { expect(conn.headers.key?('content-length')).to be_falsey } + it { expect(conn.params.key?('b')).to be_falsey } + it { expect(subject.options[:timeout]).to eq(5) } + it { expect(conn.options[:open_timeout]).to be_nil } + end + end + + describe '#respond_to?' do + it { expect(Faraday.respond_to?(:get)).to be_truthy } + it { expect(Faraday.respond_to?(:post)).to be_truthy } + end + + describe 'default_connection_options' do + context 'assigning a default value' do + before do + Faraday.default_connection_options = nil + Faraday.default_connection_options.request.timeout = 10 + end + + it_behaves_like 'default connection options' + end + + context 'assigning a hash' do + before { Faraday.default_connection_options = { request: { timeout: 10 } } } + + it_behaves_like 'default connection options' + end + + context 'preserving a user_agent assigned via default_conncetion_options' do + around do |example| + old = Faraday.default_connection_options + Faraday.default_connection_options = { headers: { user_agent: 'My Agent 1.2' } } + example.run + Faraday.default_connection_options = old + end + + context 'when url is a Hash' do + let(:conn) { Faraday.new(url: 'http://example.co', headers: { 'CustomHeader' => 'CustomValue' }) } + + it { expect(conn.headers).to eq('CustomHeader' => 'CustomValue', 'User-Agent' => 'My Agent 1.2') } + end + + context 'when url is a String' do + let(:conn) { Faraday.new('http://example.co', headers: { 'CustomHeader' => 'CustomValue' }) } + + it { expect(conn.headers).to eq('CustomHeader' => 'CustomValue', 'User-Agent' => 'My Agent 1.2') } + end + end + end + + describe 'request params' do + context 'with simple url' do + let(:url) { 'http://example.com' } + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + + before do + conn.adapter(:test, stubs) + stubs.get('http://example.com?a=a&p=3') do + [200, {}, 'ok'] + end + end + + after { stubs.verify_stubbed_calls } + + it 'test_overrides_request_params' do + conn.get('?p=2&a=a', p: 3) + end + + it 'test_overrides_request_params_block' do + conn.get('?p=1&a=a', p: 2) do |req| + req.params[:p] = 3 + end + end + + it 'test_overrides_request_params_block_url' do + conn.get(nil, p: 2) do |req| + req.url('?p=1&a=a', 'p' => 3) + end + end + end + + context 'with url and extra params' do + let(:url) { 'http://example.com?a=1&b=2' } + let(:options) { { params: { c: 3 } } } + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + + before do + conn.adapter(:test, stubs) + end + + it 'merges connection and request params' do + expected = 'http://example.com?a=1&b=2&c=3&limit=5&page=1' + stubs.get(expected) { [200, {}, 'ok'] } + conn.get('?page=1', limit: 5) + stubs.verify_stubbed_calls + end + + it 'allows to override all params' do + expected = 'http://example.com?b=b' + stubs.get(expected) { [200, {}, 'ok'] } + conn.get('?p=1&a=a', p: 2) do |req| + expect(req.params[:a]).to eq('a') + expect(req.params['c']).to eq(3) + expect(req.params['p']).to eq(2) + req.params = { b: 'b' } + expect(req.params['b']).to eq('b') + end + stubs.verify_stubbed_calls + end + + it 'allows to set params_encoder for single request' do + encoder = CustomEncoder.new + expected = 'http://example.com/?A-1,B-2,C-3,FEELING-BLUE' + stubs.get(expected) { [200, {}, 'ok'] } + + conn.get('/', a: 1, b: 2, c: 3, feeling: 'blue') do |req| + req.options.params_encoder = encoder + end + stubs.verify_stubbed_calls + end + end + + context 'with default params encoder' do + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + + before do + conn.adapter(:test, stubs) + stubs.get('http://example.com?color%5B%5D=blue&color%5B%5D=red') do + [200, {}, 'ok'] + end + end + + after { stubs.verify_stubbed_calls } + + it 'supports array params in url' do + conn.get('http://example.com?color[]=blue&color[]=red') + end + + it 'supports array params in params' do + conn.get('http://example.com', color: %w[blue red]) + end + end + + context 'with flat params encoder' do + let(:options) { { request: { params_encoder: Faraday::FlatParamsEncoder } } } + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + + before do + conn.adapter(:test, stubs) + stubs.get('http://example.com?color=blue&color=red') do + [200, {}, 'ok'] + end + end + + after { stubs.verify_stubbed_calls } + + it 'supports array params in params' do + conn.get('http://example.com', color: %w[blue red]) + end + + context 'with array param in url' do + let(:url) { 'http://example.com?color[]=blue&color[]=red' } + + it do + conn.get('/') + end + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/error_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/error_spec.rb new file mode 100644 index 00000000..fd30e2d3 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/error_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Error do + describe '.initialize' do + subject { described_class.new(exception, response) } + let(:response) { nil } + + context 'with exception only' do + let(:exception) { RuntimeError.new('test') } + + it { expect(subject.wrapped_exception).to eq(exception) } + it { expect(subject.response).to be_nil } + it { expect(subject.message).to eq(exception.message) } + it { expect(subject.backtrace).to eq(exception.backtrace) } + it { expect(subject.inspect).to eq('#>') } + it { expect(subject.response_status).to be_nil } + it { expect(subject.response_headers).to be_nil } + it { expect(subject.response_body).to be_nil } + end + + context 'with response hash' do + let(:exception) { { status: 400 } } + + it { expect(subject.wrapped_exception).to be_nil } + it { expect(subject.response).to eq(exception) } + it { expect(subject.message).to eq('the server responded with status 400') } + it { expect(subject.inspect).to eq('#400}>') } + it { expect(subject.response_status).to eq(400) } + it { expect(subject.response_headers).to be_nil } + it { expect(subject.response_body).to be_nil } + end + + context 'with string' do + let(:exception) { 'custom message' } + + it { expect(subject.wrapped_exception).to be_nil } + it { expect(subject.response).to be_nil } + it { expect(subject.message).to eq('custom message') } + it { expect(subject.inspect).to eq('#>') } + it { expect(subject.response_status).to be_nil } + it { expect(subject.response_headers).to be_nil } + it { expect(subject.response_body).to be_nil } + end + + context 'with anything else #to_s' do + let(:exception) { %w[error1 error2] } + + it { expect(subject.wrapped_exception).to be_nil } + it { expect(subject.response).to be_nil } + it { expect(subject.message).to eq('["error1", "error2"]') } + it { expect(subject.inspect).to eq('#>') } + it { expect(subject.response_status).to be_nil } + it { expect(subject.response_headers).to be_nil } + it { expect(subject.response_body).to be_nil } + end + + context 'with exception string and response hash' do + let(:exception) { 'custom message' } + let(:response) { { status: 400 } } + + it { expect(subject.wrapped_exception).to be_nil } + it { expect(subject.response).to eq(response) } + it { expect(subject.message).to eq('custom message') } + it { expect(subject.inspect).to eq('#400}>') } + it { expect(subject.response_status).to eq(400) } + it { expect(subject.response_headers).to be_nil } + it { expect(subject.response_body).to be_nil } + end + + context 'with exception and response object' do + let(:exception) { RuntimeError.new('test') } + let(:body) { { test: 'test' } } + let(:headers) { { 'Content-Type' => 'application/json' } } + let(:response) { Faraday::Response.new(status: 400, response_headers: headers, response_body: body) } + + it { expect(subject.wrapped_exception).to eq(exception) } + it { expect(subject.response).to eq(response) } + it { expect(subject.message).to eq(exception.message) } + it { expect(subject.backtrace).to eq(exception.backtrace) } + it { expect(subject.response_status).to eq(400) } + it { expect(subject.response_headers).to eq(headers) } + it { expect(subject.response_body).to eq(body) } + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/middleware_registry_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/middleware_registry_spec.rb new file mode 100644 index 00000000..a8fa7cc7 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/middleware_registry_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::MiddlewareRegistry do + before do + stub_const('CustomMiddleware', custom_middleware_klass) + end + let(:custom_middleware_klass) { Class.new(Faraday::Middleware) } + let(:dummy) { Class.new { extend Faraday::MiddlewareRegistry } } + + after { dummy.unregister_middleware(:custom) } + + it 'allows to register with constant' do + dummy.register_middleware(custom: custom_middleware_klass) + expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass) + end + + it 'allows to register with symbol' do + dummy.register_middleware(custom: :CustomMiddleware) + expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass) + end + + it 'allows to register with string' do + dummy.register_middleware(custom: 'CustomMiddleware') + expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass) + end + + it 'allows to register with Proc' do + dummy.register_middleware(custom: -> { custom_middleware_klass }) + expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass) + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/middleware_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/middleware_spec.rb new file mode 100644 index 00000000..f5cc2a11 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/middleware_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Middleware do + subject { described_class.new(app) } + let(:app) { double } + + describe 'options' do + context 'when options are passed to the middleware' do + subject { described_class.new(app, options) } + let(:options) { { field: 'value' } } + + it 'accepts options when initialized' do + expect(subject.options[:field]).to eq('value') + end + end + end + + describe '#on_request' do + subject do + Class.new(described_class) do + def on_request(env) + # do nothing + end + end.new(app) + end + + it 'is called by #call' do + expect(app).to receive(:call).and_return(app) + expect(app).to receive(:on_complete) + is_expected.to receive(:call).and_call_original + is_expected.to receive(:on_request) + subject.call(double) + end + end + + describe '#on_error' do + subject do + Class.new(described_class) do + def on_error(error) + # do nothing + end + end.new(app) + end + + it 'is called by #call' do + expect(app).to receive(:call).and_raise(Faraday::ConnectionFailed) + is_expected.to receive(:call).and_call_original + is_expected.to receive(:on_error) + + expect { subject.call(double) }.to raise_error(Faraday::ConnectionFailed) + end + end + + describe '#close' do + context "with app that doesn't support \#close" do + it 'should issue warning' do + is_expected.to receive(:warn) + subject.close + end + end + + context "with app that supports \#close" do + it 'should issue warning' do + expect(app).to receive(:close) + is_expected.to_not receive(:warn) + subject.close + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/options/env_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/options/env_spec.rb new file mode 100644 index 00000000..006bd5fb --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/options/env_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Env do + subject(:env) { described_class.new } + + it 'allows to access members' do + expect(env.method).to be_nil + env.method = :get + expect(env.method).to eq(:get) + end + + it 'allows to access symbol non members' do + expect(env[:custom]).to be_nil + env[:custom] = :boom + expect(env[:custom]).to eq(:boom) + end + + it 'allows to access string non members' do + expect(env['custom']).to be_nil + env['custom'] = :boom + expect(env['custom']).to eq(:boom) + end + + it 'ignores false when fetching' do + ssl = Faraday::SSLOptions.new + ssl.verify = false + expect(ssl.fetch(:verify, true)).to be_falsey + end + + it 'handle verify_hostname when fetching' do + ssl = Faraday::SSLOptions.new + ssl.verify_hostname = true + expect(ssl.fetch(:verify_hostname, false)).to be_truthy + end + + it 'retains custom members' do + env[:foo] = 'custom 1' + env[:bar] = :custom2 + env2 = Faraday::Env.from(env) + env2[:baz] = 'custom 3' + + expect(env2[:foo]).to eq('custom 1') + expect(env2[:bar]).to eq(:custom2) + expect(env[:baz]).to be_nil + end + + describe '#body' do + subject(:env) { described_class.from(body: { foo: 'bar' }) } + + context 'when response is not finished yet' do + it 'returns the request body' do + expect(env.body).to eq(foo: 'bar') + end + end + + context 'when response is finished' do + before do + env.status = 200 + env.body = { bar: 'foo' } + env.response = Faraday::Response.new(env) + end + + it 'returns the response body' do + expect(env.body).to eq(bar: 'foo') + end + + it 'allows to access request_body' do + expect(env.request_body).to eq(foo: 'bar') + end + + it 'allows to access response_body' do + expect(env.response_body).to eq(bar: 'foo') + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/options/options_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/options/options_spec.rb new file mode 100644 index 00000000..fc0b117a --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/options/options_spec.rb @@ -0,0 +1,297 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Options do + SubOptions = Class.new(Faraday::Options.new(:sub_a, :sub_b)) + ParentOptions = Faraday::Options.new(:a, :b, :c) do + options c: SubOptions + end + + describe '#merge' do + it 'merges options with hashes' do + options = ParentOptions.new(1) + expect(options.a).to eq(1) + expect(options.b).to be_nil + + dup = options.merge a: 2, b: 3 + expect(dup.a).to eq(2) + expect(dup.b).to eq(3) + expect(options.a).to eq(1) + expect(options.b).to be_nil + end + + it 'deeply merges two options' do + sub_opts1 = SubOptions.from(sub_a: 3) + sub_opts2 = SubOptions.from(sub_b: 4) + opt1 = ParentOptions.from(a: 1, c: sub_opts1) + opt2 = ParentOptions.from(b: 2, c: sub_opts2) + + merged = opt1.merge(opt2) + + expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4) + expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts) + expect(merged).to eq(expected) + end + + it 'deeply merges options with hashes' do + sub_opts1 = SubOptions.from(sub_a: 3) + sub_opts2 = { sub_b: 4 } + opt1 = ParentOptions.from(a: 1, c: sub_opts1) + opt2 = { b: 2, c: sub_opts2 } + + merged = opt1.merge(opt2) + + expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4) + expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts) + expect(merged).to eq(expected) + end + + it 'deeply merges options with nil' do + sub_opts = SubOptions.new(3, 4) + options = ParentOptions.new(1, 2, sub_opts) + expect(options.a).to eq(1) + expect(options.b).to eq(2) + expect(options.c.sub_a).to eq(3) + expect(options.c.sub_b).to eq(4) + + options2 = ParentOptions.from(b: 5, c: nil) + + merged = options.merge(options2) + + expect(merged.b).to eq(5) + expect(merged.c).to eq(sub_opts) + end + + it 'deeply merges options with options having nil sub-options' do + options = ParentOptions.from(a: 1) + + sub_opts = SubOptions.new(3, 4) + options2 = ParentOptions.from(b: 2, c: sub_opts) + + expect(options.a).to eq(1) + expect(options2.b).to eq(2) + expect(options2.c.sub_a).to eq(3) + expect(options2.c.sub_b).to eq(4) + + merged = options.merge(options2) + + expect(merged.c).to eq(sub_opts) + end + + describe '#dup' do + it 'duplicate options but not sub-options' do + sub_opts = SubOptions.from(sub_a: 3) + opts = ParentOptions.from(b: 1, c: sub_opts) + + duped = opts.dup + duped.b = 2 + duped.c.sub_a = 4 + + expect(opts.b).to eq(1) + expect(opts.c.sub_a).to eq(4) + end + end + + describe '#deep_dup' do + it 'duplicate options and also suboptions' do + sub_opts = SubOptions.from(sub_a: 3) + opts = ParentOptions.from(b: 1, c: sub_opts) + + duped = opts.deep_dup + duped.b = 2 + duped.c.sub_a = 4 + + expect(opts.b).to eq(1) + expect(opts.c.sub_a).to eq(3) + end + end + + describe '#clear' do + it 'clears the options' do + options = SubOptions.new(1) + expect(options.empty?).not_to be_truthy + options.clear + expect(options.empty?).to be_truthy + end + end + + describe '#empty?' do + it 'returns true only if all options are nil' do + options = SubOptions.new + expect(options.empty?).to be_truthy + options.sub_a = 1 + expect(options.empty?).not_to be_truthy + options.delete(:sub_a) + expect(options.empty?).to be_truthy + end + end + + describe '#each_key' do + it 'allows to iterate through keys' do + options = ParentOptions.new(1, 2, 3) + enum = options.each_key + expect(enum.next.to_sym).to eq(:a) + expect(enum.next.to_sym).to eq(:b) + expect(enum.next.to_sym).to eq(:c) + end + end + + describe '#key?' do + it 'returns true if the key exists and is not nil' do + options = SubOptions.new + expect(options.key?(:sub_a)).not_to be_truthy + options.sub_a = 1 + expect(options.key?(:sub_a)).to be_truthy + end + end + + describe '#each_value' do + it 'allows to iterate through values' do + options = ParentOptions.new(1, 2, 3) + enum = options.each_value + expect(enum.next).to eq(1) + expect(enum.next).to eq(2) + expect(enum.next).to eq(3) + end + end + + describe '#value?' do + it 'returns true if any key has that value' do + options = SubOptions.new + expect(options.value?(1)).not_to be_truthy + options.sub_a = 1 + expect(options.value?(1)).to be_truthy + end + end + + describe '#update' do + it 'updates options from hashes' do + options = ParentOptions.new(1) + expect(options.a).to eq(1) + expect(options.b).to be_nil + + updated = options.update a: 2, b: 3 + expect(options.a).to eq(2) + expect(options.b).to eq(3) + expect(updated).to eq(options) + end + end + + describe '#delete' do + it 'allows to remove value for key' do + options = ParentOptions.new(1) + expect(options.a).to eq(1) + expect(options.delete(:a)).to eq(1) + expect(options.a).to be_nil + end + end + + describe '#from' do + it { expect { ParentOptions.from invalid: 1 }.to raise_error(NoMethodError) } + + it 'works with options' do + options = ParentOptions.new(1) + + value = ParentOptions.from(options) + expect(value.a).to eq(1) + expect(value.b).to be_nil + end + + it 'works with options with sub object' do + sub = SubOptions.new(1) + options = ParentOptions.from a: 1, c: sub + expect(options).to be_a_kind_of(ParentOptions) + expect(options.a).to eq(1) + expect(options.b).to be_nil + expect(options.c).to be_a_kind_of(SubOptions) + expect(options.c.sub_a).to eq(1) + end + + it 'works with hash' do + options = ParentOptions.from a: 1 + expect(options).to be_a_kind_of(ParentOptions) + expect(options.a).to eq(1) + expect(options.b).to be_nil + end + + it 'works with hash with sub object' do + options = ParentOptions.from a: 1, c: { sub_a: 1 } + expect(options).to be_a_kind_of(ParentOptions) + expect(options.a).to eq(1) + expect(options.b).to be_nil + expect(options.c).to be_a_kind_of(SubOptions) + expect(options.c.sub_a).to eq(1) + end + + it 'works with deep hash' do + hash = { b: 1 } + options = ParentOptions.from a: hash + expect(options.a[:b]).to eq(1) + + hash[:b] = 2 + expect(options.a[:b]).to eq(1) + + options.a[:b] = 3 + expect(hash[:b]).to eq(2) + expect(options.a[:b]).to eq(3) + end + + it 'works with nil' do + options = ParentOptions.from(nil) + expect(options).to be_a_kind_of(ParentOptions) + expect(options.a).to be_nil + expect(options.b).to be_nil + end + + it 'respects inheritance' do + subclass = Class.new(ParentOptions) + options = subclass.from(c: { sub_a: 'hello' }) + expect(options.c).to be_a_kind_of(SubOptions) + expect(options.c.sub_a).to eq('hello') + end + end + + describe '#memoized' do + subject(:options_class) { Class.new(ParentOptions) } + it 'requires block' do + expect { options_class.memoized(:a) }.to raise_error(ArgumentError) + end + + it 'accepts block' do + options_class.memoized(:a) { :foo } + expect(options_class.new.a).to eql(:foo) + end + end + + describe '#fetch' do + subject { SubOptions.new } + + context 'when the fetched key has no value' do + it 'uses falsey default' do + expect(subject.fetch(:sub_a, false) { |_| :blah }).to be_falsey + end + + it 'accepts block' do + expect(subject.fetch(:sub_a) { |k| "yo #{k.inspect}" }).to eq('yo :sub_a') + end + + it 'needs a default if key is missing' do + expect { subject.fetch(:sub_a) }.to raise_error(Faraday::Options.fetch_error_class) + end + end + + context 'when the fetched key has a value' do + before do + subject.sub_a = 1 + end + + it 'grabs value' do + expect(subject.fetch(:sub_a, false) { |_| :blah }).to eq(1) + end + + it 'works with key' do + expect(subject.fetch(:sub_a)).to eq(1) + end + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/options/proxy_options_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/options/proxy_options_spec.rb new file mode 100644 index 00000000..749247d1 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/options/proxy_options_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::ProxyOptions do + describe '#from' do + it 'works with string' do + options = Faraday::ProxyOptions.from 'http://user:pass@example.org' + expect(options.user).to eq('user') + expect(options.password).to eq('pass') + expect(options.uri).to be_a_kind_of(URI) + expect(options.path).to eq('') + expect(options.port).to eq(80) + expect(options.host).to eq('example.org') + expect(options.scheme).to eq('http') + expect(options.inspect).to match('#') + end + + it 'works with no auth' do + proxy = Faraday::ProxyOptions.from 'http://example.org' + expect(proxy.user).to be_nil + expect(proxy.password).to be_nil + end + + it 'treats empty string as nil' do + proxy = nil + proxy_string = proxy.to_s # => empty string + options = Faraday::ProxyOptions.from proxy_string + expect(options).to be_a_kind_of(Faraday::ProxyOptions) + expect(options.inspect).to eq('#') + end + end + + it 'allows hash access' do + proxy = Faraday::ProxyOptions.from 'http://a%40b:pw%20d@example.org' + expect(proxy.user).to eq('a@b') + expect(proxy[:user]).to eq('a@b') + expect(proxy.password).to eq('pw d') + expect(proxy[:password]).to eq('pw d') + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/options/request_options_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/options/request_options_spec.rb new file mode 100644 index 00000000..8c1bb992 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/options/request_options_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::RequestOptions do + subject(:options) { Faraday::RequestOptions.new } + + it 'allows to set the request proxy' do + expect(options.proxy).to be_nil + + expect { options[:proxy] = { booya: 1 } }.to raise_error(NoMethodError) + + options[:proxy] = { user: 'user' } + expect(options.proxy).to be_a_kind_of(Faraday::ProxyOptions) + expect(options.proxy.user).to eq('user') + + options.proxy = nil + expect(options.proxy).to be_nil + expect(options.inspect).to eq('#') + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/flat_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/flat_spec.rb new file mode 100644 index 00000000..115342e5 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/flat_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'rack/utils' + +RSpec.describe Faraday::FlatParamsEncoder do + it_behaves_like 'a params encoder' + + it 'decodes arrays' do + query = 'a=one&a=two&a=three' + expected = { 'a' => %w[one two three] } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes boolean values' do + query = 'a=true&b=false' + expected = { 'a' => 'true', 'b' => 'false' } + expect(subject.decode(query)).to eq(expected) + end + + it 'encodes boolean values' do + params = { a: true, b: false } + expect(subject.encode(params)).to eq('a=true&b=false') + end + + it 'encodes boolean values in array' do + params = { a: [true, false] } + expect(subject.encode(params)).to eq('a=true&a=false') + end + + it 'encodes empty array in hash' do + params = { a: [] } + expect(subject.encode(params)).to eq('a=') + end + + it 'encodes unsorted when asked' do + params = { b: false, a: true } + expect(subject.encode(params)).to eq('a=true&b=false') + Faraday::FlatParamsEncoder.sort_params = false + expect(subject.encode(params)).to eq('b=false&a=true') + Faraday::FlatParamsEncoder.sort_params = true + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/nested_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/nested_spec.rb new file mode 100644 index 00000000..46312047 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/params_encoders/nested_spec.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +require 'rack/utils' + +RSpec.describe Faraday::NestedParamsEncoder do + it_behaves_like 'a params encoder' + + it 'decodes arrays' do + query = 'a[1]=one&a[2]=two&a[3]=three' + expected = { 'a' => %w[one two three] } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes hashes' do + query = 'a[b1]=one&a[b2]=two&a[b][c]=foo' + expected = { 'a' => { 'b1' => 'one', 'b2' => 'two', 'b' => { 'c' => 'foo' } } } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested arrays rack compat' do + query = 'a[][one]=1&a[][two]=2&a[][one]=3&a[][two]=4' + expected = Rack::Utils.parse_nested_query(query) + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested array mixed types' do + query = 'a[][one]=1&a[]=2&a[]=&a[]' + expected = Rack::Utils.parse_nested_query(query) + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested ignores invalid array' do + query = '[][a]=1&b=2' + expected = { 'a' => '1', 'b' => '2' } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested ignores repeated array notation' do + query = 'a[][][]=1' + expected = { 'a' => ['1'] } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested ignores malformed keys' do + query = '=1&[]=2' + expected = {} + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested subkeys dont have to be in brackets' do + query = 'a[b]c[d]e=1' + expected = { 'a' => { 'b' => { 'c' => { 'd' => { 'e' => '1' } } } } } + expect(subject.decode(query)).to eq(expected) + end + + it 'decodes nested final value overrides any type' do + query = 'a[b][c]=1&a[b]=2' + expected = { 'a' => { 'b' => '2' } } + expect(subject.decode(query)).to eq(expected) + end + + it 'encodes rack compat' do + params = { a: [{ one: '1', two: '2' }, '3', ''] } + result = Faraday::Utils.unescape(Faraday::NestedParamsEncoder.encode(params)).split('&') + expected = Rack::Utils.build_nested_query(params).split('&') + expect(result).to match_array(expected) + end + + it 'encodes empty string array value' do + expected = 'baz=&foo%5Bbar%5D=' + result = Faraday::NestedParamsEncoder.encode(foo: { bar: '' }, baz: '') + expect(result).to eq(expected) + end + + it 'encodes nil array value' do + expected = 'baz&foo%5Bbar%5D' + result = Faraday::NestedParamsEncoder.encode(foo: { bar: nil }, baz: nil) + expect(result).to eq(expected) + end + + it 'encodes empty array value' do + expected = 'baz%5B%5D&foo%5Bbar%5D%5B%5D' + result = Faraday::NestedParamsEncoder.encode(foo: { bar: [] }, baz: []) + expect(result).to eq(expected) + end + + it 'encodes boolean values' do + params = { a: true, b: false } + expect(subject.encode(params)).to eq('a=true&b=false') + end + + it 'encodes boolean values in array' do + params = { a: [true, false] } + expect(subject.encode(params)).to eq('a%5B%5D=true&a%5B%5D=false') + end + + it 'encodes unsorted when asked' do + params = { b: false, a: true } + expect(subject.encode(params)).to eq('a=true&b=false') + Faraday::NestedParamsEncoder.sort_params = false + expect(subject.encode(params)).to eq('b=false&a=true') + Faraday::NestedParamsEncoder.sort_params = true + end + + it 'encodes arrays indices when asked' do + params = { a: [0, 1, 2] } + expect(subject.encode(params)).to eq('a%5B%5D=0&a%5B%5D=1&a%5B%5D=2') + Faraday::NestedParamsEncoder.array_indices = true + expect(subject.encode(params)).to eq('a%5B0%5D=0&a%5B1%5D=1&a%5B2%5D=2') + Faraday::NestedParamsEncoder.array_indices = false + end + + shared_examples 'a wrong decoding' do + it do + expect { subject.decode(query) }.to raise_error(TypeError) do |e| + expect(e.message).to eq(error_message) + end + end + end + + context 'when expecting hash but getting string' do + let(:query) { 'a=1&a[b]=2' } + let(:error_message) { "expected Hash (got String) for param `a'" } + it_behaves_like 'a wrong decoding' + end + + context 'when expecting hash but getting array' do + let(:query) { 'a[]=1&a[b]=2' } + let(:error_message) { "expected Hash (got Array) for param `a'" } + it_behaves_like 'a wrong decoding' + end + + context 'when expecting nested hash but getting non nested' do + let(:query) { 'a[b]=1&a[b][c]=2' } + let(:error_message) { "expected Hash (got String) for param `b'" } + it_behaves_like 'a wrong decoding' + end + + context 'when expecting array but getting hash' do + let(:query) { 'a[b]=1&a[]=2' } + let(:error_message) { "expected Array (got Hash) for param `a'" } + it_behaves_like 'a wrong decoding' + end + + context 'when expecting array but getting string' do + let(:query) { 'a=1&a[]=2' } + let(:error_message) { "expected Array (got String) for param `a'" } + it_behaves_like 'a wrong decoding' + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/rack_builder_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/rack_builder_spec.rb new file mode 100644 index 00000000..89f17ca9 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/rack_builder_spec.rb @@ -0,0 +1,317 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::RackBuilder do + # mock handler classes + (Handler = Struct.new(:app)).class_eval do + def call(env) + env[:request_headers]['X-Middleware'] ||= '' + env[:request_headers]['X-Middleware'] += ":#{self.class.name.split('::').last}" + app.call(env) + end + end + + class Apple < Handler + end + + class Orange < Handler + end + + class Banana < Handler + end + + subject { conn.builder } + before { Faraday.default_adapter = :test } + after { Faraday.default_adapter = nil } + + context 'with default stack' do + let(:conn) { Faraday::Connection.new } + + it { expect(subject[0]).to eq(Faraday::Request.lookup_middleware(:url_encoded)) } + it { expect(subject.adapter).to eq(Faraday::Adapter.lookup_middleware(Faraday.default_adapter)) } + end + + context 'with custom empty block' do + let(:conn) { Faraday::Connection.new {} } + + it { expect(subject[0]).to be_nil } + it { expect(subject.adapter).to eq(Faraday::Adapter.lookup_middleware(Faraday.default_adapter)) } + end + + context 'with custom adapter only' do + let(:conn) do + Faraday::Connection.new do |builder| + builder.adapter :test do |stub| + stub.get('/') { |_| [200, {}, ''] } + end + end + end + + it { expect(subject[0]).to be_nil } + it { expect(subject.adapter).to eq(Faraday::Adapter.lookup_middleware(:test)) } + end + + context 'with custom handler and adapter' do + let(:conn) do + Faraday::Connection.new do |builder| + builder.use Apple + builder.adapter :test do |stub| + stub.get('/') { |_| [200, {}, ''] } + end + end + end + + it 'locks the stack after making a request' do + expect(subject.locked?).to be_falsey + conn.get('/') + expect(subject.locked?).to be_truthy + expect { subject.use(Orange) }.to raise_error(Faraday::RackBuilder::StackLocked) + end + + it 'dup stack is unlocked' do + expect(subject.locked?).to be_falsey + subject.lock! + expect(subject.locked?).to be_truthy + dup = subject.dup + expect(dup).to eq(subject) + expect(dup.locked?).to be_falsey + end + + it 'allows to compare handlers' do + expect(subject.handlers.first).to eq(Faraday::RackBuilder::Handler.new(Apple)) + end + end + + context 'when having a single handler' do + let(:conn) { Faraday::Connection.new {} } + + before { subject.use(Apple) } + + it { expect(subject.handlers).to eq([Apple]) } + + it 'allows use' do + subject.use(Orange) + expect(subject.handlers).to eq([Apple, Orange]) + end + + it 'allows insert_before' do + subject.insert_before(Apple, Orange) + expect(subject.handlers).to eq([Orange, Apple]) + end + + it 'allows insert_after' do + subject.insert_after(Apple, Orange) + expect(subject.handlers).to eq([Apple, Orange]) + end + + it 'raises an error trying to use an unregistered symbol' do + expect { subject.use(:apple) }.to raise_error(Faraday::Error) do |err| + expect(err.message).to eq(':apple is not registered on Faraday::Middleware') + end + end + end + + context 'when having two handlers' do + let(:conn) { Faraday::Connection.new {} } + + before do + subject.use(Apple) + subject.use(Orange) + end + + it 'allows insert_before' do + subject.insert_before(Orange, Banana) + expect(subject.handlers).to eq([Apple, Banana, Orange]) + end + + it 'allows insert_after' do + subject.insert_after(Apple, Banana) + expect(subject.handlers).to eq([Apple, Banana, Orange]) + end + + it 'allows to swap handlers' do + subject.swap(Apple, Banana) + expect(subject.handlers).to eq([Banana, Orange]) + end + + it 'allows to delete a handler' do + subject.delete(Apple) + expect(subject.handlers).to eq([Orange]) + end + end + + context 'when adapter is added with named options' do + after { Faraday.default_adapter_options = {} } + let(:conn) { Faraday::Connection.new {} } + + let(:cat_adapter) do + Class.new(Faraday::Adapter) do + attr_accessor :name + + def initialize(app, name:) + super(app) + @name = name + end + end + end + + let(:cat) { subject.adapter.build } + + it 'adds a handler to construct adapter with named options' do + Faraday.default_adapter = cat_adapter + Faraday.default_adapter_options = { name: 'Chloe' } + expect { cat }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(cat.name).to eq 'Chloe' + end + end + + context 'when middleware is added with named arguments' do + let(:conn) { Faraday::Connection.new {} } + + let(:dog_middleware) do + Class.new(Faraday::Middleware) do + attr_accessor :name + + def initialize(app, name:) + super(app) + @name = name + end + end + end + let(:dog) do + subject.handlers.find { |handler| handler == dog_middleware }.build + end + + it 'adds a handler to construct middleware with options passed to use' do + subject.use dog_middleware, name: 'Rex' + expect { dog }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(dog.name).to eq('Rex') + end + end + + context 'when a middleware is added with named arguments' do + let(:conn) { Faraday::Connection.new {} } + + let(:cat_request) do + Class.new(Faraday::Middleware) do + attr_accessor :name + + def initialize(app, name:) + super(app) + @name = name + end + end + end + let(:cat) do + subject.handlers.find { |handler| handler == cat_request }.build + end + + it 'adds a handler to construct request adapter with options passed to request' do + Faraday::Request.register_middleware cat_request: cat_request + subject.request :cat_request, name: 'Felix' + expect { cat }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(cat.name).to eq('Felix') + end + end + + context 'when a middleware is added with named arguments' do + let(:conn) { Faraday::Connection.new {} } + + let(:fish_response) do + Class.new(Faraday::Middleware) do + attr_accessor :name + + def initialize(app, name:) + super(app) + @name = name + end + end + end + let(:fish) do + subject.handlers.find { |handler| handler == fish_response }.build + end + + it 'adds a handler to construct response adapter with options passed to response' do + Faraday::Response.register_middleware fish_response: fish_response + subject.response :fish_response, name: 'Bubbles' + expect { fish }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(fish.name).to eq('Bubbles') + end + end + + context 'when a plain adapter is added with named arguments' do + let(:conn) { Faraday::Connection.new {} } + + let(:rabbit_adapter) do + Class.new(Faraday::Adapter) do + attr_accessor :name + + def initialize(app, name:) + super(app) + @name = name + end + end + end + let(:rabbit) do + subject.adapter.build + end + + it 'adds a handler to construct adapter with options passed to adapter' do + Faraday::Adapter.register_middleware rabbit_adapter: rabbit_adapter + subject.adapter :rabbit_adapter, name: 'Thumper' + expect { rabbit }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(rabbit.name).to eq('Thumper') + end + end + + context 'when handlers are directly added or updated' do + let(:conn) { Faraday::Connection.new {} } + + let(:rock_handler) do + Class.new do + attr_accessor :name + + def initialize(_app, name:) + @name = name + end + end + end + let(:rock) do + subject.handlers.find { |handler| handler == rock_handler }.build + end + + it 'adds a handler to construct adapter with options passed to insert' do + subject.insert 0, rock_handler, name: 'Stony' + expect { rock }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(rock.name).to eq('Stony') + end + + it 'adds a handler with options passed to insert_after' do + subject.insert_after 0, rock_handler, name: 'Rocky' + expect { rock }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(rock.name).to eq('Rocky') + end + + it 'adds a handler with options passed to swap' do + subject.insert 0, rock_handler, name: 'Flint' + subject.swap 0, rock_handler, name: 'Chert' + expect { rock }.to_not output( + /warning: Using the last argument as keyword parameters is deprecated/ + ).to_stderr + expect(rock.name).to eq('Chert') + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/request/authorization_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/request/authorization_spec.rb new file mode 100644 index 00000000..437c88ae --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/request/authorization_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Request::Authorization do + let(:conn) do + Faraday.new do |b| + b.request :authorization, auth_type, *auth_config + b.adapter :test do |stub| + stub.get('/auth-echo') do |env| + [200, {}, env[:request_headers]['Authorization']] + end + end + end + end + + shared_examples 'does not interfere with existing authentication' do + context 'and request already has an authentication header' do + let(:response) { conn.get('/auth-echo', nil, authorization: 'OAuth oauth_token') } + + it 'does not interfere with existing authorization' do + expect(response.body).to eq('OAuth oauth_token') + end + end + end + + let(:response) { conn.get('/auth-echo') } + + describe 'basic_auth' do + let(:auth_type) { :basic } + + context 'when passed correct params' do + let(:auth_config) { %w[aladdin opensesame] } + + it { expect(response.body).to eq('Basic YWxhZGRpbjpvcGVuc2VzYW1l') } + + include_examples 'does not interfere with existing authentication' + end + + context 'when passed very long values' do + let(:auth_config) { ['A' * 255, ''] } + + it { expect(response.body).to eq("Basic #{'QUFB' * 85}Og==") } + + include_examples 'does not interfere with existing authentication' + end + end + + describe 'authorization' do + let(:auth_type) { :Bearer } + + context 'when passed a string' do + let(:auth_config) { ['custom'] } + + it { expect(response.body).to eq('Bearer custom') } + + include_examples 'does not interfere with existing authentication' + end + + context 'when passed a proc' do + let(:auth_config) { [-> { 'custom_from_proc' }] } + + it { expect(response.body).to eq('Bearer custom_from_proc') } + + include_examples 'does not interfere with existing authentication' + end + + context 'when passed a callable' do + let(:callable) { double('Callable Authorizer', call: 'custom_from_callable') } + let(:auth_config) { [callable] } + + it { expect(response.body).to eq('Bearer custom_from_callable') } + + include_examples 'does not interfere with existing authentication' + end + + context 'with an argument' do + let(:response) { conn.get('/auth-echo', nil, 'middle' => 'crunchy surprise') } + + context 'when passed a proc' do + let(:auth_config) { [proc { |env| "proc #{env.request_headers['middle']}" }] } + + it { expect(response.body).to eq('Bearer proc crunchy surprise') } + + include_examples 'does not interfere with existing authentication' + end + + context 'when passed a lambda' do + let(:auth_config) { [->(env) { "lambda #{env.request_headers['middle']}" }] } + + it { expect(response.body).to eq('Bearer lambda crunchy surprise') } + + include_examples 'does not interfere with existing authentication' + end + + context 'when passed a callable with an argument' do + let(:callable) do + Class.new do + def call(env) + "callable #{env.request_headers['middle']}" + end + end.new + end + let(:auth_config) { [callable] } + + it { expect(response.body).to eq('Bearer callable crunchy surprise') } + + include_examples 'does not interfere with existing authentication' + end + end + + context 'when passed too many arguments' do + let(:auth_config) { %w[baz foo] } + + it { expect { response }.to raise_error(ArgumentError) } + + include_examples 'does not interfere with existing authentication' + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/request/instrumentation_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/request/instrumentation_spec.rb new file mode 100644 index 00000000..d207c556 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/request/instrumentation_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Request::Instrumentation do + class FakeInstrumenter + attr_reader :instrumentations + + def initialize + @instrumentations = [] + end + + def instrument(name, env) + @instrumentations << [name, env] + yield + end + end + + let(:config) { {} } + let(:options) { Faraday::Request::Instrumentation::Options.from config } + let(:instrumenter) { FakeInstrumenter.new } + let(:conn) do + Faraday.new do |f| + f.request :instrumentation, config.merge(instrumenter: instrumenter) + f.adapter :test do |stub| + stub.get '/' do + [200, {}, 'ok'] + end + end + end + end + + it { expect(options.name).to eq('request.faraday') } + it 'defaults to ActiveSupport::Notifications' do + res = options.instrumenter + rescue NameError => e + expect(e.to_s).to match('ActiveSupport') + else + expect(res).to eq(ActiveSupport::Notifications) + end + + it 'instruments with default name' do + expect(instrumenter.instrumentations.size).to eq(0) + + res = conn.get '/' + expect(res.body).to eq('ok') + expect(instrumenter.instrumentations.size).to eq(1) + + name, env = instrumenter.instrumentations.first + expect(name).to eq('request.faraday') + expect(env[:url].path).to eq('/') + end + + context 'with custom name' do + let(:config) { { name: 'custom' } } + + it { expect(options.name).to eq('custom') } + it 'instruments with custom name' do + expect(instrumenter.instrumentations.size).to eq(0) + + res = conn.get '/' + expect(res.body).to eq('ok') + expect(instrumenter.instrumentations.size).to eq(1) + + name, env = instrumenter.instrumentations.first + expect(name).to eq('custom') + expect(env[:url].path).to eq('/') + end + end + + context 'with custom instrumenter' do + let(:config) { { instrumenter: :custom } } + + it { expect(options.instrumenter).to eq(:custom) } + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/request/json_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/request/json_spec.rb new file mode 100644 index 00000000..44dee796 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/request/json_spec.rb @@ -0,0 +1,199 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Request::Json do + let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) } + + def process(body, content_type = nil) + env = { body: body, request_headers: Faraday::Utils::Headers.new } + env[:request_headers]['content-type'] = content_type if content_type + middleware.call(Faraday::Env.from(env)).env + end + + def result_body + result[:body] + end + + def result_type + result[:request_headers]['content-type'] + end + + context 'no body' do + let(:result) { process(nil) } + + it "doesn't change body" do + expect(result_body).to be_nil + end + + it "doesn't add content type" do + expect(result_type).to be_nil + end + end + + context 'empty body' do + let(:result) { process('') } + + it "doesn't change body" do + expect(result_body).to be_empty + end + + it "doesn't add content type" do + expect(result_type).to be_nil + end + end + + context 'string body' do + let(:result) { process('{"a":1}') } + + it "doesn't change body" do + expect(result_body).to eq('{"a":1}') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'object body' do + let(:result) { process(a: 1) } + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'empty object body' do + let(:result) { process({}) } + + it 'encodes body' do + expect(result_body).to eq('{}') + end + end + + context 'true body' do + let(:result) { process(true) } + + it 'encodes body' do + expect(result_body).to eq('true') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'false body' do + let(:result) { process(false) } + + it 'encodes body' do + expect(result_body).to eq('false') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'object body with json type' do + let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') } + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it "doesn't change content type" do + expect(result_type).to eq('application/json; charset=utf-8') + end + end + + context 'object body with vendor json type' do + let(:result) { process({ a: 1 }, 'application/vnd.myapp.v1+json; charset=utf-8') } + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it "doesn't change content type" do + expect(result_type).to eq('application/vnd.myapp.v1+json; charset=utf-8') + end + end + + context 'object body with incompatible type' do + let(:result) { process({ a: 1 }, 'application/xml; charset=utf-8') } + + it "doesn't change body" do + expect(result_body).to eq(a: 1) + end + + it "doesn't change content type" do + expect(result_type).to eq('application/xml; charset=utf-8') + end + end + + context 'with encoder' do + let(:encoder) do + double('Encoder').tap do |e| + allow(e).to receive(:dump) { |s, opts| JSON.generate(s, opts) } + end + end + + let(:result) { process(a: 1) } + + context 'when encoder is passed as object' do + let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: encoder }) } + + it 'calls specified JSON encoder\'s dump method' do + expect(encoder).to receive(:dump).with({ a: 1 }) + + result + end + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'when encoder is passed as an object-method pair' do + let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: [encoder, :dump] }) } + + it 'calls specified JSON encoder' do + expect(encoder).to receive(:dump).with({ a: 1 }) + + result + end + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + + context 'when encoder is not passed' do + let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) } + + it 'calls JSON.generate' do + expect(JSON).to receive(:generate).with({ a: 1 }) + + result + end + + it 'encodes body' do + expect(result_body).to eq('{"a":1}') + end + + it 'adds content type' do + expect(result_type).to eq('application/json') + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/request/url_encoded_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/request/url_encoded_spec.rb new file mode 100644 index 00000000..bdd9e0ac --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/request/url_encoded_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'stringio' + +RSpec.describe Faraday::Request::UrlEncoded do + let(:conn) do + Faraday.new do |b| + b.request :url_encoded + b.adapter :test do |stub| + stub.post('/echo') do |env| + posted_as = env[:request_headers]['Content-Type'] + body = env[:body] + if body.respond_to?(:read) + body = body.read + end + [200, { 'Content-Type' => posted_as }, body] + end + end + end + end + + it 'does nothing without payload' do + response = conn.post('/echo') + expect(response.headers['Content-Type']).to be_nil + expect(response.body.empty?).to be_truthy + end + + it 'ignores custom content type' do + response = conn.post('/echo', { some: 'data' }, 'content-type' => 'application/x-foo') + expect(response.headers['Content-Type']).to eq('application/x-foo') + expect(response.body).to eq(some: 'data') + end + + it 'works with no headers' do + response = conn.post('/echo', fruit: %w[apples oranges]) + expect(response.headers['Content-Type']).to eq('application/x-www-form-urlencoded') + expect(response.body).to eq('fruit%5B%5D=apples&fruit%5B%5D=oranges') + end + + it 'works with with headers' do + response = conn.post('/echo', { 'a' => 123 }, 'content-type' => 'application/x-www-form-urlencoded') + expect(response.headers['Content-Type']).to eq('application/x-www-form-urlencoded') + expect(response.body).to eq('a=123') + end + + it 'works with nested params' do + response = conn.post('/echo', user: { name: 'Mislav', web: 'mislav.net' }) + expect(response.headers['Content-Type']).to eq('application/x-www-form-urlencoded') + expected = { 'user' => { 'name' => 'Mislav', 'web' => 'mislav.net' } } + expect(Faraday::Utils.parse_nested_query(response.body)).to eq(expected) + end + + it 'works with non nested params' do + response = conn.post('/echo', dimensions: %w[date location]) do |req| + req.options.params_encoder = Faraday::FlatParamsEncoder + end + expect(response.headers['Content-Type']).to eq('application/x-www-form-urlencoded') + expected = { 'dimensions' => %w[date location] } + expect(Faraday::Utils.parse_query(response.body)).to eq(expected) + expect(response.body).to eq('dimensions=date&dimensions=location') + end + + it 'works with unicode' do + err = capture_warnings do + response = conn.post('/echo', str: 'eé cç aã aâ') + expect(response.body).to eq('str=e%C3%A9+c%C3%A7+a%C3%A3+a%C3%A2') + end + expect(err.empty?).to be_truthy + end + + it 'works with nested keys' do + response = conn.post('/echo', 'a' => { 'b' => { 'c' => ['d'] } }) + expect(response.body).to eq('a%5Bb%5D%5Bc%5D%5B%5D=d') + end + + it 'works with files' do + response = conn.post('/echo', StringIO.new('str=apple')) + expect(response.body).to eq('str=apple') + end + + context 'customising default_space_encoding' do + around do |example| + Faraday::Utils.default_space_encoding = '%20' + example.run + Faraday::Utils.default_space_encoding = nil + end + + it 'uses the custom character to encode spaces' do + response = conn.post('/echo', str: 'apple banana') + expect(response.body).to eq('str=apple%20banana') + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/request_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/request_spec.rb new file mode 100644 index 00000000..fbf85b56 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/request_spec.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Request do + let(:conn) do + Faraday.new(url: 'http://httpbingo.org/api', + headers: { 'Mime-Version' => '1.0' }, + request: { oauth: { consumer_key: 'anonymous' } }) + end + let(:http_method) { :get } + let(:block) { nil } + + subject { conn.build_request(http_method, &block) } + + context 'when nothing particular is configured' do + it { expect(subject.http_method).to eq(:get) } + it { expect(subject.to_env(conn).ssl.verify).to be_falsey } + it { expect(subject.to_env(conn).ssl.verify_hostname).to be_falsey } + end + + context 'when HTTP method is post' do + let(:http_method) { :post } + + it { expect(subject.http_method).to eq(:post) } + end + + context 'when setting the url on setup with a URI' do + let(:block) { proc { |req| req.url URI.parse('foo.json?a=1') } } + + it { expect(subject.path).to eq(URI.parse('foo.json')) } + it { expect(subject.params).to eq('a' => '1') } + it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') } + end + + context 'when setting the url on setup with a string path and params' do + let(:block) { proc { |req| req.url 'foo.json', 'a' => 1 } } + + it { expect(subject.path).to eq('foo.json') } + it { expect(subject.params).to eq('a' => 1) } + it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') } + end + + context 'when setting the url on setup with a path including params' do + let(:block) { proc { |req| req.url 'foo.json?b=2&a=1#qqq' } } + + it { expect(subject.path).to eq('foo.json') } + it { expect(subject.params).to eq('a' => '1', 'b' => '2') } + it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1&b=2') } + end + + context 'when setting a header on setup with []= syntax' do + let(:block) { proc { |req| req['Server'] = 'Faraday' } } + let(:headers) { subject.to_env(conn).request_headers } + + it { expect(subject.headers['Server']).to eq('Faraday') } + it { expect(headers['mime-version']).to eq('1.0') } + it { expect(headers['server']).to eq('Faraday') } + end + + context 'when setting the body on setup' do + let(:block) { proc { |req| req.body = 'hi' } } + + it { expect(subject.body).to eq('hi') } + it { expect(subject.to_env(conn).body).to eq('hi') } + end + + context 'with global request options set' do + let(:env_request) { subject.to_env(conn).request } + + before do + conn.options.timeout = 3 + conn.options.open_timeout = 5 + conn.ssl.verify = false + conn.proxy = 'http://proxy.com' + end + + it { expect(subject.options.timeout).to eq(3) } + it { expect(subject.options.open_timeout).to eq(5) } + it { expect(env_request.timeout).to eq(3) } + it { expect(env_request.open_timeout).to eq(5) } + + context 'and per-request options set' do + let(:block) do + proc do |req| + req.options.timeout = 10 + req.options.boundary = 'boo' + req.options.oauth[:consumer_secret] = 'xyz' + req.options.context = { + foo: 'foo', + bar: 'bar' + } + end + end + + it { expect(subject.options.timeout).to eq(10) } + it { expect(subject.options.open_timeout).to eq(5) } + it { expect(env_request.timeout).to eq(10) } + it { expect(env_request.open_timeout).to eq(5) } + it { expect(env_request.boundary).to eq('boo') } + it { expect(env_request.context).to eq(foo: 'foo', bar: 'bar') } + it do + oauth_expected = { consumer_secret: 'xyz', consumer_key: 'anonymous' } + expect(env_request.oauth).to eq(oauth_expected) + end + end + end + + it 'supports marshal serialization' do + expect(Marshal.load(Marshal.dump(subject))).to eq(subject) + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/response/json_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/response/json_spec.rb new file mode 100644 index 00000000..6108c5fd --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/response/json_spec.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Response::Json, type: :response do + let(:options) { {} } + let(:headers) { {} } + let(:middleware) do + described_class.new(lambda { |env| + Faraday::Response.new(env) + }, **options) + end + + def process(body, content_type = 'application/json', options = {}) + env = { + body: body, request: options, + request_headers: Faraday::Utils::Headers.new, + response_headers: Faraday::Utils::Headers.new(headers) + } + env[:response_headers]['content-type'] = content_type if content_type + yield(env) if block_given? + middleware.call(Faraday::Env.from(env)) + end + + context 'no type matching' do + it "doesn't change nil body" do + expect(process(nil).body).to be_nil + end + + it 'nullifies empty body' do + expect(process('').body).to be_nil + end + + it 'parses json body' do + response = process('{"a":1}') + expect(response.body).to eq('a' => 1) + expect(response.env[:raw_body]).to be_nil + end + end + + context 'with preserving raw' do + let(:options) { { preserve_raw: true } } + + it 'parses json body' do + response = process('{"a":1}') + expect(response.body).to eq('a' => 1) + expect(response.env[:raw_body]).to eq('{"a":1}') + end + end + + context 'with default regexp type matching' do + it 'parses json body of correct type' do + response = process('{"a":1}', 'application/x-json') + expect(response.body).to eq('a' => 1) + end + + it 'ignores json body of incorrect type' do + response = process('{"a":1}', 'text/json-xml') + expect(response.body).to eq('{"a":1}') + end + end + + context 'with array type matching' do + let(:options) { { content_type: %w[a/b c/d] } } + + it 'parses json body of correct type' do + expect(process('{"a":1}', 'a/b').body).to be_a(Hash) + expect(process('{"a":1}', 'c/d').body).to be_a(Hash) + end + + it 'ignores json body of incorrect type' do + expect(process('{"a":1}', 'a/d').body).not_to be_a(Hash) + end + end + + it 'chokes on invalid json' do + expect { process('{!') }.to raise_error(Faraday::ParsingError) + end + + it 'includes the response on the ParsingError instance' do + process('{') { |env| env[:response] = Faraday::Response.new } + raise 'Parsing should have failed.' + rescue Faraday::ParsingError => e + expect(e.response).to be_a(Faraday::Response) + end + + context 'HEAD responses' do + it "nullifies the body if it's only one space" do + response = process(' ') + expect(response.body).to be_nil + end + + it "nullifies the body if it's two spaces" do + response = process(' ') + expect(response.body).to be_nil + end + end + + context 'JSON options' do + let(:body) { '{"a": 1}' } + let(:result) { { a: 1 } } + let(:options) do + { + parser_options: { + symbolize_names: true + } + } + end + + it 'passes relevant options to JSON parse' do + expect(::JSON).to receive(:parse) + .with(body, options[:parser_options]) + .and_return(result) + + response = process(body) + expect(response.body).to eq(result) + end + end + + context 'with decoder' do + let(:decoder) do + double('Decoder').tap do |e| + allow(e).to receive(:load) { |s, opts| JSON.parse(s, opts) } + end + end + + let(:body) { '{"a": 1}' } + let(:result) { { a: 1 } } + + context 'when decoder is passed as object' do + let(:options) do + { + parser_options: { + decoder: decoder, + option: :option_value, + symbolize_names: true + } + } + end + + it 'passes relevant options to specified decoder\'s load method' do + expect(decoder).to receive(:load) + .with(body, { option: :option_value, symbolize_names: true }) + .and_return(result) + + response = process(body) + expect(response.body).to eq(result) + end + end + + context 'when decoder is passed as an object-method pair' do + let(:options) do + { + parser_options: { + decoder: [decoder, :load], + option: :option_value, + symbolize_names: true + } + } + end + + it 'passes relevant options to specified decoder\'s method' do + expect(decoder).to receive(:load) + .with(body, { option: :option_value, symbolize_names: true }) + .and_return(result) + + response = process(body) + expect(response.body).to eq(result) + end + end + + context 'when decoder is not passed' do + let(:options) do + { + parser_options: { + symbolize_names: true + } + } + end + + it 'passes relevant options to JSON parse' do + expect(JSON).to receive(:parse) + .with(body, { symbolize_names: true }) + .and_return(result) + + response = process(body) + expect(response.body).to eq(result) + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/response/logger_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/response/logger_spec.rb new file mode 100644 index 00000000..4fd1e11c --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/response/logger_spec.rb @@ -0,0 +1,258 @@ +# frozen_string_literal: true + +require 'stringio' +require 'logger' + +RSpec.describe Faraday::Response::Logger do + let(:string_io) { StringIO.new } + let(:logger) { Logger.new(string_io) } + let(:logger_options) { {} } + let(:conn) do + rubbles = ['Barney', 'Betty', 'Bam Bam'] + + Faraday.new do |b| + b.response :logger, logger, logger_options do |logger| + logger.filter(/(soylent green is) (.+)/, '\1 tasty') + logger.filter(/(api_key:).*"(.+)."/, '\1[API_KEY]') + logger.filter(/(password)=(.+)/, '\1=[HIDDEN]') + end + b.adapter :test do |stubs| + stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] } + stubs.post('/ohai') { [200, { 'Content-Type' => 'text/html' }, 'fred'] } + stubs.post('/ohyes') { [200, { 'Content-Type' => 'text/html' }, 'pebbles'] } + stubs.get('/rubbles') { [200, { 'Content-Type' => 'application/json' }, rubbles] } + stubs.get('/filtered_body') { [200, { 'Content-Type' => 'text/html' }, 'soylent green is people'] } + stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] } + stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] } + stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] } + stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' } + end + end + end + + before do + logger.level = Logger::DEBUG + end + + it 'still returns output' do + resp = conn.get '/hello', nil, accept: 'text/html' + expect(resp.body).to eq('hello') + end + + context 'without configuration' do + let(:conn) do + Faraday.new do |b| + b.response :logger + b.adapter :test do |stubs| + stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] } + end + end + end + + it 'defaults to stdout' do + expect(Logger).to receive(:new).with($stdout).and_return(Logger.new(nil)) + conn.get('/hello') + end + end + + context 'with default formatter' do + let(:formatter) { instance_double(Faraday::Logging::Formatter, request: true, response: true, filter: []) } + + before { allow(Faraday::Logging::Formatter).to receive(:new).and_return(formatter) } + + it 'delegates logging to the formatter' do + expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env)) + expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env)) + conn.get '/hello' + end + + context 'when no route' do + it 'delegates logging to the formatter' do + expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env)) + expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound)) + + expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound) + end + end + end + + context 'with custom formatter' do + let(:formatter_class) do + Class.new(Faraday::Logging::Formatter) do + def request(_env) + info 'Custom log formatter request' + end + + def response(_env) + info 'Custom log formatter response' + end + end + end + + let(:logger_options) { { formatter: formatter_class } } + + it 'logs with custom formatter' do + conn.get '/hello' + + expect(string_io.string).to match('Custom log formatter request') + expect(string_io.string).to match('Custom log formatter response') + end + end + + it 'logs method and url' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).to match('GET http:/hello') + end + + it 'logs status' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).to match('Status 200') + end + + it 'does not log error message by default' do + expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound) + expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute)) + end + + it 'logs request headers by default' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).to match(%(Accept: "text/html)) + end + + it 'logs response headers by default' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).to match(%(Content-Type: "text/html)) + end + + it 'does not log request body by default' do + conn.post '/ohai', 'name=Unagi', accept: 'text/html' + expect(string_io.string).not_to match(%(name=Unagi)) + end + + it 'does not log response body by default' do + conn.post '/ohai', 'name=Toro', accept: 'text/html' + expect(string_io.string).not_to match(%(fred)) + end + + it 'logs filter headers' do + conn.headers = { 'api_key' => 'ABC123' } + conn.get '/filtered_headers', nil, accept: 'text/html' + expect(string_io.string).to match(%(api_key:)) + expect(string_io.string).to match(%([API_KEY])) + expect(string_io.string).not_to match(%(ABC123)) + end + + it 'logs filter url' do + conn.get '/filtered_url?password=hunter2', nil, accept: 'text/html' + expect(string_io.string).to match(%([HIDDEN])) + expect(string_io.string).not_to match(%(hunter2)) + end + + context 'when not logging request headers' do + let(:logger_options) { { headers: { request: false } } } + + it 'does not log request headers if option is false' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).not_to match(%(Accept: "text/html)) + end + end + + context 'when not logging response headers' do + let(:logger_options) { { headers: { response: false } } } + + it 'does not log response headers if option is false' do + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).not_to match(%(Content-Type: "text/html)) + end + end + + context 'when logging request body' do + let(:logger_options) { { bodies: { request: true } } } + + it 'log only request body' do + conn.post '/ohyes', 'name=Tamago', accept: 'text/html' + expect(string_io.string).to match(%(name=Tamago)) + expect(string_io.string).not_to match(%(pebbles)) + end + end + + context 'when logging response body' do + let(:logger_options) { { bodies: { response: true } } } + + it 'log only response body' do + conn.post '/ohyes', 'name=Hamachi', accept: 'text/html' + expect(string_io.string).to match(%(pebbles)) + expect(string_io.string).not_to match(%(name=Hamachi)) + end + end + + context 'when logging request and response bodies' do + let(:logger_options) { { bodies: true } } + + it 'log request and response body' do + conn.post '/ohyes', 'name=Ebi', accept: 'text/html' + expect(string_io.string).to match(%(name=Ebi)) + expect(string_io.string).to match(%(pebbles)) + end + + it 'log response body object' do + conn.get '/rubbles', nil, accept: 'text/html' + expect(string_io.string).to match(%([\"Barney\", \"Betty\", \"Bam Bam\"]\n)) + end + + it 'logs filter body' do + conn.get '/filtered_body', nil, accept: 'text/html' + expect(string_io.string).to match(%(soylent green is)) + expect(string_io.string).to match(%(tasty)) + expect(string_io.string).not_to match(%(people)) + end + end + + context 'when logging errors' do + let(:logger_options) { { errors: true } } + + it 'logs error message' do + expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound) + expect(string_io.string).to match(%(no stubbed request for get http:/noroute)) + end + end + + context 'when logging headers and errors' do + let(:logger_options) { { headers: true, errors: true } } + + it 'logs error message' do + expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed) + expect(string_io.string).to match(%(Failed to open TCP connection)) + end + end + + context 'when using log_level' do + let(:logger_options) { { bodies: true, log_level: :debug } } + + it 'logs request/request body on the specified level (debug)' do + logger.level = Logger::DEBUG + conn.post '/ohyes', 'name=Ebi', accept: 'text/html' + expect(string_io.string).to match(%(name=Ebi)) + expect(string_io.string).to match(%(pebbles)) + end + + it 'logs headers on the debug level' do + logger.level = Logger::DEBUG + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).to match(%(Content-Type: "text/html)) + end + + it 'does not log request/response body on the info level' do + logger.level = Logger::INFO + conn.post '/ohyes', 'name=Ebi', accept: 'text/html' + expect(string_io.string).not_to match(%(name=Ebi)) + expect(string_io.string).not_to match(%(pebbles)) + end + + it 'does not log headers on the info level' do + logger.level = Logger::INFO + conn.get '/hello', nil, accept: 'text/html' + expect(string_io.string).not_to match(%(Content-Type: "text/html)) + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/response/raise_error_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/response/raise_error_spec.rb new file mode 100644 index 00000000..d106e9a9 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/response/raise_error_spec.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Response::RaiseError do + let(:conn) do + Faraday.new do |b| + b.response :raise_error + b.adapter :test do |stub| + stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, ''] } + stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('unauthorized') { [401, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] } + stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] } + stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] } + end + end + end + + it 'raises no exception for 200 responses' do + expect { conn.get('ok') }.not_to raise_error + end + + it 'raises Faraday::BadRequestError for 400 responses' do + expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) do |ex| + expect(ex.message).to eq('the server responded with status 400') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(400) + expect(ex.response_status).to eq(400) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::UnauthorizedError for 401 responses' do + expect { conn.get('unauthorized') }.to raise_error(Faraday::UnauthorizedError) do |ex| + expect(ex.message).to eq('the server responded with status 401') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(401) + expect(ex.response_status).to eq(401) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::ForbiddenError for 403 responses' do + expect { conn.get('forbidden') }.to raise_error(Faraday::ForbiddenError) do |ex| + expect(ex.message).to eq('the server responded with status 403') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(403) + expect(ex.response_status).to eq(403) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::ResourceNotFound for 404 responses' do + expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex| + expect(ex.message).to eq('the server responded with status 404') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(404) + expect(ex.response_status).to eq(404) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::ProxyAuthError for 407 responses' do + expect { conn.get('proxy-error') }.to raise_error(Faraday::ProxyAuthError) do |ex| + expect(ex.message).to eq('407 "Proxy Authentication Required"') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(407) + expect(ex.response_status).to eq(407) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::RequestTimeoutError for 408 responses' do + expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex| + expect(ex.message).to eq('the server responded with status 408') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(408) + expect(ex.response_status).to eq(408) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::ConflictError for 409 responses' do + expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex| + expect(ex.message).to eq('the server responded with status 409') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(409) + expect(ex.response_status).to eq(409) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::UnprocessableEntityError for 422 responses' do + expect { conn.get('unprocessable-entity') }.to raise_error(Faraday::UnprocessableEntityError) do |ex| + expect(ex.message).to eq('the server responded with status 422') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(422) + expect(ex.response_status).to eq(422) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::TooManyRequestsError for 429 responses' do + expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex| + expect(ex.message).to eq('the server responded with status 429') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(429) + expect(ex.response_status).to eq(429) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::NilStatusError for nil status in response' do + expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex| + expect(ex.message).to eq('http status could not be derived from the server response') + expect(ex.response[:headers]['X-Reason']).to eq('nil') + expect(ex.response[:status]).to be_nil + expect(ex.response_status).to be_nil + expect(ex.response_body).to eq('fail') + expect(ex.response_headers['X-Reason']).to eq('nil') + end + end + + it 'raises Faraday::ClientError for other 4xx responses' do + expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex| + expect(ex.message).to eq('the server responded with status 499') + expect(ex.response[:headers]['X-Reason']).to eq('because') + expect(ex.response[:status]).to eq(499) + expect(ex.response_status).to eq(499) + expect(ex.response_body).to eq('keep looking') + expect(ex.response_headers['X-Reason']).to eq('because') + end + end + + it 'raises Faraday::ServerError for 500 responses' do + expect { conn.get('server-error') }.to raise_error(Faraday::ServerError) do |ex| + expect(ex.message).to eq('the server responded with status 500') + expect(ex.response[:headers]['X-Error']).to eq('bailout') + expect(ex.response[:status]).to eq(500) + expect(ex.response_status).to eq(500) + expect(ex.response_body).to eq('fail') + expect(ex.response_headers['X-Error']).to eq('bailout') + end + end + + describe 'request info' do + let(:conn) do + Faraday.new do |b| + b.response :raise_error, **middleware_options + b.adapter :test do |stub| + stub.post(url, request_body, request_headers) do + [400, { 'X-Reason' => 'because' }, 'keep looking'] + end + end + end + end + let(:middleware_options) { {} } + let(:request_body) { JSON.generate({ 'item' => 'sth' }) } + let(:request_headers) { { 'Authorization' => 'Basic 123' } } + let(:url_path) { 'request' } + let(:query_params) { 'full=true' } + let(:url) { "#{url_path}?#{query_params}" } + + subject(:perform_request) do + conn.post url do |req| + req.headers['Authorization'] = 'Basic 123' + req.body = request_body + end + end + + it 'returns the request info in the exception' do + expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex| + expect(ex.response[:request][:method]).to eq(:post) + expect(ex.response[:request][:url]).to eq(URI("http:/#{url}")) + expect(ex.response[:request][:url_path]).to eq("/#{url_path}") + expect(ex.response[:request][:params]).to eq({ 'full' => 'true' }) + expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers)) + expect(ex.response[:request][:body]).to eq(request_body) + end + end + + context 'when the include_request option is set to false' do + let(:middleware_options) { { include_request: false } } + + it 'does not include request info in the exception' do + expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex| + expect(ex.response.keys).to contain_exactly( + :status, + :headers, + :body + ) + end + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/response_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/response_spec.rb new file mode 100644 index 00000000..e3e2c237 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/response_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Response do + subject { Faraday::Response.new(env) } + + let(:env) do + Faraday::Env.from(status: 404, body: 'yikes', url: Faraday::Utils.URI('https://lostisland.github.io/faraday'), + response_headers: { 'Content-Type' => 'text/plain' }) + end + + it { expect(subject.finished?).to be_truthy } + it { expect { subject.finish({}) }.to raise_error(RuntimeError) } + it { expect(subject.success?).to be_falsey } + it { expect(subject.status).to eq(404) } + it { expect(subject.body).to eq('yikes') } + it { expect(subject.headers['Content-Type']).to eq('text/plain') } + it { expect(subject['content-type']).to eq('text/plain') } + + describe '#apply_request' do + before { subject.apply_request(body: 'a=b', method: :post) } + + it { expect(subject.body).to eq('yikes') } + it { expect(subject.env[:method]).to eq(:post) } + end + + describe '#to_hash' do + let(:hash) { subject.to_hash } + + it { expect(hash).to be_a(Hash) } + it { expect(hash[:status]).to eq(subject.status) } + it { expect(hash[:response_headers]).to eq(subject.headers) } + it { expect(hash[:body]).to eq(subject.body) } + it { expect(hash[:url]).to eq(subject.env.url) } + end + + describe 'marshal serialization support' do + subject { Faraday::Response.new } + let(:loaded) { Marshal.load(Marshal.dump(subject)) } + + before do + subject.on_complete {} + subject.finish(env.merge(params: 'moo')) + end + + it { expect(loaded.env[:params]).to be_nil } + it { expect(loaded.env[:body]).to eq(env[:body]) } + it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) } + it { expect(loaded.env[:status]).to eq(env[:status]) } + it { expect(loaded.env[:url]).to eq(env[:url]) } + end + + describe '#on_complete' do + subject { Faraday::Response.new } + + it 'parse body on finish' do + subject.on_complete { |env| env[:body] = env[:body].upcase } + subject.finish(env) + + expect(subject.body).to eq('YIKES') + end + + it 'can access response body in on_complete callback' do + subject.on_complete { |env| env[:body] = subject.body.upcase } + subject.finish(env) + + expect(subject.body).to eq('YIKES') + end + + it 'can access response body in on_complete callback' do + callback_env = nil + subject.on_complete { |env| callback_env = env } + subject.finish({}) + + expect(subject.env).to eq(callback_env) + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/utils/headers_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/utils/headers_spec.rb new file mode 100644 index 00000000..66751f7f --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/utils/headers_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Utils::Headers do + subject { Faraday::Utils::Headers.new } + + context 'when Content-Type is set to application/json' do + before { subject['Content-Type'] = 'application/json' } + + it { expect(subject.keys).to eq(['Content-Type']) } + it { expect(subject['Content-Type']).to eq('application/json') } + it { expect(subject['CONTENT-TYPE']).to eq('application/json') } + it { expect(subject['content-type']).to eq('application/json') } + it { is_expected.to include('content-type') } + end + + context 'when Content-Type is set to application/xml' do + before { subject['Content-Type'] = 'application/xml' } + + it { expect(subject.keys).to eq(['Content-Type']) } + it { expect(subject['Content-Type']).to eq('application/xml') } + it { expect(subject['CONTENT-TYPE']).to eq('application/xml') } + it { expect(subject['content-type']).to eq('application/xml') } + it { is_expected.to include('content-type') } + end + + describe '#fetch' do + before { subject['Content-Type'] = 'application/json' } + + it { expect(subject.fetch('Content-Type')).to eq('application/json') } + it { expect(subject.fetch('CONTENT-TYPE')).to eq('application/json') } + it { expect(subject.fetch(:content_type)).to eq('application/json') } + it { expect(subject.fetch('invalid', 'default')).to eq('default') } + it { expect(subject.fetch('invalid', false)).to eq(false) } + it { expect(subject.fetch('invalid', nil)).to be_nil } + it { expect(subject.fetch('Invalid') { |key| "#{key} key" }).to eq('Invalid key') } + it 'calls a block when provided' do + block_called = false + expect(subject.fetch('content-type') { block_called = true }).to eq('application/json') + expect(block_called).to be_falsey + end + it 'raises an error if key not found' do + expected_error = defined?(KeyError) ? KeyError : IndexError + expect { subject.fetch('invalid') }.to raise_error(expected_error) + end + end + + describe '#delete' do + before do + subject['Content-Type'] = 'application/json' + @deleted = subject.delete('content-type') + end + + it { expect(@deleted).to eq('application/json') } + it { expect(subject.size).to eq(0) } + it { is_expected.not_to include('content-type') } + it { expect(subject.delete('content-type')).to be_nil } + end + + describe '#parse' do + context 'when response headers leave http status line out' do + let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" } + + before { subject.parse(headers) } + + it { expect(subject.keys).to eq(%w[Content-Type]) } + it { expect(subject['Content-Type']).to eq('text/html') } + it { expect(subject['content-type']).to eq('text/html') } + end + + context 'when response headers values include a colon' do + let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" } + + before { subject.parse(headers) } + + it { expect(subject['location']).to eq('http://httpbingo.org/') } + end + + context 'when response headers include a blank line' do + let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" } + + before { subject.parse(headers) } + + it { expect(subject['content-type']).to eq('text/html') } + end + + context 'when response headers include already stored keys' do + let(:headers) { "HTTP/1.1 200 OK\r\nX-Numbers: 123\r\n\r\n" } + + before do + h = subject + h[:x_numbers] = 8 + h.parse(headers) + end + + it do + expect(subject[:x_numbers]).to eq('8, 123') + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday/utils_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday/utils_spec.rb new file mode 100644 index 00000000..bf7499eb --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday/utils_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +RSpec.describe Faraday::Utils do + describe 'headers parsing' do + let(:multi_response_headers) do + "HTTP/1.x 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n" \ + "HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n" + end + + it 'parse headers for aggregated responses' do + headers = Faraday::Utils::Headers.new + headers.parse(multi_response_headers) + + result = headers.to_hash + + expect(result['Content-Type']).to eq('application/json; charset=UTF-8') + end + end + + describe 'URI parsing' do + let(:url) { 'http://example.com/abc' } + + it 'escapes safe buffer' do + str = FakeSafeBuffer.new('$32,000.00') + expect(Faraday::Utils.escape(str)).to eq('%2432%2C000.00') + end + + it 'parses with default parser' do + with_default_uri_parser(nil) do + uri = normalize(url) + expect(uri.host).to eq('example.com') + end + end + + it 'parses with URI' do + with_default_uri_parser(::URI) do + uri = normalize(url) + expect(uri.host).to eq('example.com') + end + end + + it 'parses with block' do + with_default_uri_parser(->(u) { "booya#{'!' * u.size}" }) do + expect(normalize(url)).to eq('booya!!!!!!!!!!!!!!!!!!!!!!') + end + end + + it 'replaces headers hash' do + headers = Faraday::Utils::Headers.new('authorization' => 't0ps3cr3t!') + expect(headers).to have_key('authorization') + + headers.replace('content-type' => 'text/plain') + expect(headers).not_to have_key('authorization') + end + end + + describe '.deep_merge!' do + let(:connection_options) { Faraday::ConnectionOptions.new } + let(:url) do + { + url: 'http://example.com/abc', + headers: { 'Mime-Version' => '1.0' }, + request: { oauth: { consumer_key: 'anonymous' } }, + ssl: { version: '2' } + } + end + + it 'recursively merges the headers' do + connection_options.headers = { user_agent: 'My Agent 1.0' } + deep_merge = Faraday::Utils.deep_merge!(connection_options, url) + + expect(deep_merge.headers).to eq('Mime-Version' => '1.0', user_agent: 'My Agent 1.0') + end + + context 'when a target hash has an Options Struct value' do + let(:request) do + { + params_encoder: nil, + proxy: nil, + bind: nil, + timeout: nil, + open_timeout: nil, + read_timeout: nil, + write_timeout: nil, + boundary: nil, + oauth: { consumer_key: 'anonymous' }, + context: nil, + on_data: nil + } + end + let(:ssl) do + { + verify: nil, + ca_file: nil, + ca_path: nil, + verify_mode: nil, + cert_store: nil, + client_cert: nil, + client_key: nil, + certificate: nil, + private_key: nil, + verify_depth: nil, + version: '2', + min_version: nil, + max_version: nil, + verify_hostname: nil + } + end + + it 'does not overwrite an Options Struct value' do + deep_merge = Faraday::Utils.deep_merge!(connection_options, url) + + expect(deep_merge.request.to_h).to eq(request) + expect(deep_merge.ssl.to_h).to eq(ssl) + end + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/faraday_spec.rb b/bin/gems/faraday-2.9.0/spec/faraday_spec.rb new file mode 100644 index 00000000..30be29cf --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/faraday_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +RSpec.describe Faraday do + it 'has a version number' do + expect(Faraday::VERSION).not_to be nil + end + + context 'proxies to default_connection' do + let(:mock_connection) { double('Connection') } + before do + Faraday.default_connection = mock_connection + end + + it 'proxies methods that exist on the default_connection' do + expect(mock_connection).to receive(:this_should_be_proxied) + + Faraday.this_should_be_proxied + end + + it 'uses method_missing on Faraday if there is no proxyable method' do + expected_message = + if RUBY_VERSION >= '3.3' + "undefined method `this_method_does_not_exist' for module Faraday" + else + "undefined method `this_method_does_not_exist' for Faraday:Module" + end + + expect { Faraday.this_method_does_not_exist }.to raise_error(NoMethodError, expected_message) + end + + it 'proxied methods can be accessed' do + allow(mock_connection).to receive(:this_should_be_proxied) + + expect(Faraday.method(:this_should_be_proxied)).to be_a(Method) + end + + after do + Faraday.default_connection = nil + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/spec_helper.rb b/bin/gems/faraday-2.9.0/spec/spec_helper.rb new file mode 100644 index 00000000..1b80ea24 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/spec_helper.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration + +require 'simplecov' +require 'coveralls' +require 'webmock/rspec' +WebMock.disable_net_connect!(allow_localhost: true) + +SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter] + +SimpleCov.start do + add_filter '/spec/' + minimum_coverage 84 + minimum_coverage_by_file 26 +end + +require 'faraday' +require 'pry' + +# Ensure all /lib files are loaded +# so they will be included in the test coverage report. +Dir['./lib/**/*.rb'].each { |file| require file } + +# Load all Rspec support files +Dir['./spec/support/**/*.rb'].each { |file| require file } + +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + # config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = "doc" + # end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + # config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed + + config.include Faraday::HelperMethods +end + +# Extends RSpec DocumentationFormatter to hide skipped tests. +module FormatterOverrides + def example_pending(_arg); end + + def dump_pending(_arg); end + + RSpec::Core::Formatters::DocumentationFormatter.prepend self +end diff --git a/bin/gems/faraday-2.9.0/spec/support/disabling_stub.rb b/bin/gems/faraday-2.9.0/spec/support/disabling_stub.rb new file mode 100644 index 00000000..3df2f21b --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/disabling_stub.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Allows to disable WebMock stubs +module DisablingStub + def disable + @disabled = true + end + + def disabled? + @disabled + end + + WebMock::RequestStub.prepend self +end diff --git a/bin/gems/faraday-2.9.0/spec/support/fake_safe_buffer.rb b/bin/gems/faraday-2.9.0/spec/support/fake_safe_buffer.rb new file mode 100644 index 00000000..69afd6ea --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/fake_safe_buffer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# emulates ActiveSupport::SafeBuffer#gsub +FakeSafeBuffer = Struct.new(:string) do + def to_s + self + end + + def gsub(regex) + string.gsub(regex) do + match, = Regexp.last_match(0), '' =~ /a/ # rubocop:disable Performance/StringInclude + yield(match) + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/support/helper_methods.rb b/bin/gems/faraday-2.9.0/spec/support/helper_methods.rb new file mode 100644 index 00000000..0f5d4f5a --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/helper_methods.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Faraday + module HelperMethods + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def features(*features) + @features = features + end + + def on_feature(name) + yield if block_given? && feature?(name) + end + + def feature?(name) + if @features.nil? + superclass.feature?(name) if superclass.respond_to?(:feature?) + elsif @features.include?(name) + true + end + end + + def method_with_body?(method) + METHODS_WITH_BODY.include?(method.to_s) + end + end + + def ssl_mode? + ENV['SSL'] == 'yes' + end + + def normalize(url) + Faraday::Utils::URI(url) + end + + def with_default_uri_parser(parser) + old_parser = Faraday::Utils.default_uri_parser + begin + Faraday::Utils.default_uri_parser = parser + yield + ensure + Faraday::Utils.default_uri_parser = old_parser + end + end + + def with_env(new_env) + old_env = {} + + new_env.each do |key, value| + old_env[key] = ENV.fetch(key, false) + ENV[key] = value + end + + begin + yield + ensure + old_env.each do |key, value| + value == false ? ENV.delete(key) : ENV[key] = value + end + end + end + + def with_env_proxy_disabled + Faraday.ignore_env_proxy = true + + begin + yield + ensure + Faraday.ignore_env_proxy = false + end + end + + def capture_warnings + old = $stderr + $stderr = StringIO.new + begin + yield + $stderr.string + ensure + $stderr = old + end + end + + def method_with_body?(method) + self.class.method_with_body?(method) + end + + def big_string + kb = 1024 + (32..126).map(&:chr).cycle.take(50 * kb).join + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/support/shared_examples/adapter.rb b/bin/gems/faraday-2.9.0/spec/support/shared_examples/adapter.rb new file mode 100644 index 00000000..62569088 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/shared_examples/adapter.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +shared_examples 'an adapter' do |**options| + before { skip } if options[:skip] + + context 'with SSL enabled' do + before { ENV['SSL'] = 'yes' } + include_examples 'adapter examples', options + end + + context 'with SSL disabled' do + before { ENV['SSL'] = 'no' } + include_examples 'adapter examples', options + end +end + +shared_examples 'adapter examples' do |**options| + include Faraday::StreamingResponseChecker + + let(:adapter) { described_class.name.split('::').last } + + let(:conn_options) { { headers: { 'X-Faraday-Adapter' => adapter } }.merge(options[:conn_options] || {}) } + + let(:adapter_options) do + return [] unless options[:adapter_options] + + if options[:adapter_options].is_a?(Array) + options[:adapter_options] + else + [options[:adapter_options]] + end + end + + let(:protocol) { ssl_mode? ? 'https' : 'http' } + let(:remote) { "#{protocol}://example.com" } + let(:stub_remote) { remote } + + let(:conn) do + conn_options[:ssl] ||= {} + conn_options[:ssl][:ca_file] ||= ENV.fetch('SSL_FILE', nil) + conn_options[:ssl][:verify_hostname] ||= ENV['SSL_VERIFY_HOSTNAME'] == 'yes' + + Faraday.new(remote, conn_options) do |conn| + conn.request :url_encoded + conn.response :raise_error + conn.adapter described_class, *adapter_options + end + end + + let!(:request_stub) { stub_request(http_method, stub_remote) } + + after do + expect(request_stub).to have_been_requested unless request_stub.disabled? + end + + describe '#delete' do + let(:http_method) { :delete } + + it_behaves_like 'a request method', :delete + end + + describe '#get' do + let(:http_method) { :get } + + it_behaves_like 'a request method', :get + end + + describe '#head' do + let(:http_method) { :head } + + it_behaves_like 'a request method', :head + end + + describe '#options' do + let(:http_method) { :options } + + it_behaves_like 'a request method', :options + end + + describe '#patch' do + let(:http_method) { :patch } + + it_behaves_like 'a request method', :patch + end + + describe '#post' do + let(:http_method) { :post } + + it_behaves_like 'a request method', :post + end + + describe '#put' do + let(:http_method) { :put } + + it_behaves_like 'a request method', :put + end + + on_feature :trace_method do + describe '#trace' do + let(:http_method) { :trace } + + it_behaves_like 'a request method', :trace + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/support/shared_examples/params_encoder.rb b/bin/gems/faraday-2.9.0/spec/support/shared_examples/params_encoder.rb new file mode 100644 index 00000000..38c85679 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/shared_examples/params_encoder.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +shared_examples 'a params encoder' do + it 'escapes safe buffer' do + monies = FakeSafeBuffer.new('$32,000.00') + expect(subject.encode('a' => monies)).to eq('a=%2432%2C000.00') + end + + it 'raises type error for empty string' do + expect { subject.encode('') }.to raise_error(TypeError) do |error| + expect(error.message).to eq("Can't convert String into Hash.") + end + end + + it 'encodes nil' do + expect(subject.encode('a' => nil)).to eq('a') + end +end diff --git a/bin/gems/faraday-2.9.0/spec/support/shared_examples/request_method.rb b/bin/gems/faraday-2.9.0/spec/support/shared_examples/request_method.rb new file mode 100644 index 00000000..afa33767 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/shared_examples/request_method.rb @@ -0,0 +1,263 @@ +# frozen_string_literal: true + +shared_examples 'proxy examples' do + it 'handles requests with proxy' do + res = conn.public_send(http_method, '/') + + expect(res.status).to eq(200) + end + + it 'handles proxy failures' do + request_stub.to_return(status: 407) + + expect { conn.public_send(http_method, '/') }.to raise_error(Faraday::ProxyAuthError) + end +end + +shared_examples 'a request method' do |http_method| + let(:query_or_body) { method_with_body?(http_method) ? :body : :query } + let(:response) { conn.public_send(http_method, '/') } + + unless http_method == :head && feature?(:skip_response_body_on_head) + it 'retrieves the response body' do + res_body = 'test' + request_stub.to_return(body: res_body) + expect(conn.public_send(http_method, '/').body).to eq(res_body) + end + end + + it 'handles headers with multiple values' do + request_stub.to_return(headers: { 'Set-Cookie' => 'name=value' }) + expect(response.headers['set-cookie']).to eq('name=value') + end + + it 'retrieves the response headers' do + request_stub.to_return(headers: { 'Content-Type' => 'text/plain' }) + expect(response.headers['Content-Type']).to match(%r{text/plain}) + expect(response.headers['content-type']).to match(%r{text/plain}) + end + + it 'sends user agent' do + request_stub.with(headers: { 'User-Agent' => 'Agent Faraday' }) + conn.public_send(http_method, '/', nil, user_agent: 'Agent Faraday') + end + + it 'represents empty body response as blank string' do + expect(response.body).to eq('') + end + + it 'handles connection error' do + request_stub.disable + expect { conn.public_send(http_method, 'http://localhost:4') }.to raise_error(Faraday::ConnectionFailed) + end + + on_feature :local_socket_binding do + it 'binds local socket' do + stub_request(http_method, 'http://example.com') + + host = '1.2.3.4' + port = 1234 + conn_options[:request] = { bind: { host: host, port: port } } + + conn.public_send(http_method, '/') + + expect(conn.options[:bind][:host]).to eq(host) + expect(conn.options[:bind][:port]).to eq(port) + end + end + + # context 'when wrong ssl certificate is provided' do + # let(:ca_file_path) { 'tmp/faraday-different-ca-cert.crt' } + # before { conn_options.merge!(ssl: { ca_file: ca_file_path }) } + # + # it do + # expect { conn.public_send(http_method, '/') }.to raise_error(Faraday::SSLError) # do |ex| + # expect(ex.message).to include?('certificate') + # end + # end + # end + + on_feature :request_body_on_query_methods do + it 'sends request body' do + request_stub.with({ body: 'test' }) + res = if query_or_body == :body + conn.public_send(http_method, '/', 'test') + else + conn.public_send(http_method, '/') do |req| + req.body = 'test' + end + end + expect(res.env.request_body).to eq('test') + end + end + + it 'sends url encoded parameters' do + payload = { name: 'zack' } + request_stub.with({ query_or_body => payload }) + res = conn.public_send(http_method, '/', payload) + if query_or_body == :query + expect(res.env.request_body).to be_nil + else + expect(res.env.request_body).to eq('name=zack') + end + end + + it 'sends url encoded nested parameters' do + payload = { name: { first: 'zack' } } + request_stub.with({ query_or_body => payload }) + conn.public_send(http_method, '/', payload) + end + + # TODO: This needs reimplementation: see https://github.com/lostisland/faraday/issues/718 + # Should raise Faraday::TimeoutError + it 'supports timeout option' do + conn_options[:request] = { timeout: 1 } + request_stub.to_timeout + exc = adapter == 'NetHttp' ? Faraday::ConnectionFailed : Faraday::TimeoutError + expect { conn.public_send(http_method, '/') }.to raise_error(exc) + end + + # TODO: This needs reimplementation: see https://github.com/lostisland/faraday/issues/718 + # Should raise Faraday::ConnectionFailed + it 'supports open_timeout option' do + conn_options[:request] = { open_timeout: 1 } + request_stub.to_timeout + exc = adapter == 'NetHttp' ? Faraday::ConnectionFailed : Faraday::TimeoutError + expect { conn.public_send(http_method, '/') }.to raise_error(exc) + end + + on_feature :reason_phrase_parse do + it 'parses the reason phrase' do + request_stub.to_return(status: [200, 'OK']) + expect(response.reason_phrase).to eq('OK') + end + end + + on_feature :compression do + # Accept-Encoding header not sent for HEAD requests as body is not expected in the response. + unless http_method == :head + it 'handles gzip compression' do + request_stub.with(headers: { 'Accept-Encoding' => /\bgzip\b/ }) + conn.public_send(http_method, '/') + end + + it 'handles deflate compression' do + request_stub.with(headers: { 'Accept-Encoding' => /\bdeflate\b/ }) + conn.public_send(http_method, '/') + end + end + end + + on_feature :streaming do + describe 'streaming' do + let(:streamed) { [] } + + context 'when response is empty' do + it 'handles streaming' do + env = nil + conn.public_send(http_method, '/') do |req| + req.options.on_data = proc do |chunk, size, block_env| + streamed << [chunk, size] + env ||= block_env + end + end + + expect(streamed).to eq([['', 0]]) + # TODO: enable this after updating all existing adapters to the new streaming API + # expect(env).to be_a(Faraday::Env) + # expect(env.status).to eq(200) + end + end + + context 'when response contains big data' do + before { request_stub.to_return(body: big_string) } + + it 'handles streaming' do + env = nil + response = conn.public_send(http_method, '/') do |req| + req.options.on_data = proc do |chunk, size, block_env| + streamed << [chunk, size] + env ||= block_env + end + end + + expect(response.body).to eq('') + check_streaming_response(streamed, chunk_size: 16 * 1024) + # TODO: enable this after updating all existing adapters to the new streaming API + # expect(env).to be_a(Faraday::Env) + # expect(env.status).to eq(200) + end + end + end + end + + on_feature :parallel do + context 'with parallel setup' do + before do + @resp1 = nil + @resp2 = nil + @payload1 = { a: '1' } + @payload2 = { b: '2' } + + request_stub + .with({ query_or_body => @payload1 }) + .to_return(body: @payload1.to_json) + + stub_request(http_method, remote) + .with({ query_or_body => @payload2 }) + .to_return(body: @payload2.to_json) + + conn.in_parallel do + @resp1 = conn.public_send(http_method, '/', @payload1) + @resp2 = conn.public_send(http_method, '/', @payload2) + + expect(conn.in_parallel?).to be_truthy + expect(@resp1.body).to be_nil + expect(@resp2.body).to be_nil + end + + expect(conn.in_parallel?).to be_falsey + end + + it 'handles parallel requests status' do + expect(@resp1&.status).to eq(200) + expect(@resp2&.status).to eq(200) + end + + unless http_method == :head && feature?(:skip_response_body_on_head) + it 'handles parallel requests body' do + expect(@resp1&.body).to eq(@payload1.to_json) + expect(@resp2&.body).to eq(@payload2.to_json) + end + end + end + end + + context 'when a proxy is provided as option' do + before do + conn_options[:proxy] = 'http://env-proxy.com:80' + end + + include_examples 'proxy examples' + end + + context 'when http_proxy env variable is set' do + let(:proxy_url) { 'http://env-proxy.com:80' } + + around do |example| + with_env 'http_proxy' => proxy_url do + example.run + end + end + + include_examples 'proxy examples' + + context 'when the env proxy is ignored' do + around do |example| + with_env_proxy_disabled(&example) + end + + include_examples 'proxy examples' + end + end +end diff --git a/bin/gems/faraday-2.9.0/spec/support/streaming_response_checker.rb b/bin/gems/faraday-2.9.0/spec/support/streaming_response_checker.rb new file mode 100644 index 00000000..8ef25999 --- /dev/null +++ b/bin/gems/faraday-2.9.0/spec/support/streaming_response_checker.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Faraday + module StreamingResponseChecker + def check_streaming_response(streamed, options = {}) + opts = { + prefix: '', + streaming?: true + }.merge(options) + + expected_response = opts[:prefix] + big_string + + chunks, sizes = streamed.transpose + + # Check that the total size of the chunks (via the last size returned) + # is the same size as the expected_response + expect(sizes.last).to eq(expected_response.bytesize) + + start_index = 0 + expected_chunks = [] + chunks.each do |actual_chunk| + expected_chunk = expected_response[start_index..((start_index + actual_chunk.bytesize) - 1)] + expected_chunks << expected_chunk + start_index += expected_chunk.bytesize + end + + # it's easier to read a smaller portion, so we check that first + expect(expected_chunks[0][0..255]).to eq(chunks[0][0..255]) + + [expected_chunks, chunks].transpose.each do |expected, actual| + expect(actual).to eq(expected) + end + end + end +end diff --git a/bin/gems/faraday-net_http-3.1.0/LICENSE.md b/bin/gems/faraday-net_http-3.1.0/LICENSE.md new file mode 100644 index 00000000..b7aabc56 --- /dev/null +++ b/bin/gems/faraday-net_http-3.1.0/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Jan van der Pas + +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/bin/gems/faraday-net_http-3.1.0/README.md b/bin/gems/faraday-net_http-3.1.0/README.md new file mode 100644 index 00000000..6d510f4b --- /dev/null +++ b/bin/gems/faraday-net_http-3.1.0/README.md @@ -0,0 +1,57 @@ +# Faraday Net::HTTP adapter + +This gem is a [Faraday][faraday] adapter for the [Net::HTTP][net-http] library. Faraday is an HTTP client library that provides a common interface over many adapters. Every adapter is defined into it's own gem. This gem defines the adapter for `Net::HTTP` the HTTP library that's included into the standard library of Ruby. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'faraday-net_http' +``` + +And then execute: + + $ bundle install + +Or install it yourself as: + + $ gem install faraday-net_http + +## Usage + +```ruby +conn = Faraday.new(...) do |f| + f.adapter :net_http do |http| + # yields Net::HTTP + http.verify_callback = lambda do |preverify, cert_store| + # do something here... + end + end +end +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](rubygems). + +## Contributing + +Bug reports and pull requests are welcome on [GitHub][repo]. + +## License + +The gem is available as open source under the terms of the [license][license]. + +## Code of Conduct + +Everyone interacting in the Faraday Net::HTTP adapter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct][code-of-conduct]. + +[faraday]: https://github.com/lostisland/faraday +[net-http]: https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html +[rubygems]: https://rubygems.org +[repo]: https://github.com/lostisland/faraday-net_http +[license]: https://github.com/lostisland/faraday-net_http/blob/main/LICENSE.md +[code-of-conduct]: https://github.com/lostisland/faraday-net_http/blob/main/CODE_OF_CONDUCT.md diff --git a/bin/gems/faraday-net_http-3.1.0/lib/faraday/adapter/net_http.rb b/bin/gems/faraday-net_http-3.1.0/lib/faraday/adapter/net_http.rb new file mode 100644 index 00000000..890648ba --- /dev/null +++ b/bin/gems/faraday-net_http-3.1.0/lib/faraday/adapter/net_http.rb @@ -0,0 +1,202 @@ +# frozen_string_literal: true + +begin + require 'net/https' +rescue LoadError + warn 'Warning: no such file to load -- net/https. ' \ + 'Make sure openssl is installed if you want ssl support' + require 'net/http' +end +require 'zlib' + +module Faraday + class Adapter + class NetHttp < Faraday::Adapter + exceptions = [ + IOError, + Errno::EADDRNOTAVAIL, + Errno::EALREADY, + Errno::ECONNABORTED, + Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::EHOSTUNREACH, + Errno::EINVAL, + Errno::ENETUNREACH, + Errno::EPIPE, + Net::HTTPBadResponse, + Net::HTTPHeaderSyntaxError, + Net::ProtocolError, + SocketError, + Zlib::GzipFile::Error + ] + + exceptions << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError) + exceptions << ::Net::OpenTimeout if defined?(::Net::OpenTimeout) + + NET_HTTP_EXCEPTIONS = exceptions.freeze + + def initialize(app = nil, opts = {}, &block) + @ssl_cert_store = nil + super(app, opts, &block) + end + + def build_connection(env) + net_http_connection(env).tap do |http| + http.use_ssl = env[:url].scheme == 'https' if http.respond_to?(:use_ssl=) + configure_ssl(http, env[:ssl]) + configure_request(http, env[:request]) + end + end + + def net_http_connection(env) + proxy = env[:request][:proxy] + port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80) + if proxy + Net::HTTP.new(env[:url].hostname, port, + proxy[:uri].hostname, proxy[:uri].port, + proxy[:user], proxy[:password]) + else + Net::HTTP.new(env[:url].hostname, port, nil) + end + end + + def call(env) + super + connection(env) do |http| + perform_request(http, env) + rescue *NET_HTTP_EXCEPTIONS => e + raise Faraday::SSLError, e if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError) + + raise Faraday::ConnectionFailed, e + end + @app.call env + rescue Timeout::Error, Errno::ETIMEDOUT => e + raise Faraday::TimeoutError, e + end + + private + + def create_request(env) + request = Net::HTTPGenericRequest.new \ + env[:method].to_s.upcase, # request method + !!env[:body], # is there request body + env[:method] != :head, # is there response body + env[:url].request_uri, # request uri path + env[:request_headers] # request headers + + if env[:body].respond_to?(:read) + request.body_stream = env[:body] + else + request.body = env[:body] + end + request + end + + def perform_request(http, env) + if env.stream_response? + http_response = env.stream_response do |&on_data| + request_with_wrapped_block(http, env, &on_data) + end + http_response.body = nil + else + http_response = request_with_wrapped_block(http, env) + end + env.response_body = encoded_body(http_response) + env.response.finish(env) + http_response + end + + def request_with_wrapped_block(http, env, &block) + # Must use Net::HTTP#start and pass it a block otherwise the server's + # TCP socket does not close correctly. + http.start do |opened_http| + opened_http.request create_request(env) do |response| + save_http_response(env, response) + + response.read_body(&block) if block_given? + end + end + end + + def save_http_response(env, http_response) + save_response( + env, http_response.code.to_i, nil, nil, http_response.message, finished: false + ) do |response_headers| + http_response.each_header do |key, value| + response_headers[key] = value + end + end + end + + def configure_ssl(http, ssl) + return unless ssl + + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.cert = ssl[:client_cert] if ssl[:client_cert] + http.key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ca_path = ssl[:ca_path] if ssl[:ca_path] + http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + http.ssl_version = ssl[:version] if ssl[:version] + http.min_version = ssl[:min_version] if ssl[:min_version] + http.max_version = ssl[:max_version] if ssl[:max_version] + http.verify_hostname = ssl[:verify_hostname] if verify_hostname_enabled?(http, ssl) + end + + def configure_request(http, req) + if (sec = request_timeout(:read, req)) + http.read_timeout = sec + end + + if (sec = http.respond_to?(:write_timeout=) && + request_timeout(:write, req)) + http.write_timeout = sec + end + + if (sec = request_timeout(:open, req)) + http.open_timeout = sec + end + + # Only set if Net::Http supports it, since Ruby 2.5. + http.max_retries = 0 if http.respond_to?(:max_retries=) + + @config_block&.call(http) + end + + def ssl_cert_store(ssl) + return ssl[:cert_store] if ssl[:cert_store] + + # Use the default cert store by default, i.e. system ca certs + @ssl_cert_store ||= OpenSSL::X509::Store.new.tap(&:set_default_paths) + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + + def encoded_body(http_response) + body = http_response.body || +'' + /\bcharset=([^;]+)/.match(http_response['Content-Type']) do |match| + content_charset = ::Encoding.find(match[1].strip) + body = body.dup if body.frozen? + body.force_encoding(content_charset) + rescue ArgumentError + nil + end + body + end + + def verify_hostname_enabled?(http, ssl) + http.respond_to?(:verify_hostname=) && ssl.key?(:verify_hostname) + end + end + end +end diff --git a/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http.rb b/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http.rb new file mode 100644 index 00000000..e4048e89 --- /dev/null +++ b/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'faraday/adapter/net_http' +require 'faraday/net_http/version' + +module Faraday + module NetHttp + Faraday::Adapter.register_middleware(net_http: Faraday::Adapter::NetHttp) + end +end diff --git a/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http/version.rb b/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http/version.rb new file mode 100644 index 00000000..86881141 --- /dev/null +++ b/bin/gems/faraday-net_http-3.1.0/lib/faraday/net_http/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Faraday + module NetHttp + VERSION = '3.1.0' + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/CHANGELOG.md b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/CHANGELOG.md new file mode 100644 index 00000000..3a9c71eb --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/CHANGELOG.md @@ -0,0 +1,465 @@ +1.17.1 / 2024-12-30 +------------------- + +Fixed: +* #1117 Restart async callback dispatcher thread after fork. +* #1133 Add ruby-3.4 native gem. +* #1134 Fix FFI::DataConverter non-generic usage in RBS files. + + +1.17.0 / 2024-06-02 +------------------- + +Fixed: +* Add FFI::AbstractMemory#read_array_of_string . It was defined but not exposed to Ruby nor tested. #1070 + + +1.17.0.rc2 / 2024-04-22 +------------------- + +Fixed: +* Add missing write barriers to StructLayout#initialize causing a segfault with GC.stress. #1079 + + +1.17.0.rc1 / 2024-04-08 +------------------- + +Fixed: +* Fix type definitions on `aarch64-linux`. #1067, #1066 +* Use RB_TEST for `Pointer.autorelease=` . #1065 + So that `false` and `nil` are treated as falsey and anything else as truthy. +* Replace Fixnum by Integer. #1064 + Fixnum is no longer present in the ruby language. +* Update `FFI::NativeType` doc. #1061 +* Store FFI::Type::Mapped of FFI::StrPtrConverter in global instead of custom type map +* Various documentation fixes. #1042 +* Update `FFI::Pointer#==` to return `false` if a pointer is compared to a non-pointer object, which is the expected behavior. #1083 +* Avoid warning about undefined wariable `@ffi_functions` #1085 +* Fix a very unlikely GC bug when using a callback block. # 1089 + +Added: +* Provide binary gems for many platforms. #990 +* Add Windows fat binary gem for Ruby-3.3 +* Add RBS type definitions for many user facing parts of the FFI API. #1042 +* Improve fallback search path logic. #1088 + Respect LD_LIBRARY_PATH and DYLD_LIBRARY_PATH on Macos. +* Update libffi to current git master branch. + +Removed: +* Remove `enum CHAR_ARRAY` which is no longer used. #1063 + + +1.16.3 / 2023-10-04 +------------------- + +Fixed: +* Fix gcc error when building on CentOS 7. #1052 +* Avoid trying to store new DataConverter type in frozen TypeDefs hash. #1057 + + +1.16.2 / 2023-09-25 +------------------- + +Fixed: +* Handle null pointer crash after fork. #1051 + + +1.16.1 / 2023-09-24 +------------------- + +Fixed: +* Fix compiling the builtin libffi. #1049 + + +1.16.0 / 2023-09-23 +------------------- + +Fixed: +* Fix an issue with signed bitmasks when using flags on the most significant bit. #949 +* Fix FFI::Pointer#initialize using NUM2LL instead of NUM2ULL. +* Fix FFI::Type#inspect to properly display the constant name. #1002 +* Use libffi closure allocations on hppa-Linux. #1017 + Previously they would segfault. +* Fix class name of Symbol#inspect. +* Fix MSVC support of libtest. #1028 +* Fix attach_function of functions ending in ? or ! #971 + +Added: +* Convert all C-based classes to TypedData and use write barriers. #994, #995, #996, #997, #998, #999, #1000, #1001, #1003, #1004, #1005, #1006, #1007, #1008, #1009, #1010, #1011, #1012 + This results in less pressure on the garbage collector, since the objects can be promoted to the old generation, which means they only get marked on major GC. +* Implement `ObjectSpace.memsize_of()` of all C-based classes. +* Make FFI Ractor compatible. #1023 + Modules extended per `extend FFI::Library` need to be frozen in order to be used by non-main Ractors. + This can be done by calling `freeze` below of all C interface definitions. + * In a Ractor it's possible to: + * load DLLs and call its functions, access its global variables + * use builtin typedefs + * use and modify ractor local typedefs + * define callbacks + * receive async callbacks from non-ruby threads + * use frozen FFI::Library based modules with all attributes (enums, structs, typedefs, functions, callbacks) + * invoke frozen functions and callbacks defined in the main Ractor + * use FFI::Struct definitions from the main Ractor + * In a Ractor it's impossible to: + * create new FFI::Library based modules + * create new FFI::Struct definitions + * use custom global typedefs + * use non-frozen FFI::Library based modules +* Allow type retrieval of attached functions+variables. #1023 +* Make FFI classes `GC.compact` friendly. #1021 +* Update libffi and disable custom trampoline when using libffi closure allocation. #1020 + This is because libffi changed the way how closures are allocated to static trampolines. +* Add types.conf for loongarch64-linux. #943 +* Add types.conf for sw_64-linux (Shen Wei 64-bit, based on Alpha). #1018 +* Add support for aarch64-windows. #1035 +* Windows: Update LoadLibrary error message to include error code. #1026 +* Allow private release method for FFI::ManagedStruct and FFI::AutoPointer. #1029 +* Add support for passing ABI version to FFI.map_library_name. #963 + This adds the new class FFI::LibraryPath . +* Add support for ruby-3.2 to windows binary gem. #1047 +* Enable debug symbols for `rake compile` builds to ease debugging. #1048 + +Removed: +* Remove allocator of AbstractMemory. #1013 + This disables AbstractMemory.new, which has no practical use. +* Remove unused FFI::SizeTypes. #1022 + + +1.15.5 / 2022-01-10 +------------------- + +Fixed: +* Fix long double argument or return values on 32bit i686. #849 +* FFI::ConstGenerator: avoid usage of the same binary file simultaneously. #929 + +Added: +* Add Windows fat binary gem for Ruby-3.1 + +Removed: +* Remove Windows fat binary gem for Ruby < 2.4 + + +1.15.4 / 2021-09-01 +------------------- + +Fixed: +* Fix build for uClibc. #913 +* Correct module lookup when including `ffi-module` gem. #912 + +Changed: +* Use ruby code of the ffi gem in JRuby-9.2.20+. #915 + + +1.15.3 / 2021-06-16 +------------------- + +Fixed: +* Fix temporary packaging issue with libffi. #904 + + +1.15.2 / 2021-06-16 +------------------- + +Added: +* Add support for Windows MINGW-UCRT build. #903 +* Add `/opt/homebrew/lib/` to fallback search paths to improve homebrew support. #880 #882 + +Changed: +* Regenerate `types.conf` for FreeBSD12 aarch64. #902 + + +1.15.1 / 2021-05-22 +------------------- + +Fixed: +* Append -pthread to linker options. #893 +* Use arm or aarch64 to identify Apple ARM CPU arch. #899 +* Allow overriding `gcc` with the `CC` env var in `const_generator.rb` and `struct_generator.rb`. #897 + + +1.15.0 / 2021-03-05 +------------------- + +Fixed: +* Fix MSVC build +* Fix async callbacks in conjunction with fork(). #884 + +Added: +* Allow to pass callbacks in varargs. #885 +* Name the threads for FFI callback dispatcher and async thread calls for easier debugging. #883 + The name can be retrieved by Thread.name and is shown by Thread.list.inspect etc. + Even gdb shows the thread name on supported operating systems. +* Add types.conf for powerpc64le-linux +* Add types.conf for riscv64-linux +* More release automation of ffi gems + +Changed: +* Switch from rubygems-tasks to bundler/gem_helper + +Removed: +* Remove unused VariadicInvoker#init + + +1.14.2 / 2020-12-21 +------------------- + +Fixed: +* Fix builtin libffi on newer Ubuntu caused by an outdated Makefile.in . #863 + + +1.14.1 / 2020-12-19 +------------------- + +Changed: +* Revert changes to FFI::Pointer#write_string made in ffi-1.14.0. + It breaks compatibilty in a way that can cause hard to find errors. #857 + + +1.14.0 / 2020-12-18 +------------------- + +Added: +* Add types.conf for x86_64-msys, x86_64-haiku, aarch64-openbsd and aarch64-darwin (alias arm64-darwin) +* Add method AbstractMemory#size_limit? . #829 +* Add new extconf option --enable-libffi-alloc which is enabled per default on Apple M1 (arm64-darwin). + +Changed: +* Do NULL pointer check only when array length > 0 . #305 +* Raise an error on an unknown order argument. #830 +* Change FFI::Pointer#write_string to terminate with a NUL byte like other string methods. #805 +* Update bundled libffi to latest master. + +Removed: +* Remove win32/stdint.h and stdbool.h because of copyright issue. #693 + +Fixed: +* Fix possible UTF-8 load error in loader script interpretation. #792 +* Fix segfault on non-array argument to #write_array_of_* +* Fix memory leak in MethodHandle . #815 +* Fix possible segfault in combination with fiddle or other libffi using gems . #835 +* Fix possibility to use ffi ruby gem with JRuby-9.3 . #763 +* Fix a GC issue, when a callback Proc is used on more than 2 callback signatures. #820 + + +1.13.1 / 2020-06-09 +------------------- + +Changed: +* Revert use of `ucrtbase.dll` as default C library on Windows-MINGW. + `ucrtbase.dll` is still used on MSWIN target. #790 +* Test for `ffi_prep_closure_loc()` to make sure we can use this function. + This fixes incorrect use of system libffi on MacOS Mojave (10.14). #787 +* Update types.conf on x86_64-dragonflybsd + + +1.13.0 / 2020-06-01 +------------------- + +Added: +* Add TruffleRuby support. Almost all specs are running on TruffleRuby and succeed. #768 +* Add ruby source files to the java gem. This allows to ship the Ruby library code per platform java gem and add it as a default gem to JRuby. #763 +* Add FFI::Platform::LONG_DOUBLE_SIZE +* Add bounds checks for writing to an inline char[] . #756 +* Add long double as callback return value. #771 +* Update type definitions and add types from stdint.h and stddef.h on i386-windows, x86_64-windows, x86_64-darwin, x86_64-linux, arm-linux, powerpc-linux. #749 +* Add new type definitions for powerpc-openbsd and sparcv9-openbsd. #775, #778 + +Changed: +* Raise required ruby version to >= 2.3. +* Lots of cleanups and improvements in library, specs and benchmarks. +* Fix a lot of compiler warnings at the C-extension +* Fix several install issues on MacOS: + * Look for libffi in SDK paths, since recent versions of macOS removed it from `/usr/include` . #757 + * Fix error `ld: library not found for -lgcc_s.10.4` + * Don't built for i386 architecture as it is deprecated +* Several fixes for MSVC build on Windows. #779 +* Use `ucrtbase.dll` as default C library on Windows instead of old `msvcrt.dll`. #779 +* Update builtin libffi to fix a Powerpc issue with parameters of type long +* Allow unmodified sourcing of (the ruby code of) this gem in JRuby and TruffleRuby as a default gem. #747 +* Improve check to detect if a module has a #find_type method suitable for FFI. This fixes compatibility with stdlib `mkmf` . #776 + +Removed: +* Reject callback with `:string` return type at definition, because it didn't work so far and is not save to use. #751, #782 + + +1.12.2 / 2020-02-01 +------------------- + +* Fix possible segfault at FFI::Struct#[] and []= after GC.compact . #742 + + +1.12.1 / 2020-01-14 +------------------- + +Added: +* Add binary gem support for ruby-2.7 on Windows + + +1.12.0 / 2020-01-14 +------------------- + +Added: +* FFI::VERSION is defined as part of `require 'ffi'` now. + It is no longer necessary to `require 'ffi/version'` . + +Changed: +* Update libffi to latest master. + +Deprecated: +* Overwriting struct layouts is now warned and will be disallowed in ffi-2.0. #734, #735 + + +1.11.3 / 2019-11-25 +------------------- + +Removed: +* Remove support for tainted objects which cause deprecation warnings in ruby-2.7. #730 + + +1.11.2 / 2019-11-11 +------------------- + +Added: +* Add DragonFlyBSD as a platform. #724 + +Changed: +* Sort all types.conf files, so that files and changes are easier to compare. +* Regenerated type conf for freebsd12 and x86_64-linux targets. #722 +* Remove MACOSX_DEPLOYMENT_TARGET that was targeting very old version 10.4. #647 +* Fix library name mangling for non glibc Linux/UNIX. #727 +* Fix compiler warnings raised by ruby-2.7 +* Update libffi to latest master. + + +1.11.1 / 2019-05-20 +------------------- + +Changed: +* Raise required ruby version to >=2.0. #699, #700 +* Fix a possible linker error on ruby < 2.3 on Linux. + + +1.11.0 / 2019-05-17 +------------------- +This version was yanked on 2019-05-20 to fix an install issue on ruby-1.9.3. #700 + +Added: +* Add ability to disable or force use of system libffi. #669 + Use like `gem inst ffi -- --enable-system-libffi` . +* Add ability to call FFI callbacks from outside of FFI call frame. #584 +* Add proper documentation to FFI::Generator and ::Task +* Add gemspec metadata. #696, #698 + +Changed: +* Fix stdcall on Win32. #649, #669 +* Fix load paths for FFI::Generator::Task +* Fix FFI::Pointer#read_string(0) to return a binary String. #692 +* Fix benchmark suite so that it runs on ruby-2.x +* Move FFI::Platform::CPU from C to Ruby. #663 +* Move FFI::StructByReference to Ruby. #681 +* Move FFI::DataConverter to Ruby (#661) +* Various cleanups and improvements of specs and benchmarks + +Removed: +* Remove ruby-1.8 and 1.9 compatibility code. #683 +* Remove unused spec files. #684 + + +1.10.0 / 2019-01-06 +------------------- + +Added: +* Add /opt/local/lib/ to ffi's fallback library search path. #638 +* Add binary gem support for ruby-2.6 on Windows +* Add FreeBSD on AArch64 and ARM support. #644 +* Add FFI::LastError.winapi_error on Windows native or Cygwin. #633 + +Changed: +* Update to rake-compiler-dock-0.7.0 +* Use 64-bit inodes on FreeBSD >= 12. #644 +* Switch time_t and suseconds_t types to long on FreeBSD. #627 +* Make register_t long_long on 64-bit FreeBSD. #644 +* Fix Pointer#write_array_of_type #637 + +Removed: +* Drop binary gem support for ruby-2.0 and 2.1 on Windows + + +1.9.25 / 2018-06-03 +------------------- + +Changed: +* Revert closures via libffi. + This re-adds ClosurePool and fixes compat with SELinux enabled systems. #621 + + +1.9.24 / 2018-06-02 +------------------- + +Security Note: + +This update addresses vulnerability CVE-2018-1000201: DLL loading issue which can be hijacked on Windows OS, when a Symbol is used as DLL name instead of a String. Found by Matthew Bush. + +Added: +* Added a CHANGELOG file +* Add mips64(eb) support, and mips r6 support. (#601) + +Changed: +* Update libffi to latest changes on master. +* Don't search in hardcoded /usr paths on Windows. +* Don't treat Symbol args different to Strings in ffi_lib. +* Make sure size_t is defined in Thread.c. Fixes #609 + + +1.9.23 / 2018-02-25 +------------------- + +Changed: +* Fix unnecessary rebuild of configure in darwin multi arch. Fixes #605 + + +1.9.22 / 2018-02-22 +------------------- + +Changed: +* Update libffi to latest changes on master. +* Update detection of system libffi to match new requirements. Fixes #617 +* Prefer bundled libffi over system libffi on Mac OS. +* Do closures via libffi. This removes ClosurePool and fixes compat with PaX. #540 +* Use a more deterministic gem packaging. +* Fix unnecessary update of autoconf files at gem install. + + +1.9.21 / 2018-02-06 +------------------- + +Added: +* Ruby-2.5 support by Windows binary gems. Fixes #598 +* Add missing win64 types. +* Added support for Bitmask. (#573) +* Add support for MSYS2 (#572) and Sparc64 Linux. (#574) + +Changed: +* Fix read_string to not throw an error on length 0. +* Don't use absolute paths for sh and env. Fixes usage on Adroid #528 +* Use Ruby implementation for `which` for better compat with Windows. Fixes #315 +* Fix compatibility with PPC64LE platform. (#577) +* Normalize sparc64 to sparcv9. (#575) + +Removed: +* Drop Ruby 1.8.7 support (#480) + + +1.9.18 / 2017-03-03 +------------------- + +Added: +* Add compatibility with Ruby-2.4. + +Changed: +* Add missing shlwapi.h include to fix Windows build. +* Avoid undefined behaviour of LoadLibrary() on Windows. #553 + + +1.9.17 / 2017-01-13 +------------------- diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/COPYING b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/COPYING new file mode 100644 index 00000000..76223189 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/COPYING @@ -0,0 +1,49 @@ +Copyright (c) 2008-2013, Ruby FFI project contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Ruby FFI project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +libffi, used by this project, is licensed under the MIT license: + +libffi - Copyright (c) 1996-2011 Anthony Green, Red Hat, Inc and others. +See source files for details. + +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/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Gemfile b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Gemfile new file mode 100644 index 00000000..49fb10cf --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Gemfile @@ -0,0 +1,21 @@ +source 'https://rubygems.org' + +group :development do + gem 'bigdecimal' # necessary on ruby-3.3+ + gem 'bundler', '>= 1.16', '< 3' + gem 'rake', '~> 13.0' + gem 'rake-compiler', '~> 1.1' + gem 'rake-compiler-dock', '~> 1.7.0' + gem 'rspec', '~> 3.0' +end + +group :doc do + gem 'kramdown' + gem 'yard', '~> 0.9' +end + +group :type_check do + if RUBY_VERSION >= "2.6" && %w[ ruby truffleruby ].include?(RUBY_ENGINE) + gem 'rbs', '~> 3.0' + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE new file mode 100644 index 00000000..20185fd4 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2008-2016, Ruby FFI project contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Ruby FFI project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE.SPECS b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE.SPECS new file mode 100644 index 00000000..5c9ffcee --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/LICENSE.SPECS @@ -0,0 +1,22 @@ +Copyright (c) 2008-2012 Ruby-FFI 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/bin/gems/ffi-1.17.1-x86_64-linux-gnu/README.md b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/README.md new file mode 100644 index 00000000..0605c819 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/README.md @@ -0,0 +1,137 @@ +# Ruby-FFI https://github.com/ffi/ffi/wiki + +## Description + +Ruby-FFI is a gem for programmatically loading dynamically-linked native +libraries, binding functions within them, and calling those functions +from Ruby code. Moreover, a Ruby-FFI extension works without changes +on CRuby (MRI), JRuby, Rubinius and TruffleRuby. [Discover why you should write your next extension +using Ruby-FFI](https://github.com/ffi/ffi/wiki/why-use-ffi). + +## Features + +* Intuitive DSL +* Supports all C native types +* C structs (also nested), enums and global variables +* Callbacks from C to Ruby +* Automatic garbage collection of native memory +* Usable in Ractor: [How-to-use-FFI-in-Ruby-Ractors](https://github.com/ffi/ffi/wiki/Ractors) + +## Synopsis + +```ruby +require 'ffi' + +module MyLib + extend FFI::Library + ffi_lib 'c' + attach_function :puts, [ :string ], :int +end + +MyLib.puts 'Hello, World using libc!' +``` + +For less minimalistic and more examples you may look at: + +* the `samples/` folder +* the examples on the [wiki](https://github.com/ffi/ffi/wiki) +* the projects using FFI listed on the wiki: https://github.com/ffi/ffi/wiki/projects-using-ffi + +## Requirements + +When installing the gem on CRuby (MRI), you will need: +* A C compiler (e.g., Xcode on macOS, `gcc` or `clang` on everything else) +Optionally (speeds up installation): +* The `libffi` library and development headers - this is commonly in the `libffi-dev` or `libffi-devel` packages + +The ffi gem comes with a builtin libffi version, which is used, when the system libffi library is not available or too old. +Use of the system libffi can be enforced by: +``` +gem install ffi -- --enable-system-libffi # to install the gem manually +bundle config build.ffi --enable-system-libffi # for bundle install +``` +or prevented by `--disable-system-libffi`. + +On Linux systems running with [PaX](https://en.wikipedia.org/wiki/PaX) (Gentoo, Alpine, etc.), FFI may trigger `mprotect` errors. You may need to disable [mprotect](https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options#Restrict_mprotect.28.29) for ruby (`paxctl -m [/path/to/ruby]`) for the time being until a solution is found. + +On FreeBSD systems pkgconf must be installed for the gem to be able to compile using clang. Install either via packages `pkg install pkgconf` or from ports via `devel/pkgconf`. + +On JRuby and TruffleRuby, there are no requirements to install the FFI gem, and `require 'ffi'` works even without installing the gem (i.e., the gem is preinstalled on these implementations). + +## Installation + +From rubygems: + + [sudo] gem install ffi + +From a Gemfile using git or GitHub + + gem 'ffi', github: 'ffi/ffi', submodules: true + +or from the git repository on github: + + git clone git://github.com/ffi/ffi.git + cd ffi + git submodule update --init --recursive + bundle install + rake install + +### Install options: + +* `--enable-system-libffi` : Force usage of system libffi +* `--disable-system-libffi` : Force usage of builtin libffi +* `--enable-libffi-alloc` : Force closure allocation by libffi +* `--disable-libffi-alloc` : Force closure allocation by builtin method + +## License + +The ffi library is covered by the BSD license, also see the LICENSE file. +The specs are covered by the same license as [ruby/spec](https://github.com/ruby/spec), the MIT license. + +## Credits + +The following people have submitted code, bug reports, or otherwise contributed to the success of this project: + +* Alban Peignier +* Aman Gupta +* Andrea Fazzi +* Andreas Niederl +* Andrew Cholakian +* Antonio Terceiro +* Benoit Daloze +* Brian Candler +* Brian D. Burns +* Bryan Kearney +* Charlie Savage +* Chikanaga Tomoyuki +* Hongli Lai +* Ian MacLeod +* Jake Douglas +* Jean-Dominique Morani +* Jeremy Hinegardner +* Jesús García Sáez +* Joe Khoobyar +* Jurij Smakov +* KISHIMOTO, Makoto +* Kim Burgestrand +* Lars Kanis +* Luc Heinrich +* Luis Lavena +* Matijs van Zuijlen +* Matthew King +* Mike Dalessio +* NARUSE, Yui +* Park Heesob +* Shin Yee +* Stephen Bannasch +* Suraj N. Kurapati +* Sylvain Daubert +* Victor Costan +* beoran@gmail.com +* ctide +* emboss +* hobophobe +* meh +* postmodern +* wycats@gmail.com +* Wayne Meissner diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Rakefile b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Rakefile new file mode 100644 index 00000000..b0d9ebc9 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/Rakefile @@ -0,0 +1,206 @@ +require 'rbconfig' +require 'date' +require 'fileutils' +require 'yaml' +require 'rspec/core/rake_task' +require 'rubygems/package_task' +require 'rake/extensiontask' +require_relative "lib/ffi/version" +require_relative "rakelib/ffi_gem_helper" + +BUILD_DIR = "build" +BUILD_EXT_DIR = File.join(BUILD_DIR, "#{RbConfig::CONFIG['arch']}", 'ffi_c', RUBY_VERSION) + +gem_spec = Bundler.load_gemspec('ffi.gemspec') + +RSpec::Core::RakeTask.new(:spec) do |config| + config.rspec_opts = YAML.load_file 'spec/spec.opts' +end + +desc "Build all packages" +task :package => %w[ gem:java gem:native ] + +CLOBBER.include 'lib/ffi/types.conf' +CLOBBER.include 'pkg' +CLOBBER.include 'log' + +CLEAN.include 'build' +CLEAN.include 'conftest.dSYM' +CLEAN.include 'spec/ffi/fixtures/libtest.{dylib,so,dll}' +CLEAN.include 'spec/ffi/fixtures/*.o' +CLEAN.include 'spec/ffi/embed-test/ext/*.{o,def}' +CLEAN.include 'spec/ffi/embed-test/ext/Makefile' +CLEAN.include "pkg/ffi-*-*/" +CLEAN.include 'lib/{2,3}.*' + +# clean all shipped files, that are not in git +CLEAN.include( + gem_spec.files - + `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0").map { |f| File.join("ext/ffi_c/libffi", f) } - + `git ls-files -z`.split("\x0") +) + +task :distclean => :clobber + +desc "Test the extension" +task :test => [ :spec ] + + +namespace :bench do + ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000 + bench_files = Dir["bench/bench_*.rb"].sort.reject { |f| f == "bench/bench_helper.rb" } + bench_files.each do |bench| + task File.basename(bench, ".rb")[6..-1] => :compile do + sh %{#{Gem.ruby} #{bench} #{ITER}} + end + end + task :all => :compile do + bench_files.each do |bench| + sh %{#{Gem.ruby} #{bench}} + end + end +end + +task 'spec:run' => :compile +task 'spec:specdoc' => :compile + +task :default => :spec + +namespace 'java' do + + java_gem_spec = gem_spec.dup.tap do |s| + s.files.reject! { |f| File.fnmatch?("ext/*", f) } + s.extensions = [] + s.platform = 'java' + end + + Gem::PackageTask.new(java_gem_spec) do |pkg| + pkg.need_zip = true + pkg.need_tar = true + pkg.package_dir = 'pkg' + end +end + +task 'gem:java' => 'java:gem' + +FfiGemHelper.install_tasks +# Register binary gems to be pushed to rubygems.org +Bundler::GemHelper.instance.cross_platforms = %w[ + x86-mingw32 + x64-mingw-ucrt + x64-mingw32 + x86-linux-gnu + x86-linux-musl + x86_64-linux-gnu + x86_64-linux-musl + arm-linux-gnu + arm-linux-musl + aarch64-linux-gnu + aarch64-linux-musl + x86_64-darwin + arm64-darwin +] + +if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx' + require 'rake/extensiontask' + Rake::ExtensionTask.new('ffi_c', gem_spec) do |ext| + ext.name = 'ffi_c' # indicate the name of the extension. + # ext.lib_dir = BUILD_DIR # put binaries into this folder. + ext.tmp_dir = BUILD_DIR # temporary folder used during compilation. + ext.cross_compile = true # enable cross compilation (requires cross compile toolchain) + ext.cross_platform = Bundler::GemHelper.instance.cross_platforms + ext.cross_compiling do |spec| + spec.files.reject! { |path| File.fnmatch?('ext/*', path) } + end + # Enable debug info for 'rake compile' but not for 'gem install' + ext.config_options << "--enable-debug" + + end +else + task :compile do + STDERR.puts "Nothing to compile on #{RUBY_ENGINE}" + end +end + + +namespace "gem" do + task 'prepare' do + require 'rake_compiler_dock' + sh "bundle package --all" + end + + Bundler::GemHelper.instance.cross_platforms.each do |plat| + desc "Build all native binary gems in parallel" + multitask 'native' => plat + + desc "Build the native gem for #{plat}" + task plat => ['prepare', 'build'] do + RakeCompilerDock.sh <<-EOT, platform: plat + sudo apt-get update && sudo apt-get install -y libltdl-dev && + bundle --local && + rake native:#{plat} pkg/#{gem_spec.full_name}-#{plat}.gem MAKE='nice make -j`nproc`' RUBY_CC_VERSION=${RUBY_CC_VERSION/:2.4.0/} + EOT + end + end +end + +directory "ext/ffi_c/libffi" +file "ext/ffi_c/libffi/autogen.sh" => "ext/ffi_c/libffi" do + warn "Downloading libffi ..." + sh "git submodule update --init --recursive" +end +task :libffi => "ext/ffi_c/libffi/autogen.sh" + +LIBFFI_GIT_FILES = `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0") + +# Generate files which are in the gemspec but not in libffi's git repo by running autogen.sh +gem_spec.files.select do |f| + f =~ /ext\/ffi_c\/libffi\/(.*)/ && !LIBFFI_GIT_FILES.include?($1) +end.each do |f| + file f => "ext/ffi_c/libffi/autogen.sh" do + chdir "ext/ffi_c/libffi" do + sh "sh ./autogen.sh" + end + touch f + if gem_spec.files != Gem::Specification.load('./ffi.gemspec').files + warn "gemspec files have changed -> Please restart rake!" + exit 1 + end + end +end + +# Make sure we have all gemspec files before packaging +task :build => gem_spec.files +task :gem => :build + + +require_relative "lib/ffi/platform" +types_conf = File.expand_path(File.join(FFI::Platform::CONF_DIR, 'types.conf')) +logfile = File.join(File.dirname(__FILE__), 'types_log') + +task types_conf do |task| + require 'fileutils' + require_relative "lib/ffi/tools/types_generator" + options = {} + FileUtils.mkdir_p(File.dirname(task.name), mode: 0755 ) + File.open(task.name, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f| + f.puts FFI::TypesGenerator.generate(options) + end + File.open(logfile, 'w') do |log| + log.puts(types_conf) + end +end + +desc "Create or update type information for platform #{FFI::Platform::NAME}" +task :types_conf => types_conf + +begin + require 'yard' + + namespace :doc do + YARD::Rake::YardocTask.new do |yard| + end + end +rescue LoadError + warn "[warn] YARD unavailable" +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/ffi.gemspec b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/ffi.gemspec new file mode 100644 index 00000000..07d549f7 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/ffi.gemspec @@ -0,0 +1,42 @@ +require File.expand_path("../lib/#{File.basename(__FILE__, '.gemspec')}/version", __FILE__) + +Gem::Specification.new do |s| + s.name = 'ffi' + s.version = FFI::VERSION + s.author = 'Wayne Meissner' + s.email = 'wmeissner@gmail.com' + s.homepage = 'https://github.com/ffi/ffi/wiki' + s.summary = 'Ruby FFI' + s.description = 'Ruby FFI library' + if s.respond_to?(:metadata) + s.metadata['bug_tracker_uri'] = 'https://github.com/ffi/ffi/issues' + s.metadata['changelog_uri'] = 'https://github.com/ffi/ffi/blob/master/CHANGELOG.md' + s.metadata['documentation_uri'] = 'https://github.com/ffi/ffi/wiki' + s.metadata['wiki_uri'] = 'https://github.com/ffi/ffi/wiki' + s.metadata['source_code_uri'] = 'https://github.com/ffi/ffi/' + s.metadata['mailing_list_uri'] = 'http://groups.google.com/group/ruby-ffi' + end + s.files = `git ls-files -z`.split("\x0").reject do |f| + f =~ /^(\.|bench|gen|libtest|nbproject|spec)/ + end + + # Add libffi git files + lfs = `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0") + # Add autoconf generated files of libffi + lfs += %w[ compile configure config.guess config.sub install-sh ltmain.sh missing fficonfig.h.in ] + # Add automake generated files of libffi + lfs += `git --git-dir ext/ffi_c/libffi/.git ls-files -z *.am */*.am`.gsub(".am\0", ".in\0").split("\x0") + s.files += lfs.map do |f| + File.join("ext/ffi_c/libffi", f) + end + + s.extensions << 'ext/ffi_c/extconf.rb' + s.rdoc_options = %w[--exclude=ext/ffi_c/.*\.o$ --exclude=ffi_c\.(bundle|so)$] + s.license = 'BSD-3-Clause' + s.require_paths << 'ext/ffi_c' + s.required_ruby_version = '>= 2.5' + s.add_development_dependency 'rake', '~> 13.0' + s.add_development_dependency 'rake-compiler', '~> 1.1' + s.add_development_dependency 'rake-compiler-dock', '~> 1.0' + s.add_development_dependency 'rspec', '~> 2.14.1' +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.5/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.5/ffi_c.so new file mode 100755 index 00000000..d5cfd086 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.5/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.6/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.6/ffi_c.so new file mode 100755 index 00000000..1641e848 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.6/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.7/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.7/ffi_c.so new file mode 100755 index 00000000..37eba059 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/2.7/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.0/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.0/ffi_c.so new file mode 100755 index 00000000..1238a727 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.0/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.1/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.1/ffi_c.so new file mode 100755 index 00000000..7c114525 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.1/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.2/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.2/ffi_c.so new file mode 100755 index 00000000..125aa3a5 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.2/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.3/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.3/ffi_c.so new file mode 100755 index 00000000..10b61119 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.3/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.4/ffi_c.so b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.4/ffi_c.so new file mode 100755 index 00000000..71d44cd9 Binary files /dev/null and b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/3.4/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi.rb new file mode 100644 index 00000000..3fb20a8c --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi.rb @@ -0,0 +1,27 @@ +if RUBY_ENGINE == 'ruby' + begin + require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c' + rescue Exception + require 'ffi_c' + end + + require 'ffi/ffi' + +elsif RUBY_ENGINE == 'jruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [9, 2, 20]) >= 0 + JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService") + require 'ffi/ffi' + +elsif RUBY_ENGINE == 'truffleruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0 + require 'truffleruby/ffi_backend' + require 'ffi/ffi' + +else + # Remove the ffi gem dir from the load path, then reload the internal ffi implementation + $LOAD_PATH.delete(File.dirname(__FILE__)) + $LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi')) + unless $LOADED_FEATURES.nil? + $LOADED_FEATURES.delete(__FILE__) + $LOADED_FEATURES.delete('ffi.rb') + end + require 'ffi.rb' +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/abstract_memory.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/abstract_memory.rb new file mode 100644 index 00000000..e0aa2216 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/abstract_memory.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2020 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + + +module FFI + class AbstractMemory + LONG_MAX = FFI::Pointer.new(1).size + private_constant :LONG_MAX + + # Return +true+ if +self+ has a size limit. + # + # @return [Boolean] + def size_limit? + size != LONG_MAX + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/autopointer.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/autopointer.rb new file mode 100644 index 00000000..d93bc45a --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/autopointer.rb @@ -0,0 +1,180 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008 Mike Dalessio +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + class AutoPointer < Pointer + extend DataConverter + + # @overload initialize(pointer, method) + # @param pointer [Pointer] + # @param method [Method] + # @return [self] + # The passed Method will be invoked at GC time. + # @overload initialize(pointer, proc) + # @param pointer [Pointer] + # @return [self] + # The passed Proc will be invoked at GC time (SEE WARNING BELOW!) + # @note WARNING: passing a proc _may_ cause your pointer to never be + # GC'd, unless you're careful to avoid trapping a reference to the + # pointer in the proc. See the test specs for examples. + # @overload initialize(pointer) + # @param pointer [Pointer] + # @return [self] + # The pointer's release() class method will be invoked at GC time. + # + # @note The safest, and therefore preferred, calling + # idiom is to pass a Method as the second parameter. Example usage: + # + # class PointerHelper + # def self.release(pointer) + # ... + # end + # end + # + # p = AutoPointer.new(other_pointer, PointerHelper.method(:release)) + # + # The above code will cause PointerHelper#release to be invoked at GC time. + # + # @note + # The last calling idiom (only one parameter) is generally only + # going to be useful if you subclass {AutoPointer}, and override + # #release, which by default does nothing. + def initialize(ptr, proc=nil) + raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) || + ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer) + super(ptr.type_size, ptr) + + @releaser = if proc + if not proc.respond_to?(:call) + raise RuntimeError.new("proc must be callable") + end + Releaser.new(ptr, proc) + + else + if not self.class.respond_to?(:release, true) + raise RuntimeError.new("no release method defined") + end + Releaser.new(ptr, self.class.method(:release)) + end + + ObjectSpace.define_finalizer(self, @releaser) + self + end + + # @return [nil] + # Free the pointer. + def free + @releaser.free + end + + # @param [Boolean] autorelease + # @return [Boolean] +autorelease+ + # Set +autorelease+ property. See {Pointer Autorelease section at Pointer}. + def autorelease=(autorelease) + raise FrozenError.new("can't modify frozen #{self.class}") if frozen? + @releaser.autorelease=(autorelease) + end + + # @return [Boolean] +autorelease+ + # Get +autorelease+ property. See {Pointer Autorelease section at Pointer}. + def autorelease? + @releaser.autorelease + end + + # @abstract Base class for {AutoPointer}'s releasers. + # + # All subclasses of Releaser should define a +#release(ptr)+ method. + # A releaser is an object in charge of release an {AutoPointer}. + class Releaser + attr_accessor :autorelease + + # @param [Pointer] ptr + # @param [#call] proc + # @return [nil] + # A new instance of Releaser. + def initialize(ptr, proc) + @ptr = ptr + @proc = proc + @autorelease = true + end + + # @return [nil] + # Free pointer. + def free + if @ptr + release(@ptr) + @autorelease = false + @ptr = nil + @proc = nil + end + end + + # @param args + # Release pointer if +autorelease+ is set. + def call(*args) + release(@ptr) if @autorelease && @ptr + end + + # Release +ptr+ by using Proc or Method defined at +ptr+ + # {AutoPointer#initialize initialization}. + # + # @param [Pointer] ptr + # @return [nil] + def release(ptr) + @proc.call(ptr) + end + end + + # Return native type of AutoPointer. + # + # Override {DataConverter#native_type}. + # @return [Type::POINTER] + # @raise {RuntimeError} if class does not implement a +#release+ method + def self.native_type + if not self.respond_to?(:release, true) + raise RuntimeError.new("no release method defined for #{self.inspect}") + end + Type::POINTER + end + + # Create a new AutoPointer. + # + # Override {DataConverter#from_native}. + # @overload self.from_native(ptr, ctx) + # @param [Pointer] ptr + # @param ctx not used. Please set +nil+. + # @return [AutoPointer] + def self.from_native(val, ctx) + self.new(val) + end + end + +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/buffer.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/buffer.rb new file mode 100644 index 00000000..449e45b0 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/buffer.rb @@ -0,0 +1,4 @@ +# +# All the code from this file is now implemented in C. This file remains +# to satisfy any leftover require 'ffi/buffer' in user code +# diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/callback.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/callback.rb new file mode 100644 index 00000000..32d52f72 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/callback.rb @@ -0,0 +1,4 @@ +# +# All the code from this file is now implemented in C. This file remains +# to satisfy any leftover require 'ffi/callback' in user code +# diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/compat.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/compat.rb new file mode 100644 index 00000000..75690134 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/compat.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2023-2023 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + if defined?(Ractor.make_shareable) + # This is for FFI internal use only. + def self.make_shareable(obj) + Ractor.make_shareable(obj) + end + else + def self.make_shareable(obj) + obj.freeze + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/data_converter.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/data_converter.rb new file mode 100644 index 00000000..7852e7ee --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/data_converter.rb @@ -0,0 +1,67 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # This module is used to extend somes classes and give then a common API. + # + # Most of methods defined here must be overridden. + module DataConverter + # Get native type. + # + # @overload native_type(type) + # @param [String, Symbol, Type] type + # @return [Type] + # Get native type from +type+. + # + # @overload native_type + # @raise {NotImplementedError} This method must be overridden. + def native_type(type = nil) + if type + @native_type = FFI.find_type(type) + else + native_type = @native_type + unless native_type + raise NotImplementedError, 'native_type method not overridden and no native_type set' + end + native_type + end + end + + # Convert to a native type. + def to_native(value, ctx) + value + end + + # Convert from a native type. + def from_native(value, ctx) + value + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/dynamic_library.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/dynamic_library.rb new file mode 100644 index 00000000..468ce044 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/dynamic_library.rb @@ -0,0 +1,118 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + class DynamicLibrary + SEARCH_PATH = [] + + # The following search paths are tried, if the library could not be loaded in the first attempt. + # They are only executed on Macos in the following order: + if FFI::Platform.mac? + + # 1. Try library paths possibly defined in LD_LIBRARY_PATH DYLD_LIBRARY_PATH first. + # This is because dlopen doesn't respect LD_LIBRARY_PATH and DYLD_LIBRARY_PATH is deleted by SIP-protected binaries. + # See here for details: https://github.com/ffi/ffi/issues/923#issuecomment-1872565313 + %w[LD_LIBRARY_PATH DYLD_LIBRARY_PATH].each do |custom_path| + SEARCH_PATH.concat ENV.fetch(custom_path,"").split(File::PATH_SEPARATOR) + end + + # 2. Then on macos/arm64 try /opt/homebrew/lib, since this is a typical standard directory. + # FFI is often used together with homebrew, so that we hardcode the path for arm64 here. + if FFI::Platform::ARCH == 'aarch64' + SEARCH_PATH << '/opt/homebrew/lib' + end + + # 3. Then try typical system directories starting with the /local/ directory first. + # + # /usr/local/lib is used by homebrow on x86_64. + # /opt/local/lib is used by MacPorts and Fink. + # /usr/lib is there, because it was always there. + SEARCH_PATH.concat %w[/opt/local/lib /usr/local/lib /usr/lib] + end + + # On Linux the library lookup paths are usually defined through /etc/ld.so.conf, which can be changed at will with root permissions. + # Also LD_LIBRARY_PATH is respected by the dynamic loader, so that there's usually no need and no advantage to do a fallback handling. + # + # Windows has it's own library lookup logic, very different to what we do here. + # See: https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers#user-content-dll-loading + + FFI.make_shareable(SEARCH_PATH) + SEARCH_PATH_MESSAGE = "Searched in #{ SEARCH_PATH.map{|a| ', ' + a}.join }".freeze + + def self.load_library(name, flags) + if name == FFI::CURRENT_PROCESS + FFI::DynamicLibrary.open(nil, RTLD_LAZY | RTLD_LOCAL) + else + flags ||= RTLD_LAZY | RTLD_LOCAL + + libnames = (name.is_a?(::Array) ? name : [name]) + libnames = libnames.map(&:to_s).map { |n| [n, FFI.map_library_name(n)].uniq }.flatten.compact + errors = [] + + libnames.each do |libname| + lib = try_load(libname, flags, errors) + return lib if lib + + unless libname.start_with?("/") + SEARCH_PATH.each do |prefix| + path = "#{prefix}/#{libname}" + if File.exist?(path) + lib = try_load(path, flags, errors) + return lib if lib + end + end + end + end + + raise LoadError, [*errors, SEARCH_PATH_MESSAGE].join(".\n") + end + end + private_class_method :load_library + + def self.try_load(libname, flags, errors) + begin + lib = FFI::DynamicLibrary.open(libname, flags) + return lib if lib + + # LoadError for C ext & JRuby, RuntimeError for TruffleRuby + rescue LoadError, RuntimeError => ex + if ex.message =~ /(([^ \t()])+\.so([^ \t:()])*):([ \t])*(invalid ELF header|file too short|invalid file format)/ + if File.binread($1) =~ /(?:GROUP|INPUT) *\( *([^ \)]+)/ + return try_load($1, flags, errors) + end + end + + errors << ex + nil + end + end + private_class_method :try_load + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/enum.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/enum.rb new file mode 100644 index 00000000..af783316 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/enum.rb @@ -0,0 +1,302 @@ +# +# Copyright (C) 2009, 2010 Wayne Meissner +# Copyright (C) 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + # An instance of this class permits to manage {Enum}s. In fact, Enums is a collection of {Enum}s. + class Enums + + def initialize + @all_enums = Array.new + @tagged_enums = Hash.new + @symbol_map = Hash.new + end + + # @param [Enum] enum + # Add an {Enum} to the collection. + def <<(enum) + @all_enums << enum + @tagged_enums[enum.tag] = enum unless enum.tag.nil? + @symbol_map.merge!(enum.symbol_map) + end + + # @param query enum tag or part of an enum name + # @return [Enum] + # Find a {Enum} in collection. + def find(query) + if @tagged_enums.has_key?(query) + @tagged_enums[query] + else + @all_enums.detect { |enum| enum.symbols.include?(query) } + end + end + + # @param symbol a symbol to find in merge symbol maps of all enums. + # @return a symbol + def __map_symbol(symbol) + @symbol_map[symbol] + end + + end + + # Represents a C enum. + # + # For a C enum: + # enum fruits { + # apple, + # banana, + # orange, + # pineapple + # }; + # are defined this vocabulary: + # * a _symbol_ is a word from the enumeration (ie. _apple_, by example); + # * a _value_ is the value of a symbol in the enumeration (by example, apple has value _0_ and banana _1_). + class Enum + include DataConverter + + attr_reader :tag + attr_reader :native_type + + # @overload initialize(info, tag=nil) + # @param [nil, Enumerable] info + # @param [nil, Symbol] tag enum tag + # @overload initialize(native_type, info, tag=nil) + # @param [FFI::Type] native_type Native type for new Enum + # @param [nil, Enumerable] info symbols and values for new Enum + # @param [nil, Symbol] tag name of new Enum + def initialize(*args) + @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT + info, @tag = *args + @kv_map = Hash.new + unless info.nil? + last_cst = nil + value = 0 + info.each do |i| + case i + when Symbol + raise ArgumentError, "duplicate enum key" if @kv_map.has_key?(i) + @kv_map[i] = value + last_cst = i + value += 1 + when Integer + @kv_map[last_cst] = i + value = i+1 + end + end + end + @vk_map = @kv_map.invert + end + + # @return [Array] enum symbol names + def symbols + @kv_map.keys + end + + # Get a symbol or a value from the enum. + # @overload [](query) + # Get enum value from symbol. + # @param [Symbol] query + # @return [Integer] + # @overload [](query) + # Get enum symbol from value. + # @param [Integer] query + # @return [Symbol] + def [](query) + case query + when Symbol + @kv_map[query] + when Integer + @vk_map[query] + end + end + alias find [] + + # Get the symbol map. + # @return [Hash] + def symbol_map + @kv_map + end + + alias to_h symbol_map + alias to_hash symbol_map + + # @param [Symbol, Integer, #to_int] val + # @param ctx unused + # @return [Integer] value of a enum symbol + def to_native(val, ctx) + @kv_map[val] || if val.is_a?(Integer) + val + elsif val.respond_to?(:to_int) + val.to_int + else + raise ArgumentError, "invalid enum value, #{val.inspect}" + end + end + + # @param val + # @return symbol name if it exists for +val+. + def from_native(val, ctx) + @vk_map[val] || val + end + end + + # Represents a C enum whose values are power of 2 + # + # @example + # enum { + # red = (1<<0), + # green = (1<<1), + # blue = (1<<2) + # } + # + # Contrary to classical enums, bitmask values are usually combined + # when used. + class Bitmask < Enum + + # @overload initialize(info, tag=nil) + # @param [nil, Enumerable] info symbols and bit rank for new Bitmask + # @param [nil, Symbol] tag name of new Bitmask + # @overload initialize(native_type, info, tag=nil) + # @param [FFI::Type] native_type Native type for new Bitmask + # @param [nil, Enumerable] info symbols and bit rank for new Bitmask + # @param [nil, Symbol] tag name of new Bitmask + def initialize(*args) + @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT + @signed = [Type::INT8, Type::INT16, Type::INT32, Type::INT64].include?(@native_type) + info, @tag = *args + @kv_map = Hash.new + unless info.nil? + last_cst = nil + value = 0 + info.each do |i| + case i + when Symbol + raise ArgumentError, "duplicate bitmask key" if @kv_map.has_key?(i) + @kv_map[i] = 1 << value + last_cst = i + value += 1 + when Integer + raise ArgumentError, "bitmask index should be positive" if i<0 + @kv_map[last_cst] = 1 << i + value = i+1 + end + end + end + @vk_map = @kv_map.invert + end + + # Get a symbol list or a value from the bitmask + # @overload [](*query) + # Get bitmask value from symbol list + # @param [Symbol] query + # @return [Integer] + # @overload [](query) + # Get bitmask value from symbol array + # @param [Array] query + # @return [Integer] + # @overload [](*query) + # Get a list of bitmask symbols corresponding to + # the or reduction of a list of integer + # @param [Integer] query + # @return [Array] + # @overload [](query) + # Get a list of bitmask symbols corresponding to + # the or reduction of a list of integer + # @param [Array] query + # @return [Array] + def [](*query) + flat_query = query.flatten + raise ArgumentError, "query should be homogeneous, #{query.inspect}" unless flat_query.all? { |o| o.is_a?(Symbol) } || flat_query.all? { |o| o.is_a?(Integer) || o.respond_to?(:to_int) } + case flat_query[0] + when Symbol + flat_query.inject(0) do |val, o| + v = @kv_map[o] + if v then val | v else val end + end + when Integer, ->(o) { o.respond_to?(:to_int) } + val = flat_query.inject(0) { |mask, o| mask |= o.to_int } + @kv_map.select { |_, v| v & val != 0 }.keys + end + end + + # Get the native value of a bitmask + # @overload to_native(query, ctx) + # @param [Symbol, Integer, #to_int] query + # @param ctx unused + # @return [Integer] value of a bitmask + # @overload to_native(query, ctx) + # @param [Array] query + # @param ctx unused + # @return [Integer] value of a bitmask + def to_native(query, ctx) + return 0 if query.nil? + flat_query = [query].flatten + res = flat_query.inject(0) do |val, o| + case o + when Symbol + v = @kv_map[o] + raise ArgumentError, "invalid bitmask value, #{o.inspect}" unless v + val | v + when Integer + val | o + when ->(obj) { obj.respond_to?(:to_int) } + val | o.to_int + else + raise ArgumentError, "invalid bitmask value, #{o.inspect}" + end + end + # Take two's complement of positive values bigger than the max value + # for the type when native type is signed. + if @signed && res >= (1 << (@native_type.size * 8 - 1)) + res = -(-res & ((1 << (@native_type.size * 8)) - 1)) + end + res + end + + # @param [Integer] val + # @param ctx unused + # @return [Array] list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant + def from_native(val, ctx) + flags = @kv_map.select { |_, v| v & val != 0 } + list = flags.keys + # force an unsigned value of the correct size + val &= (1 << (@native_type.size * 8)) - 1 if @signed + # If there are unmatch flags, + # return them in an integer, + # else information can be lost. + # Similar to Enum behavior. + remainder = val ^ flags.values.reduce(0, :|) + list.push remainder unless remainder == 0 + return list + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/errno.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/errno.rb new file mode 100644 index 00000000..de82d891 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/errno.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # @return (see FFI::LastError.error) + # @see FFI::LastError.error + def self.errno + FFI::LastError.error + end + # @param error (see FFI::LastError.error=) + # @return (see FFI::LastError.error=) + # @see FFI::LastError.error= + def self.errno=(error) + FFI::LastError.error = error + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/ffi.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/ffi.rb new file mode 100644 index 00000000..47822705 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/ffi.rb @@ -0,0 +1,109 @@ +# +# Copyright (C) 2008-2010 JRuby project +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'ffi/compat' +require 'ffi/platform' +require 'ffi/data_converter' +require 'ffi/types' +require 'ffi/library_path' +require 'ffi/library' +require 'ffi/errno' +require 'ffi/abstract_memory' +require 'ffi/pointer' +require 'ffi/memorypointer' +require 'ffi/struct' +require 'ffi/union' +require 'ffi/managedstruct' +require 'ffi/callback' +require 'ffi/io' +require 'ffi/autopointer' +require 'ffi/variadic' +require 'ffi/enum' +require 'ffi/version' +require 'ffi/function' + +module FFI + module ModernForkTracking + def _fork + pid = super + if pid == 0 + FFI._async_cb_dispatcher_atfork_child + end + pid + end + end + + module LegacyForkTracking + module KernelExt + def fork + if block_given? + super do + FFI._async_cb_dispatcher_atfork_child + yield + end + else + pid = super + FFI._async_cb_dispatcher_atfork_child if pid.nil? + pid + end + end + end + + module KernelExtPrivate + include KernelExt + private :fork + end + + module IOExt + def popen(*args) + return super unless args[0] == '-' + + super(*args) do |pipe| + FFI._async_cb_dispatcher_atfork_child if pipe.nil? + yield pipe + end + end + ruby2_keywords :popen if respond_to?(:ruby2_keywords) + end + end + + if Process.respond_to?(:_fork) + # The nice Ruby 3.1+ way of doing things + ::Process.singleton_class.prepend(ModernForkTracking) + elsif Process.respond_to?(:fork) + # Barf. Old CRuby. + # Most of the inspiration for how to do this was stolen from ActiveSupport. + ::Object.prepend(LegacyForkTracking::KernelExtPrivate) + ::Object.singleton_class.prepend(LegacyForkTracking::KernelExt) + ::Kernel.prepend(LegacyForkTracking::KernelExtPrivate) + ::Kernel.singleton_class.prepend(LegacyForkTracking::KernelExt) + ::IO.singleton_class.prepend(LegacyForkTracking::IOExt) + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/function.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/function.rb new file mode 100644 index 00000000..eb2ae00c --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/function.rb @@ -0,0 +1,71 @@ +# +# Copyright (C) 2008-2010 JRuby project +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + class Function + # Only MRI allows function type queries + if private_method_defined?(:type) + # Retrieve the return type of the function + # + # This method returns FFI type returned by the function. + # + # @return [FFI::Type] + def return_type + type.return_type + end + + # Retrieve Array of parameter types + # + # This method returns an Array of FFI types accepted as function parameters. + # + # @return [Array] + def param_types + type.param_types + end + end + + # Stash the Function in a module variable so it can be inspected by attached_functions. + # On CRuby it also ensures that it does not get garbage collected. + module RegisterAttach + def attach(mod, name) + funcs = mod.instance_variable_defined?("@ffi_functions") && mod.instance_variable_get("@ffi_functions") + unless funcs + funcs = {} + mod.instance_variable_set("@ffi_functions", funcs) + end + funcs[name.to_sym] = self + # Jump to the native attach method of CRuby, JRuby or Tuffleruby + super + end + end + private_constant :RegisterAttach + prepend RegisterAttach + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/io.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/io.rb new file mode 100644 index 00000000..7fb28574 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/io.rb @@ -0,0 +1,62 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + + # This module implements a couple of class methods to play with IO. + module IO + # @param [Integer] fd file decriptor + # @param [String] mode mode string + # @return [::IO] + # Synonym for IO::for_fd. + def self.for_fd(fd, mode = "r") + ::IO.for_fd(fd, mode) + end + + # @param [#read] io io to read from + # @param [AbstractMemory] buf destination for data read from +io+ + # @param [nil, Integer] len maximul number of bytes to read from +io+. If +nil+, + # read until end of file. + # @return [Integer] length really read, in bytes + # + # A version of IO#read that reads data from an IO and put then into a native buffer. + # + # This will be optimized at some future time to eliminate the double copy. + # + def self.native_read(io, buf, len) + tmp = io.read(len) + return -1 unless tmp + buf.put_bytes(0, tmp) + tmp.length + end + + end +end + diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library.rb new file mode 100644 index 00000000..e47da166 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library.rb @@ -0,0 +1,576 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +require 'ffi/dynamic_library' + +module FFI + CURRENT_PROCESS = USE_THIS_PROCESS_AS_LIBRARY = FFI.make_shareable(Object.new) + + # @param [String, FFI::LibraryPath] lib library name or LibraryPath object + # @return [String] library name formatted for current platform + # Transform a generic library name to a platform library name + # @example + # # Linux + # FFI.map_library_name 'c' # -> "libc.so.6" + # FFI.map_library_name 'jpeg' # -> "libjpeg.so" + # # Windows + # FFI.map_library_name 'c' # -> "msvcrt.dll" + # FFI.map_library_name 'jpeg' # -> "jpeg.dll" + def self.map_library_name(lib) + # Mangle the library name to reflect the native library naming conventions + LibraryPath.wrap(lib).to_s + end + + # Exception raised when a function is not found in libraries + class NotFoundError < LoadError + def initialize(function, *libraries) + super("Function '#{function}' not found in [#{libraries[0].nil? ? 'current process' : libraries.join(", ")}]") + end + end + + # This module is the base to use native functions. + # + # A basic usage may be: + # require 'ffi' + # + # module Hello + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function 'puts', [ :string ], :int + # end + # + # Hello.puts("Hello, World") + # + # + module Library + CURRENT_PROCESS = FFI::CURRENT_PROCESS + LIBC = FFI::Platform::LIBC + + # @param mod extended object + # @return [nil] + # @raise {RuntimeError} if +mod+ is not a Module + # Test if extended object is a Module. If not, raise RuntimeError. + def self.extended(mod) + raise RuntimeError.new("must only be extended by module") unless mod.kind_of?(::Module) + end + + + # @param [Array] names names of libraries to load + # @return [Array] + # @raise {LoadError} if a library cannot be opened + # Load native libraries. + def ffi_lib(*names) + raise LoadError.new("library names list must not be empty") if names.empty? + + lib_flags = defined?(@ffi_lib_flags) && @ffi_lib_flags + + @ffi_libs = names.map do |name| + FFI::DynamicLibrary.send(:load_library, name, lib_flags) + end + end + + # Set the calling convention for {#attach_function} and {#callback} + # + # @see http://en.wikipedia.org/wiki/Stdcall#stdcall + # @note +:stdcall+ is typically used for attaching Windows API functions + # + # @param [Symbol] convention one of +:default+, +:stdcall+ + # @return [Symbol] the new calling convention + def ffi_convention(convention = nil) + @ffi_convention ||= :default + @ffi_convention = convention if convention + @ffi_convention + end + + # @see #ffi_lib + # @return [Array] array of currently loaded FFI libraries + # @raise [LoadError] if no libraries have been loaded (using {#ffi_lib}) + # Get FFI libraries loaded using {#ffi_lib}. + def ffi_libraries + raise LoadError.new("no library specified") if !defined?(@ffi_libs) || @ffi_libs.empty? + @ffi_libs + end + + # Flags used in {#ffi_lib}. + # + # This map allows you to supply symbols to {#ffi_lib_flags} instead of + # the actual constants. + FlagsMap = { + :global => DynamicLibrary::RTLD_GLOBAL, + :local => DynamicLibrary::RTLD_LOCAL, + :lazy => DynamicLibrary::RTLD_LAZY, + :now => DynamicLibrary::RTLD_NOW + } + + # Sets library flags for {#ffi_lib}. + # + # @example + # ffi_lib_flags(:lazy, :local) # => 5 + # + # @param [Symbol, …] flags (see {FlagsMap}) + # @return [Integer] the new value + def ffi_lib_flags(*flags) + @ffi_lib_flags = flags.inject(0) { |result, f| result | FlagsMap[f] } + end + + + ## + # @overload attach_function(func, args, returns, options = {}) + # @example attach function without an explicit name + # module Foo + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function :malloc, [:size_t], :pointer + # end + # # now callable via Foo.malloc + # @overload attach_function(name, func, args, returns, options = {}) + # @example attach function with an explicit name + # module Bar + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function :c_malloc, :malloc, [:size_t], :pointer + # end + # # now callable via Bar.c_malloc + # + # Attach C function +func+ to this module. + # + # + # @param [#to_s] name name of ruby method to attach as + # @param [#to_s] func name of C function to attach + # @param [Array] args an array of types + # @param [Symbol] returns type of return value + # @option options [Boolean] :blocking (@blocking) set to true if the C function is a blocking call + # @option options [Symbol] :convention (:default) calling convention (see {#ffi_convention}) + # @option options [FFI::Enums] :enums + # @option options [Hash] :type_map + # + # @return [FFI::VariadicInvoker] + # + # @raise [FFI::NotFoundError] if +func+ cannot be found in the attached libraries (see {#ffi_lib}) + def attach_function(name, func, args, returns = nil, options = nil) + mname, a2, a3, a4, a5 = name, func, args, returns, options + cname, arg_types, ret_type, opts = (a4 && (a2.is_a?(String) || a2.is_a?(Symbol))) ? [ a2, a3, a4, a5 ] : [ mname.to_s, a2, a3, a4 ] + + # Convert :foo to the native type + arg_types = arg_types.map { |e| find_type(e) } + options = { + :convention => ffi_convention, + :type_map => defined?(@ffi_typedefs) ? @ffi_typedefs : nil, + :blocking => defined?(@blocking) && @blocking, + :enums => defined?(@ffi_enums) ? @ffi_enums : nil, + } + + @blocking = false + options.merge!(opts) if opts && opts.is_a?(Hash) + + # Try to locate the function in any of the libraries + invokers = [] + ffi_libraries.each do |lib| + if invokers.empty? + begin + function = nil + function_names(cname, arg_types).find do |fname| + function = lib.find_function(fname) + end + raise LoadError unless function + + invokers << if arg_types[-1] == FFI::NativeType::VARARGS + VariadicInvoker.new(function, arg_types, find_type(ret_type), options) + + else + Function.new(find_type(ret_type), arg_types, function, options) + end + + rescue LoadError + end + end + end + invoker = invokers.compact.shift + raise FFI::NotFoundError.new(cname.to_s, ffi_libraries.map { |lib| lib.name }) unless invoker + + invoker.attach(self, mname.to_s) + invoker + end + + # @param [#to_s] name function name + # @param [Array] arg_types function's argument types + # @return [Array] + # This function returns a list of possible names to lookup. + # @note Function names on windows may be decorated if they are using stdcall. See + # * http://en.wikipedia.org/wiki/Name_mangling#C_name_decoration_in_Microsoft_Windows + # * http://msdn.microsoft.com/en-us/library/zxk0tw93%28v=VS.100%29.aspx + # * http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL + # Note that decorated names can be overridden via def files. Also note that the + # windows api, although using, doesn't have decorated names. + def function_names(name, arg_types) + result = [name.to_s] + if ffi_convention == :stdcall + # Get the size of each parameter + size = arg_types.inject(0) do |mem, arg| + size = arg.size + # The size must be a multiple of 4 + size += (4 - size) % 4 + mem + size + end + + result << "_#{name.to_s}@#{size}" # win32 + result << "#{name.to_s}@#{size}" # win64 + end + result + end + + # @overload attach_variable(mname, cname, type) + # @param [#to_s] mname name of ruby method to attach as + # @param [#to_s] cname name of C variable to attach + # @param [DataConverter, Struct, Symbol, Type] type C variable's type + # @example + # module Bar + # extend FFI::Library + # ffi_lib 'my_lib' + # attach_variable :c_myvar, :myvar, :long + # end + # # now callable via Bar.c_myvar + # @overload attach_variable(cname, type) + # @param [#to_s] mname name of ruby method to attach as + # @param [DataConverter, Struct, Symbol, Type] type C variable's type + # @example + # module Bar + # extend FFI::Library + # ffi_lib 'my_lib' + # attach_variable :myvar, :long + # end + # # now callable via Bar.myvar + # @return [DynamicLibrary::Symbol] + # @raise {FFI::NotFoundError} if +cname+ cannot be found in libraries + # + # Attach C variable +cname+ to this module. + def attach_variable(mname, a1, a2 = nil) + cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ] + mname = mname.to_sym + address = nil + ffi_libraries.each do |lib| + begin + address = lib.find_variable(cname.to_s) + break unless address.nil? + rescue LoadError + end + end + + raise FFI::NotFoundError.new(cname, ffi_libraries) if address.nil? || address.null? + if type.is_a?(Class) && type < FFI::Struct + # If it is a global struct, just attach directly to the pointer + s = s = type.new(address) # Assigning twice to suppress unused variable warning + self.module_eval <<-code, __FILE__, __LINE__ + @ffi_gsvars = {} unless defined?(@ffi_gsvars) + @ffi_gsvars[#{mname.inspect}] = s + def self.#{mname} + @ffi_gsvars[#{mname.inspect}] + end + code + + else + sc = Class.new(FFI::Struct) + sc.layout :gvar, find_type(type) + s = sc.new(address) + # + # Attach to this module as mname/mname= + # + self.module_eval <<-code, __FILE__, __LINE__ + @ffi_gvars = {} unless defined?(@ffi_gvars) + @ffi_gvars[#{mname.inspect}] = s + def self.#{mname} + @ffi_gvars[#{mname.inspect}][:gvar] + end + def self.#{mname}=(value) + @ffi_gvars[#{mname.inspect}][:gvar] = value + end + code + + end + + address + end + + + # @overload callback(name, params, ret) + # @param name callback name to add to type map + # @param [Array] params array of parameters' types + # @param [DataConverter, Struct, Symbol, Type] ret callback return type + # @overload callback(params, ret) + # @param [Array] params array of parameters' types + # @param [DataConverter, Struct, Symbol, Type] ret callback return type + # @return [FFI::CallbackInfo] + def callback(*args) + raise ArgumentError, "wrong number of arguments" if args.length < 2 || args.length > 3 + name, params, ret = if args.length == 3 + args + else + [ nil, args[0], args[1] ] + end + + native_params = params.map { |e| find_type(e) } + raise ArgumentError, "callbacks cannot have variadic parameters" if native_params.include?(FFI::Type::VARARGS) + options = Hash.new + options[:convention] = ffi_convention + options[:enums] = @ffi_enums if defined?(@ffi_enums) + ret_type = find_type(ret) + if ret_type == Type::STRING + raise TypeError, ":string is not allowed as return type of callbacks" + end + cb = FFI::CallbackInfo.new(ret_type, native_params, options) + + # Add to the symbol -> type map (unless there was no name) + unless name.nil? + typedef cb, name + end + + cb + end + + # Register or get an already registered type definition. + # + # To register a new type definition, +old+ should be a {FFI::Type}. +add+ + # is in this case the type definition. + # + # If +old+ is a {DataConverter}, a {Type::Mapped} is returned. + # + # If +old+ is +:enum+ + # * and +add+ is an +Array+, a call to {#enum} is made with +add+ as single parameter; + # * in others cases, +info+ is used to create a named enum. + # + # If +old+ is a key for type map, #typedef get +old+ type definition. + # + # @param [DataConverter, Symbol, Type] old + # @param [Symbol] add + # @param [Symbol] info + # @return [FFI::Enum, FFI::Type] + def typedef(old, add, info=nil) + @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs) + + @ffi_typedefs[add] = if old.kind_of?(FFI::Type) + old + + elsif @ffi_typedefs.has_key?(old) + @ffi_typedefs[old] + + elsif old.is_a?(DataConverter) + FFI::Type::Mapped.new(old) + + elsif old == :enum + if add.kind_of?(Array) + self.enum(add) + else + self.enum(info, add) + end + + else + FFI.find_type(old) + end + end + + # @param [DataConverter, Type, Struct, Symbol] t type to find + # @return [Type] + # Find a type definition. + def find_type(t) + if t.kind_of?(Type) + t + + elsif defined?(@ffi_typedefs) && @ffi_typedefs.has_key?(t) + @ffi_typedefs[t] + + elsif t.is_a?(Class) && t < Struct + Type::POINTER + + elsif t.is_a?(DataConverter) + # Add a typedef so next time the converter is used, it hits the cache + typedef Type::Mapped.new(t), t + + end || FFI.find_type(t) + end + + private + # Generic enum builder + # @param [Class] klass can be one of FFI::Enum or FFI::Bitmask + # @param args (see #enum or #bitmask) + def generic_enum(klass, *args) + native_type = args.first.kind_of?(FFI::Type) ? args.shift : nil + name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array) + [ args[0], args[1] ] + elsif args[0].kind_of?(Array) + [ nil, args[0] ] + else + [ nil, args ] + end + @ffi_enums = FFI::Enums.new unless defined?(@ffi_enums) + @ffi_enums << (e = native_type ? klass.new(native_type, values, name) : klass.new(values, name)) + + # If called with a name, add a typedef alias + typedef(e, name) if name + e + end + + public + # @overload enum(name, values) + # Create a named enum. + # @example + # enum :foo, [:zero, :one, :two] # named enum + # @param [Symbol] name name for new enum + # @param [Array] values values for enum + # @overload enum(*args) + # Create an unnamed enum. + # @example + # enum :zero, :one, :two # unnamed enum + # @param args values for enum + # @overload enum(values) + # Create an unnamed enum. + # @example + # enum [:zero, :one, :two] # unnamed enum, equivalent to above example + # @param [Array] values values for enum + # @overload enum(native_type, name, values) + # Create a named enum and specify the native type. + # @example + # enum FFI::Type::UINT64, :foo, [:zero, :one, :two] # named enum + # @param [FFI::Type] native_type native type for new enum + # @param [Symbol] name name for new enum + # @param [Array] values values for enum + # @overload enum(native_type, *args) + # Create an unnamed enum and specify the native type. + # @example + # enum FFI::Type::UINT64, :zero, :one, :two # unnamed enum + # @param [FFI::Type] native_type native type for new enum + # @param args values for enum + # @overload enum(native_type, values) + # Create an unnamed enum and specify the native type. + # @example + # enum Type::UINT64, [:zero, :one, :two] # unnamed enum, equivalent to above example + # @param [FFI::Type] native_type native type for new enum + # @param [Array] values values for enum + # @return [FFI::Enum] + # Create a new {FFI::Enum}. + def enum(*args) + generic_enum(FFI::Enum, *args) + end + + # @overload bitmask(name, values) + # Create a named bitmask + # @example + # bitmask :foo, [:red, :green, :blue] # bits 0,1,2 are used + # bitmask :foo, [:red, :green, 5, :blue] # bits 0,5,6 are used + # @param [Symbol] name for new bitmask + # @param [Array] values for new bitmask + # @overload bitmask(*args) + # Create an unamed bitmask + # @example + # bm = bitmask :red, :green, :blue # bits 0,1,2 are used + # bm = bitmask :red, :green, 5, blue # bits 0,5,6 are used + # @param [Symbol, Integer] args values for new bitmask + # @overload bitmask(values) + # Create an unamed bitmask + # @example + # bm = bitmask [:red, :green, :blue] # bits 0,1,2 are used + # bm = bitmask [:red, :green, 5, blue] # bits 0,5,6 are used + # @param [Array] values for new bitmask + # @overload bitmask(native_type, name, values) + # Create a named enum and specify the native type. + # @example + # bitmask FFI::Type::UINT64, :foo, [:red, :green, :blue] + # @param [FFI::Type] native_type native type for new bitmask + # @param [Symbol] name for new bitmask + # @param [Array] values for new bitmask + # @overload bitmask(native_type, *args) + # @example + # bitmask FFI::Type::UINT64, :red, :green, :blue + # @param [FFI::Type] native_type native type for new bitmask + # @param [Symbol, Integer] args values for new bitmask + # @overload bitmask(native_type, values) + # Create a named enum and specify the native type. + # @example + # bitmask FFI::Type::UINT64, [:red, :green, :blue] + # @param [FFI::Type] native_type native type for new bitmask + # @param [Array] values for new bitmask + # @return [FFI::Bitmask] + # Create a new FFI::Bitmask + def bitmask(*args) + generic_enum(FFI::Bitmask, *args) + end + + # @param name + # @return [FFI::Enum] + # Find an enum by name. + def enum_type(name) + @ffi_enums.find(name) if defined?(@ffi_enums) + end + + # @param symbol + # @return [FFI::Enum] + # Find an enum by a symbol it contains. + def enum_value(symbol) + @ffi_enums.__map_symbol(symbol) + end + + # Retrieve all attached functions and their function signature + # + # This method returns a Hash of method names of attached functions connected by #attach_function and the corresponding function type. + # The function type responds to #return_type and #param_types which return the FFI types of the function signature. + # + # @return [Hash< Symbol => [FFI::Function, FFI::VariadicInvoker] >] + def attached_functions + @ffi_functions || {} + end + + # Retrieve all attached variables and their type + # + # This method returns a Hash of variable names and the corresponding type or variables connected by #attach_variable . + # + # @return [Hash< Symbol => ffi_type >] + def attached_variables + ( + (defined?(@ffi_gsvars) ? @ffi_gsvars : {}).map do |name, gvar| + [name, gvar.class] + end + + (defined?(@ffi_gvars) ? @ffi_gvars : {}).map do |name, gvar| + [name, gvar.layout[:gvar].type] + end + ).to_h + end + + # Freeze all definitions of the module + # + # This freezes the module's definitions, so that it can be used in a Ractor. + # No further methods or variables can be attached and no further enums or typedefs can be created in this module afterwards. + def freeze + instance_variables.each do |name| + var = instance_variable_get(name) + FFI.make_shareable(var) + end + nil + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library_path.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library_path.rb new file mode 100644 index 00000000..5575a5f1 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/library_path.rb @@ -0,0 +1,109 @@ +# +# Copyright (C) 2023 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # Transform a generic library name and ABI number to a platform library name + # + # Example: + # module LibVips + # extend FFI::Library + # ffi_lib LibraryPath.new("vips", abi_number: 42) + # end + # + # This translates to the following library file names: + # libvips-42.dll on Windows + # libvips.so.42 on Linux + # libvips.42.dylib on Macos + # + # See https://packaging.ubuntu.com/html/libraries.html for more information about library naming. + class LibraryPath + attr_reader :name + attr_reader :abi_number + attr_reader :root + + # Build a new library path + # + # * name : The name of the library without file prefix or suffix. + # * abi_number : The ABI number of the library. + # * root : An optional base path prepended to the library name. + def initialize(name, abi_number: nil, root: nil) + @name = name + @abi_number = abi_number + @root = root + end + + def self.wrap(value) + # We allow instances of LibraryPath to pass through transparently: + return value if value.is_a?(self) + + # We special case a library named 'c' to be the standard C library: + return Library::LIBC if value == 'c' + + # If provided a relative file name we convert it into a library path: + if value && File.basename(value) == value + return self.new(value) + end + + # Otherwise, we assume it's a full path to a library: + return value + end + + def full_name + # If the abi_number is given, we format it specifically according to platform rules: + if abi_number + if Platform.windows? + "#{Platform::LIBPREFIX}#{name}-#{abi_number}.#{Platform::LIBSUFFIX}" + elsif Platform.mac? + "#{Platform::LIBPREFIX}#{name}.#{abi_number}.#{Platform::LIBSUFFIX}" + else # Linux? BSD? etc. + "#{Platform::LIBPREFIX}#{name}.#{Platform::LIBSUFFIX}.#{abi_number}" + end + else + # Otherwise we just add prefix and suffix: + lib = name + # Add library prefix if missing + lib = Platform::LIBPREFIX + lib unless lib =~ /^#{Platform::LIBPREFIX}/ + # Add library extension if missing + r = Platform.windows? || Platform.mac? ? "\\.#{Platform::LIBSUFFIX}$" : "\\.so($|\\.[1234567890]+)" + lib += ".#{Platform::LIBSUFFIX}" unless lib =~ /#{r}/ + lib + end + end + + def to_s + if root + # If the root path is given, we generate the full path: + File.join(root, full_name) + else + full_name + end + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/managedstruct.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/managedstruct.rb new file mode 100644 index 00000000..5d243e5b --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/managedstruct.rb @@ -0,0 +1,84 @@ +# Copyright (C) 2008 Mike Dalessio +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + # + # FFI::ManagedStruct allows custom garbage-collection of your FFI::Structs. + # + # The typical use case would be when interacting with a library + # that has a nontrivial memory management design, such as a linked + # list or a binary tree. + # + # When the {Struct} instance is garbage collected, FFI::ManagedStruct will + # invoke the class's release() method during object finalization. + # + # @example Example usage: + # module MyLibrary + # ffi_lib "libmylibrary" + # attach_function :new_dlist, [], :pointer + # attach_function :destroy_dlist, [:pointer], :void + # end + # + # class DoublyLinkedList < FFI::ManagedStruct + # @@@ + # struct do |s| + # s.name 'struct dlist' + # s.include 'dlist.h' + # s.field :head, :pointer + # s.field :tail, :pointer + # end + # @@@ + # + # def self.release ptr + # MyLibrary.destroy_dlist(ptr) + # end + # end + # + # begin + # ptr = DoublyLinkedList.new(MyLibrary.new_dlist) + # # do something with the list + # end + # # struct is out of scope, and will be GC'd using DoublyLinkedList#release + # + # + class ManagedStruct < FFI::Struct + + # @overload initialize(pointer) + # @param [Pointer] pointer + # Create a new ManagedStruct which will invoke the class method #release on + # @overload initialize + # A new instance of FFI::ManagedStruct. + def initialize(pointer=nil) + raise NoMethodError, "release() not implemented for class #{self}" unless self.class.respond_to?(:release, true) + raise ArgumentError, "Must supply a pointer to memory for the Struct" unless pointer + super AutoPointer.new(pointer, self.class.method(:release)) + end + + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/memorypointer.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/memorypointer.rb new file mode 100644 index 00000000..9f07bc69 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/memorypointer.rb @@ -0,0 +1 @@ +# This class is now implemented in C diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform.rb new file mode 100644 index 00000000..5ac4dd70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform.rb @@ -0,0 +1,187 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +require 'rbconfig' +require_relative 'compat' + +module FFI + class PlatformError < LoadError; end + + # This module defines different constants and class methods to play with + # various platforms. + module Platform + OS = FFI.make_shareable(case RbConfig::CONFIG['host_os'].downcase + when /linux/ + "linux" + when /darwin/ + "darwin" + when /freebsd/ + "freebsd" + when /netbsd/ + "netbsd" + when /openbsd/ + "openbsd" + when /dragonfly/ + "dragonflybsd" + when /sunos|solaris/ + "solaris" + when /mingw|mswin/ + "windows" + else + RbConfig::CONFIG['host_os'].downcase + end) + + OSVERSION = RbConfig::CONFIG['host_os'].gsub(/[^\d]/, '').to_i + + CPU = FFI.make_shareable(RbConfig::CONFIG['host_cpu']) + + ARCH = FFI.make_shareable(case CPU.downcase + when /amd64|x86_64|x64/ + "x86_64" + when /i\d86|x86|i86pc/ + "i386" + when /ppc64|powerpc64/ + "powerpc64" + when /ppc|powerpc/ + "powerpc" + when /sparcv9|sparc64/ + "sparcv9" + when /arm64|aarch64/ # MacOS calls it "arm64", other operating systems "aarch64" + "aarch64" + when /^arm/ + if OS == "darwin" # Ruby before 3.0 reports "arm" instead of "arm64" as host_cpu on darwin + "aarch64" + else + "arm" + end + else + RbConfig::CONFIG['host_cpu'] + end) + + private + # @param [String) os + # @return [Boolean] + # Test if current OS is +os+. + def self.is_os(os) + OS == os + end + + IS_GNU = defined?(GNU_LIBC) + IS_LINUX = is_os("linux") + IS_MAC = is_os("darwin") + IS_FREEBSD = is_os("freebsd") + IS_NETBSD = is_os("netbsd") + IS_OPENBSD = is_os("openbsd") + IS_DRAGONFLYBSD = is_os("dragonfly") + IS_SOLARIS = is_os("solaris") + IS_WINDOWS = is_os("windows") + IS_BSD = IS_MAC || IS_FREEBSD || IS_NETBSD || IS_OPENBSD || IS_DRAGONFLYBSD + + # Add the version for known ABI breaks + name_version = "12" if IS_FREEBSD && OSVERSION >= 12 # 64-bit inodes + + NAME = FFI.make_shareable("#{ARCH}-#{OS}#{name_version}") + CONF_DIR = FFI.make_shareable(File.join(File.dirname(__FILE__), 'platform', NAME)) + + public + + LIBPREFIX = FFI.make_shareable(case OS + when /windows|msys/ + '' + when /cygwin/ + 'cyg' + else + 'lib' + end) + + LIBSUFFIX = FFI.make_shareable(case OS + when /darwin/ + 'dylib' + when /linux|bsd|solaris/ + 'so' + when /windows|cygwin|msys/ + 'dll' + else + # Punt and just assume a sane unix (i.e. anything but AIX) + 'so' + end) + + LIBC = FFI.make_shareable(if IS_WINDOWS + crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase' + "#{crtname}.dll" + elsif IS_GNU + GNU_LIBC + elsif OS == 'cygwin' + "cygwin1.dll" + elsif OS == 'msys' + # Not sure how msys 1.0 behaves, tested on MSYS2. + "msys-2.0.dll" + else + "#{LIBPREFIX}c.#{LIBSUFFIX}" + end) + + LITTLE_ENDIAN = 1234 unless defined?(LITTLE_ENDIAN) + BIG_ENDIAN = 4321 unless defined?(BIG_ENDIAN) + unless defined?(BYTE_ORDER) + BYTE_ORDER = [0x12345678].pack("I") == [0x12345678].pack("N") ? BIG_ENDIAN : LITTLE_ENDIAN + end + + # Test if current OS is a *BSD (include MAC) + # @return [Boolean] + def self.bsd? + IS_BSD + end + + # Test if current OS is Windows + # @return [Boolean] + def self.windows? + IS_WINDOWS + end + + # Test if current OS is Mac OS + # @return [Boolean] + def self.mac? + IS_MAC + end + + # Test if current OS is Solaris (Sun OS) + # @return [Boolean] + def self.solaris? + IS_SOLARIS + end + + # Test if current OS is a unix OS + # @return [Boolean] + def self.unix? + !IS_WINDOWS + end + end +end + diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf new file mode 100644 index 00000000..68841bb1 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = long +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_string_t[37] = char +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sae_associd_t = uint +rbx.platform.typedef.sae_connid_t = uint +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_off_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf new file mode 100644 index 00000000..8d111e0a --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long_long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf new file mode 100644 index 00000000..3ccb8f66 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf @@ -0,0 +1,181 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = uint +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__char16_t = ushort +rbx.platform.typedef.__char32_t = uint +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = long +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__daddr_t = long +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__rman_res_t = ulong +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = long +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = ulong +rbx.platform.typedef.__vm_paddr_t = ulong +rbx.platform.typedef.__vm_size_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.cap_ioctl_t = ulong +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.kpaddr_t = ulong +rbx.platform.typedef.ksize_t = ulong +rbx.platform.typedef.kssize_t = long +rbx.platform.typedef.kvaddr_t = ulong +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.rman_res_t = ulong +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.rune_t = int +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_ooffset_t = ulong +rbx.platform.typedef.vm_paddr_t = ulong +rbx.platform.typedef.vm_pindex_t = ulong +rbx.platform.typedef.vm_size_t = ulong +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf new file mode 100644 index 00000000..c56206e0 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf @@ -0,0 +1,175 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = int +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = uint +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = ushort +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = ushort +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = long +rbx.platform.typedef.__kernel_size_t = ulong +rbx.platform.typedef.__kernel_ssize_t = long +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds64_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf new file mode 100644 index 00000000..6abc9c09 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf @@ -0,0 +1,134 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf new file mode 100644 index 00000000..5bdbbde2 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = long_long +rbx.platform.typedef._sigset_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long_long +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = long_long +rbx.platform.typedef.ptrdiff_t = long_long +rbx.platform.typedef.rsize_t = ulong_long +rbx.platform.typedef.size_t = ulong_long +rbx.platform.typedef.ssize_t = long_long +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong_long +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf new file mode 100644 index 00000000..cfbb90f3 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf new file mode 100644 index 00000000..523370d9 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong_long +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf new file mode 100644 index 00000000..a070d394 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf @@ -0,0 +1,132 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf new file mode 100644 index 00000000..c8a81411 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf new file mode 100644 index 00000000..c8a81411 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf new file mode 100644 index 00000000..93f6b861 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf @@ -0,0 +1,3 @@ +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.ssize_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf new file mode 100644 index 00000000..ae100f41 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = int +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf new file mode 100644 index 00000000..6c882d48 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf new file mode 100644 index 00000000..523370d9 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong_long +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf new file mode 100644 index 00000000..fa2fa8ce --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf @@ -0,0 +1,107 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsid_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__pthread_key = int +rbx.platform.typedef.__pthread_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__sigset_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.fsid_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.pthread_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf new file mode 100644 index 00000000..feb6bc47 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf @@ -0,0 +1,103 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf new file mode 100644 index 00000000..a5aba894 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf @@ -0,0 +1,126 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf new file mode 100644 index 00000000..15a0d613 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf new file mode 100644 index 00000000..22a2414e --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf @@ -0,0 +1,122 @@ +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.datalink_id_t = uint +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lgrp_id_t = long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf new file mode 100644 index 00000000..a5d0b058 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = int +rbx.platform.typedef._sigset_t = ulong +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rsize_t = uint +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf new file mode 100644 index 00000000..e0eeecc9 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf new file mode 100644 index 00000000..aa8716d8 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf @@ -0,0 +1,141 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf new file mode 100644 index 00000000..cbd20e78 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf @@ -0,0 +1,180 @@ +rbx.platform.typedef.UTF32Char = uint +rbx.platform.typedef.UniChar = ushort +rbx.platform.typedef.__cptr32 = string +rbx.platform.typedef.__cptr64 = ulong_long +rbx.platform.typedef.__long32_t = long +rbx.platform.typedef.__long64_t = int +rbx.platform.typedef.__ptr32 = pointer +rbx.platform.typedef.__ptr64 = ulong_long +rbx.platform.typedef.__ulong32_t = ulong +rbx.platform.typedef.__ulong64_t = uint +rbx.platform.typedef.aptx_t = ushort +rbx.platform.typedef.blkcnt32_t = int +rbx.platform.typedef.blkcnt64_t = ulong_long +rbx.platform.typedef.blkcnt_t = int +rbx.platform.typedef.blksize32_t = int +rbx.platform.typedef.blksize64_t = ulong_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.boolean_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.chan_t = int +rbx.platform.typedef.class_id_t = uint +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = long_long +rbx.platform.typedef.cnt64_t = long_long +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.crid_t = int +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev32_t = uint +rbx.platform.typedef.dev64_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.esid_t = uint +rbx.platform.typedef.ext_t = int +rbx.platform.typedef.fpos64_t = long_long +rbx.platform.typedef.fpos_t = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino32_t = uint +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16 = short +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32 = int +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int32long64_t = int +rbx.platform.typedef.int64 = long_long +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8 = char +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intfast_t = int +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.krpn_t = int +rbx.platform.typedef.kvmhandle_t = ulong +rbx.platform.typedef.kvmid_t = long +rbx.platform.typedef.kvpn_t = int +rbx.platform.typedef.level_t = int +rbx.platform.typedef.liobn_t = uint +rbx.platform.typedef.long32int64_t = long +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.mid_t = pointer +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.mtyp_t = long +rbx.platform.typedef.nlink_t = short +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.paddr_t = long +rbx.platform.typedef.pdtx_t = int +rbx.platform.typedef.pid32_t = int +rbx.platform.typedef.pid64_t = ulong_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pshift_t = ushort +rbx.platform.typedef.psize_t = long_long +rbx.platform.typedef.psx_t = short +rbx.platform.typedef.ptex_t = ulong +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.rpn64_t = long_long +rbx.platform.typedef.rpn_t = int +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.signal_t = int +rbx.platform.typedef.size64_t = ulong_long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.slab_t[12] = char +rbx.platform.typedef.snidx_t = int +rbx.platform.typedef.socklen_t = ulong +rbx.platform.typedef.soff_t = int +rbx.platform.typedef.sshift_t = ushort +rbx.platform.typedef.ssize64_t = long_long +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.swhatx_t = ulong +rbx.platform.typedef.tid32_t = int +rbx.platform.typedef.tid64_t = ulong_long +rbx.platform.typedef.tid_t = int +rbx.platform.typedef.time32_t = int +rbx.platform.typedef.time64_t = long_long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer32_t = int +rbx.platform.typedef.timer64_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16 = ushort +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32 = uint +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64 = ulong_long +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8 = uchar +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar = uchar +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint32long64_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintfast_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong32int64_t = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unidx_t = int +rbx.platform.typedef.unit_addr_t = ulong_long +rbx.platform.typedef.ureg_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.va_list = string +rbx.platform.typedef.vmfkey_t = uint +rbx.platform.typedef.vmhandle32_t = uint +rbx.platform.typedef.vmhandle_t = ulong +rbx.platform.typedef.vmhwkey_t = int +rbx.platform.typedef.vmid32_t = int +rbx.platform.typedef.vmid64_t = long_long +rbx.platform.typedef.vmid_t = long +rbx.platform.typedef.vmidx_t = int +rbx.platform.typedef.vmkey_t = int +rbx.platform.typedef.vmlpghandle_t = ulong +rbx.platform.typedef.vmm_lock_t = int +rbx.platform.typedef.vmnodeidx_t = int +rbx.platform.typedef.vmprkey_t = uint +rbx.platform.typedef.vmsize_t = int +rbx.platform.typedef.vpn_t = int +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = uint +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf new file mode 100644 index 00000000..ae100f41 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = int +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf new file mode 100644 index 00000000..42eec130 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf new file mode 100644 index 00000000..aea79551 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf @@ -0,0 +1,156 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong +rbx.platform.typedef.wchar_t = int +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf new file mode 100644 index 00000000..9ac9c2e5 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf new file mode 100644 index 00000000..ede0f985 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf new file mode 100644 index 00000000..291b0326 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf new file mode 100644 index 00000000..32a7feba --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf new file mode 100644 index 00000000..aea09d32 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf new file mode 100644 index 00000000..a1548e56 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.() = pointer +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.Psocklen_t = pointer +rbx.platform.typedef.avl_index_t = uint +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = long +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.kid_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.size_t) = pointer +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.ts_t = long_long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = long +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf new file mode 100644 index 00000000..7626bfce --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf new file mode 100644 index 00000000..aea79551 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf @@ -0,0 +1,156 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong +rbx.platform.typedef.wchar_t = int +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf new file mode 100644 index 00000000..a1548e56 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.() = pointer +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.Psocklen_t = pointer +rbx.platform.typedef.avl_index_t = uint +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = long +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.kid_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.size_t) = pointer +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.ts_t = long_long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = long +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf new file mode 100644 index 00000000..aa8716d8 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf @@ -0,0 +1,141 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf new file mode 100644 index 00000000..5bef6d70 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf @@ -0,0 +1,3 @@ +rbx.platform.typedef.ptrdiff_t = int64 +rbx.platform.typedef.size_t = uint64 +rbx.platform.typedef.ssize_t = int64 diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf new file mode 100644 index 00000000..68841bb1 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = long +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_string_t[37] = char +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sae_associd_t = uint +rbx.platform.typedef.sae_connid_t = uint +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_off_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf new file mode 100644 index 00000000..889f6a32 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = int +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intlp_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintlp_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_daddr_t = uint +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.v_caddr_t = pointer +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf new file mode 100644 index 00000000..8dbe3703 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long_long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf new file mode 100644 index 00000000..31b1073d --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf @@ -0,0 +1,158 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = int +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__char16_t = ushort +rbx.platform.typedef.__char32_t = uint +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = long +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__rman_res_t = ulong +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = long +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = ulong +rbx.platform.typedef.__vm_paddr_t = ulong +rbx.platform.typedef.__vm_size_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.cap_ioctl_t = ulong +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.ksize_t = ulong +rbx.platform.typedef.kvaddr_t = ulong +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.rman_res_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_ooffset_t = long +rbx.platform.typedef.vm_paddr_t = ulong +rbx.platform.typedef.vm_pindex_t = ulong +rbx.platform.typedef.vm_size_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf new file mode 100644 index 00000000..d5ddfa79 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf @@ -0,0 +1,117 @@ +rbx.platform.typedef.__haiku_addr_t = ulong +rbx.platform.typedef.__haiku_generic_addr_t = ulong +rbx.platform.typedef.__haiku_int16 = short +rbx.platform.typedef.__haiku_int32 = int +rbx.platform.typedef.__haiku_int64 = long +rbx.platform.typedef.__haiku_int8 = char +rbx.platform.typedef.__haiku_phys_addr_t = ulong +rbx.platform.typedef.__haiku_phys_saddr_t = long +rbx.platform.typedef.__haiku_saddr_t = long +rbx.platform.typedef.__haiku_std_int16 = short +rbx.platform.typedef.__haiku_std_int32 = int +rbx.platform.typedef.__haiku_std_int64 = long +rbx.platform.typedef.__haiku_std_int8 = char +rbx.platform.typedef.__haiku_std_uint16 = ushort +rbx.platform.typedef.__haiku_std_uint32 = uint +rbx.platform.typedef.__haiku_std_uint64 = ulong +rbx.platform.typedef.__haiku_std_uint8 = uchar +rbx.platform.typedef.__haiku_uint16 = ushort +rbx.platform.typedef.__haiku_uint32 = uint +rbx.platform.typedef.__haiku_uint64 = ulong +rbx.platform.typedef.__haiku_uint8 = uchar +rbx.platform.typedef.addr_t = ulong +rbx.platform.typedef.bigtime_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = pointer +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = int +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = uint +rbx.platform.typedef.fsblkcnt_t = long +rbx.platform.typedef.fsfilcnt_t = long +rbx.platform.typedef.generic_addr_t = ulong +rbx.platform.typedef.generic_size_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = int +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = long +rbx.platform.typedef.int16 = short +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32 = int +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64 = long +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8 = char +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nanotime_t = long +rbx.platform.typedef.nlink_t = int +rbx.platform.typedef.off_t = long +rbx.platform.typedef.perform_code = uint +rbx.platform.typedef.phys_addr_t = ulong +rbx.platform.typedef.phys_size_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sig_atomic_t = int +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.status_t = int +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.type_code = uint +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16 = ushort +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32 = uint +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64 = ulong +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8 = uchar +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.umode_t = uint +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.unichar = ushort +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.void*) = pointer +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf new file mode 100644 index 00000000..060f1617 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf @@ -0,0 +1,132 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf new file mode 100644 index 00000000..aa827c00 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf @@ -0,0 +1,119 @@ +rbx.platform.typedef.*addr_t = char +rbx.platform.typedef.__ULong = uint +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = ulong +rbx.platform.typedef.__cpu_mask = ulong +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long_long +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__sigset_t = ulong +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = ulong +rbx.platform.typedef._fpos64_t = long_long +rbx.platform.typedef._fpos_t = long +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = ulong +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long_long +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.sig_atomic_t = int +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = ulong +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.useconds_t = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_size_t = ulong +rbx.platform.typedef.wint_t = uint diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf new file mode 100644 index 00000000..15a0d613 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf new file mode 100644 index 00000000..6abc9c09 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf @@ -0,0 +1,134 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf new file mode 100644 index 00000000..a7890d16 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf @@ -0,0 +1,122 @@ +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.blkcnt64_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = int +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.datalink_id_t = uint +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt64_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = int +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lgrp_id_t = int +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = uint +rbx.platform.typedef.minor_t = uint +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.poolid_t = int +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = int +rbx.platform.typedef.t_uscalar_t = uint +rbx.platform.typedef.taskid_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = int diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf new file mode 100644 index 00000000..5bdbbde2 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = long_long +rbx.platform.typedef._sigset_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long_long +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = long_long +rbx.platform.typedef.ptrdiff_t = long_long +rbx.platform.typedef.rsize_t = ulong_long +rbx.platform.typedef.size_t = ulong_long +rbx.platform.typedef.ssize_t = long_long +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong_long +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/pointer.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/pointer.rb new file mode 100644 index 00000000..e65835f3 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/pointer.rb @@ -0,0 +1,167 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# Copyright (c) 2007, 2008 Evan Phoenix +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/platform' + +# NOTE: all method definitions in this file are conditional on +# whether they are not already defined. This is needed because +# some Ruby implementations (e.g., TruffleRuby) might already +# provide these methods due to using FFI internally, and we +# should not override them to avoid warnings. + +module FFI + class Pointer + + # Pointer size + SIZE = Platform::ADDRESS_SIZE / 8 unless const_defined?(:SIZE) + + # Return the size of a pointer on the current platform, in bytes + # @return [Integer] + def self.size + SIZE + end unless respond_to?(:size) + + # @param [nil,Integer] len length of string to return + # @return [String] + # Read pointer's contents as a string, or the first +len+ bytes of the + # equivalent string if +len+ is not +nil+. + def read_string(len=nil) + if len + return ''.b if len == 0 + get_bytes(0, len) + else + get_string(0) + end + end unless method_defined?(:read_string) + + # @param [Integer] len length of string to return + # @return [String] + # Read the first +len+ bytes of pointer's contents as a string. + # + # Same as: + # ptr.read_string(len) # with len not nil + def read_string_length(len) + get_bytes(0, len) + end unless method_defined?(:read_string_length) + + # @return [String] + # Read pointer's contents as a string. + # + # Same as: + # ptr.read_string # with no len + def read_string_to_null + get_string(0) + end unless method_defined?(:read_string_to_null) + + # @param [String] str string to write + # @param [Integer] len length of string to return + # @return [self] + # Write +len+ first bytes of +str+ in pointer's contents. + # + # Same as: + # ptr.write_string(str, len) # with len not nil + def write_string_length(str, len) + put_bytes(0, str, 0, len) + end unless method_defined?(:write_string_length) + + # @param [String] str string to write + # @param [Integer] len length of string to return + # @return [self] + # Write +str+ in pointer's contents, or first +len+ bytes if + # +len+ is not +nil+. + def write_string(str, len=nil) + len = str.bytesize unless len + # Write the string data without NUL termination + put_bytes(0, str, 0, len) + end unless method_defined?(:write_string) + + # @param [Type] type type of data to read from pointer's contents + # @param [Symbol] reader method to send to +self+ to read +type+ + # @param [Integer] length + # @return [Array] + # Read an array of +type+ of length +length+. + # @example + # ptr.read_array_of_type(TYPE_UINT8, :read_uint8, 4) # -> [1, 2, 3, 4] + def read_array_of_type(type, reader, length) + ary = [] + size = FFI.type_size(type) + tmp = self + length.times { |j| + ary << tmp.send(reader) + tmp += size unless j == length-1 # avoid OOB + } + ary + end unless method_defined?(:read_array_of_type) + + # @param [Type] type type of data to write to pointer's contents + # @param [Symbol] writer method to send to +self+ to write +type+ + # @param [Array] ary + # @return [self] + # Write +ary+ in pointer's contents as +type+. + # @example + # ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4]) + def write_array_of_type(type, writer, ary) + size = FFI.type_size(type) + ary.each_with_index { |val, i| + break unless i < self.size + self.send(writer, i * size, val) + } + self + end unless method_defined?(:write_array_of_type) + + # @return [self] + def to_ptr + self + end unless method_defined?(:to_ptr) + + # @param [Symbol,Type] type of data to read + # @return [Object] + # Read pointer's contents as +type+ + # + # Same as: + # ptr.get(type, 0) + def read(type) + get(type, 0) + end unless method_defined?(:read) + + # @param [Symbol,Type] type of data to read + # @param [Object] value to write + # @return [nil] + # Write +value+ of type +type+ to pointer's content + # + # Same as: + # ptr.put(type, 0) + def write(type, value) + put(type, 0, value) + end unless method_defined?(:write) + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct.rb new file mode 100644 index 00000000..bf6228ab --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct.rb @@ -0,0 +1,317 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008, 2009 Andrea Fazzi +# Copyright (C) 2008, 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/platform' +require 'ffi/struct_layout' +require 'ffi/struct_layout_builder' +require 'ffi/struct_by_reference' + +module FFI + + class Struct + + # Get struct size + # @return [Integer] + def size + self.class.size + end + + # @return [Integer] Struct alignment + def alignment + self.class.alignment + end + alias_method :align, :alignment + + # (see FFI::StructLayout#offset_of) + def offset_of(name) + self.class.offset_of(name) + end + + # (see FFI::StructLayout#members) + def members + self.class.members + end + + # @return [Array] + # Get array of values from Struct fields. + def values + members.map { |m| self[m] } + end + + # (see FFI::StructLayout#offsets) + def offsets + self.class.offsets + end + + # Clear the struct content. + # @return [self] + def clear + pointer.clear + self + end + + # Get {Pointer} to struct content. + # @return [AbstractMemory] + def to_ptr + pointer + end + + # Get struct size + # @return [Integer] + def self.size + defined?(@layout) ? @layout.size : defined?(@size) ? @size : 0 + end + + # set struct size + # @param [Integer] size + # @return [size] + def self.size=(size) + raise ArgumentError, "Size already set" if defined?(@size) || defined?(@layout) + @size = size + end + + # @return (see Struct#alignment) + def self.alignment + @layout.alignment + end + + # (see FFI::Type#members) + def self.members + @layout.members + end + + # (see FFI::StructLayout#offsets) + def self.offsets + @layout.offsets + end + + # (see FFI::StructLayout#offset_of) + def self.offset_of(name) + @layout.offset_of(name) + end + + def self.in + ptr(:in) + end + + def self.out + ptr(:out) + end + + def self.ptr(flags = :inout) + @ref_data_type ||= Type::Mapped.new(StructByReference.new(self)) + end + + def self.val + @val_data_type ||= StructByValue.new(self) + end + + def self.by_value + self.val + end + + def self.by_ref(flags = :inout) + self.ptr(flags) + end + + class ManagedStructConverter < StructByReference + + # @param [Struct] struct_class + def initialize(struct_class) + super(struct_class) + + raise NoMethodError, "release() not implemented for class #{struct_class}" unless struct_class.respond_to? :release + @method = struct_class.method(:release) + end + + # @param [Pointer] ptr + # @param [nil] ctx + # @return [Struct] + def from_native(ptr, ctx) + struct_class.new(AutoPointer.new(ptr, @method)) + end + end + + def self.auto_ptr + @managed_type ||= Type::Mapped.new(ManagedStructConverter.new(self)) + end + + + class << self + public + + # @return [StructLayout] + # @overload layout + # @return [StructLayout] + # Get struct layout. + # @overload layout(*spec) + # @param [Array,Array(Hash)] spec + # @return [StructLayout] + # Create struct layout from +spec+. + # @example Creating a layout from an array +spec+ + # class MyStruct < Struct + # layout :field1, :int, + # :field2, :pointer, + # :field3, :string + # end + # @example Creating a layout from an array +spec+ with offset + # class MyStructWithOffset < Struct + # layout :field1, :int, + # :field2, :pointer, 6, # set offset to 6 for this field + # :field3, :string + # end + # @example Creating a layout from a hash +spec+ + # class MyStructFromHash < Struct + # layout :field1 => :int, + # :field2 => :pointer, + # :field3 => :string + # end + # @example Creating a layout with pointers to functions + # class MyFunctionTable < Struct + # layout :function1, callback([:int, :int], :int), + # :function2, callback([:pointer], :void), + # :field3, :string + # end + def layout(*spec) + return @layout if spec.size == 0 + + warn "[DEPRECATION] Struct layout is already defined for class #{self.inspect}. Redefinition as in #{caller[0]} will be disallowed in ffi-2.0." if defined?(@layout) + + builder = StructLayoutBuilder.new + builder.union = self < Union + builder.packed = @packed if defined?(@packed) + builder.alignment = @min_alignment if defined?(@min_alignment) + + if spec[0].kind_of?(Hash) + hash_layout(builder, spec) + else + array_layout(builder, spec) + end + builder.size = @size if defined?(@size) && @size > builder.size + cspec = builder.build + @layout = cspec unless self == Struct + @size = cspec.size + return cspec + end + + + protected + + def callback(params, ret) + mod = enclosing_module + ret_type = find_type(ret, mod) + if ret_type == Type::STRING + raise TypeError, ":string is not allowed as return type of callbacks" + end + FFI::CallbackInfo.new(ret_type, params.map { |e| find_type(e, mod) }) + end + + def packed(packed = 1) + @packed = packed + end + alias :pack :packed + + def aligned(alignment = 1) + @min_alignment = alignment + end + alias :align :aligned + + def enclosing_module + begin + mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) } + if mod.respond_to?(:find_type) && (mod.is_a?(FFI::Library) || mod < FFI::Struct) + mod + end + rescue Exception + nil + end + end + + + def find_field_type(type, mod = enclosing_module) + if type.kind_of?(Class) && type < Struct + FFI::Type::Struct.new(type) + + elsif type.kind_of?(Class) && type < FFI::StructLayout::Field + type + + elsif type.kind_of?(::Array) + FFI::Type::Array.new(find_field_type(type[0]), type[1]) + + else + find_type(type, mod) + end + end + + def find_type(type, mod = enclosing_module) + if mod + mod.find_type(type) + end || FFI.find_type(type) + end + + private + + # @param [StructLayoutBuilder] builder + # @param [Hash] spec + # @return [builder] + # Add hash +spec+ to +builder+. + def hash_layout(builder, spec) + spec[0].each do |name, type| + builder.add name, find_field_type(type), nil + end + end + + # @param [StructLayoutBuilder] builder + # @param [Array] spec + # @return [builder] + # Add array +spec+ to +builder+. + def array_layout(builder, spec) + i = 0 + while i < spec.size + name, type = spec[i, 2] + i += 2 + + # If the next param is a Integer, it specifies the offset + if spec[i].kind_of?(Integer) + offset = spec[i] + i += 1 + else + offset = nil + end + + builder.add name, find_field_type(type), offset + end + end + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb new file mode 100644 index 00000000..27f25eca --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb @@ -0,0 +1,72 @@ +# +# Copyright (C) 2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # This class includes the {FFI::DataConverter} module. + class StructByReference + include DataConverter + + attr_reader :struct_class + + # @param [Struct] struct_class + def initialize(struct_class) + unless Class === struct_class and struct_class < FFI::Struct + raise TypeError, 'wrong type (expected subclass of FFI::Struct)' + end + @struct_class = struct_class + end + + # Always get {FFI::Type}::POINTER. + def native_type + FFI::Type::POINTER + end + + # @param [nil, Struct] value + # @param [nil] ctx + # @return [AbstractMemory] Pointer on +value+. + def to_native(value, ctx) + return Pointer::NULL if value.nil? + + unless @struct_class === value + raise TypeError, "wrong argument type #{value.class} (expected #{@struct_class})" + end + + value.pointer + end + + # @param [AbstractMemory] value + # @param [nil] ctx + # @return [Struct] + # Create a struct from content of memory +value+. + def from_native(value, ctx) + @struct_class.new(value) + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout.rb new file mode 100644 index 00000000..fb842023 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout.rb @@ -0,0 +1,96 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008, 2009 Andrea Fazzi +# Copyright (C) 2008, 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + class StructLayout + + # @return [Array + # Get an array of tuples (field name, offset of the field). + def offsets + members.map { |m| [ m, self[m].offset ] } + end + + # @return [Integer] + # Get the offset of a field. + def offset_of(field_name) + self[field_name].offset + end + + # An enum {Field} in a {StructLayout}. + class Enum < Field + + # @param [AbstractMemory] ptr pointer on a {Struct} + # @return [Object] + # Get an object of type {#type} from memory pointed by +ptr+. + def get(ptr) + type.find(ptr.get_int(offset)) + end + + # @param [AbstractMemory] ptr pointer on a {Struct} + # @param value + # @return [nil] + # Set +value+ into memory pointed by +ptr+. + def put(ptr, value) + ptr.put_int(offset, type.find(value)) + end + + end + + class InnerStruct < Field + def get(ptr) + type.struct_class.new(ptr.slice(self.offset, self.size)) + end + + def put(ptr, value) + raise TypeError, "wrong value type (expected #{type.struct_class})" unless value.is_a?(type.struct_class) + ptr.slice(self.offset, self.size).__copy_from__(value.pointer, self.size) + end + end + + class Mapped < Field + def initialize(name, offset, type, orig_field) + @orig_field = orig_field + super(name, offset, type) + end + + def get(ptr) + type.from_native(@orig_field.get(ptr), nil) + end + + def put(ptr, value) + @orig_field.put(ptr, type.to_native(value, nil)) + end + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb new file mode 100644 index 00000000..2221a607 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb @@ -0,0 +1,227 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + # Build a {StructLayout struct layout}. + class StructLayoutBuilder + attr_reader :size + attr_reader :alignment + + def initialize + @size = 0 + @alignment = 1 + @min_alignment = 1 + @packed = false + @union = false + @fields = Array.new + end + + # Set size attribute with +size+ only if +size+ is greater than attribute value. + # @param [Integer] size + def size=(size) + @size = size if size > @size + end + + # Set alignment attribute with +align+ only if it is greater than attribute value. + # @param [Integer] align + def alignment=(align) + @alignment = align if align > @alignment + @min_alignment = align + end + + # Set union attribute. + # Set to +true+ to build a {Union} instead of a {Struct}. + # @param [Boolean] is_union + # @return [is_union] + def union=(is_union) + @union = is_union + end + + # Building a {Union} or a {Struct} ? + # + # @return [Boolean] + # + def union? + @union + end + + # Set packed attribute + # @overload packed=(packed) Set alignment and packed attributes to + # +packed+. + # + # @param [Integer] packed + # + # @return [packed] + # @overload packed=(packed) Set packed attribute. + # @param packed + # + # @return [0,1] + # + def packed=(packed) + if packed.is_a?(0.class) + @alignment = packed + @packed = packed + else + @packed = packed ? 1 : 0 + end + end + + + # List of number types + NUMBER_TYPES = [ + Type::INT8, + Type::UINT8, + Type::INT16, + Type::UINT16, + Type::INT32, + Type::UINT32, + Type::LONG, + Type::ULONG, + Type::INT64, + Type::UINT64, + Type::FLOAT32, + Type::FLOAT64, + Type::LONGDOUBLE, + Type::BOOL, + ].freeze + + # @param [String, Symbol] name name of the field + # @param [Array, DataConverter, Struct, StructLayout::Field, Symbol, Type] type type of the field + # @param [Integer, nil] offset + # @return [self] + # Add a field to the builder. + # @note Setting +offset+ to +nil+ or +-1+ is equivalent to +0+. + def add(name, type, offset = nil) + + if offset.nil? || offset == -1 + offset = @union ? 0 : align(@size, @packed ? [ @packed, type.alignment ].min : [ @min_alignment, type.alignment ].max) + end + + # + # If a FFI::Type type was passed in as the field arg, try and convert to a StructLayout::Field instance + # + field = type.is_a?(StructLayout::Field) ? type : field_for_type(name, offset, type) + @fields << field + @alignment = [ @alignment, field.alignment ].max unless @packed + @size = [ @size, field.size + (@union ? 0 : field.offset) ].max + + return self + end + + # @param (see #add) + # @return (see #add) + # Same as {#add}. + # @see #add + def add_field(name, type, offset = nil) + add(name, type, offset) + end + + # @param (see #add) + # @return (see #add) + # Add a struct as a field to the builder. + def add_struct(name, type, offset = nil) + add(name, Type::Struct.new(type), offset) + end + + # @param name (see #add) + # @param type (see #add) + # @param [Integer] count array length + # @param offset (see #add) + # @return (see #add) + # Add an array as a field to the builder. + def add_array(name, type, count, offset = nil) + add(name, Type::Array.new(type, count), offset) + end + + # @return [StructLayout] + # Build and return the struct layout. + def build + # Add tail padding if the struct is not packed + size = @packed ? @size : align(@size, @alignment) + + layout = StructLayout.new(@fields, size, @alignment) + layout.__union! if @union + layout + end + + private + + # @param [Integer] offset + # @param [Integer] align + # @return [Integer] + def align(offset, align) + align + ((offset - 1) & ~(align - 1)); + end + + # @param (see #add) + # @return [StructLayout::Field] + def field_for_type(name, offset, type) + field_class = case + when type.is_a?(Type::Function) + StructLayout::Function + + when type.is_a?(Type::Struct) + StructLayout::InnerStruct + + when type.is_a?(Type::Array) + StructLayout::Array + + when type.is_a?(FFI::Enum) + StructLayout::Enum + + when NUMBER_TYPES.include?(type) + StructLayout::Number + + when type == Type::POINTER + StructLayout::Pointer + + when type == Type::STRING + StructLayout::String + + when type.is_a?(Class) && type < StructLayout::Field + type + + when type.is_a?(DataConverter) + return StructLayout::Mapped.new(name, offset, Type::Mapped.new(type), field_for_type(name, offset, type.native_type)) + + when type.is_a?(Type::Mapped) + return StructLayout::Mapped.new(name, offset, type, field_for_type(name, offset, type.native_type)) + + else + raise TypeError, "invalid struct field type #{type.inspect}" + end + + field_class.new(name, offset, type) + end + end + +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb new file mode 100644 index 00000000..70ba9c2a --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb @@ -0,0 +1,232 @@ +require 'tempfile' +require 'open3' + +module FFI + + # ConstGenerator turns C constants into ruby values. + # + # @example a simple example for stdio + # require 'ffi/tools/const_generator' + # cg = FFI::ConstGenerator.new('stdio') do |gen| + # gen.const(:SEEK_SET) + # gen.const('SEEK_CUR') + # gen.const('seek_end') # this constant does not exist + # end # #calculate called automatically at the end of the block + # + # cg['SEEK_SET'] # => 0 + # cg['SEEK_CUR'] # => 1 + # cg['seek_end'] # => nil + # cg.to_ruby # => "SEEK_SET = 0\nSEEK_CUR = 1\n# seek_end not available" + class ConstGenerator + @options = {} + attr_reader :constants + + # Creates a new constant generator that uses +prefix+ as a name, and an + # options hash. + # + # The only option is +:required+, which if set to +true+ raises an error if a + # constant you have requested was not found. + # + # @param [#to_s] prefix + # @param [Hash] options + # @return + # @option options [Boolean] :required + # @overload initialize(prefix, options) + # @overload initialize(prefix, options) { |gen| ... } + # @yieldparam [ConstGenerator] gen new generator is passed to the block + # When passed a block, {#calculate} is automatically called at the end of + # the block, otherwise you must call it yourself. + def initialize(prefix = nil, options = {}) + @includes = ['stdio.h', 'stddef.h'] + @constants = {} + @prefix = prefix + + @required = options[:required] + @options = options + + if block_given? then + yield self + calculate self.class.options.merge(options) + end + end + # Set class options + # These options are merged with {#initialize} options when it is called with a block. + # @param [Hash] options + # @return [Hash] class options + def self.options=(options) + @options = options + end + # Get class options. + # @return [Hash] class options + def self.options + @options + end + # @param [String] name + # @return constant value (converted if a +converter+ was defined). + # Access a constant by name. + def [](name) + @constants[name].converted_value + end + + # Request the value for C constant +name+. + # + # @param [#to_s] name C constant name + # @param [String] format a printf format string to print the value out + # @param [String] cast a C cast for the value + # @param ruby_name alternate ruby name for {#to_ruby} + # + # @overload const(name, format=nil, cast='', ruby_name=nil, converter=nil) + # +converter+ is a Method or a Proc. + # @param [#call] converter convert the value from a string to the appropriate + # type for {#to_ruby}. + # @overload const(name, format=nil, cast='', ruby_name=nil) { |value| ... } + # Use a converter block. This block convert the value from a string to the + # appropriate type for {#to_ruby}. + # @yieldparam value constant value + def const(name, format = nil, cast = '', ruby_name = nil, converter = nil, + &converter_proc) + format ||= '%d' + cast ||= '' + + if converter_proc and converter then + raise ArgumentError, "Supply only converter or converter block" + end + + converter = converter_proc if converter.nil? + + const = Constant.new name, format, cast, ruby_name, converter + @constants[name.to_s] = const + return const + end + + # Calculate constants values. + # @param [Hash] options + # @option options [String] :cppflags flags for C compiler + # @return [nil] + # @raise if a constant is missing and +:required+ was set to +true+ (see {#initialize}) + def calculate(options = {}) + binary_path = nil + + Tempfile.open("#{@prefix}.const_generator") do |f| + binary_path = f.path + ".bin" + @includes.each do |inc| + f.puts "#include <#{inc}>" + end + f.puts "\nint main(int argc, char **argv)\n{" + + @constants.each_value do |const| + f.puts <<-EOF + #ifdef #{const.name} + printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name}); + #endif + EOF + end + + f.puts "\n\treturn 0;\n}" + f.flush + + cc = ENV['CC'] || 'gcc' + output = `#{cc} #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary_path} 2>&1` + + unless $?.success? then + output = output.split("\n").map { |l| "\t#{l}" }.join "\n" + raise "Compilation error generating constants #{@prefix}:\n#{output}" + end + end + + output = `#{binary_path}` + File.unlink(binary_path + (FFI::Platform.windows? ? ".exe" : "")) + output.each_line do |line| + line =~ /^(\S+)\s(.*)$/ + const = @constants[$1] + const.value = $2 + end + + missing_constants = @constants.select do |name, constant| + constant.value.nil? + end.map { |name,| name } + + if @required and not missing_constants.empty? then + raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}" + end + end + + # Dump constants to +io+. + # @param [#puts] io + # @return [nil] + def dump_constants(io) + @constants.each do |name, constant| + name = [@prefix, name].join '.' if @prefix + io.puts "#{name} = #{constant.converted_value}" + end + end + + # Outputs values for discovered constants. If the constant's value was + # not discovered it is not omitted. + # @return [String] + def to_ruby + @constants.sort_by { |name,| name }.map do |name, constant| + if constant.value.nil? then + "# #{name} not available" + else + constant.to_ruby + end + end.join "\n" + end + + # Add additional C include file(s) to calculate constants from. + # @note +stdio.h+ and +stddef.h+ automatically included + # @param [List, Array] i include file(s) + # @return [Array] array of include files + def include(*i) + @includes |= i.flatten + end + + end + + # This class hold constants for {ConstGenerator} + class ConstGenerator::Constant + + attr_reader :name, :format, :cast + attr_accessor :value + + # @param [#to_s] name + # @param [String] format a printf format string to print the value out + # @param [String] cast a C cast for the value + # @param ruby_name alternate ruby name for {#to_ruby} + # @param [#call] converter convert the value from a string to the appropriate + # type for {#to_ruby}. + def initialize(name, format, cast, ruby_name = nil, converter=nil) + @name = name + @format = format + @cast = cast + @ruby_name = ruby_name + @converter = converter + @value = nil + end + + # Return constant value (converted if a +converter+ was defined). + # @return constant value. + def converted_value + if @converter + @converter.call(@value) + else + @value + end + end + + # get constant ruby name + # @return [String] + def ruby_name + @ruby_name || @name + end + + # Get an evaluable string from constant. + # @return [String] + def to_ruby + "#{ruby_name} = #{converted_value}" + end + + end + +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator.rb new file mode 100644 index 00000000..5552ea59 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator.rb @@ -0,0 +1,105 @@ +require 'ffi/tools/struct_generator' +require 'ffi/tools/const_generator' + +module FFI + + ## + # Generate files with C structs for FFI::Struct and C constants. + # + # == A simple example + # + # In file +zlib.rb.ffi+: + # module Zlib + # @@@ + # constants do |c| + # c.include "zlib.h" + # c.const :ZLIB_VERNUM + # end + # @@@ + # + # class ZStream < FFI::Struct + # + # struct do |s| + # s.name "struct z_stream_s" + # s.include "zlib.h" + # + # s.field :next_in, :pointer + # s.field :avail_in, :uint + # s.field :total_in, :ulong + # end + # @@@ + # end + # end + # + # Translate the file: + # require "ffi/tools/generator" + # FFI::Generator.new "zlib.rb.ffi", "zlib.rb" + # + # Generates the file +zlib.rb+ with constant values and offsets: + # module Zlib + # ZLIB_VERNUM = 4784 + # + # class ZStream < FFI::Struct + # layout :next_in, :pointer, 0, + # :avail_in, :uint, 8, + # :total_in, :ulong, 16 + # end + # + # @see FFI::Generator::Task for easy integration in a Rakefile + class Generator + + def initialize(ffi_name, rb_name, options = {}) + @ffi_name = ffi_name + @rb_name = rb_name + @options = options + @name = File.basename rb_name, '.rb' + + file = File.read @ffi_name + + new_file = file.gsub(/^( *)@@@(.*?)@@@/m) do + @constants = [] + @structs = [] + + indent = $1 + original_lines = $2.count "\n" + + instance_eval $2, @ffi_name, $`.count("\n") + + new_lines = [] + @constants.each { |c| new_lines << c.to_ruby } + @structs.each { |s| new_lines << s.generate_layout } + + new_lines = new_lines.join("\n").split "\n" # expand multiline blocks + new_lines = new_lines.map { |line| indent + line } + + padding = original_lines - new_lines.length + new_lines += [nil] * padding if padding >= 0 + + new_lines.join "\n" + end + + open @rb_name, 'w' do |f| + f.puts "# This file is generated from `#{@ffi_name}'. Do not edit." + f.puts + f.puts new_file + end + end + + def constants(options = {}, &block) + @constants << FFI::ConstGenerator.new(@name, @options.merge(options), &block) + end + + def struct(options = {}, &block) + @structs << FFI::StructGenerator.new(@name, @options.merge(options), &block) + end + + ## + # Utility converter for constants + + def to_s + proc { |obj| obj.to_s.inspect } + end + + end +end + diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb new file mode 100644 index 00000000..da72968b --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb @@ -0,0 +1,32 @@ +require 'ffi/tools/generator' +require 'rake' +require 'rake/tasklib' + +## +# Add Rake tasks that generate files with C structs for FFI::Struct and C constants. +# +# @example a simple example for your Rakefile +# require "ffi/tools/generator_task" +# # Add a task to generate my_object.rb out of my_object.rb.ffi +# FFI::Generator::Task.new ["my_object.rb"], cflags: "-I/usr/local/mylibrary" +# +# The generated files are also added to the 'clear' task. +# +# @see FFI::Generator for a description of the file content +class FFI::Generator::Task < Rake::TaskLib + + def initialize(rb_names, options={}) + task :clean do rm_f rb_names end + + rb_names.each do |rb_name| + ffi_name = "#{rb_name}.ffi" + + file rb_name => ffi_name do |t| + puts "Generating #{rb_name}..." if Rake.application.options.trace + + FFI::Generator.new ffi_name, rb_name, options + end + end + end + +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb new file mode 100644 index 00000000..3a951c38 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb @@ -0,0 +1,195 @@ +require 'tempfile' + +module FFI + + ## + # Generates an FFI Struct layout. + # + # Given the @@@ portion in: + # + # class Zlib::ZStream < FFI::Struct + # @@@ + # name "struct z_stream_s" + # include "zlib.h" + # + # field :next_in, :pointer + # field :avail_in, :uint + # field :total_in, :ulong + # + # # ... + # @@@ + # end + # + # StructGenerator will create the layout: + # + # layout :next_in, :pointer, 0, + # :avail_in, :uint, 4, + # :total_in, :ulong, 8, + # # ... + # + # StructGenerator does its best to pad the layout it produces to preserve + # line numbers. Place the struct definition as close to the top of the file + # for best results. + + class StructGenerator + @options = {} + attr_accessor :size + attr_reader :fields + + def initialize(name, options = {}) + @name = name + @struct_name = nil + @includes = [] + @fields = [] + @found = false + @size = nil + + if block_given? then + yield self + calculate self.class.options.merge(options) + end + end + def self.options=(options) + @options = options + end + def self.options + @options + end + def calculate(options = {}) + binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}" + + raise "struct name not set" if @struct_name.nil? + + Tempfile.open("#{@name}.struct_generator") do |f| + f.puts "#include " + + @includes.each do |inc| + f.puts "#include <#{inc}>" + end + + f.puts "#include \n\n" + f.puts "int main(int argc, char **argv)\n{" + f.puts " #{@struct_name} s;" + f.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));] + + @fields.each do |field| + f.puts <<-EOF + printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}), + (unsigned int) sizeof(s.#{field.name})); + EOF + end + + f.puts "\n return 0;\n}" + f.flush + + cc = ENV['CC'] || 'gcc' + output = `#{cc} #{options[:cppflags]} #{options[:cflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1` + + unless $?.success? then + @found = false + output = output.split("\n").map { |l| "\t#{l}" }.join "\n" + raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}" + end + end + + output = `#{binary}`.split "\n" + File.unlink(binary + (FFI::Platform.windows? ? ".exe" : "")) + sizeof = output.shift + unless @size + m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof + @size = m[1] + end + + line_no = 0 + output.each do |line| + md = line.match(/.+ (\d+) (\d+)/) + @fields[line_no].offset = md[1].to_i + @fields[line_no].size = md[2].to_i + + line_no += 1 + end + + @found = true + end + + def field(name, type=nil) + field = Field.new(name, type) + @fields << field + return field + end + + def found? + @found + end + + def dump_config(io) + io.puts "rbx.platform.#{@name}.sizeof = #{@size}" + + @fields.each { |field| io.puts field.to_config(@name) } + end + + def generate_layout + buf = "" + + @fields.each_with_index do |field, i| + if buf.empty? + buf << "layout :#{field.name}, :#{field.type}, #{field.offset}" + else + buf << " :#{field.name}, :#{field.type}, #{field.offset}" + end + + if i < @fields.length - 1 + buf << ",\n" + end + end + + buf + end + + def get_field(name) + @fields.find { |f| name == f.name } + end + + def include(i) + @includes << i + end + + def name(n) + @struct_name = n + end + + end + + ## + # A field in a Struct. + + class StructGenerator::Field + + attr_reader :name + attr_reader :type + attr_reader :offset + attr_accessor :size + + def initialize(name, type) + @name = name + @type = type + @offset = nil + @size = nil + end + + def offset=(o) + @offset = o + end + + def to_config(name) + buf = [] + buf << "rbx.platform.#{name}.#{@name}.offset = #{@offset}" + buf << "rbx.platform.#{name}.#{@name}.size = #{@size}" + buf << "rbx.platform.#{name}.#{@name}.type = #{@type}" if @type + buf + end + + end + +end + diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/types_generator.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/types_generator.rb new file mode 100644 index 00000000..ba2d8c5b --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/tools/types_generator.rb @@ -0,0 +1,137 @@ +require 'tempfile' + +module FFI + + # @private + class TypesGenerator + + ## + # Maps different C types to the C type representations we use + + TYPE_MAP = { + "char" => :char, + "signed char" => :char, + "__signed char" => :char, + "unsigned char" => :uchar, + + "short" => :short, + "signed short" => :short, + "signed short int" => :short, + "unsigned short" => :ushort, + "unsigned short int" => :ushort, + + "int" => :int, + "signed int" => :int, + "unsigned int" => :uint, + + "long" => :long, + "long int" => :long, + "signed long" => :long, + "signed long int" => :long, + "unsigned long" => :ulong, + "unsigned long int" => :ulong, + "long unsigned int" => :ulong, + + "long long" => :long_long, + "long long int" => :long_long, + "signed long long" => :long_long, + "signed long long int" => :long_long, + "unsigned long long" => :ulong_long, + "unsigned long long int" => :ulong_long, + + "char *" => :string, + "void *" => :pointer, + } + + def self.generate(options = {}) + typedefs = nil + Tempfile.open 'ffi_types_generator' do |io| + io.puts <<-C +#include +#include +#include +#if !(defined(WIN32)) +#include +#include +#include +#endif + C + + io.close + cc = ENV['CC'] || 'gcc' + cmd = "#{cc} -E -x c #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -c" + if options[:input] + typedefs = File.read(options[:input]) + elsif options[:remote] + typedefs = `ssh #{options[:remote]} #{cmd} - < #{io.path}` + else + typedefs = `#{cmd} #{io.path}` + end + end + + code = [] + + typedefs.each_line do |type| + # We only care about single line typedef + next unless type =~ /typedef/ + # Ignore unions or structs + next if type =~ /union|struct/ + + # strip off the starting typedef and ending ; + type.gsub!(/^(.*typedef\s*)/, "") + type.gsub!(/\s*;\s*$/, "") + + parts = type.split(/\s+/) + def_type = parts.join(" ") + + # GCC does mapping with __attribute__ stuf, also see + # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem + # with this is that the __attribute__ stuff can either occur before or + # after the new type that is defined... + if type =~ /__attribute__/ + if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/ + + # In this case, the new type is BEFORE __attribute__ we need to + # find the final_type as the type before the part that starts with + # __attribute__ + final_type = "" + parts.each do |p| + break if p =~ /__attribute__/ + final_type = p + end + else + final_type = parts.pop + end + + def_type = case type + when /__QI__/ then "char" + when /__HI__/ then "short" + when /__SI__/ then "int" + when /__DI__/ then "long long" + when /__word__/ then "long" + else "int" + end + + def_type = "unsigned #{def_type}" if type =~ /unsigned/ + else + final_type = parts.pop + def_type = parts.join(" ") + end + + if type = TYPE_MAP[def_type] + code << "rbx.platform.typedef.#{final_type} = #{type}" + TYPE_MAP[final_type] = TYPE_MAP[def_type] + else + # Fallback to an ordinary pointer if we don't know the type + if def_type =~ /\*/ + code << "rbx.platform.typedef.#{final_type} = pointer" + TYPE_MAP[final_type] = :pointer + end + end + end + + code.sort.join("\n") + end + end +end + diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/types.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/types.rb new file mode 100644 index 00000000..6f3ee4bc --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/types.rb @@ -0,0 +1,222 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (c) 2007, 2008 Evan Phoenix +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# see {file:README} +module FFI + + # Unless custom_typedefs already defined in the C-ext? + unless defined?(custom_typedefs) + # Truffleruby and JRuby don't support Ractor so far. + # So they don't need separation between builtin and custom types. + def self.custom_typedefs + TypeDefs + end + writable_typemap = true + end + + class << self + + private :custom_typedefs + + # @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type} + # @param [Symbol] add new type definition's name to add + # @return [Type] + # Add a definition type to type definitions. + # + # The type definition is local per Ractor. + def typedef(old, add) + tm = custom_typedefs + tm[add] = find_type(old) + end + + # (see FFI.typedef) + def add_typedef(old, add) + typedef old, add + end + + private def __typedef(old, add) + TypeDefs[add] = find_type(old, TypeDefs) + end + + # @param [Type, DataConverter, Symbol] name + # @param [Hash] type_map if nil, {FFI::TypeDefs} is used + # @return [Type] + # Find a type in +type_map+ ({FFI::TypeDefs}, by default) from + # a type objet, a type name (symbol). If +name+ is a {DataConverter}, + # a new {Type::Mapped} is created. + def find_type(name, type_map = nil) + if name.is_a?(Type) + name + + elsif type_map&.has_key?(name) + type_map[name] + + elsif (tm=custom_typedefs).has_key?(name) + tm[name] + + elsif TypeDefs.has_key?(name) + TypeDefs[name] + + elsif name.is_a?(DataConverter) + # Add a typedef so next time the converter is used, it hits the cache + tm = (type_map || custom_typedefs) + tm[name] = Type::Mapped.new(name) + else + raise TypeError, "unable to resolve type '#{name}'" + end + end + + # @param type +type+ is an instance of class accepted by {FFI.find_type} + # @return [Integer] + # Get +type+ size, in bytes. + def type_size(type) + find_type(type).size + end + end + + # List of type definitions + TypeDefs.merge!({ + # The C void type; only useful for function return types + :void => Type::VOID, + + # C boolean type + :bool => Type::BOOL, + + # C nul-terminated string + :string => Type::STRING, + + # C signed char + :char => Type::CHAR, + # C unsigned char + :uchar => Type::UCHAR, + + # C signed short + :short => Type::SHORT, + # C unsigned short + :ushort => Type::USHORT, + + # C signed int + :int => Type::INT, + # C unsigned int + :uint => Type::UINT, + + # C signed long + :long => Type::LONG, + + # C unsigned long + :ulong => Type::ULONG, + + # C signed long long integer + :long_long => Type::LONG_LONG, + + # C unsigned long long integer + :ulong_long => Type::ULONG_LONG, + + # C single precision float + :float => Type::FLOAT, + + # C double precision float + :double => Type::DOUBLE, + + # C long double + :long_double => Type::LONGDOUBLE, + + # Native memory address + :pointer => Type::POINTER, + + # 8 bit signed integer + :int8 => Type::INT8, + # 8 bit unsigned integer + :uint8 => Type::UINT8, + + # 16 bit signed integer + :int16 => Type::INT16, + # 16 bit unsigned integer + :uint16 => Type::UINT16, + + # 32 bit signed integer + :int32 => Type::INT32, + # 32 bit unsigned integer + :uint32 => Type::UINT32, + + # 64 bit signed integer + :int64 => Type::INT64, + # 64 bit unsigned integer + :uint64 => Type::UINT64, + + :buffer_in => Type::BUFFER_IN, + :buffer_out => Type::BUFFER_OUT, + :buffer_inout => Type::BUFFER_INOUT, + + # Used in function prototypes to indicate the arguments are variadic + :varargs => Type::VARARGS, + }) + + # This will convert a pointer to a Ruby string (just like `:string`), but + # also allow to work with the pointer itself. This is useful when you want + # a Ruby string already containing a copy of the data, but also the pointer + # to the data for you to do something with it, like freeing it, in case the + # library handed the memory off to the caller (Ruby-FFI). + # + # It's {typedef}'d as +:strptr+. + class StrPtrConverter + extend DataConverter + native_type Type::POINTER + + # @param [Pointer] val + # @param ctx not used + # @return [Array(String, Pointer)] + # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed + def self.from_native(val, ctx) + [ val.null? ? nil : val.get_string(0), val ] + end + end + + __typedef(StrPtrConverter, :strptr) + + # Load all the platform dependent types + begin + File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f| + prefix = "rbx.platform.typedef." + f.each_line { |line| + if line.index(prefix) == 0 + new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/) + __typedef(orig_type.to_sym, new_type.to_sym) + end + } + end + __typedef :pointer, :caddr_t + rescue Errno::ENOENT + end + + FFI.make_shareable(TypeDefs) unless writable_typemap +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/union.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/union.rb new file mode 100644 index 00000000..38414ab9 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/union.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2009 Andrea Fazzi +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/struct' + +module FFI + + class Union < FFI::Struct + def self.builder + b = StructLayoutBuilder.new + b.union = true + b + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/variadic.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/variadic.rb new file mode 100644 index 00000000..ee334091 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/variadic.rb @@ -0,0 +1,80 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# Copyright (C) 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + class VariadicInvoker + def call(*args, &block) + param_types = Array.new(@fixed) + param_values = Array.new + @fixed.each_with_index do |t, i| + param_values << args[i] + end + i = @fixed.length + while i < args.length + param_types << FFI.find_type(args[i], @type_map) + param_values << args[i + 1] + i += 2 + end + invoke(param_types, param_values, &block) + end + + # + # Attach the invoker to module +mod+ as +mname+ + # + def attach(mod, mname) + invoker = self + params = "*args" + call = "call" + mname = mname.to_sym + mod.module_eval <<-code, __FILE__, __LINE__ + @ffi_functions = {} unless defined?(@ffi_functions) + @ffi_functions[#{mname.inspect}] = invoker + + def self.#{mname}(#{params}) + @ffi_functions[#{mname.inspect}].#{call}(#{params}) + end + + define_method(#{mname.inspect}, &method(#{mname.inspect})) + code + invoker + end + + # Retrieve Array of parameter types + # + # This method returns an Array of FFI types accepted as function parameters. + # + # @return [Array] + def param_types + [*@fixed, Type::Builtin::VARARGS] + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/version.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/version.rb new file mode 100644 index 00000000..d84d7ae8 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/lib/ffi/version.rb @@ -0,0 +1,3 @@ +module FFI + VERSION = '1.17.1' +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/rakelib/ffi_gem_helper.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/rakelib/ffi_gem_helper.rb new file mode 100644 index 00000000..74be1311 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/rakelib/ffi_gem_helper.rb @@ -0,0 +1,65 @@ +require 'bundler' +require 'bundler/gem_helper' + +class FfiGemHelper < Bundler::GemHelper + attr_accessor :cross_platforms + + def install + super + + task "release:guard_clean" => ["release:update_history"] + + task "release:update_history" do + update_history + end + + task "release:rubygem_push" => ["gem:native", "gem:java"] + end + + def hfile + "CHANGELOG.md" + end + + def headline + '([^\w]*)(\d+\.\d+\.\d+(?:\.\w+)?)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)' + end + + def reldate + Time.now.strftime("%Y-%m-%d") + end + + def update_history + hin = File.read(hfile) + hout = hin.sub(/#{headline}/) do + raise "#{hfile} isn't up-to-date for version #{version}" unless $2==version.to_s + $1 + $2 + $3 + reldate + $5 + end + if hout != hin + Bundler.ui.confirm "Updating #{hfile} for release." + File.write(hfile, hout) + Rake::FileUtilsExt.sh "git", "commit", hfile, "-m", "Update release date in #{hfile}" + end + end + + def tag_version + Bundler.ui.confirm "Tag release with annotation:" + m = File.read(hfile).match(/(?#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}") + Bundler.ui.info(m[:annotation].gsub(/^/, " ")) + IO.popen(["git", "tag", "--file=-", version_tag], "w") do |fd| + fd.write m[:annotation] + end + yield if block_given? + rescue + Bundler.ui.error "Untagging #{version_tag} due to error." + sh_with_code "git tag -d #{version_tag}" + raise + end + + def rubygem_push(path) + cross_platforms.each do |ruby_platform| + super(path.gsub(/\.gem\z/, "-#{ruby_platform}.gem")) + end + super(path.gsub(/\.gem\z/, "-java.gem")) + super(path) + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getlogin.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getlogin.rb new file mode 100644 index 00000000..6713021d --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getlogin.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :getlogin, [ ], :string +end +puts "getlogin=#{Foo.getlogin}" diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getpid.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getpid.rb new file mode 100644 index 00000000..1720635b --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/getpid.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :getpid, [ ], :int +end +puts "My pid=#{Foo.getpid}" diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/gettimeofday.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/gettimeofday.rb new file mode 100644 index 00000000..864bbb62 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/gettimeofday.rb @@ -0,0 +1,18 @@ +require 'ffi' +require 'rbconfig' + +class Timeval < FFI::Struct + layout tv_sec: :ulong, tv_usec: :ulong +end +module LibC + extend FFI::Library + if FFI::Platform.windows? + ffi_lib RbConfig::CONFIG["LIBRUBY_SO"] + else + ffi_lib FFI::Library::LIBC + end + attach_function :gettimeofday, [ :pointer, :pointer ], :int +end +t = Timeval.new +LibC.gettimeofday(t.pointer, nil) +puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}" diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello.rb new file mode 100644 index 00000000..f2ccf377 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function("cputs", "puts", [ :string ], :int) +end +Foo.cputs("Hello, World via libc puts using FFI on MRI ruby") diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello_ractor.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello_ractor.rb new file mode 100644 index 00000000..904fe854 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/hello_ractor.rb @@ -0,0 +1,11 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function("cputs", "puts", [ :string ], :int) + freeze +end +Ractor.new do + Foo.cputs("Hello, World via libc puts using FFI in a Ractor") +end.take diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/inotify.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/inotify.rb new file mode 100644 index 00000000..018d78cf --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/inotify.rb @@ -0,0 +1,60 @@ +require 'ffi' + +module Inotify + extend FFI::Library + ffi_lib FFI::Library::LIBC + class Event < FFI::Struct + layout \ + :wd, :int, + :mask, :uint, + :cookie, :uint, + :len, :uint + end + attach_function :init, :inotify_init, [ ], :int + attach_function :add_watch, :inotify_add_watch, [ :int, :string, :uint ], :int + attach_function :rm_watch, :inotify_rm_watch, [ :int, :uint ], :int + attach_function :read, [ :int, :buffer_out, :uint ], :int + IN_ACCESS=0x00000001 + IN_MODIFY=0x00000002 + IN_ATTRIB=0x00000004 + IN_CLOSE_WRITE=0x00000008 + IN_CLOSE_NOWRITE=0x00000010 + IN_CLOSE=(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) + IN_OPEN=0x00000020 + IN_MOVED_FROM=0x00000040 + IN_MOVED_TO=0x00000080 + IN_MOVE= (IN_MOVED_FROM | IN_MOVED_TO) + IN_CREATE=0x00000100 + IN_DELETE=0x00000200 + IN_DELETE_SELF=0x00000400 + IN_MOVE_SELF=0x00000800 + # Events sent by the kernel. + IN_UNMOUNT=0x00002000 + IN_Q_OVERFLOW=0x00004000 + IN_IGNORED=0x00008000 + IN_ONLYDIR=0x01000000 + IN_DONT_FOLLOW=0x02000000 + IN_MASK_ADD=0x20000000 + IN_ISDIR=0x40000000 + IN_ONESHOT=0x80000000 + IN_ALL_EVENTS=(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \ + | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \ + | IN_MOVED_TO | IN_CREATE | IN_DELETE \ + | IN_DELETE_SELF | IN_MOVE_SELF) + +end +if $0 == __FILE__ + fd = Inotify.init + puts "fd=#{fd}" + wd = Inotify.add_watch(fd, "/tmp/", Inotify::IN_ALL_EVENTS) + fp = FFI::IO.for_fd(fd) + puts "wfp=#{fp}" + while true + buf = FFI::Buffer.alloc_out(Inotify::Event.size + 4096, 1, false) + ev = Inotify::Event.new buf + ready = IO.select([ fp ], nil, nil, nil) + n = Inotify.read(fd, buf, buf.total) + puts "Read #{n} bytes from inotify fd" + puts "event.wd=#{ev[:wd]} mask=#{ev[:mask]} len=#{ev[:len]} name=#{ev[:len] > 0 ? buf.get_string(16) : 'unknown'}" + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/pty.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/pty.rb new file mode 100644 index 00000000..8b6b885f --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/pty.rb @@ -0,0 +1,75 @@ +require 'ffi' + +module PTY + private + module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int + attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int + attach_function :login_tty, [ :int ], :int + attach_function :close, [ :int ], :int + attach_function :strerror, [ :int ], :string + attach_function :fork, [], :int + attach_function :execv, [ :string, :buffer_in ], :int + attach_function :execvp, [ :string, :buffer_in ], :int + attach_function :dup2, [ :int, :int ], :int + attach_function :dup, [ :int ], :int + end + Buffer = FFI::Buffer + def self.build_args(args) + cmd = args.shift + cmd_args = args.map do |arg| + MemoryPointer.from_string(arg) + end + exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1) + exec_cmd = MemoryPointer.from_string(cmd) + exec_args[0].put_pointer(0, exec_cmd) + cmd_args.each_with_index do |arg, i| + exec_args[i + 1].put_pointer(0, arg) + end + [ cmd, exec_args ] + end + public + def self.getpty(*args) + mfdp = Buffer.new :int + name = Buffer.new 1024 + # + # All the execv setup is done in the parent, since doing anything other than + # execv in the child after fork is really flakey + # + exec_cmd, exec_args = build_args(args) + pid = LibC.forkpty(mfdp, name, nil, nil) + raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0 + if pid == 0 + LibC.execvp(exec_cmd, exec_args) + exit 1 + end + masterfd = mfdp.get_int(0) + rfp = FFI::IO.for_fd(masterfd, "r") + wfp = FFI::IO.for_fd(LibC.dup(masterfd), "w") + if block_given? + yield rfp, wfp, pid + rfp.close unless rfp.closed? + wfp.close unless wfp.closed? + else + [ rfp, wfp, pid ] + end + end + def self.spawn(*args, &block) + self.getpty("/bin/sh", "-c", args[0], &block) + end +end +module LibC + extend FFI::Library + attach_function :close, [ :int ], :int + attach_function :write, [ :int, :buffer_in, :ulong ], :long + attach_function :read, [ :int, :buffer_out, :ulong ], :long +end +PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid| +#PTY.spawn("ls -laR /") { |rfd, wfd, pid| + puts "child pid=#{pid}" + while !rfd.eof? && (buf = rfd.gets) + puts "child: '#{buf.strip}'" + end +} diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort.rb new file mode 100644 index 00000000..58622c16 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort.rb @@ -0,0 +1,20 @@ +require 'ffi' + +module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + callback :qsort_cmp, [ :pointer, :pointer ], :int + attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int +end + +p = FFI::MemoryPointer.new(:int, 2) +p.put_array_of_int32(0, [ 2, 1 ]) +puts "ptr=#{p.inspect}" +puts "Before qsort #{p.get_array_of_int32(0, 2).join(', ')}" +LibC.qsort(p, 2, 4) do |p1, p2| + i1 = p1.get_int32(0) + i2 = p2.get_int32(0) + puts "In block: comparing #{i1} and #{i2}" + i1 < i2 ? -1 : i1 > i2 ? 1 : 0 +end +puts "After qsort #{p.get_array_of_int32(0, 2).join(', ')}" diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort_ractor.rb b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort_ractor.rb new file mode 100644 index 00000000..db085de2 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/samples/qsort_ractor.rb @@ -0,0 +1,28 @@ +require 'ffi' + +module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + callback :qsort_cmp, [ :pointer, :pointer ], :int + attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int + + freeze # Freeze the module variables, so that it can be shared across ractors. +end + +p = FFI::MemoryPointer.new(:int, 3) +p.put_array_of_int32(0, [ 2, 3, 1 ]) # Write some unsorted data into the memory +# Ractor.make_shareable(p) # freeze the pointer to be shared between ractors instead of copied +puts "main -ptr=#{p.inspect}" +res = Ractor.new(p) do |p| + puts "ractor-ptr=#{p.inspect}" + puts "Before qsort #{p.get_array_of_int32(0, 3).join(', ')}" + LibC.qsort(p, 3, 4) do |p1, p2| + i1 = p1.get_int32(0) + i2 = p2.get_int32(0) + puts "In block: comparing #{i1} and #{i2}" + i1 < i2 ? -1 : i1 > i2 ? 1 : 0 + end + puts "After qsort #{p.get_array_of_int32(0, 3).join(', ')}" +end.take + +puts "After ractor termination #{p.get_array_of_int32(0, 3).join(', ')}" diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi.rbs new file mode 100644 index 00000000..c40ad6f2 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi.rbs @@ -0,0 +1,26 @@ +module FFI + type ffi_type = Type | Symbol + type ffi_auto_type = ffi_type | DataConverter[untyped, untyped, untyped] + type type_map = Hash[Symbol | DataConverter[untyped, untyped, untyped], Type] + + class CallbackInfo = FunctionType + class FunctionInfo = FunctionType + class NativeLibrary = DynamicLibrary + + VERSION: String + TypeDefs: type_map + + type current_process = Object + CURRENT_PROCESS: current_process + USE_THIS_PROCESS_AS_LIBRARY: current_process + + private def self.custom_typedefs: () -> type_map + def self.errno: () -> Integer + def self.errno=: (Integer) -> nil + def self.find_type: (ffi_auto_type name, ?type_map? type_map) -> Type + def self.make_shareable: [T] (T obj) -> T + def self.map_library_name: (_ToS lib) -> String + def self.type_size: (ffi_auto_type type) -> Integer + def self.typedef: (ffi_auto_type old, Symbol add) -> Type + alias self.add_typedef self.typedef +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs new file mode 100644 index 00000000..9678ad01 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs @@ -0,0 +1,165 @@ +module FFI + class AbstractMemory + interface _Size + def size: () -> Integer + end + include _Size + type type_size = Integer | _Size | Symbol + + type order_out = :big | :little + type order_in = order_out | :network + + def []: (Integer idx) -> instance + def clear: () -> self + def freeze: ... + def get: (ffi_type type, Integer offset) -> top + def put: (ffi_type type, Integer offset, top value) -> nil + def size_limit?: () -> bool + def type_size: () -> Integer + alias total size + + def get_int8: (Integer offset) -> Integer + def get_int16: (Integer offset) -> Integer + def get_int32: (Integer offset) -> Integer + def get_int64: (Integer offset) -> Integer + def get_uint8: (Integer offset) -> Integer + def get_uint16: (Integer offset) -> Integer + def get_uint32: (Integer offset) -> Integer + def get_uint64: (Integer offset) -> Integer + def get_char: (Integer offset) -> Integer + def get_short: (Integer offset) -> Integer + def get_int: (Integer offset) -> Integer + def get_long_long: (Integer offset) -> Integer + def get_float32: (Integer offset) -> Float + def get_float64: (Integer offset) -> Float + def get_pointer: (Integer offset) -> Pointer + def get_bytes: (Integer offset, Integer length) -> String + def get_string: (Integer offset, ?Integer? length) -> String + alias get_float get_float32 + alias get_double get_float64 + + def put_int8: (Integer offset, int value) -> self + def put_int16: (Integer offset, int value) -> self + def put_int32: (Integer offset, int value) -> self + def put_int64: (Integer offset, int value) -> self + def put_uint8: (Integer offset, int value) -> self + def put_uint16: (Integer offset, int value) -> self + def put_uint32: (Integer offset, int value) -> self + def put_uint64: (Integer offset, int value) -> self + def put_char: (Integer offset, int value) -> self + def put_short: (Integer offset, int value) -> self + def put_int: (Integer offset, int value) -> self + def put_long_long: (Integer offset, int value) -> self + def put_float32: (Integer offset, Numeric value) -> self + def put_float64: (Integer offset, Numeric value) -> self + def put_pointer: (Integer offset, pointer value) -> self + def put_bytes: (Integer offset, String str, ?Integer index, ?Integer? length) -> self + def put_string: (Integer offset, String value) -> self + alias put_float put_float32 + alias put_double put_float64 + + def read_int8: () -> Integer + def read_int16: () -> Integer + def read_int32: () -> Integer + def read_int64: () -> Integer + def read_uint8: () -> Integer + def read_uint16: () -> Integer + def read_uint32: () -> Integer + def read_uint64: () -> Integer + def read_char: () -> Integer + def read_short: () -> Integer + def read_int: () -> Integer + def read_long_long: () -> Integer + def read_float: () -> Float + def read_double: () -> Float + def read_pointer: () -> Pointer + def read_bytes: (Integer length) -> String + + def write_int8: (int value) -> self + def write_int16: (int value) -> self + def write_int32: (int value) -> self + def write_int64: (int value) -> self + def write_uint8: (int value) -> self + def write_uint16: (int value) -> self + def write_uint32: (int value) -> self + def write_uint64: (int value) -> self + def write_char: (int value) -> self + def write_short: (int value) -> self + def write_int: (int value) -> self + def write_long_long: (int value) -> self + def write_float: (Numeric value) -> self + def write_double: (Numeric value) -> self + def write_pointer: (pointer value) -> self + def write_bytes: (String str, ?Integer index, ?Integer? length) -> self + + def get_array_of_int8: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int16: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int32: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int64: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint8: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint16: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint32: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint64: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_char: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_short: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_long_long: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_float32: (Integer offset, Integer length) -> Array[Float] + def get_array_of_float64: (Integer offset, Integer length) -> Array[Float] + def get_array_of_pointer: (Integer offset, Integer length) -> Array[Pointer] + def get_array_of_string: (Integer offset, ?Integer? count) -> Array[String?] + alias get_array_of_float get_array_of_float32 + alias get_array_of_double get_array_of_float64 + + def put_array_of_int8: (Integer offset, Array[int] ary) -> self + def put_array_of_int16: (Integer offset, Array[int] ary) -> self + def put_array_of_int32: (Integer offset, Array[int] ary) -> self + def put_array_of_int64: (Integer offset, Array[int] ary) -> self + def put_array_of_uint8: (Integer offset, Array[int] ary) -> self + def put_array_of_uint16: (Integer offset, Array[int] ary) -> self + def put_array_of_uint32: (Integer offset, Array[int] ary) -> self + def put_array_of_uint64: (Integer offset, Array[int] ary) -> self + def put_array_of_char: (Integer offset, Array[int] ary) -> self + def put_array_of_short: (Integer offset, Array[int] ary) -> self + def put_array_of_int: (Integer offset, Array[int] ary) -> self + def put_array_of_long_long: (Integer offset, Array[int] ary) -> self + def put_array_of_float32: (Integer offset, Array[Numeric] ary) -> self + def put_array_of_float64: (Integer offset, Array[Numeric] ary) -> self + def put_array_of_pointer: (Integer offset, Array[pointer] ary) -> self + alias put_array_of_float put_array_of_float32 + alias put_array_of_double put_array_of_float64 + + def read_array_of_int8: (Integer length) -> Array[Integer] + def read_array_of_int16: (Integer length) -> Array[Integer] + def read_array_of_int32: (Integer length) -> Array[Integer] + def read_array_of_int64: (Integer length) -> Array[Integer] + def read_array_of_uint8: (Integer length) -> Array[Integer] + def read_array_of_uint16: (Integer length) -> Array[Integer] + def read_array_of_uint32: (Integer length) -> Array[Integer] + def read_array_of_uint64: (Integer length) -> Array[Integer] + def read_array_of_char: (Integer length) -> Array[Integer] + def read_array_of_short: (Integer length) -> Array[Integer] + def read_array_of_int: (Integer length) -> Array[Integer] + def read_array_of_long_long: (Integer length) -> Array[Integer] + def read_array_of_float: (Integer length) -> Array[Float] + def read_array_of_double: (Integer length) -> Array[Float] + def read_array_of_pointer: (Integer length) -> Array[Pointer] + def read_array_of_string: (?Integer? count) -> Array[String?] + + def write_array_of_int8: (Array[int] ary) -> self + def write_array_of_int16: (Array[int] ary) -> self + def write_array_of_int32: (Array[int] ary) -> self + def write_array_of_int64: (Array[int] ary) -> self + def write_array_of_uint8: (Array[int] ary) -> self + def write_array_of_uint16: (Array[int] ary) -> self + def write_array_of_uint32: (Array[int] ary) -> self + def write_array_of_uint64: (Array[int] ary) -> self + def write_array_of_char: (Array[int] ary) -> self + def write_array_of_short: (Array[int] ary) -> self + def write_array_of_int: (Array[int] ary) -> self + def write_array_of_long_long: (Array[int] ary) -> self + def write_array_of_float: (Array[Numeric] ary) -> self + def write_array_of_double: (Array[Numeric] ary) -> self + def write_array_of_pointer: (Array[pointer] ary) -> self + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs new file mode 100644 index 00000000..cd289c6f --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs @@ -0,0 +1,26 @@ +module FFI + class AutoPointer < Pointer + class Releaser + attr_accessor autorelease: boolish + interface _Proc[P < Pointer] + def call: (P) -> void + end + def initialize: [P < Pointer] (P ptr, _Proc[P] proc) -> void + + def call: (*untyped) -> void + def free: () -> nil + def release: (Pointer ptr) -> void + end + + def initialize: (Pointer pointer, Method | ^(self) -> void | Releaser::_Proc[self] callable) -> self + | (Pointer pointer) -> self # where class < `def self.release: (instance pointer) -> void` + + extend DataConverter[Pointer, instance, nil] + def self.from_native: ... + def self.native_type: () -> Type::Builtin + + def autorelease?: ... + def autorelease=: ... + def free: () -> nil + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/buffer.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/buffer.rbs new file mode 100644 index 00000000..68cde6bc --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/buffer.rbs @@ -0,0 +1,18 @@ +module FFI + class Buffer < AbstractMemory + def initialize: (AbstractMemory::type_size, ?Integer count, boolish clear) -> self + alias self.alloc_inout self.new + alias self.new_inout self.alloc_inout + alias self.alloc_in self.alloc_inout + alias self.new_in self.alloc_in + alias self.alloc_out self.alloc_inout + alias self.new_out self.alloc_out + + def +: (Integer) -> Buffer + def inspect: ... + def order: () -> AbstractMemory::order_out + | (AbstractMemory::order_in order) -> Buffer + | (untyped order) -> (self | Buffer) + def slice: (Integer offset, Integer length) -> Buffer + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/data_converter.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/data_converter.rbs new file mode 100644 index 00000000..a0e2e39f --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/data_converter.rbs @@ -0,0 +1,10 @@ +module FFI + interface _DataConverter[N, R, in C] + def from_native: (N value, C ctx) -> R + def native_type: (?ffi_auto_type? type) -> Type + def to_native: (R value, C ctx) -> N + end + module DataConverter[N, R, in C] + include _DataConverter[N, R, C] + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs new file mode 100644 index 00000000..48031bfa --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs @@ -0,0 +1,9 @@ +module FFI + class DynamicLibrary + # TODO + + class Symbol < Pointer + # TODO + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/enum.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/enum.rbs new file mode 100644 index 00000000..3cae0b2d --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/enum.rbs @@ -0,0 +1,38 @@ +module FFI + class Enums + def initialize: () -> void + + def <<: (Enum enum) -> void + def __map_symbol: (Symbol symbol) -> Integer? + def find: (Symbol query) -> Enum + end + + class Enum + include DataConverter[Integer, Symbol | Integer, untyped] + + attr_reader native_type: Type + attr_reader tag: Symbol? + def initialize: (Enumerable[Symbol | Integer], ?Symbol? tag, *untyped) -> void + | (Type native_type, Enumerable[Symbol | Integer], ?Symbol? tag, *untyped) -> void + + def []: (Symbol query) -> Integer? + | (Integer query) -> Symbol? + def symbol_map: () -> Hash[Symbol, Integer] + alias to_h symbol_map + alias to_hash symbol_map + def symbols: () -> Array[Symbol] + def to_native: (Symbol | int value, untyped ctx) -> Integer + end + + class Bitmask < Enum + def initialize: ... + + def []: (*Symbol query) -> Integer + | (Array[Symbol] query) -> Integer + | (*Integer query) -> Array[Symbol] + | (Array[Integer] query) -> Array[Symbol] + def from_native: (Integer, untyped ctx) -> Array[Symbol | Integer] + def to_native: (Array[Symbol | int] value, untyped ctx) -> Integer + | ... + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/function.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/function.rbs new file mode 100644 index 00000000..94a23c2d --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/function.rbs @@ -0,0 +1,39 @@ +module FFI + interface _Function + # TODO: leads to a endless recursion when used with -rrbs/test/setup + # def attach: (Module mod, String name) -> self + def call: (*untyped args) -> untyped + def param_types: () -> Array[Type] + def return_type: () -> Type + end + + class Function < Pointer + include _Function + # ?blocking: boolish?, ?convention: Library::convention?, ?enums: Enums? + def initialize: + ( + ffi_type return_type, Array[ffi_type] param_types, + ?Hash[Symbol, untyped] options + ) { (*untyped) -> untyped } -> self + | ( + ffi_type return_type, Array[ffi_type] param_types, Proc | Pointer proc, + ?Hash[Symbol, untyped] options + ) -> self + + def autorelease?: ... + alias autorelease autorelease? + def autorelease=: ... + def free: () -> self + end + + class VariadicInvoker + include _Function + def initialize: + ( + Pointer function, Array[ffi_type] parameter_types, ffi_type return_type, + Hash[Symbol, untyped] options #TODO + ) -> void + + def invoke: (Array[Type] parameter_types, Array[untyped] parameter_values) -> untyped + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/library.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/library.rbs new file mode 100644 index 00000000..e823b6d2 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/library.rbs @@ -0,0 +1,42 @@ +module FFI + module Library + type convention = :default | :stdcall + type ffi_lib_flag = :global | :local | :lazy | :now + type ffi_lib_type = ffi_auto_type | singleton(Struct) + + CURRENT_PROCESS: current_process + LIBC: String + FlagsMap: Hash[ffi_lib_flag, Integer] + + def self.extended: ... + + def attach_function: ( _ToS func, Array[ffi_lib_type] args, ffi_lib_type? returns, ?blocking: boolish, ?convention: convention, ?enums: Enums, ?type_map: type_map) -> (Function | VariadicInvoker) + | (_ToS name, _ToS func, Array[ffi_lib_type] args, ?ffi_lib_type? returns, ?blocking: boolish, ?convention: convention, ?enums: Enums, ?type_map: type_map) -> (Function | VariadicInvoker) + def attach_variable: (?_ToS mname, _ToS cname, ffi_lib_type type) -> DynamicLibrary::Symbol + def attached_functions: () -> Hash[Symbol, Function | VariadicInvoker] + def attached_variables: () -> Hash[Symbol, Type | singleton(Struct)] + + def bitmask: (?Type native_type, Symbol name, Array[Symbol | Integer] values) -> Bitmask + | (?Type native_type, *Symbol | Integer args) -> Bitmask + | (?Type native_type, Array[Symbol | Integer] values) -> Bitmask + def enum: (?Type native_type, Symbol name, Array[Symbol | Integer] values) -> Enum + | (?Type native_type, *Symbol | Integer args) -> Enum + | (?Type native_type, Array[Symbol | Integer] values) -> Enum + def enum_type: (Symbol name) -> Enum? + def enum_for: (Symbol name) -> Integer? + + def callback: (?Symbol name, Array[ffi_lib_type] params, ffi_lib_type ret) -> CallbackInfo + def ffi_convention: (?convention? convention) -> convention + def ffi_lib: (*_ToS names) -> Array[DynamicLibrary] + def ffi_lib_flags: (*ffi_lib_flag flags) -> Integer + def ffi_libraries: () -> Array[DynamicLibrary] + def find_type: (ffi_lib_type t) -> Type + def freeze: () -> void + def function_names: (_ToS name, Array[Type | singleton(Struct)] arg_types) -> Array[String] + def typedef: [T < Type, N, R, C] (T old, Symbol | DataConverter[N, R, C] add, ?untyped) -> T + | (Symbol old, Symbol add, ?untyped) -> (Type | Enum) + | [X < DataConverter[N, R, C], N, R, C] (X old, Symbol add, ?untyped) -> Type::Mapped[X, N, R, C] + | (:enum old, Array[Symbol | Integer] add, ?untyped) -> Enum + | (:enum old, Symbol | Type add, Array[Symbol | Integer] info) -> Enum + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/native_type.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/native_type.rbs new file mode 100644 index 00000000..c9617a03 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/native_type.rbs @@ -0,0 +1,86 @@ +module FFI + class Type + INT8: Builtin + SCHAR: Builtin + CHAR: Builtin + UINT8: Builtin + UCHAR: Builtin + INT16: Builtin + SHORT: Builtin + SSHORT: Builtin + UINT16: Builtin + USHORT: Builtin + INT32: Builtin + INT: Builtin + SINT: Builtin + UINT32: Builtin + UINT: Builtin + INT64: Builtin + LONG_LONG: Builtin + SLONG_LONG: Builtin + UINT64: Builtin + ULONG_LONG: Builtin + LONG: Builtin + SLONG: Builtin + ULONG: Builtin + FLOAT32: Builtin + FLOAT: Builtin + FLOAT64: Builtin + DOUBLE: Builtin + LONGDOUBLE: Builtin + POINTER: Builtin + BOOL: Builtin + STRING: Builtin + BUFFER_IN: Builtin + BUFFER_OUT: Builtin + BUFFER_INOUT: Builtin + VARARGS: Builtin + VOID: Builtin + end + + module NativeType + INT8: Type::Builtin + UINT8: Type::Builtin + INT16: Type::Builtin + UINT16: Type::Builtin + INT32: Type::Builtin + UINT32: Type::Builtin + INT64: Type::Builtin + UINT64: Type::Builtin + LONG: Type::Builtin + ULONG: Type::Builtin + FLOAT32: Type::Builtin + FLOAT64: Type::Builtin + LONGDOUBLE: Type::Builtin + POINTER: Type::Builtin + BOOL: Type::Builtin + STRING: Type::Builtin + BUFFER_IN: Type::Builtin + BUFFER_OUT: Type::Builtin + BUFFER_INOUT: Type::Builtin + VARARGS: Type::Builtin + VOID: Type::Builtin + end + + TYPE_INT8: Type::Builtin + TYPE_UINT8: Type::Builtin + TYPE_INT16: Type::Builtin + TYPE_UINT16: Type::Builtin + TYPE_INT32: Type::Builtin + TYPE_UINT32: Type::Builtin + TYPE_INT64: Type::Builtin + TYPE_UINT64: Type::Builtin + TYPE_LONG: Type::Builtin + TYPE_ULONG: Type::Builtin + TYPE_FLOAT32: Type::Builtin + TYPE_FLOAT64: Type::Builtin + TYPE_LONGDOUBLE: Type::Builtin + TYPE_POINTER: Type::Builtin + TYPE_BOOL: Type::Builtin + TYPE_STRING: Type::Builtin + TYPE_BUFFER_IN: Type::Builtin + TYPE_BUFFER_OUT: Type::Builtin + TYPE_BUFFER_INOUT: Type::Builtin + TYPE_VARARGS: Type::Builtin + TYPE_VOID: Type::Builtin +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/pointer.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/pointer.rbs new file mode 100644 index 00000000..fd4e9b89 --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/pointer.rbs @@ -0,0 +1,42 @@ +module FFI + type pointer = Pointer::_ToPtr? | Integer + class Pointer < AbstractMemory + interface _ToPtr + def to_ptr: () -> Pointer + end + include _ToPtr + + SIZE: Integer + NULL: Pointer + def self.size: () -> Integer + + def initialize: (?AbstractMemory::type_size type, (Pointer | Integer) address) -> void + def +: (Integer offset) -> Pointer + def ==: (Pointer? other) -> bool + def address: () -> Integer + alias to_i address + def autorelease?: () -> bool + def autorelease=: (boolish autorelease) -> boolish + def free: () -> self + def inspect: ... + def null?: () -> bool + def order: () -> AbstractMemory::order_out + | (AbstractMemory::order_in) -> Pointer + def read: (ffi_type type) -> top + def read_array_of_type: (ffi_auto_type type, Symbol reader, Integer length) -> Array[top] + def read_string: (?Integer? len) -> String + def read_string_length: (Integer len) -> String + def read_string_to_null: () -> String + def slice: (Integer offset, Integer length) -> Pointer + def type_size: () -> Integer + def write: (ffi_type type, top value) -> nil + def write_array_of_type: (ffi_auto_type type, Symbol writer, Array[top]) -> self + def write_string: (String str, ?Integer? len) -> self + def write_string_length: (String str, Integer len) -> self + end + + class MemoryPointer < Pointer + def initialize: (AbstractMemory::type_size size, ?Integer count, ?boolish clear) -> self + def self.from_string: (String s) -> instance + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct.rbs new file mode 100644 index 00000000..5b349bfc --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct.rbs @@ -0,0 +1,76 @@ +module FFI + class Struct[out P < AbstractMemory, unchecked out E] + type layout = Library::ffi_lib_type | singleton(StructLayout::Field) | [layout, Integer] + + type ptr = Type::Mapped[ + StructByReference[Struct[AbstractMemory, untyped], AbstractMemory], + AbstractMemory, instance, untyped + ] + def self.ptr: (?untyped flags) -> ptr # https://github.com/ffi/ffi/issues/1073 + alias self.by_ref self.ptr + def self.in: () -> ptr + def self.out: () -> ptr + def self.val: () -> StructByValue[singleton(Struct)] + alias self.by_value self.val + + alias self.alloc_inout self.new + alias self.alloc_in self.new + alias self.alloc_out self.new + alias self.new_inout self.new + alias self.new_in self.new + alias self.new_out self.new + + def self.auto_ptr: () -> Type::Mapped[ + ManagedStructConverter[ManagedStruct[AutoPointer, untyped], AutoPointer], + Pointer, instance, untyped + ] + def self.layout: (*layout | Integer) -> StructLayout + | (Hash[Symbol, layout]) -> StructLayout + def self.size=: (Integer size) -> Integer + + def self?.alignment: () -> Integer + def self?.members: () -> Array[Symbol] + def self?.offset_of: (Symbol name) -> Integer + def self?.offsets: () -> Array[[Symbol, Integer]] + def self?.size: -> Integer + + def initialize: (?P pointer, *layout args) -> void + def []: (Symbol field_name) -> E + def []=: (Symbol field_name, E value) -> E + alias align alignment + def clear: () -> self + def layout: () -> StructLayout + def null?: () -> bool + def order: (AbstractMemory::order_in order) -> Struct[P, E] + | () -> AbstractMemory::order_out + def pointer: () -> P + alias to_ptr pointer + def values: () -> Array[E] + + class InlineArray[out P < AbstractMemory, unchecked out E] + include Enumerable[E] + include AbstractMemory::_Size + + def initialize: (P memory, StructLayout::Field field) -> self + def []: (Integer index) -> E + def []=: (Integer index, E value) -> E + def each: () { (E) -> void } -> self + def to_a: () -> Array[E] + def to_ptr: () -> P + end + + class ManagedStructConverter[S < ManagedStruct[P, untyped], P < AutoPointer] < StructByReference[S, P] + def initialize: ... + def from_native: (Pointer ptr, untyped ctx) -> S + end + end + + class ManagedStruct[out P < AutoPointer, unchecked out E] < Struct[P, E] + def self.release: (AbstractMemory ptr) -> void + def initialize: (Pointer pointer) -> self + end + + class Union[out P < AbstractMemory, unchecked out E] < Struct[P, E] + def self.builder: () -> StructLayoutBuilder + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs new file mode 100644 index 00000000..475b483e --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs @@ -0,0 +1,11 @@ +module FFI + class StructByReference[S < Struct[P, untyped], P < AbstractMemory] + include DataConverter[P, S, untyped] + attr_reader struct_class: Struct[P, untyped] + + def initialize: (S struct_class) -> void + def from_native: (P value, untyped ctx) -> S + def native_type: () -> Type::Builtin + def to_native: (S? value, untyped ctx) -> P + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs new file mode 100644 index 00000000..902bcc6b --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs @@ -0,0 +1,7 @@ +module FFI + class StructByValue[C < singleton(Struct)] < Type + def initialize: (C) -> self + def layout: () -> StructLayout + def struct_class: () -> C + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout.rbs new file mode 100644 index 00000000..12b05aed --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout.rbs @@ -0,0 +1,9 @@ +module FFI + class StructLayout + #TODO + + class Field + #TODO + end + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs new file mode 100644 index 00000000..291a669a --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs @@ -0,0 +1,5 @@ +module FFI + class StructLayoutBuilder + #TODO + end +end diff --git a/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/type.rbs b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/type.rbs new file mode 100644 index 00000000..66186d1a --- /dev/null +++ b/bin/gems/ffi-1.17.1-x86_64-linux-gnu/sig/ffi/type.rbs @@ -0,0 +1,39 @@ +module FFI + class Type + class Array = ArrayType + class Function = FunctionType + class Struct = StructByValue + + include AbstractMemory::_Size + def initialize: (Integer | Type value) -> self + def alignment: () -> Integer + def inspect: ... + + class Builtin < Type + def inspect: ... + end + + class Mapped[X < _DataConverter[N, R, C], N, R, C] + include _DataConverter[N, R, C] + + def initialize: (X converter) -> self + def converter: () -> X + end + end + + class ArrayType + def initialize: (Type component_type, Integer length) -> self + def element_type: -> Type + def length: -> Integer + end + + class FunctionType < Type + def initialize: + ( + ffi_type return_type, Array[ffi_type] param_types, + ?blocking: boolish, ?convention: Library::convention, ?enums: Enums + ) -> self + def param_types: () -> Array[Type] + def return_type: () -> Type + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/CHANGELOG.md b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/CHANGELOG.md new file mode 100644 index 00000000..95e32c27 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/CHANGELOG.md @@ -0,0 +1,507 @@ +1.17.4 / 2026-03-26 +------------------- + +Fixed: +* Fix union by-value ABI mismatch with float and double types on ARM64 and X86_64. + See #1177 and #1178 for details. +* Exclude libffi files, which are unnecessary. #1176 + + +1.17.3 / 2025-12-29 +------------------- + +Fixed: +* Opt-in for MFA requirement explicitly. #1159 +* Fix type signature for FFI::AutoPointer#initialize, FFI::StructByReference#native_type and FFI::Struct#auto_ptr . #1158 +* Fix function signature of function_call in FFI trampoline. #1154 + It failed on `aarch64-mingw-ucrt`. +* Add workaround for segmentation faults on `aarch64-mingw-ucrt`. #1154 +* Call super in `Library#freeze` . #1154 +* Deny duplication of AutoPointer per #dup and #clone . #1173 + They led to double free before. + +Added: +* Add binary gems for Ruby-4.0, now providing binary gems for Ruby-3.0 to 4.0. +* Add msys2_mingw_dependencies for Windows Mingw for automatic installation of libffi. #1143 +* Mark callback dispatcher thread as fork safe for Puma. #1156 +* Add missing FFI::Platform module and LastError signatures. #1169 + +Removed: +* Drop fat binary gems for Ruby < 3.0 +* Remove `FFI::TypesGenerator` from distributed gems. #1164 +* Remove libffi build dir after install, safing some install space. #1157 + + +1.17.2 / 2025-04-15 +------------------- + +Fixed: +* #1144, #1145 Update libffi to 3.4.8 to fix installation issues on latest Macos on ARM64 +* Various adjustments to run the specs cleanly on Ruby-3.5 master branch. + + +1.17.1 / 2024-12-30 +------------------- + +Fixed: +* #1117 Restart async callback dispatcher thread after fork. +* #1133 Add ruby-3.4 native gem. +* #1134 Fix FFI::DataConverter non-generic usage in RBS files. + + +1.17.0 / 2024-06-02 +------------------- + +Fixed: +* Add FFI::AbstractMemory#read_array_of_string . It was defined but not exposed to Ruby nor tested. #1070 + + +1.17.0.rc2 / 2024-04-22 +------------------- + +Fixed: +* Add missing write barriers to StructLayout#initialize causing a segfault with GC.stress. #1079 + + +1.17.0.rc1 / 2024-04-08 +------------------- + +Fixed: +* Fix type definitions on `aarch64-linux`. #1067, #1066 +* Use RB_TEST for `Pointer.autorelease=` . #1065 + So that `false` and `nil` are treated as falsey and anything else as truthy. +* Replace Fixnum by Integer. #1064 + Fixnum is no longer present in the ruby language. +* Update `FFI::NativeType` doc. #1061 +* Store FFI::Type::Mapped of FFI::StrPtrConverter in global instead of custom type map +* Various documentation fixes. #1042 +* Update `FFI::Pointer#==` to return `false` if a pointer is compared to a non-pointer object, which is the expected behavior. #1083 +* Avoid warning about undefined wariable `@ffi_functions` #1085 +* Fix a very unlikely GC bug when using a callback block. # 1089 + +Added: +* Provide binary gems for many platforms. #990 +* Add Windows fat binary gem for Ruby-3.3 +* Add RBS type definitions for many user facing parts of the FFI API. #1042 +* Improve fallback search path logic. #1088 + Respect LD_LIBRARY_PATH and DYLD_LIBRARY_PATH on Macos. +* Update libffi to current git master branch. + +Removed: +* Remove `enum CHAR_ARRAY` which is no longer used. #1063 + + +1.16.3 / 2023-10-04 +------------------- + +Fixed: +* Fix gcc error when building on CentOS 7. #1052 +* Avoid trying to store new DataConverter type in frozen TypeDefs hash. #1057 + + +1.16.2 / 2023-09-25 +------------------- + +Fixed: +* Handle null pointer crash after fork. #1051 + + +1.16.1 / 2023-09-24 +------------------- + +Fixed: +* Fix compiling the builtin libffi. #1049 + + +1.16.0 / 2023-09-23 +------------------- + +Fixed: +* Fix an issue with signed bitmasks when using flags on the most significant bit. #949 +* Fix FFI::Pointer#initialize using NUM2LL instead of NUM2ULL. +* Fix FFI::Type#inspect to properly display the constant name. #1002 +* Use libffi closure allocations on hppa-Linux. #1017 + Previously they would segfault. +* Fix class name of Symbol#inspect. +* Fix MSVC support of libtest. #1028 +* Fix attach_function of functions ending in ? or ! #971 + +Added: +* Convert all C-based classes to TypedData and use write barriers. #994, #995, #996, #997, #998, #999, #1000, #1001, #1003, #1004, #1005, #1006, #1007, #1008, #1009, #1010, #1011, #1012 + This results in less pressure on the garbage collector, since the objects can be promoted to the old generation, which means they only get marked on major GC. +* Implement `ObjectSpace.memsize_of()` of all C-based classes. +* Make FFI Ractor compatible. #1023 + Modules extended per `extend FFI::Library` need to be frozen in order to be used by non-main Ractors. + This can be done by calling `freeze` below of all C interface definitions. + * In a Ractor it's possible to: + * load DLLs and call its functions, access its global variables + * use builtin typedefs + * use and modify ractor local typedefs + * define callbacks + * receive async callbacks from non-ruby threads + * use frozen FFI::Library based modules with all attributes (enums, structs, typedefs, functions, callbacks) + * invoke frozen functions and callbacks defined in the main Ractor + * use FFI::Struct definitions from the main Ractor + * In a Ractor it's impossible to: + * create new FFI::Library based modules + * create new FFI::Struct definitions + * use custom global typedefs + * use non-frozen FFI::Library based modules +* Allow type retrieval of attached functions+variables. #1023 +* Make FFI classes `GC.compact` friendly. #1021 +* Update libffi and disable custom trampoline when using libffi closure allocation. #1020 + This is because libffi changed the way how closures are allocated to static trampolines. +* Add types.conf for loongarch64-linux. #943 +* Add types.conf for sw_64-linux (Shen Wei 64-bit, based on Alpha). #1018 +* Add support for aarch64-windows. #1035 +* Windows: Update LoadLibrary error message to include error code. #1026 +* Allow private release method for FFI::ManagedStruct and FFI::AutoPointer. #1029 +* Add support for passing ABI version to FFI.map_library_name. #963 + This adds the new class FFI::LibraryPath . +* Add support for ruby-3.2 to windows binary gem. #1047 +* Enable debug symbols for `rake compile` builds to ease debugging. #1048 + +Removed: +* Remove allocator of AbstractMemory. #1013 + This disables AbstractMemory.new, which has no practical use. +* Remove unused FFI::SizeTypes. #1022 + + +1.15.5 / 2022-01-10 +------------------- + +Fixed: +* Fix long double argument or return values on 32bit i686. #849 +* FFI::ConstGenerator: avoid usage of the same binary file simultaneously. #929 + +Added: +* Add Windows fat binary gem for Ruby-3.1 + +Removed: +* Remove Windows fat binary gem for Ruby < 2.4 + + +1.15.4 / 2021-09-01 +------------------- + +Fixed: +* Fix build for uClibc. #913 +* Correct module lookup when including `ffi-module` gem. #912 + +Changed: +* Use ruby code of the ffi gem in JRuby-9.2.20+. #915 + + +1.15.3 / 2021-06-16 +------------------- + +Fixed: +* Fix temporary packaging issue with libffi. #904 + + +1.15.2 / 2021-06-16 +------------------- + +Added: +* Add support for Windows MINGW-UCRT build. #903 +* Add `/opt/homebrew/lib/` to fallback search paths to improve homebrew support. #880 #882 + +Changed: +* Regenerate `types.conf` for FreeBSD12 aarch64. #902 + + +1.15.1 / 2021-05-22 +------------------- + +Fixed: +* Append -pthread to linker options. #893 +* Use arm or aarch64 to identify Apple ARM CPU arch. #899 +* Allow overriding `gcc` with the `CC` env var in `const_generator.rb` and `struct_generator.rb`. #897 + + +1.15.0 / 2021-03-05 +------------------- + +Fixed: +* Fix MSVC build +* Fix async callbacks in conjunction with fork(). #884 + +Added: +* Allow to pass callbacks in varargs. #885 +* Name the threads for FFI callback dispatcher and async thread calls for easier debugging. #883 + The name can be retrieved by Thread.name and is shown by Thread.list.inspect etc. + Even gdb shows the thread name on supported operating systems. +* Add types.conf for powerpc64le-linux +* Add types.conf for riscv64-linux +* More release automation of ffi gems + +Changed: +* Switch from rubygems-tasks to bundler/gem_helper + +Removed: +* Remove unused VariadicInvoker#init + + +1.14.2 / 2020-12-21 +------------------- + +Fixed: +* Fix builtin libffi on newer Ubuntu caused by an outdated Makefile.in . #863 + + +1.14.1 / 2020-12-19 +------------------- + +Changed: +* Revert changes to FFI::Pointer#write_string made in ffi-1.14.0. + It breaks compatibilty in a way that can cause hard to find errors. #857 + + +1.14.0 / 2020-12-18 +------------------- + +Added: +* Add types.conf for x86_64-msys, x86_64-haiku, aarch64-openbsd and aarch64-darwin (alias arm64-darwin) +* Add method AbstractMemory#size_limit? . #829 +* Add new extconf option --enable-libffi-alloc which is enabled per default on Apple M1 (arm64-darwin). + +Changed: +* Do NULL pointer check only when array length > 0 . #305 +* Raise an error on an unknown order argument. #830 +* Change FFI::Pointer#write_string to terminate with a NUL byte like other string methods. #805 +* Update bundled libffi to latest master. + +Removed: +* Remove win32/stdint.h and stdbool.h because of copyright issue. #693 + +Fixed: +* Fix possible UTF-8 load error in loader script interpretation. #792 +* Fix segfault on non-array argument to #write_array_of_* +* Fix memory leak in MethodHandle . #815 +* Fix possible segfault in combination with fiddle or other libffi using gems . #835 +* Fix possibility to use ffi ruby gem with JRuby-9.3 . #763 +* Fix a GC issue, when a callback Proc is used on more than 2 callback signatures. #820 + + +1.13.1 / 2020-06-09 +------------------- + +Changed: +* Revert use of `ucrtbase.dll` as default C library on Windows-MINGW. + `ucrtbase.dll` is still used on MSWIN target. #790 +* Test for `ffi_prep_closure_loc()` to make sure we can use this function. + This fixes incorrect use of system libffi on MacOS Mojave (10.14). #787 +* Update types.conf on x86_64-dragonflybsd + + +1.13.0 / 2020-06-01 +------------------- + +Added: +* Add TruffleRuby support. Almost all specs are running on TruffleRuby and succeed. #768 +* Add ruby source files to the java gem. This allows to ship the Ruby library code per platform java gem and add it as a default gem to JRuby. #763 +* Add FFI::Platform::LONG_DOUBLE_SIZE +* Add bounds checks for writing to an inline char[] . #756 +* Add long double as callback return value. #771 +* Update type definitions and add types from stdint.h and stddef.h on i386-windows, x86_64-windows, x86_64-darwin, x86_64-linux, arm-linux, powerpc-linux. #749 +* Add new type definitions for powerpc-openbsd and sparcv9-openbsd. #775, #778 + +Changed: +* Raise required ruby version to >= 2.3. +* Lots of cleanups and improvements in library, specs and benchmarks. +* Fix a lot of compiler warnings at the C-extension +* Fix several install issues on MacOS: + * Look for libffi in SDK paths, since recent versions of macOS removed it from `/usr/include` . #757 + * Fix error `ld: library not found for -lgcc_s.10.4` + * Don't built for i386 architecture as it is deprecated +* Several fixes for MSVC build on Windows. #779 +* Use `ucrtbase.dll` as default C library on Windows instead of old `msvcrt.dll`. #779 +* Update builtin libffi to fix a Powerpc issue with parameters of type long +* Allow unmodified sourcing of (the ruby code of) this gem in JRuby and TruffleRuby as a default gem. #747 +* Improve check to detect if a module has a #find_type method suitable for FFI. This fixes compatibility with stdlib `mkmf` . #776 + +Removed: +* Reject callback with `:string` return type at definition, because it didn't work so far and is not save to use. #751, #782 + + +1.12.2 / 2020-02-01 +------------------- + +* Fix possible segfault at FFI::Struct#[] and []= after GC.compact . #742 + + +1.12.1 / 2020-01-14 +------------------- + +Added: +* Add binary gem support for ruby-2.7 on Windows + + +1.12.0 / 2020-01-14 +------------------- + +Added: +* FFI::VERSION is defined as part of `require 'ffi'` now. + It is no longer necessary to `require 'ffi/version'` . + +Changed: +* Update libffi to latest master. + +Deprecated: +* Overwriting struct layouts is now warned and will be disallowed in ffi-2.0. #734, #735 + + +1.11.3 / 2019-11-25 +------------------- + +Removed: +* Remove support for tainted objects which cause deprecation warnings in ruby-2.7. #730 + + +1.11.2 / 2019-11-11 +------------------- + +Added: +* Add DragonFlyBSD as a platform. #724 + +Changed: +* Sort all types.conf files, so that files and changes are easier to compare. +* Regenerated type conf for freebsd12 and x86_64-linux targets. #722 +* Remove MACOSX_DEPLOYMENT_TARGET that was targeting very old version 10.4. #647 +* Fix library name mangling for non glibc Linux/UNIX. #727 +* Fix compiler warnings raised by ruby-2.7 +* Update libffi to latest master. + + +1.11.1 / 2019-05-20 +------------------- + +Changed: +* Raise required ruby version to >=2.0. #699, #700 +* Fix a possible linker error on ruby < 2.3 on Linux. + + +1.11.0 / 2019-05-17 +------------------- +This version was yanked on 2019-05-20 to fix an install issue on ruby-1.9.3. #700 + +Added: +* Add ability to disable or force use of system libffi. #669 + Use like `gem inst ffi -- --enable-system-libffi` . +* Add ability to call FFI callbacks from outside of FFI call frame. #584 +* Add proper documentation to FFI::Generator and ::Task +* Add gemspec metadata. #696, #698 + +Changed: +* Fix stdcall on Win32. #649, #669 +* Fix load paths for FFI::Generator::Task +* Fix FFI::Pointer#read_string(0) to return a binary String. #692 +* Fix benchmark suite so that it runs on ruby-2.x +* Move FFI::Platform::CPU from C to Ruby. #663 +* Move FFI::StructByReference to Ruby. #681 +* Move FFI::DataConverter to Ruby (#661) +* Various cleanups and improvements of specs and benchmarks + +Removed: +* Remove ruby-1.8 and 1.9 compatibility code. #683 +* Remove unused spec files. #684 + + +1.10.0 / 2019-01-06 +------------------- + +Added: +* Add /opt/local/lib/ to ffi's fallback library search path. #638 +* Add binary gem support for ruby-2.6 on Windows +* Add FreeBSD on AArch64 and ARM support. #644 +* Add FFI::LastError.winapi_error on Windows native or Cygwin. #633 + +Changed: +* Update to rake-compiler-dock-0.7.0 +* Use 64-bit inodes on FreeBSD >= 12. #644 +* Switch time_t and suseconds_t types to long on FreeBSD. #627 +* Make register_t long_long on 64-bit FreeBSD. #644 +* Fix Pointer#write_array_of_type #637 + +Removed: +* Drop binary gem support for ruby-2.0 and 2.1 on Windows + + +1.9.25 / 2018-06-03 +------------------- + +Changed: +* Revert closures via libffi. + This re-adds ClosurePool and fixes compat with SELinux enabled systems. #621 + + +1.9.24 / 2018-06-02 +------------------- + +Security Note: + +This update addresses vulnerability CVE-2018-1000201: DLL loading issue which can be hijacked on Windows OS, when a Symbol is used as DLL name instead of a String. Found by Matthew Bush. + +Added: +* Added a CHANGELOG file +* Add mips64(eb) support, and mips r6 support. (#601) + +Changed: +* Update libffi to latest changes on master. +* Don't search in hardcoded /usr paths on Windows. +* Don't treat Symbol args different to Strings in ffi_lib. +* Make sure size_t is defined in Thread.c. Fixes #609 + + +1.9.23 / 2018-02-25 +------------------- + +Changed: +* Fix unnecessary rebuild of configure in darwin multi arch. Fixes #605 + + +1.9.22 / 2018-02-22 +------------------- + +Changed: +* Update libffi to latest changes on master. +* Update detection of system libffi to match new requirements. Fixes #617 +* Prefer bundled libffi over system libffi on Mac OS. +* Do closures via libffi. This removes ClosurePool and fixes compat with PaX. #540 +* Use a more deterministic gem packaging. +* Fix unnecessary update of autoconf files at gem install. + + +1.9.21 / 2018-02-06 +------------------- + +Added: +* Ruby-2.5 support by Windows binary gems. Fixes #598 +* Add missing win64 types. +* Added support for Bitmask. (#573) +* Add support for MSYS2 (#572) and Sparc64 Linux. (#574) + +Changed: +* Fix read_string to not throw an error on length 0. +* Don't use absolute paths for sh and env. Fixes usage on Adroid #528 +* Use Ruby implementation for `which` for better compat with Windows. Fixes #315 +* Fix compatibility with PPC64LE platform. (#577) +* Normalize sparc64 to sparcv9. (#575) + +Removed: +* Drop Ruby 1.8.7 support (#480) + + +1.9.18 / 2017-03-03 +------------------- + +Added: +* Add compatibility with Ruby-2.4. + +Changed: +* Add missing shlwapi.h include to fix Windows build. +* Avoid undefined behaviour of LoadLibrary() on Windows. #553 + + +1.9.17 / 2017-01-13 +------------------- diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/COPYING b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/COPYING new file mode 100644 index 00000000..76223189 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/COPYING @@ -0,0 +1,49 @@ +Copyright (c) 2008-2013, Ruby FFI project contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Ruby FFI project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +libffi, used by this project, is licensed under the MIT license: + +libffi - Copyright (c) 1996-2011 Anthony Green, Red Hat, Inc and others. +See source files for details. + +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/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Gemfile b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Gemfile new file mode 100644 index 00000000..637f1a46 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Gemfile @@ -0,0 +1,26 @@ +source 'https://rubygems.org' + +gemspec + +group :development do + gem 'benchmark' # necessary on ruby-3.5+ + gem 'bigdecimal' # necessary on ruby-3.3+ + gem 'bundler', '>= 1.16', '< 5.dev' + gem 'fiddle' # necessary on ruby-4.0+ + gem 'rake', '~> 13.0' + gem 'rake-compiler', '~> 1.1' + gem 'rake-compiler-dock', '~> 1.11.0' + gem 'rspec', '~> 3.0' +end + +group :doc do + gem 'kramdown' + gem 'yard', '~> 0.9' +end + +group :type_check do + if RUBY_VERSION >= "3.0" && %w[ ruby truffleruby ].include?(RUBY_ENGINE) + gem 'rbs', '~> 3.0' + gem 'steep', '~> 1.6' + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE new file mode 100644 index 00000000..20185fd4 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2008-2016, Ruby FFI project contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Ruby FFI project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE.SPECS b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE.SPECS new file mode 100644 index 00000000..5c9ffcee --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/LICENSE.SPECS @@ -0,0 +1,22 @@ +Copyright (c) 2008-2012 Ruby-FFI 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/bin/gems/ffi-1.17.4-x86_64-linux-gnu/README.md b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/README.md new file mode 100644 index 00000000..7f7304b6 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/README.md @@ -0,0 +1,138 @@ +# Ruby-FFI https://github.com/ffi/ffi/wiki + +## Description + +Ruby-FFI is a gem for programmatically loading dynamically-linked native +libraries, binding functions within them, and calling those functions +from Ruby code. Moreover, a Ruby-FFI extension works without changes +on CRuby (MRI), JRuby, Rubinius and TruffleRuby. [Discover why you should write your next extension +using Ruby-FFI](https://github.com/ffi/ffi/wiki/why-use-ffi). + +## Features + +* Intuitive DSL +* Supports all C native types +* C structs (also nested), enums and global variables +* Callbacks from C to Ruby +* Automatic garbage collection of native memory +* Usable in Ractor: [How-to-use-FFI-in-Ruby-Ractors](https://github.com/ffi/ffi/wiki/Ractors) + +## Synopsis + +```ruby +require 'ffi' + +module MyLib + extend FFI::Library + ffi_lib 'c' + attach_function :puts, [ :string ], :int +end + +MyLib.puts 'Hello, World using libc!' +``` + +For less minimalistic and more examples you may look at: + +* The [documentation](https://www.rubydoc.info/gems/ffi) +* the `samples/` folder +* the examples on the [wiki](https://github.com/ffi/ffi/wiki) +* the projects using FFI listed on the wiki: https://github.com/ffi/ffi/wiki/projects-using-ffi + +## Requirements + +When installing the gem on CRuby (MRI), you will need: +* A C compiler (e.g., Xcode on macOS, `gcc` or `clang` on everything else) +Optionally (speeds up installation): +* The `libffi` library and development headers - this is commonly in the `libffi-dev` or `libffi-devel` packages + +The ffi gem comes with a builtin libffi version, which is used, when the system libffi library is not available or too old. +Use of the system libffi can be enforced by: +``` +gem install ffi -- --enable-system-libffi # to install the gem manually +bundle config build.ffi --enable-system-libffi # for bundle install +``` +or prevented by `--disable-system-libffi`. + +On Linux systems running with [PaX](https://en.wikipedia.org/wiki/PaX) (Gentoo, Alpine, etc.), FFI may trigger `mprotect` errors. You may need to disable [mprotect](https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options#Restrict_mprotect.28.29) for ruby (`paxctl -m [/path/to/ruby]`) for the time being until a solution is found. + +On FreeBSD systems pkgconf must be installed for the gem to be able to compile using clang. Install either via packages `pkg install pkgconf` or from ports via `devel/pkgconf`. + +On JRuby and TruffleRuby, there are no requirements to install the FFI gem, and `require 'ffi'` works even without installing the gem (i.e., the gem is preinstalled on these implementations). + +## Installation + +From rubygems: + + [sudo] gem install ffi + +From a Gemfile using git or GitHub + + gem 'ffi', github: 'ffi/ffi', submodules: true + +or from the git repository on github: + + git clone git://github.com/ffi/ffi.git + cd ffi + git submodule update --init --recursive + bundle install + rake install + +### Install options: + +* `--enable-system-libffi` : Force usage of system libffi +* `--disable-system-libffi` : Force usage of builtin libffi +* `--enable-libffi-alloc` : Force closure allocation by libffi +* `--disable-libffi-alloc` : Force closure allocation by builtin method + +## License + +The ffi library is covered by the BSD license, also see the LICENSE file. +The specs are covered by the same license as [ruby/spec](https://github.com/ruby/spec), the MIT license. + +## Credits + +The following people have submitted code, bug reports, or otherwise contributed to the success of this project: + +* Alban Peignier +* Aman Gupta +* Andrea Fazzi +* Andreas Niederl +* Andrew Cholakian +* Antonio Terceiro +* Benoit Daloze +* Brian Candler +* Brian D. Burns +* Bryan Kearney +* Charlie Savage +* Chikanaga Tomoyuki +* Hongli Lai +* Ian MacLeod +* Jake Douglas +* Jean-Dominique Morani +* Jeremy Hinegardner +* Jesús García Sáez +* Joe Khoobyar +* Jurij Smakov +* KISHIMOTO, Makoto +* Kim Burgestrand +* Lars Kanis +* Luc Heinrich +* Luis Lavena +* Matijs van Zuijlen +* Matthew King +* Mike Dalessio +* NARUSE, Yui +* Park Heesob +* Shin Yee +* Stephen Bannasch +* Suraj N. Kurapati +* Sylvain Daubert +* Victor Costan +* beoran@gmail.com +* ctide +* emboss +* hobophobe +* meh +* postmodern +* wycats@gmail.com +* Wayne Meissner diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Rakefile b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Rakefile new file mode 100644 index 00000000..3422b74e --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Rakefile @@ -0,0 +1,209 @@ +require 'rbconfig' +require 'date' +require 'fileutils' +require 'yaml' +require 'rspec/core/rake_task' +require 'rubygems/package_task' +require 'rake/extensiontask' +require_relative "lib/ffi/version" +require_relative "rakelib/ffi_gem_helper" + +BUILD_DIR = "build" +BUILD_EXT_DIR = File.join(BUILD_DIR, "#{RbConfig::CONFIG['arch']}", 'ffi_c', RUBY_VERSION) + +gem_spec = Bundler.load_gemspec('ffi.gemspec') + +RSpec::Core::RakeTask.new(:spec) do |config| + config.rspec_opts = YAML.load_file 'spec/spec.opts' +end + +desc "Build all packages" +task :package => %w[ gem:java gem:native ] + +CLOBBER.include 'lib/ffi/types.conf' +CLOBBER.include 'pkg' +CLOBBER.include 'log' + +CLEAN.include 'build' +CLEAN.include 'conftest.dSYM' +CLEAN.include 'spec/ffi/fixtures/libtest.{dylib,so,dll}' +CLEAN.include 'spec/ffi/fixtures/*.o' +CLEAN.include 'spec/ffi/embed-test/ext/*.{o,def}' +CLEAN.include 'spec/ffi/embed-test/ext/Makefile' +CLEAN.include "pkg/ffi-*-*/" +CLEAN.include 'lib/{2,3}.*' + +# clean all shipped files, that are not in git +CLEAN.include( + gem_spec.files - + `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0").map { |f| File.join("ext/ffi_c/libffi", f) } - + `git ls-files -z`.split("\x0") +) + +task :distclean => :clobber + +desc "Test the extension" +task :test => [ :spec ] + + +namespace :bench do + ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000 + bench_files = Dir["bench/bench_*.rb"].sort.reject { |f| f == "bench/bench_helper.rb" } + bench_files.each do |bench| + task File.basename(bench, ".rb")[6..-1] => :compile do + sh %{#{Gem.ruby} #{bench} #{ITER}} + end + end + task :all => :compile do + bench_files.each do |bench| + sh %{#{Gem.ruby} #{bench}} + end + end +end + +task 'spec:run' => :compile +task 'spec:specdoc' => :compile + +task :default => :spec + +namespace 'java' do + + java_gem_spec = gem_spec.dup.tap do |s| + s.files.reject! { |f| File.fnmatch?("ext/*", f) } + s.extensions = [] + s.platform = 'java' + end + + Gem::PackageTask.new(java_gem_spec) do |pkg| + pkg.need_zip = true + pkg.need_tar = true + pkg.package_dir = 'pkg' + end +end + +task 'gem:java' => 'java:gem' + +FfiGemHelper.install_tasks +# Register binary gems to be pushed to rubygems.org +Bundler::GemHelper.instance.cross_platforms = %w[ + x86-mingw32 + x64-mingw-ucrt + x64-mingw32 + x86-linux-gnu + x86-linux-musl + x86_64-linux-gnu + x86_64-linux-musl + arm-linux-gnu + arm-linux-musl + aarch64-linux-gnu + aarch64-linux-musl + aarch64-mingw-ucrt + x86_64-darwin + arm64-darwin +] + +if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx' + require 'rake/extensiontask' + Rake::ExtensionTask.new('ffi_c', gem_spec) do |ext| + ext.name = 'ffi_c' # indicate the name of the extension. + # ext.lib_dir = BUILD_DIR # put binaries into this folder. + ext.tmp_dir = BUILD_DIR # temporary folder used during compilation. + ext.cross_compile = true # enable cross compilation (requires cross compile toolchain) + ext.cross_platform = Bundler::GemHelper.instance.cross_platforms + ext.cross_compiling do |spec| + spec.files.reject! { |path| File.fnmatch?('ext/*', path) } + # Binary gems don't need libffi header+lib files + spec.metadata.delete("msys2_mingw_dependencies") + end + # Enable debug info for 'rake compile' but not for 'gem install' + ext.config_options << "--enable-debug" + + end +else + task :compile do + STDERR.puts "Nothing to compile on #{RUBY_ENGINE}" + end +end + + +namespace "gem" do + task 'prepare' do + require 'rake_compiler_dock' + sh "bundle package" + end + + Bundler::GemHelper.instance.cross_platforms.each do |plat| + desc "Build all native binary gems in parallel" + multitask 'native' => plat + + desc "Build the native gem for #{plat}" + task plat => ['prepare', 'build'] do + RakeCompilerDock.sh <<-EOT, platform: plat + sudo apt-get update && sudo apt-get install -y libltdl-dev && + bundle install --local && + rake native:#{plat} pkg/#{gem_spec.full_name}-#{plat}.gem MAKE='nice make -j`nproc`' RUBY_CC_VERSION=#{RakeCompilerDock.ruby_cc_version("~>4.0", "~>3.0")} + EOT + end + end +end + +directory "ext/ffi_c/libffi" +file "ext/ffi_c/libffi/autogen.sh" => "ext/ffi_c/libffi" do + warn "Downloading libffi ..." + sh "git submodule update --init --recursive" +end +task :libffi => "ext/ffi_c/libffi/autogen.sh" + +LIBFFI_GIT_FILES = `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0") + +# Generate files which are in the gemspec but not in libffi's git repo by running autogen.sh +gem_spec.files.select do |f| + f =~ /ext\/ffi_c\/libffi\/(.*)/ && !LIBFFI_GIT_FILES.include?($1) +end.each do |f| + file f => "ext/ffi_c/libffi/autogen.sh" do + chdir "ext/ffi_c/libffi" do + sh "sh ./autogen.sh" + end + touch f + if gem_spec.files != Gem::Specification.load('./ffi.gemspec').files + warn "gemspec files have changed -> Please restart rake!" + exit 1 + end + end +end + +# Make sure we have all gemspec files before packaging +task :build => gem_spec.files +task :gem => :build + + +require_relative "lib/ffi/platform" +types_conf = File.expand_path(File.join(FFI::Platform::CONF_DIR, 'types.conf')) +logfile = File.join(File.dirname(__FILE__), 'types_log') + +task types_conf do |task| + require 'fileutils' + require_relative "rakelib/types_generator" + options = {} + FileUtils.mkdir_p(File.dirname(task.name), mode: 0755 ) + File.open(task.name, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f| + f.puts FFI::TypesGenerator.generate(options) + end + File.open(logfile, 'w') do |log| + log.puts(types_conf) + end +end + +desc "Create or update type information for platform #{FFI::Platform::NAME}" +task :types_conf => types_conf + +begin + require 'yard' + + namespace :doc do + YARD::Rake::YardocTask.new do |yard| + end + end +rescue LoadError + warn "[warn] YARD unavailable" +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Steepfile b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Steepfile new file mode 100644 index 00000000..d35d735f --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/Steepfile @@ -0,0 +1,8 @@ +target :lib do + signature "sig" + + check "lib" + + # ignore whole of lib, to just validate RBS in sig + ignore "lib" +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/ffi.gemspec b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/ffi.gemspec new file mode 100644 index 00000000..6fdf2f1e --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/ffi.gemspec @@ -0,0 +1,43 @@ +require File.expand_path("../lib/#{File.basename(__FILE__, '.gemspec')}/version", __FILE__) + +Gem::Specification.new do |s| + s.name = 'ffi' + s.version = FFI::VERSION + s.author = 'Wayne Meissner' + s.email = 'wmeissner@gmail.com' + s.homepage = 'https://github.com/ffi/ffi/wiki' + s.summary = 'Ruby FFI' + s.description = 'Ruby FFI library' + if s.respond_to?(:metadata) + s.metadata['bug_tracker_uri'] = 'https://github.com/ffi/ffi/issues' + s.metadata['changelog_uri'] = 'https://github.com/ffi/ffi/blob/master/CHANGELOG.md' + s.metadata['documentation_uri'] = 'https://github.com/ffi/ffi/wiki' + s.metadata['wiki_uri'] = 'https://github.com/ffi/ffi/wiki' + s.metadata['source_code_uri'] = 'https://github.com/ffi/ffi/' + s.metadata['mailing_list_uri'] = 'http://groups.google.com/group/ruby-ffi' + s.metadata['rubygems_mfa_required'] = 'true' + end + s.files = `git ls-files -z`.split("\x0").reject do |f| + f =~ /^(\.|bench|gen|libtest|nbproject|spec|rakelib)/ + end + + # Add libffi git files + lfs = `git --git-dir ext/ffi_c/libffi/.git ls-files -z`.split("\x0").reject do |f| + f =~ /^(\.|testsuite)/ + end + # Add autoconf generated files of libffi + lfs += %w[ compile configure config.guess config.sub install-sh ltmain.sh missing fficonfig.h.in ] + # Add automake generated files of libffi + lfs += `git --git-dir ext/ffi_c/libffi/.git ls-files -z *.am */*.am`.gsub(".am\0", ".in\0").split("\x0") + s.files += lfs.map do |f| + File.join("ext/ffi_c/libffi", f) + end + + s.extensions << 'ext/ffi_c/extconf.rb' + s.rdoc_options = %w[--exclude=ext/ffi_c/.*\.o$ --exclude=ffi_c\.(bundle|so)$] + s.license = 'BSD-3-Clause' + s.require_paths << 'ext/ffi_c' + s.required_ruby_version = '>= 2.5' + + s.metadata['msys2_mingw_dependencies'] = 'libffi' +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.0/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.0/ffi_c.so new file mode 100755 index 00000000..cf10591a Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.0/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.1/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.1/ffi_c.so new file mode 100755 index 00000000..c4ff3699 Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.1/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.2/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.2/ffi_c.so new file mode 100755 index 00000000..435463e0 Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.2/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.3/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.3/ffi_c.so new file mode 100755 index 00000000..11a39d55 Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.3/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.4/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.4/ffi_c.so new file mode 100755 index 00000000..9e28397f Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/3.4/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/4.0/ffi_c.so b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/4.0/ffi_c.so new file mode 100755 index 00000000..3906adab Binary files /dev/null and b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/4.0/ffi_c.so differ diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi.rb new file mode 100644 index 00000000..3fb20a8c --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi.rb @@ -0,0 +1,27 @@ +if RUBY_ENGINE == 'ruby' + begin + require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c' + rescue Exception + require 'ffi_c' + end + + require 'ffi/ffi' + +elsif RUBY_ENGINE == 'jruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [9, 2, 20]) >= 0 + JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService") + require 'ffi/ffi' + +elsif RUBY_ENGINE == 'truffleruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0 + require 'truffleruby/ffi_backend' + require 'ffi/ffi' + +else + # Remove the ffi gem dir from the load path, then reload the internal ffi implementation + $LOAD_PATH.delete(File.dirname(__FILE__)) + $LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi')) + unless $LOADED_FEATURES.nil? + $LOADED_FEATURES.delete(__FILE__) + $LOADED_FEATURES.delete('ffi.rb') + end + require 'ffi.rb' +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/abstract_memory.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/abstract_memory.rb new file mode 100644 index 00000000..e0aa2216 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/abstract_memory.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2020 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + + +module FFI + class AbstractMemory + LONG_MAX = FFI::Pointer.new(1).size + private_constant :LONG_MAX + + # Return +true+ if +self+ has a size limit. + # + # @return [Boolean] + def size_limit? + size != LONG_MAX + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/autopointer.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/autopointer.rb new file mode 100644 index 00000000..4dd6113a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/autopointer.rb @@ -0,0 +1,186 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008 Mike Dalessio +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + class AutoPointer < Pointer + extend DataConverter + + # @overload initialize(pointer, method) + # @param pointer [Pointer] + # @param method [Method] + # @return [self] + # The passed Method will be invoked at GC time. + # @overload initialize(pointer, proc) + # @param pointer [Pointer] + # @return [self] + # The passed Proc will be invoked at GC time (SEE WARNING BELOW!) + # @note WARNING: passing a proc _may_ cause your pointer to never be + # GC'd, unless you're careful to avoid trapping a reference to the + # pointer in the proc. See the test specs for examples. + # @overload initialize(pointer) + # @param pointer [Pointer] + # @return [self] + # The pointer's release() class method will be invoked at GC time. + # + # @note The safest, and therefore preferred, calling + # idiom is to pass a Method as the second parameter. Example usage: + # + # class PointerHelper + # def self.release(pointer) + # ... + # end + # end + # + # p = AutoPointer.new(other_pointer, PointerHelper.method(:release)) + # + # The above code will cause PointerHelper#release to be invoked at GC time. + # + # @note + # The last calling idiom (only one parameter) is generally only + # going to be useful if you subclass {AutoPointer}, and override + # #release, which by default does nothing. + def initialize(ptr, proc=nil) + raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) || + ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer) + super(ptr.type_size, ptr) + + @releaser = if proc + if not proc.respond_to?(:call) + raise RuntimeError.new("proc must be callable") + end + Releaser.new(ptr, proc) + + else + if not self.class.respond_to?(:release, true) + raise RuntimeError.new("no release method defined") + end + Releaser.new(ptr, self.class.method(:release)) + end + + ObjectSpace.define_finalizer(self, @releaser) + self + end + + def dup + raise RuntimeError, "cannot duplicate FFI::AutoPointer" + end + + alias clone dup + + # @return [nil] + # Free the pointer. + def free + @releaser.free + end + + # @param [Boolean] autorelease + # @return [Boolean] +autorelease+ + # Set +autorelease+ property. See {Pointer Autorelease section at Pointer}. + def autorelease=(autorelease) + raise FrozenError.new("can't modify frozen #{self.class}") if frozen? + @releaser.autorelease=(autorelease) + end + + # @return [Boolean] +autorelease+ + # Get +autorelease+ property. See {Pointer Autorelease section at Pointer}. + def autorelease? + @releaser.autorelease + end + + # @abstract Base class for {AutoPointer}'s releasers. + # + # All subclasses of Releaser should define a +#release(ptr)+ method. + # A releaser is an object in charge of release an {AutoPointer}. + class Releaser + attr_accessor :autorelease + + # @param [Pointer] ptr + # @param [#call] proc + # @return [nil] + # A new instance of Releaser. + def initialize(ptr, proc) + @ptr = ptr + @proc = proc + @autorelease = true + end + + # @return [nil] + # Free pointer. + def free + if @ptr + release(@ptr) + @autorelease = false + @ptr = nil + @proc = nil + end + end + + # @param args + # Release pointer if +autorelease+ is set. + def call(*args) + release(@ptr) if @autorelease && @ptr + end + + # Release +ptr+ by using Proc or Method defined at +ptr+ + # {AutoPointer#initialize initialization}. + # + # @param [Pointer] ptr + # @return [nil] + def release(ptr) + @proc.call(ptr) + end + end + + # Return native type of AutoPointer. + # + # Override {DataConverter#native_type}. + # @return [Type::POINTER] + # @raise {RuntimeError} if class does not implement a +#release+ method + def self.native_type + if not self.respond_to?(:release, true) + raise RuntimeError.new("no release method defined for #{self.inspect}") + end + Type::POINTER + end + + # Create a new AutoPointer. + # + # Override {DataConverter#from_native}. + # @overload self.from_native(ptr, ctx) + # @param [Pointer] ptr + # @param ctx not used. Please set +nil+. + # @return [AutoPointer] + def self.from_native(val, ctx) + self.new(val) + end + end + +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/buffer.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/buffer.rb new file mode 100644 index 00000000..449e45b0 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/buffer.rb @@ -0,0 +1,4 @@ +# +# All the code from this file is now implemented in C. This file remains +# to satisfy any leftover require 'ffi/buffer' in user code +# diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/callback.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/callback.rb new file mode 100644 index 00000000..32d52f72 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/callback.rb @@ -0,0 +1,4 @@ +# +# All the code from this file is now implemented in C. This file remains +# to satisfy any leftover require 'ffi/callback' in user code +# diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/compat.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/compat.rb new file mode 100644 index 00000000..051724fb --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/compat.rb @@ -0,0 +1,54 @@ +# +# Copyright (C) 2023-2023 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + if defined?(Ractor.make_shareable) + # This is for FFI internal use only. + def self.make_shareable(obj) + Ractor.make_shareable(obj) + end + else + def self.make_shareable(obj) + obj.freeze + end + end + + if defined?(Ractor.shareable_proc) + # This is for FFI internal use only. + def self.shareable_proc(**kwargs, &block) + Ractor.shareable_proc(**kwargs, &block) + end + else + def self.shareable_proc(**_kwargs, &block) + block + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/data_converter.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/data_converter.rb new file mode 100644 index 00000000..7852e7ee --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/data_converter.rb @@ -0,0 +1,67 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # This module is used to extend somes classes and give then a common API. + # + # Most of methods defined here must be overridden. + module DataConverter + # Get native type. + # + # @overload native_type(type) + # @param [String, Symbol, Type] type + # @return [Type] + # Get native type from +type+. + # + # @overload native_type + # @raise {NotImplementedError} This method must be overridden. + def native_type(type = nil) + if type + @native_type = FFI.find_type(type) + else + native_type = @native_type + unless native_type + raise NotImplementedError, 'native_type method not overridden and no native_type set' + end + native_type + end + end + + # Convert to a native type. + def to_native(value, ctx) + value + end + + # Convert from a native type. + def from_native(value, ctx) + value + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/dynamic_library.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/dynamic_library.rb new file mode 100644 index 00000000..468ce044 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/dynamic_library.rb @@ -0,0 +1,118 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + class DynamicLibrary + SEARCH_PATH = [] + + # The following search paths are tried, if the library could not be loaded in the first attempt. + # They are only executed on Macos in the following order: + if FFI::Platform.mac? + + # 1. Try library paths possibly defined in LD_LIBRARY_PATH DYLD_LIBRARY_PATH first. + # This is because dlopen doesn't respect LD_LIBRARY_PATH and DYLD_LIBRARY_PATH is deleted by SIP-protected binaries. + # See here for details: https://github.com/ffi/ffi/issues/923#issuecomment-1872565313 + %w[LD_LIBRARY_PATH DYLD_LIBRARY_PATH].each do |custom_path| + SEARCH_PATH.concat ENV.fetch(custom_path,"").split(File::PATH_SEPARATOR) + end + + # 2. Then on macos/arm64 try /opt/homebrew/lib, since this is a typical standard directory. + # FFI is often used together with homebrew, so that we hardcode the path for arm64 here. + if FFI::Platform::ARCH == 'aarch64' + SEARCH_PATH << '/opt/homebrew/lib' + end + + # 3. Then try typical system directories starting with the /local/ directory first. + # + # /usr/local/lib is used by homebrow on x86_64. + # /opt/local/lib is used by MacPorts and Fink. + # /usr/lib is there, because it was always there. + SEARCH_PATH.concat %w[/opt/local/lib /usr/local/lib /usr/lib] + end + + # On Linux the library lookup paths are usually defined through /etc/ld.so.conf, which can be changed at will with root permissions. + # Also LD_LIBRARY_PATH is respected by the dynamic loader, so that there's usually no need and no advantage to do a fallback handling. + # + # Windows has it's own library lookup logic, very different to what we do here. + # See: https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers#user-content-dll-loading + + FFI.make_shareable(SEARCH_PATH) + SEARCH_PATH_MESSAGE = "Searched in #{ SEARCH_PATH.map{|a| ', ' + a}.join }".freeze + + def self.load_library(name, flags) + if name == FFI::CURRENT_PROCESS + FFI::DynamicLibrary.open(nil, RTLD_LAZY | RTLD_LOCAL) + else + flags ||= RTLD_LAZY | RTLD_LOCAL + + libnames = (name.is_a?(::Array) ? name : [name]) + libnames = libnames.map(&:to_s).map { |n| [n, FFI.map_library_name(n)].uniq }.flatten.compact + errors = [] + + libnames.each do |libname| + lib = try_load(libname, flags, errors) + return lib if lib + + unless libname.start_with?("/") + SEARCH_PATH.each do |prefix| + path = "#{prefix}/#{libname}" + if File.exist?(path) + lib = try_load(path, flags, errors) + return lib if lib + end + end + end + end + + raise LoadError, [*errors, SEARCH_PATH_MESSAGE].join(".\n") + end + end + private_class_method :load_library + + def self.try_load(libname, flags, errors) + begin + lib = FFI::DynamicLibrary.open(libname, flags) + return lib if lib + + # LoadError for C ext & JRuby, RuntimeError for TruffleRuby + rescue LoadError, RuntimeError => ex + if ex.message =~ /(([^ \t()])+\.so([^ \t:()])*):([ \t])*(invalid ELF header|file too short|invalid file format)/ + if File.binread($1) =~ /(?:GROUP|INPUT) *\( *([^ \)]+)/ + return try_load($1, flags, errors) + end + end + + errors << ex + nil + end + end + private_class_method :try_load + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/enum.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/enum.rb new file mode 100644 index 00000000..af783316 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/enum.rb @@ -0,0 +1,302 @@ +# +# Copyright (C) 2009, 2010 Wayne Meissner +# Copyright (C) 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + # An instance of this class permits to manage {Enum}s. In fact, Enums is a collection of {Enum}s. + class Enums + + def initialize + @all_enums = Array.new + @tagged_enums = Hash.new + @symbol_map = Hash.new + end + + # @param [Enum] enum + # Add an {Enum} to the collection. + def <<(enum) + @all_enums << enum + @tagged_enums[enum.tag] = enum unless enum.tag.nil? + @symbol_map.merge!(enum.symbol_map) + end + + # @param query enum tag or part of an enum name + # @return [Enum] + # Find a {Enum} in collection. + def find(query) + if @tagged_enums.has_key?(query) + @tagged_enums[query] + else + @all_enums.detect { |enum| enum.symbols.include?(query) } + end + end + + # @param symbol a symbol to find in merge symbol maps of all enums. + # @return a symbol + def __map_symbol(symbol) + @symbol_map[symbol] + end + + end + + # Represents a C enum. + # + # For a C enum: + # enum fruits { + # apple, + # banana, + # orange, + # pineapple + # }; + # are defined this vocabulary: + # * a _symbol_ is a word from the enumeration (ie. _apple_, by example); + # * a _value_ is the value of a symbol in the enumeration (by example, apple has value _0_ and banana _1_). + class Enum + include DataConverter + + attr_reader :tag + attr_reader :native_type + + # @overload initialize(info, tag=nil) + # @param [nil, Enumerable] info + # @param [nil, Symbol] tag enum tag + # @overload initialize(native_type, info, tag=nil) + # @param [FFI::Type] native_type Native type for new Enum + # @param [nil, Enumerable] info symbols and values for new Enum + # @param [nil, Symbol] tag name of new Enum + def initialize(*args) + @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT + info, @tag = *args + @kv_map = Hash.new + unless info.nil? + last_cst = nil + value = 0 + info.each do |i| + case i + when Symbol + raise ArgumentError, "duplicate enum key" if @kv_map.has_key?(i) + @kv_map[i] = value + last_cst = i + value += 1 + when Integer + @kv_map[last_cst] = i + value = i+1 + end + end + end + @vk_map = @kv_map.invert + end + + # @return [Array] enum symbol names + def symbols + @kv_map.keys + end + + # Get a symbol or a value from the enum. + # @overload [](query) + # Get enum value from symbol. + # @param [Symbol] query + # @return [Integer] + # @overload [](query) + # Get enum symbol from value. + # @param [Integer] query + # @return [Symbol] + def [](query) + case query + when Symbol + @kv_map[query] + when Integer + @vk_map[query] + end + end + alias find [] + + # Get the symbol map. + # @return [Hash] + def symbol_map + @kv_map + end + + alias to_h symbol_map + alias to_hash symbol_map + + # @param [Symbol, Integer, #to_int] val + # @param ctx unused + # @return [Integer] value of a enum symbol + def to_native(val, ctx) + @kv_map[val] || if val.is_a?(Integer) + val + elsif val.respond_to?(:to_int) + val.to_int + else + raise ArgumentError, "invalid enum value, #{val.inspect}" + end + end + + # @param val + # @return symbol name if it exists for +val+. + def from_native(val, ctx) + @vk_map[val] || val + end + end + + # Represents a C enum whose values are power of 2 + # + # @example + # enum { + # red = (1<<0), + # green = (1<<1), + # blue = (1<<2) + # } + # + # Contrary to classical enums, bitmask values are usually combined + # when used. + class Bitmask < Enum + + # @overload initialize(info, tag=nil) + # @param [nil, Enumerable] info symbols and bit rank for new Bitmask + # @param [nil, Symbol] tag name of new Bitmask + # @overload initialize(native_type, info, tag=nil) + # @param [FFI::Type] native_type Native type for new Bitmask + # @param [nil, Enumerable] info symbols and bit rank for new Bitmask + # @param [nil, Symbol] tag name of new Bitmask + def initialize(*args) + @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT + @signed = [Type::INT8, Type::INT16, Type::INT32, Type::INT64].include?(@native_type) + info, @tag = *args + @kv_map = Hash.new + unless info.nil? + last_cst = nil + value = 0 + info.each do |i| + case i + when Symbol + raise ArgumentError, "duplicate bitmask key" if @kv_map.has_key?(i) + @kv_map[i] = 1 << value + last_cst = i + value += 1 + when Integer + raise ArgumentError, "bitmask index should be positive" if i<0 + @kv_map[last_cst] = 1 << i + value = i+1 + end + end + end + @vk_map = @kv_map.invert + end + + # Get a symbol list or a value from the bitmask + # @overload [](*query) + # Get bitmask value from symbol list + # @param [Symbol] query + # @return [Integer] + # @overload [](query) + # Get bitmask value from symbol array + # @param [Array] query + # @return [Integer] + # @overload [](*query) + # Get a list of bitmask symbols corresponding to + # the or reduction of a list of integer + # @param [Integer] query + # @return [Array] + # @overload [](query) + # Get a list of bitmask symbols corresponding to + # the or reduction of a list of integer + # @param [Array] query + # @return [Array] + def [](*query) + flat_query = query.flatten + raise ArgumentError, "query should be homogeneous, #{query.inspect}" unless flat_query.all? { |o| o.is_a?(Symbol) } || flat_query.all? { |o| o.is_a?(Integer) || o.respond_to?(:to_int) } + case flat_query[0] + when Symbol + flat_query.inject(0) do |val, o| + v = @kv_map[o] + if v then val | v else val end + end + when Integer, ->(o) { o.respond_to?(:to_int) } + val = flat_query.inject(0) { |mask, o| mask |= o.to_int } + @kv_map.select { |_, v| v & val != 0 }.keys + end + end + + # Get the native value of a bitmask + # @overload to_native(query, ctx) + # @param [Symbol, Integer, #to_int] query + # @param ctx unused + # @return [Integer] value of a bitmask + # @overload to_native(query, ctx) + # @param [Array] query + # @param ctx unused + # @return [Integer] value of a bitmask + def to_native(query, ctx) + return 0 if query.nil? + flat_query = [query].flatten + res = flat_query.inject(0) do |val, o| + case o + when Symbol + v = @kv_map[o] + raise ArgumentError, "invalid bitmask value, #{o.inspect}" unless v + val | v + when Integer + val | o + when ->(obj) { obj.respond_to?(:to_int) } + val | o.to_int + else + raise ArgumentError, "invalid bitmask value, #{o.inspect}" + end + end + # Take two's complement of positive values bigger than the max value + # for the type when native type is signed. + if @signed && res >= (1 << (@native_type.size * 8 - 1)) + res = -(-res & ((1 << (@native_type.size * 8)) - 1)) + end + res + end + + # @param [Integer] val + # @param ctx unused + # @return [Array] list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant + def from_native(val, ctx) + flags = @kv_map.select { |_, v| v & val != 0 } + list = flags.keys + # force an unsigned value of the correct size + val &= (1 << (@native_type.size * 8)) - 1 if @signed + # If there are unmatch flags, + # return them in an integer, + # else information can be lost. + # Similar to Enum behavior. + remainder = val ^ flags.values.reduce(0, :|) + list.push remainder unless remainder == 0 + return list + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/errno.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/errno.rb new file mode 100644 index 00000000..de82d891 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/errno.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # @return (see FFI::LastError.error) + # @see FFI::LastError.error + def self.errno + FFI::LastError.error + end + # @param error (see FFI::LastError.error=) + # @return (see FFI::LastError.error=) + # @see FFI::LastError.error= + def self.errno=(error) + FFI::LastError.error = error + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/ffi.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/ffi.rb new file mode 100644 index 00000000..47822705 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/ffi.rb @@ -0,0 +1,109 @@ +# +# Copyright (C) 2008-2010 JRuby project +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'ffi/compat' +require 'ffi/platform' +require 'ffi/data_converter' +require 'ffi/types' +require 'ffi/library_path' +require 'ffi/library' +require 'ffi/errno' +require 'ffi/abstract_memory' +require 'ffi/pointer' +require 'ffi/memorypointer' +require 'ffi/struct' +require 'ffi/union' +require 'ffi/managedstruct' +require 'ffi/callback' +require 'ffi/io' +require 'ffi/autopointer' +require 'ffi/variadic' +require 'ffi/enum' +require 'ffi/version' +require 'ffi/function' + +module FFI + module ModernForkTracking + def _fork + pid = super + if pid == 0 + FFI._async_cb_dispatcher_atfork_child + end + pid + end + end + + module LegacyForkTracking + module KernelExt + def fork + if block_given? + super do + FFI._async_cb_dispatcher_atfork_child + yield + end + else + pid = super + FFI._async_cb_dispatcher_atfork_child if pid.nil? + pid + end + end + end + + module KernelExtPrivate + include KernelExt + private :fork + end + + module IOExt + def popen(*args) + return super unless args[0] == '-' + + super(*args) do |pipe| + FFI._async_cb_dispatcher_atfork_child if pipe.nil? + yield pipe + end + end + ruby2_keywords :popen if respond_to?(:ruby2_keywords) + end + end + + if Process.respond_to?(:_fork) + # The nice Ruby 3.1+ way of doing things + ::Process.singleton_class.prepend(ModernForkTracking) + elsif Process.respond_to?(:fork) + # Barf. Old CRuby. + # Most of the inspiration for how to do this was stolen from ActiveSupport. + ::Object.prepend(LegacyForkTracking::KernelExtPrivate) + ::Object.singleton_class.prepend(LegacyForkTracking::KernelExt) + ::Kernel.prepend(LegacyForkTracking::KernelExtPrivate) + ::Kernel.singleton_class.prepend(LegacyForkTracking::KernelExt) + ::IO.singleton_class.prepend(LegacyForkTracking::IOExt) + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/function.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/function.rb new file mode 100644 index 00000000..d8d47657 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/function.rb @@ -0,0 +1,94 @@ +# +# Copyright (C) 2008-2010 JRuby project +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + class Function + # Only MRI allows function type queries + if private_method_defined?(:type) + # Retrieve the return type of the function + # + # This method returns FFI type returned by the function. + # + # @return [FFI::Type] + def return_type + type.return_type + end + + # Retrieve Array of parameter types + # + # This method returns an Array of FFI types accepted as function parameters. + # + # @return [Array] + def param_types + type.param_types + end + end + + if RUBY_PLATFORM == 'aarch64-mingw-ucrt' + # Use a workaround for https://github.com/libffi/libffi/issues/905 + def attach(mod, name) + this = self + body = proc do |*args, &block| + this.call(*args, &block) + end + + mod.define_method(name, body) + mod.define_singleton_method(name, body) + + # Store function Proc's for re-definition as Ractor-shareable in Library#freeze + funcs = mod.instance_variable_get("@ffi_function_procs") + unless funcs + funcs = {} + mod.instance_variable_set("@ffi_function_procs", funcs) + end + funcs[name] = self + + self + end + end + + # Stash the Function in a module variable so it can be inspected by attached_functions. + # On CRuby it also ensures that it does not get garbage collected. + module RegisterAttach + def attach(mod, name) + funcs = mod.instance_variable_defined?("@ffi_functions") && mod.instance_variable_get("@ffi_functions") + unless funcs + funcs = {} + mod.instance_variable_set("@ffi_functions", funcs) + end + funcs[name.to_sym] = self + # Jump to the native attach method of CRuby, JRuby or Tuffleruby + super + end + end + private_constant :RegisterAttach + prepend RegisterAttach + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/io.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/io.rb new file mode 100644 index 00000000..7fb28574 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/io.rb @@ -0,0 +1,62 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + + # This module implements a couple of class methods to play with IO. + module IO + # @param [Integer] fd file decriptor + # @param [String] mode mode string + # @return [::IO] + # Synonym for IO::for_fd. + def self.for_fd(fd, mode = "r") + ::IO.for_fd(fd, mode) + end + + # @param [#read] io io to read from + # @param [AbstractMemory] buf destination for data read from +io+ + # @param [nil, Integer] len maximul number of bytes to read from +io+. If +nil+, + # read until end of file. + # @return [Integer] length really read, in bytes + # + # A version of IO#read that reads data from an IO and put then into a native buffer. + # + # This will be optimized at some future time to eliminate the double copy. + # + def self.native_read(io, buf, len) + tmp = io.read(len) + return -1 unless tmp + buf.put_bytes(0, tmp) + tmp.length + end + + end +end + diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library.rb new file mode 100644 index 00000000..e497b64a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library.rb @@ -0,0 +1,592 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +require 'ffi/dynamic_library' + +module FFI + CURRENT_PROCESS = USE_THIS_PROCESS_AS_LIBRARY = FFI.make_shareable(Object.new) + + # @param [String, FFI::LibraryPath] lib library name or LibraryPath object + # @return [String] library name formatted for current platform + # Transform a generic library name to a platform library name + # @example + # # Linux + # FFI.map_library_name 'c' # -> "libc.so.6" + # FFI.map_library_name 'jpeg' # -> "libjpeg.so" + # # Windows + # FFI.map_library_name 'c' # -> "msvcrt.dll" + # FFI.map_library_name 'jpeg' # -> "jpeg.dll" + def self.map_library_name(lib) + # Mangle the library name to reflect the native library naming conventions + LibraryPath.wrap(lib).to_s + end + + # Exception raised when a function is not found in libraries + class NotFoundError < LoadError + def initialize(function, *libraries) + super("Function '#{function}' not found in [#{libraries[0].nil? ? 'current process' : libraries.join(", ")}]") + end + end + + # This module is the base to use native functions. + # + # A basic usage may be: + # require 'ffi' + # + # module Hello + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function 'puts', [ :string ], :int + # end + # + # Hello.puts("Hello, World") + # + # + module Library + CURRENT_PROCESS = FFI::CURRENT_PROCESS + LIBC = FFI::Platform::LIBC + + # @param mod extended object + # @return [nil] + # @raise {RuntimeError} if +mod+ is not a Module + # Test if extended object is a Module. If not, raise RuntimeError. + def self.extended(mod) + raise RuntimeError.new("must only be extended by module") unless mod.kind_of?(::Module) + end + + + # @param [Array] names names of libraries to load + # @return [Array] + # @raise {LoadError} if a library cannot be opened + # Load native libraries. + def ffi_lib(*names) + raise LoadError.new("library names list must not be empty") if names.empty? + + lib_flags = defined?(@ffi_lib_flags) && @ffi_lib_flags + + @ffi_libs = names.map do |name| + FFI::DynamicLibrary.send(:load_library, name, lib_flags) + end + end + + # Set the calling convention for {#attach_function} and {#callback} + # + # @see http://en.wikipedia.org/wiki/Stdcall#stdcall + # @note +:stdcall+ is typically used for attaching Windows API functions + # + # @param [Symbol] convention one of +:default+, +:stdcall+ + # @return [Symbol] the new calling convention + def ffi_convention(convention = nil) + @ffi_convention ||= :default + @ffi_convention = convention if convention + @ffi_convention + end + + # @see #ffi_lib + # @return [Array] array of currently loaded FFI libraries + # @raise [LoadError] if no libraries have been loaded (using {#ffi_lib}) + # Get FFI libraries loaded using {#ffi_lib}. + def ffi_libraries + raise LoadError.new("no library specified") if !defined?(@ffi_libs) || @ffi_libs.empty? + @ffi_libs + end + + # Flags used in {#ffi_lib}. + # + # This map allows you to supply symbols to {#ffi_lib_flags} instead of + # the actual constants. + FlagsMap = { + :global => DynamicLibrary::RTLD_GLOBAL, + :local => DynamicLibrary::RTLD_LOCAL, + :lazy => DynamicLibrary::RTLD_LAZY, + :now => DynamicLibrary::RTLD_NOW + } + + # Sets library flags for {#ffi_lib}. + # + # @example + # ffi_lib_flags(:lazy, :local) # => 5 + # + # @param [Symbol, …] flags (see {FlagsMap}) + # @return [Integer] the new value + def ffi_lib_flags(*flags) + @ffi_lib_flags = flags.inject(0) { |result, f| result | FlagsMap[f] } + end + + + ## + # @overload attach_function(func, args, returns, options = {}) + # @example attach function without an explicit name + # module Foo + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function :malloc, [:size_t], :pointer + # end + # # now callable via Foo.malloc + # @overload attach_function(name, func, args, returns, options = {}) + # @example attach function with an explicit name + # module Bar + # extend FFI::Library + # ffi_lib FFI::Library::LIBC + # attach_function :c_malloc, :malloc, [:size_t], :pointer + # end + # # now callable via Bar.c_malloc + # + # Attach C function +func+ to this module. + # + # + # @param [#to_s] name name of ruby method to attach as + # @param [#to_s] func name of C function to attach + # @param [Array] args an array of types + # @param [Symbol] returns type of return value + # @option options [Boolean] :blocking (@blocking) set to true if the C function is a blocking call + # @option options [Symbol] :convention (:default) calling convention (see {#ffi_convention}) + # @option options [FFI::Enums] :enums + # @option options [Hash] :type_map + # + # @return [FFI::VariadicInvoker] + # + # @raise [FFI::NotFoundError] if +func+ cannot be found in the attached libraries (see {#ffi_lib}) + def attach_function(name, func, args, returns = nil, options = nil) + mname, a2, a3, a4, a5 = name, func, args, returns, options + cname, arg_types, ret_type, opts = (a4 && (a2.is_a?(String) || a2.is_a?(Symbol))) ? [ a2, a3, a4, a5 ] : [ mname.to_s, a2, a3, a4 ] + + # Convert :foo to the native type + arg_types = arg_types.map { |e| find_type(e) } + options = { + :convention => ffi_convention, + :type_map => defined?(@ffi_typedefs) ? @ffi_typedefs : nil, + :blocking => defined?(@blocking) && @blocking, + :enums => defined?(@ffi_enums) ? @ffi_enums : nil, + } + + @blocking = false + options.merge!(opts) if opts && opts.is_a?(Hash) + + # Try to locate the function in any of the libraries + invokers = [] + ffi_libraries.each do |lib| + if invokers.empty? + begin + function = nil + function_names(cname, arg_types).find do |fname| + function = lib.find_function(fname) + end + raise LoadError unless function + + invokers << if arg_types[-1] == FFI::NativeType::VARARGS + VariadicInvoker.new(function, arg_types, find_type(ret_type), options) + + else + Function.new(find_type(ret_type), arg_types, function, options) + end + + rescue LoadError + end + end + end + invoker = invokers.compact.shift + raise FFI::NotFoundError.new(cname.to_s, ffi_libraries.map { |lib| lib.name }) unless invoker + + invoker.attach(self, mname.to_s) + invoker + end + + # @param [#to_s] name function name + # @param [Array] arg_types function's argument types + # @return [Array] + # This function returns a list of possible names to lookup. + # @note Function names on windows may be decorated if they are using stdcall. See + # * http://en.wikipedia.org/wiki/Name_mangling#C_name_decoration_in_Microsoft_Windows + # * http://msdn.microsoft.com/en-us/library/zxk0tw93%28v=VS.100%29.aspx + # * http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL + # Note that decorated names can be overridden via def files. Also note that the + # windows api, although using, doesn't have decorated names. + def function_names(name, arg_types) + result = [name.to_s] + if ffi_convention == :stdcall + # Get the size of each parameter + size = arg_types.inject(0) do |mem, arg| + size = arg.size + # The size must be a multiple of 4 + size += (4 - size) % 4 + mem + size + end + + result << "_#{name.to_s}@#{size}" # win32 + result << "#{name.to_s}@#{size}" # win64 + end + result + end + + # @overload attach_variable(mname, cname, type) + # @param [#to_s] mname name of ruby method to attach as + # @param [#to_s] cname name of C variable to attach + # @param [DataConverter, Struct, Symbol, Type] type C variable's type + # @example + # module Bar + # extend FFI::Library + # ffi_lib 'my_lib' + # attach_variable :c_myvar, :myvar, :long + # end + # # now callable via Bar.c_myvar + # @overload attach_variable(cname, type) + # @param [#to_s] mname name of ruby method to attach as + # @param [DataConverter, Struct, Symbol, Type] type C variable's type + # @example + # module Bar + # extend FFI::Library + # ffi_lib 'my_lib' + # attach_variable :myvar, :long + # end + # # now callable via Bar.myvar + # @return [DynamicLibrary::Symbol] + # @raise {FFI::NotFoundError} if +cname+ cannot be found in libraries + # + # Attach C variable +cname+ to this module. + def attach_variable(mname, a1, a2 = nil) + cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ] + mname = mname.to_sym + address = nil + ffi_libraries.each do |lib| + begin + address = lib.find_variable(cname.to_s) + break unless address.nil? + rescue LoadError + end + end + + raise FFI::NotFoundError.new(cname, ffi_libraries) if address.nil? || address.null? + if type.is_a?(Class) && type < FFI::Struct + # If it is a global struct, just attach directly to the pointer + s = s = type.new(address) # Assigning twice to suppress unused variable warning + self.module_eval(<<-code, __FILE__, __LINE__) + @ffi_gsvars = {} unless defined?(@ffi_gsvars) + @ffi_gsvars[#{mname.inspect}] = s + def self.#{mname} + @ffi_gsvars[#{mname.inspect}] + end + code + + else + sc = Class.new(FFI::Struct) + sc.layout :gvar, find_type(type) + s = sc.new(address) + # + # Attach to this module as mname/mname= + # + self.module_eval(<<-code, __FILE__, __LINE__) + @ffi_gvars = {} unless defined?(@ffi_gvars) + @ffi_gvars[#{mname.inspect}] = s + def self.#{mname} + @ffi_gvars[#{mname.inspect}][:gvar] + end + def self.#{mname}=(value) + @ffi_gvars[#{mname.inspect}][:gvar] = value + end + code + + end + + address + end + + + # @overload callback(name, params, ret) + # @param name callback name to add to type map + # @param [Array] params array of parameters' types + # @param [DataConverter, Struct, Symbol, Type] ret callback return type + # @overload callback(params, ret) + # @param [Array] params array of parameters' types + # @param [DataConverter, Struct, Symbol, Type] ret callback return type + # @return [FFI::CallbackInfo] + def callback(*args) + raise ArgumentError, "wrong number of arguments" if args.length < 2 || args.length > 3 + name, params, ret = if args.length == 3 + args + else + [ nil, args[0], args[1] ] + end + + native_params = params.map { |e| find_type(e) } + raise ArgumentError, "callbacks cannot have variadic parameters" if native_params.include?(FFI::Type::VARARGS) + options = Hash.new + options[:convention] = ffi_convention + options[:enums] = @ffi_enums if defined?(@ffi_enums) + ret_type = find_type(ret) + if ret_type == Type::STRING + raise TypeError, ":string is not allowed as return type of callbacks" + end + cb = FFI::CallbackInfo.new(ret_type, native_params, options) + + # Add to the symbol -> type map (unless there was no name) + unless name.nil? + typedef cb, name + end + + cb + end + + # Register or get an already registered type definition. + # + # To register a new type definition, +old+ should be a {FFI::Type}. +add+ + # is in this case the type definition. + # + # If +old+ is a {DataConverter}, a {Type::Mapped} is returned. + # + # If +old+ is +:enum+ + # * and +add+ is an +Array+, a call to {#enum} is made with +add+ as single parameter; + # * in others cases, +info+ is used to create a named enum. + # + # If +old+ is a key for type map, #typedef get +old+ type definition. + # + # @param [DataConverter, Symbol, Type] old + # @param [Symbol] add + # @param [Symbol] info + # @return [FFI::Enum, FFI::Type] + def typedef(old, add, info=nil) + @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs) + + @ffi_typedefs[add] = if old.kind_of?(FFI::Type) + old + + elsif @ffi_typedefs.has_key?(old) + @ffi_typedefs[old] + + elsif old.is_a?(DataConverter) + FFI::Type::Mapped.new(old) + + elsif old == :enum + if add.kind_of?(Array) + self.enum(add) + else + self.enum(info, add) + end + + else + FFI.find_type(old) + end + end + + # @param [DataConverter, Type, Struct, Symbol] t type to find + # @return [Type] + # Find a type definition. + def find_type(t) + if t.kind_of?(Type) + t + + elsif defined?(@ffi_typedefs) && @ffi_typedefs.has_key?(t) + @ffi_typedefs[t] + + elsif t.is_a?(Class) && t < Struct + Type::POINTER + + elsif t.is_a?(DataConverter) + # Add a typedef so next time the converter is used, it hits the cache + typedef Type::Mapped.new(t), t + + end || FFI.find_type(t) + end + + private + # Generic enum builder + # @param [Class] klass can be one of FFI::Enum or FFI::Bitmask + # @param args (see #enum or #bitmask) + def generic_enum(klass, *args) + native_type = args.first.kind_of?(FFI::Type) ? args.shift : nil + name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array) + [ args[0], args[1] ] + elsif args[0].kind_of?(Array) + [ nil, args[0] ] + else + [ nil, args ] + end + @ffi_enums = FFI::Enums.new unless defined?(@ffi_enums) + @ffi_enums << (e = native_type ? klass.new(native_type, values, name) : klass.new(values, name)) + + # If called with a name, add a typedef alias + typedef(e, name) if name + e + end + + public + # @overload enum(name, values) + # Create a named enum. + # @example + # enum :foo, [:zero, :one, :two] # named enum + # @param [Symbol] name name for new enum + # @param [Array] values values for enum + # @overload enum(*args) + # Create an unnamed enum. + # @example + # enum :zero, :one, :two # unnamed enum + # @param args values for enum + # @overload enum(values) + # Create an unnamed enum. + # @example + # enum [:zero, :one, :two] # unnamed enum, equivalent to above example + # @param [Array] values values for enum + # @overload enum(native_type, name, values) + # Create a named enum and specify the native type. + # @example + # enum FFI::Type::UINT64, :foo, [:zero, :one, :two] # named enum + # @param [FFI::Type] native_type native type for new enum + # @param [Symbol] name name for new enum + # @param [Array] values values for enum + # @overload enum(native_type, *args) + # Create an unnamed enum and specify the native type. + # @example + # enum FFI::Type::UINT64, :zero, :one, :two # unnamed enum + # @param [FFI::Type] native_type native type for new enum + # @param args values for enum + # @overload enum(native_type, values) + # Create an unnamed enum and specify the native type. + # @example + # enum Type::UINT64, [:zero, :one, :two] # unnamed enum, equivalent to above example + # @param [FFI::Type] native_type native type for new enum + # @param [Array] values values for enum + # @return [FFI::Enum] + # Create a new {FFI::Enum}. + def enum(*args) + generic_enum(FFI::Enum, *args) + end + + # @overload bitmask(name, values) + # Create a named bitmask + # @example + # bitmask :foo, [:red, :green, :blue] # bits 0,1,2 are used + # bitmask :foo, [:red, :green, 5, :blue] # bits 0,5,6 are used + # @param [Symbol] name for new bitmask + # @param [Array] values for new bitmask + # @overload bitmask(*args) + # Create an unamed bitmask + # @example + # bm = bitmask :red, :green, :blue # bits 0,1,2 are used + # bm = bitmask :red, :green, 5, blue # bits 0,5,6 are used + # @param [Symbol, Integer] args values for new bitmask + # @overload bitmask(values) + # Create an unamed bitmask + # @example + # bm = bitmask [:red, :green, :blue] # bits 0,1,2 are used + # bm = bitmask [:red, :green, 5, blue] # bits 0,5,6 are used + # @param [Array] values for new bitmask + # @overload bitmask(native_type, name, values) + # Create a named enum and specify the native type. + # @example + # bitmask FFI::Type::UINT64, :foo, [:red, :green, :blue] + # @param [FFI::Type] native_type native type for new bitmask + # @param [Symbol] name for new bitmask + # @param [Array] values for new bitmask + # @overload bitmask(native_type, *args) + # @example + # bitmask FFI::Type::UINT64, :red, :green, :blue + # @param [FFI::Type] native_type native type for new bitmask + # @param [Symbol, Integer] args values for new bitmask + # @overload bitmask(native_type, values) + # Create a named enum and specify the native type. + # @example + # bitmask FFI::Type::UINT64, [:red, :green, :blue] + # @param [FFI::Type] native_type native type for new bitmask + # @param [Array] values for new bitmask + # @return [FFI::Bitmask] + # Create a new FFI::Bitmask + def bitmask(*args) + generic_enum(FFI::Bitmask, *args) + end + + # @param name + # @return [FFI::Enum] + # Find an enum by name. + def enum_type(name) + @ffi_enums.find(name) if defined?(@ffi_enums) + end + + # @param symbol + # @return [FFI::Enum] + # Find an enum by a symbol it contains. + def enum_value(symbol) + @ffi_enums.__map_symbol(symbol) + end + + # Retrieve all attached functions and their function signature + # + # This method returns a Hash of method names of attached functions connected by #attach_function and the corresponding function type. + # The function type responds to #return_type and #param_types which return the FFI types of the function signature. + # + # @return [Hash< Symbol => [FFI::Function, FFI::VariadicInvoker] >] + def attached_functions + @ffi_functions || {} + end + + # Retrieve all attached variables and their type + # + # This method returns a Hash of variable names and the corresponding type or variables connected by #attach_variable . + # + # @return [Hash< Symbol => ffi_type >] + def attached_variables + ( + (defined?(@ffi_gsvars) ? @ffi_gsvars : {}).map do |name, gvar| + [name, gvar.class] + end + + (defined?(@ffi_gvars) ? @ffi_gvars : {}).map do |name, gvar| + [name, gvar.layout[:gvar].type] + end + ).to_h + end + + # Freeze all definitions of the module + # + # This freezes the module's definitions, so that it can be used in a Ractor. + # No further functions or variables can be attached and no further enums or typedefs can be created in this module afterwards. + def freeze + # @ffi_function_procs is only used on aarch64-mingw-ucrt + instance_variable_get("@ffi_function_procs")&.each do |name, func| + # Redefine attached functions as Ractor-shareable. + # The function Proc can't be shareable from the beginning, since it references enums and typedefs. + this = FFI.make_shareable(func) + body = FFI.shareable_proc(self: nil) do |*args, &block| + this.call(*args, &block) + end + undef_method(name) + singleton_class.undef_method(name) + + define_method(name, body) + define_singleton_method(name, body) + end + + instance_variables.each do |name| + var = instance_variable_get(name) + FFI.make_shareable(var) + end + super + nil + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library_path.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library_path.rb new file mode 100644 index 00000000..5575a5f1 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/library_path.rb @@ -0,0 +1,109 @@ +# +# Copyright (C) 2023 Lars Kanis +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # Transform a generic library name and ABI number to a platform library name + # + # Example: + # module LibVips + # extend FFI::Library + # ffi_lib LibraryPath.new("vips", abi_number: 42) + # end + # + # This translates to the following library file names: + # libvips-42.dll on Windows + # libvips.so.42 on Linux + # libvips.42.dylib on Macos + # + # See https://packaging.ubuntu.com/html/libraries.html for more information about library naming. + class LibraryPath + attr_reader :name + attr_reader :abi_number + attr_reader :root + + # Build a new library path + # + # * name : The name of the library without file prefix or suffix. + # * abi_number : The ABI number of the library. + # * root : An optional base path prepended to the library name. + def initialize(name, abi_number: nil, root: nil) + @name = name + @abi_number = abi_number + @root = root + end + + def self.wrap(value) + # We allow instances of LibraryPath to pass through transparently: + return value if value.is_a?(self) + + # We special case a library named 'c' to be the standard C library: + return Library::LIBC if value == 'c' + + # If provided a relative file name we convert it into a library path: + if value && File.basename(value) == value + return self.new(value) + end + + # Otherwise, we assume it's a full path to a library: + return value + end + + def full_name + # If the abi_number is given, we format it specifically according to platform rules: + if abi_number + if Platform.windows? + "#{Platform::LIBPREFIX}#{name}-#{abi_number}.#{Platform::LIBSUFFIX}" + elsif Platform.mac? + "#{Platform::LIBPREFIX}#{name}.#{abi_number}.#{Platform::LIBSUFFIX}" + else # Linux? BSD? etc. + "#{Platform::LIBPREFIX}#{name}.#{Platform::LIBSUFFIX}.#{abi_number}" + end + else + # Otherwise we just add prefix and suffix: + lib = name + # Add library prefix if missing + lib = Platform::LIBPREFIX + lib unless lib =~ /^#{Platform::LIBPREFIX}/ + # Add library extension if missing + r = Platform.windows? || Platform.mac? ? "\\.#{Platform::LIBSUFFIX}$" : "\\.so($|\\.[1234567890]+)" + lib += ".#{Platform::LIBSUFFIX}" unless lib =~ /#{r}/ + lib + end + end + + def to_s + if root + # If the root path is given, we generate the full path: + File.join(root, full_name) + else + full_name + end + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/managedstruct.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/managedstruct.rb new file mode 100644 index 00000000..5d243e5b --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/managedstruct.rb @@ -0,0 +1,84 @@ +# Copyright (C) 2008 Mike Dalessio +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module FFI + # + # FFI::ManagedStruct allows custom garbage-collection of your FFI::Structs. + # + # The typical use case would be when interacting with a library + # that has a nontrivial memory management design, such as a linked + # list or a binary tree. + # + # When the {Struct} instance is garbage collected, FFI::ManagedStruct will + # invoke the class's release() method during object finalization. + # + # @example Example usage: + # module MyLibrary + # ffi_lib "libmylibrary" + # attach_function :new_dlist, [], :pointer + # attach_function :destroy_dlist, [:pointer], :void + # end + # + # class DoublyLinkedList < FFI::ManagedStruct + # @@@ + # struct do |s| + # s.name 'struct dlist' + # s.include 'dlist.h' + # s.field :head, :pointer + # s.field :tail, :pointer + # end + # @@@ + # + # def self.release ptr + # MyLibrary.destroy_dlist(ptr) + # end + # end + # + # begin + # ptr = DoublyLinkedList.new(MyLibrary.new_dlist) + # # do something with the list + # end + # # struct is out of scope, and will be GC'd using DoublyLinkedList#release + # + # + class ManagedStruct < FFI::Struct + + # @overload initialize(pointer) + # @param [Pointer] pointer + # Create a new ManagedStruct which will invoke the class method #release on + # @overload initialize + # A new instance of FFI::ManagedStruct. + def initialize(pointer=nil) + raise NoMethodError, "release() not implemented for class #{self}" unless self.class.respond_to?(:release, true) + raise ArgumentError, "Must supply a pointer to memory for the Struct" unless pointer + super AutoPointer.new(pointer, self.class.method(:release)) + end + + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/memorypointer.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/memorypointer.rb new file mode 100644 index 00000000..9f07bc69 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/memorypointer.rb @@ -0,0 +1 @@ +# This class is now implemented in C diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform.rb new file mode 100644 index 00000000..5ac4dd70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform.rb @@ -0,0 +1,187 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +require 'rbconfig' +require_relative 'compat' + +module FFI + class PlatformError < LoadError; end + + # This module defines different constants and class methods to play with + # various platforms. + module Platform + OS = FFI.make_shareable(case RbConfig::CONFIG['host_os'].downcase + when /linux/ + "linux" + when /darwin/ + "darwin" + when /freebsd/ + "freebsd" + when /netbsd/ + "netbsd" + when /openbsd/ + "openbsd" + when /dragonfly/ + "dragonflybsd" + when /sunos|solaris/ + "solaris" + when /mingw|mswin/ + "windows" + else + RbConfig::CONFIG['host_os'].downcase + end) + + OSVERSION = RbConfig::CONFIG['host_os'].gsub(/[^\d]/, '').to_i + + CPU = FFI.make_shareable(RbConfig::CONFIG['host_cpu']) + + ARCH = FFI.make_shareable(case CPU.downcase + when /amd64|x86_64|x64/ + "x86_64" + when /i\d86|x86|i86pc/ + "i386" + when /ppc64|powerpc64/ + "powerpc64" + when /ppc|powerpc/ + "powerpc" + when /sparcv9|sparc64/ + "sparcv9" + when /arm64|aarch64/ # MacOS calls it "arm64", other operating systems "aarch64" + "aarch64" + when /^arm/ + if OS == "darwin" # Ruby before 3.0 reports "arm" instead of "arm64" as host_cpu on darwin + "aarch64" + else + "arm" + end + else + RbConfig::CONFIG['host_cpu'] + end) + + private + # @param [String) os + # @return [Boolean] + # Test if current OS is +os+. + def self.is_os(os) + OS == os + end + + IS_GNU = defined?(GNU_LIBC) + IS_LINUX = is_os("linux") + IS_MAC = is_os("darwin") + IS_FREEBSD = is_os("freebsd") + IS_NETBSD = is_os("netbsd") + IS_OPENBSD = is_os("openbsd") + IS_DRAGONFLYBSD = is_os("dragonfly") + IS_SOLARIS = is_os("solaris") + IS_WINDOWS = is_os("windows") + IS_BSD = IS_MAC || IS_FREEBSD || IS_NETBSD || IS_OPENBSD || IS_DRAGONFLYBSD + + # Add the version for known ABI breaks + name_version = "12" if IS_FREEBSD && OSVERSION >= 12 # 64-bit inodes + + NAME = FFI.make_shareable("#{ARCH}-#{OS}#{name_version}") + CONF_DIR = FFI.make_shareable(File.join(File.dirname(__FILE__), 'platform', NAME)) + + public + + LIBPREFIX = FFI.make_shareable(case OS + when /windows|msys/ + '' + when /cygwin/ + 'cyg' + else + 'lib' + end) + + LIBSUFFIX = FFI.make_shareable(case OS + when /darwin/ + 'dylib' + when /linux|bsd|solaris/ + 'so' + when /windows|cygwin|msys/ + 'dll' + else + # Punt and just assume a sane unix (i.e. anything but AIX) + 'so' + end) + + LIBC = FFI.make_shareable(if IS_WINDOWS + crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase' + "#{crtname}.dll" + elsif IS_GNU + GNU_LIBC + elsif OS == 'cygwin' + "cygwin1.dll" + elsif OS == 'msys' + # Not sure how msys 1.0 behaves, tested on MSYS2. + "msys-2.0.dll" + else + "#{LIBPREFIX}c.#{LIBSUFFIX}" + end) + + LITTLE_ENDIAN = 1234 unless defined?(LITTLE_ENDIAN) + BIG_ENDIAN = 4321 unless defined?(BIG_ENDIAN) + unless defined?(BYTE_ORDER) + BYTE_ORDER = [0x12345678].pack("I") == [0x12345678].pack("N") ? BIG_ENDIAN : LITTLE_ENDIAN + end + + # Test if current OS is a *BSD (include MAC) + # @return [Boolean] + def self.bsd? + IS_BSD + end + + # Test if current OS is Windows + # @return [Boolean] + def self.windows? + IS_WINDOWS + end + + # Test if current OS is Mac OS + # @return [Boolean] + def self.mac? + IS_MAC + end + + # Test if current OS is Solaris (Sun OS) + # @return [Boolean] + def self.solaris? + IS_SOLARIS + end + + # Test if current OS is a unix OS + # @return [Boolean] + def self.unix? + !IS_WINDOWS + end + end +end + diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf new file mode 100644 index 00000000..68841bb1 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-darwin/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = long +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_string_t[37] = char +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sae_associd_t = uint +rbx.platform.typedef.sae_connid_t = uint +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_off_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf new file mode 100644 index 00000000..8d111e0a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long_long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf new file mode 100644 index 00000000..3ccb8f66 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-freebsd12/types.conf @@ -0,0 +1,181 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = uint +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__char16_t = ushort +rbx.platform.typedef.__char32_t = uint +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = long +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__daddr_t = long +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__rman_res_t = ulong +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = long +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = ulong +rbx.platform.typedef.__vm_paddr_t = ulong +rbx.platform.typedef.__vm_size_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.cap_ioctl_t = ulong +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.kpaddr_t = ulong +rbx.platform.typedef.ksize_t = ulong +rbx.platform.typedef.kssize_t = long +rbx.platform.typedef.kvaddr_t = ulong +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.rman_res_t = ulong +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.rune_t = int +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_ooffset_t = ulong +rbx.platform.typedef.vm_paddr_t = ulong +rbx.platform.typedef.vm_pindex_t = ulong +rbx.platform.typedef.vm_size_t = ulong +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf new file mode 100644 index 00000000..c56206e0 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-linux/types.conf @@ -0,0 +1,175 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = int +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = uint +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = ushort +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = ushort +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = long +rbx.platform.typedef.__kernel_size_t = ulong +rbx.platform.typedef.__kernel_ssize_t = long +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds64_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf new file mode 100644 index 00000000..6abc9c09 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-openbsd/types.conf @@ -0,0 +1,134 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf new file mode 100644 index 00000000..5bdbbde2 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/aarch64-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = long_long +rbx.platform.typedef._sigset_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long_long +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = long_long +rbx.platform.typedef.ptrdiff_t = long_long +rbx.platform.typedef.rsize_t = ulong_long +rbx.platform.typedef.size_t = ulong_long +rbx.platform.typedef.ssize_t = long_long +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong_long +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf new file mode 100644 index 00000000..cfbb90f3 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf new file mode 100644 index 00000000..523370d9 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-freebsd12/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong_long +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf new file mode 100644 index 00000000..a070d394 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/arm-linux/types.conf @@ -0,0 +1,132 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf new file mode 100644 index 00000000..c8a81411 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa1.1-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf new file mode 100644 index 00000000..c8a81411 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/hppa2.0-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf new file mode 100644 index 00000000..93f6b861 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-cygwin/types.conf @@ -0,0 +1,3 @@ +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.ssize_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf new file mode 100644 index 00000000..ae100f41 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-darwin/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = int +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf new file mode 100644 index 00000000..6c882d48 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf new file mode 100644 index 00000000..523370d9 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-freebsd12/types.conf @@ -0,0 +1,152 @@ + +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = uint +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpumask_t = uint +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = int +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long_long +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = int +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong_long +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = int +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = long_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = uint +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__u_register_t = uint +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = uint +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = uint +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = uint +rbx.platform.typedef.__vm_ooffset_t = long_long +rbx.platform.typedef.__vm_paddr_t = uint +rbx.platform.typedef.__vm_pindex_t = ulong_long +rbx.platform.typedef.__vm_size_t = uint +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = uint +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpumask_t = uint +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long_long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = long_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_register_t = uint +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = uint +rbx.platform.typedef.vm_ooffset_t = long_long +rbx.platform.typedef.vm_paddr_t = uint +rbx.platform.typedef.vm_pindex_t = ulong_long +rbx.platform.typedef.vm_size_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf new file mode 100644 index 00000000..fa2fa8ce --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-gnu/types.conf @@ -0,0 +1,107 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsid_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__pthread_key = int +rbx.platform.typedef.__pthread_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__sigset_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.fsid_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.pthread_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf new file mode 100644 index 00000000..feb6bc47 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-linux/types.conf @@ -0,0 +1,103 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf new file mode 100644 index 00000000..a5aba894 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-netbsd/types.conf @@ -0,0 +1,126 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf new file mode 100644 index 00000000..15a0d613 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-openbsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf new file mode 100644 index 00000000..22a2414e --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-solaris/types.conf @@ -0,0 +1,122 @@ +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.datalink_id_t = uint +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lgrp_id_t = long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf new file mode 100644 index 00000000..a5d0b058 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/i386-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = int +rbx.platform.typedef._sigset_t = ulong +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rsize_t = uint +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf new file mode 100644 index 00000000..e0eeecc9 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/ia64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf new file mode 100644 index 00000000..aa8716d8 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/loongarch64-linux/types.conf @@ -0,0 +1,141 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mips64el-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsel-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf new file mode 100644 index 00000000..24e82024 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa32r6el-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/mipsisa64r6el-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf new file mode 100644 index 00000000..cbd20e78 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-aix/types.conf @@ -0,0 +1,180 @@ +rbx.platform.typedef.UTF32Char = uint +rbx.platform.typedef.UniChar = ushort +rbx.platform.typedef.__cptr32 = string +rbx.platform.typedef.__cptr64 = ulong_long +rbx.platform.typedef.__long32_t = long +rbx.platform.typedef.__long64_t = int +rbx.platform.typedef.__ptr32 = pointer +rbx.platform.typedef.__ptr64 = ulong_long +rbx.platform.typedef.__ulong32_t = ulong +rbx.platform.typedef.__ulong64_t = uint +rbx.platform.typedef.aptx_t = ushort +rbx.platform.typedef.blkcnt32_t = int +rbx.platform.typedef.blkcnt64_t = ulong_long +rbx.platform.typedef.blkcnt_t = int +rbx.platform.typedef.blksize32_t = int +rbx.platform.typedef.blksize64_t = ulong_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.boolean_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.chan_t = int +rbx.platform.typedef.class_id_t = uint +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = long_long +rbx.platform.typedef.cnt64_t = long_long +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.crid_t = int +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev32_t = uint +rbx.platform.typedef.dev64_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.esid_t = uint +rbx.platform.typedef.ext_t = int +rbx.platform.typedef.fpos64_t = long_long +rbx.platform.typedef.fpos_t = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino32_t = uint +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16 = short +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32 = int +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int32long64_t = int +rbx.platform.typedef.int64 = long_long +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8 = char +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intfast_t = int +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.krpn_t = int +rbx.platform.typedef.kvmhandle_t = ulong +rbx.platform.typedef.kvmid_t = long +rbx.platform.typedef.kvpn_t = int +rbx.platform.typedef.level_t = int +rbx.platform.typedef.liobn_t = uint +rbx.platform.typedef.long32int64_t = long +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.mid_t = pointer +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.mtyp_t = long +rbx.platform.typedef.nlink_t = short +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.paddr_t = long +rbx.platform.typedef.pdtx_t = int +rbx.platform.typedef.pid32_t = int +rbx.platform.typedef.pid64_t = ulong_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pshift_t = ushort +rbx.platform.typedef.psize_t = long_long +rbx.platform.typedef.psx_t = short +rbx.platform.typedef.ptex_t = ulong +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.rpn64_t = long_long +rbx.platform.typedef.rpn_t = int +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.signal_t = int +rbx.platform.typedef.size64_t = ulong_long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.slab_t[12] = char +rbx.platform.typedef.snidx_t = int +rbx.platform.typedef.socklen_t = ulong +rbx.platform.typedef.soff_t = int +rbx.platform.typedef.sshift_t = ushort +rbx.platform.typedef.ssize64_t = long_long +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.swhatx_t = ulong +rbx.platform.typedef.tid32_t = int +rbx.platform.typedef.tid64_t = ulong_long +rbx.platform.typedef.tid_t = int +rbx.platform.typedef.time32_t = int +rbx.platform.typedef.time64_t = long_long +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer32_t = int +rbx.platform.typedef.timer64_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16 = ushort +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32 = uint +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64 = ulong_long +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8 = uchar +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar = uchar +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint32long64_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintfast_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong32int64_t = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unidx_t = int +rbx.platform.typedef.unit_addr_t = ulong_long +rbx.platform.typedef.ureg_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.va_list = string +rbx.platform.typedef.vmfkey_t = uint +rbx.platform.typedef.vmhandle32_t = uint +rbx.platform.typedef.vmhandle_t = ulong +rbx.platform.typedef.vmhwkey_t = int +rbx.platform.typedef.vmid32_t = int +rbx.platform.typedef.vmid64_t = long_long +rbx.platform.typedef.vmid_t = long +rbx.platform.typedef.vmidx_t = int +rbx.platform.typedef.vmkey_t = int +rbx.platform.typedef.vmlpghandle_t = ulong +rbx.platform.typedef.vmm_lock_t = int +rbx.platform.typedef.vmnodeidx_t = int +rbx.platform.typedef.vmprkey_t = uint +rbx.platform.typedef.vmsize_t = int +rbx.platform.typedef.vpn_t = int +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = uint +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf new file mode 100644 index 00000000..ae100f41 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-darwin/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = int +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf new file mode 100644 index 00000000..42eec130 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-linux/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf new file mode 100644 index 00000000..aea79551 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc-openbsd/types.conf @@ -0,0 +1,156 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong +rbx.platform.typedef.wchar_t = int +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf new file mode 100644 index 00000000..b61f4f70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf new file mode 100644 index 00000000..9ac9c2e5 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/powerpc64le-linux/types.conf @@ -0,0 +1,100 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf new file mode 100644 index 00000000..ede0f985 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/riscv64-linux/types.conf @@ -0,0 +1,104 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf new file mode 100644 index 00000000..291b0326 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf new file mode 100644 index 00000000..32a7feba --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/s390x-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf new file mode 100644 index 00000000..aea09d32 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long_long +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf new file mode 100644 index 00000000..a1548e56 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparc-solaris/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.() = pointer +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.Psocklen_t = pointer +rbx.platform.typedef.avl_index_t = uint +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = long +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.kid_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.size_t) = pointer +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.ts_t = long_long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = long +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf new file mode 100644 index 00000000..7626bfce --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-linux/types.conf @@ -0,0 +1,102 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.*__qaddr_t = long +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf new file mode 100644 index 00000000..aea79551 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-openbsd/types.conf @@ -0,0 +1,156 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong +rbx.platform.typedef.wchar_t = int +rbx.platform.typedef.wint_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf new file mode 100644 index 00000000..a1548e56 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sparcv9-solaris/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.() = pointer +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.Psocklen_t = pointer +rbx.platform.typedef.avl_index_t = uint +rbx.platform.typedef.blkcnt64_t = long_long +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong_long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt64_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = long +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int) = pointer +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.kid_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = ulong +rbx.platform.typedef.minor_t = ulong +rbx.platform.typedef.mode_t = ulong +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long_long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = long +rbx.platform.typedef.poolid_t = long +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = long +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.size_t) = pointer +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = long +rbx.platform.typedef.t_uscalar_t = ulong +rbx.platform.typedef.taskid_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.ts_t = long_long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = long +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong_long +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = long diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf new file mode 100644 index 00000000..aa8716d8 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/sw_64-linux/types.conf @@ -0,0 +1,141 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf new file mode 100644 index 00000000..5bef6d70 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-cygwin/types.conf @@ -0,0 +1,3 @@ +rbx.platform.typedef.ptrdiff_t = int64 +rbx.platform.typedef.size_t = uint64 +rbx.platform.typedef.ssize_t = int64 diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf new file mode 100644 index 00000000..68841bb1 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-darwin/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.__darwin_blkcnt_t = long_long +rbx.platform.typedef.__darwin_blksize_t = int +rbx.platform.typedef.__darwin_clock_t = ulong +rbx.platform.typedef.__darwin_ct_rune_t = int +rbx.platform.typedef.__darwin_dev_t = int +rbx.platform.typedef.__darwin_fsblkcnt_t = uint +rbx.platform.typedef.__darwin_fsfilcnt_t = uint +rbx.platform.typedef.__darwin_gid_t = uint +rbx.platform.typedef.__darwin_id_t = uint +rbx.platform.typedef.__darwin_ino64_t = ulong_long +rbx.platform.typedef.__darwin_ino_t = ulong_long +rbx.platform.typedef.__darwin_intptr_t = long +rbx.platform.typedef.__darwin_mach_port_name_t = uint +rbx.platform.typedef.__darwin_mach_port_t = uint +rbx.platform.typedef.__darwin_mode_t = ushort +rbx.platform.typedef.__darwin_natural_t = uint +rbx.platform.typedef.__darwin_off_t = long_long +rbx.platform.typedef.__darwin_pid_t = int +rbx.platform.typedef.__darwin_pthread_key_t = ulong +rbx.platform.typedef.__darwin_ptrdiff_t = long +rbx.platform.typedef.__darwin_rune_t = int +rbx.platform.typedef.__darwin_sigset_t = uint +rbx.platform.typedef.__darwin_size_t = ulong +rbx.platform.typedef.__darwin_socklen_t = uint +rbx.platform.typedef.__darwin_ssize_t = long +rbx.platform.typedef.__darwin_suseconds_t = int +rbx.platform.typedef.__darwin_time_t = long +rbx.platform.typedef.__darwin_uid_t = uint +rbx.platform.typedef.__darwin_useconds_t = uint +rbx.platform.typedef.__darwin_uuid_string_t[37] = char +rbx.platform.typedef.__darwin_uuid_t[16] = uchar +rbx.platform.typedef.__darwin_wchar_t = int +rbx.platform.typedef.__darwin_wint_t = int +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.fd_mask = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = uint +rbx.platform.typedef.fsfilcnt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino64_t = ulong_long +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.rsize_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sae_associd_t = uint +rbx.platform.typedef.sae_connid_t = uint +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.syscall_arg_t = ulong_long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.user_addr_t = ulong_long +rbx.platform.typedef.user_long_t = long_long +rbx.platform.typedef.user_off_t = long_long +rbx.platform.typedef.user_size_t = ulong_long +rbx.platform.typedef.user_ssize_t = long_long +rbx.platform.typedef.user_time_t = long_long +rbx.platform.typedef.user_ulong_t = ulong_long +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf new file mode 100644 index 00000000..889f6a32 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-dragonflybsd/types.conf @@ -0,0 +1,130 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = int +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intlp_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintlp_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = ulong +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_daddr_t = uint +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.v_caddr_t = pointer +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf new file mode 100644 index 00000000..8dbe3703 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long_long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long_long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf new file mode 100644 index 00000000..31b1073d --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-freebsd12/types.conf @@ -0,0 +1,158 @@ +rbx.platform.typedef.*) = pointer +rbx.platform.typedef.___wchar_t = int +rbx.platform.typedef.__accmode_t = int +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__char16_t = ushort +rbx.platform.typedef.__char32_t = uint +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpulevel_t = int +rbx.platform.typedef.__cpusetid_t = int +rbx.platform.typedef.__cpuwhich_t = int +rbx.platform.typedef.__critical_t = long +rbx.platform.typedef.__ct_rune_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = ulong +rbx.platform.typedef.__fflags_t = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intfptr_t = long +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__lwpid_t = int +rbx.platform.typedef.__mode_t = ushort +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = long +rbx.platform.typedef.__rman_res_t = ulong +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = long +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__u_register_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintfptr_t = ulong +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vm_offset_t = ulong +rbx.platform.typedef.__vm_paddr_t = ulong +rbx.platform.typedef.__vm_size_t = ulong +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.accmode_t = int +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.c_caddr_t = pointer +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.cap_ioctl_t = ulong +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpulevel_t = int +rbx.platform.typedef.cpusetid_t = int +rbx.platform.typedef.cpuwhich_t = int +rbx.platform.typedef.critical_t = long +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fflags_t = uint +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = long +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.ksize_t = ulong +rbx.platform.typedef.kvaddr_t = ulong +rbx.platform.typedef.lwpid_t = int +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = long +rbx.platform.typedef.rman_res_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.segsz_t = long +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_ooffset_t = long +rbx.platform.typedef.vm_paddr_t = ulong +rbx.platform.typedef.vm_pindex_t = ulong +rbx.platform.typedef.vm_size_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf new file mode 100644 index 00000000..d5ddfa79 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-haiku/types.conf @@ -0,0 +1,117 @@ +rbx.platform.typedef.__haiku_addr_t = ulong +rbx.platform.typedef.__haiku_generic_addr_t = ulong +rbx.platform.typedef.__haiku_int16 = short +rbx.platform.typedef.__haiku_int32 = int +rbx.platform.typedef.__haiku_int64 = long +rbx.platform.typedef.__haiku_int8 = char +rbx.platform.typedef.__haiku_phys_addr_t = ulong +rbx.platform.typedef.__haiku_phys_saddr_t = long +rbx.platform.typedef.__haiku_saddr_t = long +rbx.platform.typedef.__haiku_std_int16 = short +rbx.platform.typedef.__haiku_std_int32 = int +rbx.platform.typedef.__haiku_std_int64 = long +rbx.platform.typedef.__haiku_std_int8 = char +rbx.platform.typedef.__haiku_std_uint16 = ushort +rbx.platform.typedef.__haiku_std_uint32 = uint +rbx.platform.typedef.__haiku_std_uint64 = ulong +rbx.platform.typedef.__haiku_std_uint8 = uchar +rbx.platform.typedef.__haiku_uint16 = ushort +rbx.platform.typedef.__haiku_uint32 = uint +rbx.platform.typedef.__haiku_uint64 = ulong +rbx.platform.typedef.__haiku_uint8 = uchar +rbx.platform.typedef.addr_t = ulong +rbx.platform.typedef.bigtime_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = pointer +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = int +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fd_mask = uint +rbx.platform.typedef.fsblkcnt_t = long +rbx.platform.typedef.fsfilcnt_t = long +rbx.platform.typedef.generic_addr_t = ulong +rbx.platform.typedef.generic_size_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = int +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = long +rbx.platform.typedef.int16 = short +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32 = int +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64 = long +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8 = char +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = int +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nanotime_t = long +rbx.platform.typedef.nlink_t = int +rbx.platform.typedef.off_t = long +rbx.platform.typedef.perform_code = uint +rbx.platform.typedef.phys_addr_t = ulong +rbx.platform.typedef.phys_size_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.sig_atomic_t = int +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.status_t = int +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.type_code = uint +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16 = ushort +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32 = uint +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64 = ulong +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8 = uchar +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uint +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.umode_t = uint +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.unichar = ushort +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.void*) = pointer +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf new file mode 100644 index 00000000..060f1617 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-linux/types.conf @@ -0,0 +1,132 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = ulong +rbx.platform.typedef.__off64_t = long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long +rbx.platform.typedef.__rlim64_t = ulong +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ulong +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.quad_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf new file mode 100644 index 00000000..aa827c00 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-msys/types.conf @@ -0,0 +1,119 @@ +rbx.platform.typedef.*addr_t = char +rbx.platform.typedef.__ULong = uint +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = ulong +rbx.platform.typedef.__clockid_t = ulong +rbx.platform.typedef.__cpu_mask = ulong +rbx.platform.typedef.__dev_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long_long +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nl_item = int +rbx.platform.typedef.__nlink_t = ushort +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__sigset_t = ulong +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = int +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = ulong +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = ulong +rbx.platform.typedef._fpos64_t = long_long +rbx.platform.typedef._fpos_t = long +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = ulong +rbx.platform.typedef.clockid_t = ulong +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.fd_mask = ulong +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = long +rbx.platform.typedef.int_fast32_t = long +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long_long +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = ushort +rbx.platform.typedef.off_t = long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sbintime_t = long +rbx.platform.typedef.sig_atomic_t = int +rbx.platform.typedef.sigset_t = ulong +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = ulong +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_register_t = ulong +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ulong +rbx.platform.typedef.uint_fast32_t = ulong +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.useconds_t = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vm_offset_t = ulong +rbx.platform.typedef.vm_size_t = ulong +rbx.platform.typedef.wint_t = uint diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf new file mode 100644 index 00000000..15a0d613 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-netbsd/types.conf @@ -0,0 +1,128 @@ +rbx.platform.typedef.__clock_t = int +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = int +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = uint +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = int +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = int +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = int +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = int +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr64_t = long_long +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = uint +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = int +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = int +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = int +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf new file mode 100644 index 00000000..6abc9c09 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-openbsd/types.conf @@ -0,0 +1,134 @@ +rbx.platform.typedef.__blkcnt_t = long_long +rbx.platform.typedef.__blksize_t = int +rbx.platform.typedef.__clock_t = long_long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__cpuid_t = ulong +rbx.platform.typedef.__dev_t = int +rbx.platform.typedef.__fd_mask = uint +rbx.platform.typedef.__fixpt_t = uint +rbx.platform.typedef.__fsblkcnt_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong_long +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__in_addr_t = uint +rbx.platform.typedef.__in_port_t = ushort +rbx.platform.typedef.__ino_t = ulong_long +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_fast16_t = int +rbx.platform.typedef.__int_fast32_t = int +rbx.platform.typedef.__int_fast64_t = long_long +rbx.platform.typedef.__int_fast8_t = int +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = long +rbx.platform.typedef.__key_t = long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off_t = long_long +rbx.platform.typedef.__paddr_t = ulong +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__psize_t = ulong +rbx.platform.typedef.__ptrdiff_t = long +rbx.platform.typedef.__register_t = long +rbx.platform.typedef.__rlim_t = ulong_long +rbx.platform.typedef.__rune_t = int +rbx.platform.typedef.__sa_family_t = uchar +rbx.platform.typedef.__segsz_t = int +rbx.platform.typedef.__size_t = ulong +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__swblk_t = int +rbx.platform.typedef.__time_t = long_long +rbx.platform.typedef.__timer_t = int +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_fast16_t = uint +rbx.platform.typedef.__uint_fast32_t = uint +rbx.platform.typedef.__uint_fast64_t = ulong_long +rbx.platform.typedef.__uint_fast8_t = uint +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__uintptr_t = ulong +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.__vaddr_t = ulong +rbx.platform.typedef.__vsize_t = ulong +rbx.platform.typedef.__wchar_t = int +rbx.platform.typedef.__wctrans_t = pointer +rbx.platform.typedef.__wctype_t = pointer +rbx.platform.typedef.__wint_t = int +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.caddr_t = string +rbx.platform.typedef.clock_t = long_long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cpuid_t = ulong +rbx.platform.typedef.daddr32_t = int +rbx.platform.typedef.daddr_t = long_long +rbx.platform.typedef.dev_t = int +rbx.platform.typedef.fixpt_t = uint +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.key_t = long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.paddr_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.psize_t = ulong +rbx.platform.typedef.qaddr_t = pointer +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = uchar +rbx.platform.typedef.segsz_t = int +rbx.platform.typedef.sigset_t = uint +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.swblk_t = int +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.vaddr_t = ulong +rbx.platform.typedef.vsize_t = ulong diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf new file mode 100644 index 00000000..a7890d16 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-solaris/types.conf @@ -0,0 +1,122 @@ +rbx.platform.typedef.*caddr_t = char +rbx.platform.typedef.blkcnt64_t = long +rbx.platform.typedef.blkcnt_t = long +rbx.platform.typedef.blksize_t = int +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.cnt_t = short +rbx.platform.typedef.cpu_flag_t = ushort +rbx.platform.typedef.ctid_t = int +rbx.platform.typedef.daddr_t = long +rbx.platform.typedef.datalink_id_t = uint +rbx.platform.typedef.dev_t = ulong +rbx.platform.typedef.diskaddr_t = ulong_long +rbx.platform.typedef.disp_lock_t = uchar +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fds_mask = long +rbx.platform.typedef.fsblkcnt64_t = ulong +rbx.platform.typedef.fsblkcnt_t = ulong +rbx.platform.typedef.fsfilcnt64_t = ulong +rbx.platform.typedef.fsfilcnt_t = ulong +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.hrtime_t = long_long +rbx.platform.typedef.id_t = int +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.index_t = short +rbx.platform.typedef.ino64_t = ulong +rbx.platform.typedef.ino_t = ulong +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long +rbx.platform.typedef.intptr_t = long +rbx.platform.typedef.ipaddr_t = uint +rbx.platform.typedef.k_fltset_t = uint +rbx.platform.typedef.key_t = int +rbx.platform.typedef.len_t = ulong_long +rbx.platform.typedef.lgrp_id_t = int +rbx.platform.typedef.lock_t = uchar +rbx.platform.typedef.longlong_t = long_long +rbx.platform.typedef.major_t = uint +rbx.platform.typedef.minor_t = uint +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.model_t = uint +rbx.platform.typedef.nfds_t = ulong +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.o_dev_t = short +rbx.platform.typedef.o_gid_t = ushort +rbx.platform.typedef.o_ino_t = ushort +rbx.platform.typedef.o_mode_t = ushort +rbx.platform.typedef.o_nlink_t = short +rbx.platform.typedef.o_pid_t = short +rbx.platform.typedef.o_uid_t = ushort +rbx.platform.typedef.off64_t = long +rbx.platform.typedef.off_t = long +rbx.platform.typedef.offset_t = long_long +rbx.platform.typedef.pad64_t = long +rbx.platform.typedef.pfn_t = ulong +rbx.platform.typedef.pgcnt_t = ulong +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.poolid_t = int +rbx.platform.typedef.pri_t = short +rbx.platform.typedef.projid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_t = uint +rbx.platform.typedef.ptrdiff_t = long +rbx.platform.typedef.rlim64_t = ulong_long +rbx.platform.typedef.rlim_t = ulong +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = ulong +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.spgcnt_t = long +rbx.platform.typedef.ssize_t = long +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.sysid_t = short +rbx.platform.typedef.t_scalar_t = int +rbx.platform.typedef.t_uscalar_t = uint +rbx.platform.typedef.taskid_t = int +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = int +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_longlong_t = ulong_long +rbx.platform.typedef.u_offset_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uchar_t = uchar +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uint_t = uint +rbx.platform.typedef.uintmax_t = ulong +rbx.platform.typedef.uintptr_t = ulong +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ulong_t = ulong +rbx.platform.typedef.unchar = uchar +rbx.platform.typedef.upad64_t = ulong +rbx.platform.typedef.use_t = uchar +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.ushort_t = ushort +rbx.platform.typedef.zoneid_t = int diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf new file mode 100644 index 00000000..5bdbbde2 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/platform/x86_64-windows/types.conf @@ -0,0 +1,52 @@ +rbx.platform.typedef.__time32_t = long +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef._dev_t = uint +rbx.platform.typedef._ino_t = ushort +rbx.platform.typedef._mode_t = ushort +rbx.platform.typedef._off64_t = long_long +rbx.platform.typedef._off_t = long +rbx.platform.typedef._pid_t = long_long +rbx.platform.typedef._sigset_t = ulong_long +rbx.platform.typedef.dev_t = uint +rbx.platform.typedef.errno_t = int +rbx.platform.typedef.ino_t = ushort +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = short +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = long_long +rbx.platform.typedef.mode_t = ushort +rbx.platform.typedef.off32_t = long +rbx.platform.typedef.off64_t = long_long +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = long_long +rbx.platform.typedef.ptrdiff_t = long_long +rbx.platform.typedef.rsize_t = ulong_long +rbx.platform.typedef.size_t = ulong_long +rbx.platform.typedef.ssize_t = long_long +rbx.platform.typedef.time_t = long_long +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = ushort +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = ulong_long +rbx.platform.typedef.useconds_t = uint +rbx.platform.typedef.wchar_t = ushort +rbx.platform.typedef.wctype_t = ushort +rbx.platform.typedef.wint_t = ushort diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/pointer.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/pointer.rb new file mode 100644 index 00000000..e65835f3 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/pointer.rb @@ -0,0 +1,167 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# Copyright (c) 2007, 2008 Evan Phoenix +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/platform' + +# NOTE: all method definitions in this file are conditional on +# whether they are not already defined. This is needed because +# some Ruby implementations (e.g., TruffleRuby) might already +# provide these methods due to using FFI internally, and we +# should not override them to avoid warnings. + +module FFI + class Pointer + + # Pointer size + SIZE = Platform::ADDRESS_SIZE / 8 unless const_defined?(:SIZE) + + # Return the size of a pointer on the current platform, in bytes + # @return [Integer] + def self.size + SIZE + end unless respond_to?(:size) + + # @param [nil,Integer] len length of string to return + # @return [String] + # Read pointer's contents as a string, or the first +len+ bytes of the + # equivalent string if +len+ is not +nil+. + def read_string(len=nil) + if len + return ''.b if len == 0 + get_bytes(0, len) + else + get_string(0) + end + end unless method_defined?(:read_string) + + # @param [Integer] len length of string to return + # @return [String] + # Read the first +len+ bytes of pointer's contents as a string. + # + # Same as: + # ptr.read_string(len) # with len not nil + def read_string_length(len) + get_bytes(0, len) + end unless method_defined?(:read_string_length) + + # @return [String] + # Read pointer's contents as a string. + # + # Same as: + # ptr.read_string # with no len + def read_string_to_null + get_string(0) + end unless method_defined?(:read_string_to_null) + + # @param [String] str string to write + # @param [Integer] len length of string to return + # @return [self] + # Write +len+ first bytes of +str+ in pointer's contents. + # + # Same as: + # ptr.write_string(str, len) # with len not nil + def write_string_length(str, len) + put_bytes(0, str, 0, len) + end unless method_defined?(:write_string_length) + + # @param [String] str string to write + # @param [Integer] len length of string to return + # @return [self] + # Write +str+ in pointer's contents, or first +len+ bytes if + # +len+ is not +nil+. + def write_string(str, len=nil) + len = str.bytesize unless len + # Write the string data without NUL termination + put_bytes(0, str, 0, len) + end unless method_defined?(:write_string) + + # @param [Type] type type of data to read from pointer's contents + # @param [Symbol] reader method to send to +self+ to read +type+ + # @param [Integer] length + # @return [Array] + # Read an array of +type+ of length +length+. + # @example + # ptr.read_array_of_type(TYPE_UINT8, :read_uint8, 4) # -> [1, 2, 3, 4] + def read_array_of_type(type, reader, length) + ary = [] + size = FFI.type_size(type) + tmp = self + length.times { |j| + ary << tmp.send(reader) + tmp += size unless j == length-1 # avoid OOB + } + ary + end unless method_defined?(:read_array_of_type) + + # @param [Type] type type of data to write to pointer's contents + # @param [Symbol] writer method to send to +self+ to write +type+ + # @param [Array] ary + # @return [self] + # Write +ary+ in pointer's contents as +type+. + # @example + # ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4]) + def write_array_of_type(type, writer, ary) + size = FFI.type_size(type) + ary.each_with_index { |val, i| + break unless i < self.size + self.send(writer, i * size, val) + } + self + end unless method_defined?(:write_array_of_type) + + # @return [self] + def to_ptr + self + end unless method_defined?(:to_ptr) + + # @param [Symbol,Type] type of data to read + # @return [Object] + # Read pointer's contents as +type+ + # + # Same as: + # ptr.get(type, 0) + def read(type) + get(type, 0) + end unless method_defined?(:read) + + # @param [Symbol,Type] type of data to read + # @param [Object] value to write + # @return [nil] + # Write +value+ of type +type+ to pointer's content + # + # Same as: + # ptr.put(type, 0) + def write(type, value) + put(type, 0, value) + end unless method_defined?(:write) + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct.rb new file mode 100644 index 00000000..bf6228ab --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct.rb @@ -0,0 +1,317 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008, 2009 Andrea Fazzi +# Copyright (C) 2008, 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/platform' +require 'ffi/struct_layout' +require 'ffi/struct_layout_builder' +require 'ffi/struct_by_reference' + +module FFI + + class Struct + + # Get struct size + # @return [Integer] + def size + self.class.size + end + + # @return [Integer] Struct alignment + def alignment + self.class.alignment + end + alias_method :align, :alignment + + # (see FFI::StructLayout#offset_of) + def offset_of(name) + self.class.offset_of(name) + end + + # (see FFI::StructLayout#members) + def members + self.class.members + end + + # @return [Array] + # Get array of values from Struct fields. + def values + members.map { |m| self[m] } + end + + # (see FFI::StructLayout#offsets) + def offsets + self.class.offsets + end + + # Clear the struct content. + # @return [self] + def clear + pointer.clear + self + end + + # Get {Pointer} to struct content. + # @return [AbstractMemory] + def to_ptr + pointer + end + + # Get struct size + # @return [Integer] + def self.size + defined?(@layout) ? @layout.size : defined?(@size) ? @size : 0 + end + + # set struct size + # @param [Integer] size + # @return [size] + def self.size=(size) + raise ArgumentError, "Size already set" if defined?(@size) || defined?(@layout) + @size = size + end + + # @return (see Struct#alignment) + def self.alignment + @layout.alignment + end + + # (see FFI::Type#members) + def self.members + @layout.members + end + + # (see FFI::StructLayout#offsets) + def self.offsets + @layout.offsets + end + + # (see FFI::StructLayout#offset_of) + def self.offset_of(name) + @layout.offset_of(name) + end + + def self.in + ptr(:in) + end + + def self.out + ptr(:out) + end + + def self.ptr(flags = :inout) + @ref_data_type ||= Type::Mapped.new(StructByReference.new(self)) + end + + def self.val + @val_data_type ||= StructByValue.new(self) + end + + def self.by_value + self.val + end + + def self.by_ref(flags = :inout) + self.ptr(flags) + end + + class ManagedStructConverter < StructByReference + + # @param [Struct] struct_class + def initialize(struct_class) + super(struct_class) + + raise NoMethodError, "release() not implemented for class #{struct_class}" unless struct_class.respond_to? :release + @method = struct_class.method(:release) + end + + # @param [Pointer] ptr + # @param [nil] ctx + # @return [Struct] + def from_native(ptr, ctx) + struct_class.new(AutoPointer.new(ptr, @method)) + end + end + + def self.auto_ptr + @managed_type ||= Type::Mapped.new(ManagedStructConverter.new(self)) + end + + + class << self + public + + # @return [StructLayout] + # @overload layout + # @return [StructLayout] + # Get struct layout. + # @overload layout(*spec) + # @param [Array,Array(Hash)] spec + # @return [StructLayout] + # Create struct layout from +spec+. + # @example Creating a layout from an array +spec+ + # class MyStruct < Struct + # layout :field1, :int, + # :field2, :pointer, + # :field3, :string + # end + # @example Creating a layout from an array +spec+ with offset + # class MyStructWithOffset < Struct + # layout :field1, :int, + # :field2, :pointer, 6, # set offset to 6 for this field + # :field3, :string + # end + # @example Creating a layout from a hash +spec+ + # class MyStructFromHash < Struct + # layout :field1 => :int, + # :field2 => :pointer, + # :field3 => :string + # end + # @example Creating a layout with pointers to functions + # class MyFunctionTable < Struct + # layout :function1, callback([:int, :int], :int), + # :function2, callback([:pointer], :void), + # :field3, :string + # end + def layout(*spec) + return @layout if spec.size == 0 + + warn "[DEPRECATION] Struct layout is already defined for class #{self.inspect}. Redefinition as in #{caller[0]} will be disallowed in ffi-2.0." if defined?(@layout) + + builder = StructLayoutBuilder.new + builder.union = self < Union + builder.packed = @packed if defined?(@packed) + builder.alignment = @min_alignment if defined?(@min_alignment) + + if spec[0].kind_of?(Hash) + hash_layout(builder, spec) + else + array_layout(builder, spec) + end + builder.size = @size if defined?(@size) && @size > builder.size + cspec = builder.build + @layout = cspec unless self == Struct + @size = cspec.size + return cspec + end + + + protected + + def callback(params, ret) + mod = enclosing_module + ret_type = find_type(ret, mod) + if ret_type == Type::STRING + raise TypeError, ":string is not allowed as return type of callbacks" + end + FFI::CallbackInfo.new(ret_type, params.map { |e| find_type(e, mod) }) + end + + def packed(packed = 1) + @packed = packed + end + alias :pack :packed + + def aligned(alignment = 1) + @min_alignment = alignment + end + alias :align :aligned + + def enclosing_module + begin + mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) } + if mod.respond_to?(:find_type) && (mod.is_a?(FFI::Library) || mod < FFI::Struct) + mod + end + rescue Exception + nil + end + end + + + def find_field_type(type, mod = enclosing_module) + if type.kind_of?(Class) && type < Struct + FFI::Type::Struct.new(type) + + elsif type.kind_of?(Class) && type < FFI::StructLayout::Field + type + + elsif type.kind_of?(::Array) + FFI::Type::Array.new(find_field_type(type[0]), type[1]) + + else + find_type(type, mod) + end + end + + def find_type(type, mod = enclosing_module) + if mod + mod.find_type(type) + end || FFI.find_type(type) + end + + private + + # @param [StructLayoutBuilder] builder + # @param [Hash] spec + # @return [builder] + # Add hash +spec+ to +builder+. + def hash_layout(builder, spec) + spec[0].each do |name, type| + builder.add name, find_field_type(type), nil + end + end + + # @param [StructLayoutBuilder] builder + # @param [Array] spec + # @return [builder] + # Add array +spec+ to +builder+. + def array_layout(builder, spec) + i = 0 + while i < spec.size + name, type = spec[i, 2] + i += 2 + + # If the next param is a Integer, it specifies the offset + if spec[i].kind_of?(Integer) + offset = spec[i] + i += 1 + else + offset = nil + end + + builder.add name, find_field_type(type), offset + end + end + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb new file mode 100644 index 00000000..9ed1f71e --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_by_reference.rb @@ -0,0 +1,72 @@ +# +# Copyright (C) 2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# + +module FFI + # This class includes the {FFI::DataConverter} module. + class StructByReference + include DataConverter + + attr_reader :struct_class + + # @param [Struct] struct_class + def initialize(struct_class) + unless Class === struct_class and struct_class < FFI::Struct + raise TypeError, 'wrong type (expected subclass of FFI::Struct)' + end + @struct_class = struct_class + end + + # Always get {FFI::Type}::POINTER. + def native_type(_type = nil) + FFI::Type::POINTER + end + + # @param [nil, Struct] value + # @param [nil] ctx + # @return [AbstractMemory] Pointer on +value+. + def to_native(value, ctx) + return Pointer::NULL if value.nil? + + unless @struct_class === value + raise TypeError, "wrong argument type #{value.class} (expected #{@struct_class})" + end + + value.pointer + end + + # @param [AbstractMemory] value + # @param [nil] ctx + # @return [Struct] + # Create a struct from content of memory +value+. + def from_native(value, ctx) + @struct_class.new(value) + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout.rb new file mode 100644 index 00000000..fb842023 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout.rb @@ -0,0 +1,96 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (C) 2008, 2009 Andrea Fazzi +# Copyright (C) 2008, 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + class StructLayout + + # @return [Array + # Get an array of tuples (field name, offset of the field). + def offsets + members.map { |m| [ m, self[m].offset ] } + end + + # @return [Integer] + # Get the offset of a field. + def offset_of(field_name) + self[field_name].offset + end + + # An enum {Field} in a {StructLayout}. + class Enum < Field + + # @param [AbstractMemory] ptr pointer on a {Struct} + # @return [Object] + # Get an object of type {#type} from memory pointed by +ptr+. + def get(ptr) + type.find(ptr.get_int(offset)) + end + + # @param [AbstractMemory] ptr pointer on a {Struct} + # @param value + # @return [nil] + # Set +value+ into memory pointed by +ptr+. + def put(ptr, value) + ptr.put_int(offset, type.find(value)) + end + + end + + class InnerStruct < Field + def get(ptr) + type.struct_class.new(ptr.slice(self.offset, self.size)) + end + + def put(ptr, value) + raise TypeError, "wrong value type (expected #{type.struct_class})" unless value.is_a?(type.struct_class) + ptr.slice(self.offset, self.size).__copy_from__(value.pointer, self.size) + end + end + + class Mapped < Field + def initialize(name, offset, type, orig_field) + @orig_field = orig_field + super(name, offset, type) + end + + def get(ptr) + type.from_native(@orig_field.get(ptr), nil) + end + + def put(ptr, value) + @orig_field.put(ptr, type.to_native(value, nil)) + end + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb new file mode 100644 index 00000000..2221a607 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/struct_layout_builder.rb @@ -0,0 +1,227 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + + # Build a {StructLayout struct layout}. + class StructLayoutBuilder + attr_reader :size + attr_reader :alignment + + def initialize + @size = 0 + @alignment = 1 + @min_alignment = 1 + @packed = false + @union = false + @fields = Array.new + end + + # Set size attribute with +size+ only if +size+ is greater than attribute value. + # @param [Integer] size + def size=(size) + @size = size if size > @size + end + + # Set alignment attribute with +align+ only if it is greater than attribute value. + # @param [Integer] align + def alignment=(align) + @alignment = align if align > @alignment + @min_alignment = align + end + + # Set union attribute. + # Set to +true+ to build a {Union} instead of a {Struct}. + # @param [Boolean] is_union + # @return [is_union] + def union=(is_union) + @union = is_union + end + + # Building a {Union} or a {Struct} ? + # + # @return [Boolean] + # + def union? + @union + end + + # Set packed attribute + # @overload packed=(packed) Set alignment and packed attributes to + # +packed+. + # + # @param [Integer] packed + # + # @return [packed] + # @overload packed=(packed) Set packed attribute. + # @param packed + # + # @return [0,1] + # + def packed=(packed) + if packed.is_a?(0.class) + @alignment = packed + @packed = packed + else + @packed = packed ? 1 : 0 + end + end + + + # List of number types + NUMBER_TYPES = [ + Type::INT8, + Type::UINT8, + Type::INT16, + Type::UINT16, + Type::INT32, + Type::UINT32, + Type::LONG, + Type::ULONG, + Type::INT64, + Type::UINT64, + Type::FLOAT32, + Type::FLOAT64, + Type::LONGDOUBLE, + Type::BOOL, + ].freeze + + # @param [String, Symbol] name name of the field + # @param [Array, DataConverter, Struct, StructLayout::Field, Symbol, Type] type type of the field + # @param [Integer, nil] offset + # @return [self] + # Add a field to the builder. + # @note Setting +offset+ to +nil+ or +-1+ is equivalent to +0+. + def add(name, type, offset = nil) + + if offset.nil? || offset == -1 + offset = @union ? 0 : align(@size, @packed ? [ @packed, type.alignment ].min : [ @min_alignment, type.alignment ].max) + end + + # + # If a FFI::Type type was passed in as the field arg, try and convert to a StructLayout::Field instance + # + field = type.is_a?(StructLayout::Field) ? type : field_for_type(name, offset, type) + @fields << field + @alignment = [ @alignment, field.alignment ].max unless @packed + @size = [ @size, field.size + (@union ? 0 : field.offset) ].max + + return self + end + + # @param (see #add) + # @return (see #add) + # Same as {#add}. + # @see #add + def add_field(name, type, offset = nil) + add(name, type, offset) + end + + # @param (see #add) + # @return (see #add) + # Add a struct as a field to the builder. + def add_struct(name, type, offset = nil) + add(name, Type::Struct.new(type), offset) + end + + # @param name (see #add) + # @param type (see #add) + # @param [Integer] count array length + # @param offset (see #add) + # @return (see #add) + # Add an array as a field to the builder. + def add_array(name, type, count, offset = nil) + add(name, Type::Array.new(type, count), offset) + end + + # @return [StructLayout] + # Build and return the struct layout. + def build + # Add tail padding if the struct is not packed + size = @packed ? @size : align(@size, @alignment) + + layout = StructLayout.new(@fields, size, @alignment) + layout.__union! if @union + layout + end + + private + + # @param [Integer] offset + # @param [Integer] align + # @return [Integer] + def align(offset, align) + align + ((offset - 1) & ~(align - 1)); + end + + # @param (see #add) + # @return [StructLayout::Field] + def field_for_type(name, offset, type) + field_class = case + when type.is_a?(Type::Function) + StructLayout::Function + + when type.is_a?(Type::Struct) + StructLayout::InnerStruct + + when type.is_a?(Type::Array) + StructLayout::Array + + when type.is_a?(FFI::Enum) + StructLayout::Enum + + when NUMBER_TYPES.include?(type) + StructLayout::Number + + when type == Type::POINTER + StructLayout::Pointer + + when type == Type::STRING + StructLayout::String + + when type.is_a?(Class) && type < StructLayout::Field + type + + when type.is_a?(DataConverter) + return StructLayout::Mapped.new(name, offset, Type::Mapped.new(type), field_for_type(name, offset, type.native_type)) + + when type.is_a?(Type::Mapped) + return StructLayout::Mapped.new(name, offset, type, field_for_type(name, offset, type.native_type)) + + else + raise TypeError, "invalid struct field type #{type.inspect}" + end + + field_class.new(name, offset, type) + end + end + +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb new file mode 100644 index 00000000..70ba9c2a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/const_generator.rb @@ -0,0 +1,232 @@ +require 'tempfile' +require 'open3' + +module FFI + + # ConstGenerator turns C constants into ruby values. + # + # @example a simple example for stdio + # require 'ffi/tools/const_generator' + # cg = FFI::ConstGenerator.new('stdio') do |gen| + # gen.const(:SEEK_SET) + # gen.const('SEEK_CUR') + # gen.const('seek_end') # this constant does not exist + # end # #calculate called automatically at the end of the block + # + # cg['SEEK_SET'] # => 0 + # cg['SEEK_CUR'] # => 1 + # cg['seek_end'] # => nil + # cg.to_ruby # => "SEEK_SET = 0\nSEEK_CUR = 1\n# seek_end not available" + class ConstGenerator + @options = {} + attr_reader :constants + + # Creates a new constant generator that uses +prefix+ as a name, and an + # options hash. + # + # The only option is +:required+, which if set to +true+ raises an error if a + # constant you have requested was not found. + # + # @param [#to_s] prefix + # @param [Hash] options + # @return + # @option options [Boolean] :required + # @overload initialize(prefix, options) + # @overload initialize(prefix, options) { |gen| ... } + # @yieldparam [ConstGenerator] gen new generator is passed to the block + # When passed a block, {#calculate} is automatically called at the end of + # the block, otherwise you must call it yourself. + def initialize(prefix = nil, options = {}) + @includes = ['stdio.h', 'stddef.h'] + @constants = {} + @prefix = prefix + + @required = options[:required] + @options = options + + if block_given? then + yield self + calculate self.class.options.merge(options) + end + end + # Set class options + # These options are merged with {#initialize} options when it is called with a block. + # @param [Hash] options + # @return [Hash] class options + def self.options=(options) + @options = options + end + # Get class options. + # @return [Hash] class options + def self.options + @options + end + # @param [String] name + # @return constant value (converted if a +converter+ was defined). + # Access a constant by name. + def [](name) + @constants[name].converted_value + end + + # Request the value for C constant +name+. + # + # @param [#to_s] name C constant name + # @param [String] format a printf format string to print the value out + # @param [String] cast a C cast for the value + # @param ruby_name alternate ruby name for {#to_ruby} + # + # @overload const(name, format=nil, cast='', ruby_name=nil, converter=nil) + # +converter+ is a Method or a Proc. + # @param [#call] converter convert the value from a string to the appropriate + # type for {#to_ruby}. + # @overload const(name, format=nil, cast='', ruby_name=nil) { |value| ... } + # Use a converter block. This block convert the value from a string to the + # appropriate type for {#to_ruby}. + # @yieldparam value constant value + def const(name, format = nil, cast = '', ruby_name = nil, converter = nil, + &converter_proc) + format ||= '%d' + cast ||= '' + + if converter_proc and converter then + raise ArgumentError, "Supply only converter or converter block" + end + + converter = converter_proc if converter.nil? + + const = Constant.new name, format, cast, ruby_name, converter + @constants[name.to_s] = const + return const + end + + # Calculate constants values. + # @param [Hash] options + # @option options [String] :cppflags flags for C compiler + # @return [nil] + # @raise if a constant is missing and +:required+ was set to +true+ (see {#initialize}) + def calculate(options = {}) + binary_path = nil + + Tempfile.open("#{@prefix}.const_generator") do |f| + binary_path = f.path + ".bin" + @includes.each do |inc| + f.puts "#include <#{inc}>" + end + f.puts "\nint main(int argc, char **argv)\n{" + + @constants.each_value do |const| + f.puts <<-EOF + #ifdef #{const.name} + printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name}); + #endif + EOF + end + + f.puts "\n\treturn 0;\n}" + f.flush + + cc = ENV['CC'] || 'gcc' + output = `#{cc} #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary_path} 2>&1` + + unless $?.success? then + output = output.split("\n").map { |l| "\t#{l}" }.join "\n" + raise "Compilation error generating constants #{@prefix}:\n#{output}" + end + end + + output = `#{binary_path}` + File.unlink(binary_path + (FFI::Platform.windows? ? ".exe" : "")) + output.each_line do |line| + line =~ /^(\S+)\s(.*)$/ + const = @constants[$1] + const.value = $2 + end + + missing_constants = @constants.select do |name, constant| + constant.value.nil? + end.map { |name,| name } + + if @required and not missing_constants.empty? then + raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}" + end + end + + # Dump constants to +io+. + # @param [#puts] io + # @return [nil] + def dump_constants(io) + @constants.each do |name, constant| + name = [@prefix, name].join '.' if @prefix + io.puts "#{name} = #{constant.converted_value}" + end + end + + # Outputs values for discovered constants. If the constant's value was + # not discovered it is not omitted. + # @return [String] + def to_ruby + @constants.sort_by { |name,| name }.map do |name, constant| + if constant.value.nil? then + "# #{name} not available" + else + constant.to_ruby + end + end.join "\n" + end + + # Add additional C include file(s) to calculate constants from. + # @note +stdio.h+ and +stddef.h+ automatically included + # @param [List, Array] i include file(s) + # @return [Array] array of include files + def include(*i) + @includes |= i.flatten + end + + end + + # This class hold constants for {ConstGenerator} + class ConstGenerator::Constant + + attr_reader :name, :format, :cast + attr_accessor :value + + # @param [#to_s] name + # @param [String] format a printf format string to print the value out + # @param [String] cast a C cast for the value + # @param ruby_name alternate ruby name for {#to_ruby} + # @param [#call] converter convert the value from a string to the appropriate + # type for {#to_ruby}. + def initialize(name, format, cast, ruby_name = nil, converter=nil) + @name = name + @format = format + @cast = cast + @ruby_name = ruby_name + @converter = converter + @value = nil + end + + # Return constant value (converted if a +converter+ was defined). + # @return constant value. + def converted_value + if @converter + @converter.call(@value) + else + @value + end + end + + # get constant ruby name + # @return [String] + def ruby_name + @ruby_name || @name + end + + # Get an evaluable string from constant. + # @return [String] + def to_ruby + "#{ruby_name} = #{converted_value}" + end + + end + +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator.rb new file mode 100644 index 00000000..5552ea59 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator.rb @@ -0,0 +1,105 @@ +require 'ffi/tools/struct_generator' +require 'ffi/tools/const_generator' + +module FFI + + ## + # Generate files with C structs for FFI::Struct and C constants. + # + # == A simple example + # + # In file +zlib.rb.ffi+: + # module Zlib + # @@@ + # constants do |c| + # c.include "zlib.h" + # c.const :ZLIB_VERNUM + # end + # @@@ + # + # class ZStream < FFI::Struct + # + # struct do |s| + # s.name "struct z_stream_s" + # s.include "zlib.h" + # + # s.field :next_in, :pointer + # s.field :avail_in, :uint + # s.field :total_in, :ulong + # end + # @@@ + # end + # end + # + # Translate the file: + # require "ffi/tools/generator" + # FFI::Generator.new "zlib.rb.ffi", "zlib.rb" + # + # Generates the file +zlib.rb+ with constant values and offsets: + # module Zlib + # ZLIB_VERNUM = 4784 + # + # class ZStream < FFI::Struct + # layout :next_in, :pointer, 0, + # :avail_in, :uint, 8, + # :total_in, :ulong, 16 + # end + # + # @see FFI::Generator::Task for easy integration in a Rakefile + class Generator + + def initialize(ffi_name, rb_name, options = {}) + @ffi_name = ffi_name + @rb_name = rb_name + @options = options + @name = File.basename rb_name, '.rb' + + file = File.read @ffi_name + + new_file = file.gsub(/^( *)@@@(.*?)@@@/m) do + @constants = [] + @structs = [] + + indent = $1 + original_lines = $2.count "\n" + + instance_eval $2, @ffi_name, $`.count("\n") + + new_lines = [] + @constants.each { |c| new_lines << c.to_ruby } + @structs.each { |s| new_lines << s.generate_layout } + + new_lines = new_lines.join("\n").split "\n" # expand multiline blocks + new_lines = new_lines.map { |line| indent + line } + + padding = original_lines - new_lines.length + new_lines += [nil] * padding if padding >= 0 + + new_lines.join "\n" + end + + open @rb_name, 'w' do |f| + f.puts "# This file is generated from `#{@ffi_name}'. Do not edit." + f.puts + f.puts new_file + end + end + + def constants(options = {}, &block) + @constants << FFI::ConstGenerator.new(@name, @options.merge(options), &block) + end + + def struct(options = {}, &block) + @structs << FFI::StructGenerator.new(@name, @options.merge(options), &block) + end + + ## + # Utility converter for constants + + def to_s + proc { |obj| obj.to_s.inspect } + end + + end +end + diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb new file mode 100644 index 00000000..da72968b --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/generator_task.rb @@ -0,0 +1,32 @@ +require 'ffi/tools/generator' +require 'rake' +require 'rake/tasklib' + +## +# Add Rake tasks that generate files with C structs for FFI::Struct and C constants. +# +# @example a simple example for your Rakefile +# require "ffi/tools/generator_task" +# # Add a task to generate my_object.rb out of my_object.rb.ffi +# FFI::Generator::Task.new ["my_object.rb"], cflags: "-I/usr/local/mylibrary" +# +# The generated files are also added to the 'clear' task. +# +# @see FFI::Generator for a description of the file content +class FFI::Generator::Task < Rake::TaskLib + + def initialize(rb_names, options={}) + task :clean do rm_f rb_names end + + rb_names.each do |rb_name| + ffi_name = "#{rb_name}.ffi" + + file rb_name => ffi_name do |t| + puts "Generating #{rb_name}..." if Rake.application.options.trace + + FFI::Generator.new ffi_name, rb_name, options + end + end + end + +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb new file mode 100644 index 00000000..3a951c38 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/tools/struct_generator.rb @@ -0,0 +1,195 @@ +require 'tempfile' + +module FFI + + ## + # Generates an FFI Struct layout. + # + # Given the @@@ portion in: + # + # class Zlib::ZStream < FFI::Struct + # @@@ + # name "struct z_stream_s" + # include "zlib.h" + # + # field :next_in, :pointer + # field :avail_in, :uint + # field :total_in, :ulong + # + # # ... + # @@@ + # end + # + # StructGenerator will create the layout: + # + # layout :next_in, :pointer, 0, + # :avail_in, :uint, 4, + # :total_in, :ulong, 8, + # # ... + # + # StructGenerator does its best to pad the layout it produces to preserve + # line numbers. Place the struct definition as close to the top of the file + # for best results. + + class StructGenerator + @options = {} + attr_accessor :size + attr_reader :fields + + def initialize(name, options = {}) + @name = name + @struct_name = nil + @includes = [] + @fields = [] + @found = false + @size = nil + + if block_given? then + yield self + calculate self.class.options.merge(options) + end + end + def self.options=(options) + @options = options + end + def self.options + @options + end + def calculate(options = {}) + binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}" + + raise "struct name not set" if @struct_name.nil? + + Tempfile.open("#{@name}.struct_generator") do |f| + f.puts "#include " + + @includes.each do |inc| + f.puts "#include <#{inc}>" + end + + f.puts "#include \n\n" + f.puts "int main(int argc, char **argv)\n{" + f.puts " #{@struct_name} s;" + f.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));] + + @fields.each do |field| + f.puts <<-EOF + printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}), + (unsigned int) sizeof(s.#{field.name})); + EOF + end + + f.puts "\n return 0;\n}" + f.flush + + cc = ENV['CC'] || 'gcc' + output = `#{cc} #{options[:cppflags]} #{options[:cflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1` + + unless $?.success? then + @found = false + output = output.split("\n").map { |l| "\t#{l}" }.join "\n" + raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}" + end + end + + output = `#{binary}`.split "\n" + File.unlink(binary + (FFI::Platform.windows? ? ".exe" : "")) + sizeof = output.shift + unless @size + m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof + @size = m[1] + end + + line_no = 0 + output.each do |line| + md = line.match(/.+ (\d+) (\d+)/) + @fields[line_no].offset = md[1].to_i + @fields[line_no].size = md[2].to_i + + line_no += 1 + end + + @found = true + end + + def field(name, type=nil) + field = Field.new(name, type) + @fields << field + return field + end + + def found? + @found + end + + def dump_config(io) + io.puts "rbx.platform.#{@name}.sizeof = #{@size}" + + @fields.each { |field| io.puts field.to_config(@name) } + end + + def generate_layout + buf = "" + + @fields.each_with_index do |field, i| + if buf.empty? + buf << "layout :#{field.name}, :#{field.type}, #{field.offset}" + else + buf << " :#{field.name}, :#{field.type}, #{field.offset}" + end + + if i < @fields.length - 1 + buf << ",\n" + end + end + + buf + end + + def get_field(name) + @fields.find { |f| name == f.name } + end + + def include(i) + @includes << i + end + + def name(n) + @struct_name = n + end + + end + + ## + # A field in a Struct. + + class StructGenerator::Field + + attr_reader :name + attr_reader :type + attr_reader :offset + attr_accessor :size + + def initialize(name, type) + @name = name + @type = type + @offset = nil + @size = nil + end + + def offset=(o) + @offset = o + end + + def to_config(name) + buf = [] + buf << "rbx.platform.#{name}.#{@name}.offset = #{@offset}" + buf << "rbx.platform.#{name}.#{@name}.size = #{@size}" + buf << "rbx.platform.#{name}.#{@name}.type = #{@type}" if @type + buf + end + + end + +end + diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/types.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/types.rb new file mode 100644 index 00000000..6f3ee4bc --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/types.rb @@ -0,0 +1,222 @@ +# +# Copyright (C) 2008-2010 Wayne Meissner +# Copyright (c) 2007, 2008 Evan Phoenix +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# see {file:README} +module FFI + + # Unless custom_typedefs already defined in the C-ext? + unless defined?(custom_typedefs) + # Truffleruby and JRuby don't support Ractor so far. + # So they don't need separation between builtin and custom types. + def self.custom_typedefs + TypeDefs + end + writable_typemap = true + end + + class << self + + private :custom_typedefs + + # @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type} + # @param [Symbol] add new type definition's name to add + # @return [Type] + # Add a definition type to type definitions. + # + # The type definition is local per Ractor. + def typedef(old, add) + tm = custom_typedefs + tm[add] = find_type(old) + end + + # (see FFI.typedef) + def add_typedef(old, add) + typedef old, add + end + + private def __typedef(old, add) + TypeDefs[add] = find_type(old, TypeDefs) + end + + # @param [Type, DataConverter, Symbol] name + # @param [Hash] type_map if nil, {FFI::TypeDefs} is used + # @return [Type] + # Find a type in +type_map+ ({FFI::TypeDefs}, by default) from + # a type objet, a type name (symbol). If +name+ is a {DataConverter}, + # a new {Type::Mapped} is created. + def find_type(name, type_map = nil) + if name.is_a?(Type) + name + + elsif type_map&.has_key?(name) + type_map[name] + + elsif (tm=custom_typedefs).has_key?(name) + tm[name] + + elsif TypeDefs.has_key?(name) + TypeDefs[name] + + elsif name.is_a?(DataConverter) + # Add a typedef so next time the converter is used, it hits the cache + tm = (type_map || custom_typedefs) + tm[name] = Type::Mapped.new(name) + else + raise TypeError, "unable to resolve type '#{name}'" + end + end + + # @param type +type+ is an instance of class accepted by {FFI.find_type} + # @return [Integer] + # Get +type+ size, in bytes. + def type_size(type) + find_type(type).size + end + end + + # List of type definitions + TypeDefs.merge!({ + # The C void type; only useful for function return types + :void => Type::VOID, + + # C boolean type + :bool => Type::BOOL, + + # C nul-terminated string + :string => Type::STRING, + + # C signed char + :char => Type::CHAR, + # C unsigned char + :uchar => Type::UCHAR, + + # C signed short + :short => Type::SHORT, + # C unsigned short + :ushort => Type::USHORT, + + # C signed int + :int => Type::INT, + # C unsigned int + :uint => Type::UINT, + + # C signed long + :long => Type::LONG, + + # C unsigned long + :ulong => Type::ULONG, + + # C signed long long integer + :long_long => Type::LONG_LONG, + + # C unsigned long long integer + :ulong_long => Type::ULONG_LONG, + + # C single precision float + :float => Type::FLOAT, + + # C double precision float + :double => Type::DOUBLE, + + # C long double + :long_double => Type::LONGDOUBLE, + + # Native memory address + :pointer => Type::POINTER, + + # 8 bit signed integer + :int8 => Type::INT8, + # 8 bit unsigned integer + :uint8 => Type::UINT8, + + # 16 bit signed integer + :int16 => Type::INT16, + # 16 bit unsigned integer + :uint16 => Type::UINT16, + + # 32 bit signed integer + :int32 => Type::INT32, + # 32 bit unsigned integer + :uint32 => Type::UINT32, + + # 64 bit signed integer + :int64 => Type::INT64, + # 64 bit unsigned integer + :uint64 => Type::UINT64, + + :buffer_in => Type::BUFFER_IN, + :buffer_out => Type::BUFFER_OUT, + :buffer_inout => Type::BUFFER_INOUT, + + # Used in function prototypes to indicate the arguments are variadic + :varargs => Type::VARARGS, + }) + + # This will convert a pointer to a Ruby string (just like `:string`), but + # also allow to work with the pointer itself. This is useful when you want + # a Ruby string already containing a copy of the data, but also the pointer + # to the data for you to do something with it, like freeing it, in case the + # library handed the memory off to the caller (Ruby-FFI). + # + # It's {typedef}'d as +:strptr+. + class StrPtrConverter + extend DataConverter + native_type Type::POINTER + + # @param [Pointer] val + # @param ctx not used + # @return [Array(String, Pointer)] + # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed + def self.from_native(val, ctx) + [ val.null? ? nil : val.get_string(0), val ] + end + end + + __typedef(StrPtrConverter, :strptr) + + # Load all the platform dependent types + begin + File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f| + prefix = "rbx.platform.typedef." + f.each_line { |line| + if line.index(prefix) == 0 + new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/) + __typedef(orig_type.to_sym, new_type.to_sym) + end + } + end + __typedef :pointer, :caddr_t + rescue Errno::ENOENT + end + + FFI.make_shareable(TypeDefs) unless writable_typemap +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/union.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/union.rb new file mode 100644 index 00000000..38414ab9 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/union.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2009 Andrea Fazzi +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'ffi/struct' + +module FFI + + class Union < FFI::Struct + def self.builder + b = StructLayoutBuilder.new + b.union = true + b + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/variadic.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/variadic.rb new file mode 100644 index 00000000..ee334091 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/variadic.rb @@ -0,0 +1,80 @@ +# +# Copyright (C) 2008, 2009 Wayne Meissner +# Copyright (C) 2009 Luc Heinrich +# +# This file is part of ruby-ffi. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of the Ruby FFI project nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +module FFI + class VariadicInvoker + def call(*args, &block) + param_types = Array.new(@fixed) + param_values = Array.new + @fixed.each_with_index do |t, i| + param_values << args[i] + end + i = @fixed.length + while i < args.length + param_types << FFI.find_type(args[i], @type_map) + param_values << args[i + 1] + i += 2 + end + invoke(param_types, param_values, &block) + end + + # + # Attach the invoker to module +mod+ as +mname+ + # + def attach(mod, mname) + invoker = self + params = "*args" + call = "call" + mname = mname.to_sym + mod.module_eval <<-code, __FILE__, __LINE__ + @ffi_functions = {} unless defined?(@ffi_functions) + @ffi_functions[#{mname.inspect}] = invoker + + def self.#{mname}(#{params}) + @ffi_functions[#{mname.inspect}].#{call}(#{params}) + end + + define_method(#{mname.inspect}, &method(#{mname.inspect})) + code + invoker + end + + # Retrieve Array of parameter types + # + # This method returns an Array of FFI types accepted as function parameters. + # + # @return [Array] + def param_types + [*@fixed, Type::Builtin::VARARGS] + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/version.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/version.rb new file mode 100644 index 00000000..59c95dff --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/lib/ffi/version.rb @@ -0,0 +1,3 @@ +module FFI + VERSION = '1.17.4' +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getlogin.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getlogin.rb new file mode 100644 index 00000000..6713021d --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getlogin.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :getlogin, [ ], :string +end +puts "getlogin=#{Foo.getlogin}" diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getpid.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getpid.rb new file mode 100644 index 00000000..1720635b --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/getpid.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :getpid, [ ], :int +end +puts "My pid=#{Foo.getpid}" diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/gettimeofday.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/gettimeofday.rb new file mode 100644 index 00000000..864bbb62 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/gettimeofday.rb @@ -0,0 +1,18 @@ +require 'ffi' +require 'rbconfig' + +class Timeval < FFI::Struct + layout tv_sec: :ulong, tv_usec: :ulong +end +module LibC + extend FFI::Library + if FFI::Platform.windows? + ffi_lib RbConfig::CONFIG["LIBRUBY_SO"] + else + ffi_lib FFI::Library::LIBC + end + attach_function :gettimeofday, [ :pointer, :pointer ], :int +end +t = Timeval.new +LibC.gettimeofday(t.pointer, nil) +puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}" diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello.rb new file mode 100644 index 00000000..f2ccf377 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello.rb @@ -0,0 +1,8 @@ +require 'ffi' + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function("cputs", "puts", [ :string ], :int) +end +Foo.cputs("Hello, World via libc puts using FFI on MRI ruby") diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello_ractor.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello_ractor.rb new file mode 100644 index 00000000..9a01704c --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/hello_ractor.rb @@ -0,0 +1,19 @@ +# See the ffi wiki for how to use FFI with Ractors: +# https://github.com/ffi/ffi/wiki/Ractors + +require 'ffi' + +class Ractor + # compat with Ruby-3.4 and older + alias value take unless method_defined? :value +end + +module Foo + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function("cputs", "puts", [ :string ], :int) + freeze +end +Ractor.new do + Foo.cputs("Hello, World via libc puts using FFI in a Ractor") +end.value diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/inotify.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/inotify.rb new file mode 100644 index 00000000..018d78cf --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/inotify.rb @@ -0,0 +1,60 @@ +require 'ffi' + +module Inotify + extend FFI::Library + ffi_lib FFI::Library::LIBC + class Event < FFI::Struct + layout \ + :wd, :int, + :mask, :uint, + :cookie, :uint, + :len, :uint + end + attach_function :init, :inotify_init, [ ], :int + attach_function :add_watch, :inotify_add_watch, [ :int, :string, :uint ], :int + attach_function :rm_watch, :inotify_rm_watch, [ :int, :uint ], :int + attach_function :read, [ :int, :buffer_out, :uint ], :int + IN_ACCESS=0x00000001 + IN_MODIFY=0x00000002 + IN_ATTRIB=0x00000004 + IN_CLOSE_WRITE=0x00000008 + IN_CLOSE_NOWRITE=0x00000010 + IN_CLOSE=(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) + IN_OPEN=0x00000020 + IN_MOVED_FROM=0x00000040 + IN_MOVED_TO=0x00000080 + IN_MOVE= (IN_MOVED_FROM | IN_MOVED_TO) + IN_CREATE=0x00000100 + IN_DELETE=0x00000200 + IN_DELETE_SELF=0x00000400 + IN_MOVE_SELF=0x00000800 + # Events sent by the kernel. + IN_UNMOUNT=0x00002000 + IN_Q_OVERFLOW=0x00004000 + IN_IGNORED=0x00008000 + IN_ONLYDIR=0x01000000 + IN_DONT_FOLLOW=0x02000000 + IN_MASK_ADD=0x20000000 + IN_ISDIR=0x40000000 + IN_ONESHOT=0x80000000 + IN_ALL_EVENTS=(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \ + | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \ + | IN_MOVED_TO | IN_CREATE | IN_DELETE \ + | IN_DELETE_SELF | IN_MOVE_SELF) + +end +if $0 == __FILE__ + fd = Inotify.init + puts "fd=#{fd}" + wd = Inotify.add_watch(fd, "/tmp/", Inotify::IN_ALL_EVENTS) + fp = FFI::IO.for_fd(fd) + puts "wfp=#{fp}" + while true + buf = FFI::Buffer.alloc_out(Inotify::Event.size + 4096, 1, false) + ev = Inotify::Event.new buf + ready = IO.select([ fp ], nil, nil, nil) + n = Inotify.read(fd, buf, buf.total) + puts "Read #{n} bytes from inotify fd" + puts "event.wd=#{ev[:wd]} mask=#{ev[:mask]} len=#{ev[:len]} name=#{ev[:len] > 0 ? buf.get_string(16) : 'unknown'}" + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/pty.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/pty.rb new file mode 100644 index 00000000..8b6b885f --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/pty.rb @@ -0,0 +1,75 @@ +require 'ffi' + +module PTY + private + module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int + attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int + attach_function :login_tty, [ :int ], :int + attach_function :close, [ :int ], :int + attach_function :strerror, [ :int ], :string + attach_function :fork, [], :int + attach_function :execv, [ :string, :buffer_in ], :int + attach_function :execvp, [ :string, :buffer_in ], :int + attach_function :dup2, [ :int, :int ], :int + attach_function :dup, [ :int ], :int + end + Buffer = FFI::Buffer + def self.build_args(args) + cmd = args.shift + cmd_args = args.map do |arg| + MemoryPointer.from_string(arg) + end + exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1) + exec_cmd = MemoryPointer.from_string(cmd) + exec_args[0].put_pointer(0, exec_cmd) + cmd_args.each_with_index do |arg, i| + exec_args[i + 1].put_pointer(0, arg) + end + [ cmd, exec_args ] + end + public + def self.getpty(*args) + mfdp = Buffer.new :int + name = Buffer.new 1024 + # + # All the execv setup is done in the parent, since doing anything other than + # execv in the child after fork is really flakey + # + exec_cmd, exec_args = build_args(args) + pid = LibC.forkpty(mfdp, name, nil, nil) + raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0 + if pid == 0 + LibC.execvp(exec_cmd, exec_args) + exit 1 + end + masterfd = mfdp.get_int(0) + rfp = FFI::IO.for_fd(masterfd, "r") + wfp = FFI::IO.for_fd(LibC.dup(masterfd), "w") + if block_given? + yield rfp, wfp, pid + rfp.close unless rfp.closed? + wfp.close unless wfp.closed? + else + [ rfp, wfp, pid ] + end + end + def self.spawn(*args, &block) + self.getpty("/bin/sh", "-c", args[0], &block) + end +end +module LibC + extend FFI::Library + attach_function :close, [ :int ], :int + attach_function :write, [ :int, :buffer_in, :ulong ], :long + attach_function :read, [ :int, :buffer_out, :ulong ], :long +end +PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid| +#PTY.spawn("ls -laR /") { |rfd, wfd, pid| + puts "child pid=#{pid}" + while !rfd.eof? && (buf = rfd.gets) + puts "child: '#{buf.strip}'" + end +} diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort.rb new file mode 100644 index 00000000..58622c16 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort.rb @@ -0,0 +1,20 @@ +require 'ffi' + +module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + callback :qsort_cmp, [ :pointer, :pointer ], :int + attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int +end + +p = FFI::MemoryPointer.new(:int, 2) +p.put_array_of_int32(0, [ 2, 1 ]) +puts "ptr=#{p.inspect}" +puts "Before qsort #{p.get_array_of_int32(0, 2).join(', ')}" +LibC.qsort(p, 2, 4) do |p1, p2| + i1 = p1.get_int32(0) + i2 = p2.get_int32(0) + puts "In block: comparing #{i1} and #{i2}" + i1 < i2 ? -1 : i1 > i2 ? 1 : 0 +end +puts "After qsort #{p.get_array_of_int32(0, 2).join(', ')}" diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort_ractor.rb b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort_ractor.rb new file mode 100644 index 00000000..7fe9afa6 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/samples/qsort_ractor.rb @@ -0,0 +1,36 @@ +# See the ffi wiki for how to use FFI with Ractors: +# https://github.com/ffi/ffi/wiki/Ractors + +require 'ffi' + +class Ractor + # compat with Ruby-3.4 and older + alias value take unless method_defined? :value +end + +module LibC + extend FFI::Library + ffi_lib FFI::Library::LIBC + callback :qsort_cmp, [ :pointer, :pointer ], :int + attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int + + freeze # Freeze the module variables, so that it can be shared across ractors. +end + +p = FFI::MemoryPointer.new(:int, 3) +p.put_array_of_int32(0, [ 2, 3, 1 ]) # Write some unsorted data into the memory +# Ractor.make_shareable(p) # freeze the pointer to be shared between ractors instead of copied +puts "main -ptr=#{p.inspect}" +res = Ractor.new(p) do |p| + puts "ractor-ptr=#{p.inspect}" + puts "Before qsort #{p.get_array_of_int32(0, 3).join(', ')}" + LibC.qsort(p, 3, 4) do |p1, p2| + i1 = p1.get_int32(0) + i2 = p2.get_int32(0) + puts "In block: comparing #{i1} and #{i2}" + i1 < i2 ? -1 : i1 > i2 ? 1 : 0 + end + puts "After qsort #{p.get_array_of_int32(0, 3).join(', ')}" +end.value + +puts "After ractor termination #{p.get_array_of_int32(0, 3).join(', ')}" diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi.rbs new file mode 100644 index 00000000..6cba15f7 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi.rbs @@ -0,0 +1,29 @@ +module FFI + type ffi_type = Type | Symbol + type ffi_auto_type = ffi_type | DataConverter[untyped, untyped, untyped] + type type_map = Hash[Symbol | DataConverter[untyped, untyped, untyped], Type] + + class CallbackInfo = FunctionType + class FunctionInfo = FunctionType + class NativeLibrary = DynamicLibrary + + VERSION: String + TypeDefs: type_map + + type current_process = Object + CURRENT_PROCESS: current_process + USE_THIS_PROCESS_AS_LIBRARY: current_process + + class NotFoundError < LoadError + end + + private def self.custom_typedefs: () -> type_map + def self.errno: () -> Integer + def self.errno=: (Integer) -> Integer + def self.find_type: (ffi_auto_type name, ?type_map? type_map) -> Type + def self.make_shareable: [T] (T obj) -> T + def self.map_library_name: (_ToS lib) -> String + def self.type_size: (ffi_auto_type type) -> Integer + def self.typedef: (ffi_auto_type old, Symbol add) -> Type + alias self.add_typedef self.typedef +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs new file mode 100644 index 00000000..9678ad01 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/abstract_memory.rbs @@ -0,0 +1,165 @@ +module FFI + class AbstractMemory + interface _Size + def size: () -> Integer + end + include _Size + type type_size = Integer | _Size | Symbol + + type order_out = :big | :little + type order_in = order_out | :network + + def []: (Integer idx) -> instance + def clear: () -> self + def freeze: ... + def get: (ffi_type type, Integer offset) -> top + def put: (ffi_type type, Integer offset, top value) -> nil + def size_limit?: () -> bool + def type_size: () -> Integer + alias total size + + def get_int8: (Integer offset) -> Integer + def get_int16: (Integer offset) -> Integer + def get_int32: (Integer offset) -> Integer + def get_int64: (Integer offset) -> Integer + def get_uint8: (Integer offset) -> Integer + def get_uint16: (Integer offset) -> Integer + def get_uint32: (Integer offset) -> Integer + def get_uint64: (Integer offset) -> Integer + def get_char: (Integer offset) -> Integer + def get_short: (Integer offset) -> Integer + def get_int: (Integer offset) -> Integer + def get_long_long: (Integer offset) -> Integer + def get_float32: (Integer offset) -> Float + def get_float64: (Integer offset) -> Float + def get_pointer: (Integer offset) -> Pointer + def get_bytes: (Integer offset, Integer length) -> String + def get_string: (Integer offset, ?Integer? length) -> String + alias get_float get_float32 + alias get_double get_float64 + + def put_int8: (Integer offset, int value) -> self + def put_int16: (Integer offset, int value) -> self + def put_int32: (Integer offset, int value) -> self + def put_int64: (Integer offset, int value) -> self + def put_uint8: (Integer offset, int value) -> self + def put_uint16: (Integer offset, int value) -> self + def put_uint32: (Integer offset, int value) -> self + def put_uint64: (Integer offset, int value) -> self + def put_char: (Integer offset, int value) -> self + def put_short: (Integer offset, int value) -> self + def put_int: (Integer offset, int value) -> self + def put_long_long: (Integer offset, int value) -> self + def put_float32: (Integer offset, Numeric value) -> self + def put_float64: (Integer offset, Numeric value) -> self + def put_pointer: (Integer offset, pointer value) -> self + def put_bytes: (Integer offset, String str, ?Integer index, ?Integer? length) -> self + def put_string: (Integer offset, String value) -> self + alias put_float put_float32 + alias put_double put_float64 + + def read_int8: () -> Integer + def read_int16: () -> Integer + def read_int32: () -> Integer + def read_int64: () -> Integer + def read_uint8: () -> Integer + def read_uint16: () -> Integer + def read_uint32: () -> Integer + def read_uint64: () -> Integer + def read_char: () -> Integer + def read_short: () -> Integer + def read_int: () -> Integer + def read_long_long: () -> Integer + def read_float: () -> Float + def read_double: () -> Float + def read_pointer: () -> Pointer + def read_bytes: (Integer length) -> String + + def write_int8: (int value) -> self + def write_int16: (int value) -> self + def write_int32: (int value) -> self + def write_int64: (int value) -> self + def write_uint8: (int value) -> self + def write_uint16: (int value) -> self + def write_uint32: (int value) -> self + def write_uint64: (int value) -> self + def write_char: (int value) -> self + def write_short: (int value) -> self + def write_int: (int value) -> self + def write_long_long: (int value) -> self + def write_float: (Numeric value) -> self + def write_double: (Numeric value) -> self + def write_pointer: (pointer value) -> self + def write_bytes: (String str, ?Integer index, ?Integer? length) -> self + + def get_array_of_int8: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int16: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int32: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int64: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint8: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint16: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint32: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_uint64: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_char: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_short: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_int: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_long_long: (Integer offset, Integer length) -> Array[Integer] + def get_array_of_float32: (Integer offset, Integer length) -> Array[Float] + def get_array_of_float64: (Integer offset, Integer length) -> Array[Float] + def get_array_of_pointer: (Integer offset, Integer length) -> Array[Pointer] + def get_array_of_string: (Integer offset, ?Integer? count) -> Array[String?] + alias get_array_of_float get_array_of_float32 + alias get_array_of_double get_array_of_float64 + + def put_array_of_int8: (Integer offset, Array[int] ary) -> self + def put_array_of_int16: (Integer offset, Array[int] ary) -> self + def put_array_of_int32: (Integer offset, Array[int] ary) -> self + def put_array_of_int64: (Integer offset, Array[int] ary) -> self + def put_array_of_uint8: (Integer offset, Array[int] ary) -> self + def put_array_of_uint16: (Integer offset, Array[int] ary) -> self + def put_array_of_uint32: (Integer offset, Array[int] ary) -> self + def put_array_of_uint64: (Integer offset, Array[int] ary) -> self + def put_array_of_char: (Integer offset, Array[int] ary) -> self + def put_array_of_short: (Integer offset, Array[int] ary) -> self + def put_array_of_int: (Integer offset, Array[int] ary) -> self + def put_array_of_long_long: (Integer offset, Array[int] ary) -> self + def put_array_of_float32: (Integer offset, Array[Numeric] ary) -> self + def put_array_of_float64: (Integer offset, Array[Numeric] ary) -> self + def put_array_of_pointer: (Integer offset, Array[pointer] ary) -> self + alias put_array_of_float put_array_of_float32 + alias put_array_of_double put_array_of_float64 + + def read_array_of_int8: (Integer length) -> Array[Integer] + def read_array_of_int16: (Integer length) -> Array[Integer] + def read_array_of_int32: (Integer length) -> Array[Integer] + def read_array_of_int64: (Integer length) -> Array[Integer] + def read_array_of_uint8: (Integer length) -> Array[Integer] + def read_array_of_uint16: (Integer length) -> Array[Integer] + def read_array_of_uint32: (Integer length) -> Array[Integer] + def read_array_of_uint64: (Integer length) -> Array[Integer] + def read_array_of_char: (Integer length) -> Array[Integer] + def read_array_of_short: (Integer length) -> Array[Integer] + def read_array_of_int: (Integer length) -> Array[Integer] + def read_array_of_long_long: (Integer length) -> Array[Integer] + def read_array_of_float: (Integer length) -> Array[Float] + def read_array_of_double: (Integer length) -> Array[Float] + def read_array_of_pointer: (Integer length) -> Array[Pointer] + def read_array_of_string: (?Integer? count) -> Array[String?] + + def write_array_of_int8: (Array[int] ary) -> self + def write_array_of_int16: (Array[int] ary) -> self + def write_array_of_int32: (Array[int] ary) -> self + def write_array_of_int64: (Array[int] ary) -> self + def write_array_of_uint8: (Array[int] ary) -> self + def write_array_of_uint16: (Array[int] ary) -> self + def write_array_of_uint32: (Array[int] ary) -> self + def write_array_of_uint64: (Array[int] ary) -> self + def write_array_of_char: (Array[int] ary) -> self + def write_array_of_short: (Array[int] ary) -> self + def write_array_of_int: (Array[int] ary) -> self + def write_array_of_long_long: (Array[int] ary) -> self + def write_array_of_float: (Array[Numeric] ary) -> self + def write_array_of_double: (Array[Numeric] ary) -> self + def write_array_of_pointer: (Array[pointer] ary) -> self + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs new file mode 100644 index 00000000..21c7d043 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/auto_pointer.rbs @@ -0,0 +1,26 @@ +module FFI + class AutoPointer < Pointer + class Releaser + attr_accessor autorelease: boolish + interface _Proc[P < Pointer] + def call: (P) -> void + end + def initialize: [P < Pointer] (P ptr, _Proc[P] proc) -> void + + def call: (*untyped) -> void + def free: () -> nil + def release: (Pointer ptr) -> void + end + + def initialize: (Pointer pointer, Method | ^(instance) -> void | Releaser::_Proc[instance] callable) -> self + | (Pointer pointer) -> self # where class < `def self.release: (instance pointer) -> void` + + extend DataConverter[Pointer, instance, nil] + def self.from_native: ... + def self.native_type: () -> Type::Builtin + + def autorelease?: ... + def autorelease=: ... + def free: () -> nil + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/buffer.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/buffer.rbs new file mode 100644 index 00000000..68cde6bc --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/buffer.rbs @@ -0,0 +1,18 @@ +module FFI + class Buffer < AbstractMemory + def initialize: (AbstractMemory::type_size, ?Integer count, boolish clear) -> self + alias self.alloc_inout self.new + alias self.new_inout self.alloc_inout + alias self.alloc_in self.alloc_inout + alias self.new_in self.alloc_in + alias self.alloc_out self.alloc_inout + alias self.new_out self.alloc_out + + def +: (Integer) -> Buffer + def inspect: ... + def order: () -> AbstractMemory::order_out + | (AbstractMemory::order_in order) -> Buffer + | (untyped order) -> (self | Buffer) + def slice: (Integer offset, Integer length) -> Buffer + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/data_converter.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/data_converter.rbs new file mode 100644 index 00000000..a0e2e39f --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/data_converter.rbs @@ -0,0 +1,10 @@ +module FFI + interface _DataConverter[N, R, in C] + def from_native: (N value, C ctx) -> R + def native_type: (?ffi_auto_type? type) -> Type + def to_native: (R value, C ctx) -> N + end + module DataConverter[N, R, in C] + include _DataConverter[N, R, C] + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs new file mode 100644 index 00000000..48031bfa --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/dynamic_library.rbs @@ -0,0 +1,9 @@ +module FFI + class DynamicLibrary + # TODO + + class Symbol < Pointer + # TODO + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/enum.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/enum.rbs new file mode 100644 index 00000000..3cae0b2d --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/enum.rbs @@ -0,0 +1,38 @@ +module FFI + class Enums + def initialize: () -> void + + def <<: (Enum enum) -> void + def __map_symbol: (Symbol symbol) -> Integer? + def find: (Symbol query) -> Enum + end + + class Enum + include DataConverter[Integer, Symbol | Integer, untyped] + + attr_reader native_type: Type + attr_reader tag: Symbol? + def initialize: (Enumerable[Symbol | Integer], ?Symbol? tag, *untyped) -> void + | (Type native_type, Enumerable[Symbol | Integer], ?Symbol? tag, *untyped) -> void + + def []: (Symbol query) -> Integer? + | (Integer query) -> Symbol? + def symbol_map: () -> Hash[Symbol, Integer] + alias to_h symbol_map + alias to_hash symbol_map + def symbols: () -> Array[Symbol] + def to_native: (Symbol | int value, untyped ctx) -> Integer + end + + class Bitmask < Enum + def initialize: ... + + def []: (*Symbol query) -> Integer + | (Array[Symbol] query) -> Integer + | (*Integer query) -> Array[Symbol] + | (Array[Integer] query) -> Array[Symbol] + def from_native: (Integer, untyped ctx) -> Array[Symbol | Integer] + def to_native: (Array[Symbol | int] value, untyped ctx) -> Integer + | ... + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/errno.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/errno.rbs new file mode 100644 index 00000000..2877cd7c --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/errno.rbs @@ -0,0 +1,8 @@ +module FFI + module LastError + def self?.error: () -> Integer + def self?.error=: (Integer) -> Integer + def self?.winapi_error: () -> Integer? + def self?.winapi_error=: (Integer? error) -> void + end +end \ No newline at end of file diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/function.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/function.rbs new file mode 100644 index 00000000..94a23c2d --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/function.rbs @@ -0,0 +1,39 @@ +module FFI + interface _Function + # TODO: leads to a endless recursion when used with -rrbs/test/setup + # def attach: (Module mod, String name) -> self + def call: (*untyped args) -> untyped + def param_types: () -> Array[Type] + def return_type: () -> Type + end + + class Function < Pointer + include _Function + # ?blocking: boolish?, ?convention: Library::convention?, ?enums: Enums? + def initialize: + ( + ffi_type return_type, Array[ffi_type] param_types, + ?Hash[Symbol, untyped] options + ) { (*untyped) -> untyped } -> self + | ( + ffi_type return_type, Array[ffi_type] param_types, Proc | Pointer proc, + ?Hash[Symbol, untyped] options + ) -> self + + def autorelease?: ... + alias autorelease autorelease? + def autorelease=: ... + def free: () -> self + end + + class VariadicInvoker + include _Function + def initialize: + ( + Pointer function, Array[ffi_type] parameter_types, ffi_type return_type, + Hash[Symbol, untyped] options #TODO + ) -> void + + def invoke: (Array[Type] parameter_types, Array[untyped] parameter_values) -> untyped + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/library.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/library.rbs new file mode 100644 index 00000000..e823b6d2 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/library.rbs @@ -0,0 +1,42 @@ +module FFI + module Library + type convention = :default | :stdcall + type ffi_lib_flag = :global | :local | :lazy | :now + type ffi_lib_type = ffi_auto_type | singleton(Struct) + + CURRENT_PROCESS: current_process + LIBC: String + FlagsMap: Hash[ffi_lib_flag, Integer] + + def self.extended: ... + + def attach_function: ( _ToS func, Array[ffi_lib_type] args, ffi_lib_type? returns, ?blocking: boolish, ?convention: convention, ?enums: Enums, ?type_map: type_map) -> (Function | VariadicInvoker) + | (_ToS name, _ToS func, Array[ffi_lib_type] args, ?ffi_lib_type? returns, ?blocking: boolish, ?convention: convention, ?enums: Enums, ?type_map: type_map) -> (Function | VariadicInvoker) + def attach_variable: (?_ToS mname, _ToS cname, ffi_lib_type type) -> DynamicLibrary::Symbol + def attached_functions: () -> Hash[Symbol, Function | VariadicInvoker] + def attached_variables: () -> Hash[Symbol, Type | singleton(Struct)] + + def bitmask: (?Type native_type, Symbol name, Array[Symbol | Integer] values) -> Bitmask + | (?Type native_type, *Symbol | Integer args) -> Bitmask + | (?Type native_type, Array[Symbol | Integer] values) -> Bitmask + def enum: (?Type native_type, Symbol name, Array[Symbol | Integer] values) -> Enum + | (?Type native_type, *Symbol | Integer args) -> Enum + | (?Type native_type, Array[Symbol | Integer] values) -> Enum + def enum_type: (Symbol name) -> Enum? + def enum_for: (Symbol name) -> Integer? + + def callback: (?Symbol name, Array[ffi_lib_type] params, ffi_lib_type ret) -> CallbackInfo + def ffi_convention: (?convention? convention) -> convention + def ffi_lib: (*_ToS names) -> Array[DynamicLibrary] + def ffi_lib_flags: (*ffi_lib_flag flags) -> Integer + def ffi_libraries: () -> Array[DynamicLibrary] + def find_type: (ffi_lib_type t) -> Type + def freeze: () -> void + def function_names: (_ToS name, Array[Type | singleton(Struct)] arg_types) -> Array[String] + def typedef: [T < Type, N, R, C] (T old, Symbol | DataConverter[N, R, C] add, ?untyped) -> T + | (Symbol old, Symbol add, ?untyped) -> (Type | Enum) + | [X < DataConverter[N, R, C], N, R, C] (X old, Symbol add, ?untyped) -> Type::Mapped[X, N, R, C] + | (:enum old, Array[Symbol | Integer] add, ?untyped) -> Enum + | (:enum old, Symbol | Type add, Array[Symbol | Integer] info) -> Enum + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/native_type.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/native_type.rbs new file mode 100644 index 00000000..c9617a03 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/native_type.rbs @@ -0,0 +1,86 @@ +module FFI + class Type + INT8: Builtin + SCHAR: Builtin + CHAR: Builtin + UINT8: Builtin + UCHAR: Builtin + INT16: Builtin + SHORT: Builtin + SSHORT: Builtin + UINT16: Builtin + USHORT: Builtin + INT32: Builtin + INT: Builtin + SINT: Builtin + UINT32: Builtin + UINT: Builtin + INT64: Builtin + LONG_LONG: Builtin + SLONG_LONG: Builtin + UINT64: Builtin + ULONG_LONG: Builtin + LONG: Builtin + SLONG: Builtin + ULONG: Builtin + FLOAT32: Builtin + FLOAT: Builtin + FLOAT64: Builtin + DOUBLE: Builtin + LONGDOUBLE: Builtin + POINTER: Builtin + BOOL: Builtin + STRING: Builtin + BUFFER_IN: Builtin + BUFFER_OUT: Builtin + BUFFER_INOUT: Builtin + VARARGS: Builtin + VOID: Builtin + end + + module NativeType + INT8: Type::Builtin + UINT8: Type::Builtin + INT16: Type::Builtin + UINT16: Type::Builtin + INT32: Type::Builtin + UINT32: Type::Builtin + INT64: Type::Builtin + UINT64: Type::Builtin + LONG: Type::Builtin + ULONG: Type::Builtin + FLOAT32: Type::Builtin + FLOAT64: Type::Builtin + LONGDOUBLE: Type::Builtin + POINTER: Type::Builtin + BOOL: Type::Builtin + STRING: Type::Builtin + BUFFER_IN: Type::Builtin + BUFFER_OUT: Type::Builtin + BUFFER_INOUT: Type::Builtin + VARARGS: Type::Builtin + VOID: Type::Builtin + end + + TYPE_INT8: Type::Builtin + TYPE_UINT8: Type::Builtin + TYPE_INT16: Type::Builtin + TYPE_UINT16: Type::Builtin + TYPE_INT32: Type::Builtin + TYPE_UINT32: Type::Builtin + TYPE_INT64: Type::Builtin + TYPE_UINT64: Type::Builtin + TYPE_LONG: Type::Builtin + TYPE_ULONG: Type::Builtin + TYPE_FLOAT32: Type::Builtin + TYPE_FLOAT64: Type::Builtin + TYPE_LONGDOUBLE: Type::Builtin + TYPE_POINTER: Type::Builtin + TYPE_BOOL: Type::Builtin + TYPE_STRING: Type::Builtin + TYPE_BUFFER_IN: Type::Builtin + TYPE_BUFFER_OUT: Type::Builtin + TYPE_BUFFER_INOUT: Type::Builtin + TYPE_VARARGS: Type::Builtin + TYPE_VOID: Type::Builtin +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/platform.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/platform.rbs new file mode 100644 index 00000000..b51188a1 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/platform.rbs @@ -0,0 +1,49 @@ +module FFI + class PlatformError < LoadError + end + + module Platform + OS: String + + OSVERSION: Integer + + CPU: String + + ARCH: String + + IS_GNU: bool + IS_LINUX: bool + IS_MAC: bool + IS_FREEBSD: bool + IS_NETBSD: bool + IS_OPENBSD: bool + IS_DRAGONFLYBSD: bool + IS_SOLARIS: bool + IS_WINDOWS: bool + IS_BSD: bool + + NAME: String + + CONF_DIR: String + + LIBPREFIX: String + + LIBSUFFIX: String + + LIBC: String + + LITTLE_ENDIAN: Integer + + BIG_ENDIAN: Integer + + def self.bsd?: () -> bool + def self.windows?: () -> bool + def self.mac?: () -> bool + def self.solaris?: () -> bool + def self.unix?: () -> bool + + private + + def self.is_os: (String os) -> bool + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/pointer.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/pointer.rbs new file mode 100644 index 00000000..fd4e9b89 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/pointer.rbs @@ -0,0 +1,42 @@ +module FFI + type pointer = Pointer::_ToPtr? | Integer + class Pointer < AbstractMemory + interface _ToPtr + def to_ptr: () -> Pointer + end + include _ToPtr + + SIZE: Integer + NULL: Pointer + def self.size: () -> Integer + + def initialize: (?AbstractMemory::type_size type, (Pointer | Integer) address) -> void + def +: (Integer offset) -> Pointer + def ==: (Pointer? other) -> bool + def address: () -> Integer + alias to_i address + def autorelease?: () -> bool + def autorelease=: (boolish autorelease) -> boolish + def free: () -> self + def inspect: ... + def null?: () -> bool + def order: () -> AbstractMemory::order_out + | (AbstractMemory::order_in) -> Pointer + def read: (ffi_type type) -> top + def read_array_of_type: (ffi_auto_type type, Symbol reader, Integer length) -> Array[top] + def read_string: (?Integer? len) -> String + def read_string_length: (Integer len) -> String + def read_string_to_null: () -> String + def slice: (Integer offset, Integer length) -> Pointer + def type_size: () -> Integer + def write: (ffi_type type, top value) -> nil + def write_array_of_type: (ffi_auto_type type, Symbol writer, Array[top]) -> self + def write_string: (String str, ?Integer? len) -> self + def write_string_length: (String str, Integer len) -> self + end + + class MemoryPointer < Pointer + def initialize: (AbstractMemory::type_size size, ?Integer count, ?boolish clear) -> self + def self.from_string: (String s) -> instance + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct.rbs new file mode 100644 index 00000000..27b4d5a2 --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct.rbs @@ -0,0 +1,76 @@ +module FFI + class Struct[out P < AbstractMemory, unchecked out E] + type layout = Library::ffi_lib_type | singleton(StructLayout::Field) | [layout, Integer] + + type ptr = Type::Mapped[ + StructByReference[Struct[AbstractMemory, untyped], AbstractMemory], + AbstractMemory, Struct[AbstractMemory, untyped], untyped + ] + def self.ptr: (?untyped flags) -> ptr # https://github.com/ffi/ffi/issues/1073 + alias self.by_ref self.ptr + def self.in: () -> ptr + def self.out: () -> ptr + def self.val: () -> StructByValue[singleton(Struct)] + alias self.by_value self.val + + alias self.alloc_inout self.new + alias self.alloc_in self.new + alias self.alloc_out self.new + alias self.new_inout self.new + alias self.new_in self.new + alias self.new_out self.new + + def self.auto_ptr: () -> Type::Mapped[ + ManagedStructConverter[ManagedStruct[AutoPointer, untyped], AutoPointer], + Pointer, ManagedStruct[AutoPointer, untyped], untyped + ] + def self.layout: (*layout | Integer) -> StructLayout + | (Hash[Symbol, layout]) -> StructLayout + def self.size=: (Integer size) -> Integer + + def self?.alignment: () -> Integer + def self?.members: () -> Array[Symbol] + def self?.offset_of: (Symbol name) -> Integer + def self?.offsets: () -> Array[[Symbol, Integer]] + def self?.size: -> Integer + + def initialize: (?P pointer, *layout args) -> void + def []: (Symbol field_name) -> E + def []=: (Symbol field_name, E value) -> E + alias align alignment + def clear: () -> self + def layout: () -> StructLayout + def null?: () -> bool + def order: (AbstractMemory::order_in order) -> Struct[P, E] + | () -> AbstractMemory::order_out + def pointer: () -> P + alias to_ptr pointer + def values: () -> Array[E] + + class InlineArray[out P < AbstractMemory, unchecked out E] + include Enumerable[E] + include AbstractMemory::_Size + + def initialize: (P memory, StructLayout::Field field) -> self + def []: (Integer index) -> E + def []=: (Integer index, E value) -> E + def each: () { (E) -> void } -> self + def to_a: () -> Array[E] + def to_ptr: () -> P + end + + class ManagedStructConverter[S < ManagedStruct[P, untyped], P < AutoPointer] < StructByReference[S, P] + def initialize: ... + def from_native: (Pointer ptr, untyped ctx) -> S + end + end + + class ManagedStruct[out P < AutoPointer, unchecked out E] < Struct[P, E] + def self.release: (AbstractMemory ptr) -> void + def initialize: (Pointer pointer) -> self + end + + class Union[out P < AbstractMemory, unchecked out E] < Struct[P, E] + def self.builder: () -> StructLayoutBuilder + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs new file mode 100644 index 00000000..20ea2f8c --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_reference.rbs @@ -0,0 +1,11 @@ +module FFI + class StructByReference[S < Struct[P, untyped], P < AbstractMemory] + include DataConverter[P, S, untyped] + attr_reader struct_class: Struct[P, untyped] + + def initialize: (S struct_class) -> void + def from_native: (P value, untyped ctx) -> S + def native_type: (?ffi_auto_type? type) -> Type + def to_native: (S? value, untyped ctx) -> P + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs new file mode 100644 index 00000000..902bcc6b --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_by_value.rbs @@ -0,0 +1,7 @@ +module FFI + class StructByValue[C < singleton(Struct)] < Type + def initialize: (C) -> self + def layout: () -> StructLayout + def struct_class: () -> C + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout.rbs new file mode 100644 index 00000000..12b05aed --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout.rbs @@ -0,0 +1,9 @@ +module FFI + class StructLayout + #TODO + + class Field + #TODO + end + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs new file mode 100644 index 00000000..291a669a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/struct_layout_builder.rbs @@ -0,0 +1,5 @@ +module FFI + class StructLayoutBuilder + #TODO + end +end diff --git a/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/type.rbs b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/type.rbs new file mode 100644 index 00000000..66186d1a --- /dev/null +++ b/bin/gems/ffi-1.17.4-x86_64-linux-gnu/sig/ffi/type.rbs @@ -0,0 +1,39 @@ +module FFI + class Type + class Array = ArrayType + class Function = FunctionType + class Struct = StructByValue + + include AbstractMemory::_Size + def initialize: (Integer | Type value) -> self + def alignment: () -> Integer + def inspect: ... + + class Builtin < Type + def inspect: ... + end + + class Mapped[X < _DataConverter[N, R, C], N, R, C] + include _DataConverter[N, R, C] + + def initialize: (X converter) -> self + def converter: () -> X + end + end + + class ArrayType + def initialize: (Type component_type, Integer length) -> self + def element_type: -> Type + def length: -> Integer + end + + class FunctionType < Type + def initialize: + ( + ffi_type return_type, Array[ffi_type] param_types, + ?blocking: boolish, ?convention: Library::convention, ?enums: Enums + ) -> self + def param_types: () -> Array[Type] + def return_type: () -> Type + end +end diff --git a/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation.rb b/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation.rb new file mode 100644 index 00000000..dc2cb493 --- /dev/null +++ b/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +require 'fiber' + +class Fiber + # A mechanism for annotating fibers. + module Annotation + # Annotate the current fiber with the given annotation. + # @parameter annotation [Object] The annotation to set. + def initialize(annotation: nil, **options, &block) + @annotation = annotation + super(**options, &block) + end + + # Get the current annotation. + # @returns [Object] The current annotation. + attr_accessor :annotation + + # Annotate the current fiber with the given annotation. + # + # If a block is given, the annotation is set for the duration of the block and then restored to the previous value. + # + # The block form of this method should only be invoked on the current fiber. + # + # @parameter annotation [Object] The annotation to set. + # @yields {} The block to execute with the given annotation. + # @returns [Object] The return value of the block. + def annotate(annotation) + if block_given? + raise "Cannot annotation a different fiber!" unless Fiber.current == self + + begin + current_annotation = @annotation + @annotation = annotation + return yield + ensure + @annotation = current_annotation + end + else + @annotation = annotation + end + end + end +end + +unless Fiber.method_defined?(:annotation) + Fiber.prepend(Fiber::Annotation) + + # @scope Fiber + # @name self.annotate + # Annotate the current fiber with the given annotation. + def Fiber.annotate(...) + Fiber.current.annotate(...) + end +end diff --git a/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation/version.rb b/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation/version.rb new file mode 100644 index 00000000..2e109c3e --- /dev/null +++ b/bin/gems/fiber-annotation-0.2.0/lib/fiber/annotation/version.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +class Fiber + module Annotation + VERSION = "0.2.0" + end +end diff --git a/bin/gems/fiber-annotation-0.2.0/license.md b/bin/gems/fiber-annotation-0.2.0/license.md new file mode 100644 index 00000000..3fe330dc --- /dev/null +++ b/bin/gems/fiber-annotation-0.2.0/license.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright, 2023, by Samuel Williams. + +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/bin/gems/fiber-annotation-0.2.0/readme.md b/bin/gems/fiber-annotation-0.2.0/readme.md new file mode 100644 index 00000000..67191ae2 --- /dev/null +++ b/bin/gems/fiber-annotation-0.2.0/readme.md @@ -0,0 +1,19 @@ +# Fiber::Annotation + +A simple way to annotate what a fiber is currently doing, useful for debugging, logging and tracing. + +[![Development Status](https://github.com/ioquatix/fiber-annotation/workflows/Test/badge.svg)](https://github.com/ioquatix/fiber-annotation/actions?workflow=Test) + +## Usage + +Please see the [project documentation](https://ioquatix.github.io/fiber-annotation). + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. diff --git a/bin/gems/fiber-local-1.1.0/lib/fiber/local.rb b/bin/gems/fiber-local-1.1.0/lib/fiber/local.rb new file mode 100644 index 00000000..27488b4f --- /dev/null +++ b/bin/gems/fiber-local-1.1.0/lib/fiber/local.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. + +require_relative "local/version" +require 'fiber/storage' + +class Fiber + module Local + def self.extended(klass) + attribute_name = klass.name.gsub('::', '_').gsub(/\W/, '').downcase.to_sym + + # This is used for the general interface and fiber storage key: + klass.instance_variable_set(:@fiber_local_attribute_name, attribute_name) + klass.singleton_class.attr :fiber_local_attribute_name + + # This is used for reading and writing directly to the thread instance variables: + klass.instance_variable_set(:@fiber_local_variable_name, :"@#{attribute_name}") + + Thread.attr_accessor(attribute_name) + end + + # Instantiate a new thread-local object. + # By default, invokes {new} to generate the instance. + # @returns [Object] + def local + self.new + end + + # Get the current thread-local instance. Create it if required. + # @returns [Object] The thread-local instance. + def instance + # This is considered a local "override" in the dynamic scope of the fiber: + if instance = Fiber[@fiber_local_attribute_name] + return instance + end + + # This is generally the fast path: + thread = Thread.current + unless instance = thread.instance_variable_get(@fiber_local_variable_name) + if instance = self.local + thread.instance_variable_set(@fiber_local_variable_name, instance) + end + end + + return instance + end + + # Assigns to the fiber-local instance. + # @parameter instance [Object] The object that will become the thread-local instance. + def instance= instance + Fiber[@fiber_local_attribute_name] = instance + end + end +end diff --git a/bin/gems/fiber-local-1.1.0/lib/fiber/local/version.rb b/bin/gems/fiber-local-1.1.0/lib/fiber/local/version.rb new file mode 100644 index 00000000..f440a69f --- /dev/null +++ b/bin/gems/fiber-local-1.1.0/lib/fiber/local/version.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020, by Samuel Williams. + +class Fiber + module Local + VERSION = "1.1.0" + end +end diff --git a/bin/gems/fiber-local-1.1.0/license.md b/bin/gems/fiber-local-1.1.0/license.md new file mode 100644 index 00000000..2e71de4a --- /dev/null +++ b/bin/gems/fiber-local-1.1.0/license.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright, 2020-2024, by Samuel Williams. + +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/bin/gems/fiber-local-1.1.0/readme.md b/bin/gems/fiber-local-1.1.0/readme.md new file mode 100644 index 00000000..5873e0a6 --- /dev/null +++ b/bin/gems/fiber-local-1.1.0/readme.md @@ -0,0 +1,82 @@ +# Fiber::Local + +A module to simplify fiber-local state. + +[![Development Status](https://github.com/socketry/fiber-local/workflows/Test/badge.svg)](https://github.com/socketry/fiber-local/actions?workflow=Test) + +## Features + + - Easily access fiber-local state from a fiber. + - Default to shared thread-local state. + +## Installation + +``` bash +$ bundle add fiber-local +``` + +## Usage + +In your own class, e.g. `Logger`: + +``` ruby +class Logger + extend Fiber::Local + + def initialize + @buffer = [] + end + + def log(*arguments) + @buffer << arguments + end +end +``` + +Now, instead of instantiating your cache `LOGGER = Logger.new`, use `Logger.instance`. It will return a thread-local instance. + +``` ruby +Thread.new do + Logger.instance + # => # +end + +Thread.new do + Logger.instance + # => # +end +``` + +In cases where you have job per fiber or request per fiber, you might want to collect all log output for a specific fiber, you can do the following: + +``` ruby +Logger.instance +# => # + +Fiber.new do + Logger.instance = Logger.new + # => # +end +``` + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +### Developer Certificate of Origin + +This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted. + +### Contributor Covenant + +This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms. + +## See Also + + - [thread-local](https://github.com/socketry/thread-local) — Strictly thread-local variables. diff --git a/bin/gems/fiber-storage-1.0.0/lib/fiber/storage.rb b/bin/gems/fiber-storage-1.0.0/lib/fiber/storage.rb new file mode 100644 index 00000000..a0490b5a --- /dev/null +++ b/bin/gems/fiber-storage-1.0.0/lib/fiber/storage.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. + +require 'fiber' + +# @namespace +class Fiber + # Provides compatibility shims for fiber storage. + module Storage + # Initialize the fiber with the given storage. + def initialize(*arguments, storage: true, **options, &block) + case storage + when true + @storage = Fiber.current.storage + else + raise TypeError, "Storage must be a hash!" unless storage.is_a?(Hash) + + @storage = storage + end + + super(*arguments, **options, &block) + end + + # Set the storage associated with this fiber, clearing any previous storage. + def storage=(hash) + @storage = hash.dup + end + + # The storage associated with this fiber. + def storage + @storage.dup + end + + # @private + def __storage__ + @storage ||= {} + end + end + + unless Fiber.current.respond_to?(:storage) + prepend Storage + + # Get a value from the current fiber's storage. + def self.[] key + raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol) + + self.current.__storage__[key] + end + + # Set a value in the current fiber's storage. + def self.[]= key, value + raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol) + + self.current.__storage__[key] = value + end + else + # Whether the fiber storage has buggy keys. Unfortunately the original implementation of fiber storage was broken, this method detects the bug and is used to apply a fix. + def self.__borked_keys__ + !Fiber.new do + key = :"#{self.object_id}.key" + Fiber[key] = true + Fiber[key] + end.resume + end + + if __borked_keys__ + # This is a fix for the original implementation of fiber storage which incorrectly handled non-dynamic symbol keys. + module FixBorkedKeys + # Lookup the value for the key, ensuring the symbol is dynamic. + def [](key) + raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol) + + super(eval(key.inspect)) + end + + # Assign the value to the key, ensuring the symbol is dynamic. + def []=(key, value) + raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol) + + super(eval(key.inspect), value) + end + end + + singleton_class.prepend FixBorkedKeys + end + end +end diff --git a/bin/gems/fiber-storage-1.0.0/lib/fiber/storage/version.rb b/bin/gems/fiber-storage-1.0.0/lib/fiber/storage/version.rb new file mode 100644 index 00000000..cfc23aab --- /dev/null +++ b/bin/gems/fiber-storage-1.0.0/lib/fiber/storage/version.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2022-2024, by Samuel Williams. + +require 'fiber' + +class Fiber + module Storage + VERSION = "1.0.0" + end +end diff --git a/bin/gems/fiber-storage-1.0.0/license.md b/bin/gems/fiber-storage-1.0.0/license.md new file mode 100644 index 00000000..e41823c4 --- /dev/null +++ b/bin/gems/fiber-storage-1.0.0/license.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright, 2022-2024, by Samuel Williams. + +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/bin/gems/fiber-storage-1.0.0/readme.md b/bin/gems/fiber-storage-1.0.0/readme.md new file mode 100644 index 00000000..d8264bd4 --- /dev/null +++ b/bin/gems/fiber-storage-1.0.0/readme.md @@ -0,0 +1,35 @@ +# Fiber::Storage + +This gem provides a shim for `Fiber.[]`, `Fiber.[]=`, `Fiber#storage`, `Fiber#storage=`, which was introduced in Ruby 3.2. + +[![Development Status](https://github.com/ioquatix/fiber-storage/workflows/Test/badge.svg)](https://github.com/ioquatix/fiber-storage/actions?workflow=Test) + +## Motivation + +Ruby 3.2 introduces inheritable fiber storage for per-request or per-operation state. This gem provides a shim for Ruby 3.1 and earlier to make adoption easier. It isn't able to provide the full range of features, but it should be sufficient for most use cases. + +Notably, it does not support inheritance across threads or lazy Enumerator. This is a limitation of the shim implementation. + +## Usage + +Please see the [project documentation](https://ioquatix.github.io/fiber-storage/) for more details. + + - [Getting Started](https://ioquatix.github.io/fiber-storage/guides/getting-started/index) - This guide explains how to use this gem and provides a brief overview of the features. + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +### Developer Certificate of Origin + +In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. + +### Community Guidelines + +This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers. diff --git a/bin/gems/forwardable-extended-2.6.0/Gemfile b/bin/gems/forwardable-extended-2.6.0/Gemfile new file mode 100644 index 00000000..ea587c77 --- /dev/null +++ b/bin/gems/forwardable-extended-2.6.0/Gemfile @@ -0,0 +1,24 @@ +# ---------------------------------------------------------------------------- +# Frozen-string-literal: true +# Copyright: 2015-2016 Jordon Bedwell - MIT License +# Encoding: utf-8 +# ---------------------------------------------------------------------------- + +source "https://rubygems.org" +gem "rake", :require => false +gemspec + +group :test do + gem "rspec-helpers", :require => false + gem "codeclimate-test-reporter", :require => false + gem "luna-rspec-formatters", :require => false + gem "rspec", :require => false +end + +group :development do + gem "luna-rubocop-formatters", :require => false + gem "rubocop", :github => "bbatsov/rubocop", :require => false + gem "pry", { + :require => false + } +end diff --git a/bin/gems/forwardable-extended-2.6.0/LICENSE b/bin/gems/forwardable-extended-2.6.0/LICENSE new file mode 100644 index 00000000..e603a782 --- /dev/null +++ b/bin/gems/forwardable-extended-2.6.0/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2016 Jordon Bedwell + +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/bin/gems/forwardable-extended-2.6.0/Rakefile b/bin/gems/forwardable-extended-2.6.0/Rakefile new file mode 100644 index 00000000..1c929e5c --- /dev/null +++ b/bin/gems/forwardable-extended-2.6.0/Rakefile @@ -0,0 +1,13 @@ +# ---------------------------------------------------------------------------- +# Frozen-string-literal: true +# Copyright: 2015-2016 Jordon Bedwell - MIT License +# Encoding: utf-8 +# ---------------------------------------------------------------------------- + +$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__)) +require "luna/rubocop/rake/task" +require "rspec/core/rake_task" + +task :default => [:spec] +RSpec::Core::RakeTask.new :spec +task :test => :spec diff --git a/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended.rb b/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended.rb new file mode 100644 index 00000000..fc694cf1 --- /dev/null +++ b/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended.rb @@ -0,0 +1,202 @@ +# ---------------------------------------------------------------------------- +# Frozen-string-literal: true +# Copyright: 2015-2016 Jordon Bedwell - MIT License +# Encoding: utf-8 +# ---------------------------------------------------------------------------- + +require "forwardable/extended/version" +require "forwardable" + +module Forwardable + module Extended + + # ------------------------------------------------------------------------ + # Make our methods private on the class, there is no reason for public. + # ------------------------------------------------------------------------ + + def self.extended(klass) + instance_methods.each do |method| + klass.private_class_method( + method + ) + end + end + + # ------------------------------------------------------------------------ + # Delegate using a Rails-like interface. + # ------------------------------------------------------------------------ + + def rb_delegate(method, to: nil, alias_of: method, **kwd) + raise ArgumentError, "to must be provided" unless to + def_delegator( + to, alias_of, method, **kwd + ) + end + + # ------------------------------------------------------------------------ + # Delegate a method to a hash and key. + # ------------------------------------------------------------------------ + + def def_hash_delegator(hash, method, key: method, **kwd) + prefix, suffix, wrap = prepare_delegate(**kwd) + + if suffix + method = method.to_s.gsub( + /\?$/, "" + ) + end + + class_eval delegate_debug(<<-STR), __FILE__, __LINE__ - 9 + def #{method}#{suffix}(*args) + #{wrap}( + #{prefix}#{hash}[#{key.inspect}] + ) + + rescue Exception + if !Forwardable.debug && $@ && $@.respond_to?(:delete_if) + $@.delete_if do |source| + source =~ %r"#{Regexp.escape(__FILE__)}"o + end + end + + raise + end + STR + end + + # ------------------------------------------------------------------------ + # Delegate a method to an instance variable. + # ------------------------------------------------------------------------ + + def def_ivar_delegator(ivar, alias_ = ivar, **kwd) + prefix, suffix, wrap = prepare_delegate(**kwd) + + if suffix + alias_ = alias_.to_s.gsub( + /\?$/, "" + ) + end + + class_eval delegate_debug(<<-STR), __FILE__, __LINE__ - 9 + def #{alias_.to_s.gsub(/\A@/, "")}#{suffix} + #{wrap}( + #{prefix}#{ivar} + ) + + rescue Exception + if !Forwardable.debug && $@ && $@.respond_to?(:delete_if) + $@.delete_if do |source| + source =~ %r"#{Regexp.escape(__FILE__)}"o + end + end + + raise + end + STR + end + + # ------------------------------------------------------------------------ + # Like def_delegator but allows you to send args and do other stuff. + # ------------------------------------------------------------------------ + + def def_modern_delegator(accessor, method, alias_ = method, args: \ + { :before => [], :after => [] }, **kwd) + + prefix, suffix, wrap = prepare_delegate(**kwd) + args = { :before => args } unless args.is_a?(Hash) + b = [args[:before]].flatten.compact.map(&:to_s).join(", ") + a = [args[ :after]].flatten.compact.map(&:to_s).join(", ") + b = b + ", " unless args[:before].nil? || args[:before].empty? + a = ", " + a unless args[ :after].nil? || args[ :after].empty? + alias_ = alias_.to_s.gsub(/\?$/, "") if suffix + + class_eval delegate_debug(<<-STR), __FILE__, __LINE__ - 10 + def #{alias_}#{suffix}(*args, &block) + #{wrap}(#{prefix}#{accessor}.send( + #{method.inspect}, #{b}*args#{a}, &block + )) + + rescue Exception + if !Forwardable.debug && $@ && $@.respond_to?(:delete_if) + $@.delete_if do |source| + source =~ %r"#{Regexp.escape(__FILE__)}"o + end + end + + raise + end + STR + end + + # ------------------------------------------------------------------------ + # Wraps around traditional delegation and modern delegation. + # ------------------------------------------------------------------------ + + def def_delegator(accessor, method, alias_ = method, **kwd) + kwd, alias_ = alias_, method if alias_.is_a?(Hash) && !kwd.any? + + if alias_.is_a?(Hash) || !kwd.any? + Forwardable.instance_method(:def_delegator).bind(self) \ + .call(accessor, method, alias_) + + elsif !kwd[:type] + def_modern_delegator( + accessor, method, alias_, **kwd + ) + + else + raise ArgumentError, "Alias not supported." if alias_ != method + send("def_#{kwd[:type]}_delegator", accessor, method, **kwd.tap do |obj| + obj.delete(:type) + end) + end + end + + # ------------------------------------------------------------------------ + # Create multiple delegates at once. + # ------------------------------------------------------------------------ + + def def_delegators(accessor, *methods) + kwd = methods.shift if methods.first.is_a?(Hash) + kwd = methods.pop if methods. last.is_a?(Hash) + kwd = {} unless kwd + + methods.each do |method| + def_delegator accessor, method, **kwd + end + end + + # ------------------------------------------------------------------------ + # Prepares a delegate and it's few arguments. + # ------------------------------------------------------------------------ + + private + def prepare_delegate(wrap: nil, bool: false) + prefix = (bool == :reverse ? "!!!" : "!!") if bool + wrap = "self.class.new" if wrap.is_a?(TrueClass) + suffix = "?" if bool + + return [ + prefix, suffix, wrap + ] + end + + # ------------------------------------------------------------------------ + + private + def delegate_debug(str) + if Forwardable.debug && !Forwardable.debug.is_a?(TrueClass) + then Forwardable.debug.debug( + str + ) + + elsif Forwardable.debug + $stdout.puts( + "\n# ------\n\n", str + ) + end + + str + end + end +end diff --git a/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended/version.rb b/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended/version.rb new file mode 100644 index 00000000..06393756 --- /dev/null +++ b/bin/gems/forwardable-extended-2.6.0/lib/forwardable/extended/version.rb @@ -0,0 +1,9 @@ +# Frozen-string-literal: true +# Copyright: 2015-2016 Jordon Bedwell - MIT License +# Encoding: utf-8 + +module Forwardable + module Extended + VERSION = "2.6.0" + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/Rakefile b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/Rakefile new file mode 100755 index 00000000..0d4f84eb --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/Rakefile @@ -0,0 +1,3 @@ +import '../../../lib/google/tasks/ffi.rake' + +task default: ['ffi-protobuf:default'] \ No newline at end of file diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.c new file mode 100755 index 00000000..2b2244b0 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.c @@ -0,0 +1,342 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. +// +// This file Also contains a few other assorted algorithms on upb_MessageValue. +// +// None of the algorithms in this file require any access to the internal +// representation of Ruby or upb objects. +// ----------------------------------------------------------------------------- + +#include "convert.h" + +#include "message.h" +#include "protobuf.h" +#include "shared_convert.h" + +static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) { + upb_StringView ret; + if (arena) { + char* ptr = upb_Arena_Malloc(arena, RSTRING_LEN(str)); + memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str)); + ret.data = ptr; + } else { + // Data is only needed temporarily (within map lookup). + ret.data = RSTRING_PTR(str); + } + ret.size = RSTRING_LEN(str); + return ret; +} + +static bool is_ruby_num(VALUE value) { + return (TYPE(value) == T_FLOAT || TYPE(value) == T_FIXNUM || + TYPE(value) == T_BIGNUM); +} + +static void Convert_CheckInt(const char* name, upb_CType type, VALUE val) { + if (!is_ruby_num(val)) { + rb_raise(cTypeError, + "Expected number type for integral field '%s' (given %s).", name, + rb_class2name(CLASS_OF(val))); + } + + // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper + // bound; we just need to do precision checks (i.e., disallow rounding) and + // check for < 0 on unsigned types. + if (TYPE(val) == T_FLOAT) { + double dbl_val = NUM2DBL(val); + if (floor(dbl_val) != dbl_val) { + rb_raise(rb_eRangeError, + "Non-integral floating point value assigned to integer field " + "'%s' (given %s).", + name, rb_class2name(CLASS_OF(val))); + } + } + if (type == kUpb_CType_UInt32 || type == kUpb_CType_UInt64) { + if (NUM2DBL(val) < 0) { + rb_raise( + rb_eRangeError, + "Assigning negative value to unsigned integer field '%s' (given %s).", + name, rb_class2name(CLASS_OF(val))); + } + } +} + +static int32_t Convert_ToEnum(VALUE value, const char* name, + const upb_EnumDef* e) { + int32_t val; + + switch (TYPE(value)) { + case T_FLOAT: + case T_FIXNUM: + case T_BIGNUM: + Convert_CheckInt(name, kUpb_CType_Int32, value); + val = NUM2INT(value); + break; + case T_STRING: { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNameWithSize( + e, RSTRING_PTR(value), RSTRING_LEN(value)); + if (!ev) goto unknownval; + val = upb_EnumValueDef_Number(ev); + break; + } + case T_SYMBOL: { + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByName(e, rb_id2name(SYM2ID(value))); + if (!ev) goto unknownval; + val = upb_EnumValueDef_Number(ev); + break; + } + default: + rb_raise(cTypeError, + "Expected number or symbol type for enum field '%s'.", name); + } + + return val; + +unknownval: + rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name); +} + +VALUE Convert_CheckStringUtf8(VALUE str) { + VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding()); + + if (rb_obj_encoding(str) == utf8) { + // Note: Just because a string is marked as having UTF-8 encoding does + // not mean that it is *valid* UTF-8. We have to check separately + // whether it is valid. + if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) { + // TODO: For now + // we only warn for this case. We will remove the warning and throw an + // exception below in the 30.x release + + rb_warn( + "String is invalid UTF-8. This will be an error in a future " + "version."); + // VALUE exc = rb_const_get_at( + // rb_cEncoding, rb_intern("InvalidByteSequenceError")); + // rb_raise(exc, "String is invalid UTF-8"); + } + } else { + // Note: this will not duplicate underlying string data unless + // necessary. + // + // This will throw an exception if the conversion cannot be performed: + // - Encoding::UndefinedConversionError if certain characters cannot be + // converted to UTF-8. + // - Encoding::InvalidByteSequenceError if certain characters were invalid + // in the source encoding. + str = rb_str_encode(str, utf8, 0, Qnil); + PBRUBY_ASSERT(rb_enc_str_coderange(str) != ENC_CODERANGE_BROKEN); + } + + return str; +} + +upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name, + TypeInfo type_info, upb_Arena* arena) { + upb_MessageValue ret; + + switch (type_info.type) { + case kUpb_CType_Float: + if (!is_ruby_num(value)) { + rb_raise(cTypeError, + "Expected number type for float field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + ret.float_val = NUM2DBL(value); + break; + case kUpb_CType_Double: + if (!is_ruby_num(value)) { + rb_raise(cTypeError, + "Expected number type for double field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + ret.double_val = NUM2DBL(value); + break; + case kUpb_CType_Bool: { + if (value == Qtrue) { + ret.bool_val = 1; + } else if (value == Qfalse) { + ret.bool_val = 0; + } else { + rb_raise(cTypeError, + "Invalid argument for boolean field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + break; + } + case kUpb_CType_String: + if (rb_obj_class(value) == rb_cSymbol) { + value = rb_funcall(value, rb_intern("to_s"), 0); + } else if (!rb_obj_is_kind_of(value, rb_cString)) { + rb_raise(cTypeError, + "Invalid argument for string field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + + value = Convert_CheckStringUtf8(value); + ret.str_val = Convert_StringData(value, arena); + break; + case kUpb_CType_Bytes: { + VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding()); + if (rb_obj_class(value) != rb_cString) { + rb_raise(cTypeError, + "Invalid argument for bytes field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + + if (rb_obj_encoding(value) != bytes) { + // Note: this will not duplicate underlying string data unless + // necessary. + // TODO: is this really necessary to get raw bytes? + value = rb_str_encode(value, bytes, 0, Qnil); + } + + ret.str_val = Convert_StringData(value, arena); + break; + } + case kUpb_CType_Message: + ret.msg_val = + Message_GetUpbMessage(value, type_info.def.msgdef, name, arena); + break; + case kUpb_CType_Enum: + ret.int32_val = Convert_ToEnum(value, name, type_info.def.enumdef); + break; + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + Convert_CheckInt(name, type_info.type, value); + switch (type_info.type) { + case kUpb_CType_Int32: + ret.int32_val = NUM2INT(value); + break; + case kUpb_CType_Int64: + ret.int64_val = NUM2LL(value); + break; + case kUpb_CType_UInt32: + ret.uint32_val = NUM2UINT(value); + break; + case kUpb_CType_UInt64: + ret.uint64_val = NUM2ULL(value); + break; + default: + rb_raise(cTypeError, "Convert_RubyToUpb(): Unexpected type %d", + (int)type_info.type); + } + break; + default: + rb_raise(cTypeError, + "Convert_RubyToUpb(): Unexpected type %d", (int)type_info.type); + } + + return ret; +} + +VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info, + VALUE arena) { + switch (type_info.type) { + case kUpb_CType_Float: + return DBL2NUM(upb_val.float_val); + case kUpb_CType_Double: + return DBL2NUM(upb_val.double_val); + case kUpb_CType_Bool: + return upb_val.bool_val ? Qtrue : Qfalse; + case kUpb_CType_Int32: + return INT2NUM(upb_val.int32_val); + case kUpb_CType_Int64: + return LL2NUM(upb_val.int64_val); + case kUpb_CType_UInt32: + return UINT2NUM(upb_val.uint32_val); + case kUpb_CType_UInt64: + return ULL2NUM(upb_val.int64_val); + case kUpb_CType_Enum: { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber( + type_info.def.enumdef, upb_val.int32_val); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return INT2NUM(upb_val.int32_val); + } + } + case kUpb_CType_String: { + VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size); + rb_enc_associate(str_rb, rb_utf8_encoding()); + rb_obj_freeze(str_rb); + return str_rb; + } + case kUpb_CType_Bytes: { + VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size); + rb_enc_associate(str_rb, rb_ascii8bit_encoding()); + rb_obj_freeze(str_rb); + return str_rb; + } + case kUpb_CType_Message: + return Message_GetRubyWrapper((upb_Message*)upb_val.msg_val, + type_info.def.msgdef, arena); + default: + rb_raise(rb_eRuntimeError, "Convert_UpbToRuby(): Unexpected type %d", + (int)type_info.type); + } +} + +upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info, + upb_Arena* arena) { + upb_MessageValue new_msgval; + + switch (type_info.type) { + default: + memcpy(&new_msgval, &msgval, sizeof(msgval)); + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + size_t n = msgval.str_val.size; + char* mem = upb_Arena_Malloc(arena, n); + new_msgval.str_val.data = mem; + new_msgval.str_val.size = n; + memcpy(mem, msgval.str_val.data, n); + break; + } + case kUpb_CType_Message: + new_msgval.msg_val = + Message_deep_copy(msgval.msg_val, type_info.def.msgdef, arena); + break; + } + + return new_msgval; +} + +bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + TypeInfo type_info) { + upb_Status status; + upb_Status_Clear(&status); + bool return_value = shared_Msgval_IsEqual(val1, val2, type_info.type, + type_info.def.msgdef, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(rb_eRuntimeError, "Msgval_IsEqual(): %s", + upb_Status_ErrorMessage(&status)); + } +} + +uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info, + uint64_t seed) { + upb_Status status; + upb_Status_Clear(&status); + uint64_t return_value = shared_Msgval_GetHash( + val, type_info.type, type_info.def.msgdef, seed, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(rb_eRuntimeError, "Msgval_GetHash(): %s", + upb_Status_ErrorMessage(&status)); + } +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.h new file mode 100755 index 00000000..ac3eaab2 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/convert.h @@ -0,0 +1,50 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_CONVERT_H_ +#define RUBY_PROTOBUF_CONVERT_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Converts |ruby_val| to a upb_MessageValue according to |type_info|. +// +// The |arena| parameter indicates the lifetime of the container where this +// value will be assigned. It is used as follows: +// - If type is string or bytes, the string data will be copied into |arena|. +// - If type is message, and we need to auto-construct a message due to implicit +// conversions (eg. Time -> Google::Protobuf::Timestamp), the new message +// will be created in |arena|. +// - If type is message and the Ruby value is a message instance, we will fuse +// the message's arena into |arena|, to ensure that this message outlives the +// container. +upb_MessageValue Convert_RubyToUpb(VALUE ruby_val, const char *name, + TypeInfo type_info, upb_Arena *arena); + +// Converts |upb_val| to a Ruby VALUE according to |type_info|. This may involve +// creating a Ruby wrapper object. +// +// The |arena| parameter indicates the arena that owns the lifetime of +// |upb_val|. Any Ruby wrapper object that is created will reference |arena| +// and ensure it outlives the wrapper. +VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info, + VALUE arena); + +// Creates a deep copy of |msgval| in |arena|. +upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info, + upb_Arena *arena); + +// Returns true if |val1| and |val2| are equal. Their type is given by +// |type_info|. +bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + TypeInfo type_info); + +// Returns a hash value for the given upb_MessageValue. +uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info, + uint64_t seed); + +#endif // RUBY_PROTOBUF_CONVERT_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.c new file mode 100755 index 00000000..d933049d --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.c @@ -0,0 +1,1741 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include +#include + +#include "convert.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor +// instances. +// ----------------------------------------------------------------------------- + +static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def); +static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def); +static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def); +static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def); +static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def); +static VALUE get_servicedef_obj(VALUE descriptor_pool, + const upb_ServiceDef* def); +static VALUE get_methoddef_obj(VALUE descriptor_pool, const upb_MethodDef* def); + +// A distinct object that is not accessible from Ruby. We use this as a +// constructor argument to enforce that certain objects cannot be created from +// Ruby. +VALUE c_only_cookie = Qnil; + +// ----------------------------------------------------------------------------- +// Common utilities. +// ----------------------------------------------------------------------------- + +static const char* get_str(VALUE str) { + Check_Type(str, T_STRING); + return RSTRING_PTR(str); +} + +static VALUE rb_str_maybe_null(const char* s) { + if (s == NULL) { + s = ""; + } + return rb_str_new2(s); +} +static ID options_instancevar_interned; +// ----------------------------------------------------------------------------- +// DescriptorPool. +// ----------------------------------------------------------------------------- + +typedef struct { + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor. + upb_DefPool* symtab; +} DescriptorPool; + +VALUE cDescriptorPool = Qnil; + +// Global singleton DescriptorPool. The user is free to create others, but this +// is used by generated code. +VALUE generated_pool = Qnil; + +static void DescriptorPool_mark(void* _self) { + DescriptorPool* self = _self; + rb_gc_mark(self->def_to_descriptor); +} + +static void DescriptorPool_free(void* _self) { + DescriptorPool* self = _self; + upb_DefPool_Free(self->symtab); + xfree(self); +} + +static const rb_data_type_t DescriptorPool_type = { + "Google::Protobuf::DescriptorPool", + {DescriptorPool_mark, DescriptorPool_free, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static DescriptorPool* ruby_to_DescriptorPool(VALUE val) { + DescriptorPool* ret; + TypedData_Get_Struct(val, DescriptorPool, &DescriptorPool_type, ret); + return ret; +} + +// Exposed to other modules in defs.h. +const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb) { + DescriptorPool* pool = ruby_to_DescriptorPool(desc_pool_rb); + return pool->symtab; +} + +/* + * call-seq: + * DescriptorPool.new => pool + * + * Creates a new, empty, descriptor pool. + */ +static VALUE DescriptorPool_alloc(VALUE klass) { + DescriptorPool* self = ALLOC(DescriptorPool); + VALUE ret; + + self->def_to_descriptor = Qnil; + ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self); + + RB_OBJ_WRITE(ret, &self->def_to_descriptor, rb_hash_new()); + self->symtab = upb_DefPool_New(); + return ObjectCache_TryAdd(self->symtab, ret); +} + +/* + * call-seq: + * DescriptorPool.add_serialized_file(serialized_file_proto) + * + * Adds the given serialized FileDescriptorProto to the pool. + */ +VALUE DescriptorPool_add_serialized_file(VALUE _self, + VALUE serialized_file_proto) { + DescriptorPool* self = ruby_to_DescriptorPool(_self); + Check_Type(serialized_file_proto, T_STRING); + VALUE arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(arena_rb); + google_protobuf_FileDescriptorProto* file_proto = + google_protobuf_FileDescriptorProto_parse( + RSTRING_PTR(serialized_file_proto), + RSTRING_LEN(serialized_file_proto), arena); + if (!file_proto) { + rb_raise(rb_eArgError, "Unable to parse FileDescriptorProto"); + } + upb_Status status; + upb_Status_Clear(&status); + const upb_FileDef* filedef = + upb_DefPool_AddFile(self->symtab, file_proto, &status); + if (!filedef) { + rb_raise(cTypeError, "Unable to build file to DescriptorPool: %s", + upb_Status_ErrorMessage(&status)); + } + RB_GC_GUARD(arena_rb); + return get_filedef_obj(_self, filedef); +} + +/* + * call-seq: + * DescriptorPool.lookup(name) => descriptor + * + * Finds a Descriptor, EnumDescriptor or FieldDescriptor by name and returns it, + * or nil if none exists with the given name. + */ +static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) { + DescriptorPool* self = ruby_to_DescriptorPool(_self); + const char* name_str = get_str(name); + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const upb_FieldDef* fielddef; + const upb_ServiceDef* servicedef; + + msgdef = upb_DefPool_FindMessageByName(self->symtab, name_str); + if (msgdef) { + return get_msgdef_obj(_self, msgdef); + } + + fielddef = upb_DefPool_FindExtensionByName(self->symtab, name_str); + if (fielddef) { + return get_fielddef_obj(_self, fielddef); + } + + enumdef = upb_DefPool_FindEnumByName(self->symtab, name_str); + if (enumdef) { + return get_enumdef_obj(_self, enumdef); + } + + servicedef = upb_DefPool_FindServiceByName(self->symtab, name_str); + if (servicedef) { + return get_servicedef_obj(_self, servicedef); + } + + return Qnil; +} + +/* + * call-seq: + * DescriptorPool.generated_pool => descriptor_pool + * + * Class method that returns the global DescriptorPool. This is a singleton into + * which generated-code message and enum types are registered. The user may also + * register types in this pool for convenience so that they do not have to hold + * a reference to a private pool instance. + */ +static VALUE DescriptorPool_generated_pool(VALUE _self) { + return generated_pool; +} + +static void DescriptorPool_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "DescriptorPool", rb_cObject); + rb_define_alloc_func(klass, DescriptorPool_alloc); + rb_define_method(klass, "add_serialized_file", + DescriptorPool_add_serialized_file, 1); + rb_define_method(klass, "lookup", DescriptorPool_lookup, 1); + rb_define_singleton_method(klass, "generated_pool", + DescriptorPool_generated_pool, 0); + rb_gc_register_address(&cDescriptorPool); + cDescriptorPool = klass; + + rb_gc_register_address(&generated_pool); + generated_pool = rb_class_new_instance(0, NULL, klass); + options_instancevar_interned = rb_intern("options"); +} + +// ----------------------------------------------------------------------------- +// Descriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_MessageDef* msgdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE klass; + VALUE descriptor_pool; +} Descriptor; + +VALUE cDescriptor = Qnil; + +static void Descriptor_mark(void* _self) { + Descriptor* self = _self; + rb_gc_mark(self->klass); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t Descriptor_type = { + "Google::Protobuf::Descriptor", + {Descriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static Descriptor* ruby_to_Descriptor(VALUE val) { + Descriptor* ret; + TypedData_Get_Struct(val, Descriptor, &Descriptor_type, ret); + return ret; +} + +// Decode and return a frozen instance of a Descriptor Option for the given pool +static VALUE decode_options(VALUE self, const char* option_type, int size, + const char* bytes, VALUE descriptor_pool) { + VALUE options_rb = rb_ivar_get(self, options_instancevar_interned); + if (options_rb != Qnil) { + return options_rb; + } + + static const char* prefix = "google.protobuf."; + char fullname + [/*strlen(prefix)*/ 16 + + /*strln(longest option type supported e.g. "MessageOptions")*/ 14 + + /*null terminator*/ 1]; + + snprintf(fullname, sizeof(fullname), "%s%s", prefix, option_type); + const upb_MessageDef* msgdef = upb_DefPool_FindMessageByName( + ruby_to_DescriptorPool(descriptor_pool)->symtab, fullname); + if (!msgdef) { + rb_raise(rb_eRuntimeError, "Cannot find %s in DescriptorPool", option_type); + } + + VALUE desc_rb = get_msgdef_obj(descriptor_pool, msgdef); + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + + options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, false); + + // Strip features from the options proto to keep it internal. + const upb_MessageDef* decoded_desc = NULL; + upb_Message* options = Message_GetMutable(options_rb, &decoded_desc); + PBRUBY_ASSERT(options != NULL); + PBRUBY_ASSERT(decoded_desc == msgdef); + const upb_FieldDef* field = + upb_MessageDef_FindFieldByName(decoded_desc, "features"); + PBRUBY_ASSERT(field != NULL); + upb_Message_ClearFieldByDef(options, field); + + Message_freeze(options_rb); + + rb_ivar_set(self, options_instancevar_interned, options_rb); + return options_rb; +} + +/* + * call-seq: + * Descriptor.new => descriptor + * + * Creates a new, empty, message type descriptor. At a minimum, its name must be + * set before it is added to a pool. It cannot be used to create messages until + * it is added to a pool, after which it becomes immutable (as part of a + * finalization process). + */ +static VALUE Descriptor_alloc(VALUE klass) { + Descriptor* self = ALLOC(Descriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &Descriptor_type, self); + self->msgdef = NULL; + self->klass = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * Descriptor.new(c_only_cookie, ptr) => Descriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE Descriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + Descriptor* self = ruby_to_Descriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->msgdef = (const upb_MessageDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * Descriptor.file_descriptor + * + * Returns the FileDescriptor object this message belongs to. + */ +static VALUE Descriptor_file_descriptor(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_MessageDef_File(self->msgdef)); +} + +/* + * call-seq: + * Descriptor.name => name + * + * Returns the name of this message type as a fully-qualified string (e.g., + * My.Package.MessageType). + */ +static VALUE Descriptor_name(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + return rb_str_maybe_null(upb_MessageDef_FullName(self->msgdef)); +} + +/* + * call-seq: + * Descriptor.each(&block) + * + * Iterates over fields in this message type, yielding to the block on each one. + */ +static VALUE Descriptor_each(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + + int n = upb_MessageDef_FieldCount(self->msgdef); + for (int i = 0; i < n; i++) { + const upb_FieldDef* field = upb_MessageDef_Field(self->msgdef, i); + VALUE obj = get_fielddef_obj(self->descriptor_pool, field); + rb_yield(obj); + } + return Qnil; +} + +/* + * call-seq: + * Descriptor.lookup(name) => FieldDescriptor + * + * Returns the field descriptor for the field with the given name, if present, + * or nil if none. + */ +static VALUE Descriptor_lookup(VALUE _self, VALUE name) { + Descriptor* self = ruby_to_Descriptor(_self); + const char* s = get_str(name); + const upb_FieldDef* field = upb_MessageDef_FindFieldByName(self->msgdef, s); + if (field == NULL) { + return Qnil; + } + return get_fielddef_obj(self->descriptor_pool, field); +} + +/* + * call-seq: + * Descriptor.each_oneof(&block) => nil + * + * Invokes the given block for each oneof in this message type, passing the + * corresponding OneofDescriptor. + */ +static VALUE Descriptor_each_oneof(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + + int n = upb_MessageDef_OneofCount(self->msgdef); + for (int i = 0; i < n; i++) { + const upb_OneofDef* oneof = upb_MessageDef_Oneof(self->msgdef, i); + VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof); + rb_yield(obj); + } + return Qnil; +} + +/* + * call-seq: + * Descriptor.lookup_oneof(name) => OneofDescriptor + * + * Returns the oneof descriptor for the oneof with the given name, if present, + * or nil if none. + */ +static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) { + Descriptor* self = ruby_to_Descriptor(_self); + const char* s = get_str(name); + const upb_OneofDef* oneof = upb_MessageDef_FindOneofByName(self->msgdef, s); + if (oneof == NULL) { + return Qnil; + } + return get_oneofdef_obj(self->descriptor_pool, oneof); +} + +/* + * call-seq: + * Descriptor.msgclass => message_klass + * + * Returns the Ruby class created for this message type. + */ +static VALUE Descriptor_msgclass(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + if (self->klass == Qnil) { + RB_OBJ_WRITE(_self, &self->klass, build_class_from_descriptor(_self)); + } + return self->klass; +} + +/* + * call-seq: + * Descriptor.options => options + * + * Returns the `MessageOptions` for this `Descriptor`. + */ +static VALUE Descriptor_options(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + const google_protobuf_MessageOptions* opts = + upb_MessageDef_Options(self->msgdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_MessageOptions_serialize(opts, arena, &size); + VALUE message_options = decode_options(_self, "MessageOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return message_options; +} + +static void Descriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "Descriptor", rb_cObject); + rb_define_alloc_func(klass, Descriptor_alloc); + rb_define_method(klass, "initialize", Descriptor_initialize, 3); + rb_define_method(klass, "each", Descriptor_each, 0); + rb_define_method(klass, "lookup", Descriptor_lookup, 1); + rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0); + rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1); + rb_define_method(klass, "msgclass", Descriptor_msgclass, 0); + rb_define_method(klass, "name", Descriptor_name, 0); + rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0); + rb_define_method(klass, "options", Descriptor_options, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cDescriptor); + cDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// FileDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_FileDef* filedef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_FileDef. +} FileDescriptor; + +static VALUE cFileDescriptor = Qnil; + +static void FileDescriptor_mark(void* _self) { + FileDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t FileDescriptor_type = { + "Google::Protobuf::FileDescriptor", + {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static FileDescriptor* ruby_to_FileDescriptor(VALUE val) { + FileDescriptor* ret; + TypedData_Get_Struct(val, FileDescriptor, &FileDescriptor_type, ret); + return ret; +} + +static VALUE FileDescriptor_alloc(VALUE klass) { + FileDescriptor* self = ALLOC(FileDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &FileDescriptor_type, self); + self->descriptor_pool = Qnil; + self->filedef = NULL; + return ret; +} + +/* + * call-seq: + * FileDescriptor.new => file + * + * Returns a new file descriptor. May + * to a builder. + */ +static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->filedef = (const upb_FileDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * FileDescriptor.name => name + * + * Returns the name of the file. + */ +static VALUE FileDescriptor_name(VALUE _self) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + const char* name = upb_FileDef_Name(self->filedef); + return name == NULL ? Qnil : rb_str_new2(name); +} + +/* + * call-seq: + * FileDescriptor.options => options + * + * Returns the `FileOptions` for this `FileDescriptor`. + */ +static VALUE FileDescriptor_options(VALUE _self) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + const google_protobuf_FileOptions* opts = upb_FileDef_Options(self->filedef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_FileOptions_serialize(opts, arena, &size); + VALUE file_options = decode_options(_self, "FileOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return file_options; +} + +static void FileDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "FileDescriptor", rb_cObject); + rb_define_alloc_func(klass, FileDescriptor_alloc); + rb_define_method(klass, "initialize", FileDescriptor_initialize, 3); + rb_define_method(klass, "name", FileDescriptor_name, 0); + rb_define_method(klass, "options", FileDescriptor_options, 0); + rb_gc_register_address(&cFileDescriptor); + cFileDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// FieldDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_FieldDef* fielddef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_FieldDef. +} FieldDescriptor; + +static VALUE cFieldDescriptor = Qnil; + +static void FieldDescriptor_mark(void* _self) { + FieldDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t FieldDescriptor_type = { + "Google::Protobuf::FieldDescriptor", + {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) { + FieldDescriptor* ret; + TypedData_Get_Struct(val, FieldDescriptor, &FieldDescriptor_type, ret); + return ret; +} + +/* + * call-seq: + * FieldDescriptor.new => field + * + * Returns a new field descriptor. Its name, type, etc. must be set before it is + * added to a message type. + */ +static VALUE FieldDescriptor_alloc(VALUE klass) { + FieldDescriptor* self = ALLOC(FieldDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &FieldDescriptor_type, self); + self->fielddef = NULL; + return ret; +} + +/* + * call-seq: + * FieldDescriptor.new(c_only_cookie, pool, ptr) => FieldDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->fielddef = (const upb_FieldDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * FieldDescriptor.name => name + * + * Returns the name of this field. + */ +static VALUE FieldDescriptor_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return rb_str_maybe_null(upb_FieldDef_Name(self->fielddef)); +} + +// Non-static, exposed to other .c files. +upb_CType ruby_to_fieldtype(VALUE type) { + if (TYPE(type) != T_SYMBOL) { + rb_raise(rb_eArgError, "Expected symbol for field type."); + } + +#define CONVERT(upb, ruby) \ + if (SYM2ID(type) == rb_intern(#ruby)) { \ + return kUpb_CType_##upb; \ + } + + CONVERT(Float, float); + CONVERT(Double, double); + CONVERT(Bool, bool); + CONVERT(String, string); + CONVERT(Bytes, bytes); + CONVERT(Message, message); + CONVERT(Enum, enum); + CONVERT(Int32, int32); + CONVERT(Int64, int64); + CONVERT(UInt32, uint32); + CONVERT(UInt64, uint64); + +#undef CONVERT + + rb_raise(rb_eArgError, "Unknown field type."); + return 0; +} + +static VALUE descriptortype_to_ruby(upb_FieldType type) { + switch (type) { +#define CONVERT(upb, ruby) \ + case kUpb_FieldType_##upb: \ + return ID2SYM(rb_intern(#ruby)); + CONVERT(Float, float); + CONVERT(Double, double); + CONVERT(Bool, bool); + CONVERT(String, string); + CONVERT(Bytes, bytes); + CONVERT(Message, message); + CONVERT(Group, group); + CONVERT(Enum, enum); + CONVERT(Int32, int32); + CONVERT(Int64, int64); + CONVERT(UInt32, uint32); + CONVERT(UInt64, uint64); + CONVERT(SInt32, sint32); + CONVERT(SInt64, sint64); + CONVERT(Fixed32, fixed32); + CONVERT(Fixed64, fixed64); + CONVERT(SFixed32, sfixed32); + CONVERT(SFixed64, sfixed64); +#undef CONVERT + } + return Qnil; +} + +/* + * call-seq: + * FieldDescriptor.type => type + * + * Returns this field's type, as a Ruby symbol, or nil if not yet set. + * + * Valid field types are: + * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, + * :bytes, :message. + */ +static VALUE FieldDescriptor__type(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return descriptortype_to_ruby(upb_FieldDef_Type(self->fielddef)); +} + +/* + * call-seq: + * FieldDescriptor.default => default + * + * Returns this field's default, as a Ruby object, or nil if not yet set. + */ +static VALUE FieldDescriptor_default(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_FieldDef* f = self->fielddef; + upb_MessageValue default_val = upb_MessageValue_Zero(); + if (upb_FieldDef_IsSubMessage(f)) { + return Qnil; + } else if (!upb_FieldDef_IsRepeated(f)) { + default_val = upb_FieldDef_Default(f); + } + return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil); +} + +/* + * call-seq: + * FieldDescriptor.has_presence? => bool + * + * Returns whether this field tracks presence. + */ +static VALUE FieldDescriptor_has_presence(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_HasPresence(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * FieldDescriptor.is_packed? => bool + * + * Returns whether this is a repeated field that uses packed encoding. + */ +static VALUE FieldDescriptor_is_packed(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_IsPacked(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * FieldDescriptor.json_name => json_name + * + * Returns this field's json_name, as a Ruby string, or nil if not yet set. + */ +static VALUE FieldDescriptor_json_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_FieldDef* f = self->fielddef; + const char* json_name = upb_FieldDef_JsonName(f); + return rb_str_new2(json_name); +} + +/* + * call-seq: + * FieldDescriptor.label => label + * + * Returns this field's label (i.e., plurality), as a Ruby symbol. + * + * Valid field labels are: + * :optional, :repeated + */ +static VALUE FieldDescriptor_label(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_Label(self->fielddef)) { +#define CONVERT(upb, ruby) \ + case kUpb_Label_##upb: \ + return ID2SYM(rb_intern(#ruby)); + + CONVERT(Optional, optional); + CONVERT(Required, required); + CONVERT(Repeated, repeated); + +#undef CONVERT + } + + return Qnil; +} + +/* + * call-seq: + * FieldDescriptor.number => number + * + * Returns the tag number for this field. + */ +static VALUE FieldDescriptor_number(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return INT2NUM(upb_FieldDef_Number(self->fielddef)); +} + +/* + * call-seq: + * FieldDescriptor.submsg_name => submsg_name + * + * Returns the name of the message or enum type corresponding to this field, if + * it is a message or enum field (respectively), or nil otherwise. This type + * name will be resolved within the context of the pool to which the containing + * message type is added. + */ +static VALUE FieldDescriptor_submsg_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_CType(self->fielddef)) { + case kUpb_CType_Enum: + return rb_str_new2( + upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(self->fielddef))); + case kUpb_CType_Message: + return rb_str_new2( + upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(self->fielddef))); + default: + return Qnil; + } +} + +/* + * call-seq: + * FieldDescriptor.subtype => message_or_enum_descriptor + * + * Returns the message or enum descriptor corresponding to this field's type if + * it is a message or enum field, respectively, or nil otherwise. Cannot be + * called *until* the containing message type is added to a pool (and thus + * resolved). + */ +static VALUE FieldDescriptor_subtype(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_CType(self->fielddef)) { + case kUpb_CType_Enum: + return get_enumdef_obj(self->descriptor_pool, + upb_FieldDef_EnumSubDef(self->fielddef)); + case kUpb_CType_Message: + return get_msgdef_obj(self->descriptor_pool, + upb_FieldDef_MessageSubDef(self->fielddef)); + default: + return Qnil; + } +} + +/* + * call-seq: + * FieldDescriptor.get(message) => value + * + * Returns the value set for this field on the given message. Raises an + * exception if message is of the wrong type. + */ +static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + + Message_Get(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "get method called on wrong message type"); + } + + return Message_getfield(msg_rb, self->fielddef); +} + +/* + * call-seq: + * FieldDescriptor.has?(message) => boolean + * + * Returns whether the value is set on the given message. Raises an + * exception when calling for fields that do not have presence. + */ +static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + const upb_Message* msg = Message_Get(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "has method called on wrong message type"); + } else if (!upb_FieldDef_HasPresence(self->fielddef)) { + rb_raise(rb_eArgError, "does not track presence"); + } + + return upb_Message_HasFieldByDef(msg, self->fielddef) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * FieldDescriptor.clear(message) + * + * Clears the field from the message if it's set. + */ +static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + upb_Message* msg = Message_GetMutable(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "has method called on wrong message type"); + } + + upb_Message_ClearFieldByDef(msg, self->fielddef); + return Qnil; +} + +/* + * call-seq: + * FieldDescriptor.set(message, value) + * + * Sets the value corresponding to this field to the given value on the given + * message. Raises an exception if message is of the wrong type. Performs the + * ordinary type-checks for field setting. + */ +static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + upb_Message* msg = Message_GetMutable(msg_rb, &m); + upb_Arena* arena = Arena_get(Message_GetArena(msg_rb)); + upb_MessageValue msgval; + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "set method called on wrong message type"); + } + + msgval = Convert_RubyToUpb(value, upb_FieldDef_Name(self->fielddef), + TypeInfo_get(self->fielddef), arena); + upb_Message_SetFieldByDef(msg, self->fielddef, msgval, arena); + return Qnil; +} + +/* + * call-seq: + * FieldDescriptor.options => options + * + * Returns the `FieldOptions` for this `FieldDescriptor`. + */ +static VALUE FieldDescriptor_options(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const google_protobuf_FieldOptions* opts = + upb_FieldDef_Options(self->fielddef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, &size); + VALUE field_options = decode_options(_self, "FieldOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return field_options; +} + +static void FieldDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "FieldDescriptor", rb_cObject); + rb_define_alloc_func(klass, FieldDescriptor_alloc); + rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3); + rb_define_method(klass, "name", FieldDescriptor_name, 0); + rb_define_method(klass, "type", FieldDescriptor__type, 0); + rb_define_method(klass, "default", FieldDescriptor_default, 0); + rb_define_method(klass, "has_presence?", FieldDescriptor_has_presence, 0); + rb_define_method(klass, "is_packed?", FieldDescriptor_is_packed, 0); + rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0); + rb_define_method(klass, "label", FieldDescriptor_label, 0); + rb_define_method(klass, "number", FieldDescriptor_number, 0); + rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0); + rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0); + rb_define_method(klass, "has?", FieldDescriptor_has, 1); + rb_define_method(klass, "clear", FieldDescriptor_clear, 1); + rb_define_method(klass, "get", FieldDescriptor_get, 1); + rb_define_method(klass, "set", FieldDescriptor_set, 2); + rb_define_method(klass, "options", FieldDescriptor_options, 0); + rb_gc_register_address(&cFieldDescriptor); + cFieldDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// OneofDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_OneofDef* oneofdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_OneofDef. +} OneofDescriptor; + +static VALUE cOneofDescriptor = Qnil; + +static void OneofDescriptor_mark(void* _self) { + OneofDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t OneofDescriptor_type = { + "Google::Protobuf::OneofDescriptor", + {OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) { + OneofDescriptor* ret; + TypedData_Get_Struct(val, OneofDescriptor, &OneofDescriptor_type, ret); + return ret; +} + +/* + * call-seq: + * OneofDescriptor.new => oneof_descriptor + * + * Creates a new, empty, oneof descriptor. The oneof may only be modified prior + * to being added to a message descriptor which is subsequently added to a pool. + */ +static VALUE OneofDescriptor_alloc(VALUE klass) { + OneofDescriptor* self = ALLOC(OneofDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &OneofDescriptor_type, self); + self->oneofdef = NULL; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->oneofdef = (const upb_OneofDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * OneofDescriptor.name => name + * + * Returns the name of this oneof. + */ +static VALUE OneofDescriptor_name(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + return rb_str_maybe_null(upb_OneofDef_Name(self->oneofdef)); +} + +/* + * call-seq: + * OneofDescriptor.each(&block) => nil + * + * Iterates through fields in this oneof, yielding to the block on each one. + */ +static VALUE OneofDescriptor_each(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + + int n = upb_OneofDef_FieldCount(self->oneofdef); + for (int i = 0; i < n; i++) { + const upb_FieldDef* f = upb_OneofDef_Field(self->oneofdef, i); + VALUE obj = get_fielddef_obj(self->descriptor_pool, f); + rb_yield(obj); + } + return Qnil; +} + +/* + * call-seq: + * OneofDescriptor.options => options + * + * Returns the `OneofOptions` for this `OneofDescriptor`. + */ +static VALUE OneOfDescriptor_options(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + const google_protobuf_OneofOptions* opts = + upb_OneofDef_Options(self->oneofdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_OneofOptions_serialize(opts, arena, &size); + VALUE oneof_options = decode_options(_self, "OneofOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return oneof_options; +} + +static void OneofDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "OneofDescriptor", rb_cObject); + rb_define_alloc_func(klass, OneofDescriptor_alloc); + rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3); + rb_define_method(klass, "name", OneofDescriptor_name, 0); + rb_define_method(klass, "each", OneofDescriptor_each, 0); + rb_define_method(klass, "options", OneOfDescriptor_options, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cOneofDescriptor); + cOneofDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// EnumDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_EnumDef* enumdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_EnumDef. +} EnumDescriptor; + +static VALUE cEnumDescriptor = Qnil; + +static void EnumDescriptor_mark(void* _self) { + EnumDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t EnumDescriptor_type = { + "Google::Protobuf::EnumDescriptor", + {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) { + EnumDescriptor* ret; + TypedData_Get_Struct(val, EnumDescriptor, &EnumDescriptor_type, ret); + return ret; +} + +static VALUE EnumDescriptor_alloc(VALUE klass) { + EnumDescriptor* self = ALLOC(EnumDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &EnumDescriptor_type, self); + self->enumdef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +// Exposed to other modules in defs.h. +const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) { + EnumDescriptor* desc = ruby_to_EnumDescriptor(enum_desc_rb); + return desc->enumdef; +} + +/* + * call-seq: + * EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->enumdef = (const upb_EnumDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * EnumDescriptor.file_descriptor + * + * Returns the FileDescriptor object this enum belongs to. + */ +static VALUE EnumDescriptor_file_descriptor(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_EnumDef_File(self->enumdef)); +} + +/* + * call-seq: + * EnumDescriptor.is_closed? => bool + * + * Returns whether this enum is open or closed. + */ +static VALUE EnumDescriptor_is_closed(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return upb_EnumDef_IsClosed(self->enumdef) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * EnumDescriptor.name => name + * + * Returns the name of this enum type. + */ +static VALUE EnumDescriptor_name(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return rb_str_maybe_null(upb_EnumDef_FullName(self->enumdef)); +} + +/* + * call-seq: + * EnumDescriptor.lookup_name(name) => value + * + * Returns the numeric value corresponding to the given key name (as a Ruby + * symbol), or nil if none. + */ +static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + const char* name_str = rb_id2name(SYM2ID(name)); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByName(self->enumdef, name_str); + if (ev) { + return INT2NUM(upb_EnumValueDef_Number(ev)); + } else { + return Qnil; + } +} + +/* + * call-seq: + * EnumDescriptor.lookup_value(name) => value + * + * Returns the key name (as a Ruby symbol) corresponding to the integer value, + * or nil if none. + */ +static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + int32_t val = NUM2INT(number); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNumber(self->enumdef, val); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return Qnil; + } +} + +/* + * call-seq: + * EnumDescriptor.each(&block) + * + * Iterates over key => value mappings in this enum's definition, yielding to + * the block with (key, value) arguments for each one. + */ +static VALUE EnumDescriptor_each(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + + int n = upb_EnumDef_ValueCount(self->enumdef); + for (int i = 0; i < n; i++) { + const upb_EnumValueDef* ev = upb_EnumDef_Value(self->enumdef, i); + VALUE key = ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + VALUE number = INT2NUM(upb_EnumValueDef_Number(ev)); + rb_yield_values(2, key, number); + } + + return Qnil; +} + +/* + * call-seq: + * EnumDescriptor.enummodule => module + * + * Returns the Ruby module corresponding to this enum type. + */ +static VALUE EnumDescriptor_enummodule(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + if (self->module == Qnil) { + RB_OBJ_WRITE(_self, &self->module, build_module_from_enumdesc(_self)); + } + return self->module; +} + +/* + * call-seq: + * EnumDescriptor.options => options + * + * Returns the `EnumOptions` for this `EnumDescriptor`. + */ +static VALUE EnumDescriptor_options(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + const google_protobuf_EnumOptions* opts = upb_EnumDef_Options(self->enumdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_EnumOptions_serialize(opts, arena, &size); + VALUE enum_options = decode_options(_self, "EnumOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return enum_options; +} + +static void EnumDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "EnumDescriptor", rb_cObject); + rb_define_alloc_func(klass, EnumDescriptor_alloc); + rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3); + rb_define_method(klass, "name", EnumDescriptor_name, 0); + rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1); + rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1); + rb_define_method(klass, "each", EnumDescriptor_each, 0); + rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0); + rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0); + rb_define_method(klass, "is_closed?", EnumDescriptor_is_closed, 0); + rb_define_method(klass, "options", EnumDescriptor_options, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cEnumDescriptor); + cEnumDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// ServiceDescriptor +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_ServiceDef* servicedef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_ServiceDef. +} ServiceDescriptor; + +static VALUE cServiceDescriptor = Qnil; + +static void ServiceDescriptor_mark(void* _self) { + ServiceDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t ServiceDescriptor_type = { + "Google::Protobuf::ServicDescriptor", + {ServiceDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static ServiceDescriptor* ruby_to_ServiceDescriptor(VALUE val) { + ServiceDescriptor* ret; + TypedData_Get_Struct(val, ServiceDescriptor, &ServiceDescriptor_type, ret); + return ret; +} + +static VALUE ServiceDescriptor_alloc(VALUE klass) { + ServiceDescriptor* self = ALLOC(ServiceDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &ServiceDescriptor_type, self); + self->servicedef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * ServiceDescriptor.new(c_only_cookie, ptr) => ServiceDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE ServiceDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->servicedef = (const upb_ServiceDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * ServiceDescriptor.name => name + * + * Returns the name of this service. + */ +static VALUE ServiceDescriptor_name(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + return rb_str_maybe_null(upb_ServiceDef_FullName(self->servicedef)); +} + +/* + * call-seq: + * ServiceDescriptor.file_descriptor + * + * Returns the FileDescriptor object this service belongs to. + */ +static VALUE ServiceDescriptor_file_descriptor(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_ServiceDef_File(self->servicedef)); +} + +/* + * call-seq: + * ServiceDescriptor.each(&block) + * + * Iterates over methods in this service, yielding to the block on each one. + */ +static VALUE ServiceDescriptor_each(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + + int n = upb_ServiceDef_MethodCount(self->servicedef); + for (int i = 0; i < n; i++) { + const upb_MethodDef* method = upb_ServiceDef_Method(self->servicedef, i); + VALUE obj = get_methoddef_obj(self->descriptor_pool, method); + rb_yield(obj); + } + return Qnil; +} + +/* + * call-seq: + * ServiceDescriptor.options => options + * + * Returns the `ServiceOptions` for this `ServiceDescriptor`. + */ +static VALUE ServiceDescriptor_options(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + const google_protobuf_ServiceOptions* opts = + upb_ServiceDef_Options(self->servicedef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_ServiceOptions_serialize(opts, arena, &size); + VALUE service_options = decode_options(_self, "ServiceOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return service_options; +} + +static void ServiceDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "ServiceDescriptor", rb_cObject); + rb_define_alloc_func(klass, ServiceDescriptor_alloc); + rb_define_method(klass, "initialize", ServiceDescriptor_initialize, 3); + rb_define_method(klass, "name", ServiceDescriptor_name, 0); + rb_define_method(klass, "each", ServiceDescriptor_each, 0); + rb_define_method(klass, "file_descriptor", ServiceDescriptor_file_descriptor, + 0); + rb_define_method(klass, "options", ServiceDescriptor_options, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cServiceDescriptor); + cServiceDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// MethodDescriptor +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_MethodDef* methoddef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_MethodDef. +} MethodDescriptor; + +static VALUE cMethodDescriptor = Qnil; + +static void MethodDescriptor_mark(void* _self) { + MethodDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t MethodDescriptor_type = { + "Google::Protobuf::MethodDescriptor", + {MethodDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static MethodDescriptor* ruby_to_MethodDescriptor(VALUE val) { + MethodDescriptor* ret; + TypedData_Get_Struct(val, MethodDescriptor, &MethodDescriptor_type, ret); + return ret; +} + +static VALUE MethodDescriptor_alloc(VALUE klass) { + MethodDescriptor* self = ALLOC(MethodDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &MethodDescriptor_type, self); + self->methoddef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * MethodDescriptor.new(c_only_cookie, ptr) => MethodDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE MethodDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->methoddef = (const upb_MethodDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * call-seq: + * MethodDescriptor.name => name + * + * Returns the name of this method + */ +static VALUE MethodDescriptor_name(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return rb_str_maybe_null(upb_MethodDef_Name(self->methoddef)); +} + +/* + * call-seq: + * MethodDescriptor.options => options + * + * Returns the `MethodOptions` for this `MethodDescriptor`. + */ +static VALUE MethodDescriptor_options(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const google_protobuf_MethodOptions* opts = + upb_MethodDef_Options(self->methoddef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_MethodOptions_serialize(opts, arena, &size); + VALUE method_options = decode_options(_self, "MethodOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return method_options; +} + +/* + * call-seq: + * MethodDescriptor.input_type => Descriptor + * + * Returns the `Descriptor` for the request message type of this method + */ +static VALUE MethodDescriptor_input_type(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const upb_MessageDef* type = upb_MethodDef_InputType(self->methoddef); + return get_msgdef_obj(self->descriptor_pool, type); +} + +/* + * call-seq: + * MethodDescriptor.output_type => Descriptor + * + * Returns the `Descriptor` for the response message type of this method + */ +static VALUE MethodDescriptor_output_type(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const upb_MessageDef* type = upb_MethodDef_OutputType(self->methoddef); + return get_msgdef_obj(self->descriptor_pool, type); +} + +/* + * call-seq: + * MethodDescriptor.client_streaming => bool + * + * Returns whether or not this is a streaming request method + */ +static VALUE MethodDescriptor_client_streaming(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return upb_MethodDef_ClientStreaming(self->methoddef) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * MethodDescriptor.server_streaming => bool + * + * Returns whether or not this is a streaming response method + */ +static VALUE MethodDescriptor_server_streaming(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return upb_MethodDef_ServerStreaming(self->methoddef) ? Qtrue : Qfalse; +} + +static void MethodDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "MethodDescriptor", rb_cObject); + rb_define_alloc_func(klass, MethodDescriptor_alloc); + rb_define_method(klass, "initialize", MethodDescriptor_initialize, 3); + rb_define_method(klass, "name", MethodDescriptor_name, 0); + rb_define_method(klass, "options", MethodDescriptor_options, 0); + rb_define_method(klass, "input_type", MethodDescriptor_input_type, 0); + rb_define_method(klass, "output_type", MethodDescriptor_output_type, 0); + rb_define_method(klass, "client_streaming", MethodDescriptor_client_streaming, + 0); + rb_define_method(klass, "server_streaming", MethodDescriptor_server_streaming, + 0); + rb_gc_register_address(&cMethodDescriptor); + cMethodDescriptor = klass; +} + +static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) { + DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool); + VALUE key = ULL2NUM((intptr_t)ptr); + VALUE def; + + def = rb_hash_aref(descriptor_pool->def_to_descriptor, key); + + if (ptr == NULL) { + return Qnil; + } + + if (def == Qnil) { + // Lazily create wrapper object. + VALUE args[3] = {c_only_cookie, _descriptor_pool, key}; + def = rb_class_new_instance(3, args, klass); + rb_hash_aset(descriptor_pool->def_to_descriptor, key, def); + } + + return def; +} + +static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def) { + return get_def_obj(descriptor_pool, def, cDescriptor); +} + +static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def) { + return get_def_obj(descriptor_pool, def, cEnumDescriptor); +} + +static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def) { + return get_def_obj(descriptor_pool, def, cFieldDescriptor); +} + +static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def) { + return get_def_obj(descriptor_pool, def, cFileDescriptor); +} + +static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def) { + return get_def_obj(descriptor_pool, def, cOneofDescriptor); +} + +static VALUE get_servicedef_obj(VALUE descriptor_pool, + const upb_ServiceDef* def) { + return get_def_obj(descriptor_pool, def, cServiceDescriptor); +} + +static VALUE get_methoddef_obj(VALUE descriptor_pool, + const upb_MethodDef* def) { + return get_def_obj(descriptor_pool, def, cMethodDescriptor); +} + +// ----------------------------------------------------------------------------- +// Shared functions +// ----------------------------------------------------------------------------- + +// Functions exposed to other modules in defs.h. + +VALUE Descriptor_DefToClass(const upb_MessageDef* m) { + const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m)); + VALUE pool = ObjectCache_Get(symtab); + PBRUBY_ASSERT(pool != Qnil); + VALUE desc_rb = get_msgdef_obj(pool, m); + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + return desc->klass; +} + +const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb) { + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + return desc->msgdef; +} + +VALUE TypeInfo_InitArg(int argc, VALUE* argv, int skip_arg) { + if (argc > skip_arg) { + if (argc > 1 + skip_arg) { + rb_raise(rb_eArgError, "Expected a maximum of %d arguments.", + skip_arg + 1); + } + return argv[skip_arg]; + } else { + return Qnil; + } +} + +TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg, + VALUE* type_class, VALUE* init_arg) { + TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])}; + + if (ret.type == kUpb_CType_Message || ret.type == kUpb_CType_Enum) { + *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2); + + if (argc < 2 + skip_arg) { + rb_raise(rb_eArgError, "Expected at least %d arguments for message/enum.", + 2 + skip_arg); + } + + VALUE klass = argv[1 + skip_arg]; + VALUE desc = MessageOrEnum_GetDescriptor(klass); + *type_class = klass; + + if (desc == Qnil) { + rb_raise(rb_eArgError, + "Type class has no descriptor. Please pass a " + "class or enum as returned by the DescriptorPool."); + } + + if (ret.type == kUpb_CType_Message) { + ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef; + Message_CheckClass(klass); + } else { + PBRUBY_ASSERT(ret.type == kUpb_CType_Enum); + ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef; + } + } else { + *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 1); + } + + return ret; +} + +void Defs_register(VALUE module) { + DescriptorPool_register(module); + Descriptor_register(module); + FileDescriptor_register(module); + FieldDescriptor_register(module); + OneofDescriptor_register(module); + EnumDescriptor_register(module); + ServiceDescriptor_register(module); + MethodDescriptor_register(module); + + rb_gc_register_address(&c_only_cookie); + c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject); +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.h new file mode 100755 index 00000000..931dd6ed --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/defs.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_DEFS_H_ +#define RUBY_PROTOBUF_DEFS_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// ----------------------------------------------------------------------------- +// TypeInfo +// ----------------------------------------------------------------------------- + +// This bundles a upb_CType and msgdef/enumdef when appropriate. This is +// convenient for functions that need type information but cannot necessarily +// assume a upb_FieldDef will be available. +// +// For example, Google::Protobuf::Map and Google::Protobuf::RepeatedField can +// be constructed with type information alone: +// +// # RepeatedField will internally store the type information in a TypeInfo. +// Google::Protobuf::RepeatedField.new(:message, FooMessage) + +typedef struct { + upb_CType type; + union { + const upb_MessageDef* msgdef; // When type == kUpb_CType_Message + const upb_EnumDef* enumdef; // When type == kUpb_CType_Enum + } def; +} TypeInfo; + +static inline TypeInfo TypeInfo_get(const upb_FieldDef* f) { + TypeInfo ret = {upb_FieldDef_CType(f), {NULL}}; + switch (ret.type) { + case kUpb_CType_Message: + ret.def.msgdef = upb_FieldDef_MessageSubDef(f); + break; + case kUpb_CType_Enum: + ret.def.enumdef = upb_FieldDef_EnumSubDef(f); + break; + default: + break; + } + return ret; +} + +TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg, + VALUE* type_class, VALUE* init_arg); + +static inline TypeInfo TypeInfo_from_type(upb_CType type) { + TypeInfo ret = {type}; + assert(type != kUpb_CType_Message && type != kUpb_CType_Enum); + return ret; +} + +// ----------------------------------------------------------------------------- +// Other utilities +// ----------------------------------------------------------------------------- + +VALUE Descriptor_DefToClass(const upb_MessageDef* m); + +// Returns the underlying msgdef, enumdef, or symtab (respectively) for the +// given Descriptor, EnumDescriptor, or DescriptorPool Ruby object. +const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb); +const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb); +const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb); + +// Returns a upb field type for the given Ruby symbol +// (eg. :float => kUpb_CType_Float). +upb_CType ruby_to_fieldtype(VALUE type); + +// The singleton generated pool (a DescriptorPool object). +extern VALUE generated_pool; + +// Call at startup to register all types in this module. +void Defs_register(VALUE module); + +#endif // RUBY_PROTOBUF_DEFS_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/extconf.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/extconf.rb new file mode 100755 index 00000000..ed812c95 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/extconf.rb @@ -0,0 +1,28 @@ +#!/usr/bin/ruby + +require 'mkmf' + +ext_name = "google/protobuf_c" + +dir_config(ext_name) + +if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/ + $CFLAGS += " -std=gnu99 -O3 -DNDEBUG -fvisibility=hidden -Wall -Wsign-compare -Wno-declaration-after-statement" +else + $CFLAGS += " -std=gnu99 -O3 -DNDEBUG" +end + +if RUBY_PLATFORM =~ /linux/ + # Instruct the linker to point memcpy calls at our __wrap_memcpy wrapper. + $LDFLAGS += " -Wl,-wrap,memcpy" +end + +$VPATH << "$(srcdir)/third_party/utf8_range" +$INCFLAGS += " -I$(srcdir)/third_party/utf8_range" + +$srcs = ["protobuf.c", "convert.c", "defs.c", "message.c", + "repeated_field.c", "map.c", "ruby-upb.c", "wrap_memcpy.c", + "utf8_range.c", "shared_convert.c", + "shared_message.c"] + +create_makefile(ext_name) diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/glue.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/glue.c new file mode 100755 index 00000000..3c84d7fb --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/glue.c @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Exposing inlined UPB functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "ruby-upb.h" + +upb_Arena* Arena_create() { return upb_Arena_Init(NULL, 0, &upb_alloc_global); } + +google_protobuf_FileDescriptorProto* FileDescriptorProto_parse( + const char* serialized_file_proto, size_t length, upb_Arena* arena) { + return google_protobuf_FileDescriptorProto_parse(serialized_file_proto, + length, arena); +} + +char* EnumDescriptor_serialized_options(const upb_EnumDef* enumdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_EnumOptions* opts = upb_EnumDef_Options(enumdef); + char* serialized = google_protobuf_EnumOptions_serialize(opts, arena, size); + return serialized; +} + +char* FileDescriptor_serialized_options(const upb_FileDef* filedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FileOptions* opts = upb_FileDef_Options(filedef); + char* serialized = google_protobuf_FileOptions_serialize(opts, arena, size); + return serialized; +} + +char* Descriptor_serialized_options(const upb_MessageDef* msgdef, size_t* size, + upb_Arena* arena) { + const google_protobuf_MessageOptions* opts = upb_MessageDef_Options(msgdef); + char* serialized = + google_protobuf_MessageOptions_serialize(opts, arena, size); + return serialized; +} + +char* OneOfDescriptor_serialized_options(const upb_OneofDef* oneofdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_OneofOptions* opts = upb_OneofDef_Options(oneofdef); + char* serialized = google_protobuf_OneofOptions_serialize(opts, arena, size); + return serialized; +} + +char* FieldDescriptor_serialized_options(const upb_FieldDef* fielddef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FieldOptions* opts = upb_FieldDef_Options(fielddef); + char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, size); + return serialized; +} + +char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_ServiceOptions* opts = + upb_ServiceDef_Options(servicedef); + char* serialized = + google_protobuf_ServiceOptions_serialize(opts, arena, size); + return serialized; +} + +char* MethodDescriptor_serialized_options(const upb_MethodDef* methoddef, + size_t* size, upb_Arena* arena) { + const google_protobuf_MethodOptions* opts = upb_MethodDef_Options(methoddef); + char* serialized = google_protobuf_MethodOptions_serialize(opts, arena, size); + return serialized; +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.c new file mode 100755 index 00000000..0b30c732 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.c @@ -0,0 +1,731 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "convert.h" +#include "defs.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Basic map operations on top of upb_Map. +// +// Note that we roll our own `Map` container here because, as for +// `RepeatedField`, we want a strongly-typed container. This is so that any user +// errors due to incorrect map key or value types are raised as close as +// possible to the error site, rather than at some deferred point (e.g., +// serialization). +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Map container type. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_Map* map; // Can convert to mutable when non-frozen. + upb_CType key_type; + TypeInfo value_type_info; + VALUE value_type_class; + VALUE arena; +} Map; + +static void Map_mark(void* _self) { + Map* self = _self; + rb_gc_mark(self->value_type_class); + rb_gc_mark(self->arena); +} + +static size_t Map_memsize(const void* _self) { return sizeof(Map); } + +const rb_data_type_t Map_type = { + "Google::Protobuf::Map", + {Map_mark, RUBY_DEFAULT_FREE, Map_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +VALUE cMap; + +static Map* ruby_to_Map(VALUE _self) { + Map* self; + TypedData_Get_Struct(_self, Map, &Map_type, self); + return self; +} + +static VALUE Map_alloc(VALUE klass) { + Map* self = ALLOC(Map); + self->map = NULL; + self->value_type_class = Qnil; + self->value_type_info.def.msgdef = NULL; + self->arena = Qnil; + return TypedData_Wrap_Struct(klass, &Map_type, self); +} + +VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type, + TypeInfo value_type, VALUE arena) { + PBRUBY_ASSERT(map); + PBRUBY_ASSERT(arena != Qnil); + + VALUE val = ObjectCache_Get(map); + + if (val == Qnil) { + val = Map_alloc(cMap); + Map* self; + TypedData_Get_Struct(val, Map, &Map_type, self); + self->map = map; + self->arena = arena; + self->key_type = key_type; + self->value_type_info = value_type; + if (self->value_type_info.type == kUpb_CType_Message) { + const upb_MessageDef* val_m = self->value_type_info.def.msgdef; + self->value_type_class = Descriptor_DefToClass(val_m); + } + return ObjectCache_TryAdd(map, val); + } + return val; +} + +static VALUE Map_new_this_type(Map* from) { + VALUE arena_rb = Arena_new(); + upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type, + from->value_type_info.type); + VALUE ret = + Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb); + PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class); + return ret; +} + +static TypeInfo Map_keyinfo(Map* self) { + TypeInfo ret; + ret.type = self->key_type; + ret.def.msgdef = NULL; + return ret; +} + +static upb_Map* Map_GetMutable(VALUE _self) { + const upb_Map* map = ruby_to_Map(_self)->map; + Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map)); + return (upb_Map*)map; +} + +VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type, + TypeInfo val_info) { + VALUE hash = rb_hash_new(); + TypeInfo key_info = TypeInfo_from_type(key_type); + + if (!map) return hash; + + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil); + VALUE val_val = Scalar_CreateHash(val, val_info); + rb_hash_aset(hash, key_val, val_val); + } + + return hash; +} + +VALUE Map_deep_copy(VALUE obj) { + Map* self = ruby_to_Map(obj); + VALUE new_arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(new_arena_rb); + upb_Map* new_map = + upb_Map_New(arena, self->key_type, self->value_type_info.type); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_MessageValue val_copy = + Msgval_DeepCopy(val, self->value_type_info, arena); + upb_Map_Set(new_map, key, val_copy, arena); + } + + return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info, + new_arena_rb); +} + +const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field, + upb_Arena* arena) { + const upb_FieldDef* key_field = map_field_key(field); + const upb_FieldDef* value_field = map_field_value(field); + TypeInfo value_type_info = TypeInfo_get(value_field); + Map* self; + + if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || + RTYPEDDATA_TYPE(val) != &Map_type) { + rb_raise(cTypeError, "Expected Map instance"); + } + + self = ruby_to_Map(val); + if (self->key_type != upb_FieldDef_CType(key_field)) { + rb_raise(cTypeError, "Map key type does not match field's key type"); + } + if (self->value_type_info.type != value_type_info.type) { + rb_raise(cTypeError, "Map value type does not match field's value type"); + } + if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) { + rb_raise(cTypeError, "Map value type has wrong message/enum class"); + } + + Arena_fuse(self->arena, arena); + return self->map; +} + +void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type, + TypeInfo val_type) { + bool first = true; + TypeInfo key_type_info = {key_type}; + StringBuilder_Printf(b, "{"); + if (map) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + if (first) { + first = false; + } else { + StringBuilder_Printf(b, ", "); + } + StringBuilder_PrintMsgval(b, key, key_type_info); + StringBuilder_Printf(b, "=>"); + StringBuilder_PrintMsgval(b, val, val_type); + } + } + StringBuilder_Printf(b, "}"); +} + +static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) { + Map* self = ruby_to_Map(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue key_val = + Convert_RubyToUpb(key, "", Map_keyinfo(self), arena); + upb_MessageValue val_val = + Convert_RubyToUpb(val, "", self->value_type_info, arena); + upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena); + return ST_CONTINUE; +} + +// Used only internally -- shared by #merge and #initialize. +static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { + if (TYPE(hashmap) == T_HASH) { + rb_hash_foreach(hashmap, merge_into_self_callback, _self); + } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) && + RTYPEDDATA_TYPE(hashmap) == &Map_type) { + Map* self = ruby_to_Map(_self); + Map* other = ruby_to_Map(hashmap); + upb_Arena* arena = Arena_get(self->arena); + upb_Map* self_map = Map_GetMutable(_self); + + Arena_fuse(other->arena, arena); + + if (self->key_type != other->key_type || + self->value_type_info.type != other->value_type_info.type || + self->value_type_class != other->value_type_class) { + rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); + } + + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(other->map, &key, &val, &iter)) { + upb_Map_Set(self_map, key, val, arena); + } + } else { + rb_raise(rb_eArgError, "Unknown type merging into Map"); + } + return _self; +} + +/* + * call-seq: + * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + * => new map + * + * Allocates a new Map container. This constructor may be called with 2, 3, or 4 + * arguments. The first two arguments are always present and are symbols (taking + * on the same values as field-type symbols in message descriptors) that + * indicate the type of the map key and value fields. + * + * The supported key types are: :int32, :int64, :uint32, :uint64, :bool, + * :string, :bytes. + * + * The supported value types are: :int32, :int64, :uint32, :uint64, :bool, + * :string, :bytes, :enum, :message. + * + * The third argument, value_typeclass, must be present if value_type is :enum + * or :message. As in RepeatedField#new, this argument must be a message class + * (for :message) or enum module (for :enum). + * + * The last argument, if present, provides initial content for map. Note that + * this may be an ordinary Ruby hashmap or another Map instance with identical + * key and value types. Also note that this argument may be present whether or + * not value_typeclass is present (and it is unambiguously separate from + * value_typeclass because value_typeclass's presence is strictly determined by + * value_type). The contents of this initial hashmap or Map instance are + * shallow-copied into the new Map: the original map is unmodified, but + * references to underlying objects will be shared if the value type is a + * message type. + */ +static VALUE Map_init(int argc, VALUE* argv, VALUE _self) { + Map* self = ruby_to_Map(_self); + VALUE init_arg; + + // We take either two args (:key_type, :value_type), three args (:key_type, + // :value_type, "ValueMessageType"), or four args (the above plus an initial + // hashmap). + if (argc < 2 || argc > 4) { + rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments."); + } + + self->key_type = ruby_to_fieldtype(argv[0]); + self->value_type_info = + TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg); + self->arena = Arena_new(); + + // Check that the key type is an allowed type. + switch (self->key_type) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Bool: + case kUpb_CType_String: + case kUpb_CType_Bytes: + // These are OK. + break; + default: + rb_raise(rb_eArgError, "Invalid key type for map."); + } + + self->map = upb_Map_New(Arena_get(self->arena), self->key_type, + self->value_type_info.type); + VALUE stored = ObjectCache_TryAdd(self->map, _self); + (void)stored; + PBRUBY_ASSERT(stored == _self); + + if (init_arg != Qnil) { + Map_merge_into_self(_self, init_arg); + } + + return Qnil; +} + +/* + * call-seq: + * Map.each(&block) + * + * Invokes &block on each |key, value| pair in the map, in unspecified order. + * Note that Map also includes Enumerable; map thus acts like a normal Ruby + * sequence. + */ +static VALUE Map_each(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); + VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); + rb_yield_values(2, key_val, val_val); + } + + return Qnil; +} + +/* + * call-seq: + * Map.keys => [list_of_keys] + * + * Returns the list of keys contained in the map, in unspecified order. + */ +static VALUE Map_keys(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + VALUE ret = rb_ary_new(); + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); + rb_ary_push(ret, key_val); + } + + return ret; +} + +/* + * call-seq: + * Map.values => [list_of_values] + * + * Returns the list of values contained in the map, in unspecified order. + */ +static VALUE Map_values(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + VALUE ret = rb_ary_new(); + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); + rb_ary_push(ret, val_val); + } + + return ret; +} + +/* + * call-seq: + * Map.[](key) => value + * + * Accesses the element at the given key. Throws an exception if the key type is + * incorrect. Returns nil when the key is not present in the map. + */ +static VALUE Map_index(VALUE _self, VALUE key) { + Map* self = ruby_to_Map(_self); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val; + + if (upb_Map_Get(self->map, key_upb, &val)) { + return Convert_UpbToRuby(val, self->value_type_info, self->arena); + } else { + return Qnil; + } +} + +/* + * call-seq: + * Map.[]=(key, value) => value + * + * Inserts or overwrites the value at the given key with the given new value. + * Throws an exception if the key type is incorrect. Returns the new value that + * was just inserted. + */ +static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) { + Map* self = ruby_to_Map(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val_upb = + Convert_RubyToUpb(val, "", self->value_type_info, arena); + + upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena); + + return val; +} + +/* + * call-seq: + * Map.has_key?(key) => bool + * + * Returns true if the given key is present in the map. Throws an exception if + * the key has the wrong type. + */ +static VALUE Map_has_key(VALUE _self, VALUE key) { + Map* self = ruby_to_Map(_self); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + + if (upb_Map_Get(self->map, key_upb, NULL)) { + return Qtrue; + } else { + return Qfalse; + } +} + +/* + * call-seq: + * Map.delete(key) => old_value + * + * Deletes the value at the given key, if any, returning either the old value or + * nil if none was present. Throws an exception if the key is of the wrong type. + */ +static VALUE Map_delete(VALUE _self, VALUE key) { + upb_Map* map = Map_GetMutable(_self); + Map* self = ruby_to_Map(_self); + + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val_upb; + + if (upb_Map_Delete(map, key_upb, &val_upb)) { + return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena); + } else { + return Qnil; + } +} + +/* + * call-seq: + * Map.clear + * + * Removes all entries from the map. + */ +static VALUE Map_clear(VALUE _self) { + upb_Map_Clear(Map_GetMutable(_self)); + return Qnil; +} + +/* + * call-seq: + * Map.length + * + * Returns the number of entries (key-value pairs) in the map. + */ +static VALUE Map_length(VALUE _self) { + Map* self = ruby_to_Map(_self); + return ULL2NUM(upb_Map_Size(self->map)); +} + +/* + * call-seq: + * Map.dup => new_map + * + * Duplicates this map with a shallow copy. References to all non-primitive + * element objects (e.g., submessages) are shared. + */ +static VALUE Map_dup(VALUE _self) { + Map* self = ruby_to_Map(_self); + VALUE new_map_rb = Map_new_this_type(self); + Map* new_self = ruby_to_Map(new_map_rb); + size_t iter = kUpb_Map_Begin; + upb_Arena* arena = Arena_get(new_self->arena); + upb_Map* new_map = Map_GetMutable(new_map_rb); + + Arena_fuse(self->arena, arena); + + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_Map_Set(new_map, key, val, arena); + } + + return new_map_rb; +} + +/* + * call-seq: + * Map.==(other) => boolean + * + * Compares this map to another. Maps are equal if they have identical key sets, + * and for each key, the values in both maps compare equal. Elements are + * compared as per normal Ruby semantics, by calling their :== methods (or + * performing a more efficient comparison for primitive types). + * + * Maps with dissimilar key types or value types/typeclasses are never equal, + * even if value comparison (for example, between integers and floats) would + * have otherwise indicated that every element has equal value. + */ +VALUE Map_eq(VALUE _self, VALUE _other) { + Map* self = ruby_to_Map(_self); + Map* other; + + // Allow comparisons to Ruby hashmaps by converting to a temporary Map + // instance. Slow, but workable. + if (TYPE(_other) == T_HASH) { + VALUE other_map = Map_new_this_type(self); + Map_merge_into_self(other_map, _other); + _other = other_map; + } + + other = ruby_to_Map(_other); + + if (self == other) { + return Qtrue; + } + if (self->key_type != other->key_type || + self->value_type_info.type != other->value_type_info.type || + self->value_type_class != other->value_type_class) { + return Qfalse; + } + if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) { + return Qfalse; + } + + // For each member of self, check that an equal member exists at the same key + // in other. + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_MessageValue other_val; + if (!upb_Map_Get(other->map, key, &other_val)) { + // Not present in other map. + return Qfalse; + } + if (!Msgval_IsEqual(val, other_val, self->value_type_info)) { + // Present but different value. + return Qfalse; + } + } + + return Qtrue; +} + +/* + * call-seq: + * Map.frozen? => bool + * + * Returns true if the map is frozen in either Ruby or the underlying + * representation. Freezes the Ruby map object if it is not already frozen in + * Ruby but it is frozen in the underlying representation. + */ +VALUE Map_frozen(VALUE _self) { + Map* self = ruby_to_Map(_self); + if (!upb_Map_IsFrozen(self->map)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * call-seq: + * Map.freeze => self + * + * Freezes the map object. We have to intercept this so we can freeze the + * underlying representation, not just the Ruby wrapper. + */ +VALUE Map_freeze(VALUE _self) { + Map* self = ruby_to_Map(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Map_IsFrozen(self->map)); + return _self; + } + + if (!upb_Map_IsFrozen(self->map)) { + if (self->value_type_info.type == kUpb_CType_Message) { + upb_Map_Freeze( + Map_GetMutable(_self), + upb_MessageDef_MiniTable(self->value_type_info.def.msgdef)); + } else { + upb_Map_Freeze(Map_GetMutable(_self), NULL); + } + } + + RB_OBJ_FREEZE(_self); + + return _self; +} + +VALUE Map_EmptyFrozen(const upb_FieldDef* f) { + PBRUBY_ASSERT(upb_FieldDef_IsMap(f)); + VALUE val = ObjectCache_Get(f); + + if (val == Qnil) { + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + val = Map_alloc(cMap); + Map* self; + TypedData_Get_Struct(val, Map, &Map_type, self); + self->arena = Arena_new(); + self->map = + upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type); + self->key_type = key_type; + self->value_type_info = value_type_info; + if (self->value_type_info.type == kUpb_CType_Message) { + const upb_MessageDef* val_m = value_type_info.def.msgdef; + self->value_type_class = Descriptor_DefToClass(val_m); + } + return ObjectCache_TryAdd(f, Map_freeze(val)); + } + PBRUBY_ASSERT(RB_OBJ_FROZEN(val)); + PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map)); + return val; +} + +/* + * call-seq: + * Map.hash => hash_value + * + * Returns a hash value based on this map's contents. + */ +VALUE Map_hash(VALUE _self) { + Map* self = ruby_to_Map(_self); + uint64_t hash = 0; + + size_t iter = kUpb_Map_Begin; + TypeInfo key_info = {self->key_type}; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + hash = Msgval_GetHash(key, key_info, hash); + hash = Msgval_GetHash(val, self->value_type_info, hash); + } + + return LL2NUM(hash); +} + +/* + * call-seq: + * Map.to_h => {} + * + * Returns a Ruby Hash object containing all the values within the map + */ +VALUE Map_to_h(VALUE _self) { + Map* self = ruby_to_Map(_self); + return Map_CreateHash(self->map, self->key_type, self->value_type_info); +} + +/* + * call-seq: + * Map.inspect => string + * + * Returns a string representing this map's elements. It will be formatted as + * "{key => value, key => value, ...}", with each key and value string + * representation computed by its own #inspect method. + */ +VALUE Map_inspect(VALUE _self) { + Map* self = ruby_to_Map(_self); + + StringBuilder* builder = StringBuilder_New(); + Map_Inspect(builder, self->map, self->key_type, self->value_type_info); + VALUE ret = StringBuilder_ToRubyString(builder); + StringBuilder_Free(builder); + return ret; +} + +/* + * call-seq: + * Map.merge(other_map) => map + * + * Copies key/value pairs from other_map into a copy of this map. If a key is + * set in other_map and this map, the value from other_map overwrites the value + * in the new copy of this map. Returns the new copy of this map with merged + * contents. + */ +static VALUE Map_merge(VALUE _self, VALUE hashmap) { + VALUE dupped = Map_dup(_self); + return Map_merge_into_self(dupped, hashmap); +} + +void Map_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "Map", rb_cObject); + rb_define_alloc_func(klass, Map_alloc); + rb_gc_register_address(&cMap); + cMap = klass; + + rb_define_method(klass, "initialize", Map_init, -1); + rb_define_method(klass, "each", Map_each, 0); + rb_define_method(klass, "keys", Map_keys, 0); + rb_define_method(klass, "values", Map_values, 0); + rb_define_method(klass, "[]", Map_index, 1); + rb_define_method(klass, "[]=", Map_index_set, 2); + rb_define_method(klass, "has_key?", Map_has_key, 1); + rb_define_method(klass, "delete", Map_delete, 1); + rb_define_method(klass, "clear", Map_clear, 0); + rb_define_method(klass, "length", Map_length, 0); + rb_define_method(klass, "size", Map_length, 0); + rb_define_method(klass, "dup", Map_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", Map_dup, 0); + rb_define_method(klass, "==", Map_eq, 1); + rb_define_method(klass, "freeze", Map_freeze, 0); + rb_define_method(klass, "frozen?", Map_frozen, 0); + rb_define_method(klass, "hash", Map_hash, 0); + rb_define_method(klass, "to_h", Map_to_h, 0); + rb_define_method(klass, "inspect", Map_inspect, 0); + rb_define_method(klass, "merge", Map_merge, 1); + rb_include_module(klass, rb_mEnumerable); +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.h new file mode 100755 index 00000000..58e8c25e --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/map.h @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_MAP_H_ +#define RUBY_PROTOBUF_MAP_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Returns a frozen sentinel Ruby wrapper object for an empty upb_Map with the +// key and value types specified by the field. Creates one if it doesn't exist. +VALUE Map_EmptyFrozen(const upb_FieldDef* f); + +// Returns a Ruby wrapper object for the given map, which will be created if +// one does not exist already. +VALUE Map_GetRubyWrapper(const upb_Map *map, upb_CType key_type, + TypeInfo value_type, VALUE arena); + +// Gets the underlying upb_Map for this Ruby map object, which must have +// key/value type that match |field|. If this is not a map or the type doesn't +// match, raises an exception. +const upb_Map *Map_GetUpbMap(VALUE val, const upb_FieldDef *field, + upb_Arena *arena); + +// Implements #inspect for this map by appending its contents to |b|. +void Map_Inspect(StringBuilder *b, const upb_Map *map, upb_CType key_type, + TypeInfo val_type); + +// Returns a new Hash object containing the contents of this Map. +VALUE Map_CreateHash(const upb_Map *map, upb_CType key_type, TypeInfo val_info); + +// Returns a deep copy of this Map object. +VALUE Map_deep_copy(VALUE obj); + +// Ruby class of Google::Protobuf::Map. +extern VALUE cMap; + +// Call at startup to register all types in this module. +void Map_register(VALUE module); + +// Recursively freeze map +VALUE Map_freeze(VALUE _self); + +#endif // RUBY_PROTOBUF_MAP_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.c new file mode 100755 index 00000000..37f4dc70 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.c @@ -0,0 +1,1428 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "message.h" + +#include "convert.h" +#include "defs.h" +#include "map.h" +#include "protobuf.h" +#include "repeated_field.h" +#include "shared_message.h" + +static VALUE cParseError = Qnil; +static VALUE cAbstractMessage = Qnil; +static ID descriptor_instancevar_interned; + +static VALUE initialize_rb_class_with_no_args(VALUE klass) { + return rb_funcall(klass, rb_intern("new"), 0); +} + +VALUE MessageOrEnum_GetDescriptor(VALUE klass) { + return rb_ivar_get(klass, descriptor_instancevar_interned); +} + +// ----------------------------------------------------------------------------- +// Class/module creation from msgdefs and enumdefs, respectively. +// ----------------------------------------------------------------------------- + +typedef struct { + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE arena; + const upb_Message* msg; // Can get as mutable when non-frozen. + const upb_MessageDef* + msgdef; // kept alive by self.class.descriptor reference. +} Message; + +static void Message_mark(void* _self) { + Message* self = (Message*)_self; + rb_gc_mark(self->arena); +} + +static size_t Message_memsize(const void* _self) { return sizeof(Message); } + +static rb_data_type_t Message_type = { + "Google::Protobuf::Message", + {Message_mark, RUBY_DEFAULT_FREE, Message_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static Message* ruby_to_Message(VALUE msg_rb) { + Message* msg; + TypedData_Get_Struct(msg_rb, Message, &Message_type, msg); + return msg; +} + +static VALUE Message_alloc(VALUE klass) { + VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); + Message* msg = ALLOC(Message); + VALUE ret; + + msg->msgdef = Descriptor_GetMsgDef(descriptor); + msg->arena = Qnil; + msg->msg = NULL; + + ret = TypedData_Wrap_Struct(klass, &Message_type, msg); + rb_ivar_set(ret, descriptor_instancevar_interned, descriptor); + + return ret; +} + +const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) { + Message* msg = ruby_to_Message(msg_rb); + if (m) *m = msg->msgdef; + return msg->msg; +} + +upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) { + const upb_Message* upb_msg = Message_Get(msg_rb, m); + Protobuf_CheckNotFrozen(msg_rb, upb_Message_IsFrozen(upb_msg)); + return (upb_Message*)upb_msg; +} + +void Message_InitPtr(VALUE self_, const upb_Message* msg, VALUE arena) { + PBRUBY_ASSERT(arena != Qnil); + Message* self = ruby_to_Message(self_); + self->msg = msg; + RB_OBJ_WRITE(self_, &self->arena, arena); + VALUE stored = ObjectCache_TryAdd(msg, self_); + (void)stored; + PBRUBY_ASSERT(stored == self_); +} + +VALUE Message_GetArena(VALUE msg_rb) { + Message* msg = ruby_to_Message(msg_rb); + return msg->arena; +} + +void Message_CheckClass(VALUE klass) { + if (rb_get_alloc_func(klass) != &Message_alloc) { + rb_raise(rb_eArgError, + "Message class was not returned by the DescriptorPool."); + } +} + +VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m, + VALUE arena) { + if (msg == NULL) return Qnil; + + VALUE val = ObjectCache_Get(msg); + + if (val == Qnil) { + VALUE klass = Descriptor_DefToClass(m); + val = Message_alloc(klass); + Message_InitPtr(val, msg, arena); + } + return val; +} + +void Message_PrintMessage(StringBuilder* b, const upb_Message* msg, + const upb_MessageDef* m) { + bool first = true; + int n = upb_MessageDef_FieldCount(m); + VALUE klass = Descriptor_DefToClass(m); + StringBuilder_Printf(b, "<%s: ", rb_class2name(klass)); + + for (int i = 0; i < n; i++) { + const upb_FieldDef* field = upb_MessageDef_Field(m, i); + + if (upb_FieldDef_HasPresence(field) && + !upb_Message_HasFieldByDef(msg, field)) { + continue; + } + + if (!first) { + StringBuilder_Printf(b, ", "); + } else { + first = false; + } + + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field); + + StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field)); + + if (upb_FieldDef_IsMap(field)) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + TypeInfo val_info = TypeInfo_get(val_f); + Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info); + } else if (upb_FieldDef_IsRepeated(field)) { + RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field)); + } else { + StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field)); + } + } + + StringBuilder_Printf(b, ">"); +} + +// Helper functions for #method_missing //////////////////////////////////////// + +enum { + METHOD_UNKNOWN = 0, + METHOD_GETTER = 1, + METHOD_SETTER = 2, + METHOD_CLEAR = 3, + METHOD_PRESENCE = 4, + METHOD_ENUM_GETTER = 5, + METHOD_WRAPPER_GETTER = 6, + METHOD_WRAPPER_SETTER = 7 +}; + +// Check if the field is a well known wrapper type +static bool IsWrapper(const upb_MessageDef* m) { + if (!m) return false; + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + return true; + default: + return false; + } +} + +static bool IsFieldWrapper(const upb_FieldDef* f) { + return IsWrapper(upb_FieldDef_MessageSubDef(f)); +} + +static bool Match(const upb_MessageDef* m, const char* name, + const upb_FieldDef** f, const upb_OneofDef** o, + const char* prefix, const char* suffix) { + size_t sp = strlen(prefix); + size_t ss = strlen(suffix); + size_t sn = strlen(name); + + if (sn <= sp + ss) return false; + + if (memcmp(name, prefix, sp) != 0 || + memcmp(name + sn - ss, suffix, ss) != 0) { + return false; + } + + return upb_MessageDef_FindByNameWithSize(m, name + sp, sn - sp - ss, f, o); +} + +static int extract_method_call(VALUE method_name, Message* self, + const upb_FieldDef** f, const upb_OneofDef** o) { + const upb_MessageDef* m = self->msgdef; + const char* name; + + Check_Type(method_name, T_SYMBOL); + name = rb_id2name(SYM2ID(method_name)); + + if (Match(m, name, f, o, "", "")) return METHOD_GETTER; + if (Match(m, name, f, o, "", "=")) return METHOD_SETTER; + if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR; + if (Match(m, name, f, o, "has_", "?") && + (*o || (*f && upb_FieldDef_HasPresence(*f)))) { + return METHOD_PRESENCE; + } + if (Match(m, name, f, o, "", "_as_value") && *f && + !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) { + return METHOD_WRAPPER_GETTER; + } + if (Match(m, name, f, o, "", "_as_value=") && *f && + !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) { + return METHOD_WRAPPER_SETTER; + } + if (Match(m, name, f, o, "", "_const") && *f && + upb_FieldDef_CType(*f) == kUpb_CType_Enum) { + return METHOD_ENUM_GETTER; + } + + return METHOD_UNKNOWN; +} + +static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o, + int accessor_type) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o); + + switch (accessor_type) { + case METHOD_PRESENCE: + return oneof_field == NULL ? Qfalse : Qtrue; + case METHOD_CLEAR: + if (oneof_field != NULL) { + upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), + oneof_field); + } + return Qnil; + case METHOD_GETTER: + return oneof_field == NULL + ? Qnil + : ID2SYM(rb_intern(upb_FieldDef_Name(oneof_field))); + case METHOD_SETTER: + rb_raise(rb_eRuntimeError, "Oneof accessors are read-only."); + } + rb_raise(rb_eRuntimeError, "Invalid access of oneof field."); +} + +static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val, + upb_Arena* arena) { + upb_MessageValue msgval; + if (upb_FieldDef_IsMap(f)) { + msgval.map_val = Map_GetUpbMap(val, f, arena); + } else if (upb_FieldDef_IsRepeated(f)) { + msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); + } else { + if (val == Qnil && + (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) { + upb_Message_ClearFieldByDef(msg, f); + return; + } + msgval = + Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + } + upb_Message_SetFieldByDef(msg, f, msgval, arena); +} + +VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f, + VALUE arena) { + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f); + if (upb_FieldDef_IsMap(f)) { + if (msgval.map_val == NULL) { + return Map_EmptyFrozen(f); + } + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, arena); + } + if (upb_FieldDef_IsRepeated(f)) { + if (msgval.array_val == NULL) { + return RepeatedField_EmptyFrozen(f); + } + return RepeatedField_GetRubyWrapper(msgval.array_val, TypeInfo_get(f), + arena); + } + VALUE ret; + if (upb_FieldDef_IsSubMessage(f)) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret = Message_GetRubyWrapper(msgval.msg_val, m, arena); + } else { + ret = Convert_UpbToRuby(msgval, TypeInfo_get(f), Qnil); + } + return ret; +} + +VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) { + Message* self = ruby_to_Message(_self); + if (upb_Message_IsFrozen(self->msg)) { + return Message_getfield_frozen(self->msg, f, self->arena); + } + upb_Message* msg = Message_GetMutable(_self, NULL); + upb_Arena* arena = Arena_get(self->arena); + if (upb_FieldDef_IsMap(f)) { + upb_Map* map = upb_Message_Mutable(msg, f, arena).map; + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena); + } else if (upb_FieldDef_IsRepeated(f)) { + upb_Array* arr = upb_Message_Mutable(msg, f, arena).array; + return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena); + } else if (upb_FieldDef_IsSubMessage(f)) { + if (!upb_Message_HasFieldByDef(msg, f)) return Qnil; + upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg; + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + return Message_GetRubyWrapper(submsg, m, self->arena); + } else { + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f); + return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena); + } +} + +static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f, + int accessor_type, int argc, VALUE* argv) { + upb_Arena* arena = Arena_get(Message_GetArena(_self)); + + switch (accessor_type) { + case METHOD_SETTER: + Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena); + return Qnil; + case METHOD_CLEAR: + upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f); + return Qnil; + case METHOD_PRESENCE: + if (!upb_FieldDef_HasPresence(f)) { + rb_raise(rb_eRuntimeError, "Field does not have presence."); + } + return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f); + case METHOD_WRAPPER_GETTER: { + Message* self = ruby_to_Message(_self); + if (upb_Message_HasFieldByDef(self->msg, f)) { + PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) && + !upb_FieldDef_IsRepeated(f)); + upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f); + const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* value_f = + upb_MessageDef_FindFieldByNumber(wrapper_m, 1); + upb_MessageValue value = + upb_Message_GetFieldByDef(wrapper.msg_val, value_f); + return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena); + } else { + return Qnil; + } + } + case METHOD_WRAPPER_SETTER: { + upb_Message* msg = Message_GetMutable(_self, NULL); + if (argv[1] == Qnil) { + upb_Message_ClearFieldByDef(msg, f); + } else { + const upb_FieldDef* val_f = + upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1); + upb_MessageValue msgval = Convert_RubyToUpb( + argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena); + upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg; + upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena); + } + return Qnil; + } + case METHOD_ENUM_GETTER: { + upb_MessageValue msgval = + upb_Message_GetFieldByDef(Message_Get(_self, NULL), f); + + if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) { + // Map repeated fields to a new type with ints + VALUE arr = rb_ary_new(); + size_t i, n = upb_Array_Size(msgval.array_val); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(msgval.array_val, i); + rb_ary_push(arr, INT2NUM(elem.int32_val)); + } + return arr; + } else { + return INT2NUM(msgval.int32_val); + } + } + case METHOD_GETTER: + return Message_getfield(_self, f); + default: + rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d", + accessor_type); + } +} + +/* + * call-seq: + * Message.method_missing(*args) + * + * Provides accessors and setters and methods to clear and check for presence of + * message fields according to their field names. + * + * For any field whose name does not conflict with a built-in method, an + * accessor is provided with the same name as the field, and a setter is + * provided with the name of the field plus the '=' suffix. Thus, given a + * message instance 'msg' with field 'foo', the following code is valid: + * + * msg.foo = 42 + * puts msg.foo + * + * This method also provides read-only accessors for oneofs. If a oneof exists + * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to + * the name of the field in that oneof that is currently set, or nil if none. + * + * It also provides methods of the form 'clear_fieldname' to clear the value + * of the field 'fieldname'. For basic data types, this will set the default + * value of the field. + * + * Additionally, it provides methods of the form 'has_fieldname?', which returns + * true if the field 'fieldname' is set in the message object, else false. For + * 'proto3' syntax, calling this for a basic type field will result in an error. + */ +static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + const upb_OneofDef* o; + const upb_FieldDef* f; + int accessor_type; + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected method name as first argument."); + } + + accessor_type = extract_method_call(argv[0], self, &f, &o); + + if (accessor_type == METHOD_UNKNOWN) return rb_call_super(argc, argv); + + // Validate argument count. + switch (accessor_type) { + case METHOD_SETTER: + case METHOD_WRAPPER_SETTER: + if (argc != 2) { + rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc); + } + break; + default: + if (argc != 1) { + rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc); + } + break; + } + + // Dispatch accessor. + if (o != NULL) { + return Message_oneof_accessor(_self, o, accessor_type); + } else { + return Message_field_accessor(_self, f, accessor_type, argc, argv); + } +} + +static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + const upb_OneofDef* o; + const upb_FieldDef* f; + int accessor_type; + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected method name as first argument."); + } + + accessor_type = extract_method_call(argv[0], self, &f, &o); + + if (accessor_type == METHOD_UNKNOWN) { + return rb_call_super(argc, argv); + } else if (o != NULL) { + return accessor_type == METHOD_SETTER ? Qfalse : Qtrue; + } else { + return Qtrue; + } +} + +void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val, + upb_Arena* arena); + +typedef struct { + upb_Map* map; + TypeInfo key_type; + TypeInfo val_type; + upb_Arena* arena; +} MapInit; + +static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { + MapInit* map_init = (MapInit*)_self; + upb_MessageValue k, v; + k = Convert_RubyToUpb(key, "", map_init->key_type, NULL); + + if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) { + const upb_MiniTable* t = + upb_MessageDef_MiniTable(map_init->val_type.def.msgdef); + upb_Message* msg = upb_Message_New(t, map_init->arena); + Message_InitFromValue(msg, map_init->val_type.def.msgdef, val, + map_init->arena); + v.msg_val = msg; + } else { + v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena); + } + upb_Map_Set(map_init->map, k, v, map_init->arena); + return ST_CONTINUE; +} + +static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val, + upb_Arena* arena) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + if (TYPE(val) != T_HASH) { + rb_raise(rb_eArgError, + "Expected Hash object as initializer value for map field '%s' " + "(given %s).", + upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val))); + } + MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena}; + rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init); +} + +static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info, + upb_Arena* arena) { + if (info.type == kUpb_CType_Message) { + upb_MessageValue msgval; + const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef); + upb_Message* msg = upb_Message_New(t, arena); + Message_InitFromValue(msg, info.def.msgdef, val, arena); + msgval.msg_val = msg; + return msgval; + } else { + return Convert_RubyToUpb(val, "", info, arena); + } +} + +static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f, + VALUE val, upb_Arena* arena) { + TypeInfo type_info = TypeInfo_get(f); + + if (TYPE(val) != T_ARRAY) { + rb_raise(rb_eArgError, + "Expected array as initializer value for repeated field '%s' " + "(given %s).", + upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val))); + } + + for (int i = 0; i < RARRAY_LEN(val); i++) { + VALUE entry = rb_ary_entry(val, i); + upb_MessageValue msgval; + if (upb_FieldDef_IsSubMessage(f) && TYPE(entry) == T_HASH) { + msgval = MessageValue_FromValue(entry, type_info, arena); + } else { + msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena); + } + upb_Array_Append(arr, msgval, arena); + } +} + +static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f, + VALUE val, upb_Arena* arena) { + if (TYPE(val) == T_NIL) return; + + if (upb_FieldDef_IsMap(f)) { + upb_Map* map = upb_Message_Mutable(msg, f, arena).map; + Map_InitFromValue(map, f, val, arena); + } else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) { + upb_Array* arr = upb_Message_Mutable(msg, f, arena).array; + RepeatedField_InitFromValue(arr, f, val, arena); + } else if (upb_FieldDef_IsSubMessage(f)) { + if (TYPE(val) == T_HASH) { + upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg; + Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena); + } else { + Message_setfield(msg, f, val, arena); + } + } else { + upb_MessageValue msgval = + Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + upb_Message_SetFieldByDef(msg, f, msgval, arena); + } +} + +typedef struct { + upb_Message* msg; + const upb_MessageDef* msgdef; + upb_Arena* arena; +} MsgInit; + +static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { + MsgInit* msg_init = (MsgInit*)_self; + const char* name; + + if (TYPE(key) == T_STRING) { + name = RSTRING_PTR(key); + } else if (TYPE(key) == T_SYMBOL) { + name = RSTRING_PTR(rb_id2str(SYM2ID(key))); + } else { + rb_raise(rb_eArgError, + "Expected string or symbols as hash keys when initializing proto " + "from hash."); + } + + const upb_FieldDef* f = + upb_MessageDef_FindFieldByName(msg_init->msgdef, name); + + if (f == NULL) { + rb_raise(rb_eArgError, + "Unknown field name '%s' in initialization map entry.", name); + } + + Message_InitFieldFromValue(msg_init->msg, f, val, msg_init->arena); + return ST_CONTINUE; +} + +void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val, + upb_Arena* arena) { + MsgInit msg_init = {msg, m, arena}; + if (TYPE(val) == T_HASH) { + rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init); + } else { + rb_raise(rb_eArgError, "Expected hash arguments or message, not %s", + rb_class2name(CLASS_OF(val))); + } +} + +/* + * call-seq: + * Message.new(kwargs) => new_message + * + * Creates a new instance of the given message class. Keyword arguments may be + * provided with keywords corresponding to field names. + * + * Note that no literal Message class exists. Only concrete classes per message + * type exist, as provided by the #msgclass method on Descriptors after they + * have been added to a pool. The method definitions described here on the + * Message class are provided on each concrete message class. + */ +static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + VALUE arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(arena_rb); + const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef); + upb_Message* msg = upb_Message_New(t, arena); + + Message_InitPtr(_self, msg, arena_rb); + + if (argc == 0) { + return Qnil; + } + if (argc != 1) { + rb_raise(rb_eArgError, "Expected 0 or 1 arguments."); + } + Message_InitFromValue((upb_Message*)self->msg, self->msgdef, argv[0], arena); + return Qnil; +} + +/* + * call-seq: + * Message.dup => new_message + * + * Performs a shallow copy of this message and returns the new copy. + */ +static VALUE Message_dup(VALUE _self) { + Message* self = ruby_to_Message(_self); + VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); + Message* new_msg_self = ruby_to_Message(new_msg); + const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef); + upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m); + Arena_fuse(self->arena, Arena_get(new_msg_self->arena)); + return new_msg; +} + +/* + * call-seq: + * Message.==(other) => boolean + * + * Performs a deep comparison of this message with another. Messages are equal + * if they have the same type and if each field is equal according to the :== + * method's semantics (a more efficient comparison may actually be done if the + * field is of a primitive type). + */ +static VALUE Message_eq(VALUE _self, VALUE _other) { + if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse; + + Message* self = ruby_to_Message(_self); + Message* other = ruby_to_Message(_other); + assert(self->msgdef == other->msgdef); + + const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef); + const int options = 0; + return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue + : Qfalse; +} + +uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed) { + upb_Status status; + upb_Status_Clear(&status); + uint64_t return_value = shared_Message_Hash(msg, m, seed, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(cParseError, "Message_Hash(): %s", + upb_Status_ErrorMessage(&status)); + } +} + +/* + * call-seq: + * Message.hash => hash_value + * + * Returns a hash value that represents this message's field values. + */ +static VALUE Message_hash(VALUE _self) { + Message* self = ruby_to_Message(_self); + uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0); + // RUBY_FIXNUM_MAX should be one less than a power of 2. + assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0); + return INT2FIX(hash_value & RUBY_FIXNUM_MAX); +} + +/* + * call-seq: + * Message.inspect => string + * + * Returns a human-readable string representing this message. It will be + * formatted as "". Each + * field's value is represented according to its own #inspect method. + */ +static VALUE Message_inspect(VALUE _self) { + Message* self = ruby_to_Message(_self); + + StringBuilder* builder = StringBuilder_New(); + Message_PrintMessage(builder, self->msg, self->msgdef); + VALUE ret = StringBuilder_ToRubyString(builder); + StringBuilder_Free(builder); + return ret; +} + +// Support functions for Message_to_h ////////////////////////////////////////// + +static VALUE RepeatedField_CreateArray(const upb_Array* arr, + TypeInfo type_info) { + int size = arr ? upb_Array_Size(arr) : 0; + VALUE ary = rb_ary_new2(size); + + for (int i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(arr, i); + VALUE val = Scalar_CreateHash(msgval, type_info); + rb_ary_push(ary, val); + } + + return ary; +} + +static VALUE Message_CreateHash(const upb_Message* msg, + const upb_MessageDef* m) { + if (!msg) return Qnil; + + VALUE hash = rb_hash_new(); + size_t iter = kUpb_Message_Begin; + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m)); + const upb_FieldDef* field; + upb_MessageValue val; + + while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) { + if (upb_FieldDef_IsExtension(field)) { + // TODO: allow extensions once we have decided what naming scheme the + // symbol should use. eg. :"[pkg.ext]" + continue; + } + + TypeInfo type_info = TypeInfo_get(field); + VALUE msg_value; + + if (upb_FieldDef_IsMap(field)) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + upb_CType key_type = upb_FieldDef_CType(key_f); + msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f)); + } else if (upb_FieldDef_IsRepeated(field)) { + msg_value = RepeatedField_CreateArray(val.array_val, type_info); + } else { + msg_value = Scalar_CreateHash(val, type_info); + } + + VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field))); + rb_hash_aset(hash, msg_key, msg_value); + } + + return hash; +} + +VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) { + if (type_info.type == kUpb_CType_Message) { + return Message_CreateHash(msgval.msg_val, type_info.def.msgdef); + } else { + return Convert_UpbToRuby(msgval, type_info, Qnil); + } +} + +/* + * call-seq: + * Message.to_h => {} + * + * Returns the message as a Ruby Hash object, with keys as symbols. + */ +static VALUE Message_to_h(VALUE _self) { + Message* self = ruby_to_Message(_self); + return Message_CreateHash(self->msg, self->msgdef); +} + +/* + * call-seq: + * Message.frozen? => bool + * + * Returns true if the message is frozen in either Ruby or the underlying + * representation. Freezes the Ruby message object if it is not already frozen + * in Ruby but it is frozen in the underlying representation. + */ +VALUE Message_frozen(VALUE _self) { + Message* self = ruby_to_Message(_self); + if (!upb_Message_IsFrozen(self->msg)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * call-seq: + * Message.freeze => self + * + * Freezes the message object. We have to intercept this so we can freeze the + * underlying representation, not just the Ruby wrapper. + */ +VALUE Message_freeze(VALUE _self) { + Message* self = ruby_to_Message(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg)); + return _self; + } + if (!upb_Message_IsFrozen(self->msg)) { + upb_Message_Freeze(Message_GetMutable(_self, NULL), + upb_MessageDef_MiniTable(self->msgdef)); + } + RB_OBJ_FREEZE(_self); + return _self; +} + +/* + * call-seq: + * Message.[](index) => value + * + * Accesses a field's value by field name. The provided field name should be a + * string. + */ +static VALUE Message_index(VALUE _self, VALUE field_name) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* field; + + Check_Type(field_name, T_STRING); + field = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name)); + + if (field == NULL) { + return Qnil; + } + + return Message_getfield(_self, field); +} + +/* + * call-seq: + * Message.[]=(index, value) + * + * Sets a field's value by field name. The provided field name should be a + * string. + */ +static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* f; + upb_MessageValue val; + upb_Arena* arena = Arena_get(self->arena); + + Check_Type(field_name, T_STRING); + f = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name)); + + if (f == NULL) { + rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name)); + } + + val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena); + + return Qnil; +} + +/* + * call-seq: + * MessageClass.decode(data, options) => message + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretation given by this message class's definition + * and returns a message object with the corresponding field values. + * @param options [Hash] options for the decoder + * recursion_limit: set to maximum decoding depth for message (default is 64) + */ +static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) { + VALUE data = argv[0]; + int options = 0; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + + if (depth != Qnil && TYPE(depth) == T_FIXNUM) { + options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth)); + } + } + + if (TYPE(data) != T_STRING) { + rb_raise(rb_eArgError, "Expected string for binary protobuf data."); + } + + return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options, + klass, /*freeze*/ false); +} + +VALUE Message_decode_bytes(int size, const char* bytes, int options, + VALUE klass, bool freeze) { + VALUE msg_rb = initialize_rb_class_with_no_args(klass); + Message* msg = ruby_to_Message(msg_rb); + + const upb_FileDef* file = upb_MessageDef_File(msg->msgdef); + const upb_ExtensionRegistry* extreg = + upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file)); + upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg, + upb_MessageDef_MiniTable(msg->msgdef), + extreg, options, Arena_get(msg->arena)); + if (status != kUpb_DecodeStatus_Ok) { + rb_raise(cParseError, "Error occurred during parsing"); + } + if (freeze) { + Message_freeze(msg_rb); + } + return msg_rb; +} + +/* + * call-seq: + * MessageClass.decode_json(data, options = {}) => message + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretration given by this message class's definition + * and returns a message object with the corresponding field values. + * + * @param options [Hash] options for the decoder + * ignore_unknown_fields: set true to ignore unknown fields (default is to + * raise an error) + */ +static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) { + VALUE data = argv[0]; + int options = 0; + upb_Status status; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + + if (RTEST(rb_hash_lookup2( + hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) { + options |= upb_JsonDecode_IgnoreUnknown; + } + } + + if (TYPE(data) != T_STRING) { + rb_raise(rb_eArgError, "Expected string for JSON data."); + } + + // TODO: Check and respect string encoding. If not UTF-8, we need to + // convert, because string handlers pass data directly to message string + // fields. + + VALUE msg_rb = initialize_rb_class_with_no_args(klass); + Message* msg = ruby_to_Message(msg_rb); + + // We don't allow users to decode a wrapper type directly. + if (IsWrapper(msg->msgdef)) { + rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly."); + } + + upb_Status_Clear(&status); + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef)); + + int result = upb_JsonDecodeDetectingNonconformance( + RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg, + msg->msgdef, pool, options, Arena_get(msg->arena), &status); + + switch (result) { + case kUpb_JsonDecodeResult_Ok: + break; + case kUpb_JsonDecodeResult_OkWithEmptyStringNumerics: + rb_warn("%s", upb_Status_ErrorMessage(&status)); + break; + case kUpb_JsonDecodeResult_Error: + rb_raise(cParseError, "Error occurred during parsing: %s", + upb_Status_ErrorMessage(&status)); + break; + } + + return msg_rb; +} + +/* + * call-seq: + * MessageClass.encode(msg, options) => bytes + * + * Encodes the given message object to its serialized form in protocol buffers + * wire format. + * @param options [Hash] options for the encoder + * recursion_limit: set to maximum encoding depth for message (default is 64) + */ +static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) { + Message* msg = ruby_to_Message(argv[0]); + int options = 0; + char* data; + size_t size; + + if (CLASS_OF(argv[0]) != klass) { + rb_raise(rb_eArgError, "Message of wrong type."); + } + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + + if (depth != Qnil && TYPE(depth) == T_FIXNUM) { + options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth)); + } + } + + upb_Arena* arena = upb_Arena_New(); + + upb_EncodeStatus status = + upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options, + arena, &data, &size); + + if (status == kUpb_EncodeStatus_Ok) { + VALUE ret = rb_str_new(data, size); + rb_enc_associate(ret, rb_ascii8bit_encoding()); + upb_Arena_Free(arena); + return ret; + } else { + upb_Arena_Free(arena); + rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)"); + } +} + +/* + * call-seq: + * MessageClass.encode_json(msg, options = {}) => json_string + * + * Encodes the given message object into its serialized JSON representation. + * @param options [Hash] options for the decoder + * preserve_proto_fieldnames: set true to use original fieldnames (default is + * to camelCase) emit_defaults: set true to emit 0/false values (default is to + * omit them) + */ +static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { + Message* msg = ruby_to_Message(argv[0]); + int options = 0; + char buf[1024]; + size_t size; + upb_Status status; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, + rb_str_new2("to_h")))) { + hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0); + } else { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + } + + if (RTEST(rb_hash_lookup2(hash_args, + ID2SYM(rb_intern("preserve_proto_fieldnames")), + Qfalse))) { + options |= upb_JsonEncode_UseProtoNames; + } + + if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")), + Qfalse))) { + options |= upb_JsonEncode_EmitDefaults; + } + + if (RTEST(rb_hash_lookup2(hash_args, + ID2SYM(rb_intern("format_enums_as_integers")), + Qfalse))) { + options |= upb_JsonEncode_FormatEnumsAsIntegers; + } + } + + upb_Status_Clear(&status); + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef)); + size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf), + &status); + + if (!upb_Status_IsOk(&status)) { + rb_raise(cParseError, "Error occurred during encoding: %s", + upb_Status_ErrorMessage(&status)); + } + + VALUE ret; + if (size >= sizeof(buf)) { + char* buf2 = malloc(size + 1); + upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1, + &status); + ret = rb_str_new(buf2, size); + free(buf2); + } else { + ret = rb_str_new(buf, size); + } + + rb_enc_associate(ret, rb_utf8_encoding()); + return ret; +} + +/* + * call-seq: + * Message.descriptor => descriptor + * + * Class method that returns the Descriptor instance corresponding to this + * message class's type. + */ +static VALUE Message_descriptor(VALUE klass) { + return rb_ivar_get(klass, descriptor_instancevar_interned); +} + +VALUE build_class_from_descriptor(VALUE descriptor) { + const char* name; + VALUE klass; + + name = upb_MessageDef_FullName(Descriptor_GetMsgDef(descriptor)); + if (name == NULL) { + rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name."); + } + + klass = rb_define_class_id( + // Docs say this parameter is ignored. User will assign return value to + // their own toplevel constant class name. + rb_intern("Message"), cAbstractMessage); + rb_ivar_set(klass, descriptor_instancevar_interned, descriptor); + return klass; +} + +/* + * call-seq: + * Enum.lookup(number) => name + * + * This module method, provided on each generated enum module, looks up an enum + * value by number and returns its name as a Ruby symbol, or nil if not found. + */ +static VALUE enum_lookup(VALUE self, VALUE number) { + int32_t num = NUM2INT(number); + VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc); + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, num); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return Qnil; + } +} + +/* + * call-seq: + * Enum.resolve(name) => number + * + * This module method, provided on each generated enum module, looks up an enum + * value by name (as a Ruby symbol) and returns its name, or nil if not found. + */ +static VALUE enum_resolve(VALUE self, VALUE sym) { + const char* name = rb_id2name(SYM2ID(sym)); + VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc); + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByName(e, name); + if (ev) { + return INT2NUM(upb_EnumValueDef_Number(ev)); + } else { + return Qnil; + } +} + +/* + * call-seq: + * Enum.descriptor + * + * This module method, provided on each generated enum module, returns the + * EnumDescriptor corresponding to this enum type. + */ +static VALUE enum_descriptor(VALUE self) { + return rb_ivar_get(self, descriptor_instancevar_interned); +} + +VALUE build_module_from_enumdesc(VALUE _enumdesc) { + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(_enumdesc); + VALUE mod = rb_define_module_id(rb_intern(upb_EnumDef_FullName(e))); + + int n = upb_EnumDef_ValueCount(e); + for (int i = 0; i < n; i++) { + const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i); + upb_Arena* arena = upb_Arena_New(); + const char* src_name = upb_EnumValueDef_Name(ev); + char* name = upb_strdup2(src_name, strlen(src_name), arena); + int32_t value = upb_EnumValueDef_Number(ev); + if (name[0] < 'A' || name[0] > 'Z') { + if (name[0] >= 'a' && name[0] <= 'z') { + name[0] -= 32; // auto capitalize + } else { + rb_warn( + "Enum value '%s' does not start with an uppercase letter " + "as is required for Ruby constants.", + name); + } + } + rb_define_const(mod, name, INT2NUM(value)); + upb_Arena_Free(arena); + } + + rb_define_singleton_method(mod, "lookup", enum_lookup, 1); + rb_define_singleton_method(mod, "resolve", enum_resolve, 1); + rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0); + rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc); + + return mod; +} + +// Internal to the library; used by Google::Protobuf.deep_copy. +upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m, + upb_Arena* arena) { + // Serialize and parse. + upb_Arena* tmp_arena = upb_Arena_New(); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + size_t size; + + upb_Message* new_msg = upb_Message_New(layout, arena); + char* data; + + const upb_FileDef* file = upb_MessageDef_File(m); + const upb_ExtensionRegistry* extreg = + upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file)); + if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) != + kUpb_EncodeStatus_Ok || + upb_Decode(data, size, new_msg, layout, extreg, 0, arena) != + kUpb_DecodeStatus_Ok) { + upb_Arena_Free(tmp_arena); + rb_raise(cParseError, "Error occurred copying proto"); + } + + upb_Arena_Free(tmp_arena); + return new_msg; +} + +const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, + const char* name, upb_Arena* arena) { + if (value == Qnil) { + rb_raise(cTypeError, "nil message not allowed here."); + } + + VALUE klass = CLASS_OF(value); + VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned); + const upb_MessageDef* val_m = + desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb); + + if (val_m != m) { + // Check for possible implicit conversions + // TODO: hash conversion? + + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Timestamp: { + // Time -> Google::Protobuf::Timestamp + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(t, arena); + upb_MessageValue sec, nsec; + struct timespec time; + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); + + if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype; + + time = rb_time_timespec(value); + sec.int64_val = time.tv_sec; + nsec.int32_val = time.tv_nsec; + upb_Message_SetFieldByDef(msg, sec_f, sec, arena); + upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena); + return msg; + } + case kUpb_WellKnown_Duration: { + // Numeric -> Google::Protobuf::Duration + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(t, arena); + upb_MessageValue sec, nsec; + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); + + if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype; + + sec.int64_val = NUM2LL(value); + nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000); + upb_Message_SetFieldByDef(msg, sec_f, sec, arena); + upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena); + return msg; + } + default: + badtype: + rb_raise(cTypeError, + "Invalid type %s to assign to submessage field '%s'.", + rb_class2name(CLASS_OF(value)), name); + } + } + + Message* self = ruby_to_Message(value); + Arena_fuse(self->arena, arena); + + return self->msg; +} + +static void Message_define_class(VALUE klass) { + rb_define_alloc_func(klass, Message_alloc); + + rb_require("google/protobuf/message_exts"); + rb_define_method(klass, "method_missing", Message_method_missing, -1); + rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing, + -1); + rb_define_method(klass, "initialize", Message_initialize, -1); + rb_define_method(klass, "dup", Message_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", Message_dup, 0); + rb_define_method(klass, "==", Message_eq, 1); + rb_define_method(klass, "eql?", Message_eq, 1); + rb_define_method(klass, "freeze", Message_freeze, 0); + rb_define_method(klass, "frozen?", Message_frozen, 0); + rb_define_method(klass, "hash", Message_hash, 0); + rb_define_method(klass, "to_h", Message_to_h, 0); + rb_define_method(klass, "inspect", Message_inspect, 0); + rb_define_method(klass, "to_s", Message_inspect, 0); + rb_define_method(klass, "[]", Message_index, 1); + rb_define_method(klass, "[]=", Message_index_set, 2); + rb_define_singleton_method(klass, "decode", Message_decode, -1); + rb_define_singleton_method(klass, "encode", Message_encode, -1); + rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1); + rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1); + rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0); +} + +void Message_register(VALUE protobuf) { + cParseError = rb_const_get(protobuf, rb_intern("ParseError")); + cAbstractMessage = + rb_define_class_under(protobuf, "AbstractMessage", rb_cObject); + Message_define_class(cAbstractMessage); + rb_gc_register_address(&cAbstractMessage); + + // Ruby-interned string: "descriptor". We use this identifier to store an + // instance variable on message classes we create in order to link them back + // to their descriptors. + descriptor_instancevar_interned = rb_intern("@descriptor"); +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.h new file mode 100755 index 00000000..6c8b9a6e --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/message.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_MESSAGE_H_ +#define RUBY_PROTOBUF_MESSAGE_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Gets the underlying upb_Message* and upb_MessageDef for the given Ruby +// message wrapper. Requires that |value| is indeed a message object. +const upb_Message* Message_Get(VALUE value, const upb_MessageDef** m); + +// Like Message_Get(), but checks that the object is not frozen and returns a +// mutable pointer. +upb_Message* Message_GetMutable(VALUE value, const upb_MessageDef** m); + +// Returns the Arena object for this message. +VALUE Message_GetArena(VALUE value); + +// Converts |value| into a upb_Message value of the expected upb_MessageDef +// type, raising an error if this is not possible. Used when assigning |value| +// to a field of another message, which means the message must be of a +// particular type. +// +// This will perform automatic conversions in some cases (for example, Time -> +// Google::Protobuf::Timestamp). If any new message is created, it will be +// created on |arena|, and any existing message will have its arena fused with +// |arena|. +const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, + const char* name, upb_Arena* arena); + +// Gets or constructs a Ruby wrapper object for the given message. The wrapper +// object will reference |arena| and ensure that it outlives this object. +VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m, + VALUE arena); + +// Gets the given field from this message. +VALUE Message_getfield(VALUE _self, const upb_FieldDef* f); + +// Implements #inspect for this message, printing the text to |b|. +void Message_PrintMessage(StringBuilder* b, const upb_Message* msg, + const upb_MessageDef* m); + +// Returns a hash value for the given message. +uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed); + +// Returns a deep copy of the given message. +upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m, + upb_Arena* arena); + +// Checks that this Ruby object is a message, and raises an exception if not. +void Message_CheckClass(VALUE klass); + +// Returns a new Hash object containing the contents of this message. +VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info); + +// Creates a message class or enum module for this descriptor, respectively. +VALUE build_class_from_descriptor(VALUE descriptor); +VALUE build_module_from_enumdesc(VALUE _enumdesc); + +// Returns the Descriptor/EnumDescriptor for the given message class or enum +// module, respectively. Returns nil if this is not a message class or enum +// module. +VALUE MessageOrEnum_GetDescriptor(VALUE klass); + +// Decodes a Message from a byte sequence. +VALUE Message_decode_bytes(int size, const char* bytes, int options, + VALUE klass, bool freeze); + +// Recursively freeze message +VALUE Message_freeze(VALUE _self); + +// Call at startup to register all types in this module. +void Message_register(VALUE protobuf); + +#endif // RUBY_PROTOBUF_MESSAGE_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.c new file mode 100755 index 00000000..e84395bf --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.c @@ -0,0 +1,356 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "protobuf.h" + +#include "defs.h" +#include "map.h" +#include "message.h" +#include "repeated_field.h" + +VALUE cParseError; +VALUE cTypeError; + +const upb_FieldDef *map_field_key(const upb_FieldDef *field) { + const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); + return upb_MessageDef_FindFieldByNumber(entry, 1); +} + +const upb_FieldDef *map_field_value(const upb_FieldDef *field) { + const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); + return upb_MessageDef_FindFieldByNumber(entry, 2); +} + +// ----------------------------------------------------------------------------- +// StringBuilder, for inspect +// ----------------------------------------------------------------------------- + +struct StringBuilder { + size_t size; + size_t cap; + char *data; +}; + +typedef struct StringBuilder StringBuilder; + +static size_t StringBuilder_SizeOf(size_t cap) { + return sizeof(StringBuilder) + cap; +} + +StringBuilder *StringBuilder_New() { + const size_t cap = 128; + StringBuilder *builder = malloc(sizeof(*builder)); + builder->size = 0; + builder->cap = cap; + builder->data = malloc(builder->cap); + return builder; +} + +void StringBuilder_Free(StringBuilder *b) { + free(b->data); + free(b); +} + +void StringBuilder_Printf(StringBuilder *b, const char *fmt, ...) { + size_t have = b->cap - b->size; + size_t n; + va_list args; + + va_start(args, fmt); + n = vsnprintf(&b->data[b->size], have, fmt, args); + va_end(args); + + if (have <= n) { + while (have <= n) { + b->cap *= 2; + have = b->cap - b->size; + } + b->data = realloc(b->data, StringBuilder_SizeOf(b->cap)); + va_start(args, fmt); + n = vsnprintf(&b->data[b->size], have, fmt, args); + va_end(args); + PBRUBY_ASSERT(n < have); + } + + b->size += n; +} + +VALUE StringBuilder_ToRubyString(StringBuilder *b) { + VALUE ret = rb_str_new(b->data, b->size); + rb_enc_associate(ret, rb_utf8_encoding()); + return ret; +} + +static void StringBuilder_PrintEnum(StringBuilder *b, int32_t val, + const upb_EnumDef *e) { + const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(e, val); + if (ev) { + StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev)); + } else { + StringBuilder_Printf(b, "%" PRId32, val); + } +} + +void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val, + TypeInfo info) { + switch (info.type) { + case kUpb_CType_Bool: + StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: { + VALUE str = rb_inspect(DBL2NUM(val.float_val)); + StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); + break; + } + case kUpb_CType_Double: { + VALUE str = rb_inspect(DBL2NUM(val.double_val)); + StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); + break; + } + case kUpb_CType_Int32: + StringBuilder_Printf(b, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + StringBuilder_Printf(b, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + StringBuilder_Printf(b, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + StringBuilder_Printf(b, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, + val.str_val.data); + break; + case kUpb_CType_Bytes: + StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, + val.str_val.data); + break; + case kUpb_CType_Enum: + StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef); + break; + case kUpb_CType_Message: + Message_PrintMessage(b, val.msg_val, info.def.msgdef); + break; + } +} + +// ----------------------------------------------------------------------------- +// Arena +// ----------------------------------------------------------------------------- + +typedef struct { + upb_Arena *arena; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE pinned_objs; +} Arena; + +static void Arena_mark(void *data) { + Arena *arena = data; + rb_gc_mark(arena->pinned_objs); +} + +static void Arena_free(void *data) { + Arena *arena = data; + upb_Arena_Free(arena->arena); + xfree(arena); +} + +static size_t Arena_memsize(const void *data) { + const Arena *arena = data; + size_t fused_count; + size_t memsize = upb_Arena_SpaceAllocated(arena->arena, &fused_count); + if (fused_count > 1) { + // If other arena were fused we attribute an equal + // share of memory usage to each one. + memsize /= fused_count; + } + return memsize + sizeof(Arena); +} + +static VALUE cArena; + +const rb_data_type_t Arena_type = { + "Google::Protobuf::Internal::Arena", + {Arena_mark, Arena_free, Arena_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, + size_t size) { + if (size == 0) { + xfree(ptr); + return NULL; + } else { + return xrealloc(ptr, size); + } +} + +upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc}; + +static VALUE Arena_alloc(VALUE klass) { + Arena *arena = ALLOC(Arena); + arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc); + arena->pinned_objs = Qnil; + return TypedData_Wrap_Struct(klass, &Arena_type, arena); +} + +upb_Arena *Arena_get(VALUE _arena) { + Arena *arena; + TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); + return arena->arena; +} + +void Arena_fuse(VALUE _arena, upb_Arena *other) { + Arena *arena; + TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); + if (!upb_Arena_Fuse(arena->arena, other)) { + rb_raise(rb_eRuntimeError, + "Unable to fuse arenas. This should never happen since Ruby does " + "not use initial blocks"); + } +} + +VALUE Arena_new() { return Arena_alloc(cArena); } + +void Arena_register(VALUE module) { + VALUE internal = rb_define_module_under(module, "Internal"); + VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject); + rb_define_alloc_func(klass, Arena_alloc); + rb_gc_register_address(&cArena); + cArena = klass; +} + +// ----------------------------------------------------------------------------- +// Object Cache +// ----------------------------------------------------------------------------- + +// Public ObjectCache API. + +VALUE weak_obj_cache = Qnil; +ID item_get; +ID item_try_add; + +static void ObjectCache_Init(VALUE protobuf) { + item_get = rb_intern("get"); + item_try_add = rb_intern("try_add"); + + rb_gc_register_address(&weak_obj_cache); + VALUE internal = rb_const_get(protobuf, rb_intern("Internal")); +#if SIZEOF_LONG >= SIZEOF_VALUE + VALUE cache_class = rb_const_get(internal, rb_intern("ObjectCache")); +#else + VALUE cache_class = rb_const_get(internal, rb_intern("LegacyObjectCache")); +#endif + + weak_obj_cache = rb_class_new_instance(0, NULL, cache_class); + rb_const_set(internal, rb_intern("OBJECT_CACHE"), weak_obj_cache); + rb_const_set(internal, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG)); + rb_const_set(internal, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE)); +} + +static VALUE ObjectCache_GetKey(const void *key) { + VALUE key_val = (VALUE)key; + PBRUBY_ASSERT((key_val & 3) == 0); + // Ensure the key can be stored as a Fixnum since 1 bit is needed for + // FIXNUM_FLAG and 1 bit is needed for the sign bit. + VALUE new_key = LL2NUM(key_val >> 2); + PBRUBY_ASSERT(FIXNUM_P(new_key)); + return new_key; +} + +VALUE ObjectCache_TryAdd(const void *key, VALUE val) { + VALUE key_val = ObjectCache_GetKey(key); + return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val); +} + +// Returns the cached object for this key, if any. Otherwise returns Qnil. +VALUE ObjectCache_Get(const void *key) { + VALUE key_val = ObjectCache_GetKey(key); + return rb_funcall(weak_obj_cache, item_get, 1, key_val); +} + +/* + * call-seq: + * Google::Protobuf.discard_unknown(msg) + * + * Discard unknown fields in the given message object and recursively discard + * unknown fields in submessages. + */ +static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) { + const upb_MessageDef *m; + upb_Message *msg = Message_GetMutable(msg_rb, &m); + if (!upb_Message_DiscardUnknown(msg, m, 128)) { + rb_raise(rb_eRuntimeError, "Messages nested too deeply."); + } + + return Qnil; +} + +/* + * call-seq: + * Google::Protobuf.deep_copy(obj) => copy_of_obj + * + * Performs a deep copy of a RepeatedField instance, a Map instance, or a + * message object, recursively copying its members. + */ +VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) { + VALUE klass = CLASS_OF(obj); + if (klass == cRepeatedField) { + return RepeatedField_deep_copy(obj); + } else if (klass == cMap) { + return Map_deep_copy(obj); + } else { + VALUE new_arena_rb = Arena_new(); + upb_Arena *new_arena = Arena_get(new_arena_rb); + const upb_MessageDef *m; + const upb_Message *msg = Message_Get(obj, &m); + upb_Message *new_msg = Message_deep_copy(msg, m, new_arena); + return Message_GetRubyWrapper(new_msg, m, new_arena_rb); + } +} + +// ----------------------------------------------------------------------------- +// Initialization/entry point. +// ----------------------------------------------------------------------------- + +// This must be named "Init_protobuf_c" because the Ruby module is named +// "protobuf_c" -- the VM looks for this symbol in our .so. +__attribute__((visibility("default"))) void Init_protobuf_c() { + VALUE google = rb_define_module("Google"); + VALUE protobuf = rb_define_module_under(google, "Protobuf"); + + ObjectCache_Init(protobuf); + Arena_register(protobuf); + Defs_register(protobuf); + RepeatedField_register(protobuf); + Map_register(protobuf); + Message_register(protobuf); + + cParseError = rb_const_get(protobuf, rb_intern("ParseError")); + rb_gc_register_mark_object(cParseError); + cTypeError = rb_const_get(protobuf, rb_intern("TypeError")); + rb_gc_register_mark_object(cTypeError); + + rb_define_singleton_method(protobuf, "discard_unknown", + Google_Protobuf_discard_unknown, 1); + rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy, + 1); +} + +// ----------------------------------------------------------------------------- +// Utilities +// ----------------------------------------------------------------------------- + +// Raises a Ruby error if val is frozen in Ruby or UPB. +void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen) { + if (RB_UNLIKELY(rb_obj_frozen_p(val)||upb_frozen)) { + rb_error_frozen_object(val); + } +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.h new file mode 100755 index 00000000..20dc9f2e --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/protobuf.h @@ -0,0 +1,108 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ +#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ + +// Ruby 3+ defines NDEBUG itself, see: https://bugs.ruby-lang.org/issues/18777 +#ifdef NDEBUG +#include +#else +#include +#undef NDEBUG +#endif + +#include + +#if RUBY_API_VERSION_CODE < 20700 +#error Protobuf requires Ruby >= 2.7 +#endif + +#include // Must be included after the NDEBUG logic above. +#include +#include + +#include "defs.h" +#include "ruby-upb.h" + +// These operate on a map field (i.e., a repeated field of submessages whose +// submessage type is a map-entry msgdef). +const upb_FieldDef* map_field_key(const upb_FieldDef* field); +const upb_FieldDef* map_field_value(const upb_FieldDef* field); + +// ----------------------------------------------------------------------------- +// Arena +// ----------------------------------------------------------------------------- + +// A Ruby object that wraps an underlying upb_Arena. Any objects that are +// allocated from this arena should reference the Arena in rb_gc_mark(), to +// ensure that the object's underlying memory outlives any Ruby object that can +// reach it. + +VALUE Arena_new(); +upb_Arena* Arena_get(VALUE arena); + +// Fuses this arena to another, throwing a Ruby exception if this is not +// possible. +void Arena_fuse(VALUE arena, upb_Arena* other); + +// ----------------------------------------------------------------------------- +// ObjectCache +// ----------------------------------------------------------------------------- + +// Global object cache from upb array/map/message/symtab to wrapper object. +// +// This is a conceptually "weak" cache, in that it does not prevent "val" from +// being collected (though in Ruby <2.7 is it effectively strong, due to +// implementation limitations). + +// Tries to add a new entry to the cache, returning the newly installed value or +// the pre-existing entry. +VALUE ObjectCache_TryAdd(const void* key, VALUE val); + +// Returns the cached object for this key, if any. Otherwise returns Qnil. +VALUE ObjectCache_Get(const void* key); + +// ----------------------------------------------------------------------------- +// StringBuilder, for inspect +// ----------------------------------------------------------------------------- + +struct StringBuilder; +typedef struct StringBuilder StringBuilder; + +StringBuilder* StringBuilder_New(); +void StringBuilder_Free(StringBuilder* b); +void StringBuilder_Printf(StringBuilder* b, const char* fmt, ...); +VALUE StringBuilder_ToRubyString(StringBuilder* b); + +void StringBuilder_PrintMsgval(StringBuilder* b, upb_MessageValue val, + TypeInfo info); + +// ----------------------------------------------------------------------------- +// Utilities. +// ----------------------------------------------------------------------------- + +extern VALUE cTypeError; + +#ifdef NDEBUG +#define PBRUBY_ASSERT(expr) \ + do { \ + } while (false && (expr)) +#else +#define PBRUBY_ASSERT(expr) \ + if (!(expr)) \ + rb_bug("Assertion failed at %s:%d, expr: %s", __FILE__, __LINE__, #expr) +#endif + +// Raises a Ruby error if val is frozen in Ruby or upb_frozen is true. +void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen); + +#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)var + +#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.c new file mode 100755 index 00000000..2d19c164 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.c @@ -0,0 +1,691 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "repeated_field.h" + +#include "convert.h" +#include "defs.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Repeated field container type. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_Array* array; // Can get as mutable when non-frozen. + TypeInfo type_info; + VALUE type_class; // To GC-root the msgdef/enumdef in type_info. + VALUE arena; // To GC-root the upb_Array. +} RepeatedField; + +VALUE cRepeatedField; + +static void RepeatedField_mark(void* _self) { + RepeatedField* self = (RepeatedField*)_self; + rb_gc_mark(self->type_class); + rb_gc_mark(self->arena); +} + +const rb_data_type_t RepeatedField_type = { + "Google::Protobuf::RepeatedField", + {RepeatedField_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static RepeatedField* ruby_to_RepeatedField(VALUE _self) { + RepeatedField* self; + TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self); + return self; +} + +static upb_Array* RepeatedField_GetMutable(VALUE _self) { + const upb_Array* array = ruby_to_RepeatedField(_self)->array; + Protobuf_CheckNotFrozen(_self, upb_Array_IsFrozen(array)); + return (upb_Array*)array; +} + +VALUE RepeatedField_alloc(VALUE klass) { + RepeatedField* self = ALLOC(RepeatedField); + self->arena = Qnil; + self->type_class = Qnil; + self->array = NULL; + return TypedData_Wrap_Struct(klass, &RepeatedField_type, self); +} + +VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f) { + PBRUBY_ASSERT(upb_FieldDef_IsRepeated(f)); + VALUE val = ObjectCache_Get(f); + + if (val == Qnil) { + val = RepeatedField_alloc(cRepeatedField); + RepeatedField* self; + TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self); + self->arena = Arena_new(); + TypeInfo type_info = TypeInfo_get(f); + self->array = upb_Array_New(Arena_get(self->arena), type_info.type); + self->type_info = type_info; + if (self->type_info.type == kUpb_CType_Message) { + self->type_class = Descriptor_DefToClass(type_info.def.msgdef); + } + val = ObjectCache_TryAdd(f, RepeatedField_freeze(val)); + } + PBRUBY_ASSERT(RB_OBJ_FROZEN(val)); + PBRUBY_ASSERT(upb_Array_IsFrozen(ruby_to_RepeatedField(val)->array)); + return val; +} + +VALUE RepeatedField_GetRubyWrapper(const upb_Array* array, TypeInfo type_info, + VALUE arena) { + PBRUBY_ASSERT(array); + PBRUBY_ASSERT(arena != Qnil); + VALUE val = ObjectCache_Get(array); + + if (val == Qnil) { + val = RepeatedField_alloc(cRepeatedField); + RepeatedField* self; + TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self); + self->array = array; + self->arena = arena; + self->type_info = type_info; + if (self->type_info.type == kUpb_CType_Message) { + self->type_class = Descriptor_DefToClass(type_info.def.msgdef); + } + val = ObjectCache_TryAdd(array, val); + } + + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type); + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef == + type_info.def.msgdef); + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->array == array); + return val; +} + +static VALUE RepeatedField_new_this_type(RepeatedField* from) { + VALUE arena_rb = Arena_new(); + upb_Array* array = upb_Array_New(Arena_get(arena_rb), from->type_info.type); + VALUE ret = RepeatedField_GetRubyWrapper(array, from->type_info, arena_rb); + PBRUBY_ASSERT(ruby_to_RepeatedField(ret)->type_class == from->type_class); + return ret; +} + +void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array, + TypeInfo info) { + bool first = true; + StringBuilder_Printf(b, "["); + size_t n = array ? upb_Array_Size(array) : 0; + for (size_t i = 0; i < n; i++) { + if (first) { + first = false; + } else { + StringBuilder_Printf(b, ", "); + } + StringBuilder_PrintMsgval(b, upb_Array_Get(array, i), info); + } + StringBuilder_Printf(b, "]"); +} + +VALUE RepeatedField_deep_copy(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + VALUE new_rptfield = RepeatedField_new_this_type(self); + RepeatedField* new_self = ruby_to_RepeatedField(new_rptfield); + VALUE arena_rb = new_self->arena; + upb_Array* new_array = RepeatedField_GetMutable(new_rptfield); + upb_Arena* arena = Arena_get(arena_rb); + size_t elements = upb_Array_Size(self->array); + + upb_Array_Resize(new_array, elements, arena); + + size_t size = upb_Array_Size(self->array); + for (size_t i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + upb_MessageValue copy = Msgval_DeepCopy(msgval, self->type_info, arena); + upb_Array_Set(new_array, i, copy); + } + + return new_rptfield; +} + +const upb_Array* RepeatedField_GetUpbArray(VALUE val, const upb_FieldDef* field, + upb_Arena* arena) { + RepeatedField* self; + TypeInfo type_info = TypeInfo_get(field); + + if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || + RTYPEDDATA_TYPE(val) != &RepeatedField_type) { + rb_raise(cTypeError, "Expected repeated field array"); + } + + self = ruby_to_RepeatedField(val); + if (self->type_info.type != type_info.type) { + rb_raise(cTypeError, "Repeated field array has wrong element type"); + } + + if (self->type_info.def.msgdef != type_info.def.msgdef) { + rb_raise(cTypeError, "Repeated field array has wrong message/enum class"); + } + + Arena_fuse(self->arena, arena); + return self->array; +} + +static int index_position(VALUE _index, RepeatedField* repeated_field) { + int index = NUM2INT(_index); + if (index < 0) index += upb_Array_Size(repeated_field->array); + return index; +} + +static VALUE RepeatedField_subarray(RepeatedField* self, long beg, long len) { + size_t size = upb_Array_Size(self->array); + VALUE ary = rb_ary_new2(size); + long i; + + for (i = beg; i < beg + len; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_ary_push(ary, elem); + } + return ary; +} + +/* + * call-seq: + * RepeatedField.each(&block) + * + * Invokes the block once for each element of the repeated field. RepeatedField + * also includes Enumerable; combined with this method, the repeated field thus + * acts like an ordinary Ruby sequence. + */ +static VALUE RepeatedField_each(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + int i; + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_yield(val); + } + return _self; +} + +/* + * call-seq: + * RepeatedField.[](index) => value + * + * Accesses the element at the given index. Returns nil on out-of-bounds + */ +static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + long size = upb_Array_Size(self->array); + + VALUE arg = argv[0]; + long beg, len; + + if (argc == 1) { + if (FIXNUM_P(arg)) { + /* standard case */ + upb_MessageValue msgval; + int index = index_position(argv[0], self); + if (index < 0 || (size_t)index >= upb_Array_Size(self->array)) { + return Qnil; + } + msgval = upb_Array_Get(self->array, index); + return Convert_UpbToRuby(msgval, self->type_info, self->arena); + } else { + /* check if idx is Range */ + switch (rb_range_beg_len(arg, &beg, &len, size, 0)) { + case Qfalse: + break; + case Qnil: + return Qnil; + default: + return RepeatedField_subarray(self, beg, len); + } + } + } + + /* assume 2 arguments */ + beg = NUM2LONG(argv[0]); + len = NUM2LONG(argv[1]); + if (beg < 0) { + beg += size; + } + if (beg >= size) { + return Qnil; + } + return RepeatedField_subarray(self, beg, len); +} + +/* + * call-seq: + * RepeatedField.[]=(index, value) + * + * Sets the element at the given index. On out-of-bounds assignments, extends + * the array and fills the hole (if any) with default values. + */ +static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena); + + int index = index_position(_index, self); + if (index < 0 || index >= (INT_MAX - 1)) { + return Qnil; + } + + if (index >= size) { + upb_Array_Resize(array, index + 1, arena); + upb_MessageValue fill; + memset(&fill, 0, sizeof(fill)); + for (int i = size; i < index; i++) { + // Fill default values. + // TODO: should this happen at the upb level? + upb_Array_Set(array, i, fill); + } + } + + upb_Array_Set(array, index, msgval); + return Qnil; +} + +/* + * call-seq: + * RepeatedField.push(value, ...) + * + * Adds a new element to the repeated field. + */ +static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_Array* array = RepeatedField_GetMutable(_self); + int i; + + for (i = 0; i < argc; i++) { + upb_MessageValue msgval = + Convert_RubyToUpb(argv[i], "", self->type_info, arena); + upb_Array_Append(array, msgval, arena); + } + + return _self; +} + +/* + * call-seq: + * RepeatedField.<<(value) + * + * Adds a new element to the repeated field. + */ +static VALUE RepeatedField_push(VALUE _self, VALUE val) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_Array* array = RepeatedField_GetMutable(_self); + + upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena); + upb_Array_Append(array, msgval, arena); + + return _self; +} + +/* + * Private ruby method, used by RepeatedField.pop + */ +static VALUE RepeatedField_pop_one(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + size_t size = upb_Array_Size(self->array); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_MessageValue last; + VALUE ret; + + if (size == 0) { + return Qnil; + } + + last = upb_Array_Get(self->array, size - 1); + ret = Convert_UpbToRuby(last, self->type_info, self->arena); + + upb_Array_Resize(array, size - 1, Arena_get(self->arena)); + return ret; +} + +/* + * call-seq: + * RepeatedField.replace(list) + * + * Replaces the contents of the repeated field with the given list of elements. + */ +static VALUE RepeatedField_replace(VALUE _self, VALUE list) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Array* array = RepeatedField_GetMutable(_self); + int i; + + Check_Type(list, T_ARRAY); + upb_Array_Resize(array, 0, Arena_get(self->arena)); + + for (i = 0; i < RARRAY_LEN(list); i++) { + RepeatedField_push(_self, rb_ary_entry(list, i)); + } + + return list; +} + +/* + * call-seq: + * RepeatedField.clear + * + * Clears (removes all elements from) this repeated field. + */ +static VALUE RepeatedField_clear(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_Array_Resize(array, 0, Arena_get(self->arena)); + return _self; +} + +/* + * call-seq: + * RepeatedField.length + * + * Returns the length of this repeated field. + */ +static VALUE RepeatedField_length(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + return INT2NUM(upb_Array_Size(self->array)); +} + +/* + * call-seq: + * RepeatedField.dup => repeated_field + * + * Duplicates this repeated field with a shallow copy. References to all + * non-primitive element objects (e.g., submessages) are shared. + */ +static VALUE RepeatedField_dup(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + VALUE new_rptfield = RepeatedField_new_this_type(self); + RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield); + upb_Array* new_array = RepeatedField_GetMutable(new_rptfield); + upb_Arena* arena = Arena_get(new_rptfield_self->arena); + int size = upb_Array_Size(self->array); + int i; + + Arena_fuse(self->arena, arena); + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + upb_Array_Append(new_array, msgval, arena); + } + + return new_rptfield; +} + +/* + * call-seq: + * RepeatedField.to_ary => array + * + * Used when converted implicitly into array, e.g. compared to an Array. + * Also called as a fallback of Object#to_a + */ +VALUE RepeatedField_to_ary(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + VALUE ary = rb_ary_new2(size); + int i; + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_ary_push(ary, val); + } + + return ary; +} + +/* + * call-seq: + * RepeatedField.==(other) => boolean + * + * Compares this repeated field to another. Repeated fields are equal if their + * element types are equal, their lengths are equal, and each element is equal. + * Elements are compared as per normal Ruby semantics, by calling their :== + * methods (or performing a more efficient comparison for primitive types). + * + * Repeated fields with dissimilar element types are never equal, even if value + * comparison (for example, between integers and floats) would have otherwise + * indicated that every element has equal value. + */ +VALUE RepeatedField_eq(VALUE _self, VALUE _other) { + RepeatedField* self; + RepeatedField* other; + + if (_self == _other) { + return Qtrue; + } + + if (TYPE(_other) == T_ARRAY) { + VALUE self_ary = RepeatedField_to_ary(_self); + return rb_equal(self_ary, _other); + } + + self = ruby_to_RepeatedField(_self); + other = ruby_to_RepeatedField(_other); + size_t n = upb_Array_Size(self->array); + + if (self->type_info.type != other->type_info.type || + self->type_class != other->type_class || + upb_Array_Size(other->array) != n) { + return Qfalse; + } + + for (size_t i = 0; i < n; i++) { + upb_MessageValue val1 = upb_Array_Get(self->array, i); + upb_MessageValue val2 = upb_Array_Get(other->array, i); + if (!Msgval_IsEqual(val1, val2, self->type_info)) { + return Qfalse; + } + } + + return Qtrue; +} + +/* + * call-seq: + * RepeatedField.frozen? => bool + * + * Returns true if the repeated field is frozen in either Ruby or the underlying + * representation. Freezes the Ruby repeated field object if it is not already + * frozen in Ruby but it is frozen in the underlying representation. + */ +VALUE RepeatedField_frozen(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + if (!upb_Array_IsFrozen(self->array)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * call-seq: + * RepeatedField.freeze => self + * + * Freezes the repeated field object. We have to intercept this so we can freeze + * the underlying representation, not just the Ruby wrapper. + */ +VALUE RepeatedField_freeze(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Array_IsFrozen(self->array)); + return _self; + } + + if (!upb_Array_IsFrozen(self->array)) { + if (self->type_info.type == kUpb_CType_Message) { + upb_Array_Freeze(RepeatedField_GetMutable(_self), + upb_MessageDef_MiniTable(self->type_info.def.msgdef)); + } else { + upb_Array_Freeze(RepeatedField_GetMutable(_self), NULL); + } + } + RB_OBJ_FREEZE(_self); + return _self; +} + +/* + * call-seq: + * RepeatedField.hash => hash_value + * + * Returns a hash value computed from this repeated field's elements. + */ +VALUE RepeatedField_hash(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + uint64_t hash = 0; + size_t n = upb_Array_Size(self->array); + + for (size_t i = 0; i < n; i++) { + upb_MessageValue val = upb_Array_Get(self->array, i); + hash = Msgval_GetHash(val, self->type_info, hash); + } + + return LL2NUM(hash); +} + +/* + * call-seq: + * RepeatedField.+(other) => repeated field + * + * Returns a new repeated field that contains the concatenated list of this + * repeated field's elements and other's elements. The other (second) list may + * be either another repeated field or a Ruby array. + */ +VALUE RepeatedField_plus(VALUE _self, VALUE list) { + VALUE dupped_ = RepeatedField_dup(_self); + + if (TYPE(list) == T_ARRAY) { + int i; + for (i = 0; i < RARRAY_LEN(list); i++) { + VALUE elem = rb_ary_entry(list, i); + RepeatedField_push(dupped_, elem); + } + } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) && + RTYPEDDATA_TYPE(list) == &RepeatedField_type) { + RepeatedField* self = ruby_to_RepeatedField(_self); + RepeatedField* list_rptfield = ruby_to_RepeatedField(list); + RepeatedField* dupped = ruby_to_RepeatedField(dupped_); + upb_Array* dupped_array = RepeatedField_GetMutable(dupped_); + upb_Arena* arena = Arena_get(dupped->arena); + Arena_fuse(list_rptfield->arena, arena); + int size = upb_Array_Size(list_rptfield->array); + int i; + + if (self->type_info.type != list_rptfield->type_info.type || + self->type_class != list_rptfield->type_class) { + rb_raise(rb_eArgError, + "Attempt to append RepeatedField with different element type."); + } + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(list_rptfield->array, i); + upb_Array_Append(dupped_array, msgval, arena); + } + } else { + rb_raise(rb_eArgError, "Unknown type appending to RepeatedField"); + } + + return dupped_; +} + +/* + * call-seq: + * RepeatedField.concat(other) => self + * + * concats the passed in array to self. Returns a Ruby array. + */ +VALUE RepeatedField_concat(VALUE _self, VALUE list) { + int i; + + Check_Type(list, T_ARRAY); + for (i = 0; i < RARRAY_LEN(list); i++) { + RepeatedField_push(_self, rb_ary_entry(list, i)); + } + return _self; +} + +/* + * call-seq: + * RepeatedField.new(type, type_class = nil, initial_elems = []) + * + * Creates a new repeated field. The provided type must be a Ruby symbol, and + * can take on the same values as those accepted by FieldDescriptor#type=. If + * the type is :message or :enum, type_class must be non-nil, and must be the + * Ruby class or module returned by Descriptor#msgclass or + * EnumDescriptor#enummodule, respectively. An initial list of elements may also + * be provided. + */ +VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena; + VALUE ary = Qnil; + + self->arena = Arena_new(); + arena = Arena_get(self->arena); + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected at least 1 argument."); + } + + self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary); + self->array = upb_Array_New(arena, self->type_info.type); + VALUE stored_val = ObjectCache_TryAdd(self->array, _self); + PBRUBY_ASSERT(stored_val == _self); + + if (ary != Qnil) { + if (!RB_TYPE_P(ary, T_ARRAY)) { + rb_raise(rb_eArgError, "Expected array as initialize argument"); + } + for (int i = 0; i < RARRAY_LEN(ary); i++) { + RepeatedField_push(_self, rb_ary_entry(ary, i)); + } + } + return Qnil; +} + +void RepeatedField_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "RepeatedField", rb_cObject); + rb_define_alloc_func(klass, RepeatedField_alloc); + rb_gc_register_address(&cRepeatedField); + cRepeatedField = klass; + + rb_define_method(klass, "initialize", RepeatedField_init, -1); + rb_define_method(klass, "each", RepeatedField_each, 0); + rb_define_method(klass, "[]", RepeatedField_index, -1); + rb_define_method(klass, "at", RepeatedField_index, -1); + rb_define_method(klass, "[]=", RepeatedField_index_set, 2); + rb_define_method(klass, "push", RepeatedField_push_vararg, -1); + rb_define_method(klass, "<<", RepeatedField_push, 1); + rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0); + rb_define_method(klass, "replace", RepeatedField_replace, 1); + rb_define_method(klass, "clear", RepeatedField_clear, 0); + rb_define_method(klass, "length", RepeatedField_length, 0); + rb_define_method(klass, "size", RepeatedField_length, 0); + rb_define_method(klass, "dup", RepeatedField_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", RepeatedField_dup, 0); + rb_define_method(klass, "==", RepeatedField_eq, 1); + rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0); + rb_define_method(klass, "freeze", RepeatedField_freeze, 0); + rb_define_method(klass, "frozen?", RepeatedField_frozen, 0); + rb_define_method(klass, "hash", RepeatedField_hash, 0); + rb_define_method(klass, "+", RepeatedField_plus, 1); + rb_define_method(klass, "concat", RepeatedField_concat, 1); + rb_include_module(klass, rb_mEnumerable); +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.h new file mode 100755 index 00000000..1ae31cfc --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/repeated_field.h @@ -0,0 +1,45 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_REPEATED_FIELD_H_ +#define RUBY_PROTOBUF_REPEATED_FIELD_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Returns a frozen sentinel Ruby wrapper object for an empty upb_Array of the +// type specified by the field. Creates one if it doesn't exist. +VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f); + +// Returns a Ruby wrapper object for the given upb_Array, which will be created +// if one does not exist already. +VALUE RepeatedField_GetRubyWrapper(const upb_Array* msg, TypeInfo type_info, + VALUE arena); + +// Gets the underlying upb_Array for this Ruby RepeatedField object, which must +// have a type that matches |f|. If this is not a repeated field or the type +// doesn't match, raises an exception. +const upb_Array* RepeatedField_GetUpbArray(VALUE value, const upb_FieldDef* f, + upb_Arena* arena); + +// Implements #inspect for this repeated field by appending its contents to |b|. +void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array, + TypeInfo info); + +// Returns a deep copy of this RepeatedField object. +VALUE RepeatedField_deep_copy(VALUE obj); + +// Ruby class of Google::Protobuf::RepeatedField. +extern VALUE cRepeatedField; + +// Call at startup to register all types in this module. +void RepeatedField_register(VALUE module); + +// Recursively freeze RepeatedField. +VALUE RepeatedField_freeze(VALUE _self); + +#endif // RUBY_PROTOBUF_REPEATED_FIELD_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.c new file mode 100755 index 00000000..c7c4526b --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.c @@ -0,0 +1,16662 @@ +/* Amalgamated source file */ +#include "ruby-upb.h" + +/* + * This is where we define internal portability macros used across upb. + * + * All of these macros are undef'd in undef.inc to avoid leaking them to users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port/def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port/undef.inc" + * + * This file is private and must not be included by users! + */ + +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +#error upb requires C99 or C++14 or MSVC >= 2015. +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef UINTPTR_MAX +Error, UINTPTR_MAX is undefined +#endif + +#if UINTPTR_MAX == 0xffffffff +#define UPB_SIZE(size32, size64) size32 +#else +#define UPB_SIZE(size32, size64) size64 +#endif + +/* If we always read/write as a consistent type to each address, this shouldn't + * violate aliasing. + */ +#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) + +#define UPB_MAPTYPE_STRING 0 + +// UPB_EXPORT: always generate a public symbol. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) +#else +#define UPB_EXPORT +#endif + +// UPB_INLINE: inline if possible, emit standalone code if required. +#ifdef __cplusplus +#define UPB_INLINE inline +#elif defined (__GNUC__) || defined(__clang__) +#define UPB_INLINE static __inline__ +#else +#define UPB_INLINE static +#endif + +#ifdef UPB_BUILD_API +#define UPB_API UPB_EXPORT +#define UPB_API_INLINE UPB_EXPORT +#else +#define UPB_API +#define UPB_API_INLINE UPB_INLINE +#endif + +#ifdef EXPORT_UPBC +#define UPBC_API UPB_EXPORT +#else +#define UPBC_API +#endif + +#define UPB_MALLOC_ALIGN 8 +#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) +#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) +#ifdef __clang__ +#define UPB_ALIGN_OF(type) _Alignof(type) +#else +#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) +#endif + +#ifdef _MSC_VER +// Some versions of our Windows compiler don't support the C11 syntax. +#define UPB_ALIGN_AS(x) __declspec(align(x)) +#else +#define UPB_ALIGN_AS(x) _Alignas(x) +#endif + +// Hints to the compiler about likely/unlikely branches. +#if defined (__GNUC__) || defined(__clang__) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) +#else +#define UPB_LIKELY(x) (x) +#define UPB_UNLIKELY(x) (x) +#endif + +// Macros for function attributes on compilers that support them. +#ifdef __GNUC__ +#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static +#define UPB_NOINLINE __attribute__((noinline)) +#define UPB_NORETURN __attribute__((__noreturn__)) +#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg))) +#elif defined(_MSC_VER) +#define UPB_NOINLINE +#define UPB_FORCEINLINE static +#define UPB_NORETURN __declspec(noreturn) +#define UPB_PRINTF(str, first_vararg) +#else /* !defined(__GNUC__) */ +#define UPB_FORCEINLINE static +#define UPB_NOINLINE +#define UPB_NORETURN +#define UPB_PRINTF(str, first_vararg) +#endif + +#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)var + +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. +#ifdef NDEBUG +#ifdef __GNUC__ +#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() +#elif defined _MSC_VER +#define UPB_ASSUME(expr) if (!(expr)) __assume(0) +#else +#define UPB_ASSUME(expr) do {} while (false && (expr)) +#endif +#else +#define UPB_ASSUME(expr) assert(expr) +#endif + +/* UPB_ASSERT(): in release mode, we use the expression without letting it be + * evaluated. This prevents "unused variable" warnings. */ +#ifdef NDEBUG +#define UPB_ASSERT(expr) do {} while (false && (expr)) +#else +#define UPB_ASSERT(expr) assert(expr) +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) +#elif defined(_MSC_VER) +#define UPB_UNREACHABLE() \ + do { \ + assert(0); \ + __assume(0); \ + } while (0) +#else +#define UPB_UNREACHABLE() do { assert(0); } while(0) +#endif + +/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */ +#ifdef __APPLE__ +#define UPB_SETJMP(buf) _setjmp(buf) +#define UPB_LONGJMP(buf, val) _longjmp(buf, val) +#elif defined(WASM_WAMR) +#define UPB_SETJMP(buf) 0 +#define UPB_LONGJMP(buf, val) abort() +#else +#define UPB_SETJMP(buf) setjmp(buf) +#define UPB_LONGJMP(buf, val) longjmp(buf, val) +#endif + +#ifdef __GNUC__ +#define UPB_USE_C11_ATOMICS +#define UPB_ATOMIC(T) _Atomic(T) +#else +#define UPB_ATOMIC(T) T +#endif + +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + +#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only + +#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY +#define UPB_ONLYBITS(x) x +#else +#define UPB_ONLYBITS(x) UPB_PRIVATE(x) +#endif + +/* Configure whether fasttable is switched on or not. *************************/ + +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) +#define UPB_FASTTABLE_SUPPORTED 1 +#else +#define UPB_FASTTABLE_SUPPORTED 0 +#endif + +/* define UPB_ENABLE_FASTTABLE to force fast table support. + * This is useful when we want to ensure we are really getting fasttable, + * for example for testing or benchmarking. */ +#if defined(UPB_ENABLE_FASTTABLE) +#if !UPB_FASTTABLE_SUPPORTED +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. +#endif +#define UPB_FASTTABLE 1 +/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. + * This is useful for releasing code that might be used on multiple platforms, + * for example the PHP or Ruby C extensions. */ +#elif defined(UPB_TRY_ENABLE_FASTTABLE) +#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED +#else +#define UPB_FASTTABLE 0 +#endif + +/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully + * degrade to non-fasttable if the runtime or platform do not support it. */ +#if !UPB_FASTTABLE +#define UPB_FASTTABLE_INIT(...) +#define UPB_FASTTABLE_MASK(mask) -1 +#else +#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ +#define UPB_FASTTABLE_MASK(mask) mask +#endif + +#undef UPB_FASTTABLE_SUPPORTED + +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ + +/* Due to preprocessor limitations, the conditional logic for setting + * UPN_CLANG_ASAN below cannot be consolidated into a portable one-liner. + * See https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. + */ +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define UPB_CLANG_ASAN 1 +#else +#define UPB_CLANG_ASAN 0 +#endif +#else +#define UPB_CLANG_ASAN 0 +#endif + +#if defined(__SANITIZE_ADDRESS__) || UPB_CLANG_ASAN +#define UPB_ASAN 1 +#define UPB_ASAN_GUARD_SIZE 32 +#ifdef __cplusplus + extern "C" { +#endif +void __asan_poison_memory_region(void const volatile *addr, size_t size); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#ifdef __cplusplus +} /* extern "C" */ +#endif +#define UPB_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) +#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) +#else +#define UPB_ASAN 0 +#define UPB_ASAN_GUARD_SIZE 0 +#define UPB_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif + +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_CLOSED_ENUM_CHECKING +#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 1 +#else +#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 0 +#endif + +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif + +#if defined(UPB_IS_GOOGLE3) && \ + (!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) +#define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() +#else +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init +#endif + +#undef UPB_IS_GOOGLE3 + +// Linker arrays combine elements from multiple translation units into a single +// array that can be iterated over at runtime. +// +// It is an alternative to pre-main "registration" functions. +// +// Usage: +// +// // In N translation units. +// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; +// +// // At runtime: +// UPB_LINKARR_DECLARE(foo_array, int); +// +// void f() { +// const int* start = UPB_LINKARR_START(foo_array); +// const int* stop = UPB_LINKARR_STOP(foo_array); +// for (const int* p = start; p < stop; p++) { +// // Windows can introduce zero padding, so we have to skip zeroes. +// if (*p != 0) { +// vec.push_back(*p); +// } +// } +// } + +#if defined(__ELF__) || defined(__wasm__) + +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("linkarr_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name; \ + extern type const __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(__MACH__) + +/* As described in: https://stackoverflow.com/a/22366882 */ +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("__DATA,__la_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name __asm( \ + "section$start$__DATA$__la_" #name); \ + extern type const __stop_linkarr_##name __asm( \ + "section$end$__DATA$" \ + "__la_" #name); \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(_MSC_VER) && defined(__clang__) + +/* See: + * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 + * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 + * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ + +// Usage of __attribute__ here probably means this is Clang-specific, and would +// not work on MSVC. +#define UPB_LINKARR_APPEND(name) \ + __declspec(allocate("la_" #name "$j")) __attribute__((retain, used)) +#define UPB_LINKARR_DECLARE(name, type) \ + __declspec(allocate("la_" #name "$a")) type __start_linkarr_##name; \ + __declspec(allocate("la_" #name "$z")) type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0} +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#else + +// Linker arrays are not supported on this platform. Make appends a no-op but +// don't define the other macros. +#define UPB_LINKARR_APPEND(name) + +#endif + +// Future versions of upb will include breaking changes to some APIs. +// This macro can be set to enable these API changes ahead of time, so that +// user code can be updated before upgrading versions of protobuf. +#ifdef UPB_FUTURE_BREAKING_CHANGES + +// Properly enforce closed enums in python. +// Owner: mkruskal@ +#define UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT 1 + +#endif + + +#include +#include +#include +#include +#include + +// Must be last. + +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; +} + +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } + +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; +} + +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} + +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + + +static const char* _upb_EpsCopyInputStream_NoOpCallback( + upb_EpsCopyInputStream* e, const char* old_end, const char* new_start) { + return new_start; +} + +const char* _upb_EpsCopyInputStream_IsDoneFallbackNoCallback( + upb_EpsCopyInputStream* e, const char* ptr, int overrun) { + return _upb_EpsCopyInputStream_IsDoneFallbackInline( + e, ptr, overrun, _upb_EpsCopyInputStream_NoOpCallback); +} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + int result; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; + +typedef struct { + upb_MessageValue value; + bool ignore; +} upb_JsonMessageValue; + +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; + +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); + +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; +} + +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; +} + +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); +} + +static void jsondec_seterrmsg(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); +} + +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + jsondec_seterrmsg(d, msg); + UPB_LONGJMP(d->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +// Advances d->ptr until the next non-whitespace character or to the end of +// the buffer. +static void jsondec_consumews(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } +} + +// Advances d->ptr until the next non-whitespace character. Postcondition that +// d->ptr is pointing at a valid non-whitespace character (will err if end of +// buffer is reached). +static void jsondec_skipws(jsondec* d) { + jsondec_consumews(d); + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF"); + } +} + +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} + +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} + +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} + +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } + +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} + +static int jsondec_rawpeek(jsondec* d) { + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF"); + } + + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + } +} + +/* JSON object/array **********************************************************/ + +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ + +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} + +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); + } + d->is_first = true; +} + +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; +} + +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} + +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} + +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); +} + +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); +} + +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; +} + +/* JSON number ****************************************************************/ + +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; + } + d->ptr++; + } + + return d->ptr != start; +} + +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } +} + +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; + + UPB_ASSERT(jsondec_rawpeek(d) == JD_NUMBER); + + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; + + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } + + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; + + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); + } + +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + // Copy the number into a null-terminated scratch buffer since strtod + // expects a null-terminated string. + char nullz[64]; + ptrdiff_t len = d->ptr - start; + if (len > (ptrdiff_t)(sizeof(nullz) - 1)) { + jsondec_err(d, "excessively long number"); + } + memcpy(nullz, start, len); + nullz[len] = '\0'; + + char* end; + double val = strtod(nullz, &end); + UPB_ASSERT(end - nullz == len); + + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } +} + +/* JSON string ****************************************************************/ + +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } +} + +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; + + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } + + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } + + return cp; +} + +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); + } + + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; +} + +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); + + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); + + *end = *buf + len; + *buf_end = *buf + size; +} + +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; + + jsondec_skipws(d); + + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } + + while (d->ptr < d->end) { + char ch = *d->ptr++; + + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } + + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; + } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized codepoint (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)ch < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; + } + } + +eof: + jsondec_err(d, "EOF inside string"); +} + +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; + } +} + +/* Base64 decoding for bytes fields. ******************************************/ + +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} + +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; + + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } + + if (val < 0) { + jsondec_err(d, "Corrupt base64"); + } + + return out; +} + +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; + } + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; +} + +/* Low-level integer parsing **************************************************/ + +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} + +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} + +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static void jsondec_checkempty(jsondec* d, upb_StringView str, + const upb_FieldDef* f) { + if (str.size != 0) return; + d->result = kUpb_JsonDecodeResult_OkWithEmptyStringNumerics; + upb_Status_SetErrorFormat(d->status, + "Empty string is not a valid number (field: %s). " + "This will be an error in a future version.", + upb_FieldDef_FullName(f)); +} + +/* Primitive value types ******************************************************/ + +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + jsondec_checkempty(d, str, f); + val.int64_val = jsondec_strtoint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; + } + + return val; +} + +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + jsondec_checkempty(d, str, f); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; + } + + return val; +} + +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (str.size == 0) { + jsondec_checkempty(d, str, f); + val.double_val = 0.0; + } else if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + char* end; + val.double_val = strtod(str.data, &end); + if (end != str.data + str.size) { + d->result = kUpb_JsonDecodeResult_OkWithEmptyStringNumerics; + upb_Status_SetErrorFormat( + d->status, + "Non-number characters in quoted number (field: %s). " + "This will be an error in a future version.", + upb_FieldDef_FullName(f)); + } + } + break; + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; + } + + return val; +} + +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); + } + return val; +} + +static upb_JsonMessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_JsonMessageValue val = {.ignore = false}; + if (ev) { + val.value.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.ignore = true; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_JsonMessageValue val = {.ignore = false}; + jsondec_null(d); + val.value.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return (upb_JsonMessageValue){.value = jsondec_int(d, f), + .ignore = false}; + } +} + +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; + + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } + } + + return val; +} + +/* Composite types (array/message/map) ****************************************/ + +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_JsonMessageValue elem = jsondec_value(d, f); + if (!elem.ignore) { + upb_Array_Append(arr, elem.value, d->arena); + } + } + jsondec_arrend(d); +} + +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_JsonMessageValue key, val; + key = jsondec_value(d, key_f); + UPB_ASSUME(!key.ignore); // Map key cannot be enum. + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + if (!val.ignore) { + upb_Map_Set(map, key.value, val.value, d->arena); + } + } + jsondec_objend(d); +} + +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } +} + +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(layout, d->arena); + upb_MessageValue val; + + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} + +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; + + name = jsondec_string(d); + jsondec_entrysep(d); + + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } + + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } + + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } + + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneofByDef(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_JsonMessageValue val = jsondec_value(d, f); + if (!val.ignore) { + upb_Message_SetFieldByDef(msg, f, val.value, d->arena); + } + } + + d->debug_field = preserved; +} + +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} + +static upb_MessageValue jsondec_nonenum(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + case kUpb_CType_Enum: + default: + UPB_UNREACHABLE(); + } +} + +static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + if (upb_FieldDef_CType(f) == kUpb_CType_Enum) { + return jsondec_enum(d, f); + } else { + return (upb_JsonMessageValue){.value = jsondec_nonenum(d, f), + .ignore = false}; + } +} + +/* Well-known types ***********************************************************/ + +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; + + UPB_ASSERT(digits <= 9); /* int can't overflow. */ + + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; +} + +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; + + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; + } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; +} + +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} + +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +} + +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + + if (str.size < 20) goto malformed; + + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); + + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + } + + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; + + if (ptr == end) goto malformed; + + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } + } + + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } + + upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), + seconds, d->arena); + upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, + d->arena); + return; + +malformed: + jsondec_err(d, "Malformed timestamp"); +} + +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + bool neg = false; + + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } + + if (neg) { + nanos.int32_val = -nanos.int32_val; + } + + upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), + seconds, d->arena); + upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, + d->arena); +} + +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_layout, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_arrend(d); +} + +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_layout, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_objend(d); +} + +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); + } + + upb_Message_SetFieldByDef(msg, f, val, d->arena); +} + +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; + + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; + } + + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; + + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } + } + + return ret; +} + +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; + } + upb_Array_Append(arr, val, d->arena); + } +} + +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); + } else { + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); + } +} + +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; + + val.str_val = type_url; + upb_Message_SetFieldByDef(msg, type_url_f, val, d->arena); + + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } + + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } + + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + + if (!type_m) { + jsondec_err(d, "Type was not found"); + } + + return type_m; +} + +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; + + jsondec_objstart(d); + + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); + } + } + + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } + + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + any_msg = upb_Message_New(any_layout, d->arena); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + d->ptr = saved_ptr; + d->end = saved_end; + } + + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + + jsondec_objend(d); + + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO: We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_SetFieldByDef(msg, value_f, encoded, d->arena); +} + +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_JsonMessageValue val = jsondec_value(d, value_f); + UPB_ASSUME(val.ignore == false); // Wrapper cannot be an enum. + upb_Message_SetFieldByDef(msg, value_f, val.value, d->arena); +} + +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); + } +} + +static int upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg, + const upb_MessageDef* const m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (UPB_SETJMP(d->err)) return kUpb_JsonDecodeResult_Error; + + jsondec_tomsg(d, msg, m); + + // Consume any trailing whitespace before checking if we read the entire + // input. + jsondec_consumews(d); + + if (d->ptr == d->end) { + return d->result; + } else { + jsondec_seterrmsg(d, "unexpected trailing characters"); + return kUpb_JsonDecodeResult_Error; + } +} + +int upb_JsonDecodeDetectingNonconformance(const char* buf, size_t size, + upb_Message* msg, + const upb_MessageDef* m, + const upb_DefPool* symtab, + int options, upb_Arena* arena, + upb_Status* status) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + jsondec d; + + if (size == 0) return true; + + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.result = kUpb_JsonDecodeResult_Ok; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; + + return upb_JsonDecoder_Decode(&d, msg, m); +} + + +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + UPB_LONGJMP(e->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(e->err, 1); +} + +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} + +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} + +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} + +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); + } +} + +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; + + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } + + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } + + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} + +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; + + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); + } + + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; + + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); +} + +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; + bool negative = false; + + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); + } + + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } + + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); +} + +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } +} + +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; + + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); + + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } +} + +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} + +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } + return true; +} + +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_GetFieldByDef(msg, val_f); + jsonenc_scalar(e, val, val_f); +} + +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; + + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; + + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} + +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_GetFieldByDef(msg, type_url_f).str_val; + upb_StringView value = upb_Message_GetFieldByDef(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_layout, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_GetFieldByDef(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_GetFieldByDef(msg, fields_f).map_val; + + if (fields) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + + size_t iter = kUpb_Map_Begin; + bool first = true; + + upb_MessageValue key, val; + while (upb_Map_Next(fields, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_GetFieldByDef(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO: do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + if (upb_JsonEncode_HandleSpecialDoubles(e, val.double_val)) { + jsonenc_err( + e, + "google.protobuf.Value cannot encode double values for " + "infinity or nan, because they would be parsed as a string"); + } + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + jsonenc_putstr(e, "{"); + + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + if (map) { + size_t iter = kUpb_Map_Begin; + bool first = true; + + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, key, key_f); + jsonenc_scalar(e, val, val_f); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); + } + + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} + +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; + + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_HasFieldByDef(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_GetFieldByDef(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +static size_t upb_JsonEncoder_Encode(jsonenc* const e, + const upb_Message* const msg, + const upb_MessageDef* const m, + const size_t size) { + if (UPB_SETJMP(e->err) != 0) return -1; + + jsonenc_msgfield(e, msg, m); + if (e->arena) upb_Arena_Free(e->arena); + return jsonenc_nullz(e, size); +} + +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; + + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; + + return upb_JsonEncoder_Encode(&e, msg, m, size); +} + + +#include + +// Must be last. + +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); + } +} + +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + + +#ifdef UPB_TRACING_ENABLED +#include +#endif + +#include +#include + + +// Must be last. + +static UPB_ATOMIC(size_t) max_block_size = 32 << 10; + +void upb_Arena_SetMaxBlockSize(size_t max) { max_block_size = max; } + +typedef struct upb_MemBlock { + // Atomic only for the benefit of SpaceAllocated(). + UPB_ATOMIC(struct upb_MemBlock*) next; + uint32_t size; + // Data follows. +} upb_MemBlock; + +typedef struct upb_ArenaInternal { + // upb_alloc* together with a low bit which signals if there is an initial + // block. + uintptr_t block_alloc; + + // When multiple arenas are fused together, each arena points to a parent + // arena (root points to itself). The root tracks how many live arenas + // reference it. + + // The low bit is tagged: + // 0: pointer to parent + // 1: count, left shifted by one + UPB_ATOMIC(uintptr_t) parent_or_count; + + // All nodes that are fused together are in a singly-linked list. + // == NULL at end of list. + UPB_ATOMIC(struct upb_ArenaInternal*) next; + + // The last element of the linked list. This is present only as an + // optimization, so that we do not have to iterate over all members for every + // fuse. Only significant for an arena root. In other cases it is ignored. + // == self when no other list members. + UPB_ATOMIC(struct upb_ArenaInternal*) tail; + + // Linked list of blocks to free/cleanup. Atomic only for the benefit of + // upb_Arena_SpaceAllocated(). + UPB_ATOMIC(upb_MemBlock*) blocks; +} upb_ArenaInternal; + +// All public + private state for an arena. +typedef struct { + upb_Arena head; + upb_ArenaInternal body; +} upb_ArenaState; + +typedef struct { + upb_ArenaInternal* root; + uintptr_t tagged_count; +} upb_ArenaRoot; + +static const size_t kUpb_MemblockReserve = + UPB_ALIGN_UP(sizeof(upb_MemBlock), UPB_MALLOC_ALIGN); + +// Extracts the (upb_ArenaInternal*) from a (upb_Arena*) +static upb_ArenaInternal* upb_Arena_Internal(const upb_Arena* a) { + return &((upb_ArenaState*)a)->body; +} + +static bool _upb_Arena_IsTaggedRefcount(uintptr_t parent_or_count) { + return (parent_or_count & 1) == 1; +} + +static bool _upb_Arena_IsTaggedPointer(uintptr_t parent_or_count) { + return (parent_or_count & 1) == 0; +} + +static uintptr_t _upb_Arena_RefCountFromTagged(uintptr_t parent_or_count) { + UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); + return parent_or_count >> 1; +} + +static uintptr_t _upb_Arena_TaggedFromRefcount(uintptr_t refcount) { + uintptr_t parent_or_count = (refcount << 1) | 1; + UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); + return parent_or_count; +} + +static upb_ArenaInternal* _upb_Arena_PointerFromTagged( + uintptr_t parent_or_count) { + UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); + return (upb_ArenaInternal*)parent_or_count; +} + +static uintptr_t _upb_Arena_TaggedFromPointer(upb_ArenaInternal* ai) { + uintptr_t parent_or_count = (uintptr_t)ai; + UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); + return parent_or_count; +} + +static upb_alloc* _upb_ArenaInternal_BlockAlloc(upb_ArenaInternal* ai) { + return (upb_alloc*)(ai->block_alloc & ~0x1); +} + +static uintptr_t _upb_Arena_MakeBlockAlloc(upb_alloc* alloc, bool has_initial) { + uintptr_t alloc_uint = (uintptr_t)alloc; + UPB_ASSERT((alloc_uint & 1) == 0); + return alloc_uint | (has_initial ? 1 : 0); +} + +static bool _upb_ArenaInternal_HasInitialBlock(upb_ArenaInternal* ai) { + return ai->block_alloc & 0x1; +} + +#ifdef UPB_TRACING_ENABLED +static void (*_init_arena_trace_handler)(const upb_Arena*, size_t size) = NULL; +static void (*_fuse_arena_trace_handler)(const upb_Arena*, + const upb_Arena*) = NULL; +static void (*_free_arena_trace_handler)(const upb_Arena*) = NULL; + +void upb_Arena_SetTraceHandler( + void (*initArenaTraceHandler)(const upb_Arena*, size_t size), + void (*fuseArenaTraceHandler)(const upb_Arena*, const upb_Arena*), + void (*freeArenaTraceHandler)(const upb_Arena*)) { + _init_arena_trace_handler = initArenaTraceHandler; + _fuse_arena_trace_handler = fuseArenaTraceHandler; + _free_arena_trace_handler = freeArenaTraceHandler; +} + +void upb_Arena_LogInit(const upb_Arena* arena, size_t size) { + if (_init_arena_trace_handler) { + _init_arena_trace_handler(arena, size); + } +} +void upb_Arena_LogFuse(const upb_Arena* arena1, const upb_Arena* arena2) { + if (_fuse_arena_trace_handler) { + _fuse_arena_trace_handler(arena1, arena2); + } +} +void upb_Arena_LogFree(const upb_Arena* arena) { + if (_free_arena_trace_handler) { + _free_arena_trace_handler(arena); + } +} +#endif // UPB_TRACING_ENABLED + +static upb_ArenaRoot _upb_Arena_FindRoot(upb_Arena* a) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + while (_upb_Arena_IsTaggedPointer(poc)) { + upb_ArenaInternal* next = _upb_Arena_PointerFromTagged(poc); + UPB_ASSERT(ai != next); + uintptr_t next_poc = + upb_Atomic_Load(&next->parent_or_count, memory_order_acquire); + + if (_upb_Arena_IsTaggedPointer(next_poc)) { + // To keep complexity down, we lazily collapse levels of the tree. This + // keeps it flat in the final case, but doesn't cost much incrementally. + // + // Path splitting keeps time complexity down, see: + // https://en.wikipedia.org/wiki/Disjoint-set_data_structure + // + // We can safely use a relaxed atomic here because all threads doing this + // will converge on the same value and we don't need memory orderings to + // be visible. + // + // This is true because: + // - If no fuses occur, this will eventually become the root. + // - If fuses are actively occurring, the root may change, but the + // invariant is that `parent_or_count` merely points to *a* parent. + // + // In other words, it is moving towards "the" root, and that root may move + // further away over time, but the path towards that root will continue to + // be valid and the creation of the path carries all the memory orderings + // required. + UPB_ASSERT(ai != _upb_Arena_PointerFromTagged(next_poc)); + upb_Atomic_Store(&ai->parent_or_count, next_poc, memory_order_relaxed); + } + ai = next; + poc = next_poc; + } + return (upb_ArenaRoot){.root = ai, .tagged_count = poc}; +} + +size_t upb_Arena_SpaceAllocated(upb_Arena* arena, size_t* fused_count) { + upb_ArenaInternal* ai = _upb_Arena_FindRoot(arena).root; + size_t memsize = 0; + size_t local_fused_count = 0; + + while (ai != NULL) { + upb_MemBlock* block = upb_Atomic_Load(&ai->blocks, memory_order_relaxed); + while (block != NULL) { + memsize += sizeof(upb_MemBlock) + block->size; + block = upb_Atomic_Load(&block->next, memory_order_relaxed); + } + ai = upb_Atomic_Load(&ai->next, memory_order_relaxed); + local_fused_count++; + } + + if (fused_count) *fused_count = local_fused_count; + return memsize; +} + +bool UPB_PRIVATE(_upb_Arena_Contains)(const upb_Arena* a, void* ptr) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + UPB_ASSERT(ai); + + upb_MemBlock* block = upb_Atomic_Load(&ai->blocks, memory_order_relaxed); + while (block) { + uintptr_t beg = (uintptr_t)block; + uintptr_t end = beg + block->size; + if ((uintptr_t)ptr >= beg && (uintptr_t)ptr < end) return true; + block = upb_Atomic_Load(&block->next, memory_order_relaxed); + } + + return false; +} + +uint32_t upb_Arena_DebugRefCount(upb_Arena* a) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + // These loads could probably be relaxed, but given that this is debug-only, + // it's not worth introducing a new variant for it. + uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + while (_upb_Arena_IsTaggedPointer(poc)) { + ai = _upb_Arena_PointerFromTagged(poc); + poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + } + return _upb_Arena_RefCountFromTagged(poc); +} + +static void _upb_Arena_AddBlock(upb_Arena* a, void* ptr, size_t size) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + upb_MemBlock* block = ptr; + + // Insert into linked list. + block->size = (uint32_t)size; + upb_Atomic_Init(&block->next, ai->blocks); + upb_Atomic_Store(&ai->blocks, block, memory_order_release); + + a->UPB_PRIVATE(ptr) = UPB_PTR_AT(block, kUpb_MemblockReserve, char); + a->UPB_PRIVATE(end) = UPB_PTR_AT(block, size, char); + + UPB_POISON_MEMORY_REGION(a->UPB_PRIVATE(ptr), + a->UPB_PRIVATE(end) - a->UPB_PRIVATE(ptr)); +} + +static bool _upb_Arena_AllocBlock(upb_Arena* a, size_t size) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + if (!ai->block_alloc) return false; + upb_MemBlock* last_block = upb_Atomic_Load(&ai->blocks, memory_order_acquire); + size_t last_size = last_block != NULL ? last_block->size : 128; + + // Don't naturally grow beyond the max block size. + size_t clamped_size = UPB_MIN(last_size * 2, max_block_size); + + // We may need to exceed the max block size if the user requested a large + // allocation. + size_t block_size = UPB_MAX(size, clamped_size) + kUpb_MemblockReserve; + + upb_MemBlock* block = + upb_malloc(_upb_ArenaInternal_BlockAlloc(ai), block_size); + + if (!block) return false; + _upb_Arena_AddBlock(a, block, block_size); + UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >= size); + return true; +} + +void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(upb_Arena* a, size_t size) { + if (!_upb_Arena_AllocBlock(a, size)) return NULL; // OOM + return upb_Arena_Malloc(a, size - UPB_ASAN_GUARD_SIZE); +} + +static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc) { + const size_t first_block_overhead = + sizeof(upb_ArenaState) + kUpb_MemblockReserve; + upb_ArenaState* a; + + // We need to malloc the initial block. + char* mem; + size_t n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; + } + + a = UPB_PTR_AT(mem, n - sizeof(upb_ArenaState), upb_ArenaState); + n -= sizeof(upb_ArenaState); + + a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 0); + upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); + upb_Atomic_Init(&a->body.next, NULL); + upb_Atomic_Init(&a->body.tail, &a->body); + upb_Atomic_Init(&a->body.blocks, NULL); + + _upb_Arena_AddBlock(&a->head, mem, n); + + return &a->head; +} + +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + UPB_ASSERT(sizeof(void*) * UPB_ARENA_SIZE_HACK >= sizeof(upb_ArenaState)); + upb_ArenaState* a; + + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; + } + + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_ArenaState)); + + if (UPB_UNLIKELY(n < sizeof(upb_ArenaState))) { +#ifdef UPB_TRACING_ENABLED + upb_Arena* ret = _upb_Arena_InitSlow(alloc); + upb_Arena_LogInit(ret, n); + return ret; +#else + return _upb_Arena_InitSlow(alloc); +#endif + } + + a = UPB_PTR_AT(mem, n - sizeof(upb_ArenaState), upb_ArenaState); + + upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); + upb_Atomic_Init(&a->body.next, NULL); + upb_Atomic_Init(&a->body.tail, &a->body); + upb_Atomic_Init(&a->body.blocks, NULL); + + a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 1); + a->head.UPB_PRIVATE(ptr) = mem; + a->head.UPB_PRIVATE(end) = UPB_PTR_AT(mem, n - sizeof(upb_ArenaState), char); +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogInit(&a->head, n); +#endif + return &a->head; +} + +static void _upb_Arena_DoFree(upb_ArenaInternal* ai) { + UPB_ASSERT(_upb_Arena_RefCountFromTagged(ai->parent_or_count) == 1); + while (ai != NULL) { + // Load first since arena itself is likely from one of its blocks. + upb_ArenaInternal* next_arena = + (upb_ArenaInternal*)upb_Atomic_Load(&ai->next, memory_order_acquire); + upb_alloc* block_alloc = _upb_ArenaInternal_BlockAlloc(ai); + upb_MemBlock* block = upb_Atomic_Load(&ai->blocks, memory_order_acquire); + while (block != NULL) { + // Load first since we are deleting block. + upb_MemBlock* next_block = + upb_Atomic_Load(&block->next, memory_order_acquire); + upb_free(block_alloc, block); + block = next_block; + } + ai = next_arena; + } +} + +void upb_Arena_Free(upb_Arena* a) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); +retry: + while (_upb_Arena_IsTaggedPointer(poc)) { + ai = _upb_Arena_PointerFromTagged(poc); + poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + } + + // compare_exchange or fetch_sub are RMW operations, which are more + // expensive then direct loads. As an optimization, we only do RMW ops + // when we need to update things for other threads to see. + if (poc == _upb_Arena_TaggedFromRefcount(1)) { +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogFree(a); +#endif + _upb_Arena_DoFree(ai); + return; + } + + if (upb_Atomic_CompareExchangeWeak( + &ai->parent_or_count, &poc, + _upb_Arena_TaggedFromRefcount(_upb_Arena_RefCountFromTagged(poc) - 1), + memory_order_release, memory_order_acquire)) { + // We were >1 and we decremented it successfully, so we are done. + return; + } + + // We failed our update, so someone has done something, retry the whole + // process, but the failed exchange reloaded `poc` for us. + goto retry; +} + +static void _upb_Arena_DoFuseArenaLists(upb_ArenaInternal* const parent, + upb_ArenaInternal* child) { + upb_ArenaInternal* parent_tail = + upb_Atomic_Load(&parent->tail, memory_order_relaxed); + + do { + // Our tail might be stale, but it will always converge to the true tail. + upb_ArenaInternal* parent_tail_next = + upb_Atomic_Load(&parent_tail->next, memory_order_relaxed); + while (parent_tail_next != NULL) { + parent_tail = parent_tail_next; + parent_tail_next = + upb_Atomic_Load(&parent_tail->next, memory_order_relaxed); + } + + upb_ArenaInternal* displaced = + upb_Atomic_Exchange(&parent_tail->next, child, memory_order_relaxed); + parent_tail = upb_Atomic_Load(&child->tail, memory_order_relaxed); + + // If we displaced something that got installed racily, we can simply + // reinstall it on our new tail. + child = displaced; + } while (child != NULL); + + upb_Atomic_Store(&parent->tail, parent_tail, memory_order_relaxed); +} + +static upb_ArenaInternal* _upb_Arena_DoFuse(upb_Arena* a1, upb_Arena* a2, + uintptr_t* ref_delta) { + // `parent_or_count` has two distinct modes + // - parent pointer mode + // - refcount mode + // + // In parent pointer mode, it may change what pointer it refers to in the + // tree, but it will always approach a root. Any operation that walks the + // tree to the root may collapse levels of the tree concurrently. + upb_ArenaRoot r1 = _upb_Arena_FindRoot(a1); + upb_ArenaRoot r2 = _upb_Arena_FindRoot(a2); + + if (r1.root == r2.root) return r1.root; // Already fused. + + // Avoid cycles by always fusing into the root with the lower address. + if ((uintptr_t)r1.root > (uintptr_t)r2.root) { + upb_ArenaRoot tmp = r1; + r1 = r2; + r2 = tmp; + } + + // The moment we install `r1` as the parent for `r2` all racing frees may + // immediately begin decrementing `r1`'s refcount (including pending + // increments to that refcount and their frees!). We need to add `r2`'s refs + // now, so that `r1` can withstand any unrefs that come from r2. + // + // Note that while it is possible for `r2`'s refcount to increase + // asynchronously, we will not actually do the reparenting operation below + // unless `r2`'s refcount is unchanged from when we read it. + // + // Note that we may have done this previously, either to this node or a + // different node, during a previous and failed DoFuse() attempt. But we will + // not lose track of these refs because we always add them to our overall + // delta. + uintptr_t r2_untagged_count = r2.tagged_count & ~1; + uintptr_t with_r2_refs = r1.tagged_count + r2_untagged_count; + if (!upb_Atomic_CompareExchangeStrong( + &r1.root->parent_or_count, &r1.tagged_count, with_r2_refs, + memory_order_release, memory_order_acquire)) { + return NULL; + } + + // Perform the actual fuse by removing the refs from `r2` and swapping in the + // parent pointer. + if (!upb_Atomic_CompareExchangeStrong( + &r2.root->parent_or_count, &r2.tagged_count, + _upb_Arena_TaggedFromPointer(r1.root), memory_order_release, + memory_order_acquire)) { + // We'll need to remove the excess refs we added to r1 previously. + *ref_delta += r2_untagged_count; + return NULL; + } + + // Now that the fuse has been performed (and can no longer fail) we need to + // append `r2` to `r1`'s linked list. + _upb_Arena_DoFuseArenaLists(r1.root, r2.root); + return r1.root; +} + +static bool _upb_Arena_FixupRefs(upb_ArenaInternal* new_root, + uintptr_t ref_delta) { + if (ref_delta == 0) return true; // No fixup required. + uintptr_t poc = + upb_Atomic_Load(&new_root->parent_or_count, memory_order_relaxed); + if (_upb_Arena_IsTaggedPointer(poc)) return false; + uintptr_t with_refs = poc - ref_delta; + UPB_ASSERT(!_upb_Arena_IsTaggedPointer(with_refs)); + return upb_Atomic_CompareExchangeStrong(&new_root->parent_or_count, &poc, + with_refs, memory_order_relaxed, + memory_order_relaxed); +} + +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + if (a1 == a2) return true; // trivial fuse + +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogFuse(a1, a2); +#endif + + upb_ArenaInternal* ai1 = upb_Arena_Internal(a1); + upb_ArenaInternal* ai2 = upb_Arena_Internal(a2); + + // Do not fuse initial blocks since we cannot lifetime extend them. + // Any other fuse scenario is allowed. + if (_upb_ArenaInternal_HasInitialBlock(ai1) || + _upb_ArenaInternal_HasInitialBlock(ai2)) { + return false; + } + + // The number of refs we ultimately need to transfer to the new root. + uintptr_t ref_delta = 0; + while (true) { + upb_ArenaInternal* new_root = _upb_Arena_DoFuse(a1, a2, &ref_delta); + if (new_root != NULL && _upb_Arena_FixupRefs(new_root, ref_delta)) { + return true; + } + } +} + +bool upb_Arena_IncRefFor(upb_Arena* a, const void* owner) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + if (_upb_ArenaInternal_HasInitialBlock(ai)) return false; + upb_ArenaRoot r; + +retry: + r = _upb_Arena_FindRoot(a); + if (upb_Atomic_CompareExchangeWeak( + &r.root->parent_or_count, &r.tagged_count, + _upb_Arena_TaggedFromRefcount( + _upb_Arena_RefCountFromTagged(r.tagged_count) + 1), + memory_order_release, memory_order_acquire)) { + // We incremented it successfully, so we are done. + return true; + } + // We failed update due to parent switching on the arena. + goto retry; +} + +void upb_Arena_DecRefFor(upb_Arena* a, const void* owner) { upb_Arena_Free(a); } + +void UPB_PRIVATE(_upb_Arena_SwapIn)(upb_Arena* des, const upb_Arena* src) { + upb_ArenaInternal* desi = upb_Arena_Internal(des); + upb_ArenaInternal* srci = upb_Arena_Internal(src); + + *des = *src; + desi->block_alloc = srci->block_alloc; + upb_MemBlock* blocks = upb_Atomic_Load(&srci->blocks, memory_order_relaxed); + upb_Atomic_Init(&desi->blocks, blocks); +} + +void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) { + upb_ArenaInternal* desi = upb_Arena_Internal(des); + upb_ArenaInternal* srci = upb_Arena_Internal(src); + + *des = *src; + upb_MemBlock* blocks = upb_Atomic_Load(&srci->blocks, memory_order_relaxed); + upb_Atomic_Store(&desi->blocks, blocks, memory_order_relaxed); +} + + +#include + + +// Must be last. + +bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* m, + const upb_MiniTableField* f, + upb_Message* map_entry_message, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message)); + const upb_MiniTable* map_entry_mini_table = + upb_MiniTable_MapEntrySubMessage(m, f); + UPB_ASSERT(map_entry_mini_table); + const upb_MiniTableField* map_entry_key_field = + upb_MiniTable_MapKey(map_entry_mini_table); + const upb_MiniTableField* map_entry_value_field = + upb_MiniTable_MapValue(map_entry_mini_table); + // Map key/value cannot have explicit defaults, + // hence assuming a zero default is valid. + upb_MessageValue default_val; + memset(&default_val, 0, sizeof(upb_MessageValue)); + upb_MessageValue map_entry_key = + upb_Message_GetField(map_entry_message, map_entry_key_field, default_val); + upb_MessageValue map_entry_value = upb_Message_GetField( + map_entry_message, map_entry_value_field, default_val); + return upb_Map_Set(map, map_entry_key, map_entry_value, arena); +} + + +#include +#include + + +// Must be last. + +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(type); + return UPB_PRIVATE(_upb_Array_New)(a, 4, lg2); +} + +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + UPB_ASSERT(i < upb_Array_Size(arr)); + upb_MessageValue ret; + const char* data = upb_Array_DataPtr(arr); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} + +upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i) { + UPB_ASSERT(i < upb_Array_Size(arr)); + upb_MutableMessageValue ret; + char* data = upb_Array_MutableDataPtr(arr); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} + +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(i < upb_Array_Size(arr)); + char* data = upb_Array_MutableDataPtr(arr); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + memcpy(data + (i << lg2), &val, 1 << lg2); +} + +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(arena); + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + upb_Array_Set(arr, arr->UPB_PRIVATE(size) - 1, val); + return true; +} + +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + char* data = upb_Array_MutableDataPtr(arr); + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} + +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(arena); + UPB_ASSERT(i <= arr->UPB_PRIVATE(size)); + UPB_ASSERT(count + arr->UPB_PRIVATE(size) >= count); + const size_t oldsize = arr->UPB_PRIVATE(size); + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + count, arena)) { + return false; + } + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; +} + +/* + * i end arr->size + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->UPB_PRIVATE(size)); + upb_Array_Move(arr, i, end, arr->UPB_PRIVATE(size) - end); + arr->UPB_PRIVATE(size) -= count; +} + +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const size_t oldsize = arr->UPB_PRIVATE(size); + if (UPB_UNLIKELY( + !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena))) { + return false; + } + const size_t newsize = arr->UPB_PRIVATE(size); + if (newsize > oldsize) { + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + char* data = upb_Array_MutableDataPtr(arr); + memset(data + (oldsize << lg2), 0, (newsize - oldsize) << lg2); + } + return true; +} + +bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity, + upb_Arena* arena) { + size_t new_capacity = UPB_MAX(array->UPB_PRIVATE(capacity), 4); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); + size_t old_bytes = array->UPB_PRIVATE(capacity) << lg2; + void* ptr = upb_Array_MutableDataPtr(array); + + // Log2 ceiling of size. + while (new_capacity < min_capacity) new_capacity *= 2; + + const size_t new_bytes = new_capacity << lg2; + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); + if (!ptr) return false; + + UPB_PRIVATE(_upb_Array_SetTaggedPtr)(array, ptr, lg2); + array->UPB_PRIVATE(capacity) = new_capacity; + return true; +} + +void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m) { + if (upb_Array_IsFrozen(arr)) return; + UPB_PRIVATE(_upb_Array_ShallowFreeze)(arr); + + if (m) { + const size_t size = upb_Array_Size(arr); + + for (size_t i = 0; i < size; i++) { + upb_MessageValue val = upb_Array_Get(arr, i); + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + + +#include +#include + + +// Must be last. + +const upb_MiniTableExtension* upb_Message_ExtensionByIndex( + const upb_Message* msg, size_t index) { + size_t count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count); + + UPB_ASSERT(index < count); + return ext[index].ext; +} + +const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( + const upb_Message* msg, uint32_t field_number) { + size_t count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count); + + for (; count--; ext++) { + const upb_MiniTableExtension* e = ext->ext; + if (upb_MiniTableExtension_Number(e) == field_number) return e; + } + return NULL; +} + + +#include +#include + + +// Must be last. + +// Strings/bytes are special-cased in maps. +char _upb_Map_CTypeSizeTable[12] = { + [kUpb_CType_Bool] = 1, + [kUpb_CType_Float] = 4, + [kUpb_CType_Int32] = 4, + [kUpb_CType_UInt32] = 4, + [kUpb_CType_Enum] = 4, + [kUpb_CType_Message] = sizeof(void*), + [kUpb_CType_Double] = 8, + [kUpb_CType_Int64] = 8, + [kUpb_CType_UInt64] = 8, + [kUpb_CType_String] = UPB_MAPTYPE_STRING, + [kUpb_CType_Bytes] = UPB_MAPTYPE_STRING, +}; + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_Map_CTypeSize(key_type), + _upb_Map_CTypeSize(value_type)); +} + +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); +} + +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(arena); + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); +} + +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key, upb_MessageValue* val) { + upb_value v; + const bool removed = _upb_Map_Delete(map, &key, map->key_size, &v); + if (val) _upb_map_fromvalue(v, val, map->val_size); + return removed; +} + +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter) { + upb_StringView k; + upb_value v; + const bool ok = upb_strtable_next2(&map->table, &k, &v, (intptr_t*)iter); + if (ok) { + _upb_map_fromkey(k, key, map->key_size); + _upb_map_fromvalue(v, val, map->val_size); + } + return ok; +} + +UPB_API void upb_Map_SetEntryValue(upb_Map* map, size_t iter, + upb_MessageValue val) { + upb_value v; + _upb_map_tovalue(&val, map->val_size, &v, NULL); + upb_strtable_setentryvalue(&map->table, iter, v); +} + +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); +} + +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); +} + +// Returns the key and value for this entry of the map. +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; +} + +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; +} + +void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m) { + if (upb_Map_IsFrozen(map)) return; + UPB_PRIVATE(_upb_Map_ShallowFreeze)(map); + + if (m) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(map, &key, &val, &iter)) { + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); + if (!map) return NULL; + + upb_strtable_init(&map->table, 4, a); + map->key_size = key_size; + map->val_size = value_size; + map->UPB_PRIVATE(is_frozen) = false; + + return map; +} + + +#include +#include + + +// Must be last. + +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_tabstrview((*a)->key); + upb_StringView b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); +} + +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return a.size < b.size ? -1 : a.size > b.size; +} + +static int (*const compar[kUpb_FieldType_SizeOf])(const void*, const void*) = { + [kUpb_FieldType_Int64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SFixed64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SInt64] = _upb_mapsorter_cmpi64, + + [kUpb_FieldType_UInt64] = _upb_mapsorter_cmpu64, + [kUpb_FieldType_Fixed64] = _upb_mapsorter_cmpu64, + + [kUpb_FieldType_Int32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SInt32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SFixed32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_Enum] = _upb_mapsorter_cmpi32, + + [kUpb_FieldType_UInt32] = _upb_mapsorter_cmpu32, + [kUpb_FieldType_Fixed32] = _upb_mapsorter_cmpu32, + + [kUpb_FieldType_Bool] = _upb_mapsorter_cmpbool, + + [kUpb_FieldType_String] = _upb_mapsorter_cmpstr, + [kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr, +}; + +static bool _upb_mapsorter_resize(_upb_mapsorter* s, _upb_sortedmap* sorted, + int size) { + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + size; + + if (sorted->end > s->cap) { + const int oldsize = s->cap * sizeof(*s->entries); + s->cap = upb_Log2CeilingSize(sorted->end); + const int newsize = s->cap * sizeof(*s->entries); + s->entries = upb_grealloc(s->entries, oldsize, newsize); + if (!s->entries) return false; + } + + s->size = sorted->end; + return true; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + UPB_ASSERT(map_size); + + if (!_upb_mapsorter_resize(s, sorted, map_size)) return false; + + // Copy non-empty entries from the table to s->entries. + const void** dst = &s->entries[sorted->start]; + const upb_tabent* src = map->table.t.entries; + const upb_tabent* end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; + } + } + UPB_ASSERT(dst == &s->entries[sorted->end]); + + // Sort entries according to the key type. + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), + compar[key_type]); + return true; +} + +static int _upb_mapsorter_cmpext(const void* _a, const void* _b) { + const upb_Extension* const* a = _a; + const upb_Extension* const* b = _b; + uint32_t a_num = upb_MiniTableExtension_Number((*a)->ext); + uint32_t b_num = upb_MiniTableExtension_Number((*b)->ext); + assert(a_num != b_num); + return a_num < b_num ? -1 : 1; +} + +bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts, + size_t count, _upb_sortedmap* sorted) { + if (!_upb_mapsorter_resize(s, sorted, count)) return false; + + for (size_t i = 0; i < count; i++) { + s->entries[sorted->start + i] = &exts[i]; + } + + qsort(&s->entries[sorted->start], count, sizeof(*s->entries), + _upb_mapsorter_cmpext); + return true; +} + + +#include +#include +#include + + +// Must be last. + +static const size_t message_overhead = sizeof(upb_Message_Internal); + +upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) { + return _upb_Message_New(m, a); +} + +bool UPB_PRIVATE(_upb_Message_AddUnknown)(upb_Message* msg, const char* data, + size_t len, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, len, arena)) return false; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + memcpy(UPB_PTR_AT(in, in->unknown_end, char), data, len); + in->unknown_end += len; + return true; +} + +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in) { + in->unknown_end = message_overhead; + } +} + +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in) { + *len = in->unknown_end - message_overhead; + return (char*)(in + 1); + } else { + *len = 0; + return NULL; + } +} + +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + const char* internal_unknown_end = UPB_PTR_AT(in, in->unknown_end, char); + +#ifndef NDEBUG + size_t full_unknown_size; + const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size); + UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown); + UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size)); + UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data); + UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end); +#endif + + if ((data + len) != internal_unknown_end) { + memmove((char*)data, data + len, internal_unknown_end - data - len); + } + in->unknown_end -= len; +} + +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + UPB_PRIVATE(_upb_Message_Getexts)(msg, &count); + return count; +} + +void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_IsFrozen(msg)) return; + UPB_PRIVATE(_upb_Message_ShallowFreeze)(msg); + + // Base Fields. + const size_t field_count = upb_MiniTable_FieldCount(m); + + for (size_t i = 0; i < field_count; i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const upb_MiniTable* m2 = upb_MiniTable_SubMessage(m, f); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = upb_Message_GetMutableArray(msg, f); + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: { + upb_Map* map = upb_Message_GetMutableMap(msg, f); + if (map) { + const upb_MiniTableField* f2 = upb_MiniTable_MapValue(m2); + const upb_MiniTable* m3 = upb_MiniTable_SubMessage(m2, f2); + upb_Map_Freeze(map, m3); + } + break; + } + case kUpb_FieldMode_Scalar: { + if (m2) { + upb_Message* msg2 = upb_Message_GetMutableMessage(msg, f); + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } + } + + // Extensions. + size_t ext_count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count); + + for (size_t i = 0; i < ext_count; i++) { + const upb_MiniTableExtension* e = ext[i].ext; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e); + + upb_MessageValue val; + memcpy(&val, &ext[i].data, sizeof(upb_MessageValue)); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = (upb_Array*)val.array_val; + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: + if (upb_MiniTableField_IsSubMessage(f)) { + upb_Message* msg2 = (upb_Message*)val.msg_val; + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } +} + + +#include + + +// Must be last. + + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_Message_IsEmpty(const upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_ExtensionCount(msg)) return false; + + const upb_MiniTableField* f; + upb_MessageValue v; + size_t iter = kUpb_BaseField_Begin; + return !UPB_PRIVATE(_upb_Message_NextBaseField)(msg, m, &f, &v, &iter); +} + +static bool _upb_Array_IsEqual(const upb_Array* arr1, const upb_Array* arr2, + upb_CType ctype, const upb_MiniTable* m, + int options) { + // Check for trivial equality. + if (arr1 == arr2) return true; + + // Must have identical element counts. + const size_t size1 = arr1 ? upb_Array_Size(arr1) : 0; + const size_t size2 = arr2 ? upb_Array_Size(arr2) : 0; + if (size1 != size2) return false; + + for (size_t i = 0; i < size1; i++) { + const upb_MessageValue val1 = upb_Array_Get(arr1, i); + const upb_MessageValue val2 = upb_Array_Get(arr2, i); + + if (!upb_MessageValue_IsEqual(val1, val2, ctype, m, options)) return false; + } + + return true; +} + +static bool _upb_Map_IsEqual(const upb_Map* map1, const upb_Map* map2, + const upb_MiniTable* m, int options) { + // Check for trivial equality. + if (map1 == map2) return true; + + // Must have identical element counts. + size_t size1 = map1 ? upb_Map_Size(map1) : 0; + size_t size2 = map2 ? upb_Map_Size(map2) : 0; + if (size1 != size2) return false; + + const upb_MiniTableField* f = upb_MiniTable_MapValue(m); + const upb_MiniTable* m2_value = upb_MiniTable_SubMessage(m, f); + const upb_CType ctype = upb_MiniTableField_CType(f); + + upb_MessageValue key, val1, val2; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map1, &key, &val1, &iter)) { + if (!upb_Map_Get(map2, key, &val2)) return false; + if (!upb_MessageValue_IsEqual(val1, val2, ctype, m2_value, options)) + return false; + } + + return true; +} + +static bool _upb_Message_BaseFieldsAreEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, + int options) { + // Iterate over all base fields for each message. + // The order will always match if the messages are equal. + size_t iter1 = kUpb_BaseField_Begin; + size_t iter2 = kUpb_BaseField_Begin; + + for (;;) { + const upb_MiniTableField *f1, *f2; + upb_MessageValue val1, val2; + + const bool got1 = + UPB_PRIVATE(_upb_Message_NextBaseField)(msg1, m, &f1, &val1, &iter1); + const bool got2 = + UPB_PRIVATE(_upb_Message_NextBaseField)(msg2, m, &f2, &val2, &iter2); + + if (got1 != got2) return false; // Must have identical field counts. + if (!got1) return true; // Loop termination condition. + if (f1 != f2) return false; // Must have identical fields set. + + const upb_MiniTable* subm = upb_MiniTable_SubMessage(m, f1); + const upb_CType ctype = upb_MiniTableField_CType(f1); + + bool eq; + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f1)) { + case kUpb_FieldMode_Array: + eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, + options); + break; + case kUpb_FieldMode_Map: + eq = _upb_Map_IsEqual(val1.map_val, val2.map_val, subm, options); + break; + case kUpb_FieldMode_Scalar: + eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); + break; + } + if (!eq) return false; + } +} + +static bool _upb_Message_ExtensionsAreEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, + int options) { + // Must have identical extension counts. + if (upb_Message_ExtensionCount(msg1) != upb_Message_ExtensionCount(msg2)) { + return false; + } + + const upb_MiniTableExtension* e; + upb_MessageValue val1; + + // Iterate over all extensions for msg1, and search msg2 for each extension. + size_t iter1 = kUpb_Extension_Begin; + while (UPB_PRIVATE(_upb_Message_NextExtension)(msg1, m, &e, &val1, &iter1)) { + const upb_Extension* ext2 = UPB_PRIVATE(_upb_Message_Getext)(msg2, e); + if (!ext2) return false; + + const upb_MessageValue val2 = ext2->data; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* subm = upb_MiniTableField_IsSubMessage(f) + ? upb_MiniTableExtension_GetSubMessage(e) + : NULL; + const upb_CType ctype = upb_MiniTableField_CType(f); + + bool eq; + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: + eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, + options); + break; + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: { + eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); + break; + } + } + if (!eq) return false; + } + return true; +} + +bool upb_Message_IsEqual(const upb_Message* msg1, const upb_Message* msg2, + const upb_MiniTable* m, int options) { + if (UPB_UNLIKELY(msg1 == msg2)) return true; + + if (!_upb_Message_BaseFieldsAreEqual(msg1, msg2, m, options)) return false; + if (!_upb_Message_ExtensionsAreEqual(msg1, msg2, m, options)) return false; + + if (!(options & kUpb_CompareOption_IncludeUnknownFields)) return true; + + // Check the unknown fields. + size_t usize1, usize2; + const char* uf1 = upb_Message_GetUnknown(msg1, &usize1); + const char* uf2 = upb_Message_GetUnknown(msg2, &usize2); + + // The wire encoder enforces a maximum depth of 100 so we match that here. + return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( + uf1, usize1, uf2, usize2, 100) == kUpb_UnknownCompareResult_Equal; +} + + +#include +#include + + +// Must be last. + +static upb_StringView upb_Clone_StringView(upb_StringView str, + upb_Arena* arena) { + if (str.size == 0) { + return upb_StringView_FromDataAndSize(NULL, 0); + } + void* cloned_data = upb_Arena_Malloc(arena, str.size); + upb_StringView cloned_str = + upb_StringView_FromDataAndSize(cloned_data, str.size); + memcpy(cloned_data, str.data, str.size); + return cloned_str; +} + +static bool upb_Clone_MessageValue(void* value, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + switch (value_type) { + case kUpb_CType_Bool: + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return true; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView source = *(upb_StringView*)value; + int size = source.size; + void* cloned_data = upb_Arena_Malloc(arena, size); + if (cloned_data == NULL) { + return false; + } + *(upb_StringView*)value = + upb_StringView_FromDataAndSize(cloned_data, size); + memcpy(cloned_data, source.data, size); + return true; + } break; + case kUpb_CType_Message: { + const upb_TaggedMessagePtr source = *(upb_TaggedMessagePtr*)value; + bool is_empty = upb_TaggedMessagePtr_IsEmpty(source); + if (is_empty) sub = UPB_PRIVATE(_upb_MiniTable_Empty)(); + UPB_ASSERT(source); + upb_Message* clone = upb_Message_DeepClone( + UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(source), sub, arena); + *(upb_TaggedMessagePtr*)value = + UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(clone, is_empty); + return clone != NULL; + } break; + } + UPB_UNREACHABLE(); +} + +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena) { + upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size); + if (cloned_map == NULL) { + return NULL; + } + upb_MessageValue key, val; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map, &key, &val, &iter)) { + const upb_MiniTableField* value_field = + upb_MiniTable_MapValue(map_entry_table); + const upb_MiniTable* value_sub = + upb_MiniTableField_CType(value_field) == kUpb_CType_Message + ? upb_MiniTable_GetSubMessageTable(map_entry_table, value_field) + : NULL; + upb_CType value_field_type = upb_MiniTableField_CType(value_field); + if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) { + return NULL; + } + if (!upb_Map_Set(cloned_map, key, val, arena)) { + return NULL; + } + } + return cloned_map; +} + +static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map, + const upb_MiniTable* mini_table, + const upb_MiniTableField* f, + upb_Message* clone, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(clone)); + const upb_MiniTable* map_entry_table = + upb_MiniTable_MapEntrySubMessage(mini_table, f); + UPB_ASSERT(map_entry_table); + + const upb_MiniTableField* key_field = upb_MiniTable_MapKey(map_entry_table); + const upb_MiniTableField* value_field = + upb_MiniTable_MapValue(map_entry_table); + + upb_Map* cloned_map = upb_Map_DeepClone( + map, upb_MiniTableField_CType(key_field), + upb_MiniTableField_CType(value_field), map_entry_table, arena); + if (!cloned_map) { + return NULL; + } + upb_Message_SetBaseField(clone, f, &cloned_map); + return cloned_map; +} + +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + const size_t size = upb_Array_Size(array); + const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(value_type); + upb_Array* cloned_array = UPB_PRIVATE(_upb_Array_New)(arena, size, lg2); + if (!cloned_array) { + return NULL; + } + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(cloned_array, size, arena)) { + return NULL; + } + for (size_t i = 0; i < size; ++i) { + upb_MessageValue val = upb_Array_Get(array, i); + if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) { + return false; + } + upb_Array_Set(cloned_array, i, val); + } + return cloned_array; +} + +static bool upb_Message_Array_DeepClone(const upb_Array* array, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(clone)); + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(field); + upb_Array* cloned_array = upb_Array_DeepClone( + array, upb_MiniTableField_CType(field), + upb_MiniTableField_CType(field) == kUpb_CType_Message + ? upb_MiniTable_GetSubMessageTable(mini_table, field) + : NULL, + arena); + + // Clear out upb_Array* due to parent memcpy. + upb_Message_SetBaseField(clone, field, &cloned_array); + return true; +} + +static bool upb_Clone_ExtensionValue( + const upb_MiniTableExtension* mini_table_ext, const upb_Extension* source, + upb_Extension* dest, upb_Arena* arena) { + dest->data = source->data; + return upb_Clone_MessageValue( + &dest->data, upb_MiniTableExtension_CType(mini_table_ext), + upb_MiniTableExtension_GetSubMessage(mini_table_ext), arena); +} + +upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0); + // Only copy message area skipping upb_Message_Internal. + memcpy(dst + 1, src + 1, mini_table->UPB_PRIVATE(size) - sizeof(upb_Message)); + for (int i = 0; i < upb_MiniTable_FieldCount(mini_table); ++i) { + const upb_MiniTableField* field = + upb_MiniTable_GetFieldByIndex(mini_table, i); + if (upb_MiniTableField_IsScalar(field)) { + switch (upb_MiniTableField_CType(field)) { + case kUpb_CType_Message: { + upb_TaggedMessagePtr tagged = + upb_Message_GetTaggedMessagePtr(src, field, NULL); + const upb_Message* sub_message = + UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged); + if (sub_message != NULL) { + // If the message is currently in an unlinked, "empty" state we keep + // it that way, because we don't want to deal with decode options, + // decode status, or possible parse failure here. + bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged); + const upb_MiniTable* sub_message_table = + is_empty ? UPB_PRIVATE(_upb_MiniTable_Empty)() + : upb_MiniTable_GetSubMessageTable(mini_table, field); + upb_Message* dst_sub_message = + upb_Message_DeepClone(sub_message, sub_message_table, arena); + if (dst_sub_message == NULL) { + return NULL; + } + UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr) + (dst, field, + UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message, + is_empty)); + } + } break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView str = upb_Message_GetString(src, field, empty_string); + if (str.size != 0) { + if (!upb_Message_SetString( + dst, field, upb_Clone_StringView(str, arena), arena)) { + return NULL; + } + } + } break; + default: + // Scalar, already copied. + break; + } + } else { + if (upb_MiniTableField_IsMap(field)) { + const upb_Map* map = upb_Message_GetMap(src, field); + if (map != NULL) { + if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) { + return NULL; + } + } + } else { + const upb_Array* array = upb_Message_GetArray(src, field); + if (array != NULL) { + if (!upb_Message_Array_DeepClone(array, mini_table, field, dst, + arena)) { + return NULL; + } + } + } + } + } + // Clone extensions. + size_t ext_count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(src, &ext_count); + for (size_t i = 0; i < ext_count; ++i) { + const upb_Extension* msg_ext = &ext[i]; + const upb_MiniTableField* field = &msg_ext->ext->UPB_PRIVATE(field); + upb_Extension* dst_ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + dst, msg_ext->ext, arena); + if (!dst_ext) return NULL; + if (upb_MiniTableField_IsScalar(field)) { + if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) { + return NULL; + } + } else { + upb_Array* msg_array = (upb_Array*)msg_ext->data.array_val; + UPB_ASSERT(msg_array); + upb_Array* cloned_array = upb_Array_DeepClone( + msg_array, upb_MiniTableField_CType(field), + upb_MiniTableExtension_GetSubMessage(msg_ext->ext), arena); + if (!cloned_array) { + return NULL; + } + dst_ext->data.array_val = cloned_array; + } + } + + // Clone unknowns. + size_t unknown_size = 0; + const char* ptr = upb_Message_GetUnknown(src, &unknown_size); + if (unknown_size != 0) { + UPB_ASSERT(ptr); + // Make a copy into destination arena. + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(dst, ptr, unknown_size, arena)) { + return NULL; + } + } + return dst; +} + +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + upb_Message_Clear(dst, mini_table); + return _upb_Message_Copy(dst, src, mini_table, arena) != NULL; +} + +// Deep clones a message using the provided target arena. +// +// Returns NULL on failure. +upb_Message* upb_Message_DeepClone(const upb_Message* msg, + const upb_MiniTable* m, upb_Arena* arena) { + upb_Message* clone = upb_Message_New(m, arena); + return _upb_Message_Copy(clone, msg, m, arena); +} + +// Performs a shallow copy. TODO: Extend to handle unknown fields. +void upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* m) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + memcpy(dst, src, m->UPB_PRIVATE(size)); +} + +// Performs a shallow clone. Ignores unknown fields. +upb_Message* upb_Message_ShallowClone(const upb_Message* msg, + const upb_MiniTable* m, + upb_Arena* arena) { + upb_Message* clone = upb_Message_New(m, arena); + upb_Message_ShallowCopy(clone, msg, m); + return clone; +} + +#include "stddef.h" + +// Must be last. + +bool upb_Message_MergeFrom(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + upb_Arena* arena) { + char* buf = NULL; + size_t size = 0; + // This tmp arena is used to hold the bytes for `src` serialized. This bends + // the typical "no hidden allocations" design of upb, but under a properly + // optimized implementation this extra allocation would not be necessary and + // so we don't want to unnecessarily have the bad API or bloat the passed-in + // arena with this very-short-term allocation. + upb_Arena* encode_arena = upb_Arena_New(); + upb_EncodeStatus e_status = upb_Encode(src, mt, 0, encode_arena, &buf, &size); + if (e_status != kUpb_EncodeStatus_Ok) { + upb_Arena_Free(encode_arena); + return false; + } + upb_DecodeStatus d_status = upb_Decode(buf, size, dst, mt, extreg, 0, arena); + if (d_status != kUpb_DecodeStatus_Ok) { + upb_Arena_Free(encode_arena); + return false; + } + upb_Arena_Free(encode_arena); + return true; +} + + +#include +#include + + +// Must be last. + +typedef struct { + upb_MdDecoder base; + upb_Arena* arena; + upb_MiniTableEnum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; +} upb_MdEnumDecoder; + +static size_t upb_MiniTableEnum_Size(size_t count) { + return sizeof(upb_MiniTableEnum) + count * sizeof(uint32_t); +} + +static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + size_t new_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); + } + d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val; + return d->enum_table; +} + +static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) { + upb_MiniTableEnum* table = d->enum_table; + d->enum_value_count++; + if (table->UPB_PRIVATE(value_count) || + (val > 512 && d->enum_value_count < val / 32)) { + if (table->UPB_PRIVATE(value_count) == 0) { + UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->UPB_PRIVATE(value_count)++; + } else { + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->UPB_PRIVATE(mask_limit) += 32; + } + table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32); + } +} + +static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum( + upb_MdEnumDecoder* d, const char* data, size_t len) { + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_EnumV1) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid enum version: %c", *data); + } + data++; + len--; + } + + upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); + + // Guarantee at least 64 bits of mask without checking mask size. + d->enum_table->UPB_PRIVATE(mask_limit) = 64; + d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); + d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); + + d->enum_table->UPB_PRIVATE(value_count) = 0; + + const char* ptr = data; + uint32_t base = 0; + + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = _upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) upb_MiniTableEnum_BuildValue(d, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_MdDecoder_ErrorJmp(&d->base, "Unexpected character: %c", ch); + } + } + + return d->enum_table; +} + +static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum( + upb_MdEnumDecoder* const decoder, const char* const data, + size_t const len) { + if (UPB_SETJMP(decoder->base.err) != 0) return NULL; + return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len); +} + +upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MdEnumDecoder decoder = { + .base = + { + .end = UPB_PTRADD(data, len), + .status = status, + }, + .arena = arena, + .enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = 1, + }; + + return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len); +} + + +#include +#include +#include +#include + + +// Must be last. + +// We reserve unused hasbits to make room for upb_Message fields. +#define kUpb_Reserved_Hasbytes sizeof(struct upb_Message) + +// 64 is the first hasbit that we currently use. +#define kUpb_Reserved_Hasbits (kUpb_Reserved_Hasbytes * 8) + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. + + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; + +#define kUpb_LayoutItem_IndexSentinel ((uint16_t) - 1) + +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; + +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; + +typedef struct { + upb_MdDecoder base; + upb_MiniTable* table; + upb_MiniTableField* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; +} upb_MtDecoder; + +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; + +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) { + return (field->UPB_PRIVATE(mode) & kUpb_FieldMode_Array) && + upb_FieldType_IsPackable(field->UPB_PRIVATE(descriptortype)); +} + +typedef struct { + uint16_t submsg_count; + uint16_t subenum_count; +} upb_SubCounts; + +static void upb_MiniTable_SetTypeAndSub(upb_MiniTableField* field, + upb_FieldType type, + upb_SubCounts* sub_counts, + uint64_t msg_modifiers, + bool is_proto3_enum) { + if (is_proto3_enum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + type = kUpb_FieldType_Int32; + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; + } else if (type == kUpb_FieldType_String && + !(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + type = kUpb_FieldType_Bytes; + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; + } + + field->UPB_PRIVATE(descriptortype) = type; + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsPacked; + } + + if (type == kUpb_FieldType_Message || type == kUpb_FieldType_Group) { + field->UPB_PRIVATE(submsg_index) = sub_counts->submsg_count++; + } else if (type == kUpb_FieldType_Enum) { + // We will need to update this later once we know the total number of + // submsg fields. + field->UPB_PRIVATE(submsg_index) = sub_counts->subenum_count++; + } else { + field->UPB_PRIVATE(submsg_index) = kUpb_NoSub; + } +} + +static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_OpenEnum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, +}; + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTableField* field, + uint64_t msg_modifiers, + upb_SubCounts* sub_counts) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_OpenEnum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, + }; + + char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit + ? kUpb_FieldRep_4Byte + : kUpb_FieldRep_8Byte; + + int8_t type = _upb_FromBase92(ch); + if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->UPB_PRIVATE(mode) = kUpb_FieldMode_Array; + field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; + field->UPB_PRIVATE(offset) = kNoPresence; + } else { + field->UPB_PRIVATE(mode) = kUpb_FieldMode_Scalar; + field->UPB_PRIVATE(offset) = kHasbitPresence; + if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { + field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; + } else if ((unsigned long)type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); + } else { + field->UPB_PRIVATE(mode) |= kUpb_EncodedToFieldRep[type] + << kUpb_FieldRep_Shift; + } + } + if ((unsigned long)type >= sizeof(kUpb_EncodedToType)) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); + } + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_counts, + msg_modifiers, type == kUpb_EncodedType_OpenEnum); +} + +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTableField* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Cannot flip packed on unpackable field %" PRIu32, + upb_MiniTableField_Number(field)); + } + field->UPB_PRIVATE(mode) ^= kUpb_LabelFlags_IsPacked; + } + + if (field_modifiers & kUpb_EncodedFieldModifier_FlipValidateUtf8) { + if (field->UPB_PRIVATE(descriptortype) != kUpb_FieldType_Bytes || + !(field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsAlternate)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Cannot flip ValidateUtf8 on field %" PRIu32 + ", type=%d, mode=%d", + upb_MiniTableField_Number(field), + (int)field->UPB_PRIVATE(descriptortype), + (int)field->UPB_PRIVATE(mode)); + } + field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_String; + field->UPB_PRIVATE(mode) &= ~kUpb_LabelFlags_IsAlternate; + } + + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + + // Validate. + if ((singular || required) && field->UPB_PRIVATE(offset) != kHasbitPresence) { + upb_MdDecoder_ErrorJmp(&d->base, + "Invalid modifier(s) for repeated field %" PRIu32, + upb_MiniTableField_Number(field)); + } + if (singular && required) { + upb_MdDecoder_ErrorJmp( + &d->base, "Field %" PRIu32 " cannot be both singular and required", + upb_MiniTableField_Number(field)); + } + + if (singular && upb_MiniTableField_IsSubMessage(field)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Field %" PRIu32 " cannot be a singular submessage", + upb_MiniTableField_Number(field)); + } + + if (singular) field->UPB_PRIVATE(offset) = kNoPresence; + if (required) { + field->UPB_PRIVATE(offset) = kRequiredPresence; + } +} + +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->vec.data); + d->vec.capacity = new_cap; + } + d->vec.data[d->vec.size++] = item; +} + +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MdDecoder_ErrorJmp(&d->base, "Empty oneof"); + } + item.field_index -= kOneofBase; + + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); + + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} + +static size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +static size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MdDecoder_DecodeBase92Varint( + &d->base, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTableField* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); + + if (!f) { + upb_MdDecoder_ErrorJmp(&d->base, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + } + if (f->UPB_PRIVATE(offset) != kHasbitPresence) { + upb_MdDecoder_ErrorJmp( + &d->base, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + } + + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; + } + // Prepend this field to the linked list. + f->UPB_PRIVATE(offset) = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} + +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } + + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} + +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTableField* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); + } else { + if (!d->table) { + upb_MdDecoder_ErrorJmp(&d->base, + "Extensions cannot have message modifiers"); + } + *msg_modifiers = mod; + } + + return ptr; +} + +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, + upb_SubCounts sub_counts) { + uint32_t total_count = sub_counts.submsg_count + sub_counts.subenum_count; + size_t subs_bytes = sizeof(*d->table->UPB_PRIVATE(subs)) * total_count; + size_t ptrs_bytes = sizeof(upb_MiniTable*) * sub_counts.submsg_count; + upb_MiniTableSubInternal* subs = upb_Arena_Malloc(d->arena, subs_bytes); + const upb_MiniTable** subs_ptrs = upb_Arena_Malloc(d->arena, ptrs_bytes); + upb_MdDecoder_CheckOutOfMemory(&d->base, subs); + upb_MdDecoder_CheckOutOfMemory(&d->base, subs_ptrs); + uint32_t i = 0; + for (; i < sub_counts.submsg_count; i++) { + subs_ptrs[i] = UPB_PRIVATE(_upb_MiniTable_Empty)(); + subs[i].UPB_PRIVATE(submsg) = &subs_ptrs[i]; + } + if (sub_counts.subenum_count) { + upb_MiniTableField* f = d->fields; + upb_MiniTableField* end_f = f + d->table->UPB_PRIVATE(field_count); + for (; f < end_f; f++) { + if (f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum) { + f->UPB_PRIVATE(submsg_index) += sub_counts.submsg_count; + } + } + for (; i < sub_counts.submsg_count + sub_counts.subenum_count; i++) { + subs[i].UPB_PRIVATE(subenum) = NULL; + } + } + d->table->UPB_PRIVATE(subs) = subs; +} + +static const char* upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, + size_t len, void* fields, + size_t field_size, uint16_t* field_count, + upb_SubCounts* sub_counts) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTableField* last_field = NULL; + bool need_dense_below = d->table != NULL; + + d->base.end = UPB_PTRADD(ptr, len); + + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (!d->table && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTableField* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->UPB_PRIVATE(number) = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_counts); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->UPB_PRIVATE(ext) |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MdDecoder_ErrorJmp(&d->base, "Extensions cannot have oneofs."); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->UPB_PRIVATE(dense_below) = d->table->UPB_PRIVATE(field_count); + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } else { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid char: %c", ch); + } + } + + if (need_dense_below) { + d->table->UPB_PRIVATE(dense_below) = d->table->UPB_PRIVATE(field_count); + } + + return ptr; +} + +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->fields); + + upb_SubCounts sub_counts = {0, 0}; + d->table->UPB_PRIVATE(field_count) = 0; + d->table->UPB_PRIVATE(fields) = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->UPB_PRIVATE(field_count), &sub_counts); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->UPB_PRIVATE(field_count)); + d->table->UPB_PRIVATE(fields) = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_counts); +} + +static int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + UPB_ASSERT(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->UPB_PRIVATE(field_count); + for (int i = 0; i < n; i++) { + upb_MiniTableField* f = &d->fields[i]; + if (f->UPB_PRIVATE(offset) >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } + + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); + } + + return true; +} + +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static void upb_MtDecoder_AssignHasbits(upb_MtDecoder* d) { + upb_MiniTable* ret = d->table; + int n = ret->UPB_PRIVATE(field_count); + size_t last_hasbit = kUpb_Reserved_Hasbits - 1; + + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = + (upb_MiniTableField*)&ret->UPB_PRIVATE(fields)[i]; + if (field->UPB_PRIVATE(offset) == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->UPB_PRIVATE(offset) == kNoPresence) { + field->presence = 0; + } + } + if (last_hasbit > kUpb_Reserved_Hasbits + 63) { + upb_MdDecoder_ErrorJmp(&d->base, "Too many required fields"); + } + + ret->UPB_PRIVATE(required_count) = last_hasbit - (kUpb_Reserved_Hasbits - 1); + + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = + (upb_MiniTableField*)&ret->UPB_PRIVATE(fields)[i]; + if (field->UPB_PRIVATE(offset) == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } + + ret->UPB_PRIVATE(size) = + last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +static size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->UPB_PRIVATE(size), align); + static const size_t max = UINT16_MAX; + size_t new_size = ret + size; + if (new_size > max) { + upb_MdDecoder_ErrorJmp( + &d->base, "Message size exceeded maximum size of %zu bytes", max); + } + d->table->UPB_PRIVATE(size) = new_size; + return ret; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } + + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTableField* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->UPB_PRIVATE(offset) == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->UPB_PRIVATE(offset) - kOneofBase < + d->table->UPB_PRIVATE(field_count)); + f = &d->fields[f->UPB_PRIVATE(offset) - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTableField* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->UPB_PRIVATE(offset); + f->UPB_PRIVATE(offset) = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->UPB_PRIVATE(offset) = item->offset; + break; + default: + break; + } + } + + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->UPB_PRIVATE(size) = UPB_ALIGN_UP(d->table->UPB_PRIVATE(size), 8); +} + +static void upb_MtDecoder_ValidateEntryField(upb_MtDecoder* d, + const upb_MiniTableField* f, + uint32_t expected_num) { + const char* name = expected_num == 1 ? "key" : "val"; + const uint32_t f_number = upb_MiniTableField_Number(f); + if (f_number != expected_num) { + upb_MdDecoder_ErrorJmp(&d->base, + "map %s did not have expected number (%d vs %d)", + name, expected_num, f_number); + } + + if (!upb_MiniTableField_IsScalar(f)) { + upb_MdDecoder_ErrorJmp( + &d->base, "map %s cannot be repeated or map, or be in oneof", name); + } + + uint32_t not_ok_types; + if (expected_num == 1) { + not_ok_types = (1 << kUpb_FieldType_Float) | (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Message) | (1 << kUpb_FieldType_Group) | + (1 << kUpb_FieldType_Bytes) | (1 << kUpb_FieldType_Enum); + } else { + not_ok_types = 1 << kUpb_FieldType_Group; + } + + if ((1 << upb_MiniTableField_Type(f)) & not_ok_types) { + upb_MdDecoder_ErrorJmp(&d->base, "map %s cannot have type %d", name, + (int)f->UPB_PRIVATE(descriptortype)); + } +} + +static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, + size_t len) { + upb_MtDecoder_ParseMessage(d, data, len); + upb_MtDecoder_AssignHasbits(d); + + if (UPB_UNLIKELY(d->table->UPB_PRIVATE(field_count) != 2)) { + upb_MdDecoder_ErrorJmp(&d->base, "%hu fields in map", + d->table->UPB_PRIVATE(field_count)); + UPB_UNREACHABLE(); + } + + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type == kUpb_LayoutItemType_OneofCase) { + upb_MdDecoder_ErrorJmp(&d->base, "Map entry cannot have oneof"); + } + } + + upb_MtDecoder_ValidateEntryField(d, &d->table->UPB_PRIVATE(fields)[0], 1); + upb_MtDecoder_ValidateEntryField(d, &d->table->UPB_PRIVATE(fields)[1], 2); + + d->fields[0].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, k); + d->fields[1].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, v); + d->table->UPB_PRIVATE(size) = sizeof(upb_MapEntry); + + // Map entries have a special bit set to signal it's a map entry, used in + // upb_MiniTable_SetSubMessage() below. + d->table->UPB_PRIVATE(ext) |= kUpb_ExtMode_IsMapEntry; +} + +static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, + size_t len) { + if (len > 0) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid message set encode length: %zu", + len); + } + + upb_MiniTable* ret = d->table; + ret->UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; + ret->UPB_PRIVATE(field_count) = 0; + ret->UPB_PRIVATE(ext) = kUpb_ExtMode_IsMessageSet; + ret->UPB_PRIVATE(dense_below) = 0; + ret->UPB_PRIVATE(table_mask) = -1; + ret->UPB_PRIVATE(required_count) = 0; +} + +static upb_MiniTable* upb_MtDecoder_DoBuildMiniTableWithBuf( + upb_MtDecoder* decoder, const char* data, size_t len, void** buf, + size_t* buf_size) { + upb_MdDecoder_CheckOutOfMemory(&decoder->base, decoder->table); + + decoder->table->UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; + decoder->table->UPB_PRIVATE(field_count) = 0; + decoder->table->UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable; + decoder->table->UPB_PRIVATE(dense_below) = 0; + decoder->table->UPB_PRIVATE(table_mask) = -1; + decoder->table->UPB_PRIVATE(required_count) = 0; +#if UPB_TRACING_ENABLED + // MiniTables built from MiniDescriptors will not be able to vend the message + // name unless it is explicitly set with upb_MiniTable_SetFullName(). + decoder->table->UPB_PRIVATE(full_name) = 0; +#endif + + // Strip off and verify the version tag. + if (!len--) goto done; + const char vers = *data++; + + switch (vers) { + case kUpb_EncodedVersion_MapV1: + upb_MtDecoder_ParseMap(decoder, data, len); + break; + + case kUpb_EncodedVersion_MessageV1: + upb_MtDecoder_ParseMessage(decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder); + upb_MtDecoder_SortLayoutItems(decoder); + upb_MtDecoder_AssignOffsets(decoder); + break; + + case kUpb_EncodedVersion_MessageSetV1: + upb_MtDecoder_ParseMessageSet(decoder, data, len); + break; + + default: + upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid message version: %c", + vers); + } + +done: + *buf = decoder->vec.data; + *buf_size = decoder->vec.capacity * sizeof(*decoder->vec.data); + return decoder->table; +} + +static upb_MiniTable* upb_MtDecoder_BuildMiniTableWithBuf( + upb_MtDecoder* const decoder, const char* const data, const size_t len, + void** const buf, size_t* const buf_size) { + if (UPB_SETJMP(decoder->base.err) != 0) { + *buf = decoder->vec.data; + *buf_size = decoder->vec.capacity * sizeof(*decoder->vec.data); + return NULL; + } + + return upb_MtDecoder_DoBuildMiniTableWithBuf(decoder, data, len, buf, + buf_size); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .base = {.status = status}, + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; + + return upb_MtDecoder_BuildMiniTableWithBuf(&decoder, data, len, buf, + buf_size); +} + +static const char* upb_MtDecoder_DoBuildMiniTableExtension( + upb_MtDecoder* decoder, const char* data, size_t len, + upb_MiniTableExtension* ext, const upb_MiniTable* extendee, + upb_MiniTableSub sub) { + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_ExtensionV1) { + upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid ext version: %c", *data); + } + data++; + len--; + } + + uint16_t count = 0; + upb_SubCounts sub_counts = {0, 0}; + const char* ret = upb_MtDecoder_Parse(decoder, data, len, ext, sizeof(*ext), + &count, &sub_counts); + if (!ret || count != 1) return NULL; + + upb_MiniTableField* f = &ext->UPB_PRIVATE(field); + + f->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsExtension; + f->UPB_PRIVATE(offset) = 0; + f->presence = 0; + + if (extendee->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_MiniTableField_IsSubMessage(f)) return NULL; + + // Extensions of MessageSet must be non-repeating. + if (upb_MiniTableField_IsArray(f)) return NULL; + } + + ext->UPB_PRIVATE(extendee) = extendee; + ext->UPB_PRIVATE(sub) = sub; + + return ret; +} + +static const char* upb_MtDecoder_BuildMiniTableExtension( + upb_MtDecoder* const decoder, const char* const data, const size_t len, + upb_MiniTableExtension* const ext, const upb_MiniTable* const extendee, + const upb_MiniTableSub sub) { + if (UPB_SETJMP(decoder->base.err) != 0) return NULL; + return upb_MtDecoder_DoBuildMiniTableExtension(decoder, data, len, ext, + extendee, sub); +} + +const char* _upb_MiniTableExtension_Init(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status) { + upb_MtDecoder decoder = { + .base = {.status = status}, + .arena = NULL, + .table = NULL, + .platform = platform, + }; + + return upb_MtDecoder_BuildMiniTableExtension(&decoder, data, len, ext, + extendee, sub); +} + +upb_MiniTableExtension* _upb_MiniTableExtension_Build( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTableSub sub, upb_MiniTablePlatform platform, upb_Arena* arena, + upb_Status* status) { + upb_MiniTableExtension* ext = + upb_Arena_Malloc(arena, sizeof(upb_MiniTableExtension)); + if (UPB_UNLIKELY(!ext)) return NULL; + + const char* ptr = _upb_MiniTableExtension_Init(data, len, ext, extendee, sub, + platform, status); + if (UPB_UNLIKELY(!ptr)) return NULL; + + return ext; +} + +upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; +} + + +#include +#include +#include + + +// Must be last. + +bool upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTableField* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && + (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + + table->UPB_PRIVATE(field_count))); + UPB_ASSERT(sub); + + const bool sub_is_map = sub->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; + + switch (field->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Message: + if (sub_is_map) { + const bool table_is_map = + table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; + if (UPB_UNLIKELY(table_is_map)) return false; + + field->UPB_PRIVATE(mode) = + (field->UPB_PRIVATE(mode) & ~kUpb_FieldMode_Mask) | + kUpb_FieldMode_Map; + } + break; + + case kUpb_FieldType_Group: + if (UPB_UNLIKELY(sub_is_map)) return false; + break; + + default: + return false; + } + + int idx = field->UPB_PRIVATE(submsg_index); + upb_MiniTableSubInternal* table_subs = (void*)table->UPB_PRIVATE(subs); + // TODO: Add this assert back once YouTube is updated to not call + // this function repeatedly. + // UPB_ASSERT(UPB_PRIVATE(_upb_MiniTable_IsEmpty)(table_sub->submsg)); + memcpy((void*)table_subs[idx].UPB_PRIVATE(submsg), &sub, sizeof(void*)); + return true; +} + +bool upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub) { + UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && + (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + + table->UPB_PRIVATE(field_count))); + UPB_ASSERT(sub); + + upb_MiniTableSub* table_sub = + (void*)&table->UPB_PRIVATE(subs)[field->UPB_PRIVATE(submsg_index)]; + *table_sub = upb_MiniTableSub_FromEnum(sub); + return true; +} + +uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* m, + const upb_MiniTableField** subs) { + uint32_t msg_count = 0; + uint32_t enum_count = 0; + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { + *subs = f; + ++subs; + msg_count++; + } + } + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_IsClosedEnum(f)) { + *subs = f; + ++subs; + enum_count++; + } + } + + return (msg_count << 16) | enum_count; +} + +// The list of sub_tables and sub_enums must exactly match the number and order +// of sub-message fields and sub-enum fields given by upb_MiniTable_GetSubList() +// above. +bool upb_MiniTable_Link(upb_MiniTable* m, const upb_MiniTable** sub_tables, + size_t sub_table_count, + const upb_MiniTableEnum** sub_enums, + size_t sub_enum_count) { + uint32_t msg_count = 0; + uint32_t enum_count = 0; + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + upb_MiniTableField* f = + (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { + const upb_MiniTable* sub = sub_tables[msg_count++]; + if (msg_count > sub_table_count) return false; + if (sub && !upb_MiniTable_SetSubMessage(m, f, sub)) return false; + } + } + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + upb_MiniTableField* f = + (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_IsClosedEnum(f)) { + const upb_MiniTableEnum* sub = sub_enums[enum_count++]; + if (enum_count > sub_enum_count) return false; + if (sub && !upb_MiniTable_SetSubEnum(m, f, sub)) return false; + } + } + + return (msg_count == sub_table_count) && (enum_count == sub_enum_count); +} + + +#include +#include +#include + + +// Must be last. + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; // Key is upb_MiniTable* concatenated with fieldnum. +}; + +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); +} + +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; +} + +UPB_API bool upb_ExtensionRegistry_Add(upb_ExtensionRegistry* r, + const upb_MiniTableExtension* e) { + char buf[EXTREG_KEY_SIZE]; + extreg_key(buf, e->UPB_PRIVATE(extendee), upb_MiniTableExtension_Number(e)); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, NULL)) return false; + return upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(e), r->arena); +} + +bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, + const upb_MiniTableExtension** e, + size_t count) { + const upb_MiniTableExtension** start = e; + const upb_MiniTableExtension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + if (!upb_ExtensionRegistry_Add(r, *e)) goto failure; + } + return true; + +failure: + // Back out the entries previously added. + for (end = e, e = start; e < end; e++) { + const upb_MiniTableExtension* ext = *e; + char buf[EXTREG_KEY_SIZE]; + extreg_key(buf, ext->UPB_PRIVATE(extendee), + upb_MiniTableExtension_Number(ext)); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); + } + return false; +} + +#ifdef UPB_LINKARR_DECLARE + +UPB_LINKARR_DECLARE(upb_AllExts, upb_MiniTableExtension); + +bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) { + const upb_MiniTableExtension* start = UPB_LINKARR_START(upb_AllExts); + const upb_MiniTableExtension* stop = UPB_LINKARR_STOP(upb_AllExts); + for (const upb_MiniTableExtension* p = start; p < stop; p++) { + // Windows can introduce zero padding, so we have to skip zeroes. + if (upb_MiniTableExtension_Number(p) != 0) { + if (!upb_ExtensionRegistry_Add(r, p)) return false; + } + } + return true; +} + +#endif // UPB_LINKARR_DECLARE + +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, t, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} + + +#include +#include +#include + + +// Must be last. + +const upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* m, uint32_t number) { + const size_t i = ((size_t)number) - 1; // 0 wraps to SIZE_MAX + + // Ideal case: index into dense fields + if (i < m->UPB_PRIVATE(dense_below)) { + UPB_ASSERT(m->UPB_PRIVATE(fields)[i].UPB_PRIVATE(number) == number); + return &m->UPB_PRIVATE(fields)[i]; + } + + // Slow case: binary search + int lo = m->UPB_PRIVATE(dense_below); + int hi = m->UPB_PRIVATE(field_count) - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + uint32_t num = m->UPB_PRIVATE(fields)[mid].UPB_PRIVATE(number); + if (num < number) { + lo = mid + 1; + continue; + } + if (num > number) { + hi = mid - 1; + continue; + } + return &m->UPB_PRIVATE(fields)[mid]; + } + return NULL; +} + +const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m, + const upb_MiniTableField* f) { + if (UPB_UNLIKELY(!upb_MiniTableField_IsInOneof(f))) { + return NULL; + } + const upb_MiniTableField* ptr = &m->UPB_PRIVATE(fields)[0]; + const upb_MiniTableField* end = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + for (; ptr < end; ptr++) { + if (ptr->presence == (*f).presence) { + return ptr; + } + } + return NULL; +} + +bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, + const upb_MiniTableField** f) { + const upb_MiniTableField* ptr = *f; + const upb_MiniTableField* end = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + while (++ptr < end) { + if (ptr->presence == (*f)->presence) { + *f = ptr; + return true; + } + } + return false; +} + + +#include +#include + + +// Must be last. + +// Checks if source and target mini table fields are identical. +// +// If the field is a sub message and sub messages are identical we record +// the association in table. +// +// Hashing the source sub message mini table and it's equivalent in the table +// stops recursing when a cycle is detected and instead just checks if the +// destination table is equal. +static upb_MiniTableEquals_Status upb_deep_check(const upb_MiniTable* src, + const upb_MiniTable* dst, + upb_inttable* table, + upb_Arena** arena) { + if (src->UPB_PRIVATE(field_count) != dst->UPB_PRIVATE(field_count)) + return kUpb_MiniTableEquals_NotEqual; + bool marked_src = false; + for (int i = 0; i < upb_MiniTable_FieldCount(src); i++) { + const upb_MiniTableField* src_field = upb_MiniTable_GetFieldByIndex(src, i); + const upb_MiniTableField* dst_field = upb_MiniTable_FindFieldByNumber( + dst, upb_MiniTableField_Number(src_field)); + + if (upb_MiniTableField_CType(src_field) != + upb_MiniTableField_CType(dst_field)) + return false; + if (src_field->UPB_PRIVATE(mode) != dst_field->UPB_PRIVATE(mode)) + return false; + if (src_field->UPB_PRIVATE(offset) != dst_field->UPB_PRIVATE(offset)) + return false; + if (src_field->presence != dst_field->presence) return false; + if (src_field->UPB_PRIVATE(submsg_index) != + dst_field->UPB_PRIVATE(submsg_index)) + return kUpb_MiniTableEquals_NotEqual; + + // Go no further if we are only checking for compatibility. + if (!table) continue; + + if (upb_MiniTableField_CType(src_field) == kUpb_CType_Message) { + if (!*arena) { + *arena = upb_Arena_New(); + if (!upb_inttable_init(table, *arena)) { + return kUpb_MiniTableEquals_OutOfMemory; + } + } + if (!marked_src) { + marked_src = true; + upb_value val; + val.val = (uint64_t)dst; + if (!upb_inttable_insert(table, (uintptr_t)src, val, *arena)) { + return kUpb_MiniTableEquals_OutOfMemory; + } + } + const upb_MiniTable* sub_src = + upb_MiniTable_GetSubMessageTable(src, src_field); + const upb_MiniTable* sub_dst = + upb_MiniTable_GetSubMessageTable(dst, dst_field); + if (sub_src != NULL) { + upb_value cmp; + if (upb_inttable_lookup(table, (uintptr_t)sub_src, &cmp)) { + // We already compared this src before. Check if same dst. + if (cmp.val != (uint64_t)sub_dst) { + return kUpb_MiniTableEquals_NotEqual; + } + } else { + // Recurse if not already visited. + upb_MiniTableEquals_Status s = + upb_deep_check(sub_src, sub_dst, table, arena); + if (s != kUpb_MiniTableEquals_Equal) { + return s; + } + } + } + } + } + return kUpb_MiniTableEquals_Equal; +} + +bool upb_MiniTable_Compatible(const upb_MiniTable* src, + const upb_MiniTable* dst) { + return upb_deep_check(src, dst, NULL, NULL); +} + +upb_MiniTableEquals_Status upb_MiniTable_Equals(const upb_MiniTable* src, + const upb_MiniTable* dst) { + // Arena allocated on demand for hash table. + upb_Arena* arena = NULL; + // Table to keep track of visited mini tables to guard against cycles. + upb_inttable table; + upb_MiniTableEquals_Status status = upb_deep_check(src, dst, &table, &arena); + if (arena) { + upb_Arena_Free(arena); + } + return status; +} + + +#include +#include +#include +#include +#include + + +// Must be last. + +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; + +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + kUpb_DecodeOp_Enum = 1, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; + +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the op. +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ + +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; + +// Ideally these two functions should take the owning MiniTable pointer as a +// first argument, then we could just put them in mini_table/message.h as nice +// clean getters. But we don't have that so instead we gotta write these +// Frankenfunctions that take an array of subtables. +// TODO: Move these to mini_table/ anyway since there are other places +// that could use them. + +// Returns the MiniTable corresponding to a given MiniTableField +// from an array of MiniTableSubs. +static const upb_MiniTable* _upb_MiniTableSubs_MessageByField( + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field) { + return *subs[field->UPB_PRIVATE(submsg_index)].UPB_PRIVATE(submsg); +} + +// Returns the MiniTableEnum corresponding to a given MiniTableField +// from an array of MiniTableSub. +static const upb_MiniTableEnum* _upb_MiniTableSubs_EnumByField( + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field) { + return subs[field->UPB_PRIVATE(submsg_index)].UPB_PRIVATE(subenum); +} + +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); + +UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, + upb_DecodeStatus status) { + UPB_ASSERT(status != kUpb_DecodeStatus_Ok); + d->status = status; + UPB_LONGJMP(d->err, 1); +} + +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { + UPB_ASSERT(status != kUpb_DecodeStatus_Ok); + d->status = status; + UPB_LONGJMP(d->err, 1); + return NULL; +} + +static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { + if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); + } +} + +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = + arr->UPB_PRIVATE(capacity) - arr->UPB_PRIVATE(size) < elem; + if (need_realloc && !UPB_PRIVATE(_upb_Array_Realloc)( + arr, arr->UPB_PRIVATE(size) + elem, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + return need_realloc; +} + +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; + +UPB_NOINLINE +static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( + const char* ptr, uint64_t val) { + _upb_DecodeLongVarintReturn ret = {NULL, 0}; + uint64_t byte; + for (int i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; + } + } + return ret; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeVarint(upb_Decoder* d, const char* ptr, + uint64_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; + } +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeTag(upb_Decoder* d, const char* ptr, + uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + const char* start = ptr; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + *val = res.val; + return res.ptr; + } +} + +UPB_FORCEINLINE +const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); + if (size64 >= INT32_MAX || + !upb_EpsCopyInputStream_CheckSize(&d->input, ptr, (int)size64)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; +} + +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; + } +} + +static void _upb_Decoder_Munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; + } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; + } + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + _upb_Decoder_MungeInt32(val); + break; + } +} + +static upb_Message* _upb_Decoder_NewSubMessage2(upb_Decoder* d, + const upb_MiniTable* subl, + const upb_MiniTableField* field, + upb_TaggedMessagePtr* target) { + UPB_ASSERT(subl); + upb_Message* msg = _upb_Message_New(subl, &d->arena); + if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + + // Extensions should not be unlinked. A message extension should not be + // registered until its sub-message type is available to be linked. + bool is_empty = UPB_PRIVATE(_upb_MiniTable_IsEmpty)(subl); + bool is_extension = field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension; + UPB_ASSERT(!(is_empty && is_extension)); + + if (is_empty && !(d->options & kUpb_DecodeOption_ExperimentalAllowUnlinked)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_UnlinkedSubMessage); + } + + upb_TaggedMessagePtr tagged = + UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(msg, is_empty); + memcpy(target, &tagged, sizeof(tagged)); + return msg; +} + +static upb_Message* _upb_Decoder_NewSubMessage( + upb_Decoder* d, const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* field, upb_TaggedMessagePtr* target) { + const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field); + return _upb_Decoder_NewSubMessage2(d, subl, field, target); +} + +static upb_Message* _upb_Decoder_ReuseSubMessage( + upb_Decoder* d, const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* field, upb_TaggedMessagePtr* target) { + upb_TaggedMessagePtr tagged = *target; + const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field); + UPB_ASSERT(subl); + if (!upb_TaggedMessagePtr_IsEmpty(tagged) || + UPB_PRIVATE(_upb_MiniTable_IsEmpty)(subl)) { + return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged); + } + + // We found an empty message from a previous parse that was performed before + // this field was linked. But it is linked now, so we want to allocate a new + // message of the correct type and promote data into it before continuing. + upb_Message* existing = + UPB_PRIVATE(_upb_TaggedMessagePtr_GetEmptyMessage)(tagged); + upb_Message* promoted = _upb_Decoder_NewSubMessage(d, subs, field, target); + size_t size; + const char* unknown = upb_Message_GetUnknown(existing, &size); + upb_DecodeStatus status = upb_Decode(unknown, size, promoted, subl, d->extreg, + d->options, &d->arena); + if (status != kUpb_DecodeStatus_Ok) _upb_Decoder_ErrorJmp(d, status); + return promoted; +} + +static const char* _upb_Decoder_ReadString(upb_Decoder* d, const char* ptr, + int size, upb_StringView* str) { + const char* str_ptr = ptr; + ptr = upb_EpsCopyInputStream_ReadString(&d->input, &str_ptr, size, &d->arena); + if (!ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + str->data = str_ptr; + str->size = size; + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeSubMessage(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* field, + int size) { + int saved_delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, size); + const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field); + UPB_ASSERT(subl); + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, saved_delta); + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (_upb_Decoder_IsDone(d, &ptr)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, const char* ptr, + uint32_t number) { + return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeKnownGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* field) { + const upb_MiniTable* subl = _upb_MiniTableSubs_MessageByField(subs, field); + UPB_ASSERT(subl); + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, + field->UPB_PRIVATE(number)); +} + +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; +} + +static void _upb_Decoder_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); + + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(msg, buf, end - buf, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +UPB_FORCEINLINE +bool _upb_Decoder_CheckEnum(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableEnum* e, + const upb_MiniTableField* field, wireval* val) { + const uint32_t v = val->uint32_val; + + if (UPB_LIKELY(upb_MiniTableEnum_CheckValue(e, v))) return true; + + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, + // so we just re-encode the tag and value here. + const uint32_t tag = + ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension ? d->unknown_msg + : msg; + _upb_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); + return false; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumArray( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = _upb_MiniTableSubs_EnumByField(subs, field); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * 4, void); + arr->UPB_PRIVATE(size)++; + memcpy(mem, val, 4); + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeFixedPacked(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTableField* field, + int lg2) { + int mask = (1 << lg2) - 1; + size_t count = val->size >> lg2; + if ((val->size & mask) != 0) { + // Length isn't a round multiple of elem size. + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + arr->UPB_PRIVATE(size) += count; + // Note: if/when the decoder supports multi-buffer input, we will need to + // handle buffer seams here. + if (upb_IsLittleEndian()) { + ptr = upb_EpsCopyInputStream_Copy(&d->input, ptr, mem, val->size); + } else { + int delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); + char* dst = mem; + while (!_upb_Decoder_IsDone(d, &ptr)) { + if (lg2 == 2) { + ptr = upb_WireReader_ReadFixed32(ptr, dst); + dst += 4; + } else { + UPB_ASSERT(lg2 == 3); + ptr = upb_WireReader_ReadFixed64(ptr, dst); + dst += 8; + } + } + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); + } + + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeVarintPacked(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTableField* field, + int lg2) { + int scale = 1 << lg2; + int saved_limit = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); + char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_Munge(field->UPB_PRIVATE(descriptortype), &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + } + arr->UPB_PRIVATE(size)++; + memcpy(out, &elem, scale); + out += scale; + } + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, saved_limit); + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = _upb_MiniTableSubs_EnumByField(subs, field); + int saved_limit = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); + char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * 4, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_MungeInt32(&elem); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { + continue; + } + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * 4, void); + } + arr->UPB_PRIVATE(size)++; + memcpy(out, &elem, 4); + out += 4; + } + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, saved_limit); + return ptr; +} + +static upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTableField* field) { + const upb_FieldType field_type = field->UPB_PRIVATE(descriptortype); + const size_t lg2 = UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type); + upb_Array* ret = UPB_PRIVATE(_upb_Array_New)(&d->arena, 4, lg2); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; +} + +static const char* _upb_Decoder_DecodeToArray( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); + upb_Array* arr = *arrp; + void* mem; + + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; + } + + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << op, void); + arr->UPB_PRIVATE(size)++; + memcpy(mem, val, 1 << op); + return ptr; + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)upb_Array_MutableDataPtr(arr) + + arr->UPB_PRIVATE(size); + arr->UPB_PRIVATE(size)++; + return _upb_Decoder_ReadString(d, ptr, val->size, str); + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_TaggedMessagePtr* target = UPB_PTR_AT( + upb_Array_MutableDataPtr(arr), arr->UPB_PRIVATE(size) * sizeof(void*), + upb_TaggedMessagePtr); + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field, target); + arr->UPB_PRIVATE(size)++; + if (UPB_UNLIKELY(field->UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_Enum: + return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); + default: + UPB_UNREACHABLE(); + } +} + +static upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, + const upb_MiniTable* entry) { + // Maps descriptor type -> upb map size + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; + + const upb_MiniTableField* key_field = &entry->UPB_PRIVATE(fields)[0]; + const upb_MiniTableField* val_field = &entry->UPB_PRIVATE(fields)[1]; + char key_size = kSizeInMap[key_field->UPB_PRIVATE(descriptortype)]; + char val_size = kSizeInMap[val_field->UPB_PRIVATE(descriptortype)]; + UPB_ASSERT(key_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, k)); + UPB_ASSERT(val_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, v)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; +} + +static const char* _upb_Decoder_DecodeToMap( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + UPB_ASSERT(upb_MiniTableField_Type(field) == kUpb_FieldType_Message); + const upb_MiniTable* entry = _upb_MiniTableSubs_MessageByField(subs, field); + + UPB_ASSERT(entry); + UPB_ASSERT(entry->UPB_PRIVATE(field_count) == 2); + UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[0])); + UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[1])); + + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; + } + + // Parse map entry. + memset(&ent, 0, sizeof(ent)); + + if (entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Message || + entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Group) { + // Create proactively to handle the case where it doesn't appear. + upb_TaggedMessagePtr msg; + _upb_Decoder_NewSubMessage(d, entry->UPB_PRIVATE(subs), + &entry->UPB_PRIVATE(fields)[1], &msg); + ent.v.val = upb_value_uintptr(msg); + } + + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.message, subs, field, + val->size); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.message, &size); + if (size != 0) { + char* buf; + size_t size; + uint32_t tag = + ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Delimited; + upb_EncodeStatus status = + upb_Encode(&ent.message, entry, 0, &d->arena, &buf, &size); + if (status != kUpb_EncodeStatus_Ok) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + _upb_Decoder_AddUnknownVarints(d, msg, tag, size); + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(msg, buf, size, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == kUpb_MapInsertStatus_OutOfMemory) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; +} + +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field, + wireval* val, int op) { + void* mem = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); + int type = field->UPB_PRIVATE(descriptortype); + + if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) && + !_upb_Decoder_CheckEnum(d, ptr, msg, + _upb_MiniTableSubs_EnumByField(subs, field), + field, val)) { + return ptr; + } + + // Set presence if necessary. + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(field)) { + UPB_PRIVATE(_upb_Message_SetHasbit)(msg, field); + } else if (upb_MiniTableField_IsInOneof(field)) { + // Oneof case + uint32_t* oneof_case = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, field); + if (op == kUpb_DecodeOp_SubMessage && + *oneof_case != field->UPB_PRIVATE(number)) { + memset(mem, 0, sizeof(void*)); + } + *oneof_case = field->UPB_PRIVATE(number); + } + + // Store into message. + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_TaggedMessagePtr* submsgp = mem; + upb_Message* submsg; + if (*submsgp) { + submsg = _upb_Decoder_ReuseSubMessage(d, subs, field, submsgp); + } else { + submsg = _upb_Decoder_NewSubMessage(d, subs, field, submsgp); + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + break; + } + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString(d, ptr, val->size, mem); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Enum: + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); + } + + return ptr; +} + +UPB_NOINLINE +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* m) { + UPB_ASSERT(m->UPB_PRIVATE(required_count)); + if (UPB_UNLIKELY(d->options & kUpb_DecodeOption_CheckRequired)) { + d->missing_required = + !UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m); + } + return ptr; +} + +UPB_FORCEINLINE +bool _upb_Decoder_TryFastDispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, const upb_MiniTable* m) { +#if UPB_FASTTABLE + if (m && m->UPB_PRIVATE(table_mask) != (unsigned char)-1) { + uint16_t tag = _upb_FastDecoder_LoadTag(*ptr); + intptr_t table = decode_totable(m); + *ptr = _upb_FastDecoder_TagDispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; +} + +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return _upb_Decoder_DecodeVarint(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; + } + case kUpb_WireType_StartGroup: + return _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + default: + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } +} + +enum { + kStartItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((kUpb_MsgSet_TypeId << 3) | kUpb_WireType_Varint), + kMessageTag = ((kUpb_MsgSet_Message << 3) | kUpb_WireType_Delimited), +}; + +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTableExtension* item_mt, + const char* data, uint32_t size) { + upb_Extension* ext = + UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message* submsg = _upb_Decoder_NewSubMessage2( + d, ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg), + &ext->ext->UPB_PRIVATE(field), (upb_TaggedMessagePtr*)&ext->data); + upb_DecodeStatus status = upb_Decode( + data, size, submsg, upb_MiniTableExtension_GetSubMessage(item_mt), + d->extreg, d->options, &d->arena); + if (status != kUpb_DecodeStatus_Ok) _upb_Decoder_ErrorJmp(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(msg, buf, split - buf, &d->arena) || + !UPB_PRIVATE(_upb_Message_AddUnknown)(msg, message_data, message_size, + &d->arena) || + !UPB_PRIVATE(_upb_Message_AddUnknown)(msg, split, end - split, + &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* t, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTableExtension* item_mt = + upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} + +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; + } + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +static const upb_MiniTableField* _upb_Decoder_FindField(upb_Decoder* d, + const upb_MiniTable* t, + uint32_t field_number, + int* last_field_index) { + static upb_MiniTableField none = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + if (t == NULL) return &none; + + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < t->UPB_PRIVATE(dense_below)) { + // Fastest case: index into dense fields. + goto found; + } + + if (t->UPB_PRIVATE(dense_below) < t->UPB_PRIVATE(field_count)) { + // Linear search non-dense fields. Resume scanning from last_field_index + // since fields are usually in order. + size_t last = *last_field_index; + for (idx = last; idx < t->UPB_PRIVATE(field_count); idx++) { + if (t->UPB_PRIVATE(fields)[idx].UPB_PRIVATE(number) == field_number) { + goto found; + } + } + + for (idx = t->UPB_PRIVATE(dense_below); idx < last; idx++) { + if (t->UPB_PRIVATE(fields)[idx].UPB_PRIVATE(number) == field_number) { + goto found; + } + } + } + + if (d->extreg) { + switch (t->UPB_PRIVATE(ext)) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); + if (ext) return &ext->UPB_PRIVATE(field); + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == kUpb_MsgSet_Item) { + static upb_MiniTableField item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } + break; + } + } + + return &none; // Unknown field. + +found: + UPB_ASSERT(t->UPB_PRIVATE(fields)[idx].UPB_PRIVATE(number) == field_number); + *last_field_index = idx; + return &t->UPB_PRIVATE(fields)[idx]; +} + +static int _upb_Decoder_GetVarintOp(const upb_MiniTableField* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; + + return kVarintOps[field->UPB_PRIVATE(descriptortype)]; +} + +UPB_FORCEINLINE +void _upb_Decoder_CheckUnlinked(upb_Decoder* d, const upb_MiniTable* mt, + const upb_MiniTableField* field, int* op) { + // If sub-message is not linked, treat as unknown. + if (field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension) return; + const upb_MiniTable* mt_sub = + _upb_MiniTableSubs_MessageByField(mt->UPB_PRIVATE(subs), field); + if ((d->options & kUpb_DecodeOption_ExperimentalAllowUnlinked) || + !UPB_PRIVATE(_upb_MiniTable_IsEmpty)(mt_sub)) { + return; + } +#ifndef NDEBUG + const upb_MiniTableField* oneof = upb_MiniTable_GetOneof(mt, field); + if (oneof) { + // All other members of the oneof must be message fields that are also + // unlinked. + do { + UPB_ASSERT(upb_MiniTableField_CType(oneof) == kUpb_CType_Message); + const upb_MiniTable* oneof_sub = + *mt->UPB_PRIVATE(subs)[oneof->UPB_PRIVATE(submsg_index)].UPB_PRIVATE( + submsg); + UPB_ASSERT(!oneof_sub); + } while (upb_MiniTable_NextOneofField(mt, &oneof)); + } +#endif // NDEBUG + *op = kUpb_DecodeOp_UnknownField; +} + +UPB_FORCEINLINE +void _upb_Decoder_MaybeVerifyUtf8(upb_Decoder* d, + const upb_MiniTableField* field, int* op) { + if ((field->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsAlternate) && + UPB_UNLIKELY(d->options & kUpb_DecodeOption_AlwaysValidateUtf8)) + *op = kUpb_DecodeOp_String; +} + +static int _upb_Decoder_GetDelimitedOp(upb_Decoder* d, const upb_MiniTable* mt, + const upb_MiniTableField* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + // For non-repeated field type. + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + // For repeated field type. + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; + + int ndx = field->UPB_PRIVATE(descriptortype); + if (upb_MiniTableField_IsArray(field)) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; + + if (op == kUpb_DecodeOp_SubMessage) { + _upb_Decoder_CheckUnlinked(d, mt, field, &op); + } else if (op == kUpb_DecodeOp_Bytes) { + _upb_Decoder_MaybeVerifyUtf8(d, field, &op); + } + + return op; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr, + const upb_MiniTable* mt, + const upb_MiniTableField* field, + int wire_type, wireval* val, int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); + + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); + *op = _upb_Decoder_GetVarintOp(field); + _upb_Decoder_Munge(field->UPB_PRIVATE(descriptortype), val); + return ptr; + case kUpb_WireType_32Bit: + *op = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return upb_WireReader_ReadFixed32(ptr, &val->uint32_val); + case kUpb_WireType_64Bit: + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return upb_WireReader_ReadFixed64(ptr, &val->uint64_val); + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(d, mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->UPB_PRIVATE(number); + if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + _upb_Decoder_CheckUnlinked(d, mt, field, op); + } else if (field->UPB_PRIVATE(descriptortype) == + kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeKnownField(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout, + const upb_MiniTableField* field, + int op, wireval* val) { + const upb_MiniTableSubInternal* subs = layout->UPB_PRIVATE(subs); + uint8_t mode = field->UPB_PRIVATE(mode); + upb_MiniTableSubInternal ext_sub; + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableExtension* ext_layout = + (const upb_MiniTableExtension*)field; + upb_Extension* ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + d->unknown_msg = msg; + msg = (upb_Message*)&ext->data; + if (upb_MiniTableField_IsSubMessage(&ext->ext->UPB_PRIVATE(field))) { + ext_sub.UPB_PRIVATE(submsg) = + &ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg); + } else { + ext_sub.UPB_PRIVATE(subenum) = + ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum); + } + subs = &ext_sub; + } + + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); + default: + UPB_UNREACHABLE(); + } +} + +static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, + uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; +} + +static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, + const char* ptr, + upb_Message* msg, + int field_number, + int wire_type, wireval val) { + if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + + // Since unknown fields are the uncommon case, we do a little extra work here + // to walk backwards through the buffer to find the field start. This frees + // up a register in the fast paths (when the field is known), which leads to + // significant speedups in benchmarks. + const char* start = ptr; + + if (wire_type == kUpb_WireType_Delimited) ptr += val.size; + if (msg) { + switch (wire_type) { + case kUpb_WireType_Varint: + case kUpb_WireType_Delimited: + start--; + while (start[-1] & 0x80) start--; + break; + case kUpb_WireType_32Bit: + start -= 4; + break; + case kUpb_WireType_64Bit: + start -= 8; + break; + default: + break; + } + + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = _upb_Decoder_ReverseSkipVarint(start, tag); + assert(start == d->debug_tagstart); + + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(msg, start, ptr - start, + &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + } + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 0; + +#if UPB_FASTTABLE + // The first time we want to skip fast dispatch, because we may have just been + // invoked by the fast parser to handle a case that it bailed on. + if (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; +#endif + + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + const upb_MiniTableField* field; + int field_number; + int wire_type; + wireval val; + int op; + + if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; + +#if UPB_FASTTABLE + nofast: +#endif + +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif + + UPB_ASSERT(ptr < d->input.limit_ptr); + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; + +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } + + field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, + &op); + + if (op >= 0) { + ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); + } else { + switch (op) { + case kUpb_DecodeOp_UnknownField: + ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, + wire_type, val); + break; + case kUpb_DecodeOp_MessageSetItem: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } + } + } + + return UPB_UNLIKELY(layout && layout->UPB_PRIVATE(required_count)) + ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) + : ptr; +} + +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); +} + +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, + upb_Message* msg, + const upb_MiniTable* m) { + if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, m)) { + _upb_Decoder_DecodeMessage(d, buf, msg, m); + } + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; +} + +UPB_NOINLINE +const char* _upb_Decoder_IsDoneFallback(upb_EpsCopyInputStream* e, + const char* ptr, int overrun) { + return _upb_EpsCopyInputStream_IsDoneFallbackInline( + e, ptr, overrun, _upb_Decoder_BufferFlipCallback); +} + +static upb_DecodeStatus upb_Decoder_Decode(upb_Decoder* const decoder, + const char* const buf, + upb_Message* const msg, + const upb_MiniTable* const m, + upb_Arena* const arena) { + if (UPB_SETJMP(decoder->err) == 0) { + decoder->status = _upb_Decoder_DecodeTop(decoder, buf, msg, m); + } else { + UPB_ASSERT(decoder->status != kUpb_DecodeStatus_Ok); + } + + UPB_PRIVATE(_upb_Arena_SwapOut)(arena, &decoder->arena); + + return decoder->status; +} + +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Decoder decoder; + unsigned depth = (unsigned)options >> 16; + + upb_EpsCopyInputStream_Init(&decoder.input, &buf, size, + options & kUpb_DecodeOption_AliasString); + + decoder.extreg = extreg; + decoder.unknown = NULL; + decoder.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; + decoder.end_group = DECODE_NOGROUP; + decoder.options = (uint16_t)options; + decoder.missing_required = false; + decoder.status = kUpb_DecodeStatus_Ok; + + // Violating the encapsulation of the arena for performance reasons. + // This is a temporary arena that we swap into and swap out of when we are + // done. The temporary arena only needs to be able to handle allocation, + // not fuse or free, so it does not need many of the members to be initialized + // (particularly parent_or_count). + UPB_PRIVATE(_upb_Arena_SwapIn)(&decoder.arena, arena); + + return upb_Decoder_Decode(&decoder, buf, msg, mt, arena); +} + +upb_DecodeStatus upb_DecodeLengthPrefixed(const char* buf, size_t size, + upb_Message* msg, + size_t* num_bytes_read, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + // To avoid needing to make a Decoder just to decode the initial length, + // hand-decode the leading varint for the message length here. + uint64_t msg_len = 0; + for (size_t i = 0;; ++i) { + if (i >= size || i > 9) { + return kUpb_DecodeStatus_Malformed; + } + uint64_t b = *buf; + buf++; + msg_len += (b & 0x7f) << (i * 7); + if ((b & 0x80) == 0) { + *num_bytes_read = i + 1 + msg_len; + break; + } + } + + // If the total number of bytes we would read (= the bytes from the varint + // plus however many bytes that varint says we should read) is larger then the + // input buffer then error as malformed. + if (*num_bytes_read > size) { + return kUpb_DecodeStatus_Malformed; + } + if (msg_len > INT32_MAX) { + return kUpb_DecodeStatus_Malformed; + } + + return upb_Decode(buf, msg_len, msg, mt, extreg, options, arena); +} + +const char* upb_DecodeStatus_String(upb_DecodeStatus status) { + switch (status) { + case kUpb_DecodeStatus_Ok: + return "Ok"; + case kUpb_DecodeStatus_Malformed: + return "Wire format was corrupt"; + case kUpb_DecodeStatus_OutOfMemory: + return "Arena alloc failed"; + case kUpb_DecodeStatus_BadUtf8: + return "String field had bad UTF-8"; + case kUpb_DecodeStatus_MaxDepthExceeded: + return "Exceeded upb_DecodeOptions_MaxDepth"; + case kUpb_DecodeStatus_MissingRequired: + return "Missing required field"; + case kUpb_DecodeStatus_UnlinkedSubMessage: + return "Unlinked sub-message field was present"; + default: + return "Unknown decode status"; + } +} + +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 + +// We encode backwards, to avoid pre-computing lengths (one-pass encode). + + +#include +#include +#include +#include + + +// Must be last. + +// Returns the MiniTable corresponding to a given MiniTableField +// from an array of MiniTableSubs. +static const upb_MiniTable* _upb_Encoder_GetSubMiniTable( + const upb_MiniTableSubInternal* subs, const upb_MiniTableField* field) { + return *subs[field->UPB_PRIVATE(submsg_index)].UPB_PRIVATE(submsg); +} + +#define UPB_PB_VARINT_MAX_LEN 10 + +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; +} + +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); +} +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); +} + +typedef struct { + upb_EncodeStatus status; + jmp_buf err; + upb_Arena* arena; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; + +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; + } + return ret; +} + +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_ASSERT(s != kUpb_EncodeStatus_Ok); + e->status = s; + UPB_LONGJMP(e->err, 1); +} + +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size); + + if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); + + // We want previous data at the end, realloc() put it at the beginning. + // TODO: This is somewhat inefficient since we are copying twice. + // Maybe create a realloc() that copies to the end of the new buffer? + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); + } + + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; + + e->ptr -= bytes; +} + +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; + } + + e->ptr -= bytes; +} + +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); +} + +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = upb_BigEndian64(val); + encode_bytes(e, &val, sizeof(uint64_t)); +} + +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = upb_BigEndian32(val); + encode_bytes(e, &val, sizeof(uint32_t)); +} + +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; + + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; +} + +UPB_FORCEINLINE +void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); + } +} + +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); +} + +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); +} + +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); +} + +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = upb_Array_Size(arr) * elem_size; + const char* data = upb_Array_DataPtr(arr); + const char* ptr = data + bytes - elem_size; + + if (tag || !upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = upb_BigEndian32(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = upb_BigEndian64(val); + encode_bytes(e, &val, elem_size); + } + + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; + } + } else { + encode_bytes(e, data, bytes); + } +} + +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); + +static void encode_TaggedMessagePtr(upb_encstate* e, + upb_TaggedMessagePtr tagged, + const upb_MiniTable* m, size_t* size) { + if (upb_TaggedMessagePtr_IsEmpty(tagged)) { + m = UPB_PRIVATE(_upb_MiniTable_Empty)(); + } + encode_message(e, UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged), m, + size); +} + +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* f) { + const char* field_mem = _field_mem; + int wire_type; + +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ + } + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; + } + case kUpb_FieldType_Group: { + size_t size; + upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; + const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f); + if (submsg == 0) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_EndGroup); + encode_TaggedMessagePtr(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; + } + case kUpb_FieldType_Message: { + size_t size; + upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; + const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f); + if (submsg == 0) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_TaggedMessagePtr(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; + } + default: + UPB_UNREACHABLE(); + } +#undef CASE + + encode_tag(e, upb_MiniTableField_Number(f), wire_type); +} + +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*); + bool packed = upb_MiniTableField_IsPacked(f); + size_t pre_len = e->limit - e->ptr; + + if (arr == NULL || upb_Array_Size(arr) == 0) { + return; + } + +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = upb_Array_DataPtr(arr); \ + const ctype* ptr = start + upb_Array_Size(arr); \ + uint32_t tag = \ + packed ? 0 : (f->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; + +#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type)) + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = upb_Array_DataPtr(arr); + const upb_StringView* ptr = start + upb_Array_Size(arr); + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const upb_TaggedMessagePtr* start = upb_Array_DataPtr(arr); + const upb_TaggedMessagePtr* ptr = start + upb_Array_Size(arr); + const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_EndGroup); + encode_TaggedMessagePtr(e, *ptr, subm, &size); + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const upb_TaggedMessagePtr* start = upb_Array_DataPtr(arr); + const upb_TaggedMessagePtr* ptr = start + upb_Array_Size(arr); + const upb_MiniTable* subm = _upb_Encoder_GetSubMiniTable(subs, f); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_TaggedMessagePtr(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; + } + } +#undef VARINT_CASE + + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, upb_MiniTableField_Number(f), kUpb_WireType_Delimited); + } +} + +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTableField* key_field = upb_MiniTable_MapKey(layout); + const upb_MiniTableField* val_field = upb_MiniTable_MapValue(layout); + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout->UPB_PRIVATE(subs), val_field); + encode_scalar(e, &ent->k, layout->UPB_PRIVATE(subs), key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); +} + +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*); + const upb_MiniTable* layout = _upb_Encoder_GetSubMiniTable(subs, f); + UPB_ASSERT(upb_MiniTable_FieldCount(layout) == 2); + + if (!map || !upb_Map_Size(map)) return; + + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap( + &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), + map, &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, upb_MiniTableField_Number(f), layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&map->table, &key, &val, &iter)) { + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, upb_MiniTableField_Number(f), layout, &ent); + } + } +} + +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableField* f) { + if (f->presence == 0) { + // Proto3 presence or map/array. + const void* mem = UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), void); + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + // Proto2 presence: hasbit. + return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f); + } else { + // Field is in a oneof. + return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) == + upb_MiniTableField_Number(f); + } +} + +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSubInternal* subs, + const upb_MiniTableField* field) { + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); + break; + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); + break; + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), subs, + field); + break; + default: + UPB_UNREACHABLE(); + } +} + +static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) { + size_t size; + encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup); + encode_message(e, ext->data.msg_val, + upb_MiniTableExtension_GetSubMessage(ext->ext), &size); + encode_varint(e, size); + encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); + encode_varint(e, upb_MiniTableExtension_Number(ext->ext)); + encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint); + encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup); +} + +static void encode_ext(upb_encstate* e, const upb_Extension* ext, + bool is_message_set) { + if (UPB_UNLIKELY(is_message_set)) { + encode_msgset_item(e, ext); + } else { + upb_MiniTableSubInternal sub; + if (upb_MiniTableField_IsSubMessage(&ext->ext->UPB_PRIVATE(field))) { + sub.UPB_PRIVATE(submsg) = &ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg); + } else { + sub.UPB_PRIVATE(subenum) = + ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum); + } + encode_field(e, (upb_Message*)&ext->data, &sub, + &ext->ext->UPB_PRIVATE(field)); + } +} + +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; + + if (e->options & kUpb_EncodeOption_CheckRequired) { + if (m->UPB_PRIVATE(required_count)) { + if (!UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m)) { + encode_err(e, kUpb_EncodeStatus_MissingRequired); + } + } + } + + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); + + if (unknown) { + encode_bytes(e, unknown, unknown_size); + } + } + + if (m->UPB_PRIVATE(ext) != kUpb_ExtMode_NonExtendable) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_Extension* ext = + UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count); + if (ext_count) { + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted); + while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) { + encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + const upb_Extension* end = ext + ext_count; + for (; ext != end; ext++) { + encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet); + } + } + } + } + + if (upb_MiniTable_FieldCount(m)) { + const upb_MiniTableField* f = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, f)) { + encode_field(e, msg, m->UPB_PRIVATE(subs), f); + } + } + } + + *size = (e->limit - e->ptr) - pre_len; +} + +static upb_EncodeStatus upb_Encoder_Encode(upb_encstate* const encoder, + const upb_Message* const msg, + const upb_MiniTable* const l, + char** const buf, size_t* const size, + bool prepend_len) { + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (UPB_SETJMP(encoder->err) == 0) { + size_t encoded_msg_size; + encode_message(encoder, msg, l, &encoded_msg_size); + if (prepend_len) { + encode_varint(encoder, encoded_msg_size); + } + *size = encoder->limit - encoder->ptr; + if (*size == 0) { + static char ch; + *buf = &ch; + } else { + UPB_ASSERT(encoder->ptr); + *buf = encoder->ptr; + } + } else { + UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); + *buf = NULL; + *size = 0; + } + + _upb_mapsorter_destroy(&encoder->sorter); + return encoder->status; +} + +static upb_EncodeStatus _upb_Encode(const upb_Message* msg, + const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, size_t* size, + bool prepend_len) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; + + e.status = kUpb_EncodeStatus_Ok; + e.arena = arena; + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; + e.options = options; + _upb_mapsorter_init(&e.sorter); + + return upb_Encoder_Encode(&e, msg, l, buf, size, prepend_len); +} + +upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { + return _upb_Encode(msg, l, options, arena, buf, size, false); +} + +upb_EncodeStatus upb_EncodeLengthPrefixed(const upb_Message* msg, + const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, + size_t* size) { + return _upb_Encode(msg, l, options, arena, buf, size, true); +} + +const char* upb_EncodeStatus_String(upb_EncodeStatus status) { + switch (status) { + case kUpb_EncodeStatus_Ok: + return "Ok"; + case kUpb_EncodeStatus_MissingRequired: + return "Missing required field"; + case kUpb_EncodeStatus_MaxDepthExceeded: + return "Max depth exceeded"; + case kUpb_EncodeStatus_OutOfMemory: + return "Arena alloc failed"; + default: + return "Unknown encode status"; + } +} + +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. +// Also the table size grows by 2x. +// +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. + + + +// Must be last. + +#if UPB_FASTTABLE + +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ + return _upb_FastDecoder_DecodeGeneric(d, ptr, msg, table, hasbits, 0); + +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; + +UPB_NOINLINE +static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; + ptr = _upb_EpsCopyInputStream_IsDoneFallbackInline( + &d->input, ptr, overrun, _upb_Decoder_BufferFlipCallback); + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { + int overrun; + switch (upb_EpsCopyInputStream_IsDoneStatus(&d->input, ptr, &overrun)) { + case kUpb_IsDoneStatus_Done: + ((uint32_t*)msg)[2] |= hasbits; // Sync hasbits. + const upb_MiniTable* m = decode_totablep(table); + return UPB_UNLIKELY(m->UPB_PRIVATE(required_count)) + ? _upb_Decoder_CheckRequired(d, ptr, msg, m) + : ptr; + case kUpb_IsDoneStatus_NotDone: + break; + case kUpb_IsDoneStatus_NeedFallback: + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + } + + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +bool fastdecode_checktag(uint16_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; + } else { + return data == 0; + } +} + +UPB_FORCEINLINE +const char* fastdecode_longsize(const char* ptr, int* size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; +} + +UPB_FORCEINLINE +const char* fastdecode_delimited( + upb_Decoder* d, const char* ptr, + upb_EpsCopyInputStream_ParseDelimitedFunc* func, void* ctx) { + ptr++; + + // Sign-extend so varint greater than one byte becomes negative, causing + // fast delimited parse to fail. + int len = (int8_t)ptr[-1]; + + if (!upb_EpsCopyInputStream_TryParseDelimitedFast(&d->input, &ptr, len, func, + ctx)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; + } + } + if (!upb_EpsCopyInputStream_CheckSize(&d->input, ptr, len)) { + // Corrupt wire format: invalid limit. + return NULL; + } + int delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, len); + ptr = func(&d->input, ptr, ctx); + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); + } + return ptr; +} + +/* singular, oneof, repeated field handling ***********************************/ + +typedef struct { + upb_Array* arr; + void* end; +} fastdecode_arr; + +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; + +typedef struct { + void* dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; + +UPB_FORCEINLINE +void* fastdecode_resizearr(upb_Decoder* d, void* dst, fastdecode_arr* farr, + int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_capacity = farr->arr->UPB_PRIVATE(capacity); + size_t old_bytes = old_capacity * valbytes; + size_t new_capacity = old_capacity * 2; + size_t new_bytes = new_capacity * valbytes; + char* old_ptr = upb_Array_MutableDataPtr(farr->arr); + char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + UPB_PRIVATE(_upb_Array_SetTaggedPtr)(farr->arr, new_ptr, elem_size_lg2); + farr->arr->UPB_PRIVATE(capacity) = new_capacity; + dst = (void*)(new_ptr + (old_capacity * valbytes)); + farr->end = (void*)(new_ptr + (new_capacity * valbytes)); + } + return dst; +} + +UPB_FORCEINLINE +bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; + } else { + return (uint16_t)tag == (uint16_t)data; + } +} + +UPB_FORCEINLINE +void fastdecode_commitarr(void* dst, fastdecode_arr* farr, int valbytes) { + farr->arr->UPB_PRIVATE(size) = + (size_t)((char*)dst - (char*)upb_Array_MutableDataPtr(farr->arr)) / + valbytes; +} + +UPB_FORCEINLINE +fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, + const char** ptr, + fastdecode_arr* farr, uint64_t data, + int tagbytes, int valbytes) { + fastdecode_nextret ret; + dst = (char*)dst + valbytes; + + if (UPB_LIKELY(!_upb_Decoder_IsDone(d, ptr))) { + ret.tag = _upb_FastDecoder_LoadTag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; + } + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; + } + + ret.dst = dst; + return ret; +} + +UPB_FORCEINLINE +void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { + size_t ofs = data >> 48; + return (char*)msg + ofs; +} + +UPB_FORCEINLINE +void* fastdecode_getfield(upb_Decoder* d, const char* ptr, upb_Message* msg, + uint64_t* data, uint64_t* hasbits, + fastdecode_arr* farr, int valbytes, upb_card card) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_Array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_Array** arr_p = fastdecode_fieldmem(msg, *data); + char* begin; + ((uint32_t*)msg)[2] |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = UPB_PRIVATE(_upb_Array_New)(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = upb_Array_MutableDataPtr(farr->arr); + farr->end = begin + (farr->arr->UPB_PRIVATE(capacity) * valbytes); + *data = _upb_FastDecoder_LoadTag(ptr); + return begin + (farr->arr->UPB_PRIVATE(size) * valbytes); + } + default: + UPB_UNREACHABLE(); + } +} + +UPB_FORCEINLINE +bool fastdecode_flippacked(uint64_t* data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); +} + +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } + +/* varint fields **************************************************************/ + +UPB_FORCEINLINE +uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); + } + UPB_UNREACHABLE(); + } + return val; +} + +UPB_FORCEINLINE +const char* fastdecode_varint64(const char* ptr, uint64_t* val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; + } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; + } + *val += (byte - 1) << 63; + } +done: + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +typedef struct { + uint8_t valbytes; + bool zigzag; + void* dst; + fastdecode_arr farr; +} fastdecode_varintdata; + +UPB_FORCEINLINE +const char* fastdecode_topackedvarint(upb_EpsCopyInputStream* e, + const char* ptr, void* ctx) { + upb_Decoder* d = (upb_Decoder*)e; + fastdecode_varintdata* data = ctx; + void* dst = data->dst; + uint64_t val; + + while (!_upb_Decoder_IsDone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char*)dst + data->valbytes; + } + + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; +} + +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); + +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ + } + +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false + +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ + +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT + +/* fixed fields ***************************************************************/ + +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(!upb_EpsCopyInputStream_CheckDataSizeAvailable( \ + &d->input, ptr, size) || \ + (size % valbytes) != 0)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ + upb_Array* arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = \ + UPB_PRIVATE(_upb_Array_New)(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, elems, &d->arena); \ + } \ + \ + char* dst = upb_Array_MutableDataPtr(arr); \ + memcpy(dst, ptr, size); \ + arr->UPB_PRIVATE(size) = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ + } + +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ + +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED + +/* string fields **************************************************************/ + +typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + const upb_MiniTable* table, + uint64_t hasbits, + upb_StringView* dst); + +UPB_NOINLINE +static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_StringView* dst = (upb_StringView*)data; + if (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); + } + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +} + +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(!upb_EpsCopyInputStream_CheckSize(&d->input, ptr, size))) { \ + dst->size = 0; \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + const char* s_ptr = ptr; \ + ptr = upb_EpsCopyInputStream_ReadString(&d->input, &s_ptr, size, &d->arena); \ + if (!ptr) _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); \ + dst->data = s_ptr; \ + dst->size = size; \ + \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + } + +UPB_NOINLINE +static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); +} + +UPB_NOINLINE +static const char* fastdecode_longstring_noutf8( + struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); +} + +UPB_FORCEINLINE +void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, int copy, + char* data, size_t data_offset, upb_StringView* dst) { + d->arena.UPB_PRIVATE(ptr) += copy; + dst->data = data + data_offset; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + data_offset + size, + copy - data_offset - size); +} + +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char* buf; \ + \ + UPB_ASSERT(!upb_EpsCopyInputStream_AliasingAvailable(&d->input, ptr, 0)); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.UPB_PRIVATE(ptr); \ + arena_has = UPB_PRIVATE(_upb_ArenaHas)(&d->arena); \ + common_has = UPB_MIN(arena_has, \ + upb_EpsCopyInputStream_BytesAvailable(&d->input, ptr)); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) goto longstr; \ + fastdecode_docopy(d, ptr - tagbytes - 1, size, 16, buf, tagbytes + 1, \ + dst); \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, 0, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, 0, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, 0, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + if (card == CARD_r) { \ + fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ + } \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } + +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY( \ + !upb_EpsCopyInputStream_AliasingAvailable(&d->input, ptr, 0))) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + \ + if (UPB_UNLIKELY( \ + !upb_EpsCopyInputStream_AliasingAvailable(&d->input, ptr, size))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + dst->data = ptr; \ + dst->size = size; \ + ptr = upb_EpsCopyInputStream_ReadStringAliased(&d->input, &dst->data, \ + dst->size); \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + +#define s_VALIDATE true +#define b_VALIDATE false + +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING + +/* message fields *************************************************************/ + +UPB_INLINE +upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* m, + int msg_ceil_bytes) { + size_t size = m->UPB_PRIVATE(size); + char* msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + UPB_PRIVATE(_upb_ArenaHas)(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.UPB_PRIVATE(ptr); + d->arena.UPB_PRIVATE(ptr) += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + } else { + msg_data = (char*)upb_Arena_Malloc(&d->arena, size); + memset(msg_data, 0, size); + } + return (upb_Message*)msg_data; +} + +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; + +UPB_FORCEINLINE +const char* fastdecode_tosubmsg(upb_EpsCopyInputStream* e, const char* ptr, + void* ctx) { + upb_Decoder* d = (upb_Decoder*)e; + fastdecode_submsgdata* submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); \ + } \ + \ + upb_Message** dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_MiniTable* tablep = decode_totablep(table); \ + const upb_MiniTable* subtablep = upb_MiniTableSub_Message( \ + *UPB_PRIVATE(_upb_MiniTable_GetSubByIndex)(tablep, submsg_idx)); \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->UPB_PRIVATE(table_mask) == (uint8_t)-1) { \ + d->depth++; \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_Message*), card); \ + \ + if (card == CARD_s) { \ + ((uint32_t*)msg)[2] |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ + } + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG + +#endif /* UPB_FASTTABLE */ + + +#include +#include + + +// Must be last. + +UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) + UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val) { + UPB_PRIVATE(_upb_WireReader_LongVarint) ret = {NULL, 0}; + uint64_t byte; + for (int i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; + } + } + return ret; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + if (--depth_limit == 0) return NULL; + uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup; + while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag); + if (!ptr) return NULL; + if (tag == end_group_tag) return ptr; + ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, stream); + if (!ptr) return NULL; + } + return ptr; +} + +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#include + +// Must be last. + +extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken); +static const upb_MiniTableSubInternal google_protobuf_FileDescriptorSet__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FileDescriptorProto_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_FileDescriptorSet__fields[1] = { + {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FileDescriptorSet_msg_init = { + &google_protobuf_FileDescriptorSet__submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileDescriptorSet", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x000800003f00000a, &upb_prm_1bt_max192b}, + }) +}; + +const upb_MiniTable* google__protobuf__FileDescriptorSet_msg_init_ptr = &google__protobuf__FileDescriptorSet_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FileDescriptorProto__submsgs[7] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FileOptions_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FileDescriptorProto__fields[13] = { + {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(60, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(32, 88), 66, 4, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(36, 96), 67, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(68, 120), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {14, UPB_SIZE(48, 12), 69, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FileDescriptorProto_msg_init = { + &google_protobuf_FileDescriptorProto__submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(80, 136), 13, kUpb_ExtMode_NonExtendable, 12, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x003000003f00001a, &upb_prs_1bt}, + {0x003800003f000022, &upb_prm_1bt_max128b}, + {0x004000003f01002a, &upb_prm_1bt_max128b}, + {0x004800003f020032, &upb_prm_1bt_max64b}, + {0x005000003f03003a, &upb_prm_1bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x006800003f000050, &upb_prv4_1bt}, + {0x007000003f000058, &upb_prv4_1bt}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__FileDescriptorProto_msg_init_ptr = &google__protobuf__FileDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_DescriptorProto__submsgs[8] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ExtensionRange_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__MessageOptions_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__OneofDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ReservedRange_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(48, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 72), 65, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__DescriptorProto_msg_init = { + &google_protobuf_DescriptorProto__submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(56, 104), 10, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002000003f000012, &upb_prm_1bt_max128b}, + {0x002800003f01001a, &upb_prm_1bt_max128b}, + {0x003000003f020022, &upb_prm_1bt_max128b}, + {0x003800003f03002a, &upb_prm_1bt_max64b}, + {0x004000003f040032, &upb_prm_1bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x005000003f060042, &upb_prm_1bt_max64b}, + {0x005800003f07004a, &upb_prm_1bt_max64b}, + {0x006000003f000052, &upb_prs_1bt}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__DescriptorProto_msg_init_ptr = &google__protobuf__DescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_DescriptorProto_ExtensionRange__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 24), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__DescriptorProto__ExtensionRange_msg_init = { + &google_protobuf_DescriptorProto_ExtensionRange__submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto.ExtensionRange", +#endif +}; + +const upb_MiniTable* google__protobuf__DescriptorProto__ExtensionRange_msg_init_ptr = &google__protobuf__DescriptorProto__ExtensionRange_msg_init; +static const upb_MiniTableField google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__DescriptorProto__ReservedRange_msg_init = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto.ReservedRange", +#endif +}; + +const upb_MiniTable* google__protobuf__DescriptorProto__ReservedRange_msg_init_ptr = &google__protobuf__DescriptorProto__ReservedRange_msg_init; +static const upb_MiniTableSubInternal google_protobuf_ExtensionRangeOptions__submsgs[4] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions__Declaration_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_ExtensionRangeOptions__fields[4] = { + {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 12), 64, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {50, UPB_SIZE(20, 24), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__ExtensionRangeOptions_msg_init = { + &google_protobuf_ExtensionRangeOptions__submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(32, 40), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ExtensionRangeOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001000003f000012, &upb_prm_1bt_max64b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002000003f023eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__ExtensionRangeOptions_msg_init_ptr = &google__protobuf__ExtensionRangeOptions_msg_init; +static const upb_MiniTableField google_protobuf_ExtensionRangeOptions_Declaration__fields[5] = { + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(28, 40), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {5, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 17, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__ExtensionRangeOptions__Declaration_msg_init = { + NULL, + &google_protobuf_ExtensionRangeOptions_Declaration__fields[0], + UPB_SIZE(40, 56), 5, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ExtensionRangeOptions.Declaration", +#endif +}; + +const upb_MiniTable* google__protobuf__ExtensionRangeOptions__Declaration_msg_init_ptr = &google__protobuf__ExtensionRangeOptions__Declaration_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FieldDescriptorProto__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Label_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Type_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(36, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(44, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 16, 67, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 20, 68, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(52, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(60, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 96), 71, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(68, 104), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(32, 28), 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FieldDescriptorProto_msg_init = { + &google_protobuf_FieldDescriptorProto__submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(80, 120), 11, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldDescriptorProto", +#endif +}; + +const upb_MiniTable* google__protobuf__FieldDescriptorProto_msg_init_ptr = &google__protobuf__FieldDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_OneofDescriptorProto__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__OneofOptions_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_OneofDescriptorProto__fields[2] = { + {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__OneofDescriptorProto_msg_init = { + &google_protobuf_OneofDescriptorProto__submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(24, 40), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.OneofDescriptorProto", +#endif +}; + +const upb_MiniTable* google__protobuf__OneofDescriptorProto_msg_init_ptr = &google__protobuf__OneofDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_EnumDescriptorProto__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumOptions_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(28, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__EnumDescriptorProto_msg_init = { + &google_protobuf_EnumDescriptorProto__submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(40, 64), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002000003f000012, &upb_prm_1bt_max64b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x003000003f020022, &upb_prm_1bt_max64b}, + {0x003800003f00002a, &upb_prs_1bt}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__EnumDescriptorProto_msg_init_ptr = &google__protobuf__EnumDescriptorProto_msg_init; +static const upb_MiniTableField google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumDescriptorProto.EnumReservedRange", +#endif +}; + +const upb_MiniTable* google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_ptr = &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init; +static const upb_MiniTableSubInternal google_protobuf_EnumValueDescriptorProto__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueOptions_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__EnumValueDescriptorProto_msg_init = { + &google_protobuf_EnumValueDescriptorProto__submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(32, 40), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumValueDescriptorProto", +#endif +}; + +const upb_MiniTable* google__protobuf__EnumValueDescriptorProto_msg_init_ptr = &google__protobuf__EnumValueDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_ServiceDescriptorProto__submsgs[2] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__MethodDescriptorProto_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceOptions_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__ServiceDescriptorProto_msg_init = { + &google_protobuf_ServiceDescriptorProto__submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(32, 48), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ServiceDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002000003f000012, &upb_prm_1bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__ServiceDescriptorProto_msg_init_ptr = &google__protobuf__ServiceDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_MethodDescriptorProto__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__MethodOptions_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(28, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(36, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 64), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 9), 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(17, 10), 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__MethodDescriptorProto_msg_init = { + &google_protobuf_MethodDescriptorProto__submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(48, 72), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MethodDescriptorProto", +#endif +}; + +const upb_MiniTable* google__protobuf__MethodDescriptorProto_msg_init_ptr = &google__protobuf__MethodDescriptorProto_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FileOptions__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FileOptions__OptimizeMode_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, 12, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, 17, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 18, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, 19, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, 20, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, 21, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, 22, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, 23, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {50, UPB_SIZE(24, 184), 83, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FileOptions_msg_init = { + &google_protobuf_FileOptions__submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(112, 200), 21, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x00c000003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__FileOptions_msg_init_ptr = &google__protobuf__FileOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_MessageOptions__submsgs[2] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_MessageOptions__fields[7] = { + {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {12, 16, 69, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__MessageOptions_msg_init = { + &google_protobuf_MessageOptions__submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(24, 32), 7, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MessageOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__MessageOptions_msg_init_ptr = &google__protobuf__MessageOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FieldOptions__submsgs[8] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__EditionDefault_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__CType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__JSType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionRetention_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionTargetType_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FieldOptions__fields[14] = { + {1, 12, 64, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 17, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, 18, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 20, 68, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 24, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, 25, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {16, 26, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 28, 72, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {21, UPB_SIZE(40, 48), 73, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {22, UPB_SIZE(44, 56), 74, 2, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FieldOptions_msg_init = { + &google_protobuf_FieldOptions__submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(56, 72), 14, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002800003f0001a2, &upb_prm_2bt_max64b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x004000003f033eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__FieldOptions_msg_init_ptr = &google__protobuf__FieldOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FieldOptions_EditionDefault__submsgs[1] = { + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FieldOptions_EditionDefault__fields[2] = { + {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 12, 65, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FieldOptions__EditionDefault_msg_init = { + &google_protobuf_FieldOptions_EditionDefault__submsgs[0], + &google_protobuf_FieldOptions_EditionDefault__fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions.EditionDefault", +#endif +}; + +const upb_MiniTable* google__protobuf__FieldOptions__EditionDefault_msg_init_ptr = &google__protobuf__FieldOptions__EditionDefault_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FieldOptions_FeatureSupport__submsgs[3] = { + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FieldOptions_FeatureSupport__fields[4] = { + {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, 20, 67, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FieldOptions__FeatureSupport_msg_init = { + &google_protobuf_FieldOptions_FeatureSupport__submsgs[0], + &google_protobuf_FieldOptions_FeatureSupport__fields[0], + UPB_SIZE(32, 40), 4, kUpb_ExtMode_NonExtendable, 4, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions.FeatureSupport", +#endif +}; + +const upb_MiniTable* google__protobuf__FieldOptions__FeatureSupport_msg_init_ptr = &google__protobuf__FieldOptions__FeatureSupport_msg_init; +static const upb_MiniTableSubInternal google_protobuf_OneofOptions__submsgs[2] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_OneofOptions__fields[2] = { + {1, UPB_SIZE(12, 16), 64, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__OneofOptions_msg_init = { + &google_protobuf_OneofOptions__submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.OneofOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__OneofOptions_msg_init_ptr = &google__protobuf__OneofOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_EnumOptions__submsgs[2] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_EnumOptions__fields[5] = { + {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(12, 16), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__EnumOptions_msg_init = { + &google_protobuf_EnumOptions__submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(24, 32), 5, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__EnumOptions_msg_init_ptr = &google__protobuf__EnumOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_EnumValueOptions__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_EnumValueOptions__fields[5] = { + {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 10), 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 24), 67, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__EnumValueOptions_msg_init = { + &google_protobuf_EnumValueOptions__submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(32, 40), 5, kUpb_ExtMode_Extendable, 4, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumValueOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x002000003f023eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__EnumValueOptions_msg_init_ptr = &google__protobuf__EnumValueOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_ServiceOptions__submsgs[2] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_ServiceOptions__fields[3] = { + {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__ServiceOptions_msg_init = { + &google_protobuf_ServiceOptions__submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ServiceOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__ServiceOptions_msg_init_ptr = &google__protobuf__ServiceOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_MethodOptions__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__MethodOptions__IdempotencyLevel_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_MethodOptions__fields[4] = { + {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, 12, 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {35, 16, 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__MethodOptions_msg_init = { + &google_protobuf_MethodOptions__submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(24, 32), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MethodOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f013eba, &upb_prm_2bt_max128b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__MethodOptions_msg_init_ptr = &google__protobuf__MethodOptions_msg_init; +static const upb_MiniTableSubInternal google_protobuf_UninterpretedOption__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption__NamePart_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 40), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(32, 48), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 64), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(56, 80), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__UninterpretedOption_msg_init = { + &google_protobuf_UninterpretedOption__submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.UninterpretedOption", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001000003f000012, &upb_prm_1bt_max64b}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__UninterpretedOption_msg_init_ptr = &google__protobuf__UninterpretedOption_msg_init; +static const upb_MiniTableField google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__UninterpretedOption__NamePart_msg_init = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(255), 2, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.UninterpretedOption.NamePart", +#endif +}; + +const upb_MiniTable* google__protobuf__UninterpretedOption__NamePart_msg_init_ptr = &google__protobuf__UninterpretedOption__NamePart_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FeatureSet__submsgs[6] = { + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__FieldPresence_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__EnumType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__Utf8Validation_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__MessageEncoding_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__JsonFormat_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FeatureSet__fields[6] = { + {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, 20, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 24, 67, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 28, 68, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, 32, 69, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FeatureSet_msg_init = { + &google_protobuf_FeatureSet__submsgs[0], + &google_protobuf_FeatureSet__fields[0], + 40, 6, kUpb_ExtMode_Extendable, 6, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSet", +#endif +}; + +const upb_MiniTable* google__protobuf__FeatureSet_msg_init_ptr = &google__protobuf__FeatureSet_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FeatureSetDefaults__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FeatureSetDefaults__fields[3] = { + {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 12), 64, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 16), 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FeatureSetDefaults_msg_init = { + &google_protobuf_FeatureSetDefaults__submsgs[0], + &google_protobuf_FeatureSetDefaults__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSetDefaults", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f00000a, &upb_prm_1bt_max64b}, + }) +}; + +const upb_MiniTable* google__protobuf__FeatureSetDefaults_msg_init_ptr = &google__protobuf__FeatureSetDefaults_msg_init; +static const upb_MiniTableSubInternal google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__submsgs[3] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init_ptr}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields[3] = { + {3, 12, 64, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 16, 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 24), 66, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init = { + &google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__submsgs[0], + &google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault", +#endif +}; + +const upb_MiniTable* google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_ptr = &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init; +static const upb_MiniTableSubInternal google_protobuf_SourceCodeInfo__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo__Location_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_SourceCodeInfo__fields[1] = { + {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__SourceCodeInfo_msg_init = { + &google_protobuf_SourceCodeInfo__submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.SourceCodeInfo", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x000800003f00000a, &upb_prm_1bt_max128b}, + }) +}; + +const upb_MiniTable* google__protobuf__SourceCodeInfo_msg_init_ptr = &google__protobuf__SourceCodeInfo_msg_init; +static const upb_MiniTableField google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(24, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(32, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__SourceCodeInfo__Location_msg_init = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(40, 72), 5, kUpb_ExtMode_NonExtendable, 4, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.SourceCodeInfo.Location", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001000003f00000a, &upb_ppv4_1bt}, + {0x001800003f000012, &upb_ppv4_1bt}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x004000003f000032, &upb_prs_1bt}, + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + }) +}; + +const upb_MiniTable* google__protobuf__SourceCodeInfo__Location_msg_init_ptr = &google__protobuf__SourceCodeInfo__Location_msg_init; +static const upb_MiniTableSubInternal google_protobuf_GeneratedCodeInfo__submsgs[1] = { + {.UPB_PRIVATE(submsg) = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init_ptr}, +}; + +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__GeneratedCodeInfo_msg_init = { + &google_protobuf_GeneratedCodeInfo__submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + 16, 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.GeneratedCodeInfo", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x000800003f00000a, &upb_prm_1bt_max64b}, + }) +}; + +const upb_MiniTable* google__protobuf__GeneratedCodeInfo_msg_init_ptr = &google__protobuf__GeneratedCodeInfo_msg_init; +static const upb_MiniTableSubInternal google_protobuf_GeneratedCodeInfo_Annotation__submsgs[1] = { + {.UPB_PRIVATE(subenum) = &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init}, +}; + +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { + {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(28, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 20), 67, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; + +const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = { + &google_protobuf_GeneratedCodeInfo_Annotation__submsgs[0], + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(40, 48), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.GeneratedCodeInfo.Annotation", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric}, + {0x001800003f00000a, &upb_ppv4_1bt}, + }) +}; + +const upb_MiniTable* google__protobuf__GeneratedCodeInfo__Annotation_msg_init_ptr = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init; +const upb_MiniTableEnum google__protobuf__Edition_enum_init = { + 64, + 9, + { + 0x7, + 0x0, + 0x384, + 0x3e6, + 0x3e7, + 0x3e8, + 0x3e9, + 0x1869d, + 0x1869e, + 0x1869f, + 0x7fffffff, + }, +}; + +const upb_MiniTableEnum google__protobuf__ExtensionRangeOptions__VerificationState_enum_init = { + 64, + 0, + { + 0x3, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__EnumType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__FieldPresence_enum_init = { + 64, + 0, + { + 0xf, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__JsonFormat_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__MessageEncoding_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__Utf8Validation_enum_init = { + 64, + 0, + { + 0xd, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Label_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Type_enum_init = { + 64, + 0, + { + 0x7fffe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__CType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__JSType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__OptionRetention_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__OptionTargetType_enum_init = { + 64, + 0, + { + 0x3ff, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FileOptions__OptimizeMode_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__MethodOptions__IdempotencyLevel_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +static const upb_MiniTable *messages_layout[33] = { + &google__protobuf__FileDescriptorSet_msg_init, + &google__protobuf__FileDescriptorProto_msg_init, + &google__protobuf__DescriptorProto_msg_init, + &google__protobuf__DescriptorProto__ExtensionRange_msg_init, + &google__protobuf__DescriptorProto__ReservedRange_msg_init, + &google__protobuf__ExtensionRangeOptions_msg_init, + &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, + &google__protobuf__FieldDescriptorProto_msg_init, + &google__protobuf__OneofDescriptorProto_msg_init, + &google__protobuf__EnumDescriptorProto_msg_init, + &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, + &google__protobuf__EnumValueDescriptorProto_msg_init, + &google__protobuf__ServiceDescriptorProto_msg_init, + &google__protobuf__MethodDescriptorProto_msg_init, + &google__protobuf__FileOptions_msg_init, + &google__protobuf__MessageOptions_msg_init, + &google__protobuf__FieldOptions_msg_init, + &google__protobuf__FieldOptions__EditionDefault_msg_init, + &google__protobuf__FieldOptions__FeatureSupport_msg_init, + &google__protobuf__OneofOptions_msg_init, + &google__protobuf__EnumOptions_msg_init, + &google__protobuf__EnumValueOptions_msg_init, + &google__protobuf__ServiceOptions_msg_init, + &google__protobuf__MethodOptions_msg_init, + &google__protobuf__UninterpretedOption_msg_init, + &google__protobuf__UninterpretedOption__NamePart_msg_init, + &google__protobuf__FeatureSet_msg_init, + &google__protobuf__FeatureSetDefaults_msg_init, + &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, + &google__protobuf__SourceCodeInfo_msg_init, + &google__protobuf__SourceCodeInfo__Location_msg_init, + &google__protobuf__GeneratedCodeInfo_msg_init, + &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, +}; + +static const upb_MiniTableEnum *enums_layout[17] = { + &google__protobuf__Edition_enum_init, + &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init, + &google__protobuf__FeatureSet__EnumType_enum_init, + &google__protobuf__FeatureSet__FieldPresence_enum_init, + &google__protobuf__FeatureSet__JsonFormat_enum_init, + &google__protobuf__FeatureSet__MessageEncoding_enum_init, + &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init, + &google__protobuf__FeatureSet__Utf8Validation_enum_init, + &google__protobuf__FieldDescriptorProto__Label_enum_init, + &google__protobuf__FieldDescriptorProto__Type_enum_init, + &google__protobuf__FieldOptions__CType_enum_init, + &google__protobuf__FieldOptions__JSType_enum_init, + &google__protobuf__FieldOptions__OptionRetention_enum_init, + &google__protobuf__FieldOptions__OptionTargetType_enum_init, + &google__protobuf__FileOptions__OptimizeMode_enum_init, + &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init, + &google__protobuf__MethodOptions__IdempotencyLevel_enum_init, +}; + +const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + enums_layout, + NULL, + 33, + 17, + 0, +}; + + + +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ + +#include + + +// Must be last. + +#define UPB_MAXARRSIZE 16 // 2**16 = 64k. + +// From Chromium. +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) + +static const double MAX_LOAD = 0.85; + +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; + +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } + +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; +} + +static int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; // Ceiling. + return UPB_MIN(UPB_MAXARRSIZE, ret); +} + +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char* str; + size_t len; + } str; +} lookupkey_t; + +static lookupkey_t strkey2(const char* str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; +} + +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; +} + +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); + +/* Base table (shared code) ***************************************************/ + +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } + +static bool isfull(upb_table* t) { return t->count == t->max_count; } + +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + size_t bytes; + + t->count = 0; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); + } else { + t->entries = NULL; + } + return true; +} + +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + UPB_ASSERT(false); + return NULL; +} + +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); +} + +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; + + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; + } +} + +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} + +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val); + } + return true; + } else { + return false; + } +} + +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, hashfunc_t* hashfunc, + eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; + + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); + + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; + + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; + } else { + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; + } else { + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + UPB_ASSERT(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; + } + } + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); +} + +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, + upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) _upb_value_setval(val, chain->val.val); + if (removed) *removed = chain->key; + if (chain->next) { + upb_tabent* move = (upb_tabent*)chain->next; + *chain = *move; + move->key = 0; /* Make the slot empty. */ + } else { + chain->key = 0; /* Make the slot empty. */ + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) { + chain = (upb_tabent*)chain->next; + } + if (chain->next) { + /* Found element to remove. */ + upb_tabent* rm = (upb_tabent*)chain->next; + t->count--; + if (val) _upb_value_setval(val, chain->next->val.val); + if (removed) *removed = rm->key; + rm->key = 0; /* Make the slot empty. */ + chain->next = rm->next; + return true; + } else { + /* Element to remove is not in the table. */ + return false; + } + } +} + +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); + + return i; +} + +static size_t begin(const upb_table* t) { return next(t, -1); } + +/* upb_strtable ***************************************************************/ + +/* A simple "subclass" of upb_table that only adds a hash function for strings. + */ + +static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { + uint32_t len = (uint32_t)k2.str.len; + char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &len, sizeof(uint32_t)); + if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); + str[sizeof(uint32_t) + k2.str.len] = '\0'; + return (uintptr_t)str; +} + +/* Adapted from ABSL's wyhash. */ + +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} + +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} + +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif + +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif +} + +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} + +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; + + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; + + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); + + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); + + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); + + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; + } + + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + + current_state = WyhashMix(a ^ salt[1], b ^ current_state); + + ptr += 16; + len -= 16; + } + + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; + } + + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); +} + +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; + +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} + +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); +} + +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); +} + +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char* str = upb_tabstr(k1, &len); + return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); +} + +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 + // denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = upb_Log2Ceiling(need_entries); + return init(&t->t, size_lg2, a); +} + +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} + +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + if (!init(&new_table.t, size_lg2, a)) return false; + + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(t, &key, &val, &iter)) { + upb_strtable_insert(&new_table, key.data, key.size, val, a); + } + *t = new_table; + return true; +} + +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; + + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { + return false; + } + } + + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return false; + + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; +} + +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); +} + +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + upb_tabkey tabkey; + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); +} + +/* Iteration */ + +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} + +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} + +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); +} + +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + upb_StringView key; + uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; +} + +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val); +} + +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} + +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; +} + +/* upb_inttable ***************************************************************/ + +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ + +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } + +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } + +static upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; +} + +static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; + } +} + +static const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} + +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; +} + +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + // This check is very expensive (makes inserts/deletes O(N)). + size_t count = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + UPB_ASSERT(upb_inttable_lookup(t, key, NULL)); + } + UPB_ASSERT(count == upb_inttable_count(t)); + } +#endif +} + +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; + + if (!init(&t->t, hsize_lg2, a)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = upb_Arena_Malloc(a, array_bytes); + if (!t->array) { + return false; + } + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; +} + +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); +} + +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + upb_tabval tabval; + tabval.val = val.val; + UPB_ASSERT( + upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ + + if (key < t->array_size) { + UPB_ASSERT(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; + + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } + + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash; + upb_value v; + + _upb_value_setval(&v, e->val.val); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } + + UPB_ASSERT(t->t.count == new_table.count); + + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); + } + check(t); + return true; +} + +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + const upb_tabval* table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val); + return true; +} + +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabval* table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; + return true; +} + +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + } + check(t); + return success; +} + +void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { + /* A power-of-two histogram of the table keys. */ + size_t counts[UPB_MAXARRSIZE + 1] = {0}; + + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; + + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; + } + } + + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + size_t arr_count = upb_inttable_count(t); + int size_lg2; + upb_inttable new_t; + + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { + if (counts[size_lg2] == 0) { + /* We can halve again without losing any entries. */ + continue; + } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { + break; + } + + arr_count -= counts[size_lg2]; + } + + UPB_ASSERT(arr_count <= upb_inttable_count(t)); + + { + /* Insert all elements into new, perfectly-sized table. */ + size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ + size_t hash_count = upb_inttable_count(t) - arr_count; + size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); + + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + upb_inttable_insert(&new_t, key, val, a); + } + } + + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); + } + *t = new_t; +} + +// Iteration. + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if ((size_t)(i + 1) <= t->array_size) { + while ((size_t)++i < t->array_size) { + upb_tabval ent = t->array[i]; + if (upb_arrhas(ent)) { + *key = i; + *val = _upb_value_val(ent.val); + *iter = i; + return true; + } + } + i--; // Back up to exactly one position before the start of the table. + } + + size_t tab_idx = next(&t->t, i - t->array_size); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + *key = ent->key; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx + t->array_size; + return true; + } + + return false; +} + +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + intptr_t i = *iter; + if ((size_t)i < t->array_size) { + t->array_count--; + mutable_array(t)[i].val = -1; + } else { + upb_tabent* ent = &t->t.entries[i - t->array_size]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } + } + + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; + } +} + +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + size_t tab_idx = next(&t->t, *iter); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + uint32_t len; + key->data = upb_tabstr(ent->key, &len); + key->size = len; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx; + return true; + } + + return false; +} + +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->t.entries[i]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } + } + + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; +} + +void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v) { + upb_tabent* ent = &t->t.entries[iter]; + ent->val.val = v.val; +} + + +// Must be last. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + return NULL; // integer overflow + } + u64 *= 10; + u64 += ch; + ptr++; + } + + *val = u64; + return ptr; +} + +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; + } + + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow + } + + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; + return ptr; +} + + +#include +#include +#include +#include + +// Must be last. + +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + if (isnan(val)) { + snprintf(buf, size, "%s", "nan"); + return; + } + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + if (isnan(val)) { + snprintf(buf, size, "%s", "nan"); + return; + } + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); +} + + +#include +#include + +// Must be last. + +// Determine the locale-specific radix character by calling sprintf() to print +// the number 1.5, then stripping off the digits. As far as I can tell, this +// is the only portable, thread-safe way to get the C library to divulge the +// locale's radix character. No, localeconv() is NOT thread-safe. + +static int GetLocaleRadix(char *data, size_t capacity) { + char temp[16]; + const int size = snprintf(temp, sizeof(temp), "%.1f", 1.5); + UPB_ASSERT(temp[0] == '1'); + UPB_ASSERT(temp[size - 1] == '5'); + UPB_ASSERT(size < capacity); + temp[size - 1] = '\0'; + strcpy(data, temp + 1); + return size - 2; +} + +// Populates a string identical to *input except that the character pointed to +// by pos (which should be '.') is replaced with the locale-specific radix. + +static void LocalizeRadix(const char *input, const char *pos, char *output) { + const int len1 = pos - input; + + char radix[8]; + const int len2 = GetLocaleRadix(radix, sizeof(radix)); + + memcpy(output, input, len1); + memcpy(output + len1, radix, len2); + strcpy(output + len1 + len2, input + len1 + 1); +} + +double _upb_NoLocaleStrtod(const char *str, char **endptr) { + // We cannot simply set the locale to "C" temporarily with setlocale() + // as this is not thread-safe. Instead, we try to parse in the current + // locale first. If parsing stops at a '.' character, then this is a + // pretty good hint that we're actually in some other locale in which + // '.' is not the radix character. + + char *temp_endptr; + double result = strtod(str, &temp_endptr); + if (endptr != NULL) *endptr = temp_endptr; + if (*temp_endptr != '.') return result; + + // Parsing halted on a '.'. Perhaps we're in a different locale? Let's + // try to replace the '.' with a locale-specific radix character and + // try again. + + char localized[80]; + LocalizeRadix(str, temp_endptr, localized); + char *localized_endptr; + result = strtod(localized, &localized_endptr); + if ((localized_endptr - &localized[0]) > (temp_endptr - str)) { + // This attempt got further, so replacing the decimal must have helped. + // Update endptr to point at the right location. + if (endptr != NULL) { + // size_diff is non-zero if the localized radix has multiple bytes. + int size_diff = strlen(localized) - strlen(str); + *endptr = (char *)str + (localized_endptr - &localized[0] - size_diff); + } + } + + return result; +} + + +// Must be last. + +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; + return 2; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; + return 3; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; + return 4; + } + return 0; +} + + +#include + + +// Must be last. + +typedef struct upb_UnknownFields upb_UnknownFields; + +typedef struct { + uint32_t tag; + union { + uint64_t varint; + uint64_t uint64; + uint32_t uint32; + upb_StringView delimited; + upb_UnknownFields* group; + } data; +} upb_UnknownField; + +struct upb_UnknownFields { + size_t size; + size_t capacity; + upb_UnknownField* fields; +}; + +typedef struct { + upb_EpsCopyInputStream stream; + upb_Arena* arena; + upb_UnknownField* tmp; + size_t tmp_size; + int depth; + upb_UnknownCompareResult status; + jmp_buf err; +} upb_UnknownField_Context; + +UPB_NORETURN static void upb_UnknownFields_OutOfMemory( + upb_UnknownField_Context* ctx) { + ctx->status = kUpb_UnknownCompareResult_OutOfMemory; + UPB_LONGJMP(ctx->err, 1); +} + +static void upb_UnknownFields_Grow(upb_UnknownField_Context* ctx, + upb_UnknownField** base, + upb_UnknownField** ptr, + upb_UnknownField** end) { + size_t old = (*ptr - *base); + size_t new = UPB_MAX(4, old * 2); + + *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), + new * sizeof(**base)); + if (!*base) upb_UnknownFields_OutOfMemory(ctx); + + *ptr = *base + old; + *end = *base + new; +} + +// We have to implement our own sort here, since qsort() is not an in-order +// sort. Here we use merge sort, the simplest in-order sort. +static void upb_UnknownFields_Merge(upb_UnknownField* arr, size_t start, + size_t mid, size_t end, + upb_UnknownField* tmp) { + memcpy(tmp, &arr[start], (end - start) * sizeof(*tmp)); + + upb_UnknownField* ptr1 = tmp; + upb_UnknownField* end1 = &tmp[mid - start]; + upb_UnknownField* ptr2 = &tmp[mid - start]; + upb_UnknownField* end2 = &tmp[end - start]; + upb_UnknownField* out = &arr[start]; + + while (ptr1 < end1 && ptr2 < end2) { + if (ptr1->tag <= ptr2->tag) { + *out++ = *ptr1++; + } else { + *out++ = *ptr2++; + } + } + + if (ptr1 < end1) { + memcpy(out, ptr1, (end1 - ptr1) * sizeof(*out)); + } else if (ptr2 < end2) { + memcpy(out, ptr1, (end2 - ptr2) * sizeof(*out)); + } +} + +static void upb_UnknownFields_SortRecursive(upb_UnknownField* arr, size_t start, + size_t end, upb_UnknownField* tmp) { + if (end - start > 1) { + size_t mid = start + ((end - start) / 2); + upb_UnknownFields_SortRecursive(arr, start, mid, tmp); + upb_UnknownFields_SortRecursive(arr, mid, end, tmp); + upb_UnknownFields_Merge(arr, start, mid, end, tmp); + } +} + +static void upb_UnknownFields_Sort(upb_UnknownField_Context* ctx, + upb_UnknownFields* fields) { + if (ctx->tmp_size < fields->size) { + const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); + while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; + const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); + } + upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp); +} + +static upb_UnknownFields* upb_UnknownFields_DoBuild( + upb_UnknownField_Context* ctx, const char** buf) { + upb_UnknownField* arr_base = NULL; + upb_UnknownField* arr_ptr = NULL; + upb_UnknownField* arr_end = NULL; + const char* ptr = *buf; + uint32_t last_tag = 0; + bool sorted = true; + while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag); + UPB_ASSERT(tag <= UINT32_MAX); + int wire_type = upb_WireReader_GetWireType(tag); + if (wire_type == kUpb_WireType_EndGroup) break; + if (tag < last_tag) sorted = false; + last_tag = tag; + + if (arr_ptr == arr_end) { + upb_UnknownFields_Grow(ctx, &arr_base, &arr_ptr, &arr_end); + } + upb_UnknownField* field = arr_ptr; + field->tag = tag; + arr_ptr++; + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = upb_WireReader_ReadVarint(ptr, &field->data.varint); + break; + case kUpb_WireType_64Bit: + ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64); + break; + case kUpb_WireType_32Bit: + ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32); + break; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + const char* s_ptr = ptr; + ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr, + size); + field->data.delimited.data = s_ptr; + field->data.delimited.size = size; + break; + } + case kUpb_WireType_StartGroup: + if (--ctx->depth == 0) { + ctx->status = kUpb_UnknownCompareResult_MaxDepthExceeded; + UPB_LONGJMP(ctx->err, 1); + } + field->data.group = upb_UnknownFields_DoBuild(ctx, &ptr); + ctx->depth++; + break; + default: + UPB_UNREACHABLE(); + } + } + + *buf = ptr; + upb_UnknownFields* ret = upb_Arena_Malloc(ctx->arena, sizeof(*ret)); + if (!ret) upb_UnknownFields_OutOfMemory(ctx); + ret->fields = arr_base; + ret->size = arr_ptr - arr_base; + ret->capacity = arr_end - arr_base; + if (!sorted) { + upb_UnknownFields_Sort(ctx, ret); + } + return ret; +} + +// Builds a upb_UnknownFields data structure from the binary data in buf. +static upb_UnknownFields* upb_UnknownFields_Build(upb_UnknownField_Context* ctx, + const char* ptr, + size_t size) { + upb_EpsCopyInputStream_Init(&ctx->stream, &ptr, size, true); + upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &ptr); + UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr) && + !upb_EpsCopyInputStream_IsError(&ctx->stream)); + return fields; +} + +// Compares two sorted upb_UnknownFields structures for equality. +static bool upb_UnknownFields_IsEqual(const upb_UnknownFields* uf1, + const upb_UnknownFields* uf2) { + if (uf1->size != uf2->size) return false; + for (size_t i = 0, n = uf1->size; i < n; i++) { + upb_UnknownField* f1 = &uf1->fields[i]; + upb_UnknownField* f2 = &uf2->fields[i]; + if (f1->tag != f2->tag) return false; + int wire_type = f1->tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: + if (f1->data.varint != f2->data.varint) return false; + break; + case kUpb_WireType_64Bit: + if (f1->data.uint64 != f2->data.uint64) return false; + break; + case kUpb_WireType_32Bit: + if (f1->data.uint32 != f2->data.uint32) return false; + break; + case kUpb_WireType_Delimited: + if (!upb_StringView_IsEqual(f1->data.delimited, f2->data.delimited)) { + return false; + } + break; + case kUpb_WireType_StartGroup: + if (!upb_UnknownFields_IsEqual(f1->data.group, f2->data.group)) { + return false; + } + break; + default: + UPB_UNREACHABLE(); + } + } + return true; +} + +static upb_UnknownCompareResult upb_UnknownField_DoCompare( + upb_UnknownField_Context* ctx, const char* buf1, size_t size1, + const char* buf2, size_t size2) { + upb_UnknownCompareResult ret; + // First build both unknown fields into a sorted data structure (similar + // to the UnknownFieldSet in C++). + upb_UnknownFields* uf1 = upb_UnknownFields_Build(ctx, buf1, size1); + upb_UnknownFields* uf2 = upb_UnknownFields_Build(ctx, buf2, size2); + + // Now perform the equality check on the sorted structures. + if (upb_UnknownFields_IsEqual(uf1, uf2)) { + ret = kUpb_UnknownCompareResult_Equal; + } else { + ret = kUpb_UnknownCompareResult_NotEqual; + } + return ret; +} + +static upb_UnknownCompareResult upb_UnknownField_Compare( + upb_UnknownField_Context* const ctx, const char* const buf1, + const size_t size1, const char* const buf2, const size_t size2) { + upb_UnknownCompareResult ret; + if (UPB_SETJMP(ctx->err) == 0) { + ret = upb_UnknownField_DoCompare(ctx, buf1, size1, buf2, size2); + } else { + ret = ctx->status; + UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); + } + + upb_Arena_Free(ctx->arena); + upb_gfree(ctx->tmp); + return ret; +} + +upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( + const char* buf1, size_t size1, const char* buf2, size_t size2, + int max_depth) { + if (size1 == 0 && size2 == 0) return kUpb_UnknownCompareResult_Equal; + if (size1 == 0 || size2 == 0) return kUpb_UnknownCompareResult_NotEqual; + if (memcmp(buf1, buf2, size1) == 0) return kUpb_UnknownCompareResult_Equal; + + upb_UnknownField_Context ctx = { + .arena = upb_Arena_New(), + .depth = max_depth, + .tmp = NULL, + .tmp_size = 0, + .status = kUpb_UnknownCompareResult_Equal, + }; + + if (!ctx.arena) return kUpb_UnknownCompareResult_OutOfMemory; + + return upb_UnknownField_Compare(&ctx, buf1, size1, buf2, size2); +} + + +#include + + +// Must be last. + +const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( + const struct upb_Message* msg, const upb_MiniTableExtension* e) { + size_t n; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &n); + + // For now we use linear search exclusively to find extensions. + // If this becomes an issue due to messages with lots of extensions, + // we can introduce a table of some sort. + for (size_t i = 0; i < n; i++) { + if (ext[i].ext == e) { + return &ext[i]; + } + } + + return NULL; +} + +const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)( + const struct upb_Message* msg, size_t* count) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in) { + *count = (in->size - in->ext_begin) / sizeof(upb_Extension); + return UPB_PTR_AT(in, in->ext_begin, void); + } else { + *count = 0; + return NULL; + } +} + +upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); + if (ext) return ext; + if (!UPB_PRIVATE(_upb_Message_Realloc)(msg, sizeof(upb_Extension), a)) + return NULL; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + in->ext_begin -= sizeof(upb_Extension); + ext = UPB_PTR_AT(in, in->ext_begin, void); + memset(ext, 0, sizeof(upb_Extension)); + ext->ext = e; + return ext; +} + + +#include +#include + + +// Must be last. + +const float kUpb_FltInfinity = (float)(1.0 / 0.0); +const double kUpb_Infinity = 1.0 / 0.0; +const double kUpb_NaN = 0.0 / 0.0; + +bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, + upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const size_t overhead = sizeof(upb_Message_Internal); + + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) { + // No internal data, allocate from scratch. + size_t size = UPB_MAX(128, upb_Log2CeilingSize(need + overhead)); + in = upb_Arena_Malloc(a, size); + if (!in) return false; + + in->size = size; + in->unknown_end = overhead; + in->ext_begin = size; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); + } else if (in->ext_begin - in->unknown_end < need) { + // Internal data is too small, reallocate. + size_t new_size = upb_Log2CeilingSize(in->size + need); + size_t ext_bytes = in->size - in->ext_begin; + size_t new_ext_begin = new_size - ext_bytes; + in = upb_Arena_Realloc(a, in, in->size, new_size); + if (!in) return false; + + if (ext_bytes) { + // Need to move extension data to the end. + char* ptr = (char*)in; + memmove(ptr + new_ext_begin, ptr + in->ext_begin, ext_bytes); + } + in->ext_begin = new_ext_begin; + in->size = new_size; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); + } + + UPB_ASSERT(in->ext_begin - in->unknown_end >= need); + return true; +} + +#if UPB_TRACING_ENABLED +static void (*_message_trace_handler)(const upb_MiniTable*, const upb_Arena*); + +void upb_Message_LogNewMessage(const upb_MiniTable* m, const upb_Arena* arena) { + if (_message_trace_handler) { + _message_trace_handler(m, arena); + } +} + +void upb_Message_SetNewMessageTraceHandler(void (*handler)(const upb_MiniTable*, + const upb_Arena*)) { + _message_trace_handler = handler; +} +#endif // UPB_TRACING_ENABLED + + +#include + + +// Must be last. + +bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField** out_f, + upb_MessageValue* out_v, + size_t* iter) { + const size_t count = upb_MiniTable_FieldCount(m); + size_t i = *iter; + + while (++i < count) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const void* src = UPB_PRIVATE(_upb_Message_DataPtr)(msg, f); + + upb_MessageValue val; + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, &val, src); + + // Skip field if unset or empty. + if (upb_MiniTableField_HasPresence(f)) { + if (!upb_Message_HasBaseField(msg, f)) continue; + } else { + if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(f, src)) continue; + + if (upb_MiniTableField_IsArray(f)) { + if (upb_Array_Size(val.array_val) == 0) continue; + } else if (upb_MiniTableField_IsMap(f)) { + if (upb_Map_Size(val.map_val) == 0) continue; + } + } + + *out_f = f; + *out_v = val; + *iter = i; + return true; + } + + return false; +} + +bool UPB_PRIVATE(_upb_Message_NextExtension)( + const upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableExtension** out_e, upb_MessageValue* out_v, + size_t* iter) { + size_t count; + const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count); + size_t i = *iter; + + if (++i < count) { + *out_e = exts[i].ext; + *out_v = exts[i].data; + *iter = i; + return true; + } + + return false; +} + +const char _kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', +}; + +const int8_t _kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, +}; + + +#include +#include +#include + + +// Must be last. + +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; + +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; + +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; +} + +static char* upb_MtDataEncoder_PutRaw(upb_MtDataEncoder* e, char* ptr, + char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = ch; + return ptr; +} + +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +} + +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = upb_Log2Ceiling(_upb_FromBase92(max) - _upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + _upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} + +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); + } + return ptr; +} + +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +} + +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, uint64_t key_mod, + uint64_t value_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); + if (!ptr) return NULL; + + ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, key_mod); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); +} + +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { + (void)upb_MtDataEncoder_GetInternal(e, ptr); + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); +} + +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +static char* _upb_MtDataEncoder_MaybePutFieldSkip(upb_MtDataEncoder* e, + char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + return ptr; +} + +static char* _upb_MtDataEncoder_PutFieldType(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_OpenEnum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; + + int encoded_type = kUpb_TypeToEncoded[type]; + + if (field_mod & kUpb_FieldModifier_IsClosedEnum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + encoded_type = kUpb_EncodedType_ClosedEnum; + } + + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + } + + return upb_MtDataEncoder_Put(e, ptr, encoded_type); +} + +static char* _upb_MtDataEncoder_MaybePutModifiers(upb_MtDataEncoder* e, + char* ptr, upb_FieldType type, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + uint32_t encoded_modifiers = 0; + if ((field_mod & kUpb_FieldModifier_IsRepeated) && + upb_FieldType_IsPackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + + if (type == kUpb_FieldType_String) { + bool field_validates_utf8 = field_mod & kUpb_FieldModifier_ValidateUtf8; + bool message_validates_utf8 = + in->state.msg_state.msg_modifiers & kUpb_MessageModifier_ValidateUtf8; + if (field_validates_utf8 != message_validates_utf8) { + // Old binaries do not recognize the field modifier. We need the failure + // mode to be too lax rather than too strict. Our caller should have + // handled this (see _upb_MessageDef_ValidateUtf8()). + assert(!message_validates_utf8); + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipValidateUtf8; + } + } + + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoder_GetInternal(e, ptr); + + ptr = _upb_MtDataEncoder_MaybePutFieldSkip(e, ptr, field_num); + if (!ptr) return NULL; + + ptr = _upb_MtDataEncoder_PutFieldType(e, ptr, type, field_mod); + if (!ptr) return NULL; + + return _upb_MtDataEncoder_MaybePutModifiers(e, ptr, type, field_mod); +} + +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, _upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, _upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} + +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, _upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, _upb_ToBase92(0), + _upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} + +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; + + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); +} + +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} + +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO: optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + if (!ptr) { + return NULL; + } + delta -= 5; + } + + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } + + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} + +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} + + +#include + + +// Must be last. + +// A MiniTable for an empty message, used for unlinked sub-messages that are +// built via MiniDescriptors. Messages that use this MiniTable may possibly +// be linked later, in which case this MiniTable will be replaced with a real +// one. This pattern is known as "dynamic tree shaking", and it introduces +// complication because sub-messages may either be the "empty" type or the +// "real" type. A tagged bit indicates the difference. +const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty) = { + .UPB_PRIVATE(subs) = NULL, + .UPB_PRIVATE(fields) = NULL, + .UPB_PRIVATE(size) = sizeof(struct upb_Message), + .UPB_PRIVATE(field_count) = 0, + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, + .UPB_PRIVATE(dense_below) = 0, + .UPB_PRIVATE(table_mask) = -1, + .UPB_PRIVATE(required_count) = 0, +}; + +// A MiniTable for a statically tree shaken message. Messages that use this +// MiniTable are guaranteed to remain unlinked; unlike the empty message, this +// MiniTable is never replaced, which greatly simplifies everything, because the +// type of a sub-message is always known, without consulting a tagged bit. +const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken) = { + .UPB_PRIVATE(subs) = NULL, + .UPB_PRIVATE(fields) = NULL, + .UPB_PRIVATE(size) = sizeof(struct upb_Message), + .UPB_PRIVATE(field_count) = 0, + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, + .UPB_PRIVATE(dense_below) = 0, + .UPB_PRIVATE(table_mask) = -1, + .UPB_PRIVATE(required_count) = 0, +}; + + + +// Must be last. + +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; // full_name -> packed def ptr + upb_strtable files; // file_name -> (upb_FileDef*) + upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + const UPB_DESC(FeatureSetDefaults) * feature_set_defaults; + upb_MiniTablePlatform platform; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; +}; + +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); +} + +static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; + +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; + + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; + + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; + + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + + s->platform = kUpb_MiniTablePlatform_Native; + + upb_Status status; + if (!upb_DefPool_SetFeatureSetDefaults( + s, serialized_defaults, sizeof(serialized_defaults) - 1, &status)) { + goto err; + } + + if (!s->feature_set_defaults) goto err; + + return s; + +err: + upb_DefPool_Free(s); + return NULL; +} + +const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s) { + return s->feature_set_defaults; +} + +bool upb_DefPool_SetFeatureSetDefaults(upb_DefPool* s, + const char* serialized_defaults, + size_t serialized_len, + upb_Status* status) { + const UPB_DESC(FeatureSetDefaults)* defaults = UPB_DESC( + FeatureSetDefaults_parse)(serialized_defaults, serialized_len, s->arena); + if (!defaults) { + upb_Status_SetErrorFormat(status, "Failed to parse defaults"); + return false; + } + if (upb_strtable_count(&s->files) > 0) { + upb_Status_SetErrorFormat(status, + "Feature set defaults can't be changed once the " + "pool has started building"); + return false; + } + int min_edition = UPB_DESC(FeatureSetDefaults_minimum_edition(defaults)); + int max_edition = UPB_DESC(FeatureSetDefaults_maximum_edition(defaults)); + if (min_edition > max_edition) { + upb_Status_SetErrorFormat(status, "Invalid edition range %s to %s", + upb_FileDef_EditionName(min_edition), + upb_FileDef_EditionName(max_edition)); + return false; + } + size_t size; + const UPB_DESC( + FeatureSetDefaults_FeatureSetEditionDefault)* const* default_list = + UPB_DESC(FeatureSetDefaults_defaults(defaults, &size)); + int prev_edition = UPB_DESC(EDITION_UNKNOWN); + for (size_t i = 0; i < size; ++i) { + int edition = UPB_DESC( + FeatureSetDefaults_FeatureSetEditionDefault_edition(default_list[i])); + if (edition == UPB_DESC(EDITION_UNKNOWN)) { + upb_Status_SetErrorFormat(status, "Invalid edition UNKNOWN specified"); + return false; + } + if (edition <= prev_edition) { + upb_Status_SetErrorFormat(status, + "Feature set defaults are not strictly " + "increasing, %s is greater than or equal to %s", + upb_FileDef_EditionName(prev_edition), + upb_FileDef_EditionName(edition)); + return false; + } + prev_edition = edition; + } + + // Copy the defaults into the pool. + s->feature_set_defaults = defaults; + return true; +} + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + const upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); +} + +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; + } + return true; +} + +static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) + ? _upb_DefType_Unpack(v, type) + : NULL; +} + +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); +} + +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; +} + +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; +} + +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; +} + +void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform) { + assert(upb_strtable_count(&s->files) == 0); + s->platform = platform; +} + +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); +} + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); +} + +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); +} + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); +} + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: + break; + } + + return NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); +} + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO: non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } + + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } + + return NULL; +} + +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } + + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} + +static const upb_FileDef* upb_DefBuilder_AddFileToPool( + upb_DefBuilder* const builder, upb_DefPool* const s, + const UPB_DESC(FileDescriptorProto) * const file_proto, + const upb_StringView name, upb_Status* const status) { + if (UPB_SETJMP(builder->err) != 0) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (builder->file) { + remove_filedef(s, builder->file); + builder->file = NULL; + } + } else if (!builder->arena || !builder->tmp_arena || + !upb_strtable_init(&builder->feature_cache, 16, + builder->tmp_arena) || + !(builder->legacy_features = + UPB_DESC(FeatureSet_new)(builder->tmp_arena))) { + _upb_DefBuilder_OomErr(builder); + } else { + _upb_FileDef_Create(builder, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(builder->file), builder->arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, builder->arena); + } + + if (builder->arena) upb_Arena_Free(builder->arena); + if (builder->tmp_arena) upb_Arena_Free(builder->tmp_arena); + return builder->file; +} + +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const UPB_DESC(FileDescriptorProto) * file_proto, + const upb_MiniTableFile* layout, upb_Status* status) { + const upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto); + + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } + + upb_DefBuilder ctx = { + .symtab = s, + .tmp_buf = NULL, + .tmp_buf_size = 0, + .layout = layout, + .platform = s->platform, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; + + return upb_DefBuilder_AddFileToPool(&ctx, s, file_proto, name, status); +} + +const upb_FileDef* upb_DefPool_AddFile(upb_DefPool* s, + const UPB_DESC(FileDescriptorProto) * + file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); +} + +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + UPB_DESC(FileDescriptorProto) * file; + upb_Arena* arena; + upb_Status status; + + upb_Status_Clear(&status); + + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; + } + + arena = upb_Arena_New(); + + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } + + file = UPB_DESC(FileDescriptorProto_parse_ex)( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } + + const upb_MiniTableFile* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; + } + + upb_Arena_Free(arena); + return true; + +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; +} + +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); + return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; + } + const upb_FieldDef** exts = upb_gmalloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + } + *count = n; + return exts; +} + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} + + +// Must be last. + +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; +} + + +// Must be last. + +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; + + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } + + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; + } + + return true; +} + + +#include +#include +#include + + +// Must be last. + +struct upb_EnumDef { + const UPB_DESC(EnumOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_MiniTableEnum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + const upb_EnumReservedRange* res_ranges; + const upb_StringView* res_names; + int value_count; + int res_range_count; + int res_name_count; + int32_t defaultval; + bool is_sorted; // Whether all of the values are defined in ascending order. +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; +} + +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} + +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; + + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); + } + return true; +} + +const UPB_DESC(EnumOptions) * upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; +} + +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e) { + return e->resolved_features; +} + +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} + +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} + +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} + +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; +} + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i) { + UPB_ASSERT(0 <= i && i < e->res_range_count); + return _upb_EnumReservedRange_At(e->res_ranges, i); +} + +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->res_name_count); + return e->res_names[i]; +} + +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + return upb_strtable_lookup2(&e->ntoi, name, size, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; +} + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { + // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect + // this to be faster (especially for small numbers). + return upb_MiniTableEnum_CheckValue(e->layout, num); +} + +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->value_count); + return _upb_EnumValueDef_At(e->values, i); +} + +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN) return false; + return upb_EnumDef_IsSpecifiedAsClosed(e); +} + +bool upb_EnumDef_IsSpecifiedAsClosed(const upb_EnumDef* e) { + return UPB_DESC(FeatureSet_enum_type)(e->resolved_features) == + UPB_DESC(FeatureSet_CLOSED); +} + +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); + + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; + + for (int i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); + + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); + + upb_Status status; + upb_MiniTableEnum* layout = + upb_MiniTableEnum_Build(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} + +static upb_StringView* _upb_EnumReservedNames_New( + upb_DefBuilder* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (int i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(EnumDescriptorProto) * enum_proto, + const UPB_DESC(FeatureSet*) parent_features, + upb_EnumDef* e) { + const UPB_DESC(EnumValueDescriptorProto)* const* values; + const UPB_DESC(EnumDescriptorProto_EnumReservedRange)* const* res_ranges; + const upb_StringView* res_names; + upb_StringView name; + size_t n_value, n_res_range, n_res_name; + + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + e->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumOptions_features)(e->opts)); + + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); + + name = UPB_DESC(EnumDescriptorProto_name)(enum_proto); + + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = UPB_DESC(EnumDescriptorProto_value)(enum_proto, &n_value); + + bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + e->defaultval = 0; + e->value_count = n_value; + e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, + e->resolved_features, e, &e->is_sorted); + + if (n_value == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } + + res_ranges = + UPB_DESC(EnumDescriptorProto_reserved_range)(enum_proto, &n_res_range); + e->res_range_count = n_res_range; + e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); + + res_names = + UPB_DESC(EnumDescriptorProto_reserved_name)(enum_proto, &n_res_name); + e->res_name_count = n_res_name; + e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); + + upb_inttable_compact(&e->iton, ctx->arena); + + if (upb_EnumDef_IsClosed(e)) { + if (ctx->layout) { + e->layout = upb_MiniTableFile_Enum(ctx->layout, ctx->enum_count++); + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } +} + +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); + + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); + + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (int i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], parent_features, &e[i]); + e[i].containing_type = containing_type; + } + return e; +} + + + +// Must be last. + +struct upb_EnumReservedRange { + int32_t start; + int32_t end; +}; + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; +} + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; +} +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; +} + +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto_EnumReservedRange) * const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + UPB_DESC(EnumDescriptorProto_EnumReservedRange_start)(protos[i]); + const int32_t end = + UPB_DESC(EnumDescriptorProto_EnumReservedRange_end)(protos[i]); + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + + // Note: Not a typo! Unlike extension ranges and message reserved ranges, + // the end value of an enum reserved range is *inclusive*! + if (end < start) { + _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + +#include + + +// Must be last. + +struct upb_EnumValueDef { + const UPB_DESC(EnumValueOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; +} + +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); +} + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; + + for (int i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); + + return (const upb_EnumValueDef**)out; +} + +const UPB_DESC(EnumValueOptions) * + upb_EnumValueDef_Options(const upb_EnumValueDef* v) { + return v->opts; +} + +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e) { + return e->resolved_features; +} + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; +} + +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; +} + +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); +} + +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } + +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); +} + +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(EnumValueDescriptorProto*) + val_proto, + const UPB_DESC(FeatureSet*) parent_features, + upb_EnumDef* e, upb_EnumValueDef* v) { + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + v->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts)); + + upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto); + + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = UPB_DESC(EnumValueDescriptorProto_number)(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); + + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx, + const upb_EnumDef* e, + const upb_EnumValueDef* v, int n) { + // When the special UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN is enabled, we have to + // exempt closed enums from this check, even when we are treating them as + // open. + if (upb_EnumDef_IsSpecifiedAsClosed(e) || n == 0 || v[0].number == 0) return; + + _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)", + upb_EnumDef_FullName(e)); +} + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); + + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); + + *is_sorted = true; + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); + + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; + } + + _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n); + + return v; +} + + +#include + + +// Must be last. + +struct upb_ExtensionRange { + const UPB_DESC(ExtensionRangeOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + int32_t start; + int32_t end; +}; + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} + +const UPB_DESC(ExtensionRangeOptions) * + upb_ExtensionRange_Options(const upb_ExtensionRange* r) { + return r->opts; +} + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} + +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } + +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); + + for (int i = 0; i < n; i++) { + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, + UPB_DESC(ExtensionRangeOptions_features)(r[i].opts)); + + const int32_t start = + UPB_DESC(DescriptorProto_ExtensionRange_start)(protos[i]); + const int32_t end = UPB_DESC(DescriptorProto_ExtensionRange_end)(protos[i]); + const int32_t max = UPB_DESC(MessageOptions_message_set_wire_format)( + upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + +#include +#include +#include +#include +#include +#include + + +// Must be last. + +#define UPB_FIELD_TYPE_UNSPECIFIED 0 + +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; + +struct upb_FieldDef { + const UPB_DESC(FieldOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + void* msg; // Always NULL. + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const UPB_DESC(FieldDescriptorProto) * unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; // Index into msgdef->layout->fields or file->exts + bool has_default; + bool has_json_name; + bool has_presence; + bool is_extension; + bool is_proto3_optional; + upb_FieldType type_; + upb_Label label_; +}; + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; +} + +const UPB_DESC(FieldOptions) * upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; +} + +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f) { + return f->resolved_features; +} + +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; +} + +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + return upb_FieldType_CType(f->type_); +} + +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } + +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } + +uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { + return f->layout_index; +} + +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { return f->is_extension; } + +bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsPrimitive(f); +} + +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { + return _upb_FieldDef_IsPackable(f) && + UPB_DESC(FeatureSet_repeated_field_encoding(f->resolved_features)) == + UPB_DESC(FeatureSet_PACKED); +} + +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); +} + +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; +} + +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name; +} + +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; +} + +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension ? f->scope.extension_scope : NULL; +} + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension ? NULL : f->scope.oneof; +} + +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; +} + +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + upb_MessageValue ret; + + if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) { + return (upb_MessageValue){.msg_val = NULL}; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } + + return ret; +} + +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) ? f->sub.msgdef : NULL; +} + +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsEnum(f) ? f->sub.enumdef : NULL; +} + +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_FileDef* file = upb_FieldDef_File(f); + return (upb_MiniTableField*)_upb_FileDef_ExtensionMiniTable( + file, f->layout_index); + } else { + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->UPB_PRIVATE(fields)[f->layout_index]; + } +} + +const upb_MiniTableExtension* upb_FieldDef_MiniTableExtension( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); +} + +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (f->type_ != kUpb_FieldType_Enum) return false; + return upb_EnumDef_IsClosed(f->sub.enumdef); +} + +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->is_proto3_optional; +} + +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } + +bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { + if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; + return UPB_DESC(FeatureSet_utf8_validation(f->resolved_features)) == + UPB_DESC(FeatureSet_VERIFY); +} + +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) { + // Groups are always tag-delimited. + if (f->type_ != kUpb_FieldType_Group) { + return false; + } + + const upb_MessageDef* msg = upb_FieldDef_MessageSubDef(f); + + // Group fields always are always the lowercase type name. + const char* mname = upb_MessageDef_Name(msg); + const char* fname = upb_FieldDef_Name(f); + size_t name_size = strlen(fname); + if (name_size != strlen(mname)) return false; + for (size_t i = 0; i < name_size; ++i) { + if ((mname[i] | 0x20) != fname[i]) { + // Case-insensitive ascii comparison. + return false; + } + } + + if (upb_MessageDef_File(msg) != upb_FieldDef_File(f)) { + return false; + } + + // Group messages are always defined in the same scope as the field. File + // level extensions will compare NULL == NULL here, which is why the file + // comparison above is necessary to ensure both come from the same file. + return upb_FieldDef_IsExtension(f) ? upb_FieldDef_ExtensionScope(f) == + upb_MessageDef_ContainingType(msg) + : upb_FieldDef_ContainingType(f) == + upb_MessageDef_ContainingType(msg); +} + +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; + + if (upb_FieldDef_IsRepeated(f)) { + out |= kUpb_FieldModifier_IsRepeated; + } else if (upb_FieldDef_IsRequired(f)) { + out |= kUpb_FieldModifier_IsRequired; + } else if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + + if (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; + } + + if (_upb_FieldDef_ValidateUtf8(f)) { + out |= kUpb_FieldModifier_ValidateUtf8; + } + + return out; +} + +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { return f->has_presence; } + +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsEnum(f); +} + +bool upb_FieldDef_IsEnum(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum; +} + +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +} + +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; +} + +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); +} + +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +} + +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return UPB_DESC(FeatureSet_field_presence)(f->resolved_features) == + UPB_DESC(FeatureSet_LEGACY_REQUIRED); +} + +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; +} + +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; +} + +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} + +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} + +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; +} + +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; + + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } + } + *des++ = '\0'; + return out; +} + +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; +} + +static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; + + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } + } + + ret->len = dst - &ret->str[0]; + return ret; +} + +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + // Standard C number parsing functions expect null-terminated strings. + if (len >= sizeof(nullz) - 1) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = upb_EnumValueDef_Number(ev); + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } + + return; + +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); +} + +static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); + break; + } + case kUpb_CType_Message: + break; + } +} + +static bool _upb_FieldDef_InferLegacyFeatures( + upb_DefBuilder* ctx, upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto*) proto, + const UPB_DESC(FieldOptions*) options, upb_Syntax syntax, + UPB_DESC(FeatureSet*) features) { + bool ret = false; + + if (UPB_DESC(FieldDescriptorProto_label)(proto) == kUpb_Label_Required) { + if (syntax == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + int val = UPB_DESC(FeatureSet_LEGACY_REQUIRED); + UPB_DESC(FeatureSet_set_field_presence(features, val)); + ret = true; + } + + if (UPB_DESC(FieldDescriptorProto_type)(proto) == kUpb_FieldType_Group) { + int val = UPB_DESC(FeatureSet_DELIMITED); + UPB_DESC(FeatureSet_set_message_encoding(features, val)); + ret = true; + } + + if (UPB_DESC(FieldOptions_has_packed)(options)) { + int val = UPB_DESC(FieldOptions_packed)(options) + ? UPB_DESC(FeatureSet_PACKED) + : UPB_DESC(FeatureSet_EXPANDED); + UPB_DESC(FeatureSet_set_repeated_field_encoding(features, val)); + ret = true; + } + + return ret; +} + +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) + field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); + + const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto); + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto); + f->is_proto3_optional = + UPB_DESC(FieldDescriptorProto_proto3_optional)(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; + + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + upb_Syntax syntax = upb_FileDef_Syntax(f->file); + const UPB_DESC(FeatureSet*) unresolved_features = + UPB_DESC(FieldOptions_features)(f->opts); + bool implicit = false; + + if (syntax != kUpb_Syntax_Editions) { + upb_Message_Clear(UPB_UPCAST(ctx->legacy_features), + UPB_DESC_MINITABLE(FeatureSet)); + if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, syntax, + ctx->legacy_features)) { + implicit = true; + unresolved_features = ctx->legacy_features; + } + } + + if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { + int oneof_index = UPB_DESC(FieldDescriptorProto_oneof_index)(field_proto); + + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } + + if (oneof_index < 0 || oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } + + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; + parent_features = upb_OneofDef_ResolvedFeatures(oneof); + + _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); + } + + f->resolved_features = _upb_DefBuilder_DoResolveFeatures( + ctx, parent_features, unresolved_features, implicit); + + f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto); + if (f->label_ == kUpb_Label_Optional && + // TODO: remove once we can deprecate kUpb_Label_Required. + UPB_DESC(FeatureSet_field_presence)(f->resolved_features) == + UPB_DESC(FeatureSet_LEGACY_REQUIRED)) { + f->label_ = kUpb_Label_Required; + } + + if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + + f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto); + if (f->has_json_name) { + const upb_StringView sv = + UPB_DESC(FieldDescriptorProto_json_name)(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); + + const bool has_type = UPB_DESC(FieldDescriptorProto_has_type)(field_proto); + const bool has_type_name = + UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto); + + f->type_ = (int)UPB_DESC(FieldDescriptorProto_type)(field_proto); + + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } + + if ((!has_type && has_type_name) || f->type_ == kUpb_FieldType_Message) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll assign this in resolve_subdef() + } else { + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } + } + + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } + + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; + + if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } + } + + f->has_presence = + (!upb_FieldDef_IsRepeated(f)) && + (f->is_extension || + (f->type_ == kUpb_FieldType_Message || + f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || + UPB_DESC(FeatureSet_field_presence)(f->resolved_features) != + UPB_DESC(FeatureSet_IMPLICIT))); +} + +static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) + field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + f->is_extension = true; + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); + + if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } + + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; + + if (ctx->layout) { + UPB_ASSERT(upb_MiniTableExtension_Number( + upb_FieldDef_MiniTableExtension(f)) == f->number_); + } +} + +static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(FeatureSet*) + parent_features, + const UPB_DESC(FieldDescriptorProto*) + field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + f->is_extension = false; + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); + + if (!UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { + if (f->is_proto3_optional) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); + } + } + + _upb_MessageDef_InsertField(ctx, m, f); +} + +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); + + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; + + _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); + f->index_ = i; + } + + return defs; +} + +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); + + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; + + _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) { + // Speculate that the def fields are sorted. We will always sort the + // MiniTable fields, so if defs are sorted then indices will match. + // + // If this is incorrect, we will overwrite later. + f->layout_index = i; + } + + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + + return defs; +} + +static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + const UPB_DESC(FieldDescriptorProto)* field_proto = f->sub.unresolved; + upb_StringView name = UPB_DESC(FieldDescriptorProto_type_name)(field_proto); + bool has_name = UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto); + switch ((int)f->type_) { + case UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; + // TODO: remove once we can deprecate + // kUpb_FieldType_Group. + if (UPB_DESC(FeatureSet_message_encoding)(f->resolved_features) == + UPB_DESC(FeatureSet_DELIMITED) && + !upb_MessageDef_IsMapEntry(def) && + !(f->msgdef && upb_MessageDef_IsMapEntry(f->msgdef))) { + f->type_ = kUpb_FieldType_Group; + } + f->has_presence = !upb_FieldDef_IsRepeated(f); + break; + default: + _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } + break; + } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; + } +} + +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); +} + +// _upb_FieldDefs_Sorted() is mostly a pure function of its inputs, but has one +// critical side effect that we depend on: it sets layout_index appropriately +// for non-sorted lists of fields. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; + + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; + } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); + + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; + } + return (const upb_FieldDef**)out; +} + +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension); + + upb_DescState s; + _upb_DescState_Init(&s); + + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, + modifiers); + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto) * + field_proto) { + if (!UPB_DESC(FieldDescriptorProto_has_extendee)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } + + upb_StringView name = UPB_DESC(FieldDescriptorProto_extendee)(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; + + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); + } +} + +void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, + const upb_FieldDef* f) { + const upb_MiniTableExtension* ext = upb_FieldDef_MiniTableExtension(f); + + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == upb_MiniTableExtension_Number(ext)); + } else { + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } + + upb_MiniTableExtension* mut_ext = (upb_MiniTableExtension*)ext; + upb_MiniTableSub sub = {NULL}; + if (upb_FieldDef_IsSubMessage(f)) { + const upb_MiniTable* submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + sub = upb_MiniTableSub_FromMessage(submsg); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + const upb_MiniTableEnum* subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); + sub = upb_MiniTableSub_FromEnum(subenum); + } + bool ok2 = _upb_MiniTableExtension_Init(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(f->msgdef), + sub, ctx->platform, ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); + } + + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto) * + field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (UPB_DESC(FieldDescriptorProto_has_default_value)(field_proto)) { + upb_StringView defaultval = + UPB_DESC(FieldDescriptorProto_default_value)(field_proto); + + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } + + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; + } +} + +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const UPB_DESC(FieldDescriptorProto)* field_proto = f->sub.unresolved; + + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); + + if (f->is_extension) { + resolve_extension(ctx, prefix, f, field_proto); + } +} + + +#include +#include +#include + + +// Must be last. + +struct upb_FileDef { + const UPB_DESC(FileOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const char* name; + const char* package; + UPB_DESC(Edition) edition; + + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTableExtension** ext_layouts; + const upb_DefPool* symtab; + + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; // All exts in the file. + upb_Syntax syntax; +}; + +UPB_API const char* upb_FileDef_EditionName(int edition) { + // TODO Synchronize this with descriptor.proto better. + switch (edition) { + case UPB_DESC(EDITION_PROTO2): + return "PROTO2"; + case UPB_DESC(EDITION_PROTO3): + return "PROTO3"; + case UPB_DESC(EDITION_2023): + return "2023"; + default: + return "UNKNOWN"; + } +} + +const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; +} + +const UPB_DESC(FeatureSet) * + upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { + return f->resolved_features; +} + +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} + +UPB_DESC(Edition) upb_FileDef_Edition(const upb_FileDef* f) { + return f->edition; +} + +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } + +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; +} + +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} + +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} + +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; +} + +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; +} + +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; +} + +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; +} + +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; +} + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; +} + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; +} + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); +} + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); +} + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); +} + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); +} + +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } + +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; +} + +// Note: Import cycles are not allowed so this will terminate. +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* path) { + if (!strcmp(f->name, path)) return true; + + for (int i = 0; i < upb_FileDef_PublicDependencyCount(f); i++) { + const upb_FileDef* dep = upb_FileDef_PublicDependency(f, i); + if (upb_FileDef_Resolves(dep, path)) return true; + } + return false; +} + +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; +} + +static int count_exts_in_msg(const UPB_DESC(DescriptorProto) * msg_proto) { + size_t n; + UPB_DESC(DescriptorProto_extension)(msg_proto, &n); + int ext_count = n; + + const UPB_DESC(DescriptorProto)* const* nested_msgs = + UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } + + return ext_count; +} + +const UPB_DESC(FeatureSet*) + _upb_FileDef_FindEdition(upb_DefBuilder* ctx, int edition) { + const UPB_DESC(FeatureSetDefaults)* defaults = + upb_DefPool_FeatureSetDefaults(ctx->symtab); + + int min = UPB_DESC(FeatureSetDefaults_minimum_edition)(defaults); + int max = UPB_DESC(FeatureSetDefaults_maximum_edition)(defaults); + if (edition < min) { + _upb_DefBuilder_Errf(ctx, + "Edition %s is earlier than the minimum edition %s " + "given in the defaults", + upb_FileDef_EditionName(edition), + upb_FileDef_EditionName(min)); + return NULL; + } + if (edition > max) { + _upb_DefBuilder_Errf(ctx, + "Edition %s is later than the maximum edition %s " + "given in the defaults", + upb_FileDef_EditionName(edition), + upb_FileDef_EditionName(max)); + return NULL; + } + + size_t n; + const UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault)* const* d = + UPB_DESC(FeatureSetDefaults_defaults)(defaults, &n); + const UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault)* result = NULL; + for (size_t i = 0; i < n; i++) { + if (UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_edition)(d[i]) > + edition) { + break; + } + result = d[i]; + } + if (result == NULL) { + _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", + upb_FileDef_EditionName(edition)); + return NULL; + } + + // Merge the fixed and overridable features to get the edition's default + // feature set. + const UPB_DESC(FeatureSet)* fixed = UPB_DESC( + FeatureSetDefaults_FeatureSetEditionDefault_fixed_features)(result); + const UPB_DESC(FeatureSet)* overridable = UPB_DESC( + FeatureSetDefaults_FeatureSetEditionDefault_overridable_features)(result); + if (!fixed && !overridable) { + _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", + upb_FileDef_EditionName(edition)); + return NULL; + } else if (!fixed) { + return overridable; + } + return _upb_DefBuilder_DoResolveFeatures(ctx, fixed, overridable, + /*is_implicit=*/true); +} + +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const UPB_DESC(FileDescriptorProto) * file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; + + const UPB_DESC(DescriptorProto)* const* msgs; + const UPB_DESC(EnumDescriptorProto)* const* enums; + const UPB_DESC(FieldDescriptorProto)* const* exts; + const UPB_DESC(ServiceDescriptorProto)* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t n; + + file->symtab = ctx->symtab; + + // Count all extensions in the file, to build a flat array of layouts. + UPB_DESC(FileDescriptorProto_extension)(file_proto, &n); + int ext_count = n; + msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + // We are using the ext layouts that were passed in. + file->ext_layouts = ctx->layout->UPB_PRIVATE(exts); + const int mt_ext_count = upb_MiniTableFile_ExtensionCount(ctx->layout); + if (mt_ext_count != file->ext_count) { + _upb_DefBuilder_Errf(ctx, + "Extension count did not match layout (%d vs %d)", + mt_ext_count, file->ext_count); + } + } else { + // We are building ext layouts from scratch. + file->ext_layouts = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTableExtension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; + } + } + + upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto); + file->name = strviewdup(ctx, name); + if (strlen(file->name) != name.size) { + _upb_DefBuilder_Errf(ctx, "File name contained embedded NULL"); + } + + upb_StringView package = UPB_DESC(FileDescriptorProto_package)(file_proto); + + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } + + // TODO: How should we validate this? + file->edition = UPB_DESC(FileDescriptorProto_edition)(file_proto); + + if (UPB_DESC(FileDescriptorProto_has_syntax)(file_proto)) { + upb_StringView syntax = UPB_DESC(FileDescriptorProto_syntax)(file_proto); + + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + file->edition = UPB_DESC(EDITION_PROTO3); + } else if (streql_view(syntax, "editions")) { + file->syntax = kUpb_Syntax_Editions; + file->edition = UPB_DESC(FileDescriptorProto_edition)(file_proto); + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); + } + + // Read options. + UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + + // Resolve features. + const UPB_DESC(FeatureSet*) edition_defaults = + _upb_FileDef_FindEdition(ctx, file->edition); + const UPB_DESC(FeatureSet*) unresolved = + UPB_DESC(FileOptions_features)(file->opts); + file->resolved_features = + _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); + + // Verify dependencies. + strs = UPB_DESC(FileDescriptorProto_dependency)(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); + + for (size_t i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } + + public_deps = UPB_DESC(FileDescriptorProto_public_dependency)(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } + + weak_deps = UPB_DESC(FileDescriptorProto_weak_dependency)(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); + } + mutable_weak_deps[i] = weak_deps[i]; + } + + // Create enums. + enums = UPB_DESC(FileDescriptorProto_enum_type)(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = + _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); + + // Create extensions. + exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = _upb_Extensions_New( + ctx, n, exts, file->resolved_features, file->package, NULL); + + // Create messages. + msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = + _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); + + // Create services. + services = UPB_DESC(FileDescriptorProto_service)(file_proto, &n); + file->service_count = n; + file->services = + _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); + + // Now that all names are in the table, build layouts and resolve refs. + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); + } + + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_CreateMiniTable(ctx, (upb_MessageDef*)m); + } + + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_BuildMiniTableExtension(ctx, f); + } + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); + } + + if (file->ext_count) { + bool ok = upb_ExtensionRegistry_AddArray( + _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } +} + + +#include + + +// Must be last. + +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static UPB_ALIGN_AS(8) const + char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; + +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } + +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); +} + +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} + +// Verify a relative identifier string. The loop is branchless for speed. +static void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0); + + good &= is_alpha | is_numer; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); +} + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; + } +} + +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; + + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } + } + + *len = 0; + return true; +} + +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + // Symbols starting with '.' are absolute, so we do a single lookup. + // Slice to omit the leading '.' + if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + // Remove components from base until we find an entry or run out. + size_t baselen = base ? strlen(base) : 0; + char* tmp = upb_gmalloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + upb_gfree(tmp); + goto notfound; + } + } + upb_gfree(tmp); + } + + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); + +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); +} + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_Errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + } + return ret; +} + +// Per ASCII this will lower-case a letter. If the result is a letter, the +// input was definitely a letter. If the output is not a letter, this may +// have transformed the character unpredictably. +static char upb_ascii_lower(char ch) { return ch | 0x20; } + +// isalpha() etc. from are locale-dependent, which we don't want. +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return low <= c && c <= high; +} + +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} + +static int TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; +} + +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + int hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_Errf( + ctx, "\\x must be followed by at least one hex digit (field='%s')", + upb_FieldDef_FullName(f)); + return 0; + } + unsigned int ret = hex_digit; + while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} + +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} + +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} + +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + + // We should never reach this point. + UPB_ASSERT(false); +} + +upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key) { + size_t need = key.size + sizeof(void*); + if (ctx->tmp_buf_size < need) { + ctx->tmp_buf_size = UPB_MAX(64, upb_Log2Ceiling(need)); + ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); + if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); + } + + memcpy(ctx->tmp_buf, &parent, sizeof(void*)); + memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); + return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); +} + +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set) { + upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); + upb_value v; + if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { + *set = upb_value_getptr(v); + return false; + } + + *set = (UPB_DESC(FeatureSet*))upb_Message_DeepClone( + UPB_UPCAST(parent), UPB_DESC_MINITABLE(FeatureSet), ctx->arena); + if (!*set) _upb_DefBuilder_OomErr(ctx); + + v = upb_value_ptr(*set); + if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, + ctx->tmp_arena)) { + _upb_DefBuilder_OomErr(ctx); + } + + return true; +} + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit) { + assert(parent); + if (!child) return parent; + + if (child && !is_implicit && + upb_FileDef_Syntax(ctx->file) != kUpb_Syntax_Editions) { + _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); + } + + UPB_DESC(FeatureSet*) resolved; + size_t child_size; + const char* child_bytes = + UPB_DESC(FeatureSet_serialize)(child, ctx->tmp_arena, &child_size); + if (!child_bytes) _upb_DefBuilder_OomErr(ctx); + + upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); + if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { + return resolved; + } + + upb_DecodeStatus dec_status = + upb_Decode(child_bytes, child_size, UPB_UPCAST(resolved), + UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); + if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); + + return resolved; +} + + +#include + + +// Must be last. + +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; + + // Prevent overflow errors. + if (len == SIZE_MAX) return NULL; + + // Always null-terminate, even if binary data; but don't rely on the input to + // have a null-terminating byte since it may be a raw binary buffer. + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + if (len != 0) memcpy(p, s, len); + p[len] = 0; + } + return p; +} + + +#include +#include + + +// Must be last. + +bool upb_Message_HasFieldByDef(const upb_Message* msg, const upb_FieldDef* f) { + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + UPB_ASSERT(upb_FieldDef_HasPresence(f)); + + if (upb_MiniTableField_IsExtension(m_f)) { + return upb_Message_HasExtension(msg, (const upb_MiniTableExtension*)m_f); + } else { + return upb_Message_HasBaseField(msg, m_f); + } +} + +const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_HasFieldByDef(msg, f) ? f : NULL; + } else { + const upb_MiniTableField* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = upb_Message_WhichOneofFieldNumber(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; + } +} + +upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg, + const upb_FieldDef* f) { + upb_MessageValue default_val = upb_FieldDef_Default(f); + return upb_Message_GetField(msg, upb_FieldDef_MiniTable(f), default_val); +} + +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f)) { + // We need to skip the upb_Message_GetFieldByDef() call in this case. + goto make; + } + + upb_MessageValue val = upb_Message_GetFieldByDef(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } + + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); + } else if (upb_FieldDef_IsRepeated(f)) { + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); + } else { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); + } + + val.array_val = ret.array; + upb_Message_SetFieldByDef(msg, f, val, a); + + return ret; +} + +bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + + if (upb_MiniTableField_IsExtension(m_f)) { + return upb_Message_SetExtension(msg, (const upb_MiniTableExtension*)m_f, + &val, a); + } else { + upb_Message_SetBaseField(msg, m_f, &val); + return true; + } +} + +void upb_Message_ClearFieldByDef(upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + + if (upb_MiniTableField_IsExtension(m_f)) { + upb_Message_ClearExtension(msg, (const upb_MiniTableExtension*)m_f); + } else { + upb_Message_ClearBaseField(msg, m_f); + } +} + +void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +} + +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + size_t i = *iter; + size_t n = upb_MiniTable_FieldCount(mt); + upb_MessageValue zero = upb_MessageValue_Zero(); + UPB_UNUSED(ext_pool); + + // Iterate over normal fields, returning the first one that is set. + while (++i < n) { + const upb_MiniTableField* field = upb_MiniTable_GetFieldByIndex(mt, i); + upb_MessageValue val = upb_Message_GetField(msg, field, zero); + + // Skip field if unset or empty. + if (upb_MiniTableField_HasPresence(field)) { + if (!upb_Message_HasBaseField(msg, field)) continue; + } else { + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { + case kUpb_FieldMode_Map: + if (!val.map_val || upb_Map_Size(val.map_val) == 0) continue; + break; + case kUpb_FieldMode_Array: + if (!val.array_val || upb_Array_Size(val.array_val) == 0) continue; + break; + case kUpb_FieldMode_Scalar: + if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(field, &val)) + continue; + break; + } + } + + *out_val = val; + *out_f = + upb_MessageDef_FindFieldByNumber(m, upb_MiniTableField_Number(field)); + *iter = i; + return true; + } + + if (ext_pool) { + // Return any extensions that are set. + size_t count; + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; + } + } + + *iter = i; + return false; +} + +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int depth) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; + + if (--depth == 0) return false; + + _upb_Message_DiscardUnknown_shallow(msg); + + while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; + + if (!val_m) continue; + + upb_MessageValue map_key, map_val; + while (upb_Map_Next(map, &map_key, &map_val, &iter)) { + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + depth)) { + ret = false; + } + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + depth)) { + ret = false; + } + } + } else { + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + depth)) { + ret = false; + } + } + } + + return ret; +} + +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} + + +#include +#include +#include + + +// Must be last. + +struct upb_MessageDef { + const UPB_DESC(MessageOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; + + // Tables for looking up fields by number and name. + upb_inttable itof; + upb_strtable ntof; + + // Looking up fields by json name. + upb_strtable jtof; + + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_StringView* res_names; + const upb_MessageDef* nested_msgs; + const upb_MessageReservedRange* res_ranges; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + + // TODO: These counters don't need anywhere near 32 bits. + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int res_range_count; + int res_name_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + bool is_sorted; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = m->full_name; + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; + } +} + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { + return true; + } + } + return false; +} + +const UPB_DESC(MessageOptions) * + upb_MessageDef_Options(const upb_MessageDef* m) { + return m->opts; +} + +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_MessageDef_ResolvedFeatures(const upb_MessageDef* m) { + return m->resolved_features; +} + +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; +} + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; +} + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} + +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} + +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} + +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ +} + +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (upb_strtable_lookup2(&m->jtof, name, size, &val)) { + return upb_value_getconstptr(val); + } + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} + +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} + +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; +} + +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; +} + +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} + +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} + +int upb_MessageDef_RealOneofCount(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; +} + +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; +} + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); +} + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_range_count); + return _upb_MessageReservedRange_At(m->res_ranges, i); +} + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_name_count); + return m->res_names[i]; +} + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, i); +} + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); +} + +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); +} + +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); +} + +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} + +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); +} + +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return UPB_DESC(MessageOptions_map_entry)(m->opts); +} + +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return UPB_DESC(MessageOptions_message_set_wire_format)(m->opts); +} + +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + upb_StringView desc; + // Note: this will assign layout_index for fields, so upb_FieldDef_MiniTable() + // is safe to call only after this call. + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, ctx->platform, ctx->arena, scratch_data, + scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + + return ret; +} + +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, f); + } + + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + UPB_DESC(MessageOptions_message_set_wire_format)( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; + } + } + + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } +} + +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); + + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); + } + + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); + + upb_value v = upb_value_constptr(f); + + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + } + + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + bool skip_json_conflicts = + UPB_DESC(MessageOptions_deprecated_legacy_json_field_conflicts)( + upb_MessageDef_Options(m)); + if (!skip_json_conflicts && strcmp(shortname, json_name) != 0 && + UPB_DESC(FeatureSet_json_format)(m->resolved_features) == + UPB_DESC(FeatureSet_ALLOW) && + upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf( + ctx, "duplicate json_name for (%s) with original field name (%s)", + shortname, json_name); + } + + if (upb_strtable_lookup(&m->jtof, json_name, &v)) { + if (!skip_json_conflicts) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + } + } else { + const size_t json_size = strlen(json_name); + ok = upb_strtable_insert(&m->jtof, json_name, json_size, + upb_value_constptr(f), ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } + + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); + } + + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m) { + if (ctx->layout == NULL) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + } else { + m->layout = upb_MiniTableFile_Message(ctx->layout, ctx->msg_count++); + UPB_ASSERT(m->field_count == upb_MiniTable_FieldCount(m->layout)); + + // We don't need the result of this call, but it will assign layout_index + // for all the fields in O(n lg n) time. + _upb_FieldDefs_Sorted(m->fields, m->field_count, ctx->tmp_arena); + } + + for (int i = 0; i < m->nested_msg_count; i++) { + upb_MessageDef* nested = + (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_CreateMiniTable(ctx, nested); + } +} + +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_BuildMiniTableExtension(ctx, ext); + } + + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); + } + + if (ctx->layout) return; + + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTableField* mt_f = + (upb_MiniTableField*)&m->layout->UPB_PRIVATE(fields)[layout_index]; + if (sub_m) { + if (!mt->UPB_PRIVATE(subs)) { + _upb_DefBuilder_Errf(ctx, "unexpected submsg for (%s)", m->full_name); + } + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + if (UPB_UNLIKELY(!upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout))) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); + } + } else if (_upb_FieldDef_IsClosedEnum(f)) { + const upb_MiniTableEnum* mt_e = _upb_EnumDef_MiniTable(sub_e); + if (UPB_UNLIKELY(!upb_MiniTable_SetSubEnum(mt, mt_f, mt_e))) { + _upb_DefBuilder_Errf(ctx, "invalid subenum for (%s)", m->full_name); + } + } + } + +#ifndef NDEBUG + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + UPB_ASSERT(layout_index < upb_MiniTable_FieldCount(m->layout)); + const upb_MiniTableField* mt_f = + &m->layout->UPB_PRIVATE(fields)[layout_index]; + UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + UPB_ASSERT(upb_FieldDef_CType(f) == upb_MiniTableField_CType(mt_f)); + UPB_ASSERT(upb_FieldDef_HasPresence(f) == + upb_MiniTableField_HasPresence(mt_f)); + } +#endif +} + +static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { + bool has_string = false; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + // Old binaries do not recognize the field-level "FlipValidateUtf8" wire + // modifier, so we do not actually have field-level control for old + // binaries. Given this, we judge that the better failure mode is to be + // more lax than intended, rather than more strict. To achieve this, we + // only mark the message with the ValidateUtf8 modifier if *all* fields + // validate UTF-8. + if (!_upb_FieldDef_ValidateUtf8(f)) return false; + if (upb_FieldDef_Type(f) == kUpb_FieldType_String) has_string = true; + } + return has_string; +} + +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + + if (UPB_DESC(FeatureSet_repeated_field_encoding(m->resolved_features)) == + UPB_DESC(FeatureSet_PACKED)) { + out |= kUpb_MessageModifier_DefaultIsPacked; + } + + if (_upb_MessageDef_ValidateUtf8(m)) { + out |= kUpb_MessageModifier_ValidateUtf8; + } + + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + + return out; +} + +static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, + upb_Arena* a) { + if (m->field_count != 2) return false; + + const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); + const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); + if (key_field == NULL || val_field == NULL) return false; + + UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); + + s->ptr = upb_MtDataEncoder_EncodeMap( + &s->e, s->ptr, upb_FieldDef_Type(key_field), upb_FieldDef_Type(val_field), + _upb_FieldDef_Modifiers(key_field), _upb_FieldDef_Modifiers(val_field)); + return true; +} + +static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; + } + + s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, + _upb_MessageDef_Modifiers(m)); + + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); + } + + for (int i = 0; i < m->real_oneof_count; i++) { + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); + + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); + } + } + + return true; +} + +static bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); + + return true; +} + +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + if (!_upb_DescState_Grow(&s, a)) return false; + + if (upb_MessageDef_IsMapEntry(m)) { + if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; + } else if (UPB_DESC(MessageOptions_message_set_wire_format)(m->opts)) { + if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; + } else { + if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return false; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (int i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + +static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const UPB_DESC(DescriptorProto*) msg_proto, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type, + upb_MessageDef* m) { + const UPB_DESC(OneofDescriptorProto)* const* oneofs; + const UPB_DESC(FieldDescriptorProto)* const* fields; + const UPB_DESC(DescriptorProto_ExtensionRange)* const* ext_ranges; + const UPB_DESC(DescriptorProto_ReservedRange)* const* res_ranges; + const upb_StringView* res_names; + size_t n_oneof, n_field, n_enum, n_ext, n_msg; + size_t n_ext_range, n_res_range, n_res_name; + upb_StringView name; + + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MessageOptions_features)(m->opts)); + + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); + + m->containing_type = containing_type; + m->is_sorted = true; + + name = UPB_DESC(DescriptorProto_name)(msg_proto); + + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); + + oneofs = UPB_DESC(DescriptorProto_oneof_decl)(msg_proto, &n_oneof); + fields = UPB_DESC(DescriptorProto_field)(msg_proto, &n_field); + ext_ranges = + UPB_DESC(DescriptorProto_extension_range)(msg_proto, &n_ext_range); + res_ranges = + UPB_DESC(DescriptorProto_reserved_range)(msg_proto, &n_res_range); + res_names = UPB_DESC(DescriptorProto_reserved_name)(msg_proto, &n_res_name); + + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); + + m->field_count = n_field; + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, + m->full_name, m, &m->is_sorted); + + // Message Sets may not contain fields. + if (UPB_UNLIKELY(UPB_DESC(MessageOptions_message_set_wire_format)(m->opts))) { + if (UPB_UNLIKELY(n_field > 0)) { + _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + } + } + + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, + m->resolved_features, m); + + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); + + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); + + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; + + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + + const UPB_DESC(EnumDescriptorProto)* const* enums = + UPB_DESC(DescriptorProto_enum_type)(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = + _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); + + const UPB_DESC(FieldDescriptorProto)* const* exts = + UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, + m->full_name, m); + + const UPB_DESC(DescriptorProto)* const* msgs = + UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = + _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); +} + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); + + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); + + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], parent_features, containing_type, + &m[i]); + } + return m; +} + + +// Must be last. + +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; +} + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; +} +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; +} + +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto_ReservedRange) * const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + UPB_DESC(DescriptorProto_ReservedRange_start)(protos[i]); + const int32_t end = UPB_DESC(DescriptorProto_ReservedRange_end)(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + + +// Must be last. + +struct upb_MethodDef { + const UPB_DESC(MethodOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} + +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; +} + +const UPB_DESC(MethodOptions) * upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; +} + +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m) { + return m->resolved_features; +} + +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; +} + +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} + +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} + +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; +} + +static void create_method(upb_DefBuilder* ctx, + const UPB_DESC(MethodDescriptorProto*) method_proto, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s, upb_MethodDef* m) { + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MethodOptions_features)(m->opts)); + + upb_StringView name = UPB_DESC(MethodDescriptorProto_name)(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + UPB_DESC(MethodDescriptorProto_client_streaming)(method_proto); + m->server_streaming = + UPB_DESC(MethodDescriptorProto_server_streaming)(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + UPB_DESC(MethodDescriptorProto_input_type)(method_proto), + UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + UPB_DESC(MethodDescriptorProto_output_type)(method_proto), + UPB_DEFTYPE_MSG); +} + +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], parent_features, s, &m[i]); + m[i].index = i; + } + return m; +} + + +#include +#include +#include + + +// Must be last. + +struct upb_OneofDef { + const UPB_DESC(OneofOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +}; + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} + +const UPB_DESC(OneofOptions) * upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} + +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o) { + return o->resolved_features; +} + +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} + +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} + +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } + +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} + +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } + +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); +} + +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; +} + +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +} + +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} + +void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, + const upb_FieldDef* f, const char* name, + size_t size) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; + + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + + // TODO: This lookup is unfortunate because we also perform it when + // inserting into the message's table. Unfortunately that step occurs after + // this one and moving things around could be tricky so let's leave it for + // a future refactoring. + const bool number_exists = upb_inttable_lookup(&o->itof, number, NULL); + if (UPB_UNLIKELY(number_exists)) { + _upb_DefBuilder_Errf(ctx, "oneof fields have the same number (%d)", number); + } + + // TODO: More redundant work happening here. + const bool name_exists = upb_strtable_lookup2(&o->ntof, name, size, NULL); + if (UPB_UNLIKELY(name_exists)) { + _upb_DefBuilder_Errf(ctx, "oneof fields have the same name (%.*s)", + (int)size, name); + } + + const bool ok = upb_inttable_insert(&o->itof, number, v, ctx->arena) && + upb_strtable_insert(&o->ntof, name, size, v, ctx->arena); + if (UPB_UNLIKELY(!ok)) { + _upb_DefBuilder_OomErr(ctx); + } +} + +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; + + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); + } + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; + } + + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } + + return synthetic_count; +} + +static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, + const UPB_DESC(OneofDescriptorProto*) oneof_proto, + const UPB_DESC(FeatureSet*) parent_features, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + o->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(OneofOptions_features)(o->opts)); + + upb_StringView name = UPB_DESC(OneofDescriptorProto_name)(oneof_proto); + + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; + + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); + } + + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); + } + return o; +} + + + +// Must be last. + +struct upb_ServiceDef { + const UPB_DESC(ServiceOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; +} + +const UPB_DESC(ServiceOptions) * + upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; +} + +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; +} + +const UPB_DESC(FeatureSet) * + upb_ServiceDef_ResolvedFeatures(const upb_ServiceDef* s) { + return s->resolved_features; +} + +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; +} + +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); +} + +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} + +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; +} + +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; + } + } + return NULL; +} + +static void create_service(upb_DefBuilder* ctx, + const UPB_DESC(ServiceDescriptorProto*) svc_proto, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s) { + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); + s->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(ServiceOptions_features)(s->opts)); + + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + upb_StringView name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + size_t n; + const UPB_DESC(MethodDescriptorProto)* const* methods = + UPB_DESC(ServiceDescriptorProto_method)(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); +} + +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], parent_features, &s[i]); + s[i].index = i; + } + return s; +} + +// This should #undef all macros #defined in def.inc + +#undef UPB_SIZE +#undef UPB_PTR_AT +#undef UPB_MAPTYPE_STRING +#undef UPB_EXPORT +#undef UPB_INLINE +#undef UPB_API +#undef UPBC_API +#undef UPB_API_INLINE +#undef UPB_ALIGN_UP +#undef UPB_ALIGN_DOWN +#undef UPB_ALIGN_MALLOC +#undef UPB_ALIGN_OF +#undef UPB_ALIGN_AS +#undef UPB_MALLOC_ALIGN +#undef UPB_LIKELY +#undef UPB_UNLIKELY +#undef UPB_FORCEINLINE +#undef UPB_NOINLINE +#undef UPB_NORETURN +#undef UPB_PRINTF +#undef UPB_MAX +#undef UPB_MIN +#undef UPB_UNUSED +#undef UPB_ASSUME +#undef UPB_ASSERT +#undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE_MASK +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT +#undef UPB_POISON_MEMORY_REGION +#undef UPB_UNPOISON_MEMORY_REGION +#undef UPB_ASAN +#undef UPB_ASAN_GUARD_SIZE +#undef UPB_CLANG_ASAN +#undef UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN +#undef UPB_DESCRIPTOR_UPB_H_FILENAME +#undef UPB_DESC +#undef UPB_DESC_MINITABLE +#undef UPB_IS_GOOGLE3 +#undef UPB_ATOMIC +#undef UPB_USE_C11_ATOMICS +#undef UPB_PRIVATE +#undef UPB_ONLYBITS +#undef UPB_LINKARR_DECLARE +#undef UPB_LINKARR_APPEND +#undef UPB_LINKARR_START +#undef UPB_LINKARR_STOP +#undef UPB_FUTURE_BREAKING_CHANGES +#undef UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.h new file mode 100755 index 00000000..3b6866ad --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/ruby-upb.h @@ -0,0 +1,15194 @@ +// Ruby is still using proto3 enum semantics for proto2 +#define UPB_DISABLE_CLOSED_ENUM_CHECKING +/* Amalgamated source file */ + +/* + * This is where we define internal portability macros used across upb. + * + * All of these macros are undef'd in undef.inc to avoid leaking them to users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port/def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port/undef.inc" + * + * This file is private and must not be included by users! + */ + +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +#error upb requires C99 or C++14 or MSVC >= 2015. +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef UINTPTR_MAX +Error, UINTPTR_MAX is undefined +#endif + +#if UINTPTR_MAX == 0xffffffff +#define UPB_SIZE(size32, size64) size32 +#else +#define UPB_SIZE(size32, size64) size64 +#endif + +/* If we always read/write as a consistent type to each address, this shouldn't + * violate aliasing. + */ +#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) + +#define UPB_MAPTYPE_STRING 0 + +// UPB_EXPORT: always generate a public symbol. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) +#else +#define UPB_EXPORT +#endif + +// UPB_INLINE: inline if possible, emit standalone code if required. +#ifdef __cplusplus +#define UPB_INLINE inline +#elif defined (__GNUC__) || defined(__clang__) +#define UPB_INLINE static __inline__ +#else +#define UPB_INLINE static +#endif + +#ifdef UPB_BUILD_API +#define UPB_API UPB_EXPORT +#define UPB_API_INLINE UPB_EXPORT +#else +#define UPB_API +#define UPB_API_INLINE UPB_INLINE +#endif + +#ifdef EXPORT_UPBC +#define UPBC_API UPB_EXPORT +#else +#define UPBC_API +#endif + +#define UPB_MALLOC_ALIGN 8 +#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) +#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) +#ifdef __clang__ +#define UPB_ALIGN_OF(type) _Alignof(type) +#else +#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) +#endif + +#ifdef _MSC_VER +// Some versions of our Windows compiler don't support the C11 syntax. +#define UPB_ALIGN_AS(x) __declspec(align(x)) +#else +#define UPB_ALIGN_AS(x) _Alignas(x) +#endif + +// Hints to the compiler about likely/unlikely branches. +#if defined (__GNUC__) || defined(__clang__) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) +#else +#define UPB_LIKELY(x) (x) +#define UPB_UNLIKELY(x) (x) +#endif + +// Macros for function attributes on compilers that support them. +#ifdef __GNUC__ +#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static +#define UPB_NOINLINE __attribute__((noinline)) +#define UPB_NORETURN __attribute__((__noreturn__)) +#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg))) +#elif defined(_MSC_VER) +#define UPB_NOINLINE +#define UPB_FORCEINLINE static +#define UPB_NORETURN __declspec(noreturn) +#define UPB_PRINTF(str, first_vararg) +#else /* !defined(__GNUC__) */ +#define UPB_FORCEINLINE static +#define UPB_NOINLINE +#define UPB_NORETURN +#define UPB_PRINTF(str, first_vararg) +#endif + +#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)var + +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. +#ifdef NDEBUG +#ifdef __GNUC__ +#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() +#elif defined _MSC_VER +#define UPB_ASSUME(expr) if (!(expr)) __assume(0) +#else +#define UPB_ASSUME(expr) do {} while (false && (expr)) +#endif +#else +#define UPB_ASSUME(expr) assert(expr) +#endif + +/* UPB_ASSERT(): in release mode, we use the expression without letting it be + * evaluated. This prevents "unused variable" warnings. */ +#ifdef NDEBUG +#define UPB_ASSERT(expr) do {} while (false && (expr)) +#else +#define UPB_ASSERT(expr) assert(expr) +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) +#elif defined(_MSC_VER) +#define UPB_UNREACHABLE() \ + do { \ + assert(0); \ + __assume(0); \ + } while (0) +#else +#define UPB_UNREACHABLE() do { assert(0); } while(0) +#endif + +/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */ +#ifdef __APPLE__ +#define UPB_SETJMP(buf) _setjmp(buf) +#define UPB_LONGJMP(buf, val) _longjmp(buf, val) +#elif defined(WASM_WAMR) +#define UPB_SETJMP(buf) 0 +#define UPB_LONGJMP(buf, val) abort() +#else +#define UPB_SETJMP(buf) setjmp(buf) +#define UPB_LONGJMP(buf, val) longjmp(buf, val) +#endif + +#ifdef __GNUC__ +#define UPB_USE_C11_ATOMICS +#define UPB_ATOMIC(T) _Atomic(T) +#else +#define UPB_ATOMIC(T) T +#endif + +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + +#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only + +#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY +#define UPB_ONLYBITS(x) x +#else +#define UPB_ONLYBITS(x) UPB_PRIVATE(x) +#endif + +/* Configure whether fasttable is switched on or not. *************************/ + +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#undef UPB_HAS_ATTRIBUTE + +/* This check is not fully robust: it does not require that we have "musttail" + * support available. We need tail calls to avoid consuming arbitrary amounts + * of stack space. + * + * GCC/Clang can mostly be trusted to generate tail calls as long as + * optimization is enabled, but, debug builds will not generate tail calls + * unless "musttail" is available. + * + * We should probably either: + * 1. require that the compiler supports musttail. + * 2. add some fallback code for when musttail isn't available (ie. return + * instead of tail calling). This is safe and portable, but this comes at + * a CPU cost. + */ +#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) +#define UPB_FASTTABLE_SUPPORTED 1 +#else +#define UPB_FASTTABLE_SUPPORTED 0 +#endif + +/* define UPB_ENABLE_FASTTABLE to force fast table support. + * This is useful when we want to ensure we are really getting fasttable, + * for example for testing or benchmarking. */ +#if defined(UPB_ENABLE_FASTTABLE) +#if !UPB_FASTTABLE_SUPPORTED +#error fasttable is x86-64/ARM64 only and requires GCC or Clang. +#endif +#define UPB_FASTTABLE 1 +/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. + * This is useful for releasing code that might be used on multiple platforms, + * for example the PHP or Ruby C extensions. */ +#elif defined(UPB_TRY_ENABLE_FASTTABLE) +#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED +#else +#define UPB_FASTTABLE 0 +#endif + +/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully + * degrade to non-fasttable if the runtime or platform do not support it. */ +#if !UPB_FASTTABLE +#define UPB_FASTTABLE_INIT(...) +#define UPB_FASTTABLE_MASK(mask) -1 +#else +#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ +#define UPB_FASTTABLE_MASK(mask) mask +#endif + +#undef UPB_FASTTABLE_SUPPORTED + +/* ASAN poisoning (for arena). + * If using UPB from an interpreted language like Ruby, a build of the + * interpreter compiled with ASAN enabled must be used in order to get sane and + * expected behavior. + */ + +/* Due to preprocessor limitations, the conditional logic for setting + * UPN_CLANG_ASAN below cannot be consolidated into a portable one-liner. + * See https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. + */ +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define UPB_CLANG_ASAN 1 +#else +#define UPB_CLANG_ASAN 0 +#endif +#else +#define UPB_CLANG_ASAN 0 +#endif + +#if defined(__SANITIZE_ADDRESS__) || UPB_CLANG_ASAN +#define UPB_ASAN 1 +#define UPB_ASAN_GUARD_SIZE 32 +#ifdef __cplusplus + extern "C" { +#endif +void __asan_poison_memory_region(void const volatile *addr, size_t size); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#ifdef __cplusplus +} /* extern "C" */ +#endif +#define UPB_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) +#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) +#else +#define UPB_ASAN 0 +#define UPB_ASAN_GUARD_SIZE 0 +#define UPB_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif + +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_CLOSED_ENUM_CHECKING +#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 1 +#else +#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 0 +#endif + +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#if __cplusplus >= 201402L +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED __attribute__((deprecated)) +#endif +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif + +#if defined(UPB_IS_GOOGLE3) && \ + (!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) +#define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() +#else +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init +#endif + +#undef UPB_IS_GOOGLE3 + +// Linker arrays combine elements from multiple translation units into a single +// array that can be iterated over at runtime. +// +// It is an alternative to pre-main "registration" functions. +// +// Usage: +// +// // In N translation units. +// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; +// +// // At runtime: +// UPB_LINKARR_DECLARE(foo_array, int); +// +// void f() { +// const int* start = UPB_LINKARR_START(foo_array); +// const int* stop = UPB_LINKARR_STOP(foo_array); +// for (const int* p = start; p < stop; p++) { +// // Windows can introduce zero padding, so we have to skip zeroes. +// if (*p != 0) { +// vec.push_back(*p); +// } +// } +// } + +#if defined(__ELF__) || defined(__wasm__) + +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("linkarr_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name; \ + extern type const __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(__MACH__) + +/* As described in: https://stackoverflow.com/a/22366882 */ +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("__DATA,__la_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name __asm( \ + "section$start$__DATA$__la_" #name); \ + extern type const __stop_linkarr_##name __asm( \ + "section$end$__DATA$" \ + "__la_" #name); \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(_MSC_VER) && defined(__clang__) + +/* See: + * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 + * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 + * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ + +// Usage of __attribute__ here probably means this is Clang-specific, and would +// not work on MSVC. +#define UPB_LINKARR_APPEND(name) \ + __declspec(allocate("la_" #name "$j")) __attribute__((retain, used)) +#define UPB_LINKARR_DECLARE(name, type) \ + __declspec(allocate("la_" #name "$a")) type __start_linkarr_##name; \ + __declspec(allocate("la_" #name "$z")) type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0} +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#else + +// Linker arrays are not supported on this platform. Make appends a no-op but +// don't define the other macros. +#define UPB_LINKARR_APPEND(name) + +#endif + +// Future versions of upb will include breaking changes to some APIs. +// This macro can be set to enable these API changes ahead of time, so that +// user code can be updated before upgrading versions of protobuf. +#ifdef UPB_FUTURE_BREAKING_CHANGES + +// Properly enforce closed enums in python. +// Owner: mkruskal@ +#define UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT 1 + +#endif + +#ifndef UPB_BASE_STATUS_H_ +#define UPB_BASE_STATUS_H_ + +#include + +// Must be last. + +#define _kUpb_Status_MaxMessage 511 + +typedef struct { + bool ok; + char msg[_kUpb_Status_MaxMessage]; // Error message; NULL-terminated. +} upb_Status; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const char* upb_Status_ErrorMessage(const upb_Status* status); +UPB_API bool upb_Status_IsOk(const upb_Status* status); + +// These are no-op if |status| is NULL. +UPB_API void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STATUS_H_ */ + +#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ +#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ + +#include + + +/* upb_Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb_Arena is *not* thread-safe. + * + * You could write a thread-safe arena allocator that satisfies the + * upb_alloc interface, but it would not be as efficient for the + * single-threaded case. */ + +#ifndef UPB_MEM_ARENA_H_ +#define UPB_MEM_ARENA_H_ + +#include +#include + + +#ifndef UPB_MEM_ALLOC_H_ +#define UPB_MEM_ALLOC_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct upb_alloc upb_alloc; + +/* A combined `malloc()`/`free()` function. + * If `size` is 0 then the function acts like `free()`, otherwise it acts like + * `realloc()`. Only `oldsize` bytes from a previous allocation are + * preserved. */ +typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size); + +/* A upb_alloc is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * `free()` calls) or a regular `malloc()` (which does). The client must + * therefore free memory unless it knows that the allocator is an arena + * allocator. */ +struct upb_alloc { + upb_alloc_func* func; +}; + +UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, NULL, 0, size); +} + +UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, ptr, oldsize, size); +} + +UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { + UPB_ASSERT(alloc); + alloc->func(alloc, ptr, 0, 0); +} + +// The global allocator used by upb. Uses the standard malloc()/free(). + +extern upb_alloc upb_alloc_global; + +/* Functions that hard-code the global malloc. + * + * We still get benefit because we can put custom logic into our global + * allocator, like injecting out-of-memory faults in debug/testing builds. */ + +UPB_INLINE void* upb_gmalloc(size_t size) { + return upb_malloc(&upb_alloc_global, size); +} + +UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) { + return upb_realloc(&upb_alloc_global, ptr, oldsize, size); +} + +UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_ALLOC_H_ */ + +#ifndef UPB_MEM_INTERNAL_ARENA_H_ +#define UPB_MEM_INTERNAL_ARENA_H_ + +#include +#include +#include + +// Must be last. + +// This is QUITE an ugly hack, which specifies the number of pointers needed +// to equal (or exceed) the storage required for one upb_Arena. +// +// We need this because the decoder inlines a upb_Arena for performance but +// the full struct is not visible outside of arena.c. Yes, I know, it's awful. +#define UPB_ARENA_SIZE_HACK 7 + +// LINT.IfChange(upb_Arena) + +struct upb_Arena { + char* UPB_ONLYBITS(ptr); + char* UPB_ONLYBITS(end); +}; + +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/arena.ts:upb_Arena) + +#ifdef __cplusplus +extern "C" { +#endif + +void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des, + const struct upb_Arena* src); +void UPB_PRIVATE(_upb_Arena_SwapOut)(struct upb_Arena* des, + const struct upb_Arena* src); + +// Returns whether |ptr| was allocated directly by |a| (so care must be used +// with fused arenas). +UPB_API bool UPB_ONLYBITS(_upb_Arena_Contains)(const struct upb_Arena* a, + void* ptr); + +UPB_INLINE size_t UPB_PRIVATE(_upb_ArenaHas)(const struct upb_Arena* a) { + return (size_t)(a->UPB_ONLYBITS(end) - a->UPB_ONLYBITS(ptr)); +} + +UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) { + void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(struct upb_Arena * a, size_t size); + + size = UPB_ALIGN_MALLOC(size); + const size_t span = size + UPB_ASAN_GUARD_SIZE; + if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) { + return UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span); + } + + // We have enough space to do a fast malloc. + void* ret = a->UPB_ONLYBITS(ptr); + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); + + a->UPB_ONLYBITS(ptr) += span; + + return ret; +} + +UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + bool is_most_recent_alloc = + (uintptr_t)ptr + oldsize == (uintptr_t)a->UPB_ONLYBITS(ptr); + + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)UPB_PRIVATE(_upb_ArenaHas)(a) >= diff) { + a->UPB_ONLYBITS(ptr) += diff; + return ptr; + } + } else if (size <= oldsize) { + return ptr; + } + + void* ret = upb_Arena_Malloc(a, size); + + if (ret && oldsize > 0) { + memcpy(ret, ptr, UPB_MIN(oldsize, size)); + } + + return ret; +} + +UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + // Must be the last alloc. + UPB_ASSERT((char*)ptr + oldsize == + a->UPB_ONLYBITS(ptr) - UPB_ASAN_GUARD_SIZE); + UPB_ASSERT(size <= oldsize); + a->UPB_ONLYBITS(ptr) = (char*)ptr + size; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_INTERNAL_ARENA_H_ */ + +// Must be last. + +typedef struct upb_Arena upb_Arena; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates an arena from the given initial block (if any -- n may be 0). +// Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this +// is a fixed-size arena and cannot grow. +UPB_API upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc); + +UPB_API void upb_Arena_Free(upb_Arena* a); +UPB_API bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b); + +bool upb_Arena_IncRefFor(upb_Arena* a, const void* owner); +void upb_Arena_DecRefFor(upb_Arena* a, const void* owner); + +size_t upb_Arena_SpaceAllocated(upb_Arena* a, size_t* fused_count); +uint32_t upb_Arena_DebugRefCount(upb_Arena* a); + +UPB_API_INLINE upb_Arena* upb_Arena_New(void) { + return upb_Arena_Init(NULL, 0, &upb_alloc_global); +} + +UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size); + +UPB_API_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, + size_t size); + +// Sets the maximum block size for all arenas. This is a global configuration +// setting that will affect all existing and future arenas. If +// upb_Arena_Malloc() is called with a size larger than this, we will exceed +// this size and allocate a larger block. +// +// This API is meant for experimentation only. It will likely be removed in +// the future. +void upb_Arena_SetMaxBlockSize(size_t max); + +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_API_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, + size_t oldsize, size_t size); + +#ifdef UPB_TRACING_ENABLED +void upb_Arena_SetTraceHandler(void (*initArenaTraceHandler)(const upb_Arena*, + size_t size), + void (*fuseArenaTraceHandler)(const upb_Arena*, + const upb_Arena*), + void (*freeArenaTraceHandler)(const upb_Arena*)); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_ARENA_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// The maximum number of bytes a single protobuf field can take up in the +// wire format. We only want to do one bounds check per field, so the input +// stream guarantees that after upb_EpsCopyInputStream_IsDone() is called, +// the decoder can read this many bytes without performing another bounds +// check. The stream will copy into a patch buffer as necessary to guarantee +// this invariant. +#define kUpb_EpsCopyInputStream_SlopBytes 16 + +enum { + kUpb_EpsCopyInputStream_NoAliasing = 0, + kUpb_EpsCopyInputStream_OnPatch = 1, + kUpb_EpsCopyInputStream_NoDelta = 2 +}; + +typedef struct { + const char* end; // Can read up to SlopBytes bytes beyond this. + const char* limit_ptr; // For bounds checks, = end + UPB_MIN(limit, 0) + uintptr_t aliasing; + int limit; // Submessage limit relative to end + bool error; // To distinguish between EOF and error. + char patch[kUpb_EpsCopyInputStream_SlopBytes * 2]; +} upb_EpsCopyInputStream; + +// Returns true if the stream is in the error state. A stream enters the error +// state when the user reads past a limit (caught in IsDone()) or the +// ZeroCopyInputStream returns an error. +UPB_INLINE bool upb_EpsCopyInputStream_IsError(upb_EpsCopyInputStream* e) { + return e->error; +} + +typedef const char* upb_EpsCopyInputStream_BufferFlipCallback( + upb_EpsCopyInputStream* e, const char* old_end, const char* new_start); + +typedef const char* upb_EpsCopyInputStream_IsDoneFallbackFunc( + upb_EpsCopyInputStream* e, const char* ptr, int overrun); + +// Initializes a upb_EpsCopyInputStream using the contents of the buffer +// [*ptr, size]. Updates `*ptr` as necessary to guarantee that at least +// kUpb_EpsCopyInputStream_SlopBytes are available to read. +UPB_INLINE void upb_EpsCopyInputStream_Init(upb_EpsCopyInputStream* e, + const char** ptr, size_t size, + bool enable_aliasing) { + if (size <= kUpb_EpsCopyInputStream_SlopBytes) { + memset(&e->patch, 0, 32); + if (size) memcpy(&e->patch, *ptr, size); + e->aliasing = enable_aliasing ? (uintptr_t)*ptr - (uintptr_t)e->patch + : kUpb_EpsCopyInputStream_NoAliasing; + *ptr = e->patch; + e->end = *ptr + size; + e->limit = 0; + } else { + e->end = *ptr + size - kUpb_EpsCopyInputStream_SlopBytes; + e->limit = kUpb_EpsCopyInputStream_SlopBytes; + e->aliasing = enable_aliasing ? kUpb_EpsCopyInputStream_NoDelta + : kUpb_EpsCopyInputStream_NoAliasing; + } + e->limit_ptr = e->end; + e->error = false; +} + +typedef enum { + // The current stream position is at a limit. + kUpb_IsDoneStatus_Done, + + // The current stream position is not at a limit. + kUpb_IsDoneStatus_NotDone, + + // The current stream position is not at a limit, and the stream needs to + // be flipped to a new buffer before more data can be read. + kUpb_IsDoneStatus_NeedFallback, +} upb_IsDoneStatus; + +// Returns the status of the current stream position. This is a low-level +// function, it is simpler to call upb_EpsCopyInputStream_IsDone() if possible. +UPB_INLINE upb_IsDoneStatus upb_EpsCopyInputStream_IsDoneStatus( + upb_EpsCopyInputStream* e, const char* ptr, int* overrun) { + *overrun = ptr - e->end; + if (UPB_LIKELY(ptr < e->limit_ptr)) { + return kUpb_IsDoneStatus_NotDone; + } else if (UPB_LIKELY(*overrun == e->limit)) { + return kUpb_IsDoneStatus_Done; + } else { + return kUpb_IsDoneStatus_NeedFallback; + } +} + +// Returns true if the stream has hit a limit, either the current delimited +// limit or the overall end-of-stream. As a side effect, this function may flip +// the pointer to a new buffer if there are less than +// kUpb_EpsCopyInputStream_SlopBytes of data to be read in the current buffer. +// +// Postcondition: if the function returns false, there are at least +// kUpb_EpsCopyInputStream_SlopBytes of data available to read at *ptr. +UPB_INLINE bool upb_EpsCopyInputStream_IsDoneWithCallback( + upb_EpsCopyInputStream* e, const char** ptr, + upb_EpsCopyInputStream_IsDoneFallbackFunc* func) { + int overrun; + switch (upb_EpsCopyInputStream_IsDoneStatus(e, *ptr, &overrun)) { + case kUpb_IsDoneStatus_Done: + return true; + case kUpb_IsDoneStatus_NotDone: + return false; + case kUpb_IsDoneStatus_NeedFallback: + *ptr = func(e, *ptr, overrun); + return *ptr == NULL; + } + UPB_UNREACHABLE(); +} + +const char* _upb_EpsCopyInputStream_IsDoneFallbackNoCallback( + upb_EpsCopyInputStream* e, const char* ptr, int overrun); + +// A simpler version of IsDoneWithCallback() that does not support a buffer flip +// callback. Useful in cases where we do not need to insert custom logic at +// every buffer flip. +// +// If this returns true, the user must call upb_EpsCopyInputStream_IsError() +// to distinguish between EOF and error. +UPB_INLINE bool upb_EpsCopyInputStream_IsDone(upb_EpsCopyInputStream* e, + const char** ptr) { + return upb_EpsCopyInputStream_IsDoneWithCallback( + e, ptr, _upb_EpsCopyInputStream_IsDoneFallbackNoCallback); +} + +// Returns the total number of bytes that are safe to read from the current +// buffer without reading uninitialized or unallocated memory. +// +// Note that this check does not respect any semantic limits on the stream, +// either limits from PushLimit() or the overall stream end, so some of these +// bytes may have unpredictable, nonsense values in them. The guarantee is only +// that the bytes are valid to read from the perspective of the C language +// (ie. you can read without triggering UBSAN or ASAN). +UPB_INLINE size_t upb_EpsCopyInputStream_BytesAvailable( + upb_EpsCopyInputStream* e, const char* ptr) { + return (e->end - ptr) + kUpb_EpsCopyInputStream_SlopBytes; +} + +// Returns true if the given delimited field size is valid (it does not extend +// beyond any previously-pushed limits). `ptr` should point to the beginning +// of the field data, after the delimited size. +// +// Note that this does *not* guarantee that all of the data for this field is in +// the current buffer. +UPB_INLINE bool upb_EpsCopyInputStream_CheckSize( + const upb_EpsCopyInputStream* e, const char* ptr, int size) { + UPB_ASSERT(size >= 0); + return ptr - e->end + size <= e->limit; +} + +UPB_INLINE bool _upb_EpsCopyInputStream_CheckSizeAvailable( + upb_EpsCopyInputStream* e, const char* ptr, int size, bool submessage) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows a small improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)e->limit_ptr; + uintptr_t res = uptr + (size_t)size; + if (!submessage) uend += kUpb_EpsCopyInputStream_SlopBytes; + // NOTE: this check depends on having a linear address space. This is not + // technically guaranteed by uintptr_t. + bool ret = res >= uptr && res <= uend; + if (size < 0) UPB_ASSERT(!ret); + return ret; +} + +// Returns true if the given delimited field size is valid (it does not extend +// beyond any previously-pushed limited) *and* all of the data for this field is +// available to be read in the current buffer. +// +// If the size is negative, this function will always return false. This +// property can be useful in some cases. +UPB_INLINE bool upb_EpsCopyInputStream_CheckDataSizeAvailable( + upb_EpsCopyInputStream* e, const char* ptr, int size) { + return _upb_EpsCopyInputStream_CheckSizeAvailable(e, ptr, size, false); +} + +// Returns true if the given sub-message size is valid (it does not extend +// beyond any previously-pushed limited) *and* all of the data for this +// sub-message is available to be parsed in the current buffer. +// +// This implies that all fields from the sub-message can be parsed from the +// current buffer while maintaining the invariant that we always have at least +// kUpb_EpsCopyInputStream_SlopBytes of data available past the beginning of +// any individual field start. +// +// If the size is negative, this function will always return false. This +// property can be useful in some cases. +UPB_INLINE bool upb_EpsCopyInputStream_CheckSubMessageSizeAvailable( + upb_EpsCopyInputStream* e, const char* ptr, int size) { + return _upb_EpsCopyInputStream_CheckSizeAvailable(e, ptr, size, true); +} + +// Returns true if aliasing_enabled=true was passed to +// upb_EpsCopyInputStream_Init() when this stream was initialized. +UPB_INLINE bool upb_EpsCopyInputStream_AliasingEnabled( + upb_EpsCopyInputStream* e) { + return e->aliasing != kUpb_EpsCopyInputStream_NoAliasing; +} + +// Returns true if aliasing_enabled=true was passed to +// upb_EpsCopyInputStream_Init() when this stream was initialized *and* we can +// alias into the region [ptr, size] in an input buffer. +UPB_INLINE bool upb_EpsCopyInputStream_AliasingAvailable( + upb_EpsCopyInputStream* e, const char* ptr, size_t size) { + // When EpsCopyInputStream supports streaming, this will need to become a + // runtime check. + return upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size) && + e->aliasing >= kUpb_EpsCopyInputStream_NoDelta; +} + +// Returns a pointer into an input buffer that corresponds to the parsing +// pointer `ptr`. The returned pointer may be the same as `ptr`, but also may +// be different if we are currently parsing out of the patch buffer. +// +// REQUIRES: Aliasing must be available for the given pointer. If the input is a +// flat buffer and aliasing is enabled, then aliasing will always be available. +UPB_INLINE const char* upb_EpsCopyInputStream_GetAliasedPtr( + upb_EpsCopyInputStream* e, const char* ptr) { + UPB_ASSUME(upb_EpsCopyInputStream_AliasingAvailable(e, ptr, 0)); + uintptr_t delta = + e->aliasing == kUpb_EpsCopyInputStream_NoDelta ? 0 : e->aliasing; + return (const char*)((uintptr_t)ptr + delta); +} + +// Reads string data from the input, aliasing into the input buffer instead of +// copying. The parsing pointer is passed in `*ptr`, and will be updated if +// necessary to point to the actual input buffer. Returns the new parsing +// pointer, which will be advanced past the string data. +// +// REQUIRES: Aliasing must be available for this data region (test with +// upb_EpsCopyInputStream_AliasingAvailable(). +UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringAliased( + upb_EpsCopyInputStream* e, const char** ptr, size_t size) { + UPB_ASSUME(upb_EpsCopyInputStream_AliasingAvailable(e, *ptr, size)); + const char* ret = *ptr + size; + *ptr = upb_EpsCopyInputStream_GetAliasedPtr(e, *ptr); + UPB_ASSUME(ret != NULL); + return ret; +} + +// Skips `size` bytes of data from the input and returns a pointer past the end. +// Returns NULL on end of stream or error. +UPB_INLINE const char* upb_EpsCopyInputStream_Skip(upb_EpsCopyInputStream* e, + const char* ptr, int size) { + if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL; + return ptr + size; +} + +// Copies `size` bytes of data from the input `ptr` into the buffer `to`, and +// returns a pointer past the end. Returns NULL on end of stream or error. +UPB_INLINE const char* upb_EpsCopyInputStream_Copy(upb_EpsCopyInputStream* e, + const char* ptr, void* to, + int size) { + if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL; + memcpy(to, ptr, size); + return ptr + size; +} + +// Reads string data from the stream and advances the pointer accordingly. +// If aliasing was enabled when the stream was initialized, then the returned +// pointer will point into the input buffer if possible, otherwise new data +// will be allocated from arena and copied into. We may be forced to copy even +// if aliasing was enabled if the input data spans input buffers. +// +// Returns NULL if memory allocation failed, or we reached a premature EOF. +UPB_INLINE const char* upb_EpsCopyInputStream_ReadString( + upb_EpsCopyInputStream* e, const char** ptr, size_t size, + upb_Arena* arena) { + if (upb_EpsCopyInputStream_AliasingAvailable(e, *ptr, size)) { + return upb_EpsCopyInputStream_ReadStringAliased(e, ptr, size); + } else { + // We need to allocate and copy. + if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, *ptr, size)) { + return NULL; + } + UPB_ASSERT(arena); + char* data = (char*)upb_Arena_Malloc(arena, size); + if (!data) return NULL; + const char* ret = upb_EpsCopyInputStream_Copy(e, *ptr, data, size); + *ptr = data; + return ret; + } +} + +UPB_INLINE void _upb_EpsCopyInputStream_CheckLimit(upb_EpsCopyInputStream* e) { + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); +} + +// Pushes a limit onto the stack of limits for the current stream. The limit +// will extend for `size` bytes beyond the position in `ptr`. Future calls to +// upb_EpsCopyInputStream_IsDone() will return `true` when the stream position +// reaches this limit. +// +// Returns a delta that the caller must store and supply to PopLimit() below. +UPB_INLINE int upb_EpsCopyInputStream_PushLimit(upb_EpsCopyInputStream* e, + const char* ptr, int size) { + int limit = size + (int)(ptr - e->end); + int delta = e->limit - limit; + _upb_EpsCopyInputStream_CheckLimit(e); + UPB_ASSERT(limit <= e->limit); + e->limit = limit; + e->limit_ptr = e->end + UPB_MIN(0, limit); + _upb_EpsCopyInputStream_CheckLimit(e); + return delta; +} + +// Pops the last limit that was pushed on this stream. This may only be called +// once IsDone() returns true. The user must pass the delta that was returned +// from PushLimit(). +UPB_INLINE void upb_EpsCopyInputStream_PopLimit(upb_EpsCopyInputStream* e, + const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - e->end == e->limit); + _upb_EpsCopyInputStream_CheckLimit(e); + e->limit += saved_delta; + e->limit_ptr = e->end + UPB_MIN(0, e->limit); + _upb_EpsCopyInputStream_CheckLimit(e); +} + +UPB_INLINE const char* _upb_EpsCopyInputStream_IsDoneFallbackInline( + upb_EpsCopyInputStream* e, const char* ptr, int overrun, + upb_EpsCopyInputStream_BufferFlipCallback* callback) { + if (overrun < e->limit) { + // Need to copy remaining data into patch buffer. + UPB_ASSERT(overrun < kUpb_EpsCopyInputStream_SlopBytes); + const char* old_end = ptr; + const char* new_start = &e->patch[0] + overrun; + memset(e->patch + kUpb_EpsCopyInputStream_SlopBytes, 0, + kUpb_EpsCopyInputStream_SlopBytes); + memcpy(e->patch, e->end, kUpb_EpsCopyInputStream_SlopBytes); + ptr = new_start; + e->end = &e->patch[kUpb_EpsCopyInputStream_SlopBytes]; + e->limit -= kUpb_EpsCopyInputStream_SlopBytes; + e->limit_ptr = e->end + e->limit; + UPB_ASSERT(ptr < e->limit_ptr); + if (e->aliasing != kUpb_EpsCopyInputStream_NoAliasing) { + e->aliasing = (uintptr_t)old_end - (uintptr_t)new_start; + } + return callback(e, old_end, new_start); + } else { + UPB_ASSERT(overrun > e->limit); + e->error = true; + return callback(e, NULL, NULL); + } +} + +typedef const char* upb_EpsCopyInputStream_ParseDelimitedFunc( + upb_EpsCopyInputStream* e, const char* ptr, void* ctx); + +// Tries to perform a fast-path handling of the given delimited message data. +// If the sub-message beginning at `*ptr` and extending for `len` is short and +// fits within this buffer, calls `func` with `ctx` as a parameter, where the +// pushing and popping of limits is handled automatically and with lower cost +// than the normal PushLimit()/PopLimit() sequence. +UPB_FORCEINLINE bool upb_EpsCopyInputStream_TryParseDelimitedFast( + upb_EpsCopyInputStream* e, const char** ptr, int len, + upb_EpsCopyInputStream_ParseDelimitedFunc* func, void* ctx) { + if (!upb_EpsCopyInputStream_CheckSubMessageSizeAvailable(e, *ptr, len)) { + return false; + } + + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = e->limit_ptr; + int saved_limit = e->limit; + e->limit_ptr = *ptr + len; + e->limit = e->limit_ptr - e->end; + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); + *ptr = func(e, *ptr, ctx); + e->limit_ptr = saved_limit_ptr; + e->limit = saved_limit; + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); + return true; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ + +#ifndef UPB_JSON_DECODE_H_ +#define UPB_JSON_DECODE_H_ + +#include + + +// Public APIs for message operations that do not depend on the schema. +// +// MiniTable-based accessors live in accessors.h. + +#ifndef UPB_MESSAGE_MESSAGE_H_ +#define UPB_MESSAGE_MESSAGE_H_ + +#include + + +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ +#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ + +#include +#include + + +#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ +#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ + +#include + + +// Users should include array.h or map.h instead. +// IWYU pragma: private, include "upb/message/array.h" + +#ifndef UPB_MESSAGE_VALUE_H_ +#define UPB_MESSAGE_VALUE_H_ + +#include +#include + +#ifndef UPB_BASE_STRING_VIEW_H_ +#define UPB_BASE_STRING_VIEW_H_ + +#include + +// Must be last. + +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } + +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data + +// LINT.IfChange(struct_definition) +typedef struct { + const char* data; + size_t size; +} upb_StringView; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} + +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} + +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return (a.size == b.size) && (!a.size || !memcmp(a.data, b.data, a.size)); +} + +// LINT.ThenChange( +// GoogleInternalName1, +// //depot/google3/third_party/upb/bits/golang/accessor.go:map_go_string, +// //depot/google3/third_party/upb/bits/typescript/string_view.ts +// ) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STRING_VIEW_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const struct upb_Array* array_val; + const struct upb_Map* map_val; + const struct upb_Message* msg_val; + upb_StringView str_val; + + // EXPERIMENTAL: A tagged upb_Message*. Users must use this instead of + // msg_val if unlinked sub-messages may possibly be in use. See the + // documentation in kUpb_DecodeOption_ExperimentalAllowUnlinked for more + // information. + uintptr_t tagged_msg_val; // upb_TaggedMessagePtr +} upb_MessageValue; + +UPB_API_INLINE upb_MessageValue upb_MessageValue_Zero(void) { + upb_MessageValue zero; + memset(&zero, 0, sizeof(zero)); + return zero; +} + +typedef union { + struct upb_Array* array; + struct upb_Map* map; + struct upb_Message* msg; +} upb_MutableMessageValue; + +UPB_API_INLINE upb_MutableMessageValue upb_MutableMessageValue_Zero(void) { + upb_MutableMessageValue zero; + memset(&zero, 0, sizeof(zero)); + return zero; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_VALUE_H_ */ + +#ifndef UPB_MINI_TABLE_EXTENSION_H_ +#define UPB_MINI_TABLE_EXTENSION_H_ + +#include + + +#ifndef UPB_BASE_DESCRIPTOR_CONSTANTS_H_ +#define UPB_BASE_DESCRIPTOR_CONSTANTS_H_ + +// Must be last. + +// The types a field can have. Note that this list is not identical to the +// types defined in descriptor.proto, which gives INT32 and SINT32 separate +// types (we distinguish the two with the "integer encoding" enum below). +// This enum is an internal convenience only and has no meaning outside of upb. +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, // Enum values are int32. TODO: rename + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; + +// The repeated-ness of each field; this matches descriptor.proto. +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; + +// Descriptor types, as defined in descriptor.proto. +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#ifdef __cplusplus +extern "C" { +#endif + +// Convert from upb_FieldType to upb_CType +UPB_INLINE upb_CType upb_FieldType_CType(upb_FieldType field_type) { + static const upb_CType c_type[] = { + kUpb_CType_Double, // kUpb_FieldType_Double + kUpb_CType_Float, // kUpb_FieldType_Float + kUpb_CType_Int64, // kUpb_FieldType_Int64 + kUpb_CType_UInt64, // kUpb_FieldType_UInt64 + kUpb_CType_Int32, // kUpb_FieldType_Int32 + kUpb_CType_UInt64, // kUpb_FieldType_Fixed64 + kUpb_CType_UInt32, // kUpb_FieldType_Fixed32 + kUpb_CType_Bool, // kUpb_FieldType_Bool + kUpb_CType_String, // kUpb_FieldType_String + kUpb_CType_Message, // kUpb_FieldType_Group + kUpb_CType_Message, // kUpb_FieldType_Message + kUpb_CType_Bytes, // kUpb_FieldType_Bytes + kUpb_CType_UInt32, // kUpb_FieldType_UInt32 + kUpb_CType_Enum, // kUpb_FieldType_Enum + kUpb_CType_Int32, // kUpb_FieldType_SFixed32 + kUpb_CType_Int64, // kUpb_FieldType_SFixed64 + kUpb_CType_Int32, // kUpb_FieldType_SInt32 + kUpb_CType_Int64, // kUpb_FieldType_SInt64 + }; + + // -1 here because the enum is one-based but the table is zero-based. + return c_type[field_type - 1]; +} + +UPB_INLINE bool upb_FieldType_IsPackable(upb_FieldType field_type) { + // clang-format off + const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << field_type) & ~kUnpackableTypes; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_DESCRIPTOR_CONSTANTS_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ +#define UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ + +#include +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_FIELD_H_ +#define UPB_MINI_TABLE_INTERNAL_FIELD_H_ + +#include +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ +#define UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Return the log2 of the storage size in bytes for a upb_CType +UPB_INLINE int UPB_PRIVATE(_upb_CType_SizeLg2)(upb_CType c_type) { + static const int8_t size[] = { + 0, // kUpb_CType_Bool + 2, // kUpb_CType_Float + 2, // kUpb_CType_Int32 + 2, // kUpb_CType_UInt32 + 2, // kUpb_CType_Enum + UPB_SIZE(2, 3), // kUpb_CType_Message + 3, // kUpb_CType_Double + 3, // kUpb_CType_Int64 + 3, // kUpb_CType_UInt64 + UPB_SIZE(3, 4), // kUpb_CType_String + UPB_SIZE(3, 4), // kUpb_CType_Bytes + }; + + // -1 here because the enum is one-based but the table is zero-based. + return size[c_type - 1]; +} + +// Return the log2 of the storage size in bytes for a upb_FieldType +UPB_INLINE int UPB_PRIVATE(_upb_FieldType_SizeLg2)(upb_FieldType field_type) { + static const int8_t size[] = { + 3, // kUpb_FieldType_Double + 2, // kUpb_FieldType_Float + 3, // kUpb_FieldType_Int64 + 3, // kUpb_FieldType_UInt64 + 2, // kUpb_FieldType_Int32 + 3, // kUpb_FieldType_Fixed64 + 2, // kUpb_FieldType_Fixed32 + 0, // kUpb_FieldType_Bool + UPB_SIZE(3, 4), // kUpb_FieldType_String + UPB_SIZE(2, 3), // kUpb_FieldType_Group + UPB_SIZE(2, 3), // kUpb_FieldType_Message + UPB_SIZE(3, 4), // kUpb_FieldType_Bytes + 2, // kUpb_FieldType_UInt32 + 2, // kUpb_FieldType_Enum + 2, // kUpb_FieldType_SFixed32 + 3, // kUpb_FieldType_SFixed64 + 2, // kUpb_FieldType_SInt32 + 3, // kUpb_FieldType_SInt64 + }; + + // -1 here because the enum is one-based but the table is zero-based. + return size[field_type - 1]; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ */ + +// Must be last. + +// LINT.IfChange(struct_definition) +struct upb_MiniTableField { + uint32_t UPB_ONLYBITS(number); + uint16_t UPB_ONLYBITS(offset); + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + + // Indexes into `upb_MiniTable.subs` + // Will be set to `kUpb_NoSub` if `descriptortype` != MESSAGE/GROUP/ENUM + uint16_t UPB_PRIVATE(submsg_index); + + uint8_t UPB_PRIVATE(descriptortype); + + // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift) + uint8_t UPB_ONLYBITS(mode); +}; + +#define kUpb_NoSub ((uint16_t) - 1) + +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} upb_FieldMode; + +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 + +// Extra flags on the mode field. +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, + // Indicates that this descriptor type is an "alternate type": + // - for Int32, this indicates that the actual type is Enum (but was + // rewritten to Int32 because it is an open enum that requires no check). + // - for Bytes, this indicates that the actual type is String (but does + // not require any UTF-8 check). + kUpb_LabelFlags_IsAlternate = 16, +} upb_LabelFlags; + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_8Byte = 3, + + kUpb_FieldRep_NativePointer = + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte), + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; + +#define kUpb_FieldRep_Shift 6 + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_FieldMode +UPB_PRIVATE(_upb_MiniTableField_Mode)(const struct upb_MiniTableField* f) { + return (upb_FieldMode)(f->UPB_ONLYBITS(mode) & kUpb_FieldMode_Mask); +} + +UPB_INLINE upb_FieldRep +UPB_PRIVATE(_upb_MiniTableField_GetRep)(const struct upb_MiniTableField* f) { + return (upb_FieldRep)(f->UPB_ONLYBITS(mode) >> kUpb_FieldRep_Shift); +} + +UPB_API_INLINE bool upb_MiniTableField_IsArray( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Array; +} + +UPB_API_INLINE bool upb_MiniTableField_IsMap( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Map; +} + +UPB_API_INLINE bool upb_MiniTableField_IsScalar( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Scalar; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_IsAlternate)( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsAlternate) != 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsExtension( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsExtension) != 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsPacked( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsPacked) != 0; +} + +UPB_API_INLINE upb_FieldType +upb_MiniTableField_Type(const struct upb_MiniTableField* f) { + const upb_FieldType type = (upb_FieldType)f->UPB_PRIVATE(descriptortype); + if (UPB_PRIVATE(_upb_MiniTableField_IsAlternate)(f)) { + if (type == kUpb_FieldType_Int32) return kUpb_FieldType_Enum; + if (type == kUpb_FieldType_Bytes) return kUpb_FieldType_String; + UPB_ASSERT(false); + } + return type; +} + +UPB_API_INLINE +upb_CType upb_MiniTableField_CType(const struct upb_MiniTableField* f) { + return upb_FieldType_CType(upb_MiniTableField_Type(f)); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_HasHasbit)( + const struct upb_MiniTableField* f) { + return f->presence > 0; +} + +UPB_INLINE char UPB_PRIVATE(_upb_MiniTableField_HasbitMask)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)); + const size_t index = f->presence; + return 1 << (index % 8); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)); + const size_t index = f->presence; + return index / 8; +} + +UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum( + const struct upb_MiniTableField* f) { + return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum; +} + +UPB_API_INLINE bool upb_MiniTableField_IsInOneof( + const struct upb_MiniTableField* f) { + return f->presence < 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsSubMessage( + const struct upb_MiniTableField* f) { + return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message || + f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group; +} + +UPB_API_INLINE bool upb_MiniTableField_HasPresence( + const struct upb_MiniTableField* f) { + if (upb_MiniTableField_IsExtension(f)) { + return upb_MiniTableField_IsScalar(f); + } else { + return f->presence != 0; + } +} + +UPB_API_INLINE uint32_t +upb_MiniTableField_Number(const struct upb_MiniTableField* f) { + return f->UPB_ONLYBITS(number); +} + +UPB_INLINE uint16_t +UPB_PRIVATE(_upb_MiniTableField_Offset)(const struct upb_MiniTableField* f) { + return f->UPB_ONLYBITS(offset); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_OneofOffset)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTableField_IsInOneof(f)); + return ~(ptrdiff_t)f->presence; +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)( + const struct upb_MiniTableField* f) { + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsArray(f)); + UPB_ASSUME(f->presence == 0); +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)( + const struct upb_MiniTableField* f) { + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsMap(f)); + UPB_ASSUME(f->presence == 0); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_ElemSizeLg2)( + const struct upb_MiniTableField* f) { + const upb_FieldType field_type = upb_MiniTableField_Type(f); + return UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type); +} + +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table_field.ts) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_FIELD_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_SUB_H_ +#define UPB_MINI_TABLE_INTERNAL_SUB_H_ + +// Must be last. + +typedef union { + const struct upb_MiniTable* const* UPB_PRIVATE(submsg); + const struct upb_MiniTableEnum* UPB_PRIVATE(subenum); +} upb_MiniTableSubInternal; + +union upb_MiniTableSub { + const struct upb_MiniTable* UPB_PRIVATE(submsg); + const struct upb_MiniTableEnum* UPB_PRIVATE(subenum); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromEnum( + const struct upb_MiniTableEnum* subenum) { + union upb_MiniTableSub out; + out.UPB_PRIVATE(subenum) = subenum; + return out; +} + +UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromMessage( + const struct upb_MiniTable* submsg) { + union upb_MiniTableSub out; + out.UPB_PRIVATE(submsg) = submsg; + return out; +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTableSub_Enum( + const union upb_MiniTableSub sub) { + return sub.UPB_PRIVATE(subenum); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableSub_Message( + const union upb_MiniTableSub sub) { + return sub.UPB_PRIVATE(submsg); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_SUB_H_ */ + +// Must be last. + +struct upb_MiniTableExtension { + // Do not move this field. We need to be able to alias pointers. + struct upb_MiniTableField UPB_PRIVATE(field); + + const struct upb_MiniTable* UPB_PRIVATE(extendee); + union upb_MiniTableSub UPB_PRIVATE(sub); // NULL unless submsg or proto2 enum +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType +upb_MiniTableExtension_CType(const struct upb_MiniTableExtension* e) { + return upb_MiniTableField_CType(&e->UPB_PRIVATE(field)); +} + +UPB_API_INLINE uint32_t +upb_MiniTableExtension_Number(const struct upb_MiniTableExtension* e) { + return e->UPB_PRIVATE(field).UPB_ONLYBITS(number); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableExtension_GetSubMessage( + const struct upb_MiniTableExtension* e) { + if (upb_MiniTableExtension_CType(e) != kUpb_CType_Message) { + return NULL; + } + return upb_MiniTableSub_Message(e->UPB_PRIVATE(sub)); +} + +UPB_API_INLINE void upb_MiniTableExtension_SetSubMessage( + struct upb_MiniTableExtension* e, const struct upb_MiniTable* m) { + e->UPB_PRIVATE(sub).UPB_PRIVATE(submsg) = m; +} + +UPB_INLINE upb_FieldRep UPB_PRIVATE(_upb_MiniTableExtension_GetRep)( + const struct upb_MiniTableExtension* e) { + return UPB_PRIVATE(_upb_MiniTableField_GetRep)(&e->UPB_PRIVATE(field)); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ */ + +#ifndef UPB_MINI_TABLE_MESSAGE_H_ +#define UPB_MINI_TABLE_MESSAGE_H_ + + +#ifndef UPB_MINI_TABLE_ENUM_H_ +#define UPB_MINI_TABLE_ENUM_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ +#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ + +#include + +// Must be last. + +struct upb_MiniTableEnum { + uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. + uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. + uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE bool upb_MiniTableEnum_CheckValue( + const struct upb_MiniTableEnum* e, uint32_t val) { + if (UPB_LIKELY(val < 64)) { + const uint64_t mask = + e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); + const uint64_t bit = 1ULL << val; + return (mask & bit) != 0; + } + if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { + const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; + const uint32_t bit = 1ULL << (val % 32); + return (mask & bit) != 0; + } + + // OPT: binary search long lists? + const uint32_t* start = + &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; + const uint32_t* limit = &e->UPB_PRIVATE( + data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ + +// Must be last + +typedef struct upb_MiniTableEnum upb_MiniTableEnum; + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates enum value against range defined by enum mini table. +UPB_API_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_ENUM_H_ */ + +#ifndef UPB_MINI_TABLE_FIELD_H_ +#define UPB_MINI_TABLE_FIELD_H_ + +#include + + +// Must be last. + +typedef struct upb_MiniTableField upb_MiniTableField; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType upb_MiniTableField_CType(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_HasPresence(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsArray(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum( + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsExtension(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsInOneof(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsMap(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsPacked(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsScalar(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsSubMessage( + const upb_MiniTableField* f); + +UPB_API_INLINE uint32_t upb_MiniTableField_Number(const upb_MiniTableField* f); + +UPB_API_INLINE upb_FieldType +upb_MiniTableField_Type(const upb_MiniTableField* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FIELD_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ +#define UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ + +#include +#include + + +// Must be last. + +struct upb_Decoder; +struct upb_Message; +typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, + struct upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data); +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; + +typedef enum { + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = + 3, // MessageSet item (temporary only, see decode.c) + + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, +} upb_ExtMode; + +// upb_MiniTable represents the memory layout of a given upb_MessageDef. +// The members are public so generated code can initialize them, +// but users MUST NOT directly read or write any of its members. + +// LINT.IfChange(minitable_struct_definition) +struct upb_MiniTable { + const upb_MiniTableSubInternal* UPB_PRIVATE(subs); + const struct upb_MiniTableField* UPB_ONLYBITS(fields); + + // Must be aligned to sizeof(void*). Doesn't include internal members like + // unknown fields, extension dict, pointer to msglayout, etc. + uint16_t UPB_PRIVATE(size); + + uint16_t UPB_ONLYBITS(field_count); + + uint8_t UPB_PRIVATE(ext); // upb_ExtMode, uint8_t here so sizeof(ext) == 1 + uint8_t UPB_PRIVATE(dense_below); + uint8_t UPB_PRIVATE(table_mask); + uint8_t UPB_PRIVATE(required_count); // Required fields have the low hasbits. + +#ifdef UPB_TRACING_ENABLED + const char* UPB_PRIVATE(full_name); +#endif + +#ifdef UPB_FASTTABLE_ENABLED + // To statically initialize the tables of variable length, we need a flexible + // array member, and we need to compile in gnu99 mode (constant initialization + // of flexible array members is a GNU extension, not in C99 unfortunately. + _upb_FastTable_Entry UPB_PRIVATE(fasttable)[]; +#endif +}; +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table.ts) + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE( + _upb_MiniTable_StrongReference)(const struct upb_MiniTable* mt) { +#if defined(__GNUC__) + __asm__("" : : "r"(mt)); +#else + const struct upb_MiniTable* volatile unused = mt; + (void)&unused; // Use address to avoid an extra load of "unused". +#endif + return mt; +} + +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(_upb_MiniTable_Empty)(void) { + extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty); + + return &UPB_PRIVATE(_kUpb_MiniTable_Empty); +} + +UPB_API_INLINE int upb_MiniTable_FieldCount(const struct upb_MiniTable* m) { + return m->UPB_ONLYBITS(field_count); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTable_IsEmpty)( + const struct upb_MiniTable* m) { + extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty); + + return m == &UPB_PRIVATE(_kUpb_MiniTable_Empty); +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_GetFieldByIndex( + const struct upb_MiniTable* m, uint32_t i) { + return &m->UPB_ONLYBITS(fields)[i]; +} + +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE( + _upb_MiniTable_GetSubTableByIndex)(const struct upb_MiniTable* m, + uint32_t i) { + return *m->UPB_PRIVATE(subs)[i].UPB_PRIVATE(submsg); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_SubMessage( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + if (upb_MiniTableField_CType(f) != kUpb_CType_Message) { + return NULL; + } + return UPB_PRIVATE(_upb_MiniTable_GetSubTableByIndex)( + m, f->UPB_PRIVATE(submsg_index)); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + const struct upb_MiniTable* ret = upb_MiniTable_SubMessage(m, f); + UPB_ASSUME(ret); + return UPB_PRIVATE(_upb_MiniTable_IsEmpty)(ret) ? NULL : ret; +} + +UPB_API_INLINE bool upb_MiniTable_FieldIsLinked( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + return upb_MiniTable_GetSubMessageTable(m, f) != NULL; +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_MapEntrySubMessage( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTable_FieldIsLinked(m, f)); // Map entries must be linked. + UPB_ASSERT(upb_MiniTableField_IsMap(f)); // Function precondition. + return upb_MiniTable_SubMessage(m, f); +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const struct upb_MiniTable* m, const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTableField_CType(f) == kUpb_CType_Enum); + return m->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)].UPB_PRIVATE( + subenum); +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapKey( + const struct upb_MiniTable* m) { + UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2); + const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 0); + UPB_ASSERT(upb_MiniTableField_Number(f) == 1); + return f; +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapValue( + const struct upb_MiniTable* m) { + UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2); + const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 1); + UPB_ASSERT(upb_MiniTableField_Number(f) == 2); + return f; +} + +// Computes a bitmask in which the |m->required_count| lowest bits are set. +// +// Sample output: +// RequiredMask(1) => 0b1 (0x1) +// RequiredMask(5) => 0b11111 (0x1f) +UPB_INLINE uint64_t +UPB_PRIVATE(_upb_MiniTable_RequiredMask)(const struct upb_MiniTable* m) { + int n = m->UPB_PRIVATE(required_count); + UPB_ASSERT(0 < n && n <= 64); + return (1ULL << n) - 1; +} + +#ifdef UPB_TRACING_ENABLED +UPB_INLINE const char* upb_MiniTable_FullName( + const struct upb_MiniTable* mini_table) { + return mini_table->UPB_PRIVATE(full_name); +} +// Initializes tracing proto name from language runtimes that construct +// mini tables dynamically at runtime. The runtime is responsible for passing +// controlling lifetime of name such as storing in same arena as mini_table. +UPB_INLINE void upb_MiniTable_SetFullName(struct upb_MiniTable* mini_table, + const char* full_name) { + mini_table->UPB_PRIVATE(full_name) = full_name; +} +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ */ + +// Must be last. + +typedef struct upb_MiniTable upb_MiniTable; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* m, uint32_t number); + +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_GetFieldByIndex( + const upb_MiniTable* m, uint32_t index); + +UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m); + +// DEPRECATED: use upb_MiniTable_SubMessage() instead +// Returns the MiniTable for a message field, NULL if the field is unlinked. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* m, const upb_MiniTableField* f); + +// Returns the MiniTable for a message field if it is a submessage, otherwise +// returns NULL. +// +// WARNING: if dynamic tree shaking is in use, the return value may be the +// "empty", zero-field placeholder message instead of the real message type. +// If the message is later linked, this function will begin returning the real +// message type. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage( + const upb_MiniTable* m, const upb_MiniTableField* f); + +// Returns the MiniTable for a map field. The given field must refer to a map. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_MapEntrySubMessage( + const upb_MiniTable* m, const upb_MiniTableField* f); + +// Returns the MiniTableEnum for a message field, NULL if the field is unlinked. +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* m, const upb_MiniTableField* f); + +// Returns the MiniTableField for the key of a map. +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapKey( + const upb_MiniTable* m); + +// Returns the MiniTableField for the value of a map. +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapValue( + const upb_MiniTable* m); + +// Returns true if this MiniTable field is linked to a MiniTable for the +// sub-message. +UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(const upb_MiniTable* m, + const upb_MiniTableField* f); + +// If this field is in a oneof, returns the first field in the oneof. +// +// Otherwise returns NULL. +// +// Usage: +// const upb_MiniTableField* field = upb_MiniTable_GetOneof(m, f); +// do { +// .. +// } while (upb_MiniTable_NextOneofField(m, &field); +// +const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m, + const upb_MiniTableField* f); + +// Iterates to the next field in the oneof. If this is the last field in the +// oneof, returns false. The ordering of fields in the oneof is not +// guaranteed. +// REQUIRES: |f| is the field initialized by upb_MiniTable_GetOneof and updated +// by prior upb_MiniTable_NextOneofField calls. +bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, + const upb_MiniTableField** f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_MESSAGE_H_ */ + +// Must be last. + +typedef struct upb_MiniTableExtension upb_MiniTableExtension; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType +upb_MiniTableExtension_CType(const upb_MiniTableExtension* e); + +UPB_API_INLINE uint32_t +upb_MiniTableExtension_Number(const upb_MiniTableExtension* e); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableExtension_GetSubMessage( + const upb_MiniTableExtension* e); + +UPB_API_INLINE void upb_MiniTableExtension_SetSubMessage( + upb_MiniTableExtension* e, const upb_MiniTable* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_EXTENSION_H_ */ + +// Must be last. + +// The internal representation of an extension is self-describing: it contains +// enough information that we can serialize it to binary format without needing +// to look it up in a upb_ExtensionRegistry. +// +// This representation allocates 16 bytes to data on 64-bit platforms. +// This is rather wasteful for scalars (in the extreme case of bool, +// it wastes 15 bytes). We accept this because we expect messages to be +// the most common extension type. +typedef struct { + const upb_MiniTableExtension* ext; + upb_MessageValue data; +} upb_Extension; + +#ifdef __cplusplus +extern "C" { +#endif + +// Adds the given extension data to the given message. +// |ext| is copied into the message instance. +// This logically replaces any previously-added extension with this number. +upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* ext, + upb_Arena* arena); + +// Returns an array of extensions for this message. +// Note: the array is ordered in reverse relative to the order of creation. +const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)( + const struct upb_Message* msg, size_t* count); + +// Returns an extension for a message with a given mini table, +// or NULL if no extension exists with this mini table. +const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( + const struct upb_Message* msg, const upb_MiniTableExtension* ext); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_EXTENSION_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; +extern const double kUpb_NaN; + +// Internal members of a upb_Message that track unknown fields and/or +// extensions. We can change this without breaking binary compatibility. + +typedef struct upb_Message_Internal { + // Total size of this structure, including the data that follows. + // Must be aligned to 8, which is alignof(upb_Extension) + uint32_t size; + + /* Offsets relative to the beginning of this structure. + * + * Unknown data grows forward from the beginning to unknown_end. + * Extension data grows backward from size to ext_begin. + * When the two meet, we're out of data and have to realloc. + * + * If we imagine that the final member of this struct is: + * char data[size - overhead]; // overhead = sizeof(upb_Message_Internal) + * + * Then we have: + * unknown data: data[0 .. (unknown_end - overhead)] + * extensions data: data[(ext_begin - overhead) .. (size - overhead)] */ + uint32_t unknown_end; + uint32_t ext_begin; + // Data follows, as if there were an array: + // char data[size - sizeof(upb_Message_Internal)]; +} upb_Message_Internal; + +#ifdef UPB_TRACING_ENABLED +UPB_API void upb_Message_LogNewMessage(const upb_MiniTable* m, + const upb_Arena* arena); +UPB_API void upb_Message_SetNewMessageTraceHandler( + void (*handler)(const upb_MiniTable*, const upb_Arena*)); +#endif // UPB_TRACING_ENABLED + +// Inline version upb_Message_New(), for internal use. +UPB_INLINE struct upb_Message* _upb_Message_New(const upb_MiniTable* m, + upb_Arena* a) { +#ifdef UPB_TRACING_ENABLED + upb_Message_LogNewMessage(m, a); +#endif // UPB_TRACING_ENABLED + + const int size = m->UPB_PRIVATE(size); + struct upb_Message* msg = (struct upb_Message*)upb_Arena_Malloc(a, size); + if (UPB_UNLIKELY(!msg)) return NULL; + memset(msg, 0, size); + return msg; +} + +// Discards the unknown fields for this message only. +void _upb_Message_DiscardUnknown_shallow(struct upb_Message* msg); + +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. +bool UPB_PRIVATE(_upb_Message_AddUnknown)(struct upb_Message* msg, + const char* data, size_t len, + upb_Arena* arena); + +bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need, + upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MESSAGE_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_TYPES_H_ +#define UPB_MESSAGE_INTERNAL_TYPES_H_ + +#include + +// Must be last. + +#define UPB_OPAQUE(x) x##_opaque + +struct upb_Message { + union { + uintptr_t UPB_OPAQUE(internal); // tagged pointer, low bit == frozen + double d; // Forces same size for 32-bit/64-bit builds + }; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void UPB_PRIVATE(_upb_Message_ShallowFreeze)( + struct upb_Message* msg) { + msg->UPB_OPAQUE(internal) |= 1ULL; +} + +UPB_API_INLINE bool upb_Message_IsFrozen(const struct upb_Message* msg) { + return (msg->UPB_OPAQUE(internal) & 1ULL) != 0; +} + +UPB_INLINE struct upb_Message_Internal* UPB_PRIVATE(_upb_Message_GetInternal)( + const struct upb_Message* msg) { + const uintptr_t tmp = msg->UPB_OPAQUE(internal) & ~1ULL; + return (struct upb_Message_Internal*)tmp; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetInternal)( + struct upb_Message* msg, struct upb_Message_Internal* internal) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + msg->UPB_OPAQUE(internal) = (uintptr_t)internal; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#undef UPB_OPAQUE + + +#endif /* UPB_MESSAGE_INTERNAL_TYPES_H_ */ + +// Must be last. + +typedef struct upb_Message upb_Message; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new message with the given mini_table on the given arena. +UPB_API upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* arena); + +// Returns a reference to the message's unknown data. +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); + +// Removes partial unknown data from message. +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); + +// Returns the number of extensions present in this message. +size_t upb_Message_ExtensionCount(const upb_Message* msg); + +// Mark a message and all of its descendents as frozen/immutable. +UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m); + +// Returns whether a message has been frozen. +UPB_API_INLINE bool upb_Message_IsFrozen(const upb_Message* msg); + +#ifdef UPB_TRACING_ENABLED +UPB_API void upb_Message_LogNewMessage(const upb_MiniTable* m, + const upb_Arena* arena); + +UPB_API void upb_Message_SetNewMessageTraceHandler( + void (*handler)(const upb_MiniTable* m, const upb_Arena* arena)); +#endif // UPB_TRACING_ENABLED + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MESSAGE_H_ */ + +#ifndef UPB_REFLECTION_DEF_H_ +#define UPB_REFLECTION_DEF_H_ + +// IWYU pragma: begin_exports + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_DEF_POOL_H_ +#define UPB_REFLECTION_DEF_POOL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +// Declarations common to all public def types. + +#ifndef UPB_REFLECTION_COMMON_H_ +#define UPB_REFLECTION_COMMON_H_ + +#ifndef THIRD_PARTY_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H_ +#define THIRD_PARTY_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H_ + +// IWYU pragma: begin_exports + +#if defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +// This header is checked in. +#elif UPB_BOOTSTRAP_STAGE == 1 +// This header is generated at build time by the bootstrapping process. +#else +// This is the normal header, generated by upb_c_proto_library(). +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ + + +#ifndef UPB_GENERATED_CODE_SUPPORT_H_ +#define UPB_GENERATED_CODE_SUPPORT_H_ + +// IWYU pragma: begin_exports + +#ifndef UPB_BASE_UPCAST_H_ +#define UPB_BASE_UPCAST_H_ + +// Must be last. + +// This macro provides a way to upcast message pointers in a way that is +// somewhat more bulletproof than blindly casting a pointer. Example: +// +// typedef struct { +// upb_Message UPB_PRIVATE(base); +// } pkg_FooMessage; +// +// void f(pkg_FooMessage* msg) { +// upb_Decode(UPB_UPCAST(msg), ...); +// } + +#define UPB_UPCAST(x) (&(x)->base##_dont_copy_me__upb_internal_use_only) + + +#endif /* UPB_BASE_UPCAST_H_ */ + +#ifndef UPB_MESSAGE_ACCESSORS_H_ +#define UPB_MESSAGE_ACCESSORS_H_ + +#include + + +#ifndef UPB_MESSAGE_ARRAY_H_ +#define UPB_MESSAGE_ARRAY_H_ + +#include + + +#ifndef UPB_MESSAGE_INTERNAL_ARRAY_H_ +#define UPB_MESSAGE_INTERNAL_ARRAY_H_ + +#include +#include + + +// Must be last. + +#define _UPB_ARRAY_MASK_IMM 0x4 // Frozen/immutable bit. +#define _UPB_ARRAY_MASK_LG2 0x3 // Encoded elem size. +#define _UPB_ARRAY_MASK_ALL (_UPB_ARRAY_MASK_IMM | _UPB_ARRAY_MASK_LG2) + +#ifdef __cplusplus +extern "C" { +#endif + +// LINT.IfChange(upb_Array) + +// Our internal representation for repeated fields. +struct upb_Array { + // This is a tagged pointer. Bits #0 and #1 encode the elem size as follows: + // 0 maps to elem size 1 + // 1 maps to elem size 4 + // 2 maps to elem size 8 + // 3 maps to elem size 16 + // + // Bit #2 contains the frozen/immutable flag. + uintptr_t UPB_ONLYBITS(data); + + size_t UPB_ONLYBITS(size); // The number of elements in the array. + size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements. +}; + +UPB_INLINE void UPB_PRIVATE(_upb_Array_ShallowFreeze)(struct upb_Array* arr) { + arr->UPB_ONLYBITS(data) |= _UPB_ARRAY_MASK_IMM; +} + +UPB_API_INLINE bool upb_Array_IsFrozen(const struct upb_Array* arr) { + return (arr->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_IMM) != 0; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array, + void* data, size_t lg2) { + UPB_ASSERT(lg2 != 1); + UPB_ASSERT(lg2 <= 4); + const size_t bits = lg2 - (lg2 != 0); + array->UPB_ONLYBITS(data) = (uintptr_t)data | bits; +} + +UPB_INLINE size_t +UPB_PRIVATE(_upb_Array_ElemSizeLg2)(const struct upb_Array* array) { + const size_t bits = array->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_LG2; + const size_t lg2 = bits + (bits != 0); + return lg2; +} + +UPB_API_INLINE const void* upb_Array_DataPtr(const struct upb_Array* array) { + UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); // Check assertions. + return (void*)(array->UPB_ONLYBITS(data) & ~(uintptr_t)_UPB_ARRAY_MASK_ALL); +} + +UPB_API_INLINE void* upb_Array_MutableDataPtr(struct upb_Array* array) { + return (void*)upb_Array_DataPtr(array); +} + +UPB_INLINE struct upb_Array* UPB_PRIVATE(_upb_Array_New)(upb_Arena* arena, + size_t init_capacity, + int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 != 1); + UPB_ASSERT(elem_size_lg2 <= 4); + const size_t array_size = + UPB_ALIGN_UP(sizeof(struct upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = array_size + (init_capacity << elem_size_lg2); + struct upb_Array* array = (struct upb_Array*)upb_Arena_Malloc(arena, bytes); + if (!array) return NULL; + UPB_PRIVATE(_upb_Array_SetTaggedPtr) + (array, UPB_PTR_AT(array, array_size, void), elem_size_lg2); + array->UPB_ONLYBITS(size) = 0; + array->UPB_PRIVATE(capacity) = init_capacity; + return array; +} + +// Resizes the capacity of the array to be at least min_size. +bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, size_t min_size, + upb_Arena* arena); + +UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, size_t size, + upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + if (array->UPB_PRIVATE(capacity) < size) + return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena); + return true; +} + +// Resize without initializing new elements. +UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + UPB_ASSERT(size <= array->UPB_ONLYBITS(size) || + arena); // Allow NULL arena when shrinking. + if (!upb_Array_Reserve(array, size, arena)) return false; + array->UPB_ONLYBITS(size) = size; + return true; +} + +// This function is intended for situations where elem_size is compile-time +// constant or a known expression of the form (1 << lg2), so that the expression +// i*elem_size does not result in an actual multiplication. +UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i, + const void* data, + size_t elem_size) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + UPB_ASSERT(i < array->UPB_ONLYBITS(size)); + UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array)); + char* arr_data = (char*)upb_Array_MutableDataPtr(array); + memcpy(arr_data + (i * elem_size), data, elem_size); +} + +UPB_API_INLINE size_t upb_Array_Size(const struct upb_Array* arr) { + return arr->UPB_ONLYBITS(size); +} + +// LINT.ThenChange(GoogleInternalName0) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#undef _UPB_ARRAY_MASK_IMM +#undef _UPB_ARRAY_MASK_LG2 +#undef _UPB_ARRAY_MASK_ALL + + +#endif /* UPB_MESSAGE_INTERNAL_ARRAY_H_ */ + +// Must be last. + +typedef struct upb_Array upb_Array; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new array on the given arena that holds elements of this type. +UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +// Returns the number of elements in the array. +UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr); + +// Returns the given element, which must be within the array's current size. +UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +// Returns a mutating pointer to the given element, which must be within the +// array's current size. +UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i); + +// Sets the given element, which must be within the array's current size. +UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +// Appends an element to the array. Returns false on allocation failure. +UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val, + upb_Arena* arena); + +// Moves elements within the array using memmove(). +// Like memmove(), the source and destination elements may be overlapping. +UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +// Inserts one or more empty elements into the array. +// Existing elements are shifted right. +// The new elements have undefined state and must be set with `upb_Array_Set()`. +// REQUIRES: `i <= upb_Array_Size(arr)` +UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +// Deletes one or more elements from the array. +// Existing elements are shifted left. +// REQUIRES: `i + count <= upb_Array_Size(arr)` +UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +// Reserves |size| elements of storage for the array. +UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, size_t size, + upb_Arena* arena); + +// Changes the size of a vector. New elements are initialized to NULL/0. +// Returns false on allocation failure. +UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +// Returns pointer to array data. +UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr); + +// Returns mutable pointer to array data. +UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr); + +// Mark an array and all of its descendents as frozen/immutable. +// If the array elements are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m); + +// Returns whether an array has been frozen. +UPB_API_INLINE bool upb_Array_IsFrozen(const upb_Array* arr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_ARRAY_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ +#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#include +#include +#include + + +#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ +#define UPB_BASE_INTERNAL_ENDIAN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool upb_IsLittleEndian(void) { + const int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { + if (upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { + if (upb_IsLittleEndian()) return val; + + const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; + const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); + return hi | lo; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_MAP_H_ +#define UPB_MESSAGE_INTERNAL_MAP_H_ + +#include +#include + + +#ifndef UPB_HASH_STR_TABLE_H_ +#define UPB_HASH_STR_TABLE_H_ + + +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ + +#ifndef UPB_HASH_COMMON_H_ +#define UPB_HASH_COMMON_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_value ******************************************************************/ + +typedef struct { + uint64_t val; +} upb_value; + +UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } + +/* For each value ctype, define the following set of functions: + * + * // Get/set an int32 from a upb_value. + * int32_t upb_value_getint32(upb_value val); + * void upb_value_setint32(upb_value *val, int32_t cval); + * + * // Construct a new upb_value from an int32. + * upb_value upb_value_int32(int32_t val); */ +#define FUNCS(name, membername, type_t, converter) \ + UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ + val->val = (converter)cval; \ + } \ + UPB_INLINE upb_value upb_value_##name(type_t val) { \ + upb_value ret; \ + upb_value_set##name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get##name(upb_value val) { \ + return (type_t)(converter)val.val; \ + } + +FUNCS(int32, int32, int32_t, int32_t) +FUNCS(int64, int64, int64_t, int64_t) +FUNCS(uint32, uint32, uint32_t, uint32_t) +FUNCS(uint64, uint64, uint64_t, uint64_t) +FUNCS(bool, _bool, bool, bool) +FUNCS(cstr, cstr, char*, uintptr_t) +FUNCS(uintptr, uptr, uintptr_t, uintptr_t) +FUNCS(ptr, ptr, void*, uintptr_t) +FUNCS(constptr, constptr, const void*, uintptr_t) + +#undef FUNCS + +UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { + memcpy(&val->val, &cval, sizeof(cval)); +} + +UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { + memcpy(&val->val, &cval, sizeof(cval)); +} + +UPB_INLINE upb_value upb_value_float(float cval) { + upb_value ret; + upb_value_setfloat(&ret, cval); + return ret; +} + +UPB_INLINE upb_value upb_value_double(double cval) { + upb_value ret; + upb_value_setdouble(&ret, cval); + return ret; +} + +/* upb_tabkey *****************************************************************/ + +/* Either: + * 1. an actual integer key, or + * 2. a pointer to a string prefixed by its uint32_t length, owned by us. + * + * ...depending on whether this is a string table or an int table. We would + * make this a union of those two types, but C89 doesn't support statically + * initializing a non-first union member. */ +typedef uintptr_t upb_tabkey; + +UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { + char* mem = (char*)key; + if (len) memcpy(len, mem, sizeof(*len)); + return mem + sizeof(*len); +} + +UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { + upb_StringView ret; + uint32_t len; + ret.data = upb_tabstr(key, &len); + ret.size = len; + return ret; +} + +/* upb_tabval *****************************************************************/ + +typedef struct upb_tabval { + uint64_t val; +} upb_tabval; + +#define UPB_TABVALUE_EMPTY_INIT \ + { -1 } + +/* upb_table ******************************************************************/ + +typedef struct _upb_tabent { + upb_tabkey key; + upb_tabval val; + + /* Internal chaining. This is const so we can create static initializers for + * tables. We cast away const sometimes, but *only* when the containing + * upb_table is known to be non-const. This requires a bit of care, but + * the subtlety is confined to table.c. */ + const struct _upb_tabent* next; +} upb_tabent; + +typedef struct { + size_t count; /* Number of entries in the hash part. */ + uint32_t mask; /* Mask to turn hash value -> bucket. */ + uint32_t max_count; /* Max count before we hit our load limit. */ + uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ + upb_tabent* entries; +} upb_table; + +UPB_INLINE size_t upb_table_size(const upb_table* t) { + return t->size_lg2 ? 1 << t->size_lg2 : 0; +} + +// Internal-only functions, in .h file only out of necessity. + +UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } + +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_COMMON_H_ */ + +// Must be last. + +typedef struct { + upb_table t; +} upb_strtable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); + +// Returns the number of values in the table. +UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { + return t->t.count; +} + +void upb_strtable_clear(upb_strtable* t); + +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. The key is not required +// to be NULL-terminated, and the table will make an internal copy of the key. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. */ +bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, + upb_value val, upb_Arena* a); + +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v); + +// For NULL-terminated strings. +UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_lookup2(t, key, strlen(key), v); +} + +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val); + +UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_remove2(t, key, strlen(key), v); +} + +// Exposed for testing only. +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); + +/* Iteration over strtable: + * + * intptr_t iter = UPB_STRTABLE_BEGIN; + * upb_StringView key; + * upb_value val; + * while (upb_strtable_next2(t, &key, &val, &iter)) { + * // ... + * } + */ + +#define UPB_STRTABLE_BEGIN -1 + +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter); +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); +void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v); + +/* DEPRECATED iterators, slated for removal. + * + * Iterators for string tables. We are subject to some kind of unusual + * design constraints: + * + * For high-level languages: + * - we must be able to guarantee that we don't crash or corrupt memory even if + * the program accesses an invalidated iterator. + * + * For C++11 range-based for: + * - iterators must be copyable + * - iterators must be comparable + * - it must be possible to construct an "end" value. + * + * Iteration order is undefined. + * + * Modifying the table invalidates iterators. upb_{str,int}table_done() is + * guaranteed to work even on an invalidated iterator, as long as the table it + * is iterating over has not been freed. Calling next() or accessing data from + * an invalidated iterator yields unspecified elements from the table, but it is + * guaranteed not to crash and to return real table elements (except when done() + * is true). */ +/* upb_strtable_iter **********************************************************/ + +/* upb_strtable_iter i; + * upb_strtable_begin(&i, t); + * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + * const char *key = upb_strtable_iter_key(&i); + * const upb_value val = upb_strtable_iter_value(&i); + * // ... + * } + */ + +typedef struct { + const upb_strtable* t; + size_t index; +} upb_strtable_iter; + +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; +} + +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); +void upb_strtable_next(upb_strtable_iter* i); +bool upb_strtable_done(const upb_strtable_iter* i); +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); +upb_value upb_strtable_iter_value(const upb_strtable_iter* i); +void upb_strtable_iter_setdone(upb_strtable_iter* i); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_STR_TABLE_H_ */ + +// Must be last. + +typedef enum { + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, +} upb_MapInsertStatus; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +struct upb_Map { + // Size of key and val, based on the map type. + // Strings are represented as '0' because they must be handled specially. + char key_size; + char val_size; + bool UPB_PRIVATE(is_frozen); + + upb_strtable table; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void UPB_PRIVATE(_upb_Map_ShallowFreeze)(struct upb_Map* map) { + map->UPB_PRIVATE(is_frozen) = true; +} + +UPB_API_INLINE bool upb_Map_IsFrozen(const struct upb_Map* map) { + return map->UPB_PRIVATE(is_frozen); +} + +// Converting between internal table representation and user values. +// +// _upb_map_tokey() and _upb_map_fromkey() are inverses. +// _upb_map_tovalue() and _upb_map_fromvalue() are inverses. +// +// These functions account for the fact that strings are treated differently +// from other types when stored in a map. + +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} + +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} + +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} + +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} + +UPB_INLINE void* _upb_map_next(const struct upb_Map* map, size_t* iter) { + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + if (upb_strtable_done(&it)) return NULL; + return (void*)str_tabent(&it); +} + +UPB_INLINE void _upb_Map_Clear(struct upb_Map* map) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + upb_strtable_clear(&map->table); +} + +UPB_INLINE bool _upb_Map_Delete(struct upb_Map* map, const void* key, + size_t key_size, upb_value* val) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->table, k.data, k.size, val); +} + +UPB_INLINE bool _upb_Map_Get(const struct upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval; + upb_StringView k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; +} + +UPB_INLINE upb_MapInsertStatus _upb_Map_Insert(struct upb_Map* map, + const void* key, size_t key_size, + void* val, size_t val_size, + upb_Arena* a) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + upb_StringView strkey = _upb_map_tokey(key, key_size); + upb_value tabval = {0}; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return kUpb_MapInsertStatus_OutOfMemory; + } + + // TODO: add overwrite operation to minimize number of lookups. + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? kUpb_MapInsertStatus_Replaced + : kUpb_MapInsertStatus_Inserted; +} + +UPB_INLINE size_t _upb_Map_Size(const struct upb_Map* map) { + return map->table.t.count; +} + +// Strings/bytes are special-cased in maps. +extern char _upb_Map_CTypeSizeTable[12]; + +UPB_INLINE size_t _upb_Map_CTypeSize(upb_CType ctype) { + return _upb_Map_CTypeSizeTable[ctype]; +} + +// Creates a new map on the given arena with this key/value type. +struct upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MAP_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_ +#define UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Internal-only because empty messages cannot be created by the user. +UPB_INLINE uintptr_t +UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(struct upb_Message* ptr, bool empty) { + UPB_ASSERT(((uintptr_t)ptr & 1) == 0); + return (uintptr_t)ptr | (empty ? 1 : 0); +} + +UPB_API_INLINE bool upb_TaggedMessagePtr_IsEmpty(uintptr_t ptr) { + return ptr & 1; +} + +UPB_INLINE struct upb_Message* UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)( + uintptr_t ptr) { + return (struct upb_Message*)(ptr & ~(uintptr_t)1); +} + +UPB_API_INLINE struct upb_Message* upb_TaggedMessagePtr_GetNonEmptyMessage( + uintptr_t ptr) { + UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(ptr)); + return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr); +} + +UPB_INLINE struct upb_Message* UPB_PRIVATE( + _upb_TaggedMessagePtr_GetEmptyMessage)(uintptr_t ptr) { + UPB_ASSERT(upb_TaggedMessagePtr_IsEmpty(ptr)); + return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_ */ + +// Must be last. + +#if defined(__GNUC__) && !defined(__clang__) +// GCC raises incorrect warnings in these functions. It thinks that we are +// overrunning buffers, but we carefully write the functions in this file to +// guarantee that this is impossible. GCC gets this wrong due it its failure +// to perform constant propagation as we expect: +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217 +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226 +// +// Unfortunately this also indicates that GCC is not optimizing away the +// switch() in cases where it should be, compromising the performance. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#if __GNUC__ >= 11 +#pragma GCC diagnostic ignored "-Wstringop-overread" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// LINT.IfChange(presence_logic) + +// Hasbit access /////////////////////////////////////////////////////////////// + +UPB_INLINE bool UPB_PRIVATE(_upb_Message_GetHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + return (*UPB_PTR_AT(msg, offset, const char) & mask) != 0; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + (*UPB_PTR_AT(msg, offset, char)) |= mask; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + (*UPB_PTR_AT(msg, offset, char)) &= ~mask; +} + +// Oneof case access /////////////////////////////////////////////////////////// + +UPB_INLINE uint32_t* UPB_PRIVATE(_upb_Message_OneofCasePtr)( + struct upb_Message* msg, const upb_MiniTableField* f) { + return UPB_PTR_AT(msg, UPB_PRIVATE(_upb_MiniTableField_OneofOffset)(f), + uint32_t); +} + +UPB_INLINE uint32_t UPB_PRIVATE(_upb_Message_GetOneofCase)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const uint32_t* ptr = + UPB_PRIVATE(_upb_Message_OneofCasePtr)((struct upb_Message*)msg, f); + + return *ptr; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetOneofCase)( + struct upb_Message* msg, const upb_MiniTableField* f) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + + *ptr = upb_MiniTableField_Number(f); +} + +// Returns true if the given field is the current oneof case. +// Does nothing if it is not the current oneof case. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_ClearOneofCase)( + struct upb_Message* msg, const upb_MiniTableField* f) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + + if (*ptr != upb_MiniTableField_Number(f)) return false; + *ptr = 0; + return true; +} + +UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( + const struct upb_Message* message, const upb_MiniTableField* oneof_field) { + UPB_ASSUME(upb_MiniTableField_IsInOneof(oneof_field)); + return UPB_PRIVATE(_upb_Message_GetOneofCase)(message, oneof_field); +} + +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const struct upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f) { + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return NULL; + } + return upb_MiniTable_FindFieldByNumber(m, field_number); +} + +// LINT.ThenChange(GoogleInternalName2) + +// Returns false if the message is missing any of its required fields. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_IsInitializedShallow)( + const struct upb_Message* msg, const upb_MiniTable* m) { + uint64_t bits; + memcpy(&bits, msg + 1, sizeof(bits)); + bits = upb_BigEndian64(bits); + return (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~bits) == 0; +} + +UPB_INLINE void* UPB_PRIVATE(_upb_Message_MutableDataPtr)( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (char*)msg + f->UPB_ONLYBITS(offset); +} + +UPB_INLINE const void* UPB_PRIVATE(_upb_Message_DataPtr)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + return (const char*)msg + f->UPB_ONLYBITS(offset); +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetPresence)( + struct upb_Message* msg, const upb_MiniTableField* f) { + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + UPB_PRIVATE(_upb_Message_SetHasbit)(msg, f); + } else if (upb_MiniTableField_IsInOneof(f)) { + UPB_PRIVATE(_upb_Message_SetOneofCase)(msg, f); + } +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_DataCopy)( + const upb_MiniTableField* f, void* to, const void* from) { + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: + memcpy(to, from, 1); + return; + case kUpb_FieldRep_4Byte: + memcpy(to, from, 4); + return; + case kUpb_FieldRep_8Byte: + memcpy(to, from, 8); + return; + case kUpb_FieldRep_StringView: { + memcpy(to, from, sizeof(upb_StringView)); + return; + } + } + UPB_UNREACHABLE(); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_DataEquals)( + const upb_MiniTableField* f, const void* a, const void* b) { + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: + return memcmp(a, b, 1) == 0; + case kUpb_FieldRep_4Byte: + return memcmp(a, b, 4) == 0; + case kUpb_FieldRep_8Byte: + return memcmp(a, b, 8) == 0; + case kUpb_FieldRep_StringView: { + const upb_StringView sa = *(const upb_StringView*)a; + const upb_StringView sb = *(const upb_StringView*)b; + return upb_StringView_IsEqual(sa, sb); + } + } + UPB_UNREACHABLE(); +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_DataClear)( + const upb_MiniTableField* f, void* val) { + const char zero[16] = {0}; + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, zero); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_DataIsZero)( + const upb_MiniTableField* f, const void* val) { + const char zero[16] = {0}; + return UPB_PRIVATE(_upb_MiniTableField_DataEquals)(f, val, zero); +} + +// Here we define universal getter/setter functions for message fields. +// These look very branchy and inefficient, but as long as the MiniTableField +// values are known at compile time, all the branches are optimized away and +// we are left with ideal code. This can happen either through through +// literals or UPB_ASSUME(): +// +// // Via struct literals. +// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { +// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; +// // All value in "field" are compile-time known. +// upb_Message_SetBaseField(msg, &field, &value); +// } +// +// // Via UPB_ASSUME(). +// UPB_INLINE bool upb_Message_SetBool(upb_Message* msg, +// const upb_MiniTableField* field, +// bool value, upb_Arena* a) { +// UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool); +// UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(field) == +// kUpb_FieldRep_1Byte); +// upb_Message_SetField(msg, field, &value, a); +// } +// +// As a result, we can use these universal getters/setters for *all* message +// accessors: generated code, MiniTable accessors, and reflection. The only +// exception is the binary encoder/decoder, which need to be a bit more clever +// about how they read/write the message data, for efficiency. +// +// These functions work on both extensions and non-extensions. If the field +// of a setter is known to be a non-extension, the arena may be NULL and the +// returned bool value may be ignored since it will always succeed. + +UPB_API_INLINE bool upb_Message_HasBaseField(const struct upb_Message* msg, + const upb_MiniTableField* field) { + UPB_ASSERT(upb_MiniTableField_HasPresence(field)); + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if (upb_MiniTableField_IsInOneof(field)) { + return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, field) == + upb_MiniTableField_Number(field); + } else { + return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, field); + } +} + +UPB_API_INLINE bool upb_Message_HasExtension(const struct upb_Message* msg, + const upb_MiniTableExtension* e) { + UPB_ASSERT(upb_MiniTableField_HasPresence(&e->UPB_PRIVATE(field))); + return UPB_PRIVATE(_upb_Message_Getext)(msg, e) != NULL; +} + +UPB_FORCEINLINE void _upb_Message_GetNonExtensionField( + const struct upb_Message* msg, const upb_MiniTableField* field, + const void* default_val, void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if ((upb_MiniTableField_IsInOneof(field) || + !UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(field, default_val)) && + !upb_Message_HasBaseField(msg, field)) { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(field, val, default_val); + return; + } + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (field, val, UPB_PRIVATE(_upb_Message_DataPtr)(msg, field)); +} + +UPB_INLINE void _upb_Message_GetExtensionField( + const struct upb_Message* msg, const upb_MiniTableExtension* mt_ext, + const void* default_val, void* val) { + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getext)(msg, mt_ext); + const upb_MiniTableField* f = &mt_ext->UPB_PRIVATE(field); + UPB_ASSUME(upb_MiniTableField_IsExtension(f)); + + if (ext) { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, &ext->data); + } else { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, default_val); + } +} + +// NOTE: The default_val is only used for fields that support presence. +// For repeated/map fields, the resulting upb_Array*/upb_Map* can be NULL if a +// upb_Array/upb_Map has not been allocated yet. Array/map fields do not have +// presence, so this is semantically identical to a pointer to an empty +// array/map, and must be treated the same for all semantic purposes. +UPB_API_INLINE upb_MessageValue upb_Message_GetField( + const struct upb_Message* msg, const upb_MiniTableField* field, + upb_MessageValue default_val) { + upb_MessageValue ret; + if (upb_MiniTableField_IsExtension(field)) { + _upb_Message_GetExtensionField(msg, (upb_MiniTableExtension*)field, + &default_val, &ret); + } else { + _upb_Message_GetNonExtensionField(msg, field, &default_val, &ret); + } + return ret; +} + +UPB_API_INLINE void upb_Message_SetBaseField(struct upb_Message* msg, + const upb_MiniTableField* f, + const void* val) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSUME(!upb_MiniTableField_IsExtension(f)); + UPB_PRIVATE(_upb_Message_SetPresence)(msg, f); + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (f, UPB_PRIVATE(_upb_Message_MutableDataPtr)(msg, f), val); +} + +UPB_API_INLINE bool upb_Message_SetExtension(struct upb_Message* msg, + const upb_MiniTableExtension* e, + const void* val, upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(a); + upb_Extension* ext = + UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, e, a); + if (!ext) return false; + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (&e->UPB_PRIVATE(field), &ext->data, val); + return true; +} + +// Sets the value of the given field in the given msg. The return value is true +// if the operation completed successfully, or false if memory allocation +// failed. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_SetField)(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_MessageValue val, + upb_Arena* a) { + if (upb_MiniTableField_IsExtension(f)) { + const upb_MiniTableExtension* ext = (const upb_MiniTableExtension*)f; + return upb_Message_SetExtension(msg, ext, &val, a); + } else { + upb_Message_SetBaseField(msg, f, &val); + return true; + } +} + +UPB_API_INLINE const upb_Array* upb_Message_GetArray( + const struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* ret; + const upb_Array* default_val = NULL; + _upb_Message_GetNonExtensionField(msg, f, &default_val, &ret); + return ret; +} + +UPB_API_INLINE bool upb_Message_GetBool(const struct upb_Message* msg, + const upb_MiniTableField* f, + bool default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Bool); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_1Byte); + upb_MessageValue def; + def.bool_val = default_val; + return upb_Message_GetField(msg, f, def).bool_val; +} + +UPB_API_INLINE double upb_Message_GetDouble(const struct upb_Message* msg, + const upb_MiniTableField* f, + double default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Double); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.double_val = default_val; + return upb_Message_GetField(msg, f, def).double_val; +} + +UPB_API_INLINE float upb_Message_GetFloat(const struct upb_Message* msg, + const upb_MiniTableField* f, + float default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Float); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.float_val = default_val; + return upb_Message_GetField(msg, f, def).float_val; +} + +UPB_API_INLINE int32_t upb_Message_GetInt32(const struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int32 || + upb_MiniTableField_CType(f) == kUpb_CType_Enum); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.int32_val = default_val; + return upb_Message_GetField(msg, f, def).int32_val; +} + +UPB_API_INLINE int64_t upb_Message_GetInt64(const struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.int64_val = default_val; + return upb_Message_GetField(msg, f, def).int64_val; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)( + const struct upb_Message* msg, const upb_MiniTableField* field) { + UPB_UNUSED(msg); + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field); +#ifndef NDEBUG + uintptr_t default_val = 0; + uintptr_t tagged; + _upb_Message_GetNonExtensionField(msg, field, &default_val, &tagged); + UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(tagged)); +#endif +} + +UPB_API_INLINE const struct upb_Map* upb_Message_GetMap( + const struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(f); + UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)(msg, f); + struct upb_Map* ret; + const struct upb_Map* default_val = NULL; + _upb_Message_GetNonExtensionField(msg, f, &default_val, &ret); + return ret; +} + +UPB_API_INLINE uintptr_t upb_Message_GetTaggedMessagePtr( + const struct upb_Message* msg, const upb_MiniTableField* f, + struct upb_Message* default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + uintptr_t tagged; + _upb_Message_GetNonExtensionField(msg, f, &default_val, &tagged); + return tagged; +} + +// For internal use only; users cannot set tagged messages because only the +// parser and the message copier are allowed to directly create an empty +// message. +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)( + struct upb_Message* msg, const upb_MiniTableField* f, + uintptr_t sub_message) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + upb_Message_SetBaseField(msg, f, &sub_message); +} + +UPB_API_INLINE const struct upb_Message* upb_Message_GetMessage( + const struct upb_Message* msg, const upb_MiniTableField* f) { + uintptr_t tagged = upb_Message_GetTaggedMessagePtr(msg, f, NULL); + return upb_TaggedMessagePtr_GetNonEmptyMessage(tagged); +} + +UPB_API_INLINE upb_Array* upb_Message_GetMutableArray( + struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + return (upb_Array*)upb_Message_GetArray(msg, f); +} + +UPB_API_INLINE struct upb_Map* upb_Message_GetMutableMap( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (struct upb_Map*)upb_Message_GetMap(msg, f); +} + +UPB_API_INLINE struct upb_Message* upb_Message_GetMutableMessage( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (struct upb_Message*)upb_Message_GetMessage(msg, f); +} + +UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray( + struct upb_Message* msg, const upb_MiniTableField* f, upb_Arena* arena) { + UPB_ASSERT(arena); + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* array = upb_Message_GetMutableArray(msg, f); + if (!array) { + array = UPB_PRIVATE(_upb_Array_New)( + arena, 4, UPB_PRIVATE(_upb_MiniTableField_ElemSizeLg2)(f)); + // Check again due to: https://godbolt.org/z/7WfaoKG1r + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_MessageValue val; + val.array_val = array; + UPB_PRIVATE(_upb_Message_SetField)(msg, f, val, arena); + } + return array; +} + +UPB_INLINE struct upb_Map* _upb_Message_GetOrCreateMutableMap( + struct upb_Message* msg, const upb_MiniTableField* field, size_t key_size, + size_t val_size, upb_Arena* arena) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field); + UPB_PRIVATE(_upb_Message_AssertMapIsUntagged)(msg, field); + struct upb_Map* map = NULL; + struct upb_Map* default_map_value = NULL; + _upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map); + if (!map) { + map = _upb_Map_New(arena, key_size, val_size); + // Check again due to: https://godbolt.org/z/7WfaoKG1r + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field); + upb_Message_SetBaseField(msg, field, &map); + } + return map; +} + +UPB_API_INLINE struct upb_Map* upb_Message_GetOrCreateMutableMap( + struct upb_Message* msg, const upb_MiniTable* map_entry_mini_table, + const upb_MiniTableField* f, upb_Arena* arena) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + const upb_MiniTableField* map_entry_key_field = + &map_entry_mini_table->UPB_ONLYBITS(fields)[0]; + const upb_MiniTableField* map_entry_value_field = + &map_entry_mini_table->UPB_ONLYBITS(fields)[1]; + return _upb_Message_GetOrCreateMutableMap( + msg, f, _upb_Map_CTypeSize(upb_MiniTableField_CType(map_entry_key_field)), + _upb_Map_CTypeSize(upb_MiniTableField_CType(map_entry_value_field)), + arena); +} + +UPB_API_INLINE struct upb_Message* upb_Message_GetOrCreateMutableMessage( + struct upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* f, upb_Arena* arena) { + UPB_ASSERT(arena); + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(!upb_MiniTableField_IsExtension(f)); + struct upb_Message* sub_message = + *UPB_PTR_AT(msg, f->UPB_ONLYBITS(offset), struct upb_Message*); + if (!sub_message) { + const upb_MiniTable* sub_mini_table = + upb_MiniTable_SubMessage(mini_table, f); + UPB_ASSERT(sub_mini_table); + sub_message = _upb_Message_New(sub_mini_table, arena); + *UPB_PTR_AT(msg, f->UPB_ONLYBITS(offset), struct upb_Message*) = + sub_message; + UPB_PRIVATE(_upb_Message_SetPresence)(msg, f); + } + return sub_message; +} + +UPB_API_INLINE upb_StringView +upb_Message_GetString(const struct upb_Message* msg, + const upb_MiniTableField* f, upb_StringView default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_String || + upb_MiniTableField_CType(f) == kUpb_CType_Bytes); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_StringView); + + upb_MessageValue def; + def.str_val = default_val; + return upb_Message_GetField(msg, f, def).str_val; +} + +UPB_API_INLINE uint32_t upb_Message_GetUInt32(const struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt32); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.uint32_val = default_val; + return upb_Message_GetField(msg, f, def).uint32_val; +} + +UPB_API_INLINE uint64_t upb_Message_GetUInt64(const struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.uint64_val = default_val; + return upb_Message_GetField(msg, f, def).uint64_val; +} + +// BaseField Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE void upb_Message_SetBaseFieldBool(struct upb_Message* msg, + const upb_MiniTableField* f, + bool value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Bool); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_1Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldDouble(struct upb_Message* msg, + const upb_MiniTableField* f, + double value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Double); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldFloat(struct upb_Message* msg, + const upb_MiniTableField* f, + float value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Float); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int32 || + upb_MiniTableField_CType(f) == kUpb_CType_Enum); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + struct upb_Message* value) { + UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr) + (msg, f, UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(value, false)); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldString(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_String || + upb_MiniTableField_CType(f) == kUpb_CType_Bytes); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_StringView); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt32); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetClosedEnum(struct upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f, + int32_t value) { + UPB_ASSERT(upb_MiniTableField_IsClosedEnum(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + UPB_ASSERT( + upb_MiniTableEnum_CheckValue(upb_MiniTable_GetSubEnumTable(m, f), value)); + upb_Message_SetBaseField(msg, f, &value); +} + +// Extension Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE bool upb_Message_SetExtensionBool( + struct upb_Message* msg, const upb_MiniTableExtension* e, bool value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Bool); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_1Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionDouble( + struct upb_Message* msg, const upb_MiniTableExtension* e, double value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Double); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionFloat( + struct upb_Message* msg, const upb_MiniTableExtension* e, float value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Float); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, int32_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int32 || + upb_MiniTableExtension_CType(e) == kUpb_CType_Enum); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, int64_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionString( + struct upb_Message* msg, const upb_MiniTableExtension* e, + upb_StringView value, upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_String || + upb_MiniTableExtension_CType(e) == kUpb_CType_Bytes); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_StringView); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionUInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint32_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt32); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_API_INLINE bool upb_Message_SetExtensionUInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint64_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +// Universal Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE bool upb_Message_SetBool(struct upb_Message* msg, + const upb_MiniTableField* f, bool value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionBool( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldBool(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetDouble(struct upb_Message* msg, + const upb_MiniTableField* f, + double value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionDouble( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldDouble(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetFloat(struct upb_Message* msg, + const upb_MiniTableField* f, + float value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionFloat( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldFloat(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionInt32( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldInt32(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionInt64( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldInt64(msg, f, value), true); +} + +// Sets the value of a message-typed field. The mini_tables of `msg` and +// `value` must have been linked for this to work correctly. +UPB_API_INLINE void upb_Message_SetMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + struct upb_Message* value) { + UPB_ASSERT(!upb_MiniTableField_IsExtension(f)); + upb_Message_SetBaseFieldMessage(msg, f, value); +} + +// Sets the value of a `string` or `bytes` field. The bytes of the value are not +// copied, so it is the caller's responsibility to ensure that they remain valid +// for the lifetime of `msg`. That might be done by copying them into the given +// arena, or by fusing that arena with the arena the bytes live in, for example. +UPB_API_INLINE bool upb_Message_SetString(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionString( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldString(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetUInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionUInt32( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldUInt32(msg, f, value), true); +} + +UPB_API_INLINE bool upb_Message_SetUInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value, upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionUInt64( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldUInt64(msg, f, value), true); +} + +UPB_API_INLINE void upb_Message_Clear(struct upb_Message* msg, + const upb_MiniTable* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + memset(msg, 0, m->UPB_PRIVATE(size)); + if (in) { + // Reset the internal buffer to empty. + in->unknown_end = sizeof(upb_Message_Internal); + in->ext_begin = in->size; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); + } +} + +UPB_API_INLINE void upb_Message_ClearBaseField(struct upb_Message* msg, + const upb_MiniTableField* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + UPB_PRIVATE(_upb_Message_ClearHasbit)(msg, f); + } else if (upb_MiniTableField_IsInOneof(f)) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + if (*ptr != upb_MiniTableField_Number(f)) return; + *ptr = 0; + } + const char zeros[16] = {0}; + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (f, UPB_PRIVATE(_upb_Message_MutableDataPtr)(msg, f), zeros); +} + +UPB_API_INLINE void upb_Message_ClearExtension( + struct upb_Message* msg, const upb_MiniTableExtension* e) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return; + const upb_Extension* base = UPB_PTR_AT(in, in->ext_begin, upb_Extension); + upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); + if (ext) { + *ext = *base; + in->ext_begin += sizeof(upb_Extension); + } +} + +UPB_API_INLINE void upb_Message_ClearOneof(struct upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return; + } + + const upb_MiniTableField* field = + upb_MiniTable_FindFieldByNumber(m, field_number); + upb_Message_ClearBaseField(msg, field); +} + +UPB_API_INLINE void* upb_Message_ResizeArrayUninitialized( + struct upb_Message* msg, const upb_MiniTableField* f, size_t size, + upb_Arena* arena) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, f, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena)) { + return NULL; + } + return upb_Array_MutableDataPtr(arr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + +#endif // UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#ifndef UPB_MESSAGE_MAP_H_ +#define UPB_MESSAGE_MAP_H_ + +#include + + +// Must be last. + +typedef struct upb_Map upb_Map; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new map on the given arena with the given key/value size. +UPB_API upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, + upb_CType value_type); + +// Returns the number of entries in the map. +UPB_API size_t upb_Map_Size(const upb_Map* map); + +// Stores a value for the given key into |*val| (or the zero value if the key is +// not present). Returns whether the key was present. The |val| pointer may be +// NULL, in which case the function tests whether the given key is present. +UPB_API bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +// Removes all entries in the map. +UPB_API void upb_Map_Clear(upb_Map* map); + +// Sets the given key to the given value, returning whether the key was inserted +// or replaced. If the key was inserted, then any existing iterators will be +// invalidated. +UPB_API upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, + upb_Arena* arena); + +// Sets the given key to the given value. Returns false if memory allocation +// failed. If the key is newly inserted, then any existing iterators will be +// invalidated. +UPB_API_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} + +// Deletes this key from the table. Returns true if the key was present. +// If present and |val| is non-NULL, stores the deleted value. +UPB_API bool upb_Map_Delete(upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +// Map iteration: +// +// size_t iter = kUpb_Map_Begin; +// upb_MessageValue key, val; +// while (upb_Map_Next(map, &key, &val, &iter)) { +// ... +// } + +#define kUpb_Map_Begin ((size_t) - 1) + +// Advances to the next entry. Returns false if no more entries are present. +// Otherwise returns true and populates both *key and *value. +UPB_API bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter); + +// Sets the value for the entry pointed to by iter. +// WARNING: this does not currently work for string values! +UPB_API void upb_Map_SetEntryValue(upb_Map* map, size_t iter, + upb_MessageValue val); + +// DEPRECATED iterator, slated for removal. + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * } + */ + +// Advances to the next entry. Returns false if no more entries are present. +UPB_API bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); + +// Returns true if the iterator still points to a valid entry, or false if the +// iterator is past the last element. It is an error to call this function with +// kUpb_Map_Begin (you must call next() at least once first). +UPB_API bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + +// Returns the key and value for this entry of the map. +UPB_API upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +UPB_API upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + +// Mark a map and all of its descendents as frozen/immutable. +// If the map values are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m); + +// Returns whether a map has been frozen. +UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MAP_H_ */ + +#ifndef UPB_MINI_TABLE_TAGGED_PTR_H_ +#define UPB_MINI_TABLE_TAGGED_PTR_H_ + +#include + + +// Must be last. + +// When a upb_Message* is stored in a message, array, or map, it is stored in a +// tagged form. If the tag bit is set, the referenced upb_Message is of type +// _kUpb_MiniTable_Empty (a sentinel message type with no fields) instead of +// that field's true message type. This forms the basis of what we call +// "dynamic tree shaking." +// +// See the documentation for kUpb_DecodeOption_ExperimentalAllowUnlinked for +// more information. + +typedef uintptr_t upb_TaggedMessagePtr; + +#ifdef __cplusplus +extern "C" { +#endif + +// Users who enable unlinked sub-messages must use this to test whether a +// message is empty before accessing it. If a message is empty, it must be +// first promoted using the interfaces in message/promote.h. +UPB_API_INLINE bool upb_TaggedMessagePtr_IsEmpty(upb_TaggedMessagePtr ptr); + +UPB_API_INLINE upb_Message* upb_TaggedMessagePtr_GetNonEmptyMessage( + upb_TaggedMessagePtr ptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_TAGGED_PTR_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Functions ending in BaseField() take a (upb_MiniTableField*) argument +// and work only on non-extension fields. +// +// Functions ending in Extension() take a (upb_MiniTableExtension*) argument +// and work only on extensions. + +UPB_API_INLINE void upb_Message_Clear(upb_Message* msg, const upb_MiniTable* m); + +UPB_API_INLINE void upb_Message_ClearBaseField(upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE void upb_Message_ClearExtension(upb_Message* msg, + const upb_MiniTableExtension* e); + +UPB_API_INLINE void upb_Message_ClearOneof(upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_HasBaseField(const upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_HasExtension(const upb_Message* msg, + const upb_MiniTableExtension* e); + +UPB_API_INLINE upb_MessageValue +upb_Message_GetField(const upb_Message* msg, const upb_MiniTableField* f, + upb_MessageValue default_val); + +UPB_API_INLINE upb_TaggedMessagePtr upb_Message_GetTaggedMessagePtr( + const upb_Message* msg, const upb_MiniTableField* field, + upb_Message* default_val); + +UPB_API_INLINE const upb_Array* upb_Message_GetArray( + const upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_GetBool(const upb_Message* msg, + const upb_MiniTableField* f, + bool default_val); + +UPB_API_INLINE double upb_Message_GetDouble(const upb_Message* msg, + const upb_MiniTableField* field, + double default_val); + +UPB_API_INLINE float upb_Message_GetFloat(const upb_Message* msg, + const upb_MiniTableField* f, + float default_val); + +UPB_API_INLINE int32_t upb_Message_GetInt32(const upb_Message* msg, + const upb_MiniTableField* f, + int32_t default_val); + +UPB_API_INLINE int64_t upb_Message_GetInt64(const upb_Message* msg, + const upb_MiniTableField* f, + int64_t default_val); + +UPB_API_INLINE const upb_Map* upb_Message_GetMap(const upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE const upb_Message* upb_Message_GetMessage( + const upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE upb_Array* upb_Message_GetMutableArray( + upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE upb_Map* upb_Message_GetMutableMap(upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE upb_Message* upb_Message_GetMutableMessage( + upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray( + upb_Message* msg, const upb_MiniTableField* f, upb_Arena* arena); + +UPB_API_INLINE upb_Map* upb_Message_GetOrCreateMutableMap( + upb_Message* msg, const upb_MiniTable* map_entry_mini_table, + const upb_MiniTableField* f, upb_Arena* arena); + +UPB_API_INLINE upb_Message* upb_Message_GetOrCreateMutableMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* f, upb_Arena* arena); + +UPB_API_INLINE upb_StringView +upb_Message_GetString(const upb_Message* msg, const upb_MiniTableField* field, + upb_StringView default_val); + +UPB_API_INLINE uint32_t upb_Message_GetUInt32(const upb_Message* msg, + const upb_MiniTableField* f, + uint32_t default_val); + +UPB_API_INLINE uint64_t upb_Message_GetUInt64(const upb_Message* msg, + const upb_MiniTableField* f, + uint64_t default_val); + +UPB_API_INLINE void upb_Message_SetClosedEnum( + upb_Message* msg, const upb_MiniTable* msg_mini_table, + const upb_MiniTableField* f, int32_t value); + +// BaseField Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE void upb_Message_SetBaseField(upb_Message* msg, + const upb_MiniTableField* f, + const void* val); + +UPB_API_INLINE void upb_Message_SetBaseFieldBool(struct upb_Message* msg, + const upb_MiniTableField* f, + bool value); + +UPB_API_INLINE void upb_Message_SetBaseFieldDouble(struct upb_Message* msg, + const upb_MiniTableField* f, + double value); + +UPB_API_INLINE void upb_Message_SetBaseFieldFloat(struct upb_Message* msg, + const upb_MiniTableField* f, + float value); + +UPB_API_INLINE void upb_Message_SetBaseFieldInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_Message* value); + +UPB_API_INLINE void upb_Message_SetBaseFieldString(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value); + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value); + +// Extension Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE bool upb_Message_SetExtension(upb_Message* msg, + const upb_MiniTableExtension* e, + const void* value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionBool( + struct upb_Message* msg, const upb_MiniTableExtension* e, bool value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionDouble( + struct upb_Message* msg, const upb_MiniTableExtension* e, double value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionFloat( + struct upb_Message* msg, const upb_MiniTableExtension* e, float value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, int32_t value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, int64_t value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionString( + struct upb_Message* msg, const upb_MiniTableExtension* e, + upb_StringView value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionUInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint32_t value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetExtensionUInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint64_t value, + upb_Arena* a); + +// Universal Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE bool upb_Message_SetBool(upb_Message* msg, + const upb_MiniTableField* f, bool value, + upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetDouble(upb_Message* msg, + const upb_MiniTableField* f, + double value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetFloat(upb_Message* msg, + const upb_MiniTableField* f, + float value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetInt32(upb_Message* msg, + const upb_MiniTableField* f, + int32_t value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetInt64(upb_Message* msg, + const upb_MiniTableField* f, + int64_t value, upb_Arena* a); + +// Unlike the other similarly-named setters, this function can only be +// called on base fields. Prefer upb_Message_SetBaseFieldMessage(). +UPB_API_INLINE void upb_Message_SetMessage(upb_Message* msg, + const upb_MiniTableField* f, + upb_Message* value); + +UPB_API_INLINE bool upb_Message_SetString(upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetUInt32(upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value, upb_Arena* a); + +UPB_API_INLINE bool upb_Message_SetUInt64(upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value, upb_Arena* a); + +//////////////////////////////////////////////////////////////////////////////// + +UPB_API_INLINE void* upb_Message_ResizeArrayUninitialized( + upb_Message* msg, const upb_MiniTableField* f, size_t size, + upb_Arena* arena); + +UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( + const upb_Message* message, const upb_MiniTableField* oneof_field); + +// For a field `f` which is in a oneof, return the field of that +// oneof that is actually set (or NULL if none). +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f); + +// Updates a map entry given an entry message. +bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* map_entry_message, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_ACCESSORS_H_ + +// These functions are only used by generated code. + +#ifndef UPB_MESSAGE_MAP_GENCODE_UTIL_H_ +#define UPB_MESSAGE_MAP_GENCODE_UTIL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Message map operations, these get the map from the message first. + +UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + uint32_t u32len; + upb_StringView k; + k.data = upb_tabstr(ent->key, &u32len); + k.size = u32len; + _upb_map_fromkey(k, key, size); +} + +UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + upb_value v = {ent->val.val}; + _upb_map_fromvalue(v, val, size); +} + +UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, + size_t size) { + upb_tabent* ent = (upb_tabent*)msg; + // This is like _upb_map_tovalue() except the entry already exists + // so we can reuse the allocated upb_StringView for string fields. + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; + memcpy(strp, val, sizeof(*strp)); + } else { + memcpy(&ent->val.val, val, size); + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MAP_GENCODE_UTIL_H_ */ + +#ifndef UPB_MINI_TABLE_DECODE_H_ +#define UPB_MINI_TABLE_DECODE_H_ + + +#ifndef UPB_MINI_TABLE_SUB_H_ +#define UPB_MINI_TABLE_SUB_H_ + + +// Must be last. + +typedef union upb_MiniTableSub upb_MiniTableSub; + +#ifdef __cplusplus +extern "C" { +#endif + +// Constructors + +UPB_API_INLINE upb_MiniTableSub +upb_MiniTableSub_FromEnum(const upb_MiniTableEnum* subenum); + +UPB_API_INLINE upb_MiniTableSub +upb_MiniTableSub_FromMessage(const upb_MiniTable* submsg); + +// Getters + +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTableSub_Enum( + upb_MiniTableSub sub); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableSub_Message( + upb_MiniTableSub sub); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_SUB_H_ */ + +// Export the newer headers, for legacy users. New users should include the +// more specific headers directly. +// IWYU pragma: begin_exports + +#ifndef UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ +#define UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Builds a upb_MiniTableEnum from an enum mini descriptor. +// The mini descriptor must be for an enum, not a message. +UPB_API upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ + +// Functions for linking MiniTables together once they are built from a +// MiniDescriptor. +// +// These functions have names like upb_MiniTable_Link() because they operate on +// MiniTables. We put them here, rather than in the mini_table/ directory, +// because they are only needed when building MiniTables from MiniDescriptors. +// The interfaces in mini_table/ assume that MiniTables are immutable. + +#ifndef UPB_MINI_DESCRIPTOR_LINK_H_ +#define UPB_MINI_DESCRIPTOR_LINK_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Links a sub-message field to a MiniTable for that sub-message. If a +// sub-message field is not linked, it will be treated as an unknown field +// during parsing, and setting the field will not be allowed. It is possible +// to link the message field later, at which point it will no longer be treated +// as unknown. However there is no synchronization for this operation, which +// means parallel mutation requires external synchronization. +// Returns success/failure. +UPB_API bool upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTableField* field, + const upb_MiniTable* sub); + +// Links an enum field to a MiniTable for that enum. +// All enum fields must be linked prior to parsing. +// Returns success/failure. +UPB_API bool upb_MiniTable_SetSubEnum(upb_MiniTable* table, + upb_MiniTableField* field, + const upb_MiniTableEnum* sub); + +// Returns a list of fields that require linking at runtime, to connect the +// MiniTable to its sub-messages and sub-enums. The list of fields will be +// written to the `subs` array, which must have been allocated by the caller +// and must be large enough to hold a list of all fields in the message. +// +// The order of the fields returned by this function is significant: it matches +// the order expected by upb_MiniTable_Link() below. +// +// The return value packs the sub-message count and sub-enum count into a single +// integer like so: +// return (msg_count << 16) | enum_count; +UPB_API uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* mt, + const upb_MiniTableField** subs); + +// Links a message to its sub-messages and sub-enums. The caller must pass +// arrays of sub-tables and sub-enums, in the same length and order as is +// returned by upb_MiniTable_GetSubList() above. However, individual elements +// of the sub_tables may be NULL if those sub-messages were tree shaken. +// +// Returns false if either array is too short, or if any of the tables fails +// to link. +UPB_API bool upb_MiniTable_Link(upb_MiniTable* mt, + const upb_MiniTable** sub_tables, + size_t sub_table_count, + const upb_MiniTableEnum** sub_enums, + size_t sub_enum_count); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_LINK_H_ +// IWYU pragma: end_exports + +// Must be last. + +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +#ifdef __cplusplus +extern "C" { +#endif + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); + +UPB_API_INLINE upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + return _upb_MiniTable_Build(data, len, kUpb_MiniTablePlatform_Native, arena, + status); +} + +// Initializes a MiniTableExtension buffer that has already been allocated. +// This is needed by upb_FileDef and upb_MessageDef, which allocate all of the +// extensions together in a single contiguous array. +const char* _upb_MiniTableExtension_Init(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status); + +UPB_API_INLINE const char* upb_MiniTableExtension_Init( + const char* data, size_t len, upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, upb_MiniTableSub sub, upb_Status* status) { + return _upb_MiniTableExtension_Init(data, len, ext, extendee, sub, + kUpb_MiniTablePlatform_Native, status); +} + +UPB_API upb_MiniTableExtension* _upb_MiniTableExtension_Build( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTableSub sub, upb_MiniTablePlatform platform, upb_Arena* arena, + upb_Status* status); + +UPB_API_INLINE upb_MiniTableExtension* upb_MiniTableExtension_Build( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_Arena* arena, upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromMessage(NULL); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +UPB_API_INLINE upb_MiniTableExtension* upb_MiniTableExtension_BuildMessage( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTable* submsg, upb_Arena* arena, upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromMessage(submsg); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +UPB_API_INLINE upb_MiniTableExtension* upb_MiniTableExtension_BuildEnum( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTableEnum* subenum, upb_Arena* arena, upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromEnum(subenum); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_DECODE_H_ */ + +#ifndef UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ +#define UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; + +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +UPB_API upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); + +UPB_API bool upb_ExtensionRegistry_Add(upb_ExtensionRegistry* r, + const upb_MiniTableExtension* e); + +// Adds the given extension info for the array |e| of size |count| into the +// registry. If there are any errors, the entire array is backed out. +// The extensions must outlive the registry. +// Possible errors include OOM or an extension number that already exists. +// TODO: There is currently no way to know the exact reason for failure. +bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, + const upb_MiniTableExtension** e, + size_t count); + +#ifdef UPB_LINKARR_DECLARE + +// Adds all extensions linked into the binary into the registry. The set of +// linked extensions is assembled by the linker using linker arrays. This +// will likely not work properly if the extensions are split across multiple +// shared libraries. +// +// Returns true if all extensions were added successfully, false on out of +// memory or if any extensions were already present. +// +// This API is currently not available on MSVC (though it *is* available on +// Windows using clang-cl). +UPB_API bool upb_ExtensionRegistry_AddAllLinkedExtensions( + upb_ExtensionRegistry* r); + +#endif // UPB_LINKARR_DECLARE + +// Looks up the extension (if any) defined for message type |t| and field +// number |num|. Returns the extension if found, otherwise NULL. +UPB_API const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ */ + +#ifndef UPB_MINI_TABLE_FILE_H_ +#define UPB_MINI_TABLE_FILE_H_ + + +#ifndef UPB_MINI_TABLE_INTERNAL_FILE_H_ +#define UPB_MINI_TABLE_INTERNAL_FILE_H_ + +// Must be last. + +struct upb_MiniTableFile { + const struct upb_MiniTable** UPB_PRIVATE(msgs); + const struct upb_MiniTableEnum** UPB_PRIVATE(enums); + const struct upb_MiniTableExtension** UPB_PRIVATE(exts); + int UPB_PRIVATE(msg_count); + int UPB_PRIVATE(enum_count); + int UPB_PRIVATE(ext_count); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE int upb_MiniTableFile_EnumCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(enum_count); +} + +UPB_API_INLINE int upb_MiniTableFile_ExtensionCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(ext_count); +} + +UPB_API_INLINE int upb_MiniTableFile_MessageCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(msg_count); +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTableFile_Enum( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(enum_count)); + return f->UPB_PRIVATE(enums)[i]; +} + +UPB_API_INLINE const struct upb_MiniTableExtension* upb_MiniTableFile_Extension( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(ext_count)); + return f->UPB_PRIVATE(exts)[i]; +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableFile_Message( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(msg_count)); + return f->UPB_PRIVATE(msgs)[i]; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_FILE_H_ */ + +// Must be last. + +typedef struct upb_MiniTableFile upb_MiniTableFile; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTableFile_Enum( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_EnumCount(const upb_MiniTableFile* f); + +UPB_API_INLINE const upb_MiniTableExtension* upb_MiniTableFile_Extension( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_ExtensionCount(const upb_MiniTableFile* f); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableFile_Message( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_MessageCount(const upb_MiniTableFile* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FILE_H_ */ + +// upb_decode: parsing into a upb_Message using a upb_MiniTable. + +#ifndef UPB_WIRE_DECODE_H_ +#define UPB_WIRE_DECODE_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + kUpb_DecodeOption_AliasString = 1, + + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implementing ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, + + /* EXPERIMENTAL: + * + * If set, the parser will allow parsing of sub-message fields that were not + * previously linked using upb_MiniTable_SetSubMessage(). The data will be + * parsed into an internal "empty" message type that cannot be accessed + * directly, but can be later promoted into the true message type if the + * sub-message fields are linked at a later time. + * + * Users should set this option if they intend to perform dynamic tree shaking + * and promoting using the interfaces in message/promote.h. If this option is + * enabled, it is important that the resulting messages are only accessed by + * code that is aware of promotion rules: + * + * 1. Message pointers in upb_Message, upb_Array, and upb_Map are represented + * by a tagged pointer upb_TaggedMessagePointer. The tag indicates whether + * the message uses the internal "empty" type. + * + * 2. Any code *reading* these message pointers must test whether the "empty" + * tag bit is set, using the interfaces in mini_table/types.h. However + * writing of message pointers should always use plain upb_Message*, since + * users are not allowed to create "empty" messages. + * + * 3. It is always safe to test whether a field is present or test the array + * length; these interfaces will reflect that empty messages are present, + * even though their data cannot be accessed without promoting first. + * + * 4. If a message pointer is indeed tagged as empty, the message may not be + * accessed directly, only promoted through the interfaces in + * message/promote.h. + * + * 5. Tagged/empty messages may never be created by the user. They may only + * be created by the parser or the message-copying logic in message/copy.h. + */ + kUpb_DecodeOption_ExperimentalAllowUnlinked = 4, + + /* EXPERIMENTAL: + * + * If set, decoding will enforce UTF-8 validation for string fields, even for + * proto2 or fields with `features.utf8_validation = NONE`. Normally, only + * proto3 string fields will be validated for UTF-8. Decoding will return + * kUpb_DecodeStatus_BadUtf8 for non-UTF-8 strings, which is the same behavior + * as non-UTF-8 proto3 string fields. + */ + kUpb_DecodeOption_AlwaysValidateUtf8 = 8, +}; + +UPB_INLINE uint32_t upb_DecodeOptions_MaxDepth(uint16_t depth) { + return (uint32_t)depth << 16; +} + +UPB_INLINE uint16_t upb_DecodeOptions_GetMaxDepth(uint32_t options) { + return options >> 16; +} + +// Enforce an upper bound on recursion depth. +UPB_INLINE int upb_Decode_LimitDepth(uint32_t decode_options, uint32_t limit) { + uint32_t max_depth = upb_DecodeOptions_GetMaxDepth(decode_options); + if (max_depth > limit) max_depth = limit; + return upb_DecodeOptions_MaxDepth(max_depth) | (decode_options & 0xffff); +} + +// LINT.IfChange +typedef enum { + kUpb_DecodeStatus_Ok = 0, + kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt + kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed + kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 + kUpb_DecodeStatus_MaxDepthExceeded = + 4, // Exceeded upb_DecodeOptions_MaxDepth + + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 5, + + // Unlinked sub-message field was present, but + // kUpb_DecodeOptions_ExperimentalAllowUnlinked was not specified in the list + // of options. + kUpb_DecodeStatus_UnlinkedSubMessage = 6, +} upb_DecodeStatus; +// LINT.ThenChange(//depot/google3/third_party/protobuf/rust/upb.rs:decode_status) + +UPB_API upb_DecodeStatus upb_Decode(const char* buf, size_t size, + upb_Message* msg, const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena); + +// Same as upb_Decode but with a varint-encoded length prepended. +// On success 'num_bytes_read' will be set to the how many bytes were read, +// on failure the contents of num_bytes_read is undefined. +UPB_API upb_DecodeStatus upb_DecodeLengthPrefixed( + const char* buf, size_t size, upb_Message* msg, size_t* num_bytes_read, + const upb_MiniTable* mt, const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); + +// Utility function for wrapper languages to get an error string from a +// upb_DecodeStatus. +UPB_API const char* upb_DecodeStatus_String(upb_DecodeStatus status); +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_DECODE_H_ */ + +// upb_Encode: parsing from a upb_Message using a upb_MiniTable. + +#ifndef UPB_WIRE_ENCODE_H_ +#define UPB_WIRE_ENCODE_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_EncodeOption_Deterministic = 1, + + // When set, unknown fields are not encoded. + kUpb_EncodeOption_SkipUnknown = 2, + + // When set, the encode will fail if any required fields are missing. + kUpb_EncodeOption_CheckRequired = 4, +}; + +// LINT.IfChange +typedef enum { + kUpb_EncodeStatus_Ok = 0, + kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed + kUpb_EncodeStatus_MaxDepthExceeded = 2, + + // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded. + kUpb_EncodeStatus_MissingRequired = 3, +} upb_EncodeStatus; +// LINT.ThenChange(//depot/google3/third_party/protobuf/rust/upb.rs:encode_status) + +UPB_INLINE uint32_t upb_EncodeOptions_MaxDepth(uint16_t depth) { + return (uint32_t)depth << 16; +} + +UPB_INLINE uint16_t upb_EncodeOptions_GetMaxDepth(uint32_t options) { + return options >> 16; +} + +// Enforce an upper bound on recursion depth. +UPB_INLINE int upb_Encode_LimitDepth(uint32_t encode_options, uint32_t limit) { + uint32_t max_depth = upb_EncodeOptions_GetMaxDepth(encode_options); + if (max_depth > limit) max_depth = limit; + return upb_EncodeOptions_MaxDepth(max_depth) | (encode_options & 0xffff); +} + +UPB_API upb_EncodeStatus upb_Encode(const upb_Message* msg, + const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, size_t* size); + +// Encodes the message prepended by a varint of the serialized length. +UPB_API upb_EncodeStatus upb_EncodeLengthPrefixed(const upb_Message* msg, + const upb_MiniTable* l, + int options, upb_Arena* arena, + char** buf, size_t* size); +// Utility function for wrapper languages to get an error string from a +// upb_EncodeStatus. +UPB_API const char* upb_EncodeStatus_String(upb_EncodeStatus status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_ENCODE_H_ */ + +// These are the specialized field parser functions for the fast parser. +// Generated tables will refer to these by name. +// +// The function names are encoded with names like: +// +// // 123 4 +// upb_pss_1bt(); // Parse singular string, 1 byte tag. +// +// In position 1: +// - 'p' for parse, most function use this +// - 'c' for copy, for when we are copying strings instead of aliasing +// +// In position 2 (cardinality): +// - 's' for singular, with or without hasbit +// - 'o' for oneof +// - 'r' for non-packed repeated +// - 'p' for packed repeated +// +// In position 3 (type): +// - 'b1' for bool +// - 'v4' for 4-byte varint +// - 'v8' for 8-byte varint +// - 'z4' for zig-zag-encoded 4-byte varint +// - 'z8' for zig-zag-encoded 8-byte varint +// - 'f4' for 4-byte fixed +// - 'f8' for 8-byte fixed +// - 'm' for sub-message +// - 's' for string (validate UTF-8) +// - 'b' for bytes +// +// In position 4 (tag length): +// - '1' for one-byte tags (field numbers 1-15) +// - '2' for two-byte tags (field numbers 16-2048) + +#ifndef UPB_WIRE_INTERNAL_DECODE_FAST_H_ +#define UPB_WIRE_INTERNAL_DECODE_FAST_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_Decoder; + +// The fallback, generic parsing function that can handle any field type. +// This just uses the regular (non-fast) parser to parse a single field. +const char* _upb_FastDecoder_DecodeGeneric(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data); + +#define UPB_PARSE_PARAMS \ + struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +/* primitive fields ***********************************************************/ + +#define F(card, type, valbytes, tagbytes) \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) \ + F(card, f, 4, tagbytes) \ + F(card, f, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES + +/* string fields **************************************************************/ + +#define F(card, tagbytes, type) \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef F +#undef UTF8 +#undef TAGBYTES + +/* sub-message fields *********************************************************/ + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef F +#undef SIZES +#undef TAGBYTES + +#undef UPB_PARSE_PARAMS + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_INTERNAL_DECODE_FAST_H_ */ +// IWYU pragma: end_exports + +#endif // UPB_GENERATED_CODE_SUPPORT_H_ + +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const upb_MiniTable google__protobuf__FileDescriptorSet_msg_init; +extern const upb_MiniTable* google__protobuf__FileDescriptorSet_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FileDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__FileDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__DescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__DescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__DescriptorProto__ExtensionRange_msg_init; +extern const upb_MiniTable* google__protobuf__DescriptorProto__ExtensionRange_msg_init_ptr; +extern const upb_MiniTable google__protobuf__DescriptorProto__ReservedRange_msg_init; +extern const upb_MiniTable* google__protobuf__DescriptorProto__ReservedRange_msg_init_ptr; +extern const upb_MiniTable google__protobuf__ExtensionRangeOptions_msg_init; +extern const upb_MiniTable* google__protobuf__ExtensionRangeOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__ExtensionRangeOptions__Declaration_msg_init; +extern const upb_MiniTable* google__protobuf__ExtensionRangeOptions__Declaration_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FieldDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__FieldDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__OneofDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__OneofDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__EnumDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__EnumDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init; +extern const upb_MiniTable* google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_ptr; +extern const upb_MiniTable google__protobuf__EnumValueDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__EnumValueDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__ServiceDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__ServiceDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__MethodDescriptorProto_msg_init; +extern const upb_MiniTable* google__protobuf__MethodDescriptorProto_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FileOptions_msg_init; +extern const upb_MiniTable* google__protobuf__FileOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__MessageOptions_msg_init; +extern const upb_MiniTable* google__protobuf__MessageOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FieldOptions_msg_init; +extern const upb_MiniTable* google__protobuf__FieldOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FieldOptions__EditionDefault_msg_init; +extern const upb_MiniTable* google__protobuf__FieldOptions__EditionDefault_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FieldOptions__FeatureSupport_msg_init; +extern const upb_MiniTable* google__protobuf__FieldOptions__FeatureSupport_msg_init_ptr; +extern const upb_MiniTable google__protobuf__OneofOptions_msg_init; +extern const upb_MiniTable* google__protobuf__OneofOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__EnumOptions_msg_init; +extern const upb_MiniTable* google__protobuf__EnumOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__EnumValueOptions_msg_init; +extern const upb_MiniTable* google__protobuf__EnumValueOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__ServiceOptions_msg_init; +extern const upb_MiniTable* google__protobuf__ServiceOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__MethodOptions_msg_init; +extern const upb_MiniTable* google__protobuf__MethodOptions_msg_init_ptr; +extern const upb_MiniTable google__protobuf__UninterpretedOption_msg_init; +extern const upb_MiniTable* google__protobuf__UninterpretedOption_msg_init_ptr; +extern const upb_MiniTable google__protobuf__UninterpretedOption__NamePart_msg_init; +extern const upb_MiniTable* google__protobuf__UninterpretedOption__NamePart_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FeatureSet_msg_init; +extern const upb_MiniTable* google__protobuf__FeatureSet_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FeatureSetDefaults_msg_init; +extern const upb_MiniTable* google__protobuf__FeatureSetDefaults_msg_init_ptr; +extern const upb_MiniTable google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init; +extern const upb_MiniTable* google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_ptr; +extern const upb_MiniTable google__protobuf__SourceCodeInfo_msg_init; +extern const upb_MiniTable* google__protobuf__SourceCodeInfo_msg_init_ptr; +extern const upb_MiniTable google__protobuf__SourceCodeInfo__Location_msg_init; +extern const upb_MiniTable* google__protobuf__SourceCodeInfo__Location_msg_init_ptr; +extern const upb_MiniTable google__protobuf__GeneratedCodeInfo_msg_init; +extern const upb_MiniTable* google__protobuf__GeneratedCodeInfo_msg_init_ptr; +extern const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init; +extern const upb_MiniTable* google__protobuf__GeneratedCodeInfo__Annotation_msg_init_ptr; + +extern const upb_MiniTableEnum google__protobuf__Edition_enum_init; +extern const upb_MiniTableEnum google__protobuf__ExtensionRangeOptions__VerificationState_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__EnumType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__FieldPresence_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__JsonFormat_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__MessageEncoding_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__Utf8Validation_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Label_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Type_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__CType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__JSType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__OptionRetention_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__OptionTargetType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FileOptions__OptimizeMode_enum_init; +extern const upb_MiniTableEnum google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init; +extern const upb_MiniTableEnum google__protobuf__MethodOptions__IdempotencyLevel_enum_init; +extern const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ */ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct google_protobuf_FileDescriptorSet { upb_Message UPB_PRIVATE(base); } google_protobuf_FileDescriptorSet; +typedef struct google_protobuf_FileDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_FileDescriptorProto; +typedef struct google_protobuf_DescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_DescriptorProto; +typedef struct google_protobuf_DescriptorProto_ExtensionRange { upb_Message UPB_PRIVATE(base); } google_protobuf_DescriptorProto_ExtensionRange; +typedef struct google_protobuf_DescriptorProto_ReservedRange { upb_Message UPB_PRIVATE(base); } google_protobuf_DescriptorProto_ReservedRange; +typedef struct google_protobuf_ExtensionRangeOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_ExtensionRangeOptions; +typedef struct google_protobuf_ExtensionRangeOptions_Declaration { upb_Message UPB_PRIVATE(base); } google_protobuf_ExtensionRangeOptions_Declaration; +typedef struct google_protobuf_FieldDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_FieldDescriptorProto; +typedef struct google_protobuf_OneofDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_OneofDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_EnumDescriptorProto; +typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange { upb_Message UPB_PRIVATE(base); } google_protobuf_EnumDescriptorProto_EnumReservedRange; +typedef struct google_protobuf_EnumValueDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_EnumValueDescriptorProto; +typedef struct google_protobuf_ServiceDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_ServiceDescriptorProto; +typedef struct google_protobuf_MethodDescriptorProto { upb_Message UPB_PRIVATE(base); } google_protobuf_MethodDescriptorProto; +typedef struct google_protobuf_FileOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_FileOptions; +typedef struct google_protobuf_MessageOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_MessageOptions; +typedef struct google_protobuf_FieldOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_FieldOptions; +typedef struct google_protobuf_FieldOptions_EditionDefault { upb_Message UPB_PRIVATE(base); } google_protobuf_FieldOptions_EditionDefault; +typedef struct google_protobuf_FieldOptions_FeatureSupport { upb_Message UPB_PRIVATE(base); } google_protobuf_FieldOptions_FeatureSupport; +typedef struct google_protobuf_OneofOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_OneofOptions; +typedef struct google_protobuf_EnumOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_EnumOptions; +typedef struct google_protobuf_EnumValueOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_EnumValueOptions; +typedef struct google_protobuf_ServiceOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_ServiceOptions; +typedef struct google_protobuf_MethodOptions { upb_Message UPB_PRIVATE(base); } google_protobuf_MethodOptions; +typedef struct google_protobuf_UninterpretedOption { upb_Message UPB_PRIVATE(base); } google_protobuf_UninterpretedOption; +typedef struct google_protobuf_UninterpretedOption_NamePart { upb_Message UPB_PRIVATE(base); } google_protobuf_UninterpretedOption_NamePart; +typedef struct google_protobuf_FeatureSet { upb_Message UPB_PRIVATE(base); } google_protobuf_FeatureSet; +typedef struct google_protobuf_FeatureSetDefaults { upb_Message UPB_PRIVATE(base); } google_protobuf_FeatureSetDefaults; +typedef struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault { upb_Message UPB_PRIVATE(base); } google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault; +typedef struct google_protobuf_SourceCodeInfo { upb_Message UPB_PRIVATE(base); } google_protobuf_SourceCodeInfo; +typedef struct google_protobuf_SourceCodeInfo_Location { upb_Message UPB_PRIVATE(base); } google_protobuf_SourceCodeInfo_Location; +typedef struct google_protobuf_GeneratedCodeInfo { upb_Message UPB_PRIVATE(base); } google_protobuf_GeneratedCodeInfo; +typedef struct google_protobuf_GeneratedCodeInfo_Annotation { upb_Message UPB_PRIVATE(base); } google_protobuf_GeneratedCodeInfo_Annotation; + +typedef enum { + google_protobuf_EDITION_UNKNOWN = 0, + google_protobuf_EDITION_1_TEST_ONLY = 1, + google_protobuf_EDITION_2_TEST_ONLY = 2, + google_protobuf_EDITION_LEGACY = 900, + google_protobuf_EDITION_PROTO2 = 998, + google_protobuf_EDITION_PROTO3 = 999, + google_protobuf_EDITION_2023 = 1000, + google_protobuf_EDITION_2024 = 1001, + google_protobuf_EDITION_99997_TEST_ONLY = 99997, + google_protobuf_EDITION_99998_TEST_ONLY = 99998, + google_protobuf_EDITION_99999_TEST_ONLY = 99999, + google_protobuf_EDITION_MAX = 2147483647 +} google_protobuf_Edition; + +typedef enum { + google_protobuf_ExtensionRangeOptions_DECLARATION = 0, + google_protobuf_ExtensionRangeOptions_UNVERIFIED = 1 +} google_protobuf_ExtensionRangeOptions_VerificationState; + +typedef enum { + google_protobuf_FeatureSet_ENUM_TYPE_UNKNOWN = 0, + google_protobuf_FeatureSet_OPEN = 1, + google_protobuf_FeatureSet_CLOSED = 2 +} google_protobuf_FeatureSet_EnumType; + +typedef enum { + google_protobuf_FeatureSet_FIELD_PRESENCE_UNKNOWN = 0, + google_protobuf_FeatureSet_EXPLICIT = 1, + google_protobuf_FeatureSet_IMPLICIT = 2, + google_protobuf_FeatureSet_LEGACY_REQUIRED = 3 +} google_protobuf_FeatureSet_FieldPresence; + +typedef enum { + google_protobuf_FeatureSet_JSON_FORMAT_UNKNOWN = 0, + google_protobuf_FeatureSet_ALLOW = 1, + google_protobuf_FeatureSet_LEGACY_BEST_EFFORT = 2 +} google_protobuf_FeatureSet_JsonFormat; + +typedef enum { + google_protobuf_FeatureSet_MESSAGE_ENCODING_UNKNOWN = 0, + google_protobuf_FeatureSet_LENGTH_PREFIXED = 1, + google_protobuf_FeatureSet_DELIMITED = 2 +} google_protobuf_FeatureSet_MessageEncoding; + +typedef enum { + google_protobuf_FeatureSet_REPEATED_FIELD_ENCODING_UNKNOWN = 0, + google_protobuf_FeatureSet_PACKED = 1, + google_protobuf_FeatureSet_EXPANDED = 2 +} google_protobuf_FeatureSet_RepeatedFieldEncoding; + +typedef enum { + google_protobuf_FeatureSet_UTF8_VALIDATION_UNKNOWN = 0, + google_protobuf_FeatureSet_VERIFY = 2, + google_protobuf_FeatureSet_NONE = 3 +} google_protobuf_FeatureSet_Utf8Validation; + +typedef enum { + google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, + google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, + google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 +} google_protobuf_FieldDescriptorProto_Label; + +typedef enum { + google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, + google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, + google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, + google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, + google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, + google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, + google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, + google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, + google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, + google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, + google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, + google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, + google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, + google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, + google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, + google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 +} google_protobuf_FieldDescriptorProto_Type; + +typedef enum { + google_protobuf_FieldOptions_STRING = 0, + google_protobuf_FieldOptions_CORD = 1, + google_protobuf_FieldOptions_STRING_PIECE = 2 +} google_protobuf_FieldOptions_CType; + +typedef enum { + google_protobuf_FieldOptions_JS_NORMAL = 0, + google_protobuf_FieldOptions_JS_STRING = 1, + google_protobuf_FieldOptions_JS_NUMBER = 2 +} google_protobuf_FieldOptions_JSType; + +typedef enum { + google_protobuf_FieldOptions_RETENTION_UNKNOWN = 0, + google_protobuf_FieldOptions_RETENTION_RUNTIME = 1, + google_protobuf_FieldOptions_RETENTION_SOURCE = 2 +} google_protobuf_FieldOptions_OptionRetention; + +typedef enum { + google_protobuf_FieldOptions_TARGET_TYPE_UNKNOWN = 0, + google_protobuf_FieldOptions_TARGET_TYPE_FILE = 1, + google_protobuf_FieldOptions_TARGET_TYPE_EXTENSION_RANGE = 2, + google_protobuf_FieldOptions_TARGET_TYPE_MESSAGE = 3, + google_protobuf_FieldOptions_TARGET_TYPE_FIELD = 4, + google_protobuf_FieldOptions_TARGET_TYPE_ONEOF = 5, + google_protobuf_FieldOptions_TARGET_TYPE_ENUM = 6, + google_protobuf_FieldOptions_TARGET_TYPE_ENUM_ENTRY = 7, + google_protobuf_FieldOptions_TARGET_TYPE_SERVICE = 8, + google_protobuf_FieldOptions_TARGET_TYPE_METHOD = 9 +} google_protobuf_FieldOptions_OptionTargetType; + +typedef enum { + google_protobuf_FileOptions_SPEED = 1, + google_protobuf_FileOptions_CODE_SIZE = 2, + google_protobuf_FileOptions_LITE_RUNTIME = 3 +} google_protobuf_FileOptions_OptimizeMode; + +typedef enum { + google_protobuf_GeneratedCodeInfo_Annotation_NONE = 0, + google_protobuf_GeneratedCodeInfo_Annotation_SET = 1, + google_protobuf_GeneratedCodeInfo_Annotation_ALIAS = 2 +} google_protobuf_GeneratedCodeInfo_Annotation_Semantic; + +typedef enum { + google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, + google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, + google_protobuf_MethodOptions_IDEMPOTENT = 2 +} google_protobuf_MethodOptions_IdempotencyLevel; + + + +/* google.protobuf.FileDescriptorSet */ + +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google__protobuf__FileDescriptorSet_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorSet_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorSet_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorSet_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorSet_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(google_protobuf_FileDescriptorSet* msg) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FileDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorSet_file_upb_array(const google_protobuf_FileDescriptorSet* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorSet_file_mutable_upb_array(google_protobuf_FileDescriptorSet* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* size) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FileDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FileDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google__protobuf__FileDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FileDescriptorProto */ + +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google__protobuf__FileDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(60, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(60, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(60, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_dependency_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_dependency_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_message_type_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_message_type_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_enum_type_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_enum_type_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_ServiceDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_service_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_service_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_extension_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_extension_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 88), 66, 4, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { + const google_protobuf_FileOptions* default_val = NULL; + const google_protobuf_FileOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(32, 88), 66, 4, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 88), 66, 4, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 96), 67, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + const google_protobuf_SourceCodeInfo* default_val = NULL; + const google_protobuf_SourceCodeInfo* ret; + const upb_MiniTableField field = {9, UPB_SIZE(36, 96), 67, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 96), 67, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_public_dependency_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_public_dependency_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_weak_dependency_upb_array(const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_weak_dependency_mutable_upb_array(google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {12, UPB_SIZE(68, 120), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {12, UPB_SIZE(68, 120), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {12, UPB_SIZE(68, 120), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(60, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(12, 48), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_DescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(16, 56), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_EnumDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(20, 64), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_ServiceDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_ServiceDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(24, 72), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google__protobuf__ServiceDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {7, UPB_SIZE(28, 80), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 88), 66, 4, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google__protobuf__FileOptions_msg_init, arena); + if (sub) google_protobuf_FileDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 96), 67, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); + if (sub == NULL) { + sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google__protobuf__SourceCodeInfo_msg_init, arena); + if (sub) google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); + } + return sub; +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(40, 104), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {11, UPB_SIZE(44, 112), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {12, UPB_SIZE(68, 120), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.DescriptorProto */ + +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_protobuf_DescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(48, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(48, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(48, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_field_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_field_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_nested_type_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_nested_type_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_enum_type_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_enum_type_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_extension_range_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_extension_range_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_extension_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_extension_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { + const google_protobuf_MessageOptions* default_val = NULL; + const google_protobuf_MessageOptions* ret; + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MessageOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_OneofDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_oneof_decl_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_oneof_decl_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto_ReservedRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_reserved_range_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_reserved_range_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_reserved_name_upb_array(const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_reserved_name_mutable_upb_array(google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(48, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_DescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_EnumDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto_ExtensionRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_DescriptorProto_ExtensionRange**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ExtensionRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, 4, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, 5, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MessageOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google__protobuf__MessageOptions_msg_init, arena); + if (sub) google_protobuf_DescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_OneofDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_OneofDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, 6, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google__protobuf__OneofDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto_ReservedRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_DescriptorProto_ReservedRange**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, 7, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ReservedRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} + +/* google.protobuf.DescriptorProto.ExtensionRange */ + +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ExtensionRange_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(const google_protobuf_DescriptorProto_ExtensionRange* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const google_protobuf_ExtensionRangeOptions* default_val = NULL; + const google_protobuf_ExtensionRangeOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { + struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions_msg_init, arena); + if (sub) google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.DescriptorProto.ReservedRange */ + +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ReservedRange_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ReservedRange_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ReservedRange_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(const google_protobuf_DescriptorProto_ReservedRange* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.ExtensionRangeOptions */ + +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { + return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google_protobuf_ExtensionRangeOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_declaration(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ExtensionRangeOptions_Declaration* const* google_protobuf_ExtensionRangeOptions_declaration(const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_ExtensionRangeOptions_Declaration* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_ExtensionRangeOptions_declaration_upb_array(const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_ExtensionRangeOptions_declaration_mutable_upb_array(google_protobuf_ExtensionRangeOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_verification(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_ExtensionRangeOptions_verification(const google_protobuf_ExtensionRangeOptions* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_verification(const google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_features(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_ExtensionRangeOptions_features(const google_protobuf_ExtensionRangeOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_features(const google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_ExtensionRangeOptions_uninterpreted_option_upb_array(const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_ExtensionRangeOptions_uninterpreted_option_mutable_upb_array(google_protobuf_ExtensionRangeOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration** google_protobuf_ExtensionRangeOptions_mutable_declaration(google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_ExtensionRangeOptions_Declaration**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration** google_protobuf_ExtensionRangeOptions_resize_declaration(google_protobuf_ExtensionRangeOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_ExtensionRangeOptions_Declaration**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_add_declaration(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_ExtensionRangeOptions_Declaration* sub = (struct google_protobuf_ExtensionRangeOptions_Declaration*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_verification(google_protobuf_ExtensionRangeOptions *msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_features(google_protobuf_ExtensionRangeOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_ExtensionRangeOptions_mutable_features(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_ExtensionRangeOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_ExtensionRangeOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.ExtensionRangeOptions.Declaration */ + +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_new(upb_Arena* arena) { + return (google_protobuf_ExtensionRangeOptions_Declaration*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init, arena); +} +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions_Declaration* ret = google_protobuf_ExtensionRangeOptions_Declaration_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions_Declaration* ret = google_protobuf_ExtensionRangeOptions_Declaration_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_Declaration_serialize(const google_protobuf_ExtensionRangeOptions_Declaration* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_Declaration_serialize_ex(const google_protobuf_ExtensionRangeOptions_Declaration* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_number(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_ExtensionRangeOptions_Declaration_number(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_number(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_full_name(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ExtensionRangeOptions_Declaration_full_name(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_full_name(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_type(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ExtensionRangeOptions_Declaration_type(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_type(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_reserved(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {5, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_reserved(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_reserved(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {5, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_repeated(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {6, 17, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_repeated(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, 17, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_repeated(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {6, 17, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_number(google_protobuf_ExtensionRangeOptions_Declaration *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_full_name(google_protobuf_ExtensionRangeOptions_Declaration *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_type(google_protobuf_ExtensionRangeOptions_Declaration *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_reserved(google_protobuf_ExtensionRangeOptions_Declaration *msg, bool value) { + const upb_MiniTableField field = {5, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_repeated(google_protobuf_ExtensionRangeOptions_Declaration *msg, bool value) { + const upb_MiniTableField field = {6, 17, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FieldDescriptorProto */ + +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_protobuf_FieldDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(36, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(36, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(36, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(44, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(44, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(44, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {4, 16, 67, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {4, 16, 67, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {4, 16, 67, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {5, 20, 68, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {5, 20, 68, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {5, 20, 68, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(52, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {6, UPB_SIZE(52, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(52, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(60, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(60, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(60, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 96), 71, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { + const google_protobuf_FieldOptions* default_val = NULL; + const google_protobuf_FieldOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(24, 96), 71, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 96), 71, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(68, 104), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {10, UPB_SIZE(68, 104), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(68, 104), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {17, UPB_SIZE(32, 28), 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, UPB_SIZE(32, 28), 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {17, UPB_SIZE(32, 28), 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(36, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(44, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {4, 16, 67, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {5, 20, 68, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {6, UPB_SIZE(52, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(60, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 96), 71, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google__protobuf__FieldOptions_msg_init, arena); + if (sub) google_protobuf_FieldDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {10, UPB_SIZE(68, 104), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {17, UPB_SIZE(32, 28), 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.OneofDescriptorProto */ + +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google__protobuf__OneofDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_protobuf_OneofDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { + const google_protobuf_OneofOptions* default_val = NULL; + const google_protobuf_OneofOptions* ret; + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google__protobuf__OneofOptions_msg_init, arena); + if (sub) google_protobuf_OneofDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.EnumDescriptorProto */ + +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_protobuf_EnumDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(28, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(28, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(28, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumValueDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_value_upb_array(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_value_mutable_upb_array(google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { + const google_protobuf_EnumOptions* default_val = NULL; + const google_protobuf_EnumOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_reserved_range_upb_array(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_reserved_range_mutable_upb_array(google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_reserved_name_upb_array(const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_reserved_name_mutable_upb_array(google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(28, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumValueDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_EnumValueDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google__protobuf__EnumValueDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google__protobuf__EnumOptions_msg_init, arena); + if (sub) google_protobuf_EnumDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} + +/* google.protobuf.EnumDescriptorProto.EnumReservedRange */ + +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize_ex(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.EnumValueDescriptorProto */ + +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google__protobuf__EnumValueDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const google_protobuf_EnumValueDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { + const google_protobuf_EnumValueOptions* default_val = NULL; + const google_protobuf_EnumValueOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google__protobuf__EnumValueOptions_msg_init, arena); + if (sub) google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.ServiceDescriptorProto */ + +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google__protobuf__ServiceDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const google_protobuf_ServiceDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_MethodDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_ServiceDescriptorProto_method_upb_array(const google_protobuf_ServiceDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_ServiceDescriptorProto_method_mutable_upb_array(google_protobuf_ServiceDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { + const google_protobuf_ServiceOptions* default_val = NULL; + const google_protobuf_ServiceOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_MethodDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_MethodDescriptorProto**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google__protobuf__MethodDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google__protobuf__ServiceOptions_msg_init, arena); + if (sub) google_protobuf_ServiceDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.MethodDescriptorProto */ + +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google__protobuf__MethodDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodDescriptorProto_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodDescriptorProto_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google_protobuf_MethodDescriptorProto* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(36, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(36, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(36, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { + const google_protobuf_MethodOptions* default_val = NULL; + const google_protobuf_MethodOptions* ret; + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(16, 9), 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, UPB_SIZE(16, 9), 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(16, 9), 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(17, 10), 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, UPB_SIZE(17, 10), 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(17, 10), 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(36, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodOptions_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google__protobuf__MethodOptions_msg_init, arena); + if (sub) google_protobuf_MethodDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {5, UPB_SIZE(16, 9), 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {6, UPB_SIZE(17, 10), 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FileOptions */ + +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { + return (google_protobuf_FileOptions*)_upb_Message_New(&google__protobuf__FileOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_FileOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {9, 12, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {9, 12, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {9, 12, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {10, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {10, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {16, 17, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 17, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {16, 17, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {17, 18, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, 18, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {17, 18, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {18, 19, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {18, 19, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {18, 19, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {20, 20, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {20, 20, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {20, 20, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {23, 21, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {23, 21, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {23, 21, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {27, 22, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {27, 22, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {27, 22, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {31, 23, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + bool default_val = true; + bool ret; + const upb_MiniTableField field = {31, 23, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {31, 23, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_features(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FileOptions_features(const google_protobuf_FileOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_features(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FileOptions_uninterpreted_option_upb_array(const google_protobuf_FileOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FileOptions_uninterpreted_option_mutable_upb_array(google_protobuf_FileOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { + const upb_MiniTableField field = {9, 12, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {10, 16, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {16, 17, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {17, 18, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {18, 19, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {20, 20, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {23, 21, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {27, 22, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {31, 23, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_features(google_protobuf_FileOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FileOptions_mutable_features(google_protobuf_FileOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FileOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FileOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.MessageOptions */ + +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new(upb_Arena* arena) { + return (google_protobuf_MessageOptions*)_upb_Message_New(&google__protobuf__MessageOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MessageOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MessageOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MessageOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protobuf_MessageOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MessageOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated_legacy_json_field_conflicts(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_deprecated_legacy_json_field_conflicts(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated_legacy_json_field_conflicts(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_features(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {12, 16, 69, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_MessageOptions_features(const google_protobuf_MessageOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {12, 16, 69, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_features(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {12, 16, 69, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_MessageOptions_uninterpreted_option_upb_array(const google_protobuf_MessageOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_MessageOptions_uninterpreted_option_mutable_upb_array(google_protobuf_MessageOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_deprecated_legacy_json_field_conflicts(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_features(google_protobuf_MessageOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {12, 16, 69, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_MessageOptions_mutable_features(google_protobuf_MessageOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_MessageOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_MessageOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FieldOptions */ + +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions*)_upb_Message_New(&google__protobuf__FieldOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf_FieldOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {1, 12, 64, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {1, 12, 64, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {3, 17, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 17, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {3, 17, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {5, 18, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 18, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {5, 18, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {6, 20, 68, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 20, 68, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {6, 20, 68, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {10, 24, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 24, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {10, 24, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {15, 25, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {15, 25, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {15, 25, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_debug_redact(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {16, 26, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_debug_redact(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 26, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_debug_redact(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {16, 26, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_retention(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {17, 28, 72, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_retention(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {17, 28, 72, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_retention(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {17, 28, 72, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_targets(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FieldOptions_targets(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_targets_upb_array(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_targets_mutable_upb_array(google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_edition_defaults(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_EditionDefault* const* google_protobuf_FieldOptions_edition_defaults(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldOptions_EditionDefault* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_edition_defaults_upb_array(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_edition_defaults_mutable_upb_array(google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_features(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {21, UPB_SIZE(40, 48), 73, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FieldOptions_features(const google_protobuf_FieldOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {21, UPB_SIZE(40, 48), 73, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_features(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {21, UPB_SIZE(40, 48), 73, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_feature_support(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {22, UPB_SIZE(44, 56), 74, 2, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_feature_support(const google_protobuf_FieldOptions* msg) { + const google_protobuf_FieldOptions_FeatureSupport* default_val = NULL; + const google_protobuf_FieldOptions_FeatureSupport* ret; + const upb_MiniTableField field = {22, UPB_SIZE(44, 56), 74, 2, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_feature_support(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {22, UPB_SIZE(44, 56), 74, 2, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_uninterpreted_option_upb_array(const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_uninterpreted_option_mutable_upb_array(google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {3, 17, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {5, 18, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { + const upb_MiniTableField field = {6, 20, 68, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {10, 24, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {15, 25, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_debug_redact(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {16, 26, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_retention(google_protobuf_FieldOptions *msg, int32_t value) { + const upb_MiniTableField field = {17, 28, 72, 6, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE int32_t* google_protobuf_FieldOptions_mutable_targets(google_protobuf_FieldOptions* msg, size_t* size) { + upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_FieldOptions_resize_targets(google_protobuf_FieldOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_FieldOptions_add_targets(google_protobuf_FieldOptions* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {19, 32, 0, 7, 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault** google_protobuf_FieldOptions_mutable_edition_defaults(google_protobuf_FieldOptions* msg, size_t* size) { + upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldOptions_EditionDefault**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault** google_protobuf_FieldOptions_resize_edition_defaults(google_protobuf_FieldOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FieldOptions_EditionDefault**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_add_edition_defaults(google_protobuf_FieldOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {20, UPB_SIZE(36, 40), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldOptions_EditionDefault* sub = (struct google_protobuf_FieldOptions_EditionDefault*)_upb_Message_New(&google__protobuf__FieldOptions__EditionDefault_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FieldOptions_set_features(google_protobuf_FieldOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {21, UPB_SIZE(40, 48), 73, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FieldOptions_mutable_features(google_protobuf_FieldOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FieldOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FieldOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FieldOptions_set_feature_support(google_protobuf_FieldOptions *msg, google_protobuf_FieldOptions_FeatureSupport* value) { + const upb_MiniTableField field = {22, UPB_SIZE(44, 56), 74, 2, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_mutable_feature_support(google_protobuf_FieldOptions* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions_FeatureSupport* sub = (struct google_protobuf_FieldOptions_FeatureSupport*)google_protobuf_FieldOptions_feature_support(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); + if (sub) google_protobuf_FieldOptions_set_feature_support(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(48, 64), 0, 3, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FieldOptions.EditionDefault */ + +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions_EditionDefault*)_upb_Message_New(&google__protobuf__FieldOptions__EditionDefault_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FieldOptions_EditionDefault* ret = google_protobuf_FieldOptions_EditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__EditionDefault_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions_EditionDefault* ret = google_protobuf_FieldOptions_EditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__EditionDefault_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_EditionDefault_serialize(const google_protobuf_FieldOptions_EditionDefault* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__EditionDefault_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_EditionDefault_serialize_ex(const google_protobuf_FieldOptions_EditionDefault* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__EditionDefault_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_clear_value(google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldOptions_EditionDefault_value(const google_protobuf_FieldOptions_EditionDefault* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_EditionDefault_has_value(const google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_clear_edition(google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 65, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_EditionDefault_edition(const google_protobuf_FieldOptions_EditionDefault* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 65, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_EditionDefault_has_edition(const google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 65, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_set_value(google_protobuf_FieldOptions_EditionDefault *msg, upb_StringView value) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_set_edition(google_protobuf_FieldOptions_EditionDefault *msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 65, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FieldOptions.FeatureSupport */ + +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FieldOptions_FeatureSupport* ret = google_protobuf_FieldOptions_FeatureSupport_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__FeatureSupport_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions_FeatureSupport* ret = google_protobuf_FieldOptions_FeatureSupport_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__FeatureSupport_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_FeatureSupport_serialize(const google_protobuf_FieldOptions_FeatureSupport* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__FeatureSupport_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_FeatureSupport_serialize_ex(const google_protobuf_FieldOptions_FeatureSupport* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__FeatureSupport_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_introduced(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_introduced(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_introduced(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_deprecated(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_deprecated(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_deprecated(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_deprecation_warning(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldOptions_FeatureSupport_deprecation_warning(const google_protobuf_FieldOptions_FeatureSupport* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_deprecation_warning(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_removed(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {4, 20, 67, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_removed(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, 20, 67, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_removed(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {4, 20, 67, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_introduced(google_protobuf_FieldOptions_FeatureSupport *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_deprecated(google_protobuf_FieldOptions_FeatureSupport *msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_deprecation_warning(google_protobuf_FieldOptions_FeatureSupport *msg, upb_StringView value) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_removed(google_protobuf_FieldOptions_FeatureSupport *msg, int32_t value) { + const upb_MiniTableField field = {4, 20, 67, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.OneofOptions */ + +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new(upb_Arena* arena) { + return (google_protobuf_OneofOptions*)_upb_Message_New(&google__protobuf__OneofOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf_OneofOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_OneofOptions_clear_features(google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_OneofOptions_features(const google_protobuf_OneofOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofOptions_has_features(const google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_OneofOptions_uninterpreted_option_upb_array(const google_protobuf_OneofOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_OneofOptions_uninterpreted_option_mutable_upb_array(google_protobuf_OneofOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_OneofOptions_set_features(google_protobuf_OneofOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_OneofOptions_mutable_features(google_protobuf_OneofOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_OneofOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_OneofOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.EnumOptions */ + +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new(upb_Arena* arena) { + return (google_protobuf_EnumOptions*)_upb_Message_New(&google__protobuf__EnumOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_EnumOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated_legacy_json_field_conflicts(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_deprecated_legacy_json_field_conflicts(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated_legacy_json_field_conflicts(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_features(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_EnumOptions_features(const google_protobuf_EnumOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_features(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_EnumOptions_uninterpreted_option_upb_array(const google_protobuf_EnumOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_EnumOptions_uninterpreted_option_mutable_upb_array(google_protobuf_EnumOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_deprecated_legacy_json_field_conflicts(google_protobuf_EnumOptions *msg, bool value) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_features(google_protobuf_EnumOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_EnumOptions_mutable_features(google_protobuf_EnumOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_EnumOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_EnumOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.EnumValueOptions */ + +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_new(upb_Arena* arena) { + return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google__protobuf__EnumValueOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_protobuf_EnumValueOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_features(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_EnumValueOptions_features(const google_protobuf_EnumValueOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_features(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_debug_redact(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 10), 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumValueOptions_debug_redact(const google_protobuf_EnumValueOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 10), 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_debug_redact(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 10), 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_feature_support(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 24), 67, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_FeatureSupport* google_protobuf_EnumValueOptions_feature_support(const google_protobuf_EnumValueOptions* msg) { + const google_protobuf_FieldOptions_FeatureSupport* default_val = NULL; + const google_protobuf_FieldOptions_FeatureSupport* ret; + const upb_MiniTableField field = {4, UPB_SIZE(20, 24), 67, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_feature_support(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 24), 67, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_EnumValueOptions_uninterpreted_option_upb_array(const google_protobuf_EnumValueOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_EnumValueOptions_uninterpreted_option_mutable_upb_array(google_protobuf_EnumValueOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_features(google_protobuf_EnumValueOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_EnumValueOptions_mutable_features(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_EnumValueOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_EnumValueOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_debug_redact(google_protobuf_EnumValueOptions *msg, bool value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 10), 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_feature_support(google_protobuf_EnumValueOptions *msg, google_protobuf_FieldOptions_FeatureSupport* value) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 24), 67, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions_FeatureSupport* google_protobuf_EnumValueOptions_mutable_feature_support(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions_FeatureSupport* sub = (struct google_protobuf_FieldOptions_FeatureSupport*)google_protobuf_EnumValueOptions_feature_support(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); + if (sub) google_protobuf_EnumValueOptions_set_feature_support(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, 2, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.ServiceOptions */ + +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new(upb_Arena* arena) { + return (google_protobuf_ServiceOptions*)_upb_Message_New(&google__protobuf__ServiceOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protobuf_ServiceOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_features(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_ServiceOptions_features(const google_protobuf_ServiceOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceOptions_has_features(const google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_ServiceOptions_uninterpreted_option_upb_array(const google_protobuf_ServiceOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_ServiceOptions_uninterpreted_option_mutable_upb_array(google_protobuf_ServiceOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ServiceOptions_set_features(google_protobuf_ServiceOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_ServiceOptions_mutable_features(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_ServiceOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_ServiceOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.MethodOptions */ + +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new(upb_Arena* arena) { + return (google_protobuf_MethodOptions*)_upb_Message_New(&google__protobuf__MethodOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodOptions_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodOptions_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobuf_MethodOptions* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {34, 12, 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {34, 12, 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {34, 12, 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_features(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {35, 16, 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_MethodOptions_features(const google_protobuf_MethodOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {35, 16, 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_features(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {35, 16, 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_MethodOptions_uninterpreted_option_upb_array(const google_protobuf_MethodOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_MethodOptions_uninterpreted_option_mutable_upb_array(google_protobuf_MethodOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { + const upb_MiniTableField field = {34, 12, 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodOptions_set_features(google_protobuf_MethodOptions *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {35, 16, 66, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_MethodOptions_mutable_features(google_protobuf_MethodOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_MethodOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_MethodOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, 1, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.UninterpretedOption */ + +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_new(upb_Arena* arena) { + return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); +} +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_protobuf_UninterpretedOption* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption_NamePart* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_UninterpretedOption_name_upb_array(const google_protobuf_UninterpretedOption* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_UninterpretedOption_name_mutable_upb_array(google_protobuf_UninterpretedOption* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + uint64_t default_val = (uint64_t)0ull; + uint64_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 48), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + int64_t default_val = (int64_t)0ll; + int64_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(32, 48), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 48), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(40, 56), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { + double default_val = 0; + double ret; + const upb_MiniTableField field = {6, UPB_SIZE(40, 56), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(40, 56), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(48, 64), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(48, 64), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(48, 64), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(56, 80), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(56, 80), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(56, 80), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption_NamePart**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_UninterpretedOption_NamePart**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google__protobuf__UninterpretedOption__NamePart_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 48), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { + const upb_MiniTableField field = {6, UPB_SIZE(40, 56), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(48, 64), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(56, 80), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.UninterpretedOption.NamePart */ + +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { + return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google__protobuf__UninterpretedOption__NamePart_msg_init, arena); +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption__NamePart_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption__NamePart_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption__NamePart_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const google_protobuf_UninterpretedOption_NamePart* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption__NamePart_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FeatureSet */ + +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_new(upb_Arena* arena) { + return (google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FeatureSet* ret = google_protobuf_FeatureSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSet* ret = google_protobuf_FeatureSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSet_serialize(const google_protobuf_FeatureSet* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSet_serialize_ex(const google_protobuf_FeatureSet* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSet_clear_field_presence(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_field_presence(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_field_presence(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_enum_type(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_enum_type(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_enum_type(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_repeated_field_encoding(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {3, 20, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_repeated_field_encoding(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 20, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_repeated_field_encoding(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {3, 20, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_utf8_validation(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {4, 24, 67, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_utf8_validation(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, 24, 67, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_utf8_validation(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {4, 24, 67, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_message_encoding(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {5, 28, 68, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_message_encoding(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, 28, 68, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_message_encoding(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {5, 28, 68, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_json_format(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {6, 32, 69, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_json_format(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 32, 69, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_json_format(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {6, 32, 69, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FeatureSet_set_field_presence(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_enum_type(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_repeated_field_encoding(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {3, 20, 66, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_utf8_validation(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {4, 24, 67, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_message_encoding(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {5, 28, 68, 4, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_json_format(google_protobuf_FeatureSet *msg, int32_t value) { + const upb_MiniTableField field = {6, 32, 69, 5, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FeatureSetDefaults */ + +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_new(upb_Arena* arena) { + return (google_protobuf_FeatureSetDefaults*)_upb_Message_New(&google__protobuf__FeatureSetDefaults_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults* ret = google_protobuf_FeatureSetDefaults_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults* ret = google_protobuf_FeatureSetDefaults_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_serialize(const google_protobuf_FeatureSetDefaults* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_serialize_ex(const google_protobuf_FeatureSetDefaults* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_defaults(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* google_protobuf_FeatureSetDefaults_defaults(const google_protobuf_FeatureSetDefaults* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_FeatureSetDefaults_defaults_upb_array(const google_protobuf_FeatureSetDefaults* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_FeatureSetDefaults_defaults_mutable_upb_array(google_protobuf_FeatureSetDefaults* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_minimum_edition(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_minimum_edition(const google_protobuf_FeatureSetDefaults* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_has_minimum_edition(const google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_maximum_edition(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_maximum_edition(const google_protobuf_FeatureSetDefaults* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_has_maximum_edition(const google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault** google_protobuf_FeatureSetDefaults_mutable_defaults(google_protobuf_FeatureSetDefaults* msg, size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault** google_protobuf_FeatureSetDefaults_resize_defaults(google_protobuf_FeatureSetDefaults* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_add_defaults(google_protobuf_FeatureSetDefaults* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* sub = (struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault*)_upb_Message_New(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_set_minimum_edition(google_protobuf_FeatureSetDefaults *msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, 1, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_set_maximum_edition(google_protobuf_FeatureSetDefaults *msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault */ + +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(upb_Arena* arena) { + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault*)_upb_Message_New(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* ret = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* ret = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_serialize(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_serialize_ex(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_edition(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 64, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 64, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_edition(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 64, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_overridable_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {4, 16, 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {4, 16, 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_overridable_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {4, 16, 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_fixed_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_fixed_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_edition(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault *msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 64, 2, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_overridable_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {4, 16, 65, 0, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_mutable_overridable_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_overridable_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_fixed_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault *msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, 1, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_mutable_fixed_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_fixed_features(msg, sub); + } + return sub; +} + +/* google.protobuf.SourceCodeInfo */ + +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google__protobuf__SourceCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(google_protobuf_SourceCodeInfo* msg) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_SourceCodeInfo_Location* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_location_upb_array(const google_protobuf_SourceCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_location_mutable_upb_array(google_protobuf_SourceCodeInfo* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* size) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_SourceCodeInfo_Location**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_SourceCodeInfo_Location**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google__protobuf__SourceCodeInfo__Location_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.SourceCodeInfo.Location */ + +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google__protobuf__SourceCodeInfo__Location_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo__Location_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo__Location_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo__Location_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo__Location_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_path_upb_array(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_path_mutable_upb_array(google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_span_upb_array(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_span_mutable_upb_array(google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(32, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {4, UPB_SIZE(32, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(32, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_leading_detached_comments_upb_array(const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_leading_detached_comments_mutable_upb_array(google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 16), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(16, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + const upb_MiniTableField field = {4, UPB_SIZE(32, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} + +/* google.protobuf.GeneratedCodeInfo */ + +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(google_protobuf_GeneratedCodeInfo* msg) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_GeneratedCodeInfo_annotation_upb_array(const google_protobuf_GeneratedCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_GeneratedCodeInfo_annotation_mutable_upb_array(google_protobuf_GeneratedCodeInfo* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* size) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_GeneratedCodeInfo_Annotation**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (google_protobuf_GeneratedCodeInfo_Annotation**)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, 0, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.GeneratedCodeInfo.Annotation */ + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char* buf, size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, extreg, options, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, int options, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE const upb_Array* _google_protobuf_GeneratedCodeInfo_Annotation_path_upb_array(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE upb_Array* _google_protobuf_GeneratedCodeInfo_Annotation_path_mutable_upb_array(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t size, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized(UPB_UPCAST(msg), + &field, size, arena); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 32), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, 0, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message *)msg, &field, &value); +} + +/* Max size 32 is google.protobuf.FileOptions */ +/* Max size 64 is google.protobuf.FileOptions */ +#define _UPB_MAXOPT_SIZE UPB_SIZE(112, 200) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ */ +#endif + +// IWYU pragma: end_exports + +#endif // THIRD_PARTY_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H_ + +typedef enum { + kUpb_Syntax_Proto2 = 2, + kUpb_Syntax_Proto3 = 3, + kUpb_Syntax_Editions = 99 +} upb_Syntax; + +// Forward declarations for circular references. +typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; +typedef struct upb_EnumValueDef upb_EnumValueDef; +typedef struct upb_ExtensionRange upb_ExtensionRange; +typedef struct upb_FieldDef upb_FieldDef; +typedef struct upb_FileDef upb_FileDef; +typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; +typedef struct upb_MethodDef upb_MethodDef; +typedef struct upb_OneofDef upb_OneofDef; +typedef struct upb_ServiceDef upb_ServiceDef; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +typedef struct upb_DefBuilder upb_DefBuilder; + +#endif /* UPB_REFLECTION_COMMON_H_ */ + +#ifndef UPB_REFLECTION_DEF_TYPE_H_ +#define UPB_REFLECTION_DEF_TYPE_H_ + + +// Must be last. + +// Inside a symtab we store tagged pointers to specific def types. +typedef enum { + UPB_DEFTYPE_MASK = 7, + + // Only inside symtab table. + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, + + // Only inside message table. + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, +} upb_deftype_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Our 3-bit pointer tagging requires all pointers to be multiples of 8. +// The arena will always yield 8-byte-aligned addresses, however we put +// the defs into arrays. For each element in the array to be 8-byte-aligned, +// the sizes of each def type must also be a multiple of 8. +// +// If any of these asserts fail, we need to add or remove padding on 32-bit +// machines (64-bit machines will have 8-byte alignment already due to +// pointers, which all of these structs have). +UPB_INLINE void _upb_DefType_CheckPadding(size_t size) { + UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); +} + +upb_deftype_t _upb_DefType_Type(upb_value v); + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type); + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_TYPE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API void upb_DefPool_Free(upb_DefPool* s); + +UPB_API upb_DefPool* upb_DefPool_New(void); + +UPB_API const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s); + +UPB_API bool upb_DefPool_SetFeatureSetDefaults(upb_DefPool* s, + const char* serialized_defaults, + size_t serialized_len, + upb_Status* status); + +UPB_API const upb_MessageDef* upb_DefPool_FindMessageByName( + const upb_DefPool* s, const char* sym); + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +UPB_API const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym); + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym); + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len); + +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext); + +UPB_API const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym); + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum); + +UPB_API const upb_ServiceDef* upb_DefPool_FindServiceByName( + const upb_DefPool* s, const char* name); + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name); + +UPB_API const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const UPB_DESC(FileDescriptorProto) * file_proto, + upb_Status* status); + +UPB_API const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s); + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_DEF_H_ +#define UPB_REFLECTION_ENUM_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); +int32_t upb_EnumDef_Default(const upb_EnumDef* e); +UPB_API const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name); +UPB_API const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size); +UPB_API const upb_EnumValueDef* upb_EnumDef_FindValueByNumber( + const upb_EnumDef* e, int32_t num); +UPB_API const char* upb_EnumDef_FullName(const upb_EnumDef* e); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e); +bool upb_EnumDef_IsClosed(const upb_EnumDef* e); +bool upb_EnumDef_IsSpecifiedAsClosed(const upb_EnumDef* e); + +// Creates a mini descriptor string for an enum, returns true on success. +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out); + +const char* upb_EnumDef_Name(const upb_EnumDef* e); +const UPB_DESC(EnumOptions) * upb_EnumDef_Options(const upb_EnumDef* e); +const UPB_DESC(FeatureSet) * upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e); + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i); +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e); + +UPB_API const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +UPB_API int upb_EnumDef_ValueCount(const upb_EnumDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v); +UPB_API const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); +UPB_API int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); +const UPB_DESC(EnumValueOptions) * + upb_EnumValueDef_Options(const upb_EnumValueDef* v); +const UPB_DESC(FeatureSet) * + upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); +const UPB_DESC(ExtensionRangeOptions) * + upb_ExtensionRange_Options(const upb_ExtensionRange* r); +const UPB_DESC(FeatureSet) * + upb_ExtensionRange_ResolvedFeatures(const upb_ExtensionRange* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FIELD_DEF_H_ +#define UPB_REFLECTION_FIELD_DEF_H_ + +#include + + +// Must be last. + +// Maximum field number allowed for FieldDefs. +// This is an inherent limit of the protobuf wire format. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); +UPB_API const upb_MessageDef* upb_FieldDef_ContainingType( + const upb_FieldDef* f); +UPB_API upb_CType upb_FieldDef_CType(const upb_FieldDef* f); +UPB_API upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); +UPB_API const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); +UPB_API const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); +const char* upb_FieldDef_FullName(const upb_FieldDef* f); +bool upb_FieldDef_HasDefault(const upb_FieldDef* f); +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_HasPresence(const upb_FieldDef* f); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); +uint32_t upb_FieldDef_Index(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsEnum(const upb_FieldDef* f); +bool upb_FieldDef_IsExtension(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsMap(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsPacked(const upb_FieldDef* f); +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); +bool upb_FieldDef_IsRequired(const upb_FieldDef* f); +bool upb_FieldDef_IsString(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); +UPB_API const char* upb_FieldDef_JsonName(const upb_FieldDef* f); +UPB_API upb_Label upb_FieldDef_Label(const upb_FieldDef* f); +uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +UPB_API const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); +bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f); +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f); + +// Creates a mini descriptor string for a field, returns true on success. +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out); + +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const upb_MiniTableExtension* upb_FieldDef_MiniTableExtension( + const upb_FieldDef* f); +UPB_API const char* upb_FieldDef_Name(const upb_FieldDef* f); +UPB_API uint32_t upb_FieldDef_Number(const upb_FieldDef* f); +const UPB_DESC(FieldOptions) * upb_FieldDef_Options(const upb_FieldDef* f); +const UPB_DESC(FeatureSet) * + upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f); +UPB_API const upb_OneofDef* upb_FieldDef_RealContainingOneof( + const upb_FieldDef* f); +UPB_API upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FILE_DEF_H_ +#define UPB_REFLECTION_FILE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const char* upb_FileDef_EditionName(int edition); + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); +int upb_FileDef_DependencyCount(const upb_FileDef* f); +bool upb_FileDef_HasOptions(const upb_FileDef* f); +UPB_API const char* upb_FileDef_Name(const upb_FileDef* f); +const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f); +const UPB_DESC(FeatureSet) * upb_FileDef_ResolvedFeatures(const upb_FileDef* f); +const char* upb_FileDef_Package(const upb_FileDef* f); +UPB_DESC(Edition) upb_FileDef_Edition(const upb_FileDef* f); +UPB_API const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); +int upb_FileDef_ServiceCount(const upb_FileDef* f); + +UPB_API upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f); + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); + +// Returns whether |symbol| is transitively included by |f| +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* symbol); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FILE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_DEF_H_ +#define UPB_REFLECTION_MESSAGE_DEF_H_ + + +// Must be last. + +// Well-known field tag numbers for map-entry messages. +#define kUpb_MapEntry_KeyFieldNumber 1 +#define kUpb_MapEntry_ValueFieldNumber 2 + +// Well-known field tag numbers for Any messages. +#define kUpb_Any_TypeFieldNumber 1 +#define kUpb_Any_ValueFieldNumber 2 + +// Well-known field tag numbers for duration messages. +#define kUpb_Duration_SecondsFieldNumber 1 +#define kUpb_Duration_NanosFieldNumber 2 + +// Well-known field tag numbers for timestamp messages. +#define kUpb_Timestamp_SecondsFieldNumber 1 +#define kUpb_Timestamp_NanosFieldNumber 2 + +// All the different kind of well known type messages. For simplicity of check, +// number wrappers and string wrappers are grouped together. Make sure the +// order and number of these groups are not changed. +typedef enum { + kUpb_WellKnown_Unspecified, + kUpb_WellKnown_Any, + kUpb_WellKnown_FieldMask, + kUpb_WellKnown_Duration, + kUpb_WellKnown_Timestamp, + + // number wrappers + kUpb_WellKnown_DoubleValue, + kUpb_WellKnown_FloatValue, + kUpb_WellKnown_Int64Value, + kUpb_WellKnown_UInt64Value, + kUpb_WellKnown_Int32Value, + kUpb_WellKnown_UInt32Value, + + // string wrappers + kUpb_WellKnown_StringValue, + kUpb_WellKnown_BytesValue, + kUpb_WellKnown_BoolValue, + kUpb_WellKnown_Value, + kUpb_WellKnown_ListValue, + kUpb_WellKnown_Struct, +} upb_WellKnown; + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); + +UPB_API const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, + int i); +UPB_API int upb_MessageDef_FieldCount(const upb_MessageDef* m); + +UPB_API const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); + +// Returns a field by either JSON name or regular proto name. +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( + const upb_MessageDef* m, const char* name) { + return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); +} + +// Lookup of either field or oneof by name. Returns whether either was found. +// If the return is true, then the found def will be set, and the non-found +// one set to NULL. +UPB_API bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t size, + const upb_FieldDef** f, + const upb_OneofDef** o); +UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, + const char* name, + const upb_FieldDef** f, + const upb_OneofDef** o) { + return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name); +UPB_API const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_API const upb_FieldDef* upb_MessageDef_FindFieldByNumber( + const upb_MessageDef* m, uint32_t i); +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name); +UPB_API const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_API const char* upb_MessageDef_FullName(const upb_MessageDef* m); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m); +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m); + +// Creates a mini descriptor string for a message, returns true on success. +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out); + +UPB_API const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const char* upb_MessageDef_Name(const upb_MessageDef* m); + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i); +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i); + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); + +UPB_API const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, + int i); +UPB_API int upb_MessageDef_OneofCount(const upb_MessageDef* m); +int upb_MessageDef_RealOneofCount(const upb_MessageDef* m); + +const UPB_DESC(MessageOptions) * + upb_MessageDef_Options(const upb_MessageDef* m); +const UPB_DESC(FeatureSet) * + upb_MessageDef_ResolvedFeatures(const upb_MessageDef* m); + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m); + +UPB_API upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); +UPB_API upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_METHOD_DEF_H_ +#define UPB_REFLECTION_METHOD_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); +UPB_API const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); +UPB_API const char* upb_MethodDef_Name(const upb_MethodDef* m); +UPB_API const UPB_DESC(MethodOptions) * + upb_MethodDef_Options(const upb_MethodDef* m); +const UPB_DESC(FeatureSet) * + upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m); +UPB_API const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); +UPB_API bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +UPB_API const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ONEOF_DEF_H_ +#define UPB_REFLECTION_ONEOF_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const upb_MessageDef* upb_OneofDef_ContainingType( + const upb_OneofDef* o); +UPB_API const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +UPB_API int upb_OneofDef_FieldCount(const upb_OneofDef* o); +const char* upb_OneofDef_FullName(const upb_OneofDef* o); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size); +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num); +UPB_API const char* upb_OneofDef_Name(const upb_OneofDef* o); +int upb_OneofDef_numfields(const upb_OneofDef* o); +const UPB_DESC(OneofOptions*) upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(FeatureSet*) + upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_SERVICE_DEF_H_ +#define UPB_REFLECTION_SERVICE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name); +UPB_API const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); +int upb_ServiceDef_Index(const upb_ServiceDef* s); +UPB_API const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, + int i); +UPB_API int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); +const char* upb_ServiceDef_Name(const upb_ServiceDef* s); +UPB_API const UPB_DESC(ServiceOptions) * + upb_ServiceDef_Options(const upb_ServiceDef* s); +const UPB_DESC(FeatureSet) * + upb_ServiceDef_ResolvedFeatures(const upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_H_ */ +// IWYU pragma: end_exports + +#endif /* UPB_REFLECTION_DEF_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +enum { + kUpb_JsonDecodeResult_Ok = 0, + kUpb_JsonDecodeResult_OkWithEmptyStringNumerics = 1, + kUpb_JsonDecodeResult_Error = 2, +}; + +UPB_API int upb_JsonDecodeDetectingNonconformance(const char* buf, size_t size, + upb_Message* msg, + const upb_MessageDef* m, + const upb_DefPool* symtab, + int options, upb_Arena* arena, + upb_Status* status); + +UPB_API_INLINE bool upb_JsonDecode(const char* buf, size_t size, + upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* symtab, int options, + upb_Arena* arena, upb_Status* status) { + return upb_JsonDecodeDetectingNonconformance(buf, size, msg, m, symtab, + options, arena, status) == + kUpb_JsonDecodeResult_Ok; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONDECODE_H_ */ + +#ifndef UPB_LEX_ATOI_H_ +#define UPB_LEX_ATOI_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// We use these hand-written routines instead of strto[u]l() because the "long +// long" variants aren't in c89. Also our version allows setting a ptr limit. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ATOI_H_ */ + +#ifndef UPB_LEX_UNICODE_H_ +#define UPB_LEX_UNICODE_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true iff a codepoint is the value for a high surrogate. +UPB_INLINE bool upb_Unicode_IsHigh(uint32_t cp) { + return (cp >= 0xd800 && cp <= 0xdbff); +} + +// Returns true iff a codepoint is the value for a low surrogate. +UPB_INLINE bool upb_Unicode_IsLow(uint32_t cp) { + return (cp >= 0xdc00 && cp <= 0xdfff); +} + +// Returns the high 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToHigh(uint32_t cp) { + return (cp >> 10) + 0xd7c0; +} + +// Returns the low 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToLow(uint32_t cp) { + return (cp & 0x3ff) | 0xdc00; +} + +// Returns the 32-bit value corresponding to a pair of 16-bit surrogates. +// Does not sanity-check the input. +UPB_INLINE uint32_t upb_Unicode_FromPair(uint32_t high, uint32_t low) { + return ((high & 0x3ff) << 10) + (low & 0x3ff) + 0x10000; +} + +// Outputs a codepoint as UTF8. +// Returns the number of bytes written (1-4 on success, 0 on error). +// Does not sanity-check the input. Specifically does not check for surrogates. +int upb_Unicode_ToUTF8(uint32_t cp, char* out); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_UNICODE_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_H_ +#define UPB_REFLECTION_MESSAGE_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns a mutable pointer to a map, array, or submessage value. If the given +// arena is non-NULL this will construct a new object if it was not previously +// present. May not be called for primitive fields. +UPB_API upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a); + +// Returns the field that is set in the oneof, or NULL if none are set. +UPB_API const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o); + +// Clear all data and unknown fields. +void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m); + +// Clears any field presence and sets the value back to its default. +UPB_API void upb_Message_ClearFieldByDef(upb_Message* msg, + const upb_FieldDef* f); + +// May only be called for fields where upb_FieldDef_HasPresence(f) == true. +UPB_API bool upb_Message_HasFieldByDef(const upb_Message* msg, + const upb_FieldDef* f); + +// Returns the value in the message associated with this field def. +UPB_API upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg, + const upb_FieldDef* f); + +// Sets the given field to the given value. For a msg/array/map/string, the +// caller must ensure that the target data outlives |msg| (by living either in +// the same arena or a different arena that outlives it). +// +// Returns false if allocation fails. +UPB_API bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a); + +// Iterate over present fields. +// +// size_t iter = kUpb_Message_Begin; +// const upb_FieldDef *f; +// upb_MessageValue val; +// while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { +// process_field(f, val); +// } +// +// If ext_pool is NULL, no extensions will be returned. If the given symtab +// returns extensions that don't match what is in this message, those extensions +// will be skipped. + +#define kUpb_Message_Begin -1 + +UPB_API bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, + const upb_FieldDef** f, upb_MessageValue* val, + size_t* iter); + +// Clears all unknown field data from this message and all submessages. +UPB_API bool upb_Message_DiscardUnknown(upb_Message* msg, + const upb_MessageDef* m, int maxdepth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_H_ */ + +#ifndef UPB_JSON_ENCODE_H_ +#define UPB_JSON_ENCODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* When set, emits 0/default values. TODO: proto3 only? */ + upb_JsonEncode_EmitDefaults = 1 << 0, + + /* When set, use normal (snake_case) field names instead of JSON (camelCase) + names. */ + upb_JsonEncode_UseProtoNames = 1 << 1, + + /* When set, emits enums as their integer values instead of as their names. */ + upb_JsonEncode_FormatEnumsAsIntegers = 1 << 2 +}; + +/* Encodes the given |msg| to JSON format. The message's reflection is given in + * |m|. The DefPool in |ext_pool| is used to find extensions (if NULL, + * extensions will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +UPB_API size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, + char* buf, size_t size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONENCODE_H_ */ + +#ifndef UPB_LEX_ROUND_TRIP_H_ +#define UPB_LEX_ROUND_TRIP_H_ + +// Must be last. + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. + +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; + +#ifdef __cplusplus +extern "C" { +#endif + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ROUND_TRIP_H_ */ + +#ifndef UPB_PORT_VSNPRINTF_COMPAT_H_ +#define UPB_PORT_VSNPRINTF_COMPAT_H_ + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif +} + + +#endif // UPB_PORT_VSNPRINTF_COMPAT_H_ + +#ifndef UPB_PORT_ATOMIC_H_ +#define UPB_PORT_ATOMIC_H_ + + +#ifdef UPB_USE_C11_ATOMICS + +// IWYU pragma: begin_exports +#include +#include +// IWYU pragma: end_exports + +#define upb_Atomic_Init(addr, val) atomic_init(addr, val) +#define upb_Atomic_Load(addr, order) atomic_load_explicit(addr, order) +#define upb_Atomic_Store(addr, val, order) \ + atomic_store_explicit(addr, val, order) +#define upb_Atomic_Add(addr, val, order) \ + atomic_fetch_add_explicit(addr, val, order) +#define upb_Atomic_Sub(addr, val, order) \ + atomic_fetch_sub_explicit(addr, val, order) +#define upb_Atomic_Exchange(addr, val, order) \ + atomic_exchange_explicit(addr, val, order) +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + atomic_compare_exchange_strong_explicit(addr, expected, desired, \ + success_order, failure_order) +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + atomic_compare_exchange_weak_explicit(addr, expected, desired, \ + success_order, failure_order) + +#else // !UPB_USE_C11_ATOMICS + +#include + +#define upb_Atomic_Init(addr, val) (*addr = val) +#define upb_Atomic_Load(addr, order) (*addr) +#define upb_Atomic_Store(addr, val, order) (*(addr) = val) +#define upb_Atomic_Add(addr, val, order) (*(addr) += val) +#define upb_Atomic_Sub(addr, val, order) (*(addr) -= val) + +UPB_INLINE void* _upb_NonAtomic_Exchange(void* addr, void* value) { + void* old; + memcpy(&old, addr, sizeof(value)); + memcpy(addr, &value, sizeof(value)); + return old; +} + +#define upb_Atomic_Exchange(addr, val, order) _upb_NonAtomic_Exchange(addr, val) + +// `addr` and `expected` are logically double pointers. +UPB_INLINE bool _upb_NonAtomic_CompareExchangeStrongP(void* addr, + void* expected, + void* desired) { + if (memcmp(addr, expected, sizeof(desired)) == 0) { + memcpy(addr, &desired, sizeof(desired)); + return true; + } else { + memcpy(expected, addr, sizeof(desired)); + return false; + } +} + +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + _upb_NonAtomic_CompareExchangeStrongP((void*)addr, (void*)expected, \ + (void*)desired) +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + upb_Atomic_CompareExchangeStrong(addr, expected, desired, 0, 0) + +#endif + + +#endif // UPB_PORT_ATOMIC_H_ + +#ifndef UPB_MESSAGE_COMPAT_H_ +#define UPB_MESSAGE_COMPAT_H_ + +#include + + +// Must be last. + +// upb does not support mixing minitables from different sources but these +// functions are still used by some existing users so for now we make them +// available here. This may or may not change in the future so do not add +// them to new code. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTableExtension* upb_Message_ExtensionByIndex( + const upb_Message* msg, size_t index); + +// Returns the minitable with the given field number, or NULL on failure. +const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( + const upb_Message* msg, uint32_t field_number); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_COMPAT_H_ */ + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ +#define UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ + +#include + + +#ifndef UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ +#define UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ + +#include + + +// Map entries aren't actually stored for map fields, they are only used during +// parsing. (It helps a lot if all map entry messages have the same layout.) +// The mini_table layout code will ensure that all map entries have this layout. +// +// Note that users can and do create map entries directly, which will also use +// this layout. + +typedef struct { + struct upb_Message message; + // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here, + // and the uint64_t helps make this clear. + uint64_t hasbits; + union { + upb_StringView str; // For str/bytes. + upb_value val; // For all other types. + double d[2]; // Padding for 32-bit builds. + } k; + union { + upb_StringView str; // For str/bytes. + upb_value val; // For all other types. + double d[2]; // Padding for 32-bit builds. + } v; +} upb_MapEntry; + +#endif // UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. + +typedef struct { + void const** entries; + int size; + int cap; +} _upb_mapsorter; + +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) upb_gfree(s->entries); +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, + const struct upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = (const upb_tabent*)s->entries[sorted->pos++]; + upb_StringView key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + +UPB_INLINE bool _upb_sortedmap_nextext(_upb_mapsorter* s, + _upb_sortedmap* sorted, + const upb_Extension** ext) { + if (sorted->pos == sorted->end) return false; + *ext = (const upb_Extension*)s->entries[sorted->pos++]; + return true; +} + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const struct upb_Map* map, _upb_sortedmap* sorted); + +bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts, + size_t count, _upb_sortedmap* sorted); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */ + +#ifndef UPB_BASE_INTERNAL_LOG2_H_ +#define UPB_BASE_INTERNAL_LOG2_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE int upb_Log2Ceiling(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while ((1 << lg2) < x) lg2++; + return lg2; +#endif +} + +UPB_INLINE int upb_Log2CeilingSize(int x) { return 1 << upb_Log2Ceiling(x); } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_LOG2_H_ */ + +#ifndef UPB_MESSAGE_COMPARE_H_ +#define UPB_MESSAGE_COMPARE_H_ + +#include + + +// Must be last. + +enum { + // If set, upb_Message_IsEqual() will attempt to compare unknown fields. + // By its very nature this comparison is inexact. + kUpb_CompareOption_IncludeUnknownFields = (1 << 0) +}; + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true if no known fields or extensions are set in the message. +UPB_API bool upb_Message_IsEmpty(const upb_Message* msg, + const upb_MiniTable* m); + +UPB_API bool upb_Message_IsEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, int options); + +// If |ctype| is a message then |m| must point to its minitable. +UPB_API_INLINE bool upb_MessageValue_IsEqual(upb_MessageValue val1, + upb_MessageValue val2, + upb_CType ctype, + const upb_MiniTable* m, + int options) { + switch (ctype) { + case kUpb_CType_Bool: + return val1.bool_val == val2.bool_val; + + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return val1.int32_val == val2.int32_val; + + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return val1.int64_val == val2.int64_val; + + case kUpb_CType_String: + case kUpb_CType_Bytes: + return upb_StringView_IsEqual(val1.str_val, val2.str_val); + + case kUpb_CType_Message: + return upb_Message_IsEqual(val1.msg_val, val2.msg_val, m, options); + + default: + UPB_UNREACHABLE(); + return false; + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COMPARE_H_ + +#ifndef UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ +#define UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true if unknown fields from the two messages are equal when sorted +// and varints are made canonical. +// +// This function is discouraged, as the comparison is inherently lossy without +// schema data: +// +// 1. We don't know whether delimited fields are sub-messages. Unknown +// sub-messages will therefore not have their fields sorted and varints +// canonicalized. +// 2. We don't know about oneof/non-repeated fields, which should semantically +// discard every value except the last. + +typedef enum { + kUpb_UnknownCompareResult_Equal = 0, + kUpb_UnknownCompareResult_NotEqual = 1, + kUpb_UnknownCompareResult_OutOfMemory = 2, + kUpb_UnknownCompareResult_MaxDepthExceeded = 3, +} upb_UnknownCompareResult; + +upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( + const char* buf1, size_t size1, const char* buf2, size_t size2, + int max_depth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ */ + +#ifndef THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_ +#define THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_ + +#include + + +// Must be last. + +#define kUpb_BaseField_Begin ((size_t)-1) +#define kUpb_Extension_Begin ((size_t)-1) + +bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField** out_f, + upb_MessageValue* out_v, + size_t* iter); + +bool UPB_PRIVATE(_upb_Message_NextExtension)( + const upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableExtension** out_e, upb_MessageValue* out_v, + size_t* iter); +#endif // THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_ + +#ifndef UPB_MESSAGE_COPY_H_ +#define UPB_MESSAGE_COPY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Deep clones a message using the provided target arena. +upb_Message* upb_Message_DeepClone(const upb_Message* msg, + const upb_MiniTable* m, upb_Arena* arena); + +// Shallow clones a message using the provided target arena. +upb_Message* upb_Message_ShallowClone(const upb_Message* msg, + const upb_MiniTable* m, upb_Arena* arena); + +// Deep clones array contents. +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena); + +// Deep clones map contents. +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena); + +// Deep copies the message from src to dst. +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* m, upb_Arena* arena); + +// Shallow copies the message from src to dst. +void upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COPY_H_ +#ifndef THIRD_PARTY_UPB_UPB_MESSAGE_MERGE_H_ +#define THIRD_PARTY_UPB_UPB_MESSAGE_MERGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API bool upb_Message_MergeFrom(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // THIRD_PARTY_UPB_UPB_MESSAGE_MERGE_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE char _upb_ToBase92(int8_t ch) { + extern const char _kUpb_ToBase92[]; + UPB_ASSERT(0 <= ch && ch < 92); + return _kUpb_ToBase92[ch]; +} + +UPB_INLINE char _upb_FromBase92(uint8_t ch) { + extern const int8_t _kUpb_FromBase92[]; + if (' ' > ch || ch > '~') return -1; + return _kUpb_FromBase92[ch - ' ']; +} + +UPB_INLINE const char* _upb_Base92_DecodeVarint(const char* ptr, + const char* end, char first_ch, + uint8_t min, uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + upb_Log2Ceiling(_upb_FromBase92(max) - _upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = _upb_FromBase92(ch) - _upb_FromBase92(min); + val |= bits << shift; + if (ptr == end || *ptr < min || max < *ptr) { + *out_val = val; + UPB_ASSUME(ptr != NULL); + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) return NULL; + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ + + +// Must be last. + +// upb_MdDecoder: used internally for decoding MiniDescriptors for messages, +// extensions, and enums. +typedef struct { + const char* end; + upb_Status* status; + jmp_buf err; +} upb_MdDecoder; + +UPB_PRINTF(2, 3) +UPB_NORETURN UPB_INLINE void upb_MdDecoder_ErrorJmp(upb_MdDecoder* d, + const char* fmt, ...) { + if (d->status) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + } + UPB_LONGJMP(d->err, 1); +} + +UPB_INLINE void upb_MdDecoder_CheckOutOfMemory(upb_MdDecoder* d, + const void* ptr) { + if (!ptr) upb_MdDecoder_ErrorJmp(d, "Out of memory"); +} + +UPB_INLINE const char* upb_MdDecoder_DecodeBase92Varint( + upb_MdDecoder* d, const char* ptr, char first_ch, uint8_t min, uint8_t max, + uint32_t* out_val) { + ptr = _upb_Base92_DecodeVarint(ptr, d->end, first_ch, min, max, out_val); + if (!ptr) upb_MdDecoder_ErrorJmp(d, "Overlong varint"); + return ptr; +} + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ + + +// Must be last. + +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_OpenEnum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + kUpb_EncodedType_ClosedEnum = 18, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; + +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsRequired = 1 << 1, + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_FlipValidateUtf8 = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'I', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; + +enum { + kUpb_EncodedVersion_EnumV1 = '!', + kUpb_EncodedVersion_ExtensionV1 = '#', + kUpb_EncodedVersion_MapV1 = '%', + kUpb_EncodedVersion_MessageV1 = '$', + kUpb_EncodedVersion_MessageSetV1 = '&', +}; + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ + +// Must be last. + +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, + kUpb_FieldModifier_ValidateUtf8 = 1 << 5, +} kUpb_FieldModifier; + +// These modifiers are also used on the wire. +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ + +#ifndef UPB_MINI_TABLE_COMPAT_H_ +#define UPB_MINI_TABLE_COMPAT_H_ + + +// Must be last. + +// upb does not support mixing minitables from different sources but these +// functions are still used by some existing users so for now we make them +// available here. This may or may not change in the future so do not add +// them to new code. + +#ifdef __cplusplus +extern "C" { +#endif + +// Checks if memory layout of src is compatible with dst. +bool upb_MiniTable_Compatible(const upb_MiniTable* src, + const upb_MiniTable* dst); + +typedef enum { + kUpb_MiniTableEquals_NotEqual, + kUpb_MiniTableEquals_Equal, + kUpb_MiniTableEquals_OutOfMemory, +} upb_MiniTableEquals_Status; + +// Checks equality of mini tables originating from different language runtimes. +upb_MiniTableEquals_Status upb_MiniTable_Equals(const upb_MiniTable* src, + const upb_MiniTable* dst); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_COMPAT_H_ */ + +#ifndef UPB_HASH_INT_TABLE_H_ +#define UPB_HASH_INT_TABLE_H_ + + +// Must be last. + +typedef struct { + upb_table t; // For entries that don't fit in the array part. + const upb_tabval* array; // Array part of the table. See const note above. + size_t array_size; // Array part size. + size_t array_count; // Array part number of elements. +} upb_inttable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +bool upb_inttable_init(upb_inttable* table, upb_Arena* a); + +// Returns the number of values in the table. +size_t upb_inttable_count(const upb_inttable* t); + +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. +// The value must not be UINTPTR_MAX. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a); + +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); + +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); + +// Updates an existing entry in an inttable. +// If the entry does not exist, returns false and does nothing. +// Unlike insert/remove, this does not invalidate iterators. +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); + +// Optimizes the table for the current set of entries, for both memory use and +// lookup time. Client should call this after all entries have been inserted; +// inserting more entries is legal, but will likely require a table resize. +void upb_inttable_compact(upb_inttable* t, upb_Arena* a); + +// Iteration over inttable: +// +// intptr_t iter = UPB_INTTABLE_BEGIN; +// uintptr_t key; +// upb_value val; +// while (upb_inttable_next(t, &key, &val, &iter)) { +// // ... +// } + +#define UPB_INTTABLE_BEGIN -1 + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_INT_TABLE_H_ */ + +#ifndef UPB_WIRE_INTERNAL_CONSTANTS_H_ +#define UPB_WIRE_INTERNAL_CONSTANTS_H_ + +#define kUpb_WireFormat_DefaultDepthLimit 100 + +// MessageSet wire format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required bytes message = 3; +// } +// } + +enum { + kUpb_MsgSet_Item = 1, + kUpb_MsgSet_TypeId = 2, + kUpb_MsgSet_Message = 3, +}; + +#endif /* UPB_WIRE_INTERNAL_CONSTANTS_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_WIRE_INTERNAL_DECODER_H_ +#define UPB_WIRE_INTERNAL_DECODER_H_ + +#include "utf8_range.h" + +// Must be last. + +#define DECODE_NOGROUP (uint32_t) - 1 + +typedef struct upb_Decoder { + upb_EpsCopyInputStream input; + const upb_ExtensionRegistry* extreg; + const char* unknown; // Start of unknown data, preserve at buffer flip + upb_Message* unknown_msg; // Pointer to preserve data to + int depth; // Tracks recursion depth to bound stack usage. + uint32_t end_group; // field number of END_GROUP tag, else DECODE_NOGROUP. + uint16_t options; + bool missing_required; + union { + upb_Arena arena; + void* foo[UPB_ARENA_SIZE_HACK]; + }; + upb_DecodeStatus status; + jmp_buf err; + +#ifndef NDEBUG + const char* debug_tagstart; + const char* debug_valstart; +#endif +} upb_Decoder; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(const char* ptr, int len) { + return utf8_range_IsValid(ptr, len); +} + +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* m); + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { + return ((intptr_t)tablep << 8) | tablep->UPB_PRIVATE(table_mask); +} + +UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { + return (const upb_MiniTable*)(table >> 8); +} + +const char* _upb_Decoder_IsDoneFallback(upb_EpsCopyInputStream* e, + const char* ptr, int overrun); + +UPB_INLINE bool _upb_Decoder_IsDone(upb_Decoder* d, const char** ptr) { + return upb_EpsCopyInputStream_IsDoneWithCallback( + &d->input, ptr, &_upb_Decoder_IsDoneFallback); +} + +UPB_INLINE const char* _upb_Decoder_BufferFlipCallback( + upb_EpsCopyInputStream* e, const char* old_end, const char* new_start) { + upb_Decoder* d = (upb_Decoder*)e; + if (!old_end) _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + + if (d->unknown) { + if (!UPB_PRIVATE(_upb_Message_AddUnknown)( + d->unknown_msg, d->unknown, old_end - d->unknown, &d->arena)) { + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + d->unknown = new_start; + } + return new_start; +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* _upb_FastDecoder_TagDispatch(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t tag) { + const upb_MiniTable* table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->UPB_PRIVATE(fasttable)[idx].field_data ^ tag; + UPB_MUSTTAIL return table_p->UPB_PRIVATE(fasttable)[idx].field_parser( + d, ptr, msg, table, hasbits, data); +} +#endif + +UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + + +#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */ + +#ifndef UPB_WIRE_READER_H_ +#define UPB_WIRE_READER_H_ + + +#ifndef UPB_WIRE_INTERNAL_READER_H_ +#define UPB_WIRE_INTERNAL_READER_H_ + +// Must be last. + +#define kUpb_WireReader_WireTypeBits 3 +#define kUpb_WireReader_WireTypeMask 7 + +typedef struct { + const char* ptr; + uint64_t val; +} UPB_PRIVATE(_upb_WireReader_LongVarint); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); + +UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( + const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)byte; + return ptr + 1; + } + const char* start = ptr; + UPB_PRIVATE(_upb_WireReader_LongVarint) + res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); + if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || + res.val > maxval) { + return NULL; // Malformed. + } + *val = res.val; + return res.ptr; +} + +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { + return tag >> kUpb_WireReader_WireTypeBits; +} + +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { + return tag & kUpb_WireReader_WireTypeMask; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_READER_H_ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ + +// Must be last. + +// The upb_WireReader interface is suitable for general-purpose parsing of +// protobuf binary wire format. It is designed to be used along with +// upb_EpsCopyInputStream for buffering, and all parsing routines in this file +// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is +// available to read without any bounds checks. + +#ifdef __cplusplus +extern "C" { +#endif + +// Parses a tag into `tag`, and returns a pointer past the end of the tag, or +// NULL if there was an error in the tag data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, + uint32_t* tag) { + uint64_t val; + ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); + if (!ptr) return NULL; + *tag = val; + return ptr; +} + +// Given a tag, returns the field number. +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); + +// Given a tag, returns the wire type. +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); + +UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, + uint64_t* val) { + return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); +} + +// Skips data for a varint, returning a pointer past the end of the varint, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) { + uint64_t val; + return upb_WireReader_ReadVarint(ptr, &val); +} + +// Reads a varint indicating the size of a delimited field into `size`, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) { + uint64_t size64; + ptr = upb_WireReader_ReadVarint(ptr, &size64); + if (!ptr || size64 >= INT32_MAX) return NULL; + *size = size64; + return ptr; +} + +// Reads a fixed32 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { + uint32_t uval; + memcpy(&uval, ptr, 4); + uval = upb_BigEndian32(uval); + memcpy(val, &uval, 4); + return ptr + 4; +} + +// Reads a fixed64 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { + uint64_t uval; + memcpy(&uval, ptr, 8); + uval = upb_BigEndian64(uval); + memcpy(val, &uval, 8); + return ptr + 8; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream); + +// Skips data for a group, returning a pointer past the end of the group, or +// NULL if there was an error parsing the group. The `tag` argument should be +// the start group tag that begins the group. The `depth_limit` argument +// indicates how many levels of recursion the group is allowed to have before +// reporting a parse error (this limit exists to protect against stack +// overflow). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipGroup( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); +} + +UPB_INLINE const char* _upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + switch (upb_WireReader_GetWireType(tag)) { + case kUpb_WireType_Varint: + return upb_WireReader_SkipVarint(ptr); + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + if (!ptr) return NULL; + ptr += size; + return ptr; + } + case kUpb_WireType_StartGroup: + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, + stream); + case kUpb_WireType_EndGroup: + return NULL; // Should be handled before now. + default: + return NULL; // Unknown wire type. + } +} + +// Skips data for a wire value of any type, returning a pointer past the end of +// the data, or NULL if there was an error parsing the group. The `tag` argument +// should be the tag that was just parsed. The `depth_limit` argument indicates +// how many levels of recursion a group is allowed to have before reporting a +// parse error (this limit exists to protect against stack overflow). +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return _upb_WireReader_SkipValue(ptr, tag, 100, stream); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_READER_H_ + +#ifndef UPB_LEX_STRTOD_H_ +#define UPB_LEX_STRTOD_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +double _upb_NoLocaleStrtod(const char *str, char **endptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_STRTOD_H_ */ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ + +#include + + +// Must be last. + +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 + +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; + +#ifdef __cplusplus +extern "C" { +#endif + +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// unit64_t msg_mod = ...; // bitwise & of kUpb_MessageModifiers or zero +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr, msg_mod); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); + +// Encodes an entire mini descriptor for an extension. +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); + +// Encodes an entire mini descriptor for a map. +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, uint64_t key_mod, + uint64_t value_mod); + +// Encodes an entire mini descriptor for a message set. +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ */ + +#ifndef UPB_REFLECTION_DEF_POOL_INTERNAL_H_ +#define UPB_REFLECTION_DEF_POOL_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + const upb_FieldDef* f); +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status); +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v); + +void** _upb_DefPool_ScratchData(const upb_DefPool* s); +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); +void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform); + +// For generated code only: loads a generated descriptor. +typedef struct _upb_DefPool_Init { + struct _upb_DefPool_Init** deps; // Dependencies of this file. + const upb_MiniTableFile* layout; + const char* filename; + upb_StringView descriptor; // Serialized descriptor. +} _upb_DefPool_Init; + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); + +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ +#define UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ + + +// Must be last. + +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define UPB_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \ + if (UPB_DESC(desc_type##_has_options)(proto)) { \ + size_t size; \ + char* pb = UPB_DESC(options_type##_serialize)( \ + UPB_DESC(desc_type##_options)(proto), ctx->tmp_arena, &size); \ + if (!pb) _upb_DefBuilder_OomErr(ctx); \ + target = \ + UPB_DESC(options_type##_parse)(pb, size, _upb_DefBuilder_Arena(ctx)); \ + if (!target) _upb_DefBuilder_OomErr(ctx); \ + } else { \ + target = (const UPB_DESC(options_type)*)kUpbDefOptDefault; \ + } + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_DefBuilder { + upb_DefPool* symtab; + upb_strtable feature_cache; // Caches features by identity. + UPB_DESC(FeatureSet*) legacy_features; // For computing legacy features. + char* tmp_buf; // Temporary buffer in tmp_arena. + size_t tmp_buf_size; // Size of temporary buffer. + upb_FileDef* file; // File we are building. + upb_Arena* arena; // Allocate defs here. + upb_Arena* tmp_arena; // For temporary allocations. + upb_Status* status; // Record errors here. + const upb_MiniTableFile* layout; // NULL if we should build layouts. + upb_MiniTablePlatform platform; // Platform we are targeting. + int enum_count; // Count of enums built so far. + int msg_count; // Count of messages built so far. + int ext_count; // Count of extensions built so far. + jmp_buf err; // longjmp() on error. +}; + +extern const char* kUpbDefOptDefault; + +// ctx->status has already been set elsewhere so just fail/longjmp() +UPB_NORETURN void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx); + +UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, + ...) UPB_PRINTF(2, 3); +UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx); + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name); + +// Given a symbol and the base symbol inside which it is defined, +// find the symbol's definition. +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type); + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type); + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end); + +const char* _upb_DefBuilder_FullToShort(const char* fullname); + +UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +// Adds a symbol |v| to the symtab, which must be a def pointer previously +// packed with pack_def(). The def's pointer to upb_FileDef* must be set before +// adding, so we know which entries to remove if building this file fails. +UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, + upb_value v) { + upb_StringView sym = {.data = name, .size = strlen(name)}; + bool ok = _upb_DefPool_InsertSym(ctx->symtab, sym, v, ctx->status); + if (!ok) _upb_DefBuilder_FailJmp(ctx); +} + +UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) { + return ctx->arena; +} + +UPB_INLINE upb_FileDef* _upb_DefBuilder_File(const upb_DefBuilder* ctx) { + return ctx->file; +} + +// This version of CheckIdent() is only called by other, faster versions after +// they detect a parsing error. +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full); + +// Verify a full identifier string. This is slightly more complicated than +// verifying a relative identifier string because we must track '.' chars. +UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + bool start = true; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & !start; + const bool is_dot = (c == '.') & !start; + + good &= is_alpha | is_numer | is_dot; + start = is_dot; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); +} + +// Returns true if the returned feature set is new and must be populated. +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set); + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit); + +UPB_INLINE const UPB_DESC(FeatureSet*) + _upb_DefBuilder_ResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child) { + return _upb_DefBuilder_DoResolveFeatures(ctx, parent, child, false); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); + +// Allocate and initialize an array of |n| enum defs. +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, + bool* is_sorted); + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ +#define UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); + +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f); +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f); +void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, + const upb_FieldDef* f); + +// Allocate and initialize an array of |n| extensions (field defs). +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m); + +// Allocate and initialize an array of |n| field defs. +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted); + +// Allocate and return a list of pointers to the |n| field defs in |ff|, +// sorted by field number. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_FILE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_FILE_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i); +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); + +// upb_FileDef_Package() returns "" if f->package is NULL, this does not. +const char* _upb_FileDef_RawPackage(const upb_FileDef* f); + +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const UPB_DESC(FileDescriptorProto) * file_proto); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FILE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size, + upb_value v, upb_Arena* a); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f); +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n); +void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m); +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); + +// Allocate and initialize an array of |n| service defs. +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "\n\023\030\204\007\"\000*\014\010\001\020\002\030\002 \003(\0010\002\n\023\030\347\007\"\000*\014\010\002\020\001\030\001 \002(\0010\001\n\023\030\350\007\"\014\010\001\020\001\030\001 \002(\0010\001*\000 \346\007(\350\007" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +#ifndef UPB_REFLECTION_DESC_STATE_INTERNAL_H_ +#define UPB_REFLECTION_DESC_STATE_INTERNAL_H_ + + +// Must be last. + +// Manages the storage for mini descriptor strings as they are being encoded. +// TODO: Move some of this state directly into the encoder, maybe. +typedef struct { + upb_MtDataEncoder e; + size_t bufsize; + char* buf; + char* ptr; +} upb_DescState; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { + d->bufsize = kUpb_MtDataEncoder_MinSize * 2; + d->buf = NULL; + d->ptr = NULL; +} + +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |e|. +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto_EnumReservedRange*) const* protos, + const upb_EnumDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_INTERNAL_STRDUP2_H_ +#define UPB_REFLECTION_INTERNAL_STRDUP2_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Variant that works with a length-delimited rather than NULL-delimited string, +// as supported by strtable. +char* upb_strdup2(const char* s, size_t len, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_INTERNAL_STRDUP2_H_ */ + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); + +// Allocate and initialize an array of |n| extension ranges owned by |m|. +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i); +void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, + const upb_FieldDef* f, const char* name, size_t size); + +// Allocate and initialize an array of |n| oneof defs owned by |m|. +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m); + +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |m|. +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto_ReservedRange) * const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ +#define UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); + +// Allocate and initialize an array of |n| method defs owned by |s|. +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ */ + +// This should #undef all macros #defined in def.inc + +#undef UPB_SIZE +#undef UPB_PTR_AT +#undef UPB_MAPTYPE_STRING +#undef UPB_EXPORT +#undef UPB_INLINE +#undef UPB_API +#undef UPBC_API +#undef UPB_API_INLINE +#undef UPB_ALIGN_UP +#undef UPB_ALIGN_DOWN +#undef UPB_ALIGN_MALLOC +#undef UPB_ALIGN_OF +#undef UPB_ALIGN_AS +#undef UPB_MALLOC_ALIGN +#undef UPB_LIKELY +#undef UPB_UNLIKELY +#undef UPB_FORCEINLINE +#undef UPB_NOINLINE +#undef UPB_NORETURN +#undef UPB_PRINTF +#undef UPB_MAX +#undef UPB_MIN +#undef UPB_UNUSED +#undef UPB_ASSUME +#undef UPB_ASSERT +#undef UPB_UNREACHABLE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE_MASK +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT +#undef UPB_POISON_MEMORY_REGION +#undef UPB_UNPOISON_MEMORY_REGION +#undef UPB_ASAN +#undef UPB_ASAN_GUARD_SIZE +#undef UPB_CLANG_ASAN +#undef UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN +#undef UPB_DESCRIPTOR_UPB_H_FILENAME +#undef UPB_DESC +#undef UPB_DESC_MINITABLE +#undef UPB_IS_GOOGLE3 +#undef UPB_ATOMIC +#undef UPB_USE_C11_ATOMICS +#undef UPB_PRIVATE +#undef UPB_ONLYBITS +#undef UPB_LINKARR_DECLARE +#undef UPB_LINKARR_APPEND +#undef UPB_LINKARR_START +#undef UPB_LINKARR_STOP +#undef UPB_FUTURE_BREAKING_CHANGES +#undef UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.c new file mode 100755 index 00000000..dd182bc2 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.c @@ -0,0 +1,69 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "shared_convert.h" + +bool shared_Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + upb_CType type, const upb_MessageDef* msgdef, + upb_Status* status) { + switch (type) { + case kUpb_CType_Bool: + return memcmp(&val1, &val2, 1) == 0; + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return memcmp(&val1, &val2, 4) == 0; + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return memcmp(&val1, &val2, 8) == 0; + case kUpb_CType_String: + case kUpb_CType_Bytes: + return val1.str_val.size == val2.str_val.size && + memcmp(val1.str_val.data, val2.str_val.data, val1.str_val.size) == + 0; + case kUpb_CType_Message: { + const upb_MiniTable* m = upb_MessageDef_MiniTable(msgdef); + const int options = 0; + return upb_Message_IsEqual(val1.msg_val, val2.msg_val, m, options); + } + default: + upb_Status_SetErrorMessage(status, "Internal error, unexpected type"); + return false; + } +} + +uint64_t shared_Msgval_GetHash(upb_MessageValue val, upb_CType type, + const upb_MessageDef* msgdef, uint64_t seed, + upb_Status* status) { + switch (type) { + case kUpb_CType_Bool: + return _upb_Hash(&val, 1, seed); + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return _upb_Hash(&val, 4, seed); + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return _upb_Hash(&val, 8, seed); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return _upb_Hash(val.str_val.data, val.str_val.size, seed); + case kUpb_CType_Message: + return shared_Message_Hash(val.msg_val, msgdef, seed, status); + default: + upb_Status_SetErrorMessage(status, "Internal error, unexpected type"); + return 0; + } +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.h new file mode 100755 index 00000000..ca1e91d5 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_convert.h @@ -0,0 +1,26 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#ifndef RUBY_PROTOBUF_SHARED_CONVERT_H_ +#define RUBY_PROTOBUF_SHARED_CONVERT_H_ + +#include "ruby-upb.h" +#include "shared_message.h" + +bool shared_Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + upb_CType type, const upb_MessageDef* msgdef, + upb_Status* status); + +uint64_t shared_Msgval_GetHash(upb_MessageValue val, upb_CType type, + const upb_MessageDef* msgdef, uint64_t seed, + upb_Status* status); + +#endif // RUBY_PROTOBUF_SHARED_CONVERT_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.c new file mode 100755 index 00000000..122682ec --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.c @@ -0,0 +1,37 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby Message functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "shared_message.h" + +// Support function for Message_Hash. Returns a hash value for the given +// message. +uint64_t shared_Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed, upb_Status* status) { + upb_Arena* arena = upb_Arena_New(); + char* data; + size_t size; + + // Hash a deterministically serialized payloads with no unknown fields. + upb_EncodeStatus encode_status = upb_Encode( + msg, upb_MessageDef_MiniTable(m), + kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena, + &data, &size); + + if (encode_status == kUpb_EncodeStatus_Ok) { + uint64_t ret = _upb_Hash(data, size, seed); + upb_Arena_Free(arena); + return ret; + } + + upb_Arena_Free(arena); + upb_Status_SetErrorMessage(status, "Error calculating hash"); + return 0; +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.h new file mode 100755 index 00000000..50722087 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/shared_message.h @@ -0,0 +1,21 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby Message functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#ifndef RUBY_PROTOBUF_SHARED_MESSAGE_H_ +#define RUBY_PROTOBUF_SHARED_MESSAGE_H_ + +#include "ruby-upb.h" + +// Returns a hash value for the given message. +uint64_t shared_Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed, upb_Status* status); + +#endif // RUBY_PROTOBUF_SHARED_MESSAGE_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/LICENSE b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/LICENSE new file mode 100755 index 00000000..e59f14fa --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2019 Yibo Cai +Copyright 2022 Google LLC + +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/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c new file mode 100755 index 00000000..9564b07e --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c @@ -0,0 +1,467 @@ +// Copyright 2023 Google LLC +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +/* This is a wrapper for the Google range-sse.cc algorithm which checks whether + * a sequence of bytes is a valid UTF-8 sequence and finds the longest valid + * prefix of the UTF-8 sequence. + * + * The key difference is that it checks for as much ASCII symbols as possible + * and then falls back to the range-sse.cc algorithm. The changes to the + * algorithm are cosmetic, mostly to trick the clang compiler to produce optimal + * code. + * + * For API see the utf8_validity.h header. + */ +#include "utf8_range.h" + +#include +#include +#include + +#ifdef __SSE4_1__ +#include +#include +#include +#endif + +#if defined(__GNUC__) +#define FORCE_INLINE_ATTR __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define FORCE_INLINE_ATTR __forceinline +#else +#define FORCE_INLINE_ATTR +#endif + +static FORCE_INLINE_ATTR inline uint64_t utf8_range_UnalignedLoad64( + const void* p) { + uint64_t t; + memcpy(&t, p, sizeof t); + return t; +} + +static FORCE_INLINE_ATTR inline int utf8_range_AsciiIsAscii(unsigned char c) { + return c < 128; +} + +static FORCE_INLINE_ATTR inline int utf8_range_IsTrailByteOk(const char c) { + return (int8_t)(c) <= (int8_t)(0xBF); +} + +/* If return_position is false then it returns 1 if |data| is a valid utf8 + * sequence, otherwise returns 0. + * If return_position is set to true, returns the length in bytes of the prefix + of |data| that is all structurally valid UTF-8. + */ +static size_t utf8_range_ValidateUTF8Naive(const char* data, const char* end, + int return_position) { + /* We return err_pos in the loop which is always 0 if !return_position */ + size_t err_pos = 0; + size_t codepoint_bytes = 0; + /* The early check is done because of early continue's on codepoints of all + * sizes, i.e. we first check for ascii and if it is, we call continue, then + * for 2 byte codepoints, etc. This is done in order to reduce indentation and + * improve readability of the codepoint validity check. + */ + while (data + codepoint_bytes < end) { + if (return_position) { + err_pos += codepoint_bytes; + } + data += codepoint_bytes; + const size_t len = end - data; + const unsigned char byte1 = data[0]; + + /* We do not skip many ascii bytes at the same time as this function is + used for tail checking (< 16 bytes) and for non x86 platforms. We also + don't think that cases where non-ASCII codepoints are followed by ascii + happen often. For small strings it also introduces some penalty. For + purely ascii UTF8 strings (which is the overwhelming case) we call + SkipAscii function which is multiplatform and extremely fast. + */ + /* [00..7F] ASCII -> 1 byte */ + if (utf8_range_AsciiIsAscii(byte1)) { + codepoint_bytes = 1; + continue; + } + /* [C2..DF], [80..BF] -> 2 bytes */ + if (len >= 2 && byte1 >= 0xC2 && byte1 <= 0xDF && + utf8_range_IsTrailByteOk(data[1])) { + codepoint_bytes = 2; + continue; + } + if (len >= 3) { + const unsigned char byte2 = data[1]; + const unsigned char byte3 = data[2]; + + /* Is byte2, byte3 between [0x80, 0xBF] + * Check for 0x80 was done above. + */ + if (!utf8_range_IsTrailByteOk(byte2) || + !utf8_range_IsTrailByteOk(byte3)) { + return err_pos; + } + + if (/* E0, A0..BF, 80..BF */ + ((byte1 == 0xE0 && byte2 >= 0xA0) || + /* E1..EC, 80..BF, 80..BF */ + (byte1 >= 0xE1 && byte1 <= 0xEC) || + /* ED, 80..9F, 80..BF */ + (byte1 == 0xED && byte2 <= 0x9F) || + /* EE..EF, 80..BF, 80..BF */ + (byte1 >= 0xEE && byte1 <= 0xEF))) { + codepoint_bytes = 3; + continue; + } + if (len >= 4) { + const unsigned char byte4 = data[3]; + /* Is byte4 between 0x80 ~ 0xBF */ + if (!utf8_range_IsTrailByteOk(byte4)) { + return err_pos; + } + + if (/* F0, 90..BF, 80..BF, 80..BF */ + ((byte1 == 0xF0 && byte2 >= 0x90) || + /* F1..F3, 80..BF, 80..BF, 80..BF */ + (byte1 >= 0xF1 && byte1 <= 0xF3) || + /* F4, 80..8F, 80..BF, 80..BF */ + (byte1 == 0xF4 && byte2 <= 0x8F))) { + codepoint_bytes = 4; + continue; + } + } + } + return err_pos; + } + if (return_position) { + err_pos += codepoint_bytes; + } + /* if return_position is false, this returns 1. + * if return_position is true, this returns err_pos. + */ + return err_pos + (1 - return_position); +} + +#ifdef __SSE4_1__ +/* Returns the number of bytes needed to skip backwards to get to the first + byte of codepoint. + */ +static inline int utf8_range_CodepointSkipBackwards(int32_t codepoint_word) { + const int8_t* const codepoint = (const int8_t*)(&codepoint_word); + if (!utf8_range_IsTrailByteOk(codepoint[3])) { + return 1; + } else if (!utf8_range_IsTrailByteOk(codepoint[2])) { + return 2; + } else if (!utf8_range_IsTrailByteOk(codepoint[1])) { + return 3; + } + return 0; +} +#endif // __SSE4_1__ + +/* Skipping over ASCII as much as possible, per 8 bytes. It is intentional + as most strings to check for validity consist only of 1 byte codepoints. + */ +static inline const char* utf8_range_SkipAscii(const char* data, + const char* end) { + while (8 <= end - data && + (utf8_range_UnalignedLoad64(data) & 0x8080808080808080) == 0) { + data += 8; + } + while (data < end && utf8_range_AsciiIsAscii(*data)) { + ++data; + } + return data; +} + +static FORCE_INLINE_ATTR inline size_t utf8_range_Validate( + const char* data, size_t len, int return_position) { + if (len == 0) return 1 - return_position; + const char* const end = data + len; + data = utf8_range_SkipAscii(data, end); + /* SIMD algorithm always outperforms the naive version for any data of + length >=16. + */ + if (end - data < 16) { + return (return_position ? (data - (end - len)) : 0) + + utf8_range_ValidateUTF8Naive(data, end, return_position); + } +#ifndef __SSE4_1__ + return (return_position ? (data - (end - len)) : 0) + + utf8_range_ValidateUTF8Naive(data, end, return_position); +#else + /* This code checks that utf-8 ranges are structurally valid 16 bytes at once + * using superscalar instructions. + * The mapping between ranges of codepoint and their corresponding utf-8 + * sequences is below. + */ + + /* + * U+0000...U+007F 00...7F + * U+0080...U+07FF C2...DF 80...BF + * U+0800...U+0FFF E0 A0...BF 80...BF + * U+1000...U+CFFF E1...EC 80...BF 80...BF + * U+D000...U+D7FF ED 80...9F 80...BF + * U+E000...U+FFFF EE...EF 80...BF 80...BF + * U+10000...U+3FFFF F0 90...BF 80...BF 80...BF + * U+40000...U+FFFFF F1...F3 80...BF 80...BF 80...BF + * U+100000...U+10FFFF F4 80...8F 80...BF 80...BF + */ + + /* First we compute the type for each byte, as given by the table below. + * This type will be used as an index later on. + */ + + /* + * Index Min Max Byte Type + * 0 00 7F Single byte sequence + * 1,2,3 80 BF Second, third and fourth byte for many of the sequences. + * 4 A0 BF Second byte after E0 + * 5 80 9F Second byte after ED + * 6 90 BF Second byte after F0 + * 7 80 8F Second byte after F4 + * 8 C2 F4 First non ASCII byte + * 9..15 7F 80 Invalid byte + */ + + /* After the first step we compute the index for all bytes, then we permute + the bytes according to their indices to check the ranges from the range + table. + * The range for a given type can be found in the range_min_table and + range_max_table, the range for type/index X is in range_min_table[X] ... + range_max_table[X]. + */ + + /* Algorithm: + * Put index zero to all bytes. + * Find all non ASCII characters, give them index 8. + * For each tail byte in a codepoint sequence, give it an index corresponding + to the 1 based index from the end. + * If the first byte of the codepoint is in the [C0...DF] range, we write + index 1 in the following byte. + * If the first byte of the codepoint is in the range [E0...EF], we write + indices 2 and 1 in the next two bytes. + * If the first byte of the codepoint is in the range [F0...FF] we write + indices 3,2,1 into the next three bytes. + * For finding the number of bytes we need to look at high nibbles (4 bits) + and do the lookup from the table, it can be done with shift by 4 + shuffle + instructions. We call it `first_len`. + * Then we shift first_len by 8 bits to get the indices of the 2nd bytes. + * Saturating sub 1 and shift by 8 bits to get the indices of the 3rd bytes. + * Again to get the indices of the 4th bytes. + * Take OR of all that 4 values and check within range. + */ + /* For example: + * input C3 80 68 E2 80 20 A6 F0 A0 80 AC 20 F0 93 80 80 + * first_len 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 0 + * 1st byte 8 0 0 8 0 0 0 8 0 0 0 0 8 0 0 0 + * 2nd byte 0 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 // Shift + sub + * 3rd byte 0 0 0 0 0 1 0 0 0 2 0 0 0 0 2 0 // Shift + sub + * 4th byte 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 // Shift + sub + * Index 8 1 0 8 2 1 0 8 3 2 1 0 8 3 2 1 // OR of results + */ + + /* Checking for errors: + * Error checking is done by looking up the high nibble (4 bits) of each byte + against an error checking table. + * Because the lookup value for the second byte depends of the value of the + first byte in codepoint, we use saturated operations to adjust the index. + * Specifically we need to add 2 for E0, 3 for ED, 3 for F0 and 4 for F4 to + match the correct index. + * If we subtract from all bytes EF then EO -> 241, ED -> 254, F0 -> 1, + F4 -> 5 + * Do saturating sub 240, then E0 -> 1, ED -> 14 and we can do lookup to + match the adjustment + * Add saturating 112, then F0 -> 113, F4 -> 117, all that were > 16 will + be more 128 and lookup in ef_fe_table will return 0 but for F0 + and F4 it will be 4 and 5 accordingly + */ + /* + * Then just check the appropriate ranges with greater/smaller equal + instructions. Check tail with a naive algorithm. + * To save from previous 16 byte checks we just align previous_first_len to + get correct continuations of the codepoints. + */ + + /* + * Map high nibble of "First Byte" to legal character length minus 1 + * 0x00 ~ 0xBF --> 0 + * 0xC0 ~ 0xDF --> 1 + * 0xE0 ~ 0xEF --> 2 + * 0xF0 ~ 0xFF --> 3 + */ + const __m128i first_len_table = + _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3); + + /* Map "First Byte" to 8-th item of range table (0xC2 ~ 0xF4) */ + const __m128i first_range_table = + _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8); + + /* + * Range table, map range index to min and max values + */ + const __m128i range_min_table = + _mm_setr_epi8(0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, 0xC2, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F); + + const __m128i range_max_table = + _mm_setr_epi8(0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, 0xF4, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); + + /* + * Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after + * which the Second Byte are not 80~BF. It contains "range index adjustment". + * +------------+---------------+------------------+----------------+ + * | First Byte | original range| range adjustment | adjusted range | + * +------------+---------------+------------------+----------------+ + * | E0 | 2 | 2 | 4 | + * +------------+---------------+------------------+----------------+ + * | ED | 2 | 3 | 5 | + * +------------+---------------+------------------+----------------+ + * | F0 | 3 | 3 | 6 | + * +------------+---------------+------------------+----------------+ + * | F4 | 4 | 4 | 8 | + * +------------+---------------+------------------+----------------+ + */ + + /* df_ee_table[1] -> E0, df_ee_table[14] -> ED as ED - E0 = 13 */ + // The values represent the adjustment in the Range Index table for a correct + // index. + const __m128i df_ee_table = + _mm_setr_epi8(0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0); + + /* ef_fe_table[1] -> F0, ef_fe_table[5] -> F4, F4 - F0 = 4 */ + // The values represent the adjustment in the Range Index table for a correct + // index. + const __m128i ef_fe_table = + _mm_setr_epi8(0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + __m128i prev_input = _mm_set1_epi8(0); + __m128i prev_first_len = _mm_set1_epi8(0); + __m128i error = _mm_set1_epi8(0); + while (end - data >= 16) { + const __m128i input = + _mm_loadu_si128((const __m128i*)(data)); + + /* high_nibbles = input >> 4 */ + const __m128i high_nibbles = + _mm_and_si128(_mm_srli_epi16(input, 4), _mm_set1_epi8(0x0F)); + + /* first_len = legal character length minus 1 */ + /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ + /* first_len = first_len_table[high_nibbles] */ + __m128i first_len = _mm_shuffle_epi8(first_len_table, high_nibbles); + + /* First Byte: set range index to 8 for bytes within 0xC0 ~ 0xFF */ + /* range = first_range_table[high_nibbles] */ + __m128i range = _mm_shuffle_epi8(first_range_table, high_nibbles); + + /* Second Byte: set range index to first_len */ + /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ + /* range |= (first_len, prev_first_len) << 1 byte */ + range = _mm_or_si128(range, _mm_alignr_epi8(first_len, prev_first_len, 15)); + + /* Third Byte: set range index to saturate_sub(first_len, 1) */ + /* 0 for 00~7F, 0 for C0~DF, 1 for E0~EF, 2 for F0~FF */ + __m128i tmp1; + __m128i tmp2; + /* tmp1 = saturate_sub(first_len, 1) */ + tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(1)); + /* tmp2 = saturate_sub(prev_first_len, 1) */ + tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(1)); + /* range |= (tmp1, tmp2) << 2 bytes */ + range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 14)); + + /* Fourth Byte: set range index to saturate_sub(first_len, 2) */ + /* 0 for 00~7F, 0 for C0~DF, 0 for E0~EF, 1 for F0~FF */ + /* tmp1 = saturate_sub(first_len, 2) */ + tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(2)); + /* tmp2 = saturate_sub(prev_first_len, 2) */ + tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(2)); + /* range |= (tmp1, tmp2) << 3 bytes */ + range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 13)); + + /* + * Now we have below range indices calculated + * Correct cases: + * - 8 for C0~FF + * - 3 for 1st byte after F0~FF + * - 2 for 1st byte after E0~EF or 2nd byte after F0~FF + * - 1 for 1st byte after C0~DF or 2nd byte after E0~EF or + * 3rd byte after F0~FF + * - 0 for others + * Error cases: + * >9 for non ascii First Byte overlapping + * E.g., F1 80 C2 90 --> 8 3 10 2, where 10 indicates error + */ + + /* Adjust Second Byte range for special First Bytes(E0,ED,F0,F4) */ + /* Overlaps lead to index 9~15, which are illegal in range table */ + __m128i shift1; + __m128i pos; + __m128i range2; + /* shift1 = (input, prev_input) << 1 byte */ + shift1 = _mm_alignr_epi8(input, prev_input, 15); + pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF)); + /* + * shift1: | EF F0 ... FE | FF 00 ... ... DE | DF E0 ... EE | + * pos: | 0 1 15 | 16 17 239| 240 241 255| + * pos-240: | 0 0 0 | 0 0 0 | 0 1 15 | + * pos+112: | 112 113 127| >= 128 | >= 128 | + */ + tmp1 = _mm_subs_epu8(pos, _mm_set1_epi8(-16)); + range2 = _mm_shuffle_epi8(df_ee_table, tmp1); + tmp2 = _mm_adds_epu8(pos, _mm_set1_epi8(112)); + range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_table, tmp2)); + + range = _mm_add_epi8(range, range2); + + /* Load min and max values per calculated range index */ + __m128i min_range = _mm_shuffle_epi8(range_min_table, range); + __m128i max_range = _mm_shuffle_epi8(range_max_table, range); + + /* Check value range */ + if (return_position) { + error = _mm_cmplt_epi8(input, min_range); + error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range)); + /* 5% performance drop from this conditional branch */ + if (!_mm_testz_si128(error, error)) { + break; + } + } else { + error = _mm_or_si128(error, _mm_cmplt_epi8(input, min_range)); + error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range)); + } + + prev_input = input; + prev_first_len = first_len; + + data += 16; + } + /* If we got to the end, we don't need to skip any bytes backwards */ + if (return_position && (data - (end - len)) == 0) { + return utf8_range_ValidateUTF8Naive(data, end, return_position); + } + /* Find previous codepoint (not 80~BF) */ + data -= utf8_range_CodepointSkipBackwards(_mm_extract_epi32(prev_input, 3)); + if (return_position) { + return (data - (end - len)) + + utf8_range_ValidateUTF8Naive(data, end, return_position); + } + /* Test if there was any error */ + if (!_mm_testz_si128(error, error)) { + return 0; + } + /* Check the tail */ + return utf8_range_ValidateUTF8Naive(data, end, return_position); +#endif +} + +int utf8_range_IsValid(const char* data, size_t len) { + return utf8_range_Validate(data, len, /*return_position=*/0) != 0; +} + +size_t utf8_range_ValidPrefix(const char* data, size_t len) { + return utf8_range_Validate(data, len, /*return_position=*/1); +} diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h new file mode 100755 index 00000000..d7c23261 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h @@ -0,0 +1,22 @@ +#ifndef THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ +#define THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns 1 if the sequence of characters is a valid UTF-8 sequence, otherwise +// 0. +int utf8_range_IsValid(const char* data, size_t len); + +// Returns the length in bytes of the prefix of str that is all +// structurally valid UTF-8. +size_t utf8_range_ValidPrefix(const char* data, size_t len); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/wrap_memcpy.c b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/wrap_memcpy.c new file mode 100755 index 00000000..2073d14d --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/ext/google/protobuf_c/wrap_memcpy.c @@ -0,0 +1,29 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include + +// On x86-64 Linux with glibc, we link against the 2.2.5 version of memcpy so +// that we avoid depending on the 2.14 version of the symbol. This way, +// distributions that are using pre-2.14 versions of glibc can successfully use +// the gem we distribute +// (https://github.com/protocolbuffers/protobuf/issues/2783). +// +// This wrapper is enabled by passing the linker flags -Wl,-wrap,memcpy in +// extconf.rb. +#ifdef __linux__ +#if defined(__x86_64__) && defined(__GNU_LIBRARY__) +__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +void *__wrap_memcpy(void *dest, const void *src, size_t n) { + return memcpy(dest, src, n); +} +#else +void *__wrap_memcpy(void *dest, const void *src, size_t n) { + return memmove(dest, src, n); +} +#endif +#endif diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.0/protobuf_c.so b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.0/protobuf_c.so new file mode 100755 index 00000000..b9d50765 Binary files /dev/null and b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.0/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.1/protobuf_c.so b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.1/protobuf_c.so new file mode 100755 index 00000000..b8f63f0f Binary files /dev/null and b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.1/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.2/protobuf_c.so b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.2/protobuf_c.so new file mode 100755 index 00000000..2033369b Binary files /dev/null and b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.2/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.3/protobuf_c.so b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.3/protobuf_c.so new file mode 100755 index 00000000..e6294614 Binary files /dev/null and b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.3/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.4/protobuf_c.so b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.4/protobuf_c.so new file mode 100755 index 00000000..8eb7099c Binary files /dev/null and b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/3.4/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf.rb new file mode 100755 index 00000000..fdfa9b68 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf.rb @@ -0,0 +1,61 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# require mixins before we hook them into the java & c code +require 'google/protobuf/message_exts' +require 'google/protobuf/internal/object_cache' + +# We define these before requiring the platform-specific modules. +# That way the module init can grab references to these. +module Google + module Protobuf + class Error < StandardError; end + class ParseError < Error; end + class TypeError < ::TypeError; end + + PREFER_FFI = case ENV['PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION'] + when nil, "", /^native$/i + false + when /^ffi$/i + true + else + warn "Unexpected value `#{ENV['PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION']}` for environment variable `PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION`. Should be either \"FFI\", \"NATIVE\"." + false + end + + def self.encode(msg, options = {}) + msg.to_proto(options) + end + + def self.encode_json(msg, options = {}) + msg.to_json(options) + end + + def self.decode(klass, proto, options = {}) + klass.decode(proto, options) + end + + def self.decode_json(klass, json, options = {}) + klass.decode_json(json, options) + end + + IMPLEMENTATION = if PREFER_FFI + begin + require 'google/protobuf_ffi' + :FFI + rescue LoadError + warn "Caught exception `#{$!.message}` while loading FFI implementation of google/protobuf." + warn "Falling back to native implementation." + require 'google/protobuf_native' + :NATIVE + end + else + require 'google/protobuf_native' + :NATIVE + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/any_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/any_pb.rb new file mode 100755 index 00000000..760712e6 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/any_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/any.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x19google/protobuf/any.proto\x12\x0fgoogle.protobuf\"&\n\x03\x41ny\x12\x10\n\x08type_url\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42v\n\x13\x63om.google.protobufB\x08\x41nyProtoP\x01Z,google.golang.org/protobuf/types/known/anypb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Any = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Any").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/api_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/api_pb.rb new file mode 100755 index 00000000..e640a229 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/api_pb.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/api.proto + +require 'google/protobuf' + +require 'google/protobuf/source_context_pb' +require 'google/protobuf/type_pb' + + +descriptor_data = "\n\x19google/protobuf/api.proto\x12\x0fgoogle.protobuf\x1a$google/protobuf/source_context.proto\x1a\x1agoogle/protobuf/type.proto\"\x81\x02\n\x03\x41pi\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x07methods\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Method\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12&\n\x06mixins\x18\x06 \x03(\x0b\x32\x16.google.protobuf.Mixin\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"\xd5\x01\n\x06Method\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10request_type_url\x18\x02 \x01(\t\x12\x19\n\x11request_streaming\x18\x03 \x01(\x08\x12\x19\n\x11response_type_url\x18\x04 \x01(\t\x12\x1a\n\x12response_streaming\x18\x05 \x01(\x08\x12(\n\x07options\x18\x06 \x03(\x0b\x32\x17.google.protobuf.Option\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\"#\n\x05Mixin\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tBv\n\x13\x63om.google.protobufB\x08\x41piProtoP\x01Z,google.golang.org/protobuf/types/known/apipb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Api = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Api").msgclass + Method = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Method").msgclass + Mixin = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Mixin").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/descriptor_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/descriptor_pb.rb new file mode 100755 index 00000000..ab92bba1 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/descriptor_pb.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/descriptor.proto + +require 'google/protobuf' + + +descriptor_data = "\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"U\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto*\x0c\x08\x80\xec\xca\xff\x01\x10\x81\xec\xca\xff\x01\"\x86\x04\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\x12)\n\x07\x65\x64ition\x18\x0e \x01(\x0e\x32\x18.google.protobuf.Edition\"\xa9\x05\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x12\x46\n\x0ereserved_range\x18\t \x03(\x0b\x32..google.protobuf.DescriptorProto.ReservedRange\x12\x15\n\rreserved_name\x18\n \x03(\t\x1a\x65\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12\x37\n\x07options\x18\x03 \x01(\x0b\x32&.google.protobuf.ExtensionRangeOptions\x1a+\n\rReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xe5\x03\n\x15\x45xtensionRangeOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\x12L\n\x0b\x64\x65\x63laration\x18\x02 \x03(\x0b\x32\x32.google.protobuf.ExtensionRangeOptions.DeclarationB\x03\x88\x01\x02\x12-\n\x08\x66\x65\x61tures\x18\x32 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12_\n\x0cverification\x18\x03 \x01(\x0e\x32\x38.google.protobuf.ExtensionRangeOptions.VerificationState:\nUNVERIFIEDB\x03\x88\x01\x02\x1ah\n\x0b\x44\x65\x63laration\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12\x11\n\tfull_name\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\t\x12\x10\n\x08reserved\x18\x05 \x01(\x08\x12\x10\n\x08repeated\x18\x06 \x01(\x08J\x04\x08\x04\x10\x05\"4\n\x11VerificationState\x12\x0f\n\x0b\x44\x45\x43LARATION\x10\x00\x12\x0e\n\nUNVERIFIED\x10\x01*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xd5\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12\x11\n\tjson_name\x18\n \x01(\t\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\x12\x17\n\x0fproto3_optional\x18\x11 \x01(\x08\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REPEATED\x10\x03\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\"T\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\x07options\x18\x02 \x01(\x0b\x32\x1d.google.protobuf.OneofOptions\"\xa4\x02\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\x12N\n\x0ereserved_range\x18\x04 \x03(\x0b\x32\x36.google.protobuf.EnumDescriptorProto.EnumReservedRange\x12\x15\n\rreserved_name\x18\x05 \x03(\t\x1a/\n\x11\x45numReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xcb\x06\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12)\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08\x42\x02\x18\x01\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x04true\x12\x19\n\x11objc_class_prefix\x18$ \x01(\t\x12\x18\n\x10\x63sharp_namespace\x18% \x01(\t\x12\x14\n\x0cswift_prefix\x18\' \x01(\t\x12\x18\n\x10php_class_prefix\x18( \x01(\t\x12\x15\n\rphp_namespace\x18) \x01(\t\x12\x1e\n\x16php_metadata_namespace\x18, \x01(\t\x12\x14\n\x0cruby_package\x18- \x01(\t\x12-\n\x08\x66\x65\x61tures\x18\x32 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08*\x10+J\x04\x08&\x10\'R\x14php_generic_services\"\xe7\x02\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x32\n&deprecated_legacy_json_field_conflicts\x18\x0b \x01(\x08\x42\x02\x18\x01\x12-\n\x08\x66\x65\x61tures\x18\x0c \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07J\x04\x08\x08\x10\tJ\x04\x08\t\x10\n\"\xa3\x0b\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12?\n\x06jstype\x18\x06 \x01(\x0e\x32$.google.protobuf.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0funverified_lazy\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x64\x65\x62ug_redact\x18\x10 \x01(\x08:\x05\x66\x61lse\x12@\n\tretention\x18\x11 \x01(\x0e\x32-.google.protobuf.FieldOptions.OptionRetention\x12?\n\x07targets\x18\x13 \x03(\x0e\x32..google.protobuf.FieldOptions.OptionTargetType\x12\x46\n\x10\x65\x64ition_defaults\x18\x14 \x03(\x0b\x32,.google.protobuf.FieldOptions.EditionDefault\x12-\n\x08\x66\x65\x61tures\x18\x15 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x45\n\x0f\x66\x65\x61ture_support\x18\x16 \x01(\x0b\x32,.google.protobuf.FieldOptions.FeatureSupport\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\x1aJ\n\x0e\x45\x64itionDefault\x12)\n\x07\x65\x64ition\x18\x03 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\r\n\x05value\x18\x02 \x01(\t\x1a\xcc\x01\n\x0e\x46\x65\x61tureSupport\x12\x34\n\x12\x65\x64ition_introduced\x18\x01 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x34\n\x12\x65\x64ition_deprecated\x18\x02 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x1b\n\x13\x64\x65precation_warning\x18\x03 \x01(\t\x12\x31\n\x0f\x65\x64ition_removed\x18\x04 \x01(\x0e\x32\x18.google.protobuf.Edition\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02\"U\n\x0fOptionRetention\x12\x15\n\x11RETENTION_UNKNOWN\x10\x00\x12\x15\n\x11RETENTION_RUNTIME\x10\x01\x12\x14\n\x10RETENTION_SOURCE\x10\x02\"\x8c\x02\n\x10OptionTargetType\x12\x17\n\x13TARGET_TYPE_UNKNOWN\x10\x00\x12\x14\n\x10TARGET_TYPE_FILE\x10\x01\x12\x1f\n\x1bTARGET_TYPE_EXTENSION_RANGE\x10\x02\x12\x17\n\x13TARGET_TYPE_MESSAGE\x10\x03\x12\x15\n\x11TARGET_TYPE_FIELD\x10\x04\x12\x15\n\x11TARGET_TYPE_ONEOF\x10\x05\x12\x14\n\x10TARGET_TYPE_ENUM\x10\x06\x12\x1a\n\x16TARGET_TYPE_ENUM_ENTRY\x10\x07\x12\x17\n\x13TARGET_TYPE_SERVICE\x10\x08\x12\x16\n\x12TARGET_TYPE_METHOD\x10\t*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x12\x10\x13\"\x8d\x01\n\x0cOneofOptions\x12-\n\x08\x66\x65\x61tures\x18\x01 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xf6\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x32\n&deprecated_legacy_json_field_conflicts\x18\x06 \x01(\x08\x42\x02\x18\x01\x12-\n\x08\x66\x65\x61tures\x18\x07 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x05\x10\x06\"\x90\x02\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12-\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x1b\n\x0c\x64\x65\x62ug_redact\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x45\n\x0f\x66\x65\x61ture_support\x18\x04 \x01(\x0b\x32,.google.protobuf.FieldOptions.FeatureSupport\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xaa\x01\n\x0eServiceOptions\x12-\n\x08\x66\x65\x61tures\x18\" \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xdc\x02\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12_\n\x11idempotency_level\x18\" \x01(\x0e\x32/.google.protobuf.MethodOptions.IdempotencyLevel:\x13IDEMPOTENCY_UNKNOWN\x12-\n\x08\x66\x65\x61tures\x18# \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"P\n\x10IdempotencyLevel\x12\x17\n\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n\nIDEMPOTENT\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xc9\t\n\nFeatureSet\x12\x82\x01\n\x0e\x66ield_presence\x18\x01 \x01(\x0e\x32).google.protobuf.FeatureSet.FieldPresenceB?\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\r\x12\x08\x45XPLICIT\x18\x84\x07\xa2\x01\r\x12\x08IMPLICIT\x18\xe7\x07\xa2\x01\r\x12\x08\x45XPLICIT\x18\xe8\x07\xb2\x01\x03\x08\xe8\x07\x12\x62\n\tenum_type\x18\x02 \x01(\x0e\x32$.google.protobuf.FeatureSet.EnumTypeB)\x88\x01\x01\x98\x01\x06\x98\x01\x01\xa2\x01\x0b\x12\x06\x43LOSED\x18\x84\x07\xa2\x01\t\x12\x04OPEN\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12\x81\x01\n\x17repeated_field_encoding\x18\x03 \x01(\x0e\x32\x31.google.protobuf.FeatureSet.RepeatedFieldEncodingB-\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\r\x12\x08\x45XPANDED\x18\x84\x07\xa2\x01\x0b\x12\x06PACKED\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12n\n\x0futf8_validation\x18\x04 \x01(\x0e\x32*.google.protobuf.FeatureSet.Utf8ValidationB)\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\t\x12\x04NONE\x18\x84\x07\xa2\x01\x0b\x12\x06VERIFY\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12m\n\x10message_encoding\x18\x05 \x01(\x0e\x32+.google.protobuf.FeatureSet.MessageEncodingB&\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\x14\x12\x0fLENGTH_PREFIXED\x18\x84\x07\xb2\x01\x03\x08\xe8\x07\x12v\n\x0bjson_format\x18\x06 \x01(\x0e\x32&.google.protobuf.FeatureSet.JsonFormatB9\x88\x01\x01\x98\x01\x03\x98\x01\x06\x98\x01\x01\xa2\x01\x17\x12\x12LEGACY_BEST_EFFORT\x18\x84\x07\xa2\x01\n\x12\x05\x41LLOW\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\"\\\n\rFieldPresence\x12\x1a\n\x16\x46IELD_PRESENCE_UNKNOWN\x10\x00\x12\x0c\n\x08\x45XPLICIT\x10\x01\x12\x0c\n\x08IMPLICIT\x10\x02\x12\x13\n\x0fLEGACY_REQUIRED\x10\x03\"7\n\x08\x45numType\x12\x15\n\x11\x45NUM_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04OPEN\x10\x01\x12\n\n\x06\x43LOSED\x10\x02\"V\n\x15RepeatedFieldEncoding\x12#\n\x1fREPEATED_FIELD_ENCODING_UNKNOWN\x10\x00\x12\n\n\x06PACKED\x10\x01\x12\x0c\n\x08\x45XPANDED\x10\x02\"I\n\x0eUtf8Validation\x12\x1b\n\x17UTF8_VALIDATION_UNKNOWN\x10\x00\x12\n\n\x06VERIFY\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x04\x08\x01\x10\x01\"S\n\x0fMessageEncoding\x12\x1c\n\x18MESSAGE_ENCODING_UNKNOWN\x10\x00\x12\x13\n\x0fLENGTH_PREFIXED\x10\x01\x12\r\n\tDELIMITED\x10\x02\"H\n\nJsonFormat\x12\x17\n\x13JSON_FORMAT_UNKNOWN\x10\x00\x12\t\n\x05\x41LLOW\x10\x01\x12\x16\n\x12LEGACY_BEST_EFFORT\x10\x02*\x06\x08\xe8\x07\x10\x8bN*\x06\x08\x8bN\x10\x90N*\x06\x08\x90N\x10\x91NJ\x06\x08\xe7\x07\x10\xe8\x07\"\x98\x03\n\x12\x46\x65\x61tureSetDefaults\x12N\n\x08\x64\x65\x66\x61ults\x18\x01 \x03(\x0b\x32<.google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault\x12\x31\n\x0fminimum_edition\x18\x04 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x31\n\x0fmaximum_edition\x18\x05 \x01(\x0e\x32\x18.google.protobuf.Edition\x1a\xcb\x01\n\x18\x46\x65\x61tureSetEditionDefault\x12)\n\x07\x65\x64ition\x18\x03 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x39\n\x14overridable_features\x18\x04 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x33\n\x0e\x66ixed_features\x18\x05 \x01(\x0b\x32\x1b.google.protobuf.FeatureSetJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03R\x08\x66\x65\x61tures\"\xe3\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x86\x01\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\t\x12!\n\x19leading_detached_comments\x18\x06 \x03(\t*\x0c\x08\x80\xec\xca\xff\x01\x10\x81\xec\xca\xff\x01\"\x9c\x02\n\x11GeneratedCodeInfo\x12\x41\n\nannotation\x18\x01 \x03(\x0b\x32-.google.protobuf.GeneratedCodeInfo.Annotation\x1a\xc3\x01\n\nAnnotation\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x13\n\x0bsource_file\x18\x02 \x01(\t\x12\r\n\x05\x62\x65gin\x18\x03 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x04 \x01(\x05\x12H\n\x08semantic\x18\x05 \x01(\x0e\x32\x36.google.protobuf.GeneratedCodeInfo.Annotation.Semantic\"(\n\x08Semantic\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03SET\x10\x01\x12\t\n\x05\x41LIAS\x10\x02*\xa7\x02\n\x07\x45\x64ition\x12\x13\n\x0f\x45\x44ITION_UNKNOWN\x10\x00\x12\x13\n\x0e\x45\x44ITION_LEGACY\x10\x84\x07\x12\x13\n\x0e\x45\x44ITION_PROTO2\x10\xe6\x07\x12\x13\n\x0e\x45\x44ITION_PROTO3\x10\xe7\x07\x12\x11\n\x0c\x45\x44ITION_2023\x10\xe8\x07\x12\x11\n\x0c\x45\x44ITION_2024\x10\xe9\x07\x12\x17\n\x13\x45\x44ITION_1_TEST_ONLY\x10\x01\x12\x17\n\x13\x45\x44ITION_2_TEST_ONLY\x10\x02\x12\x1d\n\x17\x45\x44ITION_99997_TEST_ONLY\x10\x9d\x8d\x06\x12\x1d\n\x17\x45\x44ITION_99998_TEST_ONLY\x10\x9e\x8d\x06\x12\x1d\n\x17\x45\x44ITION_99999_TEST_ONLY\x10\x9f\x8d\x06\x12\x13\n\x0b\x45\x44ITION_MAX\x10\xff\xff\xff\xff\x07\x42~\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01Z-google.golang.org/protobuf/types/descriptorpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1aGoogle.Protobuf.Reflection" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + FileDescriptorSet = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileDescriptorSet").msgclass + FileDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileDescriptorProto").msgclass + DescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto").msgclass + DescriptorProto::ExtensionRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto.ExtensionRange").msgclass + DescriptorProto::ReservedRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto.ReservedRange").msgclass + ExtensionRangeOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions").msgclass + ExtensionRangeOptions::Declaration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions.Declaration").msgclass + ExtensionRangeOptions::VerificationState = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions.VerificationState").enummodule + FieldDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto").msgclass + FieldDescriptorProto::Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto.Type").enummodule + FieldDescriptorProto::Label = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto.Label").enummodule + OneofDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.OneofDescriptorProto").msgclass + EnumDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumDescriptorProto").msgclass + EnumDescriptorProto::EnumReservedRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumDescriptorProto.EnumReservedRange").msgclass + EnumValueDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValueDescriptorProto").msgclass + ServiceDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ServiceDescriptorProto").msgclass + MethodDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodDescriptorProto").msgclass + FileOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileOptions").msgclass + FileOptions::OptimizeMode = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileOptions.OptimizeMode").enummodule + MessageOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MessageOptions").msgclass + FieldOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions").msgclass + FieldOptions::EditionDefault = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.EditionDefault").msgclass + FieldOptions::FeatureSupport = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.FeatureSupport").msgclass + FieldOptions::CType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.CType").enummodule + FieldOptions::JSType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.JSType").enummodule + FieldOptions::OptionRetention = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.OptionRetention").enummodule + FieldOptions::OptionTargetType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.OptionTargetType").enummodule + OneofOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.OneofOptions").msgclass + EnumOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumOptions").msgclass + EnumValueOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValueOptions").msgclass + ServiceOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ServiceOptions").msgclass + MethodOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodOptions").msgclass + MethodOptions::IdempotencyLevel = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodOptions.IdempotencyLevel").enummodule + UninterpretedOption = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UninterpretedOption").msgclass + UninterpretedOption::NamePart = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UninterpretedOption.NamePart").msgclass + FeatureSet = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet").msgclass + FeatureSet::FieldPresence = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.FieldPresence").enummodule + FeatureSet::EnumType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.EnumType").enummodule + FeatureSet::RepeatedFieldEncoding = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.RepeatedFieldEncoding").enummodule + FeatureSet::Utf8Validation = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.Utf8Validation").enummodule + FeatureSet::MessageEncoding = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.MessageEncoding").enummodule + FeatureSet::JsonFormat = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.JsonFormat").enummodule + FeatureSetDefaults = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSetDefaults").msgclass + FeatureSetDefaults::FeatureSetEditionDefault = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault").msgclass + SourceCodeInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceCodeInfo").msgclass + SourceCodeInfo::Location = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceCodeInfo.Location").msgclass + GeneratedCodeInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo").msgclass + GeneratedCodeInfo::Annotation = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo.Annotation").msgclass + GeneratedCodeInfo::Annotation::Semantic = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo.Annotation.Semantic").enummodule + Edition = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Edition").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/duration_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/duration_pb.rb new file mode 100755 index 00000000..f5b9e918 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/duration_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/duration.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1egoogle/protobuf/duration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Duration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Duration").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/empty_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/empty_pb.rb new file mode 100755 index 00000000..0ac1b524 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/empty_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/empty.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1bgoogle/protobuf/empty.proto\x12\x0fgoogle.protobuf\"\x07\n\x05\x45mptyB}\n\x13\x63om.google.protobufB\nEmptyProtoP\x01Z.google.golang.org/protobuf/types/known/emptypb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Empty = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor.rb new file mode 100755 index 00000000..ee52a5cb --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor.rb @@ -0,0 +1,165 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + ## + # Message Descriptor - Descriptor for short. + class Descriptor + attr :descriptor_pool, :msg_class + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [Descriptor] Descriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _ = nil) + msg_def_ptr = value.nil? ? nil : value.instance_variable_get(:@msg_def) + return ::FFI::Pointer::NULL if msg_def_ptr.nil? + raise "Underlying msg_def was null!" if msg_def_ptr.null? + msg_def_ptr + end + + ## + # @param msg_def [::FFI::Pointer] MsgDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(msg_def, _ = nil) + return nil if msg_def.nil? or msg_def.null? + file_def = Google::Protobuf::FFI.get_message_file_def msg_def + descriptor_from_file_def(file_def, msg_def) + end + end + + def to_native + self.class.to_native(self) + end + + ## + # Great write up of this strategy: + # See https://blog.appsignal.com/2018/08/07/ruby-magic-changing-the-way-ruby-creates-objects.html + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "Descriptor - (not the message class) #{name}" + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.get_message_file_def(@msg_def)) + end + + def name + @name ||= Google::Protobuf::FFI.get_message_fullname(self) + end + + def each_oneof &block + n = Google::Protobuf::FFI.oneof_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_oneof_by_index(self, i)) + end + nil + end + + def each &block + n = Google::Protobuf::FFI.field_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_field_by_index(self, i)) + end + nil + end + + def lookup(name) + Google::Protobuf::FFI.get_field_by_name(self, name, name.size) + end + + def lookup_oneof(name) + Google::Protobuf::FFI.get_oneof_by_name(self, name, name.size) + end + + def msgclass + @msg_class ||= build_message_class + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.message_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::MessageOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + private + + extend Google::Protobuf::Internal::Convert + + def initialize(msg_def, descriptor_pool) + @msg_def = msg_def + @msg_class = nil + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(msg_def, descriptor_pool) + instance = allocate + instance.send(:initialize, msg_def, descriptor_pool) + instance + end + + def wrapper? + if defined? @wrapper + @wrapper + else + @wrapper = case Google::Protobuf::FFI.get_well_known_type self + when :DoubleValue, :FloatValue, :Int64Value, :UInt64Value, :Int32Value, :UInt32Value, :StringValue, :BytesValue, :BoolValue + true + else + false + end + end + end + + def self.get_message(msg, descriptor, arena) + return nil if msg.nil? or msg.null? + message = OBJECT_CACHE.get(msg.address) + if message.nil? + message = descriptor.msgclass.send(:private_constructor, arena, msg: msg) + end + message + end + + def pool + @descriptor_pool + end + end + + class FFI + # MessageDef + attach_function :new_message_from_def, :upb_Message_New, [MiniTable.by_ref, Internal::Arena], :Message + attach_function :field_count, :upb_MessageDef_FieldCount, [Descriptor], :int + attach_function :get_message_file_def, :upb_MessageDef_File, [:pointer], :FileDef + attach_function :get_message_fullname, :upb_MessageDef_FullName, [Descriptor], :string + attach_function :get_mini_table, :upb_MessageDef_MiniTable, [Descriptor], MiniTable.ptr + attach_function :oneof_count, :upb_MessageDef_OneofCount, [Descriptor], :int + attach_function :message_options, :Descriptor_serialized_options, [Descriptor, :pointer, Internal::Arena], :pointer + attach_function :get_well_known_type, :upb_MessageDef_WellKnownType, [Descriptor], WellKnown + attach_function :find_msg_def_by_name, :upb_MessageDef_FindByNameWithSize, [Descriptor, :string, :size_t, :FieldDefPointer, :OneofDefPointer], :bool + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor_pool.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor_pool.rb new file mode 100755 index 00000000..4dc177d5 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/descriptor_pool.rb @@ -0,0 +1,77 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # DefPool + attach_function :add_serialized_file, :upb_DefPool_AddFile, [:DefPool, :FileDescriptorProto, Status.by_ref], :FileDef + attach_function :free_descriptor_pool, :upb_DefPool_Free, [:DefPool], :void + attach_function :create_descriptor_pool,:upb_DefPool_New, [], :DefPool + attach_function :get_extension_registry,:upb_DefPool_ExtensionRegistry, [:DefPool], :ExtensionRegistry + attach_function :lookup_enum, :upb_DefPool_FindEnumByName, [:DefPool, :string], EnumDescriptor + attach_function :lookup_extension, :upb_DefPool_FindExtensionByName,[:DefPool, :string], FieldDescriptor + attach_function :lookup_msg, :upb_DefPool_FindMessageByName, [:DefPool, :string], Descriptor + attach_function :lookup_service, :upb_DefPool_FindServiceByName, [:DefPool, :string], ServiceDescriptor + + # FileDescriptorProto + attach_function :parse, :FileDescriptorProto_parse, [:binary_string, :size_t, Internal::Arena], :FileDescriptorProto + end + class DescriptorPool + attr :descriptor_pool + attr_accessor :descriptor_class_by_def + + def initialize + @descriptor_pool = ::FFI::AutoPointer.new(Google::Protobuf::FFI.create_descriptor_pool, Google::Protobuf::FFI.method(:free_descriptor_pool)) + @descriptor_class_by_def = {} + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + Google::Protobuf::OBJECT_CACHE.try_add @descriptor_pool.address, self + end + + def add_serialized_file(file_contents) + # Allocate memory sized to file_contents + memBuf = ::FFI::MemoryPointer.new(:char, file_contents.bytesize) + # Insert the data + memBuf.put_bytes(0, file_contents) + temporary_arena = Google::Protobuf::FFI.create_arena + file_descriptor_proto = Google::Protobuf::FFI.parse memBuf, file_contents.bytesize, temporary_arena + raise ArgumentError.new("Unable to parse FileDescriptorProto") if file_descriptor_proto.null? + + status = Google::Protobuf::FFI::Status.new + file_descriptor = Google::Protobuf::FFI.add_serialized_file @descriptor_pool, file_descriptor_proto, status + if file_descriptor.null? + raise TypeError.new("Unable to build file to DescriptorPool: #{Google::Protobuf::FFI.error_message(status)}") + else + @descriptor_class_by_def[file_descriptor.address] = FileDescriptor.new file_descriptor, self + end + end + + def lookup name + Google::Protobuf::FFI.lookup_msg(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_enum(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_extension(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_service(@descriptor_pool, name) + end + + def self.generated_pool + @@generated_pool ||= DescriptorPool.new + end + + private + + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + def get_file_descriptor file_def + return nil if file_def.null? + @descriptor_class_by_def[file_def.address] ||= FileDescriptor.new(file_def, self) + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/enum_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/enum_descriptor.rb new file mode 100755 index 00000000..e7ce04da --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/enum_descriptor.rb @@ -0,0 +1,173 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class EnumDescriptor + attr :descriptor_pool, :enum_def + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [EnumDescriptor] EnumDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + value.instance_variable_get(:@enum_def) || ::FFI::Pointer::NULL + end + + ## + # @param enum_def [::FFI::Pointer] EnumDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(enum_def, _) + return nil if enum_def.nil? or enum_def.null? + file_def = Google::Protobuf::FFI.get_message_file_def enum_def + descriptor_from_file_def(file_def, enum_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.get_enum_file_descriptor(self)) + end + + def name + Google::Protobuf::FFI.get_enum_fullname(self) + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def lookup_name(name) + self.class.send(:lookup_name, self, name) + end + + def lookup_value(number) + self.class.send(:lookup_value, self, number) + end + + def each &block + n = Google::Protobuf::FFI.enum_value_count(self) + 0.upto(n - 1) do |i| + enum_value = Google::Protobuf::FFI.enum_value_by_index(self, i) + yield(Google::Protobuf::FFI.enum_name(enum_value).to_sym, Google::Protobuf::FFI.enum_number(enum_value)) + end + nil + end + + def enummodule + if @module.nil? + @module = build_enum_module + end + @module + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.enum_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::EnumOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + private + + def initialize(enum_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @enum_def = enum_def + @module = nil + end + + def self.private_constructor(enum_def, descriptor_pool) + instance = allocate + instance.send(:initialize, enum_def, descriptor_pool) + instance + end + + def self.lookup_value(enum_def, number) + enum_value = Google::Protobuf::FFI.enum_value_by_number(enum_def, number) + if enum_value.null? + nil + else + Google::Protobuf::FFI.enum_name(enum_value).to_sym + end + end + + def self.lookup_name(enum_def, name) + enum_value = Google::Protobuf::FFI.enum_value_by_name(enum_def, name.to_s, name.size) + if enum_value.null? + nil + else + Google::Protobuf::FFI.enum_number(enum_value) + end + end + + def build_enum_module + descriptor = self + dynamic_module = Module.new do + @descriptor = descriptor + + class << self + attr_accessor :descriptor + end + + def self.lookup(number) + descriptor.lookup_value number + end + + def self.resolve(name) + descriptor.lookup_name name + end + end + + self.each do |name, value| + if name[0] < 'A' || name[0] > 'Z' + if name[0] >= 'a' and name[0] <= 'z' + name = name[0].upcase + name[1..-1] # auto capitalize + else + warn( + "Enum value '#{name}' does not start with an uppercase letter " + + "as is required for Ruby constants.") + next + end + end + dynamic_module.const_set(name.to_sym, value) + end + dynamic_module + end + end + + class FFI + # EnumDescriptor + attach_function :get_enum_file_descriptor, :upb_EnumDef_File, [EnumDescriptor], :FileDef + attach_function :enum_value_by_name, :upb_EnumDef_FindValueByNameWithSize,[EnumDescriptor, :string, :size_t], :EnumValueDef + attach_function :enum_value_by_number, :upb_EnumDef_FindValueByNumber, [EnumDescriptor, :int], :EnumValueDef + attach_function :get_enum_fullname, :upb_EnumDef_FullName, [EnumDescriptor], :string + attach_function :enum_options, :EnumDescriptor_serialized_options, [EnumDescriptor, :pointer, Internal::Arena], :pointer + attach_function :enum_value_by_index, :upb_EnumDef_Value, [EnumDescriptor, :int], :EnumValueDef + attach_function :enum_value_count, :upb_EnumDef_ValueCount, [EnumDescriptor], :int + attach_function :enum_name, :upb_EnumValueDef_Name, [:EnumValueDef], :string + attach_function :enum_number, :upb_EnumValueDef_Number, [:EnumValueDef], :int + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/ffi.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/ffi.rb new file mode 100755 index 00000000..0270f977 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/ffi.rb @@ -0,0 +1,215 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + extend ::FFI::Library + # Workaround for Bazel's use of symlinks + JRuby's __FILE__ and `caller` + # that resolves them. + if ENV['BAZEL'] == 'true' + ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi', ENV['PWD'] + else + ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi' + end + + ## Map + Upb_Map_Begin = -1 + + ## Encoding Status + Upb_Status_MaxMessage = 511 + Upb_Encode_Deterministic = 1 + Upb_Encode_SkipUnknown = 2 + + ## JSON Encoding options + # When set, emits 0/default values. TODO: proto3 only? + Upb_JsonEncode_EmitDefaults = 1 + # When set, use normal (snake_case) field names instead of JSON (camelCase) names. + Upb_JsonEncode_UseProtoNames = 2 + # When set, emits enums as their integer values instead of as their names. + Upb_JsonEncode_FormatEnumsAsIntegers = 4 + + ## JSON Decoding options + Upb_JsonDecode_IgnoreUnknown = 1 + + ## JSON Decoding results + Upb_JsonDecodeResult_Ok = 0 + Upb_JsonDecodeResult_OkWithEmptyStringNumerics = 1 + Upb_JsonDecodeResult_Error = 2 + + typedef :pointer, :Array + typedef :pointer, :DefPool + typedef :pointer, :EnumValueDef + typedef :pointer, :ExtensionRegistry + typedef :pointer, :FieldDefPointer + typedef :pointer, :FileDef + typedef :pointer, :FileDescriptorProto + typedef :pointer, :Map + typedef :pointer, :Message # Instances of a message + typedef :pointer, :OneofDefPointer + typedef :pointer, :binary_string + if ::FFI::Platform::ARCH == "aarch64" + typedef :u_int8_t, :uint8_t + typedef :u_int16_t, :uint16_t + typedef :u_int32_t, :uint32_t + typedef :u_int64_t, :uint64_t + end + + FieldType = enum( + :double, 1, + :float, + :int64, + :uint64, + :int32, + :fixed64, + :fixed32, + :bool, + :string, + :group, + :message, + :bytes, + :uint32, + :enum, + :sfixed32, + :sfixed64, + :sint32, + :sint64 + ) + + CType = enum( + :bool, 1, + :float, + :int32, + :uint32, + :enum, + :message, + :double, + :int64, + :uint64, + :string, + :bytes + ) + + Label = enum( + :optional, 1, + :required, + :repeated + ) + + # All the different kind of well known type messages. For simplicity of check, + # number wrappers and string wrappers are grouped together. Make sure the + # order and merber of these groups are not changed. + + WellKnown = enum( + :Unspecified, + :Any, + :FieldMask, + :Duration, + :Timestamp, + # number wrappers + :DoubleValue, + :FloatValue, + :Int64Value, + :UInt64Value, + :Int32Value, + :UInt32Value, + # string wrappers + :StringValue, + :BytesValue, + :BoolValue, + :Value, + :ListValue, + :Struct + ) + + DecodeStatus = enum( + :Ok, + :Malformed, # Wire format was corrupt + :OutOfMemory, # Arena alloc failed + :BadUtf8, # String field had bad UTF-8 + :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH + + # CheckRequired failed, but the parse otherwise succeeded. + :MissingRequired, + ) + + EncodeStatus = enum( + :Ok, + :OutOfMemory, # Arena alloc failed + :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH + + # CheckRequired failed, but the parse otherwise succeeded. + :MissingRequired, + ) + + class StringView < ::FFI::Struct + layout :data, :pointer, + :size, :size_t + end + + class MiniTable < ::FFI::Struct + layout :subs, :pointer, + :fields, :pointer, + :size, :uint16_t, + :field_count, :uint16_t, + :ext, :uint8_t, # upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 + :dense_below, :uint8_t, + :table_mask, :uint8_t, + :required_count, :uint8_t # Required fields have the lowest hasbits. + # To statically initialize the tables of variable length, we need a flexible + # array member, and we need to compile in gnu99 mode (constant initialization + # of flexible array members is a GNU extension, not in C99 unfortunately. */ + # _upb_FastTable_Entry fasttable[]; + end + + class Status < ::FFI::Struct + layout :ok, :bool, + :msg, [:char, Upb_Status_MaxMessage] + + def initialize + super + FFI.clear self + end + end + + class MessageValue < ::FFI::Union + layout :bool_val, :bool, + :float_val, :float, + :double_val, :double, + :int32_val, :int32_t, + :int64_val, :int64_t, + :uint32_val, :uint32_t, + :uint64_val,:uint64_t, + :map_val, :pointer, + :msg_val, :pointer, + :array_val,:pointer, + :str_val, StringView + end + + Upb_Message_Begin = -1 + + class MutableMessageValue < ::FFI::Union + layout :map, :Map, + :msg, :Message, + :array, :Array + end + + # Status + attach_function :clear, :upb_Status_Clear, [Status.by_ref], :void + attach_function :error_message, :upb_Status_ErrorMessage, [Status.by_ref], :string + + # Generic + attach_function :memcmp, [:pointer, :pointer, :size_t], :int + attach_function :memcpy, [:pointer, :pointer, :size_t], :int + + # Alternatives to pre-processor macros + def self.decode_max_depth(i) + i << 16 + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/field_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/field_descriptor.rb new file mode 100755 index 00000000..632692b7 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/field_descriptor.rb @@ -0,0 +1,330 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FieldDescriptor + attr :field_def, :descriptor_pool + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [FieldDescriptor] FieldDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + field_def_ptr = value.instance_variable_get(:@field_def) + warn "Underlying field_def was nil!" if field_def_ptr.nil? + raise "Underlying field_def was null!" if !field_def_ptr.nil? and field_def_ptr.null? + field_def_ptr + end + + ## + # @param field_def [::FFI::Pointer] FieldDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(field_def, _ = nil) + return nil if field_def.nil? or field_def.null? + file_def = Google::Protobuf::FFI.file_def_by_raw_field_def(field_def) + descriptor_from_file_def(file_def, field_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_full_name(self) + end + + def json_name + @json_name ||= Google::Protobuf::FFI.get_json_name(self) + end + + def number + @number ||= Google::Protobuf::FFI.get_number(self) + end + + def type + @type ||= Google::Protobuf::FFI.get_type(self) + end + + def label + @label ||= Google::Protobuf::FFI.get_label(self) + end + + def default + return nil if Google::Protobuf::FFI.is_sub_message(self) + if Google::Protobuf::FFI.is_repeated(self) + message_value = Google::Protobuf::FFI::MessageValue.new + else + message_value = Google::Protobuf::FFI.get_default(self) + end + enum_def = Google::Protobuf::FFI.get_subtype_as_enum(self) + if enum_def.null? + convert_upb_to_ruby message_value, c_type + else + convert_upb_to_ruby message_value, c_type, enum_def + end + end + + def submsg_name + if defined? @submsg_name + @submsg_name + else + @submsg_name = case c_type + when :enum + Google::Protobuf::FFI.get_enum_fullname Google::Protobuf::FFI.get_subtype_as_enum self + when :message + Google::Protobuf::FFI.get_message_fullname Google::Protobuf::FFI.get_subtype_as_message self + else + nil + end + end + end + + ## + # Tests if this field has been set on the argument message. + # + # @param msg [Google::Protobuf::Message] + # @return [Object] Value of the field on this message. + # @raise [TypeError] If the field is not defined on this message. + def get(msg) + if msg.class.descriptor == Google::Protobuf::FFI.get_containing_message_def(self) + msg.send :get_field, self + else + raise TypeError.new "get method called on wrong message type" + end + end + + def subtype + if defined? @subtype + @subtype + else + @subtype = case c_type + when :enum + Google::Protobuf::FFI.get_subtype_as_enum(self) + when :message + Google::Protobuf::FFI.get_subtype_as_message(self) + else + nil + end + end + end + + ## + # Tests if this field has been set on the argument message. + # + # @param msg [Google::Protobuf::Message] + # @return [Boolean] True iff message has this field set + # @raise [TypeError] If this field does not exist on the message + # @raise [ArgumentError] If this field does not track presence + def has?(msg) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "has method called on wrong message type" + end + unless has_presence? + raise ArgumentError.new "does not track presence" + end + + Google::Protobuf::FFI.get_message_has msg.instance_variable_get(:@msg), self + end + + ## + # Tests if this field tracks presence. + # + # @return [Boolean] True iff this field tracks presence + def has_presence? + @has_presence ||= Google::Protobuf::FFI.get_has_presence(self) + end + + ## + # Tests if this is a repeated field that uses packed encoding. + # + # @return [Boolean] True iff this field is packed + def is_packed? + @is_packed ||= Google::Protobuf::FFI.get_is_packed(self) + end + + # @param msg [Google::Protobuf::Message] + def clear(msg) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "clear method called on wrong message type" + end + Google::Protobuf::FFI.clear_message_field msg.instance_variable_get(:@msg), self + nil + end + + ## + # call-seq: + # FieldDescriptor.set(message, value) + # + # Sets the value corresponding to this field to the given value on the given + # message. Raises an exception if message is of the wrong type. Performs the + # ordinary type-checks for field setting. + # + # @param msg [Google::Protobuf::Message] + # @param value [Object] + def set(msg, value) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "set method called on wrong message type" + end + unless set_value_on_message value, msg.instance_variable_get(:@msg), msg.instance_variable_get(:@arena) + raise RuntimeError.new "allocation failed" + end + nil + end + + def map? + @map ||= Google::Protobuf::FFI.is_map self + end + + def repeated? + @repeated ||= Google::Protobuf::FFI.is_repeated self + end + + def sub_message? + @sub_message ||= Google::Protobuf::FFI.is_sub_message self + end + + def wrapper? + if defined? @wrapper + @wrapper + else + message_descriptor = Google::Protobuf::FFI.get_subtype_as_message(self) + @wrapper = message_descriptor.nil? ? false : message_descriptor.send(:wrapper?) + end + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.field_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::FieldOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + private + + def initialize(field_def, descriptor_pool) + @field_def = field_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(field_def, descriptor_pool) + instance = allocate + instance.send(:initialize, field_def, descriptor_pool) + instance + end + + # TODO Can this be added to the public API? + def real_containing_oneof + @real_containing_oneof ||= Google::Protobuf::FFI.real_containing_oneof self + end + + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + ## + # Sets the field this FieldDescriptor represents to the given value on the given message. + # @param value [Object] Value to be set + # @param msg [::FFI::Pointer] Pointer the the upb_Message + # @param arena [Arena] Arena of the message that owns msg + def set_value_on_message(value, msg, arena, wrap: false) + message_to_alter = msg + field_def_to_set = self + if map? + raise TypeError.new "Expected map" unless value.is_a? Google::Protobuf::Map + message_descriptor = subtype + + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + raise TypeError.new "Map key type does not match field's key type" unless key_field_type == value.send(:key_type) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + raise TypeError.new "Map value type does not match field's value type" unless value_field_type == value.send(:value_type) + + raise TypeError.new "Map value type has wrong message/enum class" unless value_field_def.subtype == value.send(:descriptor) + + arena.fuse(value.send(:arena)) + message_value = Google::Protobuf::FFI::MessageValue.new + message_value[:map_val] = value.send(:map_ptr) + elsif repeated? + raise TypeError.new "Expected repeated field array" unless value.is_a? RepeatedField + raise TypeError.new "Repeated field array has wrong message/enum class" unless value.send(:type) == type + arena.fuse(value.send(:arena)) + message_value = Google::Protobuf::FFI::MessageValue.new + message_value[:array_val] = value.send(:array) + else + if value.nil? and (sub_message? or !real_containing_oneof.nil?) + Google::Protobuf::FFI.clear_message_field message_to_alter, field_def_to_set + return true + end + if wrap + value_field_def = Google::Protobuf::FFI.get_field_by_number subtype, 1 + type_for_conversion = Google::Protobuf::FFI.get_c_type(value_field_def) + raise RuntimeError.new "Not expecting to get a msg or enum when unwrapping" if [:enum, :message].include? type_for_conversion + message_value = convert_ruby_to_upb(value, arena, type_for_conversion, nil) + message_to_alter = Google::Protobuf::FFI.get_mutable_message(msg, self, arena)[:msg] + field_def_to_set = value_field_def + else + message_value = convert_ruby_to_upb(value, arena, c_type, subtype) + end + end + Google::Protobuf::FFI.set_message_field message_to_alter, field_def_to_set, message_value, arena + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # MessageDef + attach_function :get_field_by_index, :upb_MessageDef_Field, [Descriptor, :int], FieldDescriptor + attach_function :get_field_by_name, :upb_MessageDef_FindFieldByNameWithSize,[Descriptor, :string, :size_t], FieldDescriptor + attach_function :get_field_by_number, :upb_MessageDef_FindFieldByNumber, [Descriptor, :uint32_t], FieldDescriptor + + # FieldDescriptor + attach_function :field_options, :FieldDescriptor_serialized_options, [FieldDescriptor, :pointer, Internal::Arena], :pointer + attach_function :get_containing_message_def, :upb_FieldDef_ContainingType, [FieldDescriptor], Descriptor + attach_function :get_c_type, :upb_FieldDef_CType, [FieldDescriptor], CType + attach_function :get_default, :upb_FieldDef_Default, [FieldDescriptor], MessageValue.by_value + attach_function :get_subtype_as_enum, :upb_FieldDef_EnumSubDef, [FieldDescriptor], EnumDescriptor + attach_function :get_has_presence, :upb_FieldDef_HasPresence, [FieldDescriptor], :bool + attach_function :get_is_packed, :upb_FieldDef_IsPacked, [FieldDescriptor], :bool + attach_function :is_map, :upb_FieldDef_IsMap, [FieldDescriptor], :bool + attach_function :is_repeated, :upb_FieldDef_IsRepeated, [FieldDescriptor], :bool + attach_function :is_sub_message, :upb_FieldDef_IsSubMessage, [FieldDescriptor], :bool + attach_function :get_json_name, :upb_FieldDef_JsonName, [FieldDescriptor], :string + attach_function :get_label, :upb_FieldDef_Label, [FieldDescriptor], Label + attach_function :get_subtype_as_message, :upb_FieldDef_MessageSubDef, [FieldDescriptor], Descriptor + attach_function :get_full_name, :upb_FieldDef_Name, [FieldDescriptor], :string + attach_function :get_number, :upb_FieldDef_Number, [FieldDescriptor], :uint32_t + attach_function :get_type, :upb_FieldDef_Type, [FieldDescriptor], FieldType + attach_function :file_def_by_raw_field_def, :upb_FieldDef_File, [:pointer], :FileDef + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/file_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/file_descriptor.rb new file mode 100755 index 00000000..2a7bf87e --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/file_descriptor.rb @@ -0,0 +1,49 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # FileDescriptor + attach_function :file_def_name, :upb_FileDef_Name, [:FileDef], :string + attach_function :file_def_pool, :upb_FileDef_Pool, [:FileDef], :DefPool + attach_function :file_options, :FileDescriptor_serialized_options, [:FileDef, :pointer, Internal::Arena], :pointer + end + + class FileDescriptor + attr :descriptor_pool, :file_def + + def initialize(file_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @file_def = file_def + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + Google::Protobuf::FFI.file_def_name(@file_def) + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.file_options(@file_def, size_ptr, temporary_arena) + opts = Google::Protobuf::FileOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/arena.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/arena.rb new file mode 100755 index 00000000..da3b2c42 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/arena.rb @@ -0,0 +1,60 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +## +# Implementation details below are subject to breaking changes without +# warning and are intended for use only within the gem. +module Google + module Protobuf + module Internal + class Arena + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + + # @param value [Arena] Arena to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + value.instance_variable_get(:@arena) || ::FFI::Pointer::NULL + end + + ## + # @param value [::FFI::Pointer] Arena pointer to be wrapped + # @param _ [Object] Unused + def from_native(value, _) + new(value) + end + end + + def initialize(pointer) + @arena = ::FFI::AutoPointer.new(pointer, Google::Protobuf::FFI.method(:free_arena)) + @pinned_messages = [] + end + + def fuse(other_arena) + return if other_arena == self + unless Google::Protobuf::FFI.fuse_arena(self, other_arena) + raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks" + end + end + end + end + + class FFI + # Arena + attach_function :create_arena, :Arena_create, [], Internal::Arena + attach_function :fuse_arena, :upb_Arena_Fuse, [Internal::Arena, Internal::Arena], :bool + # Argument takes a :pointer rather than a typed Arena here due to + # implementation details of FFI::AutoPointer. + attach_function :free_arena, :upb_Arena_Free, [:pointer], :void + attach_function :arena_malloc, :upb_Arena_Malloc, [Internal::Arena, :size_t], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/convert.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/convert.rb new file mode 100755 index 00000000..b22184e4 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/convert.rb @@ -0,0 +1,296 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +## +# Implementation details below are subject to breaking changes without +# warning and are intended for use only within the gem. +module Google + module Protobuf + module Internal + module Convert + + # Arena should be the + # @param value [Object] Value to convert + # @param arena [Arena] Arena that owns the Message where the MessageValue + # will be set + # @return [Google::Protobuf::FFI::MessageValue] + def convert_ruby_to_upb(value, arena, c_type, msg_or_enum_def) + raise ArgumentError.new "Expected Descriptor or EnumDescriptor, instead got #{msg_or_enum_def.class}" unless [NilClass, Descriptor, EnumDescriptor].include? msg_or_enum_def.class + return_value = Google::Protobuf::FFI::MessageValue.new + case c_type + when :float + raise TypeError.new "Expected number type for float field '#{name}' (given #{value.class})." unless value.respond_to? :to_f + return_value[:float_val] = value.to_f + when :double + raise TypeError.new "Expected number type for double field '#{name}' (given #{value.class})." unless value.respond_to? :to_f + return_value[:double_val] = value.to_f + when :bool + raise TypeError.new "Invalid argument for boolean field '#{name}' (given #{value.class})." unless [TrueClass, FalseClass].include? value.class + return_value[:bool_val] = value + when :string + raise TypeError.new "Invalid argument for string field '#{name}' (given #{value.class})." unless value.is_a?(String) or value.is_a?(Symbol) + value = value.to_s if value.is_a?(Symbol) + if value.encoding == Encoding::UTF_8 + unless value.valid_encoding? + # TODO: + # For now we only warn for this case. We will remove the + # warning and throw an exception below in the 30.x release + warn "String is invalid UTF-8. This will be an error in a future version." + # raise Encoding::InvalidByteSequenceError.new "String is invalid UTF-8" + end + string_value = value + else + string_value = value.to_s.encode("UTF-8") + end + return_value[:str_val][:size] = string_value.bytesize + return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize) + # TODO - how important is it to still use arena malloc, versus the following? + # buffer = ::FFI::MemoryPointer.new(:char, string_value.bytesize) + # buffer.put_bytes(0, string_value) + # return_value[:str_val][:data] = buffer + raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for string on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null? + return_value[:str_val][:data].write_string(string_value) + when :bytes + raise TypeError.new "Invalid argument for bytes field '#{name}' (given #{value.class})." unless value.is_a? String + string_value = value.encode("ASCII-8BIT") + return_value[:str_val][:size] = string_value.bytesize + return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize) + raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for bytes on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null? + return_value[:str_val][:data].write_string_length(string_value, string_value.bytesize) + when :message + raise TypeError.new "nil message not allowed here." if value.nil? + if value.is_a? Hash + raise RuntimeError.new "Attempted to initialize message from Hash for field #{name} but have no definition" if msg_or_enum_def.nil? + new_message = msg_or_enum_def.msgclass. + send(:private_constructor, arena, initial_value: value) + return_value[:msg_val] = new_message.instance_variable_get(:@msg) + return return_value + end + + descriptor = value.class.respond_to?(:descriptor) ? value.class.descriptor : nil + if descriptor != msg_or_enum_def + wkt = Google::Protobuf::FFI.get_well_known_type(msg_or_enum_def) + case wkt + when :Timestamp + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Time + new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena + sec = Google::Protobuf::FFI::MessageValue.new + sec[:int64_val] = value.tv_sec + sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1 + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena + nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2 + nsec = Google::Protobuf::FFI::MessageValue.new + nsec[:int32_val] = value.tv_nsec + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena + return_value[:msg_val] = new_message + when :Duration + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Numeric + new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena + sec = Google::Protobuf::FFI::MessageValue.new + sec[:int64_val] = value + sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1 + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena + nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2 + nsec = Google::Protobuf::FFI::MessageValue.new + nsec[:int32_val] = ((value.to_f - value.to_i) * 1000000000).round + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena + return_value[:msg_val] = new_message + else + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." + end + else + arena.fuse(value.instance_variable_get(:@arena)) + return_value[:msg_val] = value.instance_variable_get :@msg + end + when :enum + return_value[:int32_val] = case value + when Numeric + value.to_i + when String, Symbol + enum_number = EnumDescriptor.send(:lookup_name, msg_or_enum_def, value.to_s) + #TODO add the bad value to the error message after tests pass + raise RangeError.new "Unknown symbol value for enum field '#{name}'." if enum_number.nil? + enum_number + else + raise TypeError.new "Expected number or symbol type for enum field '#{name}'." + end + #TODO After all tests pass, improve error message across integer type by including actual offending value + when :int32 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Value assigned to int32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 32 + return_value[:int32_val] = value.to_i + when :uint32 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0 + raise RangeError.new "Value assigned to uint32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 33 + return_value[:uint32_val] = value.to_i + when :int64 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Value assigned to int64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 64 + return_value[:int64_val] = value.to_i + when :uint64 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0 + raise RangeError.new "Value assigned to uint64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 65 + return_value[:uint64_val] = value.to_i + else + raise RuntimeError.new "Unsupported type #{c_type}" + end + return_value + end + + ## + # Safe to call without an arena if the caller has checked that c_type + # is not :message. + # @param message_value [Google::Protobuf::FFI::MessageValue] Value to be converted. + # @param c_type [Google::Protobuf::FFI::CType] Enum representing the type of message_value + # @param msg_or_enum_def [::FFI::Pointer] Pointer to the MsgDef or EnumDef definition + # @param arena [Google::Protobuf::Internal::Arena] Arena to create Message instances, if needed + def convert_upb_to_ruby(message_value, c_type, msg_or_enum_def = nil, arena = nil) + throw TypeError.new "Expected MessageValue but got #{message_value.class}" unless message_value.is_a? Google::Protobuf::FFI::MessageValue + + case c_type + when :bool + message_value[:bool_val] + when :int32 + message_value[:int32_val] + when :uint32 + message_value[:uint32_val] + when :double + message_value[:double_val] + when :int64 + message_value[:int64_val] + when :uint64 + message_value[:uint64_val] + when :string + if message_value[:str_val][:size].zero? + "" + else + message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("UTF-8").freeze + end + when :bytes + if message_value[:str_val][:size].zero? + "" + else + message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("ASCII-8BIT").freeze + end + when :float + message_value[:float_val] + when :enum + EnumDescriptor.send(:lookup_value, msg_or_enum_def, message_value[:int32_val]) || message_value[:int32_val] + when :message + raise "Null Arena for message" if arena.nil? + Descriptor.send(:get_message, message_value[:msg_val], msg_or_enum_def, arena) + else + raise RuntimeError.new "Unexpected type #{c_type}" + end + end + + def to_h_internal(msg, message_descriptor) + return nil if msg.nil? or msg.null? + hash = {} + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Message_Begin) + message_value = Google::Protobuf::FFI::MessageValue.new + field_def_ptr = ::FFI::MemoryPointer.new :pointer + + while Google::Protobuf::FFI::message_next(msg, message_descriptor, nil, field_def_ptr, message_value, iter) do + field_descriptor = FieldDescriptor.from_native field_def_ptr.get_pointer(0) + + if field_descriptor.map? + hash_entry = map_create_hash(message_value[:map_val], field_descriptor) + elsif field_descriptor.repeated? + hash_entry = repeated_field_create_array(message_value[:array_val], field_descriptor, field_descriptor.type) + else + hash_entry = scalar_create_hash(message_value, field_descriptor.type, field_descriptor: field_descriptor) + end + + hash[field_descriptor.name.to_sym] = hash_entry + end + + hash + end + + def map_create_hash(map_ptr, field_descriptor) + return {} if map_ptr.nil? or map_ptr.null? + return_value = {} + + message_descriptor = field_descriptor.send(:subtype) + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + while Google::Protobuf::FFI.map_next(map_ptr, iter) do + iter_size_t = iter.read(:size_t) + key_message_value = Google::Protobuf::FFI.map_key(map_ptr, iter_size_t) + value_message_value = Google::Protobuf::FFI.map_value(map_ptr, iter_size_t) + hash_key = convert_upb_to_ruby(key_message_value, key_field_type) + hash_value = scalar_create_hash(value_message_value, value_field_type, msg_or_enum_descriptor: value_field_def.subtype) + return_value[hash_key] = hash_value + end + return_value + end + + def repeated_field_create_array(array, field_descriptor, type) + return_value = [] + n = (array.nil? || array.null?) ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n - 1) do |i| + message_value = Google::Protobuf::FFI.get_msgval_at(array, i) + return_value << scalar_create_hash(message_value, type, field_descriptor: field_descriptor) + end + return_value + end + + # @param field_descriptor [FieldDescriptor] Descriptor of the field to convert to a hash. + def scalar_create_hash(message_value, type, field_descriptor: nil, msg_or_enum_descriptor: nil) + if [:message, :enum].include? type + if field_descriptor.nil? + if msg_or_enum_descriptor.nil? + raise "scalar_create_hash requires either a FieldDescriptor, MessageDescriptor, or EnumDescriptor as an argument, but received only nil" + end + else + msg_or_enum_descriptor = field_descriptor.subtype + end + if type == :message + to_h_internal(message_value[:msg_val], msg_or_enum_descriptor) + elsif type == :enum + convert_upb_to_ruby message_value, type, msg_or_enum_descriptor + end + else + convert_upb_to_ruby message_value, type + end + end + + def message_value_deep_copy(message_value, type, descriptor, arena) + raise unless message_value.is_a? Google::Protobuf::FFI::MessageValue + new_message_value = Google::Protobuf::FFI::MessageValue.new + case type + when :string, :bytes + # TODO - how important is it to still use arena malloc, versus using FFI MemoryPointers? + new_message_value[:str_val][:size] = message_value[:str_val][:size] + new_message_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, message_value[:str_val][:size]) + raise NoMemoryError.new "Allocation failed" if new_message_value[:str_val][:data].nil? or new_message_value[:str_val][:data].null? + Google::Protobuf::FFI.memcpy(new_message_value[:str_val][:data], message_value[:str_val][:data], message_value[:str_val][:size]) + when :message + new_message_value[:msg_val] = descriptor.msgclass.send(:deep_copy, message_value[:msg_val], arena).instance_variable_get(:@msg) + else + Google::Protobuf::FFI.memcpy(new_message_value.to_ptr, message_value.to_ptr, Google::Protobuf::FFI::MessageValue.size) + end + new_message_value + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/pointer_helper.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/pointer_helper.rb new file mode 100755 index 00000000..a7910ca7 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/pointer_helper.rb @@ -0,0 +1,35 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module Internal + module PointerHelper + # Utility code to defensively walk the object graph from a file_def to + # the pool, and either retrieve the wrapper object for the given pointer + # or create one. Assumes that the caller is the wrapper class for the + # given pointer and that it implements `private_constructor`. + def descriptor_from_file_def(file_def, pointer) + raise RuntimeError.new "FileDef is nil" if file_def.nil? + raise RuntimeError.new "FileDef is null" if file_def.null? + pool_def = Google::Protobuf::FFI.file_def_pool file_def + raise RuntimeError.new "PoolDef is nil" if pool_def.nil? + raise RuntimeError.new "PoolDef is null" if pool_def.null? + pool = Google::Protobuf::OBJECT_CACHE.get(pool_def.address) + raise "Cannot find pool in ObjectCache!" if pool.nil? + descriptor = pool.descriptor_class_by_def[pointer.address] + if descriptor.nil? + pool.descriptor_class_by_def[pointer.address] = private_constructor(pointer, pool) + else + descriptor + end + end + end + end + end +end + diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/type_safety.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/type_safety.rb new file mode 100755 index 00000000..6cdb3e99 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/internal/type_safety.rb @@ -0,0 +1,25 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# A to_native DataConverter method that raises an error if the value is not of the same type. +# Adapted from to https://www.varvet.com/blog/advanced-topics-in-ruby-ffi/ +module Google + module Protobuf + module Internal + module TypeSafety + def to_native(value, ctx = nil) + if value.kind_of?(self) or value.nil? + super + else + raise TypeError.new "Expected a kind of #{name}, was #{value.class}" + end + end + end + end + end +end + diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/map.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/map.rb new file mode 100755 index 00000000..67901212 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/map.rb @@ -0,0 +1,433 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # Map + attach_function :map_clear, :upb_Map_Clear, [:Map], :void + attach_function :map_delete, :upb_Map_Delete, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool + attach_function :map_get, :upb_Map_Get, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool + attach_function :create_map, :upb_Map_New, [Internal::Arena, CType, CType], :Map + attach_function :map_size, :upb_Map_Size, [:Map], :size_t + attach_function :map_set, :upb_Map_Set, [:Map, MessageValue.by_value, MessageValue.by_value, Internal::Arena], :bool + attach_function :map_freeze, :upb_Map_Freeze, [:Map, MiniTable.by_ref], :void + attach_function :map_frozen?, :upb_Map_IsFrozen, [:Map], :bool + + # MapIterator + attach_function :map_next, :upb_MapIterator_Next, [:Map, :pointer], :bool + attach_function :map_done, :upb_MapIterator_Done, [:Map, :size_t], :bool + attach_function :map_key, :upb_MapIterator_Key, [:Map, :size_t], MessageValue.by_value + attach_function :map_value, :upb_MapIterator_Value, [:Map, :size_t], MessageValue.by_value + end + class Map + include Enumerable + ## + # call-seq: + # Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + # => new map + # + # Allocates a new Map container. This constructor may be called with 2, 3, or 4 + # arguments. The first two arguments are always present and are symbols (taking + # on the same values as field-type symbols in message descriptors) that + # indicate the type of the map key and value fields. + # + # The supported key types are: :int32, :int64, :uint32, :uint64, :bool, + # :string, :bytes. + # + # The supported value types are: :int32, :int64, :uint32, :uint64, :bool, + # :string, :bytes, :enum, :message. + # + # The third argument, value_typeclass, must be present if value_type is :enum + # or :message. As in RepeatedField#new, this argument must be a message class + # (for :message) or enum module (for :enum). + # + # The last argument, if present, provides initial content for map. Note that + # this may be an ordinary Ruby hashmap or another Map instance with identical + # key and value types. Also note that this argument may be present whether or + # not value_typeclass is present (and it is unambiguously separate from + # value_typeclass because value_typeclass's presence is strictly determined by + # value_type). The contents of this initial hashmap or Map instance are + # shallow-copied into the new Map: the original map is unmodified, but + # references to underlying objects will be shared if the value type is a + # message type. + def self.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + instance = allocate + # TODO This argument mangling doesn't agree with the type signature, + # but does align with the text of the comments and is required to make unit tests pass. + if init_hashmap.empty? and ![:enum, :message].include?(value_type) + init_hashmap = value_typeclass + value_typeclass = nil + end + instance.send(:initialize, key_type, value_type, value_type_class: value_typeclass, initial_values: init_hashmap) + instance + end + + ## + # call-seq: + # Map.keys => [list_of_keys] + # + # Returns the list of keys contained in the map, in unspecified order. + def keys + return_value = [] + internal_iterator do |iterator| + key_message_value = Google::Protobuf::FFI.map_key(@map_ptr, iterator) + return_value << convert_upb_to_ruby(key_message_value, key_type) + end + return_value + end + + ## + # call-seq: + # Map.values => [list_of_values] + # + # Returns the list of values contained in the map, in unspecified order. + def values + return_value = [] + internal_iterator do |iterator| + value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator) + return_value << convert_upb_to_ruby(value_message_value, value_type, descriptor, arena) + end + return_value + end + + ## + # call-seq: + # Map.[](key) => value + # + # Accesses the element at the given key. Throws an exception if the key type is + # incorrect. Returns nil when the key is not present in the map. + def [](key) + value = Google::Protobuf::FFI::MessageValue.new + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + if Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, value) + convert_upb_to_ruby(value, value_type, descriptor, arena) + end + end + + ## + # call-seq: + # Map.[]=(key, value) => value + # + # Inserts or overwrites the value at the given key with the given new value. + # Throws an exception if the key type is incorrect. Returns the new value that + # was just inserted. + def []=(key, value) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + value_message_value = convert_ruby_to_upb(value, arena, value_type, descriptor) + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + value + end + + def has_key?(key) + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, nil) + end + + ## + # call-seq: + # Map.delete(key) => old_value + # + # Deletes the value at the given key, if any, returning either the old value or + # nil if none was present. Throws an exception if the key is of the wrong type. + def delete(key) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + value = Google::Protobuf::FFI::MessageValue.new + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + if Google::Protobuf::FFI.map_delete(@map_ptr, key_message_value, value) + convert_upb_to_ruby(value, value_type, descriptor, arena) + else + nil + end + end + + def clear + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + Google::Protobuf::FFI.map_clear(@map_ptr) + nil + end + + def length + Google::Protobuf::FFI.map_size(@map_ptr) + end + alias size length + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.map_frozen? @map_ptr + raise RuntimeError.new "Ruby frozen Map with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the map object. We have to intercept this so we can freeze the + # underlying representation, not just the Ruby wrapper. Returns self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.map_frozen? @map_ptr + raise RuntimeError.new "Underlying representation of map still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.map_frozen? @map_ptr + mini_table = (value_type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil + Google::Protobuf::FFI.map_freeze(@map_ptr, mini_table) + end + super + end + + ## + # call-seq: + # Map.dup => new_map + # + # Duplicates this map with a shallow copy. References to all non-primitive + # element objects (e.g., submessages) are shared. + def dup + internal_dup + end + alias clone dup + + ## + # call-seq: + # Map.==(other) => boolean + # + # Compares this map to another. Maps are equal if they have identical key sets, + # and for each key, the values in both maps compare equal. Elements are + # compared as per normal Ruby semantics, by calling their :== methods (or + # performing a more efficient comparison for primitive types). + # + # Maps with dissimilar key types or value types/typeclasses are never equal, + # even if value comparison (for example, between integers and floats) would + # have otherwise indicated that every element has equal value. + def ==(other) + if other.is_a? Hash + other = self.class.send(:private_constructor, key_type, value_type, descriptor, initial_values: other) + elsif !other.is_a? Google::Protobuf::Map + return false + end + + return true if object_id == other.object_id + return false if key_type != other.send(:key_type) or value_type != other.send(:value_type) or descriptor != other.send(:descriptor) or length != other.length + other_map_ptr = other.send(:map_ptr) + each_msg_val do |key_message_value, value_message_value| + other_value = Google::Protobuf::FFI::MessageValue.new + return false unless Google::Protobuf::FFI.map_get(other_map_ptr, key_message_value, other_value) + return false unless Google::Protobuf::FFI.message_value_equal(value_message_value, other_value, value_type, descriptor) + end + true + end + + def hash + return_value = 0 + each_msg_val do |key_message_value, value_message_value| + return_value = Google::Protobuf::FFI.message_value_hash(key_message_value, key_type, nil, return_value) + return_value = Google::Protobuf::FFI.message_value_hash(value_message_value, value_type, descriptor, return_value) + end + return_value + end + + ## + # call-seq: + # Map.to_h => {} + # + # Returns a Ruby Hash object containing all the values within the map + def to_h + return {} if map_ptr.nil? or map_ptr.null? + return_value = {} + each_msg_val do |key_message_value, value_message_value| + hash_key = convert_upb_to_ruby(key_message_value, key_type) + hash_value = scalar_create_hash(value_message_value, value_type, msg_or_enum_descriptor: descriptor) + return_value[hash_key] = hash_value + end + return_value + end + + def inspect + key_value_pairs = [] + each_msg_val do |key_message_value, value_message_value| + key_string = convert_upb_to_ruby(key_message_value, key_type).inspect + if value_type == :message + sub_msg_descriptor = Google::Protobuf::FFI.get_subtype_as_message(descriptor) + value_string = sub_msg_descriptor.msgclass.send(:inspect_internal, value_message_value[:msg_val]) + else + value_string = convert_upb_to_ruby(value_message_value, value_type, descriptor).inspect + end + key_value_pairs << "#{key_string}=>#{value_string}" + end + "{#{key_value_pairs.join(", ")}}" + end + + ## + # call-seq: + # Map.merge(other_map) => map + # + # Copies key/value pairs from other_map into a copy of this map. If a key is + # set in other_map and this map, the value from other_map overwrites the value + # in the new copy of this map. Returns the new copy of this map with merged + # contents. + def merge(other) + internal_merge(other) + end + + ## + # call-seq: + # Map.each(&block) + # + # Invokes &block on each |key, value| pair in the map, in unspecified order. + # Note that Map also includes Enumerable; map thus acts like a normal Ruby + # sequence. + def each &block + each_msg_val do |key_message_value, value_message_value| + key_value = convert_upb_to_ruby(key_message_value, key_type) + value_value = convert_upb_to_ruby(value_message_value, value_type, descriptor, arena) + yield key_value, value_value + end + nil + end + + private + attr :arena, :map_ptr, :key_type, :value_type, :descriptor, :name + + include Google::Protobuf::Internal::Convert + + def internal_iterator + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + while Google::Protobuf::FFI.map_next(@map_ptr, iter) do + iter_size_t = iter.read(:size_t) + yield iter_size_t + end + end + + def each_msg_val &block + internal_iterator do |iterator| + key_message_value = Google::Protobuf::FFI.map_key(@map_ptr, iterator) + value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator) + yield key_message_value, value_message_value + end + end + + def internal_dup + instance = self.class.send(:private_constructor, key_type, value_type, descriptor, arena: arena) + new_map_ptr = instance.send(:map_ptr) + each_msg_val do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(new_map_ptr, key_message_value, value_message_value, arena) + end + instance + end + + def internal_merge_into_self(other) + case other + when Hash + other.each do |key, value| + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + value_message_value = convert_ruby_to_upb(value, arena, value_type, descriptor) + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + end + when Google::Protobuf::Map + unless key_type == other.send(:key_type) and value_type == other.send(:value_type) and descriptor == other.descriptor + raise ArgumentError.new "Attempt to merge Map with mismatching types" #TODO Improve error message by adding type information + end + arena.fuse(other.send(:arena)) + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + other.send(:each_msg_val) do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + end + else + raise ArgumentError.new "Unknown type merging into Map" #TODO improve this error message by including type information + end + self + end + + def internal_merge(other) + internal_dup.internal_merge_into_self(other) + end + + def initialize(key_type, value_type, value_type_class: nil, initial_values: nil, arena: nil, map: nil, descriptor: nil, name: nil) + @name = name || 'Map' + + unless [:int32, :int64, :uint32, :uint64, :bool, :string, :bytes].include? key_type + raise ArgumentError.new "Invalid key type for map." #TODO improve error message to include what type was passed + end + @key_type = key_type + + unless [:int32, :int64, :uint32, :uint64, :bool, :string, :bytes, :enum, :message].include? value_type + raise ArgumentError.new "Invalid value type for map." #TODO improve error message to include what type was passed + end + @value_type = value_type + + if !descriptor.nil? + raise ArgumentError "Expected descriptor to be a Descriptor or EnumDescriptor" unless [EnumDescriptor, Descriptor].include? descriptor.class + @descriptor = descriptor + elsif [:message, :enum].include? value_type + raise ArgumentError.new "Expected at least 3 arguments for message/enum." if value_type_class.nil? + descriptor = value_type_class.respond_to?(:descriptor) ? value_type_class.descriptor : nil + raise ArgumentError.new "Type class #{value_type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil? + @descriptor = descriptor + else + @descriptor = nil + end + + @arena = arena || Google::Protobuf::FFI.create_arena + @map_ptr = map || Google::Protobuf::FFI.create_map(@arena, @key_type, @value_type) + + internal_merge_into_self(initial_values) unless initial_values.nil? + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + OBJECT_CACHE.try_add(@map_ptr.address, self) + end + + ## + # Constructor that uses the type information from the given + # FieldDescriptor to configure the new Map instance. + # @param field [FieldDescriptor] Type information for the new Map + # @param arena [Arena] Owning message's arena + # @param value [Hash|Map] Initial value + # @param map [::FFI::Pointer] Existing upb_Map + def self.construct_for_field(field, arena: nil, value: nil, map: nil) + raise ArgumentError.new "Expected Hash object as initializer value for map field '#{field.name}' (given #{value.class})." unless value.nil? or value.is_a? Hash + instance = allocate + raise ArgumentError.new "Expected field with type :message, instead got #{field.class}" unless field.type == :message + message_descriptor = field.send(:subtype) + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + instance.send(:initialize, key_field_type, value_field_type, initial_values: value, name: field.name, arena: arena, map: map, descriptor: value_field_def.subtype) + instance + end + + def self.private_constructor(key_type, value_type, descriptor, initial_values: nil, arena: nil) + instance = allocate + instance.send(:initialize, key_type, value_type, descriptor: descriptor, initial_values: initial_values, arena: arena) + instance + end + + extend Google::Protobuf::Internal::Convert + + def self.deep_copy(map) + instance = allocate + instance.send(:initialize, map.send(:key_type), map.send(:value_type), descriptor: map.send(:descriptor)) + map.send(:each_msg_val) do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(instance.send(:map_ptr), key_message_value, message_value_deep_copy(value_message_value, map.send(:value_type), map.send(:descriptor), instance.send(:arena)), instance.send(:arena)) + end + instance + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/message.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/message.rb new file mode 100755 index 00000000..4b02ae52 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/message.rb @@ -0,0 +1,785 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + + +# Decorates Descriptor with the `build_message_class` method that defines +# Message classes. +module Google + module Protobuf + class FFI + # Message + attach_function :clear_message_field, :upb_Message_ClearFieldByDef, [:Message, FieldDescriptor], :void + attach_function :get_message_value, :upb_Message_GetFieldByDef, [:Message, FieldDescriptor], MessageValue.by_value + attach_function :get_message_has, :upb_Message_HasFieldByDef, [:Message, FieldDescriptor], :bool + attach_function :set_message_field, :upb_Message_SetFieldByDef, [:Message, FieldDescriptor, MessageValue.by_value, Internal::Arena], :bool + attach_function :encode_message, :upb_Encode, [:Message, MiniTable.by_ref, :size_t, Internal::Arena, :pointer, :pointer], EncodeStatus + attach_function :json_decode_message_detecting_nonconformance, :upb_JsonDecodeDetectingNonconformance, [:binary_string, :size_t, :Message, Descriptor, :DefPool, :int, Internal::Arena, Status.by_ref], :int + attach_function :json_encode_message, :upb_JsonEncode, [:Message, Descriptor, :DefPool, :int, :binary_string, :size_t, Status.by_ref], :size_t + attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus + attach_function :get_mutable_message, :upb_Message_Mutable, [:Message, FieldDescriptor, Internal::Arena], MutableMessageValue.by_value + attach_function :get_message_which_oneof, :upb_Message_WhichOneofByDef, [:Message, OneofDescriptor], FieldDescriptor + attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :int], :bool + attach_function :message_next, :upb_Message_Next, [:Message, Descriptor, :DefPool, :FieldDefPointer, MessageValue.by_ref, :pointer], :bool + attach_function :message_freeze, :upb_Message_Freeze, [:Message, MiniTable.by_ref], :void + attach_function :message_frozen?, :upb_Message_IsFrozen, [:Message], :bool + + # MessageValue + attach_function :message_value_equal, :shared_Msgval_IsEqual, [MessageValue.by_value, MessageValue.by_value, CType, Descriptor], :bool + attach_function :message_value_hash, :shared_Msgval_GetHash, [MessageValue.by_value, CType, Descriptor, :uint64_t], :uint64_t + end + + class Descriptor + def build_message_class + descriptor = self + Class.new(Google::Protobuf::const_get(:AbstractMessage)) do + @descriptor = descriptor + class << self + attr_accessor :descriptor + private + attr_accessor :oneof_field_names + include ::Google::Protobuf::Internal::Convert + end + + alias original_method_missing method_missing + def method_missing(method_name, *args) + method_missing_internal method_name, *args, mode: :method_missing + end + + def respond_to_missing?(method_name, include_private = false) + method_missing_internal(method_name, mode: :respond_to_missing?) || super + end + + ## + # Public constructor. Automatically allocates from a new Arena. + def self.new(initial_value = nil) + instance = allocate + instance.send(:initialize, initial_value) + instance + end + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.message_frozen? @msg + raise RuntimeError.new "Ruby frozen Message with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the map object. We have to intercept this so we can freeze the + # underlying representation, not just the Ruby wrapper. Returns self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.message_frozen? @msg + raise RuntimeError.new "Underlying representation of message still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.message_frozen? @msg + Google::Protobuf::FFI.message_freeze(@msg, Google::Protobuf::FFI.get_mini_table(self.class.descriptor)) + end + super + end + + def dup + duplicate = self.class.private_constructor(@arena) + mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + size = mini_table[:size] + duplicate.instance_variable_get(:@msg).write_string_length(@msg.read_string_length(size), size) + duplicate + end + alias clone dup + + def eql?(other) + return false unless self.class === other + encoding_options = Google::Protobuf::FFI::Upb_Encode_Deterministic | Google::Protobuf::FFI::Upb_Encode_SkipUnknown + temporary_arena = Google::Protobuf::FFI.create_arena + mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + size_one = ::FFI::MemoryPointer.new(:size_t, 1) + encoding_one = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(@msg, mini_table, encoding_options, temporary_arena, encoding_one.to_ptr, size_one) + raise ParseError.new "Error comparing messages due to #{encoding_status} while encoding LHS of `eql?()`" unless encoding_status == :Ok + + size_two = ::FFI::MemoryPointer.new(:size_t, 1) + encoding_two = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(other.instance_variable_get(:@msg), mini_table, encoding_options, temporary_arena, encoding_two.to_ptr, size_two) + raise ParseError.new "Error comparing messages due to #{encoding_status} while encoding RHS of `eql?()`" unless encoding_status == :Ok + + if encoding_one.null? or encoding_two.null? + raise ParseError.new "Error comparing messages" + end + size_one.read(:size_t) == size_two.read(:size_t) and Google::Protobuf::FFI.memcmp(encoding_one.read(:pointer), encoding_two.read(:pointer), size_one.read(:size_t)).zero? + end + alias == eql? + + def hash + encoding_options = Google::Protobuf::FFI::Upb_Encode_Deterministic | Google::Protobuf::FFI::Upb_Encode_SkipUnknown + temporary_arena = Google::Protobuf::FFI.create_arena + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + encoding = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(@msg, mini_table_ptr, encoding_options, temporary_arena, encoding.to_ptr, size_ptr) + if encoding_status != :Ok or encoding.null? + raise ParseError.new "Error calculating hash" + end + encoding.read(:pointer).read_string(size_ptr.read(:size_t)).hash + end + + def to_h + to_h_internal @msg, self.class.descriptor + end + + ## + # call-seq: + # Message.inspect => string + # + # Returns a human-readable string representing this message. It will be + # formatted as "". Each + # field's value is represented according to its own #inspect method. + def inspect + self.class.inspect_internal @msg + end + + def to_s + self.inspect + end + + ## + # call-seq: + # Message.[](index) => value + # Accesses a field's value by field name. The provided field name + # should be a string. + def [](name) + raise TypeError.new "Expected String for name but got #{name.class}" unless name.is_a? String + index_internal name + end + + ## + # call-seq: + # Message.[]=(index, value) + # Sets a field's value by field name. The provided field name should + # be a string. + # @param name [String] Name of the field to be set + # @param value [Object] Value to set the field to + def []=(name, value) + raise TypeError.new "Expected String for name but got #{name.class}" unless name.is_a? String + index_assign_internal(value, name: name) + end + + ## + # call-seq: + # MessageClass.decode(data, options) => message + # + # Decodes the given data (as a string containing bytes in protocol buffers wire + # format) under the interpretation given by this message class's definition + # and returns a message object with the corresponding field values. + # @param data [String] Binary string in Protobuf wire format to decode + # @param options [Hash] options for the decoder + # @option options [Integer] :recursion_limit Set to maximum decoding depth for message (default is 64) + def self.decode(data, options = {}) + raise ArgumentError.new "Expected hash arguments." unless options.is_a? Hash + raise ArgumentError.new "Expected string for binary protobuf data." unless data.is_a? String + decoding_options = 0 + depth = options[:recursion_limit] + + if depth.is_a? Numeric + decoding_options |= Google::Protobuf::FFI.decode_max_depth(depth.to_i) + end + + message = new + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(message.class.descriptor) + status = Google::Protobuf::FFI.decode_message( + data, + data.bytesize, + message.instance_variable_get(:@msg), + mini_table_ptr, + Google::Protobuf::FFI.get_extension_registry(message.class.descriptor.send(:pool).descriptor_pool), + decoding_options, + message.instance_variable_get(:@arena) + ) + raise ParseError.new "Error occurred during parsing" unless status == :Ok + message + end + + ## + # call-seq: + # MessageClass.encode(msg, options) => bytes + # + # Encodes the given message object to its serialized form in protocol buffers + # wire format. + # @param options [Hash] options for the encoder + # @option options [Integer] :recursion_limit Set to maximum encoding depth for message (default is 64) + def self.encode(message, options = {}) + raise ArgumentError.new "Message of wrong type." unless message.is_a? self + raise ArgumentError.new "Expected hash arguments." unless options.is_a? Hash + + encoding_options = 0 + depth = options[:recursion_limit] + + if depth.is_a? Numeric + encoding_options |= Google::Protobuf::FFI.decode_max_depth(depth.to_i) + end + + encode_internal(message.instance_variable_get(:@msg), encoding_options) do |encoding, size, _| + if encoding.nil? or encoding.null? + raise RuntimeError.new "Exceeded maximum depth (possibly cycle)" + else + encoding.read_string_length(size).force_encoding("ASCII-8BIT").freeze + end + end + end + + ## + # all-seq: + # MessageClass.decode_json(data, options = {}) => message + # + # Decodes the given data (as a string containing bytes in protocol buffers wire + # format) under the interpretation given by this message class's definition + # and returns a message object with the corresponding field values. + # + # @param options [Hash] options for the decoder + # @option options [Boolean] :ignore_unknown_fields Set true to ignore unknown fields (default is to raise an error) + # @return [Message] + def self.decode_json(data, options = {}) + decoding_options = 0 + unless options.is_a? Hash + if options.respond_to? :to_h + options options.to_h + else + #TODO can this error message be improve to include what was received? + raise ArgumentError.new "Expected hash arguments" + end + end + raise ArgumentError.new "Expected string for JSON data." unless data.is_a? String + raise RuntimeError.new "Cannot parse a wrapper directly" if descriptor.send(:wrapper?) + + if options[:ignore_unknown_fields] + decoding_options |= Google::Protobuf::FFI::Upb_JsonDecode_IgnoreUnknown + end + + message = new + pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool + status = Google::Protobuf::FFI::Status.new + result = Google::Protobuf::FFI.json_decode_message_detecting_nonconformance(data, data.bytesize, message.instance_variable_get(:@msg), message.class.descriptor, pool_def, decoding_options, message.instance_variable_get(:@arena), status) + case result + when Google::Protobuf::FFI::Upb_JsonDecodeResult_OkWithEmptyStringNumerics + warn Google::Protobuf::FFI.error_message(status) + when Google::Protobuf::FFI::Upb_JsonDecodeResult_Error + raise ParseError.new "Error occurred during parsing: #{Google::Protobuf::FFI.error_message(status)}" + end + message + end + + def self.encode_json(message, options = {}) + encoding_options = 0 + unless options.is_a? Hash + if options.respond_to? :to_h + options = options.to_h + else + #TODO can this error message be improve to include what was received? + raise ArgumentError.new "Expected hash arguments" + end + end + + if options[:preserve_proto_fieldnames] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_UseProtoNames + end + if options[:emit_defaults] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_EmitDefaults + end + if options[:format_enums_as_integers] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_FormatEnumsAsIntegers + end + + buffer_size = 1024 + buffer = ::FFI::MemoryPointer.new(:char, buffer_size) + status = Google::Protobuf::FFI::Status.new + msg = message.instance_variable_get(:@msg) + pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool + size = Google::Protobuf::FFI::json_encode_message(msg, message.class.descriptor, pool_def, encoding_options, buffer, buffer_size, status) + unless status[:ok] + raise ParseError.new "Error occurred during encoding: #{Google::Protobuf::FFI.error_message(status)}" + end + + if size >= buffer_size + buffer_size = size + 1 + buffer = ::FFI::MemoryPointer.new(:char, buffer_size) + status.clear + size = Google::Protobuf::FFI::json_encode_message(msg, message.class.descriptor, pool_def, encoding_options, buffer, buffer_size, status) + unless status[:ok] + raise ParseError.new "Error occurred during encoding: #{Google::Protobuf::FFI.error_message(status)}" + end + if size >= buffer_size + raise ParseError.new "Inconsistent JSON encoding sizes - was #{buffer_size - 1}, now #{size}" + end + end + + buffer.read_string_length(size).force_encoding("UTF-8").freeze + end + + private + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + include Google::Protobuf::Internal::Convert + + ## + # Checks ObjectCache for a sentinel empty frozen Map of the key and + # value types matching the field descriptor's MessageDef and returns + # the cache entry. If an entry is not found, one is created and added + # to the cache keyed by the MessageDef pointer first. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def empty_frozen_map(field_descriptor) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + frozen_map = OBJECT_CACHE.get sub_message_def + if frozen_map.nil? + frozen_map = Google::Protobuf::Map.send(:construct_for_field, field_descriptor) + OBJECT_CACHE.try_add(sub_message_def, frozen_map.freeze) + end + raise "Empty Frozen Map is not frozen" unless frozen_map.frozen? + frozen_map + end + + ## + # Returns a frozen Map instance for the given field. If the message + # already has a value for that field, it is used. If not, a sentinel + # (per FieldDescriptor) empty frozen Map is returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def frozen_map_from_field_descriptor(field_descriptor) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + return empty_frozen_map field_descriptor if message_value[:map_val].null? + get_map_field(message_value[:map_val], field_descriptor).freeze + end + + ## + # Returns a Map instance for the given field. If the message is frozen + # the return value is also frozen. If not, a mutable instance is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def map_from_field_descriptor(field_descriptor) + return frozen_map_from_field_descriptor field_descriptor if frozen? + mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + get_map_field(mutable_message_value[:map], field_descriptor) + end + + ## + # Checks ObjectCache for a sentinel empty frozen RepeatedField of the + # value type matching the field descriptor's MessageDef and returns + # the cache entry. If an entry is not found, one is created and added + # to the cache keyed by the MessageDef pointer first. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def empty_frozen_repeated_field(field_descriptor) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + frozen_repeated_field = OBJECT_CACHE.get sub_message_def + if frozen_repeated_field.nil? + frozen_repeated_field = Google::Protobuf::RepeatedField.send(:construct_for_field, field_descriptor) + OBJECT_CACHE.try_add(sub_message_def, frozen_repeated_field.freeze) + end + raise "Empty frozen RepeatedField is not frozen" unless frozen_repeated_field.frozen? + frozen_repeated_field + end + + ## + # Returns a frozen RepeatedField instance for the given field. If the + # message already has a value for that field, it is used. If not, a + # sentinel (per FieldDescriptor) empty frozen RepeatedField is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def frozen_repeated_field_from_field_descriptor(field_descriptor) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + return empty_frozen_repeated_field field_descriptor if message_value[:array_val].null? + get_repeated_field(message_value[:array_val], field_descriptor).freeze + end + + ## + # Returns a RepeatedField instance for the given field. If the message + # is frozen the return value is also frozen. If not, a mutable + # instance is returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def repeated_field_from_field_descriptor(field_descriptor) + return frozen_repeated_field_from_field_descriptor field_descriptor if frozen? + mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + get_repeated_field(mutable_message_value[:array], field_descriptor) + end + + ## + # Returns a Message instance for the given field. If the message + # is frozen nil is always returned. Otherwise, a mutable instance is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def message_from_field_descriptor(field_descriptor) + return nil if frozen? + return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor + mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + sub_message = mutable_message[:msg] + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + Descriptor.send(:get_message, sub_message, sub_message_def, @arena) + end + + ## + # Returns a scalar value for the given field. If the message + # is frozen the return value is also frozen. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def scalar_from_field_descriptor(field_descriptor) + c_type = field_descriptor.send(:c_type) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + msg_or_enum_def = c_type == :enum ? Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor) : nil + return_value = convert_upb_to_ruby message_value, c_type, msg_or_enum_def + frozen? ? return_value.freeze : return_value + end + + ## + # Dynamically define accessors methods for every field of @descriptor. + # Methods with names that conflict with existing methods are skipped. + def self.setup_accessors! + @descriptor.each do |field_descriptor| + field_name = field_descriptor.name + unless instance_methods(true).include?(field_name.to_sym) + # Dispatching to either index_internal or get_field is logically + # correct, but slightly slower due to having to perform extra + # lookups on each invocation rather than doing it once here. + if field_descriptor.map? + define_method(field_name) do + map_from_field_descriptor field_descriptor + end + elsif field_descriptor.repeated? + define_method(field_name) do + repeated_field_from_field_descriptor field_descriptor + end + elsif field_descriptor.sub_message? + define_method(field_name) do + message_from_field_descriptor field_descriptor + end + else + define_method(field_name) do + scalar_from_field_descriptor field_descriptor + end + end + define_method("#{field_name}=") do |value| + index_assign_internal(value, field_descriptor: field_descriptor) + end + define_method("clear_#{field_name}") do + clear_internal(field_descriptor) + end + if field_descriptor.type == :enum + if field_descriptor.repeated? + define_method("#{field_name}_const") do + return_value = [] + repeated_field_from_field_descriptor(field_descriptor).send(:each_msg_val) do |msg_val| + return_value << msg_val[:int32_val] + end + return_value + end + else + define_method("#{field_name}_const") do + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + message_value[:int32_val] + end + end + end + if !field_descriptor.repeated? and field_descriptor.wrapper? + define_method("#{field_name}_as_value") do + get_field(field_descriptor, unwrap: true) + end + define_method("#{field_name}_as_value=") do |value| + if value.nil? + clear_internal(field_descriptor) + else + index_assign_internal(value, field_descriptor: field_descriptor, wrap: true) + end + end + end + if field_descriptor.has_presence? + define_method("has_#{field_name}?") do + Google::Protobuf::FFI.get_message_has(@msg, field_descriptor) + end + end + end + end + end + + ## + # Dynamically define accessors methods for every OneOf field of + # @descriptor. + def self.setup_oneof_accessors! + @oneof_field_names = [] + @descriptor.each_oneof do |oneof_descriptor| + self.add_oneof_accessors_for! oneof_descriptor + end + end + + ## + # Dynamically define accessors methods for the given OneOf field. + # Methods with names that conflict with existing methods are skipped. + # @param oneof_descriptor [OneofDescriptor] Field to create accessors + # for. + def self.add_oneof_accessors_for!(oneof_descriptor) + field_name = oneof_descriptor.name.to_sym + @oneof_field_names << field_name + unless instance_methods(true).include?(field_name) + define_method(field_name) do + field_descriptor = Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor) + if field_descriptor.nil? + return + else + return field_descriptor.name.to_sym + end + end + define_method("clear_#{field_name}") do + field_descriptor = Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor) + unless field_descriptor.nil? + clear_internal(field_descriptor) + end + end + define_method("has_#{field_name}?") do + !Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor).nil? + end + end + end + + setup_accessors! + setup_oneof_accessors! + + def self.private_constructor(arena, msg: nil, initial_value: nil) + instance = allocate + instance.send(:initialize, initial_value, arena, msg) + instance + end + + def self.inspect_field(field_descriptor, c_type, message_value) + if field_descriptor.sub_message? + sub_msg_descriptor = Google::Protobuf::FFI.get_subtype_as_message(field_descriptor) + sub_msg_descriptor.msgclass.send(:inspect_internal, message_value[:msg_val]) + else + convert_upb_to_ruby(message_value, c_type, field_descriptor.subtype).inspect + end + end + + # @param msg [::FFI::Pointer] Pointer to the Message + def self.inspect_internal(msg) + field_output = [] + descriptor.each do |field_descriptor| + next if field_descriptor.has_presence? && !Google::Protobuf::FFI.get_message_has(msg, field_descriptor) + if field_descriptor.map? + # TODO Adapted - from map#each_msg_val and map#inspect- can this be refactored to reduce echo without introducing a arena allocation? + message_descriptor = field_descriptor.subtype + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + + message_value = Google::Protobuf::FFI.get_message_value(msg, field_descriptor) + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + key_value_pairs = [] + while Google::Protobuf::FFI.map_next(message_value[:map_val], iter) do + iter_size_t = iter.read(:size_t) + key_message_value = Google::Protobuf::FFI.map_key(message_value[:map_val], iter_size_t) + value_message_value = Google::Protobuf::FFI.map_value(message_value[:map_val], iter_size_t) + key_string = convert_upb_to_ruby(key_message_value, key_field_type).inspect + value_string = inspect_field(value_field_def, value_field_type, value_message_value) + key_value_pairs << "#{key_string}=>#{value_string}" + end + field_output << "#{field_descriptor.name}: {#{key_value_pairs.join(", ")}}" + elsif field_descriptor.repeated? + # TODO Adapted - from repeated_field#each - can this be refactored to reduce echo? + repeated_field_output = [] + message_value = Google::Protobuf::FFI.get_message_value(msg, field_descriptor) + array = message_value[:array_val] + n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n - 1) do |i| + element = Google::Protobuf::FFI.get_msgval_at(array, i) + repeated_field_output << inspect_field(field_descriptor, field_descriptor.send(:c_type), element) + end + field_output << "#{field_descriptor.name}: [#{repeated_field_output.join(", ")}]" + else + message_value = Google::Protobuf::FFI.get_message_value msg, field_descriptor + rendered_value = inspect_field(field_descriptor, field_descriptor.send(:c_type), message_value) + field_output << "#{field_descriptor.name}: #{rendered_value}" + end + end + "<#{name}: #{field_output.join(', ')}>" + end + + def self.deep_copy(msg, arena = nil) + arena ||= Google::Protobuf::FFI.create_arena + encode_internal(msg) do |encoding, size, mini_table_ptr| + message = private_constructor(arena) + if encoding.nil? or encoding.null? or Google::Protobuf::FFI.decode_message(encoding, size, message.instance_variable_get(:@msg), mini_table_ptr, nil, 0, arena) != :Ok + raise ParseError.new "Error occurred copying proto" + end + message + end + end + + def self.encode_internal(msg, encoding_options = 0) + temporary_arena = Google::Protobuf::FFI.create_arena + + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(descriptor) + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + pointer_ptr = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(msg, mini_table_ptr, encoding_options, temporary_arena, pointer_ptr.to_ptr, size_ptr) + raise "Encoding failed due to #{encoding_status}" unless encoding_status == :Ok + yield pointer_ptr.read(:pointer), size_ptr.read(:size_t), mini_table_ptr + end + + def method_missing_internal(method_name, *args, mode: nil) + raise ArgumentError.new "method_missing_internal called with invalid mode #{mode.inspect}" unless [:respond_to_missing?, :method_missing].include? mode + + #TODO not being allowed is not the same thing as not responding, but this is needed to pass tests + if method_name.to_s.end_with? '=' + if self.class.send(:oneof_field_names).include? method_name.to_s[0..-2].to_sym + return false if mode == :respond_to_missing? + raise RuntimeError.new "Oneof accessors are read-only." + end + end + + original_method_missing(method_name, *args) if mode == :method_missing + end + + def clear_internal(field_def) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + Google::Protobuf::FFI.clear_message_field(@msg, field_def) + end + + # Accessor for field by name. Does not delegate to methods setup by + # self.setup_accessors! in order to avoid conflicts with bad field + # names e.g. `dup` or `class` which are perfectly valid for proto + # fields. + def index_internal(name) + field_descriptor = self.class.descriptor.lookup(name) + get_field field_descriptor unless field_descriptor.nil? + end + + #TODO - well known types keeps us on our toes by overloading methods. + # How much of the public API needs to be defended? + def index_assign_internal(value, name: nil, field_descriptor: nil, wrap: false) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + if field_descriptor.nil? + field_descriptor = self.class.descriptor.lookup(name) + if field_descriptor.nil? + raise ArgumentError.new "Unknown field: #{name}" + end + end + unless field_descriptor.send :set_value_on_message, value, @msg, @arena, wrap: wrap + raise RuntimeError.new "allocation failed" + end + end + + ## + # @param initial_value [Object] initial value of this Message + # @param arena [Arena] Optional; Arena where this message will be allocated + # @param msg [::FFI::Pointer] Optional; Message to initialize; creates + # one if omitted or nil. + def initialize(initial_value = nil, arena = nil, msg = nil) + @arena = arena || Google::Protobuf::FFI.create_arena + @msg = msg || Google::Protobuf::FFI.new_message_from_def(Google::Protobuf::FFI.get_mini_table(self.class.descriptor), @arena) + + unless initial_value.nil? + raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each + + field_def_ptr = ::FFI::MemoryPointer.new :pointer + oneof_def_ptr = ::FFI::MemoryPointer.new :pointer + + initial_value.each do |key, value| + raise ArgumentError.new "Expected string or symbols as hash keys when initializing proto from hash." unless [String, Symbol].include? key.class + + unless Google::Protobuf::FFI.find_msg_def_by_name self.class.descriptor, key.to_s, key.to_s.bytesize, field_def_ptr, oneof_def_ptr + raise ArgumentError.new "Unknown field name '#{key}' in initialization map entry." + end + raise NotImplementedError.new "Haven't added oneofsupport yet" unless oneof_def_ptr.get_pointer(0).null? + raise NotImplementedError.new "Expected a field def" if field_def_ptr.get_pointer(0).null? + + field_descriptor = FieldDescriptor.from_native field_def_ptr.get_pointer(0) + + next if value.nil? + if field_descriptor.map? + index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, arena: @arena, value: value), name: key.to_s) + elsif field_descriptor.repeated? + index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, arena: @arena, values: value), name: key.to_s) + else + index_assign_internal(value, name: key.to_s) + end + end + end + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + Google::Protobuf::OBJECT_CACHE.try_add @msg.address, self + end + + ## + # Gets a field of this message identified by FieldDescriptor. + # + # @param field [FieldDescriptor] Field to retrieve. + # @param unwrap [Boolean](false) If true, unwraps wrappers. + def get_field(field, unwrap: false) + if field.map? + map_from_field_descriptor field + elsif field.repeated? + repeated_field_from_field_descriptor field + elsif field.sub_message? + return nil unless Google::Protobuf::FFI.get_message_has @msg, field + if unwrap + if field.has?(self) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field + wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field + fields = Google::Protobuf::FFI.field_count(sub_message_def) + raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1 + value_field_def = Google::Protobuf::FFI.get_field_by_number sub_message_def, 1 + message_value = Google::Protobuf::FFI.get_message_value wrapper_message_value[:msg_val], value_field_def + convert_upb_to_ruby message_value, Google::Protobuf::FFI.get_c_type(value_field_def) + else + nil + end + else + message_from_field_descriptor field + end + else + scalar_from_field_descriptor field + end + end + + ## + # Gets a RepeatedField from the ObjectCache or creates a new one. + # @param array [::FFI::Pointer] Pointer to the upb_Array + # @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field + def get_repeated_field(array, field) + return nil if array.nil? or array.null? + repeated_field = OBJECT_CACHE.get(array.address) + if repeated_field.nil? + repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array) + repeated_field.freeze if frozen? + end + repeated_field + end + + ## + # Gets a Map from the ObjectCache or creates a new one. + # @param map [::FFI::Pointer] Pointer to the upb_Map + # @param field [Google::Protobuf::FieldDescriptor] Type of the map field + def get_map_field(map, field) + return nil if map.nil? or map.null? + map_field = OBJECT_CACHE.get(map.address) + if map_field.nil? + map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map) + map_field.freeze if frozen? + end + map_field + end + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/method_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/method_descriptor.rb new file mode 100755 index 00000000..b7bbf0af --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/method_descriptor.rb @@ -0,0 +1,114 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2024 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class MethodDescriptor + attr :method_def, :descriptor_pool + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [MethodDescriptor] MethodDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + method_def_ptr = value.nil? ? nil : value.instance_variable_get(:@method_def) + return ::FFI::Pointer::NULL if method_def_ptr.nil? + raise "Underlying method_def was null!" if method_def_ptr.null? + method_def_ptr + end + + ## + # @param service_def [::FFI::Pointer] MethodDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(method_def, _ = nil) + return nil if method_def.nil? or method_def.null? + service_def = Google::Protobuf::FFI.raw_service_def_by_raw_method_def(method_def) + file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) + descriptor_from_file_def(file_def, method_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_method_name(self) + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.method_options(self, size_ptr, temporary_arena) + Google::Protobuf::MethodOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze + end + end + + def input_type + @input_type ||= Google::Protobuf::FFI.method_input_type(self) + end + + def output_type + @output_type ||= Google::Protobuf::FFI.method_output_type(self) + end + + def client_streaming + @client_streaming ||= Google::Protobuf::FFI.method_client_streaming(self) + end + + def server_streaming + @server_streaming ||= Google::Protobuf::FFI.method_server_streaming(self) + end + + private + + def initialize(method_def, descriptor_pool) + @method_def = method_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(method_def, descriptor_pool) + instance = allocate + instance.send(:initialize, method_def, descriptor_pool) + instance + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # MethodDef + attach_function :raw_service_def_by_raw_method_def, :upb_MethodDef_Service, [:pointer], :pointer + attach_function :get_method_name, :upb_MethodDef_Name, [MethodDescriptor], :string + attach_function :method_options, :MethodDescriptor_serialized_options, [MethodDescriptor, :pointer, Internal::Arena], :pointer + attach_function :method_input_type, :upb_MethodDef_InputType, [MethodDescriptor], Descriptor + attach_function :method_output_type, :upb_MethodDef_OutputType, [MethodDescriptor], Descriptor + attach_function :method_client_streaming, :upb_MethodDef_ClientStreaming, [MethodDescriptor], :bool + attach_function :method_server_streaming, :upb_MethodDef_ServerStreaming, [MethodDescriptor], :bool + end + end +end + diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/object_cache.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/object_cache.rb new file mode 100755 index 00000000..61f5c8e7 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/object_cache.rb @@ -0,0 +1,30 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + private + + SIZEOF_LONG = ::FFI::MemoryPointer.new(:long).size + SIZEOF_VALUE = ::FFI::Pointer::SIZE + + def self.interpreter_supports_non_finalized_keys_in_weak_map? + ! defined? JRUBY_VERSION + end + + def self.cache_implementation + if interpreter_supports_non_finalized_keys_in_weak_map? and SIZEOF_LONG >= SIZEOF_VALUE + Google::Protobuf::Internal::ObjectCache + else + Google::Protobuf::Internal::LegacyObjectCache + end + end + + public + OBJECT_CACHE = cache_implementation.new + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/oneof_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/oneof_descriptor.rb new file mode 100755 index 00000000..65050ef0 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/oneof_descriptor.rb @@ -0,0 +1,97 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class OneofDescriptor + attr :descriptor_pool, :oneof_def + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [OneofDescriptor] FieldDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _ = nil) + value.instance_variable_get(:@oneof_def) || ::FFI::Pointer::NULL + end + + ## + # @param oneof_def [::FFI::Pointer] OneofDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(oneof_def, _ = nil) + return nil if oneof_def.nil? or oneof_def.null? + message_descriptor = Google::Protobuf::FFI.get_oneof_containing_type oneof_def + raise RuntimeError.new "Message Descriptor is nil" if message_descriptor.nil? + file_def = Google::Protobuf::FFI.get_message_file_def message_descriptor.to_native + descriptor_from_file_def(file_def, oneof_def) + end + end + + def self.new(*arguments, &block) + raise "OneofDescriptor objects may not be created from Ruby." + end + + def name + Google::Protobuf::FFI.get_oneof_name(self) + end + + def each &block + n = Google::Protobuf::FFI.get_oneof_field_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_oneof_field_by_index(self, i)) + end + nil + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.oneof_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::OneofOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + private + + def initialize(oneof_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @oneof_def = oneof_def + end + + def self.private_constructor(oneof_def, descriptor_pool) + instance = allocate + instance.send(:initialize, oneof_def, descriptor_pool) + instance + end + end + + class FFI + # MessageDef + attach_function :get_oneof_by_name, :upb_MessageDef_FindOneofByNameWithSize, [Descriptor, :string, :size_t], OneofDescriptor + attach_function :get_oneof_by_index, :upb_MessageDef_Oneof, [Descriptor, :int], OneofDescriptor + + # OneofDescriptor + attach_function :get_oneof_name, :upb_OneofDef_Name, [OneofDescriptor], :string + attach_function :get_oneof_field_count, :upb_OneofDef_FieldCount, [OneofDescriptor], :int + attach_function :get_oneof_field_by_index, :upb_OneofDef_Field, [OneofDescriptor, :int], FieldDescriptor + attach_function :get_oneof_containing_type,:upb_OneofDef_ContainingType, [:pointer], Descriptor + attach_function :oneof_options, :OneOfDescriptor_serialized_options, [OneofDescriptor, :pointer, Internal::Arena], :pointer + + # FieldDescriptor + attach_function :real_containing_oneof, :upb_FieldDef_RealContainingOneof, [FieldDescriptor], OneofDescriptor + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/repeated_field.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/repeated_field.rb new file mode 100755 index 00000000..5c3306e8 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/repeated_field.rb @@ -0,0 +1,411 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# +# This class makes RepeatedField act (almost-) like a Ruby Array. +# It has convenience methods that extend the core C or Java based +# methods. +# +# This is a best-effort to mirror Array behavior. Two comments: +# 1) patches always welcome :) +# 2) if performance is an issue, feel free to rewrite the method +# in C. The source code has plenty of examples +# +# KNOWN ISSUES +# - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'` +# - #concat should return the orig array +# - #push should accept multiple arguments and push them all at the same time +# +module Google + module Protobuf + class FFI + # Array + attach_function :append_array, :upb_Array_Append, [:Array, MessageValue.by_value, Internal::Arena], :bool + attach_function :get_msgval_at, :upb_Array_Get, [:Array, :size_t], MessageValue.by_value + attach_function :create_array, :upb_Array_New, [Internal::Arena, CType], :Array + attach_function :array_resize, :upb_Array_Resize, [:Array, :size_t, Internal::Arena], :bool + attach_function :array_set, :upb_Array_Set, [:Array, :size_t, MessageValue.by_value], :void + attach_function :array_size, :upb_Array_Size, [:Array], :size_t + attach_function :array_freeze, :upb_Array_Freeze, [:Array, MiniTable.by_ref], :void + attach_function :array_frozen?, :upb_Array_IsFrozen, [:Array], :bool + end + + class RepeatedField + include Enumerable + + ## + # call-seq: + # RepeatedField.new(type, type_class = nil, initial_values = []) + # + # Creates a new repeated field. The provided type must be a Ruby symbol, and + # an take on the same values as those accepted by FieldDescriptor#type=. If + # the type is :message or :enum, type_class must be non-nil, and must be the + # Ruby class or module returned by Descriptor#msgclass or + # EnumDescriptor#enummodule, respectively. An initial list of elements may also + # be provided. + def self.new(type, type_class = nil, initial_values = []) + instance = allocate + # TODO This argument mangling doesn't agree with the type signature in the comments + # but is required to make unit tests pass; + if type_class.is_a?(Enumerable) and initial_values.empty? and ![:enum, :message].include?(type) + initial_values = type_class + type_class = nil + end + instance.send(:initialize, type, type_class: type_class, initial_values: initial_values) + instance + end + + ## + # call-seq: + # RepeatedField.each(&block) + # + # Invokes the block once for each element of the repeated field. RepeatedField + # also includes Enumerable; combined with this method, the repeated field thus + # acts like an ordinary Ruby sequence. + def each &block + each_msg_val do |element| + yield(convert_upb_to_ruby(element, type, descriptor, arena)) + end + self + end + + def [](*args) + count = length + if args.size < 1 + raise ArgumentError.new "Index or range is a required argument." + end + if args[0].is_a? Range + if args.size > 1 + raise ArgumentError.new "Expected 1 when passing Range argument, but got #{args.size}" + end + range = args[0] + # Handle begin-less and/or endless ranges, when supported. + index_of_first = range.respond_to?(:begin) ? range.begin : range.last + index_of_first = 0 if index_of_first.nil? + end_of_range = range.respond_to?(:end) ? range.end : range.last + index_of_last = end_of_range.nil? ? -1 : end_of_range + + if index_of_last < 0 + index_of_last += count + end + unless range.exclude_end? and !end_of_range.nil? + index_of_last += 1 + end + index_of_first += count if index_of_first < 0 + length = index_of_last - index_of_first + return [] if length.zero? + elsif args[0].is_a? Integer + index_of_first = args[0] + index_of_first += count if index_of_first < 0 + if args.size > 2 + raise ArgumentError.new "Expected 1 or 2 arguments, but got #{args.size}" + end + if args.size == 1 # No length specified, return one element + if array.null? or index_of_first < 0 or index_of_first >= count + return nil + else + return convert_upb_to_ruby(Google::Protobuf::FFI.get_msgval_at(array, index_of_first), type, descriptor, arena) + end + else + length = [args[1],count].min + end + else + raise NotImplementedError + end + + if array.null? or index_of_first < 0 or index_of_first >= count + nil + else + if index_of_first + length > count + length = count - index_of_first + end + if length < 0 + nil + else + subarray(index_of_first, length) + end + end + end + alias at [] + + + def []=(index, value) + raise FrozenError if frozen? + count = length + index += count if index < 0 + return nil if index < 0 + if index >= count + resize(index+1) + empty_message_value = Google::Protobuf::FFI::MessageValue.new # Implicitly clear + count.upto(index-1) do |i| + Google::Protobuf::FFI.array_set(array, i, empty_message_value) + end + end + Google::Protobuf::FFI.array_set(array, index, convert_ruby_to_upb(value, arena, type, descriptor)) + nil + end + + def push(*elements) + raise FrozenError if frozen? + internal_push(*elements) + end + + def <<(element) + raise FrozenError if frozen? + push element + end + + def replace(replacements) + raise FrozenError if frozen? + clear + push(*replacements) + end + + def clear + raise FrozenError if frozen? + resize 0 + self + end + + def length + array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + end + alias size :length + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.array_frozen? array + raise RuntimeError.new "Ruby frozen RepeatedField with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the RepeatedField object. We have to intercept this so we can + # freeze the underlying representation, not just the Ruby wrapper. Returns + # self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.array_frozen? array + raise RuntimeError.new "Underlying representation of repeated field still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.array_frozen? array + mini_table = (type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil + Google::Protobuf::FFI.array_freeze(array, mini_table) + end + super + end + + def dup + instance = self.class.allocate + instance.send(:initialize, type, descriptor: descriptor, arena: arena) + each_msg_val do |element| + instance.send(:append_msg_val, element) + end + instance + end + alias clone dup + + def ==(other) + return true if other.object_id == object_id + if other.is_a? RepeatedField + return false unless other.length == length + each_msg_val_with_index do |msg_val, i| + other_msg_val = Google::Protobuf::FFI.get_msgval_at(other.send(:array), i) + unless Google::Protobuf::FFI.message_value_equal(msg_val, other_msg_val, type, descriptor) + return false + end + end + return true + elsif other.is_a? Enumerable + return to_ary == other.to_a + end + false + end + + ## + # call-seq: + # RepeatedField.to_ary => array + # + # Used when converted implicitly into array, e.g. compared to an Array. + # Also called as a fallback of Object#to_a + def to_ary + return_value = [] + each do |element| + return_value << element + end + return_value + end + + def hash + return_value = 0 + each_msg_val do |msg_val| + return_value = Google::Protobuf::FFI.message_value_hash(msg_val, type, descriptor, return_value) + end + return_value + end + + def +(other) + if other.is_a? RepeatedField + if type != other.instance_variable_get(:@type) or descriptor != other.instance_variable_get(:@descriptor) + raise ArgumentError.new "Attempt to append RepeatedField with different element type." + end + fuse_arena(other.send(:arena)) + super_set = dup + other.send(:each_msg_val) do |msg_val| + super_set.send(:append_msg_val, msg_val) + end + super_set + elsif other.is_a? Enumerable + super_set = dup + super_set.push(*other.to_a) + else + raise ArgumentError.new "Unknown type appending to RepeatedField" + end + end + + def concat(other) + raise ArgumentError.new "Expected Enumerable, but got #{other.class}" unless other.is_a? Enumerable + push(*other.to_a) + end + + private + include Google::Protobuf::Internal::Convert + + attr :name, :arena, :array, :type, :descriptor + + def internal_push(*elements) + elements.each do |element| + append_msg_val convert_ruby_to_upb(element, arena, type, descriptor) + end + self + end + + def pop_one + raise FrozenError if frozen? + count = length + return nil if length.zero? + last_element = Google::Protobuf::FFI.get_msgval_at(array, count-1) + return_value = convert_upb_to_ruby(last_element, type, descriptor, arena) + resize(count-1) + return_value + end + + def subarray(start, length) + return_result = [] + (start..(start + length - 1)).each do |i| + element = Google::Protobuf::FFI.get_msgval_at(array, i) + return_result << convert_upb_to_ruby(element, type, descriptor, arena) + end + return_result + end + + def each_msg_val_with_index &block + n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n-1) do |i| + yield Google::Protobuf::FFI.get_msgval_at(array, i), i + end + end + + def each_msg_val &block + each_msg_val_with_index do |msg_val, _| + yield msg_val + end + end + + # @param msg_val [Google::Protobuf::FFI::MessageValue] Value to append + def append_msg_val(msg_val) + unless Google::Protobuf::FFI.append_array(array, msg_val, arena) + raise NoMemoryError.new "Could not allocate room for #{msg_val} in Arena" + end + end + + # @param new_size [Integer] New size of the array + def resize(new_size) + unless Google::Protobuf::FFI.array_resize(array, new_size, arena) + raise NoMemoryError.new "Array resize to #{new_size} failed!" + end + end + + def initialize(type, type_class: nil, initial_values: nil, name: nil, arena: nil, array: nil, descriptor: nil) + @name = name || 'RepeatedField' + raise ArgumentError.new "Expected argument type to be a Symbol" unless type.is_a? Symbol + field_number = Google::Protobuf::FFI::FieldType[type] + raise ArgumentError.new "Unsupported type '#{type}'" if field_number.nil? + if !descriptor.nil? + @descriptor = descriptor + elsif [:message, :enum].include? type + raise ArgumentError.new "Expected at least 2 arguments for message/enum." if type_class.nil? + descriptor = type_class.respond_to?(:descriptor) ? type_class.descriptor : nil + raise ArgumentError.new "Type class #{type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil? + @descriptor = descriptor + else + @descriptor = nil + end + @type = type + + @arena = arena || Google::Protobuf::FFI.create_arena + @array = array || Google::Protobuf::FFI.create_array(@arena, @type) + unless initial_values.nil? + unless initial_values.is_a? Enumerable + raise ArgumentError.new "Expected array as initializer value for repeated field '#{name}' (given #{initial_values.class})." + end + internal_push(*initial_values) + end + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + OBJECT_CACHE.try_add(@array.address, self) + end + + ## + # Constructor that uses the type information from the given + # FieldDescriptor to configure the new RepeatedField instance. + # @param field [FieldDescriptor] Type information for the new RepeatedField + # @param arena [Arena] Owning message's arena + # @param values [Enumerable] Initial values + # @param array [::FFI::Pointer] Existing upb_Array + def self.construct_for_field(field, arena: nil, values: nil, array: nil) + instance = allocate + options = {initial_values: values, name: field.name, arena: arena, array: array} + if [:enum, :message].include? field.type + options[:descriptor] = field.subtype + end + instance.send(:initialize, field.type, **options) + instance + end + + def fuse_arena(arena) + arena.fuse(arena) + end + + extend Google::Protobuf::Internal::Convert + + def self.deep_copy(repeated_field) + instance = allocate + instance.send(:initialize, repeated_field.send(:type), descriptor: repeated_field.send(:descriptor)) + instance.send(:resize, repeated_field.length) + new_array = instance.send(:array) + repeated_field.send(:each_msg_val_with_index) do |element, i| + Google::Protobuf::FFI.array_set(new_array, i, message_value_deep_copy(element, repeated_field.send(:type), repeated_field.send(:descriptor), instance.send(:arena))) + end + instance + end + + end + end +end + +require 'google/protobuf/repeated_field' diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/service_descriptor.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/service_descriptor.rb new file mode 100755 index 00000000..d8554d37 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/ffi/service_descriptor.rb @@ -0,0 +1,107 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2024 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class ServiceDescriptor + attr :service_def, :descriptor_pool + include Enumerable + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [ServiceDescriptor] ServiceDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + service_def_ptr = value.nil? ? nil : value.instance_variable_get(:@service_def) + return ::FFI::Pointer::NULL if service_def_ptr.nil? + raise "Underlying service_def was null!" if service_def_ptr.null? + service_def_ptr + end + + ## + # @param service_def [::FFI::Pointer] ServiceDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(service_def, _ = nil) + return nil if service_def.nil? or service_def.null? + file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) + descriptor_from_file_def(file_def, service_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_service_full_name(self) + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.file_def_by_raw_service_def(@service_def)) + end + + def each &block + n = Google::Protobuf::FFI.method_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_method_by_index(self, i)) + end + nil + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.service_options(self, size_ptr, temporary_arena) + Google::Protobuf::ServiceOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze + end + end + + private + + def initialize(service_def, descriptor_pool) + @service_def = service_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(service_def, descriptor_pool) + instance = allocate + instance.send(:initialize, service_def, descriptor_pool) + instance + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # ServiceDef + attach_function :file_def_by_raw_service_def, :upb_ServiceDef_File, [:pointer], :FileDef + attach_function :get_service_full_name, :upb_ServiceDef_FullName, [ServiceDescriptor], :string + attach_function :method_count, :upb_ServiceDef_MethodCount, [ServiceDescriptor], :int + attach_function :get_method_by_index, :upb_ServiceDef_Method, [ServiceDescriptor, :int], MethodDescriptor + attach_function :service_options, :ServiceDescriptor_serialized_options, [ServiceDescriptor, :pointer, Internal::Arena], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/field_mask_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/field_mask_pb.rb new file mode 100755 index 00000000..f241be5f --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/field_mask_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/field_mask.proto + +require 'google/protobuf' + + +descriptor_data = "\n google/protobuf/field_mask.proto\x12\x0fgoogle.protobuf\"\x1a\n\tFieldMask\x12\r\n\x05paths\x18\x01 \x03(\tB\x85\x01\n\x13\x63om.google.protobufB\x0e\x46ieldMaskProtoP\x01Z2google.golang.org/protobuf/types/known/fieldmaskpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + FieldMask = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldMask").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/internal/object_cache.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/internal/object_cache.rb new file mode 100755 index 00000000..38e9bb5f --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/internal/object_cache.rb @@ -0,0 +1,99 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module Internal + # A pointer -> Ruby Object cache that keeps references to Ruby wrapper + # objects. This allows us to look up any Ruby wrapper object by the address + # of the object it is wrapping. That way we can avoid ever creating two + # different wrapper objects for the same C object, which saves memory and + # preserves object identity. + # + # We use WeakMap for the cache. If sizeof(long) > sizeof(VALUE), we also + # need a secondary Hash to store WeakMap keys, because our pointer keys may + # need to be stored as Bignum instead of Fixnum. Since WeakMap is weak for + # both keys and values, a Bignum key will cause the WeakMap entry to be + # collected immediately unless there is another reference to the Bignum. + # This happens on 64-bit Windows, on which pointers are 64 bits but longs + # are 32 bits. In this case, we enable the secondary Hash to hold the keys + # and prevent them from being collected. + class ObjectCache + def initialize + @map = ObjectSpace::WeakMap.new + @mutex = Mutex.new + end + + def get(key) + @map[key] + end + + def try_add(key, value) + @map[key] || @mutex.synchronize do + @map[key] ||= value + end + end + end + + class LegacyObjectCache + def initialize + @secondary_map = {} + @map = ObjectSpace::WeakMap.new + @mutex = Mutex.new + end + + def get(key) + value = if secondary_key = @secondary_map[key] + @map[secondary_key] + else + @mutex.synchronize do + @map[(@secondary_map[key] ||= Object.new)] + end + end + + # GC if we could remove at least 2000 entries or 20% of the table size + # (whichever is greater). Since the cost of the GC pass is O(N), we + # want to make sure that we condition this on overall table size, to + # avoid O(N^2) CPU costs. + cutoff = (@secondary_map.size * 0.2).ceil + cutoff = 2_000 if cutoff < 2_000 + if (@secondary_map.size - @map.size) > cutoff + purge + end + + value + end + + def try_add(key, value) + if secondary_key = @secondary_map[key] + if old_value = @map[secondary_key] + return old_value + end + end + + @mutex.synchronize do + secondary_key ||= (@secondary_map[key] ||= Object.new) + @map[secondary_key] ||= value + end + end + + private + + def purge + @mutex.synchronize do + @secondary_map.each do |key, secondary_key| + unless @map.key?(secondary_key) + @secondary_map.delete(key) + end + end + end + nil + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/message_exts.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/message_exts.rb new file mode 100755 index 00000000..dd1b7320 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/message_exts.rb @@ -0,0 +1,35 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module MessageExts + + #this is only called in jruby; mri loades the ClassMethods differently + def self.included(klass) + klass.extend(ClassMethods) + end + + module ClassMethods + end + + def to_json(options = {}) + self.class.encode_json(self, options) + end + + def to_proto(options = {}) + self.class.encode(self, options) + end + + end + class AbstractMessage + include MessageExts + extend MessageExts::ClassMethods + end + private_constant :AbstractMessage + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/plugin_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/plugin_pb.rb new file mode 100755 index 00000000..de3bf074 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/plugin_pb.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/compiler/plugin.proto + +require 'google/protobuf' + +require 'google/protobuf/descriptor_pb' + + +descriptor_data = "\n%google/protobuf/compiler/plugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"F\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x12\r\n\x05patch\x18\x03 \x01(\x05\x12\x0e\n\x06suffix\x18\x04 \x01(\t\"\x81\x02\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12\x45\n\x17source_file_descriptors\x18\x11 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12;\n\x10\x63ompiler_version\x18\x03 \x01(\x0b\x32!.google.protobuf.compiler.Version\"\x92\x03\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x1a\n\x12supported_features\x18\x02 \x01(\x04\x12\x17\n\x0fminimum_edition\x18\x03 \x01(\x05\x12\x17\n\x0fmaximum_edition\x18\x04 \x01(\x05\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a\x7f\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\t\x12?\n\x13generated_code_info\x18\x10 \x01(\x0b\x32\".google.protobuf.GeneratedCodeInfo\"W\n\x07\x46\x65\x61ture\x12\x10\n\x0c\x46\x45\x41TURE_NONE\x10\x00\x12\x1b\n\x17\x46\x45\x41TURE_PROTO3_OPTIONAL\x10\x01\x12\x1d\n\x19\x46\x45\x41TURE_SUPPORTS_EDITIONS\x10\x02\x42r\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtosZ)google.golang.org/protobuf/types/pluginpb\xaa\x02\x18Google.Protobuf.Compiler" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + module Compiler + Version = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.Version").msgclass + CodeGeneratorRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorRequest").msgclass + CodeGeneratorResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse").msgclass + CodeGeneratorResponse::File = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse.File").msgclass + CodeGeneratorResponse::Feature = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse.Feature").enummodule + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/repeated_field.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/repeated_field.rb new file mode 100755 index 00000000..53de122f --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/repeated_field.rb @@ -0,0 +1,177 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'forwardable' + +# +# This class makes RepeatedField act (almost-) like a Ruby Array. +# It has convenience methods that extend the core C or Java based +# methods. +# +# This is a best-effort to mirror Array behavior. Two comments: +# 1) patches always welcome :) +# 2) if performance is an issue, feel free to rewrite the method +# in jruby and C. The source code has plenty of examples +# +# KNOWN ISSUES +# - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'` +# - #concat should return the orig array +# - #push should accept multiple arguments and push them all at the same time +# +module Google + module Protobuf + class RepeatedField + extend Forwardable + + # methods defined in C or Java: + # + + # [], at + # []= + # concat + # clear + # dup, clone + # each + # push, << + # replace + # length, size + # == + # to_ary, to_a + # also all enumerable + # + # NOTE: using delegators rather than method_missing to make the + # relationship explicit instead of implicit + def_delegators :to_ary, + :&, :*, :-, :'<=>', + :assoc, :bsearch, :bsearch_index, :combination, :compact, :count, + :cycle, :difference, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten, + :include?, :index, :inspect, :intersection, :join, + :pack, :permutation, :product, :pretty_print, :pretty_print_cycle, + :rassoc, :repeated_combination, :repeated_permutation, :reverse, + :rindex, :rotate, :sample, :shuffle, :shelljoin, + :to_s, :transpose, :union, :uniq, :| + + + def first(n=nil) + if n.nil? + return self[0] + elsif n < 0 + raise ArgumentError, "negative array size" + else + return self[0...n] + end + end + + + def last(n=nil) + if n.nil? + return self[-1] + elsif n < 0 + raise ArgumentError, "negative array size" + else + start = [self.size-n, 0].max + return self[start...self.size] + end + end + + + def pop(n=nil) + if n + results = [] + n.times{ results << pop_one } + return results + else + return pop_one + end + end + + + def empty? + self.size == 0 + end + + # array aliases into enumerable + alias_method :slice, :[] + alias_method :values_at, :select + alias_method :map, :collect + + + class << self + def define_array_wrapper_method(method_name) + define_method(method_name) do |*args, &block| + arr = self.to_a + result = arr.send(method_name, *args) + self.replace(arr) + return result if result + return block ? block.call : result + end + end + private :define_array_wrapper_method + + + def define_array_wrapper_with_result_method(method_name) + define_method(method_name) do |*args, &block| + # result can be an Enumerator, Array, or nil + # Enumerator can sometimes be returned if a block is an optional argument and it is not passed in + # nil usually specifies that no change was made + result = self.to_a.send(method_name, *args, &block) + if result + new_arr = result.to_a + self.replace(new_arr) + if result.is_a?(Enumerator) + # generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will + # reset the enum with the same length, but all the #next calls will + # return nil + result = new_arr.to_enum + # generate a wrapper enum so any changes which occur by a chained + # enum can be captured + ie = ProxyingEnumerator.new(self, result) + result = ie.to_enum + end + end + result + end + end + private :define_array_wrapper_with_result_method + end + + + %w(delete delete_at shift slice! unshift).each do |method_name| + define_array_wrapper_method(method_name) + end + + + %w(collect! compact! delete_if each_index fill flatten! insert reverse! + rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name| + define_array_wrapper_with_result_method(method_name) + end + alias_method :keep_if, :select! + alias_method :map!, :collect! + alias_method :reject!, :delete_if + + + # propagates changes made by user of enumerator back to the original repeated field. + # This only applies in cases where the calling function which created the enumerator, + # such as #sort!, modifies itself rather than a new array, such as #sort + class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator) + def each(*args, &block) + results = [] + external_enumerator.each_with_index do |val, i| + result = yield(val) + results << result + #nil means no change occurred from yield; usually occurs when #to_a is called + if result + repeated_field[i] = result if result != val + end + end + results + end + end + + + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/source_context_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/source_context_pb.rb new file mode 100755 index 00000000..f913c6f4 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/source_context_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/source_context.proto + +require 'google/protobuf' + + +descriptor_data = "\n$google/protobuf/source_context.proto\x12\x0fgoogle.protobuf\"\"\n\rSourceContext\x12\x11\n\tfile_name\x18\x01 \x01(\tB\x8a\x01\n\x13\x63om.google.protobufB\x12SourceContextProtoP\x01Z6google.golang.org/protobuf/types/known/sourcecontextpb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + SourceContext = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceContext").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/struct_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/struct_pb.rb new file mode 100755 index 00000000..5b8422cb --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/struct_pb.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/struct.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1cgoogle/protobuf/struct.proto\x12\x0fgoogle.protobuf\"\x84\x01\n\x06Struct\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.protobuf.Struct.FieldsEntry\x1a\x45\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01\"\xea\x01\n\x05Value\x12\x30\n\nnull_value\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x16\n\x0cnumber_value\x18\x02 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x03 \x01(\tH\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12/\n\x0cstruct_value\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x12\x30\n\nlist_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x42\x06\n\x04kind\"3\n\tListValue\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value*\x1b\n\tNullValue\x12\x0e\n\nNULL_VALUE\x10\x00\x42\x7f\n\x13\x63om.google.protobufB\x0bStructProtoP\x01Z/google.golang.org/protobuf/types/known/structpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Struct = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Struct").msgclass + Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Value").msgclass + ListValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ListValue").msgclass + NullValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.NullValue").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/timestamp_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/timestamp_pb.rb new file mode 100755 index 00000000..e3c9e07c --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/timestamp_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/timestamp.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1fgoogle/protobuf/timestamp.proto\x12\x0fgoogle.protobuf\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x85\x01\n\x13\x63om.google.protobufB\x0eTimestampProtoP\x01Z2google.golang.org/protobuf/types/known/timestamppb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Timestamp = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Timestamp").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/type_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/type_pb.rb new file mode 100755 index 00000000..b921d456 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/type_pb.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/type.proto + +require 'google/protobuf' + +require 'google/protobuf/any_pb' +require 'google/protobuf/source_context_pb' + + +descriptor_data = "\n\x1agoogle/protobuf/type.proto\x12\x0fgoogle.protobuf\x1a\x19google/protobuf/any.proto\x1a$google/protobuf/source_context.proto\"\xe8\x01\n\x04Type\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Field\x12\x0e\n\x06oneofs\x18\x03 \x03(\t\x12(\n\x07options\x18\x04 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x06 \x01(\x0e\x32\x17.google.protobuf.Syntax\x12\x0f\n\x07\x65\x64ition\x18\x07 \x01(\t\"\xd5\x05\n\x05\x46ield\x12)\n\x04kind\x18\x01 \x01(\x0e\x32\x1b.google.protobuf.Field.Kind\x12\x37\n\x0b\x63\x61rdinality\x18\x02 \x01(\x0e\x32\".google.protobuf.Field.Cardinality\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x10\n\x08type_url\x18\x06 \x01(\t\x12\x13\n\x0boneof_index\x18\x07 \x01(\x05\x12\x0e\n\x06packed\x18\x08 \x01(\x08\x12(\n\x07options\x18\t \x03(\x0b\x32\x17.google.protobuf.Option\x12\x11\n\tjson_name\x18\n \x01(\t\x12\x15\n\rdefault_value\x18\x0b \x01(\t\"\xc8\x02\n\x04Kind\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"t\n\x0b\x43\x61rdinality\x12\x17\n\x13\x43\x41RDINALITY_UNKNOWN\x10\x00\x12\x18\n\x14\x43\x41RDINALITY_OPTIONAL\x10\x01\x12\x18\n\x14\x43\x41RDINALITY_REQUIRED\x10\x02\x12\x18\n\x14\x43\x41RDINALITY_REPEATED\x10\x03\"\xdf\x01\n\x04\x45num\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\tenumvalue\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.EnumValue\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x05 \x01(\x0e\x32\x17.google.protobuf.Syntax\x12\x0f\n\x07\x65\x64ition\x18\x06 \x01(\t\"S\n\tEnumValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\";\n\x06Option\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any*C\n\x06Syntax\x12\x11\n\rSYNTAX_PROTO2\x10\x00\x12\x11\n\rSYNTAX_PROTO3\x10\x01\x12\x13\n\x0fSYNTAX_EDITIONS\x10\x02\x42{\n\x13\x63om.google.protobufB\tTypeProtoP\x01Z-google.golang.org/protobuf/types/known/typepb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Type").msgclass + Field = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field").msgclass + Field::Kind = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Kind").enummodule + Field::Cardinality = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Cardinality").enummodule + Enum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Enum").msgclass + EnumValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValue").msgclass + Option = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Option").msgclass + Syntax = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Syntax").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/well_known_types.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/well_known_types.rb new file mode 100755 index 00000000..c2df7236 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/well_known_types.rb @@ -0,0 +1,211 @@ +#!/usr/bin/ruby +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'google/protobuf/any_pb' +require 'google/protobuf/duration_pb' +require 'google/protobuf/field_mask_pb' +require 'google/protobuf/struct_pb' +require 'google/protobuf/timestamp_pb' + +module Google + module Protobuf + + Any.class_eval do + def self.pack(msg, type_url_prefix='type.googleapis.com/') + any = self.new + any.pack(msg, type_url_prefix) + any + end + + def pack(msg, type_url_prefix='type.googleapis.com/') + if type_url_prefix.empty? or type_url_prefix[-1] != '/' then + self.type_url = "#{type_url_prefix}/#{msg.class.descriptor.name}" + else + self.type_url = "#{type_url_prefix}#{msg.class.descriptor.name}" + end + self.value = msg.to_proto + end + + def unpack(klass) + if self.is(klass) then + klass.decode(self.value) + else + nil + end + end + + def type_name + return self.type_url.split("/")[-1] + end + + def is(klass) + return self.type_name == klass.descriptor.name + end + end + + Timestamp.class_eval do + def to_time + Time.at(seconds, nanos, :nanosecond) + end + + def self.from_time(time) + new.from_time(time) + end + + def from_time(time) + self.seconds = time.to_i + self.nanos = time.nsec + self + end + + def to_i + self.seconds + end + + def to_f + self.seconds + (self.nanos.quo(1_000_000_000)) + end + end + + Duration.class_eval do + def to_f + self.seconds + (self.nanos.to_f / 1_000_000_000) + end + end + + class UnexpectedStructType < Google::Protobuf::Error; end + + Value.class_eval do + def to_ruby(recursive = false) + case self.kind + when :struct_value + if recursive + self.struct_value.to_h + else + self.struct_value + end + when :list_value + if recursive + self.list_value.to_a + else + self.list_value + end + when :null_value + nil + when :number_value + self.number_value + when :string_value + self.string_value + when :bool_value + self.bool_value + else + raise UnexpectedStructType + end + end + + def self.from_ruby(value) + self.new.from_ruby(value) + end + + def from_ruby(value) + case value + when NilClass + self.null_value = :NULL_VALUE + when Numeric + self.number_value = value + when String + self.string_value = value + when TrueClass + self.bool_value = true + when FalseClass + self.bool_value = false + when Struct + self.struct_value = value + when Hash + self.struct_value = Struct.from_hash(value) + when ListValue + self.list_value = value + when Array + self.list_value = ListValue.from_a(value) + else + raise UnexpectedStructType + end + + self + end + end + + Struct.class_eval do + def [](key) + self.fields[key].to_ruby + rescue NoMethodError + nil + end + + def []=(key, value) + unless key.is_a?(String) + raise UnexpectedStructType, "Struct keys must be strings." + end + self.fields[key] ||= Google::Protobuf::Value.new + self.fields[key].from_ruby(value) + end + + def to_h + ret = {} + self.fields.each { |key, val| ret[key] = val.to_ruby(true) } + ret + end + + def self.from_hash(hash) + ret = Struct.new + hash.each { |key, val| ret[key] = val } + ret + end + + def has_key?(key) + self.fields.has_key?(key) + end + end + + ListValue.class_eval do + include Enumerable + + def length + self.values.length + end + + def [](index) + self.values[index].to_ruby + end + + def []=(index, value) + self.values[index].from_ruby(value) + end + + def <<(value) + wrapper = Google::Protobuf::Value.new + wrapper.from_ruby(value) + self.values << wrapper + end + + def each + self.values.each { |x| yield(x.to_ruby) } + end + + def to_a + self.values.map { |x| x.to_ruby(true) } + end + + def self.from_a(arr) + ret = ListValue.new + arr.each { |val| ret << val } + ret + end + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/wrappers_pb.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/wrappers_pb.rb new file mode 100755 index 00000000..dda2a15a --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf/wrappers_pb.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/wrappers.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1egoogle/protobuf/wrappers.proto\x12\x0fgoogle.protobuf\"\x1c\n\x0b\x44oubleValue\x12\r\n\x05value\x18\x01 \x01(\x01\"\x1b\n\nFloatValue\x12\r\n\x05value\x18\x01 \x01(\x02\"\x1b\n\nInt64Value\x12\r\n\x05value\x18\x01 \x01(\x03\"\x1c\n\x0bUInt64Value\x12\r\n\x05value\x18\x01 \x01(\x04\"\x1b\n\nInt32Value\x12\r\n\x05value\x18\x01 \x01(\x05\"\x1c\n\x0bUInt32Value\x12\r\n\x05value\x18\x01 \x01(\r\"\x1a\n\tBoolValue\x12\r\n\x05value\x18\x01 \x01(\x08\"\x1c\n\x0bStringValue\x12\r\n\x05value\x18\x01 \x01(\t\"\x1b\n\nBytesValue\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x83\x01\n\x13\x63om.google.protobufB\rWrappersProtoP\x01Z1google.golang.org/protobuf/types/known/wrapperspb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + DoubleValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DoubleValue").msgclass + FloatValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FloatValue").msgclass + Int64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int64Value").msgclass + UInt64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt64Value").msgclass + Int32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int32Value").msgclass + UInt32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt32Value").msgclass + BoolValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BoolValue").msgclass + StringValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.StringValue").msgclass + BytesValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BytesValue").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_ffi.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_ffi.rb new file mode 100755 index 00000000..6580df49 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_ffi.rb @@ -0,0 +1,51 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'ffi-compiler/loader' +require 'google/protobuf/ffi/ffi' +require 'google/protobuf/ffi/internal/type_safety' +require 'google/protobuf/ffi/internal/pointer_helper' +require 'google/protobuf/ffi/internal/arena' +require 'google/protobuf/ffi/internal/convert' +require 'google/protobuf/ffi/descriptor' +require 'google/protobuf/ffi/enum_descriptor' +require 'google/protobuf/ffi/field_descriptor' +require 'google/protobuf/ffi/oneof_descriptor' +require 'google/protobuf/ffi/method_descriptor' +require 'google/protobuf/ffi/service_descriptor' +require 'google/protobuf/ffi/descriptor_pool' +require 'google/protobuf/ffi/file_descriptor' +require 'google/protobuf/ffi/map' +require 'google/protobuf/ffi/object_cache' +require 'google/protobuf/ffi/repeated_field' +require 'google/protobuf/ffi/message' + +module Google + module Protobuf + def self.deep_copy(object) + case object + when RepeatedField + RepeatedField.send(:deep_copy, object) + when Google::Protobuf::Map + Google::Protobuf::Map.deep_copy(object) + when Google::Protobuf::MessageExts + object.class.send(:deep_copy, object.instance_variable_get(:@msg)) + else + raise NotImplementedError + end + end + + def self.discard_unknown(message) + raise FrozenError if message.frozen? + raise ArgumentError.new "Expected message, got #{message.class} instead." if message.instance_variable_get(:@msg).nil? + unless Google::Protobuf::FFI.message_discard_unknown(message.instance_variable_get(:@msg), message.class.descriptor, 128) + raise RuntimeError.new "Messages nested too deeply." + end + nil + end + end +end diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_native.rb b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_native.rb new file mode 100755 index 00000000..9605b6b5 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/protobuf_native.rb @@ -0,0 +1,19 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +if RUBY_PLATFORM == "java" + require 'json' + require 'google/protobuf_java' +else + begin + require "google/#{RUBY_VERSION.sub(/\.\d+$/, '')}/protobuf_c" + rescue LoadError + require 'google/protobuf_c' + end +end + +require 'google/protobuf/repeated_field' diff --git a/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/tasks/ffi.rake b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/tasks/ffi.rake new file mode 100755 index 00000000..5de10a75 --- /dev/null +++ b/bin/gems/google-protobuf-4.29.3-x86_64-linux/lib/google/tasks/ffi.rake @@ -0,0 +1,100 @@ +# # @param task [FFI::Compiler::CompileTask] task to configure +def configure_common_compile_task(task) + if FileUtils.pwd.include? 'ext' + src_dir = '.' + third_party_path = 'third_party/utf8_range' + else + src_dir = 'ext/google/protobuf_c' + third_party_path = 'ext/google/protobuf_c/third_party/utf8_range' + end + + task.add_include_path third_party_path + task.add_define 'NDEBUG' + task.cflags << "-std=gnu99 -O3" + [ + :convert, :defs, :map, :message, :protobuf, :repeated_field, :wrap_memcpy + ].each { |file| task.exclude << "/#{file}.c" } + task.ext_dir = src_dir + task.source_dirs = [src_dir] + if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ + task.cflags << "-Wall -Wsign-compare -Wno-declaration-after-statement" + end +end + +# FFI::CompilerTask's constructor walks the filesystem at task definition time +# to create subtasks for each source file, so files from third_party must be +# copied into place before the task is defined for it to work correctly. +# TODO Is there a sane way to check for generated protos under lib too? +def with_generated_files + expected_path = FileUtils.pwd.include?('ext') ? 'third_party/utf8_range' : 'ext/google/protobuf_c/third_party/utf8_range' + if File.directory?(expected_path) + yield + else + task :default do + # It is possible, especially in cases like the first invocation of + # `rake test` following `rake clean` or a fresh checkout that the + # `copy_third_party` task has been executed since initial task definition. + # If so, run the task definition block now and invoke it explicitly. + if File.directory?(expected_path) + yield + Rake::Task[:default].invoke + else + raise "Missing directory #{File.absolute_path(expected_path)}." + + " Did you forget to run `rake copy_third_party` before building" + + " native extensions?" + end + end + end +end + +begin + require "ffi-compiler/compile_task" + + desc "Compile Protobuf library for FFI" + namespace "ffi-protobuf" do + with_generated_files do + # Compile Ruby UPB separately in order to limit use of -DUPB_BUILD_API to one + # compilation unit. + desc "Compile UPB library for FFI" + namespace "ffi-upb" do + with_generated_files do + FFI::Compiler::CompileTask.new('ruby-upb') do |c| + configure_common_compile_task c + c.add_define "UPB_BUILD_API" + c.exclude << "/glue.c" + c.exclude << "/shared_message.c" + c.exclude << "/shared_convert.c" + if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ + c.cflags << "-fvisibility=hidden" + end + end + end + end + + FFI::Compiler::CompileTask.new 'protobuf_c_ffi' do |c| + configure_common_compile_task c + # Ruby UPB was already compiled with different flags. + c.exclude << "/utf8_range.c" + c.exclude << "/ruby-upb.c" + end + + # Setup dependencies so that the .o files generated by building ffi-upb are + # available to link here. + # TODO Can this be simplified? Can the single shared library be used + # instead of the object files? + protobuf_c_task = Rake::Task[:default] + protobuf_c_shared_lib_task = Rake::Task[protobuf_c_task.prereqs.last] + ruby_upb_shared_lib_task = Rake::Task[:"ffi-upb:default"].prereqs.first + Rake::Task[ruby_upb_shared_lib_task].prereqs.each do |dependency| + protobuf_c_shared_lib_task.prereqs.prepend dependency + end + end + end +rescue LoadError + desc "Compile Protobuf library for FFI" + namespace "ffi-protobuf" do + task :default do + warn "Skipping build of FFI; `gem install ffi-compiler` to enable." + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/Rakefile b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/Rakefile new file mode 100755 index 00000000..0d4f84eb --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/Rakefile @@ -0,0 +1,3 @@ +import '../../../lib/google/tasks/ffi.rake' + +task default: ['ffi-protobuf:default'] \ No newline at end of file diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.c new file mode 100755 index 00000000..baabad32 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.c @@ -0,0 +1,335 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. +// +// This file Also contains a few other assorted algorithms on upb_MessageValue. +// +// None of the algorithms in this file require any access to the internal +// representation of Ruby or upb objects. +// ----------------------------------------------------------------------------- + +#include "convert.h" + +#include "message.h" +#include "protobuf.h" +#include "shared_convert.h" + +static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) { + upb_StringView ret; + if (arena) { + char* ptr = upb_Arena_Malloc(arena, RSTRING_LEN(str)); + memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str)); + ret.data = ptr; + } else { + // Data is only needed temporarily (within map lookup). + ret.data = RSTRING_PTR(str); + } + ret.size = RSTRING_LEN(str); + return ret; +} + +static bool is_ruby_num(VALUE value) { + return (TYPE(value) == T_FLOAT || TYPE(value) == T_FIXNUM || + TYPE(value) == T_BIGNUM); +} + +static void Convert_CheckInt(const char* name, upb_CType type, VALUE val) { + if (!is_ruby_num(val)) { + rb_raise(cTypeError, + "Expected number type for integral field '%s' (given %s).", name, + rb_class2name(CLASS_OF(val))); + } + + // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper + // bound; we just need to do precision checks (i.e., disallow rounding) and + // check for < 0 on unsigned types. + if (TYPE(val) == T_FLOAT) { + double dbl_val = NUM2DBL(val); + if (floor(dbl_val) != dbl_val) { + rb_raise(rb_eRangeError, + "Non-integral floating point value assigned to integer field " + "'%s' (given %s).", + name, rb_class2name(CLASS_OF(val))); + } + } + if (type == kUpb_CType_UInt32 || type == kUpb_CType_UInt64) { + if (NUM2DBL(val) < 0) { + rb_raise( + rb_eRangeError, + "Assigning negative value to unsigned integer field '%s' (given %s).", + name, rb_class2name(CLASS_OF(val))); + } + } +} + +static int32_t Convert_ToEnum(VALUE value, const char* name, + const upb_EnumDef* e) { + int32_t val; + + switch (TYPE(value)) { + case T_FLOAT: + case T_FIXNUM: + case T_BIGNUM: + Convert_CheckInt(name, kUpb_CType_Int32, value); + val = NUM2INT(value); + break; + case T_STRING: { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNameWithSize( + e, RSTRING_PTR(value), RSTRING_LEN(value)); + if (!ev) goto unknownval; + val = upb_EnumValueDef_Number(ev); + break; + } + case T_SYMBOL: { + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByName(e, rb_id2name(SYM2ID(value))); + if (!ev) goto unknownval; + val = upb_EnumValueDef_Number(ev); + break; + } + default: + rb_raise(cTypeError, + "Expected number or symbol type for enum field '%s'.", name); + } + + return val; + +unknownval: + rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name); +} + +VALUE Convert_CheckStringUtf8(VALUE str) { + VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding()); + + if (rb_obj_encoding(str) == utf8) { + // Note: Just because a string is marked as having UTF-8 encoding does + // not mean that it is *valid* UTF-8. We have to check separately + // whether it is valid. + if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) { + VALUE exc = + rb_const_get_at(rb_cEncoding, rb_intern("InvalidByteSequenceError")); + rb_raise(exc, "String is invalid UTF-8"); + } + } else { + // Note: this will not duplicate underlying string data unless + // necessary. + // + // This will throw an exception if the conversion cannot be performed: + // - Encoding::UndefinedConversionError if certain characters cannot be + // converted to UTF-8. + // - Encoding::InvalidByteSequenceError if certain characters were invalid + // in the source encoding. + str = rb_str_encode(str, utf8, 0, Qnil); + PBRUBY_ASSERT(rb_enc_str_coderange(str) != ENC_CODERANGE_BROKEN); + } + + return str; +} + +upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name, + TypeInfo type_info, upb_Arena* arena) { + upb_MessageValue ret; + + switch (type_info.type) { + case kUpb_CType_Float: + if (!is_ruby_num(value)) { + rb_raise(cTypeError, + "Expected number type for float field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + ret.float_val = NUM2DBL(value); + break; + case kUpb_CType_Double: + if (!is_ruby_num(value)) { + rb_raise(cTypeError, + "Expected number type for double field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + ret.double_val = NUM2DBL(value); + break; + case kUpb_CType_Bool: { + if (value == Qtrue) { + ret.bool_val = 1; + } else if (value == Qfalse) { + ret.bool_val = 0; + } else { + rb_raise(cTypeError, + "Invalid argument for boolean field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + break; + } + case kUpb_CType_String: + if (rb_obj_class(value) == rb_cSymbol) { + value = rb_funcall(value, rb_intern("to_s"), 0); + } else if (!rb_obj_is_kind_of(value, rb_cString)) { + rb_raise(cTypeError, + "Invalid argument for string field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + + value = Convert_CheckStringUtf8(value); + ret.str_val = Convert_StringData(value, arena); + break; + case kUpb_CType_Bytes: { + VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding()); + if (rb_obj_class(value) != rb_cString) { + rb_raise(cTypeError, + "Invalid argument for bytes field '%s' (given %s).", name, + rb_class2name(CLASS_OF(value))); + } + + if (rb_obj_encoding(value) != bytes) { + // Note: this will not duplicate underlying string data unless + // necessary. + // TODO: is this really necessary to get raw bytes? + value = rb_str_encode(value, bytes, 0, Qnil); + } + + ret.str_val = Convert_StringData(value, arena); + break; + } + case kUpb_CType_Message: + ret.msg_val = + Message_GetUpbMessage(value, type_info.def.msgdef, name, arena); + break; + case kUpb_CType_Enum: + ret.int32_val = Convert_ToEnum(value, name, type_info.def.enumdef); + break; + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + Convert_CheckInt(name, type_info.type, value); + switch (type_info.type) { + case kUpb_CType_Int32: + ret.int32_val = NUM2INT(value); + break; + case kUpb_CType_Int64: + ret.int64_val = NUM2LL(value); + break; + case kUpb_CType_UInt32: + ret.uint32_val = NUM2UINT(value); + break; + case kUpb_CType_UInt64: + ret.uint64_val = NUM2ULL(value); + break; + default: + rb_raise(cTypeError, "Convert_RubyToUpb(): Unexpected type %d", + (int)type_info.type); + } + break; + default: + rb_raise(cTypeError, "Convert_RubyToUpb(): Unexpected type %d", + (int)type_info.type); + } + + return ret; +} + +VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info, + VALUE arena) { + switch (type_info.type) { + case kUpb_CType_Float: + return DBL2NUM(upb_val.float_val); + case kUpb_CType_Double: + return DBL2NUM(upb_val.double_val); + case kUpb_CType_Bool: + return upb_val.bool_val ? Qtrue : Qfalse; + case kUpb_CType_Int32: + return INT2NUM(upb_val.int32_val); + case kUpb_CType_Int64: + return LL2NUM(upb_val.int64_val); + case kUpb_CType_UInt32: + return UINT2NUM(upb_val.uint32_val); + case kUpb_CType_UInt64: + return ULL2NUM(upb_val.int64_val); + case kUpb_CType_Enum: { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber( + type_info.def.enumdef, upb_val.int32_val); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return INT2NUM(upb_val.int32_val); + } + } + case kUpb_CType_String: { + VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size); + rb_enc_associate(str_rb, rb_utf8_encoding()); + rb_obj_freeze(str_rb); + return str_rb; + } + case kUpb_CType_Bytes: { + VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size); + rb_enc_associate(str_rb, rb_ascii8bit_encoding()); + rb_obj_freeze(str_rb); + return str_rb; + } + case kUpb_CType_Message: + return Message_GetRubyWrapper((upb_Message*)upb_val.msg_val, + type_info.def.msgdef, arena); + default: + rb_raise(rb_eRuntimeError, "Convert_UpbToRuby(): Unexpected type %d", + (int)type_info.type); + } +} + +upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info, + upb_Arena* arena) { + upb_MessageValue new_msgval; + + switch (type_info.type) { + default: + memcpy(&new_msgval, &msgval, sizeof(msgval)); + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + size_t n = msgval.str_val.size; + char* mem = upb_Arena_Malloc(arena, n); + new_msgval.str_val.data = mem; + new_msgval.str_val.size = n; + memcpy(mem, msgval.str_val.data, n); + break; + } + case kUpb_CType_Message: + new_msgval.msg_val = + Message_deep_copy(msgval.msg_val, type_info.def.msgdef, arena); + break; + } + + return new_msgval; +} + +bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + TypeInfo type_info) { + upb_Status status; + upb_Status_Clear(&status); + bool return_value = shared_Msgval_IsEqual(val1, val2, type_info.type, + type_info.def.msgdef, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(rb_eRuntimeError, "Msgval_IsEqual(): %s", + upb_Status_ErrorMessage(&status)); + } +} + +uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info, + uint64_t seed) { + upb_Status status; + upb_Status_Clear(&status); + uint64_t return_value = shared_Msgval_GetHash( + val, type_info.type, type_info.def.msgdef, seed, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(rb_eRuntimeError, "Msgval_GetHash(): %s", + upb_Status_ErrorMessage(&status)); + } +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.h new file mode 100755 index 00000000..d2c4e218 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/convert.h @@ -0,0 +1,50 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_CONVERT_H_ +#define RUBY_PROTOBUF_CONVERT_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Converts |ruby_val| to a upb_MessageValue according to |type_info|. +// +// The |arena| parameter indicates the lifetime of the container where this +// value will be assigned. It is used as follows: +// - If type is string or bytes, the string data will be copied into |arena|. +// - If type is message, and we need to auto-construct a message due to implicit +// conversions (eg. Time -> Google::Protobuf::Timestamp), the new message +// will be created in |arena|. +// - If type is message and the Ruby value is a message instance, we will fuse +// the message's arena into |arena|, to ensure that this message outlives the +// container. +upb_MessageValue Convert_RubyToUpb(VALUE ruby_val, const char* name, + TypeInfo type_info, upb_Arena* arena); + +// Converts |upb_val| to a Ruby VALUE according to |type_info|. This may involve +// creating a Ruby wrapper object. +// +// The |arena| parameter indicates the arena that owns the lifetime of +// |upb_val|. Any Ruby wrapper object that is created will reference |arena| +// and ensure it outlives the wrapper. +VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info, + VALUE arena); + +// Creates a deep copy of |msgval| in |arena|. +upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info, + upb_Arena* arena); + +// Returns true if |val1| and |val2| are equal. Their type is given by +// |type_info|. +bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + TypeInfo type_info); + +// Returns a hash value for the given upb_MessageValue. +uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info, + uint64_t seed); + +#endif // RUBY_PROTOBUF_CONVERT_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.c new file mode 100755 index 00000000..5bc405f3 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.c @@ -0,0 +1,2084 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include +#include + +#include "convert.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor +// instances. +// ----------------------------------------------------------------------------- + +static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def); +static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def); +static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def); +static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def); +static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def); +static VALUE get_servicedef_obj(VALUE descriptor_pool, + const upb_ServiceDef* def); +static VALUE get_methoddef_obj(VALUE descriptor_pool, const upb_MethodDef* def); + +// A distinct object that is not accessible from Ruby. We use this as a +// constructor argument to enforce that certain objects cannot be created from +// Ruby. +VALUE c_only_cookie = Qnil; + +// ----------------------------------------------------------------------------- +// Common utilities. +// ----------------------------------------------------------------------------- + +static const char* get_str(VALUE str) { + Check_Type(str, T_STRING); + return RSTRING_PTR(str); +} + +static VALUE rb_str_maybe_null(const char* s) { + if (s == NULL) { + s = ""; + } + return rb_str_new2(s); +} +static ID options_instancevar_interned; +// ----------------------------------------------------------------------------- +// DescriptorPool. +// ----------------------------------------------------------------------------- + +typedef struct { + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE def_to_descriptor; // Hash table of def* -> Ruby descriptor. + upb_DefPool* symtab; +} DescriptorPool; + +VALUE cDescriptorPool = Qnil; + +// Global singleton DescriptorPool. The user is free to create others, but this +// is used by generated code. +VALUE generated_pool = Qnil; + +static void DescriptorPool_mark(void* _self) { + DescriptorPool* self = _self; + rb_gc_mark(self->def_to_descriptor); +} + +static void DescriptorPool_free(void* _self) { + DescriptorPool* self = _self; + upb_DefPool_Free(self->symtab); + xfree(self); +} + +static const rb_data_type_t DescriptorPool_type = { + "Google::Protobuf::DescriptorPool", + {DescriptorPool_mark, DescriptorPool_free, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static DescriptorPool* ruby_to_DescriptorPool(VALUE val) { + DescriptorPool* ret; + TypedData_Get_Struct(val, DescriptorPool, &DescriptorPool_type, ret); + return ret; +} + +// Exposed to other modules in defs.h. +const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb) { + DescriptorPool* pool = ruby_to_DescriptorPool(desc_pool_rb); + return pool->symtab; +} + +/** + * ruby-doc: DescriptorPool + * + * A DescriptorPool is the registry of all known Protobuf descriptor objects. + * + */ + +/* + * ruby-doc: DescriptorPool.new + * + * Creates a new, empty, descriptor pool. + */ +static VALUE DescriptorPool_alloc(VALUE klass) { + DescriptorPool* self = ALLOC(DescriptorPool); + VALUE ret; + + self->def_to_descriptor = Qnil; + ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self); + + RB_OBJ_WRITE(ret, &self->def_to_descriptor, rb_hash_new()); + self->symtab = upb_DefPool_New(); + + // Ruby treats all enums as open. + upb_DefPool_DisableClosedEnumChecking(self->symtab); + + return ObjectCache_TryAdd(self->symtab, ret); +} + +/* + * ruby-doc: DescriptorPool#add_serialized_file + * + * Adds the given serialized + * {https://protobuf.com/docs/descriptors#file-descriptors FileDescriptorProto} + * to the pool. + * + * @param serialized_file_proto [String] + * @return [FileDescriptor] + */ +VALUE DescriptorPool_add_serialized_file(VALUE _self, + VALUE serialized_file_proto) { + DescriptorPool* self = ruby_to_DescriptorPool(_self); + Check_Type(serialized_file_proto, T_STRING); + VALUE arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(arena_rb); + google_protobuf_FileDescriptorProto* file_proto = + google_protobuf_FileDescriptorProto_parse( + RSTRING_PTR(serialized_file_proto), + RSTRING_LEN(serialized_file_proto), arena); + if (!file_proto) { + rb_raise(rb_eArgError, "Unable to parse FileDescriptorProto"); + } + upb_Status status; + upb_Status_Clear(&status); + const upb_FileDef* filedef = + upb_DefPool_AddFile(self->symtab, file_proto, &status); + if (!filedef) { + rb_raise(cTypeError, "Unable to build file to DescriptorPool: %s", + upb_Status_ErrorMessage(&status)); + } + RB_GC_GUARD(arena_rb); + return get_filedef_obj(_self, filedef); +} + +/* + * ruby-doc: DescriptorPool#lookup + * + * Finds a {Descriptor}, {EnumDescriptor}, + * {FieldDescriptor} or {ServiceDescriptor} by + * name and returns it, or nil if none exists with the given name. + * + * @param name [String] + * @return [Descriptor,EnumDescriptor,FieldDescriptor,ServiceDescriptor] + */ +static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) { + DescriptorPool* self = ruby_to_DescriptorPool(_self); + const char* name_str = get_str(name); + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const upb_FieldDef* fielddef; + const upb_ServiceDef* servicedef; + const upb_FileDef* filedef; + + msgdef = upb_DefPool_FindMessageByName(self->symtab, name_str); + if (msgdef) { + return get_msgdef_obj(_self, msgdef); + } + + fielddef = upb_DefPool_FindExtensionByName(self->symtab, name_str); + if (fielddef) { + return get_fielddef_obj(_self, fielddef); + } + + enumdef = upb_DefPool_FindEnumByName(self->symtab, name_str); + if (enumdef) { + return get_enumdef_obj(_self, enumdef); + } + + servicedef = upb_DefPool_FindServiceByName(self->symtab, name_str); + if (servicedef) { + return get_servicedef_obj(_self, servicedef); + } + + filedef = upb_DefPool_FindFileByName(self->symtab, name_str); + if (filedef) { + return get_filedef_obj(_self, filedef); + } + + return Qnil; +} + +/* + * ruby-doc: DescriptorPool.generated_pool + * + * Class method that returns the global {DescriptorPool}. This is a singleton + * into which generated-code message and enum types are registered. The user may + * also register types in this pool for convenience so that they do not have to + * hold a reference to a private pool instance. + * + * @return [DescriptorPool] + */ +static VALUE DescriptorPool_generated_pool(VALUE _self) { + return generated_pool; +} + +static void DescriptorPool_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "DescriptorPool", rb_cObject); + rb_define_alloc_func(klass, DescriptorPool_alloc); + rb_define_method(klass, "add_serialized_file", + DescriptorPool_add_serialized_file, 1); + rb_define_method(klass, "lookup", DescriptorPool_lookup, 1); + rb_define_singleton_method(klass, "generated_pool", + DescriptorPool_generated_pool, 0); + rb_gc_register_address(&cDescriptorPool); + cDescriptorPool = klass; + + rb_gc_register_address(&generated_pool); + generated_pool = rb_class_new_instance(0, NULL, klass); + options_instancevar_interned = rb_intern("options"); +} + +// ----------------------------------------------------------------------------- +// Descriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_MessageDef* msgdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE klass; + VALUE descriptor_pool; +} Descriptor; + +VALUE cDescriptor = Qnil; + +static void Descriptor_mark(void* _self) { + Descriptor* self = _self; + rb_gc_mark(self->klass); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t Descriptor_type = { + "Google::Protobuf::Descriptor", + {Descriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static Descriptor* ruby_to_Descriptor(VALUE val) { + Descriptor* ret; + TypedData_Get_Struct(val, Descriptor, &Descriptor_type, ret); + return ret; +} + +// Decode and return a frozen instance of a Descriptor Option for the given pool +static VALUE decode_options(VALUE self, const char* option_type, int size, + const char* bytes, VALUE descriptor_pool) { + VALUE options_rb = rb_ivar_get(self, options_instancevar_interned); + if (options_rb != Qnil) { + return options_rb; + } + + static const char* prefix = "google.protobuf."; + char fullname + [/*strlen(prefix)*/ 16 + + /*strln(longest option type supported e.g. "MessageOptions")*/ 14 + + /*null terminator*/ 1]; + + snprintf(fullname, sizeof(fullname), "%s%s", prefix, option_type); + const upb_MessageDef* msgdef = upb_DefPool_FindMessageByName( + ruby_to_DescriptorPool(descriptor_pool)->symtab, fullname); + if (!msgdef) { + rb_raise(rb_eRuntimeError, "Cannot find %s in DescriptorPool", option_type); + } + + VALUE desc_rb = get_msgdef_obj(descriptor_pool, msgdef); + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + + options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, false); + + // Strip features from the options proto to keep it internal. + const upb_MessageDef* decoded_desc = NULL; + upb_Message* options = Message_GetMutable(options_rb, &decoded_desc); + PBRUBY_ASSERT(options != NULL); + PBRUBY_ASSERT(decoded_desc == msgdef); + const upb_FieldDef* field = + upb_MessageDef_FindFieldByName(decoded_desc, "features"); + PBRUBY_ASSERT(field != NULL); + upb_Message_ClearFieldByDef(options, field); + + Message_freeze(options_rb); + + rb_ivar_set(self, options_instancevar_interned, options_rb); + return options_rb; +} + +/* + * ruby-doc: Descriptor + * + * A Descriptor provides information about a given Protobuf definition. + */ + +/* + * ruby-doc: Descriptor.initialize + * + * Creates a new, empty, message type descriptor. At a minimum, its name must be + * set before it is added to a pool. It cannot be used to create messages until + * it is added to a pool, after which it becomes immutable (as part of a + * finalization process). + */ +static VALUE Descriptor_alloc(VALUE klass) { + Descriptor* self = ALLOC(Descriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &Descriptor_type, self); + self->msgdef = NULL; + self->klass = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * Descriptor.new(c_only_cookie, ptr) => Descriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE Descriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + Descriptor* self = ruby_to_Descriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->msgdef = (const upb_MessageDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: Descriptor#file_descriptor + * + * Returns the {FileDescriptor} object this message belongs to. + * + * @return [FileDescriptor] + */ +static VALUE Descriptor_file_descriptor(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_MessageDef_File(self->msgdef)); +} + +/* + * ruby-doc: Descriptor#name + * + * Returns the name of this message type as a fully-qualified string (e.g., + * My.Package.MessageType). + * + * @return [String] + */ +static VALUE Descriptor_name(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + return rb_str_maybe_null(upb_MessageDef_FullName(self->msgdef)); +} + +/* + * ruby-doc: Descriptor#each + * + * Iterates over fields in this message type, yielding to the block on each one. + * + * @yield [FieldDescriptor] + * @return [nil] + */ +static VALUE Descriptor_each(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + + int n = upb_MessageDef_FieldCount(self->msgdef); + for (int i = 0; i < n; i++) { + const upb_FieldDef* field = upb_MessageDef_Field(self->msgdef, i); + VALUE obj = get_fielddef_obj(self->descriptor_pool, field); + rb_yield(obj); + } + return Qnil; +} + +/* + * ruby-doc: Descriptor#lookup + * + * Returns the field descriptor for the field with the given name, if present, + * or nil if none. + * + * @param name [String] + * @return [FieldDescriptor] + */ +static VALUE Descriptor_lookup(VALUE _self, VALUE name) { + Descriptor* self = ruby_to_Descriptor(_self); + const char* s = get_str(name); + const upb_FieldDef* field = upb_MessageDef_FindFieldByName(self->msgdef, s); + if (field == NULL) { + return Qnil; + } + return get_fielddef_obj(self->descriptor_pool, field); +} + +/* + * ruby-doc: Descriptor#each_oneof + * + * Invokes the given block for each oneof in this message type, passing the + * corresponding {OneofDescriptor}. + * + * @yield [OneofDescriptor] + * @return [nil] + */ +static VALUE Descriptor_each_oneof(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + + int n = upb_MessageDef_OneofCount(self->msgdef); + for (int i = 0; i < n; i++) { + const upb_OneofDef* oneof = upb_MessageDef_Oneof(self->msgdef, i); + VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof); + rb_yield(obj); + } + return Qnil; +} + +/* + * ruby-doc: Descriptor#lookup_oneof + * + * Returns the oneof descriptor for the oneof with the given name, if present, + * or nil if none. + * + * @param name [String] + * @return [OneofDescriptor] + */ +static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) { + Descriptor* self = ruby_to_Descriptor(_self); + const char* s = get_str(name); + const upb_OneofDef* oneof = upb_MessageDef_FindOneofByName(self->msgdef, s); + if (oneof == NULL) { + return Qnil; + } + return get_oneofdef_obj(self->descriptor_pool, oneof); +} + +/* + * ruby-doc: Descriptor#msgclass + * + * Returns the Ruby class created for this message type. + * + * @return [Class] + */ +static VALUE Descriptor_msgclass(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + if (self->klass == Qnil) { + RB_OBJ_WRITE(_self, &self->klass, build_class_from_descriptor(_self)); + } + return self->klass; +} + +/* + * ruby-doc: Descriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L571 + * MessageOptions} for this {Descriptor}. + * + * @return [MessageOptions] + */ +static VALUE Descriptor_options(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + const google_protobuf_MessageOptions* opts = + upb_MessageDef_Options(self->msgdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_MessageOptions_serialize(opts, arena, &size); + VALUE message_options = decode_options(_self, "MessageOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return message_options; +} + +/* + * ruby-doc: Descriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L147 + * DescriptorProto} of this {Descriptor}. + * + * @return [DescriptorProto] + */ +static VALUE Descriptor_to_proto(VALUE _self) { + Descriptor* self = ruby_to_Descriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_DescriptorProto* proto = + upb_MessageDef_ToProto(self->msgdef, arena); + size_t size; + const char* serialized = + google_protobuf_DescriptorProto_serialize(proto, arena, &size); + VALUE proto_class = rb_path2class("Google::Protobuf::DescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void Descriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "Descriptor", rb_cObject); + rb_define_alloc_func(klass, Descriptor_alloc); + rb_define_method(klass, "initialize", Descriptor_initialize, 3); + rb_define_method(klass, "each", Descriptor_each, 0); + rb_define_method(klass, "lookup", Descriptor_lookup, 1); + rb_define_method(klass, "each_oneof", Descriptor_each_oneof, 0); + rb_define_method(klass, "lookup_oneof", Descriptor_lookup_oneof, 1); + rb_define_method(klass, "msgclass", Descriptor_msgclass, 0); + rb_define_method(klass, "name", Descriptor_name, 0); + rb_define_method(klass, "file_descriptor", Descriptor_file_descriptor, 0); + rb_define_method(klass, "options", Descriptor_options, 0); + rb_define_method(klass, "to_proto", Descriptor_to_proto, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cDescriptor); + cDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// FileDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_FileDef* filedef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_FileDef. +} FileDescriptor; + +static VALUE cFileDescriptor = Qnil; + +static void FileDescriptor_mark(void* _self) { + FileDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t FileDescriptor_type = { + "Google::Protobuf::FileDescriptor", + {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static FileDescriptor* ruby_to_FileDescriptor(VALUE val) { + FileDescriptor* ret; + TypedData_Get_Struct(val, FileDescriptor, &FileDescriptor_type, ret); + return ret; +} + +static VALUE FileDescriptor_alloc(VALUE klass) { + FileDescriptor* self = ALLOC(FileDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &FileDescriptor_type, self); + self->descriptor_pool = Qnil; + self->filedef = NULL; + return ret; +} + +/** + * ruby-doc: FileDescriptor + * + * A FileDescriptor provides information about all Protobuf definitions in a + * particular file. + */ + +/* + * ruby-doc: FileDescriptor#initialize + * + * Returns a new file descriptor. May + * to a builder. + */ +static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->filedef = (const upb_FileDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: FileDescriptor#name + * + * Returns the name of the file. + * + * @return [String] + */ +static VALUE FileDescriptor_name(VALUE _self) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + const char* name = upb_FileDef_Name(self->filedef); + return name == NULL ? Qnil : rb_str_new2(name); +} + +/* + * ruby-doc: FileDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L442 + * FileOptions} for this {FileDescriptor}. + * + * @return [FileOptions] + */ +static VALUE FileDescriptor_options(VALUE _self) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + const google_protobuf_FileOptions* opts = upb_FileDef_Options(self->filedef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_FileOptions_serialize(opts, arena, &size); + VALUE file_options = decode_options(_self, "FileOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return file_options; +} + +/* + * ruby-doc: FileDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L104 + * FileDescriptorProto} of this {FileDescriptor}. + * + * @return [FileDescriptorProto] + */ +static VALUE FileDescriptor_to_proto(VALUE _self) { + FileDescriptor* self = ruby_to_FileDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_FileDescriptorProto* file_proto = + upb_FileDef_ToProto(self->filedef, arena); + + size_t size; + const char* serialized = + google_protobuf_FileDescriptorProto_serialize(file_proto, arena, &size); + + VALUE file_proto_class = + rb_path2class("Google::Protobuf::FileDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, file_proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void FileDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "FileDescriptor", rb_cObject); + rb_define_alloc_func(klass, FileDescriptor_alloc); + rb_define_method(klass, "initialize", FileDescriptor_initialize, 3); + rb_define_method(klass, "name", FileDescriptor_name, 0); + rb_define_method(klass, "options", FileDescriptor_options, 0); + rb_define_method(klass, "to_proto", FileDescriptor_to_proto, 0); + rb_gc_register_address(&cFileDescriptor); + cFileDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// FieldDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_FieldDef* fielddef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_FieldDef. +} FieldDescriptor; + +static VALUE cFieldDescriptor = Qnil; + +static void FieldDescriptor_mark(void* _self) { + FieldDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t FieldDescriptor_type = { + "Google::Protobuf::FieldDescriptor", + {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) { + FieldDescriptor* ret; + TypedData_Get_Struct(val, FieldDescriptor, &FieldDescriptor_type, ret); + return ret; +} + +/** + * ruby-doc: FieldDescriptor + * + * A FieldDescriptor provides information about the Protobuf definition of a + * field inside a {Descriptor}. + */ + +/* + * ruby-doc: FieldDescriptor#initialize + * + * Returns a new field descriptor. Its name, type, etc. must be set before it is + * added to a message type. + */ +static VALUE FieldDescriptor_alloc(VALUE klass) { + FieldDescriptor* self = ALLOC(FieldDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &FieldDescriptor_type, self); + self->fielddef = NULL; + return ret; +} + +/* + * call-seq: + * FieldDescriptor.new(c_only_cookie, pool, ptr) => FieldDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE FieldDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->fielddef = (const upb_FieldDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: FieldDescriptor#name + * + * Returns the name of this field. + * + * @return [String] + */ +static VALUE FieldDescriptor_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return rb_str_maybe_null(upb_FieldDef_Name(self->fielddef)); +} + +// Non-static, exposed to other .c files. +upb_CType ruby_to_fieldtype(VALUE type) { + if (TYPE(type) != T_SYMBOL) { + rb_raise(rb_eArgError, "Expected symbol for field type."); + } + +#define CONVERT(upb, ruby) \ + if (SYM2ID(type) == rb_intern(#ruby)) { \ + return kUpb_CType_##upb; \ + } + + CONVERT(Float, float); + CONVERT(Double, double); + CONVERT(Bool, bool); + CONVERT(String, string); + CONVERT(Bytes, bytes); + CONVERT(Message, message); + CONVERT(Enum, enum); + CONVERT(Int32, int32); + CONVERT(Int64, int64); + CONVERT(UInt32, uint32); + CONVERT(UInt64, uint64); + +#undef CONVERT + + rb_raise(rb_eArgError, "Unknown field type."); + return 0; +} + +static VALUE descriptortype_to_ruby(upb_FieldType type) { + switch (type) { +#define CONVERT(upb, ruby) \ + case kUpb_FieldType_##upb: \ + return ID2SYM(rb_intern(#ruby)); + CONVERT(Float, float); + CONVERT(Double, double); + CONVERT(Bool, bool); + CONVERT(String, string); + CONVERT(Bytes, bytes); + CONVERT(Message, message); + CONVERT(Group, group); + CONVERT(Enum, enum); + CONVERT(Int32, int32); + CONVERT(Int64, int64); + CONVERT(UInt32, uint32); + CONVERT(UInt64, uint64); + CONVERT(SInt32, sint32); + CONVERT(SInt64, sint64); + CONVERT(Fixed32, fixed32); + CONVERT(Fixed64, fixed64); + CONVERT(SFixed32, sfixed32); + CONVERT(SFixed64, sfixed64); +#undef CONVERT + } + return Qnil; +} + +/* + * ruby-doc: FieldDescriptor#type + * + * Returns this field's type, as a Ruby symbol, or nil if not yet set. + * + * Valid field types are: + * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, + * :bytes, :message. + * + * @return [Symbol] + */ +static VALUE FieldDescriptor__type(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return descriptortype_to_ruby(upb_FieldDef_Type(self->fielddef)); +} + +/* + * ruby-doc: FieldDescriptor#default + * + * Returns this field's default, as a Ruby object, or nil if not yet set. + * + * @return [Object,nil] + */ +static VALUE FieldDescriptor_default(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_FieldDef* f = self->fielddef; + upb_MessageValue default_val = upb_MessageValue_Zero(); + if (upb_FieldDef_IsSubMessage(f)) { + return Qnil; + } else if (!upb_FieldDef_IsRepeated(f)) { + default_val = upb_FieldDef_Default(f); + } + return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil); +} + +/* + * ruby-doc: FieldDescriptor.has_presence? + * + * Returns whether this field tracks presence. + * + * @return [Boolean] + */ +static VALUE FieldDescriptor_has_presence(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_HasPresence(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: FieldDescriptor#required? + * + * Returns whether this is a required field. + * + * @return [Boolean] + */ +static VALUE FieldDescriptor_is_required(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_IsRequired(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: FieldDescriptor#repeated? + * + * Returns whether this is a repeated field. + * @return [Boolean] + */ +static VALUE FieldDescriptor_is_repeated(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_IsRepeated(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: FieldDescriptor#is_packed? + * + * Returns whether this is a repeated field that uses packed encoding. + * @return [Boolean] + */ +static VALUE FieldDescriptor_is_packed(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return upb_FieldDef_IsPacked(self->fielddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: FieldDescriptor#json_name + * + * Returns this field's json_name, as a Ruby string, or nil if not yet set. + * + * @return [String,nil] + */ +static VALUE FieldDescriptor_json_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_FieldDef* f = self->fielddef; + const char* json_name = upb_FieldDef_JsonName(f); + return rb_str_new2(json_name); +} + +/* + * ruby-doc: FieldDescriptor#label + * + * Returns this field's label (i.e., plurality), as a Ruby symbol. + * Valid field labels are: + * :optional, :repeated + * + * @return [Symbol] + * @deprecated Use {#repeated?} or {#required?} instead. + */ +static VALUE FieldDescriptor_label(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_Label(self->fielddef)) { +#define CONVERT(upb, ruby) \ + case kUpb_Label_##upb: \ + return ID2SYM(rb_intern(#ruby)); + + CONVERT(Optional, optional); + CONVERT(Required, required); + CONVERT(Repeated, repeated); + +#undef CONVERT + } + + return Qnil; +} + +/* + * ruby-doc: FieldDescriptor#number + * + * Returns the tag number for this field. + * + * @return [Integer] + */ +static VALUE FieldDescriptor_number(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + return INT2NUM(upb_FieldDef_Number(self->fielddef)); +} + +/* + * ruby-doc: FieldDescriptor#submsg_name + * + * Returns the name of the message or enum type corresponding to this field, if + * it is a message or enum field (respectively), or nil otherwise. This type + * name will be resolved within the context of the pool to which the containing + * message type is added. + * + * @return [String,nil] + */ +static VALUE FieldDescriptor_submsg_name(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_CType(self->fielddef)) { + case kUpb_CType_Enum: + return rb_str_new2( + upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(self->fielddef))); + case kUpb_CType_Message: + return rb_str_new2( + upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(self->fielddef))); + default: + return Qnil; + } +} + +/* + * ruby-doc: FieldDescriptor#subtype + * + * Returns the message or enum descriptor corresponding to this field's type if + * it is a message or enum field, respectively, or nil otherwise. Cannot be + * called *until* the containing message type is added to a pool (and thus + * resolved). + * + * @return [Descriptor,EnumDescriptor,nil] + */ +static VALUE FieldDescriptor_subtype(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + switch (upb_FieldDef_CType(self->fielddef)) { + case kUpb_CType_Enum: + return get_enumdef_obj(self->descriptor_pool, + upb_FieldDef_EnumSubDef(self->fielddef)); + case kUpb_CType_Message: + return get_msgdef_obj(self->descriptor_pool, + upb_FieldDef_MessageSubDef(self->fielddef)); + default: + return Qnil; + } +} + +/* + * ruby-doc: FieldDescriptor#get + * + * Returns the value set for this field on the given message. Raises an + * exception if message is of the wrong type. + * + * @param message [AbstractMessage] + * @return [Object] + */ +static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + + Message_Get(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "get method called on wrong message type"); + } + + return Message_getfield(msg_rb, self->fielddef); +} + +/* + * ruby-doc: FieldDescriptor.has? + * + * Returns whether the value is set on the given message. Raises an + * exception when calling for fields that do not have presence. + * + * @param message [AbstractMessage] + * @return [Boolean] + */ +static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + const upb_Message* msg = Message_Get(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "has method called on wrong message type"); + } else if (!upb_FieldDef_HasPresence(self->fielddef)) { + rb_raise(rb_eArgError, "does not track presence"); + } + + return upb_Message_HasFieldByDef(msg, self->fielddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: FieldDescriptor#clear + * + * Clears the field from the message if it's set. + * + * @param message [AbstractMessage] + * @return [nil] + */ +static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + upb_Message* msg = Message_GetMutable(msg_rb, &m); + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "has method called on wrong message type"); + } + + upb_Message_ClearFieldByDef(msg, self->fielddef); + return Qnil; +} + +/* + * ruby-doc: FieldDescriptor#set + * + * Sets the value corresponding to this field to the given value on the given + * message. Raises an exception if message is of the wrong type. Performs the + * ordinary type-checks for field setting. + * + * @param message [AbstractMessage] + * @param value [Object] + */ +static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const upb_MessageDef* m; + upb_Message* msg = Message_GetMutable(msg_rb, &m); + upb_Arena* arena = Arena_get(Message_GetArena(msg_rb)); + upb_MessageValue msgval; + + if (m != upb_FieldDef_ContainingType(self->fielddef)) { + rb_raise(cTypeError, "set method called on wrong message type"); + } + + msgval = Convert_RubyToUpb(value, upb_FieldDef_Name(self->fielddef), + TypeInfo_get(self->fielddef), arena); + upb_Message_SetFieldByDef(msg, self->fielddef, msgval, arena); + return Qnil; +} + +/* + * ruby-doc: FieldDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L656 + * FieldOptions} for this {FieldDescriptor}. + * + * @return [FieldOptions] + */ +static VALUE FieldDescriptor_options(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + const google_protobuf_FieldOptions* opts = + upb_FieldDef_Options(self->fielddef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, &size); + VALUE field_options = decode_options(_self, "FieldOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return field_options; +} + +/* + * ruby-doc: FieldDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L236 + * FieldDescriptorProto} of this {FieldDescriptor}. + * + * @return [FieldDescriptorProto] + */ +static VALUE FieldDescriptor_to_proto(VALUE _self) { + FieldDescriptor* self = ruby_to_FieldDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_FieldDescriptorProto* proto = + upb_FieldDef_ToProto(self->fielddef, arena); + size_t size; + const char* serialized = + google_protobuf_FieldDescriptorProto_serialize(proto, arena, &size); + VALUE proto_class = rb_path2class("Google::Protobuf::FieldDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void FieldDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "FieldDescriptor", rb_cObject); + rb_define_alloc_func(klass, FieldDescriptor_alloc); + rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3); + rb_define_method(klass, "name", FieldDescriptor_name, 0); + rb_define_method(klass, "type", FieldDescriptor__type, 0); + rb_define_method(klass, "default", FieldDescriptor_default, 0); + rb_define_method(klass, "has_presence?", FieldDescriptor_has_presence, 0); + rb_define_method(klass, "required?", FieldDescriptor_is_required, 0); + rb_define_method(klass, "repeated?", FieldDescriptor_is_repeated, 0); + rb_define_method(klass, "is_packed?", FieldDescriptor_is_packed, 0); + rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0); + rb_define_method(klass, "label", FieldDescriptor_label, 0); + rb_define_method(klass, "number", FieldDescriptor_number, 0); + rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0); + rb_define_method(klass, "subtype", FieldDescriptor_subtype, 0); + rb_define_method(klass, "has?", FieldDescriptor_has, 1); + rb_define_method(klass, "clear", FieldDescriptor_clear, 1); + rb_define_method(klass, "get", FieldDescriptor_get, 1); + rb_define_method(klass, "set", FieldDescriptor_set, 2); + rb_define_method(klass, "options", FieldDescriptor_options, 0); + rb_define_method(klass, "to_proto", FieldDescriptor_to_proto, 0); + rb_gc_register_address(&cFieldDescriptor); + cFieldDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// OneofDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_OneofDef* oneofdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE descriptor_pool; // Owns the upb_OneofDef. +} OneofDescriptor; + +static VALUE cOneofDescriptor = Qnil; + +static void OneofDescriptor_mark(void* _self) { + OneofDescriptor* self = _self; + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t OneofDescriptor_type = { + "Google::Protobuf::OneofDescriptor", + {OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) { + OneofDescriptor* ret; + TypedData_Get_Struct(val, OneofDescriptor, &OneofDescriptor_type, ret); + return ret; +} + +/** + * ruby-doc: OneofDescriptor + * + * A OneofDescriptor provides information about the Protobuf definition of a + * oneof inside a {Descriptor}. + */ + +/* + * ruby-doc: OneofDescriptor#initialize + * + * Creates a new, empty, oneof descriptor. The oneof may only be modified prior + * to being added to a message descriptor which is subsequently added to a pool. + */ +static VALUE OneofDescriptor_alloc(VALUE klass) { + OneofDescriptor* self = ALLOC(OneofDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &OneofDescriptor_type, self); + self->oneofdef = NULL; + self->descriptor_pool = Qnil; + return ret; +} + +/* + * call-seq: + * OneofDescriptor.new(c_only_cookie, pool, ptr) => OneofDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->oneofdef = (const upb_OneofDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: OneofDescriptor#name + * + * Returns the name of this oneof. + * + * @return [String] + */ +static VALUE OneofDescriptor_name(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + return rb_str_maybe_null(upb_OneofDef_Name(self->oneofdef)); +} + +/* + * ruby-doc: OneofDescriptor#each + * + * Iterates through fields in this oneof, yielding to the block on each one. + * + * @yield [FieldDescriptor] + * @return [nil] + */ +static VALUE OneofDescriptor_each(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + + int n = upb_OneofDef_FieldCount(self->oneofdef); + for (int i = 0; i < n; i++) { + const upb_FieldDef* f = upb_OneofDef_Field(self->oneofdef, i); + VALUE obj = get_fielddef_obj(self->descriptor_pool, f); + rb_yield(obj); + } + return Qnil; +} + +/* + * ruby-doc: OneofDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L824 + * OneofOptions} for this {OneofDescriptor}. + * + * @return [OneofOptions] + */ +static VALUE OneOfDescriptor_options(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + const google_protobuf_OneofOptions* opts = + upb_OneofDef_Options(self->oneofdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_OneofOptions_serialize(opts, arena, &size); + VALUE oneof_options = decode_options(_self, "OneofOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return oneof_options; +} + +/* + * ruby-doc: OneofDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L343 + * OneofDescriptorProto} of this {OneofDescriptor}. + * + * @return [OneofDescriptorProto] + */ +static VALUE OneOfDescriptor_to_proto(VALUE _self) { + OneofDescriptor* self = ruby_to_OneofDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_OneofDescriptorProto* proto = + upb_OneofDef_ToProto(self->oneofdef, arena); + size_t size; + const char* serialized = + google_protobuf_OneofDescriptorProto_serialize(proto, arena, &size); + VALUE proto_class = rb_path2class("Google::Protobuf::OneofDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void OneofDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "OneofDescriptor", rb_cObject); + rb_define_alloc_func(klass, OneofDescriptor_alloc); + rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3); + rb_define_method(klass, "name", OneofDescriptor_name, 0); + rb_define_method(klass, "each", OneofDescriptor_each, 0); + rb_define_method(klass, "options", OneOfDescriptor_options, 0); + rb_define_method(klass, "to_proto", OneOfDescriptor_to_proto, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cOneofDescriptor); + cOneofDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// EnumDescriptor. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_EnumDef* enumdef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_EnumDef. +} EnumDescriptor; + +static VALUE cEnumDescriptor = Qnil; + +static void EnumDescriptor_mark(void* _self) { + EnumDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t EnumDescriptor_type = { + "Google::Protobuf::EnumDescriptor", + {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) { + EnumDescriptor* ret; + TypedData_Get_Struct(val, EnumDescriptor, &EnumDescriptor_type, ret); + return ret; +} + +static VALUE EnumDescriptor_alloc(VALUE klass) { + EnumDescriptor* self = ALLOC(EnumDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &EnumDescriptor_type, self); + self->enumdef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +// Exposed to other modules in defs.h. +const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) { + EnumDescriptor* desc = ruby_to_EnumDescriptor(enum_desc_rb); + return desc->enumdef; +} + +/** + * ruby-doc: EnumDescriptor + * + * An EnumDescriptor provides information about the Protobuf definition of an + * enum inside a {Descriptor}. + */ + +/* + * call-seq: + * EnumDescriptor.new(c_only_cookie, ptr) => EnumDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE EnumDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->enumdef = (const upb_EnumDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: EnumDescriptor#file_descriptor + * + * Returns the {FileDescriptor} object this enum belongs to. + * + * @return [FileDescriptor] + */ +static VALUE EnumDescriptor_file_descriptor(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_EnumDef_File(self->enumdef)); +} + +/* + * ruby-doc: EnumDescriptor#is_closed? + * + * Returns whether this enum is open or closed. + * + * @return [Boolean] + */ +static VALUE EnumDescriptor_is_closed(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return upb_EnumDef_IsClosed(self->enumdef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: EnumDescriptor#name + * + * Returns the name of this enum type. + * + * @return [String] + */ +static VALUE EnumDescriptor_name(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + return rb_str_maybe_null(upb_EnumDef_FullName(self->enumdef)); +} + +/* + * ruby-doc: EnumDescriptor#lookup_name + * + * Returns the numeric value corresponding to the given key name (as a Ruby + * symbol), or nil if none. + * + * @param name [Symbol] + * @return [Integer,nil] + */ +static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + const char* name_str = rb_id2name(SYM2ID(name)); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByName(self->enumdef, name_str); + if (ev) { + return INT2NUM(upb_EnumValueDef_Number(ev)); + } else { + return Qnil; + } +} + +/* + * ruby-doc: EnumDescriptor#lookup_value + * + * Returns the key name (as a Ruby symbol) corresponding to the integer value, + * or nil if none. + * + * @param name [Integer] + * @return [Symbol,nil] + */ +static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + int32_t val = NUM2INT(number); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNumber(self->enumdef, val); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return Qnil; + } +} + +/* + * ruby-doc: EnumDescriptor#each + * + * Iterates over key => value mappings in this enum's definition, yielding to + * the block with (key, value) arguments for each one. + * + * @yield [Symbol, Integer] + * @return [nil] + */ +static VALUE EnumDescriptor_each(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + + int n = upb_EnumDef_ValueCount(self->enumdef); + for (int i = 0; i < n; i++) { + const upb_EnumValueDef* ev = upb_EnumDef_Value(self->enumdef, i); + VALUE key = ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + VALUE number = INT2NUM(upb_EnumValueDef_Number(ev)); + rb_yield_values(2, key, number); + } + + return Qnil; +} + +/* + * ruby-doc: EnumDescriptor#enummodule + * + * Returns the Ruby module corresponding to this enum type. + * + * @return [Module] + */ +static VALUE EnumDescriptor_enummodule(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + if (self->module == Qnil) { + RB_OBJ_WRITE(_self, &self->module, build_module_from_enumdesc(_self)); + } + return self->module; +} + +/* + * ruby-doc: EnumDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L838 + * EnumOptions} for this {EnumDescriptor}. + * + * @return [EnumOptions] + */ +static VALUE EnumDescriptor_options(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + const google_protobuf_EnumOptions* opts = upb_EnumDef_Options(self->enumdef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = google_protobuf_EnumOptions_serialize(opts, arena, &size); + VALUE enum_options = decode_options(_self, "EnumOptions", size, serialized, + self->descriptor_pool); + upb_Arena_Free(arena); + return enum_options; +} + +/* + * ruby-doc: EnumDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L349 + * EnumDescriptorProto} of this {EnumDescriptor}. + * @return [EnumDescriptorProto] + */ +static VALUE EnumDescriptor_to_proto(VALUE _self) { + EnumDescriptor* self = ruby_to_EnumDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_EnumDescriptorProto* proto = + upb_EnumDef_ToProto(self->enumdef, arena); + + size_t size; + const char* serialized = + google_protobuf_EnumDescriptorProto_serialize(proto, arena, &size); + + VALUE proto_class = rb_path2class("Google::Protobuf::EnumDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void EnumDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "EnumDescriptor", rb_cObject); + rb_define_alloc_func(klass, EnumDescriptor_alloc); + rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3); + rb_define_method(klass, "name", EnumDescriptor_name, 0); + rb_define_method(klass, "lookup_name", EnumDescriptor_lookup_name, 1); + rb_define_method(klass, "lookup_value", EnumDescriptor_lookup_value, 1); + rb_define_method(klass, "each", EnumDescriptor_each, 0); + rb_define_method(klass, "enummodule", EnumDescriptor_enummodule, 0); + rb_define_method(klass, "file_descriptor", EnumDescriptor_file_descriptor, 0); + rb_define_method(klass, "is_closed?", EnumDescriptor_is_closed, 0); + rb_define_method(klass, "options", EnumDescriptor_options, 0); + rb_define_method(klass, "to_proto", EnumDescriptor_to_proto, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cEnumDescriptor); + cEnumDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// ServiceDescriptor +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_ServiceDef* servicedef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_ServiceDef. +} ServiceDescriptor; + +static VALUE cServiceDescriptor = Qnil; + +static void ServiceDescriptor_mark(void* _self) { + ServiceDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t ServiceDescriptor_type = { + "Google::Protobuf::ServicDescriptor", + {ServiceDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static ServiceDescriptor* ruby_to_ServiceDescriptor(VALUE val) { + ServiceDescriptor* ret; + TypedData_Get_Struct(val, ServiceDescriptor, &ServiceDescriptor_type, ret); + return ret; +} + +static VALUE ServiceDescriptor_alloc(VALUE klass) { + ServiceDescriptor* self = ALLOC(ServiceDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &ServiceDescriptor_type, self); + self->servicedef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/** + * ruby-doc: ServiceDescriptor + * + * A ServiceDescriptor provides information about the Protobuf definition of an + * RPC service. + */ + +/* + * call-seq: + * ServiceDescriptor.new(c_only_cookie, ptr) => ServiceDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE ServiceDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->servicedef = (const upb_ServiceDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: ServiceDescriptor#name + * + * Returns the name of this service. + * + * @return [String] + */ +static VALUE ServiceDescriptor_name(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + return rb_str_maybe_null(upb_ServiceDef_FullName(self->servicedef)); +} + +/* + * ruby-doc: ServiceDescriptor#file_descriptor + * + * Returns the {FileDescriptor} object this service belongs to. + * @return [FileDescriptor] + */ +static VALUE ServiceDescriptor_file_descriptor(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + return get_filedef_obj(self->descriptor_pool, + upb_ServiceDef_File(self->servicedef)); +} + +/* + * ruby-doc: ServiceDescriptor#each + * + * Iterates over methods in this service, yielding to the block on each one. + * + * @yield [MethodDescriptor] + * @return [nil] + */ +static VALUE ServiceDescriptor_each(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + + int n = upb_ServiceDef_MethodCount(self->servicedef); + for (int i = 0; i < n; i++) { + const upb_MethodDef* method = upb_ServiceDef_Method(self->servicedef, i); + VALUE obj = get_methoddef_obj(self->descriptor_pool, method); + rb_yield(obj); + } + return Qnil; +} + +/* + * ruby-doc: ServiceDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L901 + * ServiceOptions} for this {ServiceDescriptor}. + * + * @return [ServiceOptions] + */ +static VALUE ServiceDescriptor_options(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + const google_protobuf_ServiceOptions* opts = + upb_ServiceDef_Options(self->servicedef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_ServiceOptions_serialize(opts, arena, &size); + VALUE service_options = decode_options(_self, "ServiceOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return service_options; +} + +/* + * ruby-doc: ServiceDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L386 + * ServiceDescriptorProto} of this {ServiceDescriptor}. + * + * @return [ServiceDescriptorProto] + */ +static VALUE ServiceDescriptor_to_proto(VALUE _self) { + ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_ServiceDescriptorProto* proto = + upb_ServiceDef_ToProto(self->servicedef, arena); + size_t size; + const char* serialized = + google_protobuf_ServiceDescriptorProto_serialize(proto, arena, &size); + VALUE proto_class = rb_path2class("Google::Protobuf::ServiceDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +static void ServiceDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "ServiceDescriptor", rb_cObject); + rb_define_alloc_func(klass, ServiceDescriptor_alloc); + rb_define_method(klass, "initialize", ServiceDescriptor_initialize, 3); + rb_define_method(klass, "name", ServiceDescriptor_name, 0); + rb_define_method(klass, "each", ServiceDescriptor_each, 0); + rb_define_method(klass, "file_descriptor", ServiceDescriptor_file_descriptor, + 0); + rb_define_method(klass, "options", ServiceDescriptor_options, 0); + rb_define_method(klass, "to_proto", ServiceDescriptor_to_proto, 0); + rb_include_module(klass, rb_mEnumerable); + rb_gc_register_address(&cServiceDescriptor); + cServiceDescriptor = klass; +} + +// ----------------------------------------------------------------------------- +// MethodDescriptor +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_MethodDef* methoddef; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE module; // begins as nil + VALUE descriptor_pool; // Owns the upb_MethodDef. +} MethodDescriptor; + +static VALUE cMethodDescriptor = Qnil; + +static void MethodDescriptor_mark(void* _self) { + MethodDescriptor* self = _self; + rb_gc_mark(self->module); + rb_gc_mark(self->descriptor_pool); +} + +static const rb_data_type_t MethodDescriptor_type = { + "Google::Protobuf::MethodDescriptor", + {MethodDescriptor_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static MethodDescriptor* ruby_to_MethodDescriptor(VALUE val) { + MethodDescriptor* ret; + TypedData_Get_Struct(val, MethodDescriptor, &MethodDescriptor_type, ret); + return ret; +} + +static VALUE MethodDescriptor_alloc(VALUE klass) { + MethodDescriptor* self = ALLOC(MethodDescriptor); + VALUE ret = TypedData_Wrap_Struct(klass, &MethodDescriptor_type, self); + self->methoddef = NULL; + self->module = Qnil; + self->descriptor_pool = Qnil; + return ret; +} + +/** + * ruby-doc: MethodDescriptor + * + * A MethodDescriptor provides information about the Protobuf definition of a + * method inside an RPC service. + */ + +/* + * call-seq: + * MethodDescriptor.new(c_only_cookie, ptr) => MethodDescriptor + * + * Creates a descriptor wrapper object. May only be called from C. + */ +static VALUE MethodDescriptor_initialize(VALUE _self, VALUE cookie, + VALUE descriptor_pool, VALUE ptr) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + + if (cookie != c_only_cookie) { + rb_raise(rb_eRuntimeError, + "Descriptor objects may not be created from Ruby."); + } + + RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool); + self->methoddef = (const upb_MethodDef*)NUM2ULL(ptr); + + return Qnil; +} + +/* + * ruby-doc: MethodDescriptor#name + * + * Returns the name of this method + * + * @return [String] + */ +static VALUE MethodDescriptor_name(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return rb_str_maybe_null(upb_MethodDef_Name(self->methoddef)); +} + +/* + * ruby-doc: MethodDescriptor#options + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L927 + * MethodOptions} for this {MethodDescriptor}. + * + * @return [MethodOptions] + */ +static VALUE MethodDescriptor_options(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const google_protobuf_MethodOptions* opts = + upb_MethodDef_Options(self->methoddef); + upb_Arena* arena = upb_Arena_New(); + size_t size; + char* serialized = + google_protobuf_MethodOptions_serialize(opts, arena, &size); + VALUE method_options = decode_options(_self, "MethodOptions", size, + serialized, self->descriptor_pool); + upb_Arena_Free(arena); + return method_options; +} + +/* + * ruby-doc: MethodDescriptor#input_type + * + * Returns the {Descriptor} for the request message type of this method + * + * @return [Descriptor] + */ +static VALUE MethodDescriptor_input_type(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const upb_MessageDef* type = upb_MethodDef_InputType(self->methoddef); + return get_msgdef_obj(self->descriptor_pool, type); +} + +/* + * ruby-doc: MethodDescriptor#output_type + * + * Returns the {Descriptor} for the response message type of this method + * + * @return [Descriptor] + */ +static VALUE MethodDescriptor_output_type(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + const upb_MessageDef* type = upb_MethodDef_OutputType(self->methoddef); + return get_msgdef_obj(self->descriptor_pool, type); +} + +/* + * ruby-doc: MethodDescriptor#client_streaming + * + * Returns whether or not this is a streaming request method + * + * @return [Boolean] + */ +static VALUE MethodDescriptor_client_streaming(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return upb_MethodDef_ClientStreaming(self->methoddef) ? Qtrue : Qfalse; +} + +/* + * ruby-doc: MethodDescriptor#to_proto + * + * Returns the + * {https://github.com/protocolbuffers/protobuf/blob/v30.2/src/google/protobuf/descriptor.proto#L394 + * MethodDescriptorProto} of this {MethodDescriptor}. + * + * @return [MethodDescriptorProto] + */ +static VALUE MethodDescriptor_to_proto(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + upb_Arena* arena = upb_Arena_New(); + google_protobuf_MethodDescriptorProto* proto = + upb_MethodDef_ToProto(self->methoddef, arena); + size_t size; + const char* serialized = + google_protobuf_MethodDescriptorProto_serialize(proto, arena, &size); + VALUE proto_class = rb_path2class("Google::Protobuf::MethodDescriptorProto"); + VALUE proto_rb = + Message_decode_bytes(size, serialized, 0, proto_class, false); + upb_Arena_Free(arena); + return proto_rb; +} + +/* + * ruby-doc: MethodDescriptor#server_streaming + * + * Returns whether or not this is a streaming response method + * + * @return [Boolean] + */ +static VALUE MethodDescriptor_server_streaming(VALUE _self) { + MethodDescriptor* self = ruby_to_MethodDescriptor(_self); + return upb_MethodDef_ServerStreaming(self->methoddef) ? Qtrue : Qfalse; +} + +static void MethodDescriptor_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "MethodDescriptor", rb_cObject); + rb_define_alloc_func(klass, MethodDescriptor_alloc); + rb_define_method(klass, "initialize", MethodDescriptor_initialize, 3); + rb_define_method(klass, "name", MethodDescriptor_name, 0); + rb_define_method(klass, "options", MethodDescriptor_options, 0); + rb_define_method(klass, "input_type", MethodDescriptor_input_type, 0); + rb_define_method(klass, "output_type", MethodDescriptor_output_type, 0); + rb_define_method(klass, "client_streaming", MethodDescriptor_client_streaming, + 0); + rb_define_method(klass, "server_streaming", MethodDescriptor_server_streaming, + 0); + rb_define_method(klass, "to_proto", MethodDescriptor_to_proto, 0); + rb_gc_register_address(&cMethodDescriptor); + cMethodDescriptor = klass; +} + +static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) { + DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool); + VALUE key = ULL2NUM((intptr_t)ptr); + VALUE def; + + def = rb_hash_aref(descriptor_pool->def_to_descriptor, key); + + if (ptr == NULL) { + return Qnil; + } + + if (def == Qnil) { + // Lazily create wrapper object. + VALUE args[3] = {c_only_cookie, _descriptor_pool, key}; + def = rb_class_new_instance(3, args, klass); + rb_hash_aset(descriptor_pool->def_to_descriptor, key, def); + } + + return def; +} + +static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def) { + return get_def_obj(descriptor_pool, def, cDescriptor); +} + +static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def) { + return get_def_obj(descriptor_pool, def, cEnumDescriptor); +} + +static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def) { + return get_def_obj(descriptor_pool, def, cFieldDescriptor); +} + +static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def) { + return get_def_obj(descriptor_pool, def, cFileDescriptor); +} + +static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def) { + return get_def_obj(descriptor_pool, def, cOneofDescriptor); +} + +static VALUE get_servicedef_obj(VALUE descriptor_pool, + const upb_ServiceDef* def) { + return get_def_obj(descriptor_pool, def, cServiceDescriptor); +} + +static VALUE get_methoddef_obj(VALUE descriptor_pool, + const upb_MethodDef* def) { + return get_def_obj(descriptor_pool, def, cMethodDescriptor); +} + +// ----------------------------------------------------------------------------- +// Shared functions +// ----------------------------------------------------------------------------- + +// Functions exposed to other modules in defs.h. + +VALUE Descriptor_DefToClass(const upb_MessageDef* m) { + const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m)); + VALUE pool = ObjectCache_Get(symtab); + PBRUBY_ASSERT(pool != Qnil); + VALUE desc_rb = get_msgdef_obj(pool, m); + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + return desc->klass; +} + +const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb) { + const Descriptor* desc = ruby_to_Descriptor(desc_rb); + return desc->msgdef; +} + +VALUE TypeInfo_InitArg(int argc, VALUE* argv, int skip_arg) { + if (argc > skip_arg) { + if (argc > 1 + skip_arg) { + rb_raise(rb_eArgError, "Expected a maximum of %d arguments.", + skip_arg + 1); + } + return argv[skip_arg]; + } else { + return Qnil; + } +} + +TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg, + VALUE* type_class, VALUE* init_arg) { + TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])}; + + if (ret.type == kUpb_CType_Message || ret.type == kUpb_CType_Enum) { + *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2); + + if (argc < 2 + skip_arg) { + rb_raise(rb_eArgError, "Expected at least %d arguments for message/enum.", + 2 + skip_arg); + } + + VALUE klass = argv[1 + skip_arg]; + VALUE desc = MessageOrEnum_GetDescriptor(klass); + *type_class = klass; + + if (desc == Qnil) { + rb_raise(rb_eArgError, + "Type class has no descriptor. Please pass a " + "class or enum as returned by the DescriptorPool."); + } + + if (ret.type == kUpb_CType_Message) { + ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef; + Message_CheckClass(klass); + } else { + PBRUBY_ASSERT(ret.type == kUpb_CType_Enum); + ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef; + } + } else { + *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 1); + } + + return ret; +} + +void Defs_register(VALUE module) { + DescriptorPool_register(module); + Descriptor_register(module); + FileDescriptor_register(module); + FieldDescriptor_register(module); + OneofDescriptor_register(module); + EnumDescriptor_register(module); + ServiceDescriptor_register(module); + MethodDescriptor_register(module); + + rb_gc_register_address(&c_only_cookie); + c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.h new file mode 100755 index 00000000..931dd6ed --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/defs.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_DEFS_H_ +#define RUBY_PROTOBUF_DEFS_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// ----------------------------------------------------------------------------- +// TypeInfo +// ----------------------------------------------------------------------------- + +// This bundles a upb_CType and msgdef/enumdef when appropriate. This is +// convenient for functions that need type information but cannot necessarily +// assume a upb_FieldDef will be available. +// +// For example, Google::Protobuf::Map and Google::Protobuf::RepeatedField can +// be constructed with type information alone: +// +// # RepeatedField will internally store the type information in a TypeInfo. +// Google::Protobuf::RepeatedField.new(:message, FooMessage) + +typedef struct { + upb_CType type; + union { + const upb_MessageDef* msgdef; // When type == kUpb_CType_Message + const upb_EnumDef* enumdef; // When type == kUpb_CType_Enum + } def; +} TypeInfo; + +static inline TypeInfo TypeInfo_get(const upb_FieldDef* f) { + TypeInfo ret = {upb_FieldDef_CType(f), {NULL}}; + switch (ret.type) { + case kUpb_CType_Message: + ret.def.msgdef = upb_FieldDef_MessageSubDef(f); + break; + case kUpb_CType_Enum: + ret.def.enumdef = upb_FieldDef_EnumSubDef(f); + break; + default: + break; + } + return ret; +} + +TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg, + VALUE* type_class, VALUE* init_arg); + +static inline TypeInfo TypeInfo_from_type(upb_CType type) { + TypeInfo ret = {type}; + assert(type != kUpb_CType_Message && type != kUpb_CType_Enum); + return ret; +} + +// ----------------------------------------------------------------------------- +// Other utilities +// ----------------------------------------------------------------------------- + +VALUE Descriptor_DefToClass(const upb_MessageDef* m); + +// Returns the underlying msgdef, enumdef, or symtab (respectively) for the +// given Descriptor, EnumDescriptor, or DescriptorPool Ruby object. +const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb); +const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb); +const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb); + +// Returns a upb field type for the given Ruby symbol +// (eg. :float => kUpb_CType_Float). +upb_CType ruby_to_fieldtype(VALUE type); + +// The singleton generated pool (a DescriptorPool object). +extern VALUE generated_pool; + +// Call at startup to register all types in this module. +void Defs_register(VALUE module); + +#endif // RUBY_PROTOBUF_DEFS_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/extconf.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/extconf.rb new file mode 100755 index 00000000..f97b9b5b --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/extconf.rb @@ -0,0 +1,38 @@ +#!/usr/bin/ruby + +require 'mkmf' + +ext_name = "google/protobuf_c" + +dir_config(ext_name) + +if ENV["CC"] + RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] +end + +if ENV["CXX"] + RbConfig::CONFIG["CXX"] = RbConfig::MAKEFILE_CONFIG["CXX"] = ENV["CXX"] +end + +if ENV["LD"] + RbConfig::CONFIG["LD"] = RbConfig::MAKEFILE_CONFIG["LD"] = ENV["LD"] +end + +debug_enabled = ENV["PROTOBUF_CONFIG"] == "dbg" + +additional_c_flags = debug_enabled ? "-O0 -fno-omit-frame-pointer -fvisibility=default -g" : "-O3 -DNDEBUG -fvisibility=hidden" + +if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/ + $CFLAGS += " -std=gnu99 -Wall -Wsign-compare -Wno-declaration-after-statement #{additional_c_flags}" +else + $CFLAGS += " -std=gnu99 #{additional_c_flags}" +end + +$VPATH << "$(srcdir)/third_party/utf8_range" +$INCFLAGS += " -I$(srcdir)/third_party/utf8_range" + +$srcs = ["protobuf.c", "convert.c", "defs.c", "message.c", "repeated_field.c", + "map.c", "ruby-upb.c", "utf8_range.c", "shared_convert.c", + "shared_message.c"] + +create_makefile(ext_name) diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/glue.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/glue.c new file mode 100755 index 00000000..46e91463 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/glue.c @@ -0,0 +1,135 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Exposing inlined UPB functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "ruby-upb.h" + +upb_Arena* Arena_create() { return upb_Arena_Init(NULL, 0, &upb_alloc_global); } + +google_protobuf_FileDescriptorProto* FileDescriptorProto_parse( + const char* serialized_file_proto, size_t length, upb_Arena* arena) { + return google_protobuf_FileDescriptorProto_parse(serialized_file_proto, + length, arena); +} + +char* EnumDescriptor_serialized_options(const upb_EnumDef* enumdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_EnumOptions* opts = upb_EnumDef_Options(enumdef); + char* serialized = google_protobuf_EnumOptions_serialize(opts, arena, size); + return serialized; +} + +char* EnumDescriptor_serialized_to_proto(const upb_EnumDef* enumdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_EnumDescriptorProto* file_proto = + upb_EnumDef_ToProto(enumdef, arena); + char* serialized = + google_protobuf_EnumDescriptorProto_serialize(file_proto, arena, size); + return serialized; +} + +char* FileDescriptor_serialized_options(const upb_FileDef* filedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FileOptions* opts = upb_FileDef_Options(filedef); + char* serialized = google_protobuf_FileOptions_serialize(opts, arena, size); + return serialized; +} + +char* FileDescriptor_serialized_to_proto(const upb_FileDef* filedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FileDescriptorProto* file_proto = + upb_FileDef_ToProto(filedef, arena); + char* serialized = + google_protobuf_FileDescriptorProto_serialize(file_proto, arena, size); + return serialized; +} + +char* Descriptor_serialized_options(const upb_MessageDef* msgdef, size_t* size, + upb_Arena* arena) { + const google_protobuf_MessageOptions* opts = upb_MessageDef_Options(msgdef); + char* serialized = + google_protobuf_MessageOptions_serialize(opts, arena, size); + return serialized; +} + +char* Descriptor_serialized_to_proto(const upb_MessageDef* msgdef, size_t* size, + upb_Arena* arena) { + const google_protobuf_DescriptorProto* proto = + upb_MessageDef_ToProto(msgdef, arena); + char* serialized = + google_protobuf_DescriptorProto_serialize(proto, arena, size); + return serialized; +} + +char* OneOfDescriptor_serialized_options(const upb_OneofDef* oneofdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_OneofOptions* opts = upb_OneofDef_Options(oneofdef); + char* serialized = google_protobuf_OneofOptions_serialize(opts, arena, size); + return serialized; +} + +char* OneOfDescriptor_serialized_to_proto(const upb_OneofDef* oneofdef, + size_t* size, upb_Arena* arena) { + const google_protobuf_OneofDescriptorProto* proto = + upb_OneofDef_ToProto(oneofdef, arena); + char* serialized = + google_protobuf_OneofDescriptorProto_serialize(proto, arena, size); + return serialized; +} + +char* FieldDescriptor_serialized_options(const upb_FieldDef* fielddef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FieldOptions* opts = upb_FieldDef_Options(fielddef); + char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, size); + return serialized; +} + +char* FieldDescriptor_serialized_to_proto(const upb_FieldDef* fieldef, + size_t* size, upb_Arena* arena) { + const google_protobuf_FieldDescriptorProto* proto = + upb_FieldDef_ToProto(fieldef, arena); + char* serialized = + google_protobuf_FieldDescriptorProto_serialize(proto, arena, size); + return serialized; +} + +char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_ServiceOptions* opts = + upb_ServiceDef_Options(servicedef); + char* serialized = + google_protobuf_ServiceOptions_serialize(opts, arena, size); + return serialized; +} + +char* ServiceDescriptor_serialized_to_proto(const upb_ServiceDef* servicedef, + size_t* size, upb_Arena* arena) { + const google_protobuf_ServiceDescriptorProto* proto = + upb_ServiceDef_ToProto(servicedef, arena); + char* serialized = + google_protobuf_ServiceDescriptorProto_serialize(proto, arena, size); + return serialized; +} + +char* MethodDescriptor_serialized_options(const upb_MethodDef* methoddef, + size_t* size, upb_Arena* arena) { + const google_protobuf_MethodOptions* opts = upb_MethodDef_Options(methoddef); + char* serialized = google_protobuf_MethodOptions_serialize(opts, arena, size); + return serialized; +} + +char* MethodDescriptor_serialized_to_proto(const upb_MethodDef* methodef, + size_t* size, upb_Arena* arena) { + const google_protobuf_MethodDescriptorProto* proto = + upb_MethodDef_ToProto(methodef, arena); + char* serialized = + google_protobuf_MethodDescriptorProto_serialize(proto, arena, size); + return serialized; +} \ No newline at end of file diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.c new file mode 100755 index 00000000..4ad39956 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.c @@ -0,0 +1,768 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "convert.h" +#include "defs.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Basic map operations on top of upb_Map. +// +// Note that we roll our own `Map` container here because, as for +// `RepeatedField`, we want a strongly-typed container. This is so that any user +// errors due to incorrect map key or value types are raised as close as +// possible to the error site, rather than at some deferred point (e.g., +// serialization). +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Map container type. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_Map* map; // Can convert to mutable when non-frozen. + upb_CType key_type; + TypeInfo value_type_info; + VALUE value_type_class; + VALUE arena; +} Map; + +static void Map_mark(void* _self) { + Map* self = _self; + rb_gc_mark(self->value_type_class); + rb_gc_mark(self->arena); +} + +static size_t Map_memsize(const void* _self) { return sizeof(Map); } + +const rb_data_type_t Map_type = { + "Google::Protobuf::Map", + {Map_mark, RUBY_DEFAULT_FREE, Map_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +VALUE cMap; + +static Map* ruby_to_Map(VALUE _self) { + Map* self; + TypedData_Get_Struct(_self, Map, &Map_type, self); + return self; +} + +static VALUE Map_alloc(VALUE klass) { + Map* self = ALLOC(Map); + self->map = NULL; + self->value_type_class = Qnil; + self->value_type_info.def.msgdef = NULL; + self->arena = Qnil; + return TypedData_Wrap_Struct(klass, &Map_type, self); +} + +VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type, + TypeInfo value_type, VALUE arena) { + PBRUBY_ASSERT(map); + PBRUBY_ASSERT(arena != Qnil); + + VALUE val = ObjectCache_Get(map); + + if (val == Qnil) { + val = Map_alloc(cMap); + Map* self; + TypedData_Get_Struct(val, Map, &Map_type, self); + self->map = map; + self->arena = arena; + self->key_type = key_type; + self->value_type_info = value_type; + if (self->value_type_info.type == kUpb_CType_Message) { + const upb_MessageDef* val_m = self->value_type_info.def.msgdef; + self->value_type_class = Descriptor_DefToClass(val_m); + } + return ObjectCache_TryAdd(map, val); + } + return val; +} + +static VALUE Map_new_this_type(Map* from) { + VALUE arena_rb = Arena_new(); + upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type, + from->value_type_info.type); + VALUE ret = + Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb); + PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class); + return ret; +} + +static TypeInfo Map_keyinfo(Map* self) { + TypeInfo ret; + ret.type = self->key_type; + ret.def.msgdef = NULL; + return ret; +} + +static upb_Map* Map_GetMutable(VALUE _self) { + const upb_Map* map = ruby_to_Map(_self)->map; + Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map)); + return (upb_Map*)map; +} + +VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type, + TypeInfo val_info) { + VALUE hash = rb_hash_new(); + TypeInfo key_info = TypeInfo_from_type(key_type); + + if (!map) return hash; + + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil); + VALUE val_val = Scalar_CreateHash(val, val_info); + rb_hash_aset(hash, key_val, val_val); + } + + return hash; +} + +VALUE Map_deep_copy(VALUE obj) { + Map* self = ruby_to_Map(obj); + VALUE new_arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(new_arena_rb); + upb_Map* new_map = + upb_Map_New(arena, self->key_type, self->value_type_info.type); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_MessageValue val_copy = + Msgval_DeepCopy(val, self->value_type_info, arena); + upb_Map_Set(new_map, key, val_copy, arena); + } + + return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info, + new_arena_rb); +} + +const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field, + upb_Arena* arena) { + const upb_FieldDef* key_field = map_field_key(field); + const upb_FieldDef* value_field = map_field_value(field); + TypeInfo value_type_info = TypeInfo_get(value_field); + Map* self; + + if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || + RTYPEDDATA_TYPE(val) != &Map_type) { + rb_raise(cTypeError, "Expected Map instance"); + } + + self = ruby_to_Map(val); + if (self->key_type != upb_FieldDef_CType(key_field)) { + rb_raise(cTypeError, "Map key type does not match field's key type"); + } + if (self->value_type_info.type != value_type_info.type) { + rb_raise(cTypeError, "Map value type does not match field's value type"); + } + if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) { + rb_raise(cTypeError, "Map value type has wrong message/enum class"); + } + + Arena_fuse(self->arena, arena); + return self->map; +} + +void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type, + TypeInfo val_type) { + bool first = true; + TypeInfo key_type_info = {key_type}; + StringBuilder_Printf(b, "{"); + if (map) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + if (first) { + first = false; + } else { + StringBuilder_Printf(b, ", "); + } + StringBuilder_PrintMsgval(b, key, key_type_info); + StringBuilder_Printf(b, "=>"); + StringBuilder_PrintMsgval(b, val, val_type); + } + } + StringBuilder_Printf(b, "}"); +} + +static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) { + Map* self = ruby_to_Map(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue key_val = + Convert_RubyToUpb(key, "", Map_keyinfo(self), arena); + upb_MessageValue val_val = + Convert_RubyToUpb(val, "", self->value_type_info, arena); + upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena); + return ST_CONTINUE; +} + +// Used only internally -- shared by #merge and #initialize. +static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { + if (TYPE(hashmap) == T_HASH) { + rb_hash_foreach(hashmap, merge_into_self_callback, _self); + } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) && + RTYPEDDATA_TYPE(hashmap) == &Map_type) { + Map* self = ruby_to_Map(_self); + Map* other = ruby_to_Map(hashmap); + upb_Arena* arena = Arena_get(self->arena); + upb_Map* self_map = Map_GetMutable(_self); + + Arena_fuse(other->arena, arena); + + if (self->key_type != other->key_type || + self->value_type_info.type != other->value_type_info.type || + self->value_type_class != other->value_type_class) { + rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); + } + + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(other->map, &key, &val, &iter)) { + upb_Map_Set(self_map, key, val, arena); + } + } else { + rb_raise(rb_eArgError, "Unknown type merging into Map"); + } + return _self; +} + +/** + * ruby-doc: Map + * + * This class represents a Protobuf Map. It is largely automatically transformed + * to and from a Ruby hash. + */ + +/* + * ruby-doc: Map#initialize + * + * Allocates a new Map container. This constructor may be called with 2, 3, or 4 + * arguments. The first two arguments are always present and are symbols (taking + * on the same values as field-type symbols in message descriptors) that + * indicate the type of the map key and value fields. + * + * The supported key types are: :int32, :int64, :uint32, :uint64, :bool, + * :string, :bytes. + * + * The supported value types are: :int32, :int64, :uint32, :uint64, :bool, + * :string, :bytes, :enum, :message. + * + * The third argument, value_typeclass, must be present if value_type is :enum + * or :message. As in RepeatedField#new, this argument must be a message class + * (for :message) or enum module (for :enum). + * + * The last argument, if present, provides initial content for map. Note that + * this may be an ordinary Ruby hashmap or another Map instance with identical + * key and value types. Also note that this argument may be present whether or + * not value_typeclass is present (and it is unambiguously separate from + * value_typeclass because value_typeclass's presence is strictly determined by + * value_type). The contents of this initial hashmap or Map instance are + * shallow-copied into the new Map: the original map is unmodified, but + * references to underlying objects will be shared if the value type is a + * message type. + * + * @param key_type [Symbol] + * @param value_type [Symbol] + * @param value_typeclass [Class,Module] + * @paramdefault value_typeclass nil + * @param init_hashmap [Hash,Map] + * @paramdefault init_hashmap {} + */ +static VALUE Map_init(int argc, VALUE* argv, VALUE _self) { + Map* self = ruby_to_Map(_self); + VALUE init_arg; + + // We take either two args (:key_type, :value_type), three args (:key_type, + // :value_type, "ValueMessageType"), or four args (the above plus an initial + // hashmap). + if (argc < 2 || argc > 4) { + rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments."); + } + + self->key_type = ruby_to_fieldtype(argv[0]); + self->value_type_info = + TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg); + self->arena = Arena_new(); + + // Check that the key type is an allowed type. + switch (self->key_type) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Bool: + case kUpb_CType_String: + case kUpb_CType_Bytes: + // These are OK. + break; + default: + rb_raise(rb_eArgError, "Invalid key type for map."); + } + + self->map = upb_Map_New(Arena_get(self->arena), self->key_type, + self->value_type_info.type); + VALUE stored = ObjectCache_TryAdd(self->map, _self); + (void)stored; + PBRUBY_ASSERT(stored == _self); + + if (init_arg != Qnil) { + Map_merge_into_self(_self, init_arg); + } + + return Qnil; +} + +/* + * ruby-doc: Map#each + * + * Invokes &block on each |key, value| pair in the map, in unspecified order. + * Note that Map also includes Enumerable; map thus acts like a normal Ruby + * sequence. + * + * @yield [Object, Object] + * @return [nil] + */ +static VALUE Map_each(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); + VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); + rb_yield_values(2, key_val, val_val); + } + + return Qnil; +} + +/* + * ruby-doc: Map#keys + * + * Returns the list of keys contained in the map, in unspecified order. + * + * @return [Array] + */ +static VALUE Map_keys(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + VALUE ret = rb_ary_new(); + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); + rb_ary_push(ret, key_val); + } + + return ret; +} + +/* + * ruby-doc: Map#values + * + * Returns the list of values contained in the map, in unspecified order. + * + * @return [Array] + */ +static VALUE Map_values(VALUE _self) { + Map* self = ruby_to_Map(_self); + size_t iter = kUpb_Map_Begin; + VALUE ret = rb_ary_new(); + upb_MessageValue key, val; + + while (upb_Map_Next(self->map, &key, &val, &iter)) { + VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); + rb_ary_push(ret, val_val); + } + + return ret; +} + +/* + * ruby-doc: Map#[] + * + * Accesses the element at the given key. Throws an exception if the key type is + * incorrect. Returns nil when the key is not present in the map. + * + * @param key [Object] + * @return [Object] + */ +static VALUE Map_index(VALUE _self, VALUE key) { + Map* self = ruby_to_Map(_self); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val; + + if (upb_Map_Get(self->map, key_upb, &val)) { + return Convert_UpbToRuby(val, self->value_type_info, self->arena); + } else { + return Qnil; + } +} + +/* + * ruby-doc: Map#[]= + * + * Inserts or overwrites the value at the given key with the given new value. + * Throws an exception if the key type is incorrect. Returns the new value that + * was just inserted. + * + * @param key [Object] + * @param value [Object] + * @return [Object] + */ +static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) { + Map* self = ruby_to_Map(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val_upb = + Convert_RubyToUpb(val, "", self->value_type_info, arena); + + upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena); + + return val; +} + +/* + * ruby-doc: Map#has_key? + * + * Returns true if the given key is present in the map. Throws an exception if + * the key has the wrong type. + * + * @param key [Object] + * @return [Boolean] + */ +static VALUE Map_has_key(VALUE _self, VALUE key) { + Map* self = ruby_to_Map(_self); + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + + if (upb_Map_Get(self->map, key_upb, NULL)) { + return Qtrue; + } else { + return Qfalse; + } +} + +/* + * ruby-doc: Map#delete + * + * Deletes the value at the given key, if any, returning either the old value or + * nil if none was present. Throws an exception if the key is of the wrong type. + * + * @param key [Object] + * @return [Object] + */ +static VALUE Map_delete(VALUE _self, VALUE key) { + upb_Map* map = Map_GetMutable(_self); + Map* self = ruby_to_Map(_self); + + upb_MessageValue key_upb = + Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL); + upb_MessageValue val_upb; + + if (upb_Map_Delete(map, key_upb, &val_upb)) { + return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena); + } else { + return Qnil; + } +} + +/* + * ruby-doc: Map#clear + * + * Removes all entries from the map. + * + * @return [nil] + */ +static VALUE Map_clear(VALUE _self) { + upb_Map_Clear(Map_GetMutable(_self)); + return Qnil; +} + +/* + * ruby-doc: Map#length + * + * Returns the number of entries (key-value pairs) in the map. + * + * @return [Integer] + */ +static VALUE Map_length(VALUE _self) { + Map* self = ruby_to_Map(_self); + return ULL2NUM(upb_Map_Size(self->map)); +} + +/* + * ruby-doc: Map#dup + * + * Duplicates this map with a shallow copy. References to all non-primitive + * element objects (e.g., submessages) are shared. + * + * @return [Map] + */ +static VALUE Map_dup(VALUE _self) { + Map* self = ruby_to_Map(_self); + VALUE new_map_rb = Map_new_this_type(self); + Map* new_self = ruby_to_Map(new_map_rb); + size_t iter = kUpb_Map_Begin; + upb_Arena* arena = Arena_get(new_self->arena); + upb_Map* new_map = Map_GetMutable(new_map_rb); + + Arena_fuse(self->arena, arena); + + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_Map_Set(new_map, key, val, arena); + } + + return new_map_rb; +} + +/* + * ruby-doc: Map#== + * + * Compares this map to another. Maps are equal if they have identical key sets, + * and for each key, the values in both maps compare equal. Elements are + * compared as per normal Ruby semantics, by calling their :== methods (or + * performing a more efficient comparison for primitive types). + * + * Maps with dissimilar key types or value types/typeclasses are never equal, + * even if value comparison (for example, between integers and floats) would + * have otherwise indicated that every element has equal value. + * + * @param other [Map] + * @return [Boolean] + */ +VALUE Map_eq(VALUE _self, VALUE _other) { + Map* self = ruby_to_Map(_self); + Map* other; + + // Allow comparisons to Ruby hashmaps by converting to a temporary Map + // instance. Slow, but workable. + if (TYPE(_other) == T_HASH) { + VALUE other_map = Map_new_this_type(self); + Map_merge_into_self(other_map, _other); + _other = other_map; + } + + other = ruby_to_Map(_other); + + if (self == other) { + return Qtrue; + } + if (self->key_type != other->key_type || + self->value_type_info.type != other->value_type_info.type || + self->value_type_class != other->value_type_class) { + return Qfalse; + } + if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) { + return Qfalse; + } + + // For each member of self, check that an equal member exists at the same key + // in other. + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + upb_MessageValue other_val; + if (!upb_Map_Get(other->map, key, &other_val)) { + // Not present in other map. + return Qfalse; + } + if (!Msgval_IsEqual(val, other_val, self->value_type_info)) { + // Present but different value. + return Qfalse; + } + } + + return Qtrue; +} + +/* + * ruby-doc: Map#frozen? + * + * Returns true if the map is frozen in either Ruby or the underlying + * representation. Freezes the Ruby map object if it is not already frozen in + * Ruby but it is frozen in the underlying representation. + * + * @return [Boolean] + */ +VALUE Map_frozen(VALUE _self) { + Map* self = ruby_to_Map(_self); + if (!upb_Map_IsFrozen(self->map)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * ruby-doc: Map#freeze + * + * Freezes the map object. We have to intercept this so we can freeze the + * underlying representation, not just the Ruby wrapper. + * + * @return [self] + */ +VALUE Map_freeze(VALUE _self) { + Map* self = ruby_to_Map(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Map_IsFrozen(self->map)); + return _self; + } + + if (!upb_Map_IsFrozen(self->map)) { + if (self->value_type_info.type == kUpb_CType_Message) { + upb_Map_Freeze( + Map_GetMutable(_self), + upb_MessageDef_MiniTable(self->value_type_info.def.msgdef)); + } else { + upb_Map_Freeze(Map_GetMutable(_self), NULL); + } + } + + RB_OBJ_FREEZE(_self); + + return _self; +} + +VALUE Map_EmptyFrozen(const upb_FieldDef* f) { + PBRUBY_ASSERT(upb_FieldDef_IsMap(f)); + VALUE val = ObjectCache_Get(f); + + if (val == Qnil) { + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + val = Map_alloc(cMap); + Map* self; + TypedData_Get_Struct(val, Map, &Map_type, self); + self->arena = Arena_new(); + self->map = + upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type); + self->key_type = key_type; + self->value_type_info = value_type_info; + if (self->value_type_info.type == kUpb_CType_Message) { + const upb_MessageDef* val_m = value_type_info.def.msgdef; + self->value_type_class = Descriptor_DefToClass(val_m); + } + return ObjectCache_TryAdd(f, Map_freeze(val)); + } + PBRUBY_ASSERT(RB_OBJ_FROZEN(val)); + PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map)); + return val; +} + +/* + * ruby-doc: Map#hash + * + * Returns a hash value based on this map's contents. + * + * @return [Integer] + */ +VALUE Map_hash(VALUE _self) { + Map* self = ruby_to_Map(_self); + uint64_t hash = 0; + + size_t iter = kUpb_Map_Begin; + TypeInfo key_info = {self->key_type}; + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { + hash += Msgval_GetHash(key, key_info, 0); + hash += Msgval_GetHash(val, self->value_type_info, 0); + } + + return LL2NUM(hash); +} + +/* + * ruby-doc: Map#to_h + * + * Returns a Ruby Hash object containing all the values within the map + * + * @return [Hash] + */ +VALUE Map_to_h(VALUE _self) { + Map* self = ruby_to_Map(_self); + return Map_CreateHash(self->map, self->key_type, self->value_type_info); +} + +/* + * ruby-doc: Map#inspect + * + * Returns a string representing this map's elements. It will be formatted as + * "{key => value, key => value, ...}", with each key and value string + * representation computed by its own #inspect method. + * + * @return [String] + */ +VALUE Map_inspect(VALUE _self) { + Map* self = ruby_to_Map(_self); + + StringBuilder* builder = StringBuilder_New(); + Map_Inspect(builder, self->map, self->key_type, self->value_type_info); + VALUE ret = StringBuilder_ToRubyString(builder); + StringBuilder_Free(builder); + return ret; +} + +/* + * ruby-doc: Map#merge + * + * Copies key/value pairs from other_map into a copy of this map. If a key is + * set in other_map and this map, the value from other_map overwrites the value + * in the new copy of this map. Returns the new copy of this map with merged + * contents. + * + * @param other_map [Map] + * @return [Map] + */ +static VALUE Map_merge(VALUE _self, VALUE hashmap) { + VALUE dupped = Map_dup(_self); + return Map_merge_into_self(dupped, hashmap); +} + +void Map_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "Map", rb_cObject); + rb_define_alloc_func(klass, Map_alloc); + rb_gc_register_address(&cMap); + cMap = klass; + + rb_define_method(klass, "initialize", Map_init, -1); + rb_define_method(klass, "each", Map_each, 0); + rb_define_method(klass, "keys", Map_keys, 0); + rb_define_method(klass, "values", Map_values, 0); + rb_define_method(klass, "[]", Map_index, 1); + rb_define_method(klass, "[]=", Map_index_set, 2); + rb_define_method(klass, "has_key?", Map_has_key, 1); + rb_define_method(klass, "delete", Map_delete, 1); + rb_define_method(klass, "clear", Map_clear, 0); + rb_define_method(klass, "length", Map_length, 0); + rb_define_method(klass, "size", Map_length, 0); + rb_define_method(klass, "dup", Map_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", Map_dup, 0); + rb_define_method(klass, "==", Map_eq, 1); + rb_define_method(klass, "freeze", Map_freeze, 0); + rb_define_method(klass, "frozen?", Map_frozen, 0); + rb_define_method(klass, "hash", Map_hash, 0); + rb_define_method(klass, "to_h", Map_to_h, 0); + rb_define_method(klass, "inspect", Map_inspect, 0); + rb_define_method(klass, "merge", Map_merge, 1); + rb_include_module(klass, rb_mEnumerable); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.h new file mode 100755 index 00000000..4527e5c5 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/map.h @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_MAP_H_ +#define RUBY_PROTOBUF_MAP_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Returns a frozen sentinel Ruby wrapper object for an empty upb_Map with the +// key and value types specified by the field. Creates one if it doesn't exist. +VALUE Map_EmptyFrozen(const upb_FieldDef* f); + +// Returns a Ruby wrapper object for the given map, which will be created if +// one does not exist already. +VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type, + TypeInfo value_type, VALUE arena); + +// Gets the underlying upb_Map for this Ruby map object, which must have +// key/value type that match |field|. If this is not a map or the type doesn't +// match, raises an exception. +const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field, + upb_Arena* arena); + +// Implements #inspect for this map by appending its contents to |b|. +void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type, + TypeInfo val_type); + +// Returns a new Hash object containing the contents of this Map. +VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type, TypeInfo val_info); + +// Returns a deep copy of this Map object. +VALUE Map_deep_copy(VALUE obj); + +// Ruby class of Google::Protobuf::Map. +extern VALUE cMap; + +// Call at startup to register all types in this module. +void Map_register(VALUE module); + +// Recursively freeze map +VALUE Map_freeze(VALUE _self); + +#endif // RUBY_PROTOBUF_MAP_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.c new file mode 100755 index 00000000..f2df05cd --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.c @@ -0,0 +1,1468 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "message.h" + +#include "convert.h" +#include "defs.h" +#include "map.h" +#include "protobuf.h" +#include "repeated_field.h" +#include "shared_message.h" + +static VALUE cParseError = Qnil; +static VALUE cAbstractMessage = Qnil; +static ID descriptor_instancevar_interned; + +static VALUE initialize_rb_class_with_no_args(VALUE klass) { + return rb_funcall(klass, rb_intern("new"), 0); +} + +VALUE MessageOrEnum_GetDescriptor(VALUE klass) { + return rb_ivar_get(klass, descriptor_instancevar_interned); +} + +// ----------------------------------------------------------------------------- +// Class/module creation from msgdefs and enumdefs, respectively. +// ----------------------------------------------------------------------------- + +typedef struct { + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE arena; + const upb_Message* msg; // Can get as mutable when non-frozen. + const upb_MessageDef* + msgdef; // kept alive by self.class.descriptor reference. +} Message; + +static void Message_mark(void* _self) { + Message* self = (Message*)_self; + rb_gc_mark(self->arena); +} + +static size_t Message_memsize(const void* _self) { return sizeof(Message); } + +static rb_data_type_t Message_type = { + "Google::Protobuf::Message", + {Message_mark, RUBY_DEFAULT_FREE, Message_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static Message* ruby_to_Message(VALUE msg_rb) { + Message* msg; + TypedData_Get_Struct(msg_rb, Message, &Message_type, msg); + return msg; +} + +static VALUE Message_alloc(VALUE klass) { + VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); + Message* msg = ALLOC(Message); + VALUE ret; + + msg->msgdef = Descriptor_GetMsgDef(descriptor); + msg->arena = Qnil; + msg->msg = NULL; + + ret = TypedData_Wrap_Struct(klass, &Message_type, msg); + rb_ivar_set(ret, descriptor_instancevar_interned, descriptor); + + return ret; +} + +const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) { + Message* msg = ruby_to_Message(msg_rb); + if (m) *m = msg->msgdef; + return msg->msg; +} + +upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) { + const upb_Message* upb_msg = Message_Get(msg_rb, m); + Protobuf_CheckNotFrozen(msg_rb, upb_Message_IsFrozen(upb_msg)); + return (upb_Message*)upb_msg; +} + +void Message_InitPtr(VALUE self_, const upb_Message* msg, VALUE arena) { + PBRUBY_ASSERT(arena != Qnil); + Message* self = ruby_to_Message(self_); + self->msg = msg; + RB_OBJ_WRITE(self_, &self->arena, arena); + VALUE stored = ObjectCache_TryAdd(msg, self_); + (void)stored; + PBRUBY_ASSERT(stored == self_); +} + +VALUE Message_GetArena(VALUE msg_rb) { + Message* msg = ruby_to_Message(msg_rb); + return msg->arena; +} + +void Message_CheckClass(VALUE klass) { + if (rb_get_alloc_func(klass) != &Message_alloc) { + rb_raise(rb_eArgError, + "Message class was not returned by the DescriptorPool."); + } +} + +VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m, + VALUE arena) { + if (msg == NULL) return Qnil; + + VALUE val = ObjectCache_Get(msg); + + if (val == Qnil) { + VALUE klass = Descriptor_DefToClass(m); + val = Message_alloc(klass); + Message_InitPtr(val, msg, arena); + } + return val; +} + +void Message_PrintMessage(StringBuilder* b, const upb_Message* msg, + const upb_MessageDef* m) { + bool first = true; + int n = upb_MessageDef_FieldCount(m); + VALUE klass = Descriptor_DefToClass(m); + StringBuilder_Printf(b, "<%s: ", rb_class2name(klass)); + + for (int i = 0; i < n; i++) { + const upb_FieldDef* field = upb_MessageDef_Field(m, i); + + if (upb_FieldDef_HasPresence(field) && + !upb_Message_HasFieldByDef(msg, field)) { + continue; + } + + if (!first) { + StringBuilder_Printf(b, ", "); + } else { + first = false; + } + + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, field); + + StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field)); + + if (upb_FieldDef_IsMap(field)) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + TypeInfo val_info = TypeInfo_get(val_f); + Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info); + } else if (upb_FieldDef_IsRepeated(field)) { + RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field)); + } else { + StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field)); + } + } + + StringBuilder_Printf(b, ">"); +} + +// Helper functions for #method_missing //////////////////////////////////////// + +enum { + METHOD_UNKNOWN = 0, + METHOD_GETTER = 1, + METHOD_SETTER = 2, + METHOD_CLEAR = 3, + METHOD_PRESENCE = 4, + METHOD_ENUM_GETTER = 5, + METHOD_WRAPPER_GETTER = 6, + METHOD_WRAPPER_SETTER = 7 +}; + +// Check if the field is a well known wrapper type +static bool IsWrapper(const upb_MessageDef* m) { + if (!m) return false; + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + return true; + default: + return false; + } +} + +static bool IsFieldWrapper(const upb_FieldDef* f) { + return IsWrapper(upb_FieldDef_MessageSubDef(f)); +} + +static bool Match(const upb_MessageDef* m, const char* name, + const upb_FieldDef** f, const upb_OneofDef** o, + const char* prefix, const char* suffix) { + size_t sp = strlen(prefix); + size_t ss = strlen(suffix); + size_t sn = strlen(name); + + if (sn <= sp + ss) return false; + + if (memcmp(name, prefix, sp) != 0 || + memcmp(name + sn - ss, suffix, ss) != 0) { + return false; + } + + return upb_MessageDef_FindByNameWithSize(m, name + sp, sn - sp - ss, f, o); +} + +static int extract_method_call(VALUE method_name, Message* self, + const upb_FieldDef** f, const upb_OneofDef** o) { + const upb_MessageDef* m = self->msgdef; + const char* name; + + Check_Type(method_name, T_SYMBOL); + name = rb_id2name(SYM2ID(method_name)); + + if (Match(m, name, f, o, "", "")) return METHOD_GETTER; + if (Match(m, name, f, o, "", "=")) return METHOD_SETTER; + if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR; + if (Match(m, name, f, o, "has_", "?") && + (*o || (*f && upb_FieldDef_HasPresence(*f)))) { + return METHOD_PRESENCE; + } + if (Match(m, name, f, o, "", "_as_value") && *f && + !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) { + return METHOD_WRAPPER_GETTER; + } + if (Match(m, name, f, o, "", "_as_value=") && *f && + !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) { + return METHOD_WRAPPER_SETTER; + } + if (Match(m, name, f, o, "", "_const") && *f && + upb_FieldDef_CType(*f) == kUpb_CType_Enum) { + return METHOD_ENUM_GETTER; + } + + return METHOD_UNKNOWN; +} + +static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o, + int accessor_type) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o); + + switch (accessor_type) { + case METHOD_PRESENCE: + return oneof_field == NULL ? Qfalse : Qtrue; + case METHOD_CLEAR: + if (oneof_field != NULL) { + upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), + oneof_field); + } + return Qnil; + case METHOD_GETTER: + return oneof_field == NULL + ? Qnil + : ID2SYM(rb_intern(upb_FieldDef_Name(oneof_field))); + case METHOD_SETTER: + rb_raise(rb_eRuntimeError, "Oneof accessors are read-only."); + } + rb_raise(rb_eRuntimeError, "Invalid access of oneof field."); +} + +static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val, + upb_Arena* arena) { + upb_MessageValue msgval; + if (upb_FieldDef_IsMap(f)) { + msgval.map_val = Map_GetUpbMap(val, f, arena); + } else if (upb_FieldDef_IsRepeated(f)) { + msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); + } else { + if (val == Qnil && + (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) { + upb_Message_ClearFieldByDef(msg, f); + return; + } + msgval = + Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + } + upb_Message_SetFieldByDef(msg, f, msgval, arena); +} + +VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f, + VALUE arena) { + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f); + if (upb_FieldDef_IsMap(f)) { + if (msgval.map_val == NULL) { + return Map_EmptyFrozen(f); + } + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + return Map_GetRubyWrapper(msgval.map_val, key_type, value_type_info, arena); + } + if (upb_FieldDef_IsRepeated(f)) { + if (msgval.array_val == NULL) { + return RepeatedField_EmptyFrozen(f); + } + return RepeatedField_GetRubyWrapper(msgval.array_val, TypeInfo_get(f), + arena); + } + VALUE ret; + if (upb_FieldDef_IsSubMessage(f)) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret = Message_GetRubyWrapper(msgval.msg_val, m, arena); + } else { + ret = Convert_UpbToRuby(msgval, TypeInfo_get(f), Qnil); + } + return ret; +} + +VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) { + Message* self = ruby_to_Message(_self); + if (upb_Message_IsFrozen(self->msg)) { + return Message_getfield_frozen(self->msg, f, self->arena); + } + upb_Message* msg = Message_GetMutable(_self, NULL); + upb_Arena* arena = Arena_get(self->arena); + if (upb_FieldDef_IsMap(f)) { + upb_Map* map = upb_Message_Mutable(msg, f, arena).map; + const upb_FieldDef* key_f = map_field_key(f); + const upb_FieldDef* val_f = map_field_value(f); + upb_CType key_type = upb_FieldDef_CType(key_f); + TypeInfo value_type_info = TypeInfo_get(val_f); + return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena); + } else if (upb_FieldDef_IsRepeated(f)) { + upb_Array* arr = upb_Message_Mutable(msg, f, arena).array; + return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena); + } else if (upb_FieldDef_IsSubMessage(f)) { + if (!upb_Message_HasFieldByDef(msg, f)) return Qnil; + upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg; + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + return Message_GetRubyWrapper(submsg, m, self->arena); + } else { + upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f); + return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena); + } +} + +static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f, + int accessor_type, int argc, VALUE* argv) { + upb_Arena* arena = Arena_get(Message_GetArena(_self)); + + switch (accessor_type) { + case METHOD_SETTER: + Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena); + return Qnil; + case METHOD_CLEAR: + upb_Message_ClearFieldByDef(Message_GetMutable(_self, NULL), f); + return Qnil; + case METHOD_PRESENCE: + if (!upb_FieldDef_HasPresence(f)) { + rb_raise(rb_eRuntimeError, "Field does not have presence."); + } + return upb_Message_HasFieldByDef(Message_Get(_self, NULL), f) ? Qtrue + : Qfalse; + case METHOD_WRAPPER_GETTER: { + Message* self = ruby_to_Message(_self); + if (upb_Message_HasFieldByDef(self->msg, f)) { + PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) && + !upb_FieldDef_IsRepeated(f)); + upb_MessageValue wrapper = upb_Message_GetFieldByDef(self->msg, f); + const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* value_f = + upb_MessageDef_FindFieldByNumber(wrapper_m, 1); + upb_MessageValue value = + upb_Message_GetFieldByDef(wrapper.msg_val, value_f); + return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena); + } else { + return Qnil; + } + } + case METHOD_WRAPPER_SETTER: { + upb_Message* msg = Message_GetMutable(_self, NULL); + if (argv[1] == Qnil) { + upb_Message_ClearFieldByDef(msg, f); + } else { + const upb_FieldDef* val_f = + upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1); + upb_MessageValue msgval = Convert_RubyToUpb( + argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena); + upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg; + upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena); + } + return Qnil; + } + case METHOD_ENUM_GETTER: { + upb_MessageValue msgval = + upb_Message_GetFieldByDef(Message_Get(_self, NULL), f); + + if (upb_FieldDef_IsRepeated(f)) { + // Map repeated fields to a new type with ints + VALUE arr = rb_ary_new(); + if (msgval.array_val == NULL) { + return arr; + } + size_t i, n = upb_Array_Size(msgval.array_val); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(msgval.array_val, i); + rb_ary_push(arr, INT2NUM(elem.int32_val)); + } + return arr; + } else { + return INT2NUM(msgval.int32_val); + } + } + case METHOD_GETTER: + return Message_getfield(_self, f); + default: + rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d", + accessor_type); + } +} + +/* + * ruby-doc: AbstractMessage + * + * The {AbstractMessage} class is the parent class for all Protobuf messages, + * and is generated from C code. + * + * For any field whose name does not conflict with a built-in method, an + * accessor is provided with the same name as the field, and a setter is + * provided with the name of the field plus the '=' suffix. Thus, given a + * message instance 'msg' with field 'foo', the following code is valid: + * + * msg.foo = 42 + * puts msg.foo + * + * This method also provides read-only accessors for oneofs. If a oneof exists + * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to + * the name of the field in that oneof that is currently set, or nil if none. + * + * It also provides methods of the form 'clear_fieldname' to clear the value + * of the field 'fieldname'. For basic data types, this will set the default + * value of the field. + * + * Additionally, it provides methods of the form 'has_fieldname?', which returns + * true if the field 'fieldname' is set in the message object, else false. For + * 'proto3' syntax, calling this for a basic type field will result in an error. + */ +static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + const upb_OneofDef* o; + const upb_FieldDef* f; + int accessor_type; + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected method name as first argument."); + } + + accessor_type = extract_method_call(argv[0], self, &f, &o); + + if (accessor_type == METHOD_UNKNOWN) return rb_call_super(argc, argv); + + // Validate argument count. + switch (accessor_type) { + case METHOD_SETTER: + case METHOD_WRAPPER_SETTER: + if (argc != 2) { + rb_raise(rb_eArgError, "Expected 2 arguments, received %d", argc); + } + break; + default: + if (argc != 1) { + rb_raise(rb_eArgError, "Expected 1 argument, received %d", argc); + } + break; + } + + // Dispatch accessor. + if (o != NULL) { + return Message_oneof_accessor(_self, o, accessor_type); + } else { + return Message_field_accessor(_self, f, accessor_type, argc, argv); + } +} + +static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + const upb_OneofDef* o; + const upb_FieldDef* f; + int accessor_type; + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected method name as first argument."); + } + + accessor_type = extract_method_call(argv[0], self, &f, &o); + + if (accessor_type == METHOD_UNKNOWN) { + return rb_call_super(argc, argv); + } else if (o != NULL) { + return accessor_type == METHOD_SETTER ? Qfalse : Qtrue; + } else { + return Qtrue; + } +} + +void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val, + upb_Arena* arena); + +typedef struct { + upb_Map* map; + TypeInfo key_type; + TypeInfo val_type; + upb_Arena* arena; +} MapInit; + +static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { + MapInit* map_init = (MapInit*)_self; + upb_MessageValue k, v; + k = Convert_RubyToUpb(key, "", map_init->key_type, NULL); + + if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) { + const upb_MiniTable* t = + upb_MessageDef_MiniTable(map_init->val_type.def.msgdef); + upb_Message* msg = upb_Message_New(t, map_init->arena); + Message_InitFromValue(msg, map_init->val_type.def.msgdef, val, + map_init->arena); + v.msg_val = msg; + } else { + v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena); + } + upb_Map_Set(map_init->map, k, v, map_init->arena); + return ST_CONTINUE; +} + +static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val, + upb_Arena* arena) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + if (TYPE(val) != T_HASH) { + rb_raise(rb_eArgError, + "Expected Hash object as initializer value for map field '%s' " + "(given %s).", + upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val))); + } + MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena}; + rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init); +} + +static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info, + upb_Arena* arena) { + if (info.type == kUpb_CType_Message) { + upb_MessageValue msgval; + const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef); + upb_Message* msg = upb_Message_New(t, arena); + Message_InitFromValue(msg, info.def.msgdef, val, arena); + msgval.msg_val = msg; + return msgval; + } else { + return Convert_RubyToUpb(val, "", info, arena); + } +} + +static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f, + VALUE val, upb_Arena* arena) { + TypeInfo type_info = TypeInfo_get(f); + + if (TYPE(val) != T_ARRAY) { + rb_raise(rb_eArgError, + "Expected array as initializer value for repeated field '%s' " + "(given %s).", + upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val))); + } + + for (int i = 0; i < RARRAY_LEN(val); i++) { + VALUE entry = rb_ary_entry(val, i); + upb_MessageValue msgval; + if (upb_FieldDef_IsSubMessage(f) && TYPE(entry) == T_HASH) { + msgval = MessageValue_FromValue(entry, type_info, arena); + } else { + msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena); + } + upb_Array_Append(arr, msgval, arena); + } +} + +static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f, + VALUE val, upb_Arena* arena) { + if (TYPE(val) == T_NIL) return; + + if (upb_FieldDef_IsMap(f)) { + upb_Map* map = upb_Message_Mutable(msg, f, arena).map; + Map_InitFromValue(map, f, val, arena); + } else if (upb_FieldDef_IsRepeated(f)) { + upb_Array* arr = upb_Message_Mutable(msg, f, arena).array; + RepeatedField_InitFromValue(arr, f, val, arena); + } else if (upb_FieldDef_IsSubMessage(f)) { + if (TYPE(val) == T_HASH) { + upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg; + Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena); + } else { + Message_setfield(msg, f, val, arena); + } + } else { + upb_MessageValue msgval = + Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + upb_Message_SetFieldByDef(msg, f, msgval, arena); + } +} + +typedef struct { + upb_Message* msg; + const upb_MessageDef* msgdef; + upb_Arena* arena; +} MsgInit; + +static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { + MsgInit* msg_init = (MsgInit*)_self; + const char* name; + + if (TYPE(key) == T_STRING) { + name = RSTRING_PTR(key); + } else if (TYPE(key) == T_SYMBOL) { + name = RSTRING_PTR(rb_id2str(SYM2ID(key))); + } else { + rb_raise(rb_eArgError, + "Expected string or symbols as hash keys when initializing proto " + "from hash."); + } + + const upb_FieldDef* f = + upb_MessageDef_FindFieldByName(msg_init->msgdef, name); + + if (f == NULL) { + rb_raise(rb_eArgError, + "Unknown field name '%s' in initialization map entry.", name); + } + + Message_InitFieldFromValue(msg_init->msg, f, val, msg_init->arena); + return ST_CONTINUE; +} + +void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val, + upb_Arena* arena) { + MsgInit msg_init = {msg, m, arena}; + if (TYPE(val) == T_HASH) { + rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init); + } else { + rb_raise(rb_eArgError, "Expected hash arguments or message, not %s", + rb_class2name(CLASS_OF(val))); + } +} + +/* + * ruby-doc: AbstractMessage#initialize + * + * Creates a new instance of the given message class. Keyword arguments may be + * provided with keywords corresponding to field names. + * + * @param kwargs the list of field keys and values. + */ +static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) { + Message* self = ruby_to_Message(_self); + VALUE arena_rb = Arena_new(); + upb_Arena* arena = Arena_get(arena_rb); + const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef); + upb_Message* msg = upb_Message_New(t, arena); + + Message_InitPtr(_self, msg, arena_rb); + + if (argc == 0) { + return Qnil; + } + if (argc != 1) { + rb_raise(rb_eArgError, "Expected 0 or 1 arguments."); + } + Message_InitFromValue((upb_Message*)self->msg, self->msgdef, argv[0], arena); + return Qnil; +} + +/* + * ruby-doc: AbstractMessage#dup + * + * Performs a shallow copy of this message and returns the new copy. + * + * @return [AbstractMessage] + */ +static VALUE Message_dup(VALUE _self) { + Message* self = ruby_to_Message(_self); + VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self)); + Message* new_msg_self = ruby_to_Message(new_msg); + const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef); + if (!upb_Message_ShallowCopy((upb_Message*)new_msg_self->msg, self->msg, m, + Arena_get(new_msg_self->arena))) { + rb_raise(rb_eRuntimeError, "Failed to shallow copy message."); + } + Arena_fuse(self->arena, Arena_get(new_msg_self->arena)); + return new_msg; +} + +/* + * ruby-doc: AbstractMessage#== + * + * Performs a deep comparison of this message with another. Messages are equal + * if they have the same type and if each field is equal according to the :== + * method's semantics (a more efficient comparison may actually be done if the + * field is of a primitive type). + * + * @param other [AbstractMessage] + * @return [Boolean] + */ +static VALUE Message_eq(VALUE _self, VALUE _other) { + if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse; + + Message* self = ruby_to_Message(_self); + Message* other = ruby_to_Message(_other); + assert(self->msgdef == other->msgdef); + + const upb_MiniTable* m = upb_MessageDef_MiniTable(self->msgdef); + const int options = 0; + return upb_Message_IsEqual(self->msg, other->msg, m, options) ? Qtrue + : Qfalse; +} + +uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed) { + upb_Status status; + upb_Status_Clear(&status); + uint64_t return_value = shared_Message_Hash(msg, m, seed, &status); + if (upb_Status_IsOk(&status)) { + return return_value; + } else { + rb_raise(cParseError, "Message_Hash(): %s", + upb_Status_ErrorMessage(&status)); + } +} + +/* + * ruby-doc: AbstractMessage#hash + * + * Returns a hash value that represents this message's field values. + * + * @return [Integer] + */ +static VALUE Message_hash(VALUE _self) { + Message* self = ruby_to_Message(_self); + uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0); + // RUBY_FIXNUM_MAX should be one less than a power of 2. + assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0); + return INT2FIX(hash_value & RUBY_FIXNUM_MAX); +} + +/* + * ruby-doc: AbstractMessage#inspect + * + * Returns a human-readable string representing this message. It will be + * formatted as "". Each + * field's value is represented according to its own #inspect method. + * + * @return [String] + */ +static VALUE Message_inspect(VALUE _self) { + Message* self = ruby_to_Message(_self); + + StringBuilder* builder = StringBuilder_New(); + Message_PrintMessage(builder, self->msg, self->msgdef); + VALUE ret = StringBuilder_ToRubyString(builder); + StringBuilder_Free(builder); + return ret; +} + +// Support functions for Message_to_h ////////////////////////////////////////// + +static VALUE RepeatedField_CreateArray(const upb_Array* arr, + TypeInfo type_info) { + int size = arr ? upb_Array_Size(arr) : 0; + VALUE ary = rb_ary_new2(size); + + for (int i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(arr, i); + VALUE val = Scalar_CreateHash(msgval, type_info); + rb_ary_push(ary, val); + } + + return ary; +} + +static VALUE Message_CreateHash(const upb_Message* msg, + const upb_MessageDef* m) { + if (!msg) return Qnil; + + VALUE hash = rb_hash_new(); + size_t iter = kUpb_Message_Begin; + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m)); + const upb_FieldDef* field; + upb_MessageValue val; + + while (upb_Message_Next(msg, m, pool, &field, &val, &iter)) { + if (upb_FieldDef_IsExtension(field)) { + // TODO: allow extensions once we have decided what naming scheme the + // symbol should use. eg. :"[pkg.ext]" + continue; + } + + TypeInfo type_info = TypeInfo_get(field); + VALUE msg_value; + + if (upb_FieldDef_IsMap(field)) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + upb_CType key_type = upb_FieldDef_CType(key_f); + msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f)); + } else if (upb_FieldDef_IsRepeated(field)) { + msg_value = RepeatedField_CreateArray(val.array_val, type_info); + } else { + msg_value = Scalar_CreateHash(val, type_info); + } + + VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field))); + rb_hash_aset(hash, msg_key, msg_value); + } + + return hash; +} + +VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) { + if (type_info.type == kUpb_CType_Message) { + return Message_CreateHash(msgval.msg_val, type_info.def.msgdef); + } else { + return Convert_UpbToRuby(msgval, type_info, Qnil); + } +} + +/* + * ruby-doc: AbstractMessage#to_h + * + * Returns the message as a Ruby Hash object, with keys as symbols. + * + * @return [Hash] + */ +static VALUE Message_to_h(VALUE _self) { + Message* self = ruby_to_Message(_self); + return Message_CreateHash(self->msg, self->msgdef); +} + +/* + * ruby-doc: AbstractMessage#frozen? + * + * Returns true if the message is frozen in either Ruby or the underlying + * representation. Freezes the Ruby message object if it is not already frozen + * in Ruby but it is frozen in the underlying representation. + * + * @return [Boolean] + */ +VALUE Message_frozen(VALUE _self) { + Message* self = ruby_to_Message(_self); + if (!upb_Message_IsFrozen(self->msg)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * ruby-doc: AbstractMessage#freeze + * + * Freezes the message object. We have to intercept this so we can freeze the + * underlying representation, not just the Ruby wrapper. + * + * @return [self] + */ +VALUE Message_freeze(VALUE _self) { + Message* self = ruby_to_Message(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Message_IsFrozen(self->msg)); + return _self; + } + if (!upb_Message_IsFrozen(self->msg)) { + upb_Message_Freeze(Message_GetMutable(_self, NULL), + upb_MessageDef_MiniTable(self->msgdef)); + } + RB_OBJ_FREEZE(_self); + return _self; +} + +/* + * ruby-doc: AbstractMessage#[] + * + * Accesses a field's value by field name. The provided field name should be a + * string. + * + * @param index [Integer] + * @return [Object] + */ +static VALUE Message_index(VALUE _self, VALUE field_name) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* field; + + Check_Type(field_name, T_STRING); + field = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name)); + + if (field == NULL) { + return Qnil; + } + + return Message_getfield(_self, field); +} + +/* + * ruby-doc: AbstractMessage#[]= + * + * Sets a field's value by field name. The provided field name should be a + * string. + * + * @param index [Integer] + * @param value [Object] + * @return [nil] + */ +static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) { + Message* self = ruby_to_Message(_self); + const upb_FieldDef* f; + upb_MessageValue val; + upb_Arena* arena = Arena_get(self->arena); + + Check_Type(field_name, T_STRING); + f = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name)); + + if (f == NULL) { + rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name)); + } + + val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena); + upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena); + + return Qnil; +} + +/* + * ruby-doc: AbstractMessage.decode + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretation given by this message class's definition + * and returns a message object with the corresponding field values. + * @param data [String] + * @param options [Hash] + * @option recursion_limit [Integer] set to maximum decoding depth for message + * (default is 64) + * @return [AbstractMessage] + */ +static VALUE Message_decode(int argc, VALUE* argv, VALUE klass) { + VALUE data = argv[0]; + int options = 0; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + + if (depth != Qnil && TYPE(depth) == T_FIXNUM) { + options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth)); + } + } + + if (TYPE(data) != T_STRING) { + rb_raise(rb_eArgError, "Expected string for binary protobuf data."); + } + + return Message_decode_bytes(RSTRING_LEN(data), RSTRING_PTR(data), options, + klass, /*freeze*/ false); +} + +VALUE Message_decode_bytes(size_t size, const char* bytes, int options, + VALUE klass, bool freeze) { + VALUE msg_rb = initialize_rb_class_with_no_args(klass); + Message* msg = ruby_to_Message(msg_rb); + + const upb_FileDef* file = upb_MessageDef_File(msg->msgdef); + const upb_ExtensionRegistry* extreg = + upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file)); + upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg, + upb_MessageDef_MiniTable(msg->msgdef), + extreg, options, Arena_get(msg->arena)); + if (status != kUpb_DecodeStatus_Ok) { + rb_raise(cParseError, "Error occurred during parsing"); + } + if (freeze) { + Message_freeze(msg_rb); + } + return msg_rb; +} + +/* + * ruby-doc: AbstractMessage.decode_json + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretration given by this message class's definition + * and returns a message object with the corresponding field values. + * + * @param data [String] + * @param options [Hash] + * @option ignore_unknown_fields [Boolean] set true to ignore unknown fields + * (default is to raise an error) + * @return [AbstractMessage] + */ +static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) { + VALUE data = argv[0]; + int options = 0; + upb_Status status; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + + if (RTEST(rb_hash_lookup2( + hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) { + options |= upb_JsonDecode_IgnoreUnknown; + } + } + + if (TYPE(data) != T_STRING) { + rb_raise(rb_eArgError, "Expected string for JSON data."); + } + + // TODO: Check and respect string encoding. If not UTF-8, we need to + // convert, because string handlers pass data directly to message string + // fields. + + VALUE msg_rb = initialize_rb_class_with_no_args(klass); + Message* msg = ruby_to_Message(msg_rb); + + // We don't allow users to decode a wrapper type directly. + if (IsWrapper(msg->msgdef)) { + rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly."); + } + + upb_Status_Clear(&status); + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef)); + + int result = upb_JsonDecodeDetectingNonconformance( + RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg, msg->msgdef, + pool, options, Arena_get(msg->arena), &status); + + switch (result) { + case kUpb_JsonDecodeResult_Ok: + break; + case kUpb_JsonDecodeResult_Error: + rb_raise(cParseError, "Error occurred during parsing: %s", + upb_Status_ErrorMessage(&status)); + break; + } + + return msg_rb; +} + +/* + * ruby-doc: AbstractMessage.encode + * + * Encodes the given message object to its serialized form in protocol buffers + * wire format. + * + * @param msg [AbstractMessage] + * @param options [Hash] + * @option recursion_limit [Integer] set to maximum encoding depth for message + * (default is 64) + * @return [String] + */ +static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) { + Message* msg = ruby_to_Message(argv[0]); + int options = 0; + char* data; + size_t size; + + if (CLASS_OF(argv[0]) != klass) { + rb_raise(rb_eArgError, "Message of wrong type."); + } + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + VALUE depth = + rb_hash_lookup(hash_args, ID2SYM(rb_intern("recursion_limit"))); + + if (depth != Qnil && TYPE(depth) == T_FIXNUM) { + options |= upb_DecodeOptions_MaxDepth(FIX2INT(depth)); + } + } + + upb_Arena* arena = upb_Arena_New(); + + upb_EncodeStatus status = + upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options, + arena, &data, &size); + + if (status == kUpb_EncodeStatus_Ok) { + VALUE ret = rb_str_new(data, size); + rb_enc_associate(ret, rb_ascii8bit_encoding()); + upb_Arena_Free(arena); + return ret; + } else { + upb_Arena_Free(arena); + rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)"); + } +} + +/* + * ruby-doc: AbstractMessage.encode_json + * + * Encodes the given message object into its serialized JSON representation. + * + * @param msg [AbstractMessage] + * @param options [Hash] + * @option preserve_proto_fieldnames [Boolean] set true to use original + * fieldnames (default is to camelCase) + * @option emit_defaults [Boolean] set true to emit 0/false values (default is + * to omit them) + * @return [String] + */ +static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { + Message* msg = ruby_to_Message(argv[0]); + int options = 0; + char buf[1024]; + size_t size; + upb_Status status; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + if (RTEST(rb_funcall(hash_args, rb_intern("respond_to?"), 1, + rb_str_new2("to_h")))) { + hash_args = rb_funcall(hash_args, rb_intern("to_h"), 0); + } else { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + } + + if (RTEST(rb_hash_lookup2(hash_args, + ID2SYM(rb_intern("preserve_proto_fieldnames")), + Qfalse))) { + options |= upb_JsonEncode_UseProtoNames; + } + + if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")), + Qfalse))) { + options |= upb_JsonEncode_EmitDefaults; + } + + if (RTEST(rb_hash_lookup2(hash_args, + ID2SYM(rb_intern("format_enums_as_integers")), + Qfalse))) { + options |= upb_JsonEncode_FormatEnumsAsIntegers; + } + } + + upb_Status_Clear(&status); + const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(msg->msgdef)); + size = upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf, sizeof(buf), + &status); + + if (!upb_Status_IsOk(&status)) { + rb_raise(cParseError, "Error occurred during encoding: %s", + upb_Status_ErrorMessage(&status)); + } + + VALUE ret; + if (size >= sizeof(buf)) { + char* buf2 = malloc(size + 1); + upb_JsonEncode(msg->msg, msg->msgdef, pool, options, buf2, size + 1, + &status); + ret = rb_str_new(buf2, size); + free(buf2); + } else { + ret = rb_str_new(buf, size); + } + + rb_enc_associate(ret, rb_utf8_encoding()); + return ret; +} + +/* + * ruby-doc: AbstractMessage.descriptor + * + * Class method that returns the Descriptor instance corresponding to this + * message class's type. + * + * @return [Descriptor] + */ +static VALUE Message_descriptor(VALUE klass) { + return rb_ivar_get(klass, descriptor_instancevar_interned); +} + +VALUE build_class_from_descriptor(VALUE descriptor) { + const char* name; + VALUE klass; + + name = upb_MessageDef_FullName(Descriptor_GetMsgDef(descriptor)); + if (name == NULL) { + rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name."); + } + + klass = rb_define_class_id( + // Docs say this parameter is ignored. User will assign return value to + // their own toplevel constant class name. + rb_intern("Message"), cAbstractMessage); + rb_ivar_set(klass, descriptor_instancevar_interned, descriptor); + return klass; +} + +/* ruby-doc: Enum + * + * There isn't really a concrete `Enum` module generated by Protobuf. Instead, + * you can use this documentation as an indicator of methods that are defined on + * each `Enum` module that is generated. E.g. if you have: + * + * enum my_enum_type + * + * in your Proto file and generate Ruby code, a module + * called `MyEnumType` will be generated with the following methods available. + */ + +/* + * ruby-doc: Enum.lookup + * + * This module method, provided on each generated enum module, looks up an enum + * value by number and returns its name as a Ruby symbol, or nil if not found. + * + * @param number [Integer] + * @return [String] + */ +static VALUE enum_lookup(VALUE self, VALUE number) { + int32_t num = NUM2INT(number); + VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc); + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, num); + if (ev) { + return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev))); + } else { + return Qnil; + } +} + +/* + * ruby-doc: Enum.resolve + * + * This module method, provided on each generated enum module, looks up an enum + * value by name (as a Ruby symbol) and returns its name, or nil if not found. + * + * @param name [String] + * @return [Integer] + */ +static VALUE enum_resolve(VALUE self, VALUE sym) { + const char* name = rb_id2name(SYM2ID(sym)); + VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned); + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc); + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByName(e, name); + if (ev) { + return INT2NUM(upb_EnumValueDef_Number(ev)); + } else { + return Qnil; + } +} + +/* + * ruby-doc: Enum.descriptor + * + * This module method, provided on each generated enum module, returns the + * {EnumDescriptor} corresponding to this enum type. + * + * @return [EnumDescriptor] + * + */ +static VALUE enum_descriptor(VALUE self) { + return rb_ivar_get(self, descriptor_instancevar_interned); +} + +VALUE build_module_from_enumdesc(VALUE _enumdesc) { + const upb_EnumDef* e = EnumDescriptor_GetEnumDef(_enumdesc); + VALUE mod = rb_define_module_id(rb_intern(upb_EnumDef_FullName(e))); + + int n = upb_EnumDef_ValueCount(e); + for (int i = 0; i < n; i++) { + const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i); + upb_Arena* arena = upb_Arena_New(); + const char* src_name = upb_EnumValueDef_Name(ev); + char* name = upb_strdup2(src_name, strlen(src_name), arena); + int32_t value = upb_EnumValueDef_Number(ev); + if (name[0] < 'A' || name[0] > 'Z') { + if (name[0] >= 'a' && name[0] <= 'z') { + name[0] -= 32; // auto capitalize + } else { + rb_warn( + "Enum value '%s' does not start with an uppercase letter " + "as is required for Ruby constants.", + name); + } + } + rb_define_const(mod, name, INT2NUM(value)); + upb_Arena_Free(arena); + } + + rb_define_singleton_method(mod, "lookup", enum_lookup, 1); + rb_define_singleton_method(mod, "resolve", enum_resolve, 1); + rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0); + rb_ivar_set(mod, descriptor_instancevar_interned, _enumdesc); + + return mod; +} + +// Internal to the library; used by Google::Protobuf.deep_copy. +upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m, + upb_Arena* arena) { + // Serialize and parse. + upb_Arena* tmp_arena = upb_Arena_New(); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + size_t size; + + upb_Message* new_msg = upb_Message_New(layout, arena); + char* data; + + const upb_FileDef* file = upb_MessageDef_File(m); + const upb_ExtensionRegistry* extreg = + upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file)); + if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) != + kUpb_EncodeStatus_Ok || + upb_Decode(data, size, new_msg, layout, extreg, 0, arena) != + kUpb_DecodeStatus_Ok) { + upb_Arena_Free(tmp_arena); + rb_raise(cParseError, "Error occurred copying proto"); + } + + upb_Arena_Free(tmp_arena); + return new_msg; +} + +const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, + const char* name, upb_Arena* arena) { + if (value == Qnil) { + rb_raise(cTypeError, "nil message not allowed here."); + } + + VALUE klass = CLASS_OF(value); + VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned); + const upb_MessageDef* val_m = + desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb); + + if (val_m != m) { + // Check for possible implicit conversions + // TODO: hash conversion? + + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Timestamp: { + // Time -> Google::Protobuf::Timestamp + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(t, arena); + upb_MessageValue sec, nsec; + struct timespec time; + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); + + if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype; + + time = rb_time_timespec(value); + sec.int64_val = time.tv_sec; + nsec.int32_val = time.tv_nsec; + upb_Message_SetFieldByDef(msg, sec_f, sec, arena); + upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena); + return msg; + } + case kUpb_WellKnown_Duration: { + // Numeric -> Google::Protobuf::Duration + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(t, arena); + upb_MessageValue sec, nsec; + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); + + if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype; + + sec.int64_val = NUM2LL(value); + nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000); + upb_Message_SetFieldByDef(msg, sec_f, sec, arena); + upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena); + return msg; + } + default: + badtype: + rb_raise(cTypeError, + "Invalid type %s to assign to submessage field '%s'.", + rb_class2name(CLASS_OF(value)), name); + } + } + + Message* self = ruby_to_Message(value); + Arena_fuse(self->arena, arena); + + return self->msg; +} + +static void Message_define_class(VALUE klass) { + rb_define_alloc_func(klass, Message_alloc); + + rb_require("google/protobuf/message_exts"); + rb_define_method(klass, "method_missing", Message_method_missing, -1); + rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing, + -1); + rb_define_method(klass, "initialize", Message_initialize, -1); + rb_define_method(klass, "dup", Message_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", Message_dup, 0); + rb_define_method(klass, "==", Message_eq, 1); + rb_define_method(klass, "eql?", Message_eq, 1); + rb_define_method(klass, "freeze", Message_freeze, 0); + rb_define_method(klass, "frozen?", Message_frozen, 0); + rb_define_method(klass, "hash", Message_hash, 0); + rb_define_method(klass, "to_h", Message_to_h, 0); + rb_define_method(klass, "inspect", Message_inspect, 0); + rb_define_method(klass, "to_s", Message_inspect, 0); + rb_define_method(klass, "[]", Message_index, 1); + rb_define_method(klass, "[]=", Message_index_set, 2); + rb_define_singleton_method(klass, "decode", Message_decode, -1); + rb_define_singleton_method(klass, "encode", Message_encode, -1); + rb_define_singleton_method(klass, "decode_json", Message_decode_json, -1); + rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1); + rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0); +} + +void Message_register(VALUE protobuf) { + cParseError = rb_const_get(protobuf, rb_intern("ParseError")); + cAbstractMessage = + rb_define_class_under(protobuf, "AbstractMessage", rb_cObject); + Message_define_class(cAbstractMessage); + rb_gc_register_address(&cAbstractMessage); + + // Ruby-interned string: "descriptor". We use this identifier to store an + // instance variable on message classes we create in order to link them back + // to their descriptors. + descriptor_instancevar_interned = rb_intern("@descriptor"); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.h new file mode 100755 index 00000000..1b37db5a --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/message.h @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_MESSAGE_H_ +#define RUBY_PROTOBUF_MESSAGE_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Gets the underlying upb_Message* and upb_MessageDef for the given Ruby +// message wrapper. Requires that |value| is indeed a message object. +const upb_Message* Message_Get(VALUE value, const upb_MessageDef** m); + +// Like Message_Get(), but checks that the object is not frozen and returns a +// mutable pointer. +upb_Message* Message_GetMutable(VALUE value, const upb_MessageDef** m); + +// Returns the Arena object for this message. +VALUE Message_GetArena(VALUE value); + +// Converts |value| into a upb_Message value of the expected upb_MessageDef +// type, raising an error if this is not possible. Used when assigning |value| +// to a field of another message, which means the message must be of a +// particular type. +// +// This will perform automatic conversions in some cases (for example, Time -> +// Google::Protobuf::Timestamp). If any new message is created, it will be +// created on |arena|, and any existing message will have its arena fused with +// |arena|. +const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, + const char* name, upb_Arena* arena); + +// Gets or constructs a Ruby wrapper object for the given message. The wrapper +// object will reference |arena| and ensure that it outlives this object. +VALUE Message_GetRubyWrapper(const upb_Message* msg, const upb_MessageDef* m, + VALUE arena); + +// Gets the given field from this message. +VALUE Message_getfield(VALUE _self, const upb_FieldDef* f); + +// Implements #inspect for this message, printing the text to |b|. +void Message_PrintMessage(StringBuilder* b, const upb_Message* msg, + const upb_MessageDef* m); + +// Returns a hash value for the given message. +uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed); + +// Returns a deep copy of the given message. +upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m, + upb_Arena* arena); + +// Checks that this Ruby object is a message, and raises an exception if not. +void Message_CheckClass(VALUE klass); + +// Returns a new Hash object containing the contents of this message. +VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info); + +// Creates a message class or enum module for this descriptor, respectively. +VALUE build_class_from_descriptor(VALUE descriptor); +VALUE build_module_from_enumdesc(VALUE _enumdesc); + +// Returns the Descriptor/EnumDescriptor for the given message class or enum +// module, respectively. Returns nil if this is not a message class or enum +// module. +VALUE MessageOrEnum_GetDescriptor(VALUE klass); + +// Decodes a Message from a byte sequence. +VALUE Message_decode_bytes(size_t size, const char* bytes, int options, + VALUE klass, bool freeze); + +// Recursively freeze message +VALUE Message_freeze(VALUE _self); + +// Call at startup to register all types in this module. +void Message_register(VALUE protobuf); + +#endif // RUBY_PROTOBUF_MESSAGE_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.c new file mode 100755 index 00000000..530a22e0 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.c @@ -0,0 +1,357 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "protobuf.h" + +#include "defs.h" +#include "map.h" +#include "message.h" +#include "repeated_field.h" + +VALUE cParseError; +VALUE cTypeError; + +const upb_FieldDef* map_field_key(const upb_FieldDef* field) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(field); + return upb_MessageDef_FindFieldByNumber(entry, 1); +} + +const upb_FieldDef* map_field_value(const upb_FieldDef* field) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(field); + return upb_MessageDef_FindFieldByNumber(entry, 2); +} + +// ----------------------------------------------------------------------------- +// StringBuilder, for inspect +// ----------------------------------------------------------------------------- + +struct StringBuilder { + size_t size; + size_t cap; + char* data; +}; + +typedef struct StringBuilder StringBuilder; + +static size_t StringBuilder_SizeOf(size_t cap) { + return sizeof(StringBuilder) + cap; +} + +StringBuilder* StringBuilder_New() { + const size_t cap = 128; + StringBuilder* builder = malloc(sizeof(*builder)); + builder->size = 0; + builder->cap = cap; + builder->data = malloc(builder->cap); + return builder; +} + +void StringBuilder_Free(StringBuilder* b) { + free(b->data); + free(b); +} + +void StringBuilder_Printf(StringBuilder* b, const char* fmt, ...) { + size_t have = b->cap - b->size; + size_t n; + va_list args; + + va_start(args, fmt); + n = vsnprintf(&b->data[b->size], have, fmt, args); + va_end(args); + + if (have <= n) { + while (have <= n) { + b->cap *= 2; + have = b->cap - b->size; + } + b->data = realloc(b->data, StringBuilder_SizeOf(b->cap)); + va_start(args, fmt); + n = vsnprintf(&b->data[b->size], have, fmt, args); + va_end(args); + PBRUBY_ASSERT(n < have); + } + + b->size += n; +} + +VALUE StringBuilder_ToRubyString(StringBuilder* b) { + VALUE ret = rb_str_new(b->data, b->size); + rb_enc_associate(ret, rb_utf8_encoding()); + return ret; +} + +static void StringBuilder_PrintEnum(StringBuilder* b, int32_t val, + const upb_EnumDef* e) { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, val); + if (ev) { + StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev)); + } else { + StringBuilder_Printf(b, "%" PRId32, val); + } +} + +void StringBuilder_PrintMsgval(StringBuilder* b, upb_MessageValue val, + TypeInfo info) { + switch (info.type) { + case kUpb_CType_Bool: + StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: { + VALUE str = rb_inspect(DBL2NUM(val.float_val)); + StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); + break; + } + case kUpb_CType_Double: { + VALUE str = rb_inspect(DBL2NUM(val.double_val)); + StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); + break; + } + case kUpb_CType_Int32: + StringBuilder_Printf(b, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + StringBuilder_Printf(b, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + StringBuilder_Printf(b, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + StringBuilder_Printf(b, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, + val.str_val.data); + break; + case kUpb_CType_Bytes: + StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, + val.str_val.data); + break; + case kUpb_CType_Enum: + StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef); + break; + case kUpb_CType_Message: + Message_PrintMessage(b, val.msg_val, info.def.msgdef); + break; + } +} + +// ----------------------------------------------------------------------------- +// Arena +// ----------------------------------------------------------------------------- + +typedef struct { + upb_Arena* arena; + // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() + // macro to update VALUE references, as to trigger write barriers. + VALUE pinned_objs; +} Arena; + +static void Arena_mark(void* data) { + Arena* arena = data; + rb_gc_mark(arena->pinned_objs); +} + +static void Arena_free(void* data) { + Arena* arena = data; + upb_Arena_Free(arena->arena); + xfree(arena); +} + +static size_t Arena_memsize(const void* data) { + const Arena* arena = data; + size_t fused_count; + size_t memsize = upb_Arena_SpaceAllocated(arena->arena, &fused_count); + if (fused_count > 1) { + // If other arena were fused we attribute an equal + // share of memory usage to each one. + memsize /= fused_count; + } + return memsize + sizeof(Arena); +} + +static VALUE cArena; + +const rb_data_type_t Arena_type = { + "Google::Protobuf::Internal::Arena", + {Arena_mark, Arena_free, Arena_memsize}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size, size_t* actual_size) { + if (size == 0) { + xfree(ptr); + return NULL; + } else { + return xrealloc(ptr, size); + } +} + +upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc}; + +static VALUE Arena_alloc(VALUE klass) { + Arena* arena = ALLOC(Arena); + arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc); + arena->pinned_objs = Qnil; + return TypedData_Wrap_Struct(klass, &Arena_type, arena); +} + +upb_Arena* Arena_get(VALUE _arena) { + Arena* arena; + TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); + return arena->arena; +} + +void Arena_fuse(VALUE _arena, upb_Arena* other) { + Arena* arena; + TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); + if (!upb_Arena_Fuse(arena->arena, other)) { + rb_raise(rb_eRuntimeError, + "Unable to fuse arenas. This should never happen since Ruby does " + "not use initial blocks"); + } +} + +VALUE Arena_new() { return Arena_alloc(cArena); } + +void Arena_register(VALUE module) { + VALUE internal = rb_define_module_under(module, "Internal"); + VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject); + rb_define_alloc_func(klass, Arena_alloc); + rb_gc_register_address(&cArena); + cArena = klass; +} + +// ----------------------------------------------------------------------------- +// Object Cache +// ----------------------------------------------------------------------------- + +// Public ObjectCache API. + +VALUE weak_obj_cache = Qnil; +ID item_get; +ID item_try_add; + +static void ObjectCache_Init(VALUE protobuf) { + item_get = rb_intern("get"); + item_try_add = rb_intern("try_add"); + + rb_gc_register_address(&weak_obj_cache); + VALUE internal = rb_const_get(protobuf, rb_intern("Internal")); +#if SIZEOF_LONG >= SIZEOF_VALUE + VALUE cache_class = rb_const_get(internal, rb_intern("ObjectCache")); +#else + VALUE cache_class = rb_const_get(internal, rb_intern("LegacyObjectCache")); +#endif + + weak_obj_cache = rb_class_new_instance(0, NULL, cache_class); + rb_const_set(internal, rb_intern("OBJECT_CACHE"), weak_obj_cache); + rb_const_set(internal, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG)); + rb_const_set(internal, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE)); +} + +static VALUE ObjectCache_GetKey(const void* key) { + VALUE key_val = (VALUE)key; + PBRUBY_ASSERT((key_val & 3) == 0); + // Ensure the key can be stored as a Fixnum since 1 bit is needed for + // FIXNUM_FLAG and 1 bit is needed for the sign bit. + VALUE new_key = LL2NUM(key_val >> 2); + PBRUBY_ASSERT(FIXNUM_P(new_key)); + return new_key; +} + +VALUE ObjectCache_TryAdd(const void* key, VALUE val) { + VALUE key_val = ObjectCache_GetKey(key); + return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val); +} + +// Returns the cached object for this key, if any. Otherwise returns Qnil. +VALUE ObjectCache_Get(const void* key) { + VALUE key_val = ObjectCache_GetKey(key); + return rb_funcall(weak_obj_cache, item_get, 1, key_val); +} + +/* + * call-seq: + * Google::Protobuf.discard_unknown(msg) + * + * Discard unknown fields in the given message object and recursively discard + * unknown fields in submessages. + */ +static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) { + const upb_MessageDef* m; + upb_Message* msg = Message_GetMutable(msg_rb, &m); + const upb_DefPool* ext_pool = upb_FileDef_Pool(upb_MessageDef_File(m)); + if (!upb_Message_DiscardUnknown(msg, m, ext_pool, 128)) { + rb_raise(rb_eRuntimeError, "Messages nested too deeply."); + } + + return Qnil; +} + +/* + * call-seq: + * Google::Protobuf.deep_copy(obj) => copy_of_obj + * + * Performs a deep copy of a RepeatedField instance, a Map instance, or a + * message object, recursively copying its members. + */ +VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) { + VALUE klass = CLASS_OF(obj); + if (klass == cRepeatedField) { + return RepeatedField_deep_copy(obj); + } else if (klass == cMap) { + return Map_deep_copy(obj); + } else { + VALUE new_arena_rb = Arena_new(); + upb_Arena* new_arena = Arena_get(new_arena_rb); + const upb_MessageDef* m; + const upb_Message* msg = Message_Get(obj, &m); + upb_Message* new_msg = Message_deep_copy(msg, m, new_arena); + return Message_GetRubyWrapper(new_msg, m, new_arena_rb); + } +} + +// ----------------------------------------------------------------------------- +// Initialization/entry point. +// ----------------------------------------------------------------------------- + +// This must be named "Init_protobuf_c" because the Ruby module is named +// "protobuf_c" -- the VM looks for this symbol in our .so. +__attribute__((visibility("default"))) void Init_protobuf_c() { + VALUE google = rb_define_module("Google"); + VALUE protobuf = rb_define_module_under(google, "Protobuf"); + + ObjectCache_Init(protobuf); + Arena_register(protobuf); + Defs_register(protobuf); + RepeatedField_register(protobuf); + Map_register(protobuf); + Message_register(protobuf); + + cParseError = rb_const_get(protobuf, rb_intern("ParseError")); + rb_gc_register_mark_object(cParseError); + cTypeError = rb_const_get(protobuf, rb_intern("TypeError")); + rb_gc_register_mark_object(cTypeError); + + rb_define_singleton_method(protobuf, "discard_unknown", + Google_Protobuf_discard_unknown, 1); + rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy, + 1); +} + +// ----------------------------------------------------------------------------- +// Utilities +// ----------------------------------------------------------------------------- + +// Raises a Ruby error if val is frozen in Ruby or UPB. +void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen) { + if (RB_UNLIKELY(rb_obj_frozen_p(val) || upb_frozen)) { + rb_error_frozen_object(val); + } +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.h new file mode 100755 index 00000000..abb7c892 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/protobuf.h @@ -0,0 +1,100 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ +#define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ + +// Ruby 3+ defines NDEBUG itself, see: https://bugs.ruby-lang.org/issues/18777 +#ifdef NDEBUG +#include +#else +#include +#undef NDEBUG +#endif + +#include // Must be included after the NDEBUG logic above. +#include +#include + +#include "defs.h" +#include "ruby-upb.h" + +// These operate on a map field (i.e., a repeated field of submessages whose +// submessage type is a map-entry msgdef). +const upb_FieldDef* map_field_key(const upb_FieldDef* field); +const upb_FieldDef* map_field_value(const upb_FieldDef* field); + +// ----------------------------------------------------------------------------- +// Arena +// ----------------------------------------------------------------------------- + +// A Ruby object that wraps an underlying upb_Arena. Any objects that are +// allocated from this arena should reference the Arena in rb_gc_mark(), to +// ensure that the object's underlying memory outlives any Ruby object that can +// reach it. + +VALUE Arena_new(); +upb_Arena* Arena_get(VALUE arena); + +// Fuses this arena to another, throwing a Ruby exception if this is not +// possible. +void Arena_fuse(VALUE arena, upb_Arena* other); + +// ----------------------------------------------------------------------------- +// ObjectCache +// ----------------------------------------------------------------------------- + +// Global object cache from upb array/map/message/symtab to wrapper object. +// +// This is a conceptually "weak" cache, in that it does not prevent "val" from +// being collected (though in Ruby <2.7 is it effectively strong, due to +// implementation limitations). + +// Tries to add a new entry to the cache, returning the newly installed value or +// the pre-existing entry. +VALUE ObjectCache_TryAdd(const void* key, VALUE val); + +// Returns the cached object for this key, if any. Otherwise returns Qnil. +VALUE ObjectCache_Get(const void* key); + +// ----------------------------------------------------------------------------- +// StringBuilder, for inspect +// ----------------------------------------------------------------------------- + +struct StringBuilder; +typedef struct StringBuilder StringBuilder; + +StringBuilder* StringBuilder_New(); +void StringBuilder_Free(StringBuilder* b); +void StringBuilder_Printf(StringBuilder* b, const char* fmt, ...); +VALUE StringBuilder_ToRubyString(StringBuilder* b); + +void StringBuilder_PrintMsgval(StringBuilder* b, upb_MessageValue val, + TypeInfo info); + +// ----------------------------------------------------------------------------- +// Utilities. +// ----------------------------------------------------------------------------- + +extern VALUE cTypeError; + +#ifdef NDEBUG +#define PBRUBY_ASSERT(expr) \ + do { \ + } while (false && (expr)) +#else +#define PBRUBY_ASSERT(expr) \ + if (!(expr)) \ + rb_bug("Assertion failed at %s:%d, expr: %s", __FILE__, __LINE__, #expr) +#endif + +// Raises a Ruby error if val is frozen in Ruby or upb_frozen is true. +void Protobuf_CheckNotFrozen(VALUE val, bool upb_frozen); + +#define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.c new file mode 100755 index 00000000..4955753f --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.c @@ -0,0 +1,735 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "repeated_field.h" + +#include "convert.h" +#include "defs.h" +#include "message.h" +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Repeated field container type. +// ----------------------------------------------------------------------------- + +typedef struct { + const upb_Array* array; // Can get as mutable when non-frozen. + TypeInfo type_info; + VALUE type_class; // To GC-root the msgdef/enumdef in type_info. + VALUE arena; // To GC-root the upb_Array. +} RepeatedField; + +VALUE cRepeatedField; + +static void RepeatedField_mark(void* _self) { + RepeatedField* self = (RepeatedField*)_self; + rb_gc_mark(self->type_class); + rb_gc_mark(self->arena); +} + +const rb_data_type_t RepeatedField_type = { + "Google::Protobuf::RepeatedField", + {RepeatedField_mark, RUBY_DEFAULT_FREE, NULL}, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static RepeatedField* ruby_to_RepeatedField(VALUE _self) { + RepeatedField* self; + TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self); + return self; +} + +static upb_Array* RepeatedField_GetMutable(VALUE _self) { + const upb_Array* array = ruby_to_RepeatedField(_self)->array; + Protobuf_CheckNotFrozen(_self, upb_Array_IsFrozen(array)); + return (upb_Array*)array; +} + +VALUE RepeatedField_alloc(VALUE klass) { + RepeatedField* self = ALLOC(RepeatedField); + self->arena = Qnil; + self->type_class = Qnil; + self->array = NULL; + return TypedData_Wrap_Struct(klass, &RepeatedField_type, self); +} + +VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f) { + PBRUBY_ASSERT(upb_FieldDef_IsRepeated(f)); + VALUE val = ObjectCache_Get(f); + + if (val == Qnil) { + val = RepeatedField_alloc(cRepeatedField); + RepeatedField* self; + TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self); + self->arena = Arena_new(); + TypeInfo type_info = TypeInfo_get(f); + self->array = upb_Array_New(Arena_get(self->arena), type_info.type); + self->type_info = type_info; + if (self->type_info.type == kUpb_CType_Message) { + self->type_class = Descriptor_DefToClass(type_info.def.msgdef); + } + val = ObjectCache_TryAdd(f, RepeatedField_freeze(val)); + } + PBRUBY_ASSERT(RB_OBJ_FROZEN(val)); + PBRUBY_ASSERT(upb_Array_IsFrozen(ruby_to_RepeatedField(val)->array)); + return val; +} + +VALUE RepeatedField_GetRubyWrapper(const upb_Array* array, TypeInfo type_info, + VALUE arena) { + PBRUBY_ASSERT(array); + PBRUBY_ASSERT(arena != Qnil); + VALUE val = ObjectCache_Get(array); + + if (val == Qnil) { + val = RepeatedField_alloc(cRepeatedField); + RepeatedField* self; + TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self); + self->array = array; + self->arena = arena; + self->type_info = type_info; + if (self->type_info.type == kUpb_CType_Message) { + self->type_class = Descriptor_DefToClass(type_info.def.msgdef); + } + val = ObjectCache_TryAdd(array, val); + } + + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type); + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef == + type_info.def.msgdef); + PBRUBY_ASSERT(ruby_to_RepeatedField(val)->array == array); + return val; +} + +static VALUE RepeatedField_new_this_type(RepeatedField* from) { + VALUE arena_rb = Arena_new(); + upb_Array* array = upb_Array_New(Arena_get(arena_rb), from->type_info.type); + VALUE ret = RepeatedField_GetRubyWrapper(array, from->type_info, arena_rb); + PBRUBY_ASSERT(ruby_to_RepeatedField(ret)->type_class == from->type_class); + return ret; +} + +void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array, + TypeInfo info) { + bool first = true; + StringBuilder_Printf(b, "["); + size_t n = array ? upb_Array_Size(array) : 0; + for (size_t i = 0; i < n; i++) { + if (first) { + first = false; + } else { + StringBuilder_Printf(b, ", "); + } + StringBuilder_PrintMsgval(b, upb_Array_Get(array, i), info); + } + StringBuilder_Printf(b, "]"); +} + +VALUE RepeatedField_deep_copy(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + VALUE new_rptfield = RepeatedField_new_this_type(self); + RepeatedField* new_self = ruby_to_RepeatedField(new_rptfield); + VALUE arena_rb = new_self->arena; + upb_Array* new_array = RepeatedField_GetMutable(new_rptfield); + upb_Arena* arena = Arena_get(arena_rb); + size_t elements = upb_Array_Size(self->array); + + upb_Array_Resize(new_array, elements, arena); + + size_t size = upb_Array_Size(self->array); + for (size_t i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + upb_MessageValue copy = Msgval_DeepCopy(msgval, self->type_info, arena); + upb_Array_Set(new_array, i, copy); + } + + return new_rptfield; +} + +const upb_Array* RepeatedField_GetUpbArray(VALUE val, const upb_FieldDef* field, + upb_Arena* arena) { + RepeatedField* self; + TypeInfo type_info = TypeInfo_get(field); + + if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || + RTYPEDDATA_TYPE(val) != &RepeatedField_type) { + rb_raise(cTypeError, "Expected repeated field array"); + } + + self = ruby_to_RepeatedField(val); + if (self->type_info.type != type_info.type) { + rb_raise(cTypeError, "Repeated field array has wrong element type"); + } + + if (self->type_info.def.msgdef != type_info.def.msgdef) { + rb_raise(cTypeError, "Repeated field array has wrong message/enum class"); + } + + Arena_fuse(self->arena, arena); + return self->array; +} + +static int index_position(VALUE _index, RepeatedField* repeated_field) { + int index = NUM2INT(_index); + if (index < 0) index += upb_Array_Size(repeated_field->array); + return index; +} + +static VALUE RepeatedField_subarray(RepeatedField* self, long beg, long len) { + long size = (long)upb_Array_Size(self->array); + + // Match Ruby Array#[beg, len] semantics and avoid an out-of-bounds read + // through upb_Array_Get (which only has a debug-only UPB_ASSERT for + // bounds): clamp len to what is actually available, and reject negative + // len up front. + if (len < 0) return Qnil; + if (beg < 0 || beg > size) return Qnil; + if (len > size - beg) len = size - beg; + + VALUE ary = rb_ary_new2(len); + for (long i = beg; i < beg + len; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_ary_push(ary, elem); + } + return ary; +} + +/** + * ruby-doc: RepeatedField + * + */ + +/* + * ruby-doc: RepeatedField#each + * + * Invokes the block once for each element of the repeated field. RepeatedField + * also includes Enumerable; combined with this method, the repeated field thus + * acts like an ordinary Ruby sequence. + * + * @yield [Object] + * @return [self] + */ +static VALUE RepeatedField_each(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + int i; + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_yield(val); + } + return _self; +} + +/* + * ruby-doc: RepeatedField#[] + * + * Accesses the element at the given index. Returns nil on out-of-bounds + * + * @param index [Integer] + * @return [Object,nil] + */ +static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + long size = upb_Array_Size(self->array); + + VALUE arg = argv[0]; + long beg, len; + + if (argc == 1) { + if (FIXNUM_P(arg)) { + /* standard case */ + upb_MessageValue msgval; + int index = index_position(argv[0], self); + if (index < 0 || (size_t)index >= upb_Array_Size(self->array)) { + return Qnil; + } + msgval = upb_Array_Get(self->array, index); + return Convert_UpbToRuby(msgval, self->type_info, self->arena); + } else { + /* check if idx is Range */ + switch (rb_range_beg_len(arg, &beg, &len, size, 0)) { + case Qfalse: + break; + case Qnil: + return Qnil; + default: + return RepeatedField_subarray(self, beg, len); + } + } + } + + /* assume 2 arguments */ + beg = NUM2LONG(argv[0]); + len = NUM2LONG(argv[1]); + if (beg < 0) { + beg += size; + } + if (beg > size) { + return Qnil; + } + return RepeatedField_subarray(self, beg, len); +} + +/* + * ruby-doc: RepeatedField#[]= + * + * Sets the element at the given index. On out-of-bounds assignments, extends + * the array and fills the hole (if any) with default values. + * + * @param index [Integer] + * @param value [Object + * @return [nil] + */ +static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena); + + int index = index_position(_index, self); + if (index < 0 || index >= (INT_MAX - 1)) { + return Qnil; + } + + if (index >= size) { + upb_Array_Resize(array, index + 1, arena); + upb_MessageValue fill; + memset(&fill, 0, sizeof(fill)); + for (int i = size; i < index; i++) { + // Fill default values. + // TODO: should this happen at the upb level? + upb_Array_Set(array, i, fill); + } + } + + upb_Array_Set(array, index, msgval); + return Qnil; +} + +/* + * ruby-doc: RepeatedField#push + * + * Adds a new element to the repeated field. + * + * @param value [Object] + * @return [self] + */ +static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_Array* array = RepeatedField_GetMutable(_self); + int i; + + for (i = 0; i < argc; i++) { + upb_MessageValue msgval = + Convert_RubyToUpb(argv[i], "", self->type_info, arena); + upb_Array_Append(array, msgval, arena); + } + + return _self; +} + +/* + * ruby-doc: RepeatedField#<< + * + * Adds a new element to the repeated field. + * + * @param value [Object] + * @return [self] + */ +static VALUE RepeatedField_push(VALUE _self, VALUE val) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena = Arena_get(self->arena); + upb_Array* array = RepeatedField_GetMutable(_self); + + upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena); + upb_Array_Append(array, msgval, arena); + + return _self; +} + +/* + * Private ruby method, used by RepeatedField.pop + */ +static VALUE RepeatedField_pop_one(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + size_t size = upb_Array_Size(self->array); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_MessageValue last; + VALUE ret; + + if (size == 0) { + return Qnil; + } + + last = upb_Array_Get(self->array, size - 1); + ret = Convert_UpbToRuby(last, self->type_info, self->arena); + + upb_Array_Resize(array, size - 1, Arena_get(self->arena)); + return ret; +} + +/* + * ruby-doc: RepeatedField#replace + * + * Replaces the contents of the repeated field with the given list of elements. + * + * @param list [Array] + * @return [Array] + */ +static VALUE RepeatedField_replace(VALUE _self, VALUE list) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Array* array = RepeatedField_GetMutable(_self); + int i; + + Check_Type(list, T_ARRAY); + upb_Array_Resize(array, 0, Arena_get(self->arena)); + + for (i = 0; i < RARRAY_LEN(list); i++) { + RepeatedField_push(_self, rb_ary_entry(list, i)); + } + + return list; +} + +/* + * ruby-doc: RepeatedField#clear + * + * Clears (removes all elements from) this repeated field. + * + * @return [self] + */ +static VALUE RepeatedField_clear(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Array* array = RepeatedField_GetMutable(_self); + upb_Array_Resize(array, 0, Arena_get(self->arena)); + return _self; +} + +/* + * ruby-doc: RepeatedField#length + * + * Returns the length of this repeated field. + * + * @return [Integer] + */ +static VALUE RepeatedField_length(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + return INT2NUM(upb_Array_Size(self->array)); +} + +/* + * ruby-doc: RepeatedField#dup + * + * Duplicates this repeated field with a shallow copy. References to all + * non-primitive element objects (e.g., submessages) are shared. + * + * @return [RepeatedField] + */ +static VALUE RepeatedField_dup(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + VALUE new_rptfield = RepeatedField_new_this_type(self); + RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield); + upb_Array* new_array = RepeatedField_GetMutable(new_rptfield); + upb_Arena* arena = Arena_get(new_rptfield_self->arena); + int size = upb_Array_Size(self->array); + int i; + + Arena_fuse(self->arena, arena); + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + upb_Array_Append(new_array, msgval, arena); + } + + return new_rptfield; +} + +/* + * ruby-doc: RepeatedField#to_ary + * + * Used when converted implicitly into array, e.g. compared to an Array. + * Also called as a fallback of Object#to_a + * + * @return [Array] + */ +VALUE RepeatedField_to_ary(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + int size = upb_Array_Size(self->array); + VALUE ary = rb_ary_new2(size); + int i; + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(self->array, i); + VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena); + rb_ary_push(ary, val); + } + + return ary; +} + +/* + * ruby-doc: RepeatedField#== + * + * Compares this repeated field to another. Repeated fields are equal if their + * element types are equal, their lengths are equal, and each element is equal. + * Elements are compared as per normal Ruby semantics, by calling their :== + * methods (or performing a more efficient comparison for primitive types). + * + * Repeated fields with dissimilar element types are never equal, even if value + * comparison (for example, between integers and floats) would have otherwise + * indicated that every element has equal value. + * + * @param other [RepeatedField] + * @return [Boolean] + */ +VALUE RepeatedField_eq(VALUE _self, VALUE _other) { + RepeatedField* self; + RepeatedField* other; + + if (_self == _other) { + return Qtrue; + } + + if (TYPE(_other) == T_ARRAY) { + VALUE self_ary = RepeatedField_to_ary(_self); + return rb_equal(self_ary, _other); + } + + self = ruby_to_RepeatedField(_self); + other = ruby_to_RepeatedField(_other); + size_t n = upb_Array_Size(self->array); + + if (self->type_info.type != other->type_info.type || + self->type_class != other->type_class || + upb_Array_Size(other->array) != n) { + return Qfalse; + } + + for (size_t i = 0; i < n; i++) { + upb_MessageValue val1 = upb_Array_Get(self->array, i); + upb_MessageValue val2 = upb_Array_Get(other->array, i); + if (!Msgval_IsEqual(val1, val2, self->type_info)) { + return Qfalse; + } + } + + return Qtrue; +} + +/* + * ruby-doc: RepeatedField#frozen? + * + * Returns true if the repeated field is frozen in either Ruby or the underlying + * representation. Freezes the Ruby repeated field object if it is not already + * frozen in Ruby but it is frozen in the underlying representation. + * + * @return [Boolean] + */ +VALUE RepeatedField_frozen(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + if (!upb_Array_IsFrozen(self->array)) { + PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self)); + return Qfalse; + } + + // Lazily freeze the Ruby wrapper. + if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self); + return Qtrue; +} + +/* + * ruby-doc: RepeatedField#freeze + * + * Freezes the repeated field object. We have to intercept this so we can freeze + * the underlying representation, not just the Ruby wrapper. + * + * @return [self] + */ +VALUE RepeatedField_freeze(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + if (RB_OBJ_FROZEN(_self)) { + PBRUBY_ASSERT(upb_Array_IsFrozen(self->array)); + return _self; + } + + if (!upb_Array_IsFrozen(self->array)) { + if (self->type_info.type == kUpb_CType_Message) { + upb_Array_Freeze(RepeatedField_GetMutable(_self), + upb_MessageDef_MiniTable(self->type_info.def.msgdef)); + } else { + upb_Array_Freeze(RepeatedField_GetMutable(_self), NULL); + } + } + RB_OBJ_FREEZE(_self); + return _self; +} + +/* + * ruby-doc: RepeatedField#hash + * + * Returns a hash value computed from this repeated field's elements. + * + * @return [Integer] + */ +VALUE RepeatedField_hash(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + uint64_t hash = 0; + size_t n = upb_Array_Size(self->array); + + for (size_t i = 0; i < n; i++) { + upb_MessageValue val = upb_Array_Get(self->array, i); + hash = Msgval_GetHash(val, self->type_info, hash); + } + + return LL2NUM(hash); +} + +/* + * ruby-doc: RepeatedField#+ + * + * Returns a new repeated field that contains the concatenated list of this + * repeated field's elements and other's elements. The other (second) list may + * be either another repeated field or a Ruby array. + * + * @param other [Array,RepeatedField] + * @return [RepeatedField] + */ +VALUE RepeatedField_plus(VALUE _self, VALUE list) { + VALUE dupped_ = RepeatedField_dup(_self); + + if (TYPE(list) == T_ARRAY) { + int i; + for (i = 0; i < RARRAY_LEN(list); i++) { + VALUE elem = rb_ary_entry(list, i); + RepeatedField_push(dupped_, elem); + } + } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) && + RTYPEDDATA_TYPE(list) == &RepeatedField_type) { + RepeatedField* self = ruby_to_RepeatedField(_self); + RepeatedField* list_rptfield = ruby_to_RepeatedField(list); + RepeatedField* dupped = ruby_to_RepeatedField(dupped_); + upb_Array* dupped_array = RepeatedField_GetMutable(dupped_); + upb_Arena* arena = Arena_get(dupped->arena); + Arena_fuse(list_rptfield->arena, arena); + int size = upb_Array_Size(list_rptfield->array); + int i; + + if (self->type_info.type != list_rptfield->type_info.type || + self->type_class != list_rptfield->type_class) { + rb_raise(rb_eArgError, + "Attempt to append RepeatedField with different element type."); + } + + for (i = 0; i < size; i++) { + upb_MessageValue msgval = upb_Array_Get(list_rptfield->array, i); + upb_Array_Append(dupped_array, msgval, arena); + } + } else { + rb_raise(rb_eArgError, "Unknown type appending to RepeatedField"); + } + + return dupped_; +} + +/* + * ruby-doc: RepeatedField#concat + * + * concats the passed in array to self. Returns a Ruby array. + * + * @param other [RepeatedField] + * @return [Array] + */ +VALUE RepeatedField_concat(VALUE _self, VALUE list) { + int i; + + Check_Type(list, T_ARRAY); + for (i = 0; i < RARRAY_LEN(list); i++) { + RepeatedField_push(_self, rb_ary_entry(list, i)); + } + return _self; +} + +/* + * ruby-doc: RepeatedField#initialize + * + * Creates a new repeated field. The provided type must be a Ruby symbol, and + * can take on the same values as those accepted by {FieldDescriptor#type=}. If + * the type is :message or :enum, type_class must be non-nil, and must be the + * Ruby class or module returned by {Descriptor#msgclass} or + * {EnumDescriptor#enummodule}, respectively. An initial list of elements may + * also be provided. + * + * @param type [Symbol] + * @param type_class [Class, Module] + * @paramdefault type_class nil + * @param initial_elems [Array] + * @paramdefault initial_elems [] + * @return [RepeatedField] + */ +VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + upb_Arena* arena; + VALUE ary = Qnil; + + self->arena = Arena_new(); + arena = Arena_get(self->arena); + + if (argc < 1) { + rb_raise(rb_eArgError, "Expected at least 1 argument."); + } + + self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary); + self->array = upb_Array_New(arena, self->type_info.type); + VALUE stored_val = ObjectCache_TryAdd(self->array, _self); + PBRUBY_ASSERT(stored_val == _self); + + if (ary != Qnil) { + if (!RB_TYPE_P(ary, T_ARRAY)) { + rb_raise(rb_eArgError, "Expected array as initialize argument"); + } + for (int i = 0; i < RARRAY_LEN(ary); i++) { + RepeatedField_push(_self, rb_ary_entry(ary, i)); + } + } + return Qnil; +} + +void RepeatedField_register(VALUE module) { + VALUE klass = rb_define_class_under(module, "RepeatedField", rb_cObject); + rb_define_alloc_func(klass, RepeatedField_alloc); + rb_gc_register_address(&cRepeatedField); + cRepeatedField = klass; + + rb_define_method(klass, "initialize", RepeatedField_init, -1); + rb_define_method(klass, "each", RepeatedField_each, 0); + rb_define_method(klass, "[]", RepeatedField_index, -1); + rb_define_method(klass, "at", RepeatedField_index, -1); + rb_define_method(klass, "[]=", RepeatedField_index_set, 2); + rb_define_method(klass, "push", RepeatedField_push_vararg, -1); + rb_define_method(klass, "<<", RepeatedField_push, 1); + rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0); + rb_define_method(klass, "replace", RepeatedField_replace, 1); + rb_define_method(klass, "clear", RepeatedField_clear, 0); + rb_define_method(klass, "length", RepeatedField_length, 0); + rb_define_method(klass, "size", RepeatedField_length, 0); + rb_define_method(klass, "dup", RepeatedField_dup, 0); + // Also define #clone so that we don't inherit Object#clone. + rb_define_method(klass, "clone", RepeatedField_dup, 0); + rb_define_method(klass, "==", RepeatedField_eq, 1); + rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0); + rb_define_method(klass, "freeze", RepeatedField_freeze, 0); + rb_define_method(klass, "frozen?", RepeatedField_frozen, 0); + rb_define_method(klass, "hash", RepeatedField_hash, 0); + rb_define_method(klass, "+", RepeatedField_plus, 1); + rb_define_method(klass, "concat", RepeatedField_concat, 1); + rb_include_module(klass, rb_mEnumerable); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.h new file mode 100755 index 00000000..1ae31cfc --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/repeated_field.h @@ -0,0 +1,45 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef RUBY_PROTOBUF_REPEATED_FIELD_H_ +#define RUBY_PROTOBUF_REPEATED_FIELD_H_ + +#include "protobuf.h" +#include "ruby-upb.h" + +// Returns a frozen sentinel Ruby wrapper object for an empty upb_Array of the +// type specified by the field. Creates one if it doesn't exist. +VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f); + +// Returns a Ruby wrapper object for the given upb_Array, which will be created +// if one does not exist already. +VALUE RepeatedField_GetRubyWrapper(const upb_Array* msg, TypeInfo type_info, + VALUE arena); + +// Gets the underlying upb_Array for this Ruby RepeatedField object, which must +// have a type that matches |f|. If this is not a repeated field or the type +// doesn't match, raises an exception. +const upb_Array* RepeatedField_GetUpbArray(VALUE value, const upb_FieldDef* f, + upb_Arena* arena); + +// Implements #inspect for this repeated field by appending its contents to |b|. +void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array, + TypeInfo info); + +// Returns a deep copy of this RepeatedField object. +VALUE RepeatedField_deep_copy(VALUE obj); + +// Ruby class of Google::Protobuf::RepeatedField. +extern VALUE cRepeatedField; + +// Call at startup to register all types in this module. +void RepeatedField_register(VALUE module); + +// Recursively freeze RepeatedField. +VALUE RepeatedField_freeze(VALUE _self); + +#endif // RUBY_PROTOBUF_REPEATED_FIELD_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.c new file mode 100755 index 00000000..22eed466 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.c @@ -0,0 +1,18844 @@ +/* Amalgamated source file */ +#include "ruby-upb.h" + +/* + * This is where we define internal portability macros used across upb. + * + * All of these macros are undef'd in undef.inc to avoid leaking them to users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port/def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port/undef.inc" + * + * This file is private and must not be included by users! + */ + +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201703L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +#error upb requires C99 or C++17 or MSVC >= 2015. +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +#define UPB_CLANG_MIN(x, y) \ + (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) +#else +#define UPB_CLANG_MIN(x, y) 0 +#endif + +// Macros for checking for compiler attributes, defined here to avoid the +// problem described in +// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#ifdef __has_c_attribute +#define UPB_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +#define UPB_HAS_C_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +// NOTE: requiring __cplusplus above should not be necessary, but +// works around https://bugs.llvm.org/show_bug.cgi?id=23435. +#define UPB_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define UPB_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +// Once in a while we want to use this macro in a C++-only portion of an +// otherwise C-compatible header, so we copy and paste this from ABSL. +#if UPB_HAS_CPP_ATTRIBUTE(deprecated) && UPB_HAS_CPP_ATTRIBUTE(clang::annotate) +#define UPB_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]] +#elif UPB_HAS_CPP_ATTRIBUTE(deprecated) +#define UPB_DEPRECATE_AND_INLINE() [[deprecated]] +#else +#define UPB_DEPRECATE_AND_INLINE() +#endif + +#ifdef __has_builtin +#define UPB_HAS_BUILTIN(x) __has_builtin(x) +#else +#define UPB_HAS_BUILTIN(x) 0 +#endif + +#ifdef __has_extension +#define UPB_HAS_EXTENSION(x) __has_extension(x) +#else +#define UPB_HAS_EXTENSION(x) 0 +#endif + +#ifdef __has_feature +#define UPB_HAS_FEATURE(x) __has_feature(x) +#else +#define UPB_HAS_FEATURE(x) 0 +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef UINTPTR_MAX +Error, UINTPTR_MAX is undefined +#endif + +#if UINTPTR_MAX == 0xffffffff +#define UPB_SIZE(size32, size64) size32 +#else +#define UPB_SIZE(size32, size64) size64 +#endif + +/* If we always read/write as a consistent type to each address, this shouldn't + * violate aliasing. + */ +#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) + +// A flexible array member may have lower alignment requirements than the struct +// overall - in that case, it can overlap with the trailing padding of the rest +// of the struct, and a naive sizeof(base) + sizeof(flex) * count calculation +// will not take into account that overlap, and allocate more than is required. +#define UPB_SIZEOF_FLEX(type, member, count) \ + UPB_MAX(sizeof(type), offsetof(type, member[count])) + +#define UPB_SIZEOF_FLEX_WOULD_OVERFLOW(type, member, count) \ + (((SIZE_MAX - offsetof(type, member[0])) / \ + (offsetof(type, member[1]) - offsetof(type, member[0]))) < (size_t)count) + +#define UPB_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#define UPB_MAPTYPE_STRING 0 + +// UPB_EXPORT: always generate a public symbol. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) +#else +#define UPB_EXPORT +#endif + +// UPB_INLINE: inline if possible, emit standalone code if required. +#ifdef __cplusplus +#define UPB_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define UPB_INLINE static __inline__ +#else +#define UPB_INLINE static +#endif + +// UPB_INLINE_IF_NOT_GCC: because gcc can be very noisy at times. +#if defined(__GNUC__) && !defined(__clang__) +#define UPB_INLINE_IF_NOT_GCC static +#else +#define UPB_INLINE_IF_NOT_GCC UPB_INLINE +#endif + +#ifdef UPB_BUILD_API +#define UPB_API UPB_EXPORT +#define UPB_API_INLINE UPB_EXPORT +#else +#define UPB_API +#define UPB_API_INLINE UPB_INLINE +#endif + +#ifdef EXPORT_UPBC +#define UPBC_API UPB_EXPORT +#else +#define UPBC_API +#endif + +#if UPB_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#define UPB_ASAN 1 +#else +#define UPB_ASAN 0 +#endif + +#if UPB_HAS_FEATURE(hwaddress_sanitizer) +#define UPB_HWASAN 1 +#define UPB_HWASAN_POISON_TAG 17 +#define UPB_MALLOC_ALIGN 16 +#else +#define UPB_HWASAN 0 +#define UPB_MALLOC_ALIGN 8 +#endif + +#if UPB_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#define UPB_TSAN 1 +#else +#define UPB_TSAN 0 +#endif + +#if UPB_HAS_FEATURE(memory_sanitizer) +#define UPB_MSAN 1 +#else +#define UPB_MSAN 0 +#endif + +// An unfortunate concession to C++17 and MSVC, which don't support zero-sized +// structs. +#if UPB_ASAN || UPB_HWASAN || UPB_TSAN +#define UPB_XSAN_MEMBER upb_Xsan xsan; +#define UPB_XSAN(st) (&(st)->xsan) +#define UPB_XSAN_STRUCT_SIZE 1 +#else +#define UPB_XSAN_MEMBER +#define UPB_XSAN(st) (NULL) +#define UPB_XSAN_STRUCT_SIZE 0 +#endif + +#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) +#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) + +#if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_alignof) || \ + defined(__cplusplus) +#define UPB_ALIGN_OF(type) alignof(type) +#elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_alignof) +#define UPB_ALIGN_OF(type) _Alignof(type) +#elif UPB_GNUC_MIN(2, 95) +#define UPB_ALIGN_OF(type) __alignof__(type) +#elif defined(_MSC_VER) +#define UPB_ALIGN_OF(type) __alignof(type) +#else +#define UPB_ALIGN_OF(type) \ + offsetof( \ + struct { \ + char c; \ + type member; \ + }, \ + member) +#endif + +#ifdef _MSC_VER +// Some versions of our Windows compiler don't support the C11 syntax. +#define UPB_ALIGN_AS(x) __declspec(align(x)) +#elif defined(__GNUC__) +#define UPB_ALIGN_AS(x) __attribute__((aligned(x))) +#else +#define UPB_ALIGN_AS(x) _Alignas(x) +#endif + +#if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_static_assert) || \ + defined(__cplusplus) +#define UPB_STATIC_ASSERT(val, msg) static_assert((val), msg) +#elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_static_assert) || \ + UPB_GNUC_MIN(4, 6) +#define UPB_STATIC_ASSERT(val, msg) _Static_assert((val), msg) +#else +// Unfortunately this hack doesn't work inside struct declarations, but it works +// everywhere else +#define UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) s1##s2 +#define UPB_STATIC_ASSERT_CONCAT(s1, s2) UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) +#ifdef __COUNTER__ +#define UPB_STATIC_ASSERT(condition, message) \ + typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ + __COUNTER__)[(condition) ? 1 : -1] +#else +#define UPB_STATIC_ASSERT(condition, message) \ + typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ + __LINE__)[(condition) ? 1 : -1] +#endif +#endif + +// Hints to the compiler about likely/unlikely branches. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) +#else +#define UPB_LIKELY(x) (x) +#define UPB_UNLIKELY(x) (x) +#endif + +#if UPB_HAS_BUILTIN(__builtin_expect_with_probability) +#define UPB_UNPREDICTABLE(x) \ + __builtin_expect_with_probability((bool)(x), 1, 0.5) +#else +#define UPB_UNPREDICTABLE(x) (x) +#endif + +// Macros for function attributes on compilers that support them. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static +#define UPB_NOINLINE __attribute__((noinline)) +#define UPB_NORETURN __attribute__((__noreturn__)) +#define UPB_PRINTF(str, first_vararg) \ + __attribute__((format(printf, str, first_vararg))) +#elif defined(_MSC_VER) +#define UPB_NOINLINE +#define UPB_FORCEINLINE static +#define UPB_NORETURN __declspec(noreturn) +#define UPB_PRINTF(str, first_vararg) +#else /* !defined(__GNUC__) */ +#define UPB_FORCEINLINE static +#define UPB_NOINLINE +#define UPB_NORETURN +#define UPB_PRINTF(str, first_vararg) +#endif + +#if UPB_HAS_ATTRIBUTE(noderef) +#define UPB_NODEREF __attribute__((noderef)) +#else +#define UPB_NODEREF +#endif + +// Will be defined properly once call sites are updated +#if false && UPB_HAS_C_ATTRIBUTE(nodiscard) +#define UPB_NODISCARD [[nodiscard]] +#elif false && UPB_HAS_ATTRIBUTE(warn_unused_result) +#define UPB_NODISCARD __attribute__((warn_unused_result)) +#elif false && UPB_HAS_CPP_ATTRIBUTE(nodiscard) +#define UPB_NODISCARD [[nodiscard]] +#else +#define UPB_NODISCARD +#endif + +#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)(var) + +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. +#ifdef NDEBUG +#ifdef __GNUC__ +#define UPB_ASSUME(expr) \ + if (!(expr)) __builtin_unreachable() +#elif defined _MSC_VER +#define UPB_ASSUME(expr) \ + if (!(expr)) __assume(0) +#else +#define UPB_ASSUME(expr) \ + do { \ + } while (false && (expr)) +#endif +#else +#define UPB_ASSUME(expr) assert(expr) +#endif + +#if UPB_HAS_BUILTIN(__builtin_constant_p) && UPB_HAS_ATTRIBUTE(const) +#define UPB_MAYBE_ASSUME(pred, x) \ + if (__builtin_constant_p(pred) && pred) UPB_ASSUME(x) +#define UPB_ATTR_CONST __attribute__((const)) +#else +#define UPB_MAYBE_ASSUME(pred, x) +#define UPB_ATTR_CONST +#endif + +/* UPB_ASSERT(): in release mode, we use the expression without letting it be + * evaluated. This prevents "unused variable" warnings. */ +#ifdef NDEBUG +#define UPB_ASSERT(expr) \ + do { \ + } while (false && (expr)) +#else +#define UPB_ASSERT(expr) assert(expr) +#endif + +#if !defined(NDEBUG) && !defined(UPB_TSAN) +#define UPB_ENABLE_REF_CYCLE_CHECKS 1 +#else +#define UPB_ENABLE_REF_CYCLE_CHECKS 0 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define UPB_PRETTY_FUNCTION NULL +#endif + +#ifdef __cplusplus + extern "C" { +#endif + UPB_NORETURN void _upb_UnreachableFailure(const char* file, int line, + const char* function_name); +#if !defined(NDEBUG) +#define UPB_UNREACHABLE_FAILURE() \ + _upb_UnreachableFailure(__FILE__, __LINE__, UPB_PRETTY_FUNCTION); +#else +#define UPB_UNREACHABLE_FAILURE() +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + __assume(0); \ + } while (0) +#else +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + } while (0) +#endif + +#ifdef __ANDROID__ +#define UPB_DEFAULT_MAX_BLOCK_SIZE 8192 +#else +#define UPB_DEFAULT_MAX_BLOCK_SIZE 32768 +#endif + +/* UPB_SETJMP() / UPB_LONGJMP() */ +// Android uses a custom libc that does not implement all of posix, but it has +// had sigsetjmp/siglongjmp forever on arm and since API 12 on x86. Apple has +// sigsetjmp, but does not define the posix feature test macro. +#if defined(__APPLE__) || defined(_POSIX_C_SOURCE) || defined(__ANDROID__) +// avoid setting/restoring signal mask, which involves costly syscalls +#define UPB_SETJMP(buf) sigsetjmp(buf, 0) +#define UPB_LONGJMP(buf, val) siglongjmp(buf, val) +#elif defined(WASM_WAMR) +#define UPB_SETJMP(buf) 0 +#define UPB_LONGJMP(buf, val) abort() +#else +#define UPB_SETJMP(buf) setjmp(buf) +#define UPB_LONGJMP(buf, val) longjmp(buf, val) +#endif + +#if ((__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)) || \ + UPB_HAS_EXTENSION(c_atomic) || \ + defined(__GNUC__) // GCC supported atomics as an extension before it + // supported __has_extension +#define UPB_USE_C11_ATOMICS +#elif defined(_MSC_VER) +#define UPB_USE_MSC_ATOMICS +#endif + +#if defined(UPB_USE_C11_ATOMICS) +#define UPB_ATOMIC(T) _Atomic(T) +#elif defined(UPB_USE_MSC_ATOMICS) +#define UPB_ATOMIC(T) volatile T +#else +#define UPB_ATOMIC(T) T +#endif + +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + +#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only + +#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY +#define UPB_ONLYBITS(x) x +#else +#define UPB_ONLYBITS(x) UPB_PRIVATE(x) +#endif + +/* Configure whether fasttable is switched on or not. *************************/ + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#if UPB_HAS_ATTRIBUTE(preserve_most) && !defined(__i386__) +#define UPB_PRESERVE_MOST __attribute__((preserve_most)) +#else +#define UPB_PRESERVE_MOST +#endif + +#if UPB_HAS_ATTRIBUTE(preserve_none) +#define UPB_PRESERVE_NONE __attribute__((preserve_none)) +#else +#define UPB_PRESERVE_NONE +#endif + +#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) +#define UPB_ARM64_ASM 1 +#else +#define UPB_ARM64_ASM 0 +#endif + +/* When compiling with branch protection, we need to ensure that all branch + * targets in assembly use the appropriate landing pad instruction. These + * instructions are backwards compatible with processors that don't have + * FEAT_BTI and are treated as nops. + */ +#if UPB_ARM64_ASM && defined(__ARM_FEATURE_BTI_DEFAULT) +#if __ARM_FEATURE_BTI_DEFAULT == 1 +#define UPB_ARM64_BTI_DEFAULT 1 +#else +#define UPB_ARM64_BTI_DEFAULT 0 +#endif +#else +#define UPB_ARM64_BTI_DEFAULT 0 +#endif + +/* aarch64 supports big and little endian modes; fasttable performs multibyte + * tag loads assumes the tag of a varint is in the low bits. */ +#if (defined(__x86_64__) || defined(__AARCH64EL__)) && \ + UPB_HAS_ATTRIBUTE(preserve_none) && UPB_HAS_ATTRIBUTE(musttail) +#define UPB_FASTTABLE_SUPPORTED 1 +#else +#define UPB_FASTTABLE_SUPPORTED 0 +#endif + +/* define UPB_ENABLE_FASTTABLE to force fast table support. + * This is useful when we want to ensure we are really getting fasttable, + * for example for testing or benchmarking. */ +#if defined(UPB_ENABLE_FASTTABLE) +#if !UPB_FASTTABLE_SUPPORTED +#error fasttable is x86-64/ARM64le only and requires preserve_none and musttail. +#endif +#define UPB_FASTTABLE 1 +/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. + * This is useful for releasing code that might be used on multiple platforms, + * for example the PHP or Ruby C extensions. */ +#elif defined(UPB_TRY_ENABLE_FASTTABLE) +#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED +#else +#define UPB_FASTTABLE 0 +#endif + +/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully + * degrade to non-fasttable if the runtime or platform do not support it. */ +#if !UPB_FASTTABLE +#define UPB_FASTTABLE_INIT(...) +#define UPB_FASTTABLE_MASK(mask) -1 +#else +#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ +#define UPB_FASTTABLE_MASK(mask) mask +#endif + +#undef UPB_FASTTABLE_SUPPORTED + +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif + +#if defined(UPB_IS_GOOGLE3) && \ + (!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_IS_GOOGLE3) && defined(UPB_BOOTSTRAP_STAGE) && \ + UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC_MINITABLE(sym) proto2__##sym##_msg_init() +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() +#else +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init +#endif + +#undef UPB_IS_GOOGLE3 + +#ifdef __clang__ +#define UPB_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address"))) +#else +#define UPB_NO_SANITIZE_ADDRESS +#endif + +#if defined(__GNUC__) && (defined(__clang__) || UPB_GNUC_MIN(11, 0)) +#define UPB_RETAIN __attribute__((retain)) +#else +#define UPB_RETAIN +#endif + +// Linker arrays combine elements from multiple translation units into a single +// array that can be iterated over at runtime. +// +// It is an alternative to pre-main "registration" functions. +// +// Usage: +// +// // In N translation units. +// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; +// +// // At runtime: +// UPB_LINKARR_DECLARE(foo_array, int); +// +// void f() { +// const int* start = UPB_LINKARR_START(foo_array); +// const int* stop = UPB_LINKARR_STOP(foo_array); +// for (const int* p = start; p < stop; p++) { +// // Windows can introduce zero padding, so we have to skip zeroes. +// if (*p != 0) { +// vec.push_back(*p); +// } +// } +// } + +#if defined(__GNUC__) && !defined(__clang__) +// GCC can't handle mismatched retain attributes in the same section: +// https://github.com/protocolbuffers/protobuf/issues/26385 +// To work around this, we retain all linker array elements, even though this +// effectively disables tree-shaking of unused extensions when using GCC. +#define UPB_LINKARR_ATTR UPB_RETAIN +#else +#define UPB_LINKARR_ATTR +#endif + +#define UPB_LINKARR_SENTINEL UPB_RETAIN __attribute__((weak, used)) + +#if defined(__ELF__) || defined(__wasm__) + +#define UPB_LINKARR_APPEND(name) \ + __attribute__(( \ + section("linkarr_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)"); \ + extern type __start_linkarr_##name; \ + extern type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) \ + UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(__MACH__) + +/* As described in: https://stackoverflow.com/a/22366882 */ +#define UPB_LINKARR_APPEND(name) \ + __attribute__(( \ + section("__DATA,__la_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)"); \ + extern type __start_linkarr_##name __asm( \ + "section$start$__DATA$__la_" #name); \ + extern type __stop_linkarr_##name __asm( \ + "section$end$__DATA$" \ + "__la_" #name); \ + UPB_LINKARR_APPEND(name) \ + UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(_MSC_VER) + +/* See: + * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 + * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 + * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ +#define UPB_STRINGIFY_INTERNAL(x) #x +#define UPB_STRINGIFY(x) UPB_STRINGIFY_INTERNAL(x) +#define UPB_CONCAT(a, b, c) a##b##c +#define UPB_LINKARR_NAME(name, index) \ + UPB_STRINGIFY(UPB_CONCAT(la_, name, index)) +#define UPB_LINKARR_APPEND(name) \ + __pragma(section(UPB_LINKARR_NAME(name, $j), read)) \ + __declspec(allocate(UPB_LINKARR_NAME(name, $j))) +// clang-format off +#define UPB_LINKARR_DECLARE(name, type) \ + __pragma(message(UPB_LINKARR_NAME(name, $j))) \ + __pragma(section(UPB_LINKARR_NAME(name, $a), read)) \ + __pragma(section(UPB_LINKARR_NAME(name, $z), read)) \ + __declspec(allocate(UPB_LINKARR_NAME(name, $a)), selectany) \ + type __start_linkarr_##name; \ + __declspec(allocate(UPB_LINKARR_NAME(name, $z)), selectany) \ + type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) \ + __declspec(selectany) type UPB_linkarr_internal_empty_##name[1] = {0} +// clang-format on +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#else + +// Linker arrays are not supported on this platform. Make macros no-ops. +#define UPB_LINKARR_APPEND(name) +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)") +#define UPB_LINKARR_START(name) (NULL) +#define UPB_LINKARR_STOP(name) (NULL) + +#endif + +// Workaround for https://github.com/llvm/llvm-project/issues/167577 until it's +// fixed. Some function must exist for the constructor to work properly. +// TODO Remove this or gate it on a future version of clang. +#if defined(__clang__) && defined(__arm__) +#define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((used, visibility("hidden"))) void UPB_PRIVATE(unique_name)( \ + void) {} +#else +#define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) +#endif + +#define _UPB_STRINGIFY2(x) #x +#define _UPB_STRINGIFY(x) _UPB_STRINGIFY2(x) + +#if defined(__ELF__) && (UPB_GNUC_MIN(15, 1) || UPB_CLANG_MIN(21, 1)) +/* + * Workaround for b/456308964 and b/456317163. Although weak constructors + * resolve to a single function body, Clang still emits a pointer into + * .init_array for every translation unit, causing the constructor to be + * executed multiple times and inflating binary size. We wrap the .init_array + * entry in a COMDAT group (using inline assembly) to force the linker to + * deduplicate the pointer to exactly one instance. %cc is used in preference to + * the more widely available %c because %c may under some circumstances still + * output a function name including relocation information, which will then + * confuse the linker. This was only a problem on gcc; when %cc was introduced + * to clang it was just an alias to %c, and clang's %c had already done the + * checks that %cc introduced to gcc. + * References: + * https://github.com/gcc-mirror/gcc/commit/74d6a676034b3ab20c387f12f19f5597e4f1c9fa + * https://github.com/llvm/llvm-project/pull/127719#issuecomment-2686276305 + */ +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((weak, used, visibility("hidden"))) void UPB_PRIVATE(name)( \ + void) { \ + __asm__ volatile( \ + ".pushsection .init_array,\"awG\",%%init_array, %cc0, comdat\n" \ + ".dc.a %cc0\n" \ + ".popsection\n" \ + : \ + : "X"(UPB_PRIVATE(name))); \ + __VA_ARGS__ \ + } +#elif defined(__ELF__) || defined(__wasm__) || defined(__MACH__) || \ + defined(__MINGW32__) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((weak, visibility("hidden"), constructor)) void UPB_PRIVATE( \ + name)(void) { \ + __VA_ARGS__ \ + } +#elif defined(_MSC_VER) +/* + * See: https://stackoverflow.com/questions/1113409 + * + * The /include pragma suggested in the link above doesn't work in our case + * because it requires globally unique names. We need a different solution + * to prevent optimizers from removing the constructor. Our solution is to + * create a dummy exported weak symbol that prevent this stripping. + */ +#pragma section(".CRT$XCT", read) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static void __cdecl UPB_PRIVATE(name)(void); \ + __declspec(allocate(".CRT$XCT"), selectany) void( \ + __cdecl * UPB_PRIVATE(name##_))(void) = UPB_PRIVATE(name); \ + __declspec(selectany, dllexport) void* UPB_PRIVATE(name##_force_linkage) = \ + &UPB_PRIVATE(name##_); \ + static void __cdecl UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#else +// No constructor support, nothing we can do except not break builds. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static __attribute__((used)) void UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#else +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static void UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#endif +#endif + +// +// Weak alias platform support. Theoretically this should be possible to do with +// only C using attributes like __attribute__((weak, alias("foo"))), but +// Clang doesn't support this properly on macOS. So we have to use assembly. +#if defined(__APPLE__) + +// TODO: once https://github.com/llvm/llvm-project/issues/167262 is fixed +// in the LLVM linker, we should have all weak variables point to a single +// "default" empty MiniTable instead of having each leaf define its own, like +// we do with ELF below. This will reduce binary size if many messages are tree +// shaken. +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) \ + __attribute__((weak)) const upb_MiniTable name = { \ + .UPB_PRIVATE(fields) = NULL, \ + .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ + .UPB_PRIVATE(field_count) = 0, \ + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ + .UPB_PRIVATE(dense_below) = 0, \ + .UPB_PRIVATE(table_mask) = -1, \ + .UPB_PRIVATE(required_count) = 0, \ + }; +#define UPB_WEAK_ALIAS(type, from, to) \ + extern type to; \ + __asm__(".globl _" #to); \ + __asm__(".private_extern _" #to); \ + __asm__(".set _" #to ", _" #from); \ + __asm__(".weak_definition _" #to); +#define UPB_STRONG_ALIAS(type, from, to) \ + __asm__(".globl _" #to); \ + __asm__(".private_extern _" #to); \ + __asm__(".set _" #to ", _" #from); + +#elif defined(__ELF__) || defined(__wasm__) + + // On ELF, weak aliases work properly, so we can have all weak MiniTables + // point to the same empty singleton MiniTable. This reduces code size if many + // MiniTables are tree shaken. +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() \ + __attribute__((weak)) \ + const upb_MiniTable kUpb_WeakSingletonPlaceholderMiniTable = { \ + .UPB_PRIVATE(fields) = NULL, \ + .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ + .UPB_PRIVATE(field_count) = 0, \ + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ + .UPB_PRIVATE(dense_below) = 0, \ + .UPB_PRIVATE(table_mask) = -1, \ + .UPB_PRIVATE(required_count) = 0, \ + }; +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) +#define UPB_WEAK_ALIAS(type, from, to) \ + extern type to \ + __attribute__((weak, alias("kUpb_WeakSingletonPlaceholderMiniTable"))); +#define UPB_STRONG_ALIAS(type, from, to) \ + extern type to __attribute__((alias(#from))); + +#else +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) +#define UPB_WEAK_ALIAS(type, from, to) weak_alias_not_supported_on_this_platform +#define UPB_STRONG_ALIAS(type, from, to) \ + strong_alias_not_supported_on_this_platform + +#endif + +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#include + +// Must be last. + +extern const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* UPB_PRIVATE(upb_generated_extension_list); +typedef struct { + upb_MiniTableField fields[1]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__FileDescriptorSet_msg_init_Fields; + +static const google__protobuf__FileDescriptorSet_msg_init_Fields google_protobuf_FileDescriptorSet__fields = {{ + {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FileDescriptorProto_msg_init}, +}}; + +const upb_MiniTable google__protobuf__FileDescriptorSet_msg_init = { + &google_protobuf_FileDescriptorSet__fields.fields[0], + 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileDescriptorSet", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[14]; + upb_MiniTableSubInternal subs[7]; +} google__protobuf__FileDescriptorProto_msg_init_Fields; + +static const google__protobuf__FileDescriptorProto_msg_init_Fields google_protobuf_FileDescriptorProto__fields = {{ + {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FileOptions_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo_msg_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}}; + +const upb_MiniTable google__protobuf__FileDescriptorProto_msg_init = { + &google_protobuf_FileDescriptorProto__fields.fields[0], + UPB_SIZE(80, 144), 14, kUpb_ExtMode_NonExtendable, 12, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0020000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x004000003f00001a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, + {0x004800003f150022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x005000003f16002a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x005800003f170032, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x006000003f18003a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x0068000002190042, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x00700000031a004a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x007800003f000050, &upb_DecodeFast_Varint32_Repeated_Tag1Byte}, + {0x008000003f000058, &upb_DecodeFast_Varint32_Repeated_Tag1Byte}, + {0x0030000004000062, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c0000051b0070, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x008800003f00007a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[11]; + upb_MiniTableSubInternal subs[9]; +} google__protobuf__DescriptorProto_msg_init_Fields; + +static const google__protobuf__DescriptorProto_msg_init_Fields google_protobuf_DescriptorProto__fields = {{ + {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ExtensionRange_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__MessageOptions_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__OneofDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ReservedRange_msg_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__SymbolVisibility_enum_init}, +}}; + +const upb_MiniTable google__protobuf__DescriptorProto_msg_init = { + &google_protobuf_DescriptorProto__fields.fields[0], + UPB_SIZE(64, 104), 11, kUpb_ExtMode_NonExtendable, 11, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x002000003f110012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x002800003f12001a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x003000003f130022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x003800003f14002a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x004000003f150032, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x004800000116003a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x005000003f170042, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x005800003f18004a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x006000003f000052, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, + {0x000c000002190058, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__DescriptorProto__ExtensionRange_msg_init_Fields; + +static const google__protobuf__DescriptorProto__ExtensionRange_msg_init_Fields google_protobuf_DescriptorProto_ExtensionRange__fields = {{ + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__DescriptorProto__ExtensionRange_msg_init = { + &google_protobuf_DescriptorProto_ExtensionRange__fields.fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto.ExtensionRange", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x001800000205001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; +} google__protobuf__DescriptorProto__ReservedRange_msg_init_Fields; + +static const google__protobuf__DescriptorProto__ReservedRange_msg_init_Fields google_protobuf_DescriptorProto_ReservedRange__fields = {{ + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable google__protobuf__DescriptorProto__ReservedRange_msg_init = { + &google_protobuf_DescriptorProto_ReservedRange__fields.fields[0], + 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.DescriptorProto.ReservedRange", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[4]; + upb_MiniTableSubInternal subs[4]; +} google__protobuf__ExtensionRangeOptions_msg_init_Fields; + +static const google__protobuf__ExtensionRangeOptions_msg_init_Fields google_protobuf_ExtensionRangeOptions__fields = {{ + {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions__Declaration_msg_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__ExtensionRangeOptions_msg_init = { + &google_protobuf_ExtensionRangeOptions__fields.fields[0], + UPB_SIZE(32, 40), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ExtensionRangeOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001000003f060012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x000c000000070018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0018000001080392, &upb_DecodeFast_Message_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x002000003f093eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; +} google__protobuf__ExtensionRangeOptions__Declaration_msg_init_Fields; + +static const google__protobuf__ExtensionRangeOptions__Declaration_msg_init_Fields google_protobuf_ExtensionRangeOptions_Declaration__fields = {{ + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable google__protobuf__ExtensionRangeOptions__Declaration_msg_init = { + &google_protobuf_ExtensionRangeOptions_Declaration__fields.fields[0], + UPB_SIZE(32, 48), 5, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ExtensionRangeOptions.Declaration", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x002000000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0009000003000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000a000004000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[11]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__FieldDescriptorProto_msg_init_Fields; + +static const google__protobuf__FieldDescriptorProto_msg_init_Fields google_protobuf_FieldDescriptorProto__fields = {{ + {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Label_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Type_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__FieldDescriptorProto_msg_init = { + &google_protobuf_FieldDescriptorProto__fields.fields[0], + UPB_SIZE(72, 120), 11, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x002000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0030000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x000c000002000018, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000003110020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0014000004120028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0040000005000032, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x005000000600003a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0070000007130042, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0018000008000048, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0060000009000052, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000a00000a000188, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__OneofDescriptorProto_msg_init_Fields; + +static const google__protobuf__OneofDescriptorProto_msg_init_Fields google_protobuf_OneofDescriptorProto__fields = {{ + {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__OneofOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__OneofDescriptorProto_msg_init = { + &google_protobuf_OneofDescriptorProto__fields.fields[0], + UPB_SIZE(24, 40), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.OneofDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0020000001030012, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[6]; + upb_MiniTableSubInternal subs[4]; +} google__protobuf__EnumDescriptorProto_msg_init_Fields; + +static const google__protobuf__EnumDescriptorProto_msg_init_Fields google_protobuf_EnumDescriptorProto__fields = {{ + {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumOptions_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__SymbolVisibility_enum_init}, +}}; + +const upb_MiniTable google__protobuf__EnumDescriptorProto_msg_init = { + &google_protobuf_EnumDescriptorProto__fields.fields[0], + UPB_SIZE(40, 64), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x002000003f090012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x00280000010a001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x003000003f0b0022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x003800003f00002a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, + {0x000c0000020c0030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; +} google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_Fields; + +static const google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_Fields google_protobuf_EnumDescriptorProto_EnumReservedRange__fields = {{ + {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init = { + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields.fields[0], + 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumDescriptorProto.EnumReservedRange", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__EnumValueDescriptorProto_msg_init_Fields; + +static const google__protobuf__EnumValueDescriptorProto_msg_init_Fields google_protobuf_EnumValueDescriptorProto__fields = {{ + {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__EnumValueDescriptorProto_msg_init = { + &google_protobuf_EnumValueDescriptorProto__fields.fields[0], + UPB_SIZE(32, 40), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumValueDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x000c000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x002000000205001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[2]; +} google__protobuf__ServiceDescriptorProto_msg_init_Fields; + +static const google__protobuf__ServiceDescriptorProto_msg_init_Fields google_protobuf_ServiceDescriptorProto__fields = {{ + {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__MethodDescriptorProto_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__ServiceDescriptorProto_msg_init = { + &google_protobuf_ServiceDescriptorProto__fields.fields[0], + UPB_SIZE(32, 48), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ServiceDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x002000003f050012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x002800000106001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[6]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__MethodDescriptorProto_msg_init_Fields; + +static const google__protobuf__MethodDescriptorProto_msg_init_Fields google_protobuf_MethodDescriptorProto__fields = {{ + {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__MethodOptions_msg_init}, +}}; + +const upb_MiniTable google__protobuf__MethodDescriptorProto_msg_init = { + &google_protobuf_MethodDescriptorProto__fields.fields[0], + UPB_SIZE(40, 72), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MethodDescriptorProto", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0020000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x003000000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0040000003090022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0009000004000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000a000005000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[21]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__FileOptions_msg_init_Fields; + +static const google__protobuf__FileOptions_msg_init_Fields google_protobuf_FileOptions__fields = {{ + {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__FileOptions__OptimizeMode_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__FileOptions_msg_init = { + &google_protobuf_FileOptions__fields.fields[0], + UPB_SIZE(112, 200), 21, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FileOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0028000001000042, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0014000002200048, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x000b000003000050, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x003800000400005a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000c000005000180, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x000d000006000188, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x000e000007000190, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000f0000080001a0, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x005800000d0002aa, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x00100000090001b8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x007800000f0002c2, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, + {0x00880000100002ca, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001100000a0001d8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x00980000110002e2, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, + {0x00a80000120002ea, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001200000b0001f8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[7]; + upb_MiniTableSubInternal subs[2]; +} google__protobuf__MessageOptions_msg_init_Fields; + +static const google__protobuf__MessageOptions_msg_init_Fields google_protobuf_MessageOptions__fields = {{ + {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__MessageOptions_msg_init = { + &google_protobuf_MessageOptions__fields.fields[0], + UPB_SIZE(24, 32), 7, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MessageOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0009000000000008, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000a000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000b000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000c000003000038, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000d000004000058, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x00100000050b0062, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800003f0c3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[14]; + upb_MiniTableSubInternal subs[8]; +} google__protobuf__FieldOptions_msg_init_Fields; + +static const google__protobuf__FieldOptions_msg_init_Fields google_protobuf_FieldOptions__fields = {{ + {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__CType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__JSType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionRetention_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionTargetType_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__EditionDefault_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__FieldOptions_msg_init = { + &google_protobuf_FieldOptions__fields.fields[0], + UPB_SIZE(48, 72), 14, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0010000000150008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x000a000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000b000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000c000003000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0014000004160030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000d000005000050, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000e000006000078, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000f000007000180, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x0018000008170188, &upb_DecodeFast_ClosedEnum_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x002000003f180198, &upb_DecodeFast_ClosedEnum_Repeated_Tag2Byte}, + {0x002800003f1901a2, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x00300000091a01aa, &upb_DecodeFast_Message_Scalar_Tag2Byte}, + {0x003800000a1b01b2, &upb_DecodeFast_Message_Scalar_Tag2Byte}, + {0x004000003f1c3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__FieldOptions__EditionDefault_msg_init_Fields; + +static const google__protobuf__FieldOptions__EditionDefault_msg_init_Fields google_protobuf_FieldOptions_EditionDefault__fields = {{ + {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}}; + +const upb_MiniTable google__protobuf__FieldOptions__EditionDefault_msg_init = { + &google_protobuf_FieldOptions_EditionDefault__fields.fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(24), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions.EditionDefault", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0010000000000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x000c000001030018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__FieldOptions__FeatureSupport_msg_init_Fields; + +static const google__protobuf__FieldOptions__FeatureSupport_msg_init_Fields google_protobuf_FieldOptions_FeatureSupport__fields = {{ + {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}}; + +const upb_MiniTable google__protobuf__FieldOptions__FeatureSupport_msg_init = { + &google_protobuf_FieldOptions_FeatureSupport__fields.fields[0], + UPB_SIZE(40, 56), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FieldOptions.FeatureSupport", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000080008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0010000001090010, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x001800000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x00140000030a0020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x002800000400002a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; + upb_MiniTableSubInternal subs[2]; +} google__protobuf__OneofOptions_msg_init_Fields; + +static const google__protobuf__OneofOptions_msg_init_Fields google_protobuf_OneofOptions__fields = {{ + {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__OneofOptions_msg_init = { + &google_protobuf_OneofOptions__fields.fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.OneofOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001000000003000a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800003f043eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; + upb_MiniTableSubInternal subs[2]; +} google__protobuf__EnumOptions_msg_init_Fields; + +static const google__protobuf__EnumOptions_msg_init_Fields google_protobuf_EnumOptions__fields = {{ + {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__EnumOptions_msg_init = { + &google_protobuf_EnumOptions__fields.fields[0], + UPB_SIZE(24, 32), 5, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0009000000000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x000a000001000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000b000002000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x001000000308003a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800003f093eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__EnumValueOptions_msg_init_Fields; + +static const google__protobuf__EnumValueOptions_msg_init_Fields google_protobuf_EnumValueOptions__fields = {{ + {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__EnumValueOptions_msg_init = { + &google_protobuf_EnumValueOptions__fields.fields[0], + UPB_SIZE(24, 40), 5, kUpb_ExtMode_Extendable, 4, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.EnumValueOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0009000000000008, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0010000001080012, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x000a000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0018000003090022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x002000003f0a3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[2]; +} google__protobuf__ServiceOptions_msg_init_Fields; + +static const google__protobuf__ServiceOptions_msg_init_Fields google_protobuf_ServiceOptions__fields = {{ + {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__ServiceOptions_msg_init = { + &google_protobuf_ServiceOptions__fields.fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.ServiceOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0009000000000288, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x0010000001050292, &upb_DecodeFast_Message_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800003f063eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[4]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__MethodOptions_msg_init_Fields; + +static const google__protobuf__MethodOptions_msg_init_Fields google_protobuf_MethodOptions__fields = {{ + {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__MethodOptions__IdempotencyLevel_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, +}}; + +const upb_MiniTable google__protobuf__MethodOptions_msg_init = { + &google_protobuf_MethodOptions__fields.fields[0], + UPB_SIZE(24, 32), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.MethodOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0009000000000288, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, + {0x000c000001060290, &upb_DecodeFast_ClosedEnum_Scalar_Tag2Byte}, + {0x001000000207029a, &upb_DecodeFast_Message_Scalar_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x001800003f083eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[7]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__UninterpretedOption_msg_init_Fields; + +static const google__protobuf__UninterpretedOption_msg_init_Fields google_protobuf_UninterpretedOption__fields = {{ + {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption__NamePart_msg_init}, +}}; + +const upb_MiniTable google__protobuf__UninterpretedOption_msg_init = { + &google_protobuf_UninterpretedOption__fields.fields[0], + UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.UninterpretedOption", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x004000003f0b0012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x001000000000001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0048000001000020, &upb_DecodeFast_Varint64_Scalar_Tag1Byte}, + {0x0050000002000028, &upb_DecodeFast_Varint64_Scalar_Tag1Byte}, + {0x0058000003000031, &upb_DecodeFast_Fixed64_Scalar_Tag1Byte}, + {0x002000000400003a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0030000005000042, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[2]; +} google__protobuf__UninterpretedOption__NamePart_msg_init_Fields; + +static const google__protobuf__UninterpretedOption__NamePart_msg_init_Fields google_protobuf_UninterpretedOption_NamePart__fields = {{ + {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable google__protobuf__UninterpretedOption__NamePart_msg_init = { + &google_protobuf_UninterpretedOption_NamePart__fields.fields[0], + UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 2, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.UninterpretedOption.NamePart", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0009000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[9]; + upb_MiniTableSubInternal subs[9]; +} google__protobuf__FeatureSet_msg_init_Fields; + +static const google__protobuf__FeatureSet_msg_init_Fields google_protobuf_FeatureSet__fields = {{ + {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__FieldPresence_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__EnumType_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__Utf8Validation_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__MessageEncoding_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__JsonFormat_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__EnforceNamingStyle_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init}, +}}; + +const upb_MiniTable google__protobuf__FeatureSet_msg_init = { + &google_protobuf_FeatureSet__fields.fields[0], + 48, 9, kUpb_ExtMode_Extendable, 9, UPB_FASTTABLE_MASK(120), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSet", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000c0000000e0008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x00100000010f0010, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0014000002100018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0018000003110020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x001c000004120028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0020000005130030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0024000006140038, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0028000007150040, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x002c000008160048, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + }) +}; + +const upb_MiniTable google__protobuf__FeatureSet__VisibilityFeature_msg_init = { + NULL, + 8, 0, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSet.VisibilityFeature", +#endif +}; + +const upb_MiniTable google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init = { + NULL, + 8, 0, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSet.ProtoLimitsFeature", +#endif +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__FeatureSetDefaults_msg_init_Fields; + +static const google__protobuf__FeatureSetDefaults_msg_init_Fields google_protobuf_FeatureSetDefaults__fields = {{ + {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, +}}; + +const upb_MiniTable google__protobuf__FeatureSetDefaults_msg_init = { + &google_protobuf_FeatureSetDefaults__fields.fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSetDefaults", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001800003f05000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000060020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0010000001070028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[3]; + upb_MiniTableSubInternal subs[3]; +} google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_Fields; + +static const google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_Fields google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields = {{ + {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, + {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, +}}; + +const upb_MiniTable google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init = { + &google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields.fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000c000000050018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0010000001060022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x001800000207002a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[1]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__SourceCodeInfo_msg_init_Fields; + +static const google__protobuf__SourceCodeInfo_msg_init_Fields google_protobuf_SourceCodeInfo__fields = {{ + {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo__Location_msg_init}, +}}; + +const upb_MiniTable google__protobuf__SourceCodeInfo_msg_init = { + &google_protobuf_SourceCodeInfo__fields.fields[0], + 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.SourceCodeInfo", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, + {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; +} google__protobuf__SourceCodeInfo__Location_msg_init_Fields; + +static const google__protobuf__SourceCodeInfo__Location_msg_init_Fields google_protobuf_SourceCodeInfo_Location__fields = {{ + {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable google__protobuf__SourceCodeInfo__Location_msg_init = { + &google_protobuf_SourceCodeInfo_Location__fields.fields[0], + UPB_SIZE(40, 72), 5, kUpb_ExtMode_NonExtendable, 4, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.SourceCodeInfo.Location", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x003000003f00000a, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, + {0x003800003f000012, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, + {0x001000000000001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0020000001000022, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x004000003f000032, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +typedef struct { + upb_MiniTableField fields[1]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__GeneratedCodeInfo_msg_init_Fields; + +static const google__protobuf__GeneratedCodeInfo_msg_init_Fields google_protobuf_GeneratedCodeInfo__fields = {{ + {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(submsg) = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init}, +}}; + +const upb_MiniTable google__protobuf__GeneratedCodeInfo_msg_init = { + &google_protobuf_GeneratedCodeInfo__fields.fields[0], + 16, 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.GeneratedCodeInfo", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, + }) +}; + +typedef struct { + upb_MiniTableField fields[5]; + upb_MiniTableSubInternal subs[1]; +} google__protobuf__GeneratedCodeInfo__Annotation_msg_init_Fields; + +static const google__protobuf__GeneratedCodeInfo__Annotation_msg_init_Fields google_protobuf_GeneratedCodeInfo_Annotation__fields = {{ + {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + }, + { + {.UPB_PRIVATE(subenum) = &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init}, +}}; + +const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = { + &google_protobuf_GeneratedCodeInfo_Annotation__fields.fields[0], + UPB_SIZE(40, 48), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0, +#ifdef UPB_TRACING_ENABLED + "google.protobuf.GeneratedCodeInfo.Annotation", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x002800003f00000a, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, + {0x0018000000000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, + {0x000c000001000018, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0010000002000020, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, + {0x0014000003080028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + }) +}; + +const upb_MiniTableEnum google__protobuf__Edition_enum_init = { + 64, + 11, + { + 0x7, + 0x0, + 0x384, + 0x3e6, + 0x3e7, + 0x3e8, + 0x3e9, + 0x3ea, + 0x270f, + 0x1869d, + 0x1869e, + 0x1869f, + 0x7fffffff, + }, +}; + +const upb_MiniTableEnum google__protobuf__ExtensionRangeOptions__VerificationState_enum_init = { + 64, + 0, + { + 0x3, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__EnforceNamingStyle_enum_init = { + 64, + 0, + { + 0xf, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__EnumType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__FieldPresence_enum_init = { + 64, + 0, + { + 0xf, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__JsonFormat_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__MessageEncoding_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__Utf8Validation_enum_init = { + 64, + 0, + { + 0xd, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init = { + 64, + 0, + { + 0x1f, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Label_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Type_enum_init = { + 64, + 0, + { + 0x7fffe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__CType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__JSType_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__OptionRetention_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FieldOptions__OptionTargetType_enum_init = { + 64, + 0, + { + 0x3ff, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__FileOptions__OptimizeMode_enum_init = { + 64, + 0, + { + 0xe, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__MethodOptions__IdempotencyLevel_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +const upb_MiniTableEnum google__protobuf__SymbolVisibility_enum_init = { + 64, + 0, + { + 0x7, + 0x0, + }, +}; + +static const upb_MiniTable *messages_layout_google_protobuf_descriptor_proto_upb_file_layout[35] = { + &google__protobuf__FileDescriptorSet_msg_init, + &google__protobuf__FileDescriptorProto_msg_init, + &google__protobuf__DescriptorProto_msg_init, + &google__protobuf__DescriptorProto__ExtensionRange_msg_init, + &google__protobuf__DescriptorProto__ReservedRange_msg_init, + &google__protobuf__ExtensionRangeOptions_msg_init, + &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, + &google__protobuf__FieldDescriptorProto_msg_init, + &google__protobuf__OneofDescriptorProto_msg_init, + &google__protobuf__EnumDescriptorProto_msg_init, + &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, + &google__protobuf__EnumValueDescriptorProto_msg_init, + &google__protobuf__ServiceDescriptorProto_msg_init, + &google__protobuf__MethodDescriptorProto_msg_init, + &google__protobuf__FileOptions_msg_init, + &google__protobuf__MessageOptions_msg_init, + &google__protobuf__FieldOptions_msg_init, + &google__protobuf__FieldOptions__EditionDefault_msg_init, + &google__protobuf__FieldOptions__FeatureSupport_msg_init, + &google__protobuf__OneofOptions_msg_init, + &google__protobuf__EnumOptions_msg_init, + &google__protobuf__EnumValueOptions_msg_init, + &google__protobuf__ServiceOptions_msg_init, + &google__protobuf__MethodOptions_msg_init, + &google__protobuf__UninterpretedOption_msg_init, + &google__protobuf__UninterpretedOption__NamePart_msg_init, + &google__protobuf__FeatureSet_msg_init, + &google__protobuf__FeatureSet__VisibilityFeature_msg_init, + &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, + &google__protobuf__FeatureSetDefaults_msg_init, + &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, + &google__protobuf__SourceCodeInfo_msg_init, + &google__protobuf__SourceCodeInfo__Location_msg_init, + &google__protobuf__GeneratedCodeInfo_msg_init, + &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, +}; + +static const upb_MiniTableEnum *enums_layout_google_protobuf_descriptor_proto_upb_file_layout[21] = { + &google__protobuf__Edition_enum_init, + &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init, + &google__protobuf__FeatureSet__EnforceNamingStyle_enum_init, + &google__protobuf__FeatureSet__EnumType_enum_init, + &google__protobuf__FeatureSet__FieldPresence_enum_init, + &google__protobuf__FeatureSet__JsonFormat_enum_init, + &google__protobuf__FeatureSet__MessageEncoding_enum_init, + &google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init, + &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init, + &google__protobuf__FeatureSet__Utf8Validation_enum_init, + &google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init, + &google__protobuf__FieldDescriptorProto__Label_enum_init, + &google__protobuf__FieldDescriptorProto__Type_enum_init, + &google__protobuf__FieldOptions__CType_enum_init, + &google__protobuf__FieldOptions__JSType_enum_init, + &google__protobuf__FieldOptions__OptionRetention_enum_init, + &google__protobuf__FieldOptions__OptionTargetType_enum_init, + &google__protobuf__FileOptions__OptimizeMode_enum_init, + &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init, + &google__protobuf__MethodOptions__IdempotencyLevel_enum_init, + &google__protobuf__SymbolVisibility_enum_init, +}; + +const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout_google_protobuf_descriptor_proto_upb_file_layout, + enums_layout_google_protobuf_descriptor_proto_upb_file_layout, + NULL, + 35, + 21, + 0, +}; + + + +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/json_enumvalue_options.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#include + +// Must be last. + +extern const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* UPB_PRIVATE(upb_generated_extension_list); +typedef struct { + upb_MiniTableField fields[1]; +} pb__enumvalue__JsonEnumValueOptions_msg_init_Fields; + +static const pb__enumvalue__JsonEnumValueOptions_msg_init_Fields pb_enumvalue_JsonEnumValueOptions__fields = {{ + {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}}; + +const upb_MiniTable pb__enumvalue__JsonEnumValueOptions_msg_init = { + &pb_enumvalue_JsonEnumValueOptions__fields.fields[0], + UPB_SIZE(24, 32), 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, +#ifdef UPB_TRACING_ENABLED + "pb.enumvalue.JsonEnumValueOptions", +#endif + UPB_FASTTABLE_INIT({ + {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, + {0x001000000000000a, &upb_DecodeFast_String_Scalar_Tag1Byte}, + }) +}; + +static const upb_MiniTableExtension pb_enumvalue_json_ext_obj = { + {998, 0, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsExtension | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {.UPB_PRIVATE(submsg) = &pb__enumvalue__JsonEnumValueOptions_msg_init}, + &google__protobuf__EnumValueOptions_msg_init, + +}; +UPB_LINKARR_APPEND(upb_AllExts) +const upb_MiniTableExtension* pb_enumvalue_json_ext = &pb_enumvalue_json_ext_obj; + static const upb_MiniTable *messages_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout[1] = { + &pb__enumvalue__JsonEnumValueOptions_msg_init, +}; + + +static const upb_MiniTableExtension *extensions_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout[1] = { + &pb_enumvalue_json_ext_obj, +}; + +UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension*); +UPB_CONSTRUCTOR(upb_GeneratedRegistry_Constructor, google_protobuf_json_enumvalue_options_proto_ext_constructor, { + static bool finished = false; + if (finished) return; + finished = true; + static UPB_PRIVATE(upb_GeneratedExtensionListEntry) entry = { + UPB_LINKARR_START(upb_AllExts), + UPB_LINKARR_STOP(upb_AllExts), + NULL + }; + UPB_ASSERT(entry.next == NULL); + entry.next = UPB_PRIVATE(upb_generated_extension_list); + UPB_PRIVATE(upb_generated_extension_list) = &entry; +}) +const upb_MiniTableFile google_protobuf_json_enumvalue_options_proto_upb_file_layout = { + messages_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout, + NULL, + extensions_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout, + 1, + 0, + 1, +}; + + + + +#include +#include +#include +#include +#include + +// Must be last. + +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; +} + +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } + +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; +} + +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} + +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ + + +#include +#include + + +// Must be last. + +#if defined(__has_builtin) +#if __has_builtin(__builtin_popcount) +#define UPB_FAST_POPCOUNT32(i) __builtin_popcount(i) +#endif +#elif defined(__GNUC__) +#define UPB_FAST_POPCOUNT32(i) __builtin_popcount(i) +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) +// Only use __popcnt on x86/x64 architectures for MSVC +#define UPB_FAST_POPCOUNT32(i) __popcnt(i) +#endif + +UPB_INLINE int _upb_popcnt32(uint32_t i) { +#ifdef UPB_FAST_POPCOUNT32 + return UPB_FAST_POPCOUNT32(i); +#else + int count = 0; + while (i != 0) { + count += i & 1; + i >>= 1; + } + return count; +#endif +} + +#undef UPB_FAST_POPCOUNT32 + +UPB_INLINE uint8_t _upb_log2_table_size(upb_table* t) { + return _upb_popcnt32(t->mask); +} + +/* A type to represent the lookup key of either a strtable, inttable or + * exttable. */ +typedef union { + uintptr_t num; + upb_StringView str; + struct { + const void* ptr; + uint32_t ext_num; + } ext; +} lookupkey_t; + +static lookupkey_t strkey2(const char* str, size_t len) { + return (lookupkey_t){.str = upb_StringView_FromDataAndSize(str, len)}; +} + +static lookupkey_t intkey(uintptr_t key) { return (lookupkey_t){.num = key}; } + +static lookupkey_t extkey(const void* ptr, uint32_t ext_num) { + return (lookupkey_t){.ext = {ptr, ext_num}}; +} + +// Conceptually the hash and equal functions should only take the key, not the +// value, but the extension table stores part of its logical key in the value +// slot. This is a sign that we have outgrown the original architecture. +typedef uint32_t hashfunc_t(upb_key key, upb_value val); +typedef bool eqlfunc_t(upb_key k1, upb_value v1, lookupkey_t k2); + +/* Base table (shared code) ***************************************************/ + +static uint32_t upb_inthash(uintptr_t key) { + UPB_STATIC_ASSERT(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8, + "Pointers don't fit"); + if (sizeof(uintptr_t) == 8) { + return (uint32_t)key ^ (uint32_t)((uint64_t)key >> 32); + } else { + return (uint32_t)key; + } +} + +static upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +static bool isfull(upb_table* t) { + uint32_t size = upb_table_size(t); + // 0.875 load factor + return t->count == (size - (size >> 3)); +} + +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + if (size_lg2 >= 32) { + return false; + } + t->count = 0; + uint32_t size = 1U << size_lg2; + t->mask = size - 1; // 0 mask if size_lg2 is 0 + if (upb_table_size(t) > (SIZE_MAX / sizeof(upb_tabent))) { + return false; + } + size_t bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); + } else { + t->entries = NULL; + } + return true; +} + +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + UPB_ASSERT(false); + return NULL; +} + +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return upb_getentry(t, hash); +} + +static upb_tabent* findentry(const upb_table* t, lookupkey_t key, uint32_t hash, + eqlfunc_t* eql) { + upb_tabent* e; + + if (t->count == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, e->val, key)) return e; + if (!upb_tabent_hasnext(e)) return NULL; + e = upb_tabent_next(e); + } +} + +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return findentry(t, key, hash, eql); +} + +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) *v = e->val; + return true; + } else { + return false; + } +} + +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_key tabkey, upb_value val, + uint32_t hash, hashfunc_t* hashfunc, eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; + + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); + + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; + + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + upb_tabent_clearnext(our_e); + } else { + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = + getentry_mutable(t, hashfunc(mainpos_e->key, mainpos_e->val)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + if (upb_tabent_hasnext(mainpos_e)) { + upb_tabent_setnext(new_e, upb_tabent_next(mainpos_e)); + } else { + upb_tabent_clearnext(new_e); + } + upb_tabent_setnext(mainpos_e, new_e); + our_e = new_e; + } else { + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + new_e->key = mainpos_e->key; + new_e->val = mainpos_e->val; + if (upb_tabent_hasnext(mainpos_e)) { + upb_tabent_setnext(new_e, upb_tabent_next(mainpos_e)); + } else { + upb_tabent_clearnext(new_e); + } + + while (upb_tabent_hasnext(chain) && upb_tabent_next(chain) != mainpos_e) { + chain = upb_tabent_next(chain); + UPB_ASSERT(chain); + } + upb_tabent_setnext(chain, new_e); + our_e = mainpos_e; + upb_tabent_clearnext(our_e); + } + } + our_e->key = tabkey; + our_e->val = val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); +} + +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, uint32_t hash, + eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, chain->val, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) *val = chain->val; + if (upb_tabent_hasnext(chain)) { + upb_tabent* move = upb_tabent_next(chain); + chain->key = move->key; + chain->val = move->val; + if (upb_tabent_hasnext(move)) { + upb_tabent_setnext(chain, upb_tabent_next(move)); + } else { + upb_tabent_clearnext(chain); + } + + upb_tabent_clear(move); + } else { + upb_tabent_clear(chain); + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while ( + upb_tabent_hasnext(chain) && + !eql(upb_tabent_next(chain)->key, upb_tabent_next(chain)->val, key)) { + chain = upb_tabent_next(chain); + } + if (upb_tabent_hasnext(chain)) { + /* Found element to remove. */ + upb_tabent* rm = upb_tabent_next(chain); + t->count--; + if (val) *val = rm->val; + if (upb_tabent_hasnext(rm)) { + upb_tabent_setnext(chain, upb_tabent_next(rm)); + } else { + upb_tabent_clearnext(chain); + } + upb_tabent_clear(rm); + return true; + } else { + /* Element to remove is not in the table. */ + return false; + } + } +} + +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); + + return i; +} + +static size_t begin(const upb_table* t) { return next(t, -1); } + +UPB_FORCEINLINE +bool _upb_tablenext(const upb_table* t, upb_tabent** ent, intptr_t* iter) { + size_t tab_idx = next(t, *iter); + if (tab_idx < upb_table_size(t)) { + *ent = &t->entries[tab_idx]; + *iter = tab_idx; + return true; + } + return false; +} + +UPB_FORCEINLINE +bool _upb_table_done(const upb_table* t, intptr_t iter) { + if (iter == INTPTR_MAX - 1 || (size_t)iter >= upb_table_size(t)) { + return true; + } + return upb_tabent_isempty(&t->entries[iter]); +} + +static void removeiter(upb_table* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->entries[i]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->entries[upb_table_size(t)]; + for (upb_tabent* e = t->entries; e != end; e++) { + if (!upb_tabent_isempty(e) && upb_tabent_hasnext(e) && + upb_tabent_next(e) == ent) { + prev = e; + break; + } + } + + if (prev) { + if (upb_tabent_hasnext(ent)) { + upb_tabent_setnext(prev, upb_tabent_next(ent)); + } else { + upb_tabent_clearnext(prev); + } + } else { + // ent is the head of the chain, so we need to move its next element into + // its slot if there is one. + if (upb_tabent_hasnext(ent)) { + upb_tabent* move = upb_tabent_next(ent); + ent->key = move->key; + ent->val = move->val; + if (upb_tabent_hasnext(move)) { + upb_tabent_setnext(ent, upb_tabent_next(move)); + } else { + upb_tabent_clearnext(ent); + } + + // If we moved an element from a higher index to a lower index, then we've + // moved an element we haven't visited yet into the slot of the one that + // was just removed; decrement iter so that the iterator visits it. + if (move > ent) { + *iter = i - 1; + } + + ent = move; + } + } + + t->count--; + upb_tabent_clear(ent); +} + +/* upb_strtable ***************************************************************/ + +// A simple "subclass" of upb_table that only adds a hash function for strings. + +static upb_SizePrefixString* upb_SizePrefixString_Copy(upb_StringView s, + upb_Arena* a) { + // A 2GB string will fail at serialization time, but we accept up to 4GB in + // memory here. + if (s.size > UINT32_MAX) return NULL; + upb_SizePrefixString* str = + upb_Arena_Malloc(a, sizeof(uint32_t) + s.size + 1); + if (str == NULL) return NULL; + str->size = s.size; + char* data = (char*)str->data; + if (s.size) memcpy(data, s.data, s.size); + data[s.size] = '\0'; + return str; +} + +/* Adapted from ABSL's wyhash. */ + +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} + +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} + +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif + +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif +} + +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} + +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; + + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; + + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); + + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); + + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); + + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; + } + + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + + current_state = WyhashMix(a ^ salt[1], b ^ current_state); + + ptr += 16; + len -= 16; + } + + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; + } + + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); +} + +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; + +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} + +static const void* const _upb_seed; + +// Returns a random seed for upb's hash function. This does not provide +// high-quality randomness, but it should be enough to prevent unit tests from +// relying on a deterministic map ordering. By returning the address of a +// variable, we are able to get some randomness for free provided that ASLR is +// enabled. +static uint64_t _upb_Seed(void) { return (uint64_t)&_upb_seed; } + +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, _upb_Seed()); +} + +static uint32_t strhash(upb_key key, upb_value val) { + UPB_UNUSED(val); + return _upb_Hash_NoSeed(key.str->data, key.str->size); +} + +static bool streql(upb_key k1, upb_value v1, lookupkey_t k2) { + UPB_UNUSED(v1); + const upb_SizePrefixString* k1s = k1.str; + const upb_StringView k2s = k2.str; + return k1s->size == k2s.size && + (k1s->size == 0 || memcmp(k1s->data, k2s.data, k1s->size) == 0); +} + +/** Calculates the number of entries required to hold an expected number of + * values, within the table's load factor. */ +static size_t _upb_entries_needed_for(size_t expected_size) { + size_t need_entries = expected_size + 1 + expected_size / 7; + UPB_ASSERT(need_entries - (need_entries >> 3) >= expected_size); + return need_entries; +} + +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + int size_lg2 = upb_Log2Ceiling(_upb_entries_needed_for(expected_size)); + return init(&t->t, size_lg2, a); +} + +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} + +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + if (!init(&new_table.t, size_lg2, a)) return false; + + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView sv; + upb_value val; + while (upb_strtable_next2(t, &sv, &val, &iter)) { + // Unlike normal insert, does not copy string data or possibly reallocate + // the table + // The data pointer used in the table is guaranteed to point at a + // upb_SizePrefixString, we just need to back up by the size of the uint32_t + // length prefix. + const upb_SizePrefixString* keystr = + (const upb_SizePrefixString*)(sv.data - sizeof(uint32_t)); + UPB_ASSERT(keystr->data == sv.data); + UPB_ASSERT(keystr->size == sv.size); + + lookupkey_t lookupkey = {.str = sv}; + upb_key tabkey = {.str = keystr}; + uint32_t hash = _upb_Hash_NoSeed(sv.data, sv.size); + insert(&new_table.t, lookupkey, tabkey, val, hash, &strhash, &streql); + } + *t = new_table; + return true; +} + +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, _upb_log2_table_size(&t->t) + 1, a)) { + return false; + } + } + + upb_StringView sv = upb_StringView_FromDataAndSize(k, len); + upb_SizePrefixString* size_prefix_string = upb_SizePrefixString_Copy(sv, a); + if (!size_prefix_string) return false; + + lookupkey_t lookupkey = {.str = sv}; + upb_key key = {.str = size_prefix_string}; + uint32_t hash = _upb_Hash_NoSeed(k, len); + insert(&t->t, lookupkey, key, v, hash, &strhash, &streql); + return true; +} + +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); +} + +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return rm(&t->t, strkey2(key, len), val, hash, &streql); +} + +/* Iteration */ + +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} + +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} + +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return _upb_table_done(&i->t->t, i->index); +} + +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return upb_key_strview(str_tabent(i)->key); +} + +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return str_tabent(i)->val; +} + +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} + +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; +} + +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + upb_tabent* ent; + if (_upb_tablenext(&t->t, &ent, iter)) { + *key = upb_key_strview(ent->key); + *val = ent->val; + return true; + } + return false; +} + +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + removeiter(&t->t, iter); +} + +void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v) { + t->t.entries[iter].val = v; +} + +/* upb_exttable ***************************************************************/ + +static uint32_t _upb_exttable_hash(const void* ptr, uint32_t ext_num) { + uint64_t a = (uintptr_t)ptr; + uint64_t b = ext_num; + return (uint32_t)WyhashMix(a ^ kWyhashSalt[1], b ^ _upb_Seed()); +} + +static uint32_t exthash(upb_key key, upb_value val) { + const void* ptr = (const void*)key.num; + uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(val); + return _upb_exttable_hash(ptr, ext_num); +} + +static bool exteql(upb_key k1, upb_value v1, lookupkey_t k2) { + if ((const void*)k1.num == k2.ext.ptr) { + uint32_t ext_num1 = *(const uint32_t*)upb_value_getconstptr(v1); + return ext_num1 == k2.ext.ext_num; + } + return false; +} + +bool upb_exttable_init(upb_exttable* t, size_t expected_size, upb_Arena* a) { + int size_lg2 = upb_Log2Ceiling(_upb_entries_needed_for(expected_size)); + return init(&t->t, size_lg2, a); +} + +void upb_exttable_clear(upb_exttable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} + +bool upb_exttable_resize(upb_exttable* t, size_t size_lg2, upb_Arena* a) { + upb_exttable new_table; + if (!init(&new_table.t, size_lg2, a)) return false; + + size_t i; + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash = exthash(e->key, e->val); + uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(e->val); + lookupkey_t lookupkey = extkey((const void*)e->key.num, ext_num); + insert(&new_table.t, lookupkey, e->key, e->val, hash, &exthash, &exteql); + } + + *t = new_table; + return true; +} + +bool upb_exttable_insert(upb_exttable* t, const void* k, const uint32_t* v, + upb_Arena* a) { + UPB_ASSERT(k != NULL); + UPB_ASSERT(v != NULL); + UPB_ASSERT(*v != 0); + + if (isfull(&t->t)) { + if (!upb_exttable_resize(t, _upb_log2_table_size(&t->t) + 1, a)) { + return false; + } + } + + lookupkey_t lookupkey = extkey(k, *v); + upb_key key = {.num = (uintptr_t)k}; + upb_value val = upb_value_constptr(v); + uint32_t hash = _upb_exttable_hash(k, *v); + insert(&t->t, lookupkey, key, val, hash, &exthash, &exteql); + return true; +} + +const uint32_t* upb_exttable_lookup(const upb_exttable* t, const void* k, + uint32_t ext_number) { + uint32_t hash = _upb_exttable_hash(k, ext_number); + upb_value val; + if (lookup(&t->t, extkey(k, ext_number), &val, hash, &exteql)) { + return (const uint32_t*)upb_value_getconstptr(val); + } + return NULL; +} + +const uint32_t* upb_exttable_remove(upb_exttable* t, const void* k, + uint32_t ext_number) { + uint32_t hash = _upb_exttable_hash(k, ext_number); + upb_value val; + if (rm(&t->t, extkey(k, ext_number), &val, hash, &exteql)) { + return (const uint32_t*)upb_value_getconstptr(val); + } + return NULL; +} + +size_t upb_exttable_size(const upb_exttable* t) { return t->t.count; } + +/* upb_inttable ***************************************************************/ + +static uint32_t inthash(upb_key key, upb_value val) { + UPB_UNUSED(val); + return upb_inthash(key.num); +} + +static bool inteql(upb_key k1, upb_value v1, lookupkey_t k2) { + UPB_UNUSED(v1); + return k1.num == k2.num; +} + +size_t upb_inttable_count(const upb_inttable* t) { return t->t.count; } + +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + // This check is very expensive (makes inserts/deletes O(N)). + size_t count = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + UPB_ASSERT(upb_inttable_lookup(t, key, NULL)); + count++; + } + UPB_ASSERT(count == upb_inttable_count(t)); + } +#endif +} + +static bool upb_inttable_sizedinit(upb_inttable* t, int hsize_lg2, + upb_Arena* a) { + if (!init(&t->t, hsize_lg2, a)) return false; + check(t); + return true; +} + +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 3, a); +} + +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + if (isfull(&t->t)) { + upb_table new_table; + + if (!init(&new_table, _upb_log2_table_size(&t->t) + 1, a)) { + return false; + } + + for (size_t i = begin(&t->t); i < upb_table_size(&t->t); + i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + insert(&new_table, intkey(e->key.num), e->key, e->val, + inthash(e->key, e->val), &inthash, &inteql); + } + + UPB_ASSERT(t->t.count == new_table.count); + + t->t = new_table; + } + upb_key tabkey = {.num = key}; + insert(&t->t, intkey(key), tabkey, val, upb_inthash(key), &inthash, &inteql); + check(t); + return true; +} + +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + return lookup(&t->t, intkey(key), v, upb_inthash(key), &inteql); +} + +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + if (!e) return false; + e->val = val; + return true; +} + +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success = rm(&t->t, intkey(key), val, upb_inthash(key), &inteql); + check(t); + return success; +} + +void upb_inttable_clear(upb_inttable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + upb_tabent* ent; + if (_upb_tablenext(&t->t, &ent, iter)) { + *key = ent->key.num; + *val = ent->val; + return true; + } + *iter = INTPTR_MAX - 1; + return false; +} + +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + removeiter(&t->t, iter); +} + +void upb_inttable_setentryvalue(upb_inttable* t, intptr_t iter, upb_value v) { + t->t.entries[iter].val = v; +} + +bool upb_inttable_done(const upb_inttable* t, intptr_t iter) { + return _upb_table_done(&t->t, iter); +} + +uintptr_t upb_inttable_iter_key(const upb_inttable* t, intptr_t iter) { + UPB_ASSERT(!upb_inttable_done(t, iter)); + return t->t.entries[iter].key.num; +} + +upb_value upb_inttable_iter_value(const upb_inttable* t, intptr_t iter) { + UPB_ASSERT(!upb_inttable_done(t, iter)); + return t->t.entries[iter].val; +} + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + int result; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; + +typedef struct { + upb_MessageValue value; + bool ignore; +} upb_JsonMessageValue; + +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; + +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); + +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; +} + +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; +} + +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); +} + +static void jsondec_seterrmsg(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); +} + +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + jsondec_seterrmsg(d, msg); + UPB_LONGJMP(d->err, 1); +} + +static void jsondec_checkoom(jsondec* d, bool ok) { + if (UPB_UNLIKELY(!ok)) { + jsondec_err(d, "Out of memory"); + } +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +// Advances d->ptr until the next non-whitespace character or to the end of +// the buffer. +static void jsondec_consumews(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } +} + +// Advances d->ptr until the next non-whitespace character. Postcondition that +// d->ptr is pointing at a valid non-whitespace character (will err if end of +// buffer is reached). +static void jsondec_skipws(jsondec* d) { + jsondec_consumews(d); + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF"); + } +} + +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} + +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} + +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} + +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } + +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} + +static int jsondec_rawpeek(jsondec* d) { + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF"); + } + + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + } +} + +/* JSON object/array **********************************************************/ + +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ + +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} + +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); + } + d->is_first = true; +} + +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; +} + +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} + +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} + +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); +} + +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); +} + +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; +} + +/* JSON number ****************************************************************/ + +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; + } + d->ptr++; + } + + return d->ptr != start; +} + +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } +} + +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; + + UPB_ASSERT(jsondec_rawpeek(d) == JD_NUMBER); + + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; + + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } + + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; + + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); + } + +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + // Copy the number into a null-terminated scratch buffer since strtod + // expects a null-terminated string. + char nullz[64]; + ptrdiff_t len = d->ptr - start; + if (len > (ptrdiff_t)(sizeof(nullz) - 1)) { + jsondec_err(d, "excessively long number"); + } + memcpy(nullz, start, len); + nullz[len] = '\0'; + + char* end; + double val = strtod(nullz, &end); + UPB_ASSERT(end - nullz == len); + + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } +} + +/* JSON string ****************************************************************/ + +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } +} + +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; + + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } + + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } + + return cp; +} + +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); + } + + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; +} + +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + + jsondec_checkoom(d, oldsize <= SIZE_MAX / 2); + size_t size = UPB_MAX(8, 2 * oldsize); + + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + jsondec_checkoom(d, *buf); + + *end = *buf + len; + *buf_end = *buf + size; +} + +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; + + jsondec_skipws(d); + + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } + + while (d->ptr < d->end) { + char ch = *d->ptr++; + + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } + + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; + } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized codepoint (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)ch < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; + } + } + +eof: + jsondec_err(d, "EOF inside string"); +} + +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; + } +} + +/* Base64 decoding for bytes fields. ******************************************/ + +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned char)ch]; +} + +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; + + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } + + if (val < 0) { + jsondec_err(d, "Corrupt base64"); + } + + return out; +} + +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; + } + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; +} + +/* Low-level integer parsing **************************************************/ + +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} + +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} + +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static void jsondec_checkempty(jsondec* d, upb_StringView str, + const upb_FieldDef* f) { + if (str.size != 0) return; + d->result = kUpb_JsonDecodeResult_Error; + upb_Status_SetErrorFormat(d->status, + "Empty string is not a valid number (field: %s). " + "This will be an error in a future version.", + upb_FieldDef_FullName(f)); +} + +/* Primitive value types ******************************************************/ + +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + jsondec_checkempty(d, str, f); + val.int64_val = jsondec_strtoint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; + } + + return val; +} + +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + jsondec_checkempty(d, str, f); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; + } + + return val; +} + +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (str.size == 0) { + jsondec_checkempty(d, str, f); + val.double_val = 0.0; + } else if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + char* end; + val.double_val = strtod(str.data, &end); + if (end != str.data + str.size) { + d->result = kUpb_JsonDecodeResult_Error; + upb_Status_SetErrorFormat( + d->status, + "Non-number characters in quoted number (field: %s). " + "This will be an error in a future version.", + upb_FieldDef_FullName(f)); + } + } + break; + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; + } + + return val; +} + +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); + } + return val; +} + +static upb_JsonMessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindByJsonNameWithSize(e, str.data, str.size); + upb_JsonMessageValue val = {.ignore = false}; + if (ev) { + val.value.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.ignore = true; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_JsonMessageValue val = {.ignore = false}; + jsondec_null(d); + val.value.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return (upb_JsonMessageValue){.value = jsondec_int(d, f), + .ignore = false}; + } +} + +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; + + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } + } + + return val; +} + +/* Composite types (array/message/map) ****************************************/ + +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; + jsondec_checkoom(d, arr); + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_JsonMessageValue elem = jsondec_value(d, f); + if (!elem.ignore) { + jsondec_checkoom(d, upb_Array_Append(arr, elem.value, d->arena)); + } + } + jsondec_arrend(d); +} + +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + jsondec_checkoom(d, map); + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_JsonMessageValue key, val; + key = jsondec_value(d, key_f); + UPB_ASSUME(!key.ignore); // Map key cannot be enum. + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + if (!val.ignore) { + jsondec_checkoom(d, upb_Map_Set(map, key.value, val.value, d->arena)); + } + } + jsondec_objend(d); +} + +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } +} + +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(layout, d->arena); + jsondec_checkoom(d, msg); + upb_MessageValue val; + + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} + +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; + + name = jsondec_string(d); + jsondec_entrysep(d); + + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } + + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } + + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } + + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneofByDef(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_checkoom(d, submsg); + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_JsonMessageValue val = jsondec_value(d, f); + if (!val.ignore) { + jsondec_checkoom(d, + upb_Message_SetFieldByDef(msg, f, val.value, d->arena)); + } + } + + d->debug_field = preserved; +} + +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} + +static upb_MessageValue jsondec_nonenum(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + case kUpb_CType_Enum: + default: + UPB_UNREACHABLE(); + } +} + +static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + if (upb_FieldDef_CType(f) == kUpb_CType_Enum) { + return jsondec_enum(d, f); + } else { + return (upb_JsonMessageValue){.value = jsondec_nonenum(d, f), + .ignore = false}; + } +} + +/* Well-known types ***********************************************************/ + +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; + + UPB_ASSERT(digits <= 9); /* int can't overflow. */ + + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; +} + +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; + + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; + } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; +} + +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} + +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +} + +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + + if (str.size < 20) goto malformed; + + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); + + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + } + + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; + + if (ptr == end) goto malformed; + + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } + } + + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } + + jsondec_checkoom( + d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), + seconds, d->arena)); + jsondec_checkoom( + d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), + nanos, d->arena)); + return; + +malformed: + jsondec_err(d, "Malformed timestamp"); +} + +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + bool neg = false; + + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } + + if (neg) { + nanos.int32_val = -nanos.int32_val; + } + + jsondec_checkoom( + d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), + seconds, d->arena)); + jsondec_checkoom( + d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), + nanos, d->arena)); +} + +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; + jsondec_checkoom(d, values); + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_layout, d->arena); + jsondec_checkoom(d, value_msg); + upb_MessageValue value; + value.msg_val = value_msg; + jsondec_checkoom(d, upb_Array_Append(values, value, d->arena)); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_arrend(d); +} + +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; + jsondec_checkoom(d, fields); + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_layout, d->arena); + jsondec_checkoom(d, value_msg); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + jsondec_checkoom(d, upb_Map_Set(fields, key, value, d->arena)); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_objend(d); +} + +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_checkoom(d, submsg); + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_checkoom(d, submsg); + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); + } + + jsondec_checkoom(d, upb_Message_SetFieldByDef(msg, f, val, d->arena)); +} + +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; + + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; + } + + out = upb_Arena_Malloc(d->arena, ret.size); + jsondec_checkoom(d, out || ret.size == 0); + ptr = buf; + ret.data = out; + + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } + } + + return ret; +} + +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + jsondec_checkoom(d, arr); + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; + } + jsondec_checkoom(d, upb_Array_Append(arr, val, d->arena)); + } +} + +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); + } else { + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); + } +} + +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; + + val.str_val = type_url; + jsondec_checkoom(d, + upb_Message_SetFieldByDef(msg, type_url_f, val, d->arena)); + + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } + + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } + + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + + if (!type_m) { + jsondec_err(d, "Type was not found"); + } + + return type_m; +} + +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; + + jsondec_objstart(d); + + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); + } + } + + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } + + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + any_msg = upb_Message_New(any_layout, d->arena); + jsondec_checkoom(d, any_msg); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + jsondec_checkoom(d, tmp); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + d->ptr = saved_ptr; + d->end = saved_end; + } + + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + + jsondec_objend(d); + + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + if (status != kUpb_EncodeStatus_Ok) { + jsondec_errf(d, "Encode failed: %s", upb_EncodeStatus_String(status)); + } + jsondec_checkoom(d, + upb_Message_SetFieldByDef(msg, value_f, encoded, d->arena)); +} + +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_JsonMessageValue val = jsondec_value(d, value_f); + UPB_ASSUME(val.ignore == false); // Wrapper cannot be an enum. + jsondec_checkoom( + d, upb_Message_SetFieldByDef(msg, value_f, val.value, d->arena)); +} + +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); + } +} + +static int upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg, + const upb_MessageDef* const m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (UPB_SETJMP(d->err)) return kUpb_JsonDecodeResult_Error; + + jsondec_tomsg(d, msg, m); + + // Consume any trailing whitespace before checking if we read the entire + // input. + jsondec_consumews(d); + + if (d->ptr == d->end) { + return d->result; + } else { + jsondec_seterrmsg(d, "unexpected trailing characters"); + return kUpb_JsonDecodeResult_Error; + } +} + +int upb_JsonDecodeDetectingNonconformance(const char* buf, size_t size, + upb_Message* msg, + const upb_MessageDef* m, + const upb_DefPool* symtab, + int options, upb_Arena* arena, + upb_Status* status) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + jsondec d; + + if (size == 0) return true; + + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.result = kUpb_JsonDecodeResult_Ok; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; + + return upb_JsonDecoder_Decode(&d, msg, m); +} + + +#include +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_string(jsonenc* e, upb_StringView str); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + UPB_LONGJMP(e->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(e->err, 1); +} + +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} + +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} + +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} + +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); + } +} + +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; + + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } + + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } + + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} + +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; + + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); + } + + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; + + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); +} + +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; + bool negative = false; + + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); + } + + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } + + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); +} + +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + const char* name = upb_EnumValueDef_JsonName(ev); + jsonenc_string(e, upb_StringView_FromString(name)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } +} + +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; + + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); + + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } +} + +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} + +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } + return true; +} + +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_GetFieldByDef(msg, val_f); + jsonenc_scalar(e, val, val_f); +} + +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; + + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; + + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} + +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_GetFieldByDef(msg, type_url_f).str_val; + upb_StringView value = upb_Message_GetFieldByDef(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_layout, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, + "Field mask path containing an uppercase letter cannot be " + "successfully round tripped through JSON format. See " + "https://github.com/protocolbuffers/protobuf/issues/25786"); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, + "Underscore in FieldMask path must be followed by a " + "lowercase letter to successfully round trip through JSON " + "format. See " + "https://github.com/protocolbuffers/protobuf/issues/25786"); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_GetFieldByDef(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_GetFieldByDef(msg, fields_f).map_val; + + if (fields) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + + size_t iter = kUpb_Map_Begin; + bool first = true; + + upb_MessageValue key, val; + while (upb_Map_Next(fields, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_GetFieldByDef(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO: do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + if (upb_JsonEncode_HandleSpecialDoubles(e, val.double_val)) { + jsonenc_err( + e, + "google.protobuf.Value cannot encode double values for " + "infinity or nan, because they would be parsed as a string"); + } + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + jsonenc_putstr(e, "{"); + + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + if (map) { + size_t iter = kUpb_Map_Begin; + bool first = true; + + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, key, key_f); + jsonenc_scalar(e, val, val_f); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); + } + + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} + +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; + + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_HasFieldByDef(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_GetFieldByDef(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +static size_t upb_JsonEncoder_Encode(jsonenc* const e, + const upb_Message* const msg, + const upb_MessageDef* const m, + const size_t size) { + if (UPB_SETJMP(e->err) != 0) return -1; + + jsonenc_msgfield(e, msg, m); + if (e->arena) upb_Arena_Free(e->arena); + return jsonenc_nullz(e, size); +} + +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; + + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; + + return upb_JsonEncoder_Encode(&e, msg, m, size); +} + + +// Must be last. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + return NULL; // integer overflow + } + u64 *= 10; + u64 += ch; + ptr++; + } + + *val = u64; + return ptr; +} + +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; + } + + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow + } + + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; + return ptr; +} + + +#include +#include +#include +#include + +// Must be last. + +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + if (isnan(val)) { + snprintf(buf, size, "%s", "nan"); + return; + } + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + if (isnan(val)) { + snprintf(buf, size, "%s", "nan"); + return; + } + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); +} + + +// Must be last. + +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; + return 2; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; + return 3; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; + return 4; + } + return 0; +} + + +#include + +// Must be last. + +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size, size_t* actual_size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + UPB_UNUSED(actual_size); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); + } +} + +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + + +#include + + +#ifdef UPB_TRACING_ENABLED +#include +#endif + +#include +#include +#include + + +// Must be last. + +static UPB_ATOMIC(size_t) g_max_block_size = UPB_DEFAULT_MAX_BLOCK_SIZE; + +void upb_Arena_SetMaxBlockSize(size_t max) { + UPB_ASSERT(max <= UINT32_MAX); + upb_Atomic_Store(&g_max_block_size, max, memory_order_relaxed); +} + +typedef struct upb_MemBlock { + struct upb_MemBlock* next; + // Size of the actual allocation. + // Size of 0 means this is a upb_ArenaRef. + size_t size; + // Data follows. +} upb_MemBlock; + +// A special block type that indicates a reference to another arena. +// When this arena is freed, a ref is released on the referenced arena. +// size must be 0. +typedef struct upb_ArenaRef { + upb_MemBlock prefix; // size is always zero + const upb_Arena* arena; +#ifndef NDEBUG + const struct upb_ArenaRef* next_ref; +#endif +} upb_ArenaRef; + +typedef struct upb_ArenaInternal { + // upb_alloc* together with a low bit which signals if there is an initial + // block. + uintptr_t block_alloc; + + // Linked list of blocks to free/cleanup. + upb_MemBlock* blocks; + +#ifndef NDEBUG + // Stack of pointers to other arenas that this arena owns. + // Used for debug-only ref cycle checks. + UPB_ATOMIC(const upb_ArenaRef*) refs; +#endif + + // Size of the last block we allocated in the normal exponential scheme. + uint32_t last_block_size; + + // A hint that grows whenever we perform a "one-off" allocation into a a + // dedicated block. This helps us determine if these outlier blocks are + // actually common enough that we should switch back to the normal exponential + // scheme at the larger size. + uint32_t size_hint; + + // All non atomic members used during allocation must be above this point, and + // are used by _SwapIn/_SwapOut + + // Total space allocated in blocks, atomic only for SpaceAllocated + UPB_ATOMIC(uintptr_t) space_allocated; + + // The cleanup for the allocator. This is called after all the blocks are + // freed in an arena. + upb_AllocCleanupFunc* upb_alloc_cleanup; + + // When multiple arenas are fused together, each arena points to a parent + // arena (root points to itself). The root tracks how many live arenas + // reference it. + + // The low bit is tagged: + // 0: pointer to parent + // 1: count, left shifted by one + UPB_ATOMIC(uintptr_t) parent_or_count; + + // All nodes that are fused together are in a singly-linked list. + // == NULL at end of list. + UPB_ATOMIC(struct upb_ArenaInternal*) next; + + // - If the low bit is set, is a pointer to the tail of the list (populated + // for roots, set to self for roots with no fused arenas). This is best + // effort, and it may not always reflect the true tail, but it will always + // be a valid node in the list. This is useful for finding the list tail + // without having to walk the entire list. + // - If the low bit is not set, is a pointer to the previous node in the list, + // such that a->previous_or_tail->next == a. + UPB_ATOMIC(uintptr_t) previous_or_tail; + + // We use a different UPB_XSAN_MEMBER than the one in upb_Arena because the + // two are distinct synchronization domains. The upb_Arena.ptr member is + // not published in the allocation path, so it is not synchronized with + // respect to operations performed in this file such as Fuse, Free, + // SpaceAllocated, etc. This means that it is not safe to read or write + // the upb_Arena.ptr member in those functions. + UPB_XSAN_MEMBER +} upb_ArenaInternal; + +// All public + private state for an arena. +typedef struct { + upb_Arena head; + upb_ArenaInternal body; +} upb_ArenaState; + +typedef struct { + upb_ArenaInternal* root; + uintptr_t tagged_count; +} upb_ArenaRoot; + +static const size_t kUpb_MemblockReserve = + UPB_ALIGN_MALLOC(sizeof(upb_MemBlock)); + +static const size_t kUpb_ArenaStateReserve = + UPB_ALIGN_MALLOC(sizeof(upb_ArenaState)); + +static const size_t kUpb_ArenaRefReserve = + UPB_ALIGN_MALLOC(sizeof(upb_ArenaRef)); + +// Extracts the (upb_ArenaInternal*) from a (upb_Arena*) +static upb_ArenaInternal* upb_Arena_Internal(const upb_Arena* a) { + return &((upb_ArenaState*)a)->body; +} + +static bool _upb_Arena_IsTaggedRefcount(uintptr_t parent_or_count) { + return (parent_or_count & 1) == 1; +} + +static bool _upb_Arena_IsTaggedPointer(uintptr_t parent_or_count) { + return (parent_or_count & 1) == 0; +} + +static uintptr_t _upb_Arena_RefCountFromTagged(uintptr_t parent_or_count) { + UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); + return parent_or_count >> 1; +} + +static uintptr_t _upb_Arena_TaggedFromRefcount(uintptr_t refcount) { + uintptr_t parent_or_count = (refcount << 1) | 1; + UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); + return parent_or_count; +} + +static upb_ArenaInternal* _upb_Arena_PointerFromTagged( + uintptr_t parent_or_count) { + UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); + return (upb_ArenaInternal*)parent_or_count; +} + +static uintptr_t _upb_Arena_TaggedFromPointer(upb_ArenaInternal* ai) { + uintptr_t parent_or_count = (uintptr_t)ai; + UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); + return parent_or_count; +} + +static bool _upb_Arena_IsTaggedTail(uintptr_t previous_or_tail) { + return (previous_or_tail & 1) == 1; +} + +static bool _upb_Arena_IsTaggedPrevious(uintptr_t previous_or_tail) { + return (previous_or_tail & 1) == 0; +} + +static upb_ArenaInternal* _upb_Arena_TailFromTagged( + uintptr_t previous_or_tail) { + UPB_ASSERT(_upb_Arena_IsTaggedTail(previous_or_tail)); + return (upb_ArenaInternal*)(previous_or_tail ^ 1); +} + +static uintptr_t _upb_Arena_TaggedFromTail(upb_ArenaInternal* tail) { + uintptr_t previous_or_tail = (uintptr_t)tail | 1; + UPB_ASSERT(_upb_Arena_IsTaggedTail(previous_or_tail)); + return previous_or_tail; +} + +static upb_ArenaInternal* _upb_Arena_PreviousFromTagged( + uintptr_t previous_or_tail) { + UPB_ASSERT(_upb_Arena_IsTaggedPrevious(previous_or_tail)); + return (upb_ArenaInternal*)previous_or_tail; +} + +static uintptr_t _upb_Arena_TaggedFromPrevious(upb_ArenaInternal* ai) { + uintptr_t previous = (uintptr_t)ai; + UPB_ASSERT(_upb_Arena_IsTaggedPrevious(previous)); + return previous; +} + +static upb_alloc* _upb_ArenaInternal_BlockAlloc(upb_ArenaInternal* ai) { + return (upb_alloc*)(ai->block_alloc & ~0x1); +} + +static uintptr_t _upb_Arena_MakeBlockAlloc(upb_alloc* alloc, bool has_initial) { + uintptr_t alloc_uint = (uintptr_t)alloc; + UPB_ASSERT((alloc_uint & 1) == 0); + return alloc_uint | (has_initial ? 1 : 0); +} + +static bool _upb_ArenaInternal_HasInitialBlock(upb_ArenaInternal* ai) { + return ai->block_alloc & 0x1; +} + +#ifdef UPB_TRACING_ENABLED +static void (*_init_arena_trace_handler)(const upb_Arena*, size_t size) = NULL; +static void (*_fuse_arena_trace_handler)(const upb_Arena*, + const upb_Arena*) = NULL; +static void (*_free_arena_trace_handler)(const upb_Arena*) = NULL; + +void upb_Arena_SetTraceHandler( + void (*initArenaTraceHandler)(const upb_Arena*, size_t size), + void (*fuseArenaTraceHandler)(const upb_Arena*, const upb_Arena*), + void (*freeArenaTraceHandler)(const upb_Arena*)) { + _init_arena_trace_handler = initArenaTraceHandler; + _fuse_arena_trace_handler = fuseArenaTraceHandler; + _free_arena_trace_handler = freeArenaTraceHandler; +} + +void upb_Arena_LogInit(const upb_Arena* arena, size_t size) { + if (_init_arena_trace_handler) { + _init_arena_trace_handler(arena, size); + } +} +void upb_Arena_LogFuse(const upb_Arena* arena1, const upb_Arena* arena2) { + if (_fuse_arena_trace_handler) { + _fuse_arena_trace_handler(arena1, arena2); + } +} +void upb_Arena_LogFree(const upb_Arena* arena) { + if (_free_arena_trace_handler) { + _free_arena_trace_handler(arena); + } +} +#endif // UPB_TRACING_ENABLED + +// If the param a is already the root, provides no memory order of refcount. +// If it has a parent, then acquire memory order is provided for both the root +// and the refcount. Thread safe. +static upb_ArenaRoot _upb_Arena_FindRoot(upb_ArenaInternal* ai) { + uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_relaxed); + if (_upb_Arena_IsTaggedRefcount(poc)) { + // Fast, relaxed path - arenas that have never been fused to a parent only + // need relaxed memory order, since they're returning themselves and the + // refcount. + return (upb_ArenaRoot){.root = ai, .tagged_count = poc}; + } + // Slow path needs acquire order; reloading is cheaper than a fence on ARM + // (LDA vs DMB ISH). Even though this is a reread, we know it must be a tagged + // pointer because if this Arena isn't a root, it can't ever become one. + poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + do { + upb_ArenaInternal* next = _upb_Arena_PointerFromTagged(poc); + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(next)); + UPB_ASSERT(ai != next); + poc = upb_Atomic_Load(&next->parent_or_count, memory_order_acquire); + + if (_upb_Arena_IsTaggedPointer(poc)) { + // To keep complexity down, we lazily collapse levels of the tree. This + // keeps it flat in the final case, but doesn't cost much incrementally. + // + // Path splitting keeps time complexity down, see: + // https://en.wikipedia.org/wiki/Disjoint-set_data_structure + UPB_ASSERT(ai != _upb_Arena_PointerFromTagged(poc)); + upb_Atomic_Store(&ai->parent_or_count, poc, memory_order_release); + } + ai = next; + } while (_upb_Arena_IsTaggedPointer(poc)); + return (upb_ArenaRoot){.root = ai, .tagged_count = poc}; +} + +uintptr_t upb_Arena_SpaceAllocated(const upb_Arena* arena, + size_t* fused_count) { + upb_ArenaInternal* ai = upb_Arena_Internal(arena); + uintptr_t memsize = 0; + size_t local_fused_count = 0; + // Our root would get updated by any racing fuses before our target arena + // became reachable from the root via the linked list; in order to preserve + // monotonic output (any arena counted by a previous invocation is counted by + // this one), we instead iterate forwards and backwards so that we only see + // the results of completed fuses. + uintptr_t previous_or_tail = + upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); + while (_upb_Arena_IsTaggedPrevious(previous_or_tail)) { + upb_ArenaInternal* previous = + _upb_Arena_PreviousFromTagged(previous_or_tail); + UPB_ASSERT(previous != ai); + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(previous)); + // Unfortunate macro behavior; prior to C11 when using nonstandard atomics + // this returns a void* and can't be used with += without an intermediate + // conversion to an integer. + // Relaxed is safe - no subsequent reads depend this one + uintptr_t allocated = + upb_Atomic_Load(&previous->space_allocated, memory_order_relaxed); + memsize += allocated; + previous_or_tail = + upb_Atomic_Load(&previous->previous_or_tail, memory_order_acquire); + local_fused_count++; + } + while (ai != NULL) { + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); + // Unfortunate macro behavior; prior to C11 when using nonstandard atomics + // this returns a void* and can't be used with += without an intermediate + // conversion to an integer. + // Relaxed is safe - no subsequent reads depend this one + uintptr_t allocated = + upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed); + memsize += allocated; + ai = upb_Atomic_Load(&ai->next, memory_order_acquire); + local_fused_count++; + } + + if (fused_count) *fused_count = local_fused_count; + return memsize; +} + +uint32_t upb_Arena_DebugRefCount(const upb_Arena* a) { + uintptr_t tagged = _upb_Arena_FindRoot(upb_Arena_Internal(a)).tagged_count; + return (uint32_t)_upb_Arena_RefCountFromTagged(tagged); +} + +#if UPB_ENABLE_REF_CYCLE_CHECKS + +bool upb_Arena_HasRefChain(const upb_Arena* from, const upb_Arena* to) { + upb_ArenaInternal* ai = upb_Arena_Internal(from); + upb_ArenaInternal* current; + + if (upb_Arena_IsFused(from, to)) return true; + + // 1. Traverse backward to the start of a consistent segment. + uintptr_t previous_or_tail = + upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); + while (_upb_Arena_IsTaggedPrevious(previous_or_tail)) { + ai = _upb_Arena_PreviousFromTagged(previous_or_tail); + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); + previous_or_tail = + upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); + } + + // 2. Traverse forward through all arenas in the fuse group. + current = ai; + while (current != NULL) { + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(current)); + const upb_ArenaRef* ref = + upb_Atomic_Load(¤t->refs, memory_order_acquire); + while (ref != NULL) { + if (ref->arena == to || upb_Arena_HasRefChain(ref->arena, to)) { + return true; + } + ref = ref->next_ref; + } + current = upb_Atomic_Load(¤t->next, memory_order_acquire); + } + return false; +} + +#endif + +static void* _upb_Arena_AllocBlockInternal(upb_alloc* alloc, size_t* size) { + size_t sz = *size + kUpb_MemblockReserve; + upb_SizedPtr alloc_result = upb_SizeReturningMalloc(alloc, sz); + if (!alloc_result.p) return NULL; + upb_MemBlock* block = alloc_result.p; + block->size = alloc_result.n; + *size = alloc_result.n - kUpb_MemblockReserve; + return UPB_PTR_AT(block, kUpb_MemblockReserve, void); +} + +void* UPB_PRIVATE(_upb_Arena_AllocBlock)(upb_Arena* a, size_t* size) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); +#if UPB_HWASAN + *size = UPB_ALIGN_UP(*size, UPB_MALLOC_ALIGN); +#endif + void* ret = + _upb_Arena_AllocBlockInternal(_upb_ArenaInternal_BlockAlloc(ai), size); +#if UPB_HWASAN + if (ret) *size = UPB_ALIGN_DOWN(*size, UPB_MALLOC_ALIGN); +#endif + return ret; +} + +void UPB_PRIVATE(_upb_Arena_AddBlock)(upb_Arena* a, void* block) { + upb_MemBlock* b = (upb_MemBlock*)((char*)block - kUpb_MemblockReserve); + upb_ArenaInternal* ai = upb_Arena_Internal(a); + + // Atomic add not required here, as threads won't race allocating blocks, plus + // atomic fetch-add is slower than load/add/store on arm devices compiled + // targeting pre-v8.1. Relaxed order is safe as nothing depends on order of + // size allocated. + uintptr_t old_space_allocated = + upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed); + upb_Atomic_Store(&ai->space_allocated, old_space_allocated + b->size, + memory_order_relaxed); + + b->next = ai->blocks; + ai->blocks = b; +} + +void UPB_PRIVATE(_upb_Arena_UseBlock)(upb_Arena* a, void* ptr, size_t size) { + UPB_ASSERT(UPB_ALIGN_DOWN((uintptr_t)ptr, UPB_MALLOC_ALIGN) == + (uintptr_t)ptr); +#if UPB_HWASAN + size = UPB_ALIGN_DOWN(size, UPB_MALLOC_ALIGN); +#endif + if (size <= UPB_PRIVATE(_upb_ArenaHas)(a)) return; + a->UPB_ONLYBITS(ptr) = ptr; + a->UPB_ONLYBITS(end) = UPB_PTR_AT(ptr, size, char); + UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, size); +} + +static bool _upb_Arena_WouldReduceFreeSpace(upb_Arena* a, size_t span, + size_t block_size) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + size_t current_free = + ai->blocks ? a->UPB_PRIVATE(end) - a->UPB_PRIVATE(ptr) : 0; + size_t future_free = block_size - span; + return current_free >= future_free; +} + +size_t UPB_PRIVATE(_upb_Arena_NextBlockSize)(upb_Arena* a, size_t span, + bool* one_off) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + bool is_one_off = false; + + size_t max_block_size = + upb_Atomic_Load(&g_max_block_size, memory_order_relaxed); + size_t block_size = UPB_MIN(ai->last_block_size * 2, max_block_size); + + if (span > block_size) { + block_size = UPB_MIN(ai->size_hint * 2, max_block_size); + if (span > block_size) { + is_one_off = true; + } + } + + is_one_off = + is_one_off || _upb_Arena_WouldReduceFreeSpace(a, span, block_size); + + if (is_one_off) { + block_size = span; + } + + if (one_off) *one_off = is_one_off; + return block_size; +} + +void UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(upb_Arena* a, size_t span, + size_t block_size, + bool one_off) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + size_t max_block_size = + upb_Atomic_Load(&g_max_block_size, memory_order_relaxed); + if (one_off) { + ai->size_hint = UPB_MIN(ai->size_hint + (span >> 1), max_block_size >> 1); + } else { + ai->last_block_size = UPB_MIN(block_size, UINT32_MAX); + ai->size_hint = ai->last_block_size; + } +} + +// Fulfills the allocation request by allocating a new block. Returns NULL on +// allocation failure. +void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(upb_Arena* a, size_t span) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + if (!_upb_ArenaInternal_BlockAlloc(ai)) return NULL; + + bool one_off = false; + size_t block_size = UPB_PRIVATE(_upb_Arena_NextBlockSize)(a, span, &one_off); + + void* block = UPB_PRIVATE(_upb_Arena_AllocBlock)(a, &block_size); + if (!block) return NULL; + UPB_PRIVATE(_upb_Arena_AddBlock)(a, block); + size_t size = span - UPB_PRIVATE(kUpb_Asan_GuardSize); + + // Recheck size, in case the allocator gave us a much larger block than we + // requested and we want to make it the new allocating region. + if (one_off && !_upb_Arena_WouldReduceFreeSpace(a, span, block_size)) { + one_off = false; + } + + UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(a, span, block_size, one_off); + + if (one_off) { + UPB_PRIVATE(upb_Xsan_PoisonRegion)(UPB_PTR_AT(block, size, void), + block_size - size); + return block; + } else { + UPB_PRIVATE(_upb_Arena_UseBlock)(a, block, block_size); + UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >= span); + return upb_Arena_Malloc(a, size); + } +} + +static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc, size_t first_size) { + if (!alloc) return NULL; + + // We need to malloc the initial block. + size_t block_size = kUpb_ArenaStateReserve + + UPB_MAX(256, UPB_ALIGN_MALLOC(first_size) + + UPB_PRIVATE(kUpb_Asan_GuardSize)); + void* block = _upb_Arena_AllocBlockInternal(alloc, &block_size); + if (!block) return NULL; + + // Initialize the arena state in the first block. We "borrow" the memory from + // the block, because we can't yet call upb_Arena_Malloc. + upb_ArenaState* a = block; + a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 0); + a->body.last_block_size = UPB_MIN(block_size, UINT32_MAX); + a->body.size_hint = UPB_MIN(block_size, UINT32_MAX); + a->head.UPB_ONLYBITS(ptr) = NULL; + a->head.UPB_ONLYBITS(end) = NULL; + + upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); + upb_Atomic_Init(&a->body.next, NULL); + upb_Atomic_Init(&a->body.previous_or_tail, + _upb_Arena_TaggedFromTail(&a->body)); + upb_Atomic_Init(&a->body.space_allocated, 0); + a->body.blocks = NULL; +#ifndef NDEBUG + a->body.refs = NULL; +#endif + a->body.upb_alloc_cleanup = NULL; + UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body)); + + UPB_PRIVATE(_upb_Arena_AddBlock)(&a->head, block); + + block = UPB_PTR_AT(block, kUpb_ArenaStateReserve, void); + block_size -= kUpb_ArenaStateReserve; + UPB_PRIVATE(_upb_Arena_UseBlock)(&a->head, block, block_size); + + return &a->head; +} + +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + UPB_STATIC_ASSERT(UPB_ARENA_SIZE_HACK >= sizeof(upb_ArenaState), + "Need to update UPB_ARENA_SIZE_HACK"); + upb_ArenaState* a; + + if (mem) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_MALLOC((uintptr_t)mem); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; + } + if (UPB_UNLIKELY(n < sizeof(upb_ArenaState) || !mem)) { + upb_Arena* ret = _upb_Arena_InitSlow(alloc, mem ? 0 : n); +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogInit(ret, n); +#endif + return ret; + } + + a = mem; + + upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); + upb_Atomic_Init(&a->body.next, NULL); + upb_Atomic_Init(&a->body.previous_or_tail, + _upb_Arena_TaggedFromTail(&a->body)); + upb_Atomic_Init(&a->body.space_allocated, 0); + a->body.blocks = NULL; +#ifndef NDEBUG + a->body.refs = NULL; +#endif + a->body.size_hint = 128; + a->body.last_block_size = 128; + a->body.upb_alloc_cleanup = NULL; + a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 1); + a->head.UPB_PRIVATE(ptr) = (void*)UPB_ALIGN_MALLOC((uintptr_t)(a + 1)); + a->head.UPB_PRIVATE(end) = UPB_PTR_AT(mem, n, char); + UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body)); +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogInit(&a->head, n); +#endif + return &a->head; +} + +static void _upb_Arena_DoFree(upb_ArenaInternal* ai) { + UPB_ASSERT(_upb_Arena_RefCountFromTagged(ai->parent_or_count) == 1); + while (ai != NULL) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(ai)); + // Load first since arena itself is likely from one of its blocks. Relaxed + // order is safe because fused arena ordering is provided by the reference + // count, and fuse is not permitted to race with the final decrement. + upb_ArenaInternal* next_arena = + (upb_ArenaInternal*)upb_Atomic_Load(&ai->next, memory_order_relaxed); + // Freeing may have memory barriers that confuse tsan, so assert immediately + // after load here + if (next_arena) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(next_arena)); + } + upb_alloc* block_alloc = _upb_ArenaInternal_BlockAlloc(ai); + upb_MemBlock* block = ai->blocks; + upb_AllocCleanupFunc* alloc_cleanup = ai->upb_alloc_cleanup; + while (block != NULL) { + // Load first since we are deleting block. + upb_MemBlock* next_block = block->next; + if (block->size == 0) { + // If the block is an arena ref, then we need to release our ref on the + // referenced arena. + upb_ArenaRef* ref = (upb_ArenaRef*)block; + upb_Arena_DecRefFor((upb_Arena*)ref->arena, ai); + } else { + upb_free_sized(block_alloc, block, block->size); + } + block = next_block; + } + if (alloc_cleanup != NULL) { + alloc_cleanup(block_alloc); + } + ai = next_arena; + } +} + +void upb_Arena_Free(upb_Arena* a) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + // Cannot be replaced with _upb_Arena_FindRoot, as that provides only a + // relaxed read of the refcount if ai is already the root. + uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); +retry: + while (_upb_Arena_IsTaggedPointer(poc)) { + ai = _upb_Arena_PointerFromTagged(poc); + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); + poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); + } + + // compare_exchange or fetch_sub are RMW operations, which are more + // expensive then direct loads. As an optimization, we only do RMW ops + // when we need to update things for other threads to see. + if (poc == _upb_Arena_TaggedFromRefcount(1)) { +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogFree(a); +#endif + _upb_Arena_DoFree(ai); + return; + } + + if (upb_Atomic_CompareExchangeWeak( + &ai->parent_or_count, &poc, + _upb_Arena_TaggedFromRefcount(_upb_Arena_RefCountFromTagged(poc) - 1), + memory_order_release, memory_order_acquire)) { + // We were >1 and we decremented it successfully, so we are done. + return; + } + + // We failed our update, so someone has done something, retry the whole + // process, but the failed exchange reloaded `poc` for us. + goto retry; +} + +// Logically performs the following operation, in a way that is safe against +// racing fuses: +// ret = TAIL(parent) +// ret->next = child +// return ret +// +// The caller is therefore guaranteed that ret->next == child. +static upb_ArenaInternal* _upb_Arena_LinkForward( + upb_ArenaInternal* const parent, upb_ArenaInternal* child) { + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent)); + uintptr_t parent_previous_or_tail = + upb_Atomic_Load(&parent->previous_or_tail, memory_order_acquire); + + // Optimization: use parent->previous_or_tail to skip to TAIL(parent) in O(1) + // time when possible. This is the common case because we just fused into + // parent, suggesting that it should be a root with a cached tail. + // + // However, if there was a racing fuse, parent may no longer be a root, in + // which case we need to walk the entire list to find the tail. The tail + // pointer is also not guaranteed to be the true tail, so even when the + // optimization is taken, we still need to walk list nodes to find the true + // tail. + upb_ArenaInternal* parent_tail = + _upb_Arena_IsTaggedTail(parent_previous_or_tail) + ? _upb_Arena_TailFromTagged(parent_previous_or_tail) + : parent; + + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent_tail)); + upb_ArenaInternal* parent_tail_next = + upb_Atomic_Load(&parent_tail->next, memory_order_acquire); + + do { + // Walk the list to find the true tail (a node with next == NULL). + while (parent_tail_next != NULL) { + parent_tail = parent_tail_next; + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent_tail)); + parent_tail_next = + upb_Atomic_Load(&parent_tail->next, memory_order_acquire); + } + } while (!upb_Atomic_CompareExchangeWeak( // Replace a NULL next with child. + &parent_tail->next, &parent_tail_next, child, memory_order_release, + memory_order_acquire)); + + return parent_tail; +} + +// Updates parent->previous_or_tail = child->previous_or_tail in hopes that the +// latter represents the true tail of the newly-combined list. +// +// This is a best-effort operation that may set the tail to a stale value, and +// may fail to update the tail at all. +void _upb_Arena_UpdateParentTail(upb_ArenaInternal* parent, + upb_ArenaInternal* child) { + // We are guaranteed that child->previous_or_tail is tagged, because we have + // just transitioned child from root -> non-root, which is an exclusive + // operation that can only happen once. So we are the exclusive updater of + // child->previous_or_tail that can transition it from tagged to untagged. + // + // However, we are not guaranteed that child->previous_or_tail is the true + // tail. A racing fuse may have appended to child's list but not yet updated + // child->previous_or_tail. + uintptr_t child_previous_or_tail = + upb_Atomic_Load(&child->previous_or_tail, memory_order_acquire); + upb_ArenaInternal* new_parent_tail = + _upb_Arena_TailFromTagged(child_previous_or_tail); + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(new_parent_tail)); + + // If another thread fused with parent, such that it is no longer a root, + // don't overwrite their previous pointer with our tail. Relaxed order is fine + // here as we only inspect the tag bit. + uintptr_t parent_previous_or_tail = + upb_Atomic_Load(&parent->previous_or_tail, memory_order_relaxed); + if (_upb_Arena_IsTaggedTail(parent_previous_or_tail)) { + upb_Atomic_CompareExchangeStrong( + &parent->previous_or_tail, &parent_previous_or_tail, + _upb_Arena_TaggedFromTail(new_parent_tail), memory_order_release, + memory_order_relaxed); + } +} + +static void _upb_Arena_LinkBackward(upb_ArenaInternal* child, + upb_ArenaInternal* old_parent_tail) { + // Link child to parent going backwards, for SpaceAllocated. This transitions + // child->previous_or_tail from tail (tagged) to previous (untagged), after + // which its value is immutable. + // + // - We are guaranteed that no other threads are also attempting to perform + // this transition (tail -> previous), because we just updated + // old_parent_tail->next from NULL to non-NULL, an exclusive operation that + // can only happen once. + // + // - _upb_Arena_UpdateParentTail() uses CAS to ensure that it + // does not perform the reverse transition (previous -> tail). + // + // - We are guaranteed that old_parent_tail is the correct "previous" pointer, + // even in the presence of racing fuses that are adding more nodes to the + // list, because _upb_Arena_LinkForward() guarantees that: + // old_parent_tail->next == child. + upb_Atomic_Store(&child->previous_or_tail, + _upb_Arena_TaggedFromPrevious(old_parent_tail), + memory_order_release); +} + +static void _upb_Arena_DoFuseArenaLists(upb_ArenaInternal* const parent, + upb_ArenaInternal* child) { + upb_ArenaInternal* old_parent_tail = _upb_Arena_LinkForward(parent, child); + _upb_Arena_UpdateParentTail(parent, child); + _upb_Arena_LinkBackward(child, old_parent_tail); +} + +void upb_Arena_SetAllocCleanup(upb_Arena* a, upb_AllocCleanupFunc* func) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + upb_ArenaInternal* ai = upb_Arena_Internal(a); + UPB_ASSERT(ai->upb_alloc_cleanup == NULL); + ai->upb_alloc_cleanup = func; +} + +// Thread safe. +static upb_ArenaInternal* _upb_Arena_DoFuse(upb_ArenaInternal** ai1, + upb_ArenaInternal** ai2, + uintptr_t* ref_delta) { + // `parent_or_count` has two distinct modes + // - parent pointer mode + // - refcount mode + // + // In parent pointer mode, it may change what pointer it refers to in the + // tree, but it will always approach a root. Any operation that walks the + // tree to the root may collapse levels of the tree concurrently. + upb_ArenaRoot r1 = _upb_Arena_FindRoot(*ai1); + upb_ArenaRoot r2 = _upb_Arena_FindRoot(*ai2); + + if (r1.root == r2.root) return r1.root; // Already fused. + + *ai1 = r1.root; + *ai2 = r2.root; + + // Avoid cycles by always fusing into the root with the lower address. + if ((uintptr_t)r1.root > (uintptr_t)r2.root) { + upb_ArenaRoot tmp = r1; + r1 = r2; + r2 = tmp; + } + + // The moment we install `r1` as the parent for `r2` all racing frees may + // immediately begin decrementing `r1`'s refcount (including pending + // increments to that refcount and their frees!). We need to add `r2`'s refs + // now, so that `r1` can withstand any unrefs that come from r2. + // + // Note that while it is possible for `r2`'s refcount to increase + // asynchronously, we will not actually do the reparenting operation below + // unless `r2`'s refcount is unchanged from when we read it. + // + // Note that we may have done this previously, either to this node or a + // different node, during a previous and failed DoFuse() attempt. But we will + // not lose track of these refs because we always add them to our overall + // delta. + uintptr_t r2_untagged_count = r2.tagged_count & ~1; + uintptr_t with_r2_refs = r1.tagged_count + r2_untagged_count; + if (!upb_Atomic_CompareExchangeStrong( + &r1.root->parent_or_count, &r1.tagged_count, with_r2_refs, + memory_order_release, memory_order_acquire)) { + return NULL; + } + + // Perform the actual fuse by removing the refs from `r2` and swapping in the + // parent pointer. + if (!upb_Atomic_CompareExchangeStrong( + &r2.root->parent_or_count, &r2.tagged_count, + _upb_Arena_TaggedFromPointer(r1.root), memory_order_release, + memory_order_acquire)) { + // We'll need to remove the excess refs we added to r1 previously. + *ref_delta += r2_untagged_count; + return NULL; + } + + // Now that the fuse has been performed (and can no longer fail) we need to + // append `r2` to `r1`'s linked list. + _upb_Arena_DoFuseArenaLists(r1.root, r2.root); + return r1.root; +} + +// Thread safe. +static bool _upb_Arena_FixupRefs(upb_ArenaInternal* new_root, + uintptr_t ref_delta) { + if (ref_delta == 0) return true; // No fixup required. + // Relaxed order is safe here as if the value is a pointer, we don't deref it + // or publish it anywhere else. The refcount does provide memory order + // between allocations on arenas and the eventual free and thus normally + // requires acquire/release; but in this case any edges provided by the refs + // we are cleaning up were already provided by the fuse operation itself. It's + // not valid for a decrement that could cause the overall fused arena to reach + // a zero refcount to race with this function, as that could result in a + // use-after-free anyway. + uintptr_t poc = + upb_Atomic_Load(&new_root->parent_or_count, memory_order_relaxed); + if (_upb_Arena_IsTaggedPointer(poc)) return false; + uintptr_t with_refs = poc - ref_delta; + UPB_ASSERT(!_upb_Arena_IsTaggedPointer(with_refs)); + // Relaxed order on success is safe here, for the same reasons as the relaxed + // read above. Relaxed order is safe on failure because the updated value is + // stored in a local variable which goes immediately out of scope; the retry + // loop will reread what it needs with proper memory order. + return upb_Atomic_CompareExchangeStrong(&new_root->parent_or_count, &poc, + with_refs, memory_order_relaxed, + memory_order_relaxed); +} + +bool upb_Arena_Fuse(const upb_Arena* a1, const upb_Arena* a2) { + if (a1 == a2) return true; // trivial fuse + +#ifdef UPB_TRACING_ENABLED + upb_Arena_LogFuse(a1, a2); +#endif + + upb_ArenaInternal* ai1 = upb_Arena_Internal(a1); + upb_ArenaInternal* ai2 = upb_Arena_Internal(a2); + + // Do not fuse initial blocks since we cannot lifetime extend them. + // Any other fuse scenario is allowed. + if (_upb_ArenaInternal_HasInitialBlock(ai1) || + _upb_ArenaInternal_HasInitialBlock(ai2)) { + return false; + } + + // The number of refs we ultimately need to transfer to the new root. + uintptr_t ref_delta = 0; + while (true) { + upb_ArenaInternal* new_root = _upb_Arena_DoFuse(&ai1, &ai2, &ref_delta); + if (new_root != NULL && _upb_Arena_FixupRefs(new_root, ref_delta)) { +#if UPB_ENABLE_REF_CYCLE_CHECKS + UPB_ASSERT(!upb_Arena_HasRefChain(a1, a2)); +#endif + return true; + } + } +} + +bool upb_Arena_IsFused(const upb_Arena* a, const upb_Arena* b) { + if (a == b) return true; // trivial fuse + upb_ArenaInternal* ra = _upb_Arena_FindRoot(upb_Arena_Internal(a)).root; + upb_ArenaInternal* rb = upb_Arena_Internal(b); + while (true) { + rb = _upb_Arena_FindRoot(rb).root; + if (ra == rb) return true; + upb_ArenaInternal* tmp = _upb_Arena_FindRoot(ra).root; + if (ra == tmp) return false; + // a's root changed since we last checked. Retry. + ra = tmp; + } +} + +bool upb_Arena_IncRefFor(const upb_Arena* a, const void* owner) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + if (_upb_ArenaInternal_HasInitialBlock(ai)) return false; + upb_ArenaRoot r; + r.root = ai; + +retry: + r = _upb_Arena_FindRoot(r.root); + if (upb_Atomic_CompareExchangeWeak( + &r.root->parent_or_count, &r.tagged_count, + _upb_Arena_TaggedFromRefcount( + _upb_Arena_RefCountFromTagged(r.tagged_count) + 1), + // Relaxed order is safe on success, incrementing the refcount + // need not perform any synchronization with the eventual free of the + // arena - that's provided by decrements. + memory_order_relaxed, + // Relaxed order is safe on failure as r.tagged_count is immediately + // overwritten by retrying the find root operation. + memory_order_relaxed)) { + // We incremented it successfully, so we are done. + return true; + } + // We failed update due to parent switching on the arena. + goto retry; +} + +void upb_Arena_DecRefFor(const upb_Arena* a, const void* owner) { + upb_Arena_Free((upb_Arena*)a); +} + +bool upb_Arena_RefArena(upb_Arena* from, const upb_Arena* to) { + UPB_ASSERT(!upb_Arena_IsFused(from, to)); + if (_upb_ArenaInternal_HasInitialBlock(upb_Arena_Internal(to))) { + // We can't increment a ref to `to`, so return early. + return false; + } + + upb_ArenaInternal* ai = upb_Arena_Internal(from); + upb_ArenaRef* ref = upb_Arena_Malloc(from, kUpb_ArenaRefReserve); + + if (!ref) { + return false; + } + + // When 'from' is freed, a ref on 'to' will be released. + // Intentionally ignore return value, since we already check up above if this + // call will succeed. + bool result = upb_Arena_IncRefFor(to, from); + UPB_ASSERT(result); + + // When we add a reference from `from` to `to`, we need to keep track of the + // ref in the `from` arena's linked list of refs. This allows us to + // walk all refs for `from` when `from` is freed, and thus allows us to + // decrement the refcount on `to` when `from` is freed. + ref->prefix.next = ai->blocks; + ref->prefix.size = 0; + ref->arena = to; + ai->blocks = (upb_MemBlock*)ref; + +#ifndef NDEBUG + // Add to the dedicated list of refs. + // This function is not thread-safe from `from`, so a simple load/store is + // sufficient. + ref->next_ref = upb_Atomic_Load(&ai->refs, memory_order_relaxed); + upb_Atomic_Store(&ai->refs, ref, memory_order_release); +#endif + +#if UPB_ENABLE_REF_CYCLE_CHECKS + UPB_ASSERT(!upb_Arena_HasRefChain(to, from)); // Forbid cycles. +#endif + + return true; +} + +#ifndef NDEBUG +bool upb_Arena_HasRef(const upb_Arena* from, const upb_Arena* to) { + const upb_ArenaInternal* ai = upb_Arena_Internal(from); + const upb_ArenaRef* ref = upb_Atomic_Load(&ai->refs, memory_order_acquire); + while (ref != NULL) { + if (upb_Arena_IsFused(ref->arena, to)) { + return true; + } + ref = ref->next_ref; + } + return false; +} +#endif + +upb_alloc* upb_Arena_GetUpbAlloc(upb_Arena* a) { + UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(a)); + upb_ArenaInternal* ai = upb_Arena_Internal(a); + return _upb_ArenaInternal_BlockAlloc(ai); +} + +void UPB_PRIVATE(_upb_Arena_SwapIn)(upb_Arena* des, const upb_Arena* src) { + memcpy(des, src, offsetof(upb_ArenaState, body.space_allocated)); + upb_ArenaInternal* desi = upb_Arena_Internal(des); + upb_ArenaInternal* srci = upb_Arena_Internal(src); + uintptr_t new_space_allocated = + upb_Atomic_Load(&srci->space_allocated, memory_order_relaxed); + upb_Atomic_Store(&desi->space_allocated, new_space_allocated, + memory_order_relaxed); +} + +void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) { + UPB_PRIVATE(_upb_Arena_SwapIn)(des, src); +} + +bool _upb_Arena_WasLastAllocFromPreviousBlock(struct upb_Arena* a, void* ptr, + size_t oldsize) { + upb_ArenaInternal* ai = upb_Arena_Internal(a); + upb_MemBlock* block = ai->blocks; + // Skip any arena refs. + while (block != NULL && block->size == 0) { + block = block->next; + } + if (block == NULL) return false; + char* start = UPB_PTR_AT(block, kUpb_MemblockReserve, char); + + // We don't actually track the final pointer value, so we can only check that + // the span is within the previous block. + return UPB_PRIVATE(upb_Xsan_PtrEq)(ptr, start) && + UPB_PRIVATE(_upb_Arena_AllocSpan)(oldsize) == + block->size - kUpb_MemblockReserve; +} + +void* UPB_PRIVATE(_upb_Arena_Steal)(struct upb_Arena* a, size_t* size) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + size_t have = UPB_PRIVATE(_upb_ArenaHas)(a); + if (have < *size) return NULL; + + *size = have; + void* ptr = a->UPB_ONLYBITS(ptr); + a->UPB_ONLYBITS(ptr) += have; + + return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ptr, have); +} + +// Frees a block previously allocated with _upb_Arena_AllocBlock. +void UPB_PRIVATE(_upb_Arena_FreeBlock)(upb_Arena* a, void* block) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + upb_MemBlock* b = + UPB_PTR_AT(block, -(ptrdiff_t)kUpb_MemblockReserve, upb_MemBlock); + upb_alloc* alloc = upb_Arena_GetUpbAlloc(a); + upb_free_sized(alloc, b, b->size); +} + + + +// Must be last. + +bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTableField* f, + upb_Message* map_entry_message, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message)); + const upb_MiniTable* map_entry_mini_table = + upb_MiniTable_MapEntrySubMessage(f); + UPB_ASSERT(map_entry_mini_table); + const upb_MiniTableField* map_entry_key_field = + upb_MiniTable_MapKey(map_entry_mini_table); + const upb_MiniTableField* map_entry_value_field = + upb_MiniTable_MapValue(map_entry_mini_table); + // Map key/value cannot have explicit defaults, + // hence assuming a zero default is valid. + upb_MessageValue default_val = upb_MessageValue_Zero(); + upb_MessageValue map_entry_key = + upb_Message_GetField(map_entry_message, map_entry_key_field, default_val); + upb_MessageValue map_entry_value = upb_Message_GetField( + map_entry_message, map_entry_value_field, default_val); + return upb_Map_Set(map, map_entry_key, map_entry_value, arena); +} + + +#include +#include + + +// Must be last. + +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(type); + return UPB_PRIVATE(_upb_Array_New)(a, _UPB_ARRAY_DEFAULT_INITIAL_SIZE, lg2); +} + +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + UPB_ASSERT(i < upb_Array_Size(arr)); + upb_MessageValue ret; + const char* data = upb_Array_DataPtr(arr); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} + +upb_Message* upb_Array_GetMutable(upb_Array* arr, size_t i) { + UPB_ASSERT(i < upb_Array_Size(arr)); + size_t elem_size = sizeof(upb_Message*); + UPB_ASSERT(elem_size == (1 << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr))); + char* data = upb_Array_MutableDataPtr(arr); + upb_Message* ret; + memcpy(&ret, data + (i * elem_size), elem_size); + UPB_ASSERT(!upb_Message_IsFrozen(ret)); + return ret; +} + +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(i < upb_Array_Size(arr)); + char* data = upb_Array_MutableDataPtr(arr); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + memcpy(data + (i << lg2), &val, 1 << lg2); +} + +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(arena); + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + upb_Array_Set(arr, arr->UPB_PRIVATE(size) - 1, val); + return true; +} + +bool upb_Array_Copy(upb_Array* dst, const upb_Array* src, upb_Arena* arena) { + UPB_ASSERT(dst); + UPB_ASSERT(src); + UPB_ASSERT(!upb_Array_IsFrozen(dst)); + if (dst == src) return true; + size_t len = upb_Array_Size(src); + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) { + return false; + } + if (len == 0) return true; + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst); + const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src); + UPB_ASSERT(lg2 == src_lg2); + char* dst_data = upb_Array_MutableDataPtr(dst); + const char* src_data = upb_Array_DataPtr(src); + memcpy(dst_data, src_data, len << lg2); + return true; +} + +bool upb_Array_AppendAll(upb_Array* dst, const upb_Array* src, + upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(dst)); + UPB_ASSERT(src); + size_t src_len = upb_Array_Size(src); + if (src_len == 0) return true; + size_t dst_len = upb_Array_Size(dst); + size_t len = dst_len + src_len; + if (UPB_UNLIKELY(len < dst_len)) return false; + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) { + return false; + } + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst); + const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src); + UPB_ASSERT(lg2 == src_lg2); + char* dst_data = upb_Array_MutableDataPtr(dst); + const char* src_data = upb_Array_DataPtr(src); + memcpy(dst_data + (dst_len << lg2), src_data, src_len << lg2); + return true; +} + +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + char* data = upb_Array_MutableDataPtr(arr); + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} + +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + UPB_ASSERT(arena); + UPB_ASSERT(i <= arr->UPB_PRIVATE(size)); + UPB_ASSERT(count + arr->UPB_PRIVATE(size) >= count); + const size_t oldsize = arr->UPB_PRIVATE(size); + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + count, arena)) { + return false; + } + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; +} + +/* + * i end arr->size + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->UPB_PRIVATE(size)); + upb_Array_Move(arr, i, end, arr->UPB_PRIVATE(size) - end); + arr->UPB_PRIVATE(size) -= count; +} + +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(arr)); + const size_t oldsize = arr->UPB_PRIVATE(size); + if (UPB_UNLIKELY( + !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena))) { + return false; + } + const size_t newsize = arr->UPB_PRIVATE(size); + if (newsize > oldsize) { + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); + char* data = upb_Array_MutableDataPtr(arr); + memset(data + (oldsize << lg2), 0, (newsize - oldsize) << lg2); + } + return true; +} + +bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity, + upb_Arena* arena) { + size_t new_capacity = UPB_MAX(array->UPB_PRIVATE(capacity), 4); + const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); + size_t old_bytes = array->UPB_PRIVATE(capacity) << lg2; + void* ptr = upb_Array_MutableDataPtr(array); + + // Log2 ceiling of size. + while (new_capacity < min_capacity) { + if (upb_ShlOverflow(&new_capacity, 1)) { + new_capacity = SIZE_MAX; + break; + } + } + + // If capacity doubling overflowed to SIZE_MAX, fail. No valid array can hold + // SIZE_MAX elements, and downstream size calculations would overflow. + if (new_capacity == SIZE_MAX) return false; + + size_t new_bytes = new_capacity; + if (upb_ShlOverflow(&new_bytes, lg2)) { + return false; + } + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); + if (!ptr) return false; + + UPB_PRIVATE(_upb_Array_SetTaggedPtr)(array, ptr, lg2); + array->UPB_PRIVATE(capacity) = new_capacity; + return true; +} + +void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m) { + if (upb_Array_IsFrozen(arr)) return; + UPB_PRIVATE(_upb_Array_ShallowFreeze)(arr); + + if (m) { + const size_t size = upb_Array_Size(arr); + + for (size_t i = 0; i < size; i++) { + upb_MessageValue val = upb_Array_Get(arr, i); + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + + +#include +#include + + +// Must be last. + +bool upb_Message_NextExtensionReverse(const upb_Message* msg, + const upb_MiniTableExtension** result, + uintptr_t* iter) { + upb_MessageValue val; + return UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, result, &val, + iter); +} + +const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( + const upb_Message* msg, uint32_t field_number) { + uintptr_t iter = kUpb_Message_ExtensionBegin; + const upb_MiniTableExtension* result; + while (upb_Message_NextExtensionReverse(msg, &result, &iter)) { + if (upb_MiniTableExtension_Number(result) == field_number) return result; + } + return NULL; +} + + +#include +#include + + +// Must be last. + +// Strings/bytes are special-cased in maps. +char _upb_Map_CTypeSizeTable[12] = { + [kUpb_CType_Bool] = 1, + [kUpb_CType_Float] = 4, + [kUpb_CType_Int32] = 4, + [kUpb_CType_UInt32] = 4, + [kUpb_CType_Enum] = 4, + [kUpb_CType_Message] = sizeof(void*), + [kUpb_CType_Double] = 8, + [kUpb_CType_Int64] = 8, + [kUpb_CType_UInt64] = 8, + [kUpb_CType_String] = UPB_MAPTYPE_STRING, + [kUpb_CType_Bytes] = UPB_MAPTYPE_STRING, +}; + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_Map_CTypeSize(key_type), + _upb_Map_CTypeSize(value_type)); +} + +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); +} + +struct upb_Message* upb_Map_GetMutable(upb_Map* map, upb_MessageValue key) { + UPB_ASSERT(map->val_size == sizeof(upb_Message*)); + upb_Message* val = NULL; + if (_upb_Map_Get(map, &key, map->key_size, &val, sizeof(upb_Message*))) { + return val; + } else { + return NULL; + } +} + +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(arena); + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); +} + +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key, upb_MessageValue* val) { + upb_value v; + const bool removed = _upb_Map_Delete(map, &key, map->key_size, &v); + if (val) _upb_map_fromvalue(v, val, map->val_size); + return removed; +} + +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter) { + upb_value v; + bool ret; + if (map->UPB_PRIVATE(is_strtable)) { + upb_StringView strkey; + ret = upb_strtable_next2(&map->t.strtable, &strkey, &v, (intptr_t*)iter); + if (ret) { + _upb_map_fromkey(strkey, key, map->key_size); + } + } else { + uintptr_t intkey; + ret = upb_inttable_next(&map->t.inttable, &intkey, &v, (intptr_t*)iter); + if (ret) { + memcpy(key, &intkey, map->key_size); + } + } + if (ret) { + _upb_map_fromvalue(v, val, map->val_size); + } + return ret; +} + +UPB_API void upb_Map_SetEntryValue(upb_Map* map, size_t iter, + upb_MessageValue val) { + upb_value v; + _upb_map_tovalue(&val, map->val_size, &v, NULL); + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_setentryvalue(&map->t.strtable, iter, v); + } else { + upb_inttable_setentryvalue(&map->t.inttable, iter, v); + } +} + +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); +} + +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + UPB_ASSERT(iter != kUpb_Map_Begin); + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_iter i; + i.t = &map->t.strtable; + i.index = iter; + return upb_strtable_done(&i); + } else { + return upb_inttable_done(&map->t.inttable, iter); + } +} + +// Returns the key and value for this entry of the map. +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_MessageValue ret; + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_iter i; + i.t = &map->t.strtable; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + } else { + uintptr_t intkey = upb_inttable_iter_key(&map->t.inttable, iter); + memcpy(&ret, &intkey, map->key_size); + } + return ret; +} + +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_value v; + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_iter i; + i.t = &map->t.strtable; + i.index = iter; + v = upb_strtable_iter_value(&i); + } else { + v = upb_inttable_iter_value(&map->t.inttable, iter); + } + + upb_MessageValue ret; + _upb_map_fromvalue(v, &ret, map->val_size); + return ret; +} + +void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m) { + if (upb_Map_IsFrozen(map)) return; + UPB_PRIVATE(_upb_Map_ShallowFreeze)(map); + + if (m) { + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + + while (upb_Map_Next(map, &key, &val, &iter)) { + upb_Message_Freeze((upb_Message*)val.msg_val, m); + } + } +} + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); + if (!map) return NULL; + + if (key_size <= sizeof(uintptr_t) && key_size != UPB_MAPTYPE_STRING) { + if (!upb_inttable_init(&map->t.inttable, a)) return NULL; + map->UPB_PRIVATE(is_strtable) = false; + } else { + if (!upb_strtable_init(&map->t.strtable, 4, a)) return NULL; + map->UPB_PRIVATE(is_strtable) = true; + } + map->key_size = key_size; + map->val_size = value_size; + map->UPB_PRIVATE(is_frozen) = false; + + return map; +} + + +#include +#include +#include + + +// Must be last. + +static int _upb_mapsorter_intkeys(const void* _a, const void* _b) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + uintptr_t a_key = (*a)->key.num; + uintptr_t b_key = (*b)->key.num; + return a_key < b_key ? -1 : a_key > b_key; +} + +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_key_strview((*a)->key); + upb_StringView b_tabkey = upb_key_strview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); +} + +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return a < b ? -1 : a > b; +} + +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return a.size < b.size ? -1 : a.size > b.size; +} + +static int (*const compar[kUpb_FieldType_SizeOf])(const void*, const void*) = { + [kUpb_FieldType_Int64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SFixed64] = _upb_mapsorter_cmpi64, + [kUpb_FieldType_SInt64] = _upb_mapsorter_cmpi64, + + [kUpb_FieldType_UInt64] = _upb_mapsorter_cmpu64, + [kUpb_FieldType_Fixed64] = _upb_mapsorter_cmpu64, + + [kUpb_FieldType_Int32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SInt32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_SFixed32] = _upb_mapsorter_cmpi32, + [kUpb_FieldType_Enum] = _upb_mapsorter_cmpi32, + + [kUpb_FieldType_UInt32] = _upb_mapsorter_cmpu32, + [kUpb_FieldType_Fixed32] = _upb_mapsorter_cmpu32, + + [kUpb_FieldType_Bool] = _upb_mapsorter_cmpbool, + + [kUpb_FieldType_String] = _upb_mapsorter_cmpstr, + [kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr, +}; + +static bool _upb_mapsorter_resize(_upb_mapsorter* s, _upb_sortedmap* sorted, + int size) { + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + size; + + if (sorted->end > s->cap) { + const int oldsize = s->cap * sizeof(*s->entries); + s->cap = upb_RoundUpToPowerOfTwo(sorted->end); + const int newsize = s->cap * sizeof(*s->entries); + s->entries = upb_grealloc(s->entries, oldsize, newsize); + if (!s->entries) return false; + } + + s->size = sorted->end; + return true; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + + if (!_upb_mapsorter_resize(s, sorted, map_size)) return false; + + // Copy non-empty entries from the table to s->entries. + const void** dst = &s->entries[sorted->start]; + const upb_tabent* src; + const upb_tabent* end; + if (map->UPB_PRIVATE(is_strtable)) { + src = map->t.strtable.t.entries; + end = src + upb_table_size(&map->t.strtable.t); + } else { + src = map->t.inttable.t.entries; + end = src + upb_table_size(&map->t.inttable.t); + } + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; + } + } + UPB_ASSERT(dst == &s->entries[sorted->end]); + + // Sort entries according to the key type. + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), + map->UPB_PRIVATE(is_strtable) ? compar[key_type] + : _upb_mapsorter_intkeys); + return true; +} + +static int _upb_mapsorter_cmpext(const void* _a, const void* _b) { + const upb_Extension* const* a = _a; + const upb_Extension* const* b = _b; + uint32_t a_num = upb_MiniTableExtension_Number((*a)->ext); + uint32_t b_num = upb_MiniTableExtension_Number((*b)->ext); + UPB_ASSERT(a_num != b_num); + return a_num < b_num ? -1 : 1; +} + +bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in, + _upb_sortedmap* sorted) { + size_t count = 0; + for (size_t i = 0; i < in->size; i++) { + count += upb_TaggedAuxPtr_IsCanonicalExtension(in->aux_data[i]); + } + if (!_upb_mapsorter_resize(s, sorted, count)) return false; + if (count == 0) return true; + const upb_Extension** entry = + (const upb_Extension**)&s->entries[sorted->start]; + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + *entry++ = upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + } + } + qsort(&s->entries[sorted->start], count, sizeof(*s->entries), + _upb_mapsorter_cmpext); + return true; +} + + +#include +#include +#include +#include + + +// Must be last. + +upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) { + return _upb_Message_New(m, a); +} + +UPB_NOINLINE bool UPB_PRIVATE(_upb_Message_AddUnknownSlowPath)(upb_Message* msg, + const char* data, + size_t len, + upb_Arena* arena, + bool alias) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + // Alias fast path was already checked in the inline function that calls + // this one + if (!alias && in && in->size) { + upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; + if (upb_TaggedAuxPtr_IsUnknownStringView(ptr)) { + upb_StringView* existing = upb_TaggedPtrAux_StringViewRepr(ptr); + if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { + // If part of the existing field was deleted at the beginning, we can + // reconstruct it by comparing the address of the end with the address + // of the entry itself; having the non-aliased tag means that the + // string_view and the data it points to are part of the same original + // upb_Arena_Malloc allocation, and the end of the string view + // represents the end of that allocation. + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= len) { + size_t new_alloc_size = prev_alloc_size + len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + memcpy(UPB_PTR_AT(existing, prev_alloc_size, void), data, len); + existing->size += len; + return true; + } + } + } + } + } + } + // TODO: b/376969853 - Add debug check that the unknown field is an overall + // valid proto field + if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) { + return false; + } + upb_StringView* view; + if (alias) { + view = upb_Arena_Malloc(arena, sizeof(upb_StringView)); + if (!view) return false; + view->data = data; + } else { + if (SIZE_MAX - sizeof(upb_StringView) < len) return false; + view = upb_Arena_Malloc(arena, sizeof(upb_StringView) + len); + if (!view) return false; + char* copy = UPB_PTR_AT(view, sizeof(upb_StringView), char); + memcpy(copy, data, len); + view->data = copy; + } + view->size = len; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + in->aux_data[in->size++] = alias + ? upb_TaggedAuxPtr_MakeUnknownDataAliased(view) + : upb_TaggedAuxPtr_MakeUnknownData(view); + return true; +} + +bool UPB_PRIVATE(_upb_Message_AddUnknownV)(struct upb_Message* msg, + upb_Arena* arena, + upb_StringView data[], + size_t count) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(count > 0); + size_t total_len = 0; + for (size_t i = 0; i < count; i++) { + if (SIZE_MAX - total_len < data[i].size) { + return false; + } + total_len += data[i].size; + } + + { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in && in->size) { + upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; + if (upb_TaggedAuxPtr_IsUnknownStringView(ptr)) { + upb_StringView* existing = upb_TaggedPtrAux_StringViewRepr(ptr); + if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { + size_t prev_alloc_size = + (existing->data + existing->size) - (char*)existing; + if (SIZE_MAX - prev_alloc_size >= total_len) { + size_t new_alloc_size = prev_alloc_size + total_len; + if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, + new_alloc_size)) { + char* copy = UPB_PTR_AT(existing, prev_alloc_size, char); + for (size_t i = 0; i < count; i++) { + memcpy(copy, data[i].data, data[i].size); + copy += data[i].size; + } + existing->size += total_len; + return true; + } + } + } + } + } + } + + if (SIZE_MAX - sizeof(upb_StringView) < total_len) return false; + if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) return false; + + upb_StringView* view = + upb_Arena_Malloc(arena, sizeof(upb_StringView) + total_len); + if (!view) return false; + char* copy = UPB_PTR_AT(view, sizeof(upb_StringView), char); + view->data = copy; + view->size = total_len; + for (size_t i = 0; i < count; i++) { + memcpy(copy, data[i].data, data[i].size); + copy += data[i].size; + } + // TODO: b/376969853 - Add debug check that the unknown field is an overall + // valid proto field + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + in->aux_data[in->size++] = upb_TaggedAuxPtr_MakeUnknownData(view); + return true; +} + +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return; + uint32_t size = 0; + for (uint32_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (upb_TaggedAuxPtr_IsSemanticallyKnown(tagged_ptr)) { + in->aux_data[size++] = tagged_ptr; + } + } + in->size = size; +} + +upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg, + upb_StringView* data, + uintptr_t* iter, + upb_Arena* arena) { + upb_MessageUnknown unknown; + unknown.type = kUpb_MessageUnknownType_StringView; + unknown.value.bytes = *data; + + upb_Message_DeleteUnknownStatus res = + upb_Message_DeleteUnknown2(msg, &unknown, iter, arena); + UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView); + if (res == kUpb_DeleteUnknown_IterUpdated || + res == kUpb_DeleteUnknown_DeletedLast) { + // the unknown data remains the same on the result of + // kUpb_DeleteUnknown_AllocFail. + *data = unknown.value.bytes; + } + return res; +} + +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return 0; + const upb_MiniTableExtension* ext; + upb_MessageValue val; + uintptr_t iter = kUpb_Message_ExtensionBegin; + size_t count = 0; + while (upb_Message_NextExtension(msg, &ext, &val, &iter)) { + count++; + } + return count; +} + +void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_IsFrozen(msg)) return; + UPB_PRIVATE(_upb_Message_ShallowFreeze)(msg); + + // Base Fields. + const size_t field_count = upb_MiniTable_FieldCount(m); + + for (size_t i = 0; i < field_count; i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const upb_MiniTable* m2 = upb_MiniTable_SubMessage(f); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = upb_Message_GetMutableArray(msg, f); + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: { + upb_Map* map = upb_Message_GetMutableMap(msg, f); + if (map) { + const upb_MiniTableField* f2 = upb_MiniTable_MapValue(m2); + const upb_MiniTable* m3 = upb_MiniTable_SubMessage(f2); + upb_Map_Freeze(map, m3); + } + break; + } + case kUpb_FieldMode_Scalar: { + if (m2) { + upb_Message* msg2 = upb_Message_GetMutableMessage(msg, f); + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } + } + + // Extensions. + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + // TODO: b/376969853 - use iterator API + uint32_t size = in ? in->size : 0; + for (size_t i = 0; i < size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + upb_TaggedAux aux; + upb_TaggedAuxType type = upb_TaggedAux_Get(tagged_ptr, &aux); + if (type != kUpb_TaggedAuxType_CanonicalExtension && + type != kUpb_TaggedAuxType_NonCanonicalExtension) { + continue; + } + const upb_Extension* ext = aux.extension; + const upb_MiniTableExtension* e = ext->ext; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e); + + upb_MessageValue val; + memcpy(&val, &(ext->data), sizeof(upb_MessageValue)); + + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: { + upb_Array* arr = (upb_Array*)val.array_val; + if (arr) upb_Array_Freeze(arr, m2); + break; + } + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: + if (upb_MiniTableField_IsSubMessage(f)) { + upb_Message* msg2 = (upb_Message*)val.msg_val; + if (msg2) upb_Message_Freeze(msg2, m2); + } + break; + } + } +} + + +#include +#include +#include + + +// Must be last. + +static upb_FindUnknownRet2 upb_FindUnknownRet2_ParseError(void) { + return (upb_FindUnknownRet2){.status = kUpb_FindUnknown_ParseError}; +} + +upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg, + uint32_t field_number, + int depth_limit) { + depth_limit = depth_limit ? depth_limit : 100; + upb_FindUnknownRet2 ret; + ret.iter = kUpb_Message_UnknownBegin; + while (upb_Message_NextUnknown2(msg, &ret.unknown, &ret.iter)) { + if (ret.unknown.type == kUpb_MessageUnknownType_StringView) { + upb_EpsCopyInputStream stream; + const char* ptr = ret.unknown.value.bytes.data; + upb_EpsCopyInputStream_Init(&stream, &ptr, ret.unknown.value.bytes.size); + + while (!upb_EpsCopyInputStream_IsDone(&stream, &ptr)) { + uint32_t tag; + const char* unknown_begin = ptr; + ptr = upb_WireReader_ReadTag(ptr, &tag, &stream); + if (!ptr) return upb_FindUnknownRet2_ParseError(); + if (field_number == upb_WireReader_GetFieldNumber(tag)) { + upb_StringView data; + ret.status = kUpb_FindUnknown_Ok; + upb_EpsCopyCapture capture; + upb_EpsCopyCapture_Start(&capture, &stream, unknown_begin); + ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream); + if (!ptr || !upb_EpsCopyCapture_End(&capture, &stream, ptr, &data)) { + return upb_FindUnknownRet2_ParseError(); + } + ret.unknown.value.bytes = data; + return ret; + } + + ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream); + if (!ptr) return upb_FindUnknownRet2_ParseError(); + } + } else if (ret.unknown.type == + kUpb_MessageUnknownType_NonCanonicalExtension) { + uint32_t ext_field_number = + upb_MiniTableExtension_Number(ret.unknown.value.extension->ext); + if (ext_field_number == field_number) { + ret.status = kUpb_FindUnknown_Ok; + return ret; + } + } + } + ret.status = kUpb_FindUnknown_NotPresent; + ret.unknown.type = kUpb_MessageUnknownType_StringView; + ret.unknown.value.bytes.data = NULL; + ret.unknown.value.bytes.size = 0; + ret.iter = kUpb_Message_UnknownBegin; + return ret; +} + +upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2( + struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter, + struct upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(*iter != kUpb_Message_UnknownBegin); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + UPB_ASSERT(in); + UPB_ASSERT(*iter <= in->size); + upb_TaggedAuxPtr unknown_ptr = in->aux_data[*iter - 1]; + + if (data->type == kUpb_MessageUnknownType_NonCanonicalExtension) { + UPB_ASSERT(upb_TaggedAuxPtr_IsNonCanonicalExtension(unknown_ptr)); + // When the unknown is a non-canonical extension, we just remove it from the + // aux data array. + in->aux_data[*iter - 1] = upb_TaggedAuxPtr_Null(); + return upb_Message_NextUnknown2(msg, data, iter) + ? kUpb_DeleteUnknown_IterUpdated + : kUpb_DeleteUnknown_DeletedLast; + } + + UPB_ASSERT(upb_TaggedAuxPtr_IsUnknownStringView(unknown_ptr)); + upb_StringView* unknown = upb_TaggedPtrAux_StringViewRepr(unknown_ptr); + UPB_ASSERT(data->type == kUpb_MessageUnknownType_StringView); + upb_StringView* data_bytes = &data->value.bytes; + if (unknown->data == data_bytes->data && unknown->size == data_bytes->size) { + // Remove whole field + in->aux_data[*iter - 1] = upb_TaggedAuxPtr_Null(); + } else if (unknown->data == data_bytes->data) { + // Strip prefix + unknown->data += data_bytes->size; + unknown->size -= data_bytes->size; + *data_bytes = *unknown; + return kUpb_DeleteUnknown_IterUpdated; + } else if (unknown->data + unknown->size == + data_bytes->data + data_bytes->size) { + // Truncate existing field + unknown->size -= data_bytes->size; + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = + upb_TaggedAuxPtr_MakeUnknownDataAliased(unknown); + } + } else { + UPB_ASSERT(unknown->data < data_bytes->data && + unknown->data + unknown->size > + data_bytes->data + data_bytes->size); + // Split in the middle + upb_StringView* prefix = unknown; + upb_StringView* suffix = upb_Arena_Malloc(arena, sizeof(upb_StringView)); + if (!suffix) { + return kUpb_DeleteUnknown_AllocFail; + } + if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) { + return kUpb_DeleteUnknown_AllocFail; + } + in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (*iter != in->size) { + // Shift later entries down so that unknown field ordering is preserved + memmove(&in->aux_data[*iter + 1], &in->aux_data[*iter], + sizeof(upb_TaggedAuxPtr) * (in->size - *iter)); + } + in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownDataAliased(suffix); + if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { + in->aux_data[*iter - 1] = upb_TaggedAuxPtr_MakeUnknownDataAliased(prefix); + } + in->size++; + suffix->data = data_bytes->data + data_bytes->size; + suffix->size = (prefix->data + prefix->size) - suffix->data; + prefix->size = data_bytes->data - prefix->data; + } + return upb_Message_NextUnknown2(msg, data, iter) + ? kUpb_DeleteUnknown_IterUpdated + : kUpb_DeleteUnknown_DeletedLast; +} + + +#include +#include + + +// Must be last. + + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_Message_IsEmpty(const upb_Message* msg, const upb_MiniTable* m) { + if (upb_Message_ExtensionCount(msg)) return false; + + const upb_MiniTableField* f; + upb_MessageValue v; + size_t iter = kUpb_BaseField_Begin; + return !UPB_PRIVATE(_upb_Message_NextBaseField)(msg, m, &f, &v, &iter); +} + +static bool _upb_Array_IsEqual(const upb_Array* arr1, const upb_Array* arr2, + upb_CType ctype, const upb_MiniTable* m, + int options) { + // Check for trivial equality. + if (arr1 == arr2) return true; + + // Must have identical element counts. + const size_t size1 = arr1 ? upb_Array_Size(arr1) : 0; + const size_t size2 = arr2 ? upb_Array_Size(arr2) : 0; + if (size1 != size2) return false; + + for (size_t i = 0; i < size1; i++) { + const upb_MessageValue val1 = upb_Array_Get(arr1, i); + const upb_MessageValue val2 = upb_Array_Get(arr2, i); + + if (!upb_MessageValue_IsEqual(val1, val2, ctype, m, options)) return false; + } + + return true; +} + +static bool _upb_Map_IsEqual(const upb_Map* map1, const upb_Map* map2, + const upb_MiniTable* m, int options) { + // Check for trivial equality. + if (map1 == map2) return true; + + // Must have identical element counts. + size_t size1 = map1 ? upb_Map_Size(map1) : 0; + size_t size2 = map2 ? upb_Map_Size(map2) : 0; + if (size1 != size2) return false; + + const upb_MiniTableField* f = upb_MiniTable_MapValue(m); + const upb_MiniTable* m2_value = upb_MiniTable_SubMessage(f); + const upb_CType ctype = upb_MiniTableField_CType(f); + + upb_MessageValue key, val1, val2; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map1, &key, &val1, &iter)) { + if (!upb_Map_Get(map2, key, &val2)) return false; + if (!upb_MessageValue_IsEqual(val1, val2, ctype, m2_value, options)) + return false; + } + + return true; +} + +static bool _upb_Message_BaseFieldsAreEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, + int options) { + // Iterate over all base fields for each message. + // The order will always match if the messages are equal. + size_t iter1 = kUpb_BaseField_Begin; + size_t iter2 = kUpb_BaseField_Begin; + + for (;;) { + const upb_MiniTableField *f1, *f2; + upb_MessageValue val1, val2; + + const bool got1 = + UPB_PRIVATE(_upb_Message_NextBaseField)(msg1, m, &f1, &val1, &iter1); + const bool got2 = + UPB_PRIVATE(_upb_Message_NextBaseField)(msg2, m, &f2, &val2, &iter2); + + if (got1 != got2) return false; // Must have identical field counts. + if (!got1) return true; // Loop termination condition. + if (f1 != f2) return false; // Must have identical fields set. + + const upb_MiniTable* subm = upb_MiniTable_SubMessage(f1); + const upb_CType ctype = upb_MiniTableField_CType(f1); + + bool eq; + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f1)) { + case kUpb_FieldMode_Array: + eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, + options); + break; + case kUpb_FieldMode_Map: + eq = _upb_Map_IsEqual(val1.map_val, val2.map_val, subm, options); + break; + case kUpb_FieldMode_Scalar: + eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); + break; + } + if (!eq) return false; + } +} + +static bool _upb_Message_ExtensionsAreEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, + int options) { + const upb_MiniTableExtension* e; + upb_MessageValue val1; + + // Iterate over all extensions for msg1, and search msg2 for each extension. + size_t count1 = 0; + size_t iter1 = kUpb_Message_ExtensionBegin; + while (upb_Message_NextExtension(msg1, &e, &val1, &iter1)) { + const upb_Extension* ext2 = UPB_PRIVATE(_upb_Message_Getext)(msg2, e); + if (!ext2) return false; + + count1++; + + const upb_MessageValue val2 = ext2->data; + const upb_MiniTableField* f = &e->UPB_PRIVATE(field); + const upb_MiniTable* subm = upb_MiniTableField_IsSubMessage(f) + ? upb_MiniTableExtension_GetSubMessage(e) + : NULL; + const upb_CType ctype = upb_MiniTableField_CType(f); + + bool eq; + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { + case kUpb_FieldMode_Array: + eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, + options); + break; + case kUpb_FieldMode_Map: + UPB_UNREACHABLE(); // Maps cannot be extensions. + break; + case kUpb_FieldMode_Scalar: { + eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); + break; + } + } + if (!eq) return false; + } + + // Must have identical extension counts (this catches the case where msg2 + // has extensions that msg1 doesn't). + if (count1 != upb_Message_ExtensionCount(msg2)) return false; + + return true; +} + +bool upb_Message_IsEqual(const upb_Message* msg1, const upb_Message* msg2, + const upb_MiniTable* m, int options) { + if (UPB_UNLIKELY(msg1 == msg2)) return true; + + if (!_upb_Message_BaseFieldsAreEqual(msg1, msg2, m, options)) return false; + if (!_upb_Message_ExtensionsAreEqual(msg1, msg2, m, options)) return false; + + if (!(options & kUpb_CompareOption_IncludeUnknownFields)) return true; + + // The wire encoder enforces a maximum depth of 100 so we match that here. + return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)(msg1, msg2, 100) == + kUpb_UnknownCompareResult_Equal; +} + + +#include +#include + + +// Must be last. + +typedef struct upb_UnknownFields upb_UnknownFields; + +typedef struct { + uint32_t tag; + union { + uint64_t varint; + uint64_t uint64; + uint32_t uint32; + upb_StringView delimited; + upb_UnknownFields* group; + } data; +} upb_UnknownField; + +struct upb_UnknownFields { + size_t size; + size_t capacity; + upb_UnknownField* fields; +}; + +typedef struct { + upb_EpsCopyInputStream stream; + upb_Arena* arena; + upb_UnknownField* tmp; + size_t tmp_size; + int depth; + upb_UnknownCompareResult status; + jmp_buf err; +} upb_UnknownField_Context; + +typedef struct { + upb_UnknownField* arr_base; + upb_UnknownField* arr_ptr; + upb_UnknownField* arr_end; + uint32_t last_tag; + bool sorted; +} upb_UnknownFields_Builder; + +UPB_NORETURN static void upb_UnknownFields_OutOfMemory( + upb_UnknownField_Context* ctx) { + ctx->status = kUpb_UnknownCompareResult_OutOfMemory; + UPB_LONGJMP(ctx->err, 1); +} + +static void upb_UnknownFields_Grow(upb_UnknownField_Context* ctx, + upb_UnknownField** base, + upb_UnknownField** ptr, + upb_UnknownField** end) { + size_t old = (*ptr - *base); + size_t new = UPB_MAX(4, old * 2); + + *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), + new * sizeof(**base)); + if (!*base) upb_UnknownFields_OutOfMemory(ctx); + + *ptr = *base + old; + *end = *base + new; +} + +// We have to implement our own sort here, since qsort() is not an in-order +// sort. Here we use merge sort, the simplest in-order sort. +static void upb_UnknownFields_Merge(upb_UnknownField* arr, size_t start, + size_t mid, size_t end, + upb_UnknownField* tmp) { + memcpy(tmp, &arr[start], (end - start) * sizeof(*tmp)); + + upb_UnknownField* ptr1 = tmp; + upb_UnknownField* end1 = &tmp[mid - start]; + upb_UnknownField* ptr2 = &tmp[mid - start]; + upb_UnknownField* end2 = &tmp[end - start]; + upb_UnknownField* out = &arr[start]; + + while (ptr1 < end1 && ptr2 < end2) { + if (ptr1->tag <= ptr2->tag) { + *out++ = *ptr1++; + } else { + *out++ = *ptr2++; + } + } + + if (ptr1 < end1) { + memcpy(out, ptr1, (end1 - ptr1) * sizeof(*out)); + } else if (ptr2 < end2) { + memcpy(out, ptr2, (end2 - ptr2) * sizeof(*out)); + } +} + +static void upb_UnknownFields_SortRecursive(upb_UnknownField* arr, size_t start, + size_t end, upb_UnknownField* tmp) { + if (end - start > 1) { + size_t mid = start + ((end - start) / 2); + upb_UnknownFields_SortRecursive(arr, start, mid, tmp); + upb_UnknownFields_SortRecursive(arr, mid, end, tmp); + upb_UnknownFields_Merge(arr, start, mid, end, tmp); + } +} + +static void upb_UnknownFields_Sort(upb_UnknownField_Context* ctx, + upb_UnknownFields* fields) { + if (ctx->tmp_size < fields->size) { + const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); + while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; + const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); + } + upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp); +} + +static upb_UnknownFields* upb_UnknownFields_BuildFromBuffer( + upb_UnknownField_Context* ctx, const char** buf); + +// Combines two unknown fields into one. +static void upb_CombineUnknownFields(upb_UnknownField_Context* ctx, + upb_UnknownFields_Builder* builder, + const char** buf) { + upb_UnknownField* arr_base = builder->arr_base; + upb_UnknownField* arr_ptr = builder->arr_ptr; + upb_UnknownField* arr_end = builder->arr_end; + const char* ptr = *buf; + uint32_t last_tag = builder->last_tag; + bool sorted = builder->sorted; + + // Parse the unknown field data. It is an invariant of the data structure that + // unknown field data is valid, so parse errors here should be impossible. + while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag, &ctx->stream); + UPB_ASSERT(tag <= UINT32_MAX); + int wire_type = upb_WireReader_GetWireType(tag); + if (wire_type == kUpb_WireType_EndGroup) break; + if (tag < last_tag) sorted = false; + last_tag = tag; + + if (arr_ptr == arr_end) { + upb_UnknownFields_Grow(ctx, &arr_base, &arr_ptr, &arr_end); + } + upb_UnknownField* field = arr_ptr; + field->tag = tag; + arr_ptr++; + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = upb_WireReader_ReadVarint(ptr, &field->data.varint, &ctx->stream); + UPB_ASSERT(ptr); + break; + case kUpb_WireType_64Bit: + ptr = + upb_WireReader_ReadFixed64(ptr, &field->data.uint64, &ctx->stream); + UPB_ASSERT(ptr); + break; + case kUpb_WireType_32Bit: + ptr = + upb_WireReader_ReadFixed32(ptr, &field->data.uint32, &ctx->stream); + UPB_ASSERT(ptr); + break; + case kUpb_WireType_Delimited: { + int size; + upb_StringView sv; + ptr = upb_WireReader_ReadSize(ptr, &size, &ctx->stream); + UPB_ASSERT(ptr); + ptr = upb_EpsCopyInputStream_ReadStringAlwaysAlias(&ctx->stream, ptr, + size, &sv); + UPB_ASSERT(ptr); + field->data.delimited.data = sv.data; + field->data.delimited.size = sv.size; + break; + } + case kUpb_WireType_StartGroup: + if (--ctx->depth < 0) { + ctx->status = kUpb_UnknownCompareResult_MaxDepthExceeded; + UPB_LONGJMP(ctx->err, 1); + } + field->data.group = upb_UnknownFields_BuildFromBuffer(ctx, &ptr); + ctx->depth++; + break; + default: + UPB_UNREACHABLE(); + } + } + *buf = ptr; + builder->arr_base = arr_base; + builder->arr_ptr = arr_ptr; + builder->arr_end = arr_end; + builder->sorted = sorted; + builder->last_tag = last_tag; +} + +static upb_UnknownFields* upb_UnknownFields_DoBuild( + upb_UnknownField_Context* ctx, upb_UnknownFields_Builder* builder) { + upb_UnknownFields* ret = upb_Arena_Malloc(ctx->arena, sizeof(*ret)); + if (!ret) upb_UnknownFields_OutOfMemory(ctx); + ret->fields = builder->arr_base; + ret->size = builder->arr_ptr - builder->arr_base; + ret->capacity = builder->arr_end - builder->arr_base; + if (!builder->sorted) { + upb_UnknownFields_Sort(ctx, ret); + } + return ret; +} + +// Builds a upb_UnknownFields data structure from the binary data in buf. +static upb_UnknownFields* upb_UnknownFields_BuildFromBuffer( + upb_UnknownField_Context* ctx, const char** buf) { + upb_UnknownFields_Builder builder = { + .arr_base = NULL, + .arr_ptr = NULL, + .arr_end = NULL, + .sorted = true, + .last_tag = 0, + }; + const char* ptr = *buf; + upb_CombineUnknownFields(ctx, &builder, &ptr); + upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &builder); + *buf = ptr; + return fields; +} + +// Builds a upb_UnknownFields data structure from the unknown fields of a +// upb_Message. +static upb_UnknownFields* upb_UnknownFields_Build(upb_UnknownField_Context* ctx, + const upb_Message* msg) { + upb_UnknownFields_Builder builder = { + .arr_base = NULL, + .arr_ptr = NULL, + .arr_end = NULL, + .sorted = true, + .last_tag = 0, + }; + uintptr_t iter = kUpb_Message_UnknownBegin; + upb_StringView view; + while (upb_Message_NextUnknown(msg, &view, &iter)) { + upb_EpsCopyInputStream_Init(&ctx->stream, &view.data, view.size); + upb_CombineUnknownFields(ctx, &builder, &view.data); + UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &view.data) && + !upb_EpsCopyInputStream_IsError(&ctx->stream)); + } + upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &builder); + return fields; +} + +// Compares two sorted upb_UnknownFields structures for equality. +static bool upb_UnknownFields_IsEqual(const upb_UnknownFields* uf1, + const upb_UnknownFields* uf2) { + if (uf1->size != uf2->size) return false; + for (size_t i = 0, n = uf1->size; i < n; i++) { + upb_UnknownField* f1 = &uf1->fields[i]; + upb_UnknownField* f2 = &uf2->fields[i]; + if (f1->tag != f2->tag) return false; + int wire_type = f1->tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: + if (f1->data.varint != f2->data.varint) return false; + break; + case kUpb_WireType_64Bit: + if (f1->data.uint64 != f2->data.uint64) return false; + break; + case kUpb_WireType_32Bit: + if (f1->data.uint32 != f2->data.uint32) return false; + break; + case kUpb_WireType_Delimited: + if (!upb_StringView_IsEqual(f1->data.delimited, f2->data.delimited)) { + return false; + } + break; + case kUpb_WireType_StartGroup: + if (!upb_UnknownFields_IsEqual(f1->data.group, f2->data.group)) { + return false; + } + break; + default: + UPB_UNREACHABLE(); + } + } + return true; +} + +static upb_UnknownCompareResult upb_UnknownField_DoCompare( + upb_UnknownField_Context* ctx, const upb_Message* msg1, + const upb_Message* msg2) { + upb_UnknownCompareResult ret; + // First build both unknown fields into a sorted data structure (similar + // to the UnknownFieldSet in C++). + upb_UnknownFields* uf1 = upb_UnknownFields_Build(ctx, msg1); + upb_UnknownFields* uf2 = upb_UnknownFields_Build(ctx, msg2); + + // Now perform the equality check on the sorted structures. + if (upb_UnknownFields_IsEqual(uf1, uf2)) { + ret = kUpb_UnknownCompareResult_Equal; + } else { + ret = kUpb_UnknownCompareResult_NotEqual; + } + return ret; +} + +static upb_UnknownCompareResult upb_UnknownField_Compare( + upb_UnknownField_Context* const ctx, const upb_Message* msg1, + const upb_Message* msg2) { + upb_UnknownCompareResult ret; + if (UPB_SETJMP(ctx->err) == 0) { + ret = upb_UnknownField_DoCompare(ctx, msg1, msg2); + } else { + ret = ctx->status; + UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); + } + + upb_Arena_Free(ctx->arena); + upb_gfree(ctx->tmp); + return ret; +} + +upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( + const upb_Message* msg1, const upb_Message* msg2, int max_depth) { + bool msg1_empty = !upb_Message_HasUnknown(msg1); + bool msg2_empty = !upb_Message_HasUnknown(msg2); + if (msg1_empty && msg2_empty) return kUpb_UnknownCompareResult_Equal; + if (msg1_empty || msg2_empty) return kUpb_UnknownCompareResult_NotEqual; + + upb_UnknownField_Context ctx = { + .arena = upb_Arena_New(), + .depth = max_depth, + .tmp = NULL, + .tmp_size = 0, + .status = kUpb_UnknownCompareResult_Equal, + }; + + if (!ctx.arena) return kUpb_UnknownCompareResult_OutOfMemory; + + return upb_UnknownField_Compare(&ctx, msg1, msg2); +} + + +#include +#include +#include + + +// Must be last. + +static upb_StringView upb_Clone_StringView(upb_StringView str, + upb_Arena* arena) { + if (str.size == 0) { + return upb_StringView_FromDataAndSize(NULL, 0); + } + void* cloned_data = upb_Arena_Malloc(arena, str.size); + upb_StringView cloned_str = + upb_StringView_FromDataAndSize(cloned_data, str.size); + memcpy(cloned_data, str.data, str.size); + return cloned_str; +} + +static bool upb_Clone_MessageValue(void* value, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + switch (value_type) { + case kUpb_CType_Bool: + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return true; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView source = *(upb_StringView*)value; + size_t size = source.size; + void* cloned_data = upb_Arena_Malloc(arena, size); + if (cloned_data == NULL) { + return false; + } + *(upb_StringView*)value = + upb_StringView_FromDataAndSize(cloned_data, size); + memcpy(cloned_data, source.data, size); + return true; + } break; + case kUpb_CType_Message: { + UPB_ASSERT(sub); + const upb_Message* source = *(upb_Message**)value; + UPB_ASSERT(source); + upb_Message* clone = upb_Message_DeepClone(source, sub, arena); + *(upb_Message**)value = clone; + return clone != NULL; + } break; + } + UPB_UNREACHABLE(); +} + +upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena) { + upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size); + if (cloned_map == NULL) { + return NULL; + } + upb_MessageValue key, val; + size_t iter = kUpb_Map_Begin; + while (upb_Map_Next(map, &key, &val, &iter)) { + const upb_MiniTableField* value_field = + upb_MiniTable_MapValue(map_entry_table); + const upb_MiniTable* value_sub = + upb_MiniTableField_CType(value_field) == kUpb_CType_Message + ? upb_MiniTable_GetSubMessageTable(value_field) + : NULL; + upb_CType value_field_type = upb_MiniTableField_CType(value_field); + if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) { + return NULL; + } + if (!upb_Map_Set(cloned_map, key, val, arena)) { + return NULL; + } + } + return cloned_map; +} + +static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map, + const upb_MiniTable* mini_table, + const upb_MiniTableField* f, + upb_Message* clone, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(clone)); + const upb_MiniTable* map_entry_table = upb_MiniTable_MapEntrySubMessage(f); + UPB_ASSERT(map_entry_table); + + const upb_MiniTableField* key_field = upb_MiniTable_MapKey(map_entry_table); + const upb_MiniTableField* value_field = + upb_MiniTable_MapValue(map_entry_table); + + upb_Map* cloned_map = upb_Map_DeepClone( + map, upb_MiniTableField_CType(key_field), + upb_MiniTableField_CType(value_field), map_entry_table, arena); + if (!cloned_map) { + return NULL; + } + upb_Message_SetBaseField(clone, f, &cloned_map); + return cloned_map; +} + +upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, + const upb_MiniTable* sub, upb_Arena* arena) { + const size_t size = upb_Array_Size(array); + const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(value_type); + upb_Array* cloned_array = UPB_PRIVATE(_upb_Array_New)(arena, size, lg2); + if (!cloned_array) { + return NULL; + } + if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(cloned_array, size, arena)) { + return NULL; + } + for (size_t i = 0; i < size; ++i) { + upb_MessageValue val = upb_Array_Get(array, i); + if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) { + return NULL; + } + upb_Array_Set(cloned_array, i, val); + } + return cloned_array; +} + +static bool upb_Message_Array_DeepClone(const upb_Array* array, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* clone, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(clone)); + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(field); + upb_Array* cloned_array = + upb_Array_DeepClone(array, upb_MiniTableField_CType(field), + upb_MiniTableField_CType(field) == kUpb_CType_Message + ? upb_MiniTable_GetSubMessageTable(field) + : NULL, + arena); + + // Clear out upb_Array* due to parent memcpy. + upb_Message_SetBaseField(clone, field, &cloned_array); + return true; +} + +static bool upb_Clone_ExtensionValue( + const upb_MiniTableExtension* mini_table_ext, const upb_Extension* source, + upb_Extension* dest, upb_Arena* arena) { + dest->data = source->data; + return upb_Clone_MessageValue( + &dest->data, upb_MiniTableExtension_CType(mini_table_ext), + upb_MiniTableExtension_GetSubMessage(mini_table_ext), arena); +} + +upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0); + // Only copy message area skipping upb_Message_Internal. + memcpy(dst + 1, src + 1, mini_table->UPB_PRIVATE(size) - sizeof(upb_Message)); + for (int i = 0; i < upb_MiniTable_FieldCount(mini_table); ++i) { + const upb_MiniTableField* field = + upb_MiniTable_GetFieldByIndex(mini_table, i); + if (upb_MiniTableField_IsScalar(field)) { + switch (upb_MiniTableField_CType(field)) { + case kUpb_CType_Message: { + const upb_Message* sub_message = upb_Message_GetMessage(src, field); + if (sub_message != NULL) { + const upb_MiniTable* sub_message_table = + upb_MiniTable_GetSubMessageTable(field); + upb_Message* dst_sub_message = + upb_Message_DeepClone(sub_message, sub_message_table, arena); + if (dst_sub_message == NULL) { + return NULL; + } + upb_Message_SetBaseFieldMessage(dst, field, dst_sub_message); + } + } break; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + upb_StringView str = upb_Message_GetString(src, field, empty_string); + if (str.size != 0) { + if (!upb_Message_SetString( + dst, field, upb_Clone_StringView(str, arena), arena)) { + return NULL; + } + } + } break; + default: + // Scalar, already copied. + break; + } + } else { + if (upb_MiniTableField_IsMap(field)) { + const upb_Map* map = upb_Message_GetMap(src, field); + if (map != NULL) { + if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) { + return NULL; + } + } + } else { + const upb_Array* array = upb_Message_GetArray(src, field); + if (array != NULL) { + if (!upb_Message_Array_DeepClone(array, mini_table, field, dst, + arena)) { + return NULL; + } + } + } + } + } + // Clone extensions. + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(src); + if (!in) return dst; + + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + // Clone extension + const upb_Extension* msg_ext = + upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + const upb_MiniTableField* field = &msg_ext->ext->UPB_PRIVATE(field); + upb_Extension* dst_ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + dst, msg_ext->ext, arena); + if (!dst_ext) return NULL; + if (upb_MiniTableField_IsScalar(field)) { + if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) { + return NULL; + } + } else { + upb_Array* msg_array = (upb_Array*)msg_ext->data.array_val; + UPB_ASSERT(msg_array); + upb_Array* cloned_array = upb_Array_DeepClone( + msg_array, upb_MiniTableField_CType(field), + upb_MiniTableExtension_GetSubMessage(msg_ext->ext), arena); + if (!cloned_array) { + return NULL; + } + dst_ext->data.array_val = cloned_array; + } + } else if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { + // Clone unknown + upb_StringView* unknown = upb_TaggedPtrAux_StringViewRepr(tagged_ptr); + // Make a copy into destination arena. + if (!UPB_PRIVATE(_upb_Message_AddUnknown)( + dst, unknown->data, unknown->size, arena, kUpb_AddUnknown_Copy)) { + return NULL; + } + } + } + + return dst; +} + +bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mini_table, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + upb_Message_Clear(dst, mini_table); + return _upb_Message_Copy(dst, src, mini_table, arena) != NULL; +} + +// Deep clones a message using the provided target arena. +// +// Returns NULL on failure. +upb_Message* upb_Message_DeepClone(const upb_Message* msg, + const upb_MiniTable* m, upb_Arena* arena) { + upb_Message* clone = upb_Message_New(m, arena); + return _upb_Message_Copy(clone, msg, m, arena); +} + +// Performs a shallow copy. +bool upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* m, upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(dst)); + memcpy(dst, src, m->UPB_PRIVATE(size)); + + const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(src); + if (!in) return true; + + size_t size = UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, in->size); + upb_Message_Internal* dst_in = upb_Arena_Malloc(arena, size); + if (!dst_in) return false; + + dst_in->size = in->size; + dst_in->capacity = in->size; + + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAux aux; + switch (upb_TaggedAux_Get(in->aux_data[i], &aux)) { + case kUpb_TaggedAuxType_CanonicalExtension: { + const upb_Extension* msg_ext = aux.extension; + upb_Extension* dst_ext = upb_Arena_Malloc(arena, sizeof(upb_Extension)); + if (!dst_ext) return false; + *dst_ext = *msg_ext; + dst_in->aux_data[i] = upb_TaggedAuxPtr_MakeCanonicalExtension(dst_ext); + break; + } + case kUpb_TaggedAuxType_Unknown: + case kUpb_TaggedAuxType_AliasedUnknown: { + upb_StringView* dst_sv = + upb_Arena_Malloc(arena, sizeof(upb_StringView)); + if (!dst_sv) return false; + *dst_sv = *aux.unknown_data; + dst_in->aux_data[i] = upb_TaggedAuxPtr_MakeUnknownDataAliased(dst_sv); + break; + } + case kUpb_TaggedAuxType_NonCanonicalExtension: { + const upb_Extension* msg_ext = aux.extension; + upb_Extension* dst_ext = upb_Arena_Malloc(arena, sizeof(upb_Extension)); + if (!dst_ext) return false; + *dst_ext = *msg_ext; + dst_in->aux_data[i] = + upb_TaggedAuxPtr_MakeNonCanonicalExtension(dst_ext); + break; + } + } + } + + UPB_PRIVATE(_upb_Message_SetInternal)(dst, dst_in); + return true; +} + +// Performs a shallow clone. +upb_Message* upb_Message_ShallowClone(const upb_Message* msg, + const upb_MiniTable* m, + upb_Arena* arena) { + upb_Message* clone = upb_Message_New(m, arena); + if (!clone) return NULL; + if (!upb_Message_ShallowCopy(clone, msg, m, arena)) return NULL; + return clone; +} + +#include "stddef.h" + +// Must be last. + +bool upb_Message_MergeFrom(upb_Message* dst, const upb_Message* src, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + upb_Arena* arena) { + char* buf = NULL; + size_t size = 0; + // This tmp arena is used to hold the bytes for `src` serialized. This bends + // the typical "no hidden allocations" design of upb, but under a properly + // optimized implementation this extra allocation would not be necessary and + // so we don't want to unnecessarily have the bad API or bloat the passed-in + // arena with this very-short-term allocation. + upb_Arena* encode_arena = upb_Arena_New(); + upb_EncodeStatus e_status = upb_Encode(src, mt, 0, encode_arena, &buf, &size); + if (e_status != kUpb_EncodeStatus_Ok) { + upb_Arena_Free(encode_arena); + return false; + } + upb_DecodeStatus d_status = upb_Decode(buf, size, dst, mt, extreg, 0, arena); + if (d_status != kUpb_DecodeStatus_Ok) { + upb_Arena_Free(encode_arena); + return false; + } + upb_Arena_Free(encode_arena); + return true; +} + + +#include +#include + + +// Must be last. + +const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( + const struct upb_Message* msg, const upb_MiniTableExtension* e) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return NULL; + + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + const upb_Extension* ext = + upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + if (ext->ext == e) { + return ext; + } + } + } + + return NULL; +} + +UPB_INLINE upb_Extension* _upb_Message_GetOrCreateExtensionInternal( + struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a, + bool canonical) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); + if (ext) return ext; + + if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL; + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + ext = upb_Arena_Malloc(a, sizeof(upb_Extension)); + if (!ext) return NULL; + memset(ext, 0, sizeof(upb_Extension)); + ext->ext = e; + in->aux_data[in->size++] = + canonical ? upb_TaggedAuxPtr_MakeCanonicalExtension(ext) + : upb_TaggedAuxPtr_MakeNonCanonicalExtension(ext); + return ext; +} + +upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) { + return _upb_Message_GetOrCreateExtensionInternal(msg, e, a, + /*canonical=*/true); +} + +upb_Extension* UPB_PRIVATE(_upb_Message_CreateNonCanonicalExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) { + return _upb_Message_GetOrCreateExtensionInternal(msg, e, a, + /*canonical=*/false); +} + + +#include +#include +#include +#include + + +// Must be last. + +// The latest win32 SDKs have an invalid definition of NAN. +// https://developercommunity.visualstudio.com/t/NAN-is-no-longer-compile-time-constant-i/10688907 +// +// Unfortunately, the `0.0 / 0.0` workaround doesn't work in Clang under C23, so +// try __builtin_nan first, if that exists. +#ifdef _WIN32 +#ifdef __has_builtin +#if __has_builtin(__builtin_nan) +#define UPB_NAN __builtin_nan("0") +#endif +#if __has_builtin(__builtin_inf) +#define UPB_INFINITY __builtin_inf() +#endif +#endif +#ifndef UPB_NAN +#define UPB_NAN 0.0 / 0.0 +#endif +#ifndef UPB_INFINITY +#define UPB_INFINITY 1.0 / 0.0 +#endif +#else +// For !_WIN32, assume math.h works. +#define UPB_NAN NAN +#define UPB_INFINITY INFINITY +#endif + +const float kUpb_FltInfinity = UPB_INFINITY; +const double kUpb_Infinity = UPB_INFINITY; +const double kUpb_NaN = UPB_NAN; + +static size_t _upb_Message_SizeOfInternal(uint32_t count) { + return UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, count); +} + +bool UPB_PRIVATE(_upb_Message_ReserveSlot)(struct upb_Message* msg, + upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) { + // No internal data, allocate from scratch. + uint32_t capacity = 4; + in = upb_Arena_Malloc(a, _upb_Message_SizeOfInternal(capacity)); + if (!in) return false; + in->size = 0; + in->capacity = capacity; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); + } else if (in->capacity == in->size) { + if (in->size == UINT32_MAX) return false; + // Internal data is too small, reallocate. + size_t needed_pow2 = upb_RoundUpToPowerOfTwo(in->size + 1); + if (needed_pow2 > UINT32_MAX) return false; + uint32_t new_capacity = needed_pow2; + if (UPB_SIZEOF_FLEX_WOULD_OVERFLOW(upb_Message_Internal, aux_data, + new_capacity)) { + return false; + } + in = upb_Arena_Realloc(a, in, _upb_Message_SizeOfInternal(in->capacity), + _upb_Message_SizeOfInternal(new_capacity)); + if (!in) return false; + in->capacity = new_capacity; + UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); + } + UPB_ASSERT(in->capacity - in->size >= 1); + return true; +} + +#ifdef UPB_TRACING_ENABLED +static void (*_message_trace_handler)(const upb_MiniTable*, const upb_Arena*); + +void upb_Message_LogNewMessage(const upb_MiniTable* m, const upb_Arena* arena) { + if (_message_trace_handler) { + _message_trace_handler(m, arena); + } +} + +void upb_Message_SetNewMessageTraceHandler(void (*handler)(const upb_MiniTable*, + const upb_Arena*)) { + _message_trace_handler = handler; +} +#endif // UPB_TRACING_ENABLED + + +#include + + +// Must be last. + +bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField** out_f, + upb_MessageValue* out_v, + size_t* iter) { + const size_t count = upb_MiniTable_FieldCount(m); + size_t i = *iter; + + while (++i < count) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + const void* src = UPB_PRIVATE(_upb_Message_DataPtr)(msg, f); + + upb_MessageValue val; + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, &val, src); + + // Skip field if unset or empty. + if (upb_MiniTableField_HasPresence(f)) { + if (!upb_Message_HasBaseField(msg, f)) continue; + } else { + if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(f, src)) continue; + + if (upb_MiniTableField_IsArray(f)) { + if (upb_Array_Size(val.array_val) == 0) continue; + } else if (upb_MiniTableField_IsMap(f)) { + if (upb_Map_Size(val.map_val) == 0) continue; + } + } + + *out_f = f; + *out_v = val; + *iter = i; + return true; + } + + return false; +} + + +#include +#include + + +// Must be last. + +typedef struct { + upb_MdDecoder base; + upb_Arena* arena; + upb_MiniTableEnum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; +} upb_MdEnumDecoder; + +static size_t upb_MiniTableEnum_Size(uint32_t count) { + return UPB_SIZEOF_FLEX(upb_MiniTableEnum, UPB_PRIVATE(data), count); +} + +static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + if (d->enum_data_capacity > UINT32_MAX / 2) { + upb_MdDecoder_ErrorJmp(&d->base, "Out of memory"); + } + uint32_t new_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + if (UPB_SIZEOF_FLEX_WOULD_OVERFLOW(upb_MiniTableEnum, UPB_PRIVATE(data), + new_capacity)) { + upb_MdDecoder_ErrorJmp(&d->base, "Out of memory"); + } + size_t new_sz = upb_MiniTableEnum_Size(new_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); + d->enum_data_capacity = new_capacity; + } + d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val; + return d->enum_table; +} + +static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) { + upb_MiniTableEnum* table = d->enum_table; + d->enum_value_count++; + if (table->UPB_PRIVATE(value_count) || + (val > 512 && d->enum_value_count < val / 32)) { + if (table->UPB_PRIVATE(value_count) == 0) { + UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->UPB_PRIVATE(value_count)++; + } else { + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->UPB_PRIVATE(mask_limit) += 32; + } + table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32); + } +} + +static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum( + upb_MdEnumDecoder* d, const char* data, size_t len) { + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_EnumV1) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid enum version: %c", *data); + } + data++; + len--; + } + + upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); + + // Guarantee at least 64 bits of mask without checking mask size. + d->enum_table->UPB_PRIVATE(mask_limit) = 64; + d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); + d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); + + d->enum_table->UPB_PRIVATE(value_count) = 0; + + const char* ptr = data; + uint32_t base = 0; + + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = _upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) upb_MiniTableEnum_BuildValue(d, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_MdDecoder_ErrorJmp(&d->base, "Unexpected character: %c", ch); + } + } + + return d->enum_table; +} + +static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum( + upb_MdEnumDecoder* const decoder, const char* const data, + size_t const len) { + if (UPB_SETJMP(decoder->base.err) != 0) return NULL; + return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len); +} + +upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + uint32_t initial_capacity = 2; + upb_MdEnumDecoder decoder = { + .base = + { + .end = UPB_PTRADD(data, len), + .status = status, + }, + .arena = arena, + .enum_table = + upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(initial_capacity)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = initial_capacity, + }; + + return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len); +} + + +#include +#include +#include +#include +#include + + +// Our awkward dance for including fasttable only when it is enabled. +#if UPB_FASTTABLE +#define UPB_INCLUDE_FAST_DECODE +#endif + +#ifdef UPB_INCLUDE_FAST_DECODE +#endif + +#undef UPB_INCLUDE_FAST_DECODE + +// Must be last. + +// We reserve unused hasbits to make room for upb_Message fields. +#define kUpb_Reserved_Hasbytes sizeof(struct upb_Message) + +// 64 is the first hasbit that we currently use. +#define kUpb_Reserved_Hasbits (kUpb_Reserved_Hasbytes * 8) + +#define kUpb_OneOfLayoutItem_IndexSentinel ((uint16_t)-1) + +// Stores the field number of the present value of the oneof +#define kUpb_OneOf_CaseFieldRep (kUpb_FieldRep_4Byte) + +// The maximum field number that can be encoded on the wire. +// Note that this limit does not apply to MessageSet, which can have field +// numbers up to INT32_MAX. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +typedef struct { + // Index of the corresponding field. The field's offset will be the index of + // the next field in a linked list. + uint16_t field_index; + // This enum is stored in bytes to avoid trailing padding while preserving + // two-byte alignment. + uint8_t /* upb_FieldRep*/ rep; +} upb_OneOfLayoutItem; + +typedef struct { + upb_OneOfLayoutItem* data; + size_t size; + size_t buf_capacity_bytes; +} upb_OneOfLayoutItemVector; + +typedef struct { + upb_MdDecoder base; + upb_MiniTableField* fields; + upb_MiniTablePlatform platform; + upb_OneOfLayoutItemVector oneofs; + upb_Arena* arena; + // Initially tracks the count of each field rep type; then, during assignment, + // tracks the base offset for the next processed field of the given rep. + uint16_t rep_counts_offsets[kUpb_FieldRep_Max + 1]; + uint32_t sub_count; + bool is_extension; + + // When building fasttables, we don't know the total size of the table until + // we're done decoding, so we allocate a temporary table on the stack and + // allocate the real thing from the arena later. + upb_MiniTable table; +} upb_MtDecoder; + +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; + +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) { + return (field->UPB_PRIVATE(mode) & kUpb_FieldMode_Array) && + upb_FieldType_IsPackable(field->UPB_PRIVATE(descriptortype)); +} + +typedef struct { + uint16_t submsg_count; + uint16_t subenum_count; +} upb_SubCounts; + +static void upb_MiniTable_SetTypeAndSub(upb_MtDecoder* d, + upb_MiniTableField* field, + upb_FieldType type, + uint64_t msg_modifiers, + bool is_proto3_enum) { + if (is_proto3_enum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + type = kUpb_FieldType_Int32; + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; + } else if (type == kUpb_FieldType_String && + !(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + type = kUpb_FieldType_Bytes; + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; + } + + field->UPB_PRIVATE(descriptortype) = type; + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsPacked; + } + + // We initially set `submsg_ofs` to the index of the sub in the list of subs. + // Later, we'll update it to be a relative byte offset. + if (type == kUpb_FieldType_Message || type == kUpb_FieldType_Group || + type == kUpb_FieldType_Enum) { + field->UPB_PRIVATE(submsg_ofs) = d->sub_count++; + } else { + field->UPB_PRIVATE(submsg_ofs) = kUpb_NoSub; + } +} + +static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_OpenEnum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, +}; + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTableField* field, + uint64_t msg_modifiers) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_OpenEnum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, + }; + + char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit + ? kUpb_FieldRep_4Byte + : kUpb_FieldRep_8Byte; + + int8_t type = _upb_FromBase92(ch); + if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->UPB_PRIVATE(mode) = kUpb_FieldMode_Array; + field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; + field->UPB_PRIVATE(offset) = kNoPresence; + } else { + field->UPB_PRIVATE(mode) = kUpb_FieldMode_Scalar; + field->UPB_PRIVATE(offset) = kHasbitPresence; + if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { + field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; + } else if ((unsigned long)type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); + } else { + field->UPB_PRIVATE(mode) |= kUpb_EncodedToFieldRep[type] + << kUpb_FieldRep_Shift; + } + } + if ((unsigned long)type >= sizeof(kUpb_EncodedToType)) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); + } + upb_MiniTable_SetTypeAndSub(d, field, kUpb_EncodedToType[type], msg_modifiers, + type == kUpb_EncodedType_OpenEnum); +} + +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTableField* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Cannot flip packed on unpackable field %" PRIu32, + upb_MiniTableField_Number(field)); + } + field->UPB_PRIVATE(mode) ^= kUpb_LabelFlags_IsPacked; + } + + if (field_modifiers & kUpb_EncodedFieldModifier_FlipValidateUtf8) { + if (field->UPB_PRIVATE(descriptortype) != kUpb_FieldType_Bytes || + !(field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsAlternate)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Cannot flip ValidateUtf8 on field %" PRIu32 + ", type=%d, mode=%d", + upb_MiniTableField_Number(field), + (int)field->UPB_PRIVATE(descriptortype), + (int)field->UPB_PRIVATE(mode)); + } + field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_String; + field->UPB_PRIVATE(mode) &= ~kUpb_LabelFlags_IsAlternate; + } + + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + + // Validate. + if ((singular || required) && field->UPB_PRIVATE(offset) != kHasbitPresence) { + upb_MdDecoder_ErrorJmp(&d->base, + "Invalid modifier(s) for repeated field %" PRIu32, + upb_MiniTableField_Number(field)); + } + if (singular && required) { + upb_MdDecoder_ErrorJmp( + &d->base, "Field %" PRIu32 " cannot be both singular and required", + upb_MiniTableField_Number(field)); + } + + if (singular && upb_MiniTableField_IsSubMessage(field)) { + upb_MdDecoder_ErrorJmp(&d->base, + "Field %" PRIu32 " cannot be a singular submessage", + upb_MiniTableField_Number(field)); + } + + if (singular) field->UPB_PRIVATE(offset) = kNoPresence; + if (required) { + field->UPB_PRIVATE(offset) = kRequiredPresence; + } +} + +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, + upb_OneOfLayoutItem item) { + if (item.field_index == kUpb_OneOfLayoutItem_IndexSentinel) { + upb_MdDecoder_ErrorJmp(&d->base, "Empty oneof"); + } + if ((d->oneofs.size + 1) * sizeof(*d->oneofs.data) > + d->oneofs.buf_capacity_bytes) { + size_t new_cap = UPB_MAX(8, d->oneofs.size * 2) * sizeof(*d->oneofs.data); + d->oneofs.data = + upb_grealloc(d->oneofs.data, d->oneofs.buf_capacity_bytes, new_cap); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->oneofs.data); + d->oneofs.buf_capacity_bytes = new_cap; + } + item.field_index -= kOneofBase; + + d->rep_counts_offsets[kUpb_OneOf_CaseFieldRep]++; + d->rep_counts_offsets[item.rep]++; + d->oneofs.data[d->oneofs.size++] = item; +} + +static size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + enum { string_view_size_32 = 8, string_view_size_64 = 16 }; + UPB_STATIC_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(string_view_size_32, string_view_size_64), + "StringView size mismatch"); + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = string_view_size_32, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = string_view_size_64, + [kUpb_FieldRep_8Byte] = 8, + }; + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +static size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + enum { string_view_align_32 = 4, string_view_align_64 = 8 }; + UPB_STATIC_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(string_view_align_32, string_view_align_64), + "StringView size mismatch"); + + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = string_view_align_32, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_StringView] = string_view_align_64, + [kUpb_FieldRep_8Byte] = 8, + }; + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_OneOfLayoutItem* item) { + uint32_t field_num; + ptr = upb_MdDecoder_DecodeBase92Varint( + &d->base, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTableField* f = + (void*)upb_MiniTable_FindFieldByNumber(&d->table, field_num); + + if (!f) { + upb_MdDecoder_ErrorJmp(&d->base, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + } + if (f->UPB_PRIVATE(offset) != kHasbitPresence) { + upb_MdDecoder_ErrorJmp( + &d->base, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + } + + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift; + size_t new_size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t new_align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t current_size = upb_MtDecoder_SizeOfRep(item->rep, d->platform); + size_t current_align = upb_MtDecoder_AlignOfRep(item->rep, d->platform); + + if (new_size > current_size || + (new_size == current_size && new_align > current_align)) { + UPB_ASSERT(new_align >= current_align); + item->rep = rep; + } else { + UPB_ASSERT(current_align >= new_align); + } + // Prepend this field to the linked list. + f->UPB_PRIVATE(offset) = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} + +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_OneOfLayoutItem item = { + .rep = 0, .field_index = kUpb_OneOfLayoutItem_IndexSentinel}; + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = + kUpb_OneOfLayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } + + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} + +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTableField* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); + } else { + if (d->is_extension) { + upb_MdDecoder_ErrorJmp(&d->base, + "Extensions cannot have message modifiers"); + } + *msg_modifiers = mod; + } + + return ptr; +} + +size_t upb_MtDecoder_PtrSize(upb_MtDecoder* d) { + return d->platform == kUpb_MiniTablePlatform_32Bit ? 4 : 8; +} + +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, + upb_MiniTableSubInternal* subs) { + // The `ofs` variable tracks byte offset between the current field and the + // current entry in the `subs` array. Whenever we move to the next entry in + // the `fields` array, the offset decreases by the size of the field, but + // whenever we move to the next entry in the `subs` array, the offset + // *increases* by the size of the entry in the `subs` array. + UPB_ASSERT((char*)subs >= (char*)d->fields); + size_t ofs = (char*)subs - (char*)d->fields; + uintptr_t ptr_size = upb_MtDecoder_PtrSize(d); + for (int i = 0; i < d->table.UPB_PRIVATE(field_count); + i++, ofs -= sizeof(upb_MiniTableField)) { + upb_MiniTableField* f = &d->fields[i]; + if (f->UPB_PRIVATE(submsg_ofs) == kUpb_NoSub) continue; + size_t u32_ofs = ofs / kUpb_SubmsgOffsetBytes; + UPB_ASSERT((ofs % 4) == 0); + UPB_ASSERT((i * sizeof(upb_MiniTableField) + ofs) % ptr_size == 0); + if (u32_ofs > UINT16_MAX) { + upb_MdDecoder_ErrorJmp(&d->base, "Submessage offset overflow"); + } + f->UPB_PRIVATE(submsg_ofs) = u32_ofs; + ofs += ptr_size; + } +} + +static const char* upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, + size_t len, void* fields, + size_t field_size, + uint16_t* field_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTableField* last_field = NULL; + bool need_dense_below = !d->is_extension; + + d->base.end = UPB_PTRADD(ptr, len); + + while (ptr < d->base.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (d->is_extension && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTableField* field = fields; + if (*field_count == UINT16_MAX) { + upb_MdDecoder_ErrorJmp( + &d->base, "Fields in message exceed the limit of %u", UINT16_MAX); + } + *field_count += 1; + fields = (char*)fields + field_size; + uint32_t number = ++last_field_number; + if (number == 0 || (number > kUpb_MaxFieldNumber && !d->is_extension)) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid field number: %" PRIu32, + number); + } + field->UPB_PRIVATE(number) = number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table.UPB_PRIVATE(ext) |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (d->is_extension) { + upb_MdDecoder_ErrorJmp(&d->base, "Extensions cannot have oneofs."); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table.UPB_PRIVATE(dense_below) = d->table.UPB_PRIVATE(field_count); + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + if (skip == 0) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid skip value: 0"); + } + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } else { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid char: %c", ch); + } + } + + if (need_dense_below) { + d->table.UPB_PRIVATE(dense_below) = d->table.UPB_PRIVATE(field_count); + } + + return ptr; +} + +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + const size_t bytes_per_field = + sizeof(upb_MiniTableField) + sizeof(upb_MiniTableSubInternal); + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + if ((SIZE_MAX - 4) / bytes_per_field < len) { + upb_MdDecoder_ErrorJmp(&d->base, "MiniDescriptor is too large"); + } + // Max size used per field is a upb_MiniTableField and a + // upb_MiniTableSubInternal. There could also be up to 4 bytes of padding, + // since sizeof(upb_MiniTableField) == 12 and + // alignof(upb_MiniTableSubInternal) == 8. + UPB_STATIC_ASSERT(UPB_ALIGN_OF(upb_MiniTableSubInternal) - + UPB_ALIGN_OF(upb_MiniTableField) <= + 4, + "alignment difference is too large"); + const size_t initial_bytes = bytes_per_field * len + 4; + d->fields = upb_Arena_Malloc(d->arena, initial_bytes); + upb_MdDecoder_CheckOutOfMemory(&d->base, d->fields); + + d->table.UPB_PRIVATE(field_count) = 0; + d->table.UPB_PRIVATE(fields) = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table.UPB_PRIVATE(field_count)); + size_t field_bytes = + UPB_ALIGN_UP(d->table.UPB_PRIVATE(field_count) * sizeof(*d->fields), + upb_MtDecoder_PtrSize(d)); + upb_MiniTableSubInternal* subs = + UPB_PTR_AT(d->fields, field_bytes, upb_MiniTableSubInternal); + memset(subs, 0, sizeof(upb_MiniTableSubInternal) * d->sub_count); + + // We now know how much space we actually used, so shrink the allocation to + // that size. + size_t final_bytes = + field_bytes + sizeof(upb_MiniTableSubInternal) * d->sub_count; + upb_Arena_ShrinkLast(d->arena, d->fields, initial_bytes, final_bytes); + upb_MtDecoder_AllocateSubs(d, subs); +} + +static void upb_MtDecoder_CalculateAlignments(upb_MtDecoder* d) { + // Add alignment counts for non-oneof fields (oneofs were added already) + int n = d->table.UPB_PRIVATE(field_count); + for (int i = 0; i < n; i++) { + upb_MiniTableField* f = &d->fields[i]; + if (f->UPB_PRIVATE(offset) >= kOneofBase) continue; + d->rep_counts_offsets[f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift]++; + } + + // Reserve properly aligned space for each type of field representation + // present in this message. When we iterate over the fields, they will obtain + // their offset from within the region matching their alignment requirements. + size_t base = d->table.UPB_PRIVATE(size); + // Start with the lowest alignment requirement, going up, because: + // 1. If there are presence bits, we won't be aligned to start, but adding + // some lower-alignment fields may get us closer without wasting space to + // padding. + // 2. The allocator enforces 8 byte alignment, so moving intermediate padding + // to trailing padding doesn't save us anything. + for (upb_FieldRep rep = kUpb_FieldRep_1Byte; rep <= kUpb_FieldRep_Max; + rep++) { + uint16_t count = d->rep_counts_offsets[rep]; + if (count) { + base = UPB_ALIGN_UP(base, upb_MtDecoder_AlignOfRep(rep, d->platform)); + // This entry now tracks the base offset for this field representation + // type, instead of the count + d->rep_counts_offsets[rep] = base; + base += upb_MtDecoder_SizeOfRep(rep, d->platform) * count; + } + } + static const size_t max = UINT16_MAX; + if (base > max) { + upb_MdDecoder_ErrorJmp( + &d->base, "Message size exceeded maximum size of %zu bytes", max); + } + d->table.UPB_PRIVATE(size) = (uint16_t)base; +} + +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static void upb_MtDecoder_AssignHasbits(upb_MtDecoder* d) { + int n = d->table.UPB_PRIVATE(field_count); + size_t last_hasbit = kUpb_Reserved_Hasbits - 1; + + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = + (upb_MiniTableField*)&d->table.UPB_PRIVATE(fields)[i]; + if (field->UPB_PRIVATE(offset) == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->UPB_PRIVATE(offset) == kNoPresence) { + field->presence = 0; + } + } + if (last_hasbit >= kUpb_Reserved_Hasbits + 63) { + upb_MdDecoder_ErrorJmp(&d->base, "Too many required fields"); + } + + d->table.UPB_PRIVATE(required_count) = + last_hasbit - (kUpb_Reserved_Hasbits - 1); + UPB_ASSERT(d->table.UPB_PRIVATE(required_count) < 64); + + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = + (upb_MiniTableField*)&d->table.UPB_PRIVATE(fields)[i]; + if (field->UPB_PRIVATE(offset) == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } + + d->table.UPB_PRIVATE(size) = + last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +static size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t offset = d->rep_counts_offsets[rep]; + d->rep_counts_offsets[rep] += size; + return offset; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_MiniTableField* field_end = + UPB_PTRADD(d->fields, d->table.UPB_PRIVATE(field_count)); + for (upb_MiniTableField* field = d->fields; field < field_end; field++) { + if (field->UPB_PRIVATE(offset) >= kOneofBase) continue; + field->UPB_PRIVATE(offset) = + upb_MtDecoder_Place(d, field->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift); + } + + upb_OneOfLayoutItem* oneof_end = UPB_PTRADD(d->oneofs.data, d->oneofs.size); + + for (upb_OneOfLayoutItem* item = d->oneofs.data; item < oneof_end; item++) { + upb_MiniTableField* f = &d->fields[item->field_index]; + uint16_t case_offset = upb_MtDecoder_Place(d, kUpb_OneOf_CaseFieldRep); + uint16_t data_offset = upb_MtDecoder_Place(d, item->rep); + while (true) { + f->presence = ~case_offset; + uint16_t next_offset = f->UPB_PRIVATE(offset); + f->UPB_PRIVATE(offset) = data_offset; + if (next_offset == kUpb_OneOfLayoutItem_IndexSentinel) break; + UPB_ASSERT(next_offset - kOneofBase < d->table.UPB_PRIVATE(field_count)); + f = &d->fields[next_offset - kOneofBase]; + } + } + + // Since messages are always allocated on arenas, we can save repeatedly + // realigning by doing alignment at minitable construction time. We don't want + // to align to UPB_MALLOC_ALIGN because it can change with sanitizers, and if + // we're generating code we don't want to calculate size differently depending + // on the proto compiler's host or build configuration. + d->table.UPB_PRIVATE(size) = + UPB_ALIGN_UP(d->table.UPB_PRIVATE(size), kUpb_Message_Align); +} + +static void upb_MtDecoder_ValidateEntryField(upb_MtDecoder* d, + const upb_MiniTableField* f, + uint32_t expected_num) { + const char* name = expected_num == 1 ? "key" : "val"; + const uint32_t f_number = upb_MiniTableField_Number(f); + if (f_number != expected_num) { + upb_MdDecoder_ErrorJmp(&d->base, + "map %s did not have expected number (%d vs %d)", + name, expected_num, f_number); + } + + if (!upb_MiniTableField_IsScalar(f)) { + upb_MdDecoder_ErrorJmp( + &d->base, "map %s cannot be repeated or map, or be in oneof", name); + } + + uint32_t not_ok_types; + if (expected_num == 1) { + not_ok_types = (1 << kUpb_FieldType_Float) | (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Message) | (1 << kUpb_FieldType_Group) | + (1 << kUpb_FieldType_Bytes) | (1 << kUpb_FieldType_Enum); + } else { + not_ok_types = 1 << kUpb_FieldType_Group; + } + + if ((1 << upb_MiniTableField_Type(f)) & not_ok_types) { + upb_MdDecoder_ErrorJmp(&d->base, "map %s cannot have type %d", name, + (int)f->UPB_PRIVATE(descriptortype)); + } +} + +static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, + size_t len) { + upb_MtDecoder_ParseMessage(d, data, len); + upb_MtDecoder_AssignHasbits(d); + + if (UPB_UNLIKELY(d->table.UPB_PRIVATE(field_count) != 2)) { + upb_MdDecoder_ErrorJmp(&d->base, "%hu fields in map", + d->table.UPB_PRIVATE(field_count)); + UPB_UNREACHABLE(); + } + + if (d->oneofs.size != 0) { + upb_MdDecoder_ErrorJmp(&d->base, "Map entry cannot have oneof"); + } + + upb_MtDecoder_ValidateEntryField(d, &d->table.UPB_PRIVATE(fields)[0], 1); + upb_MtDecoder_ValidateEntryField(d, &d->table.UPB_PRIVATE(fields)[1], 2); + + d->fields[0].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, k); + d->fields[1].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, v); + d->table.UPB_PRIVATE(size) = sizeof(upb_MapEntry); + + // Map entries have a special bit set to signal it's a map entry, used in + // upb_MiniTable_SetSubMessage() below. + d->table.UPB_PRIVATE(ext) |= kUpb_ExtMode_IsMapEntry; +} + +static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, + size_t len) { + if (len > 0) { + upb_MdDecoder_ErrorJmp(&d->base, "Invalid message set encode length: %zu", + len); + } + + upb_MiniTable* ret = &d->table; + ret->UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; + ret->UPB_PRIVATE(field_count) = 0; + ret->UPB_PRIVATE(ext) = kUpb_ExtMode_IsMessageSet; + ret->UPB_PRIVATE(dense_below) = 0; + ret->UPB_PRIVATE(table_mask) = -1; + ret->UPB_PRIVATE(required_count) = 0; +} + +static upb_MiniTable* upb_MtDecoder_DoBuildMiniTableWithBuf( + upb_MtDecoder* decoder, const char* data, size_t len, void** buf, + size_t* buf_size) { + decoder->table.UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; + decoder->table.UPB_PRIVATE(field_count) = 0; + decoder->table.UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable; + decoder->table.UPB_PRIVATE(dense_below) = 0; + decoder->table.UPB_PRIVATE(table_mask) = -1; + decoder->table.UPB_PRIVATE(required_count) = 0; +#ifdef UPB_TRACING_ENABLED + // MiniTables built from MiniDescriptors will not be able to vend the message + // name unless it is explicitly set with upb_MiniTable_SetFullName(). + decoder->table.UPB_PRIVATE(full_name) = 0; +#endif + + // Strip off and verify the version tag. + if (!len--) goto done; + const char vers = *data++; + + switch (vers) { + case kUpb_EncodedVersion_MapV1: + upb_MtDecoder_ParseMap(decoder, data, len); + break; + + case kUpb_EncodedVersion_MessageV1: + upb_MtDecoder_ParseMessage(decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder); + upb_MtDecoder_CalculateAlignments(decoder); + upb_MtDecoder_AssignOffsets(decoder); + break; + + case kUpb_EncodedVersion_MessageSetV1: + upb_MtDecoder_ParseMessageSet(decoder, data, len); + break; + + default: + upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid message version: %c", + vers); + } + +done: + *buf = decoder->oneofs.data; + *buf_size = decoder->oneofs.buf_capacity_bytes; + size_t mt_size = sizeof(upb_MiniTable); + +#if UPB_FASTTABLE + upb_DecodeFast_TableEntry fasttable[32]; + int fasttable_size = upb_DecodeFast_BuildTable(&decoder->table, fasttable); + mt_size += fasttable_size * sizeof(fasttable[0]); +#endif + + upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size); + memcpy(ret, &decoder->table, sizeof(*ret)); + +#if UPB_FASTTABLE + ret->UPB_PRIVATE(table_mask) = upb_DecodeFast_GetTableMask(fasttable_size); + for (int i = 0; i < fasttable_size; i++) { + ret->UPB_PRIVATE(fasttable)[i].field_data = fasttable[i].function_data; + ret->UPB_PRIVATE(fasttable)[i].field_parser = + upb_DecodeFast_GetFunctionPointer(fasttable[i].function_idx); + } +#endif + UPB_PRIVATE(upb_MiniTable_CheckInvariants)(ret); + +#ifndef NDEBUG + for (int i = 1; i < upb_MiniTable_FieldCount(ret); i++) { + const upb_MiniTableField* f1 = upb_MiniTable_GetFieldByIndex(ret, i - 1); + const upb_MiniTableField* f2 = upb_MiniTable_GetFieldByIndex(ret, i); + UPB_ASSERT(upb_MiniTableField_Number(f2) > upb_MiniTableField_Number(f1)); + } +#endif + return ret; +} + +static upb_MiniTable* upb_MtDecoder_BuildMiniTableWithBuf( + upb_MtDecoder* const decoder, const char* const data, const size_t len, + void** const buf, size_t* const buf_size) { + if (UPB_SETJMP(decoder->base.err) != 0) { + *buf = decoder->oneofs.data; + *buf_size = decoder->oneofs.buf_capacity_bytes; + return NULL; + } + + return upb_MtDecoder_DoBuildMiniTableWithBuf(decoder, data, len, buf, + buf_size); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .base = {.status = status}, + .platform = platform, + .sub_count = 0, + .is_extension = false, + .oneofs = + { + .data = *buf, + .buf_capacity_bytes = *buf_size, + .size = 0, + }, + .arena = arena, + }; + + return upb_MtDecoder_BuildMiniTableWithBuf(&decoder, data, len, buf, + buf_size); +} + +static const char* upb_MtDecoder_DoBuildMiniTableExtension( + upb_MtDecoder* decoder, const char* data, size_t len, + upb_MiniTableExtension* ext, const upb_MiniTable* extendee, + upb_MiniTableSub sub) { + if (!(extendee->UPB_PRIVATE(ext) & + (kUpb_ExtMode_Extendable | kUpb_ExtMode_IsMessageSet))) { + upb_MdDecoder_ErrorJmp(&decoder->base, "Extendee is not extendable"); + } + + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_ExtensionV1) { + upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid ext version: %c", *data); + } + data++; + len--; + } + + uint16_t count = 0; + const char* ret = + upb_MtDecoder_Parse(decoder, data, len, ext, sizeof(*ext), &count); + if (!ret || count != 1) return NULL; + + upb_MiniTableField* f = &ext->UPB_PRIVATE(field); + uint32_t fieldnum = upb_MiniTableField_Number(f); + + const uint32_t kMaxFieldNumber = (1 << 29) - 1; + if (fieldnum == 0 || + (fieldnum > kMaxFieldNumber && !upb_MiniTable_IsMessageSet(extendee))) { + upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid extension field number"); + } + + if (upb_MiniTable_FindFieldByNumber(extendee, fieldnum) != NULL) { + upb_MdDecoder_ErrorJmp(&decoder->base, + "Extension overlaps with a known field"); + } + + f->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsExtension; + f->UPB_PRIVATE(offset) = 0; + f->presence = 0; + + // In upb_MiniTableExtension, the `sub` member is a pointer-sized member that + // directly follows the `field` member. + f->UPB_PRIVATE(submsg_ofs) = + UPB_ALIGN_UP(sizeof(upb_MiniTableField), upb_MtDecoder_PtrSize(decoder)) / + kUpb_SubmsgOffsetBytes; + + if (extendee->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_MiniTableField_IsSubMessage(f)) return NULL; + + // Extensions of MessageSet must be non-repeating. + if (upb_MiniTableField_IsArray(f)) return NULL; + } + + ext->UPB_PRIVATE(extendee) = extendee; + ext->UPB_PRIVATE(sub) = sub; + + return ret; +} + +static const char* upb_MtDecoder_BuildMiniTableExtension( + upb_MtDecoder* const decoder, const char* const data, const size_t len, + upb_MiniTableExtension* const ext, const upb_MiniTable* const extendee, + const upb_MiniTableSub sub) { + if (UPB_SETJMP(decoder->base.err) != 0) return NULL; + return upb_MtDecoder_DoBuildMiniTableExtension(decoder, data, len, ext, + extendee, sub); +} + +const char* _upb_MiniTableExtension_Init(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status) { + upb_MtDecoder decoder = { + .base = {.status = status}, + .arena = NULL, + .platform = platform, + .sub_count = 0, + .is_extension = true, + }; + + return upb_MtDecoder_BuildMiniTableExtension(&decoder, data, len, ext, + extendee, sub); +} + +upb_MiniTableExtension* _upb_MiniTableExtension_Build( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTableSub sub, upb_MiniTablePlatform platform, upb_Arena* arena, + upb_Status* status) { + upb_MiniTableExtension* ext = + upb_Arena_Malloc(arena, sizeof(upb_MiniTableExtension)); + if (UPB_UNLIKELY(!ext)) return NULL; + + const char* ptr = _upb_MiniTableExtension_Init(data, len, ext, extendee, sub, + platform, status); + if (UPB_UNLIKELY(!ptr)) return NULL; + + return ext; +} + +upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + upb_gfree(buf); + return ret; +} + + +#include +#include +#include + + +// Our awkward dance for including fasttable only when it is enabled. +#if UPB_FASTTABLE +#define UPB_INCLUDE_FAST_DECODE +#endif + +#ifdef UPB_INCLUDE_FAST_DECODE +#endif + +#undef UPB_INCLUDE_FAST_DECODE + +// Must be last. + +bool upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTableField* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && + (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + + table->UPB_PRIVATE(field_count))); + UPB_ASSERT(sub); + + const bool sub_is_map = sub->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; + + switch (field->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Message: + if (sub_is_map) { + const bool table_is_map = + table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; + if (UPB_UNLIKELY(table_is_map)) return false; + + field->UPB_PRIVATE(mode) = + (field->UPB_PRIVATE(mode) & ~kUpb_FieldMode_Mask) | + kUpb_FieldMode_Map; + +#if UPB_FASTTABLE + // The fasttable decoder cannot decode maps. Unfortunately we do not + // know until this moment that the field is a map, so we have to + // overwrite the fasttable entry (if any) that we built for this field + // previously. + int size = table->UPB_PRIVATE(table_mask) == 0xff + ? 0 + : ((table->UPB_PRIVATE(table_mask) >> 3) + 1); + for (int i = 0; i < size; i++) { + _upb_FastTable_Entry* entry = &table->UPB_PRIVATE(fasttable)[i]; + uint32_t field_number = (((int)entry->field_data >> 3) & 0xf) | + (((int)entry->field_data >> 4) & 0x7f0); + if (field_number == upb_MiniTableField_Number(field)) { + entry->field_parser = &_upb_FastDecoder_DecodeGeneric; + entry->field_data = 0; + } + } +#endif + } + break; + + case kUpb_FieldType_Group: + if (UPB_UNLIKELY(sub_is_map)) return false; + break; + + default: + return false; + } + + upb_MiniTableSubInternal* table_sub = + UPB_PTR_AT(field, field->UPB_PRIVATE(submsg_ofs) * kUpb_SubmsgOffsetBytes, + upb_MiniTableSubInternal); + // TODO: Add this assert back once YouTube is updated to not call + // this function repeatedly. + // UPB_ASSERT(upb_MiniTable_GetSubMessageTable(table, field) == NULL); + table_sub->UPB_PRIVATE(submsg) = sub; + return true; +} + +bool upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub) { + UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && + (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + + table->UPB_PRIVATE(field_count))); + UPB_ASSERT(sub); + + if (field->UPB_PRIVATE(descriptortype) != kUpb_FieldType_Enum) { + return false; + } + + if ((table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry) && + !upb_MiniTableEnum_CheckValue(sub, 0)) { + // An enum used in a map must include 0 as a value. This matches a check + // performed in protoc ("Enum value in map must define 0 as the first + // value"). Protoc should ensure that we never get here. + // + // This ends up being important if we receive wire messages where a map + // entry omits the value (and thus defaults to 0). + return false; + } + + upb_MiniTableSubInternal* table_sub = + UPB_PTR_AT(field, field->UPB_PRIVATE(submsg_ofs) * kUpb_SubmsgOffsetBytes, + upb_MiniTableSubInternal); + *table_sub = upb_MiniTableSub_FromEnum(sub); + return true; +} + +uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* m, + const upb_MiniTableField** subs) { + uint32_t msg_count = 0; + uint32_t enum_count = 0; + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { + *subs = f; + ++subs; + msg_count++; + } + } + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_IsClosedEnum(f)) { + *subs = f; + ++subs; + enum_count++; + } + } + + return (msg_count << 16) | enum_count; +} + +// The list of sub_tables and sub_enums must exactly match the number and order +// of sub-message fields and sub-enum fields given by upb_MiniTable_GetSubList() +// above. +bool upb_MiniTable_Link(upb_MiniTable* m, const upb_MiniTable** sub_tables, + size_t sub_table_count, + const upb_MiniTableEnum** sub_enums, + size_t sub_enum_count) { + uint32_t msg_count = 0; + uint32_t enum_count = 0; + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + upb_MiniTableField* f = + (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { + const upb_MiniTable* sub = sub_tables[msg_count++]; + if (msg_count > sub_table_count) return false; + if (sub && !upb_MiniTable_SetSubMessage(m, f, sub)) return false; + } + } + + for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { + upb_MiniTableField* f = + (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); + if (upb_MiniTableField_IsClosedEnum(f)) { + const upb_MiniTableEnum* sub = sub_enums[enum_count++]; + if (enum_count > sub_enum_count) return false; + if (sub && !upb_MiniTable_SetSubEnum(m, f, sub)) return false; + } + } + + return (msg_count == sub_table_count) && (enum_count == sub_enum_count); +} + + +const char _kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', +}; + +const int8_t _kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, +}; + + +#include +#include +#include + + +// Must be last. + +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; + +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; + +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; +} + +static char* upb_MtDataEncoder_PutRaw(upb_MtDataEncoder* e, char* ptr, + char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = ch; + return ptr; +} + +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +} + +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = upb_Log2Ceiling(_upb_FromBase92(max) - _upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + _upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} + +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); + } + return ptr; +} + +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +} + +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, uint64_t key_mod, + uint64_t value_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); + if (!ptr) return NULL; + + ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, key_mod); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); +} + +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { + (void)upb_MtDataEncoder_GetInternal(e, ptr); + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); +} + +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); + if (!ptr) return NULL; + + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +static char* _upb_MtDataEncoder_MaybePutFieldSkip(upb_MtDataEncoder* e, + char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + return ptr; +} + +static char* _upb_MtDataEncoder_PutFieldType(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_OpenEnum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; + + int encoded_type = kUpb_TypeToEncoded[type]; + + if (field_mod & kUpb_FieldModifier_IsClosedEnum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + encoded_type = kUpb_EncodedType_ClosedEnum; + } + + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + } + + return upb_MtDataEncoder_Put(e, ptr, encoded_type); +} + +static char* _upb_MtDataEncoder_MaybePutModifiers(upb_MtDataEncoder* e, + char* ptr, upb_FieldType type, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + uint32_t encoded_modifiers = 0; + if ((field_mod & kUpb_FieldModifier_IsRepeated) && + upb_FieldType_IsPackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + + if (type == kUpb_FieldType_String) { + bool field_validates_utf8 = field_mod & kUpb_FieldModifier_ValidateUtf8; + bool message_validates_utf8 = + in->state.msg_state.msg_modifiers & kUpb_MessageModifier_ValidateUtf8; + if (field_validates_utf8 != message_validates_utf8) { + // Old binaries do not recognize the field modifier. We need the failure + // mode to be too lax rather than too strict. Our caller should have + // handled this (see _upb_MessageDef_ValidateUtf8()). + assert(!message_validates_utf8); + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipValidateUtf8; + } + } + + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoder_GetInternal(e, ptr); + + ptr = _upb_MtDataEncoder_MaybePutFieldSkip(e, ptr, field_num); + if (!ptr) return NULL; + + ptr = _upb_MtDataEncoder_PutFieldType(e, ptr, type, field_mod); + if (!ptr) return NULL; + + return _upb_MtDataEncoder_MaybePutModifiers(e, ptr, type, field_mod); +} + +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, _upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, _upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} + +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, _upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, _upb_ToBase92(0), + _upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} + +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; + + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); +} + +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} + +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO: optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + if (!ptr) { + return NULL; + } + delta -= 5; + } + + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } + + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} + +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} + + +#include +#include +#include + + +// Must be last. + +struct upb_ExtensionRegistry { + upb_exttable exts; + upb_Arena* arena; +}; + +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_exttable_init(&r->exts, 8, arena)) return NULL; + return r; +} + +UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add( + upb_ExtensionRegistry* r, const upb_MiniTableExtension* e) { + UPB_STATIC_ASSERT( + offsetof(upb_MiniTableExtension, + UPB_PRIVATE(field).UPB_PRIVATE(number)) == 0, + "Extension must be first-member-of-struct convertable with uint32_t"); + uint32_t fieldnum = upb_MiniTableExtension_Number(e); + const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(e); + + if (upb_exttable_lookup(&r->exts, extendee, fieldnum) != NULL) { + return kUpb_ExtensionRegistryStatus_DuplicateEntry; + } + + if (!upb_exttable_insert(&r->exts, extendee, (const uint32_t*)e, r->arena)) { + return kUpb_ExtensionRegistryStatus_OutOfMemory; + } + return kUpb_ExtensionRegistryStatus_Ok; +} + +upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray( + upb_ExtensionRegistry* r, const upb_MiniTableExtension** e, size_t count) { + const upb_MiniTableExtension** start = e; + const upb_MiniTableExtension** end = UPB_PTRADD(e, count); + upb_ExtensionRegistryStatus status = kUpb_ExtensionRegistryStatus_Ok; + for (; e < end; e++) { + status = upb_ExtensionRegistry_Add(r, *e); + if (status != kUpb_ExtensionRegistryStatus_Ok) goto failure; + } + return kUpb_ExtensionRegistryStatus_Ok; + +failure: + // Back out the entries previously added. + for (end = e, e = start; e < end; e++) { + const upb_MiniTableExtension* ext = *e; + upb_exttable_remove(&r->exts, upb_MiniTableExtension_Extendee(ext), + upb_MiniTableExtension_Number(ext)); + } + UPB_ASSERT(status != kUpb_ExtensionRegistryStatus_Ok); + return status; +} + +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { + const uint32_t* v = upb_exttable_lookup(&r->exts, t, num); + return (const upb_MiniTableExtension*)v; +} + +size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r) { + return upb_exttable_size(&r->exts); +} + + +#include +#include + + +// Must be last. + +#if UPB_TSAN +#include +#endif // UPB_TSAN + +const UPB_PRIVATE(upb_GeneratedExtensionListEntry) * + UPB_PRIVATE(upb_generated_extension_list) = NULL; + +typedef struct upb_GeneratedRegistry { + UPB_ATOMIC(upb_GeneratedRegistryRef*) ref; + UPB_ATOMIC(int32_t) ref_count; +} upb_GeneratedRegistry; + +static upb_GeneratedRegistry* _upb_generated_registry(void) { + static upb_GeneratedRegistry r = {NULL, 0}; + return &r; +} + +static bool _upb_GeneratedRegistry_AddAllLinkedExtensions( + upb_ExtensionRegistry* r) { + const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* entry = + UPB_PRIVATE(upb_generated_extension_list); + while (entry != NULL) { + const upb_MiniTableExtension** current = entry->start; + for (current = entry->start; current != entry->stop; ++current) { + const upb_MiniTableExtension* ext = *current; + // Sentinels and padding introduced by the linker can result in zeroed + // entries, so simply skip them. + if (*current == NULL) { + // MSVC introduces padding that might not be sized exactly the same as + // the linker array element, but it should be properly aligned, so just + // skipping empty elements should be safe. (If the size and align of + // the array elements was different, we'd have to do something more + // complicated). + continue; + } + + if (upb_ExtensionRegistry_Add(r, ext) != + kUpb_ExtensionRegistryStatus_Ok) { + return false; + } + } + entry = entry->next; + } + return true; +} + +// Constructs a new GeneratedRegistryRef, adding all linked extensions to the +// registry or returning NULL on failure. +static upb_GeneratedRegistryRef* _upb_GeneratedRegistry_New(void) { + upb_Arena* arena = NULL; + upb_ExtensionRegistry* extreg = NULL; + upb_GeneratedRegistryRef* ref = upb_gmalloc(sizeof(upb_GeneratedRegistryRef)); + if (ref == NULL) goto err; + arena = upb_Arena_New(); + if (arena == NULL) goto err; + extreg = upb_ExtensionRegistry_New(arena); + if (extreg == NULL) goto err; + + ref->UPB_PRIVATE(arena) = arena; + ref->UPB_PRIVATE(registry) = extreg; + + if (!_upb_GeneratedRegistry_AddAllLinkedExtensions(extreg)) goto err; + + return ref; + +err: + if (arena != NULL) upb_Arena_Free(arena); + if (ref != NULL) upb_gfree(ref); + return NULL; +} + +const upb_GeneratedRegistryRef* upb_GeneratedRegistry_Load(void) { + upb_GeneratedRegistry* registry = _upb_generated_registry(); + + // Loop until we successfully acquire a reference. This loop should only + // kick in under extremely high contention, and it should be guaranteed to + // succeed. + while (true) { + int32_t count = upb_Atomic_Load(®istry->ref_count, memory_order_acquire); + + // Try to increment the refcount, but only if it's not zero. + while (count > 0) { + if (upb_Atomic_CompareExchangeStrong(®istry->ref_count, &count, + count + 1, memory_order_acquire, + memory_order_relaxed)) { + // Successfully incremented. We can now safely load and return the + // pointer. + const upb_GeneratedRegistryRef* ref = + upb_Atomic_Load(®istry->ref, memory_order_acquire); + UPB_ASSERT(ref != NULL); + return ref; + } + // CAS failed, `count` was updated. Loop will retry. + } + + // If we're here, the count was 0. Time for the slow path. + // Double-check that the pointer is NULL before trying to create. + upb_GeneratedRegistryRef* ref = + upb_Atomic_Load(®istry->ref, memory_order_acquire); + if (ref == NULL) { + // Pointer is NULL, try to create and publish a new registry. + upb_GeneratedRegistryRef* new_ref = _upb_GeneratedRegistry_New(); + if (new_ref == NULL) return NULL; // OOM + + // Try to CAS the pointer from NULL to our new_ref. + if (upb_Atomic_CompareExchangeStrong(®istry->ref, &ref, new_ref, + memory_order_release, + memory_order_acquire)) { + // We won the race. Set the ref count to 1. + upb_Atomic_Store(®istry->ref_count, 1, memory_order_release); + return new_ref; + } else { + // We lost the race. `ref` now holds the pointer from the winning + // thread. Clean up our unused one and loop to try again to get a + // reference. + upb_Arena_Free(new_ref->UPB_PRIVATE(arena)); + upb_gfree(new_ref); + } + } + // If we are here, either we lost the CAS race, or the pointer was already + // non-NULL. In either case, we loop to the top and try to increment the + // refcount of the existing object. + +#if UPB_TSAN + // Yield to give other threads a chance to increment the refcount. This is + // especially an issue for TSAN builds, which are prone to locking up from + // the thread with the upb_Atomic_Store call above getting starved. + sched_yield(); +#endif // UPB_TSAN + } +} + +void upb_GeneratedRegistry_Release(const upb_GeneratedRegistryRef* r) { + if (r == NULL) return; + + upb_GeneratedRegistry* registry = _upb_generated_registry(); + + int ref_count = upb_Atomic_Sub(®istry->ref_count, 1, memory_order_acq_rel); + UPB_ASSERT(registry->ref_count >= 0); + + // A ref_count of 1 means that we decremented the refcount to 0. + if (ref_count == 1) { + upb_GeneratedRegistryRef* ref = + upb_Atomic_Exchange(®istry->ref, NULL, memory_order_acq_rel); + if (ref != NULL) { + // This is the last reference and we won any potential race to store NULL, + // so we need to clean up. + upb_Arena_Free(ref->UPB_PRIVATE(arena)); + upb_gfree(ref); + } + } +} + +const upb_ExtensionRegistry* upb_GeneratedRegistry_Get( + const upb_GeneratedRegistryRef* r) { + if (r == NULL) return NULL; + return r->UPB_PRIVATE(registry); +} + + +#include +#include + + +// Must be last. + +const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m, + const upb_MiniTableField* f) { + if (UPB_UNLIKELY(!upb_MiniTableField_IsInOneof(f))) { + return NULL; + } + const upb_MiniTableField* ptr = &m->UPB_PRIVATE(fields)[0]; + const upb_MiniTableField* end = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + for (; ptr < end; ptr++) { + if (ptr->presence == (*f).presence) { + return ptr; + } + } + return NULL; +} + +bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, + const upb_MiniTableField** f) { + const upb_MiniTableField* ptr = *f; + const upb_MiniTableField* end = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + while (++ptr < end) { + if (ptr->presence == (*f)->presence) { + *f = ptr; + return true; + } + } + return false; +} + + +#include + + +// Must be last. + +// A MiniTable for a statically tree shaken message. Messages that use this +// MiniTable are guaranteed to remain unlinked; unlike the empty message, this +// MiniTable is never replaced, which greatly simplifies everything, because the +// type of a sub-message is always known, without consulting a tagged bit. +const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken) = { + .UPB_PRIVATE(fields) = NULL, + .UPB_PRIVATE(size) = sizeof(struct upb_Message), + .UPB_PRIVATE(field_count) = 0, + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, + .UPB_PRIVATE(dense_below) = 0, + .UPB_PRIVATE(table_mask) = -1, + .UPB_PRIVATE(required_count) = 0, +}; + +#include +#include + +// Must be last. + +UPB_NORETURN void _upb_UnreachableFailure(const char* file, int line, + const char* function_name) { + fprintf(stderr, "%s:%d: Reached unreachable statement in function `%s`.\n", + file, line, function_name ? function_name : "(unknown)"); + abort(); +} + + +#include +#include +#include +#include +#include + + +// Must be last. + +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; // full_name -> packed def ptr + upb_strtable files; // file_name -> (upb_FileDef*) + upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + const upb_GeneratedRegistryRef* generated_extreg; + const google_protobuf_FeatureSetDefaults* feature_set_defaults; + upb_MiniTablePlatform platform; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; + bool disable_closed_enum_checking; + bool disable_implicit_field_presence; +}; + +void upb_DefPool_Free(upb_DefPool* s) { + upb_GeneratedRegistry_Release(s->generated_extreg); + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); +} + +static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; + +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; + + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; + s->disable_closed_enum_checking = false; + s->disable_implicit_field_presence = false; + + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; + + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + + s->generated_extreg = upb_GeneratedRegistry_Load(); + if (!s->generated_extreg) goto err; + + s->platform = kUpb_MiniTablePlatform_Native; + + upb_Status status; + if (!upb_DefPool_SetFeatureSetDefaults( + s, serialized_defaults, sizeof(serialized_defaults) - 1, &status)) { + goto err; + } + + if (!s->feature_set_defaults) goto err; + + return s; + +err: + upb_DefPool_Free(s); + return NULL; +} + +void upb_DefPool_DisableClosedEnumChecking(upb_DefPool* s) { + UPB_ASSERT(upb_strtable_count(&s->files) == 0); + s->disable_closed_enum_checking = true; +} + +bool upb_DefPool_ClosedEnumCheckingDisabled(const upb_DefPool* s) { + return s->disable_closed_enum_checking; +} + +void upb_DefPool_DisableImplicitFieldPresence(upb_DefPool* s) { + UPB_ASSERT(upb_strtable_count(&s->files) == 0); + s->disable_implicit_field_presence = true; +} + +bool upb_DefPool_ImplicitFieldPresenceDisabled(const upb_DefPool* s) { + return s->disable_implicit_field_presence; +} + +const google_protobuf_FeatureSetDefaults* upb_DefPool_FeatureSetDefaults( + const upb_DefPool* s) { + return s->feature_set_defaults; +} + +bool upb_DefPool_SetFeatureSetDefaults(upb_DefPool* s, + const char* serialized_defaults, + size_t serialized_len, + upb_Status* status) { + const google_protobuf_FeatureSetDefaults* defaults = google_protobuf_FeatureSetDefaults_parse( + serialized_defaults, serialized_len, s->arena); + if (!defaults) { + upb_Status_SetErrorFormat(status, "Failed to parse defaults"); + return false; + } + if (upb_strtable_count(&s->files) > 0) { + upb_Status_SetErrorFormat(status, + "Feature set defaults can't be changed once the " + "pool has started building"); + return false; + } + int min_edition = google_protobuf_FeatureSetDefaults_minimum_edition(defaults); + int max_edition = google_protobuf_FeatureSetDefaults_maximum_edition(defaults); + if (min_edition > max_edition) { + upb_Status_SetErrorFormat(status, "Invalid edition range %s to %s", + upb_FileDef_EditionName(min_edition), + upb_FileDef_EditionName(max_edition)); + return false; + } + size_t size; + const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* + default_list = google_protobuf_FeatureSetDefaults_defaults(defaults, &size); + int prev_edition = google_protobuf_EDITION_UNKNOWN; + for (size_t i = 0; i < size; ++i) { + int edition = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition( + default_list[i]); + if (edition == google_protobuf_EDITION_UNKNOWN) { + upb_Status_SetErrorFormat(status, "Invalid edition UNKNOWN specified"); + return false; + } + if (edition <= prev_edition) { + upb_Status_SetErrorFormat(status, + "Feature set defaults are not strictly " + "increasing, %s is greater than or equal to %s", + upb_FileDef_EditionName(prev_edition), + upb_FileDef_EditionName(edition)); + return false; + } + prev_edition = edition; + } + + // Copy the defaults into the pool. + s->feature_set_defaults = defaults; + return true; +} + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + const upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); +} + +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; + } + return true; +} + +static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) + ? _upb_DefType_Unpack(v, type) + : NULL; +} + +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); +} + +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; +} + +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; +} + +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; +} + +void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform) { + assert(upb_strtable_count(&s->files) == 0); + s->platform = platform; +} + +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindMessageByNameWithSize(s, sym, strlen(sym)); +} + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); +} + +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindEnumByNameWithSize(s, sym, strlen(sym)); +} + +const upb_EnumDef* upb_DefPool_FindEnumByNameWithSize(const upb_DefPool* s, + const char* sym, + size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUM); +} + +const upb_EnumValueDef* upb_DefPool_FindEnumValueByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindEnumValueByNameWithSize(s, sym, strlen(sym)); +} + +const upb_EnumValueDef* upb_DefPool_FindEnumValueByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUMVAL); +} + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + if (_upb_MessageDef_InMessageSet(m)) { + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i); + if (upb_FieldDef_MessageSubDef(ext) == m) { + return ext; + } + } + } + return NULL; + } + default: + break; + } + + return NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); +} + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); +} + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO: non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } + + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } + + return NULL; +} + +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } + + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} + +static const upb_FileDef* upb_DefBuilder_AddFileToPool( + upb_DefBuilder* const builder, upb_DefPool* const s, + const google_protobuf_FileDescriptorProto* const file_proto, + const upb_StringView name, upb_Status* const status) { + if (UPB_SETJMP(builder->err) != 0) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (builder->file) { + remove_filedef(s, builder->file); + builder->file = NULL; + } + } else if (!builder->arena || !builder->tmp_arena || + !upb_strtable_init(&builder->feature_cache, 16, + builder->tmp_arena) || + !(builder->legacy_features = + google_protobuf_FeatureSet_new(builder->tmp_arena))) { + _upb_DefBuilder_OomErr(builder); + } else { + _upb_FileDef_Create(builder, file_proto); + bool ok = + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(builder->file), builder->arena); + UPB_ASSERT(ok); + UPB_ASSERT(upb_Status_IsOk(status)); + ok = upb_Arena_Fuse(s->arena, builder->arena); + UPB_ASSERT(ok); + } + + if (builder->arena) upb_Arena_Free(builder->arena); + if (builder->tmp_arena) upb_Arena_Free(builder->tmp_arena); + return builder->file; +} + +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTableFile* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } + + upb_DefBuilder ctx = { + .symtab = s, + .tmp_buf = NULL, + .tmp_buf_size = 0, + .layout = layout, + .platform = s->platform, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; + + return upb_DefBuilder_AddFileToPool(&ctx, s, file_proto, name, status); +} + +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); +} + +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; + + upb_Status_Clear(&status); + + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; + } + + arena = upb_Arena_New(); + + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } + + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } + + const upb_MiniTableFile* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; + } + + upb_Arena_Free(arena); + return true; + +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; +} + +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); + return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} + +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; + } + const upb_FieldDef** exts = upb_gmalloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; + } + *count = n; + return exts; +} + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} + +const upb_ExtensionRegistry* _upb_DefPool_GeneratedExtensionRegistry( + const upb_DefPool* s) { + return upb_GeneratedRegistry_Get(s->generated_extreg); +} + + +// Must be last. + +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; +} + + +// Must be last. + +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; + + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } + + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; + } + + return true; +} + + +#include +#include +#include + + +// Must be last. + +struct upb_EnumDef { + UPB_ALIGN_AS(8) const google_protobuf_EnumOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_MiniTableEnum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + const upb_EnumReservedRange* res_ranges; + const upb_StringView* res_names; + int value_count; + int res_range_count; + int res_name_count; + int32_t defaultval; + google_protobuf_SymbolVisibility visibility; + bool is_sorted; // Whether all of the values are defined in ascending order. +}; + +// We store both regular proto enum names and custom JSON enum names in the +// same strtable (ntoi). This is safe because protoc enforces that custom JSON +// enum names never conflict with default enum names across different enum +// values (or are identical, in which case we leave the entry untagged). Because +// upb_EnumValueDef pointers are arena-aligned to at least 4 bytes (bit 0 is +// always 0 for untagged pointers), we set bit 0 to tag custom JSON-only names +// so that regular name lookups can ignore them. +static const uintptr_t kUpb_EnumDef_JsonOnlyTag = 1ULL; + +static upb_value _upb_EnumDef_TagJsonOnly(upb_value v) { + v.val |= kUpb_EnumDef_JsonOnlyTag; + return v; +} + +static bool _upb_EnumDef_IsJsonOnly(upb_value v) { + return (v.val & kUpb_EnumDef_JsonOnlyTag) != 0; +} + +static const upb_EnumValueDef* _upb_EnumDef_Untag(upb_value v) { + return (const upb_EnumValueDef*)(v.val & ~kUpb_EnumDef_JsonOnlyTag); +} + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; +} + +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} + +void _upb_EnumDef_Insert(upb_DefBuilder* ctx, upb_EnumDef* e, + upb_EnumValueDef* v) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + // Aliased enum values can share the same custom JSON name, first one wins. + const char* json_name = upb_EnumValueDef_JsonName(v); + size_t json_len = strlen(json_name); + if (strcmp(json_name, name) != 0) { + upb_value existing_value; + if (upb_strtable_lookup2(&e->ntoi, json_name, json_len, &existing_value)) { + const upb_EnumValueDef* enumval = _upb_EnumDef_Untag(existing_value); + if (upb_EnumValueDef_Number(enumval) != upb_EnumValueDef_Number(v)) { + // If the custom JSON name exists, but points to a value with a + // different number, then this is a parse/conflict error. + _upb_DefBuilder_Errf(ctx, + "duplicate custom json_name (%s) in enum (%s)", + json_name, upb_EnumDef_FullName(e)); + } + } else { + upb_value json_val = _upb_EnumDef_TagJsonOnly(val); + if (!upb_strtable_insert(&e->ntoi, json_name, json_len, json_val, + ctx->arena)) { + _upb_DefBuilder_OomErr(ctx); + } + } + } + + // Multiple enum values can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + if (!upb_inttable_insert(&e->iton, number, val, ctx->arena)) { + _upb_DefBuilder_OomErr(ctx); + } + } +} + +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; +} + +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e) { + return e->resolved_features; +} + +google_protobuf_SymbolVisibility upb_EnumDef_Visibility(const upb_EnumDef* e) { + return e->visibility; +} + +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} + +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} + +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} + +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; +} + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i) { + UPB_ASSERT(0 <= i && i < e->res_range_count); + return _upb_EnumReservedRange_At(e->res_ranges, i); +} + +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->res_name_count); + return e->res_names[i]; +} + +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindByJsonNameWithSize(const upb_EnumDef* e, + const char* name, + size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&e->ntoi, name, size, &v)) { + return NULL; + } + return _upb_EnumDef_Untag(v); +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&e->ntoi, name, size, &v)) { + return NULL; + } + if (_upb_EnumDef_IsJsonOnly(v)) { + return NULL; + } + return upb_value_getconstptr(v); +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; +} + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { + // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect + // this to be faster (especially for small numbers). + return upb_MiniTableEnum_CheckValue(e->layout, num); +} + +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->value_count); + return _upb_EnumValueDef_At(e->values, i); +} + +static bool upb_EnumDef_IsSpecifiedAsClosed(const upb_EnumDef* e) { + return google_protobuf_FeatureSet_enum_type(e->resolved_features) == + google_protobuf_FeatureSet_CLOSED; +} + +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (_upb_FileDef_ClosedEnumCheckingDisabled(e->file)) return false; + return upb_EnumDef_IsSpecifiedAsClosed(e); +} + +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); + + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; + + for (int i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); + + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); + + upb_Status status; + upb_MiniTableEnum* layout = + upb_MiniTableEnum_Build(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} + +static upb_StringView* _upb_EnumReservedNames_New( + upb_DefBuilder* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_StringView, n); + for (int i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + const google_protobuf_FeatureSet* parent_features, + upb_EnumDef* e) { + const google_protobuf_EnumValueDescriptorProto* const* values; + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* res_ranges; + const upb_StringView* res_names; + upb_StringView name; + size_t n_value, n_res_range, n_res_name; + + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + e->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_EnumOptions_features(e->opts)); + + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n_value); + + if (n_value == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } + + e->defaultval = google_protobuf_EnumValueDescriptorProto_number(values[0]); + + // When the special UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN is enabled, we have to + // exempt closed enums from this check, even when we are treating them as + // open. + // + // We rely on the fact that the proto compiler will have already ensured that + // implicit presence fields do not use closed enums, even if we are treating + // them as open. + if (!upb_EnumDef_IsSpecifiedAsClosed(e) && e->defaultval != 0) { + _upb_DefBuilder_Errf(ctx, + "for open enums, the first value must be zero (%s)", + upb_EnumDef_FullName(e)); + } + + bool ok = upb_strtable_init(&e->ntoi, n_value * 2, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + e->value_count = n_value; + e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, + e->resolved_features, e, &e->is_sorted); + + res_ranges = + google_protobuf_EnumDescriptorProto_reserved_range(enum_proto, &n_res_range); + e->res_range_count = n_res_range; + e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); + + res_names = google_protobuf_EnumDescriptorProto_reserved_name(enum_proto, &n_res_name); + e->res_name_count = n_res_name; + e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); + + e->visibility = google_protobuf_EnumDescriptorProto_visibility(enum_proto); + if (upb_EnumDef_IsClosed(e)) { + if (ctx->layout) { + e->layout = upb_MiniTableFile_Enum(ctx->layout, ctx->enum_count++); + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } +} + +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); + + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); + + upb_EnumDef* e = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumDef, n); + for (int i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], parent_features, &e[i]); + e[i].containing_type = containing_type; + } + return e; +} + + +#include + + +// Must be last. + +struct upb_EnumReservedRange { + int32_t start; + int32_t end; +}; + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; +} + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; +} +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; +} + +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumReservedRange, n); + + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); + const int32_t end = + google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + + // Note: Not a typo! Unlike extension ranges and message reserved ranges, + // the end value of an enum reserved range is *inclusive*! + if (end < start) { + _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + +#include +#include +#include + + +// Must be last. + +struct upb_EnumValueDef { + UPB_ALIGN_AS(8) const google_protobuf_EnumValueOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_EnumDef* parent; + const char* full_name; + const char* json_name; + int32_t number; +}; + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; +} + +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); +} + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + size_t n, upb_Arena* a) { + if (SIZE_MAX / sizeof(void*) < n) return NULL; + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; + + for (size_t i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); + + return (const upb_EnumValueDef**)out; +} + +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; +} + +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_EnumValueDef_ResolvedFeatures( + const upb_EnumValueDef* e) { + return e->resolved_features; +} + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; +} + +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; +} + +const char* upb_EnumValueDef_JsonName(const upb_EnumValueDef* v) { + return v->json_name ? v->json_name : upb_EnumValueDef_Name(v); +} + +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); +} + +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } + +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); +} + +static const char* _upb_EnumValueDef_ExtractJsonName( + upb_DefBuilder* ctx, const upb_EnumValueDef* v) { + if (!upb_EnumValueDef_HasOptions(v)) return NULL; + const google_protobuf_EnumValueOptions* opts = (const google_protobuf_EnumValueOptions*)v->opts; + if (!pb_enumvalue_has_json(opts)) return NULL; + const pb_enumvalue_JsonEnumValueOptions* json_opts = pb_enumvalue_json(opts); + if (!json_opts || !pb_enumvalue_JsonEnumValueOptions_has_string(json_opts)) { + return NULL; + } + upb_StringView str = pb_enumvalue_JsonEnumValueOptions_string(json_opts); + return upb_strdup2(str.data, str.size, ctx->arena); +} + +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + const google_protobuf_FeatureSet* parent_features, + upb_EnumDef* e, upb_EnumValueDef* v) { + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + v->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_EnumValueOptions_features(v->opts)); + + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); + + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + v->json_name = _upb_EnumValueDef_ExtractJsonName(ctx, v); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); + + _upb_EnumDef_Insert(ctx, e, v); +} + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_EnumDef* e, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); + + upb_EnumValueDef* v = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumValueDef, n); + + *is_sorted = true; + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); + + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; + } + + return v; +} + + +#include + + +// Must be last. + +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + int32_t start; + int32_t end; +}; + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} + +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} + +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } + +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const google_protobuf_FeatureSet* parent_features, const upb_MessageDef* m) { + upb_ExtensionRange* r = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_ExtensionRange, n); + + for (int i = 0; i < n; i++) { + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_ExtensionRangeOptions_features(r[i].opts)); + + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + +#include +#include +#include +#include +#include +#include + + +// Must be last. + +#define UPB_FIELD_TYPE_UNSPECIFIED 0 + +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; + +struct upb_FieldDef { + UPB_ALIGN_AS(8) const google_protobuf_FieldOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + void* msg; // Always NULL. + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const google_protobuf_FieldDescriptorProto* unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; // Index into msgdef->layout->fields or file->exts + bool has_default; + bool has_json_name; + bool has_presence; + bool is_extension; + bool is_proto3_optional; + upb_FieldType type_; + upb_Label label_; +}; + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; +} + +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; +} + +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f) { + return f->resolved_features; +} + +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; +} + +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + return upb_FieldType_CType(f->type_); +} + +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } + +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } + +uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { + return f->layout_index; +} + +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { return f->is_extension; } + +bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsPrimitive(f); +} + +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { + return _upb_FieldDef_IsPackable(f) && + google_protobuf_FeatureSet_repeated_field_encoding(f->resolved_features) == + google_protobuf_FeatureSet_PACKED; +} + +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); +} + +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; +} + +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name; +} + +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; +} + +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension ? f->scope.extension_scope : NULL; +} + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension ? NULL : f->scope.oneof; +} + +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; +} + +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + upb_MessageValue ret; + + if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) { + return (upb_MessageValue){.msg_val = NULL}; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } + + return ret; +} + +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) ? f->sub.msgdef : NULL; +} + +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsEnum(f) ? f->sub.enumdef : NULL; +} + +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_FileDef* file = upb_FieldDef_File(f); + return (upb_MiniTableField*)_upb_FileDef_ExtensionMiniTable( + file, f->layout_index); + } else { + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->UPB_PRIVATE(fields)[f->layout_index]; + } +} + +const upb_MiniTableExtension* upb_FieldDef_MiniTableExtension( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); +} + +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (f->type_ != kUpb_FieldType_Enum) return false; + return upb_EnumDef_IsClosed(f->sub.enumdef); +} + +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->is_proto3_optional; +} + +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } + +bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { + if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; + return google_protobuf_FeatureSet_utf8_validation(f->resolved_features) == + google_protobuf_FeatureSet_VERIFY; +} + +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) { + // Groups are always tag-delimited. + if (f->type_ != kUpb_FieldType_Group) { + return false; + } + + const upb_MessageDef* msg = upb_FieldDef_MessageSubDef(f); + + // Group fields always are always the lowercase type name. + const char* mname = upb_MessageDef_Name(msg); + const char* fname = upb_FieldDef_Name(f); + size_t name_size = strlen(fname); + if (name_size != strlen(mname)) return false; + for (size_t i = 0; i < name_size; ++i) { + if ((mname[i] | 0x20) != fname[i]) { + // Case-insensitive ascii comparison. + return false; + } + } + + if (upb_MessageDef_File(msg) != upb_FieldDef_File(f)) { + return false; + } + + // Group messages are always defined in the same scope as the field. File + // level extensions will compare NULL == NULL here, which is why the file + // comparison above is necessary to ensure both come from the same file. + return upb_FieldDef_IsExtension(f) ? upb_FieldDef_ExtensionScope(f) == + upb_MessageDef_ContainingType(msg) + : upb_FieldDef_ContainingType(f) == + upb_MessageDef_ContainingType(msg); +} + +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; + + if (upb_FieldDef_IsRepeated(f)) { + out |= kUpb_FieldModifier_IsRepeated; + } else if (upb_FieldDef_IsRequired(f)) { + out |= kUpb_FieldModifier_IsRequired; + } else if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + + if (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; + } + + if (_upb_FieldDef_ValidateUtf8(f)) { + out |= kUpb_FieldModifier_ValidateUtf8; + } + + return out; +} + +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { return f->has_presence; } + +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsEnum(f); +} + +bool upb_FieldDef_IsEnum(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum; +} + +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +} + +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; +} + +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); +} + +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +} + +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return google_protobuf_FeatureSet_field_presence(f->resolved_features) == + google_protobuf_FeatureSet_LEGACY_REQUIRED; +} + +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; +} + +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; +} + +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} + +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} + +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; +} + +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; + + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } + } + *des++ = '\0'; + return out; +} + +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; +} + +static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; + + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } + } + + ret->len = dst - &ret->str[0]; + return ret; +} + +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + // Standard C number parsing functions expect null-terminated strings. + if (len >= sizeof(nullz) - 1) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = upb_EnumValueDef_Number(ev); + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } + + return; + +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); +} + +static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f, + bool must_be_empty) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: { + f->defaultval.sint = upb_EnumDef_Default(f->sub.enumdef); + if (must_be_empty && f->defaultval.sint != 0) { + _upb_DefBuilder_Errf(ctx, + "Implicit presence field (%s) cannot use an enum " + "type with a non-zero default (%s)", + f->full_name, + upb_EnumDef_FullName(f->sub.enumdef)); + } + break; + } + case kUpb_CType_Message: + break; + } +} + +static bool _upb_FieldDef_InferLegacyFeatures( + upb_DefBuilder* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* proto, + const google_protobuf_FieldOptions* options, google_protobuf_Edition edition, + google_protobuf_FeatureSet* features) { + bool ret = false; + + if (google_protobuf_FieldDescriptorProto_label(proto) == kUpb_Label_Required) { + if (edition == google_protobuf_EDITION_PROTO3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + int val = google_protobuf_FeatureSet_LEGACY_REQUIRED; + google_protobuf_FeatureSet_set_field_presence(features, val); + ret = true; + } + + if (google_protobuf_FieldDescriptorProto_type(proto) == kUpb_FieldType_Group) { + int val = google_protobuf_FeatureSet_DELIMITED; + google_protobuf_FeatureSet_set_message_encoding(features, val); + ret = true; + } + + if (google_protobuf_FieldOptions_has_packed(options)) { + int val = google_protobuf_FieldOptions_packed(options) ? google_protobuf_FeatureSet_PACKED + : google_protobuf_FeatureSet_EXPANDED; + google_protobuf_FeatureSet_set_repeated_field_encoding(features, val); + ret = true; + } + + return ret; +} + +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FeatureSet* parent_features, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); + + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->is_proto3_optional = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; + + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + google_protobuf_Edition edition = upb_FileDef_Edition(f->file); + const google_protobuf_FeatureSet* unresolved_features = + google_protobuf_FieldOptions_features(f->opts); + bool implicit = false; + + if (_upb_DefBuilder_IsLegacyEdition(edition)) { + upb_Message_Clear(UPB_UPCAST(ctx->legacy_features), + UPB_DESC_MINITABLE(FeatureSet)); + if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, edition, + ctx->legacy_features)) { + implicit = true; + unresolved_features = ctx->legacy_features; + } + } + + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + int oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } + + if (oneof_index < 0 || oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } + + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; + parent_features = upb_OneofDef_ResolvedFeatures(oneof); + + _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); + } + + f->resolved_features = _upb_DefBuilder_DoResolveFeatures( + ctx, parent_features, unresolved_features, implicit); + + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + if (f->label_ == kUpb_Label_Optional && + // TODO: remove once we can deprecate kUpb_Label_Required. + google_protobuf_FeatureSet_field_presence(f->resolved_features) == + google_protobuf_FeatureSet_LEGACY_REQUIRED) { + f->label_ = kUpb_Label_Required; + } + + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + + f->has_json_name = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); + if (f->has_json_name) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); + + const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + const bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } + + if ((!has_type && has_type_name) || f->type_ == kUpb_FieldType_Message) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll assign this in resolve_subdef() + } else { + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } + } + + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } + + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; + + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } + } + + f->has_presence = + (!upb_FieldDef_IsRepeated(f)) && + (f->is_extension || _upb_FileDef_ImplicitFieldPresenceDisabled(f->file) || + (f->type_ == kUpb_FieldType_Message || + f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || + google_protobuf_FeatureSet_field_presence(f->resolved_features) != + google_protobuf_FeatureSet_IMPLICIT)); +} + +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FeatureSet* parent_features, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + f->is_extension = true; + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); + + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } + + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; + + if (ctx->layout) { + UPB_ASSERT(upb_MiniTableExtension_Number( + upb_FieldDef_MiniTableExtension(f)) == f->number_); + } +} + +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FeatureSet* parent_features, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + f->is_extension = false; + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); + + if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (f->is_proto3_optional) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); + } + } + + _upb_MessageDef_InsertField(ctx, m, f); +} + +upb_FieldDef* _upb_Extensions_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, const char* prefix, + upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_FieldDef, n); + + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; + + _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); + f->index_ = i; + } + + return defs; +} + +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, const char* prefix, + upb_MessageDef* m, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_FieldDef, n); + + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; + + _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) { + // Speculate that the def fields are sorted. We will always sort the + // MiniTable fields, so if defs are sorted then indices will match. + // + // If this is incorrect, we will overwrite later. + f->layout_index = i; + } + + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + + return defs; +} + +static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; + // TODO: remove once we can deprecate + // kUpb_FieldType_Group. + if (google_protobuf_FeatureSet_message_encoding(f->resolved_features) == + google_protobuf_FeatureSet_DELIMITED && + !upb_MessageDef_IsMapEntry(def) && + !(f->msgdef && upb_MessageDef_IsMapEntry(f->msgdef))) { + f->type_ = kUpb_FieldType_Group; + } + f->has_presence = !upb_FieldDef_IsRepeated(f); + break; + default: + _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } + break; + } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; + } +} + +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); +} + +// _upb_FieldDefs_Sorted() is mostly a pure function of its inputs, but has one +// critical side effect that we depend on: it sets layout_index appropriately +// for non-sorted lists of fields. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; + + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; + } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); + + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; + } + return (const upb_FieldDef**)out; +} + +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension); + + upb_DescState s; + _upb_DescState_Init(&s); + + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, + modifiers); + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } + + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; + + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); + } +} + +void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, + const upb_FieldDef* f) { + const upb_MiniTableExtension* ext = upb_FieldDef_MiniTableExtension(f); + + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == upb_MiniTableExtension_Number(ext)); + } else { + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } + + upb_MiniTableExtension* mut_ext = (upb_MiniTableExtension*)ext; + upb_MiniTableSub sub = {NULL}; + if (upb_FieldDef_IsSubMessage(f)) { + const upb_MiniTable* submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + sub = upb_MiniTableSub_FromMessage(submsg); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + const upb_MiniTableEnum* subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); + sub = upb_MiniTableSub_FromEnum(subenum); + } + bool ok2 = _upb_MiniTableExtension_Init(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(f->msgdef), + sub, ctx->platform, ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); + } + + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Implicit presence fields should always have an effective default of 0. + // This should naturally fall out of the validations that protoc performs: + // - Implicit presence fields cannot specify a default value. + // - Implicit presence fields for for enums can only use open enums, which + // are required to have zero as their default. + // - Even if we are treating all enums as open, the proto compiler will + // still reject using a nominally closed enum with an implicit presence + // field. + bool must_be_empty = !f->has_presence && !upb_FieldDef_IsRepeated(f); + + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); + + if (must_be_empty) { + _upb_DefBuilder_Errf(ctx, + "fields with implicit presence cannot have " + "explicit defaults (%s)", + f->full_name); + } + + if (upb_FileDef_Edition(f->file) == google_protobuf_EDITION_PROTO3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } + + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f, must_be_empty); + f->has_default = false; + } +} + +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); + + if (f->is_extension) { + resolve_extension(ctx, prefix, f, field_proto); + } +} + + +#include +#include +#include + + +// Must be last. + +struct upb_FileDef { + const google_protobuf_FileOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const char* name; + const char* package; + google_protobuf_Edition edition; + + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTableExtension** ext_layouts; + const upb_DefPool* symtab; + + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; // All exts in the file. +}; + +UPB_API const char* upb_FileDef_EditionName(int edition) { + // TODO Synchronize this with descriptor.proto better. + switch (edition) { + case google_protobuf_EDITION_PROTO2: + return "PROTO2"; + case google_protobuf_EDITION_PROTO3: + return "PROTO3"; + case google_protobuf_EDITION_2023: + return "2023"; + default: + return "UNKNOWN"; + } +} + +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; +} + +const google_protobuf_FeatureSet* upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { + return f->resolved_features; +} + +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} + +google_protobuf_Edition upb_FileDef_Edition(const upb_FileDef* f) { return f->edition; } + +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } + +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; +} + +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} + +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} + +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; +} + +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; +} + +bool _upb_FileDef_ClosedEnumCheckingDisabled(const upb_FileDef* f) { + return upb_DefPool_ClosedEnumCheckingDisabled(f->symtab); +} + +bool _upb_FileDef_ImplicitFieldPresenceDisabled(const upb_FileDef* f) { + return upb_DefPool_ImplicitFieldPresenceDisabled(f->symtab); +} + +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; +} + +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; +} + +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; +} + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; +} + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->weak_dep_count); + return f->deps[f->weak_deps[i]]; +} + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); +} + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); +} + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); +} + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); +} + +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } + +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; +} + +// Note: Import cycles are not allowed so this will terminate. +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* path) { + if (!strcmp(f->name, path)) return true; + + for (int i = 0; i < upb_FileDef_PublicDependencyCount(f); i++) { + const upb_FileDef* dep = upb_FileDef_PublicDependency(f, i); + if (upb_FileDef_Resolves(dep, path)) return true; + } + return false; +} + +static char* _strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; +} + +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; + + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } + + return ext_count; +} + +const google_protobuf_FeatureSet* _upb_FileDef_FindEdition(upb_DefBuilder* ctx, + int edition) { + const google_protobuf_FeatureSetDefaults* defaults = + upb_DefPool_FeatureSetDefaults(ctx->symtab); + + int min = google_protobuf_FeatureSetDefaults_minimum_edition(defaults); + int max = google_protobuf_FeatureSetDefaults_maximum_edition(defaults); + if (edition < min) { + _upb_DefBuilder_Errf(ctx, + "Edition %s is earlier than the minimum edition %s " + "given in the defaults", + upb_FileDef_EditionName(edition), + upb_FileDef_EditionName(min)); + return NULL; + } + if (edition > max && edition != google_protobuf_EDITION_UNSTABLE) { + _upb_DefBuilder_Errf(ctx, + "Edition %s is later than the maximum edition %s " + "given in the defaults", + upb_FileDef_EditionName(edition), + upb_FileDef_EditionName(max)); + return NULL; + } + + size_t n; + const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* d = + google_protobuf_FeatureSetDefaults_defaults(defaults, &n); + const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* result = NULL; + for (size_t i = 0; i < n; i++) { + if (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition(d[i]) > + edition) { + break; + } + result = d[i]; + } + if (result == NULL) { + _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", + upb_FileDef_EditionName(edition)); + return NULL; + } + + // Merge the fixed and overridable features to get the edition's default + // feature set. + const google_protobuf_FeatureSet* fixed = + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(result); + const google_protobuf_FeatureSet* overridable = + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features( + result); + if (!fixed && !overridable) { + _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", + upb_FileDef_EditionName(edition)); + return NULL; + } else if (!fixed) { + return overridable; + } + return _upb_DefBuilder_DoResolveFeatures(ctx, fixed, overridable, + /*is_implicit=*/true); +} + +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; + + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t n; + + file->symtab = ctx->symtab; + + // Count all extensions in the file, to build a flat array of layouts. + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + // We are using the ext layouts that were passed in. + file->ext_layouts = ctx->layout->UPB_PRIVATE(exts); + const int mt_ext_count = upb_MiniTableFile_ExtensionCount(ctx->layout); + if (mt_ext_count != file->ext_count) { + _upb_DefBuilder_Errf(ctx, + "Extension count did not match layout (%d vs %d)", + mt_ext_count, file->ext_count); + } + } else { + // We are building ext layouts from scratch. + file->ext_layouts = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTableExtension* ext = + UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MiniTableExtension, file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; + } + } + + upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + file->name = _strviewdup(ctx, name); + if (strlen(file->name) != name.size) { + _upb_DefBuilder_Errf(ctx, "File name contained embedded NULL"); + } + + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = _strviewdup(ctx, package); + } else { + file->package = NULL; + } + + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); + + if (google_protobuf_FileDescriptorProto_has_edition(file_proto)) { + if (!streql_view(syntax, "editions")) { + _upb_DefBuilder_Errf(ctx, + "Setting edition requires that syntax=\"editions\", " + "but syntax is \"" UPB_STRINGVIEW_FORMAT "\"", + UPB_STRINGVIEW_ARGS(syntax)); + } + file->edition = google_protobuf_FileDescriptorProto_edition(file_proto); + } else if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + if (streql_view(syntax, "proto2")) { + file->edition = google_protobuf_EDITION_PROTO2; + } else if (streql_view(syntax, "proto3")) { + file->edition = google_protobuf_EDITION_PROTO3; + } else if (streql_view(syntax, "editions")) { + _upb_DefBuilder_Errf( + ctx, "File has syntax=\"editions\", but no edition is specified"); + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + // The legacy default when no edition or syntax is specified is proto2. + file->edition = google_protobuf_EDITION_PROTO2; + } + + // Read options. + UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + + // Resolve features. + const google_protobuf_FeatureSet* edition_defaults = + _upb_FileDef_FindEdition(ctx, file->edition); + const google_protobuf_FeatureSet* unresolved = google_protobuf_FileOptions_features(file->opts); + file->resolved_features = + _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); + + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, const upb_FileDef*, n); + + for (size_t i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } + + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, int32_t, n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] < 0 || public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } + + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, const int32_t, n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] < 0 || weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); + } + mutable_weak_deps[i] = weak_deps[i]; + } + + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = + _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); + + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = _upb_Extensions_New( + ctx, n, exts, file->resolved_features, file->package, NULL); + + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = + _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); + + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = + _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); + + // Now that all names are in the table, build layouts and resolve refs. + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); + } + + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_CreateMiniTable(ctx, (upb_MessageDef*)m); + } + + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_BuildMiniTableExtension(ctx, f); + } + + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); + } + + if (file->ext_count) { + upb_ExtensionRegistryStatus status = upb_ExtensionRegistry_AddArray( + _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); + if (status != kUpb_ExtensionRegistryStatus_Ok) { + if (status == kUpb_ExtensionRegistryStatus_OutOfMemory) { + _upb_DefBuilder_OomErr(ctx); + } + + UPB_ASSERT(status == kUpb_ExtensionRegistryStatus_DuplicateEntry); + _upb_DefBuilder_Errf(ctx, "duplicate extension entry"); + } + } +} + + +#include +#include +#include +#include + + +// Must be last. + +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static UPB_ALIGN_AS(8) const + char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; + +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } + +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); +} + +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} + +// Verify a relative identifier string. The loop is branchless for speed. +static void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0); + + good &= is_alpha | is_numer; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); +} + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; + } +} + +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; + + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } + } + + *len = 0; + return true; +} + +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + // Symbols starting with '.' are absolute, so we do a single lookup. + // Slice to omit the leading '.' + if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + // Remove components from base until we find an entry or run out. + size_t baselen = base ? strlen(base) : 0; + char* tmp = upb_gmalloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + upb_gfree(tmp); + goto notfound; + } + } + upb_gfree(tmp); + } + + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); + +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); +} + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_Errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + } + return ret; +} + +// Per ASCII this will lower-case a letter. If the result is a letter, the +// input was definitely a letter. If the output is not a letter, this may +// have transformed the character unpredictably. +static char upb_ascii_lower(char ch) { return ch | 0x20; } + +// isalpha() etc. from are locale-dependent, which we don't want. +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return low <= c && c <= high; +} + +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} + +static int TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; +} + +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + int hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_Errf( + ctx, "\\x must be followed by at least one hex digit (field='%s')", + upb_FieldDef_FullName(f)); + return 0; + } + unsigned int ret = hex_digit; + while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} + +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} + +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} + +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + + // We should never reach this point. + UPB_ASSERT(false); +} + +upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, + const google_protobuf_FeatureSet* parent, + upb_StringView key) { + size_t need = key.size + sizeof(void*); + if (ctx->tmp_buf_size < need) { + ctx->tmp_buf_size = UPB_MAX(64, upb_RoundUpToPowerOfTwo(need)); + ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); + if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); + } + + memcpy(ctx->tmp_buf, &parent, sizeof(void*)); + memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); + return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); +} + +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const google_protobuf_FeatureSet* parent, + upb_StringView key, + google_protobuf_FeatureSet** set) { + upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); + upb_value v; + if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { + *set = upb_value_getptr(v); + return false; + } + + *set = (google_protobuf_FeatureSet*)upb_Message_DeepClone( + UPB_UPCAST(parent), UPB_DESC_MINITABLE(FeatureSet), ctx->arena); + if (!*set) _upb_DefBuilder_OomErr(ctx); + + v = upb_value_ptr(*set); + if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, + ctx->tmp_arena)) { + _upb_DefBuilder_OomErr(ctx); + } + + return true; +} + +const google_protobuf_FeatureSet* _upb_DefBuilder_DoResolveFeatures( + upb_DefBuilder* ctx, const google_protobuf_FeatureSet* parent, + const google_protobuf_FeatureSet* child, bool is_implicit) { + assert(parent); + if (!child) return parent; + + if (!is_implicit && + _upb_DefBuilder_IsLegacyEdition(upb_FileDef_Edition(ctx->file))) { + _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); + } + + google_protobuf_FeatureSet* resolved; + size_t child_size; + const char* child_bytes = + google_protobuf_FeatureSet_serialize(child, ctx->tmp_arena, &child_size); + if (!child_bytes) _upb_DefBuilder_OomErr(ctx); + + upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); + if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { + return resolved; + } + + upb_DecodeStatus dec_status = + upb_Decode(child_bytes, child_size, UPB_UPCAST(resolved), + UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); + if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); + + return resolved; +} + + +#include + + +// Must be last. + +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; + + // Prevent overflow errors. + if (len == SIZE_MAX) return NULL; + + // Always null-terminate, even if binary data; but don't rely on the input to + // have a null-terminating byte since it may be a raw binary buffer. + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + if (len != 0) memcpy(p, s, len); + p[len] = 0; + } + return p; +} + + +#include +#include + + +// Must be last. + +bool upb_Message_HasFieldByDef(const upb_Message* msg, const upb_FieldDef* f) { + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + UPB_ASSERT(upb_FieldDef_HasPresence(f)); + + if (upb_MiniTableField_IsExtension(m_f)) { + return upb_Message_HasExtension(msg, (const upb_MiniTableExtension*)m_f); + } else { + return upb_Message_HasBaseField(msg, m_f); + } +} + +const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_HasFieldByDef(msg, f) ? f : NULL; + } else { + const upb_MiniTableField* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = upb_Message_WhichOneofFieldNumber(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; + } +} + +upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg, + const upb_FieldDef* f) { + upb_MessageValue default_val = upb_FieldDef_Default(f); + return upb_Message_GetField(msg, upb_FieldDef_MiniTable(f), default_val); +} + +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f)) { + // We need to skip the upb_Message_GetFieldByDef() call in this case. + goto make; + } + + upb_MessageValue val = upb_Message_GetFieldByDef(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } + + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); + } else if (upb_FieldDef_IsRepeated(f)) { + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); + } else { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); + } + + val.array_val = ret.array; + if (!upb_Message_SetFieldByDef(msg, f, val, a)) { + ret.array = NULL; + } + + return ret; +} + +bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + + if (upb_MiniTableField_IsExtension(m_f)) { + return upb_Message_SetExtension(msg, (const upb_MiniTableExtension*)m_f, + &val, a); + } else { + upb_Message_SetBaseField(msg, m_f, &val); + return true; + } +} + +void upb_Message_ClearFieldByDef(upb_Message* msg, const upb_FieldDef* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); + + if (upb_MiniTableField_IsExtension(m_f)) { + upb_Message_ClearExtension(msg, (const upb_MiniTableExtension*)m_f); + } else { + upb_Message_ClearBaseField(msg, m_f); + } +} + +void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +} + +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + size_t i = *iter; + size_t n = upb_MiniTable_FieldCount(mt); + upb_MessageValue zero = upb_MessageValue_Zero(); + UPB_UNUSED(ext_pool); + + // Iterate over normal fields, returning the first one that is set. + while (++i < n) { + const upb_MiniTableField* field = upb_MiniTable_GetFieldByIndex(mt, i); + upb_MessageValue val = upb_Message_GetField(msg, field, zero); + + // Skip field if unset or empty. + if (upb_MiniTableField_HasPresence(field)) { + if (!upb_Message_HasBaseField(msg, field)) continue; + } else { + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { + case kUpb_FieldMode_Map: + if (!val.map_val || upb_Map_Size(val.map_val) == 0) continue; + break; + case kUpb_FieldMode_Array: + if (!val.array_val || upb_Array_Size(val.array_val) == 0) continue; + break; + case kUpb_FieldMode_Scalar: + if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(field, &val)) + continue; + break; + } + } + + *out_val = val; + *out_f = + upb_MessageDef_FindFieldByNumber(m, upb_MiniTableField_Number(field)); + *iter = i; + return true; + } + + if (ext_pool) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return false; + + for (; (i - n) < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i - n]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + const upb_Extension* ext = + upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; + } + } + } + + *iter = i; + return false; +} + +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int depth) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; + + if (--depth == 0) return false; + + _upb_Message_DiscardUnknown_shallow(msg); + + while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; + + if (!val_m) continue; + + upb_MessageValue map_key, map_val; + while (upb_Map_Next(map, &map_key, &map_val, &iter)) { + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + ext_pool, depth)) { + ret = false; + } + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + ext_pool, depth)) { + ret = false; + } + } + } else { + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + ext_pool, depth)) { + ret = false; + } + } + } + + return ret; +} + +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, ext_pool, maxdepth); +} + + +#include +#include +#include + + +// Must be last. + +struct upb_MessageDef { + UPB_ALIGN_AS(8) const google_protobuf_MessageOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; + + // Tables for looking up fields by number and name. + upb_inttable itof; + upb_strtable ntof; + + // Looking up fields by json name. + upb_strtable jtof; + + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_StringView* res_names; + const upb_MessageDef* nested_msgs; + const upb_MessageReservedRange* res_ranges; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + + // TODO: These counters don't need anywhere near 32 bits. + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int res_range_count; + int res_name_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + bool is_sorted; + upb_WellKnown well_known_type; + google_protobuf_SymbolVisibility visibility; +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = m->full_name; + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; + } +} + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { + return true; + } + } + return false; +} + +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { + return m->opts; +} + +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_MessageDef_ResolvedFeatures( + const upb_MessageDef* m) { + return m->resolved_features; +} + +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; +} + +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; +} + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} + +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} + +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} + +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ +} + +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + + if (upb_strtable_lookup2(&m->jtof, name, size, &val)) { + return upb_value_getconstptr(val); + } + + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} + +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} + +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; +} + +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; +} + +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} + +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} + +int upb_MessageDef_RealOneofCount(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; +} + +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; +} + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); +} + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_range_count); + return _upb_MessageReservedRange_At(m->res_ranges, i); +} + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_name_count); + return m->res_names[i]; +} + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, i); +} + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); +} + +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); +} + +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); +} + +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} + +UPB_API google_protobuf_SymbolVisibility +upb_MessageDef_Visibility(const upb_MessageDef* m) { + return m->visibility; +} + +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); +} + +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); +} + +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(m->opts); +} + +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format(m->opts); +} + +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + upb_StringView desc; + // Note: this will assign layout_index for fields, so upb_FieldDef_MiniTable() + // is safe to call only after this call. + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, ctx->platform, ctx->arena, scratch_data, + scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + + return ret; +} + +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, f); + } + + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; + } + } + + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } +} + +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); + + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); + } + + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); + + upb_value v = upb_value_constptr(f); + + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + } + + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + bool skip_json_conflicts = + google_protobuf_MessageOptions_deprecated_legacy_json_field_conflicts( + upb_MessageDef_Options(m)); + if (!skip_json_conflicts && strcmp(shortname, json_name) != 0 && + google_protobuf_FeatureSet_json_format(m->resolved_features) == + google_protobuf_FeatureSet_ALLOW && + upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf( + ctx, "duplicate json_name for (%s) with original field name (%s)", + shortname, json_name); + } + + if (upb_strtable_lookup(&m->jtof, json_name, &v)) { + if (!skip_json_conflicts) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + } + } else { + const size_t json_size = strlen(json_name); + ok = upb_strtable_insert(&m->jtof, json_name, json_size, + upb_value_constptr(f), ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } + + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); + } + + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m) { + if (ctx->layout == NULL) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + } else { + m->layout = upb_MiniTableFile_Message(ctx->layout, ctx->msg_count++); + UPB_ASSERT(m->field_count == upb_MiniTable_FieldCount(m->layout)); + + // We don't need the result of this call, but it will assign layout_index + // for all the fields in O(n lg n) time. + _upb_FieldDefs_Sorted(m->fields, m->field_count, ctx->tmp_arena); + } + + for (int i = 0; i < m->nested_msg_count; i++) { + upb_MessageDef* nested = + (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_CreateMiniTable(ctx, nested); + } +} + +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_BuildMiniTableExtension(ctx, ext); + } + + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); + } + + if (ctx->layout || ctx->platform != kUpb_MiniTablePlatform_Native) return; + + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTableField* mt_f = + (upb_MiniTableField*)&m->layout->UPB_PRIVATE(fields)[layout_index]; + if (sub_m) { + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + if (UPB_UNLIKELY(!upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout))) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); + } + } else if (_upb_FieldDef_IsClosedEnum(f)) { + const upb_MiniTableEnum* mt_e = _upb_EnumDef_MiniTable(sub_e); + if (UPB_UNLIKELY(!upb_MiniTable_SetSubEnum(mt, mt_f, mt_e))) { + _upb_DefBuilder_Errf(ctx, "invalid subenum for (%s)", m->full_name); + } + } + } + +#ifndef NDEBUG + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + UPB_ASSERT(layout_index < upb_MiniTable_FieldCount(m->layout)); + const upb_MiniTableField* mt_f = + &m->layout->UPB_PRIVATE(fields)[layout_index]; + UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + UPB_ASSERT(upb_FieldDef_CType(f) == upb_MiniTableField_CType(mt_f)); + UPB_ASSERT(upb_FieldDef_HasPresence(f) == + upb_MiniTableField_HasPresence(mt_f)); + } +#endif +} + +// Returns whether packable repeated fields in the message should be considered +// packed by default. This is used only for the purpose of encoding +// MiniDescriptors, so we just return true if there are more packed fields than +// unpacked. This optimizes for smaller MiniDescriptors. +static bool _upb_MessageDef_DefaultIsPacked(const upb_MessageDef* m) { + int packed = 0; + int unpacked = 0; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + if (_upb_FieldDef_IsPackable(f)) { + if (upb_FieldDef_IsPacked(f)) { + ++packed; + } else { + ++unpacked; + } + } + } + return packed > unpacked; +} + +static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { + bool has_string = false; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + // Old binaries do not recognize the field-level "FlipValidateUtf8" wire + // modifier, so we do not actually have field-level control for old + // binaries. Given this, we judge that the better failure mode is to be + // more lax than intended, rather than more strict. To achieve this, we + // only mark the message with the ValidateUtf8 modifier if *all* fields + // validate UTF-8. + if (!_upb_FieldDef_ValidateUtf8(f)) return false; + if (upb_FieldDef_Type(f) == kUpb_FieldType_String) has_string = true; + } + return has_string; +} + +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + + if (_upb_MessageDef_DefaultIsPacked(m)) { + out |= kUpb_MessageModifier_DefaultIsPacked; + } + + if (_upb_MessageDef_ValidateUtf8(m)) { + out |= kUpb_MessageModifier_ValidateUtf8; + } + + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + + return out; +} + +static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, + upb_Arena* a) { + if (m->field_count != 2) return false; + + const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); + const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); + if (key_field == NULL || val_field == NULL) return false; + + UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); + + s->ptr = upb_MtDataEncoder_EncodeMap( + &s->e, s->ptr, upb_FieldDef_Type(key_field), upb_FieldDef_Type(val_field), + _upb_FieldDef_Modifiers(key_field), _upb_FieldDef_Modifiers(val_field)); + return true; +} + +static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; + } + + s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, + _upb_MessageDef_Modifiers(m)); + + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); + } + + for (int i = 0; i < m->real_oneof_count; i++) { + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); + + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); + } + } + + return true; +} + +static bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); + + return true; +} + +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + if (!_upb_DescState_Grow(&s, a)) return false; + + if (upb_MessageDef_IsMapEntry(m)) { + if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; + } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; + } else { + if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return false; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; + + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; +} + +static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_StringView, n); + for (int i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + +static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const google_protobuf_FeatureSet* parent_features, + const upb_MessageDef* containing_type, + upb_MessageDef* m) { + const google_protobuf_OneofDescriptorProto* const* oneofs; + const google_protobuf_FieldDescriptorProto* const* fields; + const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; + const google_protobuf_DescriptorProto_ReservedRange* const* res_ranges; + const upb_StringView* res_names; + size_t n_oneof, n_field, n_enum, n_ext, n_msg; + size_t n_ext_range, n_res_range, n_res_name; + upb_StringView name; + + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_MessageOptions_features(m->opts)); + + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); + + m->containing_type = containing_type; + m->is_sorted = true; + + name = google_protobuf_DescriptorProto_name(msg_proto); + + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + res_ranges = google_protobuf_DescriptorProto_reserved_range(msg_proto, &n_res_range); + res_names = google_protobuf_DescriptorProto_reserved_name(msg_proto, &n_res_name); + + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); + + m->field_count = n_field; + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, + m->full_name, m, &m->is_sorted); + + // Message Sets may not contain fields. + if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { + if (UPB_UNLIKELY(n_field > 0)) { + _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + } + } + + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, + m->resolved_features, m); + + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); + + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); + + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; + + assign_msg_wellknowntype(m); + + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = + _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); + + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, + m->full_name, m); + + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = + _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); + + m->visibility = google_protobuf_DescriptorProto_visibility(msg_proto); +} + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); + + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); + + upb_MessageDef* m = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MessageDef, n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], parent_features, containing_type, + &m[i]); + } + return m; +} + +#include + + +// Must be last. + +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; +} + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; +} +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; +} + +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MessageReservedRange, n); + + for (int i = 0; i < n; i++) { + const int32_t start = google_protobuf_DescriptorProto_ReservedRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + + + +// Must be last. + +struct upb_MethodDef { + const google_protobuf_MethodOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} + +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; +} + +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; +} + +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_MethodDef_ResolvedFeatures( + const upb_MethodDef* m) { + return m->resolved_features; +} + +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; +} + +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); +} + +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} + +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} + +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} + +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; +} + +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + const google_protobuf_FeatureSet* parent_features, + upb_ServiceDef* s, upb_MethodDef* m) { + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_MethodOptions_features(m->opts)); + + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + _upb_ServiceDef_InsertMethod(ctx, s, m); +} + +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_ServiceDef* s) { + upb_MethodDef* m = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MethodDef, n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], parent_features, s, &m[i]); + m[i].index = i; + } + return m; +} + + +#include +#include +#include + + +// Must be last. + +struct upb_OneofDef { + UPB_ALIGN_AS(8) const google_protobuf_OneofOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +}; + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} + +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} + +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o) { + return o->resolved_features; +} + +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} + +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} + +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } + +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} + +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } + +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); +} + +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; +} + +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +} + +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} + +void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, + const upb_FieldDef* f, const char* name, + size_t size) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; + + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + + // TODO: This lookup is unfortunate because we also perform it when + // inserting into the message's table. Unfortunately that step occurs after + // this one and moving things around could be tricky so let's leave it for + // a future refactoring. + const bool number_exists = upb_inttable_lookup(&o->itof, number, NULL); + if (UPB_UNLIKELY(number_exists)) { + _upb_DefBuilder_Errf(ctx, "oneof fields have the same number (%d)", number); + } + + // TODO: More redundant work happening here. + const bool name_exists = upb_strtable_lookup2(&o->ntof, name, size, NULL); + if (UPB_UNLIKELY(name_exists)) { + _upb_DefBuilder_Errf(ctx, "oneof fields have the same name (%.*s)", + (int)size, name); + } + + const bool ok = upb_inttable_insert(&o->itof, number, v, ctx->arena) && + upb_strtable_insert(&o->ntof, name, size, v, ctx->arena); + if (UPB_UNLIKELY(!ok)) { + _upb_DefBuilder_OomErr(ctx); + } +} + +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; + + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); + } + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + UPB_DEFBUILDER_ALLOCARRAY(ctx, const upb_FieldDef*, o->field_count); + o->field_count = 0; + } + + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } + + return synthetic_count; +} + +static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const google_protobuf_FeatureSet* parent_features, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + o->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_OneofOptions_features(o->opts)); + + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); + + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; + + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); + } + + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + + upb_OneofDef* o = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_OneofDef, n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); + } + return o; +} + + +#include +#include + + +// Must be last. + +struct upb_ServiceDef { + UPB_ALIGN_AS(8) const google_protobuf_ServiceOptions* opts; + const google_protobuf_FeatureSet* resolved_features; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; + upb_strtable ntom; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; +} + +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; +} + +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; +} + +const google_protobuf_FeatureSet* upb_ServiceDef_ResolvedFeatures( + const upb_ServiceDef* s) { + return s->resolved_features; +} + +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; +} + +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); +} + +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} + +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; +} + +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + return upb_ServiceDef_FindMethodByNameWithSize(s, name, strlen(name)); +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByNameWithSize( + const upb_ServiceDef* s, const char* name, size_t len) { + upb_value val; + + if (!upb_strtable_lookup2(&s->ntom, name, len, &val)) { + return NULL; + } + + return _upb_DefType_Unpack(val, UPB_DEFTYPE_METHOD); +} + +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + const google_protobuf_FeatureSet* parent_features, + upb_ServiceDef* s) { + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); + s->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, google_protobuf_ServiceOptions_features(s->opts)); + + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + upb_StringView name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + size_t n; + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + bool ok = upb_strtable_init(&s->ntom, n, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); +} + +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_ServiceDef, n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], parent_features, &s[i]); + s[i].index = i; + } + return s; +} + +void _upb_ServiceDef_InsertMethod(upb_DefBuilder* ctx, upb_ServiceDef* s, + const upb_MethodDef* m) { + const char* shortname = upb_MethodDef_Name(m); + const size_t shortnamelen = strlen(shortname); + upb_value existing_v; + if (upb_strtable_lookup(&s->ntom, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate method name (%s)", shortname); + } + const upb_value method_v = _upb_DefType_Pack(m, UPB_DEFTYPE_METHOD); + bool ok = upb_strtable_insert(&s->ntom, shortname, shortnamelen, method_v, + ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} + + +#include +#include +#include +#include +#include +#include +#include + + +// Must be last. + +typedef struct { + upb_Arena* arena; + jmp_buf err; +} upb_ToProto_Context; + +#define CHK_OOM(val) \ + if (!(val)) UPB_LONGJMP(ctx->err, 1); + +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define SET_OPTIONS(proto, desc_type, options_type, src, extreg) \ + { \ + size_t size; \ + /* MEM: could use a temporary arena here instead. */ \ + char* pb = google_protobuf_##options_type##_serialize(src, ctx->arena, &size); \ + CHK_OOM(pb); \ + google_protobuf_##options_type* dst = \ + google_protobuf_##options_type##_parse_ex(pb, size, extreg, 0, ctx->arena); \ + CHK_OOM(dst); \ + google_protobuf_##desc_type##_set_options(proto, dst); \ + } + +static upb_StringView strviewdup2(upb_ToProto_Context* ctx, + upb_StringView str) { + char* p = upb_Arena_Malloc(ctx->arena, str.size); + CHK_OOM(p); + memcpy(p, str.data, str.size); + return (upb_StringView){.data = p, .size = str.size}; +} + +static upb_StringView strviewdup(upb_ToProto_Context* ctx, const char* s) { + return strviewdup2(ctx, (upb_StringView){.data = s, .size = strlen(s)}); +} + +static upb_StringView qual_dup(upb_ToProto_Context* ctx, const char* s) { + size_t n = strlen(s); + char* p = upb_Arena_Malloc(ctx->arena, n + 1); + CHK_OOM(p); + p[0] = '.'; + memcpy(p + 1, s, n); + return (upb_StringView){.data = p, .size = n + 1}; +} + +UPB_PRINTF(2, 3) +static upb_StringView printf_dup(upb_ToProto_Context* ctx, const char* fmt, + ...) { + const size_t max = 32; + char* p = upb_Arena_Malloc(ctx->arena, max); + CHK_OOM(p); + va_list args; + va_start(args, fmt); + size_t n = _upb_vsnprintf(p, max, fmt, args); + va_end(args); + UPB_ASSERT(n < max); + return (upb_StringView){.data = p, .size = n}; +} + +static bool upb_isprint(char ch) { return ch >= 0x20 && ch <= 0x7f; } + +static int special_escape(char ch) { + switch (ch) { + // This is the same set of special escapes recognized by + // absl::CEscape(). + case '\n': + return 'n'; + case '\r': + return 'r'; + case '\t': + return 't'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '"': + return '"'; + default: + return -1; + } +} + +static upb_StringView default_bytes(upb_ToProto_Context* ctx, + upb_StringView val) { + size_t n = 0; + for (size_t i = 0; i < val.size; i++) { + char ch = val.data[i]; + if (special_escape(ch) >= 0) + n += 2; // '\C' + else if (upb_isprint(ch)) + n += 1; + else + n += 4; // '\123' + } + char* p = upb_Arena_Malloc(ctx->arena, n); + CHK_OOM(p); + char* dst = p; + const char* src = val.data; + const char* end = src + val.size; + while (src < end) { + unsigned char ch = *src++; + if (special_escape(ch) >= 0) { + *dst++ = '\\'; + *dst++ = (char)special_escape(ch); + } else if (upb_isprint(ch)) { + *dst++ = ch; + } else { + *dst++ = '\\'; + *dst++ = '0' + (ch >> 6); + *dst++ = '0' + ((ch >> 3) & 0x7); + *dst++ = '0' + (ch & 0x7); + } + } + return (upb_StringView){.data = p, .size = n}; +} + +static upb_StringView default_string(upb_ToProto_Context* ctx, + const upb_FieldDef* f) { + upb_MessageValue d = upb_FieldDef_Default(f); + upb_CType type = upb_FieldDef_CType(f); + + if (type == kUpb_CType_Float || type == kUpb_CType_Double) { + double val = type == kUpb_CType_Float ? d.float_val : d.double_val; + if (val == INFINITY) { + return strviewdup(ctx, "inf"); + } else if (val == -INFINITY) { + return strviewdup(ctx, "-inf"); + } else if (val != val) { + return strviewdup(ctx, "nan"); + } + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return strviewdup(ctx, d.bool_val ? "true" : "false"); + case kUpb_CType_Enum: { + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNumber(e, d.int32_val); + return strviewdup(ctx, upb_EnumValueDef_Name(ev)); + } + case kUpb_CType_Int64: + return printf_dup(ctx, "%" PRId64, d.int64_val); + case kUpb_CType_UInt64: + return printf_dup(ctx, "%" PRIu64, d.uint64_val); + case kUpb_CType_Int32: + return printf_dup(ctx, "%" PRId32, d.int32_val); + case kUpb_CType_UInt32: + return printf_dup(ctx, "%" PRIu32, d.uint32_val); + case kUpb_CType_Float: + return printf_dup(ctx, "%.9g", d.float_val); + case kUpb_CType_Double: + return printf_dup(ctx, "%.17g", d.double_val); + case kUpb_CType_String: + return strviewdup2(ctx, d.str_val); + case kUpb_CType_Bytes: + return default_bytes(ctx, d.str_val); + default: + UPB_UNREACHABLE(); + } +} + +static google_protobuf_DescriptorProto_ReservedRange* resrange_toproto( + upb_ToProto_Context* ctx, const upb_MessageReservedRange* r) { + google_protobuf_DescriptorProto_ReservedRange* proto = + google_protobuf_DescriptorProto_ReservedRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_ReservedRange_set_start( + proto, upb_MessageReservedRange_Start(r)); + google_protobuf_DescriptorProto_ReservedRange_set_end(proto, + upb_MessageReservedRange_End(r)); + + return proto; +} + +static google_protobuf_EnumDescriptorProto_EnumReservedRange* enumresrange_toproto( + upb_ToProto_Context* ctx, const upb_EnumReservedRange* r) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* proto = + google_protobuf_EnumDescriptorProto_EnumReservedRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start( + proto, upb_EnumReservedRange_Start(r)); + google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end( + proto, upb_EnumReservedRange_End(r)); + + return proto; +} + +static google_protobuf_FieldDescriptorProto* fielddef_toproto(upb_ToProto_Context* ctx, + const upb_FieldDef* f) { + google_protobuf_FieldDescriptorProto* proto = + google_protobuf_FieldDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_FieldDescriptorProto_set_name(proto, + strviewdup(ctx, upb_FieldDef_Name(f))); + google_protobuf_FieldDescriptorProto_set_number(proto, upb_FieldDef_Number(f)); + + if (upb_FieldDef_IsRequired(f) && + upb_FileDef_Edition(upb_FieldDef_File(f)) >= google_protobuf_EDITION_2023) { + google_protobuf_FieldDescriptorProto_set_label( + proto, google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL); + } else { + google_protobuf_FieldDescriptorProto_set_label(proto, upb_FieldDef_Label(f)); + } + if (upb_FieldDef_Type(f) == kUpb_FieldType_Group && + upb_FileDef_Edition(upb_FieldDef_File(f)) >= google_protobuf_EDITION_2023) { + google_protobuf_FieldDescriptorProto_set_type(proto, kUpb_FieldType_Message); + } else { + google_protobuf_FieldDescriptorProto_set_type(proto, upb_FieldDef_Type(f)); + } + + if (upb_FieldDef_HasJsonName(f)) { + google_protobuf_FieldDescriptorProto_set_json_name( + proto, strviewdup(ctx, upb_FieldDef_JsonName(f))); + } + + if (upb_FieldDef_IsSubMessage(f)) { + google_protobuf_FieldDescriptorProto_set_type_name( + proto, + qual_dup(ctx, upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(f)))); + } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum) { + google_protobuf_FieldDescriptorProto_set_type_name( + proto, qual_dup(ctx, upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)))); + } + + if (upb_FieldDef_IsExtension(f)) { + google_protobuf_FieldDescriptorProto_set_extendee( + proto, + qual_dup(ctx, upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)))); + } + + if (upb_FieldDef_HasDefault(f)) { + google_protobuf_FieldDescriptorProto_set_default_value(proto, + default_string(ctx, f)); + } + + const upb_OneofDef* o = upb_FieldDef_ContainingOneof(f); + if (o) { + google_protobuf_FieldDescriptorProto_set_oneof_index(proto, upb_OneofDef_Index(o)); + } + + if (_upb_FieldDef_IsProto3Optional(f)) { + google_protobuf_FieldDescriptorProto_set_proto3_optional(proto, true); + } + + if (upb_FieldDef_HasOptions(f)) { + SET_OPTIONS(proto, FieldDescriptorProto, FieldOptions, + upb_FieldDef_Options(f), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_FieldDef_File(f)))); + } + + return proto; +} + +static google_protobuf_OneofDescriptorProto* oneofdef_toproto(upb_ToProto_Context* ctx, + const upb_OneofDef* o) { + google_protobuf_OneofDescriptorProto* proto = + google_protobuf_OneofDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_OneofDescriptorProto_set_name(proto, + strviewdup(ctx, upb_OneofDef_Name(o))); + + if (upb_OneofDef_HasOptions(o)) { + SET_OPTIONS(proto, OneofDescriptorProto, OneofOptions, + upb_OneofDef_Options(o), + _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool( + upb_MessageDef_File(upb_OneofDef_ContainingType(o))))); + } + + return proto; +} + +static google_protobuf_EnumValueDescriptorProto* enumvaldef_toproto( + upb_ToProto_Context* ctx, const upb_EnumValueDef* e) { + google_protobuf_EnumValueDescriptorProto* proto = + google_protobuf_EnumValueDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumValueDescriptorProto_set_name( + proto, strviewdup(ctx, upb_EnumValueDef_Name(e))); + google_protobuf_EnumValueDescriptorProto_set_number(proto, upb_EnumValueDef_Number(e)); + + if (upb_EnumValueDef_HasOptions(e)) { + SET_OPTIONS(proto, EnumValueDescriptorProto, EnumValueOptions, + upb_EnumValueDef_Options(e), + _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool( + upb_EnumDef_File(upb_EnumValueDef_Enum(e))))); + } + + return proto; +} + +static google_protobuf_EnumDescriptorProto* enumdef_toproto(upb_ToProto_Context* ctx, + const upb_EnumDef* e) { + google_protobuf_EnumDescriptorProto* proto = + google_protobuf_EnumDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumDescriptorProto_set_name(proto, + strviewdup(ctx, upb_EnumDef_Name(e))); + + int n = upb_EnumDef_ValueCount(e); + google_protobuf_EnumValueDescriptorProto** vals = + google_protobuf_EnumDescriptorProto_resize_value(proto, n, ctx->arena); + CHK_OOM(vals); + for (int i = 0; i < n; i++) { + vals[i] = enumvaldef_toproto(ctx, upb_EnumDef_Value(e, i)); + } + + n = upb_EnumDef_ReservedRangeCount(e); + google_protobuf_EnumDescriptorProto_EnumReservedRange** res_ranges = + google_protobuf_EnumDescriptorProto_resize_reserved_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_ranges[i] = enumresrange_toproto(ctx, upb_EnumDef_ReservedRange(e, i)); + } + + n = upb_EnumDef_ReservedNameCount(e); + upb_StringView* res_names = + google_protobuf_EnumDescriptorProto_resize_reserved_name(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_names[i] = upb_EnumDef_ReservedName(e, i); + } + + if (upb_EnumDef_HasOptions(e)) { + SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions, upb_EnumDef_Options(e), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_EnumDef_File(e)))); + } + + google_protobuf_SymbolVisibility visibility = upb_EnumDef_Visibility(e); + if (visibility != google_protobuf_VISIBILITY_UNSET) { + google_protobuf_EnumDescriptorProto_set_visibility(proto, visibility); + } + + return proto; +} + +static google_protobuf_DescriptorProto_ExtensionRange* extrange_toproto( + upb_ToProto_Context* ctx, const upb_MessageDef* m, + const upb_ExtensionRange* e) { + google_protobuf_DescriptorProto_ExtensionRange* proto = + google_protobuf_DescriptorProto_ExtensionRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_ExtensionRange_set_start(proto, + upb_ExtensionRange_Start(e)); + google_protobuf_DescriptorProto_ExtensionRange_set_end(proto, + upb_ExtensionRange_End(e)); + + if (upb_ExtensionRange_HasOptions(e)) { + SET_OPTIONS(proto, DescriptorProto_ExtensionRange, ExtensionRangeOptions, + upb_ExtensionRange_Options(e), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_MessageDef_File(m)))); + } + + return proto; +} + +static google_protobuf_DescriptorProto* msgdef_toproto(upb_ToProto_Context* ctx, + const upb_MessageDef* m) { + google_protobuf_DescriptorProto* proto = google_protobuf_DescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_set_name(proto, + strviewdup(ctx, upb_MessageDef_Name(m))); + + int n; + + n = upb_MessageDef_FieldCount(m); + google_protobuf_FieldDescriptorProto** fields = + google_protobuf_DescriptorProto_resize_field(proto, n, ctx->arena); + CHK_OOM(fields); + for (int i = 0; i < n; i++) { + fields[i] = fielddef_toproto(ctx, upb_MessageDef_Field(m, i)); + } + + n = upb_MessageDef_OneofCount(m); + google_protobuf_OneofDescriptorProto** oneofs = + google_protobuf_DescriptorProto_resize_oneof_decl(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + oneofs[i] = oneofdef_toproto(ctx, upb_MessageDef_Oneof(m, i)); + } + + n = upb_MessageDef_NestedMessageCount(m); + google_protobuf_DescriptorProto** nested_msgs = + google_protobuf_DescriptorProto_resize_nested_type(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_msgs[i] = msgdef_toproto(ctx, upb_MessageDef_NestedMessage(m, i)); + } + + n = upb_MessageDef_NestedEnumCount(m); + google_protobuf_EnumDescriptorProto** nested_enums = + google_protobuf_DescriptorProto_resize_enum_type(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_enums[i] = enumdef_toproto(ctx, upb_MessageDef_NestedEnum(m, i)); + } + + n = upb_MessageDef_NestedExtensionCount(m); + google_protobuf_FieldDescriptorProto** nested_exts = + google_protobuf_DescriptorProto_resize_extension(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + nested_exts[i] = + fielddef_toproto(ctx, upb_MessageDef_NestedExtension(m, i)); + } + + n = upb_MessageDef_ExtensionRangeCount(m); + google_protobuf_DescriptorProto_ExtensionRange** ext_ranges = + google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + ext_ranges[i] = + extrange_toproto(ctx, m, upb_MessageDef_ExtensionRange(m, i)); + } + + n = upb_MessageDef_ReservedRangeCount(m); + google_protobuf_DescriptorProto_ReservedRange** res_ranges = + google_protobuf_DescriptorProto_resize_reserved_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_ranges[i] = resrange_toproto(ctx, upb_MessageDef_ReservedRange(m, i)); + } + + n = upb_MessageDef_ReservedNameCount(m); + upb_StringView* res_names = + google_protobuf_DescriptorProto_resize_reserved_name(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_names[i] = upb_MessageDef_ReservedName(m, i); + } + + if (upb_MessageDef_HasOptions(m)) { + SET_OPTIONS(proto, DescriptorProto, MessageOptions, + upb_MessageDef_Options(m), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_MessageDef_File(m)))); + } + + google_protobuf_SymbolVisibility visibility = upb_MessageDef_Visibility(m); + if (visibility != google_protobuf_VISIBILITY_UNSET) { + google_protobuf_DescriptorProto_set_visibility(proto, visibility); + } + + return proto; +} + +static google_protobuf_MethodDescriptorProto* methoddef_toproto(upb_ToProto_Context* ctx, + const upb_MethodDef* m) { + google_protobuf_MethodDescriptorProto* proto = + google_protobuf_MethodDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_MethodDescriptorProto_set_name(proto, + strviewdup(ctx, upb_MethodDef_Name(m))); + + google_protobuf_MethodDescriptorProto_set_input_type( + proto, + qual_dup(ctx, upb_MessageDef_FullName(upb_MethodDef_InputType(m)))); + google_protobuf_MethodDescriptorProto_set_output_type( + proto, + qual_dup(ctx, upb_MessageDef_FullName(upb_MethodDef_OutputType(m)))); + + if (upb_MethodDef_ClientStreaming(m)) { + google_protobuf_MethodDescriptorProto_set_client_streaming(proto, true); + } + + if (upb_MethodDef_ServerStreaming(m)) { + google_protobuf_MethodDescriptorProto_set_server_streaming(proto, true); + } + + if (upb_MethodDef_HasOptions(m)) { + SET_OPTIONS( + proto, MethodDescriptorProto, MethodOptions, upb_MethodDef_Options(m), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_ServiceDef_File(upb_MethodDef_Service(m))))); + } + + return proto; +} + +static google_protobuf_ServiceDescriptorProto* servicedef_toproto( + upb_ToProto_Context* ctx, const upb_ServiceDef* s) { + google_protobuf_ServiceDescriptorProto* proto = + google_protobuf_ServiceDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_ServiceDescriptorProto_set_name( + proto, strviewdup(ctx, upb_ServiceDef_Name(s))); + + size_t n = upb_ServiceDef_MethodCount(s); + google_protobuf_MethodDescriptorProto** methods = + google_protobuf_ServiceDescriptorProto_resize_method(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + methods[i] = methoddef_toproto(ctx, upb_ServiceDef_Method(s, i)); + } + + if (upb_ServiceDef_HasOptions(s)) { + SET_OPTIONS(proto, ServiceDescriptorProto, ServiceOptions, + upb_ServiceDef_Options(s), + _upb_DefPool_GeneratedExtensionRegistry( + upb_FileDef_Pool(upb_ServiceDef_File(s)))); + } + + return proto; +} + +static google_protobuf_FileDescriptorProto* filedef_toproto(upb_ToProto_Context* ctx, + const upb_FileDef* f) { + google_protobuf_FileDescriptorProto* proto = + google_protobuf_FileDescriptorProto_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_FileDescriptorProto_set_name(proto, + strviewdup(ctx, upb_FileDef_Name(f))); + + const char* package = upb_FileDef_Package(f); + if (package) { + size_t n = strlen(package); + if (n) { + google_protobuf_FileDescriptorProto_set_package(proto, strviewdup(ctx, package)); + } + } + + google_protobuf_Edition edition = upb_FileDef_Edition(f); + + switch (edition) { + case google_protobuf_EDITION_PROTO2: + // We could set syntax to "proto2", but C++ omits it completely, which is + // equivalent. + break; + case google_protobuf_EDITION_PROTO3: + google_protobuf_FileDescriptorProto_set_syntax(proto, strviewdup(ctx, "proto3")); + break; + default: + google_protobuf_FileDescriptorProto_set_syntax(proto, strviewdup(ctx, "editions")); + google_protobuf_FileDescriptorProto_set_edition(proto, edition); + break; + } + + size_t n; + n = upb_FileDef_DependencyCount(f); + upb_StringView* deps = + google_protobuf_FileDescriptorProto_resize_dependency(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + deps[i] = strviewdup(ctx, upb_FileDef_Name(upb_FileDef_Dependency(f, i))); + } + + n = upb_FileDef_PublicDependencyCount(f); + int32_t* public_deps = + google_protobuf_FileDescriptorProto_resize_public_dependency(proto, n, ctx->arena); + const int32_t* public_dep_nums = _upb_FileDef_PublicDependencyIndexes(f); + if (n) memcpy(public_deps, public_dep_nums, n * sizeof(int32_t)); + + n = upb_FileDef_WeakDependencyCount(f); + int32_t* weak_deps = + google_protobuf_FileDescriptorProto_resize_weak_dependency(proto, n, ctx->arena); + const int32_t* weak_dep_nums = _upb_FileDef_WeakDependencyIndexes(f); + if (n) memcpy(weak_deps, weak_dep_nums, n * sizeof(int32_t)); + + n = upb_FileDef_TopLevelMessageCount(f); + google_protobuf_DescriptorProto** msgs = + google_protobuf_FileDescriptorProto_resize_message_type(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + msgs[i] = msgdef_toproto(ctx, upb_FileDef_TopLevelMessage(f, i)); + } + + n = upb_FileDef_TopLevelEnumCount(f); + google_protobuf_EnumDescriptorProto** enums = + google_protobuf_FileDescriptorProto_resize_enum_type(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + enums[i] = enumdef_toproto(ctx, upb_FileDef_TopLevelEnum(f, i)); + } + + n = upb_FileDef_ServiceCount(f); + google_protobuf_ServiceDescriptorProto** services = + google_protobuf_FileDescriptorProto_resize_service(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + services[i] = servicedef_toproto(ctx, upb_FileDef_Service(f, i)); + } + + n = upb_FileDef_TopLevelExtensionCount(f); + google_protobuf_FieldDescriptorProto** exts = + google_protobuf_FileDescriptorProto_resize_extension(proto, n, ctx->arena); + for (size_t i = 0; i < n; i++) { + exts[i] = fielddef_toproto(ctx, upb_FileDef_TopLevelExtension(f, i)); + } + + if (upb_FileDef_HasOptions(f)) { + SET_OPTIONS(proto, FileDescriptorProto, FileOptions, upb_FileDef_Options(f), + _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool(f))); + } + + return proto; +} + +static google_protobuf_DescriptorProto* upb_ToProto_ConvertMessageDef( + upb_ToProto_Context* const ctx, const upb_MessageDef* const m) { + if (UPB_SETJMP(ctx->err)) return NULL; + return msgdef_toproto(ctx, m); +} + +google_protobuf_DescriptorProto* upb_MessageDef_ToProto(const upb_MessageDef* m, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertMessageDef(&ctx, m); +} + +google_protobuf_EnumDescriptorProto* upb_ToProto_ConvertEnumDef( + upb_ToProto_Context* const ctx, const upb_EnumDef* const e) { + if (UPB_SETJMP(ctx->err)) return NULL; + return enumdef_toproto(ctx, e); +} + +google_protobuf_EnumDescriptorProto* upb_EnumDef_ToProto(const upb_EnumDef* e, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertEnumDef(&ctx, e); +} + +google_protobuf_EnumValueDescriptorProto* upb_ToProto_ConvertEnumValueDef( + upb_ToProto_Context* const ctx, const upb_EnumValueDef* e) { + if (UPB_SETJMP(ctx->err)) return NULL; + return enumvaldef_toproto(ctx, e); +} + +google_protobuf_EnumValueDescriptorProto* upb_EnumValueDef_ToProto( + const upb_EnumValueDef* e, upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertEnumValueDef(&ctx, e); +} + +google_protobuf_FieldDescriptorProto* upb_ToProto_ConvertFieldDef( + upb_ToProto_Context* const ctx, const upb_FieldDef* f) { + if (UPB_SETJMP(ctx->err)) return NULL; + return fielddef_toproto(ctx, f); +} + +google_protobuf_FieldDescriptorProto* upb_FieldDef_ToProto(const upb_FieldDef* f, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertFieldDef(&ctx, f); +} + +google_protobuf_OneofDescriptorProto* upb_ToProto_ConvertOneofDef( + upb_ToProto_Context* const ctx, const upb_OneofDef* o) { + if (UPB_SETJMP(ctx->err)) return NULL; + return oneofdef_toproto(ctx, o); +} + +google_protobuf_OneofDescriptorProto* upb_OneofDef_ToProto(const upb_OneofDef* o, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertOneofDef(&ctx, o); +} + +google_protobuf_FileDescriptorProto* upb_ToProto_ConvertFileDef( + upb_ToProto_Context* const ctx, const upb_FileDef* const f) { + if (UPB_SETJMP(ctx->err)) return NULL; + return filedef_toproto(ctx, f); +} + +google_protobuf_FileDescriptorProto* upb_FileDef_ToProto(const upb_FileDef* f, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertFileDef(&ctx, f); +} + +google_protobuf_MethodDescriptorProto* upb_ToProto_ConvertMethodDef( + upb_ToProto_Context* const ctx, const upb_MethodDef* m) { + if (UPB_SETJMP(ctx->err)) return NULL; + return methoddef_toproto(ctx, m); +} + +google_protobuf_MethodDescriptorProto* upb_MethodDef_ToProto( + const upb_MethodDef* const m, upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertMethodDef(&ctx, m); +} + +google_protobuf_ServiceDescriptorProto* upb_ToProto_ConvertServiceDef( + upb_ToProto_Context* const ctx, const upb_ServiceDef* const s) { + if (UPB_SETJMP(ctx->err)) return NULL; + return servicedef_toproto(ctx, s); +} + +google_protobuf_ServiceDescriptorProto* upb_ServiceDef_ToProto(const upb_ServiceDef* s, + upb_Arena* a) { + upb_ToProto_Context ctx = {a}; + return upb_ToProto_ConvertServiceDef(&ctx, s); +} + + +#include +#include +#include +#include +#include + + +// Our awkward dance for including fasttable only when it is enabled. +#if UPB_FASTTABLE +#define UPB_INCLUDE_FAST_DECODE +#endif + +#ifdef UPB_INCLUDE_FAST_DECODE +#endif + +#undef UPB_INCLUDE_FAST_DECODE + +// Must be last. + +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; + +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; + +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the op. +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ + +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = + arr->UPB_PRIVATE(capacity) - arr->UPB_PRIVATE(size) < elem; + if (need_realloc && !UPB_PRIVATE(_upb_Array_Realloc)( + arr, arr->UPB_PRIVATE(size) + elem, &d->arena)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + return need_realloc; +} + +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; + +// This is identical to _upb_Decoder_DecodeTag() except that the maximum value +// is INT32_MAX instead of UINT32_MAX. +UPB_FORCEINLINE +const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + int sz; + ptr = upb_WireReader_ReadSize(ptr, &sz, EPS(d)); + *size = sz; + return ptr; +} + +UPB_FORCEINLINE upb_AddUnknownMode +_upb_Decoder_GetAddUnknownMode(upb_Decoder* d, const char* data) { + if (d->options & kUpb_DecodeOption_AliasString) { + if (data != d->input.buffer_start) { + // If the data is not from the beginning of the input buffer, then we can + // safely attempt to coalesce this region with the previous one. + return kUpb_AddUnknown_AliasAllowMerge; + } else { + return kUpb_AddUnknown_Alias; + } + } + return kUpb_AddUnknown_Copy; +} + +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; + } +} + +static void _upb_Decoder_Munge(const upb_MiniTableField* field, wireval* val) { + switch (field->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; + } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; + } + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + _upb_Decoder_MungeInt32(val); + break; + case kUpb_FieldType_Enum: + UPB_UNREACHABLE(); + } +} + +static upb_Message* _upb_Decoder_NewSubMessage2(upb_Decoder* d, + const upb_MiniTable* subl, + const upb_MiniTableField* field, + upb_Message** target) { + UPB_ASSERT(subl); + upb_Message* msg = _upb_Message_New(subl, &d->arena); + if (!msg) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + + *target = msg; + return msg; +} + +static upb_Message* _upb_Decoder_NewSubMessage(upb_Decoder* d, + const upb_MiniTableField* field, + upb_Message** target) { + const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); + return _upb_Decoder_NewSubMessage2(d, subl, field, target); +} + +static const char* _upb_Decoder_ReadString2(upb_Decoder* d, const char* ptr, + int size, upb_StringView* str, + bool validate_utf8) { + if (!_upb_Decoder_ReadString(d, &ptr, size, str, validate_utf8)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeSubMessage(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTableField* field, + size_t size) { + ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, size); + const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); + UPB_ASSERT(subl); + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeKnownGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTableField* field) { + const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); + UPB_ASSERT(subl); + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, + field->UPB_PRIVATE(number)); +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeFixedPacked(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTableField* field, + int lg2) { + upb_StringView sv; + ptr = upb_EpsCopyInputStream_ReadStringEphemeral(&d->input, ptr, val->size, + &sv); + if (!ptr) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + int mask = (1 << lg2) - 1; + if (UPB_UNLIKELY((val->size & mask) != 0 || ptr == NULL)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + size_t count = val->size >> lg2; + if (count == 0) return ptr; + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + arr->UPB_PRIVATE(size) += count; + if (upb_IsLittleEndian()) { + memcpy(mem, sv.data, sv.size); + } else { + const char* src = sv.data; + const char* src_end = src + sv.size; + char* dst = mem; + if (lg2 == 2) { + for (; src < src_end; src += 4, dst += 4) { + uint32_t x; + memcpy(&x, src, 4); + x = upb_BigEndian32(x); + memcpy(dst, &x, 4); + } + } else { + UPB_ASSERT(lg2 == 3); + for (; src < src_end; src += 8, dst += 8) { + uint64_t x; + memcpy(&x, src, 8); + x = upb_BigEndian64(x); + memcpy(dst, &x, 8); + } + } + } + + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeVarintPacked(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTableField* field, + int lg2) { + int scale = 1 << lg2; + ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); + char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + wireval elem; + ptr = upb_WireReader_ReadVarint(ptr, &elem.uint64_val, EPS(d)); + _upb_Decoder_Munge(field, &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << lg2, void); + } + arr->UPB_PRIVATE(size)++; + memcpy(out, &elem, scale); + out += scale; + } + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTableField* field, wireval* val) { + const upb_MiniTableEnum* e = upb_MiniTable_GetSubEnumTable(field); + ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); + char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * 4, void); + while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + wireval elem; + ptr = upb_WireReader_ReadVarint(ptr, &elem.uint64_val, EPS(d)); + if (!upb_MiniTableEnum_CheckValue(e, elem.uint64_val)) { + upb_Message* unknown_msg = + field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension + ? d->original_msg + : msg; + if (!_upb_Encoder_AddEnumValueToUnknown(unknown_msg, field, + elem.uint64_val, &d->arena)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + continue; + } + _upb_Decoder_MungeInt32(&elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * 4, void); + } + arr->UPB_PRIVATE(size)++; + memcpy(out, &elem, 4); + out += 4; + } + upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); + return ptr; +} + +static upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTableField* field) { + const upb_FieldType field_type = field->UPB_PRIVATE(descriptortype); + const size_t lg2 = UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type); + upb_Array* ret = UPB_PRIVATE(_upb_Array_New)( + &d->arena, _UPB_ARRAY_DEFAULT_INITIAL_SIZE, lg2); + if (!ret) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + return ret; +} + +#if UPB_FASTTABLE +UPB_PRESERVE_NONE +#endif +static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableField* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); + upb_Array* arr = *arrp; + void* mem; + + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; + } + + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) << op, void); + arr->UPB_PRIVATE(size)++; + memcpy(mem, val, 1 << op); + return ptr; + case kUpb_DecodeOp_String: { + /* Append string. */ + upb_StringView* str = (upb_StringView*)upb_Array_MutableDataPtr(arr) + + arr->UPB_PRIVATE(size); + ptr = _upb_Decoder_ReadString2(d, ptr, val->size, str, + /*validate_utf8=*/true); + arr->UPB_PRIVATE(size)++; + return ptr; + } + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)upb_Array_MutableDataPtr(arr) + + arr->UPB_PRIVATE(size); + ptr = _upb_Decoder_ReadString2(d, ptr, val->size, str, + /*validate_utf8=*/false); + arr->UPB_PRIVATE(size)++; + return ptr; + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_Message** target = + UPB_PTR_AT(upb_Array_MutableDataPtr(arr), + arr->UPB_PRIVATE(size) * sizeof(void*), upb_Message*); + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, field, target); + arr->UPB_PRIVATE(size)++; + if (UPB_UNLIKELY(field->UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, field); + } else { + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, field, val->size); + } + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, field, val); + default: + UPB_UNREACHABLE(); + } +} + +static upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, + const upb_MiniTable* entry) { + // Maps descriptor type -> upb map size + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; + + const upb_MiniTableField* key_field = &entry->UPB_PRIVATE(fields)[0]; + const upb_MiniTableField* val_field = &entry->UPB_PRIVATE(fields)[1]; + char key_size = kSizeInMap[key_field->UPB_PRIVATE(descriptortype)]; + char val_size = kSizeInMap[val_field->UPB_PRIVATE(descriptortype)]; + UPB_ASSERT(key_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, k)); + UPB_ASSERT(val_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, v)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + return ret; +} + +#if UPB_FASTTABLE +UPB_PRESERVE_NONE +#endif +static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableField* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + UPB_ASSERT(upb_MiniTableField_Type(field) == kUpb_FieldType_Message); + const upb_MiniTable* entry = upb_MiniTable_GetSubMessageTable(field); + + UPB_ASSERT(entry); + UPB_ASSERT(entry->UPB_PRIVATE(field_count) == 2); + UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[0])); + UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[1])); + + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; + } + + // Parse map entry. + memset(&ent, 0, sizeof(ent)); + + bool value_is_message = + entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Message || + entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == + kUpb_FieldType_Group; + const upb_MiniTable* sub_table = + value_is_message + ? upb_MiniTable_GetSubMessageTable(&entry->UPB_PRIVATE(fields)[1]) + : NULL; + upb_Message* sub_msg = NULL; + + if (sub_table) { + // Create proactively to handle the case where it doesn't appear. + _upb_Decoder_NewSubMessage(d, &entry->UPB_PRIVATE(fields)[1], &sub_msg); + ent.v.val = upb_value_ptr(sub_msg); + } + + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.message, field, val->size); + + if (sub_msg && sub_table->UPB_PRIVATE(required_count)) { + // If the map entry did not contain a value on the wire, `sub_msg` is an + // empty message; we must check if it is missing any required fields. If the + // value was present, this check is redundant but harmless. + _upb_Decoder_CheckRequired(d, ptr, sub_msg, sub_table); + } + + if (upb_Message_HasUnknown(&ent.message)) { + if (!_upb_Encoder_AddMapEntryUnknown(msg, field, &ent.message, entry, + &d->arena)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == kUpb_MapInsertStatus_OutOfMemory) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; +} + +#if UPB_FASTTABLE +UPB_PRESERVE_NONE +#endif +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableField* field, wireval* val, int op) { + void* mem = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); + int type = field->UPB_PRIVATE(descriptortype); + + // Set presence if necessary. + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(field)) { + UPB_PRIVATE(_upb_Message_SetHasbit)(msg, field); + } else if (upb_MiniTableField_IsInOneof(field)) { + // Oneof case + uint32_t* oneof_case = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, field); + if (op == kUpb_DecodeOp_SubMessage && + *oneof_case != field->UPB_PRIVATE(number)) { + memset(mem, 0, sizeof(void*)); + } + *oneof_case = field->UPB_PRIVATE(number); + } + + // Store into message. + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) submsg = _upb_Decoder_NewSubMessage(d, field, submsgp); + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, field, val->size); + } + break; + } + case kUpb_DecodeOp_String: + return _upb_Decoder_ReadString2(d, ptr, val->size, mem, + /*validate_utf8=*/true); + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString2(d, ptr, val->size, mem, + /*validate_utf8=*/false); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); + } + + return ptr; +} + +enum { + kStartItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((kUpb_MsgSet_TypeId << 3) | kUpb_WireType_Varint), + kMessageTag = ((kUpb_MsgSet_Message << 3) | kUpb_WireType_Delimited), +}; + +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTableExtension* item_mt, + const char* data, uint32_t size) { + upb_Extension* ext = + UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message** submsgp = (upb_Message**)&ext->data.msg_val; + upb_Message* submsg = _upb_Decoder_NewSubMessage2( + d, ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg), + &ext->ext->UPB_PRIVATE(field), submsgp); + // upb_Decode_LimitDepth() takes uint32_t, d->depth - 1 can not be negative. + if (d->depth <= 1) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_MaxDepthExceeded); + } + upb_DecodeStatus status = upb_Decode( + data, size, submsg, upb_MiniTableExtension_GetSubMessage(item_mt), + d->extreg, upb_Decode_LimitDepth(d->options, d->depth - 1), &d->arena); + if (status != kUpb_DecodeStatus_Ok) { + upb_ErrorHandler_ThrowError(d->err, status); + } +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[6 * kUpb_Encoder_EncodeVarint32MaxSize]; + char* ptr = buf; + ptr = upb_Encoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Encoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Encoder_EncodeVarint32(type_id, ptr); + ptr = upb_Encoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Encoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Encoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + upb_StringView unknown[] = { + {buf, split - buf}, + {message_data, message_size}, + {split, end - split}, + }; + if (!UPB_PRIVATE(_upb_Message_AddUnknownV)(msg, &d->arena, unknown, 3)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* t, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTableExtension* item_mt = + upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} + +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = upb_WireReader_ReadVarint(ptr, &tmp, EPS(d)); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + upb_StringView sv; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + ptr = upb_EpsCopyInputStream_ReadStringAlwaysAlias(&d->input, ptr, size, + &sv); + if (!ptr) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, sv.data, + sv.size); + } else { + // Out of order, we must preserve the payload. + preserved = sv; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = _upb_WireReader_SkipValue(ptr, tag, d->depth, &d->input); + break; + } + } + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); +} + +static upb_MiniTableField upb_Decoder_FieldNotFoundField = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + +UPB_NOINLINE const upb_MiniTableField* _upb_Decoder_FindExtensionField( + upb_Decoder* d, const upb_MiniTable* t, uint32_t field_number, int ext_mode, + uint32_t wire_type) { + // Treat a message set as an extendable message if it is a delimited field. + // This provides compatibility with encoders that are unaware of message + // sets and serialize them as normal extensions. + if (ext_mode == kUpb_ExtMode_Extendable || + (ext_mode == kUpb_ExtMode_IsMessageSet && + wire_type == kUpb_WireType_Delimited)) { + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); + if (ext) return &ext->UPB_PRIVATE(field); + } else if (ext_mode == kUpb_ExtMode_IsMessageSet) { + if (field_number == kUpb_MsgSet_Item) { + static upb_MiniTableField item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } + } + return &upb_Decoder_FieldNotFoundField; +} + +static const upb_MiniTableField* _upb_Decoder_FindField(upb_Decoder* d, + const upb_MiniTable* t, + uint32_t field_number, + uint32_t wire_type) { + UPB_ASSERT(t); + const upb_MiniTableField* field = + upb_MiniTable_FindFieldByNumber(t, field_number); + if (field) return field; + + if (d->extreg && UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(t)) { + return _upb_Decoder_FindExtensionField( + d, t, field_number, UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(t), + wire_type); + } + + return &upb_Decoder_FieldNotFoundField; // Unknown field. +} + +static int _upb_Decoder_GetVarintOp(const upb_MiniTableField* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; + + return kVarintOps[field->UPB_PRIVATE(descriptortype)]; +} + +UPB_FORCEINLINE +void _upb_Decoder_CheckUnlinked(upb_Decoder* d, const upb_MiniTable* mt, + const upb_MiniTableField* field, int* op) { + // If sub-message is not linked, treat as unknown. + if (field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension) return; + const upb_MiniTable* mt_sub = upb_MiniTable_GetSubMessageTable(field); + if (mt_sub != NULL) return; // Normal case, sub-message is linked. + _upb_Decoder_VerifyOneofUnlinked(mt, field); + *op = kUpb_DecodeOp_UnknownField; +} + +UPB_FORCEINLINE +void _upb_Decoder_MaybeVerifyUtf8(upb_Decoder* d, + const upb_MiniTableField* field, int* op) { + UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bytes); + if (_upb_Decoder_FieldRequiresUtf8Validation(d, field)) { + *op = kUpb_DecodeOp_String; + } +} + +static int _upb_Decoder_GetDelimitedOp(upb_Decoder* d, const upb_MiniTable* mt, + const upb_MiniTableField* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + // For non-repeated field type. + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_SubMessage, + // For repeated field type. + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; + + int ndx = field->UPB_PRIVATE(descriptortype); + if (upb_MiniTableField_IsArray(field)) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; + + if (op == kUpb_DecodeOp_SubMessage) { + _upb_Decoder_CheckUnlinked(d, mt, field, &op); + } else if (op == kUpb_DecodeOp_Bytes) { + _upb_Decoder_MaybeVerifyUtf8(d, field, &op); + } + + return op; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr, + const upb_MiniTable* mt, + const upb_MiniTableField* field, + uint32_t wire_type, wireval* val, + int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); + + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = upb_WireReader_ReadVarint(ptr, &val->uint64_val, EPS(d)); + if (upb_MiniTableField_IsClosedEnum(field)) { + const upb_MiniTableEnum* e = upb_MiniTable_GetSubEnumTable(field); + if (!upb_MiniTableEnum_CheckValue(e, val->uint64_val)) { + *op = kUpb_DecodeOp_UnknownField; + return ptr; + } + _upb_Decoder_MungeInt32(val); + } else { + _upb_Decoder_Munge(field, val); + } + *op = _upb_Decoder_GetVarintOp(field); + return ptr; + case kUpb_WireType_32Bit: + *op = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return upb_WireReader_ReadFixed32(ptr, &val->uint32_val, &d->input); + case kUpb_WireType_64Bit: + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return upb_WireReader_ReadFixed64(ptr, &val->uint64_val, &d->input); + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(d, mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->UPB_PRIVATE(number); + if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + _upb_Decoder_CheckUnlinked(d, mt, field, op); + } else if (field->UPB_PRIVATE(descriptortype) == + kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; + } + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeKnownField(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableField* field, + int op, wireval* val) { + uint8_t mode = field->UPB_PRIVATE(mode); + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableExtension* ext_layout = + (const upb_MiniTableExtension*)field; + upb_Extension* ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + d->original_msg = msg; + msg = &ext->data.UPB_PRIVATE(ext_msg_val); + } + + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return _upb_Decoder_DecodeToArray(d, ptr, msg, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, field, val, op); + default: + UPB_UNREACHABLE(); + } +} + +UPB_FORCEINLINE +bool _upb_Decoder_CanSkipUnknownField(upb_Decoder* d, uint32_t next_field_num, + uint32_t next_wire_type, + const upb_MiniTable* mt, uint32_t* gap_lo, + uint32_t* gap_hi, bool is_extendable) { + if (next_wire_type == kUpb_WireType_EndGroup) { + return false; + } + + if (UPB_UNLIKELY(upb_MiniTable_IsMessageSet(mt))) { + if (next_field_num == kUpb_MsgSet_Item) { + return false; + } + } + + if (next_field_num <= *gap_lo || next_field_num >= *gap_hi) { + if (UPB_LIKELY(next_field_num == *gap_hi)) { + // Common case of fields in ascending order encountering a known + // field + return false; + } + if (UPB_UNLIKELY(next_field_num == 0)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + if (next_field_num == *gap_lo) { + return false; + } + if (!UPB_PRIVATE(_upb_MiniTable_FindUnknownGap)(mt, next_field_num, gap_lo, + gap_hi)) { + return false; + } + } + + if (is_extendable) { + if (upb_ExtensionRegistry_Lookup(d->extreg, mt, next_field_num)) { + return false; + } + } + + return true; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeUnknowns( + upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable* mt, + uint32_t field_number, uint32_t wire_type, wireval val, const char* start) { + if (field_number == 0) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); + } + + upb_EpsCopyCapture capture; + upb_EpsCopyCapture_Start(&capture, &d->input, start); + + // We have already parsed the tag and "value" (or size) of the first unknown + // field. ptr is currently: + // - after value for Varint, 32Bit, 64Bit. + // - after size for Delimited. + // - after tag for StartGroup. + + // We need to finish skipping the first field. + if (wire_type == kUpb_WireType_Delimited) { + upb_StringView sv; + ptr = upb_EpsCopyInputStream_ReadStringEphemeral(&d->input, ptr, val.size, + &sv); + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, field_number << 3, + d->depth, &d->input); + } + + // Fast check if next fields are also unknown, based on the gap between known + // fields our first unknown falls between. + + uint32_t gap_lo = 0; + uint32_t gap_hi = 0; + bool has_gap = UPB_PRIVATE(_upb_MiniTable_FindUnknownGap)(mt, field_number, + &gap_lo, &gap_hi); + + if (has_gap) { + bool is_extendable = + (UPB_UNLIKELY(UPB_PRIVATE(_upb_MiniTable_IsExtendable)(mt)) || + UPB_UNLIKELY(upb_MiniTable_IsMessageSet(mt))) && + d->extreg; + while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + const char* start_ptr = ptr; + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); + + uint32_t next_field_num = tag >> 3; + uint32_t next_wire_type = tag & 7; + + if (_upb_Decoder_CanSkipUnknownField(d, next_field_num, next_wire_type, + mt, &gap_lo, &gap_hi, + is_extendable)) { + ptr = _upb_WireReader_SkipValueForceInline(ptr, tag, d->depth, EPS(d)); + } else { + ptr = start_ptr; + break; + } + } + } + + upb_StringView sv; + upb_EpsCopyCapture_End(&capture, &d->input, ptr, &sv); + + if (UPB_LIKELY(sv.size > 0)) { + if (!UPB_PRIVATE(_upb_Message_AddUnknown)( + msg, sv.data, sv.size, &d->arena, + _upb_Decoder_GetAddUnknownMode(d, sv.data))) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + } + + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeFieldTag(upb_Decoder* d, const char* ptr, + uint32_t* field_number, + uint32_t* wire_type) { + uint32_t tag; + UPB_ASSERT(ptr < d->input.limit_ptr); + ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); + *field_number = tag >> 3; + *wire_type = tag & 7; + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeFieldData( + upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable* mt, + uint32_t field_number, uint32_t wire_type, const char* start) { + int op; + wireval val; + + const upb_MiniTableField* field = + _upb_Decoder_FindField(d, mt, field_number, wire_type); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, mt, field, wire_type, &val, &op); + + if (op >= 0) { + return _upb_Decoder_DecodeKnownField(d, ptr, msg, field, op, &val); + } else { + switch (op) { + case kUpb_DecodeOp_UnknownField: + return _upb_Decoder_DecodeUnknowns(d, ptr, msg, mt, field_number, + wire_type, val, start); + case kUpb_DecodeOp_MessageSetItem: + return upb_Decoder_DecodeMessageSetItem(d, ptr, msg, mt); + default: + UPB_UNREACHABLE(); + } + } +} + +static const char* _upb_Decoder_EndMessage(upb_Decoder* d, const char* ptr) { + d->message_is_done = true; + return ptr; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeFieldNoFast(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* mt) { + uint32_t field_number; + uint32_t wire_type; + + const char* start = ptr; + ptr = _upb_Decoder_DecodeFieldTag(d, ptr, &field_number, &wire_type); + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return _upb_Decoder_EndMessage(d, ptr); + } + + ptr = _upb_Decoder_DecodeFieldData(d, ptr, msg, mt, field_number, wire_type, + start); + _upb_Decoder_Trace(d, 'M'); + return ptr; +} + +UPB_FORCEINLINE +bool _upb_Decoder_TryDecodeMessageFast(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* mt, + uint64_t last_field_index, + uint64_t data) { +#if UPB_FASTTABLE + if (mt->UPB_PRIVATE(table_mask) == (unsigned char)-1 || + (d->options & kUpb_DecodeOption_DisableFastTable)) { + // Fast table is unavailable or disabled. + return false; + } + + uint64_t data2 = upb_DecodeFastData2_PackMask(mt->UPB_PRIVATE(table_mask)); + const char* start = + UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(&d->input, *ptr); + char* trace_next = _upb_Decoder_TraceNext(d); + + upb_FastDecoder_Return ret = + upb_DecodeFast_Dispatch(d, *ptr, msg, mt, 0, 0, data2); + *ptr = ret.ptr; + + if (d->message_is_done) { + // The entire message was successfully parsed fast. + return true; + } + + // *ptr now points to the beginning of a field that could not be parsed fast. + // It's possible that some fields were parsed fast, in which case *ptr will + // have been updated. However, it's also possible that the very first field + // encountered could not be parsed fast, in which case *ptr will be unchanged. + // + // If the fast decoder consumed any data, it must have emitted at least + // one 'F' event into the trace buffer (in addition to the 'D' event + // that is always emitted). + const char* end = + UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(&d->input, *ptr); + char* trace_end = _upb_Decoder_TracePtr(d); + UPB_ASSERT(trace_end == NULL || trace_end != trace_next || end == start); + _upb_Decoder_Trace(d, '<'); +#endif + return false; +} + +UPB_FORCEINLINE +const char* _upb_Decoder_DecodeField(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable* mt, + uint64_t last_field_index, uint64_t data) { + if (_upb_Decoder_TryDecodeMessageFast(d, &ptr, msg, mt, last_field_index, + data)) { + return ptr; + } else if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + return _upb_Decoder_EndMessage(d, ptr); + } + + return _upb_Decoder_DecodeFieldNoFast(d, ptr, msg, mt); +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEmptyMessage(upb_Decoder* d, + const char* ptr, + upb_Message* msg) { + if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + return ptr; + } + + const char* start = ptr; + const char* capture_end = ptr; + upb_EpsCopyCapture capture; + upb_EpsCopyCapture_Start(&capture, &d->input, start); + while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { + uint32_t tag; + capture_end = ptr; + ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); + if ((tag & 7) == kUpb_WireType_EndGroup) { + d->end_group = tag >> 3; + break; + } + ptr = _upb_WireReader_SkipValueForceInline(ptr, tag, d->depth, EPS(d)); + capture_end = ptr; + } + upb_StringView sv; + upb_EpsCopyCapture_End(&capture, EPS(d), capture_end, &sv); + + if (sv.size > 0) { + if (!UPB_PRIVATE(_upb_Message_AddUnknown)( + msg, sv.data, sv.size, &d->arena, + _upb_Decoder_GetAddUnknownMode(d, sv.data))) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; +} + +// When fasttable is enabled, _upb_Decoder_DecodeMessage possibly calls a +// preserve_none function, which forces a spill of all callee-save registers +// registers to the stack in its prologue and restoration in its epilogue, due +// to mismatched calling conventions - the fast decoder (preserve_none) calls +// _upb_Decoder_DecodeMessage (normal) which calls the fast decoder +// (preserve_none). Arm has a lot of callee-save registers in its normal calling +// convention, including a bunch of simd&fp registers that our preserve_none +// caller is probably not actually using. To avoid this cost, all functions in +// the call stack (excluding force-inlined) between the fast decoder's decode +// message function and a recursive call to the fast decoder should use the fast +// decoder's calling convention. +#if UPB_FASTTABLE +UPB_PRESERVE_NONE +#endif +UPB_NOINLINE +const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* mt) { + UPB_ASSERT(mt); + UPB_ASSERT(d->message_is_done == false); + + if (UPB_UNLIKELY(upb_MiniTable_FieldCount(mt) == 0 && + UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(mt) == + kUpb_ExtMode_NonExtendable)) { + return _upb_Decoder_DecodeEmptyMessage(d, ptr, msg); + } + + do { + ptr = _upb_Decoder_DecodeField(d, ptr, msg, mt, 0, 0); + } while (!d->message_is_done); + d->message_is_done = false; + + return UPB_UNLIKELY(mt && mt->UPB_PRIVATE(required_count)) + ? _upb_Decoder_CheckRequired(d, ptr, msg, mt) + : ptr; +} + +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, + upb_Message* msg, + const upb_MiniTable* m) { + _upb_Decoder_DecodeMessage(d, buf, msg, m); + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; +} + +static upb_DecodeStatus upb_Decoder_Decode(upb_Decoder* const decoder, + const char* const buf, + upb_Message* const msg, + const upb_MiniTable* const m, + upb_Arena* const arena) { + if (UPB_SETJMP(decoder->err->buf) == 0) { + decoder->err->code = _upb_Decoder_DecodeTop(decoder, buf, msg, m); + } else { + UPB_ASSERT(decoder->err->code != kUpb_DecodeStatus_Ok); + } + + return upb_Decoder_Destroy(decoder, arena); +} + +static uint16_t upb_DecodeOptions_GetMaxDepth(uint32_t options) { + return options >> 16; +} + +uint16_t upb_DecodeOptions_GetEffectiveMaxDepth(uint32_t options) { + uint16_t max_depth = upb_DecodeOptions_GetMaxDepth(options); + return max_depth ? max_depth : kUpb_WireFormat_DefaultDepthLimit; +} + +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Decoder decoder; + upb_ErrorHandler err; + upb_ErrorHandler_Init(&err); + buf = upb_Decoder_Init(&decoder, buf, size, extreg, options, arena, &err, + NULL, 0); + + return upb_Decoder_Decode(&decoder, buf, msg, mt, arena); +} + +upb_DecodeStatus upb_DecodeWithTrace(const char* buf, size_t size, + upb_Message* msg, const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena, + char* trace_buf, size_t trace_size) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Decoder decoder; + upb_ErrorHandler err; + upb_ErrorHandler_Init(&err); + buf = upb_Decoder_Init(&decoder, buf, size, extreg, options, arena, &err, + trace_buf, trace_size); + + return upb_Decoder_Decode(&decoder, buf, msg, mt, arena); +} + +upb_DecodeStatus upb_DecodeLengthPrefixed(const char* buf, size_t size, + upb_Message* msg, + size_t* num_bytes_read, + const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + // To avoid needing to make a Decoder just to decode the initial length, + // hand-decode the leading varint for the message length here. + uint64_t msg_len = 0; + for (size_t i = 0;; ++i) { + if (i >= size || i > 9) { + return kUpb_DecodeStatus_Malformed; + } + uint64_t b = *buf; + buf++; + msg_len += (b & 0x7f) << (i * 7); + if ((b & 0x80) == 0) { + *num_bytes_read = i + 1 + msg_len; + break; + } + } + + // If the total number of bytes we would read (= the bytes from the varint + // plus however many bytes that varint says we should read) is larger then the + // input buffer then error as malformed. + if (*num_bytes_read > size) { + return kUpb_DecodeStatus_Malformed; + } + if (msg_len > INT32_MAX) { + return kUpb_DecodeStatus_Malformed; + } + + return upb_Decode(buf, msg_len, msg, mt, extreg, options, arena); +} + +const char* upb_DecodeStatus_String(upb_DecodeStatus status) { + switch (status) { + case kUpb_DecodeStatus_Ok: + return "Ok"; + case kUpb_DecodeStatus_Malformed: + return "Wire format was corrupt"; + case kUpb_DecodeStatus_OutOfMemory: + return "Arena alloc failed"; + case kUpb_DecodeStatus_BadUtf8: + return "String field had bad UTF-8"; + case kUpb_DecodeStatus_MaxDepthExceeded: + return "Exceeded upb_DecodeOptions_MaxDepth"; + case kUpb_DecodeStatus_MissingRequired: + return "Missing required field"; + default: + return "Unknown decode status"; + } +} + +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 + +// We encode backwards, to avoid pre-computing lengths (one-pass encode). + + +#include +#include +#include +#include + + +// Must be last. + +upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { + return _upb_Encode(msg, l, options, arena, buf, size, false); +} + +upb_EncodeStatus upb_EncodeLengthPrefixed(const upb_Message* msg, + const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, + size_t* size) { + return _upb_Encode(msg, l, options, arena, buf, size, true); +} + +const char* upb_EncodeStatus_String(upb_EncodeStatus status) { + switch (status) { + case kUpb_EncodeStatus_Ok: + return "Ok"; + case kUpb_EncodeStatus_MissingRequired: + return "Missing required field"; + case kUpb_EncodeStatus_MaxDepthExceeded: + return "Max depth exceeded"; + case kUpb_EncodeStatus_OutOfMemory: + return "Arena alloc failed"; + default: + return "Unknown encode status"; + } +} + + +#include +#include +#include + + +// Must be last. + +char upb_BackAlloc_sentinel; + +static size_t upb_BackAlloc_CalcBlockSize(upb_BackAlloc* a, size_t required, + bool* one_off) { +#if UPB_HWASAN + required = UPB_ALIGN_UP(required, UPB_MALLOC_ALIGN); +#endif + size_t organic_block_size = + UPB_PRIVATE(_upb_Arena_NextBlockSize)(a->arena, required, one_off); + + // We want to offer amortized linear time, which means we must grow block + // sizes exponentially. However, merely allocating a power of 2 is + // pathological for allocators that use a header with mmap for large + // contiguous allocations. Instead, we want to allocate based on a power of + // 2, but request slightly less to leave room for backing allocator + // metadata. If we had universal size feedback this would not be necessary. + size_t scaled_block_size = upb_RoundUpToPowerOfTwo(required); + + // Estimated value such that 128 bytes of possible overhead is not + // significant. 128 bytes should be enough for whatever metadata is needed. + if (scaled_block_size >= 4096 * 4) { + scaled_block_size = upb_RoundUpToPowerOfTwo(required + 128) - 128; + } + + // Scaled block size calculations could overflow, but that's OK as it's + // unsigned and won't be used if it's less than the organic block size + if (scaled_block_size > organic_block_size) { + return UPB_PRIVATE(_upb_Arena_NextBlockSize)(a->arena, scaled_block_size, + one_off); + } + + return organic_block_size; +} + +static char* upb_BackAlloc_Realloc(upb_BackAlloc* a, char* ptr, size_t n) { + size_t copy = a->limit - ptr; + if (SIZE_MAX - copy < n) { + return NULL; + } + + bool one_off = false; + size_t required_block_size = copy + n; + size_t size = upb_BackAlloc_CalcBlockSize(a, required_block_size, &one_off); + + char* block = UPB_PRIVATE(_upb_Arena_AllocBlock)(a->arena, &size); + + if (!block) { + return NULL; + } + + UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(a->arena, required_block_size, size, + one_off); + + char* dst = block + size - copy; + memcpy(dst, ptr, copy); + + if (a->limit != a->buf) { + // Dispose of the old block. + if (a->standalone) { + // Note: while it would technically be possible to give this block to the + // arena to use for allocations, this could lead to a lot of garbage + // blocks that never get used. + UPB_PRIVATE(_upb_Arena_FreeBlock)(a->arena, a->buf); + } else { + UPB_PRIVATE(_upb_Arena_UseBlock)(a->arena, a->buf, a->limit - a->buf); + } + } + + a->buf = block; + a->limit = block + size; + a->standalone = true; + return dst - n; +} + +char* upb_BackAlloc_Grow(upb_BackAlloc* a, char* ptr, size_t n) { + if (a->limit == a->buf) { + // First allocation: try to steal a block. + size_t size = n; + char* block = UPB_PRIVATE(_upb_Arena_Steal)(a->arena, &size); + if (block) { + UPB_ASSERT(size >= n); + UPB_ASSERT(a->standalone == false); + a->buf = block; + a->limit = block + size; + return a->limit - n; + } + } + + return upb_BackAlloc_Realloc(a, ptr, n); +} + + + + +// Must be last. + +UPB_NOINLINE +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* m) { + UPB_ASSERT(m->UPB_PRIVATE(required_count)); + if (UPB_UNLIKELY(d->options & kUpb_DecodeOption_CheckRequired)) { + d->missing_required = + d->missing_required || + !UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m); + } + return ptr; +} + +// We encode backwards, to avoid pre-computing lengths (one-pass encode). + + +#include +#include +#include +#include + + +// Must be last. + +UPB_NOINLINE bool _upb_Encoder_AddMapEntryUnknown( + upb_Message* msg, const upb_MiniTableField* field, upb_Message* ent_msg, + const upb_MiniTable* entry, upb_Arena* arena) { + char* buf; + size_t size; + upb_EncodeStatus status = + _upb_Encode(ent_msg, entry, 0, arena, &buf, &size, false); + if (status != kUpb_EncodeStatus_Ok) { + return false; + } + char delim_buf[2 * kUpb_Encoder_EncodeVarint32MaxSize]; + char* delim_end = delim_buf; + uint32_t tag = + ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Delimited; + delim_end = upb_Encoder_EncodeVarint32(tag, delim_end); + delim_end = upb_Encoder_EncodeVarint32(size, delim_end); + upb_StringView unknown[] = { + {delim_buf, delim_end - delim_buf}, + {buf, size}, + }; + + return UPB_PRIVATE(_upb_Message_AddUnknownV)(msg, arena, unknown, 2); +} + +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); +} +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); +} + +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_ASSERT(s != kUpb_EncodeStatus_Ok); + e->status = s; + UPB_LONGJMP(*e->err, 1); +} + +UPB_NOINLINE static char* encode_growbuffer(char* ptr, upb_encstate* e, + size_t bytes) { + ptr = upb_BackAlloc_Grow(&e->alloc, ptr, bytes); + if (ptr == NULL) { + encode_err(e, kUpb_EncodeStatus_OutOfMemory); + } + return ptr; +} + +// Call to ensure that at least `bytes` bytes are available for writing at +// ptr. +UPB_FORCEINLINE +char* encode_reserve(char* ptr, upb_encstate* e, size_t bytes) { + if (upb_BackAlloc_HasBytes(&e->alloc, ptr, bytes)) { + return ptr - bytes; + } + return encode_growbuffer(ptr, e, bytes); +} + +static char* encode_bytes_unchecked(char* ptr, upb_encstate* e, + const void* data, size_t len) { + if (len == 0) return ptr; /* memcpy() with zero size is UB */ + ptr -= len; + memcpy(ptr, data, len); + return ptr; +} + +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static char* encode_bytes(char* ptr, upb_encstate* e, const void* data, + size_t len) { + if (len == 0) return ptr; /* memcpy() with zero size is UB */ + ptr = encode_reserve(ptr, e, len); + memcpy(ptr, data, len); + return ptr; +} + +static char* encode_fixed64_unchecked(char* ptr, upb_encstate* e, + uint64_t val) { + val = upb_BigEndian64(val); + return encode_bytes_unchecked(ptr, e, &val, sizeof(uint64_t)); +} + +static char* encode_fixed32_unchecked(char* ptr, upb_encstate* e, + uint32_t val) { + val = upb_BigEndian32(val); + return encode_bytes_unchecked(ptr, e, &val, sizeof(uint32_t)); +} + +#define UPB_PB_VARINT_MAX_LEN 10 +#define UPB_PB_VARINT32_MAX_LEN 5 + +#if UPB_ARM64_ASM +// Each arm64 instruction encodes to 4 bytes, and it takes two intructions +// to process each byte of output, so we branch ahead by (4 + 4) * skip to +// avoid the remaining bytes. When BTI is on, we need to use specific +// "landing pad" instructions, so we pad those with nop to make it a power +// of 2, skipping 16 bytes at each stage instead of 8. This carries some +// overhead especially on in-order cores so they're not included unless +// building with branch protection. +#if UPB_ARM64_BTI_DEFAULT +// BTI is used with jc targets here because we don't control which register will +// be used for addr; if it's x16 or x17 a `br` is treated like a call. +#define UPB_BTI_JC "bti jc\n" +#define UPB_BTI_NOP "nop\n" +#define UPB_BTI_SHIFT_IMM "4\n" +#else +#define UPB_BTI_JC +#define UPB_BTI_NOP +#define UPB_BTI_SHIFT_IMM "3\n" +#endif +UPB_NOINLINE static char* encode_longvarint(char* ptr, upb_encstate* e, + uint64_t val) { + ptr = encode_reserve(ptr, e, UPB_PB_VARINT_MAX_LEN); + uint64_t clz; + __asm__("clz %[cnt], %[val]\n" : [cnt] "=r"(clz) : [val] "r"(val)); + + uint32_t skip = + UPB_PRIVATE(upb_WireWriter_VarintUnusedSizeFromLeadingZeros64)(clz); + + ptr += skip; + uint64_t addr, mask; + __asm__ volatile( + // Formatter keeps merging short lines + // clang-format off + "adr %[addr], 0f\n" + "add %[addr], %[addr], %[cnt], lsl #" UPB_BTI_SHIFT_IMM + "mov %w[mask], #0x80\n" + "br %[addr]\n" + // Work around llvm/llvm-project#47432, where alignment directives inside + // functions crash the compiler when generating SEH info on windows. + #ifndef __SEH__ + ".p2align " UPB_BTI_SHIFT_IMM + #endif + "0:\n" + // We don't need addr any more, but we've got the register for our whole + // assembly block so we'll use it as scratch to store the shift+masked + // values before storing them. + // The following stores are unsigned offset stores: + // strb Wt, [Xn, #imm] + UPB_BTI_JC + "orr %[addr], %[mask], %[val], lsr #56\n" + "strb %w[addr], [%[ptr], #8]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %[addr], %[mask], %[val], lsr #49\n" + "strb %w[addr], [%[ptr], #7]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %[addr], %[mask], %[val], lsr #42\n" + "strb %w[addr], [%[ptr], #6]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %[addr], %[mask], %[val], lsr #35\n" + "strb %w[addr], [%[ptr], #5]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %[addr], %[mask], %[val], lsr #28\n" + "strb %w[addr], [%[ptr], #4]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %w[addr], %w[mask], %w[val], lsr #21\n" + "strb %w[addr], [%[ptr], #3]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %w[addr], %w[mask], %w[val], lsr #14\n" + "strb %w[addr], [%[ptr], #2]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %w[addr], %w[mask], %w[val], lsr #7\n" + "strb %w[addr], [%[ptr], #1]\n" + UPB_BTI_NOP + + UPB_BTI_JC + "orr %w[addr], %w[val], #0x80\n" + "strb %w[addr], [%[ptr]]\n" + UPB_BTI_NOP + + UPB_BTI_JC + // clang-format on + : [addr] "=&r"(addr), [mask] "=&r"(mask) + : [val] "r"(val), [ptr] "r"(ptr), [cnt] "r"((uint64_t)skip) + : "memory"); + uint32_t continuations = UPB_PB_VARINT_MAX_LEN - 1 - skip; + // msan can't instrument stores in inline assembly + UPB_PRIVATE(upb_Xsan_MarkInitialized)(ptr, continuations); + // Encode the final byte after the continuation bytes. + ptr[continuations] = val >> (7 * continuations); + return ptr; +} +#undef UPB_BTI_JC +#undef UPB_BTI_NOP +#undef UPB_BTI_SHIFT_IMM +#else +UPB_NOINLINE +static char* encode_longvarint(char* ptr, upb_encstate* e, uint64_t val) { + ptr = encode_reserve(ptr, e, UPB_PB_VARINT_MAX_LEN); + size_t len = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + ptr[len++] = byte; + } while (val); + char* start = ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, ptr, len); + return start; +} +#endif + +UPB_FORCEINLINE +char* encode_varint_unchecked(char* ptr, upb_encstate* e, uint64_t val) { + if (val < 128) { + --ptr; + *ptr = val; + return ptr; + } else { + return encode_longvarint(ptr, e, val); + } +} +UPB_FORCEINLINE +char* encode_varint(char* ptr, upb_encstate* e, uint64_t val) { + if (val < 128 && upb_BackAlloc_HasBytes(&e->alloc, ptr, 1)) { + --ptr; + *ptr = val; + return ptr; + } else { + return encode_longvarint(ptr, e, val); + } +} + +UPB_NOINLINE +char* encode_longlength(char* ptr, upb_encstate* e, uint64_t val) { + if (val > INT32_MAX) { + encode_err(e, kUpb_EncodeStatus_MaxSizeExceeded); + } + return encode_longvarint(ptr, e, val); +} + +UPB_FORCEINLINE +char* encode_length(char* ptr, upb_encstate* e, uint64_t val) { + if (val < 128 && upb_BackAlloc_HasBytes(&e->alloc, ptr, 1)) { + --ptr; + *ptr = val; + return ptr; + } else { + return encode_longlength(ptr, e, val); + } +} + +UPB_FORCEINLINE +char* encode_length_unchecked(char* ptr, upb_encstate* e, uint64_t val) { + if (val < 128) { + --ptr; + *ptr = val; + return ptr; + } else { + return encode_longlength(ptr, e, val); + } +} + +static char* encode_double_unchecked(char* ptr, upb_encstate* e, double d) { + uint64_t u64; + UPB_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), "bad double size"); + memcpy(&u64, &d, sizeof(uint64_t)); + return encode_fixed64_unchecked(ptr, e, u64); +} + +static char* encode_float_unchecked(char* ptr, upb_encstate* e, float d) { + uint32_t u32; + UPB_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "bad float size"); + memcpy(&u32, &d, sizeof(uint32_t)); + return encode_fixed32_unchecked(ptr, e, u32); +} + +static char* encode_tag_unchecked(char* ptr, upb_encstate* e, + uint32_t field_number, uint8_t wire_type) { + return encode_varint_unchecked(ptr, e, (field_number << 3) | wire_type); +} + +static char* encode_tag(char* ptr, upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + return encode_varint(ptr, e, (field_number << 3) | wire_type); +} + +static char* encode_fixedarray(char* ptr, upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = upb_Array_Size(arr) * elem_size; + const char* data = upb_Array_DataPtr(arr); + const char* arr_ptr = data + bytes - elem_size; + + if (tag || !upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, arr_ptr, sizeof(val)); + val = upb_BigEndian32(val); + ptr = encode_bytes(ptr, e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, arr_ptr, sizeof(val)); + val = upb_BigEndian64(val); + ptr = encode_bytes(ptr, e, &val, elem_size); + } + + if (tag) { + ptr = encode_varint(ptr, e, tag); + } + if (arr_ptr == data) break; + arr_ptr -= elem_size; + } + return ptr; + } else { + return encode_bytes(ptr, e, data, bytes); + } +} + +static char* encode_scalar(char* ptr, upb_encstate* e, const void* field_mem, + const upb_MiniTableField* f) { + // Max size is tag + 10 bytes for max varint or 8 for largest fixed size +#define CASE(ctype, type, wtype, encodeval) \ + { \ + const size_t bytes = UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT_MAX_LEN; \ + ptr = encode_reserve(ptr, e, bytes); \ + ptr += bytes; \ + const ctype val = *(const ctype*)field_mem; \ + ptr = encode_##type##_unchecked(ptr, e, encodeval); \ + return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), wtype); \ + } + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + const size_t max_size = + UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT32_MAX_LEN + view.size; + ptr = encode_reserve(ptr, e, max_size); + ptr += max_size; + ptr = encode_bytes_unchecked(ptr, e, view.data, view.size); + ptr = encode_length_unchecked(ptr, e, view.size); + return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_Delimited); + } + case kUpb_FieldType_Group: { + size_t size; + upb_Message* submsg = *(upb_Message**)field_mem; + const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); + if (submsg == 0) { + return ptr; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_EndGroup); + ptr = encode_message(ptr, e, submsg, subm, &size); + e->depth++; + return encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_StartGroup); + } + case kUpb_FieldType_Message: { + size_t size; + upb_Message* submsg = *(upb_Message**)field_mem; + const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); + if (submsg == 0) { + return ptr; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + ptr = encode_message(ptr, e, submsg, subm, &size); + e->depth++; + size_t max_size = UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT32_MAX_LEN; + ptr = encode_reserve(ptr, e, max_size); + ptr += max_size; + ptr = encode_length_unchecked(ptr, e, size); + return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_Delimited); + } + default: + UPB_UNREACHABLE(); + } +#undef CASE +} + +static char* encode_array(char* ptr, upb_encstate* e, const upb_Message* msg, + const upb_MiniTableField* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*); + bool packed = upb_MiniTableField_IsPacked(f); + size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); + + if (arr == NULL || upb_Array_Size(arr) == 0) { + return ptr; + } + +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = upb_Array_DataPtr(arr); \ + const ctype* arr_ptr = start + upb_Array_Size(arr); \ + if (packed) { \ + do { \ + arr_ptr--; \ + ptr = encode_varint(ptr, e, encode); \ + } while (arr_ptr != start); \ + } else { \ + uint32_t number = upb_MiniTableField_Number(f); \ + do { \ + arr_ptr--; \ + ptr = encode_varint(ptr, e, encode); \ + ptr = encode_tag(ptr, e, number, kUpb_WireType_Varint); \ + } while (arr_ptr != start); \ + } \ + } \ + break; + +#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type)) + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + ptr = encode_fixedarray(ptr, e, arr, sizeof(double), + TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + ptr = encode_fixedarray(ptr, e, arr, sizeof(float), + TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + ptr = encode_fixedarray(ptr, e, arr, sizeof(uint64_t), + TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + ptr = encode_fixedarray(ptr, e, arr, sizeof(uint32_t), + TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *arr_ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *arr_ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*arr_ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *arr_ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*arr_ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*arr_ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = upb_Array_DataPtr(arr); + const upb_StringView* str_ptr = start + upb_Array_Size(arr); + do { + str_ptr--; + ptr = encode_bytes(ptr, e, str_ptr->data, str_ptr->size); + ptr = encode_length(ptr, e, str_ptr->size); + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_Delimited); + } while (str_ptr != start); + return ptr; + } + case kUpb_FieldType_Group: { + const upb_Message* const* start = upb_Array_DataPtr(arr); + const upb_Message* const* arr_ptr = start + upb_Array_Size(arr); + const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + arr_ptr--; + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_EndGroup); + ptr = encode_message(ptr, e, *arr_ptr, subm, &size); + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_StartGroup); + } while (arr_ptr != start); + e->depth++; + return ptr; + } + case kUpb_FieldType_Message: { + const upb_Message* const* start = upb_Array_DataPtr(arr); + const upb_Message* const* arr_ptr = start + upb_Array_Size(arr); + const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + arr_ptr--; + ptr = encode_message(ptr, e, *arr_ptr, subm, &size); + ptr = encode_length(ptr, e, size); + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_Delimited); + } while (arr_ptr != start); + e->depth++; + return ptr; + } + } +#undef VARINT_CASE + + if (packed) { + ptr = encode_length(ptr, e, upb_BackAlloc_Size(&e->alloc, ptr) - pre_len); + ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), + kUpb_WireType_Delimited); + } + return ptr; +} + +static char* encode_mapentry(char* ptr, upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTableField* key_field = upb_MiniTable_MapKey(layout); + const upb_MiniTableField* val_field = upb_MiniTable_MapValue(layout); + size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); + size_t size; + ptr = encode_scalar(ptr, e, &ent->v, val_field); + ptr = encode_scalar(ptr, e, &ent->k, key_field); + size = upb_BackAlloc_Size(&e->alloc, ptr) - pre_len; + ptr = encode_length(ptr, e, size); + ptr = encode_tag(ptr, e, number, kUpb_WireType_Delimited); + return ptr; +} + +static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg, + const upb_MiniTableField* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*); + const upb_MiniTable* layout = upb_MiniTable_MapEntrySubMessage(f); + UPB_ASSERT(upb_MiniTable_FieldCount(layout) == 2); + + if (!map || !upb_Map_Size(map)) return ptr; + + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap( + &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), + map, &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + ptr = encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + upb_value val; + if (map->UPB_PRIVATE(is_strtable)) { + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView strkey; + while (upb_strtable_next2(&map->t.strtable, &strkey, &val, &iter)) { + upb_MapEntry ent; + _upb_map_fromkey(strkey, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + ptr = + encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent); + } + } else { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t intkey = 0; + while (upb_inttable_next(&map->t.inttable, &intkey, &val, &iter)) { + upb_MapEntry ent; + memcpy(&ent.k, &intkey, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + ptr = + encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent); + } + } + } + return ptr; +} + +static bool encode_shouldencode(const upb_Message* msg, + const upb_MiniTableField* f) { + if (f->presence == 0) { + // Proto3 presence or map/array. + const void* mem = UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), void); + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + // Proto2 presence: hasbit. + return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f); + } else { + // Field is in a oneof. + return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) == + upb_MiniTableField_Number(f); + } +} + +static char* encode_field(char* ptr, upb_encstate* e, const upb_Message* msg, + const upb_MiniTableField* field) { + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { + case kUpb_FieldMode_Array: + return encode_array(ptr, e, msg, field); + case kUpb_FieldMode_Map: + return encode_map(ptr, e, msg, field); + case kUpb_FieldMode_Scalar: + return encode_scalar( + ptr, e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), field); + default: + UPB_UNREACHABLE(); + } +} + +static char* encode_msgset_item(char* ptr, upb_encstate* e, + const upb_MiniTableExtension* ext, + const upb_MessageValue ext_val) { + size_t size; + ptr = encode_tag(ptr, e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup); + ptr = encode_message(ptr, e, ext_val.msg_val, + upb_MiniTableExtension_GetSubMessage(ext), &size); + ptr = encode_varint(ptr, e, size); + ptr = encode_tag(ptr, e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); + ptr = encode_varint(ptr, e, upb_MiniTableExtension_Number(ext)); + ptr = encode_tag(ptr, e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint); + ptr = encode_tag(ptr, e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup); + return ptr; +} + +static char* encode_ext(char* ptr, upb_encstate* e, + const upb_MiniTableExtension* ext, + upb_MessageValue ext_val, bool is_message_set) { + if (UPB_UNLIKELY(is_message_set)) { + ptr = encode_msgset_item(ptr, e, ext, ext_val); + } else { + ptr = encode_field(ptr, e, &ext_val.UPB_PRIVATE(ext_msg_val), + &ext->UPB_PRIVATE(field)); + } + return ptr; +} + +static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m, + const upb_Message* msg) { + if (UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == kUpb_ExtMode_NonExtendable) + return ptr; + + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return ptr; + + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + uintptr_t iter = kUpb_Message_ExtensionBegin; + const upb_MiniTableExtension* ext; + upb_MessageValue ext_val; + if (!UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &ext_val, + &iter)) { + // Message has no extensions. + return ptr; + } + + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) { + // TODO: b/378744096 - handle alloc failure + } + const upb_Extension* ext; + while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) { + ptr = encode_ext(ptr, e, ext->ext, ext->data, + UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == + kUpb_ExtMode_IsMessageSet); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + do { + ptr = encode_ext(ptr, e, ext, ext_val, + m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet); + } while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &ext_val, + &iter)); + } + return ptr; +} + +char* encode_message(char* ptr, upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); + + if (e->options & kUpb_EncodeOption_CheckRequired) { + if (m->UPB_PRIVATE(required_count)) { + if (!UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m)) { + encode_err(e, kUpb_EncodeStatus_MissingRequired); + } + } + } + + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { + size_t unknown_size = 0; + uintptr_t iter = kUpb_Message_UnknownBegin; + upb_StringView unknown; + // Need to write in reverse order, but iteration is in-order; scan to + // reserve capacity up front, then write in-order + while (upb_Message_NextUnknown(msg, &unknown, &iter)) { + unknown_size += unknown.size; + } + if (unknown_size != 0) { + ptr = encode_reserve(ptr, e, unknown_size); + char* tmp_ptr = ptr; + iter = kUpb_Message_UnknownBegin; + while (upb_Message_NextUnknown(msg, &unknown, &iter)) { + memcpy(tmp_ptr, unknown.data, unknown.size); + tmp_ptr += unknown.size; + } + } + } + + ptr = encode_exts(ptr, e, m, msg); + + if (upb_MiniTable_FieldCount(m)) { + const upb_MiniTableField* f = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0]; + while (f != first) { + f--; + if (encode_shouldencode(msg, f)) { + ptr = encode_field(ptr, e, msg, f); + } + } + } + + *size = upb_BackAlloc_Size(&e->alloc, ptr) - pre_len; + return ptr; +} + +static upb_EncodeStatus upb_Encoder_Encode(char* ptr, + upb_encstate* const encoder, + const upb_Message* const msg, + const upb_MiniTable* const l, + char** const buf, size_t* const size, + bool prepend_len) { + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (UPB_SETJMP(*encoder->err) == 0) { + size_t encoded_msg_size; + ptr = encode_message(ptr, encoder, msg, l, &encoded_msg_size); + if (prepend_len) { + ptr = encode_length(ptr, encoder, encoded_msg_size); + } + *size = upb_BackAlloc_Finish(&encoder->alloc, ptr); + *buf = ptr; + } else { + UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); + upb_BackAlloc_Abort(&encoder->alloc); + *buf = NULL; + *size = 0; + } + UPB_PRIVATE(_upb_encstate_destroy)(encoder); + return encoder->status; +} + +upb_EncodeStatus _upb_Encode(const upb_Message* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size, bool prepend_len) { + upb_encstate e; + jmp_buf err; + + e.status = kUpb_EncodeStatus_Ok; + e.err = &err; + char* ptr = upb_BackAlloc_Init(&e.alloc, arena); + e.depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); + e.options = options; + _upb_mapsorter_init(&e.sorter); + + return upb_Encoder_Encode(ptr, &e, msg, l, buf, size, prepend_len); +} + +upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Field)(upb_encstate* e, + const upb_Message* msg, + const upb_MiniTableField* field, + char** buf, size_t* size, + int options) { + e->options = options; + e->depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); + char* ptr = *buf; + if (encode_shouldencode(msg, field)) { + ptr = encode_field(ptr, e, msg, field); + } + *size = upb_BackAlloc_Finish(&e->alloc, ptr); + *buf = ptr; + return e->status; +} + +upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Extension)( + upb_encstate* e, const upb_MiniTableExtension* ext, + upb_MessageValue ext_val, bool is_message_set, char** buf, size_t* size, + int options) { + e->options = options; + e->depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); + char* ptr = *buf; + ptr = encode_ext(ptr, e, ext, ext_val, is_message_set); + *size = upb_BackAlloc_Finish(&e->alloc, ptr); + *buf = ptr; + return e->status; +} + + +#include +#include + + +// Must be last. + +UPB_NORETURN UPB_NOINLINE void UPB_PRIVATE( + upb_EpsCopyInputStream_ThrowMalformed)(upb_EpsCopyInputStream* e) { + e->error = true; + upb_ErrorHandler_ThrowError(e->err, kUpb_ErrorCode_Malformed); +} + +const char* UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneFallback)( + struct upb_EpsCopyInputStream* e, const char* ptr, int overrun) { + if (overrun < e->limit) { + // Need to copy remaining data into patch buffer. + UPB_ASSERT(overrun < kUpb_EpsCopyInputStream_SlopBytes); + const char* old_end = ptr; + const char* new_start = &e->patch[overrun]; + memset(&e->patch[kUpb_EpsCopyInputStream_SlopBytes], 0, + kUpb_EpsCopyInputStream_SlopBytes); + memcpy(e->patch, e->end, kUpb_EpsCopyInputStream_SlopBytes); + ptr = new_start; + e->end = &e->patch[kUpb_EpsCopyInputStream_SlopBytes]; + e->limit -= kUpb_EpsCopyInputStream_SlopBytes; + e->limit_ptr = e->end + e->limit; + UPB_ASSERT(ptr < e->limit_ptr); + e->input_delta = (uintptr_t)old_end - (uintptr_t)new_start; + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)(e); + return new_start; + } else { + UPB_ASSERT(overrun > e->limit); + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); + } +} + + +#include +#include + + +// Must be last. + +UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) + UPB_PRIVATE(_upb_WireReader_ReadLongVarint)( + const char* ptr, uint64_t val, upb_EpsCopyInputStream* stream) { + for (int i = 1; i < 10; i++) { + uint64_t byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; + } + } + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ + UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; +} + +UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) + UPB_PRIVATE(_upb_WireReader_ReadLongTag)(const char* ptr, uint64_t val, + upb_EpsCopyInputStream* stream) { + for (int i = 1; i < 5; i++) { + uint64_t byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + if (val > UINT32_MAX) break; + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; + } + } + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ + UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; +} + +UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) + UPB_PRIVATE(_upb_WireReader_ReadLongSize)(const char* ptr, uint64_t val, + upb_EpsCopyInputStream* stream) { + for (int i = 1; i < 5; i++) { + uint64_t byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + if (val > INT32_MAX) break; + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; + } + } + return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ + UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + if (--depth_limit < 0) { + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); + } + uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup; + while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag, stream); + if (!ptr) break; + if (tag == end_group_tag) return ptr; + ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, stream); + if (!ptr) break; + } + // Encountered limit end before end group tag. + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); +} + +// This should #undef all macros #defined in def.inc + +#undef UPB_SIZE +#undef UPB_PTR_AT +#undef UPB_SIZEOF_FLEX +#undef UPB_SIZEOF_FLEX_WOULD_OVERFLOW +#undef UPB_MAPTYPE_STRING +#undef UPB_EXPORT +#undef UPB_INLINE +#undef UPB_API +#undef UPBC_API +#undef UPB_API_INLINE +#undef UPB_API_INLINE_IF_NOT_GCC +#undef UPB_ALIGN_UP +#undef UPB_ALIGN_DOWN +#undef UPB_ALIGN_MALLOC +#undef UPB_ALIGN_OF +#undef UPB_ALIGN_AS +#undef UPB_STATIC_ASSERT +#undef UPB_STATIC_ASSERT_CONCAT +#undef UPB_STATIC_ASSERT_CONCAT_IMPL +#undef UPB_LIKELY +#undef UPB_UNLIKELY +#undef UPB_UNPREDICTABLE +#undef UPB_FORCEINLINE +#undef UPB_NOINLINE +#undef UPB_NORETURN +#undef UPB_PRINTF +#undef UPB_NODEREF +#undef UPB_NODISCARD +#undef UPB_MAX +#undef UPB_MIN +#undef UPB_UNUSED +#undef UPB_ASSUME +#undef UPB_ASSERT +#undef UPB_UNREACHABLE +#undef UPB_UNREACHABLE_FAILURE +#undef UPB_PRETTY_FUNCTION +#undef UPB_DEFAULT_MAX_BLOCK_SIZE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_PRESERVE_MOST +#undef UPB_PRESERVE_NONE +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE_MASK +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT +#undef UPB_POISON_MEMORY_REGION +#undef UPB_UNPOISON_MEMORY_REGION +#undef UPB_ASAN +#undef UPB_HWASAN +#undef UPB_HWASAN_POISON_TAG +#undef UPB_MSAN +#undef UPB_MALLOC_ALIGN +#undef UPB_TSAN +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN +#undef UPB_CLANG_MIN +#undef UPB_DESCRIPTOR_UPB_H_FILENAME +#undef UPB_DESC_MINITABLE +#undef UPB_IS_GOOGLE3 +#undef UPB_ATOMIC +#undef UPB_USE_C11_ATOMICS +#undef UPB_USE_MSC_ATOMICS +#undef UPB_PRIVATE +#undef UPB_ONLYBITS +#undef UPB_LINKARR_DECLARE +#undef UPB_LINKARR_APPEND +#undef UPB_LINKARR_START +#undef UPB_LINKARR_STOP +#undef UPB_HAS_ATTRIBUTE +#undef UPB_HAS_CPP_ATTRIBUTE +#undef UPB_HAS_BUILTIN +#undef UPB_HAS_EXTENSION +#undef UPB_HAS_FEATURE +#undef UPB_XSAN_MEMBER +#undef UPB_XSAN +#undef UPB_XSAN_STRUCT_SIZE +#undef UPB_ENABLE_REF_CYCLE_CHECKS +#undef UPB_ARM64_ASM +#undef UPB_ARM64_BTI_DEFAULT +#undef UPB_DEPRECATE_AND_INLINE +#undef UPB_MAYBE_ASSUME +#undef UPB_ATTR_CONST +#undef _UPB_STRINGIFY +#undef _UPB_STRINGIFY2 +#undef UPB_CONSTRUCTOR diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.h new file mode 100755 index 00000000..71dfff57 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/ruby-upb.h @@ -0,0 +1,19260 @@ +/* Amalgamated source file */ + +/* + * This is where we define internal portability macros used across upb. + * + * All of these macros are undef'd in undef.inc to avoid leaking them to users. + * + * The correct usage is: + * + * #include "upb/foobar.h" + * #include "upb/baz.h" + * + * // MUST be last included header. + * #include "upb/port/def.inc" + * + * // Code for this file. + * // <...> + * + * // Can be omitted for .c files, required for .h. + * #include "upb/port/undef.inc" + * + * This file is private and must not be included by users! + */ + +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201703L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +#error upb requires C99 or C++17 or MSVC >= 2015. +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +#define UPB_GNUC_MIN(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define UPB_GNUC_MIN(x, y) 0 +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +#define UPB_CLANG_MIN(x, y) \ + (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) +#else +#define UPB_CLANG_MIN(x, y) 0 +#endif + +// Macros for checking for compiler attributes, defined here to avoid the +// problem described in +// https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. +#ifdef __has_attribute +#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +#define UPB_HAS_ATTRIBUTE(x) 0 +#endif + +#ifdef __has_c_attribute +#define UPB_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +#define UPB_HAS_C_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +// NOTE: requiring __cplusplus above should not be necessary, but +// works around https://bugs.llvm.org/show_bug.cgi?id=23435. +#define UPB_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define UPB_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +// Once in a while we want to use this macro in a C++-only portion of an +// otherwise C-compatible header, so we copy and paste this from ABSL. +#if UPB_HAS_CPP_ATTRIBUTE(deprecated) && UPB_HAS_CPP_ATTRIBUTE(clang::annotate) +#define UPB_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]] +#elif UPB_HAS_CPP_ATTRIBUTE(deprecated) +#define UPB_DEPRECATE_AND_INLINE() [[deprecated]] +#else +#define UPB_DEPRECATE_AND_INLINE() +#endif + +#ifdef __has_builtin +#define UPB_HAS_BUILTIN(x) __has_builtin(x) +#else +#define UPB_HAS_BUILTIN(x) 0 +#endif + +#ifdef __has_extension +#define UPB_HAS_EXTENSION(x) __has_extension(x) +#else +#define UPB_HAS_EXTENSION(x) 0 +#endif + +#ifdef __has_feature +#define UPB_HAS_FEATURE(x) __has_feature(x) +#else +#define UPB_HAS_FEATURE(x) 0 +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef UINTPTR_MAX +Error, UINTPTR_MAX is undefined +#endif + +#if UINTPTR_MAX == 0xffffffff +#define UPB_SIZE(size32, size64) size32 +#else +#define UPB_SIZE(size32, size64) size64 +#endif + +/* If we always read/write as a consistent type to each address, this shouldn't + * violate aliasing. + */ +#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) + +// A flexible array member may have lower alignment requirements than the struct +// overall - in that case, it can overlap with the trailing padding of the rest +// of the struct, and a naive sizeof(base) + sizeof(flex) * count calculation +// will not take into account that overlap, and allocate more than is required. +#define UPB_SIZEOF_FLEX(type, member, count) \ + UPB_MAX(sizeof(type), offsetof(type, member[count])) + +#define UPB_SIZEOF_FLEX_WOULD_OVERFLOW(type, member, count) \ + (((SIZE_MAX - offsetof(type, member[0])) / \ + (offsetof(type, member[1]) - offsetof(type, member[0]))) < (size_t)count) + +#define UPB_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#define UPB_MAPTYPE_STRING 0 + +// UPB_EXPORT: always generate a public symbol. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) +#else +#define UPB_EXPORT +#endif + +// UPB_INLINE: inline if possible, emit standalone code if required. +#ifdef __cplusplus +#define UPB_INLINE inline +#elif defined(__GNUC__) || defined(__clang__) +#define UPB_INLINE static __inline__ +#else +#define UPB_INLINE static +#endif + +// UPB_INLINE_IF_NOT_GCC: because gcc can be very noisy at times. +#if defined(__GNUC__) && !defined(__clang__) +#define UPB_INLINE_IF_NOT_GCC static +#else +#define UPB_INLINE_IF_NOT_GCC UPB_INLINE +#endif + +#ifdef UPB_BUILD_API +#define UPB_API UPB_EXPORT +#define UPB_API_INLINE UPB_EXPORT +#else +#define UPB_API +#define UPB_API_INLINE UPB_INLINE +#endif + +#ifdef EXPORT_UPBC +#define UPBC_API UPB_EXPORT +#else +#define UPBC_API +#endif + +#if UPB_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#define UPB_ASAN 1 +#else +#define UPB_ASAN 0 +#endif + +#if UPB_HAS_FEATURE(hwaddress_sanitizer) +#define UPB_HWASAN 1 +#define UPB_HWASAN_POISON_TAG 17 +#define UPB_MALLOC_ALIGN 16 +#else +#define UPB_HWASAN 0 +#define UPB_MALLOC_ALIGN 8 +#endif + +#if UPB_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#define UPB_TSAN 1 +#else +#define UPB_TSAN 0 +#endif + +#if UPB_HAS_FEATURE(memory_sanitizer) +#define UPB_MSAN 1 +#else +#define UPB_MSAN 0 +#endif + +// An unfortunate concession to C++17 and MSVC, which don't support zero-sized +// structs. +#if UPB_ASAN || UPB_HWASAN || UPB_TSAN +#define UPB_XSAN_MEMBER upb_Xsan xsan; +#define UPB_XSAN(st) (&(st)->xsan) +#define UPB_XSAN_STRUCT_SIZE 1 +#else +#define UPB_XSAN_MEMBER +#define UPB_XSAN(st) (NULL) +#define UPB_XSAN_STRUCT_SIZE 0 +#endif + +#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) +#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) + +#if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_alignof) || \ + defined(__cplusplus) +#define UPB_ALIGN_OF(type) alignof(type) +#elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_alignof) +#define UPB_ALIGN_OF(type) _Alignof(type) +#elif UPB_GNUC_MIN(2, 95) +#define UPB_ALIGN_OF(type) __alignof__(type) +#elif defined(_MSC_VER) +#define UPB_ALIGN_OF(type) __alignof(type) +#else +#define UPB_ALIGN_OF(type) \ + offsetof( \ + struct { \ + char c; \ + type member; \ + }, \ + member) +#endif + +#ifdef _MSC_VER +// Some versions of our Windows compiler don't support the C11 syntax. +#define UPB_ALIGN_AS(x) __declspec(align(x)) +#elif defined(__GNUC__) +#define UPB_ALIGN_AS(x) __attribute__((aligned(x))) +#else +#define UPB_ALIGN_AS(x) _Alignas(x) +#endif + +#if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_static_assert) || \ + defined(__cplusplus) +#define UPB_STATIC_ASSERT(val, msg) static_assert((val), msg) +#elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_static_assert) || \ + UPB_GNUC_MIN(4, 6) +#define UPB_STATIC_ASSERT(val, msg) _Static_assert((val), msg) +#else +// Unfortunately this hack doesn't work inside struct declarations, but it works +// everywhere else +#define UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) s1##s2 +#define UPB_STATIC_ASSERT_CONCAT(s1, s2) UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) +#ifdef __COUNTER__ +#define UPB_STATIC_ASSERT(condition, message) \ + typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ + __COUNTER__)[(condition) ? 1 : -1] +#else +#define UPB_STATIC_ASSERT(condition, message) \ + typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ + __LINE__)[(condition) ? 1 : -1] +#endif +#endif + +// Hints to the compiler about likely/unlikely branches. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) +#else +#define UPB_LIKELY(x) (x) +#define UPB_UNLIKELY(x) (x) +#endif + +#if UPB_HAS_BUILTIN(__builtin_expect_with_probability) +#define UPB_UNPREDICTABLE(x) \ + __builtin_expect_with_probability((bool)(x), 1, 0.5) +#else +#define UPB_UNPREDICTABLE(x) (x) +#endif + +// Macros for function attributes on compilers that support them. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static +#define UPB_NOINLINE __attribute__((noinline)) +#define UPB_NORETURN __attribute__((__noreturn__)) +#define UPB_PRINTF(str, first_vararg) \ + __attribute__((format(printf, str, first_vararg))) +#elif defined(_MSC_VER) +#define UPB_NOINLINE +#define UPB_FORCEINLINE static +#define UPB_NORETURN __declspec(noreturn) +#define UPB_PRINTF(str, first_vararg) +#else /* !defined(__GNUC__) */ +#define UPB_FORCEINLINE static +#define UPB_NOINLINE +#define UPB_NORETURN +#define UPB_PRINTF(str, first_vararg) +#endif + +#if UPB_HAS_ATTRIBUTE(noderef) +#define UPB_NODEREF __attribute__((noderef)) +#else +#define UPB_NODEREF +#endif + +// Will be defined properly once call sites are updated +#if false && UPB_HAS_C_ATTRIBUTE(nodiscard) +#define UPB_NODISCARD [[nodiscard]] +#elif false && UPB_HAS_ATTRIBUTE(warn_unused_result) +#define UPB_NODISCARD __attribute__((warn_unused_result)) +#elif false && UPB_HAS_CPP_ATTRIBUTE(nodiscard) +#define UPB_NODISCARD [[nodiscard]] +#else +#define UPB_NODISCARD +#endif + +#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)(var) + +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. +#ifdef NDEBUG +#ifdef __GNUC__ +#define UPB_ASSUME(expr) \ + if (!(expr)) __builtin_unreachable() +#elif defined _MSC_VER +#define UPB_ASSUME(expr) \ + if (!(expr)) __assume(0) +#else +#define UPB_ASSUME(expr) \ + do { \ + } while (false && (expr)) +#endif +#else +#define UPB_ASSUME(expr) assert(expr) +#endif + +#if UPB_HAS_BUILTIN(__builtin_constant_p) && UPB_HAS_ATTRIBUTE(const) +#define UPB_MAYBE_ASSUME(pred, x) \ + if (__builtin_constant_p(pred) && pred) UPB_ASSUME(x) +#define UPB_ATTR_CONST __attribute__((const)) +#else +#define UPB_MAYBE_ASSUME(pred, x) +#define UPB_ATTR_CONST +#endif + +/* UPB_ASSERT(): in release mode, we use the expression without letting it be + * evaluated. This prevents "unused variable" warnings. */ +#ifdef NDEBUG +#define UPB_ASSERT(expr) \ + do { \ + } while (false && (expr)) +#else +#define UPB_ASSERT(expr) assert(expr) +#endif + +#if !defined(NDEBUG) && !defined(UPB_TSAN) +#define UPB_ENABLE_REF_CYCLE_CHECKS 1 +#else +#define UPB_ENABLE_REF_CYCLE_CHECKS 0 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define UPB_PRETTY_FUNCTION NULL +#endif + +#ifdef __cplusplus + extern "C" { +#endif + UPB_NORETURN void _upb_UnreachableFailure(const char* file, int line, + const char* function_name); +#if !defined(NDEBUG) +#define UPB_UNREACHABLE_FAILURE() \ + _upb_UnreachableFailure(__FILE__, __LINE__, UPB_PRETTY_FUNCTION); +#else +#define UPB_UNREACHABLE_FAILURE() +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + __assume(0); \ + } while (0) +#else +#define UPB_UNREACHABLE() \ + do { \ + UPB_UNREACHABLE_FAILURE(); \ + } while (0) +#endif + +#ifdef __ANDROID__ +#define UPB_DEFAULT_MAX_BLOCK_SIZE 8192 +#else +#define UPB_DEFAULT_MAX_BLOCK_SIZE 32768 +#endif + +/* UPB_SETJMP() / UPB_LONGJMP() */ +// Android uses a custom libc that does not implement all of posix, but it has +// had sigsetjmp/siglongjmp forever on arm and since API 12 on x86. Apple has +// sigsetjmp, but does not define the posix feature test macro. +#if defined(__APPLE__) || defined(_POSIX_C_SOURCE) || defined(__ANDROID__) +// avoid setting/restoring signal mask, which involves costly syscalls +#define UPB_SETJMP(buf) sigsetjmp(buf, 0) +#define UPB_LONGJMP(buf, val) siglongjmp(buf, val) +#elif defined(WASM_WAMR) +#define UPB_SETJMP(buf) 0 +#define UPB_LONGJMP(buf, val) abort() +#else +#define UPB_SETJMP(buf) setjmp(buf) +#define UPB_LONGJMP(buf, val) longjmp(buf, val) +#endif + +#if ((__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)) || \ + UPB_HAS_EXTENSION(c_atomic) || \ + defined(__GNUC__) // GCC supported atomics as an extension before it + // supported __has_extension +#define UPB_USE_C11_ATOMICS +#elif defined(_MSC_VER) +#define UPB_USE_MSC_ATOMICS +#endif + +#if defined(UPB_USE_C11_ATOMICS) +#define UPB_ATOMIC(T) _Atomic(T) +#elif defined(UPB_USE_MSC_ATOMICS) +#define UPB_ATOMIC(T) volatile T +#else +#define UPB_ATOMIC(T) T +#endif + +/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ +#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) + +#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only + +#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY +#define UPB_ONLYBITS(x) x +#else +#define UPB_ONLYBITS(x) UPB_PRIVATE(x) +#endif + +/* Configure whether fasttable is switched on or not. *************************/ + +#if UPB_HAS_ATTRIBUTE(musttail) +#define UPB_MUSTTAIL __attribute__((musttail)) +#else +#define UPB_MUSTTAIL +#endif + +#if UPB_HAS_ATTRIBUTE(preserve_most) && !defined(__i386__) +#define UPB_PRESERVE_MOST __attribute__((preserve_most)) +#else +#define UPB_PRESERVE_MOST +#endif + +#if UPB_HAS_ATTRIBUTE(preserve_none) +#define UPB_PRESERVE_NONE __attribute__((preserve_none)) +#else +#define UPB_PRESERVE_NONE +#endif + +#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) +#define UPB_ARM64_ASM 1 +#else +#define UPB_ARM64_ASM 0 +#endif + +/* When compiling with branch protection, we need to ensure that all branch + * targets in assembly use the appropriate landing pad instruction. These + * instructions are backwards compatible with processors that don't have + * FEAT_BTI and are treated as nops. + */ +#if UPB_ARM64_ASM && defined(__ARM_FEATURE_BTI_DEFAULT) +#if __ARM_FEATURE_BTI_DEFAULT == 1 +#define UPB_ARM64_BTI_DEFAULT 1 +#else +#define UPB_ARM64_BTI_DEFAULT 0 +#endif +#else +#define UPB_ARM64_BTI_DEFAULT 0 +#endif + +/* aarch64 supports big and little endian modes; fasttable performs multibyte + * tag loads assumes the tag of a varint is in the low bits. */ +#if (defined(__x86_64__) || defined(__AARCH64EL__)) && \ + UPB_HAS_ATTRIBUTE(preserve_none) && UPB_HAS_ATTRIBUTE(musttail) +#define UPB_FASTTABLE_SUPPORTED 1 +#else +#define UPB_FASTTABLE_SUPPORTED 0 +#endif + +/* define UPB_ENABLE_FASTTABLE to force fast table support. + * This is useful when we want to ensure we are really getting fasttable, + * for example for testing or benchmarking. */ +#if defined(UPB_ENABLE_FASTTABLE) +#if !UPB_FASTTABLE_SUPPORTED +#error fasttable is x86-64/ARM64le only and requires preserve_none and musttail. +#endif +#define UPB_FASTTABLE 1 +/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. + * This is useful for releasing code that might be used on multiple platforms, + * for example the PHP or Ruby C extensions. */ +#elif defined(UPB_TRY_ENABLE_FASTTABLE) +#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED +#else +#define UPB_FASTTABLE 0 +#endif + +/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully + * degrade to non-fasttable if the runtime or platform do not support it. */ +#if !UPB_FASTTABLE +#define UPB_FASTTABLE_INIT(...) +#define UPB_FASTTABLE_MASK(mask) -1 +#else +#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ +#define UPB_FASTTABLE_MASK(mask) mask +#endif + +#undef UPB_FASTTABLE_SUPPORTED + +#if defined(__cplusplus) +#if defined(__clang__) || UPB_GNUC_MIN(6, 0) +// https://gcc.gnu.org/gcc-6/changes.html +#define UPB_DEPRECATED [[deprecated]] +#else +#define UPB_DEPRECATED +#endif +#else +#define UPB_DEPRECATED +#endif + +#if defined(UPB_IS_GOOGLE3) && \ + (!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_IS_GOOGLE3) && defined(UPB_BOOTSTRAP_STAGE) && \ + UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC_MINITABLE(sym) proto2__##sym##_msg_init() +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() +#else +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init +#endif + +#undef UPB_IS_GOOGLE3 + +#ifdef __clang__ +#define UPB_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address"))) +#else +#define UPB_NO_SANITIZE_ADDRESS +#endif + +#if defined(__GNUC__) && (defined(__clang__) || UPB_GNUC_MIN(11, 0)) +#define UPB_RETAIN __attribute__((retain)) +#else +#define UPB_RETAIN +#endif + +// Linker arrays combine elements from multiple translation units into a single +// array that can be iterated over at runtime. +// +// It is an alternative to pre-main "registration" functions. +// +// Usage: +// +// // In N translation units. +// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; +// +// // At runtime: +// UPB_LINKARR_DECLARE(foo_array, int); +// +// void f() { +// const int* start = UPB_LINKARR_START(foo_array); +// const int* stop = UPB_LINKARR_STOP(foo_array); +// for (const int* p = start; p < stop; p++) { +// // Windows can introduce zero padding, so we have to skip zeroes. +// if (*p != 0) { +// vec.push_back(*p); +// } +// } +// } + +#if defined(__GNUC__) && !defined(__clang__) +// GCC can't handle mismatched retain attributes in the same section: +// https://github.com/protocolbuffers/protobuf/issues/26385 +// To work around this, we retain all linker array elements, even though this +// effectively disables tree-shaking of unused extensions when using GCC. +#define UPB_LINKARR_ATTR UPB_RETAIN +#else +#define UPB_LINKARR_ATTR +#endif + +#define UPB_LINKARR_SENTINEL UPB_RETAIN __attribute__((weak, used)) + +#if defined(__ELF__) || defined(__wasm__) + +#define UPB_LINKARR_APPEND(name) \ + __attribute__(( \ + section("linkarr_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)"); \ + extern type __start_linkarr_##name; \ + extern type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) \ + UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(__MACH__) + +/* As described in: https://stackoverflow.com/a/22366882 */ +#define UPB_LINKARR_APPEND(name) \ + __attribute__(( \ + section("__DATA,__la_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)"); \ + extern type __start_linkarr_##name __asm( \ + "section$start$__DATA$__la_" #name); \ + extern type __stop_linkarr_##name __asm( \ + "section$end$__DATA$" \ + "__la_" #name); \ + UPB_LINKARR_APPEND(name) \ + UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#elif defined(_MSC_VER) + +/* See: + * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 + * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 + * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ +#define UPB_STRINGIFY_INTERNAL(x) #x +#define UPB_STRINGIFY(x) UPB_STRINGIFY_INTERNAL(x) +#define UPB_CONCAT(a, b, c) a##b##c +#define UPB_LINKARR_NAME(name, index) \ + UPB_STRINGIFY(UPB_CONCAT(la_, name, index)) +#define UPB_LINKARR_APPEND(name) \ + __pragma(section(UPB_LINKARR_NAME(name, $j), read)) \ + __declspec(allocate(UPB_LINKARR_NAME(name, $j))) +// clang-format off +#define UPB_LINKARR_DECLARE(name, type) \ + __pragma(message(UPB_LINKARR_NAME(name, $j))) \ + __pragma(section(UPB_LINKARR_NAME(name, $a), read)) \ + __pragma(section(UPB_LINKARR_NAME(name, $z), read)) \ + __declspec(allocate(UPB_LINKARR_NAME(name, $a)), selectany) \ + type __start_linkarr_##name; \ + __declspec(allocate(UPB_LINKARR_NAME(name, $z)), selectany) \ + type __stop_linkarr_##name; \ + UPB_LINKARR_APPEND(name) \ + __declspec(selectany) type UPB_linkarr_internal_empty_##name[1] = {0} +// clang-format on +#define UPB_LINKARR_START(name) (&__start_linkarr_##name) +#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) + +#else + +// Linker arrays are not supported on this platform. Make macros no-ops. +#define UPB_LINKARR_APPEND(name) +#define UPB_LINKARR_DECLARE(name, type) \ + UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ + "Linker array name too long for Mach-O (16-char limit)") +#define UPB_LINKARR_START(name) (NULL) +#define UPB_LINKARR_STOP(name) (NULL) + +#endif + +// Workaround for https://github.com/llvm/llvm-project/issues/167577 until it's +// fixed. Some function must exist for the constructor to work properly. +// TODO Remove this or gate it on a future version of clang. +#if defined(__clang__) && defined(__arm__) +#define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((used, visibility("hidden"))) void UPB_PRIVATE(unique_name)( \ + void) {} +#else +#define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) +#endif + +#define _UPB_STRINGIFY2(x) #x +#define _UPB_STRINGIFY(x) _UPB_STRINGIFY2(x) + +#if defined(__ELF__) && (UPB_GNUC_MIN(15, 1) || UPB_CLANG_MIN(21, 1)) +/* + * Workaround for b/456308964 and b/456317163. Although weak constructors + * resolve to a single function body, Clang still emits a pointer into + * .init_array for every translation unit, causing the constructor to be + * executed multiple times and inflating binary size. We wrap the .init_array + * entry in a COMDAT group (using inline assembly) to force the linker to + * deduplicate the pointer to exactly one instance. %cc is used in preference to + * the more widely available %c because %c may under some circumstances still + * output a function name including relocation information, which will then + * confuse the linker. This was only a problem on gcc; when %cc was introduced + * to clang it was just an alias to %c, and clang's %c had already done the + * checks that %cc introduced to gcc. + * References: + * https://github.com/gcc-mirror/gcc/commit/74d6a676034b3ab20c387f12f19f5597e4f1c9fa + * https://github.com/llvm/llvm-project/pull/127719#issuecomment-2686276305 + */ +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((weak, used, visibility("hidden"))) void UPB_PRIVATE(name)( \ + void) { \ + __asm__ volatile( \ + ".pushsection .init_array,\"awG\",%%init_array, %cc0, comdat\n" \ + ".dc.a %cc0\n" \ + ".popsection\n" \ + : \ + : "X"(UPB_PRIVATE(name))); \ + __VA_ARGS__ \ + } +#elif defined(__ELF__) || defined(__wasm__) || defined(__MACH__) || \ + defined(__MINGW32__) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ + __attribute__((weak, visibility("hidden"), constructor)) void UPB_PRIVATE( \ + name)(void) { \ + __VA_ARGS__ \ + } +#elif defined(_MSC_VER) +/* + * See: https://stackoverflow.com/questions/1113409 + * + * The /include pragma suggested in the link above doesn't work in our case + * because it requires globally unique names. We need a different solution + * to prevent optimizers from removing the constructor. Our solution is to + * create a dummy exported weak symbol that prevent this stripping. + */ +#pragma section(".CRT$XCT", read) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static void __cdecl UPB_PRIVATE(name)(void); \ + __declspec(allocate(".CRT$XCT"), selectany) void( \ + __cdecl * UPB_PRIVATE(name##_))(void) = UPB_PRIVATE(name); \ + __declspec(selectany, dllexport) void* UPB_PRIVATE(name##_force_linkage) = \ + &UPB_PRIVATE(name##_); \ + static void __cdecl UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#else +// No constructor support, nothing we can do except not break builds. +#if defined(__GNUC__) || defined(__clang__) +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static __attribute__((used)) void UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#else +#define UPB_CONSTRUCTOR(name, unique_name, ...) \ + static void UPB_PRIVATE(name)(void) { __VA_ARGS__ } +#endif +#endif + +// +// Weak alias platform support. Theoretically this should be possible to do with +// only C using attributes like __attribute__((weak, alias("foo"))), but +// Clang doesn't support this properly on macOS. So we have to use assembly. +#if defined(__APPLE__) + +// TODO: once https://github.com/llvm/llvm-project/issues/167262 is fixed +// in the LLVM linker, we should have all weak variables point to a single +// "default" empty MiniTable instead of having each leaf define its own, like +// we do with ELF below. This will reduce binary size if many messages are tree +// shaken. +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) \ + __attribute__((weak)) const upb_MiniTable name = { \ + .UPB_PRIVATE(fields) = NULL, \ + .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ + .UPB_PRIVATE(field_count) = 0, \ + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ + .UPB_PRIVATE(dense_below) = 0, \ + .UPB_PRIVATE(table_mask) = -1, \ + .UPB_PRIVATE(required_count) = 0, \ + }; +#define UPB_WEAK_ALIAS(type, from, to) \ + extern type to; \ + __asm__(".globl _" #to); \ + __asm__(".private_extern _" #to); \ + __asm__(".set _" #to ", _" #from); \ + __asm__(".weak_definition _" #to); +#define UPB_STRONG_ALIAS(type, from, to) \ + __asm__(".globl _" #to); \ + __asm__(".private_extern _" #to); \ + __asm__(".set _" #to ", _" #from); + +#elif defined(__ELF__) || defined(__wasm__) + + // On ELF, weak aliases work properly, so we can have all weak MiniTables + // point to the same empty singleton MiniTable. This reduces code size if many + // MiniTables are tree shaken. +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() \ + __attribute__((weak)) \ + const upb_MiniTable kUpb_WeakSingletonPlaceholderMiniTable = { \ + .UPB_PRIVATE(fields) = NULL, \ + .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ + .UPB_PRIVATE(field_count) = 0, \ + .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ + .UPB_PRIVATE(dense_below) = 0, \ + .UPB_PRIVATE(table_mask) = -1, \ + .UPB_PRIVATE(required_count) = 0, \ + }; +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) +#define UPB_WEAK_ALIAS(type, from, to) \ + extern type to \ + __attribute__((weak, alias("kUpb_WeakSingletonPlaceholderMiniTable"))); +#define UPB_STRONG_ALIAS(type, from, to) \ + extern type to __attribute__((alias(#from))); + +#else +#define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() +#define UPB_WEAK_PLACEHOLDER_MINITABLE(name) +#define UPB_WEAK_ALIAS(type, from, to) weak_alias_not_supported_on_this_platform +#define UPB_STRONG_ALIAS(type, from, to) \ + strong_alias_not_supported_on_this_platform + +#endif + +#ifndef UPB_GENERATED_CODE_SUPPORT_H_ +#define UPB_GENERATED_CODE_SUPPORT_H_ + +// This is a bit awkward; we want to conditionally include the fast decoder, +// but we generally don't let macros like UPB_FASTTABLE leak into user code. +// We can't #include "decode_fast.h" inside the port/def.inc, because the +// inc files strictly prohibit recursive inclusion, and decode_fast.h includes +// port/def.inc. So instead we use this two-part dance to conditionally include +// decode_fast.h. +#if UPB_FASTTABLE +#define UPB_INCLUDE_FAST_DECODE +#endif + +// IWYU pragma: begin_exports + +#ifndef UPB_BASE_UPCAST_H_ +#define UPB_BASE_UPCAST_H_ + +// Must be last. + +// This macro provides a way to upcast message pointers in a way that is +// somewhat more bulletproof than blindly casting a pointer. Example: +// +// typedef struct { +// upb_Message UPB_PRIVATE(base); +// } pkg_FooMessage; +// +// void f(pkg_FooMessage* msg) { +// upb_Decode(UPB_UPCAST(msg), ...); +// } + +#define UPB_UPCAST(x) (&(x)->base##_dont_copy_me__upb_internal_use_only) + + +#endif /* UPB_BASE_UPCAST_H_ */ + +#ifndef UPB_MESSAGE_ACCESSORS_H_ +#define UPB_MESSAGE_ACCESSORS_H_ + +#include + +#ifndef UPB_BASE_STRING_VIEW_H_ +#define UPB_BASE_STRING_VIEW_H_ + +#include + +// Must be last. + +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } + +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data + +// LINT.IfChange(struct_definition) +typedef struct { + const char* data; + size_t size; +} upb_StringView; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} + +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} + +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return (a.size == b.size) && (!a.size || !memcmp(a.data, b.data, a.size)); +} + +// Compares StringViews following strcmp rules. +// Please note this comparison is neither unicode nor locale aware. +UPB_INLINE int upb_StringView_Compare(upb_StringView a, upb_StringView b) { + int result = memcmp(a.data, b.data, UPB_MIN(a.size, b.size)); + if (result != 0) return result; + if (a.size < b.size) { + return -1; + } else if (a.size > b.size) { + return 1; + } else { + return 0; + } +} + +// LINT.ThenChange( +// GoogleInternalName1, +// //depot/google3/third_party/upb/bits/golang/accessor.go:map_go_string, +// //depot/google3/third_party/upb/bits/typescript/string_view.ts +// ) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STRING_VIEW_H_ */ + +/* upb_Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb_Arena is *not* thread-safe, although some functions related to its + * managing its lifetime are, and are documented as such. + * + * You could write a thread-safe arena allocator that satisfies the + * upb_alloc interface, but it would not be as efficient for the + * single-threaded case. */ + +#ifndef UPB_MEM_ARENA_H_ +#define UPB_MEM_ARENA_H_ + +#include +#include + + +#ifndef UPB_MEM_ALLOC_H_ +#define UPB_MEM_ALLOC_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct upb_alloc upb_alloc; + +/* A combined `malloc()`/`free()` function. + * If `size` is 0 then the function acts like `free()`, otherwise it acts like + * `realloc()`. Only `oldsize` bytes from a previous allocation are + * preserved. If `actual_size` is not null and the allocator supports it, the + * actual size of the resulting allocation is stored in `actual_size`. If + * `actual_size` is not null, you must zero out the memory pointed to by + * `actual_size` before calling. */ +typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size, size_t* actual_size); + +/* A upb_alloc is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * `free()` calls) or a regular `malloc()` (which does). The client must + * therefore free memory unless it knows that the allocator is an arena + * allocator. */ +struct upb_alloc { + upb_alloc_func* func; +}; + +UPB_NODISCARD UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, NULL, 0, size, NULL); +} + +typedef struct { + void* p; + size_t n; +} upb_SizedPtr; + +UPB_INLINE upb_SizedPtr upb_SizeReturningMalloc(upb_alloc* alloc, size_t size) { + UPB_ASSERT(alloc); + upb_SizedPtr result; + result.n = 0; + result.p = alloc->func(alloc, NULL, 0, size, &result.n); + result.n = result.p != NULL ? UPB_MAX(result.n, size) : 0; + return result; +} + +UPB_NODISCARD UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, + size_t oldsize, size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, ptr, oldsize, size, NULL); +} + +UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { + UPB_ASSERT(alloc); + alloc->func(alloc, ptr, 0, 0, NULL); +} + +UPB_INLINE void upb_free_sized(upb_alloc* alloc, void* ptr, size_t size) { + UPB_ASSERT(alloc); + alloc->func(alloc, ptr, size, 0, NULL); +} + +// The global allocator used by upb. Uses the standard malloc()/free(). + +extern upb_alloc upb_alloc_global; + +/* Functions that hard-code the global malloc. + * + * We still get benefit because we can put custom logic into our global + * allocator, like injecting out-of-memory faults in debug/testing builds. */ + +UPB_NODISCARD UPB_INLINE void* upb_gmalloc(size_t size) { + return upb_malloc(&upb_alloc_global, size); +} + +UPB_NODISCARD UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, + size_t size) { + return upb_realloc(&upb_alloc_global, ptr, oldsize, size); +} + +UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_ALLOC_H_ */ + +#ifndef UPB_MEM_INTERNAL_ARENA_H_ +#define UPB_MEM_INTERNAL_ARENA_H_ + +#include +#include +#include + + +#ifndef UPB_PORT_SANITIZERS_H_ +#define UPB_PORT_SANITIZERS_H_ + +#include +#include +#include + +// Must be last. + +// Must be inside def.inc/undef.inc +#if UPB_HWASAN +#include +#endif + +#if UPB_MSAN +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// UPB_ARENA_SIZE_HACK depends on this struct having size 1. +typedef struct { + uint8_t state; +} upb_Xsan; + +UPB_INLINE uint8_t _upb_Xsan_NextTag(upb_Xsan *xsan) { +#if UPB_HWASAN + xsan->state++; + if (xsan->state <= UPB_HWASAN_POISON_TAG) { + xsan->state = UPB_HWASAN_POISON_TAG + 1; + } + return xsan->state; +#else + UPB_UNUSED(xsan); + return 0; +#endif +} + +enum { +#if UPB_ASAN + UPB_PRIVATE(kUpb_Asan_GuardSize) = 32, +#else + UPB_PRIVATE(kUpb_Asan_GuardSize) = 0, +#endif +}; + +UPB_INLINE uint8_t UPB_PRIVATE(_upb_Xsan_GetTag)(const void *addr) { +#if UPB_HWASAN + return __hwasan_get_tag_from_pointer(addr); +#else + UPB_UNUSED(addr); + return 0; +#endif +} + +UPB_INLINE void UPB_PRIVATE(upb_Xsan_Init)(upb_Xsan *xsan) { +#if UPB_HWASAN || UPB_TSAN + xsan->state = 0; +#else + UPB_UNUSED(xsan); +#endif +} + +UPB_INLINE void UPB_PRIVATE(upb_Xsan_MarkInitialized)(void* addr, size_t size) { +#if UPB_HAS_FEATURE(memory_sanitizer) + if (size) { + __msan_unpoison(addr, size); + } +#else + UPB_UNUSED(addr); + UPB_UNUSED(size); +#endif +} + +// Marks the given region as poisoned, meaning that it is not accessible until +// it is unpoisoned. +UPB_INLINE void UPB_PRIVATE(upb_Xsan_PoisonRegion)(const void *addr, + size_t size) { +#if UPB_ASAN + void __asan_poison_memory_region(void const volatile *addr, size_t size); + __asan_poison_memory_region(addr, size); +#elif UPB_HWASAN + __hwasan_tag_memory(addr, UPB_HWASAN_POISON_TAG, UPB_ALIGN_MALLOC(size)); +#else + UPB_UNUSED(addr); + UPB_UNUSED(size); +#endif +} + +UPB_INLINE void *UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)(void *addr, size_t size, + uint8_t tag) { +#if UPB_ASAN + UPB_UNUSED(tag); + void __asan_unpoison_memory_region(void const volatile *addr, size_t size); + __asan_unpoison_memory_region(addr, size); + return addr; +#elif UPB_HWASAN + __hwasan_tag_memory(addr, tag, UPB_ALIGN_MALLOC(size)); + return __hwasan_tag_pointer(addr, tag); +#else + UPB_UNUSED(size); + UPB_UNUSED(tag); + + // `addr` is the pointer that will be returned from arena alloc/realloc + // functions. In this code-path we know it must be non-NULL, but the compiler + // doesn't know this unless we add a UPB_ASSUME() annotation. + // + // This will let the optimizer optimize away NULL-checks if it can see that + // this path was taken. + UPB_ASSUME(addr); + return addr; +#endif +} + +// Allows users to read and write to the given region, which will be considered +// distinct from other regions and may only be accessed through the returned +// pointer. +// +// `addr` must be aligned to the malloc alignment. Size may be unaligned, +// and with ASAN we can respect `size` precisely, but with HWASAN we must +// round `size` up to the next multiple of the malloc alignment, so the caller +// must guarantee that rounding up `size` will not cause overlap with other +// regions. +UPB_INLINE void *UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(upb_Xsan *xsan, + void *addr, + size_t size) { + return UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)(addr, size, + _upb_Xsan_NextTag(xsan)); +} + +// Resizes the given region to a new size, *without* invalidating any existing +// pointers to the region. +// +// `tagged_addr` must be a pointer that was previously returned from +// `upb_Xsan_NewUnpoisonedRegion`. `old_size` must be the size that was +// originally passed to `upb_Xsan_NewUnpoisonedRegion`. +UPB_INLINE void *UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(void *tagged_addr, + size_t old_size, + size_t new_size) { + UPB_PRIVATE(upb_Xsan_PoisonRegion)(tagged_addr, old_size); + return UPB_PRIVATE(_upb_Xsan_UnpoisonRegion)( + tagged_addr, new_size, UPB_PRIVATE(_upb_Xsan_GetTag)(tagged_addr)); +} + +// Compares two pointers and returns true if they are equal. This returns the +// correct result even if one or both of the pointers are tagged. +UPB_INLINE bool UPB_PRIVATE(upb_Xsan_PtrEq)(const void *a, const void *b) { +#if UPB_HWASAN + return __hwasan_tag_pointer(a, 0) == __hwasan_tag_pointer(b, 0); +#else + return a == b; +#endif +} + +// These annotations improve TSAN's ability to detect data races. By +// proactively accessing a non-atomic variable at the point where it is +// "logically" accessed, we can trigger TSAN diagnostics that might have +// otherwise been masked by subsequent atomic operations. + +UPB_INLINE void UPB_PRIVATE(upb_Xsan_AccessReadOnly)(upb_Xsan *xsan) { +#if UPB_TSAN + // For performance we avoid using a volatile variable. + __asm__ volatile("" ::"r"(xsan->state)); +#else + UPB_UNUSED(xsan); +#endif +} + +UPB_INLINE void UPB_PRIVATE(upb_Xsan_AccessReadWrite)(upb_Xsan *xsan) { +#if UPB_TSAN + // For performance we avoid using a volatile variable. + __asm__ volatile("" : "+r"(xsan->state)); +#else + UPB_UNUSED(xsan); +#endif +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_PORT_SANITIZERS_H_ + +// Must be last. + +// This is QUITE an ugly hack, which specifies the number of pointers needed +// to equal (or exceed) the storage required for one upb_Arena. +// +// We need this because the decoder inlines a upb_Arena for performance but +// the full struct is not visible outside of arena.c. Yes, I know, it's awful. +#ifndef NDEBUG +#define UPB_ARENA_BASE_SIZE_HACK 10 +#else +#define UPB_ARENA_BASE_SIZE_HACK 9 +#endif + +#define UPB_ARENA_SIZE_HACK \ + (sizeof(void*) * (UPB_ARENA_BASE_SIZE_HACK + (UPB_XSAN_STRUCT_SIZE * 2))) + \ + (sizeof(uint32_t) * 2) + +// LINT.IfChange(upb_Arena) + +struct upb_Arena { + char* UPB_ONLYBITS(ptr); + const UPB_NODEREF char* UPB_ONLYBITS(end); + UPB_XSAN_MEMBER +}; + +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/arena.ts:upb_Arena) + +#ifdef __cplusplus +extern "C" { +#endif + +void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des, + const struct upb_Arena* src); +void UPB_PRIVATE(_upb_Arena_SwapOut)(struct upb_Arena* des, + const struct upb_Arena* src); + +UPB_INLINE size_t UPB_PRIVATE(_upb_ArenaHas)(const struct upb_Arena* a) { + return (size_t)(a->UPB_ONLYBITS(end) - a->UPB_ONLYBITS(ptr)); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_Arena_AllocSpan)(size_t size) { + return UPB_ALIGN_MALLOC(size) + UPB_PRIVATE(kUpb_Asan_GuardSize); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)( + const struct upb_Arena* a, void* ptr, size_t size) { + return UPB_PRIVATE(upb_Xsan_PtrEq)( + (char*)ptr + UPB_PRIVATE(_upb_Arena_AllocSpan)(size), + a->UPB_ONLYBITS(ptr)); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Arena_IsAligned)(const void* ptr) { + return (uintptr_t)ptr % UPB_MALLOC_ALIGN == 0; +} + +UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + + size_t span = UPB_PRIVATE(_upb_Arena_AllocSpan)(size); + + if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) { + void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(struct upb_Arena * a, size_t size); + return UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span); + } + + // We have enough space to do a fast malloc. + void* ret = a->UPB_ONLYBITS(ptr); + a->UPB_ONLYBITS(ptr) += span; + UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(ret)); + UPB_ASSERT(UPB_PRIVATE(_upb_Arena_IsAligned)(a->UPB_ONLYBITS(ptr))); + + return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size); +} + +UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + UPB_ASSERT(ptr); + UPB_ASSERT(size <= oldsize); + + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(ptr, oldsize, size); + + if (UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize)) { + // We can reclaim some memory. + a->UPB_ONLYBITS(ptr) -= UPB_ALIGN_MALLOC(oldsize) - UPB_ALIGN_MALLOC(size); + } else { + // We can't reclaim any memory, but we need to verify that `ptr` really + // does represent the most recent allocation. +#ifndef NDEBUG + bool _upb_Arena_WasLastAllocFromPreviousBlock(struct upb_Arena * a, + void* ptr, size_t oldsize); + UPB_ASSERT(_upb_Arena_WasLastAllocFromPreviousBlock(a, ptr, oldsize)); +#endif + } +} + +UPB_API_INLINE bool upb_Arena_TryExtend(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + UPB_ASSERT(ptr); + UPB_ASSERT(size > oldsize); + + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + size_t extend = UPB_ALIGN_MALLOC(size) - UPB_ALIGN_MALLOC(oldsize); + + if (UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize) && + UPB_PRIVATE(_upb_ArenaHas)(a) >= extend) { + a->UPB_ONLYBITS(ptr) += extend; + UPB_PRIVATE(upb_Xsan_ResizeUnpoisonedRegion)(ptr, oldsize, size); + return true; + } + + return false; +} + +UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr, + size_t oldsize, size_t size) { + UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); + + void* ret; + + if (ptr && (size <= oldsize || upb_Arena_TryExtend(a, ptr, oldsize, size))) { + // We can extend or shrink in place. + if (size <= oldsize && + UPB_PRIVATE(_upb_Arena_WasLastAllocFromCurrentBlock)(a, ptr, oldsize)) { + upb_Arena_ShrinkLast(a, ptr, oldsize, size); + } + ret = ptr; + } else { + // We need to copy into a new allocation. + ret = upb_Arena_Malloc(a, size); + if (ret && oldsize > 0) { + memcpy(ret, ptr, UPB_MIN(oldsize, size)); + } + } + + if (ret) { + // We want to invalidate pointers to the old region if hwasan is enabled, so + // we poison and unpoison even if ptr == ret. However, if reallocation fails + // we do not want to poison the old memory, or attempt to poison null. + UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, oldsize); + return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ret, size); + } + return ret; +} + +// Returns the next block size to allocate for the arena based on exponential +// growth and size hint. +size_t UPB_PRIVATE(_upb_Arena_NextBlockSize)(struct upb_Arena* a, size_t span, + bool* one_off); + +// Updates the arena's growth state based on the block size actually allocated. +void UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(struct upb_Arena* a, size_t span, + size_t block_size, bool one_off); + +// Allocates a block for the arena of at least the given size, but does not add +// it to the arena. The block must either be added to the arena or manually +// freed, otherwise memory will be leaked. +// +// Returns the allocated block (or NULL on failure), and writes the actual size +// of the block to size. +void* UPB_PRIVATE(_upb_Arena_AllocBlock)(struct upb_Arena* a, size_t* size); + +// Adds a block previously allocated with _upb_Arena_AllocBlock() to the arena. +// This will cause it to be owned by the arena and freed when the arena is +// freed. +// +// Note that this call does *not* cause the block to be used for arena +// allocations. Call _upb_Arena_UseBlock() to do that. +// +// This operation cannot be undone, so the caller should not call it until they +// are sure that the block will be useful to the arena. +void UPB_PRIVATE(_upb_Arena_AddBlock)(struct upb_Arena* a, void* block); + +// Frees a block previously allocated with _upb_Arena_AllocBlock. This is only +// necessary if the block ends up not being useful to the arena. +void UPB_PRIVATE(_upb_Arena_FreeBlock)(struct upb_Arena* a, void* block); + +// Sets the arena's current block to the given block. Subsequent allocations +// may be made from this block. +// +// The given memory must be either: +// - The arena block most recently returned by _upb_Arena_AllocBlock, or +// - A block that was just stolen from the arena using _upb_Arena_Steal. +// +// After this call, the memory may only be used by the arena -- it is poisoned +// against further use by the caller. +// +// Note: if the arena determines that this block is smaller than the block it +// currently has, it may decide to not use the block. +void UPB_PRIVATE(_upb_Arena_UseBlock)(struct upb_Arena* a, void* ptr, + size_t size); + +// Steals all available memory from the current arena block, but only if at +// least `size` bytes are available. The number of bytes stolen is written to +// size. The memory will be unpoisoned and ready for use. +void* UPB_PRIVATE(_upb_Arena_Steal)(struct upb_Arena* a, size_t* size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_INTERNAL_ARENA_H_ */ + +// Must be last. + +typedef struct upb_Arena upb_Arena; + +typedef void upb_AllocCleanupFunc(upb_alloc* alloc); + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates an arena from the given initial block (if any -- mem may be NULL). If +// an initial block is specified, the arena's lifetime cannot be extended by +// |upb_Arena_IncRefFor| or |upb_Arena_Fuse|. Additional blocks will be +// allocated from |alloc|. If |alloc| is NULL, this is a fixed-size arena and +// cannot grow. If an initial block is specified, |n| is its length; if there is +// no initial block, |n| is a hint of the size that should be allocated for the +// first block of the arena, such that `upb_Arena_Malloc(hint)` will not require +// another call to |alloc|. +UPB_NODISCARD UPB_API upb_Arena* upb_Arena_Init(void* mem, size_t n, + upb_alloc* alloc); + +UPB_API void upb_Arena_Free(upb_Arena* a); +// Sets the cleanup function for the upb_alloc used by the arena. Only one +// cleanup function can be set, which will be called after all blocks are +// freed. +UPB_API void upb_Arena_SetAllocCleanup(upb_Arena* a, + upb_AllocCleanupFunc* func); + +// Fuses the lifetime of two arenas, such that no arenas that have been +// transitively fused together will be freed until all of them have reached a +// zero refcount. This operation is safe to use concurrently from multiple +// threads. +UPB_NODISCARD UPB_API bool upb_Arena_Fuse(const upb_Arena* a, + const upb_Arena* b); + +// This operation is safe to use concurrently from multiple threads. +UPB_API bool upb_Arena_IsFused(const upb_Arena* a, const upb_Arena* b); + +// Returns the upb_alloc used by the arena. +UPB_API upb_alloc* upb_Arena_GetUpbAlloc(upb_Arena* a); + +// This operation is safe to use concurrently from multiple threads. +bool upb_Arena_IncRefFor(const upb_Arena* a, const void* owner); +// This operation is safe to use concurrently from multiple threads. +void upb_Arena_DecRefFor(const upb_Arena* a, const void* owner); + +// Creates a reference between the arenas `from` and `to`, guaranteeing that +// the latter will not be freed until `from` is freed. +// +// Users must avoid all of the following error conditions, which will be +// checked in debug mode but are UB in opt: +// +// - Creating reference cycles between arenas. +// - Creating a reference between two arenas that are fused, either now +// or in the future. +// +// Creating a reference multiple times between the same two arenas is not UB but +// is considered wasteful and may be disallowed in the future. +// +// Note that fuses can participate in reference cycles. The following set of +// calls creates a cycle A -> B -> C -> A +// Fuse(A, B); +// Ref(B, C); +// Ref(C, A); +// +// From this perspective, the second rule is just a special-case of the first. +// This set of calls is disallowed because it is effectively creating a +// cycle A -> B -> A +// Fuse(A, B); +// Ref(B, A); +// +// Fuse is special because it creates what is effectively a bidirectional +// ref, but it is not considered a cycle and will be collected correctly. +// +// Note that `from` is not `const`, so it may not be called concurrently +// with any other function on `from`. +// +// Returns whether the reference was created successfully. +UPB_NODISCARD bool upb_Arena_RefArena(upb_Arena* from, const upb_Arena* to); + +#ifndef NDEBUG +// Returns true if upb_Arena_RefArena(from, to) was previously called. +// Note that this does not take fuses into account, and it does not follow +// chains of references; it must have been these two arenas exactly that +// created a reference. +bool upb_Arena_HasRef(const upb_Arena* from, const upb_Arena* to); +#endif + +// This operation is safe to use concurrently from multiple threads. +uintptr_t upb_Arena_SpaceAllocated(const upb_Arena* a, size_t* fused_count); +// This operation is safe to use concurrently from multiple threads. +uint32_t upb_Arena_DebugRefCount(const upb_Arena* a); + +#if UPB_ENABLE_REF_CYCLE_CHECKS +// Returns true if there is a chain of arena refs that spans `from` -> `to`. +// Fused arenas are taken into account; for example, this series of calls +// will cause the function to return true: +// +// 1. upb_Arena_Fuse(a, b) +// 2. upb_Arena_RefArena(from, a) +// 3. upb_Arena_RefArena(b, to) +// +// However this function does not return true if `from` and `to` are directly +// fused. +bool upb_Arena_HasRefChain(const upb_Arena* from, const upb_Arena* to); +#endif + +UPB_NODISCARD UPB_API_INLINE upb_Arena* upb_Arena_New(void) { + return upb_Arena_Init(NULL, 0, &upb_alloc_global); +} + +UPB_NODISCARD UPB_API_INLINE upb_Arena* upb_Arena_NewSized(size_t size_hint) { + return upb_Arena_Init(NULL, size_hint, &upb_alloc_global); +} + +UPB_NODISCARD UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, + size_t size); + +UPB_NODISCARD UPB_API_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, + size_t oldsize, + size_t size); + +static const size_t UPB_PRIVATE(kUpbDefaultMaxBlockSize) = + UPB_DEFAULT_MAX_BLOCK_SIZE; + +// Sets the maximum block size for all arenas. This is a global configuration +// setting that will affect all existing and future arenas. If +// upb_Arena_Malloc() is called with a size larger than this, we will exceed +// this size and allocate a larger block. +// +// This API is meant for experimentation only. It will likely be removed in +// the future. +// This operation is safe to use concurrently from multiple threads. +void upb_Arena_SetMaxBlockSize(size_t max); + +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_API_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, + size_t oldsize, size_t size); + +// Attempts to extend the given alloc from arena, in place. Is generally +// only likely to succeed for the most recent allocation from this arena. If it +// succeeds, returns true and `ptr`'s allocation is now `size` rather than +// `oldsize`. Returns false if the allocation cannot be extended; `ptr`'s +// allocation is unmodified. See also upb_Arena_Realloc. +// REQUIRES: `size > oldsize`; to shrink, use `upb_Arena_Realloc` or +// `upb_Arena_ShrinkLast`. +UPB_NODISCARD UPB_API_INLINE bool upb_Arena_TryExtend(upb_Arena* a, void* ptr, + size_t oldsize, + size_t size); + +#ifdef UPB_TRACING_ENABLED +void upb_Arena_SetTraceHandler(void (*initArenaTraceHandler)(const upb_Arena*, + size_t size), + void (*fuseArenaTraceHandler)(const upb_Arena*, + const upb_Arena*), + void (*freeArenaTraceHandler)(const upb_Arena*)); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MEM_ARENA_H_ */ + +#ifndef UPB_MESSAGE_ARRAY_H_ +#define UPB_MESSAGE_ARRAY_H_ + +#include + + +#ifndef UPB_BASE_DESCRIPTOR_CONSTANTS_H_ +#define UPB_BASE_DESCRIPTOR_CONSTANTS_H_ + +// Must be last. + +// The types a field can have. Note that this list is not identical to the +// types defined in descriptor.proto, which gives INT32 and SINT32 separate +// types (we distinguish the two with the "integer encoding" enum below). +// This enum is an internal convenience only and has no meaning outside of upb. +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, // Enum values are int32. TODO: rename + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; + +// The repeated-ness of each field; this matches descriptor.proto. +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; + +// Descriptor types, as defined in descriptor.proto. +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#ifdef __cplusplus +extern "C" { +#endif + +// Convert from upb_FieldType to upb_CType +UPB_INLINE upb_CType upb_FieldType_CType(upb_FieldType field_type) { + static const upb_CType c_type[] = { + kUpb_CType_Double, // kUpb_FieldType_Double + kUpb_CType_Float, // kUpb_FieldType_Float + kUpb_CType_Int64, // kUpb_FieldType_Int64 + kUpb_CType_UInt64, // kUpb_FieldType_UInt64 + kUpb_CType_Int32, // kUpb_FieldType_Int32 + kUpb_CType_UInt64, // kUpb_FieldType_Fixed64 + kUpb_CType_UInt32, // kUpb_FieldType_Fixed32 + kUpb_CType_Bool, // kUpb_FieldType_Bool + kUpb_CType_String, // kUpb_FieldType_String + kUpb_CType_Message, // kUpb_FieldType_Group + kUpb_CType_Message, // kUpb_FieldType_Message + kUpb_CType_Bytes, // kUpb_FieldType_Bytes + kUpb_CType_UInt32, // kUpb_FieldType_UInt32 + kUpb_CType_Enum, // kUpb_FieldType_Enum + kUpb_CType_Int32, // kUpb_FieldType_SFixed32 + kUpb_CType_Int64, // kUpb_FieldType_SFixed64 + kUpb_CType_Int32, // kUpb_FieldType_SInt32 + kUpb_CType_Int64, // kUpb_FieldType_SInt64 + }; + + // -1 here because the enum is one-based but the table is zero-based. + return c_type[field_type - 1]; +} + +UPB_INLINE bool upb_FieldType_IsPackable(upb_FieldType field_type) { + // clang-format off + const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << field_type) & ~kUnpackableTypes; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_DESCRIPTOR_CONSTANTS_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_ARRAY_H_ +#define UPB_MESSAGE_INTERNAL_ARRAY_H_ + +#include +#include + + +// Must be last. + +#define _UPB_ARRAY_MASK_IMM 0x4 // Frozen/immutable bit. +#define _UPB_ARRAY_MASK_LG2 0x3 // Encoded elem size. +#define _UPB_ARRAY_MASK_ALL (_UPB_ARRAY_MASK_IMM | _UPB_ARRAY_MASK_LG2) + +#ifdef __cplusplus +extern "C" { +#endif + +#define _UPB_ARRAY_DEFAULT_INITIAL_SIZE 4 + +// LINT.IfChange(upb_Array) + +// Our internal representation for repeated fields. +struct upb_Array { + // This is a tagged pointer. Bits #0 and #1 encode the elem size as follows: + // 0 maps to elem size 1 + // 1 maps to elem size 4 + // 2 maps to elem size 8 + // 3 maps to elem size 16 + // + // Bit #2 contains the frozen/immutable flag. + uintptr_t UPB_ONLYBITS(data); + + size_t UPB_ONLYBITS(size); // The number of elements in the array. + size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements. +}; + +UPB_INLINE void UPB_PRIVATE(_upb_Array_ShallowFreeze)(struct upb_Array* arr) { + arr->UPB_ONLYBITS(data) |= _UPB_ARRAY_MASK_IMM; +} + +UPB_API_INLINE bool upb_Array_IsFrozen(const struct upb_Array* arr) { + return (arr->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_IMM) != 0; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array, + void* data, size_t lg2) { + UPB_ASSERT(lg2 != 1); + UPB_ASSERT(lg2 <= 4); + const size_t bits = lg2 - (lg2 != 0); + array->UPB_ONLYBITS(data) = (uintptr_t)data | bits; +} + +UPB_INLINE size_t +UPB_PRIVATE(_upb_Array_ElemSizeLg2)(const struct upb_Array* array) { + const size_t bits = array->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_LG2; + const size_t lg2 = bits + (bits != 0); + return lg2; +} + +UPB_API_INLINE const void* upb_Array_DataPtr(const struct upb_Array* array) { + UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); // Check assertions. + return (void*)(array->UPB_ONLYBITS(data) & ~(uintptr_t)_UPB_ARRAY_MASK_ALL); +} + +UPB_API_INLINE void* upb_Array_MutableDataPtr(struct upb_Array* array) { + return (void*)upb_Array_DataPtr(array); +} + +UPB_NODISCARD UPB_INLINE struct upb_Array* UPB_PRIVATE( + _upb_Array_NewMaybeAllowSlow)(upb_Arena* arena, size_t init_capacity, + int elem_size_lg2, bool allow_slow) { + UPB_ASSERT(elem_size_lg2 != 1); + UPB_ASSERT(elem_size_lg2 <= 4); + const size_t array_size = + UPB_ALIGN_UP(sizeof(struct upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = array_size + (init_capacity << elem_size_lg2); + size_t span = UPB_PRIVATE(_upb_Arena_AllocSpan)(bytes); + if (!allow_slow && UPB_PRIVATE(_upb_ArenaHas)(arena) < span) return NULL; + struct upb_Array* array = (struct upb_Array*)upb_Arena_Malloc(arena, bytes); + if (!array) return NULL; + UPB_PRIVATE(_upb_Array_SetTaggedPtr) + (array, UPB_PTR_AT(array, array_size, void), (size_t)elem_size_lg2); + array->UPB_ONLYBITS(size) = 0; + array->UPB_PRIVATE(capacity) = init_capacity; + return array; +} + +UPB_NODISCARD UPB_INLINE struct upb_Array* UPB_PRIVATE(_upb_Array_New)( + upb_Arena* arena, size_t init_capacity, int elem_size_lg2) { + return UPB_PRIVATE(_upb_Array_NewMaybeAllowSlow)(arena, init_capacity, + elem_size_lg2, true); +} + +UPB_NODISCARD UPB_INLINE struct upb_Array* UPB_PRIVATE(_upb_Array_TryFastNew)( + upb_Arena* arena, size_t init_capacity, int elem_size_lg2) { + return UPB_PRIVATE(_upb_Array_NewMaybeAllowSlow)(arena, init_capacity, + elem_size_lg2, false); +} + +// Resizes the capacity of the array to be at least min_size. +UPB_NODISCARD bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, + size_t min_size, + upb_Arena* arena); + +UPB_NODISCARD UPB_FORCEINLINE bool UPB_PRIVATE(_upb_Array_TryFastRealloc)( + struct upb_Array* array, size_t capacity, int elem_size_lg2, + upb_Arena* arena) { + size_t old_bytes = array->UPB_PRIVATE(capacity) << elem_size_lg2; + size_t new_bytes = capacity << elem_size_lg2; + UPB_ASSUME(new_bytes > old_bytes); + if (!upb_Arena_TryExtend(arena, array, old_bytes, new_bytes)) return false; + array->UPB_PRIVATE(capacity) = capacity; + return true; +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, + size_t size, + upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + if (array->UPB_PRIVATE(capacity) < size) + return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena); + return true; +} + +// Resize without initializing new elements. +UPB_NODISCARD UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + struct upb_Array* array, size_t size, upb_Arena* arena) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + UPB_ASSERT(size <= array->UPB_ONLYBITS(size) || + arena); // Allow NULL arena when shrinking. + if (!upb_Array_Reserve(array, size, arena)) return false; + array->UPB_ONLYBITS(size) = size; + return true; +} + +// This function is intended for situations where elem_size is compile-time +// constant or a known expression of the form (1 << lg2), so that the expression +// i*elem_size does not result in an actual multiplication. +UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i, + const void* data, + size_t elem_size) { + UPB_ASSERT(!upb_Array_IsFrozen(array)); + UPB_ASSERT(i < array->UPB_ONLYBITS(size)); + UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array)); + char* arr_data = (char*)upb_Array_MutableDataPtr(array); + memcpy(arr_data + (i * elem_size), data, elem_size); +} + +UPB_API_INLINE size_t upb_Array_Size(const struct upb_Array* arr) { + return arr->UPB_ONLYBITS(size); +} + +UPB_API_INLINE size_t upb_Array_Capacity(const struct upb_Array* arr) { + return arr->UPB_PRIVATE(capacity); +} + +// LINT.ThenChange(GoogleInternalName0) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#undef _UPB_ARRAY_MASK_IMM +#undef _UPB_ARRAY_MASK_LG2 +#undef _UPB_ARRAY_MASK_ALL + + +#endif /* UPB_MESSAGE_INTERNAL_ARRAY_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_TYPES_H_ +#define UPB_MESSAGE_INTERNAL_TYPES_H_ + +#include + +// Must be last. + +#define UPB_OPAQUE(x) x##_opaque + +struct upb_Message { + union { + uintptr_t UPB_OPAQUE(internal); // tagged pointer, low bit == frozen + double d; // Forces same size for 32-bit/64-bit builds + }; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void UPB_PRIVATE(_upb_Message_ShallowFreeze)( + struct upb_Message* msg) { + msg->UPB_OPAQUE(internal) |= 1ULL; +} + +UPB_API_INLINE bool upb_Message_IsFrozen(const struct upb_Message* msg) { + return (msg->UPB_OPAQUE(internal) & 1ULL) != 0; +} + +UPB_INLINE struct upb_Message_Internal* UPB_PRIVATE(_upb_Message_GetInternal)( + const struct upb_Message* msg) { + const uintptr_t tmp = msg->UPB_OPAQUE(internal) & ~1ULL; + return (struct upb_Message_Internal*)tmp; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetInternal)( + struct upb_Message* msg, struct upb_Message_Internal* internal) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + msg->UPB_OPAQUE(internal) = (uintptr_t)internal; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#undef UPB_OPAQUE + + +#endif /* UPB_MESSAGE_INTERNAL_TYPES_H_ */ + +// Users should include array.h or map.h instead. +// IWYU pragma: private, include "upb/message/array.h" + +#ifndef UPB_MESSAGE_VALUE_H_ +#define UPB_MESSAGE_VALUE_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const struct upb_Array* array_val; + const struct upb_Map* map_val; + const struct upb_Message* msg_val; + upb_StringView str_val; + + // For an extension field, we are essentially treating ext->data (a + // upb_MessageValue) as if it were a message with one field that lives at + // offset 0. This works because upb_MessageValue is precisely one value that + // can hold any type of data. Recall that an extension can be of any type + // (scalar, repeated, or message). For a message extension, that will be a + // single upb_Message* at offset 0 of the upb_MessageValue. + struct upb_Message UPB_PRIVATE(ext_msg_val); +} upb_MessageValue; + +UPB_API_INLINE upb_MessageValue upb_MessageValue_Zero(void) { + upb_MessageValue zero; + memset(&zero, 0, sizeof(zero)); + return zero; +} + +typedef union { + struct upb_Array* array; + struct upb_Map* map; + struct upb_Message* msg; +} upb_MutableMessageValue; + +UPB_API_INLINE upb_MutableMessageValue upb_MutableMessageValue_Zero(void) { + upb_MutableMessageValue zero; + memset(&zero, 0, sizeof(zero)); + return zero; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_VALUE_H_ */ + +#ifndef UPB_MINI_TABLE_MESSAGE_H_ +#define UPB_MINI_TABLE_MESSAGE_H_ + +#include + + +#ifndef UPB_MINI_TABLE_ENUM_H_ +#define UPB_MINI_TABLE_ENUM_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_ +#define UPB_MINI_TABLE_INTERNAL_ENUM_H_ + +#include + +// Must be last. + +struct upb_MiniTableEnum { + uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask. + uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield. + uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow. +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE bool upb_MiniTableEnum_CheckValue( + const struct upb_MiniTableEnum* e, uint32_t val) { + if (UPB_LIKELY(val < 64)) { + const uint64_t mask = + e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32); + const uint64_t bit = 1ULL << val; + return (mask & bit) != 0; + } + if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) { + const uint32_t mask = e->UPB_PRIVATE(data)[val / 32]; + const uint32_t bit = 1U << (val % 32); + return (mask & bit) != 0; + } + + // OPT: binary search long lists? + const uint32_t* start = + &e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32]; + const uint32_t* limit = &e->UPB_PRIVATE( + data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */ + +// Must be last + +typedef struct upb_MiniTableEnum upb_MiniTableEnum; + +#ifdef __cplusplus +extern "C" { +#endif + +// Validates enum value against range defined by enum mini table. +UPB_API_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_ENUM_H_ */ + +#ifndef UPB_MINI_TABLE_FIELD_H_ +#define UPB_MINI_TABLE_FIELD_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_FIELD_H_ +#define UPB_MINI_TABLE_INTERNAL_FIELD_H_ + +#include +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ +#define UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Return the log2 of the storage size in bytes for a upb_CType +UPB_INLINE int UPB_PRIVATE(_upb_CType_SizeLg2)(upb_CType c_type) { + static const int8_t size[] = { + 0, // kUpb_CType_Bool + 2, // kUpb_CType_Float + 2, // kUpb_CType_Int32 + 2, // kUpb_CType_UInt32 + 2, // kUpb_CType_Enum + UPB_SIZE(2, 3), // kUpb_CType_Message + 3, // kUpb_CType_Double + 3, // kUpb_CType_Int64 + 3, // kUpb_CType_UInt64 + UPB_SIZE(3, 4), // kUpb_CType_String + UPB_SIZE(3, 4), // kUpb_CType_Bytes + }; + + // -1 here because the enum is one-based but the table is zero-based. + return size[c_type - 1]; +} + +// Return the log2 of the storage size in bytes for a upb_FieldType +UPB_INLINE size_t +UPB_PRIVATE(_upb_FieldType_SizeLg2)(upb_FieldType field_type) { + static const int8_t size[] = { + 3, // kUpb_FieldType_Double + 2, // kUpb_FieldType_Float + 3, // kUpb_FieldType_Int64 + 3, // kUpb_FieldType_UInt64 + 2, // kUpb_FieldType_Int32 + 3, // kUpb_FieldType_Fixed64 + 2, // kUpb_FieldType_Fixed32 + 0, // kUpb_FieldType_Bool + UPB_SIZE(3, 4), // kUpb_FieldType_String + UPB_SIZE(2, 3), // kUpb_FieldType_Group + UPB_SIZE(2, 3), // kUpb_FieldType_Message + UPB_SIZE(3, 4), // kUpb_FieldType_Bytes + 2, // kUpb_FieldType_UInt32 + 2, // kUpb_FieldType_Enum + 2, // kUpb_FieldType_SFixed32 + 3, // kUpb_FieldType_SFixed64 + 2, // kUpb_FieldType_SInt32 + 3, // kUpb_FieldType_SInt64 + }; + + // -1 here because the enum is one-based but the table is zero-based. + return size[field_type - 1]; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ */ + +// Must be last. + +// LINT.IfChange(struct_definition) +struct upb_MiniTableField { + uint32_t UPB_ONLYBITS(number); + uint16_t UPB_ONLYBITS(offset); + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + + // Offset from this upb_MiniTableField to the upb_MiniTableSubInternal + // for this field, in uint32_t units (so bytes/4). + // Will be set to `kUpb_NoSub` if `descriptortype` != MESSAGE/GROUP/ENUM + uint16_t UPB_PRIVATE(submsg_ofs); + + uint8_t UPB_PRIVATE(descriptortype); + + // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift) + uint8_t UPB_ONLYBITS(mode); +}; + +#define kUpb_NoSub ((uint16_t)-1) +#define kUpb_SubmsgOffsetBytes 4 + +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} upb_FieldMode; + +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 + +// Extra flags on the mode field. +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, + // Indicates that this descriptor type is an "alternate type": + // - for Int32, this indicates that the actual type is Enum (but was + // rewritten to Int32 because it is an open enum that requires no check). + // - for Bytes, this indicates that the actual type is String (but does + // not require any UTF-8 check). + kUpb_LabelFlags_IsAlternate = 16, +} upb_LabelFlags; + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_8Byte = 3, + + kUpb_FieldRep_NativePointer = + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte), + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; + +#define kUpb_FieldRep_Shift 6 + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_FieldMode +UPB_PRIVATE(_upb_MiniTableField_Mode)(const struct upb_MiniTableField* f) { + return (upb_FieldMode)(f->UPB_ONLYBITS(mode) & kUpb_FieldMode_Mask); +} + +UPB_INLINE upb_FieldRep +UPB_PRIVATE(_upb_MiniTableField_GetRep)(const struct upb_MiniTableField* f) { + return (upb_FieldRep)(f->UPB_ONLYBITS(mode) >> kUpb_FieldRep_Shift); +} + +UPB_API_INLINE bool upb_MiniTableField_IsArray( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Array; +} + +UPB_API_INLINE bool upb_MiniTableField_IsMap( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Map; +} + +UPB_API_INLINE bool upb_MiniTableField_IsScalar( + const struct upb_MiniTableField* f) { + return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Scalar; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_IsAlternate)( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsAlternate) != 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsExtension( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsExtension) != 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsPacked( + const struct upb_MiniTableField* f) { + return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsPacked) != 0; +} + +UPB_API_INLINE upb_FieldType +upb_MiniTableField_Type(const struct upb_MiniTableField* f) { + const upb_FieldType type = (upb_FieldType)f->UPB_PRIVATE(descriptortype); + if (UPB_PRIVATE(_upb_MiniTableField_IsAlternate)(f)) { + if (type == kUpb_FieldType_Int32) return kUpb_FieldType_Enum; + if (type == kUpb_FieldType_Bytes) return kUpb_FieldType_String; + UPB_ASSERT(false); + } + return type; +} + +UPB_API_INLINE +upb_CType upb_MiniTableField_CType(const struct upb_MiniTableField* f) { + return upb_FieldType_CType(upb_MiniTableField_Type(f)); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_HasHasbit)( + const struct upb_MiniTableField* f) { + return f->presence > 0; +} + +UPB_INLINE char UPB_PRIVATE(_upb_MiniTableField_HasbitMask)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)); + const uint16_t index = (uint16_t)f->presence; + return (char)(1 << (index % 8)); +} + +UPB_INLINE uint16_t UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)); + const uint16_t index = (uint16_t)f->presence; + return index / 8; +} + +UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum( + const struct upb_MiniTableField* f) { + return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum; +} + +UPB_API_INLINE bool upb_MiniTableField_IsInOneof( + const struct upb_MiniTableField* f) { + return f->presence < 0; +} + +UPB_API_INLINE bool upb_MiniTableField_IsSubMessage( + const struct upb_MiniTableField* f) { + return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message || + f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group; +} + +UPB_API_INLINE bool upb_MiniTableField_HasPresence( + const struct upb_MiniTableField* f) { + if (upb_MiniTableField_IsExtension(f)) { + return upb_MiniTableField_IsScalar(f); + } else { + return f->presence != 0; + } +} + +UPB_API_INLINE uint32_t +upb_MiniTableField_Number(const struct upb_MiniTableField* f) { + return f->UPB_ONLYBITS(number); +} + +UPB_INLINE uint16_t +UPB_PRIVATE(_upb_MiniTableField_Offset)(const struct upb_MiniTableField* f) { + return f->UPB_ONLYBITS(offset); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_OneofOffset)( + const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTableField_IsInOneof(f)); + return (size_t)(~(ptrdiff_t)f->presence); +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)( + const struct upb_MiniTableField* f) { + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsArray(f)); + UPB_ASSUME(f->presence == 0); +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)( + const struct upb_MiniTableField* f) { + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsMap(f)); + UPB_ASSUME(f->presence == 0); +} + +UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_ElemSizeLg2)( + const struct upb_MiniTableField* f) { + const upb_FieldType field_type = upb_MiniTableField_Type(f); + return UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type); +} + +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table_field.ts) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_FIELD_H_ */ + +// Must be last. + +typedef struct upb_MiniTableField upb_MiniTableField; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType upb_MiniTableField_CType(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_HasPresence(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsArray(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum( + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsExtension(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsInOneof(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsMap(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsPacked(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsScalar(const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_MiniTableField_IsSubMessage( + const upb_MiniTableField* f); + +UPB_API_INLINE uint32_t upb_MiniTableField_Number(const upb_MiniTableField* f); + +UPB_API_INLINE upb_FieldType +upb_MiniTableField_Type(const upb_MiniTableField* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FIELD_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ +#define UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ + +#include +#include +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_SUB_H_ +#define UPB_MINI_TABLE_INTERNAL_SUB_H_ + +// Must be last. + +union upb_MiniTableSub { + const struct upb_MiniTable* UPB_PRIVATE(submsg); + const struct upb_MiniTableEnum* UPB_PRIVATE(subenum); +}; + +typedef union upb_MiniTableSub upb_MiniTableSubInternal; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromEnum( + const struct upb_MiniTableEnum* subenum) { + union upb_MiniTableSub out; + out.UPB_PRIVATE(subenum) = subenum; + return out; +} + +UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromMessage( + const struct upb_MiniTable* submsg) { + union upb_MiniTableSub out; + out.UPB_PRIVATE(submsg) = submsg; + return out; +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTableSub_Enum( + const union upb_MiniTableSub sub) { + return sub.UPB_PRIVATE(subenum); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableSub_Message( + const union upb_MiniTableSub sub) { + return sub.UPB_PRIVATE(submsg); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_SUB_H_ */ + +// Must be last. + +struct upb_Decoder; +struct upb_Message; +struct upb_FastDecoder_Return; + +typedef UPB_PRESERVE_NONE struct upb_FastDecoder_Return _upb_FieldParser( + struct upb_Decoder* d, const char* ptr, struct upb_Message* msg, + const struct upb_MiniTable* table, uint64_t hasbits, uint64_t data, + uint64_t data2); + +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; + +// Ext Mode consists of 4 bits: +// * Extensibility +// * MessageSet +// * Map +// * FastTable field coverage +typedef enum { + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = + 3, // MessageSet item (temporary only, see decode.c) + + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, + + // Indicates that all eligible fields (with 1- or 2-byte) tags were + // successfully assigned to the fasttable. + kUpb_ExtMode_AllFastFieldsAssigned = 8, +} upb_ExtMode; + +// Check ExtMode base message info, excluding fasttable state info. +UPB_FORCEINLINE uint8_t UPB_PRIVATE(_upb_ExtMode_Base)(uint8_t ext_mode) { + return ext_mode & 7; +} + +enum { + kUpb_Message_Align = 8, +}; + +// upb_MiniTable represents the memory layout of a given upb_MessageDef. +// The members are public so generated code can initialize them, +// but users MUST NOT directly read or write any of its members. + +// LINT.IfChange(minitable_struct_definition) +struct upb_MiniTable { + const struct upb_MiniTableField* UPB_ONLYBITS(fields); + + // Must be aligned to kUpb_Message_Align. Doesn't include internal members + // like unknown fields, extension dict, pointer to msglayout, etc. + uint16_t UPB_PRIVATE(size); + + uint16_t UPB_ONLYBITS(field_count); + + uint8_t UPB_PRIVATE(ext); // upb_ExtMode, uint8_t here so sizeof(ext) == 1 + uint8_t UPB_PRIVATE(dense_below); + uint8_t UPB_PRIVATE(table_mask); + uint8_t UPB_PRIVATE(required_count); // Required fields have the low hasbits. + +#ifdef UPB_TRACING_ENABLED + const char* UPB_PRIVATE(full_name); +#endif + +#if UPB_FASTTABLE + // Flexible array member is not supported in C++ standard, but it is supported + // as an extension in all compilers we support. + _upb_FastTable_Entry UPB_PRIVATE(fasttable)[]; +#endif +}; +// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table.ts) + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void UPB_PRIVATE(upb_MiniTable_CheckInvariants)( + const struct upb_MiniTable* mt) { + UPB_STATIC_ASSERT(UPB_MALLOC_ALIGN >= kUpb_Message_Align, "Under aligned"); + UPB_STATIC_ASSERT(kUpb_Message_Align >= UPB_ALIGN_OF(void*), "Under aligned"); + UPB_ASSERT(mt->UPB_PRIVATE(size) % kUpb_Message_Align == 0); +} + +UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE( + _upb_MiniTable_StrongReference)(const struct upb_MiniTable* mt) { +#if defined(__GNUC__) + __asm__("" : : "r"(mt)); +#else + const struct upb_MiniTable* volatile unused = mt; + (void)&unused; // Use address to avoid an extra load of "unused". +#endif + return mt; +} + +UPB_API_INLINE int upb_MiniTable_FieldCount(const struct upb_MiniTable* m) { + return m->UPB_ONLYBITS(field_count); +} + +UPB_FORCEINLINE uint8_t +UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(const struct upb_MiniTable* m) { + return UPB_PRIVATE(_upb_ExtMode_Base)(m->UPB_PRIVATE(ext)); +} + +UPB_FORCEINLINE bool UPB_PRIVATE(_upb_MiniTable_IsExtendable)( + const struct upb_MiniTable* m) { + return UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == kUpb_ExtMode_Extendable; +} + +UPB_API_INLINE bool upb_MiniTable_IsMessageSet(const struct upb_MiniTable* m) { + return UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == + kUpb_ExtMode_IsMessageSet; +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_GetFieldByIndex( + const struct upb_MiniTable* m, uint32_t i) { + UPB_ASSERT(i < m->UPB_ONLYBITS(field_count)); + return &m->UPB_ONLYBITS(fields)[i]; +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTableField_CType(f) == kUpb_CType_Message); + upb_MiniTableSubInternal* sub = + UPB_PTR_AT(f, f->UPB_PRIVATE(submsg_ofs) * kUpb_SubmsgOffsetBytes, + upb_MiniTableSubInternal); + return sub->UPB_PRIVATE(submsg); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_SubMessage( + const struct upb_MiniTableField* f) { + if (upb_MiniTableField_CType(f) != kUpb_CType_Message) { + return NULL; + } + return upb_MiniTable_GetSubMessageTable(f); +} + +UPB_API_INLINE bool upb_MiniTable_FieldIsLinked( + const struct upb_MiniTableField* f) { + return upb_MiniTable_GetSubMessageTable(f) != NULL; +} + +UPB_FORCEINLINE +const struct upb_MiniTableField* UPB_PRIVATE(upb_MiniTable_GenericLowerBound)( + const struct upb_MiniTable* m, uint32_t lo, uint32_t search_len, + uint32_t number) { + const struct upb_MiniTableField* search_base = &m->UPB_ONLYBITS(fields)[lo]; + while (search_len > 1) { + size_t mid_offset = search_len >> 1; + if (UPB_UNPREDICTABLE(search_base[mid_offset].UPB_ONLYBITS(number) <= + number)) { + search_base = &search_base[mid_offset]; + } + search_len -= mid_offset; + } + + return search_base; +} + +// This implements the same algorithm as upb_MiniTable_GenericLowerBound but +// contorts itself to select specific arm instructions, which show significant +// effects on little cores. +UPB_FORCEINLINE const struct upb_MiniTableField* UPB_PRIVATE( + upb_MiniTable_ArmOptimizedLowerBound)(const struct upb_MiniTable* m, + uint32_t lo, uint32_t search_len, + uint32_t number) { + const uint32_t* search_base = + &m->UPB_ONLYBITS(fields)[lo].UPB_ONLYBITS(number); + UPB_STATIC_ASSERT(sizeof(struct upb_MiniTableField) == sizeof(uint32_t) * 3, + "Need to update multiplication"); + // Address generation units can't multiply by 12, but they can by 4. So we + // split it into multiplying by 3 (add and shift) and multiplying by 4 (shift) + // This code is carefully tuned to produce an optimal assembly sequence on + // arm64, which takes advantage of dual issue on in-order CPUs to maximize + // what little instruction level parallelism they have. + /* + and w9, w1, #0xfffffffe + add w9, w9, w1, lsr #1 + ldr w10, [x0, w9, uxtw #2] + sub w1, w1, w1, lsr #1 + add x9, x0, w9, uxtw #2 + cmp w10, w2 + csel x0, x0, x9, hi + cmp w1, #1 + b.hi .LBB3_1 + */ + // Doing this requires inhibiting the natural instincts of the compiler to + // eliminate duplicate work, so we introduce an optimization barrier with + // asm blocks to defeat common subexpression elimination. + UPB_STATIC_ASSERT( + offsetof(struct upb_MiniTableField, UPB_ONLYBITS(number)) == 0, + "Tag number must be first element of minitable field struct"); + while (search_len > 1) { +#if UPB_ARM64_ASM +#define UPB_OPT_LAUNDER(val) __asm__("" : "+r"(val)) +#define UPB_OPT_LAUNDER2(val1, val2) __asm__("" : "+r"(val1), "+r"(val2)) +#else +#define UPB_OPT_LAUNDER(val) +#define UPB_OPT_LAUNDER2(val1, val2) +#endif + // (search_len & ~1) is exactly (half_len * 2). Adding half_len yields + // (half_len * 3). + // + // and mid_offset_words, search_len, #0xfffffffe + uint32_t mid_offset_words = search_len & 0xfffffffe; + + // add mid_offset_words, mid_offset_words, search_len, lsr #1 + mid_offset_words = mid_offset_words + (search_len >> 1); + + UPB_OPT_LAUNDER(search_len); + UPB_OPT_LAUNDER(mid_offset_words); + + // Arm processors, even little cores, have Address Generation Units capable + // of performing these extensions, so we achieve more instruction level + // parallelism by doing this shift by 2 redundantly with the mid pointer + // calculation below. + // + // ldr mid_num, [search_base, mid_offset_words, uxtw #2] + uint32_t mid_num = search_base[mid_offset_words]; + + // Shrink the search window by half + // sub search_len, search_len, search_len, lsr #1 + search_len = search_len - (search_len >> 1); + UPB_OPT_LAUNDER(search_len); + UPB_OPT_LAUNDER(mid_offset_words); + + // Calculate the mid pointer for the next iteration + // add mid_ptr, search_base, mid_offset_words, uxtw #2 + const uint32_t* mid_ptr = search_base + mid_offset_words; + + // Forbids LLVM's CSE pass from attempting to merge mid_ptr and mid_num's + // math. It sees that it can do a select before adding, rather than after; + // but if it orders it that way it creates a longer dependency chain. We + // need both as input/output to the same asm block to force them to be + // present in different registers at the same time; two separate LAUNDER + // usages could get reordered. + UPB_OPT_LAUNDER2(mid_ptr, mid_num); + + // cmp + csel + search_base = UPB_UNPREDICTABLE(mid_num <= number) ? mid_ptr : search_base; + } +#undef UPB_OPT_LAUNDER +#undef UPB_OPT_LAUNDER2 + return (const struct upb_MiniTableField*)search_base; +} + +UPB_FORCEINLINE const struct upb_MiniTableField* UPB_PRIVATE( + upb_MiniTable_LowerBound)(const struct upb_MiniTable* m, uint32_t lo, + uint32_t search_len, uint32_t number) { +#ifndef NDEBUG + const struct upb_MiniTableField* candidate = UPB_PRIVATE( + upb_MiniTable_ArmOptimizedLowerBound)(m, lo, search_len, number); + UPB_ASSERT(candidate == UPB_PRIVATE(upb_MiniTable_GenericLowerBound)( + m, lo, search_len, number)); + return candidate; +#elif UPB_ARM64_ASM + return UPB_PRIVATE(upb_MiniTable_ArmOptimizedLowerBound)(m, lo, search_len, + number); +#else + return UPB_PRIVATE(upb_MiniTable_GenericLowerBound)(m, lo, search_len, + number); +#endif +} + +UPB_API_INLINE +const struct upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const struct upb_MiniTable* m, uint32_t number) { + const uint32_t i = number - 1; // 0 wraps to UINT32_MAX + + // Ideal case: index into dense fields + if (i < m->UPB_PRIVATE(dense_below)) { + UPB_ASSERT(m->UPB_ONLYBITS(fields)[i].UPB_ONLYBITS(number) == number); + return &m->UPB_ONLYBITS(fields)[i]; + } + + // Early exit if the field number is out of range. + uint32_t hi = m->UPB_ONLYBITS(field_count); + uint32_t lo = m->UPB_PRIVATE(dense_below); + UPB_ASSERT(hi >= lo); + uint32_t search_len = hi - lo; + if (search_len == 0 || + number > m->UPB_ONLYBITS(fields)[hi - 1].UPB_ONLYBITS(number)) { + return NULL; + } + + // Slow case: binary search + const struct upb_MiniTableField* candidate = + UPB_PRIVATE(upb_MiniTable_LowerBound)(m, lo, search_len, number); + + return candidate->UPB_ONLYBITS(number) == number ? candidate : NULL; +} + +UPB_FORCEINLINE bool UPB_PRIVATE(_upb_MiniTable_GapIfUnlinked)( + const struct upb_MiniTableField* field, uint32_t number, + uint32_t* out_gap_lo, uint32_t* out_gap_hi) { + UPB_STATIC_ASSERT(sizeof(upb_MiniTableSubInternal) == sizeof(void*), + "SubInternal size must be pointer sized."); + if (field->UPB_PRIVATE(submsg_ofs) != kUpb_NoSub) { + upb_MiniTableSubInternal* sub = UPB_PTR_AT( + field, field->UPB_PRIVATE(submsg_ofs) * kUpb_SubmsgOffsetBytes, + upb_MiniTableSubInternal); + // Type punning via union is legal in C and we're just checking if it's NULL + // but it's UB in C++, and this header could be included in C++. + void* sub_ptr; + memcpy(&sub_ptr, sub, sizeof(void*)); + if (sub_ptr == NULL) { + UPB_ASSERT(!upb_MiniTableField_IsClosedEnum(field)); + *out_gap_lo = number - 1; + *out_gap_hi = number + 1; + return true; + } + } + return false; +} + +// Given a tag number, finds the known field tags bounding the gap of unknown +// fields containing it. Returns false and does not set bounds if the tag number +// matches a known field and it is linked or primitive. Otherwise returns true +// and sets out_gap_lo and out_gap_hi (exclusive/exclusive) to define the range +// of unknown fields (out_gap_lo, out_gap_hi). Unlinked submessages are treated +// as gaps. +UPB_FORCEINLINE bool UPB_PRIVATE(_upb_MiniTable_FindUnknownGap)( + const struct upb_MiniTable* m, uint32_t number, uint32_t* out_gap_lo, + uint32_t* out_gap_hi) { + UPB_ASSERT(number != 0); + UPB_ASSERT(number < ((uint32_t)1 << 29)); + const uint32_t i = number - 1; + if (i < m->UPB_PRIVATE(dense_below)) { + // Dense field; we know it's present. + return UPB_PRIVATE(_upb_MiniTable_GapIfUnlinked)( + &m->UPB_ONLYBITS(fields)[i], number, out_gap_lo, out_gap_hi); + } + + uint32_t hi = m->UPB_ONLYBITS(field_count); + uint32_t lo = m->UPB_PRIVATE(dense_below); + if (hi == lo) { + *out_gap_lo = lo; + *out_gap_hi = UINT32_MAX; + return true; + } + + uint32_t max_field = m->UPB_ONLYBITS(fields)[hi - 1].UPB_ONLYBITS(number); + if (number > max_field) { + *out_gap_lo = max_field; + *out_gap_hi = UINT32_MAX; + return true; + } + + uint32_t search_len = hi - lo; + const struct upb_MiniTableField* candidate = + UPB_PRIVATE(upb_MiniTable_LowerBound)(m, lo, search_len, number); + + uint32_t candidate_num = candidate->UPB_ONLYBITS(number); + if (candidate_num == number) { + return UPB_PRIVATE(_upb_MiniTable_GapIfUnlinked)(candidate, number, + out_gap_lo, out_gap_hi); + } + + if (candidate_num < number) { + *out_gap_lo = candidate_num; + // Checking this next pointer is safe as we have already validated that the + // field we're searching for is not greater than or equal to the last field + *out_gap_hi = (candidate + 1)->UPB_ONLYBITS(number); + } else { + UPB_ASSERT(candidate == &m->UPB_ONLYBITS(fields)[lo]); + *out_gap_lo = lo; + *out_gap_hi = candidate_num; + } + return true; +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_MapEntrySubMessage( + const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTable_FieldIsLinked(f)); // Map entries must be linked. + UPB_ASSERT(upb_MiniTableField_IsMap(f)); // Function precondition. + return upb_MiniTable_GetSubMessageTable(f); +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const struct upb_MiniTableField* f) { + UPB_ASSERT(upb_MiniTableField_CType(f) == kUpb_CType_Enum); + upb_MiniTableSubInternal* sub = + UPB_PTR_AT(f, f->UPB_PRIVATE(submsg_ofs) * kUpb_SubmsgOffsetBytes, + upb_MiniTableSubInternal); + return sub->UPB_PRIVATE(subenum); +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapKey( + const struct upb_MiniTable* m) { + UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2); + const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 0); + UPB_ASSERT(upb_MiniTableField_Number(f) == 1); + return f; +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapValue( + const struct upb_MiniTable* m) { + UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2); + const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 1); + UPB_ASSERT(upb_MiniTableField_Number(f) == 2); + return f; +} + +// Computes a bitmask in which the |m->required_count| lowest bits are set. +// +// Sample output: +// RequiredMask(1) => 0b1 (0x1) +// RequiredMask(5) => 0b11111 (0x1f) +UPB_INLINE uint64_t +UPB_PRIVATE(_upb_MiniTable_RequiredMask)(const struct upb_MiniTable* m) { + int n = m->UPB_PRIVATE(required_count); + UPB_ASSERT(0 < n && n <= 64); + return (1ULL << n) - 1; +} + +#ifdef UPB_TRACING_ENABLED +UPB_INLINE const char* upb_MiniTable_FullName( + const struct upb_MiniTable* mini_table) { + return mini_table->UPB_PRIVATE(full_name); +} +// Initializes tracing proto name from language runtimes that construct +// mini tables dynamically at runtime. The runtime is responsible for passing +// controlling lifetime of name such as storing in same arena as mini_table. +UPB_INLINE void upb_MiniTable_SetFullName(struct upb_MiniTable* mini_table, + const char* full_name) { + mini_table->UPB_PRIVATE(full_name) = full_name; +} +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ */ + +// Must be last. + +typedef struct upb_MiniTable upb_MiniTable; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* m, uint32_t number); + +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_GetFieldByIndex( + const upb_MiniTable* m, uint32_t index); + +UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m); + +UPB_API_INLINE bool upb_MiniTable_IsMessageSet(const upb_MiniTable* m); + +// DEPRECATED: use upb_MiniTable_SubMessage() instead +// Returns the MiniTable for a message field, NULL if the field is unlinked. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTableField* f); + +// Returns the MiniTable for a message field if it is a submessage and the field +// is linked, otherwise returns NULL. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage( + const upb_MiniTableField* f); + +// Returns the MiniTable for a map field. The given field must refer to a map. +UPB_API_INLINE const upb_MiniTable* upb_MiniTable_MapEntrySubMessage( + const upb_MiniTableField* f); + +// Returns the MiniTableEnum for a message field, NULL if the field is unlinked. +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTableField* f); + +// Returns the MiniTableField for the key of a map. +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapKey( + const upb_MiniTable* m); + +// Returns the MiniTableField for the value of a map. +UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapValue( + const upb_MiniTable* m); + +// Returns true if this MiniTable field is linked to a MiniTable for the +// sub-message. +UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(const upb_MiniTableField* f); + +// If this field is in a oneof, returns the first field in the oneof. +// +// Otherwise returns NULL. +// +// Usage: +// const upb_MiniTableField* field = upb_MiniTable_GetOneof(m, f); +// do { +// .. +// } while (upb_MiniTable_NextOneofField(m, &field); +// +const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m, + const upb_MiniTableField* f); + +// Iterates to the next field in the oneof. If this is the last field in the +// oneof, returns false. The ordering of fields in the oneof is not +// guaranteed. +// REQUIRES: |f| is the field initialized by upb_MiniTable_GetOneof and updated +// by prior upb_MiniTable_NextOneofField calls. +bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, + const upb_MiniTableField** f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#ifdef __cplusplus +// Temporary overloads for functions whose signature has recently changed. +UPB_DEPRECATE_AND_INLINE() +inline const upb_MiniTable* upb_MiniTable_SubMessage( + const upb_MiniTable* m, const upb_MiniTableField* f) { + return upb_MiniTable_SubMessage(f); +} + +UPB_DEPRECATE_AND_INLINE() +inline const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* m, const upb_MiniTableField* f) { + return upb_MiniTable_GetSubMessageTable(f); +} + +UPB_DEPRECATE_AND_INLINE() +inline const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* m, const upb_MiniTableField* f) { + return upb_MiniTable_GetSubEnumTable(f); +} + +UPB_DEPRECATE_AND_INLINE() +inline bool upb_MiniTable_FieldIsLinked(const upb_MiniTable* m, + const upb_MiniTableField* f) { + return upb_MiniTable_FieldIsLinked(f); +} +#endif + + +#endif /* UPB_MINI_TABLE_MESSAGE_H_ */ + +// Must be last. + +typedef struct upb_Array upb_Array; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new array on the given arena that holds elements of this type. +UPB_NODISCARD UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +// Returns the number of elements in the array. +UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr); + +// Returns the number of elements in the array. +UPB_API_INLINE size_t upb_Array_Capacity(const upb_Array* arr); + +// Returns the given element, which must be within the array's current size. +UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +// Returns a non-null mutating pointer to the given element. `arr` must be an +// array of a message type, and `i` must be within the array's current size. +UPB_API struct upb_Message* upb_Array_GetMutable(upb_Array* arr, size_t i); + +// Sets the given element, which must be within the array's current size. +UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +// Appends an element to the array. Returns false on allocation failure. +UPB_NODISCARD UPB_API bool upb_Array_Append(upb_Array* array, + upb_MessageValue val, + upb_Arena* arena); + +// Copies elements from |src| to |dst|, resizing |dst| to match |src| size. +// Returns false on allocation failure. +UPB_NODISCARD UPB_API bool upb_Array_Copy(upb_Array* dst, const upb_Array* src, + upb_Arena* arena); + +// Appends all elements from |src| to the end of |dst|. +// Returns false on allocation failure. +UPB_NODISCARD UPB_API bool upb_Array_AppendAll(upb_Array* dst, + const upb_Array* src, + upb_Arena* arena); + +// Moves elements within the array using memmove(). +// Like memmove(), the source and destination elements may be overlapping. +UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +// Inserts one or more empty elements into the array. +// Existing elements are shifted right. +// The new elements have undefined state and must be set with `upb_Array_Set()`. +// REQUIRES: `i <= upb_Array_Size(arr)` +UPB_NODISCARD UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, + size_t count, upb_Arena* arena); + +// Deletes one or more elements from the array. +// Existing elements are shifted left. +// REQUIRES: `i + count <= upb_Array_Size(arr)` +UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +// Reserves |size| elements of storage for the array. +UPB_NODISCARD UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, + size_t size, + upb_Arena* arena); + +// Changes the size of a vector. New elements are initialized to NULL/0. +// Returns false on allocation failure. +UPB_NODISCARD UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, + upb_Arena* arena); + +// Returns pointer to array data. +UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr); + +// Returns mutable pointer to array data. +UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr); + +// Mark an array and all of its descendents as frozen/immutable. +// If the array elements are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m); + +// Returns whether an array has been frozen. +UPB_API_INLINE bool upb_Array_IsFrozen(const upb_Array* arr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_ARRAY_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_ +#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#include +#include +#include + + +#ifndef UPB_BASE_INTERNAL_ENDIAN_H_ +#define UPB_BASE_INTERNAL_ENDIAN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool upb_IsLittleEndian(void) { + const int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) { + if (upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) { + if (upb_IsLittleEndian()) return val; + + const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32; + const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32)); + return hi | lo; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */ + +#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_ +#define UPB_MESSAGE_INTERNAL_EXTENSION_H_ + +#include + + +#ifndef UPB_MESSAGE_INTERNAL_MAP_H_ +#define UPB_MESSAGE_INTERNAL_MAP_H_ + +#include +#include +#include + + +/* + * upb_table + * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! + * This file defines very fast int->upb_value (inttable) and string->upb_value + * (strtable) hash tables. + * + * The table uses chained scatter with Brent's variation (inspired by the Lua + * implementation of hash tables). The hash function for strings is Austin + * Appleby's "MurmurHash." + * + * The inttable uses uintptr_t as its key, which guarantees it can be used to + * store pointers or integers of at least 32 bits (upb isn't really useful on + * systems where sizeof(void*) < 4). + * + * The table must be homogeneous (all values of the same type). In debug + * mode, we check this on insert and lookup. + */ + +#ifndef UPB_HASH_COMMON_H_ +#define UPB_HASH_COMMON_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_value ******************************************************************/ + +typedef struct { + uint64_t val; +} upb_value; + +/* For each value ctype, define the following set of functions: + * + * // Get/set an int32 from a upb_value. + * int32_t upb_value_getint32(upb_value val); + * void upb_value_setint32(upb_value *val, int32_t cval); + * + * // Construct a new upb_value from an int32. + * upb_value upb_value_int32(int32_t val); */ +#define FUNCS(name, membername, type_t, converter) \ + UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ + val->val = (uint64_t)cval; \ + } \ + UPB_INLINE upb_value upb_value_##name(type_t val) { \ + upb_value ret; \ + upb_value_set##name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get##name(upb_value val) { \ + return (type_t)(converter)val.val; \ + } + +FUNCS(int32, int32, int32_t, int32_t) +FUNCS(int64, int64, int64_t, int64_t) +FUNCS(uint32, uint32, uint32_t, uint32_t) +FUNCS(uint64, uint64, uint64_t, uint64_t) +FUNCS(bool, _bool, bool, bool) +FUNCS(cstr, cstr, char*, uintptr_t) +FUNCS(uintptr, uptr, uintptr_t, uintptr_t) +FUNCS(ptr, ptr, void*, uintptr_t) +FUNCS(constptr, constptr, const void*, uintptr_t) + +#undef FUNCS + +UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { + memcpy(&val->val, &cval, sizeof(cval)); +} + +UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { + memcpy(&val->val, &cval, sizeof(cval)); +} + +UPB_INLINE upb_value upb_value_float(float cval) { + upb_value ret; + upb_value_setfloat(&ret, cval); + return ret; +} + +UPB_INLINE upb_value upb_value_double(double cval) { + upb_value ret; + upb_value_setdouble(&ret, cval); + return ret; +} + +/* upb_key *****************************************************************/ + +// A uint32 size followed by that number of bytes stored contiguously. +typedef struct { + uint32_t size; + const char data[]; +} upb_SizePrefixString; + +/* Either: + * 1. an actual integer key + * 2. a SizePrefixString*, owned by us. + * + * ...depending on whether this is a string table or an int table. */ +typedef union { + uintptr_t num; + const upb_SizePrefixString* str; +} upb_key; + +UPB_INLINE upb_StringView upb_key_strview(upb_key key) { + return upb_StringView_FromDataAndSize(key.str->data, key.str->size); +} + +/* upb_table ******************************************************************/ + +typedef struct _upb_tabent { + upb_value val; + upb_key key; + + /* Internal chaining and presence: + * - next == NULL: The entry is empty. + * - ent.next == kUpb_NoNextTabent indicating the entry is occupied but has no + * successor. + * - otherwise: The entry is occupied, and next points to the next entry in + * the collision chain. */ + uintptr_t next; +} upb_tabent; + +typedef struct { + upb_tabent* entries; + /* Number of entries in the hash part. */ + uint32_t count; + + /* Mask to turn hash value -> bucket. The map's allocated size is mask + 1.*/ + uint32_t mask; +} upb_table; + +UPB_INLINE size_t upb_table_size(const upb_table* t) { return t->mask + 1; } + +// Internal-only functions, in .h file only out of necessity. + +UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->next == 0; } + +#define kUpb_NoNextTabent ((uintptr_t)1) + +UPB_INLINE bool upb_tabent_hasnext(const upb_tabent* e) { + UPB_STATIC_ASSERT(UPB_ALIGN_OF(upb_tabent) > 1, + "valid upb_tabent* can't reference address 1"); + return e->next != kUpb_NoNextTabent; +} + +UPB_INLINE void upb_tabent_clearnext(upb_tabent* e) { + e->next = kUpb_NoNextTabent; +} + +UPB_INLINE void upb_tabent_clear(upb_tabent* e) { + e->next = 0; + UPB_ASSERT(upb_tabent_isempty(e)); +} + +UPB_INLINE upb_tabent* upb_tabent_next(const upb_tabent* e) { + UPB_ASSERT(upb_tabent_hasnext(e)); + return (upb_tabent*)e->next; +} + +UPB_INLINE void upb_tabent_setnext(upb_tabent* e, upb_tabent* next) { + UPB_ASSERT((uintptr_t)next != 0); + UPB_ASSERT(next != e); + UPB_ASSERT((uintptr_t)next != kUpb_NoNextTabent); + e->next = (uintptr_t)next; + UPB_ASSERT(upb_tabent_hasnext(e)); +} + +#undef kUpb_NoNextTabent + +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_COMMON_H_ */ + +#ifndef UPB_HASH_INT_TABLE_H_ +#define UPB_HASH_INT_TABLE_H_ + +#include +#include + + +// Must be last. + +typedef struct { + upb_table t; +} upb_inttable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +UPB_NODISCARD bool upb_inttable_init(upb_inttable* table, upb_Arena* a); + +// Returns the number of values in the table. +size_t upb_inttable_count(const upb_inttable* t); + +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. +UPB_NODISCARD bool upb_inttable_insert(upb_inttable* t, uintptr_t key, + upb_value val, upb_Arena* a); + +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); + +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); + +// Updates an existing entry in an inttable. +// If the entry does not exist, returns false and does nothing. +// Unlike insert/remove, this does not invalidate iterators. +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); + +// Clears the table. +void upb_inttable_clear(upb_inttable* t); + +// Iteration over inttable: +// +// intptr_t iter = UPB_INTTABLE_BEGIN; +// uintptr_t key; +// upb_value val; +// while (upb_inttable_next(t, &key, &val, &iter)) { +// // ... +// } + +#define UPB_INTTABLE_BEGIN -1 + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); +void upb_inttable_setentryvalue(upb_inttable* t, intptr_t iter, upb_value v); +bool upb_inttable_done(const upb_inttable* t, intptr_t i); +uintptr_t upb_inttable_iter_key(const upb_inttable* t, intptr_t iter); +upb_value upb_inttable_iter_value(const upb_inttable* t, intptr_t iter); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_INT_TABLE_H_ */ + +#ifndef UPB_HASH_STR_TABLE_H_ +#define UPB_HASH_STR_TABLE_H_ + +#include +#include +#include + + +// Must be last. + +typedef struct { + upb_table t; +} upb_strtable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +UPB_NODISCARD bool upb_strtable_init(upb_strtable* table, size_t expected_size, + upb_Arena* a); + +// Returns the number of values in the table. +UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { + return t->t.count; +} + +void upb_strtable_clear(upb_strtable* t); + +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. The key is not required +// to be NULL-terminated, and the table will make an internal copy of the key. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. */ +UPB_NODISCARD bool upb_strtable_insert(upb_strtable* t, const char* key, + size_t len, upb_value val, upb_Arena* a); + +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v); + +// For NULL-terminated strings. +UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_lookup2(t, key, strlen(key), v); +} + +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val); + +UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, + upb_value* v) { + return upb_strtable_remove2(t, key, strlen(key), v); +} + +// Exposed for testing only. +UPB_NODISCARD bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, + upb_Arena* a); + +/* Iteration over strtable: + * + * intptr_t iter = UPB_STRTABLE_BEGIN; + * upb_StringView key; + * upb_value val; + * while (upb_strtable_next2(t, &key, &val, &iter)) { + * // ... + * } + */ + +#define UPB_STRTABLE_BEGIN -1 + +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter); +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); +void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v); + +/* DEPRECATED iterators, slated for removal. + * + * Iterators for string tables. We are subject to some kind of unusual + * design constraints: + * + * For high-level languages: + * - we must be able to guarantee that we don't crash or corrupt memory even if + * the program accesses an invalidated iterator. + * + * For C++11 range-based for: + * - iterators must be copyable + * - iterators must be comparable + * - it must be possible to construct an "end" value. + * + * Iteration order is undefined. + * + * Modifying the table invalidates iterators. upb_{str,int}table_done() is + * guaranteed to work even on an invalidated iterator, as long as the table it + * is iterating over has not been freed. Calling next() or accessing data from + * an invalidated iterator yields unspecified elements from the table, but it is + * guaranteed not to crash and to return real table elements (except when done() + * is true). */ +/* upb_strtable_iter **********************************************************/ + +/* upb_strtable_iter i; + * upb_strtable_begin(&i, t); + * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + * const char *key = upb_strtable_iter_key(&i); + * const upb_value val = upb_strtable_iter_value(&i); + * // ... + * } + */ + +typedef struct { + const upb_strtable* t; + size_t index; +} upb_strtable_iter; + +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; +} + +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); +void upb_strtable_next(upb_strtable_iter* i); +bool upb_strtable_done(const upb_strtable_iter* i); +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i); +upb_value upb_strtable_iter_value(const upb_strtable_iter* i); +void upb_strtable_iter_setdone(upb_strtable_iter* i); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_STR_TABLE_H_ */ + +// Must be last. + +typedef enum { + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, +} upb_MapInsertStatus; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +union upb_Map_Table { + upb_strtable strtable; + upb_inttable inttable; +}; + +struct upb_Map { + // Size of key and val, based on the map type. + // Strings are represented as '0' because they must be handled specially. + char key_size; + char val_size; + bool UPB_PRIVATE(is_frozen); + bool UPB_PRIVATE(is_strtable); + + union upb_Map_Table t; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void UPB_PRIVATE(_upb_Map_ShallowFreeze)(struct upb_Map* map) { + map->UPB_PRIVATE(is_frozen) = true; +} + +UPB_API_INLINE bool upb_Map_IsFrozen(const struct upb_Map* map) { + return map->UPB_PRIVATE(is_frozen); +} + +// Converting between internal table representation and user values. +// +// _upb_map_tokey() and _upb_map_fromkey() are inverses. +// _upb_map_tovalue() and _upb_map_fromvalue() are inverses. +// +// These functions account for the fact that strings are treated differently +// from other types when stored in a map. + +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} + +UPB_INLINE uintptr_t _upb_map_tointkey(const void* key, size_t key_size) { + uintptr_t intkey = 0; + memcpy(&intkey, key, key_size); + return intkey; +} + +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} + +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} + +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} + +UPB_INLINE bool _upb_map_next(const struct upb_Map* map, size_t* iter) { + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_iter it; + it.t = &map->t.strtable; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + return !upb_strtable_done(&it); + } else { + uintptr_t key; + upb_value val; + intptr_t int_iter = 0; + memcpy(&int_iter, iter, sizeof(intptr_t)); + upb_inttable_next(&map->t.inttable, &key, &val, &int_iter); + memcpy(iter, &int_iter, sizeof(size_t)); + return !upb_inttable_done(&map->t.inttable, int_iter); + } +} + +UPB_INLINE void _upb_Map_Clear(struct upb_Map* map) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + if (map->UPB_PRIVATE(is_strtable)) { + upb_strtable_clear(&map->t.strtable); + } else { + upb_inttable_clear(&map->t.inttable); + } +} + +UPB_INLINE bool _upb_Map_Delete(struct upb_Map* map, const void* key, + size_t key_size, upb_value* val) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + if (map->UPB_PRIVATE(is_strtable)) { + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->t.strtable, k.data, k.size, val); + } else { + uintptr_t intkey = _upb_map_tointkey(key, key_size); + return upb_inttable_remove(&map->t.inttable, intkey, val); + } +} + +UPB_INLINE bool _upb_Map_Get(const struct upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval = {0}; + bool ret; + if (map->UPB_PRIVATE(is_strtable)) { + upb_StringView k = _upb_map_tokey(key, key_size); + ret = upb_strtable_lookup2(&map->t.strtable, k.data, k.size, &tabval); + } else { + uintptr_t intkey = _upb_map_tointkey(key, key_size); + ret = upb_inttable_lookup(&map->t.inttable, intkey, &tabval); + } + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; +} + +UPB_INLINE upb_MapInsertStatus _upb_Map_Insert(struct upb_Map* map, + const void* key, size_t key_size, + void* val, size_t val_size, + upb_Arena* a) { + UPB_ASSERT(!upb_Map_IsFrozen(map)); + + // Prep the value. + upb_value tabval = {0}; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return kUpb_MapInsertStatus_OutOfMemory; + } + + bool removed; + if (map->UPB_PRIVATE(is_strtable)) { + upb_StringView strkey = _upb_map_tokey(key, key_size); + // TODO: add overwrite operation to minimize number of lookups. + removed = + upb_strtable_remove2(&map->t.strtable, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->t.strtable, strkey.data, strkey.size, tabval, + a)) { + return kUpb_MapInsertStatus_OutOfMemory; + } + } else { + uintptr_t intkey = _upb_map_tointkey(key, key_size); + removed = upb_inttable_remove(&map->t.inttable, intkey, NULL); + if (!upb_inttable_insert(&map->t.inttable, intkey, tabval, a)) { + return kUpb_MapInsertStatus_OutOfMemory; + } + } + return removed ? kUpb_MapInsertStatus_Replaced + : kUpb_MapInsertStatus_Inserted; +} + +UPB_INLINE size_t _upb_Map_Size(const struct upb_Map* map) { + if (map->UPB_PRIVATE(is_strtable)) { + return map->t.strtable.t.count; + } else { + return upb_inttable_count(&map->t.inttable); + } +} + +// Strings/bytes are special-cased in maps. +extern char _upb_Map_CTypeSizeTable[12]; + +UPB_INLINE size_t _upb_Map_CTypeSize(upb_CType ctype) { + return (size_t)_upb_Map_CTypeSizeTable[ctype]; +} + +// Creates a new map on the given arena with this key/value type. +struct upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MAP_H_ */ + +#ifndef UPB_MINI_TABLE_EXTENSION_H_ +#define UPB_MINI_TABLE_EXTENSION_H_ + +#include + + +#ifndef UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ +#define UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ + +#include +#include + + +// Must be last. + +struct upb_MiniTableExtension { + // Do not move this field. We need to be able to alias pointers. + struct upb_MiniTableField UPB_PRIVATE(field); + + union upb_MiniTableSub UPB_PRIVATE(sub); // NULL unless submsg or proto2 enum + + // A known extendee schema for a canonical extension. For a non-canonical + // extension, it's typically converted from a canonical extension via the + // upb_Message_Convert() API, but is not registered on the extension + // registry of the target message when it gets converted. In this case, the + // `extendee` info is present on the source message before conversion. + const struct upb_MiniTable* UPB_PRIVATE(extendee); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType +upb_MiniTableExtension_CType(const struct upb_MiniTableExtension* e) { + return upb_MiniTableField_CType(&e->UPB_PRIVATE(field)); +} + +UPB_API_INLINE uint32_t +upb_MiniTableExtension_Number(const struct upb_MiniTableExtension* e) { + return e->UPB_PRIVATE(field).UPB_ONLYBITS(number); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableExtension_Extendee( + const struct upb_MiniTableExtension* e) { + return e->UPB_PRIVATE(extendee); +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableExtension_GetSubMessage( + const struct upb_MiniTableExtension* e) { + if (upb_MiniTableExtension_CType(e) != kUpb_CType_Message) { + return NULL; + } + return upb_MiniTableSub_Message(e->UPB_PRIVATE(sub)); +} + +UPB_API_INLINE const struct upb_MiniTableEnum* +upb_MiniTableExtension_GetSubEnum(const struct upb_MiniTableExtension* e) { + if (upb_MiniTableExtension_CType(e) != kUpb_CType_Enum) { + return NULL; + } + return upb_MiniTableSub_Enum(e->UPB_PRIVATE(sub)); +} + +UPB_API_INLINE bool upb_MiniTableExtension_SetSubMessage( + struct upb_MiniTableExtension* e, const struct upb_MiniTable* m) { + if (e->UPB_PRIVATE(field).UPB_PRIVATE(descriptortype) != + kUpb_FieldType_Message && + e->UPB_PRIVATE(field).UPB_PRIVATE(descriptortype) != + kUpb_FieldType_Group) { + return false; + } + e->UPB_PRIVATE(sub).UPB_PRIVATE(submsg) = m; + return true; +} + +UPB_API_INLINE bool upb_MiniTableExtension_SetSubEnum( + struct upb_MiniTableExtension* e, const struct upb_MiniTableEnum* en) { + if (e->UPB_PRIVATE(field).UPB_PRIVATE(descriptortype) != + kUpb_FieldType_Enum) { + return false; + } + e->UPB_PRIVATE(sub).UPB_PRIVATE(subenum) = en; + return true; +} + +UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTableExtension_ToField( + const struct upb_MiniTableExtension* e) { + return &e->UPB_PRIVATE(field); +} + +UPB_INLINE upb_FieldRep UPB_PRIVATE(_upb_MiniTableExtension_GetRep)( + const struct upb_MiniTableExtension* e) { + return UPB_PRIVATE(_upb_MiniTableField_GetRep)(&e->UPB_PRIVATE(field)); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ */ + +// Must be last. + +typedef struct upb_MiniTableExtension upb_MiniTableExtension; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE upb_CType +upb_MiniTableExtension_CType(const upb_MiniTableExtension* e); + +UPB_API_INLINE uint32_t +upb_MiniTableExtension_Number(const upb_MiniTableExtension* e); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableExtension_Extendee( + const upb_MiniTableExtension* e); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableExtension_GetSubMessage( + const upb_MiniTableExtension* e); + +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTableExtension_GetSubEnum( + const upb_MiniTableExtension* e); + +UPB_API_INLINE bool upb_MiniTableExtension_SetSubMessage( + upb_MiniTableExtension* e, const upb_MiniTable* m); + +UPB_API_INLINE bool upb_MiniTableExtension_SetSubEnum( + upb_MiniTableExtension* e, const upb_MiniTableEnum* m); + +UPB_API_INLINE const upb_MiniTableField* upb_MiniTableExtension_ToField( + const upb_MiniTableExtension* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_EXTENSION_H_ */ + +// Must be last. + +// The internal representation of an extension is self-describing: it contains +// enough information that we can serialize it to binary format without needing +// to look it up in a upb_ExtensionRegistry. +// +// This representation allocates 16 bytes to data on 64-bit platforms. +// This is rather wasteful for scalars (in the extreme case of bool, +// it wastes 15 bytes). We accept this because we expect messages to be +// the most common extension type. +typedef struct { + const upb_MiniTableExtension* ext; + upb_MessageValue data; +} upb_Extension; + +#ifdef __cplusplus +extern "C" { +#endif + +// Adds the given extension data to the given message. +// |ext| is copied into the message instance. +// This logically replaces any previously-added extension with this number. +UPB_NODISCARD upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* ext, + upb_Arena* arena); + +// Adds the given non-canonical extension data to the given message. +// |ext| is copied into the message instance. +// This logically replaces any previously-added extension with this number. +UPB_NODISCARD upb_Extension* UPB_PRIVATE( + _upb_Message_CreateNonCanonicalExtension)(struct upb_Message* msg, + const upb_MiniTableExtension* ext, + upb_Arena* arena); + +// Returns an extension for a message with a given mini table, +// or NULL if no extension exists with this mini table. +const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( + const struct upb_Message* msg, const upb_MiniTableExtension* ext); + +UPB_INLINE bool UPB_PRIVATE(_upb_Extension_IsEmpty)(const upb_Extension* ext) { + switch ( + UPB_PRIVATE(_upb_MiniTableField_Mode)(&ext->ext->UPB_PRIVATE(field))) { + case kUpb_FieldMode_Scalar: + return false; + case kUpb_FieldMode_Array: + return upb_Array_Size(ext->data.array_val) == 0; + case kUpb_FieldMode_Map: + return _upb_Map_Size(ext->data.map_val) == 0; + } + UPB_UNREACHABLE(); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_EXTENSION_H_ */ + +/* +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ + +#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_ +#define UPB_MESSAGE_INTERNAL_MESSAGE_H_ + +#include +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; +extern const double kUpb_NaN; + +// Internal members of a upb_Message that track unknown fields and/or +// extensions. We can change this without breaking binary compatibility. + +// LINT.IfChange(tagged_aux_type) +typedef struct upb_TaggedAuxPtr { + // Three lowest bits form a tag: + // 000 - non-aliased unknown data (upb_StringView*) + // 100 - aliased unknown data (upb_StringView*) + // 001 - non-canonical extension (upb_Extension*) + // 011 - canonical extension (upb_Extension*) + // + // Bit 0 (lowest bit): Represents the data format in memory (1 for parsed + // form, 0 for serialized form). + // Bit 1 (middle bit): Represents whether the data is semantically known or + // not (1 for known, 0 for unknown). + // Bit 2 (highest bit): Aliased/Non-aliased (1 for aliased, 0 for + // non-aliased). + // + // Following this tag structure, we can later use tag `010` for lazy + // extensions. + // + // The main semantic difference between aliased and non-aliased + // unknown data is that non-aliased unknown data can be assumed to have the + // following layout: + // + // [upb_StringView] [data] + // + // where the StringView points to the data buffer and the data buffer is + // immediately following the StringView. + // + // The string view does not necessarily point to the start of the data buffer; + // if the initial part of the buffer is removed from the message, the string + // view will point to the beginning of the remaining buffer. + // + // For aliased unknown data, this layout is _not_ guaranteed, since the + // pointer to the StringView can be anywhere in the allocation, and the + // StringView may point to non-data memory. + // + // For a non-canonical extension, its schema is known but not + // the one expected by the message, so it should be treated like an unknown + // field, but is stored as an extension to lazily defer serialization. + uintptr_t ptr; +} upb_TaggedAuxPtr; + +// If this returns true, then the entry is semantically known (but may be in +// either parsed or unparsed form). +UPB_INLINE bool upb_TaggedAuxPtr_IsSemanticallyKnown(upb_TaggedAuxPtr ptr) { + return (ptr.ptr & 0x2) != 0; +} + +UPB_INLINE bool upb_TaggedAuxPtr_IsCanonicalExtension(upb_TaggedAuxPtr ptr) { + return (ptr.ptr & 3) == 3; +} + +UPB_INLINE bool upb_TaggedAuxPtr_IsNonCanonicalExtension(upb_TaggedAuxPtr ptr) { + return (ptr.ptr & 3) == 1; +} + +// Returns true if the entry is aliased/non-aliased unknown data. +UPB_INLINE bool upb_TaggedAuxPtr_IsUnknownStringView(upb_TaggedAuxPtr ptr) { + return (ptr.ptr != 0) && ((ptr.ptr & 3) == 0); +} + +UPB_INLINE bool upb_TaggedAuxPtr_IsUnknownAliased(upb_TaggedAuxPtr ptr) { + return (ptr.ptr != 0) && ((ptr.ptr & 5) == 4); +} + +UPB_INLINE upb_Extension* upb_TaggedAuxPtr_CanonicalExtension( + upb_TaggedAuxPtr ptr) { + UPB_ASSERT(upb_TaggedAuxPtr_IsCanonicalExtension(ptr)); + return (upb_Extension*)(ptr.ptr & ~7ULL); +} + +UPB_INLINE upb_Extension* upb_TaggedAuxPtr_NonCanonicalExtension( + upb_TaggedAuxPtr ptr) { + UPB_ASSERT(upb_TaggedAuxPtr_IsNonCanonicalExtension(ptr)); + return (upb_Extension*)(ptr.ptr & ~7ULL); +} + +// Returns a pointer to the aliased or unaliased unknown upb_StringView* data. +UPB_INLINE upb_StringView* upb_TaggedPtrAux_StringViewRepr( + upb_TaggedAuxPtr ptr) { + UPB_ASSERT(upb_TaggedAuxPtr_IsUnknownStringView(ptr)); + return (upb_StringView*)(ptr.ptr & ~7ULL); +} + +// LINT.ThenChange(//depot/google3/third_party/upb/bits/golang/message.go:tagged_aux_type) + +typedef enum { + kUpb_TaggedAuxType_Unknown = 0, // tag 000 + kUpb_TaggedAuxType_NonCanonicalExtension = 1, // tag 001 + kUpb_TaggedAuxType_CanonicalExtension = 3, // tag 011 + kUpb_TaggedAuxType_AliasedUnknown = 4 // tag 100 +} upb_TaggedAuxType; + +typedef union { + upb_Extension* extension; + const upb_StringView* unknown_data; +} upb_TaggedAux; + +UPB_INLINE upb_TaggedAuxType upb_TaggedAux_Get(upb_TaggedAuxPtr ptr, + upb_TaggedAux* data) { + uintptr_t untagged = ptr.ptr & ~7ULL; + UPB_ASSERT((untagged & 7) == 0); + memcpy(data, &untagged, sizeof(*data)); + return (upb_TaggedAuxType)(ptr.ptr & 7); +} + +UPB_INLINE upb_TaggedAuxPtr upb_TaggedAuxPtr_Null(void) { + upb_TaggedAuxPtr ptr; + ptr.ptr = 0; + return ptr; +} + +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeCanonicalExtension(const upb_Extension* e) { + UPB_ASSERT(((uintptr_t)e & 7) == 0); + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)e | 3; + return ptr; +} + +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeNonCanonicalExtension(const upb_Extension* e) { + UPB_ASSERT(((uintptr_t)e & 7) == 0); + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)e | 1; + return ptr; +} + +// This tag means that the original allocation for this field starts with the +// string view and ends with the end of the content referenced by the string +// view. +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeUnknownData(const upb_StringView* sv) { + UPB_ASSERT(((uintptr_t)sv & 7) == 0); + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)sv; + return ptr; +} + +// This tag implies no guarantee between the relationship of the string view and +// the data it points to. +UPB_INLINE upb_TaggedAuxPtr +upb_TaggedAuxPtr_MakeUnknownDataAliased(const upb_StringView* sv) { + UPB_ASSERT(((uintptr_t)sv & 7) == 0); + upb_TaggedAuxPtr ptr; + ptr.ptr = (uintptr_t)sv | 4; + return ptr; +} + +typedef struct upb_Message_Internal { + // Total number of entries set in aux_data + uint32_t size; + uint32_t capacity; + // Tagged pointers to upb_StringView or upb_Extension + upb_TaggedAuxPtr aux_data[]; +} upb_Message_Internal; + +#ifdef UPB_TRACING_ENABLED +UPB_API void upb_Message_LogNewMessage(const upb_MiniTable* m, + const upb_Arena* arena); +UPB_API void upb_Message_SetNewMessageTraceHandler( + void (*handler)(const upb_MiniTable*, const upb_Arena*)); +#endif // UPB_TRACING_ENABLED + +// We want to avoid the PLT and register spills for the many tiny memsets used +// to initialize messages; the dedicated memset instructions won't do that +#ifdef __ARM_FEAT_MOPS +#define UPB_ARM_MOPS __ARM_FEAT_MOPS +#else +#define UPB_ARM_MOPS 0 +#endif + +UPB_FORCEINLINE void _upb_Message_AlignedMemsetZero(void* dst, size_t size) { + UPB_ASSUME(size % kUpb_Message_Align == 0); + UPB_ASSUME(size != 0); + UPB_ASSUME((uintptr_t)dst % kUpb_Message_Align == 0); +#if UPB_ARM64_ASM && !UPB_ARM_MOPS +#if UPB_HAS_BUILTIN(__builtin_constant_p) + if (__builtin_constant_p(size)) { + // We assume the compiler will do something intelligent with a known-length + // memset. + memset(dst, 0, size); + return; + } +#endif + char* ptr = (char*)dst; + char* end = ptr + size; + __asm__( + // Unconditionally zero the first 8 byte chunk; if the loop runs this is + // wasted work, but doing it unconditionally is cheaper than adding + // another branch. + "str xzr, [%x[ptr]]\n\t" + + // If size == 8, skip the loop. + "cmp %x[count], #8\n\t" + "b.eq 2f\n\t" + + // Loop for size >= 16. + // In each iteration, we zero 16 bytes from the ptr and 16 bytes from the + // end. These regions may overlap, which is OK; doing it this way lets us + // process two chunks per loop iteration. + "1:\n\t" + "stp xzr, xzr, [%x[ptr]], #16\n\t" // Store then increment by 16 + "stp xzr, xzr, [%x[end], #-16]!\n\t" // Decrement by 16 then store + // End the loop when pointers cross or meet. + "cmp %x[ptr], %x[end]\n\t" + "b.lo 1b\n\t" + "2:\n\t" + : [ptr] "+&r"(ptr), [end] "+&r"(end), "=m"(*(char (*)[])dst) + : [count] "r"(size) + : "cc"); + UPB_PRIVATE(upb_Xsan_MarkInitialized)(dst, size); +#else + memset(dst, 0, size); +#endif +} +#undef UPB_ARM_MOPS + +// Inline version upb_Message_New(), for internal use. +UPB_NODISCARD UPB_INLINE struct upb_Message* _upb_Message_New( + const upb_MiniTable* m, upb_Arena* a) { + UPB_PRIVATE(upb_MiniTable_CheckInvariants)(m); +#ifdef UPB_TRACING_ENABLED + upb_Message_LogNewMessage(m, a); +#endif // UPB_TRACING_ENABLED + + const size_t size = m->UPB_PRIVATE(size); + // Message sizes are aligned up when constructing minitables; telling the + // compiler this avoids redoing alignment on the malloc fast path + UPB_ASSUME(size % kUpb_Message_Align == 0); + struct upb_Message* msg = (struct upb_Message*)upb_Arena_Malloc(a, size); + if (UPB_UNLIKELY(!msg)) return NULL; + _upb_Message_AlignedMemsetZero(msg, size); + return msg; +} + +// Discards the unknown fields for this message only. +void _upb_Message_DiscardUnknown_shallow(struct upb_Message* msg); + +UPB_NODISCARD UPB_NOINLINE bool UPB_PRIVATE(_upb_Message_AddUnknownSlowPath)( + struct upb_Message* msg, const char* data, size_t len, upb_Arena* arena, + bool alias); + +typedef enum { + // Provided buffer is copied into the message. + kUpb_AddUnknown_Copy = 0, + + // The message will alias the provided buffer. + kUpb_AddUnknown_Alias = 1, + + // The message will alias the provided buffer, and we may merge the data with + // the immediately preceding unknown field if possible. + kUpb_AddUnknown_AliasAllowMerge = 2, +} upb_AddUnknownMode; + +UPB_NODISCARD UPB_INLINE bool UPB_PRIVATE( + _upb_Message_TryAddUnknownAliasAllowMerge)(struct upb_Message* msg, + const char* data, size_t len, + upb_Arena* arena, + upb_AddUnknownMode mode) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(mode == kUpb_AddUnknown_AliasAllowMerge); + // Aliasing parse of a message with sequential unknown fields is a simple + // pointer bump, so inline it. + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (in && in->size) { + upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; + if (upb_TaggedAuxPtr_IsUnknownStringView(ptr)) { + upb_StringView* existing = upb_TaggedPtrAux_StringViewRepr(ptr); + // Fast path if the field we're adding is immediately after the last + // added unknown field. + // + // The caller has guaranteed to us, by passing + // kUpb_AddUnknown_AliasAllowMerge, that there is no risk that these two + // regions of memory are from different objects that are contiguous in + // memory by coincidence. + if (existing->data + existing->size == data) { + existing->size += len; + return true; + } + } + } + return false; +} + +// Adds unknown data (serialized protobuf data) to the given message. The data +// must represent one or more complete and well formed proto fields. +// +// If `alias_base` is NULL, the bytes from `data` will be copied into the +// destination arena. Otherwise it must be a pointer to the beginning of the +// buffer that `data` points into, which signals that the message must alias +// the bytes instead of copying them. The value of `alias_base` is also used +// to mark the boundary of the buffer, so that we do not inappropriately +// coalesce two buffers that are separate objects but happen to be contiguous +// in memory. +UPB_NODISCARD UPB_INLINE bool UPB_PRIVATE(_upb_Message_AddUnknown)( + struct upb_Message* msg, const char* data, size_t len, upb_Arena* arena, + upb_AddUnknownMode mode) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (mode == kUpb_AddUnknown_AliasAllowMerge && + UPB_PRIVATE(_upb_Message_TryAddUnknownAliasAllowMerge)(msg, data, len, + arena, mode)) { + return true; + } + return UPB_PRIVATE(_upb_Message_AddUnknownSlowPath)( + msg, data, len, arena, mode != kUpb_AddUnknown_Copy); +} + +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. Data when concatenated together +// must represent one or more complete and well formed proto fields, but the +// individual spans may point only to partial fields. +UPB_NODISCARD bool UPB_PRIVATE(_upb_Message_AddUnknownV)( + struct upb_Message* msg, upb_Arena* arena, upb_StringView data[], + size_t count); + +// Ensures at least one slot is available in the aux_data of this message. +// Returns false if a reallocation is needed to satisfy the request, and fails. +UPB_NODISCARD bool UPB_PRIVATE(_upb_Message_ReserveSlot)( + struct upb_Message* msg, upb_Arena* arena); + +typedef enum { + kUpb_MessageUnknownType_StringView, + kUpb_MessageUnknownType_NonCanonicalExtension, +} upb_MessageUnknownType; + +// Represents an unknown field in a message, whether it's in a serialized +// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format. +typedef struct upb_MessageUnknown { + uint8_t type; + union { + upb_StringView bytes; + const upb_Extension* extension; + } value; +} upb_MessageUnknown; + +typedef enum upb_Message_DeleteUnknownStatus { + kUpb_DeleteUnknown_DeletedLast, + kUpb_DeleteUnknown_IterUpdated, + kUpb_DeleteUnknown_AllocFail, +} upb_Message_DeleteUnknownStatus; + +#define kUpb_Message_UnknownBegin 0 +#define kUpb_Message_ExtensionBegin 0 + +UPB_INLINE bool upb_Message_NextUnknown(const struct upb_Message* msg, + upb_StringView* data, uintptr_t* iter) { + const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + size_t i = *iter; + if (in) { + while (i < in->size) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++]; + if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { + *data = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr); + *iter = i; + return true; + } + } + } + data->size = 0; + data->data = NULL; + *iter = i; + return false; +} + +UPB_INLINE bool upb_Message_NextExtension(const struct upb_Message* msg, + const upb_MiniTableExtension** out_e, + upb_MessageValue* out_v, + uintptr_t* iter) { + const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + uintptr_t i = *iter; + if (in) { + while (i < in->size) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + const upb_Extension* ext = + upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + + // Empty repeated fields or maps semantically don't exist. + if (UPB_PRIVATE(_upb_Extension_IsEmpty)(ext)) continue; + + *out_e = ext->ext; + *out_v = ext->data; + *iter = i; + return true; + } + } + } + *iter = i; + + return false; +} + +UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)( + const struct upb_Message* msg, const upb_MiniTableExtension** out_e, + upb_MessageValue* out_v, uintptr_t* iter) { + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return false; + uintptr_t i = *iter; + uint32_t size = in->size; + while (i < size) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[size - 1 - i]; + i++; + if (!upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + continue; + } + const upb_Extension* ext = upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + + // Empty repeated fields or maps semantically don't exist. + if (UPB_PRIVATE(_upb_Extension_IsEmpty)(ext)) continue; + + *out_e = ext->ext; + *out_v = ext->data; + *iter = i; + return true; + } + *iter = i; + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MESSAGE_H_ */ + +// Must be last. + +#if defined(__GNUC__) && !defined(__clang__) +// GCC raises incorrect warnings in these functions. It thinks that we are +// overrunning buffers, but we carefully write the functions in this file to +// guarantee that this is impossible. GCC gets this wrong due it its failure +// to perform constant propagation as we expect: +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217 +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226 +// +// Unfortunately this also indicates that GCC is not optimizing away the +// switch() in cases where it should be, compromising the performance. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#if __GNUC__ >= 11 +#pragma GCC diagnostic ignored "-Wstringop-overread" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// LINT.IfChange(presence_logic) + +// Hasbit access /////////////////////////////////////////////////////////////// + +UPB_INLINE bool UPB_PRIVATE(_upb_Message_GetHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const uint16_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + return (*UPB_PTR_AT(msg, offset, const char) & mask) != 0; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const uint16_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + (*UPB_PTR_AT(msg, offset, char)) |= mask; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearHasbit)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const uint16_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f); + const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f); + + (*UPB_PTR_AT(msg, offset, char)) &= ~mask; +} + +// Oneof case access /////////////////////////////////////////////////////////// + +UPB_INLINE uint32_t* UPB_PRIVATE(_upb_Message_OneofCasePtr)( + struct upb_Message* msg, const upb_MiniTableField* f) { + return UPB_PTR_AT(msg, UPB_PRIVATE(_upb_MiniTableField_OneofOffset)(f), + uint32_t); +} + +UPB_INLINE uint32_t UPB_PRIVATE(_upb_Message_GetOneofCase)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + const uint32_t* ptr = + UPB_PRIVATE(_upb_Message_OneofCasePtr)((struct upb_Message*)msg, f); + + return *ptr; +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetOneofCase)( + struct upb_Message* msg, const upb_MiniTableField* f) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + + *ptr = upb_MiniTableField_Number(f); +} + +// Returns true if the given field is the current oneof case. +// Does nothing if it is not the current oneof case. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_ClearOneofCase)( + struct upb_Message* msg, const upb_MiniTableField* f) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + + if (*ptr != upb_MiniTableField_Number(f)) return false; + *ptr = 0; + return true; +} + +UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( + const struct upb_Message* message, const upb_MiniTableField* oneof_field) { + UPB_ASSUME(upb_MiniTableField_IsInOneof(oneof_field)); + return UPB_PRIVATE(_upb_Message_GetOneofCase)(message, oneof_field); +} + +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const struct upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f) { + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return NULL; + } + return upb_MiniTable_FindFieldByNumber(m, field_number); +} + +// LINT.ThenChange(GoogleInternalName2) + +// Returns false if the message is missing any of its required fields. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_IsInitializedShallow)( + const struct upb_Message* msg, const upb_MiniTable* m) { + uint64_t bits; + memcpy(&bits, msg + 1, sizeof(bits)); + bits = upb_BigEndian64(bits); + return (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~bits) == 0; +} + +// LINT.IfChange(message_raw_fields) +UPB_INLINE void* UPB_PRIVATE(_upb_Message_MutableDataPtr)( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (char*)msg + f->UPB_ONLYBITS(offset); +} + +UPB_INLINE const void* UPB_PRIVATE(_upb_Message_DataPtr)( + const struct upb_Message* msg, const upb_MiniTableField* f) { + return (const char*)msg + f->UPB_ONLYBITS(offset); +} + +UPB_INLINE void UPB_PRIVATE(_upb_Message_SetPresence)( + struct upb_Message* msg, const upb_MiniTableField* f) { + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + UPB_PRIVATE(_upb_Message_SetHasbit)(msg, f); + } else if (upb_MiniTableField_IsInOneof(f)) { + UPB_PRIVATE(_upb_Message_SetOneofCase)(msg, f); + } +} + +UPB_INLINE_IF_NOT_GCC void UPB_PRIVATE(_upb_MiniTableField_DataCopy)( + const upb_MiniTableField* f, void* to, const void* from) { + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: + memcpy(to, from, 1); + return; + case kUpb_FieldRep_4Byte: + memcpy(to, from, 4); + return; + case kUpb_FieldRep_8Byte: + memcpy(to, from, 8); + return; + case kUpb_FieldRep_StringView: { + memcpy(to, from, sizeof(upb_StringView)); + return; + } + } + UPB_UNREACHABLE(); +} +// LINT.ThenChange(//depot/google3/third_party/upb/bits/golang/message.go:message_raw_fields) + +UPB_INLINE_IF_NOT_GCC bool UPB_PRIVATE(_upb_MiniTableField_DataEquals)( + const upb_MiniTableField* f, const void* a, const void* b) { + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: + return memcmp(a, b, 1) == 0; + case kUpb_FieldRep_4Byte: + return memcmp(a, b, 4) == 0; + case kUpb_FieldRep_8Byte: + return memcmp(a, b, 8) == 0; + case kUpb_FieldRep_StringView: { + const upb_StringView sa = *(const upb_StringView*)a; + const upb_StringView sb = *(const upb_StringView*)b; + return upb_StringView_IsEqual(sa, sb); + } + } + UPB_UNREACHABLE(); +} + +UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_DataClear)( + const upb_MiniTableField* f, void* val) { + const char zero[16] = {0}; + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, zero); +} + +UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_DataIsZero)( + const upb_MiniTableField* f, const void* val) { + const char zero[16] = {0}; + return UPB_PRIVATE(_upb_MiniTableField_DataEquals)(f, val, zero); +} + +// Here we define universal getter/setter functions for message fields. +// These look very branchy and inefficient, but as long as the MiniTableField +// values are known at compile time, all the branches are optimized away and +// we are left with ideal code. This can happen either through through +// literals or UPB_ASSUME(): +// +// // Via struct literals. +// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { +// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; +// // All value in "field" are compile-time known. +// upb_Message_SetBaseField(msg, &field, &value); +// } +// +// // Via UPB_ASSUME(). +// UPB_INLINE bool upb_Message_SetBool(upb_Message* msg, +// const upb_MiniTableField* field, +// bool value, upb_Arena* a) { +// UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool); +// UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(field) == +// kUpb_FieldRep_1Byte); +// upb_Message_SetField(msg, field, &value, a); +// } +// +// As a result, we can use these universal getters/setters for *all* message +// accessors: generated code, MiniTable accessors, and reflection. The only +// exception is the binary encoder/decoder, which need to be a bit more clever +// about how they read/write the message data, for efficiency. +// +// These functions work on both extensions and non-extensions. If the field +// of a setter is known to be a non-extension, the arena may be NULL and the +// returned bool value may be ignored since it will always succeed. + +UPB_API_INLINE bool upb_Message_HasBaseField(const struct upb_Message* msg, + const upb_MiniTableField* field) { + UPB_ASSERT(upb_MiniTableField_HasPresence(field)); + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if (upb_MiniTableField_IsInOneof(field)) { + return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, field) == + upb_MiniTableField_Number(field); + } else { + return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, field); + } +} + +UPB_API_INLINE bool upb_Message_HasExtension(const struct upb_Message* msg, + const upb_MiniTableExtension* e) { + UPB_ASSERT(upb_MiniTableField_HasPresence(&e->UPB_PRIVATE(field))); + return UPB_PRIVATE(_upb_Message_Getext)(msg, e) != NULL; +} + +UPB_FORCEINLINE void _upb_Message_GetNonExtensionField( + const struct upb_Message* msg, const upb_MiniTableField* field, + const void* default_val, void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if ((upb_MiniTableField_IsInOneof(field) || + !UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(field, default_val)) && + !upb_Message_HasBaseField(msg, field)) { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(field, val, default_val); + return; + } + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (field, val, UPB_PRIVATE(_upb_Message_DataPtr)(msg, field)); +} + +UPB_INLINE void _upb_Message_GetExtensionField( + const struct upb_Message* msg, const upb_MiniTableExtension* mt_ext, + const void* default_val, void* val) { + const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getext)(msg, mt_ext); + const upb_MiniTableField* f = &mt_ext->UPB_PRIVATE(field); + UPB_ASSUME(upb_MiniTableField_IsExtension(f)); + + if (ext) { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, &ext->data); + } else { + UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, val, default_val); + } +} + +// NOTE: The default_val is only used for fields that support presence. +// For repeated/map fields, the resulting upb_Array*/upb_Map* can be NULL if a +// upb_Array/upb_Map has not been allocated yet. Array/map fields do not have +// presence, so this is semantically identical to a pointer to an empty +// array/map, and must be treated the same for all semantic purposes. +UPB_API_INLINE upb_MessageValue upb_Message_GetField( + const struct upb_Message* msg, const upb_MiniTableField* field, + upb_MessageValue default_val) { + upb_MessageValue ret; + if (upb_MiniTableField_IsExtension(field)) { + _upb_Message_GetExtensionField(msg, (upb_MiniTableExtension*)field, + &default_val, &ret); + } else { + _upb_Message_GetNonExtensionField(msg, field, &default_val, &ret); + } + return ret; +} + +UPB_API_INLINE void upb_Message_SetBaseField(struct upb_Message* msg, + const upb_MiniTableField* f, + const void* val) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSUME(!upb_MiniTableField_IsExtension(f)); + UPB_PRIVATE(_upb_Message_SetPresence)(msg, f); + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (f, UPB_PRIVATE(_upb_Message_MutableDataPtr)(msg, f), val); +} + +UPB_API_INLINE bool upb_Message_SetExtension(struct upb_Message* msg, + const upb_MiniTableExtension* e, + const void* val, upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(a); + upb_Extension* ext = + UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, e, a); + if (!ext) return false; + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (&e->UPB_PRIVATE(field), &ext->data, val); + return true; +} + +UPB_API_INLINE bool UPB_PRIVATE(_upb_Message_SetNonCanonicalExtension)( + struct upb_Message* msg, const upb_MiniTableExtension* e, const void* val, + upb_Arena* a) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSERT(a); + upb_Extension* ext = + UPB_PRIVATE(_upb_Message_CreateNonCanonicalExtension)(msg, e, a); + if (!ext) return false; + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (&e->UPB_PRIVATE(field), &ext->data, val); + return true; +} + +// Sets the value of the given field in the given msg. The return value is true +// if the operation completed successfully, or false if memory allocation +// failed. +UPB_INLINE bool UPB_PRIVATE(_upb_Message_SetField)(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_MessageValue val, + upb_Arena* a) { + if (upb_MiniTableField_IsExtension(f)) { + const upb_MiniTableExtension* ext = (const upb_MiniTableExtension*)f; + return upb_Message_SetExtension(msg, ext, &val, a); + } else { + upb_Message_SetBaseField(msg, f, &val); + return true; + } +} + +UPB_API_INLINE const upb_Array* upb_Message_GetArray( + const struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* ret; + const upb_Array* default_val = NULL; + _upb_Message_GetNonExtensionField(msg, f, &default_val, &ret); + return ret; +} + +UPB_API_INLINE bool upb_Message_GetBool(const struct upb_Message* msg, + const upb_MiniTableField* f, + bool default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Bool); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_1Byte); + upb_MessageValue def; + def.bool_val = default_val; + return upb_Message_GetField(msg, f, def).bool_val; +} + +UPB_API_INLINE double upb_Message_GetDouble(const struct upb_Message* msg, + const upb_MiniTableField* f, + double default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Double); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.double_val = default_val; + return upb_Message_GetField(msg, f, def).double_val; +} + +UPB_API_INLINE float upb_Message_GetFloat(const struct upb_Message* msg, + const upb_MiniTableField* f, + float default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Float); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.float_val = default_val; + return upb_Message_GetField(msg, f, def).float_val; +} + +UPB_API_INLINE int32_t upb_Message_GetInt32(const struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int32 || + upb_MiniTableField_CType(f) == kUpb_CType_Enum); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.int32_val = default_val; + return upb_Message_GetField(msg, f, def).int32_val; +} + +UPB_API_INLINE int64_t upb_Message_GetInt64(const struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.int64_val = default_val; + return upb_Message_GetField(msg, f, def).int64_val; +} + +UPB_API_INLINE const struct upb_Map* upb_Message_GetMap( + const struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(f); + struct upb_Map* ret; + const struct upb_Map* default_val = NULL; + _upb_Message_GetNonExtensionField(msg, f, &default_val, &ret); + return ret; +} + +UPB_API_INLINE const struct upb_Message* upb_Message_GetMessage( + const struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + upb_MessageValue def; + def.msg_val = NULL; + return upb_Message_GetField(msg, f, def).msg_val; +} + +UPB_API_INLINE upb_Array* upb_Message_GetMutableArray( + struct upb_Message* msg, const upb_MiniTableField* f) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + return (upb_Array*)upb_Message_GetArray(msg, f); +} + +UPB_API_INLINE struct upb_Map* upb_Message_GetMutableMap( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (struct upb_Map*)upb_Message_GetMap(msg, f); +} + +UPB_API_INLINE struct upb_Message* upb_Message_GetMutableMessage( + struct upb_Message* msg, const upb_MiniTableField* f) { + return (struct upb_Message*)upb_Message_GetMessage(msg, f); +} + +UPB_NODISCARD UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray( + struct upb_Message* msg, const upb_MiniTableField* f, upb_Arena* arena) { + UPB_ASSERT(arena); + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* array = upb_Message_GetMutableArray(msg, f); + if (!array) { + array = UPB_PRIVATE(_upb_Array_New)( + arena, _UPB_ARRAY_DEFAULT_INITIAL_SIZE, + UPB_PRIVATE(_upb_MiniTableField_ElemSizeLg2)(f)); + // Check again due to: https://godbolt.org/z/7WfaoKG1r + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_MessageValue val; + val.array_val = array; + UPB_PRIVATE(_upb_Message_SetField)(msg, f, val, arena); + } + return array; +} + +UPB_NODISCARD UPB_INLINE struct upb_Map* _upb_Message_GetOrCreateMutableMap( + struct upb_Message* msg, const upb_MiniTableField* field, size_t key_size, + size_t val_size, upb_Arena* arena) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field); + struct upb_Map* map = NULL; + struct upb_Map* default_map_value = NULL; + _upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map); + if (!map) { + map = _upb_Map_New(arena, key_size, val_size); + // Check again due to: https://godbolt.org/z/7WfaoKG1r + UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(field); + upb_Message_SetBaseField(msg, field, &map); + } + return map; +} + +UPB_NODISCARD UPB_API_INLINE struct upb_Map* upb_Message_GetOrCreateMutableMap( + struct upb_Message* msg, const upb_MiniTable* map_entry_mini_table, + const upb_MiniTableField* f, upb_Arena* arena) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + const upb_MiniTableField* map_entry_key_field = + &map_entry_mini_table->UPB_ONLYBITS(fields)[0]; + const upb_MiniTableField* map_entry_value_field = + &map_entry_mini_table->UPB_ONLYBITS(fields)[1]; + return _upb_Message_GetOrCreateMutableMap( + msg, f, _upb_Map_CTypeSize(upb_MiniTableField_CType(map_entry_key_field)), + _upb_Map_CTypeSize(upb_MiniTableField_CType(map_entry_value_field)), + arena); +} + +UPB_NODISCARD UPB_API_INLINE struct upb_Message* +upb_Message_GetOrCreateMutableMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_Arena* arena) { + UPB_ASSERT(arena); + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(!upb_MiniTableField_IsExtension(f)); + struct upb_Message* sub_message = + *UPB_PTR_AT(msg, f->UPB_ONLYBITS(offset), struct upb_Message*); + if (!sub_message) { + const upb_MiniTable* sub_mini_table = upb_MiniTable_SubMessage(f); + UPB_ASSERT(sub_mini_table); + sub_message = _upb_Message_New(sub_mini_table, arena); + *UPB_PTR_AT(msg, f->UPB_ONLYBITS(offset), struct upb_Message*) = + sub_message; + UPB_PRIVATE(_upb_Message_SetPresence)(msg, f); + } + return sub_message; +} + +UPB_API_INLINE upb_StringView +upb_Message_GetString(const struct upb_Message* msg, + const upb_MiniTableField* f, upb_StringView default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_String || + upb_MiniTableField_CType(f) == kUpb_CType_Bytes); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_StringView); + + upb_MessageValue def; + def.str_val = default_val; + return upb_Message_GetField(msg, f, def).str_val; +} + +UPB_API_INLINE uint32_t upb_Message_GetUInt32(const struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt32); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + + upb_MessageValue def; + def.uint32_val = default_val; + return upb_Message_GetField(msg, f, def).uint32_val; +} + +UPB_API_INLINE uint64_t upb_Message_GetUInt64(const struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t default_val) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + + upb_MessageValue def; + def.uint64_val = default_val; + return upb_Message_GetField(msg, f, def).uint64_val; +} + +// BaseField Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE void upb_Message_SetBaseFieldBool(struct upb_Message* msg, + const upb_MiniTableField* f, + bool value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Bool); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_1Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldDouble(struct upb_Message* msg, + const upb_MiniTableField* f, + double value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Double); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldFloat(struct upb_Message* msg, + const upb_MiniTableField* f, + float value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Float); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int32 || + upb_MiniTableField_CType(f) == kUpb_CType_Enum); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Int64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + struct upb_Message* value) { + // TODO - Re-enable this assertion. + // UPB_ASSERT(value); + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldArray(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_Array* arr, + const upb_MiniTable* arr_mt) { + UPB_ASSERT(upb_MiniTableField_IsArray(f)); + UPB_ASSERT(arr_mt == upb_MiniTable_SubMessage(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + upb_Message_SetBaseField(msg, f, &arr); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldMap( + struct upb_Message* msg, const upb_MiniTableField* f, struct upb_Map* map, + const upb_MiniTable* map_entry_mt) { + UPB_ASSERT(upb_MiniTableField_IsMap(f)); + UPB_ASSERT(map_entry_mt == upb_MiniTable_MapEntrySubMessage(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_NativePointer); + upb_Message_SetBaseField(msg, f, &map); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldString(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_String || + upb_MiniTableField_CType(f) == kUpb_CType_Bytes); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == + kUpb_FieldRep_StringView); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt32); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value) { + UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_UInt64); + UPB_ASSUME(upb_MiniTableField_IsScalar(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_8Byte); + upb_Message_SetBaseField(msg, f, &value); +} + +UPB_API_INLINE void upb_Message_SetClosedEnum(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value) { + UPB_ASSERT(upb_MiniTableField_IsClosedEnum(f)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) == kUpb_FieldRep_4Byte); + UPB_ASSERT(upb_MiniTableEnum_CheckValue(upb_MiniTable_GetSubEnumTable(f), + (uint32_t)value)); + upb_Message_SetBaseField(msg, f, &value); +} + +// Extension Setters /////////////////////////////////////////////////////////// + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionMessage( + struct upb_Message* msg, const upb_MiniTableExtension* e, + struct upb_Message* value, upb_Arena* a) { + UPB_ASSERT(value); + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionBool( + struct upb_Message* msg, const upb_MiniTableExtension* e, bool value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Bool); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_1Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionDouble( + struct upb_Message* msg, const upb_MiniTableExtension* e, double value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Double); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionFloat( + struct upb_Message* msg, const upb_MiniTableExtension* e, float value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Float); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, int32_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int32 || + upb_MiniTableExtension_CType(e) == kUpb_CType_Enum); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, int64_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionString( + struct upb_Message* msg, const upb_MiniTableExtension* e, + upb_StringView value, upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_String || + upb_MiniTableExtension_CType(e) == kUpb_CType_Bytes); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_StringView); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionUInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint32_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt32); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionUInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint64_t value, + upb_Arena* a) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + return upb_Message_SetExtension(msg, e, &value, a); +} + +// Universal Setters /////////////////////////////////////////////////////////// + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetBool( + struct upb_Message* msg, const upb_MiniTableField* f, bool value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionBool( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldBool(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetDouble( + struct upb_Message* msg, const upb_MiniTableField* f, double value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionDouble( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldDouble(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetFloat( + struct upb_Message* msg, const upb_MiniTableField* f, float value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionFloat( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldFloat(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetInt32( + struct upb_Message* msg, const upb_MiniTableField* f, int32_t value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionInt32( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldInt32(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetInt64( + struct upb_Message* msg, const upb_MiniTableField* f, int64_t value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionInt64( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldInt64(msg, f, value), true); +} + +// Sets the value of a message-typed field. The mini_tables of `msg` and +// `value` must have been linked for this to work correctly. +UPB_API_INLINE void upb_Message_SetMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + struct upb_Message* value) { + UPB_ASSERT(!upb_MiniTableField_IsExtension(f)); + upb_Message_SetBaseFieldMessage(msg, f, value); +} + +// Sets the value of a `string` or `bytes` field. The bytes of the value are not +// copied, so it is the caller's responsibility to ensure that they remain valid +// for the lifetime of `msg`. That might be done by copying them into the given +// arena, or by fusing that arena with the arena the bytes live in, for example. +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetString( + struct upb_Message* msg, const upb_MiniTableField* f, upb_StringView value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionString( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldString(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetUInt32( + struct upb_Message* msg, const upb_MiniTableField* f, uint32_t value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionUInt32( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldUInt32(msg, f, value), true); +} + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetUInt64( + struct upb_Message* msg, const upb_MiniTableField* f, uint64_t value, + upb_Arena* a) { + return upb_MiniTableField_IsExtension(f) + ? upb_Message_SetExtensionUInt64( + msg, (const upb_MiniTableExtension*)f, value, a) + : (upb_Message_SetBaseFieldUInt64(msg, f, value), true); +} + +UPB_API_INLINE void upb_Message_Clear(struct upb_Message* msg, + const upb_MiniTable* m) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + memset(msg, 0, m->UPB_PRIVATE(size)); + if (in) { + // Reset the internal buffer to empty. + in->size = 0; + } +} + +UPB_API_INLINE void upb_Message_ClearBaseField(struct upb_Message* msg, + const upb_MiniTableField* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f)) { + UPB_PRIVATE(_upb_Message_ClearHasbit)(msg, f); + } else if (upb_MiniTableField_IsInOneof(f)) { + uint32_t* ptr = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, f); + if (*ptr != upb_MiniTableField_Number(f)) return; + *ptr = 0; + } + const char zeros[16] = {0}; + UPB_PRIVATE(_upb_MiniTableField_DataCopy) + (f, UPB_PRIVATE(_upb_Message_MutableDataPtr)(msg, f), zeros); +} + +UPB_API_INLINE void upb_Message_ClearExtension( + struct upb_Message* msg, const upb_MiniTableExtension* e) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return; + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { + const upb_Extension* ext = + upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); + if (ext->ext == e) { + in->aux_data[i] = upb_TaggedAuxPtr_Null(); + return; + } + } + } +} + +UPB_API_INLINE void upb_Message_ClearOneof(struct upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return; + } + + const upb_MiniTableField* field = + upb_MiniTable_FindFieldByNumber(m, field_number); + upb_Message_ClearBaseField(msg, field); +} + +UPB_NODISCARD UPB_API_INLINE void* upb_Message_ResizeArrayUninitialized( + struct upb_Message* msg, const upb_MiniTableField* f, size_t size, + upb_Arena* arena) { + UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(f); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, f, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena)) { + return NULL; + } + return upb_Array_MutableDataPtr(arr); +} + +UPB_API_INLINE bool upb_Message_GetExtensionBool( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + bool default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Bool); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_1Byte); + bool ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE double upb_Message_GetExtensionDouble( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + double default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Double); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + double ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE float upb_Message_GetExtensionFloat( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + float default_val) { + float ret; + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Float); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE int32_t upb_Message_GetExtensionInt32( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + int32_t default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int32 || + upb_MiniTableExtension_CType(e) == kUpb_CType_Enum); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + int32_t ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE int64_t upb_Message_GetExtensionInt64( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + int64_t default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Int64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + int64_t ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE uint32_t upb_Message_GetExtensionUInt32( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + uint32_t default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt32); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_4Byte); + uint32_t ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE uint64_t upb_Message_GetExtensionUInt64( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + uint64_t default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_UInt64); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_8Byte); + uint64_t ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE upb_StringView upb_Message_GetExtensionString( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + upb_StringView default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_String || + upb_MiniTableExtension_CType(e) == kUpb_CType_Bytes); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + kUpb_FieldRep_StringView); + upb_StringView ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE struct upb_Message* upb_Message_GetExtensionMessage( + const struct upb_Message* msg, const upb_MiniTableExtension* e, + struct upb_Message* default_val) { + UPB_ASSUME(upb_MiniTableExtension_CType(e) == kUpb_CType_Message); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(e) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + struct upb_Message* ret; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +// Repeated +UPB_API_INLINE const upb_Array* upb_Message_GetExtensionArray( + const struct upb_Message* msg, const upb_MiniTableExtension* e) { + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(&e->UPB_PRIVATE(field)) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsArray(&e->UPB_PRIVATE(field))); + UPB_ASSUME(e->UPB_PRIVATE(field).presence == 0); + upb_Array* ret; + const upb_Array* default_val = NULL; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +UPB_API_INLINE upb_Array* upb_Message_GetExtensionMutableArray( + struct upb_Message* msg, const upb_MiniTableExtension* e) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(&e->UPB_PRIVATE(field)) == + kUpb_FieldRep_NativePointer); + UPB_ASSUME(upb_MiniTableField_IsArray(&e->UPB_PRIVATE(field))); + UPB_ASSUME(e->UPB_PRIVATE(field).presence == 0); + upb_Array* ret; + upb_Array* default_val = NULL; + _upb_Message_GetExtensionField(msg, e, &default_val, &ret); + return ret; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + +#endif // UPB_MESSAGE_INTERNAL_ACCESSORS_H_ + +#ifndef UPB_MESSAGE_MAP_H_ +#define UPB_MESSAGE_MAP_H_ + +#include + + +// Must be last. + +typedef struct upb_Map upb_Map; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new map on the given arena with the given key/value size. +UPB_NODISCARD UPB_API upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, + upb_CType value_type); + +// Returns the number of entries in the map. +UPB_API size_t upb_Map_Size(const upb_Map* map); + +// Stores a value for the given key into |*val| (or the zero value if the key is +// not present). Returns whether the key was present. The |val| pointer may be +// NULL, in which case the function tests whether the given key is present. +UPB_API bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +// Returns a mutable pointer to the value for the given key. Returns NULL if the +// key is not present. +// This function is only legal to call for maps that contain messages. +UPB_API struct upb_Message* upb_Map_GetMutable(upb_Map* map, + upb_MessageValue key); + +// Removes all entries in the map. +UPB_API void upb_Map_Clear(upb_Map* map); + +// Sets the given key to the given value, returning whether the key was inserted +// or replaced. If the key was inserted, then any existing iterators will be +// invalidated. +UPB_NODISCARD UPB_API upb_MapInsertStatus upb_Map_Insert(upb_Map* map, + upb_MessageValue key, + upb_MessageValue val, + upb_Arena* arena); + +// Sets the given key to the given value. Returns false if memory allocation +// failed. If the key is newly inserted, then any existing iterators will be +// invalidated. +UPB_NODISCARD UPB_API_INLINE bool upb_Map_Set(upb_Map* map, + upb_MessageValue key, + upb_MessageValue val, + upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} + +// Deletes this key from the table. Returns true if the key was present. +// If present and |val| is non-NULL, stores the deleted value. +UPB_API bool upb_Map_Delete(upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +// Map iteration: +// +// size_t iter = kUpb_Map_Begin; +// upb_MessageValue key, val; +// while (upb_Map_Next(map, &key, &val, &iter)) { +// ... +// } + +#define kUpb_Map_Begin ((size_t)-1) + +// Advances to the next entry. Returns false if no more entries are present. +// Otherwise returns true and populates both *key and *value. +UPB_API bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter); + +// Sets the value for the entry pointed to by iter. +// WARNING: this does not currently work for string values! +UPB_API void upb_Map_SetEntryValue(upb_Map* map, size_t iter, + upb_MessageValue val); + +// DEPRECATED iterator, slated for removal. + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * } + */ + +// Advances to the next entry. Returns false if no more entries are present. +UPB_API bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); + +// Returns true if the iterator still points to a valid entry, or false if the +// iterator is past the last element. It is an error to call this function with +// kUpb_Map_Begin (you must call next() at least once first). +UPB_API bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + +// Returns the key and value for this entry of the map. +UPB_API upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +UPB_API upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + +// Mark a map and all of its descendents as frozen/immutable. +// If the map values are messages then |m| must point to the minitable for +// those messages. Otherwise |m| must be NULL. +UPB_API void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m); + +// Returns whether a map has been frozen. +UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MAP_H_ */ + +// Public APIs for message operations that do not depend on the schema. +// +// MiniTable-based accessors live in accessors.h. + +#ifndef UPB_MESSAGE_MESSAGE_H_ +#define UPB_MESSAGE_MESSAGE_H_ + +#include +#include + + +// Must be last. + +typedef struct upb_Message upb_Message; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new message with the given mini_table on the given arena. +UPB_NODISCARD UPB_API upb_Message* upb_Message_New(const upb_MiniTable* m, + upb_Arena* arena); + +// +// Unknown data may be stored non-contiguously. Each segment stores a block of +// unknown fields. To iterate over segments: +// +// uintptr_t iter = kUpb_Message_UnknownBegin; +// upb_StringView data; +// while (upb_Message_NextUnknown(msg, &data, &iter)) { +// // Use data +// } +// Iterates in the order unknown fields were parsed. + +#define kUpb_Message_UnknownBegin 0 +#define kUpb_Message_ExtensionBegin 0 + +// TODO: b/510055656 - Legacy API that works with messages that only have +// unknown data in upb_StringView format. Use `upb_Message_NextUnknown2` for +// messages that may have non-canonical extensions. +UPB_INLINE bool upb_Message_NextUnknown(const upb_Message* msg, + upb_StringView* data, uintptr_t* iter); + +UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg) { + const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + if (!in) return false; + for (size_t i = 0; i < in->size; i++) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; + if (tagged_ptr.ptr != 0 && + !upb_TaggedAuxPtr_IsSemanticallyKnown(tagged_ptr)) { + return true; + } + } + return false; +} + +// Removes a segment of unknown data from the message, advancing to the next +// segment. Returns false if the removed segment was at the end of the last +// chunk. +// +// This must be done while iterating: +// +// uintptr_t iter = kUpb_Message_UnknownBegin; +// upb_StringView data; +// // Iterate chunks +// while (upb_Message_NextUnknown(msg, &data, &iter)) { +// // Iterate within a chunk, deleting ranges +// while (ShouldDeleteSubSegment(&data)) { +// // Data now points to the region to be deleted +// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) { +// case kUpb_Message_DeleteUnknown_DeletedLast: return ok; +// case kUpb_Message_DeleteUnknown_IterUpdated: break; +// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated, +// // then data now points to the remaining unknown fields after the +// // region that was just deleted. +// case kUpb_Message_DeleteUnknown_AllocFail: return err; +// } +// } +// } +// +// The range given in `data` must be contained inside the most recently +// returned region. +// +// TODO: b/510055656 - Legacy API that works with messages that only have +// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for +// messages that may have non-canonical extensions. +UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown( + upb_Message* msg, upb_StringView* data, uintptr_t* iter, upb_Arena* arena); + +// Returns the number of extensions present in this message. +size_t upb_Message_ExtensionCount(const upb_Message* msg); + +// Iterates extensions in wire order +UPB_INLINE bool upb_Message_NextExtension(const upb_Message* msg, + const upb_MiniTableExtension** out_e, + upb_MessageValue* out_v, + uintptr_t* iter); + +// Iterates extensions in reverse wire order +UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)( + const struct upb_Message* msg, const upb_MiniTableExtension** out_e, + upb_MessageValue* out_v, uintptr_t* iter); + +// Mark a message and all of its descendents as frozen/immutable. +UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m); + +// Returns whether a message has been frozen. +UPB_API_INLINE bool upb_Message_IsFrozen(const upb_Message* msg); + +#ifdef UPB_TRACING_ENABLED +UPB_API void upb_Message_LogNewMessage(const upb_MiniTable* m, + const upb_Arena* arena); + +UPB_API void upb_Message_SetNewMessageTraceHandler( + void (*handler)(const upb_MiniTable* m, const upb_Arena* arena)); +#endif // UPB_TRACING_ENABLED + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MESSAGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Functions ending in BaseField() take a (upb_MiniTableField*) argument +// and work only on non-extension fields. +// +// Functions ending in Extension() take a (upb_MiniTableExtension*) argument +// and work only on extensions. + +UPB_API_INLINE void upb_Message_Clear(upb_Message* msg, const upb_MiniTable* m); + +UPB_API_INLINE void upb_Message_ClearBaseField(upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE void upb_Message_ClearExtension(upb_Message* msg, + const upb_MiniTableExtension* e); + +UPB_API_INLINE void upb_Message_ClearOneof(upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_HasBaseField(const upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_HasExtension(const upb_Message* msg, + const upb_MiniTableExtension* e); + +UPB_API_INLINE upb_MessageValue +upb_Message_GetField(const upb_Message* msg, const upb_MiniTableField* f, + upb_MessageValue default_val); + +UPB_API_INLINE const upb_Array* upb_Message_GetArray( + const upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE bool upb_Message_GetBool(const upb_Message* msg, + const upb_MiniTableField* f, + bool default_val); + +UPB_API_INLINE double upb_Message_GetDouble(const upb_Message* msg, + const upb_MiniTableField* field, + double default_val); + +UPB_API_INLINE float upb_Message_GetFloat(const upb_Message* msg, + const upb_MiniTableField* f, + float default_val); + +UPB_API_INLINE int32_t upb_Message_GetInt32(const upb_Message* msg, + const upb_MiniTableField* f, + int32_t default_val); + +UPB_API_INLINE int64_t upb_Message_GetInt64(const upb_Message* msg, + const upb_MiniTableField* f, + int64_t default_val); + +UPB_API_INLINE const upb_Map* upb_Message_GetMap(const upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE const upb_Message* upb_Message_GetMessage( + const upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE upb_Array* upb_Message_GetMutableArray( + upb_Message* msg, const upb_MiniTableField* f); + +UPB_API_INLINE upb_Map* upb_Message_GetMutableMap(upb_Message* msg, + const upb_MiniTableField* f); + +UPB_API_INLINE upb_Message* upb_Message_GetMutableMessage( + upb_Message* msg, const upb_MiniTableField* f); + +UPB_NODISCARD UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray( + upb_Message* msg, const upb_MiniTableField* f, upb_Arena* arena); + +UPB_NODISCARD UPB_API_INLINE upb_Map* upb_Message_GetOrCreateMutableMap( + upb_Message* msg, const upb_MiniTable* map_entry_mini_table, + const upb_MiniTableField* f, upb_Arena* arena); + +UPB_NODISCARD UPB_API_INLINE upb_Message* upb_Message_GetOrCreateMutableMessage( + upb_Message* msg, const upb_MiniTableField* f, upb_Arena* arena); + +UPB_API_INLINE upb_StringView +upb_Message_GetString(const upb_Message* msg, const upb_MiniTableField* field, + upb_StringView default_val); + +UPB_API_INLINE uint32_t upb_Message_GetUInt32(const upb_Message* msg, + const upb_MiniTableField* f, + uint32_t default_val); + +UPB_API_INLINE uint64_t upb_Message_GetUInt64(const upb_Message* msg, + const upb_MiniTableField* f, + uint64_t default_val); + +UPB_API_INLINE void upb_Message_SetClosedEnum(upb_Message* msg, + const upb_MiniTableField* f, + int32_t value); + +// BaseField Setters /////////////////////////////////////////////////////////// + +UPB_API_INLINE void upb_Message_SetBaseField(upb_Message* msg, + const upb_MiniTableField* f, + const void* val); + +UPB_API_INLINE void upb_Message_SetBaseFieldBool(struct upb_Message* msg, + const upb_MiniTableField* f, + bool value); + +UPB_API_INLINE void upb_Message_SetBaseFieldDouble(struct upb_Message* msg, + const upb_MiniTableField* f, + double value); + +UPB_API_INLINE void upb_Message_SetBaseFieldFloat(struct upb_Message* msg, + const upb_MiniTableField* f, + float value); + +UPB_API_INLINE void upb_Message_SetBaseFieldInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + int32_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + int64_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldMessage(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_Message* value); + +UPB_API_INLINE void upb_Message_SetBaseFieldArray(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_Array* arr, + const upb_MiniTable* arr_mt); + +UPB_API_INLINE void upb_Message_SetBaseFieldMap( + struct upb_Message* msg, const upb_MiniTableField* f, struct upb_Map* map, + const upb_MiniTable* map_entry_mt); + +UPB_API_INLINE void upb_Message_SetBaseFieldString(struct upb_Message* msg, + const upb_MiniTableField* f, + upb_StringView value); + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt32(struct upb_Message* msg, + const upb_MiniTableField* f, + uint32_t value); + +UPB_API_INLINE void upb_Message_SetBaseFieldUInt64(struct upb_Message* msg, + const upb_MiniTableField* f, + uint64_t value); + +// Extension Getters /////////////////////////////////////////////////////////// +UPB_API_INLINE bool upb_Message_GetExtensionBool( + const upb_Message* msg, const upb_MiniTableExtension* f, bool default_val); + +UPB_API_INLINE double upb_Message_GetExtensionDouble( + const upb_Message* msg, const upb_MiniTableExtension* f, + double default_val); + +UPB_API_INLINE float upb_Message_GetExtensionFloat( + const upb_Message* msg, const upb_MiniTableExtension* f, float default_val); + +UPB_API_INLINE int32_t upb_Message_GetExtensionInt32( + const upb_Message* msg, const upb_MiniTableExtension* f, + int32_t default_val); + +UPB_API_INLINE int64_t upb_Message_GetExtensionInt64( + const upb_Message* msg, const upb_MiniTableExtension* f, + int64_t default_val); + +UPB_API_INLINE uint32_t upb_Message_GetExtensionUInt32( + const upb_Message* msg, const upb_MiniTableExtension* f, + uint32_t default_val); + +UPB_API_INLINE uint64_t upb_Message_GetExtensionUInt64( + const upb_Message* msg, const upb_MiniTableExtension* f, + uint64_t default_val); + +UPB_API_INLINE upb_StringView upb_Message_GetExtensionString( + const upb_Message* msg, const upb_MiniTableExtension* f, + upb_StringView default_val); + +UPB_API_INLINE upb_Message* upb_Message_GetExtensionMessage( + const upb_Message* msg, const upb_MiniTableExtension* f, + struct upb_Message* default_val); + +UPB_API_INLINE const upb_Array* upb_Message_GetExtensionArray( + const upb_Message* msg, const upb_MiniTableExtension* f); + +UPB_API_INLINE upb_Array* upb_Message_GetExtensionMutableArray( + upb_Message* msg, const upb_MiniTableExtension* f); + +// Extension Setters /////////////////////////////////////////////////////////// + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtension( + upb_Message* msg, const upb_MiniTableExtension* e, const void* value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionMessage( + struct upb_Message* msg, const upb_MiniTableExtension* e, + struct upb_Message* value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionBool( + struct upb_Message* msg, const upb_MiniTableExtension* e, bool value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionDouble( + struct upb_Message* msg, const upb_MiniTableExtension* e, double value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionFloat( + struct upb_Message* msg, const upb_MiniTableExtension* e, float value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, int32_t value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, int64_t value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionString( + struct upb_Message* msg, const upb_MiniTableExtension* e, + upb_StringView value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionUInt32( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint32_t value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetExtensionUInt64( + struct upb_Message* msg, const upb_MiniTableExtension* e, uint64_t value, + upb_Arena* a); + +// Universal Setters /////////////////////////////////////////////////////////// + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetBool( + upb_Message* msg, const upb_MiniTableField* f, bool value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetDouble( + upb_Message* msg, const upb_MiniTableField* f, double value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetFloat( + upb_Message* msg, const upb_MiniTableField* f, float value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetInt32( + upb_Message* msg, const upb_MiniTableField* f, int32_t value, upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetInt64( + upb_Message* msg, const upb_MiniTableField* f, int64_t value, upb_Arena* a); + +// Unlike the other similarly-named setters, this function can only be +// called on base fields. Prefer upb_Message_SetBaseFieldMessage(). +UPB_API_INLINE void upb_Message_SetMessage(upb_Message* msg, + const upb_MiniTableField* f, + upb_Message* value); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetString( + upb_Message* msg, const upb_MiniTableField* f, upb_StringView value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetUInt32( + upb_Message* msg, const upb_MiniTableField* f, uint32_t value, + upb_Arena* a); + +UPB_NODISCARD UPB_API_INLINE bool upb_Message_SetUInt64( + upb_Message* msg, const upb_MiniTableField* f, uint64_t value, + upb_Arena* a); + +//////////////////////////////////////////////////////////////////////////////// + +UPB_NODISCARD UPB_API_INLINE void* upb_Message_ResizeArrayUninitialized( + upb_Message* msg, const upb_MiniTableField* f, size_t size, + upb_Arena* arena); + +UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( + const upb_Message* message, const upb_MiniTableField* oneof_field); + +// For a field `f` which is in a oneof, return the field of that +// oneof that is actually set (or NULL if none). +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f); + +// Updates a map entry given an entry message. +UPB_NODISCARD bool upb_Message_SetMapEntry(upb_Map* map, + const upb_MiniTableField* field, + upb_Message* map_entry_message, + upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__cplusplus) +// Temporary overloads for functions whose signature has recently changed. +UPB_DEPRECATE_AND_INLINE() +UPB_NODISCARD inline upb_Message* upb_Message_GetOrCreateMutableMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* f, upb_Arena* arena) { + return upb_Message_GetOrCreateMutableMessage(msg, f, arena); +} + +UPB_DEPRECATE_AND_INLINE() +inline void upb_Message_SetClosedEnum(upb_Message* msg, + const upb_MiniTable* msg_mini_table, + const upb_MiniTableField* f, + int32_t value) { + upb_Message_SetClosedEnum(msg, f, value); +} + +UPB_DEPRECATE_AND_INLINE() +UPB_NODISCARD +inline bool upb_Message_SetMapEntry(upb_Map* map, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* map_entry_message, + upb_Arena* arena) { + return upb_Message_SetMapEntry(map, field, map_entry_message, arena); +} +#endif + + +#endif // UPB_MESSAGE_ACCESSORS_H_ + +// These functions are only used by generated code. + +#ifndef UPB_MESSAGE_MAP_GENCODE_UTIL_H_ +#define UPB_MESSAGE_MAP_GENCODE_UTIL_H_ + +// This header file is referenced by multiple files. Leave it empty. +// TODO: b/399481227 - Remove this header file, after all the references are +// cleaned up. +#endif /* UPB_MESSAGE_MAP_GENCODE_UTIL_H_ */ + +#ifndef UPB_MINI_TABLE_DECODE_H_ +#define UPB_MINI_TABLE_DECODE_H_ + +#include + + +#ifndef UPB_BASE_STATUS_H_ +#define UPB_BASE_STATUS_H_ + +#include + +// Must be last. + +#define _kUpb_Status_MaxMessage 511 + +typedef struct { + bool ok; + char msg[_kUpb_Status_MaxMessage]; // Error message; NULL-terminated. +} upb_Status; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const char* upb_Status_ErrorMessage(const upb_Status* status); +UPB_API bool upb_Status_IsOk(const upb_Status* status); + +// These are no-op if |status| is NULL. +UPB_API void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STATUS_H_ */ + +#ifndef UPB_MINI_TABLE_SUB_H_ +#define UPB_MINI_TABLE_SUB_H_ + + +// Must be last. + +typedef union upb_MiniTableSub upb_MiniTableSub; + +#ifdef __cplusplus +extern "C" { +#endif + +// Constructors + +UPB_API_INLINE upb_MiniTableSub +upb_MiniTableSub_FromEnum(const upb_MiniTableEnum* subenum); + +UPB_API_INLINE upb_MiniTableSub +upb_MiniTableSub_FromMessage(const upb_MiniTable* submsg); + +// Getters + +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTableSub_Enum( + upb_MiniTableSub sub); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableSub_Message( + upb_MiniTableSub sub); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_SUB_H_ */ + +// Export the newer headers, for legacy users. New users should include the +// more specific headers directly. +// IWYU pragma: begin_exports + +#ifndef UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ +#define UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Builds a upb_MiniTableEnum from an enum mini descriptor. +// The mini descriptor must be for an enum, not a message. +UPB_NODISCARD UPB_API upb_MiniTableEnum* upb_MiniTableEnum_Build( + const char* data, size_t len, upb_Arena* arena, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_BUILD_ENUM_H_ + +// Functions for linking MiniTables together once they are built from a +// MiniDescriptor. +// +// These functions have names like upb_MiniTable_Link() because they operate on +// MiniTables. We put them here, rather than in the mini_table/ directory, +// because they are only needed when building MiniTables from MiniDescriptors. +// The interfaces in mini_table/ assume that MiniTables are immutable. + +#ifndef UPB_MINI_DESCRIPTOR_LINK_H_ +#define UPB_MINI_DESCRIPTOR_LINK_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Links a sub-message field to a MiniTable for that sub-message. If a +// sub-message field is not linked, it will be treated as an unknown field +// during parsing, and setting the field will not be allowed. It is possible +// to link the message field later, at which point it will no longer be treated +// as unknown. However there is no synchronization for this operation, which +// means parallel mutation requires external synchronization. +// Returns success/failure. +UPB_NODISCARD UPB_API bool upb_MiniTable_SetSubMessage( + upb_MiniTable* table, upb_MiniTableField* field, const upb_MiniTable* sub); + +// Links an enum field to a MiniTable for that enum. +// All enum fields must be linked prior to parsing. +// Returns success/failure. +UPB_NODISCARD UPB_API bool upb_MiniTable_SetSubEnum( + upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub); + +// Returns a list of fields that require linking at runtime, to connect the +// MiniTable to its sub-messages and sub-enums. The list of fields will be +// written to the `subs` array, which must have been allocated by the caller +// and must be large enough to hold a list of all fields in the message. +// +// The order of the fields returned by this function is significant: it matches +// the order expected by upb_MiniTable_Link() below. +// +// The return value packs the sub-message count and sub-enum count into a single +// integer like so: +// return (msg_count << 16) | enum_count; +UPB_API uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* mt, + const upb_MiniTableField** subs); + +// Links a message to its sub-messages and sub-enums. The caller must pass +// arrays of sub-tables and sub-enums, in the same length and order as is +// returned by upb_MiniTable_GetSubList() above. However, individual elements +// of the sub_tables may be NULL if those sub-messages were tree shaken. +// +// Returns false if either array is too short, or if any of the tables fails +// to link. +UPB_NODISCARD UPB_API bool upb_MiniTable_Link( + upb_MiniTable* mt, const upb_MiniTable** sub_tables, size_t sub_table_count, + const upb_MiniTableEnum** sub_enums, size_t sub_enum_count); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_LINK_H_ +// IWYU pragma: end_exports + +// Must be last. + +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +#ifdef __cplusplus +extern "C" { +#endif + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +UPB_NODISCARD upb_MiniTable* _upb_MiniTable_Build( + const char* data, size_t len, upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); + +UPB_NODISCARD UPB_API_INLINE upb_MiniTable* upb_MiniTable_Build( + const char* data, size_t len, upb_Arena* arena, upb_Status* status) { + return _upb_MiniTable_Build(data, len, kUpb_MiniTablePlatform_Native, arena, + status); +} + +// Initializes a MiniTableExtension buffer that has already been allocated. +// This is needed by upb_FileDef and upb_MessageDef, which allocate all of the +// extensions together in a single contiguous array. +UPB_NODISCARD const char* _upb_MiniTableExtension_Init( + const char* data, size_t len, upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, upb_MiniTableSub sub, + upb_MiniTablePlatform platform, upb_Status* status); + +UPB_NODISCARD UPB_API_INLINE const char* upb_MiniTableExtension_Init( + const char* data, size_t len, upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, upb_MiniTableSub sub, upb_Status* status) { + return _upb_MiniTableExtension_Init(data, len, ext, extendee, sub, + kUpb_MiniTablePlatform_Native, status); +} + +UPB_NODISCARD UPB_API upb_MiniTableExtension* _upb_MiniTableExtension_Build( + const char* data, size_t len, const upb_MiniTable* extendee, + upb_MiniTableSub sub, upb_MiniTablePlatform platform, upb_Arena* arena, + upb_Status* status); + +UPB_NODISCARD UPB_API_INLINE upb_MiniTableExtension* +upb_MiniTableExtension_Build(const char* data, size_t len, + const upb_MiniTable* extendee, upb_Arena* arena, + upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromMessage(NULL); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +UPB_NODISCARD UPB_API_INLINE upb_MiniTableExtension* +upb_MiniTableExtension_BuildMessage(const char* data, size_t len, + const upb_MiniTable* extendee, + const upb_MiniTable* submsg, + upb_Arena* arena, upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromMessage(submsg); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +UPB_NODISCARD UPB_API_INLINE upb_MiniTableExtension* +upb_MiniTableExtension_BuildEnum(const char* data, size_t len, + const upb_MiniTable* extendee, + const upb_MiniTableEnum* subenum, + upb_Arena* arena, upb_Status* status) { + upb_MiniTableSub sub = upb_MiniTableSub_FromEnum(subenum); + return _upb_MiniTableExtension_Build( + data, len, extendee, sub, kUpb_MiniTablePlatform_Native, arena, status); +} + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated +// upb_grealloc()/upb_gfree(). +// +// The caller owns `*buf` both before and after the call, and must upb_gfree() +// it when it is no longer in use. The function will upb_grealloc() `*buf` as +// necessary, updating `*size` accordingly. +UPB_NODISCARD upb_MiniTable* upb_MiniTable_BuildWithBuf( + const char* data, size_t len, upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, size_t* buf_size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_DECODE_H_ */ + +#ifndef UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ +#define UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; + +// LINT.IfChange +typedef enum { + kUpb_ExtensionRegistryStatus_Ok = 0, + kUpb_ExtensionRegistryStatus_DuplicateEntry = 1, + kUpb_ExtensionRegistryStatus_OutOfMemory = 2, +} upb_ExtensionRegistryStatus; +// LINT.ThenChange(//depot/google3/third_party/upb/rust/sys/mini_table/extension_registry.rs) + +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +UPB_NODISCARD UPB_API upb_ExtensionRegistry* upb_ExtensionRegistry_New( + upb_Arena* arena); + +UPB_NODISCARD UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add( + upb_ExtensionRegistry* r, const upb_MiniTableExtension* e); + +// Adds the given extension info for the array |e| of size |count| into the +// registry. If there are any errors, the entire array is backed out. +// The extensions must outlive the registry. +// Possible errors include OOM or an extension number that already exists. +UPB_NODISCARD upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray( + upb_ExtensionRegistry* r, const upb_MiniTableExtension** e, size_t count); + +// Looks up the extension (if any) defined for message type |t| and field +// number |num|. Returns the extension if found, otherwise NULL. +UPB_API const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); + +// Returns the number of extensions in the registry. For testing/debugging only. +UPB_API size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_EXTENSION_REGISTRY_H_ */ + +#ifndef UPB_MINI_TABLE_FILE_H_ +#define UPB_MINI_TABLE_FILE_H_ + + +#ifndef UPB_MINI_TABLE_INTERNAL_FILE_H_ +#define UPB_MINI_TABLE_INTERNAL_FILE_H_ + +// Must be last. + +struct upb_MiniTableFile { + const struct upb_MiniTable** UPB_PRIVATE(msgs); + const struct upb_MiniTableEnum** UPB_PRIVATE(enums); + const struct upb_MiniTableExtension** UPB_PRIVATE(exts); + int UPB_PRIVATE(msg_count); + int UPB_PRIVATE(enum_count); + int UPB_PRIVATE(ext_count); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE int upb_MiniTableFile_EnumCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(enum_count); +} + +UPB_API_INLINE int upb_MiniTableFile_ExtensionCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(ext_count); +} + +UPB_API_INLINE int upb_MiniTableFile_MessageCount( + const struct upb_MiniTableFile* f) { + return f->UPB_PRIVATE(msg_count); +} + +UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTableFile_Enum( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(enum_count)); + return f->UPB_PRIVATE(enums)[i]; +} + +UPB_API_INLINE const struct upb_MiniTableExtension* upb_MiniTableFile_Extension( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(ext_count)); + return f->UPB_PRIVATE(exts)[i]; +} + +UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableFile_Message( + const struct upb_MiniTableFile* f, int i) { + UPB_ASSERT(i < f->UPB_PRIVATE(msg_count)); + return f->UPB_PRIVATE(msgs)[i]; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_FILE_H_ */ + +// Must be last. + +typedef struct upb_MiniTableFile upb_MiniTableFile; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTableFile_Enum( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_EnumCount(const upb_MiniTableFile* f); + +UPB_API_INLINE const upb_MiniTableExtension* upb_MiniTableFile_Extension( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_ExtensionCount(const upb_MiniTableFile* f); + +UPB_API_INLINE const upb_MiniTable* upb_MiniTableFile_Message( + const upb_MiniTableFile* f, int i); + +UPB_API_INLINE int upb_MiniTableFile_MessageCount(const upb_MiniTableFile* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FILE_H_ */ + +#ifndef UPB_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_ +#define UPB_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UPB_PRIVATE(upb_GeneratedExtensionListEntry) { + const struct upb_MiniTableExtension** start; + const struct upb_MiniTableExtension** stop; + const struct UPB_PRIVATE(upb_GeneratedExtensionListEntry) * next; +} UPB_PRIVATE(upb_GeneratedExtensionListEntry); + +struct upb_GeneratedRegistryRef { + struct upb_Arena* UPB_PRIVATE(arena); + const struct upb_ExtensionRegistry* UPB_PRIVATE(registry); +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_ */ + +// upb_decode: parsing into a upb_Message using a upb_MiniTable. + +#ifndef UPB_WIRE_DECODE_H_ +#define UPB_WIRE_DECODE_H_ + +#include +#include + + +#ifndef GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__ +#define GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__ + +#include + +// Must be last. + +// upb_ErrorHandler is a standard longjmp()-based exception handler for UPB. +// It is used for efficient error handling in cases where longjmp() is safe to +// use, such as in highly performance-sensitive C parsing code. +// +// This structure contains both a jmp_buf and an error code; the error code is +// stored in the structure prior to calling longjmp(). This is necessary because +// per the C standard, it is not possible to store the result of setjmp(), so +// the error code must be passed out-of-band. +// +// upb_ErrorHandler is generally not C++-compatible, because longjmp() does not +// run C++ destructors. So any library that supports upb_ErrorHandler should +// also support a regular return-based error handling mechanism. (Note: we +// could conceivably extend this to take a callback, which could either call +// longjmp() or throw a C++ exception. But since C++ exceptions are forbidden +// by the C++ style guide, there's not likely to be a demand for this.) +// +// To support both cases (longjmp() or return-based status) efficiently, code +// can be written like this: +// +// UPB_ATTR_CONST bool upb_Arena_HasErrHandler(const upb_Arena* a); +// +// INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { +// if (UPB_UNLIKELY(a->end - a->ptr < size)) { +// void* ret = upb_Arena_MallocFallback(a, size); +// UPB_MAYBE_ASSUME(upb_Arena_HasErrHandler(a), ret != NULL); +// return ret; +// } +// void* ret = a->ptr; +// a->ptr += size; +// UPB_ASSUME(ret != NULL); +// return ret; +// } +// +// If the optimizer can prove that an error handler is present, it can assume +// that upb_Arena_Malloc() will not return NULL. + +// We need to standardize on any error code that might be thrown by an error +// handler. + +typedef enum { + kUpb_ErrorCode_Ok = 0, + kUpb_ErrorCode_OutOfMemory = 1, + kUpb_ErrorCode_Malformed = 2, + kUpb_ErrorCode_MaxDepthExceeded = 3, +} upb_ErrorCode; + +typedef struct { + int code; + jmp_buf buf; +} upb_ErrorHandler; + +UPB_INLINE void upb_ErrorHandler_Init(upb_ErrorHandler* e) { + e->code = kUpb_ErrorCode_Ok; +} + +UPB_INLINE UPB_NORETURN void upb_ErrorHandler_ThrowError(upb_ErrorHandler* e, + int code) { + UPB_ASSERT(code != kUpb_ErrorCode_Ok); + e->code = code; + UPB_LONGJMP(e->buf, 1); +} + + +#endif // GOOGLE_UPB_UPB_BASE_ERROR_HANDLER_H__ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// LINT.IfChange +enum { + /* If set, strings and unknown fields will alias the input buffer instead of + * copying into the arena. */ + kUpb_DecodeOption_AliasString = 1, + + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implementing ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, + + /* EXPERIMENTAL: + * + * If set, decoding will enforce UTF-8 validation for string fields, even for + * proto2 or fields with `features.utf8_validation = NONE`. Normally, only + * proto3 string fields will be validated for UTF-8. Decoding will return + * kUpb_DecodeStatus_BadUtf8 for non-UTF-8 strings, which is the same behavior + * as non-UTF-8 proto3 string fields. + */ + kUpb_DecodeOption_AlwaysValidateUtf8 = 8, + + /* EXPERIMENTAL: + * + * If set, the fasttable decoder will not be used. */ + kUpb_DecodeOption_DisableFastTable = 16, +}; +// LINT.ThenChange(//depot/google3/third_party/upb/rust/wire.rs:decode_status) + +UPB_INLINE uint32_t upb_DecodeOptions_MaxDepth(uint16_t depth) { + return (uint32_t)depth << 16; +} + +uint16_t upb_DecodeOptions_GetEffectiveMaxDepth(uint32_t options); + +// Enforce an upper bound on recursion depth. +UPB_INLINE int upb_Decode_LimitDepth(uint32_t decode_options, uint32_t limit) { + uint32_t max_depth = upb_DecodeOptions_GetEffectiveMaxDepth(decode_options); + if (max_depth > limit) max_depth = limit; + return (int)(upb_DecodeOptions_MaxDepth(max_depth) | + (decode_options & 0xffff)); +} + +// LINT.IfChange +typedef enum { + kUpb_DecodeStatus_Ok = kUpb_ErrorCode_Ok, + kUpb_DecodeStatus_OutOfMemory = + kUpb_ErrorCode_OutOfMemory, // Arena alloc failed + kUpb_DecodeStatus_Malformed = + kUpb_ErrorCode_Malformed, // Wire format was corrupt + kUpb_DecodeStatus_MaxDepthExceeded = + kUpb_ErrorCode_MaxDepthExceeded, // Exceeded upb_DecodeOptions_MaxDepth + + kUpb_DecodeStatus_BadUtf8 = 10, // String field had bad UTF-8 + + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 11, +} upb_DecodeStatus; +// LINT.ThenChange(//depot/google3/third_party/upb/rust/sys/wire/wire.rs:decode_status) + +UPB_NODISCARD UPB_API upb_DecodeStatus upb_Decode( + const char* buf, size_t size, upb_Message* msg, const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, int options, upb_Arena* arena); + +// Same as upb_Decode but with a varint-encoded length prepended. +// On success 'num_bytes_read' will be set to the how many bytes were read, +// on failure the contents of num_bytes_read is undefined. +UPB_NODISCARD UPB_API upb_DecodeStatus upb_DecodeLengthPrefixed( + const char* buf, size_t size, upb_Message* msg, size_t* num_bytes_read, + const upb_MiniTable* mt, const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); + +// For testing: decode with tracing. +UPB_NODISCARD UPB_API upb_DecodeStatus upb_DecodeWithTrace( + const char* buf, size_t size, upb_Message* msg, const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, int options, upb_Arena* arena, + char* trace_buf, size_t trace_size); + +// Utility function for wrapper languages to get an error string from a +// upb_DecodeStatus. +UPB_API const char* upb_DecodeStatus_String(upb_DecodeStatus status); +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_DECODE_H_ */ + +// upb_Encode: parsing from a upb_Message using a upb_MiniTable. + +#ifndef UPB_WIRE_ENCODE_H_ +#define UPB_WIRE_ENCODE_H_ + +#include +#include + + +#ifndef UPB_WIRE_INTERNAL_CONSTANTS_H_ +#define UPB_WIRE_INTERNAL_CONSTANTS_H_ + +#define kUpb_WireFormat_DefaultDepthLimit 100 + +// MessageSet wire format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required bytes message = 3; +// } +// } + +enum { + kUpb_MsgSet_Item = 1, + kUpb_MsgSet_TypeId = 2, + kUpb_MsgSet_Message = 3, +}; + +#endif /* UPB_WIRE_INTERNAL_CONSTANTS_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_EncodeOption_Deterministic = 1, + + // When set, unknown fields are not encoded. + kUpb_EncodeOption_SkipUnknown = 2, + + // When set, the encode will fail if any required fields are missing. + kUpb_EncodeOption_CheckRequired = 4, +}; + +// LINT.IfChange +typedef enum { + kUpb_EncodeStatus_Ok = kUpb_ErrorCode_Ok, + kUpb_EncodeStatus_OutOfMemory = + kUpb_ErrorCode_OutOfMemory, // Arena alloc failed + // One or more required fields are missing. Only returned if + // kUpb_EncodeOption_CheckRequired is set. + kUpb_EncodeStatus_MaxDepthExceeded = kUpb_ErrorCode_MaxDepthExceeded, + + kUpb_EncodeStatus_MissingRequired = 10, + // The message is larger than protobuf's 2GB size limit. + kUpb_EncodeStatus_MaxSizeExceeded = 11, +} upb_EncodeStatus; +// LINT.ThenChange(//depot/google3/third_party/upb/rust/sys/wire/wire.rs:encode_status) + +UPB_INLINE uint32_t upb_EncodeOptions_MaxDepth(uint16_t depth) { + return (uint32_t)depth << 16; +} + +UPB_INLINE uint16_t upb_EncodeOptions_GetMaxDepth(uint32_t options) { + return options >> 16; +} + +UPB_INLINE uint16_t upb_EncodeOptions_GetEffectiveMaxDepth(uint32_t options) { + uint16_t max_depth = upb_EncodeOptions_GetMaxDepth(options); + return max_depth ? max_depth : kUpb_WireFormat_DefaultDepthLimit; +} + +// Enforce an upper bound on recursion depth. +UPB_INLINE int upb_Encode_LimitDepth(uint32_t encode_options, uint32_t limit) { + uint32_t max_depth = upb_EncodeOptions_GetEffectiveMaxDepth(encode_options); + if (max_depth > limit) max_depth = limit; + return (int)(upb_EncodeOptions_MaxDepth(max_depth) | + (encode_options & 0xffff)); +} + +UPB_NODISCARD UPB_API upb_EncodeStatus upb_Encode(const upb_Message* msg, + const upb_MiniTable* l, + int options, upb_Arena* arena, + char** buf, size_t* size); + +// Encodes the message prepended by a varint of the serialized length. +UPB_NODISCARD UPB_API upb_EncodeStatus upb_EncodeLengthPrefixed( + const upb_Message* msg, const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, size_t* size); +// Utility function for wrapper languages to get an error string from a +// upb_EncodeStatus. +UPB_API const char* upb_EncodeStatus_String(upb_EncodeStatus status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_ENCODE_H_ */ +#ifdef UPB_INCLUDE_FAST_DECODE +#endif +// IWYU pragma: end_exports + +#undef UPB_INCLUDE_FAST_DECODE + +#endif // UPB_GENERATED_CODE_SUPPORT_H_ +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const upb_MiniTable google__protobuf__FileDescriptorSet_msg_init; +extern const upb_MiniTable google__protobuf__FileDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__DescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__DescriptorProto__ExtensionRange_msg_init; +extern const upb_MiniTable google__protobuf__DescriptorProto__ReservedRange_msg_init; +extern const upb_MiniTable google__protobuf__ExtensionRangeOptions_msg_init; +extern const upb_MiniTable google__protobuf__ExtensionRangeOptions__Declaration_msg_init; +extern const upb_MiniTable google__protobuf__FieldDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__OneofDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__EnumDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init; +extern const upb_MiniTable google__protobuf__EnumValueDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__ServiceDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__MethodDescriptorProto_msg_init; +extern const upb_MiniTable google__protobuf__FileOptions_msg_init; +extern const upb_MiniTable google__protobuf__MessageOptions_msg_init; +extern const upb_MiniTable google__protobuf__FieldOptions_msg_init; +extern const upb_MiniTable google__protobuf__FieldOptions__EditionDefault_msg_init; +extern const upb_MiniTable google__protobuf__FieldOptions__FeatureSupport_msg_init; +extern const upb_MiniTable google__protobuf__OneofOptions_msg_init; +extern const upb_MiniTable google__protobuf__EnumOptions_msg_init; +extern const upb_MiniTable google__protobuf__EnumValueOptions_msg_init; +extern const upb_MiniTable google__protobuf__ServiceOptions_msg_init; +extern const upb_MiniTable google__protobuf__MethodOptions_msg_init; +extern const upb_MiniTable google__protobuf__UninterpretedOption_msg_init; +extern const upb_MiniTable google__protobuf__UninterpretedOption__NamePart_msg_init; +extern const upb_MiniTable google__protobuf__FeatureSet_msg_init; +extern const upb_MiniTable google__protobuf__FeatureSet__VisibilityFeature_msg_init; +extern const upb_MiniTable google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init; +extern const upb_MiniTable google__protobuf__FeatureSetDefaults_msg_init; +extern const upb_MiniTable google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init; +extern const upb_MiniTable google__protobuf__SourceCodeInfo_msg_init; +extern const upb_MiniTable google__protobuf__SourceCodeInfo__Location_msg_init; +extern const upb_MiniTable google__protobuf__GeneratedCodeInfo_msg_init; +extern const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init; + +extern const upb_MiniTableEnum google__protobuf__Edition_enum_init; +extern const upb_MiniTableEnum google__protobuf__ExtensionRangeOptions__VerificationState_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__EnforceNamingStyle_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__EnumType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__FieldPresence_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__JsonFormat_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__MessageEncoding_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__Utf8Validation_enum_init; +extern const upb_MiniTableEnum google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Label_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Type_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__CType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__JSType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__OptionRetention_enum_init; +extern const upb_MiniTableEnum google__protobuf__FieldOptions__OptionTargetType_enum_init; +extern const upb_MiniTableEnum google__protobuf__FileOptions__OptimizeMode_enum_init; +extern const upb_MiniTableEnum google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init; +extern const upb_MiniTableEnum google__protobuf__MethodOptions__IdempotencyLevel_enum_init; +extern const upb_MiniTableEnum google__protobuf__SymbolVisibility_enum_init; +extern const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_MINITABLE_H_ */ +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/json_enumvalue_options.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_MINITABLE_H_ +#define GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_MINITABLE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const upb_MiniTable pb__enumvalue__JsonEnumValueOptions_msg_init; +extern const upb_MiniTableExtension* pb_enumvalue_json_ext; + +extern const upb_MiniTableFile google_protobuf_json_enumvalue_options_proto_upb_file_layout; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_MINITABLE_H_ */ + +#ifndef UPB_BASE_INTERNAL_LOG2_H_ +#define UPB_BASE_INTERNAL_LOG2_H_ + +#include +#include +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE int upb_Log2Ceiling(size_t x) { + if (x <= 1) return 0; +#if SIZE_MAX == ULLONG_MAX && UPB_HAS_BUILTIN(__builtin_clzll) + return (sizeof(size_t) * CHAR_BIT) - __builtin_clzll(x - 1); +#elif SIZE_MAX == ULONG_MAX && UPB_HAS_BUILTIN(__builtin_clzl) + return (sizeof(size_t) * CHAR_BIT) - __builtin_clzl(x - 1); +#elif SIZE_MAX == UINT_MAX && UPB_HAS_BUILTIN(__builtin_clz) + return (sizeof(size_t) * CHAR_BIT) - __builtin_clz(x - 1); +#else + if (x > SIZE_MAX / 2) return sizeof(size_t) * CHAR_BIT; + int lg2 = 0; + while (((size_t)1 << lg2) < x) lg2++; + return lg2; +#endif +} + +// Returns the smallest power of two that is greater than or equal to x. Returns +// SIZE_MAX if the computation would overflow. +UPB_INLINE size_t upb_RoundUpToPowerOfTwo(size_t x) { + int lg2 = upb_Log2Ceiling(x); + UPB_ASSERT(lg2 >= 0 && lg2 <= (int)sizeof(size_t) * CHAR_BIT); + if (lg2 == sizeof(size_t) * CHAR_BIT) { + return SIZE_MAX; + } + return ((size_t)1) << lg2; +} + +UPB_INLINE bool upb_ShlOverflow(size_t* a, unsigned int b) { + if (*a > (SIZE_MAX >> b)) { + return true; + } + *a <<= b; + return false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_INTERNAL_LOG2_H_ */ + +#ifndef UPB_HASH_EXT_TABLE_H_ +#define UPB_HASH_EXT_TABLE_H_ + +#include +#include + + +// Must be last. + +typedef struct { + upb_table t; +} upb_exttable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +UPB_NODISCARD bool upb_exttable_init(upb_exttable* table, size_t expected_size, + upb_Arena* a); + +// Returns the number of values in the table. +UPB_INLINE size_t upb_exttable_count(const upb_exttable* t) { + return t->t.count; +} + +void upb_exttable_clear(upb_exttable* t); + +// Inserts the given key and value into the hashtable. +// The key must not already exist in the hash table, and must not be NULL. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. +UPB_NODISCARD bool upb_exttable_insert(upb_exttable* t, const void* k, + const uint32_t* v, upb_Arena* a); + +// Looks up key and ext_number in this table, returning the value if the key was +// found, or NULL otherwise. +const uint32_t* upb_exttable_lookup(const upb_exttable* t, const void* k, + uint32_t ext_number); + +// Removes an item from the table. Returns the removed item if the remove was +// successful, or NULL if the key was not found. +const uint32_t* upb_exttable_remove(upb_exttable* t, const void* k, + uint32_t ext_number); + +size_t upb_exttable_size(const upb_exttable* t); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_EXT_TABLE_H_ */ + +#ifndef UPB_JSON_DECODE_H_ +#define UPB_JSON_DECODE_H_ + +#include + + +#ifndef UPB_REFLECTION_DEF_H_ +#define UPB_REFLECTION_DEF_H_ + +// IWYU pragma: begin_exports + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_DEF_POOL_H_ +#define UPB_REFLECTION_DEF_POOL_H_ + +#include +#include + + +// IWYU pragma: private, include "upb/reflection/def.h" + +// Declarations common to all public def types. + +#ifndef UPB_REFLECTION_COMMON_H_ +#define UPB_REFLECTION_COMMON_H_ + +#ifndef GOOGLE_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H__ +#define GOOGLE_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H__ + +// IWYU pragma: begin_exports + +#if defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +// This header is checked in. +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 1 +// This header is generated at build time by the bootstrapping process. +#else +// This is the normal header, generated by upb_c_proto_library(). +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct google_protobuf_FileDescriptorSet { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FileDescriptorSet; + +typedef struct google_protobuf_FileDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FileDescriptorProto; + +typedef struct google_protobuf_DescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_DescriptorProto; + +typedef struct google_protobuf_DescriptorProto_ExtensionRange { + upb_Message UPB_PRIVATE(base); +} google_protobuf_DescriptorProto_ExtensionRange; + +typedef struct google_protobuf_DescriptorProto_ReservedRange { + upb_Message UPB_PRIVATE(base); +} google_protobuf_DescriptorProto_ReservedRange; + +typedef struct google_protobuf_ExtensionRangeOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_ExtensionRangeOptions; + +typedef struct google_protobuf_ExtensionRangeOptions_Declaration { + upb_Message UPB_PRIVATE(base); +} google_protobuf_ExtensionRangeOptions_Declaration; + +typedef struct google_protobuf_FieldDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FieldDescriptorProto; + +typedef struct google_protobuf_OneofDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_OneofDescriptorProto; + +typedef struct google_protobuf_EnumDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_EnumDescriptorProto; + +typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange { + upb_Message UPB_PRIVATE(base); +} google_protobuf_EnumDescriptorProto_EnumReservedRange; + +typedef struct google_protobuf_EnumValueDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_EnumValueDescriptorProto; + +typedef struct google_protobuf_ServiceDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_ServiceDescriptorProto; + +typedef struct google_protobuf_MethodDescriptorProto { + upb_Message UPB_PRIVATE(base); +} google_protobuf_MethodDescriptorProto; + +typedef struct google_protobuf_FileOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FileOptions; + +typedef struct google_protobuf_MessageOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_MessageOptions; + +typedef struct google_protobuf_FieldOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FieldOptions; + +typedef struct google_protobuf_FieldOptions_EditionDefault { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FieldOptions_EditionDefault; + +typedef struct google_protobuf_FieldOptions_FeatureSupport { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FieldOptions_FeatureSupport; + +typedef struct google_protobuf_OneofOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_OneofOptions; + +typedef struct google_protobuf_EnumOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_EnumOptions; + +typedef struct google_protobuf_EnumValueOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_EnumValueOptions; + +typedef struct google_protobuf_ServiceOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_ServiceOptions; + +typedef struct google_protobuf_MethodOptions { + upb_Message UPB_PRIVATE(base); +} google_protobuf_MethodOptions; + +typedef struct google_protobuf_UninterpretedOption { + upb_Message UPB_PRIVATE(base); +} google_protobuf_UninterpretedOption; + +typedef struct google_protobuf_UninterpretedOption_NamePart { + upb_Message UPB_PRIVATE(base); +} google_protobuf_UninterpretedOption_NamePart; + +typedef struct google_protobuf_FeatureSet { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FeatureSet; + +typedef struct google_protobuf_FeatureSet_VisibilityFeature { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FeatureSet_VisibilityFeature; + +typedef struct google_protobuf_FeatureSet_ProtoLimitsFeature { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FeatureSet_ProtoLimitsFeature; + +typedef struct google_protobuf_FeatureSetDefaults { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FeatureSetDefaults; + +typedef struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault { + upb_Message UPB_PRIVATE(base); +} google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault; + +typedef struct google_protobuf_SourceCodeInfo { + upb_Message UPB_PRIVATE(base); +} google_protobuf_SourceCodeInfo; + +typedef struct google_protobuf_SourceCodeInfo_Location { + upb_Message UPB_PRIVATE(base); +} google_protobuf_SourceCodeInfo_Location; + +typedef struct google_protobuf_GeneratedCodeInfo { + upb_Message UPB_PRIVATE(base); +} google_protobuf_GeneratedCodeInfo; + +typedef struct google_protobuf_GeneratedCodeInfo_Annotation { + upb_Message UPB_PRIVATE(base); +} google_protobuf_GeneratedCodeInfo_Annotation; + + +typedef enum { + google_protobuf_EDITION_UNKNOWN = 0, + google_protobuf_EDITION_1_TEST_ONLY = 1, + google_protobuf_EDITION_2_TEST_ONLY = 2, + google_protobuf_EDITION_LEGACY = 900, + google_protobuf_EDITION_PROTO2 = 998, + google_protobuf_EDITION_PROTO3 = 999, + google_protobuf_EDITION_2023 = 1000, + google_protobuf_EDITION_2024 = 1001, + google_protobuf_EDITION_2026 = 1002, + google_protobuf_EDITION_UNSTABLE = 9999, + google_protobuf_EDITION_99997_TEST_ONLY = 99997, + google_protobuf_EDITION_99998_TEST_ONLY = 99998, + google_protobuf_EDITION_99999_TEST_ONLY = 99999, + google_protobuf_EDITION_MAX = 2147483647 +} google_protobuf_Edition; + +typedef enum { + google_protobuf_ExtensionRangeOptions_DECLARATION = 0, + google_protobuf_ExtensionRangeOptions_UNVERIFIED = 1 +} google_protobuf_ExtensionRangeOptions_VerificationState; + +typedef enum { + google_protobuf_FeatureSet_ENFORCE_NAMING_STYLE_UNKNOWN = 0, + google_protobuf_FeatureSet_STYLE2024 = 1, + google_protobuf_FeatureSet_STYLE_LEGACY = 2, + google_protobuf_FeatureSet_STYLE2026 = 3 +} google_protobuf_FeatureSet_EnforceNamingStyle; + +typedef enum { + google_protobuf_FeatureSet_ENUM_TYPE_UNKNOWN = 0, + google_protobuf_FeatureSet_OPEN = 1, + google_protobuf_FeatureSet_CLOSED = 2 +} google_protobuf_FeatureSet_EnumType; + +typedef enum { + google_protobuf_FeatureSet_FIELD_PRESENCE_UNKNOWN = 0, + google_protobuf_FeatureSet_EXPLICIT = 1, + google_protobuf_FeatureSet_IMPLICIT = 2, + google_protobuf_FeatureSet_LEGACY_REQUIRED = 3 +} google_protobuf_FeatureSet_FieldPresence; + +typedef enum { + google_protobuf_FeatureSet_JSON_FORMAT_UNKNOWN = 0, + google_protobuf_FeatureSet_ALLOW = 1, + google_protobuf_FeatureSet_LEGACY_BEST_EFFORT = 2 +} google_protobuf_FeatureSet_JsonFormat; + +typedef enum { + google_protobuf_FeatureSet_MESSAGE_ENCODING_UNKNOWN = 0, + google_protobuf_FeatureSet_LENGTH_PREFIXED = 1, + google_protobuf_FeatureSet_DELIMITED = 2 +} google_protobuf_FeatureSet_MessageEncoding; + +typedef enum { + google_protobuf_FeatureSet_ProtoLimitsFeature_PROTO_LIMITS_UNKNOWN = 0, + google_protobuf_FeatureSet_ProtoLimitsFeature_LEGACY_NO_EXPLICIT_LIMITS = 1, + google_protobuf_FeatureSet_ProtoLimitsFeature_PROTO_LIMITS2026 = 2 +} google_protobuf_FeatureSet_ProtoLimitsFeature_EnforceProtoLimits; + +typedef enum { + google_protobuf_FeatureSet_REPEATED_FIELD_ENCODING_UNKNOWN = 0, + google_protobuf_FeatureSet_PACKED = 1, + google_protobuf_FeatureSet_EXPANDED = 2 +} google_protobuf_FeatureSet_RepeatedFieldEncoding; + +typedef enum { + google_protobuf_FeatureSet_UTF8_VALIDATION_UNKNOWN = 0, + google_protobuf_FeatureSet_VERIFY = 2, + google_protobuf_FeatureSet_NONE = 3 +} google_protobuf_FeatureSet_Utf8Validation; + +typedef enum { + google_protobuf_FeatureSet_VisibilityFeature_DEFAULT_SYMBOL_VISIBILITY_UNKNOWN = 0, + google_protobuf_FeatureSet_VisibilityFeature_EXPORT_ALL = 1, + google_protobuf_FeatureSet_VisibilityFeature_EXPORT_TOP_LEVEL = 2, + google_protobuf_FeatureSet_VisibilityFeature_LOCAL_ALL = 3, + google_protobuf_FeatureSet_VisibilityFeature_STRICT = 4 +} google_protobuf_FeatureSet_VisibilityFeature_DefaultSymbolVisibility; + +typedef enum { + google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, + google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, + google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 +} google_protobuf_FieldDescriptorProto_Label; + +typedef enum { + google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, + google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, + google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, + google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, + google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, + google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, + google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, + google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, + google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, + google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, + google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, + google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, + google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, + google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, + google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, + google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 +} google_protobuf_FieldDescriptorProto_Type; + +typedef enum { + google_protobuf_FieldOptions_STRING = 0, + google_protobuf_FieldOptions_CORD = 1, + google_protobuf_FieldOptions_STRING_PIECE = 2 +} google_protobuf_FieldOptions_CType; + +typedef enum { + google_protobuf_FieldOptions_JS_NORMAL = 0, + google_protobuf_FieldOptions_JS_STRING = 1, + google_protobuf_FieldOptions_JS_NUMBER = 2 +} google_protobuf_FieldOptions_JSType; + +typedef enum { + google_protobuf_FieldOptions_RETENTION_UNKNOWN = 0, + google_protobuf_FieldOptions_RETENTION_RUNTIME = 1, + google_protobuf_FieldOptions_RETENTION_SOURCE = 2 +} google_protobuf_FieldOptions_OptionRetention; + +typedef enum { + google_protobuf_FieldOptions_TARGET_TYPE_UNKNOWN = 0, + google_protobuf_FieldOptions_TARGET_TYPE_FILE = 1, + google_protobuf_FieldOptions_TARGET_TYPE_EXTENSION_RANGE = 2, + google_protobuf_FieldOptions_TARGET_TYPE_MESSAGE = 3, + google_protobuf_FieldOptions_TARGET_TYPE_FIELD = 4, + google_protobuf_FieldOptions_TARGET_TYPE_ONEOF = 5, + google_protobuf_FieldOptions_TARGET_TYPE_ENUM = 6, + google_protobuf_FieldOptions_TARGET_TYPE_ENUM_ENTRY = 7, + google_protobuf_FieldOptions_TARGET_TYPE_SERVICE = 8, + google_protobuf_FieldOptions_TARGET_TYPE_METHOD = 9 +} google_protobuf_FieldOptions_OptionTargetType; + +typedef enum { + google_protobuf_FileOptions_SPEED = 1, + google_protobuf_FileOptions_CODE_SIZE = 2, + google_protobuf_FileOptions_LITE_RUNTIME = 3 +} google_protobuf_FileOptions_OptimizeMode; + +typedef enum { + google_protobuf_GeneratedCodeInfo_Annotation_NONE = 0, + google_protobuf_GeneratedCodeInfo_Annotation_SET = 1, + google_protobuf_GeneratedCodeInfo_Annotation_ALIAS = 2 +} google_protobuf_GeneratedCodeInfo_Annotation_Semantic; + +typedef enum { + google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, + google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, + google_protobuf_MethodOptions_IDEMPOTENT = 2 +} google_protobuf_MethodOptions_IdempotencyLevel; + +typedef enum { + google_protobuf_VISIBILITY_UNSET = 0, + google_protobuf_VISIBILITY_LOCAL = 1, + google_protobuf_VISIBILITY_EXPORT = 2 +} google_protobuf_SymbolVisibility; + + + +/* google.protobuf.FileDescriptorSet */ +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google__protobuf__FileDescriptorSet_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorSet_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorSet_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorSet_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorSet_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(google_protobuf_FileDescriptorSet* msg) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, + size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FileDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorSet_file_upb_array( + const google_protobuf_FileDescriptorSet* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorSet_file_mutable_upb_array( + google_protobuf_FileDescriptorSet* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, + size_t* size) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FileDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + return (google_protobuf_FileDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file( + google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FileDescriptorProto* sub = + (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google__protobuf__FileDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FileDescriptorProto */ +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google__protobuf__FileDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_dependency_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_dependency_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_message_type_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_message_type_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_enum_type_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_enum_type_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_ServiceDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_service_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_service_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_extension_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_extension_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { + const google_protobuf_FileOptions* default_val = NULL; + const google_protobuf_FileOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + const google_protobuf_SourceCodeInfo* default_val = NULL; + const google_protobuf_SourceCodeInfo* ret; + const upb_MiniTableField field = {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_public_dependency_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_public_dependency_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_weak_dependency_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_weak_dependency_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_option_dependency(google_protobuf_FileDescriptorProto* msg) { + const upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_option_dependency(const google_protobuf_FileDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileDescriptorProto_option_dependency_upb_array( + const google_protobuf_FileDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileDescriptorProto_option_dependency_mutable_upb_array( + google_protobuf_FileDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, + upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + return (google_protobuf_DescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto* sub = + (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + return (google_protobuf_EnumDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto* sub = + (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_ServiceDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + return (google_protobuf_ServiceDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_ServiceDescriptorProto* sub = + (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google__protobuf__ServiceDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = + (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto* msg, google_protobuf_FileOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FileOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google__protobuf__FileOptions_msg_init, arena); + if (sub) google_protobuf_FileDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto* msg, google_protobuf_SourceCodeInfo* value) { + const upb_MiniTableField field = {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info( + google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); + if (sub == NULL) { + sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google__protobuf__SourceCodeInfo_msg_init, arena); + if (sub) google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); + } + return sub; +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_option_dependency(google_protobuf_FileDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_option_dependency(google_protobuf_FileDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_option_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, + upb_Arena* arena) { + upb_MiniTableField field = {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} + +/* google.protobuf.DescriptorProto */ +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_protobuf_DescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_field_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_field_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_nested_type_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_nested_type_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_enum_type_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_enum_type_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_extension_range_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_extension_range_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_extension_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_extension_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { + const google_protobuf_MessageOptions* default_val = NULL; + const google_protobuf_MessageOptions* ret; + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MessageOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_OneofDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_oneof_decl_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_oneof_decl_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_DescriptorProto_ReservedRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_reserved_range_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_reserved_range_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_DescriptorProto_reserved_name_upb_array( + const google_protobuf_DescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_DescriptorProto_reserved_name_mutable_upb_array( + google_protobuf_DescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_visibility(google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_visibility(const google_protobuf_DescriptorProto* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_visibility(const google_protobuf_DescriptorProto* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = + (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + return (google_protobuf_DescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto* sub = + (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google__protobuf__DescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + return (google_protobuf_EnumDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto* sub = + (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto_ExtensionRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + return (google_protobuf_DescriptorProto_ExtensionRange**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ExtensionRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto_ExtensionRange* sub = + (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ExtensionRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + return (google_protobuf_FieldDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldDescriptorProto* sub = + (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto* msg, google_protobuf_MessageOptions* value) { + const upb_MiniTableField field = {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MessageOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google__protobuf__MessageOptions_msg_init, arena); + if (sub) google_protobuf_DescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_OneofDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + return (google_protobuf_OneofDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_OneofDescriptorProto* sub = + (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google__protobuf__OneofDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_DescriptorProto_ReservedRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + return (google_protobuf_DescriptorProto_ReservedRange**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range( + google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__DescriptorProto__ReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_DescriptorProto_ReservedRange* sub = + (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ReservedRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto* msg, upb_StringView val, + upb_Arena* arena) { + upb_MiniTableField field = {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_DescriptorProto_set_visibility(google_protobuf_DescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.DescriptorProto.ExtensionRange */ +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ExtensionRange_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(const google_protobuf_DescriptorProto_ExtensionRange* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ExtensionRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const google_protobuf_ExtensionRangeOptions* default_val = NULL; + const google_protobuf_ExtensionRangeOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange* msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange* msg, google_protobuf_ExtensionRangeOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options( + google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { + struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions_msg_init, arena); + if (sub) google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.DescriptorProto.ReservedRange */ +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_new(upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google__protobuf__DescriptorProto__ReservedRange_msg_init, arena); +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ReservedRange_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__DescriptorProto__ReservedRange_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(const google_protobuf_DescriptorProto_ReservedRange* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__DescriptorProto__ReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange* msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.ExtensionRangeOptions */ +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { + return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google_protobuf_ExtensionRangeOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_declaration(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ExtensionRangeOptions_Declaration* const* google_protobuf_ExtensionRangeOptions_declaration(const google_protobuf_ExtensionRangeOptions* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_ExtensionRangeOptions_Declaration* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_ExtensionRangeOptions_declaration_upb_array( + const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_ExtensionRangeOptions_declaration_mutable_upb_array( + google_protobuf_ExtensionRangeOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_verification(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_ExtensionRangeOptions_verification(const google_protobuf_ExtensionRangeOptions* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_verification(const google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_features(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_ExtensionRangeOptions_features(const google_protobuf_ExtensionRangeOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_features(const google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_ExtensionRangeOptions_uninterpreted_option_upb_array( + const google_protobuf_ExtensionRangeOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_ExtensionRangeOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_ExtensionRangeOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration** google_protobuf_ExtensionRangeOptions_mutable_declaration(google_protobuf_ExtensionRangeOptions* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_ExtensionRangeOptions_Declaration**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration** google_protobuf_ExtensionRangeOptions_resize_declaration(google_protobuf_ExtensionRangeOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + return (google_protobuf_ExtensionRangeOptions_Declaration**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_add_declaration( + google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_ExtensionRangeOptions_Declaration* sub = + (struct google_protobuf_ExtensionRangeOptions_Declaration*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_verification(google_protobuf_ExtensionRangeOptions* msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_set_features(google_protobuf_ExtensionRangeOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_ExtensionRangeOptions_mutable_features( + google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_ExtensionRangeOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_ExtensionRangeOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option( + google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.ExtensionRangeOptions.Declaration */ +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_new(upb_Arena* arena) { + return (google_protobuf_ExtensionRangeOptions_Declaration*)_upb_Message_New(&google__protobuf__ExtensionRangeOptions__Declaration_msg_init, arena); +} +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions_Declaration* ret = google_protobuf_ExtensionRangeOptions_Declaration_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ExtensionRangeOptions_Declaration* google_protobuf_ExtensionRangeOptions_Declaration_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ExtensionRangeOptions_Declaration* ret = google_protobuf_ExtensionRangeOptions_Declaration_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_Declaration_serialize(const google_protobuf_ExtensionRangeOptions_Declaration* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ExtensionRangeOptions_Declaration_serialize_ex(const google_protobuf_ExtensionRangeOptions_Declaration* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_number(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_ExtensionRangeOptions_Declaration_number(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_number(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_full_name(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ExtensionRangeOptions_Declaration_full_name(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_full_name(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_type(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ExtensionRangeOptions_Declaration_type(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_type(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_reserved(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_reserved(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_reserved(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_clear_repeated(google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_repeated(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_Declaration_has_repeated(const google_protobuf_ExtensionRangeOptions_Declaration* msg) { + const upb_MiniTableField field = {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_number(google_protobuf_ExtensionRangeOptions_Declaration* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_full_name(google_protobuf_ExtensionRangeOptions_Declaration* msg, upb_StringView value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_type(google_protobuf_ExtensionRangeOptions_Declaration* msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_reserved(google_protobuf_ExtensionRangeOptions_Declaration* msg, bool value) { + const upb_MiniTableField field = {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_Declaration_set_repeated(google_protobuf_ExtensionRangeOptions_Declaration* msg, bool value) { + const upb_MiniTableField field = {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FieldDescriptorProto */ +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google__protobuf__FieldDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_protobuf_FieldDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { + const google_protobuf_FieldOptions* default_val = NULL; + const google_protobuf_FieldOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + const upb_MiniTableField field = {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto* msg, google_protobuf_FieldOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options( + google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google__protobuf__FieldOptions_msg_init, arena); + if (sub) google_protobuf_FieldDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto* msg, bool value) { + const upb_MiniTableField field = {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.OneofDescriptorProto */ +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google__protobuf__OneofDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_protobuf_OneofDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { + const google_protobuf_OneofOptions* default_val = NULL; + const google_protobuf_OneofOptions* ret; + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto* msg, google_protobuf_OneofOptions* value) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__OneofOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options( + google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google__protobuf__OneofOptions_msg_init, arena); + if (sub) google_protobuf_OneofDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.EnumDescriptorProto */ +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google__protobuf__EnumDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_protobuf_EnumDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumValueDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_value_upb_array( + const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_value_mutable_upb_array( + google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { + const google_protobuf_EnumOptions* default_val = NULL; + const google_protobuf_EnumOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_reserved_range_upb_array( + const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_reserved_range_mutable_upb_array( + google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_EnumDescriptorProto_reserved_name_upb_array( + const google_protobuf_EnumDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_EnumDescriptorProto_reserved_name_mutable_upb_array( + google_protobuf_EnumDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_visibility(google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_visibility(const google_protobuf_EnumDescriptorProto* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_visibility(const google_protobuf_EnumDescriptorProto* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumValueDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + return (google_protobuf_EnumValueDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value( + google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumValueDescriptorProto* sub = + (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google__protobuf__EnumValueDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto* msg, google_protobuf_EnumOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options( + google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google__protobuf__EnumOptions_msg_init, arena); + if (sub) google_protobuf_EnumDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range( + google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = + (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView val, + upb_Arena* arena) { + upb_MiniTableField field = {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_set_visibility(google_protobuf_EnumDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.EnumDescriptorProto.EnumReservedRange */ +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize_ex(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.EnumValueDescriptorProto */ +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google__protobuf__EnumValueDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const google_protobuf_EnumValueDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { + const google_protobuf_EnumValueOptions* default_val = NULL; + const google_protobuf_EnumValueOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto* msg, int32_t value) { + const upb_MiniTableField field = {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto* msg, google_protobuf_EnumValueOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__EnumValueOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options( + google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google__protobuf__EnumValueOptions_msg_init, arena); + if (sub) google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.ServiceDescriptorProto */ +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google__protobuf__ServiceDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const google_protobuf_ServiceDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_MethodDescriptorProto* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_ServiceDescriptorProto_method_upb_array( + const google_protobuf_ServiceDescriptorProto* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_ServiceDescriptorProto_method_mutable_upb_array( + google_protobuf_ServiceDescriptorProto* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { + const google_protobuf_ServiceOptions* default_val = NULL; + const google_protobuf_ServiceOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_MethodDescriptorProto**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + return (google_protobuf_MethodDescriptorProto**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method( + google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodDescriptorProto_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_MethodDescriptorProto* sub = + (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google__protobuf__MethodDescriptorProto_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto* msg, google_protobuf_ServiceOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__ServiceOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options( + google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google__protobuf__ServiceOptions_msg_init, arena); + if (sub) google_protobuf_ServiceDescriptorProto_set_options(msg, sub); + } + return sub; +} + +/* google.protobuf.MethodDescriptorProto */ +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_new(upb_Arena* arena) { + return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google__protobuf__MethodDescriptorProto_msg_init, arena); +} +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodDescriptorProto_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodDescriptorProto_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodDescriptorProto_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google_protobuf_MethodDescriptorProto* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodDescriptorProto_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { + const google_protobuf_MethodOptions* default_val = NULL; + const google_protobuf_MethodOptions* ret; + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodOptions_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + const upb_MiniTableField field = {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto* msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto* msg, google_protobuf_MethodOptions* value) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__MethodOptions_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options( + google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { + struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); + if (sub == NULL) { + sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google__protobuf__MethodOptions_msg_init, arena); + if (sub) google_protobuf_MethodDescriptorProto_set_options(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto* msg, bool value) { + const upb_MiniTableField field = {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto* msg, bool value) { + const upb_MiniTableField field = {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FileOptions */ +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { + return (google_protobuf_FileOptions*)_upb_Message_New(&google__protobuf__FileOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FileOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_FileOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FileOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + bool default_val = true; + bool ret; + const upb_MiniTableField field = {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_features(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FileOptions_features(const google_protobuf_FileOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FileOptions_has_features(const google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(google_protobuf_FileOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FileOptions_uninterpreted_option_upb_array( + const google_protobuf_FileOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FileOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_FileOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions* msg, int32_t value) { + const upb_MiniTableField field = {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions* msg, bool value) { + const upb_MiniTableField field = {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FileOptions_set_features(google_protobuf_FileOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FileOptions_mutable_features( + google_protobuf_FileOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FileOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FileOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option( + google_protobuf_FileOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.MessageOptions */ +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new(upb_Arena* arena) { + return (google_protobuf_MessageOptions*)_upb_Message_New(&google__protobuf__MessageOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MessageOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MessageOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MessageOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protobuf_MessageOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MessageOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated_legacy_json_field_conflicts(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MessageOptions_deprecated_legacy_json_field_conflicts(const google_protobuf_MessageOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated_legacy_json_field_conflicts(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_features(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_MessageOptions_features(const google_protobuf_MessageOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MessageOptions_has_features(const google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(google_protobuf_MessageOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_MessageOptions_uninterpreted_option_upb_array( + const google_protobuf_MessageOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_MessageOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_MessageOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions* msg, bool value) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions* msg, bool value) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions* msg, bool value) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions* msg, bool value) { + const upb_MiniTableField field = {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_deprecated_legacy_json_field_conflicts(google_protobuf_MessageOptions* msg, bool value) { + const upb_MiniTableField field = {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MessageOptions_set_features(google_protobuf_MessageOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_MessageOptions_mutable_features( + google_protobuf_MessageOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_MessageOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_MessageOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option( + google_protobuf_MessageOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FieldOptions */ +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions*)_upb_Message_New(&google__protobuf__FieldOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf_FieldOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_debug_redact(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_FieldOptions_debug_redact(const google_protobuf_FieldOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_debug_redact(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_retention(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_retention(const google_protobuf_FieldOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_retention(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_targets(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_FieldOptions_targets(const google_protobuf_FieldOptions* msg, + size_t* size) { + const upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_targets_upb_array( + const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_targets_mutable_upb_array( + google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_edition_defaults(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_EditionDefault* const* google_protobuf_FieldOptions_edition_defaults(const google_protobuf_FieldOptions* msg, + size_t* size) { + const upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FieldOptions_EditionDefault* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_edition_defaults_upb_array( + const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_edition_defaults_mutable_upb_array( + google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FieldOptions_clear_features(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FieldOptions_features(const google_protobuf_FieldOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_features(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_feature_support(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_feature_support(const google_protobuf_FieldOptions* msg) { + const google_protobuf_FieldOptions_FeatureSupport* default_val = NULL; + const google_protobuf_FieldOptions_FeatureSupport* ret; + const upb_MiniTableField field = {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_has_feature_support(const google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(google_protobuf_FieldOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FieldOptions_uninterpreted_option_upb_array( + const google_protobuf_FieldOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FieldOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_FieldOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions* msg, int32_t value) { + const upb_MiniTableField field = {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions* msg, int32_t value) { + const upb_MiniTableField field = {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_debug_redact(google_protobuf_FieldOptions* msg, bool value) { + const upb_MiniTableField field = {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_set_retention(google_protobuf_FieldOptions* msg, int32_t value) { + const upb_MiniTableField field = {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE int32_t* google_protobuf_FieldOptions_mutable_targets(google_protobuf_FieldOptions* msg, + size_t* size) { + upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_FieldOptions_resize_targets(google_protobuf_FieldOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_FieldOptions_add_targets(google_protobuf_FieldOptions* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault** google_protobuf_FieldOptions_mutable_edition_defaults(google_protobuf_FieldOptions* msg, + size_t* size) { + upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FieldOptions_EditionDefault**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FieldOptions_EditionDefault** google_protobuf_FieldOptions_resize_edition_defaults(google_protobuf_FieldOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + return (google_protobuf_FieldOptions_EditionDefault**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_add_edition_defaults( + google_protobuf_FieldOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__EditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FieldOptions_EditionDefault* sub = + (struct google_protobuf_FieldOptions_EditionDefault*)_upb_Message_New(&google__protobuf__FieldOptions__EditionDefault_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FieldOptions_set_features(google_protobuf_FieldOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FieldOptions_mutable_features( + google_protobuf_FieldOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FieldOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FieldOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FieldOptions_set_feature_support(google_protobuf_FieldOptions* msg, google_protobuf_FieldOptions_FeatureSupport* value) { + const upb_MiniTableField field = {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_mutable_feature_support( + google_protobuf_FieldOptions* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions_FeatureSupport* sub = (struct google_protobuf_FieldOptions_FeatureSupport*)google_protobuf_FieldOptions_feature_support(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); + if (sub) google_protobuf_FieldOptions_set_feature_support(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option( + google_protobuf_FieldOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.FieldOptions.EditionDefault */ +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions_EditionDefault*)_upb_Message_New(&google__protobuf__FieldOptions__EditionDefault_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FieldOptions_EditionDefault* ret = google_protobuf_FieldOptions_EditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__EditionDefault_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions_EditionDefault* google_protobuf_FieldOptions_EditionDefault_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions_EditionDefault* ret = google_protobuf_FieldOptions_EditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__EditionDefault_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_EditionDefault_serialize(const google_protobuf_FieldOptions_EditionDefault* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__EditionDefault_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_EditionDefault_serialize_ex(const google_protobuf_FieldOptions_EditionDefault* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__EditionDefault_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_clear_value(google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldOptions_EditionDefault_value(const google_protobuf_FieldOptions_EditionDefault* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_EditionDefault_has_value(const google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_clear_edition(google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_EditionDefault_edition(const google_protobuf_FieldOptions_EditionDefault* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_EditionDefault_has_edition(const google_protobuf_FieldOptions_EditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_set_value(google_protobuf_FieldOptions_EditionDefault* msg, upb_StringView value) { + const upb_MiniTableField field = {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_EditionDefault_set_edition(google_protobuf_FieldOptions_EditionDefault* msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FieldOptions.FeatureSupport */ +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_new(upb_Arena* arena) { + return (google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); +} +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FieldOptions_FeatureSupport* ret = google_protobuf_FieldOptions_FeatureSupport_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__FeatureSupport_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FieldOptions_FeatureSupport* google_protobuf_FieldOptions_FeatureSupport_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FieldOptions_FeatureSupport* ret = google_protobuf_FieldOptions_FeatureSupport_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FieldOptions__FeatureSupport_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FieldOptions_FeatureSupport_serialize(const google_protobuf_FieldOptions_FeatureSupport* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__FeatureSupport_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FieldOptions_FeatureSupport_serialize_ex(const google_protobuf_FieldOptions_FeatureSupport* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FieldOptions__FeatureSupport_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_introduced(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_introduced(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_introduced(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_deprecated(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_deprecated(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_deprecated(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_deprecation_warning(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldOptions_FeatureSupport_deprecation_warning(const google_protobuf_FieldOptions_FeatureSupport* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_deprecation_warning(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_edition_removed(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FieldOptions_FeatureSupport_edition_removed(const google_protobuf_FieldOptions_FeatureSupport* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_edition_removed(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_clear_removal_error(google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_FieldOptions_FeatureSupport_removal_error(const google_protobuf_FieldOptions_FeatureSupport* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FieldOptions_FeatureSupport_has_removal_error(const google_protobuf_FieldOptions_FeatureSupport* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_introduced(google_protobuf_FieldOptions_FeatureSupport* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_deprecated(google_protobuf_FieldOptions_FeatureSupport* msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_deprecation_warning(google_protobuf_FieldOptions_FeatureSupport* msg, upb_StringView value) { + const upb_MiniTableField field = {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_edition_removed(google_protobuf_FieldOptions_FeatureSupport* msg, int32_t value) { + const upb_MiniTableField field = {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FieldOptions_FeatureSupport_set_removal_error(google_protobuf_FieldOptions_FeatureSupport* msg, upb_StringView value) { + const upb_MiniTableField field = {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.OneofOptions */ +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new(upb_Arena* arena) { + return (google_protobuf_OneofOptions*)_upb_Message_New(&google__protobuf__OneofOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__OneofOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf_OneofOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__OneofOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_OneofOptions_clear_features(google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_OneofOptions_features(const google_protobuf_OneofOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_OneofOptions_has_features(const google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(google_protobuf_OneofOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_OneofOptions_uninterpreted_option_upb_array( + const google_protobuf_OneofOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_OneofOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_OneofOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_OneofOptions_set_features(google_protobuf_OneofOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_OneofOptions_mutable_features( + google_protobuf_OneofOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_OneofOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_OneofOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option( + google_protobuf_OneofOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.EnumOptions */ +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new(upb_Arena* arena) { + return (google_protobuf_EnumOptions*)_upb_Message_New(&google__protobuf__EnumOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_EnumOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated_legacy_json_field_conflicts(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumOptions_deprecated_legacy_json_field_conflicts(const google_protobuf_EnumOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated_legacy_json_field_conflicts(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_features(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_EnumOptions_features(const google_protobuf_EnumOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumOptions_has_features(const google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(google_protobuf_EnumOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_EnumOptions_uninterpreted_option_upb_array( + const google_protobuf_EnumOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_EnumOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_EnumOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions* msg, bool value) { + const upb_MiniTableField field = {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions* msg, bool value) { + const upb_MiniTableField field = {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_deprecated_legacy_json_field_conflicts(google_protobuf_EnumOptions* msg, bool value) { + const upb_MiniTableField field = {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumOptions_set_features(google_protobuf_EnumOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_EnumOptions_mutable_features( + google_protobuf_EnumOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_EnumOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_EnumOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option( + google_protobuf_EnumOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.EnumValueOptions */ +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_new(upb_Arena* arena) { + return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google__protobuf__EnumValueOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__EnumValueOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_protobuf_EnumValueOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__EnumValueOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_features(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_EnumValueOptions_features(const google_protobuf_EnumValueOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_features(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_debug_redact(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_EnumValueOptions_debug_redact(const google_protobuf_EnumValueOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_debug_redact(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_feature_support(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FieldOptions_FeatureSupport* google_protobuf_EnumValueOptions_feature_support(const google_protobuf_EnumValueOptions* msg) { + const google_protobuf_FieldOptions_FeatureSupport* default_val = NULL; + const google_protobuf_FieldOptions_FeatureSupport* ret; + const upb_MiniTableField field = {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_EnumValueOptions_has_feature_support(const google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_EnumValueOptions_uninterpreted_option_upb_array( + const google_protobuf_EnumValueOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_EnumValueOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_EnumValueOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions* msg, bool value) { + const upb_MiniTableField field = {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_features(google_protobuf_EnumValueOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_EnumValueOptions_mutable_features( + google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_EnumValueOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_EnumValueOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_debug_redact(google_protobuf_EnumValueOptions* msg, bool value) { + const upb_MiniTableField field = {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_EnumValueOptions_set_feature_support(google_protobuf_EnumValueOptions* msg, google_protobuf_FieldOptions_FeatureSupport* value) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FieldOptions__FeatureSupport_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FieldOptions_FeatureSupport* google_protobuf_EnumValueOptions_mutable_feature_support( + google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct google_protobuf_FieldOptions_FeatureSupport* sub = (struct google_protobuf_FieldOptions_FeatureSupport*)google_protobuf_EnumValueOptions_feature_support(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FieldOptions_FeatureSupport*)_upb_Message_New(&google__protobuf__FieldOptions__FeatureSupport_msg_init, arena); + if (sub) google_protobuf_EnumValueOptions_set_feature_support(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option( + google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.ServiceOptions */ +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new(upb_Arena* arena) { + return (google_protobuf_ServiceOptions*)_upb_Message_New(&google__protobuf__ServiceOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__ServiceOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protobuf_ServiceOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__ServiceOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_features(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_ServiceOptions_features(const google_protobuf_ServiceOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_ServiceOptions_has_features(const google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(google_protobuf_ServiceOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_ServiceOptions_uninterpreted_option_upb_array( + const google_protobuf_ServiceOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_ServiceOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_ServiceOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions* msg, bool value) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_ServiceOptions_set_features(google_protobuf_ServiceOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_ServiceOptions_mutable_features( + google_protobuf_ServiceOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_ServiceOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_ServiceOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option( + google_protobuf_ServiceOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.MethodOptions */ +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new(upb_Arena* arena) { + return (google_protobuf_MethodOptions*)_upb_Message_New(&google__protobuf__MethodOptions_msg_init, arena); +} +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__MethodOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobuf_MethodOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__MethodOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_features(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_MethodOptions_features(const google_protobuf_MethodOptions* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_MethodOptions_has_features(const google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(google_protobuf_MethodOptions* msg) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, + size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_MethodOptions_uninterpreted_option_upb_array( + const google_protobuf_MethodOptions* msg, size_t* size) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_MethodOptions_uninterpreted_option_mutable_upb_array( + google_protobuf_MethodOptions* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions* msg, bool value) { + const upb_MiniTableField field = {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions* msg, int32_t value) { + const upb_MiniTableField field = {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_MethodOptions_set_features(google_protobuf_MethodOptions* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_MethodOptions_mutable_features( + google_protobuf_MethodOptions* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_MethodOptions_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_MethodOptions_set_features(msg, sub); + } + return sub; +} +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, + size_t* size) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + return (google_protobuf_UninterpretedOption**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option( + google_protobuf_MethodOptions* msg, upb_Arena* arena) { + upb_MiniTableField field = {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption* sub = + (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.UninterpretedOption */ +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_new(upb_Arena* arena) { + return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google__protobuf__UninterpretedOption_msg_init, arena); +} +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_protobuf_UninterpretedOption* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_UninterpretedOption_NamePart* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_UninterpretedOption_name_upb_array( + const google_protobuf_UninterpretedOption* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_UninterpretedOption_name_mutable_upb_array( + google_protobuf_UninterpretedOption* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + uint64_t default_val = (uint64_t)0ull; + uint64_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + int64_t default_val = (int64_t)0ll; + int64_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { + double default_val = 0; + double ret; + const upb_MiniTableField field = {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_UninterpretedOption_NamePart**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + return (google_protobuf_UninterpretedOption_NamePart**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name( + google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__UninterpretedOption__NamePart_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_UninterpretedOption_NamePart* sub = + (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google__protobuf__UninterpretedOption__NamePart_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption* msg, upb_StringView value) { + const upb_MiniTableField field = {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption* msg, uint64_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption* msg, int64_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption* msg, double value) { + const upb_MiniTableField field = {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption* msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption* msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.UninterpretedOption.NamePart */ +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { + return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google__protobuf__UninterpretedOption__NamePart_msg_init, arena); +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption__NamePart_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__UninterpretedOption__NamePart_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption__NamePart_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const google_protobuf_UninterpretedOption_NamePart* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__UninterpretedOption__NamePart_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart* msg, bool value) { + const upb_MiniTableField field = {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FeatureSet */ +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_new(upb_Arena* arena) { + return (google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FeatureSet* ret = google_protobuf_FeatureSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSet* google_protobuf_FeatureSet_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSet* ret = google_protobuf_FeatureSet_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSet_serialize(const google_protobuf_FeatureSet* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSet_serialize_ex(const google_protobuf_FeatureSet* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSet_clear_field_presence(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_field_presence(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_field_presence(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_enum_type(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_enum_type(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_enum_type(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_repeated_field_encoding(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_repeated_field_encoding(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_repeated_field_encoding(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_utf8_validation(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_utf8_validation(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_utf8_validation(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_message_encoding(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_message_encoding(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_message_encoding(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_json_format(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_json_format(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_json_format(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_enforce_naming_style(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_enforce_naming_style(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_enforce_naming_style(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_default_symbol_visibility(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_default_symbol_visibility(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_default_symbol_visibility(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSet_clear_enforce_proto_limits(google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSet_enforce_proto_limits(const google_protobuf_FeatureSet* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSet_has_enforce_proto_limits(const google_protobuf_FeatureSet* msg) { + const upb_MiniTableField field = {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FeatureSet_set_field_presence(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_enum_type(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_repeated_field_encoding(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_utf8_validation(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_message_encoding(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_json_format(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_enforce_naming_style(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_default_symbol_visibility(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSet_set_enforce_proto_limits(google_protobuf_FeatureSet* msg, int32_t value) { + const upb_MiniTableField field = {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FeatureSet.VisibilityFeature */ +UPB_INLINE google_protobuf_FeatureSet_VisibilityFeature* google_protobuf_FeatureSet_VisibilityFeature_new(upb_Arena* arena) { + return (google_protobuf_FeatureSet_VisibilityFeature*)_upb_Message_New(&google__protobuf__FeatureSet__VisibilityFeature_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSet_VisibilityFeature* google_protobuf_FeatureSet_VisibilityFeature_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FeatureSet_VisibilityFeature* ret = google_protobuf_FeatureSet_VisibilityFeature_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet__VisibilityFeature_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSet_VisibilityFeature* google_protobuf_FeatureSet_VisibilityFeature_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSet_VisibilityFeature* ret = google_protobuf_FeatureSet_VisibilityFeature_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet__VisibilityFeature_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSet_VisibilityFeature_serialize(const google_protobuf_FeatureSet_VisibilityFeature* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet__VisibilityFeature_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSet_VisibilityFeature_serialize_ex(const google_protobuf_FeatureSet_VisibilityFeature* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet__VisibilityFeature_msg_init, options, arena, &ptr, len); + return ptr; +} + + +/* google.protobuf.FeatureSet.ProtoLimitsFeature */ +UPB_INLINE google_protobuf_FeatureSet_ProtoLimitsFeature* google_protobuf_FeatureSet_ProtoLimitsFeature_new(upb_Arena* arena) { + return (google_protobuf_FeatureSet_ProtoLimitsFeature*)_upb_Message_New(&google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSet_ProtoLimitsFeature* google_protobuf_FeatureSet_ProtoLimitsFeature_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FeatureSet_ProtoLimitsFeature* ret = google_protobuf_FeatureSet_ProtoLimitsFeature_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSet_ProtoLimitsFeature* google_protobuf_FeatureSet_ProtoLimitsFeature_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSet_ProtoLimitsFeature* ret = google_protobuf_FeatureSet_ProtoLimitsFeature_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSet_ProtoLimitsFeature_serialize(const google_protobuf_FeatureSet_ProtoLimitsFeature* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSet_ProtoLimitsFeature_serialize_ex(const google_protobuf_FeatureSet_ProtoLimitsFeature* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, options, arena, &ptr, len); + return ptr; +} + + +/* google.protobuf.FeatureSetDefaults */ +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_new(upb_Arena* arena) { + return (google_protobuf_FeatureSetDefaults*)_upb_Message_New(&google__protobuf__FeatureSetDefaults_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FeatureSetDefaults* ret = google_protobuf_FeatureSetDefaults_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSetDefaults* google_protobuf_FeatureSetDefaults_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults* ret = google_protobuf_FeatureSetDefaults_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_serialize(const google_protobuf_FeatureSetDefaults* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_serialize_ex(const google_protobuf_FeatureSetDefaults* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_defaults(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* google_protobuf_FeatureSetDefaults_defaults(const google_protobuf_FeatureSetDefaults* msg, + size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_FeatureSetDefaults_defaults_upb_array( + const google_protobuf_FeatureSetDefaults* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_FeatureSetDefaults_defaults_mutable_upb_array( + google_protobuf_FeatureSetDefaults* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_minimum_edition(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_minimum_edition(const google_protobuf_FeatureSetDefaults* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_has_minimum_edition(const google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_clear_maximum_edition(google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_maximum_edition(const google_protobuf_FeatureSetDefaults* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_has_maximum_edition(const google_protobuf_FeatureSetDefaults* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault** google_protobuf_FeatureSetDefaults_mutable_defaults(google_protobuf_FeatureSetDefaults* msg, + size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault** google_protobuf_FeatureSetDefaults_resize_defaults(google_protobuf_FeatureSetDefaults* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_add_defaults( + google_protobuf_FeatureSetDefaults* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* sub = + (struct google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault*)_upb_Message_New(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_set_minimum_edition(google_protobuf_FeatureSetDefaults* msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_set_maximum_edition(google_protobuf_FeatureSetDefaults* msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault */ +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(upb_Arena* arena) { + return (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault*)_upb_Message_New(&google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, arena); +} +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* ret = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* ret = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_serialize(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_serialize_ex(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_edition(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_edition(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_overridable_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_overridable_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_clear_fixed_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const google_protobuf_FeatureSet* default_val = NULL; + const google_protobuf_FeatureSet* ret; + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_has_fixed_features(const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_edition(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, int32_t value) { + const upb_MiniTableField field = {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_overridable_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_mutable_overridable_features( + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_overridable_features(msg, sub); + } + return sub; +} +UPB_INLINE void google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_fixed_features(google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, google_protobuf_FeatureSet* value) { + const upb_MiniTableField field = {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__FeatureSet_msg_init); + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE struct google_protobuf_FeatureSet* google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_mutable_fixed_features( + google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* msg, upb_Arena* arena) { + struct google_protobuf_FeatureSet* sub = (struct google_protobuf_FeatureSet*)google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(msg); + if (sub == NULL) { + sub = (struct google_protobuf_FeatureSet*)_upb_Message_New(&google__protobuf__FeatureSet_msg_init, arena); + if (sub) google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_set_fixed_features(msg, sub); + } + return sub; +} + +/* google.protobuf.SourceCodeInfo */ +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google__protobuf__SourceCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(google_protobuf_SourceCodeInfo* msg) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, + size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_SourceCodeInfo_Location* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_location_upb_array( + const google_protobuf_SourceCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_location_mutable_upb_array( + google_protobuf_SourceCodeInfo* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, + size_t* size) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_SourceCodeInfo_Location**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + return (google_protobuf_SourceCodeInfo_Location**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location( + google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__SourceCodeInfo__Location_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_SourceCodeInfo_Location* sub = + (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google__protobuf__SourceCodeInfo__Location_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.SourceCodeInfo.Location */ +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) { + return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google__protobuf__SourceCodeInfo__Location_msg_init, arena); +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo__Location_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__SourceCodeInfo__Location_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo__Location_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__SourceCodeInfo__Location_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_path_upb_array( + const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_path_mutable_upb_array( + google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_span_upb_array( + const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_span_mutable_upb_array( + google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_SourceCodeInfo_Location_leading_detached_comments_upb_array( + const google_protobuf_SourceCodeInfo_Location* msg, size_t* size) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_SourceCodeInfo_Location_leading_detached_comments_mutable_upb_array( + google_protobuf_SourceCodeInfo_Location* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView value) { + const upb_MiniTableField field = {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, + size_t* size) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (upb_StringView*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (upb_StringView*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, + upb_Arena* arena) { + upb_MiniTableField field = {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} + +/* google.protobuf.GeneratedCodeInfo */ +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(google_protobuf_GeneratedCodeInfo* msg) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, + size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_GeneratedCodeInfo_annotation_upb_array( + const google_protobuf_GeneratedCodeInfo* msg, size_t* size) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_GeneratedCodeInfo_annotation_mutable_upb_array( + google_protobuf_GeneratedCodeInfo* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, + size_t* size) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (google_protobuf_GeneratedCodeInfo_Annotation**)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + return (google_protobuf_GeneratedCodeInfo_Annotation**)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation( + google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { + upb_MiniTableField field = {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + UPB_PRIVATE(_upb_MiniTable_StrongReference)(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init); + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return NULL; + } + struct google_protobuf_GeneratedCodeInfo_Annotation* sub = + (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init, arena); + if (!arr || !sub) return NULL; + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &sub, sizeof(sub)); + return sub; +} + +/* google.protobuf.GeneratedCodeInfo.Annotation */ +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) { + return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google__protobuf__GeneratedCodeInfo__Annotation_msg_init, arena); +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, + upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, + size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t const*)upb_Array_DataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +// +UPB_INLINE const upb_Array* _google_protobuf_GeneratedCodeInfo_Annotation_path_upb_array( + const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + const upb_Array* arr = upb_Message_GetArray(UPB_UPCAST(msg), &field); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} + +UPB_INLINE upb_Array* _google_protobuf_GeneratedCodeInfo_Annotation_path_mutable_upb_array( + google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* size, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray(UPB_UPCAST(msg), + &field, arena); + if (size) { + *size = arr ? arr->UPB_PRIVATE(size) : 0; + } + return arr; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, + size_t* size) { + upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetMutableArray(UPB_UPCAST(msg), &field); + if (arr) { + if (size) *size = arr->UPB_PRIVATE(size); + return (int32_t*)upb_Array_MutableDataPtr(arr); + } else { + if (size) *size = 0; + return NULL; + } +} + +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, + size_t size, + upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + return (int32_t*)upb_Message_ResizeArrayUninitialized( + UPB_UPCAST(msg), &field, size, arena); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, + upb_Arena* arena) { + upb_MiniTableField field = {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + upb_Array* arr = upb_Message_GetOrCreateMutableArray( + UPB_UPCAST(msg), &field, arena); + if (!arr || !UPB_PRIVATE(_upb_Array_ResizeUninitialized)( + arr, arr->UPB_PRIVATE(size) + 1, arena)) { + return false; + } + UPB_PRIVATE(_upb_Array_Set) + (arr, arr->UPB_PRIVATE(size) - 1, &val, sizeof(val)); + return true; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +/* Max size 32 is google.protobuf.FileOptions */ +/* Max size 64 is google.protobuf.FileOptions */ +#define _UPB_MAXOPT_SIZE UPB_SIZE(112, 200) +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_ */ +#endif + +// IWYU pragma: end_exports + +#endif // GOOGLE_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H__ + +// Forward declarations for circular references. +typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; +typedef struct upb_EnumValueDef upb_EnumValueDef; +typedef struct upb_ExtensionRange upb_ExtensionRange; +typedef struct upb_FieldDef upb_FieldDef; +typedef struct upb_FileDef upb_FileDef; +typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; +typedef struct upb_MethodDef upb_MethodDef; +typedef struct upb_OneofDef upb_OneofDef; +typedef struct upb_ServiceDef upb_ServiceDef; + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +typedef struct upb_DefBuilder upb_DefBuilder; + +#endif /* UPB_REFLECTION_COMMON_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API void upb_DefPool_Free(upb_DefPool* s); + +UPB_NODISCARD UPB_API upb_DefPool* upb_DefPool_New(void); + +UPB_API const google_protobuf_FeatureSetDefaults* upb_DefPool_FeatureSetDefaults( + const upb_DefPool* s); + +UPB_NODISCARD UPB_API bool upb_DefPool_SetFeatureSetDefaults( + upb_DefPool* s, const char* serialized_defaults, size_t serialized_len, + upb_Status* status); + +UPB_API const upb_MessageDef* upb_DefPool_FindMessageByName( + const upb_DefPool* s, const char* sym); + +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +UPB_API const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym); + +UPB_API const upb_EnumDef* upb_DefPool_FindEnumByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +UPB_API const upb_EnumValueDef* upb_DefPool_FindEnumValueByName( + const upb_DefPool* s, const char* sym); + +UPB_API const upb_EnumValueDef* upb_DefPool_FindEnumValueByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len); + +UPB_API const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name); + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len); + +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext); + +UPB_API const upb_FieldDef* upb_DefPool_FindExtensionByName( + const upb_DefPool* s, const char* sym); + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum); + +UPB_API const upb_ServiceDef* upb_DefPool_FindServiceByName( + const upb_DefPool* s, const char* name); + +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size); + +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name); + +UPB_NODISCARD UPB_API const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status); + +UPB_API const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s); + +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count); + +// If called, closed enums will be treated as open enums. This is non-standard +// behavior and will cause conformance tests to fail, but it is more useful +// behavior overall and can be used in situations where where the +// non-conformance is acceptable. +// +// This function may only be called immediately after upb_DefPool_New(). +// It is an error to call it on an existing def pool or after defs have +// already been added to the pool. +// +// Note: we still require that implicit presence fields have zero as their +// default value. +UPB_API void upb_DefPool_DisableClosedEnumChecking(upb_DefPool* s); +bool upb_DefPool_ClosedEnumCheckingDisabled(const upb_DefPool* s); + +// If called, implicit field presence will be disabled. +// This is non-standard behavior and will cause conformance tests to fail, but +// it can be used in situations where where the non-conformance is acceptable. +// +// This function may only be called immediately after upb_DefPool_New(). +// It is an error to call it on an existing def pool or after defs have +// already been added to the pool. +UPB_API void upb_DefPool_DisableImplicitFieldPresence(upb_DefPool* s); +bool upb_DefPool_ImplicitFieldPresenceDisabled(const upb_DefPool* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_DEF_H_ +#define UPB_REFLECTION_ENUM_DEF_H_ + +#include +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num); +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e); +int32_t upb_EnumDef_Default(const upb_EnumDef* e); +UPB_API const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e); +UPB_API const upb_EnumValueDef* upb_EnumDef_FindByJsonNameWithSize( + const upb_EnumDef* e, const char* name, size_t size); +UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindByJsonName( + const upb_EnumDef* e, const char* name) { + return upb_EnumDef_FindByJsonNameWithSize(e, name, strlen(name)); +} +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name); +UPB_API const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size); +UPB_API const upb_EnumValueDef* upb_EnumDef_FindValueByNumber( + const upb_EnumDef* e, int32_t num); +UPB_API const char* upb_EnumDef_FullName(const upb_EnumDef* e); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e); +bool upb_EnumDef_IsClosed(const upb_EnumDef* e); + +// Creates a mini descriptor string for an enum, returns true on success. +UPB_NODISCARD bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, + upb_Arena* a, + upb_StringView* out); + +const char* upb_EnumDef_Name(const upb_EnumDef* e); +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); +const google_protobuf_FeatureSet* upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e); +google_protobuf_SymbolVisibility upb_EnumDef_Visibility(const upb_EnumDef* e); + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i); +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e); + +UPB_API const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); +UPB_API int upb_EnumDef_ValueCount(const upb_EnumDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v); +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v); +UPB_API const char* upb_EnumValueDef_JsonName(const upb_EnumValueDef* v); +UPB_API const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); +UPB_API int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v); +const google_protobuf_FeatureSet* upb_EnumValueDef_ResolvedFeatures( + const upb_EnumValueDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r); +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r); +const google_protobuf_FeatureSet* upb_ExtensionRange_ResolvedFeatures( + const upb_ExtensionRange* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FIELD_DEF_H_ +#define UPB_REFLECTION_FIELD_DEF_H_ + +#include + + +// Must be last. + +// Maximum field number allowed for FieldDefs. +// This is an inherent limit of the protobuf wire format. +#define kUpb_MaxFieldNumber ((1 << 29) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f); +UPB_API const upb_MessageDef* upb_FieldDef_ContainingType( + const upb_FieldDef* f); +UPB_API upb_CType upb_FieldDef_CType(const upb_FieldDef* f); +UPB_API upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); +UPB_API const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f); +UPB_API const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f); +const char* upb_FieldDef_FullName(const upb_FieldDef* f); +bool upb_FieldDef_HasDefault(const upb_FieldDef* f); +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_HasPresence(const upb_FieldDef* f); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f); +uint32_t upb_FieldDef_Index(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsEnum(const upb_FieldDef* f); +bool upb_FieldDef_IsExtension(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsMap(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +bool _upb_FieldDef_IsPackable(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsPacked(const upb_FieldDef* f); +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsRequired(const upb_FieldDef* f); +bool upb_FieldDef_IsString(const upb_FieldDef* f); +UPB_API bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); +UPB_API const char* upb_FieldDef_JsonName(const upb_FieldDef* f); +UPB_API upb_Label upb_FieldDef_Label(const upb_FieldDef* f); +uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +UPB_API const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); +bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f); +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f); + +// Creates a mini descriptor string for a field, returns true on success. +UPB_NODISCARD bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, + upb_Arena* a, + upb_StringView* out); + +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const upb_MiniTableExtension* upb_FieldDef_MiniTableExtension( + const upb_FieldDef* f); +UPB_API const char* upb_FieldDef_Name(const upb_FieldDef* f); +UPB_API uint32_t upb_FieldDef_Number(const upb_FieldDef* f); +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); +const google_protobuf_FeatureSet* upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f); +UPB_API const upb_OneofDef* upb_FieldDef_RealContainingOneof( + const upb_FieldDef* f); +UPB_API upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_FILE_DEF_H_ +#define UPB_REFLECTION_FILE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const char* upb_FileDef_EditionName(int edition); + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i); +int upb_FileDef_DependencyCount(const upb_FileDef* f); +bool upb_FileDef_HasOptions(const upb_FileDef* f); +UPB_API const char* upb_FileDef_Name(const upb_FileDef* f); +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f); +const google_protobuf_FeatureSet* upb_FileDef_ResolvedFeatures(const upb_FileDef* f); +const char* upb_FileDef_Package(const upb_FileDef* f); +google_protobuf_Edition upb_FileDef_Edition(const upb_FileDef* f); +UPB_API const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i); +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f); + +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i); +int upb_FileDef_ServiceCount(const upb_FileDef* f); + +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f); + +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f); + +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i); +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); + +// Returns whether |symbol| is transitively included by |f| +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* symbol); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FILE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_DEF_H_ +#define UPB_REFLECTION_MESSAGE_DEF_H_ + + +// Must be last. + +// Well-known field tag numbers for map-entry messages. +#define kUpb_MapEntry_KeyFieldNumber 1 +#define kUpb_MapEntry_ValueFieldNumber 2 + +// Well-known field tag numbers for Any messages. +#define kUpb_Any_TypeFieldNumber 1 +#define kUpb_Any_ValueFieldNumber 2 + +// Well-known field tag numbers for duration messages. +#define kUpb_Duration_SecondsFieldNumber 1 +#define kUpb_Duration_NanosFieldNumber 2 + +// Well-known field tag numbers for timestamp messages. +#define kUpb_Timestamp_SecondsFieldNumber 1 +#define kUpb_Timestamp_NanosFieldNumber 2 + +// All the different kind of well known type messages. For simplicity of check, +// number wrappers and string wrappers are grouped together. Make sure the +// order and number of these groups are not changed. +typedef enum { + kUpb_WellKnown_Unspecified, + kUpb_WellKnown_Any, + kUpb_WellKnown_FieldMask, + kUpb_WellKnown_Duration, + kUpb_WellKnown_Timestamp, + + // number wrappers + kUpb_WellKnown_DoubleValue, + kUpb_WellKnown_FloatValue, + kUpb_WellKnown_Int64Value, + kUpb_WellKnown_UInt64Value, + kUpb_WellKnown_Int32Value, + kUpb_WellKnown_UInt32Value, + + // string wrappers + kUpb_WellKnown_StringValue, + kUpb_WellKnown_BytesValue, + kUpb_WellKnown_BoolValue, + kUpb_WellKnown_Value, + kUpb_WellKnown_ListValue, + kUpb_WellKnown_Struct, +} upb_WellKnown; + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m); + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m); + +UPB_API const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, + int i); +UPB_API int upb_MessageDef_FieldCount(const upb_MessageDef* m); + +UPB_API const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m); + +// Returns a field by either JSON name or regular proto name. +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( + const upb_MessageDef* m, const char* name) { + return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); +} + +// Lookup of either field or oneof by name. Returns whether either was found. +// If the return is true, then the found def will be set, and the non-found +// one set to NULL. +UPB_API bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t size, + const upb_FieldDef** f, + const upb_OneofDef** o); +UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m, + const char* name, + const upb_FieldDef** f, + const upb_OneofDef** o) { + return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o); +} + +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name); +UPB_API const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_API const upb_FieldDef* upb_MessageDef_FindFieldByNumber( + const upb_MessageDef* m, uint32_t i); +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name); +UPB_API const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size); +UPB_API const char* upb_MessageDef_FullName(const upb_MessageDef* m); +bool upb_MessageDef_HasOptions(const upb_MessageDef* m); +bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m); + +// Creates a mini descriptor string for a message, returns true on success. +UPB_NODISCARD bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, + upb_Arena* a, + upb_StringView* out); + +UPB_API const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m); +const char* upb_MessageDef_Name(const upb_MessageDef* m); + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i); +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i); +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i); + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); + +UPB_API const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, + int i); +UPB_API int upb_MessageDef_OneofCount(const upb_MessageDef* m); +int upb_MessageDef_RealOneofCount(const upb_MessageDef* m); + +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); +const google_protobuf_FeatureSet* upb_MessageDef_ResolvedFeatures( + const upb_MessageDef* m); + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m); + +UPB_API upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); +UPB_API google_protobuf_SymbolVisibility +upb_MessageDef_Visibility(const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_METHOD_DEF_H_ +#define UPB_REFLECTION_METHOD_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m); +const char* upb_MethodDef_FullName(const upb_MethodDef* m); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); +UPB_API const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); +UPB_API const char* upb_MethodDef_Name(const upb_MethodDef* m); +UPB_API const google_protobuf_MethodOptions* upb_MethodDef_Options( + const upb_MethodDef* m); +const google_protobuf_FeatureSet* upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m); +UPB_API const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); +UPB_API bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); +UPB_API const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ONEOF_DEF_H_ +#define UPB_REFLECTION_ONEOF_DEF_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const upb_MessageDef* upb_OneofDef_ContainingType( + const upb_OneofDef* o); +UPB_API const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i); +UPB_API int upb_OneofDef_FieldCount(const upb_OneofDef* o); +const char* upb_OneofDef_FullName(const upb_OneofDef* o); +bool upb_OneofDef_HasOptions(const upb_OneofDef* o); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o); +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o); +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name); +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size); +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num); +UPB_API const char* upb_OneofDef_Name(const upb_OneofDef* o); +int upb_OneofDef_numfields(const upb_OneofDef* o); +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); +const google_protobuf_FeatureSet* upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_SERVICE_DEF_H_ +#define UPB_REFLECTION_SERVICE_DEF_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_API const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name); +const upb_MethodDef* upb_ServiceDef_FindMethodByNameWithSize( + const upb_ServiceDef* s, const char* name, size_t len); +UPB_API const char* upb_ServiceDef_FullName(const upb_ServiceDef* s); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s); +int upb_ServiceDef_Index(const upb_ServiceDef* s); +UPB_API const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, + int i); +UPB_API int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); +const char* upb_ServiceDef_Name(const upb_ServiceDef* s); +UPB_API const google_protobuf_ServiceOptions* upb_ServiceDef_Options( + const upb_ServiceDef* s); +const google_protobuf_FeatureSet* upb_ServiceDef_ResolvedFeatures( + const upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_H_ */ +// IWYU pragma: end_exports + +#endif /* UPB_REFLECTION_DEF_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +enum { + kUpb_JsonDecodeResult_Ok = 0, + kUpb_JsonDecodeResult_Error = 2, +}; + +UPB_NODISCARD UPB_API int upb_JsonDecodeDetectingNonconformance( + const char* buf, size_t size, upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* symtab, int options, upb_Arena* arena, + upb_Status* status); + +UPB_NODISCARD UPB_API_INLINE bool upb_JsonDecode(const char* buf, size_t size, + upb_Message* msg, + const upb_MessageDef* m, + const upb_DefPool* symtab, + int options, upb_Arena* arena, + upb_Status* status) { + return upb_JsonDecodeDetectingNonconformance(buf, size, msg, m, symtab, + options, arena, status) == + kUpb_JsonDecodeResult_Ok; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONDECODE_H_ */ + +#ifndef UPB_LEX_ATOI_H_ +#define UPB_LEX_ATOI_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// We use these hand-written routines instead of strto[u]l() because the "long +// long" variants aren't in c89. Also our version allows setting a ptr limit. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ATOI_H_ */ + +#ifndef UPB_LEX_UNICODE_H_ +#define UPB_LEX_UNICODE_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true iff a codepoint is the value for a high surrogate. +UPB_INLINE bool upb_Unicode_IsHigh(uint32_t cp) { + return (cp >= 0xd800 && cp <= 0xdbff); +} + +// Returns true iff a codepoint is the value for a low surrogate. +UPB_INLINE bool upb_Unicode_IsLow(uint32_t cp) { + return (cp >= 0xdc00 && cp <= 0xdfff); +} + +// Returns the high 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToHigh(uint32_t cp) { + return (cp >> 10) + 0xd7c0; +} + +// Returns the low 16-bit surrogate value for a supplementary codepoint. +// Does not sanity-check the input. +UPB_INLINE uint16_t upb_Unicode_ToLow(uint32_t cp) { + return (cp & 0x3ff) | 0xdc00; +} + +// Returns the 32-bit value corresponding to a pair of 16-bit surrogates. +// Does not sanity-check the input. +UPB_INLINE uint32_t upb_Unicode_FromPair(uint32_t high, uint32_t low) { + return ((high & 0x3ff) << 10) + (low & 0x3ff) + 0x10000; +} + +// Outputs a codepoint as UTF8. +// Returns the number of bytes written (1-4 on success, 0 on error). +// Does not sanity-check the input. Specifically does not check for surrogates. +int upb_Unicode_ToUTF8(uint32_t cp, char* out); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_UNICODE_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_H_ +#define UPB_REFLECTION_MESSAGE_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns a mutable pointer to a map, array, or submessage value. If the given +// arena is non-NULL this will construct a new object if it was not previously +// present. May not be called for primitive fields. +UPB_NODISCARD UPB_API upb_MutableMessageValue +upb_Message_Mutable(upb_Message* msg, const upb_FieldDef* f, upb_Arena* a); + +// Returns the field that is set in the oneof, or NULL if none are set. +UPB_API const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o); + +// Clear all data and unknown fields. +void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m); + +// Clears any field presence and sets the value back to its default. +UPB_API void upb_Message_ClearFieldByDef(upb_Message* msg, + const upb_FieldDef* f); + +// May only be called for fields where upb_FieldDef_HasPresence(f) == true. +UPB_API bool upb_Message_HasFieldByDef(const upb_Message* msg, + const upb_FieldDef* f); + +// Returns the value in the message associated with this field def. +UPB_API upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg, + const upb_FieldDef* f); + +// Sets the given field to the given value. For a msg/array/map/string, the +// caller must ensure that the target data outlives |msg| (by living either in +// the same arena or a different arena that outlives it). +// +// Returns false if allocation fails. +UPB_NODISCARD UPB_API bool upb_Message_SetFieldByDef(upb_Message* msg, + const upb_FieldDef* f, + upb_MessageValue val, + upb_Arena* a); + +// Iterate over present fields. +// +// size_t iter = kUpb_Message_Begin; +// const upb_FieldDef *f; +// upb_MessageValue val; +// while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { +// process_field(f, val); +// } +// +// If ext_pool is NULL, no extensions will be returned. If the given symtab +// returns extensions that don't match what is in this message, those extensions +// will be skipped. + +#define kUpb_Message_Begin -1 + +UPB_API bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, + const upb_FieldDef** f, upb_MessageValue* val, + size_t* iter); + +// Clears all unknown field data from this message and all submessages. +UPB_API bool upb_Message_DiscardUnknown(upb_Message* msg, + const upb_MessageDef* m, + const upb_DefPool* ext_pool, + int maxdepth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_H_ */ + +#ifndef UPB_JSON_ENCODE_H_ +#define UPB_JSON_ENCODE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* When set, emits 0/default values. TODO: proto3 only? */ + upb_JsonEncode_EmitDefaults = 1 << 0, + + /* When set, use normal (snake_case) field names instead of JSON (camelCase) + names. */ + upb_JsonEncode_UseProtoNames = 1 << 1, + + /* When set, emits enums as their integer values instead of as their names. */ + upb_JsonEncode_FormatEnumsAsIntegers = 1 << 2 +}; + +/* Encodes the given |msg| to JSON format. The message's reflection is given in + * |m|. The DefPool in |ext_pool| is used to find extensions (if NULL, + * extensions will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +UPB_API size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, + char* buf, size_t size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_JSONENCODE_H_ */ + +#ifndef UPB_LEX_ROUND_TRIP_H_ +#define UPB_LEX_ROUND_TRIP_H_ + +// Must be last. + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. + +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; + +#ifdef __cplusplus +extern "C" { +#endif + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ROUND_TRIP_H_ */ + +#ifndef UPB_PORT_VSNPRINTF_COMPAT_H_ +#define UPB_PORT_VSNPRINTF_COMPAT_H_ + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif +} + + +#endif // UPB_PORT_VSNPRINTF_COMPAT_H_ + +#ifndef UPB_PORT_ATOMIC_H_ +#define UPB_PORT_ATOMIC_H_ + + +#ifdef UPB_USE_C11_ATOMICS + +// IWYU pragma: begin_exports +#include +#include +// IWYU pragma: end_exports + +#define upb_Atomic_Init(addr, val) atomic_init(addr, val) +#define upb_Atomic_Load(addr, order) atomic_load_explicit(addr, order) +#define upb_Atomic_Store(addr, val, order) \ + atomic_store_explicit(addr, val, order) +#define upb_Atomic_Exchange(addr, val, order) \ + atomic_exchange_explicit(addr, val, order) +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + atomic_compare_exchange_strong_explicit(addr, expected, desired, \ + success_order, failure_order) +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + atomic_compare_exchange_weak_explicit(addr, expected, desired, \ + success_order, failure_order) +#define upb_Atomic_Add(addr, val, order) \ + atomic_fetch_add_explicit(addr, val, order) +#define upb_Atomic_Sub(addr, val, order) \ + atomic_fetch_sub_explicit(addr, val, order) + +#elif defined(UPB_USE_MSC_ATOMICS) +#include +#include +#include + +#define upb_Atomic_Init(addr, val) (*(addr) = val) + +#pragma intrinsic(_InterlockedExchange) +static int32_t upb_Atomic_LoadMsc32(int32_t volatile* addr) { + // Compare exchange with an unlikely value reduces the risk of a spurious + // (but harmless) store + return _InterlockedCompareExchange(addr, 0xDEADC0DE, 0xDEADC0DE); +} + +#pragma intrinsic(_InterlockedCompareExchange) +static bool upb_Atomic_CompareExchangeMscP32(int32_t volatile* addr, + int32_t* expected, + int32_t desired) { + int32_t expect_val = *expected; + int32_t actual_val = _InterlockedCompareExchange(addr, desired, expect_val); + if (expect_val != actual_val) { + *expected = actual_val; + return false; + } + return true; +} + +#if defined(_WIN64) +// MSVC, without C11 atomics, does not have any way in pure C to force +// load-acquire store-release behavior, so we hack it with exchanges. +#pragma intrinsic(_InterlockedCompareExchange64) +static uintptr_t upb_Atomic_LoadMsc64(uint64_t volatile* addr) { + // Compare exchange with an unlikely value reduces the risk of a spurious + // (but harmless) store + return _InterlockedCompareExchange64(addr, 0xDEADC0DEBAADF00D, + 0xDEADC0DEBAADF00D); +} + +#pragma intrinsic(_InterlockedCompareExchange64) +static bool upb_Atomic_CompareExchangeMscP64(uint64_t volatile* addr, + uint64_t* expected, + uint64_t desired) { + uint64_t expect_val = *expected; + uint64_t actual_val = + _InterlockedCompareExchange64(addr, desired, expect_val); + if (expect_val != actual_val) { + *expected = actual_val; + return false; + } + return true; +} + +#pragma intrinsic(_InterlockedExchange64) +// If _Generic is available, use it to avoid emitting a "'uintptr_t' differs in +// levels of indirection from 'void *'" or -Wint-conversion compiler warning. +#if __STDC_VERSION__ >= 201112L +#define upb_Atomic_Store(addr, val, order) \ + _Generic(addr, \ + UPB_ATOMIC(uintptr_t)*: (void)_InterlockedExchange64( \ + (uint64_t volatile*)(addr), (uint64_t)val), \ + UPB_ATOMIC(int32_t)*: (void)_InterlockedExchange( \ + (int32_t volatile*)(addr), (int32_t)val), \ + default: (void)_InterlockedExchange64((uint64_t volatile*)addr, \ + (uint64_t)val)) + +#define upb_Atomic_Load(addr, order) \ + _Generic(addr, \ + UPB_ATOMIC(uintptr_t)*: upb_Atomic_LoadMsc64( \ + (uint64_t volatile*)(addr)), \ + UPB_ATOMIC(int32_t)*: upb_Atomic_LoadMsc32((int32_t volatile*)(addr)), \ + default: (void*)upb_Atomic_LoadMsc64((uint64_t volatile*)(addr))) + +#define upb_Atomic_Exchange(addr, val, order) \ + _Generic(addr, \ + UPB_ATOMIC(uintptr_t)*: _InterlockedExchange64( \ + (uint64_t volatile*)(addr), (uint64_t)val), \ + UPB_ATOMIC(int32_t)*: _InterlockedExchange((int32_t volatile*)(addr), \ + (int32_t)val), \ + default: (void*)_InterlockedExchange64((uint64_t volatile*)addr, \ + (uint64_t)val)) + +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + _Generic(addr, \ + UPB_ATOMIC(int32_t)*: upb_Atomic_CompareExchangeMscP32( \ + (int32_t volatile*)(addr), (int32_t*)expected, \ + (int32_t)desired), \ + default: upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)(addr), \ + (uint64_t*)expected, \ + (uint64_t)desired)) + +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + _Generic(addr, \ + UPB_ATOMIC(int32_t)*: upb_Atomic_CompareExchangeMscP32( \ + (int32_t volatile*)(addr), (int32_t*)expected, \ + (int32_t)desired), \ + default: upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)(addr), \ + (uint64_t*)expected, \ + (uint64_t)desired)) + +#else + +UPB_INLINE void _upb_Atomic_StoreP(void volatile* addr, uint64_t val, + size_t size) { + if (size == sizeof(int32_t)) { + (void)_InterlockedExchange((int32_t volatile*)addr, (int32_t)val); + } else { + (void)_InterlockedExchange64((uint64_t volatile*)addr, val); + } +} + +#define upb_Atomic_Store(addr, val, order) \ + _upb_Atomic_StoreP(addr, val, sizeof(*addr)) + +UPB_INLINE int64_t _upb_Atomic_LoadP(void volatile* addr, size_t size) { + if (size == sizeof(int32_t)) { + return (int64_t)upb_Atomic_LoadMsc32((int32_t volatile*)addr); + } else { + return upb_Atomic_LoadMsc64((uint64_t volatile*)addr); + } +} + +#define upb_Atomic_Load(addr, order) \ + (void*)_upb_Atomic_LoadP((void volatile*)addr, sizeof(*addr)) + +UPB_INLINE int64_t _upb_Atomic_ExchangeP(void volatile* addr, uint64_t val, + size_t size) { + if (size == sizeof(int32_t)) { + return (int64_t)_InterlockedExchange((int32_t volatile*)addr, (int32_t)val); + } else { + return (int64_t)_InterlockedExchange64((uint64_t volatile*)addr, val); + } +} + +#define upb_Atomic_Exchange(addr, val, order) \ + (void*)_upb_Atomic_ExchangeP((void volatile*)addr, (uint64_t)val, \ + sizeof(*addr)) + +UPB_INLINE bool _upb_Atomic_CompareExchangeMscP(void volatile* addr, + void* expected, + uint64_t desired, size_t size) { + if (size == sizeof(int32_t)) { + return upb_Atomic_CompareExchangeMscP32( + (int32_t volatile*)addr, (int32_t*)expected, (int32_t)desired); + } else { + return upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)addr, + (uint64_t*)expected, desired); + } +} + +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + _upb_Atomic_CompareExchangeMscP(addr, expected, (uint64_t)desired, \ + sizeof(*addr)) + +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + _upb_Atomic_CompareExchangeMscP(addr, expected, (uint64_t)desired, \ + sizeof(*addr)) + +#endif + +#else // 32 bit pointers +#pragma intrinsic(_InterlockedExchange) +#define upb_Atomic_Store(addr, val, order) \ + (void)_InterlockedExchange((uint32_t volatile*)addr, (uint32_t)val) + +// If _Generic is available, use it to avoid emitting 'uintptr_t' differs in +// levels of indirection from 'void *' +#if __STDC_VERSION__ >= 201112L +#define upb_Atomic_Load(addr, order) \ + _Generic(addr, \ + UPB_ATOMIC(uintptr_t)*: (uintptr_t)upb_Atomic_LoadMsc32( \ + (uint32_t volatile*)(addr)), \ + UPB_ATOMIC(int32_t)*: upb_Atomic_LoadMsc32((int32_t volatile*)(addr)), \ + default: (void*)upb_Atomic_LoadMsc32((uint32_t volatile*)(addr))) + +#define upb_Atomic_Exchange(addr, val, order) \ + _Generic(addr, \ + UPB_ATOMIC(uintptr_t)*: _InterlockedExchange((uint32_t volatile*)(addr), \ + (uint32_t)val), \ + default: (void*)_InterlockedExchange((uint32_t volatile*)addr, \ + (uint32_t)val)) +#else +#define upb_Atomic_Load(addr, order) \ + (void*)upb_Atomic_LoadMsc32((uint32_t volatile*)(addr)) + +#define upb_Atomic_Exchange(addr, val, order) \ + (void*)_InterlockedExchange((uint32_t volatile*)addr, (uint32_t)val) +#endif + +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + upb_Atomic_CompareExchangeMscP32((uint32_t volatile*)addr, \ + (uint32_t*)expected, (uint32_t)desired) + +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + upb_Atomic_CompareExchangeMscP32((uint32_t volatile*)addr, \ + (uint32_t*)expected, (uint32_t)desired) +#endif + +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchangeAdd64) + +// If _Generic is available, use it to switch between 32 and 64 bit types. +#if __STDC_VERSION__ >= 201112L +#define upb_Atomic_Add(addr, val, order) \ + _Generic(addr, \ + UPB_ATOMIC(int64_t)*: _InterlockedExchangeAdd64(addr, (int64_t)val), \ + UPB_ATOMIC(int32_t)*: _InterlockedExchangeAdd(addr, (int32_t)val)) +#define upb_Atomic_Sub(addr, val, order) \ + _Generic(addr, \ + UPB_ATOMIC(int64_t)*: _InterlockedExchangeAdd64(addr, -(int64_t)val), \ + UPB_ATOMIC(int32_t)*: _InterlockedExchangeAdd(addr, -(int32_t)val)) +#else +#define upb_Atomic_Add(addr, val, order) \ + sizeof(*addr) == sizeof(int32_t) \ + ? _InterlockedExchangeAdd((uint32_t volatile*)addr, (int32_t)val) \ + : _InterlockedExchangeAdd64((uint64_t volatile*)addr, (int64_t)val) +#define upb_Atomic_Sub(addr, val, order) \ + sizeof(*addr) == sizeof(int32_t) \ + ? _InterlockedExchangeAdd((uint32_t volatile*)addr, -(int32_t)val) \ + : _InterlockedExchangeAdd64((uint64_t volatile*)addr, -(int64_t)val) +#endif + +#else // No atomics + +#if !defined(UPB_SUPPRESS_MISSING_ATOMICS) +// NOLINTNEXTLINE +#error Your compiler does not support atomic instructions, which UPB uses. If you do not use UPB on multiple threads, you can suppress this error by defining UPB_SUPPRESS_MISSING_ATOMICS. +#endif + +#include + +#define upb_Atomic_Init(addr, val) (*addr = val) +#define upb_Atomic_Load(addr, order) (*addr) +#define upb_Atomic_Store(addr, val, order) (*(addr) = val) + +UPB_INLINE void* _upb_NonAtomic_Exchange(void* addr, void* value) { + void* old; + memcpy(&old, addr, sizeof(value)); + memcpy(addr, &value, sizeof(value)); + return old; +} + +#define upb_Atomic_Exchange(addr, val, order) _upb_NonAtomic_Exchange(addr, val) + +// `addr` and `expected` are logically double pointers. +UPB_INLINE bool _upb_NonAtomic_CompareExchangeStrongP(void* addr, + void* expected, + void* desired) { + if (memcmp(addr, expected, sizeof(desired)) == 0) { + memcpy(addr, &desired, sizeof(desired)); + return true; + } else { + memcpy(expected, addr, sizeof(desired)); + return false; + } +} + +#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \ + success_order, failure_order) \ + _upb_NonAtomic_CompareExchangeStrongP((void*)addr, (void*)expected, \ + (void*)desired) +#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \ + failure_order) \ + upb_Atomic_CompareExchangeStrong(addr, expected, desired, 0, 0) + +#define upb_Atomic_Add(addr, val, order) (*addr += val) +#define upb_Atomic_Sub(addr, val, order) (*addr -= val) + +#endif + + +#endif // UPB_PORT_ATOMIC_H_ + +#ifndef UPB_MESSAGE_COMPAT_H_ +#define UPB_MESSAGE_COMPAT_H_ + +#include + + +// Must be last. + +// upb does not support mixing minitables from different sources but these +// functions are still used by some existing users so for now we make them +// available here. This may or may not change in the future so do not add +// them to new code. + +#ifdef __cplusplus +extern "C" { +#endif + +// Same as upb_Message_NextExtension but iterates in reverse wire order +bool upb_Message_NextExtensionReverse(const upb_Message* msg, + const upb_MiniTableExtension** result, + uintptr_t* iter); +// Returns the minitable with the given field number, or NULL on failure. +const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( + const upb_Message* msg, uint32_t field_number); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_COMPAT_H_ */ + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ +#define UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ + +#include +#include +#include + + +#ifndef UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ +#define UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ + +#include + + +// Map entries aren't actually stored for map fields, they are only used during +// parsing. (It helps a lot if all map entry messages have the same layout.) +// The mini_table layout code will ensure that all map entries have this layout. +// +// Note that users can and do create map entries directly, which will also use +// this layout. + +typedef struct { + struct upb_Message message; + // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here, + // and the uint64_t helps make this clear. + uint64_t hasbits; + union { + upb_StringView str; // For str/bytes. + upb_value val; // For all other types. + double d[2]; // Padding for 32-bit builds. + } k; + union { + upb_StringView str; // For str/bytes. + upb_value val; // For all other types. + double d[2]; // Padding for 32-bit builds. + } v; +} upb_MapEntry; + +#endif // UPB_MESSAGE_INTERNAL_MAP_ENTRY_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. + +typedef struct { + void const** entries; + int size; + int cap; +} _upb_mapsorter; + +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) upb_gfree(s->entries); +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, + const struct upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = (const upb_tabent*)s->entries[sorted->pos++]; + if (map->UPB_PRIVATE(is_strtable)) { + upb_StringView key = upb_key_strview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + } else { + uintptr_t key = tabent->key.num; + memcpy(&ent->k, &key, map->key_size); + } + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + +UPB_INLINE bool _upb_sortedmap_nextext(_upb_mapsorter* s, + _upb_sortedmap* sorted, + const upb_Extension** ext) { + if (sorted->pos == sorted->end) return false; + *ext = (const upb_Extension*)s->entries[sorted->pos++]; + return true; +} + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const struct upb_Map* map, _upb_sortedmap* sorted); + +bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in, + _upb_sortedmap* sorted); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */ + +#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_ +#define UPB_MESSAGE_UNKNOWN_FIELDS_H_ + +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Support iteration over unknown (upb_MessageUnknown*), including unknown +// upb_StringView and non-canonical extensions (upb_Extension*). +UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg, + struct upb_MessageUnknown* data, + uintptr_t* iter) { + const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); + size_t i = *iter; + if (in) { + while (i < in->size) { + upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++]; + if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { + data->type = kUpb_MessageUnknownType_StringView; + data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr); + *iter = i; + return true; + } else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) { + data->type = kUpb_MessageUnknownType_NonCanonicalExtension; + data->value.extension = + upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr); + *iter = i; + return true; + } + } + } + data->type = kUpb_MessageUnknownType_StringView; + data->value.bytes.size = 0; + data->value.bytes.data = NULL; + *iter = i; + return false; +} + +typedef enum { + kUpb_FindUnknown_Ok, + kUpb_FindUnknown_NotPresent, + kUpb_FindUnknown_ParseError, +} upb_FindUnknown_Status; + +typedef struct { + upb_FindUnknown_Status status; + struct upb_MessageUnknown unknown; + uintptr_t iter; +} upb_FindUnknownRet2; + +// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in +// message, including unknown upb_StringView and non-canonical extensions +// (upb_Extension*). +// +// If multiple matching entries exist for the same field number (e.g. both a +// raw unknown upb_StringView and a non-canonical extension), this function +// returns the one encountered first in internal iteration order (which follows +// the order they were added or parsed). +// +// A depth_limit of zero means to just use the upb default depth limit. +upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg, + uint32_t field_number, + int depth_limit); + +// Removes a segment of unknown data from the message, advancing to the next +// segment. Returns false if the removed segment was at the end of the last +// chunk. +// +// This must be done while iterating: +// +// uintptr_t iter = kUpb_Message_UnknownBegin; +// upb_MessageUnknown data; +// // Iterate chunks +// while (upb_Message_NextUnknown2(msg, &data, &iter)) { +// // Iterate within a chunk, deleting ranges +// while (ShouldDeleteSubSegment(&data)) { +// // Data now points to the region to be deleted +// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) { +// case kUpb_Message_DeleteUnknown_DeletedLast: return ok; +// case kUpb_Message_DeleteUnknown_IterUpdated: break; +// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated, +// // then data now points to the remaining unknown fields after the +// // region that was just deleted. +// case kUpb_Message_DeleteUnknown_AllocFail: return err; +// } +// } +// } +// +// The range given in `data` must be contained inside the most recently +// returned region. +// +// Support deletion of unknown (upb_MessageUnknown*), including unknown +// upb_StringView and non-canonical extensions (upb_Extension*). +UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2( + struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter, + struct upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */ + +#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ +#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ + +#include +#include + + +#ifndef UPB_WIRE_INTERNAL_EPS_COPY_INPUT_STREAM_H_ +#define UPB_WIRE_INTERNAL_EPS_COPY_INPUT_STREAM_H_ + +#include +#include +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// The maximum number of bytes a single protobuf field can take up in the +// wire format. We only want to do one bounds check per field, so the input +// stream guarantees that after upb_EpsCopyInputStream_IsDone() is called, +// the decoder can read this many bytes without performing another bounds +// check. The stream will copy into a patch buffer as necessary to guarantee +// this invariant. Since tags can only be up to 5 bytes, and a max-length scalar +// field can be 10 bytes, only 15 is required; but sizing up to 16 permits more +// efficient fixed size copies. +#define kUpb_EpsCopyInputStream_SlopBytes 16 + +struct upb_EpsCopyCapture { + const char* start; // Pointer to the beginning of the captured region. +}; + +struct upb_EpsCopyInputStream { + const char* end; // Can read up to SlopBytes bytes beyond this. + const char* limit_ptr; // For bounds checks, = end + UPB_MIN(limit, 0) + uintptr_t input_delta; // Diff between the original input pointer and patch + const char* buffer_start; // Pointer to the original input buffer + ptrdiff_t limit; // Submessage limit relative to end + upb_ErrorHandler* err; // Error handler to use when things go wrong. + bool error; // To distinguish between EOF and error. +#ifndef NDEBUG + int guaranteed_bytes; +#endif + // Allocate double the size of what's required; this permits a fixed-size copy + // from the input buffer, regardless of how many bytes actually remain in the + // input buffer. + char patch[kUpb_EpsCopyInputStream_SlopBytes * 2]; +}; + +UPB_INLINE void UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)( + struct upb_EpsCopyInputStream* e); + +UPB_INLINE bool upb_EpsCopyInputStream_IsError( + struct upb_EpsCopyInputStream* e) { + return e->error; +} + +UPB_INLINE void upb_EpsCopyInputStream_InitWithErrorHandler( + struct upb_EpsCopyInputStream* e, const char** ptr, size_t size, + upb_ErrorHandler* err) { + e->buffer_start = *ptr; + e->err = err; + if (size <= kUpb_EpsCopyInputStream_SlopBytes) { + memset(&e->patch, 0, 32); + if (size) memcpy(&e->patch, *ptr, size); + e->input_delta = (uintptr_t)*ptr - (uintptr_t)e->patch; + *ptr = e->patch; + e->end = *ptr + size; + e->limit = 0; + } else { + e->end = *ptr + size - kUpb_EpsCopyInputStream_SlopBytes; + e->limit = kUpb_EpsCopyInputStream_SlopBytes; + e->input_delta = 0; + } + e->limit_ptr = e->end; + e->error = false; + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)(e); +} + +UPB_INLINE void upb_EpsCopyInputStream_Init(struct upb_EpsCopyInputStream* e, + const char** ptr, size_t size) { + upb_EpsCopyInputStream_InitWithErrorHandler(e, ptr, size, NULL); +} + +UPB_ATTR_CONST +UPB_INLINE bool upb_EpsCopyInputStream_HasErrorHandler( + const struct upb_EpsCopyInputStream* e) { + return e && e->err != NULL; +} + +UPB_NORETURN UPB_NOINLINE void UPB_PRIVATE( + upb_EpsCopyInputStream_ThrowMalformed)(struct upb_EpsCopyInputStream* e); + +// Call this function to signal an error. If an error handler is set, it will be +// called and the function will never return. Otherwise, returns NULL to +// indicate an error. +UPB_INLINE const char* UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)( + struct upb_EpsCopyInputStream* e) { + if (e->err) { + UPB_PRIVATE(upb_EpsCopyInputStream_ThrowMalformed)(e); + } else { + e->error = true; + } + return NULL; +} + +UPB_INLINE const char* UPB_PRIVATE(upb_EpsCopyInputStream_AssumeResult)( + struct upb_EpsCopyInputStream* e, const char* ptr) { + UPB_MAYBE_ASSUME(upb_EpsCopyInputStream_HasErrorHandler(e), ptr != NULL); + return ptr; +} + +//////////////////////////////////////////////////////////////////////////////// + +// Debug checks that attempt to ensure that no code paths will overrun the slop +// bytes even in the worst case. Since we are frequently parsing varints, it's +// possible that the user is trying to parse too many varints before calling +// upb_EpsCopyInputStream_IsDone(), but this error case is not detected because +// the varints are short. These checks ensure that will not overrun the slop +// bytes, even if each varint is its maximum possible length. + +UPB_INLINE void UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)( + struct upb_EpsCopyInputStream* e) { +#ifndef NDEBUG + e->guaranteed_bytes = kUpb_EpsCopyInputStream_SlopBytes; +#endif +} + +UPB_INLINE void UPB_PRIVATE(upb_EpsCopyInputStream_BoundsHit)( + struct upb_EpsCopyInputStream* e) { +#ifndef NDEBUG + e->guaranteed_bytes = 0; +#endif +} + +// Signals the maximum number that the operation about to be performed may +// consume. +UPB_INLINE void UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)( + struct upb_EpsCopyInputStream* e, int n) { +#ifndef NDEBUG + if (e) { + UPB_ASSERT(e->guaranteed_bytes >= n); + e->guaranteed_bytes -= n; + } +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + +typedef enum { + // The current stream position is at a limit. + kUpb_IsDoneStatus_Done, + + // The current stream position is not at a limit. + kUpb_IsDoneStatus_NotDone, + + // The current stream position is not at a limit, and the stream needs to + // be flipped to a new buffer before more data can be read. + kUpb_IsDoneStatus_NeedFallback, +} upb_IsDoneStatus; + +// Returns the status of the current stream position. This is a low-level +// function, it is simpler to call upb_EpsCopyInputStream_IsDone() if possible. +UPB_INLINE upb_IsDoneStatus UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneStatus)( + struct upb_EpsCopyInputStream* e, const char* ptr, int* overrun) { + *overrun = ptr - e->end; + if (UPB_LIKELY(ptr < e->limit_ptr)) { + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)(e); + return kUpb_IsDoneStatus_NotDone; + } else if (UPB_LIKELY(*overrun == e->limit)) { + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsHit)(e); + return kUpb_IsDoneStatus_Done; + } else { + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsHit)(e); + return kUpb_IsDoneStatus_NeedFallback; + } +} + +const char* UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneFallback)( + struct upb_EpsCopyInputStream* e, const char* ptr, int overrun); + +UPB_INLINE bool upb_EpsCopyInputStream_IsDone(struct upb_EpsCopyInputStream* e, + const char** ptr) { + int overrun; + switch (UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneStatus)(e, *ptr, &overrun)) { + case kUpb_IsDoneStatus_Done: + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsHit)(e); + return true; + case kUpb_IsDoneStatus_NotDone: + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)(e); + return false; + case kUpb_IsDoneStatus_NeedFallback: + *ptr = + UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneFallback)(e, *ptr, overrun); + if (*ptr) { + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)(e); + } else { + UPB_PRIVATE(upb_EpsCopyInputStream_BoundsHit)(e); + } + return *ptr == NULL; + } + UPB_UNREACHABLE(); +} + +UPB_INLINE bool upb_EpsCopyInputStream_CheckSize( + const struct upb_EpsCopyInputStream* e, const char* ptr, int size) { + UPB_ASSERT(size >= 0); + return size <= e->limit - (ptr - e->end); +} + +// Returns a pointer into an input buffer that corresponds to the parsing +// pointer `ptr`. The returned pointer may be the same as `ptr`, but also may +// be different if we are currently parsing out of the patch buffer. +UPB_INLINE const char* UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)( + struct upb_EpsCopyInputStream* e, const char* ptr) { + // This somewhat silly looking add-and-subtract behavior provides provenance + // from the original input buffer's pointer. After optimization it produces + // the same assembly as just casting `(uintptr_t)ptr+input_delta` + // https://godbolt.org/z/zosG88oPn + size_t position = + (uintptr_t)ptr + e->input_delta - (uintptr_t)e->buffer_start; + return e->buffer_start + position; +} + +UPB_INLINE void upb_EpsCopyCapture_Start(struct upb_EpsCopyCapture* c, + struct upb_EpsCopyInputStream* e, + const char* ptr) { + c->start = UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(e, ptr); +} + +UPB_INLINE bool upb_EpsCopyCapture_End(struct upb_EpsCopyCapture* c, + struct upb_EpsCopyInputStream* e, + const char* ptr, upb_StringView* sv) { + if (ptr - e->end > e->limit) { + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); + } + const char* end = UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(e, ptr); + sv->data = c->start; + sv->size = end - sv->data; + return true; +} + +UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringAlwaysAlias( + struct upb_EpsCopyInputStream* e, const char* ptr, size_t size, + upb_StringView* sv) { + UPB_ASSERT(size <= PTRDIFF_MAX); + // The `size` must be within the input buffer. If `ptr` is in the input + // buffer, then using the slop bytes is fine (because they are real bytes from + // the tail of the input buffer). If `ptr` is in the patch buffer, then slop + // bytes represent bytes that do not actually exist in the original input + // buffer, so we must fail if the size extends into the slop bytes. + const char* limit = + e->end + (e->input_delta == 0) * kUpb_EpsCopyInputStream_SlopBytes; + if ((ptrdiff_t)size > limit - ptr) { + // For the moment, we consider this an error. In a multi-buffer world, + // it could be that the requested string extends into the next buffer, which + // is not an error and should be recoverable. + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); + } + const char* input = UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(e, ptr); + *sv = upb_StringView_FromDataAndSize(input, size); + return ptr + size; +} + +UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringEphemeral( + struct upb_EpsCopyInputStream* e, const char* ptr, size_t size, + upb_StringView* sv) { + UPB_ASSERT(size <= PTRDIFF_MAX); + // Size must be within the current buffer (including slop bytes). + const char* limit = e->end + kUpb_EpsCopyInputStream_SlopBytes; + if ((ptrdiff_t)size > limit - ptr) { + // For the moment, we consider this an error. In a multi-buffer world, + // it could be that the requested string extends into the next buffer, which + // is not an error and should be recoverable. + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); + } + *sv = upb_StringView_FromDataAndSize(ptr, size); + return ptr + size; +} + +UPB_INLINE void UPB_PRIVATE(upb_EpsCopyInputStream_CheckLimit)( + struct upb_EpsCopyInputStream* e) { + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); +} + +UPB_INLINE ptrdiff_t upb_EpsCopyInputStream_PushLimit( + struct upb_EpsCopyInputStream* e, const char* ptr, size_t size) { + UPB_ASSERT(size <= PTRDIFF_MAX); + ptrdiff_t limit = (ptrdiff_t)size + (ptr - e->end); + ptrdiff_t delta = e->limit - limit; + UPB_PRIVATE(upb_EpsCopyInputStream_CheckLimit)(e); + e->limit = limit; + e->limit_ptr = e->end + UPB_MIN(0, limit); + UPB_PRIVATE(upb_EpsCopyInputStream_CheckLimit)(e); + if (UPB_UNLIKELY(delta < 0)) { + UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); + } + return delta; +} + +// Pops the last limit that was pushed on this stream. This may only be called +// once IsDone() returns true. The user must pass the delta that was returned +// from PushLimit(). +UPB_INLINE void upb_EpsCopyInputStream_PopLimit( + struct upb_EpsCopyInputStream* e, const char* ptr, ptrdiff_t saved_delta) { + UPB_ASSERT(ptr - e->end == e->limit); + UPB_PRIVATE(upb_EpsCopyInputStream_CheckLimit)(e); + e->limit += saved_delta; + e->limit_ptr = e->end + UPB_MIN(0, e->limit); + UPB_PRIVATE(upb_EpsCopyInputStream_CheckLimit)(e); +} + +typedef const char* upb_EpsCopyInputStream_ParseDelimitedFunc( + struct upb_EpsCopyInputStream* e, const char* ptr, int size, void* ctx); + +UPB_FORCEINLINE bool upb_EpsCopyInputStream_TryParseDelimitedFast( + struct upb_EpsCopyInputStream* e, const char** ptr, size_t size, + upb_EpsCopyInputStream_ParseDelimitedFunc* func, void* ctx) { + UPB_ASSERT(size <= PTRDIFF_MAX); + if ((ptrdiff_t)size > e->limit_ptr - *ptr) { + return false; + } + + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = e->limit_ptr; + ptrdiff_t saved_limit = e->limit; + e->limit_ptr = *ptr + size; + e->limit = e->limit_ptr - e->end; + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); + *ptr = func(e, *ptr, size, ctx); + e->limit_ptr = saved_limit_ptr; + e->limit = saved_limit; + UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit)); + return true; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_EPS_COPY_INPUT_STREAM_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct upb_EpsCopyCapture upb_EpsCopyCapture; +typedef struct upb_EpsCopyInputStream upb_EpsCopyInputStream; + +// Initializes a upb_EpsCopyInputStream using the contents of the buffer +// [*ptr, size]. Updates `*ptr` as necessary to guarantee that at least +// kUpb_EpsCopyInputStream_SlopBytes are available to read. +UPB_INLINE void upb_EpsCopyInputStream_Init(upb_EpsCopyInputStream* e, + const char** ptr, size_t size); + +// Like the previous function, but registers an error handler that will be +// called for any errors encountered. +UPB_INLINE void upb_EpsCopyInputStream_InitWithErrorHandler( + upb_EpsCopyInputStream* e, const char** ptr, size_t size, + upb_ErrorHandler* err); + +// Returns true if the stream has an error handler. +// +// This function is marked const, which indicates to the compiler that the +// return value is solely a function of the pointer value. This is not +// entirely true if the stream is reinitialized with +// upb_EpsCopyInputStream_Init*(), so users must not call this function in +// any context where the stream may be reinitialized between calls to this +// function, and the presence of an error handler changes when reinitialized. +UPB_ATTR_CONST +UPB_INLINE bool upb_EpsCopyInputStream_HasErrorHandler( + const upb_EpsCopyInputStream* e); + +// Returns true if the stream is in the error state. A stream enters the error +// state when the user reads past a limit (caught in IsDone()) or the +// ZeroCopyInputStream returns an error. +UPB_INLINE bool upb_EpsCopyInputStream_IsError(upb_EpsCopyInputStream* e); + +// Returns true if the stream has hit a limit, either the current delimited +// limit or the overall end-of-stream. As a side effect, this function may flip +// the pointer to a new buffer if there are less than +// kUpb_EpsCopyInputStream_SlopBytes of data to be read in the current buffer. +// +// Postcondition: if the function returns false, there are at least +// kUpb_EpsCopyInputStream_SlopBytes of data available to read at *ptr. +// +// If this returns true, the user must call upb_EpsCopyInputStream_IsError() +// to distinguish between EOF and error. +UPB_INLINE bool upb_EpsCopyInputStream_IsDone(upb_EpsCopyInputStream* e, + const char** ptr); + +// Returns true if the given delimited field size is valid (it does not extend +// beyond any previously-pushed limits). `ptr` should point to the beginning +// of the field data, after the delimited size. +// +// Note that this does *not* guarantee that all of the data for this field is in +// the current buffer. +UPB_INLINE bool upb_EpsCopyInputStream_CheckSize( + const upb_EpsCopyInputStream* e, const char* ptr, int size); + +// Marks the start of a capture operation. The capture operation will be +// finalized by a call to upb_EpsCopyCapture_End(). The captured string will +// be returned in sv, and will point to the original input buffer if possible. +UPB_INLINE void upb_EpsCopyCapture_Start(upb_EpsCopyCapture* c, + upb_EpsCopyInputStream* e, + const char* ptr); + +// Ends a capture operation and returns the captured string. Returns false if +// the capture operation was invalid (the parsing pointer extends beyond the +// end of the stream). +UPB_INLINE bool upb_EpsCopyCapture_End(upb_EpsCopyCapture* c, + upb_EpsCopyInputStream* e, + const char* ptr, upb_StringView* sv); + +// Reads a string from the stream and advances the pointer accordingly. The +// returned string view will always alias the input buffer. +// +// Returns NULL if size extends beyond the end of the current input buffer. +// Currently, we only support a single input buffer, so this function will only +// fail if `size` overflows the end of the stream. +// +// If/when we support multiple input buffers, there may be cases where this +// function returns failure, even if the requested region is valid, because the +// requested region spans multiple buffers. In this case, the caller must +// attempt to read the string using other string reading functions before +// signaling an error. +UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringAlwaysAlias( + upb_EpsCopyInputStream* e, const char* ptr, size_t size, + upb_StringView* sv); + +// Reads a string from the stream and advances the pointer accordingly. The +// returned string view is ephemeral, only valid until the next call to +// upb_EpsCopyInputStream. It may point to the patch buffer. +// +// Returns NULL if size extends beyond the end of the current buffer (which may +// be the patch buffer). +// +// IMPORTANT NOTE: If `size` extends beyond the end of the stream, the returned +// data may contain garbage bytes from the patch buffer. For efficiency, this +// function does not check that `size` is within the current limit or even the +// end of the stream. +// +// The bytes are guaranteed to be safe to read ephemerally, but they may contain +// garbage data that does not correspond to anything in the input. This error +// will be detected later, when calling upb_EpsCopyInputStream_IsDone() (because +// we will not end at the proper limit), but it may result in nonsense bytes +// ending up in the output. +UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringEphemeral( + upb_EpsCopyInputStream* e, const char* ptr, size_t size, + upb_StringView* sv); + +// Pushes a limit onto the stack of limits for the current stream. The limit +// will extend for `size` bytes beyond the position in `ptr`. Future calls to +// upb_EpsCopyInputStream_IsDone() will return `true` when the stream position +// reaches this limit. +// +// Returns a delta that the caller must store and supply to PopLimit() below. +// +// A return value of <0 indicates that `size` is too large, and exceeds a +// previous limit. If this occurs, the stream is in an error state and must no +// longer be used. +UPB_INLINE ptrdiff_t upb_EpsCopyInputStream_PushLimit(upb_EpsCopyInputStream* e, + const char* ptr, + size_t size); + +// Pops the last limit that was pushed on this stream. This may only be called +// once IsDone() returns true. The user must pass the delta that was returned +// from PushLimit(). +UPB_INLINE void upb_EpsCopyInputStream_PopLimit(upb_EpsCopyInputStream* e, + const char* ptr, + ptrdiff_t saved_delta); + +// Tries to perform a fast-path handling of the given delimited message data. +// If the sub-message beginning at `*ptr` and extending for `len` is short and +// fits within this buffer, calls `func` with `ctx` as a parameter, where the +// pushing and popping of limits is handled automatically and with lower cost +// than the normal PushLimit()/PopLimit() sequence. +UPB_FORCEINLINE bool upb_EpsCopyInputStream_TryParseDelimitedFast( + upb_EpsCopyInputStream* e, const char** ptr, size_t size, + upb_EpsCopyInputStream_ParseDelimitedFunc* func, void* ctx); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#ifdef __cplusplus +// Temporary overloads for functions whose signature has recently changed. +UPB_DEPRECATE_AND_INLINE() +UPB_INLINE void upb_EpsCopyInputStream_Init(upb_EpsCopyInputStream* e, + const char** ptr, size_t size, + bool enable_aliasing) { + upb_EpsCopyInputStream_Init(e, ptr, size); +} +#endif + + +#endif // UPB_WIRE_EPS_COPY_INPUT_STREAM_H_ + +#ifndef UPB_WIRE_READER_H_ +#define UPB_WIRE_READER_H_ + +#include +#include +#include + + +#ifndef UPB_WIRE_INTERNAL_READER_H_ +#define UPB_WIRE_INTERNAL_READER_H_ + +#include +#include + + +// Must be last. + +#define kUpb_WireReader_WireTypeBits 3 +#define kUpb_WireReader_WireTypeMask 7 + +typedef struct { + const char* ptr; + uint64_t val; +} UPB_PRIVATE(_upb_WireReader_LongVarint); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val, + upb_EpsCopyInputStream* stream); +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongTag)(const char* ptr, uint64_t val, + upb_EpsCopyInputStream* stream); +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongSize)(const char* ptr, uint64_t val, + upb_EpsCopyInputStream* stream); + +UPB_FORCEINLINE const char* upb_WireReader_ReadVarint( + const char* ptr, uint64_t* val, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 10); + uint8_t byte = *ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } + UPB_PRIVATE(_upb_WireReader_LongVarint) res; + res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte, stream); + *val = res.val; + return UPB_PRIVATE(upb_EpsCopyInputStream_AssumeResult)(stream, res.ptr); +} + +UPB_FORCEINLINE const char* upb_WireReader_ReadTag( + const char* ptr, uint32_t* val, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 5); + uint8_t byte = *ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } + UPB_PRIVATE(_upb_WireReader_LongVarint) res; + res = UPB_PRIVATE(_upb_WireReader_ReadLongTag)(ptr, byte, stream); + *val = res.val; + return UPB_PRIVATE(upb_EpsCopyInputStream_AssumeResult)(stream, res.ptr); +} + +UPB_FORCEINLINE const char* upb_WireReader_ReadSize( + const char* ptr, int* val, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 5); + uint8_t byte = *ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } + UPB_PRIVATE(_upb_WireReader_LongVarint) res; + res = UPB_PRIVATE(_upb_WireReader_ReadLongSize)(ptr, byte, stream); + *val = res.val; + return UPB_PRIVATE(upb_EpsCopyInputStream_AssumeResult)(stream, res.ptr); +} + +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { + return tag >> kUpb_WireReader_WireTypeBits; +} + +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { + return tag & kUpb_WireReader_WireTypeMask; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_READER_H_ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ + +// Must be last. + +// The upb_WireReader interface is suitable for general-purpose parsing of +// protobuf binary wire format. It is designed to be used along with +// upb_EpsCopyInputStream for buffering, and all parsing routines in this file +// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is +// available to read without any bounds checks. + +#ifdef __cplusplus +extern "C" { +#endif + +// Parses a tag into `tag`, and returns a pointer past the end of the tag, or +// NULL if there was an error in the tag data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_FORCEINLINE const char* upb_WireReader_ReadTag( + const char* ptr, uint32_t* tag, upb_EpsCopyInputStream* stream); + +// Given a tag, returns the field number. +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); + +// Given a tag, returns the wire type. +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); + +UPB_FORCEINLINE const char* upb_WireReader_ReadVarint( + const char* ptr, uint64_t* val, upb_EpsCopyInputStream* stream); + +// Skips data for a varint, returning a pointer past the end of the varint, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_SkipVarint( + const char* ptr, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 10); + const char* bound = ptr + 10; + do { + if ((*(ptr++) & 0x80) == 0) { + return ptr; + } + } while (ptr != bound); + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); +} + +// Reads a varint indicating the size of a delimited field into `size`, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size, + upb_EpsCopyInputStream* stream); + +// Reads a fixed32 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed32( + const char* ptr, void* val, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 4); + uint32_t uval; + memcpy(&uval, ptr, 4); + uval = upb_BigEndian32(uval); + memcpy(val, &uval, 4); + return ptr + 4; +} + +// Reads a fixed64 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed64( + const char* ptr, void* val, upb_EpsCopyInputStream* stream) { + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 8); + uint64_t uval; + memcpy(&uval, ptr, 8); + uval = upb_BigEndian64(uval); + memcpy(val, &uval, 8); + return ptr + 8; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream); + +// Skips data for a group, returning a pointer past the end of the group, or +// NULL if there was an error parsing the group. The `tag` argument should be +// the start group tag that begins the group. The `depth_limit` argument +// indicates how many levels of recursion the group is allowed to have before +// reporting a parse error (this limit exists to protect against stack +// overflow). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipGroup( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + const char* ret = + UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); + return UPB_PRIVATE(upb_EpsCopyInputStream_AssumeResult)(stream, ret); +} + +UPB_FORCEINLINE const char* _upb_WireReader_SkipValueForceInline( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + switch (upb_WireReader_GetWireType(tag)) { + case kUpb_WireType_Varint: + return upb_WireReader_SkipVarint(ptr, stream); + case kUpb_WireType_32Bit: + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 4); + return ptr + 4; + case kUpb_WireType_64Bit: + UPB_PRIVATE(upb_EpsCopyInputStream_ConsumeBytes)(stream, 8); + return ptr + 8; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size, stream); + if (!ptr || !upb_EpsCopyInputStream_CheckSize(stream, ptr, size)) { + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); + } + ptr += size; + return ptr; + } + case kUpb_WireType_StartGroup: + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, + stream); + case kUpb_WireType_EndGroup: + // Should be handled before now. + default: + // Unknown wire type. + return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); + } +} + +UPB_INLINE const char* _upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + return _upb_WireReader_SkipValueForceInline(ptr, tag, depth_limit, stream); +} + +// Skips data for a wire value of any type, returning a pointer past the end of +// the data, or NULL if there was an error parsing the group. The `tag` argument +// should be the tag that was just parsed. The `depth_limit` argument indicates +// how many levels of recursion a group is allowed to have before reporting a +// parse error (this limit exists to protect against stack overflow). +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return _upb_WireReader_SkipValue(ptr, tag, 100, stream); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_READER_H_ + +#ifndef UPB_MESSAGE_COMPARE_H_ +#define UPB_MESSAGE_COMPARE_H_ + +#include + + +// Must be last. + +enum { + // If set, upb_Message_IsEqual() will attempt to compare unknown fields. + // By its very nature this comparison is inexact. + kUpb_CompareOption_IncludeUnknownFields = (1 << 0) +}; + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true if no known fields or extensions are set in the message. +UPB_API bool upb_Message_IsEmpty(const upb_Message* msg, + const upb_MiniTable* m); + +UPB_API bool upb_Message_IsEqual(const upb_Message* msg1, + const upb_Message* msg2, + const upb_MiniTable* m, int options); + +// If |ctype| is a message then |m| must point to its minitable. +UPB_API_INLINE bool upb_MessageValue_IsEqual(upb_MessageValue val1, + upb_MessageValue val2, + upb_CType ctype, + const upb_MiniTable* m, + int options) { + switch (ctype) { + case kUpb_CType_Bool: + return val1.bool_val == val2.bool_val; + + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return val1.int32_val == val2.int32_val; + + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return val1.int64_val == val2.int64_val; + + case kUpb_CType_String: + case kUpb_CType_Bytes: + return upb_StringView_IsEqual(val1.str_val, val2.str_val); + + case kUpb_CType_Message: + return upb_Message_IsEqual(val1.msg_val, val2.msg_val, m, options); + + default: + UPB_UNREACHABLE(); + return false; + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COMPARE_H_ + +#ifndef UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ +#define UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ + +#include + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns true if unknown fields from the two messages are equal when sorted +// and varints are made canonical. +// +// This function is discouraged, as the comparison is inherently lossy without +// schema data: +// +// 1. We don't know whether delimited fields are sub-messages. Unknown +// sub-messages will therefore not have their fields sorted and varints +// canonicalized. +// 2. We don't know about oneof/non-repeated fields, which should semantically +// discard every value except the last. + +typedef enum { + kUpb_UnknownCompareResult_Equal = 0, + kUpb_UnknownCompareResult_NotEqual = 1, + kUpb_UnknownCompareResult_OutOfMemory = 2, + kUpb_UnknownCompareResult_MaxDepthExceeded = 3, +} upb_UnknownCompareResult; + +upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( + const upb_Message* msg1, const upb_Message* msg2, int max_depth); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_COMPARE_UNKNOWN_H_ */ + +#ifndef GOOGLE_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H__ +#define GOOGLE_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H__ + +#include +#include + + +// Must be last. + +#define kUpb_BaseField_Begin ((size_t)-1) +bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField** out_f, + upb_MessageValue* out_v, + uintptr_t* iter); + +#endif // GOOGLE_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H__ + +#ifndef UPB_MESSAGE_COPY_H_ +#define UPB_MESSAGE_COPY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Deep clones a message using the provided target arena. +UPB_NODISCARD upb_Message* upb_Message_DeepClone(const upb_Message* msg, + const upb_MiniTable* m, + upb_Arena* arena); + +// Shallow clones a message using the provided target arena. +// `msg` must outlive the returned message since all strings, repeated fields, +// maps, and unknown fields will alias the original message. +UPB_NODISCARD upb_Message* upb_Message_ShallowClone(const upb_Message* msg, + const upb_MiniTable* m, + upb_Arena* arena); + +// Deep clones array contents. +UPB_NODISCARD upb_Array* upb_Array_DeepClone(const upb_Array* array, + upb_CType value_type, + const upb_MiniTable* sub, + upb_Arena* arena); + +// Deep clones map contents. +UPB_NODISCARD upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, + upb_CType value_type, + const upb_MiniTable* map_entry_table, + upb_Arena* arena); + +// Deep copies the message from src to dst. +UPB_NODISCARD bool upb_Message_DeepCopy(upb_Message* dst, + const upb_Message* src, + const upb_MiniTable* m, + upb_Arena* arena); + +// Shallow copies the message from src to dst. +// `src` must outlive `dst` since all strings, repeated fields, maps, and +// unknown fields will alias the original message. +UPB_NODISCARD UPB_API bool upb_Message_ShallowCopy(upb_Message* dst, + const upb_Message* src, + const upb_MiniTable* m, + upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MESSAGE_COPY_H_ +#ifndef GOOGLE_UPB_UPB_MESSAGE_MERGE_H__ +#define GOOGLE_UPB_UPB_MESSAGE_MERGE_H__ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_NODISCARD UPB_API bool upb_Message_MergeFrom( + upb_Message* dst, const upb_Message* src, const upb_MiniTable* mt, + const upb_ExtensionRegistry* extreg, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // GOOGLE_UPB_UPB_MESSAGE_MERGE_H__ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE char _upb_ToBase92(int8_t ch) { + extern const char _kUpb_ToBase92[]; + UPB_ASSERT(0 <= ch && ch < 92); + return _kUpb_ToBase92[ch]; +} + +UPB_INLINE char _upb_FromBase92(uint8_t ch) { + extern const int8_t _kUpb_FromBase92[]; + if (' ' > ch || ch > '~') return -1; + return _kUpb_FromBase92[ch - ' ']; +} + +UPB_INLINE const char* _upb_Base92_DecodeVarint(const char* ptr, + const char* end, char first_ch, + uint8_t min, uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + upb_Log2Ceiling(_upb_FromBase92(max) - _upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = _upb_FromBase92(ch) - _upb_FromBase92(min); + val |= bits << shift; + if (ptr == end || *ptr < min || max < *ptr) { + *out_val = val; + UPB_ASSUME(ptr != NULL); + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) return NULL; + } +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_BASE92_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ + + +// Must be last. + +// upb_MdDecoder: used internally for decoding MiniDescriptors for messages, +// extensions, and enums. +typedef struct { + const char* end; + upb_Status* status; + jmp_buf err; +} upb_MdDecoder; + +UPB_PRINTF(2, 3) +UPB_NORETURN UPB_INLINE void upb_MdDecoder_ErrorJmp(upb_MdDecoder* d, + const char* fmt, ...) { + if (d->status) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + } + UPB_LONGJMP(d->err, 1); +} + +UPB_INLINE void upb_MdDecoder_CheckOutOfMemory(upb_MdDecoder* d, + const void* ptr) { + if (!ptr) upb_MdDecoder_ErrorJmp(d, "Out of memory"); +} + +UPB_INLINE const char* upb_MdDecoder_DecodeBase92Varint( + upb_MdDecoder* d, const char* ptr, char first_ch, uint8_t min, uint8_t max, + uint32_t* out_val) { + ptr = _upb_Base92_DecodeVarint(ptr, d->end, first_ch, min, max, out_val); + if (!ptr) upb_MdDecoder_ErrorJmp(d, "Overlong varint"); + return ptr; +} + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_DECODER_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ + + +// Must be last. + +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_OpenEnum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + kUpb_EncodedType_ClosedEnum = 18, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; + +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsRequired = 1 << 1, + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_FlipValidateUtf8 = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'I', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; + +enum { + kUpb_EncodedVersion_EnumV1 = '!', + kUpb_EncodedVersion_ExtensionV1 = '#', + kUpb_EncodedVersion_MapV1 = '%', + kUpb_EncodedVersion_MessageV1 = '$', + kUpb_EncodedVersion_MessageSetV1 = '&', +}; + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_WIRE_CONSTANTS_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ + +// Must be last. + +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, + kUpb_FieldModifier_ValidateUtf8 = 1 << 5, +} kUpb_FieldModifier; + +// These modifiers are also used on the wire. +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + + +#endif // UPB_MINI_DESCRIPTOR_INTERNAL_MODIFIERS_H_ + +#ifndef UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ +#define UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ + +#include + + +// Must be last. + +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 + +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; + +#ifdef __cplusplus +extern "C" { +#endif + +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// unit64_t msg_mod = ...; // bitwise & of kUpb_MessageModifiers or zero +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr, msg_mod); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); + +// Encodes an entire mini descriptor for an extension. +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); + +// Encodes an entire mini descriptor for a map. +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, uint64_t key_mod, + uint64_t value_mod); + +// Encodes an entire mini descriptor for a message set. +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_DESCRIPTOR_INTERNAL_ENCODE_H_ */ + +#ifndef UPB_MINI_TABLE_GENERATED_REGISTRY_H_ +#define UPB_MINI_TABLE_GENERATED_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Generated registry: a global singleton that gathers all extensions linked + * into the binary. + * + * This singleton is thread-safe and lock-free, implemented using atomics. The + * registry is lazily initialized the first time it is loaded. When all + * references are released, the registry will be destroyed. New loads + * afterwards will simply reload the same registry as needed. + * + * The extension minitables are registered in gencode using linker arrays. Each + * .proto file produces a weak, hidden, constructor function that adds all + * visible extensions from the array into the registry. In each binary, only + * one copy of the constructor will actually be preserved by the linker, and + * that copy will add all of the extensions for the entire binary. All of these + * are added to a global linked list of minitables pre-main, which are then used + * to construct this singleton as needed. + */ + +typedef struct upb_GeneratedRegistryRef upb_GeneratedRegistryRef; + +// Loads the generated registry, returning a reference to it. The reference +// must be held for the lifetime of any ExtensionRegistry obtained from it. +// +// Returns NULL on failure. +UPB_API const upb_GeneratedRegistryRef* upb_GeneratedRegistry_Load(void); + +// Releases a reference to the generated registry. This may destroy the +// registry if there are no other references to it. +// +// NULL is a valid argument and is simply ignored for easier error handling in +// callers. +UPB_API void upb_GeneratedRegistry_Release(const upb_GeneratedRegistryRef* r); + +// Returns the extension registry contained by a reference to the generated +// registry. +// +// The reference must be held for the lifetime of the registry. +UPB_API const upb_ExtensionRegistry* upb_GeneratedRegistry_Get( + const upb_GeneratedRegistryRef* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_MINI_TABLE_GENERATED_REGISTRY_H_ + +#ifndef UPB_REFLECTION_DEF_POOL_INTERNAL_H_ +#define UPB_REFLECTION_DEF_POOL_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); + +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + const upb_FieldDef* f); +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status); +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v); + +void** _upb_DefPool_ScratchData(const upb_DefPool* s); +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); +void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform); + +// For generated code only: loads a generated descriptor. +typedef struct _upb_DefPool_Init { + struct _upb_DefPool_Init** deps; // Dependencies of this file. + const upb_MiniTableFile* layout; + const char* filename; + upb_StringView descriptor; // Serialized descriptor. +} _upb_DefPool_Init; + +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); + +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +const upb_ExtensionRegistry* _upb_DefPool_GeneratedExtensionRegistry( + const upb_DefPool* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_POOL_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_DEF_TYPE_H_ +#define UPB_REFLECTION_DEF_TYPE_H_ + + +// Must be last. + +// Inside a symtab we store tagged pointers to specific def types. +typedef enum { + UPB_DEFTYPE_MASK = 7, + + // Only inside symtab table. + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, + + // Only inside message table. + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, + + // Only inside service table. + UPB_DEFTYPE_METHOD = 0, +} upb_deftype_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Our 3-bit pointer tagging requires all pointers to be multiples of 8. +// The arena will always yield 8-byte-aligned addresses, however we put +// the defs into arrays. For each element in the array to be 8-byte-aligned, +// the sizes of each def type must also be a multiple of 8. +// +// If any of these asserts fail, we need to add or remove padding on 32-bit +// machines (64-bit machines will have 8-byte alignment already due to +// pointers, which all of these structs have). +UPB_INLINE void _upb_DefType_CheckPadding(size_t size) { + UPB_ASSERT((size & UPB_DEFTYPE_MASK) == 0); +} + +upb_deftype_t _upb_DefType_Type(upb_value v); + +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type); + +const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_TYPE_H_ */ + +#ifndef UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ +#define UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ + +#include +#include +#include +#include + + +// Must be last. + +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define _UPB_FREEZE_OPTIONS(target, options_type) \ + upb_Message_Freeze((upb_Message*)target, UPB_DESC_MINITABLE(options_type)) + +#define UPB_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + if (!pb) _upb_DefBuilder_OomErr(ctx); \ + target = google_protobuf_##options_type##_parse_ex( \ + pb, size, _upb_DefPool_GeneratedExtensionRegistry(ctx->symtab), 0, \ + _upb_DefBuilder_Arena(ctx)); \ + if (!target) _upb_DefBuilder_OomErr(ctx); \ + _UPB_FREEZE_OPTIONS(target, options_type); \ + } else { \ + target = (const google_protobuf_##options_type*)kUpbDefOptDefault; \ + } + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_DefBuilder { + upb_DefPool* symtab; + upb_strtable feature_cache; // Caches features by identity. + google_protobuf_FeatureSet* legacy_features; // For computing legacy features. + char* tmp_buf; // Temporary buffer in tmp_arena. + size_t tmp_buf_size; // Size of temporary buffer. + upb_FileDef* file; // File we are building. + upb_Arena* arena; // Allocate defs here. + upb_Arena* tmp_arena; // For temporary allocations. + upb_Status* status; // Record errors here. + const upb_MiniTableFile* layout; // NULL if we should build layouts. + upb_MiniTablePlatform platform; // Platform we are targeting. + int enum_count; // Count of enums built so far. + int msg_count; // Count of messages built so far. + int ext_count; // Count of extensions built so far. + jmp_buf err; // longjmp() on error. +}; + +extern const char* kUpbDefOptDefault; + +// ctx->status has already been set elsewhere so just fail/longjmp() +UPB_NORETURN void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx); + +UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, + ...) UPB_PRINTF(2, 3); +UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx); + +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name); + +// Given a symbol and the base symbol inside which it is defined, +// find the symbol's definition. +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type); + +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type); + +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end); + +const char* _upb_DefBuilder_FullToShort(const char* fullname); + +UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; +} + +/* Allocates an array of `count` elements, checking for size_t overflow */ +UPB_INLINE void* _upb_DefBuilder_AllocCounted(upb_DefBuilder* ctx, size_t size, + size_t count) { + if (count == 0) return NULL; + if (SIZE_MAX / size < count) { + _upb_DefBuilder_OomErr(ctx); + } + return _upb_DefBuilder_Alloc(ctx, size * count); +} + +#define UPB_DEFBUILDER_ALLOCARRAY(ctx, type, count) \ + ((type*)_upb_DefBuilder_AllocCounted(ctx, sizeof(type), (count))) + +// Adds a symbol |v| to the symtab, which must be a def pointer previously +// packed with pack_def(). The def's pointer to upb_FileDef* must be set before +// adding, so we know which entries to remove if building this file fails. +UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name, + upb_value v) { + upb_StringView sym = {.data = name, .size = strlen(name)}; + bool ok = _upb_DefPool_InsertSym(ctx->symtab, sym, v, ctx->status); + if (!ok) _upb_DefBuilder_FailJmp(ctx); +} + +UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) { + return ctx->arena; +} + +UPB_INLINE upb_FileDef* _upb_DefBuilder_File(const upb_DefBuilder* ctx) { + return ctx->file; +} + +// This version of CheckIdent() is only called by other, faster versions after +// they detect a parsing error. +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full); + +// Verify a full identifier string. This is slightly more complicated than +// verifying a relative identifier string because we must track '.' chars. +UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, + upb_StringView name) { + bool good = name.size > 0; + bool start = true; + + for (size_t i = 0; i < name.size; i++) { + const char c = name.data[i]; + const char d = c | 0x20; // force lowercase + const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); + const bool is_numer = ('0' <= c) & (c <= '9') & !start; + const bool is_dot = (c == '.') & !start; + + good &= is_alpha | is_numer | is_dot; + start = is_dot; + } + + if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); +} + +UPB_INLINE bool _upb_DefBuilder_IsLegacyEdition(google_protobuf_Edition edition) { + // Should only be called for a real edition, not a placeholder like + // EDITION_LEGACY. + UPB_ASSERT(edition >= google_protobuf_EDITION_PROTO2); + return edition <= google_protobuf_EDITION_PROTO3; +} + +// Returns true if the returned feature set is new and must be populated. +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const google_protobuf_FeatureSet* parent, + upb_StringView key, + google_protobuf_FeatureSet** set); + +const google_protobuf_FeatureSet* _upb_DefBuilder_DoResolveFeatures( + upb_DefBuilder* ctx, const google_protobuf_FeatureSet* parent, + const google_protobuf_FeatureSet* child, bool is_implicit); + +UPB_INLINE const google_protobuf_FeatureSet* _upb_DefBuilder_ResolveFeatures( + upb_DefBuilder* ctx, const google_protobuf_FeatureSet* parent, + const google_protobuf_FeatureSet* child) { + return _upb_DefBuilder_DoResolveFeatures(ctx, parent, child, false); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DEF_BUILDER_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_FILE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_FILE_DEF_INTERNAL_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i); +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); +bool _upb_FileDef_ClosedEnumCheckingDisabled(const upb_FileDef* f); +bool _upb_FileDef_ImplicitFieldPresenceDisabled(const upb_FileDef* f); + +// upb_FileDef_Package() returns "" if f->package is NULL, this does not. +const char* _upb_FileDef_RawPackage(const upb_FileDef* f); + +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FILE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size, + upb_value v, upb_Arena* a); +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f); +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n); +void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m); +void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m); +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); + +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "\n\031\030\204\007\"\000*\022\010\001\020\002\030\002 \003(\0010\0028\002@\001H\001\n\031\030\347\007\"\000*\022\010\002\020\001\030\001 \002(\0010\0018\002@\001H\001\n\031\030\350\007\"\014\010\001\020\001\030\001 \002(\0010\001*\0068\002@\001H\001\n\031\030\351\007\"\020\010\001\020\001\030\001 \002(\0010\0018\001@\002*\002H\001\n\031\030\352\007\"\022\010\001\020\001\030\001 \002(\0010\0018\003@\004H\002*\000 \346\007(\352\007" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +#ifndef UPB_REFLECTION_DESC_STATE_INTERNAL_H_ +#define UPB_REFLECTION_DESC_STATE_INTERNAL_H_ + + +// Must be last. + +// Manages the storage for mini descriptor strings as they are being encoded. +// TODO: Move some of this state directly into the encoder, maybe. +typedef struct { + upb_MtDataEncoder e; + size_t bufsize; + char* buf; + char* ptr; +} upb_DescState; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { + d->bufsize = kUpb_MtDataEncoder_MinSize * 2; + d->buf = NULL; + d->ptr = NULL; +} + +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); +void _upb_EnumDef_Insert(upb_DefBuilder* ctx, upb_EnumDef* e, + upb_EnumValueDef* v); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); + +// Allocate and initialize an array of |n| enum defs. +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, + const upb_MessageDef* containing_type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |e|. +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); + +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_EnumDef* e, bool* is_sorted); + +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + size_t n, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_VALUE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_INTERNAL_STRDUP2_H_ +#define UPB_REFLECTION_INTERNAL_STRDUP2_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Variant that works with a length-delimited rather than NULL-delimited string, +// as supported by strtable. +char* upb_strdup2(const char* s, size_t len, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_INTERNAL_STRDUP2_H_ */ +#ifndef GOOGLE_UPB_UPB_REFLECTION_JSON_ENUMVALUE_OPTIONS_BOOTSTRAP_H__ +#define GOOGLE_UPB_UPB_REFLECTION_JSON_ENUMVALUE_OPTIONS_BOOTSTRAP_H__ + +// IWYU pragma: begin_exports + +#if defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 +// This header is checked in. +#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 1 +// This header is generated at build time by the bootstrapping process. +#else +// This is the normal header, generated by upb_c_proto_library(). +/* This file was generated by upb_generator from the input file: + * + * google/protobuf/json_enumvalue_options.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. + * NO CHECKED-IN PROTOBUF GENCODE */ + +#ifndef GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_H_ +#define GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct pb_enumvalue_JsonEnumValueOptions { + upb_Message UPB_PRIVATE(base); +} pb_enumvalue_JsonEnumValueOptions; + +struct google_protobuf_EnumValueOptions; + + + +/* pb.enumvalue.JsonEnumValueOptions */ +UPB_INLINE pb_enumvalue_JsonEnumValueOptions* pb_enumvalue_JsonEnumValueOptions_new(upb_Arena* arena) { + return (pb_enumvalue_JsonEnumValueOptions*)_upb_Message_New(&pb__enumvalue__JsonEnumValueOptions_msg_init, arena); +} +UPB_INLINE pb_enumvalue_JsonEnumValueOptions* pb_enumvalue_JsonEnumValueOptions_parse(const char* buf, size_t size, + upb_Arena* arena) { + pb_enumvalue_JsonEnumValueOptions* ret = pb_enumvalue_JsonEnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &pb__enumvalue__JsonEnumValueOptions_msg_init, NULL, 0, + arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE pb_enumvalue_JsonEnumValueOptions* pb_enumvalue_JsonEnumValueOptions_parse_ex( + const char* buf, size_t size, const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena) { + pb_enumvalue_JsonEnumValueOptions* ret = pb_enumvalue_JsonEnumValueOptions_new(arena); + if (!ret) return NULL; + if (upb_Decode(buf, size, UPB_UPCAST(ret), &pb__enumvalue__JsonEnumValueOptions_msg_init, extreg, + options, arena) != kUpb_DecodeStatus_Ok) { + return NULL; + } + return ret; +} +UPB_INLINE char* pb_enumvalue_JsonEnumValueOptions_serialize(const pb_enumvalue_JsonEnumValueOptions* msg, + upb_Arena* arena, size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &pb__enumvalue__JsonEnumValueOptions_msg_init, 0, arena, &ptr, len); + return ptr; +} +UPB_INLINE char* pb_enumvalue_JsonEnumValueOptions_serialize_ex(const pb_enumvalue_JsonEnumValueOptions* msg, + int options, upb_Arena* arena, + size_t* len) { + char* ptr; + (void)upb_Encode(UPB_UPCAST(msg), &pb__enumvalue__JsonEnumValueOptions_msg_init, options, arena, &ptr, len); + return ptr; +} +UPB_INLINE void pb_enumvalue_JsonEnumValueOptions_clear_string(pb_enumvalue_JsonEnumValueOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_ClearBaseField(UPB_UPCAST(msg), &field); +} +UPB_INLINE upb_StringView pb_enumvalue_JsonEnumValueOptions_string(const pb_enumvalue_JsonEnumValueOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_Message_GetNonExtensionField(UPB_UPCAST(msg), &field, + &default_val, &ret); + return ret; +} +UPB_INLINE bool pb_enumvalue_JsonEnumValueOptions_has_string(const pb_enumvalue_JsonEnumValueOptions* msg) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + return upb_Message_HasBaseField(UPB_UPCAST(msg), &field); +} + +UPB_INLINE void pb_enumvalue_JsonEnumValueOptions_set_string(pb_enumvalue_JsonEnumValueOptions* msg, upb_StringView value) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + upb_Message_SetBaseField((upb_Message*)msg, &field, &value); +} + +UPB_INLINE bool pb_enumvalue_has_json(const struct google_protobuf_EnumValueOptions* msg) { + return upb_Message_HasExtension((upb_Message*)msg, pb_enumvalue_json_ext); +} + +UPB_INLINE void pb_enumvalue_clear_json(struct google_protobuf_EnumValueOptions* msg) { + upb_Message_ClearExtension((upb_Message*)msg, pb_enumvalue_json_ext); +} +UPB_INLINE const pb_enumvalue_JsonEnumValueOptions* +pb_enumvalue_json(const struct google_protobuf_EnumValueOptions* msg) { + const upb_MiniTableExtension* ext = pb_enumvalue_json_ext; + UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field))); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)( + &ext->UPB_PRIVATE(field)) == UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + const pb_enumvalue_JsonEnumValueOptions* default_val = NULL; + const pb_enumvalue_JsonEnumValueOptions* ret; + _upb_Message_GetExtensionField((upb_Message*)msg, ext, &default_val, &ret); + return ret; +} + +UPB_INLINE void pb_enumvalue_set_json(struct google_protobuf_EnumValueOptions* msg, + const pb_enumvalue_JsonEnumValueOptions* val, + upb_Arena* arena) { + const upb_MiniTableExtension* ext = pb_enumvalue_json_ext; + UPB_ASSUME(upb_MiniTableField_IsScalar(&ext->UPB_PRIVATE(field))); + UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)( + &ext->UPB_PRIVATE(field)) == UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + bool ok = upb_Message_SetExtension((upb_Message*)msg, ext, &val, arena); + UPB_ASSERT(ok); +} +UPB_INLINE struct pb_enumvalue_JsonEnumValueOptions* pb_enumvalue_mutable_json( + struct google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { + struct pb_enumvalue_JsonEnumValueOptions* sub = (struct pb_enumvalue_JsonEnumValueOptions*)pb_enumvalue_json(msg); + if (sub == NULL) { + sub = (struct pb_enumvalue_JsonEnumValueOptions*)_upb_Message_New(&pb__enumvalue__JsonEnumValueOptions_msg_init, arena); + if (sub) pb_enumvalue_set_json(msg, sub, arena); + } + return sub; +} +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_JSON_ENUMVALUE_OPTIONS_PROTO_UPB_H__UPB_H_ */ +#endif + +// IWYU pragma: end_exports + +#endif // GOOGLE_UPB_UPB_REFLECTION_JSON_ENUMVALUE_OPTIONS_BOOTSTRAP_H__ + +#ifndef UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); + +// Allocate and initialize an array of |n| extension ranges owned by |m|. +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const google_protobuf_FeatureSet* parent_features, const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ +#define UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); + +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f); +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f); +void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f); +void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, + const upb_FieldDef* f); + +// Allocate and initialize an array of |n| extensions (field defs). +upb_FieldDef* _upb_Extensions_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, const char* prefix, + upb_MessageDef* m); + +// Allocate and initialize an array of |n| field defs. +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, const char* prefix, + upb_MessageDef* m, bool* is_sorted); + +// Allocate and return a list of pointers to the |n| field defs in |ff|, +// sorted by field number. +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_FIELD_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ +#define UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i); +void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, + const upb_FieldDef* f, const char* name, size_t size); + +// Allocate and initialize an array of |n| oneof defs owned by |m|. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_MessageDef* m); + +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ +#define UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); + +// Allocate and initialize an array of |n| service defs. +upb_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features); + +void _upb_ServiceDef_InsertMethod(upb_DefBuilder* ctx, upb_ServiceDef* s, + const upb_MethodDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_SERVICE_DEF_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |m|. +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ +#define UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); + +// Allocate and initialize an array of |n| method defs owned by |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, + const google_protobuf_FeatureSet* parent_features, upb_ServiceDef* s); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ */ + +#ifndef UPB_UTIL_DEF_TO_PROTO_H_ +#define UPB_UTIL_DEF_TO_PROTO_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +// Must be last + +// Functions for converting defs back to the equivalent descriptor proto. +// Ultimately the goal is that a round-trip proto->def->proto is lossless. Each +// function returns a new proto created in arena `a`, or NULL if memory +// allocation failed. +UPB_NODISCARD google_protobuf_DescriptorProto* upb_MessageDef_ToProto( + const upb_MessageDef* m, upb_Arena* a); +UPB_NODISCARD google_protobuf_EnumDescriptorProto* upb_EnumDef_ToProto( + const upb_EnumDef* e, upb_Arena* a); +UPB_NODISCARD google_protobuf_EnumValueDescriptorProto* upb_EnumValueDef_ToProto( + const upb_EnumValueDef* e, upb_Arena* a); +UPB_NODISCARD google_protobuf_FieldDescriptorProto* upb_FieldDef_ToProto( + const upb_FieldDef* f, upb_Arena* a); +UPB_NODISCARD google_protobuf_OneofDescriptorProto* upb_OneofDef_ToProto( + const upb_OneofDef* o, upb_Arena* a); +UPB_NODISCARD google_protobuf_FileDescriptorProto* upb_FileDef_ToProto( + const upb_FileDef* f, upb_Arena* a); +UPB_NODISCARD google_protobuf_MethodDescriptorProto* upb_MethodDef_ToProto( + const upb_MethodDef* m, upb_Arena* a); +UPB_NODISCARD google_protobuf_ServiceDescriptorProto* upb_ServiceDef_ToProto( + const upb_ServiceDef* s, upb_Arena* a); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_UTIL_DEF_TO_PROTO_H_ */ + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_WIRE_INTERNAL_DECODER_H_ +#define UPB_WIRE_INTERNAL_DECODER_H_ + +#include +#include +#include + +#include "utf8_range.h" + +// Must be last. + +#define DECODE_NOGROUP (uint32_t)-1 +#define kUpb_Decoder_EncodeVarint32MaxSize 5 + +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; + +typedef struct upb_Decoder { + upb_EpsCopyInputStream input; + const upb_ExtensionRegistry* extreg; + upb_Message* original_msg; // Pointer to preserve data to + int depth; // Tracks recursion depth to bound stack usage. + uint32_t end_group; // field number of END_GROUP tag, else DECODE_NOGROUP. + uint16_t options; + bool missing_required; + bool message_is_done; + union { + upb_Arena arena; + void* foo[UPB_ARENA_SIZE_HACK / sizeof(void*)]; + }; + upb_ErrorHandler* err; + +#ifndef NDEBUG + char* trace_buf; + char* trace_ptr; + char* trace_end; +#endif +} upb_Decoder; + +UPB_INLINE void _upb_Decoder_AssumeEpsHasErrorHandler(upb_Decoder* d) { + UPB_ASSUME(upb_EpsCopyInputStream_HasErrorHandler(&d->input)); +} + +#define EPS(d) (_upb_Decoder_AssumeEpsHasErrorHandler(d), &(d)->input) + +UPB_INLINE const char* upb_Decoder_Init(upb_Decoder* d, const char* buf, + size_t size, + const upb_ExtensionRegistry* extreg, + int options, upb_Arena* arena, + upb_ErrorHandler* err, char* trace_buf, + size_t trace_size) { + d->err = err; + upb_EpsCopyInputStream_InitWithErrorHandler(&d->input, &buf, size, d->err); + + UPB_STATIC_ASSERT((int)kUpb_DecodeStatus_Ok == (int)kUpb_ErrorCode_Ok, + "mismatched error codes"); + UPB_STATIC_ASSERT( + (int)kUpb_DecodeStatus_OutOfMemory == (int)kUpb_ErrorCode_OutOfMemory, + "mismatched error codes"); + UPB_STATIC_ASSERT( + (int)kUpb_DecodeStatus_Malformed == (int)kUpb_ErrorCode_Malformed, + "mismatched error codes"); + + if (options & kUpb_DecodeOption_AlwaysValidateUtf8) { + // Fasttable decoder does not support this option. + options |= kUpb_DecodeOption_DisableFastTable; + } + + d->extreg = extreg; + d->depth = upb_DecodeOptions_GetEffectiveMaxDepth(options); + d->end_group = DECODE_NOGROUP; + d->options = (uint16_t)options; + d->missing_required = false; + d->message_is_done = false; +#ifndef NDEBUG + d->trace_buf = trace_buf; + d->trace_ptr = trace_buf; + d->trace_end = UPB_PTRADD(trace_buf, trace_size); +#endif + if (trace_buf) *trace_buf = 0; // Null-terminate. + + // Violating the encapsulation of the arena for performance reasons. + // This is a temporary arena that we swap into and swap out of when we are + // done. The temporary arena only needs to be able to handle allocation, + // not fuse or free, so it does not need many of the members to be initialized + // (particularly parent_or_count). + UPB_PRIVATE(_upb_Arena_SwapIn)(&d->arena, arena); + return buf; +} + +UPB_INLINE upb_DecodeStatus upb_Decoder_Destroy(upb_Decoder* d, + upb_Arena* arena) { + UPB_PRIVATE(_upb_Arena_SwapOut)(arena, &d->arena); + return (upb_DecodeStatus)d->err->code; +} + +// Resets decoder fields in preparation for decoding a new message. +// +// Some decoder fields (arena, extreg, err) are preserved so they can be +// reused across messages. +// NOTE: The input stream is NOT reset. If a new input buffer is being used, +// upb_EpsCopyInputStream_InitWithErrorHandler() must be called separately. +UPB_INLINE void upb_Decoder_Reset(upb_Decoder* d, int options, + upb_Message* msg) { + d->depth = upb_DecodeOptions_GetEffectiveMaxDepth(options); + d->options = options; + d->end_group = DECODE_NOGROUP; + d->missing_required = false; + d->message_is_done = false; + d->original_msg = msg; +} + +#ifndef NDEBUG +UPB_INLINE bool _upb_Decoder_TraceBufferHasBytesAvailable(upb_Decoder* d, + int n) { + return d->trace_ptr && d->trace_end && d->trace_end - d->trace_ptr > n; +} +#endif + +UPB_INLINE char* _upb_Decoder_TraceNext(upb_Decoder* d) { +#ifndef NDEBUG + return _upb_Decoder_TraceBufferHasBytesAvailable(d, 2) ? d->trace_ptr + 1 + : NULL; +#else + return NULL; +#endif +} + +UPB_INLINE char* _upb_Decoder_TracePtr(upb_Decoder* d) { +#ifndef NDEBUG + return d->trace_ptr; +#else + return NULL; +#endif +} + +// Trace events are used to trace the progress of the decoder. +// Events: +// 'D' Fast dispatch +// 'F' Field successfully parsed fast. +// '<' Fallback to MiniTable parser. +// 'M' Field successfully parsed with MiniTable. +// 'X' Truncated -- trace buffer is full, further events were discarded. +// 'U' Unknown field parsed fast +// +// Lower-case letters indicate events that are more subtle and therefore +// difficult to assert on, but may be useful information for debugging: +// 'r' Refresh buffer. +// 's' Fall back to unknown fast path +// 'm' Fall back to minitable lookup fast path +UPB_INLINE void _upb_Decoder_Trace(upb_Decoder* d, char event) { +#ifndef NDEBUG +#ifdef UPB_TRACE_FASTDECODER + fprintf(stderr, "Fasttable trace event: %c\n", event); +#endif + if (d->trace_ptr == NULL) return; + if (!_upb_Decoder_TraceBufferHasBytesAvailable(d, 1)) { + d->trace_ptr[-1] = 'X'; // Truncated. + return; + } + d->trace_ptr[0] = event; + d->trace_ptr[1] = '\0'; + d->trace_ptr++; +#endif +}; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(const char* ptr, int len) { + return utf8_range_IsValid(ptr, len); +} + +UPB_INLINE void _upb_Decoder_VerifyOneofUnlinked( + const upb_MiniTable* mt, const upb_MiniTableField* field) { +#ifndef NDEBUG + const upb_MiniTableField* oneof = upb_MiniTable_GetOneof(mt, field); + if (oneof) { + // All other members of the oneof must be message fields that are also + // unlinked. + do { + UPB_ASSERT(upb_MiniTableField_CType(oneof) == kUpb_CType_Message); + const upb_MiniTable* oneof_sub = upb_MiniTable_GetSubMessageTable(oneof); + UPB_ASSERT(!oneof_sub); + } while (upb_MiniTable_NextOneofField(mt, &oneof)); + } +#endif // NDEBUG +} + +const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* m); + +#if UPB_FASTTABLE +UPB_PRESERVE_NONE +#endif +const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); + +UPB_INLINE bool _upb_Decoder_FieldRequiresUtf8Validation( + const upb_Decoder* d, const upb_MiniTableField* field) { + if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_String) return true; + + if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bytes && + (field->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsAlternate) && + (d->options & kUpb_DecodeOption_AlwaysValidateUtf8)) { + return true; + } + + return false; +} + +UPB_INLINE bool _upb_Decoder_ReadString(upb_Decoder* d, const char** ptr, + size_t size, upb_StringView* sv, + bool validate_utf8) { + upb_StringView tmp; + *ptr = + upb_EpsCopyInputStream_ReadStringAlwaysAlias(&d->input, *ptr, size, &tmp); + if (*ptr == NULL) return false; + if (validate_utf8 && !utf8_range_IsValid(tmp.data, tmp.size)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_BadUtf8); + return false; + } + if ((d->options & kUpb_DecodeOption_AliasString) == 0) { + char* data = (char*)upb_Arena_Malloc(&d->arena, tmp.size); + if (!data) return false; + memcpy(data, tmp.data, tmp.size); + tmp.data = data; + } + *sv = tmp; + return true; +} + +UPB_INLINE char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; +} + +UPB_FORCEINLINE +void _upb_Decoder_AddEnumValueToUnknown(upb_Decoder* d, upb_Message* msg, + const upb_MiniTableField* field, + uint64_t val) { + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, + // so we just re-encode the tag and value here. + const uint32_t tag = + ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension ? d->original_msg + : msg; + char buf[2 * kUpb_Decoder_EncodeVarint32MaxSize]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(tag, end); + end = upb_Decoder_EncodeVarint32(val, end); + + if (!UPB_PRIVATE(_upb_Message_AddUnknown)(unknown_msg, buf, end - buf, + &d->arena, kUpb_AddUnknown_Copy)) { + upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); + } +} + + +#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */ + +#ifndef UPB_WIRE_INTERNAL_ENCODE_H_ +#define UPB_WIRE_INTERNAL_ENCODE_H_ + +#include +#include +#include + + +#ifndef GOOGLE_UPB_UPB_WIRE_INTERNAL_BACK_ALLOC_H__ +#define GOOGLE_UPB_UPB_WIRE_INTERNAL_BACK_ALLOC_H__ + +#include + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Allocates memory from the back of the arena. +typedef struct { + upb_Arena* arena; + char *buf, *limit; + bool standalone; +} upb_BackAlloc; + +// Needed because C doesn't allow NULL - NULL. +extern char upb_BackAlloc_sentinel; + +char* upb_BackAlloc_Grow(upb_BackAlloc* a, char* ptr, size_t need); + +UPB_INLINE char* upb_BackAlloc_Init(upb_BackAlloc* a, upb_Arena* arena) { + a->arena = arena; + // This could eagerly steal whatever's in the arena, since stealing with a + // minimum of 0 can't fail. + a->buf = &upb_BackAlloc_sentinel; + a->limit = &upb_BackAlloc_sentinel; + a->standalone = false; + return a->limit; +} + +UPB_INLINE void upb_BackAlloc_Abort(upb_BackAlloc* a) { + if (a->standalone) { + UPB_PRIVATE(_upb_Arena_FreeBlock)(a->arena, a->buf); + } else if (a->limit != a->buf) { + UPB_PRIVATE(_upb_Arena_UseBlock)(a->arena, a->buf, a->limit - a->buf); + } +} + +UPB_INLINE size_t upb_BackAlloc_Finish(upb_BackAlloc* a, const char* ptr) { + if (a->standalone) { + UPB_PRIVATE(_upb_Arena_AddBlock)(a->arena, a->buf); + } + if (ptr != a->buf) { + UPB_PRIVATE(_upb_Arena_UseBlock)(a->arena, a->buf, ptr - a->buf); + } + return a->limit - ptr; +} + +UPB_FORCEINLINE bool upb_BackAlloc_HasBytes(const upb_BackAlloc* a, + const char* ptr, size_t need) { + size_t have = ptr - a->buf; + return have >= need; +} + +UPB_FORCEINLINE char* upb_BackAlloc_Reserve(upb_BackAlloc* a, char* ptr, + size_t need) { + return upb_BackAlloc_HasBytes(a, ptr, need) + ? ptr - need + : upb_BackAlloc_Grow(a, ptr, need); +} + +UPB_INLINE size_t upb_BackAlloc_Size(const upb_BackAlloc* a, const char* ptr) { + return a->limit - ptr; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // GOOGLE_UPB_UPB_WIRE_INTERNAL_BACK_ALLOC_H__ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + upb_BackAlloc alloc; + int options; + int depth; + upb_EncodeStatus status; + _upb_mapsorter sorter; + jmp_buf* err; +} upb_encstate; + +UPB_INLINE char* UPB_PRIVATE(_upb_encstate_init)(upb_encstate* e, jmp_buf* err, + upb_Arena* arena) { + e->status = kUpb_EncodeStatus_Ok; + char* ptr = upb_BackAlloc_Init(&e->alloc, arena); + e->options = 0; + e->depth = 0; + e->err = err; + _upb_mapsorter_init(&e->sorter); + return ptr; +} + +UPB_INLINE void UPB_PRIVATE(_upb_encstate_destroy)(upb_encstate* e) { + _upb_mapsorter_destroy(&e->sorter); +} + +// Internal version of upb_Encode that encodes a single field. +// +// The caller must clean up the `upb_encstate` by calling +// `_upb_encstate_destroy(e)` when done. +upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Field)(upb_encstate* e, + const upb_Message* msg, + const upb_MiniTableField* field, + char** buf, size_t* size, + int options); + +// Internal version of upb_Encode that encodes a single extension. +// +// The caller must clean up the `upb_encstate` by calling +// `_upb_encstate_destroy(e)` when done. +upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Extension)( + upb_encstate* e, const upb_MiniTableExtension* ext, + upb_MessageValue ext_val, bool is_message_set, char** buf, size_t* size, + int options); + +char* encode_message(char* ptr, upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); + +#define kUpb_Encoder_EncodeVarint32MaxSize 5 +#define kUpb_Encoder_EncodeVarint64MaxSize 10 + +static char* upb_Encoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; +} + +static char* upb_Encoder_EncodeVarint64(uint64_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; +} + +UPB_INLINE +bool _upb_Encoder_AddEnumValueToUnknown(upb_Message* msg, + const upb_MiniTableField* field, + uint64_t val, upb_Arena* arena) { + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, + // so we just re-encode the tag and value here. + const uint32_t tag = + ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; + char buf[kUpb_Encoder_EncodeVarint32MaxSize + + kUpb_Encoder_EncodeVarint64MaxSize]; + char* end = buf; + end = upb_Encoder_EncodeVarint32(tag, end); + end = upb_Encoder_EncodeVarint64(val, end); + + return UPB_PRIVATE(_upb_Message_AddUnknown)(msg, buf, end - buf, arena, + kUpb_AddUnknown_Copy); +} + +bool _upb_Encoder_AddMapEntryUnknown(upb_Message* msg, + const upb_MiniTableField* field, + upb_Message* ent_msg, + const upb_MiniTable* entry, + upb_Arena* arena); + +upb_EncodeStatus _upb_Encode(const upb_Message* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size, bool prepend_len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_INTERNAL_ENCODE_H_ */ +#ifndef GOOGLE_UPB_UPB_WIRE_WRITER_H__ +#define GOOGLE_UPB_UPB_WIRE_WRITER_H__ + +#include + +// Must be last. + +UPB_FORCEINLINE uint32_t +UPB_PRIVATE(upb_WireWriter_VarintUnusedSizeFromLeadingZeros64)(uint64_t clz) { + // Calculate how many bytes of the possible 10 bytes we will *not* encode, + // because they are part of a zero prefix. For the number 300, it would use 2 + // bytes encoded, so the number of bytes to skip would be 8. Adding 7 to the + // clz input ensures that we're rounding up. + return (((uint32_t)clz + 7) * 9) >> 6; +} + + +#endif // GOOGLE_UPB_UPB_WIRE_WRITER_H__ + +// This should #undef all macros #defined in def.inc + +#undef UPB_SIZE +#undef UPB_PTR_AT +#undef UPB_SIZEOF_FLEX +#undef UPB_SIZEOF_FLEX_WOULD_OVERFLOW +#undef UPB_MAPTYPE_STRING +#undef UPB_EXPORT +#undef UPB_INLINE +#undef UPB_API +#undef UPBC_API +#undef UPB_API_INLINE +#undef UPB_API_INLINE_IF_NOT_GCC +#undef UPB_ALIGN_UP +#undef UPB_ALIGN_DOWN +#undef UPB_ALIGN_MALLOC +#undef UPB_ALIGN_OF +#undef UPB_ALIGN_AS +#undef UPB_STATIC_ASSERT +#undef UPB_STATIC_ASSERT_CONCAT +#undef UPB_STATIC_ASSERT_CONCAT_IMPL +#undef UPB_LIKELY +#undef UPB_UNLIKELY +#undef UPB_UNPREDICTABLE +#undef UPB_FORCEINLINE +#undef UPB_NOINLINE +#undef UPB_NORETURN +#undef UPB_PRINTF +#undef UPB_NODEREF +#undef UPB_NODISCARD +#undef UPB_MAX +#undef UPB_MIN +#undef UPB_UNUSED +#undef UPB_ASSUME +#undef UPB_ASSERT +#undef UPB_UNREACHABLE +#undef UPB_UNREACHABLE_FAILURE +#undef UPB_PRETTY_FUNCTION +#undef UPB_DEFAULT_MAX_BLOCK_SIZE +#undef UPB_SETJMP +#undef UPB_LONGJMP +#undef UPB_PTRADD +#undef UPB_MUSTTAIL +#undef UPB_PRESERVE_MOST +#undef UPB_PRESERVE_NONE +#undef UPB_FASTTABLE_SUPPORTED +#undef UPB_FASTTABLE_MASK +#undef UPB_FASTTABLE +#undef UPB_FASTTABLE_INIT +#undef UPB_POISON_MEMORY_REGION +#undef UPB_UNPOISON_MEMORY_REGION +#undef UPB_ASAN +#undef UPB_HWASAN +#undef UPB_HWASAN_POISON_TAG +#undef UPB_MSAN +#undef UPB_MALLOC_ALIGN +#undef UPB_TSAN +#undef UPB_DEPRECATED +#undef UPB_GNUC_MIN +#undef UPB_CLANG_MIN +#undef UPB_DESCRIPTOR_UPB_H_FILENAME +#undef UPB_DESC_MINITABLE +#undef UPB_IS_GOOGLE3 +#undef UPB_ATOMIC +#undef UPB_USE_C11_ATOMICS +#undef UPB_USE_MSC_ATOMICS +#undef UPB_PRIVATE +#undef UPB_ONLYBITS +#undef UPB_LINKARR_DECLARE +#undef UPB_LINKARR_APPEND +#undef UPB_LINKARR_START +#undef UPB_LINKARR_STOP +#undef UPB_HAS_ATTRIBUTE +#undef UPB_HAS_CPP_ATTRIBUTE +#undef UPB_HAS_BUILTIN +#undef UPB_HAS_EXTENSION +#undef UPB_HAS_FEATURE +#undef UPB_XSAN_MEMBER +#undef UPB_XSAN +#undef UPB_XSAN_STRUCT_SIZE +#undef UPB_ENABLE_REF_CYCLE_CHECKS +#undef UPB_ARM64_ASM +#undef UPB_ARM64_BTI_DEFAULT +#undef UPB_DEPRECATE_AND_INLINE +#undef UPB_MAYBE_ASSUME +#undef UPB_ATTR_CONST +#undef _UPB_STRINGIFY +#undef _UPB_STRINGIFY2 +#undef UPB_CONSTRUCTOR diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.c new file mode 100755 index 00000000..dd182bc2 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.c @@ -0,0 +1,69 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "shared_convert.h" + +bool shared_Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + upb_CType type, const upb_MessageDef* msgdef, + upb_Status* status) { + switch (type) { + case kUpb_CType_Bool: + return memcmp(&val1, &val2, 1) == 0; + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return memcmp(&val1, &val2, 4) == 0; + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return memcmp(&val1, &val2, 8) == 0; + case kUpb_CType_String: + case kUpb_CType_Bytes: + return val1.str_val.size == val2.str_val.size && + memcmp(val1.str_val.data, val2.str_val.data, val1.str_val.size) == + 0; + case kUpb_CType_Message: { + const upb_MiniTable* m = upb_MessageDef_MiniTable(msgdef); + const int options = 0; + return upb_Message_IsEqual(val1.msg_val, val2.msg_val, m, options); + } + default: + upb_Status_SetErrorMessage(status, "Internal error, unexpected type"); + return false; + } +} + +uint64_t shared_Msgval_GetHash(upb_MessageValue val, upb_CType type, + const upb_MessageDef* msgdef, uint64_t seed, + upb_Status* status) { + switch (type) { + case kUpb_CType_Bool: + return _upb_Hash(&val, 1, seed); + case kUpb_CType_Float: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Enum: + return _upb_Hash(&val, 4, seed); + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return _upb_Hash(&val, 8, seed); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return _upb_Hash(val.str_val.data, val.str_val.size, seed); + case kUpb_CType_Message: + return shared_Message_Hash(val.msg_val, msgdef, seed, status); + default: + upb_Status_SetErrorMessage(status, "Internal error, unexpected type"); + return 0; + } +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.h new file mode 100755 index 00000000..ca1e91d5 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_convert.h @@ -0,0 +1,26 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby <-> upb data conversion functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#ifndef RUBY_PROTOBUF_SHARED_CONVERT_H_ +#define RUBY_PROTOBUF_SHARED_CONVERT_H_ + +#include "ruby-upb.h" +#include "shared_message.h" + +bool shared_Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2, + upb_CType type, const upb_MessageDef* msgdef, + upb_Status* status); + +uint64_t shared_Msgval_GetHash(upb_MessageValue val, upb_CType type, + const upb_MessageDef* msgdef, uint64_t seed, + upb_Status* status); + +#endif // RUBY_PROTOBUF_SHARED_CONVERT_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.c new file mode 100755 index 00000000..122682ec --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.c @@ -0,0 +1,37 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby Message functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#include "shared_message.h" + +// Support function for Message_Hash. Returns a hash value for the given +// message. +uint64_t shared_Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed, upb_Status* status) { + upb_Arena* arena = upb_Arena_New(); + char* data; + size_t size; + + // Hash a deterministically serialized payloads with no unknown fields. + upb_EncodeStatus encode_status = upb_Encode( + msg, upb_MessageDef_MiniTable(m), + kUpb_EncodeOption_SkipUnknown | kUpb_EncodeOption_Deterministic, arena, + &data, &size); + + if (encode_status == kUpb_EncodeStatus_Ok) { + uint64_t ret = _upb_Hash(data, size, seed); + upb_Arena_Free(arena); + return ret; + } + + upb_Arena_Free(arena); + upb_Status_SetErrorMessage(status, "Error calculating hash"); + return 0; +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.h new file mode 100755 index 00000000..50722087 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/shared_message.h @@ -0,0 +1,21 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// ----------------------------------------------------------------------------- +// Ruby Message functions. Strictly free of dependencies on +// Ruby interpreter internals. + +#ifndef RUBY_PROTOBUF_SHARED_MESSAGE_H_ +#define RUBY_PROTOBUF_SHARED_MESSAGE_H_ + +#include "ruby-upb.h" + +// Returns a hash value for the given message. +uint64_t shared_Message_Hash(const upb_Message* msg, const upb_MessageDef* m, + uint64_t seed, upb_Status* status); + +#endif // RUBY_PROTOBUF_SHARED_MESSAGE_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/LICENSE b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/LICENSE new file mode 100755 index 00000000..e59f14fa --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2019 Yibo Cai +Copyright 2022 Google LLC + +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/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c new file mode 100755 index 00000000..f3301cc2 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c @@ -0,0 +1,207 @@ +// Copyright 2023 Google LLC +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +/* This is a wrapper for the Google range-sse.cc algorithm which checks whether + * a sequence of bytes is a valid UTF-8 sequence and finds the longest valid + * prefix of the UTF-8 sequence. + * + * The key difference is that it checks for as much ASCII symbols as possible + * and then falls back to the range-sse.cc algorithm. The changes to the + * algorithm are cosmetic, mostly to trick the clang compiler to produce optimal + * code. + * + * For API see the utf8_validity.h header. + */ +#include "utf8_range.h" + +#include +#include +#include + +#if defined(__GNUC__) +#define FORCE_INLINE_ATTR __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +#define FORCE_INLINE_ATTR __forceinline +#else +#define FORCE_INLINE_ATTR inline +#endif + +static FORCE_INLINE_ATTR uint64_t utf8_range_UnalignedLoad64( + const void* p) { + uint64_t t; + memcpy(&t, p, sizeof t); + return t; +} + +static FORCE_INLINE_ATTR int utf8_range_AsciiIsAscii(unsigned char c) { + return c < 128; +} + +static FORCE_INLINE_ATTR int utf8_range_IsTrailByteOk(const char c) { + return (int8_t)(c) <= (int8_t)(0xBF); +} + +/* If return_position is false then it returns 1 if |data| is a valid utf8 + * sequence, otherwise returns 0. + * If return_position is set to true, returns the length in bytes of the prefix + of |data| that is all structurally valid UTF-8. + */ +static size_t utf8_range_ValidateUTF8Naive(const char* data, const char* end, + int return_position) { + /* We return err_pos in the loop which is always 0 if !return_position */ + size_t err_pos = 0; + size_t codepoint_bytes = 0; + /* The early check is done because of early continue's on codepoints of all + * sizes, i.e. we first check for ascii and if it is, we call continue, then + * for 2 byte codepoints, etc. This is done in order to reduce indentation and + * improve readability of the codepoint validity check. + */ + while (data + codepoint_bytes < end) { + if (return_position) { + err_pos += codepoint_bytes; + } + data += codepoint_bytes; + const size_t len = end - data; + const unsigned char byte1 = data[0]; + + /* We do not skip many ascii bytes at the same time as this function is + used for tail checking (< 16 bytes) and for non x86 platforms. We also + don't think that cases where non-ASCII codepoints are followed by ascii + happen often. For small strings it also introduces some penalty. For + purely ascii UTF8 strings (which is the overwhelming case) we call + SkipAscii function which is multiplatform and extremely fast. + */ + /* [00..7F] ASCII -> 1 byte */ + if (utf8_range_AsciiIsAscii(byte1)) { + codepoint_bytes = 1; + continue; + } + /* [C2..DF], [80..BF] -> 2 bytes */ + if (len >= 2 && byte1 >= 0xC2 && byte1 <= 0xDF && + utf8_range_IsTrailByteOk(data[1])) { + codepoint_bytes = 2; + continue; + } + if (len >= 3) { + const unsigned char byte2 = data[1]; + const unsigned char byte3 = data[2]; + + /* Is byte2, byte3 between [0x80, 0xBF] + * Check for 0x80 was done above. + */ + if (!utf8_range_IsTrailByteOk(byte2) || + !utf8_range_IsTrailByteOk(byte3)) { + return err_pos; + } + + if (/* E0, A0..BF, 80..BF */ + ((byte1 == 0xE0 && byte2 >= 0xA0) || + /* E1..EC, 80..BF, 80..BF */ + (byte1 >= 0xE1 && byte1 <= 0xEC) || + /* ED, 80..9F, 80..BF */ + (byte1 == 0xED && byte2 <= 0x9F) || + /* EE..EF, 80..BF, 80..BF */ + (byte1 >= 0xEE && byte1 <= 0xEF))) { + codepoint_bytes = 3; + continue; + } + if (len >= 4) { + const unsigned char byte4 = data[3]; + /* Is byte4 between 0x80 ~ 0xBF */ + if (!utf8_range_IsTrailByteOk(byte4)) { + return err_pos; + } + + if (/* F0, 90..BF, 80..BF, 80..BF */ + ((byte1 == 0xF0 && byte2 >= 0x90) || + /* F1..F3, 80..BF, 80..BF, 80..BF */ + (byte1 >= 0xF1 && byte1 <= 0xF3) || + /* F4, 80..8F, 80..BF, 80..BF */ + (byte1 == 0xF4 && byte2 <= 0x8F))) { + codepoint_bytes = 4; + continue; + } + } + } + return err_pos; + } + if (return_position) { + err_pos += codepoint_bytes; + } + /* if return_position is false, this returns 1. + * if return_position is true, this returns err_pos. + */ + return err_pos + (1 - return_position); +} + +#if defined(__SSE4_1__) || (defined(__ARM_NEON) && defined(__ARM_64BIT_STATE)) +/* Returns the number of bytes needed to skip backwards to get to the first + byte of codepoint. + */ +static inline int utf8_range_CodepointSkipBackwards(int32_t codepoint_word) { + const int8_t* const codepoint = (const int8_t*)(&codepoint_word); + if (!utf8_range_IsTrailByteOk(codepoint[3])) { + return 1; + } else if (!utf8_range_IsTrailByteOk(codepoint[2])) { + return 2; + } else if (!utf8_range_IsTrailByteOk(codepoint[1])) { + return 3; + } + return 0; +} +#endif // __SSE4_1__ + +/* Skipping over ASCII as much as possible, per 8 bytes. It is intentional + as most strings to check for validity consist only of 1 byte codepoints. + */ +static inline const char* utf8_range_SkipAscii(const char* data, + const char* end) { + while (8 <= end - data && + (utf8_range_UnalignedLoad64(data) & 0x8080808080808080) == 0) { + data += 8; + } + while (data < end && utf8_range_AsciiIsAscii(*data)) { + ++data; + } + return data; +} + +#if defined(__SSE4_1__) +#include "utf8_range_sse.inc" +#elif defined(__ARM_NEON) && defined(__ARM_64BIT_STATE) +#include "utf8_range_neon.inc" +#endif + +static FORCE_INLINE_ATTR size_t utf8_range_Validate( + const char* data, size_t len, int return_position) { + if (len == 0) return 1 - return_position; + // Save buffer start address for later use + const char* const data_original = data; + const char* const end = data + len; + data = utf8_range_SkipAscii(data, end); + /* SIMD algorithm always outperforms the naive version for any data of + length >=16. + */ + if (end - data < 16) { + return (return_position ? (data - data_original) : 0) + + utf8_range_ValidateUTF8Naive(data, end, return_position); + } +#if defined(__SSE4_1__) || (defined(__ARM_NEON) && defined(__ARM_64BIT_STATE)) + return utf8_range_ValidateUTF8Simd( + data_original, data, end, return_position); +#else + return (return_position ? (data - data_original) : 0) + + utf8_range_ValidateUTF8Naive(data, end, return_position); +#endif +} + +bool utf8_range_IsValid(const char* data, size_t len) { + return utf8_range_Validate(data, len, /*return_position=*/0) != 0; +} + +size_t utf8_range_ValidPrefix(const char* data, size_t len) { + return utf8_range_Validate(data, len, /*return_position=*/1); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h new file mode 100755 index 00000000..5942d80e --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h @@ -0,0 +1,23 @@ +#ifndef THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ +#define THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns 1 if the sequence of characters is a valid UTF-8 sequence, otherwise +// 0. +bool utf8_range_IsValid(const char* data, size_t len); + +// Returns the length in bytes of the prefix of str that is all +// structurally valid UTF-8. +size_t utf8_range_ValidPrefix(const char* data, size_t len); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // THIRD_PARTY_UTF8_RANGE_UTF8_RANGE_H_ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc new file mode 100755 index 00000000..ab73754d --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc @@ -0,0 +1,117 @@ +#include + +/* This code is almost the same as SSE implementation, please reference + * utf8-range-sse.inc for detailed explanation. + * The only difference is the range adjustment step. NEON code is more + * straightforward. + */ + +static FORCE_INLINE_ATTR size_t utf8_range_ValidateUTF8Simd( + const char* data_original, const char* data, const char* end, + int return_position) { + const uint8x16_t first_len_tbl = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, + }; + const uint8x16_t first_range_tbl = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, + }; + const uint8x16_t range_min_tbl = { + 0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, + 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + const uint8x16_t range_max_tbl = { + 0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, + 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + /* Range adjustment in NEON uint8x16x2 table. Note that lanes are interleaved + * in register. The table below is plotted vertically to ease understanding. + * The 1st column is for E0~EF, 2nd column for F0~FF. + */ + // clang-format off + const uint8_t range_adjust_tbl_data[] = { + /* index -> 0~15 16~31 <- index */ + /* E0 -> */ 2, 3, /* <- F0 */ + 0, 0, + 0, 0, + 0, 0, + 0, 4, /* <- F4 */ + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + /* ED -> */ 3, 0, + 0, 0, + 0, 0, + }; + // clang-format on + const uint8x16x2_t range_adjust_tbl = vld2q_u8(range_adjust_tbl_data); + + const uint8x16_t const_1 = vdupq_n_u8(1); + const uint8x16_t const_2 = vdupq_n_u8(2); + const uint8x16_t const_e0 = vdupq_n_u8(0xE0); + + uint8x16_t prev_input = vdupq_n_u8(0); + uint8x16_t prev_first_len = vdupq_n_u8(0); + uint8x16_t error = vdupq_n_u8(0); + + while (end - data >= 16) { + const uint8x16_t input = vld1q_u8((const uint8_t*)data); + + const uint8x16_t high_nibbles = vshrq_n_u8(input, 4); + + const uint8x16_t first_len = vqtbl1q_u8(first_len_tbl, high_nibbles); + + uint8x16_t range = vqtbl1q_u8(first_range_tbl, high_nibbles); + + range = vorrq_u8(range, vextq_u8(prev_first_len, first_len, 15)); + + uint8x16_t shift2 = vextq_u8(prev_first_len, first_len, 14); + shift2 = vqsubq_u8(shift2, const_1); + range = vorrq_u8(range, shift2); + + uint8x16_t shift3 = vextq_u8(prev_first_len, first_len, 13); + shift3 = vqsubq_u8(shift3, const_2); + range = vorrq_u8(range, shift3); + + uint8x16_t shift1 = vextq_u8(prev_input, input, 15); + shift1 = vsubq_u8(shift1, const_e0); + range = vaddq_u8(range, vqtbl2q_u8(range_adjust_tbl, shift1)); + + const uint8x16_t min_range = vqtbl1q_u8(range_min_tbl, range); + const uint8x16_t max_range = vqtbl1q_u8(range_max_tbl, range); + + if (return_position) { + error = vcltq_u8(input, min_range); + error = vorrq_u8(error, vcgtq_u8(input, max_range)); + if (vmaxvq_u32(vreinterpretq_u32_u8(error))) { + break; + } + } else { + error = vorrq_u8(error, vcltq_u8(input, min_range)); + error = vorrq_u8(error, vcgtq_u8(input, max_range)); + } + + prev_input = input; + prev_first_len = first_len; + + data += 16; + } + + if (return_position && data == data_original) { + return utf8_range_ValidateUTF8Naive(data, end, return_position); + } + const int32_t prev = vgetq_lane_s32(vreinterpretq_s32_u8(prev_input), 3); + data -= utf8_range_CodepointSkipBackwards(prev); + if (return_position) { + return (data - data_original) + + utf8_range_ValidateUTF8Naive(data, end, return_position); + } + if (vmaxvq_u32(vreinterpretq_u32_u8(error))) { + return 0; + } + return utf8_range_ValidateUTF8Naive(data, end, return_position); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc new file mode 100755 index 00000000..c93fa963 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc @@ -0,0 +1,272 @@ +#include +#include +#include + +static FORCE_INLINE_ATTR size_t utf8_range_ValidateUTF8Simd( + const char* data_original, const char* data, const char* end, + int return_position) { + /* This code checks that utf-8 ranges are structurally valid 16 bytes at once + * using superscalar instructions. + * The mapping between ranges of codepoint and their corresponding utf-8 + * sequences is below. + */ + + /* + * U+0000...U+007F 00...7F + * U+0080...U+07FF C2...DF 80...BF + * U+0800...U+0FFF E0 A0...BF 80...BF + * U+1000...U+CFFF E1...EC 80...BF 80...BF + * U+D000...U+D7FF ED 80...9F 80...BF + * U+E000...U+FFFF EE...EF 80...BF 80...BF + * U+10000...U+3FFFF F0 90...BF 80...BF 80...BF + * U+40000...U+FFFFF F1...F3 80...BF 80...BF 80...BF + * U+100000...U+10FFFF F4 80...8F 80...BF 80...BF + */ + + /* First we compute the type for each byte, as given by the table below. + * This type will be used as an index later on. + */ + + /* + * Index Min Max Byte Type + * 0 00 7F Single byte sequence + * 1,2,3 80 BF Second, third and fourth byte for many of the sequences. + * 4 A0 BF Second byte after E0 + * 5 80 9F Second byte after ED + * 6 90 BF Second byte after F0 + * 7 80 8F Second byte after F4 + * 8 C2 F4 First non ASCII byte + * 9..15 7F 80 Invalid byte + */ + + /* After the first step we compute the index for all bytes, then we permute + the bytes according to their indices to check the ranges from the range + table. + * The range for a given type can be found in the range_min_table and + range_max_table, the range for type/index X is in range_min_table[X] ... + range_max_table[X]. + */ + + /* Algorithm: + * Put index zero to all bytes. + * Find all non ASCII characters, give them index 8. + * For each tail byte in a codepoint sequence, give it an index corresponding + to the 1 based index from the end. + * If the first byte of the codepoint is in the [C0...DF] range, we write + index 1 in the following byte. + * If the first byte of the codepoint is in the range [E0...EF], we write + indices 2 and 1 in the next two bytes. + * If the first byte of the codepoint is in the range [F0...FF] we write + indices 3,2,1 into the next three bytes. + * For finding the number of bytes we need to look at high nibbles (4 bits) + and do the lookup from the table, it can be done with shift by 4 + shuffle + instructions. We call it `first_len`. + * Then we shift first_len by 8 bits to get the indices of the 2nd bytes. + * Saturating sub 1 and shift by 8 bits to get the indices of the 3rd bytes. + * Again to get the indices of the 4th bytes. + * Take OR of all that 4 values and check within range. + */ + /* For example: + * input C3 80 68 E2 80 20 A6 F0 A0 80 AC 20 F0 93 80 80 + * first_len 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 0 + * 1st byte 8 0 0 8 0 0 0 8 0 0 0 0 8 0 0 0 + * 2nd byte 0 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 // Shift + sub + * 3rd byte 0 0 0 0 0 1 0 0 0 2 0 0 0 0 2 0 // Shift + sub + * 4th byte 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 // Shift + sub + * Index 8 1 0 8 2 1 0 8 3 2 1 0 8 3 2 1 // OR of results + */ + + /* Checking for errors: + * Error checking is done by looking up the high nibble (4 bits) of each byte + against an error checking table. + * Because the lookup value for the second byte depends of the value of the + first byte in codepoint, we use saturated operations to adjust the index. + * Specifically we need to add 2 for E0, 3 for ED, 3 for F0 and 4 for F4 to + match the correct index. + * If we subtract from all bytes EF then EO -> 241, ED -> 254, F0 -> 1, + F4 -> 5 + * Do saturating sub 240, then E0 -> 1, ED -> 14 and we can do lookup to + match the adjustment + * Add saturating 112, then F0 -> 113, F4 -> 117, all that were > 16 will + be more 128 and lookup in ef_fe_table will return 0 but for F0 + and F4 it will be 4 and 5 accordingly + */ + /* + * Then just check the appropriate ranges with greater/smaller equal + instructions. Check tail with a naive algorithm. + * To save from previous 16 byte checks we just align previous_first_len to + get correct continuations of the codepoints. + */ + + /* + * Map high nibble of "First Byte" to legal character length minus 1 + * 0x00 ~ 0xBF --> 0 + * 0xC0 ~ 0xDF --> 1 + * 0xE0 ~ 0xEF --> 2 + * 0xF0 ~ 0xFF --> 3 + */ + const __m128i first_len_table = + _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3); + + /* Map "First Byte" to 8-th item of range table (0xC2 ~ 0xF4) */ + const __m128i first_range_table = + _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8); + + /* + * Range table, map range index to min and max values + */ + const __m128i range_min_table = + _mm_setr_epi8(0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, 0xC2, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F); + + const __m128i range_max_table = + _mm_setr_epi8(0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, 0xF4, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80); + + /* + * Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after + * which the Second Byte are not 80~BF. It contains "range index adjustment". + * +------------+---------------+------------------+----------------+ + * | First Byte | original range| range adjustment | adjusted range | + * +------------+---------------+------------------+----------------+ + * | E0 | 2 | 2 | 4 | + * +------------+---------------+------------------+----------------+ + * | ED | 2 | 3 | 5 | + * +------------+---------------+------------------+----------------+ + * | F0 | 3 | 3 | 6 | + * +------------+---------------+------------------+----------------+ + * | F4 | 4 | 4 | 8 | + * +------------+---------------+------------------+----------------+ + */ + + /* df_ee_table[1] -> E0, df_ee_table[14] -> ED as ED - E0 = 13 */ + // The values represent the adjustment in the Range Index table for a correct + // index. + const __m128i df_ee_table = + _mm_setr_epi8(0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0); + + /* ef_fe_table[1] -> F0, ef_fe_table[5] -> F4, F4 - F0 = 4 */ + // The values represent the adjustment in the Range Index table for a correct + // index. + const __m128i ef_fe_table = + _mm_setr_epi8(0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + __m128i prev_input = _mm_set1_epi8(0); + __m128i prev_first_len = _mm_set1_epi8(0); + __m128i error = _mm_set1_epi8(0); + + while (end - data >= 16) { + const __m128i input = _mm_loadu_si128((const __m128i*)(data)); + + /* high_nibbles = input >> 4 */ + const __m128i high_nibbles = + _mm_and_si128(_mm_srli_epi16(input, 4), _mm_set1_epi8(0x0F)); + + /* first_len = legal character length minus 1 */ + /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ + /* first_len = first_len_table[high_nibbles] */ + __m128i first_len = _mm_shuffle_epi8(first_len_table, high_nibbles); + + /* First Byte: set range index to 8 for bytes within 0xC0 ~ 0xFF */ + /* range = first_range_table[high_nibbles] */ + __m128i range = _mm_shuffle_epi8(first_range_table, high_nibbles); + + /* Second Byte: set range index to first_len */ + /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ + /* range |= (first_len, prev_first_len) << 1 byte */ + range = _mm_or_si128(range, _mm_alignr_epi8(first_len, prev_first_len, 15)); + + /* Third Byte: set range index to saturate_sub(first_len, 1) */ + /* 0 for 00~7F, 0 for C0~DF, 1 for E0~EF, 2 for F0~FF */ + __m128i tmp1; + __m128i tmp2; + /* tmp1 = saturate_sub(first_len, 1) */ + tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(1)); + /* tmp2 = saturate_sub(prev_first_len, 1) */ + tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(1)); + /* range |= (tmp1, tmp2) << 2 bytes */ + range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 14)); + + /* Fourth Byte: set range index to saturate_sub(first_len, 2) */ + /* 0 for 00~7F, 0 for C0~DF, 0 for E0~EF, 1 for F0~FF */ + /* tmp1 = saturate_sub(first_len, 2) */ + tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(2)); + /* tmp2 = saturate_sub(prev_first_len, 2) */ + tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(2)); + /* range |= (tmp1, tmp2) << 3 bytes */ + range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 13)); + + /* + * Now we have below range indices calculated + * Correct cases: + * - 8 for C0~FF + * - 3 for 1st byte after F0~FF + * - 2 for 1st byte after E0~EF or 2nd byte after F0~FF + * - 1 for 1st byte after C0~DF or 2nd byte after E0~EF or + * 3rd byte after F0~FF + * - 0 for others + * Error cases: + * >9 for non ascii First Byte overlapping + * E.g., F1 80 C2 90 --> 8 3 10 2, where 10 indicates error + */ + + /* Adjust Second Byte range for special First Bytes(E0,ED,F0,F4) */ + /* Overlaps lead to index 9~15, which are illegal in range table */ + __m128i shift1; + __m128i pos; + __m128i range2; + /* shift1 = (input, prev_input) << 1 byte */ + shift1 = _mm_alignr_epi8(input, prev_input, 15); + pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF)); + /* + * shift1: | EF F0 ... FE | FF 00 ... ... DE | DF E0 ... EE | + * pos: | 0 1 15 | 16 17 239| 240 241 255| + * pos-240: | 0 0 0 | 0 0 0 | 0 1 15 | + * pos+112: | 112 113 127| >= 128 | >= 128 | + */ + tmp1 = _mm_subs_epu8(pos, _mm_set1_epi8(-16)); + range2 = _mm_shuffle_epi8(df_ee_table, tmp1); + tmp2 = _mm_adds_epu8(pos, _mm_set1_epi8(112)); + range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_table, tmp2)); + + range = _mm_add_epi8(range, range2); + + /* Load min and max values per calculated range index */ + __m128i min_range = _mm_shuffle_epi8(range_min_table, range); + __m128i max_range = _mm_shuffle_epi8(range_max_table, range); + + /* Check value range */ + if (return_position) { + error = _mm_cmplt_epi8(input, min_range); + error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range)); + /* 5% performance drop from this conditional branch */ + if (!_mm_testz_si128(error, error)) { + break; + } + } else { + error = _mm_or_si128(error, _mm_cmplt_epi8(input, min_range)); + error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range)); + } + + prev_input = input; + prev_first_len = first_len; + + data += 16; + } + /* If we got to the end, we don't need to skip any bytes backwards */ + if (return_position && data == data_original) { + return utf8_range_ValidateUTF8Naive(data, end, return_position); + } + /* Find previous codepoint (not 80~BF) */ + data -= utf8_range_CodepointSkipBackwards(_mm_extract_epi32(prev_input, 3)); + if (return_position) { + return (data - data_original) + + utf8_range_ValidateUTF8Naive(data, end, return_position); + } + /* Test if there was any error */ + if (!_mm_testz_si128(error, error)) { + return 0; + } + /* Check the tail */ + return utf8_range_ValidateUTF8Naive(data, end, return_position); +} diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.2/protobuf_c.so b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.2/protobuf_c.so new file mode 100755 index 00000000..a0ddf5e4 Binary files /dev/null and b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.2/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.3/protobuf_c.so b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.3/protobuf_c.so new file mode 100755 index 00000000..fff46807 Binary files /dev/null and b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.3/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.4/protobuf_c.so b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.4/protobuf_c.so new file mode 100755 index 00000000..08eaab12 Binary files /dev/null and b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/3.4/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/4.0/protobuf_c.so b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/4.0/protobuf_c.so new file mode 100755 index 00000000..02d31dc2 Binary files /dev/null and b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/4.0/protobuf_c.so differ diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf.rb new file mode 100755 index 00000000..fdfa9b68 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf.rb @@ -0,0 +1,61 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# require mixins before we hook them into the java & c code +require 'google/protobuf/message_exts' +require 'google/protobuf/internal/object_cache' + +# We define these before requiring the platform-specific modules. +# That way the module init can grab references to these. +module Google + module Protobuf + class Error < StandardError; end + class ParseError < Error; end + class TypeError < ::TypeError; end + + PREFER_FFI = case ENV['PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION'] + when nil, "", /^native$/i + false + when /^ffi$/i + true + else + warn "Unexpected value `#{ENV['PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION']}` for environment variable `PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION`. Should be either \"FFI\", \"NATIVE\"." + false + end + + def self.encode(msg, options = {}) + msg.to_proto(options) + end + + def self.encode_json(msg, options = {}) + msg.to_json(options) + end + + def self.decode(klass, proto, options = {}) + klass.decode(proto, options) + end + + def self.decode_json(klass, json, options = {}) + klass.decode_json(json, options) + end + + IMPLEMENTATION = if PREFER_FFI + begin + require 'google/protobuf_ffi' + :FFI + rescue LoadError + warn "Caught exception `#{$!.message}` while loading FFI implementation of google/protobuf." + warn "Falling back to native implementation." + require 'google/protobuf_native' + :NATIVE + end + else + require 'google/protobuf_native' + :NATIVE + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/any_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/any_pb.rb new file mode 100755 index 00000000..c53e405e --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/any_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/any.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x19google/protobuf/any.proto\x12\x0fgoogle.protobuf\"&\n\x03\x41ny\x12\x10\n\x08type_url\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42v\n\x13\x63om.google.protobufB\x08\x41nyProtoP\x01Z,google.golang.org/protobuf/types/known/anypb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Any = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Any").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/api_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/api_pb.rb new file mode 100755 index 00000000..e786a8e8 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/api_pb.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/api.proto + +require 'google/protobuf' + +require 'google/protobuf/source_context_pb' +require 'google/protobuf/type_pb' + + +descriptor_data = "\n\x19google/protobuf/api.proto\x12\x0fgoogle.protobuf\x1a$google/protobuf/source_context.proto\x1a\x1agoogle/protobuf/type.proto\"\x92\x02\n\x03\x41pi\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x07methods\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Method\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12&\n\x06mixins\x18\x06 \x03(\x0b\x32\x16.google.protobuf.Mixin\x12\'\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.Syntax\x12\x0f\n\x07\x65\x64ition\x18\x08 \x01(\t\"\xee\x01\n\x06Method\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x10request_type_url\x18\x02 \x01(\t\x12\x19\n\x11request_streaming\x18\x03 \x01(\x08\x12\x19\n\x11response_type_url\x18\x04 \x01(\t\x12\x1a\n\x12response_streaming\x18\x05 \x01(\x08\x12(\n\x07options\x18\x06 \x03(\x0b\x32\x17.google.protobuf.Option\x12+\n\x06syntax\x18\x07 \x01(\x0e\x32\x17.google.protobuf.SyntaxB\x02\x18\x01\x12\x13\n\x07\x65\x64ition\x18\x08 \x01(\tB\x02\x18\x01\"#\n\x05Mixin\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tBv\n\x13\x63om.google.protobufB\x08\x41piProtoP\x01Z,google.golang.org/protobuf/types/known/apipb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Api = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Api").msgclass + Method = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Method").msgclass + Mixin = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Mixin").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/descriptor_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/descriptor_pb.rb new file mode 100755 index 00000000..feb910f5 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/descriptor_pb.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/descriptor.proto + +require 'google/protobuf' + + +descriptor_data = "\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"U\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto*\x0c\x08\x80\xec\xca\xff\x01\x10\x81\xec\xca\xff\x01\"\xa1\x04\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x19\n\x11option_dependency\x18\x0f \x03(\t\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\x12)\n\x07\x65\x64ition\x18\x0e \x01(\x0e\x32\x18.google.protobuf.Edition\"\xe0\x05\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x12\x46\n\x0ereserved_range\x18\t \x03(\x0b\x32..google.protobuf.DescriptorProto.ReservedRange\x12\x15\n\rreserved_name\x18\n \x03(\t\x12\x35\n\nvisibility\x18\x0b \x01(\x0e\x32!.google.protobuf.SymbolVisibility\x1a\x65\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12\x37\n\x07options\x18\x03 \x01(\x0b\x32&.google.protobuf.ExtensionRangeOptions\x1a+\n\rReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xed\x03\n\x15\x45xtensionRangeOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\x12L\n\x0b\x64\x65\x63laration\x18\x02 \x03(\x0b\x32\x32.google.protobuf.ExtensionRangeOptions.DeclarationB\x03\x88\x01\x02\x12-\n\x08\x66\x65\x61tures\x18\x32 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12_\n\x0cverification\x18\x03 \x01(\x0e\x32\x38.google.protobuf.ExtensionRangeOptions.VerificationState:\nUNVERIFIEDB\x03\x88\x01\x02\x1ah\n\x0b\x44\x65\x63laration\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12\x11\n\tfull_name\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\t\x12\x10\n\x08reserved\x18\x05 \x01(\x08\x12\x10\n\x08repeated\x18\x06 \x01(\x08J\x04\x08\x04\x10\x05\"4\n\x11VerificationState\x12\x0f\n\x0b\x44\x45\x43LARATION\x10\x00\x12\x0e\n\nUNVERIFIED\x10\x01*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xd5\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12\x11\n\tjson_name\x18\n \x01(\t\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\x12\x17\n\x0fproto3_optional\x18\x11 \x01(\x08\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REPEATED\x10\x03\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\"T\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\x07options\x18\x02 \x01(\x0b\x32\x1d.google.protobuf.OneofOptions\"\xdb\x02\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\x12N\n\x0ereserved_range\x18\x04 \x03(\x0b\x32\x36.google.protobuf.EnumDescriptorProto.EnumReservedRange\x12\x15\n\rreserved_name\x18\x05 \x03(\t\x12\x35\n\nvisibility\x18\x06 \x01(\x0e\x32!.google.protobuf.SymbolVisibility\x1a/\n\x11\x45numReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x9e\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptionsJ\x04\x08\x04\x10\x05R\x06stream\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xaa\t\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\xe6\x01\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lseB\xc1\x01\xb2\x01\xbd\x01\x08\xe6\x07 \xe9\x07*\xb4\x01This behavior is enabled by default in editions 2024 and above. To disable it, you can set `features.(pb.java).nest_in_file_class = YES` on individual messages, enums, or services.\x12)\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08\x42\x02\x18\x01\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\xaf\x01\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x04trueB\x8e\x01\xb2\x01\x8a\x01 \xea\x07*\x84\x01\x63\x63_enable_arenas is enabled by default in every edition and overrides are ignored.This option is removed in editions 2026 and above.\x12\x19\n\x11objc_class_prefix\x18$ \x01(\t\x12\x18\n\x10\x63sharp_namespace\x18% \x01(\t\x12\x14\n\x0cswift_prefix\x18\' \x01(\t\x12\x18\n\x10php_class_prefix\x18( \x01(\t\x12\x15\n\rphp_namespace\x18) \x01(\t\x12\x1e\n\x16php_metadata_namespace\x18, \x01(\t\x12\x14\n\x0cruby_package\x18- \x01(\t\x12-\n\x08\x66\x65\x61tures\x18\x32 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08*\x10+J\x04\x08&\x10\'R\x14php_generic_services\"\xef\x02\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x32\n&deprecated_legacy_json_field_conflicts\x18\x0b \x01(\x08\x42\x02\x18\x01\x12-\n\x08\x66\x65\x61tures\x18\x0c \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07J\x04\x08\x08\x10\tJ\x04\x08\t\x10\n\"\xc6\x0b\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12?\n\x06jstype\x18\x06 \x01(\x0e\x32$.google.protobuf.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0funverified_lazy\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x17\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lseB\x02\x18\x01\x12\x1b\n\x0c\x64\x65\x62ug_redact\x18\x10 \x01(\x08:\x05\x66\x61lse\x12@\n\tretention\x18\x11 \x01(\x0e\x32-.google.protobuf.FieldOptions.OptionRetention\x12?\n\x07targets\x18\x13 \x03(\x0e\x32..google.protobuf.FieldOptions.OptionTargetType\x12\x46\n\x10\x65\x64ition_defaults\x18\x14 \x03(\x0b\x32,.google.protobuf.FieldOptions.EditionDefault\x12-\n\x08\x66\x65\x61tures\x18\x15 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x45\n\x0f\x66\x65\x61ture_support\x18\x16 \x01(\x0b\x32,.google.protobuf.FieldOptions.FeatureSupport\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\x1aJ\n\x0e\x45\x64itionDefault\x12)\n\x07\x65\x64ition\x18\x03 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\r\n\x05value\x18\x02 \x01(\t\x1a\xe3\x01\n\x0e\x46\x65\x61tureSupport\x12\x34\n\x12\x65\x64ition_introduced\x18\x01 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x34\n\x12\x65\x64ition_deprecated\x18\x02 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x1b\n\x13\x64\x65precation_warning\x18\x03 \x01(\t\x12\x31\n\x0f\x65\x64ition_removed\x18\x04 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x15\n\rremoval_error\x18\x05 \x01(\t\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02\"U\n\x0fOptionRetention\x12\x15\n\x11RETENTION_UNKNOWN\x10\x00\x12\x15\n\x11RETENTION_RUNTIME\x10\x01\x12\x14\n\x10RETENTION_SOURCE\x10\x02\"\x8c\x02\n\x10OptionTargetType\x12\x17\n\x13TARGET_TYPE_UNKNOWN\x10\x00\x12\x14\n\x10TARGET_TYPE_FILE\x10\x01\x12\x1f\n\x1bTARGET_TYPE_EXTENSION_RANGE\x10\x02\x12\x17\n\x13TARGET_TYPE_MESSAGE\x10\x03\x12\x15\n\x11TARGET_TYPE_FIELD\x10\x04\x12\x15\n\x11TARGET_TYPE_ONEOF\x10\x05\x12\x14\n\x10TARGET_TYPE_ENUM\x10\x06\x12\x1a\n\x16TARGET_TYPE_ENUM_ENTRY\x10\x07\x12\x17\n\x13TARGET_TYPE_SERVICE\x10\x08\x12\x16\n\x12TARGET_TYPE_METHOD\x10\t*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x12\x10\x13\"\x95\x01\n\x0cOneofOptions\x12-\n\x08\x66\x65\x61tures\x18\x01 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xfe\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x32\n&deprecated_legacy_json_field_conflicts\x18\x06 \x01(\x08\x42\x02\x18\x01\x12-\n\x08\x66\x65\x61tures\x18\x07 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x05\x10\x06\"\x98\x02\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12-\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x1b\n\x0c\x64\x65\x62ug_redact\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x45\n\x0f\x66\x65\x61ture_support\x18\x04 \x01(\x0b\x32,.google.protobuf.FieldOptions.FeatureSupport\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xb2\x01\n\x0eServiceOptions\x12-\n\x08\x66\x65\x61tures\x18\" \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe4\x02\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12_\n\x11idempotency_level\x18\" \x01(\x0e\x32/.google.protobuf.MethodOptions.IdempotencyLevel:\x13IDEMPOTENCY_UNKNOWN\x12-\n\x08\x66\x65\x61tures\x18# \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"P\n\x10IdempotencyLevel\x12\x17\n\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n\nIDEMPOTENT\x10\x02*\x06\x08\xde\x07\x10\xe7\x07*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xde\x10\n\nFeatureSet\x12\x82\x01\n\x0e\x66ield_presence\x18\x01 \x01(\x0e\x32).google.protobuf.FeatureSet.FieldPresenceB?\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\r\x12\x08\x45XPLICIT\x18\x84\x07\xa2\x01\r\x12\x08IMPLICIT\x18\xe7\x07\xa2\x01\r\x12\x08\x45XPLICIT\x18\xe8\x07\xb2\x01\x03\x08\xe8\x07\x12\x62\n\tenum_type\x18\x02 \x01(\x0e\x32$.google.protobuf.FeatureSet.EnumTypeB)\x88\x01\x01\x98\x01\x06\x98\x01\x01\xa2\x01\x0b\x12\x06\x43LOSED\x18\x84\x07\xa2\x01\t\x12\x04OPEN\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12\x81\x01\n\x17repeated_field_encoding\x18\x03 \x01(\x0e\x32\x31.google.protobuf.FeatureSet.RepeatedFieldEncodingB-\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\r\x12\x08\x45XPANDED\x18\x84\x07\xa2\x01\x0b\x12\x06PACKED\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12n\n\x0futf8_validation\x18\x04 \x01(\x0e\x32*.google.protobuf.FeatureSet.Utf8ValidationB)\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\t\x12\x04NONE\x18\x84\x07\xa2\x01\x0b\x12\x06VERIFY\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12m\n\x10message_encoding\x18\x05 \x01(\x0e\x32+.google.protobuf.FeatureSet.MessageEncodingB&\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\x14\x12\x0fLENGTH_PREFIXED\x18\x84\x07\xb2\x01\x03\x08\xe8\x07\x12v\n\x0bjson_format\x18\x06 \x01(\x0e\x32&.google.protobuf.FeatureSet.JsonFormatB9\x88\x01\x01\x98\x01\x03\x98\x01\x06\x98\x01\x01\xa2\x01\x17\x12\x12LEGACY_BEST_EFFORT\x18\x84\x07\xa2\x01\n\x12\x05\x41LLOW\x18\xe7\x07\xb2\x01\x03\x08\xe8\x07\x12\xa8\x01\n\x14\x65nforce_naming_style\x18\x07 \x01(\x0e\x32..google.protobuf.FeatureSet.EnforceNamingStyleBZ\x88\x01\x02\x98\x01\x01\x98\x01\x02\x98\x01\x03\x98\x01\x04\x98\x01\x05\x98\x01\x06\x98\x01\x07\x98\x01\x08\x98\x01\t\xa2\x01\x11\x12\x0cSTYLE_LEGACY\x18\x84\x07\xa2\x01\x0e\x12\tSTYLE2024\x18\xe9\x07\xa2\x01\x0e\x12\tSTYLE2026\x18\xea\x07\xb2\x01\x03\x08\xe9\x07\x12\xae\x01\n\x19\x64\x65\x66\x61ult_symbol_visibility\x18\x08 \x01(\x0e\x32\x45.google.protobuf.FeatureSet.VisibilityFeature.DefaultSymbolVisibilityBD\x88\x01\x02\x98\x01\x01\xa2\x01\x0f\x12\nEXPORT_ALL\x18\x84\x07\xa2\x01\x15\x12\x10\x45XPORT_TOP_LEVEL\x18\xe9\x07\xa2\x01\x0b\x12\x06STRICT\x18\xea\x07\xb2\x01\x03\x08\xe9\x07\x12\xaf\x01\n\x14\x65nforce_proto_limits\x18\t \x01(\x0e\x32\x41.google.protobuf.FeatureSet.ProtoLimitsFeature.EnforceProtoLimitsBN\x88\x01\x02\x98\x01\x06\x98\x01\x03\x98\x01\x04\x98\x01\x05\xa2\x01\x1e\x12\x19LEGACY_NO_EXPLICIT_LIMITS\x18\x84\x07\xa2\x01\x15\x12\x10PROTO_LIMITS2026\x18\xea\x07\xb2\x01\x03\x08\xea\x07\x1a\xa1\x01\n\x11VisibilityFeature\"\x81\x01\n\x17\x44\x65\x66\x61ultSymbolVisibility\x12%\n!DEFAULT_SYMBOL_VISIBILITY_UNKNOWN\x10\x00\x12\x0e\n\nEXPORT_ALL\x10\x01\x12\x14\n\x10\x45XPORT_TOP_LEVEL\x10\x02\x12\r\n\tLOCAL_ALL\x10\x03\x12\n\n\x06STRICT\x10\x04J\x08\x08\x01\x10\x80\x80\x80\x80\x02\x1ay\n\x12ProtoLimitsFeature\"c\n\x12\x45nforceProtoLimits\x12\x18\n\x14PROTO_LIMITS_UNKNOWN\x10\x00\x12\x1d\n\x19LEGACY_NO_EXPLICIT_LIMITS\x10\x01\x12\x14\n\x10PROTO_LIMITS2026\x10\x02\"\\\n\rFieldPresence\x12\x1a\n\x16\x46IELD_PRESENCE_UNKNOWN\x10\x00\x12\x0c\n\x08\x45XPLICIT\x10\x01\x12\x0c\n\x08IMPLICIT\x10\x02\x12\x13\n\x0fLEGACY_REQUIRED\x10\x03\"7\n\x08\x45numType\x12\x15\n\x11\x45NUM_TYPE_UNKNOWN\x10\x00\x12\x08\n\x04OPEN\x10\x01\x12\n\n\x06\x43LOSED\x10\x02\"V\n\x15RepeatedFieldEncoding\x12#\n\x1fREPEATED_FIELD_ENCODING_UNKNOWN\x10\x00\x12\n\n\x06PACKED\x10\x01\x12\x0c\n\x08\x45XPANDED\x10\x02\"I\n\x0eUtf8Validation\x12\x1b\n\x17UTF8_VALIDATION_UNKNOWN\x10\x00\x12\n\n\x06VERIFY\x10\x02\x12\x08\n\x04NONE\x10\x03\"\x04\x08\x01\x10\x01\"S\n\x0fMessageEncoding\x12\x1c\n\x18MESSAGE_ENCODING_UNKNOWN\x10\x00\x12\x13\n\x0fLENGTH_PREFIXED\x10\x01\x12\r\n\tDELIMITED\x10\x02\"H\n\nJsonFormat\x12\x17\n\x13JSON_FORMAT_UNKNOWN\x10\x00\x12\t\n\x05\x41LLOW\x10\x01\x12\x16\n\x12LEGACY_BEST_EFFORT\x10\x02\"f\n\x12\x45nforceNamingStyle\x12 \n\x1c\x45NFORCE_NAMING_STYLE_UNKNOWN\x10\x00\x12\r\n\tSTYLE2024\x10\x01\x12\x10\n\x0cSTYLE_LEGACY\x10\x02\x12\r\n\tSTYLE2026\x10\x03*\x06\x08\xe8\x07\x10\x8bN*\x06\x08\x8bN\x10\x90N*\x06\x08\x90N\x10\x91NJ\x06\x08\xe7\x07\x10\xe8\x07\"\x98\x03\n\x12\x46\x65\x61tureSetDefaults\x12N\n\x08\x64\x65\x66\x61ults\x18\x01 \x03(\x0b\x32<.google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault\x12\x31\n\x0fminimum_edition\x18\x04 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x31\n\x0fmaximum_edition\x18\x05 \x01(\x0e\x32\x18.google.protobuf.Edition\x1a\xcb\x01\n\x18\x46\x65\x61tureSetEditionDefault\x12)\n\x07\x65\x64ition\x18\x03 \x01(\x0e\x32\x18.google.protobuf.Edition\x12\x39\n\x14overridable_features\x18\x04 \x01(\x0b\x32\x1b.google.protobuf.FeatureSet\x12\x33\n\x0e\x66ixed_features\x18\x05 \x01(\x0b\x32\x1b.google.protobuf.FeatureSetJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03R\x08\x66\x65\x61tures\"\xe3\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x86\x01\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\t\x12!\n\x19leading_detached_comments\x18\x06 \x03(\t*\x0c\x08\x80\xec\xca\xff\x01\x10\x81\xec\xca\xff\x01\"\x9c\x02\n\x11GeneratedCodeInfo\x12\x41\n\nannotation\x18\x01 \x03(\x0b\x32-.google.protobuf.GeneratedCodeInfo.Annotation\x1a\xc3\x01\n\nAnnotation\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x13\n\x0bsource_file\x18\x02 \x01(\t\x12\r\n\x05\x62\x65gin\x18\x03 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x04 \x01(\x05\x12H\n\x08semantic\x18\x05 \x01(\x0e\x32\x36.google.protobuf.GeneratedCodeInfo.Annotation.Semantic\"(\n\x08Semantic\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03SET\x10\x01\x12\t\n\x05\x41LIAS\x10\x02*\xd1\x02\n\x07\x45\x64ition\x12\x13\n\x0f\x45\x44ITION_UNKNOWN\x10\x00\x12\x13\n\x0e\x45\x44ITION_LEGACY\x10\x84\x07\x12\x13\n\x0e\x45\x44ITION_PROTO2\x10\xe6\x07\x12\x13\n\x0e\x45\x44ITION_PROTO3\x10\xe7\x07\x12\x11\n\x0c\x45\x44ITION_2023\x10\xe8\x07\x12\x11\n\x0c\x45\x44ITION_2024\x10\xe9\x07\x12\x11\n\x0c\x45\x44ITION_2026\x10\xea\x07\x12\x15\n\x10\x45\x44ITION_UNSTABLE\x10\x8fN\x12\x17\n\x13\x45\x44ITION_1_TEST_ONLY\x10\x01\x12\x17\n\x13\x45\x44ITION_2_TEST_ONLY\x10\x02\x12\x1d\n\x17\x45\x44ITION_99997_TEST_ONLY\x10\x9d\x8d\x06\x12\x1d\n\x17\x45\x44ITION_99998_TEST_ONLY\x10\x9e\x8d\x06\x12\x1d\n\x17\x45\x44ITION_99999_TEST_ONLY\x10\x9f\x8d\x06\x12\x13\n\x0b\x45\x44ITION_MAX\x10\xff\xff\xff\xff\x07*U\n\x10SymbolVisibility\x12\x14\n\x10VISIBILITY_UNSET\x10\x00\x12\x14\n\x10VISIBILITY_LOCAL\x10\x01\x12\x15\n\x11VISIBILITY_EXPORT\x10\x02\x42~\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01Z-google.golang.org/protobuf/types/descriptorpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1aGoogle.Protobuf.Reflection" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + FileDescriptorSet = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileDescriptorSet").msgclass + FileDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileDescriptorProto").msgclass + DescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto").msgclass + DescriptorProto::ExtensionRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto.ExtensionRange").msgclass + DescriptorProto::ReservedRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DescriptorProto.ReservedRange").msgclass + ExtensionRangeOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions").msgclass + ExtensionRangeOptions::Declaration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions.Declaration").msgclass + ExtensionRangeOptions::VerificationState = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ExtensionRangeOptions.VerificationState").enummodule + FieldDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto").msgclass + FieldDescriptorProto::Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto.Type").enummodule + FieldDescriptorProto::Label = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldDescriptorProto.Label").enummodule + OneofDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.OneofDescriptorProto").msgclass + EnumDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumDescriptorProto").msgclass + EnumDescriptorProto::EnumReservedRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumDescriptorProto.EnumReservedRange").msgclass + EnumValueDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValueDescriptorProto").msgclass + ServiceDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ServiceDescriptorProto").msgclass + MethodDescriptorProto = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodDescriptorProto").msgclass + FileOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileOptions").msgclass + FileOptions::OptimizeMode = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FileOptions.OptimizeMode").enummodule + MessageOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MessageOptions").msgclass + FieldOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions").msgclass + FieldOptions::EditionDefault = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.EditionDefault").msgclass + FieldOptions::FeatureSupport = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.FeatureSupport").msgclass + FieldOptions::CType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.CType").enummodule + FieldOptions::JSType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.JSType").enummodule + FieldOptions::OptionRetention = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.OptionRetention").enummodule + FieldOptions::OptionTargetType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldOptions.OptionTargetType").enummodule + OneofOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.OneofOptions").msgclass + EnumOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumOptions").msgclass + EnumValueOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValueOptions").msgclass + ServiceOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ServiceOptions").msgclass + MethodOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodOptions").msgclass + MethodOptions::IdempotencyLevel = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.MethodOptions.IdempotencyLevel").enummodule + UninterpretedOption = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UninterpretedOption").msgclass + UninterpretedOption::NamePart = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UninterpretedOption.NamePart").msgclass + FeatureSet = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet").msgclass + FeatureSet::VisibilityFeature = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.VisibilityFeature").msgclass + FeatureSet::VisibilityFeature::DefaultSymbolVisibility = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.VisibilityFeature.DefaultSymbolVisibility").enummodule + FeatureSet::ProtoLimitsFeature = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.ProtoLimitsFeature").msgclass + FeatureSet::ProtoLimitsFeature::EnforceProtoLimits = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.ProtoLimitsFeature.EnforceProtoLimits").enummodule + FeatureSet::FieldPresence = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.FieldPresence").enummodule + FeatureSet::EnumType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.EnumType").enummodule + FeatureSet::RepeatedFieldEncoding = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.RepeatedFieldEncoding").enummodule + FeatureSet::Utf8Validation = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.Utf8Validation").enummodule + FeatureSet::MessageEncoding = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.MessageEncoding").enummodule + FeatureSet::JsonFormat = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.JsonFormat").enummodule + FeatureSet::EnforceNamingStyle = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSet.EnforceNamingStyle").enummodule + FeatureSetDefaults = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSetDefaults").msgclass + FeatureSetDefaults::FeatureSetEditionDefault = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault").msgclass + SourceCodeInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceCodeInfo").msgclass + SourceCodeInfo::Location = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceCodeInfo.Location").msgclass + GeneratedCodeInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo").msgclass + GeneratedCodeInfo::Annotation = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo.Annotation").msgclass + GeneratedCodeInfo::Annotation::Semantic = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.GeneratedCodeInfo.Annotation.Semantic").enummodule + Edition = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Edition").enummodule + SymbolVisibility = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SymbolVisibility").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/duration_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/duration_pb.rb new file mode 100755 index 00000000..f9697768 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/duration_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/duration.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1egoogle/protobuf/duration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Duration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Duration").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/empty_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/empty_pb.rb new file mode 100755 index 00000000..da9c7237 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/empty_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/empty.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1bgoogle/protobuf/empty.proto\x12\x0fgoogle.protobuf\"\x07\n\x05\x45mptyB}\n\x13\x63om.google.protobufB\nEmptyProtoP\x01Z.google.golang.org/protobuf/types/known/emptypb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Empty = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor.rb new file mode 100755 index 00000000..c30da20b --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor.rb @@ -0,0 +1,175 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + ## + # Message Descriptor - Descriptor for short. + class Descriptor + attr :descriptor_pool, :msg_class + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [Descriptor] Descriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _ = nil) + msg_def_ptr = value.nil? ? nil : value.instance_variable_get(:@msg_def) + return ::FFI::Pointer::NULL if msg_def_ptr.nil? + raise "Underlying msg_def was null!" if msg_def_ptr.null? + msg_def_ptr + end + + ## + # @param msg_def [::FFI::Pointer] MsgDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(msg_def, _ = nil) + return nil if msg_def.nil? or msg_def.null? + file_def = Google::Protobuf::FFI.get_message_file_def msg_def + descriptor_from_file_def(file_def, msg_def) + end + end + + def to_native + self.class.to_native(self) + end + + ## + # Great write up of this strategy: + # See https://blog.appsignal.com/2018/08/07/ruby-magic-changing-the-way-ruby-creates-objects.html + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "Descriptor - (not the message class) #{name}" + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.get_message_file_def(@msg_def)) + end + + def name + @name ||= Google::Protobuf::FFI.get_message_fullname(self) + end + + def each_oneof &block + n = Google::Protobuf::FFI.oneof_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_oneof_by_index(self, i)) + end + nil + end + + def each &block + n = Google::Protobuf::FFI.field_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_field_by_index(self, i)) + end + nil + end + + def lookup(name) + Google::Protobuf::FFI.get_field_by_name(self, name, name.size) + end + + def lookup_oneof(name) + Google::Protobuf::FFI.get_oneof_by_name(self, name, name.size) + end + + def msgclass + @msg_class ||= build_message_class + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.message_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::MessageOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.message_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::DescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + extend Google::Protobuf::Internal::Convert + + def initialize(msg_def, descriptor_pool) + @msg_def = msg_def + @msg_class = nil + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(msg_def, descriptor_pool) + instance = allocate + instance.send(:initialize, msg_def, descriptor_pool) + instance + end + + def wrapper? + if defined? @wrapper + @wrapper + else + @wrapper = case Google::Protobuf::FFI.get_well_known_type self + when :DoubleValue, :FloatValue, :Int64Value, :UInt64Value, :Int32Value, :UInt32Value, :StringValue, :BytesValue, :BoolValue + true + else + false + end + end + end + + def self.get_message(msg, descriptor, arena) + return nil if msg.nil? or msg.null? + message = OBJECT_CACHE.get(msg.address) + if message.nil? + message = descriptor.msgclass.send(:private_constructor, arena, msg: msg) + end + message + end + + def pool + @descriptor_pool + end + end + + class FFI + # MessageDef + attach_function :new_message_from_def, :upb_Message_New, [MiniTable.by_ref, Internal::Arena], :Message + attach_function :field_count, :upb_MessageDef_FieldCount, [Descriptor], :int + attach_function :get_message_file_def, :upb_MessageDef_File, [:pointer], :FileDef + attach_function :get_message_fullname, :upb_MessageDef_FullName, [Descriptor], :string + attach_function :get_mini_table, :upb_MessageDef_MiniTable, [Descriptor], MiniTable.ptr + attach_function :oneof_count, :upb_MessageDef_OneofCount, [Descriptor], :int + attach_function :message_options, :Descriptor_serialized_options, [Descriptor, :pointer, Internal::Arena], :pointer + attach_function :get_well_known_type, :upb_MessageDef_WellKnownType, [Descriptor], WellKnown + attach_function :find_msg_def_by_name, :upb_MessageDef_FindByNameWithSize, [Descriptor, :string, :size_t, :FieldDefPointer, :OneofDefPointer], :bool + attach_function :message_to_proto, :Descriptor_serialized_to_proto, [Descriptor, :pointer, Internal::Arena], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor_pool.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor_pool.rb new file mode 100755 index 00000000..c39b3d7c --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/descriptor_pool.rb @@ -0,0 +1,83 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # DefPool + attach_function :add_serialized_file, :upb_DefPool_AddFile, [:DefPool, :FileDescriptorProto, Status.by_ref], :FileDef + attach_function :free_descriptor_pool, :upb_DefPool_Free, [:DefPool], :void + attach_function :create_descriptor_pool,:upb_DefPool_New, [], :DefPool + attach_function :disable_closed_enum_checking, :upb_DefPool_DisableClosedEnumChecking, [:DefPool], :void + attach_function :get_extension_registry,:upb_DefPool_ExtensionRegistry, [:DefPool], :ExtensionRegistry + attach_function :lookup_enum, :upb_DefPool_FindEnumByName, [:DefPool, :string], EnumDescriptor + attach_function :lookup_extension, :upb_DefPool_FindExtensionByName,[:DefPool, :string], FieldDescriptor + attach_function :lookup_msg, :upb_DefPool_FindMessageByName, [:DefPool, :string], Descriptor + attach_function :lookup_service, :upb_DefPool_FindServiceByName, [:DefPool, :string], ServiceDescriptor + attach_function :lookup_file, :upb_DefPool_FindFileByName, [:DefPool, :string], FileDescriptor + + # FileDescriptorProto + attach_function :parse, :FileDescriptorProto_parse, [:binary_string, :size_t, Internal::Arena], :FileDescriptorProto + end + class DescriptorPool + attr :descriptor_pool + attr_accessor :descriptor_class_by_def + + def initialize + @descriptor_pool = ::FFI::AutoPointer.new(Google::Protobuf::FFI.create_descriptor_pool, Google::Protobuf::FFI.method(:free_descriptor_pool)) + @descriptor_class_by_def = {} + + # Ruby treats all enums as open. + Google::Protobuf::FFI.disable_closed_enum_checking(@descriptor_pool) + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + Google::Protobuf::OBJECT_CACHE.try_add @descriptor_pool.address, self + end + + def add_serialized_file(file_contents) + # Allocate memory sized to file_contents + memBuf = ::FFI::MemoryPointer.new(:char, file_contents.bytesize) + # Insert the data + memBuf.put_bytes(0, file_contents) + temporary_arena = Google::Protobuf::FFI.create_arena + file_descriptor_proto = Google::Protobuf::FFI.parse memBuf, file_contents.bytesize, temporary_arena + raise ArgumentError.new("Unable to parse FileDescriptorProto") if file_descriptor_proto.null? + + status = Google::Protobuf::FFI::Status.new + file_descriptor = Google::Protobuf::FFI.add_serialized_file @descriptor_pool, file_descriptor_proto, status + if file_descriptor.null? + raise TypeError.new("Unable to build file to DescriptorPool: #{Google::Protobuf::FFI.error_message(status)}") + else + @descriptor_class_by_def[file_descriptor.address] = FileDescriptor.new file_descriptor, self + end + end + + def lookup name + Google::Protobuf::FFI.lookup_msg(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_enum(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_extension(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_service(@descriptor_pool, name) || + Google::Protobuf::FFI.lookup_file(@descriptor_pool, name) + end + + def self.generated_pool + @@generated_pool ||= DescriptorPool.new + end + + private + + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + def get_file_descriptor file_def + return nil if file_def.null? + @descriptor_class_by_def[file_def.address] ||= FileDescriptor.new(file_def, self) + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/enum_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/enum_descriptor.rb new file mode 100755 index 00000000..f95e0915 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/enum_descriptor.rb @@ -0,0 +1,183 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class EnumDescriptor + attr :descriptor_pool, :enum_def + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [EnumDescriptor] EnumDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + value.instance_variable_get(:@enum_def) || ::FFI::Pointer::NULL + end + + ## + # @param enum_def [::FFI::Pointer] EnumDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(enum_def, _) + return nil if enum_def.nil? or enum_def.null? + file_def = Google::Protobuf::FFI.get_message_file_def enum_def + descriptor_from_file_def(file_def, enum_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.get_enum_file_descriptor(self)) + end + + def name + Google::Protobuf::FFI.get_enum_fullname(self) + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def lookup_name(name) + self.class.send(:lookup_name, self, name) + end + + def lookup_value(number) + self.class.send(:lookup_value, self, number) + end + + def each &block + n = Google::Protobuf::FFI.enum_value_count(self) + 0.upto(n - 1) do |i| + enum_value = Google::Protobuf::FFI.enum_value_by_index(self, i) + yield(Google::Protobuf::FFI.enum_name(enum_value).to_sym, Google::Protobuf::FFI.enum_number(enum_value)) + end + nil + end + + def enummodule + if @module.nil? + @module = build_enum_module + end + @module + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.enum_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::EnumOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.enum_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::EnumDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + def initialize(enum_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @enum_def = enum_def + @module = nil + end + + def self.private_constructor(enum_def, descriptor_pool) + instance = allocate + instance.send(:initialize, enum_def, descriptor_pool) + instance + end + + def self.lookup_value(enum_def, number) + enum_value = Google::Protobuf::FFI.enum_value_by_number(enum_def, number) + if enum_value.null? + nil + else + Google::Protobuf::FFI.enum_name(enum_value).to_sym + end + end + + def self.lookup_name(enum_def, name) + enum_value = Google::Protobuf::FFI.enum_value_by_name(enum_def, name.to_s, name.size) + if enum_value.null? + nil + else + Google::Protobuf::FFI.enum_number(enum_value) + end + end + + def build_enum_module + descriptor = self + dynamic_module = Module.new do + @descriptor = descriptor + + class << self + attr_accessor :descriptor + end + + def self.lookup(number) + descriptor.lookup_value number + end + + def self.resolve(name) + descriptor.lookup_name name + end + end + + self.each do |name, value| + if name[0] < 'A' || name[0] > 'Z' + if name[0] >= 'a' and name[0] <= 'z' + name = name[0].upcase + name[1..-1] # auto capitalize + else + warn( + "Enum value '#{name}' does not start with an uppercase letter " + + "as is required for Ruby constants.") + next + end + end + dynamic_module.const_set(name.to_sym, value) + end + dynamic_module + end + end + + class FFI + # EnumDescriptor + attach_function :get_enum_file_descriptor, :upb_EnumDef_File, [EnumDescriptor], :FileDef + attach_function :enum_value_by_name, :upb_EnumDef_FindValueByNameWithSize,[EnumDescriptor, :string, :size_t], :EnumValueDef + attach_function :enum_value_by_number, :upb_EnumDef_FindValueByNumber, [EnumDescriptor, :int], :EnumValueDef + attach_function :get_enum_fullname, :upb_EnumDef_FullName, [EnumDescriptor], :string + attach_function :enum_options, :EnumDescriptor_serialized_options, [EnumDescriptor, :pointer, Internal::Arena], :pointer + attach_function :enum_to_proto, :EnumDescriptor_serialized_to_proto, [EnumDescriptor, :pointer, Internal::Arena], :pointer + attach_function :enum_value_by_index, :upb_EnumDef_Value, [EnumDescriptor, :int], :EnumValueDef + attach_function :enum_value_count, :upb_EnumDef_ValueCount, [EnumDescriptor], :int + attach_function :enum_name, :upb_EnumValueDef_Name, [:EnumValueDef], :string + attach_function :enum_number, :upb_EnumValueDef_Number, [:EnumValueDef], :int + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/ffi.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/ffi.rb new file mode 100755 index 00000000..0a916696 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/ffi.rb @@ -0,0 +1,213 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + extend ::FFI::Library + # Workaround for Bazel's use of symlinks + JRuby's __FILE__ and `caller` + # that resolves them. + if ENV['BAZEL'] == 'true' + ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi', ENV['PWD'] + else + ffi_lib ::FFI::Compiler::Loader.find 'protobuf_c_ffi' + end + + ## Map + Upb_Map_Begin = -1 + + ## Encoding Status + Upb_Status_MaxMessage = 511 + Upb_Encode_Deterministic = 1 + Upb_Encode_SkipUnknown = 2 + + ## JSON Encoding options + # When set, emits 0/default values. TODO: proto3 only? + Upb_JsonEncode_EmitDefaults = 1 + # When set, use normal (snake_case) field names instead of JSON (camelCase) names. + Upb_JsonEncode_UseProtoNames = 2 + # When set, emits enums as their integer values instead of as their names. + Upb_JsonEncode_FormatEnumsAsIntegers = 4 + + ## JSON Decoding options + Upb_JsonDecode_IgnoreUnknown = 1 + + ## JSON Decoding results + Upb_JsonDecodeResult_Ok = 0 + Upb_JsonDecodeResult_Error = 2 + + typedef :pointer, :Array + typedef :pointer, :DefPool + typedef :pointer, :EnumValueDef + typedef :pointer, :ExtensionRegistry + typedef :pointer, :FieldDefPointer + typedef :pointer, :FileDef + typedef :pointer, :FileDescriptorProto + typedef :pointer, :Map + typedef :pointer, :Message # Instances of a message + typedef :pointer, :OneofDefPointer + typedef :pointer, :binary_string + if ::FFI::Platform::ARCH == "aarch64" + typedef :u_int8_t, :uint8_t + typedef :u_int16_t, :uint16_t + typedef :u_int32_t, :uint32_t + typedef :u_int64_t, :uint64_t + end + + FieldType = enum( + :double, 1, + :float, + :int64, + :uint64, + :int32, + :fixed64, + :fixed32, + :bool, + :string, + :group, + :message, + :bytes, + :uint32, + :enum, + :sfixed32, + :sfixed64, + :sint32, + :sint64 + ) + + CType = enum( + :bool, 1, + :float, + :int32, + :uint32, + :enum, + :message, + :double, + :int64, + :uint64, + :string, + :bytes + ) + + Label = enum( + :optional, 1, + :required, + :repeated + ) + + # All the different kind of well known type messages. For simplicity of check, + # number wrappers and string wrappers are grouped together. Make sure the + # order and merber of these groups are not changed. + + WellKnown = enum( + :Unspecified, + :Any, + :FieldMask, + :Duration, + :Timestamp, + # number wrappers + :DoubleValue, + :FloatValue, + :Int64Value, + :UInt64Value, + :Int32Value, + :UInt32Value, + # string wrappers + :StringValue, + :BytesValue, + :BoolValue, + :Value, + :ListValue, + :Struct + ) + + DecodeStatus = enum( + :Ok, + :Malformed, # Wire format was corrupt + :OutOfMemory, # Arena alloc failed + :BadUtf8, # String field had bad UTF-8 + :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH + + # CheckRequired failed, but the parse otherwise succeeded. + :MissingRequired, + ) + + EncodeStatus = enum( + :Ok, + :OutOfMemory, # Arena alloc failed + :MaxDepthExceeded, # Exceeded UPB_DECODE_MAXDEPTH + + # CheckRequired failed, but the parse otherwise succeeded. + :MissingRequired, + ) + + class StringView < ::FFI::Struct + layout :data, :pointer, + :size, :size_t + end + + class MiniTable < ::FFI::Struct + layout :fields, :pointer, + :size, :uint16_t, + :field_count, :uint16_t, + :ext, :uint8_t, # upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 + :dense_below, :uint8_t, + :table_mask, :uint8_t, + :required_count, :uint8_t # Required fields have the lowest hasbits. + # To statically initialize the tables of variable length, we need a flexible + # array member, and we need to compile in gnu99 mode (constant initialization + # of flexible array members is a GNU extension, not in C99 unfortunately. */ + # _upb_FastTable_Entry fasttable[]; + end + + class Status < ::FFI::Struct + layout :ok, :bool, + :msg, [:char, Upb_Status_MaxMessage] + + def initialize + super + FFI.clear self + end + end + + class MessageValue < ::FFI::Union + layout :bool_val, :bool, + :float_val, :float, + :double_val, :double, + :int32_val, :int32_t, + :int64_val, :int64_t, + :uint32_val, :uint32_t, + :uint64_val,:uint64_t, + :map_val, :pointer, + :msg_val, :pointer, + :array_val,:pointer, + :str_val, StringView + end + + Upb_Message_Begin = -1 + + class MutableMessageValue < ::FFI::Union + layout :map, :Map, + :msg, :Message, + :array, :Array + end + + # Status + attach_function :clear, :upb_Status_Clear, [Status.by_ref], :void + attach_function :error_message, :upb_Status_ErrorMessage, [Status.by_ref], :string + + # Generic + attach_function :memcmp, [:pointer, :pointer, :size_t], :int + attach_function :memcpy, [:pointer, :pointer, :size_t], :int + + # Alternatives to pre-processor macros + def self.decode_max_depth(i) + i << 16 + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/field_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/field_descriptor.rb new file mode 100755 index 00000000..2ec6d8e2 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/field_descriptor.rb @@ -0,0 +1,346 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FieldDescriptor + attr :field_def, :descriptor_pool + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [FieldDescriptor] FieldDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + field_def_ptr = value.instance_variable_get(:@field_def) + warn "Underlying field_def was nil!" if field_def_ptr.nil? + raise "Underlying field_def was null!" if !field_def_ptr.nil? and field_def_ptr.null? + field_def_ptr + end + + ## + # @param field_def [::FFI::Pointer] FieldDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(field_def, _ = nil) + return nil if field_def.nil? or field_def.null? + file_def = Google::Protobuf::FFI.file_def_by_raw_field_def(field_def) + descriptor_from_file_def(file_def, field_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_full_name(self) + end + + def json_name + @json_name ||= Google::Protobuf::FFI.get_json_name(self) + end + + def number + @number ||= Google::Protobuf::FFI.get_number(self) + end + + def type + @type ||= Google::Protobuf::FFI.get_type(self) + end + + # DEPRECATED: Use required? or repeated? instead. + def label + @label ||= Google::Protobuf::FFI.get_label(self) + end + + def default + return nil if Google::Protobuf::FFI.is_sub_message(self) + if Google::Protobuf::FFI.is_repeated(self) + message_value = Google::Protobuf::FFI::MessageValue.new + else + message_value = Google::Protobuf::FFI.get_default(self) + end + enum_def = Google::Protobuf::FFI.get_subtype_as_enum(self) + if enum_def.null? + convert_upb_to_ruby message_value, c_type + else + convert_upb_to_ruby message_value, c_type, enum_def + end + end + + def submsg_name + if defined? @submsg_name + @submsg_name + else + @submsg_name = case c_type + when :enum + Google::Protobuf::FFI.get_enum_fullname Google::Protobuf::FFI.get_subtype_as_enum self + when :message + Google::Protobuf::FFI.get_message_fullname Google::Protobuf::FFI.get_subtype_as_message self + else + nil + end + end + end + + ## + # Tests if this field has been set on the argument message. + # + # @param msg [Google::Protobuf::Message] + # @return [Object] Value of the field on this message. + # @raise [TypeError] If the field is not defined on this message. + def get(msg) + if msg.class.descriptor == Google::Protobuf::FFI.get_containing_message_def(self) + msg.send :get_field, self + else + raise TypeError.new "get method called on wrong message type" + end + end + + def subtype + if defined? @subtype + @subtype + else + @subtype = case c_type + when :enum + Google::Protobuf::FFI.get_subtype_as_enum(self) + when :message + Google::Protobuf::FFI.get_subtype_as_message(self) + else + nil + end + end + end + + ## + # Tests if this field has been set on the argument message. + # + # @param msg [Google::Protobuf::Message] + # @return [Boolean] True iff message has this field set + # @raise [TypeError] If this field does not exist on the message + # @raise [ArgumentError] If this field does not track presence + def has?(msg) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "has method called on wrong message type" + end + unless has_presence? + raise ArgumentError.new "does not track presence" + end + + Google::Protobuf::FFI.get_message_has msg.instance_variable_get(:@msg), self + end + + ## + # Tests if this field tracks presence. + # + # @return [Boolean] True iff this field tracks presence + def has_presence? + @has_presence ||= Google::Protobuf::FFI.get_has_presence(self) + end + + ## + # Tests if this is a repeated field that uses packed encoding. + # + # @return [Boolean] True iff this field is packed + def is_packed? + @is_packed ||= Google::Protobuf::FFI.get_is_packed(self) + end + + # @param msg [Google::Protobuf::Message] + def clear(msg) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "clear method called on wrong message type" + end + Google::Protobuf::FFI.clear_message_field msg.instance_variable_get(:@msg), self + nil + end + + ## + # call-seq: + # FieldDescriptor.set(message, value) + # + # Sets the value corresponding to this field to the given value on the given + # message. Raises an exception if message is of the wrong type. Performs the + # ordinary type-checks for field setting. + # + # @param msg [Google::Protobuf::Message] + # @param value [Object] + def set(msg, value) + if msg.class.descriptor != Google::Protobuf::FFI.get_containing_message_def(self) + raise TypeError.new "set method called on wrong message type" + end + unless set_value_on_message value, msg.instance_variable_get(:@msg), msg.instance_variable_get(:@arena) + raise RuntimeError.new "allocation failed" + end + nil + end + + def map? + @map ||= Google::Protobuf::FFI.is_map self + end + + def required? + @required ||= Google::Protobuf::FFI.is_required self + end + + def repeated? + @repeated ||= Google::Protobuf::FFI.is_repeated self + end + + def sub_message? + @sub_message ||= Google::Protobuf::FFI.is_sub_message self + end + + def wrapper? + if defined? @wrapper + @wrapper + else + message_descriptor = Google::Protobuf::FFI.get_subtype_as_message(self) + @wrapper = message_descriptor.nil? ? false : message_descriptor.send(:wrapper?) + end + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.field_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::FieldOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.field_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::FieldDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + def initialize(field_def, descriptor_pool) + @field_def = field_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(field_def, descriptor_pool) + instance = allocate + instance.send(:initialize, field_def, descriptor_pool) + instance + end + + # TODO Can this be added to the public API? + def real_containing_oneof + @real_containing_oneof ||= Google::Protobuf::FFI.real_containing_oneof self + end + + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + ## + # Sets the field this FieldDescriptor represents to the given value on the given message. + # @param value [Object] Value to be set + # @param msg [::FFI::Pointer] Pointer the the upb_Message + # @param arena [Arena] Arena of the message that owns msg + def set_value_on_message(value, msg, arena, wrap: false) + message_to_alter = msg + field_def_to_set = self + if map? + raise TypeError.new "Expected map" unless value.is_a? Google::Protobuf::Map + message_descriptor = subtype + + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + raise TypeError.new "Map key type does not match field's key type" unless key_field_type == value.send(:key_type) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + raise TypeError.new "Map value type does not match field's value type" unless value_field_type == value.send(:value_type) + + raise TypeError.new "Map value type has wrong message/enum class" unless value_field_def.subtype == value.send(:descriptor) + + arena.fuse(value.send(:arena)) + message_value = Google::Protobuf::FFI::MessageValue.new + message_value[:map_val] = value.send(:map_ptr) + elsif repeated? + raise TypeError.new "Expected repeated field array" unless value.is_a? RepeatedField + raise TypeError.new "Repeated field array has wrong message/enum class" unless value.send(:type) == type + arena.fuse(value.send(:arena)) + message_value = Google::Protobuf::FFI::MessageValue.new + message_value[:array_val] = value.send(:array) + else + if value.nil? and (sub_message? or !real_containing_oneof.nil?) + Google::Protobuf::FFI.clear_message_field message_to_alter, field_def_to_set + return true + end + if wrap + value_field_def = Google::Protobuf::FFI.get_field_by_number subtype, 1 + type_for_conversion = Google::Protobuf::FFI.get_c_type(value_field_def) + raise RuntimeError.new "Not expecting to get a msg or enum when unwrapping" if [:enum, :message].include? type_for_conversion + message_value = convert_ruby_to_upb(value, arena, type_for_conversion, nil) + message_to_alter = Google::Protobuf::FFI.get_mutable_message(msg, self, arena)[:msg] + field_def_to_set = value_field_def + else + message_value = convert_ruby_to_upb(value, arena, c_type, subtype) + end + end + Google::Protobuf::FFI.set_message_field message_to_alter, field_def_to_set, message_value, arena + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # MessageDef + attach_function :get_field_by_index, :upb_MessageDef_Field, [Descriptor, :int], FieldDescriptor + attach_function :get_field_by_name, :upb_MessageDef_FindFieldByNameWithSize,[Descriptor, :string, :size_t], FieldDescriptor + attach_function :get_field_by_number, :upb_MessageDef_FindFieldByNumber, [Descriptor, :uint32_t], FieldDescriptor + + # FieldDescriptor + attach_function :field_options, :FieldDescriptor_serialized_options, [FieldDescriptor, :pointer, Internal::Arena], :pointer + attach_function :get_containing_message_def, :upb_FieldDef_ContainingType, [FieldDescriptor], Descriptor + attach_function :get_c_type, :upb_FieldDef_CType, [FieldDescriptor], CType + attach_function :get_default, :upb_FieldDef_Default, [FieldDescriptor], MessageValue.by_value + attach_function :get_subtype_as_enum, :upb_FieldDef_EnumSubDef, [FieldDescriptor], EnumDescriptor + attach_function :get_has_presence, :upb_FieldDef_HasPresence, [FieldDescriptor], :bool + attach_function :get_is_packed, :upb_FieldDef_IsPacked, [FieldDescriptor], :bool + attach_function :is_map, :upb_FieldDef_IsMap, [FieldDescriptor], :bool + attach_function :is_required, :upb_FieldDef_IsRequired, [FieldDescriptor], :bool + attach_function :is_repeated, :upb_FieldDef_IsRepeated, [FieldDescriptor], :bool + attach_function :is_sub_message, :upb_FieldDef_IsSubMessage, [FieldDescriptor], :bool + attach_function :get_json_name, :upb_FieldDef_JsonName, [FieldDescriptor], :string + attach_function :get_label, :upb_FieldDef_Label, [FieldDescriptor], Label + attach_function :get_subtype_as_message, :upb_FieldDef_MessageSubDef, [FieldDescriptor], Descriptor + attach_function :get_full_name, :upb_FieldDef_Name, [FieldDescriptor], :string + attach_function :get_number, :upb_FieldDef_Number, [FieldDescriptor], :uint32_t + attach_function :get_type, :upb_FieldDef_Type, [FieldDescriptor], FieldType + attach_function :file_def_by_raw_field_def, :upb_FieldDef_File, [:pointer], :FileDef + attach_function :field_to_proto, :FieldDescriptor_serialized_to_proto,[FieldDescriptor, :pointer, Internal::Arena], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/file_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/file_descriptor.rb new file mode 100755 index 00000000..72e6a0c7 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/file_descriptor.rb @@ -0,0 +1,85 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # FileDescriptor + attach_function :file_def_name, :upb_FileDef_Name, [:FileDef], :string + attach_function :file_def_pool, :upb_FileDef_Pool, [:FileDef], :DefPool + attach_function :file_options, :FileDescriptor_serialized_options, [:FileDef, :pointer, Internal::Arena], :pointer + attach_function :file_to_proto, :FileDescriptor_serialized_to_proto, [:FileDef, :pointer, Internal::Arena], :pointer + end + + class FileDescriptor + attr :descriptor_pool, :file_def + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [FileDescriptor] FileDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + file_def_ptr = value.nil? ? nil : value.instance_variable_get(:@file_def) + return ::FFI::Pointer::NULL if file_def_ptr.nil? + raise "Underlying file_def was null!" if file_def_ptr.null? + file_def_ptr + end + + ## + # @param file_def [::FFI::Pointer] FileDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(file_def, _ = nil) + return nil if file_def.nil? or file_def.null? + descriptor_from_file_def(file_def) + end + end + + def initialize(file_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @file_def = file_def + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + Google::Protobuf::FFI.file_def_name(@file_def) + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.file_options(@file_def, size_ptr, temporary_arena) + opts = Google::Protobuf::FileOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.file_to_proto(@file_def, size_ptr, temporary_arena) + Google::Protobuf::FileDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/arena.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/arena.rb new file mode 100755 index 00000000..da3b2c42 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/arena.rb @@ -0,0 +1,60 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +## +# Implementation details below are subject to breaking changes without +# warning and are intended for use only within the gem. +module Google + module Protobuf + module Internal + class Arena + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + + # @param value [Arena] Arena to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + value.instance_variable_get(:@arena) || ::FFI::Pointer::NULL + end + + ## + # @param value [::FFI::Pointer] Arena pointer to be wrapped + # @param _ [Object] Unused + def from_native(value, _) + new(value) + end + end + + def initialize(pointer) + @arena = ::FFI::AutoPointer.new(pointer, Google::Protobuf::FFI.method(:free_arena)) + @pinned_messages = [] + end + + def fuse(other_arena) + return if other_arena == self + unless Google::Protobuf::FFI.fuse_arena(self, other_arena) + raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks" + end + end + end + end + + class FFI + # Arena + attach_function :create_arena, :Arena_create, [], Internal::Arena + attach_function :fuse_arena, :upb_Arena_Fuse, [Internal::Arena, Internal::Arena], :bool + # Argument takes a :pointer rather than a typed Arena here due to + # implementation details of FFI::AutoPointer. + attach_function :free_arena, :upb_Arena_Free, [:pointer], :void + attach_function :arena_malloc, :upb_Arena_Malloc, [Internal::Arena, :size_t], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/convert.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/convert.rb new file mode 100755 index 00000000..649b90ad --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/convert.rb @@ -0,0 +1,292 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +## +# Implementation details below are subject to breaking changes without +# warning and are intended for use only within the gem. +module Google + module Protobuf + module Internal + module Convert + + # Arena should be the + # @param value [Object] Value to convert + # @param arena [Arena] Arena that owns the Message where the MessageValue + # will be set + # @return [Google::Protobuf::FFI::MessageValue] + def convert_ruby_to_upb(value, arena, c_type, msg_or_enum_def) + raise ArgumentError.new "Expected Descriptor or EnumDescriptor, instead got #{msg_or_enum_def.class}" unless [NilClass, Descriptor, EnumDescriptor].include? msg_or_enum_def.class + return_value = Google::Protobuf::FFI::MessageValue.new + case c_type + when :float + raise TypeError.new "Expected number type for float field '#{name}' (given #{value.class})." unless value.respond_to? :to_f + return_value[:float_val] = value.to_f + when :double + raise TypeError.new "Expected number type for double field '#{name}' (given #{value.class})." unless value.respond_to? :to_f + return_value[:double_val] = value.to_f + when :bool + raise TypeError.new "Invalid argument for boolean field '#{name}' (given #{value.class})." unless [TrueClass, FalseClass].include? value.class + return_value[:bool_val] = value + when :string + raise TypeError.new "Invalid argument for string field '#{name}' (given #{value.class})." unless value.is_a?(String) or value.is_a?(Symbol) + value = value.to_s if value.is_a?(Symbol) + if value.encoding == Encoding::UTF_8 + unless value.valid_encoding? + raise Encoding::InvalidByteSequenceError.new "String is invalid UTF-8" + end + string_value = value + else + string_value = value.to_s.encode("UTF-8") + end + return_value[:str_val][:size] = string_value.bytesize + return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize) + # TODO - how important is it to still use arena malloc, versus the following? + # buffer = ::FFI::MemoryPointer.new(:char, string_value.bytesize) + # buffer.put_bytes(0, string_value) + # return_value[:str_val][:data] = buffer + raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for string on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null? + return_value[:str_val][:data].write_string(string_value) + when :bytes + raise TypeError.new "Invalid argument for bytes field '#{name}' (given #{value.class})." unless value.is_a? String + string_value = value.encode("ASCII-8BIT") + return_value[:str_val][:size] = string_value.bytesize + return_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, string_value.bytesize) + raise NoMemoryError.new "Cannot allocate #{string_value.bytesize} bytes for bytes on Arena" if return_value[:str_val][:data].nil? || return_value[:str_val][:data].null? + return_value[:str_val][:data].write_string_length(string_value, string_value.bytesize) + when :message + raise TypeError.new "nil message not allowed here." if value.nil? + if value.is_a? Hash + raise RuntimeError.new "Attempted to initialize message from Hash for field #{name} but have no definition" if msg_or_enum_def.nil? + new_message = msg_or_enum_def.msgclass. + send(:private_constructor, arena, initial_value: value) + return_value[:msg_val] = new_message.instance_variable_get(:@msg) + return return_value + end + + descriptor = value.class.respond_to?(:descriptor) ? value.class.descriptor : nil + if descriptor != msg_or_enum_def + wkt = Google::Protobuf::FFI.get_well_known_type(msg_or_enum_def) + case wkt + when :Timestamp + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Time + new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena + sec = Google::Protobuf::FFI::MessageValue.new + sec[:int64_val] = value.tv_sec + sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1 + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena + nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2 + nsec = Google::Protobuf::FFI::MessageValue.new + nsec[:int32_val] = value.tv_nsec + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena + return_value[:msg_val] = new_message + when :Duration + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." unless value.kind_of? Numeric + new_message = Google::Protobuf::FFI.new_message_from_def Google::Protobuf::FFI.get_mini_table(msg_or_enum_def), arena + sec = Google::Protobuf::FFI::MessageValue.new + sec[:int64_val] = value + sec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 1 + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, sec_field_def, sec, arena + nsec_field_def = Google::Protobuf::FFI.get_field_by_number msg_or_enum_def, 2 + nsec = Google::Protobuf::FFI::MessageValue.new + nsec[:int32_val] = ((value.to_f - value.to_i) * 1000000000).round + raise "Should be impossible" unless Google::Protobuf::FFI.set_message_field new_message, nsec_field_def, nsec, arena + return_value[:msg_val] = new_message + else + raise TypeError.new "Invalid type #{value.class} to assign to submessage field '#{name}'." + end + else + arena.fuse(value.instance_variable_get(:@arena)) + return_value[:msg_val] = value.instance_variable_get :@msg + end + when :enum + return_value[:int32_val] = case value + when Numeric + value.to_i + when String, Symbol + enum_number = EnumDescriptor.send(:lookup_name, msg_or_enum_def, value.to_s) + #TODO add the bad value to the error message after tests pass + raise RangeError.new "Unknown symbol value for enum field '#{name}'." if enum_number.nil? + enum_number + else + raise TypeError.new "Expected number or symbol type for enum field '#{name}'." + end + #TODO After all tests pass, improve error message across integer type by including actual offending value + when :int32 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Value assigned to int32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 32 + return_value[:int32_val] = value.to_i + when :uint32 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0 + raise RangeError.new "Value assigned to uint32 field '#{name}' (given #{value.class}) with more than 32-bits." unless value.to_i.bit_length < 33 + return_value[:uint32_val] = value.to_i + when :int64 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Value assigned to int64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 64 + return_value[:int64_val] = value.to_i + when :uint64 + raise TypeError.new "Expected number type for integral field '#{name}' (given #{value.class})." unless value.is_a? Numeric + raise RangeError.new "Non-integral floating point value assigned to integer field '#{name}' (given #{value.class})." if value.floor != value + raise RangeError.new "Assigning negative value to unsigned integer field '#{name}' (given #{value.class})." if value < 0 + raise RangeError.new "Value assigned to uint64 field '#{name}' (given #{value.class}) with more than 64-bits." unless value.to_i.bit_length < 65 + return_value[:uint64_val] = value.to_i + else + raise RuntimeError.new "Unsupported type #{c_type}" + end + return_value + end + + ## + # Safe to call without an arena if the caller has checked that c_type + # is not :message. + # @param message_value [Google::Protobuf::FFI::MessageValue] Value to be converted. + # @param c_type [Google::Protobuf::FFI::CType] Enum representing the type of message_value + # @param msg_or_enum_def [::FFI::Pointer] Pointer to the MsgDef or EnumDef definition + # @param arena [Google::Protobuf::Internal::Arena] Arena to create Message instances, if needed + def convert_upb_to_ruby(message_value, c_type, msg_or_enum_def = nil, arena = nil) + throw TypeError.new "Expected MessageValue but got #{message_value.class}" unless message_value.is_a? Google::Protobuf::FFI::MessageValue + + case c_type + when :bool + message_value[:bool_val] + when :int32 + message_value[:int32_val] + when :uint32 + message_value[:uint32_val] + when :double + message_value[:double_val] + when :int64 + message_value[:int64_val] + when :uint64 + message_value[:uint64_val] + when :string + if message_value[:str_val][:size].zero? + "" + else + message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("UTF-8").freeze + end + when :bytes + if message_value[:str_val][:size].zero? + "" + else + message_value[:str_val][:data].read_string_length(message_value[:str_val][:size]).force_encoding("ASCII-8BIT").freeze + end + when :float + message_value[:float_val] + when :enum + EnumDescriptor.send(:lookup_value, msg_or_enum_def, message_value[:int32_val]) || message_value[:int32_val] + when :message + raise "Null Arena for message" if arena.nil? + Descriptor.send(:get_message, message_value[:msg_val], msg_or_enum_def, arena) + else + raise RuntimeError.new "Unexpected type #{c_type}" + end + end + + def to_h_internal(msg, message_descriptor) + return nil if msg.nil? or msg.null? + hash = {} + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Message_Begin) + message_value = Google::Protobuf::FFI::MessageValue.new + field_def_ptr = ::FFI::MemoryPointer.new :pointer + + while Google::Protobuf::FFI::message_next(msg, message_descriptor, nil, field_def_ptr, message_value, iter) do + field_descriptor = FieldDescriptor.from_native field_def_ptr.get_pointer(0) + + if field_descriptor.map? + hash_entry = map_create_hash(message_value[:map_val], field_descriptor) + elsif field_descriptor.repeated? + hash_entry = repeated_field_create_array(message_value[:array_val], field_descriptor, field_descriptor.type) + else + hash_entry = scalar_create_hash(message_value, field_descriptor.type, field_descriptor: field_descriptor) + end + + hash[field_descriptor.name.to_sym] = hash_entry + end + + hash + end + + def map_create_hash(map_ptr, field_descriptor) + return {} if map_ptr.nil? or map_ptr.null? + return_value = {} + + message_descriptor = field_descriptor.send(:subtype) + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + while Google::Protobuf::FFI.map_next(map_ptr, iter) do + iter_size_t = iter.read(:size_t) + key_message_value = Google::Protobuf::FFI.map_key(map_ptr, iter_size_t) + value_message_value = Google::Protobuf::FFI.map_value(map_ptr, iter_size_t) + hash_key = convert_upb_to_ruby(key_message_value, key_field_type) + hash_value = scalar_create_hash(value_message_value, value_field_type, msg_or_enum_descriptor: value_field_def.subtype) + return_value[hash_key] = hash_value + end + return_value + end + + def repeated_field_create_array(array, field_descriptor, type) + return_value = [] + n = (array.nil? || array.null?) ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n - 1) do |i| + message_value = Google::Protobuf::FFI.get_msgval_at(array, i) + return_value << scalar_create_hash(message_value, type, field_descriptor: field_descriptor) + end + return_value + end + + # @param field_descriptor [FieldDescriptor] Descriptor of the field to convert to a hash. + def scalar_create_hash(message_value, type, field_descriptor: nil, msg_or_enum_descriptor: nil) + if [:message, :enum].include? type + if field_descriptor.nil? + if msg_or_enum_descriptor.nil? + raise "scalar_create_hash requires either a FieldDescriptor, MessageDescriptor, or EnumDescriptor as an argument, but received only nil" + end + else + msg_or_enum_descriptor = field_descriptor.subtype + end + if type == :message + to_h_internal(message_value[:msg_val], msg_or_enum_descriptor) + elsif type == :enum + convert_upb_to_ruby message_value, type, msg_or_enum_descriptor + end + else + convert_upb_to_ruby message_value, type + end + end + + def message_value_deep_copy(message_value, type, descriptor, arena) + raise unless message_value.is_a? Google::Protobuf::FFI::MessageValue + new_message_value = Google::Protobuf::FFI::MessageValue.new + case type + when :string, :bytes + # TODO - how important is it to still use arena malloc, versus using FFI MemoryPointers? + new_message_value[:str_val][:size] = message_value[:str_val][:size] + new_message_value[:str_val][:data] = Google::Protobuf::FFI.arena_malloc(arena, message_value[:str_val][:size]) + raise NoMemoryError.new "Allocation failed" if new_message_value[:str_val][:data].nil? or new_message_value[:str_val][:data].null? + Google::Protobuf::FFI.memcpy(new_message_value[:str_val][:data], message_value[:str_val][:data], message_value[:str_val][:size]) + when :message + new_message_value[:msg_val] = descriptor.msgclass.send(:deep_copy, message_value[:msg_val], arena).instance_variable_get(:@msg) + else + Google::Protobuf::FFI.memcpy(new_message_value.to_ptr, message_value.to_ptr, Google::Protobuf::FFI::MessageValue.size) + end + new_message_value + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/pointer_helper.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/pointer_helper.rb new file mode 100755 index 00000000..fdf4df37 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/pointer_helper.rb @@ -0,0 +1,36 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module Internal + module PointerHelper + # Utility code to defensively walk the object graph from a file_def to + # the pool, and either retrieve the wrapper object for the given pointer + # or create one. Assumes that the caller is the wrapper class for the + # given pointer and that it implements `private_constructor`. + def descriptor_from_file_def(file_def, pointer = nil) + pointer = file_def if pointer.nil? + raise RuntimeError.new "FileDef is nil" if file_def.nil? + raise RuntimeError.new "FileDef is null" if file_def.null? + pool_def = Google::Protobuf::FFI.file_def_pool file_def + raise RuntimeError.new "PoolDef is nil" if pool_def.nil? + raise RuntimeError.new "PoolDef is null" if pool_def.null? + pool = Google::Protobuf::OBJECT_CACHE.get(pool_def.address) + raise "Cannot find pool in ObjectCache!" if pool.nil? + descriptor = pool.descriptor_class_by_def[pointer.address] + if descriptor.nil? + pool.descriptor_class_by_def[pointer.address] = private_constructor(pointer, pool) + else + descriptor + end + end + end + end + end +end + diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/type_safety.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/type_safety.rb new file mode 100755 index 00000000..6cdb3e99 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/internal/type_safety.rb @@ -0,0 +1,25 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# A to_native DataConverter method that raises an error if the value is not of the same type. +# Adapted from to https://www.varvet.com/blog/advanced-topics-in-ruby-ffi/ +module Google + module Protobuf + module Internal + module TypeSafety + def to_native(value, ctx = nil) + if value.kind_of?(self) or value.nil? + super + else + raise TypeError.new "Expected a kind of #{name}, was #{value.class}" + end + end + end + end + end +end + diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/map.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/map.rb new file mode 100755 index 00000000..fc806094 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/map.rb @@ -0,0 +1,433 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class FFI + # Map + attach_function :map_clear, :upb_Map_Clear, [:Map], :void + attach_function :map_delete, :upb_Map_Delete, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool + attach_function :map_get, :upb_Map_Get, [:Map, MessageValue.by_value, MessageValue.by_ref], :bool + attach_function :create_map, :upb_Map_New, [Internal::Arena, CType, CType], :Map + attach_function :map_size, :upb_Map_Size, [:Map], :size_t + attach_function :map_set, :upb_Map_Set, [:Map, MessageValue.by_value, MessageValue.by_value, Internal::Arena], :bool + attach_function :map_freeze, :upb_Map_Freeze, [:Map, MiniTable.by_ref], :void + attach_function :map_frozen?, :upb_Map_IsFrozen, [:Map], :bool + + # MapIterator + attach_function :map_next, :upb_MapIterator_Next, [:Map, :pointer], :bool + attach_function :map_done, :upb_MapIterator_Done, [:Map, :size_t], :bool + attach_function :map_key, :upb_MapIterator_Key, [:Map, :size_t], MessageValue.by_value + attach_function :map_value, :upb_MapIterator_Value, [:Map, :size_t], MessageValue.by_value + end + class Map + include Enumerable + ## + # call-seq: + # Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + # => new map + # + # Allocates a new Map container. This constructor may be called with 2, 3, or 4 + # arguments. The first two arguments are always present and are symbols (taking + # on the same values as field-type symbols in message descriptors) that + # indicate the type of the map key and value fields. + # + # The supported key types are: :int32, :int64, :uint32, :uint64, :bool, + # :string, :bytes. + # + # The supported value types are: :int32, :int64, :uint32, :uint64, :bool, + # :string, :bytes, :enum, :message. + # + # The third argument, value_typeclass, must be present if value_type is :enum + # or :message. As in RepeatedField#new, this argument must be a message class + # (for :message) or enum module (for :enum). + # + # The last argument, if present, provides initial content for map. Note that + # this may be an ordinary Ruby hashmap or another Map instance with identical + # key and value types. Also note that this argument may be present whether or + # not value_typeclass is present (and it is unambiguously separate from + # value_typeclass because value_typeclass's presence is strictly determined by + # value_type). The contents of this initial hashmap or Map instance are + # shallow-copied into the new Map: the original map is unmodified, but + # references to underlying objects will be shared if the value type is a + # message type. + def self.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + instance = allocate + # TODO This argument mangling doesn't agree with the type signature, + # but does align with the text of the comments and is required to make unit tests pass. + if init_hashmap.empty? and ![:enum, :message].include?(value_type) + init_hashmap = value_typeclass + value_typeclass = nil + end + instance.send(:initialize, key_type, value_type, value_type_class: value_typeclass, initial_values: init_hashmap) + instance + end + + ## + # call-seq: + # Map.keys => [list_of_keys] + # + # Returns the list of keys contained in the map, in unspecified order. + def keys + return_value = [] + internal_iterator do |iterator| + key_message_value = Google::Protobuf::FFI.map_key(@map_ptr, iterator) + return_value << convert_upb_to_ruby(key_message_value, key_type) + end + return_value + end + + ## + # call-seq: + # Map.values => [list_of_values] + # + # Returns the list of values contained in the map, in unspecified order. + def values + return_value = [] + internal_iterator do |iterator| + value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator) + return_value << convert_upb_to_ruby(value_message_value, value_type, descriptor, arena) + end + return_value + end + + ## + # call-seq: + # Map.[](key) => value + # + # Accesses the element at the given key. Throws an exception if the key type is + # incorrect. Returns nil when the key is not present in the map. + def [](key) + value = Google::Protobuf::FFI::MessageValue.new + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + if Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, value) + convert_upb_to_ruby(value, value_type, descriptor, arena) + end + end + + ## + # call-seq: + # Map.[]=(key, value) => value + # + # Inserts or overwrites the value at the given key with the given new value. + # Throws an exception if the key type is incorrect. Returns the new value that + # was just inserted. + def []=(key, value) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + value_message_value = convert_ruby_to_upb(value, arena, value_type, descriptor) + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + value + end + + def has_key?(key) + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, nil) + end + + ## + # call-seq: + # Map.delete(key) => old_value + # + # Deletes the value at the given key, if any, returning either the old value or + # nil if none was present. Throws an exception if the key is of the wrong type. + def delete(key) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + value = Google::Protobuf::FFI::MessageValue.new + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + if Google::Protobuf::FFI.map_delete(@map_ptr, key_message_value, value) + convert_upb_to_ruby(value, value_type, descriptor, arena) + else + nil + end + end + + def clear + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + Google::Protobuf::FFI.map_clear(@map_ptr) + nil + end + + def length + Google::Protobuf::FFI.map_size(@map_ptr) + end + alias size length + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.map_frozen? @map_ptr + raise RuntimeError.new "Ruby frozen Map with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the map object. We have to intercept this so we can freeze the + # underlying representation, not just the Ruby wrapper. Returns self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.map_frozen? @map_ptr + raise RuntimeError.new "Underlying representation of map still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.map_frozen? @map_ptr + mini_table = (value_type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil + Google::Protobuf::FFI.map_freeze(@map_ptr, mini_table) + end + super + end + + ## + # call-seq: + # Map.dup => new_map + # + # Duplicates this map with a shallow copy. References to all non-primitive + # element objects (e.g., submessages) are shared. + def dup + internal_dup + end + alias clone dup + + ## + # call-seq: + # Map.==(other) => boolean + # + # Compares this map to another. Maps are equal if they have identical key sets, + # and for each key, the values in both maps compare equal. Elements are + # compared as per normal Ruby semantics, by calling their :== methods (or + # performing a more efficient comparison for primitive types). + # + # Maps with dissimilar key types or value types/typeclasses are never equal, + # even if value comparison (for example, between integers and floats) would + # have otherwise indicated that every element has equal value. + def ==(other) + if other.is_a? Hash + other = self.class.send(:private_constructor, key_type, value_type, descriptor, initial_values: other) + elsif !other.is_a? Google::Protobuf::Map + return false + end + + return true if object_id == other.object_id + return false if key_type != other.send(:key_type) or value_type != other.send(:value_type) or descriptor != other.send(:descriptor) or length != other.length + other_map_ptr = other.send(:map_ptr) + each_msg_val do |key_message_value, value_message_value| + other_value = Google::Protobuf::FFI::MessageValue.new + return false unless Google::Protobuf::FFI.map_get(other_map_ptr, key_message_value, other_value) + return false unless Google::Protobuf::FFI.message_value_equal(value_message_value, other_value, value_type, descriptor) + end + true + end + + def hash + return_value = 0 + each_msg_val do |key_message_value, value_message_value| + return_value += Google::Protobuf::FFI.message_value_hash(key_message_value, key_type, nil, 0) + return_value += Google::Protobuf::FFI.message_value_hash(value_message_value, value_type, descriptor, 0) + end + return_value + end + + ## + # call-seq: + # Map.to_h => {} + # + # Returns a Ruby Hash object containing all the values within the map + def to_h + return {} if map_ptr.nil? or map_ptr.null? + return_value = {} + each_msg_val do |key_message_value, value_message_value| + hash_key = convert_upb_to_ruby(key_message_value, key_type) + hash_value = scalar_create_hash(value_message_value, value_type, msg_or_enum_descriptor: descriptor) + return_value[hash_key] = hash_value + end + return_value + end + + def inspect + key_value_pairs = [] + each_msg_val do |key_message_value, value_message_value| + key_string = convert_upb_to_ruby(key_message_value, key_type).inspect + if value_type == :message + sub_msg_descriptor = Google::Protobuf::FFI.get_subtype_as_message(descriptor) + value_string = sub_msg_descriptor.msgclass.send(:inspect_internal, value_message_value[:msg_val]) + else + value_string = convert_upb_to_ruby(value_message_value, value_type, descriptor).inspect + end + key_value_pairs << "#{key_string}=>#{value_string}" + end + "{#{key_value_pairs.join(", ")}}" + end + + ## + # call-seq: + # Map.merge(other_map) => map + # + # Copies key/value pairs from other_map into a copy of this map. If a key is + # set in other_map and this map, the value from other_map overwrites the value + # in the new copy of this map. Returns the new copy of this map with merged + # contents. + def merge(other) + internal_merge(other) + end + + ## + # call-seq: + # Map.each(&block) + # + # Invokes &block on each |key, value| pair in the map, in unspecified order. + # Note that Map also includes Enumerable; map thus acts like a normal Ruby + # sequence. + def each &block + each_msg_val do |key_message_value, value_message_value| + key_value = convert_upb_to_ruby(key_message_value, key_type) + value_value = convert_upb_to_ruby(value_message_value, value_type, descriptor, arena) + yield key_value, value_value + end + nil + end + + private + attr :arena, :map_ptr, :key_type, :value_type, :descriptor, :name + + include Google::Protobuf::Internal::Convert + + def internal_iterator + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + while Google::Protobuf::FFI.map_next(@map_ptr, iter) do + iter_size_t = iter.read(:size_t) + yield iter_size_t + end + end + + def each_msg_val &block + internal_iterator do |iterator| + key_message_value = Google::Protobuf::FFI.map_key(@map_ptr, iterator) + value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator) + yield key_message_value, value_message_value + end + end + + def internal_dup + instance = self.class.send(:private_constructor, key_type, value_type, descriptor, arena: arena) + new_map_ptr = instance.send(:map_ptr) + each_msg_val do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(new_map_ptr, key_message_value, value_message_value, arena) + end + instance + end + + def internal_merge_into_self(other) + case other + when Hash + other.each do |key, value| + key_message_value = convert_ruby_to_upb(key, arena, key_type, nil) + value_message_value = convert_ruby_to_upb(value, arena, value_type, descriptor) + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + end + when Google::Protobuf::Map + unless key_type == other.send(:key_type) and value_type == other.send(:value_type) and descriptor == other.descriptor + raise ArgumentError.new "Attempt to merge Map with mismatching types" #TODO Improve error message by adding type information + end + arena.fuse(other.send(:arena)) + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + other.send(:each_msg_val) do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena) + end + else + raise ArgumentError.new "Unknown type merging into Map" #TODO improve this error message by including type information + end + self + end + + def internal_merge(other) + internal_dup.internal_merge_into_self(other) + end + + def initialize(key_type, value_type, value_type_class: nil, initial_values: nil, arena: nil, map: nil, descriptor: nil, name: nil) + @name = name || 'Map' + + unless [:int32, :int64, :uint32, :uint64, :bool, :string, :bytes].include? key_type + raise ArgumentError.new "Invalid key type for map." #TODO improve error message to include what type was passed + end + @key_type = key_type + + unless [:int32, :int64, :uint32, :uint64, :bool, :string, :bytes, :enum, :message].include? value_type + raise ArgumentError.new "Invalid value type for map." #TODO improve error message to include what type was passed + end + @value_type = value_type + + if !descriptor.nil? + raise ArgumentError "Expected descriptor to be a Descriptor or EnumDescriptor" unless [EnumDescriptor, Descriptor].include? descriptor.class + @descriptor = descriptor + elsif [:message, :enum].include? value_type + raise ArgumentError.new "Expected at least 3 arguments for message/enum." if value_type_class.nil? + descriptor = value_type_class.respond_to?(:descriptor) ? value_type_class.descriptor : nil + raise ArgumentError.new "Type class #{value_type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil? + @descriptor = descriptor + else + @descriptor = nil + end + + @arena = arena || Google::Protobuf::FFI.create_arena + @map_ptr = map || Google::Protobuf::FFI.create_map(@arena, @key_type, @value_type) + + internal_merge_into_self(initial_values) unless initial_values.nil? + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + OBJECT_CACHE.try_add(@map_ptr.address, self) + end + + ## + # Constructor that uses the type information from the given + # FieldDescriptor to configure the new Map instance. + # @param field [FieldDescriptor] Type information for the new Map + # @param arena [Arena] Owning message's arena + # @param value [Hash|Map] Initial value + # @param map [::FFI::Pointer] Existing upb_Map + def self.construct_for_field(field, arena: nil, value: nil, map: nil) + raise ArgumentError.new "Expected Hash object as initializer value for map field '#{field.name}' (given #{value.class})." unless value.nil? or value.is_a? Hash + instance = allocate + raise ArgumentError.new "Expected field with type :message, instead got #{field.class}" unless field.type == :message + message_descriptor = field.send(:subtype) + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + instance.send(:initialize, key_field_type, value_field_type, initial_values: value, name: field.name, arena: arena, map: map, descriptor: value_field_def.subtype) + instance + end + + def self.private_constructor(key_type, value_type, descriptor, initial_values: nil, arena: nil) + instance = allocate + instance.send(:initialize, key_type, value_type, descriptor: descriptor, initial_values: initial_values, arena: arena) + instance + end + + extend Google::Protobuf::Internal::Convert + + def self.deep_copy(map) + instance = allocate + instance.send(:initialize, map.send(:key_type), map.send(:value_type), descriptor: map.send(:descriptor)) + map.send(:each_msg_val) do |key_message_value, value_message_value| + Google::Protobuf::FFI.map_set(instance.send(:map_ptr), key_message_value, message_value_deep_copy(value_message_value, map.send(:value_type), map.send(:descriptor), instance.send(:arena)), instance.send(:arena)) + end + instance + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/message.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/message.rb new file mode 100755 index 00000000..6c703820 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/message.rb @@ -0,0 +1,785 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + + +# Decorates Descriptor with the `build_message_class` method that defines +# Message classes. +module Google + module Protobuf + class FFI + # Message + attach_function :clear_message_field, :upb_Message_ClearFieldByDef, [:Message, FieldDescriptor], :void + attach_function :get_message_value, :upb_Message_GetFieldByDef, [:Message, FieldDescriptor], MessageValue.by_value + attach_function :get_message_has, :upb_Message_HasFieldByDef, [:Message, FieldDescriptor], :bool + attach_function :set_message_field, :upb_Message_SetFieldByDef, [:Message, FieldDescriptor, MessageValue.by_value, Internal::Arena], :bool + attach_function :encode_message, :upb_Encode, [:Message, MiniTable.by_ref, :size_t, Internal::Arena, :pointer, :pointer], EncodeStatus + attach_function :json_decode_message_detecting_nonconformance, :upb_JsonDecodeDetectingNonconformance, [:binary_string, :size_t, :Message, Descriptor, :DefPool, :int, Internal::Arena, Status.by_ref], :int + attach_function :json_encode_message, :upb_JsonEncode, [:Message, Descriptor, :DefPool, :int, :binary_string, :size_t, Status.by_ref], :size_t + attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus + attach_function :get_mutable_message, :upb_Message_Mutable, [:Message, FieldDescriptor, Internal::Arena], MutableMessageValue.by_value + attach_function :get_message_which_oneof, :upb_Message_WhichOneofByDef, [:Message, OneofDescriptor], FieldDescriptor + attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :DefPool, :int], :bool + attach_function :message_next, :upb_Message_Next, [:Message, Descriptor, :DefPool, :FieldDefPointer, MessageValue.by_ref, :pointer], :bool + attach_function :message_freeze, :upb_Message_Freeze, [:Message, MiniTable.by_ref], :void + attach_function :message_frozen?, :upb_Message_IsFrozen, [:Message], :bool + attach_function :message_shallow_copy, :upb_Message_ShallowCopy, [:Message, :Message, MiniTable.by_ref, Internal::Arena], :bool + + # MessageValue + attach_function :message_value_equal, :shared_Msgval_IsEqual, [MessageValue.by_value, MessageValue.by_value, CType, Descriptor], :bool + attach_function :message_value_hash, :shared_Msgval_GetHash, [MessageValue.by_value, CType, Descriptor, :uint64_t], :uint64_t + end + + class Descriptor + def build_message_class + descriptor = self + Class.new(Google::Protobuf::const_get(:AbstractMessage)) do + @descriptor = descriptor + class << self + attr_accessor :descriptor + private + attr_accessor :oneof_field_names + include ::Google::Protobuf::Internal::Convert + end + + alias original_method_missing method_missing + def method_missing(method_name, *args) + method_missing_internal method_name, *args, mode: :method_missing + end + + def respond_to_missing?(method_name, include_private = false) + method_missing_internal(method_name, mode: :respond_to_missing?) || super + end + + ## + # Public constructor. Automatically allocates from a new Arena. + def self.new(initial_value = nil) + instance = allocate + instance.send(:initialize, initial_value) + instance + end + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.message_frozen? @msg + raise RuntimeError.new "Ruby frozen Message with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the map object. We have to intercept this so we can freeze the + # underlying representation, not just the Ruby wrapper. Returns self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.message_frozen? @msg + raise RuntimeError.new "Underlying representation of message still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.message_frozen? @msg + Google::Protobuf::FFI.message_freeze(@msg, Google::Protobuf::FFI.get_mini_table(self.class.descriptor)) + end + super + end + + def dup + mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + new_msg = Google::Protobuf::FFI.new_message_from_def(mini_table, @arena) + unless Google::Protobuf::FFI.message_shallow_copy(new_msg, @msg, mini_table, @arena) + raise RuntimeError.new "Failed to shallow copy message." + end + self.class.private_constructor(@arena, msg: new_msg) + end + alias clone dup + + def eql?(other) + return false unless self.class === other + encoding_options = Google::Protobuf::FFI::Upb_Encode_Deterministic | Google::Protobuf::FFI::Upb_Encode_SkipUnknown + temporary_arena = Google::Protobuf::FFI.create_arena + mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + size_one = ::FFI::MemoryPointer.new(:size_t, 1) + encoding_one = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(@msg, mini_table, encoding_options, temporary_arena, encoding_one.to_ptr, size_one) + raise ParseError.new "Error comparing messages due to #{encoding_status} while encoding LHS of `eql?()`" unless encoding_status == :Ok + + size_two = ::FFI::MemoryPointer.new(:size_t, 1) + encoding_two = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(other.instance_variable_get(:@msg), mini_table, encoding_options, temporary_arena, encoding_two.to_ptr, size_two) + raise ParseError.new "Error comparing messages due to #{encoding_status} while encoding RHS of `eql?()`" unless encoding_status == :Ok + + if encoding_one.null? or encoding_two.null? + raise ParseError.new "Error comparing messages" + end + size_one.read(:size_t) == size_two.read(:size_t) and Google::Protobuf::FFI.memcmp(encoding_one.read(:pointer), encoding_two.read(:pointer), size_one.read(:size_t)).zero? + end + alias == eql? + + def hash + encoding_options = Google::Protobuf::FFI::Upb_Encode_Deterministic | Google::Protobuf::FFI::Upb_Encode_SkipUnknown + temporary_arena = Google::Protobuf::FFI.create_arena + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + encoding = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(@msg, mini_table_ptr, encoding_options, temporary_arena, encoding.to_ptr, size_ptr) + if encoding_status != :Ok or encoding.null? + raise ParseError.new "Error calculating hash" + end + encoding.read(:pointer).read_string(size_ptr.read(:size_t)).hash + end + + def to_h + to_h_internal @msg, self.class.descriptor + end + + ## + # call-seq: + # Message.inspect => string + # + # Returns a human-readable string representing this message. It will be + # formatted as "". Each + # field's value is represented according to its own #inspect method. + def inspect + self.class.inspect_internal @msg + end + + def to_s + self.inspect + end + + ## + # call-seq: + # Message.[](index) => value + # Accesses a field's value by field name. The provided field name + # should be a string. + def [](name) + raise TypeError.new "Expected String for name but got #{name.class}" unless name.is_a? String + index_internal name + end + + ## + # call-seq: + # Message.[]=(index, value) + # Sets a field's value by field name. The provided field name should + # be a string. + # @param name [String] Name of the field to be set + # @param value [Object] Value to set the field to + def []=(name, value) + raise TypeError.new "Expected String for name but got #{name.class}" unless name.is_a? String + index_assign_internal(value, name: name) + end + + ## + # call-seq: + # MessageClass.decode(data, options) => message + # + # Decodes the given data (as a string containing bytes in protocol buffers wire + # format) under the interpretation given by this message class's definition + # and returns a message object with the corresponding field values. + # @param data [String] Binary string in Protobuf wire format to decode + # @param options [Hash] options for the decoder + # @option options [Integer] :recursion_limit Set to maximum decoding depth for message (default is 64) + def self.decode(data, options = {}) + raise ArgumentError.new "Expected hash arguments." unless options.is_a? Hash + raise ArgumentError.new "Expected string for binary protobuf data." unless data.is_a? String + decoding_options = 0 + depth = options[:recursion_limit] + + if depth.is_a? Numeric + decoding_options |= Google::Protobuf::FFI.decode_max_depth(depth.to_i) + end + + message = new + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(message.class.descriptor) + status = Google::Protobuf::FFI.decode_message( + data, + data.bytesize, + message.instance_variable_get(:@msg), + mini_table_ptr, + Google::Protobuf::FFI.get_extension_registry(message.class.descriptor.send(:pool).descriptor_pool), + decoding_options, + message.instance_variable_get(:@arena) + ) + raise ParseError.new "Error occurred during parsing" unless status == :Ok + message + end + + ## + # call-seq: + # MessageClass.encode(msg, options) => bytes + # + # Encodes the given message object to its serialized form in protocol buffers + # wire format. + # @param options [Hash] options for the encoder + # @option options [Integer] :recursion_limit Set to maximum encoding depth for message (default is 64) + def self.encode(message, options = {}) + raise ArgumentError.new "Message of wrong type." unless message.is_a? self + raise ArgumentError.new "Expected hash arguments." unless options.is_a? Hash + + encoding_options = 0 + depth = options[:recursion_limit] + + if depth.is_a? Numeric + encoding_options |= Google::Protobuf::FFI.decode_max_depth(depth.to_i) + end + + encode_internal(message.instance_variable_get(:@msg), encoding_options) do |encoding, size, _| + if encoding.nil? or encoding.null? + raise RuntimeError.new "Exceeded maximum depth (possibly cycle)" + else + encoding.read_string_length(size).force_encoding("ASCII-8BIT").freeze + end + end + end + + ## + # all-seq: + # MessageClass.decode_json(data, options = {}) => message + # + # Decodes the given data (as a string containing bytes in protocol buffers wire + # format) under the interpretation given by this message class's definition + # and returns a message object with the corresponding field values. + # + # @param options [Hash] options for the decoder + # @option options [Boolean] :ignore_unknown_fields Set true to ignore unknown fields (default is to raise an error) + # @return [Message] + def self.decode_json(data, options = {}) + decoding_options = 0 + unless options.is_a? Hash + if options.respond_to? :to_h + options = options.to_h + else + #TODO can this error message be improve to include what was received? + raise ArgumentError.new "Expected hash arguments" + end + end + raise ArgumentError.new "Expected string for JSON data." unless data.is_a? String + raise RuntimeError.new "Cannot parse a wrapper directly" if descriptor.send(:wrapper?) + + if options[:ignore_unknown_fields] + decoding_options |= Google::Protobuf::FFI::Upb_JsonDecode_IgnoreUnknown + end + + message = new + pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool + status = Google::Protobuf::FFI::Status.new + result = Google::Protobuf::FFI.json_decode_message_detecting_nonconformance(data, data.bytesize, message.instance_variable_get(:@msg), message.class.descriptor, pool_def, decoding_options, message.instance_variable_get(:@arena), status) + case result + when Google::Protobuf::FFI::Upb_JsonDecodeResult_Error + raise ParseError.new "Error occurred during parsing: #{Google::Protobuf::FFI.error_message(status)}" + end + message + end + + def self.encode_json(message, options = {}) + encoding_options = 0 + unless options.is_a? Hash + if options.respond_to? :to_h + options = options.to_h + else + #TODO can this error message be improve to include what was received? + raise ArgumentError.new "Expected hash arguments" + end + end + + if options[:preserve_proto_fieldnames] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_UseProtoNames + end + if options[:emit_defaults] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_EmitDefaults + end + if options[:format_enums_as_integers] + encoding_options |= Google::Protobuf::FFI::Upb_JsonEncode_FormatEnumsAsIntegers + end + + buffer_size = 1024 + buffer = ::FFI::MemoryPointer.new(:char, buffer_size) + status = Google::Protobuf::FFI::Status.new + msg = message.instance_variable_get(:@msg) + pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool + size = Google::Protobuf::FFI::json_encode_message(msg, message.class.descriptor, pool_def, encoding_options, buffer, buffer_size, status) + unless status[:ok] + raise ParseError.new "Error occurred during encoding: #{Google::Protobuf::FFI.error_message(status)}" + end + + if size >= buffer_size + buffer_size = size + 1 + buffer = ::FFI::MemoryPointer.new(:char, buffer_size) + status.clear + size = Google::Protobuf::FFI::json_encode_message(msg, message.class.descriptor, pool_def, encoding_options, buffer, buffer_size, status) + unless status[:ok] + raise ParseError.new "Error occurred during encoding: #{Google::Protobuf::FFI.error_message(status)}" + end + if size >= buffer_size + raise ParseError.new "Inconsistent JSON encoding sizes - was #{buffer_size - 1}, now #{size}" + end + end + + buffer.read_string_length(size).force_encoding("UTF-8").freeze + end + + private + # Implementation details below are subject to breaking changes without + # warning and are intended for use only within the gem. + + include Google::Protobuf::Internal::Convert + + ## + # Checks ObjectCache for a sentinel empty frozen Map of the key and + # value types matching the field descriptor's MessageDef and returns + # the cache entry. If an entry is not found, one is created and added + # to the cache keyed by the MessageDef pointer first. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def empty_frozen_map(field_descriptor) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + frozen_map = OBJECT_CACHE.get sub_message_def + if frozen_map.nil? + frozen_map = Google::Protobuf::Map.send(:construct_for_field, field_descriptor) + OBJECT_CACHE.try_add(sub_message_def, frozen_map.freeze) + end + raise "Empty Frozen Map is not frozen" unless frozen_map.frozen? + frozen_map + end + + ## + # Returns a frozen Map instance for the given field. If the message + # already has a value for that field, it is used. If not, a sentinel + # (per FieldDescriptor) empty frozen Map is returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def frozen_map_from_field_descriptor(field_descriptor) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + return empty_frozen_map field_descriptor if message_value[:map_val].null? + get_map_field(message_value[:map_val], field_descriptor).freeze + end + + ## + # Returns a Map instance for the given field. If the message is frozen + # the return value is also frozen. If not, a mutable instance is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def map_from_field_descriptor(field_descriptor) + return frozen_map_from_field_descriptor field_descriptor if frozen? + mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + get_map_field(mutable_message_value[:map], field_descriptor) + end + + ## + # Checks ObjectCache for a sentinel empty frozen RepeatedField of the + # value type matching the field descriptor's MessageDef and returns + # the cache entry. If an entry is not found, one is created and added + # to the cache keyed by the MessageDef pointer first. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def empty_frozen_repeated_field(field_descriptor) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + frozen_repeated_field = OBJECT_CACHE.get sub_message_def + if frozen_repeated_field.nil? + frozen_repeated_field = Google::Protobuf::RepeatedField.send(:construct_for_field, field_descriptor) + OBJECT_CACHE.try_add(sub_message_def, frozen_repeated_field.freeze) + end + raise "Empty frozen RepeatedField is not frozen" unless frozen_repeated_field.frozen? + frozen_repeated_field + end + + ## + # Returns a frozen RepeatedField instance for the given field. If the + # message already has a value for that field, it is used. If not, a + # sentinel (per FieldDescriptor) empty frozen RepeatedField is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def frozen_repeated_field_from_field_descriptor(field_descriptor) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + return empty_frozen_repeated_field field_descriptor if message_value[:array_val].null? + get_repeated_field(message_value[:array_val], field_descriptor).freeze + end + + ## + # Returns a RepeatedField instance for the given field. If the message + # is frozen the return value is also frozen. If not, a mutable + # instance is returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def repeated_field_from_field_descriptor(field_descriptor) + return frozen_repeated_field_from_field_descriptor field_descriptor if frozen? + mutable_message_value = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + get_repeated_field(mutable_message_value[:array], field_descriptor) + end + + ## + # Returns a Message instance for the given field. If the message + # is frozen nil is always returned. Otherwise, a mutable instance is + # returned instead. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def message_from_field_descriptor(field_descriptor) + return nil if frozen? + return nil unless Google::Protobuf::FFI.get_message_has @msg, field_descriptor + mutable_message = Google::Protobuf::FFI.get_mutable_message @msg, field_descriptor, @arena + sub_message = mutable_message[:msg] + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field_descriptor + Descriptor.send(:get_message, sub_message, sub_message_def, @arena) + end + + ## + # Returns a scalar value for the given field. If the message + # is frozen the return value is also frozen. + # @param field_descriptor [FieldDescriptor] Field to retrieve. + def scalar_from_field_descriptor(field_descriptor) + c_type = field_descriptor.send(:c_type) + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + msg_or_enum_def = c_type == :enum ? Google::Protobuf::FFI.get_subtype_as_enum(field_descriptor) : nil + return_value = convert_upb_to_ruby message_value, c_type, msg_or_enum_def + frozen? ? return_value.freeze : return_value + end + + ## + # Dynamically define accessors methods for every field of @descriptor. + # Methods with names that conflict with existing methods are skipped. + def self.setup_accessors! + @descriptor.each do |field_descriptor| + field_name = field_descriptor.name + unless instance_methods(true).include?(field_name.to_sym) + # Dispatching to either index_internal or get_field is logically + # correct, but slightly slower due to having to perform extra + # lookups on each invocation rather than doing it once here. + if field_descriptor.map? + define_method(field_name) do + map_from_field_descriptor field_descriptor + end + elsif field_descriptor.repeated? + define_method(field_name) do + repeated_field_from_field_descriptor field_descriptor + end + elsif field_descriptor.sub_message? + define_method(field_name) do + message_from_field_descriptor field_descriptor + end + else + define_method(field_name) do + scalar_from_field_descriptor field_descriptor + end + end + define_method("#{field_name}=") do |value| + index_assign_internal(value, field_descriptor: field_descriptor) + end + define_method("clear_#{field_name}") do + clear_internal(field_descriptor) + end + if field_descriptor.type == :enum + if field_descriptor.repeated? + define_method("#{field_name}_const") do + return_value = [] + repeated_field_from_field_descriptor(field_descriptor).send(:each_msg_val) do |msg_val| + return_value << msg_val[:int32_val] + end + return_value + end + else + define_method("#{field_name}_const") do + message_value = Google::Protobuf::FFI.get_message_value @msg, field_descriptor + message_value[:int32_val] + end + end + end + if !field_descriptor.repeated? and field_descriptor.wrapper? + define_method("#{field_name}_as_value") do + get_field(field_descriptor, unwrap: true) + end + define_method("#{field_name}_as_value=") do |value| + if value.nil? + clear_internal(field_descriptor) + else + index_assign_internal(value, field_descriptor: field_descriptor, wrap: true) + end + end + end + if field_descriptor.has_presence? + define_method("has_#{field_name}?") do + Google::Protobuf::FFI.get_message_has(@msg, field_descriptor) + end + end + end + end + end + + ## + # Dynamically define accessors methods for every OneOf field of + # @descriptor. + def self.setup_oneof_accessors! + @oneof_field_names = [] + @descriptor.each_oneof do |oneof_descriptor| + self.add_oneof_accessors_for! oneof_descriptor + end + end + + ## + # Dynamically define accessors methods for the given OneOf field. + # Methods with names that conflict with existing methods are skipped. + # @param oneof_descriptor [OneofDescriptor] Field to create accessors + # for. + def self.add_oneof_accessors_for!(oneof_descriptor) + field_name = oneof_descriptor.name.to_sym + @oneof_field_names << field_name + unless instance_methods(true).include?(field_name) + define_method(field_name) do + field_descriptor = Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor) + if field_descriptor.nil? + return + else + return field_descriptor.name.to_sym + end + end + define_method("clear_#{field_name}") do + field_descriptor = Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor) + unless field_descriptor.nil? + clear_internal(field_descriptor) + end + end + define_method("has_#{field_name}?") do + !Google::Protobuf::FFI.get_message_which_oneof(@msg, oneof_descriptor).nil? + end + end + end + + setup_accessors! + setup_oneof_accessors! + + def self.private_constructor(arena, msg: nil, initial_value: nil) + instance = allocate + instance.send(:initialize, initial_value, arena, msg) + instance + end + + def self.inspect_field(field_descriptor, c_type, message_value) + if field_descriptor.sub_message? + sub_msg_descriptor = Google::Protobuf::FFI.get_subtype_as_message(field_descriptor) + sub_msg_descriptor.msgclass.send(:inspect_internal, message_value[:msg_val]) + else + convert_upb_to_ruby(message_value, c_type, field_descriptor.subtype).inspect + end + end + + # @param msg [::FFI::Pointer] Pointer to the Message + def self.inspect_internal(msg) + field_output = [] + descriptor.each do |field_descriptor| + next if field_descriptor.has_presence? && !Google::Protobuf::FFI.get_message_has(msg, field_descriptor) + if field_descriptor.map? + # TODO Adapted - from map#each_msg_val and map#inspect- can this be refactored to reduce echo without introducing a arena allocation? + message_descriptor = field_descriptor.subtype + key_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 1) + key_field_type = Google::Protobuf::FFI.get_type(key_field_def) + + value_field_def = Google::Protobuf::FFI.get_field_by_number(message_descriptor, 2) + value_field_type = Google::Protobuf::FFI.get_type(value_field_def) + + message_value = Google::Protobuf::FFI.get_message_value(msg, field_descriptor) + iter = ::FFI::MemoryPointer.new(:size_t, 1) + iter.write(:size_t, Google::Protobuf::FFI::Upb_Map_Begin) + key_value_pairs = [] + while Google::Protobuf::FFI.map_next(message_value[:map_val], iter) do + iter_size_t = iter.read(:size_t) + key_message_value = Google::Protobuf::FFI.map_key(message_value[:map_val], iter_size_t) + value_message_value = Google::Protobuf::FFI.map_value(message_value[:map_val], iter_size_t) + key_string = convert_upb_to_ruby(key_message_value, key_field_type).inspect + value_string = inspect_field(value_field_def, value_field_type, value_message_value) + key_value_pairs << "#{key_string}=>#{value_string}" + end + field_output << "#{field_descriptor.name}: {#{key_value_pairs.join(", ")}}" + elsif field_descriptor.repeated? + # TODO Adapted - from repeated_field#each - can this be refactored to reduce echo? + repeated_field_output = [] + message_value = Google::Protobuf::FFI.get_message_value(msg, field_descriptor) + array = message_value[:array_val] + n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n - 1) do |i| + element = Google::Protobuf::FFI.get_msgval_at(array, i) + repeated_field_output << inspect_field(field_descriptor, field_descriptor.send(:c_type), element) + end + field_output << "#{field_descriptor.name}: [#{repeated_field_output.join(", ")}]" + else + message_value = Google::Protobuf::FFI.get_message_value msg, field_descriptor + rendered_value = inspect_field(field_descriptor, field_descriptor.send(:c_type), message_value) + field_output << "#{field_descriptor.name}: #{rendered_value}" + end + end + "<#{name}: #{field_output.join(', ')}>" + end + + def self.deep_copy(msg, arena = nil) + arena ||= Google::Protobuf::FFI.create_arena + encode_internal(msg) do |encoding, size, mini_table_ptr| + message = private_constructor(arena) + if encoding.nil? or encoding.null? or Google::Protobuf::FFI.decode_message(encoding, size, message.instance_variable_get(:@msg), mini_table_ptr, nil, 0, arena) != :Ok + raise ParseError.new "Error occurred copying proto" + end + message + end + end + + def self.encode_internal(msg, encoding_options = 0) + temporary_arena = Google::Protobuf::FFI.create_arena + + mini_table_ptr = Google::Protobuf::FFI.get_mini_table(descriptor) + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + pointer_ptr = ::FFI::MemoryPointer.new(:pointer, 1) + encoding_status = Google::Protobuf::FFI.encode_message(msg, mini_table_ptr, encoding_options, temporary_arena, pointer_ptr.to_ptr, size_ptr) + raise "Encoding failed due to #{encoding_status}" unless encoding_status == :Ok + yield pointer_ptr.read(:pointer), size_ptr.read(:size_t), mini_table_ptr + end + + def method_missing_internal(method_name, *args, mode: nil) + raise ArgumentError.new "method_missing_internal called with invalid mode #{mode.inspect}" unless [:respond_to_missing?, :method_missing].include? mode + + #TODO not being allowed is not the same thing as not responding, but this is needed to pass tests + if method_name.to_s.end_with? '=' + if self.class.send(:oneof_field_names).include? method_name.to_s[0..-2].to_sym + return false if mode == :respond_to_missing? + raise RuntimeError.new "Oneof accessors are read-only." + end + end + + original_method_missing(method_name, *args) if mode == :method_missing + end + + def clear_internal(field_def) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + Google::Protobuf::FFI.clear_message_field(@msg, field_def) + end + + # Accessor for field by name. Does not delegate to methods setup by + # self.setup_accessors! in order to avoid conflicts with bad field + # names e.g. `dup` or `class` which are perfectly valid for proto + # fields. + def index_internal(name) + field_descriptor = self.class.descriptor.lookup(name) + get_field field_descriptor unless field_descriptor.nil? + end + + #TODO - well known types keeps us on our toes by overloading methods. + # How much of the public API needs to be defended? + def index_assign_internal(value, name: nil, field_descriptor: nil, wrap: false) + raise FrozenError.new "can't modify frozen #{self.class}" if frozen? + if field_descriptor.nil? + field_descriptor = self.class.descriptor.lookup(name) + if field_descriptor.nil? + raise ArgumentError.new "Unknown field: #{name}" + end + end + unless field_descriptor.send :set_value_on_message, value, @msg, @arena, wrap: wrap + raise RuntimeError.new "allocation failed" + end + end + + ## + # @param initial_value [Object] initial value of this Message + # @param arena [Arena] Optional; Arena where this message will be allocated + # @param msg [::FFI::Pointer] Optional; Message to initialize; creates + # one if omitted or nil. + def initialize(initial_value = nil, arena = nil, msg = nil) + @arena = arena || Google::Protobuf::FFI.create_arena + @msg = msg || Google::Protobuf::FFI.new_message_from_def(Google::Protobuf::FFI.get_mini_table(self.class.descriptor), @arena) + + unless initial_value.nil? + raise ArgumentError.new "Expected hash arguments or message, not #{initial_value.class}" unless initial_value.respond_to? :each + + field_def_ptr = ::FFI::MemoryPointer.new :pointer + oneof_def_ptr = ::FFI::MemoryPointer.new :pointer + + initial_value.each do |key, value| + raise ArgumentError.new "Expected string or symbols as hash keys when initializing proto from hash." unless [String, Symbol].include? key.class + + unless Google::Protobuf::FFI.find_msg_def_by_name self.class.descriptor, key.to_s, key.to_s.bytesize, field_def_ptr, oneof_def_ptr + raise ArgumentError.new "Unknown field name '#{key}' in initialization map entry." + end + raise NotImplementedError.new "Haven't added oneofsupport yet" unless oneof_def_ptr.get_pointer(0).null? + raise NotImplementedError.new "Expected a field def" if field_def_ptr.get_pointer(0).null? + + field_descriptor = FieldDescriptor.from_native field_def_ptr.get_pointer(0) + + next if value.nil? + if field_descriptor.map? + index_assign_internal(Google::Protobuf::Map.send(:construct_for_field, field_descriptor, arena: @arena, value: value), name: key.to_s) + elsif field_descriptor.repeated? + index_assign_internal(RepeatedField.send(:construct_for_field, field_descriptor, arena: @arena, values: value), name: key.to_s) + else + index_assign_internal(value, name: key.to_s) + end + end + end + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + Google::Protobuf::OBJECT_CACHE.try_add @msg.address, self + end + + ## + # Gets a field of this message identified by FieldDescriptor. + # + # @param field [FieldDescriptor] Field to retrieve. + # @param unwrap [Boolean](false) If true, unwraps wrappers. + def get_field(field, unwrap: false) + if field.map? + map_from_field_descriptor field + elsif field.repeated? + repeated_field_from_field_descriptor field + elsif field.sub_message? + return nil unless Google::Protobuf::FFI.get_message_has @msg, field + if unwrap + if field.has?(self) + sub_message_def = Google::Protobuf::FFI.get_subtype_as_message field + wrapper_message_value = Google::Protobuf::FFI.get_message_value @msg, field + fields = Google::Protobuf::FFI.field_count(sub_message_def) + raise "Sub message has #{fields} fields! Expected exactly 1." unless fields == 1 + value_field_def = Google::Protobuf::FFI.get_field_by_number sub_message_def, 1 + message_value = Google::Protobuf::FFI.get_message_value wrapper_message_value[:msg_val], value_field_def + convert_upb_to_ruby message_value, Google::Protobuf::FFI.get_c_type(value_field_def) + else + nil + end + else + message_from_field_descriptor field + end + else + scalar_from_field_descriptor field + end + end + + ## + # Gets a RepeatedField from the ObjectCache or creates a new one. + # @param array [::FFI::Pointer] Pointer to the upb_Array + # @param field [Google::Protobuf::FieldDescriptor] Type of the repeated field + def get_repeated_field(array, field) + return nil if array.nil? or array.null? + repeated_field = OBJECT_CACHE.get(array.address) + if repeated_field.nil? + repeated_field = RepeatedField.send(:construct_for_field, field, arena: @arena, array: array) + repeated_field.freeze if frozen? + end + repeated_field + end + + ## + # Gets a Map from the ObjectCache or creates a new one. + # @param map [::FFI::Pointer] Pointer to the upb_Map + # @param field [Google::Protobuf::FieldDescriptor] Type of the map field + def get_map_field(map, field) + return nil if map.nil? or map.null? + map_field = OBJECT_CACHE.get(map.address) + if map_field.nil? + map_field = Google::Protobuf::Map.send(:construct_for_field, field, arena: @arena, map: map) + map_field.freeze if frozen? + end + map_field + end + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/method_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/method_descriptor.rb new file mode 100755 index 00000000..f879d49c --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/method_descriptor.rb @@ -0,0 +1,124 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2024 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class MethodDescriptor + attr :method_def, :descriptor_pool + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [MethodDescriptor] MethodDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + method_def_ptr = value.nil? ? nil : value.instance_variable_get(:@method_def) + return ::FFI::Pointer::NULL if method_def_ptr.nil? + raise "Underlying method_def was null!" if method_def_ptr.null? + method_def_ptr + end + + ## + # @param service_def [::FFI::Pointer] MethodDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(method_def, _ = nil) + return nil if method_def.nil? or method_def.null? + service_def = Google::Protobuf::FFI.raw_service_def_by_raw_method_def(method_def) + file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) + descriptor_from_file_def(file_def, method_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_method_name(self) + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.method_options(self, size_ptr, temporary_arena) + Google::Protobuf::MethodOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze + end + end + + def input_type + @input_type ||= Google::Protobuf::FFI.method_input_type(self) + end + + def output_type + @output_type ||= Google::Protobuf::FFI.method_output_type(self) + end + + def client_streaming + @client_streaming ||= Google::Protobuf::FFI.method_client_streaming(self) + end + + def server_streaming + @server_streaming ||= Google::Protobuf::FFI.method_server_streaming(self) + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.method_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::MethodDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + def initialize(method_def, descriptor_pool) + @method_def = method_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(method_def, descriptor_pool) + instance = allocate + instance.send(:initialize, method_def, descriptor_pool) + instance + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # MethodDef + attach_function :raw_service_def_by_raw_method_def, :upb_MethodDef_Service, [:pointer], :pointer + attach_function :get_method_name, :upb_MethodDef_Name, [MethodDescriptor], :string + attach_function :method_options, :MethodDescriptor_serialized_options, [MethodDescriptor, :pointer, Internal::Arena], :pointer + attach_function :method_input_type, :upb_MethodDef_InputType, [MethodDescriptor], Descriptor + attach_function :method_output_type, :upb_MethodDef_OutputType, [MethodDescriptor], Descriptor + attach_function :method_client_streaming, :upb_MethodDef_ClientStreaming, [MethodDescriptor], :bool + attach_function :method_server_streaming, :upb_MethodDef_ServerStreaming, [MethodDescriptor], :bool + attach_function :method_to_proto, :MethodDescriptor_serialized_to_proto, [MethodDescriptor, :pointer, Internal::Arena], :pointer + end + end +end + diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/object_cache.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/object_cache.rb new file mode 100755 index 00000000..61f5c8e7 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/object_cache.rb @@ -0,0 +1,30 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + private + + SIZEOF_LONG = ::FFI::MemoryPointer.new(:long).size + SIZEOF_VALUE = ::FFI::Pointer::SIZE + + def self.interpreter_supports_non_finalized_keys_in_weak_map? + ! defined? JRUBY_VERSION + end + + def self.cache_implementation + if interpreter_supports_non_finalized_keys_in_weak_map? and SIZEOF_LONG >= SIZEOF_VALUE + Google::Protobuf::Internal::ObjectCache + else + Google::Protobuf::Internal::LegacyObjectCache + end + end + + public + OBJECT_CACHE = cache_implementation.new + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/oneof_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/oneof_descriptor.rb new file mode 100755 index 00000000..3733900c --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/oneof_descriptor.rb @@ -0,0 +1,107 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2022 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class OneofDescriptor + attr :descriptor_pool, :oneof_def + include Enumerable + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [OneofDescriptor] FieldDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _ = nil) + value.instance_variable_get(:@oneof_def) || ::FFI::Pointer::NULL + end + + ## + # @param oneof_def [::FFI::Pointer] OneofDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(oneof_def, _ = nil) + return nil if oneof_def.nil? or oneof_def.null? + message_descriptor = Google::Protobuf::FFI.get_oneof_containing_type oneof_def + raise RuntimeError.new "Message Descriptor is nil" if message_descriptor.nil? + file_def = Google::Protobuf::FFI.get_message_file_def message_descriptor.to_native + descriptor_from_file_def(file_def, oneof_def) + end + end + + def self.new(*arguments, &block) + raise "OneofDescriptor objects may not be created from Ruby." + end + + def name + Google::Protobuf::FFI.get_oneof_name(self) + end + + def each &block + n = Google::Protobuf::FFI.get_oneof_field_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_oneof_field_by_index(self, i)) + end + nil + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.oneof_options(self, size_ptr, temporary_arena) + opts = Google::Protobuf::OneofOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + opts.clear_features() + opts.freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.oneof_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::OneofDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + def initialize(oneof_def, descriptor_pool) + @descriptor_pool = descriptor_pool + @oneof_def = oneof_def + end + + def self.private_constructor(oneof_def, descriptor_pool) + instance = allocate + instance.send(:initialize, oneof_def, descriptor_pool) + instance + end + end + + class FFI + # MessageDef + attach_function :get_oneof_by_name, :upb_MessageDef_FindOneofByNameWithSize, [Descriptor, :string, :size_t], OneofDescriptor + attach_function :get_oneof_by_index, :upb_MessageDef_Oneof, [Descriptor, :int], OneofDescriptor + + # OneofDescriptor + attach_function :get_oneof_name, :upb_OneofDef_Name, [OneofDescriptor], :string + attach_function :get_oneof_field_count, :upb_OneofDef_FieldCount, [OneofDescriptor], :int + attach_function :get_oneof_field_by_index, :upb_OneofDef_Field, [OneofDescriptor, :int], FieldDescriptor + attach_function :get_oneof_containing_type,:upb_OneofDef_ContainingType, [:pointer], Descriptor + attach_function :oneof_options, :OneOfDescriptor_serialized_options, [OneofDescriptor, :pointer, Internal::Arena], :pointer + attach_function :oneof_to_proto, :OneOfDescriptor_serialized_to_proto, [OneofDescriptor, :pointer, Internal::Arena], :pointer + + # FieldDescriptor + attach_function :real_containing_oneof, :upb_FieldDef_RealContainingOneof, [FieldDescriptor], OneofDescriptor + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/repeated_field.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/repeated_field.rb new file mode 100755 index 00000000..92840680 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/repeated_field.rb @@ -0,0 +1,411 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# +# This class makes RepeatedField act (almost-) like a Ruby Array. +# It has convenience methods that extend the core C or Java based +# methods. +# +# This is a best-effort to mirror Array behavior. Two comments: +# 1) patches always welcome :) +# 2) if performance is an issue, feel free to rewrite the method +# in C. The source code has plenty of examples +# +# KNOWN ISSUES +# - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'` +# - #concat should return the orig array +# - #push should accept multiple arguments and push them all at the same time +# +module Google + module Protobuf + class FFI + # Array + attach_function :append_array, :upb_Array_Append, [:Array, MessageValue.by_value, Internal::Arena], :bool + attach_function :get_msgval_at, :upb_Array_Get, [:Array, :size_t], MessageValue.by_value + attach_function :create_array, :upb_Array_New, [Internal::Arena, CType], :Array + attach_function :array_resize, :upb_Array_Resize, [:Array, :size_t, Internal::Arena], :bool + attach_function :array_set, :upb_Array_Set, [:Array, :size_t, MessageValue.by_value], :void + attach_function :array_size, :upb_Array_Size, [:Array], :size_t + attach_function :array_freeze, :upb_Array_Freeze, [:Array, MiniTable.by_ref], :void + attach_function :array_frozen?, :upb_Array_IsFrozen, [:Array], :bool + end + + class RepeatedField + include Enumerable + + ## + # call-seq: + # RepeatedField.new(type, type_class = nil, initial_values = []) + # + # Creates a new repeated field. The provided type must be a Ruby symbol, and + # an take on the same values as those accepted by FieldDescriptor#type=. If + # the type is :message or :enum, type_class must be non-nil, and must be the + # Ruby class or module returned by Descriptor#msgclass or + # EnumDescriptor#enummodule, respectively. An initial list of elements may also + # be provided. + def self.new(type, type_class = nil, initial_values = []) + instance = allocate + # TODO This argument mangling doesn't agree with the type signature in the comments + # but is required to make unit tests pass; + if type_class.is_a?(Enumerable) and initial_values.empty? and ![:enum, :message].include?(type) + initial_values = type_class + type_class = nil + end + instance.send(:initialize, type, type_class: type_class, initial_values: initial_values) + instance + end + + ## + # call-seq: + # RepeatedField.each(&block) + # + # Invokes the block once for each element of the repeated field. RepeatedField + # also includes Enumerable; combined with this method, the repeated field thus + # acts like an ordinary Ruby sequence. + def each &block + each_msg_val do |element| + yield(convert_upb_to_ruby(element, type, descriptor, arena)) + end + self + end + + def [](*args) + count = length + if args.size < 1 + raise ArgumentError.new "Index or range is a required argument." + end + if args[0].is_a? Range + if args.size > 1 + raise ArgumentError.new "Expected 1 when passing Range argument, but got #{args.size}" + end + range = args[0] + # Handle begin-less and/or endless ranges, when supported. + index_of_first = range.respond_to?(:begin) ? range.begin : range.last + index_of_first = 0 if index_of_first.nil? + end_of_range = range.respond_to?(:end) ? range.end : range.last + index_of_last = end_of_range.nil? ? -1 : end_of_range + + if index_of_last < 0 + index_of_last += count + end + unless range.exclude_end? and !end_of_range.nil? + index_of_last += 1 + end + index_of_first += count if index_of_first < 0 + length = index_of_last - index_of_first + return [] if length.zero? + elsif args[0].is_a? Integer + index_of_first = args[0] + index_of_first += count if index_of_first < 0 + if args.size > 2 + raise ArgumentError.new "Expected 1 or 2 arguments, but got #{args.size}" + end + if args.size == 1 # No length specified, return one element + if array.null? or index_of_first < 0 or index_of_first >= count + return nil + else + return convert_upb_to_ruby(Google::Protobuf::FFI.get_msgval_at(array, index_of_first), type, descriptor, arena) + end + else + length = [args[1],count].min + end + else + raise NotImplementedError + end + + if array.null? or index_of_first < 0 or index_of_first > count + nil + else + if index_of_first + length > count + length = count - index_of_first + end + if length < 0 + nil + else + subarray(index_of_first, length) + end + end + end + alias at [] + + + def []=(index, value) + raise FrozenError if frozen? + count = length + index += count if index < 0 + return nil if index < 0 + if index >= count + resize(index+1) + empty_message_value = Google::Protobuf::FFI::MessageValue.new # Implicitly clear + count.upto(index-1) do |i| + Google::Protobuf::FFI.array_set(array, i, empty_message_value) + end + end + Google::Protobuf::FFI.array_set(array, index, convert_ruby_to_upb(value, arena, type, descriptor)) + nil + end + + def push(*elements) + raise FrozenError if frozen? + internal_push(*elements) + end + + def <<(element) + raise FrozenError if frozen? + push element + end + + def replace(replacements) + raise FrozenError if frozen? + clear + push(*replacements) + end + + def clear + raise FrozenError if frozen? + resize 0 + self + end + + def length + array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + end + alias size :length + + ## + # Is this object frozen? + # Returns true if either this Ruby wrapper or the underlying + # representation are frozen. Freezes the wrapper if the underlying + # representation is already frozen but this wrapper isn't. + def frozen? + unless Google::Protobuf::FFI.array_frozen? array + raise RuntimeError.new "Ruby frozen RepeatedField with mutable representation" if super + return false + end + method(:freeze).super_method.call unless super + true + end + + ## + # Freezes the RepeatedField object. We have to intercept this so we can + # freeze the underlying representation, not just the Ruby wrapper. Returns + # self. + def freeze + if method(:frozen?).super_method.call + unless Google::Protobuf::FFI.array_frozen? array + raise RuntimeError.new "Underlying representation of repeated field still mutable despite frozen wrapper" + end + return self + end + unless Google::Protobuf::FFI.array_frozen? array + mini_table = (type == :message) ? Google::Protobuf::FFI.get_mini_table(@descriptor) : nil + Google::Protobuf::FFI.array_freeze(array, mini_table) + end + super + end + + def dup + instance = self.class.allocate + instance.send(:initialize, type, descriptor: descriptor, arena: arena) + each_msg_val do |element| + instance.send(:append_msg_val, element) + end + instance + end + alias clone dup + + def ==(other) + return true if other.object_id == object_id + if other.is_a? RepeatedField + return false unless other.length == length + each_msg_val_with_index do |msg_val, i| + other_msg_val = Google::Protobuf::FFI.get_msgval_at(other.send(:array), i) + unless Google::Protobuf::FFI.message_value_equal(msg_val, other_msg_val, type, descriptor) + return false + end + end + return true + elsif other.is_a? Enumerable + return to_ary == other.to_a + end + false + end + + ## + # call-seq: + # RepeatedField.to_ary => array + # + # Used when converted implicitly into array, e.g. compared to an Array. + # Also called as a fallback of Object#to_a + def to_ary + return_value = [] + each do |element| + return_value << element + end + return_value + end + + def hash + return_value = 0 + each_msg_val do |msg_val| + return_value = Google::Protobuf::FFI.message_value_hash(msg_val, type, descriptor, return_value) + end + return_value + end + + def +(other) + if other.is_a? RepeatedField + if type != other.instance_variable_get(:@type) or descriptor != other.instance_variable_get(:@descriptor) + raise ArgumentError.new "Attempt to append RepeatedField with different element type." + end + fuse_arena(other.send(:arena)) + super_set = dup + other.send(:each_msg_val) do |msg_val| + super_set.send(:append_msg_val, msg_val) + end + super_set + elsif other.is_a? Enumerable + super_set = dup + super_set.push(*other.to_a) + else + raise ArgumentError.new "Unknown type appending to RepeatedField" + end + end + + def concat(other) + raise ArgumentError.new "Expected Enumerable, but got #{other.class}" unless other.is_a? Enumerable + push(*other.to_a) + end + + private + include Google::Protobuf::Internal::Convert + + attr :name, :arena, :array, :type, :descriptor + + def internal_push(*elements) + elements.each do |element| + append_msg_val convert_ruby_to_upb(element, arena, type, descriptor) + end + self + end + + def pop_one + raise FrozenError if frozen? + count = length + return nil if length.zero? + last_element = Google::Protobuf::FFI.get_msgval_at(array, count-1) + return_value = convert_upb_to_ruby(last_element, type, descriptor, arena) + resize(count-1) + return_value + end + + def subarray(start, length) + return_result = [] + (start..(start + length - 1)).each do |i| + element = Google::Protobuf::FFI.get_msgval_at(array, i) + return_result << convert_upb_to_ruby(element, type, descriptor, arena) + end + return_result + end + + def each_msg_val_with_index &block + n = array.null? ? 0 : Google::Protobuf::FFI.array_size(array) + 0.upto(n-1) do |i| + yield Google::Protobuf::FFI.get_msgval_at(array, i), i + end + end + + def each_msg_val &block + each_msg_val_with_index do |msg_val, _| + yield msg_val + end + end + + # @param msg_val [Google::Protobuf::FFI::MessageValue] Value to append + def append_msg_val(msg_val) + unless Google::Protobuf::FFI.append_array(array, msg_val, arena) + raise NoMemoryError.new "Could not allocate room for #{msg_val} in Arena" + end + end + + # @param new_size [Integer] New size of the array + def resize(new_size) + unless Google::Protobuf::FFI.array_resize(array, new_size, arena) + raise NoMemoryError.new "Array resize to #{new_size} failed!" + end + end + + def initialize(type, type_class: nil, initial_values: nil, name: nil, arena: nil, array: nil, descriptor: nil) + @name = name || 'RepeatedField' + raise ArgumentError.new "Expected argument type to be a Symbol" unless type.is_a? Symbol + field_number = Google::Protobuf::FFI::FieldType[type] + raise ArgumentError.new "Unsupported type '#{type}'" if field_number.nil? + if !descriptor.nil? + @descriptor = descriptor + elsif [:message, :enum].include? type + raise ArgumentError.new "Expected at least 2 arguments for message/enum." if type_class.nil? + descriptor = type_class.respond_to?(:descriptor) ? type_class.descriptor : nil + raise ArgumentError.new "Type class #{type_class} has no descriptor. Please pass a class or enum as returned by the DescriptorPool." if descriptor.nil? + @descriptor = descriptor + else + @descriptor = nil + end + @type = type + + @arena = arena || Google::Protobuf::FFI.create_arena + @array = array || Google::Protobuf::FFI.create_array(@arena, @type) + unless initial_values.nil? + unless initial_values.is_a? Enumerable + raise ArgumentError.new "Expected array as initializer value for repeated field '#{name}' (given #{initial_values.class})." + end + internal_push(*initial_values) + end + + # Should always be the last expression of the initializer to avoid + # leaking references to this object before construction is complete. + OBJECT_CACHE.try_add(@array.address, self) + end + + ## + # Constructor that uses the type information from the given + # FieldDescriptor to configure the new RepeatedField instance. + # @param field [FieldDescriptor] Type information for the new RepeatedField + # @param arena [Arena] Owning message's arena + # @param values [Enumerable] Initial values + # @param array [::FFI::Pointer] Existing upb_Array + def self.construct_for_field(field, arena: nil, values: nil, array: nil) + instance = allocate + options = {initial_values: values, name: field.name, arena: arena, array: array} + if [:enum, :message].include? field.type + options[:descriptor] = field.subtype + end + instance.send(:initialize, field.type, **options) + instance + end + + def fuse_arena(other_arena) + @arena.fuse(other_arena) + end + + extend Google::Protobuf::Internal::Convert + + def self.deep_copy(repeated_field) + instance = allocate + instance.send(:initialize, repeated_field.send(:type), descriptor: repeated_field.send(:descriptor)) + instance.send(:resize, repeated_field.length) + new_array = instance.send(:array) + repeated_field.send(:each_msg_val_with_index) do |element, i| + Google::Protobuf::FFI.array_set(new_array, i, message_value_deep_copy(element, repeated_field.send(:type), repeated_field.send(:descriptor), instance.send(:arena))) + end + instance + end + + end + end +end + +require 'google/protobuf/repeated_field' diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/service_descriptor.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/service_descriptor.rb new file mode 100755 index 00000000..72fd679c --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/ffi/service_descriptor.rb @@ -0,0 +1,117 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2024 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + class ServiceDescriptor + attr :service_def, :descriptor_pool + include Enumerable + + include Google::Protobuf::Internal::Convert + + # FFI Interface methods and setup + extend ::FFI::DataConverter + native_type ::FFI::Type::POINTER + + class << self + prepend Google::Protobuf::Internal::TypeSafety + include Google::Protobuf::Internal::PointerHelper + + # @param value [ServiceDescriptor] ServiceDescriptor to convert to an FFI native type + # @param _ [Object] Unused + def to_native(value, _) + service_def_ptr = value.nil? ? nil : value.instance_variable_get(:@service_def) + return ::FFI::Pointer::NULL if service_def_ptr.nil? + raise "Underlying service_def was null!" if service_def_ptr.null? + service_def_ptr + end + + ## + # @param service_def [::FFI::Pointer] ServiceDef pointer to be wrapped + # @param _ [Object] Unused + def from_native(service_def, _ = nil) + return nil if service_def.nil? or service_def.null? + file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) + descriptor_from_file_def(file_def, service_def) + end + end + + def self.new(*arguments, &block) + raise "Descriptor objects may not be created from Ruby." + end + + def to_s + inspect + end + + def inspect + "#{self.class.name}: #{name}" + end + + def name + @name ||= Google::Protobuf::FFI.get_service_full_name(self) + end + + def file_descriptor + @descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.file_def_by_raw_service_def(@service_def)) + end + + def each &block + n = Google::Protobuf::FFI.method_count(self) + 0.upto(n-1) do |i| + yield(Google::Protobuf::FFI.get_method_by_index(self, i)) + end + nil + end + + def options + @options ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.service_options(self, size_ptr, temporary_arena) + Google::Protobuf::ServiceOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze + end + end + + def to_proto + @to_proto ||= begin + size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) + temporary_arena = Google::Protobuf::FFI.create_arena + buffer = Google::Protobuf::FFI.service_to_proto(self, size_ptr, temporary_arena) + Google::Protobuf::ServiceDescriptorProto.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze) + end + end + + private + + def initialize(service_def, descriptor_pool) + @service_def = service_def + @descriptor_pool = descriptor_pool + end + + def self.private_constructor(service_def, descriptor_pool) + instance = allocate + instance.send(:initialize, service_def, descriptor_pool) + instance + end + + def c_type + @c_type ||= Google::Protobuf::FFI.get_c_type(self) + end + end + + class FFI + # ServiceDef + attach_function :file_def_by_raw_service_def, :upb_ServiceDef_File, [:pointer], :FileDef + attach_function :get_service_full_name, :upb_ServiceDef_FullName, [ServiceDescriptor], :string + attach_function :method_count, :upb_ServiceDef_MethodCount, [ServiceDescriptor], :int + attach_function :get_method_by_index, :upb_ServiceDef_Method, [ServiceDescriptor, :int], MethodDescriptor + attach_function :service_options, :ServiceDescriptor_serialized_options, [ServiceDescriptor, :pointer, Internal::Arena], :pointer + attach_function :service_to_proto, :ServiceDescriptor_serialized_to_proto, [ServiceDescriptor, :pointer, Internal::Arena], :pointer + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/field_mask_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/field_mask_pb.rb new file mode 100755 index 00000000..5240768e --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/field_mask_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/field_mask.proto + +require 'google/protobuf' + + +descriptor_data = "\n google/protobuf/field_mask.proto\x12\x0fgoogle.protobuf\"\x1a\n\tFieldMask\x12\r\n\x05paths\x18\x01 \x03(\tB\x85\x01\n\x13\x63om.google.protobufB\x0e\x46ieldMaskProtoP\x01Z2google.golang.org/protobuf/types/known/fieldmaskpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + FieldMask = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldMask").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/internal/object_cache.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/internal/object_cache.rb new file mode 100755 index 00000000..38e9bb5f --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/internal/object_cache.rb @@ -0,0 +1,99 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module Internal + # A pointer -> Ruby Object cache that keeps references to Ruby wrapper + # objects. This allows us to look up any Ruby wrapper object by the address + # of the object it is wrapping. That way we can avoid ever creating two + # different wrapper objects for the same C object, which saves memory and + # preserves object identity. + # + # We use WeakMap for the cache. If sizeof(long) > sizeof(VALUE), we also + # need a secondary Hash to store WeakMap keys, because our pointer keys may + # need to be stored as Bignum instead of Fixnum. Since WeakMap is weak for + # both keys and values, a Bignum key will cause the WeakMap entry to be + # collected immediately unless there is another reference to the Bignum. + # This happens on 64-bit Windows, on which pointers are 64 bits but longs + # are 32 bits. In this case, we enable the secondary Hash to hold the keys + # and prevent them from being collected. + class ObjectCache + def initialize + @map = ObjectSpace::WeakMap.new + @mutex = Mutex.new + end + + def get(key) + @map[key] + end + + def try_add(key, value) + @map[key] || @mutex.synchronize do + @map[key] ||= value + end + end + end + + class LegacyObjectCache + def initialize + @secondary_map = {} + @map = ObjectSpace::WeakMap.new + @mutex = Mutex.new + end + + def get(key) + value = if secondary_key = @secondary_map[key] + @map[secondary_key] + else + @mutex.synchronize do + @map[(@secondary_map[key] ||= Object.new)] + end + end + + # GC if we could remove at least 2000 entries or 20% of the table size + # (whichever is greater). Since the cost of the GC pass is O(N), we + # want to make sure that we condition this on overall table size, to + # avoid O(N^2) CPU costs. + cutoff = (@secondary_map.size * 0.2).ceil + cutoff = 2_000 if cutoff < 2_000 + if (@secondary_map.size - @map.size) > cutoff + purge + end + + value + end + + def try_add(key, value) + if secondary_key = @secondary_map[key] + if old_value = @map[secondary_key] + return old_value + end + end + + @mutex.synchronize do + secondary_key ||= (@secondary_map[key] ||= Object.new) + @map[secondary_key] ||= value + end + end + + private + + def purge + @mutex.synchronize do + @secondary_map.each do |key, secondary_key| + unless @map.key?(secondary_key) + @secondary_map.delete(key) + end + end + end + nil + end + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_enumvalue_options_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_enumvalue_options_pb.rb new file mode 100755 index 00000000..df8abd30 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_enumvalue_options_pb.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/json_enumvalue_options.proto + +require 'google/protobuf' + +require 'google/protobuf/descriptor_pb' + + +descriptor_data = "\n,google/protobuf/json_enumvalue_options.proto\x12\x0cpb.enumvalue\x1a google/protobuf/descriptor.proto\"(\n\x14JsonEnumValueOptions\x12\x0e\n\x06string\x18\x01 \x01(\tX\x01:\\\n\x04json\x12!.google.protobuf.EnumValueOptions\x18\xe6\x07 \x01(\x0b\x32\".pb.enumvalue.JsonEnumValueOptionsB\x06\xb2\x01\x03\x08\xea\x07\x42\x1a\n\x18\x63om.google.protobuf.utilb\x08\x65\x64itionsp\xe9\x07" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Pb + module Enumvalue + JsonEnumValueOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("pb.enumvalue.JsonEnumValueOptions").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_options_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_options_pb.rb new file mode 100755 index 00000000..f246b395 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/json_options_pb.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/json_options.proto + +require 'google/protobuf' + +require 'google/protobuf/json_enumvalue_options_pb' + + +descriptor_data = "\n\"google/protobuf/json_options.proto\x12\x02pb\x1a,google/protobuf/json_enumvalue_options.protoB\x1a\n\x18\x63om.google.protobuf.utilP\x00\x62\x08\x65\x64itionsp\xe9\x07" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Pb +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/message_exts.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/message_exts.rb new file mode 100755 index 00000000..a014304e --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/message_exts.rb @@ -0,0 +1,39 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +module Google + module Protobuf + module MessageExts + + #this is only called in jruby; mri loades the ClassMethods differently + def self.included(klass) + klass.extend(ClassMethods) + end + + module ClassMethods + end + + def to_json(options = {}) + self.class.encode_json(self, options) + end + + def to_proto(options = {}) + self.class.encode(self, options) + end + + def to_hash + self.to_h + end + + end + class AbstractMessage + include MessageExts + extend MessageExts::ClassMethods + end + private_constant :AbstractMessage + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/plugin_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/plugin_pb.rb new file mode 100755 index 00000000..a8aebec4 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/plugin_pb.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/compiler/plugin.proto + +require 'google/protobuf' + +require 'google/protobuf/descriptor_pb' + + +descriptor_data = "\n%google/protobuf/compiler/plugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"F\n\x07Version\x12\r\n\x05major\x18\x01 \x01(\x05\x12\r\n\x05minor\x18\x02 \x01(\x05\x12\r\n\x05patch\x18\x03 \x01(\x05\x12\x0e\n\x06suffix\x18\x04 \x01(\t\"\x81\x02\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12\x45\n\x17source_file_descriptors\x18\x11 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\x12;\n\x10\x63ompiler_version\x18\x03 \x01(\x0b\x32!.google.protobuf.compiler.Version\"\x92\x03\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x1a\n\x12supported_features\x18\x02 \x01(\x04\x12\x17\n\x0fminimum_edition\x18\x03 \x01(\x05\x12\x17\n\x0fmaximum_edition\x18\x04 \x01(\x05\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a\x7f\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\t\x12?\n\x13generated_code_info\x18\x10 \x01(\x0b\x32\".google.protobuf.GeneratedCodeInfo\"W\n\x07\x46\x65\x61ture\x12\x10\n\x0c\x46\x45\x41TURE_NONE\x10\x00\x12\x1b\n\x17\x46\x45\x41TURE_PROTO3_OPTIONAL\x10\x01\x12\x1d\n\x19\x46\x45\x41TURE_SUPPORTS_EDITIONS\x10\x02\x42r\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtosZ)google.golang.org/protobuf/types/pluginpb\xaa\x02\x18Google.Protobuf.Compiler" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + module Compiler + Version = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.Version").msgclass + CodeGeneratorRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorRequest").msgclass + CodeGeneratorResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse").msgclass + CodeGeneratorResponse::File = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse.File").msgclass + CodeGeneratorResponse::Feature = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.compiler.CodeGeneratorResponse.Feature").enummodule + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/repeated_field.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/repeated_field.rb new file mode 100755 index 00000000..53de122f --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/repeated_field.rb @@ -0,0 +1,177 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'forwardable' + +# +# This class makes RepeatedField act (almost-) like a Ruby Array. +# It has convenience methods that extend the core C or Java based +# methods. +# +# This is a best-effort to mirror Array behavior. Two comments: +# 1) patches always welcome :) +# 2) if performance is an issue, feel free to rewrite the method +# in jruby and C. The source code has plenty of examples +# +# KNOWN ISSUES +# - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'` +# - #concat should return the orig array +# - #push should accept multiple arguments and push them all at the same time +# +module Google + module Protobuf + class RepeatedField + extend Forwardable + + # methods defined in C or Java: + # + + # [], at + # []= + # concat + # clear + # dup, clone + # each + # push, << + # replace + # length, size + # == + # to_ary, to_a + # also all enumerable + # + # NOTE: using delegators rather than method_missing to make the + # relationship explicit instead of implicit + def_delegators :to_ary, + :&, :*, :-, :'<=>', + :assoc, :bsearch, :bsearch_index, :combination, :compact, :count, + :cycle, :difference, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten, + :include?, :index, :inspect, :intersection, :join, + :pack, :permutation, :product, :pretty_print, :pretty_print_cycle, + :rassoc, :repeated_combination, :repeated_permutation, :reverse, + :rindex, :rotate, :sample, :shuffle, :shelljoin, + :to_s, :transpose, :union, :uniq, :| + + + def first(n=nil) + if n.nil? + return self[0] + elsif n < 0 + raise ArgumentError, "negative array size" + else + return self[0...n] + end + end + + + def last(n=nil) + if n.nil? + return self[-1] + elsif n < 0 + raise ArgumentError, "negative array size" + else + start = [self.size-n, 0].max + return self[start...self.size] + end + end + + + def pop(n=nil) + if n + results = [] + n.times{ results << pop_one } + return results + else + return pop_one + end + end + + + def empty? + self.size == 0 + end + + # array aliases into enumerable + alias_method :slice, :[] + alias_method :values_at, :select + alias_method :map, :collect + + + class << self + def define_array_wrapper_method(method_name) + define_method(method_name) do |*args, &block| + arr = self.to_a + result = arr.send(method_name, *args) + self.replace(arr) + return result if result + return block ? block.call : result + end + end + private :define_array_wrapper_method + + + def define_array_wrapper_with_result_method(method_name) + define_method(method_name) do |*args, &block| + # result can be an Enumerator, Array, or nil + # Enumerator can sometimes be returned if a block is an optional argument and it is not passed in + # nil usually specifies that no change was made + result = self.to_a.send(method_name, *args, &block) + if result + new_arr = result.to_a + self.replace(new_arr) + if result.is_a?(Enumerator) + # generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will + # reset the enum with the same length, but all the #next calls will + # return nil + result = new_arr.to_enum + # generate a wrapper enum so any changes which occur by a chained + # enum can be captured + ie = ProxyingEnumerator.new(self, result) + result = ie.to_enum + end + end + result + end + end + private :define_array_wrapper_with_result_method + end + + + %w(delete delete_at shift slice! unshift).each do |method_name| + define_array_wrapper_method(method_name) + end + + + %w(collect! compact! delete_if each_index fill flatten! insert reverse! + rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name| + define_array_wrapper_with_result_method(method_name) + end + alias_method :keep_if, :select! + alias_method :map!, :collect! + alias_method :reject!, :delete_if + + + # propagates changes made by user of enumerator back to the original repeated field. + # This only applies in cases where the calling function which created the enumerator, + # such as #sort!, modifies itself rather than a new array, such as #sort + class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator) + def each(*args, &block) + results = [] + external_enumerator.each_with_index do |val, i| + result = yield(val) + results << result + #nil means no change occurred from yield; usually occurs when #to_a is called + if result + repeated_field[i] = result if result != val + end + end + results + end + end + + + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/source_context_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/source_context_pb.rb new file mode 100755 index 00000000..74aec1e1 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/source_context_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/source_context.proto + +require 'google/protobuf' + + +descriptor_data = "\n$google/protobuf/source_context.proto\x12\x0fgoogle.protobuf\"\"\n\rSourceContext\x12\x11\n\tfile_name\x18\x01 \x01(\tB\x8a\x01\n\x13\x63om.google.protobufB\x12SourceContextProtoP\x01Z6google.golang.org/protobuf/types/known/sourcecontextpb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + SourceContext = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceContext").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/struct_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/struct_pb.rb new file mode 100755 index 00000000..6c1cde71 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/struct_pb.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/struct.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1cgoogle/protobuf/struct.proto\x12\x0fgoogle.protobuf\"\x84\x01\n\x06Struct\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.protobuf.Struct.FieldsEntry\x1a\x45\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01\"\xea\x01\n\x05Value\x12\x30\n\nnull_value\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x16\n\x0cnumber_value\x18\x02 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x03 \x01(\tH\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12/\n\x0cstruct_value\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x12\x30\n\nlist_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x42\x06\n\x04kind\"3\n\tListValue\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value*\x1b\n\tNullValue\x12\x0e\n\nNULL_VALUE\x10\x00\x42\x7f\n\x13\x63om.google.protobufB\x0bStructProtoP\x01Z/google.golang.org/protobuf/types/known/structpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Struct = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Struct").msgclass + Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Value").msgclass + ListValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ListValue").msgclass + NullValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.NullValue").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/timestamp_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/timestamp_pb.rb new file mode 100755 index 00000000..87930df0 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/timestamp_pb.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/timestamp.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1fgoogle/protobuf/timestamp.proto\x12\x0fgoogle.protobuf\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x85\x01\n\x13\x63om.google.protobufB\x0eTimestampProtoP\x01Z2google.golang.org/protobuf/types/known/timestamppb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Timestamp = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Timestamp").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/type_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/type_pb.rb new file mode 100755 index 00000000..c3fc0873 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/type_pb.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/type.proto + +require 'google/protobuf' + +require 'google/protobuf/any_pb' +require 'google/protobuf/source_context_pb' + + +descriptor_data = "\n\x1agoogle/protobuf/type.proto\x12\x0fgoogle.protobuf\x1a\x19google/protobuf/any.proto\x1a$google/protobuf/source_context.proto\"\xe8\x01\n\x04Type\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Field\x12\x0e\n\x06oneofs\x18\x03 \x03(\t\x12(\n\x07options\x18\x04 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x06 \x01(\x0e\x32\x17.google.protobuf.Syntax\x12\x0f\n\x07\x65\x64ition\x18\x07 \x01(\t\"\xd5\x05\n\x05\x46ield\x12)\n\x04kind\x18\x01 \x01(\x0e\x32\x1b.google.protobuf.Field.Kind\x12\x37\n\x0b\x63\x61rdinality\x18\x02 \x01(\x0e\x32\".google.protobuf.Field.Cardinality\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x10\n\x08type_url\x18\x06 \x01(\t\x12\x13\n\x0boneof_index\x18\x07 \x01(\x05\x12\x0e\n\x06packed\x18\x08 \x01(\x08\x12(\n\x07options\x18\t \x03(\x0b\x32\x17.google.protobuf.Option\x12\x11\n\tjson_name\x18\n \x01(\t\x12\x15\n\rdefault_value\x18\x0b \x01(\t\"\xc8\x02\n\x04Kind\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"t\n\x0b\x43\x61rdinality\x12\x17\n\x13\x43\x41RDINALITY_UNKNOWN\x10\x00\x12\x18\n\x14\x43\x41RDINALITY_OPTIONAL\x10\x01\x12\x18\n\x14\x43\x41RDINALITY_REQUIRED\x10\x02\x12\x18\n\x14\x43\x41RDINALITY_REPEATED\x10\x03\"\xdf\x01\n\x04\x45num\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\tenumvalue\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.EnumValue\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x05 \x01(\x0e\x32\x17.google.protobuf.Syntax\x12\x0f\n\x07\x65\x64ition\x18\x06 \x01(\t\"S\n\tEnumValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\";\n\x06Option\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any*C\n\x06Syntax\x12\x11\n\rSYNTAX_PROTO2\x10\x00\x12\x11\n\rSYNTAX_PROTO3\x10\x01\x12\x13\n\x0fSYNTAX_EDITIONS\x10\x02\x42{\n\x13\x63om.google.protobufB\tTypeProtoP\x01Z-google.golang.org/protobuf/types/known/typepb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Type").msgclass + Field = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field").msgclass + Field::Kind = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Kind").enummodule + Field::Cardinality = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Cardinality").enummodule + Enum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Enum").msgclass + EnumValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValue").msgclass + Option = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Option").msgclass + Syntax = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Syntax").enummodule + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/well_known_types.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/well_known_types.rb new file mode 100755 index 00000000..c2df7236 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/well_known_types.rb @@ -0,0 +1,211 @@ +#!/usr/bin/ruby +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'google/protobuf/any_pb' +require 'google/protobuf/duration_pb' +require 'google/protobuf/field_mask_pb' +require 'google/protobuf/struct_pb' +require 'google/protobuf/timestamp_pb' + +module Google + module Protobuf + + Any.class_eval do + def self.pack(msg, type_url_prefix='type.googleapis.com/') + any = self.new + any.pack(msg, type_url_prefix) + any + end + + def pack(msg, type_url_prefix='type.googleapis.com/') + if type_url_prefix.empty? or type_url_prefix[-1] != '/' then + self.type_url = "#{type_url_prefix}/#{msg.class.descriptor.name}" + else + self.type_url = "#{type_url_prefix}#{msg.class.descriptor.name}" + end + self.value = msg.to_proto + end + + def unpack(klass) + if self.is(klass) then + klass.decode(self.value) + else + nil + end + end + + def type_name + return self.type_url.split("/")[-1] + end + + def is(klass) + return self.type_name == klass.descriptor.name + end + end + + Timestamp.class_eval do + def to_time + Time.at(seconds, nanos, :nanosecond) + end + + def self.from_time(time) + new.from_time(time) + end + + def from_time(time) + self.seconds = time.to_i + self.nanos = time.nsec + self + end + + def to_i + self.seconds + end + + def to_f + self.seconds + (self.nanos.quo(1_000_000_000)) + end + end + + Duration.class_eval do + def to_f + self.seconds + (self.nanos.to_f / 1_000_000_000) + end + end + + class UnexpectedStructType < Google::Protobuf::Error; end + + Value.class_eval do + def to_ruby(recursive = false) + case self.kind + when :struct_value + if recursive + self.struct_value.to_h + else + self.struct_value + end + when :list_value + if recursive + self.list_value.to_a + else + self.list_value + end + when :null_value + nil + when :number_value + self.number_value + when :string_value + self.string_value + when :bool_value + self.bool_value + else + raise UnexpectedStructType + end + end + + def self.from_ruby(value) + self.new.from_ruby(value) + end + + def from_ruby(value) + case value + when NilClass + self.null_value = :NULL_VALUE + when Numeric + self.number_value = value + when String + self.string_value = value + when TrueClass + self.bool_value = true + when FalseClass + self.bool_value = false + when Struct + self.struct_value = value + when Hash + self.struct_value = Struct.from_hash(value) + when ListValue + self.list_value = value + when Array + self.list_value = ListValue.from_a(value) + else + raise UnexpectedStructType + end + + self + end + end + + Struct.class_eval do + def [](key) + self.fields[key].to_ruby + rescue NoMethodError + nil + end + + def []=(key, value) + unless key.is_a?(String) + raise UnexpectedStructType, "Struct keys must be strings." + end + self.fields[key] ||= Google::Protobuf::Value.new + self.fields[key].from_ruby(value) + end + + def to_h + ret = {} + self.fields.each { |key, val| ret[key] = val.to_ruby(true) } + ret + end + + def self.from_hash(hash) + ret = Struct.new + hash.each { |key, val| ret[key] = val } + ret + end + + def has_key?(key) + self.fields.has_key?(key) + end + end + + ListValue.class_eval do + include Enumerable + + def length + self.values.length + end + + def [](index) + self.values[index].to_ruby + end + + def []=(index, value) + self.values[index].from_ruby(value) + end + + def <<(value) + wrapper = Google::Protobuf::Value.new + wrapper.from_ruby(value) + self.values << wrapper + end + + def each + self.values.each { |x| yield(x.to_ruby) } + end + + def to_a + self.values.map { |x| x.to_ruby(true) } + end + + def self.from_a(arr) + ret = ListValue.new + arr.each { |val| ret << val } + ret + end + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/wrappers_pb.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/wrappers_pb.rb new file mode 100755 index 00000000..ec43b6ca --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf/wrappers_pb.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/protobuf/wrappers.proto + +require 'google/protobuf' + + +descriptor_data = "\n\x1egoogle/protobuf/wrappers.proto\x12\x0fgoogle.protobuf\"\x1c\n\x0b\x44oubleValue\x12\r\n\x05value\x18\x01 \x01(\x01\"\x1b\n\nFloatValue\x12\r\n\x05value\x18\x01 \x01(\x02\"\x1b\n\nInt64Value\x12\r\n\x05value\x18\x01 \x01(\x03\"\x1c\n\x0bUInt64Value\x12\r\n\x05value\x18\x01 \x01(\x04\"\x1b\n\nInt32Value\x12\r\n\x05value\x18\x01 \x01(\x05\"\x1c\n\x0bUInt32Value\x12\r\n\x05value\x18\x01 \x01(\r\"\x1a\n\tBoolValue\x12\r\n\x05value\x18\x01 \x01(\x08\"\x1c\n\x0bStringValue\x12\r\n\x05value\x18\x01 \x01(\t\"\x1b\n\nBytesValue\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x83\x01\n\x13\x63om.google.protobufB\rWrappersProtoP\x01Z1google.golang.org/protobuf/types/known/wrapperspb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3" + +pool = ::Google::Protobuf::DescriptorPool.generated_pool +pool.add_serialized_file(descriptor_data) + +module Google + module Protobuf + DoubleValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DoubleValue").msgclass + FloatValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FloatValue").msgclass + Int64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int64Value").msgclass + UInt64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt64Value").msgclass + Int32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int32Value").msgclass + UInt32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt32Value").msgclass + BoolValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BoolValue").msgclass + StringValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.StringValue").msgclass + BytesValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BytesValue").msgclass + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_ffi.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_ffi.rb new file mode 100755 index 00000000..731848f1 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_ffi.rb @@ -0,0 +1,52 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +require 'ffi-compiler/loader' +require 'google/protobuf/ffi/ffi' +require 'google/protobuf/ffi/internal/type_safety' +require 'google/protobuf/ffi/internal/pointer_helper' +require 'google/protobuf/ffi/internal/arena' +require 'google/protobuf/ffi/internal/convert' +require 'google/protobuf/ffi/descriptor' +require 'google/protobuf/ffi/enum_descriptor' +require 'google/protobuf/ffi/field_descriptor' +require 'google/protobuf/ffi/oneof_descriptor' +require 'google/protobuf/ffi/method_descriptor' +require 'google/protobuf/ffi/service_descriptor' +require 'google/protobuf/ffi/file_descriptor' +require 'google/protobuf/ffi/descriptor_pool' +require 'google/protobuf/ffi/map' +require 'google/protobuf/ffi/object_cache' +require 'google/protobuf/ffi/repeated_field' +require 'google/protobuf/ffi/message' + +module Google + module Protobuf + def self.deep_copy(object) + case object + when RepeatedField + RepeatedField.send(:deep_copy, object) + when Google::Protobuf::Map + Google::Protobuf::Map.deep_copy(object) + when Google::Protobuf::MessageExts + object.class.send(:deep_copy, object.instance_variable_get(:@msg)) + else + raise NotImplementedError + end + end + + def self.discard_unknown(message) + raise FrozenError if message.frozen? + raise ArgumentError.new "Expected message, got #{message.class} instead." if message.instance_variable_get(:@msg).nil? + pool_def = message.class.descriptor.instance_variable_get(:@descriptor_pool).descriptor_pool + unless Google::Protobuf::FFI.message_discard_unknown(message.instance_variable_get(:@msg), message.class.descriptor, pool_def, 128) + raise RuntimeError.new "Messages nested too deeply." + end + nil + end + end +end diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_native.rb b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_native.rb new file mode 100755 index 00000000..9605b6b5 --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/protobuf_native.rb @@ -0,0 +1,19 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2023 Google Inc. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +if RUBY_PLATFORM == "java" + require 'json' + require 'google/protobuf_java' +else + begin + require "google/#{RUBY_VERSION.sub(/\.\d+$/, '')}/protobuf_c" + rescue LoadError + require 'google/protobuf_c' + end +end + +require 'google/protobuf/repeated_field' diff --git a/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/tasks/ffi.rake b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/tasks/ffi.rake new file mode 100755 index 00000000..e983c1ad --- /dev/null +++ b/bin/gems/google-protobuf-4.36.1-x86_64-linux-gnu/lib/google/tasks/ffi.rake @@ -0,0 +1,100 @@ +# # @param task [FFI::Compiler::CompileTask] task to configure +def configure_common_compile_task(task) + if FileUtils.pwd.include? 'ext' + src_dir = '.' + third_party_path = 'third_party/utf8_range' + else + src_dir = 'ext/google/protobuf_c' + third_party_path = 'ext/google/protobuf_c/third_party/utf8_range' + end + + task.add_include_path third_party_path + task.add_define 'NDEBUG' + task.cflags << "-std=gnu99 -O3" + [ + :convert, :defs, :map, :message, :protobuf, :repeated_field + ].each { |file| task.exclude << "/#{file}.c" } + task.ext_dir = src_dir + task.source_dirs = [src_dir] + if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ + task.cflags << "-Wall -Wsign-compare -Wno-declaration-after-statement" + end +end + +# FFI::CompilerTask's constructor walks the filesystem at task definition time +# to create subtasks for each source file, so files from third_party must be +# copied into place before the task is defined for it to work correctly. +# TODO Is there a sane way to check for generated protos under lib too? +def with_generated_files + expected_path = FileUtils.pwd.include?('ext') ? 'third_party/utf8_range' : 'ext/google/protobuf_c/third_party/utf8_range' + if File.directory?(expected_path) + yield + else + task :default do + # It is possible, especially in cases like the first invocation of + # `rake test` following `rake clean` or a fresh checkout that the + # `copy_third_party` task has been executed since initial task definition. + # If so, run the task definition block now and invoke it explicitly. + if File.directory?(expected_path) + yield + Rake::Task[:default].invoke + else + raise "Missing directory #{File.absolute_path(expected_path)}." + + " Did you forget to run `rake copy_third_party` before building" + + " native extensions?" + end + end + end +end + +begin + require "ffi-compiler/compile_task" + + desc "Compile Protobuf library for FFI" + namespace "ffi-protobuf" do + with_generated_files do + # Compile Ruby UPB separately in order to limit use of -DUPB_BUILD_API to one + # compilation unit. + desc "Compile UPB library for FFI" + namespace "ffi-upb" do + with_generated_files do + FFI::Compiler::CompileTask.new('ruby-upb') do |c| + configure_common_compile_task c + c.add_define "UPB_BUILD_API" + c.exclude << "/glue.c" + c.exclude << "/shared_message.c" + c.exclude << "/shared_convert.c" + if RbConfig::CONFIG['target_os'] =~ /darwin|linux/ + c.cflags << "-fvisibility=hidden" + end + end + end + end + + FFI::Compiler::CompileTask.new 'protobuf_c_ffi' do |c| + configure_common_compile_task c + # Ruby UPB was already compiled with different flags. + c.exclude << "/utf8_range.c" + c.exclude << "/ruby-upb.c" + end + + # Setup dependencies so that the .o files generated by building ffi-upb are + # available to link here. + # TODO Can this be simplified? Can the single shared library be used + # instead of the object files? + protobuf_c_task = Rake::Task[:default] + protobuf_c_shared_lib_task = Rake::Task[protobuf_c_task.prereqs.last] + ruby_upb_shared_lib_task = Rake::Task[:"ffi-upb:default"].prereqs.first + Rake::Task[ruby_upb_shared_lib_task].prereqs.each do |dependency| + protobuf_c_shared_lib_task.prereqs.prepend dependency + end + end + end +rescue LoadError + desc "Compile Protobuf library for FFI" + namespace "ffi-protobuf" do + task :default do + warn "Skipping build of FFI; `gem install ffi-compiler` to enable." + end + end +end diff --git a/bin/gems/hashery-2.1.2/.index b/bin/gems/hashery-2.1.2/.index new file mode 100644 index 00000000..ead4e7a2 --- /dev/null +++ b/bin/gems/hashery-2.1.2/.index @@ -0,0 +1,78 @@ +--- +revision: 2013 +type: ruby +sources: +- Index.yml +- Gemfile +authors: +- name: Trans + email: transfire@gmail.com +- name: Kirk Haines +- name: Robert Klemme +- name: Jan Molic +- name: George Moschovitis +- name: Jeena Paradies +- name: Erik Veenstra +organizations: +- name: RubyWorks (http://rubyworks.github.com/) +requirements: +- groups: + - development + - test + version: ">= 0" + name: qed +- groups: + - development + - test + version: ">= 0" + name: lemon +- groups: + - development + - test + version: ">= 0" + name: rubytest-cli +conflicts: [] +alternatives: [] +resources: +- type: home + uri: http://rubyworks.github.com/hashery + label: Homepage +- type: code + uri: http://github.com/rubyworks/hashery + label: Source Code +- type: mail + uri: http://groups.google.com/group/rubyworks-mailinglist + label: Mailing List +- type: docs + uri: http://rubydoc.info/github/rubyworks/hashery/master/frames + label: Documentation +- type: wiki + uri: http://wiki.github.com/rubyworks/hashery + label: User Guide +- type: gems + uri: http://rubygems.org/gems/hashery +repositories: +- name: upstream + scm: git + uri: git://github.com/rubyworks/hashery.git +categories: [] +copyrights: +- holder: Rubyworks + year: '2010' + license: BSD-2-Clause +customs: [] +paths: + lib: + - lib + - alt +name: hashery +title: Hashery +version: 2.1.2 +summary: Facets-bread collection of Hash-like classes. +description: The Hashery is a tight collection of Hash-like classes. Included among + its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, + the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass + of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making + it a snap to subclass and augment to fit any specific use case. +created: '2010-04-21' +date: '2016-05-01' diff --git a/bin/gems/hashery-2.1.2/.yardopts b/bin/gems/hashery-2.1.2/.yardopts new file mode 100644 index 00000000..c56eafea --- /dev/null +++ b/bin/gems/hashery-2.1.2/.yardopts @@ -0,0 +1,9 @@ +--plugin tomdoc +--output-dir doc +--title Hashery +--protected +--private +lib/ +- +[A-Z]*.* + diff --git a/bin/gems/hashery-2.1.2/HISTORY.md b/bin/gems/hashery-2.1.2/HISTORY.md new file mode 100644 index 00000000..a239b613 --- /dev/null +++ b/bin/gems/hashery-2.1.2/HISTORY.md @@ -0,0 +1,188 @@ +# RELEASE HISTORY + +## 2.1.1 / 2013-08-21 + +This minor release clarifies the licensing. The entire library is now +distributed under the BSD-2-Clause license, also known as the FreeBSD +license. In addition this release provides a bug fix for flattening +arrays that contain an OpenCascade object. + +Changes: + +* Clarify licensing. +* Fix #flatten on Arrays that contain an OpenCascade. + + +## 2.1.0 / 2012-11-24 (Golden Retriever) + +The major change of the 2.1 release is to switch over to `Hash#fetch` +as the fundamental CRUD read method in-place of the previous `#read` core +extension (an alias of `#[]`). This is a pretty fundamental change which +required modification of a number of classes. So please do extra-diligence +and file an issue if you experience any problems. + +In addition, the Hash#read core extension has been renamed to Hash#retrieve +to avoid any possible confusion with IO objects. This release also fixes +a couple of issues with 1.8 compatibility and makes a few other small +enhancements. + +Changes: + +* Rename Hash#read to Hash#retrieve. +* Deprecate `Dictionary.alpha` in favor of `Dictionary.alphabetic`. +* Add support for block argument in Dictionary#order_by_key and #order_by_value. +* Fix OpenHash issues with Ruby 1.8.x compatibility. +* OpenHash methods are opened up via `protected` instead of `private`. +* Change OpenCascade to auto-create the subclass when inherited. + + +## 2.0.1 / 2012-07-06 + +This minor release fixes an issue with OpenCascade (#13). +The key_proc procedure wasn't being passed along to sub-cascades. + +Changes: + +* OpenCascade passes along key_proc to children. + + +## 2.0.0 / 2012-05-11 (Crud Space) + +This is a big release for Hashery which both culls some of it's +less fitting classes and modules while greatly improving the rest. +The first and most immediate change is use of a proper namespace. +All classes and modules are now appropriately kept in the `Hashery` +namespace. To get the old behavior you can `include Hashery` as the +toplevel. For the other changes and improvements dive into the +API documentation. + +Changes: + +* Use proper Hashery namespace. +* Add CRUDHash, which also serves a good base class. +* Improved OpenHash to be nearly 100% open. +* Deprecate BasicStruct, as it would be better to improve OpenStruct. +* Deprecate BasicCascade, though it never really came to be. +* Deprecate BasicObject emulator, as it is no longer needed. +* Deprecate Memoizer, not sure how that got in here anyway. +* Deprecate Ostructable, which can be paired up with better OpenStruct. +* Removed open_object.rb, which has long been deprecated. + + +## 1.5.1 / 2012-05-09 + +This release adds transformative #each method to OpenCascade, to +ensure #each returns an OpenCascade. Also, BasicCascade has been +added that is like OpenCascade by fully open by use of BasicObject +as a base class. + +Changes: + +* Fix OpenCascade#each (porecreat). +* Introduce BasicCascade class. +* Renamed `Ini` class to `IniHash` class. + + +## 1.5.0 / 2011-11-10 (Devil's Core) + +In this release, CoreExt module has been added to encapsulate +methods that extend Ruby's core Hash class (there are only a few). +Presently these are only loaded when using `require 'hashery'`. +If you are cherry-picking from Hashery but still want the core +extensions, you need to use `require 'hasery/core_ext'` first. +In addition, BasicStruct class now has a #key method. And finally +this release switches licensing to BSD 2-Clause. + +Changes: + +* Use CoreExt mixin for core Hash extensions. +* Add BasicStruct#key method (b/c #index is deprecated in Ruby 1.9). +* Deprecate SparseArray class. +* Switch license to BSD-2-Clause license. + + +## 1.4.0 / 2011-01-19 (Back To Basics) + +This release includes a copy of Ruby Facets' BasicObject class, which +fixes the loading bug of the previous version. This release also renames +OpenObject to BasicStruct, which is a much better description of what the +class actually provides. + +Changes: + +* Rename OpenObject to BasicStruct. +* Fix basicobject.rb loading issue. + + +## 1.3.0 / 2010-10-01 (Private Property) + +This release fixes a minor bug in CastingHash and adds a new +PropertyHash class. + +Changes: + +* 1 New Library + + * Added PropertyHash + +* 1 Bug Fix + + * Fixed CastingHash#new where #to_proc is called against NilClass + + +## 1.2.0 / 2010-06-04 (Fuzzy Wuzzy) + +This release makes two significant changes to the Hashery. +First, we have a new shiny library called FuzzyHash by +Joshua Hull. It's a cool idea that allows hash keys to be +regular expressions. Secondly, OpenCascade is now a subclass +of OpenHash rather than OpenObject (to go along with the +changes of the last release), and it now support cascading +within Arrays. + +Changes: + +* 1 New Library + + * FuzzyHash by Joshua Hull + +* 1 Major Enhancement + + * OpenCascade subclasses OpenHash and handles Array cascading. + + +## 1.1.0 / 2010-04-28 (Ugly Ducklings) + +A follow-up release of Hashery that adds two new libraries: +Association and SparseArray. Both of these may seem like odd +entries, but they each belong in a unique way. An Association +is akin to a single entry Hash --it represents a pairing. +While a SpareArray, though compatible with the Array class, +is completely under-pinned by a Hash in order to make it +efficient when no entries are given for a set of indexes, +hence "sparse". + +Changes: + +* 2 New Libraries + + * Added association.rb + * Added sparsearray.rb + + +## 1.0.0 / 2010-04-21 (Hatching Hashery) + +This is the first release of the Facets Hashery. +Most of included classes come directly from Ruby +Facets, so they have been around a while and are +in good working condition. + +Some improvements are planned for the next release. +In particular the OrderHash and Dictionary, which +presently have essentially the same coding, will +diverge to target slightly different use cases. + +Changes: + +* Happy Birthday! + diff --git a/bin/gems/hashery-2.1.2/Index.yml b/bin/gems/hashery-2.1.2/Index.yml new file mode 100644 index 00000000..5d882853 --- /dev/null +++ b/bin/gems/hashery-2.1.2/Index.yml @@ -0,0 +1,52 @@ +--- +name: + hashery + +version: + 2.1.2 + +title: + Hashery + +summary: + Facets-bread collection of Hash-like classes. + +description: + The Hashery is a tight collection of Hash-like classes. Included among its many + offerings are the auto-sorting Dictionary class, the efficient LRUHash, the + flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass + of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash + making it a snap to subclass and augment to fit any specific use case. + +authors: + - Trans + - Kirk Haines + - Robert Klemme + - Jan Molic + - George Moschovitis + - Jeena Paradies + - Erik Veenstra + +resources: + home: http://rubyworks.github.com/hashery + code: http://github.com/rubyworks/hashery + mail: http://groups.google.com/group/rubyworks-mailinglist + docs: http://rubydoc.info/github/rubyworks/hashery/master/frames + wiki: http://wiki.github.com/rubyworks/hashery + gems: http://rubygems.org/gems/hashery + +repositories: + upstream: "git://github.com/rubyworks/hashery.git" + +organizations: + - RubyWorks (http://rubyworks.github.com/) + +copyrights: + - 2010 Rubyworks (BSD-2-Clause) + +load_path: + - lib + - alt + +created: '2010-04-21' + diff --git a/bin/gems/hashery-2.1.2/LICENSE.txt b/bin/gems/hashery-2.1.2/LICENSE.txt new file mode 100644 index 00000000..ef220789 --- /dev/null +++ b/bin/gems/hashery-2.1.2/LICENSE.txt @@ -0,0 +1,23 @@ +BSD-2-Clause License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/bin/gems/hashery-2.1.2/NOTICE.txt b/bin/gems/hashery-2.1.2/NOTICE.txt new file mode 100644 index 00000000..5b16948d --- /dev/null +++ b/bin/gems/hashery-2.1.2/NOTICE.txt @@ -0,0 +1,46 @@ +All copyright holders have released their wares with a compatible +license or have given permission for their work to be distributed +under the same license as Hashery. + +Dictionary is based on OrderedHash by Jan Molic. + + OrderHash 2.0 Copyright (c) 2005 Jan Molic. + + +LRUHash is based on same by Robert Klemme + + Copyright (c) 2010 Robert Klemme + + +Memoizer is based on same by Erik Veenstra + + Copyright (c) 2006 Erik Veenstra + + +IniHash is based on Ini library by Jeena Paradies + + Copyright (c) 2007 Jeena Paradies + + +LinkedList is based on same by Kirk Haines + + Copyright (C) 2006 Kirk Haines + + +FuzzyHash is based on the same by Joshua Hull. + + Copyright (c) 2009 Joshua Hull + + +PathHash is based on SlashedHash by Daniel Parker + + HashMagic by Daniel Parker + Copyright (c) 2006 BehindLogic + http://hash_magic.rubyforge.org + +BasicObject is based on Jim Weirich's BlankSlate class. + + BlankSlate + Copyright 2004 by Jim Weirich (jim@weirichhouse.org). + All rights reserved. + diff --git a/bin/gems/hashery-2.1.2/README.md b/bin/gems/hashery-2.1.2/README.md new file mode 100644 index 00000000..ba11c164 --- /dev/null +++ b/bin/gems/hashery-2.1.2/README.md @@ -0,0 +1,128 @@ +# Hashery + +[![Gem Version](http://img.shields.io/gem/v/hashery.svg?style=flat)](http://rubygems.org/gem/hashery) +[![Build Status](http://img.shields.io/travis/rubyworks/hashery.svg?style=flat)](http://travis-ci.org/rubyworks/hashery) +[![Fork Me](http://img.shields.io/badge/scm-github-blue.svg?style=flat)](http://github.com/rubyworks/hashery) +[![Report Issue](http://img.shields.io/github/issues/rubyworks/hashery.svg?style=flat)](http://github.com/rubyworks/hashery/issues) +[![Gittip](http://img.shields.io/badge/gittip-$1/wk-green.svg?style=flat)](https://www.gittip.com/rubyworksorg/) + +[Homepage](http://rubyworks.github.com/hashery) · +[Development](http://github.com/rubyworks/hashery) · +[Report Issue](http://github.com/rubyworks/hashery/issues) · +[Chat](https://kiwiirc.com/client/irc.freenode.net/?nick=user1|?#rubyworks) + + +## Description + +Among Ruby Facets most common additions were an assortment +of Hash-like classes. To better support this collection +of libraries it was deemed prudent to create a new project +specifically for them. Hence the *Facets Hashery*. + +Included in this collection are the widely used OrderedHash, +the related but more featured Dictionary class, a number +of _open_ classes similar to the standard OpenStruct, +some variations of the standard Hash class and a few +other yummy morsels. + + +## Usage + +For instruction on usage, please see the individual library files +included in this collection and read the demo documents which give +examples of almost all features. + + +### Core Extensions + +Hashery adds four core extensions of Ruby's Hash class: `#retrieve`, +`#rekey`, `#rekey!` and `Hash.create`. The first is simply an alias +for `#[]`. The later two have proven too useful over the years to +omit. And the last is a convenience class method for populating +a new hash with another hash upon initialization. All of these are +sorely missing for Ruby itself, which is why they are provided here. + + +## Installation + +To install with RubyGems simply open a console and type: + + $ sudo gem install hashery + +Or add it as a dependency to your project's Gemfile: + + gem "hashery" + +Tarball packages are available for manual site installations +via [Ruby Setup](http://rubyworks.github.com/setup). + + +## Authors + +Developers who have contributed code to the project include: + +* Kirk Haines +* Joshua Hull +* Robert Klemme +* Jan Molic +* George Moschovitis +* Jeena Paradies +* Erik Veenstra + + +## Contributing + +Don't be a lump on a log. See an issue? Have a suggestion? Want to help? +Well *git* in there! + +### Communicating + +The project is hosted on Github so the easiest means of communication +is via the [Issues](http://github.com/rubyworks/hashery/issues) page. +For more direct communication you can try the **#rubyworks** IRC channel +on **irc.freenode.net**. + +    [![IRC](https://kiwiirc.com/buttons/irc.freenode.net/rubyworks.png)](https://kiwiirc.com/client/irc.freenode.net/?nick=user1|?#rubyworks) + +### Testing + +Hashery uses [QED](http://rubyworks.github.com/qed) and +[Lemon](http://rubyworks.github.com/lemon) test frameworks. +The QED framework to create well tested high-level documentation. +Run the QED specs via: + + $ qed -Ilib demo/ + +Lemon is used to create low-level unit tests. Run these via the Rubytest: + + $ rubytest -Ilib -Itest test/ + +### Patches + +Hashery's repository is hosted on [GitHub](http://github.com/rubyworks/hashery). +If you'd like to offer up a fix or feature, fork the repo and submit a pull +request (preferably in a topic branch). I assume you have heard +all the talk about proper [practices](https://github.com/rubyworks/rubyworks.github.com/wiki/GitHub-Best-Pactices), +so I won't bug you with it yet again. + +### Donations + +Yes, we FOSS programmers need to eat too! ;-) No seriously, any help you can +offer goes a long way toward continued development of Rubyworks projects, +including Hashery. Hop over to our [Gittips](https://www.gittip.com/rubyworksorg/) +page, or see the upper right-hand corner on the [Rubyworks](http://rubyworks.github.com) homepage. +Thanks! + + +## Copyrights + +Copyright (c) 2010 Rubyworks + +Licensed under the *BSD-2-Clause* license. + +See LICENSE.txt file for further details. + +Some libraries included in the Hashery have special copyrights +attributing specific authors. Please see each library script for +specifics and the NOTICE.txt file for an overview. + diff --git a/bin/gems/hashery-2.1.2/alt/hashery/castinghash.rb b/bin/gems/hashery-2.1.2/alt/hashery/castinghash.rb new file mode 100644 index 00000000..70076061 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/castinghash.rb @@ -0,0 +1 @@ +require 'hashery/casting_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/fuzzyhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/fuzzyhash.rb new file mode 100644 index 00000000..35258976 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/fuzzyhash.rb @@ -0,0 +1 @@ +require 'hashery/fuzzy_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/keyhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/keyhash.rb new file mode 100644 index 00000000..e41c9054 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/keyhash.rb @@ -0,0 +1 @@ +require 'hashery/key_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/linkedlist.rb b/bin/gems/hashery-2.1.2/alt/hashery/linkedlist.rb new file mode 100644 index 00000000..51609ef6 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/linkedlist.rb @@ -0,0 +1 @@ +require 'hashery/linked_list' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/lruhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/lruhash.rb new file mode 100644 index 00000000..a246fec7 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/lruhash.rb @@ -0,0 +1 @@ +require 'hashery/lru_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/opencascade.rb b/bin/gems/hashery-2.1.2/alt/hashery/opencascade.rb new file mode 100644 index 00000000..406314a6 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/opencascade.rb @@ -0,0 +1 @@ +require 'hashery/open_cascade' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/openhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/openhash.rb new file mode 100644 index 00000000..f48271c4 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/openhash.rb @@ -0,0 +1 @@ +require 'hashery/open_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/orderedhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/orderedhash.rb new file mode 100644 index 00000000..dbb8a11c --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/orderedhash.rb @@ -0,0 +1 @@ +require 'hashery/ordered_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/propertyhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/propertyhash.rb new file mode 100644 index 00000000..71964e21 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/propertyhash.rb @@ -0,0 +1 @@ +require 'hashery/property_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/queryhash.rb b/bin/gems/hashery-2.1.2/alt/hashery/queryhash.rb new file mode 100644 index 00000000..795ba912 --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/queryhash.rb @@ -0,0 +1 @@ +require 'hashery/query_hash' diff --git a/bin/gems/hashery-2.1.2/alt/hashery/statichash.rb b/bin/gems/hashery-2.1.2/alt/hashery/statichash.rb new file mode 100644 index 00000000..15da70fe --- /dev/null +++ b/bin/gems/hashery-2.1.2/alt/hashery/statichash.rb @@ -0,0 +1 @@ +require 'hashery/static_hash' diff --git a/bin/gems/hashery-2.1.2/demo/00_introduction.rdoc b/bin/gems/hashery-2.1.2/demo/00_introduction.rdoc new file mode 100644 index 00000000..1cc22205 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/00_introduction.rdoc @@ -0,0 +1,6 @@ += Hashery + +For the following demos the `hashery` script has +been preloaded and the Hashery namespace has been +included into the demo context for convenience. + diff --git a/bin/gems/hashery-2.1.2/demo/01_open_hash.rdoc b/bin/gems/hashery-2.1.2/demo/01_open_hash.rdoc new file mode 100644 index 00000000..2f43f79f --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/01_open_hash.rdoc @@ -0,0 +1,63 @@ += OpenHash + +An OpenHash is a Hash that provides +open+ access to its entries via method +calls. Writers (methods ending in =-marks) assign entries. Methods without +special puncuation will retrieve entries. + + o = OpenHash.new + o.a = 1 + o.b = 2 + o.a.assert == 1 + o.b.assert == 2 + +Writers always use a Symbol for keys in the underlying Hash. + + o.to_h.assert == { :a=>1, :b=>2 } + +All the usual Hash methods are still available in an OpenHash. + + c = o.map{ |k,v| [k,v] } + c.assert.include?([:a,1]) + c.assert.include?([:b,2]) + +And they are protected from being overridden by writers. + + o.map = 3 + o.map.refute == 3 + +Even so, the underlying Hash object does contain the entry even +when it cannot be accessed via a reader method. + + o.to_h.assert == { :a=>1, :b=>2, :map=>3 } + +We can see if a method is open or not via the `#open?` method. + + o.open?(:a).assert == true + o.open?(:map).assert == false + +For some usecases it may be necessary to give up access to one or +more Hash methods in favor of access to the hash entries. This can +be done using the `#open!` method. + + o.open!(:map, :merge) + o.map.assert == 3 + o.merge = 4 + o.merge.assert == 4 + +Becuase of nature of a writer, a certain set of Hash methods are always +protected, in particluar all methods buffered by underscore (e.g. `__id__`). +So these cannot be opened. + + expect ArgumentError do + o.open!(:__id__) + end + +Even though writers alwasy use Symbols as keys, because an OpenHash +is a true Hash object, any object can be used as a key internally. + + o = OpenHash.new + o[nil] = "Nothing" + o.to_h.assert == { nil=>"Nothing" } + +It simply cannot be accessible via a reader method. + diff --git a/bin/gems/hashery-2.1.2/demo/02_query_hash.rdoc b/bin/gems/hashery-2.1.2/demo/02_query_hash.rdoc new file mode 100644 index 00000000..d249bce8 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/02_query_hash.rdoc @@ -0,0 +1,17 @@ += QueryHash + +A QueryHash is a Hash that provides open access much like an OpenHash, but it limits readers +to bang and query methods (i.e. method ending in `!` or `?`). + + q = QueryHash.new + q.a = 1 + q.b = 2 + q.a?.assert == 1 + q.b?.assert == 2 + +By default keys are converted to strings. + + q.assert == { "a"=>1, "b"=>2 } + +A QueryHash is compatible with Ruby's standard Hash in every other respect. + diff --git a/bin/gems/hashery-2.1.2/demo/03_casting_hash.rdoc b/bin/gems/hashery-2.1.2/demo/03_casting_hash.rdoc new file mode 100644 index 00000000..249ab6b2 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/03_casting_hash.rdoc @@ -0,0 +1,12 @@ += CastingHash + +A CastingHash is a Hash that allows _casting_ procedures to +defined that the keys and values pass through upon assignment. + + c = CastingHash.new + c.cast_proc = lambda { |k,v| [k.to_s, v.to_s.upcase] } + + c[:a] = 'a' + + c.assert == {'a'=>'A'} + diff --git a/bin/gems/hashery-2.1.2/demo/04_static_hash.rdoc b/bin/gems/hashery-2.1.2/demo/04_static_hash.rdoc new file mode 100644 index 00000000..4ddb79ad --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/04_static_hash.rdoc @@ -0,0 +1,20 @@ += StaticHash + +A StaticHash is simply a Hash that can only be assigned +once per key. Once assigned a subsequent attempt to assign +a value to the same key will raise an ArgumentError. + + h = StaticHash.new + + h["x"] = 1 + + expect ArgumentError do + h["x"] = 2 + end + +The same error will be raised when using #update or #merge!. + + expect ArgumentError do + h.update( "x"=>3 ) + end + diff --git a/bin/gems/hashery-2.1.2/demo/05_key_hash.rdoc b/bin/gems/hashery-2.1.2/demo/05_key_hash.rdoc new file mode 100644 index 00000000..b9db1485 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/05_key_hash.rdoc @@ -0,0 +1,17 @@ += KeyHash + +The KeyHash is essentially the same as regular Hash but instead +of a `default_proc` the initializer takes the `key_proc` for +normalizing keys. + + kh = KeyHash.new{ |k| k.to_s.upcase } + kh[:a] = 1 + kh.to_h #=> ({'A'=>1}) + +By default, when no `key_proc` is given, it converts all keys to strings. + + kh = KeyHash.new + kh[:a] = 1 + kh.to_h #=> ({'a'=>1}) + + diff --git a/bin/gems/hashery-2.1.2/demo/06_open_cascade.rdoc b/bin/gems/hashery-2.1.2/demo/06_open_cascade.rdoc new file mode 100644 index 00000000..fe3e3fee --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/06_open_cascade.rdoc @@ -0,0 +1,64 @@ += OpenCascade + +The reason this class is labeled "cascade", is that every internal +Hash is transformed into an OpenCascade dynamically upon access. +This makes it easy to create _cascading_ references. + + h = { :x => { :y => { :z => 1 } } } + c = OpenCascade[h] + assert c.x.y.z == 1 + +As soon as you access a node it automatically becomes an OpenCascade. + + c = OpenCascade.new + assert(OpenCascade === c.r) + assert(OpenCascade === c.a.b) + +But if you set a node, then that will be it's value. + + c.a.b = 4 + assert c.a.b == 4 + +To query a node without causing the auto-creation of an OpenCasade +object, use the ?-mark. + + assert c.a.z? == nil + +OpenCascade also transforms Hashes within Arrays. + + h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 } + c = OpenCascade[h] + assert c.x.first.a == 1 + assert c.x.last.a == 2 + +Like OpenObject, OpenCascade allows you to insert entries as array +pairs. + + c = OpenCascade.new + c << [:x,8] + c << [:y,9] + + assert c.x == 8 + assert c.y == 9 + +Finally, you can call methods ending in a !-mark to access the +underlying hash (Note that these differ in behavior from the +built-in !-methods). + + bk = c.map!{ |k,v| k.to_s.upcase } + bk.sort.assert == ['X', 'Y'] + +So you can see that for the most an OpenCascade is just like +OpenHash, but it allows us to conveniently build open sub-layers +easily. + +Enumerable still works with OpenCascades too. + + h = {} + c = OpenCascade[:a=>1,:b=>{:c=>3}] + c.each do |k,v| + h[k] = v + end + OpenCascade.assert === h[:b] + + diff --git a/bin/gems/hashery-2.1.2/demo/07_fuzzy_hash.rdoc b/bin/gems/hashery-2.1.2/demo/07_fuzzy_hash.rdoc new file mode 100644 index 00000000..c4f5aa70 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/07_fuzzy_hash.rdoc @@ -0,0 +1,137 @@ += FuzzyHash + +Should accept strings and retrieve based on them. + + l = FuzzyHash.new + l['asd'] = 'qwe' + l['asd'].should == 'qwe' + +Should accept strings, but the second time you set the same string, it should overwrite. + + l = FuzzyHash.new + l['asd'] = 'asd' + l['asd'] = 'qwe' + l['asd'].should == 'qwe' + +Should accept regexs too. + + l = FuzzyHash.new + l[/asd.*/] = 'qwe' + l['asdqweasd'].should == 'qwe' + +Should accept regexs too, but the second time you set the same regex, it should overwrite. + + l = FuzzyHash.new + l[/asd/] = 'asd' + l[/asd/] = 'qwe' + l['asdqweasd'].should == 'qwe' + +Should accept regexs too with the match. + + l = FuzzyHash.new + l[/asd.*/] = 'qwe' + l.match_with_result('asdqweasd').should == ['qwe', 'asdqweasd'] + +Should accept regexs that match the whole strong too with the match. + + l = FuzzyHash.new + l[/asd/] = 'qwe' + l.match_with_result('asd').should == ['qwe', 'asd'] + +Should prefer string to regex matches. + + l = FuzzyHash.new + l['asd'] = 'qwe2' + l[/asd.*/] = 'qwe' + l['asd'].should == 'qwe2' + +Should allow nil keys. + + l = FuzzyHash.new + l[nil] = 'qwe2' + l['asd'] = 'qwe' + l['asd'].should == 'qwe' + l[nil].should == 'qwe2' + +Should allow boolean keys. + + l = FuzzyHash.new + l[false] = 'false' + l[true] = 'true' + l[/.*/] = 'everything else' + l[true].should == 'true' + l[false].should == 'false' + l['false'].should == 'everything else' + +Should pick between the correct regex. + + hash = FuzzyHash.new + hash[/^\d+$/] = 'number' + hash[/.*/] = 'something' + hash['123asd'].should == 'something' + +Should be able to delete by value for hash. + + l = FuzzyHash.new + l[nil] = 'qwe2' + l['asd'] = 'qwe' + l['asd'].should == 'qwe' + l[nil].should == 'qwe2' + l.delete_value('qwe2') + l[nil].should == nil + +Should be able to delete by value for regex. + + l = FuzzyHash.new + l[/qwe.*/] = 'qwe2' + l['asd'] = 'qwe' + l['asd'].should == 'qwe' + l['qweasd'].should == 'qwe2' + l.delete_value('qwe2') + l['qweasd'].should == nil + +Should iterate through the keys. + + l = FuzzyHash.new + l[/qwe.*/] = 'qwe2' + l['asd'] = 'qwe' + l['zxc'] = 'qwe' + l.keys.size.should == 3 + +Should iterate through the values. + + l = FuzzyHash.new + l[/qwe.*/] = 'qwe2' + l['asd'] = 'qwe' + l['zxc'] = 'qwelkj' + (['qwe2','qwe','qwelkj'] & l.values).size.should == 3 + +Should clear. + + l = FuzzyHash.new + l[/qwe.*/] = 'qwe2' + l['asd'] = 'qwe' + l['zxc'] = 'qwelkj' + l.clear + l.empty?.should == true + +Should handle equality. + + l_1 = FuzzyHash.new + l_1[/qwe.*/] = 'qwe2' + l_1['asd'] = 'qwelkj' + l_1['zxc'] = 'qwe' + l_2 = FuzzyHash.new + l_2['zxc'] = 'qwe' + l_2['asd'] = 'qwelkj' + l_2[/qwe.*/] = 'qwe2' + l_1.should == l_2 + +Should return the value when adding the value. + + h = FuzzyHash.new + (h[/asd/] = '123').should == '123' + (h['qwe'] = '123').should == '123' + +That's It. + diff --git a/bin/gems/hashery-2.1.2/demo/08_propery_hash.rdoc b/bin/gems/hashery-2.1.2/demo/08_propery_hash.rdoc new file mode 100644 index 00000000..89aafaea --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/08_propery_hash.rdoc @@ -0,0 +1,34 @@ += PropertyHash + +The Property hash can be used an object in itself. + + h = PropertyHash.new(:a=>1, :b=>2) + h[:a] #=> 1 + h[:a] = 3 + h[:a] #=> 3 + +Becuase the properties are fixed, if we try to set a key that is not present, +then we will get an error. + + expect ArgumentError do + h[:x] = 5 + end + +The PropertyHash can also be used as a superclass. + + class MyPropertyHash < PropertyHash + property :a, :default => 1 + property :b, :default => 2 + end + + h = MyPropertyHash.new + h[:a] #=> 1 + h[:a] = 3 + h[:a] #=> 3 + +Again, if we try to set key that was not fixed, then we will get an error. + + expect ArgumentError do + h[:x] = 5 + end + diff --git a/bin/gems/hashery-2.1.2/demo/10_association.rdoc b/bin/gems/hashery-2.1.2/demo/10_association.rdoc new file mode 100644 index 00000000..d8c29d43 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/10_association.rdoc @@ -0,0 +1,59 @@ += Association + +An Association is a class for creating simple pairings. + + require 'hashery/association' + +An Association can bew created through the usual means +of instantiation. + + Association.new(:a, :b) + +Or the shortcut method #>> can be used in most cases. + + :x >> :z + +An association provides two methods to access its content, #index and #value. + + a = 'foo' >> 'bar' + + a.index.assert == 'foo' + a.value.assert == 'bar' + +Associations can be used to create ordered-hashes via normal +arrays. + + keys = [] + vals = [] + + ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ] + + ohash.each{ |k,v| keys << k ; vals << v } + + keys.assert == ['A','B','C'] + vals.assert == ['3','2','1'] + + +Becuase Associations are objects in themselves more complex +collections can also be created. + + complex = [ + 'parent' >> 'child', + 'childless', + 'another_parent' >> [ + 'subchildless', + 'subparent' >> 'subchild' + ] + ] + +An experimental feature of Association keeps a cache of all defined associations. + + o = Object.new + o >> :a + o >> :b + o >> :c + + o.associations.assert == [:a, :b, :c] + +However this feature will probably be deprecated. + diff --git a/bin/gems/hashery-2.1.2/demo/applique/ae.rb b/bin/gems/hashery-2.1.2/demo/applique/ae.rb new file mode 100644 index 00000000..ebab99a8 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/applique/ae.rb @@ -0,0 +1,2 @@ +require 'ae' +require 'ae/should' diff --git a/bin/gems/hashery-2.1.2/demo/applique/hashery.rb b/bin/gems/hashery-2.1.2/demo/applique/hashery.rb new file mode 100644 index 00000000..b0015268 --- /dev/null +++ b/bin/gems/hashery-2.1.2/demo/applique/hashery.rb @@ -0,0 +1,3 @@ +require 'hashery' + +include Hashery diff --git a/bin/gems/hashery-2.1.2/lib/hashery.rb b/bin/gems/hashery-2.1.2/lib/hashery.rb new file mode 100644 index 00000000..1255296c --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery.rb @@ -0,0 +1,24 @@ +module Hashery + VERSION = "2.1.0" +end + +require 'hashery/core_ext' + +#require 'hashery/basic_struct' +require 'hashery/casting_hash' +require 'hashery/crud_hash' +require 'hashery/dictionary' +require 'hashery/fuzzy_hash' +require 'hashery/ini_hash' +require 'hashery/linked_list' +require 'hashery/lru_hash' +require 'hashery/key_hash' +require 'hashery/open_cascade' +require 'hashery/open_hash' +#require 'hashery/ordered_hash' +#require 'hashery/ostructable' +require 'hashery/property_hash' +require 'hashery/query_hash' +require 'hashery/static_hash' + + diff --git a/bin/gems/hashery-2.1.2/lib/hashery.yml b/bin/gems/hashery-2.1.2/lib/hashery.yml new file mode 100644 index 00000000..ead4e7a2 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery.yml @@ -0,0 +1,78 @@ +--- +revision: 2013 +type: ruby +sources: +- Index.yml +- Gemfile +authors: +- name: Trans + email: transfire@gmail.com +- name: Kirk Haines +- name: Robert Klemme +- name: Jan Molic +- name: George Moschovitis +- name: Jeena Paradies +- name: Erik Veenstra +organizations: +- name: RubyWorks (http://rubyworks.github.com/) +requirements: +- groups: + - development + - test + version: ">= 0" + name: qed +- groups: + - development + - test + version: ">= 0" + name: lemon +- groups: + - development + - test + version: ">= 0" + name: rubytest-cli +conflicts: [] +alternatives: [] +resources: +- type: home + uri: http://rubyworks.github.com/hashery + label: Homepage +- type: code + uri: http://github.com/rubyworks/hashery + label: Source Code +- type: mail + uri: http://groups.google.com/group/rubyworks-mailinglist + label: Mailing List +- type: docs + uri: http://rubydoc.info/github/rubyworks/hashery/master/frames + label: Documentation +- type: wiki + uri: http://wiki.github.com/rubyworks/hashery + label: User Guide +- type: gems + uri: http://rubygems.org/gems/hashery +repositories: +- name: upstream + scm: git + uri: git://github.com/rubyworks/hashery.git +categories: [] +copyrights: +- holder: Rubyworks + year: '2010' + license: BSD-2-Clause +customs: [] +paths: + lib: + - lib + - alt +name: hashery +title: Hashery +version: 2.1.2 +summary: Facets-bread collection of Hash-like classes. +description: The Hashery is a tight collection of Hash-like classes. Included among + its many offerings are the auto-sorting Dictionary class, the efficient LRUHash, + the flexible OpenHash and the convenient KeyHash. Nearly every class is a subclass + of the CRUDHash which defines a CRUD model on top of Ruby's standard Hash making + it a snap to subclass and augment to fit any specific use case. +created: '2010-04-21' +date: '2016-05-01' diff --git a/bin/gems/hashery-2.1.2/lib/hashery/association.rb b/bin/gems/hashery-2.1.2/lib/hashery/association.rb new file mode 100644 index 00000000..5b937a24 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/association.rb @@ -0,0 +1,222 @@ +module Hashery + + # TODO: Should associations be singleton? + # + # TODO: Is it really wise to keep a table of all associations? + + # Association is a general binary association that allows one + # object to be associated with another. It has a variety of uses, + # such as linked-lists, simple ordered maps and mixed collections, + # among them. + # + # NOTE: This class is still fairly experimental. And it is not + # loaded along with the other Hashery libraries when using + # `require 'hashery'`. It must be required independently. + # + # Associations can be used to draw simple relationships. + # + # :Apple >> :Fruit + # :Apple >> :Red + # + # :Apple.associations #=> [ :Fruit, :Red ] + # + # It can also be used for simple lists of ordered pairs. + # + # c = [ :a >> 1, :b >> 2 ] + # c.each { |k,v| puts "#{k} associated with #{v} } + # + # produces + # + # a associated with 1 + # b associated with 2 + # + # The method :>> is used to construct the association. + # It is a rarely used method so it is generally available. + # But you can't use it for any of the following classes + # becuase they use #>> for other things. + # + # Bignum + # Fixnum + # Date + # IPAddr + # Process::Status + # + class Association + include Comparable + + class << self + # + # Store association references. + # + # Returns `Hash` of all associaitons. + # + def reference + @reference ||= Hash.new{ |h,k,v| h[k]=[] } + end + + # + # Shortcut for #new. + # + # index - The "index key" of the association. + # value - The "value" of the association. + # + # Returns `Association`. + # + def [](index, value) + new(index, value) + end + + #def new(index, value) + # lookup[[index, value]] ||= new(index, value) + #end + + #def lookup + # @lookup ||= {} + #end + end + + # + # The "index key" of the association. + # + attr_accessor :index + + # + # The "value" of the association. + # + attr_accessor :value + + # + # Initialize new Association. + # + # index - The "index key" of the association. + # value - The "value" of the association. + # + def initialize(index, value=nil) + @index = index + @value = value + + unless index.associations.include?(value) + index.associations << value + end + end + + # + # Compare the values of two associations. + # + # TODO: Comparions with non-associations? + # + # assoc - The other `Association`. + # + # Returns [Integer] `1`, `0`, or `-1`. + # + def <=>(assoc) + return -1 if self.value < assoc.value + return 1 if self.value > assoc.value + return 0 if self.value == assoc.value + end + + # + # Invert association, making the index the value and vice-versa. + # + # Returns [Array] with two-elements reversed. + # + def invert! + temp = @index + @index = @value + @value = temp + end + + # + # Produce a string representation. + # + # Returns [String]. + # + def to_s + return "#{index} >> #{value}" + end + + # + # Produce a literal code string for creating an association. + # + # Returns [String]. + # + def inspect + "#{index.inspect} >> #{value.inspect}" + end + + # + # Convert to two-element associative array. + # + # Returns [Array] Two-element Array of index and value pair. + # + def to_ary + [index, value] + end + + # + # Object extensions. + # + module Kernel + + # + # Define an association for +self+. + # + # to - The value of the association. + # + # Returns [Association]. + # + def >>(to) + Association.new(self, to) + end + + # + # List of associations for this object. + # + # Returns an `Array` of `Associations`. + # + def associations + Association.reference[self] + end + + end + + end + +end + +class Object #:nodoc: + include Hashery::Association::Kernel +end + +#-- +# Setup the >> method in classes that use it already. +# +# This is a bad idea b/c it can cause backward compability issues. +# +# class Bignum +# alias_method( :rshift, :>>) if method_defined?(:>>) +# remove_method :>> +# end +# +# class Fixnum +# alias_method( :rshift, :>>) if method_defined?(:>>) +# remove_method :>> +# end +# +# class Date +# alias_method( :months_later, :>>) if method_defined?(:>>) +# remove_method :>> +# end +# +# class IPAddr +# alias_method( :rshift, :>>) if method_defined?(:>>) +# remove_method :>> +# end +# +# class Process::Status +# alias_method( :rshift, :>>) if method_defined?(:>>) +# remove_method :>> +# end +#++ + +# Copyright (c) 2005 Rubyworks, Thomas Sawyer diff --git a/bin/gems/hashery-2.1.2/lib/hashery/casting_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/casting_hash.rb new file mode 100644 index 00000000..67c2aa82 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/casting_hash.rb @@ -0,0 +1,164 @@ +require 'hashery/crud_hash' + +module Hashery + + # CastingHash is just like CRUDHash, except that both keys and values + # can be passed through casting procedures. + # + class CastingHash < CRUDHash + + # + # Like `#new` but can take a priming Hash or Array-pairs. + # + # hash - Hash-like object. + # + # Examples + # + # CastingHash[:a,1,:b,2] + # + # Returns `CastingHash`. + # + def self.[](hash) + s = new + hash.each{ |k,v| s[k] = v } + s + end + + # + # Unlike traditional Hash a CastingHash's block argument + # coerces key/value pairs when #store is called. + # + # default - Default value. + # cast_proc - Casting procedure. + # + def initialize(default=nil, &cast_proc) + @cast_proc = cast_proc + super(default, &nil) + end + + # + # The cast procedure. + # + # proc - Casting procedure. + # + # Returns `Proc` used for casting. + # + def cast_proc(&proc) + @cast_proc = proc if proc + @cast_proc + end + + # + # Set `cast_proc`. This procedure must take two arguments (`key, value`) + # and return the same. + # + # proc - Casting procedure. + # + # Returns +proc+. + # + def cast_proc=(proc) + raise ArgumentError unless Proc === proc or NilClass === proc + @cast_proc = proc + end + + # + # CRUD method for create and update. Unlike the parent class + # the key, value pair are passed threw the cast_proc before + # being set in the underlying hash table. + # + # key - Key of entry. + # value - Value of entry. + # + # Returns the +value+. + # + def store(key, value) + super(*cast_pair(key, value)) + end + + # + # Replace current entries with those from another Hash, + # or Hash-like object. Each entry is run through the + # casting procedure as it is added. + # + # other - Hash-like object. + # + # Returns +self+. + # + def replace(other) + super cast(other) + end + + # + # Convert the CastingHash to a regular Hash. + # + # Returns an ordinary `Hash`. + # + def to_hash + h = {}; each{ |k,v| h[k] = v }; h + end + + # + # Returns an ordinary `Hash`. + # + alias_method :to_h, :to_hash + + # + # Recast all entries via the cast procedure. + # + # TODO: Isn't this the same as `#rehash`? + # + # Returns +self+. + # + def recast! + replace self + end + + private + + # + # If `cast_proc` is defined then use it to process key-value pair, + # otherwise return them as is. + # + # key - Key of entry. + # value - Value of entry. + # + # Returns `Array` of key-value pair. + # + def cast_pair(key, value) + if cast_proc + return cast_proc.call(key, value) + else + return key, value + end + end + + # + # Cast a given +hash+ according to the `#key_proc` and `#value_proc`. + # + # hash - A `Hash` or anything the responds to `#each` like a hash. + # + # Returns a recasted `Hash`. + # + def cast(hash) + h = {} + hash.each do |k,v| + k, v = cast_pair(k, v) + h[k] = v + end + h + end + + end + +end + +# TODO: Should we add #to_casting_hash to Hash classs? + +#class Hash +# +# # Convert a Hash to a CastingHash. +# def to_casting_hash(value_cast=nil, &key_cast) +# CastingHash.new(self, value_cast, &key_cast) +# end +# +#end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/core_ext.rb b/bin/gems/hashery-2.1.2/lib/hashery/core_ext.rb new file mode 100644 index 00000000..bdd4f5cd --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/core_ext.rb @@ -0,0 +1,119 @@ +class Hash + + # + # Create a hash given an `initial_hash`. + # + # initial_hash - Hash or hash-like object to use as priming data. + # block - Procedure used by initialize (e.g. default_proc). + # + # Returns a `Hash`. + # + def self.create(initial_hash={}, &block) + o = new &block + o.update(initial_hash) + o + end + + # + # Like #fetch but returns the results of calling `default_proc`, if defined, + # otherwise `default`. + # + # key - Hash key to lookup. + # + # Returns value of Hash entry or `nil`. + # + def retrieve(key) + fetch(key, default_proc ? default_proc[self, key] : default) + end + + # + # Convert to Hash. + # + def to_hash + dup # -or- `h = {}; each{ |k,v| h[k] = v }; h` ? + end \ + unless method_defined?(:to_hash) + + # + # For a Hash, `#to_h` is the same as `#to_hash`. + # + alias :to_h :to_hash \ + unless method_defined?(:to_h) + + # + # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). + # + # key_map - Hash of old key to new key. + # block - Procedure to convert keys, which can take just the key + # or both key and value as arguments. + # + # Examples + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo.inspect #=> { "name"=>"Gavin", "wife"=>:Lisa } + # + # Returns `Hash`. + # + def rekey(key_map=nil, &block) + if !(key_map or block) + block = lambda{|k| k.to_sym} + end + + key_map ||= {} + + hash = {} + + (keys - key_map.keys).each do |key| + hash[key] = self[key] + end + + key_map.each do |from, to| + hash[to] = self[from] if key?(from) + end + + hash2 = {} + + if block + case block.arity + when 0 + raise ArgumentError, "arity of 0 for #{block.inspect}" + when 2 + hash.each do |k,v| + nk = block.call(k,v) + hash2[nk] = v + end + else + hash.each do |k,v| + nk = block[k] + hash2[nk] = v + end + end + else + hash2 = hash + end + + hash2 + end + + # + # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). + # + # key_map - Hash of old key to new key. + # block - Procedure to convert keys, which can take just the key + # or both key and value as arguments. + # + # Examples + # + # foo = { :name=>'Gavin', :wife=>:Lisa } + # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } + # foo #=> { "name"=>"Gavin", "wife"=>:Lisa } + # + # Returns `Hash`. + # + def rekey!(key_map=nil, &block) + replace(rekey(key_map, &block)) + end + +end + diff --git a/bin/gems/hashery-2.1.2/lib/hashery/crud_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/crud_hash.rb new file mode 100644 index 00000000..906fb24b --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/crud_hash.rb @@ -0,0 +1,405 @@ +require 'hashery/core_ext' + +module Hashery + + # The CRUDHash is essentailly the same as the Hash class, but it reduces the + # the set of necessary methods to the fundametal CRUD requirements. All other + # methods route through these CRUD methods. This is a better general design, + # although it is, of course, a little bit slower. The utility of this class + # becomes appearent when subclassing or delegating, as only a handful of methods + # need to be changed for all other methods to work accordingly. + # + # In addition to the CRUD features, CRUDHash supports a `#key_proc`, akin to + # `#default_proc`, that can be used to normalize keys. + # + # The CRUD methods are: + # + # * key? + # * fetch + # * store + # * delete + # + # In addition to these main methods, there are these supporting "CRUD" methods: + # + # * default + # * default_proc + # * default_proc= + # * key_proc + # * key_proc= + # + class CRUDHash < ::Hash + + # + # Dummy object for null arguments. + # + NA = Object.new + + # + # This method is overridden to ensure that new entries pass through + # the `#store` method. + # + # hash - [#each] Single Hash, associative array or just a list of pairs. + # + def self.[](*hash) + h = new + if hash.size == 1 + hash.first.each do |k,v| + h.store(k, v) + end + else + hash.each do |(k,v)| + h.store(k, v) + end + end + h + end + + # + # Alternate to #new which auto-creates sub-dictionaries as needed. + # By default the `default_proc` procuced a empty Hash and is + # self-referential so every such Hash also has the same `default_proc`. + # + # args - Pass-thru arguments to `#new`. + # block - Alternate internal procedure for default proc. + # + # Examples + # + # d = CRUDHash.auto + # d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}} + # + # Returns `Hash`. + # + def self.auto(*args, &block) + if block + leet = lambda { |hsh, key| hsh[key] = block.call(hsh, key) } + else + leet = lambda { |hsh, key| hsh[key] = new(&leet) } + end + new(*args, &leet) + end + + # + # Set `key_proc`. + # + # Examples + # + # ch = CRUDHash.new + # ch.key_proc = Proc.new{ |key| key.to_sym } + # + # Returns `Proc`. + # + def key_proc=(proc) + raise ArgumentError unless Proc === proc or NilClass === proc + @key_proc = proc + end + + # + # Get/set `key_proc`. + # + # Examples + # + # ch = CRUDHash.new + # ch.key_proc + # + # Returns `Proc`. + # + def key_proc(&block) + @key_proc = block if block + @key_proc + end + + # + # Allow `#default_proc` to take a block. + # + # block - The `Proc` object to set the `default_proc`. + # + # Returns `Proc`, the `default_proc`. + # + def default_proc(&block) + self.default_proc = block if block + super() + end + + # + # CRUD method for checking if key exists. + # + # key - Hash key to lookup. + # + # Returns `true/false`. + # + def key?(key) + super cast_key(key) + end + + # + # CRUD method for read. This method gets the value for a given key. + # An error is raised if the key is not present, but an optional argument + # can be provided to be returned instead. + # + # key - Hash key to lookup. + # default - Value to return if key is not present. + # + # Raises KeyError when key is not found and default has not been given. + # + # Returns the `Object` that is the Hash entry's value. + # + def fetch(key, *default) + super(cast_key(key), *default) + end + + # + # CRUD method for create and update. + # + # key - The `Object` to act as indexing key. + # value - The `Object` to associate with key. + # + # Returns +value+. + # + def store(key, value) + super(cast_key(key), value) + end + + # + # CRUD method for delete. + # + # key - Hash key to remove. + # + # Returns value of deleted Hash entry. + # + def delete(key) + super cast_key(key) + end + + # END OF CRUD METHODS + + # + # Like #fetch but returns the results of calling `default_proc`, if defined, + # otherwise `default`. + # + # key - Hash key to lookup. + # + # Returns value of Hash entry or `nil`. + # + def retrieve(key) + if key?(key) + fetch(key) + else + default_proc ? default_proc.call(self, key) : default + end + end + + # + # Method for reading value. Returns `nil` if key is not present. + # + # Note that this method used to be the CRUD method instead of #retrieve. Complaints about + # #read being indicative of an IO object (though in my opinion that is a bad asumption) have + # led to this method's deprecation. + # + # key - Hash key to lookup. + # + # Returns value of Hash entry. + # + def read(key) + warn "The #read method as been deprecated. Use #retrieve instead." + retrieve(key) + end + + # + # Update Hash with +assoc+. + # + # assoc - Two-element `Array` or a `Hash`. + # + # Returns +assoc+. + # + def <<(assoc) + case assoc + when Hash + update(assoc) + when Array + assoc.each_slice(2) do |(k,v)| + store(k,v) + end + else + raise ArgumentError # or TypeError ? + end + end + + # + # Operator for `#retrieve`. + # + # key - Index key to lookup. + # + # Returns `Object` value of key. + # + def [](key) + retrieve(key) + end + + # + # Operator for `#store`. + # + # key - The `Object` to act as indexing key. + # value - The `Object` to associate with key. + # + # Returns +value+. + # + def []=(key,value) + store(key,value) + end + + # + # Update the Hash with another hash. + # + # other - Other hash or hash-like object to add to the hash. + # + # Returns +self+. + # + def update(other) + other.each do |k,v| + store(k, v) + end + self + end + + # + # Alias for `#update`. + # + alias merge! update + + # + # Merge the Hash with another hash, returning a new Hash. + # + # other - Other hash or hash-like object to add to the hash. + # + # Returns `Hash`. + # + def merge(other) + #super(other.rekey{ |key| cast_key(key) }) + copy = dup + other.each{ |k,v| copy.store(k, v) } + copy + end + + # + # Iterate over each hash pair. + # + def each #:yield: + if block_given? + keys.each do |k| + yield(k, retrieve(k)) + end + else + to_enum(:each) + end + end + + # + # Alias for #each. + # + alias each_pair each + + # + # Alias for `#key?`. + # + alias has_key? key? + + # + # Alias for `#key?`. + # + alias member? key? + + # + # Alias for `#key?`. + # + alias include? key? # why isn't it an alias for `#has_value?` ? + + # + # Replace current entries with those from another Hash, + # or Hash-like object. Each entry is run through the + # casting procedure as it is added. + # + # other - Hash-like object. + # + # Returns +self+. + # + def replace(other) + super cast(other) + end + + # + # Get the values at. + # + # keys - List of keys to lookup. + # + # Returns `Array` of values. + # + def values_at(*keys) + super *keys.map{ |key| cast_key(key) } + end + + # Convert CRUDHash to regular Hash. + # + # TODO: Since a CRUDHash is a subclass of Hash should #to_hash just `#dup` + # insted of converting to traditional Hash? + # + def to_hash + h = {}; each{ |k,v| h[k] = v }; h + end #unless method_defined?(:to_hash) + + # + # Convert CRUDHash to regular Hash. + # + # TODO: Since a CRUDHash is a subclass of Hash should #to_h just `#dup` + # insted of converting to traditional Hash? + # + # Returns `Hash`. + # + alias :to_h :to_hash + + private + + # + # Cast a given `hash` in accordance to the `#key_proc`. + # + # hash - Any object the responds to `#each` like a Hash. + # + # Returns `Hash`. + # + def cast(hash) + h = {} + hash.each do |k,v| + h[cast_key(k)] = v + end + h + end + + # + # Callback for normalizing hash keys. + # + # key - Index key. + # + # Returns key after passing through the `key_proc`. + # + def cast_key(key) + @key_proc ? @key_proc.call(key) : key + end + + # TODO: Consider value callback procs for future version of CRUDHash. + # + # # + # # Callback for writing value. + # # + # def cast_write(value) + # @write_proc ? @write_proc.call(value) : value + # end + # + # # + # # Callback for reading value. + # # + # def cast_read(value) + # @read_proc ? @read_proc.call(value) : value + # end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/dictionary.rb b/bin/gems/hashery-2.1.2/lib/hashery/dictionary.rb new file mode 100644 index 00000000..15834a9c --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/dictionary.rb @@ -0,0 +1,641 @@ +module Hashery + + # The Dictionary class is a Hash that preserves order. + # So it has some array-like extensions also. By defualt + # a Dictionary object preserves insertion order, but any + # order can be specified including alphabetical key order. + # + # Using a Dictionary is almost the same as using a Hash. + # + # # You can do simply + # hsh = Dictionary.new + # hsh['z'] = 1 + # hsh['a'] = 2 + # hsh['c'] = 3 + # p hsh.keys #=> ['z','a','c'] + # + # # or using Dictionary[] method + # hsh = Dictionary['z', 1, 'a', 2, 'c', 3] + # p hsh.keys #=> ['z','a','c'] + # + # # but this don't preserve order + # hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3] + # p hsh.keys #=> ['a','c','z'] + # + # # Dictionary has useful extensions: push, pop and unshift + # p hsh.push('to_end', 15) #=> true, key added + # p hsh.push('to_end', 30) #=> false, already - nothing happen + # p hsh.unshift('to_begin', 50) #=> true, key added + # p hsh.unshift('to_begin', 60) #=> false, already - nothing happen + # p hsh.keys #=> ["to_begin", "a", "c", "z", "to_end"] + # p hsh.pop #=> ["to_end", 15], if nothing remains, return nil + # p hsh.keys #=> ["to_begin", "a", "c", "z"] + # p hsh.shift #=> ["to_begin", 30], if nothing remains, return nil + # + # == Notes + # + # * You can use #order_by to set internal sort order. + # * #<< takes a two element [k,v] array and inserts. + # * Use ::auto which creates Dictionay sub-entries as needed. + # * And ::alpha which creates a new Dictionary sorted by key. + # + # == Acknowledgments + # + # Dictionary is a port of OrderHash 2.0 Copyright (c) 2005 Jan Molic. + # + # People who have contributed to this class since then include: + # + # * Andrew Johnson (merge, to_a, inspect, shift and Hash[]) + # * Jeff Sharpe (reverse and reverse!) + # * Thomas Leitner (has_key? and key?) + # + # OrderedHash is public domain. + # + class Dictionary + + include Enumerable + + class << self + + # + # Create a new Dictionary storing argument pairs as an initial mapping. + # + # TODO: Is this needed? Doesn't the super class do this? + # + # Returns Dictionary instance. + # + def [](*args) + hsh = new + if Hash === args[0] + hsh.replace(args[0]) + elsif (args.size % 2) != 0 + raise ArgumentError, "odd number of elements for Hash" + else + while !args.empty? + hsh[args.shift] = args.shift + end + end + hsh + end + + # + # Like #new but the block sets the order instead of the default. + # + # Dictionary.new_by{ |k,v| k } + # + def new_by(*args, &blk) + new(*args).order_by(&blk) + end + + # + # Alternate to #new which creates a dictionary sorted by the key as a string. + # + # d = Dictionary.alphabetic + # d["z"] = 1 + # d["y"] = 2 + # d["x"] = 3 + # d #=> {"x"=>3,"y"=>2,"z"=>2} + # + # This is equivalent to: + # + # Dictionary.new.order_by { |key,value| key.to_s } + # + def alphabetic(*args, &block) + new(*args, &block).order_by { |key,value| key.to_s } + end + + # DEPRECATED: Use #alphabetic instead. + alias :alpha :alphabetic + + # + # Alternate to #new which auto-creates sub-dictionaries as needed. + # + # Examples + # + # d = Dictionary.auto + # d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}} + # + def auto(*args) + #AutoDictionary.new(*args) + leet = lambda { |hsh, key| hsh[key] = new(&leet) } + new(*args, &leet) + end + end + + # + # New Dictiionary. + # + def initialize(*args, &blk) + @order = [] + @order_by = nil + if blk + dict = self # This ensures automatic key entry effect the + oblk = lambda{ |hsh, key| blk[dict,key] } # dictionary rather then just the interal hash. + @hash = Hash.new(*args, &oblk) + else + @hash = Hash.new(*args) + end + end + + # + # Order of keys. + # + # Returns [Array]. + # + def order + reorder if @order_by + @order + end + + # + # Keep dictionary sorted by a specific sort order. + # + # block - Ordering procedure. + # + # Returns +self+. + # + def order_by( &block ) + @order_by = block + order + self + end + + # + # Keep dictionary sorted by key. + # + # d = Dictionary.new.order_by_key + # d["z"] = 1 + # d["y"] = 2 + # d["x"] = 3 + # d #=> {"x"=>3,"y"=>2,"z"=>2} + # + # This is equivalent to: + # + # Dictionary.new.order_by { |key,value| key } + # + # The initializer Dictionary#alpha also provides this. + # + # Returns +self+. + # + def order_by_key + if block_given? + @order_by = Proc.new{ |k,v| yield(k) } + else + @order_by = Proc.new{ |k,v| k } + end + order + self + end + + # + # Keep dictionary sorted by value. + # + # d = Dictionary.new.order_by_value + # d["z"] = 1 + # d["y"] = 2 + # d["x"] = 3 + # d #=> {"x"=>3,"y"=>2,"z"=>2} + # + # This is equivalent to: + # + # Dictionary.new.order_by { |key,value| value } + # + def order_by_value + if block_given? + @order_by = Proc.new{ |k,v| yield(v) } + else + @order_by = Proc.new{ |k,v| v } + end + order + self + end + + # + # Re-apply the sorting procedure. + # + def reorder + if @order_by + assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by) + @order = assoc.collect{ |k,v| k } + end + @order + end + + #def ==( hsh2 ) + # return false if @order != hsh2.order + # super hsh2 + #end + + # + # Is the dictionary instance equivalent to another? + # + def ==(hsh2) + if hsh2.is_a?( Dictionary ) + @order == hsh2.order && + @hash == hsh2.instance_variable_get("@hash") + else + false + end + end + + # + # Lookup entry with key. + # + def [] key + @hash[ key ] + end + + # + # Featch entry given +key+. + # + def fetch(key, *a, &b) + @hash.fetch(key, *a, &b) + end + + # + # Store operator. + # + # h[key] = value + # + # Or with additional index. + # + # h[key,index] = value + # + def []=(k, i=nil, v=nil) + if v + insert(i,k,v) + else + store(k,i) + end + end + + # + # Insert entry into dictionary at specific index position. + # + # index - [Integer] Position of order placement. + # key - [Object] Key to associate with value. + # value - [Object] Value to associate with key. + # + # Returns `value` stored. + # + def insert(index, key, value) + @order.insert(index, key) + @hash.store(key, value) + end + + # + # Add entry into dictionary. + # + # Returns `value`. + # + def store(key, value) + @order.push(key) unless @hash.has_key?(key) + @hash.store(key, value) + end + + # + # Clear dictionary of all entries. + # + def clear + @order = [] + @hash.clear + end + + # + # Delete the entry with given +key+. + # + def delete(key) + @order.delete(key) + @hash.delete(key) + end + + # + # Iterate over each key. + # + def each_key + order.each { |k| yield( k ) } + self + end + + # + # Iterate over each value. + # + def each_value + order.each { |k| yield( @hash[k] ) } + self + end + + # + # Iterate over each key-value pair. + # + def each + order.each { |k| yield( k,@hash[k] ) } + self + end + + alias each_pair each + + # + # Delete entry if it fits conditional block. + # + def delete_if + order.clone.each { |k| delete k if yield(k,@hash[k]) } + self + end + + # + # List of all dictionary values. + # + # Returns [Array]. + # + def values + ary = [] + order.each { |k| ary.push @hash[k] } + ary + end + + # + # List of all dictionary keys. + # + # Returns [Array]. + # + def keys + order + end + + # + # Invert the dictionary. + # + # Returns [Dictionary] New dictionary that is inverse of the original. + # + def invert + hsh2 = self.class.new + order.each { |k| hsh2[@hash[k]] = k } + hsh2 + end + + # + # Reject entries based on give condition block and return + # new dictionary. + # + # Returns [Dictionary]. + # + def reject(&block) + self.dup.delete_if(&block) + end + + # + # Reject entries based on give condition block. + # + # Returns [Hash] of rejected entries. + # + # FIXME: This looks like it is implemented wrong!!! + # + def reject!( &block ) + hsh2 = reject(&block) + self == hsh2 ? nil : hsh2 + end + + # + # Replace dictionary entries with new table. + # + def replace(hsh2) + case hsh2 + when Dictionary + @order = hsh2.order + @hash = hsh2.to_h + when Hash + @hash = hsh2 + @order = @hash.keys + else + @hash = hsh2.to_h + @order = @hash.keys + end + reorder + end + + # + # Remove entry from the to top of dictionary. + # + def shift + key = order.first + key ? [key,delete(key)] : super + end + + # + # Push entry on to the top of dictionary. + # + def unshift( k,v ) + unless @hash.include?( k ) + @order.unshift( k ) + @hash.store( k,v ) + true + else + false + end + end + + # + # Same as #push. + # + def <<(kv) + push(*kv) + end + + # + # Push entry on to bottom of the dictionary. + # + def push(k,v) + unless @hash.include?( k ) + @order.push( k ) + @hash.store( k,v ) + true + else + false + end + end + + # + # Pop entry off the bottom of dictionary. + # + def pop + key = order.last + key ? [key,delete(key)] : nil + end + + # + # Inspection string for Dictionary. + # + # Returns [String]. + # + def inspect + ary = [] + each {|k,v| ary << k.inspect + "=>" + v.inspect} + '{' + ary.join(", ") + '}' + end + + # + # Duplicate dictionary. + # + # Returns [Dictionary]. + # + def dup + a = [] + each{ |k,v| a << k; a << v } + self.class[*a] + end + + # + # Update dictionary with other hash. + # + # Returns self. + # + def update( hsh2 ) + hsh2.each { |k,v| self[k] = v } + reorder + self + end + + alias :merge! update + + # + # Merge other hash creating new dictionary. + # + # Returns [Dictionary]. + # + def merge(hsh2) + self.dup.update(hsh2) + end + + # + # Select items from dictiornary. + # + # Returns [Array] of two-element arrays. + # + def select + ary = [] + each { |k,v| ary << [k,v] if yield k,v } + ary + end + + # + # Reverse the order of the dictionary. + # + # Returns self. + # + def reverse! + @order.reverse! + self + end + + # + # Reverse the order of duplicte dictionary. + # + # Returns [Dictionary]. + # + def reverse + dup.reverse! + end + + # + # Get/set initial entry value. + # + def first(x=nil) + return @hash[order.first] unless x + order.first(x).collect { |k| @hash[k] } + end + + # + # Get/set last entry value. + # + def last(x=nil) + return @hash[order.last] unless x + order.last(x).collect { |k| @hash[k] } + end + + # + # Number of items in the dictionary. + # + def length + @order.length + end + + alias :size :length + + # + # Is the dictionary empty? + # + # Returns `true` or `false`. + # + def empty? + @hash.empty? + end + + # + # Does the dictionary have a given +key+. + # + # Returns `true` or `false`. + # + def has_key?(key) + @hash.has_key?(key) + end + + # + # Does the dictionary have a given +key+. + # + # Returns `true` or `false`. + # + def key?(key) + @hash.key?(key) + end + + # + # Convert to array. + # + # Returns [Array] of two-element arrays. + # + def to_a + ary = [] + each { |k,v| ary << [k,v] } + ary + end + + # + # Convert to array then to string. + # + # Returns [String]. + # + def to_s + self.to_a.to_s + end + + # + # Get a duplicate of the underlying hash table. + # + # Returns [Hash]. + # + def to_hash + @hash.dup + end + + # + # Get a duplicate of the underlying hash table. + # + # Returns [Hash]. + # + def to_h + @hash.dup + end + + protected + + # + # Underlying hash table. + # + def hash_table + @hash + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/fuzzy_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/fuzzy_hash.rb new file mode 100644 index 00000000..63a6544d --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/fuzzy_hash.rb @@ -0,0 +1,206 @@ +require 'set' + +module Hashery + + # FuzzyHash is a weird hash with special semantics for regex keys. + # + # This is useful when you want to have a lookup table that can either contain strings or regexes. + # For instance, you might want a catch all for certain regexes that perform a certain logic. + # + # >> hash = FuzzyHash.new + # >> hash[/^\d+$/] = 'number' + # >> hash[/.*/] = 'something' + # >> hash['chunky'] = 'bacon' + # >> hash['foo'] = 'vader' + # + # >> hash['foo'] + # << 'vader' + # >> hash['food'] + # << 'something' + # >> hash['123'] + # << 'number' + # + # This class is based on Joshua Hull's original FuzzyHash class. + # + class FuzzyHash + + # + # + # + def initialize(init_hash = nil) + @fuzzies = [] + @hash_reverse = {} + @fuzzies_reverse = {} + @fuzzy_hash = {} + @hash = {} + init_hash.each{ |key,value| self[key] = value } if init_hash + end + + # + # + # + def clear + hash.clear + fuzzies.clear + hash_reverse.clear + fuzzies_reverse.clear + end + + # + # + # + def size + hash.size + fuzzies.size + end + + alias_method :count, :size + + # + # + # + def ==(o) + o.is_a?(FuzzyHash) + o.send(:hash) == hash && + o.send(:fuzzies) == fuzzies + end + + # + # + # + def empty? + hash.empty? && fuzzies.empty? + end + + # + # + # + def keys + hash.keys + fuzzy_hash.keys + end + + # + # + # + def values + hash.values + fuzzies.collect{|r| r.last} + end + + # + # + # + def each + hash.each{|k,v| yield k,v } + fuzzies.each{|v| yield v.first, v.last } + end + + # + # + # + def delete_value(value) + hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0])) + end + + # + # + # + def []=(key, value) + if Regexp === key + fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash} + fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash} + hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash} + + fuzzy_hash[key] = value + fuzzies << [key, value] + reset_fuzz_test! + fuzzies_reverse[value] = [fuzzies.size - 1, key, value] + else + hash[key] = value + hash_reverse.delete_if{|k,v| v.hash == key.hash} + hash_reverse[value] = key + end + value + end + + # + # + # + def replace(src, dest) + if hash_reverse.key?(src) + key = hash_reverse[src] + hash[key] = dest + hash_reverse.delete(src) + hash_reverse[dest] = key + elsif fuzzies_reverse.key?(src) + key = fuzzies_reverse[src] + fuzzies[rkey[0]] = [rkey[1], dest] + fuzzies_reverse.delete(src) + fuzzies_reverse[dest] = [rkey[0], rkey[1], dest] + end + end + + # + # + # + def [](key) + (hash.key?(key) && hash[key]) || + ((lookup = fuzzy_lookup(key)) && lookup && lookup.first) || + fuzzy_hash[key] + end + + # + # + # + def match_with_result(key) + if hash.key?(key) + [hash[key], key] + else + fuzzy_lookup(key) + end + end + + private + + attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash + attr_writer :fuzz_test + + # + # + # + def reset_fuzz_test! + self.fuzz_test = nil + end + + # + # + # + def fuzz_test + unless @fuzz_test + @fuzz_test = Object.new + @fuzz_test.instance_variable_set(:'@fuzzies', fuzzies) + method = " + def match(str) + case str\n + " + fuzzies.each_with_index do |reg, index| + method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];" + end + method << "end\nend\n" + @fuzz_test.instance_eval method + end + @fuzz_test + end + + # + # + # + def fuzzy_lookup(key) + if !fuzzies.empty? && (value = fuzz_test.match(key)) + value + end + end + + end + +end + +# Copyright (c) 2009 Joshua Hull diff --git a/bin/gems/hashery-2.1.2/lib/hashery/ini_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/ini_hash.rb new file mode 100644 index 00000000..ee84f5a2 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/ini_hash.rb @@ -0,0 +1,321 @@ +module Hashery + + # Hash class with methods to read from and write into ini files. + # + # A ini file is a text file in a specific format, + # it may include several fields which are sparated by + # field headlines which are enclosured by "[]". + # Each field may include several key-value pairs. + # + # Each key-value pair is represented by one line and + # the value is sparated from the key by a "=". + # + # == Examples + # + # === Example ini file + # + # # this is the first comment which will be saved in the comment attribute + # mail=info@example.com + # domain=example.com # this is a comment which will not be saved + # [database] + # db=example + # user=john + # passwd=very-secure + # host=localhost + # # this is another comment + # [filepaths] + # tmp=/tmp/example + # lib=/home/john/projects/example/lib + # htdocs=/home/john/projects/example/htdocs + # [ texts ] + # wellcome=Wellcome on my new website! + # Website description = This is only a example. # and another comment + # + # === Example object + # + # Ini#comment stores: + # + # "this is the first comment which will be saved in the comment attribute" + # + # Ini's internal hash stores: + # + # { + # "mail" => "info@example.com", + # "domain" => "example.com", + # "database" => { + # "db" => "example", + # "user" => "john", + # "passwd" => "very-secure", + # "host" => "localhost" + # }, + # "filepaths" => { + # "tmp" => "/tmp/example", + # "lib" => "/home/john/projects/example/lib", + # "htdocs" => "/home/john/projects/example/htdocs" + # } + # "texts" => { + # "wellcome" => "Wellcome on my new website!", + # "Website description" => "This is only a example." + # } + # } + # + # As you can see this module gets rid of all comments, linebreaks + # and unnecessary spaces at the beginning and the end of each + # field headline, key or value. + # + # === Using the object + # + # Using the object is stright forward: + # + # ini = IniHash.new("path/settings.ini") + # ini["mail"] = "info@example.com" + # ini["filepaths"] = { "tmp" => "/tmp/example" } + # ini.comment = "This is\na comment" + # puts ini["filepaths"]["tmp"] + # # => /tmp/example + # ini.write() + # + # == Acknowlegements + # + # IniHash is based on ini.rb. + # + # Copyright (C) 2007 Jeena Paradies + + class IniHash + + # TODO: Use class method for loading from file, not initializer. + + # + # NOTE: In future versions, `#new` will not take a path, and `#load` + # will have to be used. + # + def self.load(path, load=true) + new(path, load) + end + + # + # The hash which holds all INI data. + # + attr_accessor :inihash + + # + # The string which holds the comments on the top of the file + # + attr_accessor :comment + + # + # Creating a new IniHash object. + # + # path - is a path to the ini file + # load - if nil restores the data if possible + # if true restores the data, if not possible raises an error + # if false does not resotre the data + # + def initialize(path, load=nil) + @path = path if String === path + @inihash = (Hash === path ? path.dup : {}) + + if load or ( load.nil? and FileTest.readable_real? @path ) + restore() + end + end + + # + # Retrive the ini data for the key +key+ + # + def [](key) + @inihash[key] + end + + # + # Set the ini data for the key +key+ + # + # key - Index key. + # value - The value to index. + # + # Returns +value+. + # + def []=(key, value) + #raise TypeError, "String expected" unless key.is_a? String + key = key.to_str + + #raise TypeError, "String or Hash expected" unless value.is_a? String or value.is_a? Hash + value = value.to_str unless Hash === value + + @inihash[key] = value + end + + # + # Restores the data from file into the object + # + def restore + @inihash = IniHash.read_from_file(@path) + @comment = IniHash.read_comment_from_file(@path) + end + + # + # Store data from the object in the file. + # + def save + IniHash.write_to_file(@path, @inihash, @comment) + end + + # + # Deprecated: Save INI data to file path. Use #save instead. + # + def update + warn 'IniHash#update is deprecated for this use, use IniHash#save instead.' + save + end + + # + # Convert to hash by duplicating the underlying hash table. + # + def to_h + @inihash.dup + end + + alias :inspect :to_s + + # + # Turn a hash (up to 2 levels deepness) into a ini string + # + # inihash - Hash representing the ini File. Default is a empty hash. + # + # Returns a string in the ini file format. + # + def to_s + str = "" + inihash.each do |key, value| + if value.is_a? Hash + str << "[#{key.to_s}]\n" + value.each do |under_key, under_value| + str << "#{under_key.to_s}=#{under_value.to_s unless under_value.nil?}\n" + end + else + str << "#{key.to_s}=#{value.to_s unless value.nil?}\n" + end + end + str + end + + # + # Delegate missing mthods to underlying Hash. + # + # TODO: Sublcass Hash instead of delegating. + # + def method_missing(s,*a,&b) + @inihash.send(s, *a, &b) if @inihash.respond_to?(s) + end + + # + # Reading data from file + # + # path - a path to the ini file + # + # Returns a `Hash` which represents the data from the file. + # + def self.read_from_file(path) + raise "file not found - #{path}" unless File.file?(path) + + inihash = {} + headline = nil + + IO.foreach(path) do |line| + line = line.strip.split(/#/)[0].to_s + + # read it only if the line doesn't begin with a "=" and is long enough + unless line.length < 2 and line[0,1] == "=" + + # it's a headline if the line begins with a "[" and ends with a "]" + if line[0,1] == "[" and line[line.length - 1, line.length] == "]" + + # get rid of the [] and unnecessary spaces + headline = line[1, line.length - 2 ].strip + inihash[headline] = {} + else + key, value = line.split(/=/, 2) + + key = key.strip unless key.nil? + value = value.strip unless value.nil? + + unless headline.nil? + inihash[headline][key] = value + else + inihash[key] = value unless key.nil? + end + end + end + end + + inihash + end + + # + # Reading comments from file + # + # path - a path to the INI file + # + # Returns a `String` with the comments from the beginning of the INI file. + # + def self.read_comment_from_file(path) + comment = "" + + IO.foreach(path) do |line| + line.strip! + + break unless line[0,1] == "#" or line == "" + + comment_line = line[1, line.length].to_s + comment << "#{comment_line.strip}\n" + end + + comment + end + + # + # Writing a ini hash into a file + # + # path - Path to the INI file. + # inihash - Hash representing the ini File. Default is a empty hash. + # comment - String with comments which appear on the + # top of the file. Each line will get a "#" before. + # Default is no comment. + # + def self.write_to_file(path, inihash={}, comment=nil) + raise TypeError, "String expected" unless comment.is_a? String or comment.nil? + + raise TypeError, "Hash expected" unless inihash.is_a? Hash + File.open(path, "w") { |file| + + unless comment.nil? + comment.each do |line| + file << "# #{line}" + end + end + + file << IniHash.text(inihash) + } + end + + # + # Turn a hash (up to 2 levels deepness) into a ini string + # + # inihash - Hash representing the ini File. Default is a empty hash. + # + # Returns a String in the ini file format. + # + # TODO: Rename `IniHash.text` method to something else ? + # + def self.text(inihash={}) + new(inihash).to_s + end + + class << self + # @deprecated + alias_method :to_s, :text + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/key_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/key_hash.rb new file mode 100644 index 00000000..ef37753d --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/key_hash.rb @@ -0,0 +1,61 @@ +require 'hashery/crud_hash' + +module Hashery + + # The KeyHash class is a Hash class which accepts a block for + # normalizing keys. + # + # The KeyHash class is essentially the same as a normal Hash. + # But notice the significant distinction of indifferent key + # access. + # + # s = KeyHash.new + # s[:x] = 1 + # s[:x] #=> 1 + # s['x'] #=> 1 + # + # We can see that internally the key has indeed been converted + # to a String. + # + # s.to_h #=> {'x'=>1 } + # + # By default all keys are converted to strings. This has two advantages + # over a regular Hash is many usecases. First it means hash entries have + # indifferent access. 1, "1" and :1 are all + # equivalent --any object that defines #to_s can be used as a key. + # Secondly, since strings are garbage collected so will default KeyHash + # objects. + # + # But keys can be normalized by any function. Theses functions can be quite + # unique. + # + # h = KeyHash.new(0){ |k| k.to_i } + # h[1.34] += 1 + # h[1.20] += 1 + # h[1.00] += 1 + # h #=> { 1 => 3 } + # + class KeyHash < CRUDHash + + # + # Unlike a regular Hash, a KeyHash's block sets the `key_proc` rather + # than the `default_proc`. + # + def initialize(*default, &block) + super(*default) + @key_proc = block || Proc.new{ |k| k.to_s } + end + + end + +end + +#class Hash +# # +# # Convert a Hash to a KeyHash object. +# # +# def to_keyhash +# Hashery::KeyHash[self] +# end +#end + diff --git a/bin/gems/hashery-2.1.2/lib/hashery/linked_list.rb b/bin/gems/hashery-2.1.2/lib/hashery/linked_list.rb new file mode 100644 index 00000000..a134da71 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/linked_list.rb @@ -0,0 +1,249 @@ +require 'enumerator' + +module Hashery + + # LinkedList implements a simple doubly linked list with efficient + # hash-like element access. + # + # This is a simple linked-list implementation with efficient random + # access of data elements. It was inspired by George Moscovitis' + # LRUCache implementation found in Facets 1.7.30, but unlike the + # linked-list in that cache, this one does not require the use of a + # mixin on any class to be stored. The linked-list provides the + # push, pop, shift, unshift, first, last, delete and length methods + # which work just like their namesakes in the Array class, but it + # also supports setting and retrieving values by key, just like a + # hash. + # + # LinkedList was ported from the original in Kirk Hanes IOWA web framework. + # + # == Acknowledgements + # + # LinkedList is based on the LinkedList library by Kirk Haines. + # + # Copyright (C) 2006 Kirk Haines . + # + class LinkedList + + include Enumerable + + # Represents a single node of the linked list. + # + class Node + attr_accessor :key, :value, :prev_node, :next_node + + def initialize(key=nil,value=nil,prev_node=nil,next_node=nil) + @key = key + @value = value + @prev_node = prev_node + @next_node = next_node + end + end + + # + # Initialize new LinkedList instance. + # + def initialize + @head = Node.new + @tail = Node.new + @lookup = Hash.new + + node_join(@head,@tail) + end + + # + # Lookup entry by key. + # + def [](key) + @lookup[key].value + end + + # + # Add node to linked list. + # + def []=(k,v) + if @lookup.has_key?(k) + @lookup[k].value = v + else + n = Node.new(k,v,@head,@head.next_node) + node_join(n,@head.next_node) + node_join(@head,n) + @lookup[k] = n + end + v + end + + # + # Is linked list empty? + # + def empty? + @lookup.empty? + end + + # + # Remove node idenified by key. + # + def delete(key) + n = @lookup.delete(key) + v = n ? node_purge(n) : nil + v + end + + # + # Get value of first node. + # + def first + @head.next_node.value + end + + # + # Get value of last node. + # + def last + @tail.prev_node.value + end + + # + # + # + def shift + k = @head.next_node.key + n = @lookup.delete(k) + node_delete(n) if n + end + + # + # + # + def unshift(v) + if @lookup.has_key?(v) + n = @lookup[v] + node_delete(n) + node_join(n,@head.next_node) + node_join(@head,n) + else + n = Node.new(v,v,@head,@head.next_node) + node_join(n,@head.next_node) + node_join(@head,n) + @lookup[v] = n + end + v + end + + # + # + # + def pop + k = @tail.prev_node.key + n = @lookup.delete(k) + node_delete(n) if n + end + + # + # + # + def push(v) + if @lookup.has_key?(v) + n = @lookup[v] + node_delete(n) + node_join(@tail.prev_node,n) + node_join(n,@tail) + else + n = Node.new(v,v,@tail.prev_node,@tail) + node_join(@tail.prev_node,n) + node_join(n,@tail) + @lookup[v] = n + end + v + end + + alias :<< :push + + # + # Produces an Array of key values. + # + # Returns [Array]. + # + def queue + r = [] + n = @head + while (n = n.next_node) and n != @tail + r << n.key + end + r + end + + # + # Converts to an Array of node values. + # + # Returns [Array]. + # + def to_a + r = [] + n = @head + while (n = n.next_node) and n != @tail + r << n.value + end + r + end + + # + # Number of nodes. + # + def length + @lookup.length + end + + alias size length + + # + # Iterate over nodes, starting with the head node + # and ending with the tail node. + # + def each + n = @head + while (n = n.next_node) and n != @tail + yield(n.key,n.value) + end + end + + private + + # + # Delete a node. + # + # n - A node. + # + def node_delete(n) + node_join(n.prev_node,n.next_node) + v = n.value + end + + # + # Purge a node. + # + # n - A node. + # + def node_purge(n) + node_join(n.prev_node,n.next_node) + v = n.value + n.value = nil + n.key = nil + n.next_node = nil + n.prev_node = nil + v + end + + # Join two nodes. + # + # a - A node. + # b - A node. + # + def node_join(a,b) + a.next_node = b + b.prev_node = a + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/lru_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/lru_hash.rb new file mode 100644 index 00000000..f21387be --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/lru_hash.rb @@ -0,0 +1,363 @@ +require 'enumerator' + +module Hashery + + # Hash with LRU expiry policy. There are at most max_size elements in a + # LRUHash. When adding more elements old elements are removed according + # to LRU policy. + # + # Based on Robert Klemme's LRUHash class. + # + # LRUHash, Copyright (c) 2010 Robert Klemme. + # + class LRUHash + + include Enumerable + + attr_reader :max_size + + attr_accessor :default + attr_accessor :default_proc + attr_accessor :release_proc + + # + # Initialize new LRUHash instance. + # + # max_size - + # default_value - + # block - + # + def initialize(max_size, default_value=nil, &block) + @max_size = normalize_max(max_size) + @default = default_value + @default_proc = block + + @h = {} + @head = Node.new + @tail = front(Node.new) + end + + # + # Iterate over each pair. + # + def each_pair + if block_given? + each_node do |n| + yield [n.key, n.value] + end + else + enum_for :each_pair + end + end + + # + # Same as each pair. + # + alias each each_pair + + # + # Iterate over each key. + # + def each_key + if block_given? + each_node do |n| + yield n.key + end + else + enum_for :each_key + end + end + + # + # Iterate over each value. + # + def each_value + if block_given? + each_node do |n| + yield n.value + end + else + enum_for :each_value + end + end + + # + # Size of the hash. + # + def size + @h.size + end + + # + # + # + def empty? + @head.succ.equal? @tail + end + + # + # + # + def fetch(key, &b) + n = @h[key] + + if n + front(n).value + else + (b || FETCH)[key] + end + end + + # + # + # + def [](key) + fetch(key) do |k| + @default_proc ? @default_proc[self, k] : default + end + end + + # + # + # + def keys + @h.keys + end + + # + # + # + def values + @h.map {|k,n| n.value} + end + + # + # + # + def has_key?(key) + @h.has_key? key + end + + alias key? has_key? + alias member? has_key? + alias include? has_key? + + # + # + # + def has_value?(value) + each_pair do |k, v| + return true if value.eql? v + end + + false + end + + alias value? has_value? + + def values_at(*key_list) + key_list.map {|k| self[k]} + end + + # + # + # + def assoc(key) + n = @h[key] + + if n + front(n) + [n.key, n.value] + end + end + + # + # + # + def rassoc(value) + each_node do |n| + if value.eql? n.value + front(n) + return [n.key, n.value] + end + end + nil + end + + # + # + # + def key(value) + pair = rassoc(value) and pair.first + end + + # + # + # + def store(key, value) + # same optimization as in Hash + key = key.dup.freeze if String === key && !key.frozen? + + n = @h[key] + + unless n + if size == max_size + # reuse node to optimize memory usage + n = delete_oldest + n.key = key + n.value = value + else + n = Node.new key, value + end + + @h[key] = n + end + + front(n).value = value + end + + alias []= store + + # + # + # + def delete(key) + n = @h[key] and remove_node(n).value + end + + # + # + # + def delete_if + each_node do |n| + remove_node n if yield n.key, n.value + end + end + + # + # + # + def max_size=(limit) + limit = normalize_max(limit) + + while size > limit + delete_oldest + end + + @max_size = limit + end + + # + # + # + def clear + until empty? + delete_oldest + end + + self + end + + # + # + # + def to_s + s = nil + each_pair {|k, v| (s ? (s << ', ') : s = '{') << k.to_s << '=>' << v.to_s} + s ? (s << '}') : '{}' + end + + alias inspect to_s + + private + + # + # Iterate nodes. + # + def each_node + n = @head.succ + + until n.equal? @tail + succ = n.succ + yield n + n = succ + end + + self + end + + # + # Move node to front. + # + # node - [Node] + # + def front(node) + node.insert_after(@head) + end + + # + # Remove the node and invoke release_proc + # if set + # + # node - [Node] + # + def remove_node(node) + n = @h.delete(node.key) + n.unlink + release_proc and release_proc[n.key, n.value] + n + end + + # + # Remove the oldest node returning the node + # + def delete_oldest + n = @tail.pred + raise "Cannot delete from empty hash" if @head.equal? n + remove_node n + end + + # + # Normalize the argument in order to be usable as max_size + # criterion is that n.to_i must be an Integer and it must + # be larger than zero. + # + # n - [#to_i] max size + # + def normalize_max(n) + n = n.to_i + raise ArgumentError, 'Invalid max_size: %p' % n unless Integer === n && n > 0 + n + end + + # + FETCH = Proc.new {|k| raise KeyError, 'key not found'} + + # A single node in the doubly linked LRU list of nodes. + Node = Struct.new :key, :value, :pred, :succ do + def unlink + pred.succ = succ if pred + succ.pred = pred if succ + self.succ = self.pred = nil + self + end + + def insert_after(node) + raise 'Cannot insert after self' if equal? node + return self if node.succ.equal? self + + unlink + + self.succ = node.succ + self.pred = node + + node.succ.pred = self if node.succ + node.succ = self + + self + end + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/open_cascade.rb b/bin/gems/hashery-2.1.2/lib/hashery/open_cascade.rb new file mode 100644 index 00000000..1305974c --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/open_cascade.rb @@ -0,0 +1,167 @@ +require 'hashery/open_hash' + +module Hashery + + # OpenCascade is subclass of OpenHash. It differs in a few + # significant ways. The reason this class is called "cascade" is that + # every internal Hash is transformed into an OpenCascade dynamically + # upon access. This makes it easy to create "cascading" references. + # + # h = { :x => { :y => { :z => 1 } } } + # c = OpenCascade[h] + # c.x.y.z #=> 1 + # + # As soon as you access a node it automatically becomes an OpenCascade. + # + # c = OpenCascade.new #=> # + # c.r #=> # + # c.a.b #=> # + # + # But if you set a node, then that will be that value. + # + # c.a.b = 4 #=> 4 + # + # To query a node without causing the auto-creation of an OpenCasade + # instance, use the `?`-mark. + # + # c.a.z? #=> nil + # + # OpenCascade also transforms Hashes within Arrays. + # + # h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 } + # c = OpenCascade[h] + # c.x.first.a.assert == 1 + # c.x.last.a.assert == 2 + # + # Finally, you can set call a private method via bang methods using the `!`-mark. + # + # c = OpenCascade.new #=> # + # c.each = 4 + # c.each! do |k,v| + # ... + # end + # + # c.x!(4).y!(3) #=> #4, :y=>3}> + # + # Subclassing OpenCascade with cause the new subclass to become the class that + # is auto-created. If this is not the behavior desired, consider using delegation + # instead of subclassing. + # + class OpenCascade < OpenHash + + # + #def self.[](hash) + # oc = new + # hash.each{ |(k,v)| oc.store(k,v) } + # oc + #end + + # + # Initialize new OpenCascade instance. + # + # default - The usual default object. + # + def initialize(*default) + @read = {} + + leet = lambda { |h,k| h[k] = self.class.new(&leet) } + super(*default, &leet) + end + + # + # Alias for original read method. + # + alias :retrieve! :retrieve + + # + # Read value given a +key+. + # + # key - Index key to lookup. + # + # Returns value. + # + def retrieve(key) + ckey = cast_key(key) + if @read[ckey] + super(key) + else + @read[ckey] = store(key, cast_value(super(key))) + end + end + + # + # + # + def method_missing(sym, *args, &blk) + type = sym.to_s[-1,1] + name = sym.to_s.gsub(/[=!?]$/, '').to_sym + + case type + when '=' + store(name, args.first) + when '?' + key?(name) ? retrieve!(name) : nil # key?(name) + when '!' + __send__(name, *args, &blk) + else + #if key?(name) + retrieve(name) + #else + # #default = OpenCascade.new #self.class.new + # #default = default_proc ? default_proc.call(self, name) : default + # store(name, read(name)) + #end + end + end + + def respond_to?(sym, include_private = false) + sym != :to_ary && super + end + + #def each + # super do |key, entry| + # yield([key, transform_entry(entry)]) + # end + #end + + private + + # + # Cast value, such that Hashes are converted to OpenCascades. + # And Hashes in Arrays are converted to OpenCascades as well. + # + def cast_value(entry) + case entry + when Hash + e = OpenCascade.new + e.key_proc = key_proc if key_proc + e.merge!(entry) + e + when Array + entry.map{ |e| cast_value(e) } + else + entry + end + end + + end + +end + + +#-- +# Last, when an entry is not found, 'null' is returned rather then 'nil'. +# This allows for run-on entries withuot error. Eg. +# +# o = OpenCascade.new +# o.a.b.c #=> null +# +# Unfortuately this requires an explict test for null? in 'if' conditions. +# +# if o.a.b.c.null? # true if null +# if o.a.b.c.nil? # true if nil or null +# if o.a.b.c.not? # true if nil or null or false +# +# So be sure to take that into account. +#++ + diff --git a/bin/gems/hashery-2.1.2/lib/hashery/open_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/open_hash.rb new file mode 100644 index 00000000..3a26cacc --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/open_hash.rb @@ -0,0 +1,145 @@ +require 'hashery/crud_hash' + +module Hashery + + # OpenHash is a Hash, but also supports open properties much like + # OpenStruct. + # + # Only names that are name methods of Hash can be used as open slots. + # To open a slot for a name that would otherwise be a method, the + # method needs to be made private. The `#open!` method can be used + # to handle this. + # + # Examples + # + # o = OpenHash.new + # o.open!(:send) + # o.send = 4 + # + class OpenHash < CRUDHash + + alias :object_class :class + + #FILTER = /(^__|^\W|^instance_|^object_|^to_)/ + #methods = Hash.instance_methods(true).select{ |m| m !~ FILTER } + #methods = methods - [:each, :inspect, :send] # :class, :as] + #private *methods + + # + # Initialize new OpenHash instance. + # + # TODO: Maybe `safe` should be the first argument? + # + def initialize(default=nil, safe=false, &block) + @safe = safe + super(*[default].compact, &block) + end + + # + # If safe is set to true, then public methods cannot be overriden + # by hash keys. + # + attr_accessor :safe + + # + # Alias to original store method. + # + #alias :store! :store + + # + # Index `value` to `key`. Unless safe mode, will also open up the + # key if it is not already open. + # + # key - Index key to associate with value. + # value - Value to be associate with key. + # + # Returns +value+. + # + def store(key, value) + #open!(key) + super(key, value) + end + + # + # Open up a slot that that would normally be a Hash method. + # + # The only methods that can't be opened are ones starting with `__`. + # + # methods - [Array] method names + # + # Returns Array of slot names that were opened. + # + def open!(*methods) + # Only select string and symbols, any other type of key is allowed, + # it just won't be accessible via dynamic methods. + methods = methods.select{ |x| String === x || Symbol === x } + if methods.any?{ |m| m.to_s.start_with?('__') } + raise ArgumentError, "cannot open shadow methods" + end + # only public methods need be made protected + methods = methods.map{ |x| x.to_sym } + methods = methods & public_methods(true).map{ |x| x.to_sym } + if @safe + raise ArgumentError, "cannot set public method" unless methods.empty? + else + (class << self; self; end).class_eval{ protected *methods } + end + methods + end + + # @deprecated + alias :omit! :open! + + # + # Is a slot open? + # + # method - [String,Symbol] method name + # + # Returns `true` or `false`. + # + def open?(method) + methods = public_methods(true).map{ |m| m.to_sym } + ! methods.include?(method.to_sym) + end + + # + # Make specific Hash methods available for use that have previously opened. + # + # methods - [Array] method names + # + # Returns +methods+. + # + def close!(*methods) + (class << self; self; end).class_eval{ public *methods } + methods + end + + # + # + # + def method_missing(s,*a, &b) + type = s.to_s[-1,1] + name = s.to_s.sub(/[!?=]$/, '') + key = name.to_sym + + case type + when '=' + store(key, a.first) + when '?' + key?(key) + when '!' + # call an underlying private method + # TODO: limit this to omitted methods (from included) ? + __send__(name, *a, &b) + else + #if key?(key) + retrieve(key) + #else + # super(s,*a,&b) + #end + end + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/ordered_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/ordered_hash.rb new file mode 100644 index 00000000..6089c203 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/ordered_hash.rb @@ -0,0 +1,174 @@ +module Hashery + + # OrderedHash is a simple ordered hash implmentation, for users of + # Ruby 1.8.7 or less. + # + # NOTE: As of Ruby 1.9+ this class is not needed, since + # Ruby 1.9's standard Hash tracks inseration order. + # + # This implementation derives from the same class in + # ActiveSupport library. + # + class OrderedHash < ::Hash + + def to_yaml_type + "!tag:yaml.org,2002:omap" + end + + def to_yaml(opts = {}) + YAML.quick_emit(self, opts) do |out| + out.seq(taguri, to_yaml_style) do |seq| + each do |k, v| + seq.add(k => v) + end + end + end + end + + # Hash is ordered in Ruby 1.9! + if RUBY_VERSION < '1.9' + + def initialize(*args, &block) + super + @keys = [] + end + + def self.[](*args) + ordered_hash = new + + if (args.length == 1 && args.first.is_a?(Array)) + args.first.each do |key_value_pair| + next unless (key_value_pair.is_a?(Array)) + ordered_hash[key_value_pair[0]] = key_value_pair[1] + end + + return ordered_hash + end + + unless (args.size % 2 == 0) + raise ArgumentError.new("odd number of arguments for Hash") + end + + args.each_with_index do |val, ind| + next if (ind % 2 != 0) + ordered_hash[val] = args[ind + 1] + end + + ordered_hash + end + + def initialize_copy(other) + super(other) + @keys = other.keys + end + + def []=(key, value) + @keys << key unless key?(key) + super(key, value) + end + + def delete(key) + if has_key? key + index = @keys.index(key) + @keys.delete_at(index) + end + super(key) + end + + def delete_if + super + sync_keys! + self + end + + def reject! + super + sync_keys! + self + end + + def reject(&block) + dup.reject!(&block) + end + + def keys + @keys.dup + end + + def values + @keys.collect{ |key| self[key] } + end + + def to_hash + self + end + + def to_a + @keys.map{ |key| [ key, self[key] ] } + end + + def each_key + @keys.each{ |key| yield(key) } + end + + def each_value + @keys.each{ |key| yield(self[key]) } + end + + def each + @keys.each{ |key| yield(key, self[key]) } + end + + alias_method :each_pair, :each + + def clear + super + @keys.clear + self + end + + def shift + k = @keys.first + v = delete(k) + [k, v] + end + + def merge!(other_hash) + other_hash.each{ |k,v| self[k] = v } + self + end + + def merge(other_hash) + dup.merge!(other_hash) + end + + # When replacing with another hash, the initial order of our + # keys must come from the other hash, ordered or not. + def replace(other) + super + @keys = other.keys + self + end + + def inspect + "#" + end + + private + + def sync_keys! + @keys.delete_if{ |k| !key?(k) } + end + + end + + end + +end + +require 'yaml' + +YAML.add_builtin_type("omap") do |type, val| + OrderedHash[val.map(&:to_a).map(&:first)] +end + diff --git a/bin/gems/hashery-2.1.2/lib/hashery/path_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/path_hash.rb new file mode 100644 index 00000000..9a587f87 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/path_hash.rb @@ -0,0 +1,238 @@ +module Hashery + + # A PathHash is a hash whose values can be accessed in the normal manner, + # or with keys that are slash (`/`) separated strings. To get the whole hash + # as a single flattened level, call `#flat`. All keys are converted to strings. + # All end-of-the-chain values are kept in whatever value they are. + # + # s = PathHash['a' => 'b', 'c' => {'d' => :e}] + # s['a'] #=> 'b' + # s['c'] #=> {slashed: 'd'=>:e} + # s['c']['d'] #=> :e + # s['c/d'] #=> :e + # + # PathHash is derived from the SlashedHash class in the HashMagic project + # by Daniel Parker . + # + # Copyright (c) 2006 BehindLogic (http://hash_magic.rubyforge.org) + # + # Authors: Daniel Parker + # + # TODO: This class is very much a work in progess and will be substantially rewritten + # for future versions. + # + class PathHash < Hash + + # + # Initialize PathHash. + # + # hsh - Priming Hash. + # + def initialize(hsh={}) + raise ArgumentError, "must be a hash or array of slashed values" unless hsh.is_a?(Hash) || hsh.is_a?(Array) + @constructor = hsh.is_a?(Hash) ? hsh.class : Hash + @flat = flatten_to_hash(hsh) + end + + # Standard Hash methods, plus the overwritten ones + #include StandardHashMethodsInRuby + + # Behaves like the usual Hash#[] method, but you can access nested hash + # values by composing a single key of the traversing keys joined by '/': + # + # hash['c']['d'] # is the same as: + # hash['c/d'] + # + def [](key) + rg = Regexp.new("^#{key}/?") + start_obj = if @constructor == OrderedHash + @constructor.new((@flat.instance_variable_get(:@keys_in_order) || []).collect {|e| e.gsub(rg,'')}) + else + @constructor.new + end + v = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ rg)}.inject(start_obj) {|h,(k,v)| h[k.gsub(rg,'')] = v; h}) + v.is_a?(self.class) && v.empty? ? nil : v + end + + # + # Same as above, except sets value rather than retrieving it. + # + def []=(key,value) + @flat.reject! {|k,v| k == key || k =~ Regexp.new("^#{key}/")} + if value.is_a?(Hash) + flatten_to_hash(value).each do |hk,hv| + @flat[key.to_s+'/'+hk.to_s] = hv + end + else + @flat[key.to_s] = value + end + end + + def clear # :nodoc: + @flat.clear + end + + # + # + # + def fetch(key,default=:ehisehoah0928309q98y30,&block) # :nodoc: + value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) + if value.is_a?(self.class) && value.empty? + if default == :ehisehoah0928309q98y30 + if block_given? + block.call(key) + else + raise IndexError + end + value + else + default + end + else + value + end + end + + # + # Delete entry from Hash. Slashed keys can be used here, too. + # + # key - The key to delete. + # block - Produces the return value if key not found. + # + # Returns delete value. + # + def delete(key,&block) + value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) + return block.call(key) if value.is_a?(self.class) && value.empty? && block_given? + @flat.keys.reject {|k| !(k == key || k =~ Regexp.new("^#{key}/"))}.each {|k| @flat.delete(k)} + return value + end + + # + def empty? + @flat.empty? + end + + # This gives you the slashed key of the value, no matter where the value is in the tree. + def index(value) + @flat.index(value) + end + + # + def inspect + @flat.inspect.insert(1,'slashed: ') + end + + # This gives you only the top-level keys, no slashes. To get the list of slashed keys, do hash.flat.keys + def keys + @flat.inject([]) {|a,(k,v)| a << [k.split('/',2)].flatten[0]; a}.uniq + end + + # This is rewritten to mean something slightly different than usual: Use this to restructure the hash, for cases when you + # end up with an array holding several hashes. + def rehash # :nodoc: + @flat.rehash + end + + # Gives a list of all keys in all levels in the multi-level hash, joined by slashes. + # + # {'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed.flat.keys + # #=> ['a/b', 'a/c', 'b'] + # + def flat + @flat + end + + # Expands the whole hash to Hash objects ... not useful very often, it seems. + def expand + inject({}) {|h,(k,v)| h[k] = v.is_a?(SlashedHash) ? v.expand : v; h} + end + + def to_string_array + flatten_to_array(flat,[]) + end + + def slashed # :nodoc: + self + end + + # Same as ordered! but returns a new SlashedHash object instead of modifying the same. + def ordered(*keys_in_order) + dup.ordered!(*keys_in_order) + end + + # Sets the SlashedArray as ordered. The *keys_in_order must be a flat array + # of slashed keys that specify the order for each level: + # + # s = {'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed + # s.ordered!('b', 'a/c', 'a/b') + # s.expand # => {'b'=>'c', 'a'=>{'c'=>'d', 'b'=>'c'}} + # # Note that the expanded hashes will *still* be ordered! + # + def ordered!(*keys_in_order) + return self if @constructor == OrderedHash + @constructor = OrderedHash + @flat = @flat.ordered(*keys_in_order) + self + end + + # + def ==(other) + case other + when SlashedHash + @slashed == other.instance_variable_get(:@slashed) + when Hash + self == SlashedHash.new(other) + else + raise TypeError, "Cannot compare #{other.class.name} with SlashedHash" + end + end + + private + + def flatten_to_hash(hsh) + flat = @constructor.new + if hsh.is_a?(Array) + hsh.each do |e| + flat.merge!(flatten_to_hash(e)) + end + elsif hsh.is_a?(Hash) + hsh.each do |k,v| + if v.is_a?(Hash) + flatten_to_hash(v).each do |hk,hv| + flat[k.to_s+'/'+hk.to_s] = hv + end + else + flat[k.to_s] = v + end + end + else + ks = hsh.split('/',-1) + v = ks.pop + ks = ks.join('/') + if !flat[ks].nil? + if flat[ks].is_a?(Array) + flat[ks] << v + else + flat[ks] = [flat[ks], v] + end + else + flat[ks] = v + end + end + flat + end + + def flatten_to_array(value,a) + if value.is_a?(Array) + value.each {|e| flatten_to_array(e,a)} + elsif value.is_a?(Hash) + value.inject([]) {|aa,(k,v)| flatten_to_array(v,[]).each {|vv| aa << k+'/'+vv.to_s}; aa}.each {|e| a << e} + else + a << value.to_s + end + a + end + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/property_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/property_hash.rb new file mode 100644 index 00000000..dbe65607 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/property_hash.rb @@ -0,0 +1,161 @@ +require 'hashery/crud_hash' + +module Hashery + + # A PropertyHash is the same as a regular Hash except it strictly limits the + # allowed keys. + # + # There are two ways to use it. + # + # 1) As an object in itself. + # + # h = PropertyHash.new(:a=>1, :b=>2) + # h[:a] #=> 1 + # h[:a] = 3 + # h[:a] #=> 3 + # + # But if we try to set key that was not fixed, then we will get an error. + # + # h[:x] = 5 #=> ArgumentError + # + # 2) As a superclass. + # + # class MyPropertyHash < PropertyHash + # property :a, :default => 1 + # property :b, :default => 2 + # end + # + # h = MyPropertyHash.new + # h[:a] #=> 1 + # h[:a] = 3 + # h[:a] #=> 3 + # + # Again, if we try to set key that was not fixed, then we will get an error. + # + # h[:x] = 5 #=> ArgumentError + # + class PropertyHash < CRUDHash + + # + # Get a list of properties with default values. + # + # Returns [Hash] of properties and their default values. + # + def self.properties + @properties ||= ( + parent = ancestors[1] + if parent.respond_to?(:properties) + parent.properties + else + {} + end + ) + end + + # + # Define a property. + # + # key - Name of property. + # opts - Property options. + # :default - Default value of property. + # + # Returns default value. + # + def self.property(key, opts={}) + properties[key] = opts[:default] + end + + # + # Initialize new instance of PropertyHash. + # + # properties - [Hash] Priming properties with default values, or + # if it doesn't respond to #each_pair, a default object. + # default_proc - [Proc] Procedure for default value of properties + # for properties without specific defaults. + # + def initialize(properties={}, &default_proc) + if properties.respond_to?(:each_pair) + super(&default_proc) + fixed = self.class.properties.merge(properties) + fixed.each_pair do |key, value| + store!(key, value) + end + else + super(*[properties].compact, &default_proc) + end + end + + # Alias original #store method and make private. + alias :store! :store + private :store! + + # + # Create a new property, on-the-fly. + # + # key - Name of property. + # opts - Property options. + # :default - Default value of property. + # + # Returns default value. + # + def property(key, opts={}) + if opts[:default] + store!(key, opts[:default]) + else + store!(key, retrieve(key)) + end + end + + # + # Store key value pair, ensuring the key is a valid property first. + # + # key - The `Object` to act as indexing key. + # value - The `Object` to associate with key. + # + # Raises ArgumentError if key is not a valid property. + # + # Returns +value+. + # + def store(key, value) + assert_key!(key) + super(key, value) + end + + # + #def update(h) + # h.keys.each{ |k| assert_key!(k) } + # super(h) + #end + + # + #def merge!(h) + # h.keys.each{ |k| assert_key!(k) } + # super(h) + #end + + # + # Like #store but takes a two-element Array of `[key, value]`. + # + # Returns value. + # + #def <<(a) + # k,v = *a + # store(k,v) + #end + + private + + # + # Asserta that a key is a defined property. + # + # Raises ArgumentError if key is not a property. + # + def assert_key!(key) + unless key?(key) + raise ArgumentError, "property is not defined -- #{key.inspect}" + end + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/query_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/query_hash.rb new file mode 100644 index 00000000..a8f77157 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/query_hash.rb @@ -0,0 +1,91 @@ +module Hashery + + require 'hashery/key_hash' + + # QueryHash is essentially a Hash class, but with some OpenStruct-like features. + # + # q = QueryHash.new + # + # Entries can be added to the Hash via a setter method. + # + # q.a = 1 + # + # Then looked up via a query method. + # + # q.a? #=> 1 + # + # The can also be looked up via a bang method. + # + # q.a! #=> 1 + # + # The difference between query methods and bang methods is that the bang method + # will auto-instantiate the entry if not present, where as a query method will not. + # + # A QueryHash might not be quite as elegant as an OpenHash in that reader + # methods must end in `?` or `!`, but it remains fully compatible with Hash + # regardless of it's settings. + # + class QueryHash < CRUDHash + + # + # By default the `key_proc` is set to convert all keys to strings via `#to_s`. + # + # default - Default object, or + # default_proc - Default procedure. + # + def initialize(*default, &default_proc) + @key_proc = Proc.new{ |k| k.to_s } + super(*default, &default_proc) + end + + # + # Route get and set calls. + # + # s - [Symbol] Name of method. + # a - [Array] Method arguments. + # b - [Proc] Block argument. + # + # Examples + # + # o = QueryHash.new + # o.a = 1 + # o.a? #=> 1 + # o.b? #=> nil + # + def method_missing(s,*a, &b) + type = s.to_s[-1,1] + name = s.to_s.sub(/[!?=]$/, '') + key = name #key = cast_key(name) + + case type + when '=' + store(key, a.first) + when '!' + default = (default_proc ? default_proc.call(self, key) : default) + key?(key) ? fetch(key) : store(key, default) + when '?' + key?(key) ? fetch(key) : nil + else + # return self[key] if key?(key) + super(s,*a,&b) + end + end + + # + # Custom #respond_to to account for #method_missing. + # + # name - The method name to check. + # + # Returns `true` or `false`. + # + def respond_to?(name) + return true if name.to_s.end_with?('=') + return true if name.to_s.end_with?('?') + return true if name.to_s.end_with?('!') + #key?(name.to_sym) || super(name) + super(name) + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/lib/hashery/stash.rb b/bin/gems/hashery-2.1.2/lib/hashery/stash.rb new file mode 100644 index 00000000..a5581983 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/stash.rb @@ -0,0 +1,14 @@ +require 'hashery/key_hash' + +module Hashery + # Stash is the original name for the KeyHash. + Stash = KeyHash +end + +class Hash + # Convert Hash to Stash. + def to_stash + Hashery::Stash[self] + end +end + diff --git a/bin/gems/hashery-2.1.2/lib/hashery/static_hash.rb b/bin/gems/hashery-2.1.2/lib/hashery/static_hash.rb new file mode 100644 index 00000000..55b84670 --- /dev/null +++ b/bin/gems/hashery-2.1.2/lib/hashery/static_hash.rb @@ -0,0 +1,53 @@ +module Hashery + + # StaticHash ia a Hash object which raises an error if any + # previously-defined key attempts to be set again. + # + # foo = StaticHash.new + # foo['name'] = 'Tom' #=> 'Tom' + # foo['age'] = 30 #=> 30 + # foo['name'] = 'Bob' + # + # produces + # + # ArgumentError: Duplicate key for StaticHash -- 'name' + # + # StaticHash has it's orgins in Gavin Kistner's WriteOnceHash + # class found in his +basiclibrary.rb+ script. + # + # TODO: Maybe StaticHash isn't bets name for this class? + # + class StaticHash < CRUDHash + + # + # Set a value for a key. Raises an error if that key already + # exists with a different value. + # + # key - Index key to associate with value. + # value - Value to associate with key. + # + # Retruns value. + # + def store(key, value) + if key?(key) && fetch(key) != value + raise ArgumentError, "Duplicate key for StaticHash -- #{key.inspect}" + end + super(key, value) + end + + # + #def update(hash) + # dups = (keys | hash.keys) + # if dups.empty? + # super(hash) + # else + # raise ArgumentError, "Duplicate key for StaticHash -- #{dups.inspect}" + # end + #end + + # + #alias_method :merge!, :update + + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_association.rb b/bin/gems/hashery-2.1.2/test/case_association.rb new file mode 100644 index 00000000..a42e6d69 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_association.rb @@ -0,0 +1,103 @@ +require 'helper' + +# must be required independently +require 'hashery/association' + +testcase Association do + + class_method :new do + test do + Association.new(:A, :B) + end + end + + class_method :[] do + test do + a = Association[:a, 1] + a.assert.index == :a + a.assert.value == 1 + end + end + + method :index do + test do + a = Association.new(:a,1) + a.index.assert == :a + end + end + + method :value do + test do + a = Association.new(:a,1) + a.value.assert == 1 + end + end + + method :to_ary do + test do + k,v = [],[] + ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ] + ohash.each { |e1,e2| k << e1 ; v << e2 } + k.assert == ['A','B','C'] + v.assert == ['3','2','1'] + end + end + + method :index do + test do + complex = [ 'Drop Menu' >> [ 'Button 1', 'Button 2', 'Button 3' ], 'Help' ] + complex[0].index.assert == 'Drop Menu' + end + end + + method :<=> do + test 'when differnt in value' do + a = Association.new(:a,1) + b = Association.new(:b,2) + (a <=> b).assert == -1 + (b <=> a).assert == 1 + end + + test 'when equal value' do + a = Association.new(:a,1) + b = Association.new(:b,1) + (a <=> b).assert == 0 + end + end + + method :invert! do + test do + a = Association.new(:a,1) + a.invert! + a.index.assert == 1 + a.value.assert == :a + end + end + + method :inspect do + test do + a = Association.new(:a,1) + a.inspect.assert == ":a >> 1" + end + end + + method :to_s do + test do + a = Association.new(:a,1) + a.to_s.assert == "a >> 1" + end + end + +end + +testcase Object do + method :associations do + test do + s = 'a' + complex = [ s >> :b, s >> :c ] + s.associations.assert == [:b, :c] + end + end + +end + diff --git a/bin/gems/hashery-2.1.2/test/case_casting_hash.rb b/bin/gems/hashery-2.1.2/test/case_casting_hash.rb new file mode 100644 index 00000000..a7f04ce4 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_casting_hash.rb @@ -0,0 +1,71 @@ +require 'helper' + +test_case CastingHash do + + class_method :[] do + test do + h = CastingHash[:a=>1, :b=>2] + end + end + + class_method :new do + test do + h = CastingHash.new + end + + test 'with default' do + h = CastingHash.new(0) + h['a'].assert == 0 + end + + test 'with casting procedure' do + h = CastingHash.new{ |k,v| [k.to_sym, v] } + h['a'] = 1 + h.assert == {:a=>1} + end + + test 'with default and casting procedure' do + h = CastingHash.new(0){ |k,v| [k.to_sym, v] } + h['a'].assert == 0 + h['b'] = 2 + h.assert == {:b=>2} + end + end + + method :recast! do + test do + h = CastingHash[:a=>1, :b=>2] + h.cast_proc{ |k,v| [k.to_s, v] } + h.recast! + h.assert == {'a'=>1, 'b'=>2} + end + end + + method :cast_proc= do + test do + h = CastingHash[:a=>1, :b=>2] + h.cast_proc = Proc.new{ |k,v| [k.to_s, v] } + h.recast! + h.assert == {'a'=>1, 'b'=>2} + end + end + + method :to_hash do + test do + h = CastingHash[:a=>1, :b=>2] + h.to_hash + ::Hash.assert === h + h.assert == {:a=>1, :b=>2} + end + end + + method :to_h do + test do + h = CastingHash[:a=>1, :b=>2] + h.to_h + ::Hash.assert === h + h.assert == {:a=>1, :b=>2} + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_core_ext.rb b/bin/gems/hashery-2.1.2/test/case_core_ext.rb new file mode 100644 index 00000000..9e419dee --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_core_ext.rb @@ -0,0 +1,79 @@ +require 'helper' + +test_case Hash do + + method :rekey do + + test "default" do + foo = { "a"=>1, "b"=>2 } + foo.rekey.assert == { :a=>1, :b=>2 } + foo.assert == { "a"=>1, "b"=>2 } + end + + test "specific key" do + bar = { :a=>1, :b=>2 } + foo = bar.rekey(:a=>:c) + foo[:c].assert == 1 + foo[:b].assert == 2 + foo[:a].assert == nil + end + + test "with block" do + bar = { :a=>1, :b=>2 } + foo = bar.rekey{ |k| k.to_s } + foo['a'].assert == 1 + foo['b'].assert == 2 + foo[:a].assert == nil + foo[:b].assert == nil + foo.assert == { 'a'=>1, 'b'=>2 } + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.rekey(&:to_s).assert == { "a"=>1, "b"=>2 } + foo.assert == { :a =>1, :b=>2 } + end + + end + + method :rekey! do + + test "default" do + foo = { "a"=>1, "b"=>2 } + foo.rekey!.assert == { :a=>1, :b=>2 } + foo.assert == { :a=>1, :b=>2 } + end + + test "specific key" do + foo = { :a=>1, :b=>2 } + foo.rekey!(:a=>:c) + foo[:c].assert == 1 + foo[:b].assert == 2 + foo[:a].assert == nil + end + + test "with block" do + foo = { :a=>1, :b=>2 } + foo.rekey!{ |k| k.to_s } + foo['a'].assert == 1 + foo['b'].assert == 2 + foo[:a].assert == nil + foo[:b].assert == nil + foo.assert == { 'a'=>1, 'b'=>2 } + end + + test "symbol proc" do + foo = { :a=>1, :b=>2 } + foo.rekey!(&:to_s).assert == { "a"=>1, "b"=>2 } + foo.assert == { "a"=>1, "b"=>2 } + end + + test "no conflict between keys" do + r = {1 => :a, 2 => :b}.rekey!{ |k| k + 1 } + r.refute = {3 => :a} + r.assert = {2 => :a, 3 => :b} + end + + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_crud_hash.rb b/bin/gems/hashery-2.1.2/test/case_crud_hash.rb new file mode 100644 index 00000000..6ede4ea0 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_crud_hash.rb @@ -0,0 +1,29 @@ +require 'helper' + +test_case CRUDHash do + + class_method :create do + test do + h = CRUDHash.create(:a=>1,:b=>2) + h.assert == {:a=>1,:b=>2} + end + end + + class_method :auto do + test 'without a block' do + h = CRUDHash.auto + h[:a].assert == {} + end + + test 'with a block' do + h = CRUDHash.auto{ [] } + h[:a].assert == [] + end + end + +end + + +# +# OT: Why not make `:a=>1` a Pair object? +# diff --git a/bin/gems/hashery-2.1.2/test/case_dictionary.rb b/bin/gems/hashery-2.1.2/test/case_dictionary.rb new file mode 100644 index 00000000..e8ba9a18 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_dictionary.rb @@ -0,0 +1,328 @@ +require 'helper' + +testcase Dictionary do + include AE::Legacy::Assertions + + class_method :[] do + test do + d = Dictionary['z', 1, 'a', 2, 'c', 3] + assert_equal( ['z','a','c'], d.keys ) + end + end + + class_method :new do + test "with default" do + d = Dictionary.new{ |hash,key| hash[key] = 0 } + d[:a] = 0 + d[:b] += 1 + assert_equal [0, 1], d.values + assert_equal [:a,:b], d.keys + end + end + + method :[] do + test do + d = Dictionary['a', 1] + d['a'].assert == 1 + end + end + + method :[]= do + test do + d = Dictionary.new + d['z'] = 1 + d['a'] = 2 + d['c'] = 3 + assert_equal( ['z','a','c'], d.keys ) + end + end + + method :[]= do + test do + d = Dictionary[] + d[:a] = 1 + d[:c] = 3 + assert_equal( [1,3], d.values ) + d[:b,1] = 2 + assert_equal( [1,2,3], d.values ) + assert_equal( [:a,:b,:c], d.keys ) + end + end + + method :push do + test do + d = Dictionary['a', 1, 'c', 2, 'z', 3] + assert( d.push('end', 15) ) + assert_equal( 15, d['end'] ) + assert( ! d.push('end', 30) ) + assert( d.unshift('begin', 50) ) + assert_equal( 50, d['begin'] ) + assert( ! d.unshift('begin', 60) ) + assert_equal( ["begin", "a", "c", "z", "end"], d.keys ) + assert_equal( ["end", 15], d.pop ) + assert_equal( ["begin", "a", "c", "z"], d.keys ) + assert_equal( ["begin", 50], d.shift ) + end + end + + method :insert do + test "front" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + r = Dictionary['d', 4, 'a', 1, 'b', 2, 'c', 3] + assert_equal( 4, d.insert(0,'d',4) ) + assert_equal( r, d ) + end + test "back" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] + assert_equal( 4, d.insert(-1,'d',4) ) + assert_equal( r, d ) + end + end + + method :update do + test "with other orderred hash" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + c = Dictionary['d', 4] + r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] + assert_equal( r, d.update(c) ) + assert_equal( r, d ) + end + test "with other hash" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + c = { 'd' => 4 } + r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] + assert_equal( r, d.update(c) ) + assert_equal( r, d ) + end + end + + method :merge do + test "with other orderred hash" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + c = Dictionary['d', 4] + r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] + assert_equal( r, d.merge(c) ) + end + test "with other hash" do + d = Dictionary['a', 1, 'b', 2, 'c', 3] + c = { 'd' => 4 } + r = Dictionary['a', 1, 'b', 2, 'c', 3, 'd', 4] + assert_equal( r, d.merge(c) ) + end + end + + method :order_by do + test do + d = Dictionary['a', 3, 'b', 2, 'c', 1] + d.order_by{ |k,v| v } + assert_equal( [1,2,3], d.values ) + assert_equal( ['c','b','a'], d.keys ) + end + end + + method :reverse! do + test do + d = Dictionary['z', 1, 'a', 2, 'c', 3] + d.reverse! + assert_equal( ['c','a','z'], d.keys ) + end + end + + method :collect do + test "enumerable method" do + d = Dictionary[] + d[:a] = "a" + d[:c] = "b" + r = d.collect{|k,v| v.capitalize} + r.assert == ["A","B"] + end + end + + method :dup do + test "with array values" do + d = Dictionary.new + d.dup + d[:a]=['t',5] + assert_equal(d, d.dup) + end + end + + method :first do + test do + d = Dictionary[] + d[:a] = "a" + d[:b] = "b" + d[:c] = "c" + d.first.assert == "a" + d.first(0).assert == [] + assert_equal ["a"] , d.first(1) + assert_equal ["a", "b"] , d.first(2) + end + end + + method :last do + test do + d = Dictionary[] + d[:a] = "a" + d[:b] = "b" + d[:c] = "c" + d.last.assert == "c" + d.last(0).assert == [] + d.last(1).assert == ["c"] + d.last(2).assert == ["b", "c"] + end + end + + method :select do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + r = d.select{ |k,v| v % 2 == 1 } + r.assert == [[:a, 1], [:c, 3]] + end + end + + method :to_h do + test do + d = Dictionary[:a=>1, :b=>2] + h = d.to_h + h.assert == {:a=>1, :b=>2} + end + end + + method :replace do + test do + d1 = Dictionary[:a=>1, :b=>2] + d2 = Dictionary[:c=>3, :d=>4] + d1.replace(d2) + d1.to_h.assert == {:c=>3, :d=>4} + end + end + + method :reverse do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + r = d.reverse + r.first.assert == 3 + end + end + + method :invert do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + r = d.invert + Dictionary.assert === r + r.to_h.assert == {1=>:a, 2=>:b, 3=>:c} + end + end + + method :each_key do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.order_by_key + a = [] + d.each_key{ |k| a << k } + a.assert == [:a, :b, :c] + end + + method :each_value do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.order_by_value + a = [] + d.each_value{ |v| a << v } + a.assert == [1, 2, 3] + end + + method :clear do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.clear + d.to_a.assert == [] + end + + method :fetch do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.fetch(:a).assert == 1 + end + + method :key? do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.assert.key?(:a) + d.refute.key?(:d) + end + end + + method :has_key? do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.assert.has_key?(:a) + d.refute.has_key?(:d) + end + end + + method :length do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.length.assert == 3 + end + end + + method :to_a do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.to_a.assert == [[:a,1], [:b,2], [:c,3]] + end + end + + method :to_hash do + test do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.to_hash.assert == {:a=>1, :b=>2, :c=>3} + end + end + + method :empty? do + test "is emtpy" do + d = Dictionary[] + d.assert.empty? + end + + test 'is not emtpy' do + d = Dictionary[:a=>1, :b=>2, :c=>3] + d.refute.empty? + end + end + + method :order_by_key do + test do + d = Dictionary[:b=>1, :c=>2, :a=>4] + d.order_by_key + d.order.assert == [:a, :b, :c] + end + end + + method :order_by_value do + test do + d = Dictionary[:b=>1, :c=>2, :a=>4] + d.order_by_value + d.order.assert == [:b, :c, :a] + end + end + + class_method :alpha do + test do + d = Dictionary.alpha + d.update(:b=>1, :c=>2, :a=>4) + d.order.assert == [:a, :b, :c] + end + end + + class_method :auto do + test do + d = Dictionary.auto + s = d[:foo] + s.class.assert == Dictionary + end + end + +end + diff --git a/bin/gems/hashery-2.1.2/test/case_ini_hash.rb b/bin/gems/hashery-2.1.2/test/case_ini_hash.rb new file mode 100644 index 00000000..f0d25937 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_ini_hash.rb @@ -0,0 +1,56 @@ +require 'helper' + +test_case IniHash do + + class_method :new do + test do + h = IniHash.new('foo.ini', false) + end + end + + method :[]= do + test do + h = IniHash.new('foo.ini', false) + h['a'] = '1' + h['a'].assert = '1' + end + end + + method :[] do + test do + h = IniHash.new('foo.ini', false) + h['a'] = '1' + h['a'].assert = '1' + end + end + + method :to_h do + test do + h = IniHash.new('foo.ini', false) + h['a'] = '1' + h.to_h.assert = {'a'=>'1'} + end + end + + method :to_s do + test do + h = IniHash.new('foo.ini', false) + h['a'] = '1' + h.to_s.assert == "a=1\n" + end + + test do + h = IniHash.new('foo.ini', false) + h['a'] = '1' + h['b'] = {'c'=>3} + h.to_s.assert == "a=1\n[b]\nc=3\n" + end + end + + class_method :load do + h = IniHash.load('test/fixture/example.ini') + h['a'].assert == '1' + end + +end + diff --git a/bin/gems/hashery-2.1.2/test/case_key_hash.rb b/bin/gems/hashery-2.1.2/test/case_key_hash.rb new file mode 100644 index 00000000..e65489d8 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_key_hash.rb @@ -0,0 +1,182 @@ +require 'helper' + +testcase KeyHash do + + class_method :[] do + test 'creates new KeyHash' do + s = KeyHash[] + KeyHash.assert === s + end + + test 'pre-assigns values' do + s = KeyHash[:a=>1, :b=>2] + s[:a].assert == 1 + s[:b].assert == 2 + end + end + + method :[] do + test 'instance level fetch' do + s = KeyHash[:a=>1, :b=>2] + s[:a].assert == 1 + s[:b].assert == 2 + end + + test 'by default keys are converted to strings' do + s = KeyHash[:a=>1, :b=>2] + s['a'].assert == 1 + s['b'].assert == 2 + end + end + + method :[]= do + test do + s = KeyHash.new + s[:a] = 1 + s[:b] = 2 + s[:a].assert == 1 + s[:b].assert == 2 + s['a'].assert == 1 + s['b'].assert == 2 + end + end + + method :initialize do + test do + StandardError.refute.raised? do + s = KeyHash.new + end + end + end + + method :to_hash do + test do + s = KeyHash[:a=>1, :b=>2] + s.to_hash.assert == {'a'=>1, 'b'=>2} + end + end + + method :to_h do + test do + s = KeyHash[:a=>1, :b=>2] + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :replace do + test do + s = KeyHash.new + s.replace(:a=>1, :b=>2) + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :delete do + test do + s = KeyHash[:a=>1, :b=>2] + s.delete(:a) + s.to_h.assert == {'b'=>2} + end + end + + method :each do + test do + s = KeyHash[:a=>1, :b=>2] + s.each do |k,v| + String.assert === k + end + end + end + + method :store do + test do + s = KeyHash.new + s.store(:a, 1) + s.to_h.assert == {'a'=>1} + end + end + + method :update do + test do + s1 = KeyHash[:a=>1,:b=>2] + s2 = KeyHash[:c=>3,:d=>4] + s1.update(s2) + s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} + end + end + + method :rekey do + test do + s = KeyHash[:a=>1,:b=>2,:c=>3] + x = s.rekey{ |k| k.upcase } + x.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} + end + end + + method :rekey! do + test do + s = KeyHash[:a=>1,:b=>2,:c=>3] + s.rekey!{ |k| k.upcase } + s.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} + end + end + + method :key? do + test do + s = KeyHash[:a=>1] + s.assert.key?(:a) + s.assert.key?('a') + end + end + + method :has_key? do + test do + s = KeyHash[:a=>1] + s.assert.has_key?(:a) + s.assert.has_key?('a') + end + end + + method :<< do + test do + s = KeyHash.new + s << [:a, 1] + s << [:b, 2] + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :merge! do + test do + s1 = KeyHash[:a=>1,:b=>2] + s2 = KeyHash[:c=>3,:d=>4] + s1.merge!(s2) + s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} + end + end + + method :values_at do + test do + s = KeyHash[:a=>1,:b=>2,:c=>3] + s.values_at(:a, :b).assert == [1,2] + s.values_at('a','b').assert == [1,2] + end + end + + method :fetch do + test do + s = KeyHash[:a=>1,:b=>2,:c=>3] + s.fetch(:a).assert == 1 + s.fetch('a').assert == 1 + end + end + + #method :cast_key do + # test do + # s = KeyHash.new + # s.send(:cast_key, :a).assert == 'a' + # end + #end + +end + diff --git a/bin/gems/hashery-2.1.2/test/case_linked_list.rb b/bin/gems/hashery-2.1.2/test/case_linked_list.rb new file mode 100644 index 00000000..60761ea0 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_linked_list.rb @@ -0,0 +1,167 @@ +require 'helper' + +test_case LinkedList do + + class_method :new do + ll = LinkedList.new + LinkedList.assert === ll + end + + method :to_a do + test 'empty' do + ll = LinkedList.new + ll.to_a.assert == [] + end + test 'not empty' do + ll = LinkedList.new + ll.push :a + ll.to_a.assert == [:a] + end + end + + method :empty? do + test do + ll = LinkedList.new + ll.assert.empty? + end + end + + method :delete do + test do + ll = LinkedList.new + ll.push :a + ll.to_a.assert == [:a] + ll.delete(:a) + ll.to_a.assert == [] + end + + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.push :c + ll.to_a.assert == [:a, :b, :c] + ll.delete(:b) + ll.to_a.assert == [:a, :c] + end + end + + method :each do + test do + a = [] + ll = LinkedList.new + ll.push :a + ll.each do |e| + a << e + end + a.assert == [:a] + end + end + + method :length do + test do + ll = LinkedList.new + ll.push :a + ll.length.assert == 1 + end + end + + method :push do + test do + ll = LinkedList.new + ll.push :a + ll.to_a.assert == [:a] + end + end + + method :unshift do + test do + ll = LinkedList.new + ll.unshift :a + ll.to_a.assert == [:a] + end + test do + ll = LinkedList.new + ll.push :a + ll.unshift :b + ll.to_a.assert == [:b, :a] + end + end + + method :pop do + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.to_a.assert == [:a, :b] + ll.pop + ll.to_a.assert == [:a] + end + end + + method :shift do + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.to_a.assert == [:a, :b] + ll.shift + ll.to_a.assert == [:b] + end + end + + method :first do + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.to_a.assert == [:a, :b] + ll.first.assert == :a + end + end + + method :last do + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.to_a.assert == [:a, :b] + ll.last.assert == :b + end + end + + method :queue do + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll.queue.assert == [:a, :b] + end + end + + method :[]= do + test do + ll = LinkedList.new + ll[:a] = :b + ll.to_a.assert == [:b] + ll[:a].assert == :b + end + end + + method :[] do + test do + ll = LinkedList.new + ll.push :a + ll[:a].assert == :a + end + + test do + ll = LinkedList.new + ll.push :a + ll.push :b + ll[:a].assert == :a + ll[:b].assert == :b + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_lru_hash.rb b/bin/gems/hashery-2.1.2/test/case_lru_hash.rb new file mode 100644 index 00000000..8912a835 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_lru_hash.rb @@ -0,0 +1,162 @@ +require 'helper' + +test_case LRUHash do + + class_method :new do + h = LRUHash.new(10) + LRUHash.assert === h + end + + method :max_size= do + test do + h = LRUHash.new(10) + h.max_size = 100 + end + end + + method :store do + test do + h = LRUHash.new(10) + h.store(:a, 1) + h[:a].assert == 1 + end + end + + method :[] do + test do + h = LRUHash.new(10) + h.store(:a, 1) + h[:a].assert == 1 + end + + test do + h = LRUHash.new(10){ |h,k| h[k] = 0 } + h[:a].assert == 0 + end + end + + method :empty? do + test do + h = LRUHash.new(10) + h.assert.empty? + end + end + + method :key do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.key(1).assert == :a + end + end + + method :keys do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.keys.assert == [:a] + end + end + + method :values do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.values.assert == [1] + end + end + + method :values_at do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.values_at(:a).assert == [1] + end + end + + method :has_key? do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.assert.has_key?(:a) + end + end + + method :has_value? do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.assert.has_value?(1) + end + end + + method :assoc do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.assoc(:a).assert == [:a,1] + end + end + + method :rassoc do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.rassoc(1).assert == [:a,1] + end + end + + method :each_key do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.each_key do |k| + [:a,:b].assert.include?(k) + end + end + end + + method :each_value do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.each_value do |v| + [1,2].assert.include?(v) + end + end + end + + method :clear do + test do + h = LRUHash.new(10) + h[:a] = 1 + h[:b] = 2 + h.clear + h.assert.empty? + end + end + + method :delete do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.delete(:a) + h.assert.empty? + end + end + + method :delete_if do + test do + h = LRUHash.new(10) + h[:a] = 1 + h.delete_if{ |k,v| k == :a } + h.assert.empty? + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_open_cascade.rb b/bin/gems/hashery-2.1.2/test/case_open_cascade.rb new file mode 100644 index 00000000..b06ad535 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_open_cascade.rb @@ -0,0 +1,122 @@ +require 'helper' + +testcase OpenCascade do + include AE::Legacy::Assertions + + class_method :new do + OpenCascade[:a=>1] + end + + class_method :[] do + test "hash" do + o = OpenCascade[:a=>1,:b=>2] + assert_equal(1, o.a) + assert_equal(2, o.b) + end + test "hash in hash" do + o = OpenCascade[:a=>1,:b=>2,:c=>{:x=>9}] + assert_equal(9, o.c.x) + end + test "hash in hash in hash" do + h = {:a=>1,:x=>{:y=>{:z=>1}}} + c = OpenCascade[h] + assert_equal(1, c.x.y.z) + end + end + + method :[] do + test "basic assignment" do + o = OpenCascade.new + o[:a] = 1 + assert_equal(1, o[:a]) + end + end + + method :[]= do + test "basic assignment with primed OpenCascade" do + o = OpenCascade[:a=>1] + o[:b] = 2 + o.to_h.assert == {:a=>1,:b=>2} + end + end + + method :to_a do + test do + o = OpenCascade[:a=>1,:b=>2] + a = o.to_a + a.assert.include?([:a,1]) + a.assert.include?([:b,2]) + a.size.assert == 2 + end + end + + method :to_h do + test do + o = OpenCascade[:a=>1] + assert_equal({:a=>1}, o.to_h) + end + end + + method :merge! do + test do + o = OpenCascade[:f0=>"f0"] + r = OpenCascade[:f0=>"f0", :h0=>"h0"] + h = { :h0=>"h0" } + assert_equal(r, o.merge!(h)) + assert_equal({:f0=>"f0", :h0=>"h0"}, h.merge(o)) + end + end + + method :update do + test do + o = OpenCascade[:f1=>"f1"] + o.update(:h1=>"h1") + o.assert == OpenCascade[:f1=>"f1", :h1=>"h1"] + end + end + + method :method_missing do + test "writer and reader" do + o = OpenCascade.new + 10.times{ |i| o.__send__("n#{i}=", 1 ) } + 10.times{ |i| assert_equal(1, o.__send__("n#{i}")) } + end + end + + method :<< do + test do + c = OpenCascade.new + c << [:x,8] + c << [:y,9] + + assert_equal(8, c.x) + assert_equal(9, c.y) + end + end + +end + +testcase Hash do + + method :update do + test "hash can be updated by OpenCascade" do + o = OpenCascade[:f1=>"f1"] + h = {:h1=>"h1"} + h.update(o) + h.assert == {:f1=>"f1", :h1=>"h1"} + end + end + +end + +testcase Array do + + method :flatten do + test "array can be flattened if contains OpenCascade" do + cascade = OpenCascade[:foo=>"bar"] + array = [cascade] + array.flatten # should not raise error + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_open_hash.rb b/bin/gems/hashery-2.1.2/test/case_open_hash.rb new file mode 100644 index 00000000..1a036c30 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_open_hash.rb @@ -0,0 +1,87 @@ +require 'helper' + +testcase OpenHash do + + class_method :[] do + test do + o = OpenHash[:a=>1, :b=>2] + o.a.assert == 1 + o.b.assert == 2 + end + + test do + o = OpenHash[:a=>1, :b=>2] + o.a.assert == 1 + o.b.assert == 2 + end + end + + method :open? do + test do + o = OpenHash[:a=>1, :b=>2] + o.assert.open?(:foo) + o.refute.open?(:each) + end + end + + method :open! do + test do + o = OpenHash[:a=>1, :b=>2] + o.open!(:each) + o.assert.open?(:each) + o.each = 10 + o.each.assert == 10 + end + end + + method :close! do + test do + o = OpenHash[:a=>1, :b=>2] + o.open!(:each) + o.assert.open?(:each) + o.each = 10 + o.each.assert == 10 + o.close!(:each) + o.each.refute == 10 + end + end + + method :method_missing do + test 'bang method' do + o = OpenHash[] + o.open!(:each) + o.each = 10 + o.each.assert == 10 + + a = [] + o.each! do |k,v| + a << [k,v] + end + a.assert == [[:each,10]] + end + + test 'query method' do + o = OpenHash[] + o.a = 1 + o.assert.a? + o.refute.b? + end + end + + method :send do + test do + o = OpenHash[] + o.open!(:each) + o.each = 10 + o.each.assert == 10 + + a = [] + o.send(:each) do |k,v| + a << [k,v] + end + a.assert == [[:each,10]] + end + end + +end + diff --git a/bin/gems/hashery-2.1.2/test/case_property_hash.rb b/bin/gems/hashery-2.1.2/test/case_property_hash.rb new file mode 100644 index 00000000..4766b69e --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_property_hash.rb @@ -0,0 +1,21 @@ +require 'helper' + +test_case PropertyHash do + + class_method :new do + test do + PropertyHash.new + end + end + + method :update do + test do + h = PropertyHash.new + h.property :a + h.property :b + h.update(:a=>1, :b=>2) + h.assert == {:a=>1, :b=>2} + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/case_query_hash.rb b/bin/gems/hashery-2.1.2/test/case_query_hash.rb new file mode 100644 index 00000000..b6e878bf --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/case_query_hash.rb @@ -0,0 +1,226 @@ +require 'helper' + +testcase QueryHash do + + class_method :new do + test 'new QueryHash with default proc' do + q = QueryHash.new{ |h,k| h[k] = 1 } + q[:a].assert == 1 + end + end + + class_method :[] do + test 'creates new QueryHash' do + s = QueryHash[] + QueryHash.assert === s + end + + test 'pre-assigns values' do + s = QueryHash[:a=>1, :b=>2] + s[:a].assert == 1 + s[:b].assert == 2 + end + end + + method :[] do + test 'instance level fetch' do + s = QueryHash[:a=>1, :b=>2] + s[:a].assert == 1 + s[:b].assert == 2 + #s['a'].assert == 1 + #s['b'].assert == 2 + end + end + + method :[]= do + test do + s = QueryHash.new + s[:a] = 1 + s[:b] = 2 + s[:a].assert == 1 + s[:b].assert == 2 + #s['a'].assert == 1 + #s['b'].assert == 2 + end + end + + method :respond_to? do + test 'responds to all query methods' do + q = QueryHash.new + q.assert.respond_to?(:anything?) + end + + test 'responds to all bang methods' do + q = QueryHash.new + q.assert.respond_to?(:anything!) + end + + test 'responds to all setter methods' do + q = QueryHash.new + q.assert.respond_to?(:anything=) + end + + test 'responds to usual methods' do + q = QueryHash.new + q.assert.respond_to?(:each) + end + end + + method :to_hash do + test do + s = QueryHash[:a=>1, :b=>2] + s.to_hash.assert == {'a'=>1, 'b'=>2} + end + end + + method :to_h do + test do + s = QueryHash[:a=>1, :b=>2] + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :replace do + test do + s = QueryHash.new + s.replace(:a=>1, :b=>2) + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :delete do + test do + s = QueryHash[:a=>1, :b=>2] + s.delete(:a) + s.to_h.assert == {'b'=>2} + end + end + + method :each do + test do + s = QueryHash[:a=>1, :b=>2] + s.each do |k,v| + String.assert === k + end + end + end + + method :store do + test do + s = QueryHash.new + s.store(:a, 1) + s.to_h.assert == {'a'=>1} + end + end + + method :update do + test do + s1 = QueryHash[:a=>1,:b=>2] + s2 = QueryHash[:c=>3,:d=>4] + s1.update(s2) + s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} + end + end + + method :rekey do + test do + s = QueryHash[:a=>1,:b=>2,:c=>3] + x = s.rekey{ |k| k.upcase } + x.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} + end + end + + method :rekey! do + test do + s = QueryHash[:a=>1,:b=>2,:c=>3] + s.rekey!{ |k| k.upcase } + s.to_h.assert == {'A'=>1,'B'=>2,'C'=>3} + end + end + + method :key? do + test do + s = QueryHash[:a=>1] + s.assert.key?(:a) + s.assert.key?('a') + end + end + + method :has_key? do + test do + s = QueryHash[:a=>1] + s.assert.has_key?(:a) + s.assert.has_key?('a') + end + end + + method :<< do + test do + s = QueryHash.new + s << [:a, 1] + s << [:b, 2] + s.to_h.assert == {'a'=>1, 'b'=>2} + end + end + + method :merge! do + test do + s1 = QueryHash[:a=>1,:b=>2] + s2 = QueryHash[:c=>3,:d=>4] + s1.merge!(s2) + s1.to_h.assert == {'a'=>1,'b'=>2,'c'=>3,'d'=>4} + end + end + + method :values_at do + test do + s = QueryHash[:a=>1,:b=>2,:c=>3] + s.values_at(:a, :b).assert == [1,2] + s.values_at('a','b').assert == [1,2] + end + end + + method :fetch do + test do + s = QueryHash[:a=>1,:b=>2,:c=>3] + s.fetch(:a).assert == 1 + s.fetch('a').assert == 1 + end + end + + method :cast_key do + test do + s = QueryHash.new + s.pry.cast_key(:a).assert == 'a' + end + end + + method :method_missing do + test 'dynamic query methods can look-up values' do + q = QueryHash[:a=>1,:b=>2,:c=>3] + q.a?.assert == 1 + q.b?.assert == 2 + q.c?.assert == 3 + end + + test 'dynamic bang methods can looks up values too' do + q = QueryHash[:a=>1,:b=>2,:c=>3] + q.a!.assert == 1 + q.b!.assert == 2 + q.c!.assert == 3 + end + + test 'dynamic bang methods will auto-instantiate' do + q = QueryHash.new + q.default_proc{ |h,k| h[k] = 'default' } + q.foo!.assert == 'default' + end + + test 'dynamic query methods will NOT auto-instantiate' do + q = QueryHash.new + q.default_proc{ |h,k| h[k] = 'default' } + q.foo?.assert == nil + end + end + +end diff --git a/bin/gems/hashery-2.1.2/test/fixture/example.ini b/bin/gems/hashery-2.1.2/test/fixture/example.ini new file mode 100644 index 00000000..91450cb9 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/fixture/example.ini @@ -0,0 +1,8 @@ +# top comment + +a = 1 + +[section] +x = 2 +y = 3 + diff --git a/bin/gems/hashery-2.1.2/test/helper.rb b/bin/gems/hashery-2.1.2/test/helper.rb new file mode 100644 index 00000000..22bd1b77 --- /dev/null +++ b/bin/gems/hashery-2.1.2/test/helper.rb @@ -0,0 +1,8 @@ +require 'lemon' +require 'ae' +require 'ae/legacy' # bacause imitation BasicObject sucks +require 'ae/pry' + +require 'hashery' + +include Hashery diff --git a/bin/gems/html-proofer-5.0.10/exe/htmlproofer b/bin/gems/html-proofer-5.0.10/exe/htmlproofer new file mode 100755 index 00000000..cc278955 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/exe/htmlproofer @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +$stdout.sync = true + +$LOAD_PATH.unshift("#{__dir__}/../lib") + +require "html-proofer" +require "benchmark" + +exit_status = -1 +cli = HTMLProofer::CLI.new + +time = Benchmark.realtime { exit_status = cli.run } + +puts "Finished in #{time.round(2)} seconds" +exit exit_status diff --git a/bin/gems/html-proofer-5.0.10/lib/html-proofer.rb b/bin/gems/html-proofer-5.0.10/lib/html-proofer.rb new file mode 100644 index 00000000..75ee89e4 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html-proofer.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative "html_proofer" diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer.rb new file mode 100644 index 00000000..bfc3c9dd --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require "zeitwerk" +lib_dir = File.join(File.dirname(__dir__), "lib") +gem_loader = Zeitwerk::Loader.for_gem +gem_loader.inflector.inflect( + "html_proofer" => "HTMLProofer", + "cli" => "CLI", +) +gem_loader.ignore(File.join(lib_dir, "html-proofer.rb")) +gem_loader.setup + +require "html_proofer/version" + +require "fileutils" + +if ENV.fetch("DEBUG", false) + require "debug" + begin + require "amazing_print" + rescue LoadError # rubocop:disable Lint/SuppressedException + end +end + +module HTMLProofer + class << self + def check_file(file, options = {}) + raise ArgumentError, "File isn't a string" unless file.is_a?(String) + raise ArgumentError, "#{file} does not exist" unless File.exist?(file) + + options[:type] = :file + HTMLProofer::Runner.new(file, options) + end + + def check_directory(directory, options = {}) + raise ArgumentError unless directory.is_a?(String) + raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory) + + options[:type] = :directory + HTMLProofer::Runner.new([directory], options) + end + + def check_directories(directories, options = {}) + raise ArgumentError unless directories.is_a?(Array) + + options[:type] = :directory + directories.each do |directory| + raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory) + end + HTMLProofer::Runner.new(directories, options) + end + + def check_links(links, options = {}) + raise ArgumentError unless links.is_a?(Array) + + options[:type] = :links + HTMLProofer::Runner.new(links, options) + end + end +end + +gem_loader.eager_load diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute.rb new file mode 100644 index 00000000..6d482da2 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module HTMLProofer + # Represents an element currently being processed + class Attribute + include HTMLProofer::Utils + + attr_reader :raw_attribute + + def initialize(runner, raw_attribute, **_) + @runner = runner + @raw_attribute = raw_attribute + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute/url.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute/url.rb new file mode 100644 index 00000000..39880c22 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/attribute/url.rb @@ -0,0 +1,268 @@ +# frozen_string_literal: true + +module HTMLProofer + class Attribute + class Url < HTMLProofer::Attribute + attr_reader :url, :size, :source, :filename + + REMOTE_SCHEMES = ["http", "https"].freeze + + def initialize(runner, link_attribute, base_url: nil, source: nil, filename: nil, extract_size: false) + super + + @source = source + @filename = filename + + if @raw_attribute.nil? + @url = nil + else + @url = @raw_attribute.delete("\u200b").strip + @url, @size = @url.split(/\s+/) if extract_size + @url = Addressable::URI.join(base_url, @url).to_s unless blank?(base_url) + @url = "" if @url.nil? + + swap_urls! + clean_url! + end + end + + def protocol_relative? + url.start_with?("//") + end + + def to_s + @url + end + + def known_extension? + return true if hash_link? + return true if path.end_with?("/") + + ext = File.extname(path) + + # no extension means we use the assumed one + return @runner.options[:extensions].include?(@runner.options[:assume_extension]) if blank?(ext) + + @runner.options[:extensions].include?(ext) + end + + def unknown_extension? + !known_extension? + end + + def ignore? + return true if /^javascript:/.match?(@url) + + true if ignores_pattern?(@runner.options[:ignore_urls]) + end + + def valid? + !parts.nil? + end + + def path? + !parts.host.nil? && !parts.path.nil? + end + + def parts + @parts ||= Addressable::URI.parse(@url) + rescue URI::Error, Addressable::URI::InvalidURIError + @parts = nil + end + + def path + Addressable::URI.unencode(parts.path) unless parts.nil? + end + + def hash + parts&.fragment + end + + # Does the URL have a hash? + def hash? + !blank?(hash) + end + + def scheme + parts&.scheme + end + + def remote? + REMOTE_SCHEMES.include?(scheme) + end + + def http? + scheme == "http" + end + + def https? + scheme == "https" + end + + def non_http_remote? + !scheme.nil? && !remote? + end + + def host + parts&.host + end + + def domain_path + (host || "") + path + end + + def query_values + parts&.query_values + end + + # checks if a file exists relative to the current pwd + def exists? + return true if base64? + + !resolved_path.nil? + end + + def resolved_path + path_to_resolve = absolute_path + + return @runner.resolved_paths[path_to_resolve] if @runner.resolved_paths.key?(path_to_resolve) + + # extensionless URLs + path_with_extension = "#{path_to_resolve}#{@runner.options[:assume_extension]}" + resolved = if @runner.options[:assume_extension] && File.file?(path_with_extension) + path_with_extension # existence checked implicitly by File.file? + # implicit index support + elsif File.directory?(path_to_resolve) && !unslashed_directory?(path_to_resolve) + path_with_index = File.join(path_to_resolve, @runner.options[:directory_index_file]) + path_with_index if File.file?(path_with_index) + # explicit file or directory + elsif File.exist?(path_to_resolve) + path_to_resolve + end + @runner.resolved_paths[path_to_resolve] = resolved + + resolved + end + + def base64? + /^data:image/.match?(@raw_attribute) + end + + def absolute_path + path = full_path || @filename + + File.expand_path(path, Dir.pwd) + end + + def full_path + return if path.nil? || path.empty? + + base = if absolute_path?(path) # path relative to root + # either overwrite with root_dir; or, if source is directory, use that; or, just get the source file's dirname + @runner.options[:root_dir] || (File.directory?(@source) ? @source : File.dirname(@source)) + else + # path relative to the file where the link is defined + File.dirname(@filename) + end + + File.join(base, path) + end + + def unslashed_directory?(file) + return false unless File.directory?(file) + + !file.end_with?(File::SEPARATOR) && !follow_location? + end + + def follow_location? + @runner.options[:typhoeus] && @runner.options[:typhoeus][:followlocation] + end + + def absolute_path?(path) + path.start_with?("/") + end + + # path is external to the file + def external? + !internal? + end + + def internal? + relative_link? || internal_absolute_link? || hash_link? + end + + def internal_absolute_link? + url.start_with?("/") + end + + def relative_link? + return false if remote? + + hash_link? || param_link? || url.start_with?(".") || url =~ /^\S/ + end + + def link_points_to_same_page? + hash_link || param_link + end + + def hash_link? + url.start_with?("#") + end + + def has_hash? + url.include?("#") + end + + def param_link? + url.start_with?("?") + end + + def without_hash + @url.to_s.sub(/##{hash}/, "") + end + + # catch any obvious issues + private def clean_url! + parsed_url = Addressable::URI.parse(@url) + url = if parsed_url.scheme.nil? + parsed_url + else + parsed_url.normalize + end.to_s + + # normalize strips this off, which causes issues with cache + @url = if @url.end_with?("/") && !url.end_with?("/") + "#{url}/" + elsif !@url.end_with?("/") && url.end_with?("/") + url.chop + else + url + end + rescue Addressable::URI::InvalidURIError # rubocop:disable Lint/SuppressedException -- error will be reported at check time + end + + private def swap_urls! + return @url if blank?(replacements = @runner.options[:swap_urls]) + + replacements.each do |link, replace| + @url = @url.gsub(link, replace) + end + end + + private def ignores_pattern?(links_to_ignore) + return false unless links_to_ignore.is_a?(Array) + + links_to_ignore.each do |link_to_ignore| + case link_to_ignore + when String + return true if link_to_ignore == @raw_attribute + when Regexp + return true if link_to_ignore&.match?(@raw_attribute) + end + end + + false + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/cache.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/cache.rb new file mode 100644 index 00000000..ef0cf3c7 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/cache.rb @@ -0,0 +1,295 @@ +# frozen_string_literal: true + +require "date" +require "json" +require "uri" + +module HTMLProofer + class Cache + include HTMLProofer::Utils + + CACHE_VERSION = 2 + + DEFAULT_STORAGE_DIR = File.join("tmp", ".htmlproofer") + DEFAULT_CACHE_FILE_NAME = "cache.json" + + URI_REGEXP = URI::DEFAULT_PARSER.make_regexp + + attr_reader :exists, :cache_log, :storage_dir, :cache_file + + def initialize(runner, options) + @runner = runner + @logger = @runner.logger + + @cache_datetime = Time.now + @cache_time = @cache_datetime.to_time + + if blank?(options) + define_singleton_method(:enabled?) { false } + define_singleton_method(:external_enabled?) { false } + define_singleton_method(:internal_enabled?) { false } + else + # we still consider the cache as enabled, regardless of the specic timeframes + define_singleton_method(:enabled?) { true } + setup_cache!(options) + + @external_timeframe = parsed_timeframe(options[:timeframe][:external]) + define_singleton_method(:external_enabled?) { !@external_timeframe.nil? } + @internal_timeframe = parsed_timeframe(options[:timeframe][:internal]) + define_singleton_method(:internal_enabled?) { !@internal_timeframe.nil? } + end + end + + def parsed_timeframe(timeframe) + return if timeframe.nil? + + time, date = timeframe.match(/(\d+)(\D)/).captures + time = time.to_i + case date + when "M" + time_ago(time, :months) + when "w" + time_ago(time, :weeks) + when "d" + time_ago(time, :days) + when "h" + time_ago(time, :hours) + else + raise ArgumentError, "#{date} is not a valid timeframe!" + end + end + + def add_internal(url, metadata, found) + return unless internal_enabled? + + @cache_log[:internal][url] = { time: @cache_time, metadata: [] } if @cache_log[:internal][url].nil? + + @cache_log[:internal][url][:metadata] << construct_internal_link_metadata(metadata, found) + end + + def add_external(url, filenames, status_code, msg, found) + return unless external_enabled? + + clean_url = cleaned_url(url) + @cache_log[:external][clean_url] = + { time: @cache_time.to_s, found: found, status_code: status_code, message: msg, metadata: filenames } + end + + def detect_url_changes(urls_detected, type) + determine_deletions(urls_detected, type) + + additions = determine_additions(urls_detected, type) + + additions + end + + def write + return unless enabled? + + File.write(@cache_file, @cache_log.to_json) + end + + def retrieve_urls(urls_detected, type) + # if there are no urls, bail + return {} if urls_detected.empty? + + if type == :external + urls_detected = urls_detected.transform_keys do |url| + cleaned_url(url) + end + end + + urls_to_check = detect_url_changes(urls_detected, type) + + urls_to_check + end + + def within_external_timeframe?(time) + within_timeframe?(time, @external_timeframe) + end + + def within_internal_timeframe?(time) + within_timeframe?(time, @internal_timeframe) + end + + def empty? + blank?(@cache_log) || (@cache_log[:internal].empty? && @cache_log[:external].empty?) + end + + def size(type) + @cache_log[type].size + end + + private def construct_internal_link_metadata(metadata, found) + { + source: metadata[:source], + filename: metadata[:filename], + line: metadata[:line], + base_url: metadata[:base_url], + found: found, + } + end + + # prepare to add new URLs detected + private def determine_additions(urls_detected, type) + additions = type == :external ? determine_external_additions(urls_detected) : determine_internal_additions(urls_detected) + + new_link_count = additions.length + new_link_text = pluralize(new_link_count, "new #{type} link", "new #{type} links") + @logger.log(:debug, "Adding #{new_link_text} to the cache") + + additions + end + + private def determine_external_additions(urls_detected) + urls_detected.reject do |url, _metadata| + if @cache_log[:external].include?(url) + found = @cache_log[:external][url][:found] # if this is false, we're trying again + unless found + @logger.log(:debug, "Adding #{url} to external cache (not found)") + end + found + else + @logger.log(:debug, "Adding #{url} to external cache") + false + end + end + end + + private def determine_internal_additions(urls_detected) + urls_detected.each_with_object({}) do |(url, detected_metadata), hsh| + # url is not even in cache + if @cache_log[:internal][url].nil? + @logger.log(:debug, "Adding #{url} to internal cache") + hsh[url] = detected_metadata + next + end + + # detect metadata additions + # NOTE: the time-stamp for the whole url key will not be updated, + # so that it reflects the earliest time any of the metadata was checked + cache_metadata = @cache_log[:internal][url][:metadata] + metadata_additions = detected_metadata.reject do |detected| + existing_cache_metadata = cache_metadata.find { |cached, _| cached[:filename] == detected[:filename] } + # cache for this url, from an existing path, exists as found + found = !existing_cache_metadata.nil? && !existing_cache_metadata.empty? && existing_cache_metadata[:found] + unless found + @logger.log(:debug, "Adding #{detected} to internal cache for #{url}") + end + found + end + + if metadata_additions.empty? + next + end + + hsh[url] = metadata_additions + # remove from the cache the detected metadata additions as they correspond to failures to be rechecked + # (this works assuming the detected url metadata have "found" set to false) + @cache_log[:internal][url][:metadata] = cache_metadata.difference(metadata_additions) + end + end + + # remove from cache URLs that no longer exist + private def determine_deletions(urls_detected, type) + deletions = 0 + + @cache_log[type].delete_if do |url, cache| + expired_timeframe = type == :external ? !within_external_timeframe?(cache[:time]) : !within_internal_timeframe?(cache[:time]) + if expired_timeframe + @logger.log(:debug, "Removing #{url} from #{type} cache (expired timeframe)") + deletions += 1 + true + elsif urls_detected.include?(url) + false + elsif url_matches_type?(url, type) + @logger.log(:debug, "Removing #{url} from #{type} cache (not detected anymore)") + deletions += 1 + true + end + end + + del_link_text = pluralize(deletions, "outdated #{type} link", "outdated #{type} links") + @logger.log(:debug, "Removing #{del_link_text} from the cache") + end + + private def setup_cache!(options) + default_structure = { + version: CACHE_VERSION, + internal: {}, + external: {}, + } + + @storage_dir = options[:storage_dir] || DEFAULT_STORAGE_DIR + + FileUtils.mkdir_p(storage_dir) unless Dir.exist?(storage_dir) + + cache_file_name = options[:cache_file] || DEFAULT_CACHE_FILE_NAME + + @cache_file = File.join(storage_dir, cache_file_name) + + return (@cache_log = default_structure) unless File.exist?(@cache_file) + + contents = File.read(@cache_file) + + return (@cache_log = default_structure) if blank?(contents) + + log = JSON.parse(contents, symbolize_names: true) + + old_cache = (cache_version = log[:version]).nil? + @cache_log = if old_cache # previous cache version, create a new one + default_structure + elsif cache_version != CACHE_VERSION + # if cache version is newer...do something + else + log[:internal] = log[:internal].transform_keys(&:to_s) + log[:external] = log[:external].transform_keys(&:to_s) + log + end + end + + # https://github.com/rails/rails/blob/3872bc0e54d32e8bf3a6299b0bfe173d94b072fc/activesupport/lib/active_support/duration.rb#L112-L117 + SECONDS_PER_HOUR = 3600 + SECONDS_PER_DAY = 86400 + SECONDS_PER_WEEK = 604800 + SECONDS_PER_MONTH = 2629746 # 1/12 of a gregorian year + + private def time_ago(measurement, unit) + case unit + when :months + @cache_datetime - (SECONDS_PER_MONTH * measurement) + when :weeks + @cache_datetime - (SECONDS_PER_WEEK * measurement) + when :days + @cache_datetime - (SECONDS_PER_DAY * measurement) + when :hours + @cache_datetime - Rational(SECONDS_PER_HOUR * measurement) + end.to_time + end + + private def url_matches_type?(url, type) + return true if type == :internal && url !~ URI_REGEXP + + true if type == :external && url =~ URI_REGEXP + end + + private def cleaned_url(url) + cleaned_url = escape_unescape(url) + + return cleaned_url unless cleaned_url.end_with?("/", "#", "?") && cleaned_url.length > 1 + + cleaned_url[0..-2] + end + + private def escape_unescape(url) + Addressable::URI.parse(url).normalize.to_s + end + + private def within_timeframe?(current_time, parsed_timeframe) + return false if current_time.nil? || parsed_timeframe.nil? + + current_time = Time.parse(current_time) if current_time.is_a?(String) + (parsed_timeframe..@cache_time).cover?(current_time) + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check.rb new file mode 100644 index 00000000..77ac6df2 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +module HTMLProofer + # Mostly handles issue management and collecting of external URLs. + class Check + include HTMLProofer::Utils + + attr_reader :failures, :options, :internal_urls, :external_urls + + def initialize(runner, html) + @runner = runner + @html = remove_ignored(html) + + @external_urls = {} + @internal_urls = {} + @failures = [] + end + + def create_element(node) + Element.new(@runner, node, base_url: base_url) + end + + def run + raise NotImplementedError, "HTMLProofer::Check subclasses must implement #run" + end + + def add_failure(description, element: nil, line: nil, status: nil, content: nil) + @failures << Failure.new( + @runner.current_filename, + short_name, + description, + line: element.nil? ? line : element.line, + status: status, + content: element.nil? ? content : element.content, + ) + end + + def short_name + self.class.name.split("::").last + end + + def add_to_internal_urls(url, line) + url_string = url.raw_attribute + + @internal_urls[url_string] = [] if @internal_urls[url_string].nil? + + metadata = { + source: url.source, + filename: url.filename, + line: line, + base_url: base_url, + found: false, + } + @internal_urls[url_string] << metadata + end + + def add_to_external_urls(url, line) + url_string = url.to_s + + @external_urls[url_string] = [] if @external_urls[url_string].nil? + + @external_urls[url_string] << { filename: url.filename, line: line } + end + + class << self + def subchecks(runner_options) + # grab all known checks + checks = ObjectSpace.each_object(Class).select do |klass| + klass < self + end + + # remove any checks not explicitly included + checks.each_with_object([]) do |check, arr| + next unless runner_options[:checks].include?(check.short_name) + + arr << check + end + end + + def short_name + name.split("::").last + end + end + + private def base_url + return @base_url if defined?(@base_url) + + return (@base_url = "") if (base = @html.at_css("base")).nil? + + @base_url = base["href"] + end + + private def remove_ignored(html) + return if html.nil? + + html.css("code, pre, tt").each(&:unlink) + html + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/favicon.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/favicon.rb new file mode 100644 index 00000000..19f5601b --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/favicon.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module HTMLProofer + class Check + class Favicon < HTMLProofer::Check + def run + found = false + @html.css("link").each do |node| + @favicon = create_element(node) + + next if @favicon.ignore? + + break if (found = @favicon.node["rel"].split.last.eql?("icon")) + end + + return if immediate_redirect? + + if found + if @favicon.url.protocol_relative? + add_failure( + "favicon link #{@favicon.url} is a protocol-relative URL, use explicit https:// instead", + element: @favicon, + ) + elsif @favicon.url.remote? + add_to_external_urls(@favicon.url, @favicon.line) + elsif !@favicon.url.exists? + add_failure( + "internal favicon #{@favicon.url.raw_attribute} does not exist", + element: @favicon, + ) + end + else + add_failure("no favicon provided") + end + end + + private + + # allow any instant-redirect meta tag + def immediate_redirect? + @html.xpath("//meta[@http-equiv='refresh']").attribute("content").value.start_with?("0;") + rescue StandardError + false + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/images.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/images.rb new file mode 100644 index 00000000..874fe40a --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/images.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module HTMLProofer + class Check + class Images < HTMLProofer::Check + SCREEN_SHOT_REGEX = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/ + + def run + @html.css("img, source").each do |node| + @img = create_element(node) + + next if @img.ignore? + + # screenshot filenames should return because of terrible names + add_failure( + "image has a terrible filename (#{@img.url.raw_attribute})", + element: @img, + ) if terrible_filename? + + # does the image exist? + if missing_src? + add_failure("image has no src or srcset attribute", element: @img) + elsif @img.multiple_srcsets? || @img.multiple_sizes? + @img.srcsets_wo_sizes.each do |srcset| + srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, source: @img.url.source, filename: @img.url.filename, extract_size: true) + + if srcset_url.protocol_relative? + add_failure( + "image link #{srcset_url.url} is a protocol-relative URL, use explicit https:// instead", + element: @img, + ) + elsif srcset_url.remote? + add_to_external_urls(srcset_url.url, @img.line) + elsif !srcset_url.exists? + add_failure("internal image #{srcset} does not exist", element: @img) + end + end + elsif @img.url.protocol_relative? + add_failure( + "image link #{@img.url} is a protocol-relative URL, use explicit https:// instead", + element: @img, + ) + elsif @img.url.remote? + add_to_external_urls(@img.url, @img.line) + elsif !@img.url.exists? && !@img.multiple_srcsets? && !@img.multiple_sizes? + add_failure( + "internal image #{@img.url.raw_attribute} does not exist", + element: @img, + ) + end + + # if this is an img element, check that the alt attribute is present + if @img.img_tag? && !ignore_element? + if missing_alt_tag? && !ignore_missing_alt? + add_failure( + "image #{@img.url.raw_attribute} does not have an alt attribute", + element: @img, + ) + elsif (empty_alt_tag? || alt_all_spaces?) && !ignore_empty_alt? + add_failure( + "image #{@img.url.raw_attribute} has an alt attribute, but no content", + element: @img, + ) + end + end + + add_failure( + "image #{@img.url.raw_attribute} uses the http scheme", + element: @img, + ) if @runner.enforce_https? && @img.url.http? + end + + external_urls + end + + def ignore_missing_alt? + @runner.options[:ignore_missing_alt] + end + + def ignore_empty_alt? + @runner.options[:ignore_empty_alt] + end + + def ignore_element? + @img.url.ignore? || @img.aria_hidden? + end + + def missing_alt_tag? + @img.node["alt"].nil? + end + + def empty_alt_tag? + !missing_alt_tag? && @img.node["alt"].empty? + end + + def empty_whitespace_alt_tag? + !missing_alt_tag? && @img.node["alt"].strip.empty? + end + + def alt_all_spaces? + !missing_alt_tag? && @img.node["alt"].split.all?(" ") + end + + def terrible_filename? + @img.url.to_s =~ SCREEN_SHOT_REGEX + end + + def missing_src? + blank?(@img.url.to_s) + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/links.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/links.rb new file mode 100644 index 00000000..ad0199bd --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/links.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +module HTMLProofer + class Check + class Links < HTMLProofer::Check + def run + @html.css("a, link").each do |node| + @link = create_element(node) + + next if @link.ignore? + + if !allow_hash_href? && @link.node["href"] == "#" + add_failure("linking to internal hash #, which points to nowhere", element: @link) + next + end + + # is there even an href? + if blank?(@link.url.raw_attribute) + next if allow_missing_href? + + add_failure("'#{@link.node.name}' tag is missing a reference", element: @link) + next + end + + # is it even a valid URL? + unless @link.url.valid? + add_failure("#{@link.href} is an invalid URL", element: @link) + next + end + + if @link.url.protocol_relative? + add_failure( + "#{@link.url} is a protocol-relative URL, use explicit https:// instead", + element: @link, + ) + next + end + + check_schemes + + # intentionally down here because we still want valid? & missing_href? to execute + next if @link.url.non_http_remote? + + if !@link.url.internal? && @link.url.remote? + check_sri if @runner.check_sri? && @link.link_tag? + + # we need to skip these for now; although the domain main be valid, + # curl/Typheous inaccurately return 404s for some links. cc https://git.io/vyCFx + next if @link.node["rel"] == "dns-prefetch" + + unless @link.url.path? + add_failure("#{@link.url.raw_attribute} is an invalid URL", element: @link) + next + end + + add_to_external_urls(@link.url, @link.line) + elsif @link.url.internal? + # does the local directory have a trailing slash? + if @link.url.unslashed_directory?(@link.url.absolute_path) + add_failure( + "internally linking to a directory #{@link.url.raw_attribute} without trailing slash", + element: @link, + ) + next + end + + add_to_internal_urls(@link.url, @link.line) + end + end + end + + def allow_missing_href? + @runner.options[:allow_missing_href] + end + + def allow_hash_href? + @runner.options[:allow_hash_href] + end + + def check_schemes + case @link.url.scheme + when "mailto" + handle_mailto + when "tel" + handle_tel + when "http" + return unless @runner.options[:enforce_https] + + add_failure("#{@link.url.raw_attribute} is not an HTTPS link", element: @link) + end + end + + def handle_mailto + if @link.url.path.empty? + add_failure( + "#{@link.url.raw_attribute} contains no email address", + element: @link, + ) unless ignore_empty_mailto? + # eg., if any do not match a valid URL + elsif @link.url.path.split(",").any? { |email| !/#{URI::MailTo::EMAIL_REGEXP}/o.match?(email) } + add_failure( + "#{@link.url.raw_attribute} contains an invalid email address", + element: @link, + ) + end + end + + def handle_tel + add_failure( + "#{@link.url.raw_attribute} contains no phone number", + element: @link, + ) if @link.url.path.empty? + end + + def ignore_empty_mailto? + @runner.options[:ignore_empty_mailto] + end + + # Allowed elements from Subresource Integrity specification + # https://w3c.github.io/webappsec-subresource-integrity/#link-element-for-stylesheets + SRI_REL_TYPES = %(stylesheet) + + def check_sri + return unless SRI_REL_TYPES.include?(@link.node["rel"]) + + if blank?(@link.node["integrity"]) && blank?(@link.node["crossorigin"]) + add_failure( + "SRI and CORS not provided in: #{@link.url.raw_attribute}", + element: @link, + ) + elsif blank?(@link.node["integrity"]) + add_failure("Integrity is missing in: #{@link.url.raw_attribute}", element: @link) + elsif blank?(@link.node["crossorigin"]) + add_failure( + "CORS not provided for external resource in: #{@link.link.url.raw_attribute}", + element: @link, + ) + end + end + + private def source_tag? + @link.node.name == "source" + end + + private def anchor_tag? + @link.node.name == "a" + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/open_graph.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/open_graph.rb new file mode 100644 index 00000000..3f10ee67 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/open_graph.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module HTMLProofer + class Check + class OpenGraph < HTMLProofer::Check + def run + @html.css('meta[property="og:url"], meta[property="og:image"]').each do |node| + @open_graph = create_element(node) + + next if @open_graph.ignore? + + # does the open_graph exist? + if missing_content? + add_failure("open graph has no content attribute", element: @open_graph) + elsif empty_content? + add_failure("open graph content attribute is empty", element: @open_graph) + elsif !@open_graph.url.valid? + add_failure("#{@open_graph.src} is an invalid URL", element: @open_graph) + elsif @open_graph.url.protocol_relative? + add_failure( + "open graph link #{@open_graph.url} is a protocol-relative URL, use explicit https:// instead", + element: @open_graph, + ) + elsif @open_graph.url.remote? + add_to_external_urls(@open_graph.url, @open_graph.line) + else + add_failure( + "internal open graph #{@open_graph.url.raw_attribute} does not exist", + element: @open_graph, + ) unless @open_graph.url.exists? + end + end + + external_urls + end + + private def missing_content? + @open_graph.node["content"].nil? + end + + private def empty_content? + @open_graph.node["content"].empty? + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/scripts.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/scripts.rb new file mode 100644 index 00000000..f80e20f8 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/check/scripts.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module HTMLProofer + class Check + class Scripts < HTMLProofer::Check + def run + @html.css("script").each do |node| + @script = create_element(node) + + next if @script.ignore? + next unless @script.content.strip.empty? + + # does the script exist? + if missing_src? + add_failure("script is empty and has no src attribute", element: @script) + elsif @script.url.protocol_relative? + add_failure( + "script link #{@script.url} is a protocol-relative URL, use explicit https:// instead", + element: @script, + ) + elsif @script.url.remote? + add_to_external_urls(@script.url, @script.line) + check_sri if @runner.check_sri? + elsif !@script.url.exists? + add_failure( + "internal script reference #{@script.src} does not exist", + element: @script, + ) + end + end + + external_urls + end + + def missing_src? + @script.node["src"].nil? + end + + def check_sri + if blank?(@script.node["integrity"]) && blank?(@script.node["crossorigin"]) + add_failure( + "SRI and CORS not provided in: #{@script.url.raw_attribute}", + element: @script, + ) + elsif blank?(@script.node["integrity"]) + add_failure( + "Integrity is missing in: #{@script.url.raw_attribute}", + element: @script, + ) + elsif blank?(@script.node["crossorigin"]) + add_failure( + "CORS not provided for external resource in: #{@script.url.raw_attribute}", + element: @script, + ) + end + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/cli.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/cli.rb new file mode 100644 index 00000000..bbece106 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/cli.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module HTMLProofer + # The CLI is a class responsible of handling all the command line interface + # logic. + class CLI + attr_reader :options + + def initialize + @options = {} + end + + def run(args = ARGV) + @options, path = HTMLProofer::Configuration.new.parse_cli_options(args) + + paths = path.split(",") + + if @options[:as_links] + links = path.split(",").map(&:strip) + HTMLProofer.check_links(links, @options).run + elsif File.directory?(paths.first) + HTMLProofer.check_directories(paths, @options).run + else + HTMLProofer.check_file(path, @options).run + end + end + end +end diff --git a/bin/gems/html-proofer-5.0.10/lib/html_proofer/configuration.rb b/bin/gems/html-proofer-5.0.10/lib/html_proofer/configuration.rb new file mode 100644 index 00000000..58936306 --- /dev/null +++ b/bin/gems/html-proofer-5.0.10/lib/html_proofer/configuration.rb @@ -0,0 +1,351 @@ +# frozen_string_literal: true + +require "optparse" + +module HTMLProofer + class Configuration + DEFAULT_TESTS = ["Links", "Images", "Scripts"].freeze + + PROOFER_DEFAULTS = { + allow_hash_href: true, + allow_missing_href: false, + assume_extension: ".html", + check_external_hash: true, + check_internal_hash: true, + checks: DEFAULT_TESTS, + directory_index_file: "index.html", + disable_external: false, + ignore_empty_alt: true, + ignore_empty_mailto: false, + ignore_files: [], + ignore_missing_alt: false, + ignore_status_codes: [], + ignore_urls: [], + enforce_https: true, + extensions: [".html"], + log_level: :info, + only_4xx: false, + swap_attributes: {}, + swap_urls: {}, + }.freeze + + TYPHOEUS_DEFAULTS = { + followlocation: true, + headers: { + "User-Agent" => "Mozilla/5.0 (compatible; HTML Proofer/#{HTMLProofer::VERSION}; +https://github.com/gjtorikian/html-proofer)", + "Accept" => "application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5", + }, + connecttimeout: 10, + timeout: 30, + }.freeze + + HYDRA_DEFAULTS = { + max_concurrency: 50, + }.freeze + + CACHE_DEFAULTS = {}.freeze + + class << self + def generate_defaults(opts) + options = PROOFER_DEFAULTS.merge(opts) + + options[:typhoeus] = HTMLProofer::Configuration::TYPHOEUS_DEFAULTS.merge(opts[:typhoeus] || {}) + options[:hydra] = HTMLProofer::Configuration::HYDRA_DEFAULTS.merge(opts[:hydra] || {}) + + options[:cache] = HTMLProofer::Configuration::CACHE_DEFAULTS.merge(opts[:cache] || {}) + + options.delete(:src) + + options + end + end + + def initialize + @options = {} + end + + def parse_cli_options(args) + define_options.parse!(args) + + input = ARGV.empty? ? "." : ARGV.join(",") + + [@options, input] + end + + private def define_options + OptionParser.new do |opts| + opts.banner = "Usage: htmlproofer [options] PATH/LINK" + + section(opts, "Input Options") do + set_option(opts, "--as-links") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--assume-extension EXT") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--directory-index-file FILENAME") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--extensions [EXT1,EXT2,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = list.nil? ? [] : list.split(",") + end + end + + section(opts, "Check Configuration") do + set_option(opts, "--[no-]allow-hash-href") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]allow-missing-href") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--checks [CHECK1,CHECK2,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = list.nil? ? [] : list.split(",") + end + + set_option(opts, "--[no-]check-external-hash") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]check-internal-hash") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]check-sri") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]disable-external") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]enforce-https") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--root-dir ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + end + + section(opts, "Ignore Configuration") do + set_option(opts, "--ignore-files [FILE1,FILE2,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = if list.nil? + [] + else + list.split(",").map.each do |l| + if l.start_with?("/") && l.end_with?("/") + Regexp.new(l[1...-1]) + else + l + end + end + end + end + + set_option(opts, "--[no-]ignore-empty-alt") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]ignore-empty-mailto") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--[no-]ignore-missing-alt") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + + set_option(opts, "--ignore-status-codes [500,401,420,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = list.nil? ? [] : list.split(",").map(&:to_i) + end + + set_option(opts, "--ignore-urls [URL1, URL2,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = if list.nil? + [] + else + list.split(",").each_with_object([]) do |url, arr| + arr << to_regex?(url) + end + end + end + + set_option(opts, "--only-status-codes [404,451,...]") do |long_opt_symbol, list| + @options[long_opt_symbol] = list.nil? ? [] : list.split(",") + end + + set_option(opts, "--only-4xx") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg + end + end + + section(opts, "Transforms Configuration") do + set_option(opts, "--swap-attributes ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = parse_json_option("swap_attributes", arg, symbolize_names: false) + end + + set_option(opts, "--swap-urls [re:string,re:string,...]") do |long_opt_symbol, arg| + @options[long_opt_symbol] = str_to_regexp_map(arg) + end + end + + section(opts, "Dependencies Configuration") do + set_option(opts, "--typhoeus ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = parse_json_option("typhoeus", arg, symbolize_names: false) + end + + set_option(opts, "--hydra ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = parse_json_option("hydra", arg, symbolize_names: true) + end + + set_option(opts, "--cache ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = parse_json_option("cache", arg, symbolize_names: true) + end + end + + section(opts, "Reporting Configuration") do + set_option(opts, "--log-level ") do |long_opt_symbol, arg| + @options[long_opt_symbol] = arg.to_sym + end + end + + section(opts, "General Configuration") do + set_option(opts, "--version") do + puts HTMLProofer::VERSION + exit(0) + end + end + end + end + + private def to_regex?(item) + if item.start_with?("/") && item.end_with?("/") + Regexp.new(item[1...-1]) + else + item + end + end + + private def str_to_regexp_map(arg) + arg.split(",").each_with_object({}) do |s, hsh| + split = s.split(/(? :allow_hash_href. + private def parse_long_opt(long_opt) + long_opt[2..].sub("[no-]", "").sub(/ .*/, "").tr("-", "_").gsub(/[\[\]]/, "").to_sym + end + + def parse_json_option(option_name, config, symbolize_names: true) + raise ArgumentError, "Must provide an option name in string format." unless option_name.is_a?(String) + raise ArgumentError, "Must provide an option name in string format." if option_name.strip.empty? + + return {} if config.nil? + + raise ArgumentError, "Must provide a JSON configuration in string format." unless config.is_a?(String) + + return {} if config.strip.empty? + + begin + JSON.parse(config, { symbolize_names: symbolize_names }) + rescue StandardError + raise ArgumentError, "Option '#{option_name} did not contain valid JSON." + end + end + + module ConfigurationHelp + TEXT = { + as_links: ["Assumes that `PATH` is a comma-separated array of links to check."], + assume_extension: [ + "Automatically add specified extension to files for internal links, ", + "to allow extensionless URLs (as supported by most servers) (default: `.html`).", + ], + directory_index_file: ["Sets the file to look for when a link refers to a directory. (default: `index.html`)."], + extensions: [ + "A comma-separated list of Strings indicating the file extensions you", + "would like to check (default: `.html`)", + ], + + allow_hash_href: ['"If `true`, assumes `href="#"` anchors are valid (default: `true`)"'], + allow_missing_href: [ + "If `true`, does not flag `a` tags missing `href`. In HTML5, this is technically ", + "allowed, but could also be human error. (default: `false`)", + ], + checks: [ + "A comma-separated list of Strings indicating which checks you", + "want to run (default: `[\"Links\", \"Images\", \"Scripts\"]", + ], + check_external_hash: ["Checks whether external hashes exist (even if the webpage exists) (default: `true`)."], + check_internal_hash: ["Checks whether internal hashes exist (even if the webpage exists) (default: `true`)."], + check_sri: ["Check that `` and ` + TEMPLATE + end + + def livereload_args + # XHTML standard requires ampersands to be encoded as entities when in + # attributes. See http://stackoverflow.com/a/2190292 + src = "" + if @options["livereload_min_delay"] + src += "&mindelay=#{@options["livereload_min_delay"]}" + end + if @options["livereload_max_delay"] + src += "&maxdelay=#{@options["livereload_max_delay"]}" + end + src += "&port=#{@options["livereload_port"]}" if @options["livereload_port"] + src + end + end + + class Servlet < WEBrick::HTTPServlet::FileHandler + DEFAULTS = { + "Cache-Control" => "private, max-age=0, proxy-revalidate, " \ + "no-store, no-cache, must-revalidate", + }.freeze + + def initialize(server, root, callbacks) + # So we can access them easily. + @jekyll_opts = server.config[:JekyllOptions] + @mime_types_charset = server.config[:MimeTypesCharset] + set_defaults + super + end + + def search_index_file(req, res) + super || + search_file(req, res, ".html") || + search_file(req, res, ".xhtml") + end + + # Add the ability to tap file.html the same way that Nginx does on our + # Docker images (or on GitHub Pages.) The difference is that we might end + # up with a different preference on which comes first. + + def search_file(req, res, basename) + # /file.* > /file/index.html > /file.html + super || + super(req, res, "#{basename}.html") || + super(req, res, "#{basename}.xhtml") + end + + # rubocop:disable Naming/MethodName + def do_GET(req, res) + rtn = super + + if @jekyll_opts["livereload"] + return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts) + + processor = BodyProcessor.new(res.body, @jekyll_opts) + processor.process! + res.body = processor.new_body + res.content_length = processor.content_length.to_s + + if processor.livereload_added + # Add a header to indicate that the page content has been modified + res["X-Rack-LiveReload"] = "1" + end + end + + conditionally_inject_charset(res) + res.header.merge!(@headers) + rtn + end + # rubocop:enable Naming/MethodName + + private + + # Inject charset based on Jekyll config only if our mime-types database contains + # the charset metadata. + # + # Refer `script/vendor-mimes` in the repository for further details. + def conditionally_inject_charset(res) + typ = res.header["content-type"] + return unless @mime_types_charset.key?(typ) + return if %r!;\s*charset=!.match?(typ) + + res.header["content-type"] = "#{typ}; charset=#{@jekyll_opts["encoding"]}" + end + + def set_defaults + hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {}) + DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash| + hash[key] = val unless hash.key?(key) + end + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb new file mode 100644 index 00000000..6aa522cc --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require "http/parser" + +module Jekyll + module Commands + class Serve + # The LiveReload protocol requires the server to serve livereload.js over HTTP + # despite the fact that the protocol itself uses WebSockets. This custom connection + # class addresses the dual protocols that the server needs to understand. + class HttpAwareConnection < EventMachine::WebSocket::Connection + attr_reader :reload_body, :reload_size + + def initialize(_opts) + # If EventMachine SSL support on Windows ever gets better, the code below will + # set up the reactor to handle SSL + # + # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"] + # if @ssl_enabled + # em_opts[:tls_options] = { + # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]), + # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"]) + # } + # em_opts[:secure] = true + # end + + # This is too noisy even for --verbose, but uncomment if you need it for + # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will + # enable logging on the client side. + # em_opts[:debug] = true + + em_opts = {} + super(em_opts) + + reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js") + + @reload_body = File.read(reload_file) + @reload_size = @reload_body.bytesize + end + + # rubocop:disable Metrics/MethodLength + def dispatch(data) + parser = Http::Parser.new + parser << data + + # WebSockets requests will have a Connection: Upgrade header + if parser.http_method != "GET" || parser.upgrade? + super + elsif parser.request_url.start_with?("/livereload.js") + headers = [ + "HTTP/1.1 200 OK", + "Content-Type: application/javascript", + "Content-Length: #{reload_size}", + "", + "", + ].join("\r\n") + send_data(headers) + + # stream_file_data would free us from keeping livereload.js in memory + # but JRuby blocks on that call and never returns + send_data(reload_body) + close_connection_after_writing + else + body = "This port only serves livereload.js over HTTP.\n" + headers = [ + "HTTP/1.1 400 Bad Request", + "Content-Type: text/plain", + "Content-Length: #{body.bytesize}", + "", + "", + ].join("\r\n") + send_data(headers) + send_data(body) + close_connection_after_writing + end + end + # rubocop:enable Metrics/MethodLength + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/configuration.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/configuration.rb new file mode 100644 index 00000000..9b2fbffc --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/configuration.rb @@ -0,0 +1,313 @@ +# frozen_string_literal: true + +module Jekyll + class Configuration < Hash + # Default options. Overridden by values in _config.yml. + # Strings rather than symbols are used for compatibility with YAML. + DEFAULTS = { + # Where things are + "source" => Dir.pwd, + "destination" => File.join(Dir.pwd, "_site"), + "collections_dir" => "", + "cache_dir" => ".jekyll-cache", + "plugins_dir" => "_plugins", + "layouts_dir" => "_layouts", + "data_dir" => "_data", + "includes_dir" => "_includes", + "collections" => {}, + + # Handling Reading + "safe" => false, + "include" => [".htaccess"], + "exclude" => [], + "keep_files" => [".git", ".svn"], + "encoding" => "utf-8", + "markdown_ext" => "markdown,mkdown,mkdn,mkd,md", + "strict_front_matter" => false, + + # Filtering Content + "show_drafts" => nil, + "limit_posts" => 0, + "future" => false, + "unpublished" => false, + + # Plugins + "whitelist" => [], + "plugins" => [], + + # Conversion + "markdown" => "kramdown", + "highlighter" => "rouge", + "lsi" => false, + "excerpt_separator" => "\n\n", + "incremental" => false, + + # Serving + "detach" => false, # default to not detaching the server + "port" => "4000", + "host" => "127.0.0.1", + "baseurl" => nil, # this mounts at /, i.e. no subdirectory + "show_dir_listing" => false, + + # Output Configuration + "permalink" => "date", + "paginate_path" => "/page:num", + "timezone" => nil, # use the local timezone + + "quiet" => false, + "verbose" => false, + "defaults" => [], + + "liquid" => { + "error_mode" => "warn", + "strict_filters" => false, + "strict_variables" => false, + }, + + "kramdown" => { + "auto_ids" => true, + "toc_levels" => (1..6).to_a, + "entity_output" => "as_char", + "smart_quotes" => "lsquo,rsquo,ldquo,rdquo", + "input" => "GFM", + "hard_wrap" => false, + "guess_lang" => true, + "footnote_nr" => 1, + "show_warnings" => false, + }, + }.each_with_object(Configuration.new) { |(k, v), hsh| hsh[k] = v.freeze }.freeze + + class << self + # Static: Produce a Configuration ready for use in a Site. + # It takes the input, fills in the defaults where values do not exist. + # + # user_config - a Hash or Configuration of overrides. + # + # Returns a Configuration filled with defaults. + def from(user_config) + Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys) + .add_default_collections.add_default_excludes + end + end + + # Public: Turn all keys into string + # + # Return a copy of the hash where all its keys are strings + def stringify_keys + each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v } + end + + def get_config_value_with_override(config_key, override) + override[config_key] || self[config_key] || DEFAULTS[config_key] + end + + # Public: Directory of the Jekyll source folder + # + # override - the command-line options hash + # + # Returns the path to the Jekyll source directory + def source(override) + get_config_value_with_override("source", override) + end + + def quiet(override = {}) + get_config_value_with_override("quiet", override) + end + alias_method :quiet?, :quiet + + def verbose(override = {}) + get_config_value_with_override("verbose", override) + end + alias_method :verbose?, :verbose + + def safe_load_file(filename) + case File.extname(filename) + when %r!\.toml!i + Jekyll::External.require_with_graceful_fail("tomlrb") unless defined?(Tomlrb) + Tomlrb.load_file(filename) + when %r!\.ya?ml!i + SafeYAML.load_file(filename) || {} + else + raise ArgumentError, + "No parser for '#{filename}' is available. Use a .y(a)ml or .toml file instead." + end + end + + # Public: Generate list of configuration files from the override + # + # override - the command-line options hash + # + # Returns an Array of config files + def config_files(override) + # Adjust verbosity quickly + Jekyll.logger.adjust_verbosity( + :quiet => quiet?(override), + :verbose => verbose?(override) + ) + + # Get configuration from /_config.yml or / + config_files = override["config"] + if config_files.to_s.empty? + default = %w(yml yaml toml).find(-> { "yml" }) do |ext| + File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}")) + end + config_files = Jekyll.sanitized_path(source(override), "_config.#{default}") + @default_config_file = true + end + Array(config_files) + end + + # Public: Read configuration and return merged Hash + # + # file - the path to the YAML file to be read in + # + # Returns this configuration, overridden by the values in the file + def read_config_file(file) + file = File.expand_path(file) + next_config = safe_load_file(file) + + unless next_config.is_a?(Hash) + raise ArgumentError, "Configuration file: (INVALID) #{file}".yellow + end + + Jekyll.logger.info "Configuration file:", file + next_config + rescue SystemCallError + if @default_config_file ||= nil + Jekyll.logger.warn "Configuration file:", "none" + {} + else + Jekyll.logger.error "Fatal:", "The configuration file '#{file}' could not be found." + raise LoadError, "The Configuration file '#{file}' could not be found." + end + end + + # Public: Read in a list of configuration files and merge with this hash + # + # files - the list of configuration file paths + # + # Returns the full configuration, with the defaults overridden by the values in the + # configuration files + def read_config_files(files) + configuration = clone + + begin + files.each do |config_file| + next if config_file.nil? || config_file.empty? + + new_config = read_config_file(config_file) + configuration = Utils.deep_merge_hashes(configuration, new_config) + end + rescue ArgumentError => e + Jekyll.logger.warn "WARNING:", "Error reading configuration. Using defaults (and options)." + warn e + end + + configuration.validate.add_default_collections + end + + # Public: Split a CSV string into an array containing its values + # + # csv - the string of comma-separated values + # + # Returns an array of the values contained in the CSV + def csv_to_array(csv) + csv.split(",").map(&:strip) + end + + # Public: Ensure the proper options are set in the configuration + # + # Returns the configuration Hash + def validate + config = clone + + check_plugins(config) + check_include_exclude(config) + + config + end + + def add_default_collections + config = clone + + # It defaults to `{}`, so this is only if someone sets it to null manually. + return config if config["collections"].nil? + + # Ensure we have a hash. + if config["collections"].is_a?(Array) + config["collections"] = config["collections"].each_with_object({}) do |collection, hash| + hash[collection] = {} + end + end + + config["collections"] = Utils.deep_merge_hashes( + { "posts" => {} }, config["collections"] + ).tap do |collections| + collections["posts"]["output"] = true + if config["permalink"] + collections["posts"]["permalink"] ||= style_to_permalink(config["permalink"]) + end + end + + config + end + + DEFAULT_EXCLUDES = %w( + .sass-cache .jekyll-cache + gemfiles Gemfile Gemfile.lock + node_modules + vendor/bundle/ vendor/cache/ vendor/gems/ vendor/ruby/ + ).freeze + + def add_default_excludes + config = clone + return config if config["exclude"].nil? + + config["exclude"].concat(DEFAULT_EXCLUDES).uniq! + config + end + + private + + STYLE_TO_PERMALINK = { + :none => "/:categories/:title:output_ext", + :date => "/:categories/:year/:month/:day/:title:output_ext", + :ordinal => "/:categories/:year/:y_day/:title:output_ext", + :pretty => "/:categories/:year/:month/:day/:title/", + :weekdate => "/:categories/:year/W:week/:short_day/:title:output_ext", + }.freeze + + private_constant :STYLE_TO_PERMALINK + + def style_to_permalink(permalink_style) + STYLE_TO_PERMALINK[permalink_style.to_sym] || permalink_style.to_s + end + + def check_include_exclude(config) + %w(include exclude).each do |option| + next unless config.key?(option) + next if config[option].is_a?(Array) + + raise Jekyll::Errors::InvalidConfigurationError, + "'#{option}' should be set as an array, but was: #{config[option].inspect}." + end + end + + # Private: Checks if the `plugins` config is a String + # + # config - the config hash + # + # Raises a Jekyll::Errors::InvalidConfigurationError if the config `plugins` + # is not an Array. + def check_plugins(config) + return unless config.key?("plugins") + return if config["plugins"].is_a?(Array) + + Jekyll.logger.error "'plugins' should be set as an array of gem-names, but was: " \ + "#{config["plugins"].inspect}. Use 'plugins_dir' instead to set " \ + "the directory for your non-gemified Ruby plugins." + raise Jekyll::Errors::InvalidConfigurationError, + "'plugins' should be set as an array, but was: #{config["plugins"].inspect}." + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/converter.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/converter.rb new file mode 100644 index 00000000..3cb74de2 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/converter.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Jekyll + class Converter < Plugin + # Public: Get or set the highlighter prefix. When an argument is specified, + # the prefix will be set. If no argument is specified, the current prefix + # will be returned. + # + # highlighter_prefix - The String prefix (default: nil). + # + # Returns the String prefix. + def self.highlighter_prefix(highlighter_prefix = nil) + unless defined?(@highlighter_prefix) && highlighter_prefix.nil? + @highlighter_prefix = highlighter_prefix + end + @highlighter_prefix + end + + # Public: Get or set the highlighter suffix. When an argument is specified, + # the suffix will be set. If no argument is specified, the current suffix + # will be returned. + # + # highlighter_suffix - The String suffix (default: nil). + # + # Returns the String suffix. + def self.highlighter_suffix(highlighter_suffix = nil) + unless defined?(@highlighter_suffix) && highlighter_suffix.nil? + @highlighter_suffix = highlighter_suffix + end + @highlighter_suffix + end + + # Initialize the converter. + # + # Returns an initialized Converter. + def initialize(config = {}) + @config = config + end + + # Get the highlighter prefix. + # + # Returns the String prefix. + def highlighter_prefix + self.class.highlighter_prefix + end + + # Get the highlighter suffix. + # + # Returns the String suffix. + def highlighter_suffix + self.class.highlighter_suffix + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb new file mode 100644 index 00000000..7579b330 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Jekyll + module Converters + # Identity converter. Returns same content as given. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class Identity < Converter + safe true + + priority :lowest + + # Public: Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # _ext - The String extension to check (not relevant here) + # + # Returns true since it always matches. + def matches(_ext) + true + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(ext) + ext + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + content + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb new file mode 100644 index 00000000..da1f1ce6 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Jekyll + module Converters + # Markdown converter. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class Markdown < Converter + highlighter_prefix "\n" + highlighter_suffix "\n" + safe true + + def setup + return if @setup ||= false + + unless (@parser = get_processor) + if @config["safe"] + Jekyll.logger.warn "Build Warning:", "Custom processors are not loaded in safe mode" + end + + Jekyll.logger.error "Markdown processor:", + "#{@config["markdown"].inspect} is not a valid Markdown processor." + Jekyll.logger.error "", "Available processors are: #{valid_processors.join(", ")}" + Jekyll.logger.error "" + raise Errors::FatalException, "Invalid Markdown processor given: #{@config["markdown"]}" + end + + @cache = Jekyll::Cache.new("Jekyll::Converters::Markdown") + @setup = true + end + + # RuboCop does not allow reader methods to have names starting with `get_` + # To ensure compatibility, this check has been disabled on this method + # + # rubocop:disable Naming/AccessorMethodName + def get_processor + case @config["markdown"].downcase + when "kramdown" then KramdownParser.new(@config) + else + custom_processor + end + end + # rubocop:enable Naming/AccessorMethodName + + # Public: Provides you with a list of processors comprised of the ones we support internally + # and the ones that you have provided to us (if they're whitelisted for use in safe mode). + # + # Returns an array of symbols. + def valid_processors + [:kramdown] + third_party_processors + end + + # Public: A list of processors that you provide via plugins. + # + # Returns an array of symbols + def third_party_processors + self.class.constants - [:KramdownParser, :PRIORITIES] + end + + # Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # ext - The String extension to check. + # + # Returns true if it matches, false otherwise. + def matches(ext) + extname_list.include?(ext.downcase) + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(_ext) + ".html" + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + setup + @cache.getset(content) do + @parser.convert(content) + end + end + + def extname_list + @extname_list ||= @config["markdown_ext"].split(",").map! { |e| ".#{e.downcase}" } + end + + private + + def custom_processor + converter_name = @config["markdown"] + self.class.const_get(converter_name).new(@config) if custom_class_allowed?(converter_name) + end + + # Private: Determine whether a class name is an allowed custom + # markdown class name. + # + # parser_name - the name of the parser class + # + # Returns true if the parser name contains only alphanumeric characters and is defined + # within Jekyll::Converters::Markdown + def custom_class_allowed?(parser_name) + parser_name !~ %r![^A-Za-z0-9_]! && self.class.constants.include?(parser_name.to_sym) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb new file mode 100644 index 00000000..1e6a1ded --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true + +module Kramdown + # A Kramdown::Document subclass meant to optimize memory usage from initializing + # a kramdown document for parsing. + # + # The optimization is by using the same options Hash (and its derivatives) for + # converting all Markdown documents in a Jekyll site. + class JekyllDocument < Document + class << self + attr_reader :options, :parser + + # The implementation is basically the core logic in +Kramdown::Document#initialize+ + # + # rubocop:disable Naming/MemoizedInstanceVariableName + def setup(options) + @cache ||= {} + + # reset variables on a subsequent set up with a different options Hash + unless @cache[:id] == options.hash + @options = @parser = nil + @cache[:id] = options.hash + end + + @options ||= Options.merge(options).freeze + @parser ||= begin + parser_name = (@options[:input] || "kramdown").to_s + parser_name = parser_name[0..0].upcase + parser_name[1..-1] + try_require("parser", parser_name) + + if Parser.const_defined?(parser_name) + Parser.const_get(parser_name) + else + raise Kramdown::Error, "kramdown has no parser to handle the specified " \ + "input format: #{@options[:input]}" + end + end + end + # rubocop:enable Naming/MemoizedInstanceVariableName + + private + + def try_require(type, name) + require "kramdown/#{type}/#{Utils.snake_case(name)}" + rescue LoadError + false + end + end + + def initialize(source, options = {}) + JekyllDocument.setup(options) + + @options = JekyllDocument.options + @root, @warnings = JekyllDocument.parser.parse(source, @options) + end + + # Use Kramdown::Converter::Html class to convert this document into HTML. + # + # The implementation is basically an optimized version of core logic in + # +Kramdown::Document#method_missing+ from kramdown-2.1.0. + def to_html + output, warnings = Kramdown::Converter::Html.convert(@root, @options) + @warnings.concat(warnings) + output + end + end +end + +# + +module Jekyll + module Converters + class Markdown + class KramdownParser + CODERAY_DEFAULTS = { + "css" => "style", + "bold_every" => 10, + "line_numbers" => "inline", + "line_number_start" => 1, + "tab_width" => 4, + "wrap" => "div", + }.freeze + + def initialize(config) + @main_fallback_highlighter = config["highlighter"] || "rouge" + @config = config["kramdown"] || {} + @highlighter = nil + setup + load_dependencies + end + + # Setup and normalize the configuration: + # * Create Kramdown if it doesn't exist. + # * Set syntax_highlighter, detecting enable_coderay and merging + # highlighter if none. + # * Merge kramdown[coderay] into syntax_highlighter_opts stripping coderay_. + # * Make sure `syntax_highlighter_opts` exists. + + def setup + @config["syntax_highlighter"] ||= highlighter + @config["syntax_highlighter_opts"] ||= {} + @config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext" + @config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"] + @config["coderay"] ||= {} # XXX: Legacy. + modernize_coderay_config + end + + def convert(content) + document = Kramdown::JekyllDocument.new(content, @config) + html_output = document.to_html + if @config["show_warnings"] + document.warnings.each do |warning| + Jekyll.logger.warn "Kramdown warning:", warning + end + end + html_output + end + + private + + def load_dependencies + require "kramdown-parser-gfm" if @config["input"] == "GFM" + + if highlighter == "coderay" + Jekyll::External.require_with_graceful_fail("kramdown-syntax-coderay") + end + + # `mathjax` engine is bundled within kramdown-2.x and will be handled by + # kramdown itself. + if (math_engine = @config["math_engine"]) && math_engine != "mathjax" + Jekyll::External.require_with_graceful_fail("kramdown-math-#{math_engine}") + end + end + + # config[kramdown][syntax_highlighter] > + # config[kramdown][enable_coderay] > + # config[highlighter] + # Where `enable_coderay` is now deprecated because Kramdown + # supports Rouge now too. + def highlighter + return @highlighter if @highlighter + + if @config["syntax_highlighter"] + return @highlighter = @config[ + "syntax_highlighter" + ] + end + + @highlighter = if @config.key?("enable_coderay") && @config["enable_coderay"] + Jekyll::Deprecator.deprecation_message( + "You are using 'enable_coderay', " \ + "use syntax_highlighter: coderay in your configuration file." + ) + + "coderay" + else + @main_fallback_highlighter + end + end + + def strip_coderay_prefix(hash) + hash.each_with_object({}) do |(key, val), hsh| + cleaned_key = key.to_s.delete_prefix("coderay_") + + if key != cleaned_key + Jekyll::Deprecator.deprecation_message( + "You are using '#{key}'. Normalizing to #{cleaned_key}." + ) + end + + hsh[cleaned_key] = val + end + end + + # If our highlighter is CodeRay we go in to merge the CodeRay defaults + # with your "coderay" key if it's there, deprecating it in the + # process of you using it. + def modernize_coderay_config + unless @config["coderay"].empty? + Jekyll::Deprecator.deprecation_message( + "You are using 'kramdown.coderay' in your configuration, " \ + "please use 'syntax_highlighter_opts' instead." + ) + + @config["syntax_highlighter_opts"] = begin + strip_coderay_prefix( + @config["syntax_highlighter_opts"] \ + .merge(CODERAY_DEFAULTS) \ + .merge(@config["coderay"]) + ) + end + end + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb new file mode 100644 index 00000000..606afdc8 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Kramdown + module Parser + class SmartyPants < Kramdown::Parser::Kramdown + def initialize(source, options) + super + @block_parsers = [:block_html, :content] + @span_parsers = [:smart_quotes, :html_entity, :typographic_syms, :span_html] + end + + def parse_content + add_text @src.scan(%r!\A.*\n!) + end + define_parser(:content, %r!\A!) + end + end +end + +module Jekyll + module Converters + # SmartyPants converter. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class SmartyPants < Converter + safe true + priority :low + + def initialize(config) + Jekyll::External.require_with_graceful_fail "kramdown" unless defined?(Kramdown) + @config = config["kramdown"].dup || {} + @config[:input] = :SmartyPants + end + + # Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # ext - The String extension to check. + # + # Returns true if it matches, false otherwise. + def matches(_ext) + false + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(_ext) + nil + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + document = Kramdown::Document.new(content, @config) + html_output = document.to_html.chomp + if @config["show_warnings"] + document.warnings.each do |warning| + Jekyll.logger.warn "Kramdown warning:", warning.sub(%r!^Warning:\s+!, "") + end + end + html_output + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/convertible.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/convertible.rb new file mode 100644 index 00000000..b9f7a93f --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/convertible.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +# Convertible provides methods for converting a pagelike item +# from a certain type of markup into actual content +# +# Requires +# self.site -> Jekyll::Site +# self.content +# self.content= +# self.data= +# self.ext= +# self.output= +# self.name +# self.path +# self.type -> :page, :post or :draft + +module Jekyll + module Convertible + # Returns the contents as a String. + def to_s + content || "" + end + + # Whether the file is published or not, as indicated in YAML front-matter + def published? + !(data.key?("published") && data["published"] == false) + end + + # Read the YAML frontmatter. + # + # base - The String path to the dir containing the file. + # name - The String filename of the file. + # opts - optional parameter to File.read, default at site configs + # + # Returns nothing. + # rubocop:disable Metrics/AbcSize + def read_yaml(base, name, opts = {}) + filename = @path || site.in_source_dir(base, name) + Jekyll.logger.debug "Reading:", relative_path + + begin + self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts)) + if content =~ Document::YAML_FRONT_MATTER_REGEXP + self.content = Regexp.last_match.post_match + self.data = SafeYAML.load(Regexp.last_match(1)) + end + rescue Psych::SyntaxError => e + Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}" + raise e if site.config["strict_front_matter"] + rescue StandardError => e + Jekyll.logger.warn "Error reading file #{filename}: #{e.message}" + raise e if site.config["strict_front_matter"] + end + + self.data ||= {} + + validate_data! filename + validate_permalink! filename + + self.data + end + # rubocop:enable Metrics/AbcSize + + def validate_data!(filename) + unless self.data.is_a?(Hash) + raise Errors::InvalidYAMLFrontMatterError, + "Invalid YAML front matter in #{filename}" + end + end + + def validate_permalink!(filename) + if self.data["permalink"] == "" + raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}" + end + end + + # Transform the contents based on the content type. + # + # Returns the transformed contents. + def transform + renderer.convert(content) + end + + # Determine the extension depending on content_type. + # + # Returns the String extension for the output file. + # e.g. ".html" for an HTML output file. + def output_ext + renderer.output_ext + end + + # Determine which converter to use based on this convertible's + # extension. + # + # Returns the Converter instance. + def converters + renderer.converters + end + + # Render Liquid in the content + # + # content - the raw Liquid content to render + # payload - the payload for Liquid + # info - the info for Liquid + # + # Returns the converted content + def render_liquid(content, payload, info, path) + renderer.render_liquid(content, payload, info, path) + end + + # Convert this Convertible's data to a Hash suitable for use by Liquid. + # + # Returns the Hash representation of this Convertible. + def to_liquid(attrs = nil) + further_data = \ + (attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh| + hsh[attribute] = send(attribute) + end + + Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data) + end + + # The type of a document, + # i.e., its classname downcase'd and to_sym'd. + # + # Returns the type of self. + def type + :pages if is_a?(Page) + end + + # returns the owner symbol for hook triggering + def hook_owner + :pages if is_a?(Page) + end + + # Determine whether the document is an asset file. + # Asset files include CoffeeScript files and Sass/SCSS files. + # + # Returns true if the extname belongs to the set of extensions + # that asset files use. + def asset_file? + sass_file? || coffeescript_file? + end + + # Determine whether the document is a Sass file. + # + # Returns true if extname == .sass or .scss, false otherwise. + def sass_file? + Jekyll::Document::SASS_FILE_EXTS.include?(ext) + end + + # Determine whether the document is a CoffeeScript file. + # + # Returns true if extname == .coffee, false otherwise. + def coffeescript_file? + ext == ".coffee" + end + + # Determine whether the file should be rendered with Liquid. + # + # Returns true if the file has Liquid Tags or Variables, false otherwise. + def render_with_liquid? + return false if data["render_with_liquid"] == false + + Jekyll::Utils.has_liquid_construct?(content) + end + + # Determine whether the file should be placed into layouts. + # + # Returns false if the document is an asset file or if the front matter + # specifies `layout: none` + def place_in_layout? + !(asset_file? || no_layout?) + end + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # + # Returns true if the layout is invalid, false if otherwise + def invalid_layout?(layout) + !data["layout"].nil? && layout.nil? && !(is_a? Jekyll::Excerpt) + end + + # Recursively render layouts + # + # layouts - a list of the layouts + # payload - the payload for Liquid + # info - the info for Liquid + # + # Returns nothing + def render_all_layouts(layouts, payload, info) + renderer.layouts = layouts + self.output = renderer.place_in_layouts(output, payload, info) + ensure + @renderer = nil # this will allow the modifications above to disappear + end + + # Add any necessary layouts to this convertible document. + # + # payload - The site payload Drop or Hash. + # layouts - A Hash of {"name" => "layout"}. + # + # Returns nothing. + def do_layout(payload, layouts) + self.output = renderer.tap do |doc_renderer| + doc_renderer.layouts = layouts + doc_renderer.payload = payload + end.run + + Jekyll.logger.debug "Post-Render Hooks:", relative_path + Jekyll::Hooks.trigger hook_owner, :post_render, self + ensure + @renderer = nil # this will allow the modifications above to disappear + end + + # Write the generated page file to the destination directory. + # + # dest - The String path to the destination dir. + # + # Returns nothing. + def write(dest) + path = destination(dest) + FileUtils.mkdir_p(File.dirname(path)) + Jekyll.logger.debug "Writing:", path + File.write(path, output, :mode => "wb") + Jekyll::Hooks.trigger hook_owner, :post_write, self + end + + # Accessor for data properties by Liquid. + # + # property - The String name of the property to retrieve. + # + # Returns the String value or nil if the property isn't included. + def [](property) + if self.class::ATTRIBUTES_FOR_LIQUID.include?(property) + send(property) + else + data[property] + end + end + + def renderer + @renderer ||= Jekyll::Renderer.new(site, self) + end + + private + + def defaults + @defaults ||= site.frontmatter_defaults.all(relative_path, type) + end + + def no_layout? + data["layout"] == "none" + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb new file mode 100644 index 00000000..4ecb6563 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Jekyll + module Deprecator + extend self + + def process(args) + arg_is_present? args, "--server", "The --server command has been replaced by the \ + 'serve' subcommand." + arg_is_present? args, "--serve", "The --serve command has been replaced by the \ + 'serve' subcommand." + arg_is_present? args, "--no-server", "To build Jekyll without launching a server, \ + use the 'build' subcommand." + arg_is_present? args, "--auto", "The switch '--auto' has been replaced with \ + '--watch'." + arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \ + the '--watch' switch." + arg_is_present? args, "--pygments", "The 'pygments' settings has been removed in \ + favour of 'highlighter'." + arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in \ + your config files." + arg_is_present? args, "--url", "The 'url' setting can only be set in your \ + config files." + no_subcommand(args) + end + + def no_subcommand(args) + unless args.empty? || + args.first !~ %r(!/^--/!) || %w(--help --version).include?(args.first) + deprecation_message "Jekyll now uses subcommands instead of just switches. \ + Run `jekyll help` to find out more." + abort + end + end + + def arg_is_present?(args, deprecated_argument, message) + deprecation_message(message) if args.include?(deprecated_argument) + end + + def deprecation_message(message) + Jekyll.logger.warn "Deprecation:", message + end + + def defaults_deprecate_type(old, current) + Jekyll.logger.warn "Defaults:", "The '#{old}' type has become '#{current}'." + Jekyll.logger.warn "Defaults:", "Please update your front-matter defaults to use \ + 'type: #{current}'." + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/document.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/document.rb new file mode 100644 index 00000000..2e39024e --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/document.rb @@ -0,0 +1,543 @@ +# frozen_string_literal: true + +module Jekyll + class Document + include Comparable + extend Forwardable + + attr_reader :path, :site, :extname, :collection, :type + attr_accessor :content, :output + + def_delegator :self, :read_post_data, :post_read + + YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m.freeze + DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze + DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze + + SASS_FILE_EXTS = %w(.sass .scss).freeze + YAML_FILE_EXTS = %w(.yaml .yml).freeze + + # + + # Class-wide cache to stash and retrieve regexp to detect "super-directories" + # of a particular Jekyll::Document object. + # + # dirname - The *special directory* for the Document. + # e.g. "_posts" or "_drafts" for Documents from the `site.posts` collection. + def self.superdirs_regex(dirname) + @superdirs_regex ||= {} + @superdirs_regex[dirname] ||= %r!#{dirname}.*! + end + + # + + # Create a new Document. + # + # path - the path to the file + # relations - a hash with keys :site and :collection, the values of which + # are the Jekyll::Site and Jekyll::Collection to which this + # Document belong. + # + # Returns nothing. + def initialize(path, relations = {}) + @site = relations[:site] + @path = path + @extname = File.extname(path) + @collection = relations[:collection] + @type = @collection.label.to_sym + + @has_yaml_header = nil + + if draft? + categories_from_path("_drafts") + else + categories_from_path(collection.relative_directory) + end + + data.default_proc = proc do |_, key| + site.frontmatter_defaults.find(relative_path, type, key) + end + + trigger_hooks(:post_init) + end + + # Fetch the Document's data. + # + # Returns a Hash containing the data. An empty hash is returned if + # no data was read. + def data + @data ||= {} + end + + # Merge some data in with this document's data. + # + # Returns the merged data. + def merge_data!(other, source: "YAML front matter") + merge_categories!(other) + Utils.deep_merge_hashes!(data, other) + merge_date!(source) + data + end + + # Returns the document date. If metadata is not present then calculates it + # based on Jekyll::Site#time or the document file modification time. + # + # Return document date string. + def date + data["date"] ||= (draft? ? source_file_mtime : site.time) + end + + # Return document file modification time in the form of a Time object. + # + # Return document file modification Time object. + def source_file_mtime + File.mtime(path) + end + + # Returns whether the document is a draft. This is only the case if + # the document is in the 'posts' collection but in a different + # directory than '_posts'. + # + # Returns whether the document is a draft. + def draft? + data["draft"] ||= relative_path.index(collection.relative_directory).nil? && + collection.label == "posts" + end + + # The path to the document, relative to the collections_dir. + # + # Returns a String path which represents the relative path from the collections_dir + # to this document. + def relative_path + @relative_path ||= path.sub("#{site.collections_path}/", "") + end + + # The output extension of the document. + # + # Returns the output extension + def output_ext + renderer.output_ext + end + + # The base filename of the document, without the file extname. + # + # Returns the basename without the file extname. + def basename_without_ext + @basename_without_ext ||= File.basename(path, ".*") + end + + # The base filename of the document. + # + # Returns the base filename of the document. + def basename + @basename ||= File.basename(path) + end + + def renderer + @renderer ||= Jekyll::Renderer.new(site, self) + end + + # Produces a "cleaned" relative path. + # The "cleaned" relative path is the relative path without the extname + # and with the collection's directory removed as well. + # This method is useful when building the URL of the document. + # + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + # + # Examples: + # When relative_path is "_methods/site/generate...md": + # cleaned_relative_path + # # => "/site/generate" + # + # Returns the cleaned relative path of the document. + def cleaned_relative_path + @cleaned_relative_path ||= + relative_path[0..-extname.length - 1] + .sub(collection.relative_directory, "") + .gsub(%r!\.*\z!, "") + end + + # Determine whether the document is a YAML file. + # + # Returns true if the extname is either .yml or .yaml, false otherwise. + def yaml_file? + YAML_FILE_EXTS.include?(extname) + end + + # Determine whether the document is an asset file. + # Asset files include CoffeeScript files and Sass/SCSS files. + # + # Returns true if the extname belongs to the set of extensions + # that asset files use. + def asset_file? + sass_file? || coffeescript_file? + end + + # Determine whether the document is a Sass file. + # + # Returns true if extname == .sass or .scss, false otherwise. + def sass_file? + SASS_FILE_EXTS.include?(extname) + end + + # Determine whether the document is a CoffeeScript file. + # + # Returns true if extname == .coffee, false otherwise. + def coffeescript_file? + extname == ".coffee" + end + + # Determine whether the file should be rendered with Liquid. + # + # Returns false if the document is either an asset file or a yaml file, + # or if the document doesn't contain any Liquid Tags or Variables, + # true otherwise. + def render_with_liquid? + return false if data["render_with_liquid"] == false + + !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content)) + end + + # Determine whether the file should be rendered with a layout. + # + # Returns true if the Front Matter specifies that `layout` is set to `none`. + def no_layout? + data["layout"] == "none" + end + + # Determine whether the file should be placed into layouts. + # + # Returns false if the document is set to `layouts: none`, or is either an + # asset file or a yaml file. Returns true otherwise. + def place_in_layout? + !(asset_file? || yaml_file? || no_layout?) + end + + # The URL template where the document would be accessible. + # + # Returns the URL template for the document. + def url_template + collection.url_template + end + + # Construct a Hash of key-value pairs which contain a mapping between + # a key in the URL template and the corresponding value for this document. + # + # Returns the Hash of key-value pairs for replacement in the URL. + def url_placeholders + @url_placeholders ||= Drops::UrlDrop.new(self) + end + + # The permalink for this Document. + # Permalink is set via the data Hash. + # + # Returns the permalink or nil if no permalink was set in the data. + def permalink + data && data.is_a?(Hash) && data["permalink"] + end + + # The computed URL for the document. See `Jekyll::URL#to_s` for more details. + # + # Returns the computed URL for the document. + def url + @url ||= URL.new( + :template => url_template, + :placeholders => url_placeholders, + :permalink => permalink + ).to_s + end + + def [](key) + data[key] + end + + # The full path to the output file. + # + # base_directory - the base path of the output directory + # + # Returns the full path to the output file of this document. + def destination(base_directory) + @destination ||= {} + @destination[base_directory] ||= begin + path = site.in_dest_dir(base_directory, URL.unescape_path(url)) + if url.end_with? "/" + path = File.join(path, "index.html") + else + path << output_ext unless path.end_with? output_ext + end + path + end + end + + # Write the generated Document file to the destination directory. + # + # dest - The String path to the destination dir. + # + # Returns nothing. + def write(dest) + path = destination(dest) + FileUtils.mkdir_p(File.dirname(path)) + Jekyll.logger.debug "Writing:", path + File.write(path, output, :mode => "wb") + + trigger_hooks(:post_write) + end + + # Whether the file is published or not, as indicated in YAML front-matter + # + # Returns 'false' if the 'published' key is specified in the + # YAML front-matter and is 'false'. Otherwise returns 'true'. + def published? + !(data.key?("published") && data["published"] == false) + end + + # Read in the file and assign the content and data based on the file contents. + # Merge the frontmatter of the file with the frontmatter default + # values + # + # Returns nothing. + def read(opts = {}) + Jekyll.logger.debug "Reading:", relative_path + + if yaml_file? + @data = SafeYAML.load_file(path) + else + begin + merge_defaults + read_content(**opts) + read_post_data + rescue StandardError => e + handle_read_error(e) + end + end + end + + # Create a Liquid-understandable version of this Document. + # + # Returns a Hash representing this Document's data. + def to_liquid + @to_liquid ||= Drops::DocumentDrop.new(self) + end + + # The inspect string for this document. + # Includes the relative path and the collection label. + # + # Returns the inspect string for this document. + def inspect + "#<#{self.class} #{relative_path} collection=#{collection.label}>" + end + + # The string representation for this document. + # + # Returns the content of the document + def to_s + output || content || "NO CONTENT" + end + + # Compare this document against another document. + # Comparison is a comparison between the 2 paths of the documents. + # + # Returns -1, 0, +1 or nil depending on whether this doc's path is less than, + # equal or greater than the other doc's path. See String#<=> for more details. + def <=>(other) + return nil unless other.respond_to?(:data) + + cmp = data["date"] <=> other.data["date"] + cmp = path <=> other.path if cmp.nil? || cmp.zero? + cmp + end + + # Determine whether this document should be written. + # Based on the Collection to which it belongs. + # + # True if the document has a collection and if that collection's #write? + # method returns true, and if the site's Publisher will publish the document. + # False otherwise. + # + # rubocop:disable Naming/MemoizedInstanceVariableName + def write? + return @write_p if defined?(@write_p) + + @write_p = collection&.write? && site.publisher.publish?(self) + end + # rubocop:enable Naming/MemoizedInstanceVariableName + + # The Document excerpt_separator, from the YAML Front-Matter or site + # default excerpt_separator value + # + # Returns the document excerpt_separator + def excerpt_separator + @excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s + end + + # Whether to generate an excerpt + # + # Returns true if the excerpt separator is configured. + def generate_excerpt? + !excerpt_separator.empty? + end + + def next_doc + pos = collection.docs.index { |post| post.equal?(self) } + collection.docs[pos + 1] if pos && pos < collection.docs.length - 1 + end + + def previous_doc + pos = collection.docs.index { |post| post.equal?(self) } + collection.docs[pos - 1] if pos && pos.positive? + end + + def trigger_hooks(hook_name, *args) + Jekyll::Hooks.trigger collection.label.to_sym, hook_name, self, *args if collection + Jekyll::Hooks.trigger :documents, hook_name, self, *args + end + + def id + @id ||= File.join(File.dirname(url), (data["slug"] || basename_without_ext).to_s) + end + + # Calculate related posts. + # + # Returns an Array of related Posts. + def related_posts + @related_posts ||= Jekyll::RelatedPosts.new(self).build + end + + # Override of method_missing to check in @data for the key. + def method_missing(method, *args, &blck) + if data.key?(method.to_s) + Jekyll::Deprecator.deprecation_message "Document##{method} is now a key in the #data hash." + Jekyll.logger.warn "", "Called by #{caller(1..1)[0]}." + data[method.to_s] + else + super + end + end + + def respond_to_missing?(method, *) + data.key?(method.to_s) || super + end + + # Add superdirectories of the special_dir to categories. + # In the case of es/_posts, 'es' is added as a category. + # In the case of _posts/es, 'es' is NOT added as a category. + # + # Returns nothing. + def categories_from_path(special_dir) + if relative_path.start_with?(special_dir) + superdirs = [] + else + superdirs = relative_path.sub(Document.superdirs_regex(special_dir), "") + superdirs = superdirs.split(File::SEPARATOR) + superdirs.reject! { |c| c.empty? || c == special_dir || c == basename } + end + + merge_data!({ "categories" => superdirs }, :source => "file path") + end + + def populate_categories + categories = Array(data["categories"]) + Utils.pluralized_array_from_hash( + data, "category", "categories" + ) + categories.map!(&:to_s) + categories.flatten! + categories.uniq! + + merge_data!({ "categories" => categories }) + end + + def populate_tags + tags = Utils.pluralized_array_from_hash(data, "tag", "tags") + tags.flatten! + + merge_data!({ "tags" => tags }) + end + + private + + def merge_categories!(other) + if other.key?("categories") && !other["categories"].nil? + other["categories"] = other["categories"].split if other["categories"].is_a?(String) + + if data["categories"].is_a?(Array) + other["categories"] = data["categories"] | other["categories"] + end + end + end + + def merge_date!(source) + if data.key?("date") + data["date"] = Utils.parse_date( + data["date"].to_s, + "Document '#{relative_path}' does not have a valid date in the #{source}." + ) + end + end + + def merge_defaults + defaults = @site.frontmatter_defaults.all(relative_path, type) + merge_data!(defaults, :source => "front matter defaults") unless defaults.empty? + end + + def read_content(**opts) + self.content = File.read(path, **Utils.merged_file_read_opts(site, opts)) + if content =~ YAML_FRONT_MATTER_REGEXP + self.content = Regexp.last_match.post_match + data_file = SafeYAML.load(Regexp.last_match(1)) + merge_data!(data_file, :source => "YAML front matter") if data_file + end + end + + def read_post_data + populate_title + populate_categories + populate_tags + generate_excerpt + end + + def handle_read_error(error) + if error.is_a? Psych::SyntaxError + Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}" + else + Jekyll.logger.error "Error:", "could not read file #{path}: #{error.message}" + end + + if site.config["strict_front_matter"] || error.is_a?(Jekyll::Errors::FatalException) + raise error + end + end + + def populate_title + if relative_path =~ DATE_FILENAME_MATCHER + date, slug, ext = Regexp.last_match.captures + modify_date(date) + elsif relative_path =~ DATELESS_FILENAME_MATCHER + slug, ext = Regexp.last_match.captures + end + # `slug` will be nil for documents without an extension since the regex patterns + # above tests for an extension as well. + # In such cases, assign `basename_without_ext` as the slug. + slug ||= basename_without_ext + + # slugs shouldn't end with a period + # `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`) + slug.gsub!(%r!\.*\z!, "") + + # Try to ensure the user gets a title. + data["title"] ||= Utils.titleize_slug(slug) + # Only overwrite slug & ext if they aren't specified. + data["slug"] ||= slug + data["ext"] ||= ext + end + + def modify_date(date) + if !data["date"] || data["date"].to_i == site.time.to_i + merge_data!({ "date" => date }, :source => "filename") + end + end + + def generate_excerpt + data["excerpt"] ||= Jekyll::Excerpt.new(self) if generate_excerpt? + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb new file mode 100644 index 00000000..4fe95a55 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class CollectionDrop < Drop + extend Forwardable + + mutable false + + delegate_method_as :write?, :output + delegate_methods :label, :docs, :files, :directory, :relative_directory + + private delegate_method_as :metadata, :fallback_data + + def to_s + docs.to_s + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb new file mode 100644 index 00000000..0cff3741 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class DocumentDrop < Drop + extend Forwardable + + NESTED_OBJECT_FIELD_BLACKLIST = %w( + content output excerpt next previous + ).freeze + + mutable false + + delegate_method_as :relative_path, :path + private delegate_method_as :data, :fallback_data + + delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date + data_delegators "title", "categories", "tags" + + def collection + @obj.collection.label + end + + def excerpt + fallback_data["excerpt"].to_s + end + + def name + fallback_data["name"] || @obj.basename + end + + def <=>(other) + return nil unless other.is_a? DocumentDrop + + cmp = self["date"] <=> other["date"] + cmp = self["path"] <=> other["path"] if cmp.nil? || cmp.zero? + cmp + end + + def previous + @obj.previous_doc.to_liquid + end + + def next + @obj.next_doc.to_liquid + end + + # Generate a Hash for use in generating JSON. + # This is useful if fields need to be cleared before the JSON can generate. + # + # state - the JSON::State object which determines the state of current processing. + # + # Returns a Hash ready for JSON generation. + def hash_for_json(state = nil) + to_h.tap do |hash| + if state && state.depth >= 2 + hash["previous"] = collapse_document(hash["previous"]) if hash["previous"] + hash["next"] = collapse_document(hash["next"]) if hash["next"] + end + end + end + + # Generate a Hash which breaks the recursive chain. + # Certain fields which are normally available are omitted. + # + # Returns a Hash with only non-recursive fields present. + def collapse_document(doc) + doc.keys.each_with_object({}) do |(key, _), result| + result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key) + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb new file mode 100644 index 00000000..b82c7b48 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb @@ -0,0 +1,294 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class Drop < Liquid::Drop + include Enumerable + + NON_CONTENT_METHODS = [:fallback_data, :collapse_document].freeze + NON_CONTENT_METHOD_NAMES = NON_CONTENT_METHODS.map(&:to_s).freeze + private_constant :NON_CONTENT_METHOD_NAMES + + # A private stash to avoid repeatedly generating the setter method name string for + # a call to `Drops::Drop#[]=`. + # The keys of the stash below have a very high probability of being called upon during + # the course of various `Jekyll::Renderer#run` calls. + SETTER_KEYS_STASH = { + "content" => "content=", + "layout" => "layout=", + "page" => "page=", + "paginator" => "paginator=", + "highlighter_prefix" => "highlighter_prefix=", + "highlighter_suffix" => "highlighter_suffix=", + }.freeze + private_constant :SETTER_KEYS_STASH + + class << self + # Get or set whether the drop class is mutable. + # Mutability determines whether or not pre-defined fields may be + # overwritten. + # + # is_mutable - Boolean set mutability of the class (default: nil) + # + # Returns the mutability of the class + def mutable(is_mutable = nil) + @is_mutable = is_mutable || false + end + + def mutable? + @is_mutable + end + + # public delegation helper methods that calls onto Drop's instance + # variable `@obj`. + + # Generate private Drop instance_methods for each symbol in the given list. + # + # Returns nothing. + def private_delegate_methods(*symbols) + symbols.each { |symbol| private delegate_method(symbol) } + nil + end + + # Generate public Drop instance_methods for each symbol in the given list. + # + # Returns nothing. + def delegate_methods(*symbols) + symbols.each { |symbol| delegate_method(symbol) } + nil + end + + # Generate public Drop instance_method for given symbol that calls `@obj.`. + # + # Returns delegated method symbol. + def delegate_method(symbol) + define_method(symbol) { @obj.send(symbol) } + end + + # Generate public Drop instance_method named `delegate` that calls `@obj.`. + # + # Returns delegated method symbol. + def delegate_method_as(original, delegate) + define_method(delegate) { @obj.send(original) } + end + + # Generate public Drop instance_methods for each string entry in the given list. + # The generated method(s) access(es) `@obj`'s data hash. + # + # Returns nothing. + def data_delegators(*strings) + strings.each do |key| + data_delegator(key) if key.is_a?(String) + end + nil + end + + # Generate public Drop instance_methods for given string `key`. + # The generated method access(es) `@obj`'s data hash. + # + # Returns method symbol. + def data_delegator(key) + define_method(key.to_sym) { @obj.data[key] } + end + + # Array of stringified instance methods that do not end with the assignment operator. + # + # (.instance_methods always generates a new Array object so it can be mutated) + # + # Returns array of strings. + def getter_method_names + @getter_method_names ||= instance_methods.map!(&:to_s).tap do |list| + list.reject! { |item| item.end_with?("=") } + end + end + end + + # Create a new Drop + # + # obj - the Jekyll Site, Collection, or Document required by the + # drop. + # + # Returns nothing + def initialize(obj) + @obj = obj + end + + # Access a method in the Drop or a field in the underlying hash data. + # If mutable, checks the mutations first. Then checks the methods, + # and finally check the underlying hash (e.g. document front matter) + # if all the previous places didn't match. + # + # key - the string key whose value to fetch + # + # Returns the value for the given key, or nil if none exists + def [](key) + if self.class.mutable? && mutations.key?(key) + mutations[key] + elsif self.class.invokable? key + public_send key + else + fallback_data[key] + end + end + alias_method :invoke_drop, :[] + + # Set a field in the Drop. If mutable, sets in the mutations and + # returns. If not mutable, checks first if it's trying to override a + # Drop method and raises a DropMutationException if so. If not + # mutable and the key is not a method on the Drop, then it sets the + # key to the value in the underlying hash (e.g. document front + # matter) + # + # key - the String key whose value to set + # val - the Object to set the key's value to + # + # Returns the value the key was set to unless the Drop is not mutable + # and the key matches a method in which case it raises a + # DropMutationException. + def []=(key, val) + setter = SETTER_KEYS_STASH[key] || "#{key}=" + if respond_to?(setter) + public_send(setter, val) + elsif respond_to?(key.to_s) + if self.class.mutable? + mutations[key] = val + else + raise Errors::DropMutationException, "Key #{key} cannot be set in the drop." + end + else + fallback_data[key] = val + end + end + + # Generates a list of strings which correspond to content getter + # methods. + # + # Returns an Array of strings which represent method-specific keys. + def content_methods + @content_methods ||= \ + self.class.getter_method_names \ + - Jekyll::Drops::Drop.getter_method_names \ + - NON_CONTENT_METHOD_NAMES + end + + # Check if key exists in Drop + # + # key - the string key whose value to fetch + # + # Returns true if the given key is present + def key?(key) + return false if key.nil? + return true if self.class.mutable? && mutations.key?(key) + + respond_to?(key) || fallback_data.key?(key) + end + + # Generates a list of keys with user content as their values. + # This gathers up the Drop methods and keys of the mutations and + # underlying data hashes and performs a set union to ensure a list + # of unique keys for the Drop. + # + # Returns an Array of unique keys for content for the Drop. + def keys + (content_methods | + mutations.keys | + fallback_data.keys).flatten + end + + # Generate a Hash representation of the Drop by resolving each key's + # value. It includes Drop methods, mutations, and the underlying object's + # data. See the documentation for Drop#keys for more. + # + # Returns a Hash with all the keys and values resolved. + def to_h + keys.each_with_object({}) do |(key, _), result| + result[key] = self[key] + end + end + alias_method :to_hash, :to_h + + # Inspect the drop's keys and values through a JSON representation + # of its keys and values. + # + # Returns a pretty generation of the hash representation of the Drop. + def inspect + JSON.pretty_generate to_h + end + + # Generate a Hash for use in generating JSON. + # This is useful if fields need to be cleared before the JSON can generate. + # + # Returns a Hash ready for JSON generation. + def hash_for_json(*) + to_h + end + + # Generate a JSON representation of the Drop. + # + # state - the JSON::State object which determines the state of current processing. + # + # Returns a JSON representation of the Drop in a String. + def to_json(state = nil) + JSON.generate(hash_for_json(state), state) + end + + # Collects all the keys and passes each to the block in turn. + # + # block - a block which accepts one argument, the key + # + # Returns nothing. + def each_key(&block) + keys.each(&block) + end + + def each + each_key.each do |key| + yield key, self[key] + end + end + + def merge(other, &block) + dup.tap do |me| + if block.nil? + me.merge!(other) + else + me.merge!(other, block) + end + end + end + + def merge!(other) + other.each_key do |key| + if block_given? + self[key] = yield key, self[key], other[key] + else + if Utils.mergable?(self[key]) && Utils.mergable?(other[key]) + self[key] = Utils.deep_merge_hashes(self[key], other[key]) + next + end + + self[key] = other[key] unless other[key].nil? + end + end + end + + # Imitate Hash.fetch method in Drop + # + # Returns value if key is present in Drop, otherwise returns default value + # KeyError is raised if key is not present and no default value given + def fetch(key, default = nil, &block) + return self[key] if key?(key) + raise KeyError, %(key not found: "#{key}") if default.nil? && block.nil? + return yield(key) unless block.nil? + + default unless default.nil? + end + + private + + def mutations + @mutations ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb new file mode 100644 index 00000000..82d3cdf8 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class ExcerptDrop < DocumentDrop + def layout + @obj.doc.data["layout"] + end + + def date + @obj.doc.date + end + + def excerpt + nil + end + + def name + @obj.doc.data["name"] || @obj.doc.basename + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb new file mode 100644 index 00000000..63187cc4 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class JekyllDrop < Liquid::Drop + class << self + def global + @global ||= JekyllDrop.new + end + end + + def version + Jekyll::VERSION + end + + def environment + Jekyll.env + end + + def to_h + @to_h ||= { + "version" => version, + "environment" => environment, + } + end + + def to_json(state = nil) + JSON.generate(to_h, state) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb new file mode 100644 index 00000000..cc3c60fb --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class SiteDrop < Drop + extend Forwardable + + mutable false + + delegate_method_as :site_data, :data + delegate_methods :time, :pages, :static_files, :tags, :categories + + private delegate_method_as :config, :fallback_data + + def [](key) + if key != "posts" && @obj.collections.key?(key) + @obj.collections[key].docs + else + super(key) + end + end + + def key?(key) + (key != "posts" && @obj.collections.key?(key)) || super + end + + def posts + @site_posts ||= @obj.posts.docs.sort { |a, b| b <=> a } + end + + def html_pages + @site_html_pages ||= @obj.pages.select do |page| + page.html? || page.url.end_with?("/") + end + end + + def collections + @site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid) + end + + # `Site#documents` cannot be memoized so that `Site#docs_to_write` can access the + # latest state of the attribute. + # + # Since this method will be called after `Site#pre_render` hook, the `Site#documents` + # array shouldn't thereafter change and can therefore be safely memoized to prevent + # additional computation of `Site#documents`. + def documents + @documents ||= @obj.documents + end + + # `{{ site.related_posts }}` is how posts can get posts related to + # them, either through LSI if it's enabled, or through the most + # recent posts. + # We should remove this in 4.0 and switch to `{{ post.related_posts }}`. + def related_posts + return nil unless @current_document.is_a?(Jekyll::Document) + + @current_document.related_posts + end + attr_writer :current_document + + # return nil for `{{ site.config }}` even if --config was passed via CLI + def config; end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb new file mode 100644 index 00000000..d00973b0 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class StaticFileDrop < Drop + extend Forwardable + delegate_methods :name, :extname, :modified_time, :basename + delegate_method_as :relative_path, :path + delegate_method_as :type, :collection + + private delegate_method_as :data, :fallback_data + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb new file mode 100644 index 00000000..dd5b281a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class ThemeDrop < Drop + delegate_method_as :runtime_dependencies, :dependencies + + def root + @root ||= ENV["JEKYLL_ENV"] == "development" ? @obj.root : "" + end + + def authors + @authors ||= gemspec.authors.join(", ") + end + + def version + @version ||= gemspec.version.to_s + end + + def description + @description ||= gemspec.description || gemspec.summary + end + + def metadata + @metadata ||= gemspec.metadata + end + + private + + def gemspec + @gemspec ||= @obj.send(:gemspec) + end + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb new file mode 100644 index 00000000..709ad712 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class UnifiedPayloadDrop < Drop + mutable true + + attr_accessor :content, :page, :layout, :paginator, + :highlighter_prefix, :highlighter_suffix + + def jekyll + JekyllDrop.global + end + + def site + @site_drop ||= SiteDrop.new(@obj) + end + + def theme + @theme_drop ||= ThemeDrop.new(@obj.theme) if @obj.theme + end + + private + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb new file mode 100644 index 00000000..de58c95f --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class UrlDrop < Drop + extend Forwardable + + mutable false + + delegate_method :output_ext + delegate_method_as :cleaned_relative_path, :path + + def collection + @obj.collection.label + end + + def name + Utils.slugify(@obj.basename_without_ext) + end + + def title + Utils.slugify(@obj.data["slug"], :mode => "pretty", :cased => true) || + Utils.slugify(@obj.basename_without_ext, :mode => "pretty", :cased => true) + end + + def slug + Utils.slugify(@obj.data["slug"]) || Utils.slugify(@obj.basename_without_ext) + end + + def categories + category_set = Set.new + Array(@obj.data["categories"]).each do |category| + category_set << category.to_s.downcase + end + category_set.to_a.join("/") + end + + # Similar to output from #categories, but each category will be downcased and + # all non-alphanumeric characters of the category replaced with a hyphen. + def slugified_categories + Array(@obj.data["categories"]).each_with_object(Set.new) do |category, set| + set << Utils.slugify(category.to_s) + end.to_a.join("/") + end + + # CCYY + def year + @obj.date.strftime("%Y") + end + + # MM: 01..12 + def month + @obj.date.strftime("%m") + end + + # DD: 01..31 + def day + @obj.date.strftime("%d") + end + + # hh: 00..23 + def hour + @obj.date.strftime("%H") + end + + # mm: 00..59 + def minute + @obj.date.strftime("%M") + end + + # ss: 00..59 + def second + @obj.date.strftime("%S") + end + + # D: 1..31 + def i_day + @obj.date.strftime("%-d") + end + + # M: 1..12 + def i_month + @obj.date.strftime("%-m") + end + + # MMM: Jan..Dec + def short_month + @obj.date.strftime("%b") + end + + # MMMM: January..December + def long_month + @obj.date.strftime("%B") + end + + # YY: 00..99 + def short_year + @obj.date.strftime("%y") + end + + # CCYYw, ISO week year + # may differ from CCYY for the first days of January and last days of December + def w_year + @obj.date.strftime("%G") + end + + # WW: 01..53 + # %W and %U do not comply with ISO 8601-1 + def week + @obj.date.strftime("%V") + end + + # d: 1..7 (Monday..Sunday) + def w_day + @obj.date.strftime("%u") + end + + # dd: Mon..Sun + def short_day + @obj.date.strftime("%a") + end + + # ddd: Monday..Sunday + def long_day + @obj.date.strftime("%A") + end + + # DDD: 001..366 + def y_day + @obj.date.strftime("%j") + end + + private + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb new file mode 100644 index 00000000..4e70a5d9 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Jekyll + class EntryFilter + attr_reader :site + + SPECIAL_LEADING_CHAR_REGEX = %r!\A#{Regexp.union([".", "_", "#", "~"])}!o.freeze + + def initialize(site, base_directory = nil) + @site = site + @base_directory = derive_base_directory( + @site, base_directory.to_s.dup + ) + end + + def base_directory + @base_directory.to_s + end + + def derive_base_directory(site, base_dir) + base_dir[site.source] = "" if base_dir.start_with?(site.source) + base_dir + end + + def relative_to_source(entry) + File.join( + base_directory, entry + ) + end + + def filter(entries) + entries.reject do |e| + # Reject this entry if it is just a "dot" representation. + # e.g.: '.', '..', '_movies/.', 'music/..', etc + next true if e.end_with?(".") + + # Check if the current entry is explicitly included and cache the result + included = included?(e) + + # Reject current entry if it is excluded but not explicitly included as well. + next true if excluded?(e) && !included + + # Reject current entry if it is a symlink. + next true if symlink?(e) + + # Do not reject current entry if it is explicitly included. + next false if included + + # Reject current entry if it is special or a backup file. + special?(e) || backup?(e) + end + end + + def included?(entry) + glob_include?(site.include, entry) || + glob_include?(site.include, File.basename(entry)) + end + + def special?(entry) + SPECIAL_LEADING_CHAR_REGEX.match?(entry) || + SPECIAL_LEADING_CHAR_REGEX.match?(File.basename(entry)) + end + + def backup?(entry) + entry.end_with?("~") + end + + def excluded?(entry) + glob_include?(site.exclude - site.include, relative_to_source(entry)).tap do |excluded| + if excluded + Jekyll.logger.debug( + "EntryFilter:", + "excluded #{relative_to_source(entry)}" + ) + end + end + end + + # -- + # Check if a file is a symlink. + # NOTE: This can be converted to allowing even in safe, + # since we use Pathutil#in_path? now. + # -- + def symlink?(entry) + site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry) + end + + # -- + # Check if given path is outside of current site's configured source directory. + # -- + def symlink_outside_site_source?(entry) + !File.realpath(entry).start_with?(site.in_source_dir) + end + + # Check if an entry matches a specific pattern. + # Returns true if path matches against any glob pattern, else false. + def glob_include?(enumerator, entry) + entry_with_source = PathManager.join(site.source, entry) + entry_is_directory = File.directory?(entry_with_source) + + enumerator.any? do |pattern| + case pattern + when String + pattern_with_source = PathManager.join(site.source, pattern) + + File.fnmatch?(pattern_with_source, entry_with_source) || + entry_with_source.start_with?(pattern_with_source) || + (pattern_with_source == "#{entry_with_source}/" if entry_is_directory) + when Regexp + pattern.match?(entry_with_source) + else + false + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/errors.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/errors.rb new file mode 100644 index 00000000..8d659e8d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/errors.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Jekyll + module Errors + FatalException = Class.new(::RuntimeError) + + InvalidThemeName = Class.new(FatalException) + + DropMutationException = Class.new(FatalException) + InvalidPermalinkError = Class.new(FatalException) + InvalidYAMLFrontMatterError = Class.new(FatalException) + MissingDependencyException = Class.new(FatalException) + + InvalidDateError = Class.new(FatalException) + InvalidPostNameError = Class.new(FatalException) + PostURLError = Class.new(FatalException) + InvalidURLError = Class.new(FatalException) + InvalidConfigurationError = Class.new(FatalException) + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb new file mode 100644 index 00000000..63185203 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +module Jekyll + class Excerpt + extend Forwardable + + attr_accessor :content, :doc, :ext + attr_writer :output + + def_delegators :@doc, + :site, :name, :ext, :extname, + :collection, :related_posts, :type, + :coffeescript_file?, :yaml_file?, + :url, :next_doc, :previous_doc + + private :coffeescript_file?, :yaml_file? + + # Initialize this Excerpt instance. + # + # doc - The Document. + # + # Returns the new Excerpt. + def initialize(doc) + self.doc = doc + self.content = extract_excerpt(doc.content) + end + + # Fetch YAML front-matter data from related doc, without layout key + # + # Returns Hash of doc data + def data + @data ||= doc.data.dup + @data.delete("layout") + @data.delete("excerpt") + @data + end + + def trigger_hooks(*); end + + # 'Path' of the excerpt. + # + # Returns the path for the doc this excerpt belongs to with #excerpt appended + def path + File.join(doc.path, "#excerpt") + end + + # 'Relative Path' of the excerpt. + # + # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended + def relative_path + @relative_path ||= File.join(doc.relative_path, "#excerpt") + end + + # Check if excerpt includes a string + # + # Returns true if the string passed in + def include?(something) + output&.include?(something) || content.include?(something) + end + + # The UID for this doc (useful in feeds). + # e.g. /2008/11/05/my-awesome-doc + # + # Returns the String UID. + def id + "#{doc.id}#excerpt" + end + + def to_s + output || content + end + + def to_liquid + Jekyll::Drops::ExcerptDrop.new(self) + end + + # Returns the shorthand String identifier of this doc. + def inspect + "<#{self.class} id=#{id}>" + end + + def output + @output ||= Renderer.new(doc.site, self, site.site_payload).run + end + + def place_in_layout? + false + end + + def render_with_liquid? + return false if data["render_with_liquid"] == false + + !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content)) + end + + protected + + # Internal: Extract excerpt from the content + # + # By default excerpt is your first paragraph of a doc: everything before + # the first two new lines: + # + # --- + # title: Example + # --- + # + # First paragraph with [link][1]. + # + # Second paragraph. + # + # [1]: http://example.com/ + # + # This is fairly good option for Markdown and Textile files. But might cause + # problems for HTML docs (which is quite unusual for Jekyll). If default + # excerpt delimiter is not good for you, you might want to set your own via + # configuration option `excerpt_separator`. For example, following is a good + # alternative for HTML docs: + # + # # file: _config.yml + # excerpt_separator: "" + # + # Notice that all markdown-style link references will be appended to the + # excerpt. So the example doc above will have this excerpt source: + # + # First paragraph with [link][1]. + # + # [1]: http://example.com/ + # + # Excerpts are rendered same time as content is rendered. + # + # Returns excerpt String + + LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze + MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze + + def extract_excerpt(doc_content) + head, _, tail = doc_content.to_s.partition(doc.excerpt_separator) + return head if tail.empty? + + head = sanctify_liquid_tags(head) if head.include?("{%") + definitions = extract_markdown_link_reference_definitions(head, tail) + return head if definitions.empty? + + head << "\n\n" << definitions.join("\n") + end + + private + + # append appropriate closing tag(s) (for each Liquid block), to the `head` if the + # partitioning resulted in leaving the closing tag somewhere in the `tail` partition. + def sanctify_liquid_tags(head) + modified = false + tag_names = head.scan(LIQUID_TAG_REGEX) + tag_names.flatten! + tag_names.reverse_each do |tag_name| + next unless liquid_block?(tag_name) + next if endtag_regex_stash(tag_name).match?(head) + + modified = true + head << "\n{% end#{tag_name} %}" + end + + print_build_warning if modified + head + end + + def extract_markdown_link_reference_definitions(head, tail) + [].tap do |definitions| + tail.scan(MKDWN_LINK_REF_REGEX).each do |segments| + definitions << segments.join if head.include?(segments[0]) + end + end + end + + def endtag_regex_stash(tag_name) + @endtag_regex_stash ||= {} + @endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m + end + + def liquid_block?(tag_name) + return false unless tag_name.is_a?(String) + return false unless Liquid::Template.tags[tag_name] + + Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block) + rescue NoMethodError + Jekyll.logger.error "Error:", + "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed." + raise + end + + def print_build_warning + Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!" + Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator " \ + "#{doc.excerpt_separator.inspect}." + Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag." + Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the" + Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory." + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/external.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/external.rb new file mode 100644 index 00000000..b484160c --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/external.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Jekyll + module External + class << self + # + # Gems that, if installed, should be loaded. + # Usually contain subcommands. + # + def blessed_gems + %w( + jekyll-compose + jekyll-docs + jekyll-import + ) + end + + # + # Require a gem or file if it's present, otherwise silently fail. + # + # names - a string gem name or array of gem names + # + def require_if_present(names) + Array(names).each do |name| + require name + rescue LoadError + Jekyll.logger.debug "Couldn't load #{name}. Skipping." + yield(name, version_constraint(name)) if block_given? + false + end + end + + # + # The version constraint required to activate a given gem. + # Usually the gem version requirement is "> 0," because any version + # will do. In the case of jekyll-docs, however, we require the exact + # same version as Jekyll. + # + # Returns a String version constraint in a parseable form for + # RubyGems. + def version_constraint(gem_name) + return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs") + + "> 0" + end + + # + # Require a gem or gems. If it's not present, show a very nice error + # message that explains everything and is much more helpful than the + # normal LoadError. + # + # names - a string gem name or array of gem names + # + def require_with_graceful_fail(names) + Array(names).each do |name| + Jekyll.logger.debug "Requiring:", name.to_s + require name + rescue LoadError => e + Jekyll.logger.error "Dependency Error:", <<~MSG + Yikes! It looks like you don't have #{name} or one of its dependencies installed. + In order to use Jekyll as currently configured, you'll need to install this gem. + + If you've run Jekyll with `bundle exec`, ensure that you have included the #{name} + gem in your Gemfile as well. + + The full error message from Ruby is: '#{e.message}' + + If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/! + MSG + raise Jekyll::Errors::MissingDependencyException, name + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/filters.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/filters.rb new file mode 100644 index 00000000..7a79eec9 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/filters.rb @@ -0,0 +1,540 @@ +# frozen_string_literal: true + +require_all "jekyll/filters" + +module Jekyll + module Filters + include URLFilters + include GroupingFilters + include DateFilters + + # Convert a Markdown string into HTML output. + # + # input - The Markdown String to convert. + # + # Returns the HTML formatted String. + def markdownify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Markdown + ).convert(input.to_s) + end + + # Convert quotes into smart quotes. + # + # input - The String to convert. + # + # Returns the smart-quotified String. + def smartify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::SmartyPants + ).convert(input.to_s) + end + + # Convert a Sass string into CSS output. + # + # input - The Sass String to convert. + # + # Returns the CSS formatted String. + def sassify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Sass + ).convert(input) + end + + # Convert a Scss string into CSS output. + # + # input - The Scss String to convert. + # + # Returns the CSS formatted String. + def scssify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Scss + ).convert(input) + end + + # Slugify a filename or title. + # + # input - The filename or title to slugify. + # mode - how string is slugified + # + # Returns the given filename or title as a lowercase URL String. + # See Utils.slugify for more detail. + def slugify(input, mode = nil) + Utils.slugify(input, :mode => mode) + end + + # XML escape a string for use. Replaces any special characters with + # appropriate HTML entity replacements. + # + # input - The String to escape. + # + # Examples + # + # xml_escape('foo "bar" ') + # # => "foo "bar" <baz>" + # + # Returns the escaped String. + def xml_escape(input) + input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "") + end + + # CGI escape a string for use in a URL. Replaces any special characters + # with appropriate %XX replacements. + # + # input - The String to escape. + # + # Examples + # + # cgi_escape('foo,bar;baz?') + # # => "foo%2Cbar%3Bbaz%3F" + # + # Returns the escaped String. + def cgi_escape(input) + CGI.escape(input) + end + + # URI escape a string. + # + # input - The String to escape. + # + # Examples + # + # uri_escape('foo, bar \\baz?') + # # => "foo,%20bar%20%5Cbaz?" + # + # Returns the escaped String. + def uri_escape(input) + Addressable::URI.normalize_component(input) + end + + # Replace any whitespace in the input string with a single space + # + # input - The String on which to operate. + # + # Returns the formatted String + def normalize_whitespace(input) + input.to_s.gsub(%r!\s+!, " ").tap(&:strip!) + end + + # Count the number of words in the input string. + # + # input - The String on which to operate. + # + # Returns the Integer word count. + def number_of_words(input, mode = nil) + cjk_charset = '\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}' + cjk_regex = %r![#{cjk_charset}]!o + word_regex = %r![^#{cjk_charset}\s]+!o + + case mode + when "cjk" + input.scan(cjk_regex).length + input.scan(word_regex).length + when "auto" + cjk_count = input.scan(cjk_regex).length + cjk_count.zero? ? input.split.length : cjk_count + input.scan(word_regex).length + else + input.split.length + end + end + + # Join an array of things into a string by separating with commas and the + # word "and" for the last one. + # + # array - The Array of Strings to join. + # connector - Word used to connect the last 2 items in the array + # + # Examples + # + # array_to_sentence_string(["apples", "oranges", "grapes"]) + # # => "apples, oranges, and grapes" + # + # Returns the formatted String. + def array_to_sentence_string(array, connector = "and") + case array.length + when 0 + "" + when 1 + array[0].to_s + when 2 + "#{array[0]} #{connector} #{array[1]}" + else + "#{array[0...-1].join(", ")}, #{connector} #{array[-1]}" + end + end + + # Convert the input into json string + # + # input - The Array or Hash to be converted + # + # Returns the converted json string + def jsonify(input) + as_liquid(input).to_json + end + + # Filter an array of objects + # + # input - the object array. + # property - the property within each object to filter by. + # value - the desired value. + # Cannot be an instance of Array nor Hash since calling #to_s on them returns + # their `#inspect` string object. + # + # Returns the filtered array of objects + def where(input, property, value) + return input if !property || value.is_a?(Array) || value.is_a?(Hash) + return input unless input.respond_to?(:select) + + input = input.values if input.is_a?(Hash) + input_id = input.hash + + # implement a hash based on method parameters to cache the end-result + # for given parameters. + @where_filter_cache ||= {} + @where_filter_cache[input_id] ||= {} + @where_filter_cache[input_id][property] ||= {} + + # stash or retrieve results to return + @where_filter_cache[input_id][property][value] ||= input.select do |object| + compare_property_vs_target(item_property(object, property), value) + end.to_a + end + + # Filters an array of objects against an expression + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression - a Liquid comparison expression passed in as a string + # + # Returns the filtered array of objects + def where_exp(input, variable, expression) + return input unless input.respond_to?(:select) + + input = input.values if input.is_a?(Hash) # FIXME + + condition = parse_condition(expression) + @context.stack do + input.select do |object| + @context[variable] = object + condition.evaluate(@context) + end + end || [] + end + + # Search an array of objects and returns the first object that has the queried attribute + # with the given value or returns nil otherwise. + # + # input - the object array. + # property - the property within each object to search by. + # value - the desired value. + # Cannot be an instance of Array nor Hash since calling #to_s on them returns + # their `#inspect` string object. + # + # Returns the found object or nil + # + # rubocop:disable Metrics/CyclomaticComplexity + def find(input, property, value) + return input if !property || value.is_a?(Array) || value.is_a?(Hash) + return input unless input.respond_to?(:find) + + input = input.values if input.is_a?(Hash) + input_id = input.hash + + # implement a hash based on method parameters to cache the end-result for given parameters. + @find_filter_cache ||= {} + @find_filter_cache[input_id] ||= {} + @find_filter_cache[input_id][property] ||= {} + + # stash or retrieve results to return + # Since `enum.find` can return nil or false, we use a placeholder string "<__NO MATCH__>" + # to validate caching. + result = @find_filter_cache[input_id][property][value] ||= input.find do |object| + compare_property_vs_target(item_property(object, property), value) + end || "<__NO MATCH__>" + + return nil if result == "<__NO MATCH__>" + + result + end + # rubocop:enable Metrics/CyclomaticComplexity + + # Searches an array of objects against an expression and returns the first object for which + # the expression evaluates to true, or returns nil otherwise. + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression - a Liquid comparison expression passed in as a string + # + # Returns the found object or nil + def find_exp(input, variable, expression) + return input unless input.respond_to?(:find) + + input = input.values if input.is_a?(Hash) + + condition = parse_condition(expression) + @context.stack do + input.find do |object| + @context[variable] = object + condition.evaluate(@context) + end + end + end + + # Convert the input into integer + # + # input - the object string + # + # Returns the integer value + def to_integer(input) + return 1 if input == true + return 0 if input == false + + input.to_i + end + + # Sort an array of objects + # + # input - the object array + # property - property within each object to filter by + # nils ('first' | 'last') - nils appear before or after non-nil values + # + # Returns the filtered array of objects + def sort(input, property = nil, nils = "first") + raise ArgumentError, "Cannot sort a null object." if input.nil? + + if property.nil? + input.sort + else + case nils + when "first" + order = - 1 + when "last" + order = + 1 + else + raise ArgumentError, "Invalid nils order: " \ + "'#{nils}' is not a valid nils order. It must be 'first' or 'last'." + end + + sort_input(input, property, order) + end + end + + def pop(array, num = 1) + return array unless array.is_a?(Array) + + num = Liquid::Utils.to_integer(num) + new_ary = array.dup + new_ary.pop(num) + new_ary + end + + def push(array, input) + return array unless array.is_a?(Array) + + new_ary = array.dup + new_ary.push(input) + new_ary + end + + def shift(array, num = 1) + return array unless array.is_a?(Array) + + num = Liquid::Utils.to_integer(num) + new_ary = array.dup + new_ary.shift(num) + new_ary + end + + def unshift(array, input) + return array unless array.is_a?(Array) + + new_ary = array.dup + new_ary.unshift(input) + new_ary + end + + def sample(input, num = 1) + return input unless input.respond_to?(:sample) + + num = Liquid::Utils.to_integer(num) rescue 1 + if num == 1 + input.sample + else + input.sample(num) + end + end + + # Convert an object into its String representation for debugging + # + # input - The Object to be converted + # + # Returns a String representation of the object. + def inspect(input) + xml_escape(input.inspect) + end + + private + + # Sort the input Enumerable by the given property. + # If the property doesn't exist, return the sort order respective of + # which item doesn't have the property. + # We also utilize the Schwartzian transform to make this more efficient. + def sort_input(input, property, order) + input.map { |item| [item_property(item, property), item] } + .sort! do |a_info, b_info| + a_property = a_info.first + b_property = b_info.first + + if !a_property.nil? && b_property.nil? + - order + elsif a_property.nil? && !b_property.nil? + + order + else + a_property <=> b_property || a_property.to_s <=> b_property.to_s + end + end + .map!(&:last) + end + + # `where` filter helper + # + def compare_property_vs_target(property, target) + case target + when NilClass + return true if property.nil? + when Liquid::Expression::MethodLiteral # `empty` or `blank` + target = target.to_s + return true if property == target || Array(property).join == target + else + target = target.to_s + if property.is_a? String + return true if property == target + else + Array(property).each do |prop| + return true if prop.to_s == target + end + end + end + + false + end + + def item_property(item, property) + @item_property_cache ||= @context.registers[:site].filter_cache[:item_property] ||= {} + @item_property_cache[property] ||= {} + @item_property_cache[property][item] ||= begin + property = property.to_s + property = if item.respond_to?(:to_liquid) + read_liquid_attribute(item.to_liquid, property) + elsif item.respond_to?(:data) + item.data[property] + else + item[property] + end + + parse_sort_input(property) + end + end + + def read_liquid_attribute(liquid_data, property) + return liquid_data[property] unless property.include?(".") + + property.split(".").reduce(liquid_data) do |data, key| + data.respond_to?(:[]) && data[key] + end + rescue TypeError => e + msg = if liquid_data.is_a?(Array) + "Error accessing object (#{liquid_data.to_s[0...20]}) with given key. Expected an " \ + "integer but got #{property.inspect} instead." + else + e.message + end + raise e, msg + end + + FLOAT_LIKE = %r!\A\s*-?(?:\d+\.?\d*|\.\d+)\s*\Z!.freeze + INTEGER_LIKE = %r!\A\s*-?\d+\s*\Z!.freeze + private_constant :FLOAT_LIKE, :INTEGER_LIKE + + # return numeric values as numbers for proper sorting + def parse_sort_input(property) + stringified = property.to_s + return property.to_i if INTEGER_LIKE.match?(stringified) + return property.to_f if FLOAT_LIKE.match?(stringified) + + property + end + + def as_liquid(item) + case item + when Hash + item.each_with_object({}) { |(k, v), result| result[as_liquid(k)] = as_liquid(v) } + when Array + item.map { |i| as_liquid(i) } + else + if item.respond_to?(:to_liquid) + liquidated = item.to_liquid + # prevent infinite recursion for simple types (which return `self`) + if liquidated == item + item + else + as_liquid(liquidated) + end + else + item + end + end + end + + # ----------- The following set of code was *adapted* from Liquid::If + # ----------- ref: https://github.com/Shopify/liquid/blob/ffb0ace30315bbcf3548a0383fab531452060ae8/lib/liquid/tags/if.rb#L84-L107 + + # Parse a string to a Liquid Condition + def parse_condition(exp) + parser = Liquid::Parser.new(exp) + condition = parse_binary_comparison(parser) + + parser.consume(:end_of_string) + condition + end + + # Generate a Liquid::Condition object from a Liquid::Parser object additionally processing + # the parsed expression based on whether the expression consists of binary operations with + # Liquid operators `and` or `or` + # + # - parser: an instance of Liquid::Parser + # + # Returns an instance of Liquid::Condition + def parse_binary_comparison(parser) + condition = parse_comparison(parser) + first_condition = condition + while (binary_operator = parser.id?("and") || parser.id?("or")) + child_condition = parse_comparison(parser) + condition.send(binary_operator, child_condition) + condition = child_condition + end + first_condition + end + + # Generates a Liquid::Condition object from a Liquid::Parser object based on whether the parsed + # expression involves a "comparison" operator (e.g. <, ==, >, !=, etc) + # + # - parser: an instance of Liquid::Parser + # + # Returns an instance of Liquid::Condition + def parse_comparison(parser) + left_operand = Liquid::Expression.parse(parser.expression) + operator = parser.consume?(:comparison) + + # No comparison-operator detected. Initialize a Liquid::Condition using only left operand + return Liquid::Condition.new(left_operand) unless operator + + # Parse what remained after extracting the left operand and the `:comparison` operator + # and initialize a Liquid::Condition object using the operands and the comparison-operator + Liquid::Condition.new(left_operand, operator, Liquid::Expression.parse(parser.expression)) + end + end +end + +Liquid::Template.register_filter( + Jekyll::Filters +) diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb new file mode 100644 index 00000000..966b49b8 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module DateFilters + # Format a date in short format e.g. "27 Jan 2011". + # Ordinal format is also supported, in both the UK + # (e.g. "27th Jan 2011") and US ("e.g. Jan 27th, 2011") formats. + # UK format is the default. + # + # date - the Time to format. + # type - if "ordinal" the returned String will be in ordinal format + # style - if "US" the returned String will be in US format. + # Otherwise it will be in UK format. + # + # Returns the formatting String. + def date_to_string(date, type = nil, style = nil) + stringify_date(date, "%b", type, style) + end + + # Format a date in long format e.g. "27 January 2011". + # Ordinal format is also supported, in both the UK + # (e.g. "27th January 2011") and US ("e.g. January 27th, 2011") formats. + # UK format is the default. + # + # date - the Time to format. + # type - if "ordinal" the returned String will be in ordinal format + # style - if "US" the returned String will be in US format. + # Otherwise it will be in UK format. + # + # Returns the formatted String. + def date_to_long_string(date, type = nil, style = nil) + stringify_date(date, "%B", type, style) + end + + # Format a date for use in XML. + # + # date - The Time to format. + # + # Examples + # + # date_to_xmlschema(Time.now) + # # => "2011-04-24T20:34:46+08:00" + # + # Returns the formatted String. + def date_to_xmlschema(date) + return date if date.to_s.empty? + + time(date).xmlschema + end + + # Format a date according to RFC-822 + # + # date - The Time to format. + # + # Examples + # + # date_to_rfc822(Time.now) + # # => "Sun, 24 Apr 2011 12:34:46 +0000" + # + # Returns the formatted String. + def date_to_rfc822(date) + return date if date.to_s.empty? + + time(date).rfc822 + end + + private + + # month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B") + # type: nil (default) or "ordinal" + # style: nil (default) or "US" + # + # Returns a stringified date or the empty input. + def stringify_date(date, month_type, type = nil, style = nil) + return date if date.to_s.empty? + + time = time(date) + if type == "ordinal" + day = time.day + ordinal_day = "#{day}#{ordinal(day)}" + return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US" + + return time.strftime("#{ordinal_day} #{month_type} %Y") + end + time.strftime("%d #{month_type} %Y") + end + + def ordinal(number) + return "th" if (11..13).cover?(number) + + case number % 10 + when 1 then "st" + when 2 then "nd" + when 3 then "rd" + else "th" + end + end + + def time(input) + date = Liquid::Utils.to_date(input) + unless date.respond_to?(:to_time) + raise Errors::InvalidDateError, + "Invalid Date: '#{input.inspect}' is not a valid datetime." + end + date.to_time.dup.localtime + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb new file mode 100644 index 00000000..c9cdc654 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module GroupingFilters + # Group an array of items by a property + # + # input - the inputted Enumerable + # property - the property + # + # Returns an array of Hashes, each looking something like this: + # {"name" => "larry" + # "items" => [...] } # all the items where `property` == "larry" + def group_by(input, property) + if groupable?(input) + groups = input.group_by { |item| item_property(item, property).to_s } + grouped_array(groups) + else + input + end + end + + # Group an array of items by an expression + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression -a Liquid comparison expression passed in as a string + # + # Returns the filtered array of objects + def group_by_exp(input, variable, expression) + return input unless groupable?(input) + + parsed_expr = parse_expression(expression) + @context.stack do + groups = input.group_by do |item| + @context[variable] = item + parsed_expr.render(@context) + end + grouped_array(groups) + end + end + + private + + def parse_expression(str) + Liquid::Variable.new(str, Liquid::ParseContext.new) + end + + def groupable?(element) + element.respond_to?(:group_by) + end + + def grouped_array(groups) + groups.each_with_object([]) do |item, array| + array << { + "name" => item.first, + "items" => item.last, + "size" => item.last.size, + } + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb new file mode 100644 index 00000000..aa28c5a5 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module URLFilters + # Produces an absolute URL based on site.url and site.baseurl. + # + # input - the URL to make absolute. + # + # Returns the absolute URL as a String. + def absolute_url(input) + return if input.nil? + + cache = if input.is_a?(String) + (@context.registers[:site].filter_cache[:absolute_url] ||= {}) + else + (@context.registers[:cached_absolute_url] ||= {}) + end + cache[input] ||= compute_absolute_url(input) + + # Duplicate cached string so that the cached value is never mutated by + # a subsequent filter. + cache[input].dup + end + + # Produces a URL relative to the domain root based on site.baseurl + # unless it is already an absolute url with an authority (host). + # + # input - the URL to make relative to the domain root + # + # Returns a URL relative to the domain root as a String. + def relative_url(input) + return if input.nil? + + cache = if input.is_a?(String) + (@context.registers[:site].filter_cache[:relative_url] ||= {}) + else + (@context.registers[:cached_relative_url] ||= {}) + end + cache[input] ||= compute_relative_url(input) + + # Duplicate cached string so that the cached value is never mutated by + # a subsequent filter. + cache[input].dup + end + + # Strips trailing `/index.html` from URLs to create pretty permalinks + # + # input - the URL with a possible `/index.html` + # + # Returns a URL with the trailing `/index.html` removed + def strip_index(input) + return if input.nil? || input.to_s.empty? + + input.sub(%r!/index\.html?$!, "/") + end + + private + + def compute_absolute_url(input) + input = input.url if input.respond_to?(:url) + return input if Addressable::URI.parse(input.to_s).absolute? + + site = @context.registers[:site] + site_url = site.config["url"] + return relative_url(input) if site_url.nil? || site_url == "" + + Addressable::URI.parse( + site_url.to_s + relative_url(input) + ).normalize.to_s + end + + def compute_relative_url(input) + input = input.url if input.respond_to?(:url) + return input if Addressable::URI.parse(input.to_s).absolute? + + parts = [sanitized_baseurl, input] + Addressable::URI.parse( + parts.map! { |part| ensure_leading_slash(part.to_s) }.join + ).normalize.to_s + end + + def sanitized_baseurl + site = @context.registers[:site] + baseurl = site.config["baseurl"] + return "" if baseurl.nil? + + baseurl.to_s.chomp("/") + end + + def ensure_leading_slash(input) + return input if input.nil? || input.empty? || input.start_with?("/") + + "/#{input}" + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb new file mode 100644 index 00000000..5ad896b2 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb @@ -0,0 +1,238 @@ +# frozen_string_literal: true + +module Jekyll + # This class handles custom defaults for YAML frontmatter settings. + # These are set in _config.yml and apply both to internal use (e.g. layout) + # and the data available to liquid. + # + # It is exposed via the frontmatter_defaults method on the site class. + class FrontmatterDefaults + # Initializes a new instance. + def initialize(site) + @site = site + end + + def reset + @glob_cache = {} if @glob_cache + end + + def update_deprecated_types(set) + return set unless set.key?("scope") && set["scope"].key?("type") + + set["scope"]["type"] = + case set["scope"]["type"] + when "page" + Deprecator.defaults_deprecate_type("page", "pages") + "pages" + when "post" + Deprecator.defaults_deprecate_type("post", "posts") + "posts" + when "draft" + Deprecator.defaults_deprecate_type("draft", "drafts") + "drafts" + else + set["scope"]["type"] + end + + set + end + + def ensure_time!(set) + return set unless set.key?("values") && set["values"].key?("date") + return set if set["values"]["date"].is_a?(Time) + + set["values"]["date"] = Utils.parse_date( + set["values"]["date"], + "An invalid date format was found in a front-matter default set: #{set}" + ) + set + end + + # Finds a default value for a given setting, filtered by path and type + # + # path - the path (relative to the source) of the page, + # post or :draft the default is used in + # type - a symbol indicating whether a :page, + # a :post or a :draft calls this method + # + # Returns the default value or nil if none was found + def find(path, type, setting) + value = nil + old_scope = nil + + matching_sets(path, type).each do |set| + if set["values"].key?(setting) && has_precedence?(old_scope, set["scope"]) + value = set["values"][setting] + old_scope = set["scope"] + end + end + value + end + + # Collects a hash with all default values for a page or post + # + # path - the relative path of the page or post + # type - a symbol indicating the type (:post, :page or :draft) + # + # Returns a hash with all default values (an empty hash if there are none) + def all(path, type) + defaults = {} + old_scope = nil + matching_sets(path, type).each do |set| + if has_precedence?(old_scope, set["scope"]) + defaults = Utils.deep_merge_hashes(defaults, set["values"]) + old_scope = set["scope"] + else + defaults = Utils.deep_merge_hashes(set["values"], defaults) + end + end + defaults + end + + private + + # Checks if a given default setting scope matches the given path and type + # + # scope - the hash indicating the scope, as defined in _config.yml + # path - the path to check for + # type - the type (:post, :page or :draft) to check for + # + # Returns true if the scope applies to the given type and path + def applies?(scope, path, type) + applies_type?(scope, type) && applies_path?(scope, path) + end + + def applies_path?(scope, path) + rel_scope_path = scope["path"] + return true if !rel_scope_path.is_a?(String) || rel_scope_path.empty? + + sanitized_path = sanitize_path(path) + + if rel_scope_path.include?("*") + glob_scope(sanitized_path, rel_scope_path) + else + path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path)) + end + end + + def glob_scope(sanitized_path, rel_scope_path) + site_source = Pathname.new(@site.source) + abs_scope_path = site_source.join(rel_scope_path).to_s + + glob_cache(abs_scope_path).each do |scope_path| + scope_path = Pathname.new(scope_path).relative_path_from(site_source).to_s + scope_path = strip_collections_dir(scope_path) + Jekyll.logger.debug "Globbed Scope Path:", scope_path + return true if path_is_subpath?(sanitized_path, scope_path) + end + false + end + + def glob_cache(path) + @glob_cache ||= {} + @glob_cache[path] ||= Dir.glob(path) + end + + def path_is_subpath?(path, parent_path) + path.start_with?(parent_path) + end + + def strip_collections_dir(path) + collections_dir = @site.config["collections_dir"] + slashed_coll_dir = collections_dir.empty? ? "/" : "#{collections_dir}/" + return path if collections_dir.empty? || !path.to_s.start_with?(slashed_coll_dir) + + path.sub(slashed_coll_dir, "") + end + + # Determines whether the scope applies to type. + # The scope applies to the type if: + # 1. no 'type' is specified + # 2. the 'type' in the scope is the same as the type asked about + # + # scope - the Hash defaults set being asked about application + # type - the type of the document being processed / asked about + # its defaults. + # + # Returns true if either of the above conditions are satisfied, + # otherwise returns false + def applies_type?(scope, type) + !scope.key?("type") || type&.to_sym.eql?(scope["type"].to_sym) + end + + # Checks if a given set of default values is valid + # + # set - the default value hash, as defined in _config.yml + # + # Returns true if the set is valid and can be used in this class + def valid?(set) + set.is_a?(Hash) && set["values"].is_a?(Hash) + end + + # Determines if a new scope has precedence over an old one + # + # old_scope - the old scope hash, or nil if there's none + # new_scope - the new scope hash + # + # Returns true if the new scope has precedence over the older + # rubocop: disable Naming/PredicateName + def has_precedence?(old_scope, new_scope) + return true if old_scope.nil? + + new_path = sanitize_path(new_scope["path"]) + old_path = sanitize_path(old_scope["path"]) + + if new_path.length != old_path.length + new_path.length >= old_path.length + elsif new_scope.key?("type") + true + else + !old_scope.key? "type" + end + end + # rubocop: enable Naming/PredicateName + + # Collects a list of sets that match the given path and type + # + # Returns an array of hashes + def matching_sets(path, type) + @matched_set_cache ||= {} + @matched_set_cache[path] ||= {} + @matched_set_cache[path][type] ||= valid_sets.select do |set| + !set.key?("scope") || applies?(set["scope"], path, type) + end + end + + # Returns a list of valid sets + # + # This is not cached to allow plugins to modify the configuration + # and have their changes take effect + # + # Returns an array of hashes + def valid_sets + sets = @site.config["defaults"] + return [] unless sets.is_a?(Array) + + sets.map do |set| + if valid?(set) + ensure_time!(update_deprecated_types(set)) + else + Jekyll.logger.warn "Defaults:", "An invalid front-matter default set was found:" + Jekyll.logger.warn set.to_s + nil + end + end.tap(&:compact!) + end + + # Sanitizes the given path by removing a leading slash + def sanitize_path(path) + if path.nil? || path.empty? + "" + elsif path.start_with?("/") + path.gsub(%r!\A/|(?<=[^/])\z!, "") + else + path + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/generator.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/generator.rb new file mode 100644 index 00000000..649715f8 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/generator.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Jekyll + Generator = Class.new(Plugin) +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/hooks.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/hooks.rb new file mode 100644 index 00000000..482d8026 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/hooks.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module Jekyll + module Hooks + DEFAULT_PRIORITY = 20 + + # compatibility layer for octopress-hooks users + PRIORITY_MAP = { + :low => 10, + :normal => 20, + :high => 30, + }.freeze + + # initial empty hooks + @registry = { + :site => { + :after_init => [], + :after_reset => [], + :post_read => [], + :pre_render => [], + :post_render => [], + :post_write => [], + }, + :pages => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :posts => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :documents => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :clean => { + :on_obsolete => [], + }, + } + + # map of all hooks and their priorities + @hook_priority = {} + + NotAvailable = Class.new(RuntimeError) + Uncallable = Class.new(RuntimeError) + + # register hook(s) to be called later, public API + def self.register(owners, event, priority: DEFAULT_PRIORITY, &block) + Array(owners).each do |owner| + register_one(owner, event, priority_value(priority), &block) + end + end + + # Ensure the priority is a Fixnum + def self.priority_value(priority) + return priority if priority.is_a?(Integer) + + PRIORITY_MAP[priority] || DEFAULT_PRIORITY + end + + # register a single hook to be called later, internal API + def self.register_one(owner, event, priority, &block) + @registry[owner] ||= { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + } + + unless @registry[owner][event] + raise NotAvailable, "Invalid hook. #{owner} supports only the following hooks " \ + "#{@registry[owner].keys.inspect}" + end + + raise Uncallable, "Hooks must respond to :call" unless block.respond_to? :call + + insert_hook owner, event, priority, &block + end + + def self.insert_hook(owner, event, priority, &block) + @hook_priority[block] = [-priority, @hook_priority.size] + @registry[owner][event] << block + end + + # interface for Jekyll core components to trigger hooks + def self.trigger(owner, event, *args) + # proceed only if there are hooks to call + hooks = @registry.dig(owner, event) + return if hooks.nil? || hooks.empty? + + # sort and call hooks according to priority and load order + hooks.sort_by { |h| @hook_priority[h] }.each do |hook| + hook.call(*args) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb new file mode 100644 index 00000000..179ddb04 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Jekyll + class Inclusion + attr_reader :site, :name, :path + private :site + + def initialize(site, base, name) + @site = site + @name = name + @path = PathManager.join(base, name) + end + + def render(context) + @template ||= site.liquid_renderer.file(path).parse(content) + @template.render!(context) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + + def content + @content ||= File.read(path, **site.file_read_opts) + end + + def inspect + "#{self.class} #{path.inspect}" + end + alias_method :to_s, :inspect + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/layout.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/layout.rb new file mode 100644 index 00000000..af3ea71a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/layout.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Jekyll + class Layout + include Convertible + + attr_accessor :content, # content of layout + :data, # the Hash that holds the metadata for this layout + :ext # extension of layout + + attr_reader :name, # name of layout + :path, # path to layout + :site, # the Site object + :relative_path # path to layout relative to its base + + # Initialize a new Layout. + # + # site - The Site. + # base - The String path to the source. + # name - The String filename of the post file. + def initialize(site, base, name) + @site = site + @base = base + @name = name + + if site.theme && site.theme.layouts_path.eql?(base) + @base_dir = site.theme.root + @path = site.in_theme_dir(base, name) + else + @base_dir = site.source + @path = site.in_source_dir(base, name) + end + @relative_path = @path.sub(@base_dir, "") + + self.data = {} + + process(name) + read_yaml(base, name) + end + + # Extract information from the layout filename. + # + # name - The String filename of the layout file. + # + # Returns nothing. + def process(name) + self.ext = File.extname(name) + end + + # Returns the object as a debug String. + def inspect + "#<#{self.class} @path=#{@path.inspect}>" + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb new file mode 100644 index 00000000..87e06ef7 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Jekyll + module LiquidExtensions + # Lookup a Liquid variable in the given context. + # + # context - the Liquid context in question. + # variable - the variable name, as a string. + # + # Returns the value of the variable in the context + # or the variable name if not found. + def lookup_variable(context, variable) + lookup = context + + variable.split(".").each do |value| + lookup = lookup[value] + end + + lookup || variable + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb new file mode 100644 index 00000000..7655e04d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require_relative "liquid_renderer/file" +require_relative "liquid_renderer/table" + +module Jekyll + class LiquidRenderer + def initialize(site) + @site = site + Liquid::Template.error_mode = @site.config["liquid"]["error_mode"].to_sym + reset + end + + def reset + @stats = {} + @cache = {} + end + + def file(filename) + filename = normalize_path(filename) + LiquidRenderer::File.new(self, filename).tap do + @stats[filename] ||= new_profile_hash + end + end + + def increment_bytes(filename, bytes) + @stats[filename][:bytes] += bytes + end + + def increment_time(filename, time) + @stats[filename][:time] += time + end + + def increment_count(filename) + @stats[filename][:count] += 1 + end + + def stats_table(num_of_rows = 50) + LiquidRenderer::Table.new(@stats).to_s(num_of_rows) + end + + def self.format_error(error, path) + "#{error.message} in #{path}" + end + + # A persistent cache to store and retrieve parsed templates based on the filename + # via `LiquidRenderer::File#parse` + # + # It is emptied when `self.reset` is called. + def cache + @cache ||= {} + end + + private + + def normalize_path(filename) + @normalize_path ||= {} + @normalize_path[filename] ||= begin + theme_dir = @site.theme&.root + case filename + when %r!\A(#{Regexp.escape(@site.source)}/)(?.*)!io + Regexp.last_match(:rest) + when %r!(/gems/.*)*/gems/(?[^/]+)(?.*)!, + %r!(?[^/]+/lib)(?.*)! + "#{Regexp.last_match(:dirname)}#{Regexp.last_match(:rest)}" + when theme_dir && %r!\A#{Regexp.escape(theme_dir)}/(?.*)!io + PathManager.join(@site.theme.basename, Regexp.last_match(:rest)) + when %r!\A/(.*)! + Regexp.last_match(1) + else + filename + end + end + end + + def new_profile_hash + Hash.new { |hash, key| hash[key] = 0 } + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb new file mode 100644 index 00000000..146c416d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module Jekyll + class LiquidRenderer + class File + def initialize(renderer, filename) + @renderer = renderer + @filename = filename + end + + def parse(content) + measure_time do + @renderer.cache[@filename] ||= Liquid::Template.parse(content, :line_numbers => true) + end + @template = @renderer.cache[@filename] + + self + end + + def render(*args) + reset_template_assigns + + measure_time do + measure_bytes do + measure_counts do + @template.render(*args) + end + end + end + end + + # This method simply 'rethrows any error' before attempting to render the template. + def render!(*args) + reset_template_assigns + + measure_time do + measure_bytes do + measure_counts do + @template.render!(*args) + end + end + end + end + + def warnings + @template.warnings + end + + private + + # clear assigns to `Liquid::Template` instance prior to rendering since + # `Liquid::Template` instances are cached in Jekyll 4. + def reset_template_assigns + @template.instance_assigns.clear + end + + def measure_counts + @renderer.increment_count(@filename) + yield + end + + def measure_bytes + yield.tap do |str| + @renderer.increment_bytes(@filename, str.bytesize) + end + end + + def measure_time + before = Time.now + yield + ensure + after = Time.now + @renderer.increment_time(@filename, after - before) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb new file mode 100644 index 00000000..2d06a26a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Jekyll + class LiquidRenderer + class Table + GAUGES = [:count, :bytes, :time].freeze + + def initialize(stats) + @stats = stats + end + + def to_s(num_of_rows = 50) + Jekyll::Profiler.tabulate(data_for_table(num_of_rows)) + end + + private + + def data_for_table(num_of_rows) + sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] } + sorted = sorted.slice(0, num_of_rows) + + table = [header_labels] + sorted.each do |filename, file_stats| + row = [] + row << filename + row << file_stats[:count].to_s + row << format_bytes(file_stats[:bytes]) + row << format("%.3f", file_stats[:time]) + table << row + end + + table + end + + def header_labels + GAUGES.map { |gauge| gauge.to_s.capitalize }.unshift("Filename") + end + + def format_bytes(bytes) + bytes /= 1024.0 + format("%.2fK", bytes) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb new file mode 100644 index 00000000..6ddfa4ad --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +module Jekyll + class LogAdapter + attr_reader :writer, :messages, :level + + LOG_LEVELS = { + :debug => ::Logger::DEBUG, + :info => ::Logger::INFO, + :warn => ::Logger::WARN, + :error => ::Logger::ERROR, + }.freeze + + # Public: Create a new instance of a log writer + # + # writer - Logger compatible instance + # log_level - (optional, symbol) the log level + # + # Returns nothing + def initialize(writer, level = :info) + @messages = [] + @writer = writer + self.log_level = level + end + + # Public: Set the log level on the writer + # + # level - (symbol) the log level + # + # Returns nothing + def log_level=(level) + writer.level = level if level.is_a?(Integer) && level.between?(0, 3) + writer.level = LOG_LEVELS[level] || + raise(ArgumentError, "unknown log level") + @level = level + end + + def adjust_verbosity(options = {}) + # Quiet always wins. + if options[:quiet] + self.log_level = :error + elsif options[:verbose] + self.log_level = :debug + end + debug "Logging at level:", LOG_LEVELS.key(writer.level).to_s + debug "Jekyll Version:", Jekyll::VERSION + end + + # Public: Print a debug message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def debug(topic, message = nil, &block) + write(:debug, topic, message, &block) + end + + # Public: Print a message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def info(topic, message = nil, &block) + write(:info, topic, message, &block) + end + + # Public: Print a message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def warn(topic, message = nil, &block) + write(:warn, topic, message, &block) + end + + # Public: Print an error message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def error(topic, message = nil, &block) + write(:error, topic, message, &block) + end + + # Public: Print an error message and immediately abort the process + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail (can be omitted) + # + # Returns nothing + def abort_with(topic, message = nil, &block) + error(topic, message, &block) + abort + end + + # Internal: Build a topic method + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns the formatted message + def message(topic, message = nil) + raise ArgumentError, "block or message, not both" if block_given? && message + + message = yield if block_given? + message = message.to_s.gsub(%r!\s+!, " ") + topic = formatted_topic(topic, block_given?) + out = topic + message + messages << out + out + end + + # Internal: Format the topic + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # colon - + # + # Returns the formatted topic statement + def formatted_topic(topic, colon = false) + "#{topic}#{colon ? ": " : " "}".rjust(20) + end + + # Internal: Check if the message should be written given the log level. + # + # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error + # + # Returns whether the message should be written. + def write_message?(level_of_message) + LOG_LEVELS.fetch(level) <= LOG_LEVELS.fetch(level_of_message) + end + + # Internal: Log a message. + # + # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error + # topic - the String topic or full message + # message - the String message (optional) + # block - a block containing the message (optional) + # + # Returns false if the message was not written, otherwise returns the value of calling + # the appropriate writer method, e.g. writer.info. + def write(level_of_message, topic, message = nil, &block) + return false unless write_message?(level_of_message) + + writer.public_send(level_of_message, message(topic, message, &block)) + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/mime.types b/bin/gems/jekyll-4.4.1/lib/jekyll/mime.types new file mode 100644 index 00000000..10f713c6 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/mime.types @@ -0,0 +1,940 @@ +# Woah there. Do not edit this file directly. +# This file is generated automatically by script/vendor-mimes. + +application/andrew-inset ez +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +application/atomdeleted+xml atomdeleted +application/atomsvc+xml atomsvc +application/atsc-dwd+xml dwd +application/atsc-held+xml held +application/atsc-rsat+xml rsat +application/bdoc bdoc +application/calendar+xml xcs +application/ccxml+xml ccxml +application/cdfx+xml cdfx +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +application/cpl+xml cpl +application/cu-seeme cu +application/dash+xml mpd +application/dash-patch+xml mpp +application/davmount+xml davmount +application/docbook+xml dbk +application/dssc+der dssc +application/dssc+xml xdssc +application/ecmascript ecma es +application/emma+xml emma +application/emotionml+xml emotionml +application/epub+zip epub +application/exi exi +application/express exp +application/fdt+xml fdt +application/font-tdpfr pfr +application/geo+json geojson +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +application/gzip gz +application/hjson hjson +application/hyperstudio stk +application/inkml+xml ink inkml +application/ipfix ipfix +application/its+xml its +application/java-archive ear jar war +application/java-serialized-object ser +application/java-vm class +application/javascript js mjs +application/json json map +application/json5 json5 +application/jsonml+json jsonml +application/ld+json jsonld +application/lgr+xml lgr +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/mads+xml mads +application/manifest+json webmanifest +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma mb nb +application/mathml+xml mathml +application/mbox mbox +application/media-policy-dataset+xml mpf +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +application/mmt-aei+xml maei +application/mmt-usd+xml musd +application/mods+xml mods +application/mp21 m21 mp21 +application/mp4 m4p mp4s +application/msword doc dot +application/mxf mxf +application/n-quads nq +application/n-triples nt +application/node cjs +application/octet-stream bin bpk buffer deb deploy dist distz dll dmg dms dump elc exe img iso lrf mar msi msm msp pkg so +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onepkg onetmp onetoc onetoc2 +application/oxps oxps +application/p2p-overlay+xml relo +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys asc +application/pgp-signature sig +application/pics-rules prf +application/pkcs10 p10 +application/pkcs7-mime p7c p7m +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/postscript ai eps ps +application/provenance+xml provx +application/prs.cww cww +application/pskc+xml pskcxml +application/raml+yaml raml +application/rdf+xml owl rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/rls-services+xml rs +application/route-apd+xml rapd +application/route-s-tsid+xml sls +application/route-usd+xml rusd +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/senml+xml senmlx +application/sensml+xml sensmlx +application/set-payment-initiation setpay +application/set-registration-initiation setreg +application/shf+xml shf +application/sieve sieve siv +application/smil+xml smi smil +application/sparql-query rq +application/sparql-results+xml srx +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +application/swid+xml swidtag +application/tei+xml tei teicorpus +application/thraud+xml tfi +application/timestamped-data tsd +application/toml toml +application/trig trig +application/ttml+xml ttml +application/ubjson ubj +application/urc-ressheet+xml rsheet +application/urc-targetdesc+xml td +application/vnd.1000minds.decision-model+xml 1km +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp acutc atc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.age age +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.keynote key +application/vnd.apple.mpegurl m3u8 +application/vnd.apple.numbers numbers +application/vnd.apple.pages pages +application/vnd.apple.pkpass pkpass +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +application/vnd.balsamiq.bmml+xml bmml +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.citationstyles.style+xml csl +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4d c4f c4g c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.cups-ppd ppd +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dbf dbf +application/vnd.dece.data uvd uvf uvvd uvvf +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvvx uvx +application/vnd.dece.zip uvvz uvz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +application/vnd.dvb.service svc +application/vnd.dynageo geo +application/vnd.ecowin.chart mag +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.eszigno3+xml es3 et3 +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed dataless seed +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.framemaker book fm frame maker +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +application/vnd.gmx gmx +application/vnd.google-apps.document gdoc +application/vnd.google-apps.presentation gslides +application/vnd.google-apps.spreadsheet gsheet +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp list3820 listafp +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktr ktz +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skd skm skp skt +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.mapbox-vector-tile mvt +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xla xlc xlm xls xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-officetheme thmx +application/vnd.ms-outlook msg +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint pot pps ppt +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpt +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wcm wdb wks wps +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf nitf ntf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.olpc-sugar xo +application/vnd.oma.dd2+xml dd2 +application/vnd.openblox.game+xml obgx +application/vnd.openofficeorg.extension oxt +application/vnd.openstreetmap.data+xml osm +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osgeo.mapguide.package mgp +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +application/vnd.palm oprc pdb pqa +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.picsel efif +application/vnd.pmi.widget wg +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.quark.quarkxpress qwd qwt qxb qxd qxl qxt +application/vnd.rar rar +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +application/vnd.sailingtracker.track st +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.smart.teacher teacher +application/vnd.software602.filler.form+xml fo +application/vnd.solent.sdkm+xml sdkd sdkm +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +application/vnd.sun.wadl+xml wadl +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.dmddf+xml ddf +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap cap dmp pcap +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.vcx vcx +application/vnd.visio vsd vss vst vsw +application/vnd.visionary vis +application/vnd.vsf vsf +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wt.stf stf +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/wasm wasm +application/watcherinfo+xml wif +application/widget wgt +application/winhlp hlp +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +application/x-arj arj +application/x-authorware-bin aab u32 vox x32 +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 boz bz2 +application/x-cbr cb7 cba cbr cbt cbz +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-chrome-extension crx +application/x-cocoa cco +application/x-conference nsc +application/x-cpio cpio +application/x-csh csh +application/x-debian-package udeb +application/x-dgc-compressed dgc +application/x-director cct cst cxt dcr dir dxr fgd swa w3d +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +application/x-font-ghostscript gsf +application/x-font-linux-psf psf +application/x-font-pcf pcf +application/x-font-snf snf +application/x-font-type1 afm pfa pfb pfm +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +application/x-hdf hdf +application/x-httpd-php php +application/x-install-instructions install +application/x-java-archive-diff jardiff +application/x-java-jnlp-file jnlp +application/x-keepass2 kdbx +application/x-latex latex +application/x-lua-bytecode luac +application/x-lzh-compressed lha lzh +application/x-makeself run +application/x-mie mie +application/x-mobipocket-ebook mobi prc +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload bat com +application/x-msmediaview m13 m14 mvb +application/x-msmetafile emf emz wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf cdf nc +application/x-ns-proxy-autoconfig pac +application/x-nzb nzb +application/x-perl pl pm +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-redhat-package-manager rpm +application/x-research-info-systems ris +application/x-sea sea +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl tk +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texi texinfo +application/x-tgif obj +application/x-ustar ustar +application/x-virtualbox-hdd hdd +application/x-virtualbox-ova ova +application/x-virtualbox-ovf ovf +application/x-virtualbox-vbox vbox +application/x-virtualbox-vbox-extpack vbox-extpack +application/x-virtualbox-vdi vdi +application/x-virtualbox-vhd vhd +application/x-virtualbox-vmdk vmdk +application/x-wais-source src +application/x-web-app-manifest+json webapp +application/x-x509-ca-cert crt der pem +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +application/xaml+xml xaml +application/xcap-att+xml xav +application/xcap-caps+xml xca +application/xcap-diff+xml xdf +application/xcap-el+xml xel +application/xcap-ns+xml xns +application/xenc+xml xenc +application/xhtml+xml xht xhtml +application/xml rng xml xsd xsl +application/xml-dtd dtd +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvm xvml +application/yang yang +application/yin+xml yin +application/zip zip +audio/3gpp 3gpp +audio/adpcm adp +audio/amr amr +audio/basic au snd +audio/midi kar mid midi rmi +audio/mobile-xmf mxmf +audio/mp3 mp3 +audio/mp4 m4a mp4a +audio/mpeg m2a m3a mp2 mp2a mpga +audio/ogg oga ogg opus spx +audio/s3m s3m +audio/silk sil +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.rip rip +audio/wav wav +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aifc aiff +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ra ram +audio/x-pn-realaudio-plugin rmp +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-xyz xyz +font/collection ttc +font/otf otf +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/aces exr +image/apng apng +image/avci avci +image/avcs avcs +image/avif avif +image/bmp bmp +image/cgm cgm +image/dicom-rle drle +image/fits fits +image/g3fax g3 +image/gif gif +image/heic heic +image/heic-sequence heics +image/heif heif +image/heif-sequence heifs +image/hej2k hej2 +image/hsj2 hsj2 +image/ief ief +image/jls jls +image/jp2 jp2 jpg2 +image/jpeg jpe jpeg jpg +image/jph jph +image/jphc jhc +image/jpm jpm +image/jpx jpf jpx +image/jxr jxr +image/jxra jxra +image/jxrs jxrs +image/jxs jxs +image/jxsc jxsc +image/jxsi jxsi +image/jxss jxss +image/ktx ktx +image/ktx2 ktx2 +image/png png +image/prs.btif btif +image/prs.pti pti +image/sgi sgi +image/svg+xml svg svgz +image/t38 t38 +image/tiff tif tiff +image/tiff-fx tfx +image/vnd.adobe.photoshop psd +image/vnd.airzip.accelerator.azv azv +image/vnd.dece.graphic uvg uvi uvvg uvvi +image/vnd.djvu djv djvu +image/vnd.dvb.subtitle sub +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.microsoft.icon ico +image/vnd.ms-dds dds +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +image/vnd.pco.b16 b16 +image/vnd.tencent.tap tap +image/vnd.valve.source.texture vtf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/vnd.zbrush.pcx pcx +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fh4 fh5 fh7 fhc +image/x-jng jng +image/x-mrsid-image sid +image/x-pict pct pic +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/disposition-notification disposition-notification +message/global u8msg +message/global-delivery-status u8dsn +message/global-disposition-notification u8mdn +message/global-headers u8hdr +message/rfc822 eml mime +message/vnd.wfa.wsc wsc +model/3mf 3mf +model/gltf+json gltf +model/gltf-binary glb +model/iges iges igs +model/mesh mesh msh silo +model/mtl mtl +model/step+xml stpx +model/step+zip stpz +model/step-xml+zip stpxz +model/vnd.collada+xml dae +model/vnd.dwf dwf +model/vnd.gdl gdl +model/vnd.gtw gtw +model/vnd.mts mts +model/vnd.opengex ogex +model/vnd.parasolid.transmit.binary x_b +model/vnd.parasolid.transmit.text x_t +model/vnd.sap.vds vds +model/vnd.usdz+zip usdz +model/vnd.valve.source.compiled-map bsp +model/vnd.vtu vtu +model/vrml vrml wrl +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +text/cache-manifest appcache manifest +text/calendar ics ifb +text/coffeescript coffee litcoffee +text/css css +text/csv csv +text/html htm html shtml +text/jade jade +text/jsx jsx +text/less less +text/markdown markdown md +text/mathml mml +text/mdx mdx +text/n3 n3 +text/plain conf def in ini list log text txt +text/prs.lines.tag dsc +text/richtext rtx +text/sgml sgm sgml +text/shex shex +text/slim slim slm +text/spdx spdx +text/stylus styl stylus +text/tab-separated-values tsv +text/troff man me ms roff t tr +text/turtle ttl +text/uri-list uri uris urls +text/vcard vcard +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.mcurl mcurl +text/vnd.curl.scurl scurl +text/vnd.familysearch.gedcom ged +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/vtt vtt +text/x-asm asm s +text/x-c c cc cpp cxx dic h hh +text/x-component htc +text/x-fortran f f77 f90 for +text/x-handlebars-template hbs +text/x-java-source java +text/x-lua lua +text/x-markdown mkd +text/x-nfo nfo +text/x-opml opml +text/x-pascal p pas +text/x-processing pde +text/x-sass sass +text/x-scss scss +text/x-setext etx +text/x-sfv sfv +text/x-suse-ymp ymp +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +text/yaml yaml yml +video/3gpp 3gp +video/3gpp2 3g2 +video/h261 h261 +video/h263 h263 +video/h264 h264 +video/iso.segment m4s +video/jpeg jpgv +video/jpm jpgm +video/mj2 mj2 mjp2 +video/mp2t ts +video/mp4 mp4 mp4v mpg4 +video/mpeg m1v m2v mpe mpeg mpg +video/ogg ogv +video/quicktime mov qt +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +video/vnd.dvb.file dvb +video/vnd.fvt fvt +video/vnd.mpegurl m4u mxu +video/vnd.ms-playready.media.pyv pyv +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mk3d mks mkv +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice \ No newline at end of file diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/page.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/page.rb new file mode 100644 index 00000000..64821a82 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/page.rb @@ -0,0 +1,215 @@ +# frozen_string_literal: true + +module Jekyll + class Page + include Convertible + + attr_writer :dir + attr_accessor :basename, :content, :data, :ext, :name, :output, :pager, :site + + alias_method :extname, :ext + + # Attributes for Liquid templates + ATTRIBUTES_FOR_LIQUID = %w( + content + dir + excerpt + name + path + url + ).freeze + + # A set of extensions that are considered HTML or HTML-like so we + # should not alter them, this includes .xhtml through XHTM5. + + HTML_EXTENSIONS = %w( + .html + .xhtml + .htm + ).freeze + + # Initialize a new Page. + # + # site - The Site object. + # base - The String path to the source. + # dir - The String path between the source and the file. + # name - The String filename of the file. + def initialize(site, base, dir, name) + @site = site + @base = base + @dir = dir + @name = name + @path = if site.in_theme_dir(base) == base # we're in a theme + site.in_theme_dir(base, dir, name) + else + site.in_source_dir(base, dir, name) + end + + process(name) + read_yaml(PathManager.join(base, dir), name) + generate_excerpt if site.config["page_excerpts"] + + data.default_proc = proc do |_, key| + site.frontmatter_defaults.find(relative_path, type, key) + end + + Jekyll::Hooks.trigger :pages, :post_init, self + end + + # The generated directory into which the page will be placed + # upon generation. This is derived from the permalink or, if + # permalink is absent, will be '/' + # + # Returns the String destination directory. + def dir + url.end_with?("/") ? url : url_dir + end + + # The full path and filename of the post. Defined in the YAML of the post + # body. + # + # Returns the String permalink or nil if none has been set. + def permalink + data.nil? ? nil : data["permalink"] + end + + # The template of the permalink. + # + # Returns the template String. + def template + if !html? + "/:path/:basename:output_ext" + elsif index? + "/:path/" + else + Utils.add_permalink_suffix("/:path/:basename", site.permalink_style) + end + end + + # The generated relative url of this page. e.g. /about.html. + # + # Returns the String url. + def url + @url ||= URL.new( + :template => template, + :placeholders => url_placeholders, + :permalink => permalink + ).to_s + end + + # Returns a hash of URL placeholder names (as symbols) mapping to the + # desired placeholder replacements. For details see "url.rb" + def url_placeholders + { + :path => @dir, + :basename => basename, + :output_ext => output_ext, + } + end + + # Extract information from the page filename. + # + # name - The String filename of the page file. + # + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + # Returns nothing. + def process(name) + return unless name + + self.ext = File.extname(name) + self.basename = name[0..-ext.length - 1].gsub(%r!\.*\z!, "") + end + + # Add any necessary layouts to this post + # + # layouts - The Hash of {"name" => "layout"}. + # site_payload - The site payload Hash. + # + # Returns String rendered page. + def render(layouts, site_payload) + site_payload["page"] = to_liquid + site_payload["paginator"] = pager.to_liquid + + do_layout(site_payload, layouts) + end + + # The path to the source file + # + # Returns the path to the source file + def path + data.fetch("path") { relative_path } + end + + # The path to the page source file, relative to the site source + def relative_path + @relative_path ||= PathManager.join(@dir, @name).delete_prefix("/") + end + + # Obtain destination path. + # + # dest - The String path to the destination dir. + # + # Returns the destination file path String. + def destination(dest) + @destination ||= {} + @destination[dest] ||= begin + path = site.in_dest_dir(dest, URL.unescape_path(url)) + path = File.join(path, "index") if url.end_with?("/") + path << output_ext unless path.end_with? output_ext + path + end + end + + # Returns the object as a debug String. + def inspect + "#<#{self.class} @relative_path=#{relative_path.inspect}>" + end + + # Returns the Boolean of whether this Page is HTML or not. + def html? + HTML_EXTENSIONS.include?(output_ext) + end + + # Returns the Boolean of whether this Page is an index file or not. + def index? + basename == "index" + end + + def trigger_hooks(hook_name, *args) + Jekyll::Hooks.trigger :pages, hook_name, self, *args + end + + def write? + true + end + + def excerpt_separator + @excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s + end + + def excerpt + return @excerpt if defined?(@excerpt) + + @excerpt = data["excerpt"] ? data["excerpt"].to_s : nil + end + + def generate_excerpt? + !excerpt_separator.empty? && instance_of?(Jekyll::Page) && html? + end + + private + + def generate_excerpt + return unless generate_excerpt? + + data["excerpt"] ||= Jekyll::PageExcerpt.new(self) + end + + def url_dir + @url_dir ||= begin + value = File.dirname(url) + value.end_with?("/") ? value : "#{value}/" + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb new file mode 100644 index 00000000..dd79fca8 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class PageExcerpt < Excerpt + attr_reader :doc + alias_method :id, :relative_path + + EXCERPT_ATTRIBUTES = (Page::ATTRIBUTES_FOR_LIQUID - %w(excerpt)).freeze + private_constant :EXCERPT_ATTRIBUTES + + def to_liquid + @to_liquid ||= doc.to_liquid(EXCERPT_ATTRIBUTES) + end + + def render_with_liquid? + return false if data["render_with_liquid"] == false + + Jekyll::Utils.has_liquid_construct?(content) + end + + def inspect + "#<#{self.class} id=#{id.inspect}>" + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb new file mode 100644 index 00000000..e314f970 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jekyll + # A Jekyll::Page subclass to handle processing files without reading it to + # determine the page-data and page-content based on Front Matter delimiters. + # + # The class instance is basically just a bare-bones entity with just + # attributes "dir", "name", "path", "url" defined on it. + class PageWithoutAFile < Page + def read_yaml(*) + @data ||= {} + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb new file mode 100644 index 00000000..5d975222 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Jekyll + # A singleton class that caches frozen instances of path strings returned from its methods. + # + # NOTE: + # This class exists because `File.join` allocates an Array and returns a new String on every + # call using **the same arguments**. Caching the result means reduced memory usage. + # However, the caches are never flushed so that they can be used even when a site is + # regenerating. The results are frozen to deter mutation of the cached string. + # + # Therefore, employ this class only for situations where caching the result is necessary + # for performance reasons. + # + class PathManager + # This class cannot be initialized from outside + private_class_method :new + + class << self + # Wraps `File.join` to cache the frozen result. + # Reassigns `nil`, empty strings and empty arrays to a frozen empty string beforehand. + # + # Returns a frozen string. + def join(base, item) + base = "" if base.nil? || base.empty? + item = "" if item.nil? || item.empty? + @join ||= {} + @join[base] ||= {} + @join[base][item] ||= File.join(base, item).freeze + end + + # Ensures the questionable path is prefixed with the base directory + # and prepends the questionable path with the base directory if false. + # + # Returns a frozen string. + def sanitized_path(base_directory, questionable_path) + @sanitized_path ||= {} + @sanitized_path[base_directory] ||= {} + @sanitized_path[base_directory][questionable_path] ||= if questionable_path.nil? + base_directory.freeze + else + sanitize_and_join( + base_directory, questionable_path + ).freeze + end + end + + private + + def sanitize_and_join(base_directory, questionable_path) + clean_path = if questionable_path.start_with?("~") + questionable_path.dup.insert(0, "/") + else + questionable_path + end + clean_path = File.expand_path(clean_path, "/") + return clean_path if clean_path.eql?(base_directory) + + # remove any remaining extra leading slashes not stripped away by calling + # `File.expand_path` above. + clean_path.squeeze!("/") + return clean_path if clean_path.start_with?(slashed_dir_cache(base_directory)) + + clean_path.sub!(%r!\A\w:/!, "/") + join(base_directory, clean_path) + end + + def slashed_dir_cache(base_directory) + @slashed_dir_cache ||= {} + @slashed_dir_cache[base_directory] ||= base_directory.sub(%r!\z!, "/") + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/plugin.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/plugin.rb new file mode 100644 index 00000000..1157e12a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/plugin.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module Jekyll + class Plugin + PRIORITIES = { + :low => -10, + :highest => 100, + :lowest => -100, + :normal => 0, + :high => 10, + }.freeze + + # + + def self.inherited(const) + catch_inheritance(const) do |const_| + catch_inheritance(const_) + end + end + + # + + def self.catch_inheritance(const) + const.define_singleton_method :inherited do |const_| + (@children ||= Set.new).add const_ + yield const_ if block_given? + end + end + + # + + def self.descendants + @children ||= Set.new + out = @children.map(&:descendants) + out << self unless superclass == Plugin + Set.new(out).flatten + end + + # Get or set the priority of this plugin. When called without an + # argument it returns the priority. When an argument is given, it will + # set the priority. + # + # priority - The Symbol priority (default: nil). Valid options are: + # :lowest, :low, :normal, :high, :highest + # + # Returns the Symbol priority. + def self.priority(priority = nil) + @priority ||= nil + @priority = priority if priority && PRIORITIES.key?(priority) + @priority || :normal + end + + # Get or set the safety of this plugin. When called without an argument + # it returns the safety. When an argument is given, it will set the + # safety. + # + # safe - The Boolean safety (default: nil). + # + # Returns the safety Boolean. + def self.safe(safe = nil) + @safe = safe unless defined?(@safe) && safe.nil? + @safe || false + end + + # Spaceship is priority [higher -> lower] + # + # other - The class to be compared. + # + # Returns -1, 0, 1. + def self.<=>(other) + PRIORITIES[other.priority] <=> PRIORITIES[priority] + end + + # Spaceship is priority [higher -> lower] + # + # other - The class to be compared. + # + # Returns -1, 0, 1. + def <=>(other) + self.class <=> other.class + end + + # Initialize a new plugin. This should be overridden by the subclass. + # + # config - The Hash of configuration options. + # + # Returns a new instance. + def initialize(config = {}) + # no-op for default + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb new file mode 100644 index 00000000..810a2fa1 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +module Jekyll + class PluginManager + attr_reader :site + + # Create an instance of this class. + # + # site - the instance of Jekyll::Site we're concerned with + # + # Returns nothing + def initialize(site) + @site = site + end + + # Require all the plugins which are allowed. + # + # Returns nothing + def conscientious_require + require_theme_deps if site.theme + require_plugin_files + require_gems + deprecation_checks + end + + # Require each of the gem plugins specified. + # + # Returns nothing. + def require_gems + Jekyll::External.require_with_graceful_fail( + site.gems.select { |plugin| plugin_allowed?(plugin) } + ) + end + + # Require each of the runtime_dependencies specified by the theme's gemspec. + # + # Returns false only if no dependencies have been specified, otherwise nothing. + def require_theme_deps + return false unless site.theme.runtime_dependencies + + site.theme.runtime_dependencies.each do |dep| + next if dep.name == "jekyll" + + External.require_with_graceful_fail(dep.name) if plugin_allowed?(dep.name) + end + end + + def self.require_from_bundler + if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && gemfile_exists? + require "bundler" + + Bundler.setup + required_gems = Bundler.require(:jekyll_plugins) + message = "Required #{required_gems.map(&:name).join(", ")}" + Jekyll.logger.debug("PluginManager:", message) + ENV["JEKYLL_NO_BUNDLER_REQUIRE"] = "true" + + true + else + false + end + end + + # Check for the existence of a Gemfile. + # + # Returns true if a Gemfile exists in the places bundler will look + def self.gemfile_exists? + File.file?("Gemfile") || (ENV["BUNDLE_GEMFILE"] && File.file?(ENV["BUNDLE_GEMFILE"])) + end + + # Check whether a gem plugin is allowed to be used during this build. + # + # plugin_name - the name of the plugin + # + # Returns true if the plugin name is in the whitelist or if the site is not + # in safe mode. + def plugin_allowed?(plugin_name) + !site.safe || whitelist.include?(plugin_name) + end + + # Build an array of allowed plugin gem names. + # + # Returns an array of strings, each string being the name of a gem name + # that is allowed to be used. + def whitelist + @whitelist ||= [site.config["whitelist"]].flatten + end + + # Require all .rb files if safe mode is off + # + # Returns nothing. + def require_plugin_files + unless site.safe + plugins_path.each do |plugin_search_path| + plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb")) + Jekyll::External.require_with_graceful_fail(plugin_files) + end + end + end + + # Public: Setup the plugin search path + # + # Returns an Array of plugin search paths + def plugins_path + if site.config["plugins_dir"].eql? Jekyll::Configuration::DEFAULTS["plugins_dir"] + [site.in_source_dir(site.config["plugins_dir"])] + else + Array(site.config["plugins_dir"]).map { |d| File.expand_path(d) } + end + end + + def deprecation_checks + pagination_included = (site.config["plugins"] || []).include?("jekyll-paginate") || + defined?(Jekyll::Paginate) + if site.config["paginate"] && !pagination_included + Jekyll::Deprecator.deprecation_message <<~MSG + You appear to have pagination turned on, but you haven't included the `jekyll-paginate` + gem. Ensure you have `plugins: [jekyll-paginate]` in your configuration file. + MSG + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/profiler.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/profiler.rb new file mode 100644 index 00000000..f5dbfb18 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/profiler.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Jekyll + class Profiler + TERMINAL_TABLE_STYLES = { + :alignment => :right, + :border_top => false, + :border_bottom => false, + }.freeze + private_constant :TERMINAL_TABLE_STYLES + + def self.tabulate(table_rows) + require "terminal-table" + + rows = table_rows.dup + header = rows.shift + output = +"\n" + + table = Terminal::Table.new do |t| + t << header + t << :separator + rows.each { |row| t << row } + t.style = TERMINAL_TABLE_STYLES + t.align_column(0, :left) + end + + output << table.to_s << "\n" + end + + def initialize(site) + @site = site + end + + def profile_process + profile_data = { "PHASE" => "TIME" } + + [:reset, :read, :generate, :render, :cleanup, :write].each do |method| + start_time = Time.now + @site.send(method) + end_time = (Time.now - start_time).round(4) + profile_data[method.to_s.upcase] = format("%.4f", end_time) + end + + Jekyll.logger.info "\nBuild Process Summary:" + Jekyll.logger.info Profiler.tabulate(Array(profile_data)) + + Jekyll.logger.info "\nSite Render Stats:" + @site.print_stats + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/publisher.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/publisher.rb new file mode 100644 index 00000000..26fe4a38 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/publisher.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + class Publisher + def initialize(site) + @site = site + end + + def publish?(thing) + can_be_published?(thing) && !hidden_in_the_future?(thing) + end + + def hidden_in_the_future?(thing) + thing.respond_to?(:date) && !@site.future && thing.date.to_i > @site.time.to_i + end + + private + + def can_be_published?(thing) + thing.data.fetch("published", true) || @site.unpublished + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/reader.rb new file mode 100644 index 00000000..5d15177c --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/reader.rb @@ -0,0 +1,209 @@ +# frozen_string_literal: true + +module Jekyll + class Reader + attr_reader :site + + def initialize(site) + @site = site + end + + # Read Site data from disk and load it into internal data structures. + # + # Returns nothing. + def read + @site.layouts = LayoutReader.new(site).read + read_directories + read_included_excludes + sort_files! + CollectionReader.new(site).read + ThemeAssetsReader.new(site).read + read_data + end + + # Read and merge the data files. + # If a theme is specified and it contains data, it will be read. + # Site data will overwrite theme data with the same key using the + # semantics of Utils.deep_merge_hashes. + # + # Returns nothing. + def read_data + @site.data = DataReader.new(site).read(site.config["data_dir"]) + return unless site.theme&.data_path + + theme_data = DataReader.new( + site, + :in_source_dir => site.method(:in_theme_dir) + ).read(site.theme.data_path) + @site.data = Jekyll::Utils.deep_merge_hashes(theme_data, @site.data) + end + + # Sorts posts, pages, and static files. + def sort_files! + site.collections.each_value { |c| c.docs.sort! } + site.pages.sort_by!(&:name) + site.static_files.sort_by!(&:relative_path) + end + + # Recursively traverse directories to find pages and static files + # that will become part of the site according to the rules in + # filter_entries. + # + # dir - The String relative path of the directory to read. Default: ''. + # + # Returns nothing. + def read_directories(dir = "") + base = site.in_source_dir(dir) + + return unless File.directory?(base) + + dot_dirs = [] + dot_pages = [] + dot_static_files = [] + + dot = Dir.chdir(base) { filter_entries(Dir.entries("."), base) } + dot.each do |entry| + file_path = @site.in_source_dir(base, entry) + if File.directory?(file_path) + dot_dirs << entry + elsif Utils.has_yaml_header?(file_path) + dot_pages << entry + else + dot_static_files << entry + end + end + + retrieve_posts(dir) + retrieve_dirs(base, dir, dot_dirs) + retrieve_pages(dir, dot_pages) + retrieve_static_files(dir, dot_static_files) + end + + # Retrieves all the posts(posts/drafts) from the given directory + # and add them to the site and sort them. + # + # dir - The String representing the directory to retrieve the posts from. + # + # Returns nothing. + def retrieve_posts(dir) + return if outside_configured_directory?(dir) + + site.posts.docs.concat(post_reader.read_posts(dir)) + site.posts.docs.concat(post_reader.read_drafts(dir)) if site.show_drafts + end + + # Recursively traverse directories with the read_directories function. + # + # base - The String representing the site's base directory. + # dir - The String representing the directory to traverse down. + # dot_dirs - The Array of subdirectories in the dir. + # + # Returns nothing. + def retrieve_dirs(_base, dir, dot_dirs) + dot_dirs.each do |file| + dir_path = site.in_source_dir(dir, file) + rel_path = PathManager.join(dir, file) + @site.reader.read_directories(rel_path) unless @site.dest.chomp("/") == dir_path + end + end + + # Retrieve all the pages from the current directory, + # add them to the site and sort them. + # + # dir - The String representing the directory retrieve the pages from. + # dot_pages - The Array of pages in the dir. + # + # Returns nothing. + def retrieve_pages(dir, dot_pages) + site.pages.concat(PageReader.new(site, dir).read(dot_pages)) + end + + # Retrieve all the static files from the current directory, + # add them to the site and sort them. + # + # dir - The directory retrieve the static files from. + # dot_static_files - The static files in the dir. + # + # Returns nothing. + def retrieve_static_files(dir, dot_static_files) + site.static_files.concat(StaticFileReader.new(site, dir).read(dot_static_files)) + end + + # Filter out any files/directories that are hidden or backup files (start + # with "." or "#" or end with "~"), or contain site content (start with "_"), + # or are excluded in the site configuration, unless they are web server + # files such as '.htaccess'. + # + # entries - The Array of String file/directory entries to filter. + # base_directory - The string representing the optional base directory. + # + # Returns the Array of filtered entries. + def filter_entries(entries, base_directory = nil) + EntryFilter.new(site, base_directory).filter(entries) + end + + # Read the entries from a particular directory for processing + # + # dir - The String representing the relative path of the directory to read. + # subfolder - The String representing the directory to read. + # + # Returns the list of entries to process + def get_entries(dir, subfolder) + base = site.in_source_dir(dir, subfolder) + return [] unless File.exist?(base) + + entries = Dir.chdir(base) { filter_entries(Dir["**/*"], base) } + entries.delete_if { |e| File.directory?(site.in_source_dir(base, e)) } + end + + private + + # Internal + # + # Determine if the directory is supposed to contain posts and drafts. + # If the user has defined a custom collections_dir, then attempt to read + # posts and drafts only from within that directory. + # + # Returns true if a custom collections_dir has been set but current directory lies + # outside that directory. + def outside_configured_directory?(dir) + collections_dir = site.config["collections_dir"] + !collections_dir.empty? && !dir.start_with?("/#{collections_dir}") + end + + # Create a single PostReader instance to retrieve drafts and posts from all valid + # directories in current site. + def post_reader + @post_reader ||= PostReader.new(site) + end + + def read_included_excludes + entry_filter = EntryFilter.new(site) + + site.include.each do |entry| + entry_path = site.in_source_dir(entry) + next if File.directory?(entry_path) + next if entry_filter.symlink?(entry_path) + + read_included_file(entry_path) if File.file?(entry_path) + end + end + + def read_included_file(entry_path) + if Utils.has_yaml_header?(entry_path) + conditionally_generate_entry(entry_path, site.pages, PageReader) + else + conditionally_generate_entry(entry_path, site.static_files, StaticFileReader) + end + end + + def conditionally_generate_entry(entry_path, container, reader) + return if container.find { |item| site.in_source_dir(item.relative_path) == entry_path } + + dir, files = File.split(entry_path) + dir.sub!(site.source, "") + files = Array(files) + container.concat(reader.new(site, dir).read(files)) + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb new file mode 100644 index 00000000..6d182750 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + class CollectionReader + SPECIAL_COLLECTIONS = %w(posts data).freeze + + attr_reader :site, :content + + def initialize(site) + @site = site + @content = {} + end + + # Read in all collections specified in the configuration + # + # Returns nothing. + def read + site.collections.each_value do |collection| + collection.read unless SPECIAL_COLLECTIONS.include?(collection.label) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb new file mode 100644 index 00000000..80b57bd6 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Jekyll + class DataReader + attr_reader :site, :content + + def initialize(site, in_source_dir: nil) + @site = site + @content = {} + @entry_filter = EntryFilter.new(site) + @in_source_dir = in_source_dir || @site.method(:in_source_dir) + @source_dir = @in_source_dir.call("/") + end + + # Read all the files in and adds them to @content + # + # dir - The String relative path of the directory to read. + # + # Returns @content, a Hash of the .yaml, .yml, + # .json, and .csv files in the base directory + def read(dir) + base = @in_source_dir.call(dir) + read_data_to(base, @content) + @content + end + + # Read and parse all .yaml, .yml, .json, .csv and .tsv + # files under and add them to the variable. + # + # dir - The string absolute path of the directory to read. + # data - The variable to which data will be added. + # + # Returns nothing + def read_data_to(dir, data) + return unless File.directory?(dir) && !@entry_filter.symlink?(dir) + + entries = Dir.chdir(dir) do + Dir["*.{yaml,yml,json,csv,tsv}"] + Dir["*"].select { |fn| File.directory?(fn) } + end + + entries.each do |entry| + path = @in_source_dir.call(dir, entry) + next if @entry_filter.symlink?(path) + + if File.directory?(path) + read_data_to(path, data[sanitize_filename(entry)] = {}) + else + key = sanitize_filename(File.basename(entry, ".*")) + data[key] = read_data_file(path) + end + end + end + + # Determines how to read a data file. + # + # Returns the contents of the data file. + def read_data_file(path) + Jekyll.logger.debug "Reading:", path.sub(@source_dir, "") + + case File.extname(path).downcase + when ".csv" + CSV.read(path, **csv_config).map { |row| convert_row(row) } + when ".tsv" + CSV.read(path, **tsv_config).map { |row| convert_row(row) } + else + SafeYAML.load_file(path) + end + end + + def sanitize_filename(name) + name.gsub(%r![^\w\s-]+|(?<=^|\b\s)\s+(?=$|\s?\b)!, "") + .gsub(%r!\s+!, "_") + end + + private + + # @return [Hash] + def csv_config + @csv_config ||= read_config("csv_reader") + end + + # @return [Hash] + def tsv_config + @tsv_config ||= read_config("tsv_reader", { :col_sep => "\t" }) + end + + # @param config_key [String] + # @param overrides [Hash] + # @return [Hash] + # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/csv/rdoc/CSV.html#Converters + def read_config(config_key, overrides = {}) + reader_config = config[config_key] || {} + + defaults = { + :converters => reader_config.fetch("csv_converters", []).map(&:to_sym), + :headers => reader_config.fetch("headers", true), + :encoding => reader_config.fetch("encoding", config["encoding"]), + } + + defaults.merge(overrides) + end + + def config + @config ||= site.config + end + + # @param row [Array, CSV::Row] + # @return [Array, Hash] + def convert_row(row) + row.instance_of?(CSV::Row) ? row.to_hash : row + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb new file mode 100644 index 00000000..981867b3 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Jekyll + class LayoutReader + attr_reader :site + + def initialize(site) + @site = site + @layouts = {} + end + + def read + layout_entries.each do |layout_file| + @layouts[layout_name(layout_file)] = \ + Layout.new(site, layout_directory, layout_file) + end + + theme_layout_entries.each do |layout_file| + @layouts[layout_name(layout_file)] ||= \ + Layout.new(site, theme_layout_directory, layout_file) + end + + @layouts + end + + def layout_directory + @layout_directory ||= site.in_source_dir(site.config["layouts_dir"]) + end + + def theme_layout_directory + @theme_layout_directory ||= site.theme.layouts_path if site.theme + end + + private + + def layout_entries + entries_in layout_directory + end + + def theme_layout_entries + theme_layout_directory ? entries_in(theme_layout_directory) : [] + end + + def entries_in(dir) + entries = [] + within(dir) do + entries = EntryFilter.new(site).filter(Dir["**/*.*"]) + end + entries + end + + def layout_name(file) + file.split(".")[0..-2].join(".") + end + + def within(directory) + return unless File.exist?(directory) + + Dir.chdir(directory) { yield } + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb new file mode 100644 index 00000000..e72f7676 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class PageReader + attr_reader :site, :dir, :unfiltered_content + + def initialize(site, dir) + @site = site + @dir = dir + @unfiltered_content = [] + end + + # Create a new `Jekyll::Page` object for each entry in a given array. + # + # files - An array of file names inside `@dir` + # + # Returns an array of publishable `Jekyll::Page` objects. + def read(files) + files.each do |page| + @unfiltered_content << Page.new(@site, @site.source, @dir, page) + end + @unfiltered_content.select { |page| site.publisher.publish?(page) } + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb new file mode 100644 index 00000000..25c5f98f --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Jekyll + class PostReader + attr_reader :site, :unfiltered_content + + def initialize(site) + @site = site + end + + # Read all the files in //_drafts and create a new + # Document object with each one. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_drafts(dir) + read_publishable(dir, "_drafts", Document::DATELESS_FILENAME_MATCHER) + end + + # Read all the files in //_posts and create a new Document + # object with each one. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_posts(dir) + read_publishable(dir, "_posts", Document::DATE_FILENAME_MATCHER) + end + + # Read all the files in // and create a new + # Document object with each one insofar as it matches the regexp matcher. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_publishable(dir, magic_dir, matcher) + read_content(dir, magic_dir, matcher) + .tap { |docs| docs.each(&:read) } + .select { |doc| processable?(doc) } + end + + # Read all the content files from //magic_dir + # and return them with the type klass. + # + # dir - The String relative path of the directory to read. + # magic_dir - The String relative directory to , + # looks for content here. + # klass - The return type of the content. + # + # Returns klass type of content files + def read_content(dir, magic_dir, matcher) + @site.reader.get_entries(dir, magic_dir).map do |entry| + next unless matcher.match?(entry) + + path = @site.in_source_dir(File.join(dir, magic_dir, entry)) + Document.new(path, + :site => @site, + :collection => @site.posts) + end.tap(&:compact!) + end + + private + + def processable?(doc) + if doc.content.nil? + Jekyll.logger.debug "Skipping:", "Content in #{doc.relative_path} is nil" + false + elsif !doc.content.valid_encoding? + Jekyll.logger.debug "Skipping:", "#{doc.relative_path} is not valid UTF-8" + false + else + publishable?(doc) + end + end + + def publishable?(doc) + site.publisher.publish?(doc).tap do |will_publish| + if !will_publish && site.publisher.hidden_in_the_future?(doc) + Jekyll.logger.warn "Skipping:", "#{doc.relative_path} has a future date" + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb new file mode 100644 index 00000000..5c8a6775 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class StaticFileReader + attr_reader :site, :dir, :unfiltered_content + + def initialize(site, dir) + @site = site + @dir = dir + @unfiltered_content = [] + end + + # Create a new StaticFile object for every entry in a given list of basenames. + # + # files - an array of file basenames. + # + # Returns an array of static files. + def read(files) + files.each do |file| + @unfiltered_content << StaticFile.new(@site, @site.source, @dir, file) + end + @unfiltered_content + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb new file mode 100644 index 00000000..b20a3a08 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Jekyll + class ThemeAssetsReader + attr_reader :site + + def initialize(site) + @site = site + end + + def read + return unless site.theme&.assets_path + + Find.find(site.theme.assets_path) do |path| + next if File.directory?(path) + + if File.symlink?(path) + Jekyll.logger.warn "Theme reader:", "Ignored symlinked asset: #{path}" + else + read_theme_asset(path) + end + end + end + + private + + def read_theme_asset(path) + base = site.theme.root + dir = File.dirname(path.sub("#{site.theme.root}/", "")) + name = File.basename(path) + + if Utils.has_yaml_header?(path) + append_unless_exists site.pages, + Jekyll::Page.new(site, base, dir, name) + else + append_unless_exists site.static_files, + Jekyll::StaticFile.new(site, base, "/#{dir}", name) + end + end + + def append_unless_exists(haystack, new_item) + if haystack.any? { |file| file.relative_path == new_item.relative_path } + Jekyll.logger.debug "Theme:", + "Ignoring #{new_item.relative_path} in theme due to existing file " \ + "with that path in site." + return + end + + haystack << new_item + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb new file mode 100644 index 00000000..88c6a819 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb @@ -0,0 +1,195 @@ +# frozen_string_literal: true + +module Jekyll + class Regenerator + attr_reader :site, :metadata, :cache + attr_accessor :disabled + private :disabled, :disabled= + + def initialize(site) + @site = site + + # Read metadata from file + read_metadata + + # Initialize cache to an empty hash + clear_cache + end + + # Checks if a renderable object needs to be regenerated + # + # Returns a boolean. + def regenerate?(document) + return true if disabled + + case document + when Page + regenerate_page?(document) + when Document + regenerate_document?(document) + else + source_path = document.respond_to?(:path) ? document.path : nil + dest_path = document.destination(@site.dest) if document.respond_to?(:destination) + source_modified_or_dest_missing?(source_path, dest_path) + end + end + + # Add a path to the metadata + # + # Returns true, also on failure. + def add(path) + return true unless File.exist?(path) + + metadata[path] = { + "mtime" => File.mtime(path), + "deps" => [], + } + cache[path] = true + end + + # Force a path to regenerate + # + # Returns true. + def force(path) + cache[path] = true + end + + # Clear the metadata and cache + # + # Returns nothing + def clear + @metadata = {} + clear_cache + end + + # Clear just the cache + # + # Returns nothing + def clear_cache + @cache = {} + end + + # Checks if the source has been modified or the + # destination is missing + # + # returns a boolean + def source_modified_or_dest_missing?(source_path, dest_path) + modified?(source_path) || (dest_path && !File.exist?(dest_path)) + end + + # Checks if a path's (or one of its dependencies) + # mtime has changed + # + # Returns a boolean. + def modified?(path) + return true if disabled? + + # objects that don't have a path are always regenerated + return true if path.nil? + + # Check for path in cache + return cache[path] if cache.key? path + + if metadata[path] + # If we have seen this file before, + # check if it or one of its dependencies has been modified + existing_file_modified?(path) + else + # If we have not seen this file before, add it to the metadata and regenerate it + add(path) + end + end + + # Add a dependency of a path + # + # Returns nothing. + def add_dependency(path, dependency) + return if metadata[path].nil? || disabled + + unless metadata[path]["deps"].include? dependency + metadata[path]["deps"] << dependency + add(dependency) unless metadata.include?(dependency) + end + regenerate? dependency + end + + # Write the metadata to disk + # + # Returns nothing. + def write_metadata + unless disabled? + Jekyll.logger.debug "Writing Metadata:", ".jekyll-metadata" + File.binwrite(metadata_file, Marshal.dump(metadata)) + end + end + + # Produce the absolute path of the metadata file + # + # Returns the String path of the file. + def metadata_file + @metadata_file ||= site.in_source_dir(".jekyll-metadata") + end + + # Check if metadata has been disabled + # + # Returns a Boolean (true for disabled, false for enabled). + def disabled? + self.disabled = !site.incremental? if disabled.nil? + disabled + end + + private + + # Read metadata from the metadata file, if no file is found, + # initialize with an empty hash + # + # Returns the read metadata. + def read_metadata + @metadata = + if !disabled? && File.file?(metadata_file) + content = File.binread(metadata_file) + + begin + Marshal.load(content) + rescue TypeError + SafeYAML.load(content) + rescue ArgumentError => e + Jekyll.logger.warn("Failed to load #{metadata_file}: #{e}") + {} + end + else + {} + end + end + + def regenerate_page?(document) + document.asset_file? || document.data["regenerate"] || + source_modified_or_dest_missing?( + site.in_source_dir(document.relative_path), document.destination(@site.dest) + ) + end + + def regenerate_document?(document) + !document.write? || document.data["regenerate"] || + source_modified_or_dest_missing?( + document.path, document.destination(@site.dest) + ) + end + + def existing_file_modified?(path) + # If one of this file dependencies have been modified, + # set the regeneration bit for both the dependency and the file to true + metadata[path]["deps"].each do |dependency| + return cache[dependency] = cache[path] = true if modified?(dependency) + end + + if File.exist?(path) && metadata[path]["mtime"].eql?(File.mtime(path)) + # If this file has not been modified, set the regeneration bit to false + cache[path] = false + else + # If it has been modified, set it to true + add(path) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb new file mode 100644 index 00000000..98fc4880 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Jekyll + class RelatedPosts + class << self + attr_accessor :lsi + end + + attr_reader :post, :site + + def initialize(post) + @post = post + @site = post.site + Jekyll::External.require_with_graceful_fail("classifier-reborn") if site.lsi + end + + def build + return [] unless site.posts.docs.size > 1 + + if site.lsi + build_index + lsi_related_posts + else + most_recent_posts + end + end + + def build_index + self.class.lsi ||= begin + lsi = ClassifierReborn::LSI.new(:auto_rebuild => false) + Jekyll.logger.info("Populating LSI...") + + site.posts.docs.each do |x| + lsi.add_item(x) + end + + Jekyll.logger.info("Rebuilding index...") + lsi.build_index + Jekyll.logger.info("") + lsi + end + end + + def lsi_related_posts + self.class.lsi.find_related(post, 11) + end + + def most_recent_posts + @most_recent_posts ||= (site.posts.docs.last(11).reverse! - [post]).first(10) + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/renderer.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/renderer.rb new file mode 100644 index 00000000..c365a0d7 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/renderer.rb @@ -0,0 +1,263 @@ +# frozen_string_literal: true + +module Jekyll + class Renderer + attr_reader :document, :site + attr_writer :layouts, :payload + + def initialize(site, document, site_payload = nil) + @site = site + @document = document + @payload = site_payload + @layouts = nil + end + + # Fetches the payload used in Liquid rendering. + # It can be written with #payload=(new_payload) + # Falls back to site.site_payload if no payload is set. + # + # Returns a Jekyll::Drops::UnifiedPayloadDrop + def payload + @payload ||= site.site_payload + end + + # The list of layouts registered for this Renderer. + # It can be written with #layouts=(new_layouts) + # Falls back to site.layouts if no layouts are registered. + # + # Returns a Hash of String => Jekyll::Layout identified + # as basename without the extension name. + def layouts + @layouts || site.layouts + end + + # Determine which converters to use based on this document's + # extension. + # + # Returns Array of Converter instances. + def converters + @converters ||= site.converters.select { |c| c.matches(document.extname) }.tap(&:sort!) + end + + # Determine the extname the outputted file should have + # + # Returns String the output extname including the leading period. + def output_ext + @output_ext ||= (permalink_ext || converter_output_ext) + end + + # Prepare payload and render the document + # + # Returns String rendered document output + def run + Jekyll.logger.debug "Rendering:", document.relative_path + + assign_pages! + assign_current_document! + assign_highlighter_options! + assign_layout_data! + + Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path + document.trigger_hooks(:pre_render, payload) + + render_document + end + + # Render the document. + # + # Returns String rendered document output + # rubocop: disable Metrics/AbcSize, Metrics/MethodLength + def render_document + info = { + :registers => { :site => site, :page => payload["page"] }, + :strict_filters => liquid_options["strict_filters"], + :strict_variables => liquid_options["strict_variables"], + } + + output = document.content + if document.render_with_liquid? + Jekyll.logger.debug "Rendering Liquid:", document.relative_path + output = render_liquid(output, payload, info, document.path) + end + + Jekyll.logger.debug "Rendering Markup:", document.relative_path + output = convert(output.to_s) + document.content = output + + Jekyll.logger.debug "Post-Convert Hooks:", document.relative_path + document.trigger_hooks(:post_convert) + output = document.content + + if document.place_in_layout? + Jekyll.logger.debug "Rendering Layout:", document.relative_path + output = place_in_layouts(output, payload, info) + end + + output + end + # rubocop: enable Metrics/AbcSize, Metrics/MethodLength + + # Convert the document using the converters which match this renderer's document. + # + # Returns String the converted content. + def convert(content) + converters.reduce(content) do |output, converter| + converter.convert output + rescue StandardError => e + Jekyll.logger.error "Conversion error:", + "#{converter.class} encountered an error while " \ + "converting '#{document.relative_path}':" + Jekyll.logger.error("", e.to_s) + raise e + end + end + + # Render the given content with the payload and info + # + # content - + # payload - + # info - + # path - (optional) the path to the file, for use in ex + # + # Returns String the content, rendered by Liquid. + def render_liquid(content, payload, info, path = nil) + template = site.liquid_renderer.file(path).parse(content) + template.warnings.each do |e| + Jekyll.logger.warn "Liquid Warning:", + LiquidRenderer.format_error(e, path || document.relative_path) + end + template.render!(payload, info) + # rubocop: disable Lint/RescueException + rescue Exception => e + Jekyll.logger.error "Liquid Exception:", + LiquidRenderer.format_error(e, path || document.relative_path) + raise e + end + # rubocop: enable Lint/RescueException + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # + # Returns Boolean true if the layout is invalid, false if otherwise + def invalid_layout?(layout) + !document.data["layout"].nil? && layout.nil? && !(document.is_a? Jekyll::Excerpt) + end + + # Render layouts and place document content inside. + # + # Returns String rendered content + def place_in_layouts(content, payload, info) + output = content.dup + layout = layouts[document.data["layout"].to_s] + validate_layout(layout) + + used = Set.new([layout]) + + # Reset the payload layout data to ensure it starts fresh for each page. + payload["layout"] = nil + + while layout + output = render_layout(output, layout, info) + add_regenerator_dependencies(layout) + + next unless (layout = site.layouts[layout.data["layout"]]) + break if used.include?(layout) + + used << layout + end + output + end + + private + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # Returns nothing + def validate_layout(layout) + return unless invalid_layout?(layout) + + Jekyll.logger.warn "Build Warning:", "Layout '#{document.data["layout"]}' requested " \ + "in #{document.relative_path} does not exist." + end + + # Render layout content into document.output + # + # Returns String rendered content + def render_layout(output, layout, info) + payload["content"] = output + payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) + + render_liquid( + layout.content, + payload, + info, + layout.path + ) + end + + def add_regenerator_dependencies(layout) + return unless document.write? + + site.regenerator.add_dependency( + site.in_source_dir(document.path), + layout.path + ) + end + + # Set page content to payload and assign pager if document has one. + # + # Returns nothing + def assign_pages! + payload["page"] = document.to_liquid + payload["paginator"] = (document.pager.to_liquid if document.respond_to?(:pager)) + end + + # Set related posts to payload if document is a post. + # + # Returns nothing + def assign_current_document! + payload["site"].current_document = document + end + + # Set highlighter prefix and suffix + # + # Returns nothing + def assign_highlighter_options! + payload["highlighter_prefix"] = converters.first.highlighter_prefix + payload["highlighter_suffix"] = converters.first.highlighter_suffix + end + + def assign_layout_data! + layout = layouts[document.data["layout"]] + payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) if layout + end + + def permalink_ext + document_permalink = document.permalink + if document_permalink && !document_permalink.end_with?("/") + permalink_ext = File.extname(document_permalink) + permalink_ext unless permalink_ext.empty? + end + end + + def converter_output_ext + if output_exts.size == 1 + output_exts.last + else + output_exts[-2] + end + end + + def output_exts + @output_exts ||= converters.map do |c| + c.output_ext(document.extname) + end.tap(&:compact!) + end + + def liquid_options + @liquid_options ||= site.config["liquid"] + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/site.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/site.rb new file mode 100644 index 00000000..adec4cc0 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/site.rb @@ -0,0 +1,576 @@ +# frozen_string_literal: true + +module Jekyll + class Site + attr_accessor :baseurl, :converters, :data, :drafts, :exclude, + :file_read_opts, :future, :gems, :generators, :highlighter, + :include, :inclusions, :keep_files, :layouts, :limit_posts, + :lsi, :pages, :permalink_style, :plugin_manager, :plugins, + :reader, :safe, :show_drafts, :static_files, :theme, :time, + :unpublished + + attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths, + :liquid_renderer, :profiler, :regenerator, :source + + # Public: Initialize a new Site. + # + # config - A Hash containing site configuration details. + def initialize(config) + # Source and destination may not be changed after the site has been created. + @source = File.expand_path(config["source"]).freeze + @dest = File.expand_path(config["destination"]).freeze + + self.config = config + + @cache_dir = in_source_dir(config["cache_dir"]) + @filter_cache = {} + + @reader = Reader.new(self) + @profiler = Profiler.new(self) + @regenerator = Regenerator.new(self) + @liquid_renderer = LiquidRenderer.new(self) + + Jekyll.sites << self + + reset + setup + + Jekyll::Hooks.trigger :site, :after_init, self + end + + # Public: Set the site's configuration. This handles side-effects caused by + # changing values in the configuration. + # + # config - a Jekyll::Configuration, containing the new configuration. + # + # Returns the new configuration. + def config=(config) + @config = config.clone + + %w(safe lsi highlighter baseurl exclude include future unpublished + show_drafts limit_posts keep_files).each do |opt| + send(:"#{opt}=", config[opt]) + end + + # keep using `gems` to avoid breaking change + self.gems = config["plugins"] + + configure_cache + configure_plugins + configure_theme + configure_include_paths + configure_file_read_opts + + self.permalink_style = config["permalink"].to_sym + + # Read in a _config.yml from the current theme-gem at the very end. + @config = load_theme_configuration(config) if theme + @config + end + + # Public: Read, process, and write this Site to output. + # + # Returns nothing. + def process + return profiler.profile_process if config["profile"] + + reset + read + generate + render + cleanup + write + end + + def print_stats + Jekyll.logger.info @liquid_renderer.stats_table + end + + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength + # + # Reset Site details. + # + # Returns nothing + def reset + self.time = if config["time"] + Utils.parse_date(config["time"].to_s, "Invalid time in _config.yml.") + else + Time.now + end + self.layouts = {} + self.inclusions = {} + self.pages = [] + self.static_files = [] + self.data = {} + @post_attr_hash = {} + @site_data = nil + @collections = nil + @documents = nil + @docs_to_write = nil + @regenerator.clear_cache + @liquid_renderer.reset + @site_cleaner = nil + frontmatter_defaults.reset + + raise ArgumentError, "limit_posts must be a non-negative number" if limit_posts.negative? + + Jekyll::Cache.clear_if_config_changed config + Jekyll::Hooks.trigger :site, :after_reset, self + nil + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/AbcSize + + # Load necessary libraries, plugins, converters, and generators. + # + # Returns nothing. + def setup + ensure_not_in_dest + + plugin_manager.conscientious_require + + self.converters = instantiate_subclasses(Jekyll::Converter) + self.generators = instantiate_subclasses(Jekyll::Generator) + end + + # Check that the destination dir isn't the source dir or a directory + # parent to the source dir. + def ensure_not_in_dest + dest_pathname = Pathname.new(dest) + Pathname.new(source).ascend do |path| + if path == dest_pathname + raise Errors::FatalException, + "Destination directory cannot be or contain the Source directory." + end + end + end + + # The list of collections and their corresponding Jekyll::Collection instances. + # If config['collections'] is set, a new instance is created + # for each item in the collection, a new hash is returned otherwise. + # + # Returns a Hash containing collection name-to-instance pairs. + def collections + @collections ||= collection_names.each_with_object({}) do |name, hsh| + hsh[name] = Jekyll::Collection.new(self, name) + end + end + + # The list of collection names. + # + # Returns an array of collection names from the configuration, + # or an empty array if the `collections` key is not set. + def collection_names + case config["collections"] + when Hash + config["collections"].keys + when Array + config["collections"] + when nil + [] + else + raise ArgumentError, "Your `collections` key must be a hash or an array." + end + end + + # Read Site data from disk and load it into internal data structures. + # + # Returns nothing. + def read + reader.read + limit_posts! + Jekyll::Hooks.trigger :site, :post_read, self + nil + end + + # Run each of the Generators. + # + # Returns nothing. + def generate + generators.each do |generator| + start = Time.now + generator.generate(self) + Jekyll.logger.debug "Generating:", + "#{generator.class} finished in #{Time.now - start} seconds." + end + nil + end + + # Render the site to the destination. + # + # Returns nothing. + def render + relative_permalinks_are_deprecated + + payload = site_payload + + Jekyll::Hooks.trigger :site, :pre_render, self, payload + + render_docs(payload) + render_pages(payload) + + Jekyll::Hooks.trigger :site, :post_render, self, payload + nil + end + + # Remove orphaned files and empty directories in destination. + # + # Returns nothing. + def cleanup + site_cleaner.cleanup! + nil + end + + # Write static files, pages, and posts. + # + # Returns nothing. + def write + Jekyll::Commands::Doctor.conflicting_urls(self) + each_site_file do |item| + item.write(dest) if regenerator.regenerate?(item) + end + regenerator.write_metadata + Jekyll::Hooks.trigger :site, :post_write, self + nil + end + + def posts + collections["posts"] ||= Collection.new(self, "posts") + end + + # Construct a Hash of Posts indexed by the specified Post attribute. + # + # post_attr - The String name of the Post attribute. + # + # Examples + # + # post_attr_hash('categories') + # # => { 'tech' => [, ], + # # 'ruby' => [] } + # + # Returns the Hash: { attr => posts } where + # attr - One of the values for the requested attribute. + # posts - The Array of Posts with the given attr value. + def post_attr_hash(post_attr) + # Build a hash map based on the specified post attribute ( post attr => + # array of posts ) then sort each array in reverse order. + @post_attr_hash[post_attr] ||= begin + hash = Hash.new { |h, key| h[key] = [] } + posts.docs.each do |p| + p.data[post_attr]&.each { |t| hash[t] << p } + end + hash.each_value { |posts| posts.sort!.reverse! } + hash + end + end + + def tags + post_attr_hash("tags") + end + + def categories + post_attr_hash("categories") + end + + # Prepare site data for site payload. The method maintains backward compatibility + # if the key 'data' is already used in _config.yml. + # + # Returns the Hash to be hooked to site.data. + def site_data + @site_data ||= (config["data"] || data) + end + + # The Hash payload containing site-wide data. + # + # Returns the Hash: { "site" => data } where data is a Hash with keys: + # "time" - The Time as specified in the configuration or the + # current time if none was specified. + # "posts" - The Array of Posts, sorted chronologically by post date + # and then title. + # "pages" - The Array of all Pages. + # "html_pages" - The Array of HTML Pages. + # "categories" - The Hash of category values and Posts. + # See Site#post_attr_hash for type info. + # "tags" - The Hash of tag values and Posts. + # See Site#post_attr_hash for type info. + def site_payload + Drops::UnifiedPayloadDrop.new self + end + alias_method :to_liquid, :site_payload + + # Get the implementation class for the given Converter. + # Returns the Converter instance implementing the given Converter. + # klass - The Class of the Converter to fetch. + def find_converter_instance(klass) + @find_converter_instance ||= {} + @find_converter_instance[klass] ||= converters.find do |converter| + converter.instance_of?(klass) + end || \ + raise("No Converters found for #{klass}") + end + + # klass - class or module containing the subclasses. + # Returns array of instances of subclasses of parameter. + # Create array of instances of the subclasses of the class or module + # passed in as argument. + + def instantiate_subclasses(klass) + klass.descendants.select { |c| !safe || c.safe }.tap do |result| + result.sort! + result.map! { |c| c.new(config) } + end + end + + # Warns the user if permanent links are relative to the parent + # directory. As this is a deprecated function of Jekyll. + # + # Returns + def relative_permalinks_are_deprecated + if config["relative_permalinks"] + Jekyll.logger.abort_with "Since v3.0, permalinks for pages " \ + "in subfolders must be relative to the " \ + "site source directory, not the parent " \ + "directory. Check https://jekyllrb.com/docs/upgrading/ " \ + "for more info." + end + end + + # Get the to be written documents + # + # Returns an Array of Documents which should be written + def docs_to_write + documents.select(&:write?) + end + + # Get the to be written static files + # + # Returns an Array of StaticFiles which should be written + def static_files_to_write + static_files.select(&:write?) + end + + # Get all the documents + # + # Returns an Array of all Documents + def documents + collections.each_with_object(Set.new) do |(_, collection), set| + set.merge(collection.docs).merge(collection.files) + end.to_a + end + + def each_site_file + pages.each { |page| yield page } + static_files.each { |file| yield(file) if file.write? } + collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } } + end + + # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults + # if it doesn't already exist. + # + # Returns The FrontmatterDefaults + def frontmatter_defaults + @frontmatter_defaults ||= FrontmatterDefaults.new(self) + end + + # Whether to perform a full rebuild without incremental regeneration + # + # Returns a Boolean: true for a full rebuild, false for normal build + def incremental?(override = {}) + override["incremental"] || config["incremental"] + end + + # Returns the publisher or creates a new publisher if it doesn't + # already exist. + # + # Returns The Publisher + def publisher + @publisher ||= Publisher.new(self) + end + + # Public: Prefix a given path with the source directory. + # + # paths - (optional) path elements to a file or directory within the + # source directory + # + # Returns a path which is prefixed with the source directory. + def in_source_dir(*paths) + paths.reduce(source) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the theme directory. + # + # paths - (optional) path elements to a file or directory within the + # theme directory + # + # Returns a path which is prefixed with the theme root directory. + def in_theme_dir(*paths) + return nil unless theme + + paths.reduce(theme.root) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the destination directory. + # + # paths - (optional) path elements to a file or directory within the + # destination directory + # + # Returns a path which is prefixed with the destination directory. + def in_dest_dir(*paths) + paths.reduce(dest) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the cache directory. + # + # paths - (optional) path elements to a file or directory within the + # cache directory + # + # Returns a path which is prefixed with the cache directory. + def in_cache_dir(*paths) + paths.reduce(cache_dir) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: The full path to the directory that houses all the collections registered + # with the current site. + # + # Returns the source directory or the absolute path to the custom collections_dir + def collections_path + dir_str = config["collections_dir"] + @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str) + end + + # Public + # + # Returns the object as a debug String. + def inspect + "#<#{self.class} @source=#{@source}>" + end + + private + + def load_theme_configuration(config) + return config if config["ignore_theme_config"] == true + + theme_config_file = in_theme_dir("_config.yml") + return config unless File.exist?(theme_config_file) + + # Bail out if the theme_config_file is a symlink file irrespective of safe mode + return config if File.symlink?(theme_config_file) + + theme_config = SafeYAML.load_file(theme_config_file) + return config unless theme_config.is_a?(Hash) + + Jekyll.logger.info "Theme Config file:", theme_config_file + + # theme_config should not be overriding Jekyll's defaults + theme_config.delete_if { |key, _| Configuration::DEFAULTS.key?(key) } + + # Override theme_config with existing config and return the result. + # Additionally ensure we return a `Jekyll::Configuration` instance instead of a Hash. + Utils.deep_merge_hashes(theme_config, config) + .each_with_object(Jekyll::Configuration.new) do |(key, value), conf| + conf[key] = value + end + end + + # Limits the current posts; removes the posts which exceed the limit_posts + # + # Returns nothing + def limit_posts! + if limit_posts.positive? + limit = [posts.docs.length, limit_posts].min + posts.docs = posts.docs[-limit, limit] + end + end + + # Returns the Cleaner or creates a new Cleaner if it doesn't + # already exist. + # + # Returns The Cleaner + def site_cleaner + @site_cleaner ||= Cleaner.new(self) + end + + def hide_cache_dir_from_git + @cache_gitignore_path ||= in_source_dir(config["cache_dir"], ".gitignore") + return if File.exist?(@cache_gitignore_path) + + cache_dir_path = in_source_dir(config["cache_dir"]) + FileUtils.mkdir_p(cache_dir_path) unless File.directory?(cache_dir_path) + + File.open(@cache_gitignore_path, "wb") do |file| + file.puts("# ignore everything in this directory\n*") + end + end + + # Disable Marshaling cache to disk in Safe Mode + def configure_cache + Jekyll::Cache.cache_dir = in_source_dir(config["cache_dir"], "Jekyll/Cache") + if safe || config["disable_disk_cache"] + Jekyll::Cache.disable_disk_cache! + else + hide_cache_dir_from_git + end + end + + def configure_plugins + self.plugin_manager = Jekyll::PluginManager.new(self) + self.plugins = plugin_manager.plugins_path + end + + def configure_theme + self.theme = nil + return if config["theme"].nil? + + self.theme = + if config["theme"].is_a?(String) + Jekyll::Theme.new(config["theme"]) + else + Jekyll.logger.warn "Theme:", "value of 'theme' in config should be String to use " \ + "gem-based themes, but got #{config["theme"].class}" + nil + end + end + + def configure_include_paths + @includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s)) + @includes_load_paths << theme.includes_path if theme&.includes_path + end + + def configure_file_read_opts + self.file_read_opts = {} + file_read_opts[:encoding] = config["encoding"] if config["encoding"] + self.file_read_opts = Jekyll::Utils.merged_file_read_opts(self, {}) + end + + def render_docs(payload) + collections.each_value do |collection| + collection.docs.each do |document| + render_regenerated(document, payload) + end + end + end + + def render_pages(payload) + pages.each do |page| + render_regenerated(page, payload) + end + end + + def render_regenerated(document, payload) + return unless regenerator.regenerate?(document) + + document.renderer.payload = payload + document.output = document.renderer.run + document.trigger_hooks(:post_render) + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/static_file.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/static_file.rb new file mode 100644 index 00000000..13479b0d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/static_file.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +module Jekyll + class StaticFile + extend Forwardable + + attr_reader :relative_path, :extname, + :type, # Returns the type of the collection if present, nil otherwise. + :name + + def_delegator :to_liquid, :to_json, :to_json + + class << self + # The cache of last modification times [path] -> mtime. + def mtimes + @mtimes ||= {} + end + + def reset_cache + @mtimes = nil + end + end + + # Initialize a new StaticFile. + # + # site - The Site. + # base - The String path to the . + # dir - The String path between and the file. + # name - The String filename of the file. + # rubocop: disable Metrics/ParameterLists + def initialize(site, base, dir, name, collection = nil) + @site = site + @base = base + @dir = dir + @name = name + @collection = collection + @relative_path = File.join(*[@dir, @name].compact) + @extname = File.extname(@name) + @type = @collection&.label&.to_sym + end + # rubocop: enable Metrics/ParameterLists + + # Returns source file path. + def path + @path ||= if !@collection.nil? && !@site.config["collections_dir"].empty? + File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact) + else + File.join(*[@base, @dir, @name].compact) + end + end + + # Obtain destination path. + # + # dest - The String path to the destination dir. + # + # Returns destination file path. + def destination(dest) + @destination ||= {} + @destination[dest] ||= @site.in_dest_dir(dest, Jekyll::URL.unescape_path(url)) + end + + def destination_rel_dir + if @collection + File.dirname(url) + else + @dir + end + end + + def modified_time + @modified_time ||= File.stat(path).mtime + end + + # Returns last modification time for this file. + def mtime + modified_time.to_i + end + + # Is source path modified? + # + # Returns true if modified since last write. + def modified? + self.class.mtimes[path] != mtime + end + + # Whether to write the file to the filesystem + # + # Returns true unless the defaults for the destination path from + # _config.yml contain `published: false`. + def write? + publishable = defaults.fetch("published", true) + return publishable unless @collection + + publishable && @collection.write? + end + + # Write the static file to the destination directory (if modified). + # + # dest - The String path to the destination dir. + # + # Returns false if the file was not modified since last time (no-op). + def write(dest) + dest_path = destination(dest) + return false if File.exist?(dest_path) && !modified? + + self.class.mtimes[path] = mtime + + FileUtils.mkdir_p(File.dirname(dest_path)) + FileUtils.rm(dest_path) if File.exist?(dest_path) + copy_file(dest_path) + + true + end + + def data + @data ||= @site.frontmatter_defaults.all(relative_path, type) + end + + def to_liquid + @to_liquid ||= Drops::StaticFileDrop.new(self) + end + + # Generate "basename without extension" and strip away any trailing periods. + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + def basename + @basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "") + end + + def placeholders + { + :collection => @collection.label, + :path => cleaned_relative_path, + :output_ext => "", + :name => basename, + :title => "", + } + end + + # Similar to Jekyll::Document#cleaned_relative_path. + # Generates a relative path with the collection's directory removed when applicable + # and additionally removes any multiple periods in the string. + # + # NOTE: `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`) + # + # Examples: + # When `relative_path` is "_methods/site/my-cool-avatar...png": + # cleaned_relative_path + # # => "/site/my-cool-avatar" + # + # Returns the cleaned relative path of the static file. + def cleaned_relative_path + @cleaned_relative_path ||= begin + cleaned = relative_path[0..-extname.length - 1] + cleaned.gsub!(%r!\.*\z!, "") + cleaned.sub!(@collection.relative_directory, "") if @collection + cleaned + end + end + + # Applies a similar URL-building technique as Jekyll::Document that takes + # the collection's URL template into account. The default URL template can + # be overridden in the collection's configuration in _config.yml. + def url + @url ||= begin + base = if @collection.nil? + cleaned_relative_path + else + Jekyll::URL.new( + :template => @collection.url_template, + :placeholders => placeholders + ) + end.to_s.chomp("/") + base << extname + end + end + + # Returns the front matter defaults defined for the file's URL and/or type + # as defined in _config.yml. + def defaults + @defaults ||= @site.frontmatter_defaults.all url, type + end + + # Returns a debug string on inspecting the static file. + # Includes only the relative path of the object. + def inspect + "#<#{self.class} @relative_path=#{relative_path.inspect}>" + end + + private + + def copy_file(dest_path) + if @site.safe || Jekyll.env == "production" + FileUtils.cp(path, dest_path) + else + FileUtils.copy_entry(path, dest_path) + end + + unless File.symlink?(dest_path) + File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path) + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb new file mode 100644 index 00000000..10e5a0b2 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Jekyll + class Stevenson < ::Logger + def initialize + formatter = proc do |_, _, _, msg| + msg.to_s + end + super($stdout, :formatter => formatter) + end + + def add(severity, message = nil, progname = nil) + severity ||= UNKNOWN + @logdev = logdevice(severity) + + return true if @logdev.nil? || severity < @level + + progname ||= @progname + if message.nil? + if block_given? + message = yield + else + message = progname + progname = @progname + end + end + @logdev.puts( + format_message(format_severity(severity), Time.now, progname, message) + ) + true + end + + # Log a +WARN+ message + def warn(progname = nil, &block) + add(WARN, nil, progname.yellow, &block) + end + + # Log an +ERROR+ message + def error(progname = nil, &block) + add(ERROR, nil, progname.red, &block) + end + + def close + # No LogDevice in use + end + + private + + def logdevice(severity) + if severity > INFO + $stderr + else + $stdout + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb new file mode 100644 index 00000000..fcea81ff --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class HighlightBlock < Liquid::Block + include Liquid::StandardFilters + + # The regular expression syntax checker. Start with the language specifier. + # Follow that by zero or more space separated options that take one of three + # forms: name, name=value, or name="" + # + # is a space-separated list of numbers + SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!.freeze + + def initialize(tag_name, markup, tokens) + super + if markup.strip =~ SYNTAX + @lang = Regexp.last_match(1).downcase + @highlight_options = parse_options(Regexp.last_match(2)) + else + raise SyntaxError, <<~MSG + Syntax Error in tag 'highlight' while parsing the following markup: + + #{markup} + + Valid syntax: highlight [linenos] [mark_lines="3 4 5"] + + See https://jekyllrb.com/docs/liquid/tags/#code-snippet-highlighting for more details. + MSG + end + end + + LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!.freeze + + def render(context) + prefix = context["highlighter_prefix"] || "" + suffix = context["highlighter_suffix"] || "" + code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, "") + + output = + case context.registers[:site].highlighter + when "rouge" + render_rouge(code) + when "pygments" + render_pygments(code, context) + else + render_codehighlighter(code) + end + + rendered_output = add_code_tag(output) + prefix + rendered_output + suffix + end + + private + + OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)+!.freeze + + def parse_options(input) + options = {} + return options if input.empty? + + # Split along 3 possible forms -- key="", key=value, or key + input.scan(OPTIONS_REGEX) do |opt| + key, value = opt.split("=") + # If a quoted list, convert to array + if value&.include?('"') + value.delete!('"') + value = value.split + end + options[key.to_sym] = value || true + end + + options[:linenos] = "inline" if options[:linenos] == true + options + end + + def render_pygments(code, _context) + Jekyll.logger.warn "Warning:", "Highlight Tag no longer supports rendering with Pygments." + Jekyll.logger.warn "", "Using the default highlighter, Rouge, instead." + render_rouge(code) + end + + def render_rouge(code) + require "rouge" + formatter = Rouge::Formatters::HTML.new + formatter = line_highlighter_formatter(formatter) if @highlight_options[:mark_lines] + formatter = table_formatter(formatter) if @highlight_options[:linenos] + + lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText + formatter.format(lexer.lex(code)) + end + + def line_highlighter_formatter(formatter) + Rouge::Formatters::HTMLLineHighlighter.new( + formatter, + :highlight_lines => mark_lines + ) + end + + def mark_lines + value = @highlight_options[:mark_lines] + return value.map(&:to_i) if value.is_a?(Array) + + raise SyntaxError, "Syntax Error for mark_lines declaration. Expected a " \ + "double-quoted list of integers." + end + + def table_formatter(formatter) + Rouge::Formatters::HTMLTable.new( + formatter, + :css_class => "highlight", + :gutter_class => "gutter", + :code_class => "code" + ) + end + + def render_codehighlighter(code) + h(code).strip + end + + def add_code_tag(code) + code_attrs = %(class="language-#{@lang.tr("+", "-")}" data-lang="#{@lang}") + %(
#{code.chomp}
) + end + end + end +end + +Liquid::Template.register_tag("highlight", Jekyll::Tags::HighlightBlock) diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb new file mode 100644 index 00000000..6960952e --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb @@ -0,0 +1,275 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class IncludeTag < Liquid::Tag + VALID_SYNTAX = %r! + ([\w-]+)\s*=\s* + (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w.-]+)) + !x.freeze + VARIABLE_SYNTAX = %r! + (?[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)+) + (?.*) + !mx.freeze + + FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze + VALID_FILENAME_CHARS = %r!^[\w/.\-()+~\#@]+$!.freeze + INVALID_SEQUENCES = %r![./]{2,}!.freeze + + def initialize(tag_name, markup, tokens) + super + markup = markup.strip + matched = markup.match(VARIABLE_SYNTAX) + if matched + @file = matched["variable"].strip + @params = matched["params"].strip + else + @file, @params = markup.split(%r!\s+!, 2) + end + validate_params if @params + @tag_name = tag_name + end + + def syntax_example + "{% #{@tag_name} file.ext param='value' param2='value' %}" + end + + def parse_params(context) + params = {} + @params.scan(VALID_SYNTAX) do |key, d_quoted, s_quoted, variable| + value = if d_quoted + d_quoted.include?('\\"') ? d_quoted.gsub('\\"', '"') : d_quoted + elsif s_quoted + s_quoted.include?("\\'") ? s_quoted.gsub("\\'", "'") : s_quoted + elsif variable + context[variable] + end + + params[key] = value + end + params + end + + def validate_file_name(file) + if INVALID_SEQUENCES.match?(file) || !VALID_FILENAME_CHARS.match?(file) + raise ArgumentError, <<~MSG + Invalid syntax for include tag. File contains invalid characters or sequences: + + #{file} + + Valid syntax: + + #{syntax_example} + + MSG + end + end + + def validate_params + unless FULL_VALID_SYNTAX.match?(@params) + raise ArgumentError, <<~MSG + Invalid syntax for include tag: + + #{@params} + + Valid syntax: + + #{syntax_example} + + MSG + end + end + + # Grab file read opts in the context + def file_read_opts(context) + context.registers[:site].file_read_opts + end + + # Render the variable if required + def render_variable(context) + Liquid::Template.parse(@file).render(context) if VARIABLE_SYNTAX.match?(@file) + end + + def tag_includes_dirs(context) + context.registers[:site].includes_load_paths.freeze + end + + def locate_include_file(context, file, safe) + includes_dirs = tag_includes_dirs(context) + includes_dirs.each do |dir| + path = PathManager.join(dir, file) + return path if valid_include_file?(path, dir.to_s, safe) + end + raise IOError, could_not_locate_message(file, includes_dirs, safe) + end + + def render(context) + site = context.registers[:site] + + file = render_variable(context) || @file + validate_file_name(file) + + path = locate_include_file(context, file, site.safe) + return unless path + + add_include_to_dependency(site, path, context) + + partial = load_cached_partial(path, context) + + context.stack do + context["include"] = parse_params(context) if @params + begin + partial.render!(context) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + end + end + + def add_include_to_dependency(site, path, context) + if context.registers[:page]&.key?("path") + site.regenerator.add_dependency( + site.in_source_dir(context.registers[:page]["path"]), + path + ) + end + end + + def load_cached_partial(path, context) + context.registers[:cached_partials] ||= {} + cached_partial = context.registers[:cached_partials] + + if cached_partial.key?(path) + cached_partial[path] + else + unparsed_file = context.registers[:site] + .liquid_renderer + .file(path) + begin + cached_partial[path] = unparsed_file.parse(read_file(path, context)) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + end + end + + def valid_include_file?(path, dir, safe) + !outside_site_source?(path, dir, safe) && File.file?(path) + end + + def outside_site_source?(path, dir, safe) + safe && !realpath_prefixed_with?(path, dir) + end + + def realpath_prefixed_with?(path, dir) + File.exist?(path) && File.realpath(path).start_with?(dir) + rescue StandardError + false + end + + # This method allows to modify the file content by inheriting from the class. + def read_file(file, context) + File.read(file, **file_read_opts(context)) + end + + private + + def could_not_locate_message(file, includes_dirs, safe) + message = "Could not locate the included file '#{file}' in any of #{includes_dirs}. " \ + "Ensure it exists in one of those directories and" + message + if safe + " is not a symlink as those are not allowed in safe mode." + else + ", if it is a symlink, does not point outside your site source." + end + end + end + + # Do not inherit from this class. + # TODO: Merge into the `Jekyll::Tags::IncludeTag` in v5.0 + class OptimizedIncludeTag < IncludeTag + def render(context) + @site ||= context.registers[:site] + + file = render_variable(context) || @file + validate_file_name(file) + + @site.inclusions[file] ||= locate_include_file(file) + inclusion = @site.inclusions[file] + + add_include_to_dependency(inclusion, context) if @site.config["incremental"] + + context.stack do + context["include"] = parse_params(context) if @params + inclusion.render(context) + end + end + + private + + def locate_include_file(file) + @site.includes_load_paths.each do |dir| + path = PathManager.join(dir, file) + return Inclusion.new(@site, dir, file) if valid_include_file?(path, dir) + end + raise IOError, could_not_locate_message(file, @site.includes_load_paths, @site.safe) + end + + def valid_include_file?(path, dir) + File.file?(path) && !outside_scope?(path, dir) + end + + def outside_scope?(path, dir) + @site.safe && !realpath_prefixed_with?(path, dir) + end + + def realpath_prefixed_with?(path, dir) + File.realpath(path).start_with?(dir) + rescue StandardError + false + end + + def add_include_to_dependency(inclusion, context) + page = context.registers[:page] + return unless page&.key?("path") + + absolute_path = \ + if page["collection"] + @site.in_source_dir(@site.config["collections_dir"], page["path"]) + else + @site.in_source_dir(page["path"]) + end + + @site.regenerator.add_dependency(absolute_path, inclusion.path) + end + end + + class IncludeRelativeTag < IncludeTag + def tag_includes_dirs(context) + Array(page_path(context)).freeze + end + + def page_path(context) + page, site = context.registers.values_at(:page, :site) + return site.source unless page + + site.in_source_dir File.dirname(resource_path(page, site)) + end + + private + + def resource_path(page, site) + path = page["path"] + path = File.join(site.config["collections_dir"], path) if page["collection"] + path.delete_suffix("/#excerpt") + end + end + end +end + +Liquid::Template.register_tag("include", Jekyll::Tags::OptimizedIncludeTag) +Liquid::Template.register_tag("include_relative", Jekyll::Tags::IncludeRelativeTag) diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb new file mode 100644 index 00000000..c986b5a9 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class Link < Liquid::Tag + include Jekyll::Filters::URLFilters + + class << self + def tag_name + name.split("::").last.downcase + end + end + + def initialize(tag_name, relative_path, tokens) + super + + @relative_path = relative_path.strip + end + + def render(context) + @context = context + site = context.registers[:site] + relative_path = Liquid::Template.parse(@relative_path).render(context) + relative_path_with_leading_slash = PathManager.join("", relative_path) + + site.each_site_file do |item| + return relative_url(item) if item.relative_path == relative_path + # This takes care of the case for static files that have a leading / + return relative_url(item) if item.relative_path == relative_path_with_leading_slash + end + + raise ArgumentError, <<~MSG + Could not find document '#{relative_path}' in tag '#{self.class.tag_name}'. + + Make sure the document exists and the path is correct. + MSG + end + end + end +end + +Liquid::Template.register_tag(Jekyll::Tags::Link.tag_name, Jekyll::Tags::Link) diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb new file mode 100644 index 00000000..7774d377 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class PostComparer + MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze + + attr_reader :path, :date, :slug, :name + + def initialize(name) + @name = name + + all, @path, @date, @slug = *name.sub(%r!^/!, "").match(MATCHER) + unless all + raise Jekyll::Errors::InvalidPostNameError, + "'#{name}' does not contain valid date and/or title." + end + + basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+" + @name_regex = %r!^_posts/#{path}#{basename_pattern}|^#{path}_posts/?#{basename_pattern}! + end + + def post_date + @post_date ||= Utils.parse_date( + date, + "'#{date}' does not contain valid date and/or title." + ) + end + + def ==(other) + other.relative_path.match(@name_regex) + end + + def deprecated_equality(other) + slug == post_slug(other) && + post_date.year == other.date.year && + post_date.month == other.date.month && + post_date.day == other.date.day + end + + private + + # Construct the directory-aware post slug for a Jekyll::Post + # + # other - the Jekyll::Post + # + # Returns the post slug with the subdirectory (relative to _posts) + def post_slug(other) + path = other.basename.split("/")[0...-1].join("/") + if path.nil? || path == "" + other.data["slug"] + else + "#{path}/#{other.data["slug"]}" + end + end + end + + class PostUrl < Liquid::Tag + include Jekyll::Filters::URLFilters + + def initialize(tag_name, post, tokens) + super + @orig_post = post.strip + begin + @post = PostComparer.new(@orig_post) + rescue StandardError => e + raise Jekyll::Errors::PostURLError, <<~MSG + Could not parse name of post "#{@orig_post}" in tag 'post_url'. + Make sure the post exists and the name is correct. + #{e.class}: #{e.message} + MSG + end + end + + def render(context) + @context = context + site = context.registers[:site] + + site.posts.docs.each do |document| + return relative_url(document) if @post == document + end + + # New matching method did not match, fall back to old method + # with deprecation warning if this matches + + site.posts.docs.each do |document| + next unless @post.deprecated_equality document + + Jekyll::Deprecator.deprecation_message( + "A call to '{% post_url #{@post.name} %}' did not match a post using the new " \ + "matching method of checking name (path-date-slug) equality. Please make sure " \ + "that you change this tag to match the post's name exactly." + ) + return relative_url(document) + end + + raise Jekyll::Errors::PostURLError, <<~MSG + Could not find post "#{@orig_post}" in tag 'post_url'. + Make sure the post exists and the name is correct. + MSG + end + end + end +end + +Liquid::Template.register_tag("post_url", Jekyll::Tags::PostUrl) diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/theme.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/theme.rb new file mode 100644 index 00000000..a3f2a94d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/theme.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module Jekyll + class Theme + extend Forwardable + attr_reader :name + + def_delegator :gemspec, :version, :version + + def initialize(name) + @name = name.downcase.strip + Jekyll.logger.debug "Theme:", name + Jekyll.logger.debug "Theme source:", root + end + + def root + # Must use File.realpath to resolve symlinks created by rbenv + # Otherwise, Jekyll.sanitized path with prepend the unresolved root + @root ||= File.realpath(gemspec.full_gem_path) + rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP + raise "Path #{gemspec.full_gem_path} does not exist, is not accessible or includes " \ + "a symbolic link loop" + end + + # The name of theme directory + def basename + @basename ||= File.basename(root) + end + + def includes_path + @includes_path ||= path_for "_includes" + end + + def layouts_path + @layouts_path ||= path_for "_layouts" + end + + def sass_path + @sass_path ||= path_for "_sass" + end + + def assets_path + @assets_path ||= path_for "assets" + end + + def data_path + @data_path ||= path_for "_data" + end + + def runtime_dependencies + gemspec.runtime_dependencies + end + + private + + def path_for(folder) + path = realpath_for(folder) + path if path && File.directory?(path) + end + + def realpath_for(folder) + # This resolves all symlinks for the theme subfolder and then ensures that the directory + # remains inside the theme root. This prevents the use of symlinks for theme subfolders to + # escape the theme root. + # However, symlinks are allowed to point to other directories within the theme. + Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s))) + rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e + log_realpath_exception(e, folder) + nil + end + + def log_realpath_exception(err, folder) + return if err.is_a?(Errno::ENOENT) + + case err + when Errno::EACCES + Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible." + when Errno::ELOOP + Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop." + end + end + + def gemspec + @gemspec ||= Gem::Specification.find_by_name(name) + rescue Gem::LoadError + raise Jekyll::Errors::MissingDependencyException, + "The #{name} theme could not be found." + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb new file mode 100644 index 00000000..b03abbf4 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +module Jekyll + class ThemeBuilder + SCAFFOLD_DIRECTORIES = %w( + assets _data _layouts _includes _sass + ).freeze + + attr_reader :name, :path, :code_of_conduct + + def initialize(theme_name, opts) + @name = theme_name.to_s.tr(" ", "_").squeeze("_") + @path = Pathname.new(File.expand_path(name, Dir.pwd)) + @code_of_conduct = !!opts["code_of_conduct"] + end + + def create! + create_directories + create_starter_files + create_gemspec + create_accessories + initialize_git_repo + end + + def user_name + @user_name ||= `git config user.name`.chomp + end + + def user_email + @user_email ||= `git config user.email`.chomp + end + + private + + def root + @root ||= Pathname.new(File.expand_path("../", __dir__)) + end + + def template_file(filename) + [ + root.join("theme_template", "#{filename}.erb"), + root.join("theme_template", filename.to_s), + ].find(&:exist?) + end + + def template(filename) + erb.render(template_file(filename).read) + end + + def erb + @erb ||= ERBRenderer.new(self) + end + + def mkdir_p(directories) + Array(directories).each do |directory| + full_path = path.join(directory) + Jekyll.logger.info "create", full_path.to_s + FileUtils.mkdir_p(full_path) + end + end + + def write_file(filename, contents) + full_path = path.join(filename) + Jekyll.logger.info "create", full_path.to_s + File.write(full_path, contents) + end + + def create_directories + mkdir_p(SCAFFOLD_DIRECTORIES) + end + + def create_starter_files + %w(page post default).each do |layout| + write_file("_layouts/#{layout}.html", template("_layouts/#{layout}.html")) + end + end + + def create_gemspec + write_file("Gemfile", template("Gemfile")) + write_file("#{name}.gemspec", template("theme.gemspec")) + end + + def create_accessories + accessories = %w(README.md LICENSE.txt) + accessories << "CODE_OF_CONDUCT.md" if code_of_conduct + accessories.each do |filename| + write_file(filename, template(filename)) + end + end + + def initialize_git_repo + Jekyll.logger.info "initialize", path.join(".git").to_s + Dir.chdir(path.to_s) { `git init` } + write_file(".gitignore", template("gitignore")) + end + + class ERBRenderer + extend Forwardable + + def_delegator :@theme_builder, :name, :theme_name + def_delegator :@theme_builder, :user_name, :user_name + def_delegator :@theme_builder, :user_email, :user_email + + def initialize(theme_builder) + @theme_builder = theme_builder + end + + def jekyll_version_with_minor + Jekyll::VERSION.split(".").take(2).join(".") + end + + def theme_directories + SCAFFOLD_DIRECTORIES + end + + def render(contents) + ERB.new(contents).result binding + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/url.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/url.rb new file mode 100644 index 00000000..aeb2ac0d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/url.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +# Public: Methods that generate a URL for a resource such as a Post or a Page. +# +# Examples +# +# URL.new({ +# :template => /:categories/:title.html", +# :placeholders => {:categories => "ruby", :title => "something"} +# }).to_s +# +module Jekyll + class URL + # options - One of :permalink or :template must be supplied. + # :template - The String used as template for URL generation, + # for example "/:path/:basename:output_ext", where + # a placeholder is prefixed with a colon. + # :placeholders - A hash containing the placeholders which will be + # replaced when used inside the template. E.g. + # { "year" => Time.now.strftime("%Y") } would replace + # the placeholder ":year" with the current year. + # :permalink - If supplied, no URL will be generated from the + # template. Instead, the given permalink will be + # used as URL. + def initialize(options) + @template = options[:template] + @placeholders = options[:placeholders] || {} + @permalink = options[:permalink] + + if (@template || @permalink).nil? + raise ArgumentError, "One of :template or :permalink must be supplied." + end + end + + # The generated relative URL of the resource + # + # Returns the String URL + def to_s + sanitize_url(generated_permalink || generated_url) + end + + # Generates a URL from the permalink + # + # Returns the _unsanitized String URL + def generated_permalink + (@generated_permalink ||= generate_url(@permalink)) if @permalink + end + + # Generates a URL from the template + # + # Returns the unsanitized String URL + def generated_url + @generated_url ||= generate_url(@template) + end + + # Internal: Generate the URL by replacing all placeholders with their + # respective values in the given template + # + # Returns the unsanitized String URL + def generate_url(template) + if @placeholders.is_a? Drops::UrlDrop + generate_url_from_drop(template) + else + generate_url_from_hash(template) + end + end + + def generate_url_from_hash(template) + @placeholders.inject(template) do |result, token| + break result if result.index(":").nil? + + if token.last.nil? + # Remove leading "/" to avoid generating urls with `//` + result.gsub("/:#{token.first}", "") + else + result.gsub(":#{token.first}", self.class.escape_path(token.last)) + end + end + end + + # We include underscores in keys to allow for 'i_month' and so forth. + # This poses a problem for keys which are followed by an underscore + # but the underscore is not part of the key, e.g. '/:month_:day'. + # That should be :month and :day, but our key extraction regexp isn't + # smart enough to know that so we have to make it an explicit + # possibility. + def possible_keys(key) + if key.end_with?("_") + [key, key.chomp("_")] + else + [key] + end + end + + def generate_url_from_drop(template) + template.gsub(%r!:([a-z_]+)!) do |match| + name = Regexp.last_match(1) + pool = name.end_with?("_") ? [name, name.chomp!("_")] : [name] + + winner = pool.find { |key| @placeholders.key?(key) } + if winner.nil? + raise NoMethodError, + "The URL template doesn't have #{pool.join(" or ")} keys. " \ + "Check your permalink template!" + end + + value = @placeholders[winner] + value = "" if value.nil? + replacement = self.class.escape_path(value) + + match.sub!(":#{winner}", replacement) + end + end + + # Returns a sanitized String URL, stripping "../../" and multiples of "/", + # as well as the beginning "/" so we can enforce and ensure it. + def sanitize_url(str) + "/#{str}".gsub("..", "/").tap do |result| + result.gsub!("./", "") + result.squeeze!("/") + end + end + + # Escapes a path to be a valid URL path segment + # + # path - The path to be escaped. + # + # Examples: + # + # URL.escape_path("/a b") + # # => "/a%20b" + # + # Returns the escaped path. + def self.escape_path(path) + return path if path.empty? || %r!^[a-zA-Z0-9./-]+$!.match?(path) + + # Because URI.escape doesn't escape "?", "[" and "]" by default, + # specify unsafe string (except unreserved, sub-delims, ":", "@" and "/"). + # + # URI path segment is defined in RFC 3986 as follows: + # segment = *pchar + # pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + # pct-encoded = "%" HEXDIG HEXDIG + # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + # / "*" / "+" / "," / ";" / "=" + Addressable::URI.encode(path).encode("utf-8").sub("#", "%23") + end + + # Unescapes a URL path segment + # + # path - The path to be unescaped. + # + # Examples: + # + # URL.unescape_path("/a%20b") + # # => "/a b" + # + # Returns the unescaped path. + def self.unescape_path(path) + path = path.encode("utf-8") + return path unless path.include?("%") + + Addressable::URI.unencode(path) + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils.rb new file mode 100644 index 00000000..2a965270 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils.rb @@ -0,0 +1,371 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + extend self + autoload :Ansi, "jekyll/utils/ansi" + autoload :Exec, "jekyll/utils/exec" + autoload :Internet, "jekyll/utils/internet" + autoload :Platforms, "jekyll/utils/platforms" + autoload :ThreadEvent, "jekyll/utils/thread_event" + autoload :WinTZ, "jekyll/utils/win_tz" + + # Constants for use in #slugify + SLUGIFY_MODES = %w(raw default pretty ascii latin).freeze + SLUGIFY_RAW_REGEXP = Regexp.new('\\s+').freeze + SLUGIFY_DEFAULT_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}]+").freeze + SLUGIFY_PRETTY_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}._~!$&'()+,;=@]+").freeze + SLUGIFY_ASCII_REGEXP = Regexp.new("[^[A-Za-z0-9]]+").freeze + + # Takes a slug and turns it into a simple title. + def titleize_slug(slug) + slug.split("-").map!(&:capitalize).join(" ") + end + + # Non-destructive version of deep_merge_hashes! See that method. + # + # Returns the merged hashes. + def deep_merge_hashes(master_hash, other_hash) + deep_merge_hashes!(master_hash.dup, other_hash) + end + + # Merges a master hash with another hash, recursively. + # + # master_hash - the "parent" hash whose values will be overridden + # other_hash - the other hash whose values will be persisted after the merge + # + # This code was lovingly stolen from some random gem: + # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html + # + # Thanks to whoever made it. + def deep_merge_hashes!(target, overwrite) + merge_values(target, overwrite) + merge_default_proc(target, overwrite) + duplicate_frozen_values(target) + + target + end + + def mergable?(value) + value.is_a?(Hash) || value.is_a?(Drops::Drop) + end + + def duplicable?(obj) + case obj + when nil, false, true, Symbol, Numeric + false + else + true + end + end + + # Read array from the supplied hash favouring the singular key + # and then the plural key, and handling any nil entries. + # + # hash - the hash to read from + # singular_key - the singular key + # plural_key - the plural key + # + # Returns an array + def pluralized_array_from_hash(hash, singular_key, plural_key) + array = [] + value = value_from_singular_key(hash, singular_key) + value ||= value_from_plural_key(hash, plural_key) + + array << value + array.flatten! + array.compact! + array + end + + def value_from_singular_key(hash, key) + hash[key] if hash.key?(key) || (hash.default_proc && hash[key]) + end + + def value_from_plural_key(hash, key) + if hash.key?(key) || (hash.default_proc && hash[key]) + val = hash[key] + case val + when String + val.split + when Array + val.compact + end + end + end + + def transform_keys(hash) + result = {} + hash.each_key do |key| + result[yield(key)] = hash[key] + end + result + end + + # Apply #to_sym to all keys in the hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with symbolized keys + def symbolize_hash_keys(hash) + transform_keys(hash) { |key| key.to_sym rescue key } + end + + # Apply #to_s to all keys in the Hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with stringified keys + def stringify_hash_keys(hash) + transform_keys(hash) { |key| key.to_s rescue key } + end + + # Parse a date/time and throw an error if invalid + # + # input - the date/time to parse + # msg - (optional) the error message to show the user + # + # Returns the parsed date if successful, throws a FatalException + # if not + def parse_date(input, msg = "Input could not be parsed.") + @parse_date_cache ||= {} + @parse_date_cache[input] ||= Time.parse(input).localtime + rescue ArgumentError + raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}" + end + + # Determines whether a given file has + # + # Returns true if the YAML front matter is present. + # rubocop: disable Naming/PredicateName + def has_yaml_header?(file) + File.open(file, "rb", &:readline).match? %r!\A---\s*\r?\n! + rescue EOFError + false + end + + # Determine whether the given content string contains Liquid Tags or Variables + # + # Returns true is the string contains sequences of `{%` or `{{` + def has_liquid_construct?(content) + return false if content.nil? || content.empty? + + content.include?("{%") || content.include?("{{") + end + # rubocop: enable Naming/PredicateName + + # Slugify a filename or title. + # + # string - the filename or title to slugify + # mode - how string is slugified + # cased - whether to replace all uppercase letters with their + # lowercase counterparts + # + # When mode is "none", return the given string. + # + # When mode is "raw", return the given string, + # with every sequence of spaces characters replaced with a hyphen. + # + # When mode is "default" or nil, non-alphabetic characters are + # replaced with a hyphen too. + # + # When mode is "pretty", some non-alphabetic characters (._~!$&'()+,;=@) + # are not replaced with hyphen. + # + # When mode is "ascii", some everything else except ASCII characters + # a-z (lowercase), A-Z (uppercase) and 0-9 (numbers) are not replaced with hyphen. + # + # When mode is "latin", the input string is first preprocessed so that + # any letters with accents are replaced with the plain letter. Afterwards, + # it follows the "default" mode of operation. + # + # If cased is true, all uppercase letters in the result string are + # replaced with their lowercase counterparts. + # + # Examples: + # slugify("The _config.yml file") + # # => "the-config-yml-file" + # + # slugify("The _config.yml file", "pretty") + # # => "the-_config.yml-file" + # + # slugify("The _config.yml file", "pretty", true) + # # => "The-_config.yml file" + # + # slugify("The _config.yml file", "ascii") + # # => "the-config-yml-file" + # + # slugify("The _config.yml file", "latin") + # # => "the-config-yml-file" + # + # Returns the slugified string. + def slugify(string, mode: nil, cased: false) + mode ||= "default" + return nil if string.nil? + + unless SLUGIFY_MODES.include?(mode) + return cased ? string : string.downcase + end + + # Drop accent marks from latin characters. Everything else turns to ? + if mode == "latin" + I18n.config.available_locales = :en if I18n.config.available_locales.empty? + string = I18n.transliterate(string) + end + + slug = replace_character_sequence_with_hyphen(string, :mode => mode) + + # Remove leading/trailing hyphen + slug.gsub!(%r!^-|-$!i, "") + + slug.downcase! unless cased + Jekyll.logger.warn("Warning:", "Empty `slug` generated for '#{string}'.") if slug.empty? + slug + end + + # Add an appropriate suffix to template so that it matches the specified + # permalink style. + # + # template - permalink template without trailing slash or file extension + # permalink_style - permalink style, either built-in or custom + # + # The returned permalink template will use the same ending style as + # specified in permalink_style. For example, if permalink_style contains a + # trailing slash (or is :pretty, which indirectly has a trailing slash), + # then so will the returned template. If permalink_style has a trailing + # ":output_ext" (or is :none, :date, or :ordinal) then so will the returned + # template. Otherwise, template will be returned without modification. + # + # Examples: + # add_permalink_suffix("/:basename", :pretty) + # # => "/:basename/" + # + # add_permalink_suffix("/:basename", :date) + # # => "/:basename:output_ext" + # + # add_permalink_suffix("/:basename", "/:year/:month/:title/") + # # => "/:basename/" + # + # add_permalink_suffix("/:basename", "/:year/:month/:title") + # # => "/:basename" + # + # Returns the updated permalink template + def add_permalink_suffix(template, permalink_style) + template = template.dup + + case permalink_style + when :pretty + template << "/" + when :date, :ordinal, :none + template << ":output_ext" + else + template << "/" if permalink_style.to_s.end_with?("/") + template << ":output_ext" if permalink_style.to_s.end_with?(":output_ext") + end + + template + end + + # Work the same way as Dir.glob but separating the input into two parts + # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act + # as a pattern. + # + # For example, Dir.glob("path[/*") always returns an empty array, + # because the method fails to find the closing pattern to '[' which is ']' + # + # Examples: + # safe_glob("path[", "*") + # # => ["path[/file1", "path[/file2"] + # + # safe_glob("path", "*", File::FNM_DOTMATCH) + # # => ["path/.", "path/..", "path/file1"] + # + # safe_glob("path", ["**", "*"]) + # # => ["path[/file1", "path[/folder/file2"] + # + # dir - the dir where glob will be executed under + # (the dir will be included to each result) + # patterns - the patterns (or the pattern) which will be applied under the dir + # flags - the flags which will be applied to the pattern + # + # Returns matched paths + def safe_glob(dir, patterns, flags = 0) + return [] unless Dir.exist?(dir) + + pattern = File.join(Array(patterns)) + return [dir] if pattern.empty? + + Dir.chdir(dir) do + Dir.glob(pattern, flags).map { |f| File.join(dir, f) } + end + end + + # Returns merged option hash for File.read of self.site (if exists) + # and a given param + def merged_file_read_opts(site, opts) + merged = (site ? site.file_read_opts : {}).merge(opts) + + # always use BOM when reading UTF-encoded files + if merged[:encoding]&.downcase&.start_with?("utf-") + merged[:encoding] = "bom|#{merged[:encoding]}" + end + if merged["encoding"]&.downcase&.start_with?("utf-") + merged["encoding"] = "bom|#{merged["encoding"]}" + end + + merged + end + + private + + def merge_values(target, overwrite) + target.merge!(overwrite) do |_key, old_val, new_val| + if new_val.nil? + old_val + elsif mergable?(old_val) && mergable?(new_val) + deep_merge_hashes(old_val, new_val) + else + new_val + end + end + end + + def merge_default_proc(target, overwrite) + if target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil? + target.default_proc = overwrite.default_proc + end + end + + def duplicate_frozen_values(target) + target.each do |key, val| + target[key] = val.dup if val.frozen? && duplicable?(val) + end + end + + # Replace each character sequence with a hyphen. + # + # See Utils#slugify for a description of the character sequence specified + # by each mode. + def replace_character_sequence_with_hyphen(string, mode: "default") + replaceable_char = + case mode + when "raw" + SLUGIFY_RAW_REGEXP + when "pretty" + # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL + # and is allowed in both extN and NTFS. + SLUGIFY_PRETTY_REGEXP + when "ascii" + # For web servers not being able to handle Unicode, the safe + # method is to ditch anything else but latin letters and numeric + # digits. + SLUGIFY_ASCII_REGEXP + else + SLUGIFY_DEFAULT_REGEXP + end + + # Strip according to the mode + string.gsub(replaceable_char, "-") + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb new file mode 100644 index 00000000..00d1b1db --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Ansi + extend self + + ESCAPE = format("%c", 27) + MATCH = %r!#{ESCAPE}\[(?:\d+)(?:;\d+)*(j|k|m|s|u|A|B|G)|\e\(B\e\[m!ix.freeze + COLORS = { + :red => 31, + :green => 32, + :black => 30, + :magenta => 35, + :yellow => 33, + :white => 37, + :blue => 34, + :cyan => 36, + }.freeze + + # Strip ANSI from the current string. It also strips cursor stuff, + # well some of it, and it also strips some other stuff that a lot of + # the other ANSI strippers don't. + + def strip(str) + str.gsub MATCH, "" + end + + # + + def has?(str) + !!(str =~ MATCH) + end + + # Reset the color back to the default color so that you do not leak any + # colors when you move onto the next line. This is probably normally + # used as part of a wrapper so that we don't leak colors. + + def reset(str = "") + @ansi_reset ||= format("%c[0m", 27) + "#{@ansi_reset}#{str}" + end + + # SEE: `self::COLORS` for a list of methods. They are mostly + # standard base colors supported by pretty much any xterm-color, we do + # not need more than the base colors so we do not include them. + # Actually... if I'm honest we don't even need most of the + # base colors. + + COLORS.each do |color, num| + define_method color do |str| + "#{format("%c", 27)}[#{num}m#{str}#{reset}" + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb new file mode 100644 index 00000000..5838ecba --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "open3" + +module Jekyll + module Utils + module Exec + extend self + + # Runs a program in a sub-shell. + # + # *args - a list of strings containing the program name and arguments + # + # Returns a Process::Status and a String of output in an array in + # that order. + def run(*args) + stdin, stdout, stderr, process = Open3.popen3(*args) + out = stdout.read.strip + err = stderr.read.strip + + [stdin, stdout, stderr].each(&:close) + [process.value, out + err] + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb new file mode 100644 index 00000000..945267f1 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Internet + # Public: Determine whether the present device has a connection to + # the Internet. This allows plugin writers which require the outside + # world to have a neat fallback mechanism for offline building. + # + # Example: + # if Internet.connected? + # Typhoeus.get("https://pages.github.com/versions.json") + # else + # Jekyll.logger.warn "Warning:", "Version check has been disabled." + # Jekyll.logger.warn "", "Connect to the Internet to enable it." + # nil + # end + # + # Returns true if a DNS call can successfully be made, or false if not. + + module_function + + def connected? + !dns("example.com").nil? + end + + def dns(domain) + require "resolv" + Resolv::DNS.open do |resolver| + resolver.getaddress(domain) + end + rescue Resolv::ResolvError, Resolv::ResolvTimeout + nil + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb new file mode 100644 index 00000000..a6c6da90 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Platforms + extend self + + def jruby? + RUBY_ENGINE == "jruby" + end + + def mri? + RUBY_ENGINE == "ruby" + end + + def windows? + vanilla_windows? || bash_on_windows? + end + + # Not a Windows Subsystem for Linux (WSL) + def vanilla_windows? + rbconfig_host.match?(%r!mswin|mingw|cygwin!) && proc_version.empty? + end + alias_method :really_windows?, :vanilla_windows? + + # Determine if Windows Subsystem for Linux (WSL) + def bash_on_windows? + linux_os? && microsoft_proc_version? + end + + def linux? + linux_os? && !microsoft_proc_version? + end + + def osx? + rbconfig_host.match?(%r!darwin|mac os!) + end + + def unix? + rbconfig_host.match?(%r!solaris|bsd!) + end + + private + + def proc_version + @proc_version ||= \ + begin + File.read("/proc/version").downcase + rescue Errno::ENOENT, Errno::EACCES + "" + end + end + + def rbconfig_host + @rbconfig_host ||= RbConfig::CONFIG["host_os"].downcase + end + + def linux_os? + rbconfig_host.include?("linux") + end + + def microsoft_proc_version? + proc_version.include?("microsoft") + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb new file mode 100644 index 00000000..801022e4 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + # Based on the pattern and code from + # https://emptysqua.re/blog/an-event-synchronization-primitive-for-ruby/ + class ThreadEvent + attr_reader :flag + + def initialize + @lock = Mutex.new + @cond = ConditionVariable.new + @flag = false + end + + def set + @lock.synchronize do + yield if block_given? + @flag = true + @cond.broadcast + end + end + + def wait + @lock.synchronize do + @cond.wait(@lock) unless @flag + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb new file mode 100644 index 00000000..ad277d3a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module WinTZ + extend self + + # Public: Calculate the Timezone for Windows when the config file has a defined + # 'timezone' key. + # + # timezone - the IANA Time Zone specified in "_config.yml" + # + # Returns a string that ultimately re-defines ENV["TZ"] in Windows + def calculate(timezone, now = Time.now) + External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo) + tz = TZInfo::Timezone.get(timezone) + + # + # Use period_for_utc and utc_total_offset instead of + # period_for and observed_utc_offset for compatibility with tzinfo v1. + offset = tz.period_for_utc(now.getutc).utc_total_offset + + # + # POSIX style definition reverses the offset sign. + # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian + # is denoted as: + # EST+5 (or) EST+05:00 + # Reference: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + sign = offset.positive? ? "-" : "+" + + rational_hours = offset.abs.to_r / 3600 + hours = rational_hours.to_i + minutes = ((rational_hours - hours) * 60).to_i + + # + # Format the hours and minutes as two-digit numbers. + time = format("%02d:%02d", :hours => hours, :minutes => minutes) + + Jekyll.logger.debug "Timezone:", "#{timezone} #{sign}#{time}" + # + # Note: The 3-letter-word below doesn't have a particular significance. + "WTZ#{sign}#{time}" + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/lib/jekyll/version.rb b/bin/gems/jekyll-4.4.1/lib/jekyll/version.rb new file mode 100644 index 00000000..eff0d1db --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/jekyll/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Jekyll + VERSION = "4.4.1" +end diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/.gitignore b/bin/gems/jekyll-4.4.1/lib/site_template/.gitignore new file mode 100644 index 00000000..f40fbd8b --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-cache +.jekyll-metadata +vendor diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/404.html b/bin/gems/jekyll-4.4.1/lib/site_template/404.html new file mode 100644 index 00000000..3a16ab53 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/404.html @@ -0,0 +1,25 @@ +--- +permalink: /404.html +layout: page +--- + + + +
+

404

+ +

Page not found :(

+

The requested page could not be found.

+
diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/_config.yml b/bin/gems/jekyll-4.4.1/lib/site_template/_config.yml new file mode 100644 index 00000000..ef7ba7c1 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/_config.yml @@ -0,0 +1,55 @@ +# Welcome to Jekyll! +# +# This config file is meant for settings that affect your whole blog, values +# which you are expected to set up once and rarely edit after that. If you find +# yourself editing this file very often, consider using Jekyll's data files +# feature for the data you need to update frequently. +# +# For technical reasons, this file is *NOT* reloaded automatically when you use +# 'bundle exec jekyll serve'. If you change this file, please restart the server process. +# +# If you need help with YAML syntax, here are some quick references for you: +# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml +# https://learnxinyminutes.com/docs/yaml/ +# +# Site settings +# These are used to personalize your new site. If you look in the HTML files, +# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. +# You can create any custom variable you would like, and they will be accessible +# in the templates via {{ site.myvariable }}. + +title: Your awesome title +email: your-email@example.com +description: >- # this means to ignore newlines until "baseurl:" + Write an awesome description for your new site here. You can edit this + line in _config.yml. It will appear in your document head meta (for + Google search results) and in your feed.xml site description. +baseurl: "" # the subpath of your site, e.g. /blog +url: "" # the base hostname & protocol for your site, e.g. http://example.com +twitter_username: jekyllrb +github_username: jekyll + +# Build settings +theme: minima +plugins: + - jekyll-feed + +# Exclude from processing. +# The following items will not be processed, by default. +# Any item listed under the `exclude:` key here will be automatically added to +# the internal "default list". +# +# Excluded items can be processed by explicitly listing the directories or +# their entries' file path in the `include:` list. +# +# exclude: +# - .sass-cache/ +# - .jekyll-cache/ +# - gemfiles/ +# - Gemfile +# - Gemfile.lock +# - node_modules/ +# - vendor/bundle/ +# - vendor/cache/ +# - vendor/gems/ +# - vendor/ruby/ diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb b/bin/gems/jekyll-4.4.1/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb new file mode 100644 index 00000000..187a4d9b --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb @@ -0,0 +1,29 @@ +--- +layout: post +title: "Welcome to Jekyll!" +date: <%= Time.now.strftime('%Y-%m-%d %H:%M:%S %z') %> +categories: jekyll update +--- +You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. + +Jekyll requires blog post files to be named according to the following format: + +`YEAR-MONTH-DAY-title.MARKUP` + +Where `YEAR` is a four-digit number, `MONTH` and `DAY` are both two-digit numbers, and `MARKUP` is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works. + +Jekyll also offers powerful support for code snippets: + +{% highlight ruby %} +def print_hi(name) + puts "Hi, #{name}" +end +print_hi('Tom') +#=> prints 'Hi, Tom' to STDOUT. +{% endhighlight %} + +Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. + +[jekyll-docs]: https://jekyllrb.com/docs/home +[jekyll-gh]: https://github.com/jekyll/jekyll +[jekyll-talk]: https://talk.jekyllrb.com/ diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/about.markdown b/bin/gems/jekyll-4.4.1/lib/site_template/about.markdown new file mode 100644 index 00000000..8b4e0b28 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/about.markdown @@ -0,0 +1,18 @@ +--- +layout: page +title: About +permalink: /about/ +--- + +This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](https://jekyllrb.com/) + +You can find the source code for Minima at GitHub: +[jekyll][jekyll-organization] / +[minima](https://github.com/jekyll/minima) + +You can find the source code for Jekyll at GitHub: +[jekyll][jekyll-organization] / +[jekyll](https://github.com/jekyll/jekyll) + + +[jekyll-organization]: https://github.com/jekyll diff --git a/bin/gems/jekyll-4.4.1/lib/site_template/index.markdown b/bin/gems/jekyll-4.4.1/lib/site_template/index.markdown new file mode 100644 index 00000000..06715078 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/site_template/index.markdown @@ -0,0 +1,6 @@ +--- +# Feel free to add content and custom Front Matter to this file. +# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults + +layout: home +--- diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/CODE_OF_CONDUCT.md.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/CODE_OF_CONDUCT.md.erb new file mode 100644 index 00000000..2b2c7734 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/CODE_OF_CONDUCT.md.erb @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at <%= user_email %>. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/Gemfile b/bin/gems/jekyll-4.4.1/lib/theme_template/Gemfile new file mode 100644 index 00000000..bb94df82 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/Gemfile @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +gemspec diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/LICENSE.txt.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/LICENSE.txt.erb new file mode 100644 index 00000000..38a0eb4e --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/LICENSE.txt.erb @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) <%= Time.now.year %> <%= user_name %> + +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/bin/gems/jekyll-4.4.1/lib/theme_template/README.md.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/README.md.erb new file mode 100644 index 00000000..9e180340 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/README.md.erb @@ -0,0 +1,50 @@ +# <%= theme_name %> + +Welcome to your new Jekyll theme! In this directory, you'll find the files you need to be able to package up your theme into a gem. Put your layouts in `_layouts`, your includes in `_includes`, your sass files in `_sass` and any other assets in `assets`. + +To experiment with this code, add some sample content and run `bundle exec jekyll serve` – this directory is setup just like a Jekyll site! + +TODO: Delete this and the text above, and describe your gem + +## Installation + +Add this line to your Jekyll site's `Gemfile`: + +```ruby +gem <%= theme_name.inspect %> +``` + +And add this line to your Jekyll site's `_config.yml`: + +```yaml +theme: <%= theme_name %> +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install <%= theme_name %> + +## Usage + +TODO: Write usage instructions here. Describe your available layouts, includes, sass and/or assets. + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/<%= theme_name %>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct. + +## Development + +To set up your environment to develop this theme, run `bundle install`. + +Your theme is setup just like a normal Jekyll site! To test your theme, run `bundle exec jekyll serve` and open your browser at `http://localhost:4000`. This starts a Jekyll server using your theme. Add pages, documents, data, etc. like normal to test your theme's contents. As you make modifications to your theme and to your content, your site will regenerate and you should see the changes in the browser after a refresh, just like normal. + +When your theme is released, only the files in `_layouts`, `_includes`, `_sass` and `assets` tracked with Git will be bundled. +To add a custom directory to your theme-gem, please edit the regexp in `<%= theme_name %>.gemspec` accordingly. + +## License + +The theme is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/default.html b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/default.html new file mode 100644 index 00000000..cddd0709 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/default.html @@ -0,0 +1 @@ +{{ content }} diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/page.html b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/page.html new file mode 100644 index 00000000..5e711268 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/page.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/post.html b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/post.html new file mode 100644 index 00000000..5e711268 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/_layouts/post.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +{{ content }} diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/example/_config.yml.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/example/_config.yml.erb new file mode 100644 index 00000000..82e8d42d --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/example/_config.yml.erb @@ -0,0 +1 @@ +theme: <%= theme_name %> diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/example/_post.md b/bin/gems/jekyll-4.4.1/lib/theme_template/example/_post.md new file mode 100644 index 00000000..145b21de --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/example/_post.md @@ -0,0 +1,12 @@ +--- +layout: post +--- + +Eos eu docendi tractatos sapientem, brute option menandri in vix, quando vivendo accommodare te ius. Nec melius fastidii constituam id, viderer theophrastus ad sit, hinc semper periculis cum id. Noluisse postulant assentior est in, no choro sadipscing repudiandae vix. Vis in euismod delenit dignissim. Ex quod nostrum sit, suas decore animal id ius, nobis solet detracto quo te. + +{% comment %} +Might you have an include in your theme? Why not try it here! +{% include my-themes-great-include.html %} +{% endcomment %} + +No laudem altera adolescens has, volumus lucilius eum no. Eam ei nulla audiam efficiantur. Suas affert per no, ei tale nibh sea. Sea ne magna harum, in denique scriptorem sea, cetero alienum tibique ei eos. Labores persequeris referrentur eos ei. diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/example/index.html b/bin/gems/jekyll-4.4.1/lib/theme_template/example/index.html new file mode 100644 index 00000000..b688538c --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/example/index.html @@ -0,0 +1,14 @@ +--- +layout: page +--- + +Lorem ipsum dolor sit amet, quo id prima corrumpit pertinacia, id ius dolor dolores, an veri pertinax explicari mea. Agam solum et qui, his id ludus graeco adipiscing. Duis theophrastus nam in, at his vidisse atomorum. Tantas gloriatur scripserit ne eos. Est wisi tempor habemus at, ei graeco dissentiet eos. Ne usu aliquip sanctus conceptam, te vis ignota animal, modus latine contentiones ius te. + +{% for post in site.posts %} +

{{ post.title }}

+
{{ post.excerpt }}
+{% endfor %} + +Te falli veritus sea, at molestiae scribentur deterruisset vix, et mea zril phaedrum vulputate. No cum dicit consulatu. Ut has nostro noluisse expetendis, te pro quaeque disputando, eu sed summo omnes. Eos at tale aperiam, usu cu propriae quaestio constituto, sed aperiam erroribus temporibus an. + +Quo eu liber mediocritatem, vix an delectus eleifend, iuvaret suscipit ei vel. Partem invenire per an, mea postulant dissentias eu, ius tantas audire nominavi eu. Dicunt tritani veritus ex vis, mei in case sententiae. At exerci democritum nam, cu lobortis iracundia mei. Alia eligendi consectetuer eu sed, paulo docendi noluisse sit ex. diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/example/style.scss b/bin/gems/jekyll-4.4.1/lib/theme_template/example/style.scss new file mode 100644 index 00000000..7388f52b --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/example/style.scss @@ -0,0 +1,7 @@ +--- +--- + +// Here, you can test out the Sass/SCSS that you include in your theme. +// Simply `@import` the necessary file(s) to get the proper styles on the site. +// E.g.: +// @import "a-file-from-my-theme"; diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/gitignore.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/gitignore.erb new file mode 100644 index 00000000..736d7400 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/gitignore.erb @@ -0,0 +1,6 @@ +*.gem +.bundle +.jekyll-cache +.sass-cache +_site +Gemfile.lock diff --git a/bin/gems/jekyll-4.4.1/lib/theme_template/theme.gemspec.erb b/bin/gems/jekyll-4.4.1/lib/theme_template/theme.gemspec.erb new file mode 100644 index 00000000..7c13cd30 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/lib/theme_template/theme.gemspec.erb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +Gem::Specification.new do |spec| + spec.name = <%= theme_name.inspect %> + spec.version = "0.1.0" + spec.authors = [<%= user_name.inspect %>] + spec.email = [<%= user_email.inspect %>] + + spec.summary = "TODO: Write a short summary, because Rubygems requires one." + spec.homepage = "TODO: Put your gem's website or public repo URL here." + spec.license = "MIT" + + spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r!^(<%= theme_directories.join("|") %>|LICENSE|README|_config\.yml)!i) } + + spec.add_runtime_dependency "jekyll", "~> <%= jekyll_version_with_minor %>" +end diff --git a/bin/gems/jekyll-4.4.1/rubocop/jekyll.rb b/bin/gems/jekyll-4.4.1/rubocop/jekyll.rb new file mode 100644 index 00000000..31236b8a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/rubocop/jekyll.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +Dir[File.join(File.expand_path("jekyll", __dir__), "*.rb")].each do |ruby_file| + require ruby_file +end diff --git a/bin/gems/jekyll-4.4.1/rubocop/jekyll/assert_equal_literal_actual.rb b/bin/gems/jekyll-4.4.1/rubocop/jekyll/assert_equal_literal_actual.rb new file mode 100644 index 00000000..7c7b9f5a --- /dev/null +++ b/bin/gems/jekyll-4.4.1/rubocop/jekyll/assert_equal_literal_actual.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Jekyll + # Checks for `assert_equal(exp, act, msg = nil)` calls containing literal values as + # second argument. The second argument should ideally be a method called on the tested + # instance. + # + # @example + # # bad + # assert_equal @foo.bar, "foobar" + # assert_equal @alpha.beta, { "foo" => "bar", "lorem" => "ipsum" } + # assert_equal @alpha.omega, ["foobar", "lipsum"] + # + # # good + # assert_equal "foobar", @foo.bar + # + # assert_equal( + # { "foo" => "bar", "lorem" => "ipsum" }, + # @alpha.beta + # ) + # + # assert_equal( + # ["foobar", "lipsum"], + # @alpha.omega + # ) + # + class AssertEqualLiteralActual < Base + extend AutoCorrector + + MSG = "Provide the 'expected value' as the first argument to `assert_equal`." + RESTRICT_ON_SEND = %i[assert_equal].freeze + + SIMPLE_LITERALS = %i( + true + false + nil + int + float + str + sym + complex + rational + regopt + ).freeze + + COMPLEX_LITERALS = %i( + array + hash + pair + irange + erange + regexp + ).freeze + + def_node_matcher :literal_actual?, <<-PATTERN + (send nil? :assert_equal $(send ...) $#literal?) + PATTERN + + def_node_matcher :literal_actual_with_msg?, <<-PATTERN + (send nil? :assert_equal $(send ...) $#literal? $#opt_msg?) + PATTERN + + def on_send(node) + return unless literal_actual?(node) || literal_actual_with_msg?(node) + + range = node.loc.expression + add_offense(range) do |corrector| + corrector.replace(range, replacement(node)) + end + end + + private + + def opt_msg?(node) + node&.source + end + + # This is not implement using a NodePattern because it seems + # to not be able to match against an explicit (nil) sexp + def literal?(node) + node && (simple_literal?(node) || complex_literal?(node)) + end + + def simple_literal?(node) + SIMPLE_LITERALS.include?(node.type) + end + + def complex_literal?(node) + COMPLEX_LITERALS.include?(node.type) && + node.each_child_node.all?(&method(:literal?)) + end + + def replacement(node) + _, _, first_param, second_param, optional_param = *node + + replaced_text = \ + if second_param.type == :hash + replace_hash_with_variable(first_param.source, second_param.source) + elsif second_param.type == :array && second_param.source != "[]" + replace_array_with_variable(first_param.source, second_param.source) + else + replace_based_on_line_length(first_param.source, second_param.source) + end + + return "#{replaced_text}, #{optional_param.source}" if optional_param + replaced_text + end + + def replace_based_on_line_length(first_expression, second_expression) + result = "assert_equal #{second_expression}, #{first_expression}" + return result if result.length < 80 + + # fold long lines independent of Rubocop configuration for better readability + <<~TEXT + assert_equal( + #{second_expression}, + #{first_expression} + ) + TEXT + end + + def replace_hash_with_variable(first_expression, second_expression) + expect_expression = if second_expression.start_with?("{") + second_expression + else + "{#{second_expression}}" + end + <<~TEXT + expected = #{expect_expression} + assert_equal expected, #{first_expression} + TEXT + end + + def replace_array_with_variable(first_expression, second_expression) + expect_expression = if second_expression.start_with?("%") + second_expression + else + Array(second_expression) + end + <<~TEXT + expected = #{expect_expression} + assert_equal expected, #{first_expression} + TEXT + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_p_allowed.rb b/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_p_allowed.rb new file mode 100644 index 00000000..b77f8f83 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_p_allowed.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Jekyll + class NoPAllowed < Base + MSG = "Avoid using `p` to print things. Use `Jekyll.logger` instead." + RESTRICT_ON_SEND = %i[p].freeze + + def_node_search :p_called?, <<-PATTERN + (send _ :p _) + PATTERN + + def on_send(node) + if p_called?(node) + add_offense(node.loc.selector) + end + end + end + end + end +end diff --git a/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_puts_allowed.rb b/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_puts_allowed.rb new file mode 100644 index 00000000..81717cc3 --- /dev/null +++ b/bin/gems/jekyll-4.4.1/rubocop/jekyll/no_puts_allowed.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Jekyll + class NoPutsAllowed < Base + MSG = "Avoid using `puts` to print things. Use `Jekyll.logger` instead." + RESTRICT_ON_SEND = %i[puts].freeze + + def_node_search :puts_called?, <<-PATTERN + (send nil? :puts _) + PATTERN + + def on_send(node) + if puts_called?(node) + add_offense(node.loc.selector) + end + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata.rb new file mode 100644 index 00000000..6aaa0042 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require "jekyll" +require "octokit" + +if Jekyll.env == "development" + begin + require "dotenv" + Dotenv.load + rescue LoadError + Jekyll.logger.debug "Dotenv not found. Skipping" + end +end + +module Jekyll + module GitHubMetadata + autoload :Client, "jekyll-github-metadata/client" + autoload :EditLinkTag, "jekyll-github-metadata/edit-link-tag" + autoload :MetadataDrop, "jekyll-github-metadata/metadata_drop" + autoload :Owner, "jekyll-github-metadata/owner" + autoload :Pages, "jekyll-github-metadata/pages" + autoload :Repository, "jekyll-github-metadata/repository" + autoload :RepositoryFinder, "jekyll-github-metadata/repository_finder" + autoload :RepositoryCompat, "jekyll-github-metadata/repository_compat" + autoload :Sanitizer, "jekyll-github-metadata/sanitizer" + autoload :Value, "jekyll-github-metadata/value" + autoload :VERSION, "jekyll-github-metadata/version" + + NoRepositoryError = RepositoryFinder::NoRepositoryError + + require_relative "jekyll-github-metadata/site_github_munger" if Jekyll.const_defined? :Site + + class << self + attr_reader :repository_finder + attr_writer :client, :logger + + def site + repository_finder.site + end + + def environment + Jekyll.env + end + + def logger + @logger ||= Jekyll.logger + end + + def log(severity, message) + if logger.method(severity).arity.abs >= 2 + logger.public_send(severity, "GitHub Metadata:", message.to_s) + else + logger.public_send(severity, "GitHub Metadata: #{message}") + end + end + + def client + @client ||= Client.new + end + + def repository + @repository ||= GitHubMetadata::Repository.new(repository_finder.nwo).tap do |repo| + log :debug, "Generating for #{repo.nwo}" + end + end + + def site=(new_site) + reset! + @repository_finder = GitHubMetadata::RepositoryFinder.new(new_site) + end + + def reset! + @logger = @client = @repository = @nwo = @site = nil + end + end + end +end + +Liquid::Template.register_tag("github_edit_link", Jekyll::GitHubMetadata::EditLinkTag) diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/client.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/client.rb new file mode 100644 index 00000000..f6551524 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/client.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +require "digest" + +module Jekyll + module GitHubMetadata + class Client + InvalidMethodError = Class.new(NoMethodError) + BadCredentialsError = Class.new(StandardError) + + # Whitelisted API calls. + API_CALLS = Set.new(%w( + repository + organization + user + repository? + pages + contributors + releases + latest_release + list_repos + organization_public_members + )) + + def initialize(options = nil) + @client = build_octokit_client(options) + end + + def safe_require(gem_name) + require gem_name + true + rescue LoadError + false + end + + def default_octokit_options + { + :api_endpoint => Jekyll::GitHubMetadata::Pages.api_url, + :web_endpoint => Jekyll::GitHubMetadata::Pages.github_url, + :auto_paginate => true, + } + end + + def build_octokit_client(options = nil) + options ||= {} + options.merge!(pluck_auth_method) unless options.key?(:access_token) + Octokit::Client.new(default_octokit_options.merge(options)) + end + + def accepts_client_method?(method_name) + API_CALLS.include?(method_name.to_s) && @client.respond_to?(method_name) + end + + def respond_to_missing?(method_name, include_private = false) + accepts_client_method?(method_name) || super + end + + def method_missing(method_name, *args, &block) + method = method_name.to_s + if accepts_client_method?(method_name) + key = cache_key(method_name, args) + GitHubMetadata.log :debug, "Calling @client.#{method}(#{args.map(&:inspect).join(", ")})" + cache[key] ||= save_from_errors { @client.public_send(method_name, *args, &block) } + elsif @client.respond_to?(method_name) + raise InvalidMethodError, "#{method_name} is not whitelisted on #{inspect}" + else + super + end + end + + # NOTE: Faraday's error classes have been simplified from v1.0.0. + # + # In older versions, both `Faraday::Error::ConnectionFailed` and `Faraday::ConnectionFailed` + # were valid and equivalent to each other. + # From v1.0.0 onwards, `Faraday::Error::ConnectionFailed` no longer exists. + # + # TODO: Remove in v2.0 of this plugin. + FARADAY_FAILED_CONNECTION = + begin + Faraday::Error::ConnectionFailed + rescue NameError + Faraday::ConnectionFailed + end + deprecate_constant :FARADAY_FAILED_CONNECTION + + def save_from_errors(default = false) + unless internet_connected? + GitHubMetadata.log :warn, "No internet connection. GitHub metadata may be missing or incorrect." + return default + end + + yield @client + rescue Octokit::Unauthorized + raise BadCredentialsError, "The GitHub API credentials you provided aren't valid." + rescue Faraday::ConnectionFailed, Octokit::TooManyRequests => e + GitHubMetadata.log :warn, e.message + default + rescue Octokit::NotFound + default + end + + def inspect + "#<#{self.class.name} @client=#{client_inspect} @internet_connected=#{internet_connected?}>" + end + + def authenticated? + !@client.access_token.to_s.empty? + end + + def internet_connected? + return @internet_connected if defined?(@internet_connected) + + require "resolv" + begin + Resolv::DNS.open do |dns| + dns.timeouts = 2 + dns.getaddress("api.github.com") + end + @internet_connected = true + rescue Resolv::ResolvError + @internet_connected = false + end + end + + private + + def client_inspect + if @client.nil? + "nil" + else + "#<#{@client.class.name} (#{"un" unless authenticated?}authenticated)>" + end + end + + # rubocop:disable Metrics/CyclomaticComplexity + def pluck_auth_method + if ENV["JEKYLL_GITHUB_TOKEN"] || Octokit.access_token + { :access_token => ENV["JEKYLL_GITHUB_TOKEN"] || Octokit.access_token } + elsif !ENV["NO_NETRC"] && File.exist?(File.join(Dir.home, ".netrc")) && safe_require("netrc") + { :netrc => true } + else + GitHubMetadata.log :warn, "No GitHub API authentication could be found. " \ + "Some fields may be missing or have incorrect data." + {}.freeze + end + end + # rubocop:enable Metrics/CyclomaticComplexity + + def cache_key(method, *args) + Digest::SHA1.hexdigest(method.to_s + args.join(", ")) + end + + def cache + @cache ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/edit-link-tag.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/edit-link-tag.rb new file mode 100644 index 00000000..c150646b --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/edit-link-tag.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class EditLinkTag < Liquid::Tag + attr_reader :context + + # Defines an instance method that delegates to a hash's key + # + # hash_method - a symbol representing the instance method to delegate to. The + # instance method should return a hash or respond to #[] + # key - the key to call within the hash + # method - (optional) the instance method the key should be aliased to. + # If not specified, defaults to the hash key + # default - (optional) value to return if value is nil (defaults to nil) + # + # Returns a symbol representing the instance method + def self.def_hash_delegator(hash_method, key, method, default = nil) + define_method(method) do + hash = send(hash_method) + if hash.respond_to? :[] + hash[key.to_s] || default + else + default + end + end + end + + MISSING_DATA_MSG = "Cannot generate edit URLs due to missing site.github data" + LINK_TEXT_REGEX = %r!(?:\"(.*)\"|'(.*)')!.freeze + + extend Forwardable + private def_hash_delegator :site, :github, :site_github, {} + private def_hash_delegator :site_github, :repository_url, :repository_url + private def_hash_delegator :site_github, :source, :source, {} + private def_hash_delegator :source, :branch, :branch + private def_hash_delegator :source, :path, :source_path + private def_hash_delegator :page, :path, :page_path + + def render(context) + @context = context + if link_text + link + else + uri.to_s + end + end + + private + + def link_text + @link_text ||= begin + matches = @markup.match LINK_TEXT_REGEX + matches[1] || matches[2] if matches + end + end + + def link + "#{link_text}" + end + + def uri + if parts.any?(&:nil?) + Jekyll.logger.warn "JekyllEditLink: ", MISSING_DATA_MSG + "" + else + Addressable::URI.join(*parts_normalized).normalize + end + end + + def parts + memoize_conditionally { [repository_url, "edit/", branch, source_path, page_path] } + end + + def parts_normalized + memoize_conditionally do + parts.map.with_index do |part, index| + part = remove_leading_slash(part.to_s) + part = ensure_trailing_slash(part) unless index == parts.length - 1 + ensure_not_just_a_slash(part) + end + end + end + + def page + memoize_conditionally { context.registers[:page] } + end + + # Utility function for compatibility with Jekyll 4.0 + def memoize_conditionally + if renderer_cached? + yield + else + dispatcher = "@#{caller_locations(1..1).first.label}".to_sym + if instance_variable_defined?(dispatcher) + instance_variable_get(dispatcher) + else + instance_variable_set(dispatcher, yield) + end + end + end + + # Utility function to detect Jekyll 4.0 + def renderer_cached? + @renderer_cached ||= context.registers[:site].liquid_renderer.respond_to?(:cache) + end + + def site + @site ||= context.registers[:site].site_payload["site"] + end + + def remove_leading_slash(part) + part.start_with?("/") ? part[1..-1] : part + end + + def ensure_trailing_slash(part) + part.end_with?("/") ? part : "#{part}/" + end + + def ensure_not_just_a_slash(part) + part == "/" ? "" : part + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/metadata_drop.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/metadata_drop.rb new file mode 100644 index 00000000..e1584c78 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/metadata_drop.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require "jekyll" +require "forwardable" + +module Jekyll + module GitHubMetadata + class MetadataDrop < Jekyll::Drops::Drop + extend Forwardable + + mutable true + + # See https://github.com/jekyll/jekyll/pull/6338 + alias_method :invoke_drop, :[] + def key?(key) + return false if key.nil? + return true if self.class.mutable? && mutations.key?(key) + + respond_to?(key) || fallback_data.key?(key) + end + + def to_s + require "json" + JSON.pretty_generate to_h + end + alias_method :to_str, :to_s + + def content_methods + super - %w(to_s to_str) + end + + def keys + super.sort + end + + def_delegator Jekyll::GitHubMetadata::Pages, :env, :environment + def_delegator Jekyll::GitHubMetadata::Pages, :env, :pages_env + def_delegator Jekyll::GitHubMetadata::Pages, :github_hostname, :hostname + def_delegator Jekyll::GitHubMetadata::Pages, :pages_hostname, :pages_hostname + def_delegator Jekyll::GitHubMetadata::Pages, :api_url, :api_url + def_delegator Jekyll::GitHubMetadata::Pages, :help_url, :help_url + + private def_delegator Jekyll::GitHubMetadata, :repository + + def_delegator :repository, :owner_public_repositories, :public_repositories + def_delegator :repository, :organization_public_members, :organization_members + def_delegator :repository, :name, :project_title + def_delegator :repository, :tagline, :project_tagline + def_delegator :repository, :owner_metadata, :owner + def_delegator :repository, :owner, :owner_name + def_delegator :repository, :owner_display_name, :owner_display_name + def_delegator :repository, :owner_url, :owner_url + def_delegator :repository, :owner_gravatar_url, :owner_gravatar_url + def_delegator :repository, :repository_url, :repository_url + def_delegator :repository, :nwo, :repository_nwo + def_delegator :repository, :name, :repository_name + def_delegator :repository, :zip_url, :zip_url + def_delegator :repository, :tar_url, :tar_url + def_delegator :repository, :repo_clone_url, :clone_url + def_delegator :repository, :releases_url, :releases_url + def_delegator :repository, :issues_url, :issues_url + def_delegator :repository, :wiki_url, :wiki_url + def_delegator :repository, :language, :language + def_delegator :repository, :user_page?, :is_user_page + def_delegator :repository, :project_page?, :is_project_page + def_delegator :repository, :show_downloads?, :show_downloads + def_delegator :repository, :html_url, :url + def_delegator :repository, :baseurl, :baseurl + def_delegator :repository, :contributors, :contributors + def_delegator :repository, :releases, :releases + def_delegator :repository, :latest_release, :latest_release + def_delegator :repository, :private?, :private + def_delegator :repository, :archived?, :archived + def_delegator :repository, :disabled?, :disabled + def_delegator :repository, :license, :license + def_delegator :repository, :source, :source + + def versions + return @versions if defined?(@versions) + + begin + require "github-pages" + @versions = GitHubPages.versions + rescue LoadError + @versions = {} + end + end + + def build_revision + @build_revision ||= begin + ENV["JEKYLL_BUILD_REVISION"] || `git rev-parse HEAD`.strip + end + end + + private + + # Nothing to see here. + def fallback_data + @fallback_data ||= {} + end + + def mutations + @mutations ||= {} + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/owner.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/owner.rb new file mode 100644 index 00000000..8430170a --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/owner.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class Owner + extend Forwardable + + # Defines an instance method that delegates to a hash's key + # + # hash - a symbol representing the instance method to delegate to. The + # instance method should return a hash or respond to #[] + # key - the key to call within the hash + # method - (optional) the instance method the key should be aliased to. + # If not specified, defaults to the hash key + # + # Returns a symbol representing the instance method + def self.def_hash_delegators(hash, *methods) + content_methods.concat(methods) + methods.each do |method| + define_method(method) do + send(hash)[method.to_s] + end + end + end + + def self.content_methods + @content_methods ||= [] + end + + # List of whitelisted keys. + def_hash_delegators :owner_info, + :avatar_url, + :bio, + :blog, + :collaborators, + :company, + :created_at, + :description, + :email, + :followers, + :following, + :has_organization_projects, + :has_repository_projects, + :hireable, + :html_url, + :id, + :is_verified, + :location, + :login, + :name, + :node_id, + :public_gists, + :public_gists, + :public_repos, + :public_repos, + :type, + :updated_at + + attr_reader :owner_login + + def initialize(owner_login) + @owner_login = owner_login + end + + def to_h + @to_h ||= self.class.content_methods + .each_with_object({}) { |method, hash| hash[method.to_s] = public_send(method) } + end + alias_method :to_hash, :to_h + def_delegator :to_h, :to_json, :to_json + def_delegator :to_h, :to_liquid, :to_liquid + + def_delegator :to_h, :to_s, :to_s + alias_method :to_str, :to_s + + private + + def owner_info + @owner_info ||= begin + Value.new( + "owner", + proc do |c| + (c.organization(owner_login) || c.user(owner_login) || {}).to_h + end + ).render || {} + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/pages.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/pages.rb new file mode 100644 index 00000000..13fdb8fd --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/pages.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class Pages + class << self + DEFAULTS = { + "PAGES_ENV" => "development", + "PAGES_API_URL" => "https://api.github.com", + "PAGES_HELP_URL" => "https://docs.github.com", + "PAGES_GITHUB_HOSTNAME" => "github.com", + "PAGES_PAGES_HOSTNAME" => "github.io", + "SSL" => "false", + "SUBDOMAIN_ISOLATION" => "false", + "PAGES_PREVIEW_HTML_URL" => nil, + "PAGE_BUILD_ID" => nil, + }.freeze + + # Whether the GitHub instance supports HTTPS + # Note: this will be the same as how sites are served in Enterprise, + # but may be different from how sites are served on GitHub.com. + # See Repository#url_scheme + def ssl? + env_var("SSL") == "true" || test? + end + + def scheme + ssl? ? "https" : "http" + end + + def subdomain_isolation? + env_var("SUBDOMAIN_ISOLATION").eql? "true" + end + + def test? + env == "test" + end + + def dotcom? + env == "dotcom" + end + + def enterprise? + env == "enterprise" + end + + def development? + env == "development" + end + + def custom_domains_enabled? + dotcom? || test? + end + + def env + env_var "PAGES_ENV", ENV["JEKYLL_ENV"] + end + + def repo_pages_html_url_preview? + env_var "PAGES_PREVIEW_HTML_URL" + end + + def github_url + if dotcom? || github_hostname == "github.com" + "https://github.com" + else + "#{scheme}://#{github_hostname}" + end + end + + def api_url + trim_last_slash env_var("PAGES_API_URL", ENV["API_URL"]) + end + + def help_url + trim_last_slash env_var("PAGES_HELP_URL", ENV["HELP_URL"]) + end + + def github_hostname + trim_last_slash env_var("PAGES_GITHUB_HOSTNAME", ENV["GITHUB_HOSTNAME"]) + end + + def pages_hostname + intermediate_default = ENV["PAGES_HOSTNAME"] + intermediate_default ||= "localhost:4000" if development? + trim_last_slash env_var("PAGES_PAGES_HOSTNAME", intermediate_default) + end + + def page_build? + !env_var("PAGE_BUILD_ID").to_s.empty? + end + + def configuration + (methods - Object.methods - [:configuration]).sort.each_with_object({}) do |meth, memo| + memo[meth.to_s] = public_send(meth) + end + end + + private + + def env_var(key, intermediate_default = nil) + !ENV[key].to_s.empty? ? ENV[key] : (intermediate_default || DEFAULTS[key]) + end + + def trim_last_slash(url) + if url[-1] == "/" + url[0..-2] + else + url + end + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository.rb new file mode 100644 index 00000000..c2bc53b5 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository.rb @@ -0,0 +1,220 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class Repository + attr_reader :nwo, :owner, :name + + # Defines an instance method that delegates to a hash's key + # + # hash - a symbol representing the instance method to delegate to. The + # instance method should return a hash or respond to #[] + # key - the key to call within the hash + # method - (optional) the instance method the key should be aliased to. + # If not specified, defaults to the hash key + # + # Returns a symbol representing the instance method + def self.def_hash_delegator(hash, key, method) + define_method(method) do + public_send(hash)[key.to_s] + end + end + + extend Forwardable + def_hash_delegator :repo_info, :license, :license + def_hash_delegator :repo_info, :language, :language + def_hash_delegator :repo_info, :description, :tagline + def_hash_delegator :repo_info, :has_downloads, :show_downloads? + def_hash_delegator :repo_info, :private, :private? + def_hash_delegator :repo_info, :archived, :archived? + def_hash_delegator :repo_info, :disabled, :disabled? + def_hash_delegator :latest_release, :url, :latest_release_url + def_hash_delegator :source, :branch, :git_ref + + def_delegator :uri, :host, :domain + def_delegator :uri, :scheme, :url_scheme + def_delegator :uri, :path, :baseurl + + def initialize(name_with_owner) + @nwo = name_with_owner + @owner = nwo.split("/").first + @name = nwo.split("/").last + end + + def repo_compat + @repo_compat ||= Jekyll::GitHubMetadata::RepositoryCompat.new(self) + end + + def repo_info + @repo_info ||= begin + options = { :accept => "application/vnd.github.drax-preview+json" } + (Value.new("repo_info", proc { |c| c.repository(nwo, options) }).render || {}) + end + end + + def repo_pages_info + @repo_pages_info ||= (Value.new("repo_pages_info", proc { |c| c.pages(nwo, repo_pages_info_opts) }).render || {}) + end + + def repo_pages_info_opts + if Pages.repo_pages_html_url_preview? + { :accept => "application/vnd.github.mister-fantastic-preview+json" } + else + {} + end + end + + def owner_display_name + owner_metadata.name + end + + def owner_metadata + @owner_metadata ||= Jekyll::GitHubMetadata::Owner.new(owner) + end + + def owner_url + "#{Pages.github_url}/#{owner}" + end + + def owner_gravatar_url + "#{owner_url}.png" + end + + def repo_clone_url + "#{repository_url}.git" + end + + def repository_url + "#{owner_url}/#{name}" + end + + def zip_url + "#{repository_url}/zipball/#{git_ref}" + end + + def tar_url + "#{repository_url}/tarball/#{git_ref}" + end + + def releases_url + "#{repository_url}/releases" + end + + def issues_url + "#{repository_url}/issues" if repo_info["has_issues"] + end + + def wiki_url + "#{repository_url}/wiki" if repo_info["has_wiki"] + end + + def organization_repository? + memoize_value :@is_organization_repository, Value.new("organization_repository?", proc { |c| !!c.organization(owner) }) + end + + def owner_public_repositories + options = { + :type => "public", + :accept => "application/vnd.github.mercy-preview+json", + } + memoize_value :@owner_public_repositories, Value.new("owner_public_repositories", proc do |c| + repos = c.list_repos(owner, options) || [] + repos.map do |r| + r[:releases] = Value.new("owner_public_repositories_releases", proc { c.releases(r[:full_name]) }) + r[:contributors] = Value.new("owner_public_repositories_contributors", proc { c.contributors(r[:full_name]) }) + r + end + end) + end + + def organization_public_members + memoize_value :@organization_public_members, Value.new("organization_public_members", proc do |c| + c.organization_public_members(owner) if organization_repository? + end) + end + + def contributors + memoize_value :@contributors, Value.new("contributors", proc { |c| c.contributors(nwo) }) + end + + def releases + memoize_value :@releases, Value.new("releases", proc { |c| c.releases(nwo) }) + end + + def latest_release + memoize_value :@latest_release, Value.new("latest_release", proc { |c| c.latest_release(nwo) }) + end + + def source + repo_pages_info["source"] || repo_compat.source + end + + def project_page? + !user_page? + end + + def github_repo? + !Pages.enterprise? && owner.eql?("github") + end + + def primary? + if Pages.enterprise? + name.downcase == "#{owner.to_s.downcase}.#{Pages.github_hostname}" + else + user_page_domains.include? name.downcase + end + end + alias_method :user_page?, :primary? + + def user_page_domains + domains = [default_user_domain] + domains.push "#{owner}.github.com".downcase unless Pages.enterprise? + domains + end + + def default_user_domain + if github_repo? + "#{owner}.#{Pages.github_hostname}".downcase + elsif Pages.enterprise? + Pages.pages_hostname.downcase + else + "#{owner}.#{Pages.pages_hostname}".downcase + end + end + + def cname + return nil unless Pages.custom_domains_enabled? + + repo_pages_info["cname"] + end + + def html_url + @html_url ||= (repo_pages_info["html_url"] || repo_compat.pages_url).chomp("/") + end + + def uri + @uri ||= URI(html_url) + end + + def url_without_path + uri.dup.tap { |u| u.path = "" }.to_s + end + + def stargazers_count + repo_pages_info["stargazers_count"] || 0 + end + + def forks_count + repo_pages_info["forks_count"] || 0 + end + + private + + def memoize_value(var_name, value) + return instance_variable_get(var_name) if instance_variable_defined?(var_name) + + instance_variable_set(var_name, value.render) + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_compat.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_compat.rb new file mode 100644 index 00000000..bd324356 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_compat.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class RepositoryCompat + attr_reader :repo + + def initialize(repo) + @repo = repo + end + + # In enterprise, the site's scheme will be the same as the instance's + # In dotcom, this will be `https` for GitHub-owned sites that end with + # `.github.com` and will be `http` for all other sites. + # Note: This is not the same as *instance*'s scheme, which may differ + def url_scheme + if Pages.enterprise? + Pages.scheme + elsif repo.owner == "github" && domain.end_with?(".github.com") + "https" + else + "http" + end + end + + def user_domain + domain = repo.default_user_domain + repo.user_page_domains.each do |user_repo| + candidate_nwo = "#{repo.owner}/#{user_repo}" + next unless Jekyll::GitHubMetadata.client.repository?(candidate_nwo) + + domain = Jekyll::GitHubMetadata::Repository.new(candidate_nwo).repo_compat.domain + end + domain + end + + def pages_url + return enterprise_url unless Pages.custom_domains_enabled? + + if repo.cname || repo.primary? + "#{url_scheme}://#{domain}" + else + URI.join("#{url_scheme}://#{domain}", repo.name).to_s + end + end + alias_method :html_url, :pages_url + + def domain + @domain ||= + if !Pages.custom_domains_enabled? + Pages.github_hostname + elsif repo.cname # explicit CNAME + repo.cname + elsif repo.primary? # user/org repo + repo.default_user_domain + else # project repo + user_domain + end + end + + def source + { + "branch" => (repo.user_page? ? "master" : "gh-pages"), + "path" => "/", + } + end + + private + + def enterprise_url + path = repo.user_page? ? repo.owner : repo.nwo + if Pages.subdomain_isolation? + URI.join("#{Pages.scheme}://#{Pages.pages_hostname}/", path).to_s + else + URI.join("#{Pages.github_url}/pages/", path).to_s + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_finder.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_finder.rb new file mode 100644 index 00000000..797f9286 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/repository_finder.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + class RepositoryFinder + NoRepositoryError = Class.new(Jekyll::Errors::FatalException) + + attr_reader :site + def initialize(site) + @site = site + end + + # Public: fetches the repository name with owner to fetch metadata for. + # In order of precedence, this method uses: + # 1. the environment variable $PAGES_REPO_NWO + # 2. 'repository' variable in the site config + # 3. the 'origin' git remote's URL + # + # site - the Jekyll::Site being processed + # + # Return the name with owner (e.g. 'parkr/my-repo') or raises an + # error if one cannot be found. + def nwo + @nwo ||= begin + nwo_from_env || \ + nwo_from_config || \ + nwo_from_git_origin_remote || \ + proc do + raise NoRepositoryError, "No repo name found. " \ + "Specify using PAGES_REPO_NWO environment variables, " \ + "'repository' in your configuration, or set up an 'origin' " \ + "git remote pointing to your github.com repository." + end.call + end + end + + private + + def nwo_from_env + ENV["PAGES_REPO_NWO"] + end + + def nwo_from_config + repo = site.config["repository"] + repo if repo&.is_a?(String) && repo&.include?("/") + end + + def git_remotes + _process, output = Jekyll::Utils::Exec.run("git", "remote", "--verbose") + output.to_s.strip.split("\n") + rescue Errno::ENOENT => e + Jekyll.logger.warn "Not Installed:", e.message + [] + end + + def git_remote_url + git_remotes.grep(%r!\Aorigin\t!).map do |remote| + remote.sub(%r!\Aorigin\t(.*) \([a-z]+\)!, "\\1") + end.uniq.first || "" + end + + def nwo_from_git_origin_remote + return unless Jekyll.env == "development" || Jekyll.env == "test" + + matches = git_remote_url.chomp(".git").match github_remote_regex + matches[2..3].join("/") if matches + end + + def github_remote_regex + github_host_regex = Regexp.escape(Jekyll::GitHubMetadata::Pages.github_hostname) + %r!#{github_host_regex}(:|/)([\w-]+)/([\w\.-]+)! + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/sanitizer.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/sanitizer.rb new file mode 100644 index 00000000..0a993d3b --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/sanitizer.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + module Sanitizer + extend self + # Sanitize an object. + # When the resource is either `false`, `true`, `nil` or a number, + # it returns the resource as-is. When the resource is an array, + # it maps over the entire array, sanitizing each of its values. + # When the resource responds to the #to_hash method, it returns + # the value of #sanitize_resource (see below). If none of the + # aforementioned conditions are met, the return value of #to_s + # is used. + # + # resource - an Object + # + # Returns the sanitized resource. + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength + def sanitize(resource) + case resource + when Array + resource.map { |item| sanitize(item) } + when Numeric, Time + resource + when FalseClass + false + when TrueClass + true + when NilClass + nil + when String + resource + when Value + resource.render + else + if resource.respond_to?(:to_hash) + sanitize_resource(resource) + else + resource.to_s + end + end + end + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength + + # Sanitize the Sawyer Resource or Hash + # Note: the object must respond to :to_hash for this to work. + # Consider using #sanitize instead of this method directly. + # + # resource - an Object which responds to :to_hash + # + # Returns the sanitized sawyer resource or hash as a hash. + def sanitize_resource(resource) + resource.to_hash.each_with_object({}) do |(k, v), result| + result[k.to_s] = sanitize(v) + result + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/site_github_munger.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/site_github_munger.rb new file mode 100644 index 00000000..c723cc04 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/site_github_munger.rb @@ -0,0 +1,107 @@ +require "jekyll" +require "uri" + +module Jekyll + module GitHubMetadata + class SiteGitHubMunger + extend Forwardable + + class << self + attr_accessor :global_munger + end + + def_delegators Jekyll::GitHubMetadata, :site, :repository + private :repository + + def initialize(site) + Jekyll::GitHubMetadata.site = site + @original_config = site.config["github"] + end + + def munge! + Jekyll::GitHubMetadata.log :debug, "Initializing..." + + add_title_and_description_fallbacks! + add_url_and_baseurl_fallbacks! if should_add_url_fallbacks? + end + + def inject_metadata!(payload) + payload.site["github"] = github_namespace + end + + def uninject_metadata!(payload) + payload.site["github"] = @original_config + end + + private + + def github_namespace + case @original_config + when nil + drop + when Hash + drop.merge(@original_config) + else + @original_config + end + end + + def drop + @drop ||= MetadataDrop.new(GitHubMetadata.site) + end + + # Set `site.url` and `site.baseurl` if unset. + def add_url_and_baseurl_fallbacks! + site.config["url"] ||= Value.new("url", proc { |_c, r| r.url_without_path }) + return unless should_set_baseurl? + + site.config["baseurl"] = Value.new("baseurl", proc { |_c, r| r.baseurl }) + end + + def add_title_and_description_fallbacks! + if should_warn_about_site_name? + msg = "site.name is set in _config.yml, but many plugins and themes expect " + msg << "site.title to be used instead. To avoid potential inconsistency, " + msg << "Jekyll GitHub Metadata will not set site.title to the repository's name." + Jekyll::GitHubMetadata.log :warn, msg + else + site.config["title"] ||= Value.new("title", proc { |_context, repository| + if repository.project_page? + repository.name + else + repository.owner_display_name || repository.owner + end + }) + end + site.config["description"] ||= Value.new("description", proc { |_c, r| r.tagline }) + end + + # Set the baseurl only if it is `nil` or `/` + # Baseurls should never be "/". See http://bit.ly/2s1Srid + def should_set_baseurl? + site.config["baseurl"].nil? || site.config["baseurl"] == "/" + end + + def should_add_url_fallbacks? + Jekyll.env == "production" || Pages.page_build? + end + + def should_warn_about_site_name? + site.config["name"] && !site.config["title"] + end + end + + Jekyll::Hooks.register :site, :after_init do |site| + SiteGitHubMunger.global_munger = SiteGitHubMunger.new(site) + SiteGitHubMunger.global_munger.munge! + end + + Jekyll::Hooks.register :site, :pre_render do |_site, payload| + SiteGitHubMunger.global_munger.inject_metadata!(payload) + end + + Jekyll::Hooks.register :site, :post_render do |_site, payload| + SiteGitHubMunger.global_munger.uninject_metadata!(payload) + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/value.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/value.rb new file mode 100644 index 00000000..49e16ae7 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/value.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require "json" + +module Jekyll + module GitHubMetadata + class Value + extend Forwardable + def_delegators :render, :+, :to_s, :to_json, :eql?, :hash + + attr_reader :key, :value + + def initialize(*args) + case args.size + when 1 + @key = "{anonymous}" + @value = args.first + when 2 + @key = args.first.to_s + @value = args.last + else + raise ArgumentError, "#{args.size} args given but expected 1 or 2" + end + end + + def render + return @rendered if defined? @rendered + + @rendered = @value = Sanitizer.sanitize(call_or_value) + rescue RuntimeError, NameError => e + Jekyll::GitHubMetadata.log :error, "Error processing value '#{key}':" + raise e + end + + def to_liquid + case render + when nil, true, false, Hash, String, Numeric, Array + value + else + to_json + end + end + + private + + # Calls the value Proc with the appropriate number of arguments + # or returns the raw value if it's a literal + def call_or_value + return value unless value.respond_to?(:call) + + case value.arity + when 0 + value.call + when 1 + value.call(GitHubMetadata.client) + when 2 + value.call(GitHubMetadata.client, GitHubMetadata.repository) + else + raise ArgumentError, "Whoa, arity of 0, 1, or 2 please in your procs." + end + end + end + end +end diff --git a/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/version.rb b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/version.rb new file mode 100644 index 00000000..935ff5d1 --- /dev/null +++ b/bin/gems/jekyll-github-metadata-2.16.1/lib/jekyll-github-metadata/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Jekyll + module GitHubMetadata + VERSION = "2.16.1" + end +end diff --git a/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache.rb b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache.rb new file mode 100644 index 00000000..f2b1ef36 --- /dev/null +++ b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "jekyll" + +module JekyllIncludeCache + autoload :Tag, "jekyll-include-cache/tag" + autoload :Cache, "jekyll-include-cache/cache" + + class << self + def cache + @cache ||= if defined? Jekyll::Cache + Jekyll::Cache.new(self.class.name) + else + JekyllIncludeCache::Cache.new + end + end + + def reset + JekyllIncludeCache.cache.clear + end + end +end + +Liquid::Template.register_tag("include_cached", JekyllIncludeCache::Tag) +Jekyll::Hooks.register :site, :pre_render do |_site| + JekyllIncludeCache.reset +end diff --git a/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/cache.rb b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/cache.rb new file mode 100644 index 00000000..3bfcd86c --- /dev/null +++ b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/cache.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Jekyll 4.x comptable caching class for pre-4.x compatability +module JekyllIncludeCache + class Cache + extend Forwardable + + def_delegators :@cache, :[]=, :key?, :delete, :clear + + def initialize(_name = nil) + @cache = {} + end + + def getset(key) + if key?(key) + @cache[key] + else + value = yield + @cache[key] = value + value + end + end + + def [](key) + if key?(key) + @cache[key] + else + raise + end + end + end +end diff --git a/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/tag.rb b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/tag.rb new file mode 100644 index 00000000..6cac15f6 --- /dev/null +++ b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/tag.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "digest/md5" + +module JekyllIncludeCache + class Tag < Jekyll::Tags::IncludeTag + def self.digest_cache + @digest_cache ||= {} + end + + def render(context) + path = path(context) + params = parse_params(context) if @params + key = key(path, params) + return unless path + + if JekyllIncludeCache.cache.key?(key) + Jekyll.logger.debug "Include cache hit:", path + JekyllIncludeCache.cache[key] + else + Jekyll.logger.debug "Include cache miss:", path + JekyllIncludeCache.cache[key] = super + end + end + + private + + def path(context) + site = context.registers[:site] + file = render_variable(context) || @file + locate_include_file(context, file, site.safe) + end + + def key(path, params) + path_hash = path.hash + params_hash = quick_hash(params) + self.class.digest_cache[path_hash] ||= {} + self.class.digest_cache[path_hash][params_hash] ||= digest(path_hash, params_hash) + end + + def quick_hash(params) + return params.hash unless params + + md5 = Digest::MD5.new + + params.sort.each do |_, value| + # Using the fact that Jekyll documents don't change during a build. + # Instead of calculating the hash of an entire document (expensive!) + # we just use its object id. + if value.is_a? Jekyll::Drops::Drop + md5.update value.object_id.to_s + else + md5.update value.hash.to_s + end + end + + md5.hexdigest + end + + def digest(path_hash, params_hash) + md5 = Digest::MD5.new + md5.update path_hash.to_s + md5.update params_hash.to_s + md5.hexdigest + end + end +end diff --git a/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/version.rb b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/version.rb new file mode 100644 index 00000000..9c54ad8f --- /dev/null +++ b/bin/gems/jekyll-include-cache-0.2.1/lib/jekyll-include-cache/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module JekyllIncludeCache + VERSION = "0.2.1" +end diff --git a/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter.rb b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter.rb new file mode 100644 index 00000000..ed73199d --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "jekyll-sass-converter/version" +require "jekyll/converters/scss" +require "jekyll/converters/sass" + +module JekyllSassConverter +end diff --git a/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter/version.rb b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter/version.rb new file mode 100644 index 00000000..25c7fc03 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll-sass-converter/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module JekyllSassConverter + VERSION = "3.0.0" +end diff --git a/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/sass.rb b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/sass.rb new file mode 100644 index 00000000..7e016c8d --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/sass.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require "jekyll/converters/scss" + +module Jekyll + module Converters + class Sass < Scss + EXTENSION_PATTERN = %r!^\.sass$!i.freeze + + safe true + priority :low + + def syntax + :indented + end + end + end +end diff --git a/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/scss.rb b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/scss.rb new file mode 100644 index 00000000..0044f329 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/converters/scss.rb @@ -0,0 +1,281 @@ +# frozen_string_literal: true + +# stdlib +require "json" + +# 3rd party +require "addressable/uri" +require "sass-embedded" + +# internal +require_relative "../source_map_page" + +module Jekyll + module Converters + class Scss < Converter + EXTENSION_PATTERN = %r!^\.scss$!i.freeze + + SyntaxError = Class.new(ArgumentError) + + safe true + priority :low + + # This hook is triggered just before the method {#convert(content)} is executed, it + # associates the Scss (and Sass) converters with their respective sass_page objects. + Jekyll::Hooks.register :pages, :pre_render do |page| + next unless page.is_a?(Jekyll::Page) + + page.converters.each do |converter| + converter.associate_page(page) if converter.is_a?(Jekyll::Converters::Scss) + end + end + + # This hook is triggered just after the method {#convert(content)} has been executed, it + # dissociates the Scss (and Sass) converters with their respective sass_page objects. + Jekyll::Hooks.register :pages, :post_render do |page| + next unless page.is_a?(Jekyll::Page) + + page.converters.each do |converter| + converter.dissociate_page(page) if converter.is_a?(Jekyll::Converters::Scss) + end + end + + ALLOWED_STYLES = %w(expanded compressed).freeze + + # Associate this Converter with the "page" object that manages input and output files for + # this converter. + # + # Note: changing the associated sass_page during the live time of this Converter instance + # may result in inconsistent results. + # + # @param [Jekyll:Page] page The sass_page for which this object acts as converter. + def associate_page(page) + if @sass_page + Jekyll.logger.debug "Sass Converter:", + "sass_page re-assigned: #{@sass_page.name} to #{page.name}" + dissociate_page(page) + return + end + @sass_page = page + end + + # Dissociate this Converter with the "page" object. + # + # @param [Jekyll:Page] page The sass_page for which this object has acted as a converter. + def dissociate_page(page) + unless page.equal?(@sass_page) + Jekyll.logger.debug "Sass Converter:", + "dissociating a page that was never associated #{page.name}" + end + + @source_map_page = nil + @sass_page = nil + @site = nil + end + + def matches(ext) + ext =~ self.class::EXTENSION_PATTERN + end + + def output_ext(_ext) + ".css" + end + + def safe? + !!@config["safe"] + end + + def jekyll_sass_configuration + @jekyll_sass_configuration ||= begin + options = @config["sass"] || {} + unless options["style"].nil? + options["style"] = options["style"].to_s.delete_prefix(":").to_sym + end + options + end + end + + def syntax + :scss + end + + def sass_dir + return "_sass" if jekyll_sass_configuration["sass_dir"].to_s.empty? + + jekyll_sass_configuration["sass_dir"] + end + + def sass_style + style = jekyll_sass_configuration["style"] + ALLOWED_STYLES.include?(style.to_s) ? style.to_sym : :expanded + end + + def user_sass_load_paths + Array(jekyll_sass_configuration["load_paths"]) + end + + def sass_dir_relative_to_site_source + @sass_dir_relative_to_site_source ||= + Jekyll.sanitized_path(site_source, sass_dir).sub(site.source + "/", "") + end + + # rubocop:disable Metrics/AbcSize + def sass_load_paths + paths = user_sass_load_paths + [sass_dir_relative_to_site_source] + + # Sanitize paths to prevent any attack vectors (.e.g. `/**/*`) + paths.map! { |path| Jekyll.sanitized_path(site_source, path) } if safe? + + # Expand file globs (e.g. `node_modules/*/node_modules` ) + Dir.chdir(site_source) do + paths = paths.flat_map { |path| Dir.glob(path) } + + paths.map! do |path| + # Sanitize again in case globbing was able to do something crazy. + safe? ? Jekyll.sanitized_path(site_source, path) : File.expand_path(path) + end + end + + paths.uniq! + paths << site.theme.sass_path if site.theme&.sass_path + paths.select { |path| File.directory?(path) } + end + # rubocop:enable Metrics/AbcSize + + def sass_configs + { + :load_paths => sass_load_paths, + :charset => !associate_page_failed?, + :source_map => sourcemap_required?, + :source_map_include_sources => true, + :style => sass_style, + :syntax => syntax, + :url => sass_file_url, + :quiet_deps => quiet_deps_option, + :verbose => verbose_option, + } + end + + def convert(content) + output = ::Sass.compile_string(content, **sass_configs) + result = output.css + + if sourcemap_required? + source_map = process_source_map(output.source_map) + generate_source_map_page(source_map) + + if (sm_url = source_mapping_url) + result += "#{sass_style == :compressed ? "" : "\n\n"}/*# sourceMappingURL=#{sm_url} */" + end + end + + result + rescue ::Sass::CompileError => e + Jekyll.logger.error e.full_message + raise SyntaxError, e.message + end + + private + + # The Page instance for which this object acts as a converter. + attr_reader :sass_page + + def associate_page_failed? + !sass_page + end + + # The URL of the input scss (or sass) file. This information will be used for error reporting. + def sass_file_url + return if associate_page_failed? + + file_url_from_path(Jekyll.sanitized_path(site_source, sass_page.relative_path)) + end + + # The value of the `sourcemap` option chosen by the user. + # + # This option controls when sourcemaps shall be generated or not. + # + # Returns the value of the `sourcemap`-option chosen by the user or ':always' by default. + def sourcemap_option + jekyll_sass_configuration.fetch("sourcemap", :always).to_sym + end + + # Determines whether a sourcemap shall be generated or not. + # + # Returns `true` if a sourcemap shall be generated, `false` otherwise. + def sourcemap_required? + return false if associate_page_failed? || sourcemap_option == :never + return true if sourcemap_option == :always + + !(sourcemap_option == :development && Jekyll.env != "development") + end + + def source_map_page + return if associate_page_failed? + + @source_map_page ||= SourceMapPage.new(sass_page) + end + + # Returns the directory that source map sources are relative to. + def sass_source_root + if associate_page_failed? + site_source + else + Jekyll.sanitized_path(site_source, File.dirname(sass_page.relative_path)) + end + end + + # Converts file urls in source map to relative paths. + # + # Returns processed source map string. + def process_source_map(source_map) + map_data = JSON.parse(source_map) + unless associate_page_failed? + map_data["file"] = Addressable::URI.encode(sass_page.basename + ".css") + end + source_root_url = Addressable::URI.parse(file_url_from_path("#{sass_source_root}/")) + map_data["sources"].map! do |s| + s.start_with?("file:") ? Addressable::URI.parse(s).route_from(source_root_url).to_s : s + end + JSON.generate(map_data) + end + + # Adds the source-map to the source-map-page and adds it to `site.pages`. + def generate_source_map_page(source_map) + return if associate_page_failed? + + source_map_page.source_map(source_map) + site.pages << source_map_page + end + + # Returns a source mapping url for given source-map. + def source_mapping_url + return if associate_page_failed? + + Addressable::URI.encode(sass_page.basename + ".css.map") + end + + def site + associate_page_failed? ? Jekyll.sites.last : sass_page.site + end + + def site_source + site.source + end + + def file_url_from_path(path) + Addressable::URI.encode("file://#{path.start_with?("/") ? "" : "/"}#{path}") + end + + # Returns the value of the `quiet_deps`-option chosen by the user or 'false' by default. + def quiet_deps_option + !!jekyll_sass_configuration.fetch("quiet_deps", false) + end + + # Returns the value of the `verbose`-option chosen by the user or 'false' by default. + def verbose_option + !!jekyll_sass_configuration.fetch("verbose", false) + end + end + end +end diff --git a/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/source_map_page.rb b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/source_map_page.rb new file mode 100644 index 00000000..26f46bf6 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.0.0/lib/jekyll/source_map_page.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Jekyll + # A Jekyll::Page subclass to manage the source map file associated with + # a given scss / sass page. + class SourceMapPage < Page + # Initialize a new SourceMapPage. + # + # @param [Jekyll::Page] css_page The Page object that manages the css file. + def initialize(css_page) + @site = css_page.site + @dir = css_page.dir + @data = css_page.data + @name = css_page.basename + ".css.map" + + process(@name) + Jekyll::Hooks.trigger :pages, :post_init, self + end + + def source_map(map) + self.content = map + end + + def ext + ".map" + end + + def asset_file? + true + end + + def render_with_liquid? + false + end + + # @return[String] the object as a debug String. + def inspect + "#<#{self.class} @name=#{name.inspect}>" + end + end +end diff --git a/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter.rb b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter.rb new file mode 100644 index 00000000..ed73199d --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "jekyll-sass-converter/version" +require "jekyll/converters/scss" +require "jekyll/converters/sass" + +module JekyllSassConverter +end diff --git a/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter/version.rb b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter/version.rb new file mode 100644 index 00000000..2e30a795 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll-sass-converter/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module JekyllSassConverter + VERSION = "3.1.0" +end diff --git a/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/sass.rb b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/sass.rb new file mode 100644 index 00000000..6a63b340 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/sass.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require "jekyll/converters/scss" + +module Jekyll + module Converters + class Sass < Scss + EXTENSION_PATTERN = %r!^\.sass$!i + + safe true + priority :low + + def syntax + :indented + end + end + end +end diff --git a/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/scss.rb b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/scss.rb new file mode 100644 index 00000000..12132a33 --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/converters/scss.rb @@ -0,0 +1,308 @@ +# frozen_string_literal: true + +# stdlib +require "json" + +# 3rd party +require "addressable/uri" +require "sass-embedded" + +# internal +require_relative "../source_map_page" + +module Jekyll + module Converters + class Scss < Converter + EXTENSION_PATTERN = %r!^\.scss$!i + + SyntaxError = Class.new(ArgumentError) + + safe true + priority :low + + # This hook is triggered just before the method {#convert(content)} is executed, it + # associates the Scss (and Sass) converters with their respective sass_page objects. + Jekyll::Hooks.register :pages, :pre_render do |page| + next unless page.is_a?(Jekyll::Page) + + page.converters.each do |converter| + converter.associate_page(page) if converter.is_a?(Jekyll::Converters::Scss) + end + end + + # This hook is triggered just after the method {#convert(content)} has been executed, it + # dissociates the Scss (and Sass) converters with their respective sass_page objects. + Jekyll::Hooks.register :pages, :post_render do |page| + next unless page.is_a?(Jekyll::Page) + + page.converters.each do |converter| + converter.dissociate_page(page) if converter.is_a?(Jekyll::Converters::Scss) + end + end + + ALLOWED_STYLES = %w(expanded compressed).freeze + + # Associate this Converter with the "page" object that manages input and output files for + # this converter. + # + # Note: changing the associated sass_page during the live time of this Converter instance + # may result in inconsistent results. + # + # @param [Jekyll:Page] page The sass_page for which this object acts as converter. + def associate_page(page) + if @sass_page + Jekyll.logger.debug "Sass Converter:", + "sass_page re-assigned: #{@sass_page.name} to #{page.name}" + dissociate_page(page) + return + end + @sass_page = page + end + + # Dissociate this Converter with the "page" object. + # + # @param [Jekyll:Page] page The sass_page for which this object has acted as a converter. + def dissociate_page(page) + unless page.equal?(@sass_page) + Jekyll.logger.debug "Sass Converter:", + "dissociating a page that was never associated #{page.name}" + end + + @source_map_page = nil + @sass_page = nil + @site = nil + end + + def matches(ext) + ext =~ self.class::EXTENSION_PATTERN + end + + def output_ext(_ext) + ".css" + end + + def safe? + !!@config["safe"] + end + + def jekyll_sass_configuration + @jekyll_sass_configuration ||= begin + options = @config["sass"] || {} + unless options["style"].nil? + options["style"] = options["style"].to_s.delete_prefix(":").to_sym + end + options + end + end + + def syntax + :scss + end + + def sass_dir + return "_sass" if jekyll_sass_configuration["sass_dir"].to_s.empty? + + jekyll_sass_configuration["sass_dir"] + end + + def sass_style + style = jekyll_sass_configuration["style"] + ALLOWED_STYLES.include?(style.to_s) ? style.to_sym : :expanded + end + + def user_sass_load_paths + Array(jekyll_sass_configuration["load_paths"]) + end + + def sass_dir_relative_to_site_source + @sass_dir_relative_to_site_source ||= + Jekyll.sanitized_path(site_source, sass_dir).delete_prefix("#{site.source}/") + end + + # rubocop:disable Metrics/AbcSize + def sass_load_paths + paths = user_sass_load_paths + [sass_dir_relative_to_site_source] + + # Sanitize paths to prevent any attack vectors (.e.g. `/**/*`) + paths.map! { |path| Jekyll.sanitized_path(site_source, path) } if safe? + + # Expand file globs (e.g. `node_modules/*/node_modules` ) + Dir.chdir(site_source) do + paths = paths.flat_map { |path| Dir.glob(path) } + + paths.map! do |path| + # Sanitize again in case globbing was able to do something crazy. + safe? ? Jekyll.sanitized_path(site_source, path) : File.expand_path(path) + end + end + + paths.uniq! + paths << site.theme.sass_path if site.theme&.sass_path + paths.select { |path| File.directory?(path) } + end + # rubocop:enable Metrics/AbcSize + + def sass_configs + { + :load_paths => sass_load_paths, + :charset => !associate_page_failed?, + :source_map => sourcemap_required?, + :source_map_include_sources => true, + :style => sass_style, + :syntax => syntax, + :url => sass_file_url, + :quiet_deps => quiet_deps_option, + :verbose => verbose_option, + :fatal_deprecations => fatal_deprecations, + :future_deprecations => future_deprecations, + :silence_deprecations => silence_deprecations, + } + end + + def convert(content) + output = ::Sass.compile_string(content, **sass_configs) + result = output.css + + if sourcemap_required? + source_map = process_source_map(output.source_map) + generate_source_map_page(source_map) + + if (sm_url = source_mapping_url) + result += "#{sass_style == :compressed ? "" : "\n\n"}/*# sourceMappingURL=#{sm_url} */" + end + end + + result + rescue ::Sass::CompileError => e + Jekyll.logger.error e.full_message + if livereload? + e.to_css # Render error message in browser window + else + raise SyntaxError, e.message + end + end + + private + + # The Page instance for which this object acts as a converter. + attr_reader :sass_page + + def associate_page_failed? + !sass_page + end + + # Returns `true` if jekyll is serving with livereload. + def livereload? + !!(@config["serving"] && @config["livereload"]) + end + + # The URL of the input scss (or sass) file. This information will be used for error reporting. + def sass_file_url + return if associate_page_failed? + + file_url_from_path(Jekyll.sanitized_path(site_source, sass_page.relative_path)) + end + + # The value of the `sourcemap` option chosen by the user. + # + # This option controls when sourcemaps shall be generated or not. + # + # Returns the value of the `sourcemap`-option chosen by the user or ':always' by default. + def sourcemap_option + jekyll_sass_configuration.fetch("sourcemap", :always).to_sym + end + + # Determines whether a sourcemap shall be generated or not. + # + # Returns `true` if a sourcemap shall be generated, `false` otherwise. + def sourcemap_required? + return false if associate_page_failed? || sourcemap_option == :never + return true if sourcemap_option == :always + + !(sourcemap_option == :development && Jekyll.env != "development") + end + + def source_map_page + return if associate_page_failed? + + @source_map_page ||= SourceMapPage.new(sass_page) + end + + # Returns the directory that source map sources are relative to. + def sass_source_root + if associate_page_failed? + site_source + else + Jekyll.sanitized_path(site_source, File.dirname(sass_page.relative_path)) + end + end + + # Converts file urls in source map to relative paths. + # + # Returns processed source map string. + def process_source_map(source_map) + map_data = JSON.parse(source_map) + unless associate_page_failed? + map_data["file"] = Addressable::URI.encode("#{sass_page.basename}.css") + end + source_root_url = Addressable::URI.parse(file_url_from_path("#{sass_source_root}/")) + map_data["sources"].map! do |s| + s.start_with?("file:") ? Addressable::URI.parse(s).route_from(source_root_url).to_s : s + end + JSON.generate(map_data) + end + + # Adds the source-map to the source-map-page and adds it to `site.pages`. + def generate_source_map_page(source_map) + return if associate_page_failed? + + source_map_page.source_map(source_map) + site.pages << source_map_page + end + + # Returns a source mapping url for given source-map. + def source_mapping_url + return if associate_page_failed? + + Addressable::URI.encode("#{sass_page.basename}.css.map") + end + + def site + associate_page_failed? ? Jekyll.sites.last : sass_page.site + end + + def site_source + site.source + end + + def file_url_from_path(path) + Addressable::URI.encode("file://#{path.start_with?("/") ? "" : "/"}#{path}") + end + + # Returns the value of the `quiet_deps`-option chosen by the user or 'false' by default. + def quiet_deps_option + !!jekyll_sass_configuration.fetch("quiet_deps", false) + end + + # Returns the value of the `verbose`-option chosen by the user or 'false' by default. + def verbose_option + !!jekyll_sass_configuration.fetch("verbose", false) + end + + # Returns the value of the `fatal_deprecations`-option or '[]' by default. + def fatal_deprecations + Array(jekyll_sass_configuration["fatal_deprecations"]) + end + + # Returns the value of the `future_deprecations`-option or '[]' by default. + def future_deprecations + Array(jekyll_sass_configuration["future_deprecations"]) + end + + # Returns the value of the `silence_deprecations`-option or '[]' by default. + def silence_deprecations + Array(jekyll_sass_configuration["silence_deprecations"]) + end + end + end +end diff --git a/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/source_map_page.rb b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/source_map_page.rb new file mode 100644 index 00000000..de9a2dfd --- /dev/null +++ b/bin/gems/jekyll-sass-converter-3.1.0/lib/jekyll/source_map_page.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Jekyll + # A Jekyll::Page subclass to manage the source map file associated with + # a given scss / sass page. + class SourceMapPage < Page + # Initialize a new SourceMapPage. + # + # @param [Jekyll::Page] css_page The Page object that manages the css file. + def initialize(css_page) + @site = css_page.site + @dir = css_page.dir + @data = css_page.data + @name = "#{css_page.basename}.css.map" + + process(@name) + Jekyll::Hooks.trigger :pages, :post_init, self + end + + def source_map(map) + self.content = map + end + + def ext + ".map" + end + + def asset_file? + true + end + + def render_with_liquid? + false + end + + # @return[String] the object as a debug String. + def inspect + "#<#{self.class} @name=#{name.inspect}>" + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/ci.yml b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/ci.yml new file mode 100644 index 00000000..75291c85 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/ci.yml @@ -0,0 +1,103 @@ +name: Continuous Integration + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + j4: + if: "!contains(github.event.commits[0].message, '[ci skip]')" + name: "Jekyll ${{ matrix.jekyll_version }} (Ruby ${{ matrix.ruby_version }})" + runs-on: 'ubuntu-latest' + env: + JEKYLL_VERSION: ${{ matrix.jekyll_version }} + strategy: + fail-fast: false + matrix: + ruby_version: + - 2.5 + - 2.7 + - 3.0 + jekyll_version: + - "~> 4.0" + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 5 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Execute tests + run: bundle exec rspec + j3: + if: "!contains(github.event.commits[0].message, '[ci skip]')" + name: "Jekyll ${{ matrix.jekyll_version }} (Ruby ${{ matrix.ruby_version }})" + runs-on: 'ubuntu-latest' + env: + JEKYLL_VERSION: ${{ matrix.jekyll_version }} + strategy: + fail-fast: false + matrix: + ruby_version: + - 2.5 + jekyll_version: + - "~> 3.9" + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 5 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Execute tests + run: bundle exec rspec + + style_check: + if: "!contains(github.event.commits[0].message, '[ci skip]')" + name: "Code Style Check (Ruby ${{ matrix.ruby_version }})" + runs-on: 'ubuntu-latest' + strategy: + fail-fast: false + matrix: + ruby_version: + - 2.5 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 5 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Check Style Offenses + run: bundle exec rubocop -S -D + + gem_build: + if: "!contains(github.event.commits[0].message, '[ci skip]')" + name: "Test Gem build (Ruby ${{ matrix.ruby_version }})" + runs-on: 'ubuntu-latest' + strategy: + fail-fast: false + matrix: + ruby_version: + - 2.5 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 5 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Test Gem build + run: bundle exec gem build jekyll-seo-tag.gemspec diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/release.yml b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/release.yml new file mode 100644 index 00000000..af07ea66 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/release.yml @@ -0,0 +1,33 @@ +name: Release Gem + +on: + push: + branches: + - master + paths: + - "lib/**/version.rb" + +jobs: + release: + if: "github.repository_owner == 'jekyll'" + name: "Release Gem (Ruby ${{ matrix.ruby_version }})" + runs-on: "ubuntu-latest" + strategy: + fail-fast: true + matrix: + ruby_version: + - 2.7 + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Build and Publish Gem + uses: ashmaroli/release-gem@dist + with: + gemspec_name: jekyll-seo-tag + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_GEM_PUSH_API_KEY }} diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof new file mode 100644 index 00000000..2f067867 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +bundle exec ruby jekyll-seo-tag/.github/workflows/scripts/memprof.rb sandbox +exit 0 diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof.rb b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof.rb new file mode 100644 index 00000000..45143d8b --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/scripts/memprof.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'jekyll' +require 'memory_profiler' + +MemoryProfiler.report(allow_files: 'lib/jekyll-seo-tag') do + Jekyll::PluginManager.require_from_bundler + Jekyll::Commands::Build.process({ + "source" => File.expand_path(ARGV[0]), + "destination" => File.expand_path("#{ARGV[0]}/_site"), + "disable_disk_cache" => true, + }) + puts '' +end.pretty_print(scale_bytes: true, normalize_paths: true) diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/third-party.yml b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/third-party.yml new file mode 100644 index 00000000..d98e371e --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.github/workflows/third-party.yml @@ -0,0 +1,62 @@ +name: Third-Party Repository Profiling + +on: + push: + branches: + - master + pull_request: + branches: + - master +jobs: + build_n_profile: + name: "Third-Party Repo Profile (Jekyll ${{ matrix.jekyll_version }}, Ruby ${{ matrix.ruby_version }})" + runs-on: "ubuntu-latest" + strategy: + fail-fast: false + matrix: + ruby_version: + - 2.7 + jekyll_version: + - "~> 4.0" + - "~> 3.9" + env: + BUNDLE_GEMFILE: "sandbox/Gemfile" + BUNDLE_PATH: "vendor/bundle" + BUNDLE_JOBS: 4 + BUNDLE_RETRY: 3 + JEKYLL_VERSION: ${{ matrix.jekyll_version }} + steps: + - name: Checkout Jekyll SEO Tag + uses: actions/checkout@v2 + with: + fetch-depth: 5 + path: jekyll-seo-tag + - name: Checkout Third-Party Repository (WITHOUT SEO Tag) + uses: actions/checkout@v2 + with: + repository: ashmaroli/tomjoht.github.io + ref: "no-seo-tag" + path: alpha-sandbox + - name: Checkout Same Third-Party Repository (WITH SEO Tag) + uses: actions/checkout@v2 + with: + repository: ashmaroli/tomjoht.github.io + ref: "seo-tag" + path: sandbox + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Run Jekyll Build (WITHOUT SEO Tag) 3 times + run: | + bundle exec jekyll build -s alpha-sandbox -d alpha-sandbox/_site --trace + bundle exec jekyll build -s alpha-sandbox -d alpha-sandbox/_site --trace + bundle exec jekyll build -s alpha-sandbox -d alpha-sandbox/_site --trace + - name: Run Jekyll Build (WITH SEO Tag) 3 times + run: | + bundle exec jekyll build -s sandbox -d sandbox/_site --trace + bundle exec jekyll build -s sandbox -d sandbox/_site --trace + bundle exec jekyll build -s sandbox -d sandbox/_site --trace + - name: Memory Analysis of Jekyll Build (WITH SEO Tag) + run: bash jekyll-seo-tag/.github/workflows/scripts/memprof diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.gitignore b/bin/gems/jekyll-seo-tag-2.8.0/.gitignore new file mode 100644 index 00000000..6256dfa7 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.gitignore @@ -0,0 +1,9 @@ +*.gem +.bundle +.yardoc +Gemfile.lock +pkg +spec/reports/ +spec/fixtures/.jekyll-cache +tmp/ +vendor/bundle diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.rspec b/bin/gems/jekyll-seo-tag-2.8.0/.rspec new file mode 100644 index 00000000..83e16f80 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.rubocop.yml b/bin/gems/jekyll-seo-tag-2.8.0/.rubocop.yml new file mode 100644 index 00000000..6688e6d8 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.rubocop.yml @@ -0,0 +1,42 @@ +inherit_from: .rubocop_todo.yml + +require: rubocop-jekyll +inherit_gem: + rubocop-jekyll: .rubocop.yml + +AllCops: + TargetRubyVersion: 2.5 + SuggestExtensions: false + Exclude: + - vendor/**/* + +Layout/LineEndStringConcatenationIndentation: + Enabled: true +Layout/LineLength: + Exclude: + - spec/**/* + - jekyll-seo-tag.gemspec + +Lint/EmptyInPattern: + Enabled: false + +Metrics/BlockLength: + Exclude: + - spec/**/* + +Naming/InclusiveLanguage: + Enabled: false + +Performance/MapCompact: + Enabled: true +Performance/RedundantEqualityComparisonBlock: + Enabled: true +Performance/RedundantSplitRegexpArgument: + Enabled: true + +Style/InPatternThen: + Enabled: false +Style/MultilineInPatternThen: + Enabled: false +Style/QuotedSymbols: + Enabled: true diff --git a/bin/gems/jekyll-seo-tag-2.8.0/.rubocop_todo.yml b/bin/gems/jekyll-seo-tag-2.8.0/.rubocop_todo.yml new file mode 100644 index 00000000..59fd59ba --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/.rubocop_todo.yml @@ -0,0 +1,46 @@ +# This configuration was generated by +# `rubocop --auto-gen-config --auto-gen-only-exclude` +# on 2021-09-17 06:40:32 UTC using RuboCop version 1.18.4. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# Configuration parameters: AllowComments. +Lint/EmptyClass: + Exclude: + - 'lib/jekyll-seo-tag/version.rb' + +# Offense count: 3 +Lint/NoReturnInBeginEndBlocks: + Exclude: + - 'lib/jekyll-seo-tag/author_drop.rb' + - 'lib/jekyll-seo-tag/drop.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Lint/ToJSON: + Exclude: + - 'lib/jekyll-seo-tag/json_ld_drop.rb' + +# Offense count: 1 +# Configuration parameters: IgnoredMethods, Max. +Metrics/PerceivedComplexity: + Exclude: + - 'lib/jekyll-seo-tag/drop.rb' + +# Offense count: 1 +# Configuration parameters: MinSize. +Performance/CollectionLiteralInLoop: + Exclude: + - 'spec/jekyll_seo_tag/author_drop_spec.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +Style/RedundantBegin: + Exclude: + - 'lib/jekyll-seo-tag.rb' + - 'lib/jekyll-seo-tag/author_drop.rb' + - 'lib/jekyll-seo-tag/drop.rb' + - 'lib/jekyll-seo-tag/image_drop.rb' diff --git a/bin/gems/jekyll-seo-tag-2.8.0/Gemfile b/bin/gems/jekyll-seo-tag-2.8.0/Gemfile new file mode 100644 index 00000000..40f83de9 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +gem "jekyll", ENV["JEKYLL_VERSION"] if ENV["JEKYLL_VERSION"] +gem "kramdown-parser-gfm" if ENV["JEKYLL_VERSION"] == "~> 3.9" diff --git a/bin/gems/jekyll-seo-tag-2.8.0/History.markdown b/bin/gems/jekyll-seo-tag-2.8.0/History.markdown new file mode 100644 index 00000000..101289e9 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/History.markdown @@ -0,0 +1,215 @@ +## 2.8.0 / 2022-02-04 + +### Minor Enhancements + + * Allow to set type for author (#427) + * Allow setting `author.url` (#453) + * Implement Facebook domain verification (#455) + * Add `og:image:alt` and `twitter:image:alt` (#438) + * Sort JSON-LD data by key (#458) + +### Bug Fixes + + * Set the default `og:type` to 'website' (#391) + * Template: Remove double new line (#454) + +### Development Fixes + + * Fix typo in source code comment (#449) + * Set up Continuous Integration via GH Actions (#450) + * Bump RuboCop to v1.18.x (#452) + * Add workflow to release gem via GH Actions + +## 2.7.1 / 2020-10-18 + +### Development Fixes + + * refactor: mutate site payload instead of duplicating it (#419) + +## 2.7.0 / 2020-10-18 + +### Minor Enhancements + + * Change pagination message with `seo_paginator_message` option (#324) + * Make Twitter Summary Card without having Twitter account (#284) + * Prefer site.tagline to site.description for page title (#356) + * Render og:locale meta only when defined explicitly (#388) + +### Bug Fixes + + * Ensure a single leading `@` for twitter usernames (#367) + +### Development Fixes + + * chore(deps): require Ruby > 2.4.0 EOL + * test: fix locale specs that use the fallback locale (#360) + * refactor: Replace read-only empty hash with private constant (#418) + * refactor: Mutate hash literals instead of duplicating them (#417) + * refactor: Reduce allocations of instance-agnostic objects (#376) + * refactor: Memoize #author_hash in SeoTag::AuthorDrop (#342) + * refactor: simplify conditional in SeoTag::Drop#date_modified (#343) + * chore(ci): profile seo-tag plugin on a third-party repository (#414) + * chore(ci): Jekyll v4.0 (#372) + * chore(ci): test against current stable Ruby 2.5 and 2.7 (#385) + * style: align with latest jekyll-rubocop (#382) + * fix: Travis builds for Jekyll 3.x (#415) + +### Documentation + + * Structured Data Testing Tool is deprecated (#409) + * Rename Google webmaster tools to Google Search Console (#403) + * Improve documentation on plugin usage (#399) + * remove Google+ from example snippet (#358) + * HTTPS link to https://ogp.me/ (#359) + * HTTPS links to schema.org (#350) + * use example.com for example URL (#351) + +## 2.6.1 / 2019-05-17 + +### Development Fixes + + * Test against Jekyll 4.x (#336) + +## 2.6.0 / 2019-03-16 + +### Minor Enhancements + + * Twitter Image and Title (#330) + +### Bug Fixes + + * Do not cache the drop payload for SeoTag (#306) + * Update url of schema website (#296) + +### Development Fixes + + * Relax version constraint on Bundler (#325) + * chore(ci): Add Ruby 2.6, drop Ruby 2.3 (#326) + * chore (ci): remove deprecated `sudo: false` in .travis.yml (#333) + * Lint Ruby code with rubocop-jekyll gem (#302) + * chore(deps): bump rubocop-jekyll to v0.4 (#320) + * chore(deps): bump rubocop-jekyll to v0.3 (#316) + * Correct RuboCop offenses in spec files (#319) + +### Documentation + + * Rectify error in Usage documentation (#328) + +## 2.5.0 / 2018-05-18 + + * Docs: Prevent GitHub Pages from processing Liquid raw tag (#276) + +### Documentation + + * Use gems config key for Jekyll < 3.5.0 (#255) + * docs/usage - replace "below" with correct link (#280) + +### Development Fixes + + * Test against Ruby 2.5 (#260) + * add tests for twitter.card types (#289) + * Target Ruby 2.3 and Rubocop 0.56.0 (#292) + +### Minor Enhancements + + * Add webmaster_verifications for baidu (#263) + * Include page number in title (#250) + * Configure default Twitter summary card type (V2) (#225) + +## 2.4.0 / 2017-12-04 + +### Minor + + * Add meta generator (#236) + * Consistently use self-closing tags (#246) + * Strip null values from JSON-LD hash (#249) + +### Documentation + + * Avoid deprecation warning when building docs (#243) + +### Development Fixes + + * Test against latest Rubies (#242) + * Use Nokigiri on CI (#181) + +## 2.3.0 + +### Minor Enhancements + + * Use canonical_url specified in page if present #211 + * Fix for image.path causing an invalid url error #228 + * Ensure `site.data.authors` is properly formatted before attempting to retrieve author meta #227 + * Convert author, image, and JSON-LD to dedicated drops #229 + * Cache parsed template #231 + * Define path with `__dir__` #232 + +### Documentation + + * gems: is deprecated in current Jekyll version of github-pages #230 + +## 2.2.3 + + * Guard against the author's Twitter handle being Nil when stripping @'s #203 + * Guard against empty title or description strings #206 + +## 2.2.2 + +### Minor Enhancements + + * Guard against arrays in subhashes #197 + * Guard against invalid or missing URLs #199 + +### Development fixes + + * Remove dynamic GitHub Pages logic from Gemfile #194 + +## 2.2.1 + + * Convert template logic to a Liquid Drop (significant performance improvement) (#184) + * Fix for JSON-LD validation warning for images missing required properties (#183) + +## 2.2.0 + +### Major Enhancements + + * Add author meta (#103) + * Add og:locale support #166 + * Add support for Bing and Yandex webmaster tools. Closes #147 (#148) + * Add SEO author and date modified to validate JSON-LD output (#151) + +### Minor Enhancements + + * Use `|` for title separator (#162) + * Use `og:image` for twitter image (#174) + +### Development Fixes + + * Style fixes (#170, #157, #149) + * Test against latest version of Jekyll (#171) + * Bump dev dependencies (#172) + * Remove Rake dependency (#180) + +## 2.1.0 + +### Major Enhancement + + * Use new URL filters (#123) + +### Minor Enhancements + + * Wraps logo image json data in a publisher property (#133) + * Fix duplicated `escape_once` (#93) + * Simplify minify regex (#125) + * Don't mangle text with newlines #126 + +### Documentation + + * Add front matter default example for image (#132) + * Fix tiny typo (#106) + * add example usage of social profiles (#139) + +### Development + + * Inherit Jekyll's rubocop config for consistency (#109) + * Correct spelling in .travis.yml (#112) diff --git a/bin/gems/jekyll-seo-tag-2.8.0/LICENSE.txt b/bin/gems/jekyll-seo-tag-2.8.0/LICENSE.txt new file mode 100644 index 00000000..3b5c0a6e --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-present Ben Balter and the jekyll-seo-tag 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/bin/gems/jekyll-seo-tag-2.8.0/docs/README.md b/bin/gems/jekyll-seo-tag-2.8.0/docs/README.md new file mode 100644 index 00000000..9a9557de --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/README.md @@ -0,0 +1,33 @@ +## About Jekyll SEO Tag + +A Jekyll plugin to add metadata tags for search engines and social networks to better index and display your site's content. + +[![Gem Version](https://badge.fury.io/rb/jekyll-seo-tag.svg)](https://badge.fury.io/rb/jekyll-seo-tag) [![Build Status](https://travis-ci.org/jekyll/jekyll-seo-tag.svg)](https://travis-ci.org/jekyll/jekyll-seo-tag) + +## What it does + +Jekyll SEO Tag adds the following meta tags to your site: + +* Page title, with site title or description appended +* Page description +* Canonical URL +* Next and previous URLs on paginated pages +* [JSON-LD Site and post metadata](https://developers.google.com/search/docs/guides/intro-structured-data) for richer indexing +* [Open Graph](https://ogp.me/) title, description, site title, and URL (for Facebook, LinkedIn, etc.) +* [Twitter Summary Card](https://dev.twitter.com/cards/overview) metadata + +While you could theoretically add the necessary metadata tags yourself, Jekyll SEO Tag provides a battle-tested template of crowdsourced best-practices. + +## What it doesn't do + +Jekyll SEO tag is designed to output machine-readable metadata for search engines and social networks to index and display. If you're looking for something to analyze your Jekyll site's structure and content (e.g., more traditional SEO optimization), take a look at [The Jekyll SEO Gem](https://github.com/pmarsceill/jekyll-seo-gem). + +Jekyll SEO tag isn't designed to accommodate every possible use case. It should work for most site out of the box and without a laundry list of configuration options that serve only to confuse most users. + +## Documentation + +For more information, see: + +* [Installation](installation.md) +* [Usage](usage.md) +* [Advanced usage](advanced-usage.md) diff --git a/bin/gems/jekyll-seo-tag-2.8.0/docs/_config.yml b/bin/gems/jekyll-seo-tag-2.8.0/docs/_config.yml new file mode 100644 index 00000000..286cdd04 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/_config.yml @@ -0,0 +1,10 @@ +title: Jekyll SEO Tag +description: A Jekyll plugin to add metadata tags for search engines and social networks to better index and display your site's content. + +permalink: pretty + +plugins: + - jekyll-seo-tag + - jekyll-sitemap + +theme: jekyll-theme-primer diff --git a/bin/gems/jekyll-seo-tag-2.8.0/docs/_layouts/default.html b/bin/gems/jekyll-seo-tag-2.8.0/docs/_layouts/default.html new file mode 100644 index 00000000..da8eec83 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/_layouts/default.html @@ -0,0 +1,18 @@ + + + + + + + {% seo %} + + +
+

{{ site.title }}

+ + {{ content }} +
+ + + + diff --git a/bin/gems/jekyll-seo-tag-2.8.0/docs/advanced-usage.md b/bin/gems/jekyll-seo-tag-2.8.0/docs/advanced-usage.md new file mode 100644 index 00000000..f3344961 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/advanced-usage.md @@ -0,0 +1,170 @@ +## Advanced usage + +Jekyll SEO Tag is designed to implement SEO best practices by default and to be the right fit for most sites right out of the box. If for some reason, you need more control over the output, read on: + +### Disabling `` output + +If for some reason, you don't want the plugin to output `<title>` tags on each page, simply invoke the plugin within your template like so: + +<!-- {% raw %} --> +``` +{% seo title=false %} +``` +<!-- {% endraw %} --> + +### Author information + +Author information is used to propagate the `creator` field of Twitter summary cards. This should be an author-specific, not site-wide Twitter handle (the site-wide username be stored as `site.twitter.username`). + +*TL;DR: In most cases, put `author: [your Twitter handle]` in the document's front matter, for sites with multiple authors. If you need something more complicated, read on.* + +There are several ways to convey this author-specific information. Author information is found in the following order of priority: + +1. An `author` object, in the documents's front matter, e.g.: + + ```yml + author: + twitter: benbalter + ``` + +2. An `author` object, in the site's `_config.yml`, e.g.: + + ```yml + author: + twitter: benbalter + ``` + +3. `site.data.authors[author]`, if an author is specified in the document's front matter, and a corresponding key exists in `site.data.authors`. E.g., you have the following in the document's front matter: + + ```yml + author: benbalter + ``` + + And you have the following in `_data/authors.yml`: + + ```yml + benbalter: + picture: /img/benbalter.png + twitter: jekyllrb + + potus: + picture: /img/potus.png + twitter: whitehouse + ``` + + In the above example, the author `benbalter`'s Twitter handle will be resolved to `@jekyllrb`. This allows you to centralize author information in a single `_data/authors` file for site with many authors that require more than just the author's username. + + *Pro-tip: If `authors` is present in the document's front matter as an array (and `author` is not), the plugin will use the first author listed, as Twitter supports only one author.* + +4. An author in the document's front matter (the simplest way), e.g.: + + ```yml + author: benbalter + ``` + +5. An author in the site's `_config.yml`, e.g.: + + ```yml + author: benbalter + ``` + +#### Setting author url + +Starting from August 6, 2021 [Google recommends](https://developers.google.com/search/updates) to set the `author.url` property. This property helps Google to disambiguate the correct author of the article. + +You can set it the same way as the other author properties. For example, you can put it in an `author` object, in the site's `_config.yml`, e.g.: + + ```yml + author: + name: My Name + url: https://example.com/ + ``` + +### Customizing JSON-LD output + +The following options can be set for any particular page. While the default options are meant to serve most users in the most common circumstances, there may be situations where more precise control is necessary. + +* `seo` + * `name` - If the name of the thing that the page represents is different from the page title. (i.e.: "Frank's Café" vs "Welcome to Frank's Café") + * `type` - The type of things that the page represents. This must be a [Schema.org type](https://schema.org/docs/schemas.html), and will probably usually be something like [`BlogPosting`](https://schema.org/BlogPosting), [`NewsArticle`](https://schema.org/NewsArticle), [`Person`](https://schema.org/Person), [`Organization`](https://schema.org/Organization), etc. + * `links` - An array of other URLs that represent the same thing that this page represents. For instance, Jane's bio page might include links to Jane's GitHub and Twitter profiles. + * `date_modified` - Manually specify the `dateModified` field in the JSON-LD output to override Jekyll's own `dateModified`. + This field will take **first priority** for the `dateModified` JSON-LD output. This is useful when the file timestamp does not match the true time that the content was modified. A user may also install [Last Modified At](https://github.com/gjtorikian/jekyll-last-modified-at) which will offer an alternative way of providing for the `dateModified` field. + +### Customizing image output + +For most users, setting `image: [path-to-image]` on a per-page basis should be enough. If you need more control over how images are represented, the `image` property can also be an object, with the following options: + +* `path` - The relative path to the image. Same as `image: [path-to-image]` +* `height` - The height of the Open Graph (`og:image`) image +* `width` - The width of the Open Graph (`og:image`) image +* `alt` - The alternative image text for Open Graph (`og:image:alt`) and Twitter (`twitter:image:alt`) + +You can use any of the above, optional properties, like so: + +```yml +image: + path: /img/twitter.png + height: 100 + width: 100 + alt: Twitter Logo +``` + +### Setting a default image + +You can define a default image using [Front Matter defaults](https://jekyllrb.com/docs/configuration/front-matter-defaults/), to provide a default Twitter Card or OGP image to all of your posts and pages. + +Here is a very basic example, that you are encouraged to adapt to your needs: + +```yml +defaults: + - scope: + path: "" + values: + image: /assets/images/default-card.png +``` + +### SmartyPants Titles + +Titles will be processed using [Jekyll's `smartify` filter](https://jekyllrb.com/docs/liquid/filters/). This will use SmartyPants to translate plain ASCII punctuation into "smart" typographic punctuation. This will not render or strip any Markdown you may be using in a page title. + +### Setting customized Canonical URL + +You can set custom Canonical URL for a page by specifying canonical_url option in page front matter. +E.g., you have the following in the page's front matter: +```yml +layout: post +title: Title of Your Post +canonical_url: 'https://github.com/jekyll/jekyll-seo-tag/' +``` + +Which will generate canonical_url with specified link in canonical_url. +```html +<link rel="canonical" href="https://github.com/jekyll/jekyll-seo-tag/" /> +``` + +If no canonical_url option was specified, then uses page url for generating canonical_url. +E.g., you have not specified canonical_url in front matter: +```yml +layout: post +title: Title of Your Post +``` + +Which will generate following canonical_url: +```html +<link rel="canonical" href="https://example.com/title-of-your-post" /> +``` + +### Customizing title modifier for paginated pages + +You can override the default title modifier for paginated pages from `Page %{current} of %{total} for ` to a string of your +choice by setting a `seo_paginator_message` key in your `_config.yml`. + +For example: + +```yml +seo_paginator_message: "%<current>s / %<total>s | " +``` + +While the value can be any string text, we recommend using a Ruby string-template containing the variables `current` and `total` +similar to the example above, to incorporate the current page-number and total number of paginated pages in the title. diff --git a/bin/gems/jekyll-seo-tag-2.8.0/docs/installation.md b/bin/gems/jekyll-seo-tag-2.8.0/docs/installation.md new file mode 100644 index 00000000..4a913403 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/installation.md @@ -0,0 +1,24 @@ +# Installing Jekyll SEO Tag + +1. Add the following to your site's `Gemfile`: + + ```ruby + gem 'jekyll-seo-tag' + ``` + +2. Add the following to your site's `_config.yml`: + + ```yml + plugins: + - jekyll-seo-tag + ``` + +If you are using a Jekyll version less than `3.5.0`, use the `gems` key instead of `plugins`. + +3. Add the following right before `</head>` in your site's template(s): + +<!-- {% raw %} --> + ```liquid + {% seo %} + ``` +<!-- {% endraw %} --> diff --git a/bin/gems/jekyll-seo-tag-2.8.0/docs/usage.md b/bin/gems/jekyll-seo-tag-2.8.0/docs/usage.md new file mode 100644 index 00000000..20dbd418 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/docs/usage.md @@ -0,0 +1,81 @@ +## Usage + +The SEO tag will respect any of the following if included in your site's `_config.yml` (and simply not include them if +they're not defined): + +* `title` - Your site's title (e.g., *Ben's Awesome Site*, *The GitHub Blog*, etc.), used as part of the title tag like +`Home | Ben's Awesome Site`. +* `tagline` - A short description (e.g., *A blog dedicated to reviewing cat gifs*), used as part of the title tag like +`Ben's Awesome Site | A blog dedicated to reviewing cat gifs` instead of `Ben's Awesome Site | Long description about a +blog dedicated to reviewing cat gifs` that would be used when `page.title` is not defined. +* `description` - A longer description used for the description meta tag. Also used as fallback for pages that don't +provide their own `description`, and also as part of the page's title tag if neither `page.title` nor `site.tagline` +has been defined. +* `url` - The full URL to your site. Note: `site.github.url` will be used by default. +* `author` - global author information (see [Advanced usage](advanced-usage.md#author-information)) +* `twitter` - The following properties are available: + * `twitter:card` - The site's default card type + * `twitter:username` - The site's Twitter handle. + + You'll want to describe them like so: + + ```yml + twitter: + username: benbalter + card: summary + ``` +* `facebook` - The following properties are available: + * `facebook:app_id` - a Facebook app ID for Facebook insights + * `facebook:publisher` - a Facebook page URL or ID of the publishing entity + * `facebook:admins` - a Facebook user ID for domain insights linked to a personal account + + You'll want to describe one or more like so: + + ```yml + facebook: + app_id: 1234 + publisher: 1234 + admins: 1234 + ``` +* `logo` - URL to a site-wide logo (e.g., `/assets/your-company-logo.png`) - If you would like the "publisher" property +to be present, you must add this field to your site's configuration, during the validation of the structured data by +Google Search Console, if the `logo` field is not validated, you will find errors inherent to the publisher in the +[Rich Results Testing Tool](https://search.google.com/test/rich-results) +* `social` - For [specifying social profiles](https://developers.google.com/search/docs/guides/enhance-site#add-your-sites-name-logo-and-social-links). +The following properties are available: + * `name` - If the user or organization name differs from the site's name + * `links` - An array of links to social media profiles. + + ```yml + social: + name: Ben Balter + links: + - https://twitter.com/BenBalter + - https://www.facebook.com/ben.balter + - https://www.linkedin.com/in/BenBalter + - https://github.com/benbalter + - https://keybase.io/benbalter + ``` +* `google_site_verification` for verifying ownership via Google Search Console +* Alternatively, verify ownership with several services at once using the following format: + ```yml + webmaster_verifications: + google: 1234 + bing: 1234 + alexa: 1234 + yandex: 1234 + baidu: 1234 + facebook: 1234 + ``` +* `locale` - The locale these tags are marked up in. Of the format `language_TERRITORY`. Default is `en_US`. Takes priority +over existing config key `lang`. + +The SEO tag will respect the following YAML front matter if included in a post, page, or document: + +* `title` - The title of the post, page, or document +* `description` - A short description of the page's content +* `image` - URL to an image associated with the post, page, or document (e.g., `/assets/page-pic.jpg`) +* `author` - Page-, post-, or document-specific author information (see [Advanced usage](advanced-usage.md#author-information)) +* `locale` - Page-, post-, or document-specific locale information. Takes priority over existing front matter attribute `lang`. + +*Note:* Front matter defaults can be used for any of the above values as described in advanced usage with an image example. diff --git a/bin/gems/jekyll-seo-tag-2.8.0/jekyll-seo-tag.gemspec b/bin/gems/jekyll-seo-tag-2.8.0/jekyll-seo-tag.gemspec new file mode 100644 index 00000000..487444b2 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/jekyll-seo-tag.gemspec @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require_relative "lib/jekyll-seo-tag/version" + +Gem::Specification.new do |spec| + spec.name = "jekyll-seo-tag" + spec.version = Jekyll::SeoTag::VERSION + spec.authors = ["Ben Balter"] + spec.email = ["ben.balter@github.com"] + spec.summary = "A Jekyll plugin to add metadata tags for search engines and social networks to better index and display your site's content." + spec.homepage = "https://github.com/jekyll/jekyll-seo-tag" + spec.license = "MIT" + + # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or + # delete this section to allow pushing this gem to any host. + if spec.respond_to?(:metadata) + spec.metadata["allowed_push_host"] = "https://rubygems.org" + else + raise "RubyGems 2.0 or newer is required to protect against public gem pushes." + end + + spec.required_ruby_version = ">= 2.5.0" + + spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|spec|features)/!) } + spec.bindir = "exe" + spec.executables = spec.files.grep(%r!^exe/!) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_dependency "jekyll", ">= 3.8", "< 5.0" + spec.add_development_dependency "bundler", ">= 1.15" + spec.add_development_dependency "html-proofer", "~> 3.7" + spec.add_development_dependency "rspec", "~> 3.5" + spec.add_development_dependency "rubocop-jekyll", "~> 0.12.0" +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag.rb new file mode 100644 index 00000000..2edafd7d --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require "jekyll" +require "jekyll-seo-tag/version" + +module Jekyll + class SeoTag < Liquid::Tag + autoload :JSONLD, "jekyll-seo-tag/json_ld" + autoload :AuthorDrop, "jekyll-seo-tag/author_drop" + autoload :ImageDrop, "jekyll-seo-tag/image_drop" + autoload :JSONLDDrop, "jekyll-seo-tag/json_ld_drop" + autoload :UrlHelper, "jekyll-seo-tag/url_helper" + autoload :Drop, "jekyll-seo-tag/drop" + autoload :Filters, "jekyll-seo-tag/filters" + + attr_accessor :context + + # Matches all whitespace that follows either + # 1. A '}', which closes a Liquid tag + # 2. A '{', which opens a JSON block + # 3. A '>' followed by a newline, which closes an XML tag or + # 4. A ',' followed by a newline, which ends a JSON line + # We will strip all of this whitespace to minify the template + # We will not strip any whitespace if the next character is a '-' + # so that we do not interfere with the HTML comment at the + # very begining + MINIFY_REGEX = %r!(?<=[{}]|[>,]\n)\s+(?\!-)!.freeze + + def initialize(_tag_name, text, _tokens) + super + @text = text + end + + def render(context) + @context = context + SeoTag.template.render!(payload, info) + end + + private + + def options + { + "version" => Jekyll::SeoTag::VERSION, + "title" => title?, + } + end + + def payload + # site_payload is an instance of UnifiedPayloadDrop. See https://git.io/v5ajm + context.registers[:site].site_payload.tap do |site_payload| + site_payload["page"] = context.registers[:page] + site_payload["paginator"] = context["paginator"] + site_payload["seo_tag"] = drop + end + end + + def drop + if context.registers[:site].liquid_renderer.respond_to?(:cache) + Jekyll::SeoTag::Drop.new(@text, @context) + else + @drop ||= Jekyll::SeoTag::Drop.new(@text, @context) + end + end + + def info + { + :registers => context.registers, + :filters => [Jekyll::Filters], + } + end + + class << self + def template + @template ||= Liquid::Template.parse template_contents + end + + private + + def template_contents + @template_contents ||= begin + File.read(template_path).gsub(MINIFY_REGEX, "") + end + end + + def template_path + @template_path ||= begin + File.expand_path "./template.html", File.dirname(__FILE__) + end + end + end + end +end + +Liquid::Template.register_tag("seo", Jekyll::SeoTag) diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/author_drop.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/author_drop.rb new file mode 100644 index 00000000..9d534cba --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/author_drop.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + # A drop representing the current page's author + # + # Author name will be pulled from: + # + # 1. The page's `author` key + # 2. The first author in the page's `authors` key + # 3. The `author` key in the site config + # + # If the result from the name search is a string, we'll also check + # for additional author metadata in `site.data.authors` + class AuthorDrop < Jekyll::Drops::Drop + # Initialize a new AuthorDrop + # + # page - The page hash (e.g., Page#to_liquid) + # site - The Jekyll::Drops::SiteDrop + def initialize(page: nil, site: nil) + raise ArgumentError unless page && site + + @mutations = {} + @page = page + @site = site + end + + # AuthorDrop#to_s should return name, allowing the author drop to safely + # replace `page.author`, if necessary, and remain backwards compatible + def name + author_hash["name"] + end + alias_method :to_s, :name + + def twitter + return @twitter if defined? @twitter + + twitter = author_hash["twitter"] || author_hash["name"] + @twitter = twitter.is_a?(String) ? twitter.sub(%r!^@!, "") : nil + end + + private + + attr_reader :site, :page + + # Finds the page author in the page.author, page.authors, or site.author + # + # Returns a string or hash representing the author + def resolved_author + return @resolved_author if defined? @resolved_author + + sources = [page["author"]] + sources << page["authors"].first if page["authors"].is_a?(Array) + sources << site["author"] + @resolved_author = sources.find { |s| !s.to_s.empty? } + end + + # If resolved_author is a string, attempts to find coresponding author + # metadata in `site.data.authors` + # + # Returns a hash representing additional metadata or an empty hash + def site_data_hash + @site_data_hash ||= begin + return {} unless resolved_author.is_a?(String) + return {} unless site.data["authors"].is_a?(Hash) + + author_hash = site.data["authors"][resolved_author] + author_hash.is_a?(Hash) ? author_hash : {} + end + end + + # Returns the normalized author hash representing the page author, + # including site-wide metadata if the author is provided as a string, + # or an empty hash, if the author cannot be resolved + def author_hash + @author_hash ||= begin + case resolved_author + when Hash + resolved_author + when String + { "name" => resolved_author }.merge!(site_data_hash) + else + {} + end + end + end + + # Since author_hash is aliased to fallback_data, any values in the hash + # will be exposed via the drop, allowing support for arbitrary metadata + alias_method :fallback_data, :author_hash + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/drop.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/drop.rb new file mode 100644 index 00000000..157babd4 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/drop.rb @@ -0,0 +1,247 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + class Drop < Jekyll::Drops::Drop + include Jekyll::SeoTag::UrlHelper + + TITLE_SEPARATOR = " | " + FORMAT_STRING_METHODS = [ + :markdownify, :strip_html, :normalize_whitespace, :escape_once, + ].freeze + HOMEPAGE_OR_ABOUT_REGEX = %r!^/(about/)?(index.html?)?$!.freeze + + EMPTY_READ_ONLY_HASH = {}.freeze + private_constant :EMPTY_READ_ONLY_HASH + + def initialize(text, context) + @obj = EMPTY_READ_ONLY_HASH + @mutations = {} + @text = text + @context = context + end + + def version + Jekyll::SeoTag::VERSION + end + + # Should the `<title>` tag be generated for this page? + def title? + return false unless title + return @display_title if defined?(@display_title) + + @display_title = (@text !~ %r!title=false!i) + end + + def site_title + @site_title ||= format_string(site["title"] || site["name"]) + end + + def site_tagline + @site_tagline ||= format_string site["tagline"] + end + + def site_description + @site_description ||= format_string site["description"] + end + + # Page title without site title or description appended + def page_title + @page_title ||= format_string(page["title"]) || site_title + end + + def site_tagline_or_description + site_tagline || site_description + end + + # Page title with site title or description appended + # rubocop:disable Metrics/CyclomaticComplexity + def title + @title ||= begin + if site_title && page_title != site_title + page_title + TITLE_SEPARATOR + site_title + elsif site_description && site_title + site_title + TITLE_SEPARATOR + site_tagline_or_description + else + page_title || site_title + end + end + + return page_number + @title if page_number + + @title + end + # rubocop:enable Metrics/CyclomaticComplexity + + def name + return @name if defined?(@name) + + @name = if seo_name + seo_name + elsif !homepage_or_about? + nil + elsif site_social["name"] + format_string site_social["name"] + elsif site_title + site_title + end + end + + def description + @description ||= begin + format_string(page["description"] || page["excerpt"]) || site_description + end + end + + # A drop representing the page author + def author + @author ||= AuthorDrop.new(:page => page, :site => site) + end + + # A drop representing the JSON-LD output + def json_ld + @json_ld ||= JSONLDDrop.new(self) + end + + # Returns a Drop representing the page's image + # Returns nil if the image has no path, to preserve backwards compatability + def image + @image ||= ImageDrop.new(:page => page, :context => @context) + @image if @image.path + end + + def date_modified + @date_modified ||= begin + date = page_seo["date_modified"] || page["last_modified_at"].to_liquid || page["date"] + filters.date_to_xmlschema(date) if date + end + end + + def date_published + @date_published ||= filters.date_to_xmlschema(page["date"]) if page["date"] + end + + def type + @type ||= begin + if page_seo["type"] + page_seo["type"] + elsif homepage_or_about? + "WebSite" + elsif page["date"] + "BlogPosting" + else + "WebPage" + end + end + end + + def links + @links ||= begin + if page_seo["links"] + page_seo["links"] + elsif homepage_or_about? && site_social["links"] + site_social["links"] + end + end + end + + def logo + @logo ||= begin + return unless site["logo"] + + if absolute_url? site["logo"] + filters.uri_escape site["logo"] + else + filters.uri_escape filters.absolute_url site["logo"] + end + end + end + + def page_lang + @page_lang ||= page["lang"] || site["lang"] || "en_US" + end + + def page_locale + @page_locale ||= (page["locale"] || site["locale"] || page_lang).tr("-", "_") + end + + def canonical_url + @canonical_url ||= begin + if page["canonical_url"].to_s.empty? + filters.absolute_url(page["url"]).to_s.gsub(%r!/index\.html$!, "/") + else + page["canonical_url"] + end + end + end + + private + + def filters + @filters ||= Jekyll::SeoTag::Filters.new(@context) + end + + def page + @page ||= @context.registers[:page].to_liquid + end + + def site + @site ||= @context.registers[:site].site_payload["site"].to_liquid + end + + def homepage_or_about? + page["url"] =~ HOMEPAGE_OR_ABOUT_REGEX + end + + def page_number + return unless @context["paginator"] && @context["paginator"]["page"] + + current = @context["paginator"]["page"] + total = @context["paginator"]["total_pages"] + paginator_message = site["seo_paginator_message"] || "Page %<current>s of %<total>s for " + + format(paginator_message, :current => current, :total => total) if current > 1 + end + + attr_reader :context + + def fallback_data + @fallback_data ||= {} + end + + def format_string(string) + string = FORMAT_STRING_METHODS.reduce(string) do |memo, method| + filters.public_send(method, memo) + end + + string unless string.empty? + end + + def seo_name + @seo_name ||= format_string(page_seo["name"]) if page_seo["name"] + end + + def page_seo + @page_seo ||= sub_hash(page, "seo") + end + + def site_social + @site_social ||= sub_hash(site, "social") + end + + # Safely returns a sub hash + # + # hash - the parent hash + # key - the key in the parent hash + # + # Returns the sub hash or an empty hash, if it does not exist + def sub_hash(hash, key) + if hash[key].is_a?(Hash) + hash[key] + else + EMPTY_READ_ONLY_HASH + end + end + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/filters.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/filters.rb new file mode 100644 index 00000000..6cbdf817 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/filters.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + class Filters + include Jekyll::Filters + include Liquid::StandardFilters + + def initialize(context) + @context = context + end + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/image_drop.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/image_drop.rb new file mode 100644 index 00000000..43367a45 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/image_drop.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + # A drop representing the page image + # The image path will be pulled from: + # + # 1. The `image` key if it's a string + # 2. The `image.path` key if it's a hash + # 3. The `image.facebook` key + # 4. The `image.twitter` key + class ImageDrop < Jekyll::Drops::Drop + include Jekyll::SeoTag::UrlHelper + + # Initialize a new ImageDrop + # + # page - The page hash (e.g., Page#to_liquid) + # context - the Liquid::Context + def initialize(page: nil, context: nil) + raise ArgumentError unless page && context + + @mutations = {} + @page = page + @context = context + end + + # Called path for backwards compatability, this is really + # the escaped, absolute URL representing the page's image + # Returns nil if no image path can be determined + def path + @path ||= filters.uri_escape(absolute_url) if absolute_url + end + alias_method :to_s, :path + + private + + attr_accessor :page, :context + + # The normalized image hash with a `path` key (which may be nil) + def image_hash + @image_hash ||= begin + image_meta = page["image"] + + case image_meta + when Hash + { "path" => nil }.merge!(image_meta) + when String + { "path" => image_meta } + else + { "path" => nil } + end + end + end + alias_method :fallback_data, :image_hash + + def raw_path + @raw_path ||= begin + image_hash["path"] || image_hash["facebook"] || image_hash["twitter"] + end + end + + def absolute_url + return unless raw_path + return @absolute_url if defined? @absolute_url + + @absolute_url = if raw_path.is_a?(String) && absolute_url?(raw_path) == false + filters.absolute_url raw_path + else + raw_path + end + end + + def filters + @filters ||= Jekyll::SeoTag::Filters.new(context) + end + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld.rb new file mode 100644 index 00000000..34d424ab --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + # This module is deprecated, but is included in the Gem to avoid a breaking + # change and should be removed at the next major version bump + module JSONLD + METHODS_KEYS = { + :json_context => "@context", + :type => "@type", + :name => "name", + :page_title => "headline", + :json_author => "author", + :json_image => "image", + :date_published => "datePublished", + :date_modified => "dateModified", + :description => "description", + :publisher => "publisher", + :main_entity => "mainEntityOfPage", + :links => "sameAs", + :canonical_url => "url", + }.freeze + + # Self should be a Jekyll::SeoTag::Drop instance (when extending the module) + def json_ld + Jekyll.logger.warn "Jekyll::SeoTag::JSONLD is deprecated" + @json_ld ||= JSONLDDrop.new(self) + end + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld_drop.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld_drop.rb new file mode 100644 index 00000000..d51404f9 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/json_ld_drop.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + class JSONLDDrop < Jekyll::Drops::Drop + extend Forwardable + + def_delegator :page_drop, :name, :name + def_delegator :page_drop, :description, :description + def_delegator :page_drop, :canonical_url, :url + def_delegator :page_drop, :page_title, :headline + def_delegator :page_drop, :date_modified, :dateModified + def_delegator :page_drop, :date_published, :datePublished + def_delegator :page_drop, :links, :sameAs + def_delegator :page_drop, :logo, :logo + def_delegator :page_drop, :type, :type + + # Expose #type and #logo as private methods and #@type as a public method + alias_method :@type, :type + private :type, :logo + + VALID_ENTITY_TYPES = %w(BlogPosting CreativeWork).freeze + VALID_AUTHOR_TYPES = %w(Organization Person).freeze + private_constant :VALID_ENTITY_TYPES, :VALID_AUTHOR_TYPES + + # page_drop should be an instance of Jekyll::SeoTag::Drop + def initialize(page_drop) + @mutations = {} + @page_drop = page_drop + end + + def fallback_data + @fallback_data ||= { + "@context" => "https://schema.org", + } + end + + def author + return unless page_drop.author["name"] + + author_type = page_drop.author["type"] + return if author_type && !VALID_AUTHOR_TYPES.include?(author_type) + + hash = { + "@type" => author_type || "Person", + "name" => page_drop.author["name"], + } + + author_url = page_drop.author["url"] + hash["url"] = author_url if author_url + + hash + end + + def image + return unless page_drop.image + return page_drop.image.path if page_drop.image.keys.length == 1 + + hash = page_drop.image.to_h + hash["url"] = hash.delete("path") + hash["@type"] = "imageObject" + hash + end + + def publisher + return unless logo + + output = { + "@type" => "Organization", + "logo" => { + "@type" => "ImageObject", + "url" => logo, + }, + } + output["name"] = page_drop.author.name if page_drop.author.name + output + end + + def main_entity + return unless VALID_ENTITY_TYPES.include?(type) + + { + "@type" => "WebPage", + "@id" => page_drop.canonical_url, + } + end + alias_method :mainEntityOfPage, :main_entity + private :main_entity + + # Returns a JSON-encoded object containing the JSON-LD data. + # Keys are sorted. + def to_json(state = nil) + keys.sort.each_with_object({}) do |(key, _), result| + v = self[key] + result[key] = v unless v.nil? + end.to_json(state) + end + + private + + attr_reader :page_drop + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/url_helper.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/url_helper.rb new file mode 100644 index 00000000..42bc803f --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/url_helper.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + class SeoTag + # Mixin to share common URL-related methods between class + module UrlHelper + private + + # Determines if the given string is an absolute URL + # + # Returns true if an absolute URL + # Returns false if it's a relative URL + # Returns nil if it is not a string or can't be parsed as a URL + def absolute_url?(string) + return unless string + + Addressable::URI.parse(string).absolute? + rescue Addressable::URI::InvalidURIError + nil + end + end + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/version.rb b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/version.rb new file mode 100644 index 00000000..3a42ca61 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/jekyll-seo-tag/version.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Prevent bundler errors +module Liquid; class Tag; end; end + +module Jekyll + class SeoTag < Liquid::Tag + VERSION = "2.8.0" + end +end diff --git a/bin/gems/jekyll-seo-tag-2.8.0/lib/template.html b/bin/gems/jekyll-seo-tag-2.8.0/lib/template.html new file mode 100755 index 00000000..1a3c9791 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/lib/template.html @@ -0,0 +1,128 @@ +<!-- Begin Jekyll SEO tag v{{ seo_tag.version }} --> +{% if seo_tag.title? %} + <title>{{ seo_tag.title }} +{% endif %} + + + +{% if seo_tag.page_title %} + +{% endif %} + +{% if seo_tag.author.name %} + +{% endif %} + + + +{% if seo_tag.description %} + + +{% endif %} + +{% if site.url %} + + +{% endif %} + +{% if seo_tag.site_title %} + +{% endif %} + +{% if seo_tag.image %} + + {% if seo_tag.image.height %} + + {% endif %} + {% if seo_tag.image.width %} + + {% endif %} + {% if seo_tag.image.alt %} + + {% endif %} +{% endif %} + +{% if page.date %} + + +{% else %} + +{% endif %} + +{% if paginator.previous_page %} + +{% endif %} +{% if paginator.next_page %} + +{% endif %} + +{% if seo_tag.image %} + + +{% else %} + +{% endif %} + +{% if seo_tag.image.alt %} + +{% endif %} + +{% if seo_tag.page_title %} + +{% endif %} + +{% if site.twitter %} + + + {% if seo_tag.author.twitter %} + + {% endif %} +{% endif %} + +{% if site.facebook %} + {% if site.facebook.admins %} + + {% endif %} + + {% if site.facebook.publisher %} + + {% endif %} + + {% if site.facebook.app_id %} + + {% endif %} +{% endif %} + +{% if site.webmaster_verifications %} + {% if site.webmaster_verifications.google %} + + {% endif %} + + {% if site.webmaster_verifications.bing %} + + {% endif %} + + {% if site.webmaster_verifications.alexa %} + + {% endif %} + + {% if site.webmaster_verifications.yandex %} + + {% endif %} + + {% if site.webmaster_verifications.baidu %} + + {% endif %} + + {% if site.webmaster_verifications.facebook %} + + {% endif %} +{% elsif site.google_site_verification %} + +{% endif %} + + + + diff --git a/bin/gems/jekyll-seo-tag-2.8.0/script/bootstrap b/bin/gems/jekyll-seo-tag-2.8.0/script/bootstrap new file mode 100755 index 00000000..654265ea --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/script/bootstrap @@ -0,0 +1,5 @@ +#!/bin/sh + +set -ex + +bundle install diff --git a/bin/gems/jekyll-seo-tag-2.8.0/script/cibuild b/bin/gems/jekyll-seo-tag-2.8.0/script/cibuild new file mode 100755 index 00000000..dec4aa6e --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/script/cibuild @@ -0,0 +1,7 @@ +#!/bin/sh + +set -ex + +bundle exec rspec +bundle exec rubocop -S -D +bundle exec gem build jekyll-seo-tag.gemspec diff --git a/bin/gems/jekyll-seo-tag-2.8.0/script/release b/bin/gems/jekyll-seo-tag-2.8.0/script/release new file mode 100755 index 00000000..14588429 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/script/release @@ -0,0 +1,38 @@ +#!/bin/sh +# Tag and push a release. + +set -e + +# Make sure we're in the project root. + +cd $(dirname "$0")/.. + +# Build a new gem archive. + +rm -rf jekyll-seo-tag-*.gem +gem build -q jekyll-seo-tag.gemspec + +# Make sure we're on the master branch. + +(git branch | grep -q '* master') || { + echo "Only release from the master branch." + exit 1 +} + +# Figure out what version we're releasing. + +tag=v`ls jekyll-seo-tag-*.gem | sed 's/^jekyll-seo-tag-\(.*\)\.gem$/\1/'` + +# Make sure we haven't released this version before. + +git fetch -t origin + +(git tag -l | grep -q "$tag") && { + echo "Whoops, there's already a '${tag}' tag." + exit 1 +} + +# Tag it and bag it. + +gem push jekyll-seo-tag-*.gem && git tag "$tag" && + git push origin master && git push origin "$tag" diff --git a/bin/gems/jekyll-seo-tag-2.8.0/script/site b/bin/gems/jekyll-seo-tag-2.8.0/script/site new file mode 100755 index 00000000..9e4f56f2 --- /dev/null +++ b/bin/gems/jekyll-seo-tag-2.8.0/script/site @@ -0,0 +1,3 @@ +#!/bin/sh + +bundle exec jekyll serve --source docs diff --git a/bin/gems/jekyll-sitemap-1.4.0/.gitignore b/bin/gems/jekyll-sitemap-1.4.0/.gitignore new file mode 100644 index 00000000..08626c88 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/.gitignore @@ -0,0 +1,6 @@ +.bundle +*.gem +Gemfile.lock +spec/dest +spec/fixtures/.jekyll-cache +vendor/bundle diff --git a/bin/gems/jekyll-sitemap-1.4.0/.rspec b/bin/gems/jekyll-sitemap-1.4.0/.rspec new file mode 100644 index 00000000..5f164763 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/.rspec @@ -0,0 +1,2 @@ +--color +--format progress diff --git a/bin/gems/jekyll-sitemap-1.4.0/.rubocop.yml b/bin/gems/jekyll-sitemap-1.4.0/.rubocop.yml new file mode 100644 index 00000000..d2e8a8ee --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/.rubocop.yml @@ -0,0 +1,9 @@ +inherit_from: .rubocop_todo.yml + +require: rubocop-jekyll +inherit_gem: + rubocop-jekyll: .rubocop.yml + +AllCops: + Exclude: + - vendor/**/* diff --git a/bin/gems/jekyll-sitemap-1.4.0/.rubocop_todo.yml b/bin/gems/jekyll-sitemap-1.4.0/.rubocop_todo.yml new file mode 100644 index 00000000..3503a7fc --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/.rubocop_todo.yml @@ -0,0 +1,26 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2018-12-06 11:55:46 +0100 using RuboCop version 0.61.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +Lint/Debugger: + Exclude: + - 'script/console' + +# Offense count: 3 +# Configuration parameters: CountComments, Max, ExcludedMethods. +# ExcludedMethods: refine +Metrics/BlockLength: + Exclude: + - 'spec/jekyll-sitemap_spec.rb' + - 'spec/test_jekyll-last-modified-at.rb' + +# Offense count: 17 +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 154 diff --git a/bin/gems/jekyll-sitemap-1.4.0/.travis.yml b/bin/gems/jekyll-sitemap-1.4.0/.travis.yml new file mode 100644 index 00000000..6c1707b2 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/.travis.yml @@ -0,0 +1,48 @@ +language: ruby +cache: bundler +rvm: +- &latest_ruby 2.6 +- 2.4 +matrix: + include: + # GitHub Pages + - rvm: 2.5.3 + env: + - JEKYLL_VERSION="~> 3.8.5" + - GITHUB_PAGES=1 # Only set on one build in matrix + - rvm: *latest_ruby + env: JEKYLL_VERSION=">= 4.0.0" +env: + matrix: + - JEKYLL_VERSION="~> 3.8" +branches: + only: + - master + - /^v\d+\.\d+\.\d+/ +git: + depth: 1000 +before_install: +- gem update --system +install: +- travis_retry script/bootstrap +script: script/cibuild +notifications: + irc: + on_success: change + on_failure: change + channels: + - irc.freenode.org#jekyll + template: + - "%{repository}#%{build_number} %{message} %{build_url}" + email: + on_success: never + on_failure: change +deploy: + provider: rubygems + api_key: + secure: O8fGRnM6OJCqC2BlVE1BqYfq5aR19ulpiHhQwRiHbtSCh8H4rYt7FLsuOwSTtRQjhWYRRSpdRt2ilfQ6PY6Jx1UkxZq5zo9QAPQ9tKxiFTm7gBpZAiAgb06eyaMBSzyQ8qe2qccaFI6CiZhsiaGMsdKsWuYpuoPmdLPd7aDyYJs= + gem: jekyll-sitemap + on: + tags: true + repo: jekyll/jekyll-sitemap + condition: "$GITHUB_PAGES == 1" diff --git a/bin/gems/jekyll-sitemap-1.4.0/Gemfile b/bin/gems/jekyll-sitemap-1.4.0/Gemfile new file mode 100644 index 00000000..46cdbf02 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +gemspec + +gem "jekyll", ENV["JEKYLL_VERSION"] if ENV["JEKYLL_VERSION"] diff --git a/bin/gems/jekyll-sitemap-1.4.0/History.markdown b/bin/gems/jekyll-sitemap-1.4.0/History.markdown new file mode 100644 index 00000000..56fc3f88 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/History.markdown @@ -0,0 +1,221 @@ +## 1.4.0 / 2019-11-21 + +### Minor Enhancements + + * Avoid overwriting an existing robots.txt (#246) + +### Bug Fixes + + * Simulate `last_modified_at` injection by plugin (#256) + +## 1.3.1 / 2019-03-25 + +### Bug Fixes + + * Update plugin metadata and dev environment (#244) + +### Development Fixes + + * Lock requirement for `jekyll-last-modified-at` to `>= 1.0` + +## 1.3.0 / 2019-03-21 + + * Allow Jekyll v4 (still alpha) + +### Documentation + + * Add PDF file exclusion documentation (#213) + * Correct capitalization of GitHub (#207) + +### Development Fixes + + * Use Ruby 2.3 and Rubocop 0.55 (#214) + * chore(deps): rubocop-jekyll-0.3 (#227) + +## 1.2.0 / 2018-01-25 + +### Minor Enhancements + + * Remove excluded static files from the sitemap (#166) + * filter/replace static index.html paths to permalink (#170) + +### Development Fixes + + * Condition the static file tests on Jekyll 3.4.2 and above (#167) + * Update versions for Travis (#174) + * Fix Travis Deploy (#173) + * Test against Jekyll 3.4.x *and* latest 3.x (#177) + * Define path with __dir__ (#186) + * Style: Rubocop auto-correct (#195) + * Test against Ruby 2.5 (#201) + +### Documentation + + * Add note about use with Github Pages gem (#179) + * Fix a couple of typos (#184) + * Use plugins instead of gems in README config (#185) + * Docs: set site.url in config (#172) + +## 1.1.1 / 2017-04-11 + + * Cut a new version to alleviate sha256 checksum issue on RubyGems.org (#165) + +## 1.1.0 / 2017-04-10 + +### Minor Enhancements + + * escape& (#162) + * feat: remove 404 pages from the sitemap. closes #113 (#164) + +## 1.0.0 / 2017-01-06 + + * No new changes + +## 0.13.0 / 2017-01-05 + +### Minor Enhancements + + * Add sitemap.xsl if exists (#143) + * Add robots.txt when none exists (#146) + * Refactor and add sitemap to `site.pages` (#137) + * DRY in sitemap.xml (#136) + +### Documentation + + * Fix #134: Rename "Issues" to "Known Issues" (#135) + * Fix #104: Add explanation in README for tag (#139) + * Update copyright attribution (#149) + +### Development Fixes + + * Travis should do a deep clone (#147) + +## 0.12.0 / 2016-10-06 + +### Minor Enhancements + + * Don't set @site.config["time"] on sitemap generation (#131) + * Use filters to clean up Liquid template (#128) + +### Development Fixes + + * Appease Rubocop (#132) + * Drop Addressable dependency (#133) + +## 0.11.0 / 2016-07-08 + + * Add Rubocop (#100) + * Allow Travis to cache dependencies (#108) + * Properly Escape URLs (#107) + * Include PDF files in sitemap (#109) + +## 0.10.0 / 2016-01-05 + + * URI encode sitemap URLs (#85) + * Do not include 'posts' collection twice (#92) + * Fix GitHub Pages tests to test just the Jekyll version (#87) + * Allow HTML files to end with `.xhtml` or `.htm` (#93) + * Simplify whitespace regex for stripping whitespace (#96) + +## 0.9.0 / 2015-09-21 + + * Test against Jekyll 2, 3, and the GitHub Pages version. (#83) + +## 0.8.1 / 2015-03-11 + + * Do not assume all pages have changed (#35) + * Remove duplicated range from regex (#73) + +## 0.8.0 / 2015-02-03 + + * Call each page `page` in pages loop in `sitemap.xml` for clarity (#64) + * Remove `changefreq` (#34) + * Remove `priority` (#33) + * Don't strip 'index.html' when there is more to filename ## Minor Enhancements (#68) + +## 0.7.0 / 2014-12-07 + + * Make `site.baseurl` support more robust (#59) + * Add `site.baseurl` to base site URL construction ## Development Fixes (#50) + * Remove unnecessary spaces and escaping in README ## Bug Fixes (#58) + +## 0.6.3 / 2014-11-11 + + * Be backwards-compatible when `Site#in_source_dir` and `Site#in_dest_dir` don't exist (#57) + +## 0.6.2 / 2014-11-08 + +### Bug Fixes + + * Don't attempt to read the sitemap upon page creation. (#52) + * Use new secure methods to build source & dest paths. (#53) + +## 0.6.1 / 2014-10-17 + +### Minor Enhancements + + * Strip excess whitespace (#40) + +### Bug Fixes + + * Add UTC offset to `` to handle non-UTC timezones (#49) + +### Development Fixes + + * Adding information about exclusion flag (#45) + +## 0.6.0 / 2014-09-05 + +### Minor Enhancements + + * Include custom collections in the sitemap. (#30) + * Use `post.last_modified_at` for post `` if available (#37) + +## 0.5.1 / 2014-07-31 + +### Bug Fixes + + * Explicitly set sitemap layout to `nil` to avoid warning (#32) + +## 0.5.0 / 2014-06-02 + +### Minor Enhancements + + * Allow users to exclude a page/post from the sitemap (#11) + +## 0.4.1 / 2014-05-10 + +### Bug Fixes + + * Force sitemap layout to be `nil` (#16) + * Correct seconds in timestamp for static files # Development Fixes (#24) + * Upgrade to Rspec 3.0 and use `be_truthy` (#24) + +## 0.4.0 / 2014-05-06 + +### Major Enhancements + + * Support Jekyll 2.0 (#12) + +## 0.3.0 / 2014-05-05 + +### Minor Enhancements + + * Generate sitemap using html_pages (#10) + +### Bug Fixes + + * Remove stray sitemap.xsl from template (#8) + +### Development Fixes + + * Added travis (#6) + * Better timezone support (#7) + +## 0.2.0 / 2014-03-24 + + * Loosen Jekyll requirement (#4) + +## 0.1.0 / 2014-03-15 + + * Birthday! diff --git a/bin/gems/jekyll-sitemap-1.4.0/LICENSE.md b/bin/gems/jekyll-sitemap-1.4.0/LICENSE.md new file mode 100644 index 00000000..1672e4a6 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-present, GitHub, inc. and the jekyll-sitemap 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/bin/gems/jekyll-sitemap-1.4.0/README.md b/bin/gems/jekyll-sitemap-1.4.0/README.md new file mode 100644 index 00000000..c85be55c --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/README.md @@ -0,0 +1,92 @@ +# Jekyll Sitemap Generator Plugin + +*Jekyll plugin to silently generate a sitemaps.org compliant sitemap for your Jekyll site* + +[![Build Status](https://travis-ci.org/jekyll/jekyll-sitemap.svg?branch=master)](https://travis-ci.org/jekyll/jekyll-sitemap) + +## Usage + +1. Add `gem 'jekyll-sitemap'` to your site's Gemfile and run `bundle` +2. Add the following to your site's `_config.yml`: + +```yml +url: "http://example.com" # the base hostname & protocol for your site +plugins: + - jekyll-sitemap +``` + +💡 If you are using a Jekyll version less than 3.5.0, use the `gems` key instead of `plugins`. + +If all gem plugins have the same `priority`, they will be executed in the +order they are required, generally. Thus, if you have other plugins which +generate content and store that content in `site.pages`, `site.posts`, or +`site.collections`, be sure to require `jekyll-sitemap` either *after* +those other gems if you *want* the sitemap to include the generated +content, or *before* those other gems if you *don't want* the sitemap to +include the generated content from the gems. (Programming is *hard*.) + +Because the sitemap is added to `site.pages`, you may have to modify any +templates that iterate through all pages (for example, to build a menu of +all of the site's content). + +## Note on Use with GitHub Pages Gem +The GitHub Pages gem ignores all plugins included in the Gemfile. If you only include `jekyll-sitemap` in the Gemfile without also including it in the `_config.yml` *the plugin will not work*. This can be confusing because the official Jekyll docs state that plugins can be included in either the Gemfile or `_config.yml`. + +When building a site that uses the GitHub Pages gem, follow the instructions above and ensure that `jekyll-sitemap` is listed in the `plugins` array in `_config.yml`. + +:warning: If you are using Jekyll < 3.5.0 use the `gems` key instead of `plugins`. + +## `` tag +The `` tag in the `sitemap.xml` will reflect by priority: + +1. The modified date of the file as reported by the filesystem if you have `jekyll-last-modified-at` plugin installed (not compatible with GitHub Pages auto building) +2. A personalised date if you add the variable `last_modified_at:` with a date in the Front Matter +3. The creation date of your post (corresponding to the `post.date` variable) + +## Exclusions + +If you would like to exclude specific pages/posts from the sitemap set the +sitemap flag to `false` in the front matter for the page/post. + +```yml +sitemap: false +``` + +To exclude files from your sitemap. It can be achieved with configuration using [Jekyll v3.7.2 and jekyll-sitemap v1.2.0](https://github.com/jekyll/jekyll/commit/776433109b96cb644938ffbf9caf4923bdde4d7f). + +Add a glob config to your `_config.yml` file. + +```yml +defaults: + - + scope: + path: "assets/**/*.pdf" + values: + sitemap: false +``` + +## Override default development settings + +[Follow these instructions on Jekyll's documentation](https://jekyllrb.com/docs/usage/#override-default-development-settings). + +## Developing locally + +* Use `script/bootstrap` to bootstrap your local development environment. +* Use `script/console` to load a local IRB console with the Gem. + +## Testing + +1. `script/bootstrap` +2. `script/cibuild` + +## Known Issues + +1. If the `sitemap.xml` doesn't generate in the `_site` folder, ensure `_config.yml` doesn't have `safe: true`. That prevents all plugins from working. +2. If the `sitemap.xml` doesn't generate in the `_site` folder, ensure that you don't have a sitemap generator plugin in your `_plugin` folder. + +## Contributing + +1. Fork the project +2. Create a descriptively named feature branch +3. Add your feature +4. Submit a pull request diff --git a/bin/gems/jekyll-sitemap-1.4.0/Rakefile b/bin/gems/jekyll-sitemap-1.4.0/Rakefile new file mode 100644 index 00000000..ee617bbb --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/Rakefile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/bin/gems/jekyll-sitemap-1.4.0/jekyll-sitemap.gemspec b/bin/gems/jekyll-sitemap-1.4.0/jekyll-sitemap.gemspec new file mode 100644 index 00000000..a9cdeeae --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/jekyll-sitemap.gemspec @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +lib = File.expand_path("lib", __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "jekyll-sitemap/version" + +Gem::Specification.new do |spec| + spec.name = "jekyll-sitemap" + spec.summary = "Automatically generate a sitemap.xml for your Jekyll site." + spec.version = Jekyll::Sitemap::VERSION + spec.authors = ["GitHub, Inc."] + spec.email = "support@github.com" + spec.homepage = "https://github.com/jekyll/jekyll-sitemap" + spec.licenses = ["MIT"] + + spec.files = `git ls-files -z`.split("\x0") + spec.executables = spec.files.grep(%r!^bin/!) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r!^(test|spec|features)/!) + spec.require_paths = ["lib"] + + spec.required_ruby_version = ">= 2.3.0" + + spec.add_dependency "jekyll", ">= 3.7", "< 5.0" + + spec.add_development_dependency "bundler" + spec.add_development_dependency "rake" + spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "rubocop-jekyll", "~> 0.4" +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap.rb b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap.rb new file mode 100644 index 00000000..b788fae9 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require "jekyll/page_without_a_file" +require "jekyll/jekyll-sitemap" diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap/version.rb b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap/version.rb new file mode 100644 index 00000000..504172d0 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll-sitemap/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Jekyll + module Sitemap + VERSION = "1.4.0" + end +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/jekyll-sitemap.rb b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/jekyll-sitemap.rb new file mode 100644 index 00000000..54ff823d --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/jekyll-sitemap.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require "fileutils" + +module Jekyll + class JekyllSitemap < Jekyll::Generator + safe true + priority :lowest + + # Main plugin action, called by Jekyll-core + def generate(site) + @site = site + @site.pages << sitemap unless file_exists?("sitemap.xml") + @site.pages << robots unless file_exists?("robots.txt") + end + + private + + INCLUDED_EXTENSIONS = %w( + .htm + .html + .xhtml + .pdf + ).freeze + + # Matches all whitespace that follows + # 1. A '>' followed by a newline or + # 2. A '}' which closes a Liquid tag + # We will strip all of this whitespace to minify the template + MINIFY_REGEX = %r!(?<=>\n|})\s+!.freeze + + # Array of all non-jekyll site files with an HTML extension + def static_files + @site.static_files.select { |file| INCLUDED_EXTENSIONS.include? file.extname } + end + + # Path to sitemap.xml template file + def source_path(file = "sitemap.xml") + File.expand_path "../#{file}", __dir__ + end + + # Destination for sitemap.xml file within the site source directory + def destination_path(file = "sitemap.xml") + @site.in_dest_dir(file) + end + + def sitemap + site_map = PageWithoutAFile.new(@site, __dir__, "", "sitemap.xml") + site_map.content = File.read(source_path).gsub(MINIFY_REGEX, "") + site_map.data["layout"] = nil + site_map.data["static_files"] = static_files.map(&:to_liquid) + site_map.data["xsl"] = file_exists?("sitemap.xsl") + site_map + end + + def robots + robots = PageWithoutAFile.new(@site, __dir__, "", "robots.txt") + robots.content = File.read(source_path("robots.txt")) + robots.data["layout"] = nil + robots + end + + # Checks if a file already exists in the site source + def file_exists?(file_path) + pages_and_files.any? { |p| p.url == "/#{file_path}" } + end + + def pages_and_files + @pages_and_files ||= @site.pages + @site.static_files + end + end +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/page_without_a_file.rb b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/page_without_a_file.rb new file mode 100644 index 00000000..42ecf08b --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/jekyll/page_without_a_file.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Jekyll + class PageWithoutAFile < Page + # rubocop:disable Naming/MemoizedInstanceVariableName + def read_yaml(*) + @data ||= {} + end + # rubocop:enable Naming/MemoizedInstanceVariableName + end +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/robots.txt b/bin/gems/jekyll-sitemap-1.4.0/lib/robots.txt new file mode 100644 index 00000000..a699016f --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/robots.txt @@ -0,0 +1 @@ +Sitemap: {{ "sitemap.xml" | absolute_url }} diff --git a/bin/gems/jekyll-sitemap-1.4.0/lib/sitemap.xml b/bin/gems/jekyll-sitemap-1.4.0/lib/sitemap.xml new file mode 100644 index 00000000..75d0c1ec --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/lib/sitemap.xml @@ -0,0 +1,36 @@ + +{% if page.xsl %} + +{% endif %} + + {% assign collections = site.collections | where_exp:'collection','collection.output != false' %} + {% for collection in collections %} + {% assign docs = collection.docs | where_exp:'doc','doc.sitemap != false' %} + {% for doc in docs %} + + {{ doc.url | replace:'/index.html','/' | absolute_url | xml_escape }} + {% if doc.last_modified_at or doc.date %} + {{ doc.last_modified_at | default: doc.date | date_to_xmlschema }} + {% endif %} + + {% endfor %} + {% endfor %} + + {% assign pages = site.html_pages | where_exp:'doc','doc.sitemap != false' | where_exp:'doc','doc.url != "/404.html"' %} + {% for page in pages %} + + {{ page.url | replace:'/index.html','/' | absolute_url | xml_escape }} + {% if page.last_modified_at %} + {{ page.last_modified_at | date_to_xmlschema }} + {% endif %} + + {% endfor %} + + {% assign static_files = page.static_files | where_exp:'page','page.sitemap != false' | where_exp:'page','page.name != "404.html"' %} + {% for file in static_files %} + + {{ file.path | replace:'/index.html','/' | absolute_url | xml_escape }} + {{ file.modified_time | date_to_xmlschema }} + + {% endfor %} + diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/bootstrap b/bin/gems/jekyll-sitemap-1.4.0/script/bootstrap new file mode 100755 index 00000000..e2b126bd --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/bootstrap @@ -0,0 +1,4 @@ +#!/bin/sh +set -ex + +bundle install diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/cibuild b/bin/gems/jekyll-sitemap-1.4.0/script/cibuild new file mode 100755 index 00000000..509b0c9f --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/cibuild @@ -0,0 +1,5 @@ +#!/bin/sh +set -e + +time script/fmt +time script/test diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/console b/bin/gems/jekyll-sitemap-1.4.0/script/console new file mode 100755 index 00000000..6132d7fe --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/console @@ -0,0 +1,35 @@ +#! /usr/bin/env ruby +# frozen_string_literal: true + +def relative_to_root(path) + File.expand_path(path, File.dirname(__dir__)) +end + +require "jekyll" +require relative_to_root("lib/jekyll-sitemap.rb") +require "pry-debugger" + +SOURCE_DIR = relative_to_root("spec/fixtures") +DEST_DIR = relative_to_root("spec/dest") + +def source_dir(*files) + File.join(SOURCE_DIR, *files) +end + +def dest_dir(*files) + File.join(DEST_DIR, *files) +end + +def config(overrides = {}) + Jekyll.configuration( + "source" => source_dir, + "destination" => dest_dir, + "url" => "http://example.org" + ).merge(overrides) +end + +def site(configuration = config) + Jekyll::Site.new(configuration) +end + +binding.pry diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/fmt b/bin/gems/jekyll-sitemap-1.4.0/script/fmt new file mode 100755 index 00000000..c5351ecf --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/fmt @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +echo "Rubocop $(bundle exec rubocop --version)" +bundle exec rubocop -D -E $@ +success=$? +if ((success != 0)); then + echo -e "\nTry running \`script/fmt -a\` to automatically fix errors" +fi +exit $success diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/release b/bin/gems/jekyll-sitemap-1.4.0/script/release new file mode 100755 index 00000000..a9c226f9 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/release @@ -0,0 +1,7 @@ +#!/bin/sh +# Tag and push a release. + +set -e + +script/cibuild +bundle exec rake release diff --git a/bin/gems/jekyll-sitemap-1.4.0/script/test b/bin/gems/jekyll-sitemap-1.4.0/script/test new file mode 100755 index 00000000..506d5ef5 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/script/test @@ -0,0 +1,5 @@ +#!/bin/bash +set -ex + +bundle exec rspec "$@" +bundle exec rspec spec/test_jekyll-last-modified-at.rb diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/404.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/404.md new file mode 100644 index 00000000..0d9de631 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/404.md @@ -0,0 +1,4 @@ +--- +--- + +404. That's an error. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_config.yml b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_config.yml new file mode 100644 index 00000000..cffd3fbf --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_config.yml @@ -0,0 +1,19 @@ +timezone: UTC + +defaults: + - + scope: + path: "" + type: page + values: + layout: some_default + - + scope: + path: "static_files/excluded.pdf" + values: + sitemap: false + - + scope: + path: "static_files/html_file.html" + values: + sitemap: false diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_layouts/some_default.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_layouts/some_default.html new file mode 100644 index 00000000..c38a7b9f --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_layouts/some_default.html @@ -0,0 +1,4 @@ +--- +--- +THIS IS MY LAYOUT +{{ content }} diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink.md new file mode 100644 index 00000000..ce4a7d05 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink.md @@ -0,0 +1,5 @@ +--- +permalink: /permalink/ +--- + +# Custom permalink diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink_2.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink_2.md new file mode 100644 index 00000000..551ee025 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/custom_permalink_2.md @@ -0,0 +1,5 @@ +--- +permalink: /permalink/unique_name.html +--- + +# Unique html name diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/test.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/test.html new file mode 100644 index 00000000..2d840215 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/test.html @@ -0,0 +1,4 @@ +--- +--- + +This is just a test. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/this-has-non-standard-chars.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/this-has-non-standard-chars.md new file mode 100644 index 00000000..519dae0a --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_my_collection/this-has-non-standard-chars.md @@ -0,0 +1,5 @@ +--- +permalink: this url has an ümlaut +--- + +# URL contains characters that need to be URI encoded diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_other_things/test2.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_other_things/test2.html new file mode 100644 index 00000000..d222dde7 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_other_things/test2.html @@ -0,0 +1,4 @@ +--- +--- + +This file shouldn't show up in the sitemap. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2013-12-12-dec-the-second.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2013-12-12-dec-the-second.md new file mode 100644 index 00000000..02829945 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2013-12-12-dec-the-second.md @@ -0,0 +1,4 @@ +--- +--- + +December the twelfth, actually. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-02-march-the-second.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-02-march-the-second.md new file mode 100644 index 00000000..9a47b49f --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-02-march-the-second.md @@ -0,0 +1,4 @@ +--- +--- + +March the second! diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-04-march-the-fourth.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-04-march-the-fourth.md new file mode 100644 index 00000000..42ed97c8 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-03-04-march-the-fourth.md @@ -0,0 +1,4 @@ +--- +--- + +March the fourth! diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-05-11-exclude-this-post.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-05-11-exclude-this-post.md new file mode 100644 index 00000000..ccd540fa --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2014-05-11-exclude-this-post.md @@ -0,0 +1,5 @@ +--- +sitemap: false +--- + +This post should not appear in the sitemap. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2015-01-18-jekyll-last-modified-at.md b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2015-01-18-jekyll-last-modified-at.md new file mode 100644 index 00000000..e26b59b7 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2015-01-18-jekyll-last-modified-at.md @@ -0,0 +1,4 @@ +--- +--- + +Please don't modify this file. It's modified time is important. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-01-错误.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-01-错误.html new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-01-错误.html @@ -0,0 +1,2 @@ +--- +--- diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-02-错误.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-02-错误.html new file mode 100644 index 00000000..f660f6f3 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-02-错误.html @@ -0,0 +1,3 @@ +--- +permalink: "/2016/04/02/错误.html" +--- diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-03-错误.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-03-错误.html new file mode 100644 index 00000000..3123e48a --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/_posts/2016-04-03-错误.html @@ -0,0 +1,3 @@ +--- +permalink: "/2016/04/03/%E9%94%99%E8%AF%AF.html" +--- diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/feeds/atom.xml b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/feeds/atom.xml new file mode 100644 index 00000000..58715b68 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/feeds/atom.xml @@ -0,0 +1,6 @@ +--- +--- + + + + diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/images/hubot.png b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/images/hubot.png new file mode 100644 index 00000000..75da791d Binary files /dev/null and b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/images/hubot.png differ diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/index.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/index.html new file mode 100644 index 00000000..fce076a3 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/index.html @@ -0,0 +1,4 @@ +--- +--- + +HERE IS MY SITE I AM SO EXCITED TO BE USING GITHUB PAGES diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/jekyll-last-modified-at/page.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/jekyll-last-modified-at/page.html new file mode 100644 index 00000000..6fe4bdb8 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/jekyll-last-modified-at/page.html @@ -0,0 +1,4 @@ +--- +--- + +This is a page with a modified time. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/exclude-this-page.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/exclude-this-page.html new file mode 100644 index 00000000..9eea02e7 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/exclude-this-page.html @@ -0,0 +1,5 @@ +--- +sitemap: false +--- + +Exclude this page diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/htm.htm b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/htm.htm new file mode 100644 index 00000000..7da6a6b0 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/htm.htm @@ -0,0 +1 @@ +This file has an .htm extension, and should be included in the sitemap diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/index.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/index.html new file mode 100644 index 00000000..2c2b27d6 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/index.html @@ -0,0 +1 @@ +static subfolder index.html file that should be indexed as permalink diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/test_index.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/test_index.html new file mode 100644 index 00000000..e1ac7a96 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/test_index.html @@ -0,0 +1,4 @@ +--- +--- + +The permalink of this page does not end with a '/', but with a filename diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/this-is-a-subfile.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/this-is-a-subfile.html new file mode 100644 index 00000000..e69de29b diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/this-is-a-subpage.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/this-is-a-subpage.html new file mode 100644 index 00000000..06dd7078 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/this-is-a-subpage.html @@ -0,0 +1,4 @@ +--- +--- + +This is a subpage! diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/xhtml.xhtml b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/xhtml.xhtml new file mode 100644 index 00000000..7c5eafaf --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/some-subfolder/xhtml.xhtml @@ -0,0 +1 @@ +This file has an .xhtml extension, and should be included in the sitemap diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/404.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/404.html new file mode 100644 index 00000000..5416e297 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/404.html @@ -0,0 +1 @@ +404. That's an error. diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/excluded.pdf b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/excluded.pdf new file mode 100644 index 00000000..e69de29b diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/html_file.html b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/html_file.html new file mode 100644 index 00000000..e69de29b diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/test.pdf b/bin/gems/jekyll-sitemap-1.4.0/spec/fixtures/static_files/test.pdf new file mode 100644 index 00000000..e69de29b diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/jekyll-sitemap_spec.rb b/bin/gems/jekyll-sitemap-1.4.0/spec/jekyll-sitemap_spec.rb new file mode 100644 index 00000000..2b7d9c58 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/jekyll-sitemap_spec.rb @@ -0,0 +1,256 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Jekyll::JekyllSitemap) do + let(:overrides) do + { + "source" => source_dir, + "destination" => dest_dir, + "url" => "http://example.org", + "collections" => { + "my_collection" => { "output" => true }, + "other_things" => { "output" => false }, + }, + } + end + let(:config) do + Jekyll.configuration(overrides) + end + let(:site) { Jekyll::Site.new(config) } + let(:contents) { File.read(dest_dir("sitemap.xml")) } + before(:each) do + site.process + end + + it "has no layout" do + expect(contents).not_to match(%r!\ATHIS IS MY LAYOUT!) + end + + it "creates a sitemap.xml file" do + expect(File.exist?(dest_dir("sitemap.xml"))).to be_truthy + end + + it "doesn't have multiple new lines or trailing whitespace" do + expect(contents).to_not match %r!\s+\n! + expect(contents).to_not match %r!\n{2,}! + end + + it "puts all the pages in the sitemap.xml file" do + expect(contents).to match %r!http://example\.org/! + expect(contents).to match %r!http://example\.org/some-subfolder/this-is-a-subpage\.html! + end + + it "only strips 'index.html' from end of permalink" do + expect(contents).to match %r!http://example\.org/some-subfolder/test_index\.html! + end + + it "puts all the posts in the sitemap.xml file" do + expect(contents).to match %r!http://example\.org/2014/03/04/march-the-fourth\.html! + expect(contents).to match %r!http://example\.org/2014/03/02/march-the-second\.html! + expect(contents).to match %r!http://example\.org/2013/12/12/dec-the-second\.html! + end + + describe "collections" do + it "puts all the `output:true` into sitemap.xml" do + expect(contents).to match %r!http://example\.org/my_collection/test\.html! + end + + it "doesn't put all the `output:false` into sitemap.xml" do + expect(contents).to_not match %r!http://example\.org/other_things/test2\.html! + end + + it "remove 'index.html' for directory custom permalinks" do + expect(contents).to match %r!http://example\.org/permalink/! + end + + it "doesn't remove filename for non-directory custom permalinks" do + expect(contents).to match %r!http://example\.org/permalink/unique_name\.html! + end + + it "performs URI encoding of site paths" do + expect(contents).to match %r!http://example\.org/this%20url%20has%20an%20%C3%BCmlaut! + end + end + + it "generates the correct date for each of the posts" do + expect(contents).to match %r!2014-03-04T00:00:00(-|\+)\d+:\d+! + expect(contents).to match %r!2014-03-02T00:00:00(-|\+)\d+:\d+! + expect(contents).to match %r!2013-12-12T00:00:00(-|\+)\d+:\d+! + end + + it "puts all the static HTML files in the sitemap.xml file" do + expect(contents).to match %r!http://example\.org/some-subfolder/this-is-a-subfile\.html! + end + + it "does not include assets or any static files that aren't .html" do + expect(contents).not_to match %r!http://example\.org/images/hubot\.png! + expect(contents).not_to match %r!http://example\.org/feeds/atom\.xml! + end + + it "converts static index.html files to permalink version" do + expect(contents).to match %r!http://example\.org/some-subfolder/! + end + + it "does include assets or any static files with .xhtml and .htm extensions" do + expect(contents).to match %r!/some-subfolder/xhtml\.xhtml! + expect(contents).to match %r!/some-subfolder/htm\.htm! + end + + it "does include assets or any static files with .pdf extension" do + expect(contents).to match %r!/static_files/test.pdf! + end + + it "does not include any static files named 404.html" do + expect(contents).not_to match %r!/static_files/404.html! + end + + if Gem::Version.new(Jekyll::VERSION) >= Gem::Version.new("3.4.2") + it "does not include any static files that have set 'sitemap: false'" do + expect(contents).not_to match %r!/static_files/excluded\.pdf! + end + + it "does not include any static files that have set 'sitemap: false'" do + expect(contents).not_to match %r!/static_files/html_file\.html! + end + end + + it "does not include posts that have set 'sitemap: false'" do + expect(contents).not_to match %r!/exclude-this-post\.html! + end + + it "does not include pages that have set 'sitemap: false'" do + expect(contents).not_to match %r!/exclude-this-page\.html! + end + + it "does not include the 404 page" do + expect(contents).not_to match %r!/404\.html! + end + + it "correctly formats timestamps of static files" do + expect(contents).to match %r!/this-is-a-subfile\.html\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(-|\+)\d{2}:\d{2}! + end + + it "includes the correct number of items" do + # static_files/excluded.pdf is excluded on Jekyll 3.4.2 and above + if Gem::Version.new(Jekyll::VERSION) >= Gem::Version.new("3.4.2") + expect(contents.scan(%r!(?=)!).count).to eql 20 + else + expect(contents.scan(%r!(?=)!).count).to eql 21 + end + end + + context "with a baseurl" do + let(:config) do + Jekyll.configuration(Jekyll::Utils.deep_merge_hashes(overrides, "baseurl" => "/bass")) + end + + it "correctly adds the baseurl to the static files" do + expect(contents).to match %r!http://example\.org/bass/some-subfolder/this-is-a-subfile\.html! + end + + it "correctly adds the baseurl to the collections" do + expect(contents).to match %r!http://example\.org/bass/my_collection/test\.html! + end + + it "correctly adds the baseurl to the pages" do + expect(contents).to match %r!http://example\.org/bass/! + expect(contents).to match %r!http://example\.org/bass/some-subfolder/this-is-a-subpage\.html! + end + + it "correctly adds the baseurl to the posts" do + expect(contents).to match %r!http://example\.org/bass/2014/03/04/march-the-fourth\.html! + expect(contents).to match %r!http://example\.org/bass/2014/03/02/march-the-second\.html! + expect(contents).to match %r!http://example\.org/bass/2013/12/12/dec-the-second\.html! + end + + it "adds baseurl to robots.txt" do + content = File.read(dest_dir("robots.txt")) + expect(content).to match("Sitemap: http://example.org/bass/sitemap.xml") + end + end + + context "with urls that needs URI encoding" do + let(:config) do + Jekyll.configuration(Jekyll::Utils.deep_merge_hashes(overrides, "url" => "http://ümlaut.example.org")) + end + + it "performs URI encoding of site url" do + expect(contents).to match %r!http://xn--mlaut-jva.example.org/! + expect(contents).to match %r!http://xn--mlaut-jva.example.org/some-subfolder/this-is-a-subpage.html! + expect(contents).to match %r!http://xn--mlaut-jva.example.org/2014/03/04/march-the-fourth.html! + expect(contents).to match %r!http://xn--mlaut-jva.example.org/2016/04/01/%E9%94%99%E8%AF%AF.html! + expect(contents).to match %r!http://xn--mlaut-jva.example.org/2016/04/02/%E9%94%99%E8%AF%AF.html! + expect(contents).to match %r!http://xn--mlaut-jva.example.org/2016/04/03/%E9%94%99%E8%AF%AF.html! + end + + it "does not double-escape urls" do + expect(contents).to_not match %r!%25! + end + + context "readme" do + let(:contents) { File.read(dest_dir("robots.txt")) } + + it "has no layout" do + expect(contents).not_to match(%r!\ATHIS IS MY LAYOUT!) + end + + it "creates a robots.txt file" do + expect(File.exist?(dest_dir("robots.txt"))).to be_truthy + end + + it "renders liquid" do + expect(contents).to match("Sitemap: http://xn--mlaut-jva.example.org/sitemap.xml") + end + end + end + + context "with user-defined robots.txt" do + let(:fixture) { "/" } + let(:fixture_source) { robot_fixtures(fixture) } + let(:fixture_dest) { robot_fixtures(fixture, "_site") } + let(:robot_contents) { File.read(robot_fixtures(fixture, "_site", "robots.txt")).strip } + let(:overrides) do + { + "source" => fixture_source, + "destination" => fixture_dest, + "url" => "http://example.org", + } + end + + before(:each) { setup_fixture(fixture) } + after(:each) { cleanup_fixture(fixture) } + + context "as a static-file at source-root" do + let(:fixture) { "static-at-source-root" } + + it "doesn't override the robots file" do + expect(robot_contents).to eql("Allow: /") + end + end + + context "as a static-file in a subdir" do + let(:fixture) { "static-in-subdir" } + + it "generates a valid robot.txt" do + expect(robot_contents).to eql("Sitemap: http://example.org/sitemap.xml") + end + end + + context "as a page at root" do + let(:fixture) { "page-at-root" } + + it "doesn't override the robots file" do + expect(robot_contents).to eql("Allow: http://example.org") + end + end + + context "as a page with permalink in a subdir" do + let(:fixture) { "permalinked-page-in-subdir" } + + it "doesn't override the robots file" do + expect(robot_contents).to eql("Allow: http://example.org") + end + end + end +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/page-at-root/robots.txt b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/page-at-root/robots.txt new file mode 100644 index 00000000..e63befd2 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/page-at-root/robots.txt @@ -0,0 +1,4 @@ +--- +--- + +Allow: {{ site.url }} diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/permalinked-page-in-subdir/assets/robots.txt b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/permalinked-page-in-subdir/assets/robots.txt new file mode 100644 index 00000000..0e396d1b --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/permalinked-page-in-subdir/assets/robots.txt @@ -0,0 +1,5 @@ +--- +permalink: '/robots.txt' +--- + +Allow: {{ site.url }} diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-at-source-root/robots.txt b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-at-source-root/robots.txt new file mode 100644 index 00000000..e9f7c886 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-at-source-root/robots.txt @@ -0,0 +1 @@ +Allow: / diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-in-subdir/assets/robots.txt b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-in-subdir/assets/robots.txt new file mode 100644 index 00000000..e9f7c886 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/robot-fixtures/static-in-subdir/assets/robots.txt @@ -0,0 +1 @@ +Allow: / diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/spec_helper.rb b/bin/gems/jekyll-sitemap-1.4.0/spec/spec_helper.rb new file mode 100644 index 00000000..ebeaef9e --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/spec_helper.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "jekyll" +require "fileutils" +require File.expand_path("../lib/jekyll-sitemap", __dir__) + +Jekyll.logger.log_level = :error + +RSpec.configure do |config| + config.run_all_when_everything_filtered = true + config.filter_run :focus + config.order = "random" + + SOURCE_DIR = File.expand_path("fixtures", __dir__) + DEST_DIR = File.expand_path("dest", __dir__) + ROBOT_FIXTURES = File.expand_path("robot-fixtures", __dir__) + ROBOT_FIXTURE_ITEMS = %w(_posts _layouts _config.yml index.html).freeze + + def source_dir(*files) + File.join(SOURCE_DIR, *files) + end + + def dest_dir(*files) + File.join(DEST_DIR, *files) + end + + def robot_fixtures(*subdirs) + File.join(ROBOT_FIXTURES, *subdirs) + end + + def setup_fixture(directory) + ROBOT_FIXTURE_ITEMS.each { |item| FileUtils.cp_r(source_dir(item), robot_fixtures(directory)) } + end + + def cleanup_fixture(directory, dest_dirname = "_site") + (ROBOT_FIXTURE_ITEMS + [dest_dirname]).each do |item| + FileUtils.remove_entry(robot_fixtures(directory, item)) + end + end +end diff --git a/bin/gems/jekyll-sitemap-1.4.0/spec/test_jekyll-last-modified-at.rb b/bin/gems/jekyll-sitemap-1.4.0/spec/test_jekyll-last-modified-at.rb new file mode 100644 index 00000000..4387b051 --- /dev/null +++ b/bin/gems/jekyll-sitemap-1.4.0/spec/test_jekyll-last-modified-at.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Jekyll::JekyllSitemap) do + let(:overrides) do + { + "source" => source_dir, + "destination" => dest_dir, + "url" => "http://example.org", + "collections" => { + "my_collection" => { "output" => true }, + "other_things" => { "output" => false }, + }, + } + end + let(:config) do + Jekyll.configuration(overrides) + end + let(:site) { Jekyll::Site.new(config) } + let(:contents) { File.read(dest_dir("sitemap.xml")) } + before(:each) do + # simulate `last_modified_at` injection by `jekyll-last-modified-at` plugin + Jekyll::Hooks.register([:pages, :documents], :post_init) do |page| + page.data["last_modified_at"] = Time.parse("2015-01-18T00:00:00+00:00") + end + + site.process + end + + context "with jekyll-last-modified-at" do + it "correctly adds the modified time to the posts" do + expect(contents).to match( + %r! + http://example.org/2015/01/18/jekyll-last-modified-at.html\s+ + 2015-01-18T00:00:00\+00:00 + !x + ) + end + + it "correctly adds the modified time to the pages" do + expect(contents).to match( + %r! + http://example.org/jekyll-last-modified-at/page.html\s+ + 2015-01-18T00:00:00\+00:00 + !x + ) + end + end +end diff --git a/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch.rb b/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch.rb new file mode 100644 index 00000000..0f8b68bc --- /dev/null +++ b/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require "jekyll-watch/version" +require_relative "jekyll/watcher" +require_relative "jekyll/commands/watch" diff --git a/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch/version.rb b/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch/version.rb new file mode 100644 index 00000000..84733776 --- /dev/null +++ b/bin/gems/jekyll-watch-2.2.1/lib/jekyll-watch/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Jekyll + module Watch + VERSION = "2.2.1" + end +end diff --git a/bin/gems/jekyll-watch-2.2.1/lib/jekyll/commands/watch.rb b/bin/gems/jekyll-watch-2.2.1/lib/jekyll/commands/watch.rb new file mode 100644 index 00000000..bf4321d1 --- /dev/null +++ b/bin/gems/jekyll-watch-2.2.1/lib/jekyll/commands/watch.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + module Watch + extend self + + def init_with_program(prog); end + + # Build your jekyll site + # Continuously watch if `watch` is set to true in the config. + def process(options) + Jekyll.logger.log_level = :error if options["quiet"] + Jekyll::Watcher.watch(options) if options["watch"] + end + end + end +end diff --git a/bin/gems/jekyll-watch-2.2.1/lib/jekyll/watcher.rb b/bin/gems/jekyll-watch-2.2.1/lib/jekyll/watcher.rb new file mode 100644 index 00000000..ea49ad6e --- /dev/null +++ b/bin/gems/jekyll-watch-2.2.1/lib/jekyll/watcher.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require "listen" + +module Jekyll + module Watcher + extend self + + # Public: Continuously watch for file changes and rebuild the site + # whenever a change is detected. + # + # If the optional site argument is populated, that site instance will be + # reused and the options Hash ignored. Otherwise, a new site instance will + # be instantiated from the options Hash and used. + # + # options - A Hash containing the site configuration + # site - The current site instance (populated starting with Jekyll 3.2) + # (optional, default: nil) + # + # Returns nothing. + def watch(options, site = nil) + ENV["LISTEN_GEM_DEBUGGING"] ||= "1" if options["verbose"] + + site ||= Jekyll::Site.new(options) + listener = build_listener(site, options) + listener.start + + Jekyll.logger.info "Auto-regeneration:", "enabled for '#{options["source"]}'" + + unless options["serving"] + trap("INT") do + listener.stop + Jekyll.logger.info "", "Halting auto-regeneration." + exit 0 + end + + sleep_forever + end + rescue ThreadError + # You pressed Ctrl-C, oh my! + end + + private + + def build_listener(site, options) + Listen.to( + options["source"], + :ignore => listen_ignore_paths(options), + :force_polling => options["force_polling"], + &listen_handler(site) + ) + end + + def listen_handler(site) + proc do |modified, added, removed| + t = Time.now + c = modified + added + removed + n = c.length + + Jekyll.logger.info "Regenerating:", + "#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}" + + c.each { |path| Jekyll.logger.info "", path["#{site.source}/".length..-1] } + process(site, t) + end + end + + def normalize_encoding(obj, desired_encoding) + case obj + when Array + obj.map { |entry| entry.encode!(desired_encoding, entry.encoding) } + when String + obj.encode!(desired_encoding, obj.encoding) + end + end + + def custom_excludes(options) + Array(options["exclude"]).map { |e| Jekyll.sanitized_path(options["source"], e) } + end + + def config_files(options) + %w(yml yaml toml).map do |ext| + Jekyll.sanitized_path(options["source"], "_config.#{ext}") + end + end + + def to_exclude(options) + [ + config_files(options), + options["destination"], + custom_excludes(options), + ].flatten + end + + # Paths to ignore for the watch option + # + # options - A Hash of options passed to the command + # + # Returns a list of relative paths from source that should be ignored + def listen_ignore_paths(options) + source = Pathname.new(options["source"]).expand_path + paths = to_exclude(options) + + paths.map do |p| + absolute_path = Pathname.new(normalize_encoding(p, options["source"].encoding)).expand_path + next unless absolute_path.exist? + + begin + relative_path = absolute_path.relative_path_from(source).to_s + relative_path = File.join(relative_path, "") if absolute_path.directory? + unless relative_path.start_with?("../") + path_to_ignore = %r!^#{Regexp.escape(relative_path)}! + Jekyll.logger.debug "Watcher:", "Ignoring #{path_to_ignore}" + path_to_ignore + end + rescue ArgumentError + # Could not find a relative path + end + end.compact + [%r!^\.jekyll\-metadata!] + end + + def sleep_forever + loop { sleep 1000 } + end + + def process(site, time) + begin + site.process + Jekyll.logger.info "", "...done in #{Time.now - time} seconds." + rescue StandardError => e + Jekyll.logger.warn "Error:", e.message + Jekyll.logger.warn "Error:", "Run jekyll build --trace for more information." + end + Jekyll.logger.info "" + end + end +end diff --git a/bin/gems/jekyll_download_link-1.0.3/.rubocop.yml b/bin/gems/jekyll_download_link-1.0.3/.rubocop.yml new file mode 100644 index 00000000..add4f465 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/.rubocop.yml @@ -0,0 +1,69 @@ +require: + # - rubocop-jekyll + - rubocop-md + - rubocop-performance + - rubocop-rake + - rubocop-rspec + +# inherit_gem: +# rubocop-jekyll: .rubocop.yml + +AllCops: + Exclude: + - binstub/**/* + - vendor/**/* + - Gemfile* + - jekyll_download_link.gemspec + NewCops: enable + +Gemspec/DeprecatedAttributeAssignment: + Enabled: false + +Gemspec/RequireMFA: + Enabled: false + +Gemspec/RequiredRubyVersion: + Enabled: false + +Layout/InitialIndentation: + Exclude: + - README.md + +Layout/HashAlignment: + EnforcedColonStyle: table + Exclude: + - jekyll_download_link.gemspec + +Layout/LineLength: + Max: 150 + +Lint/RedundantCopDisableDirective: + Exclude: + - jekyll_download_link.gemspec + +Lint/SymbolConversion: + Exclude: + - jekyll_download_link.gemspec + +Metrics/BlockLength: + Exclude: + - jekyll_download_link.gemspec + - spec/**/* + Max: 35 + +Metrics/ClassLength: + Exclude: + - spec/**/* + +Naming/FileName: + Exclude: + - Rakefile + +RSpec/MultipleExpectations: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma diff --git a/bin/gems/jekyll_download_link-1.0.3/CHANGELOG.md b/bin/gems/jekyll_download_link-1.0.3/CHANGELOG.md new file mode 100644 index 00000000..346436ac --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/CHANGELOG.md @@ -0,0 +1,28 @@ +# Change Log + + +## 1.0.3 / 2024-07-24 + +* Updated to `jekyll_plugin_support` v1.0.0 + + +## 1.0.2 / 2023-12-02 + +* Now depends on `jekyll_plugin_support` +* Demo website added +* Better Rubocop support +* Pinned to `json` gem v3.6.2 because Jekyll 4.3.2 requires it + + +## 1.0.1 / 2022-04-05 + +* Updated to `jekyll_plugin_logger` v2.1.0 + + +## 1.0.0 / 2022-03-16 + +* Published as a gem + +## 2020-10-03 + +* Initial version published at https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html diff --git a/bin/gems/jekyll_download_link-1.0.3/LICENSE.txt b/bin/gems/jekyll_download_link-1.0.3/LICENSE.txt new file mode 100644 index 00000000..805ae6c4 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Mike Slinn + +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/bin/gems/jekyll_download_link-1.0.3/README.md b/bin/gems/jekyll_download_link-1.0.3/README.md new file mode 100644 index 00000000..6796b482 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/README.md @@ -0,0 +1,144 @@ +# `jekyll_download_link` [![Gem Version](https://badge.fury.io/rb/jekyll_download_link.svg)](https://badge.fury.io/rb/jekyll_download_link) + +`jekyll_download_link` is a Jekyll tag plugin that generates a link to the given URI, +which must be a file on the server. +The file name can be absolute or relative to the top-level directory of the website. + + +## Usage + +```html +{% download_link cloud9.tar %} +``` + +Generates: + +```html +cloud9.tar (4.5 KB) +``` + +Which renders as:
+`cloud9.tar` (4.5 KB) + + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'jekyll_download_link' +``` + +And then execute: + +```shell +$ bundle install +``` + + +## Additional Information + +More information is available on +[Mike Slinn’s website](https://mslinn.com/jekyll/3000-jekyll-plugins.html#download_link). + + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. + +You can also run `bin/console` for an interactive prompt that will allow you to experiment. + + +### Build and Install Locally + +To build and install this gem onto your local machine, type: + +```shell +$ bundle exec rake install +jekyll_download_link 1.0.0 built to pkg/jekyll_download_link-0.1.0.gem. +jekyll_download_link (1.0.0) installed. +``` + +Examine the newly built gem: + +```shell +$ gem info jekyll_download_link + +*** LOCAL GEMS *** + +jekyll_download_link (1.0.0) + Author: Mike Slinn + Homepage: + https://github.com/mslinn/jekyll_download_link + License: MIT + Installed at: /home/mslinn/.gems + + Generates Jekyll logger with colored output. +``` + + +## Demo Website + +A test/demo website is provided in the `demo` directory. +You can run it under a debugger, or let it run free. + +The `demo/_bin/debug` script can set various parameters for the demo. +View the help information with the `-h` option: + +```shell +$ demo/_bin/debug -h + +debug - Run the demo Jekyll website. + +By default the demo Jekyll website runs without restriction under ruby-debug-ide and debase. +View it at http://localhost:4444 + +Options: + -h Show this error message + + -r Run freely, without a debugger +``` + + +### Debugging the Demo + +To run under a debugger, for example Visual Studio Code: + +1. Set breakpoints. +2. Initiate a debug session from the command line: + + ```shell + $ demo/bin/debug + ``` + +3. Once the `Fast Debugger` signon appears, launch the Visual Studio Code launch configuration called `Attach rdebug-ide`. +4. View the generated website at [`http://localhost:4444`](http://localhost:4444). + + +### Build and Push to RubyGems + +To release a new version, + + 1. Update the version number in `version.rb`. + 2. Commit all changes to git; if you don't the next step might fail with an unexplainable error message. + 3. Run the following: + + ```shell + $ bundle exec rake release + ``` + + The above creates a git tag for the version, commits the created tag, + and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org). + + +## Contributing + +1. Fork the project +2. Create a descriptively named feature branch +3. Add your feature +4. Submit a pull request + + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/bin/gems/jekyll_download_link-1.0.3/Rakefile b/bin/gems/jekyll_download_link-1.0.3/Rakefile new file mode 100644 index 00000000..da5c9db9 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/Rakefile @@ -0,0 +1,5 @@ +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) +task default: :spec diff --git a/bin/gems/jekyll_download_link-1.0.3/jekyll_download_link.gemspec b/bin/gems/jekyll_download_link-1.0.3/jekyll_download_link.gemspec new file mode 100644 index 00000000..10ca4bba --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/jekyll_download_link.gemspec @@ -0,0 +1,36 @@ +require_relative 'lib/jekyll_download_link/version' + +Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength + github = 'https://github.com/mslinn/jekyll_download_link' + + spec.authors = ['Mike Slinn'] + spec.bindir = 'exe' + spec.description = <<~END_OF_DESC + Provides a Jekyll tag that generates an href to a file for the user to download, plus human-friendly filesize. + END_OF_DESC + spec.email = ['mslinn@mslinn.com'] + spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md'] + spec.homepage = 'https://www.mslinn.com/jekyll_plugins/jekyll_download_link.html' + spec.license = 'MIT' + spec.metadata = { + 'allowed_push_host' => 'https://rubygems.org', + 'bug_tracker_uri' => "#{github}/issues", + 'changelog_uri' => "#{github}/CHANGELOG.md", + 'homepage_uri' => spec.homepage, + 'source_code_uri' => github, + } + spec.name = 'jekyll_download_link' + spec.post_install_message = <<~END_MESSAGE + + Thanks for installing #{spec.name}! + + END_MESSAGE + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.6.0' + spec.summary = 'Provides a Jekyll tag that generates an href to a file for the user to download, plus human-friendly filesize.' + spec.test_files = spec.files.grep(%r!^(test|spec|features)/!) + spec.version = JekyllDownloadLinkVersion::VERSION + + spec.add_dependency 'jekyll', '>= 4.3.3' + spec.add_dependency 'jekyll_plugin_support', '>= 1.0.0' +end diff --git a/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link.rb b/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link.rb new file mode 100644 index 00000000..a17f63ca --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link.rb @@ -0,0 +1,36 @@ +require 'jekyll_plugin_support' +require_relative 'jekyll_download_link/version' + +module JekyllPluginDownloadLinkName + PLUGIN_NAME = 'download_link'.freeze +end + +# Generates an href to a file for the user to download from the site. +# Also shows the file size in a human-readable format. +class DownloadLink < JekyllSupport::JekyllTagNoArgParsing + include JekyllDownloadLinkVersion + + def self.as_size(string) + units = %w[B KB MB GB TB] + + size, unit = units.reduce(string.to_f) do |(fsize, _), utype| + fsize > 512 ? [fsize / 1024, utype] : (break [fsize, utype]) + end + + fmt_str = "#{size > 9 || size.modulo(1) < 0.1 ? '%d' : '%.1f'} %s" + format(fmt_str, size, unit) + end + + def render_impl + @filename = @argument_string.delete('"').delete("'").strip + + source = @config['source'] + file_fq = File.join(source, @filename) + abort "Error: '#{file_fq}' not found. See the link tag in" unless File.exist?(file_fq) + + size_str = self.class.as_size(File.size(file_fq)) + "#{@filename} (#{size_str})" + end + + JekyllSupport::JekyllPluginHelper.register(self, JekyllPluginDownloadLinkName::PLUGIN_NAME) +end diff --git a/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link/version.rb b/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link/version.rb new file mode 100644 index 00000000..57fd0d09 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/lib/jekyll_download_link/version.rb @@ -0,0 +1,3 @@ +module JekyllDownloadLinkVersion + VERSION = '1.0.3'.freeze +end diff --git a/bin/gems/jekyll_download_link-1.0.3/spec/download_link_spec.rb b/bin/gems/jekyll_download_link-1.0.3/spec/download_link_spec.rb new file mode 100644 index 00000000..c0406285 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/spec/download_link_spec.rb @@ -0,0 +1,19 @@ +require 'jekyll_plugin_support' +require_relative '../lib/jekyll_download_link' + +RSpec.describe(DownloadLink) do + let(:config) { instance_double(Configuration) } + let(:context) do + context_ = instance_double(Liquid::Context) + context_.config = config + context_ + end + + it 'generates proper size comment' do + expect(described_class.as_size('123')).to eq('123 B') + expect(described_class.as_size('123456')).to eq('120 KB') + expect(described_class.as_size('123456789')).to eq('117 MB') + expect(described_class.as_size('123456789012')).to eq('114 GB') + expect(described_class.as_size('123456789012345')).to eq('112 TB') + end +end diff --git a/bin/gems/jekyll_download_link-1.0.3/spec/spec_helper.rb b/bin/gems/jekyll_download_link-1.0.3/spec/spec_helper.rb new file mode 100644 index 00000000..86221d55 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/spec/spec_helper.rb @@ -0,0 +1,10 @@ +require 'jekyll' +require_relative '../lib/jekyll_download_link' + +RSpec.configure do |config| + config.filter_run_when_matching focus: true + # config.order = 'random' + + # See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures + config.example_status_persistence_file_path = 'spec/status_persistence.txt' +end diff --git a/bin/gems/jekyll_download_link-1.0.3/spec/status_persistence.txt b/bin/gems/jekyll_download_link-1.0.3/spec/status_persistence.txt new file mode 100644 index 00000000..e10f6447 --- /dev/null +++ b/bin/gems/jekyll_download_link-1.0.3/spec/status_persistence.txt @@ -0,0 +1,3 @@ +example_id | status | run_time | +--------------------------------- | ------ | --------------- | +./spec/download_link_spec.rb[1:1] | passed | 0.00116 seconds | diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/.rubocop.yml b/bin/gems/jekyll_plugin_logger-2.1.2/.rubocop.yml new file mode 100644 index 00000000..6930bde7 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/.rubocop.yml @@ -0,0 +1,85 @@ +require: + # - rubocop-jekyll + - rubocop-md + - rubocop-performance + - rubocop-rake + - rubocop-rspec + +# inherit_gem: +# rubocop-jekyll: .rubocop.yml + +AllCops: + Exclude: + - demo/_site/**/* + - binstub/**/* + - vendor/**/* + - jekyll_plugin_logger.gemspec + NewCops: enable + +Gemspec/DeprecatedAttributeAssignment: + Enabled: false + +Gemspec/RequiredRubyVersion: + Enabled: false + +Gemspec/RequireMFA: + Enabled: false + +# Jekyll/NoPutsAllowed: +# Exclude: +# - spec/**/* + +Layout/InitialIndentation: + Exclude: + - README.md + +Layout/HashAlignment: + EnforcedColonStyle: table + EnforcedHashRocketStyle: table + +Layout/LineLength: + Max: 150 + +Lint/RedundantCopDisableDirective: + Exclude: + - jekyll_plugin_logger.gemspec + +Metrics/AbcSize: + Max: 25 + +Metrics/BlockLength: + Exclude: + - jekyll_plugin_logger.gemspec + - spec/**/* + +Metrics/ClassLength: + Exclude: + - spec/**/* + +Metrics/CyclomaticComplexity: + Max: 25 + +Metrics/MethodLength: + Max: 25 + +Metrics/PerceivedComplexity: + Max: 20 + +Naming/FileName: + Exclude: + - Rakefile + +RSpec/ExampleLength: + Max: 20 + +RSpec/MultipleExpectations: + Max: 15 + +Style/Documentation: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/CHANGELOG.md b/bin/gems/jekyll_plugin_logger-2.1.2/CHANGELOG.md new file mode 100644 index 00000000..0913bb36 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/CHANGELOG.md @@ -0,0 +1,47 @@ +# Change Log + +## 2.1.2 / 2023-11-21 + +* Added `demo`. +* Added `fatal` and `unknown` log levels. + + +## 2.1.1 / 2022-04-15 + +* Fixed `progname` reference for the `PluginMetaLogger` debug startup statement. + + +## 2.1.0 / 2022-04-05 + +* Changed how config info is made available. +* `PluginLogger` is a class once again. + + +## 2.0.1 / 2022-04-05 + +* Changed to registration hook to `:site`, `:after_reset` because that is the first hook that gets called. +* Improved the detection of various types of `progname`. + + +## 2.0.0 / 2022-03-16 + +* Completely rewrote this plugin, now not a class, + but a module that monkey patches the existing Jekyll logger for compatibility. +* Renamed the gem from `jekyll_logger_factory` to `jekyll_plugin_logger`. +* Automatically obtains plugin class name and uses that as `progname`. +* `:into` level output is colored cyan. + + +## 1.0.0 / 2022-03-16 + +* Published as a gem. +* New instances are now created with `new` instead of `create_logger`. +* Now subclasses Jekyll's Stevenson logger. +* Documentation improved, clarifies that the only supported levels are those provided by the + Stevenson logger: `:debug`, `:info`, and `:error`. +* No longer supports control over where log output goes; STDERR and STDOUT are automatically selected according to log level. + + +## 2020-12-28 + +* Initial version published at https://www.mslinn.com/blog/2020/12/28/custom-logging-in-jekyll-plugins.html diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/LICENSE.txt b/bin/gems/jekyll_plugin_logger-2.1.2/LICENSE.txt new file mode 100644 index 00000000..805ae6c4 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Mike Slinn + +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/bin/gems/jekyll_plugin_logger-2.1.2/README.md b/bin/gems/jekyll_plugin_logger-2.1.2/README.md new file mode 100644 index 00000000..998f47ea --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/README.md @@ -0,0 +1,160 @@ +# `jekyll_plugin_logger` [![Gem Version](https://badge.fury.io/rb/jekyll_plugin_logger.svg)](https://badge.fury.io/rb/jekyll_plugin_logger) + +`jekyll_plugin_logger` is a Jekyll plugin, packaged as a Ruby gem, that provides colored console logs for Jekyll plugins. +It is based on the standard Ruby [`Logger`](https://ruby-doc.org/stdlib-3.1.0/libdoc/logger/rdoc/Logger.html) class. + +Log levels are normally set from `_config.yml`: + +* 0: `debug` +* 1: `info` +* 2: `warn` +* 3: `error` +* 4: `fatal` +* 5: `unknown` (displays as `ANY`) + + +## Usage + +The [`demo/_plugins/`](demo/_plugins/) directory demonstrates two ways of working with `jekyll_plugin_logger`: + +* `liquid_tag.rb`, a Jekyll plugin subclassed from + [`Liquid::Tag`](https://jekyllrb.com/docs/plugins/tags/). +* `support_tag.rb`, a Jekyll plugin subclassed from + [`JekyllSupport::JekyllTag`](https://www.mslinn.com/jekyll_plugins/jekyll_plugin_support.html). + + +## Installation + +### To A Jekyll Website + +Add the following to your Jekyll website's `Gemfile`: + +```ruby +group :jekyll_plugins do + gem 'jekyll_plugin_logger' +end +``` + +Install all of the dependent gems of your Jekyll website by typing: + +```shell +$ bundle +``` + +### To A Jekyll Plugin Packaged As A Gem + +Add the following to your Gem’s `.gemspec`: + +```ruby +Gem::Specification.new do |spec| + spec.add_dependency 'jekyll_plugin_logger' +end +``` + +Install all of the dependent gems of your Gem by typing: + +```shell +$ bundle +``` + + +## Configuration + +The default log level is `info`. +You can change the log level by editing `_config.yml` and adding a `plugin_loggers` section. +Within that section, add an entry for the fully qualified name of your plugin class. + +For example, the fully qualified class names of the Jekyll plugins provided in `demo/_plugins/` +are `Raw::InlineTag` and `Support::InlineTag`, respectively. +Their log levels can be set to `debug` with the following entries in [`_config.yml`](demo/_config.yml): + +```yaml +plugin_loggers: + Raw::InlineTag: debug # Notice the module name is specified as well as the class name + Support::InlineTag: debug # Notice the module name is specified as well as the class name +``` + + +## Run the Demo + +Run the demo by typing: + +```shell +$ demo/_bin/debug -r +``` + +See what happens to the output when you edit the logging levels in the `plugin_loggers` section of `_config.yml`. +You will have to restart the demo after each modification to `_config.yml` +in order to see the output change. + + +## Additional Information + +More information is available on Mike Slinn's web site about +[Jekyll plugins](https://www.mslinn.com/jekyll/10100-custom-logging-in-jekyll-plugins.html). + + +## Development + +After checking out the `jekyll_plugin_logger` repository, +run `bin/setup` to install dependencies, +which includes development dependencies. + +You can then run `bin/console` for an interactive prompt that will allow you to experiment. + + +### Build and Install Locally + +To build and install this gem onto your local machine, run: + +```shell +$ bundle exec rake install +jekyll_plugin_logger 1.0.0 built to pkg/jekyll_plugin_logger-0.1.0.gem. +jekyll_plugin_logger (1.0.0) installed. +``` + +Examine the newly built gem: + +```shell +$ gem info jekyll_plugin_logger + +*** LOCAL GEMS *** + +jekyll_plugin_logger (1.0.0) + Author: Mike Slinn + Homepage: + https://github.com/mslinn/jekyll_plugin_logger + License: MIT + Installed at: /home/mslinn/.gems + + Generates a Jekyll logger with colored output. +``` + + +### Build and Push to RubyGems + +To release a new version, + +1. Update the version number in `version.rb`. +2. Commit all changes to git; if you don't the next step might fail with an unexplainable error message. +3. Run the following: + + ```shell + $ bundle exec rake release + ``` + + The above creates a git tag for the version, commits the created tag, + and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org). + + +## Contributing + +1. Fork the project +2. Create a descriptively named feature branch +3. Add your feature +4. Submit a pull request + + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/Rakefile b/bin/gems/jekyll_plugin_logger-2.1.2/Rakefile new file mode 100644 index 00000000..1db09e9b --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/Rakefile @@ -0,0 +1,21 @@ +require 'bump/tasks' +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +# do not always tag the version +# Bump.tag_by_default = false + +# bump the version in additional files +# Bump.replace_in_default = ['Readme.md'] + +# Maintain changelog: +Bump.changelog = true + +# Open the changelog in an editor when bumping +Bump.changelog = :editor + +# Configure bump to not use a prefix: +ENV['TAG_PREFIX'] = '' + +RSpec::Core::RakeTask.new(:spec) +task default: :spec diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/jekyll_plugin_logger.gemspec b/bin/gems/jekyll_plugin_logger-2.1.2/jekyll_plugin_logger.gemspec new file mode 100644 index 00000000..2b202591 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/jekyll_plugin_logger.gemspec @@ -0,0 +1,36 @@ +require_relative 'lib/jekyll_plugin_logger/version' + +Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength + github = 'https://github.com/mslinn/jekyll_plugin_logger' + + spec.authors = ['Mike Slinn'] + spec.bindir = 'exe' + spec.description = <<~END_OF_DESC + Generates Jekyll logger with colored output. + END_OF_DESC + spec.email = ['mslinn@mslinn.com'] + spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md'] + spec.homepage = 'https://www.mslinn.com/jekyll_plugins/jekyll_plugin_logger.html' + spec.license = 'MIT' + spec.metadata = { + 'allowed_push_host' => 'https://rubygems.org', + 'bug_tracker_uri' => "#{github}/issues", + 'changelog_uri' => "#{github}/CHANGELOG.md", + 'homepage_uri' => spec.homepage, + 'source_code_uri' => github, + } + spec.name = 'jekyll_plugin_logger' + spec.post_install_message = <<~END_MESSAGE + + Thanks for installing #{spec.name}! + + END_MESSAGE + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.6.0' + spec.summary = 'Generates a Jekyll logger with colored output.' + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.version = JekyllPluginLoggerVersion::VERSION + + spec.add_dependency 'bump' + spec.add_dependency 'jekyll', '>= 3.5.0' +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger.rb b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger.rb new file mode 100644 index 00000000..a99c5d9b --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger.rb @@ -0,0 +1,152 @@ +require 'colorator' +require 'logger' +require 'yaml' +require_relative 'jekyll_plugin_logger/version' +require_relative 'jekyll_plugin_meta_logger' + +module JekyllPluginLoggerName + PLUGIN_NAME = 'jekyll_plugin_logger'.freeze +end + +# Once the meta-logger is made (see `PluginMetaLogger`, below) new instances of `PluginLogger` can be created with log levels set +# by `config` entries. +# @example Create new `PluginLogger`s like this: +# @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) +# +# self can be a module, a class, a string, or a symbol. +# +# Best practice is to invoke `info`, `warn, `debug` and `error` methods by passing blocks that contain the message. +# The blocks will only be evaluated if output for that level is enabled. +# @example Use `PluginLogger`s like this: +# @logger.info { "This is only evaluated if info level debugging is enabled" } +# +# For more information about the logging feature in the Ruby standard library, +# @see https://ruby-doc.org/stdlib-2.7.1/libdoc/logger/rdoc/Logger.html +class PluginLogger + # This method should only be called by PluginMetaLogger + # @param log_level [String, Symbol, Integer] can be specified as $stderr or $stdout, + # or an integer from 0..3 (inclusive), + # or as a case-insensitive string + # (`debug`, `info`, `warn`, `error`, or `DEBUG`, `INFO`, `WARN`, `ERROR`), + # or as a symbol (`:debug`, `:info`, `:warn`, `:error` ). + # + # 0: debug + # 1: info + # 2: warn + # 3: error + # 4: fatal + # 5: unknown (displays as ANY) + # + # @param config [YAML] is normally created by reading a YAML file such as Jekyll's `_config.yml`. + # When invoking from a Jekyll plugin, provide `site.config`, + # which is available from all types of Jekyll plugins as `Jekyll.configuration({})`. + # + # @example If `progname` has value `abc`, then the YAML to override the programmatically set log_level to `debug` is: + # logger_factory: + # abc: debug + def initialize(klass, config = nil, stream_name = $stdout) + @config = config + plugin_loggers = config&.[] 'plugin_loggers' + + @logger = Logger.new stream_name + @logger.progname = derive_progname klass + @logger.level = :info + @logger.level = plugin_loggers[@logger.progname] if plugin_loggers&.[] @logger.progname + # puts "PluginLogger.initialize: @logger.progname=#{@logger.progname} set to #{@logger.level}".red + @logger.formatter = proc { |severity, _datetime, progname, msg| + "#{severity} #{progname}: #{msg}\n" + } + end + + def debug(progname = nil, &block) + if block + @logger.debug(@logger.progname) { (yield block).to_s.magenta } + else + @logger.debug(@logger.progname) { progname.to_s.magenta } + end + end + + def info(progname = nil, &block) + if block + @logger.info(@logger.progname) { (yield block).to_s.cyan } + else + @logger.info(@logger.progname) { progname.to_s.cyan } + end + end + + def level=(value) + @logger.level = value + end + + # @return the log level specified in _config.yml, or :info (1) if not specified + def level + @logger.level + end + + def progname=(value) + @logger.progname = value + end + + def progname + @logger.progname + end + + def warn(progname = nil, &block) + if block + @logger.warn(@logger.progname) { (yield block).to_s.yellow } + else + @logger.warn(@logger.progname) { progname.to_s.yellow } + end + end + + def error(progname = nil, &block) + if block + @logger.error(@logger.progname) { (yield block).to_s.red } + else + @logger.error(@logger.progname) { progname.to_s.red } + end + end + + def fatal(progname = nil, &block) + if block + @logger.fatal(@logger.progname) { (yield block).to_s.red.bold } + else + @logger.fatal(@logger.progname) { progname.to_s.red.bold } + end + end + + # @return the log level specified in _config.yml, or :info (1) if not specified + # Available colors are: :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, and the modifier :bold + def level_as_sym + return :unknown if @logger.level.negative? || level > 4 + + %i[debug info warn error fatal unknown][@logger.level] + end + + def unknown(progname = nil, &block) + if block + @logger.unknown(@logger.progname) { (yield block).to_s.green } + else + @logger.unknown(@logger.progname) { progname.to_s.green } + end + end + + private + + def derive_progname(klass) + class_name = klass.class.to_s + case class_name + when 'Class', 'Module', 'Symbol', 'String' + klass.to_s.split('::').last + else + class_name + end + end +end + +Jekyll::Hooks.register(:site, :after_reset, priority: :high) do |site| + instance = PluginMetaLogger.instance + logger = instance.new_logger(PluginMetaLogger, site.config) + logger.info { "Loaded #{JekyllPluginLoggerName::PLUGIN_NAME} v#{JekyllPluginLoggerVersion::VERSION} plugin." } + logger.debug { "Logger for #{instance.logger.progname} created at level #{instance.level_as_sym}" } +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger/version.rb b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger/version.rb new file mode 100644 index 00000000..5682af0c --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_logger/version.rb @@ -0,0 +1,3 @@ +module JekyllPluginLoggerVersion + VERSION = '2.1.2'.freeze +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_meta_logger.rb b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_meta_logger.rb new file mode 100644 index 00000000..a7b14714 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/lib/jekyll_plugin_meta_logger.rb @@ -0,0 +1,70 @@ +require 'colorator' +require 'logger' +require 'singleton' + +# Makes a meta-logger instance (a singleton) with level set by `site.config`. +# Saves `site.config` for later use when creating plugin loggers; these loggers each have their own log levels. +# +# For example, if the plugin's progname has value `MyPlugin` then an entry called `plugin_loggers.MyPlugin` +# will be read from `config`, if present. +# If no such entry is found then the meta-logger log_level is set to `:info`. +# If you want to see messages that indicate the loggers and log levels as they are created, +# set the log level for `PluginMetaLogger` to `debug` in `_config.yml` +# +# @example +# # Create and initialize the meta-logger singleton in a high priority Jekyll `site` `:after_init` hook: +# @meta_logger = PluginMetaLogger.instance.new_logger(site.config, self) +# @meta_logger.info { "Meta-logger has been created" } +# +# # In `config.yml`: +# plugin_loggers: +# PluginMetaLogger: info +# MyPlugin: warn +# MakeArchive: error +# ArchiveDisplayTag: debug +# +# # In a Jekyll plugin: +# @logger = PluginMetaLogger.instance.setup(self) +# @logger.info { "This is a log message from a Jekyll plugin" } +# # +# PluginMetaLogger.instance.info { "MyPlugin vX.Y.Z has been loaded" } +class PluginMetaLogger + include Singleton + attr_reader :config, :logger + + def initialize + super + @config = nil + @logger = new_logger(self) + end + + def info(&block) + @logger.info(self) { yield block } + end + + def debug(&block) + @logger.debug(self) { yield block } + end + + def level_as_sym + @logger.level_as_sym + end + + def warn(&block) + @logger.warn(self) { yield block } + end + + def error(&block) + @logger.error(self) { yield block } + end + + def new_logger(klass, config = nil, stream_name = $stdout) + @config ||= config + if @config.nil? + puts { 'Error: PluginMetaLogger has not been initialized with site.config.'.red } + PluginLogger.new(klass, {}, stream_name) + else + PluginLogger.new(klass, @config, stream_name) + end + end +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/spec/jekyll_plugin_logger_spec.rb b/bin/gems/jekyll_plugin_logger-2.1.2/spec/jekyll_plugin_logger_spec.rb new file mode 100644 index 00000000..f1120c6d --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/spec/jekyll_plugin_logger_spec.rb @@ -0,0 +1,85 @@ +require 'colorator' +require 'jekyll' +require_relative '../lib/jekyll_plugin_logger' + +# Output should be: + +# Info message 1 (cyan) +# MyPlugin Info message 2 (cyan) +# MyPlugin: Info message 3 (cyan) +# MyTestPlugin: Info message 4 (cyan) +# . +# MyPlugin: Warn message 1 (yellow) +# MyTestPlugin: Warn message 2 (yellow) +# MyPlugin: Error message 1 (red) +# MyTestPlugin: Error message 2 (red) + +class MyTestPlugin + instance = PluginMetaLogger.instance + logger = instance.new_logger(self) # Should generate a warning + PluginMetaLogger.instance.info { 'How now, brown cow' } + PluginMetaLogger.instance.debug { 'How now, brown cow' } + PluginMetaLogger.instance.warn { 'How now, brown cow' } + PluginMetaLogger.instance.error { 'How now, brown cow' } + + logger = PluginMetaLogger.instance.new_logger(self, RSpec.configuration.site_config) + logger.debug { '3 fleas fleeing freedom' } + logger.info { '3 fleas fleeing freedom' } + logger.warn { '3 fleas fleeing freedom' } + logger.error { '3 fleas fleeing freedom' } + + def self.exercise(logger) + puts + # puts '\ncalling_class_name=#{logger.send(:calling_class_name)}' + logger.debug('Debug message 1') + # logger.debug('MyPlugin', 'Debug message 2') + # logger.debug('MyPlugin') { 'Debug message 3' } + logger.debug { 'Debug message 4' } + + logger.info('Info message 1') + # logger.info('MyPlugin', 'Info message 2') + # logger.info('MyPlugin') { 'Info message 3' } + logger.info { 'Info message 4' } + + logger.warn('Warn message 1') + # logger.warn('MyPlugin', 'Warn message 2') + # logger.warn('MyPlugin') { 'Warn message 3' } + logger.warn { 'Warn message 4' } + + logger.error('Error message 1') + # logger.error('MyPlugin', 'Error message 2') + # logger.error('MyPlugin') { 'Error message 3' } + logger.error { 'Error message 4' } + end + + RSpec.describe PluginLogger do + it 'outputs at info level' do + MyTestPlugin.exercise(PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config, $stdout)) + expect(PluginMetaLogger.instance.level_as_sym).to eq(:info) + end + + it 'uses config debug' do + logger = PluginMetaLogger.instance.new_logger(:MyBlock, PluginMetaLogger.instance.config) + expect(logger.level_as_sym).to eq(:debug) + MyTestPlugin.exercise(logger) + end + + it 'uses config info' do + logger = PluginMetaLogger.instance.new_logger(:ArchiveDisplayTag, PluginMetaLogger.instance.config) + expect(logger.level_as_sym).to eq(:info) + MyTestPlugin.exercise(logger) + end + + it 'uses config warn' do + logger = PluginMetaLogger.instance.new_logger('SiteInspector', PluginMetaLogger.instance.config, $stdout) + expect(logger.level_as_sym).to eq(:warn) + MyTestPlugin.exercise(logger) + end + + it 'uses config error' do + logger = PluginMetaLogger.instance.new_logger(:PreTagBlock, PluginMetaLogger.instance.config) + expect(logger.level_as_sym).to eq(:error) + MyTestPlugin.exercise(logger) + end + end +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/spec/spec_helper.rb b/bin/gems/jekyll_plugin_logger-2.1.2/spec/spec_helper.rb new file mode 100644 index 00000000..3ec793d4 --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/spec/spec_helper.rb @@ -0,0 +1,27 @@ +require 'jekyll' +require_relative '../lib/jekyll_plugin_logger' + +Jekyll.logger.log_level = :info + +RSpec.configure do |config| + config.filter_run_when_matching focus: true + plugin_config = <<~END_CONFIG + plugin_loggers: + ArchiveDisplayTag: info + FlexibleInclude: info + MakeArchive: info + MyBlock: debug + PluginMetaLogger: info + PreTagBlock: error + SiteInspector: warn + UnselectableTag: info + END_CONFIG + + config.add_setting :site_config + config.site_config = YAML.safe_load(plugin_config) + + config.order = 'random' + + # See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures + config.example_status_persistence_file_path = 'spec/status_persistence.txt' +end diff --git a/bin/gems/jekyll_plugin_logger-2.1.2/spec/status_persistence.txt b/bin/gems/jekyll_plugin_logger-2.1.2/spec/status_persistence.txt new file mode 100644 index 00000000..1e29dc3e --- /dev/null +++ b/bin/gems/jekyll_plugin_logger-2.1.2/spec/status_persistence.txt @@ -0,0 +1,7 @@ +example_id | status | run_time | +---------------------------------------- | ------ | --------------- | +./spec/jekyll_plugin_logger_spec.rb[1:1] | passed | 0.00004 seconds | +./spec/jekyll_plugin_logger_spec.rb[1:2] | passed | 0.00005 seconds | +./spec/jekyll_plugin_logger_spec.rb[1:3] | passed | 0.00009 seconds | +./spec/jekyll_plugin_logger_spec.rb[1:4] | passed | 0.00005 seconds | +./spec/jekyll_plugin_logger_spec.rb[1:5] | passed | 0.00117 seconds | diff --git a/bin/gems/jekyll_plugin_support-3.0.0/.rubocop.yml b/bin/gems/jekyll_plugin_support-3.0.0/.rubocop.yml new file mode 100644 index 00000000..0e521fca --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/.rubocop.yml @@ -0,0 +1,99 @@ +plugins: + # - rubocop-jekyll + - rubocop-md + - rubocop-performance + - rubocop-rake + - rubocop-rspec + +AllCops: + Exclude: + - binstub/**/* + - demo/_site/* + - vendor/**/* + - Gemfile* + NewCops: enable + +Gemspec/DeprecatedAttributeAssignment: + Enabled: false + +Gemspec/RequireMFA: + Enabled: false + +Gemspec/RequiredRubyVersion: + Enabled: false + +Layout/HashAlignment: + EnforcedColonStyle: table + EnforcedHashRocketStyle: table + +Layout/IndentationConsistency: + Exclude: + - "*.md" + +Layout/InitialIndentation: + Exclude: + - "*.md" + +Layout/LineLength: + Max: 150 + +Metrics/AbcSize: + Max: 55 + +Metrics/BlockLength: + Exclude: + - jekyll_plugin_support.gemspec + Max: 30 + +Metrics/ClassLength: + Exclude: + - "**/all_collections_tag.rb" + +Metrics/CyclomaticComplexity: + Max: 25 + +Metrics/MethodLength: + Max: 50 + +Metrics/ModuleLength: + Exclude: + - "**/jekyll_plugin_support_class.rb" + +Metrics/PerceivedComplexity: + Max: 25 + +Naming/FileName: + Exclude: + - Rakefile + - "*.md" + +RSpec/ExampleLength: + Max: 30 + +RSpec/SpecFilePathFormat: + Enabled: false + IgnoreMethods: true + +RSpec/SpecFilePathSuffix: + Enabled: false + +RSpec/IndexedLet: + Enabled: false + +RSpec/MultipleExpectations: + Max: 15 + +Style/ClassVars: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/StringConcatenation: + Enabled: false + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma diff --git a/bin/gems/jekyll_plugin_support-3.0.0/ATTIBUTION_NOTES.md b/bin/gems/jekyll_plugin_support-3.0.0/ATTIBUTION_NOTES.md new file mode 100644 index 00000000..ab48ebfb --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/ATTIBUTION_NOTES.md @@ -0,0 +1,4 @@ +# Notes on Attribution + +The following additional public methods could be supported for the attribution string: +`full_name`, `conflicts`, `dependencies`, `platform`, `specification_version`, `summary`, `cert_chain`, `description`, `email`, `extensions`, `licenses`, `metadata`, `post_install_message`, `rg_full_gem_path`, `location`, `git_version`, `rg_extension_dir`, `nondevelopment_dependencies`, `default_executable`, `original_platform`, `gems_dir`, `groups`, `requirements`, `bin_file`, `executables`, `bindir`, `loaded_from`, `hash`, `files`, `spec_file`, `abbreviate`, `bin_dir`, `default_value`, `doc_dir`, `mark_version`, `executable`, `file_name`, `rubygems_version`, `lib_files`, `license`, `name_tuple`, `original_name`, `require_path`, `ri_dir`, `spec_dir`, `spec_name`, `source`, `validate_permissions`, `extension_dir`, `full_gem_path`, `remote`, `base_dir`, `gem_dir`, `normalize`, `match_platform`, `plugins`, `source_paths`, `datadir`, `require_paths`, and `this`. diff --git a/bin/gems/jekyll_plugin_support-3.0.0/CHANGELOG.md b/bin/gems/jekyll_plugin_support-3.0.0/CHANGELOG.md new file mode 100644 index 00000000..5a7fae1c --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/CHANGELOG.md @@ -0,0 +1,216 @@ +# Change Log + +## 3.0.0 / 2025-02-09 + +* Numbered as v3.0.0 because `jekyll_draft` was at v2.1.0 and the two projects should have similar version numbers. +* `Jekyll_all_collections` was folded into this project. +* Now requires [Jekyll 4.4.1](https://jekyllrb.com/news/2025/01/29/jekyll-4-4-1-released/) or later, + and Ruby 3.2.0 or later + + +## 1.1.0 / 2025-02-07 + +* Now replaces include and layout variables with their values +* Renamed `@helper.markup` to `@helper.argument_string` +* Improved `nil` handling throughout +* Added the **Debug Demo production** launch configuration to debug the demo website in production mode +* Added the `bin/release_port` script that kills hung processes being debugged +* Added the `cleanDemo` task for the **Debug Demo production** and **Debug Demo development** tasks +* Many minor improvements to the demo. +* `JekyllSupport::JekyllPluginHelper::register` now accepts a `quiet` option, to suppress the signon message. + Use it like this: + + ```ruby + JekyllPluginHelper.register(self, 'tag_name', quiet: true) + ``` + + +## 1.0.3 / 2024-08-19 + +* Still fussing with error handling + + +## 1.0.2 / 2024-08-19 + +* Computes line_number and path properly +* Refactored demo CSS +* Improved custom plugin error handling and sample code. + The following seems to be optimal for custom plugins; it suppresses the ridiculously long stack trace that used to be generated: + + ```ruby + begin + # ... + rescue DemoInlineTagError => e # jekyll_plugin_support handles StandardError + @logger.error { e.logger_message } + exit! 1 if @die_on_demo_tag_error + + e.html_message + end + ``` + + +## 1.0.1 / 2024-07-27 + +* Moved `warn_short_trace`, `maybe_reraise_error`, `remove_ansi_color`, +`format_error_message` and `exit_without_stack_trace` into `JekyllSupportError`. +* Added missing `shared_include.css` and `clippy.svg` to `demo/`. +* Fixed missing module name when invoking `format_error_message`. + + +## 1.0.0 / 2024-07-23 + +* Added the `redef_without_warning` method so tag and block plugins can be subclassed. +* Put most of the functionality into the `JekyllSupport` module. +* Made tag and block code more consistent + + +## 0.8.6 / 2024-06-11 + +* Fixup version, containing what was supposed to be in v0.8.5 + + +## 0.8.5 / 2024-03-25 + +* Empty block tags now return a value. See https://talk.jekyllrb.com/t/empty-liquid-block-not-rendering + + +## 0.8.4 / 2024-02-27 + +* Problem in error handler fixed. +* A warning is logged if an environment variable is undefined and `die_if_undefined` is not set. + + +## 0.8.3 / 2024-01-05 + +* Variables defined in front matter of layouts and pages are now handled. + + +## 0.8.2 / 2024-01-03 + +* `JekyllSupport::JekyllBlock` and `JekyllSupport::JekyllTag` subclasses now have automatically created error classes, + named after the subclass. +* Error class methods have been provided for standardized and convenient error handling: + * `shorten_backtrace` + * `logger_message` + * `html_message` +* Tags now self-report when registered. + + +## 0.8.1 / 2023-12-10 + +* Added the `JekyllPluginHelper.remove_html_tags` method. + + +## 0.8.0 / 2023-11-14 + +* Restructured for better support of Liquid variables. +* Removed redundant class name in error message. +* Improved handling of StandardError. +* Demo site now shows how to define and handle custom errors. +* Added `@tag_config` variable, which can be inspected to determine whether to die on various types of exceptions. +* Added `format_error_message`, `maybe_reraise_error`, and `raise_error` to `JekyllBlock` and `JekyllTag` +* Adds a method called `shorten_backtrace` to `StandardError` and all custom error + classes defined by `JekyllSupport.define_error`. + See the `demo/` directory for examples of how to use this optional feature. +* The `plugin-vars` section in `_config.yml` was renamed to `liquid_vars`. + + +## 0.7.2 / 2023-08-14 + +* Hopefully takes care of issue [#4](../../issues/4). + + +## 0.7.1 / 2023-08-11 + +* Suppressed stack trace from issue [#4](../../issues/4). +* Now using Shopify `ruby-lsp` instead of `rebornix.Ruby` by Peng Lv +* Debug configurations changed to `rdbg` instead of `ruby`, so the `debase` development dependency was changed to + [`debug`](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg), + which provides the `rdgb` command. + The `ruby-debug-ide` development dependency is also no longer required. + + +## 0.7.0 / 2023-05-22 + +* Added `error_short_trace` and `warn_short_trace` methods for displaying non-fatal errors on the console. + +## 0.6.2 / 2023-05-15 + +* Removed annoying blank line output when attribute was invoked. + +## 0.6.1 / 2023-04-12 + +* Added `CallChain.excerpt_caller` to detect if an excerpt is being generated. + + +## 0.6.0 / 2023-04-05 + +* Added attribution support +* Renamed `jekyll_plugin_support_helper.rb` to `jekyll_plugin_helper.rb`. +* Now returns `undefined` instead of `false'` when `@keys_values.empty?` + and parameter is not specified. + + +## 0.5.3 / 2023-03-19 + +* Added properties `argv_original`, `keys_values_original`, `remaining_markup_original`, + and `params_original`, which are the original values of `argv`, `keys_values`, + `remaining_markup`, and `params`, before environment variable expansion. + + +## 0.5.2 / 2023-03-17 + +* Added `@helper.remaining_markup` public method, which returns remaining markup passed to your tag, + after keyword and name/value parsing is complete. + * Finally wrote proper `rspec` tests. + * Finally documented argument parsing. + * Fixed bug introduced in v0.5.1 which did not remove elements from `@params`. + + +## 0.5.1 / 2023-02-17 + +* `no_arg_parsing` optimization added. + + +## 0.5.0 / 2023-02-15 + +* Plugins now register themselves +* Plugins now report their name and version +* `@layout`, `@paginator`, and `@theme` have values if supported by the version of Jekyll, and they are active. + (See [Jekyll docs](https://jekyllrb.com/docs/variables/).) + + +## 0.4.1 / 2023-02-14 + +* Fixed several problems +* Added demo site + + +## 0.4.0 / 2023-02-12 + +* `render_impl` for tags and blocks now predefines more instance variables: + + * `@liquid_context` – passed to `render` + * `@config` Jekyll configuration + * `@envs` Environment variables + * `@mode` ('development', 'test' or 'production') + + +## 0.3.1 / 2023-02-07 + +* `JekyllBlock.render_impl` and `JekyllTag.render_impl` now define `@page` and `@site`. + + +## 0.3.0 / 2023-01-14 + +* Added support for tags, which should subclass JekyllSupport::JekyllTag + + +## 0.2.0 / 2023-01-12 + +* Refactored + + +## 0.1.0 / 2023-01-10 + +* Initial version; only supports Jekyll block tags diff --git a/bin/gems/jekyll_plugin_support-3.0.0/LICENSE.txt b/bin/gems/jekyll_plugin_support-3.0.0/LICENSE.txt new file mode 100644 index 00000000..805ae6c4 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Mike Slinn + +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/bin/gems/jekyll_plugin_support-3.0.0/README.md b/bin/gems/jekyll_plugin_support-3.0.0/README.md new file mode 100644 index 00000000..6cc4f0a7 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/README.md @@ -0,0 +1,1489 @@ +# `jekyll_plugin_support` [![Gem Version](https://badge.fury.io/rb/jekyll_plugin_support.svg)](https://badge.fury.io/rb/jekyll_plugin_support) + +After writing over two dozen Jekyll plugins, I distilled the common code into `Jekyll_plugin_support`. +This F/OSS Ruby gem facilitates writing and testing Jekyll plugins and handles the standard housekeeping that every Jekyll +inline and block tag plugin requires. +Logging, parsing arguments, obtaining references to site and page objects, etc. are all handled. +The result is faster Jekyll plugin writing with fewer bugs. + +`Jekyll_plugin_support` can be used to create simple Jekyll plugins in +the `_plugins/` directory of your Jekyll project, or gem-based Jekyll plugins. + +At present, only Jekyll tags and blocks are supported. + +Public plugins that use `jekyll_plugin_support` include: + + + +... and also the demonstration plugins in +[`jekyll_plugin_support`](https://github.com/mslinn/jekyll_plugin_support/tree/master/demo/_plugins) + + +## Features + +Jekyll plugin tags created from `jekyll_plugin_support` framework automatically have the following features: + +1. Boilerplate is removed, so you can focus on the required logic and output. +2. Arguments are parsed for keywords and name/value parameters. +3. Single or double quotes can be used for arguments and parameters. +4. Important variables are predefined. +5. Error handling is standardized, and includes an automatically defined error type + and corresponding CSS tag for each Jekyll tag. +6. Jekyll and Liquid variables, including `layout`, `page` and `include` variables, + can be passed as parameters to tags, and used in the body of block tags. +7. Plugin registration is integrated, and important configuration details are reported during registration. +8. A custom logger is created for each tag, independent of the default Jekyll logger. +9. Variables can be defined in `_config.yml`, and optionally have different values for debug mode, + production mode and test mode. +10. An attribution message is available. +11. Draft pages are automatically detected. +12. A demonstration website is provided for easy testing of every plugin. +13. Visual Studio Code debugging is set up for the plugin code and the demo website. +14. Plugins can be subclassed. +15. [`Nugem`](https://mslinn.com/ruby/6800-nugem.html) can create working scaffolding for new plugins built + using `jekyll_plugin_support`. +16. Four new attributes are added to + [`site`](https://jekyllrb.com/docs/variables/#site-variables): + + a. `all_collections` includes all documents in all collections. + + b. `all_documents` includes `all_collections` plus all standalone pages. + + c. `everything` includes `all_documents` plus all static files. + + d. `sorted_lru_files` is used by a new binary search lookup for matching page suffixes. + The `jekyll_href` and `jekyll_draft` plugins use this feature. + +## Installation + +### For A Jekyll Website + +`Jekyll_plugin_support` is packaged as a Ruby gem. +If you want to write a custom Jekyll plugin that will reside in a Jekyll project’s `_plugins` directory, +add the following line to your Jekyll plugin’s `Gemfile`. + +```ruby +group :jekyll_plugins do + # ... + gem 'jekyll_plugin_support', '>= 1.1.0' + # ... +end +``` + +Run the standard `jekyll_plugin_support` setup procedure: + +```shell +$ bin/setup +``` + + +### As a Gem Dependency + +If your custom plugin will be packaged into a gem, add the following to your plugin’s `.gemspec`: + +```ruby +Gem::Specification.new do |spec| + # ... + spec.add_dependency 'jekyll_plugin_support', '>= 1.1.0' + # ... +end +``` + +Install the `jekyll_plugin_support` gem into your plugin project in the usual manner: + +```shell +$ bundle +``` + +Copy the CSS classes from +[`demo/assets/css/jekyll_plugin_support.css`](demo/assets/css/jekyll_plugin_support.css) +to your Jekyll project’s CSS file. + + + + +## About `jekyll_plugin_support` + +This Jekyll plugin includes a generator, +triggered by a high-priority hook, and a block tag called `all_collections`. + +`JekyllSupport::JekyllBlock` and `JekyllSupport::JekyllTag` +provide support for [Jekyll tag block plugins](https://jekyllrb.com/docs/plugins/tags/#tag-blocks) +and [Jekyll inline tag plugins](https://jekyllrb.com/docs/plugins/tags/), respectively. +They are very similar in construction and usage. + +Instead of subclassing your custom Jekyll block tag class from `Liquid::Block`, +subclass from `JekyllSupport::JekyllBlock`. +Similarly, instead of subclassing your custom Jekyll tag class from `Liquid::Tag`, +subclass from `JekyllSupport::JekyllTag`. + +Both JekyllSupport classes instantiate new instances of +[`PluginMetaLogger`](https://github.com/mslinn/jekyll_plugin_logger) (called `@logger`) and +[`JekyllPluginHelper`](https://github.com/mslinn/jekyll_plugin_support/blob/master/lib/jekyll_plugin_support_helper.rb) +(called `@helper`). + +`JekyllPluginHelper` defines a generic initialize method, and your tag or block tag class should not need to override it. +Also, your tag or block tag class should not define a method called render, because `jekyll_plugin_support` defines one. + +Instead, define a method called `render_impl`. +For inline tags, `render_impl` does not accept any parameters. +For block tags, a single parameter is required, which contains text passed from your block in the page. + +Your implementation of render_impl can parse parameters passed to your tag, as described in +[Tag Parameter Parsing](http://mslinn.com/jekyll/10100-jekyll-plugin-background.html#params). + +In addition, within render_impl, +the arguments passed to the tag will have been tokenized and parsed, +with Jekyll and Liquid variables substituted for their values, +and all the public Jekyll variables will be available as instance variables. +Error handling will also have been set up, +and access to your tag's entry within _config.yml will have been set up. + + + +## General Usage + +Please see the [`demo/`](demo/) project for a well-documented set of demonstration Jekyll plugins built from `jekyll_plugin_support`. +Additional information is available [here](https://mslinn.com/jekyll/10200-jekyll-plugin-background.html) and the +[`jekyll_plugin_support`](https://www.mslinn.com/jekyll_plugins/jekyll_plugin_support.html) documentation. + +[`JekyllSupport::JekyllBlock`](https://github.com/mslinn/jekyll_plugin_support/blob/master/lib/jekyll_plugin_support_block.rb) and +[`JekyllSupport::JekyllTag`](https://github.com/mslinn/jekyll_plugin_support/blob/master/lib/jekyll_plugin_support_tag.rb) provide +support for Jekyll block tags and Jekyll inline tags, respectively. +They are similar in construction and usage. + +Instead of subclassing your Jekyll block tag class from `Liquid::Block`, +subclass from `JekyllSupport::JekyllBlock` instead. + +Likewise, instead of subclassing your Jekyll inline tag class from `Liquid::Tag`, +subclass from `JekyllSupport::JekyllTag` instead. + +Both `JekyllSupport` classes instantiate new instances of +[`PluginMetaLogger`](https://github.com/mslinn/jekyll_plugin_logger) (called `@logger`) and +[`JekyllPluginHelper`](lib/jekyll_plugin_helper.rb) (called `@helper`). + + +### Inline and Block Tag Plugin Implementation + +Both `JekyllSupport` classes define a generic `initialize` method, +and your inline tag or block tag class should not override it. + +Also, your inline tag or block tag class should not define a method called `render`, +because both `JekyllSupport` classes define this method. + + +Instead, define a method called `render_impl`. +For inline tags, `render_impl` does not accept any parameters. +For block tags, a single parameter is required, which receives any text enclosed within your block by the website author. + + +### New `Site` Attributes + +No explicit initialization or setup is required. +Jekyll plugins can access the value of +`site.all_collections`, `site.all_documents` and `site.everything`; +however, Liquid code in Jekyll pages and documents cannot. + + +### Excluding Files + +There are two ways to exclude files from the new `site` attributes. + +1) The [`exclude` entry in `_config.yml`](https://jekyllrb.com/docs/configuration/options#global-configuration) + can be used as it normally would. + +2) Adding the following entry to a page’s front matter causes that page to be excluded + from the collection created by this plugin: + + ```html + --- + exclude_from_all: true + --- + ``` + +### `all_collections` Plugin Usage + +Jekyll generators and tags receive an enhanced version of the `site` Jekyll variable. + + +#### From a Custom Plugin + +In the following example of how to use the `all_collections` plugin in a custom plugin, +the `do_something_with` function processes all `Jekyll::Page`s, `Jekyll:Document`s, and static files. + +```ruby +@site.everything.each do |apage| + do_something_with apage +end +``` + + +#### Using the Block Tag + +The general form of the Jekyll tag, including all options, is: + +```html +{% all_collections + date_column='date|last_modified' + heading='All Posts' + id='asdf' + sort_by='SORT_KEYS' +%} +``` + + +##### `date_column` Attribute + +One of two date columns can be displayed in the generated HTML: +either `date` (when the article was originally written), +or `last_modified`. +The default value for the `date_column` attribute is `date`. + + +##### `heading` Attribute + +If no `heading` attribute is specified, a heading will automatically be generated, which contains the `sort_by` values, +for example: + +```html +{% all_collections id='abcdef' sort_by="last_modified" %} +``` + +The above generates a heading like: + +```html +

All Posts Sorted By last_modified

+``` + +To suppress both a `h2` heading (and the enclosed `id`) from being generated, +specify an empty string for the value of `heading`: + +```html +{% all_collections heading='' %} +``` + + +##### `id` Attribute + +If your Jekyll layout employs [`jekyll-toc`](https://github.com/allejo/jekyll-toc), then `id` attributes are important. +The `jekyll-toc` include checks for `id` attributes in `h2` ... `h6` tags, and if found, +and if the attribute value is enclosed in double quotes +(`id="my_id"`, not single quotes like `id='my_id'`), +then the heading is included in the table of contents. + +To suppress an `id` from being generated, +and thereby preventing the heading from appearing in the automatically generated table of contents from `jekyll-toc`, +specify an empty string for the value of `id`, like this: + +```html +{% all_collections id='' %} +``` + + +##### `SORT_KEYS` Values + +`SORT_KEYS` specifies how to sort the collection. +Values can include one or more of the following attributes: +`date`, `destination`, `draft`, `label`, `last_modified`, `last_modified_at`, `path`, `relative_path`, +`title`, `type`, and `url`. +Ascending sorts are the default; however, a descending sort can be achieved by prepending `-` before an attribute. + +To specify more than one sort key, provide a comma-delimited string of values. +Included spaces are ignored. +For example, specify the primary sort key as `draft`, +the secondary sort key as `last_modified`, +and the tertiary key as `label`: + +```html +{% all_collections + date_column='last_modified' + heading='All Posts' + id='asdf' + sort_by='draft, last_modified, label' +%} +``` + + +#### Liquid Usage Examples + +Here is a short Jekyll page, including front matter, +demonstrating this plugin being invoked with all default attribute values: + +```html +--- +description: " + Dump of all collections, sorted by date originally written, newest to oldest. + The heading text will be All Posts Sorted By -date +" +layout: default +title: Testing, 1, 2, 3 +--- +{% all_collections %} +``` + +Following are examples of how to specify the sort parameters. + +**Explicitly express the default sort**
+(sort by the date originally written, newest to oldest): + +```html +{% all_collections sort_by="-date" %} +``` + +Sort by date, from oldest to newest: + +```html +{% all_collections sort_by="date" %} +``` + +**Sort by the date last modified, oldest to newest:** + +```html +{% all_collections sort_by="last_modified" %} +``` + +**Sort by the date last modified, newest to oldest:** + +```html +{% all_collections sort_by="-last_modified" %} +``` + +**Several attributes can be specified as sort criteria**
+by passing them as a comma-delimited string. +Included spaces are ignored: + +```html +{% all_collections sort_by="-last_modified, -date" %} +{% all_collections sort_by="-last_modified, title" %} +{% all_collections sort_by="-last_modified, -date, title" %} +``` + +**The following two examples produce the same output:** + +```html +{% all_collections sort_by="-last_modified,-date" %} +{% all_collections sort_by="-last_modified, -date" %} +``` + + +## Predefined Plugin Variables + +`Jekyll_plugin_support` defines the following Ruby variables that you can use in your plugin’s `render_impl` method: + +* `@argument_string` Unparsed markup passed as a parameter to your block tag and inline tag. + +* `@argv` returns any remaining tokens after `parameter_specified?` has been invoked. + +* [`@attribution`](#subclass-attribution) Attribution markup + +* [`@config`](https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll#configuring-jekyll-in-your-github-pages-site) + The [YAML](https://yaml.org/) Jekyll site configuration file + +* [`@helper`](https://github.com/mslinn/jekyll_plugin_support/blob/master/lib/jekyll_plugin_helper.rb) + `JekyllPluginHelper` instance for your plugin. + +* [`@layout`](https://jekyllrb.com/docs/variables/#global-variables) Layout information + +* `@logger` [`jekyll_plugin_logger`](https://github.com/mslinn/jekyll_plugin_logger) instance for your Jekyll plugin. + +* [`@mode`](https://jekyllrb.com/docs/configuration/environments/) + Indicates `production`, `test` or `development` mode. + +* [`@page`](https://jekyllrb.com/docs/variables/#page-variables) `Jekyll::Page` variables + +* [`@paginator`](https://jekyllrb.com/docs/variables/#page-variables) Pagination variables + +* [`@scopes`](https://jekyllrb.com/docs/variables/) + See the [`jekyll_plugin_support` demo project](demo/variables.html) + +* [`@site`](https://jekyllrb.com/docs/variables/#site-variables) Site variables + +* [`@tag_config`](lib/jekyll_plugin_support_tag.rb) + Contents of the section of `_config.yml` named after your plugin. + +* `@tag_name` Name of your Jekyll block tag or inline tag plugin. + +* [`@theme`](https://jekyllrb.com/docs/variables/#global-variables) Theme variables + +* `text` Content provided to your block tag. + + +## Argument Parsing + +Tag arguments can be obtained within `render_impl`. +Both keyword options and name/value parameters are supported. + +Both `JekyllTag` and `JekyllBlock` use the standard Ruby mechanism for parsing command-line options: +[`shellwords`](https://ruby-doc.org/stdlib-2.5.1/libdoc/shellwords/rdoc/Shellwords.html) and +[`key_value_parser`](https://www.rubydoc.info/gems/key-value-parser). + +All your code has to do is to specify the keywords to search for in the string +passed from the HTML page that your tag is embedded in. +The included `demo` website has examples; +both [`demo/_plugins/demo_inline_tag.rb`](demo/_plugins/demo_inline_tag.rb) and +[`demo/_plugins/demo_block_tag.rb`](demo/_plugins/demo_block_tag.rb) contain the following: + +```ruby +@keyword1 = @helper.parameter_specified? 'keyword1' +@keyword2 = @helper.parameter_specified? 'keyword2' +@name1 = @helper.parameter_specified? 'name1' +@name2 = @helper.parameter_specified? 'name2' +``` + +If an argument has a variable reference in it, the value of the variable is substituted for the reference. +For example, given: + +* `_layouts/default.html` defines a variable called `var_layout` in its front matter. +* `index.html` defines a variable called `var_page` in its front matter. +* `index.html` assigns a variable called `x` via the liquid `assign` statement. + +... then the following references in a page will be substituted for their values in arguments and in block tag bodies: + +```html +{% my_block_tag + param1="x={{x}}" + param2="var_page={{page.var_page}}" + param3="var_layout={{layout.var_layout}}" +%} + +Assigned variables do not need a namespace: x={{x}} + +Page variables must be qualified with the 'page' namespace: + var_page={{page.var_page}} + +Layout variables must be qualified with the 'layout' namespace: + var_layout={{layout.var_layout}} +{% endmy_block_tag %} +``` + +You can see similar code in [`demo/demo_inline_tag.html`](demo/demo_inline_tag.html). + +The `page['excerpt']` and `page['output']` key/value pairs are removed from processing because of recursion issues. +You cannot look up those values from a `jekyll_plugin_support` plugin. + + +### Keyword Options + +For all keyword options, values specified in the document _may_ be provided. +If a value is not provided, the value `true` is assumed. +Otherwise, if a value is provided, it _must_ be wrapped in single or double quotes. + + +### Examples + +The following examples use the `die_if_error` keyword option for the +[`pre`](https://www.mslinn.com/jekyll_plugins/jekyll_pre.html#tag) and +[`exec`](https://www.mslinn.com/jekyll_plugins/jekyll_pre.html#tag_exec) +tags from the [`jekyll_pre`](https://www.mslinn.com/jekyll_plugins/jekyll_pre.html) plugin %}. + + +#### Specifying Tag Option Values + +The following sets `die_if_error` `true`: + +```html +{% pre die_if_error %} ... {% endpre %} +``` + +The above is the same as writing: + +```html +{% pre die_if_error='true' %} ... {% endpre %} +``` + +Or writing: + +```html +{% pre die_if_error="true" %} ... {% endpre %} +``` + +Neglecting to provide surrounding quotes around the provided value causes the parser to not recognize the option. +Instead, what you had intended to be the keyword/value pair will be parsed as part of the command. +For the `pre` tag, this means the erroneous string becomes part of the `label` value, +unless `label` is explicitly specified. +For the `exec` tag, this means the erroneous string becomes part of the command to execute. +The following demonstrates the error. + +```html +{% pre die_if_error=false %} ... {% endpre %} +``` + +The above causes the label to be `die_if_error=false`. + +```html +{% exec die_if_error=false ls %} ... {% endpre %} +``` + +The above causes the command to be executed to be `die_if_error=false ls` instead of `ls`. + + +### Quoting + +Parameter values can be quoted. + +If the value consists of only one token then quoting is optional. +The following name/value parameters all have the same result: + +* `pay_tuesday="true"` +* `pay_tuesday='true'` +* `pay_tuesday=true` +* `pay_tuesday` + +If the values consist of more than one token, quotes must be used. +The following examples both yield the same result: + +* `pay_tuesday="maybe not"` +* `pay_tuesday='maybe not'` + + +### Remaining Markup + +After your plugin has parsed all the keyword options and name/value parameters, +call `@helper.remaining_markup` to obtain the remaining markup that was passed to your plugin. + + +## Configuration Variables + +`jekyll_plugin_support` provides support for +[Liquid variables](https://shopify.github.io/liquid/tags/variable/) +to be defined in `_config.yml`, in a section called `liquid_vars`. +These variables behave exactly like Liquid variables defined by `assign` and `capture` expressions, +except they are global in scope; these variables are available in every Jekyll web page. + +The following `_config.yml` fragment defines 3 variables called `var1`, `var2` and `var3`: + +```yaml +liquid-vars: + var1: value1 + var2: 'value 2' + var3: value3 +``` + +Liquid variables defined in this manner are intended to be embedded in a webpage. +They are can be used like any other Liquid variable. + + +## Variable Expansion + +Jekyll expands Liquid variable references during the page rendering process. +Jekyll does not expand Liquid variable references passes as parameters to tag and block plugins, however. +However, plugins made from `jekyll_plugin_support` automatically +expand all types of variable references passed as parameters and in block tag bodies. + +`Jekyll_plugin_support` tag and block plugins expand the following types of variables: + +* Jekyll_plugin_support configuration variables, discussed above. +* Jekyll [page](https://jekyllrb.com/docs/variables/#page-variables) and + [layout](https://jekyllrb.com/docs/layouts/#variables) variables. +* Inline Liquid variables (defined in [assign](https://shopify.dev/docs/api/liquid/tags/assign) and [capture](https://shopify.dev/docs/api/liquid/tags/capture) statements). + +In the following example web page, Jekyll expands the `var1` reference within the `

` tag, +but not the `var1` or `var2` references passed to `my_plugin`. + +```html +

This is the value of var1: {{var1}}.

+ +{% my_plugin param1="{{var1}}" param2="{{var2}}" %} +``` + +Assuming that `my_plugin` was written as a `jekyll_plugin_support` plugin, +all variable references in its parameters are expanded. +Thus, the above is interpreted as follows when `my_plugin` is evaluated during the Jekyll rendering process: +

+ +```html +

This is the value of var1: value1.

+ +{% my_plugin param1="value1" param2="value 2" %} +``` + + +`Jekyll_plugin_support` expands most of the [plugin variables described above](#predefined-variables), +replacing Liquid variable references with their values. +The exception is `@argument_string`, which is not expanded. + + +### Liquid Variable Values Specific To Production And Development Modes + +`jekyll_plugin_support` allows Liquid variables defined in `_config.yml` to have different values +when Jekyll is running in `development`, `production` and `test` modes. +When injecting variables into your Jekyll website, `Jekyll_plugin_support` +refers to definitions specific to the current environment, +and then refers to other definitions that are not overridden. + +Here is an example: + +```yaml +liquid-vars: + development: + var1: 'http://localhost:4444/demo_block_tag.html' + var2: 'http://localhost:4444/demo_inline_tag.html' + production: + var1: 'https://github.com/django/django/blob/3.1.7' + var2: 'https://github.com/django-oscar/django-oscar/blob/3.0.2' + var3: 'https://github.com/mslinn' +``` + +For the above, the following variable values are set in `development` mode: + +* `var1`: `http://localhost:4444/demo_block_tag.html` +* `var2`: `http://localhost:4444/demo_inline_tag.html` +* `var3`: `https://github.com/mslinn` + +... and the following variable values are set in `production` and `test` modes: + +* `var1`: `https://github.com/django/django/blob/3.1.7` +* `var2`: `https://github.com/django-oscar/django-oscar/blob/3.0.2` +* `var3`: `https://github.com/mslinn` + + +### Liquid Variables in `jekyll_plugin_support` Subclasses + +You can define additional Liquid variables in plugins built using `jekyll_plugin_support`. +To do this, make entries in `_config.yml` under a key named after the value of `@tag_name`. + +For example, let’s imagine you create a plugin using `jekyll_plugin_support`, +and hou register it with the name `phonetic_alphabet`. +You could define Liquid variables that would be made available to content pages in web applications that +incorporate the `phonetic_alphabet` plugin. +The following section in `_config.yml` defines variables called `x`, `y` and `z`, +with values `xray`, `yankee` and `zulu`, respectively: + +```yaml +phonetic_alphabet: + x: xray + y: yankee + z: zulu +``` + +The above definitions allow you to write content pages that use those variables, like the following page containing markup: + +```html +--- +layout: default +title: Variable demo +--- +The letter `x` is pronounced {{x}}. +Similarly, the letters `y` and `z` are pronounced {{y}} and {{z}}. +``` + + +### Evaluating Include Variables + +This information is only useful if a plugin might be executed from within an included file. + +While Liquid handles regular variables, Jekyll has special handling for variables defined by include parameters. +For example, the following defines a variable in the `include` scope called `var1` +when processing the body of an included file: + +```html +{% include myfile.html var1='value1' %} +``` + +You can obtain the value of this variable from the `render_impl` method of a +`JekyllSupport::JekyllTag` or `JekyllSupport::JekyllBlock` subclass as follows: + +```ruby + @var1 = @scopes.first['include']&.[]('var1') +``` + + +## Automatically Created Error Classes + +`JekyllSupport::JekyllBlock` and `JekyllSupport::JekyllTag` subclasses +automatically create error classes, named after the subclass. + +For example, if you create a `JekyllSupport::JekyllBlock` subclass called `DemoBlockTag`, +the automatically generated error class will be called `DemoBlockTagError`. + +Although you could use it as you would any other error class, `JekyllPluginSupport` +provides additional helper methods. +These methods fill in the page path and line number that caused the error, shorten the stack trace, +log an error message, and can be used to return an HTML-friendly version of the message to the web page. + +The following example is a shortened version of `demo/_plugins/demo_block_tag.rb`. +You might want to write similar code in your `rescue` blocks. + +```ruby +class DemoBlock < JekyllSupport::JekyllBlock + VERSION = '0.1.2'.freeze + + def render_impl(text) + raise DemoBlockTagError, 'Fall down, go boom.' + rescue DemoBlockTagError => e + @logger.error e.logger_message + exit! 1 if @die_on_demo_block_error + + e.html_message + end +end +``` + +Error class methods have been provided for standardized and convenient error handling: + +* `shorten_backtrace` - most of the lines that spew from a Jekyll backtrace are uninteresting. +* `logger_message` - The message is constructed from the string provided when the error was raised, + with the page path and line number added. +* `html_message` - The same as `logger_message`, but constructed with HTML. + + +## Self-Reporting Upon Registration + +When each tag is registered, it self-reports, for example: + +```text +INFO PluginMetaLogger: Loaded plugin demo_inline_tag v0.1.2. It has: + Error class: DemoTagError + CSS class for error messages: demo_tag_error + + _config.yml contains the following configuration for this plugin: + {"die_on_demo_tag_error"=>false, "die_on_standard_error"=>false} + + +INFO PluginMetaLogger: Loaded plugin demo_inline_tag_no_arg v0.1.0. It has: + Error class: DemoTagNoArgsError + CSS class for error messages: demo_tag_no_args_error + + _config.yml does not contain configuration information for this plugin. + You could add a section containing default values by specifying a section for the tag name, + and an entry whose name starts with `die_on_`, followed by a snake_case version of the error name. + + demo_inline_tag_no_arg: + die_on_demo_tag_no_args_error: false +``` + + +## `no_arg_parsing` Optimization + +If your tag or block plugin only needs access to the raw arguments passed from the web page, +without tokenization, and you expect that the plugin might be invoked with large amounts of text, +derive your plugin from `JekyllBlockNoArgParsing` or `JekyllTagNoArgParsing`. + +## Writing Plugins + +The following minimal examples define `VERSION`, +which is important because `JekyllPluginHelper.register` logs that value when registering the plugin. + +This is how you would define plugins in the `_plugins` directory + +**Boilerplate for an inline tag plugin** + +```ruby +require 'jekyll_plugin_support' + +module Jekyll + class DemoTag < JekyllSupport::JekyllTag + VERSION = '0.1.0'.freeze + + def render_impl + @helper.gem_file __FILE__ # Enables attribution; only works when plugin is a gem + # Your Jekyll plugin logic goes here + end + + JekyllPluginHelper.register(self, 'demo_tag') + end +end +``` + +**Boilerplate for a tag block plugin** + +```ruby +require 'jekyll_plugin_support' + +module Jekyll + class DemoBlock < JekyllSupport::JekyllBlock + VERSION = '0.1.0'.freeze + + def render_impl(text) + @helper.gem_file __FILE__ # Enables attribution; only works when plugin is a gem + # Your Jekyll plugin logic goes here + end + + JekyllPluginHelper.register(self, 'demo_block') + end +end +``` + +If your plugin is packaged as a gem, then you might need to include `version.rb` into the plugin class. +For example, if your version module looks like this: + +**lib/my_plugin/version.rb**: + +```ruby +module MyPluginVersion + VERSION = '0.5.0'.freeze +end +``` + +Then your plugin can incorporate the VERSION constant into your plugin like this: + +**lib/my_plugin.rb**: + +```ruby +require 'jekyll_plugin_support' +require_relative 'my_plugin/version' + +module Jekyll + class MyBlock < JekyllSupport::JekyllBlock + include MyPluginVersion + + def render_impl(text) + @helper.gem_file __FILE__ # Enables attribution; only works when plugin is a gem + # Your code here + end + + JekyllPluginHelper.register(self, 'demo_block') + end +end +``` + +## Attribution + +`JekyllTag` and `JekyllBlock` subclasses of `jekyll_plugin_support` can utilize the `attribution` +option if they are published as a gem. +`JekyllTagNoArgParsing` and `JekyllBlockNoArgParsing` subclasses cannot. +This feature is usually only desired for `JekyllBlock` subclasses. + +* When used as a keyword option, a default value is used for the attribution string. +* When used as a name/value option, the attribution string can be specified. + +Using the `attribution` option cause subclasses to replace their usual output with HTML that looks like: + +```html + +``` + +The `id` attribute is in the sample HTML above is randomized so more than one attribution can appear on a page. + + +### Attribution Generation + +You can decide where you want the attribution string for your Jekyll tag to appear by invoking `@helper.attribute`. +For example, this is how the +[`jekyll_outline` tag](https://github.com/mslinn/jekyll_outline/blob/v1.1.1/lib/outline_tag.rb#L32-L46) generates output: + +```html +<<~HEREDOC +
+ #{make_entries(collection)&.join("\n")} +
+ #{@helper.attribute if @helper.attribution} +HEREDOC +``` + + +### Usage + +Typical usage for the `attribution` tag is: + +```html +{% my_block_tag attribution %} + Content of my_block_tag. +{% endmy_block_tag %} +``` + +The normal processing of `my_block_tag` is augmented by interpolating the attribution format string, +which is a Ruby-compatible interpolated string. + +The default attribution format string is: + +```ruby +"Generated by the #{name} #{version} Jekyll plugin, written by #{author} #{date}." +``` + +Because `jekyll_plugin_suppprt` subclasses are `gem`s, their `gemfile`s define values for +`name`, `version`, `homepage`, and `authors`, as well as many other properties. +The `date` property is obtained from the plugin/gem publishing date. + +An alternative attribution string can be specified properties can be output using any of the above properties: + +```html +{% my_tag attribution="Generated by the #{name} #{version} Jekyll plugin, written by #{author} #{date}" %} +``` + +## Subclassing Plugins + +Jekyll plugins created using `jekyll_plugin_support` are implemented as Ruby classes. +If you would like to create a version of an existing Jekyll plugin, you will need to subclass the plugin. +In order to do that, you will need to override the plugin name and version, which are defined as constants. + +`Jekyll_plugin_support` provides a method that allows +a constant to be redefined, called `redef_without_warning`. +Use it in a subclass like this: + +```ruby +redef_without_warning :PLUGIN_NAME, 'my_plugin'.freeze +redef_without_warning :VERSION, '0.1.0'.freeze +``` + + +## Generator + +This plugin incorporates a generator, which adds four new attributes to +[`site`](https://jekyllrb.com/docs/variables/#site-variables): +`all_collections`, `all_documents`, `everything`, and `sorted_lru_files`. + +These three attributes can be referenced as `site.everything`, `site.all_collections` +and `site.all_documents`. + +* `all_collections` includes all documents in all collections. + +* `all_documents` includes `all_collections` plus all standalone pages. + +* `everything` includes `all_documents` plus all static files. + +* `sorted_lru_files` is used by a new binary search lookup for matching page suffixes. + Currently only `jekyll_href` and `jekyll_draft` use this feature. + + +### Collection Management + +Jekyll provides inconsistent attributes for +[`site.pages`](https://jekyllrb.com/docs/pages/), +[`site.posts`](https://jekyllrb.com/docs/posts/) and +[`site.static_files`](https://jekyllrb.com/docs/static-files/). + + +* While the `url` attributes of items in `site.posts` and `site.pages` start with a slash (/), + `site.static_files` items do not have a `url` attribute. +* Static files have a `relative_path` attribute, which starts with a slash (/), + but although that attribute is also provided in `site.posts` and `site.pages`, + those values do not start with a slash. +* Paths ending with a slash (`/`) imply that a file called `index.html` should be fetched. +* HTML redirect files created by the + [`jekyll-redirect-from`](https://github.com/jekyll/jekyll-redirect-from) Jekyll plugin, + which are included in `site.static_files`, should be ignored. + +These inconsistencies mean that combining the standard three collections of files +provided as `site` attributes will create a new collection that is difficult +to process consistently: + +```ruby +# This pseudocode creates `oops`, which is problematic to process consistently +oops = site.all_collections + site.pages + site.static_files +``` + +`oops`, above, is difficult to process because of inconsistencies in the provided attributes +and how the attributes are constructed. + + +### Solving The Problem + +The generator normalizes these inconsistencies by utilizing the `APage` class +and filtering out HTML redirect files. + +The `all_collections` collection contains `APage` representations of `site.collections`. + +The `all_documents` collection contains `APage` representations of `site.pages`. + +The `everything` collection contains `APage` representations of: + +```text +# Pseudocode +site.collections + site.pages + site.static_files - HTML_redirect_files +``` + + +## The `APage` Class + +The `site.all_collections`, `site.all_documents` and `site.everything` attributes +consist of arrays of [`APage`](lib/hooks/a_page.rb) instances. + +The `APage` class has the following attributes: +`content` (HTML or Markdown), `data` (array), `date` (Ruby Date), `description`, `destination`, +`draft` (Boolean), `ext`, `href`, `label`, `last_modified` or `last_modified_at` (Ruby Date), +`layout`, `origin`, `path`, `relative_path`, `tags`, `title`, `type`, and `url`. + +* `href` always starts with a slash. + This value is consistent with `a href` values in website HTML. + Paths ending with a slash (`/`) have `index.html` appended so the path specifies an actual file. + +* `origin` indicates the original source of the item. + Possible values are `collection`, `individual_page` and `static_file`. + Knowing the origin of each item allows code to process each type of item appropriately. + + +## `all_collections` Block Tag + +The `all_collections` block tag creates a formatted listing of Jekyll files. +The ordering is configurable; by default, the listing is sorted by `date`, newest to oldest. +The `all_collections` tag has a `data_source` parameter that specifies which new property to report on +(`all_collections`, `all_documents`, or `everything`). + + +## Requirements + +All the pages in the Jekyll website must have an implicit date +(for example, all posts are assigned this property by Jekyll), +or an explicit `date` set in front matter, like this: + +```html +--- +date: 2022-01-01 +--- +``` + +If a front matter variable called `last_modified` or `last_modified_at` exists, +its value will be converted to a Ruby `Date`: + +```html +--- +last_modified: 2023-01-01 +--- +``` + +Or: + +```html +--- +last_modified_at: 2023-01-01 +--- +``` + +Otherwise, if `last_modified` or `last_modified_at` is not present in the front matter for a page, +the `date` value will be used last modified date value. + + +## Development + +After checking out the `jekyll_plugin_suppprt` repository, run `bin/setup` to install dependencies. + +`bin/console` provides an interactive prompt that allows you to experiment. + + +To build and install this gem onto your local machine, run: + +```shell +$ bundle exec rake install +jekyll_plugin_support 0.1.0 built to pkg/jekyll_plugin_support-0.1.0.gem. +jekyll_plugin_support (0.1.0) installed. +``` + +Examine the newly built gem: + +```shell +$ gem info jekyll_plugin_support + +*** LOCAL GEMS *** + +jekyll_plugin_support (0.1.0) + Author: Mike Slinn + Homepage: + https://github.com/mslinn/jekyll_plugin_support + License: MIT + Installed at: /home/mslinn/.gems + + Provides support for writing Jekyll plugins. +``` + + +### Build and Install Locally + +To build and install this gem onto your local machine, run: + +```shell +$ bundle exec rake install +jekyll_all_collections 0.3.8 built to pkg/jekyll_all_collections-0.3.8.gem. +jekyll_all_collections (0.3.8) installed. +``` + +Examine the newly built gem: + +```shell +$ gem info jekyll_all_collections + +*** LOCAL GEMS *** + +jekyll_all_collections (0.3.8) + Author: Mike Slinn + Homepage: + https://www.mslinn.com/jekyll_plugins/jekyll_all_collections.html + License: MIT + Installed at (0.3.8): /home/mslinn/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0 + + Provides normalized collections and extra functionality for Jekyll websites. +``` + + +### Build and Push to RubyGems + +To release a new version: + +1. Update the version number in `version.rb`. +2. Add an entry in `CHANGELOG.md` describing the changes since the last release. +3. Commit all changes to git; if you don't the next step might fail with a confusing error message. +4. Run the following: + + ```shell + $ bundle exec rake release + ``` + + The above creates a git tag for the version, commits the created tag, + and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org). + + +### Pry Breakpoint On StandardError + +A `pry` breakpoint will be set in the `StandardError` handler if `pry_on_standard_error: true` +is set in variable configuration section of `_config.yml`. + +For example, if your plugin is called `blah`, enable the breakpoint with the following section: + +```yml +blah: + pry_on_standard_error: true +``` + + +## Debugging + +You can control the verbosity of log output by adding the following to `_config.yml` in your Jekyll project: + +```yaml +plugin_loggers: + AllCollectionsTag::AllCollectionsTag: warn +``` + +1. First set breakpoints in the Ruby code that interests you. + +2. You have several options for initiating a debug session: + + 1. Use the **Debug Demo** Visual Studio Code launch configuration. + + 2. Type the `demo/_bin/debug` command, without the `-r` options shown above. + + ```console + ... lots of output as bundle update runs... + Bundle updated! + + INFO PluginMetaLogger: Loaded AllCollectionsHooks v0.2.0 :site, :pre_render, :normal hook plugin. + INFO PluginMetaLogger: Loaded DraftFilter plugin. + INFO PluginMetaLogger: Loaded all_collections v0.2.0 tag plugin. + Configuration file: /mnt/_/work/jekyll/my_plugins/jekyll_all_collections/demo/_config.yml + Cleaner: Removing /mnt/_/work/jekyll/my_plugins/jekyll_all_collections/demo/_site... + Cleaner: Removing /mnt/_/work/jekyll/my_plugins/jekyll_all_collections/demo/.jekyll-metadata... + Cleaner: Removing /mnt/_/work/jekyll/my_plugins/jekyll_all_collections/demo/.jekyll-cache... + Cleaner: Nothing to do for .sass-cache. + Fast Debugger (ruby-debug-ide 0.7.3, debase 0.2.5.beta2, file filtering is supported) listens on 0.0.0.0:1234 + ``` + + 3. Run `bin/attach` and pass the directory name of a Jekyll website that has a suitable script called `_bin/debug`. + The `demo` subdirectory fits this description. + + ```console + $ bin/attach demo + Successfully uninstalled jekyll_all_collections-0.1.2 + jekyll_all_collections 0.1.2 built to pkg/jekyll_all_collections-0.1.2.gem. + jekyll_all_collections (0.1.2) installed. + Fast Debugger (ruby-debug-ide 0.7.3, debase 0.2.4.1, file filtering is supported) listens on 0.0.0.0:1234 + ``` + + +3. Attach to the debugger process if required. + This git repo includes two [Visual Studio Code launch configurations](./.vscode/launch.json) for this purpose labeled + **Attach rdbg** and **Attach with ruby_lsp**. + +4. Point your web browser to http://localhost:4444 + +If a debugging session terminates abruptly and leaves ports tied up, +run the `demo/_bin/release_port` script. + + +## Demonstration Plugins and Website + +A demo / test website is provided in the [`demo`](demo) directory. +It can be used to debug the plugin or to run freely. + +### Examining the Demo Plugins + +The following example plugins use +[Ruby’s squiggly heredoc operator](https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html#label-Here+Documents) (`<<~`). +The squiggly heredoc operator removes the outermost indentation. +This provides easy-to-read multiline text literals. + +**demo/_plugins/demo_tag.rb**: + +```ruby +require 'jekyll_plugin_support' + +# Use the JekyllSupport module namespace so the self methods are automajically found +module JekyllSupport + DemoInlineTagError = JekyllSupport.define_error + + class DemoTag < JekyllTag + VERSION = '0.1.2'.freeze + # JekyllSupport.redef_without_warning 'VERSION', '0.1.2'.freeze + + def render_impl + @demo_tag_error = @helper.parameter_specified? 'raise_demo_tag_error' + @keyword1 = @helper.parameter_specified? 'keyword1' + @keyword2 = @helper.parameter_specified? 'keyword2' + @name1 = @helper.parameter_specified? 'name1' + @name2 = @helper.parameter_specified? 'name2' + @standard_error = @helper.parameter_specified? 'raise_standard_error' + + if @tag_config + @die_on_demo_tag_error = @tag_config['die_on_demo_tag_error'] == true + @die_on_standard_error = @tag_config['die_on_standard_error'] == true + end + + raise DemoInlineTagError, 'This DemoInlineTagError error is expected.' if @demo_tag_error + raise StandardError, 'This StandardError error is expected.' if @standard_error + + # _infinity = 1 / 0 if @standard_error # Not required + + output + rescue DemoInlineTagError => e # jekyll_plugin_support handles StandardError + @logger.error { e.logger_message } + exit! 1 if @die_on_demo_tag_error + + e.html_message + end + + private + + def output + <<~END_OUTPUT +
# jekyll_plugin_support becomes able to perform variable substitution after this variable is defined.
+        # The value could be updated at a later stage, but no need to add that complexity unless there is a use case.
+        @argument_string="#{@argument_string}"
+
+        @helper.argv=
+          #{@helper.argv&.join("\n  ")}
+
+        # Liquid variable name/value pairs
+        @helper.params=
+          #{@helper.params&.map { |k, v| "#{k}=#{v}" }&.join("\n  ")}
+
+        # The keys_values property serves no purpose any more, consider it deprecated
+        @helper.keys_values=
+          #{(@helper.keys_values&.map { |k, v| "#{k}=#{v}" })&.join("\n  ")}
+
+        @layout='#{@layout}'
+        @page.keys='#{@page.keys}'
+
+        remaining_markup='#{@helper.remaining_markup}'
+
+        @keyword1='#{@keyword1}'
+        @keyword2='#{@keyword2}'
+        @name1='#{@name1}'
+        @name2='#{@name2}'
+ END_OUTPUT + end + + JekyllPluginHelper.register(self, 'demo_inline_tag') + end +end +``` + +**demo/_plugins/demo_block.rb**: + +```ruby +require 'cgi' +require 'jekyll_plugin_support' + +# Use the JekyllSupport module namespace so the self methods are automajically found +module JekyllSupport + DemoBlockError = JekyllSupport.define_error + + class DemoBlock < JekyllBlock + VERSION = '0.1.2'.freeze + + def render_impl(text) + @demo_block_error = @helper.parameter_specified? 'raise_demo_block_error' + @keyword1 = @helper.parameter_specified? 'keyword1' + @keyword2 = @helper.parameter_specified? 'keyword2' + @name1 = @helper.parameter_specified? 'name1' + @name2 = @helper.parameter_specified? 'name2' + @standard_error = @helper.parameter_specified? 'raise_standard_error' + + if @tag_config + @die_on_demo_block_error = @tag_config['die_on_demo_block_error'] == true + @die_on_standard_error = @tag_config['die_on_standard_error'] == true + end + + raise DemoBlockTagError, 'This DemoBlockTagError error is expected.' if @demo_block_error + raise StandardError, 'This StandardError error is expected.' if @standard_error + + # _infinity = 1 / 0 if @standard_error # Not required + + output text + rescue DemoBlockTagError => e # jekyll_plugin_support handles StandardError + @logger.error { e.logger_message } + exit! 1 if @die_on_demo_block_error + + e.html_message + end + + private + + def output(text) + <<~END_OUTPUT +
@helper.tag_name=#{@helper.tag_name}
+
+        @mode=#{@mode}
+
+        # jekyll_plugin_support becomes able to perform variable substitution after this variable is defined.
+        # The value could be updated at a later stage, but no need to add that complexity unless there is a use case.
+        @argument_string="#{@argument_string}"
+
+        @helper.argv=
+          #{@helper.argv&.join("\n  ")}
+
+        # Liquid variable name/value pairs
+        @helper.params=
+          #{@helper.params&.map { |k, v| "#{k}=#{v}" }&.join("\n  ")}
+
+        # The keys_values property serves no purpose any more, consider it deprecated
+        @helper.keys_values=
+          #{(@helper.keys_values&.map { |k, v| "#{k}=#{v}" })&.join("\n  ")}
+
+        @helper.remaining_markup='#{@helper.remaining_markup}'
+
+        @envs=#{@envs.keys.sort.join(', ')}
+
+        @config['url']='#{@config['url']}'
+
+        @site.collection_names=#{@site.collection_names&.sort&.join(', ')}
+
+        @page['description']=#{@page['description']}
+
+        @page['path']=#{@page['path']}
+
+        @keyword1=#{@keyword1}
+
+        @keyword2=#{@keyword2}
+
+        @name1=#{@name1}
+
+        @name2=#{@name2}
+
+        text=#{text}
+ END_OUTPUT + end + + JekyllPluginHelper.register(self, 'demo_block_tag') + end +end +``` + +The following is an example of no_arg_parsing optimization. + +```ruby +require 'jekyll_plugin_support' + +# Use the JekyllSupport module namespace so the self methods are automajically found +module JekyllSupport + class DemoTagNoArgs < JekyllTagNoArgParsing + VERSION = '0.1.0'.freeze + + def render_impl + <<~END_OUTPUT + The raw arguments passed to this DemoTagNoArgs instance are:
+ #{@argument_string} + END_OUTPUT + end + + JekyllPluginHelper.register(self, 'demo_inline_tag_no_arg') + end +end +``` + +### Run Freely + + 1. Run from the command line: + + ```shell + $ demo/_bin/debug -r + ``` + + 2. View the generated website, + which might be at [`http://localhost:4444`](http://localhost:4444), + depending on how you configured it. + + +### Plugin Debugging + + 1. Set breakpoints in Visual Studio Code. + + 2. Run the **Debug Demo development** or **Debug Demo production** launch configuration. + +Alternatively, you can: + + 2. Initiate a debug session from the command line by running the `demo/_bin/debug` script: + + ```shell + $ demo/_bin/debug + Fetching gem metadata from https://rubygems.org/.......... + Resolving dependencies... + Fetching public_suffix 5.0.4 + Fetching nokogiri 1.15.5 (x86_64-linux) + Installing public_suffix 5.0.4 + Installing nokogiri 1.15.5 (x86_64-linux) + Bundle complete! 17 Gemfile dependencies, 96 gems now installed. + Use `bundle info [gemname]` to see where a bundled gem is installed. + + INFO PluginMetaLogger: Loaded DraftFilter plugin. + INFO PluginMetaLogger: Loaded outline_js v1.2.1 plugin. + INFO PluginMetaLogger: Loaded outline v1.2.1 plugin. + Configuration file: /mnt/f/jekyll_plugin_support/demo/_config.yml + Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/_site... + Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/.jekyll-metadata... + Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/.jekyll-cache... + Cleaner: Nothing to do for .sass-cache. + DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:37177) + DEBUGGER: wait for debugger connection... + ``` + + 3. Once the `DEBUGGER: wait for debugger connection...` message appears, + run the Visual Studio Code launch configuration called **Attach with rdbg**. + + 4. View the generated website, + which might be at [`http://localhost:4444`](http://localhost:4444), + depending on how you configured it. + + +### Build and Push to RubyGems + +To release a new version: + + 1. Update the version number in `version.rb`. + 2. Add an entry to `CHANGELOG.md` describing the changes since the previous version. + 3. Commit all changes to git; + if you don't the next step might fail with an unexplainable error message. + 4. Run the following: + + ```shell + $ bundle exec rake release + ``` + + The above creates a git tag for the version, commits the created tag, + and pushes the new `.gem` file to [RubyGems.org](https://rubygems.org). + + +## Contributing + +1. Fork the project +2. Create a descriptively named feature branch +3. Add your feature +4. Submit a pull request + + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/bin/gems/jekyll_plugin_support-3.0.0/Rakefile b/bin/gems/jekyll_plugin_support-3.0.0/Rakefile new file mode 100644 index 00000000..da5c9db9 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/Rakefile @@ -0,0 +1,5 @@ +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) +task default: :spec diff --git a/bin/gems/jekyll_plugin_support-3.0.0/jekyll_plugin_support.gemspec b/bin/gems/jekyll_plugin_support-3.0.0/jekyll_plugin_support.gemspec new file mode 100644 index 00000000..319f6293 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/jekyll_plugin_support.gemspec @@ -0,0 +1,38 @@ +require_relative 'lib/jekyll_plugin_support/version' + +Gem::Specification.new do |spec| + github = 'https://github.com/mslinn/jekyll_plugin_support' + + spec.bindir = 'exe' + spec.authors = ['Mike Slinn'] + spec.email = ['mslinn@mslinn.com'] + spec.files = Dir['.rubocop.yml', 'LICENSE.*', 'Rakefile', '{lib,spec}/**/*', '*.gemspec', '*.md'] + spec.homepage = 'https://www.mslinn.com/jekyll_plugins/jekyll_plugin_support.html' + spec.license = 'MIT' + spec.metadata = { + 'allowed_push_host' => 'https://rubygems.org', + 'bug_tracker_uri' => "#{github}/issues", + 'changelog_uri' => "#{github}/CHANGELOG.md", + 'homepage_uri' => spec.homepage, + 'source_code_uri' => github, + } + spec.name = 'jekyll_plugin_support' + spec.platform = Gem::Platform::RUBY + spec.post_install_message = <<~END_MESSAGE + + Thanks for installing #{spec.name}! + + END_MESSAGE + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.6.0' + spec.summary = 'Provides a framework for writing and testing Jekyll plugins' + spec.test_files = spec.files.grep %r{^(test|spec|features)/} + spec.version = JekyllPluginSupportVersion::VERSION + + spec.add_dependency 'facets' + spec.add_dependency 'jekyll', '>= 4.4.1' + spec.add_dependency 'jekyll_plugin_logger' + spec.add_dependency 'key-value-parser' + spec.add_dependency 'pry' + spec.add_dependency 'sorted_set' +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block.rb new file mode 100644 index 00000000..57969166 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block.rb @@ -0,0 +1,118 @@ +module JekyllSupport + # Base class for Jekyll block tags + class JekyllBlock < Liquid::Block + attr_reader :argument_string, :helper, :line_number, :logger, :page, :site, :text + + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @param tag_name [String] the name of the tag, which we usually know. + # @param argument_string [String] the arguments passed to the tag, as a single string. + # @param parse_context [Liquid::ParseContext] contains the following attributes: + # @depth might have the value 0 + # @error_mode might have the value `:strict` + # @line_number duplicates @ptions[:line_number] + # @locale duplicates @ptions[:locale] + # @options is a hash with the following two keys that holds Liquid options: + # :locale is a Liquid::I18n object, used to display localized error messages on Liquid built-in tags and filters. + # :line_number is the line number containing the plugin invocation. + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @partial Boolean, unclear what this indicates + # @template_options Replicates @options + # @trim_whitespace might have the value `false` + # @warnings array + # @return [void] + def initialize(tag_name, markup, parse_context) + super + @tag_name = tag_name + raise JekyllPluginSupportError, "markup is a #{markup.class} with value '#{markup}'." unless markup.instance_of? String + + # Lookup variable names with values in markup in render because site and config are not available here + @argument_string = markup # Replace variable names with values in markup in render because site and config are not available here + + @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) + @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." } + @helper = JekyllPluginHelper.new tag_name, markup, @logger, respond_to?(:no_arg_parsing) + + @error_name = "#{tag_name.camelcase(:upper)}Error" + ::JekyllSupport::CustomError.factory @error_name + end + + # Liquid::Block subclasses do not render if there is no content within the tag + # This override fixes that + def blank? + false + end + + # Method prescribed by the Jekyll plugin lifecycle. + # Defines @config, @envs, @mode, @page and @site + # @return [String] + def render(liquid_context) + @helper.liquid_context = ::JekyllSupport.inject_config_vars liquid_context # modifies liquid_context + text = super # Liquid variable values in content are looked up and substituted + + @envs = liquid_context.environments.first + @page = liquid_context.registers[:page] + @scopes = liquid_context.scopes + @site = liquid_context.registers[:site] + + @config = @site.config + @tag_config = @config[@tag_name] + @jps = @config['jekyll_plugin_support'] + @pry_on_standard_error = @jps['pry_on_standard_error'] || false if @jps + + set_error_context + + # @envs.keys are :content, :highlighter_prefix, :highlighter_suffix, :jekyll, :layout, :page, :paginator, :site, :theme + @layout = @envs[:layout] + @paginator = @envs[:paginator] + @theme = @envs[:theme] + + env = @config['env'] + @mode = env&.key?('JEKYLL_ENV') ? env['JEKYLL_ENV'] : 'development' + + @argument_string = JekyllSupport.lookup_liquid_variables @logger, @helper.liquid_context, @argument_string.to_s.strip + @helper.reinitialize @argument_string.to_s.strip + + @attribution = @helper.parameter_specified?('attribution') || false unless @no_arg_parsing + @logger.debug { "@keys_values='#{@keys_values}'" } + + # @argument_string = JekyllSupport.lookup_liquid_variables @logger, liquid_context, @argument_string # Is this redundant? + # @argument_string.strip! # Is this redundant? + # @helper.reinitialize @argument_string # Is this redundant? + + render_impl(text) + rescue StandardError => e + e.shorten_backtrace + file_name = e.backtrace[0]&.split(':')&.first + in_file_name = "in '#{file_name}' " if file_name + of_page = "of '#{@page['path']}'" if @page + @logger.error { "#{e.class} on line #{@line_number} #{of_page} while processing #{tag_name} #{in_file_name}- #{e.message}" } + binding.pry if @pry_on_standard_error # rubocop:disable Lint/Debugger + raise e if @die_on_standard_error + + <<~END_MSG +
+ #{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} by #{@tag_name}: #{e.message} +
+ END_MSG + end + + # Jekyll plugins should override this method, not render, + # so they can be tested more easily. + # The following variables are predefined: + # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme + # @return [String] The result to be rendered to the invoking page + def render_impl(text) + text + end + + def set_error_context + return unless Object.const_defined? @error_name + + error_class = Object.const_get @error_name + error_class.class_variable_set(:@@argument_string, @argument_string) + error_class.class_variable_set(:@@line_number, @line_number) + error_class.class_variable_set(:@@path, @page['path']) + error_class.class_variable_set(:@@tag_name, @tag_name) + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block_noarg.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block_noarg.rb new file mode 100644 index 00000000..3fa341a8 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/block/jekyll_plugin_support_block_noarg.rb @@ -0,0 +1,31 @@ +module JekyllSupport + class JekyllBlockNoArgParsing < JekyllBlock + attr_reader :argument_string, :helper, :line_number, :logger, :page, :site + + def initialize(tag_name, argument_string, parse_context) + class << self + include NoArgParsing + end + + super + @logger.debug { "#{self.class}: respond_to?(:o_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." } + rescue StandardError => e + e.shorten_backtrace + @logger.error { e.full_message } + JekyllSupport.error_short_trace(@logger, e) + end + + # Liquid::Block subclasses do not render if there is no content within the tag + # This override fixes that + def blank? + false + end + + # Jekyll plugins must override this method, not render, so their plugin can be tested more easily + # The following variables are predefined: + # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme + def render_impl + abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not." + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_custom_error.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_custom_error.rb new file mode 100644 index 00000000..7a6b202c --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_custom_error.rb @@ -0,0 +1,52 @@ +require 'facets/string/camelcase' +require 'facets/string/snakecase' + +module JekyllSupport + # Use like this: + # CustomError.new(:MyError, 'blah', 'asdf') + class CustomError < StandardError + def self.factory(error_class_name) + return if Object.const_defined? "::#{error_class_name}" + + Object.const_set error_class_name, Class.new(CustomError) + end + + def error_name + self.class.name.split('::').last + end + + def calling_file + file_fq, _line_number, _extra = backtrace[0]&.split(':') + file_fq + end + + # @return HTML
tag with class set to the snake_case version of the error class name. + def html_message + shorten_backtrace + path, line_number, _caller = backtrace[1]&.split(':') + <<~END_MSG +
+ #{self.class} raised in #{calling_file} while processing line #{line_number} (after front matter) of #{path} + #{message} +
+ END_MSG + end + + def logger_message + shorten_backtrace + kaller = caller(1..1).first + path, line_number, _caller = backtrace[1]&.split(':') + <<~END_MSG + #{error_name} raised in #{kaller} while processing line #{line_number} (after front matter) of #{path} + #{message} + END_MSG + end + + def shorten_backtrace(backtrace_element_count = 3) + b = backtrace[0..backtrace_element_count - 1].map do |x| + x.gsub(Dir.pwd + '/', './') + end + set_backtrace b + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_plugin_error_handling.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_plugin_error_handling.rb new file mode 100644 index 00000000..55b4e757 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/error/jekyll_plugin_error_handling.rb @@ -0,0 +1,48 @@ +module JekyllSupportError + attr_reader :logger, :page + + # If a Jekyll plugin needs to crash exit, and stop Jekyll, call this method. + # It does not generate a stack trace. + # This method does not return because the process is abruptly terminated. + # + # @param error StandardError or a subclass of StandardError is required + # + # Do not raise the error before calling this method, just create it via 'new', like this: + # exit_without_stack_trace StandardError.new('This is my error message') + # + # If you want to call this method from a handler method, the default index for the backtrace array must be specified. + # The default backtrace index is 1, which means the calling method. + # To specify the calling method's caller, pass in 2, like this: + # exit_without_stack_trace StandardError.new('This is my error message'), 2 + def exit_without_stack_trace(error, caller_index = 1) + raise error + rescue StandardError => e + file, line_number, caller = e.backtrace[caller_index].split(':') + caller = caller.tr('`', "'") + warn "#{error.message} #{caller} on line #{line_number} (after front matter) of #{file}".red + # Process.kill('HUP', Process.pid) # generates huge stack trace + exec "echo ''" + end + + def format_error_message(message) + page = " of #{@page['path']}" if @page + remove_ansi_color "on line #{line_number} (after front matter)#{page}.\n#{message}" + end + + def remove_ansi_color(string) + string.gsub(/\e\[([;\d]+)?m/, '') + end + + def maybe_reraise_error(error, throw_error: true) + fmsg = format_error_message "#{error.class}: #{error.message.strip}" + @logger.error { fmsg } + return "#{fmsg}" unless throw_error + + error.set_backtrace error.backtrace[0..9] + raise error + end + + def warn_short_trace(error) + JekyllSupport.warn_short_trace(@logger, error) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/generator/jekyll_plugin_support_generator.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/generator/jekyll_plugin_support_generator.rb new file mode 100644 index 00000000..3b4c6a9b --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/generator/jekyll_plugin_support_generator.rb @@ -0,0 +1,69 @@ +module JekyllSupport + # Base class for Jekyll generators. + # PluginMetaLogger.instance.config is populated with the contents of `_config.yml` before Jekyll::Generator instances run. + class JekyllGenerator < Jekyll::Generator + attr_reader :helper, :line_number, :logger, :site + + # Method prescribed by the Jekyll plugin lifecycle. + # Defines @config, @envs, @mode and @site + # @return [void] + def generate(site) + @logger ||= PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) + + @error_name = "#{self.class.name}Error" + + @site = site + @config = @site.config + @envs = site.config['env'] + @theme = @site.theme + + @mode = ENV['JEKYLL_ENV'] || 'development' + + generate_impl + rescue StandardError => e + e.shorten_backtrace + @logger.error { "#{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} by #{self.class.name} - #{e.message}" } + binding.pry if @pry_on_standard_error # rubocop:disable Lint/Debugger + raise e if @die_on_standard_error + + <<~END_MSG +
+ #{e.class} on line #{@line_number} of #{e.backtrace[0].split(':').first} by #{self.class.name}: #{e.message} +
+ END_MSG + end + + # Jekyll plugins should override this method, not `generate`, so they can be tested more easily. + # The following variables are predefined: + # @config, @envs, @helper, @logger, @mode, @paginator, @site and @theme + # @return [void] + def generate_impl; end + + def self.register(klass) + abort("Error: The #{klass.name} plugin does not define VERSION") \ + unless klass.const_defined?(:VERSION) + + version = klass.const_get(:VERSION) + error_name_stub = klass.name.include?('::') ? klass.name.split('::')[1] : klass.name + error_ruby_class_name = "#{error_name_stub.camelcase(:upper)}Error" + error_css_class_name = error_ruby_class_name.split('::').last.snakecase + msg = <<~END_MSG + Loaded generator plugin #{klass.name} v#{version}. It has: + Error class: #{@error_name} + CSS class for error messages: #{error_css_class_name} + END_MSG + + PluginMetaLogger.instance.info { msg } + end + + def set_error_context(klass) # rubocop:disable Naming/AccessorMethodName + return unless Object.const_defined? @error_name + + error_class = Object.const_get @error_name + error_class.class_variable_set(:@@argument_string, @argument_string) + error_class.class_variable_set(:@@line_number, @line_number) + error_class.class_variable_set(:@@path, @page['path']) + error_class.class_variable_set(:@@tag_name, klass.name) + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper.rb new file mode 100644 index 00000000..affaf136 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper.rb @@ -0,0 +1,112 @@ +require 'facets/string/interpolate' +require 'key_value_parser' +require 'shellwords' + +module JekyllSupport + class JekyllPluginHelper + attr_accessor :liquid_context + attr_reader :argument_string, :argv, :argv_original, :attribution, :excerpt_caller, :keys_values_original, + :keys_values, :jpsh_subclass_caller, :logger, :markup, :no_arg_parsing, :params, :params_original, + :tag_name + + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @param tag_name [String] the name of the tag, which we already know. + # @param argument_string [String] the arguments from the tag, as a single string. + # @param parse_context [Liquid::ParseContext] hash that stores Liquid options. + # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second, + # a boolean parameter that determines if error messages should display the line number the error occurred. + # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters. + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @return [void] + def initialize(tag_name, markup, logger, no_arg_parsing) + @tag_name = tag_name + @logger = logger + @markup = markup + @argument_string = markup + @no_arg_parsing = no_arg_parsing + rescue StandardError => e + e.shorten_backtrace + @logger.error { e.message } + end + + # @return undefined if parameter was specified, removes it from the available tokens and returns value + def parameter_specified?(name, delete_param: true) + return false if @keys_values.to_s.empty? + + key = name + key = name.to_sym if @keys_values&.first&.first.instance_of?(Symbol) + value = @keys_values[key] + delete_parameter(name) if delete_param + value + end + + def reinitialize(markup) + # @keys_values was a Hash[Symbol, String|Boolean] but now it is Hash[String, String|Boolean] + @argument_string = markup + if @no_arg_parsing + define_singleton_method(:argv) { warn_fetch :argv } + define_singleton_method(:keys_values) { warn_fetch :keys_values } + define_singleton_method(:params) { warn_fetch :params } + define_singleton_method(:parameter_specified?) { |_name| warn_parse(:parameter_specified?) } + define_singleton_method(:delete_parameter) { |_name| warn_parse(:delete_parameter) } + @attribution = false + else + parse markup + @attribution = parameter_specified?('attribution') || false + @logger.debug { "@keys_values='#{@keys_values}'" } + end + end + + # Call this method to return the remaining markup after `parameter_specified?` has been invoked. + def remaining_markup + @argv&.join(' ') + end + + def remaining_markup_original + @argv_original&.join(' ') + end + + def warn_fetch(variable) + abort "Error: Argument parsing was suppressed, but an attempt to obtain the value of #{variable} was made" + end + + def warn_parse(meth) + abort "Error: Argument parsing was suppressed, but an attempt to invoke #{meth} was made" + end + + def delete_parameter(key) + return if @keys_values.empty? || @params.nil? + + @params.delete(key) + @argv.delete_if { |x| x == key or x.start_with?("#{key}=") } + @keys_values.delete(key) + + @params_original.delete(key) + @argv_original.delete_if { |x| x == key or x.start_with?("#{key}=") } + @keys_values_original.delete(key) + end + + private + + def page + @liquid_context.registers[:page] + end + + def parse(markup) + @argv_original = Shellwords.split(markup) + @keys_values_original = KeyValueParser + .new({}, { array_values: false, normalize_keys: false, separator: /=/ }) + .parse(@argv_original) + @params_original = @keys_values_original unless respond_to?(:no_arg_parsing) && no_arg_parsing + + @argv = Shellwords.split(self.class.expand_env(markup, logger)) + @keys_values = KeyValueParser + .new({}, { array_values: false, normalize_keys: false, separator: /=/ }) + .parse(@argv) + + return if respond_to?(:no_arg_parsing) && no_arg_parsing + + @params = @keys_values # TODO: @keys_values should be deleted + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_attribution.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_attribution.rb new file mode 100644 index 00000000..8c75b47e --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_attribution.rb @@ -0,0 +1,74 @@ +module JekyllSupport + # Attribution aspect of JekyllPluginHelper + class JekyllPluginHelper + # @param file must be a fully qualified file name that points to a file within a gem. + # @return Gem::Specification of gem that file points into, or nil if not called from a gem + # See https://stackoverflow.com/a/75890279/553865 + def self.current_spec(file) + abort 'JekyllPluginHelper::current_spec: file is nil' if file.nil? + return nil unless File.exist?(file) + + searcher = if Gem::Specification.respond_to?(:find) + Gem::Specification + elsif Gem.respond_to?(:searcher) + Gem.searcher.init_gemspecs + end + + searcher&.find do |spec| + file.start_with? spec.full_gem_path + end + end + + def attribute + return unless @current_gem + + <<~END_OUTPUT + + END_OUTPUT + end + + def default_attribution + authors = @authors&.join(', ') + result = "Generated by the \#{@name} v\#{@version} Jekyll plugin" + result << ", written by #{authors}" if authors + result << " \#{@published_date}" if @published_date + result << '.' + result + end + + # Sets @current_gem if file points at a uniquely named file within a gem. + # @param file must be a fully qualified file name in a gem, for example: __FILE__ + def gem_file(file) + @current_gem = JekyllPluginHelper.current_spec file + @logger.debug "No gem found for '#{file} was found." unless @current_gem + annotate_globals if @attribution && @current_gem + end + + private + + def annotate_globals + return unless @current_gem + + @name = @current_gem.name + @authors = @current_gem.authors + @homepage = @current_gem.homepage + @published_date = @current_gem.date.to_date.to_s + @version = @current_gem.version + end + + def attribution_string + string = if @attribution == true + default_attribution + else + @attribution + end + String.interpolate { string } + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_class.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_class.rb new file mode 100644 index 00000000..1d1c812a --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/helper/jekyll_plugin_helper_class.rb @@ -0,0 +1,88 @@ +require 'facets/string/camelcase' +require 'facets/string/snakecase' +require 'yaml' + +module JekyllSupport + # Class methods for JekyllPluginHelper + class JekyllPluginHelper + # Expand an environment variable reference + def self.expand_env(str, logger = nil, die_if_undefined: false) + str&.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}/) do + envar = Regexp.last_match(1) + unless ENV.key? envar + msg = "jekyll_plugin_support error: environment variable #{envar} is undefined" + raise JekyllPluginSupportError, msg.red, [] if die_if_undefined + + if logger + logger.warn msg + else + puts msg.red + end + end + ENV.fetch(envar, nil) + end + end + + def self.generate_message(klass, tag_name, version) + error_name_stub = klass.name.include?('::') ? klass.name.split('::')[1] : klass.name + error_ruby_class_name = "#{error_name_stub.camelcase(:upper)}Error" + config_die_key = "die_on_#{error_ruby_class_name.snakecase}" + error_css_class_name = error_ruby_class_name.split('::').last.snakecase + config = YAML.load_file('_config.yml') + tag_config = config[tag_name] + tag_config_msg = if tag_config.nil? + <<~END_MSG + _config.yml does not contain configuration information for this plugin. + You could add a section containing default values by specifying a section for the tag name, + and an entry whose name starts with `die_on_`, followed by a snake_case version of the error name. + + #{tag_name}: + #{config_die_key}: false + END_MSG + else + <<~END_MSG + _config.yml contains the following configuration for this plugin: + #{tag_config} + END_MSG + end + + <<~END_MSG + Loaded plugin #{tag_name} v#{version}. It has: + Error class: #{error_ruby_class_name} + CSS class for error messages: #{error_css_class_name} + + #{tag_config_msg} + END_MSG + end + + # @param klass [Class] class instance to register + # @param tag_name [String] name of plugin defined by klass to register as + # @param quiet [Boolean] suppress registration message if truthy + def self.register(klass, tag_name, quiet: false) + abort("Error: The #{tag_name} plugin does not define VERSION") \ + unless klass.const_defined?(:VERSION) + + version = klass.const_get(:VERSION) + + abort("Error: The #{tag_name} plugin is not an instance of JekyllSupport::JekyllBlock or JekyllSupport::JekyllTag") \ + unless klass.instance_of?(Class) && + (klass.ancestors.include?(::JekyllSupport::JekyllBlock) || + klass.ancestors.include?(::JekyllSupport::JekyllTag)) + + Liquid::Template.register_tag(tag_name, klass) + return if quiet + + msg = generate_message(klass, tag_name, version) + PluginMetaLogger.instance.info { msg } + end + + def self.remove_html_tags(string) + string.gsub(/<[^>]*>/, '').strip + end + + # strip leading and trailing quotes if present + def self.remove_quotes(string) + string.strip.gsub(/\A'|\A"|'\Z|"\Z/, '').strip if string + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/a_page.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/a_page.rb new file mode 100644 index 00000000..e5e5ac5d --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/a_page.rb @@ -0,0 +1,69 @@ +module AllCollectionsHooks + class APage + attr_reader :content, :data, :date, :description, :destination, :draft, :excerpt, :ext, :extname, :href, + :label, :last_modified, :layout, :origin, :path, :relative_path, :tags, :title, :type, :url + + def initialize(obj, origin) + @origin = origin + data_field_init obj + obj_field_init obj + @draft = Jekyll::Draft.draft? obj + @href = @url if @href.nil? + # @href = "/#{@href}" if @origin == 'individual_page' + @href = "#{@href}index.html" if @href.end_with? '/' + @name = File.basename(@href) + @title = if @data&.key?('title') + @data['title'] + elsif obj.respond_to?(:title) + obj.title + else + "#{@href}" + end + rescue StandardError => e + JekyllSupport.error_short_trace(@logger, e) + # JekyllSupport.warn_short_trace(@logger, e) + end + + def to_s + @label || @date.to_s + end + + private + + def data_field_init(obj) + return unless obj.respond_to? :data + + @data = obj.data + + @categories = @data['categories'] if @data.key? 'categories' + @date = (@data['date'].to_date if @data&.key?('date')) || Date.today + @description = @data['description'] if @data.key? 'description' + @excerpt = @data['excerpt'] if @data.key? 'excerpt' + @ext ||= @data['ext'] if @data.key? 'ext' + @last_modified = @data['last_modified'] || @data['last_modified_at'] || @date + @last_modified_field = case @data + when @data.key?('last_modified') + 'last_modified' + when @data.key?('last_modified_at') + 'last_modified_at' + end + @layout = @data['layout'] if @data.key? 'layout' + @tags = @data['tags'] if @data.key? 'tags' + end + + def obj_field_init(obj) + @content = obj.content if obj.respond_to? :content + + # TODO: What _config.yml setting should be passed to destination()? + @destination = obj.destination('') if obj.respond_to? :destination + @ext = obj.extname + @extname = @ext # For compatibility with previous versions of all_collections + @label = obj.collection.label if obj.respond_to?(:collection) && obj.collection.respond_to?(:label) + @path = obj.path if obj.respond_to? :path + @relative_path = obj.relative_path if obj.respond_to? :relative_path + @type = obj.type if obj.respond_to? :type + @url = obj.url + @url = "#{@url}index.html" if @url.end_with? '/' + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_collections_hooks.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_collections_hooks.rb new file mode 100644 index 00000000..8c693666 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_collections_hooks.rb @@ -0,0 +1,61 @@ +module JekyllAllCollections + module AllCollectionsHooks + class << self + attr_accessor :logger + end + @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) + + # No, all_collections is not defined for this hook + # Jekyll::Hooks.register(:site, :after_init, priority: :normal) do |site| + # defined_msg = ::AllCollectionsHooks.all_collections_defined?(site) + # @logger.debug { "Jekyll::Hooks.register(:site, :after_init: #{defined_msg}" } + # end + + # Creates a `Array[APage]` property called site.all_collections if it does not already exist. + # The array is available from :site, :pre_render onwards + # Each `APage` entry is one document or page. + Jekyll::Hooks.register(:site, :post_read, priority: :normal) do |site| + @site = site + unless site.class.method_defined? :all_collections + defined_msg = ::AllCollectionsHooks.all_collections_defined? site + @logger.debug { "Jekyll::Hooks.register(:site, :post_read, :normal: #{defined_msg}" } + ::AllCollectionsHooks.compute(site) if !@site.class.method_defined?(:all_documents) || @site.all_documents.nil? + end + rescue StandardError => e + JekyllSupport.error_short_trace(@logger, e) + # JekyllSupport.warn_short_trace(@logger, e) + end + + # Yes, all_collections is defined for this hook + # Jekyll::Hooks.register(:site, :post_read, priority: :low) do |site| + # defined_msg = ::AllCollectionsHooks.all_collections_defined?(site) + # @logger.debug { "Jekyll::Hooks.register(:site, :post_read, :low: #{defined_msg}" } + # rescue StandardError => e + # JekyllSupport.error_short_trace(@logger, e) + # # JekyllSupport.warn_short_trace(@logger, e) + # end + + # Yes, all_collections is defined for this hook + # Jekyll::Hooks.register(:site, :post_read, priority: :normal) do |site| + # defined_msg = ::AllCollectionsHooks.all_collections_defined?(site) + # @logger.debug { "Jekyll::Hooks.register(:site, :post_read, :normal: #{defined_msg}" } + # rescue StandardError => e + # JekyllSupport.error_short_trace(@logger, e) + # # JekyllSupport.warn_short_trace(@logger, e) + # end + + # Yes, all_collections is defined for this hook + # Jekyll::Hooks.register(:site, :pre_render, priority: :normal) do |site, _payload| + # defined_msg = ::AllCollectionsHooks.all_collections_defined?(site) + # @logger.debug { "Jekyll::Hooks.register(:site, :pre_render: #{defined_msg}" } + # rescue StandardError => e + # JekyllSupport.error_short_trace(@logger, e) + # # JekyllSupport.warn_short_trace(@logger, e) + # end + end +end + +PluginMetaLogger.instance.logger.info do + "Loaded AllCollectionsHooks v#{JekyllPluginSupportVersion::VERSION} :site, :pre_render, :normal hook plugin." +end +Liquid::Template.register_filter(JekyllAllCollections::AllCollectionsHooks) diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_files.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_files.rb new file mode 100644 index 00000000..8a0c0411 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/all_files.rb @@ -0,0 +1,48 @@ +# Insert the url of a Jekyll::Page into each LruFile instance, +# along with the Page reference +# todo: replace references to url and :url with reverse_url and :reverse_url +LruFile = Struct.new(:url, :page) do + include SendChain + + def <=>(other) + url <=> other.url + end + + def href + url.reverse + end +end + +# Matches suffixes of an array of urls +# Converts suffixes to prefixes +class SortedLruFiles + attr_reader :msbs + + def initialize + @msbs = MSlinnBinarySearch.new %i[url start_with?] + end + + # @param apages [Array[APage]] + def add_pages(apages) + apages.each { |apage| insert apage.href, apage } + @msbs.enable_search + end + + def enable_search + @msbs.enable_search + end + + def find(suffix) + @msbs.find suffix + end + + def insert(url, file) + lru_file = LruFile.new(url.reverse, file) + lru_file.new_chain [:url, %i[start_with? placeholder]] + @msbs.insert(lru_file) + end + + def select(suffix) + @msbs.select_pages suffix + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/class_methods.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/class_methods.rb new file mode 100644 index 00000000..5eded81a --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/hooks/class_methods.rb @@ -0,0 +1,50 @@ +module AllCollectionsHooks + class << self + attr_accessor :all_collections, :all_documents, :everything, :sorted_lru_files + end + + # @sort_by = ->(apages, criteria) { [apages.sort(criteria)] } # todo delete this + + # @return [String] indicating if :all_collections is defined or not + def self.all_collections_defined?(site) + "site.all_collections #{site.class.method_defined?(:all_collections) ? 'IS' : 'IS NOT'} defined" + end + + # Create Array of AllCollectionsHooks::APage from objects + # @param objects [Array] An array of Jekyll::Document, Jekyll::Page or file names + # @param origin [String] Indicates type of objects being passed + def self.apages_from_objects(objects, origin) + pages = [] + objects.each do |object| + page = APage.new(object, origin) + pages << page unless page.data['exclude_from_all'] || page.path == 'redirect.html' + end + pages + end + + # Called by early, high-priority hook. + # Computes site.all_collections, site.all_documents, site.everything, and site.sorted_lru_files + def self.compute(site) + site.class.module_eval { attr_accessor :all_collections, :all_documents, :everything, :sorted_lru_files } + + documents = site.collections + .values + .map { |x| x.class.method_defined?(:docs) ? x.docs : x } + .flatten + .compact + @all_collections = AllCollectionsHooks.apages_from_objects(documents, 'collection') + @all_documents = @all_collections + + AllCollectionsHooks.apages_from_objects(site.pages, 'individual_page') + @everything = @all_documents + + AllCollectionsHooks.apages_from_objects(site.static_files, 'static_file') + @sorted_lru_files = SortedLruFiles.new.add_pages @everything + + site.all_collections = @all_collections + site.all_documents = @all_documents + site.everything = @everything + site.sorted_lru_files = @sorted_lru_files + rescue StandardError => e + JekyllSupport.error_short_trace(::JekyllAllCollections::AllCollectionsHooks.logger, e) + # JekyllSupport.warn_short_trace(::JekyllAllCollections::AllCollectionsHooks.logger, e) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_all_collections/all_collections_tag.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_all_collections/all_collections_tag.rb new file mode 100644 index 00000000..6c8a4080 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_all_collections/all_collections_tag.rb @@ -0,0 +1,157 @@ +# require 'jekyll_draft' +require 'securerandom' + +# @author Copyright 2020 Michael Slinn +# @license SPDX-License-Identifier: Apache-2.0 +module JekyllAllCollections + PLUGIN_NAME = 'all_collections'.freeze unless defined?(PLUGIN_NAME) + CRITERIA = %w[date destination draft label last_modified last_modified_at path relative_path title type url].freeze unless defined?(CRITERIA) + DRAFT_HTML = 'Draft'.freeze unless defined?(DRAFT_HTML) + + class AllCollectionsTag < ::JekyllSupport::JekyllTag + include ::JekyllPluginSupportVersion + + # Method prescribed by JekyllTag. + # @return [String] + def render_impl + parse_arguments # Defines instance variables like @sort_by + sort_lambda = init_sort_by @sort_by, @sort_by_param + @heading = @helper.parameter_specified?('heading') || default_head(@sort_by) + generate_output sort_lambda + rescue StandardError => e + JekyllSupport.error_short_trace @logger, e + # JekyllSupport.warn_short_trace @logger, e + end + + # Descending sort keys reverse the order of comparison + # Example return values: + # "->(a, b) { [a.last_modified] <=> [b.last_modified] }" + # "->(a, b) { [b.last_modified] <=> [a.last_modified] }" (descending) + # "->(a, b) { [a.last_modified, a.date] <=> [b.last_modified, b.date] }" (descending last_modified, ascending date) + # "->(a, b) { [a.last_modified, b.date] <=> [b.last_modified, a.date] }" (ascending last_modified, descending date) + def self.create_lambda_string(criteria) + criteria_lhs_array = [] + criteria_rhs_array = [] + verify_sort_by_type(criteria).each do |c| + descending_sort = c.start_with? '-' + c.delete_prefix! '-' + abort("Error: '#{c}' is not a valid sort field. Valid field names are: #{CRITERIA.join ', '}") \ + unless CRITERIA.include?(c) + criteria_lhs_array << (descending_sort ? "b.#{c}" : "a.#{c}") + criteria_rhs_array << (descending_sort ? "a.#{c}" : "b.#{c}") + end + "->(a, b) { [#{criteria_lhs_array.join(', ')}] <=> [#{criteria_rhs_array.join(', ')}] }" + end + + def self.verify_sort_by_type(sort_by) + case sort_by + when Array + sort_by + when Enumerable + sort_by.to_a + when Date + [sort_by.to_i] + when String + [sort_by] + else + abort "Error: @sort_by was specified as '#{sort_by}'; it must either be a string or an array of strings" + end + end + + private + + def default_head(sort_by) + criteria = (sort_by.map do |x| + reverse = x.start_with? '-' + criterion = x.delete_prefix('-').capitalize + criterion += reverse ? ' (Newest to Oldest)' : ' (Oldest to Newest)' + criterion + end).join(', ') + "All Posts in All Categories Sorted By #{criteria}" + end + + def evaluate(string) + self.eval string, binding, __FILE__, __LINE__ + rescue StandardError => e + warn_short_trace e.red + end + + def last_modified_value(apage) + @logger.debug do + " apage.last_modified='#{apage.last_modified}'; " \ + "apage.last_modified_at='#{apage.last_modified_at}'; " \ + "@date_column='#{@date_column}'" + end + last_modified = if @date_column == 'last_modified' && apage.respond_to?(:last_modified) + apage.last_modified + elsif apage.respond_to? :last_modified_at + apage.last_modified_at + else + apage.date + end + last_modified ||= apage.date || Date.today + last_modified + end + + def generate_output(sort_lambda) + id = @id.to_s.strip.empty? ? '' : " id='#{@id}'" + heading = @heading.strip.to_s.empty? ? '' : "#{@heading}" + data = case @data_selector + when 'all_collections' + @site.all_collections + when 'all_documents' + @site.all_documents + when 'everything' + @site.everything + else + raise AllCollectionsError, "Invalid value for @data_selector (#{data_selector})" + end + collection = data.sort(&sort_lambda) + posts = collection.map do |x| + last_modified = last_modified_value x + date = last_modified.strftime '%Y-%m-%d' + draft = x.draft ? DRAFT_HTML : '' + href = "#{x.title}" + @logger.debug { " date='#{date}' #{x.title}\n" } + " #{date}#{href}#{draft}" + end + <<~END_TEXT + #{heading} +
+ #{posts.join "\n"} +
+ END_TEXT + rescue ArgumentError => e + warn_short_trace e + end + + # See https://stackoverflow.com/a/75377832/553865 + def init_sort_by(sort_by, sort_by_param) + sort_lambda_string = AllCollectionsTag.create_lambda_string sort_by + + @logger.debug do + "#{@page['path']} sort_by_param=#{sort_by_param} " \ + "sort_lambda_string = #{sort_lambda_string}\n" + end + + evaluate sort_lambda_string + end + + def parse_arguments + @data_selector = @helper.parameter_specified?('data_selector') || 'all_collections' + abort "Invalid data_selector #{@data_selector}" unless %w[all_collections all_documents everything].include? @data_selector + + @date_column = @helper.parameter_specified?('date_column') || 'date' + unless %w[date last_modified].include?(@date_column) + raise AllCollectionsError "The date_column attribute must either have value 'date' or 'last_modified', " \ + "but '#{@date_column}' was specified" + end + + @id = @helper.parameter_specified?('id') || SecureRandom.hex(10) + @sort_by_param = @helper.parameter_specified? 'sort_by' + @sort_by = (@sort_by_param&.delete(' ')&.split(',') if @sort_by_param != false) || ['-date'] + end + + ::JekyllSupport::JekyllPluginHelper.register(self, PLUGIN_NAME) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support.rb new file mode 100644 index 00000000..c6561aee --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support.rb @@ -0,0 +1,53 @@ +def require_directory(dir) + Dir[File.join(dir, '*.rb')]&.sort&.each do |file| + require file unless file == __FILE__ + end +end + +require 'colorator' +require 'jekyll' +require 'jekyll_plugin_logger' +require 'pry' +require 'sorted_set' + +# require_directory __dir__ +require_directory "#{__dir__}/util" +require_directory "#{__dir__}/error" +require_directory "#{__dir__}/block" +require_directory "#{__dir__}/generator" +require_directory "#{__dir__}/helper" +require_directory "#{__dir__}/jekyll_plugin_support" +require_directory "#{__dir__}/tag" +require_directory "#{__dir__}/jekyll_all_collections" +require_directory "#{__dir__}/hooks" + +module JekyllSupport + def self.redef_without_warning(const, value) + send(:remove_const, const) if const_defined?(const) + const_set const, value + end +end + +module NoArgParsing + attr_accessor :no_arg_parsing + + @no_arg_parsing = true +end + +module JekyllSupport + class JekyllTag + include JekyllSupportError + end + + class JekyllTagNoArgParsing + include JekyllSupportError + end + + class JekyllBlock + include JekyllSupportError + end + + class JekyllBlockNoArgParsing + include JekyllSupportError + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_class.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_class.rb new file mode 100644 index 00000000..bc00ec56 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_class.rb @@ -0,0 +1,159 @@ +# Monkey patch StandardError so a new method called shorten_backtrace is added. +class StandardError + def shorten_backtrace(backtrace_element_count = 3) + # self.backtrace = backtrace[0..backtrace_element_count].map do |x| + # raise JekyllPluginSupportError, "backtrace contains a #{x.class} with value '#{x}'." unless x.instance_of? String + + # x.gsub(Dir.pwd + '/', './') + # end + end +end + +module JekyllSupport + DISPLAYED_CALLS = 8 unless defined?(DISPLAYED_CALLS) + + def self.error_short_trace(logger, error) + error.set_backtrace error.backtrace[0..DISPLAYED_CALLS] + logger.error { error } + error + end + + # @return a new StandardError subclass containing the shorten_backtrace method + def define_error + Class.new ::JekyllSupport::CustomError + end + module_function :define_error + + JekyllPluginSupportError = define_error unless defined?(JekyllPluginSupportError) + + def self.dump_vars(_logger, liquid_context) + page = liquid_context.registers[:page] + vars = liquid_context.scopes.map do |scope| + scope.map { |name, value| " #{name} = #{value}" }.join("\n") + end.join("\n") + puts <<~END_MSG + #{page['name']} variables after injecting any defined in _config.yml: + #{vars} + END_MSG + end + + # Inject variable definitions from _config.yml into liquid_context + # Modifies liquid_context.scopes in the caller + # (call by object reference, see https://stackoverflow.com/a/1872159/553865) + # @return modified liquid_context + # See README.md#configuration-variable-definitions + # See demo/variables.html + def self.inject_config_vars(liquid_context) + site = liquid_context.registers[:site] + + plugin_variables = site.config['liquid_vars'] + + scope = liquid_context.scopes.last + + env = site.config['env'] + @mode = env&.key?('JEKYLL_ENV') ? env['JEKYLL_ENV'] : 'development' + + # Set default values + plugin_variables&.each do |name, value| + scope[name] = value if value.instance_of? String + end + + # Override with environment-specific values + plugin_variables&.[](@mode)&.each do |name, value| + scope[name] = value if value.instance_of? String + end + + liquid_context + end + + def self.dump_stack(stack, cycles, interval) + stack_depth = stack.length + puts "Stack depth is #{stack_depth}" + num_entries = cycles * interval + return unless stack_depth > interval * 5 + + stack.last(num_entries).each_with_index do |x, i| + msg = " #{i}: #{x}" + (i % interval).zero? ? puts(msg.yellow) : puts(msg) + end + end + + # Modifies a clone of markup_original so variable references are replaced by their values + # @param markup_original to be cloned + # @return modified markup_original + def self.lookup_liquid_variables(logger, liquid_context, markup_original) + markup = markup_original.clone + page = liquid_context.registers[:page] + envs = liquid_context.environments.first + layout = envs[:layout] + + markup = process_layout_variables logger, layout, markup + markup = process_page_variables logger, page, markup + liquid_context.scopes&.each do |scope| + markup = process_included_variables logger, scope, markup + markup = process_liquid_variables logger, scope, markup + end + markup + rescue StandardError => e + logger.error { e.full_message } + end + + def self.process_included_variables(logger, scope, markup) + scope['include']&.each do |name, value| + if value.nil? + value = '' + logger.warn { "include.#{name} is undefined." } + end + markup.gsub!("{{include.#{name}}}", value) + end + markup + rescue StandardError => e + logger.error { e.full_message } + end + + def self.process_layout_variables(logger, layout, markup) + layout&.each do |name, value| + if value.nil? + value = '' + logger.warn { "layout.#{value} is undefined." } + end + markup.gsub!("{{layout.#{name}}}", value.to_s) + end + markup + rescue StandardError => e + logger.error { e.full_message } + end + + # Process assigned, captured and injected variables + def self.process_liquid_variables(logger, scope, markup) + scope&.each do |name, value| + next if name.nil? + + value = '' if value.nil? + markup.gsub!("{{#{name}}}", value&.to_s) + end + markup + rescue StandardError => e + logger.error { e.full_message } + end + + def self.process_page_variables(logger, page, markup) + page&.each_key do |key| + next if %w[content excerpt next previous output].include? key # Skip problem attributes + + markup.gsub!("{{page.#{key}}}", page[key].to_s) + end + markup + rescue StandardError => e + logger.error { e.full_message } + end + + def self.warn_short_trace(logger, error) + remaining = error.backtrace.length - DISPLAYED_CALLS + logger.warn do + error.message + "\n" + + error.backtrace.take(DISPLAYED_CALLS).join("\n") + + "\n...Remaining #{remaining} call sites elided.\n" + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_spec_support.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_spec_support.rb new file mode 100644 index 00000000..0803f817 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/jekyll_plugin_support_spec_support.rb @@ -0,0 +1,34 @@ +Registers = Struct.new(:page, :site) unless defined?(Registers) + +# Mock for Collections +class Collections + def values + [] + end +end + +# Mock for Site +class SiteMock + attr_reader :config + + def collections + Collections.new + end +end + +# Mock for Liquid::ParseContent +class TestParseContext < Liquid::ParseContext + attr_reader :line_number, :registers + + # rubocop:disable Layout/CommentIndentation + # def initialize + # super + # @line_number = 123 + + # @registers = Registers.new( + # { 'path' => 'https://feeds.soundcloud.com/users/soundcloud:users:7143896/sounds.rss' }, + # SiteMock.new + # ) + # end + # rubocop:enable Layout/CommentIndentation +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/version.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/version.rb new file mode 100644 index 00000000..bb07fabf --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/jekyll_plugin_support/version.rb @@ -0,0 +1,3 @@ +module JekyllPluginSupportVersion + VERSION = '3.0.0'.freeze unless defined?(VERSION) +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag.rb new file mode 100644 index 00000000..f9eabc7e --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag.rb @@ -0,0 +1,106 @@ +module JekyllSupport + # Base class for Jekyll tags + class JekyllTag < Liquid::Tag + attr_reader :argument_string, :helper, :line_number, :logger, :page, :site + + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @param tag_name [String] the name of the tag, which we usually know. + # @param argument_string [String] the arguments passed to the tag, as a single string. + # @param parse_context [Liquid::ParseContext] contains the following attributes: + # @depth might have the value 0 + # @error_mode might have the value `:strict` + # @line_number duplicates @ptions[:line_number] + # @locale duplicates @ptions[:locale] + # @options is a hash with the following two keys that holds Liquid options: + # :locale is a Liquid::I18n object, used to display localized error messages on Liquid built-in tags and filters. + # :line_number is the line number containing the plugin invocation. + # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags + # @partial Boolean, unclear what this indicates + # @template_options Replicates @options + # @trim_whitespace might have the value `false` + # @warnings array + # @return [void] + def initialize(tag_name, markup, parse_context) + super + @tag_name = tag_name + raise JekyllPluginSupportError, "markup is a #{markup.class} with value '#{markup}'." unless markup.instance_of? String + + # Vars in plugin parameters cannot be replaced yet + @argument_string = markup.to_s # Lookup variable names with values in markup in render because site and config are not available here + + @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) + @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." } + @helper = JekyllPluginHelper.new(tag_name, @argument_string, @logger, respond_to?(:no_arg_parsing)) + + @error_name = "#{tag_name.camelcase(:upper)}Error" + ::JekyllSupport::CustomError.factory @error_name + end + + # Method prescribed by the Jekyll plugin lifecycle. + def render(liquid_context) + return if @helper.excerpt_caller + + @helper.liquid_context = JekyllSupport.inject_config_vars liquid_context # modifies liquid_context + + @envs = liquid_context.environments.first + @page = liquid_context.registers[:page] + @scopes = liquid_context.scopes + @site = liquid_context.registers[:site] + + @config = @site.config + @tag_config = @config[@tag_name] + @jps = @config['jekyll_plugin_support'] + @pry_on_standard_error = @jps['pry_on_standard_error'] || false if @jps + + set_error_context + + # @envs.keys are :content, :highlighter_prefix, :highlighter_suffix, :jekyll, :layout, :page, :paginator, :site, :theme + @layout = @envs[:layout] + @paginator = @envs[:paginator] + @theme = @envs[:theme] + + env = @config['env'] + @mode = env&.key?('JEKYLL_ENV') ? env['JEKYLL_ENV'] : 'development' + + @argument_string = JekyllSupport.lookup_liquid_variables @logger, @helper.liquid_context, @argument_string.to_s.strip + @helper.reinitialize @argument_string.to_s.strip + + # @argument_string = JekyllSupport.lookup_liquid_variables @logger, liquid_context, @argument_string # Is this redundant? + # @argument_string.strip! # Is this redundant? + # @helper.reinitialize @argument_string # Is this redundant? + + render_impl + rescue StandardError => e + e.shorten_backtrace + file_name = e.backtrace[0]&.split(':')&.first + in_file_name = "in '#{file_name}' " if file_name + of_page = "of '#{@page['path']}'" if @page + @logger.error { "#{e.class} on line #{@line_number} #{of_page} while processing #{tag_name} #{in_file_name}- #{e.message}" } + binding.pry if @pry_on_standard_error # rubocop:disable Lint/Debugger + raise e if @die_on_standard_error + + <<~END_MSG +
+ #{e.class} on line #{@line_number} #{of_page} while processing #{tag_name} #{in_file_name} - #{JekyllPluginHelper.remove_html_tags e.message} +
+ END_MSG + end + + # Jekyll plugins must override this method, not render, so their plugin can be tested more easily + # The following variables are predefined: + # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme + def render_impl + abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not." + end + + def set_error_context + return unless Object.const_defined? @error_name + + error_class = Object.const_get @error_name + error_class.class_variable_set(:@@argument_string, @argument_string) + error_class.class_variable_set(:@@line_number, @line_number) + error_class.class_variable_set(:@@path, @page['path']) + error_class.class_variable_set(:@@tag_name, @tag_name) + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag_noarg.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag_noarg.rb new file mode 100644 index 00000000..773b2ccf --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/tag/jekyll_plugin_support_tag_noarg.rb @@ -0,0 +1,21 @@ +module JekyllSupport + class JekyllTagNoArgParsing < JekyllTag + attr_reader :argument_string, :helper, :line_number, :logger, :page, :site + + def initialize(tag_name, argument_string, parse_context) + class << self + include NoArgParsing + end + + super + @logger.debug { "#{self.class}: respond_to?(:no_arg_parsing) #{respond_to?(:no_arg_parsing) ? 'yes' : 'no'}." } + end + + # Jekyll plugins must override this method, not render, so their plugin can be tested more easily + # The following variables are predefined: + # @argument_string, @config, @envs, @helper, @layout, @logger, @mode, @page, @paginator, @site, @tag_name and @theme + def render_impl + abort "#{self.class}.render_impl for tag #{@tag_name} must be overridden, but it was not." + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/util/mslinn_binary_search.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/util/mslinn_binary_search.rb new file mode 100644 index 00000000..d84d7203 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/util/mslinn_binary_search.rb @@ -0,0 +1,152 @@ +unless defined?(MSlinnBinarySearchError) + class MSlinnBinarySearchError < StandardError + end +end + +# Ruby's binary search is unsuitable because the value to be searched for changes the required ordering for String compares +class MSlinnBinarySearch + attr_reader :accessor_chain, :array # For testing only + + def initialize(accessor_chain) + @array = SortedSet.new # [LruFile] Ordered highest to lowest + @accessor_chain = accessor_chain + end + + # Convert the SortedSet to an Array + def enable_search + @array = @array.to_a + end + + # A match is found when the Array[LruFile] has an href which starts with the given stem + # @param stem [String] + # @return first item from @array.url that matches, or nil if no match + def find(stem) + raise MSlinnBinarySearchError, 'Invalid find because stem to search for is nil.' if stem.nil? + + index = find_index(stem) + return nil if index.nil? + + @array[index] + end + + # @param stem [String] + # @return index of first matching stem, or nil if @array is empty, or 0 if no stem specified + def find_index(stem) + return nil if @array.empty? + return 0 if stem.nil? || stem.empty? + + mets = stem.reverse + return nil if @array[0].url[0...mets.size] > mets # TODO: use chain eval for item + return nil if @array[0].url[0] != mets[0] + + _find_index(mets, 0, @array.length - 1) + end + + # @param stem [String] + # @return [index] of matching values, or [] if @array is empty, or entire array if no stem specified + def find_indices(stem) + return [] if @array.empty? + return @array if stem.nil? || stem.empty? + + first_index = _find_index(stem, 0, @array.length - 1) + last_index = first_index + last_index += 1 while @array[last_index].url.start_with? stem + [first_index..last_index] + end + + # @param item [LruFile] + # @return [int] index of matching LruFile in @array, or nil if not found + def index_of(lru_file) + raise MSlinnBinarySearchError, 'Invalid index_of lru_file (nil).' if lru_file.nil? + + find_index lru_file.url + end + + # @return [LruFile] item at given index in @array + def item_at(index) + if index > @array.length - 1 + raise MSlinnBinarySearchError, + "Invalid item_at index (#{index}) is greater than maximum stem (#{@array.length - 1})." + end + raise MSlinnBinarySearchError, "Invalid item_at index (#{index}) is less than zero." if index.negative? + + @array[index] + end + + # @param lru_file [LruFile] + def insert(lru_file) + raise MSlinnBinarySearchError, 'Invalid insert because new item is nil.' if lru_file.nil? + raise MSlinnBinarySearchError, "Invalid insert because new item has no chain (#{lru_file})" if lru_file.chain.nil? + + @array.add lru_file + end + + # TODO: Cache this method + # @param suffix [String] to use stem search on + # @return nil if @array is empty + # @return the first item in @array if suffix is nil or an empty string + def prefix_search(suffix) + return nil if @array.empty? + return @array[0] if suffix.empty? || suffix.nil? + + low = search_index { |x| x.evaluate_with suffix } + return [] if low.nil? + + high = low + high += 1 while high < @array.length && + @array[high].evaluate_with(suffix) + @array[low..high] + end + + # @param stem [String] + # @return [APage] matching APages, or [] if @array is empty, or entire array if no stem specified + def select_pages(stem) + first_index = find_index stem + return [] if first_index.nil? + + last_index = first_index + while last_index < @array.length - 1 + # LruFile.url is reversed, bug LruFile.page is not + break unless @array[last_index + 1].url.start_with?(stem.reverse) + + last_index += 1 + end + Range.new(first_index, last_index).map { |i| @array[i].page } + end + + private + + # A match is found when the Array[LruFile] has an href which starts with the given stem + # @param stem [String] + # @return [int] first index in @array that matches, or nil if no match + def _find_index(mets, min_index, max_index) + raise MSlinnBinarySearchError, "_find_index min_index(#{min_index})<0" if min_index.negative? + raise MSlinnBinarySearchError, "_find_index min_index(#{min_index})>max_index(#{max_index})" if min_index > max_index + raise MSlinnBinarySearchError, "_find_index max_index(#{max_index})>=@array.length(#{@array.length})" if max_index >= @array.length + + return min_index if (min_index == max_index) && @array[min_index].url.start_with?(mets) + + while min_index < max_index + mid_index = (min_index + max_index) / 2 + mid_value = @array[mid_index].url[0...(mets.size)] # TODO: use chain eval for item + + if mid_value == mets # back up until the first match is found + index = mid_index + loop do + return 0 if index.zero? + + return index unless @array[index - 1].url.start_with?(mets) + + index -= 1 + end + elsif mid_value > mets + max_index = mid_index - 1 + return _find_index(mets, min_index, max_index) + else + min_index = mid_index + 1 + return _find_index(mets, min_index, max_index) + end + end + nil + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/lib/util/send_chain.rb b/bin/gems/jekyll_plugin_support-3.0.0/lib/util/send_chain.rb new file mode 100644 index 00000000..86ac03b8 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/lib/util/send_chain.rb @@ -0,0 +1,56 @@ +# Supports one chain at a time +module SendChain + # See https://stackoverflow.com/a/79333706/553865 + # This method can be called directly if no methods in the chain require arguments + # Does not use any external state + def send_chain(chain) + Array(chain).inject(self) { |o, a| o.send(*a) } + end + + # Saves @chain structure containing :placeholders for arguments to be supplied later + # Call when a different chain with :placeholders is desired + def new_chain(chain) + abort "new_chain error: chain must be an array ('#{chain}' was an #{chain.class.name})" \ + unless chain.instance_of?(Array) + @chain = chain + end + + # Call after new_chain, to evaluate @chain with values + def substitute_and_send_chain_with(values) + send_chain substitute_chain_with values + end + + alias evaluate_with substitute_and_send_chain_with + + # Call this method after calling new_chain to perform error checking and replace :placeholders with values. + # @chain is not modified. + # @return [Array] Modified chain + def substitute_chain_with(values) + values = [values] unless values.instance_of?(Array) + + placeholder_count = @chain.flatten.count { |x| x == :placeholder } + if values.length != placeholder_count + abort "with_values error: number of values (#{values.length}) does not match the number of placeholders (#{placeholder_count})" + end + + eval_chain @chain, values + end + + private + + # Replaces :placeholders with values + # Does not use any external state + # @return modified chain + def eval_chain(chain, values) + chain.map do |c| + case c + when :placeholder + values.shift + when Array + eval_chain c, values + else + c + end + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/all_collections_tag/all_collections_tag_sort_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/all_collections_tag/all_collections_tag_sort_spec.rb new file mode 100644 index 00000000..e2640275 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/all_collections_tag/all_collections_tag_sort_spec.rb @@ -0,0 +1,112 @@ +require 'spec_helper' +require_relative '../../lib/jekyll_all_collections' + +class APageStub + attr_reader :date, :last_modified, :label + + def initialize(date, last_modified, label = '') + @date = Date.parse date + @last_modified = Date.parse last_modified + @label = label + end + + def to_s + @label + end +end + +def show(lambda_string, result, expected) + p "For lambda_string: #{lambda_string}" + p " result: #{result.map(&:label).join(', ')} <==> expected: #{expected.map(&:label).join(', ')}" +end + +# See https://stackoverflow.com/a/75388137/553865 +RSpec.describe(AllCollectionsTag::AllCollectionsTag) do + let(:o1) { APageStub.new('2020-01-01', '2020-01-01', 'a_A') } + let(:o2) { APageStub.new('2021-01-01', '2020-01-01', 'b_A') } + let(:o3) { APageStub.new('2021-01-01', '2023-01-01', 'b_B') } + let(:o4) { APageStub.new('2022-01-01', '2023-01-01', 'c_B') } + let(:objs) { [o1, o2, o3, o4] } + + it 'defines sort_by lambda with last_modified' do + sort_lambda = ->(a, b) { [a.last_modified] <=> [b.last_modified] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o2, o3, o4]) + end + + it 'makes sort_by lambdas from stringified date' do + sort_lambda = eval '->(a, b) { a.last_modified <=> b.last_modified }', + NullBinding.new.min_binding, __FILE__, __LINE__ - 1 + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o2, o3, o4]) + end + + it 'makes sort_by lambdas from stringified array of last_modified' do + sort_lambda = eval '->(a, b) { [a.last_modified] <=> [b.last_modified] }', + NullBinding.new.min_binding, __FILE__, __LINE__ - 1 + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o2, o3, o4]) + end + + it 'makes sort_by lambdas with descending keys from stringified array of last_modified' do + sort_lambda = eval '->(a, b) { [b.last_modified] <=> [a.last_modified] }', + NullBinding.new.min_binding, __FILE__, __LINE__ - 1 + result = objs.sort(&sort_lambda) + expected = [o3, o4, o1, o2] + expect(result).to eq(expected) + end + + it 'create_lambda with 1 date key, descending' do + lambda_string = described_class.create_lambda_string('-last_modified') + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o3, o4, o1, o2] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end + + it 'create_lambda with 1 date key, ascending' do + lambda_string = described_class.create_lambda_string('date') + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o1, o2, o3, o4] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end + + it 'create_lambda with 2 date keys, both ascending' do + lambda_string = described_class.create_lambda_string(%w[date last_modified]) + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o1, o2, o3, o4] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end + + it 'create_lambda with 2 date keys, both descending' do + lambda_string = described_class.create_lambda_string(['-date', '-last_modified']) + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o4, o3, o2, o1] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end + + it 'create_lambda with 2 date keys, first descending and second ascending' do + lambda_string = described_class.create_lambda_string(['-date', 'last_modified']) + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o4, o2, o3, o1] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end + + it 'create_lambda with 2 date keys, first ascending and second descending' do + lambda_string = described_class.create_lambda_string(['date', '-last_modified']) + sort_lambda = described_class.evaluate(lambda_string) + result = objs.sort(&sort_lambda) + expected = [o1, o3, o2, o4] + # show(lambda_string, result, expected) + expect(result).to eq(expected) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/bsearch_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/bsearch_spec.rb new file mode 100644 index 00000000..37883bc2 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/bsearch_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +# Ruby's binary search is unsuitable because ordering requirements are not stable. +# the value to be searched for changes the required ordering + +RSpec.describe(Array) do + before { skip('Never gonna give you up/Never gonna let you down') } + + sorted_ints = [0, 4, 7, 10, 12] + sorted_strings = %w[aaa aab aac bbb bbc bbd ccc ccd cce].sort.reverse + + it 'returns index of first int match' do + actual = sorted_ints.bsearch_index { |x| x >= 4 } + expect(actual).to eq(1) + + actual = sorted_ints.bsearch_index { |x| x >= 6 } + expect(actual).to eq(2) + + actual = sorted_ints.bsearch_index { |x| x >= -1 } + expect(actual).to eq(0) + + actual = sorted_ints.bsearch_index { |x| x >= 100 } + expect(actual).to be_nil + end + + # See https://stackoverflow.com/q/79333097/553865 + it 'returns index of first string match' do + puts(sorted_strings.map { |x| x.start_with? 'a' }) + index = sorted_strings.bsearch_index { |x| x.start_with? 'a' } + expect(sorted_strings[index]).to eq('aac') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'aa' } + expect(sorted_strings[index]).to eq('aac') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'aaa' } + expect(sorted_strings[index]).to eq('aaa') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'b' } + expect(sorted_strings[index]).to eq('bbd') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'bb' } + expect(sorted_strings[index]).to eq('bbd') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'bbc' } + expect(sorted_strings[index]).to eq('bbc') + + index = sorted_strings.bsearch_index { |x| x.start_with? 'cc' } + expect(sorted_strings[index]).to eq('cce') + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/custom_error_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/custom_error_spec.rb new file mode 100644 index 00000000..f0037be9 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/custom_error_spec.rb @@ -0,0 +1,39 @@ +require_relative '../lib/error/jekyll_custom_error' +require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_class' + +class Dummy + def just_for_testing; end +end + +class CustomErrorSpec + tag_name = 'test_tag' + argument_string = 'This is the argument string' + AnError = ::JekyllSupport.define_error + AnError.class_variable_set(:@@tag_name, tag_name) + AnError.class_variable_set(:@@argument_string, argument_string) + + puts "AnError is a #{AnError.class}; StandardError is a #{StandardError.class}" + begin + raise AnError, 'Oops' + rescue AnError => e + puts "Caught AnError: #{e.message}" + rescue ::JekyllSupport::CustomError => e + puts "Caught CustomError: #{e.message}" + end + + RSpec.describe JekyllSupport::JekyllPluginHelper do + it 'generates messages' do + msg = described_class.generate_message(Dummy, tag_name, '0.1.0') + puts msg + expect(msg).to include('Error class: DummyError') + expect(msg).to include('CSS class for error messages: dummy_error') + expect(msg).to include('die_on_dummy_error: false') + end + end + + RSpec.describe ::JekyllSupport::CustomError do + it 'can create custom errors' do + expect { raise AnError, 'Oops' }.to raise_error(AnError) + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/date_sort_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/date_sort_spec.rb new file mode 100644 index 00000000..7cde5245 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/date_sort_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' +require_relative '../lib/jekyll_plugin_support' + +# Verifies how data comparisons work + +class Obj + # `last_modified` is primary sort key + # `date` (when specified) is secondary sort key + attr_reader :date, :last_modified + + def initialize(param1, param2) + @last_modified = Date.parse(param1) + @date = Date.parse(param2) + end +end + +RSpec.describe(Obj) do + let(:o1) { described_class.new('2000-01-01', '2001-01-01') } + let(:o2) { described_class.new('2010-01-01', '2001-01-01') } + let(:o3) { described_class.new('2010-01-01', '2011-01-01') } + let(:o4) { described_class.new('2020-01-01', '2011-01-01') } + let(:objs) { [o1, o2, o3, o4] } + + # See https://ruby-doc.org/3.2.0/Comparable.html + it 'compares one key with ascending dates' do + expect([o1.last_modified] <=> [o2.last_modified]).to eq(-1) + expect([o2.last_modified] <=> [o3.last_modified]).to eq(0) + expect([o3.last_modified] <=> [o4.last_modified]).to eq(-1) + end + + it 'compares two keys with ascending dates' do + expect([o1.last_modified, o1.date] <=> [o2.last_modified, o2.date]).to eq(-1) + expect([o2.last_modified, o2.date] <=> [o3.last_modified, o3.date]).to eq(-1) + expect([o3.last_modified, o3.date] <=> [o4.last_modified, o4.date]).to eq(-1) + end + + it 'compares one key with descending dates' do + expect([o1.last_modified] <=> [o2.last_modified]).to eq(-1) + expect([o2.last_modified] <=> [o3.last_modified]).to eq(0) + end + + it 'compares two keys with descending dates' do + expect([o2.last_modified, o2.date] <=> [o1.last_modified, o1.date]).to eq(1) + expect([o3.last_modified, o3.date] <=> [o2.last_modified, o2.date]).to eq(1) + expect([o4.last_modified, o4.date] <=> [o3.last_modified, o3.date]).to eq(1) + end + + # See https://ruby-doc.org/3.2.0/Enumerable.html#method-i-sort + it 'sort with one key ascending' do + sort_lambda = ->(a, b) { [a.last_modified] <=> [b.last_modified] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o2, o3, o4]) + end + + it 'sort with one key descending' do + sort_lambda = ->(a, b) { [b.last_modified] <=> [a.last_modified] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o4, o2, o3, o1]) + end + + it 'sort with two keys ascending' do + sort_lambda = ->(a, b) { [a.last_modified, a.date] <=> [b.last_modified, b.date] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o2, o3, o4]) + end + + it 'sort with both keys descending' do + sort_lambda = ->(a, b) { [b.last_modified, b.date] <=> [a.last_modified, a.date] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o4, o3, o2, o1]) + end + + it 'sort with last_modified descending and date ascending' do + sort_lambda = ->(a, b) { [b.last_modified, a.date] <=> [a.last_modified, b.date] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o4, o2, o3, o1]) + end + + it 'sort with last_modified ascending and date descending' do + sort_lambda = ->(a, b) { [a.last_modified, b.date] <=> [b.last_modified, a.date] } + result = objs.sort(&sort_lambda) + expect(result).to eq([o1, o3, o2, o4]) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/jekyll_plugin_helper_options_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/jekyll_plugin_helper_options_spec.rb new file mode 100644 index 00000000..8d7f19b0 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/jekyll_plugin_helper_options_spec.rb @@ -0,0 +1,64 @@ +require 'jekyll_plugin_logger' +# require 'rspec/match_ignoring_whitespace' +require_relative '../lib/jekyll_plugin_support' +require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_spec_support' + +class JekyllPluginHelperOptionsTest + RSpec.describe ::JekyllSupport::JekyllPluginHelper do + logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config) + + it 'parses quoted string options' do + helper = described_class.new('my_tag', "colors='blue or green' blah ick", logger, false) + helper.reinitialize helper.markup + expect(helper.keys_values.keys).to eq(%w[colors blah ick]) + + colors = helper.parameter_specified? 'colors' + expect(colors).to eq('blue or green') + + expect(helper.keys_values.keys).to eq(%w[blah ick]) + end + + it 'parses unquoted string options' do + helper = described_class.new('my_tag', 'color=blue blah ick', logger, false) + helper.reinitialize helper.markup + expect(helper.keys_values.keys).to eq(%w[color blah ick]) + + color = helper.parameter_specified? 'color' + expect(color).to eq('blue') + + expect(helper.keys_values.keys).to eq(%w[blah ick]) + end + + it 'parses quoted booleans' do + helper = described_class.new('my_tag', "bool1='true' bool2='false' blah ick", logger, false) + helper.reinitialize helper.markup + expect(helper.keys_values.keys).to eq(%w[bool1 bool2 blah ick]) + + bool1 = helper.parameter_specified? 'bool1' + expect(bool1).to be true + + bool2 = helper.parameter_specified? 'bool2' + expect(bool2).to be false + + expect(helper.keys_values.keys).to eq(%w[blah ick]) + + expect(helper.remaining_markup).to eq('blah ick') + end + + it 'parses unquoted booleans' do + helper = described_class.new('my_tag', 'bool1=true bool2=false blah ick', logger, false) + helper.reinitialize helper.markup + expect(helper.keys_values.keys).to eq(%w[bool1 bool2 blah ick]) + + bool1 = helper.parameter_specified? 'bool1' + expect(bool1).to be true + + bool2 = helper.parameter_specified? 'bool2' + expect(bool2).to be false + + expect(helper.keys_values.keys).to eq(%w[blah ick]) + + expect(helper.remaining_markup).to eq('blah ick') + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/liquid_variable_parsing_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/liquid_variable_parsing_spec.rb new file mode 100644 index 00000000..646278a1 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/liquid_variable_parsing_spec.rb @@ -0,0 +1,34 @@ +require 'jekyll_plugin_logger' +# require 'rspec/match_ignoring_whitespace' +require_relative '../lib/jekyll_plugin_support' +require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_spec_support' + +class LiquidVariableParsing + # @return copy of str with references to defined variables replaced by the values of the variables + def self.variable_replace(str, scopes) + result = str.clone + match_data_list = str.to_enum(:scan, /{{[a-z_][a-zA-Z_0-9]*}}/).map { Regexp.last_match }.reverse + match_data_list&.each do |md| + from = md.begin(0) + to = md.end(0) - 1 + ref = str[from..to] + name = ref[2..-3] + scopes&.each do |scope| + value = scope.key?(name) ? scope[name] : ref + # puts "str=#{str}; from=#{from}; to=#{to}; name=#{name} value=#{value}" + result[from..to] = value + end + end + result + end + + RSpec.describe ::JekyllSupport::JekyllPluginHelper do + it 'substitutes variable references for values without recursion' do + scopes = [{ 'a' => '{{', 'b' => 'asdf', 'c' => '}}' }] + str = '{{a}}{{b}}{{c}} This should be unchanged: {{d}}' + new_str = LiquidVariableParsing.variable_replace(str, scopes) + expect(str).to start_with('{{a}}') + expect(new_str).to eq('{{asdf}} This should be unchanged: {{d}}') + end + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/mslinn_binary_search_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/mslinn_binary_search_spec.rb new file mode 100644 index 00000000..dbfeee06 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/mslinn_binary_search_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' +require_relative '../lib/hooks/all_files' + +def build_msbs(sorted_strings) + sorted_strings.each do |string| + $msbs.insert LruFile.new(string.reverse, "Page #{string}") # { |x| x.url.start_with? string } + end + $msbs.enable_search +end + +RSpec.describe(MSlinnBinarySearch) do + $msbs = described_class.new [:url, %i[start_with? placeholder]] + build_msbs %w[aaa.html baa.html caa.html bbb.html cbb.html dbb.html ccc.html ccd.html cce.html] + + it 'handles an empty search string by returning the index of the first item (0)' do + index = $msbs.find_index '' # { |x| x.url.start_with? '' } + expect(index).to be_zero + end + + it 'returns the index of the first partial match' do + index = $msbs.find_index 'a.html' # { |x| x.url.start_with? 'a.html' } + expect(index).to eq(0) + + index = $msbs.find_index 'baa.html' # { |x| x.url.start_with? 'baa.html' } + expect(index).to eq(1) + + index = $msbs.find_index 'c.html' # { |x| x.url.start_with? 'c.html' } + expect(index).to eq(6) + + index = $msbs.find_index 'cce.html' # { |x| x.url.start_with? 'cce.html' } + expect(index).to eq(8) + end + + it 'returns the item of the first match' do + item = $msbs.find 'a.html' # { |x| x.url.start_with? 'a.html' } + expect(item.url.reverse).to eq('aaa.html') + + item = $msbs.find 'baa.html' # { |x| x.url.start_with? 'baa.html' } + expect(item.url.reverse).to eq('baa.html') + + item = $msbs.find 'c.html' # { |x| x.url.start_with? 'c.html' } + expect(item.url.reverse).to eq('ccc.html') + + item = $msbs.find 'cce.html' # { |x| x.url.start_with? 'cce.html' } + expect(item.url.reverse).to eq('cce.html') + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/send_chain_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/send_chain_spec.rb new file mode 100644 index 00000000..375049ec --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/send_chain_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' +require_relative '../lib/util/send_chain' + +unless defined? LruFile + LruFile = Struct.new(:url, :page) do + include SendChain + end +end + +RSpec.describe(LruFile) do + lru_file = described_class.new 'abc', 'def' + + it 'can perform a simple call if no arguments are required' do + # Equivalent to: lru_file.url.reverse + actual = lru_file.send_chain %i[url reverse] + expect(actual).to eq('cba') + end + + it 'can accept a scalar argument in stages' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + # Equivalent to: lru_file.url.end_with?('bc') + substituted_chain = lru_file.substitute_chain_with 'bc' + actual = lru_file.send_chain substituted_chain + expect(actual).to be true + end + + it 'can accept a vector argument in stages' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + # Next 2 lines are equivalent to: lru_file.url.end_with?('bc') + substituted_chain = lru_file.substitute_chain_with ['bc'] + actual = lru_file.send_chain substituted_chain + expect(actual).to be true + end + + it 'can accept a scalar argument in one stage' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + # Equivalent to: lru_file.url.end_with?('bc') + actual = lru_file.substitute_and_send_chain_with 'bc' + expect(actual).to be true + end + + it 'can accept an array argument in one stage' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + # Equivalent to: lru_file.url.end_with?('bc') + actual = lru_file.substitute_and_send_chain_with ['bc'] + expect(actual).to be true + end + + it 'can use the evaluate_with alias' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + # Equivalent to: lru_file.url.end_with?('bc') + actual = lru_file.evaluate_with ['bc'] + expect(actual).to be true + end + + it 'can reuse the chain with different values' do + lru_file.new_chain [:url, %i[end_with? placeholder]] + + # Equivalent to: lru_file.url.end_with?('bc') + actual = lru_file.substitute_and_send_chain_with 'bc' + expect(actual).to be true + + # Equivalent to: lru_file.url.end_with?('abc') + substituted_chain = lru_file.substitute_chain_with ['abc'] + actual = lru_file.send_chain substituted_chain + expect(actual).to be true + + # Equivalent to: lru_file.url.end_with?('de') + actual = lru_file.substitute_and_send_chain_with 'de' + expect(actual).to be false + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/send_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/send_spec.rb new file mode 100644 index 00000000..7413b44f --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/send_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +# Exploring how to set date attributes in an object + +class Obj + # `last_modified` is primary sort key + # `date` (when specified) is secondary sort key + attr_reader :date, :last_modified + + def initialize(param1, param2) + @last_modified = Date.parse(param1) + @date = Date.parse(param2) + end +end + +RSpec.describe(Obj) do + let(:obj) { described_class.new('2000-01-01', '2001-01-01') } + + it 'can send date' do + date = obj.send :date + expect(obj.date).to eq(date) + end + + it 'can send last_modified' do + last_modified = obj.send :last_modified + expect(obj.last_modified).to eq(last_modified) + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/sorted_lru_files_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/sorted_lru_files_spec.rb new file mode 100644 index 00000000..f5fee1c2 --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/sorted_lru_files_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' +require_relative '../lib/hooks/all_files' + +RSpec.describe(SortedLruFiles) do + expected1 = 'first-page.html' + expected2 = 'second-page.html' + expected3 = 'third-page.html' + + it 'can read back an inserted item' do + sorted_files = described_class.new + sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1 + sorted_files.enable_search + + actual = sorted_files.select expected1 + expect(actual.length).to eq(1) + expect(actual.first&.reverse&.start_with?(expected1.reverse)).to be true + + actual = sorted_files.select expected1[5..] + expect(actual.length).to eq(1) + expect(actual.first&.reverse&.start_with?(expected1[5..].reverse)).to be true + + actual = sorted_files.select 'should_not_match' + expect(actual).to be_empty + end + + it 'works with 2 items and one match' do + sorted_files = described_class.new + sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1 + sorted_files.insert(expected2, "https://mslinn.com/#{expected2}") + sorted_files.enable_search + + expect(sorted_files.msbs.array[0].url).to be <= sorted_files.msbs.array[1].url + + actual = sorted_files.select expected1 + expect(actual.length).to eq(1) + expect(actual.first&.end_with?(expected1)).to be true + + actual = sorted_files.select expected2 + expect(actual.length).to eq(1) + expect(actual.first&.end_with?(expected2)).to be true + end + + it 'handles multiple matches' do + sorted_files = described_class.new + sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1 + sorted_files.insert(expected2, "https://mslinn.com/#{expected2}") + sorted_files.enable_search + + expected = '.html' + actual = sorted_files.select expected + expect(actual.length).to eq(2) + expect(actual.first&.end_with?(expected)).to be true + end + + it 'works with 3 items' do + sorted_files = described_class.new + sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1 + sorted_files.insert(expected2, "https://mslinn.com/#{expected2}") + sorted_files.insert(expected3, "https://mslinn.com/#{expected3}") + sorted_files.enable_search + + expect(sorted_files.msbs.array[0].url).to be <= sorted_files.msbs.array[1].url + expect(sorted_files.msbs.array[1].url).to be <= sorted_files.msbs.array[2].url + + actual = sorted_files.select expected1 + expect(actual.length).to eq(1) + expect(actual.first&.end_with?(expected1)).to be true + + actual = sorted_files.select expected2 + expect(actual.length).to eq(1) + expect(actual.first&.end_with?(expected2)).to be true + + actual = sorted_files.select expected3 + expect(actual.length).to eq(1) + expect(actual.first&.end_with?(expected3)).to be true + + expected = '.html' + actual = sorted_files.select expected + expect(actual.length).to eq(3) + expect(actual.first&.end_with?(expected)).to be true + end +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/spec_helper.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/spec_helper.rb new file mode 100644 index 00000000..8e132a3c --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/spec_helper.rb @@ -0,0 +1,12 @@ +require 'jekyll' +require_relative '../lib/jekyll_plugin_support' + +Jekyll.logger.log_level = :info + +RSpec.configure do |config| + config.filter_run_when_matching focus: true + # config.order = 'random' + + # See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures + config.example_status_persistence_file_path = 'spec/status_persistence.txt' +end diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/status_persistence.txt b/bin/gems/jekyll_plugin_support-3.0.0/spec/status_persistence.txt new file mode 100644 index 00000000..662699bd --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/status_persistence.txt @@ -0,0 +1,3 @@ +example_id | status | run_time | +----------------------------------------------- | ------ | --------------- | +./spec/jekyll_block_plugin_support_spec.rb[1:1] | passed | 0.00062 seconds | diff --git a/bin/gems/jekyll_plugin_support-3.0.0/spec/testable_spec.rb b/bin/gems/jekyll_plugin_support-3.0.0/spec/testable_spec.rb new file mode 100644 index 00000000..64e0aa7f --- /dev/null +++ b/bin/gems/jekyll_plugin_support-3.0.0/spec/testable_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +# Exploring how to invoke methods from classes and modules +# See https://mslinn.com/jekyll/10700-designing-for-testability.html + +module TestModule + def a_method + 'a_method says Hi!' + end +end + +class TestClass + extend TestModule # Defines class methods + + def initialize(param1, param2) + super() + @param1 = param1 + @param2 = param2 + end +end + +RSpec.describe(TestModule) do + extend described_class + + it 'Invokes a_method from module' do + result = self.class.a_method + expect(result).to eq('a_method says Hi!') + end +end + +RSpec.describe(TestClass) do + let(:o1) { described_class.new('value1', 'value2') } + + it 'Invokes a_method from class' do + result = o1.class.a_method + expect(result).to eq('a_method says Hi!') + end +end diff --git a/bin/gems/json-2.10.2/BSDL b/bin/gems/json-2.10.2/BSDL new file mode 100644 index 00000000..66d93598 --- /dev/null +++ b/bin/gems/json-2.10.2/BSDL @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/bin/gems/json-2.10.2/CHANGES.md b/bin/gems/json-2.10.2/CHANGES.md new file mode 100644 index 00000000..69762423 --- /dev/null +++ b/bin/gems/json-2.10.2/CHANGES.md @@ -0,0 +1,590 @@ +# Changes + +### 2025-03-12 (2.10.2) + +* Fix a potential crash in the C extension parser. +* Raise a ParserError on all incomplete unicode escape sequence. This was the behavior until `2.10.0` unadvertently changed it. +* Ensure document snippets that are included in parser errors don't include truncated multibyte characters. + +### 2025-02-10 (2.10.1) + +* Fix a compatibility issue with `MultiJson.dump(obj, pretty: true)`: `no implicit conversion of false into Proc (TypeError)`. + +### 2025-02-10 (2.10.0) + +* `strict: true` now accept symbols as values. Previously they'd only be accepted as hash keys. +* The C extension Parser has been entirely reimplemented from scratch. +* Introduced `JSON::Coder` as a new API allowing to customize how non native types are serialized in a non-global way. +* Introduced `JSON::Fragment` to allow assembling cached fragments in a safe way. +* The Java implementation of the generator received many optimizations. + +### 2024-12-18 (2.9.1) + +* Fix support for Solaris 10. + +### 2024-12-03 (2.9.0) + +* Fix C implementation of `script_safe` escaping to not confuse some other 3 wide characters with `\u2028` and `\u2029`. + e.g. `JSON.generate(["倩", "瀨"], script_safe: true)` would generate the wrong JSON. +* `JSON.dump(object, some_io)` now write into the IO in chunks while previously it would buffer the entire JSON before writing. +* `JSON::GeneratorError` now has a `#invalid_object` attribute, making it easier to understand why an object tree cannot be serialized. +* Numerous improvements to the JRuby extension. + +### 2024-11-14 (2.8.2) + +* `JSON.load_file` explictly read the file as UTF-8. + +### 2024-11-06 (2.8.1) + +* Fix the java packages to include the extension. + +### 2024-11-06 (2.8.0) + +* Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled. + * Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`. +* Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`. +* Bump required Ruby version to 2.7. +* Add support for optionally parsing trailing commas, via `allow_trailing_comma: true`, which in cunjunction with the + pre-existing support for comments, make it suitable to parse `jsonc` documents. +* Many performance improvements to `JSON.parse` and `JSON.load`, up to `1.7x` faster on real world documents. +* Some minor performance improvements to `JSON.dump` and `JSON.generate`. +* `JSON.pretty_generate` no longer include newline inside empty object and arrays. + +### 2024-11-04 (2.7.6) + +* Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them. + +### 2024-10-25 (2.7.5) + +* Fix a memory leak when `#to_json` methods raise an exception. +* Gracefully handle formatting configs being set to `nil` instead of `""`. +* Workaround another issue caused by conflicting versions of both `json_pure` and `json` being loaded. + +### 2024-10-25 (2.7.4) + +* Workaround a bug in 3.4.8 and older https://github.com/rubygems/rubygems/pull/6490. + This bug would cause some gems with native extension to fail during compilation. +* Workaround different versions of `json` and `json_pure` being loaded (not officially supported). +* Make `json_pure` Ractor compatible. + +### 2024-10-24 (2.7.3) + +* Numerous performance optimizations in `JSON.generate` and `JSON.dump` (up to 2 times faster). +* Limit the size of ParserError exception messages, only include up to 32 bytes of the unparseable source. +* Fix json-pure's `Object#to_json` to accept non state arguments +* Fix multiline comment support in `json-pure`. +* Fix `JSON.parse` to no longer mutate the argument encoding when passed an ASCII-8BIT string. +* Fix `String#to_json` to raise on invalid encoding in `json-pure`. +* Delete code that was based on CVTUTF. +* Use the pure-Ruby generator on TruffleRuby. +* Fix `strict` mode in `json-pure` to not break on Integer. + +### 2024-04-04 (2.7.2) + +* Use rb_sym2str instead of SYM2ID #561 +* Fix memory leak when exception is raised during JSON generation #574 +* Remove references to "19" methods in JRuby #576 +* Make OpenStruct support as optional by @hsbt in #565 +* Autoload JSON::GenericObject to avoid require ostruct warning in Ruby 3.4 #577 +* Warn to install ostruct if json couldn't load it by @hsbt #578 + +### 2023-12-05 (2.7.1) + +* JSON.dump: handle unenclosed hashes regression #554 +* Overload kwargs in JSON.dump #556 +* [DOC] RDoc for additions #557 +* Fix JSON.dump overload combination #558 + +### 2023-12-01 (2.7.0) + +* Add a strict option to Generator #519 +* `escape_slash` option was renamed as `script_safe` and now also escape U+2028 and U+2029. `escape_slash` is now an alias of `script_safe` #525 +* Remove unnecessary initialization of create_id in JSON.parse() #454 +* Improvements to Hash#to_json in pure implementation generator #203 +* Use ruby_xfree to free buffers #518 +* Fix "unexpected token" offset for Infinity #507 +* Avoid using deprecated BigDecimal.new on JRuby #546 +* Removed code for Ruby 1.8 #540 +* Rename JSON::ParseError to JSON:ParserError #530 +* Call super in included hook #486 +* JRuby requires a minimum of Java 8 #516 +* Always indent even if empty #517 + +### 2022-11-30 (2.6.3) + +* bugfix json/pure mixing escaped with literal unicode raises Encoding::CompatibilityError #483 +* Stop including the parser source __LINE__ in exceptions #470 + +### 2022-11-17 (2.6.2) + +* Remove unknown keyword arg from DateTime.parse #488 +* Ignore java artifacts by @hsbt #489 +* Fix parser bug for empty string allocation #496 + +### 2021-10-24 (2.6.1) + +* Restore version.rb with 2.6.1 + +### 2021-10-14 (2.6.0) + +* Use `rb_enc_interned_str` if available to reduce allocations in `freeze: true` mode. #451. +* Bump required_ruby_version to 2.3. +* Fix compatibility with `GC.compact`. +* Fix some compilation warnings. #469 + +## 2020-12-22 (2.5.1) + +* Restore the compatibility for constants of JSON class. + +## 2020-12-22 (2.5.0) + +* Ready to Ractor-safe at Ruby 3.0. + +## 2020-12-17 (2.4.1) + +* Restore version.rb with 2.4.1 + +## 2020-12-15 (2.4.0) + +* Implement a freeze: parser option #447 +* Fix an issue with generate_pretty and empty objects in the Ruby and Java implementations #449 +* Fix JSON.load_file doc #448 +* Fix pure parser with unclosed arrays / objects #425 +* bundle the LICENSE file in the gem #444 +* Add an option to escape forward slash character #405 +* RDoc for JSON #439 #446 #442 #434 #433 #430 + +## 2020-06-30 (2.3.1) + +* Spelling and grammar fixes for comments. Pull request #191 by Josh + Kline. +* Enhance generic JSON and #generate docs. Pull request #347 by Victor + Shepelev. +* Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev. +* Baseline changes to help (JRuby) development. Pull request #371 by Karol + Bucek. +* Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI. +* Remove invalid JSON.generate description from JSON module rdoc. Pull + request #384 by Jeremy Evans. +* Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze. +* Rdoc enhancements. Pull request #413 by Burdette Lamar. +* Fixtures/ are not being tested... Pull request #416 by Marc-André + Lafortune. +* Use frozen string for hash key. Pull request #420 by Marc-André + Lafortune. +* Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette + Lamar. +* Small typo fix. Pull request #423 by Marc-André Lafortune. + +## 2019-12-11 (2.3.0) + * Fix default of `create_additions` to always be `false` for `JSON(user_input)` + and `JSON.parse(user_input, nil)`. + Note that `JSON.load` remains with default `true` and is meant for internal + serialization of trusted data. [CVE-2020-10663] + * Fix passing args all #to_json in json/add/*. + * Fix encoding issues + * Fix issues of keyword vs positional parameter + * Fix JSON::Parser against bigdecimal updates + * Bug fixes to JRuby port + +## 2019-02-21 (2.2.0) + * Adds support for 2.6 BigDecimal and ruby standard library Set datetype. + +## 2017-04-18 (2.1.0) + * Allow passing of `decimal_class` option to specify a class as which to parse + JSON float numbers. +## 2017-03-23 (2.0.4) + * Raise exception for incomplete unicode surrogates/character escape + sequences. This problem was reported by Daniel Gollahon (dgollahon). + * Fix arbitrary heap exposure problem. This problem was reported by Ahmad + Sherif (ahmadsherif). + +## 2017-01-12 (2.0.3) + * Set `required_ruby_version` to 1.9 + * Some small fixes + +## 2016-07-26 (2.0.2) + * Specify `required_ruby_version` for json\_pure. + * Fix issue #295 failure when parsing frozen strings. + +## 2016-07-01 (2.0.1) + * Fix problem when requiring json\_pure and Parser constant was defined top + level. + * Add `RB_GC_GUARD` to avoid possible GC problem via Pete Johns. + * Store `current_nesting` on stack by Aaron Patterson. + +## 2015-09-11 (2.0.0) + * Now complies to newest JSON RFC 7159. + * Implements compatibility to ruby 2.4 integer unification. + * Drops support for old rubies whose life has ended, that is rubies < 2.0. + Also see https://www.ruby-lang.org/en/news/2014/07/01/eol-for-1-8-7-and-1-9-2/ + * There were still some mentions of dual GPL licensing in the source, but JSON + has just the Ruby license that itself includes an explicit dual-licensing + clause that allows covered software to be distributed under the terms of + the Simplified BSD License instead for all ruby versions >= 1.9.3. This is + however a GPL compatible license according to the Free Software Foundation. + I changed these mentions to be consistent with the Ruby license setting in + the gemspec files which were already correct now. + +## 2017-01-13 (1.8.6) + * Be compatible with ancient ruby 1.8 (maybe?) + +## 2015-09-11 (1.8.5) + * Be compatible with ruby 2.4.0 + * There were still some mentions of dual GPL licensing in the source, but JSON + has just the Ruby license that itself includes an explicit dual-licensing + clause that allows covered software to be distributed under the terms of + the Simplified BSD License instead for all ruby versions >= 1.9.3. This is + however a GPL compatible license according to the Free Software Foundation. + I changed these mentions to be consistent with the Ruby license setting in + the gemspec files which were already correct now. + +## 2015-06-01 (1.8.3) + * Fix potential memory leak, thx to nobu. + +## 2015-01-08 (1.8.2) + * Some performance improvements by Vipul A M . + * Fix by Jason R. Clark to avoid mutation of + `JSON.dump_default_options`. + * More tests by Michael Mac-Vicar and fixing + `space_before` accessor in generator. + * Performance on Jruby improved by Ben Browning . + * Some fixes to be compatible with the new Ruby 2.2 by Zachary Scott + and SHIBATA Hiroshi . + +## 2013-05-13 (1.8.1) + * Remove Rubinius exception since transcoding should be working now. + +## 2013-05-13 (1.8.0) + * Fix https://github.com/ruby/json/issues/162 reported by Marc-Andre + Lafortune . Thanks! + * Applied patches by Yui NARUSE to suppress warning with + -Wchar-subscripts and better validate UTF-8 strings. + * Applied patch by ginriki@github to remove unnecessary if. + * Add load/dump interface to `JSON::GenericObject` to make + serialize :some_attribute, `JSON::GenericObject` + work in Rails active models for convenient `SomeModel#some_attribute.foo.bar` + access to serialised JSON data. + +## 2013-02-04 (1.7.7) + * Security fix for JSON create_additions default value and + `JSON::GenericObject`. It should not be possible to create additions unless + explicitly requested by setting the create_additions argument to true or + using the JSON.load/dump interface. If `JSON::GenericObject` is supposed to + be automatically deserialised, this has to be explicitly enabled by + setting + JSON::GenericObject.json_creatable = true + as well. + * Remove useless assert in fbuffer implementation. + * Apply patch attached to https://github.com/ruby/json/issues#issue/155 + provided by John Shahid , Thx! + * Add license information to rubygems spec data, reported by Jordi Massaguer Pla . + * Improve documentation, thx to Zachary Scott . + +## 2012-11-29 (1.7.6) + * Add `GeneratorState#merge` alias for JRuby, fix state accessor methods. Thx to + jvshahid@github. + * Increase hash likeness of state objects. + +## 2012-08-17 (1.7.5) + * Fix compilation of extension on older rubies. + +## 2012-07-26 (1.7.4) + * Fix compilation problem on AIX, see https://github.com/ruby/json/issues/142 + +## 2012-05-12 (1.7.3) + * Work around Rubinius encoding issues using iconv for conversion instead. + +## 2012-05-11 (1.7.2) + * Fix some encoding issues, that cause problems for the pure and the + extension variant in jruby 1.9 mode. + +## 2012-04-28 (1.7.1) + * Some small fixes for building + +## 2012-04-28 (1.7.0) + * Add `JSON::GenericObject` for method access to objects transmitted via JSON. + +## 2012-04-27 (1.6.7) + * Fix possible crash when trying to parse nil value. + +## 2012-02-11 (1.6.6) + * Propagate src encoding to values made from it (fixes 1.9 mode converting + everything to ascii-8bit; harmless for 1.8 mode too) (Thomas E. Enebo + ), should fix + https://github.com/ruby/json/issues#issue/119. + * Fix https://github.com/ruby/json/issues#issue/124 Thx to Jason Hutchens. + * Fix https://github.com/ruby/json/issues#issue/117 + +## 2012-01-15 (1.6.5) + * Vit Ondruch reported a bug that shows up when using + optimisation under GCC 4.7. Thx to him, Bohuslav Kabrda + and Yui NARUSE for debugging and + developing a patch fix. + +## 2011-12-24 (1.6.4) + * Patches that improve speed on JRuby contributed by Charles Oliver Nutter + . + * Support `object_class`/`array_class` with duck typed hash/array. + +## 2011-12-01 (1.6.3) + * Let `JSON.load('')` return nil as well to make mysql text columns (default to + `''`) work better for serialization. + +## 2011-11-21 (1.6.2) + * Add support for OpenStruct and BigDecimal. + * Fix bug when parsing nil in `quirks_mode`. + * Make JSON.dump and JSON.load methods better cooperate with Rails' serialize + method. Just use: + serialize :value, JSON + * Fix bug with time serialization concerning nanoseconds. Thanks for the + patch go to Josh Partlow (jpartlow@github). + * Improve parsing speed for JSON numbers (integers and floats) in a similar way to + what Evan Phoenix suggested in: + https://github.com/ruby/json/pull/103 + +## 2011-09-18 (1.6.1) + * Using -target 1.5 to force Java bits to compile with 1.5. + +## 2011-09-12 (1.6.0) + * Extract utilities (prettifier and GUI-editor) in its own gem json-utils. + * Split json/add/core into different files for classes to be serialised. + +## 2011-08-31 (1.5.4) + * Fix memory leak when used from multiple JRuby. (Patch by + jfirebaugh@github). + * Apply patch by Eric Wong that fixes garbage collection problem + reported in https://github.com/ruby/json/issues/46. + * Add :quirks_mode option to parser and generator. + * Add support for Rational and Complex number additions via json/add/complex + and json/add/rational requires. + +## 2011-06-20 (1.5.3) + * Alias State#configure method as State#merge to increase duck type synonymy with Hash. + * Add `as_json` methods in json/add/core, so rails can create its json objects the new way. + +## 2011-05-11 (1.5.2) + * Apply documentation patch by Cory Monty . + * Add gemspecs for json and json\_pure. + * Fix bug in jruby pretty printing. + * Fix bug in `object_class` and `array_class` when inheriting from Hash or + Array. + +## 2011-01-24 (1.5.1) + * Made rake-compiler build a fat binary gem. This should fix issue + https://github.com/ruby/json/issues#issue/54. + +## 2011-01-22 (1.5.0) + * Included Java source codes for the Jruby extension made by Daniel Luz + . + * Output full exception message of `deep_const_get` to aid debugging. + * Fixed an issue with ruby 1.9 `Module#const_defined?` method, that was + reported by Riley Goodside. + +## 2010-08-09 (1.4.6) + * Fixed oversight reported in http://github.com/ruby/json/issues/closed#issue/23, + always create a new object from the state prototype. + * Made pure and ext api more similar again. + +## 2010-08-07 (1.4.5) + * Manage data structure nesting depth in state object during generation. This + should reduce problems with `to_json` method definіtions that only have one + argument. + * Some fixes in the state objects and additional tests. +## 2010-08-06 (1.4.4) + * Fixes build problem for rubinius under OS X, http://github.com/ruby/json/issues/closed#issue/25 + * Fixes crashes described in http://github.com/ruby/json/issues/closed#issue/21 and + http://github.com/ruby/json/issues/closed#issue/23 +## 2010-05-05 (1.4.3) + * Fixed some test assertions, from Ruby r27587 and r27590, patch by nobu. + * Fixed issue http://github.com/ruby/json/issues/#issue/20 reported by + electronicwhisper@github. Thx! + +## 2010-04-26 (1.4.2) + * Applied patch from naruse Yui NARUSE to make building with + Microsoft Visual C possible again. + * Applied patch from devrandom in order to allow building of + json_pure if extensiontask is not present. + * Thanks to Dustin Schneider , who reported a memory + leak, which is fixed in this release. + * Applied 993f261ccb8f911d2ae57e9db48ec7acd0187283 patch from josh@github. + +## 2010-04-25 (1.4.1) + * Fix for a bug reported by Dan DeLeo , caused by T_FIXNUM + being different on 32bit/64bit architectures. + +## 2010-04-23 (1.4.0) + * Major speed improvements and building with simplified + directory/file-structure. + * Extension should at least be compatible with MRI, YARV and Rubinius. + +## 2010-04-07 (1.2.4) + * Trigger const_missing callback to make Rails' dynamic class loading work. + +## 2010-03-11 (1.2.3) + * Added a `State#[]` method which returns an attribute's value in order to + increase duck type compatibility to Hash. + +## 2010-02-27 (1.2.2) + * Made some changes to make the building of the parser/generator compatible + to Rubinius. + +## 2009-11-25 (1.2.1) + * Added `:symbolize_names` option to Parser, which returns symbols instead of + strings in object names/keys. + +## 2009-10-01 (1.2.0) + * `fast_generate` now raises an exception for nan and infinite floats. + * On Ruby 1.8 json supports parsing of UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, + and UTF-32LE JSON documents now. Under Ruby 1.9 the M17n conversion + functions are used to convert from all supported encodings. ASCII-8BIT + encoded strings are handled like all strings under Ruby 1.8 were. + * Better documentation + +## 2009-08-23 (1.1.9) + * Added forgotten main doc file `extra_rdoc_files`. + +## 2009-08-23 (1.1.8) + * Applied a patch by OZAWA Sakuro to make json/pure + work in environments that don't provide iconv. + * Applied patch by okkez_ in order to fix Ruby Bug #1768: + http://redmine.ruby-lang.org/issues/show/1768. + * Finally got around to avoid the rather paranoid escaping of ?/ characters + in the generator's output. The parsers aren't affected by this change. + Thanks to Rich Apodaca for the suggestion. + +## 2009-06-29 (1.1.7) + * Security Fix for JSON::Pure::Parser. A specially designed string could + cause catastrophic backtracking in one of the parser's regular expressions + in earlier 1.1.x versions. JSON::Ext::Parser isn't affected by this issue. + Thanks to Bartosz Blimke for reporting this + problem. + * This release also uses a less strict ruby version requirement for the + creation of the mswin32 native gem. + +## 2009-05-10 (1.1.6) + * No changes. І tested native linux gems in the last release and they don't + play well with different ruby versions other than the one the gem was built + with. This release is just to bump the version number in order to skip the + native gem on rubyforge. + +## 2009-05-10 (1.1.5) + * Started to build gems with rake-compiler gem. + * Applied patch object/array class patch from Brian Candler + and fixes. + +## 2009-04-01 (1.1.4) + * Fixed a bug in the creation of serialized generic rails objects reported by + Friedrich Graeter . + * Deleted tests/runner.rb, we're using testrb instead. + * Editor supports Infinity in numbers now. + * Made some changes in order to get the library to compile/run under Ruby + 1.9. + * Improved speed of the code path for the fast_generate method in the pure + variant. + +## 2008-07-10 (1.1.3) + * Wesley Beary reported a bug in json/add/core's DateTime + handling: If the nominator and denominator of the offset were divisible by + each other Ruby's Rational#to_s returns them as an integer not a fraction + with '/'. This caused a ZeroDivisionError during parsing. + * Use Date#start and DateTime#start instead of sg method, while + remaining backwards compatible. + * Supports ragel >= 6.0 now. + * Corrected some tests. + * Some minor changes. + +## 2007-11-27 (1.1.2) + * Remember default dir (last used directory) in editor. + * JSON::Editor.edit method added, the editor can now receive json texts from + the clipboard via C-v. + * Load json texts from an URL pasted via middle button press. + * Added :create_additions option to Parser. This makes it possible to disable + the creation of additions by force, in order to treat json texts as data + while having additions loaded. + * Jacob Maine reported, that JSON(:foo) outputs a JSON + object if the rails addition is enabled, which is wrong. It now outputs a + JSON string "foo" instead, like suggested by Jacob Maine. + * Discovered a bug in the Ruby Bugs Tracker on rubyforge, that was reported + by John Evans lgastako@gmail.com. He could produce a crash in the JSON + generator by returning something other than a String instance from a + to_json method. I now guard against this by doing a rather crude type + check, which raises an exception instead of crashing. + +## 2007-07-06 (1.1.1) + * Yui NARUSE sent some patches to fix tests for Ruby + 1.9. I applied them and adapted some of them a bit to run both on 1.8 and + 1.9. + * Introduced a `JSON.parse!` method without depth checking for people who + like danger. + * Made generate and `pretty_generate` methods configurable by an options hash. + * Added :allow_nan option to parser and generator in order to handle NaN, + Infinity, and -Infinity correctly - if requested. Floats, which aren't numbers, + aren't valid JSON according to RFC4627, so by default an exception will be + raised if any of these symbols are encountered. Thanks to Andrea Censi + for his hint about this. + * Fixed some more tests for Ruby 1.9. + * Implemented dump/load interface of Marshal as suggested in ruby-core:11405 + by murphy . + * Implemented the `max_nesting` feature for generate methods, too. + * Added some implementations for ruby core's custom objects for + serialisation/deserialisation purposes. + +## 2007-05-21 (1.1.0) + * Implemented max_nesting feature for parser to avoid stack overflows for + data from untrusted sources. If you trust the source, you can disable it + with the option max_nesting => false. + * Piers Cawley reported a bug, that not every + character can be escaped by `\` as required by RFC4627. There's a + contradiction between David Crockford's JSON checker test vectors (in + tests/fixtures) and RFC4627, though. I decided to stick to the RFC, because + the JSON checker seems to be a bit older than the RFC. + * Extended license to Ruby License, which includes the GPL. + * Added keyboard shortcuts, and 'Open location' menu item to edit_json.rb. + +## 2007-05-09 (1.0.4) + * Applied a patch from Yui NARUSE to make JSON compile + under Ruby 1.9. Thank you very much for mailing it to me! + * Made binary variants of JSON fail early, instead of falling back to the + pure version. This should avoid overshadowing of eventual problems while + loading of the binary. + +## 2007-03-24 (1.0.3) + * Improved performance of pure variant a bit. + * The ext variant of this release supports the mswin32 platform. Ugh! + +## 2007-03-24 (1.0.2) + * Ext Parser didn't parse 0e0 correctly into 0.0: Fixed! + +## 2007-03-24 (1.0.1) + * Forgot some object files in the build dir. I really like that - not! + +## 2007-03-24 (1.0.0) + * Added C implementations for the JSON generator and a ragel based JSON + parser in C. + * Much more tests, especially fixtures from json.org. + * Further improved conformance to RFC4627. + +## 2007-02-09 (0.4.3) + * Conform more to RFC4627 for JSON: This means JSON strings + now always must contain exactly one object `"{ ... }"` or array `"[ ... ]"` in + order to be parsed without raising an exception. The definition of what + constitutes a whitespace is narrower in JSON than in Ruby ([ \t\r\n]), and + there are differences in floats and integers (no octals or hexadecimals) as + well. + * Added aliases generate and `pretty_generate` of unparse and `pretty_unparse`. + * Fixed a test case. + * Catch an `Iconv::InvalidEncoding` exception, that seems to occur on some Sun + boxes with SunOS 5.8, if iconv doesn't support utf16 conversions. This was + reported by Andrew R Jackson , thanks a bunch! + +## 2006-08-25 (0.4.2) + * Fixed a bug in handling solidi (/-characters), that was reported by + Kevin Gilpin . + +## 2006-02-06 (0.4.1) + * Fixed a bug related to escaping with backslashes. Thanks for the report go + to Florian Munz . + +## 2005-09-23 (0.4.0) + * Initial Rubyforge Version diff --git a/bin/gems/json-2.10.2/COPYING b/bin/gems/json-2.10.2/COPYING new file mode 100644 index 00000000..426810a7 --- /dev/null +++ b/bin/gems/json-2.10.2/COPYING @@ -0,0 +1,56 @@ +Ruby is copyrighted free software by Yukihiro Matsumoto . +You can redistribute it and/or modify it under either the terms of the +2-clause BSDL (see the file BSDL), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or binary form, + provided that you do at least ONE of the following: + + a) distribute the binaries and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard binaries non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under these terms. + + For the list of those files and their copying conditions, see the + file LEGAL. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. diff --git a/bin/gems/json-2.10.2/LEGAL b/bin/gems/json-2.10.2/LEGAL new file mode 100644 index 00000000..737d18cb --- /dev/null +++ b/bin/gems/json-2.10.2/LEGAL @@ -0,0 +1,8 @@ +# -*- rdoc -*- + += LEGAL NOTICE INFORMATION +-------------------------- + +All the files in this distribution are covered under either the Ruby's +license (see the file COPYING) or public-domain except some files +mentioned below. diff --git a/bin/gems/json-2.10.2/README.md b/bin/gems/json-2.10.2/README.md new file mode 100644 index 00000000..d327f74a --- /dev/null +++ b/bin/gems/json-2.10.2/README.md @@ -0,0 +1,268 @@ +# JSON implementation for Ruby + +[![CI](https://github.com/ruby/json/actions/workflows/ci.yml/badge.svg)](https://github.com/ruby/json/actions/workflows/ci.yml) + +## Description + +This is an implementation of the JSON specification according to RFC 7159 +http://www.ietf.org/rfc/rfc7159.txt . + +The JSON generator generate UTF-8 character sequences by default. +If an :ascii\_only option with a true value is given, they escape all +non-ASCII and control characters with \uXXXX escape sequences, and support +UTF-16 surrogate pairs in order to be able to generate the whole range of +unicode code points. + +All strings, that are to be encoded as JSON strings, should be UTF-8 byte +sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8 +encoded, please use the to\_json\_raw\_object method of String (which produces +an object, that contains a byte array) and decode the result on the receiving +endpoint. + +## Installation + +Install the gem and add to the application's Gemfile by executing: + + $ bundle add json + +If bundler is not being used to manage dependencies, install the gem by executing: + + $ gem install json + +## Basic Usage + +To use JSON you can + +```ruby +require 'json' +``` + +Now you can parse a JSON document into a ruby data structure by calling + +```ruby +JSON.parse(document) +``` + +If you want to generate a JSON document from a ruby data structure call +```ruby +JSON.generate(data) +``` + +You can also use the `pretty_generate` method (which formats the output more +verbosely and nicely) or `fast_generate` (which doesn't do any of the security +checks generate performs, e. g. nesting deepness checks). + +## Casting non native types + +JSON documents can only support Hashes, Arrays, Strings, Integers and Floats. + +By default if you attempt to serialize something else, `JSON.generate` will +search for a `#to_json` method on that object: + +```ruby +Position = Struct.new(:latitude, :longitude) do + def to_json(state = nil, *) + JSON::State.from_state(state).generate({ + latitude: latitude, + longitude: longitude, + }) + end +end + +JSON.generate([ + Position.new(12323.234, 435345.233), + Position.new(23434.676, 159435.324), +]) # => [{"latitude":12323.234,"longitude":435345.233},{"latitude":23434.676,"longitude":159435.324}] +``` + +If a `#to_json` method isn't defined on the object, `JSON.generate` will fallback to call `#to_s`: + +```ruby +JSON.generate(Object.new) # => "#" +``` + +Both of these behavior can be disabled using the `strict: true` option: + +```ruby +JSON.generate(Object.new, strict: true) # => Object not allowed in JSON (JSON::GeneratorError) +JSON.generate(Position.new(1, 2)) # => Position not allowed in JSON (JSON::GeneratorError) +``` + +## JSON::Coder + +Since `#to_json` methods are global, it can sometimes be problematic if you need a given type to be +serialized in different ways in different locations. + +Instead it is recommended to use the newer `JSON::Coder` API: + +```ruby +module MyApp + API_JSON_CODER = JSON::Coder.new do |object| + case object + when Time + object.iso8601(3) + else + object + end + end +end + +puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z" +``` + +The provided block is called for all objects that don't have a native JSON equivalent, and +must return a Ruby object that has a native JSON equivalent. + +## Combining JSON fragments + +To combine JSON fragments into a bigger JSON document, you can use `JSON::Fragment`: + +```ruby +posts_json = cache.fetch_multi(post_ids) do |post_id| + JSON.generate(Post.find(post_id)) +end +posts_json.map! { |post_json| JSON::Fragment.new(post_json) } +JSON.generate({ posts: posts_json, count: posts_json.count }) +``` + +## Round-tripping arbitrary types + +> [!CAUTION] +> You should never use `JSON.unsafe_load` nor `JSON.parse(str, create_additions: true)` to parse untrusted user input, +> as it can lead to remote code execution vulnerabilities. + +To create a JSON document from a ruby data structure, you can call +`JSON.generate` like that: + +```ruby +json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10] +# => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]" +``` + +To get back a ruby data structure from a JSON document, you have to call +JSON.parse on it: + +```ruby +JSON.parse json +# => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"] +``` + +Note, that the range from the original data structure is a simple +string now. The reason for this is, that JSON doesn't support ranges +or arbitrary classes. In this case the json library falls back to call +`Object#to_json`, which is the same as `#to_s.to_json`. + +It's possible to add JSON support serialization to arbitrary classes by +simply implementing a more specialized version of the `#to_json method`, that +should return a JSON object (a hash converted to JSON with `#to_json`) like +this (don't forget the `*a` for all the arguments): + +```ruby +class Range + def to_json(*a) + { + 'json_class' => self.class.name, # = 'Range' + 'data' => [ first, last, exclude_end? ] + }.to_json(*a) + end +end +``` + +The hash key `json_class` is the class, that will be asked to deserialise the +JSON representation later. In this case it's `Range`, but any namespace of +the form `A::B` or `::A::B` will do. All other keys are arbitrary and can be +used to store the necessary data to configure the object to be deserialised. + +If the key `json_class` is found in a JSON object, the JSON parser checks +if the given class responds to the `json_create` class method. If so, it is +called with the JSON object converted to a Ruby hash. So a range can +be deserialised by implementing `Range.json_create` like this: + +```ruby +class Range + def self.json_create(o) + new(*o['data']) + end +end +``` + +Now it possible to serialise/deserialise ranges as well: + +```ruby +json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10] +# => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]" +JSON.parse json +# => [1, 2, {"a"=>3.141}, false, true, nil, 4..10] +json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10] +# => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]" +JSON.unsafe_load json +# => [1, 2, {"a"=>3.141}, false, true, nil, 4..10] +``` + +`JSON.generate` always creates the shortest possible string representation of a +ruby data structure in one line. This is good for data storage or network +protocols, but not so good for humans to read. Fortunately there's also +`JSON.pretty_generate` (or `JSON.pretty_generate`) that creates a more readable +output: + +```ruby + puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10]) + [ + 1, + 2, + { + "a": 3.141 + }, + false, + true, + null, + { + "json_class": "Range", + "data": [ + 4, + 10, + false + ] + } + ] +``` + +There are also the methods `Kernel#j` for generate, and `Kernel#jj` for +`pretty_generate` output to the console, that work analogous to Core Ruby's `p` and +the `pp` library's `pp` methods. + +## Development + +### Release + +Update the `lib/json/version.rb` file. + +``` +rbenv shell 2.6.5 +rake build +gem push pkg/json-2.3.0.gem + +rbenv shell jruby-9.2.9.0 +rake build +gem push pkg/json-2.3.0-java.gem +``` + +## Author + +Florian Frank + +## License + +Ruby License, see https://www.ruby-lang.org/en/about/license.txt. + +## Download + +The latest version of this library can be downloaded at + +* https://rubygems.org/gems/json + +Online Documentation should be located at + +* https://www.rubydoc.info/gems/json + +[Ragel]: http://www.colm.net/open-source/ragel/ diff --git a/bin/gems/json-2.10.2/ext/json/ext/fbuffer/fbuffer.h b/bin/gems/json-2.10.2/ext/json/ext/fbuffer/fbuffer.h new file mode 100644 index 00000000..4c42e14b --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/fbuffer/fbuffer.h @@ -0,0 +1,205 @@ +#ifndef _FBUFFER_H_ +#define _FBUFFER_H_ + +#include "ruby.h" +#include "ruby/encoding.h" + +/* shims */ +/* This is the fallback definition from Ruby 3.4 */ + +#ifndef RBIMPL_STDBOOL_H +#if defined(__cplusplus) +# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L) +# include +# endif +#elif defined(HAVE_STDBOOL_H) +# include +#elif !defined(HAVE__BOOL) +typedef unsigned char _Bool; +# define bool _Bool +# define true ((_Bool)+1) +# define false ((_Bool)+0) +# define __bool_true_false_are_defined +#endif +#endif + +#ifndef RB_UNLIKELY +#define RB_UNLIKELY(expr) expr +#endif + +#ifndef RB_LIKELY +#define RB_LIKELY(expr) expr +#endif + +#ifndef MAYBE_UNUSED +# define MAYBE_UNUSED(x) x +#endif + +enum fbuffer_type { + FBUFFER_HEAP_ALLOCATED = 0, + FBUFFER_STACK_ALLOCATED = 1, +}; + +typedef struct FBufferStruct { + enum fbuffer_type type; + unsigned long initial_length; + unsigned long len; + unsigned long capa; + char *ptr; + VALUE io; +} FBuffer; + +#define FBUFFER_STACK_SIZE 512 +#define FBUFFER_IO_BUFFER_SIZE (16384 - 1) +#define FBUFFER_INITIAL_LENGTH_DEFAULT 1024 + +#define FBUFFER_PTR(fb) ((fb)->ptr) +#define FBUFFER_LEN(fb) ((fb)->len) +#define FBUFFER_CAPA(fb) ((fb)->capa) +#define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb) + +static void fbuffer_free(FBuffer *fb); +static void fbuffer_clear(FBuffer *fb); +static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len); +static void fbuffer_append_long(FBuffer *fb, long number); +static inline void fbuffer_append_char(FBuffer *fb, char newchr); +static VALUE fbuffer_finalize(FBuffer *fb); + +static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size) +{ + fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT; + if (stack_buffer) { + fb->type = FBUFFER_STACK_ALLOCATED; + fb->ptr = stack_buffer; + fb->capa = stack_buffer_size; + } +} + +static void fbuffer_free(FBuffer *fb) +{ + if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) { + ruby_xfree(fb->ptr); + } +} + +static void fbuffer_clear(FBuffer *fb) +{ + fb->len = 0; +} + +static void fbuffer_flush(FBuffer *fb) +{ + rb_io_write(fb->io, rb_utf8_str_new(fb->ptr, fb->len)); + fbuffer_clear(fb); +} + +static void fbuffer_realloc(FBuffer *fb, unsigned long required) +{ + if (required > fb->capa) { + if (fb->type == FBUFFER_STACK_ALLOCATED) { + const char *old_buffer = fb->ptr; + fb->ptr = ALLOC_N(char, required); + fb->type = FBUFFER_HEAP_ALLOCATED; + MEMCPY(fb->ptr, old_buffer, char, fb->len); + } else { + REALLOC_N(fb->ptr, char, required); + } + fb->capa = required; + } +} + +static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested) +{ + if (RB_UNLIKELY(fb->io)) { + if (fb->capa < FBUFFER_IO_BUFFER_SIZE) { + fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE); + } else { + fbuffer_flush(fb); + } + + if (RB_LIKELY(requested < fb->capa)) { + return; + } + } + + unsigned long required; + + if (RB_UNLIKELY(!fb->ptr)) { + fb->ptr = ALLOC_N(char, fb->initial_length); + fb->capa = fb->initial_length; + } + + for (required = fb->capa; requested > required - fb->len; required <<= 1); + + fbuffer_realloc(fb, required); +} + +static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested) +{ + if (RB_UNLIKELY(requested > fb->capa - fb->len)) { + fbuffer_do_inc_capa(fb, requested); + } +} + +static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len) +{ + if (len > 0) { + fbuffer_inc_capa(fb, len); + MEMCPY(fb->ptr + fb->len, newstr, char, len); + fb->len += len; + } +} + +static void fbuffer_append_str(FBuffer *fb, VALUE str) +{ + const char *newstr = StringValuePtr(str); + unsigned long len = RSTRING_LEN(str); + + RB_GC_GUARD(str); + + fbuffer_append(fb, newstr, len); +} + +static inline void fbuffer_append_char(FBuffer *fb, char newchr) +{ + fbuffer_inc_capa(fb, 1); + *(fb->ptr + fb->len) = newchr; + fb->len++; +} + +static long fltoa(long number, char *buf) +{ + static const char digits[] = "0123456789"; + long sign = number; + char* tmp = buf; + + if (sign < 0) number = -number; + do *tmp-- = digits[number % 10]; while (number /= 10); + if (sign < 0) *tmp-- = '-'; + return buf - tmp; +} + +#define LONG_BUFFER_SIZE 20 +static void fbuffer_append_long(FBuffer *fb, long number) +{ + char buf[LONG_BUFFER_SIZE]; + char *buffer_end = buf + LONG_BUFFER_SIZE; + long len = fltoa(number, buffer_end - 1); + fbuffer_append(fb, buffer_end - len, len); +} + +static VALUE fbuffer_finalize(FBuffer *fb) +{ + if (fb->io) { + fbuffer_flush(fb); + fbuffer_free(fb); + rb_io_flush(fb->io); + return fb->io; + } else { + VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb)); + fbuffer_free(fb); + return result; + } +} + +#endif diff --git a/bin/gems/json-2.10.2/ext/json/ext/generator/Makefile b/bin/gems/json-2.10.2/ext/json/ext/generator/Makefile new file mode 100644 index 00000000..1f04f9c2 --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/generator/Makefile @@ -0,0 +1,269 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = . +topdir = /usr/include/ruby-3.2.0 +hdrdir = $(topdir) +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR)/etc +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ +LIBRUBY = $(LIBRUBY_SO) +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = -fPIC +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -std=c99 $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = +CPPFLAGS = -DJSON_GENERATOR -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CC) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-linux-gnu-gcc-ar +EXEEXT = + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 +RUBYW_INSTALL_NAME = +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x86_64-linux-gnu +sitearch = $(arch) +ruby_version = 3.2.0 +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 +RUBY = $(ruby) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h + +RM = rm -f +RM_RF = rm -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) +DEFFILE = + +CLEANFILES = mkmf.log +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = /json/ext +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc +ORIG_SRCS = generator.c +SRCS = $(ORIG_SRCS) +OBJS = generator.o +HDRS = +LOCAL_HDRS = +TARGET = generator +TARGET_NAME = generator +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = $(OBJS) *.bak +TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.-.json.-.ext.time + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP) + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + -$(Q)$(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TARGET_SO_DIR_TIMESTAMP): + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(OBJS) Makefile + $(ECHO) linking shared-object json/ext/$(DLLIB) + -$(Q)$(RM) $(@) + $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) + + + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/bin/gems/json-2.10.2/ext/json/ext/generator/extconf.rb b/bin/gems/json-2.10.2/ext/json/ext/generator/extconf.rb new file mode 100644 index 00000000..078068cf --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/generator/extconf.rb @@ -0,0 +1,10 @@ +require 'mkmf' + +if RUBY_ENGINE == 'truffleruby' + # The pure-Ruby generator is faster on TruffleRuby, so skip compiling the generator extension + File.write('Makefile', dummy_makefile("").join) +else + append_cflags("-std=c99") + $defs << "-DJSON_GENERATOR" + create_makefile 'json/ext/generator' +end diff --git a/bin/gems/json-2.10.2/ext/json/ext/generator/generator.c b/bin/gems/json-2.10.2/ext/json/ext/generator/generator.c new file mode 100644 index 00000000..08338853 --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/generator/generator.c @@ -0,0 +1,1822 @@ +#include "ruby.h" +#include "../fbuffer/fbuffer.h" + +#include +#include + +/* ruby api and some helpers */ + +typedef struct JSON_Generator_StateStruct { + VALUE indent; + VALUE space; + VALUE space_before; + VALUE object_nl; + VALUE array_nl; + VALUE as_json; + + long max_nesting; + long depth; + long buffer_initial_length; + + bool allow_nan; + bool ascii_only; + bool script_safe; + bool strict; +} JSON_Generator_State; + +#ifndef RB_UNLIKELY +#define RB_UNLIKELY(cond) (cond) +#endif + +static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8; + +static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode; +static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, + sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json; + + +#define GET_STATE_TO(self, state) \ + TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state) + +#define GET_STATE(self) \ + JSON_Generator_State *state; \ + GET_STATE_TO(self, state) + +struct generate_json_data; + +typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); + +struct generate_json_data { + FBuffer *buffer; + VALUE vstate; + JSON_Generator_State *state; + VALUE obj; + generator_func func; +}; + +static VALUE cState_from_state_s(VALUE self, VALUE opts); +static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io); +static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +#ifdef RUBY_INTEGER_UNIFICATION +static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +#endif +static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); +static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj); + +static int usascii_encindex, utf8_encindex, binary_encindex; + +#ifdef RBIMPL_ATTR_NORETURN +RBIMPL_ATTR_NORETURN() +#endif +static void raise_generator_error_str(VALUE invalid_object, VALUE str) +{ + VALUE exc = rb_exc_new_str(eGeneratorError, str); + rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object); + rb_exc_raise(exc); +} + +#ifdef RBIMPL_ATTR_NORETURN +RBIMPL_ATTR_NORETURN() +#endif +#ifdef RBIMPL_ATTR_FORMAT +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3) +#endif +static void raise_generator_error(VALUE invalid_object, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + VALUE str = rb_vsprintf(fmt, args); + va_end(args); + raise_generator_error_str(invalid_object, str); +} + +// 0 - single byte char that don't need to be escaped. +// (x | 8) - char that needs to be escaped. +static const unsigned char CHAR_LENGTH_MASK = 7; +static const unsigned char ESCAPE_MASK = 8; + +typedef struct _search_state { + const char *ptr; + const char *end; + const char *cursor; + FBuffer *buffer; +} search_state; + +static inline void search_flush(search_state *search) +{ + fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor); + search->cursor = search->ptr; +} + +static const unsigned char escape_table_basic[256] = { + // ASCII Control Characters + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + // ASCII Characters + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static inline unsigned char search_escape_basic(search_state *search) +{ + while (search->ptr < search->end) { + if (RB_UNLIKELY(escape_table_basic[(const unsigned char)*search->ptr])) { + search_flush(search); + return 1; + } else { + search->ptr++; + } + } + search_flush(search); + return 0; +} + +static inline void escape_UTF8_char_basic(search_state *search) { + const unsigned char ch = (unsigned char)*search->ptr; + switch (ch) { + case '"': fbuffer_append(search->buffer, "\\\"", 2); break; + case '\\': fbuffer_append(search->buffer, "\\\\", 2); break; + case '/': fbuffer_append(search->buffer, "\\/", 2); break; + case '\b': fbuffer_append(search->buffer, "\\b", 2); break; + case '\f': fbuffer_append(search->buffer, "\\f", 2); break; + case '\n': fbuffer_append(search->buffer, "\\n", 2); break; + case '\r': fbuffer_append(search->buffer, "\\r", 2); break; + case '\t': fbuffer_append(search->buffer, "\\t", 2); break; + default: { + const char *hexdig = "0123456789abcdef"; + char scratch[6] = { '\\', 'u', '0', '0', 0, 0 }; + scratch[4] = hexdig[(ch >> 4) & 0xf]; + scratch[5] = hexdig[ch & 0xf]; + fbuffer_append(search->buffer, scratch, 6); + break; + } + } + search->ptr++; + search->cursor = search->ptr; +} + +/* Converts in_string to a JSON string (without the wrapping '"' + * characters) in FBuffer out_buffer. + * + * Character are JSON-escaped according to: + * + * - Always: ASCII control characters (0x00-0x1F), dquote, and + * backslash. + * + * - If out_ascii_only: non-ASCII characters (>0x7F) + * + * - If script_safe: forwardslash (/), line separator (U+2028), and + * paragraph separator (U+2029) + * + * Everything else (should be UTF-8) is just passed through and + * appended to the result. + */ +static inline void convert_UTF8_to_JSON(search_state *search) +{ + while (search_escape_basic(search)) { + escape_UTF8_char_basic(search); + } +} + +static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) { + const unsigned char ch = (unsigned char)*search->ptr; + switch (ch_len) { + case 1: { + switch (ch) { + case '"': fbuffer_append(search->buffer, "\\\"", 2); break; + case '\\': fbuffer_append(search->buffer, "\\\\", 2); break; + case '/': fbuffer_append(search->buffer, "\\/", 2); break; + case '\b': fbuffer_append(search->buffer, "\\b", 2); break; + case '\f': fbuffer_append(search->buffer, "\\f", 2); break; + case '\n': fbuffer_append(search->buffer, "\\n", 2); break; + case '\r': fbuffer_append(search->buffer, "\\r", 2); break; + case '\t': fbuffer_append(search->buffer, "\\t", 2); break; + default: { + const char *hexdig = "0123456789abcdef"; + char scratch[6] = { '\\', 'u', '0', '0', 0, 0 }; + scratch[4] = hexdig[(ch >> 4) & 0xf]; + scratch[5] = hexdig[ch & 0xf]; + fbuffer_append(search->buffer, scratch, 6); + break; + } + } + break; + } + case 3: { + if (search->ptr[2] & 1) { + fbuffer_append(search->buffer, "\\u2029", 6); + } else { + fbuffer_append(search->buffer, "\\u2028", 6); + } + break; + } + } + search->cursor = (search->ptr += ch_len); +} + +static const unsigned char script_safe_escape_table[256] = { + // ASCII Control Characters + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + // ASCII Characters + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, // '"' and '/' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // Continuation byte + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + // First byte of a 2-byte code point + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + // First byte of a 3-byte code point + 3, 3,11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE2 is the start of \u2028 and \u2029 + //First byte of a 4+ byte code point + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9, +}; + +static inline unsigned char search_script_safe_escape(search_state *search) +{ + while (search->ptr < search->end) { + unsigned char ch = (unsigned char)*search->ptr; + unsigned char ch_len = script_safe_escape_table[ch]; + + if (RB_UNLIKELY(ch_len)) { + if (ch_len & ESCAPE_MASK) { + if (RB_UNLIKELY(ch_len == 11)) { + const unsigned char *uptr = (const unsigned char *)search->ptr; + if (!(uptr[1] == 0x80 && (uptr[2] >> 1) == 0x54)) { + search->ptr += 3; + continue; + } + } + search_flush(search); + return ch_len & CHAR_LENGTH_MASK; + } else { + search->ptr += ch_len; + } + } else { + search->ptr++; + } + } + search_flush(search); + return 0; +} + +static void convert_UTF8_to_script_safe_JSON(search_state *search) +{ + unsigned char ch_len; + while ((ch_len = search_script_safe_escape(search))) { + escape_UTF8_char(search, ch_len); + } +} + +static const unsigned char ascii_only_escape_table[256] = { + // ASCII Control Characters + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + // ASCII Characters + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // Continuation byte + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + // First byte of a 2-byte code point + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + // First byte of a 3-byte code point + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + //First byte of a 4+ byte code point + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9, +}; + +static inline unsigned char search_ascii_only_escape(search_state *search, const unsigned char escape_table[256]) +{ + while (search->ptr < search->end) { + unsigned char ch = (unsigned char)*search->ptr; + unsigned char ch_len = escape_table[ch]; + + if (RB_UNLIKELY(ch_len)) { + search_flush(search); + return ch_len & CHAR_LENGTH_MASK; + } else { + search->ptr++; + } + } + search_flush(search); + return 0; +} + +static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) { + const unsigned char ch = (unsigned char)*search->ptr; + switch (ch_len) { + case 1: { + switch (ch) { + case '"': fbuffer_append(search->buffer, "\\\"", 2); break; + case '\\': fbuffer_append(search->buffer, "\\\\", 2); break; + case '/': fbuffer_append(search->buffer, "\\/", 2); break; + case '\b': fbuffer_append(search->buffer, "\\b", 2); break; + case '\f': fbuffer_append(search->buffer, "\\f", 2); break; + case '\n': fbuffer_append(search->buffer, "\\n", 2); break; + case '\r': fbuffer_append(search->buffer, "\\r", 2); break; + case '\t': fbuffer_append(search->buffer, "\\t", 2); break; + default: { + const char *hexdig = "0123456789abcdef"; + char scratch[6] = { '\\', 'u', '0', '0', 0, 0 }; + scratch[4] = hexdig[(ch >> 4) & 0xf]; + scratch[5] = hexdig[ch & 0xf]; + fbuffer_append(search->buffer, scratch, 6); + break; + } + } + break; + } + default: { + const char *hexdig = "0123456789abcdef"; + char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' }; + + uint32_t wchar = 0; + + switch(ch_len) { + case 2: + wchar = ch & 0x1F; + break; + case 3: + wchar = ch & 0x0F; + break; + case 4: + wchar = ch & 0x07; + break; + } + + for (short i = 1; i < ch_len; i++) { + wchar = (wchar << 6) | (search->ptr[i] & 0x3F); + } + + if (wchar <= 0xFFFF) { + scratch[2] = hexdig[wchar >> 12]; + scratch[3] = hexdig[(wchar >> 8) & 0xf]; + scratch[4] = hexdig[(wchar >> 4) & 0xf]; + scratch[5] = hexdig[wchar & 0xf]; + fbuffer_append(search->buffer, scratch, 6); + } else { + uint16_t hi, lo; + wchar -= 0x10000; + hi = 0xD800 + (uint16_t)(wchar >> 10); + lo = 0xDC00 + (uint16_t)(wchar & 0x3FF); + + scratch[2] = hexdig[hi >> 12]; + scratch[3] = hexdig[(hi >> 8) & 0xf]; + scratch[4] = hexdig[(hi >> 4) & 0xf]; + scratch[5] = hexdig[hi & 0xf]; + + scratch[8] = hexdig[lo >> 12]; + scratch[9] = hexdig[(lo >> 8) & 0xf]; + scratch[10] = hexdig[(lo >> 4) & 0xf]; + scratch[11] = hexdig[lo & 0xf]; + + fbuffer_append(search->buffer, scratch, 12); + } + + break; + } + } + search->cursor = (search->ptr += ch_len); +} + +static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned char escape_table[256]) +{ + unsigned char ch_len; + while ((ch_len = search_ascii_only_escape(search, escape_table))) { + full_escape_UTF8_char(search, ch_len); + } +} + +/* + * Document-module: JSON::Ext::Generator + * + * This is the JSON generator implemented as a C extension. It can be + * configured to be used by setting + * + * JSON.generator = JSON::Ext::Generator + * + * with the method generator= in JSON. + * + */ + +/* Explanation of the following: that's the only way to not pollute + * standard library's docs with GeneratorMethods:: which + * are uninformative and take a large place in a list of classes + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Array + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Float + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::Object + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::String + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend + * :nodoc: + */ + +/* + * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass + * :nodoc: + */ + +/* + * call-seq: to_json(state = nil) + * + * Returns a JSON string containing a JSON object, that is generated from + * this Hash instance. + * _state_ is a JSON::State object, that can also be used to configure the + * produced JSON string output further. + */ +static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_object, Qfalse); +} + +/* + * call-seq: to_json(state = nil) + * + * Returns a JSON string containing a JSON array, that is generated from + * this Array instance. + * _state_ is a JSON::State object, that can also be used to configure the + * produced JSON string output further. + */ +static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) { + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_array, Qfalse); +} + +#ifdef RUBY_INTEGER_UNIFICATION +/* + * call-seq: to_json(*) + * + * Returns a JSON string representation for this Integer number. + */ +static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse); +} + +#else +/* + * call-seq: to_json(*) + * + * Returns a JSON string representation for this Integer number. + */ +static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse); +} + +/* + * call-seq: to_json(*) + * + * Returns a JSON string representation for this Integer number. + */ +static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse); +} +#endif + +/* + * call-seq: to_json(*) + * + * Returns a JSON string representation for this Float number. + */ +static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_float, Qfalse); +} + +/* + * call-seq: String.included(modul) + * + * Extends _modul_ with the String::Extend module. + */ +static VALUE mString_included_s(VALUE self, VALUE modul) { + VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend); + rb_call_super(1, &modul); + return result; +} + +/* + * call-seq: to_json(*) + * + * This string should be encoded with UTF-8 A call to this method + * returns a JSON string encoded with UTF16 big endian characters as + * \u????. + */ +static VALUE mString_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil); + return cState_partial_generate(Vstate, self, generate_json_string, Qfalse); +} + +/* + * call-seq: to_json_raw_object() + * + * This method creates a raw object hash, that can be nested into + * other data structures and will be generated as a raw string. This + * method should be used, if you want to convert raw strings to JSON + * instead of UTF-8 strings, e. g. binary data. + */ +static VALUE mString_to_json_raw_object(VALUE self) +{ + VALUE ary; + VALUE result = rb_hash_new(); + rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self))); + ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*")); + rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary); + return result; +} + +/* + * call-seq: to_json_raw(*args) + * + * This method creates a JSON text from the result of a call to + * to_json_raw_object of this String. + */ +static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self) +{ + VALUE obj = mString_to_json_raw_object(self); + Check_Type(obj, T_HASH); + return mHash_to_json(argc, argv, obj); +} + +/* + * call-seq: json_create(o) + * + * Raw Strings are JSON Objects (the raw bytes are stored in an array for the + * key "raw"). The Ruby String can be created by this module method. + */ +static VALUE mString_Extend_json_create(VALUE self, VALUE o) +{ + VALUE ary; + Check_Type(o, T_HASH); + ary = rb_hash_aref(o, rb_str_new2("raw")); + return rb_funcall(ary, i_pack, 1, rb_str_new2("C*")); +} + +/* + * call-seq: to_json(*) + * + * Returns a JSON string for true: 'true'. + */ +static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + return rb_utf8_str_new("true", 4); +} + +/* + * call-seq: to_json(*) + * + * Returns a JSON string for false: 'false'. + */ +static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + return rb_utf8_str_new("false", 5); +} + +/* + * call-seq: to_json(*) + * + * Returns a JSON string for nil: 'null'. + */ +static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 0, 1); + return rb_utf8_str_new("null", 4); +} + +/* + * call-seq: to_json(*) + * + * Converts this object to a string (calling #to_s), converts + * it to a JSON string, and returns the result. This is a fallback, if no + * special method #to_json was defined for some object. + */ +static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self) +{ + VALUE state; + VALUE string = rb_funcall(self, i_to_s, 0); + rb_scan_args(argc, argv, "01", &state); + Check_Type(string, T_STRING); + state = cState_from_state_s(cState, state); + return cState_partial_generate(state, string, generate_json_string, Qfalse); +} + +static void State_mark(void *ptr) +{ + JSON_Generator_State *state = ptr; + rb_gc_mark_movable(state->indent); + rb_gc_mark_movable(state->space); + rb_gc_mark_movable(state->space_before); + rb_gc_mark_movable(state->object_nl); + rb_gc_mark_movable(state->array_nl); + rb_gc_mark_movable(state->as_json); +} + +static void State_compact(void *ptr) +{ + JSON_Generator_State *state = ptr; + state->indent = rb_gc_location(state->indent); + state->space = rb_gc_location(state->space); + state->space_before = rb_gc_location(state->space_before); + state->object_nl = rb_gc_location(state->object_nl); + state->array_nl = rb_gc_location(state->array_nl); + state->as_json = rb_gc_location(state->as_json); +} + +static void State_free(void *ptr) +{ + JSON_Generator_State *state = ptr; + ruby_xfree(state); +} + +static size_t State_memsize(const void *ptr) +{ + return sizeof(JSON_Generator_State); +} + +#ifndef HAVE_RB_EXT_RACTOR_SAFE +# undef RUBY_TYPED_FROZEN_SHAREABLE +# define RUBY_TYPED_FROZEN_SHAREABLE 0 +#endif + +static const rb_data_type_t JSON_Generator_State_type = { + "JSON/Generator/State", + { + .dmark = State_mark, + .dfree = State_free, + .dsize = State_memsize, + .dcompact = State_compact, + }, + 0, 0, + RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE, +}; + +static void state_init(JSON_Generator_State *state) +{ + state->max_nesting = 100; + state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT; +} + +static VALUE cState_s_allocate(VALUE klass) +{ + JSON_Generator_State *state; + VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state); + state_init(state); + return obj; +} + +static void vstate_spill(struct generate_json_data *data) +{ + VALUE vstate = cState_s_allocate(cState); + GET_STATE(vstate); + MEMCPY(state, data->state, JSON_Generator_State, 1); + data->state = state; + data->vstate = vstate; + RB_OBJ_WRITTEN(vstate, Qundef, state->indent); + RB_OBJ_WRITTEN(vstate, Qundef, state->space); + RB_OBJ_WRITTEN(vstate, Qundef, state->space_before); + RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl); + RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl); + RB_OBJ_WRITTEN(vstate, Qundef, state->as_json); +} + +static inline VALUE vstate_get(struct generate_json_data *data) +{ + if (RB_UNLIKELY(!data->vstate)) { + vstate_spill(data); + } + return data->vstate; +} + +struct hash_foreach_arg { + struct generate_json_data *data; + int iter; +}; + +static int +json_object_i(VALUE key, VALUE val, VALUE _arg) +{ + struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg; + struct generate_json_data *data = arg->data; + + FBuffer *buffer = data->buffer; + JSON_Generator_State *state = data->state; + + long depth = state->depth; + int j; + + if (arg->iter > 0) fbuffer_append_char(buffer, ','); + if (RB_UNLIKELY(state->object_nl)) { + fbuffer_append_str(buffer, state->object_nl); + } + if (RB_UNLIKELY(state->indent)) { + for (j = 0; j < depth; j++) { + fbuffer_append_str(buffer, state->indent); + } + } + + VALUE key_to_s; + switch(rb_type(key)) { + case T_STRING: + if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) { + key_to_s = key; + } else { + key_to_s = rb_funcall(key, i_to_s, 0); + } + break; + case T_SYMBOL: + key_to_s = rb_sym2str(key); + break; + default: + key_to_s = rb_convert_type(key, T_STRING, "String", "to_s"); + break; + } + + if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) { + generate_json_string(buffer, data, state, key_to_s); + } else { + generate_json(buffer, data, state, key_to_s); + } + if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before); + fbuffer_append_char(buffer, ':'); + if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space); + generate_json(buffer, data, state, val); + + arg->iter++; + return ST_CONTINUE; +} + +static inline long increase_depth(JSON_Generator_State *state) +{ + long depth = ++state->depth; + if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) { + rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth); + } + return depth; +} + +static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + int j; + long depth = increase_depth(state); + + if (RHASH_SIZE(obj) == 0) { + fbuffer_append(buffer, "{}", 2); + --state->depth; + return; + } + + fbuffer_append_char(buffer, '{'); + + struct hash_foreach_arg arg = { + .data = data, + .iter = 0, + }; + rb_hash_foreach(obj, json_object_i, (VALUE)&arg); + + depth = --state->depth; + if (RB_UNLIKELY(state->object_nl)) { + fbuffer_append_str(buffer, state->object_nl); + if (RB_UNLIKELY(state->indent)) { + for (j = 0; j < depth; j++) { + fbuffer_append_str(buffer, state->indent); + } + } + } + fbuffer_append_char(buffer, '}'); +} + +static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + int i, j; + long depth = increase_depth(state); + + if (RARRAY_LEN(obj) == 0) { + fbuffer_append(buffer, "[]", 2); + --state->depth; + return; + } + + fbuffer_append_char(buffer, '['); + if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl); + for(i = 0; i < RARRAY_LEN(obj); i++) { + if (i > 0) { + fbuffer_append_char(buffer, ','); + if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl); + } + if (RB_UNLIKELY(state->indent)) { + for (j = 0; j < depth; j++) { + fbuffer_append_str(buffer, state->indent); + } + } + generate_json(buffer, data, state, RARRAY_AREF(obj, i)); + } + state->depth = --depth; + if (RB_UNLIKELY(state->array_nl)) { + fbuffer_append_str(buffer, state->array_nl); + if (RB_UNLIKELY(state->indent)) { + for (j = 0; j < depth; j++) { + fbuffer_append_str(buffer, state->indent); + } + } + } + fbuffer_append_char(buffer, ']'); +} + +static inline int enc_utf8_compatible_p(int enc_idx) +{ + if (enc_idx == usascii_encindex) return 1; + if (enc_idx == utf8_encindex) return 1; + return 0; +} + +static VALUE encode_json_string_try(VALUE str) +{ + return rb_funcall(str, i_encode, 1, Encoding_UTF_8); +} + +static VALUE encode_json_string_rescue(VALUE str, VALUE exception) +{ + raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0)); + return Qundef; +} + +static inline VALUE ensure_valid_encoding(VALUE str) +{ + int encindex = RB_ENCODING_GET(str); + VALUE utf8_string; + if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) { + if (encindex == binary_encindex) { + utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex); + switch (rb_enc_str_coderange(utf8_string)) { + case ENC_CODERANGE_7BIT: + return utf8_string; + case ENC_CODERANGE_VALID: + // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work. + // TODO: Raise in 3.0.0 + rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0"); + return utf8_string; + break; + } + } + + str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str); + } + return str; +} + +static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + obj = ensure_valid_encoding(obj); + + fbuffer_append_char(buffer, '"'); + + long len; + search_state search; + search.buffer = buffer; + RSTRING_GETMEM(obj, search.ptr, len); + search.cursor = search.ptr; + search.end = search.ptr + len; + + switch(rb_enc_str_coderange(obj)) { + case ENC_CODERANGE_7BIT: + case ENC_CODERANGE_VALID: + if (RB_UNLIKELY(state->ascii_only)) { + convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table); + } else if (RB_UNLIKELY(state->script_safe)) { + convert_UTF8_to_script_safe_JSON(&search); + } else { + convert_UTF8_to_JSON(&search); + } + break; + default: + raise_generator_error(obj, "source sequence is illegal/malformed utf-8"); + break; + } + fbuffer_append_char(buffer, '"'); +} + +static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + VALUE tmp; + if (rb_respond_to(obj, i_to_json)) { + tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data)); + Check_Type(tmp, T_STRING); + fbuffer_append_str(buffer, tmp); + } else { + tmp = rb_funcall(obj, i_to_s, 0); + Check_Type(tmp, T_STRING); + generate_json_string(buffer, data, state, tmp); + } +} + +static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + if (state->strict) { + generate_json_string(buffer, data, state, rb_sym2str(obj)); + } else { + generate_json_fallback(buffer, data, state, obj); + } +} + +static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + fbuffer_append(buffer, "null", 4); +} + +static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + fbuffer_append(buffer, "false", 5); +} + +static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + fbuffer_append(buffer, "true", 4); +} + +static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + fbuffer_append_long(buffer, FIX2LONG(obj)); +} + +static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + VALUE tmp = rb_funcall(obj, i_to_s, 0); + fbuffer_append_str(buffer, tmp); +} + +#ifdef RUBY_INTEGER_UNIFICATION +static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + if (FIXNUM_P(obj)) + generate_json_fixnum(buffer, data, state, obj); + else + generate_json_bignum(buffer, data, state, obj); +} +#endif + +static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + double value = RFLOAT_VALUE(obj); + char allow_nan = state->allow_nan; + if (!allow_nan) { + if (isinf(value) || isnan(value)) { + if (state->strict && state->as_json) { + VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil); + if (casted_obj != obj) { + increase_depth(state); + generate_json(buffer, data, state, casted_obj); + state->depth--; + return; + } + } + raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", rb_funcall(obj, i_to_s, 0)); + } + } + fbuffer_append_str(buffer, rb_funcall(obj, i_to_s, 0)); +} + +static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + VALUE fragment = RSTRUCT_GET(obj, 0); + Check_Type(fragment, T_STRING); + fbuffer_append_str(buffer, fragment); +} + +static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj) +{ + bool as_json_called = false; +start: + if (obj == Qnil) { + generate_json_null(buffer, data, state, obj); + } else if (obj == Qfalse) { + generate_json_false(buffer, data, state, obj); + } else if (obj == Qtrue) { + generate_json_true(buffer, data, state, obj); + } else if (RB_SPECIAL_CONST_P(obj)) { + if (RB_FIXNUM_P(obj)) { + generate_json_fixnum(buffer, data, state, obj); + } else if (RB_FLONUM_P(obj)) { + generate_json_float(buffer, data, state, obj); + } else if (RB_STATIC_SYM_P(obj)) { + generate_json_symbol(buffer, data, state, obj); + } else { + goto general; + } + } else { + VALUE klass = RBASIC_CLASS(obj); + switch (RB_BUILTIN_TYPE(obj)) { + case T_BIGNUM: + generate_json_bignum(buffer, data, state, obj); + break; + case T_HASH: + if (klass != rb_cHash) goto general; + generate_json_object(buffer, data, state, obj); + break; + case T_ARRAY: + if (klass != rb_cArray) goto general; + generate_json_array(buffer, data, state, obj); + break; + case T_STRING: + if (klass != rb_cString) goto general; + generate_json_string(buffer, data, state, obj); + break; + case T_SYMBOL: + generate_json_symbol(buffer, data, state, obj); + break; + case T_FLOAT: + if (klass != rb_cFloat) goto general; + generate_json_float(buffer, data, state, obj); + break; + case T_STRUCT: + if (klass != cFragment) goto general; + generate_json_fragment(buffer, data, state, obj); + break; + default: + general: + if (state->strict) { + if (RTEST(state->as_json) && !as_json_called) { + obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil); + as_json_called = true; + goto start; + } else { + raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj)); + } + } else { + generate_json_fallback(buffer, data, state, obj); + } + } + } +} + +static VALUE generate_json_try(VALUE d) +{ + struct generate_json_data *data = (struct generate_json_data *)d; + + data->func(data->buffer, data, data->state, data->obj); + + return Qnil; +} + +static VALUE generate_json_rescue(VALUE d, VALUE exc) +{ + struct generate_json_data *data = (struct generate_json_data *)d; + fbuffer_free(data->buffer); + + rb_exc_raise(exc); + + return Qundef; +} + +static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io) +{ + GET_STATE(self); + + char stack_buffer[FBUFFER_STACK_SIZE]; + FBuffer buffer = { + .io = RTEST(io) ? io : Qfalse, + }; + fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE); + + struct generate_json_data data = { + .buffer = &buffer, + .vstate = self, + .state = state, + .obj = obj, + .func = func + }; + rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); + + return fbuffer_finalize(&buffer); +} + +/* call-seq: + * generate(obj) -> String + * generate(obj, anIO) -> anIO + * + * Generates a valid JSON document from object +obj+ and returns the + * result. If no valid JSON document can be created this method raises a + * GeneratorError exception. + */ +static VALUE cState_generate(int argc, VALUE *argv, VALUE self) +{ + rb_check_arity(argc, 1, 2); + VALUE obj = argv[0]; + VALUE io = argc > 1 ? argv[1] : Qnil; + VALUE result = cState_partial_generate(self, obj, generate_json, io); + GET_STATE(self); + (void)state; + return result; +} + +static VALUE cState_initialize(int argc, VALUE *argv, VALUE self) +{ + rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`"); + return self; +} + +/* + * call-seq: initialize_copy(orig) + * + * Initializes this object from orig if it can be duplicated/cloned and returns + * it. +*/ +static VALUE cState_init_copy(VALUE obj, VALUE orig) +{ + JSON_Generator_State *objState, *origState; + + if (obj == orig) return obj; + GET_STATE_TO(obj, objState); + GET_STATE_TO(orig, origState); + if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State"); + + MEMCPY(objState, origState, JSON_Generator_State, 1); + objState->indent = origState->indent; + objState->space = origState->space; + objState->space_before = origState->space_before; + objState->object_nl = origState->object_nl; + objState->array_nl = origState->array_nl; + objState->as_json = origState->as_json; + return obj; +} + +/* + * call-seq: from_state(opts) + * + * Creates a State object from _opts_, which ought to be Hash to create a + * new State instance configured by _opts_, something else to create an + * unconfigured instance. If _opts_ is a State object, it is just returned. + */ +static VALUE cState_from_state_s(VALUE self, VALUE opts) +{ + if (rb_obj_is_kind_of(opts, self)) { + return opts; + } else if (rb_obj_is_kind_of(opts, rb_cHash)) { + return rb_funcall(self, i_new, 1, opts); + } else { + return rb_class_new_instance(0, NULL, cState); + } +} + +/* + * call-seq: indent() + * + * Returns the string that is used to indent levels in the JSON text. + */ +static VALUE cState_indent(VALUE self) +{ + GET_STATE(self); + return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0)); +} + +static VALUE string_config(VALUE config) +{ + if (RTEST(config)) { + Check_Type(config, T_STRING); + if (RSTRING_LEN(config)) { + return rb_str_new_frozen(config); + } + } + return Qfalse; +} + +/* + * call-seq: indent=(indent) + * + * Sets the string that is used to indent levels in the JSON text. + */ +static VALUE cState_indent_set(VALUE self, VALUE indent) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->indent, string_config(indent)); + return Qnil; +} + +/* + * call-seq: space() + * + * Returns the string that is used to insert a space between the tokens in a JSON + * string. + */ +static VALUE cState_space(VALUE self) +{ + GET_STATE(self); + return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0)); +} + +/* + * call-seq: space=(space) + * + * Sets _space_ to the string that is used to insert a space between the tokens in a JSON + * string. + */ +static VALUE cState_space_set(VALUE self, VALUE space) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->space, string_config(space)); + return Qnil; +} + +/* + * call-seq: space_before() + * + * Returns the string that is used to insert a space before the ':' in JSON objects. + */ +static VALUE cState_space_before(VALUE self) +{ + GET_STATE(self); + return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0)); +} + +/* + * call-seq: space_before=(space_before) + * + * Sets the string that is used to insert a space before the ':' in JSON objects. + */ +static VALUE cState_space_before_set(VALUE self, VALUE space_before) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->space_before, string_config(space_before)); + return Qnil; +} + +/* + * call-seq: object_nl() + * + * This string is put at the end of a line that holds a JSON object (or + * Hash). + */ +static VALUE cState_object_nl(VALUE self) +{ + GET_STATE(self); + return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0)); +} + +/* + * call-seq: object_nl=(object_nl) + * + * This string is put at the end of a line that holds a JSON object (or + * Hash). + */ +static VALUE cState_object_nl_set(VALUE self, VALUE object_nl) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl)); + return Qnil; +} + +/* + * call-seq: array_nl() + * + * This string is put at the end of a line that holds a JSON array. + */ +static VALUE cState_array_nl(VALUE self) +{ + GET_STATE(self); + return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0)); +} + +/* + * call-seq: array_nl=(array_nl) + * + * This string is put at the end of a line that holds a JSON array. + */ +static VALUE cState_array_nl_set(VALUE self, VALUE array_nl) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl)); + return Qnil; +} + +/* + * call-seq: as_json() + * + * This string is put at the end of a line that holds a JSON array. + */ +static VALUE cState_as_json(VALUE self) +{ + GET_STATE(self); + return state->as_json; +} + +/* + * call-seq: as_json=(as_json) + * + * This string is put at the end of a line that holds a JSON array. + */ +static VALUE cState_as_json_set(VALUE self, VALUE as_json) +{ + GET_STATE(self); + RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc")); + return Qnil; +} + +/* +* call-seq: check_circular? +* +* Returns true, if circular data structures should be checked, +* otherwise returns false. +*/ +static VALUE cState_check_circular_p(VALUE self) +{ + GET_STATE(self); + return state->max_nesting ? Qtrue : Qfalse; +} + +/* + * call-seq: max_nesting + * + * This integer returns the maximum level of data structure nesting in + * the generated JSON, max_nesting = 0 if no maximum is checked. + */ +static VALUE cState_max_nesting(VALUE self) +{ + GET_STATE(self); + return LONG2FIX(state->max_nesting); +} + +static long long_config(VALUE num) +{ + return RTEST(num) ? FIX2LONG(num) : 0; +} + +/* + * call-seq: max_nesting=(depth) + * + * This sets the maximum level of data structure nesting in the generated JSON + * to the integer depth, max_nesting = 0 if no maximum should be checked. + */ +static VALUE cState_max_nesting_set(VALUE self, VALUE depth) +{ + GET_STATE(self); + state->max_nesting = long_config(depth); + return Qnil; +} + +/* + * call-seq: script_safe + * + * If this boolean is true, the forward slashes will be escaped in + * the json output. + */ +static VALUE cState_script_safe(VALUE self) +{ + GET_STATE(self); + return state->script_safe ? Qtrue : Qfalse; +} + +/* + * call-seq: script_safe=(enable) + * + * This sets whether or not the forward slashes will be escaped in + * the json output. + */ +static VALUE cState_script_safe_set(VALUE self, VALUE enable) +{ + GET_STATE(self); + state->script_safe = RTEST(enable); + return Qnil; +} + +/* + * call-seq: strict + * + * If this boolean is false, types unsupported by the JSON format will + * be serialized as strings. + * If this boolean is true, types unsupported by the JSON format will + * raise a JSON::GeneratorError. + */ +static VALUE cState_strict(VALUE self) +{ + GET_STATE(self); + return state->strict ? Qtrue : Qfalse; +} + +/* + * call-seq: strict=(enable) + * + * This sets whether or not to serialize types unsupported by the + * JSON format as strings. + * If this boolean is false, types unsupported by the JSON format will + * be serialized as strings. + * If this boolean is true, types unsupported by the JSON format will + * raise a JSON::GeneratorError. + */ +static VALUE cState_strict_set(VALUE self, VALUE enable) +{ + GET_STATE(self); + state->strict = RTEST(enable); + return Qnil; +} + +/* + * call-seq: allow_nan? + * + * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise + * returns false. + */ +static VALUE cState_allow_nan_p(VALUE self) +{ + GET_STATE(self); + return state->allow_nan ? Qtrue : Qfalse; +} + +/* + * call-seq: allow_nan=(enable) + * + * This sets whether or not to serialize NaN, Infinity, and -Infinity + */ +static VALUE cState_allow_nan_set(VALUE self, VALUE enable) +{ + GET_STATE(self); + state->allow_nan = RTEST(enable); + return Qnil; +} + +/* + * call-seq: ascii_only? + * + * Returns true, if only ASCII characters should be generated. Otherwise + * returns false. + */ +static VALUE cState_ascii_only_p(VALUE self) +{ + GET_STATE(self); + return state->ascii_only ? Qtrue : Qfalse; +} + +/* + * call-seq: ascii_only=(enable) + * + * This sets whether only ASCII characters should be generated. + */ +static VALUE cState_ascii_only_set(VALUE self, VALUE enable) +{ + GET_STATE(self); + state->ascii_only = RTEST(enable); + return Qnil; +} + +/* + * call-seq: depth + * + * This integer returns the current depth of data structure nesting. + */ +static VALUE cState_depth(VALUE self) +{ + GET_STATE(self); + return LONG2FIX(state->depth); +} + +/* + * call-seq: depth=(depth) + * + * This sets the maximum level of data structure nesting in the generated JSON + * to the integer depth, max_nesting = 0 if no maximum should be checked. + */ +static VALUE cState_depth_set(VALUE self, VALUE depth) +{ + GET_STATE(self); + state->depth = long_config(depth); + return Qnil; +} + +/* + * call-seq: buffer_initial_length + * + * This integer returns the current initial length of the buffer. + */ +static VALUE cState_buffer_initial_length(VALUE self) +{ + GET_STATE(self); + return LONG2FIX(state->buffer_initial_length); +} + +static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length) +{ + Check_Type(buffer_initial_length, T_FIXNUM); + long initial_length = FIX2LONG(buffer_initial_length); + if (initial_length > 0) { + state->buffer_initial_length = initial_length; + } +} + +/* + * call-seq: buffer_initial_length=(length) + * + * This sets the initial length of the buffer to +length+, if +length+ > 0, + * otherwise its value isn't changed. + */ +static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length) +{ + GET_STATE(self); + buffer_initial_length_set(state, buffer_initial_length); + return Qnil; +} + +static int configure_state_i(VALUE key, VALUE val, VALUE _arg) +{ + JSON_Generator_State *state = (JSON_Generator_State *)_arg; + + if (key == sym_indent) { state->indent = string_config(val); } + else if (key == sym_space) { state->space = string_config(val); } + else if (key == sym_space_before) { state->space_before = string_config(val); } + else if (key == sym_object_nl) { state->object_nl = string_config(val); } + else if (key == sym_array_nl) { state->array_nl = string_config(val); } + else if (key == sym_max_nesting) { state->max_nesting = long_config(val); } + else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); } + else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); } + else if (key == sym_depth) { state->depth = long_config(val); } + else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); } + else if (key == sym_script_safe) { state->script_safe = RTEST(val); } + else if (key == sym_escape_slash) { state->script_safe = RTEST(val); } + else if (key == sym_strict) { state->strict = RTEST(val); } + else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; } + return ST_CONTINUE; +} + +static void configure_state(JSON_Generator_State *state, VALUE config) +{ + if (!RTEST(config)) return; + + Check_Type(config, T_HASH); + + if (!RHASH_SIZE(config)) return; + + // We assume in most cases few keys are set so it's faster to go over + // the provided keys than to check all possible keys. + rb_hash_foreach(config, configure_state_i, (VALUE)state); +} + +static VALUE cState_configure(VALUE self, VALUE opts) +{ + GET_STATE(self); + configure_state(state, opts); + return self; +} + +static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io) +{ + JSON_Generator_State state = {0}; + state_init(&state); + configure_state(&state, opts); + + char stack_buffer[FBUFFER_STACK_SIZE]; + FBuffer buffer = { + .io = RTEST(io) ? io : Qfalse, + }; + fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE); + + struct generate_json_data data = { + .buffer = &buffer, + .vstate = Qfalse, + .state = &state, + .obj = obj, + .func = generate_json, + }; + rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); + + return fbuffer_finalize(&buffer); +} + +/* + * + */ +void Init_generator(void) +{ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + +#undef rb_intern + rb_require("json/common"); + + mJSON = rb_define_module("JSON"); + + rb_global_variable(&cFragment); + cFragment = rb_const_get(mJSON, rb_intern("Fragment")); + + VALUE mExt = rb_define_module_under(mJSON, "Ext"); + VALUE mGenerator = rb_define_module_under(mExt, "Generator"); + + rb_global_variable(&eGeneratorError); + eGeneratorError = rb_path2class("JSON::GeneratorError"); + + rb_global_variable(&eNestingError); + eNestingError = rb_path2class("JSON::NestingError"); + + cState = rb_define_class_under(mGenerator, "State", rb_cObject); + rb_define_alloc_func(cState, cState_s_allocate); + rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1); + rb_define_method(cState, "initialize", cState_initialize, -1); + rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings + rb_define_private_method(cState, "_configure", cState_configure, 1); + + rb_define_method(cState, "initialize_copy", cState_init_copy, 1); + rb_define_method(cState, "indent", cState_indent, 0); + rb_define_method(cState, "indent=", cState_indent_set, 1); + rb_define_method(cState, "space", cState_space, 0); + rb_define_method(cState, "space=", cState_space_set, 1); + rb_define_method(cState, "space_before", cState_space_before, 0); + rb_define_method(cState, "space_before=", cState_space_before_set, 1); + rb_define_method(cState, "object_nl", cState_object_nl, 0); + rb_define_method(cState, "object_nl=", cState_object_nl_set, 1); + rb_define_method(cState, "array_nl", cState_array_nl, 0); + rb_define_method(cState, "array_nl=", cState_array_nl_set, 1); + rb_define_method(cState, "as_json", cState_as_json, 0); + rb_define_method(cState, "as_json=", cState_as_json_set, 1); + rb_define_method(cState, "max_nesting", cState_max_nesting, 0); + rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1); + rb_define_method(cState, "script_safe", cState_script_safe, 0); + rb_define_method(cState, "script_safe?", cState_script_safe, 0); + rb_define_method(cState, "script_safe=", cState_script_safe_set, 1); + rb_define_alias(cState, "escape_slash", "script_safe"); + rb_define_alias(cState, "escape_slash?", "script_safe?"); + rb_define_alias(cState, "escape_slash=", "script_safe="); + rb_define_method(cState, "strict", cState_strict, 0); + rb_define_method(cState, "strict?", cState_strict, 0); + rb_define_method(cState, "strict=", cState_strict_set, 1); + rb_define_method(cState, "check_circular?", cState_check_circular_p, 0); + rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0); + rb_define_method(cState, "allow_nan=", cState_allow_nan_set, 1); + rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0); + rb_define_method(cState, "ascii_only=", cState_ascii_only_set, 1); + rb_define_method(cState, "depth", cState_depth, 0); + rb_define_method(cState, "depth=", cState_depth_set, 1); + rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0); + rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1); + rb_define_method(cState, "generate", cState_generate, -1); + rb_define_alias(cState, "generate_new", "generate"); // :nodoc: + + rb_define_singleton_method(cState, "generate", cState_m_generate, 3); + + VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods"); + + VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object"); + rb_define_method(mObject, "to_json", mObject_to_json, -1); + + VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash"); + rb_define_method(mHash, "to_json", mHash_to_json, -1); + + VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array"); + rb_define_method(mArray, "to_json", mArray_to_json, -1); + +#ifdef RUBY_INTEGER_UNIFICATION + VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer"); + rb_define_method(mInteger, "to_json", mInteger_to_json, -1); +#else + VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum"); + rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1); + + VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum"); + rb_define_method(mBignum, "to_json", mBignum_to_json, -1); +#endif + VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float"); + rb_define_method(mFloat, "to_json", mFloat_to_json, -1); + + VALUE mString = rb_define_module_under(mGeneratorMethods, "String"); + rb_define_singleton_method(mString, "included", mString_included_s, 1); + rb_define_method(mString, "to_json", mString_to_json, -1); + rb_define_method(mString, "to_json_raw", mString_to_json_raw, -1); + rb_define_method(mString, "to_json_raw_object", mString_to_json_raw_object, 0); + + mString_Extend = rb_define_module_under(mString, "Extend"); + rb_define_method(mString_Extend, "json_create", mString_Extend_json_create, 1); + + VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass"); + rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1); + + VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass"); + rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1); + + VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass"); + rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1); + + rb_global_variable(&Encoding_UTF_8); + Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8")); + + i_to_s = rb_intern("to_s"); + i_to_json = rb_intern("to_json"); + i_new = rb_intern("new"); + i_pack = rb_intern("pack"); + i_unpack = rb_intern("unpack"); + i_create_id = rb_intern("create_id"); + i_extend = rb_intern("extend"); + i_encode = rb_intern("encode"); + + sym_indent = ID2SYM(rb_intern("indent")); + sym_space = ID2SYM(rb_intern("space")); + sym_space_before = ID2SYM(rb_intern("space_before")); + sym_object_nl = ID2SYM(rb_intern("object_nl")); + sym_array_nl = ID2SYM(rb_intern("array_nl")); + sym_max_nesting = ID2SYM(rb_intern("max_nesting")); + sym_allow_nan = ID2SYM(rb_intern("allow_nan")); + sym_ascii_only = ID2SYM(rb_intern("ascii_only")); + sym_depth = ID2SYM(rb_intern("depth")); + sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length")); + sym_script_safe = ID2SYM(rb_intern("script_safe")); + sym_escape_slash = ID2SYM(rb_intern("escape_slash")); + sym_strict = ID2SYM(rb_intern("strict")); + sym_as_json = ID2SYM(rb_intern("as_json")); + + usascii_encindex = rb_usascii_encindex(); + utf8_encindex = rb_utf8_encindex(); + binary_encindex = rb_ascii8bit_encindex(); + + rb_require("json/ext/generator/state"); +} diff --git a/bin/gems/json-2.10.2/ext/json/ext/parser/Makefile b/bin/gems/json-2.10.2/ext/json/ext/parser/Makefile new file mode 100644 index 00000000..4ae6e954 --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/parser/Makefile @@ -0,0 +1,269 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = . +topdir = /usr/include/ruby-3.2.0 +hdrdir = $(topdir) +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR)/etc +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ +LIBRUBY = $(LIBRUBY_SO) +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = -fPIC +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 -fPIC -std=c99 $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = +CPPFLAGS = -DHAVE_RB_ENC_INTERNED_STR -DHAVE_RB_HASH_NEW_CAPA -DHAVE_RB_HASH_BULK_INSERT -DHAVE_RB_CATEGORY_WARN -DHAVE_STRNLEN -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.8 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now +ARCH_FLAG = +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CC) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-linux-gnu-gcc-ar +EXEEXT = + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 +RUBYW_INSTALL_NAME = +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x86_64-linux-gnu +sitearch = $(arch) +ruby_version = 3.2.0 +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 +RUBY = $(ruby) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h + +RM = rm -f +RM_RF = rm -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) +DEFFILE = + +CLEANFILES = mkmf.log +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = /json/ext +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc +ORIG_SRCS = parser.c +SRCS = $(ORIG_SRCS) +OBJS = parser.o +HDRS = +LOCAL_HDRS = +TARGET = parser +TARGET_NAME = parser +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = $(OBJS) *.bak +TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.-.json.-.ext.time + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP) + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + -$(Q)$(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TARGET_SO_DIR_TIMESTAMP): + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(OBJS) Makefile + $(ECHO) linking shared-object json/ext/$(DLLIB) + -$(Q)$(RM) $(@) + $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) + + + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/bin/gems/json-2.10.2/ext/json/ext/parser/extconf.rb b/bin/gems/json-2.10.2/ext/json/ext/parser/extconf.rb new file mode 100644 index 00000000..a8e21aed --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/parser/extconf.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +require 'mkmf' + +have_func("rb_enc_interned_str", "ruby.h") # RUBY_VERSION >= 3.0 +have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2 +have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby +have_func("rb_category_warn", "ruby.h") # Missing on TruffleRuby +have_func("strnlen", "string.h") # Missing on Solaris 10 + +append_cflags("-std=c99") + +create_makefile 'json/ext/parser' diff --git a/bin/gems/json-2.10.2/ext/json/ext/parser/parser.c b/bin/gems/json-2.10.2/ext/json/ext/parser/parser.c new file mode 100644 index 00000000..d990612a --- /dev/null +++ b/bin/gems/json-2.10.2/ext/json/ext/parser/parser.c @@ -0,0 +1,1486 @@ +#include "ruby.h" +#include "ruby/encoding.h" + +/* shims */ +/* This is the fallback definition from Ruby 3.4 */ + +#ifndef RBIMPL_STDBOOL_H +#if defined(__cplusplus) +# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L) +# include +# endif +#elif defined(HAVE_STDBOOL_H) +# include +#elif !defined(HAVE__BOOL) +typedef unsigned char _Bool; +# define bool _Bool +# define true ((_Bool)+1) +# define false ((_Bool)+0) +# define __bool_true_false_are_defined +#endif +#endif + +#ifndef RB_UNLIKELY +#define RB_UNLIKELY(expr) expr +#endif + +#ifndef RB_LIKELY +#define RB_LIKELY(expr) expr +#endif + +static VALUE mJSON, eNestingError, Encoding_UTF_8; +static VALUE CNaN, CInfinity, CMinusInfinity; + +static ID i_json_creatable_p, i_json_create, i_create_id, + i_chr, i_deep_const_get, i_match, i_aset, i_aref, + i_leftshift, i_new, i_try_convert, i_uminus, i_encode; + +static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze, + sym_create_additions, sym_create_id, sym_object_class, sym_array_class, + sym_decimal_class, sym_match_string; + +static int binary_encindex; +static int utf8_encindex; + +#ifdef HAVE_RB_CATEGORY_WARN +# define json_deprecated(message) rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, message) +#else +# define json_deprecated(message) rb_warn(message) +#endif + +static const char deprecated_create_additions_warning[] = + "JSON.load implicit support for `create_additions: true` is deprecated " + "and will be removed in 3.0, use JSON.unsafe_load or explicitly " + "pass `create_additions: true`"; + +#ifndef HAVE_RB_HASH_BULK_INSERT +// For TruffleRuby +void +rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash) +{ + long index = 0; + while (index < count) { + VALUE name = pairs[index++]; + VALUE value = pairs[index++]; + rb_hash_aset(hash, name, value); + } + RB_GC_GUARD(hash); +} +#endif + +#ifndef HAVE_RB_HASH_NEW_CAPA +#define rb_hash_new_capa(n) rb_hash_new() +#endif + + +/* name cache */ + +#include +#include + +// Object names are likely to be repeated, and are frozen. +// As such we can re-use them if we keep a cache of the ones we've seen so far, +// and save much more expensive lookups into the global fstring table. +// This cache implementation is deliberately simple, as we're optimizing for compactness, +// to be able to fit safely on the stack. +// As such, binary search into a sorted array gives a good tradeoff between compactness and +// performance. +#define JSON_RVALUE_CACHE_CAPA 63 +typedef struct rvalue_cache_struct { + int length; + VALUE entries[JSON_RVALUE_CACHE_CAPA]; +} rvalue_cache; + +static rb_encoding *enc_utf8; + +#define JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH 55 + +static inline VALUE build_interned_string(const char *str, const long length) +{ +# ifdef HAVE_RB_ENC_INTERNED_STR + return rb_enc_interned_str(str, length, enc_utf8); +# else + VALUE rstring = rb_utf8_str_new(str, length); + return rb_funcall(rb_str_freeze(rstring), i_uminus, 0); +# endif +} + +static inline VALUE build_symbol(const char *str, const long length) +{ + return rb_str_intern(build_interned_string(str, length)); +} + +static void rvalue_cache_insert_at(rvalue_cache *cache, int index, VALUE rstring) +{ + MEMMOVE(&cache->entries[index + 1], &cache->entries[index], VALUE, cache->length - index); + cache->length++; + cache->entries[index] = rstring; +} + +static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring) +{ + long rstring_length = RSTRING_LEN(rstring); + if (length == rstring_length) { + return memcmp(str, RSTRING_PTR(rstring), length); + } else { + return (int)(length - rstring_length); + } +} + +static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length) +{ + if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) { + // Common names aren't likely to be very long. So we just don't + // cache names above an arbitrary threshold. + return Qfalse; + } + + if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) { + // Simple heuristic, if the first character isn't a letter, + // we're much less likely to see this string again. + // We mostly want to cache strings that are likely to be repeated. + return Qfalse; + } + + int low = 0; + int high = cache->length - 1; + int mid = 0; + int last_cmp = 0; + + while (low <= high) { + mid = (high + low) >> 1; + VALUE entry = cache->entries[mid]; + last_cmp = rstring_cache_cmp(str, length, entry); + + if (last_cmp == 0) { + return entry; + } else if (last_cmp > 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + if (RB_UNLIKELY(memchr(str, '\\', length))) { + // We assume the overwhelming majority of names don't need to be escaped. + // But if they do, we have to fallback to the slow path. + return Qfalse; + } + + VALUE rstring = build_interned_string(str, length); + + if (cache->length < JSON_RVALUE_CACHE_CAPA) { + if (last_cmp > 0) { + mid += 1; + } + + rvalue_cache_insert_at(cache, mid, rstring); + } + return rstring; +} + +static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const long length) +{ + if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) { + // Common names aren't likely to be very long. So we just don't + // cache names above an arbitrary threshold. + return Qfalse; + } + + if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) { + // Simple heuristic, if the first character isn't a letter, + // we're much less likely to see this string again. + // We mostly want to cache strings that are likely to be repeated. + return Qfalse; + } + + int low = 0; + int high = cache->length - 1; + int mid = 0; + int last_cmp = 0; + + while (low <= high) { + mid = (high + low) >> 1; + VALUE entry = cache->entries[mid]; + last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry)); + + if (last_cmp == 0) { + return entry; + } else if (last_cmp > 0) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + if (RB_UNLIKELY(memchr(str, '\\', length))) { + // We assume the overwhelming majority of names don't need to be escaped. + // But if they do, we have to fallback to the slow path. + return Qfalse; + } + + VALUE rsymbol = build_symbol(str, length); + + if (cache->length < JSON_RVALUE_CACHE_CAPA) { + if (last_cmp > 0) { + mid += 1; + } + + rvalue_cache_insert_at(cache, mid, rsymbol); + } + return rsymbol; +} + +/* rvalue stack */ + +#define RVALUE_STACK_INITIAL_CAPA 128 + +enum rvalue_stack_type { + RVALUE_STACK_HEAP_ALLOCATED = 0, + RVALUE_STACK_STACK_ALLOCATED = 1, +}; + +typedef struct rvalue_stack_struct { + enum rvalue_stack_type type; + long capa; + long head; + VALUE *ptr; +} rvalue_stack; + +static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref); + +static rvalue_stack *rvalue_stack_grow(rvalue_stack *stack, VALUE *handle, rvalue_stack **stack_ref) +{ + long required = stack->capa * 2; + + if (stack->type == RVALUE_STACK_STACK_ALLOCATED) { + stack = rvalue_stack_spill(stack, handle, stack_ref); + } else { + REALLOC_N(stack->ptr, VALUE, required); + stack->capa = required; + } + return stack; +} + +static VALUE rvalue_stack_push(rvalue_stack *stack, VALUE value, VALUE *handle, rvalue_stack **stack_ref) +{ + if (RB_UNLIKELY(stack->head >= stack->capa)) { + stack = rvalue_stack_grow(stack, handle, stack_ref); + } + stack->ptr[stack->head] = value; + stack->head++; + return value; +} + +static inline VALUE *rvalue_stack_peek(rvalue_stack *stack, long count) +{ + return stack->ptr + (stack->head - count); +} + +static inline void rvalue_stack_pop(rvalue_stack *stack, long count) +{ + stack->head -= count; +} + +static void rvalue_stack_mark(void *ptr) +{ + rvalue_stack *stack = (rvalue_stack *)ptr; + long index; + for (index = 0; index < stack->head; index++) { + rb_gc_mark(stack->ptr[index]); + } +} + +static void rvalue_stack_free(void *ptr) +{ + rvalue_stack *stack = (rvalue_stack *)ptr; + if (stack) { + ruby_xfree(stack->ptr); + ruby_xfree(stack); + } +} + +static size_t rvalue_stack_memsize(const void *ptr) +{ + const rvalue_stack *stack = (const rvalue_stack *)ptr; + return sizeof(rvalue_stack) + sizeof(VALUE) * stack->capa; +} + +static const rb_data_type_t JSON_Parser_rvalue_stack_type = { + "JSON::Ext::Parser/rvalue_stack", + { + .dmark = rvalue_stack_mark, + .dfree = rvalue_stack_free, + .dsize = rvalue_stack_memsize, + }, + 0, 0, + RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref) +{ + rvalue_stack *stack; + *handle = TypedData_Make_Struct(0, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack); + *stack_ref = stack; + MEMCPY(stack, old_stack, rvalue_stack, 1); + + stack->capa = old_stack->capa << 1; + stack->ptr = ALLOC_N(VALUE, stack->capa); + stack->type = RVALUE_STACK_HEAP_ALLOCATED; + MEMCPY(stack->ptr, old_stack->ptr, VALUE, old_stack->head); + return stack; +} + +static void rvalue_stack_eagerly_release(VALUE handle) +{ + if (handle) { + rvalue_stack *stack; + TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack); + RTYPEDDATA_DATA(handle) = NULL; + rvalue_stack_free(stack); + } +} + + +#ifndef HAVE_STRNLEN +static size_t strnlen(const char *s, size_t maxlen) +{ + char *p; + return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen); +} +#endif + +#define PARSE_ERROR_FRAGMENT_LEN 32 +#ifdef RBIMPL_ATTR_NORETURN +RBIMPL_ATTR_NORETURN() +#endif +static void raise_parse_error(const char *format, const char *start) +{ + unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1]; + + size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0; + const char *ptr = start; + + if (len == PARSE_ERROR_FRAGMENT_LEN) { + MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN); + + while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte + len--; + } + + if (buffer[len - 1] >= 0xC0) { // multibyte character start + len--; + } + + buffer[len] = '\0'; + ptr = (const char *)buffer; + } + + rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr); +} + +/* unicode */ + +static const signed char digit_values[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, + -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1 +}; + +static uint32_t unescape_unicode(const unsigned char *p) +{ + signed char b; + uint32_t result = 0; + b = digit_values[p[0]]; + if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2); + result = (result << 4) | (unsigned char)b; + b = digit_values[p[1]]; + if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2); + result = (result << 4) | (unsigned char)b; + b = digit_values[p[2]]; + if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2); + result = (result << 4) | (unsigned char)b; + b = digit_values[p[3]]; + if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2); + result = (result << 4) | (unsigned char)b; + return result; +} + +static int convert_UTF32_to_UTF8(char *buf, uint32_t ch) +{ + int len = 1; + if (ch <= 0x7F) { + buf[0] = (char) ch; + } else if (ch <= 0x07FF) { + buf[0] = (char) ((ch >> 6) | 0xC0); + buf[1] = (char) ((ch & 0x3F) | 0x80); + len++; + } else if (ch <= 0xFFFF) { + buf[0] = (char) ((ch >> 12) | 0xE0); + buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80); + buf[2] = (char) ((ch & 0x3F) | 0x80); + len += 2; + } else if (ch <= 0x1fffff) { + buf[0] =(char) ((ch >> 18) | 0xF0); + buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80); + buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80); + buf[3] =(char) ((ch & 0x3F) | 0x80); + len += 3; + } else { + buf[0] = '?'; + } + return len; +} + +typedef struct JSON_ParserStruct { + VALUE create_id; + VALUE object_class; + VALUE array_class; + VALUE decimal_class; + ID decimal_method_id; + VALUE match_string; + int max_nesting; + bool allow_nan; + bool allow_trailing_comma; + bool parsing_name; + bool symbolize_names; + bool freeze; + bool create_additions; + bool deprecated_create_additions; +} JSON_ParserConfig; + +typedef struct JSON_ParserStateStruct { + VALUE stack_handle; + const char *cursor; + const char *end; + rvalue_stack *stack; + rvalue_cache name_cache; + int in_array; + int current_nesting; +} JSON_ParserState; + +#define GET_PARSER_CONFIG \ + JSON_ParserConfig *config; \ + TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config) + +static const rb_data_type_t JSON_ParserConfig_type; + +static const bool whitespace[256] = { + [' '] = 1, + ['\t'] = 1, + ['\n'] = 1, + ['\r'] = 1, + ['/'] = 1, +}; + +static void +json_eat_comments(JSON_ParserState *state) +{ + if (state->cursor + 1 < state->end) { + switch(state->cursor[1]) { + case '/': { + state->cursor = memchr(state->cursor, '\n', state->end - state->cursor); + if (!state->cursor) { + state->cursor = state->end; + } else { + state->cursor++; + } + break; + } + case '*': { + state->cursor += 2; + while (true) { + state->cursor = memchr(state->cursor, '*', state->end - state->cursor); + if (!state->cursor) { + state->cursor = state->end; + raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor); + } else { + state->cursor++; + if (state->cursor < state->end && *state->cursor == '/') { + state->cursor++; + break; + } + } + } + break; + } + default: + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + } + } else { + raise_parse_error("unexpected token at '%s'", state->cursor); + } +} + +static inline void +json_eat_whitespace(JSON_ParserState *state) +{ + while (state->cursor < state->end && RB_UNLIKELY(whitespace[(unsigned char)*state->cursor])) { + if (RB_LIKELY(*state->cursor != '/')) { + state->cursor++; + } else { + json_eat_comments(state); + } + } +} + +static inline VALUE build_string(const char *start, const char *end, bool intern, bool symbolize) +{ + if (symbolize) { + intern = true; + } + VALUE result; +# ifdef HAVE_RB_ENC_INTERNED_STR + if (intern) { + result = rb_enc_interned_str(start, (long)(end - start), enc_utf8); + } else { + result = rb_utf8_str_new(start, (long)(end - start)); + } +# else + result = rb_utf8_str_new(start, (long)(end - start)); + if (intern) { + result = rb_funcall(rb_str_freeze(result), i_uminus, 0); + } +# endif + + if (symbolize) { + result = rb_str_intern(result); + } + + return result; +} + +static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize) +{ + size_t bufferSize = stringEnd - string; + + if (is_name && state->in_array) { + VALUE cached_key; + if (RB_UNLIKELY(symbolize)) { + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); + } else { + cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize); + } + + if (RB_LIKELY(cached_key)) { + return cached_key; + } + } + + return build_string(string, stringEnd, intern, symbolize); +} + +static VALUE json_string_unescape(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize) +{ + size_t bufferSize = stringEnd - string; + const char *p = string, *pe = string, *unescape, *bufferStart; + char *buffer; + int unescape_len; + char buf[4]; + + if (is_name && state->in_array) { + VALUE cached_key; + if (RB_UNLIKELY(symbolize)) { + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); + } else { + cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize); + } + + if (RB_LIKELY(cached_key)) { + return cached_key; + } + } + + VALUE result = rb_str_buf_new(bufferSize); + rb_enc_associate_index(result, utf8_encindex); + buffer = RSTRING_PTR(result); + bufferStart = buffer; + + while (pe < stringEnd && (pe = memchr(pe, '\\', stringEnd - pe))) { + unescape = (char *) "?"; + unescape_len = 1; + if (pe > p) { + MEMCPY(buffer, p, char, pe - p); + buffer += pe - p; + } + switch (*++pe) { + case 'n': + unescape = (char *) "\n"; + break; + case 'r': + unescape = (char *) "\r"; + break; + case 't': + unescape = (char *) "\t"; + break; + case '"': + unescape = (char *) "\""; + break; + case '\\': + unescape = (char *) "\\"; + break; + case 'b': + unescape = (char *) "\b"; + break; + case 'f': + unescape = (char *) "\f"; + break; + case 'u': + if (pe > stringEnd - 5) { + raise_parse_error("incomplete unicode character escape sequence at '%s'", p); + } else { + uint32_t ch = unescape_unicode((unsigned char *) ++pe); + pe += 3; + /* To handle values above U+FFFF, we take a sequence of + * \uXXXX escapes in the U+D800..U+DBFF then + * U+DC00..U+DFFF ranges, take the low 10 bits from each + * to make a 20-bit number, then add 0x10000 to get the + * final codepoint. + * + * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling + * Surrogate Pairs in UTF-16", and 23.6 "Surrogates + * Area". + */ + if ((ch & 0xFC00) == 0xD800) { + pe++; + if (pe > stringEnd - 6) { + raise_parse_error("incomplete surrogate pair at '%s'", p); + } + if (pe[0] == '\\' && pe[1] == 'u') { + uint32_t sur = unescape_unicode((unsigned char *) pe + 2); + ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16) + | (sur & 0x3FF)); + pe += 5; + } else { + unescape = (char *) "?"; + break; + } + } + unescape_len = convert_UTF32_to_UTF8(buf, ch); + unescape = buf; + } + break; + default: + p = pe; + continue; + } + MEMCPY(buffer, unescape, char, unescape_len); + buffer += unescape_len; + p = ++pe; + } + + if (stringEnd > p) { + MEMCPY(buffer, p, char, stringEnd - p); + buffer += stringEnd - p; + } + rb_str_set_len(result, buffer - bufferStart); + + if (symbolize) { + result = rb_str_intern(result); + } else if (intern) { + result = rb_funcall(rb_str_freeze(result), i_uminus, 0); + } + + return result; +} + +#define MAX_FAST_INTEGER_SIZE 18 +static inline VALUE fast_decode_integer(const char *p, const char *pe) +{ + bool negative = false; + if (*p == '-') { + negative = true; + p++; + } + + long long memo = 0; + while (p < pe) { + memo *= 10; + memo += *p - '0'; + p++; + } + + if (negative) { + memo = -memo; + } + return LL2NUM(memo); +} + +static VALUE json_decode_large_integer(const char *start, long len) +{ + VALUE buffer_v; + char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + VALUE number = rb_cstr2inum(buffer, 10); + RB_ALLOCV_END(buffer_v); + return number; +} + +static inline VALUE +json_decode_integer(const char *start, const char *end) +{ + long len = end - start; + if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) { + return fast_decode_integer(start, end); + } + return json_decode_large_integer(start, len); +} + +static VALUE json_decode_large_float(const char *start, long len) +{ + VALUE buffer_v; + char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1)); + RB_ALLOCV_END(buffer_v); + return number; +} + +static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, const char *end) +{ + long len = end - start; + + if (RB_UNLIKELY(config->decimal_class)) { + VALUE text = rb_str_new(start, len); + return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text); + } else if (RB_LIKELY(len < 64)) { + char buffer[64]; + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + return DBL2NUM(rb_cstr_to_dbl(buffer, 1)); + } else { + return json_decode_large_float(start, len); + } +} + +static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count) +{ + VALUE array; + if (RB_UNLIKELY(config->array_class)) { + array = rb_class_new_instance(0, 0, config->array_class); + VALUE *items = rvalue_stack_peek(state->stack, count); + long index; + for (index = 0; index < count; index++) { + rb_funcall(array, i_leftshift, 1, items[index]); + } + } else { + array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count)); + } + + rvalue_stack_pop(state->stack, count); + + if (config->freeze) { + RB_OBJ_FREEZE(array); + } + + return array; +} + +static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count) +{ + VALUE object; + if (RB_UNLIKELY(config->object_class)) { + object = rb_class_new_instance(0, 0, config->object_class); + long index = 0; + VALUE *items = rvalue_stack_peek(state->stack, count); + while (index < count) { + VALUE name = items[index++]; + VALUE value = items[index++]; + rb_funcall(object, i_aset, 2, name, value); + } + } else { + object = rb_hash_new_capa(count); + rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object); + } + + rvalue_stack_pop(state->stack, count); + + if (RB_UNLIKELY(config->create_additions)) { + VALUE klassname; + if (config->object_class) { + klassname = rb_funcall(object, i_aref, 1, config->create_id); + } else { + klassname = rb_hash_aref(object, config->create_id); + } + if (!NIL_P(klassname)) { + VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname); + if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) { + if (config->deprecated_create_additions) { + json_deprecated(deprecated_create_additions_warning); + } + object = rb_funcall(klass, i_json_create, 1, object); + } + } + } + + if (config->freeze) { + RB_OBJ_FREEZE(object); + } + + return object; +} + +static int match_i(VALUE regexp, VALUE klass, VALUE memo) +{ + if (regexp == Qundef) return ST_STOP; + if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) && + RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) { + rb_ary_push(memo, klass); + return ST_STOP; + } + return ST_CONTINUE; +} + +static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name) +{ + VALUE string; + bool intern = is_name || config->freeze; + bool symbolize = is_name && config->symbolize_names; + if (escaped) { + string = json_string_unescape(state, start, end, is_name, intern, symbolize); + } else { + string = json_string_fastpath(state, start, end, is_name, intern, symbolize); + } + + if (RB_UNLIKELY(config->create_additions && RTEST(config->match_string))) { + VALUE klass; + VALUE memo = rb_ary_new2(2); + rb_ary_push(memo, string); + rb_hash_foreach(config->match_string, match_i, memo); + klass = rb_ary_entry(memo, 1); + if (RTEST(klass)) { + string = rb_funcall(klass, i_json_create, 1, string); + } + } + + return string; +} + +#define PUSH(result) rvalue_stack_push(state->stack, result, &state->stack_handle, &state->stack) + +static const bool string_scan[256] = { + // ASCII Control Characters + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + // ASCII Characters + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // '\\' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name) +{ + state->cursor++; + const char *start = state->cursor; + bool escaped = false; + + while (state->cursor < state->end) { + if (RB_UNLIKELY(string_scan[(unsigned char)*state->cursor])) { + switch (*state->cursor) { + case '"': { + VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name); + state->cursor++; + return PUSH(string); + } + case '\\': { + state->cursor++; + escaped = true; + if ((unsigned char)*state->cursor < 0x20) { + raise_parse_error("invalid ASCII control character in string: %s", state->cursor); + } + break; + } + default: + raise_parse_error("invalid ASCII control character in string: %s", state->cursor); + break; + } + } + + state->cursor++; + } + + raise_parse_error("unexpected end of input, expected closing \"", state->cursor); + return Qfalse; +} + +static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) +{ + json_eat_whitespace(state); + if (state->cursor >= state->end) { + raise_parse_error("unexpected end of input", state->cursor); + } + + switch (*state->cursor) { + case 'n': + if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) { + state->cursor += 4; + return PUSH(Qnil); + } + + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + case 't': + if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) { + state->cursor += 4; + return PUSH(Qtrue); + } + + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + case 'f': + // Note: memcmp with a small power of two compile to an integer comparison + if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) { + state->cursor += 5; + return PUSH(Qfalse); + } + + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + case 'N': + // Note: memcmp with a small power of two compile to an integer comparison + if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) { + state->cursor += 3; + return PUSH(CNaN); + } + + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + case 'I': + if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) { + state->cursor += 8; + return PUSH(CInfinity); + } + + raise_parse_error("unexpected token at '%s'", state->cursor); + break; + case '-': + // Note: memcmp with a small power of two compile to an integer comparison + if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) { + if (config->allow_nan) { + state->cursor += 9; + return PUSH(CMinusInfinity); + } else { + raise_parse_error("unexpected token at '%s'", state->cursor); + } + } + // Fallthrough + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { + bool integer = true; + + // /\A-?(0|[1-9]\d*)(\.\d+)?([Ee][-+]?\d+)?/ + const char *start = state->cursor; + state->cursor++; + + while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) { + state->cursor++; + } + + long integer_length = state->cursor - start; + + if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) { + raise_parse_error("invalid number: %s", start); + } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) { + raise_parse_error("invalid number: %s", start); + } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) { + raise_parse_error("invalid number: %s", start); + } + + if ((state->cursor < state->end) && (*state->cursor == '.')) { + integer = false; + state->cursor++; + + if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') { + raise_parse_error("invalid number: %s", state->cursor); + } + + while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) { + state->cursor++; + } + } + + if ((state->cursor < state->end) && ((*state->cursor == 'e') || (*state->cursor == 'E'))) { + integer = false; + state->cursor++; + if ((state->cursor < state->end) && ((*state->cursor == '+') || (*state->cursor == '-'))) { + state->cursor++; + } + + if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') { + raise_parse_error("invalid number: %s", state->cursor); + } + + while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) { + state->cursor++; + } + } + + if (integer) { + return PUSH(json_decode_integer(start, state->cursor)); + } + return PUSH(json_decode_float(config, start, state->cursor)); + } + case '"': { + // %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"} + return json_parse_string(state, config, false); + break; + } + case '[': { + state->cursor++; + json_eat_whitespace(state); + long stack_head = state->stack->head; + + if ((state->cursor < state->end) && (*state->cursor == ']')) { + state->cursor++; + return PUSH(json_decode_array(state, config, 0)); + } else { + state->current_nesting++; + if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) { + rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting); + } + state->in_array++; + json_parse_any(state, config); + } + + while (true) { + json_eat_whitespace(state); + + if (state->cursor < state->end) { + if (*state->cursor == ']') { + state->cursor++; + long count = state->stack->head - stack_head; + state->current_nesting--; + state->in_array--; + return PUSH(json_decode_array(state, config, count)); + } + + if (*state->cursor == ',') { + state->cursor++; + if (config->allow_trailing_comma) { + json_eat_whitespace(state); + if ((state->cursor < state->end) && (*state->cursor == ']')) { + continue; + } + } + json_parse_any(state, config); + continue; + } + } + + raise_parse_error("expected ',' or ']' after array value", state->cursor); + } + break; + } + case '{': { + state->cursor++; + json_eat_whitespace(state); + long stack_head = state->stack->head; + + if ((state->cursor < state->end) && (*state->cursor == '}')) { + state->cursor++; + return PUSH(json_decode_object(state, config, 0)); + } else { + state->current_nesting++; + if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) { + rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting); + } + + if (*state->cursor != '"') { + raise_parse_error("expected object key, got '%s", state->cursor); + } + json_parse_string(state, config, true); + + json_eat_whitespace(state); + if ((state->cursor >= state->end) || (*state->cursor != ':')) { + raise_parse_error("expected ':' after object key", state->cursor); + } + state->cursor++; + + json_parse_any(state, config); + } + + while (true) { + json_eat_whitespace(state); + + if (state->cursor < state->end) { + if (*state->cursor == '}') { + state->cursor++; + state->current_nesting--; + long count = state->stack->head - stack_head; + return PUSH(json_decode_object(state, config, count)); + } + + if (*state->cursor == ',') { + state->cursor++; + json_eat_whitespace(state); + + if (config->allow_trailing_comma) { + if ((state->cursor < state->end) && (*state->cursor == '}')) { + continue; + } + } + + if (*state->cursor != '"') { + raise_parse_error("expected object key, got: '%s'", state->cursor); + } + json_parse_string(state, config, true); + + json_eat_whitespace(state); + if ((state->cursor >= state->end) || (*state->cursor != ':')) { + raise_parse_error("expected ':' after object key, got: '%s", state->cursor); + } + state->cursor++; + + json_parse_any(state, config); + + continue; + } + } + + raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor); + } + break; + } + + default: + raise_parse_error("unexpected character: '%s'", state->cursor); + break; + } + + raise_parse_error("unreacheable: '%s'", state->cursor); +} + +static void json_ensure_eof(JSON_ParserState *state) +{ + json_eat_whitespace(state); + if (state->cursor != state->end) { + raise_parse_error("unexpected token at end of stream '%s'", state->cursor); + } +} + +/* + * Document-class: JSON::Ext::Parser + * + * This is the JSON parser implemented as a C extension. It can be configured + * to be used by setting + * + * JSON.parser = JSON::Ext::Parser + * + * with the method parser= in JSON. + * + */ + +static VALUE convert_encoding(VALUE source) +{ + int encindex = RB_ENCODING_GET(source); + + if (RB_LIKELY(encindex == utf8_encindex)) { + return source; + } + + if (encindex == binary_encindex) { + // For historical reason, we silently reinterpret binary strings as UTF-8 + return rb_enc_associate_index(rb_str_dup(source), utf8_encindex); + } + + return rb_funcall(source, i_encode, 1, Encoding_UTF_8); +} + +static int parser_config_init_i(VALUE key, VALUE val, VALUE data) +{ + JSON_ParserConfig *config = (JSON_ParserConfig *)data; + + if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; } + else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); } + else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); } + else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); } + else if (key == sym_freeze) { config->freeze = RTEST(val); } + else if (key == sym_create_id) { config->create_id = RTEST(val) ? val : Qfalse; } + else if (key == sym_object_class) { config->object_class = RTEST(val) ? val : Qfalse; } + else if (key == sym_array_class) { config->array_class = RTEST(val) ? val : Qfalse; } + else if (key == sym_match_string) { config->match_string = RTEST(val) ? val : Qfalse; } + else if (key == sym_decimal_class) { + if (RTEST(val)) { + if (rb_respond_to(val, i_try_convert)) { + config->decimal_class = val; + config->decimal_method_id = i_try_convert; + } else if (rb_respond_to(val, i_new)) { + config->decimal_class = val; + config->decimal_method_id = i_new; + } else if (RB_TYPE_P(val, T_CLASS)) { + VALUE name = rb_class_name(val); + const char *name_cstr = RSTRING_PTR(name); + const char *last_colon = strrchr(name_cstr, ':'); + if (last_colon) { + const char *mod_path_end = last_colon - 1; + VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr); + config->decimal_class = rb_path_to_class(mod_path); + + const char *method_name_beg = last_colon + 1; + long before_len = method_name_beg - name_cstr; + long len = RSTRING_LEN(name) - before_len; + VALUE method_name = rb_str_substr(name, before_len, len); + config->decimal_method_id = SYM2ID(rb_str_intern(method_name)); + } else { + config->decimal_class = rb_mKernel; + config->decimal_method_id = SYM2ID(rb_str_intern(name)); + } + } + } + } + else if (key == sym_create_additions) { + if (NIL_P(val)) { + config->create_additions = true; + config->deprecated_create_additions = true; + } else { + config->create_additions = RTEST(val); + config->deprecated_create_additions = false; + } + } + + return ST_CONTINUE; +} + +static void parser_config_init(JSON_ParserConfig *config, VALUE opts) +{ + config->max_nesting = 100; + + if (!NIL_P(opts)) { + Check_Type(opts, T_HASH); + if (RHASH_SIZE(opts) > 0) { + // We assume in most cases few keys are set so it's faster to go over + // the provided keys than to check all possible keys. + rb_hash_foreach(opts, parser_config_init_i, (VALUE)config); + + if (config->symbolize_names && config->create_additions) { + rb_raise(rb_eArgError, + "options :symbolize_names and :create_additions cannot be " + " used in conjunction"); + } + + if (config->create_additions && !config->create_id) { + config->create_id = rb_funcall(mJSON, i_create_id, 0); + } + } + + } +} + +/* + * call-seq: new(opts => {}) + * + * Creates a new JSON::Ext::ParserConfig instance. + * + * It will be configured by the _opts_ hash. _opts_ can have the following + * keys: + * + * _opts_ can have the following keys: + * * *max_nesting*: The maximum depth of nesting allowed in the parsed data + * structures. Disable depth checking with :max_nesting => false|nil|0, it + * defaults to 100. + * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in + * defiance of RFC 4627 to be parsed by the Parser. This option defaults to + * false. + * * *symbolize_names*: If set to true, returns symbols for the names + * (keys) in a JSON object. Otherwise strings are returned, which is + * also the default. It's not possible to use this option in + * conjunction with the *create_additions* option. + * * *create_additions*: If set to false, the Parser doesn't create + * additions even if a matching class and create_id was found. This option + * defaults to false. + * * *object_class*: Defaults to Hash. If another type is provided, it will be used + * instead of Hash to represent JSON objects. The type must respond to + * +new+ without arguments, and return an object that respond to +[]=+. + * * *array_class*: Defaults to Array If another type is provided, it will be used + * instead of Hash to represent JSON arrays. The type must respond to + * +new+ without arguments, and return an object that respond to +<<+. + * * *decimal_class*: Specifies which class to use instead of the default + * (Float) when parsing decimal numbers. This class must accept a single + * string argument in its constructor. + */ +static VALUE cParserConfig_initialize(VALUE self, VALUE opts) +{ + GET_PARSER_CONFIG; + + parser_config_init(config, opts); + + RB_OBJ_WRITTEN(self, Qundef, config->create_id); + RB_OBJ_WRITTEN(self, Qundef, config->object_class); + RB_OBJ_WRITTEN(self, Qundef, config->array_class); + RB_OBJ_WRITTEN(self, Qundef, config->decimal_class); + RB_OBJ_WRITTEN(self, Qundef, config->match_string); + + return self; +} + +static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) +{ + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); + + VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; + rvalue_stack stack = { + .type = RVALUE_STACK_STACK_ALLOCATED, + .ptr = rvalue_stack_buffer, + .capa = RVALUE_STACK_INITIAL_CAPA, + }; + + JSON_ParserState _state = { + .cursor = RSTRING_PTR(Vsource), + .end = RSTRING_END(Vsource), + .stack = &stack, + }; + JSON_ParserState *state = &_state; + + VALUE result = json_parse_any(state, config); + + // This may be skipped in case of exception, but + // it won't cause a leak. + rvalue_stack_eagerly_release(state->stack_handle); + + json_ensure_eof(state); + + return result; +} + +/* + * call-seq: parse(source) + * + * Parses the current JSON text _source_ and returns the complete data + * structure as a result. + * It raises JSON::ParserError if fail to parse. + */ +static VALUE cParserConfig_parse(VALUE self, VALUE Vsource) +{ + GET_PARSER_CONFIG; + return cParser_parse(config, Vsource); +} + +static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts) +{ + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); + + JSON_ParserConfig _config = {0}; + JSON_ParserConfig *config = &_config; + parser_config_init(config, opts); + + return cParser_parse(config, Vsource); +} + +static void JSON_ParserConfig_mark(void *ptr) +{ + JSON_ParserConfig *config = ptr; + rb_gc_mark(config->create_id); + rb_gc_mark(config->object_class); + rb_gc_mark(config->array_class); + rb_gc_mark(config->decimal_class); + rb_gc_mark(config->match_string); +} + +static void JSON_ParserConfig_free(void *ptr) +{ + JSON_ParserConfig *config = ptr; + ruby_xfree(config); +} + +static size_t JSON_ParserConfig_memsize(const void *ptr) +{ + return sizeof(JSON_ParserConfig); +} + +static const rb_data_type_t JSON_ParserConfig_type = { + "JSON::Ext::Parser/ParserConfig", + { + JSON_ParserConfig_mark, + JSON_ParserConfig_free, + JSON_ParserConfig_memsize, + }, + 0, 0, + RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE cJSON_parser_s_allocate(VALUE klass) +{ + JSON_ParserConfig *config; + return TypedData_Make_Struct(klass, JSON_ParserConfig, &JSON_ParserConfig_type, config); +} + +void Init_parser(void) +{ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + +#undef rb_intern + rb_require("json/common"); + mJSON = rb_define_module("JSON"); + VALUE mExt = rb_define_module_under(mJSON, "Ext"); + VALUE cParserConfig = rb_define_class_under(mExt, "ParserConfig", rb_cObject); + eNestingError = rb_path2class("JSON::NestingError"); + rb_gc_register_mark_object(eNestingError); + rb_define_alloc_func(cParserConfig, cJSON_parser_s_allocate); + rb_define_method(cParserConfig, "initialize", cParserConfig_initialize, 1); + rb_define_method(cParserConfig, "parse", cParserConfig_parse, 1); + + VALUE cParser = rb_define_class_under(mExt, "Parser", rb_cObject); + rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2); + + CNaN = rb_const_get(mJSON, rb_intern("NaN")); + rb_gc_register_mark_object(CNaN); + + CInfinity = rb_const_get(mJSON, rb_intern("Infinity")); + rb_gc_register_mark_object(CInfinity); + + CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity")); + rb_gc_register_mark_object(CMinusInfinity); + + rb_global_variable(&Encoding_UTF_8); + Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8")); + + sym_max_nesting = ID2SYM(rb_intern("max_nesting")); + sym_allow_nan = ID2SYM(rb_intern("allow_nan")); + sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma")); + sym_symbolize_names = ID2SYM(rb_intern("symbolize_names")); + sym_freeze = ID2SYM(rb_intern("freeze")); + sym_create_additions = ID2SYM(rb_intern("create_additions")); + sym_create_id = ID2SYM(rb_intern("create_id")); + sym_object_class = ID2SYM(rb_intern("object_class")); + sym_array_class = ID2SYM(rb_intern("array_class")); + sym_decimal_class = ID2SYM(rb_intern("decimal_class")); + sym_match_string = ID2SYM(rb_intern("match_string")); + + i_create_id = rb_intern("create_id"); + i_json_creatable_p = rb_intern("json_creatable?"); + i_json_create = rb_intern("json_create"); + i_chr = rb_intern("chr"); + i_match = rb_intern("match"); + i_deep_const_get = rb_intern("deep_const_get"); + i_aset = rb_intern("[]="); + i_aref = rb_intern("[]"); + i_leftshift = rb_intern("<<"); + i_new = rb_intern("new"); + i_try_convert = rb_intern("try_convert"); + i_uminus = rb_intern("-@"); + i_encode = rb_intern("encode"); + + binary_encindex = rb_ascii8bit_encindex(); + utf8_encindex = rb_utf8_encindex(); + enc_utf8 = rb_utf8_encoding(); +} diff --git a/bin/gems/json-2.10.2/json.gemspec b/bin/gems/json-2.10.2/json.gemspec new file mode 100644 index 00000000..943c78aa --- /dev/null +++ b/bin/gems/json-2.10.2/json.gemspec @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +version = File.foreach(File.join(__dir__, "lib/json/version.rb")) do |line| + /^\s*VERSION\s*=\s*'(.*)'/ =~ line and break $1 +end rescue nil + +spec = Gem::Specification.new do |s| + java_ext = Gem::Platform === s.platform && s.platform =~ 'java' || RUBY_ENGINE == 'jruby' + + s.name = "json" + s.version = version + + s.summary = "JSON Implementation for Ruby" + s.homepage = "https://github.com/ruby/json" + s.metadata = { + 'bug_tracker_uri' => 'https://github.com/ruby/json/issues', + 'changelog_uri' => 'https://github.com/ruby/json/blob/master/CHANGES.md', + 'documentation_uri' => 'https://docs.ruby-lang.org/en/master/JSON.html', + 'homepage_uri' => s.homepage, + 'source_code_uri' => 'https://github.com/ruby/json', + } + + s.required_ruby_version = Gem::Requirement.new(">= 2.7") + + if java_ext + s.description = "A JSON implementation as a JRuby extension." + s.author = "Daniel Luz" + s.email = "dev+ruby@mernen.com" + else + s.description = "This is a JSON implementation as a Ruby extension in C." + s.authors = ["Florian Frank"] + s.email = "flori@ping.de" + end + + s.licenses = ["Ruby"] + + s.extra_rdoc_files = ["README.md"] + s.rdoc_options = ["--title", "JSON implementation for Ruby", "--main", "README.md"] + + s.files = [ + "CHANGES.md", + "COPYING", + "BSDL", + "LEGAL", + "README.md", + "json.gemspec", + *Dir["lib/**/*.rb"], + ] + + if java_ext + s.platform = 'java' + s.files += Dir["lib/json/ext/**/*.jar"] + else + s.extensions = Dir["ext/json/**/extconf.rb"] + s.files += Dir["ext/json/**/*.{c,h}"] + end +end + +if RUBY_ENGINE == 'jruby' && $0 == __FILE__ + Gem::Builder.new(spec).build +else + spec +end diff --git a/bin/gems/json-2.10.2/lib/json.rb b/bin/gems/json-2.10.2/lib/json.rb new file mode 100644 index 00000000..dfd9b7df --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json.rb @@ -0,0 +1,587 @@ +# frozen_string_literal: true +require 'json/common' + +## +# = JavaScript \Object Notation (\JSON) +# +# \JSON is a lightweight data-interchange format. +# +# A \JSON value is one of the following: +# - Double-quoted text: "foo". +# - Number: +1+, +1.0+, +2.0e2+. +# - Boolean: +true+, +false+. +# - Null: +null+. +# - \Array: an ordered list of values, enclosed by square brackets: +# ["foo", 1, 1.0, 2.0e2, true, false, null] +# +# - \Object: a collection of name/value pairs, enclosed by curly braces; +# each name is double-quoted text; +# the values may be any \JSON values: +# {"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null} +# +# A \JSON array or object may contain nested arrays, objects, and scalars +# to any depth: +# {"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]} +# [{"foo": 0, "bar": 1}, ["baz", 2]] +# +# == Using \Module \JSON +# +# To make module \JSON available in your code, begin with: +# require 'json' +# +# All examples here assume that this has been done. +# +# === Parsing \JSON +# +# You can parse a \String containing \JSON data using +# either of two methods: +# - JSON.parse(source, opts) +# - JSON.parse!(source, opts) +# +# where +# - +source+ is a Ruby object. +# - +opts+ is a \Hash object containing options +# that control both input allowed and output formatting. +# +# The difference between the two methods +# is that JSON.parse! omits some checks +# and may not be safe for some +source+ data; +# use it only for data from trusted sources. +# Use the safer method JSON.parse for less trusted sources. +# +# ==== Parsing \JSON Arrays +# +# When +source+ is a \JSON array, JSON.parse by default returns a Ruby \Array: +# json = '["foo", 1, 1.0, 2.0e2, true, false, null]' +# ruby = JSON.parse(json) +# ruby # => ["foo", 1, 1.0, 200.0, true, false, nil] +# ruby.class # => Array +# +# The \JSON array may contain nested arrays, objects, and scalars +# to any depth: +# json = '[{"foo": 0, "bar": 1}, ["baz", 2]]' +# JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]] +# +# ==== Parsing \JSON \Objects +# +# When the source is a \JSON object, JSON.parse by default returns a Ruby \Hash: +# json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}' +# ruby = JSON.parse(json) +# ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil} +# ruby.class # => Hash +# +# The \JSON object may contain nested arrays, objects, and scalars +# to any depth: +# json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}' +# JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]} +# +# ==== Parsing \JSON Scalars +# +# When the source is a \JSON scalar (not an array or object), +# JSON.parse returns a Ruby scalar. +# +# \String: +# ruby = JSON.parse('"foo"') +# ruby # => 'foo' +# ruby.class # => String +# \Integer: +# ruby = JSON.parse('1') +# ruby # => 1 +# ruby.class # => Integer +# \Float: +# ruby = JSON.parse('1.0') +# ruby # => 1.0 +# ruby.class # => Float +# ruby = JSON.parse('2.0e2') +# ruby # => 200 +# ruby.class # => Float +# Boolean: +# ruby = JSON.parse('true') +# ruby # => true +# ruby.class # => TrueClass +# ruby = JSON.parse('false') +# ruby # => false +# ruby.class # => FalseClass +# Null: +# ruby = JSON.parse('null') +# ruby # => nil +# ruby.class # => NilClass +# +# ==== Parsing Options +# +# ====== Input Options +# +# Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed; +# defaults to +100+; specify +false+ to disable depth checking. +# +# With the default, +false+: +# source = '[0, [1, [2, [3]]]]' +# ruby = JSON.parse(source) +# ruby # => [0, [1, [2, [3]]]] +# Too deep: +# # Raises JSON::NestingError (nesting of 2 is too deep): +# JSON.parse(source, {max_nesting: 1}) +# Bad value: +# # Raises TypeError (wrong argument type Symbol (expected Fixnum)): +# JSON.parse(source, {max_nesting: :foo}) +# +# --- +# +# Option +allow_nan+ (boolean) specifies whether to allow +# NaN, Infinity, and MinusInfinity in +source+; +# defaults to +false+. +# +# With the default, +false+: +# # Raises JSON::ParserError (225: unexpected token at '[NaN]'): +# JSON.parse('[NaN]') +# # Raises JSON::ParserError (232: unexpected token at '[Infinity]'): +# JSON.parse('[Infinity]') +# # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'): +# JSON.parse('[-Infinity]') +# Allow: +# source = '[NaN, Infinity, -Infinity]' +# ruby = JSON.parse(source, {allow_nan: true}) +# ruby # => [NaN, Infinity, -Infinity] +# +# ====== Output Options +# +# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys +# should be Symbols; +# defaults to +false+ (use Strings). +# +# With the default, +false+: +# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}' +# ruby = JSON.parse(source) +# ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil} +# Use Symbols: +# ruby = JSON.parse(source, {symbolize_names: true}) +# ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil} +# +# --- +# +# Option +object_class+ (\Class) specifies the Ruby class to be used +# for each \JSON object; +# defaults to \Hash. +# +# With the default, \Hash: +# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}' +# ruby = JSON.parse(source) +# ruby.class # => Hash +# Use class \OpenStruct: +# ruby = JSON.parse(source, {object_class: OpenStruct}) +# ruby # => # +# +# --- +# +# Option +array_class+ (\Class) specifies the Ruby class to be used +# for each \JSON array; +# defaults to \Array. +# +# With the default, \Array: +# source = '["foo", 1.0, true, false, null]' +# ruby = JSON.parse(source) +# ruby.class # => Array +# Use class \Set: +# ruby = JSON.parse(source, {array_class: Set}) +# ruby # => # +# +# --- +# +# Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing. +# See {\JSON Additions}[#module-JSON-label-JSON+Additions]. +# +# === Generating \JSON +# +# To generate a Ruby \String containing \JSON data, +# use method JSON.generate(source, opts), where +# - +source+ is a Ruby object. +# - +opts+ is a \Hash object containing options +# that control both input allowed and output formatting. +# +# ==== Generating \JSON from Arrays +# +# When the source is a Ruby \Array, JSON.generate returns +# a \String containing a \JSON array: +# ruby = [0, 's', :foo] +# json = JSON.generate(ruby) +# json # => '[0,"s","foo"]' +# +# The Ruby \Array array may contain nested arrays, hashes, and scalars +# to any depth: +# ruby = [0, [1, 2], {foo: 3, bar: 4}] +# json = JSON.generate(ruby) +# json # => '[0,[1,2],{"foo":3,"bar":4}]' +# +# ==== Generating \JSON from Hashes +# +# When the source is a Ruby \Hash, JSON.generate returns +# a \String containing a \JSON object: +# ruby = {foo: 0, bar: 's', baz: :bat} +# json = JSON.generate(ruby) +# json # => '{"foo":0,"bar":"s","baz":"bat"}' +# +# The Ruby \Hash array may contain nested arrays, hashes, and scalars +# to any depth: +# ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad} +# json = JSON.generate(ruby) +# json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}' +# +# ==== Generating \JSON from Other Objects +# +# When the source is neither an \Array nor a \Hash, +# the generated \JSON data depends on the class of the source. +# +# When the source is a Ruby \Integer or \Float, JSON.generate returns +# a \String containing a \JSON number: +# JSON.generate(42) # => '42' +# JSON.generate(0.42) # => '0.42' +# +# When the source is a Ruby \String, JSON.generate returns +# a \String containing a \JSON string (with double-quotes): +# JSON.generate('A string') # => '"A string"' +# +# When the source is +true+, +false+ or +nil+, JSON.generate returns +# a \String containing the corresponding \JSON token: +# JSON.generate(true) # => 'true' +# JSON.generate(false) # => 'false' +# JSON.generate(nil) # => 'null' +# +# When the source is none of the above, JSON.generate returns +# a \String containing a \JSON string representation of the source: +# JSON.generate(:foo) # => '"foo"' +# JSON.generate(Complex(0, 0)) # => '"0+0i"' +# JSON.generate(Dir.new('.')) # => '"#"' +# +# ==== Generating Options +# +# ====== Input Options +# +# Option +allow_nan+ (boolean) specifies whether +# +NaN+, +Infinity+, and -Infinity may be generated; +# defaults to +false+. +# +# With the default, +false+: +# # Raises JSON::GeneratorError (920: NaN not allowed in JSON): +# JSON.generate(JSON::NaN) +# # Raises JSON::GeneratorError (917: Infinity not allowed in JSON): +# JSON.generate(JSON::Infinity) +# # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON): +# JSON.generate(JSON::MinusInfinity) +# +# Allow: +# ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity] +# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]' +# +# --- +# +# Option +max_nesting+ (\Integer) specifies the maximum nesting depth +# in +obj+; defaults to +100+. +# +# With the default, +100+: +# obj = [[[[[[0]]]]]] +# JSON.generate(obj) # => '[[[[[[0]]]]]]' +# +# Too deep: +# # Raises JSON::NestingError (nesting of 2 is too deep): +# JSON.generate(obj, max_nesting: 2) +# +# ====== Escaping Options +# +# Options +script_safe+ (boolean) specifies wether '\u2028', '\u2029' +# and '/' should be escaped as to make the JSON object safe to interpolate in script +# tags. +# +# Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range +# should be escaped. +# +# ====== Output Options +# +# The default formatting options generate the most compact +# \JSON data, all on one line and with no whitespace. +# +# You can use these formatting options to generate +# \JSON data in a more open format, using whitespace. +# See also JSON.pretty_generate. +# +# - Option +array_nl+ (\String) specifies a string (usually a newline) +# to be inserted after each \JSON array; defaults to the empty \String, ''. +# - Option +object_nl+ (\String) specifies a string (usually a newline) +# to be inserted after each \JSON object; defaults to the empty \String, ''. +# - Option +indent+ (\String) specifies the string (usually spaces) to be +# used for indentation; defaults to the empty \String, ''; +# defaults to the empty \String, ''; +# has no effect unless options +array_nl+ or +object_nl+ specify newlines. +# - Option +space+ (\String) specifies a string (usually a space) to be +# inserted after the colon in each \JSON object's pair; +# defaults to the empty \String, ''. +# - Option +space_before+ (\String) specifies a string (usually a space) to be +# inserted before the colon in each \JSON object's pair; +# defaults to the empty \String, ''. +# +# In this example, +obj+ is used first to generate the shortest +# \JSON data (no whitespace), then again with all formatting options +# specified: +# +# obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}} +# json = JSON.generate(obj) +# puts 'Compact:', json +# opts = { +# array_nl: "\n", +# object_nl: "\n", +# indent: ' ', +# space_before: ' ', +# space: ' ' +# } +# puts 'Open:', JSON.generate(obj, opts) +# +# Output: +# Compact: +# {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}} +# Open: +# { +# "foo" : [ +# "bar", +# "baz" +# ], +# "bat" : { +# "bam" : 0, +# "bad" : 1 +# } +# } +# +# == \JSON Additions +# +# When you "round trip" a non-\String object from Ruby to \JSON and back, +# you have a new \String, instead of the object you began with: +# ruby0 = Range.new(0, 2) +# json = JSON.generate(ruby0) +# json # => '0..2"' +# ruby1 = JSON.parse(json) +# ruby1 # => '0..2' +# ruby1.class # => String +# +# You can use \JSON _additions_ to preserve the original object. +# The addition is an extension of a ruby class, so that: +# - \JSON.generate stores more information in the \JSON string. +# - \JSON.parse, called with option +create_additions+, +# uses that information to create a proper Ruby object. +# +# This example shows a \Range being generated into \JSON +# and parsed back into Ruby, both without and with +# the addition for \Range: +# ruby = Range.new(0, 2) +# # This passage does not use the addition for Range. +# json0 = JSON.generate(ruby) +# ruby0 = JSON.parse(json0) +# # This passage uses the addition for Range. +# require 'json/add/range' +# json1 = JSON.generate(ruby) +# ruby1 = JSON.parse(json1, create_additions: true) +# # Make a nice display. +# display = <<~EOT +# Generated JSON: +# Without addition: #{json0} (#{json0.class}) +# With addition: #{json1} (#{json1.class}) +# Parsed JSON: +# Without addition: #{ruby0.inspect} (#{ruby0.class}) +# With addition: #{ruby1.inspect} (#{ruby1.class}) +# EOT +# puts display +# +# This output shows the different results: +# Generated JSON: +# Without addition: "0..2" (String) +# With addition: {"json_class":"Range","a":[0,2,false]} (String) +# Parsed JSON: +# Without addition: "0..2" (String) +# With addition: 0..2 (Range) +# +# The \JSON module includes additions for certain classes. +# You can also craft custom additions. +# See {Custom \JSON Additions}[#module-JSON-label-Custom+JSON+Additions]. +# +# === Built-in Additions +# +# The \JSON module includes additions for certain classes. +# To use an addition, +require+ its source: +# - BigDecimal: require 'json/add/bigdecimal' +# - Complex: require 'json/add/complex' +# - Date: require 'json/add/date' +# - DateTime: require 'json/add/date_time' +# - Exception: require 'json/add/exception' +# - OpenStruct: require 'json/add/ostruct' +# - Range: require 'json/add/range' +# - Rational: require 'json/add/rational' +# - Regexp: require 'json/add/regexp' +# - Set: require 'json/add/set' +# - Struct: require 'json/add/struct' +# - Symbol: require 'json/add/symbol' +# - Time: require 'json/add/time' +# +# To reduce punctuation clutter, the examples below +# show the generated \JSON via +puts+, rather than the usual +inspect+, +# +# \BigDecimal: +# require 'json/add/bigdecimal' +# ruby0 = BigDecimal(0) # 0.0 +# json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"} +# ruby1 = JSON.parse(json, create_additions: true) # 0.0 +# ruby1.class # => BigDecimal +# +# \Complex: +# require 'json/add/complex' +# ruby0 = Complex(1+0i) # 1+0i +# json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0} +# ruby1 = JSON.parse(json, create_additions: true) # 1+0i +# ruby1.class # Complex +# +# \Date: +# require 'json/add/date' +# ruby0 = Date.today # 2020-05-02 +# json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0} +# ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 +# ruby1.class # Date +# +# \DateTime: +# require 'json/add/date_time' +# ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00 +# json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0} +# ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00 +# ruby1.class # DateTime +# +# \Exception (and its subclasses including \RuntimeError): +# require 'json/add/exception' +# ruby0 = Exception.new('A message') # A message +# json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null} +# ruby1 = JSON.parse(json, create_additions: true) # A message +# ruby1.class # Exception +# ruby0 = RuntimeError.new('Another message') # Another message +# json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null} +# ruby1 = JSON.parse(json, create_additions: true) # Another message +# ruby1.class # RuntimeError +# +# \OpenStruct: +# require 'json/add/ostruct' +# ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # # +# json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}} +# ruby1 = JSON.parse(json, create_additions: true) # # +# ruby1.class # OpenStruct +# +# \Range: +# require 'json/add/range' +# ruby0 = Range.new(0, 2) # 0..2 +# json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]} +# ruby1 = JSON.parse(json, create_additions: true) # 0..2 +# ruby1.class # Range +# +# \Rational: +# require 'json/add/rational' +# ruby0 = Rational(1, 3) # 1/3 +# json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3} +# ruby1 = JSON.parse(json, create_additions: true) # 1/3 +# ruby1.class # Rational +# +# \Regexp: +# require 'json/add/regexp' +# ruby0 = Regexp.new('foo') # (?-mix:foo) +# json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"} +# ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo) +# ruby1.class # Regexp +# +# \Set: +# require 'json/add/set' +# ruby0 = Set.new([0, 1, 2]) # # +# json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]} +# ruby1 = JSON.parse(json, create_additions: true) # # +# ruby1.class # Set +# +# \Struct: +# require 'json/add/struct' +# Customer = Struct.new(:name, :address) # Customer +# ruby0 = Customer.new("Dave", "123 Main") # # +# json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]} +# ruby1 = JSON.parse(json, create_additions: true) # # +# ruby1.class # Customer +# +# \Symbol: +# require 'json/add/symbol' +# ruby0 = :foo # foo +# json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"} +# ruby1 = JSON.parse(json, create_additions: true) # foo +# ruby1.class # Symbol +# +# \Time: +# require 'json/add/time' +# ruby0 = Time.now # 2020-05-02 11:28:26 -0500 +# json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000} +# ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500 +# ruby1.class # Time +# +# +# === Custom \JSON Additions +# +# In addition to the \JSON additions provided, +# you can craft \JSON additions of your own, +# either for Ruby built-in classes or for user-defined classes. +# +# Here's a user-defined class +Foo+: +# class Foo +# attr_accessor :bar, :baz +# def initialize(bar, baz) +# self.bar = bar +# self.baz = baz +# end +# end +# +# Here's the \JSON addition for it: +# # Extend class Foo with JSON addition. +# class Foo +# # Serialize Foo object with its class name and arguments +# def to_json(*args) +# { +# JSON.create_id => self.class.name, +# 'a' => [ bar, baz ] +# }.to_json(*args) +# end +# # Deserialize JSON string by constructing new Foo object with arguments. +# def self.json_create(object) +# new(*object['a']) +# end +# end +# +# Demonstration: +# require 'json' +# # This Foo object has no custom addition. +# foo0 = Foo.new(0, 1) +# json0 = JSON.generate(foo0) +# obj0 = JSON.parse(json0) +# # Lood the custom addition. +# require_relative 'foo_addition' +# # This foo has the custom addition. +# foo1 = Foo.new(0, 1) +# json1 = JSON.generate(foo1) +# obj1 = JSON.parse(json1, create_additions: true) +# # Make a nice display. +# display = <<~EOT +# Generated JSON: +# Without custom addition: #{json0} (#{json0.class}) +# With custom addition: #{json1} (#{json1.class}) +# Parsed JSON: +# Without custom addition: #{obj0.inspect} (#{obj0.class}) +# With custom addition: #{obj1.inspect} (#{obj1.class}) +# EOT +# puts display +# +# Output: +# +# Generated JSON: +# Without custom addition: "#" (String) +# With custom addition: {"json_class":"Foo","a":[0,1]} (String) +# Parsed JSON: +# Without custom addition: "#" (String) +# With custom addition: # (Foo) +# +module JSON + require 'json/version' + require 'json/ext' +end diff --git a/bin/gems/json-2.10.2/lib/json/add/bigdecimal.rb b/bin/gems/json-2.10.2/lib/json/add/bigdecimal.rb new file mode 100644 index 00000000..5dbc12c0 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/bigdecimal.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end +begin + require 'bigdecimal' +rescue LoadError +end + +class BigDecimal + + # See #as_json. + def self.json_create(object) + BigDecimal._load object['b'] + end + + # Methods BigDecimal#as_json and +BigDecimal.json_create+ may be used + # to serialize and deserialize a \BigDecimal object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method BigDecimal#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/bigdecimal' + # x = BigDecimal(2).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"} + # y = BigDecimal(2.0, 4).as_json # => {"json_class"=>"BigDecimal", "b"=>"36:0.2e1"} + # z = BigDecimal(Complex(2, 0)).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"} + # + # \Method +JSON.create+ deserializes such a hash, returning a \BigDecimal object: + # + # BigDecimal.json_create(x) # => 0.2e1 + # BigDecimal.json_create(y) # => 0.2e1 + # BigDecimal.json_create(z) # => 0.2e1 + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'b' => _dump.force_encoding(Encoding::UTF_8), + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/bigdecimal' + # puts BigDecimal(2).to_json + # puts BigDecimal(2.0, 4).to_json + # puts BigDecimal(Complex(2, 0)).to_json + # + # Output: + # + # {"json_class":"BigDecimal","b":"27:0.2e1"} + # {"json_class":"BigDecimal","b":"36:0.2e1"} + # {"json_class":"BigDecimal","b":"27:0.2e1"} + # + def to_json(*args) + as_json.to_json(*args) + end +end if defined?(::BigDecimal) diff --git a/bin/gems/json-2.10.2/lib/json/add/complex.rb b/bin/gems/json-2.10.2/lib/json/add/complex.rb new file mode 100644 index 00000000..a69002ef --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/complex.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Complex + + # See #as_json. + def self.json_create(object) + Complex(object['r'], object['i']) + end + + # Methods Complex#as_json and +Complex.json_create+ may be used + # to serialize and deserialize a \Complex object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Complex#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/complex' + # x = Complex(2).as_json # => {"json_class"=>"Complex", "r"=>2, "i"=>0} + # y = Complex(2.0, 4).as_json # => {"json_class"=>"Complex", "r"=>2.0, "i"=>4} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Complex object: + # + # Complex.json_create(x) # => (2+0i) + # Complex.json_create(y) # => (2.0+4i) + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'r' => real, + 'i' => imag, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/complex' + # puts Complex(2).to_json + # puts Complex(2.0, 4).to_json + # + # Output: + # + # {"json_class":"Complex","r":2,"i":0} + # {"json_class":"Complex","r":2.0,"i":4} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/core.rb b/bin/gems/json-2.10.2/lib/json/add/core.rb new file mode 100644 index 00000000..485f097f --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/core.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true +# This file requires the implementations of ruby core's custom objects for +# serialisation/deserialisation. + +require 'json/add/date' +require 'json/add/date_time' +require 'json/add/exception' +require 'json/add/range' +require 'json/add/regexp' +require 'json/add/struct' +require 'json/add/symbol' +require 'json/add/time' diff --git a/bin/gems/json-2.10.2/lib/json/add/date.rb b/bin/gems/json-2.10.2/lib/json/add/date.rb new file mode 100644 index 00000000..66965d49 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/date.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end +require 'date' + +class Date + + # See #as_json. + def self.json_create(object) + civil(*object.values_at('y', 'm', 'd', 'sg')) + end + + alias start sg unless method_defined?(:start) + + # Methods Date#as_json and +Date.json_create+ may be used + # to serialize and deserialize a \Date object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Date#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/date' + # x = Date.today.as_json + # # => {"json_class"=>"Date", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Date object: + # + # Date.json_create(x) + # # => # + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'y' => year, + 'm' => month, + 'd' => day, + 'sg' => start, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/date' + # puts Date.today.to_json + # + # Output: + # + # {"json_class":"Date","y":2023,"m":11,"d":21,"sg":2299161.0} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/date_time.rb b/bin/gems/json-2.10.2/lib/json/add/date_time.rb new file mode 100644 index 00000000..569f6ec1 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/date_time.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end +require 'date' + +class DateTime + + # See #as_json. + def self.json_create(object) + args = object.values_at('y', 'm', 'd', 'H', 'M', 'S') + of_a, of_b = object['of'].split('/') + if of_b and of_b != '0' + args << Rational(of_a.to_i, of_b.to_i) + else + args << of_a + end + args << object['sg'] + civil(*args) + end + + alias start sg unless method_defined?(:start) + + # Methods DateTime#as_json and +DateTime.json_create+ may be used + # to serialize and deserialize a \DateTime object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method DateTime#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/datetime' + # x = DateTime.now.as_json + # # => {"json_class"=>"DateTime", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0} + # + # \Method +JSON.create+ deserializes such a hash, returning a \DateTime object: + # + # DateTime.json_create(x) # BUG? Raises Date::Error "invalid date" + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'y' => year, + 'm' => month, + 'd' => day, + 'H' => hour, + 'M' => min, + 'S' => sec, + 'of' => offset.to_s, + 'sg' => start, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/datetime' + # puts DateTime.now.to_json + # + # Output: + # + # {"json_class":"DateTime","y":2023,"m":11,"d":21,"sg":2299161.0} + # + def to_json(*args) + as_json.to_json(*args) + end +end + + diff --git a/bin/gems/json-2.10.2/lib/json/add/exception.rb b/bin/gems/json-2.10.2/lib/json/add/exception.rb new file mode 100644 index 00000000..5338ff83 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/exception.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Exception + + # See #as_json. + def self.json_create(object) + result = new(object['m']) + result.set_backtrace object['b'] + result + end + + # Methods Exception#as_json and +Exception.json_create+ may be used + # to serialize and deserialize a \Exception object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Exception#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/exception' + # x = Exception.new('Foo').as_json # => {"json_class"=>"Exception", "m"=>"Foo", "b"=>nil} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Exception object: + # + # Exception.json_create(x) # => # + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'm' => message, + 'b' => backtrace, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/exception' + # puts Exception.new('Foo').to_json + # + # Output: + # + # {"json_class":"Exception","m":"Foo","b":null} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/ostruct.rb b/bin/gems/json-2.10.2/lib/json/add/ostruct.rb new file mode 100644 index 00000000..534403b7 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/ostruct.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end +begin + require 'ostruct' +rescue LoadError +end + +class OpenStruct + + # See #as_json. + def self.json_create(object) + new(object['t'] || object[:t]) + end + + # Methods OpenStruct#as_json and +OpenStruct.json_create+ may be used + # to serialize and deserialize a \OpenStruct object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method OpenStruct#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/ostruct' + # x = OpenStruct.new('name' => 'Rowdy', :age => nil).as_json + # # => {"json_class"=>"OpenStruct", "t"=>{:name=>'Rowdy', :age=>nil}} + # + # \Method +JSON.create+ deserializes such a hash, returning a \OpenStruct object: + # + # OpenStruct.json_create(x) + # # => # + # + def as_json(*) + klass = self.class.name + klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" + { + JSON.create_id => klass, + 't' => table, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/ostruct' + # puts OpenStruct.new('name' => 'Rowdy', :age => nil).to_json + # + # Output: + # + # {"json_class":"OpenStruct","t":{'name':'Rowdy',"age":null}} + # + def to_json(*args) + as_json.to_json(*args) + end +end if defined?(::OpenStruct) diff --git a/bin/gems/json-2.10.2/lib/json/add/range.rb b/bin/gems/json-2.10.2/lib/json/add/range.rb new file mode 100644 index 00000000..eb4b29a8 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/range.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Range + + # See #as_json. + def self.json_create(object) + new(*object['a']) + end + + # Methods Range#as_json and +Range.json_create+ may be used + # to serialize and deserialize a \Range object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Range#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/range' + # x = (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]} + # y = (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]} + # z = ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Range object: + # + # Range.json_create(x) # => 1..4 + # Range.json_create(y) # => 1...4 + # Range.json_create(z) # => "a".."d" + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'a' => [ first, last, exclude_end? ] + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/range' + # puts (1..4).to_json + # puts (1...4).to_json + # puts ('a'..'d').to_json + # + # Output: + # + # {"json_class":"Range","a":[1,4,false]} + # {"json_class":"Range","a":[1,4,true]} + # {"json_class":"Range","a":["a","d",false]} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/rational.rb b/bin/gems/json-2.10.2/lib/json/add/rational.rb new file mode 100644 index 00000000..1eb23147 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/rational.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Rational + + # See #as_json. + def self.json_create(object) + Rational(object['n'], object['d']) + end + + # Methods Rational#as_json and +Rational.json_create+ may be used + # to serialize and deserialize a \Rational object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Rational#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/rational' + # x = Rational(2, 3).as_json + # # => {"json_class"=>"Rational", "n"=>2, "d"=>3} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Rational object: + # + # Rational.json_create(x) + # # => (2/3) + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'n' => numerator, + 'd' => denominator, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/rational' + # puts Rational(2, 3).to_json + # + # Output: + # + # {"json_class":"Rational","n":2,"d":3} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/regexp.rb b/bin/gems/json-2.10.2/lib/json/add/regexp.rb new file mode 100644 index 00000000..f033dd1d --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/regexp.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Regexp + + # See #as_json. + def self.json_create(object) + new(object['s'], object['o']) + end + + # Methods Regexp#as_json and +Regexp.json_create+ may be used + # to serialize and deserialize a \Regexp object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Regexp#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/regexp' + # x = /foo/.as_json + # # => {"json_class"=>"Regexp", "o"=>0, "s"=>"foo"} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Regexp object: + # + # Regexp.json_create(x) # => /foo/ + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'o' => options, + 's' => source, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/regexp' + # puts /foo/.to_json + # + # Output: + # + # {"json_class":"Regexp","o":0,"s":"foo"} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/set.rb b/bin/gems/json-2.10.2/lib/json/add/set.rb new file mode 100644 index 00000000..c521d8b9 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/set.rb @@ -0,0 +1,48 @@ +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end +defined?(::Set) or require 'set' + +class Set + + # See #as_json. + def self.json_create(object) + new object['a'] + end + + # Methods Set#as_json and +Set.json_create+ may be used + # to serialize and deserialize a \Set object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Set#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/set' + # x = Set.new(%w/foo bar baz/).as_json + # # => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Set object: + # + # Set.json_create(x) # => # + # + def as_json(*) + { + JSON.create_id => self.class.name, + 'a' => to_a, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/set' + # puts Set.new(%w/foo bar baz/).to_json + # + # Output: + # + # {"json_class":"Set","a":["foo","bar","baz"]} + # + def to_json(*args) + as_json.to_json(*args) + end +end + diff --git a/bin/gems/json-2.10.2/lib/json/add/struct.rb b/bin/gems/json-2.10.2/lib/json/add/struct.rb new file mode 100644 index 00000000..98c38d32 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/struct.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Struct + + # See #as_json. + def self.json_create(object) + new(*object['v']) + end + + # Methods Struct#as_json and +Struct.json_create+ may be used + # to serialize and deserialize a \Struct object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Struct#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/struct' + # Customer = Struct.new('Customer', :name, :address, :zip) + # x = Struct::Customer.new.as_json + # # => {"json_class"=>"Struct::Customer", "v"=>[nil, nil, nil]} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Struct object: + # + # Struct::Customer.json_create(x) + # # => # + # + def as_json(*) + klass = self.class.name + klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" + { + JSON.create_id => klass, + 'v' => values, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/struct' + # Customer = Struct.new('Customer', :name, :address, :zip) + # puts Struct::Customer.new.to_json + # + # Output: + # + # {"json_class":"Struct","t":{'name':'Rowdy',"age":null}} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/symbol.rb b/bin/gems/json-2.10.2/lib/json/add/symbol.rb new file mode 100644 index 00000000..20dd5948 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/symbol.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Symbol + + # Methods Symbol#as_json and +Symbol.json_create+ may be used + # to serialize and deserialize a \Symbol object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Symbol#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/symbol' + # x = :foo.as_json + # # => {"json_class"=>"Symbol", "s"=>"foo"} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Symbol object: + # + # Symbol.json_create(x) # => :foo + # + def as_json(*) + { + JSON.create_id => self.class.name, + 's' => to_s, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/symbol' + # puts :foo.to_json + # + # Output: + # + # # {"json_class":"Symbol","s":"foo"} + # + def to_json(state = nil, *a) + state = ::JSON::State.from_state(state) + if state.strict? + super + else + as_json.to_json(state, *a) + end + end + + # See #as_json. + def self.json_create(o) + o['s'].to_sym + end +end diff --git a/bin/gems/json-2.10.2/lib/json/add/time.rb b/bin/gems/json-2.10.2/lib/json/add/time.rb new file mode 100644 index 00000000..05a1f242 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/add/time.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED + require 'json' +end + +class Time + + # See #as_json. + def self.json_create(object) + if usec = object.delete('u') # used to be tv_usec -> tv_nsec + object['n'] = usec * 1000 + end + at(object['s'], Rational(object['n'], 1000)) + end + + # Methods Time#as_json and +Time.json_create+ may be used + # to serialize and deserialize a \Time object; + # see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html]. + # + # \Method Time#as_json serializes +self+, + # returning a 2-element hash representing +self+: + # + # require 'json/add/time' + # x = Time.now.as_json + # # => {"json_class"=>"Time", "s"=>1700931656, "n"=>472846644} + # + # \Method +JSON.create+ deserializes such a hash, returning a \Time object: + # + # Time.json_create(x) + # # => 2023-11-25 11:00:56.472846644 -0600 + # + def as_json(*) + { + JSON.create_id => self.class.name, + 's' => tv_sec, + 'n' => tv_nsec, + } + end + + # Returns a JSON string representing +self+: + # + # require 'json/add/time' + # puts Time.now.to_json + # + # Output: + # + # {"json_class":"Time","s":1700931678,"n":980650786} + # + def to_json(*args) + as_json.to_json(*args) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/common.rb b/bin/gems/json-2.10.2/lib/json/common.rb new file mode 100644 index 00000000..9094df00 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/common.rb @@ -0,0 +1,987 @@ +# frozen_string_literal: true + +require 'json/version' + +module JSON + autoload :GenericObject, 'json/generic_object' + + NOT_SET = Object.new.freeze + private_constant :NOT_SET + + class << self + # :call-seq: + # JSON[object] -> new_array or new_string + # + # If +object+ is a \String, + # calls JSON.parse with +object+ and +opts+ (see method #parse): + # json = '[0, 1, null]' + # JSON[json]# => [0, 1, nil] + # + # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate): + # ruby = [0, 1, nil] + # JSON[ruby] # => '[0,1,null]' + def [](object, opts = {}) + if object.is_a?(String) + return JSON.parse(object, opts) + elsif object.respond_to?(:to_str) + str = object.to_str + if str.is_a?(String) + return JSON.parse(str, opts) + end + end + + JSON.generate(object, opts) + end + + # Returns the JSON parser class that is used by JSON. + attr_reader :parser + + # Set the JSON parser class _parser_ to be used by JSON. + def parser=(parser) # :nodoc: + @parser = parser + remove_const :Parser if const_defined?(:Parser, false) + const_set :Parser, parser + end + + # Return the constant located at _path_. The format of _path_ has to be + # either ::A::B::C or A::B::C. In any case, A has to be located at the top + # level (absolute namespace path?). If there doesn't exist a constant at + # the given path, an ArgumentError is raised. + def deep_const_get(path) # :nodoc: + Object.const_get(path) + rescue NameError => e + raise ArgumentError, "can't get const #{path}: #{e}" + end + + # Set the module _generator_ to be used by JSON. + def generator=(generator) # :nodoc: + old, $VERBOSE = $VERBOSE, nil + @generator = generator + generator_methods = generator::GeneratorMethods + for const in generator_methods.constants + klass = const_get(const) + modul = generator_methods.const_get(const) + klass.class_eval do + instance_methods(false).each do |m| + m.to_s == 'to_json' and remove_method m + end + include modul + end + end + self.state = generator::State + const_set :State, self.state + const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby + const_set :FAST_STATE_PROTOTYPE, create_fast_state + const_set :PRETTY_STATE_PROTOTYPE, create_pretty_state + ensure + $VERBOSE = old + end + + def create_fast_state + State.new( + :indent => '', + :space => '', + :object_nl => "", + :array_nl => "", + :max_nesting => false + ) + end + + def create_pretty_state + State.new( + :indent => ' ', + :space => ' ', + :object_nl => "\n", + :array_nl => "\n" + ) + end + + # Returns the JSON generator module that is used by JSON. + attr_reader :generator + + # Sets or Returns the JSON generator state class that is used by JSON. + attr_accessor :state + end + + # Sets create identifier, which is used to decide if the _json_create_ + # hook of a class should be called; initial value is +json_class+: + # JSON.create_id # => 'json_class' + def self.create_id=(new_value) + Thread.current[:"JSON.create_id"] = new_value.dup.freeze + end + + # Returns the current create identifier. + # See also JSON.create_id=. + def self.create_id + Thread.current[:"JSON.create_id"] || 'json_class' + end + + NaN = 0.0/0 + + Infinity = 1.0/0 + + MinusInfinity = -Infinity + + # The base exception for JSON errors. + class JSONError < StandardError + def self.wrap(exception) + obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}") + obj.set_backtrace exception.backtrace + obj + end + end + + # This exception is raised if a parser error occurs. + class ParserError < JSONError; end + + # This exception is raised if the nesting of parsed data structures is too + # deep. + class NestingError < ParserError; end + + # :stopdoc: + class CircularDatastructure < NestingError; end + # :startdoc: + + # This exception is raised if a generator or unparser error occurs. + class GeneratorError < JSONError + attr_reader :invalid_object + + def initialize(message, invalid_object = nil) + super(message) + @invalid_object = invalid_object + end + + def detailed_message(...) + # Exception#detailed_message doesn't exist until Ruby 3.2 + super_message = defined?(super) ? super : message + + if @invalid_object.nil? + super_message + else + "#{super_message}\nInvalid object: #{@invalid_object.inspect}" + end + end + end + + # For backwards compatibility + UnparserError = GeneratorError # :nodoc: + + # This exception is raised if the required unicode support is missing on the + # system. Usually this means that the iconv library is not installed. + class MissingUnicodeSupport < JSONError; end + + # Fragment of JSON document that is to be included as is: + # fragment = JSON::Fragment.new("[1, 2, 3]") + # JSON.generate({ count: 3, items: fragments }) + # + # This allows to easily assemble multiple JSON fragments that have + # been persisted somewhere without having to parse them nor resorting + # to string interpolation. + # + # Note: no validation is performed on the provided string. It is the + # responsability of the caller to ensure the string contains valid JSON. + Fragment = Struct.new(:json) do + def initialize(json) + unless string = String.try_convert(json) + raise TypeError, " no implicit conversion of #{json.class} into String" + end + + super(string) + end + + def to_json(state = nil, *) + json + end + end + + module_function + + # :call-seq: + # JSON.parse(source, opts) -> object + # + # Returns the Ruby objects created by parsing the given +source+. + # + # Argument +source+ contains the \String to be parsed. + # + # Argument +opts+, if given, contains a \Hash of options for the parsing. + # See {Parsing Options}[#module-JSON-label-Parsing+Options]. + # + # --- + # + # When +source+ is a \JSON array, returns a Ruby \Array: + # source = '["foo", 1.0, true, false, null]' + # ruby = JSON.parse(source) + # ruby # => ["foo", 1.0, true, false, nil] + # ruby.class # => Array + # + # When +source+ is a \JSON object, returns a Ruby \Hash: + # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}' + # ruby = JSON.parse(source) + # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil} + # ruby.class # => Hash + # + # For examples of parsing for all \JSON data types, see + # {Parsing \JSON}[#module-JSON-label-Parsing+JSON]. + # + # Parses nested JSON objects: + # source = <<~JSON + # { + # "name": "Dave", + # "age" :40, + # "hats": [ + # "Cattleman's", + # "Panama", + # "Tophat" + # ] + # } + # JSON + # ruby = JSON.parse(source) + # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # --- + # + # Raises an exception if +source+ is not valid JSON: + # # Raises JSON::ParserError (783: unexpected token at ''): + # JSON.parse('') + # + def parse(source, opts = nil) + Parser.parse(source, opts) + end + + # :call-seq: + # JSON.parse!(source, opts) -> object + # + # Calls + # parse(source, opts) + # with +source+ and possibly modified +opts+. + # + # Differences from JSON.parse: + # - Option +max_nesting+, if not provided, defaults to +false+, + # which disables checking for nesting depth. + # - Option +allow_nan+, if not provided, defaults to +true+. + def parse!(source, opts = nil) + options = { + :max_nesting => false, + :allow_nan => true + } + options.merge!(opts) if opts + Parser.new(source, options).parse + end + + # :call-seq: + # JSON.load_file(path, opts={}) -> object + # + # Calls: + # parse(File.read(path), opts) + # + # See method #parse. + def load_file(filespec, opts = nil) + parse(File.read(filespec, encoding: Encoding::UTF_8), opts) + end + + # :call-seq: + # JSON.load_file!(path, opts = {}) + # + # Calls: + # JSON.parse!(File.read(path, opts)) + # + # See method #parse! + def load_file!(filespec, opts = nil) + parse!(File.read(filespec, encoding: Encoding::UTF_8), opts) + end + + # :call-seq: + # JSON.generate(obj, opts = nil) -> new_string + # + # Returns a \String containing the generated \JSON data. + # + # See also JSON.fast_generate, JSON.pretty_generate. + # + # Argument +obj+ is the Ruby object to be converted to \JSON. + # + # Argument +opts+, if given, contains a \Hash of options for the generation. + # See {Generating Options}[#module-JSON-label-Generating+Options]. + # + # --- + # + # When +obj+ is an \Array, returns a \String containing a \JSON array: + # obj = ["foo", 1.0, true, false, nil] + # json = JSON.generate(obj) + # json # => '["foo",1.0,true,false,null]' + # + # When +obj+ is a \Hash, returns a \String containing a \JSON object: + # obj = {foo: 0, bar: 's', baz: :bat} + # json = JSON.generate(obj) + # json # => '{"foo":0,"bar":"s","baz":"bat"}' + # + # For examples of generating from other Ruby objects, see + # {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects]. + # + # --- + # + # Raises an exception if any formatting option is not a \String. + # + # Raises an exception if +obj+ contains circular references: + # a = []; b = []; a.push(b); b.push(a) + # # Raises JSON::NestingError (nesting of 100 is too deep): + # JSON.generate(a) + # + def generate(obj, opts = nil) + if State === opts + opts.generate(obj) + else + State.generate(obj, opts, nil) + end + end + + # :stopdoc: + # I want to deprecate these later, so I'll first be silent about them, and + # later delete them. + alias unparse generate + module_function :unparse + # :startdoc: + + # :call-seq: + # JSON.fast_generate(obj, opts) -> new_string + # + # Arguments +obj+ and +opts+ here are the same as + # arguments +obj+ and +opts+ in JSON.generate. + # + # By default, generates \JSON data without checking + # for circular references in +obj+ (option +max_nesting+ set to +false+, disabled). + # + # Raises an exception if +obj+ contains circular references: + # a = []; b = []; a.push(b); b.push(a) + # # Raises SystemStackError (stack level too deep): + # JSON.fast_generate(a) + def fast_generate(obj, opts = nil) + if State === opts + state = opts + else + state = JSON.create_fast_state.configure(opts) + end + state.generate(obj) + end + + # :stopdoc: + # I want to deprecate these later, so I'll first be silent about them, and later delete them. + alias fast_unparse fast_generate + module_function :fast_unparse + # :startdoc: + + # :call-seq: + # JSON.pretty_generate(obj, opts = nil) -> new_string + # + # Arguments +obj+ and +opts+ here are the same as + # arguments +obj+ and +opts+ in JSON.generate. + # + # Default options are: + # { + # indent: ' ', # Two spaces + # space: ' ', # One space + # array_nl: "\n", # Newline + # object_nl: "\n" # Newline + # } + # + # Example: + # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}} + # json = JSON.pretty_generate(obj) + # puts json + # Output: + # { + # "foo": [ + # "bar", + # "baz" + # ], + # "bat": { + # "bam": 0, + # "bad": 1 + # } + # } + # + def pretty_generate(obj, opts = nil) + if State === opts + state, opts = opts, nil + else + state = JSON.create_pretty_state + end + if opts + if opts.respond_to? :to_hash + opts = opts.to_hash + elsif opts.respond_to? :to_h + opts = opts.to_h + else + raise TypeError, "can't convert #{opts.class} into Hash" + end + state.configure(opts) + end + state.generate(obj) + end + + # :stopdoc: + # I want to deprecate these later, so I'll first be silent about them, and later delete them. + alias pretty_unparse pretty_generate + module_function :pretty_unparse + # :startdoc: + + class << self + # Sets or returns default options for the JSON.unsafe_load method. + # Initially: + # opts = JSON.load_default_options + # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true} + attr_accessor :unsafe_load_default_options + end + self.unsafe_load_default_options = { + :max_nesting => false, + :allow_nan => true, + :allow_blank => true, + :create_additions => true, + } + + class << self + # Sets or returns default options for the JSON.load method. + # Initially: + # opts = JSON.load_default_options + # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true} + attr_accessor :load_default_options + end + self.load_default_options = { + :allow_nan => true, + :allow_blank => true, + :create_additions => nil, + } + # :call-seq: + # JSON.unsafe_load(source, proc = nil, options = {}) -> object + # + # Returns the Ruby objects created by parsing the given +source+. + # + # BEWARE: This method is meant to serialise data from trusted user input, + # like from your own database server or clients under your control, it could + # be dangerous to allow untrusted users to pass JSON sources into it. + # + # - Argument +source+ must be, or be convertible to, a \String: + # - If +source+ responds to instance method +to_str+, + # source.to_str becomes the source. + # - If +source+ responds to instance method +to_io+, + # source.to_io.read becomes the source. + # - If +source+ responds to instance method +read+, + # source.read becomes the source. + # - If both of the following are true, source becomes the \String 'null': + # - Option +allow_blank+ specifies a truthy value. + # - The source, as defined above, is +nil+ or the empty \String ''. + # - Otherwise, +source+ remains the source. + # - Argument +proc+, if given, must be a \Proc that accepts one argument. + # It will be called recursively with each result (depth-first order). + # See details below. + # - Argument +opts+, if given, contains a \Hash of options for the parsing. + # See {Parsing Options}[#module-JSON-label-Parsing+Options]. + # The default options can be changed via method JSON.unsafe_load_default_options=. + # + # --- + # + # When no +proc+ is given, modifies +source+ as above and returns the result of + # parse(source, opts); see #parse. + # + # Source for following examples: + # source = <<~JSON + # { + # "name": "Dave", + # "age" :40, + # "hats": [ + # "Cattleman's", + # "Panama", + # "Tophat" + # ] + # } + # JSON + # + # Load a \String: + # ruby = JSON.unsafe_load(source) + # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # Load an \IO object: + # require 'stringio' + # object = JSON.unsafe_load(StringIO.new(source)) + # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # Load a \File object: + # path = 't.json' + # File.write(path, source) + # File.open(path) do |file| + # JSON.unsafe_load(file) + # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # --- + # + # When +proc+ is given: + # - Modifies +source+ as above. + # - Gets the +result+ from calling parse(source, opts). + # - Recursively calls proc(result). + # - Returns the final result. + # + # Example: + # require 'json' + # + # # Some classes for the example. + # class Base + # def initialize(attributes) + # @attributes = attributes + # end + # end + # class User < Base; end + # class Account < Base; end + # class Admin < Base; end + # # The JSON source. + # json = <<-EOF + # { + # "users": [ + # {"type": "User", "username": "jane", "email": "jane@example.com"}, + # {"type": "User", "username": "john", "email": "john@example.com"} + # ], + # "accounts": [ + # {"account": {"type": "Account", "paid": true, "account_id": "1234"}}, + # {"account": {"type": "Account", "paid": false, "account_id": "1235"}} + # ], + # "admins": {"type": "Admin", "password": "0wn3d"} + # } + # EOF + # # Deserializer method. + # def deserialize_obj(obj, safe_types = %w(User Account Admin)) + # type = obj.is_a?(Hash) && obj["type"] + # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj + # end + # # Call to JSON.unsafe_load + # ruby = JSON.unsafe_load(json, proc {|obj| + # case obj + # when Hash + # obj.each {|k, v| obj[k] = deserialize_obj v } + # when Array + # obj.map! {|v| deserialize_obj v } + # end + # }) + # pp ruby + # Output: + # {"users"=> + # [#"User", "username"=>"jane", "email"=>"jane@example.com"}>, + # #"User", "username"=>"john", "email"=>"john@example.com"}>], + # "accounts"=> + # [{"account"=> + # #"Account", "paid"=>true, "account_id"=>"1234"}>}, + # {"account"=> + # #"Account", "paid"=>false, "account_id"=>"1235"}>}], + # "admins"=> + # #"Admin", "password"=>"0wn3d"}>} + # + def unsafe_load(source, proc = nil, options = nil) + opts = if options.nil? + unsafe_load_default_options + else + unsafe_load_default_options.merge(options) + end + + unless source.is_a?(String) + if source.respond_to? :to_str + source = source.to_str + elsif source.respond_to? :to_io + source = source.to_io.read + elsif source.respond_to?(:read) + source = source.read + end + end + + if opts[:allow_blank] && (source.nil? || source.empty?) + source = 'null' + end + result = parse(source, opts) + recurse_proc(result, &proc) if proc + result + end + + # :call-seq: + # JSON.load(source, proc = nil, options = {}) -> object + # + # Returns the Ruby objects created by parsing the given +source+. + # + # BEWARE: This method is meant to serialise data from trusted user input, + # like from your own database server or clients under your control, it could + # be dangerous to allow untrusted users to pass JSON sources into it. + # If you must use it, use JSON.unsafe_load instead to make it clear. + # + # Since JSON version 2.8.0, `load` emits a deprecation warning when a + # non native type is deserialized, without `create_additions` being explicitly + # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled + # by default. + # + # - Argument +source+ must be, or be convertible to, a \String: + # - If +source+ responds to instance method +to_str+, + # source.to_str becomes the source. + # - If +source+ responds to instance method +to_io+, + # source.to_io.read becomes the source. + # - If +source+ responds to instance method +read+, + # source.read becomes the source. + # - If both of the following are true, source becomes the \String 'null': + # - Option +allow_blank+ specifies a truthy value. + # - The source, as defined above, is +nil+ or the empty \String ''. + # - Otherwise, +source+ remains the source. + # - Argument +proc+, if given, must be a \Proc that accepts one argument. + # It will be called recursively with each result (depth-first order). + # See details below. + # - Argument +opts+, if given, contains a \Hash of options for the parsing. + # See {Parsing Options}[#module-JSON-label-Parsing+Options]. + # The default options can be changed via method JSON.load_default_options=. + # + # --- + # + # When no +proc+ is given, modifies +source+ as above and returns the result of + # parse(source, opts); see #parse. + # + # Source for following examples: + # source = <<~JSON + # { + # "name": "Dave", + # "age" :40, + # "hats": [ + # "Cattleman's", + # "Panama", + # "Tophat" + # ] + # } + # JSON + # + # Load a \String: + # ruby = JSON.load(source) + # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # Load an \IO object: + # require 'stringio' + # object = JSON.load(StringIO.new(source)) + # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # Load a \File object: + # path = 't.json' + # File.write(path, source) + # File.open(path) do |file| + # JSON.load(file) + # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]} + # + # --- + # + # When +proc+ is given: + # - Modifies +source+ as above. + # - Gets the +result+ from calling parse(source, opts). + # - Recursively calls proc(result). + # - Returns the final result. + # + # Example: + # require 'json' + # + # # Some classes for the example. + # class Base + # def initialize(attributes) + # @attributes = attributes + # end + # end + # class User < Base; end + # class Account < Base; end + # class Admin < Base; end + # # The JSON source. + # json = <<-EOF + # { + # "users": [ + # {"type": "User", "username": "jane", "email": "jane@example.com"}, + # {"type": "User", "username": "john", "email": "john@example.com"} + # ], + # "accounts": [ + # {"account": {"type": "Account", "paid": true, "account_id": "1234"}}, + # {"account": {"type": "Account", "paid": false, "account_id": "1235"}} + # ], + # "admins": {"type": "Admin", "password": "0wn3d"} + # } + # EOF + # # Deserializer method. + # def deserialize_obj(obj, safe_types = %w(User Account Admin)) + # type = obj.is_a?(Hash) && obj["type"] + # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj + # end + # # Call to JSON.load + # ruby = JSON.load(json, proc {|obj| + # case obj + # when Hash + # obj.each {|k, v| obj[k] = deserialize_obj v } + # when Array + # obj.map! {|v| deserialize_obj v } + # end + # }) + # pp ruby + # Output: + # {"users"=> + # [#"User", "username"=>"jane", "email"=>"jane@example.com"}>, + # #"User", "username"=>"john", "email"=>"john@example.com"}>], + # "accounts"=> + # [{"account"=> + # #"Account", "paid"=>true, "account_id"=>"1234"}>}, + # {"account"=> + # #"Account", "paid"=>false, "account_id"=>"1235"}>}], + # "admins"=> + # #"Admin", "password"=>"0wn3d"}>} + # + def load(source, proc = nil, options = nil) + opts = if options.nil? + load_default_options + else + load_default_options.merge(options) + end + + unless source.is_a?(String) + if source.respond_to? :to_str + source = source.to_str + elsif source.respond_to? :to_io + source = source.to_io.read + elsif source.respond_to?(:read) + source = source.read + end + end + + if opts[:allow_blank] && (source.nil? || source.empty?) + source = 'null' + end + result = parse(source, opts) + recurse_proc(result, &proc) if proc + result + end + + # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_ + def recurse_proc(result, &proc) # :nodoc: + case result + when Array + result.each { |x| recurse_proc x, &proc } + proc.call result + when Hash + result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc } + proc.call result + else + proc.call result + end + end + + alias restore load + module_function :restore + + class << self + # Sets or returns the default options for the JSON.dump method. + # Initially: + # opts = JSON.dump_default_options + # opts # => {:max_nesting=>false, :allow_nan=>true} + attr_accessor :dump_default_options + end + self.dump_default_options = { + :max_nesting => false, + :allow_nan => true, + } + + # :call-seq: + # JSON.dump(obj, io = nil, limit = nil) + # + # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result. + # + # The default options can be changed via method JSON.dump_default_options. + # + # - Argument +io+, if given, should respond to method +write+; + # the \JSON \String is written to +io+, and +io+ is returned. + # If +io+ is not given, the \JSON \String is returned. + # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+. + # + # --- + # + # When argument +io+ is not given, returns the \JSON \String generated from +obj+: + # obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad} + # json = JSON.dump(obj) + # json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}" + # + # When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+: + # path = 't.json' + # File.open(path, 'w') do |file| + # JSON.dump(obj, file) + # end # => # + # puts File.read(path) + # Output: + # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"} + def dump(obj, anIO = nil, limit = nil, kwargs = nil) + if kwargs.nil? + if limit.nil? + if anIO.is_a?(Hash) + kwargs = anIO + anIO = nil + end + elsif limit.is_a?(Hash) + kwargs = limit + limit = nil + end + end + + unless anIO.nil? + if anIO.respond_to?(:to_io) + anIO = anIO.to_io + elsif limit.nil? && !anIO.respond_to?(:write) + anIO, limit = nil, anIO + end + end + + opts = JSON.dump_default_options + opts = opts.merge(:max_nesting => limit) if limit + opts = opts.merge(kwargs) if kwargs + + begin + State.generate(obj, opts, anIO) + rescue JSON::NestingError + raise ArgumentError, "exceed depth limit" + end + end + + # Encodes string using String.encode. + def self.iconv(to, from, string) + string.encode(to, from) + end + + # JSON::Coder holds a parser and generator configuration. + # + # module MyApp + # JSONC_CODER = JSON::Coder.new( + # allow_trailing_comma: true + # ) + # end + # + # MyApp::JSONC_CODER.load(document) + # + class Coder + # :call-seq: + # JSON.new(options = nil, &block) + # + # Argument +options+, if given, contains a \Hash of options for both parsing and generating. + # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options]. + # + # For generation, the strict: true option is always set. When a Ruby object with no native \JSON counterpart is + # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native + # \JSON counterpart: + # + # module MyApp + # API_JSON_CODER = JSON::Coder.new do |object| + # case object + # when Time + # object.iso8601(3) + # else + # object # Unknown type, will raise + # end + # end + # end + # + # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z" + # + def initialize(options = nil, &as_json) + if options.nil? + options = { strict: true } + else + options = options.dup + options[:strict] = true + end + options[:as_json] = as_json if as_json + options[:create_additions] = false unless options.key?(:create_additions) + + @state = State.new(options).freeze + @parser_config = Ext::Parser::Config.new(options) + end + + # call-seq: + # dump(object) -> String + # dump(object, io) -> io + # + # Serialize the given object into a \JSON document. + def dump(object, io = nil) + @state.generate_new(object, io) + end + alias_method :generate, :dump + + # call-seq: + # load(string) -> Object + # + # Parse the given \JSON document and return an equivalent Ruby object. + def load(source) + @parser_config.parse(source) + end + alias_method :parse, :load + + # call-seq: + # load(path) -> Object + # + # Parse the given \JSON document and return an equivalent Ruby object. + def load_file(path) + load(File.read(path, encoding: Encoding::UTF_8)) + end + end +end + +module ::Kernel + private + + # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in + # one line. + def j(*objs) + objs.each do |obj| + puts JSON::generate(obj, :allow_nan => true, :max_nesting => false) + end + nil + end + + # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with + # indentation and over many lines. + def jj(*objs) + objs.each do |obj| + puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false) + end + nil + end + + # If _object_ is string-like, parse the string and return the parsed result as + # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data + # structure object and return it. + # + # The _opts_ argument is passed through to generate/parse respectively. See + # generate and parse for their documentation. + def JSON(object, *args) + if object.is_a?(String) + return JSON.parse(object, args.first) + elsif object.respond_to?(:to_str) + str = object.to_str + if str.is_a?(String) + return JSON.parse(object.to_str, args.first) + end + end + + JSON.generate(object, args.first) + end +end + +# Extends any Class to include _json_creatable?_ method. +class ::Class + # Returns true if this class can be used to create an instance + # from a serialised JSON string. The class has to implement a class + # method _json_create_ that expects a hash as first parameter. The hash + # should include the required data. + def json_creatable? + respond_to?(:json_create) + end +end diff --git a/bin/gems/json-2.10.2/lib/json/ext.rb b/bin/gems/json-2.10.2/lib/json/ext.rb new file mode 100644 index 00000000..1db5ea12 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/ext.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'json/common' + +module JSON + # This module holds all the modules/classes that implement JSON's + # functionality as C extensions. + module Ext + class Parser + class << self + def parse(...) + new(...).parse + end + alias_method :parse, :parse # Allow redefinition by extensions + end + + def initialize(source, opts = nil) + @source = source + @config = Config.new(opts) + end + + def source + @source.dup + end + + def parse + @config.parse(@source) + end + end + + require 'json/ext/parser' + Ext::Parser::Config = Ext::ParserConfig + JSON.parser = Ext::Parser + + if RUBY_ENGINE == 'truffleruby' + require 'json/truffle_ruby/generator' + JSON.generator = ::JSON::TruffleRuby::Generator + else + require 'json/ext/generator' + JSON.generator = Generator + end + end + + JSON_LOADED = true unless defined?(::JSON::JSON_LOADED) +end diff --git a/bin/gems/json-2.10.2/lib/json/ext/generator.so b/bin/gems/json-2.10.2/lib/json/ext/generator.so new file mode 100755 index 00000000..ca348658 Binary files /dev/null and b/bin/gems/json-2.10.2/lib/json/ext/generator.so differ diff --git a/bin/gems/json-2.10.2/lib/json/ext/generator/state.rb b/bin/gems/json-2.10.2/lib/json/ext/generator/state.rb new file mode 100644 index 00000000..d40c3b5e --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/ext/generator/state.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module JSON + module Ext + module Generator + class State + # call-seq: new(opts = {}) + # + # Instantiates a new State object, configured by _opts_. + # + # _opts_ can have the following keys: + # + # * *indent*: a string used to indent levels (default: ''), + # * *space*: a string that is put after, a : or , delimiter (default: ''), + # * *space_before*: a string that is put before a : pair delimiter (default: ''), + # * *object_nl*: a string that is put at the end of a JSON object (default: ''), + # * *array_nl*: a string that is put at the end of a JSON array (default: ''), + # * *allow_nan*: true if NaN, Infinity, and -Infinity should be + # generated, otherwise an exception is thrown, if these values are + # encountered. This options defaults to false. + # * *ascii_only*: true if only ASCII characters should be generated. This + # option defaults to false. + # * *buffer_initial_length*: sets the initial length of the generator's + # internal buffer. + def initialize(opts = nil) + if opts && !opts.empty? + configure(opts) + end + end + + # call-seq: configure(opts) + # + # Configure this State instance with the Hash _opts_, and return + # itself. + def configure(opts) + unless opts.is_a?(Hash) + if opts.respond_to?(:to_hash) + opts = opts.to_hash + elsif opts.respond_to?(:to_h) + opts = opts.to_h + else + raise TypeError, "can't convert #{opts.class} into Hash" + end + end + _configure(opts) + end + + alias_method :merge, :configure + + # call-seq: to_h + # + # Returns the configuration instance variables as a hash, that can be + # passed to the configure method. + def to_h + result = { + indent: indent, + space: space, + space_before: space_before, + object_nl: object_nl, + array_nl: array_nl, + as_json: as_json, + allow_nan: allow_nan?, + ascii_only: ascii_only?, + max_nesting: max_nesting, + script_safe: script_safe?, + strict: strict?, + depth: depth, + buffer_initial_length: buffer_initial_length, + } + + instance_variables.each do |iv| + iv = iv.to_s[1..-1] + result[iv.to_sym] = self[iv] + end + + result + end + + alias_method :to_hash, :to_h + + # call-seq: [](name) + # + # Returns the value returned by method +name+. + def [](name) + if respond_to?(name) + __send__(name) + else + instance_variable_get("@#{name}") if + instance_variables.include?("@#{name}".to_sym) # avoid warning + end + end + + # call-seq: []=(name, value) + # + # Sets the attribute name to value. + def []=(name, value) + if respond_to?(name_writer = "#{name}=") + __send__ name_writer, value + else + instance_variable_set "@#{name}", value + end + end + end + end + end +end diff --git a/bin/gems/json-2.10.2/lib/json/ext/parser.so b/bin/gems/json-2.10.2/lib/json/ext/parser.so new file mode 100755 index 00000000..79f1247f Binary files /dev/null and b/bin/gems/json-2.10.2/lib/json/ext/parser.so differ diff --git a/bin/gems/json-2.10.2/lib/json/generic_object.rb b/bin/gems/json-2.10.2/lib/json/generic_object.rb new file mode 100644 index 00000000..ec5aa9dc --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/generic_object.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true +begin + require 'ostruct' +rescue LoadError + warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`." +end + +module JSON + class GenericObject < OpenStruct + class << self + alias [] new + + def json_creatable? + @json_creatable + end + + attr_writer :json_creatable + + def json_create(data) + data = data.dup + data.delete JSON.create_id + self[data] + end + + def from_hash(object) + case + when object.respond_to?(:to_hash) + result = new + object.to_hash.each do |key, value| + result[key] = from_hash(value) + end + result + when object.respond_to?(:to_ary) + object.to_ary.map { |a| from_hash(a) } + else + object + end + end + + def load(source, proc = nil, opts = {}) + result = ::JSON.load(source, proc, opts.merge(:object_class => self)) + result.nil? ? new : result + end + + def dump(obj, *args) + ::JSON.dump(obj, *args) + end + end + self.json_creatable = false + + def to_hash + table + end + + def [](name) + __send__(name) + end unless method_defined?(:[]) + + def []=(name, value) + __send__("#{name}=", value) + end unless method_defined?(:[]=) + + def |(other) + self.class[other.to_hash.merge(to_hash)] + end + + def as_json(*) + { JSON.create_id => self.class.name }.merge to_hash + end + + def to_json(*a) + as_json.to_json(*a) + end + end if defined?(::OpenStruct) +end diff --git a/bin/gems/json-2.10.2/lib/json/truffle_ruby/generator.rb b/bin/gems/json-2.10.2/lib/json/truffle_ruby/generator.rb new file mode 100644 index 00000000..bf6289f1 --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/truffle_ruby/generator.rb @@ -0,0 +1,690 @@ +# frozen_string_literal: true +module JSON + module TruffleRuby + module Generator + MAP = { + "\x0" => '\u0000', + "\x1" => '\u0001', + "\x2" => '\u0002', + "\x3" => '\u0003', + "\x4" => '\u0004', + "\x5" => '\u0005', + "\x6" => '\u0006', + "\x7" => '\u0007', + "\b" => '\b', + "\t" => '\t', + "\n" => '\n', + "\xb" => '\u000b', + "\f" => '\f', + "\r" => '\r', + "\xe" => '\u000e', + "\xf" => '\u000f', + "\x10" => '\u0010', + "\x11" => '\u0011', + "\x12" => '\u0012', + "\x13" => '\u0013', + "\x14" => '\u0014', + "\x15" => '\u0015', + "\x16" => '\u0016', + "\x17" => '\u0017', + "\x18" => '\u0018', + "\x19" => '\u0019', + "\x1a" => '\u001a', + "\x1b" => '\u001b', + "\x1c" => '\u001c', + "\x1d" => '\u001d', + "\x1e" => '\u001e', + "\x1f" => '\u001f', + '"' => '\"', + '\\' => '\\\\', + }.freeze # :nodoc: + + SCRIPT_SAFE_MAP = MAP.merge( + '/' => '\\/', + "\u2028" => '\u2028', + "\u2029" => '\u2029', + ).freeze + + SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/ + + # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with + # UTF16 big endian characters as \u????, and return it. + def self.utf8_to_json(string, script_safe = false) # :nodoc: + if script_safe + if SCRIPT_SAFE_ESCAPE_PATTERN.match?(string) + string.gsub(SCRIPT_SAFE_ESCAPE_PATTERN, SCRIPT_SAFE_MAP) + else + string + end + else + if /["\\\x0-\x1f]/.match?(string) + string.gsub(/["\\\x0-\x1f]/, MAP) + else + string + end + end + end + + def self.utf8_to_json_ascii(original_string, script_safe = false) # :nodoc: + string = original_string.b + map = script_safe ? SCRIPT_SAFE_MAP : MAP + string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& } + string.gsub!(/( + (?: + [\xc2-\xdf][\x80-\xbf] | + [\xe0-\xef][\x80-\xbf]{2} | + [\xf0-\xf4][\x80-\xbf]{3} + )+ | + [\x80-\xc1\xf5-\xff] # invalid + )/nx) { |c| + c.size == 1 and raise GeneratorError.new("invalid utf8 byte: '#{c}'", original_string) + s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0] + s.force_encoding(::Encoding::BINARY) + s.gsub!(/.{4}/n, '\\\\u\&') + s.force_encoding(::Encoding::UTF_8) + } + string.force_encoding(::Encoding::UTF_8) + string + rescue => e + raise GeneratorError.new(e.message, original_string) + end + + def self.valid_utf8?(string) + encoding = string.encoding + (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) && + string.valid_encoding? + end + + # This class is used to create State instances, that are use to hold data + # while generating a JSON text from a Ruby data structure. + class State + def self.generate(obj, opts = nil, io = nil) + new(opts).generate(obj, io) + end + + # Creates a State object from _opts_, which ought to be Hash to create + # a new State instance configured by _opts_, something else to create + # an unconfigured instance. If _opts_ is a State object, it is just + # returned. + def self.from_state(opts) + if opts + case + when self === opts + return opts + when opts.respond_to?(:to_hash) + return new(opts.to_hash) + when opts.respond_to?(:to_h) + return new(opts.to_h) + end + end + SAFE_STATE_PROTOTYPE.dup + end + + # Instantiates a new State object, configured by _opts_. + # + # _opts_ can have the following keys: + # + # * *indent*: a string used to indent levels (default: ''), + # * *space*: a string that is put after, a : or , delimiter (default: ''), + # * *space_before*: a string that is put before a : pair delimiter (default: ''), + # * *object_nl*: a string that is put at the end of a JSON object (default: ''), + # * *array_nl*: a string that is put at the end of a JSON array (default: ''), + # * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped + # as to make the JSON object safe to interpolate in a script tag (default: false). + # * *check_circular*: is deprecated now, use the :max_nesting option instead, + # * *max_nesting*: sets the maximum level of data structure nesting in + # the generated JSON, max_nesting = 0 if no maximum should be checked. + # * *allow_nan*: true if NaN, Infinity, and -Infinity should be + # generated, otherwise an exception is thrown, if these values are + # encountered. This options defaults to false. + def initialize(opts = nil) + @indent = '' + @space = '' + @space_before = '' + @object_nl = '' + @array_nl = '' + @allow_nan = false + @ascii_only = false + @as_json = false + @depth = 0 + @buffer_initial_length = 1024 + @script_safe = false + @strict = false + @max_nesting = 100 + configure(opts) if opts + end + + # This string is used to indent levels in the JSON text. + attr_accessor :indent + + # This string is used to insert a space between the tokens in a JSON + # string. + attr_accessor :space + + # This string is used to insert a space before the ':' in JSON objects. + attr_accessor :space_before + + # This string is put at the end of a line that holds a JSON object (or + # Hash). + attr_accessor :object_nl + + # This string is put at the end of a line that holds a JSON array. + attr_accessor :array_nl + + # This proc converts unsupported types into native JSON types. + attr_accessor :as_json + + # This integer returns the maximum level of data structure nesting in + # the generated JSON, max_nesting = 0 if no maximum is checked. + attr_accessor :max_nesting + + # If this attribute is set to true, forward slashes will be escaped in + # all json strings. + attr_accessor :script_safe + + # If this attribute is set to true, attempting to serialize types not + # supported by the JSON spec will raise a JSON::GeneratorError + attr_accessor :strict + + # :stopdoc: + attr_reader :buffer_initial_length + + def buffer_initial_length=(length) + if length > 0 + @buffer_initial_length = length + end + end + # :startdoc: + + # This integer returns the current depth data structure nesting in the + # generated JSON. + attr_accessor :depth + + def check_max_nesting # :nodoc: + return if @max_nesting.zero? + current_nesting = depth + 1 + current_nesting > @max_nesting and + raise NestingError, "nesting of #{current_nesting} is too deep" + end + + # Returns true, if circular data structures are checked, + # otherwise returns false. + def check_circular? + !@max_nesting.zero? + end + + # Returns true if NaN, Infinity, and -Infinity should be considered as + # valid JSON and output. + def allow_nan? + @allow_nan + end + + # Returns true, if only ASCII characters should be generated. Otherwise + # returns false. + def ascii_only? + @ascii_only + end + + # Returns true, if forward slashes are escaped. Otherwise returns false. + def script_safe? + @script_safe + end + + # Returns true, if strict mode is enabled. Otherwise returns false. + # Strict mode only allow serializing JSON native types: Hash, Array, + # String, Integer, Float, true, false and nil. + def strict? + @strict + end + + # Configure this State instance with the Hash _opts_, and return + # itself. + def configure(opts) + if opts.respond_to?(:to_hash) + opts = opts.to_hash + elsif opts.respond_to?(:to_h) + opts = opts.to_h + else + raise TypeError, "can't convert #{opts.class} into Hash" + end + opts.each do |key, value| + instance_variable_set "@#{key}", value + end + + # NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json + @indent = opts[:indent] || '' if opts.key?(:indent) + @space = opts[:space] || '' if opts.key?(:space) + @space_before = opts[:space_before] || '' if opts.key?(:space_before) + @object_nl = opts[:object_nl] || '' if opts.key?(:object_nl) + @array_nl = opts[:array_nl] || '' if opts.key?(:array_nl) + @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan) + @as_json = opts[:as_json].to_proc if opts[:as_json] + @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only) + @depth = opts[:depth] || 0 + @buffer_initial_length ||= opts[:buffer_initial_length] + + @script_safe = if opts.key?(:script_safe) + !!opts[:script_safe] + elsif opts.key?(:escape_slash) + !!opts[:escape_slash] + else + false + end + + @strict = !!opts[:strict] if opts.key?(:strict) + + if !opts.key?(:max_nesting) # defaults to 100 + @max_nesting = 100 + elsif opts[:max_nesting] + @max_nesting = opts[:max_nesting] + else + @max_nesting = 0 + end + self + end + alias merge configure + + # Returns the configuration instance variables as a hash, that can be + # passed to the configure method. + def to_h + result = {} + instance_variables.each do |iv| + iv = iv.to_s[1..-1] + result[iv.to_sym] = self[iv] + end + result + end + + alias to_hash to_h + + # Generates a valid JSON document from object +obj+ and + # returns the result. If no valid JSON document can be + # created this method raises a + # GeneratorError exception. + def generate(obj, anIO = nil) + if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and + !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj) + result = generate_json(obj, ''.dup) + else + result = obj.to_json(self) + end + JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new( + "source sequence #{result.inspect} is illegal/malformed utf-8", + obj + ) + if anIO + anIO.write(result) + anIO + else + result + end + end + + def generate_new(obj, anIO = nil) # :nodoc: + dup.generate(obj, anIO) + end + + # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above) + private def generate_json(obj, buf) + case obj + when Hash + buf << '{' + first = true + obj.each_pair do |k,v| + buf << ',' unless first + + key_str = k.to_s + if key_str.class == String + fast_serialize_string(key_str, buf) + elsif key_str.is_a?(String) + generate_json(key_str, buf) + else + raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String" + end + + buf << ':' + generate_json(v, buf) + first = false + end + buf << '}' + when Array + buf << '[' + first = true + obj.each do |e| + buf << ',' unless first + generate_json(e, buf) + first = false + end + buf << ']' + when String + if obj.class == String + fast_serialize_string(obj, buf) + else + buf << obj.to_json(self) + end + when Integer + buf << obj.to_s + when Symbol + if @strict + fast_serialize_string(obj.name, buf) + else + buf << obj.to_json(self) + end + else + # Note: Float is handled this way since Float#to_s is slow anyway + buf << obj.to_json(self) + end + end + + # Assumes !@ascii_only, !@script_safe + private def fast_serialize_string(string, buf) # :nodoc: + buf << '"' + unless string.encoding == ::Encoding::UTF_8 + begin + string = string.encode(::Encoding::UTF_8) + rescue Encoding::UndefinedConversionError => error + raise GeneratorError.new(error.message, string) + end + end + raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding? + + if /["\\\x0-\x1f]/.match?(string) + buf << string.gsub(/["\\\x0-\x1f]/, MAP) + else + buf << string + end + buf << '"' + end + + # Return the value returned by method +name+. + def [](name) + if respond_to?(name) + __send__(name) + else + instance_variable_get("@#{name}") if + instance_variables.include?("@#{name}".to_sym) # avoid warning + end + end + + def []=(name, value) + if respond_to?(name_writer = "#{name}=") + __send__ name_writer, value + else + instance_variable_set "@#{name}", value + end + end + end + + module GeneratorMethods + module Object + # Converts this object to a string (calling #to_s), converts + # it to a JSON string, and returns the result. This is a fallback, if no + # special method #to_json was defined for some object. + def to_json(state = nil, *) + state = State.from_state(state) if state + if state&.strict? + value = self + if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value) + if state.as_json + value = state.as_json.call(value) + unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value + raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value) + end + value.to_json(state) + else + raise GeneratorError.new("#{value.class} not allowed in JSON", value) + end + end + else + to_s.to_json + end + end + end + + module Hash + # Returns a JSON string containing a JSON object, that is unparsed from + # this Hash instance. + # _state_ is a JSON::State object, that can also be used to configure the + # produced JSON string output further. + # _depth_ is used to find out nesting depth, to indent accordingly. + def to_json(state = nil, *) + state = State.from_state(state) + state.check_max_nesting + json_transform(state) + end + + private + + def json_shift(state) + state.object_nl.empty? or return '' + state.indent * state.depth + end + + def json_transform(state) + depth = state.depth += 1 + + if empty? + state.depth -= 1 + return '{}' + end + + delim = ",#{state.object_nl}" + result = +"{#{state.object_nl}" + first = true + indent = !state.object_nl.empty? + each { |key, value| + result << delim unless first + result << state.indent * depth if indent + + key_str = key.to_s + if key_str.is_a?(String) + key_json = key_str.to_json(state) + else + raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String" + end + + result = +"#{result}#{key_json}#{state.space_before}:#{state.space}" + if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value) + if state.as_json + value = state.as_json.call(value) + unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value + raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value) + end + result << value.to_json(state) + else + raise GeneratorError.new("#{value.class} not allowed in JSON", value) + end + elsif value.respond_to?(:to_json) + result << value.to_json(state) + else + result << %{"#{String(value)}"} + end + first = false + } + depth = state.depth -= 1 + unless first + result << state.object_nl + result << state.indent * depth if indent + end + result << '}' + result + end + end + + module Array + # Returns a JSON string containing a JSON array, that is unparsed from + # this Array instance. + # _state_ is a JSON::State object, that can also be used to configure the + # produced JSON string output further. + def to_json(state = nil, *) + state = State.from_state(state) + state.check_max_nesting + json_transform(state) + end + + private + + def json_transform(state) + depth = state.depth += 1 + + if empty? + state.depth -= 1 + return '[]' + end + + result = '['.dup + if state.array_nl.empty? + delim = "," + else + result << state.array_nl + delim = ",#{state.array_nl}" + end + + first = true + indent = !state.array_nl.empty? + each { |value| + result << delim unless first + result << state.indent * depth if indent + if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol == value) + if state.as_json + value = state.as_json.call(value) + unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol === value + raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value) + end + result << value.to_json(state) + else + raise GeneratorError.new("#{value.class} not allowed in JSON", value) + end + elsif value.respond_to?(:to_json) + result << value.to_json(state) + else + result << %{"#{String(value)}"} + end + first = false + } + depth = state.depth -= 1 + result << state.array_nl + result << state.indent * depth if indent + result << ']' + end + end + + module Integer + # Returns a JSON string representation for this Integer number. + def to_json(*) to_s end + end + + module Float + # Returns a JSON string representation for this Float number. + def to_json(state = nil, *args) + state = State.from_state(state) + if infinite? || nan? + if state.allow_nan? + to_s + elsif state.strict? && state.as_json + casted_value = state.as_json.call(self) + + if casted_value.equal?(self) + raise GeneratorError.new("#{self} not allowed in JSON", self) + end + + state.check_max_nesting + state.depth += 1 + result = casted_value.to_json(state, *args) + state.depth -= 1 + result + else + raise GeneratorError.new("#{self} not allowed in JSON", self) + end + else + to_s + end + end + end + + module Symbol + def to_json(state = nil, *args) + state = State.from_state(state) + if state.strict? + name.to_json(state, *args) + else + super + end + end + end + + module String + # This string should be encoded with UTF-8 A call to this method + # returns a JSON string encoded with UTF16 big endian characters as + # \u????. + def to_json(state = nil, *args) + state = State.from_state(state) + if encoding == ::Encoding::UTF_8 + unless valid_encoding? + raise GeneratorError.new("source sequence is illegal/malformed utf-8", self) + end + string = self + else + string = encode(::Encoding::UTF_8) + end + if state.ascii_only? + %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}") + else + %("#{JSON::TruffleRuby::Generator.utf8_to_json(string, state.script_safe)}") + end + rescue Encoding::UndefinedConversionError => error + raise ::JSON::GeneratorError.new(error.message, self) + end + + # Module that holds the extending methods if, the String module is + # included. + module Extend + # Raw Strings are JSON Objects (the raw bytes are stored in an + # array for the key "raw"). The Ruby String can be created by this + # module method. + def json_create(o) + o['raw'].pack('C*') + end + end + + # Extends _modul_ with the String::Extend module. + def self.included(modul) + modul.extend Extend + end + + # This method creates a raw object hash, that can be nested into + # other data structures and will be unparsed as a raw string. This + # method should be used, if you want to convert raw strings to JSON + # instead of UTF-8 strings, e. g. binary data. + def to_json_raw_object + { + JSON.create_id => self.class.name, + 'raw' => self.unpack('C*'), + } + end + + # This method creates a JSON text from the result of + # a call to to_json_raw_object of this String. + def to_json_raw(*args) + to_json_raw_object.to_json(*args) + end + end + + module TrueClass + # Returns a JSON string for true: 'true'. + def to_json(*) 'true' end + end + + module FalseClass + # Returns a JSON string for false: 'false'. + def to_json(*) 'false' end + end + + module NilClass + # Returns a JSON string for nil: 'null'. + def to_json(*) 'null' end + end + end + end + end +end diff --git a/bin/gems/json-2.10.2/lib/json/version.rb b/bin/gems/json-2.10.2/lib/json/version.rb new file mode 100644 index 00000000..9c21f18b --- /dev/null +++ b/bin/gems/json-2.10.2/lib/json/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module JSON + VERSION = '2.10.2' +end diff --git a/bin/gems/key-value-parser-0.0.2/.gitignore b/bin/gems/key-value-parser-0.0.2/.gitignore new file mode 100644 index 00000000..aa87180f --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/.gitignore @@ -0,0 +1,7 @@ +.DS_STORE +*.swp +*.sass-cache +pkg/ +Gemfile.lock +.bundle/ + diff --git a/bin/gems/key-value-parser-0.0.2/Gemfile b/bin/gems/key-value-parser-0.0.2/Gemfile new file mode 100644 index 00000000..fe52fd11 --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' +gemspec +gem 'minitest', '>=5.8.0' + diff --git a/bin/gems/key-value-parser-0.0.2/LICENSE b/bin/gems/key-value-parser-0.0.2/LICENSE new file mode 100644 index 00000000..07bc7357 --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2016 Mickael Riga + +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/bin/gems/key-value-parser-0.0.2/README.md b/bin/gems/key-value-parser-0.0.2/README.md new file mode 100644 index 00000000..46bd514f --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/README.md @@ -0,0 +1,183 @@ +Key Value Parser +================ + +The primary purpose of `KeyValueParser` is to have a +simple class to be able to parse command line arguments +which are all formated as `key=value`. + +For example you could call a script like this: + +``` +$ ruby my-script.rb port=3000 host=localhost user=bob +``` + +Then in your script you would do: + +```ruby +# my-script.rb + +require 'key_value_parser' + +options = KeyValueParser.new.parse(ARGV) +options[:port] == 3000 +options[:host] == 'localhost' +options[:user] == 'bob' +``` + +Since `KeyValueParser` is quite opinionated, it is absolutely +not a replacement for `OptionParser` which aim is to be able to +parse Unix style arguments. + +Also `KeyValueParser` is not limited to command line arguments. +It can potentially parse any array which is a list of Key/Value +strings. For example you can parse a list of HTTP header lines. + +The following sections are list of features in order to understand +what `KeyValueParser` can and cannot do. + +Default Values +-------------- + +When you create the parser instance, you can pass a `Hash` with +default values. + +```ruby +# $ ruby my-script.rb host=www.domain.com +parser = KeyValueParser.new host: 'localhost', port: 3000 +options = parser.parse(ARGV) +options[:port] == 3000 +options[:host] == 'www.domain.com' +``` + +Typecasted Values +----------------- + +As you may have noticed in previous examples, values are +typecasted. So far it does typecast integers, floats and booleans. +Also if you don't give a value, the parser will interpret +it as a flag and set it to `true`. + +```ruby +# $ ruby myscript.rb port=3000 broadcast=false running +options = KeyValueParser.new.parse(ARGV) +options[:port] == 3000 +options[:broadcast] == false +options[:running] == true +``` + +If you don't want to cast values, you can use the second argument of +`KeyValueParse#parse` which is a list of options. Just set +`typecast_values` to `false`. + +```ruby +parser = KeyValueParser.new({}, {typecast_values: false}) +``` + +Typecasting is still very basic and will most likely evolve, +but it will move in this direction. + +Normalized Keys +--------------- + +Keys of the resulting `Hash` are normalized. Dash in the middle +of words are replaced by underscores. Double dash in front of a +word are also removed. It allows you to have unix style double dash +arguments. + +```ruby +# $ ruby my-script.rb --user-name="bob mould" +options = KeyValueParser.new.parse(ARGV) +options[:user_name] == 'bob' +``` + +Because of the way command line arguments are created for `ARGV` +you can even surround an argument with quotes in order to have +spaces in the argument's value. + +There is nothing yet for unix style single dash arguments. +I could remove the dash and treat it like a single letter key, +but the true purpose of single letter arguments is to be an +alternative to a longer argument name. If you have a simple idea +to implement this without too much hassle, please send me a pull +request. + +If you don't want the keys to be normalized, there is an option +for this. + +```ruby +# $ ruby my-script.rb --user-name=bob +parser = KeyValueParser.new({}, {normalize_keys: false}) +options = parser.parse(ARGV) +options['--user-name'] == 'bob' +``` + +Array Arguments +--------------- + +You can have array values if you chain more than one `=` +after the key. And the values are still typecasted unless you +disable it. + +```ruby +# $ ruby my-script.rb heroes=batman=robin ids=1=2 +options = KeyValueParser.new.parse(ARGV) +options[:heroes] == ['batman', 'robin'] +options[:ids] == [1, 2] +``` + +You can also disable this option: + +```ruby +# $ ruby my-script.rb heroes=batman=robin +parser = KeyValueParser.new({}, {array_values: false}) +options = parser.parse(ARGV) +options[:heroes] == 'batman=robin' +``` + +Please note that so far this is the only way to make an array. +Setting multiple times the same value would just result +in the key being set to the last value. + +```ruby +# $ ruby my-script.rb heroes=batman heroes=robin +options = KeyValueParser.new.parse(ARGV) +options[:heroes] == 'robin' +``` + +Parsing More Than ARGV +---------------------- + +By default, the separator allows you to have an equal sign `=` +or a colon `:`. And the regexp allows spaces around the separator. +The surrounded spaces are if you want to parse a list of keys/values +from a file for example. Let say you have a file containing a +key/value per line. + +``` +user: Bob Mould +number: 42 +``` + +Which looks like a subset of YAML. +Then you can parse the file for settings. + +```ruby +parser = KeyValueParser.new +settings = parser.parse File.readlines('settings.conf') +``` +Everything works the same, typecasting, normalizing keys, defaults, arrays... +You can also set another separator. Anything which works with +`String#split` will do. + +```ruby +# settings.conf: +# author | Kevin Smith +# characters | Jay | Silent Bob + +parser = KeyValueParser.new({stars: 5}, {separator: /\s*\|\s*/}) +settings = parser.parse File.readlines('settings.conf') +settings[:author] == 'Kevin Smith' +settings[:characters] == ['Jay', 'Silent Bob'] +settings[:stars] == 5 +``` + diff --git a/bin/gems/key-value-parser-0.0.2/key-value-parser.gemspec b/bin/gems/key-value-parser-0.0.2/key-value-parser.gemspec new file mode 100644 index 00000000..49bf1d76 --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/key-value-parser.gemspec @@ -0,0 +1,19 @@ +Gem::Specification.new do |s| + + s.authors = ["Mickael Riga"] + s.email = ["mig@mypeplum.com"] + s.homepage = "https://github.com/mig-hub/key-value-parser" + s.licenses = ['MIT'] + + s.name = 'key-value-parser' + s.version = '0.0.2' + s.summary = "Key Value Parser" + s.description = "KeyValueParser parses arrays of string options like 'machine=coconut'. It is mainly done for parsing ARGV, but can be used for other things." + + s.platform = Gem::Platform::RUBY + s.files = `git ls-files`.split("\n").sort + s.test_files = s.files.grep(/^test\//) + s.require_paths = ['lib'] + +end + diff --git a/bin/gems/key-value-parser-0.0.2/lib/key_value_parser.rb b/bin/gems/key-value-parser-0.0.2/lib/key_value_parser.rb new file mode 100644 index 00000000..bab42ba9 --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/lib/key_value_parser.rb @@ -0,0 +1,56 @@ +class KeyValueParser + + def initialize defaults={}, options={} + @defaults = defaults + @options = { + separator: /\s*[=:]\s*/, + normalize_keys: true, + typecast_values: true, + array_values: true + }.merge(options) + end + + def parse kvs + @defaults.merge( + Hash[ + kvs.map do |a| + k, *v = a.split(@options[:separator], @options[:array_values] ? 0 : 2) + if v.size==1 + v = v[0] + elsif v.size==0 + v = nil + end + [ + @options[:normalize_keys] ? normalize_key(k) : k, + @options[:typecast_values] ? typecast(v) : v + ] + end + ] + ) + end + + private + + def normalize_key k + k.sub(/^--/,'').gsub(/[\s\-]+/, '_').to_sym + end + + def typecast v + if v.is_a? Array + return v.map{|item| typecast(item)} + end + if v=='true' or v.nil? + v = true + elsif v=='false' + v = false + elsif v=~/^-?\d*\.\d+$/ + v = v.to_f + elsif v=~/^-?\d+$/ + v = v.to_i + else + v + end + end + +end + diff --git a/bin/gems/key-value-parser-0.0.2/test/test_key_value_parser.rb b/bin/gems/key-value-parser-0.0.2/test/test_key_value_parser.rb new file mode 100644 index 00000000..1cb1b091 --- /dev/null +++ b/bin/gems/key-value-parser-0.0.2/test/test_key_value_parser.rb @@ -0,0 +1,124 @@ +require 'minitest/autorun' +require 'key_value_parser' + +class TestKeyValueParser < Minitest::Test + + def setup + @parser = KeyValueParser.new + end + + def test_parses_kvs + kvs = ['user:mig', 'machine:coconut'] + expected = {user: 'mig', machine: 'coconut'} + assert_equal expected, @parser.parse(kvs) + end + + def test_equal_works_as_separator + kvs = ['user=mig', 'machine=coconut'] + expected = {user: 'mig', machine: 'coconut'} + assert_equal expected, @parser.parse(kvs) + end + + def test_spaces_work_in_separator + kvs = ['user= mig', 'machine = coconut'] + expected = {user: 'mig', machine: 'coconut'} + assert_equal expected, @parser.parse(kvs) + end + + def test_booleans_are_typecasted + kvs = ['dead:false', 'running:true'] + expected = {dead: false, running: true} + assert_equal expected, @parser.parse(kvs) + end + + def test_integers_are_typecasted + kvs = ['machine:1coconut', 'size:11', 'negative:-5'] + expected = {machine: '1coconut', size: 11, negative: -5} + assert_equal expected, @parser.parse(kvs) + end + + def test_floats_are_typecasted + kvs = [ + 'machine:5.0coconut', + 'float1:99.99', 'float2:-5.0', 'float3:.4' + ] + expected = { + machine: '5.0coconut', + float1: 99.99, float2: -5.0, float3: 0.4 + } + assert_equal expected, @parser.parse(kvs) + end + + def test_nil_value_typecasted_to_true + kvs = ['running'] + expected = {running: true} + assert_equal expected, @parser.parse(kvs) + end + + def test_parser_can_have_defaults + kvs = ['user:mig'] + expected = {user: 'mig', role: 'dev'} + parser = KeyValueParser.new user: 'marty', role: 'dev' + assert_equal expected, parser.parse(kvs) + end + + def test_separator_can_be_changed + kvs = ['user|mig', 'machine|coconut'] + expected = {user: 'mig', machine: 'coconut'} + wrong_parser = KeyValueParser.new + refute_equal expected, wrong_parser.parse(kvs) + parser = KeyValueParser.new({}, separator: '|') + assert_equal expected, parser.parse(kvs) + end + + def test_keys_are_normalized + kvs = ['user-name=mig', 'machine_name=coconut', 'why not=yes'] + expected = {user_name: 'mig', machine_name: 'coconut', why_not: 'yes'} + assert_equal expected, @parser.parse(kvs) + end + + def test_unix_double_dash_keys_are_normalized + kvs = ['--user-name=mig', '--running'] + expected = {user_name: 'mig', running: true} + assert_equal expected, @parser.parse(kvs) + end + + def test_value_is_updated_if_key_is_referenced_multiple_times + kvs = ['user:bad', 'user:mig'] + expected = {user: 'mig'} + assert_equal expected, @parser.parse(kvs) + end + + def test_arrays + kvs = ['users:mig:why', 'numbers:3:5', 'request:false:POST:500'] + expected = { + users: ['mig', 'why'], + numbers: [3,5], + request: [false, 'POST', 500] + } + assert_equal expected, @parser.parse(kvs) + end + + def test_normalize_key_can_be_skipped + kvs = ['--user-name=mig', '--running'] + expected = {'--user-name' => 'mig', '--running' => true} + parser = KeyValueParser.new({}, {normalize_keys: false}) + assert_equal expected, parser.parse(kvs) + end + + def test_typecast_can_be_skipped + kvs = ['user:mig', 'size:5', 'crazy:false:maybe', 'dev'] + expected = {user: 'mig', size: '5', crazy: ['false','maybe'], dev: nil} + parser = KeyValueParser.new({}, {typecast_values: false}) + assert_equal expected, parser.parse(kvs) + end + + def test_arrays_can_be_avoided + kvs = ['users:mig=why', 'size:5:6', 'running'] + expected = {users: 'mig=why', size: '5:6', running: true} + parser = KeyValueParser.new({}, {array_values: false}) + assert_equal expected, parser.parse(kvs) + end + +end + diff --git a/bin/gems/kramdown-2.5.1/AUTHORS b/bin/gems/kramdown-2.5.1/AUTHORS new file mode 100644 index 00000000..05835967 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/AUTHORS @@ -0,0 +1 @@ +The author of kramdown is Thomas Leitner . diff --git a/bin/gems/kramdown-2.5.1/CONTRIBUTERS b/bin/gems/kramdown-2.5.1/CONTRIBUTERS new file mode 100644 index 00000000..61ebb2ff --- /dev/null +++ b/bin/gems/kramdown-2.5.1/CONTRIBUTERS @@ -0,0 +1,93 @@ + Count Name +======= ==== + 988 Thomas Leitner + 18 Ashwin Maroli + 7 Christian Cornelssen + 6 Gioele Barabucci + 5 Gleb Mazovetskiy + 4 Ted Pak + 4 Shuanglei Tao + 4 Dan Allen + 4 Arne Brasseur + 3 Henning Perl + 3 gettalong + 3 Carsten Bormann + 3 Brandur + 3 Ben Armston + 3 Ashwin Maroli + 3 Alex Marandon + 2 Tom Thorogood + 2 Parker Moore + 2 Nathanael Jones + 2 Max Meyer + 2 Jo Hund + 2 Bryce Willey + 2 Bran + 1 winniehell + 1 William + 1 Virgil Ierubino <30758921+Convincible@users.noreply.github.com> + 1 Uwe Kubosch + 1 utenmiki + 1 Trevor Wennblom + 1 tomykaira + 1 tom93 + 1 Tobin Yehle + 1 timcraft + 1 Tim Blair + 1 Tim Besard + 1 Tim Bates + 1 Sun Yaozhu + 1 Stephen + 1 Stephen Crosby + 1 Stan Hu + 1 Simon Lydell + 1 Simon Coffey + 1 Shusaku NAKAZATO + 1 Sebastian Boehm + 1 scherr + 1 Postmodern + 1 Pete Michaud + 1 Paul McMahon + 1 Paul <2528280+psfrolov@users.noreply.github.com> + 1 Noah Doersing + 1 myqlarson + 1 milo.simpson + 1 Michal Till + 1 Maxime Kjaer + 1 Matt Hickford + 1 Martyn Chamberlin + 1 Marek Tuchowski + 1 Marcus Stollsteimer + 1 Luca Barbato + 1 l3kn + 1 Kir Kolyshkin + 1 Jun Aruga + 1 Jonathan Hooper + 1 John Haugeland + 1 John Croisant + 1 Joe Fiorini + 1 Jens Kraemer + 1 Jay Stramel + 1 Hirofumi Wakasugi + 1 Hector Correa + 1 Florian Klampfer + 1 Floreal Morandat florealm@gmail.com + 1 Fangyi Zhou + 1 Diego Galeota + 1 David Rodríguez + 1 Daniel Bair + 1 Damien Pollet + 1 Christopher Jefferson + 1 Christian Boos + 1 Cédric Boutillier + 1 Bob Lail + 1 Ashesh Kumar Singh + 1 Ashe Connor + 1 aschmitz <29508+aschmitz@users.noreply.github.com> + 1 Antoine Cotten + 1 Andrew + 1 Alpha Chen + 1 Alex Tomlins + 1 Alex Taylor + 1 Alexey Vasiliev + 1 284km diff --git a/bin/gems/kramdown-2.5.1/COPYING b/bin/gems/kramdown-2.5.1/COPYING new file mode 100644 index 00000000..1c29282e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/COPYING @@ -0,0 +1,30 @@ +kramdown - fast, pure-Ruby Markdown-superset converter +Copyright (C) 2009-2013 Thomas Leitner + +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. + + +Some test cases and the benchmark files are based on test cases from +the MDTest test suite: + + MDTest + Copyright (c) 2007 Michel Fortin + + diff --git a/bin/gems/kramdown-2.5.1/README.md b/bin/gems/kramdown-2.5.1/README.md new file mode 100644 index 00000000..981c0044 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/README.md @@ -0,0 +1,77 @@ +# kramdown + +## Readme first! + +kramdown was originally licensed under the GPL until the 1.0.0 release. However, due to the many +requests it is now released under the MIT license and therefore can easily be used in commercial +projects, too. + +However, if you use kramdown in a commercial setting, please consider **contributing back any +changes** for the benefit of the community and/or [**becoming a +sponsor**](https://github.com/sponsors/gettalong/) or [**a +patron**](https://www.patreon.com/gettalong) - thanks! + +Sponsors: + +* **GROSSWEBER** provides software + development consulting and training services. + + +## Introduction + +kramdown is a fast, pure Ruby Markdown superset converter, using a strict syntax definition and +supporting several common extensions. + +The syntax definition for the kramdown syntax can be found in **doc/syntax.page** (or online at +) and a quick reference is available in +**doc/quickref.page** or online at . + +The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However, +due to its flexibility (by creating an internal AST) it supports other input and output formats as +well. Here is a list of the supported formats: + +* input formats: kramdown (a Markdown superset), Markdown, GFM, HTML +* output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn + +All the documentation on the available input and output formats is available in the **doc/** +directory and online at . + +Starting from version 1.0.0 kramdown is using a versioning scheme with major, minor and patch parts +in the version number where the major number changes on backwards-incompatible changes, the minor +number on the introduction of new features and the patch number on everything else. + +For information about changes between versions, have a look at + or the commit history! + + +## Usage + +kramdown has a very simple API, so using kramdown is as easy as + +```ruby +require 'kramdown' + +Kramdown::Document.new(text).to_html +``` + +For detailed information have a look at the API documentation of the `Kramdown::Document` class. + +The full API documentation is available at , other sites with an +API documentation for kramdown probably don't provide the complete documentation! + +There are also some third-party libraries that extend the functionality of kramdown -- see the +kramdown Wiki at . + + +## Development + +Just clone the git repository as described in **doc/installation.page** and you are good to go. You +probably want to install `rake` so that you can use the provided rake tasks. + +If you want to run the tests, the development dependencies are needed as well as some additional +programs like `tidy` and `latex`. See the `.travis.yml` file for more information. + + +## License + +MIT - see the **COPYING** file. diff --git a/bin/gems/kramdown-2.5.1/VERSION b/bin/gems/kramdown-2.5.1/VERSION new file mode 100644 index 00000000..73462a5a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/VERSION @@ -0,0 +1 @@ +2.5.1 diff --git a/bin/gems/kramdown-2.5.1/bin/kramdown b/bin/gems/kramdown-2.5.1/bin/kramdown new file mode 100755 index 00000000..6aeb9a46 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/bin/kramdown @@ -0,0 +1,135 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'optparse' +require 'rbconfig' +require 'yaml' +require 'kramdown' + +def add_kramdown_options(opts, parsed_options, banner: [], ignore: []) + banner_shown = false + defined_options = [] + Kramdown::Options.definitions.sort.each do |n, definition| + next if ignore.include?(n) + + unless banner_shown + opts.separator("") + banner.each {|part| opts.separator(part) } + opts.separator("") + banner_shown = true + end + + defined_options << n + no = n.to_s.tr('_', '-') + if definition.type == Kramdown::Options::Boolean + opts.on("--[no-]#{no}") {|v| parsed_options[n] = Kramdown::Options.parse(n, v) } + else + type = definition.type + type = String if type == Symbol || type == Object + opts.on("--#{no} ARG", type) {|v| parsed_options[n] = Kramdown::Options.parse(n, v) } + end + + definition.desc.split("\n").each do |line| + opts.separator opts.summary_indent + ' ' * 6 + line + end + opts.separator '' + end + defined_options +end + +config_file = nil +begin + config_dir = case RbConfig::CONFIG['host_os'] + when /bccwin|cygwin|djgpp|mingw|mswin|wince/i + File.expand_path((ENV['HOME'] || ENV['USERPROFILE'] || "~") + "/AppData/Local") + when /darwin|mac os/ + File.expand_path("~/Library/Preferences/") + else + File.expand_path(ENV['XDG_CONFIG_HOME'] || '~/.config') + end + config_file = File.join(config_dir, "kramdownrc") +rescue StandardError +end + +options = {} +format = ['html'] + +defined_options = [] +OptionParser.new do |opts| + opts.banner = "Usage: kramdown [options] [FILE FILE ...]" + opts.summary_indent = ' ' * 4 + + opts.separator "" + opts.separator "Command line options:" + opts.separator "" + + opts.on("-i", "--input ARG", "Specify the input format: kramdown (default), " \ + "html, or markdown") {|v| options[:input] = v } + opts.on("-o", "--output ARG", Array, "Specify one or more output formats separated by commas: " \ + "html (default),", "kramdown, latex, man or remove_html_tags") {|v| format = v } + opts.on("-x", "--extension EXT", Array, "Load one or more extensions (without the 'kramdown-' " \ + "prefix) separated", "by commas (e.g. parser-gfm,syntax-coderay)", + "Note: Use this option before other options!") do |exts| + exts.each do |ext| + require "kramdown-#{ext}" + new_options = add_kramdown_options(opts, options, banner: ["#{ext} options:"], + ignore: defined_options) + defined_options.concat(new_options) + rescue LoadError + $stderr.puts "Couldn't load extension #{ext}, ignoring" + end + end + opts.separator "" + opts.on("--no-config-file", "Do not read any configuration file. Default behavior is to check " \ + "for a", "configuration file and read it if it exists.") { config_file = nil } + opts.on("--config-file FILE", "Specify the name of a configuration file with kramdown options " \ + "in YAML", "format, e.g. \"auto_id_prefix: ARG\" instead of \"--auto-id-prefix ARG\"", + "and \"auto_ids: false\" instead of \"--no-auto-ids\".", + "Default: #{config_file}") {|v| config_file = v } + opts.separator "" + opts.on("-v", "--version", "Show the version of kramdown") do + puts Kramdown::VERSION + exit + end + opts.on("-h", "--help", "Show the help") do + puts opts.summarize(+'', 5, 72) + exit + end + + new_options = add_kramdown_options(opts, options, banner: ["kramdown options:"]) + defined_options.concat(new_options) +end.parse! + +begin + if config_file && File.exist?(config_file) + config_file_options = + if YAML.method(:safe_load).parameters.include?(%i[key permitted_classes]) + YAML.safe_load(File.read(config_file), permitted_classes: [Symbol]) + else # compatibility with Psych < 3.1.0 + YAML.safe_load(File.read(config_file), [Symbol]) + end + case config_file_options + when nil # empty configuration file except perhaps YAML header and comments + # Nothing to do + when Hash + options = config_file_options.merge(options) + else + raise Kramdown::Error, "No YAML map in configuration file \"#{config_file}\"" + end + end + doc = Kramdown::Document.new(ARGF.read, options) + result = '' + format.each {|f| result = doc.send("to_#{f}") } + puts result + doc.warnings.each {|warn| $stderr.puts "Warning: #{warn}" } +rescue Kramdown::Error => e + $stderr.puts "Error: #{e.message}" + exit(1) +end diff --git a/bin/gems/kramdown-2.5.1/data/kramdown/document.html b/bin/gems/kramdown-2.5.1/data/kramdown/document.html new file mode 100644 index 00000000..731d0ea9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/data/kramdown/document.html @@ -0,0 +1,22 @@ + + + + <% if @converter.root.options[:encoding] %> + + <% end %> +<% +extend ::Kramdown::Utils::Html +title = '' +h = @converter.root.children.find {|c| c.type == :header} +if h + collector = lambda {|c| c.children.collect {|cc| cc.type == :text ? escape_html(cc.value, :text) : collector.call(cc)}.join('')} + title = collector.call(h) +end +%> + <%= title %> + + + + <%= @body %> + + diff --git a/bin/gems/kramdown-2.5.1/data/kramdown/document.latex b/bin/gems/kramdown-2.5.1/data/kramdown/document.latex new file mode 100644 index 00000000..acdf346a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/data/kramdown/document.latex @@ -0,0 +1,50 @@ +<% +encmap = { + 'UTF-8' => 'utf8x', + 'US-ASCII' => 'ascii', + 'ISO-8859-1' => 'latin1', + 'ISO-8859-2' => 'latin2', + 'ISO-8859-3' => 'latin3', + 'ISO-8859-4' => 'latin4', + 'ISO-8859-5' => 'latin5', + 'ISO-8859-9' => 'latin9', + 'ISO-8859-10' => 'latin10', + 'CP850' => 'cp850', + 'CP852' => 'cp852', + 'CP858' => 'cp858', + 'CP437' => 'cp437', + 'CP865' => 'cp865', + 'CP1250' => 'cp120', + 'CP1252' => 'cp1252', + 'CP1257' => 'cp1257' +} +%> +\documentclass{scrartcl} +<% if RUBY_VERSION >= '1.9' %> +\usepackage[<%= encmap[@body.encoding.name] %>]{inputenc} +<% else %> +\usepackage[mathletters]{ucs} +\usepackage[utf8x]{inputenc} +<% end %> +\usepackage[T1]{fontenc} +\usepackage{listings} +<% @converter.data[:packages].each {|pkg| %>\usepackage{<%= pkg %>} +<% } %> +\usepackage{hyperref} + +<% if @converter.data[:packages].include?('fancyvrb') %> +\VerbatimFootnotes +<% end %> + +<% if @converter.data[:packages].include?('acronym') %> +<% @converter.root.options[:abbrev_defs].each_pair do |k,v| %>\acrodef{<%= @converter.normalize_abbreviation_key(k) %>}[<%= k %>]{<%= @converter.escape(v) %>} +<% end %> +<% end %> + +\setcounter{footnote}{<%= @converter.options[:footnote_nr] - 1 %>} + +\hypersetup{colorlinks=true,urlcolor=blue} + +\begin{document} +<%= @body %> +\end{document} diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown.rb b/bin/gems/kramdown-2.5.1/lib/kramdown.rb new file mode 100644 index 00000000..3700b9de --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown.rb @@ -0,0 +1,10 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/document' diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter.rb new file mode 100644 index 00000000..0055a144 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter.rb @@ -0,0 +1,68 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' + +module Kramdown + + # This module contains all available converters, i.e. classes that take a root Element and convert + # it to a specific output format. The result is normally a string. For example, the + # Converter::Html module converts an element tree into valid HTML. + # + # Converters use the Base class for common functionality (like applying a template to the output) + # \- see its API documentation for how to create a custom converter class. + module Converter + + autoload :Base, 'kramdown/converter/base' + autoload :Html, 'kramdown/converter/html' + autoload :Latex, 'kramdown/converter/latex' + autoload :Kramdown, 'kramdown/converter/kramdown' + autoload :Toc, 'kramdown/converter/toc' + autoload :RemoveHtmlTags, 'kramdown/converter/remove_html_tags' + autoload :HashAST, 'kramdown/converter/hash_ast' + autoload :HashAst, 'kramdown/converter/hash_ast' + autoload :Man, 'kramdown/converter/man' + + extend ::Kramdown::Utils::Configurable + + configurable(:syntax_highlighter) + + ['Minted', "Rouge"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_syntax_highlighter(kn_down) do |converter, text, lang, type, opts| + require "kramdown/converter/syntax_highlighter/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::SyntaxHighlighter::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_syntax_highlighter(kn_down, klass) + else + add_syntax_highlighter(kn_down) { nil } + end + syntax_highlighter(kn_down).call(converter, text, lang, type, opts) + end + end + + configurable(:math_engine) + + ["Mathjax"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_math_engine(kn_down) do |converter, el, opts| + require "kramdown/converter/math_engine/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::MathEngine::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_math_engine(kn_down, klass) + else + add_math_engine(kn_down) { nil } + end + math_engine(kn_down).call(converter, el, opts) + end + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb new file mode 100644 index 00000000..86cd2b4c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/base.rb @@ -0,0 +1,257 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'erb' +require 'kramdown/utils' +require 'kramdown/document' + +module Kramdown + + module Converter + + # == \Base class for converters + # + # This class serves as base class for all converters. It provides methods that can/should be + # used by all converters (like #generate_id) as well as common functionality that is + # automatically applied to the result (for example, embedding the output into a template). + # + # A converter object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during conversion. Therefore one can't instantiate a converter object + # directly but only use the Base::convert method. + # + # == Implementing a converter + # + # Implementing a new converter is rather easy: just derive a new class from this class and put + # it in the Kramdown::Converter module (the latter is only needed if auto-detection should work + # properly). Then you need to implement the #convert method which has to contain the conversion + # code for converting an element and has to return the conversion result. + # + # The actual transformation of the document tree can be done in any way. However, writing one + # method per element type is a straight forward way to do it - this is how the Html and Latex + # converters do the transformation. + # + # Have a look at the Base::convert method for additional information! + class Base + + # Can be used by a converter for storing arbitrary information during the conversion process. + attr_reader :data + + # The hash with the conversion options. + attr_reader :options + + # The root element that is converted. + attr_reader :root + + # The warnings array. + attr_reader :warnings + + # Initialize the converter with the given +root+ element and +options+ hash. + def initialize(root, options) + @options = options + @root = root + @data = {} + @warnings = [] + end + private_class_method(:new, :allocate) + + # Returns whether the template should be applied before the conversion of the tree. + # + # Defaults to false. + def apply_template_before? + false + end + + # Returns whether the template should be applied after the conversion of the tree. + # + # Defaults to true. + def apply_template_after? + true + end + + # Convert the element tree +tree+ and return the resulting conversion object (normally a + # string) and an array with warning messages. The parameter +options+ specifies the conversion + # options that should be used. + # + # Initializes a new instance of the calling class and then calls the #convert method with + # +tree+ as parameter. + # + # If the +template+ option is specified and non-empty, the template is evaluate with ERB + # before and/or after the tree conversion depending on the result of #apply_template_before? + # and #apply_template_after?. If the template is evaluated before, an empty string is used for + # the body; if evaluated after, the result is used as body. See ::apply_template. + # + # The template resolution is done in the following way (for the converter ConverterName): + # + # 1. Look in the current working directory for the template. + # + # 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting + # file in the current working directory (the form +.convertername+ is deprecated). + # + # 3. Append +.converter_name+ to the template name and look for it in the kramdown data + # directory (the form +.convertername+ is deprecated). + # + # 4. Check if the template name starts with 'string://' and if so, strip this prefix away and + # use the rest as template. + def self.convert(tree, options = {}) + converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {}))) + + if !converter.options[:template].empty? && converter.apply_template_before? + apply_template(converter, '') + end + result = converter.convert(tree) + if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY + result.encode!(tree.options[:encoding] || + (raise ::Kramdown::Error, "Missing encoding option on root element")) + end + if !converter.options[:template].empty? && converter.apply_template_after? + result = apply_template(converter, result) + end + + [result, converter.warnings] + end + + # Convert the element +el+ and return the resulting object. + # + # This is the only method that has to be implemented by sub-classes! + def convert(_el) + raise NotImplementedError + end + + # Apply the +template+ using +body+ as the body string. + # + # The template is evaluated using ERB and the body is available in the @body instance variable + # and the converter object in the @converter instance variable. + def self.apply_template(converter, body) # :nodoc: + erb = ERB.new(get_template(converter.options[:template])) + obj = Object.new + obj.instance_variable_set(:@converter, converter) + obj.instance_variable_set(:@body, body) + erb.result(obj.instance_eval { binding }) + end + + # Return the template specified by +template+. + def self.get_template(template) # :nodoc: + format_ext = '.' + ::Kramdown::Utils.snake_case(name.split("::").last) + shipped = File.join(::Kramdown.data_dir, template + format_ext) + if File.exist?(template) + File.read(template) + elsif File.exist?(template + format_ext) + File.read(template + format_ext) + elsif File.exist?(shipped) + File.read(shipped) + elsif template.start_with?('string://') + template.delete_prefix("string://") + else + raise "The specified template file #{template} does not exist" + end + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + end + + # Return +true+ if the header element +el+ should be used for the table of contents (as + # specified by the +toc_levels+ option). + def in_toc?(el) + @options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/ + end + + # Return the output header level given a level. + # + # Uses the +header_offset+ option for adjusting the header level. + def output_header_level(level) + [[level + @options[:header_offset], 6].min, 1].max + end + + # Extract the code block/span language from the attributes. + def extract_code_language(attr) + if attr['class'] && attr['class'] =~ /\blanguage-\S+/ + attr['class'].scan(/\blanguage-(\S+)/).first.first + end + end + + # See #extract_code_language + # + # *Warning*: This version will modify the given attributes if a language is present. + def extract_code_language!(attr) + lang = extract_code_language(attr) + attr['class'] = attr['class'].sub(/\blanguage-\S+/, '').strip if lang + attr.delete('class') if lang && attr['class'].empty? + lang + end + + # Highlight the given +text+ in the language +lang+ with the syntax highlighter configured + # through the option 'syntax_highlighter'. + def highlight_code(text, lang, type, opts = {}) + return nil unless @options[:syntax_highlighter] + + highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter]) + if highlighter + highlighter.call(self, text, lang, type, opts) + else + warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.") + nil + end + end + + # Format the given math element with the math engine configured through the option + # 'math_engine'. + def format_math(el, opts = {}) + return nil unless @options[:math_engine] + + engine = ::Kramdown::Converter.math_engine(@options[:math_engine]) + if engine + engine.call(self, el, opts) + else + warning("The configured math engine #{@options[:math_engine]} is not available.") + nil + end + end + + # Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID. + # + # Uses the option +auto_id_prefix+: the value of this option is prepended to every generated + # ID. + def generate_id(str) + str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids] + gen_id = basic_generate_id(str) + gen_id = 'section' if gen_id.empty? + @used_ids ||= {} + if @used_ids.key?(gen_id) + gen_id += "-#{@used_ids[gen_id] += 1}" + else + @used_ids[gen_id] = 0 + end + @options[:auto_id_prefix] + gen_id + end + + # The basic version of the ID generator, without any special provisions for empty or unique + # IDs. + def basic_generate_id(str) + gen_id = str.gsub(/^[^a-zA-Z]+/, '') + gen_id.tr!('^a-zA-Z0-9 -', '') + gen_id.tr!(' ', '-') + gen_id.downcase! + gen_id + end + + SMART_QUOTE_INDICES = {lsquo: 0, rsquo: 1, ldquo: 2, rdquo: 3} # :nodoc: + + # Return the entity that represents the given smart_quote element. + def smart_quote_entity(el) + res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]] + ::Kramdown::Utils::Entities.entity(res) + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb new file mode 100644 index 00000000..95714d43 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/hash_ast.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a nested hash for further processing or debug output. + class HashAST < Base + + def convert(el) + hash = {type: el.type} + hash[:attr] = el.attr unless el.attr.empty? + hash[:value] = el.value unless el.value.nil? + hash[:options] = el.options unless el.options.empty? + unless el.children.empty? + hash[:children] = [] + el.children.each {|child| hash[:children] << convert(child) } + end + hash + end + + end + + HashAst = HashAST + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb new file mode 100644 index 00000000..51ac9eb8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/html.rb @@ -0,0 +1,545 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to HTML. + # + # You can customize the HTML converter by sub-classing it and overriding the +convert_NAME+ + # methods. Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+indent+] A number representing the current amount of spaces for indent (only used for + # block-level elements). + # + # The return value of such a method has to be a string containing the element +el+ formatted as + # HTML element. + class Html < Base + + include ::Kramdown::Utils::Html + include ::Kramdown::Parser::Html::Constants + + # The amount of indentation used when nesting HTML tags. + attr_accessor :indent + + # Initialize the HTML converter with the given Kramdown document +doc+. + def initialize(root, options) + super + @footnote_counter = @footnote_start = @options[:footnote_nr] + @footnotes = [] + @footnotes_by_name = {} + @footnote_location = nil + @toc = [] + @toc_code = nil + @indent = 2 + @stack = [] + + # stash string representation of symbol to avoid allocations from multiple interpolations. + @highlighter_class = " highlighter-#{options[:syntax_highlighter]}" + @dispatcher = Hash.new {|h, k| h[k] = :"convert_#{k}" } + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, indent = -@indent) + send(@dispatcher[el.type], el, indent) + end + + # Return the converted content of the children of +el+ as a string. The parameter +indent+ has + # to be the amount of indentation used for the element +el+. + # + # Pushes +el+ onto the @stack before converting the child elements and pops it from the stack + # afterwards. + def inner(el, indent) + result = +'' + indent += @indent + @stack.push(el) + el.children.each do |inner_el| + result << send(@dispatcher[inner_el.type], inner_el, indent) + end + @stack.pop + result + end + + def convert_blank(_el, _indent) + "\n" + end + + def convert_text(el, _indent) + escaped = escape_html(el.value, :text) + @options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped + end + + def convert_p(el, indent) + if el.options[:transparent] + inner(el, indent) + elsif el.children.size == 1 && el.children.first.type == :img && + el.children.first.options[:ial]&.[](:refs)&.include?('standalone') + convert_standalone_image(el, indent) + else + format_as_block_html("p", el.attr, inner(el, indent), indent) + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, indent) + figure_attr = el.attr.dup + image_attr = el.children.first.attr.dup + + if image_attr.key?('class') && !figure_attr.key?('class') + figure_attr['class'] = image_attr.delete('class') + end + if image_attr.key?('id') && !figure_attr.key?('id') + figure_attr['id'] = image_attr.delete('id') + end + + body = "#{' ' * (indent + @indent)}\n" \ + "#{' ' * (indent + @indent)}
#{image_attr['alt']}
\n" + format_as_indented_block_html("figure", figure_attr, body, indent) + end + + def convert_codeblock(el, indent) + attr = el.attr.dup + lang = extract_code_language!(attr) + hl_opts = {} + highlighted_code = highlight_code(el.value, el.options[:lang] || lang, :block, hl_opts) + + if highlighted_code + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + "#{' ' * indent}#{highlighted_code}#{' ' * indent}
\n" + else + result = escape_html(el.value) + result.chomp! + if el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m| + suffix = ($1 ? '-l' : ($2 ? '-r' : '')) + m.scan(/./).map do |c| + case c + when "\t" then "\t" + when " " then "⋅" + end + end.join + end + end + code_attr = {} + code_attr['class'] = "language-#{lang}" if lang + "#{' ' * indent}" \ + "#{result}\n\n" + end + end + + def convert_blockquote(el, indent) + format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent) + end + + def convert_header(el, indent) + attr = el.attr.dup + if @options[:auto_ids] && !attr['id'] + attr['id'] = generate_id(el.options[:raw_text]) + end + + if @options[:header_links] && attr['id'].to_s.length > 0 + link = Element.new(:a, nil, nil) + link.attr['href'] = "##{attr['id']}" + el.children.unshift(link) + end + + @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el) + level = output_header_level(el.options[:level]) + format_as_block_html("h#{level}", attr, inner(el, indent), indent) + end + + def convert_hr(el, indent) + "#{' ' * indent}\n" + end + + ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze + private_constant :ZERO_TO_ONETWENTYEIGHT + + def convert_ul(el, indent) + if !@toc_code && el.options.dig(:ial, :refs)&.include?('toc') + @toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join] + @toc_code.last + elsif !@footnote_location && el.options.dig(:ial, :refs)&.include?('footnotes') + @footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join + else + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + end + alias convert_ol convert_ul + + def convert_dl(el, indent) + format_as_indented_block_html("dl", el.attr, inner(el, indent), indent) + end + + def convert_li(el, indent) + output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">" + res = inner(el, indent) + if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent]) + output << res << (res.match?(/\n\Z/) ? ' ' * indent : '') + else + output << "\n" << res << ' ' * indent + end + output << "\n" + end + alias convert_dd convert_li + + def convert_dt(el, indent) + attr = el.attr.dup + @stack.last.options[:ial][:refs].each do |ref| + if ref =~ /\Aauto_ids(?:-([\w-]+))?/ + attr['id'] = "#{$1}#{basic_generate_id(el.options[:raw_text])}".lstrip + break + end + end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs] + format_as_block_html("dt", attr, inner(el, indent), indent) + end + + def convert_html_element(el, indent) + res = inner(el, indent) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}") + else + output = +'' + if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output << ' ' * indent + end + output << "<#{el.value}#{html_attributes(el.attr)}" + if el.options[:is_closed] && el.options[:content_model] == :raw + output << " />" + elsif !res.empty? && el.options[:content_model] != :block + output << ">#{res}" + elsif !res.empty? + output << ">\n#{res.chomp}\n" << ' ' * indent << "" + elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + output << " />" + else + output << ">" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, indent) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + ' ' * indent << el.value << "\n" + else + el.value + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, indent) + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + alias convert_thead convert_table + alias convert_tbody convert_table + alias convert_tfoot convert_table + alias convert_tr convert_table + + ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc: + + def convert_td(el, indent) + res = inner(el, indent) + type = (@stack[-2].type == :thead ? :th : :td) + attr = el.attr + alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)] + if alignment != :default + attr = el.attr.dup + attr['style'] = (attr.key?('style') ? "#{attr['style']}; " : '') + "text-align: #{alignment}" + end + format_as_block_html(type, attr, res.empty? ? entity_to_str(ENTITY_NBSP) : res, indent) + end + + def convert_comment(el, indent) + if el.options[:category] == :block + "#{' ' * indent}\n" + else + "" + end + end + + def convert_br(_el, _indent) + "
" + end + + def convert_a(el, indent) + format_as_span_html("a", el.attr, inner(el, indent)) + end + + def convert_img(el, _indent) + "" + end + + def convert_codespan(el, _indent) + attr = el.attr.dup + lang = extract_code_language(attr) + hl_opts = {} + result = highlight_code(el.value, lang, :span, hl_opts) + if result + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + else + result = escape_html(el.value) + end + + format_as_span_html('code', attr, result) + end + + def convert_footnote(el, _indent) + repeat = '' + name = @options[:footnote_prefix] + el.options[:name] + if (footnote = @footnotes_by_name[name]) + number = footnote[2] + repeat = ":#{footnote[3] += 1}" + else + number = @footnote_counter + @footnote_counter += 1 + @footnotes << [name, el.value, number, 0] + @footnotes_by_name[name] = @footnotes.last + end + formatted_link_text = sprintf(@options[:footnote_link_text], number) + "" \ + "" \ + "#{formatted_link_text}" + end + + def convert_raw(el, _indent) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, indent) + format_as_span_html(el.type, el.attr, inner(el, indent)) + end + alias convert_strong convert_em + + def convert_entity(el, _indent) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: [::Kramdown::Utils::Entities.entity('mdash')], + ndash: [::Kramdown::Utils::Entities.entity('ndash')], + hellip: [::Kramdown::Utils::Entities.entity('hellip')], + laquo_space: [::Kramdown::Utils::Entities.entity('laquo'), + ::Kramdown::Utils::Entities.entity('nbsp')], + raquo_space: [::Kramdown::Utils::Entities.entity('nbsp'), + ::Kramdown::Utils::Entities.entity('raquo')], + laquo: [::Kramdown::Utils::Entities.entity('laquo')], + raquo: [::Kramdown::Utils::Entities.entity('raquo')], + } # :nodoc: + def convert_typographic_sym(el, _indent) + if (result = @options[:typographic_symbols][el.value]) + escape_html(result, :text) + else + TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join + end + end + + def convert_smart_quote(el, _indent) + entity_to_str(smart_quote_entity(el)) + end + + def convert_math(el, indent) + if (result = format_math(el, indent: indent)) + result + else + attr = el.attr.dup + attr['class'] = "#{attr['class']} kdmath".lstrip + if el.options[:category] == :block + format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent) + else + format_as_span_html('span', attr, "$#{el.value}$") + end + end + end + + def convert_abbreviation(el, _indent) + title = @root.options[:abbrev_defs][el.value] + attr = @root.options[:abbrev_attr][el.value].dup + attr['title'] = title unless title.empty? + format_as_span_html("abbr", attr, el.value) + end + + def convert_root(el, indent) + result = inner(el, indent) + if @footnote_location + result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\")) + else + result << footnote_content + end + if @toc_code + toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {}) + text = toc_tree.children.empty? ? '' : convert(toc_tree, 0) + result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\")) + end + result + end + + # Format the given element as span HTML. + def format_as_span_html(name, attr, body) + "<#{name}#{html_attributes(attr)}>#{body}" + end + + # Format the given element as block HTML. + def format_as_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>#{body}\n" + end + + # Format the given element as block HTML with a newline after the start tag and indentation + # before the end tag. + def format_as_indented_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' ' * indent}\n" + end + + # Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And + # overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil. + def add_syntax_highlighter_to_class_attr(attr, lang = nil) + (attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip! + attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang + end + + # Generate and return an element tree for the table of contents. + def generate_toc_tree(toc, type, attr) + sections = Element.new(type, nil, attr.dup) + sections.attr['id'] ||= 'markdown-toc' + stack = [] + toc.each do |level, id, children| + li = Element.new(:li, nil, nil, level: level) + li.children << Element.new(:p, nil, nil, transparent: true) + a = Element.new(:a, nil) + a.attr['href'] = "##{id}" + a.attr['id'] = "#{sections.attr['id']}-#{id}" + a.children.concat(fix_for_toc_entry(Marshal.load(Marshal.dump(children)))) + li.children.last.children << a + li.children << Element.new(type) + + success = false + until success + if stack.empty? + sections.children << li + stack << li + success = true + elsif stack.last.options[:level] < li.options[:level] + stack.last.children.last.children << li + stack << li + success = true + else + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + end + end + until stack.empty? + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + sections + end + + # Fixes the elements for use in a TOC entry. + def fix_for_toc_entry(elements) + remove_footnotes(elements) + unwrap_links(elements) + elements + end + + # Remove all link elements by unwrapping them. + def unwrap_links(elements) + elements.map! do |c| + unwrap_links(c.children) + c.type == :a ? c.children : c + end.flatten! + end + + # Remove all footnotes from the given elements. + def remove_footnotes(elements) + elements.delete_if do |c| + remove_footnotes(c.children) + c.type == :footnote + end + end + + # Obfuscate the +text+ by using HTML entities. + def obfuscate(text) + result = +'' + text.each_byte do |b| + result << (b > 128 ? b.chr : sprintf("&#%03d;", b)) + end + result.force_encoding(text.encoding) + result + end + + FOOTNOTE_BACKLINK_FMT = "%s%s" + + # Return an HTML ordered list with the footnote content for the used footnotes. + def footnote_content + ol = Element.new(:ol) + ol.attr['start'] = @footnote_start if @footnote_start != 1 + i = 0 + backlink_text = escape_html(@options[:footnote_backlink], :text) + while i < @footnotes.length + name, data, _, repeat = *@footnotes[i] + li = Element.new(:li, nil, 'id' => "fn:#{name}") + li.children = Marshal.load(Marshal.dump(data.children)) + + para = nil + if li.children.last.type == :p || @options[:footnote_backlink_inline] + parent = li + while !parent.children.empty? && ![:p, :header].include?(parent.children.last.type) + parent = parent.children.last + end + para = parent.children.last + insert_space = true + end + + unless para + li.children << (para = Element.new(:p)) + insert_space = false + end + + unless @options[:footnote_backlink].empty? + nbsp = entity_to_str(ENTITY_NBSP) + value = sprintf(FOOTNOTE_BACKLINK_FMT, (insert_space ? nbsp : ''), name, backlink_text) + para.children << Element.new(:raw, value) + (1..repeat).each do |index| + value = sprintf(FOOTNOTE_BACKLINK_FMT, nbsp, "#{name}:#{index}", + "#{backlink_text}#{index + 1}") + para.children << Element.new(:raw, value) + end + end + + ol.children << Element.new(:raw, convert(li, 4)) + i += 1 + end + if ol.children.empty? + '' + else + format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0) + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb new file mode 100644 index 00000000..3be4a8d8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/kramdown.rb @@ -0,0 +1,458 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts an element tree to the kramdown format. + class Kramdown < Base + + # :stopdoc: + + include ::Kramdown::Utils::Html + + def initialize(root, options) + super + @linkrefs = [] + @footnotes = [] + @abbrevs = [] + @stack = [] + @list_indent = @options[:list_indent] + @list_spacing = ' ' * (@list_indent - 2) + end + + def convert(el, opts = {indent: 0}) + res = send("convert_#{el.type}", el, opts) + res = res.dup if res.frozen? + if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el)) + res << ial + res << "\n\n" if el.block? + elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] && + ([el.type, :codeblock].include?(opts[:next].type) || + (opts[:next].type == :blank && opts[:nnext] && + [el.type, :codeblock].include?(opts[:nnext].type))) + res << "^\n\n" + elsif el.block? && + ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) && + (el.type != :html_element || @stack.last.type != :html_element) && + (el.type != :p || !el.options[:transparent]) && + !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li) + res << "\n" + end + res + end + + def inner(el, opts = {indent: 0}) + @stack.push(el) + result = +'' + el.children.each_with_index do |inner_el, index| + options = opts.dup + options[:index] = index + options[:prev] = (index == 0 ? nil : el.children[index - 1]) + options[:pprev] = (index <= 1 ? nil : el.children[index - 2]) + options[:next] = (index == el.children.length - 1 ? nil : el.children[index + 1]) + options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index + 2]) + result << convert(inner_el, options) + end + @stack.pop + result + end + + def convert_blank(_el, _opts) + "" + end + + ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/ + + def convert_text(el, opts) + if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw) + el.value + else + result = el.value.gsub(/\A\n/) do + opts[:prev] && opts[:prev].type == :br ? '' : "\n" + end + result.gsub!(/\s+/, ' ') unless el.options[:cdata] + result.gsub!(ESCAPED_CHAR_RE) do + $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $& + end + result + end + end + + def convert_p(el, opts) + w = @options[:line_width] - opts[:indent].to_s.to_i + first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/) + first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" } + second&.gsub!(/^([=-]+\s*?)$/, "\\\1") + res = [first, second, *rest].compact.join("\n") + "\n" + res.gsub!(/^ {0,3}:/, "\\:") + if el.children.length == 1 && el.children.first.type == :math + res = "\\#{res}" + elsif res.start_with?('\$$') && res.end_with?("\\$$\n") + res.sub!(/^\\\$\$/, '\$\$') + end + res + end + + def convert_codeblock(el, _opts) + el.value.split("\n").map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n" + end + + def convert_blockquote(el, opts) + opts[:indent] += 2 + inner(el, opts).chomp.split("\n").map {|l| "> #{l}" }.join("\n") << "\n" + end + + def convert_header(el, opts) + opts[:in_header] = true + res = +'' + res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}" + res[-1, 1] = "\\#" if res[-1] == '#' + res << " {##{el.attr['id']}}" if el.attr['id'] && !el.attr['id'].strip.empty? + res << "\n" + end + + def convert_hr(_el, _opts) + "* * *\n" + end + + def convert_ul(el, opts) + inner(el, opts).sub(/\n+\Z/, "\n") + end + alias convert_ol convert_ul + alias convert_dl convert_ul + + def convert_li(el, opts) + sym, width = if @stack.last.type == :ul + ['* ' + @list_spacing, el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent] + else + ["#{opts[:index] + 1}.".ljust(4), 4] + end + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines) + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + res = +"#{sym}#{text}" + res << "^\n" if el.children.size == 1 && @stack.last.children.last == el && + (@stack.last.children.any? {|c| !c.children.first || c.children.first.type != :p } || @stack.last.children.size == 1) + res + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dd(el, opts) + sym, width = ": " + @list_spacing, (el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent) + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = first.to_s + (last.empty? ? "" : "\n") + last + newlines + text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd + text << "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt + text << "\n" if el.children.empty? + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + "\n#{sym}#{text}" + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dt(el, opts) + result = +'' + if (ial = ial_for_element(el)) + result << ial << " " + end + result << inner(el, opts) << "\n" + end + + HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td] + + HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze + private_constant :HTML_ELEMENT_TYPES + + def convert_html_element(el, opts) + markdown_attr = el.options[:category] == :block && el.children.any? do |c| + c.type != :html_element && + (c.type != :p || !c.options[:transparent] || + c.children.any? {|t| !HTML_ELEMENT_TYPES.member?(t.type) }) && + c.block? + end + opts[:force_raw_text] = true if %w[script pre code].include?(el.value) + opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || \ + (el.options[:category] != :span && !markdown_attr) + opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text] + res = inner(el, opts) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}" : " />") + else + output = +'' + attr = el.attr.dup + attr['markdown'] = '1' if markdown_attr + output << "<#{el.value}#{html_attributes(attr)}" + if !res.empty? && el.options[:content_model] != :block + output << ">#{res}" + elsif !res.empty? + output << ">\n#{res}" << "" + elsif HTML_TAGS_WITH_BODY.include?(el.value) + output << ">" + else + output << " />" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, _opts) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + el.value + "\n" + else + el.value.dup + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment] + inner(el, opts) + end + + def convert_thead(el, opts) + rows = inner(el, opts) + if opts[:alignment].all?(:default) + "#{rows}|#{'-' * 10}\n" + else + "#{rows}| " + opts[:alignment].map do |a| + case a + when :left then ":-" + when :right then "-:" + when :center then ":-:" + when :default then "-" + end + end.join(' ') << "\n" + end + end + + def convert_tbody(el, opts) + res = +'' + res << inner(el, opts) + res << '|' << '-' * 10 << "\n" if opts[:next] && opts[:next].type == :tbody + res + end + + def convert_tfoot(el, opts) + "|#{'=' * 10}\n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + "| #{el.children.map {|c| convert(c, opts) }.join(' | ')} |\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + if el.options[:category] == :block + "{::comment}\n#{el.value}\n{:/}\n" + else + "{::comment}#{el.value}{:/}" + end + end + + def convert_br(_el, opts) + opts[:in_header] ? "
" : " \n" + end + + def convert_a(el, opts) + if el.attr['href'].empty? + "[#{inner(el, opts)}]()" + elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0 + index = if (link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href'] }) + @linkrefs.index(link_el) + 1 + else + @linkrefs << el + @linkrefs.size + end + "[#{inner(el, opts)}][#{index}]" + else + title = parse_title(el.attr['title']) + "[#{inner(el, opts)}](#{el.attr['href']}#{title})" + end + end + + def convert_img(el, _opts) + alt_text = el.attr['alt'].to_s.gsub(ESCAPED_CHAR_RE) { $1 ? "\\#{$1}" : $2 } + src = el.attr['src'].to_s + if src.empty? + "![#{alt_text}]()" + else + title = parse_title(el.attr['title']) + link = if src.count("()") > 0 + "<#{src}>" + else + src + end + "![#{alt_text}](#{link}#{title})" + end + end + + def convert_codespan(el, _opts) + delim = (el.value.scan(/`+/).max || '') + '`' + "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}" + end + + def convert_footnote(el, _opts) + @footnotes << [el.options[:name], el.value] + "[^#{el.options[:name]}]" + end + + def convert_raw(el, _opts) + attr = (el.options[:type] || []).join(' ') + attr = " type=\"#{attr}\"" unless attr.empty? + if @stack.last.type == :html_element + el.value + elsif el.options[:category] == :block + "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n" + else + "{::nomarkdown#{attr}}#{el.value}{:/}" + end + end + + def convert_em(el, opts) + "*#{inner(el, opts)}*" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_strong(el, opts) + "**#{inner(el, opts)}**" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_entity(el, _opts) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '...', + laquo_space: '<< ', raquo_space: ' >>', + laquo: '<<', raquo: '>>' + } + def convert_typographic_sym(el, _opts) + TYPOGRAPHIC_SYMS[el.value] + end + + def convert_smart_quote(el, _opts) + el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'" + end + + def convert_math(el, _opts) + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '') + end + + def convert_abbreviation(el, _opts) + el.value + end + + def convert_root(el, opts) + res = inner(el, opts) + res << create_link_defs + res << create_footnote_defs + res << create_abbrev_defs + res + end + + def create_link_defs + res = +'' + res << "\n\n" unless @linkrefs.empty? + @linkrefs.each_with_index do |el, i| + title = parse_title(el.attr['title']) + res << "[#{i + 1}]: #{el.attr['href']}#{title}\n" + end + res + end + + def create_footnote_defs + res = +'' + @footnotes.each do |name, data| + res << "[^#{name}]:\n" + res << inner(data).chomp.split("\n").map {|l| " #{l}" }.join("\n") + "\n\n" + end + res + end + + def create_abbrev_defs + return '' unless @root.options[:abbrev_defs] + res = +'' + @root.options[:abbrev_defs].each do |name, text| + res << "*[#{name}]: #{text}\n" + res << ial_for_element(Element.new(:unused, nil, @root.options[:abbrev_attr][name])).to_s << "\n\n" + end + res + end + + # Return the IAL containing the attributes of the element +el+. + def ial_for_element(el) + res = el.attr.map do |k, v| + next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k) + next if el.type == :header && k == 'id' && !v.strip.empty? + if v.nil? + '' + elsif k == 'class' && !v.empty? && !v.index(/[.#]/) + " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ") + elsif k == 'id' && !v.strip.empty? + " ##{v}" + else + " #{k}=\"#{v}\"" + end + end.compact.join + res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('toc') + res = "footnotes" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('footnotes') + if el.type == :dl && el.options[:ial] && el.options[:ial][:refs] + auto_ids = el.options[:ial][:refs].select {|ref| ref.start_with?('auto_ids') }.join(" ") + res = auto_ids << (res.strip.empty? ? '' : " #{res}") unless auto_ids.empty? + end + res.strip.empty? ? nil : "{:#{res}}" + end + + def parse_title(attr) + attr.to_s.empty? ? '' : ' "' + attr.gsub(/"/, '"') + '"' + end + + # :startdoc: + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb new file mode 100644 index 00000000..25f2bbb6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/latex.rb @@ -0,0 +1,626 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'set' +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts an element tree to LaTeX. + # + # This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku. + # + # You can customize this converter by sub-classing it and overriding the +convert_NAME+ methods. + # Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+opts+] A hash containing processing options that are passed down from parent elements. The + # key :parent is always set and contains the parent element as value. + # + # The return value of such a method has to be a string containing the element +el+ formatted + # correctly as LaTeX markup. + class Latex < Base + + # Initialize the LaTeX converter with the +root+ element and the conversion +options+. + def initialize(root, options) + super + @data[:packages] = Set.new + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, opts = {}) + send("convert_#{el.type}", el, opts) + end + + # Return the converted content of the children of +el+ as a string. + def inner(el, opts) + result = +'' + options = opts.dup.merge(parent: el) + el.children.each_with_index do |inner_el, index| + options[:index] = index + options[:result] = result + result << send("convert_#{inner_el.type}", inner_el, options) + end + result + end + + def convert_root(el, opts) + inner(el, opts) + end + + def convert_blank(_el, opts) + opts[:result].match?(/\n\n\Z|\A\Z/) ? "" : "\n" + end + + def convert_text(el, _opts) + escape(el.value) + end + + def convert_p(el, opts) + if el.children.size == 1 && el.children.first.type == :img && + !(img = convert_img(el.children.first, opts)).empty? + convert_standalone_image(el, opts, img) + else + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, _opts, img) + attrs = attribute_list(el) + "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n" \ + "\\caption{#{escape(el.children.first.attr['alt'])}}\n" \ + "#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n" + end + + def convert_codeblock(el, _opts) + show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + lang = extract_code_language(el.attr) + + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :block)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}\n" + elsif show_whitespace || lang + options = [] + options << (show_whitespace ? "showspaces=true,showtabs=true" : "showspaces=false,showtabs=false") + options << "language=#{lang}" if lang + options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr" + id = el.attr['id'] + options << "label=#{id}" if id + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n" \ + "#{el.value}\n\\end{lstlisting}#{attrs}\n" + else + "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n" + end + end + + def convert_blockquote(el, opts) + latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts)) + end + + def convert_header(el, opts) + type = @options[:latex_headers][output_header_level(el.options[:level]) - 1] + if ((id = el.attr['id']) || + (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el) + "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n" + else + "\\#{type}*{#{inner(el, opts)}}\n\n" + end + end + + def convert_hr(el, _opts) + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n" + end + + def convert_ul(el, opts) + if !@data[:has_toc] && el.options.dig(:ial, :refs)&.include?('toc') + @data[:has_toc] = true + '\tableofcontents' + else + latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts)) + end + end + alias convert_ol convert_ul + + def convert_dl(el, opts) + latex_environment('description', el, inner(el, opts)) + end + + def convert_li(el, opts) + "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n" + end + + def convert_dt(el, opts) + "\\item[#{inner(el, opts)}] " + end + + def convert_dd(el, opts) + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + + def convert_html_element(el, opts) + case el.value + when 'i', 'em' + "\\emph{#{inner(el, opts)}}" + when 'b', 'strong' + "\\textbf{#{inner(el, opts)}}" + else + warning("Can't convert HTML element") + '' + end + end + + def convert_xml_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") + "\n" + end + + def convert_xml_pi(_el, _opts) + warning("Can't convert XML PI") + '' + end + + TABLE_ALIGNMENT_CHAR = {default: 'l', left: 'l', center: 'c', right: 'r'} # :nodoc: + + def convert_table(el, opts) + @data[:packages] << 'longtable' + align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a] }.join('|') + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n" \ + "\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n" + end + + def convert_thead(el, opts) + "#{inner(el, opts)}\\hline\n" + end + + def convert_tbody(el, opts) + inner(el, opts) + end + + def convert_tfoot(el, opts) + "\\hline \\hline \n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + el.children.map {|c| send("convert_#{c.type}", c, opts) }.join(' & ') << "\\\\\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") << "\n" + end + + def convert_br(_el, opts) + res = +"\\newline" + res << "\n" if (c = opts[:parent].children[opts[:index] + 1]) && + (c.type != :text || c.value !~ /^\s*\n/) + res + end + + def convert_a(el, opts) + url = el.attr['href'] + if url.start_with?('#') + "\\hyperlink{#{url[1..-1].gsub('%', '\\%')}}{#{inner(el, opts)}}" + else + "\\href{#{url.gsub('%', '\\%')}}{#{inner(el, opts)}}" + end + end + + def convert_img(el, _opts) + line = el.options[:location] + if el.attr['src'].match?(/^(https?|ftps?):\/\//) + warning("Cannot include non-local image#{line ? " (line #{line})" : ''}") + '' + elsif !el.attr['src'].empty? + @data[:packages] << 'graphicx' + "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}" + else + warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}") + '' + end + end + + def convert_codespan(el, _opts) + lang = extract_code_language(el.attr) + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :span)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}" + else + "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}" + end + end + + def convert_footnote(el, opts) + @data[:packages] << 'fancyvrb' + "\\footnote{#{inner(el.value, opts).rstrip}}" + end + + def convert_raw(el, _opts) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, opts) + "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + def convert_strong(el, opts) + "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + # Inspired by Maruku: entity conversion table based on the one from htmltolatex + # (http://sourceforge.net/projects/htmltolatex/), with some small adjustments/additions + ENTITY_CONV_TABLE = { + 913 => ['$A$'], + 914 => ['$B$'], + 915 => ['$\Gamma$'], + 916 => ['$\Delta$'], + 917 => ['$E$'], + 918 => ['$Z$'], + 919 => ['$H$'], + 920 => ['$\Theta$'], + 921 => ['$I$'], + 922 => ['$K$'], + 923 => ['$\Lambda$'], + 924 => ['$M$'], + 925 => ['$N$'], + 926 => ['$\Xi$'], + 927 => ['$O$'], + 928 => ['$\Pi$'], + 929 => ['$P$'], + 931 => ['$\Sigma$'], + 932 => ['$T$'], + 933 => ['$Y$'], + 934 => ['$\Phi$'], + 935 => ['$X$'], + 936 => ['$\Psi$'], + 937 => ['$\Omega$'], + 945 => ['$\alpha$'], + 946 => ['$\beta$'], + 947 => ['$\gamma$'], + 948 => ['$\delta$'], + 949 => ['$\epsilon$'], + 950 => ['$\zeta$'], + 951 => ['$\eta$'], + 952 => ['$\theta$'], + 953 => ['$\iota$'], + 954 => ['$\kappa$'], + 955 => ['$\lambda$'], + 956 => ['$\mu$'], + 957 => ['$\nu$'], + 958 => ['$\xi$'], + 959 => ['$o$'], + 960 => ['$\pi$'], + 961 => ['$\rho$'], + 963 => ['$\sigma$'], + 964 => ['$\tau$'], + 965 => ['$\upsilon$'], + 966 => ['$\phi$'], + 967 => ['$\chi$'], + 968 => ['$\psi$'], + 969 => ['$\omega$'], + 962 => ['$\varsigma$'], + 977 => ['$\vartheta$'], + 982 => ['$\varpi$'], + 8230 => ['\ldots'], + 8242 => ['$\prime$'], + 8254 => ['-'], + 8260 => ['/'], + 8472 => ['$\wp$'], + 8465 => ['$\Im$'], + 8476 => ['$\Re$'], + 8501 => ['$\aleph$'], + 8226 => ['$\bullet$'], + 8482 => ['$^{\rm TM}$'], + 8592 => ['$\leftarrow$'], + 8594 => ['$\rightarrow$'], + 8593 => ['$\uparrow$'], + 8595 => ['$\downarrow$'], + 8596 => ['$\leftrightarrow$'], + 8629 => ['$\hookleftarrow$'], + 8657 => ['$\Uparrow$'], + 8659 => ['$\Downarrow$'], + 8656 => ['$\Leftarrow$'], + 8658 => ['$\Rightarrow$'], + 8660 => ['$\Leftrightarrow$'], + 8704 => ['$\forall$'], + 8706 => ['$\partial$'], + 8707 => ['$\exists$'], + 8709 => ['$\emptyset$'], + 8711 => ['$\nabla$'], + 8712 => ['$\in$'], + 8715 => ['$\ni$'], + 8713 => ['$\notin$'], + 8721 => ['$\sum$'], + 8719 => ['$\prod$'], + 8722 => ['$-$'], + 8727 => ['$\ast$'], + 8730 => ['$\surd$'], + 8733 => ['$\propto$'], + 8734 => ['$\infty$'], + 8736 => ['$\angle$'], + 8743 => ['$\wedge$'], + 8744 => ['$\vee$'], + 8745 => ['$\cap$'], + 8746 => ['$\cup$'], + 8747 => ['$\int$'], + 8756 => ['$\therefore$', 'amssymb'], + 8764 => ['$\sim$'], + 8776 => ['$\approx$'], + 8773 => ['$\cong$'], + 8800 => ['$\neq$'], + 8801 => ['$\equiv$'], + 8804 => ['$\leq$'], + 8805 => ['$\geq$'], + 8834 => ['$\subset$'], + 8835 => ['$\supset$'], + 8838 => ['$\subseteq$'], + 8839 => ['$\supseteq$'], + 8836 => ['$\nsubset$', 'amssymb'], + 8853 => ['$\oplus$'], + 8855 => ['$\otimes$'], + 8869 => ['$\perp$'], + 8901 => ['$\cdot$'], + 8968 => ['$\rceil$'], + 8969 => ['$\lceil$'], + 8970 => ['$\lfloor$'], + 8971 => ['$\rfloor$'], + 9001 => ['$\rangle$'], + 9002 => ['$\langle$'], + 9674 => ['$\lozenge$', 'amssymb'], + 9824 => ['$\spadesuit$'], + 9827 => ['$\clubsuit$'], + 9829 => ['$\heartsuit$'], + 9830 => ['$\diamondsuit$'], + 38 => ['\&'], + 34 => ['"'], + 39 => ['\''], + 169 => ['\copyright'], + 60 => ['\textless'], + 62 => ['\textgreater'], + 338 => ['\OE'], + 339 => ['\oe'], + 352 => ['\v{S}'], + 353 => ['\v{s}'], + 376 => ['\"Y'], + 710 => ['\textasciicircum'], + 732 => ['\textasciitilde'], + 8211 => ['--'], + 8212 => ['---'], + 8216 => ['`'], + 8217 => ['\''], + 8220 => ['``'], + 8221 => ['\'\''], + 8224 => ['\dag'], + 8225 => ['\ddag'], + 8240 => ['\permil', 'wasysym'], + 8364 => ['\euro', 'eurosym'], + 8249 => ['\guilsinglleft'], + 8250 => ['\guilsinglright'], + 8218 => ['\quotesinglbase', 'mathcomp'], + 8222 => ['\quotedblbase', 'mathcomp'], + 402 => ['\textflorin', 'mathcomp'], + 381 => ['\v{Z}'], + 382 => ['\v{z}'], + 160 => ['~'], + 161 => ['\textexclamdown'], + 163 => ['\pounds'], + 164 => ['\currency', 'wasysym'], + 165 => ['\textyen', 'textcomp'], + 166 => ['\brokenvert', 'wasysym'], + 167 => ['\S'], + 171 => ['\guillemotleft'], + 187 => ['\guillemotright'], + 174 => ['\textregistered'], + 170 => ['\textordfeminine'], + 172 => ['$\neg$'], + 173 => ['\-'], + 176 => ['$\degree$', 'mathabx'], + 177 => ['$\pm$'], + 180 => ['\''], + 181 => ['$\mu$'], + 182 => ['\P'], + 183 => ['$\cdot$'], + 186 => ['\textordmasculine'], + 162 => ['\cent', 'wasysym'], + 185 => ['$^1$'], + 178 => ['$^2$'], + 179 => ['$^3$'], + 189 => ['$\frac{1}{2}$'], + 188 => ['$\frac{1}{4}$'], + 190 => ['$\frac{3}{4}'], + 192 => ['\`A'], + 193 => ['\\\'A'], + 194 => ['\^A'], + 195 => ['\~A'], + 196 => ['\"A'], + 197 => ['\AA'], + 198 => ['\AE'], + 199 => ['\cC'], + 200 => ['\`E'], + 201 => ['\\\'E'], + 202 => ['\^E'], + 203 => ['\"E'], + 204 => ['\`I'], + 205 => ['\\\'I'], + 206 => ['\^I'], + 207 => ['\"I'], + 208 => ['$\eth$', 'amssymb'], + 209 => ['\~N'], + 210 => ['\`O'], + 211 => ['\\\'O'], + 212 => ['\^O'], + 213 => ['\~O'], + 214 => ['\"O'], + 215 => ['$\times$'], + 216 => ['\O'], + 217 => ['\`U'], + 218 => ['\\\'U'], + 219 => ['\^U'], + 220 => ['\"U'], + 221 => ['\\\'Y'], + 222 => ['\Thorn', 'wasysym'], + 223 => ['\ss'], + 224 => ['\`a'], + 225 => ['\\\'a'], + 226 => ['\^a'], + 227 => ['\~a'], + 228 => ['\"a'], + 229 => ['\aa'], + 230 => ['\ae'], + 231 => ['\cc'], + 232 => ['\`e'], + 233 => ['\\\'e'], + 234 => ['\^e'], + 235 => ['\"e'], + 236 => ['\`i'], + 237 => ['\\\'i'], + 238 => ['\^i'], + 239 => ['\"i'], + 240 => ['$\eth$'], + 241 => ['\~n'], + 242 => ['\`o'], + 243 => ['\\\'o'], + 244 => ['\^o'], + 245 => ['\~o'], + 246 => ['\"o'], + 247 => ['$\divide$'], + 248 => ['\o'], + 249 => ['\`u'], + 250 => ['\\\'u'], + 251 => ['\^u'], + 252 => ['\"u'], + 253 => ['\\\'y'], + 254 => ['\thorn', 'wasysym'], + 255 => ['\"y'], + 8201 => ['\thinspace'], + 8194 => ['\hskip .5em\relax'], + 8195 => ['\quad'], + } # :nodoc: + ENTITY_CONV_TABLE.each_value {|v| v[0] = "#{v[0]}{}" } + + def entity_to_latex(entity) + text, package = ENTITY_CONV_TABLE[entity.code_point] + if text + @data[:packages] << package if package + text + else + warning("Couldn't find entity with code #{entity.code_point} in substitution table!") + '' + end + end + + def convert_entity(el, _opts) + entity_to_latex(el.value) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '\ldots{}', + laquo_space: '\guillemotleft{}~', raquo_space: '~\guillemotright{}', + laquo: '\guillemotleft{}', raquo: '\guillemotright{}' + } # :nodoc: + def convert_typographic_sym(el, _opts) + if (result = @options[:typographic_symbols][el.value]) + escape(result) + else + TYPOGRAPHIC_SYMS[el.value] + end + end + + def convert_smart_quote(el, opts) + res = entity_to_latex(smart_quote_entity(el)).chomp('{}') + res << "{}" if ((nel = opts[:parent].children[opts[:index] + 1]) && nel.type == :smart_quote) || res =~ /\w$/ + res + end + + def convert_math(el, _opts) + @data[:packages] += %w[amssymb amsmath amsthm amsfonts] + if el.options[:category] == :block + if el.value.match?(/\A\s*\\begin\{/) + el.value + else + latex_environment('displaymath', el, el.value) + end + else + "$#{el.value}$" + end + end + + def convert_abbreviation(el, _opts) + @data[:packages] += %w[acronym] + "\\ac{#{normalize_abbreviation_key(el.value)}}" + end + + # Normalize the abbreviation key so that it only contains allowed ASCII character + def normalize_abbreviation_key(key) + key.gsub(/\W/) {|m| m.unpack1('H*') } + end + + # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to + # the method #attribute_list -- the resulting string is appended to both the \\begin and the + # \\end lines of the LaTeX environment for easier post-processing of LaTeX environments. + def latex_environment(type, el, text) + attrs = attribute_list(el) + "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n" + end + + # Return a string containing a valid \hypertarget command if the element has an ID defined, or + # +nil+ otherwise. If the parameter +add_label+ is +true+, a \label command will also be used + # additionally to the \hypertarget command. + def latex_link_target(el, add_label = false) + if (id = el.attr['id']) + "\\hypertarget{#{id}}{}#{add_label ? "\\label{#{id}}" : ''}" + else + nil + end + end + + # Return a LaTeX comment containing all attributes as 'key="value"' pairs. + def attribute_list(el) + attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join + attrs = " % #{attrs}" unless attrs.empty? + attrs + end + + ESCAPE_MAP = { + "^" => "\\^{}", + "\\" => "\\textbackslash{}", + "~" => "\\ensuremath{\\sim}", + "|" => "\\textbar{}", + "<" => "\\textless{}", + ">" => "\\textgreater{}", + "[" => "{[}", + "]" => "{]}", + }.merge(Hash[*"{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten]) # :nodoc: + ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc: + + # Escape the special LaTeX characters in the string +str+. + def escape(str) + str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m] } + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb new file mode 100644 index 00000000..50da45a7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/man.rb @@ -0,0 +1,300 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a manpage in groff format. See man(7), groff_man(7) and + # man-pages(7) for information regarding the output. + class Man < Base + + def convert(el, opts = {indent: 0, result: +''}) # :nodoc: + send("convert_#{el.type}", el, opts) + end + + private + + def inner(el, opts, use = :all) + arr = el.children.reject {|e| e.type == :blank } + arr.each_with_index do |inner_el, index| + next if use == :rest && index == 0 + break if use == :first && index > 0 + options = opts.dup + options[:parent] = el + options[:index] = index + options[:prev] = (index == 0 ? nil : arr[index - 1]) + options[:next] = (index == arr.length - 1 ? nil : arr[index + 1]) + convert(inner_el, options) + end + end + + def convert_root(el, opts) + @title_done = false + opts[:result] = +".\\\" generated by kramdown\n" + inner(el, opts) + opts[:result] + end + + def convert_blank(*) + end + alias convert_hr convert_blank + alias convert_xml_pi convert_blank + + def convert_p(el, opts) + if (opts[:index] != 0 && opts[:prev].type != :header) || + (opts[:parent].type == :blockquote && opts[:index] == 0) + opts[:result] << macro("P") + end + inner(el, opts) + newline(opts[:result]) + end + + def convert_header(el, opts) + return unless opts[:parent].type == :root + case el.options[:level] + when 1 + unless @title_done + @title_done = true + data = el.options[:raw_text].scan(/([^(]+)\s*\((\d\w*)\)(?:\s*-+\s*(.*))?/).first || + el.options[:raw_text].scan(/([^\s]+)\s*(?:-*\s+)?()(.*)/).first + return unless data && data[0] + name = data[0] + section = (data[1].to_s.empty? ? el.attr['data-section'] || '7' : data[1]) + description = (data[2].to_s.empty? ? nil : " - #{data[2]}") + date = el.attr['data-date'] ? quote(el.attr['data-date']) : nil + extra = (el.attr['data-extra'] ? quote(escape(el.attr['data-extra'].to_s)) : nil) + opts[:result] << macro("TH", quote(escape(name.upcase)), quote(section), date, extra) + if description + opts[:result] << macro("SH", "NAME") << escape("#{name}#{description}") << "\n" + end + end + when 2 + opts[:result] << macro("SH", quote(escape(el.options[:raw_text]))) + when 3 + opts[:result] << macro("SS", quote(escape(el.options[:raw_text]))) + else + warning("Header levels greater than three are not supported") + end + end + + def convert_codeblock(el, opts) + opts[:result] << macro("sp") << macro("RS", 4) << macro("EX") + opts[:result] << newline(escape(el.value, true)) + opts[:result] << macro("EE") << macro("RE") + end + + def convert_blockquote(el, opts) + opts[:result] << macro("RS") + inner(el, opts) + opts[:result] << macro("RE") + end + + def convert_ul(el, opts) + compact = (el.attr['class'] =~ /\bcompact\b/) + opts[:result] << macro("sp") << macro("PD", 0) if compact + inner(el, opts) + opts[:result] << macro("PD") if compact + end + alias convert_dl convert_ul + alias convert_ol convert_ul + + def convert_li(el, opts) + sym = (opts[:parent].type == :ul ? '\(bu' : "#{opts[:index] + 1}.") + opts[:result] << macro("IP", sym, 4) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + end + + def convert_dt(el, opts) + opts[:result] << macro(opts[:prev] && opts[:prev].type == :dt ? "TQ" : "TP") + inner(el, opts) + opts[:result] << "\n" + end + + def convert_dd(el, opts) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + opts[:result] << macro("sp") if opts[:next] && opts[:next].type == :dd + end + + TABLE_CELL_ALIGNMENT = {left: 'l', center: 'c', right: 'r', default: 'l'} + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] } + table_options = ["box"] + table_options << "center" if el.attr['class']&.match?(/\bcenter\b/) + opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n" + inner(el, opts) + opts[:result] << macro("TE") << macro("sp") + end + + def convert_thead(el, opts) + opts[:result] << opts[:alignment].map {|a| "#{a}b" }.join(' ') << " .\n" + inner(el, opts) + opts[:result] << "=\n" + end + + def convert_tbody(el, opts) + opts[:result] << ".T&\n" if opts[:index] != 0 + opts[:result] << opts[:alignment].join(' ') << " .\n" + inner(el, opts) + opts[:result] << (opts[:next].type == :tfoot ? "=\n" : "_\n") if opts[:next] + end + + def convert_tfoot(el, opts) + inner(el, opts) + end + + def convert_tr(el, opts) + inner(el, opts) + opts[:result] << "\n" + end + + def convert_td(el, opts) + result = opts[:result] + opts[:result] = +'' + inner(el, opts) + if opts[:result].include?("\n") + warning("Table cells using links are not supported") + result << "\t" + else + result << opts[:result] << "\t" + end + end + + def convert_html_element(*) + warning("HTML elements are not supported") + end + + def convert_xml_comment(el, opts) + newline(opts[:result]) << ".\"#{escape(el.value, true).rstrip.gsub(/\n/, "\n.\"")}\n" + end + alias convert_comment convert_xml_comment + + def convert_a(el, opts) + if el.children.size == 1 && el.children[0].type == :text && + el.attr['href'] == el.children[0].value + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) << macro("UE") + elsif el.attr['href'].start_with?('mailto:') + newline(opts[:result]) << macro("MT", escape(el.attr['href'].sub(/^mailto:/, ''))) << + macro("UE") + else + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) + inner(el, opts) + newline(opts[:result]) << macro("UE") + end + end + + def convert_img(_el, _opts) + warning("Images are not supported") + end + + def convert_em(el, opts) + opts[:result] << '\fI' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_strong(el, opts) + opts[:result] << '\fB' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_codespan(el, opts) + opts[:result] << "\\fB#{escape(el.value)}\\fP" + end + + def convert_br(_el, opts) + newline(opts[:result]) << macro("br") + end + + def convert_abbreviation(el, opts) + opts[:result] << escape(el.value) + end + + def convert_math(el, opts) + if el.options[:category] == :block + convert_codeblock(el, opts) + else + convert_codespan(el, opts) + end + end + + def convert_footnote(*) + warning("Footnotes are not supported") + end + + def convert_raw(*) + warning("Raw content is not supported") + end + + def convert_text(el, opts) + text = escape(el.value) + text.lstrip! if opts[:result][-1] == "\n" + opts[:result] << text + end + + def convert_entity(el, opts) + opts[:result] << unicode_char(el.value.code_point) + end + + def convert_smart_quote(el, opts) + opts[:result] << unicode_char(::Kramdown::Utils::Entities.entity(el.value.to_s).code_point) + end + + TYPOGRAPHIC_SYMS_MAP = { + mdash: '\(em', ndash: '\(em', hellip: '\.\.\.', + laquo_space: '\[Fo]', raquo_space: '\[Fc]', laquo: '\[Fo]', raquo: '\[Fc]' + } + + def convert_typographic_sym(el, opts) + opts[:result] << TYPOGRAPHIC_SYMS_MAP[el.value] + end + + def macro(name, *args) + ".#{[name, *args].compact.join(' ')}\n" + end + + def newline(text) + text << "\n" unless text[-1] == "\n" + text + end + + def quote(text) + "\"#{text.gsub(/"/, '\\"')}\"" + end + + def escape(text, preserve_whitespace = false) + text = (preserve_whitespace ? text.dup : text.gsub(/\s+/, ' ')) + text.gsub!('\\', "\\e") + text.gsub!(/^\./, '\\\\&.') + text.gsub!(/[.'-]/) {|m| "\\#{m}" } + text + end + + def unicode_char(codepoint) + "\\[u#{codepoint.to_s(16).rjust(4, '0')}]" + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb new file mode 100644 index 00000000..84e21445 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/math_engine/mathjax.rb @@ -0,0 +1,32 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::MathEngine + + # Uses the MathJax javascript library for displaying math. + # + # Note that the javascript library itself is not include or linked, this has to be done + # separately. Only the math content is marked up correctly. + module Mathjax + + def self.call(converter, el, opts) + value = converter.escape_html(el.value) + result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)" + if el.attr.empty? + result + elsif el.options[:category] == :block + converter.format_as_block_html('div', el.attr, result, opts[:indent]) + else + converter.format_as_span_html('span', el.attr, "$#{el.value}$") + end + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb new file mode 100644 index 00000000..af81ad51 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/remove_html_tags.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Removes all block (and optionally span) level HTML tags from the element tree. + # + # This converter can be used on parsed HTML documents to get an element tree that will only + # contain native kramdown elements. + # + # *Note* that the returned element tree may not be fully conformant (i.e. the content models of + # *some elements may be violated)! + # + # This converter modifies the given tree in-place and returns it. + class RemoveHtmlTags < Base + + def initialize(root, options) + super + @options[:template] = '' + end + + def convert(el) + real_el, el = el, el.value if el.type == :footnote + + children = el.children.dup + index = 0 + while index < children.length + if children[index].type == :xml_pi || + (children[index].type == :html_element && (children[index].value == 'style' || + children[index].value == 'script')) + children[index..index] = [] + elsif children[index].type == :html_element && + ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) || + (@options[:remove_span_html_tags] && children[index].options[:category] == :span)) + children[index..index] = children[index].children + else + convert(children[index]) + index += 1 + end + end + el.children = children + real_el || el + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb new file mode 100644 index 00000000..683acbff --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter.rb @@ -0,0 +1,56 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Converter + + # == Container for Syntax Highlighters + # + # This module serves as container for the syntax highlighters that can be used together with + # kramdown. + # + # A syntax highlighter should not store any data itself but should use the provided converter + # object to do so (See Kramdown::Converter::Base#data). + # + # == Implementing a Syntax Highlighter + # + # Implementing a new syntax highlighter is easy because it is just an object that needs to + # respond to #call. + # + # The method #call needs to take the following arguments: + # + # converter:: This argument contains the converter object that calls the syntax highlighter. It + # can be used, for example, to store data in Kramdown::Converter::Base#data for one + # conversion run. + # + # text:: The raw text that should be highlighted. + # + # lang:: The language that the text should be highlighted for (e.g. ruby, python, ...). + # + # type:: The type of text, either :span for span-level code or :block for a codeblock. + # + # opts:: A Hash with options that may be passed from the converter. + # + # The return value of the method should be the highlighted text, suitable for the given + # converter (e.g. HTML for the HTML converter). + # + # == Special Implementation Details + # + # HTML converter:: If the syntax highlighter is used with an HTML converter, it should return + # :block type text correctly wrapped (i.e. normally inside a pre-tag, but may + # also be a table-tag or just a div-tag) but :span type text *without* a + # code-tag! + # + # Also, a syntax highlighter should store the default highlighting language for + # the invocation in the +opts+ hash under the key :default_lang. + module SyntaxHighlighter + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb new file mode 100644 index 00000000..2119f002 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/minted.rb @@ -0,0 +1,35 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Minted to highlight code blocks and code spans. + module Minted + + def self.call(converter, text, lang, type, _opts) + opts = converter.options[:syntax_highlighter_opts] + + # Fallback to default language + lang ||= opts[:default_lang] + + options = [] + options << "breaklines" if opts[:wrap] + options << "linenos" if opts[:line_numbers] + options << "frame=#{opts[:frame]}" if opts[:frame] + + if lang && type == :block + "\\begin{minted}[#{options.join(',')}]{#{lang}}\n#{text}\n\\end{minted}" + elsif lang && type == :span + "\\mintinline{#{lang}}{#{text}}" + else + nil + end + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb new file mode 100644 index 00000000..ed6a4f83 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/syntax_highlighter/rouge.rb @@ -0,0 +1,85 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Rouge which is CSS-compatible to Pygments to highlight code blocks and code spans. + module Rouge + + begin + require 'rouge' + + # Highlighting via Rouge is available if this constant is +true+. + AVAILABLE = true + rescue LoadError, SyntaxError + AVAILABLE = false # :nodoc: + end + + def self.call(converter, text, lang, type, call_opts) + opts = options(converter, type) + call_opts[:default_lang] = opts[:default_lang] + return nil unless lang || opts[:default_lang] || opts[:guess_lang] + + lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text) + return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang]) + + opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0 + formatter = formatter_class(opts).new(opts) + formatter.format(lexer.lex(text)) + end + + def self.options(converter, type) + prepare_options(converter) + converter.data[:syntax_highlighter_rouge][type] + end + + def self.prepare_options(converter) + return if converter.data.key?(:syntax_highlighter_rouge) + + cache = converter.data[:syntax_highlighter_rouge] = {} + + opts = converter.options[:syntax_highlighter_opts].dup + + span_opts = opts.delete(:span)&.dup || {} + block_opts = opts.delete(:block)&.dup || {} + normalize_keys(span_opts) + normalize_keys(block_opts) + + cache[:span] = opts.merge(span_opts) + cache[:span][:wrap] = false + + cache[:block] = opts.merge(block_opts) + end + + def self.normalize_keys(hash) + return if hash.empty? + + hash.keys.each do |k| + hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k) + end + end + + def self.formatter_class(opts = {}) + case formatter = opts[:formatter] + when Class + formatter + when /\A[[:upper:]][[:alnum:]_]*\z/ + ::Rouge::Formatters.const_get(formatter, false) + else + # Available in Rouge 2.0 or later + ::Rouge::Formatters::HTMLLegacy + end + rescue NameError + # Fallback to Rouge 1.x + ::Rouge::Formatters::HTML + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb new file mode 100644 index 00000000..7ffbc5d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/converter/toc.rb @@ -0,0 +1,69 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to an element tree that represents the table of contents. + # + # The returned tree consists of Element objects of type :toc where the root element is just used + # as container object. Each :toc element contains as value the wrapped :header element and under + # the attribute key :id the header ID that should be used (note that this ID may not exist in + # the wrapped element). + # + # Since the TOC tree consists of special :toc elements, one cannot directly feed this tree to + # other converters! + class Toc < Base + + def initialize(root, options) + super + @toc = Element.new(:toc) + @stack = [] + @options[:template] = '' + end + + def convert(el) + if el.type == :header && in_toc?(el) + attr = el.attr.dup + attr['id'] = generate_id(el.options[:raw_text]) if @options[:auto_ids] && !attr['id'] + add_to_toc(el, attr['id']) if attr['id'] + else + el.children.each {|child| convert(child) } + end + @toc + end + + private + + def add_to_toc(el, id) + toc_element = Element.new(:toc, el, id: id) + + success = false + until success + if @stack.empty? + @toc.children << toc_element + @stack << toc_element + success = true + elsif @stack.last.value.options[:level] < el.options[:level] + @stack.last.children << toc_element + @stack << toc_element + success = true + else + @stack.pop + end + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/document.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/document.rb new file mode 100644 index 00000000..7a10e763 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/document.rb @@ -0,0 +1,139 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# = kramdown +# +# kramdown is fast, pure Ruby Markdown superset converter, using a strict syntax definition and +# supporting several common extensions. +# +# The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However, +# due to its flexibility it supports other input and output formats as well. Here is a list of the +# supported formats: +# +# * input formats: kramdown (a Markdown superset), Markdown, GFM, HTML +# * output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn +# +# All the documentation on the available input and output formats is available at +# http://kramdown.gettalong.org. +# +# == Usage +# +# kramdown has a simple API, so using kramdown is as easy as +# +# require 'kramdown' +# +# Kramdown::Document.new(text).to_html +# +# For detailed information have a look at the *\Kramdown::Document* class. +# +# == License +# +# MIT - see the COPYING file. + +require 'kramdown/version' +require 'kramdown/element' +require 'kramdown/error' +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/options' +require 'kramdown/utils' + +module Kramdown + + # Return the data directory for kramdown. + def self.data_dir + unless defined?(@data_dir) + require 'rbconfig' + @data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown')) + @data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "kramdown")) unless File.exist?(@data_dir) + raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@data_dir) + end + @data_dir + end + + # The main interface to kramdown. + # + # This class provides a one-stop-shop for using kramdown to convert text into various output + # formats. Use it like this: + # + # require 'kramdown' + # doc = Kramdown::Document.new('This *is* some kramdown text') + # puts doc.to_html + # + # The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for + # more information. + # + # The second argument to the ::new method is an options hash for customizing the behaviour of the + # used parser and the converter. See ::new for more information! + class Document + + # The root Element of the element tree. It is immediately available after the ::new method has + # been called. + attr_accessor :root + + # The options hash which holds the options for parsing/converting the Kramdown document. + attr_reader :options + + # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in + # ::new) and the conversion phase. + attr_reader :warnings + + # Create a new Kramdown document from the string +source+ and use the provided +options+. The + # options that can be used are defined in the Options module. + # + # The special options key :input can be used to select the parser that should parse the + # +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to + # select the kramdown parser, one would set the :input key to +Kramdown+. If this key is not + # set, it defaults to +Kramdown+. + # + # The +source+ is immediately parsed by the selected parser so that the root element is + # immediately available and the output can be generated. + def initialize(source, options = {}) + @options = Options.merge(options).freeze + parser = (@options[:input] || 'kramdown').to_s + parser = parser[0..0].upcase + parser[1..-1] + try_require('parser', parser) + if Parser.const_defined?(parser) + @root, @warnings = Parser.const_get(parser).parse(source, @options) + else + raise Kramdown::Error, "kramdown has no parser to handle the specified " \ + "input format: #{@options[:input]}" + end + end + + # Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter + # class (i.e. a class in the Kramdown::Converter module) and use it for converting the document. + # + # For example, +to_html+ would instantiate the Kramdown::Converter::Html class. + def method_missing(id, *attr, &block) + if id.to_s =~ /^to_(\w+)$/ && (name = Utils.camelize($1)) && + try_require('converter', name) && Converter.const_defined?(name) + output, warnings = Converter.const_get(name).convert(@root, @options) + @warnings.concat(warnings) + output + else + super + end + end + + def inspect # :nodoc: + "" + end + + # Try requiring a parser or converter class and don't raise an error if the file is not found. + def try_require(type, name) + require("kramdown/#{type}/#{Utils.snake_case(name)}") + true + rescue LoadError + true + end + protected :try_require + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/element.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/element.rb new file mode 100644 index 00000000..031c7dd1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/element.rb @@ -0,0 +1,551 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # Represents all elements in the element tree. + # + # kramdown only uses this one class for representing all available elements in an element tree + # (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor. + # + # The root of a kramdown element tree has to be an element of type :root. It needs to have certain + # option keys set so that conversions work correctly. If only a part of a tree should be + # converted, duplicate the root node and assign the #children appropriately, e.g: + # + # root = doc.root + # new_root = root.dup + # new_root.children = [root.children[0]] # assign new array with elements to convert + # + # Following is a description of all supported element types. + # + # Note that the option :location may contain the start line number of an element in the source + # document. + # + # == Structural Elements + # + # === :root + # + # [Category] None + # [Usage context] As the root element of a document + # [Content model] Block-level elements + # + # Represents the root of a kramdown document. + # + # The root element contains the following option keys: + # + # :encoding:: When running on Ruby 1.9 this key has to be set to the encoding used for the text + # parts of the kramdown document. + # + # :abbrev_defs:: This key may be used to store the mapping of abbreviation to abbreviation + # definition. + # + # :abbrev_attr:: This key may be used to store the mapping of abbreviation to abbreviation + # attributes. + # + # :options:: This key may be used to store options that were set during parsing of the document. + # + # :footnote_count:: This key stores the number of actually referenced footnotes of the document. + # + # === :blank + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents one or more blank lines. It is not allowed to have two or more consecutive blank + # elements. + # + # The +value+ field may contain the original content of the blank lines. + # + # + # === :p + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a paragraph. + # + # If the option :transparent is +true+, this element just represents a block of text. I.e. this + # element just functions as a container for span-level elements. + # + # + # === :header + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a header. + # + # The option :level specifies the header level and has to contain a number between 1 and \6. The + # option :raw_text has to contain the raw header text. + # + # + # === :blockquote + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Block-level elements + # + # Represents a blockquote. + # + # + # === :codeblock + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents a code block, i.e. a block of text that should be used as-is. + # + # The +value+ field has to contain the content of the code block. + # + # The option :lang specifies a highlighting language with possible HTML style options (e.g. + # php?start_inline=1) and should be used instead of a possibly also available language embedded in + # a class name of the form 'language-LANG'. + # + # + # === :ul + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an unordered list. + # + # + # === :ol + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an ordered list. + # + # + # === :li + # + # [Category] Block-level element + # [Usage context] Inside :ol and :ul elements + # [Content model] Block-level elements + # + # Represents a list item of an ordered or unordered list. + # + # Note that the first child of a list item must not be a :blank element! + # + # + # === :dl + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more groups each consisting of one or more :dt elements followed by one + # or more :dd elements. + # + # Represents a definition list which contains groups consisting of terms and definitions for them. + # + # + # === :dt + # + # [Category] Block-level element + # [Usage context] Before :dt or :dd elements inside a :dl elment + # [Content model] Span-level elements + # + # Represents the term part of a term-definition group in a definition list. + # + # + # === :dd + # + # [Category] Block-level element + # [Usage context] After :dt or :dd elements inside a :dl elment + # [Content model] Block-level elements + # + # Represents the definition part of a term-definition group in a definition list. + # + # + # === :hr + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] None + # + # Represents a horizontal line. + # + # + # === :table + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Zero or one :thead elements, one or more :tbody elements, zero or one :tfoot + # elements + # + # Represents a table. Each table row (i.e. :tr element) of the table has to contain the same + # number of :td elements. + # + # The option :alignment has to be an array containing the alignment values, exactly one for each + # column of the table. The possible alignment values are :left, :center, :right and :default. + # + # + # === :thead + # + # [Category] None + # [Usage context] As first element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table header. + # + # + # === :tbody + # + # [Category] None + # [Usage context] After a :thead element but before a :tfoot element inside a :table element + # [Content model] One or more :tr elements + # + # Represents a table body. + # + # + # === :tfoot + # + # [Category] None + # [Usage context] As last element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table footer. + # + # + # === :tr + # + # [Category] None + # [Usage context] Inside :thead, :tbody and :tfoot elements + # [Content model] One or more :td elements + # + # Represents a table row. + # + # + # === :td + # + # [Category] Block-level element + # [Usage context] Inside :tr elements + # [Content model] As child of :thead/:tr span-level elements, as child of :tbody/:tr and + # :tfoot/:tr block-level elements + # + # Represents a table cell. + # + # + # === :math + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents mathematical text that is written in LaTeX. + # + # The +value+ field has to contain the actual mathematical text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # == Text Markup Elements + # + # === :text + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents text. + # + # The +value+ field has to contain the text itself. + # + # + # === :br + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a hard line break. + # + # + # === :a + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents a link to an URL. + # + # The attribute +href+ has to be set to the URL to which the link points. The attribute +title+ + # optionally contains the title of the link. + # + # + # === :img + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an image. + # + # The attribute +src+ has to be set to the URL of the image. The attribute +alt+ has to contain a + # text description of the image. The attribute +title+ optionally contains the title of the image. + # + # + # === :codespan + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents verbatim text. + # + # The +value+ field has to contain the content of the code span. + # + # + # === :footnote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a footnote marker. + # + # The +value+ field has to contain an element whose children are the content of the footnote. The + # option :name has to contain a valid and unique footnote name. A valid footnote name consists of + # a word character or a digit and then optionally followed by other word characters, digits or + # dashes. + # + # + # === :em + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents emphasis of its contents. + # + # + # === :strong + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents strong importance for its contents. + # + # + # === :entity + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an HTML entity. + # + # The +value+ field has to contain an instance of Kramdown::Utils::Entities::Entity. The option + # :original can be used to store the original representation of the entity. + # + # + # === :typographic_sym + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a typographic symbol. + # + # The +value+ field needs to contain a Symbol representing the specific typographic symbol from + # the following list: + # + # :mdash:: An mdash character (---) + # :ndash:: An ndash character (--) + # :hellip:: An ellipsis (...) + # :laquo:: A left guillemet (<<) + # :raquo:: A right guillemet (>>) + # :laquo_space:: A left guillemet with a space (<< ) + # :raquo_space:: A right guillemet with a space ( >>) + # + # + # === :smart_quote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a quotation character. + # + # The +value+ field needs to contain a Symbol representing the specific quotation character: + # + # :lsquo:: Left single quote + # :rsquo:: Right single quote + # :ldquo:: Left double quote + # :rdquo:: Right double quote + # + # + # === :abbreviation + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a text part that is an abbreviation. + # + # The +value+ field has to contain the text part that is the abbreviation. The definition of the + # abbreviation is stored in the :root element of the document. + # + # + # == Other Elements + # + # === :html_element + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements or raw HTML elements are expected + # [Content model] Depends on the element + # + # Represents an HTML element. + # + # The +value+ field has to contain the name of the HTML element the element is representing. + # + # The option :category has to be set to either :span or :block depending on the whether the + # element is a block-level or a span-level element. The option :content_model has to be set to the + # content model for the element (either :block if it contains block-level elements, :span if it + # contains span-level elements or :raw if it contains raw content). + # + # + # === :xml_comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML comment. + # + # The +value+ field has to contain the whole XML/HTML comment including the delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :xml_pi + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML processing instruction. + # + # The +value+ field has to contain the whole XML/HTML processing instruction including the + # delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a comment. + # + # The +value+ field has to contain the comment. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the comment. + # + # + # === :raw + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a raw string that should not be modified. For example, the element could contain some + # HTML code that should be output as-is without modification and escaping. + # + # The +value+ field has to contain the actual raw text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the raw text. + # + # The option :type can be set to an array of strings to define for which converters the raw string + # is valid. + # + class Element + + # A symbol representing the element type. For example, :p or :blockquote. + attr_accessor :type + + # The value of the element. The interpretation of this field depends on the type of the element. + # Many elements don't use this field. + attr_accessor :value + + # The child elements of this element. + attr_accessor :children + + # Create a new Element object of type +type+. The optional parameters +value+, +attr+ and + # +options+ can also be set in this constructor for convenience. + def initialize(type, value = nil, attr = nil, options = nil) + @type, @value, @attr, @options = type, value, attr, options + @children = [] + end + + # The attributes of the element. + def attr + @attr ||= {} + end + + # The options hash for the element. It is used for storing arbitray options. + def options + @options ||= {} + end + + def inspect # :nodoc: + "hallo` the emphasis tag + would normally be converted to an `:html` element with tag type `:em`. + If `html_to_native` is `true`, then the emphasis would be converted to a + native `:em` element. + + This is useful for converters that cannot deal with HTML elements. + + Default: false + Used by: kramdown parser + EOF + + define(:link_defs, Object, {}, <<~EOF) do |val| + Pre-defines link definitions + + This option can be used to pre-define link definitions. The value needs + to be a Hash where the keys are the link identifiers and the values are + two element Arrays with the link URL and the link title. + + If the value is a String, it has to contain a valid YAML hash and the + hash has to follow the above guidelines. + + Default: {} + Used by: kramdown parser + EOF + val = simple_hash_validator(val, :link_defs) + val.each do |_k, v| + if !(Array === v) || v.size > 2 || v.empty? + raise Kramdown::Error, "Invalid structure for hash value of option #{name}" + end + v << nil if v.size == 1 + end + val + end + + define(:footnote_nr, Integer, 1, <<~EOF) + The number of the first footnote + + This option can be used to specify the number that is used for the first + footnote. + + Default: 1 + Used by: HTML converter + EOF + + define(:entity_output, Symbol, :as_char, <<~EOF) + Defines how entities are output + + The possible values are :as_input (entities are output in the same + form as found in the input), :numeric (entities are output in numeric + form), :symbolic (entities are output in symbolic form if possible) or + :as_char (entities are output as characters if possible, only available + on Ruby 1.9). + + Default: :as_char + Used by: HTML converter, kramdown converter + EOF + + TOC_LEVELS_RANGE = (1..6).freeze + TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze + private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY + + define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val| + Defines the levels that are used for the table of contents + + The individual levels can be specified by separating them with commas + (e.g. 1,2,3) or by using the range syntax (e.g. 1..3). Only the + specified levels are used for the table of contents. + + Default: 1..6 + Used by: HTML/Latex converter + EOF + case val + when String + if val =~ /^(\d)\.\.(\d)$/ + val = Range.new($1.to_i, $2.to_i).to_a + elsif val.match?(/^\d(?:,\d)*$/) + val = val.split(",").map(&:to_i).uniq + else + raise Kramdown::Error, "Invalid syntax for option toc_levels" + end + when Array + unless val.eql?(TOC_LEVELS_ARRAY) + val = val.map(&:to_i).uniq + end + when Range + val = if val.eql?(TOC_LEVELS_RANGE) + TOC_LEVELS_ARRAY + else + val.map(&:to_i).uniq + end + else + raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels" + end + if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) } + raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6" + end + val + end + + define(:line_width, Integer, 72, <<~EOF) + Defines the line width to be used when outputting a document + + Default: 72 + Used by: kramdown converter + EOF + + define(:latex_headers, Object, %w[section subsection subsubsection paragraph subparagraph subparagraph], <<~EOF) do |val| + Defines the LaTeX commands for different header levels + + The commands for the header levels one to six can be specified by + separating them with commas. + + Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph + Used by: Latex converter + EOF + simple_array_validator(val, :latex_headers, 6) + end + + SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze + SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze + private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR + + define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val| + Defines the HTML entity names or code points for smart quote output + + The entities identified by entity name or code point that should be + used for, in order, a left single quote, a right single quote, a left + double and a right double quote are specified by separating them with + commas. + + Default: lsquo,rsquo,ldquo,rdquo + Used by: HTML/Latex converter + EOF + if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES + SMART_QUOTES_ENTITIES + else + val = simple_array_validator(val, :smart_quotes, 4) + val.map! {|v| Integer(v) rescue v } + val + end + end + + define(:typographic_symbols, Object, {}, <<~EOF) do |val| + Defines a mapping from typographical symbol to output characters + + Typographical symbols are normally output using their equivalent Unicode + codepoint. However, sometimes one wants to change the output, mostly to + fallback to a sequence of ASCII characters. + + This option allows this by specifying a mapping from typographical + symbol to its output string. For example, the mapping {hellip: ...} would + output the standard ASCII representation of an ellipsis. + + The available typographical symbol names are: + + * hellip: ellipsis + * mdash: em-dash + * ndash: en-dash + * laquo: left guillemet + * raquo: right guillemet + * laquo_space: left guillemet followed by a space + * raquo_space: right guillemet preceeded by a space + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :typographic_symbols) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k).to_s + end + val + end + + define(:remove_block_html_tags, Boolean, true, <<~EOF) + Remove block HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + block HTML tags. + + Default: true + Used by: RemoveHtmlTags converter + EOF + + define(:remove_span_html_tags, Boolean, false, <<~EOF) + Remove span HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + span HTML tags. + + Default: false + Used by: RemoveHtmlTags converter + EOF + + define(:header_offset, Integer, 0, <<~EOF) + Sets the output offset for headers + + If this option is c (may also be negative) then a header with level n + will be output as a header with level c+n. If c+n is lower than 1, + level 1 will be used. If c+n is greater than 6, level 6 will be used. + + Default: 0 + Used by: HTML converter, Kramdown converter, Latex converter + EOF + + define(:syntax_highlighter, Symbol, :rouge, <<~EOF) + Set the syntax highlighter + + Specifies the syntax highlighter that should be used for highlighting + code blocks and spans. If this option is set to +nil+, no syntax + highlighting is done. + + Options for the syntax highlighter can be set with the + syntax_highlighter_opts configuration option. + + Default: rouge + Used by: HTML/Latex converter + EOF + + define(:syntax_highlighter_opts, Object, {}, <<~EOF) do |val| + Set the syntax highlighter options + + Specifies options for the syntax highlighter set via the + syntax_highlighter configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used syntax highlighter. + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :syntax_highlighter_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:math_engine, Symbol, :mathjax, <<~EOF) + Set the math engine + + Specifies the math engine that should be used for converting math + blocks/spans. If this option is set to +nil+, no math engine is used and + the math blocks/spans are output as is. + + Options for the selected math engine can be set with the + math_engine_opts configuration option. + + Default: mathjax + Used by: HTML converter + EOF + + define(:math_engine_opts, Object, {}, <<~EOF) do |val| + Set the math engine options + + Specifies options for the math engine set via the math_engine + configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used math engine. + + Default: {} + Used by: HTML converter + EOF + val = simple_hash_validator(val, :math_engine_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:footnote_backlink, String, '↩', <<~EOF) + Defines the text that should be used for the footnote backlinks + + The footnote backlink is just text, so any special HTML characters will + be escaped. + + If the footnote backlint text is an empty string, no footnote backlinks + will be generated. + + Default: '&8617;' + Used by: HTML converter + EOF + + define(:footnote_backlink_inline, Boolean, false, <<~EOF) + Specifies whether the footnote backlink should always be inline + + With the default of false the footnote backlink is placed at the end of + the last paragraph if there is one, or an extra paragraph with only the + footnote backlink is created. + + Setting this option to true tries to place the footnote backlink in the + last, possibly nested paragraph or header. If this fails (e.g. in the + case of a table), an extra paragraph with only the footnote backlink is + created. + + Default: false + Used by: HTML converter + EOF + + define(:footnote_prefix, String, '', <<~EOF) + Prefix used for footnote IDs + + This option can be used to set a prefix for footnote IDs. This is useful + when rendering multiple documents into the same output file to avoid + duplicate IDs. The prefix should only contain characters that are valid + in an ID! + + Default: '' + Used by: HTML + EOF + + define(:footnote_link_text, String, '%s', <<~EOF) do |val| + The text used for the footnote number in a footnote link + + This option can be used to add additional text to the footnote + link. It should be a format string, and is passed the footnote + number as the only argument to the format string. + e.g. "[footnote %s]" would display as "[footnote 1]". + + Default: '%s' + Used by: HTML + EOF + if !val.include?('%s') + raise Kramdown::Error, "option footnote_link_text needs to contain a '%s'" + end + val + end + + + define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF) + Specifies whether line breaks should be removed between CJK characters + + Default: false + Used by: HTML converter + EOF + + define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val| + Defines the options that may not be set using the {::options} extension + + The value needs to be an array of option names. + + Default: [template] + Used by: HTML converter + EOF + val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item } + simple_array_validator(val, :forbidden_inline_options) + end + + define(:list_indent, Integer, 2, <<~EOF) + Sets the number of spaces to use for list indentation + + Default: 2 + Used by: Kramdown converter + EOF + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser.rb new file mode 100644 index 00000000..f77dcf6a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # This module contains all available parsers. A parser takes an input string and converts the + # string to an element tree. + # + # New parsers should be derived from the Base class which provides common functionality - see its + # API documentation for how to create a custom converter class. + module Parser + + autoload :Base, 'kramdown/parser/base' + autoload :Kramdown, 'kramdown/parser/kramdown' + autoload :Html, 'kramdown/parser/html' + autoload :Markdown, 'kramdown/parser/markdown' + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb new file mode 100644 index 00000000..298c9745 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/base.rb @@ -0,0 +1,137 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # == \Base class for parsers + # + # This class serves as base class for parsers. It provides common methods that can/should be + # used by all parsers, especially by those using StringScanner(Kramdown) for parsing. + # + # A parser object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during parsing. Therefore one can't instantiate a parser object directly but + # only use the Base::parse method. + # + # == Implementing a parser + # + # Implementing a new parser is rather easy: just derive a new class from this class and put it + # in the Kramdown::Parser module -- the latter is needed so that the auto-detection of the new + # parser works correctly. Then you need to implement the +#parse+ method which has to contain + # the parsing code. + # + # Have a look at the Base::parse, Base::new and Base#parse methods for additional information! + class Base + + # The hash with the parsing options. + attr_reader :options + + # The array with the parser warnings. + attr_reader :warnings + + # The original source string. + attr_reader :source + + # The root element of element tree that is created from the source string. + attr_reader :root + + # Initialize the parser object with the +source+ string and the parsing +options+. + # + # The @root element, the @warnings array and @text_type (specifies the default type for newly + # created text nodes) are automatically initialized. + def initialize(source, options) + @source = source + @options = Kramdown::Options.merge(options) + @root = Element.new(:root, nil, nil, encoding: (source.encoding rescue nil), location: 1, + options: {}, abbrev_defs: {}, abbrev_attr: {}) + + @root.options[:abbrev_defs].default_proc = @root.options[:abbrev_attr].default_proc = + lambda do |h, k| + k_mod = k.gsub(/[\s\p{Z}]+/, " ") + k != k_mod ? h[k_mod] : nil + end + @warnings = [] + @text_type = :text + end + private_class_method(:new, :allocate) + + # Parse the +source+ string into an element tree, possibly using the parsing +options+, and + # return the root element of the element tree and an array with warning messages. + # + # Initializes a new instance of the calling class and then calls the +#parse+ method that must + # be implemented by each subclass. + def self.parse(source, options = {}) + parser = new(source, options) + parser.parse + [parser.root, parser.warnings] + end + + # Parse the source string into an element tree. + # + # The parsing code should parse the source provided in @source and build an element tree the + # root of which should be @root. + # + # This is the only method that has to be implemented by sub-classes! + def parse + raise NotImplementedError + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + # TODO: add position information + end + + # Modify the string +source+ to be usable by the parser (unifies line ending characters to + # +\n+ and makes sure +source+ ends with a new line character). + def adapt_source(source) + unless source.valid_encoding? + raise "The source text contains invalid characters for the used encoding #{source.encoding}" + end + source = source.encode('UTF-8') + source.gsub!(/\r\n?/, "\n") + source.chomp! + source << "\n" + end + + # This helper method adds the given +text+ either to the last element in the +tree+ if it is a + # +type+ element or creates a new text element with the given +type+. + def add_text(text, tree = @tree, type = @text_type) + last = tree.children.last + if last && last.type == type + last.value << text + elsif !text.empty? + location = (last && last.options[:location] || tree.options[:location]) + tree.children << Element.new(type, text, nil, location: location) + end + end + + # Extract the part of the StringScanner +strscan+ backed string specified by the +range+. This + # method works correctly under Ruby 1.8 and Ruby 1.9. + def extract_string(range, strscan) + result = nil + begin + enc = strscan.string.encoding + strscan.string.force_encoding('ASCII-8BIT') + result = strscan.string[range].force_encoding(enc) + ensure + strscan.string.force_encoding(enc) + end + result + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb new file mode 100644 index 00000000..2c99fdc5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/html.rb @@ -0,0 +1,621 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' +require 'strscan' +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing an HTML document. + # + # The parsing code is in the Parser module that can also be used by other parsers. + class Html < Base + + # Contains all constants that are used when parsing. + module Constants + + # :stopdoc: + # The following regexps are based on the ones used by REXML, with some slight modifications. + HTML_DOCTYPE_RE = //im + HTML_COMMENT_RE = //m + HTML_INSTRUCTION_RE = /<\?(.*?)\?>/m + HTML_CDATA_RE = //m + HTML_ATTRIBUTE_RE = /\s*(#{REXML::Parsers::BaseParser::UNAME_STR})(?:\s*=\s*(?:(\p{Word}+)|("|')(.*?)\3))?/m + HTML_TAG_RE = /<((?>#{REXML::Parsers::BaseParser::UNAME_STR}))\s*((?>\s+#{REXML::Parsers::BaseParser::UNAME_STR}(?:\s*=\s*(?:\p{Word}+|("|').*?\3))?)*)\s*(\/)?>/m + HTML_TAG_CLOSE_RE = /<\/(#{REXML::Parsers::BaseParser::UNAME_STR})\s*>/m + HTML_ENTITY_RE = /&([\w:][\w.:-]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/ + + HTML_CONTENT_MODEL_BLOCK = %w[address applet article aside blockquote body + dd details div dl fieldset figure figcaption + footer form header hgroup iframe li main + map menu nav noscript object section summary td] + HTML_CONTENT_MODEL_SPAN = %w[a abbr acronym b bdo big button cite caption del dfn dt em + h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc + rp rt rtc ruby select small span strong sub sup th tt] + HTML_CONTENT_MODEL_RAW = %w[script style math option textarea pre code kbd samp var] + # The following elements are also parsed as raw since they need child elements that cannot + # be expressed using kramdown syntax: colgroup table tbody thead tfoot tr ul ol + + HTML_CONTENT_MODEL = Hash.new {|h, k| h[k] = :raw } + HTML_CONTENT_MODEL_BLOCK.each {|i| HTML_CONTENT_MODEL[i] = :block } + HTML_CONTENT_MODEL_SPAN.each {|i| HTML_CONTENT_MODEL[i] = :span } + HTML_CONTENT_MODEL_RAW.each {|i| HTML_CONTENT_MODEL[i] = :raw } + + # Some HTML elements like script belong to both categories (i.e. are valid in block and + # span HTML) and don't appear therefore! + # script, textarea + HTML_SPAN_ELEMENTS = %w[a abbr acronym b big bdo br button cite code del dfn em i img input + ins kbd label mark option q rb rbc rp rt rtc ruby samp select small + span strong sub sup time tt u var] + HTML_BLOCK_ELEMENTS = %w[address article aside applet body blockquote caption col colgroup + dd div dl dt fieldset figcaption footer form h1 h2 h3 h4 h5 h6 + header hgroup hr html head iframe legend menu li main map nav ol + optgroup p pre section summary table tbody td th thead tfoot tr ul] + HTML_ELEMENTS_WITHOUT_BODY = %w[area base br col command embed hr img input keygen link + meta param source track wbr] + + HTML_ELEMENT = Hash.new(false) + (HTML_SPAN_ELEMENTS + HTML_BLOCK_ELEMENTS + HTML_ELEMENTS_WITHOUT_BODY + + HTML_CONTENT_MODEL.keys).each do |a| + HTML_ELEMENT[a] = true + end + end + + # Contains the parsing methods. This module can be mixed into any parser to get HTML parsing + # functionality. The only thing that must be provided by the class are instance variable + # @stack for storing the needed state and @src (instance of StringScanner) for the actual + # parsing. + module Parser + + include Constants + + # Process the HTML start tag that has already be scanned/checked via @src. + # + # Does the common processing steps and then yields to the caller for further processing + # (first parameter is the created element; the second parameter is +true+ if the HTML + # element is already closed, ie. contains no body; the third parameter specifies whether the + # body - and the end tag - need to be handled in case closed=false). + def handle_html_start_tag(line = nil) # :yields: el, closed, handle_body + name = @src[1] + name.downcase! if HTML_ELEMENT[name.downcase] + closed = !@src[4].nil? + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[name]) + + el = Element.new(:html_element, name, attrs, category: :block) + el.options[:location] = line if line + @tree.children << el + + if !closed && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + closed = true + end + if name == 'script' || name == 'style' + handle_raw_html_tag(name) + yield(el, false, false) + else + yield(el, closed, true) + end + end + + # Parses the given string for HTML attributes and returns the resulting hash. + # + # If the optional +line+ parameter is supplied, it is used in warning messages. + # + # If the optional +in_html_tag+ parameter is set to +false+, attributes are not modified to + # contain only lowercase letters. + def parse_html_attributes(str, line = nil, in_html_tag = true) + attrs = {} + str.scan(HTML_ATTRIBUTE_RE).each do |attr, val, _sep, quoted_val| + attr.downcase! if in_html_tag + if attrs.key?(attr) + warning("Duplicate HTML attribute '#{attr}' on line #{line || '?'} - overwriting previous one") + end + attrs[attr] = val || quoted_val || "" + end + attrs + end + + # Handle the raw HTML tag at the current position. + def handle_raw_html_tag(name) + curpos = @src.pos + if @src.scan_until(/(?=<\/#{name}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), @tree.children.last, :raw) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, @tree.children.last, :raw) + @src.terminate + warning("Found no end tag for '#{name}' - auto-closing it") + end + end + + HTML_RAW_START = /(?=<(#{REXML::Parsers::BaseParser::UNAME_STR}|\/|!--|\?|!\[CDATA\[))/ # :nodoc: + + # Parse raw HTML from the current source position, storing the found elements in +el+. + # Parsing continues until one of the following criteria are fulfilled: + # + # - The end of the document is reached. + # - The matching end tag for the element +el+ is found (only used if +el+ is an HTML + # element). + # + # When an HTML start tag is found, processing is deferred to #handle_html_start_tag, + # providing the block given to this method. + def parse_raw_html(el, &block) + @stack.push(@tree) + @tree = el + + done = false + while !@src.eos? && !done + if (result = @src.scan_until(HTML_RAW_START)) + add_text(result, @tree, :text) + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + elsif (result = @src.scan(HTML_INSTRUCTION_RE)) + @tree.children << Element.new(:xml_pi, result, nil, category: :block, location: line) + elsif @src.scan(HTML_CDATA_RE) + @tree.children << Element.new(:text, @src[1], nil, cdata: true, location: line) + elsif @src.scan(HTML_TAG_RE) + if method(:handle_html_start_tag).arity.abs >= 1 + handle_html_start_tag(line, &block) + else + handle_html_start_tag(&block) # DEPRECATED: method needs to accept line number in 2.0 + end + elsif @src.scan(HTML_TAG_CLOSE_RE) + if @tree.value == (HTML_ELEMENT[@tree.value] ? @src[1].downcase : @src[1]) + done = true + else + add_text(@src.matched, @tree, :text) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on " \ + "line #{line} - ignoring it") + end + else + add_text(@src.getch, @tree, :text) + end + else + add_text(@src.rest, @tree, :text) + @src.terminate + if @tree.type == :html_element + warning("Found no end tag for '#{@tree.value}' on line " \ + "#{@tree.options[:location]} - auto-closing it") + end + done = true + end + end + + @tree = @stack.pop + end + + end + + # Converts HTML elements to native elements if possible. + class ElementConverter + + # :stopdoc: + + include Constants + include ::Kramdown::Utils::Entities + + REMOVE_TEXT_CHILDREN = %w[html head hgroup ol ul dl table colgroup tbody thead tfoot tr + select optgroup] + WRAP_TEXT_CHILDREN = %w[body section nav article aside header footer address div li dd + blockquote figure figcaption fieldset form] + REMOVE_WHITESPACE_CHILDREN = %w[body section nav article aside header footer address + div li dd blockquote figure figcaption td th fieldset form] + STRIP_WHITESPACE = %w[address article aside blockquote body caption dd div dl dt fieldset + figcaption form footer header h1 h2 h3 h4 h5 h6 legend li nav p + section td th] + SIMPLE_ELEMENTS = %w[em strong blockquote hr br img p thead tbody tfoot tr td th ul ol dl + li dl dt dd] + + def initialize(root) + @root = root + end + + def self.convert(root, el = root) + new(root).process(el) + end + + # Convert the element +el+ and its children. + def process(el, do_conversion = true, preserve_text = false, parent = nil) + case el.type + when :xml_comment, :xml_pi + ptype = if parent.nil? + 'div' + else + case parent.type + when :html_element then parent.value + when :code_span then 'code' + when :code_block then 'pre' + when :header then 'h1' + else parent.type.to_s + end + end + el.options.replace(category: (HTML_CONTENT_MODEL[ptype] == :span ? :span : :block)) + return + when :html_element + # do nothing + when :root + el.children.map! do |c| + if c.type == :text + process_text(c.value, !do_conversion) + else + process(c) + c + end + end.flatten! + remove_whitespace_children(el) + return + else return + end + + mname = "convert_#{el.value}" + if do_conversion && self.class.method_defined?(mname) + send(mname, el) + else + type = el.value + remove_text_children(el) if do_conversion && REMOVE_TEXT_CHILDREN.include?(type) + + if do_conversion && SIMPLE_ELEMENTS.include?(type) + set_basics(el, type.intern) + process_children(el, do_conversion, preserve_text) + else + process_html_element(el, do_conversion, preserve_text) + end + + if do_conversion + strip_whitespace(el) if STRIP_WHITESPACE.include?(type) + remove_whitespace_children(el) if REMOVE_WHITESPACE_CHILDREN.include?(type) + wrap_text_children(el) if WRAP_TEXT_CHILDREN.include?(type) + end + end + end + + def process_children(el, do_conversion = true, preserve_text = false) + el.children.map! do |c| + if c.type == :text + process_text(c.value, preserve_text || !do_conversion) + else + process(c, do_conversion, preserve_text, el) + c + end + end.flatten! + end + + # Process the HTML text +raw+: compress whitespace (if +preserve+ is +false+) and convert + # entities in entity elements. + def process_text(raw, preserve = false) + raw.gsub!(/\s+/, ' ') unless preserve + src = Kramdown::Utils::StringScanner.new(raw) + result = [] + until src.eos? + if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o)) + result << Element.new(:text, tmp) + src.scan(HTML_ENTITY_RE) + val = src[1] || src[2]&.to_i || src[3].hex + result << if %w[lsquo rsquo ldquo rdquo].include?(val) + Element.new(:smart_quote, val.intern) + elsif %w[mdash ndash hellip laquo raquo].include?(val) + Element.new(:typographic_sym, val.intern) + else + begin + Element.new(:entity, entity(val), nil, original: src.matched) + rescue ::Kramdown::Error + src.pos -= src.matched_size - 1 + Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp')) + end + end + else + result << Element.new(:text, src.rest) + src.terminate + end + end + result + end + + def process_html_element(el, do_conversion = true, preserve_text = false) + el.options.replace(category: HTML_SPAN_ELEMENTS.include?(el.value) ? :span : :block, + content_model: (do_conversion ? HTML_CONTENT_MODEL[el.value] : :raw)) + process_children(el, do_conversion, preserve_text) + end + + def remove_text_children(el) + el.children.delete_if {|c| c.type == :text } + end + + def wrap_text_children(el) + tmp = [] + last_is_p = false + el.children.each do |c| + if !c.block? || c.type == :text + unless last_is_p + tmp << Element.new(:p, nil, nil, transparent: true) + last_is_p = true + end + tmp.last.children << c + tmp + else + tmp << c + last_is_p = false + end + end + el.children = tmp + end + + def strip_whitespace(el) + return if el.children.empty? + if el.children.first.type == :text + el.children.first.value.lstrip! + end + if el.children.last.type == :text + el.children.last.value.rstrip! + end + end + + def remove_whitespace_children(el) + i = -1 + el.children = el.children.reject do |c| + i += 1 + c.type == :text && c.value.strip.empty? && + (i == 0 || i == el.children.length - 1 || (el.children[i - 1].block? && + el.children[i + 1].block?)) + end + end + + def set_basics(el, type, opts = {}) + el.type = type + el.options.replace(opts) + el.value = nil + end + + def extract_text(el, raw) + raw << el.value.to_s if el.type == :text + el.children.each {|c| extract_text(c, raw) } + end + + def convert_textarea(el) + process_html_element(el, true, true) + end + + def convert_a(el) + if el.attr['href'] + set_basics(el, :a) + process_children(el) + else + process_html_element(el, false) + end + end + + EMPHASIS_TYPE_MAP = {'em' => :em, 'i' => :em, 'strong' => :strong, 'b' => :strong} + def convert_em(el) + text = +'' + extract_text(el, text) + if text =~ /\A\s/ || text =~ /\s\z/ + process_html_element(el, false) + else + set_basics(el, EMPHASIS_TYPE_MAP[el.value]) + process_children(el) + end + end + %w[b strong i].each do |i| + alias_method("convert_#{i}".to_sym, :convert_em) + end + + def convert_h1(el) + set_basics(el, :header, level: el.value[1..1].to_i) + extract_text(el, el.options[:raw_text] = +'') + process_children(el) + end + %w[h2 h3 h4 h5 h6].each do |i| + alias_method("convert_#{i}".to_sym, :convert_h1) + end + + def convert_code(el) + raw = +'' + extract_text(el, raw) + result = process_text(raw, true) + begin + str = result.inject(+'') do |mem, c| + case c.type + when :text + mem << c.value + when :entity + mem << if [60, 62, 34, 38].include?(c.value.code_point) + c.value.code_point.chr + else + c.value.char + end + when :smart_quote, :typographic_sym + mem << entity(c.value.to_s).char + else + raise "Bug - please report" + end + end + result.clear + result << Element.new(:text, str) + rescue StandardError + end + if result.length > 1 || result.first.type != :text + process_html_element(el, false, true) + else + if el.value == 'code' + set_basics(el, :codespan) + el.attr['class']&.gsub!(/\s+\bhighlighter-\w+\b|\bhighlighter-\w+\b\s*/, '') + else + set_basics(el, :codeblock) + if el.children.size == 1 && el.children.first.value == 'code' + value = (el.children.first.attr['class'] || '').scan(/\blanguage-\S+/).first + el.attr['class'] = "#{value} #{el.attr['class']}".rstrip if value + end + end + el.value = result.first.value + el.children.clear + end + end + alias convert_pre convert_code + + def convert_table(el) + unless is_simple_table?(el) + process_html_element(el, false) + return + end + remove_text_children(el) + process_children(el) + set_basics(el, :table) + + calc_alignment = lambda do |c| + if c.type == :tr + el.options[:alignment] = c.children.map do |td| + if td.attr['style'] + td.attr['style'].slice!(/(?:;\s*)?text-align:\s+(center|left|right)/) + td.attr.delete('style') if td.attr['style'].strip.empty? + $1 ? $1.to_sym : :default + else + :default + end + end + else + c.children.each {|cc| calc_alignment.call(cc) } + end + end + calc_alignment.call(el) + el.children.delete_if {|c| c.type == :html_element } + + change_th_type = lambda do |c| + if c.type == :th + c.type = :td + else + c.children.each {|cc| change_th_type.call(cc) } + end + end + change_th_type.call(el) + + if el.children.first.type == :tr + tbody = Element.new(:tbody) + tbody.children = el.children + el.children = [tbody] + end + end + + def is_simple_table?(el) + only_phrasing_content = lambda do |c| + c.children.all? do |cc| + (cc.type == :text || !HTML_BLOCK_ELEMENTS.include?(cc.value)) && only_phrasing_content.call(cc) + end + end + check_cells = proc do |c| + if c.value == 'th' || c.value == 'td' + return false unless only_phrasing_content.call(c) + else + c.children.each {|cc| check_cells.call(cc) } + end + end + check_cells.call(el) + + nr_cells = 0 + check_nr_cells = lambda do |t| + if t.value == 'tr' + count = t.children.count {|cc| cc.value == 'th' || cc.value == 'td' } + if count != nr_cells + if nr_cells == 0 + nr_cells = count + else + nr_cells = -1 + break + end + end + else + t.children.each {|cc| check_nr_cells.call(cc) } + end + end + check_nr_cells.call(el) + return false if nr_cells == -1 || nr_cells == 0 + + alignment = nil + check_alignment = proc do |t| + if t.value == 'tr' + cur_alignment = t.children.select {|cc| cc.value == 'th' || cc.value == 'td' }.map do |cell| + md = /text-align:\s+(center|left|right|justify|inherit)/.match(cell.attr['style'].to_s) + return false if md && (md[1] == 'justify' || md[1] == 'inherit') + md.nil? ? :default : md[1] + end + alignment = cur_alignment if alignment.nil? + return false if alignment != cur_alignment + else + t.children.each {|cc| check_alignment.call(cc) } + end + end + check_alignment.call(el) + + check_rows = lambda do |t, type| + t.children.all? do |r| + (r.value == 'tr' || r.type == :text) && r.children.all? {|c| c.value == type || c.type == :text } + end + end + check_rows.call(el, 'td') || + (el.children.all? do |t| + t.type == :text || (t.value == 'thead' && check_rows.call(t, 'th')) || + ((t.value == 'tfoot' || t.value == 'tbody') && check_rows.call(t, 'td')) + end && el.children.any? {|t| t.value == 'tbody' }) + end + + def convert_script(el) + if is_math_tag?(el) + handle_math_tag(el) + else + process_html_element(el) + end + end + + def is_math_tag?(el) + el.attr['type'].to_s =~ /\bmath\/tex\b/ + end + + def handle_math_tag(el) + set_basics(el, :math, category: (el.attr['type'].include?("mode=display") ? :block : :span)) + el.value = el.children.shift.value.sub(/\A(?:%\s*)?\z/m, '\1') + el.attr.delete('type') + end + + end + + include Parser + + # Parse the source string provided on initialization as HTML document. + def parse + @stack, @tree = [], @root + @src = Kramdown::Utils::StringScanner.new(adapt_source(source)) + + while true + if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o)) + @tree.children << Element.new(:xml_pi, result.strip, nil, category: :block) + elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o)) + # ignore the doctype + elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o)) + @tree.children << Element.new(:xml_comment, result.strip, nil, category: :block) + else + break + end + end + + tag_handler = lambda do |c, closed, handle_body| + parse_raw_html(c, &tag_handler) if !closed && handle_body + end + parse_raw_html(@tree, &tag_handler) + + ElementConverter.convert(@tree) + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb new file mode 100644 index 00000000..a8f480bc --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown.rb @@ -0,0 +1,377 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' +require 'stringio' +require 'kramdown/parser' + +# TODO: use [[:alpha:]] in all regexp to allow parsing of international values in 1.9.1 +# NOTE: use @src.pre_match only before other check/match?/... operations, otherwise the content is changed + +module Kramdown + + module Parser + + # Used for parsing a document in kramdown format. + # + # If you want to extend the functionality of the parser, you need to do the following: + # + # * Create a new subclass + # * add the needed parser methods + # * modify the @block_parsers and @span_parsers variables and add the names of your parser + # methods + # + # Here is a small example for an extended parser class that parses ERB style tags as raw text if + # they are used as span-level elements (an equivalent block-level parser should probably also be + # made to handle the block case): + # + # require 'kramdown/parser/kramdown' + # + # class Kramdown::Parser::ERBKramdown < Kramdown::Parser::Kramdown + # + # def initialize(source, options) + # super + # @span_parsers.unshift(:erb_tags) + # end + # + # ERB_TAGS_START = /<%.*?%>/ + # + # def parse_erb_tags + # @src.pos += @src.matched_size + # @tree.children << Element.new(:raw, @src.matched) + # end + # define_parser(:erb_tags, ERB_TAGS_START, '<%') + # + # end + # + # The new parser can be used like this: + # + # require 'kramdown/document' + # # require the file with the above parser class + # + # Kramdown::Document.new(input_text, :input => 'ERBKramdown').to_html + # + class Kramdown < Base + + include ::Kramdown + + # Create a new Kramdown parser object with the given +options+. + def initialize(source, options) + super + + reset_env + + @alds = {} + @footnotes = {} + @link_defs = {} + update_link_definitions(@options[:link_defs]) + + @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header, + :horizontal_rule, :list, :definition_list, :block_html, :setext_header, + :block_math, :table, :footnote_definition, :link_definition, + :abbrev_definition, :block_extensions, :eob_marker, :paragraph] + @span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, + :smart_quotes, :inline_math, :span_extensions, :html_entity, + :typographic_syms, :line_break, :escaped_chars] + + @span_pattern_cache ||= Hash.new {|h, k| h[k] = {} } + end + private_class_method(:new, :allocate) + + # The source string provided on initialization is parsed into the @root element. + def parse + configure_parser + parse_blocks(@root, adapt_source(source)) + update_tree(@root) + correct_abbreviations_attributes + replace_abbreviations(@root) + @footnotes.each do |_name, data| + update_tree(data[:content]) + replace_abbreviations(data[:content]) + end + footnote_count = 0 + @footnotes.each do |name, data| + (footnote_count += 1; next) if data.key?(:marker) + line = data[:content].options[:location] + warning("Footnote definition for '#{name}' on line #{line} is unreferenced - ignoring") + end + @root.options[:footnote_count] = footnote_count + end + + protected + + # :doc: + # + # Update the parser specific link definitions with the data from +link_defs+ (the value of the + # :link_defs option). + # + # The parameter +link_defs+ is a hash where the keys are possibly unnormalized link IDs and + # the values are two element arrays consisting of the link target and a title (can be +nil+). + def update_link_definitions(link_defs) + link_defs.each {|k, v| @link_defs[normalize_link_id(k)] = v } + end + + # Adapt the object to allow parsing like specified in the options. + def configure_parser + @parsers = {} + (@block_parsers + @span_parsers).each do |name| + if self.class.has_parser?(name) + @parsers[name] = self.class.parser(name) + else + raise Kramdown::Error, "Unknown parser: #{name}" + end + end + @span_start, @span_start_re = span_parser_regexps + end + + # Create the needed span parser regexps. + def span_parser_regexps(parsers = @span_parsers) + span_start = /#{parsers.map {|name| @parsers[name].span_start }.join('|')}/ + [span_start, /(?=#{span_start})/] + end + + # Parse all block-level elements in +text+ into the element +el+. + def parse_blocks(el, text = nil) + @stack.push([@tree, @src, @block_ial]) + @tree, @block_ial = el, nil + @src = (text.nil? ? @src : ::Kramdown::Utils::StringScanner.new(text, el.options[:location])) + + status = catch(:stop_block_parsing) do + until @src.eos? + @block_parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + else + false + end + end || begin + warning('Warning: this should not occur - no block parser handled the line') + add_text(@src.scan(/.*\n/)) + end + end + end + + @tree, @src, @block_ial = *@stack.pop + status + end + + # Update the tree by parsing all :+raw_text+ elements with the span-level parser (resets the + # environment) and by updating the attributes from the IALs. + def update_tree(element) + last_blank = nil + element.children.map! do |child| + case child.type + when :raw_text + last_blank = nil + reset_env(src: ::Kramdown::Utils::StringScanner.new(child.value, element.options[:location]), + text_type: :text) + parse_spans(child) + child.children + when :eob + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + [] + when :blank + if last_blank + last_blank.value << child.value + [] + else + last_blank = child + child + end + else + last_blank = nil + update_tree(child) + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be + # the default behaviour + if child.type == :dt || (child.type == :header && @options[:auto_id_stripping]) + update_raw_text(child) + end + child + end + end.flatten! + end + + def span_pattern_cache(stop_re, span_start) + @span_pattern_cache[stop_re][span_start] ||= /(?=#{Regexp.union(stop_re, span_start)})/ + end + private :span_pattern_cache + + # Parse all span-level elements in the source string of @src into +el+. + # + # If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp + # matches and if no block is given or if a block is given and it returns +true+. + # + # The parameter +parsers+ can be used to specify the (span-level) parsing methods that should + # be used for parsing. + # + # The parameter +text_type+ specifies the type which should be used for created text nodes. + def parse_spans(el, stop_re = nil, parsers = nil, text_type = @text_type) + @stack.push([@tree, @text_type]) unless @tree.nil? + @tree, @text_type = el, text_type + + span_start = @span_start + span_start_re = @span_start_re + span_start, span_start_re = span_parser_regexps(parsers) if parsers + parsers ||= @span_parsers + + used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start)) + stop_re_found = false + while !@src.eos? && !stop_re_found + if (result = @src.scan_until(used_re)) + add_text(result) + if stop_re && @src.check(stop_re) + stop_re_found = (block_given? ? yield : true) + end + processed = parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + true + else + false + end + end unless stop_re_found + add_text(@src.getch) if !processed && !stop_re_found + else + (add_text(@src.rest); @src.terminate) unless stop_re + break + end + end + + @tree, @text_type = @stack.pop + + stop_re_found + end + + # Reset the current parsing environment. The parameter +env+ can be used to set initial + # values for one or more environment variables. + def reset_env(opts = {}) + opts = {text_type: :raw_text, stack: []}.merge(opts) + @src = opts[:src] + @tree = opts[:tree] + @block_ial = opts[:block_ial] + @stack = opts[:stack] + @text_type = opts[:text_type] + end + + # Return the current parsing environment. + def save_env + [@src, @tree, @block_ial, @stack, @text_type] + end + + # Restore the current parsing environment. + def restore_env(env) + @src, @tree, @block_ial, @stack, @text_type = *env + end + + # Update the given attributes hash +attr+ with the information from the inline attribute list + # +ial+ and all referenced ALDs. + def update_attr_with_ial(attr, ial) + ial[:refs]&.each do |ref| + update_attr_with_ial(attr, ref) if (ref = @alds[ref]) + end + ial.each do |k, v| + if k == IAL_CLASS_ATTR + attr[k] = "#{attr[k]} #{v}".lstrip + elsif k.kind_of?(String) + attr[k] = v + end + end + end + + # Update the raw text for automatic ID generation. + def update_raw_text(item) + raw_text = +'' + + append_text = lambda do |child| + if child.type == :text + raw_text << child.value + else + child.children.each {|c| append_text.call(c) } + end + end + + append_text.call(item) + item.options[:raw_text] = raw_text + end + + # Create a new block-level element, taking care of applying a preceding block IAL if it + # exists. This method should always be used for creating a block-level element! + def new_block_el(*args) + el = Element.new(*args) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + el + end + + @@parsers = {} + + # Struct class holding all the needed data for one block/span-level parser method. + Data = Struct.new(:name, :start_re, :span_start, :method) + + # Add a parser method + # + # * with the given +name+, + # * using +start_re+ as start regexp + # * and, for span parsers, +span_start+ as a String that can be used in a regexp and + # which identifies the starting character(s) + # + # to the registry. The method name is automatically derived from the +name+ or can explicitly + # be set by using the +meth_name+ parameter. + def self.define_parser(name, start_re, span_start = nil, meth_name = "parse_#{name}") + raise "A parser with the name #{name} already exists!" if @@parsers.key?(name) + @@parsers[name] = Data.new(name, start_re, span_start, meth_name) + end + + # Return the Data structure for the parser +name+. + def self.parser(name = nil) + @@parsers[name] + end + + # Return +true+ if there is a parser called +name+. + def self.has_parser?(name) + @@parsers.key?(name) + end + + # Regexp for matching indentation (one tab or four spaces) + INDENT = /^(?:\t| {4})/ + # Regexp for matching the optional space (zero or up to three spaces) + OPT_SPACE = / {0,3}/ + + require 'kramdown/parser/kramdown/blank_line' + require 'kramdown/parser/kramdown/eob' + require 'kramdown/parser/kramdown/paragraph' + require 'kramdown/parser/kramdown/header' + require 'kramdown/parser/kramdown/blockquote' + require 'kramdown/parser/kramdown/table' + require 'kramdown/parser/kramdown/codeblock' + require 'kramdown/parser/kramdown/horizontal_rule' + require 'kramdown/parser/kramdown/list' + require 'kramdown/parser/kramdown/link' + require 'kramdown/parser/kramdown/extensions' + require 'kramdown/parser/kramdown/footnote' + require 'kramdown/parser/kramdown/html' + require 'kramdown/parser/kramdown/escaped_chars' + require 'kramdown/parser/kramdown/html_entity' + require 'kramdown/parser/kramdown/line_break' + require 'kramdown/parser/kramdown/typographic_symbol' + require 'kramdown/parser/kramdown/autolink' + require 'kramdown/parser/kramdown/codespan' + require 'kramdown/parser/kramdown/emphasis' + require 'kramdown/parser/kramdown/smart_quotes' + require 'kramdown/parser/kramdown/math' + require 'kramdown/parser/kramdown/abbreviation' + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb new file mode 100644 index 00000000..dbde8d29 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/abbreviation.rb @@ -0,0 +1,80 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ABBREV_DEFINITION_START = /^#{OPT_SPACE}\*\[(.+?)\]:(.*?)\n/ + + # Parse the link definition at the current location. + def parse_abbrev_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + abbrev_id, abbrev_text = @src[1], @src[2] + abbrev_text.strip! + if @root.options[:abbrev_defs][abbrev_id] + warning("Duplicate abbreviation ID '#{abbrev_id}' on line #{start_line_number} " \ + "- overwriting") + end + @tree.children << new_block_el(:eob, :abbrev_def) + @root.options[:abbrev_defs][abbrev_id] = abbrev_text + @root.options[:abbrev_attr][abbrev_id] = @tree.children.last + true + end + define_parser(:abbrev_definition, ABBREV_DEFINITION_START) + + # Correct abbreviation attributes. + def correct_abbreviations_attributes + @root.options[:abbrev_attr].keys.each do |k| + @root.options[:abbrev_attr][k] = @root.options[:abbrev_attr][k].attr + end + end + + # Replace the abbreviation text with elements. + def replace_abbreviations(el, regexps = nil) + return if @root.options[:abbrev_defs].empty? + unless regexps + sorted_abbrevs = @root.options[:abbrev_defs].keys.sort {|a, b| b.length <=> a.length } + regexps = [Regexp.union(*sorted_abbrevs.map do |k| + /#{Regexp.escape(k).gsub(/\\\s/, "[\\s\\p{Z}]+").force_encoding(Encoding::UTF_8)}/ + end)] + regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries + end + el.children.map! do |child| + if child.type == :text && el.options[:content_model] != :raw + if child.value.match?(regexps.first) + result = [] + strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location]) + text_lineno = strscan.current_line_number + while (temp = strscan.scan_until(regexps.last)) + abbr_lineno = strscan.current_line_number + abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one + if abbr.nil? + temp << strscan.scan(/\W|^/) + abbr = strscan.scan(regexps.first) + end + result << Element.new(:text, temp, nil, location: text_lineno) + result << Element.new(:abbreviation, abbr, nil, location: abbr_lineno) + text_lineno = strscan.current_line_number + end + result << Element.new(:text, strscan.rest, nil, location: text_lineno) + else + child + end + else + replace_abbreviations(child, regexps) + child + end + end.flatten! + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb new file mode 100644 index 00000000..8fa974e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/autolink.rb @@ -0,0 +1,31 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ACHARS = '[[:alnum:]]-_.' + AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[#{ACHARS}]+?@[#{ACHARS}]+?)>" + AUTOLINK_START = /#{AUTOLINK_START_STR}/u + + # Parse the autolink at the current location. + def parse_autolink + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1]) + el = Element.new(:a, nil, {'href' => href}, location: start_line_number) + add_text(@src[1].sub(/^mailto:/, ''), el) + @tree.children << el + end + define_parser(:autolink, AUTOLINK_START, '<') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb new file mode 100644 index 00000000..bb8989a6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blank_line.rb @@ -0,0 +1,30 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + BLANK_LINE = /(?>^\s*\n)+/ + + # Parse the blank line at the current postition. + def parse_blank_line + @src.pos += @src.matched_size + if (last_child = @tree.children.last) && last_child.type == :blank + last_child.value << @src.matched + else + @tree.children << new_block_el(:blank, @src.matched) + end + true + end + define_parser(:blank_line, BLANK_LINE) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb new file mode 100644 index 00000000..daa08849 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/block_boundary.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/ + + # Return +true+ if we are after a block boundary. + def after_block_boundary? + last_child = @tree.children.last + !last_child || last_child.type == :blank || + (last_child.type == :eob && last_child.value.nil?) || @block_ial + end + + # Return +true+ if we are before a block boundary. + def before_block_boundary? + @src.check(self.class::BLOCK_BOUNDARY) + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb new file mode 100644 index 00000000..8934c5a2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/blockquote.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/ + + # Parse the blockquote at the current location. + def parse_blockquote + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(self.class::LAZY_END) + result << @src.scan(PARAGRAPH_MATCH) + end + result.gsub!(BLOCKQUOTE_START, '') + + el = new_block_el(:blockquote, nil, nil, location: start_line_number) + @tree.children << el + parse_blocks(el, result) + true + end + define_parser(:blockquote, BLOCKQUOTE_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb new file mode 100644 index 00000000..b2b76d97 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codeblock.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/paragraph' + +module Kramdown + module Parser + class Kramdown + + CODEBLOCK_START = INDENT + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/ + + # Parse the indented codeblock at the current location. + def parse_codeblock + start_line_number = @src.current_line_number + data = @src.scan(self.class::CODEBLOCK_MATCH) + data.gsub!(/\n( {0,3}\S)/, ' \\1') + data.gsub!(INDENT, '') + @tree.children << new_block_el(:codeblock, data, nil, location: start_line_number) + true + end + define_parser(:codeblock, CODEBLOCK_START) + + FENCED_CODEBLOCK_START = /^~{3,}/ + FENCED_CODEBLOCK_MATCH = /^((~){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m + + # Parse the fenced codeblock at the current location. + def parse_codeblock_fenced + if @src.check(self.class::FENCED_CODEBLOCK_MATCH) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:codeblock, @src[5], nil, location: start_line_number, fenced: true) + lang = @src[3].to_s.strip + unless lang.empty? + el.options[:lang] = lang + el.attr['class'] = "language-#{@src[4]}" + end + @tree.children << el + true + else + false + end + end + define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb new file mode 100644 index 00000000..450d1efe --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/codespan.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + CODESPAN_DELIMITER = /`+/ + + # Parse the codespan at the current scanner location. + def parse_codespan + start_line_number = @src.current_line_number + result = @src.scan(CODESPAN_DELIMITER) + simple = (result.length == 1) + saved_pos = @src.save_pos + + if simple && @src.pre_match =~ /\s\Z|\A\Z/ && @src.match?(/\s/) + add_text(result) + return + end + + # assign static regex to avoid allocating the same on every instance + # where +result+ equals a single-backtick. Interpolate otherwise. + if result == '`' + scan_pattern = /`/ + str_sub_pattern = /`\Z/ + else + scan_pattern = /#{result}/ + str_sub_pattern = /#{result}\Z/ + end + + if (text = @src.scan_until(scan_pattern)) + text.sub!(str_sub_pattern, '') + unless simple + text = text[1..-1] if text[0..0] == ' ' + text = text[0..-2] if text[-1..-1] == ' ' + end + @tree.children << Element.new(:codespan, text, nil, { + codespan_delimiter: result, + location: start_line_number, + }) + + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:codespan, CODESPAN_DELIMITER, '`') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb new file mode 100644 index 00000000..bedeaa05 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/emphasis.rb @@ -0,0 +1,66 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EMPHASIS_START = /(?:\*\*?|__?)/ + + # Parse the emphasis at the current location. + def parse_emphasis + start_line_number = @src.current_line_number + saved_pos = @src.save_pos + + result = @src.scan(EMPHASIS_START) + element = (result.length == 2 ? :strong : :em) + type = result[0..0] + + if (type == '_' && @src.pre_match =~ /[[:alpha:]]-?[[:alpha:]]*_*\z/) || @src.check(/\s/) || + @tree.type == element || @stack.any? {|el, _| el.type == element } + add_text(result) + return + end + + warnings_pos = @warnings.size + sub_parse = lambda do |delim, elem| + el = Element.new(elem, nil, nil, location: start_line_number) + stop_re = /#{Regexp.escape(delim)}/ + found = parse_spans(el, stop_re) do + (@src.pre_match[-1, 1] !~ /\s/) && + (elem != :em || !@src.match?(/#{Regexp.escape(delim * 2)}(?!#{Regexp.escape(delim)})/)) && + (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && !el.children.empty? + end + [found, el, stop_re] + end + + found, el, stop_re = sub_parse.call(result, element) + if !found && element == :strong && @tree.type != :em + @src.revert_pos(saved_pos) + @src.pos += 1 + found, el, stop_re = sub_parse.call(type, :em) + end + if found + # Useful for implementing underlines. + el.options[:char] = type + + @src.scan(stop_re) + @tree.children << el + else + @warnings.slice!(0...warnings_pos) + @src.revert_pos(saved_pos) + @src.pos += result.length + add_text(result) + end + end + define_parser(:emphasis, EMPHASIS_START, '\*|_') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb new file mode 100644 index 00000000..f151a9a3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/eob.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EOB_MARKER = /^\^\s*?\n/ + + # Parse the EOB marker at the current location. + def parse_eob_marker + @src.pos += @src.matched_size + @tree.children << new_block_el(:eob) + true + end + define_parser(:eob_marker, EOB_MARKER) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb new file mode 100644 index 00000000..d63ada97 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/escaped_chars.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'$=-])/ + + # Parse the backslash-escaped character at the current location. + def parse_escaped_chars + @src.pos += @src.matched_size + add_text(@src[1]) + end + define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb new file mode 100644 index 00000000..3d291154 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/extensions.rb @@ -0,0 +1,214 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + IAL_CLASS_ATTR = 'class' + + # Parse the string +str+ and extract all attributes and add all found attributes to the hash + # +opts+. + def parse_attribute_list(str, opts) + return if str.strip.empty? || str.strip == ':' + attrs = str.scan(ALD_TYPE_ANY) + attrs.each do |key, sep, val, ref, id_and_or_class, _, _| + if ref + (opts[:refs] ||= []) << ref + elsif id_and_or_class + id_and_or_class.scan(ALD_TYPE_ID_OR_CLASS).each do |id_attr, class_attr| + if class_attr + opts[IAL_CLASS_ATTR] = "#{opts[IAL_CLASS_ATTR]} #{class_attr}".lstrip + else + opts['id'] = id_attr + end + end + else + val.gsub!(/\\(\}|#{sep})/, "\\1") + opts[key] = val + end + end + warning("No or invalid attributes found in IAL/ALD content: #{str}") if attrs.empty? + end + + # Update the +ial+ with the information from the inline attribute list +opts+. + def update_ial_with_ial(ial, opts) + (ial[:refs] ||= []).concat(opts[:refs]) if opts.key?(:refs) + opts.each do |k, v| + if k == IAL_CLASS_ATTR + ial[k] = "#{ial[k]} #{v}".lstrip + elsif k.kind_of?(String) + ial[k] = v + end + end + end + + # Parse the generic extension at the current point. The parameter +type+ can either be :block + # or :span depending whether we parse a block or span extension tag. + def parse_extension_start_tag(type) + saved_pos = @src.save_pos + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + error_block = lambda do |msg| + warning(msg) + @src.revert_pos(saved_pos) + add_text(@src.getch) if type == :span + false + end + + if @src[4] || @src.matched == '{:/}' + name = (@src[4] ? "for '#{@src[4]}' " : '') + return error_block.call("Invalid extension stop tag #{name} found on line " \ + "#{start_line_number} - ignoring it") + end + + ext = @src[1] + opts = {} + body = nil + parse_attribute_list(@src[2] || '', opts) + + unless @src[3] + stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/) + if (result = @src.scan_until(stop_re)) + body = result.sub!(stop_re, '') + body.chomp! if type == :block + else + return error_block.call("No stop tag for extension '#{ext}' found on line " \ + "#{start_line_number} - ignoring it") + end + end + + if handle_extension(ext, opts, body, type, start_line_number) + true + else + error_block.call("Invalid extension with name '#{ext}' specified on line " \ + "#{start_line_number} - ignoring it") + end + end + + def handle_extension(name, opts, body, type, line_no = nil) + case name + when 'comment' + if body.kind_of?(String) + @tree.children << Element.new(:comment, body, nil, category: type, location: line_no) + end + true + when 'nomarkdown' + if body.kind_of?(String) + @tree.children << Element.new(:raw, body, nil, category: type, + location: line_no, type: opts['type'].to_s.split(/\s+/)) + end + true + when 'options' + opts.select do |k, v| + k = k.to_sym + if Kramdown::Options.defined?(k) + if @options[:forbidden_inline_options].include?(k) || + k == :forbidden_inline_options + warning("Option #{k} may not be set inline") + next false + end + + begin + val = Kramdown::Options.parse(k, v) + @options[k] = val + (@root.options[:options] ||= {})[k] = val + rescue StandardError + end + false + else + true + end + end.each do |k, _v| + warning("Unknown kramdown option '#{k}'") + end + @tree.children << new_block_el(:eob, :extension) if type == :block + true + else + false + end + end + + ALD_ID_CHARS = /[\w-]/ + ALD_ANY_CHARS = /\\\}|[^}]/ + ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/ + ALD_CLASS_NAME = /[^\s.#]+/ + ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^}\2])*?)\2/ + ALD_TYPE_CLASS_NAME = /\.(#{ALD_CLASS_NAME})/ + ALD_TYPE_ID_NAME = /#([A-Za-z][\w:-]*)/ + ALD_TYPE_ID_OR_CLASS = /#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}/ + ALD_TYPE_ID_OR_CLASS_MULTI = /((?:#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME})+)/ + ALD_TYPE_REF = /(#{ALD_ID_NAME})/ + ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_REF}|#{ALD_TYPE_ID_OR_CLASS_MULTI})(?=\s|\Z)/ + ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/ + + EXT_STOP_STR = "\\{:/(%s)?\\}" + EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}" + EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/ + EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n" + + IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/ + IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/ + + BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/ + + # Parse one of the block extensions (ALD, block IAL or generic extension) at the current + # location. + def parse_block_extensions + if @src.scan(ALD_START) + parse_attribute_list(@src[2], @alds[@src[1]] ||= {}) + @tree.children << new_block_el(:eob, :ald) + true + elsif @src.check(EXT_BLOCK_START) + parse_extension_start_tag(:block) + elsif @src.scan(IAL_BLOCK_START) + if (last_child = @tree.children.last) && last_child.type != :blank && + (last_child.type != :eob || + [:link_def, :abbrev_def, :footnote_def].include?(last_child.value)) + parse_attribute_list(@src[1], last_child.options[:ial] ||= {}) + @tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START) + else + parse_attribute_list(@src[1], @block_ial ||= {}) + end + true + else + false + end + end + define_parser(:block_extensions, BLOCK_EXTENSIONS_START) + + EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/ + IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/ + SPAN_EXTENSIONS_START = /\{:/ + + # Parse the extension span at the current location. + def parse_span_extensions + if @src.check(EXT_SPAN_START) + parse_extension_start_tag(:span) + elsif @src.check(IAL_SPAN_START) + if (last_child = @tree.children.last) && last_child.type != :text + @src.pos += @src.matched_size + attr = {} + parse_attribute_list(@src[1], attr) + update_ial_with_ial(last_child.options[:ial] ||= {}, attr) + update_attr_with_ial(last_child.attr, attr) + else + warning("Found span IAL after text - ignoring it") + add_text(@src.getch) + end + else + add_text(@src.getch) + end + end + define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb new file mode 100644 index 00000000..b45fc121 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/footnote.rb @@ -0,0 +1,64 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/codeblock' + +module Kramdown + module Parser + class Kramdown + + FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/ + + # Parse the foot note definition at the current location. + def parse_footnote_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + el = Element.new(:footnote_def, nil, nil, location: start_line_number) + parse_blocks(el, @src[2].gsub(INDENT, '')) + if @footnotes[@src[1]] + warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :footnote_def) + (@footnotes[@src[1]] = {})[:content] = el + @footnotes[@src[1]][:eob] = @tree.children.last + true + end + define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START) + + FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/ + + # Parse the footnote marker at the current location. + def parse_footnote_marker + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + fn_def = @footnotes[@src[1]] + if fn_def + if fn_def[:eob] + update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {}) + fn_def[:attr] = fn_def[:eob].attr + fn_def[:options] = fn_def[:eob].options + fn_def.delete(:eob) + end + fn_def[:marker] ||= [] + fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr], + fn_def[:options].merge(name: @src[1], location: start_line_number))) + @tree.children << fn_def[:marker].last + else + warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}") + add_text(@src.matched) + end + end + define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb new file mode 100644 index 00000000..d490a464 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/header.rb @@ -0,0 +1,70 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' +require 'rexml/xmltokens' + +module Kramdown + module Parser + class Kramdown + + SETEXT_HEADER_START = /^#{OPT_SPACE}(?[^ \t].*)\n(?[-=])[-=]*[ \t\r\f\v]*\n/ + + # Parse the Setext header at the current location. + def parse_setext_header + return false unless after_block_boundary? + text, id = parse_header_contents + return false if text.empty? + add_header(@src["level"] == '-' ? 2 : 1, text, id) + true + end + define_parser(:setext_header, SETEXT_HEADER_START) + + ATX_HEADER_START = /^(?\#{1,6})[\t ]*(?[^ \t].*)\n/ + + # Parse the Atx header at the current location. + def parse_atx_header + return false unless after_block_boundary? + text, id = parse_header_contents + text.sub!(/(?#{REXML::XMLTokens::NAME_START_CHAR}#{REXML::XMLTokens::NAME_CHAR}*)}\z/ + + # Returns header text and optional ID. + def parse_header_contents + text = @src["contents"] + text.rstrip! + id_match = HEADER_ID.match(text) + if id_match + id = id_match["id"] + text = text[0...-id_match[0].length] + text.rstrip! + end + [text, id] + end + + def add_header(level, text, id) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:header, nil, nil, level: level, raw_text: text, location: start_line_number) + add_text(text, el) + el.attr['id'] = id if id + @tree.children << el + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb new file mode 100644 index 00000000..73a936dc --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/horizontal_rule.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + HR_START = /^#{OPT_SPACE}(\*|-|_)[ \t]*\1[ \t]*\1(\1|[ \t])*\n/ + + # Parse the horizontal rule at the current location. + def parse_horizontal_rule + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << new_block_el(:hr, nil, nil, location: start_line_number) + true + end + define_parser(:horizontal_rule, HR_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb new file mode 100644 index 00000000..c0fcd1ac --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html.rb @@ -0,0 +1,165 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + include Kramdown::Parser::Html::Parser + include Kramdown::Utils::Html + + # Mapping of markdown attribute value to content model. I.e. :raw when "0", :default when "1" + # (use default content model for the HTML element), :span when "span", :block when block and + # for everything else +nil+ is returned. + HTML_MARKDOWN_ATTR_MAP = {"0" => :raw, "1" => :default, "span" => :span, "block" => :block} + + TRAILING_WHITESPACE = /[ \t]*\n/ + + def handle_kramdown_html_tag(el, closed, handle_body) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + + content_model = if @tree.type != :html_element || @tree.options[:content_model] != :raw + (@options[:parse_block_html] ? HTML_CONTENT_MODEL[el.value] : :raw) + else + :raw + end + if (val = HTML_MARKDOWN_ATTR_MAP[el.attr.delete('markdown')]) + content_model = (val == :default ? HTML_CONTENT_MODEL[el.value] : val) + end + + @src.scan(TRAILING_WHITESPACE) if content_model == :block + el.options[:content_model] = content_model + el.options[:is_closed] = closed + + if !closed && handle_body + case content_model + when :block + unless parse_blocks(el) + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + when :span + curpos = @src.pos + if @src.scan_until(/(?=<\/#{el.value}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), el) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, el) + @src.terminate + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + else + parse_raw_html(el) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + end + unless @tree.type == :html_element && @tree.options[:content_model] == :raw + @src.scan(TRAILING_WHITESPACE) + end + end + end + + HTML_BLOCK_START = /^#{OPT_SPACE}<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/)/ + + # Parse the HTML at the current position as block-level HTML. + def parse_block_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + @src.scan(TRAILING_WHITESPACE) + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + @src.pos += @src.matched_size + handle_html_start_tag(line) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + Kramdown::Parser::Html::ElementConverter.convert(@root, @tree.children.last) if @options[:html_to_native] + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + name = @src[1].downcase + + if @tree.type == :html_element && @tree.value == name + @src.pos += @src.matched_size + throw :stop_block_parsing, :found + else + false + end + else + false + end + end + define_parser(:block_html, HTML_BLOCK_START) + + HTML_SPAN_START = /<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/|!\[CDATA\[)/ + + # Parse the HTML at the current position as span-level HTML. + def parse_span_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :span, location: line) + elsif @src.scan(HTML_CDATA_RE) + add_text(escape_html(@src[1])) + elsif (result = @src.scan(HTML_TAG_CLOSE_RE)) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on line #{line}") + add_text(result) + elsif (result = @src.scan(HTML_TAG_RE)) + tag_name = @src[1] + tag_name.downcase! if HTML_ELEMENT[tag_name.downcase] + if HTML_BLOCK_ELEMENTS.include?(tag_name) + warning("Found block HTML tag '#{tag_name}' in span-level text on line #{line}") + add_text(result) + return + end + + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[tag_name]) + attrs.each_value {|value| value.gsub!(/\n+/, ' ') unless value.empty? } + + do_parsing = if HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw + false + else + @options[:parse_span_html] + end + if (val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')]) + case val + when :block + warning("Cannot use block-level parsing in span-level HTML tag (line #{line}) " \ + "- using default mode") + when :span + do_parsing = true + when :default + do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw + when :raw + do_parsing = false + end + end + + el = Element.new(:html_element, tag_name, attrs, category: :span, location: line, + content_model: (do_parsing ? :span : :raw), is_closed: !@src[4].nil?) + @tree.children << el + stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/ + stop_re = Regexp.new(stop_re.source, Regexp::IGNORECASE) if HTML_ELEMENT[tag_name] + if !@src[4] && !HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html])) + @src.scan(stop_re) + else + warning("Found no end tag for '#{el.value}' (line #{line}) - auto-closing it") + add_text(@src.rest, el) + @src.terminate + end + end + Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native] + else + add_text(@src.getch) + end + end + define_parser(:span_html, HTML_SPAN_START, '<') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb new file mode 100644 index 00000000..9852df7e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/html_entity.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + # Parse the HTML entity at the current location. + def parse_html_entity + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + begin + value = ::Kramdown::Utils::Entities.entity(@src[1] || @src[2]&.to_i || @src[3].hex) + @tree.children << Element.new(:entity, value, + nil, original: @src.matched, location: start_line_number) + rescue ::Kramdown::Error + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'), + nil, location: start_line_number) + add_text(@src.matched[1..-1]) + end + end + define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb new file mode 100644 index 00000000..5f854271 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/line_break.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + LINE_BREAK = /( |\\\\)(?=\n)/ + + # Parse the line break at the current location. + def parse_line_break + @tree.children << Element.new(:br, nil, nil, location: @src.current_line_number) + @src.pos += @src.matched_size + end + define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb new file mode 100644 index 00000000..e4c0935b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/link.rb @@ -0,0 +1,149 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/escaped_chars' + +module Kramdown + module Parser + class Kramdown + + # Normalize the link identifier. + def normalize_link_id(id) + id.gsub(/\s+/, ' ').downcase + end + + LINK_DEFINITION_START = /^#{OPT_SPACE}\[([^\n\]]+)\]:[ \t]*(?:<(.*?)>|([^\n]*?\S[^\n]*?))(?:(?:[ \t]*?\n|[ \t]+?)[ \t]*?(["'])(.+?)\4)?[ \t]*?\n/ + + # Parse the link definition at the current location. + def parse_link_definition + return false if @src[3].to_s.match?(/[ \t]+["']/) + @src.pos += @src.matched_size + link_id, link_url, link_title = normalize_link_id(@src[1]), @src[2] || @src[3], @src[5] + if @link_defs[link_id] + warning("Duplicate link ID '#{link_id}' on line #{@src.current_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :link_def) + @link_defs[link_id] = [link_url, link_title, @tree.children.last] + true + end + define_parser(:link_definition, LINK_DEFINITION_START) + + # This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+ + # and the element itself to the @tree. + def add_link(el, href, title, alt_text = nil, ial = nil) + el.options[:ial] = ial + update_attr_with_ial(el.attr, ial) if ial + if el.type == :a + el.attr['href'] = href + else + el.attr['src'] = href + el.attr['alt'] = alt_text + el.children.clear + end + el.attr['title'] = title if title + @tree.children << el + end + + LINK_BRACKET_STOP_RE = /(\])|!?\[/ + LINK_PAREN_STOP_RE = /(\()|(\))|\s(?=['"])/ + LINK_INLINE_ID_RE = /\s*?\[([^\]]+)?\]/ + LINK_INLINE_TITLE_RE = /\s*?(["'])(.+?)\1\s*?\)/m + LINK_START = /!?\[(?=[^^])/ + + # Parse the link at the current scanner position. This method is used to parse normal links as + # well as image links. + def parse_link + start_line_number = @src.current_line_number + result = @src.scan(LINK_START) + cur_pos = @src.pos + saved_pos = @src.save_pos + + link_type = (result.match?(/^!/) ? :img : :a) + + # no nested links allowed + if link_type == :a && (@tree.type == :img || @tree.type == :a || + @stack.any? {|t, _| t && (t.type == :img || t.type == :a) }) + add_text(result) + return + end + el = Element.new(link_type, nil, nil, location: start_line_number) + + count = 1 + found = parse_spans(el, LINK_BRACKET_STOP_RE) do + count += (@src[1] ? -1 : 1) + count - el.children.count {|c| c.type == :img } == 0 + end + unless found + @src.revert_pos(saved_pos) + add_text(result) + return + end + alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1') + @src.scan(LINK_BRACKET_STOP_RE) + + # reference style link or no link url + if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/) + emit_warning = !@src[1] + link_id = normalize_link_id(@src[1] || alt_text) + if @link_defs.key?(link_id) + link_def = @link_defs[link_id] + add_link(el, link_def[0], link_def[1], alt_text, + link_def[2] && link_def[2].options[:ial]) + else + if emit_warning + warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}") + end + @src.revert_pos(saved_pos) + add_text(result) + end + return + end + + # link url in parentheses + if @src.scan(/\(<(.*?)>/) + link_url = @src[1] + if @src.scan(/\)/) + add_link(el, link_url, nil, alt_text) + return + end + else + link_url = +'' + nr_of_brackets = 0 + while (temp = @src.scan_until(LINK_PAREN_STOP_RE)) + link_url << temp + if @src[2] + nr_of_brackets -= 1 + break if nr_of_brackets == 0 + elsif @src[1] + nr_of_brackets += 1 + else + break + end + end + link_url = link_url[1..-2] + link_url.strip! + + if nr_of_brackets == 0 + add_link(el, link_url, nil, alt_text) + return + end + end + + if @src.scan(LINK_INLINE_TITLE_RE) + add_link(el, link_url, @src[2], alt_text) + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:link, LINK_START, '!?\[') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb new file mode 100644 index 00000000..4cf9d3f2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/list.rb @@ -0,0 +1,286 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/horizontal_rule' +require 'kramdown/parser/kramdown/extensions' + +module Kramdown + module Parser + class Kramdown + + LIST_ITEM_IAL = /^\s*(?:\{:(?!(?:#{ALD_ID_NAME})?:|\/)(#{ALD_ANY_CHARS}+)\})\s*/ + LIST_ITEM_IAL_CHECK = /^#{LIST_ITEM_IAL}?\s*\n/ + + PARSE_FIRST_LIST_LINE_REGEXP_CACHE = Hash.new do |h, indentation| + indent_re = /^ {#{indentation}}/ + content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/ + lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/ + + h[indentation] = [content_re, lazy_re, indent_re] + end + + # Used for parsing the first line of a list item or a definition, i.e. the line with list item + # marker or the definition marker. + def parse_first_list_line(indentation, content) + if content.match?(self.class::LIST_ITEM_IAL_CHECK) + indentation = 4 + else + while content.match?(/^ *\t/) + temp = content.scan(/^ */).first.length + indentation + content.sub!(/^( *)(\t+)/) { $1 << " " * (4 - (temp % 4) + ($2.length - 1) * 4) } + end + indentation += content[/^ */].length + end + content.sub!(/^\s*/, '') + + [content, indentation, *PARSE_FIRST_LIST_LINE_REGEXP_CACHE[indentation]] + end + + PATTERN_TAIL = /[\t| ].*?\n/ + + LIST_START_UL = /^(#{OPT_SPACE}[+*-])(#{PATTERN_TAIL})/ + LIST_START_OL = /^(#{OPT_SPACE}\d+\.)(#{PATTERN_TAIL})/ + LIST_START = /#{LIST_START_UL}|#{LIST_START_OL}/ + + # Parse the ordered or unordered list at the current location. + def parse_list + start_line_number = @src.current_line_number + type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL]) + list = new_block_el(type, nil, nil, location: start_line_number) + + item = nil + content_re, lazy_re, indent_re = nil + eob_found = false + nested_list_found = false + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if last_is_blank && @src.check(HR_START) + break + elsif @src.scan(EOB_MARKER) + eob_found = true + break + elsif @src.scan(list_start_re) + list.options[:first_list_marker] ||= @src[1].strip + item = Element.new(:li, nil, nil, location: start_line_number) + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + list.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + list_start_re = fetch_pattern(type, indentation) + nested_list_found = (item.value =~ LIST_START) + last_is_blank = false + item.value = [item.value] + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * 4 * $1.length } + indentation_found = result.sub!(indent_re, '') + if !nested_list_found && indentation_found && result =~ LIST_START + item.value << +'' + nested_list_found = true + elsif nested_list_found && !indentation_found && result =~ LIST_START + result = " " * (indentation + 4) << result + end + item.value.last << result + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + nested_list_found = true + last_is_blank = true + item.value.last << result + else + break + end + end + + @tree.children << list + + last = nil + list.children.each do |it| + temp = Element.new(:temp, nil, nil, location: it.options[:location]) + + env = save_env + location = it.options[:location] + it.value.each do |val| + @src = ::Kramdown::Utils::StringScanner.new(val, location) + parse_blocks(temp) + location = @src.current_line_number + end + restore_env(env) + + it.children = temp.children + it.value = nil + + it_children = it.children + next if it_children.empty? + + # Handle the case where an EOB marker is inserted by a block IAL for the first paragraph + it_children.delete_at(1) if it_children.first.type == :p && + it_children.length >= 2 && it_children[1].type == :eob && it_children.first.options[:ial] + + if it_children.first.type == :p && + (it_children.length < 2 || it_children[1].type != :blank || + (it == list.children.last && it_children.length == 2 && !eob_found)) && + (list.children.last != it || list.children.size == 1 || + list.children[0..-2].any? {|cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] }) + it_children.first.children.first.value << "\n" if it_children.size > 1 && it_children[1].type != :blank + it_children.first.options[:transparent] = true + end + + last = (it_children.last.type == :blank ? it_children.pop : nil) + end + + @tree.children << last if !last.nil? && !eob_found + + true + end + define_parser(:list, LIST_START) + + DEFINITION_LIST_START = /^(#{OPT_SPACE}:)(#{PATTERN_TAIL})/ + + # Parse the ordered or unordered list at the current location. + def parse_definition_list + children = @tree.children + if !children.last || (children.length == 1 && children.last.type != :p) || + (children.length >= 2 && children[-1].type != :p && + (children[-1].type != :blank || children[-1].value != "\n" || children[-2].type != :p)) + return false + end + + first_as_para = false + deflist = new_block_el(:dl) + para = @tree.children.pop + if para.type == :blank + para = @tree.children.pop + first_as_para = true + end + # take location from preceding para which is the first definition term + deflist.options[:location] = para.options[:location] + para.children.first.value.split("\n").each do |term| + el = Element.new(:dt, nil, nil, location: @src.current_line_number) + term.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, el.options[:ial] ||= {}) + '' + end + el.options[:raw_text] = term + el.children << Element.new(:raw_text, term) + deflist.children << el + end + deflist.options[:ial] = para.options[:ial] + + item = nil + content_re, lazy_re, indent_re = nil + def_start_re = DEFINITION_LIST_START + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if @src.scan(def_start_re) + item = Element.new(:dd, nil, nil, location: start_line_number) + item.options[:first_as_para] = first_as_para + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + deflist.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do |_match| + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + def_start_re = fetch_pattern(:dl, indentation) + first_as_para = false + last_is_blank = false + elsif @src.check(EOB_MARKER) + break + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * ($1 ? 4 * $1.length : 0) } + result.sub!(indent_re, '') + item.value << result + first_as_para = false + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + first_as_para = true + item.value << result + last_is_blank = true + else + break + end + end + + last = nil + deflist.children.each do |it| + next if it.type == :dt + + parse_blocks(it, it.value) + it.value = nil + it_children = it.children + next if it_children.empty? + + last = (it_children.last.type == :blank ? it_children.pop : nil) + + if it_children.first && it_children.first.type == :p && !it.options.delete(:first_as_para) + it_children.first.children.first.value << "\n" if it_children.size > 1 + it_children.first.options[:transparent] = true + end + end + + children = @tree.children + if children.length >= 1 && children.last.type == :dl + children[-1].children.concat(deflist.children) + elsif children.length >= 2 && children[-1].type == :blank && + children[-2].type == :dl + children.pop + children[-1].children.concat(deflist.children) + else + children << deflist + end + + children << last if last + + true + end + define_parser(:definition_list, DEFINITION_LIST_START) + + private + + # precomputed patterns for indentations 1..4 and fallback expression + # to compute pattern when indentation is outside the 1..4 range. + def fetch_pattern(type, indentation) + case type + when :ul + case indentation + when 1 then /^( {0}[+*-])(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}[+*-])(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}[+*-])(#{PATTERN_TAIL})/o + else /^( {0,3}[+*-])(#{PATTERN_TAIL})/o + end + when :ol + case indentation + when 1 then /^( {0}\d+\.)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}\d+\.)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}\d+\.)(#{PATTERN_TAIL})/o + else /^( {0,3}\d+\.)(#{PATTERN_TAIL})/o + end + when :dl + case indentation + when 1 then /^( {0}:)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}:)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}:)(#{PATTERN_TAIL})/o + else /^( {0,3}:)(#{PATTERN_TAIL})/o + end + end + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb new file mode 100644 index 00000000..32c87bfc --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/math.rb @@ -0,0 +1,53 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + BLOCK_MATH_START = /^#{OPT_SPACE}(\\)?\$\$(.*?)\$\$(\s*?\n)?/m + + # Parse the math block at the current location. + def parse_block_math + start_line_number = @src.current_line_number + if !after_block_boundary? + return false + elsif @src[1] + @src.scan(/^#{OPT_SPACE}\\/o) if @src[3] + return false + end + + saved_pos = @src.save_pos + @src.pos += @src.matched_size + data = @src[2].strip + if before_block_boundary? + @tree.children << new_block_el(:math, data, nil, category: :block, location: start_line_number) + true + else + @src.revert_pos(saved_pos) + false + end + end + define_parser(:block_math, BLOCK_MATH_START) + + INLINE_MATH_START = /\$\$(.*?)\$\$/m + + # Parse the inline math at the current location. + def parse_inline_math + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << Element.new(:math, @src[1].strip, nil, category: :span, location: start_line_number) + end + define_parser(:inline_math, INLINE_MATH_START, '\$') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb new file mode 100644 index 00000000..d89e6a24 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/paragraph.rb @@ -0,0 +1,62 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/list' +require 'kramdown/parser/kramdown/html' + +module Kramdown + module Parser + class Kramdown + + LAZY_END_HTML_SPAN_ELEMENTS = HTML_SPAN_ELEMENTS + %w[script] + LAZY_END_HTML_START = /<(?>(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR})/ + LAZY_END_HTML_STOP = /<\/(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR}\s*>/m + + LAZY_END = /#{BLANK_LINE}|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/ + + PARAGRAPH_START = /^#{OPT_SPACE}[^ \t].*?\n/ + PARAGRAPH_MATCH = /^.*?\n/ + PARAGRAPH_END = /#{LAZY_END}|#{DEFINITION_LIST_START}/ + + # Parse the paragraph at the current location. + def parse_paragraph + pos = @src.pos + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(paragraph_end) + result << @src.scan(PARAGRAPH_MATCH) + end + result.rstrip! + if (last_child = @tree.children.last) && last_child.type == :p + last_item_in_para = last_child.children.last + if last_item_in_para && last_item_in_para.type == @text_type + joiner = (extract_string((pos - 3)...pos, @src) == " \n" ? " \n" : "\n") + last_item_in_para.value << joiner << result + else + add_text(result, last_child) + end + else + @tree.children << new_block_el(:p, nil, nil, location: start_line_number) + result.lstrip! + add_text(result, @tree.children.last) + end + true + end + define_parser(:paragraph, PARAGRAPH_START) + + def paragraph_end + self.class::PARAGRAPH_END + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb new file mode 100644 index 00000000..c0a6aaa0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/smart_quotes.rb @@ -0,0 +1,174 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +#-- +# Parts of this file are based on code from RubyPants: +# +# = RubyPants -- SmartyPants ported to Ruby +# +# Ported by Christian Neukirchen +# Copyright (C) 2004 Christian Neukirchen +# +# Incooporates ideas, comments and documentation by Chad Miller +# Copyright (C) 2004 Chad Miller +# +# Original SmartyPants by John Gruber +# Copyright (C) 2003 John Gruber +# +# +# = RubyPants -- SmartyPants ported to Ruby +# +# +# [snip] +# +# == Authors +# +# John Gruber did all of the hard work of writing this software in +# Perl for Movable Type and almost all of this useful documentation. +# Chad Miller ported it to Python to use with Pyblosxom. +# +# Christian Neukirchen provided the Ruby port, as a general-purpose +# library that follows the *Cloth API. +# +# +# == Copyright and License +# +# === SmartyPants license: +# +# Copyright (c) 2003 John Gruber +# (http://daringfireball.net) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name "SmartyPants" nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# === RubyPants license +# +# RubyPants is a derivative work of SmartyPants and smartypants.py. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# == Links +# +# John Gruber:: http://daringfireball.net +# SmartyPants:: http://daringfireball.net/projects/smartypants +# +# Chad Miller:: http://web.chad.org +# +# Christian Neukirchen:: http://kronavita.de/chris +# +#++ +# + +module Kramdown + module Parser + class Kramdown + + SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]' + SQ_CLOSE = %![^ \\\\\t\r\n\\[{(-]! + + SQ_RULES = [ + [/("|')(?=[_*]{1,2}\S)/, [:lquote1]], + [/("|')(?=#{SQ_PUNCT}(?!\.\.)\B)/, [:rquote1]], + # Special case for double sets of quotes, e.g.: + #

He said, "'Quoted' words in a larger quote."

+ [/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]], + [/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]], + # Special case for decade abbreviations (the '80s): + [/(\s?)'(?=\d\ds)/, [1, :rsquo]], + + # Get most opening single/double quotes: + [/(\s)('|")(?=\w)/, [1, :lquote2]], + # Single/double closing quotes: + [/(#{SQ_CLOSE})('|")/, [1, :rquote2]], + # Special case for e.g. "Custer's Last Stand." + [/("|')(?=\s|s\b|$)/, [:rquote1]], + # Any remaining single quotes should be opening ones: + [/(.?)'/m, [1, :lsquo]], + [/(.?)"/m, [1, :ldquo]], + ] # '" + + SQ_SUBSTS = { + [:rquote1, '"'] => :rdquo, + [:rquote1, "'"] => :rsquo, + [:rquote2, '"'] => :rdquo, + [:rquote2, "'"] => :rsquo, + [:lquote1, '"'] => :ldquo, + [:lquote1, "'"] => :lsquo, + [:lquote2, '"'] => :ldquo, + [:lquote2, "'"] => :lsquo, + } + SMART_QUOTES_RE = /[^\\]?["']/ + + # Parse the smart quotes at current location. + def parse_smart_quotes + start_line_number = @src.current_line_number + substs = SQ_RULES.find {|reg, _subst| @src.scan(reg) }[1] + substs.each do |subst| + if subst.kind_of?(Integer) + add_text(@src[subst]) + else + val = SQ_SUBSTS[[subst, @src[subst.to_s[-1, 1].to_i]]] || subst + @tree.children << Element.new(:smart_quote, val, nil, location: start_line_number) + end + end + end + define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb new file mode 100644 index 00000000..68be6b4c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/table.rb @@ -0,0 +1,171 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + TABLE_SEP_LINE = /^([+|: \t-]*?-[+|: \t-]*?)[ \t]*\n/ + TABLE_HSEP_ALIGN = /[ \t]?(:?)-+(:?)[ \t]?/ + TABLE_FSEP_LINE = /^[+|: \t=]*?=[+|: \t=]*?[ \t]*\n/ + TABLE_ROW_LINE = /^(.*?)[ \t]*\n/ + TABLE_PIPE_CHECK = /(?:\||.*?[^\\\n]\|)/ + TABLE_LINE = /#{TABLE_PIPE_CHECK}.*?\n/ + TABLE_START = /^#{OPT_SPACE}(?=\S)#{TABLE_LINE}/ + + # Parse the table at the current location. + def parse_table + return false unless after_block_boundary? + + saved_pos = @src.save_pos + orig_pos = @src.pos + table = new_block_el(:table, nil, nil, alignment: [], location: @src.current_line_number) + leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/) + @src.scan(TABLE_SEP_LINE) + + rows = [] + has_footer = false + columns = 0 + + add_container = lambda do |type, force| + if !has_footer || type != :tbody || force + cont = Element.new(type) + cont.children, rows = rows, [] + table.children << cont + end + end + + until @src.eos? + break unless @src.check(TABLE_LINE) + if @src.scan(TABLE_SEP_LINE) + if rows.empty? + # nothing to do, ignoring multiple consecutive separator lines + elsif table.options[:alignment].empty? && !has_footer + add_container.call(:thead, false) + table.options[:alignment] = @src[1].scan(TABLE_HSEP_ALIGN).map do |left, right| + (left.empty? && right.empty? && :default) || (right.empty? && :left) || + (left.empty? && :right) || :center + end + else # treat as normal separator line + add_container.call(:tbody, false) + end + elsif @src.scan(TABLE_FSEP_LINE) + add_container.call(:tbody, true) unless rows.empty? + has_footer = true + elsif @src.scan(TABLE_ROW_LINE) + trow = Element.new(:tr) + + # parse possible code spans on the line and correctly split the line into cells + env = save_env + cells = [] + @src[1].split(/(.*?<\/code>)/).each_with_index do |str, i| + if i.odd? + (cells.empty? ? cells : cells.last) << str + else + reset_env(src: Kramdown::Utils::StringScanner.new(str, @src.current_line_number)) + root = Element.new(:root) + parse_spans(root, nil, [:codespan]) + + root.children.each do |c| + if c.type == :raw_text + f, *l = c.value.split(/(? 1}#{c.value}#{' ' if delim.size > 1}#{delim}" + (cells.empty? ? cells : cells.last) << tmp + end + end + end + end + restore_env(env) + + cells.shift if leading_pipe && cells.first.strip.empty? + cells.pop if cells.last.strip.empty? + cells.each do |cell_text| + tcell = Element.new(:td) + tcell.children << Element.new(:raw_text, cell_text.strip) + trow.children << tcell + end + columns = [columns, cells.length].max + rows << trow + else + break + end + end + + unless before_block_boundary? + @src.revert_pos(saved_pos) + return false + end + + # Parse all lines of the table with the code span parser + env = save_env + l_src = ::Kramdown::Utils::StringScanner.new(extract_string(orig_pos...(@src.pos - 1), @src), + @src.current_line_number) + reset_env(src: l_src) + root = Element.new(:root) + parse_spans(root, nil, [:codespan, :span_html]) + restore_env(env) + + # Check if each line has at least one unescaped pipe that is not inside a code span/code + # HTML element + # Note: It doesn't matter that we parse *all* span HTML elements because the row splitting + # algorithm above only takes elements into account! + pipe_on_line = false + while (c = root.children.shift) + next unless (lines = c.value) + lines = lines.split("\n") + if c.type == :codespan + if lines.size > 2 || (lines.size == 2 && !pipe_on_line) + break + elsif lines.size == 2 && pipe_on_line + pipe_on_line = false + end + else + break if lines.size > 1 && !pipe_on_line && lines.first !~ /^#{TABLE_PIPE_CHECK}/o + pipe_on_line = (lines.size > 1 ? false : pipe_on_line) || (lines.last =~ /^#{TABLE_PIPE_CHECK}/o) + end + end + @src.revert_pos(saved_pos) and return false unless pipe_on_line + + add_container.call(has_footer ? :tfoot : :tbody, false) unless rows.empty? + + if table.children.none? {|el| el.type == :tbody } + warning("Found table without body on line #{table.options[:location]} - ignoring it") + @src.revert_pos(saved_pos) + return false + end + + # adjust all table rows to have equal number of columns, same for alignment defs + table.children.each do |kind| + kind.children.each do |row| + (columns - row.children.length).times do + row.children << Element.new(:td) + end + end + end + if table.options[:alignment].length > columns + table.options[:alignment] = table.options[:alignment][0...columns] + else + table.options[:alignment] += [:default] * (columns - table.options[:alignment].length) + end + + @tree.children << table + + true + end + define_parser(:table, TABLE_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb new file mode 100644 index 00000000..095c8d53 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/kramdown/typographic_symbol.rb @@ -0,0 +1,44 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + TYPOGRAPHIC_SYMS = [['---', :mdash], ['--', :ndash], ['...', :hellip], + ['\\<<', '<<'], ['\\>>', '>>'], + ['<< ', :laquo_space], [' >>', :raquo_space], + ['<<', :laquo], ['>>', :raquo]] + TYPOGRAPHIC_SYMS_SUBST = Hash[*TYPOGRAPHIC_SYMS.flatten] + TYPOGRAPHIC_SYMS_RE = /#{TYPOGRAPHIC_SYMS.map {|k, _v| Regexp.escape(k) }.join('|')}/ + + # Parse the typographic symbols at the current location. + def parse_typographic_syms + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + val = TYPOGRAPHIC_SYMS_SUBST[@src.matched] + if val.kind_of?(Symbol) + @tree.children << Element.new(:typographic_sym, val, nil, location: start_line_number) + elsif @src.matched == '\\<<' + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + else + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + end + end + define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE, '--|\\.\\.\\.|(?:\\\\| )?(?:<<|>>)') + + end + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb new file mode 100644 index 00000000..9f36758a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/parser/markdown.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing a document in Markdown format. + # + # This parser is based on the kramdown parser and removes the parser methods for the additional + # non-Markdown features. However, since some things are handled differently by the kramdown + # parser methods (like deciding when a list item contains just text), this parser differs from + # real Markdown parsers in some respects. + # + # Note, though, that the parser basically fails just one of the Markdown test cases (some others + # also fail but those failures are negligible). + class Markdown < Kramdown + + # Array with all the parsing methods that should be removed from the standard kramdown parser. + EXTENDED = [:codeblock_fenced, :table, :definition_list, :footnote_definition, + :abbrev_definition, :block_math, :block_extensions, + :footnote_marker, :smart_quotes, :inline_math, :span_extensions, :typographic_syms] + + def initialize(source, options) # :nodoc: + super + @block_parsers.delete_if {|i| EXTENDED.include?(i) } + @span_parsers.delete_if {|i| EXTENDED.include?(i) } + end + + # :stopdoc: + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|\Z/ + LAZY_END = /#{BLANK_LINE}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}| + ^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/x + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+)*/ + PARAGRAPH_END = LAZY_END + + IAL_RAND_CHARS = (('a'..'z').to_a + ('0'..'9').to_a) + IAL_RAND_STRING = (1..20).collect { IAL_RAND_CHARS[rand(IAL_RAND_CHARS.size)] }.join + LIST_ITEM_IAL = /^\s*(#{IAL_RAND_STRING})?\s*\n/ + IAL_SPAN_START = LIST_ITEM_IAL + + # :startdoc: + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils.rb new file mode 100644 index 00000000..5928def6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # == \Utils Module + # + # This module contains utility class/modules/methods that can be used by both parsers and + # converters. + module Utils + + autoload :Entities, 'kramdown/utils/entities' + autoload :Html, 'kramdown/utils/html' + autoload :Unidecoder, 'kramdown/utils/unidecoder' + autoload :StringScanner, 'kramdown/utils/string_scanner' + autoload :Configurable, 'kramdown/utils/configurable' + autoload :LRUCache, 'kramdown/utils/lru_cache' + + # Treat +name+ as if it were snake cased (e.g. snake_case) and camelize it (e.g. SnakeCase). + def self.camelize(name) + name.split('_').inject(+'') {|s, x| s << x[0..0].upcase << x[1..-1] } + end + + # Treat +name+ as if it were camelized (e.g. CamelizedName) and snake-case it (e.g. camelized_name). + def self.snake_case(name) + name = name.dup + name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + name.gsub!(/([a-z])([A-Z])/, '\1_\2') + name.downcase! + name + end + + def self.deep_const_get(str) + ::Object.const_get(str) + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb new file mode 100644 index 00000000..2989493f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/configurable.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # Methods for registering configurable extensions. + module Configurable + + # Create a new configurable extension called +name+. + # + # Three methods will be defined on the calling object which allow to use this configurable + # extension: + # + # configurables:: Returns a hash of hashes that is used to store all configurables of the + # object. + # + # (ext_name):: Return the configured extension +ext_name+. + # + # add_(ext_name, data=nil, &block):: Define an extension +ext_name+ by specifying either + # the data as argument or by using a block. + def configurable(name) + unless respond_to?(:configurables) + singleton_class.send(:define_method, :configurables) do + @_configurables ||= Hash.new {|h, k| h[k] = {} } + end + end + singleton_class.send(:define_method, name) do |data| + configurables[name][data] + end + singleton_class.send(:define_method, "add_#{name}".intern) do |data, *args, &block| + configurables[name][data] = args.first || block + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb new file mode 100644 index 00000000..156dd76f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/entities.rb @@ -0,0 +1,1000 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + module Utils + + # Provides convenience methods for handling named and numeric entities. + module Entities + + # Represents an entity that has a +code_point+ and +name+. + Entity = Struct.new(:code_point, :name) do + # Return the UTF8 representation of the entity. + def char + [code_point].pack('U*') rescue nil + end + end + + # Array of arrays. Each sub-array specifies a code point and the associated name. + # + # This table is not used directly -- Entity objects are automatically created from it and put + # into a Hash map when this file is loaded. + ENTITY_TABLE = [ + + # html4 + [913, 'Alpha'], + [914, 'Beta'], + [915, 'Gamma'], + [916, 'Delta'], + [917, 'Epsilon'], + [918, 'Zeta'], + [919, 'Eta'], + [920, 'Theta'], + [921, 'Iota'], + [922, 'Kappa'], + [923, 'Lambda'], + [924, 'Mu'], + [925, 'Nu'], + [926, 'Xi'], + [927, 'Omicron'], + [928, 'Pi'], + [929, 'Rho'], + [931, 'Sigma'], + [932, 'Tau'], + [933, 'Upsilon'], + [934, 'Phi'], + [935, 'Chi'], + [936, 'Psi'], + [937, 'Omega'], + [945, 'alpha'], + [946, 'beta'], + [947, 'gamma'], + [948, 'delta'], + [949, 'epsilon'], + [950, 'zeta'], + [951, 'eta'], + [952, 'theta'], + [953, 'iota'], + [954, 'kappa'], + [955, 'lambda'], + [956, 'mu'], + [957, 'nu'], + [958, 'xi'], + [959, 'omicron'], + [960, 'pi'], + [961, 'rho'], + [963, 'sigma'], + [964, 'tau'], + [965, 'upsilon'], + [966, 'phi'], + [967, 'chi'], + [968, 'psi'], + [969, 'omega'], + [962, 'sigmaf'], + [977, 'thetasym'], + [978, 'upsih'], + [982, 'piv'], + [988, 'Gammad'], + [989, 'gammad'], + [8204, 'zwnj'], + [8205, 'zwj'], + [8206, 'lrm'], + [8207, 'rlm'], + [8230, 'hellip'], + [8242, 'prime'], + [8243, 'Prime'], + [8254, 'oline'], + [8260, 'frasl'], + [8472, 'weierp'], + [8465, 'image'], + [8476, 'real'], + [8501, 'alefsym'], + [8226, 'bull'], + [8482, 'trade'], + [8592, 'larr'], + [8594, 'rarr'], + [8593, 'uarr'], + [8595, 'darr'], + [8596, 'harr'], + [8629, 'crarr'], + [8657, 'uArr'], + [8659, 'dArr'], + [8656, 'lArr'], + [8658, 'rArr'], + [8660, 'hArr'], + [8704, 'forall'], + [8706, 'part'], + [8707, 'exist'], + [8709, 'empty'], + [8711, 'nabla'], + [8712, 'isin'], + [8715, 'ni'], + [8713, 'notin'], + [8721, 'sum'], + [8719, 'prod'], + [8722, 'minus'], + [8727, 'lowast'], + [8730, 'radic'], + [8733, 'prop'], + [8734, 'infin'], + [8736, 'ang'], + [8743, 'and'], + [8744, 'or'], + [8745, 'cap'], + [8746, 'cup'], + [8747, 'int'], + [8756, 'there4'], + [8764, 'sim'], + [8776, 'asymp'], + [8773, 'cong'], + [8800, 'ne'], + [8801, 'equiv'], + [8804, 'le'], + [8805, 'ge'], + [8834, 'sub'], + [8835, 'sup'], + [8838, 'sube'], + [8839, 'supe'], + [8836, 'nsub'], + [8853, 'oplus'], + [8855, 'otimes'], + [8869, 'perp'], + [8901, 'sdot'], + [8942, 'vellip'], + [8968, 'rceil'], + [8969, 'lceil'], + [8970, 'lfloor'], + [8971, 'rfloor'], + [9001, 'rang'], + [9002, 'lang'], + [9674, 'loz'], + [9824, 'spades'], + [9827, 'clubs'], + [9829, 'hearts'], + [9830, 'diams'], + [38, 'amp'], + [34, 'quot'], + [39, 'apos'], + [169, 'copy'], + [60, 'lt'], + [62, 'gt'], + [338, 'OElig'], + [339, 'oelig'], + [352, 'Scaron'], + [353, 'scaron'], + [376, 'Yuml'], + [710, 'circ'], + [732, 'tilde'], + [8211, 'ndash'], + [8212, 'mdash'], + [8216, 'lsquo'], + [8217, 'rsquo'], + [8220, 'ldquo'], + [8221, 'rdquo'], + [8224, 'dagger'], + [8225, 'Dagger'], + [8240, 'permil'], + [8364, 'euro'], + [8249, 'lsaquo'], + [8250, 'rsaquo'], + [160, 'nbsp'], + [161, 'iexcl'], + [163, 'pound'], + [164, 'curren'], + [165, 'yen'], + [166, 'brvbar'], + [167, 'sect'], + [168, 'uml'], + [171, 'laquo'], + [187, 'raquo'], + [174, 'reg'], + [170, 'ordf'], + [172, 'not'], + [173, 'shy'], + [175, 'macr'], + [176, 'deg'], + [177, 'plusmn'], + [180, 'acute'], + [181, 'micro'], + [182, 'para'], + [183, 'middot'], + [184, 'cedil'], + [186, 'ordm'], + [162, 'cent'], + [185, 'sup1'], + [178, 'sup2'], + [179, 'sup3'], + [189, 'frac12'], + [188, 'frac14'], + [190, 'frac34'], + [8531, 'frac13'], + [8532, 'frac23'], + [8533, 'frac15'], + [8534, 'frac25'], + [8535, 'frac35'], + [8536, 'frac45'], + [8537, 'frac16'], + [8538, 'frac56'], + [8539, 'frac18'], + [8540, 'frac38'], + [8541, 'frac58'], + [8542, 'frac78'], + [191, 'iquest'], + [192, 'Agrave'], + [193, 'Aacute'], + [194, 'Acirc'], + [195, 'Atilde'], + [196, 'Auml'], + [197, 'Aring'], + [198, 'AElig'], + [199, 'Ccedil'], + [200, 'Egrave'], + [201, 'Eacute'], + [202, 'Ecirc'], + [203, 'Euml'], + [204, 'Igrave'], + [205, 'Iacute'], + [206, 'Icirc'], + [207, 'Iuml'], + [208, 'ETH'], + [209, 'Ntilde'], + [210, 'Ograve'], + [211, 'Oacute'], + [212, 'Ocirc'], + [213, 'Otilde'], + [214, 'Ouml'], + [215, 'times'], + [216, 'Oslash'], + [217, 'Ugrave'], + [218, 'Uacute'], + [219, 'Ucirc'], + [220, 'Uuml'], + [221, 'Yacute'], + [222, 'THORN'], + [223, 'szlig'], + [224, 'agrave'], + [225, 'aacute'], + [226, 'acirc'], + [227, 'atilde'], + [228, 'auml'], + [229, 'aring'], + [230, 'aelig'], + [231, 'ccedil'], + [232, 'egrave'], + [233, 'eacute'], + [234, 'ecirc'], + [235, 'euml'], + [236, 'igrave'], + [237, 'iacute'], + [238, 'icirc'], + [239, 'iuml'], + [240, 'eth'], + [241, 'ntilde'], + [242, 'ograve'], + [243, 'oacute'], + [244, 'ocirc'], + [245, 'otilde'], + [246, 'ouml'], + [247, 'divide'], + [248, 'oslash'], + [249, 'ugrave'], + [250, 'uacute'], + [251, 'ucirc'], + [252, 'uuml'], + [253, 'yacute'], + [254, 'thorn'], + [255, 'yuml'], + + [8218, 'sbquo'], + [402, 'fnof'], + [8222, 'bdquo'], + + [128, 8364], + [130, 8218], + [131, 402], + [132, 8222], + [133, 8230], + [134, 8224], + [135, 8225], + [136, 710], + [137, 8240], + [138, 352], + [139, 8249], + [140, 338], + [142, 381], + [145, 8216], + [146, 8217], + [147, 8220], + [148, 8221], + [149, 8226], + [150, 8211], + [151, 8212], + [152, 732], + [153, 8482], + [154, 353], + [155, 8250], + [156, 339], + [158, 382], + [159, 376], + + [8194, 'ensp'], + [8195, 'emsp'], + [8201, 'thinsp'], + + # html5 + [10218, 'Lang'], + [10219, 'Rang'], + [10220, 'loang'], + [10221, 'roang'], + [10229, 'xlarr'], + [10229, 'longleftarrow'], + [10229, 'LongLeftArrow'], + [10230, 'xrarr'], + [10230, 'longrightarrow'], + [10230, 'LongRightArrow'], + [10231, 'xharr'], + [10231, 'longleftrightarrow'], + [10231, 'LongLeftRightArrow'], + [10232, 'xlArr'], + [10232, 'Longleftarrow'], + [10232, 'DoubleLongLeftArrow'], + [10233, 'xrArr'], + [10233, 'Longrightarrow'], + [10233, 'DoubleLongRightArrow'], + [10234, 'xhArr'], + [10234, 'Longleftrightarrow'], + [10234, 'DoubleLongLeftRightArrow'], + [10236, 'xmap'], + [10236, 'longmapsto'], + [10239, 'dzigrarr'], + [10498, 'nvlArr'], + [10499, 'nvrArr'], + [10500, 'nvHarr'], + [10501, 'Map'], + [10508, 'lbarr'], + [10509, 'rbarr'], + [10509, 'bkarow'], + [10510, 'lBarr'], + [10511, 'rBarr'], + [10511, 'dbkarow'], + [10512, 'RBarr'], + [10512, 'drbkarow'], + [10513, 'DDotrahd'], + [10514, 'UpArrowBar'], + [10515, 'DownArrowBar'], + [10518, 'Rarrtl'], + [10521, 'latail'], + [10522, 'ratail'], + [10523, 'lAtail'], + [10524, 'rAtail'], + [10525, 'larrfs'], + [10526, 'rarrfs'], + [10527, 'larrbfs'], + [10528, 'rarrbfs'], + [10531, 'nwarhk'], + [10532, 'nearhk'], + [10533, 'searhk'], + [10533, 'hksearow'], + [10534, 'swarhk'], + [10534, 'hkswarow'], + [10535, 'nwnear'], + [10536, 'nesear'], + [10536, 'toea'], + [10537, 'seswar'], + [10537, 'tosa'], + [10538, 'swnwar'], + [10547, 'rarrc'], + [10549, 'cudarrr'], + [10550, 'ldca'], + [10551, 'rdca'], + [10552, 'cudarrl'], + [10553, 'larrpl'], + [10556, 'curarrm'], + [10557, 'cularrp'], + [10565, 'rarrpl'], + [10568, 'harrcir'], + [10569, 'Uarrocir'], + [10570, 'lurdshar'], + [10571, 'ldrushar'], + [10574, 'LeftRightVector'], + [10575, 'RightUpDownVector'], + [10576, 'DownLeftRightVector'], + [10577, 'LeftUpDownVector'], + [10578, 'LeftVectorBar'], + [10579, 'RightVectorBar'], + [10580, 'RightUpVectorBar'], + [10581, 'RightDownVectorBar'], + [10582, 'DownLeftVectorBar'], + [10583, 'DownRightVectorBar'], + [10584, 'LeftUpVectorBar'], + [10585, 'LeftDownVectorBar'], + [10586, 'LeftTeeVector'], + [10587, 'RightTeeVector'], + [10588, 'RightUpTeeVector'], + [10589, 'RightDownTeeVector'], + [10590, 'DownLeftTeeVector'], + [10591, 'DownRightTeeVector'], + [10592, 'LeftUpTeeVector'], + [10593, 'LeftDownTeeVector'], + [10594, 'lHar'], + [10595, 'uHar'], + [10596, 'rHar'], + [10597, 'dHar'], + [10598, 'luruhar'], + [10599, 'ldrdhar'], + [10600, 'ruluhar'], + [10601, 'rdldhar'], + [10602, 'lharul'], + [10603, 'llhard'], + [10604, 'rharul'], + [10605, 'lrhard'], + [10606, 'udhar'], + [10606, 'UpEquilibrium'], + [10607, 'duhar'], + [10607, 'ReverseUpEquilibrium'], + [10608, 'RoundImplies'], + [10609, 'erarr'], + [10610, 'simrarr'], + [10611, 'larrsim'], + [10612, 'rarrsim'], + [10613, 'rarrap'], + [10614, 'ltlarr'], + [10616, 'gtrarr'], + [10617, 'subrarr'], + [10619, 'suplarr'], + [10620, 'lfisht'], + [10621, 'rfisht'], + [10622, 'ufisht'], + [10623, 'dfisht'], + [10629, 'lopar'], + [10630, 'ropar'], + [10635, 'lbrke'], + [10636, 'rbrke'], + [10637, 'lbrkslu'], + [10638, 'rbrksld'], + [10639, 'lbrksld'], + [10640, 'rbrkslu'], + [10641, 'langd'], + [10642, 'rangd'], + [10643, 'lparlt'], + [10644, 'rpargt'], + [10645, 'gtlPar'], + [10646, 'ltrPar'], + [10650, 'vzigzag'], + [10652, 'vangrt'], + [10653, 'angrtvbd'], + [10660, 'ange'], + [10661, 'range'], + [10662, 'dwangle'], + [10663, 'uwangle'], + [10664, 'angmsdaa'], + [10665, 'angmsdab'], + [10666, 'angmsdac'], + [10667, 'angmsdad'], + [10668, 'angmsdae'], + [10669, 'angmsdaf'], + [10670, 'angmsdag'], + [10671, 'angmsdah'], + [10672, 'bemptyv'], + [10673, 'demptyv'], + [10674, 'cemptyv'], + [10675, 'raemptyv'], + [10676, 'laemptyv'], + [10677, 'ohbar'], + [10678, 'omid'], + [10679, 'opar'], + [10681, 'operp'], + [10683, 'olcross'], + [10684, 'odsold'], + [10686, 'olcir'], + [10687, 'ofcir'], + [10688, 'olt'], + [10689, 'ogt'], + [10690, 'cirscir'], + [10691, 'cirE'], + [10692, 'solb'], + [10693, 'bsolb'], + [10697, 'boxbox'], + [10701, 'trisb'], + [10702, 'rtriltri'], + [10703, 'LeftTriangleBar'], + [10704, 'RightTriangleBar'], + [10716, 'iinfin'], + [10717, 'infintie'], + [10718, 'nvinfin'], + [10723, 'eparsl'], + [10724, 'smeparsl'], + [10725, 'eqvparsl'], + [10731, 'lozf'], + [10731, 'blacklozenge'], + [10740, 'RuleDelayed'], + [10742, 'dsol'], + [10752, 'xodot'], + [10752, 'bigodot'], + [10753, 'xoplus'], + [10753, 'bigoplus'], + [10754, 'xotime'], + [10754, 'bigotimes'], + [10756, 'xuplus'], + [10756, 'biguplus'], + [10758, 'xsqcup'], + [10758, 'bigsqcup'], + [10764, 'qint'], + [10764, 'iiiint'], + [10765, 'fpartint'], + [10768, 'cirfnint'], + [10769, 'awint'], + [10770, 'rppolint'], + [10771, 'scpolint'], + [10772, 'npolint'], + [10773, 'pointint'], + [10774, 'quatint'], + [10775, 'intlarhk'], + [10786, 'pluscir'], + [10787, 'plusacir'], + [10788, 'simplus'], + [10789, 'plusdu'], + [10790, 'plussim'], + [10791, 'plustwo'], + [10793, 'mcomma'], + [10794, 'minusdu'], + [10797, 'loplus'], + [10798, 'roplus'], + [10799, 'Cross'], + [10800, 'timesd'], + [10801, 'timesbar'], + [10803, 'smashp'], + [10804, 'lotimes'], + [10805, 'rotimes'], + [10806, 'otimesas'], + [10807, 'Otimes'], + [10808, 'odiv'], + [10809, 'triplus'], + [10810, 'triminus'], + [10811, 'tritime'], + [10812, 'iprod'], + [10812, 'intprod'], + [10815, 'amalg'], + [10816, 'capdot'], + [10818, 'ncup'], + [10819, 'ncap'], + [10820, 'capand'], + [10821, 'cupor'], + [10822, 'cupcap'], + [10823, 'capcup'], + [10824, 'cupbrcap'], + [10825, 'capbrcup'], + [10826, 'cupcup'], + [10827, 'capcap'], + [10828, 'ccups'], + [10829, 'ccaps'], + [10832, 'ccupssm'], + [10835, 'And'], + [10836, 'Or'], + [10837, 'andand'], + [10838, 'oror'], + [10839, 'orslope'], + [10840, 'andslope'], + [10842, 'andv'], + [10843, 'orv'], + [10844, 'andd'], + [10845, 'ord'], + [10847, 'wedbar'], + [10854, 'sdote'], + [10858, 'simdot'], + [10861, 'congdot'], + [10862, 'easter'], + [10863, 'apacir'], + [10864, 'apE'], + [10865, 'eplus'], + [10866, 'pluse'], + [10867, 'Esim'], + [10868, 'Colone'], + [10869, 'Equal'], + [10871, 'eDDot'], + [10871, 'ddotseq'], + [10872, 'equivDD'], + [10873, 'ltcir'], + [10874, 'gtcir'], + [10875, 'ltquest'], + [10876, 'gtquest'], + [10877, 'les'], + [10877, 'LessSlantEqual'], + [10877, 'leqslant'], + [10878, 'ges'], + [10878, 'GreaterSlantEqual'], + [10878, 'geqslant'], + [10879, 'lesdot'], + [10880, 'gesdot'], + [10881, 'lesdoto'], + [10882, 'gesdoto'], + [10883, 'lesdotor'], + [10884, 'gesdotol'], + [10885, 'lap'], + [10885, 'lessapprox'], + [10886, 'gap'], + [10886, 'gtrapprox'], + [10887, 'lne'], + [10887, 'lneq'], + [10888, 'gne'], + [10888, 'gneq'], + [10889, 'lnap'], + [10889, 'lnapprox'], + [10890, 'gnap'], + [10890, 'gnapprox'], + [10891, 'lEg'], + [10891, 'lesseqqgtr'], + [10892, 'gEl'], + [10892, 'gtreqqless'], + [10893, 'lsime'], + [10894, 'gsime'], + [10895, 'lsimg'], + [10896, 'gsiml'], + [10897, 'lgE'], + [10898, 'glE'], + [10899, 'lesges'], + [10900, 'gesles'], + [10901, 'els'], + [10901, 'eqslantless'], + [10902, 'egs'], + [10902, 'eqslantgtr'], + [10903, 'elsdot'], + [10904, 'egsdot'], + [10905, 'el'], + [10906, 'eg'], + [10909, 'siml'], + [10910, 'simg'], + [10911, 'simlE'], + [10912, 'simgE'], + [10913, 'LessLess'], + [10914, 'GreaterGreater'], + [10916, 'glj'], + [10917, 'gla'], + [10918, 'ltcc'], + [10919, 'gtcc'], + [10920, 'lescc'], + [10921, 'gescc'], + [10922, 'smt'], + [10923, 'lat'], + [10924, 'smte'], + [10925, 'late'], + [10926, 'bumpE'], + [10927, 'pre'], + [10927, 'preceq'], + [10927, 'PrecedesEqual'], + [10928, 'sce'], + [10928, 'succeq'], + [10928, 'SucceedsEqual'], + [10931, 'prE'], + [10932, 'scE'], + [10933, 'prnE'], + [10933, 'precneqq'], + [10934, 'scnE'], + [10934, 'succneqq'], + [10935, 'prap'], + [10935, 'precapprox'], + [10936, 'scap'], + [10936, 'succapprox'], + [10937, 'prnap'], + [10937, 'precnapprox'], + [10938, 'scnap'], + [10938, 'succnapprox'], + [10939, 'Pr'], + [10940, 'Sc'], + [10941, 'subdot'], + [10942, 'supdot'], + [10943, 'subplus'], + [10944, 'supplus'], + [10945, 'submult'], + [10946, 'supmult'], + [10947, 'subedot'], + [10948, 'supedot'], + [10949, 'subE'], + [10949, 'subseteqq'], + [10950, 'supE'], + [10950, 'supseteqq'], + [10951, 'subsim'], + [10952, 'supsim'], + [10955, 'subnE'], + [10955, 'subsetneqq'], + [10956, 'supnE'], + [10956, 'supsetneqq'], + [10959, 'csub'], + [10960, 'csup'], + [10961, 'csube'], + [10962, 'csupe'], + [10963, 'subsup'], + [10964, 'supsub'], + [10965, 'subsub'], + [10966, 'supsup'], + [10967, 'suphsub'], + [10968, 'supdsub'], + [10969, 'forkv'], + [10970, 'topfork'], + [10971, 'mlcp'], + [10980, 'Dashv'], + [10980, 'DoubleLeftTee'], + [10982, 'Vdashl'], + [10983, 'Barv'], + [10984, 'vBar'], + [10985, 'vBarv'], + [10987, 'Vbar'], + [10988, 'Not'], + [10989, 'bNot'], + [10990, 'rnmid'], + [10991, 'cirmid'], + [10992, 'midcir'], + [10993, 'topcir'], + [10994, 'nhpar'], + [10995, 'parsim'], + [11005, 'parsl'], + [64256, 'fflig'], + [64257, 'filig'], + [64258, 'fllig'], + [64259, 'ffilig'], + [64260, 'ffllig'], + [119964, 'Ascr'], + [119966, 'Cscr'], + [119967, 'Dscr'], + [119970, 'Gscr'], + [119973, 'Jscr'], + [119974, 'Kscr'], + [119977, 'Nscr'], + [119978, 'Oscr'], + [119979, 'Pscr'], + [119980, 'Qscr'], + [119982, 'Sscr'], + [119983, 'Tscr'], + [119984, 'Uscr'], + [119985, 'Vscr'], + [119986, 'Wscr'], + [119987, 'Xscr'], + [119988, 'Yscr'], + [119989, 'Zscr'], + [119990, 'ascr'], + [119991, 'bscr'], + [119992, 'cscr'], + [119993, 'dscr'], + [119995, 'fscr'], + [119997, 'hscr'], + [119998, 'iscr'], + [119999, 'jscr'], + [120000, 'kscr'], + [120001, 'lscr'], + [120002, 'mscr'], + [120003, 'nscr'], + [120005, 'pscr'], + [120006, 'qscr'], + [120007, 'rscr'], + [120008, 'sscr'], + [120009, 'tscr'], + [120010, 'uscr'], + [120011, 'vscr'], + [120012, 'wscr'], + [120013, 'xscr'], + [120014, 'yscr'], + [120015, 'zscr'], + [120068, 'Afr'], + [120069, 'Bfr'], + [120071, 'Dfr'], + [120072, 'Efr'], + [120073, 'Ffr'], + [120074, 'Gfr'], + [120077, 'Jfr'], + [120078, 'Kfr'], + [120079, 'Lfr'], + [120080, 'Mfr'], + [120081, 'Nfr'], + [120082, 'Ofr'], + [120083, 'Pfr'], + [120084, 'Qfr'], + [120086, 'Sfr'], + [120087, 'Tfr'], + [120088, 'Ufr'], + [120089, 'Vfr'], + [120090, 'Wfr'], + [120091, 'Xfr'], + [120092, 'Yfr'], + [120094, 'afr'], + [120095, 'bfr'], + [120096, 'cfr'], + [120097, 'dfr'], + [120098, 'efr'], + [120099, 'ffr'], + [120100, 'gfr'], + [120101, 'hfr'], + [120102, 'ifr'], + [120103, 'jfr'], + [120104, 'kfr'], + [120105, 'lfr'], + [120106, 'mfr'], + [120107, 'nfr'], + [120108, 'ofr'], + [120109, 'pfr'], + [120110, 'qfr'], + [120111, 'rfr'], + [120112, 'sfr'], + [120113, 'tfr'], + [120114, 'ufr'], + [120115, 'vfr'], + [120116, 'wfr'], + [120117, 'xfr'], + [120118, 'yfr'], + [120119, 'zfr'], + [120120, 'Aopf'], + [120121, 'Bopf'], + [120123, 'Dopf'], + [120124, 'Eopf'], + [120125, 'Fopf'], + [120126, 'Gopf'], + [120128, 'Iopf'], + [120129, 'Jopf'], + [120130, 'Kopf'], + [120131, 'Lopf'], + [120132, 'Mopf'], + [120134, 'Oopf'], + [120138, 'Sopf'], + [120139, 'Topf'], + [120140, 'Uopf'], + [120141, 'Vopf'], + [120142, 'Wopf'], + [120143, 'Xopf'], + [120144, 'Yopf'], + [120146, 'aopf'], + [120147, 'bopf'], + [120148, 'copf'], + [120149, 'dopf'], + [120150, 'eopf'], + [120151, 'fopf'], + [120152, 'gopf'], + [120153, 'hopf'], + [120154, 'iopf'], + [120155, 'jopf'], + [120156, 'kopf'], + [120157, 'lopf'], + [120158, 'mopf'], + [120159, 'nopf'], + [120160, 'oopf'], + [120161, 'popf'], + [120162, 'qopf'], + [120163, 'ropf'], + [120164, 'sopf'], + [120165, 'topf'], + [120166, 'uopf'], + [120167, 'vopf'], + [120168, 'wopf'], + [120169, 'xopf'], + [120170, 'yopf'], + [120171, 'zopf'], + [60, 'nvlt'], + [61, 'bne'], + [62, 'nvgt'], + [102, 'fjlig'], + [8287, 'ThickSpace'], + [8605, 'nrarrw'], + [8706, 'npart'], + [8736, 'nang'], + [8745, 'caps'], + [8746, 'cups'], + [8764, 'nvsim'], + [8765, 'race'], + [8766, 'acE'], + [8770, 'nesim'], + [8770, 'NotEqualTilde'], + [8779, 'napid'], + [8781, 'nvap'], + [8782, 'nbump'], + [8782, 'NotHumpDownHump'], + [8783, 'nbumpe'], + [8783, 'NotHumpEqual'], + [8784, 'nedot'], + [8801, 'bnequiv'], + [8804, 'nvle'], + [8805, 'nvge'], + [8806, 'nlE'], + [8806, 'nleqq'], + [8807, 'ngE'], + [8807, 'ngeqq'], + [8807, 'NotGreaterFullEqual'], + [8808, 'lvertneqq'], + [8808, 'lvnE'], + [8809, 'gvertneqq'], + [8809, 'gvnE'], + [8810, 'nLtv'], + [8810, 'NotLessLess'], + [8810, 'nLt'], + [8811, 'nGtv'], + [8811, 'NotGreaterGreater'], + [8811, 'nGt'], + [8831, 'NotSucceedsTilde'], + [8834, 'NotSubset'], + [8834, 'nsubset'], + [8834, 'vnsub'], + [8835, 'NotSuperset'], + [8835, 'nsupset'], + [8835, 'vnsup'], + [8842, 'varsubsetneq'], + [8842, 'vsubne'], + [8843, 'varsupsetneq'], + [8843, 'vsupne'], + [8847, 'NotSquareSubset'], + [8848, 'NotSquareSuperset'], + [8851, 'sqcaps'], + [8852, 'sqcups'], + [8884, 'nvltrie'], + [8885, 'nvrtrie'], + [8920, 'nLl'], + [8921, 'nGg'], + [8922, 'lesg'], + [8923, 'gesl'], + [8949, 'notindot'], + [8953, 'notinE'], + [10547, 'nrarrc'], + [10703, 'NotLeftTriangleBar'], + [10704, 'NotRightTriangleBar'], + [10861, 'ncongdot'], + [10864, 'napE'], + [10877, 'nleqslant'], + [10877, 'nles'], + [10877, 'NotLessSlantEqual'], + [10878, 'ngeqslant'], + [10878, 'nges'], + [10878, 'NotGreaterSlantEqual'], + [10913, 'NotNestedLessLess'], + [10914, 'NotNestedGreaterGreater'], + [10924, 'smtes'], + [10925, 'lates'], + [10927, 'NotPrecedesEqual'], + [10927, 'npre'], + [10927, 'npreceq'], + [10928, 'NotSucceedsEqual'], + [10928, 'nsce'], + [10928, 'nsucceq'], + [10949, 'nsubE'], + [10949, 'nsubseteqq'], + [10950, 'nsupE'], + [10950, 'nsupseteqq'], + [10955, 'varsubsetneqq'], + [10955, 'vsubnE'], + [10956, 'varsupsetneqq'], + [10956, 'vsupnE'], + [11005, 'nparsl'], + + ] + + # Contains the mapping of code point (or name) to the actual Entity object. + ENTITY_MAP = Hash.new do |h, k| + if k.kind_of?(Integer) + h[k] = Entity.new(k, nil) + else + raise Kramdown::Error, "Can't handle generic non-integer character reference '#{k}'" + end + end + + ENTITY_TABLE.each do |code_point, data| + ENTITY_MAP[code_point] = if data.kind_of?(String) + ENTITY_MAP[data] = Entity.new(code_point, data) + else + ENTITY_MAP[data] + end + end + + # Return the entity for the given code point or name +point_or_name+. + def entity(point_or_name) + ENTITY_MAP[point_or_name] + end + + module_function :entity + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb new file mode 100644 index 00000000..0fba9d4b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/html.rb @@ -0,0 +1,84 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' + +module Kramdown + + module Utils + + # Provides convenience methods for HTML related tasks. + # + # *Note* that this module has to be mixed into a class that has a @root (containing an element + # of type :root) and an @options (containing an options hash) instance variable so that some of + # the methods can work correctly. + module Html + + # Convert the entity +e+ to a string. The optional parameter +original+ may contain the + # original representation of the entity. + # + # This method uses the option +entity_output+ to determine the output form for the entity. + def entity_to_str(e, original = nil) + entity_output = @options[:entity_output] + + if entity_output == :as_char && + (c = e.char.encode(@root.options[:encoding]) rescue nil) && + ((c = e.char) == '"' || !ESCAPE_MAP.key?(c)) + c + elsif (entity_output == :as_input || entity_output == :as_char) && original + original + elsif (entity_output == :symbolic || ESCAPE_MAP.key?(e.char)) && !e.name.nil? + "&#{e.name};" + else # default to :numeric + "&##{e.code_point};" + end + end + + # Return the HTML representation of the attributes +attr+. + def html_attributes(attr) + return '' if attr.empty? + + attr.map do |k, v| + v.nil? || (k == 'id' && v.strip.empty?) ? '' : " #{k}=\"#{escape_html(v.to_s, :attribute)}\"" + end.join + end + + # :stopdoc: + ESCAPE_MAP = { + '<' => '<', + '>' => '>', + '&' => '&', + '"' => '"', + } + ESCAPE_ALL_RE = /<|>|&/ + ESCAPE_TEXT_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&/) + ESCAPE_ATTRIBUTE_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&|"/) + ESCAPE_RE_FROM_TYPE = {all: ESCAPE_ALL_RE, text: ESCAPE_TEXT_RE, attribute: ESCAPE_ATTRIBUTE_RE} + # :startdoc: + + # Escape the special HTML characters in the string +str+. The parameter +type+ specifies what + # is escaped: :all - all special HTML characters except the quotation mark as well as + # entities, :text - all special HTML characters except the quotation mark but no entities and + # :attribute - all special HTML characters including the quotation mark but no entities. + def escape_html(str, type = :all) + str.gsub(ESCAPE_RE_FROM_TYPE[type]) {|m| ESCAPE_MAP[m] || m } + end + + REDUNDANT_LINE_BREAK_REGEX = /([\p{Han}\p{Hiragana}\p{Katakana}]+)\n([\p{Han}\p{Hiragana}\p{Katakana}]+)/u + def fix_cjk_line_break(str) + while str.gsub!(REDUNDANT_LINE_BREAK_REGEX, '\1\2') + end + str + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb new file mode 100644 index 00000000..32549fba --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/lru_cache.rb @@ -0,0 +1,41 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # A simple least recently used (LRU) cache. + # + # The cache relies on the fact that Ruby's Hash class maintains insertion order. So deleting + # and re-inserting a key-value pair on access moves the key to the last position. When an + # entry is added and the cache is full, the first entry is removed. + class LRUCache + + # Creates a new LRUCache that can hold +size+ entries. + def initialize(size) + @size = size + @cache = {} + end + + # Returns the stored value for +key+ or +nil+ if no value was stored under the key. + def [](key) + (val = @cache.delete(key)).nil? ? nil : @cache[key] = val + end + + # Stores the +value+ under the +key+. + def []=(key, value) + @cache.delete(key) + @cache[key] = value + @cache.shift if @cache.length > @size + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb new file mode 100644 index 00000000..2ef194ef --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/string_scanner.rb @@ -0,0 +1,81 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' + +module Kramdown + module Utils + + # This patched StringScanner adds line number information for current scan position and a + # start_line_number override for nested StringScanners. + class StringScanner < ::StringScanner + + # The start line number. Used for nested StringScanners that scan a sub-string of the source + # document. The kramdown parser uses this, e.g., for span level parsers. + attr_reader :start_line_number + + # Takes the start line number as optional second argument. + # + # Note: The original second argument is no longer used so this should be safe. + def initialize(string, start_line_number = 1) + super(string) + @start_line_number = start_line_number || 1 + @previous_pos = 0 + @previous_line_number = @start_line_number + end + + # Sets the byte position of the scan pointer. + # + # Note: This also resets some internal variables, so always use pos= when setting the position + # and don't use any other method for that! + def pos=(pos) + if self.pos > pos + @previous_line_number = @start_line_number + @previous_pos = 0 + end + super + end + + # Return information needed to revert the byte position of the string scanner in a performant + # way. + # + # The returned data can be fed to #revert_pos to revert the position to the saved one. + # + # Note: Just saving #pos won't be enough. + def save_pos + [pos, @previous_pos, @previous_line_number] + end + + # Revert the position to one saved by #save_pos. + def revert_pos(data) + self.pos = data[0] + @previous_pos, @previous_line_number = data[1], data[2] + end + + # Returns the line number for current charpos. + # + # NOTE: Requires that all line endings are normalized to '\n' + # + # NOTE: Normally we'd have to add one to the count of newlines to get the correct line number. + # However we add the one indirectly by using a one-based start_line_number. + def current_line_number + # Not using string[@previous_pos..best_pos].count('\n') because it is slower + strscan = ::StringScanner.new(string) + strscan.pos = @previous_pos + old_pos = pos + 1 + @previous_line_number += 1 while strscan.skip_until(/\n/) && strscan.pos <= old_pos + + @previous_pos = (eos? ? pos : pos + 1) + @previous_line_number + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb new file mode 100644 index 00000000..b4bbe28e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/utils/unidecoder.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# This file is based on code originally from the Stringex library and needs the data files from +# Stringex to work correctly. + +module Kramdown + module Utils + + # Provides the ability to tranliterate Unicode strings into plain ASCII ones. + module Unidecoder + + gem 'stringex' + path = $:.find do |dir| + File.directory?(File.join(File.expand_path(dir), "stringex", "unidecoder_data")) + end + + if path + CODEPOINTS = Hash.new do |h, k| + h[k] = YAML.load_file(File.join(path, "stringex", "unidecoder_data", "#{k}.yml")) + end + + # Transliterate string from Unicode into ASCII. + def self.decode(string) + string.gsub(/[^\x00-\x7f]/u) do |codepoint| + unpacked = codepoint.unpack1("U") + CODEPOINTS[sprintf("x%02x", unpacked >> 8)][unpacked & 255] + rescue StandardError + "?" + end + end + else + def self.decode(string) + string + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.1/lib/kramdown/version.rb b/bin/gems/kramdown-2.5.1/lib/kramdown/version.rb new file mode 100644 index 00000000..0bc41309 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/lib/kramdown/version.rb @@ -0,0 +1,15 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # The kramdown version. + VERSION = '2.5.1' + +end diff --git a/bin/gems/kramdown-2.5.1/man/man1/kramdown.1 b/bin/gems/kramdown-2.5.1/man/man1/kramdown.1 new file mode 100644 index 00000000..80225825 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/man/man1/kramdown.1 @@ -0,0 +1,373 @@ +.\" generated by kramdown +.TH "KRAMDOWN" "1" "January 2019" +.SH NAME +kramdown \- a fast, pure\-Ruby Markdown\-superset converter +.SH "SYNOPSIS" +\fBkramdown\fP [\fIoptions\fP] [\fIFILE\fP\.\.\.] +.SH "DESCRIPTION" +kramdown is primarily used for parsing a superset of Markdown and converting it to different output formats\. It supports standard Markdown (with some minor modifications) and various extensions like tables and definition lists\. Due to its modular architecture it also allows other input formats than Markdown, for example, HTML or Github Flavored Markdown\. +.P +If \fIFILE\fP is not specified, kramdown reads from the standard input\. The result is written to the standard output\. +.P +There are two sets of options that kramdown accepts: The first one includes the options that are used directly by the kramdown binary\. The second set of options controls how kramdown parses and converts its input\. +.P +Default values for this second set can be set using YAML via the configuration file \fBkramdownrc\fP\&\. Note that configuration option names use underscores, not dashes (dashes are just used in the CLI options names), and boolean options do not have a \fBno\fP variant but a value of \fBtrue\fP or \fBfalse\fP\&\. This file has to be in XDG_CONFIG_HOME on Linux/Unix, ~/Library/Preferences on macOS and ~/AppData/Local on Windows\. +.SH "CLI\-ONLY OPTIONS" +.TP +\fB\-i\fP \fIFORMAT\fP, \fB\-\-input\fP \fIFORMAT\fP +Specify the input format\. Available input formats: \fIkramdown\fP (this is the default), \fImarkdown\fP, or \fIhtml\fP\&\. The input format \fIGFM\fP is available through the \fBkramdown\-parser\-gfm\fP gem\. +.TP +\fB\-o\fP \fIFORMAT\fP, \fB\-\-output\fP \fIFORMAT\fP +Specify one or more output formats separated by commas: \fIhtml\fP (default), \fIkramdown\fP, \fIlatex\fP, \fIman\fP or \fIremove_html_tags\fP\&\. The converter \fIpdf\fP is available through the \fBkramdown\-converter\-pdf\fP gem\. +.TP +\fB\-x\fP \fIEXT\fP, \fB\-\-extension\fP \fIEXT\fP +Load one or more extensions\. The name of the extension should not include the \fBkramdown\-\fP prefix, e\.g\. just \fBparser\-gfm\fP\&\. Multiple extensions can be loaded by separating them with commas\. +.RS +.P +Note: This option has to be used before any other options that rely on the extension already being loaded\. +.RE +.TP +\fB\-\-no\-config\-file\fP +Do not read any configuration file\. Default behavior is to check for a configuration file and read it if it exists\. +.TP +\fB\-\-config\-file\fP \fIFILE\fP +Override the default path and name of the configuration file\. +.TP +\fB\-v\fP, \fB\-\-version\fP +Show the version of kramdown\. +.TP +\fB\-h\fP, \fB\-\-help\fP +Show the help\. +.SH "KRAMDOWN OPTIONS" +.TP +\fB\-\-auto\-id\-prefix\fP \fIARG\fP +Prefix used for automatically generated header IDs +.RS +.P +This option can be used to set a prefix for the automatically generated header IDs so that there is no conflict when rendering multiple kramdown documents into one output file separately\. The prefix should only contain characters that are valid in an ID! +.P +Default: \[u2018]\[u2019] Used by: HTML/Latex converter +.RE +.TP +\fB\-\-[no\-]auto\-id\-stripping\fP +Strip all formatting from header text for automatic ID generation +.RS +.P +If this option is \fBtrue\fP, only the text elements of a header are used for generating the ID later (in contrast to just using the raw header text line)\. +.P +This option will be removed in version 2\.0 because this will be the default then\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]auto\-ids\fP +Use automatic header ID generation +.RS +.P +If this option is \fBtrue\fP, ID values for all headers are automatically generated if no ID is explicitly specified\. +.P +Default: true Used by: HTML/Latex converter +.RE +.TP +\fB\-\-entity\-output\fP \fIARG\fP +Defines how entities are output +.RS +.P +The possible values are :as_input (entities are output in the same form as found in the input), :numeric (entities are output in numeric form), :symbolic (entities are output in symbolic form if possible) or :as_char (entities are output as characters if possible, only available on Ruby 1\.9)\. +.P +Default: :as_char Used by: HTML converter, kramdown converter +.RE +.TP +\fB\-\-footnote\-backlink\fP \fIARG\fP +Defines the text that should be used for the footnote backlinks +.RS +.P +The footnote backlink is just text, so any special HTML characters will be escaped\. +.P +If the footnote backlint text is an empty string, no footnote backlinks will be generated\. +.P +Default: \[u2018]\[u0026]8617;\[u2019] Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]footnote\-backlink\-inline\fP +Specifies whether the footnote backlink should always be inline +.RS +.P +With the default of false the footnote backlink is placed at the end of the last paragraph if there is one, or an extra paragraph with only the footnote backlink is created\. +.P +Setting this option to true tries to place the footnote backlink in the last, possibly nested paragraph or header\. If this fails (e\.g\. in the case of a table), an extra paragraph with only the footnote backlink is created\. +.P +Default: false Used by: HTML converter +.RE +.TP +\fB\-\-footnote\-link\-text\fP \fIARG\fP +The text used for the footnote number in a footnote link +.RS +.P +This option can be used to add additional text to the footnote link\. It should be a format string, and is passed the footnote number as the only argument to the format string\. e\.g\. \[u201c][footnote %s]\[u201d] would display as \[u201c][footnote 1]\[u201d]\&\. +.P +Default: \[u2018]%s\[u2019] Used by: HTML +.RE +.TP +\fB\-\-footnote\-nr\fP \fIARG\fP +The number of the first footnote +.RS +.P +This option can be used to specify the number that is used for the first footnote\. +.P +Default: 1 Used by: HTML converter +.RE +.TP +\fB\-\-footnote\-prefix\fP \fIARG\fP +Prefix used for footnote IDs +.RS +.P +This option can be used to set a prefix for footnote IDs\. This is useful when rendering multiple documents into the same output file to avoid duplicate IDs\. The prefix should only contain characters that are valid in an ID! +.P +Default: \[u2018]\[u2019] Used by: HTML +.RE +.TP +\fB\-\-forbidden\-inline\-options\fP \fIARG\fP +Defines the options that may not be set using the {::options} extension +.RS +.P +The value needs to be an array of option names\. +.P +Default: [template] Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]header\-links\fP +Adds anchor tags within headers that can be used to generate permalinks when not using a table of contents\. +.RS +.P +The anchor tags are empty, but can be styled to your liking\. +.P +Default: false +.RE +.TP +\fB\-\-header\-offset\fP \fIARG\fP +Sets the output offset for headers +.RS +.P +If this option is c (may also be negative) then a header with level n will be output as a header with level c+n\. If c+n is lower than 1, level 1 will be used\. If c+n is greater than 6, level 6 will be used\. +.P +Default: 0 Used by: HTML converter, Kramdown converter, Latex converter +.RE +.TP +\fB\-\-[no\-]html\-to\-native\fP +Convert HTML elements to native elements +.RS +.P +If this option is \fBtrue\fP, the parser converts HTML elements to native elements\. For example, when parsing \fBhallo\fP the emphasis tag would normally be converted to an \fB:html\fP element with tag type \fB:em\fP\&\. If \fBhtml_to_native\fP is \fBtrue\fP, then the emphasis would be converted to a native \fB:em\fP element\. +.P +This is useful for converters that cannot deal with HTML elements\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-latex\-headers\fP \fIARG\fP +Defines the LaTeX commands for different header levels +.RS +.P +The commands for the header levels one to six can be specified by separating them with commas\. +.P +Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph Used by: Latex converter +.RE +.TP +\fB\-\-line\-width\fP \fIARG\fP +Defines the line width to be used when outputting a document +.RS +.P +Default: 72 Used by: kramdown converter +.RE +.TP +\fB\-\-link\-defs\fP \fIARG\fP +Pre\-defines link definitions +.RS +.P +This option can be used to pre\-define link definitions\. The value needs to be a Hash where the keys are the link identifiers and the values are two element Arrays with the link URL and the link title\. +.P +If the value is a String, it has to contain a valid YAML hash and the hash has to follow the above guidelines\. +.P +Default: {} Used by: kramdown parser +.RE +.TP +\fB\-\-list\-indent\fP \fIARG\fP +Sets the number of spaces to use for list indentation +.RS +.P +Default: 2 Used by: Kramdown converter +.RE +.TP +\fB\-\-math\-engine\fP \fIARG\fP +Set the math engine +.RS +.P +Specifies the math engine that should be used for converting math blocks/spans\. If this option is set to +nil+, no math engine is used and the math blocks/spans are output as is\. +.P +Options for the selected math engine can be set with the math_engine_opts configuration option\. +.P +Default: mathjax Used by: HTML converter +.RE +.TP +\fB\-\-math\-engine\-opts\fP \fIARG\fP +Set the math engine options +.RS +.P +Specifies options for the math engine set via the math_engine configuration option\. +.P +The value needs to be a hash with key\-value pairs that are understood by the used math engine\. +.P +Default: {} Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]parse\-block\-html\fP +Process kramdown syntax in block HTML tags +.RS +.P +If this option is \fBtrue\fP, the kramdown parser processes the content of block HTML tags as text containing block\-level elements\. Since this is not wanted normally, the default is \fBfalse\fP\&\. It is normally better to selectively enable kramdown processing via the markdown attribute\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]parse\-span\-html\fP +Process kramdown syntax in span HTML tags +.RS +.P +If this option is \fBtrue\fP, the kramdown parser processes the content of span HTML tags as text containing span\-level elements\. +.P +Default: true Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]remove\-block\-html\-tags\fP +Remove block HTML tags +.RS +.P +If this option is \fBtrue\fP, the RemoveHtmlTags converter removes block HTML tags\. +.P +Default: true Used by: RemoveHtmlTags converter +.RE +.TP +\fB\-\-[no\-]remove\-line\-breaks\-for\-cjk\fP +Specifies whether line breaks should be removed between CJK characters +.RS +.P +Default: false Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]remove\-span\-html\-tags\fP +Remove span HTML tags +.RS +.P +If this option is \fBtrue\fP, the RemoveHtmlTags converter removes span HTML tags\. +.P +Default: false Used by: RemoveHtmlTags converter +.RE +.TP +\fB\-\-smart\-quotes\fP \fIARG\fP +Defines the HTML entity names or code points for smart quote output +.RS +.P +The entities identified by entity name or code point that should be used for, in order, a left single quote, a right single quote, a left double and a right double quote are specified by separating them with commas\. +.P +Default: lsquo,rsquo,ldquo,rdquo Used by: HTML/Latex converter +.RE +.TP +\fB\-\-syntax\-highlighter\fP \fIARG\fP +Set the syntax highlighter +.RS +.P +Specifies the syntax highlighter that should be used for highlighting code blocks and spans\. If this option is set to +nil+, no syntax highlighting is done\. +.P +Options for the syntax highlighter can be set with the syntax_highlighter_opts configuration option\. +.P +Default: rouge Used by: HTML/Latex converter +.RE +.TP +\fB\-\-syntax\-highlighter\-opts\fP \fIARG\fP +Set the syntax highlighter options +.RS +.P +Specifies options for the syntax highlighter set via the syntax_highlighter configuration option\. +.P +The value needs to be a hash with key\-value pairs that are understood by the used syntax highlighter\. +.P +Default: {} Used by: HTML/Latex converter +.RE +.TP +\fB\-\-template\fP \fIARG\fP +The name of an ERB template file that should be used to wrap the output or the ERB template itself\. +.RS +.P +This is used to wrap the output in an environment so that the output can be used as a stand\-alone document\. For example, an HTML template would provide the needed header and body tags so that the whole output is a valid HTML file\. If no template is specified, the output will be just the converted text\. +.P +When resolving the template file, the given template name is used first\. If such a file is not found, the converter extension (the same as the converter name) is appended\. If the file still cannot be found, the templates name is interpreted as a template name that is provided by kramdown (without the converter extension)\. If the file is still not found, the template name is checked if it starts with \[u2018]string://\[u2019] and if it does, this prefix is removed and the rest is used as template content\. +.P +kramdown provides a default template named \[u2018]document\[u2019] for each converter\. +.P +Default: \[u2018]\[u2019] Used by: all converters +.RE +.TP +\fB\-\-toc\-levels\fP \fIARG\fP +Defines the levels that are used for the table of contents +.RS +.P +The individual levels can be specified by separating them with commas (e\.g\. 1,2,3) or by using the range syntax (e\.g\. 1\.\.3)\. Only the specified levels are used for the table of contents\. +.P +Default: 1\.\.6 Used by: HTML/Latex converter +.RE +.TP +\fB\-\-[no\-]transliterated\-header\-ids\fP +Transliterate the header text before generating the ID +.RS +.P +Only ASCII characters are used in headers IDs\. This is not good for languages with many non\-ASCII characters\. By enabling this option the header text is transliterated to ASCII as good as possible so that the resulting header ID is more useful\. +.P +The stringex library needs to be installed for this feature to work! +.P +Default: false Used by: HTML/Latex converter +.RE +.TP +\fB\-\-typographic\-symbols\fP \fIARG\fP +Defines a mapping from typographical symbol to output characters +.RS +.P +Typographical symbols are normally output using their equivalent Unicode codepoint\. However, sometimes one wants to change the output, mostly to fallback to a sequence of ASCII characters\. +.P +This option allows this by specifying a mapping from typographical symbol to its output string\. For example, the mapping {hellip: \.\.\.} would output the standard ASCII representation of an ellipsis\. +.P +The available typographical symbol names are: +.IP \(bu 4 +hellip: ellipsis +.IP \(bu 4 +mdash: em\-dash +.IP \(bu 4 +ndash: en\-dash +.IP \(bu 4 +laquo: left guillemet +.IP \(bu 4 +raquo: right guillemet +.IP \(bu 4 +laquo_space: left guillemet followed by a space +.IP \(bu 4 +raquo_space: right guillemet preceeded by a space +.P +Default: {} Used by: HTML/Latex converter +.RE +.SH "EXIT STATUS" +The exit status is 0 if no error happened\. Otherwise it is 1\. +.SH "SEE ALSO" +The kramdown website +.UR http://kramdown\.gettalong\.org +.UE +for more information, especially on the supported input syntax\. +.SH "AUTHOR" +kramdown was written by Thomas Leitner +.MT t_leitner@gmx\.at +.UE +\&\. +.P +This manual page was written by Thomas Leitner +.MT t_leitner@gmx\.at +.UE +\&\. diff --git a/bin/gems/kramdown-2.5.1/test/run_tests.rb b/bin/gems/kramdown-2.5.1/test/run_tests.rb new file mode 100644 index 00000000..abda5021 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/run_tests.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'kramdown' +require 'test/unit/assertions' +require 'yaml' + +include Test::Unit::Assertions + +arg = ARGV[0] || File.join(File.dirname(__FILE__), 'testcases') + +arg = if File.directory?(arg) + File.join(arg, '**/*.text') + else + arg + '.text' + end + +width = ((size = `stty size 2>/dev/null`).length > 0 ? size.split.last.to_i : 72) rescue 72 +width -= 8 +fwidth = 0 +Dir[arg].each {|f| fwidth = [fwidth, f.length + 10].max }.each do |file| + print(('Testing ' + file + ' ').ljust([fwidth, width].min)) + $stdout.flush + + html_file = file.sub('.text', '.html') + opts_file = file.sub('.text', '.options') + opts_file = File.join(File.dirname(file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.safe_load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(file), options) + begin + assert_equal(File.read(html_file), doc.to_html) + puts 'PASSED' + rescue StandardError + puts ' FAILED' + puts $!.message if $VERBOSE + puts $!.backtrace if $DEBUG + end + puts "Warnings:\n" + doc.warnings.join("\n") if !doc.warnings.empty? && $VERBOSE +end diff --git a/bin/gems/kramdown-2.5.1/test/test_files.rb b/bin/gems/kramdown-2.5.1/test/test_files.rb new file mode 100644 index 00000000..6bc0a028 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/test_files.rb @@ -0,0 +1,313 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown' +require 'yaml' +require 'tmpdir' +require 'open3' + +begin + require 'kramdown/converter/syntax_highlighter/rouge' + + Kramdown::Converter::SyntaxHighlighter::Rouge.formatter_class.send(:define_method, :format) do |tokens, &b| + super(tokens, &b).sub(/<\/code><\/pre>\n?/, "\n") + end + + # custom formatter for tests + module Rouge + module Formatters + class RougeHTMLFormatters < Kramdown::Converter::SyntaxHighlighter::Rouge.formatter_class + + tag 'rouge_html_formatters' + + def stream(tokens, &b) + yield %(
) + super + yield %(
) + end + + end + end + end +rescue LoadError, SyntaxError, NameError +end + +Encoding.default_external = 'utf-8' + +class TestFiles < Minitest::Test + + EXCLUDE_KD_FILES = [].compact + + # Generate test methods for kramdown-to-xxx conversion + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_KD_FILES.any? {|f| text_file =~ /#{f}/ } + basename = text_file.sub(/\.text$/, '') + opts_file = text_file.sub(/\.text$/, '.options') + (Dir[basename + ".*"] - [text_file, opts_file]).each do |output_file| + output_format = File.extname(output_file)[1..-1] + next unless Kramdown::Converter.const_defined?(output_format[0..0].upcase + output_format[1..-1]) + define_method('test_' + text_file.tr('.', '_') + "_to_#{output_format}") do + opts_file = File.join(File.dirname(text_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(text_file), options) + assert_equal(File.read(output_file), doc.send("to_#{output_format}")) + end + end + end + + # Generate test methods for html-to-{html,kramdown} conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping html-to-{html,kramdown} tests because tidy executable is missing") + else + EXCLUDE_HTML_FILES = [ + 'test/testcases/block/06_codeblock/whitespace.html', # bc of span inside pre + 'test/testcases/block/09_html/simple.html', # bc of xml elements + 'test/testcases/span/03_codespan/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option + 'test/testcases/block/04_header/header_type_offset.html', # bc of header_offset option + 'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/highlighting-opts.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/guess_lang_css_class.html', # bc of double surrounding
+ 'test/testcases/block/12_extension/options3.html', # bc of rouge + 'test/testcases/block/14_table/empty_tag_in_cell.html', # bc of tidy + 'test/testcases/block/15_math/mathjax_preview.html', # bc of mathjax preview + 'test/testcases/block/15_math/mathjax_preview_simple.html', # bc of mathjax preview + 'test/testcases/block/15_math/mathjax_preview_as_code.html', # bc of mathjax preview + 'test/testcases/span/05_html/mark_element.html', # bc of tidy + 'test/testcases/block/09_html/xml.html', # bc of tidy + 'test/testcases/span/05_html/xml.html', # bc of tidy + 'test/testcases/block/04_header/with_header_links.html', # because of header_links option + ].compact + EXCLUDE_HTML_TEXT_FILES = [ + 'test/testcases/block/09_html/parse_as_span.htmlinput', + 'test/testcases/block/09_html/parse_as_raw.htmlinput', + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.{html,htmlinput}'].each do |html_file| + next if EXCLUDE_HTML_FILES.any? {|f| html_file =~ /#{f}/ } + + out_files = [] + out_files << [(html_file =~ /\.htmlinput$/ ? html_file.sub(/input$/, '') : html_file), :to_html] + if html_file =~ /\.htmlinput$/ && EXCLUDE_HTML_TEXT_FILES.none? {|f| html_file =~ /#{f}/ } + out_files << [html_file.sub(/htmlinput$/, 'text'), :to_kramdown] + end + out_files.select {|f, _| File.exist?(f) }.each do |out_file, out_method| + define_method('test_' + html_file.tr('.', '_') + "_to_#{File.extname(out_file)}") do + opts_file = html_file.sub(/\.html(input)?$/, '.options') + opts_file = File.join(File.dirname(html_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(html_file), options.merge(input: 'html')) + if out_method == :to_html + assert_equal(tidy_output(File.read(out_file)), tidy_output(doc.send(out_method))) + else + assert_equal(File.read(out_file), doc.send(out_method)) + end + end + end + end + end + + def tidy_output(out) + cmd = "tidy -q --doctype omit -utf8" + result, error, status = Open3.capture3(cmd, stdin_data: out) + if status.exitstatus == 2 + raise "Problem using tidy: #{error}" + end + result + end + + # Generate test methods for text-to-latex conversion and compilation + `latex -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping latex compilation tests because latex executable is missing") + else + EXCLUDE_LATEX_FILES = [ + 'test/testcases/span/01_link/image_in_a.text', # bc of image link + 'test/testcases/span/01_link/imagelinks.text', # bc of image links + 'test/testcases/span/01_link/empty_title.text', + 'test/testcases/span/04_footnote/markers.text', # bc of footnote in header + 'test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text', + 'test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text', + 'test/testcases/block/03_paragraph/standalone_image.text', # bc of standalone image + 'test/testcases/cjk-line-break.text', # latex unicode support + 'test/testcases/block/04_header/with_auto_ids.text', # bc of Unicode characters + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_LATEX_FILES.any? {|f| text_file =~ /#{f}$/ } + define_method('test_' + text_file.tr('.', '_') + "_to_latex_compilation") do + latex = Kramdown::Document.new(File.read(text_file), auto_ids: false, footnote_nr: 1, + template: 'document').to_latex + Dir.mktmpdir do |tmpdir| + result = IO.popen("latex -output-directory='#{tmpdir}' 2>/dev/null", 'r+') do |io| + io.write(latex) + io.close_write + io.read + end + assert($?.exitstatus == 0, result.scan(/^!(.*\n.*)/).join("\n")) + end + end + end + end + + # Generate test methods for text->kramdown->html conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping text->kramdown->html tests because tidy executable is missing") + else + EXCLUDE_TEXT_FILES = [ + 'test/testcases/span/05_html/markdown_attr.text', # bc of markdown attr + 'test/testcases/block/09_html/markdown_attr.text', # bc of markdown attr + 'test/testcases/span/extension/options.text', # bc of parse_span_html option + 'test/testcases/block/12_extension/options.text', # bc of options option + 'test/testcases/block/12_extension/options3.text', # bc of options option + 'test/testcases/block/09_html/content_model/tables.text', # bc of parse_block_html option + 'test/testcases/block/09_html/html_to_native/header.text', # bc of auto_ids option that interferes + 'test/testcases/block/09_html/html_to_native/table_simple.text', # bc of tr style attr getting removed + 'test/testcases/block/09_html/simple.text', # bc of webgen:block elements + 'test/testcases/block/11_ial/simple.text', # bc of change of ordering of attributes in header + 'test/testcases/span/extension/comment.text', # bc of comment text modifications (can this be avoided?) + 'test/testcases/block/04_header/header_type_offset.text', # bc of header_offset being applied twice + 'test/testcases/block/06_codeblock/rouge/simple.text', + 'test/testcases/block/06_codeblock/rouge/multiple.text', # check, what document contain more, than one code block + 'test/testcases/block/14_table/empty_tag_in_cell.text', # bc of tidy + 'test/testcases/span/01_link/link_defs_with_ial.text', # bc of attribute ordering + 'test/testcases/span/05_html/mark_element.text', # bc of tidy + 'test/testcases/block/09_html/xml.text', # bc of tidy + 'test/testcases/span/05_html/xml.text', # bc of tidy + 'test/testcases/block/03_paragraph/standalone_image.text', # bc of standalone image + 'test/testcases/cjk-line-break.text', + 'test/testcases/block/09_html/standalone_image_in_div.html', # bc of standalone image + 'test/testcases/span/abbreviations/abbrev_in_html.text', # bc of invalid abbr tag in SVG + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_TEXT_FILES.any? {|f| text_file =~ /#{f}$/ } + html_file = text_file.sub(/\.text$/, '.html') + next unless File.exist?(html_file) + define_method('test_' + text_file.tr('.', '_') + "_to_kramdown_to_html") do + opts_file = text_file.sub(/\.text$/, '.options') + opts_file = File.join(File.dirname(text_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + kdtext = Kramdown::Document.new(File.read(text_file), options).to_kramdown + html = Kramdown::Document.new(kdtext, options).to_html + assert_equal(tidy_output(File.read(html_file)), tidy_output(html)) + kdtext4 = Kramdown::Document.new(File.read(text_file), options.merge({list_indent: 4})).to_kramdown + html = Kramdown::Document.new(kdtext4, options).to_html + assert_equal(tidy_output(File.read(html_file)), tidy_output(html)) + end + end + end + + # Generate test methods for html-to-kramdown-to-html conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping html-to-kramdown-to-html tests because tidy executable is missing") + else + EXCLUDE_HTML_KD_FILES = [ + 'test/testcases/span/extension/options.html', # bc of parse_span_html option + 'test/testcases/span/05_html/normal.html', # bc of br tag before closing p tag + 'test/testcases/block/12_extension/nomarkdown.html', # bc of nomarkdown extension + 'test/testcases/block/12_extension/options3.html', # bc of rouge + 'test/testcases/block/09_html/simple.html', # bc of webgen:block elements + 'test/testcases/block/09_html/markdown_attr.html', # bc of markdown attr + 'test/testcases/block/09_html/html_to_native/table_simple.html', # bc of invalidly converted simple table + 'test/testcases/block/06_codeblock/whitespace.html', # bc of entity to char conversion + 'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/guess_lang_css_class.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/highlighting-opts.html', # bc of span elements inside code element + 'test/testcases/block/11_ial/simple.html', # bc of change of ordering of attributes in header + 'test/testcases/span/03_codespan/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option + 'test/testcases/block/04_header/header_type_offset.html', # bc of header_offset option + 'test/testcases/block/16_toc/toc_exclude.html', # bc of different attribute ordering + 'test/testcases/span/autolinks/url_links.html', # bc of quot entity being converted to char + 'test/testcases/block/14_table/empty_tag_in_cell.html', # bc of tidy + 'test/testcases/span/01_link/link_defs_with_ial.html', # bc of attribute ordering + 'test/testcases/span/05_html/mark_element.html', # bc of tidy + 'test/testcases/block/09_html/xml.html', # bc of tidy + 'test/testcases/span/05_html/xml.html', # bc of tidy + 'test/testcases/block/03_paragraph/standalone_image.html', # bc of standalone image + 'test/testcases/block/15_math/normal.html', # bc of mathjax and HTML parser + 'test/testcases/block/15_math/gh_128.html', # bc of mathjax and HTML parser + 'test/testcases/span/04_footnote/backlink_inline.html', # bc of mathjax + 'test/testcases/block/09_html/standalone_image_in_div.html', # bc of standalone image + 'test/testcases/block/09_html/processing_instruction.html', # bc of PI + 'test/testcases/block/04_header/with_header_links.html', # bc of header_links option + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.html'].each do |html_file| + next if EXCLUDE_HTML_KD_FILES.any? {|f| html_file =~ /#{f}$/ } + define_method('test_' + html_file.tr('.', '_') + "_to_kramdown_to_html") do + kd = Kramdown::Document.new(File.read(html_file), input: 'html', + auto_ids: false, footnote_nr: 1).to_kramdown + opts_file = html_file.sub(/\.html$/, '.options') + opts_file = File.join(File.dirname(html_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(kd, options) + assert_equal(tidy_output(File.read(html_file)), tidy_output(doc.to_html)) + end + end + end + + # Generate test methods for text-manpage conversion + Dir[File.dirname(__FILE__) + '/testcases/man/**/*.text'].each do |text_file| + define_method('test_' + text_file.tr('.', '_') + "_to_man") do + man_file = text_file.sub(/\.text$/, '.man') + doc = Kramdown::Document.new(File.read(text_file)) + assert_equal(File.read(man_file), doc.to_man) + end + end + + EXCLUDE_MODIFY = [ + 'test/testcases/block/06_codeblock/rouge/multiple.text', # bc of HTMLFormater in options + 'test/testcases/block/04_header/with_header_links.text', # bc of header_links option + ].compact + + # Generate test methods for asserting that converters don't modify the document tree. + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + opts_file = text_file.sub(/\.text$/, '.options') + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + (Kramdown::Converter.constants.map(&:to_sym) - + [:Base, :RemoveHtmlTags, :MathEngine, :SyntaxHighlighter]).each do |conv_class| + next if EXCLUDE_MODIFY.any? {|f| text_file =~ /#{f}$/ } + define_method("test_whether_#{conv_class}_modifies_tree_with_file_#{text_file.tr('.', '_')}") do + doc = Kramdown::Document.new(File.read(text_file), options) + options_before = Marshal.load(Marshal.dump(doc.options)) + abbrev_proc = doc.root.options[:abbrev_defs].default_proc + doc.root.options[:abbrev_defs].default_proc = doc.root.options[:abbrev_attr].default_proc = nil + tree_before = Marshal.load(Marshal.dump(doc.root)) + doc.root.options[:abbrev_defs].default_proc = doc.root.options[:abbrev_attr].default_proc = + abbrev_proc + Kramdown::Converter.const_get(conv_class).convert(doc.root, doc.options) + assert_equal(options_before, doc.options) + assert_tree_not_changed(tree_before, doc.root) + end + end + end + + def assert_tree_not_changed(old, new) + assert_equal(old.type, new.type, "type mismatch") + if old.value.kind_of?(Kramdown::Element) + assert_tree_not_changed(old.value, new.value) + else + assert(old.value == new.value, "value mismatch") + end + assert_equal(old.attr, new.attr, "attr mismatch") + assert_equal(old.options, new.options, "options mismatch") + assert_equal(old.children.length, new.children.length, "children count mismatch") + + old.children.each_with_index do |child, index| + assert_tree_not_changed(child, new.children[index]) + end + end + +end diff --git a/bin/gems/kramdown-2.5.1/test/test_location.rb b/bin/gems/kramdown-2.5.1/test/test_location.rb new file mode 100644 index 00000000..d2642c78 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/test_location.rb @@ -0,0 +1,216 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown' + +Encoding.default_external = 'utf-8' + +describe 'location' do + # checks that +element+'s :location option corresponds to the location stored + # in the element.attr['class'] + def check_element_for_location(element) + if (match = /^line-(\d+)/.match(element.attr['class'] || '')) + expected_line = match[1].to_i + assert_equal(expected_line, element.options[:location]) + end + element.children.each do |child| + check_element_for_location(child) + end + end + + # Test cases consist of a kramdown string that uses IALs to specify the expected + # line numbers for a given element. + test_cases = { + 'autolink' => %(testing autolinks\n\n{:.line-3}), + 'blockquote' => %( + > block quote1 + > + > * {:.line-3} list item in block quote + > * {:.line-4} list item in block quote + > {:.line-3} + {:.line-1} + + > block quote2 + {:.line-8} + ), + 'codeblock' => %(\na para\n\n~~~~\ntest code 1\n~~~~\n{:.line-3}\n\n test code 2\n{:.line-8}\n), + 'codespan' => %(a para\n\nanother para ``{:.line-3} with code\n), + 'emphasis' => %( + para *span*{:.line-1} + {:.line-1} + + ## header *span*{:.line-4} + {:.line-4} + + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum *short span on single line*{:.line-11} + dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + *long span over multiple lines - proident, sunt in culpa qui officia deserunt + mollit anim id est laborum.*{:.line-13} + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + `code span`{:.line-18} + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + {:.line-7} + ), + 'header' => %( + # header1 + {:.line-1} + + ## header2 + {:.line-4} + + ## header3 + {:.line-7} + + header4 + ======= + {:.line-10} + + ^ + + header5 + ------- + {:.line-16} + ), + 'horizontal_rule' => %(\na para\n\n----\n{:.line-3}\n), + 'html_entity' => "a para\n\nanother para with &{:.line-3} html entity.\n", + 'link' => %( + a para + + This is [a link](http://rubyforge.org){:.line-3} to a page. + + Here comes a ![smiley](../images/smiley.png){:.line-5} + ), + 'list' => %( + * {:.line-1} list item + * {:.line-2} list item + * {:.line-3} list item + {:.line-1} + + {:.line-7} + 1. {:.line-7} list item + 2. {:.line-8} list item + 3. {:.line-9} list item + + {:.line-12} + definition term 1 + : {:.line-13} definition definition 1 + definition term 2 + : {:.line-15} definition definition 2 + ), + 'math_block' => %(\na para\n\n$$5+5$$\n{:.line-3}\n), + 'math_inline' => %(\na para\n\nanother para with inline math $$5+5$${:.line-3}\n), + 'paragraph' => %( + para1 + {:.line-1} + + para2 + {:.line-4} + + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + {:.line-7} + + {:.line-14} + para with leading IAL + ), + 'table' => %( + a para + + |first|second|third| + |-----|------|-----| + |a |b |c | + {:.line-3} + ), + 'typographic_symbol' => %( + a para + + another para ---{:.line-3} + + another para ...{:.line-5} + ), + 'gh issue 129' => %( + `|` + {:.line-1} + ), + 'gh issue 131' => %( + * {:.line-1} test + line 2 + * {:.line-3} second + * {:.line-4} third + * {:.line-5} * {:.line-5} one + * {:.line-6} two + ), + 'gh issue 158' => %( + 😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁 + {:.line-1} + + - {:.line-4} T + {:.line-4} + + # T + {:.line-7} + ), + 'gh issue 243 - HTML raw elements' => %( +
    +
  • Test
  • +
+ ), + } + test_cases.each do |name, test_string| + it "Handles #{name}" do + doc = Kramdown::Document.new(test_string.gsub(/^ /, '').strip) + check_element_for_location(doc.root) + end + end + + it 'adds location info to duplicate abbreviation definition warnings' do + test_string = %(This snippet contains a duplicate abbreviation definition + +*[duplicate]: The first definition +*[duplicate]: The second definition + ) + doc = Kramdown::Document.new(test_string.strip) + assert_equal(["Duplicate abbreviation ID 'duplicate' on line 4 - overwriting"], doc.warnings) + end + + it 'handles abbreviations' do + str = "This *is* ABC and\n**and** ABC second\nanother ABC\nas ABC as\nABC at the end.\n\n*[ABC]: ABC" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :abbreviation }.each_with_index do |e, i| + assert_equal(i + 1, e.options[:location]) + end + end + + it 'handles line breaks' do + str = "First \nsecond\\\\\nthird \n" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :br }.each_with_index do |e, i| + assert_equal(i + 1, e.options[:location]) + end + end + + it 'handles smart quotes' do + str = "This is 'first'\nand 'second' and\n'third'" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :smart_quote }.each_with_index do |e, i| + assert_equal(((i + 1) / 2.0).ceil, e.options[:location]) + end + end +end diff --git a/bin/gems/kramdown-2.5.1/test/test_string_scanner_kramdown.rb b/bin/gems/kramdown-2.5.1/test/test_string_scanner_kramdown.rb new file mode 100644 index 00000000..713c03c4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/test_string_scanner_kramdown.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown/utils/string_scanner' + +describe Kramdown::Utils::StringScanner do + [ + ["...........X............", [/X/], 1], + ["1\n2\n3\n4\n5\n6X", [/X/], 6], + ["1\n2\n3\n4\n5\n6X\n7\n8X", [/X/, /X/], 8], + [(".\n" * 1000) + 'X', [/X/], 1001], + ].each_with_index do |test_data, i| + test_string, scan_regexes, expect = test_data + it "computes the correct current_line_number for example ##{i + 1}" do + str_sc = Kramdown::Utils::StringScanner.new(test_string) + scan_regexes.each {|scan_re| str_sc.scan_until(scan_re) } + assert_equal(expect, str_sc.current_line_number) + end + end +end diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.html b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.text b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.text new file mode 100644 index 00000000..2cbdaa62 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/spaces.text @@ -0,0 +1,3 @@ + + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.html b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.text b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.text new file mode 100644 index 00000000..69d6a470 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/01_blank_line/tabs.text @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.html b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.text b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.text new file mode 100644 index 00000000..8d158026 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/beginning.text @@ -0,0 +1,3 @@ +^ + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.text new file mode 100644 index 00000000..db56ec3b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/end.text @@ -0,0 +1,3 @@ + + +^ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.html b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.text b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.text new file mode 100644 index 00000000..87210a14 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/02_eob/middle.text @@ -0,0 +1,5 @@ + + +^ + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html new file mode 100644 index 00000000..810cfc09 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html @@ -0,0 +1,18 @@ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +
This is a code block.
+
+ +

And this is another.

+ +

A para + with + mixed +indents. + and with much indent

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html.gfm b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html.gfm new file mode 100644 index 00000000..4440c62e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.html.gfm @@ -0,0 +1,18 @@ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +
This is a code block.
+
+ +

And this is another.

+ +

A para +
with +
mixed +
indents. +
and with much indent

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.text new file mode 100644 index 00000000..5849f5b7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/indented.text @@ -0,0 +1,19 @@ +This is a para. + + This is a para. + + This is a para. + + This is a para. + + This is a code block. + + + +And this is another. + +A para + with + mixed +indents. + and with much indent diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.html new file mode 100644 index 00000000..9bc47dbf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.html @@ -0,0 +1,9 @@ +

First line
+https://example.com

+ +

First line
+https://example.com

+ +

Last Line

+ +

Last Line\

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.text new file mode 100644 index 00000000..bbc4cc53 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/line_break_last_line.text @@ -0,0 +1,9 @@ +First line + + +First line\\ + + +Last Line + +Last Line\\ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.html new file mode 100644 index 00000000..6a209e21 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.html @@ -0,0 +1,5 @@ +

One paragraph +over + multiple lines.

+ +

Second one without newline.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.text new file mode 100644 index 00000000..7f1169d6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/no_newline_at_end.text @@ -0,0 +1,5 @@ + One paragraph +over + multiple lines. + +Second one without newline. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.html new file mode 100644 index 00000000..0d20e175 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.html @@ -0,0 +1 @@ +

This is just a normal paragraph.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.text new file mode 100644 index 00000000..0b01324f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/one_para.text @@ -0,0 +1 @@ +This is just a normal paragraph. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.html new file mode 100644 index 00000000..7faa971f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.html @@ -0,0 +1,13 @@ +

para

+ +
+ standalone image +
standalone image
+
+ +
+ standalone image +
standalone image
+
+ +

para

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.text new file mode 100644 index 00000000..3010140c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/standalone_image.text @@ -0,0 +1,9 @@ +para +{:standalone} + +![standalone image](some.jpg){:#id .class key="value" standalone} + +![standalone image](some.jpg){:#id .class key="value" standalone} +{:#block-id .block-class block-key="block-value"} + +para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.kramdown b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.kramdown new file mode 100644 index 00000000..2108d98d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.kramdown @@ -0,0 +1,7 @@ +aa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa +\: No definiion list + +a: + +*a*: + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.text new file mode 100644 index 00000000..031d2d18 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/to_kramdown.text @@ -0,0 +1,5 @@ +aa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa : No definiion list + +a: + +*a*: diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.html new file mode 100644 index 00000000..d6194ea9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.html @@ -0,0 +1,4 @@ +

This is just a normal paragraph. +That goes on to the second line.

+ +

Another paragraph.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.text new file mode 100644 index 00000000..b0c730db --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/two_para.text @@ -0,0 +1,4 @@ +This is just a normal paragraph. +That goes on to the second line. + +Another paragraph. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.html b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.html new file mode 100644 index 00000000..a8831e66 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.html @@ -0,0 +1 @@ +

some text

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.options b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.text b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.text new file mode 100644 index 00000000..e5fe18a6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/03_paragraph/with_html_to_native.text @@ -0,0 +1 @@ +

some text diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.html new file mode 100644 index 00000000..07041072 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.html @@ -0,0 +1,57 @@ +

This is a header

+ +

This is a header

+ +

This is a header

+ +

This is a header

+ +
This is a header
+ +
This is a header
+ +

Header

+

Header

+ +

Header

+
+

blockquote

+
+ +
header
+

paragraph

+ +
+

blockquote +### not a header

+
+ +

header

+ +

header

+ +

header

+ +

header #

+ +

header

+ +

#

+ +

#

+ +

Header

+ +

Header

+ +

Header

+ +

Header

+ +

Header {#9ab}

+ +

Header{#noid}

+ +

Header ##{#noid}

+ +

Last

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.text new file mode 100644 index 00000000..392b3f69 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header.text @@ -0,0 +1,54 @@ +# This is a header + +## This is a header + +### This is a header + +#### This is a header + +##### This is a header + +###### This is a header + +# Header +^ +# Header + +##Header ##### +> blockquote + +###### header +paragraph + +> blockquote +### not a header + +# header # + +# header# + +#header# + +# header \# + +# header + +# + +# + +### Header {#id} + +### Header ## {#Id} + +### Header ## {#id} + +### Header {#A-Za-z0-9_:t} + +### Header {#9ab} + +### Header{#noid} + +### Header ##{#noid} + +### Last diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.html new file mode 100644 index 00000000..9f49c3bf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.html @@ -0,0 +1 @@ +

header

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.text new file mode 100644 index 00000000..7b74be4d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/atx_header_no_newline_at_end.text @@ -0,0 +1 @@ +# header \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.html new file mode 100644 index 00000000..e031b9a6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.html @@ -0,0 +1,11 @@ +

Lorem ipsum

+ +

Lorem ipsum

+ +

Lorem ipsum

+ +
Lorem ipsum
+ +

Lorem ipsum

+ +

Lorem ipsum

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.kramdown b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.kramdown new file mode 100644 index 00000000..a77deb9b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.kramdown @@ -0,0 +1,12 @@ +## Lorem ipsum + +### Lorem ipsum + +#### Lorem ipsum + +###### Lorem ipsum + +## Lorem ipsum + +### Lorem ipsum + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.latex new file mode 100644 index 00000000..c9017e6e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.latex @@ -0,0 +1,12 @@ +\subsection*{Lorem ipsum} + +\subsubsection*{Lorem ipsum} + +\paragraph*{Lorem ipsum} + +\subparagraph*{Lorem ipsum} + +\subsection*{Lorem ipsum} + +\subsubsection*{Lorem ipsum} + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.options b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.options new file mode 100644 index 00000000..a8050358 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.options @@ -0,0 +1,2 @@ +:header_offset: 1 +:auto_ids: false \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.text new file mode 100644 index 00000000..bfaefa28 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/header_type_offset.text @@ -0,0 +1,13 @@ +# Lorem ipsum + +## Lorem ipsum + +### Lorem ipsum + +###### Lorem ipsum + +Lorem ipsum +=========== + +Lorem ipsum +----------- diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.html new file mode 100644 index 00000000..147c3451 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.html @@ -0,0 +1,32 @@ +

test

+ +

test2

+ +

test

+

para

+ +
   header =
+
+ +

=

+ +

This is a para. +With two lines. +And not a header. +=================

+ +
+

Blockquote. +Not a Header +-

+
+ +

header

+ +

header

+ +

header

+ +

header{#noid}

+ +

header

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.text new file mode 100644 index 00000000..ae94ecd8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header.text @@ -0,0 +1,39 @@ +test +- + +test2 +========= + +test +- +para + + header += + + += + +This is a para. +With two lines. +And not a header. +================= + +> Blockquote. +Not a Header +- + +header {#id} +------------ + +header {#Id} +====== + +header {#A-Za-z0-9_:} +------ + +header{#noid} +----- + +header +------ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.html new file mode 100644 index 00000000..9f49c3bf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.html @@ -0,0 +1 @@ +

header

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.text new file mode 100644 index 00000000..0f00750a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/setext_header_no_newline_at_end.text @@ -0,0 +1,2 @@ +header +====== \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.html new file mode 100644 index 00000000..724d391b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.html @@ -0,0 +1,3 @@ +

Header 1

+ +

123

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.options b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.options new file mode 100644 index 00000000..83305cbe --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.options @@ -0,0 +1,2 @@ +:auto_ids: true +:auto_id_prefix: hallo_ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.text new file mode 100644 index 00000000..acf09fe4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_prefix.text @@ -0,0 +1,3 @@ +# Header 1 + +# 123 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.html new file mode 100644 index 00000000..1d342cd6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.html @@ -0,0 +1 @@ +

This is a header

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.options b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.options new file mode 100644 index 00000000..68800f69 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.options @@ -0,0 +1 @@ +:auto_id_stripping: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.text new file mode 100644 index 00000000..2b57bc8d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_id_stripping.text @@ -0,0 +1 @@ +# This is a header diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.html new file mode 100644 index 00000000..af8126d5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.html @@ -0,0 +1,21 @@ +

This is a header

+ +

12. Another one-1-here

+ +

Do ^& it now

+ +

Hallo

+ +

Not now

+ +

Hallo

+ +

23232

+ +

33333

+ +

hallO

+ +

Header without ID

+ +

Transliterated: Đây-là-ví-dụ

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.options b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.options new file mode 100644 index 00000000..0a1fec87 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.options @@ -0,0 +1,2 @@ +:auto_ids: true +:transliterated_header_ids: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.text new file mode 100644 index 00000000..f4cd91b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_auto_ids.text @@ -0,0 +1,24 @@ +# This is a header + +## 12. Another one-1-here + +### Do ^& it now + +Hallo +===== + +Not now +------- + +# Hallo + +# 23232 + +# 33333 + +## hallO + +# Header without ID +{: id=""} + +# Transliterated: Đây-là-ví-dụ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.html new file mode 100644 index 00000000..64ae37f4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.html @@ -0,0 +1,7 @@ +

This is a header

+ +

12. Another one-1-here

+ +

Do ^& it now

+ +

Header without ID

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.options b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.options new file mode 100644 index 00000000..87f9047c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.options @@ -0,0 +1,2 @@ +:header_links: true +:auto_ids: false diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.text new file mode 100644 index 00000000..0166e29f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_header_links.text @@ -0,0 +1,8 @@ +# This is a header {#header} + +## 12. Another one-1-here + +### Do ^& it now + +# Header without ID +{: id=""} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.html b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.html new file mode 100644 index 00000000..880dc9e4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.html @@ -0,0 +1 @@ +

foo
bar

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.text b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.text new file mode 100644 index 00000000..c7fe2ab0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/04_header/with_line_break.text @@ -0,0 +1 @@ +# foo
bar diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.html new file mode 100644 index 00000000..734bb7a1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.html @@ -0,0 +1,25 @@ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
> A codeblock
+
+ +
+

Blockquote +with +mixed +indents.

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.text new file mode 100644 index 00000000..70850b0d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/indented.text @@ -0,0 +1,14 @@ +> A normal blockquote. + + > A normal blockquote. + + > A normal blockquote. + + > A normal blockquote. + + > A codeblock + +> Blockquote + > with + >mixed +> indents. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.html new file mode 100644 index 00000000..00a21024 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.html @@ -0,0 +1,34 @@ +
+

This is a long +long line.

+
+ +
+
+

Nested quote +inside +still inside

+
+
+ +
+
+

This is a subquote. +over multipline lines. +continuing +here

+
+
+ +
+

This is a quote + no code

+
+ +
+

This is a quote

+
+ +
+

This is a quote

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.text new file mode 100644 index 00000000..adde6a67 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/lazy.text @@ -0,0 +1,20 @@ +> This is a long +long line. + +> > Nested quote +inside +> still inside + +> > This is a subquote. +> > over multipline lines. +> continuing +here + +> This is a quote + no code + +> This is a quote +{: #id} + +> This is a quote +^ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.html new file mode 100644 index 00000000..4bc94f08 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.html @@ -0,0 +1,10 @@ +
+

foo

+ +
+

bar + baz

+
+ +

foo

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.text new file mode 100644 index 00000000..2176882c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/nested.text @@ -0,0 +1,6 @@ +> foo +> +> > bar +>> baz +> +> foo diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.html new file mode 100644 index 00000000..1de4a60f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.html @@ -0,0 +1,4 @@ +
+

This is a block quote +with no newline.

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.text new file mode 100644 index 00000000..402648ad --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/no_newline_at_end.text @@ -0,0 +1,2 @@ +> This is a block quote +> with no newline. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.html new file mode 100644 index 00000000..4a9aaf5e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.html @@ -0,0 +1,3 @@ +
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.text new file mode 100644 index 00000000..a2b33bdf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/very_long_line.text @@ -0,0 +1 @@ +> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.html b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.html new file mode 100644 index 00000000..30abd99e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.html @@ -0,0 +1,15 @@ +
+

Example:

+ +
sub status {
+    print "working";
+}
+
+ +

Or:

+ +
sub status {
+    return "working";
+}
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.text b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.text new file mode 100644 index 00000000..3b188dd4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/05_blockquote/with_code_blocks.text @@ -0,0 +1,11 @@ +>Example: +> +> sub status { +> print "working"; +> } +> +> Or: +> +> sub status { +> return "working"; +> } diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.html new file mode 100644 index 00000000..142a5d34 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.html @@ -0,0 +1,4 @@ +
x = Class.new
+
+
<a>href</a>
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.options new file mode 100644 index 00000000..72e9bc1e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.options @@ -0,0 +1 @@ +:enable_coderay: false diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.text new file mode 100644 index 00000000..af4d0bde --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/disable-highlighting.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: lang="html"} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.html new file mode 100644 index 00000000..d9f9da32 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.html @@ -0,0 +1,4 @@ +

Some para

+ +

~~~~~~ +not codeblock

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.text new file mode 100644 index 00000000..60ea366c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/error.text @@ -0,0 +1,4 @@ +Some para + +~~~~~~ +not codeblock diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.html new file mode 100644 index 00000000..066e909f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.html @@ -0,0 +1,15 @@ +
class Foo
+  def bar
+    puts 'Hello'
+  end
+end
+
+
+ +
class Foo
+  def bar
+    puts 'Hello'
+  end
+end
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.options new file mode 100644 index 00000000..bfc92f45 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.options @@ -0,0 +1,2 @@ +:syntax_highlighter_opts: + guess_lang: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.text new file mode 100644 index 00000000..4b074a8a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/guess_lang_css_class.text @@ -0,0 +1,13 @@ +~~~ +class Foo + def bar + puts 'Hello' + end +end +~~~ + + class Foo + def bar + puts 'Hello' + end + end diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex new file mode 100644 index 00000000..a092a1f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex @@ -0,0 +1,9 @@ +\begin{minted}[breaklines,linenos]{ruby} +x = Class.new + +\end{minted} + +\begin{minted}[breaklines,linenos]{html} +this is a reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, long link + +\end{minted} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options new file mode 100644 index 00000000..b773fc8f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options @@ -0,0 +1,4 @@ +:syntax_highlighter: minted +:syntax_highlighter_opts: + wrap: true + line_numbers: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text new file mode 100644 index 00000000..26365189 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text @@ -0,0 +1,5 @@ + x = Class.new +{: .language-ruby} + + this is a reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, long link +{: .language-html} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.latex new file mode 100644 index 00000000..354d6ab9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.latex @@ -0,0 +1,8 @@ +\begin{minted}[]{ruby} +x = Class.new + +\end{minted} +\begin{minted}[]{html} +href + +\end{minted} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.options new file mode 100644 index 00000000..b2ee189a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.options @@ -0,0 +1,3 @@ +:syntax_highlighter: minted +:syntax_highlighter_opts: + default_lang: ruby diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-minted.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.html new file mode 100644 index 00000000..b694d375 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.html @@ -0,0 +1,6 @@ +
x = Class.new
+
+
+
<a>href</a>
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.options new file mode 100644 index 00000000..be21a32e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.options @@ -0,0 +1,7 @@ +:syntax_highlighter_opts: + block: + css: class + default_lang: ruby + wrap: span + line_numbers: null + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting-opts.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.html new file mode 100644 index 00000000..33dd015a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.html @@ -0,0 +1,5 @@ +
x = Class.new
+
+
<a>href</a>
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.options new file mode 100644 index 00000000..8133537d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.options @@ -0,0 +1,5 @@ +:coderay_default_lang: ruby +:coderay_wrap: span +:coderay_line_numbers: ~ +:coderay_css: class + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/highlighting.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.html new file mode 100644 index 00000000..b096a9ed --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.html @@ -0,0 +1,164 @@ + +

B

+ +
                       BBBBBBBB. 
+
+
+
+           BBBB BB BBBBBBBB BBBBB. BBBBBBB BB BBBBB BB BBB BBBB BBBBB BBB BBB BBBB BBB BBBBBBB BBB BBBBBBB. B BBB'B BBBBB BBBB BBB BBBB BBBBBBB BBBB BBBB BBBB BBBBBBBB.
+
+
+                BBB BBBBB BBBBB BBB BBBB BBBB BBBB, BBB BBBBB BB BBBBB BBB BB BBBBBB BBBB BBB BBBBB BBBB BB. BBBBB BBB BBBBB BBBBB BBB BBBB BB BBBB BBBB BBBBB.
+
+
+                         BBBB BBBBB, BBBBB, BBBBBBBB?
+
+                   BB BBB BB BBBB BBB BBBB BBB BBBBBB /BBB BB BBBBBBBBB BBBB BBBBBBB BBBBBB BB BBB. 
+
+
+                   BBBB BBBBBBBB BBB BBBB BB BBBBB BBB BBBBBB BBBB BBBBB BBBBBB BBBBBBBBB BBBB BB BBBBB......................................................................
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+              BBBBB B'B BBB BBBBB. BBBB BBBBB BBBBB. ( B BBBBB BBBBBBBBBB BBBBB BBBB'B BBBBB BBBBB. BBB BBBB BBBBB BBBB BBBB. BBBBBBB BBB BB BBBBBBB BBB BBB B BBBB BBBBBBBBBBBB. BBBBB BBBBB.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+             BBBB'B BB
+
+ +

.

+ +
        B BBB BBB BBB ? B. B BBB BBBBBB BBBB BBB BBBB. BBBBBBB BB BBBBBBB B BBBB BBBB BBB BBBBBB. 
+
+
+
+
+
+
+
+
+
+
+
+
+
+         BBBB BB 'BBBB' BBBB BBBBB.
+
+
+                           BBBBBBBB B BBBB BBBBBB BB BBBBBBBB BBB BBBBBBB BBBBBBB BBBBBBB. 
+
+
+     B BBBB BB BBBB. BBBBB BBBBBBBB. BBB BB BB. BB BB BBBB BB BBBBBBBBBB. BB BBBBBBBB BB BBBBBBBBB. 
+
+
+                     BBBBBBBB BB BBBB. BBBBBBB BBB BBBBB BBBBB BBBBB. B'BB BBBBBBB BB BBBBB BBBBB BBBBBBB BBB BBBBB. BBBB. 
+
+  B BBBBBB BBBB BB BBBB BBB. (BB BBB BBBBB BBBBB...............B)
+
+
+
+           BBBB!
+
+
+
+         BBBB BB BBB BBBBBBB BBBBBB.            B
+
+ +

B

+ +
     BBBBB BB/BBB BBBBB!  BBBB BBBB BBBBBBBBBBB 'BBB'B BBBBBB.' 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          BBBB BBBBBBB BBBB BB BBB BBBBBBBB BB BBBB BBBBBB BBB BBBBBBBBB BBBB. BBBBBBBB BBBBBBB BBBB BBBB BBBB BB BBBB BB BBBB BB BBBB B BBB BB BBBBB BBBBBB.  B BBBB BBBBBBB BB BBBB BBBBB B BBB BBBBBBB BB BBBBB BBBB. BBB BBBBBBB BBBB. B BBB BBBB BBBB B BBBB BBBBBB BBB B BBBBBB BBBBBB. BBB BB BBBBBB BBBBBB BBBBBBBBBB BB...BBBBB BBBB BBBB BB BBBBB. (BBBBBBB BBB BBBBBB BBB'B BBBB BBB BBBBB BBB BB BBBBB BBBBBBBBBBB  BBBBB B BBBB BBBB BBBBB. 
+
+
+
+
+
+
+
+
+
+BBBBB BB BB BBBB B'B BBBB BBBBB BBBBB BBB BB BBBBBB/BBB (BBBBB) BBBBBB BB. 
+                          BBBBBBBB. B BBB BBBB BB BB BBB/BBBBBB BBBBBB BBB BBBB BBBBBBBB BB BB B BBBBBB BBBBBB BBBBB. (BBB/B BBB BBBB BBBB...BBB BBB BBB BBBB BB BB B BBBB BB BBB BB? BBBBBBB B BBB B BBBB BBBBBBBB BBB B BBB BBB BBBBB BBBB BBB BBBB BB B BBBBBBBB BB BBBBB BB BB BBB BBBBB BBB BB BBBBB BBBBBBB B BBB BBBBBBB. BBBBBB (BBBBB) BBBB BBBBB BBBBBBB BBBBB BBBB BBBB BBB. 100 BBBBBB BB BBBBB. BBBB BBB BBB BBBBBB BBB BB. BBB BBBB BB BBB BBBBB! BBB BB BBBBBB BBBBB B BBB'B BBBBBBBBB BBBB BBB BBB. (BBBBBB BBBBBBB BB BBBB BBBBB (BBBBBB BBBBB BBBBB BBBBB.))
+
+
+    BBB B BBBBBBBBBBB BBBB BBB BB BBB. BBBBB BBB BBBBB B BBBB BBBBBB BBBBB BBB. BB BBBBBB BBB BBBB B BBB BB BBBBBBBB BBBBBB BBBB BBB B BBBBBB BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBBBBBB.
+
+
+
+
+
+
+
+
+
+
+
+           BBBBB!!!!!!!
+
+
+         B BBB BBBB BBBBBB BBBB BBBB BBBB B BBB BBBBB BBB BBBBB B BBBB BBBBBBB BB BB BBBB BBBBBBBBB. B BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBB.
+
+                                               BB BB, BB BBBBBB BBBB, (BBBBBB BB BBB BBBB . BBBBB BB BBBB BBBB BB BB BBBB BBBB B BBBB BB BB (BB BBBB BB BBB BBBBBBB BB BBBBBBB. )) BB'BB BBB BBB'B BB BB BBBB BB B BBBB B BBBBB (BB BBBBBB BB BBB B'BB BBBBBBBB BB BBBB BBBB.)
+
+
+  B BBBBB B'BB BBB BB BBBB BBB BBB.
+
+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.test b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.test new file mode 100644 index 00000000..87f81c91 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/issue_gh45.test @@ -0,0 +1,188 @@ + + + B + + + + + BBBBBBBB. + + + + BBBB BB BBBBBBBB BBBBB. BBBBBBB BB BBBBB BB BBB BBBB BBBBB BBB BBB BBBB BBB BBBBBBB BBB BBBBBBB. B BBB'B BBBBB BBBB BBB BBBB BBBBBBB BBBB BBBB BBBB BBBBBBBB. + + + BBB BBBBB BBBBB BBB BBBB BBBB BBBB, BBB BBBBB BB BBBBB BBB BB BBBBBB BBBB BBB BBBBB BBBB BB. BBBBB BBB BBBBB BBBBB BBB BBBB BB BBBB BBBB BBBBB. + + + BBBB BBBBB, BBBBB, BBBBBBBB? + + BB BBB BB BBBB BBB BBBB BBB BBBBBB /BBB BB BBBBBBBBB BBBB BBBBBBB BBBBBB BB BBB. + + + BBBB BBBBBBBB BBB BBBB BB BBBBB BBB BBBBBB BBBB BBBBB BBBBBB BBBBBBBBB BBBB BB BBBBB...................................................................... + + + + + + + + + + + + + + + + + + + + + + BBBBB B'B BBB BBBBB. BBBB BBBBB BBBBB. ( B BBBBB BBBBBBBBBB BBBBB BBBB'B BBBBB BBBBB. BBB BBBB BBBBB BBBB BBBB. BBBBBBB BBB BB BBBBBBB BBB BBB B BBBB BBBBBBBBBBBB. BBBBB BBBBB.) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BBBB'B BB + + + + + + + + + + + + + + + + + + +. + + B BBB BBB BBB ? B. B BBB BBBBBB BBBB BBB BBBB. BBBBBBB BB BBBBBBB B BBBB BBBB BBB BBBBBB. + + + + + + + + + + + + + + BBBB BB 'BBBB' BBBB BBBBB. + + + BBBBBBBB B BBBB BBBBBB BB BBBBBBBB BBB BBBBBBB BBBBBBB BBBBBBB. + + + B BBBB BB BBBB. BBBBB BBBBBBBB. BBB BB BB. BB BB BBBB BB BBBBBBBBBB. BB BBBBBBBB BB BBBBBBBBB. + + + BBBBBBBB BB BBBB. BBBBBBB BBB BBBBB BBBBB BBBBB. B'BB BBBBBBB BB BBBBB BBBBB BBBBBBB BBB BBBBB. BBBB. + + B BBBBBB BBBB BB BBBB BBB. (BB BBB BBBBB BBBBB...............B) + + + + BBBB! + + + + BBBB BB BBB BBBBBBB BBBBBB. +B + +B + + + + BBBBB BB/BBB BBBBB! BBBB BBBB BBBBBBBBBBB 'BBB'B BBBBBB.' + + + + + + + + + + + + + + + BBBB BBBBBBB BBBB BB BBB BBBBBBBB BB BBBB BBBBBB BBB BBBBBBBBB BBBB. BBBBBBBB BBBBBBB BBBB BBBB BBBB BB BBBB BB BBBB BB BBBB B BBB BB BBBBB BBBBBB. B BBBB BBBBBBB BB BBBB BBBBB B BBB BBBBBBB BB BBBBB BBBB. BBB BBBBBBB BBBB. B BBB BBBB BBBB B BBBB BBBBBB BBB B BBBBBB BBBBBB. BBB BB BBBBBB BBBBBB BBBBBBBBBB BB...BBBBB BBBB BBBB BB BBBBB. (BBBBBBB BBB BBBBBB BBB'B BBBB BBB BBBBB BBB BB BBBBB BBBBBBBBBBB BBBBB B BBBB BBBB BBBBB. + + + + + + + + + + BBBBB BB BB BBBB B'B BBBB BBBBB BBBBB BBB BB BBBBBB/BBB (BBBBB) BBBBBB BB. + BBBBBBBB. B BBB BBBB BB BB BBB/BBBBBB BBBBBB BBB BBBB BBBBBBBB BB BB B BBBBBB BBBBBB BBBBB. (BBB/B BBB BBBB BBBB...BBB BBB BBB BBBB BB BB B BBBB BB BBB BB? BBBBBBB B BBB B BBBB BBBBBBBB BBB B BBB BBB BBBBB BBBB BBB BBBB BB B BBBBBBBB BB BBBBB BB BB BBB BBBBB BBB BB BBBBB BBBBBBB B BBB BBBBBBB. BBBBBB (BBBBB) BBBB BBBBB BBBBBBB BBBBB BBBB BBBB BBB. 100 BBBBBB BB BBBBB. BBBB BBB BBB BBBBBB BBB BB. BBB BBBB BB BBB BBBBB! BBB BB BBBBBB BBBBB B BBB'B BBBBBBBBB BBBB BBB BBB. (BBBBBB BBBBBBB BB BBBB BBBBB (BBBBBB BBBBB BBBBB BBBBB.)) + + + BBB B BBBBBBBBBBB BBBB BBB BB BBB. BBBBB BBB BBBBB B BBBB BBBBBB BBBBB BBB. BB BBBBBB BBB BBBB B BBB BB BBBBBBBB BBBBBB BBBB BBB B BBBBBB BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBBBBBB. + + + + + + + + + + + + BBBBB!!!!!!! + + + B BBB BBBB BBBBBB BBBB BBBB BBBB B BBB BBBBB BBB BBBBB B BBBB BBBBBBB BB BB BBBB BBBBBBBBB. B BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBB. + + BB BB, BB BBBBBB BBBB, (BBBBBB BB BBB BBBB . BBBBB BB BBBB BBBB BB BB BBBB BBBB B BBBB BB BB (BB BBBB BB BBB BBBBBBB BB BBBBBBB. )) BB'BB BBB BBB'B BB BB BBBB BB B BBBB B BBBBB (BB BBBBBB BB BBB B'BB BBBBBBBB BB BBBB BBBB.) + + + B BBBBB B'BB BBB BB BBBB BBB BBB. + + + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.html new file mode 100644 index 00000000..47188f2e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.html @@ -0,0 +1,4 @@ +
This is some code
+
+This is some  other code
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.text new file mode 100644 index 00000000..2a95de65 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/lazy.text @@ -0,0 +1,5 @@ + This is some +code + + This is some + other code diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.html new file mode 100644 index 00000000..7a003b28 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.html @@ -0,0 +1,2 @@ +
test  
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.text new file mode 100644 index 00000000..b64563f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end.text @@ -0,0 +1 @@ + test \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.html new file mode 100644 index 00000000..005870eb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.html @@ -0,0 +1,2 @@ +
test   test
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.text new file mode 100644 index 00000000..65df71e8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/no_newline_at_end_1.text @@ -0,0 +1,2 @@ + test +test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.html new file mode 100644 index 00000000..0bd2c1f4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.html @@ -0,0 +1,13 @@ +
starting code
+
+ +

paragraph

+ +
other code  
+with samples 
+
+ +

paragraph

+ +
  ending code
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.text new file mode 100644 index 00000000..40ea7023 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/normal.text @@ -0,0 +1,10 @@ + starting code + +paragraph + + other code + with samples + +paragraph + + ending code diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.html new file mode 100644 index 00000000..2cc34d30 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.html @@ -0,0 +1,2 @@ +
x = Class.new
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.options new file mode 100644 index 00000000..5688828c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + block: + disable: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.text new file mode 100644 index 00000000..0e50b41c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/disabled.text @@ -0,0 +1 @@ + x = Class.new diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.html new file mode 100644 index 00000000..6ece5432 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.html @@ -0,0 +1,11 @@ +
puts "Hello"
+
+
+ +
puts "World"
+
+
+ +
$foo = new Bar;
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.options new file mode 100644 index 00000000..b910f756 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + default_lang: ruby + formatter: RougeHTMLFormatters diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.text new file mode 100644 index 00000000..d1dd283b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/multiple.text @@ -0,0 +1,11 @@ +~~~ ruby +puts "Hello" +~~~ + +~~~ ruby +puts "World" +~~~ + +~~~ php?start_inline=1 +$foo = new Bar; +~~~ \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.html new file mode 100644 index 00000000..1c2259af --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.html @@ -0,0 +1,10 @@ +
x = Class.new
+
+
+
<a>href</a>
+
+
+ +
$foo = new Bar;
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.options new file mode 100644 index 00000000..f59e0ff8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.options @@ -0,0 +1,3 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + default_lang: ruby diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.text new file mode 100644 index 00000000..6c740e53 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/rouge/simple.text @@ -0,0 +1,9 @@ + x = Class.new +^ + href +{: .language-html} + + +~~~ php?start_inline=1 +$foo = new Bar; +~~~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.html new file mode 100644 index 00000000..1ddd91e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.html @@ -0,0 +1,7 @@ +
Here comes some code.
+
+ +
~~~~~~~
+code with tildes
+~~~~~~~~
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.text new file mode 100644 index 00000000..7625a1bd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/tilde_syntax.text @@ -0,0 +1,9 @@ +~~~~~~~~ +Here comes some code. +~~~~~~~~ + +~~~~~~~~~~~~ +~~~~~~~ +code with tildes +~~~~~~~~ +~~~~~~~~~~~~~~~~~~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.html new file mode 100644 index 00000000..dcbb40f3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.html @@ -0,0 +1,3 @@ +
This	is⋅some⋅⋅
+⋅⋅⋅⋅whitespace⋅⋅
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.text new file mode 100644 index 00000000..b15c9c9a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/whitespace.text @@ -0,0 +1,3 @@ + This is some + whitespace +{:.show-whitespaces} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.html new file mode 100644 index 00000000..f7c20b2b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.html @@ -0,0 +1,13 @@ +

paragraph

+ +
code block
+
+continued here
+
+ +

ended

+ +
next blank line has 4 spaces
+
+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.text new file mode 100644 index 00000000..e51dfa53 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_blank_line.text @@ -0,0 +1,12 @@ +paragraph + + code block + + continued here + + +ended + + next blank line has 4 spaces + +paragraph diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.html new file mode 100644 index 00000000..cca17a20 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.html @@ -0,0 +1,6 @@ +
code block
+
+continued here
+
+
new block here
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.text new file mode 100644 index 00000000..834c768f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_eob_marker.text @@ -0,0 +1,5 @@ + code block + + continued here +^ + new block here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.html new file mode 100644 index 00000000..77085b30 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.html @@ -0,0 +1,6 @@ +
code block
+
+continued here
+
+
new block here
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.text new file mode 100644 index 00000000..4489f2d9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_ial.text @@ -0,0 +1,5 @@ + code block + + continued here +{:.cls} + new block here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html new file mode 100644 index 00000000..f5872c30 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html @@ -0,0 +1,24 @@ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options new file mode 100644 index 00000000..e2e91dba --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options @@ -0,0 +1,2 @@ +:syntax_highlighter: null + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text new file mode 100644 index 00000000..07f437e7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text @@ -0,0 +1,33 @@ +~~~ ruby +def what? + 42 +end +~~~ + +~~~ ruby +def what? + 42 +end +~~~ +{:.class1} + +~~~ +def what? + 42 +end +~~~ +{: .language-ruby} + +~~~ ruby +def what? + 42 +end +~~~ +{: .language-python} + +~~~ ruby +def what? + 42 +end +~~~ +{: class="language-python"} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html new file mode 100644 index 00000000..2530b1e0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html @@ -0,0 +1,8 @@ +
text
+
+ +
text
+
+ +
text
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options new file mode 100644 index 00000000..871923ca --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options @@ -0,0 +1,2 @@ +:enable_coderay: false + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text new file mode 100644 index 00000000..60424a02 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text @@ -0,0 +1,11 @@ +~~~ asn.1 +text +~~~ + +~~~ asn#w1 +text +~~~ + +~~~ русский +text +~~~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html new file mode 100644 index 00000000..aa4b60f2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html @@ -0,0 +1,3 @@ +
s1'dim'a'500'm'500'q'500''
+index'j'j+1'j-1''
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options new file mode 100644 index 00000000..871923ca --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options @@ -0,0 +1,2 @@ +:enable_coderay: false + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text new file mode 100644 index 00000000..423d5b73 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text @@ -0,0 +1,4 @@ +~~~ act-iii +s1'dim'a'500'm'500'q'500'' +index'j'j+1'j-1'' +~~~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.html b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.html new file mode 100644 index 00000000..068811c0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.html @@ -0,0 +1,7 @@ +

_ * _

+ +

— * * *

+ +

_ - *

+ +

———————————————- test

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.text b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.text new file mode 100644 index 00000000..a024710d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/error.text @@ -0,0 +1,7 @@ +_ * _ + +--- * * * + +_ - * + +---------------------------------------------- test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.html new file mode 100644 index 00000000..e74b6e6c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.html @@ -0,0 +1,19 @@ +
+
+
+ +

d- -

+ +
+
+
+ +

para

+

text

+ +
+ +
- - -
+
+ +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.text new file mode 100644 index 00000000..986101ab --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/normal.text @@ -0,0 +1,20 @@ +*** +* * * +- - - + +d- - + +--- +___ +*** + +para +----------- +text + +* * * + + - - - + +* * * +{:.test} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.html b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.html new file mode 100644 index 00000000..dbb86e58 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.text b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.text new file mode 100644 index 00000000..a5798b29 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/sepspaces.text @@ -0,0 +1,3 @@ +- - - +* * * +_ _ _ _ _ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.html b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.html new file mode 100644 index 00000000..dbb86e58 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.text b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.text new file mode 100644 index 00000000..464fe20c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/07_horizontal_rule/septabs.text @@ -0,0 +1,3 @@ +- - - +* * * +_ _ _ _ _ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.latex new file mode 100644 index 00000000..e71fde2a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.latex @@ -0,0 +1,3 @@ +\begin{itemize} +\item{} {[}and{]} another +\end{itemize} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.text new file mode 100644 index 00000000..515e3a7d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/brackets_in_item.text @@ -0,0 +1 @@ +* \[and\] another diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.html new file mode 100644 index 00000000..5a6ebb33 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.html @@ -0,0 +1,21 @@ +

I have read the book +1984. It was great +- other say that, too!

+ +

I have read the book +1984. It was great +- other say that, too!

+ +

I have read the book + 1984. It was great.

+ +

I have read the book 1984. + - it was great!

+ +

1984. Was great!

+ +

1984.5 is not a book.

+ +

1984.

+ +

- This too!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.text new file mode 100644 index 00000000..264dcfb3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/escaping.text @@ -0,0 +1,21 @@ +I have read the book +1984. It was great +- other say that, too! + +I have read the book +1984\. It was great +\- other say that, too! + +I have read the book + 1984. It was great. + +I have read the book 1984. + - it was great! + +1984\. Was great! + +1984.5 is not a book. + +1984\. + +\- This too! diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.html new file mode 100644 index 00000000..e6dfd3a5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.html @@ -0,0 +1,10 @@ +
    +
  • IAL at first +continued
  • +
  • another {:.cls}
  • +
  • IAL at last + code
  • +
  • X + test
  • +
  • X OK
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.text new file mode 100644 index 00000000..67bee706 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/item_ial.text @@ -0,0 +1,8 @@ +* {:.cls} IAL at first + continued +* another {:.cls} +* {:.cls} IAL at last + code +* {::nomarkdown type="html"}X{:/nomarkdown} + test +* {::nomarkdown type="html"}X{:/nomarkdown} OK diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.html new file mode 100644 index 00000000..01a5f9dd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.html @@ -0,0 +1,39 @@ +
    +
  • This is a simple +list item
  • +
  • +

    Followed by another +list item

    +
  • +
  • +

    Followed by

    + +

    a para list item +continued here

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para +continued here

    +
  • +
+ +

para

+ +
    +
  • multi line +list item
  • +
+ +

para

+ +
    +
  • list item line1 + one line + two lines
  • +
  • list item line2 +one line +two lines
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.text new file mode 100644 index 00000000..f372422a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy.text @@ -0,0 +1,29 @@ +* This is a simple +list item +* Followed by another +list item + + +* Followed by + + a para list item +continued here +* and a normal one +* and + + a para +continued here + +para + +* multi line +list item + +para + +* list item line1 + one line + two lines +* list item line2 + one line +two lines diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.html new file mode 100644 index 00000000..90c7447e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.html @@ -0,0 +1,9 @@ +
    +
  1. Root level + * Second level +
      +
    • Third level + * Back to second level
    • +
    +
  2. +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.text new file mode 100644 index 00000000..97a77558 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/lazy_and_nested.text @@ -0,0 +1,4 @@ +1. Root level + * Second level + * Third level + * Back to second level diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.html new file mode 100644 index 00000000..ecf51c76 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.html @@ -0,0 +1,9 @@ +
    +
  • Starting a list
  • +
+ +
+ +
    +
  • Starting a new list
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.text new file mode 100644 index 00000000..c7fcd47b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_hr.text @@ -0,0 +1,5 @@ +* Starting a list + +* * * + +* Starting a new list diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.html new file mode 100644 index 00000000..672428ed --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.html @@ -0,0 +1,40 @@ +
    +
  • list item
  • +
+ +
+

blockquote

+
+ +

para +* * * +para + - no list

+ +
    +
  • +

    item

    + +
    +

    block

    +
    + +

    header

    +
  • +
  • +

    test

    + +
    codeblock
    +
    + +

    test

    +
  • +
  • +

    test

    + +
    codeblock
    +
    + +

    test

    +
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.text new file mode 100644 index 00000000..f680262c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/list_and_others.text @@ -0,0 +1,26 @@ +* list item + +> blockquote + +para +* * * +para + - no list + ++ item + + > block + + ## header + +* test + + codeblock + + test + +* test + + codeblock + + test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.html new file mode 100644 index 00000000..9bc47e3b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.html @@ -0,0 +1,117 @@ +

With tabs/spaces, no paras:

+ +
    +
  • item1
  • +
  • item2
  • +
  • item3
  • +
+ +

With tabs/spaces, paras:

+ +
    +
  • +

    item1

    +
  • +
  • +

    item2

    +
  • +
  • +

    item3

    +
  • +
+ +

With tabs/spaces, no paras:

+ +
    +
  1. item1
  2. +
  3. item2
  4. +
  5. item3
  6. +
+ +

With tabs/spaces, paras:

+ +
    +
  1. +

    item1

    +
  2. +
  3. +

    item2

    +
  4. +
  5. +

    item3

    +
  6. +
+ +

Nested, without paras:

+ +
    +
  • item1 +
      +
    • item2 +
        +
      • item3
      • +
      +
    • +
    +
  • +
+ +

Nested, with paras:

+ +
    +
  • +

    item1

    + +
      +
    • item2 +
        +
      • item3 (level 3)
      • +
      +
    • +
    +
  • +
+ +

Ordered, without paras:

+ +
    +
  1. item1
  2. +
  3. item2 +
      +
    • do
    • +
    • it
    • +
    • now
    • +
    +
  4. +
  5. item3
  6. +
+ +

Ordered, with paras:

+ +
    +
  1. +

    item1

    +
  2. +
  3. +

    item2

    + +
      +
    • do
    • +
    • it
    • +
    • now
    • +
    +
  4. +
  5. +

    item3

    +
  6. +
+ +

Mixed tabs and spaces:

+ +
    +
  • some text +
      +
    • nested
    • +
    +
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.text new file mode 100644 index 00000000..22b578df --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/mixed.text @@ -0,0 +1,66 @@ +With tabs/spaces, no paras: + +* item1 ++ item2 +- item3 + +With tabs/spaces, paras: + +- item1 + +* item2 + ++ item3 + +With tabs/spaces, no paras: + +1. item1 +20. item2 +3. item3 + +With tabs/spaces, paras: + +1. item1 + +2. item2 + +3. item3 + +Nested, without paras: + +* item1 + * item2 + * item3 + +Nested, with paras: + ++ item1 + + * item2 + * item3 (level 3) + +Ordered, without paras: + +1. item1 +2. item2 + * do + * it + * now +3. item3 + +Ordered, with paras: + +1. item1 + +2. item2 + + * do + * it + * now + +3. item3 + +Mixed tabs and spaces: + +* some text + * nested diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.html new file mode 100644 index 00000000..1921ee9d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.html @@ -0,0 +1,17 @@ +
    +
  • some item +
      +
    • nested
    • +
    +
  • +
  • last item
  • +
+
    +
  • +

    some text

    + +
      +
    • nested
    • +
    +
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.text new file mode 100644 index 00000000..c71d864b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested.text @@ -0,0 +1,7 @@ +* some item + * nested +* last item +^ +* some text + + * nested diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.kramdown b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.kramdown new file mode 100644 index 00000000..dfede9b8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.kramdown @@ -0,0 +1,7 @@ +* First item + * Sub item 1 + * Sub sub item + * Sub item 2 +* Second item + * Sub item + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.text new file mode 100644 index 00000000..414afcc9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/nested_compact.text @@ -0,0 +1,6 @@ +* First item + * Sub item 1 + * Sub sub item + * Sub item 2 +* Second item + * Sub item diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.html new file mode 100644 index 00000000..3f4cd0f8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.html @@ -0,0 +1,39 @@ +
    +
  • +
    This is a code block.
    +
    +
  • +
  • +
    +

    This is a blockquote.

    +
    +
  • +
  • +

    A header

    +
  • +
+
    +
  • +
    This is a code block.
    +
    +
  • +
  • +
    +

    This is a blockquote. +continued by some para.

    +
    +
  • +
  • +

    A header

    +

    a para

    +
  • +
+
    +
  • +
      +
    • nested list
    • +
    • other nested item
    • +
    +
  • +
  • item 2
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.text new file mode 100644 index 00000000..321cef64 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/other_first_element.text @@ -0,0 +1,18 @@ +* + This is a code block. +* > This is a blockquote. +* ## A header +^ +* + This is a code block. + +* > This is a blockquote. + continued by some para. + +* A header + ========= + a para +^ +* * nested list + * other nested item +* item 2 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.html new file mode 100644 index 00000000..84e5a6ba --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.html @@ -0,0 +1,19 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    + +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    + +

    a para

    +
  10. +
+ +

para

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.text new file mode 100644 index 00000000..aaf7dae8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ol.text @@ -0,0 +1,13 @@ +1. This is a simple list item +3. Followed by another + + +10. Followed by + + a para list item +1. and a normal one +2. and + + a para + +para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.html new file mode 100644 index 00000000..68db05e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.html @@ -0,0 +1,48 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    + +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para

    +
  • +
+ +

para

+ +
    +
  • multi line +list item
  • +
+ +

para

+ +
    +
  • list item line1 +one line +two lines
  • +
  • list item line2 +one line +two lines
  • +
+ +

para

+ +
    +
  • list item line3 +one line +two lines
  • +
  • list item line4 + one line + two lines
  • +
+ +

para

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.text new file mode 100644 index 00000000..ccd25c35 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/simple_ul.text @@ -0,0 +1,36 @@ +* This is a simple list item +* Followed by another + + +* Followed by + + a para list item +* and a normal one +* and + + a para + +para + +* multi line + list item + +para + +* list item line1 + one line + two lines +* list item line2 + one line + two lines + +para + +* list item line3 + one line + two lines +* list item line4 + one line + two lines + +para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.html new file mode 100644 index 00000000..e0794614 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.html @@ -0,0 +1,3 @@ +
    +
  • single
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.text new file mode 100644 index 00000000..877d3699 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/single_item.text @@ -0,0 +1 @@ +* single diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.html b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.html new file mode 100644 index 00000000..e329931d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.html @@ -0,0 +1,72 @@ +
    +
  • +

    not a para +here

    + +
    +

    blockquote

    +
    +
  • +
  • +

    and not + here

    + +
    +

    blockquote

    +
    +
  • +
  • +

    this is a para

    +
  • +
  • +
    +

    blockquote

    +
    +
  • +
  • +

    this too

    +
  • +
+ +

A paragraph + 1. followed not by ol +- followed not by ul

+ +

A compact list:

+ +
    +
  • compact
  • +
  • list
  • +
  • items
  • +
+ +

A normal list:

+ +
    +
  • +

    not

    +
  • +
  • +

    compact

    +
  • +
  • +

    but here

    +
  • +
+ +

List item without content:

+ +
    +
  • +
  • a
  • +
+ +
    +
  • +
  • +

    one

    +
  • +
  • +

    two

    +
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.text b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.text new file mode 100644 index 00000000..7253f4a0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/08_list/special_cases.text @@ -0,0 +1,49 @@ +* not a para + here + + > blockquote + +* and not + here + + >blockquote + +* this is a para + +* > blockquote + +* this too + +^ + +A paragraph + 1. followed not by ol +- followed not by ul + +A compact list: + +* compact +* list +* items + +A normal list: + +* not + +* compact + +* but here + +List item without content: + +* +* a +^ + +* + +* one + +* two + +^ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.html new file mode 100644 index 00000000..43c82af3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.html @@ -0,0 +1,10 @@ +
++-----------------------+ +| Use XML, be Happy :-) | +|_______________________| + +
+ +

Inline section <goes> here.

+ +

Inline test *case* *section* <goes> here end.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.text new file mode 100644 index 00000000..a4de06fd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/cdata_section.text @@ -0,0 +1,10 @@ +
+
+ +Inline ]]> here. + +Inline test *case* ]]> here end. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.html new file mode 100644 index 00000000..8d31bd4e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.html @@ -0,0 +1,18 @@ + + +

para1

+ + + +

para2

+ + +

para

+ +
+

This is +

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.text new file mode 100644 index 00000000..b632bf29 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/comment.text @@ -0,0 +1,15 @@ + + +para1 + + + +para2 + + para + +> This is +> diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.html new file mode 100644 index 00000000..587d55af --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.html @@ -0,0 +1,6 @@ +
+
text
+
+

para

+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.text new file mode 100644 index 00000000..1e381d1f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/deflists.text @@ -0,0 +1,6 @@ +
+
*text*
+
+para +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.html new file mode 100644 index 00000000..e11dc14b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.html @@ -0,0 +1,14 @@ + + + + + + + + + +
Usage +Output +
Some data +

Some more

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.text new file mode 100644 index 00000000..c0cf2e7d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/content_model/tables.text @@ -0,0 +1,14 @@ + + + + + + + + + +
*Usage* +Output +
Some *data* +# Some more +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.html new file mode 100644 index 00000000..743c8224 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.html @@ -0,0 +1,15 @@ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.text new file mode 100644 index 00000000..44a060d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html5_attributes.text @@ -0,0 +1,15 @@ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.html new file mode 100644 index 00000000..f51c75bb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.html @@ -0,0 +1,7 @@ +

Para

+
division
+ +
+

Quote

+
+
division
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.text new file mode 100644 index 00000000..cdcbff6c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_after_block.text @@ -0,0 +1,5 @@ +Para +
division
+ +> Quote +
division
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.html new file mode 100644 index 00000000..93d695aa --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.html @@ -0,0 +1,15 @@ +

para

+ +
codeblock
+
+ +
+

test

+
+ +
<p>codeblock</p>
+
+ +
+

test

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.text new file mode 100644 index 00000000..a3cfda74 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_codeblocks.text @@ -0,0 +1,13 @@ +para + + codeblock + +
+ test +
+ +

codeblock

+ +
+ test +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.html new file mode 100644 index 00000000..65cb7e2b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.html @@ -0,0 +1,5 @@ +

header

+ +
+====== +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.text new file mode 100644 index 00000000..64dc477e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_and_headers.text @@ -0,0 +1,6 @@ +header +====== + +
+====== +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.html new file mode 100644 index 00000000..f4b32210 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.html @@ -0,0 +1,10 @@ +

This is a code span with <entities> that should be preserved. +This is a simple code span.

+ +

Some <

+ +
Some very important < thing
+
+ +
Some code<<
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.text new file mode 100644 index 00000000..fda7db54 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/code.text @@ -0,0 +1,9 @@ +This is a code span with <entities> that should be preserved. +This is a simple code span. + +

Some <

+ +
Some very important < thing
+ +
Some code<<
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.html new file mode 100644 index 00000000..dacd4373 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.html @@ -0,0 +1,7 @@ +
+ + +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.text new file mode 100644 index 00000000..1788630c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/comment.text @@ -0,0 +1,8 @@ +
+ + + +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.html new file mode 100644 index 00000000..e4389c06 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.html @@ -0,0 +1,6 @@ +

This is sizedhallo.

+ +

This is strongitalic, yes!.

+ +

This is not converted, as is + this.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.text new file mode 100644 index 00000000..7c75930c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/emphasis.text @@ -0,0 +1,6 @@ +This is sizedhallo. + +This is strongitalic, yes!. + +This is not converted, as is + this. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.html new file mode 100644 index 00000000..5c80ce6b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.html @@ -0,0 +1 @@ +

This is *raw* HTML text containing < entities!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.text new file mode 100644 index 00000000..5c80ce6b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/entity.text @@ -0,0 +1 @@ +

This is *raw* HTML text containing < entities!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.html new file mode 100644 index 00000000..aebb2065 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.html @@ -0,0 +1,6 @@ +

Some headerhere!

+

hallo

+

hallo

+

hallo

+
hallo
+
hallo
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.options new file mode 100644 index 00000000..987b4d99 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.options @@ -0,0 +1,2 @@ +:auto_ids: true +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.text new file mode 100644 index 00000000..27eed3b0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/header.text @@ -0,0 +1,6 @@ +

Some headerhere!

+

hallo

+

hallo

+

hallo

+
hallo
+
hallo
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.html new file mode 100644 index 00000000..6eaccfe3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.html @@ -0,0 +1,8 @@ +
+
kram
+
down
+
kram
+
down
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.text new file mode 100644 index 00000000..6eaccfe3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_dl.text @@ -0,0 +1,8 @@ +
+
kram
+
down
+
kram
+
down
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.html new file mode 100644 index 00000000..eeebdfbe --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.html @@ -0,0 +1,15 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    +

    a para

    +
  10. +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.text new file mode 100644 index 00000000..41246dfb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ol.text @@ -0,0 +1,17 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    + +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    + +

    a para

    +
  10. +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.html new file mode 100644 index 00000000..c9b38d08 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.html @@ -0,0 +1,19 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    +

    a para

    +
  • +
+ +
    +
  • multi line list item
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.text new file mode 100644 index 00000000..5a2d68e7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/list_ul.text @@ -0,0 +1,22 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    + +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para

    +
  • +
+ +
    +
  • multi line +list item
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.html new file mode 100644 index 00000000..a276b1ca --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.html @@ -0,0 +1,3 @@ +

Some text here and end

+ +

Some other text here

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.text new file mode 100644 index 00000000..b10035cd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/paragraph.text @@ -0,0 +1,4 @@ +

Some text here and end +

+ +

Some other text here

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.html new file mode 100644 index 00000000..bdd79ee7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.html @@ -0,0 +1,12 @@ + + + + + + + + + +
UsageOther
Some *data* +

Some more

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.text new file mode 100644 index 00000000..bdd79ee7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_normal.text @@ -0,0 +1,12 @@ + + + + + + + + + +
UsageOther
Some *data* +

Some more

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.html new file mode 100644 index 00000000..0567d738 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.html @@ -0,0 +1,64 @@ + + + + + + + + + + + +
UsageOutput
Some *data*Some more
+ + + + + + + + + + + + + + + + + + + + +
UsageOutput
Some *data*Some more
footlocker
+ + + + + + + + + + + + +
UsageOutput
Some *data*Some more
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.text new file mode 100644 index 00000000..7d294304 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/table_simple.text @@ -0,0 +1,74 @@ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + + + + + + + + + + + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
foot +locker +
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.html new file mode 100644 index 00000000..24439650 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.html @@ -0,0 +1 @@ +

This is … something “to remember”!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.text new file mode 100644 index 00000000..ee33c5ce --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/html_to_native/typography.text @@ -0,0 +1 @@ +

This is … something “to remember”!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.html new file mode 100644 index 00000000..77e0d78a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.html @@ -0,0 +1,5 @@ +

para

+ +

</div>

+ +

para

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.text new file mode 100644 index 00000000..f2fc834a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_1.text @@ -0,0 +1,5 @@ +para + +
+ +para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.html new file mode 100644 index 00000000..b5da12fe --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.html @@ -0,0 +1,5 @@ +

para

+ +
+ +

para

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.text new file mode 100644 index 00000000..675c94f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/invalid_html_2.text @@ -0,0 +1,5 @@ +para + +
+ +para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.html new file mode 100644 index 00000000..930b8f41 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.html @@ -0,0 +1,38 @@ +
+

para

+
+ +
+para +
+ +
+

para

+
+ +
+*para* +
+ +

+

para

+

+ +

+para +

+ +

+para +

+ +

+*para* +

+ +
+
emphasize
+
+

para

+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.text new file mode 100644 index 00000000..12e5aee6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/markdown_attr.text @@ -0,0 +1,38 @@ +
+*para* +
+ +
+*para* +
+ +
+*para* +
+ +
+*para* +
+ +

+*para* +

+ +

+*para* +

+ +

+*para* +

+ +

+*para* +

+ +
+
*emphasize*
+
+para +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.html new file mode 100644 index 00000000..90bda034 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.html @@ -0,0 +1,24 @@ +
+This is some text +
+ +
+This is some text +
+ +
+</p> +
+ +
+

Foo

+
+ +

This is some +text

+ +

http://example.com

+ +
+<http://example.com> +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.text new file mode 100644 index 00000000..1d1c71ca --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/not_parsed.text @@ -0,0 +1,24 @@ +
+This is some text +
+ +
+This is some text +
+ +
+

+
+ +
+

Foo

+
+ +

This is some +text

+ + + +
+ +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.html new file mode 100644 index 00000000..860f9b2f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.html @@ -0,0 +1,35 @@ +

baz { |qux| quux }

+ +

This is some para. +

+ + + + +

parsed +This too +

+ + + + + + + + + +

http://example.com

+ + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.htmlinput b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.htmlinput new file mode 100644 index 00000000..22b9ea5c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.htmlinput @@ -0,0 +1,34 @@ +

baz { |qux| quux }

+ +

This is some para. +

+ + + + +

parsed +This too +

+ + + + + + + + + +

http://example.com

+ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.text new file mode 100644 index 00000000..e0617c41 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_raw.text @@ -0,0 +1,33 @@ +

baz { |qux| quux }

+ +This is some para. + + + + +

*parsed* +This too +

+ + + + + + + + + + + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.html new file mode 100644 index 00000000..2a6191fb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.html @@ -0,0 +1,12 @@ +

This text +should be parsed +as span +

+ +

This produces `

+

` an unwanted result.</p>

+ +

This text too

+

+some text +

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.htmlinput b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.htmlinput new file mode 100644 index 00000000..4199b8b2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.htmlinput @@ -0,0 +1,12 @@ +

This text +should be parsed +as span +

+ +

This produces `

+

` an unwanted result.</p>

+ +

This text too

+

+some text +

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.text new file mode 100644 index 00000000..d07cf6d8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_as_span.text @@ -0,0 +1,9 @@ +

This *text +should* be parsed +as span +

+ +

This produces `

` an unwanted result.

+ +

This *text* too

+some text diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.html new file mode 100644 index 00000000..8de78c04 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.html @@ -0,0 +1,21 @@ +

+

test

+
+ +
+
test
+
+
+
test
+
+
+
+ +
+
code block with </div>
+
+
+ +
+

No matching end tag

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.text new file mode 100644 index 00000000..b8b18453 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/parse_block_html.text @@ -0,0 +1,17 @@ +
+ test +
+ +
+ test +
+ test +
+
+ +
+ code block with
+
+ +
+No matching end tag diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.html new file mode 100644 index 00000000..939b996b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.html @@ -0,0 +1,12 @@ +

<?xml version=”1.0”?>

+ +

para

+ +

<? test ?> para

+ +

other

+ +

<? +multiline text +is allowed +?>

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.text new file mode 100644 index 00000000..fcb866ff --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/processing_instruction.text @@ -0,0 +1,12 @@ + + +para + + para + +other + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.html new file mode 100644 index 00000000..0d926c5d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.html @@ -0,0 +1,60 @@ +
+

test

+
+ +

+para2 +

+ +
+

tes

+ +

test +weiter +

+
+ +

para4

+ +
+
+
+

foo

+
+
+
+
+

bar 

+
+
+ +

para5

+ +
+

id

+
+

test

+ +
+

hallo

+
+
+

hallo

+
+ +

para6

+ +
+
+

Another para.

+
+ +

Test

+ +

Test

+ +

Test + +

+ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.options b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.text new file mode 100644 index 00000000..a2ffe25e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/simple.text @@ -0,0 +1,55 @@ +
+test +
+ +

+para2 +

+ +
+

tes

+ +

test +weiter +

+
+ +para4 + +
+
+
+foo +
+
+
+
bar  +
+
+ +para5 + +
id +
test + +
+hallo +
+hallo +
+ +para6 + +
+Another para. +
+ +Test + +

Test

+ +

Test + +

+ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.htmlinput b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.htmlinput new file mode 100644 index 00000000..72ff4539 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.htmlinput @@ -0,0 +1,7 @@ +
+ inside +
+ +
+ text +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.text new file mode 100644 index 00000000..7f0d12cf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/standalone_image_in_div.text @@ -0,0 +1,8 @@ +
+![inside](src.png) +
+ +
+[text](website.html) +
+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.kramdown b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.kramdown new file mode 100644 index 00000000..f8d6802e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.kramdown @@ -0,0 +1,8 @@ + + + + + + +
test
+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.text new file mode 100644 index 00000000..32e01da5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/table.text @@ -0,0 +1,7 @@ + + + + + + +
test
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.html new file mode 100644 index 00000000..6f5693ed --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.html @@ -0,0 +1,8 @@ +

This is a

+ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.text new file mode 100644 index 00000000..a240f5c4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/textarea.text @@ -0,0 +1,8 @@ +This is a + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.html b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.html new file mode 100644 index 00000000..d941bc09 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.html @@ -0,0 +1,8 @@ + + +doit + +doit + +doit</some> + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.text b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.text new file mode 100644 index 00000000..6427fae3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/09_html/xml.text @@ -0,0 +1,7 @@ + + +doit + +doit + +doit diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.html new file mode 100644 index 00000000..74b03d58 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.html @@ -0,0 +1,2 @@ +

Some paragraph

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.text new file mode 100644 index 00000000..f58768a3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/10_ald/simple.text @@ -0,0 +1,8 @@ +Some paragraph + +{:id: ref1} +{:id: .class1} + {:id: #id} + {:id: key="value"} + {:id: .class2 .class3 ref2 #id-with key="value" key='value' key='dfsd\}' } +{:test: k ey=value} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.html new file mode 100644 index 00000000..9857a038 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.html @@ -0,0 +1 @@ +

A header

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.options b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.text new file mode 100644 index 00000000..f521fb0f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/auto_id_and_ial.text @@ -0,0 +1,2 @@ +## A header +{:#myid .cls} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.html b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.html new file mode 100644 index 00000000..84cc368d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.html @@ -0,0 +1,11 @@ +
+test +
+ +
+

test

+
+ +
+

para

+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.text b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.text new file mode 100644 index 00000000..827645cc --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/nested.text @@ -0,0 +1,15 @@ +{:.cls} +
+test +
+{:#id} + +{:.cls} +
+test +
+{:#id} + +{:.cls} +> para +{:#id} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.html new file mode 100644 index 00000000..1086f0cf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.html @@ -0,0 +1,29 @@ +

Some paragraph.

+ +

Some paragraph.

+ +
+

quote

+
+ +
    +
  • list
  • +
+ +
code block
+
+ +
other code block
+
+ +

A header

+ +

Some paragraph here

+ +

Some paragraph here

+ +

Paragraph

+

Paragraph

+ +

Another header

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.text new file mode 100644 index 00000000..b97eef3f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/11_ial/simple.text @@ -0,0 +1,41 @@ +Some paragraph. +{:.class .-class id key="val"} + +Some paragraph. +{:.cls1#id.cls2} + +> quote +{: #id} + {: .class} + +* list +{: key="val"} + + code block +{: #other} + + other code block + +## A header +{:#myid} + +{:.cls} +Some paragraph here + +{:.cls1} +{:.cls2} +Some paragraph here + +Paragraph +{:.cls} +Paragraph + +Another header +============== +{: .class #other} + +{:id: #id key="valo"} +{:id: #other .myclass other} +{:other: key1="val\"" - ig.nored as_is#this key2='val\'' .other-class} + +{:.invalid} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.html new file mode 100644 index 00000000..20b4c662 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.html @@ -0,0 +1,8 @@ +

This is a simple paragraph.

+ + + +

And another paragraph

+ +

{::comment} +Another paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.text new file mode 100644 index 00000000..2dfc9197 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/comment.text @@ -0,0 +1,12 @@ +This is a simple paragraph. + +{::comment} +This is a comment {:/}which is {:/comment} ignored. +{:/comment} + +And another paragraph + +{::comment this='is' .ignore /} + +{::comment} +Another paragraph diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.html new file mode 100644 index 00000000..17aae5cd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.html @@ -0,0 +1,8 @@ +

paragraph

+ +

{::something} +anotherthing +{:/something}

+ +

{::something/} +paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.text new file mode 100644 index 00000000..ae94a8fe --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/ignored.text @@ -0,0 +1,8 @@ +paragraph + +{::something} +anotherthing +{:/something} + +{::something/} +paragraph diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.html new file mode 100644 index 00000000..7fe58d50 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.html @@ -0,0 +1,10 @@ +

This is a simple paragraph.

+ +This *is* not processed + +

And another paragraph

+ +bold + +

{::nomarkdown} +Another paragraph

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.kramdown b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.kramdown new file mode 100644 index 00000000..2cee5122 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.kramdown @@ -0,0 +1,20 @@ +This is a simple paragraph. + +{::nomarkdown} +This *is* not processed +{:/} + +And another paragraph + +{::nomarkdown type="html"} +bold +{:/} + +{::nomarkdown type="latex"} +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} +{:/} + +\{::nomarkdown} Another paragraph + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.latex new file mode 100644 index 00000000..5af0263c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.latex @@ -0,0 +1,13 @@ +This is a simple paragraph. + +This *is* not processed + +And another paragraph + +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} + +\{::nomarkdown\} +Another paragraph + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.text new file mode 100644 index 00000000..43d441df --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/nomarkdown.text @@ -0,0 +1,21 @@ +This is a simple paragraph. + +{::nomarkdown} +This *is* not processed + {:/nomarkdown} + +And another paragraph + +{::nomarkdown this='is' .ignore /} + +{::nomarkdown type='html'} +bold +{:/} +{::nomarkdown type="latex"} +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} +{:/} + +{::nomarkdown} +Another paragraph diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.html new file mode 100644 index 00000000..bf3a47f0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.html @@ -0,0 +1,21 @@ +

No header id

+ +

without header id

+ +
+some *para* +
+ +
+

some para

+
+ +

Some text10.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.text new file mode 100644 index 00000000..b63f34b5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options.text @@ -0,0 +1,23 @@ +# No header id + +{::options unusedvar="val" /} + +# without header id + +
+some *para* +
+ +{::options parse_block_html="true" parse_span_html="true" /} + +
+some *para* +
+ +{::options footnote_nr="10" /} + +Some text[^ab]. + +[^ab]: Some text. + +{::options template="/etc/passwd" /} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.html new file mode 100644 index 00000000..2db8e20f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.html @@ -0,0 +1,10 @@ + +

Some text1.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.text new file mode 100644 index 00000000..78abfbee --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options2.text @@ -0,0 +1,5 @@ +{::options footnote_nr="da10" /} + +Some text[^ab]. + +[^ab]: Some text. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.html b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.html new file mode 100644 index 00000000..d5a5ad6b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.html @@ -0,0 +1,8 @@ +
x = Class.new
+
+
+ +
x = Class.new
+
+
+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.text b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.text new file mode 100644 index 00000000..f37839b2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/12_extension/options3.text @@ -0,0 +1,7 @@ + x = Class.new +{: .language-ruby} + +{::options syntax_highlighter_opts="{default_lang: ruby\}" /} + + x = Class.new + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.html new file mode 100644 index 00000000..398628ab --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.html @@ -0,0 +1,15 @@ +
+
item
+
def
+
item2
+
def
+
+ +
+
item
+
def
+
item2
+
def
+
item3
+
def
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.text new file mode 100644 index 00000000..f1797a74 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/auto_ids.text @@ -0,0 +1,18 @@ +{:auto_ids} +item +: def + +item2 +: def + +^ + +{:auto_ids-prefix-} +item +: def + +item2 +: def + +{:#id} item3 +: def diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.html new file mode 100644 index 00000000..7c5cc048 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.html @@ -0,0 +1 @@ +

: no definition

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.text new file mode 100644 index 00000000..cd3671b9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/definition_at_beginning.text @@ -0,0 +1 @@ +: no definition diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.html new file mode 100644 index 00000000..3090b1ef --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.html @@ -0,0 +1,4 @@ +
+
item
+
definition
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.text new file mode 100644 index 00000000..587c3b07 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/deflist_ial.text @@ -0,0 +1,4 @@ +{:.dl-horizontal} +item +: definition +{:.dl-other} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.html new file mode 100644 index 00000000..0ed1197f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.html @@ -0,0 +1,17 @@ +
+
item
+
definition +continued
+
another {:.cls}
+
+
code
+
+
+
IAL at last + no code bc of text
+
term
+
definition
+
term1
+
term2
+
definition
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.text new file mode 100644 index 00000000..2058d749 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/item_ial.text @@ -0,0 +1,16 @@ +item +: {:.cls} definition + continued +: another {:.cls} +: {:.class} + code +: {:.cls} IAL at last + no code bc of text + + +{:.class} term +: definition + +{:.class1} term1 +{:.class2} term2 +: definition diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.html new file mode 100644 index 00000000..e2e089b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.html @@ -0,0 +1,13 @@ +
+
kram
+
down
+
now
+
definition 1
+
definition 2
+
+

definition 3

+
+
+

definition 4

+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.text new file mode 100644 index 00000000..b834258b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/multiple_terms.text @@ -0,0 +1,10 @@ +kram +*down* +now +: definition 1 +: definition 2 + +: definition 3 + + +: definition 4 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.html new file mode 100644 index 00000000..c16f9623 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.html @@ -0,0 +1,2 @@ +

This is a para +: and not a definition list

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.text new file mode 100644 index 00000000..98b52b37 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/no_def_list.text @@ -0,0 +1,2 @@ +This is a para +\: and not a definition list diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.html new file mode 100644 index 00000000..5f28fdf8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.html @@ -0,0 +1,10 @@ +
+
term
+
+

definition

+
+
definition
+
+

definition

+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.text new file mode 100644 index 00000000..280fa474 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/para_wrapping.text @@ -0,0 +1,6 @@ +term + +: definition +: definition + +: definition diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.html new file mode 100644 index 00000000..0a1c4dc2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.html @@ -0,0 +1,8 @@ +
+
kram
+
down
+
+
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.text new file mode 100644 index 00000000..56fedf16 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/separated_by_eob.text @@ -0,0 +1,5 @@ +kram +: down +^ +kram +: down diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.html new file mode 100644 index 00000000..791f1451 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.html @@ -0,0 +1,10 @@ +
+
kram
+
down
+
novalue
+
+
kram
+
down +kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.text new file mode 100644 index 00000000..e3bf730e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/simple.text @@ -0,0 +1,10 @@ +kram +: down + +novalue +: + +kram +: down +kram +: down diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.html new file mode 100644 index 00000000..cf7d7859 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.html @@ -0,0 +1,4 @@ +
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.text new file mode 100644 index 00000000..76eb3553 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/styled_terms.text @@ -0,0 +1,2 @@ +*kram* +: down diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.html new file mode 100644 index 00000000..b4df8780 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.html @@ -0,0 +1,3 @@ +

para

+ +

: no definition

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.text new file mode 100644 index 00000000..30ab445c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/too_much_space.text @@ -0,0 +1,4 @@ +para + + +: no definition diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.html b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.html new file mode 100644 index 00000000..45b58656 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.html @@ -0,0 +1,38 @@ +
+
kram
+
this is some +text
+
+

this is some +more text

+
+
kram
+
+
+

blockquote

+
+
+
kram
+
+
code
+
+
+
kram
+
+
+
kram
+
down
+
+
+
kram
+
+

header

+
+
kram
+
+
    +
  • list
  • +
  • items
  • +
+
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.text b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.text new file mode 100644 index 00000000..15195ce3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/13_definition_list/with_blocks.text @@ -0,0 +1,24 @@ +kram +: this is some + text + + : this is some + more text + +kram +: > blockquote + +kram +: + code + +kram +: kram + : down + +kram +: # header + +kram +: * list + * items diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.html new file mode 100644 index 00000000..af9b3e5f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.html @@ -0,0 +1,8 @@ + + + + + + + +
first line of cell
second line of cell
another cell
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.options b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.text new file mode 100644 index 00000000..60fec0b4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/empty_tag_in_cell.text @@ -0,0 +1 @@ +| first line of cell
second line of cell | another cell | diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.html new file mode 100644 index 00000000..302e97ae --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.html @@ -0,0 +1,12 @@ +

No table body

+ +

|-|-|-

+ +

|no|table|here|

+ +

|no|table|here| +paragraph

+ +

|-|-| +|-|-|

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.text new file mode 100644 index 00000000..3565d5b8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/errors.text @@ -0,0 +1,13 @@ +No table body + +|-|-|- + +[5]: test +|no|table|here| + +|no|table|here| +paragraph + +|-|-| +|-|-| + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.html new file mode 100644 index 00000000..b4528a17 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.html @@ -0,0 +1,52 @@ +

cell 1 | cell 2

+ +

cell 1 | cell 2

+ + + + + + + + +
cell 1cell 2 | continued
+ + + + + + + + +
cell 1cell 2
+ + + + + + + + +
cell 1code | span
+ +

cell 1 code | span

+ +

cell 1 | code | span

+ + + + + + + + + + + + + + +
cell 1cell `2cell 3
cell 1`cell 2cell 3
+ +

cell 1 | cell 2 | cell 3 +cell 1 | cell 2 | cell 3

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.text new file mode 100644 index 00000000..a8a24d6a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/escaping.text @@ -0,0 +1,19 @@ +`cell 1 | cell 2` + +cell 1 \| cell 2 + +cell 1 | cell 2 \| continued + +cell 1 | cell `2` + +cell 1 | `code | span` + +cell 1 `code | span` + +cell 1 \| `code | span` + +cell 1 | cell `2 | cell 3 +cell 1` | cell 2 | cell 3 + +cell 1 \| cell `2 | cell 3 +cell 1` | cell 2 | cell 3 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.html new file mode 100644 index 00000000..e6596ed5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.html @@ -0,0 +1,65 @@ +

Simple footer

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Full footer

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Footer with separator lines

+ + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6
+ +

Empty footer

+ + + + + + + + +
cell1cell2
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.text new file mode 100644 index 00000000..faaed8d9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/footer.text @@ -0,0 +1,25 @@ +Simple footer + +| cell1 | cell2 +|= +| cell3 | cell4 + +Full footer + +| cell1 | cell2 +|=======|=======| +| cell3 | cell4 + +Footer with separator lines + +| cell1 | cell2 +|=======|=======| +| cell3 | cell4 +|--- +| cell5 | cell6 +|--- + +Empty footer + +| cell1 | cell2 +|= diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.html new file mode 100644 index 00000000..647f2c48 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.html @@ -0,0 +1,117 @@ +

Simple header

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Full header

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

With alignment and superfluous alignment defs

+ + + + + + + + + + + + + + + + + + + + +
defaultleftcenterrightdefault
cell1cell2cell3cell4cell5
+ +

With leading sep line

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Multiple bodies

+ + + + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6
+ +

Sep line with tab

+ + + + + + + + + + + + + + + + + + +
rightcenter
cell1cell2
cell3cell4
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.text new file mode 100644 index 00000000..6961bfb9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/header.text @@ -0,0 +1,39 @@ +Simple header + +| cell1 | cell2 +|----- +| cell3 | cell4 + +Full header + +| cell1 | cell2 +|-------|-------| +| cell3 | cell4 + +With alignment and superfluous alignment defs + +| default | left | center | right | default +|-| :- |:-: | -: | - | :-: | :- +| cell1 | cell2 | cell3 | cell4 | cell5 + +With leading sep line + +|:-:|-:| +| cell1 | cell2 +|-------|-------| +| cell3 | cell4 + +Multiple bodies + +| cell1 | cell2 ++ :-: | +| cell3 | cell4 +|----||| +| cell5 | cell6 + +Sep line with tab + +right | center +---: | :---: +cell1 | cell2 +cell3 | cell4 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.html new file mode 100644 index 00000000..dce46b1d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.html @@ -0,0 +1,3 @@ +

No table

+ +

| Some | thing | here

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.text new file mode 100644 index 00000000..90f90b3d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/no_table.text @@ -0,0 +1,3 @@ +No table + +\| Some \| thing \| here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.html new file mode 100644 index 00000000..506b4421 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.html @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6 |
cell7cell8
+ +

Missing cells at end

+ + + + + + + + + + + + + + + + + + + +
cell1cell2cell3
cell1  
 cell2cell3
+ +

Escaped pipe characters

+ + + + + + + + + + + + + + + + +
cell1 | cell1cell2
cell1cell2 |
cell1 | concell2
+ +

Table with code elements

+ + + + + + + + + + + + + + + + +
This is a span | with a pipe.   
Some span</em> herea span | with apipe.
+ +

Special cases regarding codespan syntax

+ + + + + + + + +
ab
+ + + + + + + +
a
+ + + + + + + + + +
tablewithial
+ + + + + + + + + +
tablewithial
+ +

not starting with a bar

+ + + + + + + + +
simpletable
+ + + + + + + + + + + + + + +
head1head2
cell1cell2
+ + + + + + + + + + + + + + +
head1head2
 cell2
+ + + + + + + + + + + + + + + + +
ab
cd
ef
+ + + + + + + + + + + + + + +
KeyValue type
Type"GROUP"|"UNKNOWN"
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.text new file mode 100644 index 00000000..0f225a4e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/simple.text @@ -0,0 +1,53 @@ +| cell1 | cell2 | +|cell3 | cell4| +|cell5|cell6 \| +| cell7|cell8 + +Missing cells at end + +| cell1 | cell2 | cell3 | +| cell1 || +|| cell2 | cell3 + +Escaped pipe characters + +| cell1 \| cell1 | cell2 | +| cell1 | cell2 \| +| cell1 `|` con | cell2 + +Table with code elements + +| This is a span | with a pipe. +| Some span | here | a span | with a | pipe. + +Special cases regarding codespan syntax + +|a|`b` + +|`a` + +{:.cls} +| table | with | ial + +| table | with | ial +{:.cls} + +not starting with a bar + +simple | table + +head1 | head2 +------|------ +cell1 | cell2 + + head1 | head2 +-------|------ + | cell2 + +| a | b | + c | d +| e | f | + +| Key | Value type | +|--------|------------------------| +| `Type` | `"GROUP"`\|`"UNKNOWN"` | diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.html b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.html new file mode 100644 index 00000000..0084283f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.html @@ -0,0 +1,25 @@ + + + + + + + + + + + +
this is 1a table
with afootnote
+ +
+
    +
  1. +

    Something

    + +
    +

    special here

    +
    +

    ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.latex b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.latex new file mode 100644 index 00000000..99b5312f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.latex @@ -0,0 +1,11 @@ +\begin{longtable}{|l|l|} +\hline +this is \footnote{Something + +\begin{quote} +special here +\end{quote}} & a table\\ +with a & footnote\\ +\hline +\end{longtable} + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.text b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.text new file mode 100644 index 00000000..345fc5d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/14_table/table_with_footnote.text @@ -0,0 +1,6 @@ +| this is [^1] | a table +| with a | footnote + +[^1]: Something + + > special here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.html b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.html new file mode 100644 index 00000000..9b2c1279 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.html @@ -0,0 +1 @@ +\[<script>alert('a')</script> <script>alert('b<')</script>\] diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.text b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.text new file mode 100644 index 00000000..95252a76 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/gh_128.text @@ -0,0 +1 @@ +$$ $$ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.html b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.html new file mode 100644 index 00000000..5d6b343e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.html @@ -0,0 +1,3 @@ +
$$ +5+5 +$$
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.options b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.options new file mode 100644 index 00000000..06d559e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.options @@ -0,0 +1 @@ +:math_engine: ~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.text b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.text new file mode 100644 index 00000000..fdee5cfb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/no_engine.text @@ -0,0 +1,2 @@ +{: #math-id} +$$5+5$$ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.html new file mode 100644 index 00000000..f80d56b6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.html @@ -0,0 +1,30 @@ +

This is a para. +\(\text{LaTeX} \lambda_5\)

+ +\[\lambda_5 = \alpha + 4\] + +

\(\lambda_\alpha > 5\) +This is a para.

+ +\[\begin{align*} +&=5 \\ +&=6 \\ +\end{align*}\] + +\[5+5\] + +\[5+5\] + +\[5+5\] + +\[5+5\] + +
$$5+5$$
+
+ +
\[5+5\] +
+
\[5+5\] +
+ +\[|x| = 5\] diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.text new file mode 100644 index 00000000..aa5984a2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/15_math/normal.text @@ -0,0 +1,30 @@ +This is a para. +$$ \text{LaTeX} \lambda_5 $$ + +$$\lambda_5 = \alpha + 4$$ + +$$\lambda_\alpha > 5$$ +This is a para. + +$$\begin{align*} +&=5 \\ +&=6 \\ +\end{align*}$$ + +$$5+5$$ + + $$5+5$$ + + $$5+5$$ + + $$5+5$$ + + $$5+5$$ + +{:.cls} +$$5+5$$ +^ +$$5+5$$ +{:.cls} + +$$|x| = 5$$ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.html b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.html new file mode 100644 index 00000000..bbb831e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.html @@ -0,0 +1,14 @@ + +

Header level 1

+ +

Header level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.text b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.text new file mode 100644 index 00000000..11ad8291 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/no_toc.text @@ -0,0 +1,16 @@ +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.html b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.html new file mode 100644 index 00000000..d3526846 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.html @@ -0,0 +1,35 @@ +

Contents

+ + + +

Header level 1

+ +

Header level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.options b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.text b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.text new file mode 100644 index 00000000..d8f0b863 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_exclude.text @@ -0,0 +1,19 @@ +# Contents +{:.no_toc} + +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.html b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.html new file mode 100644 index 00000000..e50a07c4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.html @@ -0,0 +1,24 @@ + + +

Header level 1

+ +

Header \` level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.options b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.options new file mode 100644 index 00000000..bdfbeba1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.options @@ -0,0 +1,2 @@ +:toc_levels: 2..3 +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.text b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.text new file mode 100644 index 00000000..1a62dea2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_levels.text @@ -0,0 +1,16 @@ +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header \\\` level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.html b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.html new file mode 100644 index 00000000..f979601d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.html @@ -0,0 +1,13 @@ + + +

Header1 level 1

+ +
+
    +
  1. +

    Some footnote content here ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.options b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.text b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.text new file mode 100644 index 00000000..5879ed57 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_footnotes.text @@ -0,0 +1,6 @@ +* Here comes the table of content +{:toc} + +# Header[^1] level 1 + +[^1]: Some footnote content here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.html b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.html new file mode 100644 index 00000000..ebde543b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.html @@ -0,0 +1,8 @@ +

Header

+ +

Header

+ + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.options b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.options new file mode 100644 index 00000000..36c20f5a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.options @@ -0,0 +1,2 @@ +:auto_ids: true +:auto_id_stripping: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.text b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.text new file mode 100644 index 00000000..9b4ac073 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/block/16_toc/toc_with_links.text @@ -0,0 +1,8 @@ +# [Header] + +# [Header] + +[header]: test.html + +* toc +{:toc} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.html b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.html new file mode 100644 index 00000000..82993163 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.html @@ -0,0 +1,4 @@ +

一二三四五

+ +

あいうえお

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.options b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.options new file mode 100644 index 00000000..4c86d365 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.options @@ -0,0 +1 @@ +:remove_line_breaks_for_cjk: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.text b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.text new file mode 100644 index 00000000..969c04ca --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/cjk-line-break.text @@ -0,0 +1,12 @@ +一 +二 +三 +四 +五 + +あ +い +う +え +お + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/encoding.html b/bin/gems/kramdown-2.5.1/test/testcases/encoding.html new file mode 100644 index 00000000..0339347f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/encoding.html @@ -0,0 +1,46 @@ +

Das ist gewöhnlich ein Über-Problem mit manchen
+Sälen http://example.org und anderen Dinge. Siehe +Über mich!

+ +
+

Vielleicht höre ich nicht richtig?

+
+ +
    +
  • Sollten wir uns das überlegen? Verhöhne mich nicht!
  • +
  • Ho ho höher! Sind *wir* da?
  • +
+ +

Titel sind urschön

+ +

Manche mögens ärmer

+ +
öha
+was nun?
+
+ +
+
Töne
+
Laute Geräusche
+
vielleicht noch was ähnliches
+
+ + + + + + + + + + + + + + + + +
hochhöheram höchsten
überdrübermüde
+ +

Das ist schön +gemacht

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/encoding.text b/bin/gems/kramdown-2.5.1/test/testcases/encoding.text new file mode 100644 index 00000000..65edf4b0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/encoding.text @@ -0,0 +1,28 @@ +Das ist gewöhnlich *ein* [Über-Problem](http://example.org) mit manchen +Sälen und anderen Dinge. Siehe +![Über mich](http://example.org)! + +> Vielleicht *höre*{:.red} ich nicht richtig? +{:.test} + +* Sollten wir uns das überl*egen*? *Verhöhne* mich nicht! +* Ho ho höher! Sind \*wir\* da? + +Titel sind urschön +================== + +## Manche mögens *ärmer* {#hot} + + öha + was nun? + +Töne +: Laute Geräusche +: vielleicht noch was ä*hnliches* + +| hoch | höher | am höchsten | +|----------------------------| +| über | drüber | müde | + +

Das ist schön +gemacht

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/example.man b/bin/gems/kramdown-2.5.1/test/testcases/man/example.man new file mode 100644 index 00000000..a03d1481 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/example.man @@ -0,0 +1,123 @@ +.\" generated by kramdown +.TH "NAME" "1" "November 2016" "Some extra data" +.SH NAME +name \- description +.SH "SYNOPSIS" +\fBname\fP [\fBOPTIONS\fP] \fIarguments\fP\.\.\. +.SH "DESCRIPTION" +This is a normal paragraph\. +.sp +.PD 0 +.IP \(bu 4 +A +.IP \(bu 4 +compact +.IP \(bu 4 +list +.IP \(bu 4 +with multiple +.RS +.IP \(bu 4 +items and +.RS +.IP \(bu 4 +nested +.RE +.RE +.IP \(bu 4 +as well +.PD +.RS +.P +blockquotes are fine +.IP 1. 4 +numbered lists +.IP 2. 4 +work too +.RS +.IP 1. 4 +and they +.IP 2. 4 +can be +.RS +.IP 1. 4 +nested +.RE +.RE +.IP 3. 4 +again +.RE +.sp +.RS 4 +.EX +Some fancy code + going + on + here +.EE +.RE +.TP +\fB\-o\fP +.TQ +\fB\-\-option\fP +Description lists +.sp +are useful as well +.P +And compact definition lists: +.sp +.PD 0 +.TP +\fBo\fP +Option +.TP +\fBk\fP +Key +.TP +\fBv\fP +Value +.PD +.TS +box center ; +l l l l . +tables can be centered +.TE +.sp +.TS +box ; +lb lb cb rb . +Default aligned Left aligned Center aligned Right aligned += +.T& +l l c r . +First body part Second cell Third cell fourth cell +Second \fIline\fP foo \fBstrong\fP baz +Third line \fBquux\fP baz bar +_ +.T& +l l c r . +Second body +2nd line += +Footer row one +Footer row two +.TE +.sp +.P +Inline formatting like \fIemphasis\fP, \fBstrong\fP and \fBcode span\fP work as ususal\. +.UR are_well\.html +Links +.UE +work, too! As do +.br +line breaks\. +.P +Abbreviations like MD can be used but the abbreviation title is ignored\. +.P +Math elements work \fB\elambda = 5\fP inline and in block form: +.sp +.RS 4 +.EX +\elambda_5 = \ealpha + 4 +.EE +.RE diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/example.text b/bin/gems/kramdown-2.5.1/test/testcases/man/example.text new file mode 100644 index 00000000..a0a26149 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/example.text @@ -0,0 +1,85 @@ +# name(1) - description +{: data-date="November 2016" data-extra="Some extra data"} + +## SYNOPSIS + +`name` \[`OPTIONS`\] *arguments*... + +## DESCRIPTION + +This is a normal paragraph. + +* A +* compact +* list +* with multiple + * items and + * nested +* as well +{:.compact} + +> blockquotes are fine +> +> 1. numbered lists +> +> 2. work too +> 1. and they +> 2. can be +> 1. nested +> +> 3. again + +~~~ +Some fancy code + going + on + here +~~~ + +`-o` +`--option` +: Description lists +: are useful as well + +And compact definition lists: + +`o` +: Option + +`k` +: Key + +`v` +: Value +{:.compact} + +| tables | can | be | centered | +{:.center} + +|-----------------+------------+-----------------+----------------| +| Default aligned |Left aligned| Center aligned | Right aligned | +|-----------------|:-----------|:---------------:|---------------:| +| First body part |Second cell | Third cell | fourth cell | +| Second *line* |foo | **strong** | baz | +| Third line |`quux` | baz | bar | +|-----------------+------------+-----------------+----------------| +| Second body | | | | +| 2nd line | | | | +|=================+============+=================+================| +| Footer row one | | | | +| Footer row two | | | | +|-----------------+------------+-----------------+----------------| + + +Inline formatting like *emphasis*, **strong** and `code span` work +as ususal. [Links](are_well.html) work, too! As do\\ +line breaks. + +Abbreviations like MD can be used but the abbreviation title is +ignored. + +*[MD]: Markdown + +Math elements work $$\lambda = 5$$ inline and in block form: + +$$\lambda_5 = \alpha + 4$$ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.man b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.man new file mode 100644 index 00000000..8e47527e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "7" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.text b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.text new file mode 100644 index 00000000..832c9213 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-dash-description.text @@ -0,0 +1 @@ +# name -- description diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.man b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.man new file mode 100644 index 00000000..e59dc5ec --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "1" "November 2016" "Something extra" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.text b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.text new file mode 100644 index 00000000..941482c1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-description.text @@ -0,0 +1,2 @@ +# name description +{: data-section="1" data-date="November 2016" data-extra="Something extra"} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.man b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.man new file mode 100644 index 00000000..8df4ff71 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "1" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.text b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.text new file mode 100644 index 00000000..5f3e765b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section-description.text @@ -0,0 +1 @@ +# name(1) -- description diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.man b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.man new file mode 100644 index 00000000..7ca87574 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.man @@ -0,0 +1,2 @@ +.\" generated by kramdown +.TH "NAME" "1" diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.text b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.text new file mode 100644 index 00000000..da98dbda --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name-section.text @@ -0,0 +1 @@ +# name(1) diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.man b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.man new file mode 100644 index 00000000..8488496f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.man @@ -0,0 +1,2 @@ +.\" generated by kramdown +.TH "NAME" "7" diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.text b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.text new file mode 100644 index 00000000..5f4656ae --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/heading-name.text @@ -0,0 +1 @@ +# name diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/sections.man b/bin/gems/kramdown-2.5.1/test/testcases/man/sections.man new file mode 100644 index 00000000..14ab2336 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/sections.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.SH "NAME" +works +.SS "Sub section" diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/sections.text b/bin/gems/kramdown-2.5.1/test/testcases/man/sections.text new file mode 100644 index 00000000..d1f5f864 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/sections.text @@ -0,0 +1,11 @@ +## NAME + +works + +### Sub section + +#### Ignored + +##### Ignored + +###### Ignored diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.man b/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.man new file mode 100644 index 00000000..710a4f14 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.man @@ -0,0 +1,8 @@ +.\" generated by kramdown +\&\. at the start of the line +.P +line with \efB backslash symbol +.P +some \. other \- escaped \' symbols +.P +\&\. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.text b/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.text new file mode 100644 index 00000000..052b94f5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/man/text-escaping.text @@ -0,0 +1,7 @@ +. at the start of the line + +line with \fB backslash symbol + +some . other - escaped \' symbols + +. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.html new file mode 100644 index 00000000..a1102ead --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.html @@ -0,0 +1,5 @@ +

This is [] empty.

+ +

This is [][] empty.

+ +

This is empty.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.text new file mode 100644 index 00000000..cca5de5f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty.text @@ -0,0 +1,5 @@ +This is [] empty. + +This is [][] empty. + +This is [](test.html) empty. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.htmlinput b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.htmlinput new file mode 100644 index 00000000..b95b2cc7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.htmlinput @@ -0,0 +1,3 @@ +

Image with empty title: alt text

+ +

Link reference with empty title.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.text new file mode 100644 index 00000000..baabe7da --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/empty_title.text @@ -0,0 +1,7 @@ +Image with empty title: ![alt text](/images/other.png) + +Link [reference][1] with empty title. + + + +[1]: http://example.tld diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.html new file mode 100644 index 00000000..e1f4ade5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.html @@ -0,0 +1,5 @@ +

Simple: Some alt text

+ +

Nested: Some alt ![img](text.png) text

+ +

Simple: Some text alt text text

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.text new file mode 100644 index 00000000..bdbfb65e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/image_in_a.text @@ -0,0 +1,5 @@ +Simple: [Some ![alt text](/images/other.png)](local.html) + +Nested: [Some ![alt ![img](text.png) text](/images/other.png)](local.html) + +Simple: [Some *text ![alt text](/images/other.png) text*](local.html) diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.html new file mode 100644 index 00000000..565d36f7 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.html @@ -0,0 +1,15 @@ +

Simple: alt text

+ +

Simple with title: alt text

+ +

Empty img link: alt text

+ +

Reference style: alt text

+ +

Reference style with title: alt text

+ +

No alt text:

+ +

No id: imgo

+ +

With escaped pipe: an | pipe

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.text new file mode 100644 index 00000000..05050a24 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/imagelinks.text @@ -0,0 +1,18 @@ +Simple: ![alt text](/images/other.png) + +Simple with title: ![alt text](/images/other.png "title") + +Empty img link: ![alt text]() + +Reference style: ![alt text][img] + +Reference style with title: ![alt text][imgo] + +No alt text: ![](other.png) + +No id: ![imgo] + +[img]: other.png +[imgo]: other.png "Title" + +With escaped pipe: ![an \| pipe](other.png) diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.html new file mode 100644 index 00000000..8d00efa9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.html @@ -0,0 +1,46 @@ +

simple URL

+ +

simple URL

+ +

simple URL with formatting

+ +

simple URL with single quoted title

+ +

simple URL with double quoted title

+ +

simple URL [with ] escaped

+ +

simple URL with ] escaped

+ +

simple URL [with] nested

+ +

simple URL with [no](link.html) inside

+ +

simple URL with parens

+ +

simple URL with parens

+ +

simple URL broken +on line

+ +

simple URL with spaces

+ +

simple URL with spaces

+ +

simple URL with spaces

+ +

simple leading/trailing spaces

+ +

simple leading/trailing spaces

+ +

simple leading/trailing spaces

+ +

bad [URL not

+ +

bad [URL with parens](something(new.html)

+ +

bad [URL with empty title](something.html ‘’)

+ +

bad [URL](

+ +

bad [URL](no

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.text new file mode 100644 index 00000000..c7057646 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/inline.text @@ -0,0 +1,48 @@ +simple [URL]() + +simple [URL](something.html) + +simple [URL *with* formatting](something.html) + +simple [URL with single quoted title](something.html 'a t"itle') + +simple [URL with double quoted title](something.html "a t'itle") + +simple [URL \[with \] escaped](something.html) + +simple [URL with \] escaped](something.html) + +simple [URL [with] nested](something.html) + +simple [URL with [no](link.html) inside](something.html) + +simple [URL with parens](/something/to(do)) + +simple [URL with parens](/something/to(do "doit") + +simple [URL broken +on line](something.html +"title") + +simple [URL with spaces](with spaces.html) + +simple [URL with spaces](with spaces.html 'title') + +simple [URL with spaces](with (spaces).html) + +simple [leading/trailing spaces]( spaces.html) + +simple [leading/trailing spaces](spaces.html ) + +simple [leading/trailing spaces]( spaces.html ) + + +bad [URL [not](something.html) + +bad [URL with parens](something(new.html) + +bad [URL with empty title](something.html '') + +bad [URL]( + +bad [URL](no diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.latex new file mode 100644 index 00000000..63e58e74 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.latex @@ -0,0 +1,6 @@ +\href{https://example.com/~tilde/}{https://example.com/\ensuremath{\sim}tilde/} + +\href{http://example.com/percent\%20percent}{http://example.com/percent\%20percent} + +\href{http://example.com/hash#hash}{http://example.com/hash\#hash} + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.text new file mode 100644 index 00000000..9b27ae86 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/latex_escaping.text @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.html new file mode 100644 index 00000000..15e2ca71 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.html @@ -0,0 +1,9 @@ +

This is a para. +[id]: http://www.example.com/

+ +
[4]: nourl
+
+ +

Points to 1 and 2 and 3 but not [4]

+ +

Points to _.:,;!?- and otherid8

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.text new file mode 100644 index 00000000..16a25b5b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs.text @@ -0,0 +1,27 @@ +This is a para. +[id]: http://www.example.com/ + +[otherid1]: http://wwww.example.com/ "title 1" +[otherid2]: http://wwww.example.com/ 'title 2' +[otherid3]: +[otherid4]: 'title' +[otherid5]: some spaces.html +[otherid6]: some spaces.html 'title' +[otherid7]: some spaces + "title" +[otherid8]:test.html#'test' 'title' + +[break]: http://www.example.com/test/asdf.html + 'Another title' + +[1]: ignored.url + [1]: one.url + [2]: two.url + [3]: three.url + [4]: nourl + +Points to [1] and [2] and [3] but not [4] + +[_.:,;!?-]: http://example.com + +Points to [_.:,;!?-] and [otherid8] diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.html new file mode 100644 index 00000000..f56d77de --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.html @@ -0,0 +1,4 @@ +

Link def with attr and attr 2 and attr 3 and attr before

+ +

test

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.text new file mode 100644 index 00000000..59398a3a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/link_defs_with_ial.text @@ -0,0 +1,16 @@ +Link def with [attr] and [attr 2] and [attr 3] and [attr before] + +[attr]: http://example.com 'title' +{: hreflang="en" .test} + +[attr 2]: http://example.com 'title' +{: hreflang="en"} +{: .test} + +[attr 3]: http://example.com +{: .test} +test + +{: hreflang="en"} +{: .test} +[attr before]: http://example.com diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.html new file mode 100644 index 00000000..ecaa31e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.html @@ -0,0 +1,3 @@ +

This is a link.

+ +

This is a link.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.text new file mode 100644 index 00000000..2cf0ecec --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/links_with_angle_brackets.text @@ -0,0 +1,3 @@ +This is a [link](). + +This is a [link]( 'and title'). diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.html b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.html new file mode 100644 index 00000000..f6fed181 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.html @@ -0,0 +1,37 @@ + +

simple URL and URL

+ +

simple URL and URL

+ +

simple 1 and isurl

+ +

simple 1 and isurl

+ +

this is [a holy isurl]

+ +

no [resolution][] here and [here]

+ +

with a break in +the text

+ +

this not [isurl] and not [isurl]

+ +

a Link with_BIG letters

+ +

bad [no URL] d isurl

+ +

[no url] invalid.html +[no url]:

+ +

“title”

+ +

test url but no title +test [urldef]

+ +

[urldef]: some.url ‘title”

+ +

some with spaces

+ +

this is a ‘special’ occasion for /all/ of us

+ +

this is predefined for URI

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.options b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.options new file mode 100644 index 00000000..efb4b018 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.options @@ -0,0 +1,3 @@ +:link_defs: + predefined: [predefined.html] + URI: [uri.html, My URI] diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.text b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.text new file mode 100644 index 00000000..9f39fa70 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/01_link/reference.text @@ -0,0 +1,53 @@ +[isurl]: someurl.html + [1]: otherurl.html + +simple [URL][1] and [URL][isurl] + +simple [URL] [1] and [URL] +[isurl] + +simple [1][] and [isurl][] + +simple [1] and [isurl] + +this is [a holy [isurl]] + +no [resolution][] here and [here] + +with a [break in +the text] + + [break in the text]: url.html + +this not \[isurl] and not [isurl\] + +a [Link with_BIG] letters + + [link WITH_big]: letters.html + 'This is the title' + +bad [no URL] d [isurl] + +[no url] invalid.html +[no url]: + +[URL but no title]: invalid.html + + "title" + +test [url but no title] +test [urldef] + +[urldef]: some.url 'title" + + +some [with spaces] + +[with spaces]: with spaces.html "title" + +this [is a 'special' occasion for /all/ of us] + +[is a 'special' occasion for /all/ of us]: occasion.html + + +this is [predefined] for [URI] diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.html b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.html new file mode 100644 index 00000000..127e6943 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.html @@ -0,0 +1,3 @@ +

This __is **empty.

+ +

This **is empty.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.text b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.text new file mode 100644 index 00000000..c99d053f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/empty.text @@ -0,0 +1,3 @@ +This __is **empty. + +This ****is empty. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.html b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.html new file mode 100644 index 00000000..e62f03fd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.html @@ -0,0 +1,9 @@ +

This is a *star.

+ +

This is a **star.

+ +

This is *a *star.

+ +

This is *a star*.

+ +

This** is** a star.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.text b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.text new file mode 100644 index 00000000..e80e5eb4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/errors.text @@ -0,0 +1,9 @@ +This is a *star. + +This is a **star. + +This is **a *star*. + +This is *a star\*. + +This** is** a star. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.html b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.html new file mode 100644 index 00000000..3d34cee1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.html @@ -0,0 +1,41 @@ +
    +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
+
    +
  • ab
  • +
  • ab
  • +
  • abc
  • +
  • ab
  • +
  • ab
  • +
  • abc
  • +
+
    +
  • _a_b
  • +
  • a_b_
  • +
  • a_b_c
  • +
  • __a__b
  • +
  • a__b__
  • +
  • a__b__c
  • +
  • a__2__c
  • +
  • a__2__3
  • +
  • 1__2__3
  • +
+
    +
  • a _b_ c
  • +
  • a __b__ c
  • +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.text b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.text new file mode 100644 index 00000000..ba67e84b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/nesting.text @@ -0,0 +1,36 @@ +- ***test test*** +- ___test test___ +- *test **test*** +- **test *test*** +- ***test* test** +- ***test** test* +- ***test* test** +- **test *test*** +- *test **test*** +- _test __test___ +- __test _test___ +- ___test_ test__ +- ___test__ test_ +- ___test_ test__ +- __test _test___ +- _test __test___ +^ +- *a*b +- a*b* +- a*b*c +- **a**b +- a**b** +- a**b**c +^ +- _a_b +- a_b_ +- a_b_c +- __a__b +- a__b__ +- a__b__c +- a__2__c +- a__2__3 +- 1__2__3 +^ +- *a _b_ c* +- **a __b__ c** diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.html new file mode 100644 index 00000000..b7ddf433 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.html @@ -0,0 +1,70 @@ +

This is so hard.

+ +

This is so hard too.

+ +

At start +At start

+ +

At end +At end

+ +

At start +At start

+ +

At end +At end

+ +

And nested.

+ +

And nest**ed.

+ +

And *nested* like this.

+ +

And not_nest_ed.

+ +

And nested.

+ +

And nested.

+ +

And neste.

+ +

And lonely * here*.

+ +

And lonely ** here**.

+ +

And lonely ** here.

+ +

** and here**.

+ +

And compli*cated * here

+ +

Some**what more * **here

+ +

Do it *this* way +Or this *this* way +Or that *that* way +Or that *that* way

+ +

http://blah.com/blah_%28 +http://blah.com/blah__%28 +http://blah.com/blah___%28 +http://blah.com/blah____%28 +http://blah.com/blah_____%28 +http://blah.com/blah______%28

+ +

A-_B

+ +
    +
  • test
  • +
  • ‘test’
  • +
  • “test”
  • +
  • (“test”)
  • +
  • (test)
  • +
  • “test”
  • +
  • `test’
  • +
  • „test“
  • +
+ +

it–by design–cannot have side-effects.

+ +

it—by design—cannot have side-effects.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.options b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.text new file mode 100644 index 00000000..a242125e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/02_emphasis/normal.text @@ -0,0 +1,68 @@ +This *is* so **hard**. + +This _is_ so __hard__ too. + +*At* start +*At* start + +At *end* +At *end* + +_At_ start +_At_ start + +At _end_ +At _end_ + +And *nest**ed***. + +And *nest**ed*. + +And *nest**ed* like** this. + +And *not_nest_ed*. + +And ***nested***. + +And ___nested___. + +And **nest*e***. + +And lonely * here*. + +And lonely ** here**. + +And **lonely ** here**. + +** and here**. + +And **compli*cated \*** here + +Some***what* more * ***he*re + +Do it *\*this\** way +Or this \**this*\* way +Or that *\*that*\* way +Or that \**that\** way + +[http://blah.com/blah_%28](http://blah.com/blah_%28) +[http://blah.com/blah__%28](http://blah.com/blah__%28) +[http://blah.com/blah___%28](http://blah.com/blah___%28) +[http://blah.com/blah____%28](http://blah.com/blah____%28) +[http://blah.com/blah_____%28](http://blah.com/blah_____%28) +[http://blah.com/blah______%28](http://blah.com/blah______%28) + +[A-_B](A_-B) + +- _test_ +- '_test_' +- "_test_" +- ("_test_") +- (_test_) +- “_test_” +- \`_test_' +- „_test_“ + +it--by design--_cannot have side-effects_. + +it---by design---_cannot have side-effects_. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.html new file mode 100644 index 00000000..20c50519 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.html @@ -0,0 +1,5 @@ +

This is `` empty.

+ +

This is ``empty.

+ +

This is ````empty.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.text new file mode 100644 index 00000000..cbb91529 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/empty.text @@ -0,0 +1,5 @@ +This is `` empty. + +This is ``empty. + +This is ````empty. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.html new file mode 100644 index 00000000..1d341a8f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.html @@ -0,0 +1 @@ +

Not ended `span.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.text new file mode 100644 index 00000000..7a948b41 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/errors.text @@ -0,0 +1 @@ +Not ended `span. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.latex new file mode 100644 index 00000000..a1f84d90 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.latex @@ -0,0 +1,2 @@ +You can say \mintinline{ruby}{x = Class.new}, for example. + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.options b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.options new file mode 100644 index 00000000..c11ebb6a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.options @@ -0,0 +1 @@ +:syntax_highlighter: minted diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting-minted.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.html new file mode 100644 index 00000000..4294542d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.html @@ -0,0 +1 @@ +

You can say x = Class.new, for example.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/highlighting.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.html new file mode 100644 index 00000000..ec21686c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.html @@ -0,0 +1 @@ +

This is a code-span

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.options b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.options new file mode 100644 index 00000000..bfc92f45 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.options @@ -0,0 +1,2 @@ +:syntax_highlighter_opts: + guess_lang: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.text new file mode 100644 index 00000000..f704439a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal-css-class.text @@ -0,0 +1 @@ +This is a `code-span` diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.html new file mode 100644 index 00000000..6de2257f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.html @@ -0,0 +1,20 @@ +

This is a simple span.

+ +

With some<ht>&ml in it.

+ +

And ` backticks.

+ +

And ``some`` more.

+ +

With backslash in\ it.

+ +

This is a ` literal backtick. +As `are` these!

+ +

No literal backtick.

+ +

something

+ +

` `

+ +

a ` `

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.text new file mode 100644 index 00000000..c1889595 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/normal.text @@ -0,0 +1,20 @@ +This is `a` simple span. + +With `some&ml` in it. + +And `` ` `` backticks. + +And ``` ``some`` ``` more. + +With backslash `in\` it. + +This is a ` literal backtick. +As \`are\` these! + +No `` literal backtick``. + +`something` + +` ` + +a ` ` diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.html new file mode 100644 index 00000000..7822f788 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.html @@ -0,0 +1 @@ +

You can say Class.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.options b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.options new file mode 100644 index 00000000..34094e96 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + span: + disable: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.text new file mode 100644 index 00000000..d958d914 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/disabled.text @@ -0,0 +1 @@ +You can say `Class`{:.language-ruby}. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.html new file mode 100644 index 00000000..4294542d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.html @@ -0,0 +1 @@ +

You can say x = Class.new, for example.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.options b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.options new file mode 100644 index 00000000..9ac61e7e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.options @@ -0,0 +1 @@ +:syntax_highlighter: rouge diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/03_codespan/rouge/simple.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.html new file mode 100644 index 00000000..f18212b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.html @@ -0,0 +1,79 @@ +

This is 123456789

+ +
+
    +
  1. + +

    A paragraph ↩

    +
  2. +
  3. + +

    A header ↩

    +
  4. +
  5. + +
    +

    blockquote

    + +

    paragraph ↩

    +
    +
  6. +
  7. + +
    codeblock
    +
    +

    ↩

    +
  8. +
  9. + +
      +
    • item 1
    • +
    • item 2 +
        +
      • +

        sub item

        + +
        +

        blockquote

        + +

        header ↩

        +
        +
      • +
      +
    • +
    +
  10. +
  11. + + + + + + + + + + + + +
    ab
    cd
    +

    ↩

    +
  12. +
  13. + +
    +

    ↩

    +
  14. +
  15. + +\[x + 2\] +

    ↩

    +
  16. +
  17. + +
    test +
    +

    ↩

    +
  18. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.options new file mode 100644 index 00000000..ac54fc0d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.options @@ -0,0 +1 @@ +footnote_backlink_inline: true diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.text new file mode 100644 index 00000000..55f94a34 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_inline.text @@ -0,0 +1,38 @@ +This is [^paragraph][^header][^blockquote][^codeblock][^list][^table][^hrule][^mathblock][^html] + +[^paragraph]: + A paragraph + +[^header]: + # A header + +[^blockquote]: + > blockquote + > + > paragraph + +[^codeblock]: + codeblock + +[^list]: + * item 1 + * item 2 + * sub item + + > blockquote + > + > # header + +[^table]: + | a | b | + | c | d | + +[^hrule]: + *** + +[^mathblock]: + $$x + 2$$ + +[^html]: +
test +
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.html new file mode 100644 index 00000000..bed08698 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.html @@ -0,0 +1,9 @@ +

Some footnote here1

+ +
+
    +
  1. +

    Some text here text &8617; <img />

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.options new file mode 100644 index 00000000..4c677eff --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.options @@ -0,0 +1 @@ +:footnote_backlink: 'text &8617; ' diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.text new file mode 100644 index 00000000..41a6f984 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/backlink_text.text @@ -0,0 +1,3 @@ +Some footnote here[^fn] + +[^fn]: Some text here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.html new file mode 100644 index 00000000..9012cc06 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.html @@ -0,0 +1,17 @@ +

Some para.

+ +
+

blockquote

+
+ +
    +
  • a list +with some text
  • +
+ +
    +
  • other list
  • +
+
code
+
+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.latex new file mode 100644 index 00000000..965653c8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.latex @@ -0,0 +1,17 @@ +Some para. + +\begin{quote} +blockquote +\end{quote} + +\begin{itemize} +\item{} a list +with some text +\end{itemize} + +\begin{itemize} +\item{} other list +\end{itemize} +\begin{verbatim}code +\end{verbatim} + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.text new file mode 100644 index 00000000..44b52e00 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/definitions.text @@ -0,0 +1,24 @@ +Some para. + +[^footnote]: ignored definition +[^footnote]: Some footnote text + +> blockquote + +[^other]: some + foot + + note text + +* a list + with some text + +[^tnote]: foot note + +* other list +^ + code + +[^1]: + > a blockquote + and some para diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.html new file mode 100644 index 00000000..0867c86f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.html @@ -0,0 +1,12 @@ +

This is a[footnote 1] footnote[footnote 1]. And another[footnote 2].

+ +
+
    +
  1. +

    Some text. ↩ ↩2

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.options new file mode 100644 index 00000000..092fd1a4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.options @@ -0,0 +1 @@ +:footnote_link_text: "[footnote %s]" diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.text new file mode 100644 index 00000000..3876de06 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_link_text.text @@ -0,0 +1,4 @@ +This is a[^ab] footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.html new file mode 100644 index 00000000..77c0a848 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.html @@ -0,0 +1,12 @@ +

This is a footnote35. And another36.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.latex new file mode 100644 index 00000000..8f07dde0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.latex @@ -0,0 +1,2 @@ +This is a footnote\footnote{Some text.}. And another\footnote{Some other text.}. + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.options new file mode 100644 index 00000000..f606ecfa --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.options @@ -0,0 +1 @@ +:footnote_nr: 35 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.text new file mode 100644 index 00000000..cad29357 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_nr.text @@ -0,0 +1,4 @@ +This is a footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.html new file mode 100644 index 00000000..90aa226c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.html @@ -0,0 +1,12 @@ +

This is a1 footnote1. And another2.

+ +
+
    +
  1. +

    Some text. ↩ ↩2

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.options new file mode 100644 index 00000000..51d78bc1 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.options @@ -0,0 +1 @@ +:footnote_prefix: adf123- diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.text new file mode 100644 index 00000000..884053e8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/footnote_prefix.text @@ -0,0 +1,4 @@ +This is a[^ab] footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.html new file mode 100644 index 00000000..d4e97ffd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.html @@ -0,0 +1,17 @@ +

Lorem ipsum1 dolor sit amet.

+ +

Lorem ipsum2 dolor sit amet.

+ +
+
    +
  1. +

    Consecutur adisping.3 ↩

    +
  2. +
  3. +

    Sed ut perspiciatis unde omnis. ↩

    +
  4. +
  5. +

    Sed ut. ↩

    +
  6. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.text new file mode 100644 index 00000000..f4f91e93 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/inside_footnote.text @@ -0,0 +1,9 @@ +Lorem ipsum[^first] dolor sit amet. + +Lorem ipsum[^second] dolor sit amet. + +[^first]: Consecutur adisping.[^third] + +[^second]: Sed ut perspiciatis unde omnis. + +[^third]: Sed ut. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.html new file mode 100644 index 00000000..90f2ccba --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.html @@ -0,0 +1,46 @@ +

This is some *ref.1

+ +
+

a blockquote 2

+
+ +
    +
  • and a list item 3
  • +
+ +

And a header4

+ +

A marker without a definition [^without].

+ +

A marker 5 used twice1 and thrice1.

+ +
+
    +
  1. +

    Some foot note text ↩ ↩2 ↩3

    +
  2. +
  3. +

    other text +with more lines

    + +
    +

    and a quote

    +
    +

    ↩

    +
  4. +
  5. +

    some text ↩

    +
  6. +
  7. + +
    code block
    +continued here
    +
    +

    ↩

    +
  8. +
  9. + +

    ↩

    +
  10. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.latex new file mode 100644 index 00000000..8f406b86 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.latex @@ -0,0 +1,23 @@ +This is some *ref.\footnote{Some foot note text} + +\begin{quote} +a blockquote \footnote{other text +with more lines + +\begin{quote} +and a quote +\end{quote}} +\end{quote} + +\begin{itemize} +\item{} and a list item \footnote{some \emph{text}} +\end{itemize} + +\section*{And a header\footnote{\begin{verbatim}code block +continued here +\end{verbatim}}} + +A marker without a definition {[}\^{}without{]}. + +A marker \footnote{} used twice\footnote{Some foot note text} and thrice\footnote{Some foot note text}. + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.options new file mode 100644 index 00000000..5cfe2502 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.options @@ -0,0 +1,2 @@ +:auto_ids: false +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.text new file mode 100644 index 00000000..42b77fb5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/markers.text @@ -0,0 +1,27 @@ +This is some *ref.[^fn] + +[^fn]: Some foot note text +{: .class} + +> a blockquote [^3] + +* and a list item [^1] + +# And a header[^now] + +[^1]:some *text* +[^3]: other text + with more lines + + > and a quote + +A marker without a definition [^without]. + +A marker [^empty] used twice[^fn] and thrice[^fn]. + +[^now]: + + code block + continued here + +[^empty]: diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.html new file mode 100644 index 00000000..a87f3599 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.html @@ -0,0 +1,11 @@ +
+
    +
  1. +

    Footnote \` text ↩

    +
  2. +
+
+ +

Some para with a1 footnote.

+ +

And another para.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.text new file mode 100644 index 00000000..97c0ab1a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/placement.text @@ -0,0 +1,8 @@ +* footnotes will be placed here +{:footnotes} + +Some para with a[^1] footnote. + +[^1]: Footnote \\\` text + +And another para. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.html new file mode 100644 index 00000000..64ce4aea --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.html @@ -0,0 +1,14 @@ +

Something

+

something1.

+ +

Footnotes

+ +

Test

+
+
    +
  1. + +

    A note ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.options new file mode 100644 index 00000000..5cfe2502 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.options @@ -0,0 +1,2 @@ +:auto_ids: false +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.text new file mode 100644 index 00000000..6a60c612 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/regexp_problem.text @@ -0,0 +1,52 @@ +# Something +something[^note1]. + +# Footnotes +[^note1]: + A note + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.html b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.html new file mode 100644 index 00000000..e6f2d79d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.html @@ -0,0 +1,9 @@ +

Some footnote here1

+ +
+
    +
  1. +

    Some text here

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.options b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.options new file mode 100644 index 00000000..0512dd6d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.options @@ -0,0 +1 @@ +:footnote_backlink: '' diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.text b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.text new file mode 100644 index 00000000..41a6f984 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/04_footnote/without_backlink.text @@ -0,0 +1,3 @@ +Some footnote here[^fn] + +[^fn]: Some text here diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.html new file mode 100644 index 00000000..e7cec40f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.html @@ -0,0 +1 @@ +

Link: test

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.text new file mode 100644 index 00000000..8f39d959 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/across_lines.text @@ -0,0 +1,2 @@ +Link: test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.html new file mode 100644 index 00000000..c49bb52f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.html @@ -0,0 +1,7 @@ +

+ +

First some text and then a

+ +

and then text.

+ +

A it.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.text new file mode 100644 index 00000000..e0a7783c --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/button.text @@ -0,0 +1,7 @@ + + +First some text and then a + + and then text. + +A it. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.html new file mode 100644 index 00000000..030552fc --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.html @@ -0,0 +1 @@ +

This is some text

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.text new file mode 100644 index 00000000..383f0a83 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/invalid.text @@ -0,0 +1 @@ +This is some text diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.html new file mode 100644 index 00000000..7d0d6ad6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.html @@ -0,0 +1 @@ +

Link: text

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.text new file mode 100644 index 00000000..fb016196 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/link_with_mailto.text @@ -0,0 +1 @@ +Link: text diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.html new file mode 100644 index 00000000..b6989b7f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.html @@ -0,0 +1,3 @@ +

Lorem ipsum.

+ +

Test

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.text new file mode 100644 index 00000000..6ae30e03 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/mark_element.text @@ -0,0 +1,3 @@ +Lorem ipsum. + +Test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.html new file mode 100644 index 00000000..44158c3b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.html @@ -0,0 +1,6 @@ +

This is text +This is *text* +This is text +This is text +This is *nothing* to fear about. +This is <http://example.com>.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.text new file mode 100644 index 00000000..dcc10ff8 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/markdown_attr.text @@ -0,0 +1,6 @@ +This is *text* +This is *text* +This is *text* +This is *text* +This is *nothing* to *fear* about. +This is . diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.html new file mode 100644 index 00000000..3cdc646d --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.html @@ -0,0 +1,43 @@ +

Empty !

+ +

title is a title.

+ +

This is <? a PI ?>.

+ +

This is comment.

+ +

This is multiline comment.

+ +

This is tag +now .

+ +

This is tag + now.

+ +

This is an empty tag.

+ +

This is something strange.

+ +

Auto-closing:

+ +

Expanding:

+ +

An invalid tag: <hR>

+ +

A <p>block tag</p>.

+ +

An invalid </closing> tag.

+ +

A tag.

+ +

An unclosed tag.

+ +

Some element with | pipe symbol

+ +

Some element with | pipe symbol

+ +

Some element with | pipe +symbol|

+ +

underlined

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.text new file mode 100644 index 00000000..0156d7c0 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/normal.text @@ -0,0 +1,43 @@ +Empty ! + +title is a title. + +This is . + +This is comment. + +This is multiline comment. + +This is tag +now . + +This is tag + now. + +This is an empty tag. + +This is _something strange_. + +Auto-closing:
+ +Expanding: + +An invalid tag:
+ +A

block tag

. + +An invalid tag. + +A tag. + +An unclosed *tag.* + +Some element with | pipe symbol + +Some element with | pipe symbol + +Some element with | pipe +symbol| + +underlined diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.html new file mode 100644 index 00000000..808f1dbf --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.html @@ -0,0 +1,2 @@ +

This is raw --version and --version and --version and +---version.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.text new file mode 100644 index 00000000..5b128fcb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/raw_span_elements.text @@ -0,0 +1,2 @@ +This is raw --version and --version and --version and +---version. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.html b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.html new file mode 100644 index 00000000..00b43c12 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.html @@ -0,0 +1,5 @@ +

This doit test

+ +

This doit test

+ +

This doit</some> test

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.text b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.text new file mode 100644 index 00000000..bc234de4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/05_html/xml.text @@ -0,0 +1,5 @@ +This doit test + +This doit test + +This doit test diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.html b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.html new file mode 100644 index 00000000..6bddfda5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.html @@ -0,0 +1,25 @@ +

This is some text.

+ +

There is some real concern about OtHeR!

+ +

is some Think empty about Oesterreich. CSS und CSS3

+ +

no abbrev here because there is someone and kulis some

+ +
    +
  • (X)HTML test
  • +
  • line two
  • +
+ +

(X)HTML

+ +
    +
  • test (X)HTML
  • +
+ +

This is awesome.

+ +

hello foo bar babble.

+ +

hello foo +bar babble.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.text b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.text new file mode 100644 index 00000000..f5ec88ef --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev.text @@ -0,0 +1,41 @@ +This is some text. + +*[is some]: Yes it is +*[OtHeR!]: This & that + +*[is some]: It is, yes +*[empty]: + +There *is some real* concern about OtHeR! + +is some Think empty about Oesterreich. CSS und CSS3 + +no abbrev here because there is someone and kulis some + +*[Oesterreich]: Very nice country + +*[CSS]: Cascading +*[CSS3]: Cascading 3 + +* (X)HTML test +* line two + +[(X)HTML](http://en.wikipedia.org/wiki/Xhtml) + +* test (X)HTML + +*[(X)HTML]: (eXtensible) HyperText Markup Language + + +This is awesome. + +{:.testit} +*[awesome]: Some text here +{:.test} + +*[foo bar]: baz + +hello foo bar babble. + +hello foo +bar babble. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.html b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.html new file mode 100644 index 00000000..108fcfce --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.html @@ -0,0 +1,2 @@ +
*[4]: noabbrev
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.text b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.text new file mode 100644 index 00000000..3f3a0e5b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_defs.text @@ -0,0 +1,5 @@ +*[ABBR]: Some abbreviations + *[one abbr]: one abbrev + *[2 and other]: another + *[3]: yet another + *[4]: noabbrev diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.html b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.html new file mode 100644 index 00000000..6da3ca4e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.html @@ -0,0 +1,9 @@ +

This is some TEST to check.

+ + + This TEST fails. + + + This TEST fails. + + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.text b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.text new file mode 100644 index 00000000..e0a0e881 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/abbrev_in_html.text @@ -0,0 +1,10 @@ +This is some TEST to check. + + + This TEST fails. + + + This TEST fails. + + +*[TEST]: This Escapes SVG Text. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.html b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.html new file mode 100644 index 00000000..7cce8beb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.html @@ -0,0 +1,9 @@ +

There is a TXT file here. 1

+ +
+
    +
  1. +

    A TXT file. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.text b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.text new file mode 100644 index 00000000..e7709cb9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/abbreviations/in_footnote.text @@ -0,0 +1,5 @@ +There is a TXT file here. [^1] + +*[TXT]: Text File + +[^1]: A TXT file. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.html b/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.html new file mode 100644 index 00000000..90eae7d5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.html @@ -0,0 +1,15 @@ +

This should be a http://www.example.com/ link. +This should be a john.doe@example.com link. +As should john.doe@example.com this. +As should john_doe@example.com this. +As should CSS@example.com this. +Another ampersand http://www.example.com/?doit&x=y link. +More entities http://www.example.com/?doit&x="y&z=y.

+ +

Email international übung@macht.den.meister.de, ü.äß@hülse.de +Email invalid: <me@example.com>

+ +

Autolink with underscore: http://www.example.com/with_under_score

+ +

http://www.example.com/

+ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.text b/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.text new file mode 100644 index 00000000..033e8af4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/autolinks/url_links.text @@ -0,0 +1,16 @@ +This should be a link. +This should be a link. +As should this. +As should this. +As should this. +Another ampersand link. +More entities . + +Email international <übung@macht.den.meister.de>, <ü.äß@hülse.de> +Email invalid: <[me@example.com](mailtos:me@example.com)> + +Autolink with underscore: + + + +*[CSS]: Cascading diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.html new file mode 100644 index 00000000..015d5948 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.html @@ -0,0 +1,47 @@ +

\

+ +

.

+ +

*

+ +

_

+ +

+

+ +

-

+ +

`

+ +

(

+ +

)

+ +

[

+ +

]

+ +

{

+ +

}

+ +

#

+ +

!

+ +

<<

+ +

>>

+ +

:

+ +

|

+ +

"

+ +

'

+ +

=

+ +

>

+ +

<

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.text new file mode 100644 index 00000000..1c47104a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/escaped_chars/normal.text @@ -0,0 +1,47 @@ +\\ + +\. + +\* + +\_ + +\+ + +\- + +\` + +\( + +\) + +\[ + +\] + +\{ + +\} + +\# + +\! + +\<< + +\>> + +\: + +\| + +\" + +\' + +\= + +\> + +\< diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.html b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.html new file mode 100644 index 00000000..3544d49f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.html @@ -0,0 +1,6 @@ +

This is a paragraph. +This is a paragraph. +This is a . +This is a paragraph. +This is a {:/comment} simple {:/} paragraph. +This is a {::comment} paragraph.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.text b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.text new file mode 100644 index 00000000..8b9e8d36 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/comment.text @@ -0,0 +1,6 @@ +This is a {::comment}simple{:/} paragraph. +This is a {::comment}simple{:/comment} paragraph. +This is a {::comment}simple {:/other} paragraph{:/comment}. +This is a {::comment/} paragraph. +This is a {:/comment} simple {:/} paragraph. +This is a {::comment} paragraph. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.html b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.html new file mode 100644 index 00000000..63c2c404 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.html @@ -0,0 +1 @@ +

This is {::something}paragraph{:/}

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.text b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.text new file mode 100644 index 00000000..a7e77375 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/ignored.text @@ -0,0 +1 @@ +This is {::something}paragraph{:/} diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.html b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.html new file mode 100644 index 00000000..83de9312 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.html @@ -0,0 +1 @@ +

This is *some* text.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.text b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.text new file mode 100644 index 00000000..57c4b38f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/nomarkdown.text @@ -0,0 +1 @@ +This is {::nomarkdown}*some*{:/} text. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.html b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.html new file mode 100644 index 00000000..48e3076a --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.html @@ -0,0 +1 @@ +

This is an option *true*!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.text b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.text new file mode 100644 index 00000000..e289491e --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/extension/options.text @@ -0,0 +1 @@ +This is an {::options parse_span_html="false" /} option *true*! diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.html b/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.html new file mode 100644 index 00000000..c0f3a475 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.html @@ -0,0 +1,6 @@ +

This is a span.

+ +

This is a span.

+ +

This is an{: .ignored} span ial. +This is an{: .escaped} span ial.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.text b/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.text new file mode 100644 index 00000000..8945602b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/ial/simple.text @@ -0,0 +1,6 @@ +This is a `span`{: .hund #dog}. + +This is a `span`{: .hund #dog}{: .katz key='val'}. + +This is an{: .ignored} span ial. +This is an\{: .escaped} span ial. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.html new file mode 100644 index 00000000..11066a50 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.html @@ -0,0 +1,11 @@ +

This is a line
+with a line break.

+ +

This is a line +without a line break.

+ +

This is a line
+with a line\
+break.

+ +

Line break on last line.

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.latex new file mode 100644 index 00000000..a62ff561 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.latex @@ -0,0 +1,12 @@ +This is a line\newline +with a line break. + +This is a line +without a line break. + +This is a line \newline +with a line\textbackslash{} \newline +break. + +Line break on last line. + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.text new file mode 100644 index 00000000..92f866f2 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/line_breaks/normal.text @@ -0,0 +1,11 @@ +This is a line +with a line break. + +This is a line +without a line break. + +This is a line \\ +with a line\\ +break. + +Line break on last line. diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.html b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.html new file mode 100644 index 00000000..3b93c542 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.html @@ -0,0 +1 @@ +

$5+5$ inline math

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.options b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.options new file mode 100644 index 00000000..06d559e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.options @@ -0,0 +1 @@ +:math_engine: ~ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.text b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.text new file mode 100644 index 00000000..a22f9fd4 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/math/no_engine.text @@ -0,0 +1 @@ +$$5+5$$ inline math diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.html b/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.html new file mode 100644 index 00000000..459d03f3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.html @@ -0,0 +1,10 @@ +

This is \(\lambda_\alpha > 5\) some math. With \(1 ++ 1\) new line characters in between.

+ +

\(5+5\) inline math, $5.00 $$no math$$

+ +

$$5+5$$ inline math

+ +

\(5+5\)

+ +

$$5+5$$

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.text b/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.text new file mode 100644 index 00000000..e37a0078 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/math/normal.text @@ -0,0 +1,10 @@ +This is $$\lambda_\alpha > 5$$ some math. With $$1 ++ 1$$ new line characters in between. + +$$5+5$$ inline math, $5.00 \$$no math$$ + +\$\$5+5$$ inline math + +\$$5+5$$ + +\$\$5+5$$ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.html new file mode 100644 index 00000000..21a29033 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.html @@ -0,0 +1,6 @@ +

This is the A&O. © 2008 by me +As well \& as this. Some ŗ other +values may ¯ may also show but +not st. like &#xYZ;.

+ +

This <span> is BS&T; done!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.options new file mode 100644 index 00000000..036c5619 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.options @@ -0,0 +1 @@ +:entity_output: :as_input diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.text new file mode 100644 index 00000000..7ef42c7b --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities.text @@ -0,0 +1,6 @@ +This is the A&O. © 2008 by me +As well \& as this. Some ŗ other +values may ¯ may also show but +not st. like &#xYZ;. + +This <span> is BS&T; done! diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.html new file mode 100644 index 00000000..ed2817bb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.html @@ -0,0 +1 @@ +

This "is" 'the' A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.options new file mode 100644 index 00000000..32a751e3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.options @@ -0,0 +1,2 @@ +:entity_output: :as_char +:smart_quotes: apos,apos,quot,quot diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.text new file mode 100644 index 00000000..279b5115 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_char.text @@ -0,0 +1 @@ +This "is" 'the' A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.html new file mode 100644 index 00000000..d2eec9dd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.options new file mode 100644 index 00000000..036c5619 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.options @@ -0,0 +1 @@ +:entity_output: :as_input diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_as_input.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.html new file mode 100644 index 00000000..d04613ee --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_numeric.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.html new file mode 100644 index 00000000..258ba147 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.options new file mode 100644 index 00000000..c195785f --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.options @@ -0,0 +1 @@ +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/entities_symbolic.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.html new file mode 100644 index 00000000..dcce4cc3 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.html @@ -0,0 +1 @@ +

2 > 1 > 0

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.text new file mode 100644 index 00000000..7dfb7f12 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/greaterthan.text @@ -0,0 +1 @@ +2 > 1 > 0 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.html new file mode 100644 index 00000000..8ebac237 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.html @@ -0,0 +1 @@ +

0 < 1 < 2

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.text new file mode 100644 index 00000000..038df8bb --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/lowerthan.text @@ -0,0 +1 @@ +0 < 1 < 2 diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.html new file mode 100644 index 00000000..02d1dbce --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.html @@ -0,0 +1,40 @@ +

This is… something—this too–!

+ +

This «is» some text, « this » too!

+ +

“Fancy quotes” are ‘cool’, even in the ’80s! +Je t’ aime. You’re a funny one! Thomas’ name +Mark’s name. “…you” +“‘Nested’ quotes are ‘possible’”, too! +‘“Otherway” is “round”’!

+ +

‘Opening now!’

+ +

’80s are really cool.

+ +

Cluster’s Last Stand.

+ +

Nam liber tempor +“…At vero eos et accusam”

+ +

“Single underscores should work.”

+ +

“Single asterisks should work.”

+ +

‘Double underscores should work.’

+ +

‘Double asterisks should work.’

+ +

“Hurrah!”

+ +

‘Absolutely.’

+ +

“…some Text”

+ +

“… some Text”

+ +

This: “…some Text”

+ +

This: “… some Text”

+ +

”[foo]” “[foo]” d “[foo]”

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.options new file mode 100644 index 00000000..4f1c17c6 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.options @@ -0,0 +1 @@ +:entity_output: symbolic diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.text new file mode 100644 index 00000000..27e090e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography.text @@ -0,0 +1,40 @@ +This is... something---this too--! + +This <> some text, << this >> too! + +"Fancy quotes" are 'cool', even in the '80s! +Je t' aime. You're a funny one! Thomas' name +Mark's name. "...you" +"'Nested' quotes are 'possible'", too! +'"Otherway" is "round"'! + +'Opening now!' + +'80s are really cool. + +Cluster's Last Stand. + +Nam liber tempor +"...At vero eos et accusam" + +"_Single underscores_ should work." + +"*Single asterisks* should work." + +'__Double underscores__ should work.' + +'**Double asterisks** should work.' + +"_Hurrah!_" + +'__Absolutely__.' + +"...some Text" + +"... some Text" + +This: "...some Text" + +This: "... some Text" + +"\[foo]" "\[foo]" d "\[foo]" diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.html b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.html new file mode 100644 index 00000000..4a6c2260 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.html @@ -0,0 +1,3 @@ +

This ... something---this too--!

+ +

This <<is>> some text, << this >> too!

diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.latex b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.latex new file mode 100644 index 00000000..c7d9ba59 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.latex @@ -0,0 +1,4 @@ +This ... something---this too--! + +This \textless{}\textless{}is\textgreater{}\textgreater{} some text, \textless{}\textless{} this \textgreater{}\textgreater{} too! + diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.options b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.options new file mode 100644 index 00000000..d0a03132 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.options @@ -0,0 +1,8 @@ +typographic_symbols: + hellip: '...' + mdash: '---' + ndash: '--' + laquo: '<<' + raquo: '>>' + laquo_space: '<< ' + raquo_space: ' >>' diff --git a/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.text b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.text new file mode 100644 index 00000000..a3d59b37 --- /dev/null +++ b/bin/gems/kramdown-2.5.1/test/testcases/span/text_substitutions/typography_subst.text @@ -0,0 +1,3 @@ +This ... something---this too--! + +This <> some text, << this >> too! diff --git a/bin/gems/kramdown-2.5.2/AUTHORS b/bin/gems/kramdown-2.5.2/AUTHORS new file mode 100644 index 00000000..05835967 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/AUTHORS @@ -0,0 +1 @@ +The author of kramdown is Thomas Leitner . diff --git a/bin/gems/kramdown-2.5.2/CONTRIBUTERS b/bin/gems/kramdown-2.5.2/CONTRIBUTERS new file mode 100644 index 00000000..fa84260f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/CONTRIBUTERS @@ -0,0 +1,93 @@ + Count Name +======= ==== + 992 Thomas Leitner + 18 Ashwin Maroli + 7 Christian Cornelssen + 6 Gioele Barabucci + 5 Gleb Mazovetskiy + 4 Ted Pak + 4 Shuanglei Tao + 4 Dan Allen + 4 Arne Brasseur + 3 gettalong + 3 Henning Perl + 3 Carsten Bormann + 3 Brandur + 3 Ben Armston + 3 Ashwin Maroli + 3 Alex Marandon + 2 Tom Thorogood + 2 Parker Moore + 2 Nathanael Jones + 2 Max Meyer + 2 Jo Hund + 2 Bryce Willey + 2 Bran + 1 winniehell + 1 utenmiki + 1 tomykaira + 1 tom93 + 1 timcraft + 1 scherr + 1 myqlarson + 1 milo.simpson + 1 l3kn + 1 aschmitz <29508+aschmitz@users.noreply.github.com> + 1 William + 1 Virgil Ierubino <30758921+Convincible@users.noreply.github.com> + 1 Uwe Kubosch + 1 Trevor Wennblom + 1 Tobin Yehle + 1 Tim Blair + 1 Tim Besard + 1 Tim Bates + 1 Sun Yaozhu + 1 Stephen Crosby + 1 Stephen + 1 Stan Hu + 1 Simon Lydell + 1 Simon Coffey + 1 Shusaku NAKAZATO + 1 Sebastian Boehm + 1 Postmodern + 1 Pete Michaud + 1 Paul McMahon + 1 Paul <2528280+psfrolov@users.noreply.github.com> + 1 Noah Doersing + 1 Michal Till + 1 Maxime Kjaer + 1 Matt Hickford + 1 Martyn Chamberlin + 1 Marek Tuchowski + 1 Marcus Stollsteimer + 1 Luca Barbato + 1 Kir Kolyshkin + 1 Jun Aruga + 1 Jonathan Hooper + 1 John Haugeland + 1 John Croisant + 1 Joe Fiorini + 1 Jens Kraemer + 1 Jay Stramel + 1 Hirofumi Wakasugi + 1 Hector Correa + 1 Florian Klampfer + 1 Floreal Morandat florealm@gmail.com + 1 Fangyi Zhou + 1 Diego Galeota + 1 David Rodríguez + 1 Daniel Bair + 1 Damien Pollet + 1 Cédric Boutillier + 1 Christopher Jefferson + 1 Christian Boos + 1 Bob Lail + 1 Ashesh Kumar Singh + 1 Ashe Connor + 1 Antoine Cotten + 1 Andrew + 1 Alpha Chen + 1 Alexey Vasiliev + 1 Alex Tomlins + 1 Alex Taylor + 1 284km diff --git a/bin/gems/kramdown-2.5.2/COPYING b/bin/gems/kramdown-2.5.2/COPYING new file mode 100644 index 00000000..1c29282e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/COPYING @@ -0,0 +1,30 @@ +kramdown - fast, pure-Ruby Markdown-superset converter +Copyright (C) 2009-2013 Thomas Leitner + +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. + + +Some test cases and the benchmark files are based on test cases from +the MDTest test suite: + + MDTest + Copyright (c) 2007 Michel Fortin + + diff --git a/bin/gems/kramdown-2.5.2/README.md b/bin/gems/kramdown-2.5.2/README.md new file mode 100644 index 00000000..981c0044 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/README.md @@ -0,0 +1,77 @@ +# kramdown + +## Readme first! + +kramdown was originally licensed under the GPL until the 1.0.0 release. However, due to the many +requests it is now released under the MIT license and therefore can easily be used in commercial +projects, too. + +However, if you use kramdown in a commercial setting, please consider **contributing back any +changes** for the benefit of the community and/or [**becoming a +sponsor**](https://github.com/sponsors/gettalong/) or [**a +patron**](https://www.patreon.com/gettalong) - thanks! + +Sponsors: + +* **GROSSWEBER** provides software + development consulting and training services. + + +## Introduction + +kramdown is a fast, pure Ruby Markdown superset converter, using a strict syntax definition and +supporting several common extensions. + +The syntax definition for the kramdown syntax can be found in **doc/syntax.page** (or online at +) and a quick reference is available in +**doc/quickref.page** or online at . + +The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However, +due to its flexibility (by creating an internal AST) it supports other input and output formats as +well. Here is a list of the supported formats: + +* input formats: kramdown (a Markdown superset), Markdown, GFM, HTML +* output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn + +All the documentation on the available input and output formats is available in the **doc/** +directory and online at . + +Starting from version 1.0.0 kramdown is using a versioning scheme with major, minor and patch parts +in the version number where the major number changes on backwards-incompatible changes, the minor +number on the introduction of new features and the patch number on everything else. + +For information about changes between versions, have a look at + or the commit history! + + +## Usage + +kramdown has a very simple API, so using kramdown is as easy as + +```ruby +require 'kramdown' + +Kramdown::Document.new(text).to_html +``` + +For detailed information have a look at the API documentation of the `Kramdown::Document` class. + +The full API documentation is available at , other sites with an +API documentation for kramdown probably don't provide the complete documentation! + +There are also some third-party libraries that extend the functionality of kramdown -- see the +kramdown Wiki at . + + +## Development + +Just clone the git repository as described in **doc/installation.page** and you are good to go. You +probably want to install `rake` so that you can use the provided rake tasks. + +If you want to run the tests, the development dependencies are needed as well as some additional +programs like `tidy` and `latex`. See the `.travis.yml` file for more information. + + +## License + +MIT - see the **COPYING** file. diff --git a/bin/gems/kramdown-2.5.2/VERSION b/bin/gems/kramdown-2.5.2/VERSION new file mode 100644 index 00000000..f225a78a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/VERSION @@ -0,0 +1 @@ +2.5.2 diff --git a/bin/gems/kramdown-2.5.2/bin/kramdown b/bin/gems/kramdown-2.5.2/bin/kramdown new file mode 100755 index 00000000..6aeb9a46 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/bin/kramdown @@ -0,0 +1,135 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2019 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'optparse' +require 'rbconfig' +require 'yaml' +require 'kramdown' + +def add_kramdown_options(opts, parsed_options, banner: [], ignore: []) + banner_shown = false + defined_options = [] + Kramdown::Options.definitions.sort.each do |n, definition| + next if ignore.include?(n) + + unless banner_shown + opts.separator("") + banner.each {|part| opts.separator(part) } + opts.separator("") + banner_shown = true + end + + defined_options << n + no = n.to_s.tr('_', '-') + if definition.type == Kramdown::Options::Boolean + opts.on("--[no-]#{no}") {|v| parsed_options[n] = Kramdown::Options.parse(n, v) } + else + type = definition.type + type = String if type == Symbol || type == Object + opts.on("--#{no} ARG", type) {|v| parsed_options[n] = Kramdown::Options.parse(n, v) } + end + + definition.desc.split("\n").each do |line| + opts.separator opts.summary_indent + ' ' * 6 + line + end + opts.separator '' + end + defined_options +end + +config_file = nil +begin + config_dir = case RbConfig::CONFIG['host_os'] + when /bccwin|cygwin|djgpp|mingw|mswin|wince/i + File.expand_path((ENV['HOME'] || ENV['USERPROFILE'] || "~") + "/AppData/Local") + when /darwin|mac os/ + File.expand_path("~/Library/Preferences/") + else + File.expand_path(ENV['XDG_CONFIG_HOME'] || '~/.config') + end + config_file = File.join(config_dir, "kramdownrc") +rescue StandardError +end + +options = {} +format = ['html'] + +defined_options = [] +OptionParser.new do |opts| + opts.banner = "Usage: kramdown [options] [FILE FILE ...]" + opts.summary_indent = ' ' * 4 + + opts.separator "" + opts.separator "Command line options:" + opts.separator "" + + opts.on("-i", "--input ARG", "Specify the input format: kramdown (default), " \ + "html, or markdown") {|v| options[:input] = v } + opts.on("-o", "--output ARG", Array, "Specify one or more output formats separated by commas: " \ + "html (default),", "kramdown, latex, man or remove_html_tags") {|v| format = v } + opts.on("-x", "--extension EXT", Array, "Load one or more extensions (without the 'kramdown-' " \ + "prefix) separated", "by commas (e.g. parser-gfm,syntax-coderay)", + "Note: Use this option before other options!") do |exts| + exts.each do |ext| + require "kramdown-#{ext}" + new_options = add_kramdown_options(opts, options, banner: ["#{ext} options:"], + ignore: defined_options) + defined_options.concat(new_options) + rescue LoadError + $stderr.puts "Couldn't load extension #{ext}, ignoring" + end + end + opts.separator "" + opts.on("--no-config-file", "Do not read any configuration file. Default behavior is to check " \ + "for a", "configuration file and read it if it exists.") { config_file = nil } + opts.on("--config-file FILE", "Specify the name of a configuration file with kramdown options " \ + "in YAML", "format, e.g. \"auto_id_prefix: ARG\" instead of \"--auto-id-prefix ARG\"", + "and \"auto_ids: false\" instead of \"--no-auto-ids\".", + "Default: #{config_file}") {|v| config_file = v } + opts.separator "" + opts.on("-v", "--version", "Show the version of kramdown") do + puts Kramdown::VERSION + exit + end + opts.on("-h", "--help", "Show the help") do + puts opts.summarize(+'', 5, 72) + exit + end + + new_options = add_kramdown_options(opts, options, banner: ["kramdown options:"]) + defined_options.concat(new_options) +end.parse! + +begin + if config_file && File.exist?(config_file) + config_file_options = + if YAML.method(:safe_load).parameters.include?(%i[key permitted_classes]) + YAML.safe_load(File.read(config_file), permitted_classes: [Symbol]) + else # compatibility with Psych < 3.1.0 + YAML.safe_load(File.read(config_file), [Symbol]) + end + case config_file_options + when nil # empty configuration file except perhaps YAML header and comments + # Nothing to do + when Hash + options = config_file_options.merge(options) + else + raise Kramdown::Error, "No YAML map in configuration file \"#{config_file}\"" + end + end + doc = Kramdown::Document.new(ARGF.read, options) + result = '' + format.each {|f| result = doc.send("to_#{f}") } + puts result + doc.warnings.each {|warn| $stderr.puts "Warning: #{warn}" } +rescue Kramdown::Error => e + $stderr.puts "Error: #{e.message}" + exit(1) +end diff --git a/bin/gems/kramdown-2.5.2/data/kramdown/document.html b/bin/gems/kramdown-2.5.2/data/kramdown/document.html new file mode 100644 index 00000000..731d0ea9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/data/kramdown/document.html @@ -0,0 +1,22 @@ + + + + <% if @converter.root.options[:encoding] %> + + <% end %> +<% +extend ::Kramdown::Utils::Html +title = '' +h = @converter.root.children.find {|c| c.type == :header} +if h + collector = lambda {|c| c.children.collect {|cc| cc.type == :text ? escape_html(cc.value, :text) : collector.call(cc)}.join('')} + title = collector.call(h) +end +%> + <%= title %> + + + + <%= @body %> + + diff --git a/bin/gems/kramdown-2.5.2/data/kramdown/document.latex b/bin/gems/kramdown-2.5.2/data/kramdown/document.latex new file mode 100644 index 00000000..acdf346a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/data/kramdown/document.latex @@ -0,0 +1,50 @@ +<% +encmap = { + 'UTF-8' => 'utf8x', + 'US-ASCII' => 'ascii', + 'ISO-8859-1' => 'latin1', + 'ISO-8859-2' => 'latin2', + 'ISO-8859-3' => 'latin3', + 'ISO-8859-4' => 'latin4', + 'ISO-8859-5' => 'latin5', + 'ISO-8859-9' => 'latin9', + 'ISO-8859-10' => 'latin10', + 'CP850' => 'cp850', + 'CP852' => 'cp852', + 'CP858' => 'cp858', + 'CP437' => 'cp437', + 'CP865' => 'cp865', + 'CP1250' => 'cp120', + 'CP1252' => 'cp1252', + 'CP1257' => 'cp1257' +} +%> +\documentclass{scrartcl} +<% if RUBY_VERSION >= '1.9' %> +\usepackage[<%= encmap[@body.encoding.name] %>]{inputenc} +<% else %> +\usepackage[mathletters]{ucs} +\usepackage[utf8x]{inputenc} +<% end %> +\usepackage[T1]{fontenc} +\usepackage{listings} +<% @converter.data[:packages].each {|pkg| %>\usepackage{<%= pkg %>} +<% } %> +\usepackage{hyperref} + +<% if @converter.data[:packages].include?('fancyvrb') %> +\VerbatimFootnotes +<% end %> + +<% if @converter.data[:packages].include?('acronym') %> +<% @converter.root.options[:abbrev_defs].each_pair do |k,v| %>\acrodef{<%= @converter.normalize_abbreviation_key(k) %>}[<%= k %>]{<%= @converter.escape(v) %>} +<% end %> +<% end %> + +\setcounter{footnote}{<%= @converter.options[:footnote_nr] - 1 %>} + +\hypersetup{colorlinks=true,urlcolor=blue} + +\begin{document} +<%= @body %> +\end{document} diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown.rb b/bin/gems/kramdown-2.5.2/lib/kramdown.rb new file mode 100644 index 00000000..3f25463b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown.rb @@ -0,0 +1,10 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/document' diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter.rb new file mode 100644 index 00000000..25cf22cc --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter.rb @@ -0,0 +1,68 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' + +module Kramdown + + # This module contains all available converters, i.e. classes that take a root Element and convert + # it to a specific output format. The result is normally a string. For example, the + # Converter::Html module converts an element tree into valid HTML. + # + # Converters use the Base class for common functionality (like applying a template to the output) + # \- see its API documentation for how to create a custom converter class. + module Converter + + autoload :Base, 'kramdown/converter/base' + autoload :Html, 'kramdown/converter/html' + autoload :Latex, 'kramdown/converter/latex' + autoload :Kramdown, 'kramdown/converter/kramdown' + autoload :Toc, 'kramdown/converter/toc' + autoload :RemoveHtmlTags, 'kramdown/converter/remove_html_tags' + autoload :HashAST, 'kramdown/converter/hash_ast' + autoload :HashAst, 'kramdown/converter/hash_ast' + autoload :Man, 'kramdown/converter/man' + + extend ::Kramdown::Utils::Configurable + + configurable(:syntax_highlighter) + + ['Minted', "Rouge"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_syntax_highlighter(kn_down) do |converter, text, lang, type, opts| + require "kramdown/converter/syntax_highlighter/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::SyntaxHighlighter::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_syntax_highlighter(kn_down, klass) + else + add_syntax_highlighter(kn_down) { nil } + end + syntax_highlighter(kn_down).call(converter, text, lang, type, opts) + end + end + + configurable(:math_engine) + + ["Mathjax"].each do |klass_name| + kn_down = klass_name.downcase.intern + add_math_engine(kn_down) do |converter, el, opts| + require "kramdown/converter/math_engine/#{kn_down}" + klass = ::Kramdown::Utils.deep_const_get("::Kramdown::Converter::MathEngine::#{klass_name}") + if !klass.const_defined?(:AVAILABLE) || klass::AVAILABLE + add_math_engine(kn_down, klass) + else + add_math_engine(kn_down) { nil } + end + math_engine(kn_down).call(converter, el, opts) + end + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/base.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/base.rb new file mode 100644 index 00000000..8809782a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/base.rb @@ -0,0 +1,257 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'erb' +require 'kramdown/utils' +require 'kramdown/document' + +module Kramdown + + module Converter + + # == \Base class for converters + # + # This class serves as base class for all converters. It provides methods that can/should be + # used by all converters (like #generate_id) as well as common functionality that is + # automatically applied to the result (for example, embedding the output into a template). + # + # A converter object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during conversion. Therefore one can't instantiate a converter object + # directly but only use the Base::convert method. + # + # == Implementing a converter + # + # Implementing a new converter is rather easy: just derive a new class from this class and put + # it in the Kramdown::Converter module (the latter is only needed if auto-detection should work + # properly). Then you need to implement the #convert method which has to contain the conversion + # code for converting an element and has to return the conversion result. + # + # The actual transformation of the document tree can be done in any way. However, writing one + # method per element type is a straight forward way to do it - this is how the Html and Latex + # converters do the transformation. + # + # Have a look at the Base::convert method for additional information! + class Base + + # Can be used by a converter for storing arbitrary information during the conversion process. + attr_reader :data + + # The hash with the conversion options. + attr_reader :options + + # The root element that is converted. + attr_reader :root + + # The warnings array. + attr_reader :warnings + + # Initialize the converter with the given +root+ element and +options+ hash. + def initialize(root, options) + @options = options + @root = root + @data = {} + @warnings = [] + end + private_class_method(:new, :allocate) + + # Returns whether the template should be applied before the conversion of the tree. + # + # Defaults to false. + def apply_template_before? + false + end + + # Returns whether the template should be applied after the conversion of the tree. + # + # Defaults to true. + def apply_template_after? + true + end + + # Convert the element tree +tree+ and return the resulting conversion object (normally a + # string) and an array with warning messages. The parameter +options+ specifies the conversion + # options that should be used. + # + # Initializes a new instance of the calling class and then calls the #convert method with + # +tree+ as parameter. + # + # If the +template+ option is specified and non-empty, the template is evaluate with ERB + # before and/or after the tree conversion depending on the result of #apply_template_before? + # and #apply_template_after?. If the template is evaluated before, an empty string is used for + # the body; if evaluated after, the result is used as body. See ::apply_template. + # + # The template resolution is done in the following way (for the converter ConverterName): + # + # 1. Look in the current working directory for the template. + # + # 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting + # file in the current working directory (the form +.convertername+ is deprecated). + # + # 3. Append +.converter_name+ to the template name and look for it in the kramdown data + # directory (the form +.convertername+ is deprecated). + # + # 4. Check if the template name starts with 'string://' and if so, strip this prefix away and + # use the rest as template. + def self.convert(tree, options = {}) + converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {}))) + + if !converter.options[:template].empty? && converter.apply_template_before? + apply_template(converter, '') + end + result = converter.convert(tree) + if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY + result.encode!(tree.options[:encoding] || + (raise ::Kramdown::Error, "Missing encoding option on root element")) + end + if !converter.options[:template].empty? && converter.apply_template_after? + result = apply_template(converter, result) + end + + [result, converter.warnings] + end + + # Convert the element +el+ and return the resulting object. + # + # This is the only method that has to be implemented by sub-classes! + def convert(_el) + raise NotImplementedError + end + + # Apply the +template+ using +body+ as the body string. + # + # The template is evaluated using ERB and the body is available in the @body instance variable + # and the converter object in the @converter instance variable. + def self.apply_template(converter, body) # :nodoc: + erb = ERB.new(get_template(converter.options[:template])) + obj = Object.new + obj.instance_variable_set(:@converter, converter) + obj.instance_variable_set(:@body, body) + erb.result(obj.instance_eval { binding }) + end + + # Return the template specified by +template+. + def self.get_template(template) # :nodoc: + format_ext = '.' + ::Kramdown::Utils.snake_case(name.split("::").last) + shipped = File.join(::Kramdown.data_dir, template + format_ext) + if File.exist?(template) + File.read(template) + elsif File.exist?(template + format_ext) + File.read(template + format_ext) + elsif File.exist?(shipped) + File.read(shipped) + elsif template.start_with?('string://') + template.delete_prefix("string://") + else + raise "The specified template file #{template} does not exist" + end + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + end + + # Return +true+ if the header element +el+ should be used for the table of contents (as + # specified by the +toc_levels+ option). + def in_toc?(el) + @options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/ + end + + # Return the output header level given a level. + # + # Uses the +header_offset+ option for adjusting the header level. + def output_header_level(level) + [[level + @options[:header_offset], 6].min, 1].max + end + + # Extract the code block/span language from the attributes. + def extract_code_language(attr) + if attr['class'] && attr['class'] =~ /\blanguage-\S+/ + attr['class'].scan(/\blanguage-(\S+)/).first.first + end + end + + # See #extract_code_language + # + # *Warning*: This version will modify the given attributes if a language is present. + def extract_code_language!(attr) + lang = extract_code_language(attr) + attr['class'] = attr['class'].sub(/\blanguage-\S+/, '').strip if lang + attr.delete('class') if lang && attr['class'].empty? + lang + end + + # Highlight the given +text+ in the language +lang+ with the syntax highlighter configured + # through the option 'syntax_highlighter'. + def highlight_code(text, lang, type, opts = {}) + return nil unless @options[:syntax_highlighter] + + highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter]) + if highlighter + highlighter.call(self, text, lang, type, opts) + else + warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.") + nil + end + end + + # Format the given math element with the math engine configured through the option + # 'math_engine'. + def format_math(el, opts = {}) + return nil unless @options[:math_engine] + + engine = ::Kramdown::Converter.math_engine(@options[:math_engine]) + if engine + engine.call(self, el, opts) + else + warning("The configured math engine #{@options[:math_engine]} is not available.") + nil + end + end + + # Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID. + # + # Uses the option +auto_id_prefix+: the value of this option is prepended to every generated + # ID. + def generate_id(str) + str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids] + gen_id = basic_generate_id(str) + gen_id = 'section' if gen_id.empty? + @used_ids ||= {} + if @used_ids.key?(gen_id) + gen_id += "-#{@used_ids[gen_id] += 1}" + else + @used_ids[gen_id] = 0 + end + @options[:auto_id_prefix] + gen_id + end + + # The basic version of the ID generator, without any special provisions for empty or unique + # IDs. + def basic_generate_id(str) + gen_id = str.gsub(/^[^a-zA-Z]+/, '') + gen_id.tr!('^a-zA-Z0-9 -', '') + gen_id.tr!(' ', '-') + gen_id.downcase! + gen_id + end + + SMART_QUOTE_INDICES = {lsquo: 0, rsquo: 1, ldquo: 2, rdquo: 3} # :nodoc: + + # Return the entity that represents the given smart_quote element. + def smart_quote_entity(el) + res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]] + ::Kramdown::Utils::Entities.entity(res) + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/hash_ast.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/hash_ast.rb new file mode 100644 index 00000000..f69d3884 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/hash_ast.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a nested hash for further processing or debug output. + class HashAST < Base + + def convert(el) + hash = {type: el.type} + hash[:attr] = el.attr unless el.attr.empty? + hash[:value] = el.value unless el.value.nil? + hash[:options] = el.options unless el.options.empty? + unless el.children.empty? + hash[:children] = [] + el.children.each {|child| hash[:children] << convert(child) } + end + hash + end + + end + + HashAst = HashAST + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/html.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/html.rb new file mode 100644 index 00000000..783c0882 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/html.rb @@ -0,0 +1,545 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to HTML. + # + # You can customize the HTML converter by sub-classing it and overriding the +convert_NAME+ + # methods. Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+indent+] A number representing the current amount of spaces for indent (only used for + # block-level elements). + # + # The return value of such a method has to be a string containing the element +el+ formatted as + # HTML element. + class Html < Base + + include ::Kramdown::Utils::Html + include ::Kramdown::Parser::Html::Constants + + # The amount of indentation used when nesting HTML tags. + attr_accessor :indent + + # Initialize the HTML converter with the given Kramdown document +doc+. + def initialize(root, options) + super + @footnote_counter = @footnote_start = @options[:footnote_nr] + @footnotes = [] + @footnotes_by_name = {} + @footnote_location = nil + @toc = [] + @toc_code = nil + @indent = 2 + @stack = [] + + # stash string representation of symbol to avoid allocations from multiple interpolations. + @highlighter_class = " highlighter-#{options[:syntax_highlighter]}" + @dispatcher = Hash.new {|h, k| h[k] = :"convert_#{k}" } + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, indent = -@indent) + send(@dispatcher[el.type], el, indent) + end + + # Return the converted content of the children of +el+ as a string. The parameter +indent+ has + # to be the amount of indentation used for the element +el+. + # + # Pushes +el+ onto the @stack before converting the child elements and pops it from the stack + # afterwards. + def inner(el, indent) + result = +'' + indent += @indent + @stack.push(el) + el.children.each do |inner_el| + result << send(@dispatcher[inner_el.type], inner_el, indent) + end + @stack.pop + result + end + + def convert_blank(_el, _indent) + "\n" + end + + def convert_text(el, _indent) + escaped = escape_html(el.value, :text) + @options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped + end + + def convert_p(el, indent) + if el.options[:transparent] + inner(el, indent) + elsif el.children.size == 1 && el.children.first.type == :img && + el.children.first.options[:ial]&.[](:refs)&.include?('standalone') + convert_standalone_image(el, indent) + else + format_as_block_html("p", el.attr, inner(el, indent), indent) + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, indent) + figure_attr = el.attr.dup + image_attr = el.children.first.attr.dup + + if image_attr.key?('class') && !figure_attr.key?('class') + figure_attr['class'] = image_attr.delete('class') + end + if image_attr.key?('id') && !figure_attr.key?('id') + figure_attr['id'] = image_attr.delete('id') + end + + body = "#{' ' * (indent + @indent)}\n" \ + "#{' ' * (indent + @indent)}
#{image_attr['alt']}
\n" + format_as_indented_block_html("figure", figure_attr, body, indent) + end + + def convert_codeblock(el, indent) + attr = el.attr.dup + lang = extract_code_language!(attr) + hl_opts = {} + highlighted_code = highlight_code(el.value, el.options[:lang] || lang, :block, hl_opts) + + if highlighted_code + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + "#{' ' * indent}#{highlighted_code}#{' ' * indent}
\n" + else + result = escape_html(el.value) + result.chomp! + if el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m| + suffix = ($1 ? '-l' : ($2 ? '-r' : '')) + m.scan(/./).map do |c| + case c + when "\t" then "\t" + when " " then "⋅" + end + end.join + end + end + code_attr = {} + code_attr['class'] = "language-#{lang}" if lang + "#{' ' * indent}" \ + "#{result}\n
\n" + end + end + + def convert_blockquote(el, indent) + format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent) + end + + def convert_header(el, indent) + attr = el.attr.dup + if @options[:auto_ids] && !attr['id'] + attr['id'] = generate_id(el.options[:raw_text]) + end + + if @options[:header_links] && attr['id'].to_s.length > 0 + link = Element.new(:a, nil, nil) + link.attr['href'] = "##{attr['id']}" + el.children.unshift(link) + end + + @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el) + level = output_header_level(el.options[:level]) + format_as_block_html("h#{level}", attr, inner(el, indent), indent) + end + + def convert_hr(el, indent) + "#{' ' * indent}\n" + end + + ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze + private_constant :ZERO_TO_ONETWENTYEIGHT + + def convert_ul(el, indent) + if !@toc_code && el.options.dig(:ial, :refs)&.include?('toc') + @toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join] + @toc_code.last + elsif !@footnote_location && el.options.dig(:ial, :refs)&.include?('footnotes') + @footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join + else + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + end + alias convert_ol convert_ul + + def convert_dl(el, indent) + format_as_indented_block_html("dl", el.attr, inner(el, indent), indent) + end + + def convert_li(el, indent) + output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">" + res = inner(el, indent) + if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent]) + output << res << (res.match?(/\n\Z/) ? ' ' * indent : '') + else + output << "\n" << res << ' ' * indent + end + output << "\n" + end + alias convert_dd convert_li + + def convert_dt(el, indent) + attr = el.attr.dup + @stack.last.options[:ial][:refs].each do |ref| + if ref =~ /\Aauto_ids(?:-([\w-]+))?/ + attr['id'] = "#{$1}#{basic_generate_id(el.options[:raw_text])}".lstrip + break + end + end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs] + format_as_block_html("dt", attr, inner(el, indent), indent) + end + + def convert_html_element(el, indent) + res = inner(el, indent) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (res.empty? && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) ? " />" : ">#{res}") + else + output = +'' + if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output << ' ' * indent + end + output << "<#{el.value}#{html_attributes(el.attr)}" + if el.options[:is_closed] && el.options[:content_model] == :raw + output << " />" + elsif !res.empty? && el.options[:content_model] != :block + output << ">#{res}" + elsif !res.empty? + output << ">\n#{res.chomp}\n" << ' ' * indent << "" + elsif HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + output << " />" + else + output << ">" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, indent) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + ' ' * indent << el.value << "\n" + else + el.value + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, indent) + format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent) + end + alias convert_thead convert_table + alias convert_tbody convert_table + alias convert_tfoot convert_table + alias convert_tr convert_table + + ENTITY_NBSP = ::Kramdown::Utils::Entities.entity('nbsp') # :nodoc: + + def convert_td(el, indent) + res = inner(el, indent) + type = (@stack[-2].type == :thead ? :th : :td) + attr = el.attr + alignment = @stack[-3].options[:alignment][@stack.last.children.index(el)] + if alignment != :default + attr = el.attr.dup + attr['style'] = (attr.key?('style') ? "#{attr['style']}; " : '') + "text-align: #{alignment}" + end + format_as_block_html(type, attr, res.empty? ? entity_to_str(ENTITY_NBSP) : res, indent) + end + + def convert_comment(el, indent) + if el.options[:category] == :block + "#{' ' * indent}\n" + else + "" + end + end + + def convert_br(_el, _indent) + "
" + end + + def convert_a(el, indent) + format_as_span_html("a", el.attr, inner(el, indent)) + end + + def convert_img(el, _indent) + "" + end + + def convert_codespan(el, _indent) + attr = el.attr.dup + lang = extract_code_language(attr) + hl_opts = {} + result = highlight_code(el.value, lang, :span, hl_opts) + if result + add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang]) + else + result = escape_html(el.value) + end + + format_as_span_html('code', attr, result) + end + + def convert_footnote(el, _indent) + repeat = '' + name = @options[:footnote_prefix] + el.options[:name] + if (footnote = @footnotes_by_name[name]) + number = footnote[2] + repeat = ":#{footnote[3] += 1}" + else + number = @footnote_counter + @footnote_counter += 1 + @footnotes << [name, el.value, number, 0] + @footnotes_by_name[name] = @footnotes.last + end + formatted_link_text = sprintf(@options[:footnote_link_text], number) + "" \ + "" \ + "#{formatted_link_text}" + end + + def convert_raw(el, _indent) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, indent) + format_as_span_html(el.type, el.attr, inner(el, indent)) + end + alias convert_strong convert_em + + def convert_entity(el, _indent) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: [::Kramdown::Utils::Entities.entity('mdash')], + ndash: [::Kramdown::Utils::Entities.entity('ndash')], + hellip: [::Kramdown::Utils::Entities.entity('hellip')], + laquo_space: [::Kramdown::Utils::Entities.entity('laquo'), + ::Kramdown::Utils::Entities.entity('nbsp')], + raquo_space: [::Kramdown::Utils::Entities.entity('nbsp'), + ::Kramdown::Utils::Entities.entity('raquo')], + laquo: [::Kramdown::Utils::Entities.entity('laquo')], + raquo: [::Kramdown::Utils::Entities.entity('raquo')], + } # :nodoc: + def convert_typographic_sym(el, _indent) + if (result = @options[:typographic_symbols][el.value]) + escape_html(result, :text) + else + TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join + end + end + + def convert_smart_quote(el, _indent) + entity_to_str(smart_quote_entity(el)) + end + + def convert_math(el, indent) + if (result = format_math(el, indent: indent)) + result + else + attr = el.attr.dup + attr['class'] = "#{attr['class']} kdmath".lstrip + if el.options[:category] == :block + format_as_block_html('div', attr, "$$\n#{el.value}\n$$", indent) + else + format_as_span_html('span', attr, "$#{el.value}$") + end + end + end + + def convert_abbreviation(el, _indent) + title = @root.options[:abbrev_defs][el.value] + attr = @root.options[:abbrev_attr][el.value].dup + attr['title'] = title unless title.empty? + format_as_span_html("abbr", attr, el.value) + end + + def convert_root(el, indent) + result = inner(el, indent) + if @footnote_location + result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\")) + else + result << footnote_content + end + if @toc_code + toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {}) + text = toc_tree.children.empty? ? '' : convert(toc_tree, 0) + result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\")) + end + result + end + + # Format the given element as span HTML. + def format_as_span_html(name, attr, body) + "<#{name}#{html_attributes(attr)}>#{body}" + end + + # Format the given element as block HTML. + def format_as_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>#{body}\n" + end + + # Format the given element as block HTML with a newline after the start tag and indentation + # before the end tag. + def format_as_indented_block_html(name, attr, body, indent) + "#{' ' * indent}<#{name}#{html_attributes(attr)}>\n#{body}#{' ' * indent}\n" + end + + # Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And + # overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil. + def add_syntax_highlighter_to_class_attr(attr, lang = nil) + (attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip! + attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang + end + + # Generate and return an element tree for the table of contents. + def generate_toc_tree(toc, type, attr) + sections = Element.new(type, nil, attr.dup) + sections.attr['id'] ||= 'markdown-toc' + stack = [] + toc.each do |level, id, children| + li = Element.new(:li, nil, nil, level: level) + li.children << Element.new(:p, nil, nil, transparent: true) + a = Element.new(:a, nil) + a.attr['href'] = "##{id}" + a.attr['id'] = "#{sections.attr['id']}-#{id}" + a.children.concat(fix_for_toc_entry(Marshal.load(Marshal.dump(children)))) + li.children.last.children << a + li.children << Element.new(type) + + success = false + until success + if stack.empty? + sections.children << li + stack << li + success = true + elsif stack.last.options[:level] < li.options[:level] + stack.last.children.last.children << li + stack << li + success = true + else + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + end + end + until stack.empty? + item = stack.pop + item.children.pop if item.children.last.children.empty? + end + sections + end + + # Fixes the elements for use in a TOC entry. + def fix_for_toc_entry(elements) + remove_footnotes(elements) + unwrap_links(elements) + elements + end + + # Remove all link elements by unwrapping them. + def unwrap_links(elements) + elements.map! do |c| + unwrap_links(c.children) + c.type == :a ? c.children : c + end.flatten! + end + + # Remove all footnotes from the given elements. + def remove_footnotes(elements) + elements.delete_if do |c| + remove_footnotes(c.children) + c.type == :footnote + end + end + + # Obfuscate the +text+ by using HTML entities. + def obfuscate(text) + result = +'' + text.each_byte do |b| + result << (b > 128 ? b.chr : sprintf("&#%03d;", b)) + end + result.force_encoding(text.encoding) + result + end + + FOOTNOTE_BACKLINK_FMT = "%s%s" + + # Return an HTML ordered list with the footnote content for the used footnotes. + def footnote_content + ol = Element.new(:ol) + ol.attr['start'] = @footnote_start if @footnote_start != 1 + i = 0 + backlink_text = escape_html(@options[:footnote_backlink], :text) + while i < @footnotes.length + name, data, _, repeat = *@footnotes[i] + li = Element.new(:li, nil, 'id' => "fn:#{name}") + li.children = Marshal.load(Marshal.dump(data.children)) + + para = nil + if li.children.last.type == :p || @options[:footnote_backlink_inline] + parent = li + while !parent.children.empty? && ![:p, :header].include?(parent.children.last.type) + parent = parent.children.last + end + para = parent.children.last + insert_space = true + end + + unless para + li.children << (para = Element.new(:p)) + insert_space = false + end + + unless @options[:footnote_backlink].empty? + nbsp = entity_to_str(ENTITY_NBSP) + value = sprintf(FOOTNOTE_BACKLINK_FMT, (insert_space ? nbsp : ''), name, backlink_text) + para.children << Element.new(:raw, value) + (1..repeat).each do |index| + value = sprintf(FOOTNOTE_BACKLINK_FMT, nbsp, "#{name}:#{index}", + "#{backlink_text}#{index + 1}") + para.children << Element.new(:raw, value) + end + end + + ol.children << Element.new(:raw, convert(li, 4)) + i += 1 + end + if ol.children.empty? + '' + else + format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0) + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/kramdown.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/kramdown.rb new file mode 100644 index 00000000..07106de7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/kramdown.rb @@ -0,0 +1,458 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' +require 'kramdown/utils' + +module Kramdown + + module Converter + + # Converts an element tree to the kramdown format. + class Kramdown < Base + + # :stopdoc: + + include ::Kramdown::Utils::Html + + def initialize(root, options) + super + @linkrefs = [] + @footnotes = [] + @abbrevs = [] + @stack = [] + @list_indent = @options[:list_indent] + @list_spacing = ' ' * (@list_indent - 2) + end + + def convert(el, opts = {indent: 0}) + res = send("convert_#{el.type}", el, opts) + res = res.dup if res.frozen? + if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el)) + res << ial + res << "\n\n" if el.block? + elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] && + ([el.type, :codeblock].include?(opts[:next].type) || + (opts[:next].type == :blank && opts[:nnext] && + [el.type, :codeblock].include?(opts[:nnext].type))) + res << "^\n\n" + elsif el.block? && + ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) && + (el.type != :html_element || @stack.last.type != :html_element) && + (el.type != :p || !el.options[:transparent]) && + !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li) + res << "\n" + end + res + end + + def inner(el, opts = {indent: 0}) + @stack.push(el) + result = +'' + el.children.each_with_index do |inner_el, index| + options = opts.dup + options[:index] = index + options[:prev] = (index == 0 ? nil : el.children[index - 1]) + options[:pprev] = (index <= 1 ? nil : el.children[index - 2]) + options[:next] = (index == el.children.length - 1 ? nil : el.children[index + 1]) + options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index + 2]) + result << convert(inner_el, options) + end + @stack.pop + result + end + + def convert_blank(_el, _opts) + "" + end + + ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/ + + def convert_text(el, opts) + if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw) + el.value + else + result = el.value.gsub(/\A\n/) do + opts[:prev] && opts[:prev].type == :br ? '' : "\n" + end + result.gsub!(/\s+/, ' ') unless el.options[:cdata] + result.gsub!(ESCAPED_CHAR_RE) do + $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $& + end + result + end + end + + def convert_p(el, opts) + w = @options[:line_width] - opts[:indent].to_s.to_i + first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/) + first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" } + second&.gsub!(/^([=-]+\s*?)$/, "\\\1") + res = [first, second, *rest].compact.join("\n") + "\n" + res.gsub!(/^ {0,3}:/, "\\:") + if el.children.length == 1 && el.children.first.type == :math + res = "\\#{res}" + elsif res.start_with?('\$$') && res.end_with?("\\$$\n") + res.sub!(/^\\\$\$/, '\$\$') + end + res + end + + def convert_codeblock(el, _opts) + el.value.split("\n").map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n" + end + + def convert_blockquote(el, opts) + opts[:indent] += 2 + inner(el, opts).chomp.split("\n").map {|l| "> #{l}" }.join("\n") << "\n" + end + + def convert_header(el, opts) + opts[:in_header] = true + res = +'' + res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}" + res[-1, 1] = "\\#" if res[-1] == '#' + res << " {##{el.attr['id']}}" if el.attr['id'] && !el.attr['id'].strip.empty? + res << "\n" + end + + def convert_hr(_el, _opts) + "* * *\n" + end + + def convert_ul(el, opts) + inner(el, opts).sub(/\n+\Z/, "\n") + end + alias convert_ol convert_ul + alias convert_dl convert_ul + + def convert_li(el, opts) + sym, width = if @stack.last.type == :ul + ['* ' + @list_spacing, el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent] + else + ["#{opts[:index] + 1}.".ljust(4), 4] + end + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines) + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + res = +"#{sym}#{text}" + res << "^\n" if el.children.size == 1 && @stack.last.children.last == el && + (@stack.last.children.any? {|c| !c.children.first || c.children.first.type != :p } || @stack.last.children.size == 1) + res + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dd(el, opts) + sym, width = ": " + @list_spacing, (el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent) + if (ial = ial_for_element(el)) + sym << ial << " " + end + + opts[:indent] += width + text = inner(el, opts) + newlines = text.scan(/\n*\Z/).first + first, *last = text.split("\n") + last = last.map {|l| " " * width + l }.join("\n") + text = first.to_s + (last.empty? ? "" : "\n") + last + newlines + text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd + text << "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt + text << "\n" if el.children.empty? + if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent] + "\n#{sym}#{text}" + elsif el.children.first && el.children.first.type == :codeblock + "#{sym}\n #{text}" + else + "#{sym}#{text}" + end + end + + def convert_dt(el, opts) + result = +'' + if (ial = ial_for_element(el)) + result << ial << " " + end + result << inner(el, opts) << "\n" + end + + HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td] + + HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze + private_constant :HTML_ELEMENT_TYPES + + def convert_html_element(el, opts) + markdown_attr = el.options[:category] == :block && el.children.any? do |c| + c.type != :html_element && + (c.type != :p || !c.options[:transparent] || + c.children.any? {|t| !HTML_ELEMENT_TYPES.member?(t.type) }) && + c.block? + end + opts[:force_raw_text] = true if %w[script pre code].include?(el.value) + opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || \ + (el.options[:category] != :span && !markdown_attr) + opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text] + res = inner(el, opts) + if el.options[:category] == :span + "<#{el.value}#{html_attributes(el.attr)}" + \ + (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}" : " />") + else + output = +'' + attr = el.attr.dup + attr['markdown'] = '1' if markdown_attr + output << "<#{el.value}#{html_attributes(attr)}" + if !res.empty? && el.options[:content_model] != :block + output << ">#{res}" + elsif !res.empty? + output << ">\n#{res}" << "" + elsif HTML_TAGS_WITH_BODY.include?(el.value) + output << ">" + else + output << " />" + end + output << "\n" if @stack.last.type != :html_element || @stack.last.options[:content_model] != :raw + output + end + end + + def convert_xml_comment(el, _opts) + if el.options[:category] == :block && + (@stack.last.type != :html_element || @stack.last.options[:content_model] != :raw) + el.value + "\n" + else + el.value.dup + end + end + alias convert_xml_pi convert_xml_comment + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment] + inner(el, opts) + end + + def convert_thead(el, opts) + rows = inner(el, opts) + if opts[:alignment].all?(:default) + "#{rows}|#{'-' * 10}\n" + else + "#{rows}| " + opts[:alignment].map do |a| + case a + when :left then ":-" + when :right then "-:" + when :center then ":-:" + when :default then "-" + end + end.join(' ') << "\n" + end + end + + def convert_tbody(el, opts) + res = +'' + res << inner(el, opts) + res << '|' << '-' * 10 << "\n" if opts[:next] && opts[:next].type == :tbody + res + end + + def convert_tfoot(el, opts) + "|#{'=' * 10}\n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + "| #{el.children.map {|c| convert(c, opts) }.join(' | ')} |\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + if el.options[:category] == :block + "{::comment}\n#{el.value}\n{:/}\n" + else + "{::comment}#{el.value}{:/}" + end + end + + def convert_br(_el, opts) + opts[:in_header] ? "
" : " \n" + end + + def convert_a(el, opts) + if el.attr['href'].empty? + "[#{inner(el, opts)}]()" + elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0 + index = if (link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href'] }) + @linkrefs.index(link_el) + 1 + else + @linkrefs << el + @linkrefs.size + end + "[#{inner(el, opts)}][#{index}]" + else + title = parse_title(el.attr['title']) + "[#{inner(el, opts)}](#{el.attr['href']}#{title})" + end + end + + def convert_img(el, _opts) + alt_text = el.attr['alt'].to_s.gsub(ESCAPED_CHAR_RE) { $1 ? "\\#{$1}" : $2 } + src = el.attr['src'].to_s + if src.empty? + "![#{alt_text}]()" + else + title = parse_title(el.attr['title']) + link = if src.count("()") > 0 + "<#{src}>" + else + src + end + "![#{alt_text}](#{link}#{title})" + end + end + + def convert_codespan(el, _opts) + delim = (el.value.scan(/`+/).max || '') + '`' + "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}" + end + + def convert_footnote(el, _opts) + @footnotes << [el.options[:name], el.value] + "[^#{el.options[:name]}]" + end + + def convert_raw(el, _opts) + attr = (el.options[:type] || []).join(' ') + attr = " type=\"#{attr}\"" unless attr.empty? + if @stack.last.type == :html_element + el.value + elsif el.options[:category] == :block + "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n" + else + "{::nomarkdown#{attr}}#{el.value}{:/}" + end + end + + def convert_em(el, opts) + "*#{inner(el, opts)}*" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_strong(el, opts) + "**#{inner(el, opts)}**" + + (opts[:next] && [:em, :strong].include?(opts[:next].type) && !ial_for_element(el) ? '{::}' : '') + end + + def convert_entity(el, _opts) + entity_to_str(el.value, el.options[:original]) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '...', + laquo_space: '<< ', raquo_space: ' >>', + laquo: '<<', raquo: '>>' + } + def convert_typographic_sym(el, _opts) + TYPOGRAPHIC_SYMS[el.value] + end + + def convert_smart_quote(el, _opts) + el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'" + end + + def convert_math(el, _opts) + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '') + end + + def convert_abbreviation(el, _opts) + el.value + end + + def convert_root(el, opts) + res = inner(el, opts) + res << create_link_defs + res << create_footnote_defs + res << create_abbrev_defs + res + end + + def create_link_defs + res = +'' + res << "\n\n" unless @linkrefs.empty? + @linkrefs.each_with_index do |el, i| + title = parse_title(el.attr['title']) + res << "[#{i + 1}]: #{el.attr['href']}#{title}\n" + end + res + end + + def create_footnote_defs + res = +'' + @footnotes.each do |name, data| + res << "[^#{name}]:\n" + res << inner(data).chomp.split("\n").map {|l| " #{l}" }.join("\n") + "\n\n" + end + res + end + + def create_abbrev_defs + return '' unless @root.options[:abbrev_defs] + res = +'' + @root.options[:abbrev_defs].each do |name, text| + res << "*[#{name}]: #{text}\n" + res << ial_for_element(Element.new(:unused, nil, @root.options[:abbrev_attr][name])).to_s << "\n\n" + end + res + end + + # Return the IAL containing the attributes of the element +el+. + def ial_for_element(el) + res = el.attr.map do |k, v| + next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k) + next if el.type == :header && k == 'id' && !v.strip.empty? + if v.nil? + '' + elsif k == 'class' && !v.empty? && !v.index(/[.#]/) + " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ") + elsif k == 'id' && !v.strip.empty? + " ##{v}" + else + " #{k}=\"#{v}\"" + end + end.compact.join + res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('toc') + res = "footnotes" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) && + el.options.dig(:ial, :refs)&.include?('footnotes') + if el.type == :dl && el.options[:ial] && el.options[:ial][:refs] + auto_ids = el.options[:ial][:refs].select {|ref| ref.start_with?('auto_ids') }.join(" ") + res = auto_ids << (res.strip.empty? ? '' : " #{res}") unless auto_ids.empty? + end + res.strip.empty? ? nil : "{:#{res}}" + end + + def parse_title(attr) + attr.to_s.empty? ? '' : ' "' + attr.gsub(/"/, '"') + '"' + end + + # :startdoc: + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/latex.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/latex.rb new file mode 100644 index 00000000..7f23338a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/latex.rb @@ -0,0 +1,626 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'set' +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts an element tree to LaTeX. + # + # This converter uses ideas from other Markdown-to-LaTeX converters like Pandoc and Maruku. + # + # You can customize this converter by sub-classing it and overriding the +convert_NAME+ methods. + # Each such method takes the following parameters: + # + # [+el+] The element of type +NAME+ to be converted. + # + # [+opts+] A hash containing processing options that are passed down from parent elements. The + # key :parent is always set and contains the parent element as value. + # + # The return value of such a method has to be a string containing the element +el+ formatted + # correctly as LaTeX markup. + class Latex < Base + + # Initialize the LaTeX converter with the +root+ element and the conversion +options+. + def initialize(root, options) + super + @data[:packages] = Set.new + end + + # Dispatch the conversion of the element +el+ to a +convert_TYPE+ method using the +type+ of + # the element. + def convert(el, opts = {}) + send("convert_#{el.type}", el, opts) + end + + # Return the converted content of the children of +el+ as a string. + def inner(el, opts) + result = +'' + options = opts.dup.merge(parent: el) + el.children.each_with_index do |inner_el, index| + options[:index] = index + options[:result] = result + result << send("convert_#{inner_el.type}", inner_el, options) + end + result + end + + def convert_root(el, opts) + inner(el, opts) + end + + def convert_blank(_el, opts) + opts[:result].match?(/\n\n\Z|\A\Z/) ? "" : "\n" + end + + def convert_text(el, _opts) + escape(el.value) + end + + def convert_p(el, opts) + if el.children.size == 1 && el.children.first.type == :img && + !(img = convert_img(el.children.first, opts)).empty? + convert_standalone_image(el, opts, img) + else + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + end + + # Helper method used by +convert_p+ to convert a paragraph that only contains a single :img + # element. + def convert_standalone_image(el, _opts, img) + attrs = attribute_list(el) + "\\begin{figure}#{attrs}\n\\begin{center}\n#{img}\n\\end{center}\n" \ + "\\caption{#{escape(el.children.first.attr['alt'])}}\n" \ + "#{latex_link_target(el, true)}\n\\end{figure}#{attrs}\n" + end + + def convert_codeblock(el, _opts) + show_whitespace = el.attr['class'].to_s =~ /\bshow-whitespaces\b/ + lang = extract_code_language(el.attr) + + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :block)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}\n" + elsif show_whitespace || lang + options = [] + options << (show_whitespace ? "showspaces=true,showtabs=true" : "showspaces=false,showtabs=false") + options << "language=#{lang}" if lang + options << "basicstyle=\\ttfamily\\footnotesize,columns=fixed,frame=tlbr" + id = el.attr['id'] + options << "label=#{id}" if id + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{lstlisting}[#{options.join(',')}]\n" \ + "#{el.value}\n\\end{lstlisting}#{attrs}\n" + else + "#{latex_link_target(el)}\\begin{verbatim}#{el.value}\\end{verbatim}\n" + end + end + + def convert_blockquote(el, opts) + latex_environment(el.children.size > 1 ? 'quotation' : 'quote', el, inner(el, opts)) + end + + def convert_header(el, opts) + type = @options[:latex_headers][output_header_level(el.options[:level]) - 1] + if ((id = el.attr['id']) || + (@options[:auto_ids] && (id = generate_id(el.options[:raw_text])))) && in_toc?(el) + "\\#{type}{#{inner(el, opts)}}\\hypertarget{#{id}}{}\\label{#{id}}\n\n" + else + "\\#{type}*{#{inner(el, opts)}}\n\n" + end + end + + def convert_hr(el, _opts) + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{center}#{attrs}\n\\rule{3in}{0.4pt}\n\\end{center}#{attrs}\n" + end + + def convert_ul(el, opts) + if !@data[:has_toc] && el.options.dig(:ial, :refs)&.include?('toc') + @data[:has_toc] = true + '\tableofcontents' + else + latex_environment(el.type == :ul ? 'itemize' : 'enumerate', el, inner(el, opts)) + end + end + alias convert_ol convert_ul + + def convert_dl(el, opts) + latex_environment('description', el, inner(el, opts)) + end + + def convert_li(el, opts) + "\\item{} #{latex_link_target(el, true)}#{inner(el, opts).sub(/\n+\Z/, '')}\n" + end + + def convert_dt(el, opts) + "\\item[#{inner(el, opts)}] " + end + + def convert_dd(el, opts) + "#{latex_link_target(el)}#{inner(el, opts)}\n\n" + end + + def convert_html_element(el, opts) + case el.value + when 'i', 'em' + "\\emph{#{inner(el, opts)}}" + when 'b', 'strong' + "\\textbf{#{inner(el, opts)}}" + else + warning("Can't convert HTML element") + '' + end + end + + def convert_xml_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") + "\n" + end + + def convert_xml_pi(_el, _opts) + warning("Can't convert XML PI") + '' + end + + TABLE_ALIGNMENT_CHAR = {default: 'l', left: 'l', center: 'c', right: 'r'} # :nodoc: + + def convert_table(el, opts) + @data[:packages] << 'longtable' + align = el.options[:alignment].map {|a| TABLE_ALIGNMENT_CHAR[a] }.join('|') + attrs = attribute_list(el) + "#{latex_link_target(el)}\\begin{longtable}{|#{align}|}#{attrs}\n" \ + "\\hline\n#{inner(el, opts)}\\hline\n\\end{longtable}#{attrs}\n\n" + end + + def convert_thead(el, opts) + "#{inner(el, opts)}\\hline\n" + end + + def convert_tbody(el, opts) + inner(el, opts) + end + + def convert_tfoot(el, opts) + "\\hline \\hline \n#{inner(el, opts)}" + end + + def convert_tr(el, opts) + el.children.map {|c| send("convert_#{c.type}", c, opts) }.join(' & ') << "\\\\\n" + end + + def convert_td(el, opts) + inner(el, opts) + end + + def convert_comment(el, _opts) + el.value.split("\n").map {|l| "% #{l}" }.join("\n") << "\n" + end + + def convert_br(_el, opts) + res = +"\\newline" + res << "\n" if (c = opts[:parent].children[opts[:index] + 1]) && + (c.type != :text || c.value !~ /^\s*\n/) + res + end + + def convert_a(el, opts) + url = el.attr['href'] + if url.start_with?('#') + "\\hyperlink{#{url[1..-1].gsub('%', '\\%')}}{#{inner(el, opts)}}" + else + "\\href{#{url.gsub('%', '\\%')}}{#{inner(el, opts)}}" + end + end + + def convert_img(el, _opts) + line = el.options[:location] + if el.attr['src'].match?(/^(https?|ftps?):\/\//) + warning("Cannot include non-local image#{line ? " (line #{line})" : ''}") + '' + elsif !el.attr['src'].empty? + @data[:packages] << 'graphicx' + "#{latex_link_target(el)}\\includegraphics{#{el.attr['src']}}" + else + warning("Cannot include image with empty path#{line ? " (line #{line})" : ''}") + '' + end + end + + def convert_codespan(el, _opts) + lang = extract_code_language(el.attr) + if @options[:syntax_highlighter] == :minted && + (highlighted_code = highlight_code(el.value, lang, :span)) + @data[:packages] << 'minted' + "#{latex_link_target(el)}#{highlighted_code}" + else + "\\texttt{#{latex_link_target(el)}#{escape(el.value)}}" + end + end + + def convert_footnote(el, opts) + @data[:packages] << 'fancyvrb' + "\\footnote{#{inner(el.value, opts).rstrip}}" + end + + def convert_raw(el, _opts) + if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('latex') + el.value + (el.options[:category] == :block ? "\n" : '') + else + '' + end + end + + def convert_em(el, opts) + "\\emph{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + def convert_strong(el, opts) + "\\textbf{#{latex_link_target(el)}#{inner(el, opts)}}" + end + + # Inspired by Maruku: entity conversion table based on the one from htmltolatex + # (http://sourceforge.net/projects/htmltolatex/), with some small adjustments/additions + ENTITY_CONV_TABLE = { + 913 => ['$A$'], + 914 => ['$B$'], + 915 => ['$\Gamma$'], + 916 => ['$\Delta$'], + 917 => ['$E$'], + 918 => ['$Z$'], + 919 => ['$H$'], + 920 => ['$\Theta$'], + 921 => ['$I$'], + 922 => ['$K$'], + 923 => ['$\Lambda$'], + 924 => ['$M$'], + 925 => ['$N$'], + 926 => ['$\Xi$'], + 927 => ['$O$'], + 928 => ['$\Pi$'], + 929 => ['$P$'], + 931 => ['$\Sigma$'], + 932 => ['$T$'], + 933 => ['$Y$'], + 934 => ['$\Phi$'], + 935 => ['$X$'], + 936 => ['$\Psi$'], + 937 => ['$\Omega$'], + 945 => ['$\alpha$'], + 946 => ['$\beta$'], + 947 => ['$\gamma$'], + 948 => ['$\delta$'], + 949 => ['$\epsilon$'], + 950 => ['$\zeta$'], + 951 => ['$\eta$'], + 952 => ['$\theta$'], + 953 => ['$\iota$'], + 954 => ['$\kappa$'], + 955 => ['$\lambda$'], + 956 => ['$\mu$'], + 957 => ['$\nu$'], + 958 => ['$\xi$'], + 959 => ['$o$'], + 960 => ['$\pi$'], + 961 => ['$\rho$'], + 963 => ['$\sigma$'], + 964 => ['$\tau$'], + 965 => ['$\upsilon$'], + 966 => ['$\phi$'], + 967 => ['$\chi$'], + 968 => ['$\psi$'], + 969 => ['$\omega$'], + 962 => ['$\varsigma$'], + 977 => ['$\vartheta$'], + 982 => ['$\varpi$'], + 8230 => ['\ldots'], + 8242 => ['$\prime$'], + 8254 => ['-'], + 8260 => ['/'], + 8472 => ['$\wp$'], + 8465 => ['$\Im$'], + 8476 => ['$\Re$'], + 8501 => ['$\aleph$'], + 8226 => ['$\bullet$'], + 8482 => ['$^{\rm TM}$'], + 8592 => ['$\leftarrow$'], + 8594 => ['$\rightarrow$'], + 8593 => ['$\uparrow$'], + 8595 => ['$\downarrow$'], + 8596 => ['$\leftrightarrow$'], + 8629 => ['$\hookleftarrow$'], + 8657 => ['$\Uparrow$'], + 8659 => ['$\Downarrow$'], + 8656 => ['$\Leftarrow$'], + 8658 => ['$\Rightarrow$'], + 8660 => ['$\Leftrightarrow$'], + 8704 => ['$\forall$'], + 8706 => ['$\partial$'], + 8707 => ['$\exists$'], + 8709 => ['$\emptyset$'], + 8711 => ['$\nabla$'], + 8712 => ['$\in$'], + 8715 => ['$\ni$'], + 8713 => ['$\notin$'], + 8721 => ['$\sum$'], + 8719 => ['$\prod$'], + 8722 => ['$-$'], + 8727 => ['$\ast$'], + 8730 => ['$\surd$'], + 8733 => ['$\propto$'], + 8734 => ['$\infty$'], + 8736 => ['$\angle$'], + 8743 => ['$\wedge$'], + 8744 => ['$\vee$'], + 8745 => ['$\cap$'], + 8746 => ['$\cup$'], + 8747 => ['$\int$'], + 8756 => ['$\therefore$', 'amssymb'], + 8764 => ['$\sim$'], + 8776 => ['$\approx$'], + 8773 => ['$\cong$'], + 8800 => ['$\neq$'], + 8801 => ['$\equiv$'], + 8804 => ['$\leq$'], + 8805 => ['$\geq$'], + 8834 => ['$\subset$'], + 8835 => ['$\supset$'], + 8838 => ['$\subseteq$'], + 8839 => ['$\supseteq$'], + 8836 => ['$\nsubset$', 'amssymb'], + 8853 => ['$\oplus$'], + 8855 => ['$\otimes$'], + 8869 => ['$\perp$'], + 8901 => ['$\cdot$'], + 8968 => ['$\rceil$'], + 8969 => ['$\lceil$'], + 8970 => ['$\lfloor$'], + 8971 => ['$\rfloor$'], + 9001 => ['$\rangle$'], + 9002 => ['$\langle$'], + 9674 => ['$\lozenge$', 'amssymb'], + 9824 => ['$\spadesuit$'], + 9827 => ['$\clubsuit$'], + 9829 => ['$\heartsuit$'], + 9830 => ['$\diamondsuit$'], + 38 => ['\&'], + 34 => ['"'], + 39 => ['\''], + 169 => ['\copyright'], + 60 => ['\textless'], + 62 => ['\textgreater'], + 338 => ['\OE'], + 339 => ['\oe'], + 352 => ['\v{S}'], + 353 => ['\v{s}'], + 376 => ['\"Y'], + 710 => ['\textasciicircum'], + 732 => ['\textasciitilde'], + 8211 => ['--'], + 8212 => ['---'], + 8216 => ['`'], + 8217 => ['\''], + 8220 => ['``'], + 8221 => ['\'\''], + 8224 => ['\dag'], + 8225 => ['\ddag'], + 8240 => ['\permil', 'wasysym'], + 8364 => ['\euro', 'eurosym'], + 8249 => ['\guilsinglleft'], + 8250 => ['\guilsinglright'], + 8218 => ['\quotesinglbase', 'mathcomp'], + 8222 => ['\quotedblbase', 'mathcomp'], + 402 => ['\textflorin', 'mathcomp'], + 381 => ['\v{Z}'], + 382 => ['\v{z}'], + 160 => ['~'], + 161 => ['\textexclamdown'], + 163 => ['\pounds'], + 164 => ['\currency', 'wasysym'], + 165 => ['\textyen', 'textcomp'], + 166 => ['\brokenvert', 'wasysym'], + 167 => ['\S'], + 171 => ['\guillemotleft'], + 187 => ['\guillemotright'], + 174 => ['\textregistered'], + 170 => ['\textordfeminine'], + 172 => ['$\neg$'], + 173 => ['\-'], + 176 => ['$\degree$', 'mathabx'], + 177 => ['$\pm$'], + 180 => ['\''], + 181 => ['$\mu$'], + 182 => ['\P'], + 183 => ['$\cdot$'], + 186 => ['\textordmasculine'], + 162 => ['\cent', 'wasysym'], + 185 => ['$^1$'], + 178 => ['$^2$'], + 179 => ['$^3$'], + 189 => ['$\frac{1}{2}$'], + 188 => ['$\frac{1}{4}$'], + 190 => ['$\frac{3}{4}'], + 192 => ['\`A'], + 193 => ['\\\'A'], + 194 => ['\^A'], + 195 => ['\~A'], + 196 => ['\"A'], + 197 => ['\AA'], + 198 => ['\AE'], + 199 => ['\cC'], + 200 => ['\`E'], + 201 => ['\\\'E'], + 202 => ['\^E'], + 203 => ['\"E'], + 204 => ['\`I'], + 205 => ['\\\'I'], + 206 => ['\^I'], + 207 => ['\"I'], + 208 => ['$\eth$', 'amssymb'], + 209 => ['\~N'], + 210 => ['\`O'], + 211 => ['\\\'O'], + 212 => ['\^O'], + 213 => ['\~O'], + 214 => ['\"O'], + 215 => ['$\times$'], + 216 => ['\O'], + 217 => ['\`U'], + 218 => ['\\\'U'], + 219 => ['\^U'], + 220 => ['\"U'], + 221 => ['\\\'Y'], + 222 => ['\Thorn', 'wasysym'], + 223 => ['\ss'], + 224 => ['\`a'], + 225 => ['\\\'a'], + 226 => ['\^a'], + 227 => ['\~a'], + 228 => ['\"a'], + 229 => ['\aa'], + 230 => ['\ae'], + 231 => ['\cc'], + 232 => ['\`e'], + 233 => ['\\\'e'], + 234 => ['\^e'], + 235 => ['\"e'], + 236 => ['\`i'], + 237 => ['\\\'i'], + 238 => ['\^i'], + 239 => ['\"i'], + 240 => ['$\eth$'], + 241 => ['\~n'], + 242 => ['\`o'], + 243 => ['\\\'o'], + 244 => ['\^o'], + 245 => ['\~o'], + 246 => ['\"o'], + 247 => ['$\divide$'], + 248 => ['\o'], + 249 => ['\`u'], + 250 => ['\\\'u'], + 251 => ['\^u'], + 252 => ['\"u'], + 253 => ['\\\'y'], + 254 => ['\thorn', 'wasysym'], + 255 => ['\"y'], + 8201 => ['\thinspace'], + 8194 => ['\hskip .5em\relax'], + 8195 => ['\quad'], + } # :nodoc: + ENTITY_CONV_TABLE.each_value {|v| v[0] = "#{v[0]}{}" } + + def entity_to_latex(entity) + text, package = ENTITY_CONV_TABLE[entity.code_point] + if text + @data[:packages] << package if package + text + else + warning("Couldn't find entity with code #{entity.code_point} in substitution table!") + '' + end + end + + def convert_entity(el, _opts) + entity_to_latex(el.value) + end + + TYPOGRAPHIC_SYMS = { + mdash: '---', ndash: '--', hellip: '\ldots{}', + laquo_space: '\guillemotleft{}~', raquo_space: '~\guillemotright{}', + laquo: '\guillemotleft{}', raquo: '\guillemotright{}' + } # :nodoc: + def convert_typographic_sym(el, _opts) + if (result = @options[:typographic_symbols][el.value]) + escape(result) + else + TYPOGRAPHIC_SYMS[el.value] + end + end + + def convert_smart_quote(el, opts) + res = entity_to_latex(smart_quote_entity(el)).chomp('{}') + res << "{}" if ((nel = opts[:parent].children[opts[:index] + 1]) && nel.type == :smart_quote) || res =~ /\w$/ + res + end + + def convert_math(el, _opts) + @data[:packages] += %w[amssymb amsmath amsthm amsfonts] + if el.options[:category] == :block + if el.value.match?(/\A\s*\\begin\{/) + el.value + else + latex_environment('displaymath', el, el.value) + end + else + "$#{el.value}$" + end + end + + def convert_abbreviation(el, _opts) + @data[:packages] += %w[acronym] + "\\ac{#{normalize_abbreviation_key(el.value)}}" + end + + # Normalize the abbreviation key so that it only contains allowed ASCII character + def normalize_abbreviation_key(key) + key.gsub(/\W/) {|m| m.unpack1('H*') } + end + + # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to + # the method #attribute_list -- the resulting string is appended to both the \\begin and the + # \\end lines of the LaTeX environment for easier post-processing of LaTeX environments. + def latex_environment(type, el, text) + attrs = attribute_list(el) + "\\begin{#{type}}#{latex_link_target(el)}#{attrs}\n#{text.rstrip}\n\\end{#{type}}#{attrs}\n" + end + + # Return a string containing a valid \hypertarget command if the element has an ID defined, or + # +nil+ otherwise. If the parameter +add_label+ is +true+, a \label command will also be used + # additionally to the \hypertarget command. + def latex_link_target(el, add_label = false) + if (id = el.attr['id']) + "\\hypertarget{#{id}}{}#{add_label ? "\\label{#{id}}" : ''}" + else + nil + end + end + + # Return a LaTeX comment containing all attributes as 'key="value"' pairs. + def attribute_list(el) + attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join + attrs = " % #{attrs}" unless attrs.empty? + attrs + end + + ESCAPE_MAP = { + "^" => "\\^{}", + "\\" => "\\textbackslash{}", + "~" => "\\ensuremath{\\sim}", + "|" => "\\textbar{}", + "<" => "\\textless{}", + ">" => "\\textgreater{}", + "[" => "{[}", + "]" => "{]}", + }.merge(Hash[*"{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten]) # :nodoc: + ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc: + + # Escape the special LaTeX characters in the string +str+. + def escape(str) + str.gsub(ESCAPE_RE) {|m| ESCAPE_MAP[m] } + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/man.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/man.rb new file mode 100644 index 00000000..dd84540d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/man.rb @@ -0,0 +1,300 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to a manpage in groff format. See man(7), groff_man(7) and + # man-pages(7) for information regarding the output. + class Man < Base + + def convert(el, opts = {indent: 0, result: +''}) # :nodoc: + send("convert_#{el.type}", el, opts) + end + + private + + def inner(el, opts, use = :all) + arr = el.children.reject {|e| e.type == :blank } + arr.each_with_index do |inner_el, index| + next if use == :rest && index == 0 + break if use == :first && index > 0 + options = opts.dup + options[:parent] = el + options[:index] = index + options[:prev] = (index == 0 ? nil : arr[index - 1]) + options[:next] = (index == arr.length - 1 ? nil : arr[index + 1]) + convert(inner_el, options) + end + end + + def convert_root(el, opts) + @title_done = false + opts[:result] = +".\\\" generated by kramdown\n" + inner(el, opts) + opts[:result] + end + + def convert_blank(*) + end + alias convert_hr convert_blank + alias convert_xml_pi convert_blank + + def convert_p(el, opts) + if (opts[:index] != 0 && opts[:prev].type != :header) || + (opts[:parent].type == :blockquote && opts[:index] == 0) + opts[:result] << macro("P") + end + inner(el, opts) + newline(opts[:result]) + end + + def convert_header(el, opts) + return unless opts[:parent].type == :root + case el.options[:level] + when 1 + unless @title_done + @title_done = true + data = el.options[:raw_text].scan(/([^(]+)\s*\((\d\w*)\)(?:\s*-+\s*(.*))?/).first || + el.options[:raw_text].scan(/([^\s]+)\s*(?:-*\s+)?()(.*)/).first + return unless data && data[0] + name = data[0] + section = (data[1].to_s.empty? ? el.attr['data-section'] || '7' : data[1]) + description = (data[2].to_s.empty? ? nil : " - #{data[2]}") + date = el.attr['data-date'] ? quote(el.attr['data-date']) : nil + extra = (el.attr['data-extra'] ? quote(escape(el.attr['data-extra'].to_s)) : nil) + opts[:result] << macro("TH", quote(escape(name.upcase)), quote(section), date, extra) + if description + opts[:result] << macro("SH", "NAME") << escape("#{name}#{description}") << "\n" + end + end + when 2 + opts[:result] << macro("SH", quote(escape(el.options[:raw_text]))) + when 3 + opts[:result] << macro("SS", quote(escape(el.options[:raw_text]))) + else + warning("Header levels greater than three are not supported") + end + end + + def convert_codeblock(el, opts) + opts[:result] << macro("sp") << macro("RS", 4) << macro("EX") + opts[:result] << newline(escape(el.value, true)) + opts[:result] << macro("EE") << macro("RE") + end + + def convert_blockquote(el, opts) + opts[:result] << macro("RS") + inner(el, opts) + opts[:result] << macro("RE") + end + + def convert_ul(el, opts) + compact = (el.attr['class'] =~ /\bcompact\b/) + opts[:result] << macro("sp") << macro("PD", 0) if compact + inner(el, opts) + opts[:result] << macro("PD") if compact + end + alias convert_dl convert_ul + alias convert_ol convert_ul + + def convert_li(el, opts) + sym = (opts[:parent].type == :ul ? '\(bu' : "#{opts[:index] + 1}.") + opts[:result] << macro("IP", sym, 4) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + end + + def convert_dt(el, opts) + opts[:result] << macro(opts[:prev] && opts[:prev].type == :dt ? "TQ" : "TP") + inner(el, opts) + opts[:result] << "\n" + end + + def convert_dd(el, opts) + inner(el, opts, :first) + if el.children.size > 1 + opts[:result] << macro("RS") + inner(el, opts, :rest) + opts[:result] << macro("RE") + end + opts[:result] << macro("sp") if opts[:next] && opts[:next].type == :dd + end + + TABLE_CELL_ALIGNMENT = {left: 'l', center: 'c', right: 'r', default: 'l'} + + def convert_table(el, opts) + opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] } + table_options = ["box"] + table_options << "center" if el.attr['class']&.match?(/\bcenter\b/) + opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n" + inner(el, opts) + opts[:result] << macro("TE") << macro("sp") + end + + def convert_thead(el, opts) + opts[:result] << opts[:alignment].map {|a| "#{a}b" }.join(' ') << " .\n" + inner(el, opts) + opts[:result] << "=\n" + end + + def convert_tbody(el, opts) + opts[:result] << ".T&\n" if opts[:index] != 0 + opts[:result] << opts[:alignment].join(' ') << " .\n" + inner(el, opts) + opts[:result] << (opts[:next].type == :tfoot ? "=\n" : "_\n") if opts[:next] + end + + def convert_tfoot(el, opts) + inner(el, opts) + end + + def convert_tr(el, opts) + inner(el, opts) + opts[:result] << "\n" + end + + def convert_td(el, opts) + result = opts[:result] + opts[:result] = +'' + inner(el, opts) + if opts[:result].include?("\n") + warning("Table cells using links are not supported") + result << "\t" + else + result << opts[:result] << "\t" + end + end + + def convert_html_element(*) + warning("HTML elements are not supported") + end + + def convert_xml_comment(el, opts) + newline(opts[:result]) << ".\"#{escape(el.value, true).rstrip.gsub(/\n/, "\n.\"")}\n" + end + alias convert_comment convert_xml_comment + + def convert_a(el, opts) + if el.children.size == 1 && el.children[0].type == :text && + el.attr['href'] == el.children[0].value + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) << macro("UE") + elsif el.attr['href'].start_with?('mailto:') + newline(opts[:result]) << macro("MT", escape(el.attr['href'].sub(/^mailto:/, ''))) << + macro("UE") + else + newline(opts[:result]) << macro("UR", escape(el.attr['href'])) + inner(el, opts) + newline(opts[:result]) << macro("UE") + end + end + + def convert_img(_el, _opts) + warning("Images are not supported") + end + + def convert_em(el, opts) + opts[:result] << '\fI' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_strong(el, opts) + opts[:result] << '\fB' + inner(el, opts) + opts[:result] << '\fP' + end + + def convert_codespan(el, opts) + opts[:result] << "\\fB#{escape(el.value)}\\fP" + end + + def convert_br(_el, opts) + newline(opts[:result]) << macro("br") + end + + def convert_abbreviation(el, opts) + opts[:result] << escape(el.value) + end + + def convert_math(el, opts) + if el.options[:category] == :block + convert_codeblock(el, opts) + else + convert_codespan(el, opts) + end + end + + def convert_footnote(*) + warning("Footnotes are not supported") + end + + def convert_raw(*) + warning("Raw content is not supported") + end + + def convert_text(el, opts) + text = escape(el.value) + text.lstrip! if opts[:result][-1] == "\n" + opts[:result] << text + end + + def convert_entity(el, opts) + opts[:result] << unicode_char(el.value.code_point) + end + + def convert_smart_quote(el, opts) + opts[:result] << unicode_char(::Kramdown::Utils::Entities.entity(el.value.to_s).code_point) + end + + TYPOGRAPHIC_SYMS_MAP = { + mdash: '\(em', ndash: '\(em', hellip: '\.\.\.', + laquo_space: '\[Fo]', raquo_space: '\[Fc]', laquo: '\[Fo]', raquo: '\[Fc]' + } + + def convert_typographic_sym(el, opts) + opts[:result] << TYPOGRAPHIC_SYMS_MAP[el.value] + end + + def macro(name, *args) + ".#{[name, *args].compact.join(' ')}\n" + end + + def newline(text) + text << "\n" unless text[-1] == "\n" + text + end + + def quote(text) + "\"#{text.gsub(/"/, '\\"')}\"" + end + + def escape(text, preserve_whitespace = false) + text = (preserve_whitespace ? text.dup : text.gsub(/\s+/, ' ')) + text.gsub!('\\', "\\e") + text.gsub!(/^\./, '\\\\&.') + text.gsub!(/[.'-]/) {|m| "\\#{m}" } + text + end + + def unicode_char(codepoint) + "\\[u#{codepoint.to_s(16).rjust(4, '0')}]" + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/math_engine/mathjax.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/math_engine/mathjax.rb new file mode 100644 index 00000000..3248e930 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/math_engine/mathjax.rb @@ -0,0 +1,32 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::MathEngine + + # Uses the MathJax javascript library for displaying math. + # + # Note that the javascript library itself is not include or linked, this has to be done + # separately. Only the math content is marked up correctly. + module Mathjax + + def self.call(converter, el, opts) + value = converter.escape_html(el.value) + result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)" + if el.attr.empty? + result + elsif el.options[:category] == :block + converter.format_as_block_html('div', el.attr, result, opts[:indent]) + else + converter.format_as_span_html('span', el.attr, "$#{el.value}$") + end + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/remove_html_tags.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/remove_html_tags.rb new file mode 100644 index 00000000..a7db73ed --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/remove_html_tags.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Removes all block (and optionally span) level HTML tags from the element tree. + # + # This converter can be used on parsed HTML documents to get an element tree that will only + # contain native kramdown elements. + # + # *Note* that the returned element tree may not be fully conformant (i.e. the content models of + # *some elements may be violated)! + # + # This converter modifies the given tree in-place and returns it. + class RemoveHtmlTags < Base + + def initialize(root, options) + super + @options[:template] = '' + end + + def convert(el) + real_el, el = el, el.value if el.type == :footnote + + children = el.children.dup + index = 0 + while index < children.length + if children[index].type == :xml_pi || + (children[index].type == :html_element && (children[index].value == 'style' || + children[index].value == 'script')) + children[index..index] = [] + elsif children[index].type == :html_element && + ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) || + (@options[:remove_span_html_tags] && children[index].options[:category] == :span)) + children[index..index] = children[index].children + else + convert(children[index]) + index += 1 + end + end + el.children = children + real_el || el + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter.rb new file mode 100644 index 00000000..fd9316d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter.rb @@ -0,0 +1,56 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Converter + + # == Container for Syntax Highlighters + # + # This module serves as container for the syntax highlighters that can be used together with + # kramdown. + # + # A syntax highlighter should not store any data itself but should use the provided converter + # object to do so (See Kramdown::Converter::Base#data). + # + # == Implementing a Syntax Highlighter + # + # Implementing a new syntax highlighter is easy because it is just an object that needs to + # respond to #call. + # + # The method #call needs to take the following arguments: + # + # converter:: This argument contains the converter object that calls the syntax highlighter. It + # can be used, for example, to store data in Kramdown::Converter::Base#data for one + # conversion run. + # + # text:: The raw text that should be highlighted. + # + # lang:: The language that the text should be highlighted for (e.g. ruby, python, ...). + # + # type:: The type of text, either :span for span-level code or :block for a codeblock. + # + # opts:: A Hash with options that may be passed from the converter. + # + # The return value of the method should be the highlighted text, suitable for the given + # converter (e.g. HTML for the HTML converter). + # + # == Special Implementation Details + # + # HTML converter:: If the syntax highlighter is used with an HTML converter, it should return + # :block type text correctly wrapped (i.e. normally inside a pre-tag, but may + # also be a table-tag or just a div-tag) but :span type text *without* a + # code-tag! + # + # Also, a syntax highlighter should store the default highlighting language for + # the invocation in the +opts+ hash under the key :default_lang. + module SyntaxHighlighter + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/minted.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/minted.rb new file mode 100644 index 00000000..21c26ec3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/minted.rb @@ -0,0 +1,35 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Minted to highlight code blocks and code spans. + module Minted + + def self.call(converter, text, lang, type, _opts) + opts = converter.options[:syntax_highlighter_opts] + + # Fallback to default language + lang ||= opts[:default_lang] + + options = [] + options << "breaklines" if opts[:wrap] + options << "linenos" if opts[:line_numbers] + options << "frame=#{opts[:frame]}" if opts[:frame] + + if lang && type == :block + "\\begin{minted}[#{options.join(',')}]{#{lang}}\n#{text}\n\\end{minted}" + elsif lang && type == :span + "\\mintinline{#{lang}}{#{text}}" + else + nil + end + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/rouge.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/rouge.rb new file mode 100644 index 00000000..a286c4d9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/syntax_highlighter/rouge.rb @@ -0,0 +1,85 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown::Converter::SyntaxHighlighter + + # Uses Rouge which is CSS-compatible to Pygments to highlight code blocks and code spans. + module Rouge + + begin + require 'rouge' + + # Highlighting via Rouge is available if this constant is +true+. + AVAILABLE = true + rescue LoadError, SyntaxError + AVAILABLE = false # :nodoc: + end + + def self.call(converter, text, lang, type, call_opts) + opts = options(converter, type) + call_opts[:default_lang] = opts[:default_lang] + return nil unless lang || opts[:default_lang] || opts[:guess_lang] + + lexer = ::Rouge::Lexer.find_fancy(lang || opts[:default_lang], text) + return nil if opts[:disable] || !lexer || (lexer.tag == "plaintext" && !opts[:guess_lang]) + + opts[:css_class] ||= 'highlight' # For backward compatibility when using Rouge 2.0 + formatter = formatter_class(opts).new(opts) + formatter.format(lexer.lex(text)) + end + + def self.options(converter, type) + prepare_options(converter) + converter.data[:syntax_highlighter_rouge][type] + end + + def self.prepare_options(converter) + return if converter.data.key?(:syntax_highlighter_rouge) + + cache = converter.data[:syntax_highlighter_rouge] = {} + + opts = converter.options[:syntax_highlighter_opts].dup + + span_opts = opts.delete(:span)&.dup || {} + block_opts = opts.delete(:block)&.dup || {} + normalize_keys(span_opts) + normalize_keys(block_opts) + + cache[:span] = opts.merge(span_opts) + cache[:span][:wrap] = false + + cache[:block] = opts.merge(block_opts) + end + + def self.normalize_keys(hash) + return if hash.empty? + + hash.keys.each do |k| + hash[k.kind_of?(String) ? Kramdown::Options.str_to_sym(k) : k] = hash.delete(k) + end + end + + def self.formatter_class(opts = {}) + case formatter = opts[:formatter] + when Class + formatter + when /\A[[:upper:]][[:alnum:]_]*\z/ + ::Rouge::Formatters.const_get(formatter, false) + else + # Available in Rouge 2.0 or later + ::Rouge::Formatters::HTMLLegacy + end + rescue NameError + # Fallback to Rouge 1.x + ::Rouge::Formatters::HTML + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/converter/toc.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/toc.rb new file mode 100644 index 00000000..725caa21 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/converter/toc.rb @@ -0,0 +1,69 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/converter' + +module Kramdown + + module Converter + + # Converts a Kramdown::Document to an element tree that represents the table of contents. + # + # The returned tree consists of Element objects of type :toc where the root element is just used + # as container object. Each :toc element contains as value the wrapped :header element and under + # the attribute key :id the header ID that should be used (note that this ID may not exist in + # the wrapped element). + # + # Since the TOC tree consists of special :toc elements, one cannot directly feed this tree to + # other converters! + class Toc < Base + + def initialize(root, options) + super + @toc = Element.new(:toc) + @stack = [] + @options[:template] = '' + end + + def convert(el) + if el.type == :header && in_toc?(el) + attr = el.attr.dup + attr['id'] = generate_id(el.options[:raw_text]) if @options[:auto_ids] && !attr['id'] + add_to_toc(el, attr['id']) if attr['id'] + else + el.children.each {|child| convert(child) } + end + @toc + end + + private + + def add_to_toc(el, id) + toc_element = Element.new(:toc, el, id: id) + + success = false + until success + if @stack.empty? + @toc.children << toc_element + @stack << toc_element + success = true + elsif @stack.last.value.options[:level] < el.options[:level] + @stack.last.children << toc_element + @stack << toc_element + success = true + else + @stack.pop + end + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/document.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/document.rb new file mode 100644 index 00000000..d31ea11f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/document.rb @@ -0,0 +1,139 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# = kramdown +# +# kramdown is fast, pure Ruby Markdown superset converter, using a strict syntax definition and +# supporting several common extensions. +# +# The kramdown library is mainly written to support the kramdown-to-HTML conversion chain. However, +# due to its flexibility it supports other input and output formats as well. Here is a list of the +# supported formats: +# +# * input formats: kramdown (a Markdown superset), Markdown, GFM, HTML +# * output formats: HTML, kramdown, LaTeX (and therefore PDF), PDF via Prawn +# +# All the documentation on the available input and output formats is available at +# http://kramdown.gettalong.org. +# +# == Usage +# +# kramdown has a simple API, so using kramdown is as easy as +# +# require 'kramdown' +# +# Kramdown::Document.new(text).to_html +# +# For detailed information have a look at the *\Kramdown::Document* class. +# +# == License +# +# MIT - see the COPYING file. + +require 'kramdown/version' +require 'kramdown/element' +require 'kramdown/error' +require 'kramdown/parser' +require 'kramdown/converter' +require 'kramdown/options' +require 'kramdown/utils' + +module Kramdown + + # Return the data directory for kramdown. + def self.data_dir + unless defined?(@data_dir) + require 'rbconfig' + @data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'kramdown')) + @data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "kramdown")) unless File.exist?(@data_dir) + raise "kramdown data directory not found! This is a bug, please report it!" unless File.directory?(@data_dir) + end + @data_dir + end + + # The main interface to kramdown. + # + # This class provides a one-stop-shop for using kramdown to convert text into various output + # formats. Use it like this: + # + # require 'kramdown' + # doc = Kramdown::Document.new('This *is* some kramdown text') + # puts doc.to_html + # + # The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for + # more information. + # + # The second argument to the ::new method is an options hash for customizing the behaviour of the + # used parser and the converter. See ::new for more information! + class Document + + # The root Element of the element tree. It is immediately available after the ::new method has + # been called. + attr_accessor :root + + # The options hash which holds the options for parsing/converting the Kramdown document. + attr_reader :options + + # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in + # ::new) and the conversion phase. + attr_reader :warnings + + # Create a new Kramdown document from the string +source+ and use the provided +options+. The + # options that can be used are defined in the Options module. + # + # The special options key :input can be used to select the parser that should parse the + # +source+. It has to be the name of a class in the Kramdown::Parser module. For example, to + # select the kramdown parser, one would set the :input key to +Kramdown+. If this key is not + # set, it defaults to +Kramdown+. + # + # The +source+ is immediately parsed by the selected parser so that the root element is + # immediately available and the output can be generated. + def initialize(source, options = {}) + @options = Options.merge(options).freeze + parser = (@options[:input] || 'kramdown').to_s + parser = parser[0..0].upcase + parser[1..-1] + try_require('parser', parser) + if Parser.const_defined?(parser) + @root, @warnings = Parser.const_get(parser).parse(source, @options) + else + raise Kramdown::Error, "kramdown has no parser to handle the specified " \ + "input format: #{@options[:input]}" + end + end + + # Check if a method is invoked that begins with +to_+ and if so, try to instantiate a converter + # class (i.e. a class in the Kramdown::Converter module) and use it for converting the document. + # + # For example, +to_html+ would instantiate the Kramdown::Converter::Html class. + def method_missing(id, *attr, &block) + if id.to_s =~ /^to_(\w+)$/ && (name = Utils.camelize($1)) && + try_require('converter', name) && Converter.const_defined?(name) + output, warnings = Converter.const_get(name).convert(@root, @options) + @warnings.concat(warnings) + output + else + super + end + end + + def inspect # :nodoc: + "" + end + + # Try requiring a parser or converter class and don't raise an error if the file is not found. + def try_require(type, name) + require("kramdown/#{type}/#{Utils.snake_case(name)}") + true + rescue LoadError + true + end + protected :try_require + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/element.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/element.rb new file mode 100644 index 00000000..9aaad96b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/element.rb @@ -0,0 +1,551 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # Represents all elements in the element tree. + # + # kramdown only uses this one class for representing all available elements in an element tree + # (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor. + # + # The root of a kramdown element tree has to be an element of type :root. It needs to have certain + # option keys set so that conversions work correctly. If only a part of a tree should be + # converted, duplicate the root node and assign the #children appropriately, e.g: + # + # root = doc.root + # new_root = root.dup + # new_root.children = [root.children[0]] # assign new array with elements to convert + # + # Following is a description of all supported element types. + # + # Note that the option :location may contain the start line number of an element in the source + # document. + # + # == Structural Elements + # + # === :root + # + # [Category] None + # [Usage context] As the root element of a document + # [Content model] Block-level elements + # + # Represents the root of a kramdown document. + # + # The root element contains the following option keys: + # + # :encoding:: When running on Ruby 1.9 this key has to be set to the encoding used for the text + # parts of the kramdown document. + # + # :abbrev_defs:: This key may be used to store the mapping of abbreviation to abbreviation + # definition. + # + # :abbrev_attr:: This key may be used to store the mapping of abbreviation to abbreviation + # attributes. + # + # :options:: This key may be used to store options that were set during parsing of the document. + # + # :footnote_count:: This key stores the number of actually referenced footnotes of the document. + # + # === :blank + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents one or more blank lines. It is not allowed to have two or more consecutive blank + # elements. + # + # The +value+ field may contain the original content of the blank lines. + # + # + # === :p + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a paragraph. + # + # If the option :transparent is +true+, this element just represents a block of text. I.e. this + # element just functions as a container for span-level elements. + # + # + # === :header + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Span-level elements + # + # Represents a header. + # + # The option :level specifies the header level and has to contain a number between 1 and \6. The + # option :raw_text has to contain the raw header text. + # + # + # === :blockquote + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Block-level elements + # + # Represents a blockquote. + # + # + # === :codeblock + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Empty + # + # Represents a code block, i.e. a block of text that should be used as-is. + # + # The +value+ field has to contain the content of the code block. + # + # The option :lang specifies a highlighting language with possible HTML style options (e.g. + # php?start_inline=1) and should be used instead of a possibly also available language embedded in + # a class name of the form 'language-LANG'. + # + # + # === :ul + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an unordered list. + # + # + # === :ol + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more :li elements + # + # Represents an ordered list. + # + # + # === :li + # + # [Category] Block-level element + # [Usage context] Inside :ol and :ul elements + # [Content model] Block-level elements + # + # Represents a list item of an ordered or unordered list. + # + # Note that the first child of a list item must not be a :blank element! + # + # + # === :dl + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] One or more groups each consisting of one or more :dt elements followed by one + # or more :dd elements. + # + # Represents a definition list which contains groups consisting of terms and definitions for them. + # + # + # === :dt + # + # [Category] Block-level element + # [Usage context] Before :dt or :dd elements inside a :dl elment + # [Content model] Span-level elements + # + # Represents the term part of a term-definition group in a definition list. + # + # + # === :dd + # + # [Category] Block-level element + # [Usage context] After :dt or :dd elements inside a :dl elment + # [Content model] Block-level elements + # + # Represents the definition part of a term-definition group in a definition list. + # + # + # === :hr + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] None + # + # Represents a horizontal line. + # + # + # === :table + # + # [Category] Block-level element + # [Usage context] Where block-level elements are expected + # [Content model] Zero or one :thead elements, one or more :tbody elements, zero or one :tfoot + # elements + # + # Represents a table. Each table row (i.e. :tr element) of the table has to contain the same + # number of :td elements. + # + # The option :alignment has to be an array containing the alignment values, exactly one for each + # column of the table. The possible alignment values are :left, :center, :right and :default. + # + # + # === :thead + # + # [Category] None + # [Usage context] As first element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table header. + # + # + # === :tbody + # + # [Category] None + # [Usage context] After a :thead element but before a :tfoot element inside a :table element + # [Content model] One or more :tr elements + # + # Represents a table body. + # + # + # === :tfoot + # + # [Category] None + # [Usage context] As last element inside a :table element + # [Content model] One or more :tr elements + # + # Represents the table footer. + # + # + # === :tr + # + # [Category] None + # [Usage context] Inside :thead, :tbody and :tfoot elements + # [Content model] One or more :td elements + # + # Represents a table row. + # + # + # === :td + # + # [Category] Block-level element + # [Usage context] Inside :tr elements + # [Content model] As child of :thead/:tr span-level elements, as child of :tbody/:tr and + # :tfoot/:tr block-level elements + # + # Represents a table cell. + # + # + # === :math + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents mathematical text that is written in LaTeX. + # + # The +value+ field has to contain the actual mathematical text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # == Text Markup Elements + # + # === :text + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents text. + # + # The +value+ field has to contain the text itself. + # + # + # === :br + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a hard line break. + # + # + # === :a + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents a link to an URL. + # + # The attribute +href+ has to be set to the URL to which the link points. The attribute +title+ + # optionally contains the title of the link. + # + # + # === :img + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an image. + # + # The attribute +src+ has to be set to the URL of the image. The attribute +alt+ has to contain a + # text description of the image. The attribute +title+ optionally contains the title of the image. + # + # + # === :codespan + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents verbatim text. + # + # The +value+ field has to contain the content of the code span. + # + # + # === :footnote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a footnote marker. + # + # The +value+ field has to contain an element whose children are the content of the footnote. The + # option :name has to contain a valid and unique footnote name. A valid footnote name consists of + # a word character or a digit and then optionally followed by other word characters, digits or + # dashes. + # + # + # === :em + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents emphasis of its contents. + # + # + # === :strong + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] Span-level elements + # + # Represents strong importance for its contents. + # + # + # === :entity + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents an HTML entity. + # + # The +value+ field has to contain an instance of Kramdown::Utils::Entities::Entity. The option + # :original can be used to store the original representation of the entity. + # + # + # === :typographic_sym + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a typographic symbol. + # + # The +value+ field needs to contain a Symbol representing the specific typographic symbol from + # the following list: + # + # :mdash:: An mdash character (---) + # :ndash:: An ndash character (--) + # :hellip:: An ellipsis (...) + # :laquo:: A left guillemet (<<) + # :raquo:: A right guillemet (>>) + # :laquo_space:: A left guillemet with a space (<< ) + # :raquo_space:: A right guillemet with a space ( >>) + # + # + # === :smart_quote + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a quotation character. + # + # The +value+ field needs to contain a Symbol representing the specific quotation character: + # + # :lsquo:: Left single quote + # :rsquo:: Right single quote + # :ldquo:: Left double quote + # :rdquo:: Right double quote + # + # + # === :abbreviation + # + # [Category] Span-level element + # [Usage context] Where span-level elements are expected + # [Content model] None + # + # Represents a text part that is an abbreviation. + # + # The +value+ field has to contain the text part that is the abbreviation. The definition of the + # abbreviation is stored in the :root element of the document. + # + # + # == Other Elements + # + # === :html_element + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements or raw HTML elements are expected + # [Content model] Depends on the element + # + # Represents an HTML element. + # + # The +value+ field has to contain the name of the HTML element the element is representing. + # + # The option :category has to be set to either :span or :block depending on the whether the + # element is a block-level or a span-level element. The option :content_model has to be set to the + # content model for the element (either :block if it contains block-level elements, :span if it + # contains span-level elements or :raw if it contains raw content). + # + # + # === :xml_comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML comment. + # + # The +value+ field has to contain the whole XML/HTML comment including the delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :xml_pi + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected or in raw HTML elements + # [Content model] None + # + # Represents an XML/HTML processing instruction. + # + # The +value+ field has to contain the whole XML/HTML processing instruction including the + # delimiters. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. + # + # + # === :comment + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a comment. + # + # The +value+ field has to contain the comment. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the comment. + # + # + # === :raw + # + # [Category] Block/span-level element + # [Usage context] Where block/span-level elements are expected + # [Content model] None + # + # Represents a raw string that should not be modified. For example, the element could contain some + # HTML code that should be output as-is without modification and escaping. + # + # The +value+ field has to contain the actual raw text. + # + # The option :category has to be set to either :span or :block depending on the context where the + # element is used. If it is set to :span, then no blank lines are allowed in the raw text. + # + # The option :type can be set to an array of strings to define for which converters the raw string + # is valid. + # + class Element + + # A symbol representing the element type. For example, :p or :blockquote. + attr_accessor :type + + # The value of the element. The interpretation of this field depends on the type of the element. + # Many elements don't use this field. + attr_accessor :value + + # The child elements of this element. + attr_accessor :children + + # Create a new Element object of type +type+. The optional parameters +value+, +attr+ and + # +options+ can also be set in this constructor for convenience. + def initialize(type, value = nil, attr = nil, options = nil) + @type, @value, @attr, @options = type, value, attr, options + @children = [] + end + + # The attributes of the element. + def attr + @attr ||= {} + end + + # The options hash for the element. It is used for storing arbitray options. + def options + @options ||= {} + end + + def inspect # :nodoc: + "hallo` the emphasis tag + would normally be converted to an `:html` element with tag type `:em`. + If `html_to_native` is `true`, then the emphasis would be converted to a + native `:em` element. + + This is useful for converters that cannot deal with HTML elements. + + Default: false + Used by: kramdown parser + EOF + + define(:link_defs, Object, {}, <<~EOF) do |val| + Pre-defines link definitions + + This option can be used to pre-define link definitions. The value needs + to be a Hash where the keys are the link identifiers and the values are + two element Arrays with the link URL and the link title. + + If the value is a String, it has to contain a valid YAML hash and the + hash has to follow the above guidelines. + + Default: {} + Used by: kramdown parser + EOF + val = simple_hash_validator(val, :link_defs) + val.each do |_k, v| + if !(Array === v) || v.size > 2 || v.empty? + raise Kramdown::Error, "Invalid structure for hash value of option #{name}" + end + v << nil if v.size == 1 + end + val + end + + define(:footnote_nr, Integer, 1, <<~EOF) + The number of the first footnote + + This option can be used to specify the number that is used for the first + footnote. + + Default: 1 + Used by: HTML converter + EOF + + define(:entity_output, Symbol, :as_char, <<~EOF) + Defines how entities are output + + The possible values are :as_input (entities are output in the same + form as found in the input), :numeric (entities are output in numeric + form), :symbolic (entities are output in symbolic form if possible) or + :as_char (entities are output as characters if possible, only available + on Ruby 1.9). + + Default: :as_char + Used by: HTML converter, kramdown converter + EOF + + TOC_LEVELS_RANGE = (1..6).freeze + TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze + private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY + + define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val| + Defines the levels that are used for the table of contents + + The individual levels can be specified by separating them with commas + (e.g. 1,2,3) or by using the range syntax (e.g. 1..3). Only the + specified levels are used for the table of contents. + + Default: 1..6 + Used by: HTML/Latex converter + EOF + case val + when String + if val =~ /^(\d)\.\.(\d)$/ + val = Range.new($1.to_i, $2.to_i).to_a + elsif val.match?(/^\d(?:,\d)*$/) + val = val.split(",").map(&:to_i).uniq + else + raise Kramdown::Error, "Invalid syntax for option toc_levels" + end + when Array + unless val.eql?(TOC_LEVELS_ARRAY) + val = val.map(&:to_i).uniq + end + when Range + val = if val.eql?(TOC_LEVELS_RANGE) + TOC_LEVELS_ARRAY + else + val.map(&:to_i).uniq + end + else + raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels" + end + if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) } + raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6" + end + val + end + + define(:line_width, Integer, 72, <<~EOF) + Defines the line width to be used when outputting a document + + Default: 72 + Used by: kramdown converter + EOF + + define(:latex_headers, Object, %w[section subsection subsubsection paragraph subparagraph subparagraph], <<~EOF) do |val| + Defines the LaTeX commands for different header levels + + The commands for the header levels one to six can be specified by + separating them with commas. + + Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph + Used by: Latex converter + EOF + simple_array_validator(val, :latex_headers, 6) + end + + SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze + SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze + private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR + + define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val| + Defines the HTML entity names or code points for smart quote output + + The entities identified by entity name or code point that should be + used for, in order, a left single quote, a right single quote, a left + double and a right double quote are specified by separating them with + commas. + + Default: lsquo,rsquo,ldquo,rdquo + Used by: HTML/Latex converter + EOF + if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES + SMART_QUOTES_ENTITIES + else + val = simple_array_validator(val, :smart_quotes, 4) + val.map! {|v| Integer(v) rescue v } + val + end + end + + define(:typographic_symbols, Object, {}, <<~EOF) do |val| + Defines a mapping from typographical symbol to output characters + + Typographical symbols are normally output using their equivalent Unicode + codepoint. However, sometimes one wants to change the output, mostly to + fallback to a sequence of ASCII characters. + + This option allows this by specifying a mapping from typographical + symbol to its output string. For example, the mapping {hellip: ...} would + output the standard ASCII representation of an ellipsis. + + The available typographical symbol names are: + + * hellip: ellipsis + * mdash: em-dash + * ndash: en-dash + * laquo: left guillemet + * raquo: right guillemet + * laquo_space: left guillemet followed by a space + * raquo_space: right guillemet preceeded by a space + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :typographic_symbols) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k).to_s + end + val + end + + define(:remove_block_html_tags, Boolean, true, <<~EOF) + Remove block HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + block HTML tags. + + Default: true + Used by: RemoveHtmlTags converter + EOF + + define(:remove_span_html_tags, Boolean, false, <<~EOF) + Remove span HTML tags + + If this option is `true`, the RemoveHtmlTags converter removes + span HTML tags. + + Default: false + Used by: RemoveHtmlTags converter + EOF + + define(:header_offset, Integer, 0, <<~EOF) + Sets the output offset for headers + + If this option is c (may also be negative) then a header with level n + will be output as a header with level c+n. If c+n is lower than 1, + level 1 will be used. If c+n is greater than 6, level 6 will be used. + + Default: 0 + Used by: HTML converter, Kramdown converter, Latex converter + EOF + + define(:syntax_highlighter, Symbol, :rouge, <<~EOF) + Set the syntax highlighter + + Specifies the syntax highlighter that should be used for highlighting + code blocks and spans. If this option is set to +nil+, no syntax + highlighting is done. + + Options for the syntax highlighter can be set with the + syntax_highlighter_opts configuration option. + + Default: rouge + Used by: HTML/Latex converter + EOF + + define(:syntax_highlighter_opts, Object, {}, <<~EOF) do |val| + Set the syntax highlighter options + + Specifies options for the syntax highlighter set via the + syntax_highlighter configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used syntax highlighter. + + Default: {} + Used by: HTML/Latex converter + EOF + val = simple_hash_validator(val, :syntax_highlighter_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:math_engine, Symbol, :mathjax, <<~EOF) + Set the math engine + + Specifies the math engine that should be used for converting math + blocks/spans. If this option is set to +nil+, no math engine is used and + the math blocks/spans are output as is. + + Options for the selected math engine can be set with the + math_engine_opts configuration option. + + Default: mathjax + Used by: HTML converter + EOF + + define(:math_engine_opts, Object, {}, <<~EOF) do |val| + Set the math engine options + + Specifies options for the math engine set via the math_engine + configuration option. + + The value needs to be a hash with key-value pairs that are understood by + the used math engine. + + Default: {} + Used by: HTML converter + EOF + val = simple_hash_validator(val, :math_engine_opts) + val.keys.each do |k| + val[k.kind_of?(String) ? str_to_sym(k) : k] = val.delete(k) + end + val + end + + define(:footnote_backlink, String, '↩', <<~EOF) + Defines the text that should be used for the footnote backlinks + + The footnote backlink is just text, so any special HTML characters will + be escaped. + + If the footnote backlint text is an empty string, no footnote backlinks + will be generated. + + Default: '&8617;' + Used by: HTML converter + EOF + + define(:footnote_backlink_inline, Boolean, false, <<~EOF) + Specifies whether the footnote backlink should always be inline + + With the default of false the footnote backlink is placed at the end of + the last paragraph if there is one, or an extra paragraph with only the + footnote backlink is created. + + Setting this option to true tries to place the footnote backlink in the + last, possibly nested paragraph or header. If this fails (e.g. in the + case of a table), an extra paragraph with only the footnote backlink is + created. + + Default: false + Used by: HTML converter + EOF + + define(:footnote_prefix, String, '', <<~EOF) + Prefix used for footnote IDs + + This option can be used to set a prefix for footnote IDs. This is useful + when rendering multiple documents into the same output file to avoid + duplicate IDs. The prefix should only contain characters that are valid + in an ID! + + Default: '' + Used by: HTML + EOF + + define(:footnote_link_text, String, '%s', <<~EOF) do |val| + The text used for the footnote number in a footnote link + + This option can be used to add additional text to the footnote + link. It should be a format string, and is passed the footnote + number as the only argument to the format string. + e.g. "[footnote %s]" would display as "[footnote 1]". + + Default: '%s' + Used by: HTML + EOF + if !val.include?('%s') + raise Kramdown::Error, "option footnote_link_text needs to contain a '%s'" + end + val + end + + + define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF) + Specifies whether line breaks should be removed between CJK characters + + Default: false + Used by: HTML converter + EOF + + define(:forbidden_inline_options, Object, %w[template], <<~EOF) do |val| + Defines the options that may not be set using the {::options} extension + + The value needs to be an array of option names. + + Default: [template] + Used by: HTML converter + EOF + val.map! {|item| item.kind_of?(String) ? str_to_sym(item) : item } + simple_array_validator(val, :forbidden_inline_options) + end + + define(:list_indent, Integer, 2, <<~EOF) + Sets the number of spaces to use for list indentation + + Default: 2 + Used by: Kramdown converter + EOF + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser.rb new file mode 100644 index 00000000..ee04bdaf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # This module contains all available parsers. A parser takes an input string and converts the + # string to an element tree. + # + # New parsers should be derived from the Base class which provides common functionality - see its + # API documentation for how to create a custom converter class. + module Parser + + autoload :Base, 'kramdown/parser/base' + autoload :Kramdown, 'kramdown/parser/kramdown' + autoload :Html, 'kramdown/parser/html' + autoload :Markdown, 'kramdown/parser/markdown' + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/base.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/base.rb new file mode 100644 index 00000000..075385eb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/base.rb @@ -0,0 +1,137 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # == \Base class for parsers + # + # This class serves as base class for parsers. It provides common methods that can/should be + # used by all parsers, especially by those using StringScanner(Kramdown) for parsing. + # + # A parser object is used as a throw-away object, i.e. it is only used for storing the needed + # state information during parsing. Therefore one can't instantiate a parser object directly but + # only use the Base::parse method. + # + # == Implementing a parser + # + # Implementing a new parser is rather easy: just derive a new class from this class and put it + # in the Kramdown::Parser module -- the latter is needed so that the auto-detection of the new + # parser works correctly. Then you need to implement the +#parse+ method which has to contain + # the parsing code. + # + # Have a look at the Base::parse, Base::new and Base#parse methods for additional information! + class Base + + # The hash with the parsing options. + attr_reader :options + + # The array with the parser warnings. + attr_reader :warnings + + # The original source string. + attr_reader :source + + # The root element of element tree that is created from the source string. + attr_reader :root + + # Initialize the parser object with the +source+ string and the parsing +options+. + # + # The @root element, the @warnings array and @text_type (specifies the default type for newly + # created text nodes) are automatically initialized. + def initialize(source, options) + @source = source + @options = Kramdown::Options.merge(options) + @root = Element.new(:root, nil, nil, encoding: (source.encoding rescue nil), location: 1, + options: {}, abbrev_defs: {}, abbrev_attr: {}) + + @root.options[:abbrev_defs].default_proc = @root.options[:abbrev_attr].default_proc = + lambda do |h, k| + k_mod = k.gsub(/[\s\p{Z}]+/, " ") + k != k_mod ? h[k_mod] : nil + end + @warnings = [] + @text_type = :text + end + private_class_method(:new, :allocate) + + # Parse the +source+ string into an element tree, possibly using the parsing +options+, and + # return the root element of the element tree and an array with warning messages. + # + # Initializes a new instance of the calling class and then calls the +#parse+ method that must + # be implemented by each subclass. + def self.parse(source, options = {}) + parser = new(source, options) + parser.parse + [parser.root, parser.warnings] + end + + # Parse the source string into an element tree. + # + # The parsing code should parse the source provided in @source and build an element tree the + # root of which should be @root. + # + # This is the only method that has to be implemented by sub-classes! + def parse + raise NotImplementedError + end + + # Add the given warning +text+ to the warning array. + def warning(text) + @warnings << text + # TODO: add position information + end + + # Modify the string +source+ to be usable by the parser (unifies line ending characters to + # +\n+ and makes sure +source+ ends with a new line character). + def adapt_source(source) + unless source.valid_encoding? + raise "The source text contains invalid characters for the used encoding #{source.encoding}" + end + source = source.encode('UTF-8') + source.gsub!(/\r\n?/, "\n") + source.chomp! + source << "\n" + end + + # This helper method adds the given +text+ either to the last element in the +tree+ if it is a + # +type+ element or creates a new text element with the given +type+. + def add_text(text, tree = @tree, type = @text_type) + last = tree.children.last + if last && last.type == type + last.value << text + elsif !text.empty? + location = (last && last.options[:location] || tree.options[:location]) + tree.children << Element.new(type, text, nil, location: location) + end + end + + # Extract the part of the StringScanner +strscan+ backed string specified by the +range+. This + # method works correctly under Ruby 1.8 and Ruby 1.9. + def extract_string(range, strscan) + result = nil + begin + enc = strscan.string.encoding + strscan.string.force_encoding('ASCII-8BIT') + result = strscan.string[range].force_encoding(enc) + ensure + strscan.string.force_encoding(enc) + end + result + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/html.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/html.rb new file mode 100644 index 00000000..47093ded --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/html.rb @@ -0,0 +1,621 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' +require 'strscan' +require 'kramdown/utils' +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing an HTML document. + # + # The parsing code is in the Parser module that can also be used by other parsers. + class Html < Base + + # Contains all constants that are used when parsing. + module Constants + + # :stopdoc: + # The following regexps are based on the ones used by REXML, with some slight modifications. + HTML_DOCTYPE_RE = //im + HTML_COMMENT_RE = //m + HTML_INSTRUCTION_RE = /<\?(.*?)\?>/m + HTML_CDATA_RE = //m + HTML_ATTRIBUTE_RE = /\s*(#{REXML::Parsers::BaseParser::UNAME_STR})(?:\s*=\s*(?:(\p{Word}+)|("|')(.*?)\3))?/m + HTML_TAG_RE = /<((?>#{REXML::Parsers::BaseParser::UNAME_STR}))\s*((?>\s+#{REXML::Parsers::BaseParser::UNAME_STR}(?:\s*=\s*(?:\p{Word}+|("|').*?\3))?)*)\s*(\/)?>/m + HTML_TAG_CLOSE_RE = /<\/(#{REXML::Parsers::BaseParser::UNAME_STR})\s*>/m + HTML_ENTITY_RE = /&([\w:][\w.:-]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/ + + HTML_CONTENT_MODEL_BLOCK = %w[address applet article aside blockquote body + dd details div dl fieldset figure figcaption + footer form header hgroup iframe li main + map menu nav noscript object section summary td] + HTML_CONTENT_MODEL_SPAN = %w[a abbr acronym b bdo big button cite caption del dfn dt em + h1 h2 h3 h4 h5 h6 i ins label legend optgroup p q rb rbc + rp rt rtc ruby select small span strong sub sup th tt] + HTML_CONTENT_MODEL_RAW = %w[script style math option textarea pre code kbd samp var] + # The following elements are also parsed as raw since they need child elements that cannot + # be expressed using kramdown syntax: colgroup table tbody thead tfoot tr ul ol + + HTML_CONTENT_MODEL = Hash.new {|h, k| h[k] = :raw } + HTML_CONTENT_MODEL_BLOCK.each {|i| HTML_CONTENT_MODEL[i] = :block } + HTML_CONTENT_MODEL_SPAN.each {|i| HTML_CONTENT_MODEL[i] = :span } + HTML_CONTENT_MODEL_RAW.each {|i| HTML_CONTENT_MODEL[i] = :raw } + + # Some HTML elements like script belong to both categories (i.e. are valid in block and + # span HTML) and don't appear therefore! + # script, textarea + HTML_SPAN_ELEMENTS = %w[a abbr acronym b big bdo br button cite code del dfn em i img input + ins kbd label mark option q rb rbc rp rt rtc ruby samp select small + span strong sub sup time tt u var] + HTML_BLOCK_ELEMENTS = %w[address article aside applet body blockquote caption col colgroup + dd div dl dt fieldset figcaption footer form h1 h2 h3 h4 h5 h6 + header hgroup hr html head iframe legend menu li main map nav ol + optgroup p pre section summary table tbody td th thead tfoot tr ul] + HTML_ELEMENTS_WITHOUT_BODY = %w[area base br col command embed hr img input keygen link + meta param source track wbr] + + HTML_ELEMENT = Hash.new(false) + (HTML_SPAN_ELEMENTS + HTML_BLOCK_ELEMENTS + HTML_ELEMENTS_WITHOUT_BODY + + HTML_CONTENT_MODEL.keys).each do |a| + HTML_ELEMENT[a] = true + end + end + + # Contains the parsing methods. This module can be mixed into any parser to get HTML parsing + # functionality. The only thing that must be provided by the class are instance variable + # @stack for storing the needed state and @src (instance of StringScanner) for the actual + # parsing. + module Parser + + include Constants + + # Process the HTML start tag that has already be scanned/checked via @src. + # + # Does the common processing steps and then yields to the caller for further processing + # (first parameter is the created element; the second parameter is +true+ if the HTML + # element is already closed, ie. contains no body; the third parameter specifies whether the + # body - and the end tag - need to be handled in case closed=false). + def handle_html_start_tag(line = nil) # :yields: el, closed, handle_body + name = @src[1] + name.downcase! if HTML_ELEMENT[name.downcase] + closed = !@src[4].nil? + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[name]) + + el = Element.new(:html_element, name, attrs, category: :block) + el.options[:location] = line if line + @tree.children << el + + if !closed && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + closed = true + end + if name == 'script' || name == 'style' + handle_raw_html_tag(name) + yield(el, false, false) + else + yield(el, closed, true) + end + end + + # Parses the given string for HTML attributes and returns the resulting hash. + # + # If the optional +line+ parameter is supplied, it is used in warning messages. + # + # If the optional +in_html_tag+ parameter is set to +false+, attributes are not modified to + # contain only lowercase letters. + def parse_html_attributes(str, line = nil, in_html_tag = true) + attrs = {} + str.scan(HTML_ATTRIBUTE_RE).each do |attr, val, _sep, quoted_val| + attr.downcase! if in_html_tag + if attrs.key?(attr) + warning("Duplicate HTML attribute '#{attr}' on line #{line || '?'} - overwriting previous one") + end + attrs[attr] = val || quoted_val || "" + end + attrs + end + + # Handle the raw HTML tag at the current position. + def handle_raw_html_tag(name) + curpos = @src.pos + if @src.scan_until(/(?=<\/#{name}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), @tree.children.last, :raw) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, @tree.children.last, :raw) + @src.terminate + warning("Found no end tag for '#{name}' - auto-closing it") + end + end + + HTML_RAW_START = /(?=<(#{REXML::Parsers::BaseParser::UNAME_STR}|\/|!--|\?|!\[CDATA\[))/ # :nodoc: + + # Parse raw HTML from the current source position, storing the found elements in +el+. + # Parsing continues until one of the following criteria are fulfilled: + # + # - The end of the document is reached. + # - The matching end tag for the element +el+ is found (only used if +el+ is an HTML + # element). + # + # When an HTML start tag is found, processing is deferred to #handle_html_start_tag, + # providing the block given to this method. + def parse_raw_html(el, &block) + @stack.push(@tree) + @tree = el + + done = false + while !@src.eos? && !done + if (result = @src.scan_until(HTML_RAW_START)) + add_text(result, @tree, :text) + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + elsif (result = @src.scan(HTML_INSTRUCTION_RE)) + @tree.children << Element.new(:xml_pi, result, nil, category: :block, location: line) + elsif @src.scan(HTML_CDATA_RE) + @tree.children << Element.new(:text, @src[1], nil, cdata: true, location: line) + elsif @src.scan(HTML_TAG_RE) + if method(:handle_html_start_tag).arity.abs >= 1 + handle_html_start_tag(line, &block) + else + handle_html_start_tag(&block) # DEPRECATED: method needs to accept line number in 2.0 + end + elsif @src.scan(HTML_TAG_CLOSE_RE) + if @tree.value == (HTML_ELEMENT[@tree.value] ? @src[1].downcase : @src[1]) + done = true + else + add_text(@src.matched, @tree, :text) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on " \ + "line #{line} - ignoring it") + end + else + add_text(@src.getch, @tree, :text) + end + else + add_text(@src.rest, @tree, :text) + @src.terminate + if @tree.type == :html_element + warning("Found no end tag for '#{@tree.value}' on line " \ + "#{@tree.options[:location]} - auto-closing it") + end + done = true + end + end + + @tree = @stack.pop + end + + end + + # Converts HTML elements to native elements if possible. + class ElementConverter + + # :stopdoc: + + include Constants + include ::Kramdown::Utils::Entities + + REMOVE_TEXT_CHILDREN = %w[html head hgroup ol ul dl table colgroup tbody thead tfoot tr + select optgroup] + WRAP_TEXT_CHILDREN = %w[body section nav article aside header footer address div li dd + blockquote figure figcaption fieldset form] + REMOVE_WHITESPACE_CHILDREN = %w[body section nav article aside header footer address + div li dd blockquote figure figcaption td th fieldset form] + STRIP_WHITESPACE = %w[address article aside blockquote body caption dd div dl dt fieldset + figcaption form footer header h1 h2 h3 h4 h5 h6 legend li nav p + section td th] + SIMPLE_ELEMENTS = %w[em strong blockquote hr br img p thead tbody tfoot tr td th ul ol dl + li dl dt dd] + + def initialize(root) + @root = root + end + + def self.convert(root, el = root) + new(root).process(el) + end + + # Convert the element +el+ and its children. + def process(el, do_conversion = true, preserve_text = false, parent = nil) + case el.type + when :xml_comment, :xml_pi + ptype = if parent.nil? + 'div' + else + case parent.type + when :html_element then parent.value + when :code_span then 'code' + when :code_block then 'pre' + when :header then 'h1' + else parent.type.to_s + end + end + el.options.replace(category: (HTML_CONTENT_MODEL[ptype] == :span ? :span : :block)) + return + when :html_element + # do nothing + when :root + el.children.map! do |c| + if c.type == :text + process_text(c.value, !do_conversion) + else + process(c) + c + end + end.flatten! + remove_whitespace_children(el) + return + else return + end + + mname = "convert_#{el.value}" + if do_conversion && self.class.method_defined?(mname) + send(mname, el) + else + type = el.value + remove_text_children(el) if do_conversion && REMOVE_TEXT_CHILDREN.include?(type) + + if do_conversion && SIMPLE_ELEMENTS.include?(type) + set_basics(el, type.intern) + process_children(el, do_conversion, preserve_text) + else + process_html_element(el, do_conversion, preserve_text) + end + + if do_conversion + strip_whitespace(el) if STRIP_WHITESPACE.include?(type) + remove_whitespace_children(el) if REMOVE_WHITESPACE_CHILDREN.include?(type) + wrap_text_children(el) if WRAP_TEXT_CHILDREN.include?(type) + end + end + end + + def process_children(el, do_conversion = true, preserve_text = false) + el.children.map! do |c| + if c.type == :text + process_text(c.value, preserve_text || !do_conversion) + else + process(c, do_conversion, preserve_text, el) + c + end + end.flatten! + end + + # Process the HTML text +raw+: compress whitespace (if +preserve+ is +false+) and convert + # entities in entity elements. + def process_text(raw, preserve = false) + raw.gsub!(/\s+/, ' ') unless preserve + src = Kramdown::Utils::StringScanner.new(raw) + result = [] + until src.eos? + if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o)) + result << Element.new(:text, tmp) + src.scan(HTML_ENTITY_RE) + val = src[1] || src[2]&.to_i || src[3].hex + result << if %w[lsquo rsquo ldquo rdquo].include?(val) + Element.new(:smart_quote, val.intern) + elsif %w[mdash ndash hellip laquo raquo].include?(val) + Element.new(:typographic_sym, val.intern) + else + begin + Element.new(:entity, entity(val), nil, original: src.matched) + rescue ::Kramdown::Error + src.pos -= src.matched_size - 1 + Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp')) + end + end + else + result << Element.new(:text, src.rest) + src.terminate + end + end + result + end + + def process_html_element(el, do_conversion = true, preserve_text = false) + el.options.replace(category: HTML_SPAN_ELEMENTS.include?(el.value) ? :span : :block, + content_model: (do_conversion ? HTML_CONTENT_MODEL[el.value] : :raw)) + process_children(el, do_conversion, preserve_text) + end + + def remove_text_children(el) + el.children.delete_if {|c| c.type == :text } + end + + def wrap_text_children(el) + tmp = [] + last_is_p = false + el.children.each do |c| + if !c.block? || c.type == :text + unless last_is_p + tmp << Element.new(:p, nil, nil, transparent: true) + last_is_p = true + end + tmp.last.children << c + tmp + else + tmp << c + last_is_p = false + end + end + el.children = tmp + end + + def strip_whitespace(el) + return if el.children.empty? + if el.children.first.type == :text + el.children.first.value.lstrip! + end + if el.children.last.type == :text + el.children.last.value.rstrip! + end + end + + def remove_whitespace_children(el) + i = -1 + el.children = el.children.reject do |c| + i += 1 + c.type == :text && c.value.strip.empty? && + (i == 0 || i == el.children.length - 1 || (el.children[i - 1].block? && + el.children[i + 1].block?)) + end + end + + def set_basics(el, type, opts = {}) + el.type = type + el.options.replace(opts) + el.value = nil + end + + def extract_text(el, raw) + raw << el.value.to_s if el.type == :text + el.children.each {|c| extract_text(c, raw) } + end + + def convert_textarea(el) + process_html_element(el, true, true) + end + + def convert_a(el) + if el.attr['href'] + set_basics(el, :a) + process_children(el) + else + process_html_element(el, false) + end + end + + EMPHASIS_TYPE_MAP = {'em' => :em, 'i' => :em, 'strong' => :strong, 'b' => :strong} + def convert_em(el) + text = +'' + extract_text(el, text) + if text =~ /\A\s/ || text =~ /\s\z/ + process_html_element(el, false) + else + set_basics(el, EMPHASIS_TYPE_MAP[el.value]) + process_children(el) + end + end + %w[b strong i].each do |i| + alias_method("convert_#{i}".to_sym, :convert_em) + end + + def convert_h1(el) + set_basics(el, :header, level: el.value[1..1].to_i) + extract_text(el, el.options[:raw_text] = +'') + process_children(el) + end + %w[h2 h3 h4 h5 h6].each do |i| + alias_method("convert_#{i}".to_sym, :convert_h1) + end + + def convert_code(el) + raw = +'' + extract_text(el, raw) + result = process_text(raw, true) + begin + str = result.inject(+'') do |mem, c| + case c.type + when :text + mem << c.value + when :entity + mem << if [60, 62, 34, 38].include?(c.value.code_point) + c.value.code_point.chr + else + c.value.char + end + when :smart_quote, :typographic_sym + mem << entity(c.value.to_s).char + else + raise "Bug - please report" + end + end + result.clear + result << Element.new(:text, str) + rescue StandardError + end + if result.length > 1 || result.first.type != :text + process_html_element(el, false, true) + else + if el.value == 'code' + set_basics(el, :codespan) + el.attr['class']&.gsub!(/\s+\bhighlighter-\w+\b|\bhighlighter-\w+\b\s*/, '') + else + set_basics(el, :codeblock) + if el.children.size == 1 && el.children.first.value == 'code' + value = (el.children.first.attr['class'] || '').scan(/\blanguage-\S+/).first + el.attr['class'] = "#{value} #{el.attr['class']}".rstrip if value + end + end + el.value = result.first.value + el.children.clear + end + end + alias convert_pre convert_code + + def convert_table(el) + unless is_simple_table?(el) + process_html_element(el, false) + return + end + remove_text_children(el) + process_children(el) + set_basics(el, :table) + + calc_alignment = lambda do |c| + if c.type == :tr + el.options[:alignment] = c.children.map do |td| + if td.attr['style'] + td.attr['style'].slice!(/(?:;\s*)?text-align:\s+(center|left|right)/) + td.attr.delete('style') if td.attr['style'].strip.empty? + $1 ? $1.to_sym : :default + else + :default + end + end + else + c.children.each {|cc| calc_alignment.call(cc) } + end + end + calc_alignment.call(el) + el.children.delete_if {|c| c.type == :html_element } + + change_th_type = lambda do |c| + if c.type == :th + c.type = :td + else + c.children.each {|cc| change_th_type.call(cc) } + end + end + change_th_type.call(el) + + if el.children.first.type == :tr + tbody = Element.new(:tbody) + tbody.children = el.children + el.children = [tbody] + end + end + + def is_simple_table?(el) + only_phrasing_content = lambda do |c| + c.children.all? do |cc| + (cc.type == :text || !HTML_BLOCK_ELEMENTS.include?(cc.value)) && only_phrasing_content.call(cc) + end + end + check_cells = proc do |c| + if c.value == 'th' || c.value == 'td' + return false unless only_phrasing_content.call(c) + else + c.children.each {|cc| check_cells.call(cc) } + end + end + check_cells.call(el) + + nr_cells = 0 + check_nr_cells = lambda do |t| + if t.value == 'tr' + count = t.children.count {|cc| cc.value == 'th' || cc.value == 'td' } + if count != nr_cells + if nr_cells == 0 + nr_cells = count + else + nr_cells = -1 + break + end + end + else + t.children.each {|cc| check_nr_cells.call(cc) } + end + end + check_nr_cells.call(el) + return false if nr_cells == -1 || nr_cells == 0 + + alignment = nil + check_alignment = proc do |t| + if t.value == 'tr' + cur_alignment = t.children.select {|cc| cc.value == 'th' || cc.value == 'td' }.map do |cell| + md = /text-align:\s+(center|left|right|justify|inherit)/.match(cell.attr['style'].to_s) + return false if md && (md[1] == 'justify' || md[1] == 'inherit') + md.nil? ? :default : md[1] + end + alignment = cur_alignment if alignment.nil? + return false if alignment != cur_alignment + else + t.children.each {|cc| check_alignment.call(cc) } + end + end + check_alignment.call(el) + + check_rows = lambda do |t, type| + t.children.all? do |r| + (r.value == 'tr' || r.type == :text) && r.children.all? {|c| c.value == type || c.type == :text } + end + end + check_rows.call(el, 'td') || + (el.children.all? do |t| + t.type == :text || (t.value == 'thead' && check_rows.call(t, 'th')) || + ((t.value == 'tfoot' || t.value == 'tbody') && check_rows.call(t, 'td')) + end && el.children.any? {|t| t.value == 'tbody' }) + end + + def convert_script(el) + if is_math_tag?(el) + handle_math_tag(el) + else + process_html_element(el) + end + end + + def is_math_tag?(el) + el.attr['type'].to_s =~ /\bmath\/tex\b/ + end + + def handle_math_tag(el) + set_basics(el, :math, category: (el.attr['type'].include?("mode=display") ? :block : :span)) + el.value = el.children.shift.value.sub(/\A(?:%\s*)?\z/m, '\1') + el.attr.delete('type') + end + + end + + include Parser + + # Parse the source string provided on initialization as HTML document. + def parse + @stack, @tree = [], @root + @src = Kramdown::Utils::StringScanner.new(adapt_source(source)) + + while true + if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o)) + @tree.children << Element.new(:xml_pi, result.strip, nil, category: :block) + elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o)) + # ignore the doctype + elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o)) + @tree.children << Element.new(:xml_comment, result.strip, nil, category: :block) + else + break + end + end + + tag_handler = lambda do |c, closed, handle_body| + parse_raw_html(c, &tag_handler) if !closed && handle_body + end + parse_raw_html(@tree, &tag_handler) + + ElementConverter.convert(@tree) + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown.rb new file mode 100644 index 00000000..7e17f3f8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown.rb @@ -0,0 +1,377 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' +require 'stringio' +require 'kramdown/parser' + +# TODO: use [[:alpha:]] in all regexp to allow parsing of international values in 1.9.1 +# NOTE: use @src.pre_match only before other check/match?/... operations, otherwise the content is changed + +module Kramdown + + module Parser + + # Used for parsing a document in kramdown format. + # + # If you want to extend the functionality of the parser, you need to do the following: + # + # * Create a new subclass + # * add the needed parser methods + # * modify the @block_parsers and @span_parsers variables and add the names of your parser + # methods + # + # Here is a small example for an extended parser class that parses ERB style tags as raw text if + # they are used as span-level elements (an equivalent block-level parser should probably also be + # made to handle the block case): + # + # require 'kramdown/parser/kramdown' + # + # class Kramdown::Parser::ERBKramdown < Kramdown::Parser::Kramdown + # + # def initialize(source, options) + # super + # @span_parsers.unshift(:erb_tags) + # end + # + # ERB_TAGS_START = /<%.*?%>/ + # + # def parse_erb_tags + # @src.pos += @src.matched_size + # @tree.children << Element.new(:raw, @src.matched) + # end + # define_parser(:erb_tags, ERB_TAGS_START, '<%') + # + # end + # + # The new parser can be used like this: + # + # require 'kramdown/document' + # # require the file with the above parser class + # + # Kramdown::Document.new(input_text, :input => 'ERBKramdown').to_html + # + class Kramdown < Base + + include ::Kramdown + + # Create a new Kramdown parser object with the given +options+. + def initialize(source, options) + super + + reset_env + + @alds = {} + @footnotes = {} + @link_defs = {} + update_link_definitions(@options[:link_defs]) + + @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header, + :horizontal_rule, :list, :definition_list, :block_html, :setext_header, + :block_math, :table, :footnote_definition, :link_definition, + :abbrev_definition, :block_extensions, :eob_marker, :paragraph] + @span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, + :smart_quotes, :inline_math, :span_extensions, :html_entity, + :typographic_syms, :line_break, :escaped_chars] + + @span_pattern_cache ||= Hash.new {|h, k| h[k] = {} } + end + private_class_method(:new, :allocate) + + # The source string provided on initialization is parsed into the @root element. + def parse + configure_parser + parse_blocks(@root, adapt_source(source)) + update_tree(@root) + correct_abbreviations_attributes + replace_abbreviations(@root) + @footnotes.each do |_name, data| + update_tree(data[:content]) + replace_abbreviations(data[:content]) + end + footnote_count = 0 + @footnotes.each do |name, data| + (footnote_count += 1; next) if data.key?(:marker) + line = data[:content].options[:location] + warning("Footnote definition for '#{name}' on line #{line} is unreferenced - ignoring") + end + @root.options[:footnote_count] = footnote_count + end + + protected + + # :doc: + # + # Update the parser specific link definitions with the data from +link_defs+ (the value of the + # :link_defs option). + # + # The parameter +link_defs+ is a hash where the keys are possibly unnormalized link IDs and + # the values are two element arrays consisting of the link target and a title (can be +nil+). + def update_link_definitions(link_defs) + link_defs.each {|k, v| @link_defs[normalize_link_id(k)] = v } + end + + # Adapt the object to allow parsing like specified in the options. + def configure_parser + @parsers = {} + (@block_parsers + @span_parsers).each do |name| + if self.class.has_parser?(name) + @parsers[name] = self.class.parser(name) + else + raise Kramdown::Error, "Unknown parser: #{name}" + end + end + @span_start, @span_start_re = span_parser_regexps + end + + # Create the needed span parser regexps. + def span_parser_regexps(parsers = @span_parsers) + span_start = /#{parsers.map {|name| @parsers[name].span_start }.join('|')}/ + [span_start, /(?=#{span_start})/] + end + + # Parse all block-level elements in +text+ into the element +el+. + def parse_blocks(el, text = nil) + @stack.push([@tree, @src, @block_ial]) + @tree, @block_ial = el, nil + @src = (text.nil? ? @src : ::Kramdown::Utils::StringScanner.new(text, el.options[:location])) + + status = catch(:stop_block_parsing) do + until @src.eos? + @block_parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + else + false + end + end || begin + warning('Warning: this should not occur - no block parser handled the line') + add_text(@src.scan(/.*\n/)) + end + end + end + + @tree, @src, @block_ial = *@stack.pop + status + end + + # Update the tree by parsing all :+raw_text+ elements with the span-level parser (resets the + # environment) and by updating the attributes from the IALs. + def update_tree(element) + last_blank = nil + element.children.map! do |child| + case child.type + when :raw_text + last_blank = nil + reset_env(src: ::Kramdown::Utils::StringScanner.new(child.value, element.options[:location]), + text_type: :text) + parse_spans(child) + child.children + when :eob + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + [] + when :blank + if last_blank + last_blank.value << child.value + [] + else + last_blank = child + child + end + else + last_blank = nil + update_tree(child) + update_attr_with_ial(child.attr, child.options[:ial]) if child.options[:ial] + # DEPRECATED: option auto_id_stripping will be removed in 2.0 because then this will be + # the default behaviour + if child.type == :dt || (child.type == :header && @options[:auto_id_stripping]) + update_raw_text(child) + end + child + end + end.flatten! + end + + def span_pattern_cache(stop_re, span_start) + @span_pattern_cache[stop_re][span_start] ||= /(?=#{Regexp.union(stop_re, span_start)})/ + end + private :span_pattern_cache + + # Parse all span-level elements in the source string of @src into +el+. + # + # If the parameter +stop_re+ (a regexp) is used, parsing is immediately stopped if the regexp + # matches and if no block is given or if a block is given and it returns +true+. + # + # The parameter +parsers+ can be used to specify the (span-level) parsing methods that should + # be used for parsing. + # + # The parameter +text_type+ specifies the type which should be used for created text nodes. + def parse_spans(el, stop_re = nil, parsers = nil, text_type = @text_type) + @stack.push([@tree, @text_type]) unless @tree.nil? + @tree, @text_type = el, text_type + + span_start = @span_start + span_start_re = @span_start_re + span_start, span_start_re = span_parser_regexps(parsers) if parsers + parsers ||= @span_parsers + + used_re = (stop_re.nil? ? span_start_re : span_pattern_cache(stop_re, span_start)) + stop_re_found = false + while !@src.eos? && !stop_re_found + if (result = @src.scan_until(used_re)) + add_text(result) + if stop_re && @src.check(stop_re) + stop_re_found = (block_given? ? yield : true) + end + processed = parsers.any? do |name| + if @src.check(@parsers[name].start_re) + send(@parsers[name].method) + true + else + false + end + end unless stop_re_found + add_text(@src.getch) if !processed && !stop_re_found + else + (add_text(@src.rest); @src.terminate) unless stop_re + break + end + end + + @tree, @text_type = @stack.pop + + stop_re_found + end + + # Reset the current parsing environment. The parameter +env+ can be used to set initial + # values for one or more environment variables. + def reset_env(opts = {}) + opts = {text_type: :raw_text, stack: []}.merge(opts) + @src = opts[:src] + @tree = opts[:tree] + @block_ial = opts[:block_ial] + @stack = opts[:stack] + @text_type = opts[:text_type] + end + + # Return the current parsing environment. + def save_env + [@src, @tree, @block_ial, @stack, @text_type] + end + + # Restore the current parsing environment. + def restore_env(env) + @src, @tree, @block_ial, @stack, @text_type = *env + end + + # Update the given attributes hash +attr+ with the information from the inline attribute list + # +ial+ and all referenced ALDs. + def update_attr_with_ial(attr, ial) + ial[:refs]&.each do |ref| + update_attr_with_ial(attr, ref) if (ref = @alds[ref]) + end + ial.each do |k, v| + if k == IAL_CLASS_ATTR + attr[k] = "#{attr[k]} #{v}".lstrip + elsif k.kind_of?(String) + attr[k] = v + end + end + end + + # Update the raw text for automatic ID generation. + def update_raw_text(item) + raw_text = +'' + + append_text = lambda do |child| + if child.type == :text + raw_text << child.value + else + child.children.each {|c| append_text.call(c) } + end + end + + append_text.call(item) + item.options[:raw_text] = raw_text + end + + # Create a new block-level element, taking care of applying a preceding block IAL if it + # exists. This method should always be used for creating a block-level element! + def new_block_el(*args) + el = Element.new(*args) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + el + end + + @@parsers = {} + + # Struct class holding all the needed data for one block/span-level parser method. + Data = Struct.new(:name, :start_re, :span_start, :method) + + # Add a parser method + # + # * with the given +name+, + # * using +start_re+ as start regexp + # * and, for span parsers, +span_start+ as a String that can be used in a regexp and + # which identifies the starting character(s) + # + # to the registry. The method name is automatically derived from the +name+ or can explicitly + # be set by using the +meth_name+ parameter. + def self.define_parser(name, start_re, span_start = nil, meth_name = "parse_#{name}") + raise "A parser with the name #{name} already exists!" if @@parsers.key?(name) + @@parsers[name] = Data.new(name, start_re, span_start, meth_name) + end + + # Return the Data structure for the parser +name+. + def self.parser(name = nil) + @@parsers[name] + end + + # Return +true+ if there is a parser called +name+. + def self.has_parser?(name) + @@parsers.key?(name) + end + + # Regexp for matching indentation (one tab or four spaces) + INDENT = /^(?:\t| {4})/ + # Regexp for matching the optional space (zero or up to three spaces) + OPT_SPACE = / {0,3}/ + + require 'kramdown/parser/kramdown/blank_line' + require 'kramdown/parser/kramdown/eob' + require 'kramdown/parser/kramdown/paragraph' + require 'kramdown/parser/kramdown/header' + require 'kramdown/parser/kramdown/blockquote' + require 'kramdown/parser/kramdown/table' + require 'kramdown/parser/kramdown/codeblock' + require 'kramdown/parser/kramdown/horizontal_rule' + require 'kramdown/parser/kramdown/list' + require 'kramdown/parser/kramdown/link' + require 'kramdown/parser/kramdown/extensions' + require 'kramdown/parser/kramdown/footnote' + require 'kramdown/parser/kramdown/html' + require 'kramdown/parser/kramdown/escaped_chars' + require 'kramdown/parser/kramdown/html_entity' + require 'kramdown/parser/kramdown/line_break' + require 'kramdown/parser/kramdown/typographic_symbol' + require 'kramdown/parser/kramdown/autolink' + require 'kramdown/parser/kramdown/codespan' + require 'kramdown/parser/kramdown/emphasis' + require 'kramdown/parser/kramdown/smart_quotes' + require 'kramdown/parser/kramdown/math' + require 'kramdown/parser/kramdown/abbreviation' + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/abbreviation.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/abbreviation.rb new file mode 100644 index 00000000..e9d7764e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/abbreviation.rb @@ -0,0 +1,80 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ABBREV_DEFINITION_START = /^#{OPT_SPACE}\*\[(.+?)\]:(.*?)\n/ + + # Parse the link definition at the current location. + def parse_abbrev_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + abbrev_id, abbrev_text = @src[1], @src[2] + abbrev_text.strip! + if @root.options[:abbrev_defs][abbrev_id] + warning("Duplicate abbreviation ID '#{abbrev_id}' on line #{start_line_number} " \ + "- overwriting") + end + @tree.children << new_block_el(:eob, :abbrev_def) + @root.options[:abbrev_defs][abbrev_id] = abbrev_text + @root.options[:abbrev_attr][abbrev_id] = @tree.children.last + true + end + define_parser(:abbrev_definition, ABBREV_DEFINITION_START) + + # Correct abbreviation attributes. + def correct_abbreviations_attributes + @root.options[:abbrev_attr].keys.each do |k| + @root.options[:abbrev_attr][k] = @root.options[:abbrev_attr][k].attr + end + end + + # Replace the abbreviation text with elements. + def replace_abbreviations(el, regexps = nil) + return if @root.options[:abbrev_defs].empty? + unless regexps + sorted_abbrevs = @root.options[:abbrev_defs].keys.sort {|a, b| b.length <=> a.length } + regexps = [Regexp.union(*sorted_abbrevs.map do |k| + /#{Regexp.escape(k).gsub(/\\\s/, "[\\s\\p{Z}]+").force_encoding(Encoding::UTF_8)}/ + end)] + regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries + end + el.children.map! do |child| + if child.type == :text && el.options[:content_model] != :raw + if child.value.match?(regexps.first) + result = [] + strscan = Kramdown::Utils::StringScanner.new(child.value, child.options[:location]) + text_lineno = strscan.current_line_number + while (temp = strscan.scan_until(regexps.last)) + abbr_lineno = strscan.current_line_number + abbr = strscan.scan(regexps.first) # begin of line case of abbr with \W char as first one + if abbr.nil? + temp << strscan.scan(/\W|^/) + abbr = strscan.scan(regexps.first) + end + result << Element.new(:text, temp, nil, location: text_lineno) + result << Element.new(:abbreviation, abbr, nil, location: abbr_lineno) + text_lineno = strscan.current_line_number + end + result << Element.new(:text, strscan.rest, nil, location: text_lineno) + else + child + end + else + replace_abbreviations(child, regexps) + child + end + end.flatten! + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/autolink.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/autolink.rb new file mode 100644 index 00000000..5f0ccfd6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/autolink.rb @@ -0,0 +1,31 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ACHARS = '[[:alnum:]]-_.' + AUTOLINK_START_STR = "<((mailto|https?|ftps?):.+?|[#{ACHARS}]+?@[#{ACHARS}]+?)>" + AUTOLINK_START = /#{AUTOLINK_START_STR}/u + + # Parse the autolink at the current location. + def parse_autolink + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1]) + el = Element.new(:a, nil, {'href' => href}, location: start_line_number) + add_text(@src[1].sub(/^mailto:/, ''), el) + @tree.children << el + end + define_parser(:autolink, AUTOLINK_START, '<') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blank_line.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blank_line.rb new file mode 100644 index 00000000..0d62c32f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blank_line.rb @@ -0,0 +1,30 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + BLANK_LINE = /(?>^\s*\n)+/ + + # Parse the blank line at the current postition. + def parse_blank_line + @src.pos += @src.matched_size + if (last_child = @tree.children.last) && last_child.type == :blank + last_child.value << @src.matched + else + @tree.children << new_block_el(:blank, @src.matched) + end + true + end + define_parser(:blank_line, BLANK_LINE) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/block_boundary.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/block_boundary.rb new file mode 100644 index 00000000..bb642993 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/block_boundary.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|#{IAL_BLOCK_START}|\Z/ + + # Return +true+ if we are after a block boundary. + def after_block_boundary? + last_child = @tree.children.last + !last_child || last_child.type == :blank || + (last_child.type == :eob && last_child.value.nil?) || @block_ial + end + + # Return +true+ if we are before a block boundary. + def before_block_boundary? + @src.check(self.class::BLOCK_BOUNDARY) + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blockquote.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blockquote.rb new file mode 100644 index 00000000..3732b83c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/blockquote.rb @@ -0,0 +1,38 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' + +module Kramdown + module Parser + class Kramdown + + BLOCKQUOTE_START = /^#{OPT_SPACE}> ?/ + + # Parse the blockquote at the current location. + def parse_blockquote + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(self.class::LAZY_END) + result << @src.scan(PARAGRAPH_MATCH) + end + result.gsub!(BLOCKQUOTE_START, '') + + el = new_block_el(:blockquote, nil, nil, location: start_line_number) + @tree.children << el + parse_blocks(el, result) + true + end + define_parser(:blockquote, BLOCKQUOTE_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codeblock.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codeblock.rb new file mode 100644 index 00000000..89d20536 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codeblock.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/paragraph' + +module Kramdown + module Parser + class Kramdown + + CODEBLOCK_START = INDENT + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+(?:(?!#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START})^[ \t]*\S.*\n)*)*/ + + # Parse the indented codeblock at the current location. + def parse_codeblock + start_line_number = @src.current_line_number + data = @src.scan(self.class::CODEBLOCK_MATCH) + data.gsub!(/\n( {0,3}\S)/, ' \\1') + data.gsub!(INDENT, '') + @tree.children << new_block_el(:codeblock, data, nil, location: start_line_number) + true + end + define_parser(:codeblock, CODEBLOCK_START) + + FENCED_CODEBLOCK_START = /^~{3,}/ + FENCED_CODEBLOCK_MATCH = /^((~){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m + + # Parse the fenced codeblock at the current location. + def parse_codeblock_fenced + if @src.check(self.class::FENCED_CODEBLOCK_MATCH) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:codeblock, @src[5], nil, location: start_line_number, fenced: true) + lang = @src[3].to_s.strip + unless lang.empty? + el.options[:lang] = lang + el.attr['class'] = "language-#{@src[4]}" + end + @tree.children << el + true + else + false + end + end + define_parser(:codeblock_fenced, FENCED_CODEBLOCK_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codespan.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codespan.rb new file mode 100644 index 00000000..90321616 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/codespan.rb @@ -0,0 +1,58 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + CODESPAN_DELIMITER = /`+/ + + # Parse the codespan at the current scanner location. + def parse_codespan + start_line_number = @src.current_line_number + result = @src.scan(CODESPAN_DELIMITER) + simple = (result.length == 1) + saved_pos = @src.save_pos + + if simple && @src.pre_match =~ /\s\Z|\A\Z/ && @src.match?(/\s/) + add_text(result) + return + end + + # assign static regex to avoid allocating the same on every instance + # where +result+ equals a single-backtick. Interpolate otherwise. + if result == '`' + scan_pattern = /`/ + str_sub_pattern = /`\Z/ + else + scan_pattern = /#{result}/ + str_sub_pattern = /#{result}\Z/ + end + + if (text = @src.scan_until(scan_pattern)) + text.sub!(str_sub_pattern, '') + unless simple + text = text[1..-1] if text[0..0] == ' ' + text = text[0..-2] if text[-1..-1] == ' ' + end + @tree.children << Element.new(:codespan, text, nil, { + codespan_delimiter: result, + location: start_line_number, + }) + + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:codespan, CODESPAN_DELIMITER, '`') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/emphasis.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/emphasis.rb new file mode 100644 index 00000000..a69ab4a1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/emphasis.rb @@ -0,0 +1,66 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EMPHASIS_START = /(?:\*\*?|__?)/ + + # Parse the emphasis at the current location. + def parse_emphasis + start_line_number = @src.current_line_number + saved_pos = @src.save_pos + + result = @src.scan(EMPHASIS_START) + element = (result.length == 2 ? :strong : :em) + type = result[0..0] + + if (type == '_' && @src.pre_match =~ /[[:alpha:]]-?[[:alpha:]]*_*\z/) || @src.check(/\s/) || + @tree.type == element || @stack.any? {|el, _| el.type == element } + add_text(result) + return + end + + warnings_pos = @warnings.size + sub_parse = lambda do |delim, elem| + el = Element.new(elem, nil, nil, location: start_line_number) + stop_re = /#{Regexp.escape(delim)}/ + found = parse_spans(el, stop_re) do + (@src.pre_match[-1, 1] !~ /\s/) && + (elem != :em || !@src.match?(/#{Regexp.escape(delim * 2)}(?!#{Regexp.escape(delim)})/)) && + (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && !el.children.empty? + end + [found, el, stop_re] + end + + found, el, stop_re = sub_parse.call(result, element) + if !found && element == :strong && @tree.type != :em + @src.revert_pos(saved_pos) + @src.pos += 1 + found, el, stop_re = sub_parse.call(type, :em) + end + if found + # Useful for implementing underlines. + el.options[:char] = type + + @src.scan(stop_re) + @tree.children << el + else + @warnings.slice!(0...warnings_pos) + @src.revert_pos(saved_pos) + @src.pos += result.length + add_text(result) + end + end + define_parser(:emphasis, EMPHASIS_START, '\*|_') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/eob.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/eob.rb new file mode 100644 index 00000000..82a037a4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/eob.rb @@ -0,0 +1,26 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + EOB_MARKER = /^\^\s*?\n/ + + # Parse the EOB marker at the current location. + def parse_eob_marker + @src.pos += @src.matched_size + @tree.children << new_block_el(:eob) + true + end + define_parser(:eob_marker, EOB_MARKER) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/escaped_chars.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/escaped_chars.rb new file mode 100644 index 00000000..9c2066f7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/escaped_chars.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + ESCAPED_CHARS = /\\([\\.*_+`<>()\[\]{}#!:|"'$=-])/ + + # Parse the backslash-escaped character at the current location. + def parse_escaped_chars + @src.pos += @src.matched_size + add_text(@src[1]) + end + define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/extensions.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/extensions.rb new file mode 100644 index 00000000..92ac6205 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/extensions.rb @@ -0,0 +1,214 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + IAL_CLASS_ATTR = 'class' + + # Parse the string +str+ and extract all attributes and add all found attributes to the hash + # +opts+. + def parse_attribute_list(str, opts) + return if str.strip.empty? || str.strip == ':' + attrs = str.scan(ALD_TYPE_ANY) + attrs.each do |key, sep, val, ref, id_and_or_class, _, _| + if ref + (opts[:refs] ||= []) << ref + elsif id_and_or_class + id_and_or_class.scan(ALD_TYPE_ID_OR_CLASS).each do |id_attr, class_attr| + if class_attr + opts[IAL_CLASS_ATTR] = "#{opts[IAL_CLASS_ATTR]} #{class_attr}".lstrip + else + opts['id'] = id_attr + end + end + else + val.gsub!(/\\(\}|#{sep})/, "\\1") + opts[key] = val + end + end + warning("No or invalid attributes found in IAL/ALD content: #{str}") if attrs.empty? + end + + # Update the +ial+ with the information from the inline attribute list +opts+. + def update_ial_with_ial(ial, opts) + (ial[:refs] ||= []).concat(opts[:refs]) if opts.key?(:refs) + opts.each do |k, v| + if k == IAL_CLASS_ATTR + ial[k] = "#{ial[k]} #{v}".lstrip + elsif k.kind_of?(String) + ial[k] = v + end + end + end + + # Parse the generic extension at the current point. The parameter +type+ can either be :block + # or :span depending whether we parse a block or span extension tag. + def parse_extension_start_tag(type) + saved_pos = @src.save_pos + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + error_block = lambda do |msg| + warning(msg) + @src.revert_pos(saved_pos) + add_text(@src.getch) if type == :span + false + end + + if @src[4] || @src.matched == '{:/}' + name = (@src[4] ? "for '#{@src[4]}' " : '') + return error_block.call("Invalid extension stop tag #{name} found on line " \ + "#{start_line_number} - ignoring it") + end + + ext = @src[1] + opts = {} + body = nil + parse_attribute_list(@src[2] || '', opts) + + unless @src[3] + stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/) + if (result = @src.scan_until(stop_re)) + body = result.sub!(stop_re, '') + body.chomp! if type == :block + else + return error_block.call("No stop tag for extension '#{ext}' found on line " \ + "#{start_line_number} - ignoring it") + end + end + + if handle_extension(ext, opts, body, type, start_line_number) + true + else + error_block.call("Invalid extension with name '#{ext}' specified on line " \ + "#{start_line_number} - ignoring it") + end + end + + def handle_extension(name, opts, body, type, line_no = nil) + case name + when 'comment' + if body.kind_of?(String) + @tree.children << Element.new(:comment, body, nil, category: type, location: line_no) + end + true + when 'nomarkdown' + if body.kind_of?(String) + @tree.children << Element.new(:raw, body, nil, category: type, + location: line_no, type: opts['type'].to_s.split(/\s+/)) + end + true + when 'options' + opts.select do |k, v| + k = k.to_sym + if Kramdown::Options.defined?(k) + if @options[:forbidden_inline_options].include?(k) || + k == :forbidden_inline_options + warning("Option #{k} may not be set inline") + next false + end + + begin + val = Kramdown::Options.parse(k, v) + @options[k] = val + (@root.options[:options] ||= {})[k] = val + rescue StandardError + end + false + else + true + end + end.each do |k, _v| + warning("Unknown kramdown option '#{k}'") + end + @tree.children << new_block_el(:eob, :extension) if type == :block + true + else + false + end + end + + ALD_ID_CHARS = /[\w-]/ + ALD_ANY_CHARS = /\\\}|[^}]/ + ALD_ID_NAME = /\w#{ALD_ID_CHARS}*/ + ALD_CLASS_NAME = /[^\s.#]+/ + ALD_TYPE_KEY_VALUE_PAIR = /(#{ALD_ID_NAME})=("|')((?:\\\}|\\\2|[^}\2])*?)\2/ + ALD_TYPE_CLASS_NAME = /\.(#{ALD_CLASS_NAME})/ + ALD_TYPE_ID_NAME = /#([A-Za-z][\w:-]*)/ + ALD_TYPE_ID_OR_CLASS = /#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME}/ + ALD_TYPE_ID_OR_CLASS_MULTI = /((?:#{ALD_TYPE_ID_NAME}|#{ALD_TYPE_CLASS_NAME})+)/ + ALD_TYPE_REF = /(#{ALD_ID_NAME})/ + ALD_TYPE_ANY = /(?:\A|\s)(?:#{ALD_TYPE_KEY_VALUE_PAIR}|#{ALD_TYPE_REF}|#{ALD_TYPE_ID_OR_CLASS_MULTI})(?=\s|\Z)/ + ALD_START = /^#{OPT_SPACE}\{:(#{ALD_ID_NAME}):(#{ALD_ANY_CHARS}+)\}\s*?\n/ + + EXT_STOP_STR = "\\{:/(%s)?\\}" + EXT_START_STR = "\\{::(\\w+)(?:\\s(#{ALD_ANY_CHARS}*?)|)(\\/)?\\}" + EXT_BLOCK_START = /^#{OPT_SPACE}(?:#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME})\s*?\n/ + EXT_BLOCK_STOP_STR = "^#{OPT_SPACE}#{EXT_STOP_STR}\s*?\n" + + IAL_BLOCK = /\{:(?!:|\/)(#{ALD_ANY_CHARS}+)\}\s*?\n/ + IAL_BLOCK_START = /^#{OPT_SPACE}#{IAL_BLOCK}/ + + BLOCK_EXTENSIONS_START = /^#{OPT_SPACE}\{:/ + + # Parse one of the block extensions (ALD, block IAL or generic extension) at the current + # location. + def parse_block_extensions + if @src.scan(ALD_START) + parse_attribute_list(@src[2], @alds[@src[1]] ||= {}) + @tree.children << new_block_el(:eob, :ald) + true + elsif @src.check(EXT_BLOCK_START) + parse_extension_start_tag(:block) + elsif @src.scan(IAL_BLOCK_START) + if (last_child = @tree.children.last) && last_child.type != :blank && + (last_child.type != :eob || + [:link_def, :abbrev_def, :footnote_def].include?(last_child.value)) + parse_attribute_list(@src[1], last_child.options[:ial] ||= {}) + @tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START) + else + parse_attribute_list(@src[1], @block_ial ||= {}) + end + true + else + false + end + end + define_parser(:block_extensions, BLOCK_EXTENSIONS_START) + + EXT_SPAN_START = /#{EXT_START_STR}|#{EXT_STOP_STR % ALD_ID_NAME}/ + IAL_SPAN_START = /\{:(#{ALD_ANY_CHARS}+)\}/ + SPAN_EXTENSIONS_START = /\{:/ + + # Parse the extension span at the current location. + def parse_span_extensions + if @src.check(EXT_SPAN_START) + parse_extension_start_tag(:span) + elsif @src.check(IAL_SPAN_START) + if (last_child = @tree.children.last) && last_child.type != :text + @src.pos += @src.matched_size + attr = {} + parse_attribute_list(@src[1], attr) + update_ial_with_ial(last_child.options[:ial] ||= {}, attr) + update_attr_with_ial(last_child.attr, attr) + else + warning("Found span IAL after text - ignoring it") + add_text(@src.getch) + end + else + add_text(@src.getch) + end + end + define_parser(:span_extensions, SPAN_EXTENSIONS_START, '\{:') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/footnote.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/footnote.rb new file mode 100644 index 00000000..cf1dc922 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/footnote.rb @@ -0,0 +1,64 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/codeblock' + +module Kramdown + module Parser + class Kramdown + + FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/ + + # Parse the foot note definition at the current location. + def parse_footnote_definition + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + + el = Element.new(:footnote_def, nil, nil, location: start_line_number) + parse_blocks(el, @src[2].gsub(INDENT, '')) + if @footnotes[@src[1]] + warning("Duplicate footnote name '#{@src[1]}' on line #{start_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :footnote_def) + (@footnotes[@src[1]] = {})[:content] = el + @footnotes[@src[1]][:eob] = @tree.children.last + true + end + define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START) + + FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/ + + # Parse the footnote marker at the current location. + def parse_footnote_marker + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + fn_def = @footnotes[@src[1]] + if fn_def + if fn_def[:eob] + update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {}) + fn_def[:attr] = fn_def[:eob].attr + fn_def[:options] = fn_def[:eob].options + fn_def.delete(:eob) + end + fn_def[:marker] ||= [] + fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr], + fn_def[:options].merge(name: @src[1], location: start_line_number))) + @tree.children << fn_def[:marker].last + else + warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}") + add_text(@src.matched) + end + end + define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/header.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/header.rb new file mode 100644 index 00000000..8424af34 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/header.rb @@ -0,0 +1,70 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' +require 'rexml/xmltokens' + +module Kramdown + module Parser + class Kramdown + + SETEXT_HEADER_START = /^#{OPT_SPACE}(?[^ \t].*)\n(?[-=])[-=]*[ \t\r\f\v]*\n/ + + # Parse the Setext header at the current location. + def parse_setext_header + return false unless after_block_boundary? + text, id = parse_header_contents + return false if text.empty? + add_header(@src["level"] == '-' ? 2 : 1, text, id) + true + end + define_parser(:setext_header, SETEXT_HEADER_START) + + ATX_HEADER_START = /^(?\#{1,6})[\t ]*(?[^ \t].*)\n/ + + # Parse the Atx header at the current location. + def parse_atx_header + return false unless after_block_boundary? + text, id = parse_header_contents + text.sub!(/(?#{REXML::XMLTokens::NAME_START_CHAR}#{REXML::XMLTokens::NAME_CHAR}*)}\z/ + + # Returns header text and optional ID. + def parse_header_contents + text = @src["contents"] + text.rstrip! + id_match = HEADER_ID.match(text) + if id_match + id = id_match["id"] + text = text[0...-id_match[0].length] + text.rstrip! + end + [text, id] + end + + def add_header(level, text, id) + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + el = new_block_el(:header, nil, nil, level: level, raw_text: text, location: start_line_number) + add_text(text, el) + el.attr['id'] = id if id + @tree.children << el + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/horizontal_rule.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/horizontal_rule.rb new file mode 100644 index 00000000..f2aa6a40 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/horizontal_rule.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + HR_START = /^#{OPT_SPACE}(\*|-|_)[ \t]*\1[ \t]*\1(\1|[ \t])*\n/ + + # Parse the horizontal rule at the current location. + def parse_horizontal_rule + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << new_block_el(:hr, nil, nil, location: start_line_number) + true + end + define_parser(:horizontal_rule, HR_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html.rb new file mode 100644 index 00000000..37e6b4c0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html.rb @@ -0,0 +1,165 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + include Kramdown::Parser::Html::Parser + include Kramdown::Utils::Html + + # Mapping of markdown attribute value to content model. I.e. :raw when "0", :default when "1" + # (use default content model for the HTML element), :span when "span", :block when block and + # for everything else +nil+ is returned. + HTML_MARKDOWN_ATTR_MAP = {"0" => :raw, "1" => :default, "span" => :span, "block" => :block} + + TRAILING_WHITESPACE = /[ \t]*\n/ + + def handle_kramdown_html_tag(el, closed, handle_body) + if @block_ial + el.options[:ial] = @block_ial + @block_ial = nil + end + + content_model = if @tree.type != :html_element || @tree.options[:content_model] != :raw + (@options[:parse_block_html] ? HTML_CONTENT_MODEL[el.value] : :raw) + else + :raw + end + if (val = HTML_MARKDOWN_ATTR_MAP[el.attr.delete('markdown')]) + content_model = (val == :default ? HTML_CONTENT_MODEL[el.value] : val) + end + + @src.scan(TRAILING_WHITESPACE) if content_model == :block + el.options[:content_model] = content_model + el.options[:is_closed] = closed + + if !closed && handle_body + case content_model + when :block + unless parse_blocks(el) + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + when :span + curpos = @src.pos + if @src.scan_until(/(?=<\/#{el.value}\s*>)/mi) + add_text(extract_string(curpos...@src.pos, @src), el) + @src.scan(HTML_TAG_CLOSE_RE) + else + add_text(@src.rest, el) + @src.terminate + warning("Found no end tag for '#{el.value}' (line #{el.options[:location]}) - auto-closing it") + end + else + parse_raw_html(el) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + end + unless @tree.type == :html_element && @tree.options[:content_model] == :raw + @src.scan(TRAILING_WHITESPACE) + end + end + end + + HTML_BLOCK_START = /^#{OPT_SPACE}<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/)/ + + # Parse the HTML at the current position as block-level HTML. + def parse_block_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :block, location: line) + @src.scan(TRAILING_WHITESPACE) + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + @src.pos += @src.matched_size + handle_html_start_tag(line) {|iel, ic, ih| handle_kramdown_html_tag(iel, ic, ih) } + Kramdown::Parser::Html::ElementConverter.convert(@root, @tree.children.last) if @options[:html_to_native] + true + elsif @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/o) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase) + name = @src[1].downcase + + if @tree.type == :html_element && @tree.value == name + @src.pos += @src.matched_size + throw :stop_block_parsing, :found + else + false + end + else + false + end + end + define_parser(:block_html, HTML_BLOCK_START) + + HTML_SPAN_START = /<(#{REXML::Parsers::BaseParser::UNAME_STR}|!--|\/|!\[CDATA\[)/ + + # Parse the HTML at the current position as span-level HTML. + def parse_span_html + line = @src.current_line_number + if (result = @src.scan(HTML_COMMENT_RE)) + @tree.children << Element.new(:xml_comment, result, nil, category: :span, location: line) + elsif @src.scan(HTML_CDATA_RE) + add_text(escape_html(@src[1])) + elsif (result = @src.scan(HTML_TAG_CLOSE_RE)) + warning("Found invalidly used HTML closing tag for '#{@src[1]}' on line #{line}") + add_text(result) + elsif (result = @src.scan(HTML_TAG_RE)) + tag_name = @src[1] + tag_name.downcase! if HTML_ELEMENT[tag_name.downcase] + if HTML_BLOCK_ELEMENTS.include?(tag_name) + warning("Found block HTML tag '#{tag_name}' in span-level text on line #{line}") + add_text(result) + return + end + + attrs = parse_html_attributes(@src[2], line, HTML_ELEMENT[tag_name]) + attrs.each_value {|value| value.gsub!(/\n+/, ' ') unless value.empty? } + + do_parsing = if HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw + false + else + @options[:parse_span_html] + end + if (val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')]) + case val + when :block + warning("Cannot use block-level parsing in span-level HTML tag (line #{line}) " \ + "- using default mode") + when :span + do_parsing = true + when :default + do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw + when :raw + do_parsing = false + end + end + + el = Element.new(:html_element, tag_name, attrs, category: :span, location: line, + content_model: (do_parsing ? :span : :raw), is_closed: !@src[4].nil?) + @tree.children << el + stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/ + stop_re = Regexp.new(stop_re.source, Regexp::IGNORECASE) if HTML_ELEMENT[tag_name] + if !@src[4] && !HTML_ELEMENTS_WITHOUT_BODY.include?(el.value) + if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html])) + @src.scan(stop_re) + else + warning("Found no end tag for '#{el.value}' (line #{line}) - auto-closing it") + add_text(@src.rest, el) + @src.terminate + end + end + Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native] + else + add_text(@src.getch) + end + end + define_parser(:span_html, HTML_SPAN_START, '<') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html_entity.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html_entity.rb new file mode 100644 index 00000000..dc5e7ada --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/html_entity.rb @@ -0,0 +1,34 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/html' + +module Kramdown + module Parser + class Kramdown + + # Parse the HTML entity at the current location. + def parse_html_entity + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + begin + value = ::Kramdown::Utils::Entities.entity(@src[1] || @src[2]&.to_i || @src[3].hex) + @tree.children << Element.new(:entity, value, + nil, original: @src.matched, location: start_line_number) + rescue ::Kramdown::Error + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'), + nil, location: start_line_number) + add_text(@src.matched[1..-1]) + end + end + define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/line_break.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/line_break.rb new file mode 100644 index 00000000..021bb0ac --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/line_break.rb @@ -0,0 +1,25 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + LINE_BREAK = /( |\\\\)(?=\n)/ + + # Parse the line break at the current location. + def parse_line_break + @tree.children << Element.new(:br, nil, nil, location: @src.current_line_number) + @src.pos += @src.matched_size + end + define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/link.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/link.rb new file mode 100644 index 00000000..f4664f30 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/link.rb @@ -0,0 +1,149 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/escaped_chars' + +module Kramdown + module Parser + class Kramdown + + # Normalize the link identifier. + def normalize_link_id(id) + id.gsub(/\s+/, ' ').downcase + end + + LINK_DEFINITION_START = /^#{OPT_SPACE}\[([^\n\]]+)\]:[ \t]*(?:<(.*?)>|([^\n]*?\S[^\n]*?))(?:(?:[ \t]*?\n|[ \t]+?)[ \t]*?(["'])(.+?)\4)?[ \t]*?\n/ + + # Parse the link definition at the current location. + def parse_link_definition + return false if @src[3].to_s.match?(/[ \t]+["']/) + @src.pos += @src.matched_size + link_id, link_url, link_title = normalize_link_id(@src[1]), @src[2] || @src[3], @src[5] + if @link_defs[link_id] + warning("Duplicate link ID '#{link_id}' on line #{@src.current_line_number} - overwriting") + end + @tree.children << new_block_el(:eob, :link_def) + @link_defs[link_id] = [link_url, link_title, @tree.children.last] + true + end + define_parser(:link_definition, LINK_DEFINITION_START) + + # This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+ + # and the element itself to the @tree. + def add_link(el, href, title, alt_text = nil, ial = nil) + el.options[:ial] = ial + update_attr_with_ial(el.attr, ial) if ial + if el.type == :a + el.attr['href'] = href + else + el.attr['src'] = href + el.attr['alt'] = alt_text + el.children.clear + end + el.attr['title'] = title if title + @tree.children << el + end + + LINK_BRACKET_STOP_RE = /(\])|!?\[/ + LINK_PAREN_STOP_RE = /(\()|(\))|\s(?=['"])/ + LINK_INLINE_ID_RE = /\s*?\[([^\]]+)?\]/ + LINK_INLINE_TITLE_RE = /\s*?(["'])(.+?)\1\s*?\)/m + LINK_START = /!?\[(?=[^^])/ + + # Parse the link at the current scanner position. This method is used to parse normal links as + # well as image links. + def parse_link + start_line_number = @src.current_line_number + result = @src.scan(LINK_START) + cur_pos = @src.pos + saved_pos = @src.save_pos + + link_type = (result.match?(/^!/) ? :img : :a) + + # no nested links allowed + if link_type == :a && (@tree.type == :img || @tree.type == :a || + @stack.any? {|t, _| t && (t.type == :img || t.type == :a) }) + add_text(result) + return + end + el = Element.new(link_type, nil, nil, location: start_line_number) + + count = 1 + found = parse_spans(el, LINK_BRACKET_STOP_RE) do + count += (@src[1] ? -1 : 1) + count - el.children.count {|c| c.type == :img } == 0 + end + unless found + @src.revert_pos(saved_pos) + add_text(result) + return + end + alt_text = extract_string(cur_pos...@src.pos, @src).gsub(ESCAPED_CHARS, '\1') + @src.scan(LINK_BRACKET_STOP_RE) + + # reference style link or no link url + if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/) + emit_warning = !@src[1] + link_id = normalize_link_id(@src[1] || alt_text) + if @link_defs.key?(link_id) + link_def = @link_defs[link_id] + add_link(el, link_def[0], link_def[1], alt_text, + link_def[2] && link_def[2].options[:ial]) + else + if emit_warning + warning("No link definition for link ID '#{link_id}' found on line #{start_line_number}") + end + @src.revert_pos(saved_pos) + add_text(result) + end + return + end + + # link url in parentheses + if @src.scan(/\(<(.*?)>/) + link_url = @src[1] + if @src.scan(/\)/) + add_link(el, link_url, nil, alt_text) + return + end + else + link_url = +'' + nr_of_brackets = 0 + while (temp = @src.scan_until(LINK_PAREN_STOP_RE)) + link_url << temp + if @src[2] + nr_of_brackets -= 1 + break if nr_of_brackets == 0 + elsif @src[1] + nr_of_brackets += 1 + else + break + end + end + link_url = link_url[1..-2] + link_url.strip! + + if nr_of_brackets == 0 + add_link(el, link_url, nil, alt_text) + return + end + end + + if @src.scan(LINK_INLINE_TITLE_RE) + add_link(el, link_url, @src[2], alt_text) + else + @src.revert_pos(saved_pos) + add_text(result) + end + end + define_parser(:link, LINK_START, '!?\[') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/list.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/list.rb new file mode 100644 index 00000000..3db5409f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/list.rb @@ -0,0 +1,286 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/horizontal_rule' +require 'kramdown/parser/kramdown/extensions' + +module Kramdown + module Parser + class Kramdown + + LIST_ITEM_IAL = /^\s*(?:\{:(?!(?:#{ALD_ID_NAME})?:|\/)(#{ALD_ANY_CHARS}+)\})\s*/ + LIST_ITEM_IAL_CHECK = /^#{LIST_ITEM_IAL}?\s*\n/ + + PARSE_FIRST_LIST_LINE_REGEXP_CACHE = Hash.new do |h, indentation| + indent_re = /^ {#{indentation}}/ + content_re = /^(?:(?:\t| {4}){#{indentation / 4}} {#{indentation % 4}}|(?:\t| {4}){#{indentation / 4 + 1}}).*\S.*\n/ + lazy_re = /(?!^ {0,#{[indentation, 3].min}}(?:#{IAL_BLOCK}|#{LAZY_END_HTML_STOP}|#{LAZY_END_HTML_START})).*\S.*\n/ + + h[indentation] = [content_re, lazy_re, indent_re] + end + + # Used for parsing the first line of a list item or a definition, i.e. the line with list item + # marker or the definition marker. + def parse_first_list_line(indentation, content) + if content.match?(self.class::LIST_ITEM_IAL_CHECK) + indentation = 4 + else + while content.match?(/^ *\t/) + temp = content.scan(/^ */).first.length + indentation + content.sub!(/^( *)(\t+)/) { $1 << " " * (4 - (temp % 4) + ($2.length - 1) * 4) } + end + indentation += content[/^ */].length + end + content.sub!(/^\s*/, '') + + [content, indentation, *PARSE_FIRST_LIST_LINE_REGEXP_CACHE[indentation]] + end + + PATTERN_TAIL = /[\t| ].*?\n/ + + LIST_START_UL = /^(#{OPT_SPACE}[+*-])(#{PATTERN_TAIL})/ + LIST_START_OL = /^(#{OPT_SPACE}\d+\.)(#{PATTERN_TAIL})/ + LIST_START = /#{LIST_START_UL}|#{LIST_START_OL}/ + + # Parse the ordered or unordered list at the current location. + def parse_list + start_line_number = @src.current_line_number + type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL]) + list = new_block_el(type, nil, nil, location: start_line_number) + + item = nil + content_re, lazy_re, indent_re = nil + eob_found = false + nested_list_found = false + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if last_is_blank && @src.check(HR_START) + break + elsif @src.scan(EOB_MARKER) + eob_found = true + break + elsif @src.scan(list_start_re) + list.options[:first_list_marker] ||= @src[1].strip + item = Element.new(:li, nil, nil, location: start_line_number) + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + list.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + list_start_re = fetch_pattern(type, indentation) + nested_list_found = (item.value =~ LIST_START) + last_is_blank = false + item.value = [item.value] + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * 4 * $1.length } + indentation_found = result.sub!(indent_re, '') + if !nested_list_found && indentation_found && result =~ LIST_START + item.value << +'' + nested_list_found = true + elsif nested_list_found && !indentation_found && result =~ LIST_START + result = " " * (indentation + 4) << result + end + item.value.last << result + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + nested_list_found = true + last_is_blank = true + item.value.last << result + else + break + end + end + + @tree.children << list + + last = nil + list.children.each do |it| + temp = Element.new(:temp, nil, nil, location: it.options[:location]) + + env = save_env + location = it.options[:location] + it.value.each do |val| + @src = ::Kramdown::Utils::StringScanner.new(val, location) + parse_blocks(temp) + location = @src.current_line_number + end + restore_env(env) + + it.children = temp.children + it.value = nil + + it_children = it.children + next if it_children.empty? + + # Handle the case where an EOB marker is inserted by a block IAL for the first paragraph + it_children.delete_at(1) if it_children.first.type == :p && + it_children.length >= 2 && it_children[1].type == :eob && it_children.first.options[:ial] + + if it_children.first.type == :p && + (it_children.length < 2 || it_children[1].type != :blank || + (it == list.children.last && it_children.length == 2 && !eob_found)) && + (list.children.last != it || list.children.size == 1 || + list.children[0..-2].any? {|cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] }) + it_children.first.children.first.value << "\n" if it_children.size > 1 && it_children[1].type != :blank + it_children.first.options[:transparent] = true + end + + last = (it_children.last.type == :blank ? it_children.pop : nil) + end + + @tree.children << last if !last.nil? && !eob_found + + true + end + define_parser(:list, LIST_START) + + DEFINITION_LIST_START = /^(#{OPT_SPACE}:)(#{PATTERN_TAIL})/ + + # Parse the ordered or unordered list at the current location. + def parse_definition_list + children = @tree.children + if !children.last || (children.length == 1 && children.last.type != :p) || + (children.length >= 2 && children[-1].type != :p && + (children[-1].type != :blank || children[-1].value != "\n" || children[-2].type != :p)) + return false + end + + first_as_para = false + deflist = new_block_el(:dl) + para = @tree.children.pop + if para.type == :blank + para = @tree.children.pop + first_as_para = true + end + # take location from preceding para which is the first definition term + deflist.options[:location] = para.options[:location] + para.children.first.value.split("\n").each do |term| + el = Element.new(:dt, nil, nil, location: @src.current_line_number) + term.sub!(self.class::LIST_ITEM_IAL) do + parse_attribute_list($1, el.options[:ial] ||= {}) + '' + end + el.options[:raw_text] = term + el.children << Element.new(:raw_text, term) + deflist.children << el + end + deflist.options[:ial] = para.options[:ial] + + item = nil + content_re, lazy_re, indent_re = nil + def_start_re = DEFINITION_LIST_START + last_is_blank = false + until @src.eos? + start_line_number = @src.current_line_number + if @src.scan(def_start_re) + item = Element.new(:dd, nil, nil, location: start_line_number) + item.options[:first_as_para] = first_as_para + item.value, indentation, content_re, lazy_re, indent_re = + parse_first_list_line(@src[1].length, @src[2]) + deflist.children << item + + item.value.sub!(self.class::LIST_ITEM_IAL) do |_match| + parse_attribute_list($1, item.options[:ial] ||= {}) + '' + end + + def_start_re = fetch_pattern(:dl, indentation) + first_as_para = false + last_is_blank = false + elsif @src.check(EOB_MARKER) + break + elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re))) + result.sub!(/^(\t+)/) { " " * ($1 ? 4 * $1.length : 0) } + result.sub!(indent_re, '') + item.value << result + first_as_para = false + last_is_blank = false + elsif (result = @src.scan(BLANK_LINE)) + first_as_para = true + item.value << result + last_is_blank = true + else + break + end + end + + last = nil + deflist.children.each do |it| + next if it.type == :dt + + parse_blocks(it, it.value) + it.value = nil + it_children = it.children + next if it_children.empty? + + last = (it_children.last.type == :blank ? it_children.pop : nil) + + if it_children.first && it_children.first.type == :p && !it.options.delete(:first_as_para) + it_children.first.children.first.value << "\n" if it_children.size > 1 + it_children.first.options[:transparent] = true + end + end + + children = @tree.children + if children.length >= 1 && children.last.type == :dl + children[-1].children.concat(deflist.children) + elsif children.length >= 2 && children[-1].type == :blank && + children[-2].type == :dl + children.pop + children[-1].children.concat(deflist.children) + else + children << deflist + end + + children << last if last + + true + end + define_parser(:definition_list, DEFINITION_LIST_START) + + private + + # precomputed patterns for indentations 1..4 and fallback expression + # to compute pattern when indentation is outside the 1..4 range. + def fetch_pattern(type, indentation) + case type + when :ul + case indentation + when 1 then /^( {0}[+*-])(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}[+*-])(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}[+*-])(#{PATTERN_TAIL})/o + else /^( {0,3}[+*-])(#{PATTERN_TAIL})/o + end + when :ol + case indentation + when 1 then /^( {0}\d+\.)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}\d+\.)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}\d+\.)(#{PATTERN_TAIL})/o + else /^( {0,3}\d+\.)(#{PATTERN_TAIL})/o + end + when :dl + case indentation + when 1 then /^( {0}:)(#{PATTERN_TAIL})/o + when 2 then /^( {0,1}:)(#{PATTERN_TAIL})/o + when 3 then /^( {0,2}:)(#{PATTERN_TAIL})/o + else /^( {0,3}:)(#{PATTERN_TAIL})/o + end + end + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/math.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/math.rb new file mode 100644 index 00000000..7812292f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/math.rb @@ -0,0 +1,53 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + BLOCK_MATH_START = /^#{OPT_SPACE}(\\)?\$\$(.*?)\$\$(\s*?\n)?/m + + # Parse the math block at the current location. + def parse_block_math + start_line_number = @src.current_line_number + if !after_block_boundary? + return false + elsif @src[1] + @src.scan(/^#{OPT_SPACE}\\/o) if @src[3] + return false + end + + saved_pos = @src.save_pos + @src.pos += @src.matched_size + data = @src[2].strip + if before_block_boundary? + @tree.children << new_block_el(:math, data, nil, category: :block, location: start_line_number) + true + else + @src.revert_pos(saved_pos) + false + end + end + define_parser(:block_math, BLOCK_MATH_START) + + INLINE_MATH_START = /\$\$(.*?)\$\$/m + + # Parse the inline math at the current location. + def parse_inline_math + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + @tree.children << Element.new(:math, @src[1].strip, nil, category: :span, location: start_line_number) + end + define_parser(:inline_math, INLINE_MATH_START, '\$') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/paragraph.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/paragraph.rb new file mode 100644 index 00000000..f6af5ceb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/paragraph.rb @@ -0,0 +1,62 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/blank_line' +require 'kramdown/parser/kramdown/extensions' +require 'kramdown/parser/kramdown/eob' +require 'kramdown/parser/kramdown/list' +require 'kramdown/parser/kramdown/html' + +module Kramdown + module Parser + class Kramdown + + LAZY_END_HTML_SPAN_ELEMENTS = HTML_SPAN_ELEMENTS + %w[script] + LAZY_END_HTML_START = /<(?>(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR})/ + LAZY_END_HTML_STOP = /<\/(?!(?:#{LAZY_END_HTML_SPAN_ELEMENTS.join('|')})\b)#{REXML::Parsers::BaseParser::UNAME_STR}\s*>/m + + LAZY_END = /#{BLANK_LINE}|#{IAL_BLOCK_START}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}|^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/ + + PARAGRAPH_START = /^#{OPT_SPACE}[^ \t].*?\n/ + PARAGRAPH_MATCH = /^.*?\n/ + PARAGRAPH_END = /#{LAZY_END}|#{DEFINITION_LIST_START}/ + + # Parse the paragraph at the current location. + def parse_paragraph + pos = @src.pos + start_line_number = @src.current_line_number + result = @src.scan(PARAGRAPH_MATCH) + until @src.match?(paragraph_end) + result << @src.scan(PARAGRAPH_MATCH) + end + result.rstrip! + if (last_child = @tree.children.last) && last_child.type == :p + last_item_in_para = last_child.children.last + if last_item_in_para && last_item_in_para.type == @text_type + joiner = (extract_string((pos - 3)...pos, @src) == " \n" ? " \n" : "\n") + last_item_in_para.value << joiner << result + else + add_text(result, last_child) + end + else + @tree.children << new_block_el(:p, nil, nil, location: start_line_number) + result.lstrip! + add_text(result, @tree.children.last) + end + true + end + define_parser(:paragraph, PARAGRAPH_START) + + def paragraph_end + self.class::PARAGRAPH_END + end + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/smart_quotes.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/smart_quotes.rb new file mode 100644 index 00000000..3a9026aa --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/smart_quotes.rb @@ -0,0 +1,174 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +#-- +# Parts of this file are based on code from RubyPants: +# +# = RubyPants -- SmartyPants ported to Ruby +# +# Ported by Christian Neukirchen +# Copyright (C) 2004 Christian Neukirchen +# +# Incooporates ideas, comments and documentation by Chad Miller +# Copyright (C) 2004 Chad Miller +# +# Original SmartyPants by John Gruber +# Copyright (C) 2003 John Gruber +# +# +# = RubyPants -- SmartyPants ported to Ruby +# +# +# [snip] +# +# == Authors +# +# John Gruber did all of the hard work of writing this software in +# Perl for Movable Type and almost all of this useful documentation. +# Chad Miller ported it to Python to use with Pyblosxom. +# +# Christian Neukirchen provided the Ruby port, as a general-purpose +# library that follows the *Cloth API. +# +# +# == Copyright and License +# +# === SmartyPants license: +# +# Copyright (c) 2003 John Gruber +# (http://daringfireball.net) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name "SmartyPants" nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# === RubyPants license +# +# RubyPants is a derivative work of SmartyPants and smartypants.py. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# This software is provided by the copyright holders and contributors +# "as is" and any express or implied warranties, including, but not +# limited to, the implied warranties of merchantability and fitness +# for a particular purpose are disclaimed. In no event shall the +# copyright owner or contributors be liable for any direct, indirect, +# incidental, special, exemplary, or consequential damages (including, +# but not limited to, procurement of substitute goods or services; +# loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict +# liability, or tort (including negligence or otherwise) arising in +# any way out of the use of this software, even if advised of the +# possibility of such damage. +# +# == Links +# +# John Gruber:: http://daringfireball.net +# SmartyPants:: http://daringfireball.net/projects/smartypants +# +# Chad Miller:: http://web.chad.org +# +# Christian Neukirchen:: http://kronavita.de/chris +# +#++ +# + +module Kramdown + module Parser + class Kramdown + + SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]' + SQ_CLOSE = %![^ \\\\\t\r\n\\[{(-]! + + SQ_RULES = [ + [/("|')(?=[_*]{1,2}\S)/, [:lquote1]], + [/("|')(?=#{SQ_PUNCT}(?!\.\.)\B)/, [:rquote1]], + # Special case for double sets of quotes, e.g.: + #

He said, "'Quoted' words in a larger quote."

+ [/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]], + [/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]], + # Special case for decade abbreviations (the '80s): + [/(\s?)'(?=\d\ds)/, [1, :rsquo]], + + # Get most opening single/double quotes: + [/(\s)('|")(?=\w)/, [1, :lquote2]], + # Single/double closing quotes: + [/(#{SQ_CLOSE})('|")/, [1, :rquote2]], + # Special case for e.g. "Custer's Last Stand." + [/("|')(?=\s|s\b|$)/, [:rquote1]], + # Any remaining single quotes should be opening ones: + [/(.?)'/m, [1, :lsquo]], + [/(.?)"/m, [1, :ldquo]], + ] # '" + + SQ_SUBSTS = { + [:rquote1, '"'] => :rdquo, + [:rquote1, "'"] => :rsquo, + [:rquote2, '"'] => :rdquo, + [:rquote2, "'"] => :rsquo, + [:lquote1, '"'] => :ldquo, + [:lquote1, "'"] => :lsquo, + [:lquote2, '"'] => :ldquo, + [:lquote2, "'"] => :lsquo, + } + SMART_QUOTES_RE = /[^\\]?["']/ + + # Parse the smart quotes at current location. + def parse_smart_quotes + start_line_number = @src.current_line_number + substs = SQ_RULES.find {|reg, _subst| @src.scan(reg) }[1] + substs.each do |subst| + if subst.kind_of?(Integer) + add_text(@src[subst]) + else + val = SQ_SUBSTS[[subst, @src[subst.to_s[-1, 1].to_i]]] || subst + @tree.children << Element.new(:smart_quote, val, nil, location: start_line_number) + end + end + end + define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/table.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/table.rb new file mode 100644 index 00000000..53103ce9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/table.rb @@ -0,0 +1,171 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser/kramdown/block_boundary' + +module Kramdown + module Parser + class Kramdown + + TABLE_SEP_LINE = /^([+|: \t-]*?-[+|: \t-]*?)[ \t]*\n/ + TABLE_HSEP_ALIGN = /[ \t]?(:?)-+(:?)[ \t]?/ + TABLE_FSEP_LINE = /^[+|: \t=]*?=[+|: \t=]*?[ \t]*\n/ + TABLE_ROW_LINE = /^(.*?)[ \t]*\n/ + TABLE_PIPE_CHECK = /(?:\||.*?[^\\\n]\|)/ + TABLE_LINE = /#{TABLE_PIPE_CHECK}.*?\n/ + TABLE_START = /^#{OPT_SPACE}(?=\S)#{TABLE_LINE}/ + + # Parse the table at the current location. + def parse_table + return false unless after_block_boundary? + + saved_pos = @src.save_pos + orig_pos = @src.pos + table = new_block_el(:table, nil, nil, alignment: [], location: @src.current_line_number) + leading_pipe = (@src.check(TABLE_LINE) =~ /^\s*\|/) + @src.scan(TABLE_SEP_LINE) + + rows = [] + has_footer = false + columns = 0 + + add_container = lambda do |type, force| + if !has_footer || type != :tbody || force + cont = Element.new(type) + cont.children, rows = rows, [] + table.children << cont + end + end + + until @src.eos? + break unless @src.check(TABLE_LINE) + if @src.scan(TABLE_SEP_LINE) + if rows.empty? + # nothing to do, ignoring multiple consecutive separator lines + elsif table.options[:alignment].empty? && !has_footer + add_container.call(:thead, false) + table.options[:alignment] = @src[1].scan(TABLE_HSEP_ALIGN).map do |left, right| + (left.empty? && right.empty? && :default) || (right.empty? && :left) || + (left.empty? && :right) || :center + end + else # treat as normal separator line + add_container.call(:tbody, false) + end + elsif @src.scan(TABLE_FSEP_LINE) + add_container.call(:tbody, true) unless rows.empty? + has_footer = true + elsif @src.scan(TABLE_ROW_LINE) + trow = Element.new(:tr) + + # parse possible code spans on the line and correctly split the line into cells + env = save_env + cells = [] + @src[1].split(/(.*?<\/code>)/).each_with_index do |str, i| + if i.odd? + (cells.empty? ? cells : cells.last) << str + else + reset_env(src: Kramdown::Utils::StringScanner.new(str, @src.current_line_number)) + root = Element.new(:root) + parse_spans(root, nil, [:codespan]) + + root.children.each do |c| + if c.type == :raw_text + f, *l = c.value.split(/(? 1}#{c.value}#{' ' if delim.size > 1}#{delim}" + (cells.empty? ? cells : cells.last) << tmp + end + end + end + end + restore_env(env) + + cells.shift if leading_pipe && cells.first.strip.empty? + cells.pop if cells.last.strip.empty? + cells.each do |cell_text| + tcell = Element.new(:td) + tcell.children << Element.new(:raw_text, cell_text.strip) + trow.children << tcell + end + columns = [columns, cells.length].max + rows << trow + else + break + end + end + + unless before_block_boundary? + @src.revert_pos(saved_pos) + return false + end + + # Parse all lines of the table with the code span parser + env = save_env + l_src = ::Kramdown::Utils::StringScanner.new(extract_string(orig_pos...(@src.pos - 1), @src), + @src.current_line_number) + reset_env(src: l_src) + root = Element.new(:root) + parse_spans(root, nil, [:codespan, :span_html]) + restore_env(env) + + # Check if each line has at least one unescaped pipe that is not inside a code span/code + # HTML element + # Note: It doesn't matter that we parse *all* span HTML elements because the row splitting + # algorithm above only takes elements into account! + pipe_on_line = false + while (c = root.children.shift) + next unless (lines = c.value) + lines = lines.split("\n") + if c.type == :codespan + if lines.size > 2 || (lines.size == 2 && !pipe_on_line) + break + elsif lines.size == 2 && pipe_on_line + pipe_on_line = false + end + else + break if lines.size > 1 && !pipe_on_line && lines.first !~ /^#{TABLE_PIPE_CHECK}/o + pipe_on_line = (lines.size > 1 ? false : pipe_on_line) || (lines.last =~ /^#{TABLE_PIPE_CHECK}/o) + end + end + @src.revert_pos(saved_pos) and return false unless pipe_on_line + + add_container.call(has_footer ? :tfoot : :tbody, false) unless rows.empty? + + if table.children.none? {|el| el.type == :tbody } + warning("Found table without body on line #{table.options[:location]} - ignoring it") + @src.revert_pos(saved_pos) + return false + end + + # adjust all table rows to have equal number of columns, same for alignment defs + table.children.each do |kind| + kind.children.each do |row| + (columns - row.children.length).times do + row.children << Element.new(:td) + end + end + end + if table.options[:alignment].length > columns + table.options[:alignment] = table.options[:alignment][0...columns] + else + table.options[:alignment] += [:default] * (columns - table.options[:alignment].length) + end + + @tree.children << table + + true + end + define_parser(:table, TABLE_START) + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/typographic_symbol.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/typographic_symbol.rb new file mode 100644 index 00000000..d8bbc635 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/kramdown/typographic_symbol.rb @@ -0,0 +1,44 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Parser + class Kramdown + + TYPOGRAPHIC_SYMS = [['---', :mdash], ['--', :ndash], ['...', :hellip], + ['\\<<', '<<'], ['\\>>', '>>'], + ['<< ', :laquo_space], [' >>', :raquo_space], + ['<<', :laquo], ['>>', :raquo]] + TYPOGRAPHIC_SYMS_SUBST = Hash[*TYPOGRAPHIC_SYMS.flatten] + TYPOGRAPHIC_SYMS_RE = /#{TYPOGRAPHIC_SYMS.map {|k, _v| Regexp.escape(k) }.join('|')}/ + + # Parse the typographic symbols at the current location. + def parse_typographic_syms + start_line_number = @src.current_line_number + @src.pos += @src.matched_size + val = TYPOGRAPHIC_SYMS_SUBST[@src.matched] + if val.kind_of?(Symbol) + @tree.children << Element.new(:typographic_sym, val, nil, location: start_line_number) + elsif @src.matched == '\\<<' + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('lt'), + nil, location: start_line_number) + else + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('gt'), + nil, location: start_line_number) + end + end + define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE, '--|\\.\\.\\.|(?:\\\\| )?(?:<<|>>)') + + end + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/parser/markdown.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/markdown.rb new file mode 100644 index 00000000..8902029b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/parser/markdown.rb @@ -0,0 +1,57 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'kramdown/parser' + +module Kramdown + + module Parser + + # Used for parsing a document in Markdown format. + # + # This parser is based on the kramdown parser and removes the parser methods for the additional + # non-Markdown features. However, since some things are handled differently by the kramdown + # parser methods (like deciding when a list item contains just text), this parser differs from + # real Markdown parsers in some respects. + # + # Note, though, that the parser basically fails just one of the Markdown test cases (some others + # also fail but those failures are negligible). + class Markdown < Kramdown + + # Array with all the parsing methods that should be removed from the standard kramdown parser. + EXTENDED = [:codeblock_fenced, :table, :definition_list, :footnote_definition, + :abbrev_definition, :block_math, :block_extensions, + :footnote_marker, :smart_quotes, :inline_math, :span_extensions, :typographic_syms] + + def initialize(source, options) # :nodoc: + super + @block_parsers.delete_if {|i| EXTENDED.include?(i) } + @span_parsers.delete_if {|i| EXTENDED.include?(i) } + end + + # :stopdoc: + + BLOCK_BOUNDARY = /#{BLANK_LINE}|#{EOB_MARKER}|\Z/ + LAZY_END = /#{BLANK_LINE}|#{EOB_MARKER}|^#{OPT_SPACE}#{LAZY_END_HTML_STOP}| + ^#{OPT_SPACE}#{LAZY_END_HTML_START}|\Z/x + CODEBLOCK_MATCH = /(?:#{BLANK_LINE}?(?:#{INDENT}[ \t]*\S.*\n)+)*/ + PARAGRAPH_END = LAZY_END + + IAL_RAND_CHARS = (('a'..'z').to_a + ('0'..'9').to_a) + IAL_RAND_STRING = (1..20).collect { IAL_RAND_CHARS[rand(IAL_RAND_CHARS.size)] }.join + LIST_ITEM_IAL = /^\s*(#{IAL_RAND_STRING})?\s*\n/ + IAL_SPAN_START = LIST_ITEM_IAL + + # :startdoc: + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils.rb new file mode 100644 index 00000000..b63894d8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # == \Utils Module + # + # This module contains utility class/modules/methods that can be used by both parsers and + # converters. + module Utils + + autoload :Entities, 'kramdown/utils/entities' + autoload :Html, 'kramdown/utils/html' + autoload :Unidecoder, 'kramdown/utils/unidecoder' + autoload :StringScanner, 'kramdown/utils/string_scanner' + autoload :Configurable, 'kramdown/utils/configurable' + autoload :LRUCache, 'kramdown/utils/lru_cache' + + # Treat +name+ as if it were snake cased (e.g. snake_case) and camelize it (e.g. SnakeCase). + def self.camelize(name) + name.split('_').inject(+'') {|s, x| s << x[0..0].upcase << x[1..-1] } + end + + # Treat +name+ as if it were camelized (e.g. CamelizedName) and snake-case it (e.g. camelized_name). + def self.snake_case(name) + name = name.dup + name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + name.gsub!(/([a-z])([A-Z])/, '\1_\2') + name.downcase! + name + end + + def self.deep_const_get(str) + ::Object.const_get(str) + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/configurable.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/configurable.rb new file mode 100644 index 00000000..d334f464 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/configurable.rb @@ -0,0 +1,45 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # Methods for registering configurable extensions. + module Configurable + + # Create a new configurable extension called +name+. + # + # Three methods will be defined on the calling object which allow to use this configurable + # extension: + # + # configurables:: Returns a hash of hashes that is used to store all configurables of the + # object. + # + # (ext_name):: Return the configured extension +ext_name+. + # + # add_(ext_name, data=nil, &block):: Define an extension +ext_name+ by specifying either + # the data as argument or by using a block. + def configurable(name) + unless respond_to?(:configurables) + singleton_class.send(:define_method, :configurables) do + @_configurables ||= Hash.new {|h, k| h[k] = {} } + end + end + singleton_class.send(:define_method, name) do |data| + configurables[name][data] + end + singleton_class.send(:define_method, "add_#{name}".intern) do |data, *args, &block| + configurables[name][data] = args.first || block + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/entities.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/entities.rb new file mode 100644 index 00000000..4086fd20 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/entities.rb @@ -0,0 +1,1000 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + module Utils + + # Provides convenience methods for handling named and numeric entities. + module Entities + + # Represents an entity that has a +code_point+ and +name+. + Entity = Struct.new(:code_point, :name) do + # Return the UTF8 representation of the entity. + def char + [code_point].pack('U*') rescue nil + end + end + + # Array of arrays. Each sub-array specifies a code point and the associated name. + # + # This table is not used directly -- Entity objects are automatically created from it and put + # into a Hash map when this file is loaded. + ENTITY_TABLE = [ + + # html4 + [913, 'Alpha'], + [914, 'Beta'], + [915, 'Gamma'], + [916, 'Delta'], + [917, 'Epsilon'], + [918, 'Zeta'], + [919, 'Eta'], + [920, 'Theta'], + [921, 'Iota'], + [922, 'Kappa'], + [923, 'Lambda'], + [924, 'Mu'], + [925, 'Nu'], + [926, 'Xi'], + [927, 'Omicron'], + [928, 'Pi'], + [929, 'Rho'], + [931, 'Sigma'], + [932, 'Tau'], + [933, 'Upsilon'], + [934, 'Phi'], + [935, 'Chi'], + [936, 'Psi'], + [937, 'Omega'], + [945, 'alpha'], + [946, 'beta'], + [947, 'gamma'], + [948, 'delta'], + [949, 'epsilon'], + [950, 'zeta'], + [951, 'eta'], + [952, 'theta'], + [953, 'iota'], + [954, 'kappa'], + [955, 'lambda'], + [956, 'mu'], + [957, 'nu'], + [958, 'xi'], + [959, 'omicron'], + [960, 'pi'], + [961, 'rho'], + [963, 'sigma'], + [964, 'tau'], + [965, 'upsilon'], + [966, 'phi'], + [967, 'chi'], + [968, 'psi'], + [969, 'omega'], + [962, 'sigmaf'], + [977, 'thetasym'], + [978, 'upsih'], + [982, 'piv'], + [988, 'Gammad'], + [989, 'gammad'], + [8204, 'zwnj'], + [8205, 'zwj'], + [8206, 'lrm'], + [8207, 'rlm'], + [8230, 'hellip'], + [8242, 'prime'], + [8243, 'Prime'], + [8254, 'oline'], + [8260, 'frasl'], + [8472, 'weierp'], + [8465, 'image'], + [8476, 'real'], + [8501, 'alefsym'], + [8226, 'bull'], + [8482, 'trade'], + [8592, 'larr'], + [8594, 'rarr'], + [8593, 'uarr'], + [8595, 'darr'], + [8596, 'harr'], + [8629, 'crarr'], + [8657, 'uArr'], + [8659, 'dArr'], + [8656, 'lArr'], + [8658, 'rArr'], + [8660, 'hArr'], + [8704, 'forall'], + [8706, 'part'], + [8707, 'exist'], + [8709, 'empty'], + [8711, 'nabla'], + [8712, 'isin'], + [8715, 'ni'], + [8713, 'notin'], + [8721, 'sum'], + [8719, 'prod'], + [8722, 'minus'], + [8727, 'lowast'], + [8730, 'radic'], + [8733, 'prop'], + [8734, 'infin'], + [8736, 'ang'], + [8743, 'and'], + [8744, 'or'], + [8745, 'cap'], + [8746, 'cup'], + [8747, 'int'], + [8756, 'there4'], + [8764, 'sim'], + [8776, 'asymp'], + [8773, 'cong'], + [8800, 'ne'], + [8801, 'equiv'], + [8804, 'le'], + [8805, 'ge'], + [8834, 'sub'], + [8835, 'sup'], + [8838, 'sube'], + [8839, 'supe'], + [8836, 'nsub'], + [8853, 'oplus'], + [8855, 'otimes'], + [8869, 'perp'], + [8901, 'sdot'], + [8942, 'vellip'], + [8968, 'rceil'], + [8969, 'lceil'], + [8970, 'lfloor'], + [8971, 'rfloor'], + [9001, 'rang'], + [9002, 'lang'], + [9674, 'loz'], + [9824, 'spades'], + [9827, 'clubs'], + [9829, 'hearts'], + [9830, 'diams'], + [38, 'amp'], + [34, 'quot'], + [39, 'apos'], + [169, 'copy'], + [60, 'lt'], + [62, 'gt'], + [338, 'OElig'], + [339, 'oelig'], + [352, 'Scaron'], + [353, 'scaron'], + [376, 'Yuml'], + [710, 'circ'], + [732, 'tilde'], + [8211, 'ndash'], + [8212, 'mdash'], + [8216, 'lsquo'], + [8217, 'rsquo'], + [8220, 'ldquo'], + [8221, 'rdquo'], + [8224, 'dagger'], + [8225, 'Dagger'], + [8240, 'permil'], + [8364, 'euro'], + [8249, 'lsaquo'], + [8250, 'rsaquo'], + [160, 'nbsp'], + [161, 'iexcl'], + [163, 'pound'], + [164, 'curren'], + [165, 'yen'], + [166, 'brvbar'], + [167, 'sect'], + [168, 'uml'], + [171, 'laquo'], + [187, 'raquo'], + [174, 'reg'], + [170, 'ordf'], + [172, 'not'], + [173, 'shy'], + [175, 'macr'], + [176, 'deg'], + [177, 'plusmn'], + [180, 'acute'], + [181, 'micro'], + [182, 'para'], + [183, 'middot'], + [184, 'cedil'], + [186, 'ordm'], + [162, 'cent'], + [185, 'sup1'], + [178, 'sup2'], + [179, 'sup3'], + [189, 'frac12'], + [188, 'frac14'], + [190, 'frac34'], + [8531, 'frac13'], + [8532, 'frac23'], + [8533, 'frac15'], + [8534, 'frac25'], + [8535, 'frac35'], + [8536, 'frac45'], + [8537, 'frac16'], + [8538, 'frac56'], + [8539, 'frac18'], + [8540, 'frac38'], + [8541, 'frac58'], + [8542, 'frac78'], + [191, 'iquest'], + [192, 'Agrave'], + [193, 'Aacute'], + [194, 'Acirc'], + [195, 'Atilde'], + [196, 'Auml'], + [197, 'Aring'], + [198, 'AElig'], + [199, 'Ccedil'], + [200, 'Egrave'], + [201, 'Eacute'], + [202, 'Ecirc'], + [203, 'Euml'], + [204, 'Igrave'], + [205, 'Iacute'], + [206, 'Icirc'], + [207, 'Iuml'], + [208, 'ETH'], + [209, 'Ntilde'], + [210, 'Ograve'], + [211, 'Oacute'], + [212, 'Ocirc'], + [213, 'Otilde'], + [214, 'Ouml'], + [215, 'times'], + [216, 'Oslash'], + [217, 'Ugrave'], + [218, 'Uacute'], + [219, 'Ucirc'], + [220, 'Uuml'], + [221, 'Yacute'], + [222, 'THORN'], + [223, 'szlig'], + [224, 'agrave'], + [225, 'aacute'], + [226, 'acirc'], + [227, 'atilde'], + [228, 'auml'], + [229, 'aring'], + [230, 'aelig'], + [231, 'ccedil'], + [232, 'egrave'], + [233, 'eacute'], + [234, 'ecirc'], + [235, 'euml'], + [236, 'igrave'], + [237, 'iacute'], + [238, 'icirc'], + [239, 'iuml'], + [240, 'eth'], + [241, 'ntilde'], + [242, 'ograve'], + [243, 'oacute'], + [244, 'ocirc'], + [245, 'otilde'], + [246, 'ouml'], + [247, 'divide'], + [248, 'oslash'], + [249, 'ugrave'], + [250, 'uacute'], + [251, 'ucirc'], + [252, 'uuml'], + [253, 'yacute'], + [254, 'thorn'], + [255, 'yuml'], + + [8218, 'sbquo'], + [402, 'fnof'], + [8222, 'bdquo'], + + [128, 8364], + [130, 8218], + [131, 402], + [132, 8222], + [133, 8230], + [134, 8224], + [135, 8225], + [136, 710], + [137, 8240], + [138, 352], + [139, 8249], + [140, 338], + [142, 381], + [145, 8216], + [146, 8217], + [147, 8220], + [148, 8221], + [149, 8226], + [150, 8211], + [151, 8212], + [152, 732], + [153, 8482], + [154, 353], + [155, 8250], + [156, 339], + [158, 382], + [159, 376], + + [8194, 'ensp'], + [8195, 'emsp'], + [8201, 'thinsp'], + + # html5 + [10218, 'Lang'], + [10219, 'Rang'], + [10220, 'loang'], + [10221, 'roang'], + [10229, 'xlarr'], + [10229, 'longleftarrow'], + [10229, 'LongLeftArrow'], + [10230, 'xrarr'], + [10230, 'longrightarrow'], + [10230, 'LongRightArrow'], + [10231, 'xharr'], + [10231, 'longleftrightarrow'], + [10231, 'LongLeftRightArrow'], + [10232, 'xlArr'], + [10232, 'Longleftarrow'], + [10232, 'DoubleLongLeftArrow'], + [10233, 'xrArr'], + [10233, 'Longrightarrow'], + [10233, 'DoubleLongRightArrow'], + [10234, 'xhArr'], + [10234, 'Longleftrightarrow'], + [10234, 'DoubleLongLeftRightArrow'], + [10236, 'xmap'], + [10236, 'longmapsto'], + [10239, 'dzigrarr'], + [10498, 'nvlArr'], + [10499, 'nvrArr'], + [10500, 'nvHarr'], + [10501, 'Map'], + [10508, 'lbarr'], + [10509, 'rbarr'], + [10509, 'bkarow'], + [10510, 'lBarr'], + [10511, 'rBarr'], + [10511, 'dbkarow'], + [10512, 'RBarr'], + [10512, 'drbkarow'], + [10513, 'DDotrahd'], + [10514, 'UpArrowBar'], + [10515, 'DownArrowBar'], + [10518, 'Rarrtl'], + [10521, 'latail'], + [10522, 'ratail'], + [10523, 'lAtail'], + [10524, 'rAtail'], + [10525, 'larrfs'], + [10526, 'rarrfs'], + [10527, 'larrbfs'], + [10528, 'rarrbfs'], + [10531, 'nwarhk'], + [10532, 'nearhk'], + [10533, 'searhk'], + [10533, 'hksearow'], + [10534, 'swarhk'], + [10534, 'hkswarow'], + [10535, 'nwnear'], + [10536, 'nesear'], + [10536, 'toea'], + [10537, 'seswar'], + [10537, 'tosa'], + [10538, 'swnwar'], + [10547, 'rarrc'], + [10549, 'cudarrr'], + [10550, 'ldca'], + [10551, 'rdca'], + [10552, 'cudarrl'], + [10553, 'larrpl'], + [10556, 'curarrm'], + [10557, 'cularrp'], + [10565, 'rarrpl'], + [10568, 'harrcir'], + [10569, 'Uarrocir'], + [10570, 'lurdshar'], + [10571, 'ldrushar'], + [10574, 'LeftRightVector'], + [10575, 'RightUpDownVector'], + [10576, 'DownLeftRightVector'], + [10577, 'LeftUpDownVector'], + [10578, 'LeftVectorBar'], + [10579, 'RightVectorBar'], + [10580, 'RightUpVectorBar'], + [10581, 'RightDownVectorBar'], + [10582, 'DownLeftVectorBar'], + [10583, 'DownRightVectorBar'], + [10584, 'LeftUpVectorBar'], + [10585, 'LeftDownVectorBar'], + [10586, 'LeftTeeVector'], + [10587, 'RightTeeVector'], + [10588, 'RightUpTeeVector'], + [10589, 'RightDownTeeVector'], + [10590, 'DownLeftTeeVector'], + [10591, 'DownRightTeeVector'], + [10592, 'LeftUpTeeVector'], + [10593, 'LeftDownTeeVector'], + [10594, 'lHar'], + [10595, 'uHar'], + [10596, 'rHar'], + [10597, 'dHar'], + [10598, 'luruhar'], + [10599, 'ldrdhar'], + [10600, 'ruluhar'], + [10601, 'rdldhar'], + [10602, 'lharul'], + [10603, 'llhard'], + [10604, 'rharul'], + [10605, 'lrhard'], + [10606, 'udhar'], + [10606, 'UpEquilibrium'], + [10607, 'duhar'], + [10607, 'ReverseUpEquilibrium'], + [10608, 'RoundImplies'], + [10609, 'erarr'], + [10610, 'simrarr'], + [10611, 'larrsim'], + [10612, 'rarrsim'], + [10613, 'rarrap'], + [10614, 'ltlarr'], + [10616, 'gtrarr'], + [10617, 'subrarr'], + [10619, 'suplarr'], + [10620, 'lfisht'], + [10621, 'rfisht'], + [10622, 'ufisht'], + [10623, 'dfisht'], + [10629, 'lopar'], + [10630, 'ropar'], + [10635, 'lbrke'], + [10636, 'rbrke'], + [10637, 'lbrkslu'], + [10638, 'rbrksld'], + [10639, 'lbrksld'], + [10640, 'rbrkslu'], + [10641, 'langd'], + [10642, 'rangd'], + [10643, 'lparlt'], + [10644, 'rpargt'], + [10645, 'gtlPar'], + [10646, 'ltrPar'], + [10650, 'vzigzag'], + [10652, 'vangrt'], + [10653, 'angrtvbd'], + [10660, 'ange'], + [10661, 'range'], + [10662, 'dwangle'], + [10663, 'uwangle'], + [10664, 'angmsdaa'], + [10665, 'angmsdab'], + [10666, 'angmsdac'], + [10667, 'angmsdad'], + [10668, 'angmsdae'], + [10669, 'angmsdaf'], + [10670, 'angmsdag'], + [10671, 'angmsdah'], + [10672, 'bemptyv'], + [10673, 'demptyv'], + [10674, 'cemptyv'], + [10675, 'raemptyv'], + [10676, 'laemptyv'], + [10677, 'ohbar'], + [10678, 'omid'], + [10679, 'opar'], + [10681, 'operp'], + [10683, 'olcross'], + [10684, 'odsold'], + [10686, 'olcir'], + [10687, 'ofcir'], + [10688, 'olt'], + [10689, 'ogt'], + [10690, 'cirscir'], + [10691, 'cirE'], + [10692, 'solb'], + [10693, 'bsolb'], + [10697, 'boxbox'], + [10701, 'trisb'], + [10702, 'rtriltri'], + [10703, 'LeftTriangleBar'], + [10704, 'RightTriangleBar'], + [10716, 'iinfin'], + [10717, 'infintie'], + [10718, 'nvinfin'], + [10723, 'eparsl'], + [10724, 'smeparsl'], + [10725, 'eqvparsl'], + [10731, 'lozf'], + [10731, 'blacklozenge'], + [10740, 'RuleDelayed'], + [10742, 'dsol'], + [10752, 'xodot'], + [10752, 'bigodot'], + [10753, 'xoplus'], + [10753, 'bigoplus'], + [10754, 'xotime'], + [10754, 'bigotimes'], + [10756, 'xuplus'], + [10756, 'biguplus'], + [10758, 'xsqcup'], + [10758, 'bigsqcup'], + [10764, 'qint'], + [10764, 'iiiint'], + [10765, 'fpartint'], + [10768, 'cirfnint'], + [10769, 'awint'], + [10770, 'rppolint'], + [10771, 'scpolint'], + [10772, 'npolint'], + [10773, 'pointint'], + [10774, 'quatint'], + [10775, 'intlarhk'], + [10786, 'pluscir'], + [10787, 'plusacir'], + [10788, 'simplus'], + [10789, 'plusdu'], + [10790, 'plussim'], + [10791, 'plustwo'], + [10793, 'mcomma'], + [10794, 'minusdu'], + [10797, 'loplus'], + [10798, 'roplus'], + [10799, 'Cross'], + [10800, 'timesd'], + [10801, 'timesbar'], + [10803, 'smashp'], + [10804, 'lotimes'], + [10805, 'rotimes'], + [10806, 'otimesas'], + [10807, 'Otimes'], + [10808, 'odiv'], + [10809, 'triplus'], + [10810, 'triminus'], + [10811, 'tritime'], + [10812, 'iprod'], + [10812, 'intprod'], + [10815, 'amalg'], + [10816, 'capdot'], + [10818, 'ncup'], + [10819, 'ncap'], + [10820, 'capand'], + [10821, 'cupor'], + [10822, 'cupcap'], + [10823, 'capcup'], + [10824, 'cupbrcap'], + [10825, 'capbrcup'], + [10826, 'cupcup'], + [10827, 'capcap'], + [10828, 'ccups'], + [10829, 'ccaps'], + [10832, 'ccupssm'], + [10835, 'And'], + [10836, 'Or'], + [10837, 'andand'], + [10838, 'oror'], + [10839, 'orslope'], + [10840, 'andslope'], + [10842, 'andv'], + [10843, 'orv'], + [10844, 'andd'], + [10845, 'ord'], + [10847, 'wedbar'], + [10854, 'sdote'], + [10858, 'simdot'], + [10861, 'congdot'], + [10862, 'easter'], + [10863, 'apacir'], + [10864, 'apE'], + [10865, 'eplus'], + [10866, 'pluse'], + [10867, 'Esim'], + [10868, 'Colone'], + [10869, 'Equal'], + [10871, 'eDDot'], + [10871, 'ddotseq'], + [10872, 'equivDD'], + [10873, 'ltcir'], + [10874, 'gtcir'], + [10875, 'ltquest'], + [10876, 'gtquest'], + [10877, 'les'], + [10877, 'LessSlantEqual'], + [10877, 'leqslant'], + [10878, 'ges'], + [10878, 'GreaterSlantEqual'], + [10878, 'geqslant'], + [10879, 'lesdot'], + [10880, 'gesdot'], + [10881, 'lesdoto'], + [10882, 'gesdoto'], + [10883, 'lesdotor'], + [10884, 'gesdotol'], + [10885, 'lap'], + [10885, 'lessapprox'], + [10886, 'gap'], + [10886, 'gtrapprox'], + [10887, 'lne'], + [10887, 'lneq'], + [10888, 'gne'], + [10888, 'gneq'], + [10889, 'lnap'], + [10889, 'lnapprox'], + [10890, 'gnap'], + [10890, 'gnapprox'], + [10891, 'lEg'], + [10891, 'lesseqqgtr'], + [10892, 'gEl'], + [10892, 'gtreqqless'], + [10893, 'lsime'], + [10894, 'gsime'], + [10895, 'lsimg'], + [10896, 'gsiml'], + [10897, 'lgE'], + [10898, 'glE'], + [10899, 'lesges'], + [10900, 'gesles'], + [10901, 'els'], + [10901, 'eqslantless'], + [10902, 'egs'], + [10902, 'eqslantgtr'], + [10903, 'elsdot'], + [10904, 'egsdot'], + [10905, 'el'], + [10906, 'eg'], + [10909, 'siml'], + [10910, 'simg'], + [10911, 'simlE'], + [10912, 'simgE'], + [10913, 'LessLess'], + [10914, 'GreaterGreater'], + [10916, 'glj'], + [10917, 'gla'], + [10918, 'ltcc'], + [10919, 'gtcc'], + [10920, 'lescc'], + [10921, 'gescc'], + [10922, 'smt'], + [10923, 'lat'], + [10924, 'smte'], + [10925, 'late'], + [10926, 'bumpE'], + [10927, 'pre'], + [10927, 'preceq'], + [10927, 'PrecedesEqual'], + [10928, 'sce'], + [10928, 'succeq'], + [10928, 'SucceedsEqual'], + [10931, 'prE'], + [10932, 'scE'], + [10933, 'prnE'], + [10933, 'precneqq'], + [10934, 'scnE'], + [10934, 'succneqq'], + [10935, 'prap'], + [10935, 'precapprox'], + [10936, 'scap'], + [10936, 'succapprox'], + [10937, 'prnap'], + [10937, 'precnapprox'], + [10938, 'scnap'], + [10938, 'succnapprox'], + [10939, 'Pr'], + [10940, 'Sc'], + [10941, 'subdot'], + [10942, 'supdot'], + [10943, 'subplus'], + [10944, 'supplus'], + [10945, 'submult'], + [10946, 'supmult'], + [10947, 'subedot'], + [10948, 'supedot'], + [10949, 'subE'], + [10949, 'subseteqq'], + [10950, 'supE'], + [10950, 'supseteqq'], + [10951, 'subsim'], + [10952, 'supsim'], + [10955, 'subnE'], + [10955, 'subsetneqq'], + [10956, 'supnE'], + [10956, 'supsetneqq'], + [10959, 'csub'], + [10960, 'csup'], + [10961, 'csube'], + [10962, 'csupe'], + [10963, 'subsup'], + [10964, 'supsub'], + [10965, 'subsub'], + [10966, 'supsup'], + [10967, 'suphsub'], + [10968, 'supdsub'], + [10969, 'forkv'], + [10970, 'topfork'], + [10971, 'mlcp'], + [10980, 'Dashv'], + [10980, 'DoubleLeftTee'], + [10982, 'Vdashl'], + [10983, 'Barv'], + [10984, 'vBar'], + [10985, 'vBarv'], + [10987, 'Vbar'], + [10988, 'Not'], + [10989, 'bNot'], + [10990, 'rnmid'], + [10991, 'cirmid'], + [10992, 'midcir'], + [10993, 'topcir'], + [10994, 'nhpar'], + [10995, 'parsim'], + [11005, 'parsl'], + [64256, 'fflig'], + [64257, 'filig'], + [64258, 'fllig'], + [64259, 'ffilig'], + [64260, 'ffllig'], + [119964, 'Ascr'], + [119966, 'Cscr'], + [119967, 'Dscr'], + [119970, 'Gscr'], + [119973, 'Jscr'], + [119974, 'Kscr'], + [119977, 'Nscr'], + [119978, 'Oscr'], + [119979, 'Pscr'], + [119980, 'Qscr'], + [119982, 'Sscr'], + [119983, 'Tscr'], + [119984, 'Uscr'], + [119985, 'Vscr'], + [119986, 'Wscr'], + [119987, 'Xscr'], + [119988, 'Yscr'], + [119989, 'Zscr'], + [119990, 'ascr'], + [119991, 'bscr'], + [119992, 'cscr'], + [119993, 'dscr'], + [119995, 'fscr'], + [119997, 'hscr'], + [119998, 'iscr'], + [119999, 'jscr'], + [120000, 'kscr'], + [120001, 'lscr'], + [120002, 'mscr'], + [120003, 'nscr'], + [120005, 'pscr'], + [120006, 'qscr'], + [120007, 'rscr'], + [120008, 'sscr'], + [120009, 'tscr'], + [120010, 'uscr'], + [120011, 'vscr'], + [120012, 'wscr'], + [120013, 'xscr'], + [120014, 'yscr'], + [120015, 'zscr'], + [120068, 'Afr'], + [120069, 'Bfr'], + [120071, 'Dfr'], + [120072, 'Efr'], + [120073, 'Ffr'], + [120074, 'Gfr'], + [120077, 'Jfr'], + [120078, 'Kfr'], + [120079, 'Lfr'], + [120080, 'Mfr'], + [120081, 'Nfr'], + [120082, 'Ofr'], + [120083, 'Pfr'], + [120084, 'Qfr'], + [120086, 'Sfr'], + [120087, 'Tfr'], + [120088, 'Ufr'], + [120089, 'Vfr'], + [120090, 'Wfr'], + [120091, 'Xfr'], + [120092, 'Yfr'], + [120094, 'afr'], + [120095, 'bfr'], + [120096, 'cfr'], + [120097, 'dfr'], + [120098, 'efr'], + [120099, 'ffr'], + [120100, 'gfr'], + [120101, 'hfr'], + [120102, 'ifr'], + [120103, 'jfr'], + [120104, 'kfr'], + [120105, 'lfr'], + [120106, 'mfr'], + [120107, 'nfr'], + [120108, 'ofr'], + [120109, 'pfr'], + [120110, 'qfr'], + [120111, 'rfr'], + [120112, 'sfr'], + [120113, 'tfr'], + [120114, 'ufr'], + [120115, 'vfr'], + [120116, 'wfr'], + [120117, 'xfr'], + [120118, 'yfr'], + [120119, 'zfr'], + [120120, 'Aopf'], + [120121, 'Bopf'], + [120123, 'Dopf'], + [120124, 'Eopf'], + [120125, 'Fopf'], + [120126, 'Gopf'], + [120128, 'Iopf'], + [120129, 'Jopf'], + [120130, 'Kopf'], + [120131, 'Lopf'], + [120132, 'Mopf'], + [120134, 'Oopf'], + [120138, 'Sopf'], + [120139, 'Topf'], + [120140, 'Uopf'], + [120141, 'Vopf'], + [120142, 'Wopf'], + [120143, 'Xopf'], + [120144, 'Yopf'], + [120146, 'aopf'], + [120147, 'bopf'], + [120148, 'copf'], + [120149, 'dopf'], + [120150, 'eopf'], + [120151, 'fopf'], + [120152, 'gopf'], + [120153, 'hopf'], + [120154, 'iopf'], + [120155, 'jopf'], + [120156, 'kopf'], + [120157, 'lopf'], + [120158, 'mopf'], + [120159, 'nopf'], + [120160, 'oopf'], + [120161, 'popf'], + [120162, 'qopf'], + [120163, 'ropf'], + [120164, 'sopf'], + [120165, 'topf'], + [120166, 'uopf'], + [120167, 'vopf'], + [120168, 'wopf'], + [120169, 'xopf'], + [120170, 'yopf'], + [120171, 'zopf'], + [60, 'nvlt'], + [61, 'bne'], + [62, 'nvgt'], + [102, 'fjlig'], + [8287, 'ThickSpace'], + [8605, 'nrarrw'], + [8706, 'npart'], + [8736, 'nang'], + [8745, 'caps'], + [8746, 'cups'], + [8764, 'nvsim'], + [8765, 'race'], + [8766, 'acE'], + [8770, 'nesim'], + [8770, 'NotEqualTilde'], + [8779, 'napid'], + [8781, 'nvap'], + [8782, 'nbump'], + [8782, 'NotHumpDownHump'], + [8783, 'nbumpe'], + [8783, 'NotHumpEqual'], + [8784, 'nedot'], + [8801, 'bnequiv'], + [8804, 'nvle'], + [8805, 'nvge'], + [8806, 'nlE'], + [8806, 'nleqq'], + [8807, 'ngE'], + [8807, 'ngeqq'], + [8807, 'NotGreaterFullEqual'], + [8808, 'lvertneqq'], + [8808, 'lvnE'], + [8809, 'gvertneqq'], + [8809, 'gvnE'], + [8810, 'nLtv'], + [8810, 'NotLessLess'], + [8810, 'nLt'], + [8811, 'nGtv'], + [8811, 'NotGreaterGreater'], + [8811, 'nGt'], + [8831, 'NotSucceedsTilde'], + [8834, 'NotSubset'], + [8834, 'nsubset'], + [8834, 'vnsub'], + [8835, 'NotSuperset'], + [8835, 'nsupset'], + [8835, 'vnsup'], + [8842, 'varsubsetneq'], + [8842, 'vsubne'], + [8843, 'varsupsetneq'], + [8843, 'vsupne'], + [8847, 'NotSquareSubset'], + [8848, 'NotSquareSuperset'], + [8851, 'sqcaps'], + [8852, 'sqcups'], + [8884, 'nvltrie'], + [8885, 'nvrtrie'], + [8920, 'nLl'], + [8921, 'nGg'], + [8922, 'lesg'], + [8923, 'gesl'], + [8949, 'notindot'], + [8953, 'notinE'], + [10547, 'nrarrc'], + [10703, 'NotLeftTriangleBar'], + [10704, 'NotRightTriangleBar'], + [10861, 'ncongdot'], + [10864, 'napE'], + [10877, 'nleqslant'], + [10877, 'nles'], + [10877, 'NotLessSlantEqual'], + [10878, 'ngeqslant'], + [10878, 'nges'], + [10878, 'NotGreaterSlantEqual'], + [10913, 'NotNestedLessLess'], + [10914, 'NotNestedGreaterGreater'], + [10924, 'smtes'], + [10925, 'lates'], + [10927, 'NotPrecedesEqual'], + [10927, 'npre'], + [10927, 'npreceq'], + [10928, 'NotSucceedsEqual'], + [10928, 'nsce'], + [10928, 'nsucceq'], + [10949, 'nsubE'], + [10949, 'nsubseteqq'], + [10950, 'nsupE'], + [10950, 'nsupseteqq'], + [10955, 'varsubsetneqq'], + [10955, 'vsubnE'], + [10956, 'varsupsetneqq'], + [10956, 'vsupnE'], + [11005, 'nparsl'], + + ] + + # Contains the mapping of code point (or name) to the actual Entity object. + ENTITY_MAP = Hash.new do |h, k| + if k.kind_of?(Integer) + h[k] = Entity.new(k, nil) + else + raise Kramdown::Error, "Can't handle generic non-integer character reference '#{k}'" + end + end + + ENTITY_TABLE.each do |code_point, data| + ENTITY_MAP[code_point] = if data.kind_of?(String) + ENTITY_MAP[data] = Entity.new(code_point, data) + else + ENTITY_MAP[data] + end + end + + # Return the entity for the given code point or name +point_or_name+. + def entity(point_or_name) + ENTITY_MAP[point_or_name] + end + + module_function :entity + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/html.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/html.rb new file mode 100644 index 00000000..18bc12ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/html.rb @@ -0,0 +1,84 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'rexml/parsers/baseparser' + +module Kramdown + + module Utils + + # Provides convenience methods for HTML related tasks. + # + # *Note* that this module has to be mixed into a class that has a @root (containing an element + # of type :root) and an @options (containing an options hash) instance variable so that some of + # the methods can work correctly. + module Html + + # Convert the entity +e+ to a string. The optional parameter +original+ may contain the + # original representation of the entity. + # + # This method uses the option +entity_output+ to determine the output form for the entity. + def entity_to_str(e, original = nil) + entity_output = @options[:entity_output] + + if entity_output == :as_char && + (c = e.char.encode(@root.options[:encoding]) rescue nil) && + ((c = e.char) == '"' || !ESCAPE_MAP.key?(c)) + c + elsif (entity_output == :as_input || entity_output == :as_char) && original + original + elsif (entity_output == :symbolic || ESCAPE_MAP.key?(e.char)) && !e.name.nil? + "&#{e.name};" + else # default to :numeric + "&##{e.code_point};" + end + end + + # Return the HTML representation of the attributes +attr+. + def html_attributes(attr) + return '' if attr.empty? + + attr.map do |k, v| + v.nil? || (k == 'id' && v.strip.empty?) ? '' : " #{k}=\"#{escape_html(v.to_s, :attribute)}\"" + end.join + end + + # :stopdoc: + ESCAPE_MAP = { + '<' => '<', + '>' => '>', + '&' => '&', + '"' => '"', + } + ESCAPE_ALL_RE = /<|>|&/ + ESCAPE_TEXT_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&/) + ESCAPE_ATTRIBUTE_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&|"/) + ESCAPE_RE_FROM_TYPE = {all: ESCAPE_ALL_RE, text: ESCAPE_TEXT_RE, attribute: ESCAPE_ATTRIBUTE_RE} + # :startdoc: + + # Escape the special HTML characters in the string +str+. The parameter +type+ specifies what + # is escaped: :all - all special HTML characters except the quotation mark as well as + # entities, :text - all special HTML characters except the quotation mark but no entities and + # :attribute - all special HTML characters including the quotation mark but no entities. + def escape_html(str, type = :all) + str.gsub(ESCAPE_RE_FROM_TYPE[type]) {|m| ESCAPE_MAP[m] || m } + end + + REDUNDANT_LINE_BREAK_REGEX = /([\p{Han}\p{Hiragana}\p{Katakana}]+)\n([\p{Han}\p{Hiragana}\p{Katakana}]+)/u + def fix_cjk_line_break(str) + while str.gsub!(REDUNDANT_LINE_BREAK_REGEX, '\1\2') + end + str + end + + end + + end + +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/lru_cache.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/lru_cache.rb new file mode 100644 index 00000000..13068c03 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/lru_cache.rb @@ -0,0 +1,41 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + module Utils + + # A simple least recently used (LRU) cache. + # + # The cache relies on the fact that Ruby's Hash class maintains insertion order. So deleting + # and re-inserting a key-value pair on access moves the key to the last position. When an + # entry is added and the cache is full, the first entry is removed. + class LRUCache + + # Creates a new LRUCache that can hold +size+ entries. + def initialize(size) + @size = size + @cache = {} + end + + # Returns the stored value for +key+ or +nil+ if no value was stored under the key. + def [](key) + (val = @cache.delete(key)).nil? ? nil : @cache[key] = val + end + + # Stores the +value+ under the +key+. + def []=(key, value) + @cache.delete(key) + @cache[key] = value + @cache.shift if @cache.length > @size + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/string_scanner.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/string_scanner.rb new file mode 100644 index 00000000..de076903 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/string_scanner.rb @@ -0,0 +1,81 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'strscan' + +module Kramdown + module Utils + + # This patched StringScanner adds line number information for current scan position and a + # start_line_number override for nested StringScanners. + class StringScanner < ::StringScanner + + # The start line number. Used for nested StringScanners that scan a sub-string of the source + # document. The kramdown parser uses this, e.g., for span level parsers. + attr_reader :start_line_number + + # Takes the start line number as optional second argument. + # + # Note: The original second argument is no longer used so this should be safe. + def initialize(string, start_line_number = 1) + super(string) + @start_line_number = start_line_number || 1 + @previous_pos = 0 + @previous_line_number = @start_line_number + end + + # Sets the byte position of the scan pointer. + # + # Note: This also resets some internal variables, so always use pos= when setting the position + # and don't use any other method for that! + def pos=(pos) + if self.pos > pos + @previous_line_number = @start_line_number + @previous_pos = 0 + end + super + end + + # Return information needed to revert the byte position of the string scanner in a performant + # way. + # + # The returned data can be fed to #revert_pos to revert the position to the saved one. + # + # Note: Just saving #pos won't be enough. + def save_pos + [pos, @previous_pos, @previous_line_number] + end + + # Revert the position to one saved by #save_pos. + def revert_pos(data) + self.pos = data[0] + @previous_pos, @previous_line_number = data[1], data[2] + end + + # Returns the line number for current charpos. + # + # NOTE: Requires that all line endings are normalized to '\n' + # + # NOTE: Normally we'd have to add one to the count of newlines to get the correct line number. + # However we add the one indirectly by using a one-based start_line_number. + def current_line_number + # Not using string[@previous_pos..best_pos].count('\n') because it is slower + strscan = ::StringScanner.new(string) + strscan.pos = @previous_pos + old_pos = pos + 1 + @previous_line_number += 1 while strscan.skip_until(/\n/) && strscan.pos <= old_pos + + @previous_pos = (eos? ? pos : pos + 1) + @previous_line_number + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/utils/unidecoder.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/unidecoder.rb new file mode 100644 index 00000000..dacf2d8f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/utils/unidecoder.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# +# This file is based on code originally from the Stringex library and needs the data files from +# Stringex to work correctly. + +module Kramdown + module Utils + + # Provides the ability to tranliterate Unicode strings into plain ASCII ones. + module Unidecoder + + gem 'stringex' + path = $:.find do |dir| + File.directory?(File.join(File.expand_path(dir), "stringex", "unidecoder_data")) + end + + if path + CODEPOINTS = Hash.new do |h, k| + h[k] = YAML.load_file(File.join(path, "stringex", "unidecoder_data", "#{k}.yml")) + end + + # Transliterate string from Unicode into ASCII. + def self.decode(string) + string.gsub(/[^\x00-\x7f]/u) do |codepoint| + unpacked = codepoint.unpack1("U") + CODEPOINTS[sprintf("x%02x", unpacked >> 8)][unpacked & 255] + rescue StandardError + "?" + end + end + else + def self.decode(string) + string + end + end + + end + + end +end diff --git a/bin/gems/kramdown-2.5.2/lib/kramdown/version.rb b/bin/gems/kramdown-2.5.2/lib/kramdown/version.rb new file mode 100644 index 00000000..ec428be8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/lib/kramdown/version.rb @@ -0,0 +1,15 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +module Kramdown + + # The kramdown version. + VERSION = '2.5.2' + +end diff --git a/bin/gems/kramdown-2.5.2/man/man1/kramdown.1 b/bin/gems/kramdown-2.5.2/man/man1/kramdown.1 new file mode 100644 index 00000000..80225825 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/man/man1/kramdown.1 @@ -0,0 +1,373 @@ +.\" generated by kramdown +.TH "KRAMDOWN" "1" "January 2019" +.SH NAME +kramdown \- a fast, pure\-Ruby Markdown\-superset converter +.SH "SYNOPSIS" +\fBkramdown\fP [\fIoptions\fP] [\fIFILE\fP\.\.\.] +.SH "DESCRIPTION" +kramdown is primarily used for parsing a superset of Markdown and converting it to different output formats\. It supports standard Markdown (with some minor modifications) and various extensions like tables and definition lists\. Due to its modular architecture it also allows other input formats than Markdown, for example, HTML or Github Flavored Markdown\. +.P +If \fIFILE\fP is not specified, kramdown reads from the standard input\. The result is written to the standard output\. +.P +There are two sets of options that kramdown accepts: The first one includes the options that are used directly by the kramdown binary\. The second set of options controls how kramdown parses and converts its input\. +.P +Default values for this second set can be set using YAML via the configuration file \fBkramdownrc\fP\&\. Note that configuration option names use underscores, not dashes (dashes are just used in the CLI options names), and boolean options do not have a \fBno\fP variant but a value of \fBtrue\fP or \fBfalse\fP\&\. This file has to be in XDG_CONFIG_HOME on Linux/Unix, ~/Library/Preferences on macOS and ~/AppData/Local on Windows\. +.SH "CLI\-ONLY OPTIONS" +.TP +\fB\-i\fP \fIFORMAT\fP, \fB\-\-input\fP \fIFORMAT\fP +Specify the input format\. Available input formats: \fIkramdown\fP (this is the default), \fImarkdown\fP, or \fIhtml\fP\&\. The input format \fIGFM\fP is available through the \fBkramdown\-parser\-gfm\fP gem\. +.TP +\fB\-o\fP \fIFORMAT\fP, \fB\-\-output\fP \fIFORMAT\fP +Specify one or more output formats separated by commas: \fIhtml\fP (default), \fIkramdown\fP, \fIlatex\fP, \fIman\fP or \fIremove_html_tags\fP\&\. The converter \fIpdf\fP is available through the \fBkramdown\-converter\-pdf\fP gem\. +.TP +\fB\-x\fP \fIEXT\fP, \fB\-\-extension\fP \fIEXT\fP +Load one or more extensions\. The name of the extension should not include the \fBkramdown\-\fP prefix, e\.g\. just \fBparser\-gfm\fP\&\. Multiple extensions can be loaded by separating them with commas\. +.RS +.P +Note: This option has to be used before any other options that rely on the extension already being loaded\. +.RE +.TP +\fB\-\-no\-config\-file\fP +Do not read any configuration file\. Default behavior is to check for a configuration file and read it if it exists\. +.TP +\fB\-\-config\-file\fP \fIFILE\fP +Override the default path and name of the configuration file\. +.TP +\fB\-v\fP, \fB\-\-version\fP +Show the version of kramdown\. +.TP +\fB\-h\fP, \fB\-\-help\fP +Show the help\. +.SH "KRAMDOWN OPTIONS" +.TP +\fB\-\-auto\-id\-prefix\fP \fIARG\fP +Prefix used for automatically generated header IDs +.RS +.P +This option can be used to set a prefix for the automatically generated header IDs so that there is no conflict when rendering multiple kramdown documents into one output file separately\. The prefix should only contain characters that are valid in an ID! +.P +Default: \[u2018]\[u2019] Used by: HTML/Latex converter +.RE +.TP +\fB\-\-[no\-]auto\-id\-stripping\fP +Strip all formatting from header text for automatic ID generation +.RS +.P +If this option is \fBtrue\fP, only the text elements of a header are used for generating the ID later (in contrast to just using the raw header text line)\. +.P +This option will be removed in version 2\.0 because this will be the default then\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]auto\-ids\fP +Use automatic header ID generation +.RS +.P +If this option is \fBtrue\fP, ID values for all headers are automatically generated if no ID is explicitly specified\. +.P +Default: true Used by: HTML/Latex converter +.RE +.TP +\fB\-\-entity\-output\fP \fIARG\fP +Defines how entities are output +.RS +.P +The possible values are :as_input (entities are output in the same form as found in the input), :numeric (entities are output in numeric form), :symbolic (entities are output in symbolic form if possible) or :as_char (entities are output as characters if possible, only available on Ruby 1\.9)\. +.P +Default: :as_char Used by: HTML converter, kramdown converter +.RE +.TP +\fB\-\-footnote\-backlink\fP \fIARG\fP +Defines the text that should be used for the footnote backlinks +.RS +.P +The footnote backlink is just text, so any special HTML characters will be escaped\. +.P +If the footnote backlint text is an empty string, no footnote backlinks will be generated\. +.P +Default: \[u2018]\[u0026]8617;\[u2019] Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]footnote\-backlink\-inline\fP +Specifies whether the footnote backlink should always be inline +.RS +.P +With the default of false the footnote backlink is placed at the end of the last paragraph if there is one, or an extra paragraph with only the footnote backlink is created\. +.P +Setting this option to true tries to place the footnote backlink in the last, possibly nested paragraph or header\. If this fails (e\.g\. in the case of a table), an extra paragraph with only the footnote backlink is created\. +.P +Default: false Used by: HTML converter +.RE +.TP +\fB\-\-footnote\-link\-text\fP \fIARG\fP +The text used for the footnote number in a footnote link +.RS +.P +This option can be used to add additional text to the footnote link\. It should be a format string, and is passed the footnote number as the only argument to the format string\. e\.g\. \[u201c][footnote %s]\[u201d] would display as \[u201c][footnote 1]\[u201d]\&\. +.P +Default: \[u2018]%s\[u2019] Used by: HTML +.RE +.TP +\fB\-\-footnote\-nr\fP \fIARG\fP +The number of the first footnote +.RS +.P +This option can be used to specify the number that is used for the first footnote\. +.P +Default: 1 Used by: HTML converter +.RE +.TP +\fB\-\-footnote\-prefix\fP \fIARG\fP +Prefix used for footnote IDs +.RS +.P +This option can be used to set a prefix for footnote IDs\. This is useful when rendering multiple documents into the same output file to avoid duplicate IDs\. The prefix should only contain characters that are valid in an ID! +.P +Default: \[u2018]\[u2019] Used by: HTML +.RE +.TP +\fB\-\-forbidden\-inline\-options\fP \fIARG\fP +Defines the options that may not be set using the {::options} extension +.RS +.P +The value needs to be an array of option names\. +.P +Default: [template] Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]header\-links\fP +Adds anchor tags within headers that can be used to generate permalinks when not using a table of contents\. +.RS +.P +The anchor tags are empty, but can be styled to your liking\. +.P +Default: false +.RE +.TP +\fB\-\-header\-offset\fP \fIARG\fP +Sets the output offset for headers +.RS +.P +If this option is c (may also be negative) then a header with level n will be output as a header with level c+n\. If c+n is lower than 1, level 1 will be used\. If c+n is greater than 6, level 6 will be used\. +.P +Default: 0 Used by: HTML converter, Kramdown converter, Latex converter +.RE +.TP +\fB\-\-[no\-]html\-to\-native\fP +Convert HTML elements to native elements +.RS +.P +If this option is \fBtrue\fP, the parser converts HTML elements to native elements\. For example, when parsing \fBhallo\fP the emphasis tag would normally be converted to an \fB:html\fP element with tag type \fB:em\fP\&\. If \fBhtml_to_native\fP is \fBtrue\fP, then the emphasis would be converted to a native \fB:em\fP element\. +.P +This is useful for converters that cannot deal with HTML elements\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-latex\-headers\fP \fIARG\fP +Defines the LaTeX commands for different header levels +.RS +.P +The commands for the header levels one to six can be specified by separating them with commas\. +.P +Default: section,subsection,subsubsection,paragraph,subparagraph,subparagraph Used by: Latex converter +.RE +.TP +\fB\-\-line\-width\fP \fIARG\fP +Defines the line width to be used when outputting a document +.RS +.P +Default: 72 Used by: kramdown converter +.RE +.TP +\fB\-\-link\-defs\fP \fIARG\fP +Pre\-defines link definitions +.RS +.P +This option can be used to pre\-define link definitions\. The value needs to be a Hash where the keys are the link identifiers and the values are two element Arrays with the link URL and the link title\. +.P +If the value is a String, it has to contain a valid YAML hash and the hash has to follow the above guidelines\. +.P +Default: {} Used by: kramdown parser +.RE +.TP +\fB\-\-list\-indent\fP \fIARG\fP +Sets the number of spaces to use for list indentation +.RS +.P +Default: 2 Used by: Kramdown converter +.RE +.TP +\fB\-\-math\-engine\fP \fIARG\fP +Set the math engine +.RS +.P +Specifies the math engine that should be used for converting math blocks/spans\. If this option is set to +nil+, no math engine is used and the math blocks/spans are output as is\. +.P +Options for the selected math engine can be set with the math_engine_opts configuration option\. +.P +Default: mathjax Used by: HTML converter +.RE +.TP +\fB\-\-math\-engine\-opts\fP \fIARG\fP +Set the math engine options +.RS +.P +Specifies options for the math engine set via the math_engine configuration option\. +.P +The value needs to be a hash with key\-value pairs that are understood by the used math engine\. +.P +Default: {} Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]parse\-block\-html\fP +Process kramdown syntax in block HTML tags +.RS +.P +If this option is \fBtrue\fP, the kramdown parser processes the content of block HTML tags as text containing block\-level elements\. Since this is not wanted normally, the default is \fBfalse\fP\&\. It is normally better to selectively enable kramdown processing via the markdown attribute\. +.P +Default: false Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]parse\-span\-html\fP +Process kramdown syntax in span HTML tags +.RS +.P +If this option is \fBtrue\fP, the kramdown parser processes the content of span HTML tags as text containing span\-level elements\. +.P +Default: true Used by: kramdown parser +.RE +.TP +\fB\-\-[no\-]remove\-block\-html\-tags\fP +Remove block HTML tags +.RS +.P +If this option is \fBtrue\fP, the RemoveHtmlTags converter removes block HTML tags\. +.P +Default: true Used by: RemoveHtmlTags converter +.RE +.TP +\fB\-\-[no\-]remove\-line\-breaks\-for\-cjk\fP +Specifies whether line breaks should be removed between CJK characters +.RS +.P +Default: false Used by: HTML converter +.RE +.TP +\fB\-\-[no\-]remove\-span\-html\-tags\fP +Remove span HTML tags +.RS +.P +If this option is \fBtrue\fP, the RemoveHtmlTags converter removes span HTML tags\. +.P +Default: false Used by: RemoveHtmlTags converter +.RE +.TP +\fB\-\-smart\-quotes\fP \fIARG\fP +Defines the HTML entity names or code points for smart quote output +.RS +.P +The entities identified by entity name or code point that should be used for, in order, a left single quote, a right single quote, a left double and a right double quote are specified by separating them with commas\. +.P +Default: lsquo,rsquo,ldquo,rdquo Used by: HTML/Latex converter +.RE +.TP +\fB\-\-syntax\-highlighter\fP \fIARG\fP +Set the syntax highlighter +.RS +.P +Specifies the syntax highlighter that should be used for highlighting code blocks and spans\. If this option is set to +nil+, no syntax highlighting is done\. +.P +Options for the syntax highlighter can be set with the syntax_highlighter_opts configuration option\. +.P +Default: rouge Used by: HTML/Latex converter +.RE +.TP +\fB\-\-syntax\-highlighter\-opts\fP \fIARG\fP +Set the syntax highlighter options +.RS +.P +Specifies options for the syntax highlighter set via the syntax_highlighter configuration option\. +.P +The value needs to be a hash with key\-value pairs that are understood by the used syntax highlighter\. +.P +Default: {} Used by: HTML/Latex converter +.RE +.TP +\fB\-\-template\fP \fIARG\fP +The name of an ERB template file that should be used to wrap the output or the ERB template itself\. +.RS +.P +This is used to wrap the output in an environment so that the output can be used as a stand\-alone document\. For example, an HTML template would provide the needed header and body tags so that the whole output is a valid HTML file\. If no template is specified, the output will be just the converted text\. +.P +When resolving the template file, the given template name is used first\. If such a file is not found, the converter extension (the same as the converter name) is appended\. If the file still cannot be found, the templates name is interpreted as a template name that is provided by kramdown (without the converter extension)\. If the file is still not found, the template name is checked if it starts with \[u2018]string://\[u2019] and if it does, this prefix is removed and the rest is used as template content\. +.P +kramdown provides a default template named \[u2018]document\[u2019] for each converter\. +.P +Default: \[u2018]\[u2019] Used by: all converters +.RE +.TP +\fB\-\-toc\-levels\fP \fIARG\fP +Defines the levels that are used for the table of contents +.RS +.P +The individual levels can be specified by separating them with commas (e\.g\. 1,2,3) or by using the range syntax (e\.g\. 1\.\.3)\. Only the specified levels are used for the table of contents\. +.P +Default: 1\.\.6 Used by: HTML/Latex converter +.RE +.TP +\fB\-\-[no\-]transliterated\-header\-ids\fP +Transliterate the header text before generating the ID +.RS +.P +Only ASCII characters are used in headers IDs\. This is not good for languages with many non\-ASCII characters\. By enabling this option the header text is transliterated to ASCII as good as possible so that the resulting header ID is more useful\. +.P +The stringex library needs to be installed for this feature to work! +.P +Default: false Used by: HTML/Latex converter +.RE +.TP +\fB\-\-typographic\-symbols\fP \fIARG\fP +Defines a mapping from typographical symbol to output characters +.RS +.P +Typographical symbols are normally output using their equivalent Unicode codepoint\. However, sometimes one wants to change the output, mostly to fallback to a sequence of ASCII characters\. +.P +This option allows this by specifying a mapping from typographical symbol to its output string\. For example, the mapping {hellip: \.\.\.} would output the standard ASCII representation of an ellipsis\. +.P +The available typographical symbol names are: +.IP \(bu 4 +hellip: ellipsis +.IP \(bu 4 +mdash: em\-dash +.IP \(bu 4 +ndash: en\-dash +.IP \(bu 4 +laquo: left guillemet +.IP \(bu 4 +raquo: right guillemet +.IP \(bu 4 +laquo_space: left guillemet followed by a space +.IP \(bu 4 +raquo_space: right guillemet preceeded by a space +.P +Default: {} Used by: HTML/Latex converter +.RE +.SH "EXIT STATUS" +The exit status is 0 if no error happened\. Otherwise it is 1\. +.SH "SEE ALSO" +The kramdown website +.UR http://kramdown\.gettalong\.org +.UE +for more information, especially on the supported input syntax\. +.SH "AUTHOR" +kramdown was written by Thomas Leitner +.MT t_leitner@gmx\.at +.UE +\&\. +.P +This manual page was written by Thomas Leitner +.MT t_leitner@gmx\.at +.UE +\&\. diff --git a/bin/gems/kramdown-2.5.2/test/run_tests.rb b/bin/gems/kramdown-2.5.2/test/run_tests.rb new file mode 100644 index 00000000..5c819e05 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/run_tests.rb @@ -0,0 +1,46 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'kramdown' +require 'test/unit/assertions' +require 'yaml' + +include Test::Unit::Assertions + +arg = ARGV[0] || File.join(File.dirname(__FILE__), 'testcases') + +arg = if File.directory?(arg) + File.join(arg, '**/*.text') + else + arg + '.text' + end + +width = ((size = `stty size 2>/dev/null`).length > 0 ? size.split.last.to_i : 72) rescue 72 +width -= 8 +fwidth = 0 +Dir[arg].each {|f| fwidth = [fwidth, f.length + 10].max }.each do |file| + print(('Testing ' + file + ' ').ljust([fwidth, width].min)) + $stdout.flush + + html_file = file.sub('.text', '.html') + opts_file = file.sub('.text', '.options') + opts_file = File.join(File.dirname(file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.safe_load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(file), options) + begin + assert_equal(File.read(html_file), doc.to_html) + puts 'PASSED' + rescue StandardError + puts ' FAILED' + puts $!.message if $VERBOSE + puts $!.backtrace if $DEBUG + end + puts "Warnings:\n" + doc.warnings.join("\n") if !doc.warnings.empty? && $VERBOSE +end diff --git a/bin/gems/kramdown-2.5.2/test/test_files.rb b/bin/gems/kramdown-2.5.2/test/test_files.rb new file mode 100644 index 00000000..6c49618b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/test_files.rb @@ -0,0 +1,313 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown' +require 'yaml' +require 'tmpdir' +require 'open3' + +begin + require 'kramdown/converter/syntax_highlighter/rouge' + + Kramdown::Converter::SyntaxHighlighter::Rouge.formatter_class.send(:define_method, :format) do |tokens, &b| + super(tokens, &b).sub(/<\/code><\/pre>\n?/, "\n") + end + + # custom formatter for tests + module Rouge + module Formatters + class RougeHTMLFormatters < Kramdown::Converter::SyntaxHighlighter::Rouge.formatter_class + + tag 'rouge_html_formatters' + + def stream(tokens, &b) + yield %(
) + super + yield %(
) + end + + end + end + end +rescue LoadError, SyntaxError, NameError +end + +Encoding.default_external = 'utf-8' + +class TestFiles < Minitest::Test + + EXCLUDE_KD_FILES = [].compact + + # Generate test methods for kramdown-to-xxx conversion + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_KD_FILES.any? {|f| text_file =~ /#{f}/ } + basename = text_file.sub(/\.text$/, '') + opts_file = text_file.sub(/\.text$/, '.options') + (Dir[basename + ".*"] - [text_file, opts_file]).each do |output_file| + output_format = File.extname(output_file)[1..-1] + next unless Kramdown::Converter.const_defined?(output_format[0..0].upcase + output_format[1..-1]) + define_method('test_' + text_file.tr('.', '_') + "_to_#{output_format}") do + opts_file = File.join(File.dirname(text_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(text_file), options) + assert_equal(File.read(output_file), doc.send("to_#{output_format}")) + end + end + end + + # Generate test methods for html-to-{html,kramdown} conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping html-to-{html,kramdown} tests because tidy executable is missing") + else + EXCLUDE_HTML_FILES = [ + 'test/testcases/block/06_codeblock/whitespace.html', # bc of span inside pre + 'test/testcases/block/09_html/simple.html', # bc of xml elements + 'test/testcases/span/03_codespan/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option + 'test/testcases/block/04_header/header_type_offset.html', # bc of header_offset option + 'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/highlighting-opts.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/guess_lang_css_class.html', # bc of double surrounding
+ 'test/testcases/block/12_extension/options3.html', # bc of rouge + 'test/testcases/block/14_table/empty_tag_in_cell.html', # bc of tidy + 'test/testcases/block/15_math/mathjax_preview.html', # bc of mathjax preview + 'test/testcases/block/15_math/mathjax_preview_simple.html', # bc of mathjax preview + 'test/testcases/block/15_math/mathjax_preview_as_code.html', # bc of mathjax preview + 'test/testcases/span/05_html/mark_element.html', # bc of tidy + 'test/testcases/block/09_html/xml.html', # bc of tidy + 'test/testcases/span/05_html/xml.html', # bc of tidy + 'test/testcases/block/04_header/with_header_links.html', # because of header_links option + ].compact + EXCLUDE_HTML_TEXT_FILES = [ + 'test/testcases/block/09_html/parse_as_span.htmlinput', + 'test/testcases/block/09_html/parse_as_raw.htmlinput', + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.{html,htmlinput}'].each do |html_file| + next if EXCLUDE_HTML_FILES.any? {|f| html_file =~ /#{f}/ } + + out_files = [] + out_files << [(html_file =~ /\.htmlinput$/ ? html_file.sub(/input$/, '') : html_file), :to_html] + if html_file =~ /\.htmlinput$/ && EXCLUDE_HTML_TEXT_FILES.none? {|f| html_file =~ /#{f}/ } + out_files << [html_file.sub(/htmlinput$/, 'text'), :to_kramdown] + end + out_files.select {|f, _| File.exist?(f) }.each do |out_file, out_method| + define_method('test_' + html_file.tr('.', '_') + "_to_#{File.extname(out_file)}") do + opts_file = html_file.sub(/\.html(input)?$/, '.options') + opts_file = File.join(File.dirname(html_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(html_file), options.merge(input: 'html')) + if out_method == :to_html + assert_equal(tidy_output(File.read(out_file)), tidy_output(doc.send(out_method))) + else + assert_equal(File.read(out_file), doc.send(out_method)) + end + end + end + end + end + + def tidy_output(out) + cmd = "tidy -q --doctype omit -utf8" + result, error, status = Open3.capture3(cmd, stdin_data: out) + if status.exitstatus == 2 + raise "Problem using tidy: #{error}" + end + result + end + + # Generate test methods for text-to-latex conversion and compilation + `latex -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping latex compilation tests because latex executable is missing") + else + EXCLUDE_LATEX_FILES = [ + 'test/testcases/span/01_link/image_in_a.text', # bc of image link + 'test/testcases/span/01_link/imagelinks.text', # bc of image links + 'test/testcases/span/01_link/empty_title.text', + 'test/testcases/span/04_footnote/markers.text', # bc of footnote in header + 'test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text', + 'test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text', + 'test/testcases/block/03_paragraph/standalone_image.text', # bc of standalone image + 'test/testcases/cjk-line-break.text', # latex unicode support + 'test/testcases/block/04_header/with_auto_ids.text', # bc of Unicode characters + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_LATEX_FILES.any? {|f| text_file =~ /#{f}$/ } + define_method('test_' + text_file.tr('.', '_') + "_to_latex_compilation") do + latex = Kramdown::Document.new(File.read(text_file), auto_ids: false, footnote_nr: 1, + template: 'document').to_latex + Dir.mktmpdir do |tmpdir| + result = IO.popen("latex -output-directory='#{tmpdir}' 2>/dev/null", 'r+') do |io| + io.write(latex) + io.close_write + io.read + end + assert($?.exitstatus == 0, result.scan(/^!(.*\n.*)/).join("\n")) + end + end + end + end + + # Generate test methods for text->kramdown->html conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping text->kramdown->html tests because tidy executable is missing") + else + EXCLUDE_TEXT_FILES = [ + 'test/testcases/span/05_html/markdown_attr.text', # bc of markdown attr + 'test/testcases/block/09_html/markdown_attr.text', # bc of markdown attr + 'test/testcases/span/extension/options.text', # bc of parse_span_html option + 'test/testcases/block/12_extension/options.text', # bc of options option + 'test/testcases/block/12_extension/options3.text', # bc of options option + 'test/testcases/block/09_html/content_model/tables.text', # bc of parse_block_html option + 'test/testcases/block/09_html/html_to_native/header.text', # bc of auto_ids option that interferes + 'test/testcases/block/09_html/html_to_native/table_simple.text', # bc of tr style attr getting removed + 'test/testcases/block/09_html/simple.text', # bc of webgen:block elements + 'test/testcases/block/11_ial/simple.text', # bc of change of ordering of attributes in header + 'test/testcases/span/extension/comment.text', # bc of comment text modifications (can this be avoided?) + 'test/testcases/block/04_header/header_type_offset.text', # bc of header_offset being applied twice + 'test/testcases/block/06_codeblock/rouge/simple.text', + 'test/testcases/block/06_codeblock/rouge/multiple.text', # check, what document contain more, than one code block + 'test/testcases/block/14_table/empty_tag_in_cell.text', # bc of tidy + 'test/testcases/span/01_link/link_defs_with_ial.text', # bc of attribute ordering + 'test/testcases/span/05_html/mark_element.text', # bc of tidy + 'test/testcases/block/09_html/xml.text', # bc of tidy + 'test/testcases/span/05_html/xml.text', # bc of tidy + 'test/testcases/block/03_paragraph/standalone_image.text', # bc of standalone image + 'test/testcases/cjk-line-break.text', + 'test/testcases/block/09_html/standalone_image_in_div.html', # bc of standalone image + 'test/testcases/span/abbreviations/abbrev_in_html.text', # bc of invalid abbr tag in SVG + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + next if EXCLUDE_TEXT_FILES.any? {|f| text_file =~ /#{f}$/ } + html_file = text_file.sub(/\.text$/, '.html') + next unless File.exist?(html_file) + define_method('test_' + text_file.tr('.', '_') + "_to_kramdown_to_html") do + opts_file = text_file.sub(/\.text$/, '.options') + opts_file = File.join(File.dirname(text_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + kdtext = Kramdown::Document.new(File.read(text_file), options).to_kramdown + html = Kramdown::Document.new(kdtext, options).to_html + assert_equal(tidy_output(File.read(html_file)), tidy_output(html)) + kdtext4 = Kramdown::Document.new(File.read(text_file), options.merge({list_indent: 4})).to_kramdown + html = Kramdown::Document.new(kdtext4, options).to_html + assert_equal(tidy_output(File.read(html_file)), tidy_output(html)) + end + end + end + + # Generate test methods for html-to-kramdown-to-html conversion + `tidy -v 2>&1` + if $?.exitstatus != 0 + warn("Skipping html-to-kramdown-to-html tests because tidy executable is missing") + else + EXCLUDE_HTML_KD_FILES = [ + 'test/testcases/span/extension/options.html', # bc of parse_span_html option + 'test/testcases/span/05_html/normal.html', # bc of br tag before closing p tag + 'test/testcases/block/12_extension/nomarkdown.html', # bc of nomarkdown extension + 'test/testcases/block/12_extension/options3.html', # bc of rouge + 'test/testcases/block/09_html/simple.html', # bc of webgen:block elements + 'test/testcases/block/09_html/markdown_attr.html', # bc of markdown attr + 'test/testcases/block/09_html/html_to_native/table_simple.html', # bc of invalidly converted simple table + 'test/testcases/block/06_codeblock/whitespace.html', # bc of entity to char conversion + 'test/testcases/block/06_codeblock/rouge/simple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/rouge/multiple.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/guess_lang_css_class.html', # bc of double surrounding
+ 'test/testcases/block/06_codeblock/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/06_codeblock/highlighting-opts.html', # bc of span elements inside code element + 'test/testcases/block/11_ial/simple.html', # bc of change of ordering of attributes in header + 'test/testcases/span/03_codespan/highlighting.html', # bc of span elements inside code element + 'test/testcases/block/04_header/with_auto_ids.html', # bc of auto_ids=true option + 'test/testcases/block/04_header/header_type_offset.html', # bc of header_offset option + 'test/testcases/block/16_toc/toc_exclude.html', # bc of different attribute ordering + 'test/testcases/span/autolinks/url_links.html', # bc of quot entity being converted to char + 'test/testcases/block/14_table/empty_tag_in_cell.html', # bc of tidy + 'test/testcases/span/01_link/link_defs_with_ial.html', # bc of attribute ordering + 'test/testcases/span/05_html/mark_element.html', # bc of tidy + 'test/testcases/block/09_html/xml.html', # bc of tidy + 'test/testcases/span/05_html/xml.html', # bc of tidy + 'test/testcases/block/03_paragraph/standalone_image.html', # bc of standalone image + 'test/testcases/block/15_math/normal.html', # bc of mathjax and HTML parser + 'test/testcases/block/15_math/gh_128.html', # bc of mathjax and HTML parser + 'test/testcases/span/04_footnote/backlink_inline.html', # bc of mathjax + 'test/testcases/block/09_html/standalone_image_in_div.html', # bc of standalone image + 'test/testcases/block/09_html/processing_instruction.html', # bc of PI + 'test/testcases/block/04_header/with_header_links.html', # bc of header_links option + ].compact + Dir[File.dirname(__FILE__) + '/testcases/**/*.html'].each do |html_file| + next if EXCLUDE_HTML_KD_FILES.any? {|f| html_file =~ /#{f}$/ } + define_method('test_' + html_file.tr('.', '_') + "_to_kramdown_to_html") do + kd = Kramdown::Document.new(File.read(html_file), input: 'html', + auto_ids: false, footnote_nr: 1).to_kramdown + opts_file = html_file.sub(/\.html$/, '.options') + opts_file = File.join(File.dirname(html_file), 'options') unless File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(kd, options) + assert_equal(tidy_output(File.read(html_file)), tidy_output(doc.to_html)) + end + end + end + + # Generate test methods for text-manpage conversion + Dir[File.dirname(__FILE__) + '/testcases/man/**/*.text'].each do |text_file| + define_method('test_' + text_file.tr('.', '_') + "_to_man_extra") do + man_file = text_file.sub(/\.text$/, '.man') + doc = Kramdown::Document.new(File.read(text_file)) + assert_equal(File.read(man_file), doc.to_man) + end + end + + EXCLUDE_MODIFY = [ + 'test/testcases/block/06_codeblock/rouge/multiple.text', # bc of HTMLFormater in options + 'test/testcases/block/04_header/with_header_links.text', # bc of header_links option + ].compact + + # Generate test methods for asserting that converters don't modify the document tree. + Dir[File.dirname(__FILE__) + '/testcases/**/*.text'].each do |text_file| + opts_file = text_file.sub(/\.text$/, '.options') + options = File.exist?(opts_file) ? YAML.load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + (Kramdown::Converter.constants.map(&:to_sym) - + [:Base, :RemoveHtmlTags, :MathEngine, :SyntaxHighlighter]).each do |conv_class| + next if EXCLUDE_MODIFY.any? {|f| text_file =~ /#{f}$/ } + define_method("test_whether_#{conv_class}_modifies_tree_with_file_#{text_file.tr('.', '_')}") do + doc = Kramdown::Document.new(File.read(text_file), options) + options_before = Marshal.load(Marshal.dump(doc.options)) + abbrev_proc = doc.root.options[:abbrev_defs].default_proc + doc.root.options[:abbrev_defs].default_proc = doc.root.options[:abbrev_attr].default_proc = nil + tree_before = Marshal.load(Marshal.dump(doc.root)) + doc.root.options[:abbrev_defs].default_proc = doc.root.options[:abbrev_attr].default_proc = + abbrev_proc + Kramdown::Converter.const_get(conv_class).convert(doc.root, doc.options) + assert_equal(options_before, doc.options) + assert_tree_not_changed(tree_before, doc.root) + end + end + end + + def assert_tree_not_changed(old, new) + assert_equal(old.type, new.type, "type mismatch") + if old.value.kind_of?(Kramdown::Element) + assert_tree_not_changed(old.value, new.value) + else + assert(old.value == new.value, "value mismatch") + end + assert_equal(old.attr, new.attr, "attr mismatch") + assert_equal(old.options, new.options, "options mismatch") + assert_equal(old.children.length, new.children.length, "children count mismatch") + + old.children.each_with_index do |child, index| + assert_tree_not_changed(child, new.children[index]) + end + end + +end diff --git a/bin/gems/kramdown-2.5.2/test/test_location.rb b/bin/gems/kramdown-2.5.2/test/test_location.rb new file mode 100644 index 00000000..533ba5f1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/test_location.rb @@ -0,0 +1,216 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown' + +Encoding.default_external = 'utf-8' + +describe 'location' do + # checks that +element+'s :location option corresponds to the location stored + # in the element.attr['class'] + def check_element_for_location(element) + if (match = /^line-(\d+)/.match(element.attr['class'] || '')) + expected_line = match[1].to_i + assert_equal(expected_line, element.options[:location]) + end + element.children.each do |child| + check_element_for_location(child) + end + end + + # Test cases consist of a kramdown string that uses IALs to specify the expected + # line numbers for a given element. + test_cases = { + 'autolink' => %(testing autolinks\n\n{:.line-3}), + 'blockquote' => %( + > block quote1 + > + > * {:.line-3} list item in block quote + > * {:.line-4} list item in block quote + > {:.line-3} + {:.line-1} + + > block quote2 + {:.line-8} + ), + 'codeblock' => %(\na para\n\n~~~~\ntest code 1\n~~~~\n{:.line-3}\n\n test code 2\n{:.line-8}\n), + 'codespan' => %(a para\n\nanother para ``{:.line-3} with code\n), + 'emphasis' => %( + para *span*{:.line-1} + {:.line-1} + + ## header *span*{:.line-4} + {:.line-4} + + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum *short span on single line*{:.line-11} + dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + *long span over multiple lines - proident, sunt in culpa qui officia deserunt + mollit anim id est laborum.*{:.line-13} + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + `code span`{:.line-18} + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + {:.line-7} + ), + 'header' => %( + # header1 + {:.line-1} + + ## header2 + {:.line-4} + + ## header3 + {:.line-7} + + header4 + ======= + {:.line-10} + + ^ + + header5 + ------- + {:.line-16} + ), + 'horizontal_rule' => %(\na para\n\n----\n{:.line-3}\n), + 'html_entity' => "a para\n\nanother para with &{:.line-3} html entity.\n", + 'link' => %( + a para + + This is [a link](http://rubyforge.org){:.line-3} to a page. + + Here comes a ![smiley](../images/smiley.png){:.line-5} + ), + 'list' => %( + * {:.line-1} list item + * {:.line-2} list item + * {:.line-3} list item + {:.line-1} + + {:.line-7} + 1. {:.line-7} list item + 2. {:.line-8} list item + 3. {:.line-9} list item + + {:.line-12} + definition term 1 + : {:.line-13} definition definition 1 + definition term 2 + : {:.line-15} definition definition 2 + ), + 'math_block' => %(\na para\n\n$$5+5$$\n{:.line-3}\n), + 'math_inline' => %(\na para\n\nanother para with inline math $$5+5$${:.line-3}\n), + 'paragraph' => %( + para1 + {:.line-1} + + para2 + {:.line-4} + + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + {:.line-7} + + {:.line-14} + para with leading IAL + ), + 'table' => %( + a para + + |first|second|third| + |-----|------|-----| + |a |b |c | + {:.line-3} + ), + 'typographic_symbol' => %( + a para + + another para ---{:.line-3} + + another para ...{:.line-5} + ), + 'gh issue 129' => %( + `|` + {:.line-1} + ), + 'gh issue 131' => %( + * {:.line-1} test + line 2 + * {:.line-3} second + * {:.line-4} third + * {:.line-5} * {:.line-5} one + * {:.line-6} two + ), + 'gh issue 158' => %( + 😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁😁 + {:.line-1} + + - {:.line-4} T + {:.line-4} + + # T + {:.line-7} + ), + 'gh issue 243 - HTML raw elements' => %( +
    +
  • Test
  • +
+ ), + } + test_cases.each do |name, test_string| + it "Handles #{name}" do + doc = Kramdown::Document.new(test_string.gsub(/^ /, '').strip) + check_element_for_location(doc.root) + end + end + + it 'adds location info to duplicate abbreviation definition warnings' do + test_string = %(This snippet contains a duplicate abbreviation definition + +*[duplicate]: The first definition +*[duplicate]: The second definition + ) + doc = Kramdown::Document.new(test_string.strip) + assert_equal(["Duplicate abbreviation ID 'duplicate' on line 4 - overwriting"], doc.warnings) + end + + it 'handles abbreviations' do + str = "This *is* ABC and\n**and** ABC second\nanother ABC\nas ABC as\nABC at the end.\n\n*[ABC]: ABC" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :abbreviation }.each_with_index do |e, i| + assert_equal(i + 1, e.options[:location]) + end + end + + it 'handles line breaks' do + str = "First \nsecond\\\\\nthird \n" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :br }.each_with_index do |e, i| + assert_equal(i + 1, e.options[:location]) + end + end + + it 'handles smart quotes' do + str = "This is 'first'\nand 'second' and\n'third'" + doc = Kramdown::Document.new(str) + doc.root.children.first.children.select {|e| e.type == :smart_quote }.each_with_index do |e, i| + assert_equal(((i + 1) / 2.0).ceil, e.options[:location]) + end + end +end diff --git a/bin/gems/kramdown-2.5.2/test/test_string_scanner_kramdown.rb b/bin/gems/kramdown-2.5.2/test/test_string_scanner_kramdown.rb new file mode 100644 index 00000000..7efc4d6e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/test_string_scanner_kramdown.rb @@ -0,0 +1,27 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2009-2026 Thomas Leitner +# +# This file is part of kramdown which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown/utils/string_scanner' + +describe Kramdown::Utils::StringScanner do + [ + ["...........X............", [/X/], 1], + ["1\n2\n3\n4\n5\n6X", [/X/], 6], + ["1\n2\n3\n4\n5\n6X\n7\n8X", [/X/, /X/], 8], + [(".\n" * 1000) + 'X', [/X/], 1001], + ].each_with_index do |test_data, i| + test_string, scan_regexes, expect = test_data + it "computes the correct current_line_number for example ##{i + 1}" do + str_sc = Kramdown::Utils::StringScanner.new(test_string) + scan_regexes.each {|scan_re| str_sc.scan_until(scan_re) } + assert_equal(expect, str_sc.current_line_number) + end + end +end diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.html b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.text b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.text new file mode 100644 index 00000000..2cbdaa62 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/spaces.text @@ -0,0 +1,3 @@ + + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.html b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.text b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.text new file mode 100644 index 00000000..69d6a470 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/01_blank_line/tabs.text @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.html b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.text b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.text new file mode 100644 index 00000000..8d158026 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/beginning.text @@ -0,0 +1,3 @@ +^ + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.text new file mode 100644 index 00000000..db56ec3b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/end.text @@ -0,0 +1,3 @@ + + +^ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.html b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.html @@ -0,0 +1 @@ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.text b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.text new file mode 100644 index 00000000..87210a14 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/02_eob/middle.text @@ -0,0 +1,5 @@ + + +^ + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html new file mode 100644 index 00000000..810cfc09 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html @@ -0,0 +1,18 @@ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +
This is a code block.
+
+ +

And this is another.

+ +

A para + with + mixed +indents. + and with much indent

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html.gfm b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html.gfm new file mode 100644 index 00000000..4440c62e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.html.gfm @@ -0,0 +1,18 @@ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +

This is a para.

+ +
This is a code block.
+
+ +

And this is another.

+ +

A para +
with +
mixed +
indents. +
and with much indent

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.text new file mode 100644 index 00000000..5849f5b7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/indented.text @@ -0,0 +1,19 @@ +This is a para. + + This is a para. + + This is a para. + + This is a para. + + This is a code block. + + + +And this is another. + +A para + with + mixed +indents. + and with much indent diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.html new file mode 100644 index 00000000..9bc47dbf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.html @@ -0,0 +1,9 @@ +

First line
+https://example.com

+ +

First line
+https://example.com

+ +

Last Line

+ +

Last Line\

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.text new file mode 100644 index 00000000..bbc4cc53 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/line_break_last_line.text @@ -0,0 +1,9 @@ +First line + + +First line\\ + + +Last Line + +Last Line\\ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.html new file mode 100644 index 00000000..6a209e21 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.html @@ -0,0 +1,5 @@ +

One paragraph +over + multiple lines.

+ +

Second one without newline.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.text new file mode 100644 index 00000000..7f1169d6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/no_newline_at_end.text @@ -0,0 +1,5 @@ + One paragraph +over + multiple lines. + +Second one without newline. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.html new file mode 100644 index 00000000..0d20e175 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.html @@ -0,0 +1 @@ +

This is just a normal paragraph.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.text new file mode 100644 index 00000000..0b01324f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/one_para.text @@ -0,0 +1 @@ +This is just a normal paragraph. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.html new file mode 100644 index 00000000..7faa971f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.html @@ -0,0 +1,13 @@ +

para

+ +
+ standalone image +
standalone image
+
+ +
+ standalone image +
standalone image
+
+ +

para

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.text new file mode 100644 index 00000000..3010140c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/standalone_image.text @@ -0,0 +1,9 @@ +para +{:standalone} + +![standalone image](some.jpg){:#id .class key="value" standalone} + +![standalone image](some.jpg){:#id .class key="value" standalone} +{:#block-id .block-class block-key="block-value"} + +para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.kramdown b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.kramdown new file mode 100644 index 00000000..2108d98d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.kramdown @@ -0,0 +1,7 @@ +aa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa +\: No definiion list + +a: + +*a*: + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.text new file mode 100644 index 00000000..031d2d18 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/to_kramdown.text @@ -0,0 +1,5 @@ +aa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa : No definiion list + +a: + +*a*: diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.html new file mode 100644 index 00000000..d6194ea9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.html @@ -0,0 +1,4 @@ +

This is just a normal paragraph. +That goes on to the second line.

+ +

Another paragraph.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.text new file mode 100644 index 00000000..b0c730db --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/two_para.text @@ -0,0 +1,4 @@ +This is just a normal paragraph. +That goes on to the second line. + +Another paragraph. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.html b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.html new file mode 100644 index 00000000..a8831e66 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.html @@ -0,0 +1 @@ +

some text

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.options b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.text b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.text new file mode 100644 index 00000000..e5fe18a6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/03_paragraph/with_html_to_native.text @@ -0,0 +1 @@ +

some text diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.html new file mode 100644 index 00000000..07041072 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.html @@ -0,0 +1,57 @@ +

This is a header

+ +

This is a header

+ +

This is a header

+ +

This is a header

+ +
This is a header
+ +
This is a header
+ +

Header

+

Header

+ +

Header

+
+

blockquote

+
+ +
header
+

paragraph

+ +
+

blockquote +### not a header

+
+ +

header

+ +

header

+ +

header

+ +

header #

+ +

header

+ +

#

+ +

#

+ +

Header

+ +

Header

+ +

Header

+ +

Header

+ +

Header {#9ab}

+ +

Header{#noid}

+ +

Header ##{#noid}

+ +

Last

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.text new file mode 100644 index 00000000..392b3f69 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header.text @@ -0,0 +1,54 @@ +# This is a header + +## This is a header + +### This is a header + +#### This is a header + +##### This is a header + +###### This is a header + +# Header +^ +# Header + +##Header ##### +> blockquote + +###### header +paragraph + +> blockquote +### not a header + +# header # + +# header# + +#header# + +# header \# + +# header + +# + +# + +### Header {#id} + +### Header ## {#Id} + +### Header ## {#id} + +### Header {#A-Za-z0-9_:t} + +### Header {#9ab} + +### Header{#noid} + +### Header ##{#noid} + +### Last diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.html new file mode 100644 index 00000000..9f49c3bf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.html @@ -0,0 +1 @@ +

header

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.text new file mode 100644 index 00000000..7b74be4d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/atx_header_no_newline_at_end.text @@ -0,0 +1 @@ +# header \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.html new file mode 100644 index 00000000..e031b9a6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.html @@ -0,0 +1,11 @@ +

Lorem ipsum

+ +

Lorem ipsum

+ +

Lorem ipsum

+ +
Lorem ipsum
+ +

Lorem ipsum

+ +

Lorem ipsum

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.kramdown b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.kramdown new file mode 100644 index 00000000..a77deb9b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.kramdown @@ -0,0 +1,12 @@ +## Lorem ipsum + +### Lorem ipsum + +#### Lorem ipsum + +###### Lorem ipsum + +## Lorem ipsum + +### Lorem ipsum + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.latex new file mode 100644 index 00000000..c9017e6e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.latex @@ -0,0 +1,12 @@ +\subsection*{Lorem ipsum} + +\subsubsection*{Lorem ipsum} + +\paragraph*{Lorem ipsum} + +\subparagraph*{Lorem ipsum} + +\subsection*{Lorem ipsum} + +\subsubsection*{Lorem ipsum} + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.options b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.options new file mode 100644 index 00000000..a8050358 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.options @@ -0,0 +1,2 @@ +:header_offset: 1 +:auto_ids: false \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.text new file mode 100644 index 00000000..bfaefa28 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/header_type_offset.text @@ -0,0 +1,13 @@ +# Lorem ipsum + +## Lorem ipsum + +### Lorem ipsum + +###### Lorem ipsum + +Lorem ipsum +=========== + +Lorem ipsum +----------- diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.html new file mode 100644 index 00000000..147c3451 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.html @@ -0,0 +1,32 @@ +

test

+ +

test2

+ +

test

+

para

+ +
   header =
+
+ +

=

+ +

This is a para. +With two lines. +And not a header. +=================

+ +
+

Blockquote. +Not a Header +-

+
+ +

header

+ +

header

+ +

header

+ +

header{#noid}

+ +

header

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.text new file mode 100644 index 00000000..ae94ecd8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header.text @@ -0,0 +1,39 @@ +test +- + +test2 +========= + +test +- +para + + header += + + += + +This is a para. +With two lines. +And not a header. +================= + +> Blockquote. +Not a Header +- + +header {#id} +------------ + +header {#Id} +====== + +header {#A-Za-z0-9_:} +------ + +header{#noid} +----- + +header +------ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.html new file mode 100644 index 00000000..9f49c3bf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.html @@ -0,0 +1 @@ +

header

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.text new file mode 100644 index 00000000..0f00750a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/setext_header_no_newline_at_end.text @@ -0,0 +1,2 @@ +header +====== \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.html new file mode 100644 index 00000000..724d391b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.html @@ -0,0 +1,3 @@ +

Header 1

+ +

123

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.options b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.options new file mode 100644 index 00000000..83305cbe --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.options @@ -0,0 +1,2 @@ +:auto_ids: true +:auto_id_prefix: hallo_ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.text new file mode 100644 index 00000000..acf09fe4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_prefix.text @@ -0,0 +1,3 @@ +# Header 1 + +# 123 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.html new file mode 100644 index 00000000..1d342cd6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.html @@ -0,0 +1 @@ +

This is a header

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.options b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.options new file mode 100644 index 00000000..68800f69 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.options @@ -0,0 +1 @@ +:auto_id_stripping: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.text new file mode 100644 index 00000000..2b57bc8d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_id_stripping.text @@ -0,0 +1 @@ +# This is a header diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.html new file mode 100644 index 00000000..af8126d5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.html @@ -0,0 +1,21 @@ +

This is a header

+ +

12. Another one-1-here

+ +

Do ^& it now

+ +

Hallo

+ +

Not now

+ +

Hallo

+ +

23232

+ +

33333

+ +

hallO

+ +

Header without ID

+ +

Transliterated: Đây-là-ví-dụ

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.options b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.options new file mode 100644 index 00000000..0a1fec87 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.options @@ -0,0 +1,2 @@ +:auto_ids: true +:transliterated_header_ids: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.text new file mode 100644 index 00000000..f4cd91b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_auto_ids.text @@ -0,0 +1,24 @@ +# This is a header + +## 12. Another one-1-here + +### Do ^& it now + +Hallo +===== + +Not now +------- + +# Hallo + +# 23232 + +# 33333 + +## hallO + +# Header without ID +{: id=""} + +# Transliterated: Đây-là-ví-dụ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.html new file mode 100644 index 00000000..64ae37f4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.html @@ -0,0 +1,7 @@ +

This is a header

+ +

12. Another one-1-here

+ +

Do ^& it now

+ +

Header without ID

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.options b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.options new file mode 100644 index 00000000..87f9047c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.options @@ -0,0 +1,2 @@ +:header_links: true +:auto_ids: false diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.text new file mode 100644 index 00000000..0166e29f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_header_links.text @@ -0,0 +1,8 @@ +# This is a header {#header} + +## 12. Another one-1-here + +### Do ^& it now + +# Header without ID +{: id=""} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.html b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.html new file mode 100644 index 00000000..880dc9e4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.html @@ -0,0 +1 @@ +

foo
bar

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.text b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.text new file mode 100644 index 00000000..c7fe2ab0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/04_header/with_line_break.text @@ -0,0 +1 @@ +# foo
bar diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.html new file mode 100644 index 00000000..734bb7a1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.html @@ -0,0 +1,25 @@ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
+

A normal blockquote.

+
+ +
> A codeblock
+
+ +
+

Blockquote +with +mixed +indents.

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.text new file mode 100644 index 00000000..70850b0d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/indented.text @@ -0,0 +1,14 @@ +> A normal blockquote. + + > A normal blockquote. + + > A normal blockquote. + + > A normal blockquote. + + > A codeblock + +> Blockquote + > with + >mixed +> indents. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.html new file mode 100644 index 00000000..00a21024 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.html @@ -0,0 +1,34 @@ +
+

This is a long +long line.

+
+ +
+
+

Nested quote +inside +still inside

+
+
+ +
+
+

This is a subquote. +over multipline lines. +continuing +here

+
+
+ +
+

This is a quote + no code

+
+ +
+

This is a quote

+
+ +
+

This is a quote

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.text new file mode 100644 index 00000000..adde6a67 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/lazy.text @@ -0,0 +1,20 @@ +> This is a long +long line. + +> > Nested quote +inside +> still inside + +> > This is a subquote. +> > over multipline lines. +> continuing +here + +> This is a quote + no code + +> This is a quote +{: #id} + +> This is a quote +^ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.html new file mode 100644 index 00000000..4bc94f08 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.html @@ -0,0 +1,10 @@ +
+

foo

+ +
+

bar + baz

+
+ +

foo

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.text new file mode 100644 index 00000000..2176882c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/nested.text @@ -0,0 +1,6 @@ +> foo +> +> > bar +>> baz +> +> foo diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.html new file mode 100644 index 00000000..1de4a60f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.html @@ -0,0 +1,4 @@ +
+

This is a block quote +with no newline.

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.text new file mode 100644 index 00000000..402648ad --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/no_newline_at_end.text @@ -0,0 +1,2 @@ +> This is a block quote +> with no newline. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.html new file mode 100644 index 00000000..4a9aaf5e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.html @@ -0,0 +1,3 @@ +
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.text new file mode 100644 index 00000000..a2b33bdf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/very_long_line.text @@ -0,0 +1 @@ +> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.html b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.html new file mode 100644 index 00000000..30abd99e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.html @@ -0,0 +1,15 @@ +
+

Example:

+ +
sub status {
+    print "working";
+}
+
+ +

Or:

+ +
sub status {
+    return "working";
+}
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.text b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.text new file mode 100644 index 00000000..3b188dd4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/05_blockquote/with_code_blocks.text @@ -0,0 +1,11 @@ +>Example: +> +> sub status { +> print "working"; +> } +> +> Or: +> +> sub status { +> return "working"; +> } diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.html new file mode 100644 index 00000000..142a5d34 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.html @@ -0,0 +1,4 @@ +
x = Class.new
+
+
<a>href</a>
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.options new file mode 100644 index 00000000..72e9bc1e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.options @@ -0,0 +1 @@ +:enable_coderay: false diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.text new file mode 100644 index 00000000..af4d0bde --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/disable-highlighting.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: lang="html"} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.html new file mode 100644 index 00000000..d9f9da32 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.html @@ -0,0 +1,4 @@ +

Some para

+ +

~~~~~~ +not codeblock

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.text new file mode 100644 index 00000000..60ea366c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/error.text @@ -0,0 +1,4 @@ +Some para + +~~~~~~ +not codeblock diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.html new file mode 100644 index 00000000..066e909f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.html @@ -0,0 +1,15 @@ +
class Foo
+  def bar
+    puts 'Hello'
+  end
+end
+
+
+ +
class Foo
+  def bar
+    puts 'Hello'
+  end
+end
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.options new file mode 100644 index 00000000..bfc92f45 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.options @@ -0,0 +1,2 @@ +:syntax_highlighter_opts: + guess_lang: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.text new file mode 100644 index 00000000..4b074a8a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/guess_lang_css_class.text @@ -0,0 +1,13 @@ +~~~ +class Foo + def bar + puts 'Hello' + end +end +~~~ + + class Foo + def bar + puts 'Hello' + end + end diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex new file mode 100644 index 00000000..a092a1f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.latex @@ -0,0 +1,9 @@ +\begin{minted}[breaklines,linenos]{ruby} +x = Class.new + +\end{minted} + +\begin{minted}[breaklines,linenos]{html} +this is a reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, long link + +\end{minted} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options new file mode 100644 index 00000000..b773fc8f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.options @@ -0,0 +1,4 @@ +:syntax_highlighter: minted +:syntax_highlighter_opts: + wrap: true + line_numbers: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text new file mode 100644 index 00000000..26365189 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted-with-opts.text @@ -0,0 +1,5 @@ + x = Class.new +{: .language-ruby} + + this is a reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, reaally, long link +{: .language-html} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.latex new file mode 100644 index 00000000..354d6ab9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.latex @@ -0,0 +1,8 @@ +\begin{minted}[]{ruby} +x = Class.new + +\end{minted} +\begin{minted}[]{html} +href + +\end{minted} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.options new file mode 100644 index 00000000..b2ee189a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.options @@ -0,0 +1,3 @@ +:syntax_highlighter: minted +:syntax_highlighter_opts: + default_lang: ruby diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-minted.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.html new file mode 100644 index 00000000..b694d375 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.html @@ -0,0 +1,6 @@ +
x = Class.new
+
+
+
<a>href</a>
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.options new file mode 100644 index 00000000..be21a32e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.options @@ -0,0 +1,7 @@ +:syntax_highlighter_opts: + block: + css: class + default_lang: ruby + wrap: span + line_numbers: null + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting-opts.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.html new file mode 100644 index 00000000..33dd015a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.html @@ -0,0 +1,5 @@ +
x = Class.new
+
+
<a>href</a>
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.options new file mode 100644 index 00000000..8133537d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.options @@ -0,0 +1,5 @@ +:coderay_default_lang: ruby +:coderay_wrap: span +:coderay_line_numbers: ~ +:coderay_css: class + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.text new file mode 100644 index 00000000..5ac47460 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/highlighting.text @@ -0,0 +1,4 @@ + x = Class.new +^ + href +{: .language-html} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.html new file mode 100644 index 00000000..b096a9ed --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.html @@ -0,0 +1,164 @@ + +

B

+ +
                       BBBBBBBB. 
+
+
+
+           BBBB BB BBBBBBBB BBBBB. BBBBBBB BB BBBBB BB BBB BBBB BBBBB BBB BBB BBBB BBB BBBBBBB BBB BBBBBBB. B BBB'B BBBBB BBBB BBB BBBB BBBBBBB BBBB BBBB BBBB BBBBBBBB.
+
+
+                BBB BBBBB BBBBB BBB BBBB BBBB BBBB, BBB BBBBB BB BBBBB BBB BB BBBBBB BBBB BBB BBBBB BBBB BB. BBBBB BBB BBBBB BBBBB BBB BBBB BB BBBB BBBB BBBBB.
+
+
+                         BBBB BBBBB, BBBBB, BBBBBBBB?
+
+                   BB BBB BB BBBB BBB BBBB BBB BBBBBB /BBB BB BBBBBBBBB BBBB BBBBBBB BBBBBB BB BBB. 
+
+
+                   BBBB BBBBBBBB BBB BBBB BB BBBBB BBB BBBBBB BBBB BBBBB BBBBBB BBBBBBBBB BBBB BB BBBBB......................................................................
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+              BBBBB B'B BBB BBBBB. BBBB BBBBB BBBBB. ( B BBBBB BBBBBBBBBB BBBBB BBBB'B BBBBB BBBBB. BBB BBBB BBBBB BBBB BBBB. BBBBBBB BBB BB BBBBBBB BBB BBB B BBBB BBBBBBBBBBBB. BBBBB BBBBB.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+             BBBB'B BB
+
+ +

.

+ +
        B BBB BBB BBB ? B. B BBB BBBBBB BBBB BBB BBBB. BBBBBBB BB BBBBBBB B BBBB BBBB BBB BBBBBB. 
+
+
+
+
+
+
+
+
+
+
+
+
+
+         BBBB BB 'BBBB' BBBB BBBBB.
+
+
+                           BBBBBBBB B BBBB BBBBBB BB BBBBBBBB BBB BBBBBBB BBBBBBB BBBBBBB. 
+
+
+     B BBBB BB BBBB. BBBBB BBBBBBBB. BBB BB BB. BB BB BBBB BB BBBBBBBBBB. BB BBBBBBBB BB BBBBBBBBB. 
+
+
+                     BBBBBBBB BB BBBB. BBBBBBB BBB BBBBB BBBBB BBBBB. B'BB BBBBBBB BB BBBBB BBBBB BBBBBBB BBB BBBBB. BBBB. 
+
+  B BBBBBB BBBB BB BBBB BBB. (BB BBB BBBBB BBBBB...............B)
+
+
+
+           BBBB!
+
+
+
+         BBBB BB BBB BBBBBBB BBBBBB.            B
+
+ +

B

+ +
     BBBBB BB/BBB BBBBB!  BBBB BBBB BBBBBBBBBBB 'BBB'B BBBBBB.' 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          BBBB BBBBBBB BBBB BB BBB BBBBBBBB BB BBBB BBBBBB BBB BBBBBBBBB BBBB. BBBBBBBB BBBBBBB BBBB BBBB BBBB BB BBBB BB BBBB BB BBBB B BBB BB BBBBB BBBBBB.  B BBBB BBBBBBB BB BBBB BBBBB B BBB BBBBBBB BB BBBBB BBBB. BBB BBBBBBB BBBB. B BBB BBBB BBBB B BBBB BBBBBB BBB B BBBBBB BBBBBB. BBB BB BBBBBB BBBBBB BBBBBBBBBB BB...BBBBB BBBB BBBB BB BBBBB. (BBBBBBB BBB BBBBBB BBB'B BBBB BBB BBBBB BBB BB BBBBB BBBBBBBBBBB  BBBBB B BBBB BBBB BBBBB. 
+
+
+
+
+
+
+
+
+
+BBBBB BB BB BBBB B'B BBBB BBBBB BBBBB BBB BB BBBBBB/BBB (BBBBB) BBBBBB BB. 
+                          BBBBBBBB. B BBB BBBB BB BB BBB/BBBBBB BBBBBB BBB BBBB BBBBBBBB BB BB B BBBBBB BBBBBB BBBBB. (BBB/B BBB BBBB BBBB...BBB BBB BBB BBBB BB BB B BBBB BB BBB BB? BBBBBBB B BBB B BBBB BBBBBBBB BBB B BBB BBB BBBBB BBBB BBB BBBB BB B BBBBBBBB BB BBBBB BB BB BBB BBBBB BBB BB BBBBB BBBBBBB B BBB BBBBBBB. BBBBBB (BBBBB) BBBB BBBBB BBBBBBB BBBBB BBBB BBBB BBB. 100 BBBBBB BB BBBBB. BBBB BBB BBB BBBBBB BBB BB. BBB BBBB BB BBB BBBBB! BBB BB BBBBBB BBBBB B BBB'B BBBBBBBBB BBBB BBB BBB. (BBBBBB BBBBBBB BB BBBB BBBBB (BBBBBB BBBBB BBBBB BBBBB.))
+
+
+    BBB B BBBBBBBBBBB BBBB BBB BB BBB. BBBBB BBB BBBBB B BBBB BBBBBB BBBBB BBB. BB BBBBBB BBB BBBB B BBB BB BBBBBBBB BBBBBB BBBB BBB B BBBBBB BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBBBBBB.
+
+
+
+
+
+
+
+
+
+
+
+           BBBBB!!!!!!!
+
+
+         B BBB BBBB BBBBBB BBBB BBBB BBBB B BBB BBBBB BBB BBBBB B BBBB BBBBBBB BB BB BBBB BBBBBBBBB. B BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBB.
+
+                                               BB BB, BB BBBBBB BBBB, (BBBBBB BB BBB BBBB . BBBBB BB BBBB BBBB BB BB BBBB BBBB B BBBB BB BB (BB BBBB BB BBB BBBBBBB BB BBBBBBB. )) BB'BB BBB BBB'B BB BB BBBB BB B BBBB B BBBBB (BB BBBBBB BB BBB B'BB BBBBBBBB BB BBBB BBBB.)
+
+
+  B BBBBB B'BB BBB BB BBBB BBB BBB.
+
+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.test b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.test new file mode 100644 index 00000000..87f81c91 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/issue_gh45.test @@ -0,0 +1,188 @@ + + + B + + + + + BBBBBBBB. + + + + BBBB BB BBBBBBBB BBBBB. BBBBBBB BB BBBBB BB BBB BBBB BBBBB BBB BBB BBBB BBB BBBBBBB BBB BBBBBBB. B BBB'B BBBBB BBBB BBB BBBB BBBBBBB BBBB BBBB BBBB BBBBBBBB. + + + BBB BBBBB BBBBB BBB BBBB BBBB BBBB, BBB BBBBB BB BBBBB BBB BB BBBBBB BBBB BBB BBBBB BBBB BB. BBBBB BBB BBBBB BBBBB BBB BBBB BB BBBB BBBB BBBBB. + + + BBBB BBBBB, BBBBB, BBBBBBBB? + + BB BBB BB BBBB BBB BBBB BBB BBBBBB /BBB BB BBBBBBBBB BBBB BBBBBBB BBBBBB BB BBB. + + + BBBB BBBBBBBB BBB BBBB BB BBBBB BBB BBBBBB BBBB BBBBB BBBBBB BBBBBBBBB BBBB BB BBBBB...................................................................... + + + + + + + + + + + + + + + + + + + + + + BBBBB B'B BBB BBBBB. BBBB BBBBB BBBBB. ( B BBBBB BBBBBBBBBB BBBBB BBBB'B BBBBB BBBBB. BBB BBBB BBBBB BBBB BBBB. BBBBBBB BBB BB BBBBBBB BBB BBB B BBBB BBBBBBBBBBBB. BBBBB BBBBB.) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BBBB'B BB + + + + + + + + + + + + + + + + + + +. + + B BBB BBB BBB ? B. B BBB BBBBBB BBBB BBB BBBB. BBBBBBB BB BBBBBBB B BBBB BBBB BBB BBBBBB. + + + + + + + + + + + + + + BBBB BB 'BBBB' BBBB BBBBB. + + + BBBBBBBB B BBBB BBBBBB BB BBBBBBBB BBB BBBBBBB BBBBBBB BBBBBBB. + + + B BBBB BB BBBB. BBBBB BBBBBBBB. BBB BB BB. BB BB BBBB BB BBBBBBBBBB. BB BBBBBBBB BB BBBBBBBBB. + + + BBBBBBBB BB BBBB. BBBBBBB BBB BBBBB BBBBB BBBBB. B'BB BBBBBBB BB BBBBB BBBBB BBBBBBB BBB BBBBB. BBBB. + + B BBBBBB BBBB BB BBBB BBB. (BB BBB BBBBB BBBBB...............B) + + + + BBBB! + + + + BBBB BB BBB BBBBBBB BBBBBB. +B + +B + + + + BBBBB BB/BBB BBBBB! BBBB BBBB BBBBBBBBBBB 'BBB'B BBBBBB.' + + + + + + + + + + + + + + + BBBB BBBBBBB BBBB BB BBB BBBBBBBB BB BBBB BBBBBB BBB BBBBBBBBB BBBB. BBBBBBBB BBBBBBB BBBB BBBB BBBB BB BBBB BB BBBB BB BBBB B BBB BB BBBBB BBBBBB. B BBBB BBBBBBB BB BBBB BBBBB B BBB BBBBBBB BB BBBBB BBBB. BBB BBBBBBB BBBB. B BBB BBBB BBBB B BBBB BBBBBB BBB B BBBBBB BBBBBB. BBB BB BBBBBB BBBBBB BBBBBBBBBB BB...BBBBB BBBB BBBB BB BBBBB. (BBBBBBB BBB BBBBBB BBB'B BBBB BBB BBBBB BBB BB BBBBB BBBBBBBBBBB BBBBB B BBBB BBBB BBBBB. + + + + + + + + + + BBBBB BB BB BBBB B'B BBBB BBBBB BBBBB BBB BB BBBBBB/BBB (BBBBB) BBBBBB BB. + BBBBBBBB. B BBB BBBB BB BB BBB/BBBBBB BBBBBB BBB BBBB BBBBBBBB BB BB B BBBBBB BBBBBB BBBBB. (BBB/B BBB BBBB BBBB...BBB BBB BBB BBBB BB BB B BBBB BB BBB BB? BBBBBBB B BBB B BBBB BBBBBBBB BBB B BBB BBB BBBBB BBBB BBB BBBB BB B BBBBBBBB BB BBBBB BB BB BBB BBBBB BBB BB BBBBB BBBBBBB B BBB BBBBBBB. BBBBBB (BBBBB) BBBB BBBBB BBBBBBB BBBBB BBBB BBBB BBB. 100 BBBBBB BB BBBBB. BBBB BBB BBB BBBBBB BBB BB. BBB BBBB BB BBB BBBBB! BBB BB BBBBBB BBBBB B BBB'B BBBBBBBBB BBBB BBB BBB. (BBBBBB BBBBBBB BB BBBB BBBBB (BBBBBB BBBBB BBBBB BBBBB.)) + + + BBB B BBBBBBBBBBB BBBB BBB BB BBB. BBBBB BBB BBBBB B BBBB BBBBBB BBBBB BBB. BB BBBBBB BBB BBBB B BBB BB BBBBBBBB BBBBBB BBBB BBB B BBBBBB BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBBBBBB. + + + + + + + + + + + + BBBBB!!!!!!! + + + B BBB BBBB BBBBBB BBBB BBBB BBBB B BBB BBBBB BBB BBBBB B BBBB BBBBBBB BB BB BBBB BBBBBBBBB. B BBBB BBBBBB BBBBBBB BBBB BBBB BBB BBBB. + + BB BB, BB BBBBBB BBBB, (BBBBBB BB BBB BBBB . BBBBB BB BBBB BBBB BB BB BBBB BBBB B BBBB BB BB (BB BBBB BB BBB BBBBBBB BB BBBBBBB. )) BB'BB BBB BBB'B BB BB BBBB BB B BBBB B BBBBB (BB BBBBBB BB BBB B'BB BBBBBBBB BB BBBB BBBB.) + + + B BBBBB B'BB BBB BB BBBB BBB BBB. + + + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.html new file mode 100644 index 00000000..47188f2e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.html @@ -0,0 +1,4 @@ +
This is some code
+
+This is some  other code
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.text new file mode 100644 index 00000000..2a95de65 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/lazy.text @@ -0,0 +1,5 @@ + This is some +code + + This is some + other code diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.html new file mode 100644 index 00000000..7a003b28 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.html @@ -0,0 +1,2 @@ +
test  
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.text new file mode 100644 index 00000000..b64563f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end.text @@ -0,0 +1 @@ + test \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.html new file mode 100644 index 00000000..005870eb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.html @@ -0,0 +1,2 @@ +
test   test
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.text new file mode 100644 index 00000000..65df71e8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/no_newline_at_end_1.text @@ -0,0 +1,2 @@ + test +test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.html new file mode 100644 index 00000000..0bd2c1f4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.html @@ -0,0 +1,13 @@ +
starting code
+
+ +

paragraph

+ +
other code  
+with samples 
+
+ +

paragraph

+ +
  ending code
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.text new file mode 100644 index 00000000..40ea7023 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/normal.text @@ -0,0 +1,10 @@ + starting code + +paragraph + + other code + with samples + +paragraph + + ending code diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.html new file mode 100644 index 00000000..2cc34d30 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.html @@ -0,0 +1,2 @@ +
x = Class.new
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.options new file mode 100644 index 00000000..5688828c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + block: + disable: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.text new file mode 100644 index 00000000..0e50b41c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/disabled.text @@ -0,0 +1 @@ + x = Class.new diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.html new file mode 100644 index 00000000..6ece5432 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.html @@ -0,0 +1,11 @@ +
puts "Hello"
+
+
+ +
puts "World"
+
+
+ +
$foo = new Bar;
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.options new file mode 100644 index 00000000..b910f756 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + default_lang: ruby + formatter: RougeHTMLFormatters diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.text new file mode 100644 index 00000000..d1dd283b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/multiple.text @@ -0,0 +1,11 @@ +~~~ ruby +puts "Hello" +~~~ + +~~~ ruby +puts "World" +~~~ + +~~~ php?start_inline=1 +$foo = new Bar; +~~~ \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.html new file mode 100644 index 00000000..1c2259af --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.html @@ -0,0 +1,10 @@ +
x = Class.new
+
+
+
<a>href</a>
+
+
+ +
$foo = new Bar;
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.options new file mode 100644 index 00000000..f59e0ff8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.options @@ -0,0 +1,3 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + default_lang: ruby diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.text new file mode 100644 index 00000000..6c740e53 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/rouge/simple.text @@ -0,0 +1,9 @@ + x = Class.new +^ + href +{: .language-html} + + +~~~ php?start_inline=1 +$foo = new Bar; +~~~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.html new file mode 100644 index 00000000..1ddd91e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.html @@ -0,0 +1,7 @@ +
Here comes some code.
+
+ +
~~~~~~~
+code with tildes
+~~~~~~~~
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.text new file mode 100644 index 00000000..7625a1bd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/tilde_syntax.text @@ -0,0 +1,9 @@ +~~~~~~~~ +Here comes some code. +~~~~~~~~ + +~~~~~~~~~~~~ +~~~~~~~ +code with tildes +~~~~~~~~ +~~~~~~~~~~~~~~~~~~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.html new file mode 100644 index 00000000..dcbb40f3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.html @@ -0,0 +1,3 @@ +
This	is⋅some⋅⋅
+⋅⋅⋅⋅whitespace⋅⋅
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.text new file mode 100644 index 00000000..b15c9c9a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/whitespace.text @@ -0,0 +1,3 @@ + This is some + whitespace +{:.show-whitespaces} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.html new file mode 100644 index 00000000..f7c20b2b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.html @@ -0,0 +1,13 @@ +

paragraph

+ +
code block
+
+continued here
+
+ +

ended

+ +
next blank line has 4 spaces
+
+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.text new file mode 100644 index 00000000..e51dfa53 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_blank_line.text @@ -0,0 +1,12 @@ +paragraph + + code block + + continued here + + +ended + + next blank line has 4 spaces + +paragraph diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.html new file mode 100644 index 00000000..cca17a20 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.html @@ -0,0 +1,6 @@ +
code block
+
+continued here
+
+
new block here
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.text new file mode 100644 index 00000000..834c768f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_eob_marker.text @@ -0,0 +1,5 @@ + code block + + continued here +^ + new block here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.html new file mode 100644 index 00000000..77085b30 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.html @@ -0,0 +1,6 @@ +
code block
+
+continued here
+
+
new block here
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.text new file mode 100644 index 00000000..4489f2d9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_ial.text @@ -0,0 +1,5 @@ + code block + + continued here +{:.cls} + new block here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html new file mode 100644 index 00000000..f5872c30 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.html @@ -0,0 +1,24 @@ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
+ +
def what?
+  42
+end
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options new file mode 100644 index 00000000..e2e91dba --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.options @@ -0,0 +1,2 @@ +:syntax_highlighter: null + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text new file mode 100644 index 00000000..07f437e7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block.text @@ -0,0 +1,33 @@ +~~~ ruby +def what? + 42 +end +~~~ + +~~~ ruby +def what? + 42 +end +~~~ +{:.class1} + +~~~ +def what? + 42 +end +~~~ +{: .language-ruby} + +~~~ ruby +def what? + 42 +end +~~~ +{: .language-python} + +~~~ ruby +def what? + 42 +end +~~~ +{: class="language-python"} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html new file mode 100644 index 00000000..2530b1e0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.html @@ -0,0 +1,8 @@ +
text
+
+ +
text
+
+ +
text
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options new file mode 100644 index 00000000..871923ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.options @@ -0,0 +1,2 @@ +:enable_coderay: false + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text new file mode 100644 index 00000000..60424a02 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_any_char.text @@ -0,0 +1,11 @@ +~~~ asn.1 +text +~~~ + +~~~ asn#w1 +text +~~~ + +~~~ русский +text +~~~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html new file mode 100644 index 00000000..aa4b60f2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.html @@ -0,0 +1,3 @@ +
s1'dim'a'500'm'500'q'500''
+index'j'j+1'j-1''
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options new file mode 100644 index 00000000..871923ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.options @@ -0,0 +1,2 @@ +:enable_coderay: false + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text new file mode 100644 index 00000000..423d5b73 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/06_codeblock/with_lang_in_fenced_block_name_with_dash.text @@ -0,0 +1,4 @@ +~~~ act-iii +s1'dim'a'500'm'500'q'500'' +index'j'j+1'j-1'' +~~~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.html b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.html new file mode 100644 index 00000000..068811c0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.html @@ -0,0 +1,7 @@ +

_ * _

+ +

— * * *

+ +

_ - *

+ +

———————————————- test

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.text b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.text new file mode 100644 index 00000000..a024710d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/error.text @@ -0,0 +1,7 @@ +_ * _ + +--- * * * + +_ - * + +---------------------------------------------- test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.html new file mode 100644 index 00000000..e74b6e6c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.html @@ -0,0 +1,19 @@ +
+
+
+ +

d- -

+ +
+
+
+ +

para

+

text

+ +
+ +
- - -
+
+ +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.text new file mode 100644 index 00000000..986101ab --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/normal.text @@ -0,0 +1,20 @@ +*** +* * * +- - - + +d- - + +--- +___ +*** + +para +----------- +text + +* * * + + - - - + +* * * +{:.test} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.html b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.html new file mode 100644 index 00000000..dbb86e58 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.text b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.text new file mode 100644 index 00000000..a5798b29 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/sepspaces.text @@ -0,0 +1,3 @@ +- - - +* * * +_ _ _ _ _ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.html b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.html new file mode 100644 index 00000000..dbb86e58 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.text b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.text new file mode 100644 index 00000000..464fe20c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/07_horizontal_rule/septabs.text @@ -0,0 +1,3 @@ +- - - +* * * +_ _ _ _ _ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.latex new file mode 100644 index 00000000..e71fde2a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.latex @@ -0,0 +1,3 @@ +\begin{itemize} +\item{} {[}and{]} another +\end{itemize} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.text new file mode 100644 index 00000000..515e3a7d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/brackets_in_item.text @@ -0,0 +1 @@ +* \[and\] another diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.html new file mode 100644 index 00000000..5a6ebb33 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.html @@ -0,0 +1,21 @@ +

I have read the book +1984. It was great +- other say that, too!

+ +

I have read the book +1984. It was great +- other say that, too!

+ +

I have read the book + 1984. It was great.

+ +

I have read the book 1984. + - it was great!

+ +

1984. Was great!

+ +

1984.5 is not a book.

+ +

1984.

+ +

- This too!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.text new file mode 100644 index 00000000..264dcfb3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/escaping.text @@ -0,0 +1,21 @@ +I have read the book +1984. It was great +- other say that, too! + +I have read the book +1984\. It was great +\- other say that, too! + +I have read the book + 1984. It was great. + +I have read the book 1984. + - it was great! + +1984\. Was great! + +1984.5 is not a book. + +1984\. + +\- This too! diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.html new file mode 100644 index 00000000..e6dfd3a5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.html @@ -0,0 +1,10 @@ +
    +
  • IAL at first +continued
  • +
  • another {:.cls}
  • +
  • IAL at last + code
  • +
  • X + test
  • +
  • X OK
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.text new file mode 100644 index 00000000..67bee706 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/item_ial.text @@ -0,0 +1,8 @@ +* {:.cls} IAL at first + continued +* another {:.cls} +* {:.cls} IAL at last + code +* {::nomarkdown type="html"}X{:/nomarkdown} + test +* {::nomarkdown type="html"}X{:/nomarkdown} OK diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.html new file mode 100644 index 00000000..01a5f9dd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.html @@ -0,0 +1,39 @@ +
    +
  • This is a simple +list item
  • +
  • +

    Followed by another +list item

    +
  • +
  • +

    Followed by

    + +

    a para list item +continued here

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para +continued here

    +
  • +
+ +

para

+ +
    +
  • multi line +list item
  • +
+ +

para

+ +
    +
  • list item line1 + one line + two lines
  • +
  • list item line2 +one line +two lines
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.text new file mode 100644 index 00000000..f372422a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy.text @@ -0,0 +1,29 @@ +* This is a simple +list item +* Followed by another +list item + + +* Followed by + + a para list item +continued here +* and a normal one +* and + + a para +continued here + +para + +* multi line +list item + +para + +* list item line1 + one line + two lines +* list item line2 + one line +two lines diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.html new file mode 100644 index 00000000..90c7447e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.html @@ -0,0 +1,9 @@ +
    +
  1. Root level + * Second level +
      +
    • Third level + * Back to second level
    • +
    +
  2. +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.text new file mode 100644 index 00000000..97a77558 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/lazy_and_nested.text @@ -0,0 +1,4 @@ +1. Root level + * Second level + * Third level + * Back to second level diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.html new file mode 100644 index 00000000..ecf51c76 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.html @@ -0,0 +1,9 @@ +
    +
  • Starting a list
  • +
+ +
+ +
    +
  • Starting a new list
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.text new file mode 100644 index 00000000..c7fcd47b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_hr.text @@ -0,0 +1,5 @@ +* Starting a list + +* * * + +* Starting a new list diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.html new file mode 100644 index 00000000..672428ed --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.html @@ -0,0 +1,40 @@ +
    +
  • list item
  • +
+ +
+

blockquote

+
+ +

para +* * * +para + - no list

+ +
    +
  • +

    item

    + +
    +

    block

    +
    + +

    header

    +
  • +
  • +

    test

    + +
    codeblock
    +
    + +

    test

    +
  • +
  • +

    test

    + +
    codeblock
    +
    + +

    test

    +
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.text new file mode 100644 index 00000000..f680262c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/list_and_others.text @@ -0,0 +1,26 @@ +* list item + +> blockquote + +para +* * * +para + - no list + ++ item + + > block + + ## header + +* test + + codeblock + + test + +* test + + codeblock + + test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.html new file mode 100644 index 00000000..9bc47e3b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.html @@ -0,0 +1,117 @@ +

With tabs/spaces, no paras:

+ +
    +
  • item1
  • +
  • item2
  • +
  • item3
  • +
+ +

With tabs/spaces, paras:

+ +
    +
  • +

    item1

    +
  • +
  • +

    item2

    +
  • +
  • +

    item3

    +
  • +
+ +

With tabs/spaces, no paras:

+ +
    +
  1. item1
  2. +
  3. item2
  4. +
  5. item3
  6. +
+ +

With tabs/spaces, paras:

+ +
    +
  1. +

    item1

    +
  2. +
  3. +

    item2

    +
  4. +
  5. +

    item3

    +
  6. +
+ +

Nested, without paras:

+ +
    +
  • item1 +
      +
    • item2 +
        +
      • item3
      • +
      +
    • +
    +
  • +
+ +

Nested, with paras:

+ +
    +
  • +

    item1

    + +
      +
    • item2 +
        +
      • item3 (level 3)
      • +
      +
    • +
    +
  • +
+ +

Ordered, without paras:

+ +
    +
  1. item1
  2. +
  3. item2 +
      +
    • do
    • +
    • it
    • +
    • now
    • +
    +
  4. +
  5. item3
  6. +
+ +

Ordered, with paras:

+ +
    +
  1. +

    item1

    +
  2. +
  3. +

    item2

    + +
      +
    • do
    • +
    • it
    • +
    • now
    • +
    +
  4. +
  5. +

    item3

    +
  6. +
+ +

Mixed tabs and spaces:

+ +
    +
  • some text +
      +
    • nested
    • +
    +
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.text new file mode 100644 index 00000000..22b578df --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/mixed.text @@ -0,0 +1,66 @@ +With tabs/spaces, no paras: + +* item1 ++ item2 +- item3 + +With tabs/spaces, paras: + +- item1 + +* item2 + ++ item3 + +With tabs/spaces, no paras: + +1. item1 +20. item2 +3. item3 + +With tabs/spaces, paras: + +1. item1 + +2. item2 + +3. item3 + +Nested, without paras: + +* item1 + * item2 + * item3 + +Nested, with paras: + ++ item1 + + * item2 + * item3 (level 3) + +Ordered, without paras: + +1. item1 +2. item2 + * do + * it + * now +3. item3 + +Ordered, with paras: + +1. item1 + +2. item2 + + * do + * it + * now + +3. item3 + +Mixed tabs and spaces: + +* some text + * nested diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.html new file mode 100644 index 00000000..1921ee9d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.html @@ -0,0 +1,17 @@ +
    +
  • some item +
      +
    • nested
    • +
    +
  • +
  • last item
  • +
+
    +
  • +

    some text

    + +
      +
    • nested
    • +
    +
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.text new file mode 100644 index 00000000..c71d864b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested.text @@ -0,0 +1,7 @@ +* some item + * nested +* last item +^ +* some text + + * nested diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.kramdown b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.kramdown new file mode 100644 index 00000000..dfede9b8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.kramdown @@ -0,0 +1,7 @@ +* First item + * Sub item 1 + * Sub sub item + * Sub item 2 +* Second item + * Sub item + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.text new file mode 100644 index 00000000..414afcc9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/nested_compact.text @@ -0,0 +1,6 @@ +* First item + * Sub item 1 + * Sub sub item + * Sub item 2 +* Second item + * Sub item diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.html new file mode 100644 index 00000000..3f4cd0f8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.html @@ -0,0 +1,39 @@ +
    +
  • +
    This is a code block.
    +
    +
  • +
  • +
    +

    This is a blockquote.

    +
    +
  • +
  • +

    A header

    +
  • +
+
    +
  • +
    This is a code block.
    +
    +
  • +
  • +
    +

    This is a blockquote. +continued by some para.

    +
    +
  • +
  • +

    A header

    +

    a para

    +
  • +
+
    +
  • +
      +
    • nested list
    • +
    • other nested item
    • +
    +
  • +
  • item 2
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.text new file mode 100644 index 00000000..321cef64 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/other_first_element.text @@ -0,0 +1,18 @@ +* + This is a code block. +* > This is a blockquote. +* ## A header +^ +* + This is a code block. + +* > This is a blockquote. + continued by some para. + +* A header + ========= + a para +^ +* * nested list + * other nested item +* item 2 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.html new file mode 100644 index 00000000..84e5a6ba --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.html @@ -0,0 +1,19 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    + +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    + +

    a para

    +
  10. +
+ +

para

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.text new file mode 100644 index 00000000..aaf7dae8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ol.text @@ -0,0 +1,13 @@ +1. This is a simple list item +3. Followed by another + + +10. Followed by + + a para list item +1. and a normal one +2. and + + a para + +para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.html new file mode 100644 index 00000000..68db05e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.html @@ -0,0 +1,48 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    + +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para

    +
  • +
+ +

para

+ +
    +
  • multi line +list item
  • +
+ +

para

+ +
    +
  • list item line1 +one line +two lines
  • +
  • list item line2 +one line +two lines
  • +
+ +

para

+ +
    +
  • list item line3 +one line +two lines
  • +
  • list item line4 + one line + two lines
  • +
+ +

para

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.text new file mode 100644 index 00000000..ccd25c35 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/simple_ul.text @@ -0,0 +1,36 @@ +* This is a simple list item +* Followed by another + + +* Followed by + + a para list item +* and a normal one +* and + + a para + +para + +* multi line + list item + +para + +* list item line1 + one line + two lines +* list item line2 + one line + two lines + +para + +* list item line3 + one line + two lines +* list item line4 + one line + two lines + +para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.html new file mode 100644 index 00000000..e0794614 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.html @@ -0,0 +1,3 @@ +
    +
  • single
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.text new file mode 100644 index 00000000..877d3699 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/single_item.text @@ -0,0 +1 @@ +* single diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.html b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.html new file mode 100644 index 00000000..e329931d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.html @@ -0,0 +1,72 @@ +
    +
  • +

    not a para +here

    + +
    +

    blockquote

    +
    +
  • +
  • +

    and not + here

    + +
    +

    blockquote

    +
    +
  • +
  • +

    this is a para

    +
  • +
  • +
    +

    blockquote

    +
    +
  • +
  • +

    this too

    +
  • +
+ +

A paragraph + 1. followed not by ol +- followed not by ul

+ +

A compact list:

+ +
    +
  • compact
  • +
  • list
  • +
  • items
  • +
+ +

A normal list:

+ +
    +
  • +

    not

    +
  • +
  • +

    compact

    +
  • +
  • +

    but here

    +
  • +
+ +

List item without content:

+ +
    +
  • +
  • a
  • +
+ +
    +
  • +
  • +

    one

    +
  • +
  • +

    two

    +
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.text b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.text new file mode 100644 index 00000000..7253f4a0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/08_list/special_cases.text @@ -0,0 +1,49 @@ +* not a para + here + + > blockquote + +* and not + here + + >blockquote + +* this is a para + +* > blockquote + +* this too + +^ + +A paragraph + 1. followed not by ol +- followed not by ul + +A compact list: + +* compact +* list +* items + +A normal list: + +* not + +* compact + +* but here + +List item without content: + +* +* a +^ + +* + +* one + +* two + +^ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.html new file mode 100644 index 00000000..43c82af3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.html @@ -0,0 +1,10 @@ +
++-----------------------+ +| Use XML, be Happy :-) | +|_______________________| + +
+ +

Inline section <goes> here.

+ +

Inline test *case* *section* <goes> here end.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.text new file mode 100644 index 00000000..a4de06fd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/cdata_section.text @@ -0,0 +1,10 @@ +
+
+ +Inline ]]> here. + +Inline test *case* ]]> here end. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.html new file mode 100644 index 00000000..8d31bd4e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.html @@ -0,0 +1,18 @@ + + +

para1

+ + + +

para2

+ + +

para

+ +
+

This is +

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.text new file mode 100644 index 00000000..b632bf29 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/comment.text @@ -0,0 +1,15 @@ + + +para1 + + + +para2 + + para + +> This is +> diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.html new file mode 100644 index 00000000..587d55af --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.html @@ -0,0 +1,6 @@ +
+
text
+
+

para

+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.text new file mode 100644 index 00000000..1e381d1f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/deflists.text @@ -0,0 +1,6 @@ +
+
*text*
+
+para +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.html new file mode 100644 index 00000000..e11dc14b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.html @@ -0,0 +1,14 @@ + + + + + + + + + +
Usage +Output +
Some data +

Some more

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.text new file mode 100644 index 00000000..c0cf2e7d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/content_model/tables.text @@ -0,0 +1,14 @@ + + + + + + + + + +
*Usage* +Output +
Some *data* +# Some more +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.html new file mode 100644 index 00000000..743c8224 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.html @@ -0,0 +1,15 @@ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.text new file mode 100644 index 00000000..44a060d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html5_attributes.text @@ -0,0 +1,15 @@ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

+ +

paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.html new file mode 100644 index 00000000..f51c75bb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.html @@ -0,0 +1,7 @@ +

Para

+
division
+ +
+

Quote

+
+
division
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.text new file mode 100644 index 00000000..cdcbff6c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_after_block.text @@ -0,0 +1,5 @@ +Para +
division
+ +> Quote +
division
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.html new file mode 100644 index 00000000..93d695aa --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.html @@ -0,0 +1,15 @@ +

para

+ +
codeblock
+
+ +
+

test

+
+ +
<p>codeblock</p>
+
+ +
+

test

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.text new file mode 100644 index 00000000..a3cfda74 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_codeblocks.text @@ -0,0 +1,13 @@ +para + + codeblock + +
+ test +
+ +

codeblock

+ +
+ test +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.html new file mode 100644 index 00000000..65cb7e2b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.html @@ -0,0 +1,5 @@ +

header

+ +
+====== +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.text new file mode 100644 index 00000000..64dc477e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_and_headers.text @@ -0,0 +1,6 @@ +header +====== + +
+====== +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.html new file mode 100644 index 00000000..f4b32210 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.html @@ -0,0 +1,10 @@ +

This is a code span with <entities> that should be preserved. +This is a simple code span.

+ +

Some <

+ +
Some very important < thing
+
+ +
Some code<<
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.text new file mode 100644 index 00000000..fda7db54 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/code.text @@ -0,0 +1,9 @@ +This is a code span with <entities> that should be preserved. +This is a simple code span. + +

Some <

+ +
Some very important < thing
+ +
Some code<<
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.html new file mode 100644 index 00000000..dacd4373 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.html @@ -0,0 +1,7 @@ +
+ + +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.text new file mode 100644 index 00000000..1788630c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/comment.text @@ -0,0 +1,8 @@ +
+ + + +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.html new file mode 100644 index 00000000..e4389c06 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.html @@ -0,0 +1,6 @@ +

This is sizedhallo.

+ +

This is strongitalic, yes!.

+ +

This is not converted, as is + this.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.text new file mode 100644 index 00000000..7c75930c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/emphasis.text @@ -0,0 +1,6 @@ +This is sizedhallo. + +This is strongitalic, yes!. + +This is not converted, as is + this. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.html new file mode 100644 index 00000000..5c80ce6b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.html @@ -0,0 +1 @@ +

This is *raw* HTML text containing < entities!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.text new file mode 100644 index 00000000..5c80ce6b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/entity.text @@ -0,0 +1 @@ +

This is *raw* HTML text containing < entities!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.html new file mode 100644 index 00000000..aebb2065 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.html @@ -0,0 +1,6 @@ +

Some headerhere!

+

hallo

+

hallo

+

hallo

+
hallo
+
hallo
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.options new file mode 100644 index 00000000..987b4d99 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.options @@ -0,0 +1,2 @@ +:auto_ids: true +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.text new file mode 100644 index 00000000..27eed3b0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/header.text @@ -0,0 +1,6 @@ +

Some headerhere!

+

hallo

+

hallo

+

hallo

+
hallo
+
hallo
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.html new file mode 100644 index 00000000..6eaccfe3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.html @@ -0,0 +1,8 @@ +
+
kram
+
down
+
kram
+
down
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.text new file mode 100644 index 00000000..6eaccfe3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_dl.text @@ -0,0 +1,8 @@ +
+
kram
+
down
+
kram
+
down
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.html new file mode 100644 index 00000000..eeebdfbe --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.html @@ -0,0 +1,15 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    +

    a para

    +
  10. +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.text new file mode 100644 index 00000000..41246dfb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ol.text @@ -0,0 +1,17 @@ +
    +
  1. This is a simple list item
  2. +
  3. +

    Followed by another

    +
  4. +
  5. +

    Followed by

    + +

    a para list item

    +
  6. +
  7. and a normal one
  8. +
  9. +

    and

    + +

    a para

    +
  10. +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.html new file mode 100644 index 00000000..c9b38d08 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.html @@ -0,0 +1,19 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    +

    a para

    +
  • +
+ +
    +
  • multi line list item
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.text new file mode 100644 index 00000000..5a2d68e7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/list_ul.text @@ -0,0 +1,22 @@ +
    +
  • This is a simple list item
  • +
  • +

    Followed by another

    +
  • +
  • +

    Followed by

    + +

    a para list item

    +
  • +
  • and a normal one
  • +
  • +

    and

    + +

    a para

    +
  • +
+ +
    +
  • multi line +list item
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.html new file mode 100644 index 00000000..a276b1ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.html @@ -0,0 +1,3 @@ +

Some text here and end

+ +

Some other text here

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.text new file mode 100644 index 00000000..b10035cd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/paragraph.text @@ -0,0 +1,4 @@ +

Some text here and end +

+ +

Some other text here

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.html new file mode 100644 index 00000000..bdd79ee7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.html @@ -0,0 +1,12 @@ + + + + + + + + + +
UsageOther
Some *data* +

Some more

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.text new file mode 100644 index 00000000..bdd79ee7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_normal.text @@ -0,0 +1,12 @@ + + + + + + + + + +
UsageOther
Some *data* +

Some more

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.html new file mode 100644 index 00000000..0567d738 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.html @@ -0,0 +1,64 @@ + + + + + + + + + + + +
UsageOutput
Some *data*Some more
+ + + + + + + + + + + + + + + + + + + + +
UsageOutput
Some *data*Some more
footlocker
+ + + + + + + + + + + + +
UsageOutput
Some *data*Some more
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.text new file mode 100644 index 00000000..7d294304 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/table_simple.text @@ -0,0 +1,74 @@ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + + + + + + + + + + + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
foot +locker +
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + + + + + + + + + +
Usage +Output +
Some *data* +Some more +
+ + +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.html new file mode 100644 index 00000000..24439650 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.html @@ -0,0 +1 @@ +

This is … something “to remember”!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.text new file mode 100644 index 00000000..ee33c5ce --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/html_to_native/typography.text @@ -0,0 +1 @@ +

This is … something “to remember”!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.html new file mode 100644 index 00000000..77e0d78a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.html @@ -0,0 +1,5 @@ +

para

+ +

</div>

+ +

para

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.text new file mode 100644 index 00000000..f2fc834a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_1.text @@ -0,0 +1,5 @@ +para + +
+ +para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.html new file mode 100644 index 00000000..b5da12fe --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.html @@ -0,0 +1,5 @@ +

para

+ +
+ +

para

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.text new file mode 100644 index 00000000..675c94f6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/invalid_html_2.text @@ -0,0 +1,5 @@ +para + +
+ +para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.html new file mode 100644 index 00000000..930b8f41 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.html @@ -0,0 +1,38 @@ +
+

para

+
+ +
+para +
+ +
+

para

+
+ +
+*para* +
+ +

+

para

+

+ +

+para +

+ +

+para +

+ +

+*para* +

+ +
+
emphasize
+
+

para

+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.text new file mode 100644 index 00000000..12e5aee6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/markdown_attr.text @@ -0,0 +1,38 @@ +
+*para* +
+ +
+*para* +
+ +
+*para* +
+ +
+*para* +
+ +

+*para* +

+ +

+*para* +

+ +

+*para* +

+ +

+*para* +

+ +
+
*emphasize*
+
+para +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.html new file mode 100644 index 00000000..90bda034 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.html @@ -0,0 +1,24 @@ +
+This is some text +
+ +
+This is some text +
+ +
+</p> +
+ +
+

Foo

+
+ +

This is some +text

+ +

http://example.com

+ +
+<http://example.com> +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.text new file mode 100644 index 00000000..1d1c71ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/not_parsed.text @@ -0,0 +1,24 @@ +
+This is some text +
+ +
+This is some text +
+ +
+

+
+ +
+

Foo

+
+ +

This is some +text

+ + + +
+ +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.html new file mode 100644 index 00000000..860f9b2f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.html @@ -0,0 +1,35 @@ +

baz { |qux| quux }

+ +

This is some para. +

+ + + + +

parsed +This too +

+ + + + + + + + + +

http://example.com

+ + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.htmlinput b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.htmlinput new file mode 100644 index 00000000..22b9ea5c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.htmlinput @@ -0,0 +1,34 @@ +

baz { |qux| quux }

+ +

This is some para. +

+ + + + +

parsed +This too +

+ + + + + + + + + +

http://example.com

+ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.text new file mode 100644 index 00000000..e0617c41 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_raw.text @@ -0,0 +1,33 @@ +

baz { |qux| quux }

+ +This is some para. + + + + +

*parsed* +This too +

+ + + + + + + + + + + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.html new file mode 100644 index 00000000..2a6191fb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.html @@ -0,0 +1,12 @@ +

This text +should be parsed +as span +

+ +

This produces `

+

` an unwanted result.</p>

+ +

This text too

+

+some text +

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.htmlinput b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.htmlinput new file mode 100644 index 00000000..4199b8b2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.htmlinput @@ -0,0 +1,12 @@ +

This text +should be parsed +as span +

+ +

This produces `

+

` an unwanted result.</p>

+ +

This text too

+

+some text +

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.text new file mode 100644 index 00000000..d07cf6d8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_as_span.text @@ -0,0 +1,9 @@ +

This *text +should* be parsed +as span +

+ +

This produces `

` an unwanted result.

+ +

This *text* too

+some text diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.html new file mode 100644 index 00000000..8de78c04 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.html @@ -0,0 +1,21 @@ +

+

test

+
+ +
+
test
+
+
+
test
+
+
+
+ +
+
code block with </div>
+
+
+ +
+

No matching end tag

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.text new file mode 100644 index 00000000..b8b18453 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/parse_block_html.text @@ -0,0 +1,17 @@ +
+ test +
+ +
+ test +
+ test +
+
+ +
+ code block with
+
+ +
+No matching end tag diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.html new file mode 100644 index 00000000..939b996b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.html @@ -0,0 +1,12 @@ +

<?xml version=”1.0”?>

+ +

para

+ +

<? test ?> para

+ +

other

+ +

<? +multiline text +is allowed +?>

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.text new file mode 100644 index 00000000..fcb866ff --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/processing_instruction.text @@ -0,0 +1,12 @@ + + +para + + para + +other + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.html new file mode 100644 index 00000000..0d926c5d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.html @@ -0,0 +1,60 @@ +
+

test

+
+ +

+para2 +

+ +
+

tes

+ +

test +weiter +

+
+ +

para4

+ +
+
+
+

foo

+
+
+
+
+

bar 

+
+
+ +

para5

+ +
+

id

+
+

test

+ +
+

hallo

+
+
+

hallo

+
+ +

para6

+ +
+
+

Another para.

+
+ +

Test

+ +

Test

+ +

Test + +

+ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.options b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.options new file mode 100644 index 00000000..a660da25 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.options @@ -0,0 +1 @@ +:parse_block_html: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.text new file mode 100644 index 00000000..a2ffe25e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/simple.text @@ -0,0 +1,55 @@ +
+test +
+ +

+para2 +

+ +
+

tes

+ +

test +weiter +

+
+ +para4 + +
+
+
+foo +
+
+
+
bar  +
+
+ +para5 + +
id +
test + +
+hallo +
+hallo +
+ +para6 + +
+Another para. +
+ +Test + +

Test

+ +

Test + +

+ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.htmlinput b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.htmlinput new file mode 100644 index 00000000..72ff4539 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.htmlinput @@ -0,0 +1,7 @@ +
+ inside +
+ +
+ text +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.text new file mode 100644 index 00000000..7f0d12cf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/standalone_image_in_div.text @@ -0,0 +1,8 @@ +
+![inside](src.png) +
+ +
+[text](website.html) +
+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.kramdown b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.kramdown new file mode 100644 index 00000000..f8d6802e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.kramdown @@ -0,0 +1,8 @@ + + + + + + +
test
+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.text new file mode 100644 index 00000000..32e01da5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/table.text @@ -0,0 +1,7 @@ + + + + + + +
test
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.html new file mode 100644 index 00000000..6f5693ed --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.html @@ -0,0 +1,8 @@ +

This is a

+ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.text new file mode 100644 index 00000000..a240f5c4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/textarea.text @@ -0,0 +1,8 @@ +This is a + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.html b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.html new file mode 100644 index 00000000..d941bc09 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.html @@ -0,0 +1,8 @@ + + +doit + +doit + +doit</some> + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.text b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.text new file mode 100644 index 00000000..6427fae3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/09_html/xml.text @@ -0,0 +1,7 @@ + + +doit + +doit + +doit diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.html new file mode 100644 index 00000000..74b03d58 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.html @@ -0,0 +1,2 @@ +

Some paragraph

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.text new file mode 100644 index 00000000..f58768a3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/10_ald/simple.text @@ -0,0 +1,8 @@ +Some paragraph + +{:id: ref1} +{:id: .class1} + {:id: #id} + {:id: key="value"} + {:id: .class2 .class3 ref2 #id-with key="value" key='value' key='dfsd\}' } +{:test: k ey=value} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.html new file mode 100644 index 00000000..9857a038 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.html @@ -0,0 +1 @@ +

A header

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.options b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.text new file mode 100644 index 00000000..f521fb0f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/auto_id_and_ial.text @@ -0,0 +1,2 @@ +## A header +{:#myid .cls} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.html b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.html new file mode 100644 index 00000000..84cc368d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.html @@ -0,0 +1,11 @@ +
+test +
+ +
+

test

+
+ +
+

para

+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.text b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.text new file mode 100644 index 00000000..827645cc --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/nested.text @@ -0,0 +1,15 @@ +{:.cls} +
+test +
+{:#id} + +{:.cls} +
+test +
+{:#id} + +{:.cls} +> para +{:#id} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.html new file mode 100644 index 00000000..1086f0cf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.html @@ -0,0 +1,29 @@ +

Some paragraph.

+ +

Some paragraph.

+ +
+

quote

+
+ +
    +
  • list
  • +
+ +
code block
+
+ +
other code block
+
+ +

A header

+ +

Some paragraph here

+ +

Some paragraph here

+ +

Paragraph

+

Paragraph

+ +

Another header

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.text new file mode 100644 index 00000000..b97eef3f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/11_ial/simple.text @@ -0,0 +1,41 @@ +Some paragraph. +{:.class .-class id key="val"} + +Some paragraph. +{:.cls1#id.cls2} + +> quote +{: #id} + {: .class} + +* list +{: key="val"} + + code block +{: #other} + + other code block + +## A header +{:#myid} + +{:.cls} +Some paragraph here + +{:.cls1} +{:.cls2} +Some paragraph here + +Paragraph +{:.cls} +Paragraph + +Another header +============== +{: .class #other} + +{:id: #id key="valo"} +{:id: #other .myclass other} +{:other: key1="val\"" - ig.nored as_is#this key2='val\'' .other-class} + +{:.invalid} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.html new file mode 100644 index 00000000..20b4c662 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.html @@ -0,0 +1,8 @@ +

This is a simple paragraph.

+ + + +

And another paragraph

+ +

{::comment} +Another paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.text new file mode 100644 index 00000000..2dfc9197 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/comment.text @@ -0,0 +1,12 @@ +This is a simple paragraph. + +{::comment} +This is a comment {:/}which is {:/comment} ignored. +{:/comment} + +And another paragraph + +{::comment this='is' .ignore /} + +{::comment} +Another paragraph diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.html new file mode 100644 index 00000000..17aae5cd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.html @@ -0,0 +1,8 @@ +

paragraph

+ +

{::something} +anotherthing +{:/something}

+ +

{::something/} +paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.text new file mode 100644 index 00000000..ae94a8fe --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/ignored.text @@ -0,0 +1,8 @@ +paragraph + +{::something} +anotherthing +{:/something} + +{::something/} +paragraph diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.html new file mode 100644 index 00000000..7fe58d50 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.html @@ -0,0 +1,10 @@ +

This is a simple paragraph.

+ +This *is* not processed + +

And another paragraph

+ +bold + +

{::nomarkdown} +Another paragraph

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.kramdown b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.kramdown new file mode 100644 index 00000000..2cee5122 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.kramdown @@ -0,0 +1,20 @@ +This is a simple paragraph. + +{::nomarkdown} +This *is* not processed +{:/} + +And another paragraph + +{::nomarkdown type="html"} +bold +{:/} + +{::nomarkdown type="latex"} +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} +{:/} + +\{::nomarkdown} Another paragraph + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.latex new file mode 100644 index 00000000..5af0263c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.latex @@ -0,0 +1,13 @@ +This is a simple paragraph. + +This *is* not processed + +And another paragraph + +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} + +\{::nomarkdown\} +Another paragraph + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.text new file mode 100644 index 00000000..43d441df --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/nomarkdown.text @@ -0,0 +1,21 @@ +This is a simple paragraph. + +{::nomarkdown} +This *is* not processed + {:/nomarkdown} + +And another paragraph + +{::nomarkdown this='is' .ignore /} + +{::nomarkdown type='html'} +bold +{:/} +{::nomarkdown type="latex"} +\begin{itemize} +\item[Yes] YESSSS! +\end{itemize} +{:/} + +{::nomarkdown} +Another paragraph diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.html new file mode 100644 index 00000000..bf3a47f0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.html @@ -0,0 +1,21 @@ +

No header id

+ +

without header id

+ +
+some *para* +
+ +
+

some para

+
+ +

Some text10.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.text new file mode 100644 index 00000000..b63f34b5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options.text @@ -0,0 +1,23 @@ +# No header id + +{::options unusedvar="val" /} + +# without header id + +
+some *para* +
+ +{::options parse_block_html="true" parse_span_html="true" /} + +
+some *para* +
+ +{::options footnote_nr="10" /} + +Some text[^ab]. + +[^ab]: Some text. + +{::options template="/etc/passwd" /} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.html new file mode 100644 index 00000000..2db8e20f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.html @@ -0,0 +1,10 @@ + +

Some text1.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.text new file mode 100644 index 00000000..78abfbee --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options2.text @@ -0,0 +1,5 @@ +{::options footnote_nr="da10" /} + +Some text[^ab]. + +[^ab]: Some text. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.html b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.html new file mode 100644 index 00000000..d5a5ad6b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.html @@ -0,0 +1,8 @@ +
x = Class.new
+
+
+ +
x = Class.new
+
+
+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.text b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.text new file mode 100644 index 00000000..f37839b2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/12_extension/options3.text @@ -0,0 +1,7 @@ + x = Class.new +{: .language-ruby} + +{::options syntax_highlighter_opts="{default_lang: ruby\}" /} + + x = Class.new + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.html new file mode 100644 index 00000000..398628ab --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.html @@ -0,0 +1,15 @@ +
+
item
+
def
+
item2
+
def
+
+ +
+
item
+
def
+
item2
+
def
+
item3
+
def
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.text new file mode 100644 index 00000000..f1797a74 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/auto_ids.text @@ -0,0 +1,18 @@ +{:auto_ids} +item +: def + +item2 +: def + +^ + +{:auto_ids-prefix-} +item +: def + +item2 +: def + +{:#id} item3 +: def diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.html new file mode 100644 index 00000000..7c5cc048 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.html @@ -0,0 +1 @@ +

: no definition

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.text new file mode 100644 index 00000000..cd3671b9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/definition_at_beginning.text @@ -0,0 +1 @@ +: no definition diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.html new file mode 100644 index 00000000..3090b1ef --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.html @@ -0,0 +1,4 @@ +
+
item
+
definition
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.text new file mode 100644 index 00000000..587c3b07 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/deflist_ial.text @@ -0,0 +1,4 @@ +{:.dl-horizontal} +item +: definition +{:.dl-other} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.html new file mode 100644 index 00000000..0ed1197f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.html @@ -0,0 +1,17 @@ +
+
item
+
definition +continued
+
another {:.cls}
+
+
code
+
+
+
IAL at last + no code bc of text
+
term
+
definition
+
term1
+
term2
+
definition
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.text new file mode 100644 index 00000000..2058d749 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/item_ial.text @@ -0,0 +1,16 @@ +item +: {:.cls} definition + continued +: another {:.cls} +: {:.class} + code +: {:.cls} IAL at last + no code bc of text + + +{:.class} term +: definition + +{:.class1} term1 +{:.class2} term2 +: definition diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.html new file mode 100644 index 00000000..e2e089b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.html @@ -0,0 +1,13 @@ +
+
kram
+
down
+
now
+
definition 1
+
definition 2
+
+

definition 3

+
+
+

definition 4

+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.text new file mode 100644 index 00000000..b834258b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/multiple_terms.text @@ -0,0 +1,10 @@ +kram +*down* +now +: definition 1 +: definition 2 + +: definition 3 + + +: definition 4 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.html new file mode 100644 index 00000000..c16f9623 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.html @@ -0,0 +1,2 @@ +

This is a para +: and not a definition list

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.text new file mode 100644 index 00000000..98b52b37 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/no_def_list.text @@ -0,0 +1,2 @@ +This is a para +\: and not a definition list diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.html new file mode 100644 index 00000000..5f28fdf8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.html @@ -0,0 +1,10 @@ +
+
term
+
+

definition

+
+
definition
+
+

definition

+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.text new file mode 100644 index 00000000..280fa474 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/para_wrapping.text @@ -0,0 +1,6 @@ +term + +: definition +: definition + +: definition diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.html new file mode 100644 index 00000000..0a1c4dc2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.html @@ -0,0 +1,8 @@ +
+
kram
+
down
+
+
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.text new file mode 100644 index 00000000..56fedf16 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/separated_by_eob.text @@ -0,0 +1,5 @@ +kram +: down +^ +kram +: down diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.html new file mode 100644 index 00000000..791f1451 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.html @@ -0,0 +1,10 @@ +
+
kram
+
down
+
novalue
+
+
kram
+
down +kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.text new file mode 100644 index 00000000..e3bf730e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/simple.text @@ -0,0 +1,10 @@ +kram +: down + +novalue +: + +kram +: down +kram +: down diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.html new file mode 100644 index 00000000..cf7d7859 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.html @@ -0,0 +1,4 @@ +
+
kram
+
down
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.text new file mode 100644 index 00000000..76eb3553 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/styled_terms.text @@ -0,0 +1,2 @@ +*kram* +: down diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.html new file mode 100644 index 00000000..b4df8780 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.html @@ -0,0 +1,3 @@ +

para

+ +

: no definition

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.text new file mode 100644 index 00000000..30ab445c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/too_much_space.text @@ -0,0 +1,4 @@ +para + + +: no definition diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.html b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.html new file mode 100644 index 00000000..45b58656 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.html @@ -0,0 +1,38 @@ +
+
kram
+
this is some +text
+
+

this is some +more text

+
+
kram
+
+
+

blockquote

+
+
+
kram
+
+
code
+
+
+
kram
+
+
+
kram
+
down
+
+
+
kram
+
+

header

+
+
kram
+
+
    +
  • list
  • +
  • items
  • +
+
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.text b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.text new file mode 100644 index 00000000..15195ce3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/13_definition_list/with_blocks.text @@ -0,0 +1,24 @@ +kram +: this is some + text + + : this is some + more text + +kram +: > blockquote + +kram +: + code + +kram +: kram + : down + +kram +: # header + +kram +: * list + * items diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.html new file mode 100644 index 00000000..af9b3e5f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.html @@ -0,0 +1,8 @@ + + + + + + + +
first line of cell
second line of cell
another cell
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.options b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.options new file mode 100644 index 00000000..63936b99 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.options @@ -0,0 +1 @@ +:html_to_native: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.text new file mode 100644 index 00000000..60fec0b4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/empty_tag_in_cell.text @@ -0,0 +1 @@ +| first line of cell
second line of cell | another cell | diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.html new file mode 100644 index 00000000..302e97ae --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.html @@ -0,0 +1,12 @@ +

No table body

+ +

|-|-|-

+ +

|no|table|here|

+ +

|no|table|here| +paragraph

+ +

|-|-| +|-|-|

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.text new file mode 100644 index 00000000..3565d5b8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/errors.text @@ -0,0 +1,13 @@ +No table body + +|-|-|- + +[5]: test +|no|table|here| + +|no|table|here| +paragraph + +|-|-| +|-|-| + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.html new file mode 100644 index 00000000..b4528a17 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.html @@ -0,0 +1,52 @@ +

cell 1 | cell 2

+ +

cell 1 | cell 2

+ + + + + + + + +
cell 1cell 2 | continued
+ + + + + + + + +
cell 1cell 2
+ + + + + + + + +
cell 1code | span
+ +

cell 1 code | span

+ +

cell 1 | code | span

+ + + + + + + + + + + + + + +
cell 1cell `2cell 3
cell 1`cell 2cell 3
+ +

cell 1 | cell 2 | cell 3 +cell 1 | cell 2 | cell 3

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.text new file mode 100644 index 00000000..a8a24d6a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/escaping.text @@ -0,0 +1,19 @@ +`cell 1 | cell 2` + +cell 1 \| cell 2 + +cell 1 | cell 2 \| continued + +cell 1 | cell `2` + +cell 1 | `code | span` + +cell 1 `code | span` + +cell 1 \| `code | span` + +cell 1 | cell `2 | cell 3 +cell 1` | cell 2 | cell 3 + +cell 1 \| cell `2 | cell 3 +cell 1` | cell 2 | cell 3 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.html new file mode 100644 index 00000000..e6596ed5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.html @@ -0,0 +1,65 @@ +

Simple footer

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Full footer

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Footer with separator lines

+ + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6
+ +

Empty footer

+ + + + + + + + +
cell1cell2
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.text new file mode 100644 index 00000000..faaed8d9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/footer.text @@ -0,0 +1,25 @@ +Simple footer + +| cell1 | cell2 +|= +| cell3 | cell4 + +Full footer + +| cell1 | cell2 +|=======|=======| +| cell3 | cell4 + +Footer with separator lines + +| cell1 | cell2 +|=======|=======| +| cell3 | cell4 +|--- +| cell5 | cell6 +|--- + +Empty footer + +| cell1 | cell2 +|= diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.html new file mode 100644 index 00000000..647f2c48 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.html @@ -0,0 +1,117 @@ +

Simple header

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Full header

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

With alignment and superfluous alignment defs

+ + + + + + + + + + + + + + + + + + + + +
defaultleftcenterrightdefault
cell1cell2cell3cell4cell5
+ +

With leading sep line

+ + + + + + + + + + + + + + +
cell1cell2
cell3cell4
+ +

Multiple bodies

+ + + + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6
+ +

Sep line with tab

+ + + + + + + + + + + + + + + + + + +
rightcenter
cell1cell2
cell3cell4
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.text new file mode 100644 index 00000000..6961bfb9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/header.text @@ -0,0 +1,39 @@ +Simple header + +| cell1 | cell2 +|----- +| cell3 | cell4 + +Full header + +| cell1 | cell2 +|-------|-------| +| cell3 | cell4 + +With alignment and superfluous alignment defs + +| default | left | center | right | default +|-| :- |:-: | -: | - | :-: | :- +| cell1 | cell2 | cell3 | cell4 | cell5 + +With leading sep line + +|:-:|-:| +| cell1 | cell2 +|-------|-------| +| cell3 | cell4 + +Multiple bodies + +| cell1 | cell2 ++ :-: | +| cell3 | cell4 +|----||| +| cell5 | cell6 + +Sep line with tab + +right | center +---: | :---: +cell1 | cell2 +cell3 | cell4 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.html new file mode 100644 index 00000000..dce46b1d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.html @@ -0,0 +1,3 @@ +

No table

+ +

| Some | thing | here

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.text new file mode 100644 index 00000000..90f90b3d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/no_table.text @@ -0,0 +1,3 @@ +No table + +\| Some \| thing \| here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.html new file mode 100644 index 00000000..506b4421 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.html @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + +
cell1cell2
cell3cell4
cell5cell6 |
cell7cell8
+ +

Missing cells at end

+ + + + + + + + + + + + + + + + + + + +
cell1cell2cell3
cell1  
 cell2cell3
+ +

Escaped pipe characters

+ + + + + + + + + + + + + + + + +
cell1 | cell1cell2
cell1cell2 |
cell1 | concell2
+ +

Table with code elements

+ + + + + + + + + + + + + + + + +
This is a span | with a pipe.   
Some span</em> herea span | with apipe.
+ +

Special cases regarding codespan syntax

+ + + + + + + + +
ab
+ + + + + + + +
a
+ + + + + + + + + +
tablewithial
+ + + + + + + + + +
tablewithial
+ +

not starting with a bar

+ + + + + + + + +
simpletable
+ + + + + + + + + + + + + + +
head1head2
cell1cell2
+ + + + + + + + + + + + + + +
head1head2
 cell2
+ + + + + + + + + + + + + + + + +
ab
cd
ef
+ + + + + + + + + + + + + + +
KeyValue type
Type"GROUP"|"UNKNOWN"
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.text new file mode 100644 index 00000000..0f225a4e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/simple.text @@ -0,0 +1,53 @@ +| cell1 | cell2 | +|cell3 | cell4| +|cell5|cell6 \| +| cell7|cell8 + +Missing cells at end + +| cell1 | cell2 | cell3 | +| cell1 || +|| cell2 | cell3 + +Escaped pipe characters + +| cell1 \| cell1 | cell2 | +| cell1 | cell2 \| +| cell1 `|` con | cell2 + +Table with code elements + +| This is a span | with a pipe. +| Some span | here | a span | with a | pipe. + +Special cases regarding codespan syntax + +|a|`b` + +|`a` + +{:.cls} +| table | with | ial + +| table | with | ial +{:.cls} + +not starting with a bar + +simple | table + +head1 | head2 +------|------ +cell1 | cell2 + + head1 | head2 +-------|------ + | cell2 + +| a | b | + c | d +| e | f | + +| Key | Value type | +|--------|------------------------| +| `Type` | `"GROUP"`\|`"UNKNOWN"` | diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.html b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.html new file mode 100644 index 00000000..0084283f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.html @@ -0,0 +1,25 @@ + + + + + + + + + + + +
this is 1a table
with afootnote
+ +
+
    +
  1. +

    Something

    + +
    +

    special here

    +
    +

    ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.latex b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.latex new file mode 100644 index 00000000..99b5312f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.latex @@ -0,0 +1,11 @@ +\begin{longtable}{|l|l|} +\hline +this is \footnote{Something + +\begin{quote} +special here +\end{quote}} & a table\\ +with a & footnote\\ +\hline +\end{longtable} + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.text b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.text new file mode 100644 index 00000000..345fc5d3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/14_table/table_with_footnote.text @@ -0,0 +1,6 @@ +| this is [^1] | a table +| with a | footnote + +[^1]: Something + + > special here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.html b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.html new file mode 100644 index 00000000..9b2c1279 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.html @@ -0,0 +1 @@ +\[<script>alert('a')</script> <script>alert('b<')</script>\] diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.text b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.text new file mode 100644 index 00000000..95252a76 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/gh_128.text @@ -0,0 +1 @@ +$$ $$ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.html b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.html new file mode 100644 index 00000000..5d6b343e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.html @@ -0,0 +1,3 @@ +
$$ +5+5 +$$
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.options b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.options new file mode 100644 index 00000000..06d559e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.options @@ -0,0 +1 @@ +:math_engine: ~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.text b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.text new file mode 100644 index 00000000..fdee5cfb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/no_engine.text @@ -0,0 +1,2 @@ +{: #math-id} +$$5+5$$ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.html new file mode 100644 index 00000000..f80d56b6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.html @@ -0,0 +1,30 @@ +

This is a para. +\(\text{LaTeX} \lambda_5\)

+ +\[\lambda_5 = \alpha + 4\] + +

\(\lambda_\alpha > 5\) +This is a para.

+ +\[\begin{align*} +&=5 \\ +&=6 \\ +\end{align*}\] + +\[5+5\] + +\[5+5\] + +\[5+5\] + +\[5+5\] + +
$$5+5$$
+
+ +
\[5+5\] +
+
\[5+5\] +
+ +\[|x| = 5\] diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.text new file mode 100644 index 00000000..aa5984a2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/15_math/normal.text @@ -0,0 +1,30 @@ +This is a para. +$$ \text{LaTeX} \lambda_5 $$ + +$$\lambda_5 = \alpha + 4$$ + +$$\lambda_\alpha > 5$$ +This is a para. + +$$\begin{align*} +&=5 \\ +&=6 \\ +\end{align*}$$ + +$$5+5$$ + + $$5+5$$ + + $$5+5$$ + + $$5+5$$ + + $$5+5$$ + +{:.cls} +$$5+5$$ +^ +$$5+5$$ +{:.cls} + +$$|x| = 5$$ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.html b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.html new file mode 100644 index 00000000..bbb831e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.html @@ -0,0 +1,14 @@ + +

Header level 1

+ +

Header level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.text b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.text new file mode 100644 index 00000000..11ad8291 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/no_toc.text @@ -0,0 +1,16 @@ +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.html b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.html new file mode 100644 index 00000000..d3526846 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.html @@ -0,0 +1,35 @@ +

Contents

+ + + +

Header level 1

+ +

Header level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.options b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.text b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.text new file mode 100644 index 00000000..d8f0b863 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_exclude.text @@ -0,0 +1,19 @@ +# Contents +{:.no_toc} + +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.html b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.html new file mode 100644 index 00000000..e50a07c4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.html @@ -0,0 +1,24 @@ + + +

Header level 1

+ +

Header \` level 2

+ +

Header level 3

+ +

Header level 4

+ +

Other header level 1

+ +

Other header level 2

+ +

Other header level 3

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.options b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.options new file mode 100644 index 00000000..bdfbeba1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.options @@ -0,0 +1,2 @@ +:toc_levels: 2..3 +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.text b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.text new file mode 100644 index 00000000..1a62dea2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_levels.text @@ -0,0 +1,16 @@ +* Here comes the table of content +{:toc} + +# Header level 1 + +## Header \\\` level 2 + +### Header level 3 + +#### Header level 4 + +# Other header level 1 + +## Other header level 2 + +### Other header level 3 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.html b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.html new file mode 100644 index 00000000..f979601d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.html @@ -0,0 +1,13 @@ + + +

Header1 level 1

+ +
+
    +
  1. +

    Some footnote content here ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.options b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.text b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.text new file mode 100644 index 00000000..5879ed57 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_footnotes.text @@ -0,0 +1,6 @@ +* Here comes the table of content +{:toc} + +# Header[^1] level 1 + +[^1]: Some footnote content here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.html b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.html new file mode 100644 index 00000000..ebde543b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.html @@ -0,0 +1,8 @@ +

Header

+ +

Header

+ + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.options b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.options new file mode 100644 index 00000000..36c20f5a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.options @@ -0,0 +1,2 @@ +:auto_ids: true +:auto_id_stripping: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.text b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.text new file mode 100644 index 00000000..9b4ac073 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/block/16_toc/toc_with_links.text @@ -0,0 +1,8 @@ +# [Header] + +# [Header] + +[header]: test.html + +* toc +{:toc} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.html b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.html new file mode 100644 index 00000000..82993163 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.html @@ -0,0 +1,4 @@ +

一二三四五

+ +

あいうえお

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.options b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.options new file mode 100644 index 00000000..4c86d365 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.options @@ -0,0 +1 @@ +:remove_line_breaks_for_cjk: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.text b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.text new file mode 100644 index 00000000..969c04ca --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/cjk-line-break.text @@ -0,0 +1,12 @@ +一 +二 +三 +四 +五 + +あ +い +う +え +お + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/encoding.html b/bin/gems/kramdown-2.5.2/test/testcases/encoding.html new file mode 100644 index 00000000..0339347f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/encoding.html @@ -0,0 +1,46 @@ +

Das ist gewöhnlich ein Über-Problem mit manchen
+Sälen http://example.org und anderen Dinge. Siehe +Über mich!

+ +
+

Vielleicht höre ich nicht richtig?

+
+ +
    +
  • Sollten wir uns das überlegen? Verhöhne mich nicht!
  • +
  • Ho ho höher! Sind *wir* da?
  • +
+ +

Titel sind urschön

+ +

Manche mögens ärmer

+ +
öha
+was nun?
+
+ +
+
Töne
+
Laute Geräusche
+
vielleicht noch was ähnliches
+
+ + + + + + + + + + + + + + + + +
hochhöheram höchsten
überdrübermüde
+ +

Das ist schön +gemacht

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/encoding.text b/bin/gems/kramdown-2.5.2/test/testcases/encoding.text new file mode 100644 index 00000000..65edf4b0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/encoding.text @@ -0,0 +1,28 @@ +Das ist gewöhnlich *ein* [Über-Problem](http://example.org) mit manchen +Sälen und anderen Dinge. Siehe +![Über mich](http://example.org)! + +> Vielleicht *höre*{:.red} ich nicht richtig? +{:.test} + +* Sollten wir uns das überl*egen*? *Verhöhne* mich nicht! +* Ho ho höher! Sind \*wir\* da? + +Titel sind urschön +================== + +## Manche mögens *ärmer* {#hot} + + öha + was nun? + +Töne +: Laute Geräusche +: vielleicht noch was ä*hnliches* + +| hoch | höher | am höchsten | +|----------------------------| +| über | drüber | müde | + +

Das ist schön +gemacht

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/example.man b/bin/gems/kramdown-2.5.2/test/testcases/man/example.man new file mode 100644 index 00000000..a03d1481 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/example.man @@ -0,0 +1,123 @@ +.\" generated by kramdown +.TH "NAME" "1" "November 2016" "Some extra data" +.SH NAME +name \- description +.SH "SYNOPSIS" +\fBname\fP [\fBOPTIONS\fP] \fIarguments\fP\.\.\. +.SH "DESCRIPTION" +This is a normal paragraph\. +.sp +.PD 0 +.IP \(bu 4 +A +.IP \(bu 4 +compact +.IP \(bu 4 +list +.IP \(bu 4 +with multiple +.RS +.IP \(bu 4 +items and +.RS +.IP \(bu 4 +nested +.RE +.RE +.IP \(bu 4 +as well +.PD +.RS +.P +blockquotes are fine +.IP 1. 4 +numbered lists +.IP 2. 4 +work too +.RS +.IP 1. 4 +and they +.IP 2. 4 +can be +.RS +.IP 1. 4 +nested +.RE +.RE +.IP 3. 4 +again +.RE +.sp +.RS 4 +.EX +Some fancy code + going + on + here +.EE +.RE +.TP +\fB\-o\fP +.TQ +\fB\-\-option\fP +Description lists +.sp +are useful as well +.P +And compact definition lists: +.sp +.PD 0 +.TP +\fBo\fP +Option +.TP +\fBk\fP +Key +.TP +\fBv\fP +Value +.PD +.TS +box center ; +l l l l . +tables can be centered +.TE +.sp +.TS +box ; +lb lb cb rb . +Default aligned Left aligned Center aligned Right aligned += +.T& +l l c r . +First body part Second cell Third cell fourth cell +Second \fIline\fP foo \fBstrong\fP baz +Third line \fBquux\fP baz bar +_ +.T& +l l c r . +Second body +2nd line += +Footer row one +Footer row two +.TE +.sp +.P +Inline formatting like \fIemphasis\fP, \fBstrong\fP and \fBcode span\fP work as ususal\. +.UR are_well\.html +Links +.UE +work, too! As do +.br +line breaks\. +.P +Abbreviations like MD can be used but the abbreviation title is ignored\. +.P +Math elements work \fB\elambda = 5\fP inline and in block form: +.sp +.RS 4 +.EX +\elambda_5 = \ealpha + 4 +.EE +.RE diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/example.text b/bin/gems/kramdown-2.5.2/test/testcases/man/example.text new file mode 100644 index 00000000..a0a26149 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/example.text @@ -0,0 +1,85 @@ +# name(1) - description +{: data-date="November 2016" data-extra="Some extra data"} + +## SYNOPSIS + +`name` \[`OPTIONS`\] *arguments*... + +## DESCRIPTION + +This is a normal paragraph. + +* A +* compact +* list +* with multiple + * items and + * nested +* as well +{:.compact} + +> blockquotes are fine +> +> 1. numbered lists +> +> 2. work too +> 1. and they +> 2. can be +> 1. nested +> +> 3. again + +~~~ +Some fancy code + going + on + here +~~~ + +`-o` +`--option` +: Description lists +: are useful as well + +And compact definition lists: + +`o` +: Option + +`k` +: Key + +`v` +: Value +{:.compact} + +| tables | can | be | centered | +{:.center} + +|-----------------+------------+-----------------+----------------| +| Default aligned |Left aligned| Center aligned | Right aligned | +|-----------------|:-----------|:---------------:|---------------:| +| First body part |Second cell | Third cell | fourth cell | +| Second *line* |foo | **strong** | baz | +| Third line |`quux` | baz | bar | +|-----------------+------------+-----------------+----------------| +| Second body | | | | +| 2nd line | | | | +|=================+============+=================+================| +| Footer row one | | | | +| Footer row two | | | | +|-----------------+------------+-----------------+----------------| + + +Inline formatting like *emphasis*, **strong** and `code span` work +as ususal. [Links](are_well.html) work, too! As do\\ +line breaks. + +Abbreviations like MD can be used but the abbreviation title is +ignored. + +*[MD]: Markdown + +Math elements work $$\lambda = 5$$ inline and in block form: + +$$\lambda_5 = \alpha + 4$$ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.man b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.man new file mode 100644 index 00000000..8e47527e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "7" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.text b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.text new file mode 100644 index 00000000..832c9213 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-dash-description.text @@ -0,0 +1 @@ +# name -- description diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.man b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.man new file mode 100644 index 00000000..e59dc5ec --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "1" "November 2016" "Something extra" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.text b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.text new file mode 100644 index 00000000..941482c1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-description.text @@ -0,0 +1,2 @@ +# name description +{: data-section="1" data-date="November 2016" data-extra="Something extra"} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.man b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.man new file mode 100644 index 00000000..8df4ff71 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.TH "NAME" "1" +.SH NAME +name \- description diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.text b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.text new file mode 100644 index 00000000..5f3e765b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section-description.text @@ -0,0 +1 @@ +# name(1) -- description diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.man b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.man new file mode 100644 index 00000000..7ca87574 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.man @@ -0,0 +1,2 @@ +.\" generated by kramdown +.TH "NAME" "1" diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.text b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.text new file mode 100644 index 00000000..da98dbda --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name-section.text @@ -0,0 +1 @@ +# name(1) diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.man b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.man new file mode 100644 index 00000000..8488496f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.man @@ -0,0 +1,2 @@ +.\" generated by kramdown +.TH "NAME" "7" diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.text b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.text new file mode 100644 index 00000000..5f4656ae --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/heading-name.text @@ -0,0 +1 @@ +# name diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/sections.man b/bin/gems/kramdown-2.5.2/test/testcases/man/sections.man new file mode 100644 index 00000000..14ab2336 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/sections.man @@ -0,0 +1,4 @@ +.\" generated by kramdown +.SH "NAME" +works +.SS "Sub section" diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/sections.text b/bin/gems/kramdown-2.5.2/test/testcases/man/sections.text new file mode 100644 index 00000000..d1f5f864 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/sections.text @@ -0,0 +1,11 @@ +## NAME + +works + +### Sub section + +#### Ignored + +##### Ignored + +###### Ignored diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.man b/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.man new file mode 100644 index 00000000..710a4f14 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.man @@ -0,0 +1,8 @@ +.\" generated by kramdown +\&\. at the start of the line +.P +line with \efB backslash symbol +.P +some \. other \- escaped \' symbols +.P +\&\. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.text b/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.text new file mode 100644 index 00000000..052b94f5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/man/text-escaping.text @@ -0,0 +1,7 @@ +. at the start of the line + +line with \fB backslash symbol + +some . other - escaped \' symbols + +. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.html new file mode 100644 index 00000000..a1102ead --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.html @@ -0,0 +1,5 @@ +

This is [] empty.

+ +

This is [][] empty.

+ +

This is empty.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.text new file mode 100644 index 00000000..cca5de5f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty.text @@ -0,0 +1,5 @@ +This is [] empty. + +This is [][] empty. + +This is [](test.html) empty. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.htmlinput b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.htmlinput new file mode 100644 index 00000000..b95b2cc7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.htmlinput @@ -0,0 +1,3 @@ +

Image with empty title: alt text

+ +

Link reference with empty title.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.text new file mode 100644 index 00000000..baabe7da --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/empty_title.text @@ -0,0 +1,7 @@ +Image with empty title: ![alt text](/images/other.png) + +Link [reference][1] with empty title. + + + +[1]: http://example.tld diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.html new file mode 100644 index 00000000..e1f4ade5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.html @@ -0,0 +1,5 @@ +

Simple: Some alt text

+ +

Nested: Some alt ![img](text.png) text

+ +

Simple: Some text alt text text

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.text new file mode 100644 index 00000000..bdbfb65e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/image_in_a.text @@ -0,0 +1,5 @@ +Simple: [Some ![alt text](/images/other.png)](local.html) + +Nested: [Some ![alt ![img](text.png) text](/images/other.png)](local.html) + +Simple: [Some *text ![alt text](/images/other.png) text*](local.html) diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.html new file mode 100644 index 00000000..565d36f7 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.html @@ -0,0 +1,15 @@ +

Simple: alt text

+ +

Simple with title: alt text

+ +

Empty img link: alt text

+ +

Reference style: alt text

+ +

Reference style with title: alt text

+ +

No alt text:

+ +

No id: imgo

+ +

With escaped pipe: an | pipe

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.text new file mode 100644 index 00000000..05050a24 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/imagelinks.text @@ -0,0 +1,18 @@ +Simple: ![alt text](/images/other.png) + +Simple with title: ![alt text](/images/other.png "title") + +Empty img link: ![alt text]() + +Reference style: ![alt text][img] + +Reference style with title: ![alt text][imgo] + +No alt text: ![](other.png) + +No id: ![imgo] + +[img]: other.png +[imgo]: other.png "Title" + +With escaped pipe: ![an \| pipe](other.png) diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.html new file mode 100644 index 00000000..8d00efa9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.html @@ -0,0 +1,46 @@ +

simple URL

+ +

simple URL

+ +

simple URL with formatting

+ +

simple URL with single quoted title

+ +

simple URL with double quoted title

+ +

simple URL [with ] escaped

+ +

simple URL with ] escaped

+ +

simple URL [with] nested

+ +

simple URL with [no](link.html) inside

+ +

simple URL with parens

+ +

simple URL with parens

+ +

simple URL broken +on line

+ +

simple URL with spaces

+ +

simple URL with spaces

+ +

simple URL with spaces

+ +

simple leading/trailing spaces

+ +

simple leading/trailing spaces

+ +

simple leading/trailing spaces

+ +

bad [URL not

+ +

bad [URL with parens](something(new.html)

+ +

bad [URL with empty title](something.html ‘’)

+ +

bad [URL](

+ +

bad [URL](no

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.text new file mode 100644 index 00000000..c7057646 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/inline.text @@ -0,0 +1,48 @@ +simple [URL]() + +simple [URL](something.html) + +simple [URL *with* formatting](something.html) + +simple [URL with single quoted title](something.html 'a t"itle') + +simple [URL with double quoted title](something.html "a t'itle") + +simple [URL \[with \] escaped](something.html) + +simple [URL with \] escaped](something.html) + +simple [URL [with] nested](something.html) + +simple [URL with [no](link.html) inside](something.html) + +simple [URL with parens](/something/to(do)) + +simple [URL with parens](/something/to(do "doit") + +simple [URL broken +on line](something.html +"title") + +simple [URL with spaces](with spaces.html) + +simple [URL with spaces](with spaces.html 'title') + +simple [URL with spaces](with (spaces).html) + +simple [leading/trailing spaces]( spaces.html) + +simple [leading/trailing spaces](spaces.html ) + +simple [leading/trailing spaces]( spaces.html ) + + +bad [URL [not](something.html) + +bad [URL with parens](something(new.html) + +bad [URL with empty title](something.html '') + +bad [URL]( + +bad [URL](no diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.latex new file mode 100644 index 00000000..63e58e74 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.latex @@ -0,0 +1,6 @@ +\href{https://example.com/~tilde/}{https://example.com/\ensuremath{\sim}tilde/} + +\href{http://example.com/percent\%20percent}{http://example.com/percent\%20percent} + +\href{http://example.com/hash#hash}{http://example.com/hash\#hash} + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.text new file mode 100644 index 00000000..9b27ae86 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/latex_escaping.text @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.html new file mode 100644 index 00000000..15e2ca71 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.html @@ -0,0 +1,9 @@ +

This is a para. +[id]: http://www.example.com/

+ +
[4]: nourl
+
+ +

Points to 1 and 2 and 3 but not [4]

+ +

Points to _.:,;!?- and otherid8

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.text new file mode 100644 index 00000000..16a25b5b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs.text @@ -0,0 +1,27 @@ +This is a para. +[id]: http://www.example.com/ + +[otherid1]: http://wwww.example.com/ "title 1" +[otherid2]: http://wwww.example.com/ 'title 2' +[otherid3]: +[otherid4]: 'title' +[otherid5]: some spaces.html +[otherid6]: some spaces.html 'title' +[otherid7]: some spaces + "title" +[otherid8]:test.html#'test' 'title' + +[break]: http://www.example.com/test/asdf.html + 'Another title' + +[1]: ignored.url + [1]: one.url + [2]: two.url + [3]: three.url + [4]: nourl + +Points to [1] and [2] and [3] but not [4] + +[_.:,;!?-]: http://example.com + +Points to [_.:,;!?-] and [otherid8] diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.html new file mode 100644 index 00000000..f56d77de --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.html @@ -0,0 +1,4 @@ +

Link def with attr and attr 2 and attr 3 and attr before

+ +

test

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.text new file mode 100644 index 00000000..59398a3a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/link_defs_with_ial.text @@ -0,0 +1,16 @@ +Link def with [attr] and [attr 2] and [attr 3] and [attr before] + +[attr]: http://example.com 'title' +{: hreflang="en" .test} + +[attr 2]: http://example.com 'title' +{: hreflang="en"} +{: .test} + +[attr 3]: http://example.com +{: .test} +test + +{: hreflang="en"} +{: .test} +[attr before]: http://example.com diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.html new file mode 100644 index 00000000..ecaa31e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.html @@ -0,0 +1,3 @@ +

This is a link.

+ +

This is a link.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.text new file mode 100644 index 00000000..2cf0ecec --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/links_with_angle_brackets.text @@ -0,0 +1,3 @@ +This is a [link](). + +This is a [link]( 'and title'). diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.html b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.html new file mode 100644 index 00000000..f6fed181 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.html @@ -0,0 +1,37 @@ + +

simple URL and URL

+ +

simple URL and URL

+ +

simple 1 and isurl

+ +

simple 1 and isurl

+ +

this is [a holy isurl]

+ +

no [resolution][] here and [here]

+ +

with a break in +the text

+ +

this not [isurl] and not [isurl]

+ +

a Link with_BIG letters

+ +

bad [no URL] d isurl

+ +

[no url] invalid.html +[no url]:

+ +

“title”

+ +

test url but no title +test [urldef]

+ +

[urldef]: some.url ‘title”

+ +

some with spaces

+ +

this is a ‘special’ occasion for /all/ of us

+ +

this is predefined for URI

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.options b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.options new file mode 100644 index 00000000..efb4b018 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.options @@ -0,0 +1,3 @@ +:link_defs: + predefined: [predefined.html] + URI: [uri.html, My URI] diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.text b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.text new file mode 100644 index 00000000..9f39fa70 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/01_link/reference.text @@ -0,0 +1,53 @@ +[isurl]: someurl.html + [1]: otherurl.html + +simple [URL][1] and [URL][isurl] + +simple [URL] [1] and [URL] +[isurl] + +simple [1][] and [isurl][] + +simple [1] and [isurl] + +this is [a holy [isurl]] + +no [resolution][] here and [here] + +with a [break in +the text] + + [break in the text]: url.html + +this not \[isurl] and not [isurl\] + +a [Link with_BIG] letters + + [link WITH_big]: letters.html + 'This is the title' + +bad [no URL] d [isurl] + +[no url] invalid.html +[no url]: + +[URL but no title]: invalid.html + + "title" + +test [url but no title] +test [urldef] + +[urldef]: some.url 'title" + + +some [with spaces] + +[with spaces]: with spaces.html "title" + +this [is a 'special' occasion for /all/ of us] + +[is a 'special' occasion for /all/ of us]: occasion.html + + +this is [predefined] for [URI] diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.html b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.html new file mode 100644 index 00000000..127e6943 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.html @@ -0,0 +1,3 @@ +

This __is **empty.

+ +

This **is empty.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.text b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.text new file mode 100644 index 00000000..c99d053f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/empty.text @@ -0,0 +1,3 @@ +This __is **empty. + +This ****is empty. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.html b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.html new file mode 100644 index 00000000..e62f03fd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.html @@ -0,0 +1,9 @@ +

This is a *star.

+ +

This is a **star.

+ +

This is *a *star.

+ +

This is *a star*.

+ +

This** is** a star.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.text b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.text new file mode 100644 index 00000000..e80e5eb4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/errors.text @@ -0,0 +1,9 @@ +This is a *star. + +This is a **star. + +This is **a *star*. + +This is *a star\*. + +This** is** a star. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.html b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.html new file mode 100644 index 00000000..3d34cee1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.html @@ -0,0 +1,41 @@ +
    +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
  • test test
  • +
+
    +
  • ab
  • +
  • ab
  • +
  • abc
  • +
  • ab
  • +
  • ab
  • +
  • abc
  • +
+
    +
  • _a_b
  • +
  • a_b_
  • +
  • a_b_c
  • +
  • __a__b
  • +
  • a__b__
  • +
  • a__b__c
  • +
  • a__2__c
  • +
  • a__2__3
  • +
  • 1__2__3
  • +
+
    +
  • a _b_ c
  • +
  • a __b__ c
  • +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.text b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.text new file mode 100644 index 00000000..ba67e84b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/nesting.text @@ -0,0 +1,36 @@ +- ***test test*** +- ___test test___ +- *test **test*** +- **test *test*** +- ***test* test** +- ***test** test* +- ***test* test** +- **test *test*** +- *test **test*** +- _test __test___ +- __test _test___ +- ___test_ test__ +- ___test__ test_ +- ___test_ test__ +- __test _test___ +- _test __test___ +^ +- *a*b +- a*b* +- a*b*c +- **a**b +- a**b** +- a**b**c +^ +- _a_b +- a_b_ +- a_b_c +- __a__b +- a__b__ +- a__b__c +- a__2__c +- a__2__3 +- 1__2__3 +^ +- *a _b_ c* +- **a __b__ c** diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.html new file mode 100644 index 00000000..b7ddf433 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.html @@ -0,0 +1,70 @@ +

This is so hard.

+ +

This is so hard too.

+ +

At start +At start

+ +

At end +At end

+ +

At start +At start

+ +

At end +At end

+ +

And nested.

+ +

And nest**ed.

+ +

And *nested* like this.

+ +

And not_nest_ed.

+ +

And nested.

+ +

And nested.

+ +

And neste.

+ +

And lonely * here*.

+ +

And lonely ** here**.

+ +

And lonely ** here.

+ +

** and here**.

+ +

And compli*cated * here

+ +

Some**what more * **here

+ +

Do it *this* way +Or this *this* way +Or that *that* way +Or that *that* way

+ +

http://blah.com/blah_%28 +http://blah.com/blah__%28 +http://blah.com/blah___%28 +http://blah.com/blah____%28 +http://blah.com/blah_____%28 +http://blah.com/blah______%28

+ +

A-_B

+ +
    +
  • test
  • +
  • ‘test’
  • +
  • “test”
  • +
  • (“test”)
  • +
  • (test)
  • +
  • “test”
  • +
  • `test’
  • +
  • „test“
  • +
+ +

it–by design–cannot have side-effects.

+ +

it—by design—cannot have side-effects.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.options b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.text new file mode 100644 index 00000000..a242125e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/02_emphasis/normal.text @@ -0,0 +1,68 @@ +This *is* so **hard**. + +This _is_ so __hard__ too. + +*At* start +*At* start + +At *end* +At *end* + +_At_ start +_At_ start + +At _end_ +At _end_ + +And *nest**ed***. + +And *nest**ed*. + +And *nest**ed* like** this. + +And *not_nest_ed*. + +And ***nested***. + +And ___nested___. + +And **nest*e***. + +And lonely * here*. + +And lonely ** here**. + +And **lonely ** here**. + +** and here**. + +And **compli*cated \*** here + +Some***what* more * ***he*re + +Do it *\*this\** way +Or this \**this*\* way +Or that *\*that*\* way +Or that \**that\** way + +[http://blah.com/blah_%28](http://blah.com/blah_%28) +[http://blah.com/blah__%28](http://blah.com/blah__%28) +[http://blah.com/blah___%28](http://blah.com/blah___%28) +[http://blah.com/blah____%28](http://blah.com/blah____%28) +[http://blah.com/blah_____%28](http://blah.com/blah_____%28) +[http://blah.com/blah______%28](http://blah.com/blah______%28) + +[A-_B](A_-B) + +- _test_ +- '_test_' +- "_test_" +- ("_test_") +- (_test_) +- “_test_” +- \`_test_' +- „_test_“ + +it--by design--_cannot have side-effects_. + +it---by design---_cannot have side-effects_. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.html new file mode 100644 index 00000000..20c50519 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.html @@ -0,0 +1,5 @@ +

This is `` empty.

+ +

This is ``empty.

+ +

This is ````empty.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.text new file mode 100644 index 00000000..cbb91529 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/empty.text @@ -0,0 +1,5 @@ +This is `` empty. + +This is ``empty. + +This is ````empty. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.html new file mode 100644 index 00000000..1d341a8f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.html @@ -0,0 +1 @@ +

Not ended `span.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.text new file mode 100644 index 00000000..7a948b41 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/errors.text @@ -0,0 +1 @@ +Not ended `span. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.latex new file mode 100644 index 00000000..a1f84d90 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.latex @@ -0,0 +1,2 @@ +You can say \mintinline{ruby}{x = Class.new}, for example. + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.options b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.options new file mode 100644 index 00000000..c11ebb6a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.options @@ -0,0 +1 @@ +:syntax_highlighter: minted diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting-minted.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.html new file mode 100644 index 00000000..4294542d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.html @@ -0,0 +1 @@ +

You can say x = Class.new, for example.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/highlighting.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.html new file mode 100644 index 00000000..ec21686c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.html @@ -0,0 +1 @@ +

This is a code-span

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.options b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.options new file mode 100644 index 00000000..bfc92f45 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.options @@ -0,0 +1,2 @@ +:syntax_highlighter_opts: + guess_lang: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.text new file mode 100644 index 00000000..f704439a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal-css-class.text @@ -0,0 +1 @@ +This is a `code-span` diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.html new file mode 100644 index 00000000..6de2257f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.html @@ -0,0 +1,20 @@ +

This is a simple span.

+ +

With some<ht>&ml in it.

+ +

And ` backticks.

+ +

And ``some`` more.

+ +

With backslash in\ it.

+ +

This is a ` literal backtick. +As `are` these!

+ +

No literal backtick.

+ +

something

+ +

` `

+ +

a ` `

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.text new file mode 100644 index 00000000..c1889595 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/normal.text @@ -0,0 +1,20 @@ +This is `a` simple span. + +With `some&ml` in it. + +And `` ` `` backticks. + +And ``` ``some`` ``` more. + +With backslash `in\` it. + +This is a ` literal backtick. +As \`are\` these! + +No `` literal backtick``. + +`something` + +` ` + +a ` ` diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.html new file mode 100644 index 00000000..7822f788 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.html @@ -0,0 +1 @@ +

You can say Class.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.options b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.options new file mode 100644 index 00000000..34094e96 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.options @@ -0,0 +1,4 @@ +:syntax_highlighter: rouge +:syntax_highlighter_opts: + span: + disable: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.text new file mode 100644 index 00000000..d958d914 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/disabled.text @@ -0,0 +1 @@ +You can say `Class`{:.language-ruby}. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.html new file mode 100644 index 00000000..4294542d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.html @@ -0,0 +1 @@ +

You can say x = Class.new, for example.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.options b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.options new file mode 100644 index 00000000..9ac61e7e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.options @@ -0,0 +1 @@ +:syntax_highlighter: rouge diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.text new file mode 100644 index 00000000..73732909 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/03_codespan/rouge/simple.text @@ -0,0 +1 @@ +You can say `x = Class.new`{:.language-ruby}, for example. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.html new file mode 100644 index 00000000..f18212b3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.html @@ -0,0 +1,79 @@ +

This is 123456789

+ +
+
    +
  1. + +

    A paragraph ↩

    +
  2. +
  3. + +

    A header ↩

    +
  4. +
  5. + +
    +

    blockquote

    + +

    paragraph ↩

    +
    +
  6. +
  7. + +
    codeblock
    +
    +

    ↩

    +
  8. +
  9. + +
      +
    • item 1
    • +
    • item 2 +
        +
      • +

        sub item

        + +
        +

        blockquote

        + +

        header ↩

        +
        +
      • +
      +
    • +
    +
  10. +
  11. + + + + + + + + + + + + +
    ab
    cd
    +

    ↩

    +
  12. +
  13. + +
    +

    ↩

    +
  14. +
  15. + +\[x + 2\] +

    ↩

    +
  16. +
  17. + +
    test +
    +

    ↩

    +
  18. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.options new file mode 100644 index 00000000..ac54fc0d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.options @@ -0,0 +1 @@ +footnote_backlink_inline: true diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.text new file mode 100644 index 00000000..55f94a34 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_inline.text @@ -0,0 +1,38 @@ +This is [^paragraph][^header][^blockquote][^codeblock][^list][^table][^hrule][^mathblock][^html] + +[^paragraph]: + A paragraph + +[^header]: + # A header + +[^blockquote]: + > blockquote + > + > paragraph + +[^codeblock]: + codeblock + +[^list]: + * item 1 + * item 2 + * sub item + + > blockquote + > + > # header + +[^table]: + | a | b | + | c | d | + +[^hrule]: + *** + +[^mathblock]: + $$x + 2$$ + +[^html]: +
test +
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.html new file mode 100644 index 00000000..bed08698 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.html @@ -0,0 +1,9 @@ +

Some footnote here1

+ +
+
    +
  1. +

    Some text here text &8617; <img />

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.options new file mode 100644 index 00000000..4c677eff --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.options @@ -0,0 +1 @@ +:footnote_backlink: 'text &8617; ' diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.text new file mode 100644 index 00000000..41a6f984 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/backlink_text.text @@ -0,0 +1,3 @@ +Some footnote here[^fn] + +[^fn]: Some text here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.html new file mode 100644 index 00000000..9012cc06 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.html @@ -0,0 +1,17 @@ +

Some para.

+ +
+

blockquote

+
+ +
    +
  • a list +with some text
  • +
+ +
    +
  • other list
  • +
+
code
+
+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.latex new file mode 100644 index 00000000..965653c8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.latex @@ -0,0 +1,17 @@ +Some para. + +\begin{quote} +blockquote +\end{quote} + +\begin{itemize} +\item{} a list +with some text +\end{itemize} + +\begin{itemize} +\item{} other list +\end{itemize} +\begin{verbatim}code +\end{verbatim} + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.text new file mode 100644 index 00000000..44b52e00 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/definitions.text @@ -0,0 +1,24 @@ +Some para. + +[^footnote]: ignored definition +[^footnote]: Some footnote text + +> blockquote + +[^other]: some + foot + + note text + +* a list + with some text + +[^tnote]: foot note + +* other list +^ + code + +[^1]: + > a blockquote + and some para diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.html new file mode 100644 index 00000000..0867c86f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.html @@ -0,0 +1,12 @@ +

This is a[footnote 1] footnote[footnote 1]. And another[footnote 2].

+ +
+
    +
  1. +

    Some text. ↩ ↩2

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.options new file mode 100644 index 00000000..092fd1a4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.options @@ -0,0 +1 @@ +:footnote_link_text: "[footnote %s]" diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.text new file mode 100644 index 00000000..3876de06 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_link_text.text @@ -0,0 +1,4 @@ +This is a[^ab] footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. \ No newline at end of file diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.html new file mode 100644 index 00000000..77c0a848 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.html @@ -0,0 +1,12 @@ +

This is a footnote35. And another36.

+ +
+
    +
  1. +

    Some text. ↩

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.latex new file mode 100644 index 00000000..8f07dde0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.latex @@ -0,0 +1,2 @@ +This is a footnote\footnote{Some text.}. And another\footnote{Some other text.}. + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.options new file mode 100644 index 00000000..f606ecfa --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.options @@ -0,0 +1 @@ +:footnote_nr: 35 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.text new file mode 100644 index 00000000..cad29357 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_nr.text @@ -0,0 +1,4 @@ +This is a footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.html new file mode 100644 index 00000000..90aa226c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.html @@ -0,0 +1,12 @@ +

This is a1 footnote1. And another2.

+ +
+
    +
  1. +

    Some text. ↩ ↩2

    +
  2. +
  3. +

    Some other text. ↩

    +
  4. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.options new file mode 100644 index 00000000..51d78bc1 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.options @@ -0,0 +1 @@ +:footnote_prefix: adf123- diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.text new file mode 100644 index 00000000..884053e8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/footnote_prefix.text @@ -0,0 +1,4 @@ +This is a[^ab] footnote[^ab]. And another[^bc]. + +[^ab]: Some text. +[^bc]: Some other text. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.html new file mode 100644 index 00000000..d4e97ffd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.html @@ -0,0 +1,17 @@ +

Lorem ipsum1 dolor sit amet.

+ +

Lorem ipsum2 dolor sit amet.

+ +
+
    +
  1. +

    Consecutur adisping.3 ↩

    +
  2. +
  3. +

    Sed ut perspiciatis unde omnis. ↩

    +
  4. +
  5. +

    Sed ut. ↩

    +
  6. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.text new file mode 100644 index 00000000..f4f91e93 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/inside_footnote.text @@ -0,0 +1,9 @@ +Lorem ipsum[^first] dolor sit amet. + +Lorem ipsum[^second] dolor sit amet. + +[^first]: Consecutur adisping.[^third] + +[^second]: Sed ut perspiciatis unde omnis. + +[^third]: Sed ut. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.html new file mode 100644 index 00000000..90f2ccba --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.html @@ -0,0 +1,46 @@ +

This is some *ref.1

+ +
+

a blockquote 2

+
+ +
    +
  • and a list item 3
  • +
+ +

And a header4

+ +

A marker without a definition [^without].

+ +

A marker 5 used twice1 and thrice1.

+ +
+
    +
  1. +

    Some foot note text ↩ ↩2 ↩3

    +
  2. +
  3. +

    other text +with more lines

    + +
    +

    and a quote

    +
    +

    ↩

    +
  4. +
  5. +

    some text ↩

    +
  6. +
  7. + +
    code block
    +continued here
    +
    +

    ↩

    +
  8. +
  9. + +

    ↩

    +
  10. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.latex new file mode 100644 index 00000000..8f406b86 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.latex @@ -0,0 +1,23 @@ +This is some *ref.\footnote{Some foot note text} + +\begin{quote} +a blockquote \footnote{other text +with more lines + +\begin{quote} +and a quote +\end{quote}} +\end{quote} + +\begin{itemize} +\item{} and a list item \footnote{some \emph{text}} +\end{itemize} + +\section*{And a header\footnote{\begin{verbatim}code block +continued here +\end{verbatim}}} + +A marker without a definition {[}\^{}without{]}. + +A marker \footnote{} used twice\footnote{Some foot note text} and thrice\footnote{Some foot note text}. + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.options new file mode 100644 index 00000000..5cfe2502 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.options @@ -0,0 +1,2 @@ +:auto_ids: false +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.text new file mode 100644 index 00000000..42b77fb5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/markers.text @@ -0,0 +1,27 @@ +This is some *ref.[^fn] + +[^fn]: Some foot note text +{: .class} + +> a blockquote [^3] + +* and a list item [^1] + +# And a header[^now] + +[^1]:some *text* +[^3]: other text + with more lines + + > and a quote + +A marker without a definition [^without]. + +A marker [^empty] used twice[^fn] and thrice[^fn]. + +[^now]: + + code block + continued here + +[^empty]: diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.html new file mode 100644 index 00000000..a87f3599 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.html @@ -0,0 +1,11 @@ +
+
    +
  1. +

    Footnote \` text ↩

    +
  2. +
+
+ +

Some para with a1 footnote.

+ +

And another para.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.text new file mode 100644 index 00000000..97c0ab1a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/placement.text @@ -0,0 +1,8 @@ +* footnotes will be placed here +{:footnotes} + +Some para with a[^1] footnote. + +[^1]: Footnote \\\` text + +And another para. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.html new file mode 100644 index 00000000..64ce4aea --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.html @@ -0,0 +1,14 @@ +

Something

+

something1.

+ +

Footnotes

+ +

Test

+
+
    +
  1. + +

    A note ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.options new file mode 100644 index 00000000..5cfe2502 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.options @@ -0,0 +1,2 @@ +:auto_ids: false +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.text new file mode 100644 index 00000000..6a60c612 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/regexp_problem.text @@ -0,0 +1,52 @@ +# Something +something[^note1]. + +# Footnotes +[^note1]: + A note + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.html b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.html new file mode 100644 index 00000000..e6f2d79d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.html @@ -0,0 +1,9 @@ +

Some footnote here1

+ +
+
    +
  1. +

    Some text here

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.options b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.options new file mode 100644 index 00000000..0512dd6d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.options @@ -0,0 +1 @@ +:footnote_backlink: '' diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.text b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.text new file mode 100644 index 00000000..41a6f984 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/04_footnote/without_backlink.text @@ -0,0 +1,3 @@ +Some footnote here[^fn] + +[^fn]: Some text here diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.html new file mode 100644 index 00000000..e7cec40f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.html @@ -0,0 +1 @@ +

Link: test

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.text new file mode 100644 index 00000000..8f39d959 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/across_lines.text @@ -0,0 +1,2 @@ +Link: test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.html new file mode 100644 index 00000000..c49bb52f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.html @@ -0,0 +1,7 @@ +

+ +

First some text and then a

+ +

and then text.

+ +

A it.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.text new file mode 100644 index 00000000..e0a7783c --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/button.text @@ -0,0 +1,7 @@ + + +First some text and then a + + and then text. + +A it. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.html new file mode 100644 index 00000000..030552fc --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.html @@ -0,0 +1 @@ +

This is some text

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.text new file mode 100644 index 00000000..383f0a83 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/invalid.text @@ -0,0 +1 @@ +This is some text diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.html new file mode 100644 index 00000000..7d0d6ad6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.html @@ -0,0 +1 @@ +

Link: text

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.text new file mode 100644 index 00000000..fb016196 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/link_with_mailto.text @@ -0,0 +1 @@ +Link: text diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.html new file mode 100644 index 00000000..b6989b7f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.html @@ -0,0 +1,3 @@ +

Lorem ipsum.

+ +

Test

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.text new file mode 100644 index 00000000..6ae30e03 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/mark_element.text @@ -0,0 +1,3 @@ +Lorem ipsum. + +Test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.html new file mode 100644 index 00000000..44158c3b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.html @@ -0,0 +1,6 @@ +

This is text +This is *text* +This is text +This is text +This is *nothing* to fear about. +This is <http://example.com>.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.text new file mode 100644 index 00000000..dcc10ff8 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/markdown_attr.text @@ -0,0 +1,6 @@ +This is *text* +This is *text* +This is *text* +This is *text* +This is *nothing* to *fear* about. +This is . diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.html new file mode 100644 index 00000000..3cdc646d --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.html @@ -0,0 +1,43 @@ +

Empty !

+ +

title is a title.

+ +

This is <? a PI ?>.

+ +

This is comment.

+ +

This is multiline comment.

+ +

This is tag +now .

+ +

This is tag + now.

+ +

This is an empty tag.

+ +

This is something strange.

+ +

Auto-closing:

+ +

Expanding:

+ +

An invalid tag: <hR>

+ +

A <p>block tag</p>.

+ +

An invalid </closing> tag.

+ +

A tag.

+ +

An unclosed tag.

+ +

Some element with | pipe symbol

+ +

Some element with | pipe symbol

+ +

Some element with | pipe +symbol|

+ +

underlined

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.text new file mode 100644 index 00000000..0156d7c0 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/normal.text @@ -0,0 +1,43 @@ +Empty ! + +title is a title. + +This is . + +This is comment. + +This is multiline comment. + +This is tag +now . + +This is tag + now. + +This is an empty tag. + +This is _something strange_. + +Auto-closing:
+ +Expanding: + +An invalid tag:
+ +A

block tag

. + +An invalid tag. + +A tag. + +An unclosed *tag.* + +Some element with | pipe symbol + +Some element with | pipe symbol + +Some element with | pipe +symbol| + +underlined diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.html new file mode 100644 index 00000000..808f1dbf --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.html @@ -0,0 +1,2 @@ +

This is raw --version and --version and --version and +---version.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.text new file mode 100644 index 00000000..5b128fcb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/raw_span_elements.text @@ -0,0 +1,2 @@ +This is raw --version and --version and --version and +---version. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.html b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.html new file mode 100644 index 00000000..00b43c12 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.html @@ -0,0 +1,5 @@ +

This doit test

+ +

This doit test

+ +

This doit</some> test

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.text b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.text new file mode 100644 index 00000000..bc234de4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/05_html/xml.text @@ -0,0 +1,5 @@ +This doit test + +This doit test + +This doit test diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.html b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.html new file mode 100644 index 00000000..6bddfda5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.html @@ -0,0 +1,25 @@ +

This is some text.

+ +

There is some real concern about OtHeR!

+ +

is some Think empty about Oesterreich. CSS und CSS3

+ +

no abbrev here because there is someone and kulis some

+ +
    +
  • (X)HTML test
  • +
  • line two
  • +
+ +

(X)HTML

+ +
    +
  • test (X)HTML
  • +
+ +

This is awesome.

+ +

hello foo bar babble.

+ +

hello foo +bar babble.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.text b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.text new file mode 100644 index 00000000..f5ec88ef --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev.text @@ -0,0 +1,41 @@ +This is some text. + +*[is some]: Yes it is +*[OtHeR!]: This & that + +*[is some]: It is, yes +*[empty]: + +There *is some real* concern about OtHeR! + +is some Think empty about Oesterreich. CSS und CSS3 + +no abbrev here because there is someone and kulis some + +*[Oesterreich]: Very nice country + +*[CSS]: Cascading +*[CSS3]: Cascading 3 + +* (X)HTML test +* line two + +[(X)HTML](http://en.wikipedia.org/wiki/Xhtml) + +* test (X)HTML + +*[(X)HTML]: (eXtensible) HyperText Markup Language + + +This is awesome. + +{:.testit} +*[awesome]: Some text here +{:.test} + +*[foo bar]: baz + +hello foo bar babble. + +hello foo +bar babble. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.html b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.html new file mode 100644 index 00000000..108fcfce --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.html @@ -0,0 +1,2 @@ +
*[4]: noabbrev
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.text b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.text new file mode 100644 index 00000000..3f3a0e5b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_defs.text @@ -0,0 +1,5 @@ +*[ABBR]: Some abbreviations + *[one abbr]: one abbrev + *[2 and other]: another + *[3]: yet another + *[4]: noabbrev diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.html b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.html new file mode 100644 index 00000000..6da3ca4e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.html @@ -0,0 +1,9 @@ +

This is some TEST to check.

+ + + This TEST fails. + + + This TEST fails. + + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.text b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.text new file mode 100644 index 00000000..e0a0e881 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/abbrev_in_html.text @@ -0,0 +1,10 @@ +This is some TEST to check. + + + This TEST fails. + + + This TEST fails. + + +*[TEST]: This Escapes SVG Text. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.html b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.html new file mode 100644 index 00000000..7cce8beb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.html @@ -0,0 +1,9 @@ +

There is a TXT file here. 1

+ +
+
    +
  1. +

    A TXT file. ↩

    +
  2. +
+
diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.text b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.text new file mode 100644 index 00000000..e7709cb9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/abbreviations/in_footnote.text @@ -0,0 +1,5 @@ +There is a TXT file here. [^1] + +*[TXT]: Text File + +[^1]: A TXT file. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.html b/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.html new file mode 100644 index 00000000..90eae7d5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.html @@ -0,0 +1,15 @@ +

This should be a http://www.example.com/ link. +This should be a john.doe@example.com link. +As should john.doe@example.com this. +As should john_doe@example.com this. +As should CSS@example.com this. +Another ampersand http://www.example.com/?doit&x=y link. +More entities http://www.example.com/?doit&x="y&z=y.

+ +

Email international übung@macht.den.meister.de, ü.äß@hülse.de +Email invalid: <me@example.com>

+ +

Autolink with underscore: http://www.example.com/with_under_score

+ +

http://www.example.com/

+ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.text b/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.text new file mode 100644 index 00000000..033e8af4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/autolinks/url_links.text @@ -0,0 +1,16 @@ +This should be a link. +This should be a link. +As should this. +As should this. +As should this. +Another ampersand link. +More entities . + +Email international <übung@macht.den.meister.de>, <ü.äß@hülse.de> +Email invalid: <[me@example.com](mailtos:me@example.com)> + +Autolink with underscore: + + + +*[CSS]: Cascading diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.html new file mode 100644 index 00000000..015d5948 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.html @@ -0,0 +1,47 @@ +

\

+ +

.

+ +

*

+ +

_

+ +

+

+ +

-

+ +

`

+ +

(

+ +

)

+ +

[

+ +

]

+ +

{

+ +

}

+ +

#

+ +

!

+ +

<<

+ +

>>

+ +

:

+ +

|

+ +

"

+ +

'

+ +

=

+ +

>

+ +

<

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.text new file mode 100644 index 00000000..1c47104a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/escaped_chars/normal.text @@ -0,0 +1,47 @@ +\\ + +\. + +\* + +\_ + +\+ + +\- + +\` + +\( + +\) + +\[ + +\] + +\{ + +\} + +\# + +\! + +\<< + +\>> + +\: + +\| + +\" + +\' + +\= + +\> + +\< diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.html b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.html new file mode 100644 index 00000000..3544d49f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.html @@ -0,0 +1,6 @@ +

This is a paragraph. +This is a paragraph. +This is a . +This is a paragraph. +This is a {:/comment} simple {:/} paragraph. +This is a {::comment} paragraph.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.text b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.text new file mode 100644 index 00000000..8b9e8d36 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/comment.text @@ -0,0 +1,6 @@ +This is a {::comment}simple{:/} paragraph. +This is a {::comment}simple{:/comment} paragraph. +This is a {::comment}simple {:/other} paragraph{:/comment}. +This is a {::comment/} paragraph. +This is a {:/comment} simple {:/} paragraph. +This is a {::comment} paragraph. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.html b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.html new file mode 100644 index 00000000..63c2c404 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.html @@ -0,0 +1 @@ +

This is {::something}paragraph{:/}

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.text b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.text new file mode 100644 index 00000000..a7e77375 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/ignored.text @@ -0,0 +1 @@ +This is {::something}paragraph{:/} diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.html b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.html new file mode 100644 index 00000000..83de9312 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.html @@ -0,0 +1 @@ +

This is *some* text.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.text b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.text new file mode 100644 index 00000000..57c4b38f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/nomarkdown.text @@ -0,0 +1 @@ +This is {::nomarkdown}*some*{:/} text. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.html b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.html new file mode 100644 index 00000000..48e3076a --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.html @@ -0,0 +1 @@ +

This is an option *true*!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.text b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.text new file mode 100644 index 00000000..e289491e --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/extension/options.text @@ -0,0 +1 @@ +This is an {::options parse_span_html="false" /} option *true*! diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.html b/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.html new file mode 100644 index 00000000..c0f3a475 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.html @@ -0,0 +1,6 @@ +

This is a span.

+ +

This is a span.

+ +

This is an{: .ignored} span ial. +This is an{: .escaped} span ial.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.text b/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.text new file mode 100644 index 00000000..8945602b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/ial/simple.text @@ -0,0 +1,6 @@ +This is a `span`{: .hund #dog}. + +This is a `span`{: .hund #dog}{: .katz key='val'}. + +This is an{: .ignored} span ial. +This is an\{: .escaped} span ial. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.html new file mode 100644 index 00000000..11066a50 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.html @@ -0,0 +1,11 @@ +

This is a line
+with a line break.

+ +

This is a line +without a line break.

+ +

This is a line
+with a line\
+break.

+ +

Line break on last line.

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.latex new file mode 100644 index 00000000..a62ff561 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.latex @@ -0,0 +1,12 @@ +This is a line\newline +with a line break. + +This is a line +without a line break. + +This is a line \newline +with a line\textbackslash{} \newline +break. + +Line break on last line. + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.text new file mode 100644 index 00000000..92f866f2 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/line_breaks/normal.text @@ -0,0 +1,11 @@ +This is a line +with a line break. + +This is a line +without a line break. + +This is a line \\ +with a line\\ +break. + +Line break on last line. diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.html b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.html new file mode 100644 index 00000000..3b93c542 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.html @@ -0,0 +1 @@ +

$5+5$ inline math

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.options b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.options new file mode 100644 index 00000000..06d559e5 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.options @@ -0,0 +1 @@ +:math_engine: ~ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.text b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.text new file mode 100644 index 00000000..a22f9fd4 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/math/no_engine.text @@ -0,0 +1 @@ +$$5+5$$ inline math diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.html b/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.html new file mode 100644 index 00000000..459d03f3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.html @@ -0,0 +1,10 @@ +

This is \(\lambda_\alpha > 5\) some math. With \(1 ++ 1\) new line characters in between.

+ +

\(5+5\) inline math, $5.00 $$no math$$

+ +

$$5+5$$ inline math

+ +

\(5+5\)

+ +

$$5+5$$

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.text b/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.text new file mode 100644 index 00000000..e37a0078 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/math/normal.text @@ -0,0 +1,10 @@ +This is $$\lambda_\alpha > 5$$ some math. With $$1 ++ 1$$ new line characters in between. + +$$5+5$$ inline math, $5.00 \$$no math$$ + +\$\$5+5$$ inline math + +\$$5+5$$ + +\$\$5+5$$ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.html new file mode 100644 index 00000000..21a29033 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.html @@ -0,0 +1,6 @@ +

This is the A&O. © 2008 by me +As well \& as this. Some ŗ other +values may ¯ may also show but +not st. like &#xYZ;.

+ +

This <span> is BS&T; done!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.options new file mode 100644 index 00000000..036c5619 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.options @@ -0,0 +1 @@ +:entity_output: :as_input diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.text new file mode 100644 index 00000000..7ef42c7b --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities.text @@ -0,0 +1,6 @@ +This is the A&O. © 2008 by me +As well \& as this. Some ŗ other +values may ¯ may also show but +not st. like &#xYZ;. + +This <span> is BS&T; done! diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.html new file mode 100644 index 00000000..ed2817bb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.html @@ -0,0 +1 @@ +

This "is" 'the' A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.options new file mode 100644 index 00000000..32a751e3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.options @@ -0,0 +1,2 @@ +:entity_output: :as_char +:smart_quotes: apos,apos,quot,quot diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.text new file mode 100644 index 00000000..279b5115 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_char.text @@ -0,0 +1 @@ +This "is" 'the' A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.html new file mode 100644 index 00000000..d2eec9dd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.options new file mode 100644 index 00000000..036c5619 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.options @@ -0,0 +1 @@ +:entity_output: :as_input diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_as_input.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.html new file mode 100644 index 00000000..d04613ee --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.options new file mode 100644 index 00000000..2e6e0a12 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.options @@ -0,0 +1 @@ +:entity_output: :numeric diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_numeric.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.html new file mode 100644 index 00000000..258ba147 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.html @@ -0,0 +1 @@ +

This is the A&O. © 2008 by me ŗ and λ

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.options new file mode 100644 index 00000000..c195785f --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.options @@ -0,0 +1 @@ +:entity_output: :symbolic diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.text new file mode 100644 index 00000000..1ddf7cdd --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/entities_symbolic.text @@ -0,0 +1 @@ +This is the A&O. © 2008 by me ŗ and λ diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.html new file mode 100644 index 00000000..dcce4cc3 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.html @@ -0,0 +1 @@ +

2 > 1 > 0

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.text new file mode 100644 index 00000000..7dfb7f12 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/greaterthan.text @@ -0,0 +1 @@ +2 > 1 > 0 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.html new file mode 100644 index 00000000..8ebac237 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.html @@ -0,0 +1 @@ +

0 < 1 < 2

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.text new file mode 100644 index 00000000..038df8bb --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/lowerthan.text @@ -0,0 +1 @@ +0 < 1 < 2 diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.html new file mode 100644 index 00000000..02d1dbce --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.html @@ -0,0 +1,40 @@ +

This is… something—this too–!

+ +

This «is» some text, « this » too!

+ +

“Fancy quotes” are ‘cool’, even in the ’80s! +Je t’ aime. You’re a funny one! Thomas’ name +Mark’s name. “…you” +“‘Nested’ quotes are ‘possible’”, too! +‘“Otherway” is “round”’!

+ +

‘Opening now!’

+ +

’80s are really cool.

+ +

Cluster’s Last Stand.

+ +

Nam liber tempor +“…At vero eos et accusam”

+ +

“Single underscores should work.”

+ +

“Single asterisks should work.”

+ +

‘Double underscores should work.’

+ +

‘Double asterisks should work.’

+ +

“Hurrah!”

+ +

‘Absolutely.’

+ +

“…some Text”

+ +

“… some Text”

+ +

This: “…some Text”

+ +

This: “… some Text”

+ +

”[foo]” “[foo]” d “[foo]”

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.options new file mode 100644 index 00000000..4f1c17c6 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.options @@ -0,0 +1 @@ +:entity_output: symbolic diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.text new file mode 100644 index 00000000..27e090e9 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography.text @@ -0,0 +1,40 @@ +This is... something---this too--! + +This <> some text, << this >> too! + +"Fancy quotes" are 'cool', even in the '80s! +Je t' aime. You're a funny one! Thomas' name +Mark's name. "...you" +"'Nested' quotes are 'possible'", too! +'"Otherway" is "round"'! + +'Opening now!' + +'80s are really cool. + +Cluster's Last Stand. + +Nam liber tempor +"...At vero eos et accusam" + +"_Single underscores_ should work." + +"*Single asterisks* should work." + +'__Double underscores__ should work.' + +'**Double asterisks** should work.' + +"_Hurrah!_" + +'__Absolutely__.' + +"...some Text" + +"... some Text" + +This: "...some Text" + +This: "... some Text" + +"\[foo]" "\[foo]" d "\[foo]" diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.html b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.html new file mode 100644 index 00000000..4a6c2260 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.html @@ -0,0 +1,3 @@ +

This ... something---this too--!

+ +

This <<is>> some text, << this >> too!

diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.latex b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.latex new file mode 100644 index 00000000..c7d9ba59 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.latex @@ -0,0 +1,4 @@ +This ... something---this too--! + +This \textless{}\textless{}is\textgreater{}\textgreater{} some text, \textless{}\textless{} this \textgreater{}\textgreater{} too! + diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.options b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.options new file mode 100644 index 00000000..d0a03132 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.options @@ -0,0 +1,8 @@ +typographic_symbols: + hellip: '...' + mdash: '---' + ndash: '--' + laquo: '<<' + raquo: '>>' + laquo_space: '<< ' + raquo_space: ' >>' diff --git a/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.text b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.text new file mode 100644 index 00000000..a3d59b37 --- /dev/null +++ b/bin/gems/kramdown-2.5.2/test/testcases/span/text_substitutions/typography_subst.text @@ -0,0 +1,3 @@ +This ... something---this too--! + +This <> some text, << this >> too! diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/CONTRIBUTERS b/bin/gems/kramdown-parser-gfm-1.1.0/CONTRIBUTERS new file mode 100644 index 00000000..262ad48c --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/CONTRIBUTERS @@ -0,0 +1,4 @@ +Count Name +======= ==== + 15 Ashwin Maroli + 5 Thomas Leitner diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/COPYING b/bin/gems/kramdown-parser-gfm-1.1.0/COPYING new file mode 100644 index 00000000..417fb2ce --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/COPYING @@ -0,0 +1,21 @@ +kramdown-parser-gfm +Copyright (C) 2019 Thomas Leitner + +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/bin/gems/kramdown-parser-gfm-1.1.0/VERSION b/bin/gems/kramdown-parser-gfm-1.1.0/VERSION new file mode 100644 index 00000000..9084fa2f --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/VERSION @@ -0,0 +1 @@ +1.1.0 diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown-parser-gfm.rb b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown-parser-gfm.rb new file mode 100644 index 00000000..3861bcaa --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown-parser-gfm.rb @@ -0,0 +1,10 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2019 Thomas Leitner +# +# This file is part of kramdown-parser-gfm which is licensed under the MIT. +#++ +# + +require_relative 'kramdown/parser/gfm' diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm.rb b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm.rb new file mode 100644 index 00000000..c803e12e --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm.rb @@ -0,0 +1,220 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2019 Thomas Leitner +# +# This file is part of kramdown-parser-gfm which is licensed under the MIT. +#++ +# + +require 'kramdown/options' +require 'kramdown/parser/kramdown' + +require_relative 'gfm/options' + +module Kramdown + module Parser + + # This class provides a parser implementation for the GFM dialect of Markdown. + class GFM < Kramdown::Parser::Kramdown + + VERSION = '1.1.0' + + attr_reader :paragraph_end + + def initialize(source, options) + super + @options[:auto_id_stripping] = true + @id_counter = Hash.new(-1) + + @span_parsers.delete(:line_break) if @options[:hard_wrap] + @span_parsers.delete(:typographic_syms) if @options[:gfm_quirks].include?(:no_auto_typographic) + + if @options[:gfm_quirks].include?(:paragraph_end) + atx_header_parser = :atx_header_gfm_quirk + @paragraph_end = self.class::PARAGRAPH_END_GFM + else + atx_header_parser = :atx_header_gfm + @paragraph_end = self.class::PARAGRAPH_END + end + + {codeblock_fenced: :codeblock_fenced_gfm, + atx_header: atx_header_parser}.each do |current, replacement| + i = @block_parsers.index(current) + @block_parsers.delete(current) + @block_parsers.insert(i, replacement) + end + + i = @span_parsers.index(:escaped_chars) + @span_parsers[i] = :escaped_chars_gfm if i + @span_parsers << :strikethrough_gfm + + @hard_line_break = "#{@options[:hard_wrap] ? '' : '\\'}\n" + end + + def parse + super + update_elements(@root) + end + + def update_elements(element) + element.children.map! do |child| + if child.type == :text && child.value.include?(@hard_line_break) + update_text_type(element, child) + elsif child.type == :html_element + child + elsif child.type == :header && @options[:auto_ids] && !child.attr.key?('id') + child.attr['id'] = generate_gfm_header_id(child.options[:raw_text]) + child + else + update_elements(child) + child + end + end.flatten! + end + + # Update the raw text for automatic ID generation. + def update_raw_text(item) + raw_text = +'' + + append_text = lambda do |child| + case child.type + when :text, :codespan, :math + raw_text << child.value + when :entity + raw_text << child.value.char + when :smart_quote + raw_text << ::Kramdown::Utils::Entities.entity(child.value.to_s).char + when :typographic_sym + raw_text << case child.value + when :laquo_space + "« " + when :raquo_space + " »" + else + ::Kramdown::Utils::Entities.entity(child.value.to_s).char + end + else + child.children.each { |c| append_text.call(c) } + end + end + + append_text.call(item) + item.options[:raw_text] = raw_text + end + + NON_WORD_RE = /[^\p{Word}\- \t]/.freeze + + def generate_gfm_header_id(text) + result = text.downcase + result.gsub!(NON_WORD_RE, '') + result.tr!(" \t", '-') + + @id_counter[result] += 1 + counter_result = @id_counter[result] + result << "-#{counter_result}" if counter_result > 0 + + @options[:auto_id_prefix] + result + end + + ATX_HEADER_START = /^(?\#{1,6})[\t ]+(?.*)\n/.freeze + define_parser(:atx_header_gfm, ATX_HEADER_START, nil, 'parse_atx_header') + define_parser(:atx_header_gfm_quirk, ATX_HEADER_START) + + # Copied from kramdown/parser/kramdown/header.rb, removed the first line + def parse_atx_header_gfm_quirk + text, id = parse_header_contents + text.sub!(/[\t ]#+\z/, '') && text.rstrip! + return false if text.empty? + + add_header(@src["level"].length, text, id) + true + end + + FENCED_CODEBLOCK_START = /^[ ]{0,3}[~`]{3,}/.freeze + FENCED_CODEBLOCK_MATCH = /^[ ]{0,3}(([~`]){3,})\s*?((\S+?)(?:\?\S*)?)?\s*?\n(.*?)^[ ]{0,3}\1\2*\s*?\n/m.freeze + define_parser(:codeblock_fenced_gfm, FENCED_CODEBLOCK_START, nil, 'parse_codeblock_fenced') + + STRIKETHROUGH_DELIM = /~~/.freeze + STRIKETHROUGH_MATCH = /#{STRIKETHROUGH_DELIM}(?!\s|~).*?[^\s~]#{STRIKETHROUGH_DELIM}/m.freeze + define_parser(:strikethrough_gfm, STRIKETHROUGH_MATCH, '~~') + + def parse_strikethrough_gfm + line_number = @src.current_line_number + + @src.pos += @src.matched_size + el = Element.new(:html_element, 'del', {}, category: :span, line: line_number) + @tree.children << el + + env = save_env + reset_env(src: Kramdown::Utils::StringScanner.new(@src.matched[2..-3], line_number), + text_type: :text) + parse_spans(el) + restore_env(env) + + el + end + + LIST_TYPES = [:ul, :ol].freeze + + # To handle task-lists we override the parse method for lists, converting matching text into + # checkbox input elements where necessary (as well as applying classes to the ul/ol and li + # elements). + def parse_list + super + current_list = @tree.children.select { |element| LIST_TYPES.include?(element.type) }.last + + is_tasklist = false + box_unchecked = '' + box_checked = '' + + current_list.children.each do |li| + list_items = li.children + next unless !list_items.empty? && list_items[0].type == :p + + # li -> p -> raw_text + descendant = list_items[0].children[0].value + checked = descendant.gsub!(/\A\s*\[ \]\s+/, box_unchecked) + unchecked = descendant.gsub!(/\A\s*\[x\]\s+/i, box_checked) + is_tasklist ||= checked || unchecked + + li.attr['class'] = 'task-list-item' if is_tasklist + end + + current_list.attr['class'] = 'task-list' if is_tasklist + + true + end + + ESCAPED_CHARS_GFM = /\\([\\.*_+`<>()\[\]{}#!:\|"'\$=\-~])/.freeze + define_parser(:escaped_chars_gfm, ESCAPED_CHARS_GFM, '\\\\', :parse_escaped_chars) + + PARAGRAPH_END_GFM = Regexp.union( + LAZY_END, LIST_START, ATX_HEADER_START, DEFINITION_LIST_START, + BLOCKQUOTE_START, FENCED_CODEBLOCK_START + ) + + private + + def update_text_type(element, child) + children = [] + lines = child.value.split(@hard_line_break, -1) + omit_trailing_br = (lines[-1].empty? && Kramdown::Element.category(element) == :block && + element.children[-1] == child) + + lines.each_with_index do |line, index| + new_element_options = {location: child.options[:location] + index} + children << Element.new(:text, (index > 0 ? "\n#{line}" : line), nil, new_element_options) + + if index < lines.size - 2 || (index == lines.size - 2 && !omit_trailing_br) + children << Element.new(:br, nil, nil, new_element_options) + end + end + + children + end + + end + end +end diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm/options.rb b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm/options.rb new file mode 100644 index 00000000..2fcd7877 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/lib/kramdown/parser/gfm/options.rb @@ -0,0 +1,60 @@ +# -*- coding: utf-8; frozen_string_literal: true -*- +# +#-- +# Copyright (C) 2019 Thomas Leitner +# +# This file is part of kramdown-parser-gfm which is licensed under the MIT. +#++ +# + +module Kramdown + module Options + + define(:hard_wrap, Boolean, true, <<~EOF) + Interprets line breaks literally + + Insert HTML `
` tags inside paragraphs where the original Markdown + document had newlines (by default, Markdown ignores these newlines). + + Default: true + Used by: GFM parser + EOF + + define(:gfm_quirks, Object, [:paragraph_end], <<~EOF) do |val| + Enables a set of GFM specific quirks + + The way how GFM is transformed on Github often differs from the way + kramdown does things. Many of these differences are negligible but + others are not. + + This option allows one to enable/disable certain GFM quirks, i.e. ways + in which GFM parsing differs from kramdown parsing. + + The value has to be a list of quirk names that should be enabled, + separated by commas. Possible names are: + + * paragraph_end + + Disables the kramdown restriction that at least one blank line has to + be used after a paragraph before a new block element can be started. + + Note that if this quirk is used, lazy line wrapping does not fully + work anymore! + + * no_auto_typographic + + Disables automatic conversion of some characters into their + corresponding typographic symbols (like `--` to em-dash etc). + This helps to achieve results closer to what GitHub Flavored + Markdown produces. + + Default: paragraph_end + Used by: GFM parser + EOF + val = simple_array_validator(val, :gfm_quirks) + val.map! { |v| str_to_sym(v.to_s) } + val + end + + end +end diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/test_files.rb b/bin/gems/kramdown-parser-gfm-1.1.0/test/test_files.rb new file mode 100644 index 00000000..664f13dd --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/test_files.rb @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# +#-- +# Copyright (C) 2019 Thomas Leitner +# +# This file is part of kramdown-parser-gfm which is licensed under the MIT. +#++ +# + +require 'minitest/autorun' +require 'kramdown' +require 'kramdown/parser/gfm' +require 'yaml' +require 'tmpdir' + +Encoding.default_external = 'utf-8' + +class TestFiles < Minitest::Test + + # Generate test methods for gfm-to-html conversion + Dir[__dir__ + '/testcases/**/*.text'].each do |text_file| + basename = text_file.sub(/\.text$/, '') + + html_file = basename + '.html' + next unless File.exist?(html_file) + + define_method('test_gfm_' + File.basename(text_file, '.*') + '_to_html') do + opts_file = basename + '.options' + opts_file = File.join(File.dirname(html_file), 'options') if !File.exist?(opts_file) + options = File.exist?(opts_file) ? YAML::load(File.read(opts_file)) : {auto_ids: false, footnote_nr: 1} + doc = Kramdown::Document.new(File.read(text_file), options.merge(input: 'GFM')) + assert_equal(File.read(html_file), doc.to_html) + end + end + +end diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.html new file mode 100644 index 00000000..776d7a15 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.html @@ -0,0 +1,3 @@ +

header

+ +

#no header

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.text new file mode 100644 index 00000000..5e70e2b1 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/atx_header.text @@ -0,0 +1,3 @@ +# header + +#no header diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.html new file mode 100644 index 00000000..305f4c5f --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.html @@ -0,0 +1,14 @@ +
Three backticks
+
+ +
Four backticks
+
+ +
Unbalanced bottom heavy
+
+ +
language no space
+
+ +
language with space
+
diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.options new file mode 100644 index 00000000..72e9bc1e --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.options @@ -0,0 +1 @@ +:enable_coderay: false diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.text new file mode 100644 index 00000000..fb5c6111 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/backticks_syntax.text @@ -0,0 +1,19 @@ +``` +Three backticks +``` + +```` +Four backticks +```` + +``` +Unbalanced bottom heavy +`````` + +````ruby +language no space +```` + +```` ruby +language with space +```` diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.html new file mode 100644 index 00000000..5ededae1 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.html @@ -0,0 +1,20 @@ +

normal

+ +
require 'kramdown'
+
+Kramdown::Document.new(text).to_html
+
+ +

indent with tab

+ +
```ruby
+require 'kramdown'
+
+Kramdown::Document.new(text).to_html
+```
+
+ +

indent with 2 spaces

+ +
  console.log("hello");
+
diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.options new file mode 100644 index 00000000..72e9bc1e --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.options @@ -0,0 +1 @@ +:enable_coderay: false diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.text new file mode 100644 index 00000000..5e3e192c --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/codeblock_fenced.text @@ -0,0 +1,21 @@ +normal + +```ruby +require 'kramdown' + +Kramdown::Document.new(text).to_html +``` + +indent with tab + + ```ruby + require 'kramdown' + + Kramdown::Document.new(text).to_html + ``` + +indent with 2 spaces + + ```js + console.log("hello"); + ``` diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.html new file mode 100644 index 00000000..1dfb2f08 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.html @@ -0,0 +1,3 @@ +

one
+two
+three

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.text new file mode 100644 index 00000000..f1287bde --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks.text @@ -0,0 +1,3 @@ +one +_two_ +three diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.html new file mode 100644 index 00000000..4b34619e --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.html @@ -0,0 +1,5 @@ +

This is just a normal paragraph.
+Containing a manual line break above.

+ +

It was the best of times,
+it was the worst of times.

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.options new file mode 100644 index 00000000..f2da6832 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.options @@ -0,0 +1 @@ +:hard_wrap: false diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.text new file mode 100644 index 00000000..29e1d485 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/hard_line_breaks_off.text @@ -0,0 +1,5 @@ +This is just a normal paragraph. +Containing a manual line break above. + +It was the best of times,\ +it was the worst of times. diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.html new file mode 100644 index 00000000..b45fe8f3 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.html @@ -0,0 +1,27 @@ +

test

+ +

variable_name

+ +

abc def öúß

+ +

192 abc 192

+ +

;.;;

+ +

variable_name

+ +

variable_name

+ +

;;

+ +

before after tab

+ +

with code

+ +

with  ä space

+ +

With “smart” quotes

+ +

with — « typographic » … symbols

+ +

with

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.options new file mode 100644 index 00000000..8776b552 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.options @@ -0,0 +1 @@ +:auto_ids: true diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.text new file mode 100644 index 00000000..0a89c0b4 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids.text @@ -0,0 +1,27 @@ +### test {#myid} + +### variable_name + +### abc def öúß + +### 192 abc 192 + +### ;.;; + +### variable_name + +### variable_name + +### ;; + +### before after tab + +### with `code` + +### with  ä space + +### With "smart" quotes + +### with --- << typographic >> ... symbols + +### with $$m=5$$ diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.html new file mode 100644 index 00000000..4aab0728 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.html @@ -0,0 +1,3 @@ +

Header 1

+ +

123

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.options new file mode 100644 index 00000000..f37255d5 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.options @@ -0,0 +1,2 @@ +:auto_ids: true +:auto_id_prefix: hallo- diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.text new file mode 100644 index 00000000..acf09fe4 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/header_ids_with_prefix.text @@ -0,0 +1,3 @@ +# Header 1 + +# 123 diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.html new file mode 100644 index 00000000..beecad4c --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.html @@ -0,0 +1,3 @@ +

Header with --ndash

+ +

with --- << typographic >> ... symbols

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.options new file mode 100644 index 00000000..4a83cd1b --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.options @@ -0,0 +1 @@ +:gfm_quirks: [no_auto_typographic] diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.text new file mode 100644 index 00000000..f5796511 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/no_typographic.text @@ -0,0 +1,3 @@ +### Header with --ndash + +### with --- << typographic >> ... symbols diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.html new file mode 100644 index 00000000..41dfb3a6 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.html @@ -0,0 +1,31 @@ +

A
+ - b

+ +

This is a list
+- or is it

+ +

blockquote
+> text

+ +

header
+# text

+ +

codeblock fenced
+ +puts hello world +

+ +
    +
  • +

    level 1
    +some text

    + +

    begin level 2
    +* level 2
    +* level 2

    +
  • +
+ +

h1

+

## h2
+### h3

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.options b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.options new file mode 100644 index 00000000..704f643d --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.options @@ -0,0 +1 @@ +:gfm_quirks: [] diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.text new file mode 100644 index 00000000..4e09e039 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end-disabled.text @@ -0,0 +1,27 @@ +A + - b + +This is a list +- or is it + +blockquote +> text + +header +# text + +codeblock fenced +``` +puts hello world +``` + +* level 1 + some text + + begin level 2 + * level 2 + * level 2 + +# h1 +## h2 +### h3 diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.html new file mode 100644 index 00000000..c337d61d --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.html @@ -0,0 +1,38 @@ +

A

+
    +
  • b
  • +
+ +

This is a list

+
    +
  • or is it
  • +
+ +

blockquote

+
+

text

+
+ +

header

+

text

+ +

codeblock fenced

+
puts hello world
+
+ +
    +
  • +

    level 1
    +some text

    + +

    begin level 2

    +
      +
    • level 2
    • +
    • level 2
    • +
    +
  • +
+ +

h1

+

h2

+

h3

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.text new file mode 100644 index 00000000..4e09e039 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/paragraph_end.text @@ -0,0 +1,27 @@ +A + - b + +This is a list +- or is it + +blockquote +> text + +header +# text + +codeblock fenced +``` +puts hello world +``` + +* level 1 + some text + + begin level 2 + * level 2 + * level 2 + +# h1 +## h2 +### h3 diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.html new file mode 100644 index 00000000..d35158fc --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.html @@ -0,0 +1,33 @@ +

This is a test

+ +

~This is another test~

+ +

This is yet another test~

+ +

~~ This is a test of it NOT working ~~

+ +

~~
+This
+is
+a
+multiline
+test
+~~

+ +

This is an inline strikethrough test

+ +

This is an ~~escaped~~ strikethrough.

+ +

This is a strikethrough with a ~ in the middle

+ +

I don’t even~ have an extra tilde.

+ +

This should ~~not be struck.

+ +

This is a complex strike through *test ~~with nesting involved* here~~.

+ +

This is a complex strike through *test with apparent nesting involved* here.

+ +

中文

+ +

a

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.text new file mode 100644 index 00000000..0984200c --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/strikethrough.text @@ -0,0 +1,33 @@ +~~This is a test~~ + +~~~This is another test~~~ + +~~This is yet another test~~~ + +~~ This is a test of it NOT working ~~ + +~~ +This +is +a +**multiline** +test +~~ + +This is an ~~_inline_ **strikethrough**~~ test + +This is an \~~escaped~~ strikethrough. + +This is a ~~strikethrough with a ~ in the middle~~ + +I ~~don't even~~~ have an extra tilde. + +This should ~~not be struck. + +This ~~is a complex *strike* through *test ~~with nesting~~ involved* here~~. + +This ~~is a complex *strike* through *test~~ with apparent nesting ~~involved* here~~. + +~~中文~~ + +~~a~~ diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.html new file mode 100644 index 00000000..a11b553b --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.html @@ -0,0 +1,40 @@ +

unordered task list

+ +
    +
  • first ul task item
  • +
  • second ul task item
  • +
  • third ul task item
  • +
  • fourth ul task item [ ] next
  • +
+ +

unordered list

+ +
    +
  • +
    +

    first ul item

    +
    +
  • +
  • +
  • +
    test
    +
    +
  • +
  • second ul item
  • +
+ +

ordered list

+ +
    +
  1. first ol item
  2. +
  3. second ol item
  4. +
+ +

ordered task list

+ +
    +
  1. first ol task item
  2. +
  3. second ol task item
  4. +
  5. third ol task item
  6. +
  7. fourth ol task item
  8. +
diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.text new file mode 100644 index 00000000..f6ade2fa --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/task_list.text @@ -0,0 +1,26 @@ +unordered task list + +- [ ] first ul task item +- [x] second ul task item +- [X] third ul task item +- [ ] fourth ul task item [ ] next + +unordered list + +- > first ul item +- +- + test +- second ul item + +ordered list + +1. first ol item +2. second ol item + +ordered task list + +1. [ ] first ol task item +2. [x] second ol task item +3. [X] third ol task item +4. [ ] fourth ol task item diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.html b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.html new file mode 100644 index 00000000..d5ba2e41 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.html @@ -0,0 +1,4 @@ +

This is just a normal paragraph.
+Containing a line break.

+ +

Another paragraph.

diff --git a/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.text b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.text new file mode 100644 index 00000000..6b3d7c55 --- /dev/null +++ b/bin/gems/kramdown-parser-gfm-1.1.0/test/testcases/two_para_hard_line_breaks.text @@ -0,0 +1,4 @@ +This is just a normal paragraph. +Containing a line break. + +Another paragraph. diff --git a/bin/gems/liquid-4.0.4/History.md b/bin/gems/liquid-4.0.4/History.md new file mode 100644 index 00000000..6887d18d --- /dev/null +++ b/bin/gems/liquid-4.0.4/History.md @@ -0,0 +1,293 @@ +# Liquid Change Log + +## 4.0.4 / (unreleased) + +### Fixed +* Fix ruby 3.2 compatibility by avoiding use of the removed taint API + +## 4.0.3 / 2019-03-12 + +### Fixed +* Fix break and continue tags inside included templates in loops (#1072) [Justin Li] + +## 4.0.2 / 2019-03-08 + +### Changed +* Add `where` filter (#1026) [Samuel Doiron] +* Add `ParseTreeVisitor` to iterate the Liquid AST (#1025) [Stephen Paul Weber] +* Improve `strip_html` performance (#1032) [printercu] + +### Fixed +* Add error checking for invalid combinations of inputs to sort, sort_natural, where, uniq, map, compact filters (#1059) [Garland Zhang] +* Validate the character encoding in url_decode (#1070) [Clayton Smith] + +## 4.0.1 / 2018-10-09 + +### Changed +* Add benchmark group in Gemfile (#855) [Jerry Liu] +* Allow benchmarks to benchmark render by itself (#851) [Jerry Liu] +* Avoid calling `line_number` on String node when rescuing a render error. (#860) [Dylan Thacker-Smith] +* Avoid duck typing to detect whether to call render on a node. [Dylan Thacker-Smith] +* Clarify spelling of `reversed` on `for` block tag (#843) [Mark Crossfield] +* Replace recursion with loop to avoid potential stack overflow from malicious input (#891, #892) [Dylan Thacker-Smith] +* Limit block tag nesting to 100 (#894) [Dylan Thacker-Smith] +* Replace `assert_equal nil` with `assert_nil` (#895) [Dylan Thacker-Smith] +* Remove Spy Gem (#896) [Dylan Thacker-Smith] +* Add `collection_name` and `variable_name` reader to `For` block (#909) +* Symbols render as strings (#920) [Justin Li] +* Remove default value from Hash objects (#932) [Maxime Bedard] +* Remove one level of nesting (#944) [Dylan Thacker-Smith] +* Update Rubocop version (#952) [Justin Li] +* Add `at_least` and `at_most` filters (#954, #958) [Nithin Bekal] +* Add a regression test for a liquid-c trim mode bug (#972) [Dylan Thacker-Smith] +* Use https rather than git protocol to fetch liquid-c [Dylan Thacker-Smith] +* Add tests against Ruby 2.4 (#963) and 2.5 (#981) +* Replace RegExp literals with constants (#988) [Ashwin Maroli] +* Replace unnecessary `#each_with_index` with `#each` (#992) [Ashwin Maroli] +* Improve the unexpected end delimiter message for block tags. (#1003) [Dylan Thacker-Smith] +* Refactor and optimize rendering (#1005) [Christopher Aue] +* Add installation instruction (#1006) [Ben Gift] +* Remove Circle CI (#1010) +* Rename deprecated `BigDecimal.new` to `BigDecimal` (#1024) [Koichi ITO] +* Rename deprecated Rubocop name (#1027) [Justin Li] + +### Fixed +* Handle `join` filter on non String joiners (#857) [Richard Monette] +* Fix duplicate inclusion condition logic error of `Liquid::Strainer.add_filter` method (#861) +* Fix `escape`, `url_encode`, `url_decode` not handling non-string values (#898) [Thierry Joyal] +* Fix raise when variable is defined but nil when using `strict_variables` [Pascal Betz] +* Fix `sort` and `sort_natural` to handle arrays with nils (#930) [Eric Chan] + +## 4.0.0 / 2016-12-14 / branch "4-0-stable" + +### Changed +* Render an opaque internal error by default for non-Liquid::Error (#835) [Dylan Thacker-Smith] +* Ruby 2.0 support dropped (#832) [Dylan Thacker-Smith] +* Add to_number Drop method to allow custom drops to work with number filters (#731) +* Add strict_variables and strict_filters options to detect undefined references (#691) +* Improve loop performance (#681) [Florian Weingarten] +* Rename Drop method `before_method` to `liquid_method_missing` (#661) [Thierry Joyal] +* Add url_decode filter to invert url_encode (#645) [Larry Archer] +* Add global_filter to apply a filter to all output (#610) [Loren Hale] +* Add compact filter (#600) [Carson Reinke] +* Rename deprecated "has_key?" and "has_interrupt?" methods (#593) [Florian Weingarten] +* Include template name with line numbers in render errors (574) [Dylan Thacker-Smith] +* Add sort_natural filter (#554) [Martin Hanzel] +* Add forloop.parentloop as a reference to the parent loop (#520) [Justin Li] +* Block parsing moved to BlockBody class (#458) [Dylan Thacker-Smith] +* Add concat filter to concatenate arrays (#429) [Diogo Beato] +* Ruby 1.9 support dropped (#491) [Justin Li] +* Liquid::Template.file_system's read_template_file method is no longer passed the context. (#441) [James Reid-Smith] +* Remove `liquid_methods` (See https://github.com/Shopify/liquid/pull/568 for replacement) +* Liquid::Template.register_filter raises when the module overrides registered public methods as private or protected (#705) [Gaurav Chande] + +### Fixed + +* Fix variable names being detected as an operator when starting with contains (#788) [Michael Angell] +* Fix include tag used with strict_variables (#828) [QuickPay] +* Fix map filter when value is a Proc (#672) [Guillaume Malette] +* Fix truncate filter when value is not a string (#672) [Guillaume Malette] +* Fix behaviour of escape filter when input is nil (#665) [Tanel Jakobsoo] +* Fix sort filter behaviour with empty array input (#652) [Marcel Cary] +* Fix test failure under certain timezones (#631) [Dylan Thacker-Smith] +* Fix bug in uniq filter (#595) [Florian Weingarten] +* Fix bug when "blank" and "empty" are used as variable names (#592) [Florian Weingarten] +* Fix condition parse order in strict mode (#569) [Justin Li] +* Fix naming of the "context variable" when dynamically including a template (#559) [Justin Li] +* Gracefully accept empty strings in the date filter (#555) [Loren Hale] +* Fix capturing into variables with a hyphen in the name (#505) [Florian Weingarten] +* Fix case sensitivity regression in date standard filter (#499) [Kelley Reynolds] +* Disallow filters with no variable in strict mode (#475) [Justin Li] +* Disallow variable names in the strict parser that are not valid in the lax parser (#463) [Justin Li] +* Fix BlockBody#warnings taking exponential time to compute (#486) [Justin Li] + +## 3.0.5 / 2015-07-23 / branch "3-0-stable" + +* Fix test failure under certain timezones [Dylan Thacker-Smith] + +## 3.0.4 / 2015-07-17 + +* Fix chained access to multi-dimensional hashes [Florian Weingarten] + +## 3.0.3 / 2015-05-28 + +* Fix condition parse order in strict mode (#569) [Justin Li] + +## 3.0.2 / 2015-04-24 + +* Expose VariableLookup private members (#551) [Justin Li] +* Documentation fixes + +## 3.0.1 / 2015-01-23 + +* Remove duplicate `index0` key in TableRow tag (#502) [Alfred Xing] + +## 3.0.0 / 2014-11-12 + +* Removed Block#end_tag. Instead, override parse with `super` followed by your code. See #446 [Dylan Thacker-Smith] +* Fixed condition with wrong data types (#423) [Bogdan Gusiev] +* Add url_encode to standard filters (#421) [Derrick Reimer] +* Add uniq to standard filters [Florian Weingarten] +* Add exception_handler feature (#397) and #254 [Bogdan Gusiev, Florian Weingarten] +* Optimize variable parsing to avoid repeated regex evaluation during template rendering #383 [Jason Hiltz-Laforge] +* Optimize checking for block interrupts to reduce object allocation #380 [Jason Hiltz-Laforge] +* Properly set context rethrow_errors on render! #349 [Thierry Joyal] +* Fix broken rendering of variables which are equal to false (#345) [Florian Weingarten] +* Remove ActionView template handler [Dylan Thacker-Smith] +* Freeze lots of string literals for new Ruby 2.1 optimization (#297) [Florian Weingarten] +* Allow newlines in tags and variables (#324) [Dylan Thacker-Smith] +* Tag#parse is called after initialize, which now takes options instead of tokens as the 3rd argument. See #321 [Dylan Thacker-Smith] +* Raise `Liquid::ArgumentError` instead of `::ArgumentError` when filter has wrong number of arguments #309 [Bogdan Gusiev] +* Add a to_s default for liquid drops (#306) [Adam Doeler] +* Add strip, lstrip, and rstrip to standard filters [Florian Weingarten] +* Make if, for & case tags return complete and consistent nodelists (#250) [Nick Jones] +* Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith] +* Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl] +* Fix resource counting bug with respond_to?(:length) (#263) [Florian Weingarten] +* Allow specifying custom patterns for template filenames (#284) [Andrei Gladkyi] +* Allow drops to optimize loading a slice of elements (#282) [Tom Burns] +* Support for passing variables to snippets in subdirs (#271) [Joost Hietbrink] +* Add a class cache to avoid runtime extend calls (#249) [James Tucker] +* Remove some legacy Ruby 1.8 compatibility code (#276) [Florian Weingarten] +* Add default filter to standard filters (#267) [Derrick Reimer] +* Add optional strict parsing and warn parsing (#235) [Tristan Hume] +* Add I18n syntax error translation (#241) [Simon Hørup Eskildsen, Sirupsen] +* Make sort filter work on enumerable drops (#239) [Florian Weingarten] +* Fix clashing method names in enumerable drops (#238) [Florian Weingarten] +* Make map filter work on enumerable drops (#233) [Florian Weingarten] +* Improved whitespace stripping for blank blocks, related to #216 [Florian Weingarten] + +## 2.6.3 / 2015-07-23 / branch "2-6-stable" + +* Fix test failure under certain timezones [Dylan Thacker-Smith] + +## 2.6.2 / 2015-01-23 + +* Remove duplicate hash key [Parker Moore] + +## 2.6.1 / 2014-01-10 + +Security fix, cherry-picked from master (4e14a65): +* Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl] +* Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith] + +## 2.6.0 / 2013-11-25 + +IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability. +The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8. + +* Bugfix for #106: fix example servlet [gnowoel] +* Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss] +* Bugfix for #114: strip_html filter supports style tags [James Allardice] +* Bugfix for #117: 'now' support for date filter in Ruby 1.9 [Notre Dame Webgroup] +* Bugfix for #166: truncate filter on UTF-8 strings with Ruby 1.8 [Florian Weingarten] +* Bugfix for #204: 'raw' parsing bug [Florian Weingarten] +* Bugfix for #150: 'for' parsing bug [Peter Schröder] +* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder] +* Bugfix for #174, "can't convert Fixnum into String" for "replace" [jsw0528] +* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep] +* Resource limits [Florian Weingarten] +* Add reverse filter [Jay Strybis] +* Add utf-8 support +* Use array instead of Hash to keep the registered filters [Tasos Stathopoulos] +* Cache tokenized partial templates [Tom Burns] +* Avoid warnings in Ruby 1.9.3 [Marcus Stollsteimer] +* Better documentation for 'include' tag (closes #163) [Peter Schröder] +* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves] + +## 2.5.5 / 2014-01-10 / branch "2-5-stable" + +Security fix, cherry-picked from master (4e14a65): +* Don't call to_sym when creating conditions for security reasons (#273) [Bouke van der Bijl] +* Prevent arbitrary method invocation on condition objects (#274) [Dylan Thacker-Smith] + +## 2.5.4 / 2013-11-11 + +* Fix "can't convert Fixnum into String" for "replace" (#173), [jsw0528] + +## 2.5.3 / 2013-10-09 + +* #232, #234, #237: Fix map filter bugs [Florian Weingarten] + +## 2.5.2 / 2013-09-03 / deleted + +Yanked from rubygems, as it contained too many changes that broke compatibility. Those changes will be on following major releases. + +## 2.5.1 / 2013-07-24 + +* #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten] + +## 2.5.0 / 2013-03-06 + +* Prevent Object methods from being called on drops +* Avoid symbol injection from liquid +* Added break and continue statements +* Fix filter parser for args without space separators +* Add support for filter keyword arguments + + +## 2.4.0 / 2012-08-03 + +* Performance improvements +* Allow filters in `assign` +* Add `modulo` filter +* Ruby 1.8, 1.9, and Rubinius compatibility fixes +* Add support for `quoted['references']` in `tablerow` +* Add support for Enumerable to `tablerow` +* `strip_html` filter removes html comments + + +## 2.3.0 / 2011-10-16 + +* Several speed/memory improvements +* Numerous bug fixes +* Added support for MRI 1.9, Rubinius, and JRuby +* Added support for integer drop parameters +* Added epoch support to `date` filter +* New `raw` tag that suppresses parsing +* Added `else` option to `for` tag +* New `increment` tag +* New `split` filter + + +## 2.2.1 / 2010-08-23 + +* Added support for literal tags + + +## 2.2.0 / 2010-08-22 + +* Compatible with Ruby 1.8.7, 1.9.1 and 1.9.2-p0 +* Merged some changed made by the community + + +## 1.9.0 / 2008-03-04 + +* Fixed gem install rake task +* Improve Error encapsulation in liquid by maintaining a own set of exceptions instead of relying on ruby build ins + + +## Before 1.9.0 + +* Added If with or / and expressions +* Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans. To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods. +* Added more tags to standard library +* Added include tag ( like partials in rails ) +* [...] Gazillion of detail improvements +* Added strainers as filter hosts for better security [Tobias Luetke] +* Fixed that rails integration would call filter with the wrong "self" [Michael Geary] +* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke] +* Removed count helper from standard lib. use size [Tobias Luetke] +* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond] +* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond] + {{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }} +* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke] + + class ProductDrop < Liquid::Drop + def top_sales + Shop.current.products.find(:all, :order => 'sales', :limit => 10 ) + end + end + t = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {% endfor %} ' ) + t.render('product' => ProductDrop.new ) +* Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond] diff --git a/bin/gems/liquid-4.0.4/LICENSE b/bin/gems/liquid-4.0.4/LICENSE new file mode 100644 index 00000000..926b04eb --- /dev/null +++ b/bin/gems/liquid-4.0.4/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2005, 2006 Tobias Luetke + +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/bin/gems/liquid-4.0.4/README.md b/bin/gems/liquid-4.0.4/README.md new file mode 100644 index 00000000..77e9ff43 --- /dev/null +++ b/bin/gems/liquid-4.0.4/README.md @@ -0,0 +1,108 @@ +[![Build Status](https://api.travis-ci.org/Shopify/liquid.svg?branch=master)](http://travis-ci.org/Shopify/liquid) +[![Inline docs](http://inch-ci.org/github/Shopify/liquid.svg?branch=master)](http://inch-ci.org/github/Shopify/liquid) + +# Liquid template engine + +* [Contributing guidelines](CONTRIBUTING.md) +* [Version history](History.md) +* [Liquid documentation from Shopify](http://docs.shopify.com/themes/liquid-basics) +* [Liquid Wiki at GitHub](https://github.com/Shopify/liquid/wiki) +* [Website](http://liquidmarkup.org/) + +## Introduction + +Liquid is a template engine which was written with very specific requirements: + +* It has to have beautiful and simple markup. Template engines which don't produce good looking markup are no fun to use. +* It needs to be non evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote. +* It has to be stateless. Compile and render steps have to be separate so that the expensive parsing and compiling can be done once and later on you can just render it passing in a hash with local variables and objects. + +## Why you should use Liquid + +* You want to allow your users to edit the appearance of your application but don't want them to run **insecure code on your server**. +* You want to render templates directly from the database. +* You like smarty (PHP) style template engines. +* You need a template engine which does HTML just as well as emails. +* You don't like the markup of your current templating engine. + +## What does it look like? + +```html +
    + {% for product in products %} +
  • +

    {{ product.name }}

    + Only {{ product.price | price }} + + {{ product.description | prettyprint | paragraph }} +
  • + {% endfor %} +
+``` + +## How to use Liquid + +Install Liquid by adding `gem 'liquid'` to your gemfile. + +Liquid supports a very simple API based around the Liquid::Template class. +For standard use you can just pass it the content of a file and call render with a parameters hash. + +```ruby +@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template +@template.render('name' => 'tobi') # => "hi tobi" +``` + +### Error Modes + +Setting the error mode of Liquid lets you specify how strictly you want your templates to be interpreted. +Normally the parser is very lax and will accept almost anything without error. Unfortunately this can make +it very hard to debug and can lead to unexpected behaviour. + +Liquid also comes with a stricter parser that can be used when editing templates to give better error messages +when templates are invalid. You can enable this new parser like this: + +```ruby +Liquid::Template.error_mode = :strict # Raises a SyntaxError when invalid syntax is used +Liquid::Template.error_mode = :warn # Adds errors to template.errors but continues as normal +Liquid::Template.error_mode = :lax # The default mode, accepts almost anything. +``` + +If you want to set the error mode only on specific templates you can pass `:error_mode` as an option to `parse`: +```ruby +Liquid::Template.parse(source, :error_mode => :strict) +``` +This is useful for doing things like enabling strict mode only in the theme editor. + +It is recommended that you enable `:strict` or `:warn` mode on new apps to stop invalid templates from being created. +It is also recommended that you use it in the template editors of existing apps to give editors better error messages. + +### Undefined variables and filters + +By default, the renderer doesn't raise or in any other way notify you if some variables or filters are missing, i.e. not passed to the `render` method. +You can improve this situation by passing `strict_variables: true` and/or `strict_filters: true` options to the `render` method. +When one of these options is set to true, all errors about undefined variables and undefined filters will be stored in `errors` array of a `Liquid::Template` instance. +Here are some examples: + +```ruby +template = Liquid::Template.parse("{{x}} {{y}} {{z.a}} {{z.b}}") +template.render({ 'x' => 1, 'z' => { 'a' => 2 } }, { strict_variables: true }) +#=> '1 2 ' # when a variable is undefined, it's rendered as nil +template.errors +#=> [#, #] +``` + +```ruby +template = Liquid::Template.parse("{{x | filter1 | upcase}}") +template.render({ 'x' => 'foo' }, { strict_filters: true }) +#=> '' # when at least one filter in the filter chain is undefined, a whole expression is rendered as nil +template.errors +#=> [#] +``` + +If you want to raise on a first exception instead of pushing all of them in `errors`, you can use `render!` method: + +```ruby +template = Liquid::Template.parse("{{x}} {{y}}") +template.render!({ 'x' => 1}, { strict_variables: true }) +#=> Liquid::UndefinedVariable: Liquid error: undefined variable y +``` diff --git a/bin/gems/liquid-4.0.4/lib/liquid.rb b/bin/gems/liquid-4.0.4/lib/liquid.rb new file mode 100644 index 00000000..770d2f91 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid.rb @@ -0,0 +1,80 @@ +# Copyright (c) 2005 Tobias Luetke +# +# 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. + +module Liquid + FilterSeparator = /\|/ + ArgumentSeparator = ','.freeze + FilterArgumentSeparator = ':'.freeze + VariableAttributeSeparator = '.'.freeze + WhitespaceControl = '-'.freeze + TagStart = /\{\%/ + TagEnd = /\%\}/ + VariableSignature = /\(?[\w\-\.\[\]]\)?/ + VariableSegment = /[\w\-]/ + VariableStart = /\{\{/ + VariableEnd = /\}\}/ + VariableIncompleteEnd = /\}\}?/ + QuotedString = /"[^"]*"|'[^']*'/ + QuotedFragment = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o + TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/o + AnyStartingTag = /#{TagStart}|#{VariableStart}/o + PartialTemplateParser = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om + TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om + VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o + + singleton_class.send(:attr_accessor, :cache_classes) + self.cache_classes = true +end + +require "liquid/version" +require 'liquid/parse_tree_visitor' +require 'liquid/lexer' +require 'liquid/parser' +require 'liquid/i18n' +require 'liquid/drop' +require 'liquid/tablerowloop_drop' +require 'liquid/forloop_drop' +require 'liquid/extensions' +require 'liquid/errors' +require 'liquid/interrupts' +require 'liquid/strainer' +require 'liquid/expression' +require 'liquid/context' +require 'liquid/parser_switching' +require 'liquid/tag' +require 'liquid/block' +require 'liquid/block_body' +require 'liquid/document' +require 'liquid/variable' +require 'liquid/variable_lookup' +require 'liquid/range_lookup' +require 'liquid/file_system' +require 'liquid/resource_limits' +require 'liquid/template' +require 'liquid/standardfilters' +require 'liquid/condition' +require 'liquid/utils' +require 'liquid/tokenizer' +require 'liquid/parse_context' + +# Load all the tags of the standard library +# +Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f } diff --git a/bin/gems/liquid-4.0.4/lib/liquid/block.rb b/bin/gems/liquid-4.0.4/lib/liquid/block.rb new file mode 100644 index 00000000..00c59b2d --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/block.rb @@ -0,0 +1,77 @@ +module Liquid + class Block < Tag + MAX_DEPTH = 100 + + def initialize(tag_name, markup, options) + super + @blank = true + end + + def parse(tokens) + @body = BlockBody.new + while parse_body(@body, tokens) + end + end + + def render(context) + @body.render(context) + end + + def blank? + @blank + end + + def nodelist + @body.nodelist + end + + def unknown_tag(tag, _params, _tokens) + if tag == 'else'.freeze + raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_else".freeze, + block_name: block_name)) + elsif tag.start_with?('end'.freeze) + raise SyntaxError.new(parse_context.locale.t("errors.syntax.invalid_delimiter".freeze, + tag: tag, + block_name: block_name, + block_delimiter: block_delimiter)) + else + raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)) + end + end + + def block_name + @tag_name + end + + def block_delimiter + @block_delimiter ||= "end#{block_name}" + end + + protected + + def parse_body(body, tokens) + if parse_context.depth >= MAX_DEPTH + raise StackLevelError, "Nesting too deep".freeze + end + parse_context.depth += 1 + begin + body.parse(tokens, parse_context) do |end_tag_name, end_tag_params| + @blank &&= body.blank? + + return false if end_tag_name == block_delimiter + unless end_tag_name + raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)) + end + + # this tag is not registered with the system + # pass it to the current block for special handling or error reporting + unknown_tag(end_tag_name, end_tag_params, tokens) + end + ensure + parse_context.depth -= 1 + end + + true + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/block_body.rb b/bin/gems/liquid-4.0.4/lib/liquid/block_body.rb new file mode 100644 index 00000000..ba294155 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/block_body.rb @@ -0,0 +1,143 @@ +module Liquid + class BlockBody + FullToken = /\A#{TagStart}#{WhitespaceControl}?\s*(\w+)\s*(.*?)#{WhitespaceControl}?#{TagEnd}\z/om + ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om + WhitespaceOrNothing = /\A\s*\z/ + TAGSTART = "{%".freeze + VARSTART = "{{".freeze + + attr_reader :nodelist + + def initialize + @nodelist = [] + @blank = true + end + + def parse(tokenizer, parse_context) + parse_context.line_number = tokenizer.line_number + while token = tokenizer.shift + next if token.empty? + case + when token.start_with?(TAGSTART) + whitespace_handler(token, parse_context) + unless token =~ FullToken + raise_missing_tag_terminator(token, parse_context) + end + tag_name = $1 + markup = $2 + # fetch the tag from registered blocks + unless tag = registered_tags[tag_name] + # end parsing if we reach an unknown tag and let the caller decide + # determine how to proceed + return yield tag_name, markup + end + new_tag = tag.parse(tag_name, markup, tokenizer, parse_context) + @blank &&= new_tag.blank? + @nodelist << new_tag + when token.start_with?(VARSTART) + whitespace_handler(token, parse_context) + @nodelist << create_variable(token, parse_context) + @blank = false + else + if parse_context.trim_whitespace + token.lstrip! + end + parse_context.trim_whitespace = false + @nodelist << token + @blank &&= !!(token =~ WhitespaceOrNothing) + end + parse_context.line_number = tokenizer.line_number + end + + yield nil, nil + end + + def whitespace_handler(token, parse_context) + if token[2] == WhitespaceControl + previous_token = @nodelist.last + if previous_token.is_a? String + previous_token.rstrip! + end + end + parse_context.trim_whitespace = (token[-3] == WhitespaceControl) + end + + def blank? + @blank + end + + def render(context) + output = [] + context.resource_limits.render_score += @nodelist.length + + idx = 0 + while node = @nodelist[idx] + case node + when String + check_resources(context, node) + output << node + when Variable + render_node_to_output(node, output, context) + when Block + render_node_to_output(node, output, context, node.blank?) + break if context.interrupt? # might have happened in a for-block + when Continue, Break + # If we get an Interrupt that means the block must stop processing. An + # Interrupt is any command that stops block execution such as {% break %} + # or {% continue %} + context.push_interrupt(node.interrupt) + break + else # Other non-Block tags + render_node_to_output(node, output, context) + break if context.interrupt? # might have happened through an include + end + idx += 1 + end + + output.join + end + + private + + def render_node_to_output(node, output, context, skip_output = false) + node_output = node.render(context) + node_output = node_output.is_a?(Array) ? node_output.join : node_output.to_s + check_resources(context, node_output) + output << node_output unless skip_output + rescue MemoryError => e + raise e + rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e + context.handle_error(e, node.line_number) + output << nil + rescue ::StandardError => e + line_number = node.is_a?(String) ? nil : node.line_number + output << context.handle_error(e, line_number) + end + + def check_resources(context, node_output) + context.resource_limits.render_length += node_output.length + return unless context.resource_limits.reached? + raise MemoryError.new("Memory limits exceeded".freeze) + end + + def create_variable(token, parse_context) + token.scan(ContentOfVariable) do |content| + markup = content.first + return Variable.new(markup, parse_context) + end + raise_missing_variable_terminator(token, parse_context) + end + + def raise_missing_tag_terminator(token, parse_context) + raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_termination".freeze, token: token, tag_end: TagEnd.inspect)) + end + + def raise_missing_variable_terminator(token, parse_context) + raise SyntaxError.new(parse_context.locale.t("errors.syntax.variable_termination".freeze, token: token, tag_end: VariableEnd.inspect)) + end + + def registered_tags + Template.tags + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/condition.rb b/bin/gems/liquid-4.0.4/lib/liquid/condition.rb new file mode 100644 index 00000000..3b51682e --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/condition.rb @@ -0,0 +1,151 @@ +module Liquid + # Container for liquid nodes which conveniently wraps decision making logic + # + # Example: + # + # c = Condition.new(1, '==', 1) + # c.evaluate #=> true + # + class Condition #:nodoc: + @@operators = { + '=='.freeze => ->(cond, left, right) { cond.send(:equal_variables, left, right) }, + '!='.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) }, + '<>'.freeze => ->(cond, left, right) { !cond.send(:equal_variables, left, right) }, + '<'.freeze => :<, + '>'.freeze => :>, + '>='.freeze => :>=, + '<='.freeze => :<=, + 'contains'.freeze => lambda do |cond, left, right| + if left && right && left.respond_to?(:include?) + right = right.to_s if left.is_a?(String) + left.include?(right) + else + false + end + end + } + + def self.operators + @@operators + end + + attr_reader :attachment, :child_condition + attr_accessor :left, :operator, :right + + def initialize(left = nil, operator = nil, right = nil) + @left = left + @operator = operator + @right = right + @child_relation = nil + @child_condition = nil + end + + def evaluate(context = Context.new) + condition = self + result = nil + loop do + result = interpret_condition(condition.left, condition.right, condition.operator, context) + + case condition.child_relation + when :or + break if result + when :and + break unless result + else + break + end + condition = condition.child_condition + end + result + end + + def or(condition) + @child_relation = :or + @child_condition = condition + end + + def and(condition) + @child_relation = :and + @child_condition = condition + end + + def attach(attachment) + @attachment = attachment + end + + def else? + false + end + + def inspect + "#" + end + + protected + + attr_reader :child_relation + + private + + def equal_variables(left, right) + if left.is_a?(Liquid::Expression::MethodLiteral) + if right.respond_to?(left.method_name) + return right.send(left.method_name) + else + return nil + end + end + + if right.is_a?(Liquid::Expression::MethodLiteral) + if left.respond_to?(right.method_name) + return left.send(right.method_name) + else + return nil + end + end + + left == right + end + + def interpret_condition(left, right, op, context) + # If the operator is empty this means that the decision statement is just + # a single variable. We can just poll this variable from the context and + # return this as the result. + return context.evaluate(left) if op.nil? + + left = context.evaluate(left) + right = context.evaluate(right) + + operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}")) + + if operation.respond_to?(:call) + operation.call(self, left, right) + elsif left.respond_to?(operation) && right.respond_to?(operation) && !left.is_a?(Hash) && !right.is_a?(Hash) + begin + left.send(operation, right) + rescue ::ArgumentError => e + raise Liquid::ArgumentError.new(e.message) + end + end + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + [ + @node.left, @node.right, + @node.child_condition, @node.attachment + ].compact + end + end + end + + class ElseCondition < Condition + def else? + true + end + + def evaluate(_context) + true + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/context.rb b/bin/gems/liquid-4.0.4/lib/liquid/context.rb new file mode 100644 index 00000000..2dcc6af8 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/context.rb @@ -0,0 +1,226 @@ +module Liquid + # Context keeps the variable stack and resolves variables, as well as keywords + # + # context['variable'] = 'testing' + # context['variable'] #=> 'testing' + # context['true'] #=> true + # context['10.2232'] #=> 10.2232 + # + # context.stack do + # context['bob'] = 'bobsen' + # end + # + # context['bob'] #=> nil class Context + class Context + attr_reader :scopes, :errors, :registers, :environments, :resource_limits + attr_accessor :exception_renderer, :template_name, :partial, :global_filter, :strict_variables, :strict_filters + + def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil) + @environments = [environments].flatten + @scopes = [(outer_scope || {})] + @registers = registers + @errors = [] + @partial = false + @strict_variables = false + @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits) + squash_instance_assigns_with_environments + + @this_stack_used = false + + self.exception_renderer = Template.default_exception_renderer + if rethrow_errors + self.exception_renderer = ->(e) { raise } + end + + @interrupts = [] + @filters = [] + @global_filter = nil + end + + def warnings + @warnings ||= [] + end + + def strainer + @strainer ||= Strainer.create(self, @filters) + end + + # Adds filters to this context. + # + # Note that this does not register the filters with the main Template object. see Template.register_filter + # for that + def add_filters(filters) + filters = [filters].flatten.compact + @filters += filters + @strainer = nil + end + + def apply_global_filter(obj) + global_filter.nil? ? obj : global_filter.call(obj) + end + + # are there any not handled interrupts? + def interrupt? + !@interrupts.empty? + end + + # push an interrupt to the stack. this interrupt is considered not handled. + def push_interrupt(e) + @interrupts.push(e) + end + + # pop an interrupt from the stack + def pop_interrupt + @interrupts.pop + end + + def handle_error(e, line_number = nil) + e = internal_error unless e.is_a?(Liquid::Error) + e.template_name ||= template_name + e.line_number ||= line_number + errors.push(e) + exception_renderer.call(e).to_s + end + + def invoke(method, *args) + strainer.invoke(method, *args).to_liquid + end + + # Push new local scope on the stack. use Context#stack instead + def push(new_scope = {}) + @scopes.unshift(new_scope) + raise StackLevelError, "Nesting too deep".freeze if @scopes.length > Block::MAX_DEPTH + end + + # Merge a hash of variables in the current local scope + def merge(new_scopes) + @scopes[0].merge!(new_scopes) + end + + # Pop from the stack. use Context#stack instead + def pop + raise ContextError if @scopes.size == 1 + @scopes.shift + end + + # Pushes a new local scope on the stack, pops it at the end of the block + # + # Example: + # context.stack do + # context['var'] = 'hi' + # end + # + # context['var] #=> nil + def stack(new_scope = nil) + old_stack_used = @this_stack_used + if new_scope + push(new_scope) + @this_stack_used = true + else + @this_stack_used = false + end + + yield + ensure + pop if @this_stack_used + @this_stack_used = old_stack_used + end + + def clear_instance_assigns + @scopes[0] = {} + end + + # Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop + def []=(key, value) + unless @this_stack_used + @this_stack_used = true + push({}) + end + @scopes[0][key] = value + end + + # Look up variable, either resolve directly after considering the name. We can directly handle + # Strings, digits, floats and booleans (true,false). + # If no match is made we lookup the variable in the current scope and + # later move up to the parent blocks to see if we can resolve the variable somewhere up the tree. + # Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions + # + # Example: + # products == empty #=> products.empty? + def [](expression) + evaluate(Expression.parse(expression)) + end + + def key?(key) + self[key] != nil + end + + def evaluate(object) + object.respond_to?(:evaluate) ? object.evaluate(self) : object + end + + # Fetches an object starting at the local scope and then moving up the hierachy + def find_variable(key, raise_on_not_found: true) + # This was changed from find() to find_index() because this is a very hot + # path and find_index() is optimized in MRI to reduce object allocation + index = @scopes.find_index { |s| s.key?(key) } + scope = @scopes[index] if index + + variable = nil + + if scope.nil? + @environments.each do |e| + variable = lookup_and_evaluate(e, key, raise_on_not_found: raise_on_not_found) + # When lookup returned a value OR there is no value but the lookup also did not raise + # then it is the value we are looking for. + if !variable.nil? || @strict_variables && raise_on_not_found + scope = e + break + end + end + end + + scope ||= @environments.last || @scopes.last + variable ||= lookup_and_evaluate(scope, key, raise_on_not_found: raise_on_not_found) + + variable = variable.to_liquid + variable.context = self if variable.respond_to?(:context=) + + variable + end + + def lookup_and_evaluate(obj, key, raise_on_not_found: true) + if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key) + raise Liquid::UndefinedVariable, "undefined variable #{key}" + end + + value = obj[key] + + if value.is_a?(Proc) && obj.respond_to?(:[]=) + obj[key] = (value.arity == 0) ? value.call : value.call(self) + else + value + end + end + + private + + def internal_error + # raise and catch to set backtrace and cause on exception + raise Liquid::InternalError, 'internal' + rescue Liquid::InternalError => exc + exc + end + + def squash_instance_assigns_with_environments + @scopes.last.each_key do |k| + @environments.each do |env| + if env.key?(k) + scopes.last[k] = lookup_and_evaluate(env, k) + break + end + end + end + end # squash_instance_assigns_with_environments + end # Context +end # Liquid diff --git a/bin/gems/liquid-4.0.4/lib/liquid/document.rb b/bin/gems/liquid-4.0.4/lib/liquid/document.rb new file mode 100644 index 00000000..d035dd46 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/document.rb @@ -0,0 +1,27 @@ +module Liquid + class Document < BlockBody + def self.parse(tokens, parse_context) + doc = new + doc.parse(tokens, parse_context) + doc + end + + def parse(tokens, parse_context) + super do |end_tag_name, end_tag_params| + unknown_tag(end_tag_name, parse_context) if end_tag_name + end + rescue SyntaxError => e + e.line_number ||= parse_context.line_number + raise + end + + def unknown_tag(tag, parse_context) + case tag + when 'else'.freeze, 'end'.freeze + raise SyntaxError.new(parse_context.locale.t("errors.syntax.unexpected_outer_tag".freeze, tag: tag)) + else + raise SyntaxError.new(parse_context.locale.t("errors.syntax.unknown_tag".freeze, tag: tag)) + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/drop.rb b/bin/gems/liquid-4.0.4/lib/liquid/drop.rb new file mode 100644 index 00000000..6b5aa993 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/drop.rb @@ -0,0 +1,78 @@ +require 'set' + +module Liquid + # A drop in liquid is a class which allows you to export DOM like things to liquid. + # Methods of drops are callable. + # The main use for liquid drops is to implement lazy loaded objects. + # If you would like to make data available to the web designers which you don't want loaded unless needed then + # a drop is a great way to do that. + # + # Example: + # + # class ProductDrop < Liquid::Drop + # def top_sales + # Shop.current.products.find(:all, :order => 'sales', :limit => 10 ) + # end + # end + # + # tmpl = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {%endfor%} ' ) + # tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query. + # + # Your drop can either implement the methods sans any parameters + # or implement the liquid_method_missing(name) method which is a catch all. + class Drop + attr_writer :context + + # Catch all for the method + def liquid_method_missing(method) + return nil unless @context && @context.strict_variables + raise Liquid::UndefinedDropMethod, "undefined method #{method}" + end + + # called by liquid to invoke a drop + def invoke_drop(method_or_key) + if self.class.invokable?(method_or_key) + send(method_or_key) + else + liquid_method_missing(method_or_key) + end + end + + def key?(_name) + true + end + + def inspect + self.class.to_s + end + + def to_liquid + self + end + + def to_s + self.class.name + end + + alias_method :[], :invoke_drop + + # Check for method existence without invoking respond_to?, which creates symbols + def self.invokable?(method_name) + invokable_methods.include?(method_name.to_s) + end + + def self.invokable_methods + @invokable_methods ||= begin + blacklist = Liquid::Drop.public_instance_methods + [:each] + + if include?(Enumerable) + blacklist += Enumerable.public_instance_methods + blacklist -= [:sort, :count, :first, :min, :max, :include?] + end + + whitelist = [:to_liquid] + (public_instance_methods - blacklist) + Set.new(whitelist.map(&:to_s)) + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/errors.rb b/bin/gems/liquid-4.0.4/lib/liquid/errors.rb new file mode 100644 index 00000000..defa5ea9 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/errors.rb @@ -0,0 +1,56 @@ +module Liquid + class Error < ::StandardError + attr_accessor :line_number + attr_accessor :template_name + attr_accessor :markup_context + + def to_s(with_prefix = true) + str = "" + str << message_prefix if with_prefix + str << super() + + if markup_context + str << " " + str << markup_context + end + + str + end + + private + + def message_prefix + str = "" + if is_a?(SyntaxError) + str << "Liquid syntax error" + else + str << "Liquid error" + end + + if line_number + str << " (" + str << template_name << " " if template_name + str << "line " << line_number.to_s << ")" + end + + str << ": " + str + end + end + + ArgumentError = Class.new(Error) + ContextError = Class.new(Error) + FileSystemError = Class.new(Error) + StandardError = Class.new(Error) + SyntaxError = Class.new(Error) + StackLevelError = Class.new(Error) + TaintedError = Class.new(Error) + MemoryError = Class.new(Error) + ZeroDivisionError = Class.new(Error) + FloatDomainError = Class.new(Error) + UndefinedVariable = Class.new(Error) + UndefinedDropMethod = Class.new(Error) + UndefinedFilter = Class.new(Error) + MethodOverrideError = Class.new(Error) + InternalError = Class.new(Error) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/expression.rb b/bin/gems/liquid-4.0.4/lib/liquid/expression.rb new file mode 100644 index 00000000..98be6db6 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/expression.rb @@ -0,0 +1,49 @@ +module Liquid + class Expression + class MethodLiteral + attr_reader :method_name, :to_s + + def initialize(method_name, to_s) + @method_name = method_name + @to_s = to_s + end + + def to_liquid + to_s + end + end + + LITERALS = { + nil => nil, 'nil'.freeze => nil, 'null'.freeze => nil, ''.freeze => nil, + 'true'.freeze => true, + 'false'.freeze => false, + 'blank'.freeze => MethodLiteral.new(:blank?, '').freeze, + 'empty'.freeze => MethodLiteral.new(:empty?, '').freeze + }.freeze + + SINGLE_QUOTED_STRING = /\A'(.*)'\z/m + DOUBLE_QUOTED_STRING = /\A"(.*)"\z/m + INTEGERS_REGEX = /\A(-?\d+)\z/ + FLOATS_REGEX = /\A(-?\d[\d\.]+)\z/ + RANGES_REGEX = /\A\((\S+)\.\.(\S+)\)\z/ + + def self.parse(markup) + if LITERALS.key?(markup) + LITERALS[markup] + else + case markup + when SINGLE_QUOTED_STRING, DOUBLE_QUOTED_STRING + $1 + when INTEGERS_REGEX + $1.to_i + when RANGES_REGEX + RangeLookup.parse($1, $2) + when FLOATS_REGEX + $1.to_f + else + VariableLookup.parse(markup) + end + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/extensions.rb b/bin/gems/liquid-4.0.4/lib/liquid/extensions.rb new file mode 100644 index 00000000..09078193 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/extensions.rb @@ -0,0 +1,74 @@ +require 'time' +require 'date' + +class String # :nodoc: + def to_liquid + self + end +end + +class Symbol # :nodoc: + def to_liquid + to_s + end +end + +class Array # :nodoc: + def to_liquid + self + end +end + +class Hash # :nodoc: + def to_liquid + self + end +end + +class Numeric # :nodoc: + def to_liquid + self + end +end + +class Range # :nodoc: + def to_liquid + self + end +end + +class Time # :nodoc: + def to_liquid + self + end +end + +class DateTime < Date # :nodoc: + def to_liquid + self + end +end + +class Date # :nodoc: + def to_liquid + self + end +end + +class TrueClass + def to_liquid # :nodoc: + self + end +end + +class FalseClass + def to_liquid # :nodoc: + self + end +end + +class NilClass + def to_liquid # :nodoc: + self + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/file_system.rb b/bin/gems/liquid-4.0.4/lib/liquid/file_system.rb new file mode 100644 index 00000000..13f1f460 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/file_system.rb @@ -0,0 +1,73 @@ +module Liquid + # A Liquid file system is a way to let your templates retrieve other templates for use with the include tag. + # + # You can implement subclasses that retrieve templates from the database, from the file system using a different + # path structure, you can provide them as hard-coded inline strings, or any manner that you see fit. + # + # You can add additional instance variables, arguments, or methods as needed. + # + # Example: + # + # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path) + # liquid = Liquid::Template.parse(template) + # + # This will parse the template with a LocalFileSystem implementation rooted at 'template_path'. + class BlankFileSystem + # Called by Liquid to retrieve a template file + def read_template_file(_template_path) + raise FileSystemError, "This liquid context does not allow includes." + end + end + + # This implements an abstract file system which retrieves template files named in a manner similar to Rails partials, + # ie. with the template name prefixed with an underscore. The extension ".liquid" is also added. + # + # For security reasons, template paths are only allowed to contain letters, numbers, and underscore. + # + # Example: + # + # file_system = Liquid::LocalFileSystem.new("/some/path") + # + # file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid" + # file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid" + # + # Optionally in the second argument you can specify a custom pattern for template filenames. + # The Kernel::sprintf format specification is used. + # Default pattern is "_%s.liquid". + # + # Example: + # + # file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html") + # + # file_system.full_path("index") # => "/some/path/index.html" + # + class LocalFileSystem + attr_accessor :root + + def initialize(root, pattern = "_%s.liquid".freeze) + @root = root + @pattern = pattern + end + + def read_template_file(template_path) + full_path = full_path(template_path) + raise FileSystemError, "No such template '#{template_path}'" unless File.exist?(full_path) + + File.read(full_path) + end + + def full_path(template_path) + raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /\A[^.\/][a-zA-Z0-9_\/]+\z/ + + full_path = if template_path.include?('/'.freeze) + File.join(root, File.dirname(template_path), @pattern % File.basename(template_path)) + else + File.join(root, @pattern % template_path) + end + + raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path).start_with?(File.expand_path(root)) + + full_path + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/forloop_drop.rb b/bin/gems/liquid-4.0.4/lib/liquid/forloop_drop.rb new file mode 100644 index 00000000..81b2d1a2 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/forloop_drop.rb @@ -0,0 +1,42 @@ +module Liquid + class ForloopDrop < Drop + def initialize(name, length, parentloop) + @name = name + @length = length + @parentloop = parentloop + @index = 0 + end + + attr_reader :name, :length, :parentloop + + def index + @index + 1 + end + + def index0 + @index + end + + def rindex + @length - @index + end + + def rindex0 + @length - @index - 1 + end + + def first + @index == 0 + end + + def last + @index == @length - 1 + end + + protected + + def increment! + @index += 1 + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/i18n.rb b/bin/gems/liquid-4.0.4/lib/liquid/i18n.rb new file mode 100644 index 00000000..2671507e --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/i18n.rb @@ -0,0 +1,39 @@ +require 'yaml' + +module Liquid + class I18n + DEFAULT_LOCALE = File.join(File.expand_path(__dir__), "locales", "en.yml") + + TranslationError = Class.new(StandardError) + + attr_reader :path + + def initialize(path = DEFAULT_LOCALE) + @path = path + end + + def translate(name, vars = {}) + interpolate(deep_fetch_translation(name), vars) + end + alias_method :t, :translate + + def locale + @locale ||= YAML.load_file(@path) + end + + private + + def interpolate(name, vars) + name.gsub(/%\{(\w+)\}/) do + # raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym] + (vars[$1.to_sym]).to_s + end + end + + def deep_fetch_translation(name) + name.split('.'.freeze).reduce(locale) do |level, cur| + level[cur] or raise TranslationError, "Translation for #{name} does not exist in locale #{path}" + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/interrupts.rb b/bin/gems/liquid-4.0.4/lib/liquid/interrupts.rb new file mode 100644 index 00000000..41359d78 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/interrupts.rb @@ -0,0 +1,16 @@ +module Liquid + # An interrupt is any command that breaks processing of a block (ex: a for loop). + class Interrupt + attr_reader :message + + def initialize(message = nil) + @message = message || "interrupt".freeze + end + end + + # Interrupt that is thrown whenever a {% break %} is called. + class BreakInterrupt < Interrupt; end + + # Interrupt that is thrown whenever a {% continue %} is called. + class ContinueInterrupt < Interrupt; end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/lexer.rb b/bin/gems/liquid-4.0.4/lib/liquid/lexer.rb new file mode 100644 index 00000000..f290744d --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/lexer.rb @@ -0,0 +1,55 @@ +require "strscan" +module Liquid + class Lexer + SPECIALS = { + '|'.freeze => :pipe, + '.'.freeze => :dot, + ':'.freeze => :colon, + ','.freeze => :comma, + '['.freeze => :open_square, + ']'.freeze => :close_square, + '('.freeze => :open_round, + ')'.freeze => :close_round, + '?'.freeze => :question, + '-'.freeze => :dash + }.freeze + IDENTIFIER = /[a-zA-Z_][\w-]*\??/ + SINGLE_STRING_LITERAL = /'[^\']*'/ + DOUBLE_STRING_LITERAL = /"[^\"]*"/ + NUMBER_LITERAL = /-?\d+(\.\d+)?/ + DOTDOT = /\.\./ + COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/ + WHITESPACE_OR_NOTHING = /\s*/ + + def initialize(input) + @ss = StringScanner.new(input) + end + + def tokenize + @output = [] + + until @ss.eos? + @ss.skip(WHITESPACE_OR_NOTHING) + break if @ss.eos? + tok = case + when t = @ss.scan(COMPARISON_OPERATOR) then [:comparison, t] + when t = @ss.scan(SINGLE_STRING_LITERAL) then [:string, t] + when t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t] + when t = @ss.scan(NUMBER_LITERAL) then [:number, t] + when t = @ss.scan(IDENTIFIER) then [:id, t] + when t = @ss.scan(DOTDOT) then [:dotdot, t] + else + c = @ss.getch + if s = SPECIALS[c] + [s, c] + else + raise SyntaxError, "Unexpected character #{c}" + end + end + @output << tok + end + + @output << [:end_of_string] + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/locales/en.yml b/bin/gems/liquid-4.0.4/lib/liquid/locales/en.yml new file mode 100644 index 00000000..48b3b1d8 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/locales/en.yml @@ -0,0 +1,26 @@ +--- + errors: + syntax: + tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: %{tag}" + assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]" + capture: "Syntax Error in 'capture' - Valid syntax: capture [var]" + case: "Syntax Error in 'case' - Valid syntax: case [condition]" + case_invalid_when: "Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %}" + case_invalid_else: "Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) " + cycle: "Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]" + for: "Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]" + for_invalid_in: "For loops require an 'in' clause" + for_invalid_attribute: "Invalid attribute in for loop. Valid attributes are limit and offset" + if: "Syntax Error in tag 'if' - Valid syntax: if [expression]" + include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]" + unknown_tag: "Unknown tag '%{tag}'" + invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" + unexpected_else: "%{block_name} tag does not expect 'else' tag" + unexpected_outer_tag: "Unexpected outer '%{tag}' tag" + tag_termination: "Tag '%{token}' was not properly terminated with regexp: %{tag_end}" + variable_termination: "Variable '%{token}' was not properly terminated with regexp: %{tag_end}" + tag_never_closed: "'%{block_name}' tag was never closed" + meta_syntax_error: "Liquid syntax error: #{e.message}" + table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" + argument: + include: "Argument error in tag 'include' - Illegal template name" diff --git a/bin/gems/liquid-4.0.4/lib/liquid/parse_context.rb b/bin/gems/liquid-4.0.4/lib/liquid/parse_context.rb new file mode 100644 index 00000000..abcdaeba --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/parse_context.rb @@ -0,0 +1,38 @@ +module Liquid + class ParseContext + attr_accessor :locale, :line_number, :trim_whitespace, :depth + attr_reader :partial, :warnings, :error_mode + + def initialize(options = {}) + @template_options = options ? options.dup : {} + @locale = @template_options[:locale] ||= I18n.new + @warnings = [] + self.depth = 0 + self.partial = false + end + + def [](option_key) + @options[option_key] + end + + def partial=(value) + @partial = value + @options = value ? partial_options : @template_options + @error_mode = @options[:error_mode] || Template.error_mode + value + end + + def partial_options + @partial_options ||= begin + dont_pass = @template_options[:include_options_blacklist] + if dont_pass == true + { locale: locale } + elsif dont_pass.is_a?(Array) + @template_options.reject { |k, v| dont_pass.include?(k) } + else + @template_options + end + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/parse_tree_visitor.rb b/bin/gems/liquid-4.0.4/lib/liquid/parse_tree_visitor.rb new file mode 100644 index 00000000..74f5563a --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/parse_tree_visitor.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Liquid + class ParseTreeVisitor + def self.for(node, callbacks = Hash.new(proc {})) + if defined?(node.class::ParseTreeVisitor) + node.class::ParseTreeVisitor + else + self + end.new(node, callbacks) + end + + def initialize(node, callbacks) + @node = node + @callbacks = callbacks + end + + def add_callback_for(*classes, &block) + callback = block + callback = ->(node, _) { yield node } if block.arity.abs == 1 + callback = ->(_, _) { yield } if block.arity.zero? + classes.each { |klass| @callbacks[klass] = callback } + self + end + + def visit(context = nil) + children.map do |node| + item, new_context = @callbacks[node.class].call(node, context) + [ + item, + ParseTreeVisitor.for(node, @callbacks).visit(new_context || context) + ] + end + end + + protected + + def children + @node.respond_to?(:nodelist) ? Array(@node.nodelist) : [] + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/parser.rb b/bin/gems/liquid-4.0.4/lib/liquid/parser.rb new file mode 100644 index 00000000..69543434 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/parser.rb @@ -0,0 +1,90 @@ +module Liquid + class Parser + def initialize(input) + l = Lexer.new(input) + @tokens = l.tokenize + @p = 0 # pointer to current location + end + + def jump(point) + @p = point + end + + def consume(type = nil) + token = @tokens[@p] + if type && token[0] != type + raise SyntaxError, "Expected #{type} but found #{@tokens[@p].first}" + end + @p += 1 + token[1] + end + + # Only consumes the token if it matches the type + # Returns the token's contents if it was consumed + # or false otherwise. + def consume?(type) + token = @tokens[@p] + return false unless token && token[0] == type + @p += 1 + token[1] + end + + # Like consume? Except for an :id token of a certain name + def id?(str) + token = @tokens[@p] + return false unless token && token[0] == :id + return false unless token[1] == str + @p += 1 + token[1] + end + + def look(type, ahead = 0) + tok = @tokens[@p + ahead] + return false unless tok + tok[0] == type + end + + def expression + token = @tokens[@p] + if token[0] == :id + variable_signature + elsif [:string, :number].include? token[0] + consume + elsif token.first == :open_round + consume + first = expression + consume(:dotdot) + last = expression + consume(:close_round) + "(#{first}..#{last})" + else + raise SyntaxError, "#{token} is not a valid expression" + end + end + + def argument + str = "" + # might be a keyword argument (identifier: expression) + if look(:id) && look(:colon, 1) + str << consume << consume << ' '.freeze + end + + str << expression + str + end + + def variable_signature + str = consume(:id) + while look(:open_square) + str << consume + str << expression + str << consume(:close_square) + end + if look(:dot) + str << consume + str << variable_signature + end + str + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/parser_switching.rb b/bin/gems/liquid-4.0.4/lib/liquid/parser_switching.rb new file mode 100644 index 00000000..3aa664ab --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/parser_switching.rb @@ -0,0 +1,31 @@ +module Liquid + module ParserSwitching + def parse_with_selected_parser(markup) + case parse_context.error_mode + when :strict then strict_parse_with_error_context(markup) + when :lax then lax_parse(markup) + when :warn + begin + return strict_parse_with_error_context(markup) + rescue SyntaxError => e + parse_context.warnings << e + return lax_parse(markup) + end + end + end + + private + + def strict_parse_with_error_context(markup) + strict_parse(markup) + rescue SyntaxError => e + e.line_number = line_number + e.markup_context = markup_context(markup) + raise e + end + + def markup_context(markup) + "in \"#{markup.strip}\"" + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/profiler.rb b/bin/gems/liquid-4.0.4/lib/liquid/profiler.rb new file mode 100644 index 00000000..dc9db60a --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/profiler.rb @@ -0,0 +1,158 @@ +require 'liquid/profiler/hooks' + +module Liquid + # Profiler enables support for profiling template rendering to help track down performance issues. + # + # To enable profiling, first require 'liquid/profiler'. + # Then, to profile a parse/render cycle, pass the profile: true option to Liquid::Template.parse. + # After Liquid::Template#render is called, the template object makes available an instance of this + # class via the Liquid::Template#profiler method. + # + # template = Liquid::Template.parse(template_content, profile: true) + # output = template.render + # profile = template.profiler + # + # This object contains all profiling information, containing information on what tags were rendered, + # where in the templates these tags live, and how long each tag took to render. + # + # This is a tree structure that is Enumerable all the way down, and keeps track of tags and rendering times + # inside of {% include %} tags. + # + # profile.each do |node| + # # Access to the node itself + # node.code + # + # # Which template and line number of this node. + # # If top level, this will be "". + # node.partial + # node.line_number + # + # # Render time in seconds of this node + # node.render_time + # + # # If the template used {% include %}, this node will also have children. + # node.children.each do |child2| + # # ... + # end + # end + # + # Profiler also exposes the total time of the template's render in Liquid::Profiler#total_render_time. + # + # All render times are in seconds. There is a small performance hit when profiling is enabled. + # + class Profiler + include Enumerable + + class Timing + attr_reader :code, :partial, :line_number, :children + + def initialize(node, partial) + @code = node.respond_to?(:raw) ? node.raw : node + @partial = partial + @line_number = node.respond_to?(:line_number) ? node.line_number : nil + @children = [] + end + + def self.start(node, partial) + new(node, partial).tap(&:start) + end + + def start + @start_time = Time.now + end + + def finish + @end_time = Time.now + end + + def render_time + @end_time - @start_time + end + end + + def self.profile_node_render(node) + if Profiler.current_profile && node.respond_to?(:render) + Profiler.current_profile.start_node(node) + output = yield + Profiler.current_profile.end_node(node) + output + else + yield + end + end + + def self.profile_children(template_name) + if Profiler.current_profile + Profiler.current_profile.push_partial(template_name) + output = yield + Profiler.current_profile.pop_partial + output + else + yield + end + end + + def self.current_profile + Thread.current[:liquid_profiler] + end + + def initialize + @partial_stack = [""] + + @root_timing = Timing.new("", current_partial) + @timing_stack = [@root_timing] + + @render_start_at = Time.now + @render_end_at = @render_start_at + end + + def start + Thread.current[:liquid_profiler] = self + @render_start_at = Time.now + end + + def stop + Thread.current[:liquid_profiler] = nil + @render_end_at = Time.now + end + + def total_render_time + @render_end_at - @render_start_at + end + + def each(&block) + @root_timing.children.each(&block) + end + + def [](idx) + @root_timing.children[idx] + end + + def length + @root_timing.children.length + end + + def start_node(node) + @timing_stack.push(Timing.start(node, current_partial)) + end + + def end_node(_node) + timing = @timing_stack.pop + timing.finish + + @timing_stack.last.children << timing + end + + def current_partial + @partial_stack.last + end + + def push_partial(partial_name) + @partial_stack.push(partial_name) + end + + def pop_partial + @partial_stack.pop + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/profiler/hooks.rb b/bin/gems/liquid-4.0.4/lib/liquid/profiler/hooks.rb new file mode 100644 index 00000000..cb11cd7e --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/profiler/hooks.rb @@ -0,0 +1,23 @@ +module Liquid + class BlockBody + def render_node_with_profiling(node, output, context, skip_output = false) + Profiler.profile_node_render(node) do + render_node_without_profiling(node, output, context, skip_output) + end + end + + alias_method :render_node_without_profiling, :render_node_to_output + alias_method :render_node_to_output, :render_node_with_profiling + end + + class Include < Tag + def render_with_profiling(context) + Profiler.profile_children(context.evaluate(@template_name_expr).to_s) do + render_without_profiling(context) + end + end + + alias_method :render_without_profiling, :render + alias_method :render, :render_with_profiling + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/range_lookup.rb b/bin/gems/liquid-4.0.4/lib/liquid/range_lookup.rb new file mode 100644 index 00000000..93bb420c --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/range_lookup.rb @@ -0,0 +1,37 @@ +module Liquid + class RangeLookup + def self.parse(start_markup, end_markup) + start_obj = Expression.parse(start_markup) + end_obj = Expression.parse(end_markup) + if start_obj.respond_to?(:evaluate) || end_obj.respond_to?(:evaluate) + new(start_obj, end_obj) + else + start_obj.to_i..end_obj.to_i + end + end + + def initialize(start_obj, end_obj) + @start_obj = start_obj + @end_obj = end_obj + end + + def evaluate(context) + start_int = to_integer(context.evaluate(@start_obj)) + end_int = to_integer(context.evaluate(@end_obj)) + start_int..end_int + end + + private + + def to_integer(input) + case input + when Integer + input + when NilClass, String + input.to_i + else + Utils.to_integer(input) + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/resource_limits.rb b/bin/gems/liquid-4.0.4/lib/liquid/resource_limits.rb new file mode 100644 index 00000000..08b359ba --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/resource_limits.rb @@ -0,0 +1,23 @@ +module Liquid + class ResourceLimits + attr_accessor :render_length, :render_score, :assign_score, + :render_length_limit, :render_score_limit, :assign_score_limit + + def initialize(limits) + @render_length_limit = limits[:render_length_limit] + @render_score_limit = limits[:render_score_limit] + @assign_score_limit = limits[:assign_score_limit] + reset + end + + def reached? + (@render_length_limit && @render_length > @render_length_limit) || + (@render_score_limit && @render_score > @render_score_limit) || + (@assign_score_limit && @assign_score > @assign_score_limit) + end + + def reset + @render_length = @render_score = @assign_score = 0 + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/standardfilters.rb b/bin/gems/liquid-4.0.4/lib/liquid/standardfilters.rb new file mode 100644 index 00000000..fffee4de --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/standardfilters.rb @@ -0,0 +1,506 @@ +require 'cgi' +require 'bigdecimal' + +module Liquid + module StandardFilters + HTML_ESCAPE = { + '&'.freeze => '&'.freeze, + '>'.freeze => '>'.freeze, + '<'.freeze => '<'.freeze, + '"'.freeze => '"'.freeze, + "'".freeze => '''.freeze + }.freeze + HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/ + STRIP_HTML_BLOCKS = Regexp.union( + //m, + //m, + //m + ) + STRIP_HTML_TAGS = /<.*?>/m + + # Return the size of an array or of an string + def size(input) + input.respond_to?(:size) ? input.size : 0 + end + + # convert an input string to DOWNCASE + def downcase(input) + input.to_s.downcase + end + + # convert an input string to UPCASE + def upcase(input) + input.to_s.upcase + end + + # capitalize words in the input centence + def capitalize(input) + input.to_s.capitalize + end + + def escape(input) + CGI.escapeHTML(input.to_s) unless input.nil? + end + alias_method :h, :escape + + def escape_once(input) + input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE) + end + + def url_encode(input) + CGI.escape(input.to_s) unless input.nil? + end + + def url_decode(input) + return if input.nil? + + result = CGI.unescape(input.to_s) + raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding? + + result + end + + def slice(input, offset, length = nil) + offset = Utils.to_integer(offset) + length = length ? Utils.to_integer(length) : 1 + + if input.is_a?(Array) + input.slice(offset, length) || [] + else + input.to_s.slice(offset, length) || '' + end + end + + # Truncate a string down to x characters + def truncate(input, length = 50, truncate_string = "...".freeze) + return if input.nil? + input_str = input.to_s + length = Utils.to_integer(length) + truncate_string_str = truncate_string.to_s + l = length - truncate_string_str.length + l = 0 if l < 0 + input_str.length > length ? input_str[0...l] + truncate_string_str : input_str + end + + def truncatewords(input, words = 15, truncate_string = "...".freeze) + return if input.nil? + wordlist = input.to_s.split + words = Utils.to_integer(words) + l = words - 1 + l = 0 if l < 0 + wordlist.length > l ? wordlist[0..l].join(" ".freeze) + truncate_string.to_s : input + end + + # Split input string into an array of substrings separated by given pattern. + # + # Example: + #
{{ post | split '//' | first }}
+ # + def split(input, pattern) + input.to_s.split(pattern.to_s) + end + + def strip(input) + input.to_s.strip + end + + def lstrip(input) + input.to_s.lstrip + end + + def rstrip(input) + input.to_s.rstrip + end + + def strip_html(input) + empty = ''.freeze + result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty) + result.gsub!(STRIP_HTML_TAGS, empty) + result + end + + # Remove all newlines from the string + def strip_newlines(input) + input.to_s.gsub(/\r?\n/, ''.freeze) + end + + # Join elements of the array with certain character between them + def join(input, glue = ' '.freeze) + InputIterator.new(input).join(glue) + end + + # Sort elements of the array + # provide optional property with which to sort an array of hashes or drops + def sort(input, property = nil) + ary = InputIterator.new(input) + + return [] if ary.empty? + + if property.nil? + ary.sort do |a, b| + nil_safe_compare(a, b) + end + elsif ary.all? { |el| el.respond_to?(:[]) } + begin + ary.sort { |a, b| nil_safe_compare(a[property], b[property]) } + rescue TypeError + raise_property_error(property) + end + end + end + + # Sort elements of an array ignoring case if strings + # provide optional property with which to sort an array of hashes or drops + def sort_natural(input, property = nil) + ary = InputIterator.new(input) + + return [] if ary.empty? + + if property.nil? + ary.sort do |a, b| + nil_safe_casecmp(a, b) + end + elsif ary.all? { |el| el.respond_to?(:[]) } + begin + ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) } + rescue TypeError + raise_property_error(property) + end + end + end + + # Filter the elements of an array to those with a certain property value. + # By default the target is any truthy value. + def where(input, property, target_value = nil) + ary = InputIterator.new(input) + + if ary.empty? + [] + elsif ary.first.respond_to?(:[]) && target_value.nil? + begin + ary.select { |item| item[property] } + rescue TypeError + raise_property_error(property) + end + elsif ary.first.respond_to?(:[]) + begin + ary.select { |item| item[property] == target_value } + rescue TypeError + raise_property_error(property) + end + end + end + + # Remove duplicate elements from an array + # provide optional property with which to determine uniqueness + def uniq(input, property = nil) + ary = InputIterator.new(input) + + if property.nil? + ary.uniq + elsif ary.empty? # The next two cases assume a non-empty array. + [] + elsif ary.first.respond_to?(:[]) + begin + ary.uniq { |a| a[property] } + rescue TypeError + raise_property_error(property) + end + end + end + + # Reverse the elements of an array + def reverse(input) + ary = InputIterator.new(input) + ary.reverse + end + + # map/collect on a given property + def map(input, property) + InputIterator.new(input).map do |e| + e = e.call if e.is_a?(Proc) + + if property == "to_liquid".freeze + e + elsif e.respond_to?(:[]) + r = e[property] + r.is_a?(Proc) ? r.call : r + end + end + rescue TypeError + raise_property_error(property) + end + + # Remove nils within an array + # provide optional property with which to check for nil + def compact(input, property = nil) + ary = InputIterator.new(input) + + if property.nil? + ary.compact + elsif ary.empty? # The next two cases assume a non-empty array. + [] + elsif ary.first.respond_to?(:[]) + begin + ary.reject { |a| a[property].nil? } + rescue TypeError + raise_property_error(property) + end + end + end + + # Replace occurrences of a string with another + def replace(input, string, replacement = ''.freeze) + input.to_s.gsub(string.to_s, replacement.to_s) + end + + # Replace the first occurrences of a string with another + def replace_first(input, string, replacement = ''.freeze) + input.to_s.sub(string.to_s, replacement.to_s) + end + + # remove a substring + def remove(input, string) + input.to_s.gsub(string.to_s, ''.freeze) + end + + # remove the first occurrences of a substring + def remove_first(input, string) + input.to_s.sub(string.to_s, ''.freeze) + end + + # add one string to another + def append(input, string) + input.to_s + string.to_s + end + + def concat(input, array) + unless array.respond_to?(:to_ary) + raise ArgumentError.new("concat filter requires an array argument") + end + InputIterator.new(input).concat(array) + end + + # prepend a string to another + def prepend(input, string) + string.to_s + input.to_s + end + + # Add
tags in front of all newlines in input string + def newline_to_br(input) + input.to_s.gsub(/\n/, "
\n".freeze) + end + + # Reformat a date using Ruby's core Time#strftime( string ) -> string + # + # %a - The abbreviated weekday name (``Sun'') + # %A - The full weekday name (``Sunday'') + # %b - The abbreviated month name (``Jan'') + # %B - The full month name (``January'') + # %c - The preferred local date and time representation + # %d - Day of the month (01..31) + # %H - Hour of the day, 24-hour clock (00..23) + # %I - Hour of the day, 12-hour clock (01..12) + # %j - Day of the year (001..366) + # %m - Month of the year (01..12) + # %M - Minute of the hour (00..59) + # %p - Meridian indicator (``AM'' or ``PM'') + # %s - Number of seconds since 1970-01-01 00:00:00 UTC. + # %S - Second of the minute (00..60) + # %U - Week number of the current year, + # starting with the first Sunday as the first + # day of the first week (00..53) + # %W - Week number of the current year, + # starting with the first Monday as the first + # day of the first week (00..53) + # %w - Day of the week (Sunday is 0, 0..6) + # %x - Preferred representation for the date alone, no time + # %X - Preferred representation for the time alone, no date + # %y - Year without a century (00..99) + # %Y - Year with century + # %Z - Time zone name + # %% - Literal ``%'' character + # + # See also: http://www.ruby-doc.org/core/Time.html#method-i-strftime + def date(input, format) + return input if format.to_s.empty? + + return input unless date = Utils.to_date(input) + + date.strftime(format.to_s) + end + + # Get the first element of the passed in array + # + # Example: + # {{ product.images | first | to_img }} + # + def first(array) + array.first if array.respond_to?(:first) + end + + # Get the last element of the passed in array + # + # Example: + # {{ product.images | last | to_img }} + # + def last(array) + array.last if array.respond_to?(:last) + end + + # absolute value + def abs(input) + result = Utils.to_number(input).abs + result.is_a?(BigDecimal) ? result.to_f : result + end + + # addition + def plus(input, operand) + apply_operation(input, operand, :+) + end + + # subtraction + def minus(input, operand) + apply_operation(input, operand, :-) + end + + # multiplication + def times(input, operand) + apply_operation(input, operand, :*) + end + + # division + def divided_by(input, operand) + apply_operation(input, operand, :/) + rescue ::ZeroDivisionError => e + raise Liquid::ZeroDivisionError, e.message + end + + def modulo(input, operand) + apply_operation(input, operand, :%) + rescue ::ZeroDivisionError => e + raise Liquid::ZeroDivisionError, e.message + end + + def round(input, n = 0) + result = Utils.to_number(input).round(Utils.to_number(n)) + result = result.to_f if result.is_a?(BigDecimal) + result = result.to_i if n == 0 + result + rescue ::FloatDomainError => e + raise Liquid::FloatDomainError, e.message + end + + def ceil(input) + Utils.to_number(input).ceil.to_i + rescue ::FloatDomainError => e + raise Liquid::FloatDomainError, e.message + end + + def floor(input) + Utils.to_number(input).floor.to_i + rescue ::FloatDomainError => e + raise Liquid::FloatDomainError, e.message + end + + def at_least(input, n) + min_value = Utils.to_number(n) + + result = Utils.to_number(input) + result = min_value if min_value > result + result.is_a?(BigDecimal) ? result.to_f : result + end + + def at_most(input, n) + max_value = Utils.to_number(n) + + result = Utils.to_number(input) + result = max_value if max_value < result + result.is_a?(BigDecimal) ? result.to_f : result + end + + def default(input, default_value = ''.freeze) + if !input || input.respond_to?(:empty?) && input.empty? + default_value + else + input + end + end + + private + + def raise_property_error(property) + raise Liquid::ArgumentError.new("cannot select the property '#{property}'") + end + + def apply_operation(input, operand, operation) + result = Utils.to_number(input).send(operation, Utils.to_number(operand)) + result.is_a?(BigDecimal) ? result.to_f : result + end + + def nil_safe_compare(a, b) + if !a.nil? && !b.nil? + a <=> b + else + a.nil? ? 1 : -1 + end + end + + def nil_safe_casecmp(a, b) + if !a.nil? && !b.nil? + a.to_s.casecmp(b.to_s) + else + a.nil? ? 1 : -1 + end + end + + class InputIterator + include Enumerable + + def initialize(input) + @input = if input.is_a?(Array) + input.flatten + elsif input.is_a?(Hash) + [input] + elsif input.is_a?(Enumerable) + input + else + Array(input) + end + end + + def join(glue) + to_a.join(glue.to_s) + end + + def concat(args) + to_a.concat(args) + end + + def reverse + reverse_each.to_a + end + + def uniq(&block) + to_a.uniq(&block) + end + + def compact + to_a.compact + end + + def empty? + @input.each { return false } + true + end + + def each + @input.each do |e| + yield(e.respond_to?(:to_liquid) ? e.to_liquid : e) + end + end + end + end + + Template.register_filter(StandardFilters) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/strainer.rb b/bin/gems/liquid-4.0.4/lib/liquid/strainer.rb new file mode 100644 index 00000000..76d56d23 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/strainer.rb @@ -0,0 +1,66 @@ +require 'set' + +module Liquid + # Strainer is the parent class for the filters system. + # New filters are mixed into the strainer class which is then instantiated for each liquid template render run. + # + # The Strainer only allows method calls defined in filters given to it via Strainer.global_filter, + # Context#add_filters or Template.register_filter + class Strainer #:nodoc: + @@global_strainer = Class.new(Strainer) do + @filter_methods = Set.new + end + @@strainer_class_cache = Hash.new do |hash, filters| + hash[filters] = Class.new(@@global_strainer) do + @filter_methods = @@global_strainer.filter_methods.dup + filters.each { |f| add_filter(f) } + end + end + + def initialize(context) + @context = context + end + + class << self + attr_reader :filter_methods + end + + def self.add_filter(filter) + raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module) + unless self.include?(filter) + invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) } + if invokable_non_public_methods.any? + raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}" + else + send(:include, filter) + @filter_methods.merge(filter.public_instance_methods.map(&:to_s)) + end + end + end + + def self.global_filter(filter) + @@strainer_class_cache.clear + @@global_strainer.add_filter(filter) + end + + def self.invokable?(method) + @filter_methods.include?(method.to_s) + end + + def self.create(context, filters = []) + @@strainer_class_cache[filters].new(context) + end + + def invoke(method, *args) + if self.class.invokable?(method) + send(method, *args) + elsif @context && @context.strict_filters + raise Liquid::UndefinedFilter, "undefined filter #{method}" + else + args.first + end + rescue ::ArgumentError => e + raise Liquid::ArgumentError, e.message, e.backtrace + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tablerowloop_drop.rb b/bin/gems/liquid-4.0.4/lib/liquid/tablerowloop_drop.rb new file mode 100644 index 00000000..cda4a1ed --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tablerowloop_drop.rb @@ -0,0 +1,62 @@ +module Liquid + class TablerowloopDrop < Drop + def initialize(length, cols) + @length = length + @row = 1 + @col = 1 + @cols = cols + @index = 0 + end + + attr_reader :length, :col, :row + + def index + @index + 1 + end + + def index0 + @index + end + + def col0 + @col - 1 + end + + def rindex + @length - @index + end + + def rindex0 + @length - @index - 1 + end + + def first + @index == 0 + end + + def last + @index == @length - 1 + end + + def col_first + @col == 1 + end + + def col_last + @col == @cols + end + + protected + + def increment! + @index += 1 + + if @col == @cols + @col = 1 + @row += 1 + else + @col += 1 + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tag.rb b/bin/gems/liquid-4.0.4/lib/liquid/tag.rb new file mode 100644 index 00000000..06970c18 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tag.rb @@ -0,0 +1,43 @@ +module Liquid + class Tag + attr_reader :nodelist, :tag_name, :line_number, :parse_context + alias_method :options, :parse_context + include ParserSwitching + + class << self + def parse(tag_name, markup, tokenizer, options) + tag = new(tag_name, markup, options) + tag.parse(tokenizer) + tag + end + + private :new + end + + def initialize(tag_name, markup, parse_context) + @tag_name = tag_name + @markup = markup + @parse_context = parse_context + @line_number = parse_context.line_number + end + + def parse(_tokens) + end + + def raw + "#{@tag_name} #{@markup}" + end + + def name + self.class.name.downcase + end + + def render(_context) + ''.freeze + end + + def blank? + false + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/assign.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/assign.rb new file mode 100644 index 00000000..c8d0574a --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/assign.rb @@ -0,0 +1,59 @@ +module Liquid + # Assign sets a variable in your template. + # + # {% assign foo = 'monkey' %} + # + # You can then use the variable later in the page. + # + # {{ foo }} + # + class Assign < Tag + Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om + + attr_reader :to, :from + + def initialize(tag_name, markup, options) + super + if markup =~ Syntax + @to = $1 + @from = Variable.new($2, options) + else + raise SyntaxError.new options[:locale].t("errors.syntax.assign".freeze) + end + end + + def render(context) + val = @from.render(context) + context.scopes.last[@to] = val + context.resource_limits.assign_score += assign_score_of(val) + ''.freeze + end + + def blank? + true + end + + private + + def assign_score_of(val) + if val.instance_of?(String) + val.length + elsif val.instance_of?(Array) || val.instance_of?(Hash) + sum = 1 + # Uses #each to avoid extra allocations. + val.each { |child| sum += assign_score_of(child) } + sum + else + 1 + end + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + [@node.from] + end + end + end + + Template.register_tag('assign'.freeze, Assign) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/break.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/break.rb new file mode 100644 index 00000000..6fe0969b --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/break.rb @@ -0,0 +1,18 @@ +module Liquid + # Break tag to be used to break out of a for loop. + # + # == Basic Usage: + # {% for item in collection %} + # {% if item.condition %} + # {% break %} + # {% endif %} + # {% endfor %} + # + class Break < Tag + def interrupt + BreakInterrupt.new + end + end + + Template.register_tag('break'.freeze, Break) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/capture.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/capture.rb new file mode 100644 index 00000000..86743567 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/capture.rb @@ -0,0 +1,38 @@ +module Liquid + # Capture stores the result of a block into a variable without rendering it inplace. + # + # {% capture heading %} + # Monkeys! + # {% endcapture %} + # ... + #

{{ heading }}

+ # + # Capture is useful for saving content for use later in your template, such as + # in a sidebar or footer. + # + class Capture < Block + Syntax = /(#{VariableSignature}+)/o + + def initialize(tag_name, markup, options) + super + if markup =~ Syntax + @to = $1 + else + raise SyntaxError.new(options[:locale].t("errors.syntax.capture")) + end + end + + def render(context) + output = super + context.scopes.last[@to] = output + context.resource_limits.assign_score += output.length + ''.freeze + end + + def blank? + true + end + end + + Template.register_tag('capture'.freeze, Capture) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/case.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/case.rb new file mode 100644 index 00000000..5036b279 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/case.rb @@ -0,0 +1,94 @@ +module Liquid + class Case < Block + Syntax = /(#{QuotedFragment})/o + WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om + + attr_reader :blocks, :left + + def initialize(tag_name, markup, options) + super + @blocks = [] + + if markup =~ Syntax + @left = Expression.parse($1) + else + raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze)) + end + end + + def parse(tokens) + body = BlockBody.new + while parse_body(body, tokens) + body = @blocks.last.attachment + end + end + + def nodelist + @blocks.map(&:attachment) + end + + def unknown_tag(tag, markup, tokens) + case tag + when 'when'.freeze + record_when_condition(markup) + when 'else'.freeze + record_else_condition(markup) + else + super + end + end + + def render(context) + context.stack do + execute_else_block = true + + output = '' + @blocks.each do |block| + if block.else? + return block.attachment.render(context) if execute_else_block + elsif block.evaluate(context) + execute_else_block = false + output << block.attachment.render(context) + end + end + output + end + end + + private + + def record_when_condition(markup) + body = BlockBody.new + + while markup + unless markup =~ WhenSyntax + raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze)) + end + + markup = $2 + + block = Condition.new(@left, '=='.freeze, Expression.parse($1)) + block.attach(body) + @blocks << block + end + end + + def record_else_condition(markup) + unless markup.strip.empty? + raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_else".freeze)) + end + + block = ElseCondition.new + block.attach(BlockBody.new) + @blocks << block + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + [@node.left] + @node.blocks + end + end + end + + Template.register_tag('case'.freeze, Case) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/comment.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/comment.rb new file mode 100644 index 00000000..c57c9cd6 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/comment.rb @@ -0,0 +1,16 @@ +module Liquid + class Comment < Block + def render(_context) + ''.freeze + end + + def unknown_tag(_tag, _markup, _tokens) + end + + def blank? + true + end + end + + Template.register_tag('comment'.freeze, Comment) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/continue.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/continue.rb new file mode 100644 index 00000000..9c81ec2c --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/continue.rb @@ -0,0 +1,18 @@ +module Liquid + # Continue tag to be used to break out of a for loop. + # + # == Basic Usage: + # {% for item in collection %} + # {% if item.condition %} + # {% continue %} + # {% endif %} + # {% endfor %} + # + class Continue < Tag + def interrupt + ContinueInterrupt.new + end + end + + Template.register_tag('continue'.freeze, Continue) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/cycle.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/cycle.rb new file mode 100644 index 00000000..17aa860d --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/cycle.rb @@ -0,0 +1,65 @@ +module Liquid + # Cycle is usually used within a loop to alternate between values, like colors or DOM classes. + # + # {% for item in items %} + #
{{ item }}
+ # {% end %} + # + #
Item one
+ #
Item two
+ #
Item three
+ #
Item four
+ #
Item five
+ # + class Cycle < Tag + SimpleSyntax = /\A#{QuotedFragment}+/o + NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om + + attr_reader :variables + + def initialize(tag_name, markup, options) + super + case markup + when NamedSyntax + @variables = variables_from_string($2) + @name = Expression.parse($1) + when SimpleSyntax + @variables = variables_from_string(markup) + @name = @variables.to_s + else + raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze)) + end + end + + def render(context) + context.registers[:cycle] ||= {} + + context.stack do + key = context.evaluate(@name) + iteration = context.registers[:cycle][key].to_i + result = context.evaluate(@variables[iteration]) + iteration += 1 + iteration = 0 if iteration >= @variables.size + context.registers[:cycle][key] = iteration + result + end + end + + private + + def variables_from_string(markup) + markup.split(',').collect do |var| + var =~ /\s*(#{QuotedFragment})\s*/o + $1 ? Expression.parse($1) : nil + end.compact + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + Array(@node.variables) + end + end + end + + Template.register_tag('cycle', Cycle) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/decrement.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/decrement.rb new file mode 100644 index 00000000..b5cdaaa6 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/decrement.rb @@ -0,0 +1,35 @@ +module Liquid + # decrement is used in a place where one needs to insert a counter + # into a template, and needs the counter to survive across + # multiple instantiations of the template. + # NOTE: decrement is a pre-decrement, --i, + # while increment is post: i++. + # + # (To achieve the survival, the application must keep the context) + # + # if the variable does not exist, it is created with value 0. + + # Hello: {% decrement variable %} + # + # gives you: + # + # Hello: -1 + # Hello: -2 + # Hello: -3 + # + class Decrement < Tag + def initialize(tag_name, markup, options) + super + @variable = markup.strip + end + + def render(context) + value = context.environments.first[@variable] ||= 0 + value -= 1 + context.environments.first[@variable] = value + value.to_s + end + end + + Template.register_tag('decrement'.freeze, Decrement) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/for.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/for.rb new file mode 100644 index 00000000..b69aa78c --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/for.rb @@ -0,0 +1,203 @@ +module Liquid + # "For" iterates over an array or collection. + # Several useful variables are available to you within the loop. + # + # == Basic usage: + # {% for item in collection %} + # {{ forloop.index }}: {{ item.name }} + # {% endfor %} + # + # == Advanced usage: + # {% for item in collection %} + #
+ # Item {{ forloop.index }}: {{ item.name }} + #
+ # {% else %} + # There is nothing in the collection. + # {% endfor %} + # + # You can also define a limit and offset much like SQL. Remember + # that offset starts at 0 for the first item. + # + # {% for item in collection limit:5 offset:10 %} + # {{ item.name }} + # {% end %} + # + # To reverse the for loop simply use {% for item in collection reversed %} (note that the flag's spelling is different to the filter `reverse`) + # + # == Available variables: + # + # forloop.name:: 'item-collection' + # forloop.length:: Length of the loop + # forloop.index:: The current item's position in the collection; + # forloop.index starts at 1. + # This is helpful for non-programmers who start believe + # the first item in an array is 1, not 0. + # forloop.index0:: The current item's position in the collection + # where the first item is 0 + # forloop.rindex:: Number of items remaining in the loop + # (length - index) where 1 is the last item. + # forloop.rindex0:: Number of items remaining in the loop + # where 0 is the last item. + # forloop.first:: Returns true if the item is the first item. + # forloop.last:: Returns true if the item is the last item. + # forloop.parentloop:: Provides access to the parent loop, if present. + # + class For < Block + Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o + + attr_reader :collection_name, :variable_name, :limit, :from + + def initialize(tag_name, markup, options) + super + @from = @limit = nil + parse_with_selected_parser(markup) + @for_block = BlockBody.new + @else_block = nil + end + + def parse(tokens) + return unless parse_body(@for_block, tokens) + parse_body(@else_block, tokens) + end + + def nodelist + @else_block ? [@for_block, @else_block] : [@for_block] + end + + def unknown_tag(tag, markup, tokens) + return super unless tag == 'else'.freeze + @else_block = BlockBody.new + end + + def render(context) + segment = collection_segment(context) + + if segment.empty? + render_else(context) + else + render_segment(context, segment) + end + end + + protected + + def lax_parse(markup) + if markup =~ Syntax + @variable_name = $1 + collection_name = $2 + @reversed = !!$3 + @name = "#{@variable_name}-#{collection_name}" + @collection_name = Expression.parse(collection_name) + markup.scan(TagAttributes) do |key, value| + set_attribute(key, value) + end + else + raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze)) + end + end + + def strict_parse(markup) + p = Parser.new(markup) + @variable_name = p.consume(:id) + raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze) + collection_name = p.expression + @name = "#{@variable_name}-#{collection_name}" + @collection_name = Expression.parse(collection_name) + @reversed = p.id?('reversed'.freeze) + + while p.look(:id) && p.look(:colon, 1) + unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze) + raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze)) + end + p.consume + set_attribute(attribute, p.expression) + end + p.consume(:end_of_string) + end + + private + + def collection_segment(context) + offsets = context.registers[:for] ||= {} + + from = if @from == :continue + offsets[@name].to_i + else + context.evaluate(@from).to_i + end + + collection = context.evaluate(@collection_name) + collection = collection.to_a if collection.is_a?(Range) + + limit = context.evaluate(@limit) + to = limit ? limit.to_i + from : nil + + segment = Utils.slice_collection(collection, from, to) + segment.reverse! if @reversed + + offsets[@name] = from + segment.length + + segment + end + + def render_segment(context, segment) + for_stack = context.registers[:for_stack] ||= [] + length = segment.length + + result = '' + + context.stack do + loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1]) + + for_stack.push(loop_vars) + + begin + context['forloop'.freeze] = loop_vars + + segment.each do |item| + context[@variable_name] = item + result << @for_block.render(context) + loop_vars.send(:increment!) + + # Handle any interrupts if they exist. + if context.interrupt? + interrupt = context.pop_interrupt + break if interrupt.is_a? BreakInterrupt + next if interrupt.is_a? ContinueInterrupt + end + end + ensure + for_stack.pop + end + end + + result + end + + def set_attribute(key, expr) + case key + when 'offset'.freeze + @from = if expr == 'continue'.freeze + :continue + else + Expression.parse(expr) + end + when 'limit'.freeze + @limit = Expression.parse(expr) + end + end + + def render_else(context) + @else_block ? @else_block.render(context) : ''.freeze + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + (super + [@node.limit, @node.from, @node.collection_name]).compact + end + end + end + + Template.register_tag('for'.freeze, For) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/if.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/if.rb new file mode 100644 index 00000000..02da42b7 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/if.rb @@ -0,0 +1,122 @@ +module Liquid + # If is the conditional block + # + # {% if user.admin %} + # Admin user! + # {% else %} + # Not admin user + # {% endif %} + # + # There are {% if count < 5 %} less {% else %} more {% endif %} items than you need. + # + class If < Block + Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o + ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o + BOOLEAN_OPERATORS = %w(and or).freeze + + attr_reader :blocks + + def initialize(tag_name, markup, options) + super + @blocks = [] + push_block('if'.freeze, markup) + end + + def nodelist + @blocks.map(&:attachment) + end + + def parse(tokens) + while parse_body(@blocks.last.attachment, tokens) + end + end + + def unknown_tag(tag, markup, tokens) + if ['elsif'.freeze, 'else'.freeze].include?(tag) + push_block(tag, markup) + else + super + end + end + + def render(context) + context.stack do + @blocks.each do |block| + if block.evaluate(context) + return block.attachment.render(context) + end + end + ''.freeze + end + end + + private + + def push_block(tag, markup) + block = if tag == 'else'.freeze + ElseCondition.new + else + parse_with_selected_parser(markup) + end + + @blocks.push(block) + block.attach(BlockBody.new) + end + + def lax_parse(markup) + expressions = markup.scan(ExpressionsAndOperators) + raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax + + condition = Condition.new(Expression.parse($1), $2, Expression.parse($3)) + + until expressions.empty? + operator = expressions.pop.to_s.strip + + raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax + + new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3)) + raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator) + new_condition.send(operator, condition) + condition = new_condition + end + + condition + end + + def strict_parse(markup) + p = Parser.new(markup) + condition = parse_binary_comparisons(p) + p.consume(:end_of_string) + condition + end + + def parse_binary_comparisons(p) + condition = parse_comparison(p) + first_condition = condition + while op = (p.id?('and'.freeze) || p.id?('or'.freeze)) + child_condition = parse_comparison(p) + condition.send(op, child_condition) + condition = child_condition + end + first_condition + end + + def parse_comparison(p) + a = Expression.parse(p.expression) + if op = p.consume?(:comparison) + b = Expression.parse(p.expression) + Condition.new(a, op, b) + else + Condition.new(a) + end + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + @node.blocks + end + end + end + + Template.register_tag('if'.freeze, If) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/ifchanged.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/ifchanged.rb new file mode 100644 index 00000000..d70cbe1f --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/ifchanged.rb @@ -0,0 +1,18 @@ +module Liquid + class Ifchanged < Block + def render(context) + context.stack do + output = super + + if output != context.registers[:ifchanged] + context.registers[:ifchanged] = output + output + else + ''.freeze + end + end + end + end + + Template.register_tag('ifchanged'.freeze, Ifchanged) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/include.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/include.rb new file mode 100644 index 00000000..c9f2a288 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/include.rb @@ -0,0 +1,124 @@ +module Liquid + # Include allows templates to relate with other templates + # + # Simply include another template: + # + # {% include 'product' %} + # + # Include a template with a local variable: + # + # {% include 'product' with products[0] %} + # + # Include a template for a collection: + # + # {% include 'product' for products %} + # + class Include < Tag + Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o + + attr_reader :template_name_expr, :variable_name_expr, :attributes + + def initialize(tag_name, markup, options) + super + + if markup =~ Syntax + + template_name = $1 + variable_name = $3 + + @variable_name_expr = variable_name ? Expression.parse(variable_name) : nil + @template_name_expr = Expression.parse(template_name) + @attributes = {} + + markup.scan(TagAttributes) do |key, value| + @attributes[key] = Expression.parse(value) + end + + else + raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze)) + end + end + + def parse(_tokens) + end + + def render(context) + template_name = context.evaluate(@template_name_expr) + raise ArgumentError.new(options[:locale].t("errors.argument.include")) unless template_name + + partial = load_cached_partial(template_name, context) + context_variable_name = template_name.split('/'.freeze).last + + variable = if @variable_name_expr + context.evaluate(@variable_name_expr) + else + context.find_variable(template_name, raise_on_not_found: false) + end + + old_template_name = context.template_name + old_partial = context.partial + begin + context.template_name = template_name + context.partial = true + context.stack do + @attributes.each do |key, value| + context[key] = context.evaluate(value) + end + + if variable.is_a?(Array) + variable.collect do |var| + context[context_variable_name] = var + partial.render(context) + end + else + context[context_variable_name] = variable + partial.render(context) + end + end + ensure + context.template_name = old_template_name + context.partial = old_partial + end + end + + private + + alias_method :parse_context, :options + private :parse_context + + def load_cached_partial(template_name, context) + cached_partials = context.registers[:cached_partials] || {} + + if cached = cached_partials[template_name] + return cached + end + source = read_template_from_file_system(context) + begin + parse_context.partial = true + partial = Liquid::Template.parse(source, parse_context) + ensure + parse_context.partial = false + end + cached_partials[template_name] = partial + context.registers[:cached_partials] = cached_partials + partial + end + + def read_template_from_file_system(context) + file_system = context.registers[:file_system] || Liquid::Template.file_system + + file_system.read_template_file(context.evaluate(@template_name_expr)) + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + [ + @node.template_name_expr, + @node.variable_name_expr + ] + @node.attributes.values + end + end + end + + Template.register_tag('include'.freeze, Include) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/increment.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/increment.rb new file mode 100644 index 00000000..baa0cbb6 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/increment.rb @@ -0,0 +1,31 @@ +module Liquid + # increment is used in a place where one needs to insert a counter + # into a template, and needs the counter to survive across + # multiple instantiations of the template. + # (To achieve the survival, the application must keep the context) + # + # if the variable does not exist, it is created with value 0. + # + # Hello: {% increment variable %} + # + # gives you: + # + # Hello: 0 + # Hello: 1 + # Hello: 2 + # + class Increment < Tag + def initialize(tag_name, markup, options) + super + @variable = markup.strip + end + + def render(context) + value = context.environments.first[@variable] ||= 0 + context.environments.first[@variable] = value + 1 + value.to_s + end + end + + Template.register_tag('increment'.freeze, Increment) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/raw.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/raw.rb new file mode 100644 index 00000000..6b461bdb --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/raw.rb @@ -0,0 +1,47 @@ +module Liquid + class Raw < Block + Syntax = /\A\s*\z/ + FullTokenPossiblyInvalid = /\A(.*)#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}\z/om + + def initialize(tag_name, markup, parse_context) + super + + ensure_valid_markup(tag_name, markup, parse_context) + end + + def parse(tokens) + @body = '' + while token = tokens.shift + if token =~ FullTokenPossiblyInvalid + @body << $1 if $1 != "".freeze + return if block_delimiter == $2 + end + @body << token unless token.empty? + end + + raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_never_closed".freeze, block_name: block_name)) + end + + def render(_context) + @body + end + + def nodelist + [@body] + end + + def blank? + @body.empty? + end + + protected + + def ensure_valid_markup(tag_name, markup, parse_context) + unless markup =~ Syntax + raise SyntaxError.new(parse_context.locale.t("errors.syntax.tag_unexpected_args".freeze, tag: tag_name)) + end + end + end + + Template.register_tag('raw'.freeze, Raw) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/table_row.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/table_row.rb new file mode 100644 index 00000000..7f391cf0 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/table_row.rb @@ -0,0 +1,62 @@ +module Liquid + class TableRow < Block + Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o + + attr_reader :variable_name, :collection_name, :attributes + + def initialize(tag_name, markup, options) + super + if markup =~ Syntax + @variable_name = $1 + @collection_name = Expression.parse($2) + @attributes = {} + markup.scan(TagAttributes) do |key, value| + @attributes[key] = Expression.parse(value) + end + else + raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze)) + end + end + + def render(context) + collection = context.evaluate(@collection_name) or return ''.freeze + + from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0 + to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil + + collection = Utils.slice_collection(collection, from, to) + + length = collection.length + + cols = context.evaluate(@attributes['cols'.freeze]).to_i + + result = "\n" + context.stack do + tablerowloop = Liquid::TablerowloopDrop.new(length, cols) + context['tablerowloop'.freeze] = tablerowloop + + collection.each do |item| + context[@variable_name] = item + + result << "" << super << '' + + if tablerowloop.col_last && !tablerowloop.last + result << "\n" + end + + tablerowloop.send(:increment!) + end + end + result << "\n" + result + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + super + @node.attributes.values + [@node.collection_name] + end + end + end + + Template.register_tag('tablerow'.freeze, TableRow) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tags/unless.rb b/bin/gems/liquid-4.0.4/lib/liquid/tags/unless.rb new file mode 100644 index 00000000..1d4280db --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tags/unless.rb @@ -0,0 +1,30 @@ +require_relative 'if' + +module Liquid + # Unless is a conditional just like 'if' but works on the inverse logic. + # + # {% unless x < 0 %} x is greater than zero {% endunless %} + # + class Unless < If + def render(context) + context.stack do + # First condition is interpreted backwards ( if not ) + first_block = @blocks.first + unless first_block.evaluate(context) + return first_block.attachment.render(context) + end + + # After the first condition unless works just like if + @blocks[1..-1].each do |block| + if block.evaluate(context) + return block.attachment.render(context) + end + end + + ''.freeze + end + end + end + + Template.register_tag('unless'.freeze, Unless) +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/template.rb b/bin/gems/liquid-4.0.4/lib/liquid/template.rb new file mode 100644 index 00000000..ba429ec0 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/template.rb @@ -0,0 +1,252 @@ +module Liquid + # Templates are central to liquid. + # Interpretating templates is a two step process. First you compile the + # source code you got. During compile time some extensive error checking is performed. + # your code should expect to get some SyntaxErrors. + # + # After you have a compiled template you can then render it. + # You can use a compiled template over and over again and keep it cached. + # + # Example: + # + # template = Liquid::Template.parse(source) + # template.render('user_name' => 'bob') + # + class Template + attr_accessor :root + attr_reader :resource_limits, :warnings + + @@file_system = BlankFileSystem.new + + class TagRegistry + include Enumerable + + def initialize + @tags = {} + @cache = {} + end + + def [](tag_name) + return nil unless @tags.key?(tag_name) + return @cache[tag_name] if Liquid.cache_classes + + lookup_class(@tags[tag_name]).tap { |o| @cache[tag_name] = o } + end + + def []=(tag_name, klass) + @tags[tag_name] = klass.name + @cache[tag_name] = klass + end + + def delete(tag_name) + @tags.delete(tag_name) + @cache.delete(tag_name) + end + + def each(&block) + @tags.each(&block) + end + + private + + def lookup_class(name) + name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) } + end + end + + attr_reader :profiler + + class << self + # Sets how strict the parser should be. + # :lax acts like liquid 2.5 and silently ignores malformed tags in most cases. + # :warn is the default and will give deprecation warnings when invalid syntax is used. + # :strict will enforce correct syntax. + attr_writer :error_mode + + # Deprecated. No longer used. Removed in version 5 + attr_writer :taint_mode + + attr_accessor :default_exception_renderer + Template.default_exception_renderer = lambda do |exception| + exception + end + + def file_system + @@file_system + end + + def file_system=(obj) + @@file_system = obj + end + + def register_tag(name, klass) + tags[name.to_s] = klass + end + + def tags + @tags ||= TagRegistry.new + end + + def error_mode + @error_mode ||= :lax + end + + # Deprecated. Removed in version 5 + def taint_mode + @taint_mode ||= :lax + end + + # Pass a module with filter methods which should be available + # to all liquid views. Good for registering the standard library + def register_filter(mod) + Strainer.global_filter(mod) + end + + def default_resource_limits + @default_resource_limits ||= {} + end + + # creates a new Template object from liquid source code + # To enable profiling, pass in profile: true as an option. + # See Liquid::Profiler for more information + def parse(source, options = {}) + template = Template.new + template.parse(source, options) + end + end + + def initialize + @rethrow_errors = false + @resource_limits = ResourceLimits.new(self.class.default_resource_limits) + end + + # Parse source code. + # Returns self for easy chaining + def parse(source, options = {}) + @options = options + @profiling = options[:profile] + @line_numbers = options[:line_numbers] || @profiling + parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options) + @root = Document.parse(tokenize(source), parse_context) + @warnings = parse_context.warnings + self + end + + def registers + @registers ||= {} + end + + def assigns + @assigns ||= {} + end + + def instance_assigns + @instance_assigns ||= {} + end + + def errors + @errors ||= [] + end + + # Render takes a hash with local variables. + # + # if you use the same filters over and over again consider registering them globally + # with Template.register_filter + # + # if profiling was enabled in Template#parse then the resulting profiling information + # will be available via Template#profiler + # + # Following options can be passed: + # + # * filters : array with local filters + # * registers : hash with register variables. Those can be accessed from + # filters and tags and might be useful to integrate liquid more with its host application + # + def render(*args) + return ''.freeze if @root.nil? + + context = case args.first + when Liquid::Context + c = args.shift + + if @rethrow_errors + c.exception_renderer = ->(e) { raise } + end + + c + when Liquid::Drop + drop = args.shift + drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits) + when Hash + Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits) + when nil + Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits) + else + raise ArgumentError, "Expected Hash or Liquid::Context as parameter" + end + + case args.last + when Hash + options = args.pop + + registers.merge!(options[:registers]) if options[:registers].is_a?(Hash) + + apply_options_to_context(context, options) + when Module, Array + context.add_filters(args.pop) + end + + # Retrying a render resets resource usage + context.resource_limits.reset + + begin + # render the nodelist. + # for performance reasons we get an array back here. join will make a string out of it. + result = with_profiling(context) do + @root.render(context) + end + result.respond_to?(:join) ? result.join : result + rescue Liquid::MemoryError => e + context.handle_error(e) + ensure + @errors = context.errors + end + end + + def render!(*args) + @rethrow_errors = true + render(*args) + end + + private + + def tokenize(source) + Tokenizer.new(source, @line_numbers) + end + + def with_profiling(context) + if @profiling && !context.partial + raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler) + + @profiler = Profiler.new + @profiler.start + + begin + yield + ensure + @profiler.stop + end + else + yield + end + end + + def apply_options_to_context(context, options) + context.add_filters(options[:filters]) if options[:filters] + context.global_filter = options[:global_filter] if options[:global_filter] + context.exception_renderer = options[:exception_renderer] if options[:exception_renderer] + context.strict_variables = options[:strict_variables] if options[:strict_variables] + context.strict_filters = options[:strict_filters] if options[:strict_filters] + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/tokenizer.rb b/bin/gems/liquid-4.0.4/lib/liquid/tokenizer.rb new file mode 100644 index 00000000..d03657e8 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/tokenizer.rb @@ -0,0 +1,31 @@ +module Liquid + class Tokenizer + attr_reader :line_number + + def initialize(source, line_numbers = false) + @source = source + @line_number = line_numbers ? 1 : nil + @tokens = tokenize + end + + def shift + token = @tokens.shift + @line_number += token.count("\n") if @line_number && token + token + end + + private + + def tokenize + @source = @source.source if @source.respond_to?(:source) + return [] if @source.to_s.empty? + + tokens = @source.split(TemplateParser) + + # removes the rogue empty element at the beginning of the array + tokens.shift if tokens[0] && tokens[0].empty? + + tokens + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/utils.rb b/bin/gems/liquid-4.0.4/lib/liquid/utils.rb new file mode 100644 index 00000000..516ac0cf --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/utils.rb @@ -0,0 +1,83 @@ +module Liquid + module Utils + def self.slice_collection(collection, from, to) + if (from != 0 || !to.nil?) && collection.respond_to?(:load_slice) + collection.load_slice(from, to) + else + slice_collection_using_each(collection, from, to) + end + end + + def self.slice_collection_using_each(collection, from, to) + segments = [] + index = 0 + + # Maintains Ruby 1.8.7 String#each behaviour on 1.9 + if collection.is_a?(String) + return collection.empty? ? [] : [collection] + end + return [] unless collection.respond_to?(:each) + + collection.each do |item| + if to && to <= index + break + end + + if from <= index + segments << item + end + + index += 1 + end + + segments + end + + def self.to_integer(num) + return num if num.is_a?(Integer) + num = num.to_s + begin + Integer(num) + rescue ::ArgumentError + raise Liquid::ArgumentError, "invalid integer" + end + end + + def self.to_number(obj) + case obj + when Float + BigDecimal(obj.to_s) + when Numeric + obj + when String + (obj.strip =~ /\A-?\d+\.\d+\z/) ? BigDecimal(obj) : obj.to_i + else + if obj.respond_to?(:to_number) + obj.to_number + else + 0 + end + end + end + + def self.to_date(obj) + return obj if obj.respond_to?(:strftime) + + if obj.is_a?(String) + return nil if obj.empty? + obj = obj.downcase + end + + case obj + when 'now'.freeze, 'today'.freeze + Time.now + when /\A\d+\z/, Integer + Time.at(obj.to_i) + when String + Time.parse(obj) + end + rescue ::ArgumentError + nil + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/variable.rb b/bin/gems/liquid-4.0.4/lib/liquid/variable.rb new file mode 100644 index 00000000..8d63eb14 --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/variable.rb @@ -0,0 +1,125 @@ +module Liquid + # Holds variables. Variables are only loaded "just in time" + # and are not evaluated as part of the render stage + # + # {{ monkey }} + # {{ user.name }} + # + # Variables can be combined with filters: + # + # {{ user | link }} + # + class Variable + FilterMarkupRegex = /#{FilterSeparator}\s*(.*)/om + FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o + FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o + JustTagAttributes = /\A#{TagAttributes}\z/o + MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om + + attr_accessor :filters, :name, :line_number + attr_reader :parse_context + alias_method :options, :parse_context + + include ParserSwitching + + def initialize(markup, parse_context) + @markup = markup + @name = nil + @parse_context = parse_context + @line_number = parse_context.line_number + + parse_with_selected_parser(markup) + end + + def raw + @markup + end + + def markup_context(markup) + "in \"{{#{markup}}}\"" + end + + def lax_parse(markup) + @filters = [] + return unless markup =~ MarkupWithQuotedFragment + + name_markup = $1 + filter_markup = $2 + @name = Expression.parse(name_markup) + if filter_markup =~ FilterMarkupRegex + filters = $1.scan(FilterParser) + filters.each do |f| + next unless f =~ /\w+/ + filtername = Regexp.last_match(0) + filterargs = f.scan(FilterArgsRegex).flatten + @filters << parse_filter_expressions(filtername, filterargs) + end + end + end + + def strict_parse(markup) + @filters = [] + p = Parser.new(markup) + + @name = Expression.parse(p.expression) + while p.consume?(:pipe) + filtername = p.consume(:id) + filterargs = p.consume?(:colon) ? parse_filterargs(p) : [] + @filters << parse_filter_expressions(filtername, filterargs) + end + p.consume(:end_of_string) + end + + def parse_filterargs(p) + # first argument + filterargs = [p.argument] + # followed by comma separated others + filterargs << p.argument while p.consume?(:comma) + filterargs + end + + def render(context) + obj = @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)| + filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs) + context.invoke(filter_name, output, *filter_args) + end + + context.apply_global_filter(obj) + end + + private + + def parse_filter_expressions(filter_name, unparsed_args) + filter_args = [] + keyword_args = {} + unparsed_args.each do |a| + if matches = a.match(JustTagAttributes) + keyword_args[matches[1]] = Expression.parse(matches[2]) + else + filter_args << Expression.parse(a) + end + end + result = [filter_name, filter_args] + result << keyword_args unless keyword_args.empty? + result + end + + def evaluate_filter_expressions(context, filter_args, filter_kwargs) + parsed_args = filter_args.map{ |expr| context.evaluate(expr) } + if filter_kwargs + parsed_kwargs = {} + filter_kwargs.each do |key, expr| + parsed_kwargs[key] = context.evaluate(expr) + end + parsed_args << parsed_kwargs + end + parsed_args + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + [@node.name] + @node.filters.flatten + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/variable_lookup.rb b/bin/gems/liquid-4.0.4/lib/liquid/variable_lookup.rb new file mode 100644 index 00000000..62f4877c --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/variable_lookup.rb @@ -0,0 +1,88 @@ +module Liquid + class VariableLookup + SQUARE_BRACKETED = /\A\[(.*)\]\z/m + COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze].freeze + + attr_reader :name, :lookups + + def self.parse(markup) + new(markup) + end + + def initialize(markup) + lookups = markup.scan(VariableParser) + + name = lookups.shift + if name =~ SQUARE_BRACKETED + name = Expression.parse($1) + end + @name = name + + @lookups = lookups + @command_flags = 0 + + @lookups.each_index do |i| + lookup = lookups[i] + if lookup =~ SQUARE_BRACKETED + lookups[i] = Expression.parse($1) + elsif COMMAND_METHODS.include?(lookup) + @command_flags |= 1 << i + end + end + end + + def evaluate(context) + name = context.evaluate(@name) + object = context.find_variable(name) + + @lookups.each_index do |i| + key = context.evaluate(@lookups[i]) + + # If object is a hash- or array-like object we look for the + # presence of the key and if its available we return it + if object.respond_to?(:[]) && + ((object.respond_to?(:key?) && object.key?(key)) || + (object.respond_to?(:fetch) && key.is_a?(Integer))) + + # if its a proc we will replace the entry with the proc + res = context.lookup_and_evaluate(object, key) + object = res.to_liquid + + # Some special cases. If the part wasn't in square brackets and + # no key with the same name was found we interpret following calls + # as commands and call them on the current object + elsif @command_flags & (1 << i) != 0 && object.respond_to?(key) + object = object.send(key).to_liquid + + # No key was present with the desired value and it wasn't one of the directly supported + # keywords either. The only thing we got left is to return nil or + # raise an exception if `strict_variables` option is set to true + else + return nil unless context.strict_variables + raise Liquid::UndefinedVariable, "undefined variable #{key}" + end + + # If we are dealing with a drop here we have to + object.context = context if object.respond_to?(:context=) + end + + object + end + + def ==(other) + self.class == other.class && state == other.state + end + + protected + + def state + [@name, @lookups, @command_flags] + end + + class ParseTreeVisitor < Liquid::ParseTreeVisitor + def children + @node.lookups + end + end + end +end diff --git a/bin/gems/liquid-4.0.4/lib/liquid/version.rb b/bin/gems/liquid-4.0.4/lib/liquid/version.rb new file mode 100644 index 00000000..9799863d --- /dev/null +++ b/bin/gems/liquid-4.0.4/lib/liquid/version.rb @@ -0,0 +1,5 @@ +# encoding: utf-8 + +module Liquid + VERSION = "4.0.4".freeze +end diff --git a/bin/gems/liquid-4.0.4/test/fixtures/en_locale.yml b/bin/gems/liquid-4.0.4/test/fixtures/en_locale.yml new file mode 100644 index 00000000..0b113c67 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/fixtures/en_locale.yml @@ -0,0 +1,9 @@ +--- + simple: "less is more" + whatever: "something %{something}" + errors: + i18n: + undefined_interpolation: "undefined key %{key}" + unknown_translation: "translation '%{name}' wasn't found" + syntax: + oops: "something wasn't right" diff --git a/bin/gems/liquid-4.0.4/test/integration/assign_test.rb b/bin/gems/liquid-4.0.4/test/integration/assign_test.rb new file mode 100644 index 00000000..55022899 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/assign_test.rb @@ -0,0 +1,48 @@ +require 'test_helper' + +class AssignTest < Minitest::Test + include Liquid + + def test_assign_with_hyphen_in_variable_name + template_source = <<-END_TEMPLATE + {% assign this-thing = 'Print this-thing' %} + {{ this-thing }} + END_TEMPLATE + template = Template.parse(template_source) + rendered = template.render! + assert_equal "Print this-thing", rendered.strip + end + + def test_assigned_variable + assert_template_result('.foo.', + '{% assign foo = values %}.{{ foo[0] }}.', + 'values' => %w(foo bar baz)) + + assert_template_result('.bar.', + '{% assign foo = values %}.{{ foo[1] }}.', + 'values' => %w(foo bar baz)) + end + + def test_assign_with_filter + assert_template_result('.bar.', + '{% assign foo = values | split: "," %}.{{ foo[1] }}.', + 'values' => "foo,bar,baz") + end + + def test_assign_syntax_error + assert_match_syntax_error(/assign/, + '{% assign foo not values %}.', + 'values' => "foo,bar,baz") + end + + def test_assign_uses_error_mode + with_error_mode(:strict) do + assert_raises(SyntaxError) do + Template.parse("{% assign foo = ('X' | downcase) %}") + end + end + with_error_mode(:lax) do + assert Template.parse("{% assign foo = ('X' | downcase) %}") + end + end +end # AssignTest diff --git a/bin/gems/liquid-4.0.4/test/integration/blank_test.rb b/bin/gems/liquid-4.0.4/test/integration/blank_test.rb new file mode 100644 index 00000000..e9b56df1 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/blank_test.rb @@ -0,0 +1,106 @@ +require 'test_helper' + +class FoobarTag < Liquid::Tag + def render(*args) + " " + end + + Liquid::Template.register_tag('foobar', FoobarTag) +end + +class BlankTestFileSystem + def read_template_file(template_path) + template_path + end +end + +class BlankTest < Minitest::Test + include Liquid + N = 10 + + def wrap_in_for(body) + "{% for i in (1..#{N}) %}#{body}{% endfor %}" + end + + def wrap_in_if(body) + "{% if true %}#{body}{% endif %}" + end + + def wrap(body) + wrap_in_for(body) + wrap_in_if(body) + end + + def test_new_tags_are_not_blank_by_default + assert_template_result(" " * N, wrap_in_for("{% foobar %}")) + end + + def test_loops_are_blank + assert_template_result("", wrap_in_for(" ")) + end + + def test_if_else_are_blank + assert_template_result("", "{% if true %} {% elsif false %} {% else %} {% endif %}") + end + + def test_unless_is_blank + assert_template_result("", wrap("{% unless true %} {% endunless %}")) + end + + def test_mark_as_blank_only_during_parsing + assert_template_result(" " * (N + 1), wrap(" {% if false %} this never happens, but still, this block is not blank {% endif %}")) + end + + def test_comments_are_blank + assert_template_result("", wrap(" {% comment %} whatever {% endcomment %} ")) + end + + def test_captures_are_blank + assert_template_result("", wrap(" {% capture foo %} whatever {% endcapture %} ")) + end + + def test_nested_blocks_are_blank_but_only_if_all_children_are + assert_template_result("", wrap(wrap(" "))) + assert_template_result("\n but this is not " * (N + 1), + wrap('{% if true %} {% comment %} this is blank {% endcomment %} {% endif %} + {% if true %} but this is not {% endif %}')) + end + + def test_assigns_are_blank + assert_template_result("", wrap(' {% assign foo = "bar" %} ')) + end + + def test_whitespace_is_blank + assert_template_result("", wrap(" ")) + assert_template_result("", wrap("\t")) + end + + def test_whitespace_is_not_blank_if_other_stuff_is_present + body = " x " + assert_template_result(body * (N + 1), wrap(body)) + end + + def test_increment_is_not_blank + assert_template_result(" 0" * 2 * (N + 1), wrap("{% assign foo = 0 %} {% increment foo %} {% decrement foo %}")) + end + + def test_cycle_is_not_blank + assert_template_result(" " * ((N + 1) / 2) + " ", wrap("{% cycle ' ', ' ' %}")) + end + + def test_raw_is_not_blank + assert_template_result(" " * (N + 1), wrap(" {% raw %} {% endraw %}")) + end + + def test_include_is_blank + Liquid::Template.file_system = BlankTestFileSystem.new + assert_template_result "foobar" * (N + 1), wrap("{% include 'foobar' %}") + assert_template_result " foobar " * (N + 1), wrap("{% include ' foobar ' %}") + assert_template_result " " * (N + 1), wrap(" {% include ' ' %} ") + end + + def test_case_is_blank + assert_template_result("", wrap(" {% assign foo = 'bar' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} ")) + assert_template_result("", wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} ")) + assert_template_result(" x " * (N + 1), wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} x {% endcase %} ")) + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/block_test.rb b/bin/gems/liquid-4.0.4/test/integration/block_test.rb new file mode 100644 index 00000000..08245301 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/block_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' + +class BlockTest < Minitest::Test + include Liquid + + def test_unexpected_end_tag + exc = assert_raises(SyntaxError) do + Template.parse("{% if true %}{% endunless %}") + end + assert_equal exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif" + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/capture_test.rb b/bin/gems/liquid-4.0.4/test/integration/capture_test.rb new file mode 100644 index 00000000..8d965b35 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/capture_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class CaptureTest < Minitest::Test + include Liquid + + def test_captures_block_content_in_variable + assert_template_result("test string", "{% capture 'var' %}test string{% endcapture %}{{var}}", {}) + end + + def test_capture_with_hyphen_in_variable_name + template_source = <<-END_TEMPLATE + {% capture this-thing %}Print this-thing{% endcapture %} + {{ this-thing }} + END_TEMPLATE + template = Template.parse(template_source) + rendered = template.render! + assert_equal "Print this-thing", rendered.strip + end + + def test_capture_to_variable_from_outer_scope_if_existing + template_source = <<-END_TEMPLATE + {% assign var = '' %} + {% if true %} + {% capture var %}first-block-string{% endcapture %} + {% endif %} + {% if true %} + {% capture var %}test-string{% endcapture %} + {% endif %} + {{var}} + END_TEMPLATE + template = Template.parse(template_source) + rendered = template.render! + assert_equal "test-string", rendered.gsub(/\s/, '') + end + + def test_assigning_from_capture + template_source = <<-END_TEMPLATE + {% assign first = '' %} + {% assign second = '' %} + {% for number in (1..3) %} + {% capture first %}{{number}}{% endcapture %} + {% assign second = first %} + {% endfor %} + {{ first }}-{{ second }} + END_TEMPLATE + template = Template.parse(template_source) + rendered = template.render! + assert_equal "3-3", rendered.gsub(/\s/, '') + end +end # CaptureTest diff --git a/bin/gems/liquid-4.0.4/test/integration/context_test.rb b/bin/gems/liquid-4.0.4/test/integration/context_test.rb new file mode 100644 index 00000000..2d109bb7 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/context_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' + +class ContextTest < Minitest::Test + include Liquid + + def test_override_global_filter + global = Module.new do + def notice(output) + "Global #{output}" + end + end + + local = Module.new do + def notice(output) + "Local #{output}" + end + end + + with_global_filter(global) do + assert_equal 'Global test', Template.parse("{{'test' | notice }}").render! + assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, filters: [local]) + end + end + + def test_has_key_will_not_add_an_error_for_missing_keys + with_error_mode :strict do + context = Context.new + context.key?('unknown') + assert_empty context.errors + end + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/document_test.rb b/bin/gems/liquid-4.0.4/test/integration/document_test.rb new file mode 100644 index 00000000..bcc4a21c --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/document_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class DocumentTest < Minitest::Test + include Liquid + + def test_unexpected_outer_tag + exc = assert_raises(SyntaxError) do + Template.parse("{% else %}") + end + assert_equal exc.message, "Liquid syntax error: Unexpected outer 'else' tag" + end + + def test_unknown_tag + exc = assert_raises(SyntaxError) do + Template.parse("{% foo %}") + end + assert_equal exc.message, "Liquid syntax error: Unknown tag 'foo'" + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/drop_test.rb b/bin/gems/liquid-4.0.4/test/integration/drop_test.rb new file mode 100644 index 00000000..723fe042 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/drop_test.rb @@ -0,0 +1,247 @@ +require 'test_helper' + +class ContextDrop < Liquid::Drop + def scopes + @context.scopes.size + end + + def scopes_as_array + (1..@context.scopes.size).to_a + end + + def loop_pos + @context['forloop.index'] + end + + def liquid_method_missing(method) + @context[method] + end +end + +class ProductDrop < Liquid::Drop + class TextDrop < Liquid::Drop + def array + ['text1', 'text2'] + end + + def text + 'text1' + end + end + + class CatchallDrop < Liquid::Drop + def liquid_method_missing(method) + 'catchall_method: ' << method.to_s + end + end + + def texts + TextDrop.new + end + + def catchall + CatchallDrop.new + end + + def context + ContextDrop.new + end + + def user_input + "foo" + end + + protected + + def callmenot + "protected" + end +end + +class EnumerableDrop < Liquid::Drop + def liquid_method_missing(method) + method + end + + def size + 3 + end + + def first + 1 + end + + def count + 3 + end + + def min + 1 + end + + def max + 3 + end + + def each + yield 1 + yield 2 + yield 3 + end +end + +class RealEnumerableDrop < Liquid::Drop + include Enumerable + + def liquid_method_missing(method) + method + end + + def each + yield 1 + yield 2 + yield 3 + end +end + +class DropsTest < Minitest::Test + include Liquid + + def test_product_drop + tpl = Liquid::Template.parse(' ') + assert_equal ' ', tpl.render!('product' => ProductDrop.new) + end + + def test_drop_does_only_respond_to_whitelisted_methods + assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new) + assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new) + assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new) + assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new) + assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new) + assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new) + end + + def test_drops_respond_to_to_liquid + assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new) + assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new) + end + + def test_text_drop + output = Liquid::Template.parse(' {{ product.texts.text }} ').render!('product' => ProductDrop.new) + assert_equal ' text1 ', output + end + + def test_catchall_unknown_method + output = Liquid::Template.parse(' {{ product.catchall.unknown }} ').render!('product' => ProductDrop.new) + assert_equal ' catchall_method: unknown ', output + end + + def test_catchall_integer_argument_drop + output = Liquid::Template.parse(' {{ product.catchall[8] }} ').render!('product' => ProductDrop.new) + assert_equal ' catchall_method: 8 ', output + end + + def test_text_array_drop + output = Liquid::Template.parse('{% for text in product.texts.array %} {{text}} {% endfor %}').render!('product' => ProductDrop.new) + assert_equal ' text1 text2 ', output + end + + def test_context_drop + output = Liquid::Template.parse(' {{ context.bar }} ').render!('context' => ContextDrop.new, 'bar' => "carrot") + assert_equal ' carrot ', output + end + + def test_nested_context_drop + output = Liquid::Template.parse(' {{ product.context.foo }} ').render!('product' => ProductDrop.new, 'foo' => "monkey") + assert_equal ' monkey ', output + end + + def test_protected + output = Liquid::Template.parse(' {{ product.callmenot }} ').render!('product' => ProductDrop.new) + assert_equal ' ', output + end + + def test_object_methods_not_allowed + [:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method| + output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new) + assert_equal ' ', output + end + end + + def test_scope + assert_equal '1', Liquid::Template.parse('{{ context.scopes }}').render!('context' => ContextDrop.new) + assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ context.scopes }}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]) + assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]) + end + + def test_scope_though_proc + assert_equal '1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }) + assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1]) + assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1]) + end + + def test_scope_with_assigns + assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{{a}}').render!('context' => ContextDrop.new) + assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]) + assert_equal 'test', Liquid::Template.parse('{% assign header_gif = "test"%}{{header_gif}}').render!('context' => ContextDrop.new) + assert_equal 'test', Liquid::Template.parse("{% assign header_gif = 'test'%}{{header_gif}}").render!('context' => ContextDrop.new) + end + + def test_scope_from_tags + assert_equal '1', Liquid::Template.parse('{% for i in context.scopes_as_array %}{{i}}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]) + assert_equal '12', Liquid::Template.parse('{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]) + assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]) + end + + def test_access_context_from_drop + assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{{ context.loop_pos }}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1, 2, 3]) + end + + def test_enumerable_drop + assert_equal '123', Liquid::Template.parse('{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new) + end + + def test_enumerable_drop_size + assert_equal '3', Liquid::Template.parse('{{collection.size}}').render!('collection' => EnumerableDrop.new) + end + + def test_enumerable_drop_will_invoke_liquid_method_missing_for_clashing_method_names + ["select", "each", "map", "cycle"].each do |method| + assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new) + assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new) + assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new) + assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new) + end + end + + def test_some_enumerable_methods_still_get_invoked + [ :count, :max ].each do |method| + assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new) + assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new) + assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new) + assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new) + end + + assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new) + + [ :min, :first ].each do |method| + assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new) + assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new) + assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new) + assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new) + end + end + + def test_empty_string_value_access + assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => '') + end + + def test_nil_value_access + assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil) + end + + def test_default_to_s_on_drops + assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new) + assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new) + end +end # DropsTest diff --git a/bin/gems/liquid-4.0.4/test/integration/error_handling_test.rb b/bin/gems/liquid-4.0.4/test/integration/error_handling_test.rb new file mode 100644 index 00000000..b2d186cf --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/error_handling_test.rb @@ -0,0 +1,260 @@ +require 'test_helper' + +class ErrorHandlingTest < Minitest::Test + include Liquid + + def test_templates_parsed_with_line_numbers_renders_them_in_errors + template = <<-LIQUID + Hello, + + {{ errors.standard_error }} will raise a standard error. + + Bla bla test. + + {{ errors.syntax_error }} will raise a syntax error. + + This is an argument error: {{ errors.argument_error }} + + Bla. + LIQUID + + expected = <<-TEXT + Hello, + + Liquid error (line 3): standard error will raise a standard error. + + Bla bla test. + + Liquid syntax error (line 7): syntax error will raise a syntax error. + + This is an argument error: Liquid error (line 9): argument error + + Bla. + TEXT + + output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new) + assert_equal expected, output + end + + def test_standard_error + template = Liquid::Template.parse(' {{ errors.standard_error }} ') + assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new) + + assert_equal 1, template.errors.size + assert_equal StandardError, template.errors.first.class + end + + def test_syntax + template = Liquid::Template.parse(' {{ errors.syntax_error }} ') + assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new) + + assert_equal 1, template.errors.size + assert_equal SyntaxError, template.errors.first.class + end + + def test_argument + template = Liquid::Template.parse(' {{ errors.argument_error }} ') + assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new) + + assert_equal 1, template.errors.size + assert_equal ArgumentError, template.errors.first.class + end + + def test_missing_endtag_parse_time_error + assert_raises(Liquid::SyntaxError) do + Liquid::Template.parse(' {% for a in b %} ... ') + end + end + + def test_unrecognized_operator + with_error_mode(:strict) do + assert_raises(SyntaxError) do + Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ') + end + end + end + + def test_lax_unrecognized_operator + template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax) + assert_equal ' Liquid error: Unknown operator =! ', template.render + assert_equal 1, template.errors.size + assert_equal Liquid::ArgumentError, template.errors.first.class + end + + def test_with_line_numbers_adds_numbers_to_parser_errors + err = assert_raises(SyntaxError) do + Liquid::Template.parse(%q( + foobar + + {% "cat" | foobar %} + + bla + ), + line_numbers: true + ) + end + + assert_match(/Liquid syntax error \(line 4\)/, err.message) + end + + def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim + err = assert_raises(SyntaxError) do + Liquid::Template.parse(%q( + foobar + + {%- "cat" | foobar -%} + + bla + ), + line_numbers: true + ) + end + + assert_match(/Liquid syntax error \(line 4\)/, err.message) + end + + def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors + template = Liquid::Template.parse(' + foobar + + {% if 1 =! 2 %}ok{% endif %} + + bla + ', + error_mode: :warn, + line_numbers: true + ) + + assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'], + template.warnings.map(&:message) + end + + def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors + err = assert_raises(SyntaxError) do + Liquid::Template.parse(' + foobar + + {% if 1 =! 2 %}ok{% endif %} + + bla + ', + error_mode: :strict, + line_numbers: true + ) + end + + assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message + end + + def test_syntax_errors_in_nested_blocks_have_correct_line_number + err = assert_raises(SyntaxError) do + Liquid::Template.parse(' + foobar + + {% if 1 != 2 %} + {% foo %} + {% endif %} + + bla + ', + line_numbers: true + ) + end + + assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message + end + + def test_strict_error_messages + err = assert_raises(SyntaxError) do + Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict) + end + assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message + + err = assert_raises(SyntaxError) do + Liquid::Template.parse('{{%%%}}', error_mode: :strict) + end + assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message + end + + def test_warnings + template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn) + assert_equal 3, template.warnings.size + assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false) + assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false) + assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false) + assert_equal '', template.render + end + + def test_warning_line_numbers + template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true) + assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message + assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message + assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message + assert_equal 3, template.warnings.size + assert_equal [1, 2, 3], template.warnings.map(&:line_number) + end + + # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError + def test_exceptions_propagate + assert_raises Exception do + template = Liquid::Template.parse('{{ errors.exception }}') + template.render('errors' => ErrorDrop.new) + end + end + + def test_default_exception_renderer_with_internal_error + template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true) + + output = template.render({ 'errors' => ErrorDrop.new }) + + assert_equal 'This is a runtime error: Liquid error (line 1): internal', output + assert_equal [Liquid::InternalError], template.errors.map(&:class) + end + + def test_setting_default_exception_renderer + old_exception_renderer = Liquid::Template.default_exception_renderer + exceptions = [] + Liquid::Template.default_exception_renderer = ->(e) { exceptions << e; '' } + template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}') + + output = template.render({ 'errors' => ErrorDrop.new }) + + assert_equal 'This is a runtime error: ', output + assert_equal [Liquid::ArgumentError], template.errors.map(&:class) + ensure + Liquid::Template.default_exception_renderer = old_exception_renderer if old_exception_renderer + end + + def test_exception_renderer_exposing_non_liquid_error + template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true) + exceptions = [] + handler = ->(e) { exceptions << e; e.cause } + + output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler) + + assert_equal 'This is a runtime error: runtime error', output + assert_equal [Liquid::InternalError], exceptions.map(&:class) + assert_equal exceptions, template.errors + assert_equal '#', exceptions.first.cause.inspect + end + + class TestFileSystem + def read_template_file(template_path) + "{{ errors.argument_error }}" + end + end + + def test_included_template_name_with_line_numbers + old_file_system = Liquid::Template.file_system + + begin + Liquid::Template.file_system = TestFileSystem.new + template = Liquid::Template.parse("Argument error:\n{% include 'product' %}", line_numbers: true) + page = template.render('errors' => ErrorDrop.new) + ensure + Liquid::Template.file_system = old_file_system + end + assert_equal "Argument error:\nLiquid error (product line 1): argument error", page + assert_equal "product", template.errors.first.template_name + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/filter_test.rb b/bin/gems/liquid-4.0.4/test/integration/filter_test.rb new file mode 100644 index 00000000..d3c880e8 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/filter_test.rb @@ -0,0 +1,178 @@ +require 'test_helper' + +module MoneyFilter + def money(input) + sprintf(' %d$ ', input) + end + + def money_with_underscore(input) + sprintf(' %d$ ', input) + end +end + +module CanadianMoneyFilter + def money(input) + sprintf(' %d$ CAD ', input) + end +end + +module SubstituteFilter + def substitute(input, params = {}) + input.gsub(/%\{(\w+)\}/) { |match| params[$1] } + end +end + +class FiltersTest < Minitest::Test + include Liquid + + module OverrideObjectMethodFilter + def tap(input) + "tap overridden" + end + end + + def setup + @context = Context.new + end + + def test_local_filter + @context['var'] = 1000 + @context.add_filters(MoneyFilter) + + assert_equal ' 1000$ ', Template.parse("{{var | money}}").render(@context) + end + + def test_underscore_in_filter_name + @context['var'] = 1000 + @context.add_filters(MoneyFilter) + assert_equal ' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context) + end + + def test_second_filter_overwrites_first + @context['var'] = 1000 + @context.add_filters(MoneyFilter) + @context.add_filters(CanadianMoneyFilter) + + assert_equal ' 1000$ CAD ', Template.parse("{{var | money}}").render(@context) + end + + def test_size + @context['var'] = 'abcd' + @context.add_filters(MoneyFilter) + + assert_equal '4', Template.parse("{{var | size}}").render(@context) + end + + def test_join + @context['var'] = [1, 2, 3, 4] + + assert_equal "1 2 3 4", Template.parse("{{var | join}}").render(@context) + end + + def test_sort + @context['value'] = 3 + @context['numbers'] = [2, 1, 4, 3] + @context['words'] = ['expected', 'as', 'alphabetic'] + @context['arrays'] = ['flower', 'are'] + @context['case_sensitive'] = ['sensitive', 'Expected', 'case'] + + assert_equal '1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context) + assert_equal 'alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context) + assert_equal '3', Template.parse("{{value | sort}}").render(@context) + assert_equal 'are flower', Template.parse("{{arrays | sort | join}}").render(@context) + assert_equal 'Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context) + end + + def test_sort_natural + @context['words'] = ['case', 'Assert', 'Insensitive'] + @context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }] + @context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')] + + # Test strings + assert_equal 'Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context) + + # Test hashes + assert_equal 'A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context) + + # Test objects + assert_equal 'A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context) + end + + def test_compact + @context['words'] = ['a', nil, 'b', nil, 'c'] + @context['hashes'] = [{ 'a' => 'A' }, { 'a' => nil }, { 'a' => 'C' }] + @context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')] + + # Test strings + assert_equal 'a b c', Template.parse("{{words | compact | join}}").render(@context) + + # Test hashes + assert_equal 'A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context) + + # Test objects + assert_equal 'A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context) + end + + def test_strip_html + @context['var'] = "bla blub" + + assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context) + end + + def test_strip_html_ignore_comments_with_html + @context['var'] = "bla blub" + + assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context) + end + + def test_capitalize + @context['var'] = "blub" + + assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context) + end + + def test_nonexistent_filter_is_ignored + @context['var'] = 1000 + + assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context) + end + + def test_filter_with_keyword_arguments + @context['surname'] = 'john' + @context['input'] = 'hello %{first_name}, %{last_name}' + @context.add_filters(SubstituteFilter) + output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context) + assert_equal 'hello john, doe', output + end + + def test_override_object_method_in_filter + assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter]) + + # tap still treated as a non-existent filter + assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }) + end +end + +class FiltersInTemplate < Minitest::Test + include Liquid + + def test_local_global + with_global_filter(MoneyFilter) do + assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil) + assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: CanadianMoneyFilter) + assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: [CanadianMoneyFilter]) + end + end + + def test_local_filter_with_deprecated_syntax + assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter) + assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter]) + end +end # FiltersTest + +class TestObject < Liquid::Drop + attr_accessor :a + def initialize(a) + @a = a + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/hash_ordering_test.rb b/bin/gems/liquid-4.0.4/test/integration/hash_ordering_test.rb new file mode 100644 index 00000000..dfc1c29f --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/hash_ordering_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class HashOrderingTest < Minitest::Test + module MoneyFilter + def money(input) + sprintf(' %d$ ', input) + end + end + + module CanadianMoneyFilter + def money(input) + sprintf(' %d$ CAD ', input) + end + end + + include Liquid + + def test_global_register_order + with_global_filter(MoneyFilter, CanadianMoneyFilter) do + assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil) + end + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/output_test.rb b/bin/gems/liquid-4.0.4/test/integration/output_test.rb new file mode 100644 index 00000000..b4cf9d70 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/output_test.rb @@ -0,0 +1,123 @@ +require 'test_helper' + +module FunnyFilter + def make_funny(input) + 'LOL' + end + + def cite_funny(input) + "LOL: #{input}" + end + + def add_smiley(input, smiley = ":-)") + "#{input} #{smiley}" + end + + def add_tag(input, tag = "p", id = "foo") + %(<#{tag} id="#{id}">#{input}) + end + + def paragraph(input) + "

#{input}

" + end + + def link_to(name, url) + %(#{name}) + end +end + +class OutputTest < Minitest::Test + include Liquid + + def setup + @assigns = { + 'best_cars' => 'bmw', + 'car' => { 'bmw' => 'good', 'gm' => 'bad' } + } + end + + def test_variable + text = %( {{best_cars}} ) + + expected = %( bmw ) + assert_equal expected, Template.parse(text).render!(@assigns) + end + + def test_variable_traversing_with_two_brackets + text = %({{ site.data.menu[include.menu][include.locale] }}) + assert_equal "it works!", Template.parse(text).render!( + "site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } }, + "include" => { "menu" => "foo", "locale" => "bar" } + ) + end + + def test_variable_traversing + text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} ) + + expected = %( good bad good ) + assert_equal expected, Template.parse(text).render!(@assigns) + end + + def test_variable_piping + text = %( {{ car.gm | make_funny }} ) + expected = %( LOL ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_variable_piping_with_input + text = %( {{ car.gm | cite_funny }} ) + expected = %( LOL: bad ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_variable_piping_with_args + text = %! {{ car.gm | add_smiley : ':-(' }} ! + expected = %| bad :-( | + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_variable_piping_with_no_args + text = %( {{ car.gm | add_smiley }} ) + expected = %| bad :-) | + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_multiple_variable_piping_with_args + text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} ! + expected = %| bad :-( :-( | + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_variable_piping_with_multiple_args + text = %( {{ car.gm | add_tag : 'span', 'bar'}} ) + expected = %( bad ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_variable_piping_with_variable_args + text = %( {{ car.gm | add_tag : 'span', car.bmw}} ) + expected = %( bad ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_multiple_pipings + text = %( {{ best_cars | cite_funny | paragraph }} ) + expected = %(

LOL: bmw

) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end + + def test_link_to + text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} ) + expected = %( Typo ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]) + end +end # OutputTest diff --git a/bin/gems/liquid-4.0.4/test/integration/parse_tree_visitor_test.rb b/bin/gems/liquid-4.0.4/test/integration/parse_tree_visitor_test.rb new file mode 100644 index 00000000..933dbc3b --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/parse_tree_visitor_test.rb @@ -0,0 +1,247 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ParseTreeVisitorTest < Minitest::Test + include Liquid + + def test_variable + assert_equal( + ["test"], + visit(%({{ test }})) + ) + end + + def test_varible_with_filter + assert_equal( + ["test", "infilter"], + visit(%({{ test | split: infilter }})) + ) + end + + def test_dynamic_variable + assert_equal( + ["test", "inlookup"], + visit(%({{ test[inlookup] }})) + ) + end + + def test_if_condition + assert_equal( + ["test"], + visit(%({% if test %}{% endif %})) + ) + end + + def test_complex_if_condition + assert_equal( + ["test"], + visit(%({% if 1 == 1 and 2 == test %}{% endif %})) + ) + end + + def test_if_body + assert_equal( + ["test"], + visit(%({% if 1 == 1 %}{{ test }}{% endif %})) + ) + end + + def test_unless_condition + assert_equal( + ["test"], + visit(%({% unless test %}{% endunless %})) + ) + end + + def test_complex_unless_condition + assert_equal( + ["test"], + visit(%({% unless 1 == 1 and 2 == test %}{% endunless %})) + ) + end + + def test_unless_body + assert_equal( + ["test"], + visit(%({% unless 1 == 1 %}{{ test }}{% endunless %})) + ) + end + + def test_elsif_condition + assert_equal( + ["test"], + visit(%({% if 1 == 1 %}{% elsif test %}{% endif %})) + ) + end + + def test_complex_elsif_condition + assert_equal( + ["test"], + visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %})) + ) + end + + def test_elsif_body + assert_equal( + ["test"], + visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %})) + ) + end + + def test_else_body + assert_equal( + ["test"], + visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %})) + ) + end + + def test_case_left + assert_equal( + ["test"], + visit(%({% case test %}{% endcase %})) + ) + end + + def test_case_condition + assert_equal( + ["test"], + visit(%({% case 1 %}{% when test %}{% endcase %})) + ) + end + + def test_case_when_body + assert_equal( + ["test"], + visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %})) + ) + end + + def test_case_else_body + assert_equal( + ["test"], + visit(%({% case 1 %}{% else %}{{ test }}{% endcase %})) + ) + end + + def test_for_in + assert_equal( + ["test"], + visit(%({% for x in test %}{% endfor %})) + ) + end + + def test_for_limit + assert_equal( + ["test"], + visit(%({% for x in (1..5) limit: test %}{% endfor %})) + ) + end + + def test_for_offset + assert_equal( + ["test"], + visit(%({% for x in (1..5) offset: test %}{% endfor %})) + ) + end + + def test_for_body + assert_equal( + ["test"], + visit(%({% for x in (1..5) %}{{ test }}{% endfor %})) + ) + end + + def test_tablerow_in + assert_equal( + ["test"], + visit(%({% tablerow x in test %}{% endtablerow %})) + ) + end + + def test_tablerow_limit + assert_equal( + ["test"], + visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %})) + ) + end + + def test_tablerow_offset + assert_equal( + ["test"], + visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %})) + ) + end + + def test_tablerow_body + assert_equal( + ["test"], + visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %})) + ) + end + + def test_cycle + assert_equal( + ["test"], + visit(%({% cycle test %})) + ) + end + + def test_assign + assert_equal( + ["test"], + visit(%({% assign x = test %})) + ) + end + + def test_capture + assert_equal( + ["test"], + visit(%({% capture x %}{{ test }}{% endcapture %})) + ) + end + + def test_include + assert_equal( + ["test"], + visit(%({% include test %})) + ) + end + + def test_include_with + assert_equal( + ["test"], + visit(%({% include "hai" with test %})) + ) + end + + def test_include_for + assert_equal( + ["test"], + visit(%({% include "hai" for test %})) + ) + end + + def test_preserve_tree_structure + assert_equal( + [[nil, [ + [nil, [[nil, [["other", []]]]]], + ["test", []], + ["xs", []] + ]]], + traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit + ) + end + + private + + def traversal(template) + ParseTreeVisitor + .for(Template.parse(template).root) + .add_callback_for(VariableLookup) { |node| node.name } # rubocop:disable Style/SymbolProc + end + + def visit(template) + traversal(template).visit.flatten.compact + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/parsing_quirks_test.rb b/bin/gems/liquid-4.0.4/test/integration/parsing_quirks_test.rb new file mode 100644 index 00000000..29cb6d6d --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/parsing_quirks_test.rb @@ -0,0 +1,122 @@ +require 'test_helper' + +class ParsingQuirksTest < Minitest::Test + include Liquid + + def test_parsing_css + text = " div { font-weight: bold; } " + assert_equal text, Template.parse(text).render! + end + + def test_raise_on_single_close_bracet + assert_raises(SyntaxError) do + Template.parse("text {{method} oh nos!") + end + end + + def test_raise_on_label_and_no_close_bracets + assert_raises(SyntaxError) do + Template.parse("TEST {{ ") + end + end + + def test_raise_on_label_and_no_close_bracets_percent + assert_raises(SyntaxError) do + Template.parse("TEST {% ") + end + end + + def test_error_on_empty_filter + assert Template.parse("{{test}}") + + with_error_mode(:lax) do + assert Template.parse("{{|test}}") + end + + with_error_mode(:strict) do + assert_raises(SyntaxError) { Template.parse("{{|test}}") } + assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") } + end + end + + def test_meaningless_parens_error + with_error_mode(:strict) do + assert_raises(SyntaxError) do + markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false" + Template.parse("{% if #{markup} %} YES {% endif %}") + end + end + end + + def test_unexpected_characters_syntax_error + with_error_mode(:strict) do + assert_raises(SyntaxError) do + markup = "true && false" + Template.parse("{% if #{markup} %} YES {% endif %}") + end + assert_raises(SyntaxError) do + markup = "false || true" + Template.parse("{% if #{markup} %} YES {% endif %}") + end + end + end + + def test_no_error_on_lax_empty_filter + assert Template.parse("{{test |a|b|}}", error_mode: :lax) + assert Template.parse("{{test}}", error_mode: :lax) + assert Template.parse("{{|test|}}", error_mode: :lax) + end + + def test_meaningless_parens_lax + with_error_mode(:lax) do + assigns = { 'b' => 'bar', 'c' => 'baz' } + markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false" + assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}", assigns) + end + end + + def test_unexpected_characters_silently_eat_logic_lax + with_error_mode(:lax) do + markup = "true && false" + assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}") + markup = "false || true" + assert_template_result('', "{% if #{markup} %} YES {% endif %}") + end + end + + def test_raise_on_invalid_tag_delimiter + assert_raises(Liquid::SyntaxError) do + Template.new.parse('{% end %}') + end + end + + def test_unanchored_filter_arguments + with_error_mode(:lax) do + assert_template_result('hi', "{{ 'hi there' | split$$$:' ' | first }}") + + assert_template_result('x', "{{ 'X' | downcase) }}") + + # After the messed up quotes a filter without parameters (reverse) should work + # but one with parameters (remove) shouldn't be detected. + assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}") + assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}") + end + end + + def test_invalid_variables_work + with_error_mode(:lax) do + assert_template_result('bar', "{% assign 123foo = 'bar' %}{{ 123foo }}") + assert_template_result('123', "{% assign 123 = 'bar' %}{{ 123 }}") + end + end + + def test_extra_dots_in_ranges + with_error_mode(:lax) do + assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}") + end + end + + def test_contains_in_id + assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', 'containsallshipments' => true) + end +end # ParsingQuirksTest diff --git a/bin/gems/liquid-4.0.4/test/integration/render_profiling_test.rb b/bin/gems/liquid-4.0.4/test/integration/render_profiling_test.rb new file mode 100644 index 00000000..d0111e77 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/render_profiling_test.rb @@ -0,0 +1,154 @@ +require 'test_helper' + +class RenderProfilingTest < Minitest::Test + include Liquid + + class ProfilingFileSystem + def read_template_file(template_path) + "Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}" + end + end + + def setup + Liquid::Template.file_system = ProfilingFileSystem.new + end + + def test_template_allows_flagging_profiling + t = Template.parse("{{ 'a string' | upcase }}") + t.render! + + assert_nil t.profiler + end + + def test_parse_makes_available_simple_profiling + t = Template.parse("{{ 'a string' | upcase }}", profile: true) + t.render! + + assert_equal 1, t.profiler.length + + node = t.profiler[0] + assert_equal " 'a string' | upcase ", node.code + end + + def test_render_ignores_raw_strings_when_profiling + t = Template.parse("This is raw string\nstuff\nNewline", profile: true) + t.render! + + assert_equal 0, t.profiler.length + end + + def test_profiling_includes_line_numbers_of_liquid_nodes + t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true) + t.render! + assert_equal 2, t.profiler.length + + # {{ 'a string' | upcase }} + assert_equal 1, t.profiler[0].line_number + # {{ increment test }} + assert_equal 2, t.profiler[1].line_number + end + + def test_profiling_includes_line_numbers_of_included_partials + t = Template.parse("{% include 'a_template' %}", profile: true) + t.render! + + included_children = t.profiler[0].children + + # {% assign template_name = 'a_template' %} + assert_equal 1, included_children[0].line_number + # {{ template_name }} + assert_equal 2, included_children[1].line_number + end + + def test_profiling_times_the_rendering_of_tokens + t = Template.parse("{% include 'a_template' %}", profile: true) + t.render! + + node = t.profiler[0] + refute_nil node.render_time + end + + def test_profiling_times_the_entire_render + t = Template.parse("{% include 'a_template' %}", profile: true) + t.render! + + assert t.profiler.total_render_time >= 0, "Total render time was not calculated" + end + + def test_profiling_uses_include_to_mark_children + t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true) + t.render! + + include_node = t.profiler[1] + assert_equal 2, include_node.children.length + end + + def test_profiling_marks_children_with_the_name_of_included_partial + t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true) + t.render! + + include_node = t.profiler[1] + include_node.children.each do |child| + assert_equal "a_template", child.partial + end + end + + def test_profiling_supports_multiple_templates + t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", profile: true) + t.render! + + a_template = t.profiler[1] + a_template.children.each do |child| + assert_equal "a_template", child.partial + end + + b_template = t.profiler[2] + b_template.children.each do |child| + assert_equal "b_template", child.partial + end + end + + def test_profiling_supports_rendering_the_same_partial_multiple_times + t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", profile: true) + t.render! + + a_template1 = t.profiler[1] + a_template1.children.each do |child| + assert_equal "a_template", child.partial + end + + a_template2 = t.profiler[2] + a_template2.children.each do |child| + assert_equal "a_template", child.partial + end + end + + def test_can_iterate_over_each_profiling_entry + t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true) + t.render! + + timing_count = 0 + t.profiler.each do |timing| + timing_count += 1 + end + + assert_equal 2, timing_count + end + + def test_profiling_marks_children_of_if_blocks + t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true) + t.render! + + assert_equal 1, t.profiler.length + assert_equal 2, t.profiler[0].children.length + end + + def test_profiling_marks_children_of_for_blocks + t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true) + t.render!({ "collection" => ["one", "two"] }) + + assert_equal 1, t.profiler.length + # Will profile each invocation of the for block + assert_equal 2, t.profiler[0].children.length + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/security_test.rb b/bin/gems/liquid-4.0.4/test/integration/security_test.rb new file mode 100644 index 00000000..f603ff08 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/security_test.rb @@ -0,0 +1,80 @@ +require 'test_helper' + +module SecurityFilter + def add_one(input) + "#{input} + 1" + end +end + +class SecurityTest < Minitest::Test + include Liquid + + def setup + @assigns = {} + end + + def test_no_instance_eval + text = %( {{ '1+1' | instance_eval }} ) + expected = %( 1+1 ) + + assert_equal expected, Template.parse(text).render!(@assigns) + end + + def test_no_existing_instance_eval + text = %( {{ '1+1' | __instance_eval__ }} ) + expected = %( 1+1 ) + + assert_equal expected, Template.parse(text).render!(@assigns) + end + + def test_no_instance_eval_after_mixing_in_new_filter + text = %( {{ '1+1' | instance_eval }} ) + expected = %( 1+1 ) + + assert_equal expected, Template.parse(text).render!(@assigns) + end + + def test_no_instance_eval_later_in_chain + text = %( {{ '1+1' | add_one | instance_eval }} ) + expected = %( 1+1 + 1 ) + + assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter) + end + + def test_does_not_add_filters_to_symbol_table + current_symbols = Symbol.all_symbols + + test = %( {{ "some_string" | a_bad_filter }} ) + + template = Template.parse(test) + assert_equal [], (Symbol.all_symbols - current_symbols) + + template.render! + assert_equal [], (Symbol.all_symbols - current_symbols) + end + + def test_does_not_add_drop_methods_to_symbol_table + current_symbols = Symbol.all_symbols + + assigns = { 'drop' => Drop.new } + assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render! + assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render! + assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render! + + assert_equal [], (Symbol.all_symbols - current_symbols) + end + + def test_max_depth_nested_blocks_does_not_raise_exception + depth = Liquid::Block::MAX_DEPTH + code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth + assert_equal "rendered", Template.parse(code).render! + end + + def test_more_than_max_depth_nested_blocks_raises_exception + depth = Liquid::Block::MAX_DEPTH + 1 + code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth + assert_raises(Liquid::StackLevelError) do + Template.parse(code).render! + end + end +end # SecurityTest diff --git a/bin/gems/liquid-4.0.4/test/integration/standard_filter_test.rb b/bin/gems/liquid-4.0.4/test/integration/standard_filter_test.rb new file mode 100644 index 00000000..60909510 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/standard_filter_test.rb @@ -0,0 +1,776 @@ +# encoding: utf-8 + +require 'test_helper' + +class Filters + include Liquid::StandardFilters +end + +class TestThing + attr_reader :foo + + def initialize + @foo = 0 + end + + def to_s + "woot: #{@foo}" + end + + def [](whatever) + to_s + end + + def to_liquid + @foo += 1 + self + end +end + +class TestDrop < Liquid::Drop + def test + "testfoo" + end +end + +class TestEnumerable < Liquid::Drop + include Enumerable + + def each(&block) + [ { "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 } ].each(&block) + end +end + +class NumberLikeThing < Liquid::Drop + def initialize(amount) + @amount = amount + end + + def to_number + @amount + end +end + +class StandardFiltersTest < Minitest::Test + include Liquid + + def setup + @filters = Filters.new + end + + def test_size + assert_equal 3, @filters.size([1, 2, 3]) + assert_equal 0, @filters.size([]) + assert_equal 0, @filters.size(nil) + end + + def test_downcase + assert_equal 'testing', @filters.downcase("Testing") + assert_equal '', @filters.downcase(nil) + end + + def test_upcase + assert_equal 'TESTING', @filters.upcase("Testing") + assert_equal '', @filters.upcase(nil) + end + + def test_slice + assert_equal 'oob', @filters.slice('foobar', 1, 3) + assert_equal 'oobar', @filters.slice('foobar', 1, 1000) + assert_equal '', @filters.slice('foobar', 1, 0) + assert_equal 'o', @filters.slice('foobar', 1, 1) + assert_equal 'bar', @filters.slice('foobar', 3, 3) + assert_equal 'ar', @filters.slice('foobar', -2, 2) + assert_equal 'ar', @filters.slice('foobar', -2, 1000) + assert_equal 'r', @filters.slice('foobar', -1) + assert_equal '', @filters.slice(nil, 0) + assert_equal '', @filters.slice('foobar', 100, 10) + assert_equal '', @filters.slice('foobar', -100, 10) + assert_equal 'oob', @filters.slice('foobar', '1', '3') + assert_raises(Liquid::ArgumentError) do + @filters.slice('foobar', nil) + end + assert_raises(Liquid::ArgumentError) do + @filters.slice('foobar', 0, "") + end + end + + def test_slice_on_arrays + input = 'foobar'.split(//) + assert_equal %w(o o b), @filters.slice(input, 1, 3) + assert_equal %w(o o b a r), @filters.slice(input, 1, 1000) + assert_equal %w(), @filters.slice(input, 1, 0) + assert_equal %w(o), @filters.slice(input, 1, 1) + assert_equal %w(b a r), @filters.slice(input, 3, 3) + assert_equal %w(a r), @filters.slice(input, -2, 2) + assert_equal %w(a r), @filters.slice(input, -2, 1000) + assert_equal %w(r), @filters.slice(input, -1) + assert_equal %w(), @filters.slice(input, 100, 10) + assert_equal %w(), @filters.slice(input, -100, 10) + end + + def test_truncate + assert_equal '1234...', @filters.truncate('1234567890', 7) + assert_equal '1234567890', @filters.truncate('1234567890', 20) + assert_equal '...', @filters.truncate('1234567890', 0) + assert_equal '1234567890', @filters.truncate('1234567890') + assert_equal "测试...", @filters.truncate("测试测试测试测试", 5) + assert_equal '12341', @filters.truncate("1234567890", 5, 1) + end + + def test_split + assert_equal ['12', '34'], @filters.split('12~34', '~') + assert_equal ['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~') + assert_equal ['A?Z'], @filters.split('A?Z', '~') + assert_equal [], @filters.split(nil, ' ') + assert_equal ['A', 'Z'], @filters.split('A1Z', 1) + end + + def test_escape + assert_equal '<strong>', @filters.escape('') + assert_equal '1', @filters.escape(1) + assert_equal '2001-02-03', @filters.escape(Date.new(2001, 2, 3)) + assert_nil @filters.escape(nil) + end + + def test_h + assert_equal '<strong>', @filters.h('') + assert_equal '1', @filters.h(1) + assert_equal '2001-02-03', @filters.h(Date.new(2001, 2, 3)) + assert_nil @filters.h(nil) + end + + def test_escape_once + assert_equal '<strong>Hulk</strong>', @filters.escape_once('<strong>Hulk') + end + + def test_url_encode + assert_equal 'foo%2B1%40example.com', @filters.url_encode('foo+1@example.com') + assert_equal '1', @filters.url_encode(1) + assert_equal '2001-02-03', @filters.url_encode(Date.new(2001, 2, 3)) + assert_nil @filters.url_encode(nil) + end + + def test_url_decode + assert_equal 'foo bar', @filters.url_decode('foo+bar') + assert_equal 'foo bar', @filters.url_decode('foo%20bar') + assert_equal 'foo+1@example.com', @filters.url_decode('foo%2B1%40example.com') + assert_equal '1', @filters.url_decode(1) + assert_equal '2001-02-03', @filters.url_decode(Date.new(2001, 2, 3)) + assert_nil @filters.url_decode(nil) + exception = assert_raises Liquid::ArgumentError do + @filters.url_decode('%ff') + end + assert_equal 'Liquid error: invalid byte sequence in UTF-8', exception.message + end + + def test_truncatewords + assert_equal 'one two three', @filters.truncatewords('one two three', 4) + assert_equal 'one two...', @filters.truncatewords('one two three', 2) + assert_equal 'one two three', @filters.truncatewords('one two three') + assert_equal 'Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13”...', @filters.truncatewords('Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13” x 16” x 10.5” high) with cover.', 15) + assert_equal "测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5) + assert_equal 'one two1', @filters.truncatewords("one two three", 2, 1) + end + + def test_strip_html + assert_equal 'test', @filters.strip_html("
test
") + assert_equal 'test', @filters.strip_html("
test
") + assert_equal '', @filters.strip_html("") + assert_equal '', @filters.strip_html("") + assert_equal 'test', @filters.strip_html("test
") + assert_equal 'test', @filters.strip_html("test") + assert_equal '', @filters.strip_html(nil) + + # Quirk of the existing implementation + assert_equal 'foo;', @filters.strip_html("<<") + end + + def test_join + assert_equal '1 2 3 4', @filters.join([1, 2, 3, 4]) + assert_equal '1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - ') + assert_equal '1121314', @filters.join([1, 2, 3, 4], 1) + end + + def test_sort + assert_equal [1, 2, 3, 4], @filters.sort([4, 3, 2, 1]) + assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a") + end + + def test_sort_with_nils + assert_equal [1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1]) + assert_equal [{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a") + end + + def test_sort_when_property_is_sometimes_missing_puts_nils_last + input = [ + { "price" => 4, "handle" => "alpha" }, + { "handle" => "beta" }, + { "price" => 1, "handle" => "gamma" }, + { "handle" => "delta" }, + { "price" => 2, "handle" => "epsilon" } + ] + expectation = [ + { "price" => 1, "handle" => "gamma" }, + { "price" => 2, "handle" => "epsilon" }, + { "price" => 4, "handle" => "alpha" }, + { "handle" => "delta" }, + { "handle" => "beta" } + ] + assert_equal expectation, @filters.sort(input, "price") + end + + def test_sort_natural + assert_equal ["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"]) + assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a") + end + + def test_sort_natural_with_nils + assert_equal ["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"]) + assert_equal [{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a") + end + + def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last + input = [ + { "price" => "4", "handle" => "alpha" }, + { "handle" => "beta" }, + { "price" => "1", "handle" => "gamma" }, + { "handle" => "delta" }, + { "price" => 2, "handle" => "epsilon" } + ] + expectation = [ + { "price" => "1", "handle" => "gamma" }, + { "price" => 2, "handle" => "epsilon" }, + { "price" => "4", "handle" => "alpha" }, + { "handle" => "delta" }, + { "handle" => "beta" } + ] + assert_equal expectation, @filters.sort_natural(input, "price") + end + + def test_sort_natural_case_check + input = [ + { "key" => "X" }, + { "key" => "Y" }, + { "key" => "Z" }, + { "fake" => "t" }, + { "key" => "a" }, + { "key" => "b" }, + { "key" => "c" } + ] + expectation = [ + { "key" => "a" }, + { "key" => "b" }, + { "key" => "c" }, + { "key" => "X" }, + { "key" => "Y" }, + { "key" => "Z" }, + { "fake" => "t" } + ] + assert_equal expectation, @filters.sort_natural(input, "key") + assert_equal ["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"]) + end + + def test_sort_empty_array + assert_equal [], @filters.sort([], "a") + end + + def test_sort_invalid_property + foo = [ + [1], + [2], + [3] + ] + + assert_raises Liquid::ArgumentError do + @filters.sort(foo, "bar") + end + end + + def test_sort_natural_empty_array + assert_equal [], @filters.sort_natural([], "a") + end + + def test_sort_natural_invalid_property + foo = [ + [1], + [2], + [3] + ] + + assert_raises Liquid::ArgumentError do + @filters.sort_natural(foo, "bar") + end + end + + def test_legacy_sort_hash + assert_equal [{ a: 1, b: 2 }], @filters.sort({ a: 1, b: 2 }) + end + + def test_numerical_vs_lexicographical_sort + assert_equal [2, 10], @filters.sort([10, 2]) + assert_equal [{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a") + assert_equal ["10", "2"], @filters.sort(["10", "2"]) + assert_equal [{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a") + end + + def test_uniq + assert_equal ["foo"], @filters.uniq("foo") + assert_equal [1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1]) + assert_equal [{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a") + testdrop = TestDrop.new + assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test') + end + + def test_uniq_empty_array + assert_equal [], @filters.uniq([], "a") + end + + def test_uniq_invalid_property + foo = [ + [1], + [2], + [3] + ] + + assert_raises Liquid::ArgumentError do + @filters.uniq(foo, "bar") + end + end + + def test_compact_empty_array + assert_equal [], @filters.compact([], "a") + end + + def test_compact_invalid_property + foo = [ + [1], + [2], + [3] + ] + + assert_raises Liquid::ArgumentError do + @filters.compact(foo, "bar") + end + end + + def test_reverse + assert_equal [4, 3, 2, 1], @filters.reverse([1, 2, 3, 4]) + end + + def test_legacy_reverse_hash + assert_equal [{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2) + end + + def test_map + assert_equal [1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a') + assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}", + 'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }] + end + + def test_map_doesnt_call_arbitrary_stuff + assert_template_result "", '{{ "foo" | map: "__id__" }}' + assert_template_result "", '{{ "foo" | map: "inspect" }}' + end + + def test_map_calls_to_liquid + t = TestThing.new + assert_template_result "woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t] + end + + def test_map_on_hashes + assert_template_result "4217", '{{ thing | map: "foo" | map: "bar" }}', + "thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] } + end + + def test_legacy_map_on_hashes_with_dynamic_key + template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}" + hash = { "foo" => { "bar" => 42 } } + assert_template_result "42", template, "thing" => hash + end + + def test_sort_calls_to_liquid + t = TestThing.new + Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t]) + assert t.foo > 0 + end + + def test_map_over_proc + drop = TestDrop.new + p = proc{ drop } + templ = '{{ procs | map: "test" }}' + assert_template_result "testfoo", templ, "procs" => [p] + end + + def test_map_over_drops_returning_procs + drops = [ + { + "proc" => ->{ "foo" }, + }, + { + "proc" => ->{ "bar" }, + }, + ] + templ = '{{ drops | map: "proc" }}' + assert_template_result "foobar", templ, "drops" => drops + end + + def test_map_works_on_enumerables + assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new + end + + def test_map_returns_empty_on_2d_input_array + foo = [ + [1], + [2], + [3] + ] + + assert_raises Liquid::ArgumentError do + @filters.map(foo, "bar") + end + end + + def test_map_returns_empty_with_no_property + foo = [ + [1], + [2], + [3] + ] + assert_raises Liquid::ArgumentError do + @filters.map(foo, nil) + end + end + + def test_sort_works_on_enumerables + assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new + end + + def test_first_and_last_call_to_liquid + assert_template_result 'foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new] + assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new] + end + + def test_truncate_calls_to_liquid + assert_template_result "wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new + end + + def test_date + assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B") + assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B") + assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B") + + assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B") + assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B") + assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B") + + assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") + assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") + assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "") + assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil) + + assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y") + + assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y") + assert_equal Date.today.year.to_s, @filters.date('now', '%Y') + assert_equal Date.today.year.to_s, @filters.date('today', '%Y') + assert_equal Date.today.year.to_s, @filters.date('Today', '%Y') + + assert_nil @filters.date(nil, "%B") + + assert_equal '', @filters.date('', "%B") + + with_timezone("UTC") do + assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y") + assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y") + end + end + + def test_first_last + assert_equal 1, @filters.first([1, 2, 3]) + assert_equal 3, @filters.last([1, 2, 3]) + assert_nil @filters.first([]) + assert_nil @filters.last([]) + end + + def test_replace + assert_equal '2 2 2 2', @filters.replace('1 1 1 1', '1', 2) + assert_equal '2 2 2 2', @filters.replace('1 1 1 1', 1, 2) + assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2) + assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2) + assert_template_result '2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}" + end + + def test_remove + assert_equal ' ', @filters.remove("a a a a", 'a') + assert_equal ' ', @filters.remove("1 1 1 1", 1) + assert_equal 'a a a', @filters.remove_first("a a a a", 'a ') + assert_equal ' 1 1 1', @filters.remove_first("1 1 1 1", 1) + assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}" + end + + def test_pipes_in_string_arguments + assert_template_result 'foobar', "{{ 'foo|bar' | remove: '|' }}" + end + + def test_strip + assert_template_result 'ab c', "{{ source | strip }}", 'source' => " ab c " + assert_template_result 'ab c', "{{ source | strip }}", 'source' => " \tab c \n \t" + end + + def test_lstrip + assert_template_result 'ab c ', "{{ source | lstrip }}", 'source' => " ab c " + assert_template_result "ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t" + end + + def test_rstrip + assert_template_result " ab c", "{{ source | rstrip }}", 'source' => " ab c " + assert_template_result " \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t" + end + + def test_strip_newlines + assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc" + assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc" + end + + def test_newlines_to_br + assert_template_result "a
\nb
\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc" + end + + def test_plus + assert_template_result "2", "{{ 1 | plus:1 }}" + assert_template_result "2.0", "{{ '1' | plus:'1.0' }}" + + assert_template_result "5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3) + end + + def test_minus + assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1 + assert_template_result "2.3", "{{ '4.3' | minus:'2' }}" + + assert_template_result "5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7) + end + + def test_abs + assert_template_result "17", "{{ 17 | abs }}" + assert_template_result "17", "{{ -17 | abs }}" + assert_template_result "17", "{{ '17' | abs }}" + assert_template_result "17", "{{ '-17' | abs }}" + assert_template_result "0", "{{ 0 | abs }}" + assert_template_result "0", "{{ '0' | abs }}" + assert_template_result "17.42", "{{ 17.42 | abs }}" + assert_template_result "17.42", "{{ -17.42 | abs }}" + assert_template_result "17.42", "{{ '17.42' | abs }}" + assert_template_result "17.42", "{{ '-17.42' | abs }}" + end + + def test_times + assert_template_result "12", "{{ 3 | times:4 }}" + assert_template_result "0", "{{ 'foo' | times:4 }}" + assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}" + assert_template_result "7.25", "{{ 0.0725 | times:100 }}" + assert_template_result "-7.25", '{{ "-0.0725" | times:100 }}' + assert_template_result "7.25", '{{ "-0.0725" | times: -100 }}' + assert_template_result "4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2) + end + + def test_divided_by + assert_template_result "4", "{{ 12 | divided_by:3 }}" + assert_template_result "4", "{{ 14 | divided_by:3 }}" + + assert_template_result "5", "{{ 15 | divided_by:3 }}" + assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render + + assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}" + assert_raises(Liquid::ZeroDivisionError) do + assert_template_result "4", "{{ 1 | modulo: 0 }}" + end + + assert_template_result "5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10) + end + + def test_modulo + assert_template_result "1", "{{ 3 | modulo:2 }}" + assert_raises(Liquid::ZeroDivisionError) do + assert_template_result "4", "{{ 1 | modulo: 0 }}" + end + + assert_template_result "1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3) + end + + def test_round + assert_template_result "5", "{{ input | round }}", 'input' => 4.6 + assert_template_result "4", "{{ '4.3' | round }}" + assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612 + assert_raises(Liquid::FloatDomainError) do + assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | round }}" + end + + assert_template_result "5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6) + assert_template_result "4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3) + end + + def test_ceil + assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6 + assert_template_result "5", "{{ '4.3' | ceil }}" + assert_raises(Liquid::FloatDomainError) do + assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | ceil }}" + end + + assert_template_result "5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6) + end + + def test_floor + assert_template_result "4", "{{ input | floor }}", 'input' => 4.6 + assert_template_result "4", "{{ '4.3' | floor }}" + assert_raises(Liquid::FloatDomainError) do + assert_template_result "4", "{{ 1.0 | divided_by: 0.0 | floor }}" + end + + assert_template_result "5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4) + end + + def test_at_most + assert_template_result "4", "{{ 5 | at_most:4 }}" + assert_template_result "5", "{{ 5 | at_most:5 }}" + assert_template_result "5", "{{ 5 | at_most:6 }}" + + assert_template_result "4.5", "{{ 4.5 | at_most:5 }}" + assert_template_result "5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6) + assert_template_result "4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4) + assert_template_result "4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4) + end + + def test_at_least + assert_template_result "5", "{{ 5 | at_least:4 }}" + assert_template_result "5", "{{ 5 | at_least:5 }}" + assert_template_result "6", "{{ 5 | at_least:6 }}" + + assert_template_result "5", "{{ 4.5 | at_least:5 }}" + assert_template_result "6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6) + assert_template_result "5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4) + assert_template_result "6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6) + end + + def test_append + assigns = { 'a' => 'bc', 'b' => 'd' } + assert_template_result('bcd', "{{ a | append: 'd'}}", assigns) + assert_template_result('bcd', "{{ a | append: b}}", assigns) + end + + def test_concat + assert_equal [1, 2, 3, 4], @filters.concat([1, 2], [3, 4]) + assert_equal [1, 2, 'a'], @filters.concat([1, 2], ['a']) + assert_equal [1, 2, 10], @filters.concat([1, 2], [10]) + + assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do + @filters.concat([1, 2], 10) + end + end + + def test_prepend + assigns = { 'a' => 'bc', 'b' => 'a' } + assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns) + assert_template_result('abc', "{{ a | prepend: b}}", assigns) + end + + def test_default + assert_equal "foo", @filters.default("foo", "bar") + assert_equal "bar", @filters.default(nil, "bar") + assert_equal "bar", @filters.default("", "bar") + assert_equal "bar", @filters.default(false, "bar") + assert_equal "bar", @filters.default([], "bar") + assert_equal "bar", @filters.default({}, "bar") + end + + def test_cannot_access_private_methods + assert_template_result('a', "{{ 'a' | to_number }}") + end + + def test_date_raises_nothing + assert_template_result('', "{{ '' | date: '%D' }}") + assert_template_result('abc', "{{ 'abc' | date: '%D' }}") + end + + def test_where + input = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "beta", "ok" => false }, + { "handle" => "gamma", "ok" => false }, + { "handle" => "delta", "ok" => true } + ] + + expectation = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "delta", "ok" => true } + ] + + assert_equal expectation, @filters.where(input, "ok", true) + assert_equal expectation, @filters.where(input, "ok") + end + + def test_where_no_key_set + input = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "beta" }, + { "handle" => "gamma" }, + { "handle" => "delta", "ok" => true } + ] + + expectation = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "delta", "ok" => true } + ] + + assert_equal expectation, @filters.where(input, "ok", true) + assert_equal expectation, @filters.where(input, "ok") + end + + def test_where_non_array_map_input + assert_equal [{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok") + assert_equal [], @filters.where({ "a" => "not ok" }, "a", "ok") + end + + def test_where_indexable_but_non_map_value + assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) } + assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") } + end + + def test_where_non_boolean_value + input = [ + { "message" => "Bonjour!", "language" => "French" }, + { "message" => "Hello!", "language" => "English" }, + { "message" => "Hallo!", "language" => "German" } + ] + + assert_equal [{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French") + assert_equal [{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German") + assert_equal [{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English") + end + + def test_where_array_of_only_unindexable_values + assert_nil @filters.where([nil], "ok", true) + assert_nil @filters.where([nil], "ok") + end + + def test_where_no_target_value + input = [ + { "foo" => false }, + { "foo" => true }, + { "foo" => "for sure" }, + { "bar" => true } + ] + + assert_equal [{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo") + end + + private + + def with_timezone(tz) + old_tz = ENV['TZ'] + ENV['TZ'] = tz + yield + ensure + ENV['TZ'] = old_tz + end +end # StandardFiltersTest diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/break_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/break_tag_test.rb new file mode 100644 index 00000000..0fbde837 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/break_tag_test.rb @@ -0,0 +1,15 @@ +require 'test_helper' + +class BreakTagTest < Minitest::Test + include Liquid + + # tests that no weird errors are raised if break is called outside of a + # block + def test_break_with_no_block + assigns = { 'i' => 1 } + markup = '{% break %}' + expected = '' + + assert_template_result(expected, markup, assigns) + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/continue_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/continue_tag_test.rb new file mode 100644 index 00000000..ce4c158b --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/continue_tag_test.rb @@ -0,0 +1,15 @@ +require 'test_helper' + +class ContinueTagTest < Minitest::Test + include Liquid + + # tests that no weird errors are raised if continue is called outside of a + # block + def test_continue_with_no_block + assigns = {} + markup = '{% continue %}' + expected = '' + + assert_template_result(expected, markup, assigns) + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/for_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/for_tag_test.rb new file mode 100644 index 00000000..cb7a822d --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/for_tag_test.rb @@ -0,0 +1,410 @@ +require 'test_helper' + +class ThingWithValue < Liquid::Drop + def value + 3 + end +end + +class ForTagTest < Minitest::Test + include Liquid + + def test_for + assert_template_result(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1, 2, 3, 4]) + assert_template_result('yoyo', '{%for item in array%}yo{%endfor%}', 'array' => [1, 2]) + assert_template_result(' yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1]) + assert_template_result('', '{%for item in array%}{%endfor%}', 'array' => [1, 2]) + expected = < [1, 2, 3]) + end + + def test_for_reversed + assigns = { 'array' => [ 1, 2, 3] } + assert_template_result('321', '{%for item in array reversed %}{{item}}{%endfor%}', assigns) + end + + def test_for_with_range + assert_template_result(' 1 2 3 ', '{%for item in (1..3) %} {{item}} {%endfor%}') + + assert_raises(Liquid::ArgumentError) do + Template.parse('{% for i in (a..2) %}{% endfor %}').render!("a" => [1, 2]) + end + + assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', "a" => "invalid integer") + end + + def test_for_with_variable_range + assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3) + end + + def test_for_with_hash_value_range + foobar = { "value" => 3 } + assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar) + end + + def test_for_with_drop_value_range + foobar = ThingWithValue.new + assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar) + end + + def test_for_with_variable + assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3]) + assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3]) + assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3]) + assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', 'b', 'c', 'd']) + assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c']) + assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c']) + end + + def test_for_helpers + assigns = { 'array' => [1, 2, 3] } + assert_template_result(' 1/3 2/3 3/3 ', + '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}', + assigns) + assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns) + assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns) + assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns) + assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns) + assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns) + assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns) + end + + def test_for_and_if + assigns = { 'array' => [1, 2, 3] } + assert_template_result('+--', + '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}', + assigns) + end + + def test_for_else + assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [1, 2, 3]) + assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => []) + assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => nil) + end + + def test_limiting + assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } + assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns) + assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns) + assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns) + assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns) + end + + def test_dynamic_variable_limiting + assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } + assigns['limit'] = 2 + assigns['offset'] = 2 + + assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns) + end + + def test_nested_for + assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] } + assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns) + end + + def test_offset_only + assigns = { 'array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } + assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns) + end + + def test_pause_resume + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } } + markup = <<-MKUP + {%for i in array.items limit: 3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%} + MKUP + expected = <<-XPCTD + 123 + next + 456 + next + 789 + XPCTD + assert_template_result(expected, markup, assigns) + end + + def test_pause_resume_limit + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } } + markup = <<-MKUP + {%for i in array.items limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%} + MKUP + expected = <<-XPCTD + 123 + next + 456 + next + 7 + XPCTD + assert_template_result(expected, markup, assigns) + end + + def test_pause_resume_big_limit + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } } + markup = <<-MKUP + {%for i in array.items limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%} + MKUP + expected = <<-XPCTD + 123 + next + 456 + next + 7890 + XPCTD + assert_template_result(expected, markup, assigns) + end + + def test_pause_resume_big_offset + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } } + markup = '{%for i in array.items limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%} + next + {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%}' + expected = '123 + next + 456 + next + ' + assert_template_result(expected, markup, assigns) + end + + def test_for_with_break + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } } + + markup = '{% for i in array.items %}{% break %}{% endfor %}' + expected = "" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{{ i }}{% break %}{% endfor %}' + expected = "1" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{% break %}{{ i }}{% endfor %}' + expected = "" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}' + expected = "1234" + assert_template_result(expected, markup, assigns) + + # tests to ensure it only breaks out of the local for loop + # and not all of them. + assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] } + markup = '{% for item in array %}' \ + '{% for i in item %}' \ + '{% if i == 1 %}' \ + '{% break %}' \ + '{% endif %}' \ + '{{ i }}' \ + '{% endfor %}' \ + '{% endfor %}' + expected = '3456' + assert_template_result(expected, markup, assigns) + + # test break does nothing when unreached + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } } + markup = '{% for i in array.items %}{% if i == 9999 %}{% break %}{% endif %}{{ i }}{% endfor %}' + expected = '12345' + assert_template_result(expected, markup, assigns) + end + + def test_for_with_continue + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } } + + markup = '{% for i in array.items %}{% continue %}{% endfor %}' + expected = "" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{{ i }}{% continue %}{% endfor %}' + expected = "12345" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{% continue %}{{ i }}{% endfor %}' + expected = "" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}' + expected = "123" + assert_template_result(expected, markup, assigns) + + markup = '{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}' + expected = "1245" + assert_template_result(expected, markup, assigns) + + # tests to ensure it only continues the local for loop and not all of them. + assigns = { 'array' => [[1, 2], [3, 4], [5, 6]] } + markup = '{% for item in array %}' \ + '{% for i in item %}' \ + '{% if i == 1 %}' \ + '{% continue %}' \ + '{% endif %}' \ + '{{ i }}' \ + '{% endfor %}' \ + '{% endfor %}' + expected = '23456' + assert_template_result(expected, markup, assigns) + + # test continue does nothing when unreached + assigns = { 'array' => { 'items' => [1, 2, 3, 4, 5] } } + markup = '{% for i in array.items %}{% if i == 9999 %}{% continue %}{% endif %}{{ i }}{% endfor %}' + expected = '12345' + assert_template_result(expected, markup, assigns) + end + + def test_for_tag_string + # ruby 1.8.7 "String".each => Enumerator with single "String" element. + # ruby 1.9.3 no longer supports .each on String though we mimic + # the functionality for backwards compatibility + + assert_template_result('test string', + '{%for val in string%}{{val}}{%endfor%}', + 'string' => "test string") + + assert_template_result('test string', + '{%for val in string limit:1%}{{val}}{%endfor%}', + 'string' => "test string") + + assert_template_result('val-string-1-1-0-1-0-true-true-test string', + '{%for val in string%}' \ + '{{forloop.name}}-' \ + '{{forloop.index}}-' \ + '{{forloop.length}}-' \ + '{{forloop.index0}}-' \ + '{{forloop.rindex}}-' \ + '{{forloop.rindex0}}-' \ + '{{forloop.first}}-' \ + '{{forloop.last}}-' \ + '{{val}}{%endfor%}', + 'string' => "test string") + end + + def test_for_parentloop_references_parent_loop + assert_template_result('1.1 1.2 1.3 2.1 2.2 2.3 ', + '{% for inner in outer %}{% for k in inner %}' \ + '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \ + '{% endfor %}{% endfor %}', + 'outer' => [[1, 1, 1], [1, 1, 1]]) + end + + def test_for_parentloop_nil_when_not_present + assert_template_result('.1 .2 ', + '{% for inner in outer %}' \ + '{{ forloop.parentloop.index }}.{{ forloop.index }} ' \ + '{% endfor %}', + 'outer' => [[1, 1, 1], [1, 1, 1]]) + end + + def test_inner_for_over_empty_input + assert_template_result 'oo', '{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}' + end + + def test_blank_string_not_iterable + assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '') + end + + def test_bad_variable_naming_in_for_loop + assert_raises(Liquid::SyntaxError) do + Liquid::Template.parse('{% for a/b in x %}{% endfor %}') + end + end + + def test_spacing_with_variable_naming_in_for_loop + expected = '12345' + template = '{% for item in items %}{{item}}{% endfor %}' + assigns = { 'items' => [1, 2, 3, 4, 5] } + assert_template_result(expected, template, assigns) + end + + class LoaderDrop < Liquid::Drop + attr_accessor :each_called, :load_slice_called + + def initialize(data) + @data = data + end + + def each + @each_called = true + @data.each { |el| yield el } + end + + def load_slice(from, to) + @load_slice_called = true + @data[(from..to - 1)] + end + end + + def test_iterate_with_each_when_no_limit_applied + loader = LoaderDrop.new([1, 2, 3, 4, 5]) + assigns = { 'items' => loader } + expected = '12345' + template = '{% for item in items %}{{item}}{% endfor %}' + assert_template_result(expected, template, assigns) + assert loader.each_called + assert !loader.load_slice_called + end + + def test_iterate_with_load_slice_when_limit_applied + loader = LoaderDrop.new([1, 2, 3, 4, 5]) + assigns = { 'items' => loader } + expected = '1' + template = '{% for item in items limit:1 %}{{item}}{% endfor %}' + assert_template_result(expected, template, assigns) + assert !loader.each_called + assert loader.load_slice_called + end + + def test_iterate_with_load_slice_when_limit_and_offset_applied + loader = LoaderDrop.new([1, 2, 3, 4, 5]) + assigns = { 'items' => loader } + expected = '34' + template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}' + assert_template_result(expected, template, assigns) + assert !loader.each_called + assert loader.load_slice_called + end + + def test_iterate_with_load_slice_returns_same_results_as_without + loader = LoaderDrop.new([1, 2, 3, 4, 5]) + loader_assigns = { 'items' => loader } + array_assigns = { 'items' => [1, 2, 3, 4, 5] } + expected = '34' + template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}' + assert_template_result(expected, template, loader_assigns) + assert_template_result(expected, template, array_assigns) + end + + def test_for_cleans_up_registers + context = Context.new(ErrorDrop.new) + + assert_raises(StandardError) do + Liquid::Template.parse('{% for i in (1..2) %}{{ standard_error }}{% endfor %}').render!(context) + end + + assert context.registers[:for_stack].empty? + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/if_else_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/if_else_tag_test.rb new file mode 100644 index 00000000..45a5d3ac --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/if_else_tag_test.rb @@ -0,0 +1,188 @@ +require 'test_helper' + +class IfElseTagTest < Minitest::Test + include Liquid + + def test_if + assert_template_result(' ', ' {% if false %} this text should not go into the output {% endif %} ') + assert_template_result(' this text should go into the output ', + ' {% if true %} this text should go into the output {% endif %} ') + assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?') + end + + def test_literal_comparisons + assert_template_result(' NO ', '{% assign v = false %}{% if v %} YES {% else %} NO {% endif %}') + assert_template_result(' YES ', '{% assign v = nil %}{% if v == nil %} YES {% else %} NO {% endif %}') + end + + def test_if_else + assert_template_result(' YES ', '{% if false %} NO {% else %} YES {% endif %}') + assert_template_result(' YES ', '{% if true %} YES {% else %} NO {% endif %}') + assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}') + end + + def test_if_boolean + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true) + end + + def test_if_or + assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true) + assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false) + assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true) + assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false) + + assert_template_result(' YES ', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true) + assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false) + end + + def test_if_or_with_operators + assert_template_result(' YES ', '{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true) + assert_template_result(' YES ', '{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true) + assert_template_result('', '{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true) + end + + def test_comparison_of_strings_containing_and_or_or + awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar" + assigns = { 'a' => 'and', 'b' => 'or', 'c' => 'foo and bar', 'd' => 'bar or baz', 'e' => 'foo', 'foo' => true, 'bar' => true } + assert_template_result(' YES ', "{% if #{awful_markup} %} YES {% endif %}", assigns) + end + + def test_comparison_of_expressions_starting_with_and_or_or + assigns = { 'order' => { 'items_count' => 0 }, 'android' => { 'name' => 'Roy' } } + assert_template_result("YES", + "{% if android.name == 'Roy' %}YES{% endif %}", + assigns) + assert_template_result("YES", + "{% if order.items_count == 0 %}YES{% endif %}", + assigns) + end + + def test_if_and + assert_template_result(' YES ', '{% if true and true %} YES {% endif %}') + assert_template_result('', '{% if false and true %} YES {% endif %}') + assert_template_result('', '{% if false and true %} YES {% endif %}') + end + + def test_hash_miss_generates_false + assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {}) + end + + def test_if_from_variable + assert_template_result('', '{% if var %} NO {% endif %}', 'var' => false) + assert_template_result('', '{% if var %} NO {% endif %}', 'var' => nil) + assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => { 'bar' => false }) + assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {}) + assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => nil) + assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => true) + + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => "text") + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true) + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 1) + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => {}) + assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => []) + assert_template_result(' YES ', '{% if "foo" %} YES {% endif %}') + assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => true }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => "text" }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 1 }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => {} }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => [] }) + + assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => false) + assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => nil) + assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', 'var' => true) + assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text") + + assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'bar' => false }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => true }) + assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => "text" }) + assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'notbar' => true }) + assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {}) + assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => { 'bar' => true }) + end + + def test_nested_if + assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}') + assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}') + assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}') + assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}') + + assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}') + assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}') + assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}') + end + + def test_comparisons_on_null + assert_template_result('', '{% if null < 10 %} NO {% endif %}') + assert_template_result('', '{% if null <= 10 %} NO {% endif %}') + assert_template_result('', '{% if null >= 10 %} NO {% endif %}') + assert_template_result('', '{% if null > 10 %} NO {% endif %}') + + assert_template_result('', '{% if 10 < null %} NO {% endif %}') + assert_template_result('', '{% if 10 <= null %} NO {% endif %}') + assert_template_result('', '{% if 10 >= null %} NO {% endif %}') + assert_template_result('', '{% if 10 > null %} NO {% endif %}') + end + + def test_else_if + assert_template_result('0', '{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}') + assert_template_result('1', '{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}') + assert_template_result('2', '{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}') + + assert_template_result('elsif', '{% if false %}if{% elsif true %}elsif{% endif %}') + end + + def test_syntax_error_no_variable + assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}') } + end + + def test_syntax_error_no_expression + assert_raises(SyntaxError) { assert_template_result('', '{% if %}') } + end + + def test_if_with_custom_condition + original_op = Condition.operators['contains'] + Condition.operators['contains'] = :[] + + assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %})) + assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %})) + ensure + Condition.operators['contains'] = original_op + end + + def test_operators_are_ignored_unless_isolated + original_op = Condition.operators['contains'] + Condition.operators['contains'] = :[] + + assert_template_result('yes', + %({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %})) + ensure + Condition.operators['contains'] = original_op + end + + def test_operators_are_whitelisted + assert_raises(SyntaxError) do + assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %})) + end + end + + def test_multiple_conditions + tpl = "{% if a or b and c %}true{% else %}false{% endif %}" + + tests = { + [true, true, true] => true, + [true, true, false] => true, + [true, false, true] => true, + [true, false, false] => true, + [false, true, true] => true, + [false, true, false] => false, + [false, false, true] => false, + [false, false, false] => false, + } + + tests.each do |vals, expected| + a, b, c = vals + assigns = { 'a' => a, 'b' => b, 'c' => c } + assert_template_result expected.to_s, tpl, assigns, assigns.to_s + end + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/include_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/include_tag_test.rb new file mode 100644 index 00000000..9c188d57 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/include_tag_test.rb @@ -0,0 +1,253 @@ +require 'test_helper' + +class TestFileSystem + def read_template_file(template_path) + case template_path + when "product" + "Product: {{ product.title }} " + + when "locale_variables" + "Locale: {{echo1}} {{echo2}}" + + when "variant" + "Variant: {{ variant.title }}" + + when "nested_template" + "{% include 'header' %} {% include 'body' %} {% include 'footer' %}" + + when "body" + "body {% include 'body_detail' %}" + + when "nested_product_template" + "Product: {{ nested_product_template.title }} {%include 'details'%} " + + when "recursively_nested_template" + "-{% include 'recursively_nested_template' %}" + + when "pick_a_source" + "from TestFileSystem" + + when 'assignments' + "{% assign foo = 'bar' %}" + + when 'break' + "{% break %}" + + else + template_path + end + end +end + +class OtherFileSystem + def read_template_file(template_path) + 'from OtherFileSystem' + end +end + +class CountingFileSystem + attr_reader :count + def read_template_file(template_path) + @count ||= 0 + @count += 1 + 'from CountingFileSystem' + end +end + +class CustomInclude < Liquid::Tag + Syntax = /(#{Liquid::QuotedFragment}+)(\s+(?:with|for)\s+(#{Liquid::QuotedFragment}+))?/o + + def initialize(tag_name, markup, tokens) + markup =~ Syntax + @template_name = $1 + super + end + + def parse(tokens) + end + + def render(context) + @template_name[1..-2] + end +end + +class IncludeTagTest < Minitest::Test + include Liquid + + def setup + Liquid::Template.file_system = TestFileSystem.new + end + + def test_include_tag_looks_for_file_system_in_registers_first + assert_equal 'from OtherFileSystem', + Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: OtherFileSystem.new }) + end + + def test_include_tag_with + assert_template_result "Product: Draft 151cm ", + "{% include 'product' with products[0] %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ] + end + + def test_include_tag_with_default_name + assert_template_result "Product: Draft 151cm ", + "{% include 'product' %}", "product" => { 'title' => 'Draft 151cm' } + end + + def test_include_tag_for + assert_template_result "Product: Draft 151cm Product: Element 155cm ", + "{% include 'product' for products %}", "products" => [ { 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' } ] + end + + def test_include_tag_with_local_variables + assert_template_result "Locale: test123 ", "{% include 'locale_variables' echo1: 'test123' %}" + end + + def test_include_tag_with_multiple_local_variables + assert_template_result "Locale: test123 test321", + "{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}" + end + + def test_include_tag_with_multiple_local_variables_from_context + assert_template_result "Locale: test123 test321", + "{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}", + 'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' } + end + + def test_included_templates_assigns_variables + assert_template_result "bar", "{% include 'assignments' %}{{ foo }}" + end + + def test_nested_include_tag + assert_template_result "body body_detail", "{% include 'body' %}" + + assert_template_result "header body body_detail footer", "{% include 'nested_template' %}" + end + + def test_nested_include_with_variable + assert_template_result "Product: Draft 151cm details ", + "{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' } + + assert_template_result "Product: Draft 151cm details Product: Element 155cm details ", + "{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }] + end + + def test_recursively_included_template_does_not_produce_endless_loop + infinite_file_system = Class.new do + def read_template_file(template_path) + "-{% include 'loop' %}" + end + end + + Liquid::Template.file_system = infinite_file_system.new + + assert_raises(Liquid::StackLevelError) do + Template.parse("{% include 'loop' %}").render! + end + end + + def test_dynamically_choosen_template + assert_template_result "Test123", "{% include template %}", "template" => 'Test123' + assert_template_result "Test321", "{% include template %}", "template" => 'Test321' + + assert_template_result "Product: Draft 151cm ", "{% include template for product %}", + "template" => 'product', 'product' => { 'title' => 'Draft 151cm' } + end + + def test_include_tag_caches_second_read_of_same_partial + file_system = CountingFileSystem.new + assert_equal 'from CountingFileSystemfrom CountingFileSystem', + Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system }) + assert_equal 1, file_system.count + end + + def test_include_tag_doesnt_cache_partials_across_renders + file_system = CountingFileSystem.new + assert_equal 'from CountingFileSystem', + Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system }) + assert_equal 1, file_system.count + + assert_equal 'from CountingFileSystem', + Template.parse("{% include 'pick_a_source' %}").render!({}, registers: { file_system: file_system }) + assert_equal 2, file_system.count + end + + def test_include_tag_within_if_statement + assert_template_result "foo_if_true", "{% if true %}{% include 'foo_if_true' %}{% endif %}" + end + + def test_custom_include_tag + original_tag = Liquid::Template.tags['include'] + Liquid::Template.tags['include'] = CustomInclude + begin + assert_equal "custom_foo", + Template.parse("{% include 'custom_foo' %}").render! + ensure + Liquid::Template.tags['include'] = original_tag + end + end + + def test_custom_include_tag_within_if_statement + original_tag = Liquid::Template.tags['include'] + Liquid::Template.tags['include'] = CustomInclude + begin + assert_equal "custom_foo_if_true", + Template.parse("{% if true %}{% include 'custom_foo_if_true' %}{% endif %}").render! + ensure + Liquid::Template.tags['include'] = original_tag + end + end + + def test_does_not_add_error_in_strict_mode_for_missing_variable + Liquid::Template.file_system = TestFileSystem.new + + a = Liquid::Template.parse(' {% include "nested_template" %}') + a.render! + assert_empty a.errors + end + + def test_passing_options_to_included_templates + assert_raises(Liquid::SyntaxError) do + Template.parse("{% include template %}", error_mode: :strict).render!("template" => '{{ "X" || downcase }}') + end + with_error_mode(:lax) do + assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: true).render!("template" => '{{ "X" || downcase }}') + end + assert_raises(Liquid::SyntaxError) do + Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:locale]).render!("template" => '{{ "X" || downcase }}') + end + with_error_mode(:lax) do + assert_equal 'x', Template.parse("{% include template %}", error_mode: :strict, include_options_blacklist: [:error_mode]).render!("template" => '{{ "X" || downcase }}') + end + end + + def test_render_raise_argument_error_when_template_is_undefined + assert_raises(Liquid::ArgumentError) do + template = Liquid::Template.parse('{% include undefined_variable %}') + template.render! + end + assert_raises(Liquid::ArgumentError) do + template = Liquid::Template.parse('{% include nil %}') + template.render! + end + end + + def test_including_via_variable_value + assert_template_result "from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}" + + assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' } + + assert_template_result "Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' } + end + + def test_including_with_strict_variables + template = Liquid::Template.parse("{% include 'simple' %}", error_mode: :warn) + template.render(nil, strict_variables: true) + + assert_equal [], template.errors + end + + def test_break_through_include + assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% break %}{{ i }}{% endfor %}" + assert_template_result "1", "{% for i in (1..3) %}{{ i }}{% include 'break' %}{{ i }}{% endfor %}" + end +end # IncludeTagTest diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/increment_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/increment_tag_test.rb new file mode 100644 index 00000000..97c51ac5 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/increment_tag_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class IncrementTagTest < Minitest::Test + include Liquid + + def test_inc + assert_template_result('0', '{%increment port %}', {}) + assert_template_result('0 1', '{%increment port %} {%increment port%}', {}) + assert_template_result('0 0 1 2 1', + '{%increment port %} {%increment starboard%} ' \ + '{%increment port %} {%increment port%} ' \ + '{%increment starboard %}', {}) + end + + def test_dec + assert_template_result('9', '{%decrement port %}', { 'port' => 10 }) + assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {}) + assert_template_result('1 5 2 2 5', + '{%increment port %} {%increment starboard%} ' \ + '{%increment port %} {%decrement port%} ' \ + '{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 }) + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/raw_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/raw_tag_test.rb new file mode 100644 index 00000000..634d052d --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/raw_tag_test.rb @@ -0,0 +1,31 @@ +require 'test_helper' + +class RawTagTest < Minitest::Test + include Liquid + + def test_tag_in_raw + assert_template_result '{% comment %} test {% endcomment %}', + '{% raw %}{% comment %} test {% endcomment %}{% endraw %}' + end + + def test_output_in_raw + assert_template_result '{{ test }}', '{% raw %}{{ test }}{% endraw %}' + end + + def test_open_tag_in_raw + assert_template_result ' Foobar {% invalid ', '{% raw %} Foobar {% invalid {% endraw %}' + assert_template_result ' Foobar invalid %} ', '{% raw %} Foobar invalid %} {% endraw %}' + assert_template_result ' Foobar {{ invalid ', '{% raw %} Foobar {{ invalid {% endraw %}' + assert_template_result ' Foobar invalid }} ', '{% raw %} Foobar invalid }} {% endraw %}' + assert_template_result ' Foobar {% invalid {% {% endraw ', '{% raw %} Foobar {% invalid {% {% endraw {% endraw %}' + assert_template_result ' Foobar {% {% {% ', '{% raw %} Foobar {% {% {% {% endraw %}' + assert_template_result ' test {% raw %} {% endraw %}', '{% raw %} test {% raw %} {% {% endraw %}endraw %}' + assert_template_result ' Foobar {{ invalid 1', '{% raw %} Foobar {{ invalid {% endraw %}{{ 1 }}' + end + + def test_invalid_raw + assert_match_syntax_error(/tag was never closed/, '{% raw %} foo') + assert_match_syntax_error(/Valid syntax/, '{% raw } foo {% endraw %}') + assert_match_syntax_error(/Valid syntax/, '{% raw } foo %}{% endraw %}') + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/standard_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/standard_tag_test.rb new file mode 100644 index 00000000..4b4703a6 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/standard_tag_test.rb @@ -0,0 +1,296 @@ +require 'test_helper' + +class StandardTagTest < Minitest::Test + include Liquid + + def test_no_transform + assert_template_result('this text should come out of the template without change...', + 'this text should come out of the template without change...') + + assert_template_result('blah', 'blah') + assert_template_result('', '') + assert_template_result('|,.:', '|,.:') + assert_template_result('', '') + + text = %(this shouldnt see any transformation either but has multiple lines + as you can clearly see here ...) + assert_template_result(text, text) + end + + def test_has_a_block_which_does_nothing + assert_template_result(%(the comment block should be removed .. right?), + %(the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?)) + + assert_template_result('', '{%comment%}{%endcomment%}') + assert_template_result('', '{%comment%}{% endcomment %}') + assert_template_result('', '{% comment %}{%endcomment%}') + assert_template_result('', '{% comment %}{% endcomment %}') + assert_template_result('', '{%comment%}comment{%endcomment%}') + assert_template_result('', '{% comment %}comment{% endcomment %}') + assert_template_result('', '{% comment %} 1 {% comment %} 2 {% endcomment %} 3 {% endcomment %}') + + assert_template_result('', '{%comment%}{%blabla%}{%endcomment%}') + assert_template_result('', '{% comment %}{% blabla %}{% endcomment %}') + assert_template_result('', '{%comment%}{% endif %}{%endcomment%}') + assert_template_result('', '{% comment %}{% endwhatever %}{% endcomment %}') + assert_template_result('', '{% comment %}{% raw %} {{%%%%}} }} { {% endcomment %} {% comment {% endraw %} {% endcomment %}') + + assert_template_result('foobar', 'foo{%comment%}comment{%endcomment%}bar') + assert_template_result('foobar', 'foo{% comment %}comment{% endcomment %}bar') + assert_template_result('foobar', 'foo{%comment%} comment {%endcomment%}bar') + assert_template_result('foobar', 'foo{% comment %} comment {% endcomment %}bar') + + assert_template_result('foo bar', 'foo {%comment%} {%endcomment%} bar') + assert_template_result('foo bar', 'foo {%comment%}comment{%endcomment%} bar') + assert_template_result('foo bar', 'foo {%comment%} comment {%endcomment%} bar') + + assert_template_result('foobar', 'foo{%comment%} + {%endcomment%}bar') + end + + def test_hyphenated_assign + assigns = { 'a-b' => '1' } + assert_template_result('a-b:1 a-b:2', 'a-b:{{a-b}} {%assign a-b = 2 %}a-b:{{a-b}}', assigns) + end + + def test_assign_with_colon_and_spaces + assigns = { 'var' => { 'a:b c' => { 'paged' => '1' } } } + assert_template_result('var2: 1', '{%assign var2 = var["a:b c"].paged %}var2: {{var2}}', assigns) + end + + def test_capture + assigns = { 'var' => 'content' } + assert_template_result('content foo content foo ', + '{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', + assigns) + end + + def test_capture_detects_bad_syntax + assert_raises(SyntaxError) do + assert_template_result('content foo content foo ', + '{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', + { 'var' => 'content' }) + end + end + + def test_case + assigns = { 'condition' => 2 } + assert_template_result(' its 2 ', + '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', + assigns) + + assigns = { 'condition' => 1 } + assert_template_result(' its 1 ', + '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', + assigns) + + assigns = { 'condition' => 3 } + assert_template_result('', + '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', + assigns) + + assigns = { 'condition' => "string here" } + assert_template_result(' hit ', + '{% case condition %}{% when "string here" %} hit {% endcase %}', + assigns) + + assigns = { 'condition' => "bad string here" } + assert_template_result('', + '{% case condition %}{% when "string here" %} hit {% endcase %}',\ + assigns) + end + + def test_case_with_else + assigns = { 'condition' => 5 } + assert_template_result(' hit ', + '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', + assigns) + + assigns = { 'condition' => 6 } + assert_template_result(' else ', + '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', + assigns) + + assigns = { 'condition' => 6 } + assert_template_result(' else ', + '{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}', + assigns) + end + + def test_case_on_size + assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => []) + assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1]) + assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1]) + assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1]) + assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1]) + assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1]) + end + + def test_case_on_size_with_else + assert_template_result('else', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => []) + + assert_template_result('1', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => [1]) + + assert_template_result('2', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => [1, 1]) + + assert_template_result('else', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => [1, 1, 1]) + + assert_template_result('else', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => [1, 1, 1, 1]) + + assert_template_result('else', + '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', + 'a' => [1, 1, 1, 1, 1]) + end + + def test_case_on_length_with_else + assert_template_result('else', + '{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', + {}) + + assert_template_result('false', + '{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', + {}) + + assert_template_result('true', + '{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', + {}) + + assert_template_result('else', + '{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', + {}) + end + + def test_assign_from_case + # Example from the shopify forums + code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}" + template = Liquid::Template.parse(code) + assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-jackets' }) + assert_equal "menswear", template.render!("collection" => { 'handle' => 'menswear-t-shirts' }) + assert_equal "womenswear", template.render!("collection" => { 'handle' => 'x' }) + assert_equal "womenswear", template.render!("collection" => { 'handle' => 'y' }) + assert_equal "womenswear", template.render!("collection" => { 'handle' => 'z' }) + end + + def test_case_when_or + code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}' + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 }) + assert_template_result(' its 4 ', code, { 'condition' => 4 }) + assert_template_result('', code, { 'condition' => 5 }) + + code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}' + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil }) + assert_template_result('', code, { 'condition' => 'something else' }) + end + + def test_case_when_comma + code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}' + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 }) + assert_template_result(' its 4 ', code, { 'condition' => 4 }) + assert_template_result('', code, { 'condition' => 5 }) + + code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}' + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' }) + assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil }) + assert_template_result('', code, { 'condition' => 'something else' }) + end + + def test_assign + assert_template_result 'variable', '{% assign a = "variable"%}{{a}}' + end + + def test_assign_unassigned + assigns = { 'var' => 'content' } + assert_template_result('var2: var2:content', 'var2:{{var2}} {%assign var2 = var%} var2:{{var2}}', assigns) + end + + def test_assign_an_empty_string + assert_template_result '', '{% assign a = ""%}{{a}}' + end + + def test_assign_is_global + assert_template_result 'variable', '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}' + end + + def test_case_detects_bad_syntax + assert_raises(SyntaxError) do + assert_template_result('', '{% case false %}{% when %}true{% endcase %}', {}) + end + + assert_raises(SyntaxError) do + assert_template_result('', '{% case false %}{% huh %}true{% endcase %}', {}) + end + end + + def test_cycle + assert_template_result('one', '{%cycle "one", "two"%}') + assert_template_result('one two', '{%cycle "one", "two"%} {%cycle "one", "two"%}') + assert_template_result(' two', '{%cycle "", "two"%} {%cycle "", "two"%}') + + assert_template_result('one two one', '{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}') + + assert_template_result('text-align: left text-align: right', + '{%cycle "text-align: left", "text-align: right" %} {%cycle "text-align: left", "text-align: right"%}') + end + + def test_multiple_cycles + assert_template_result('1 2 1 1 2 3 1', + '{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}') + end + + def test_multiple_named_cycles + assert_template_result('one one two two one one', + '{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}') + end + + def test_multiple_named_cycles_with_names_from_context + assigns = { "var1" => 1, "var2" => 2 } + assert_template_result('one one two two one one', + '{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', assigns) + end + + def test_size_of_array + assigns = { "array" => [1, 2, 3, 4] } + assert_template_result('array has 4 elements', "array has {{ array.size }} elements", assigns) + end + + def test_size_of_hash + assigns = { "hash" => { a: 1, b: 2, c: 3, d: 4 } } + assert_template_result('hash has 4 elements', "hash has {{ hash.size }} elements", assigns) + end + + def test_illegal_symbols + assert_template_result('', '{% if true == empty %}?{% endif %}', {}) + assert_template_result('', '{% if true == null %}?{% endif %}', {}) + assert_template_result('', '{% if empty == true %}?{% endif %}', {}) + assert_template_result('', '{% if null == true %}?{% endif %}', {}) + end + + def test_ifchanged + assigns = { 'array' => [ 1, 1, 2, 2, 3, 3] } + assert_template_result('123', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns) + + assigns = { 'array' => [ 1, 1, 1, 1] } + assert_template_result('1', '{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}', assigns) + end + + def test_multiline_tag + assert_template_result '0 1 2 3', "0{%\nfor i in (1..3)\n%} {{\ni\n}}{%\nendfor\n%}" + end +end # StandardTagTest diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/statements_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/statements_test.rb new file mode 100644 index 00000000..eeff166f --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/statements_test.rb @@ -0,0 +1,111 @@ +require 'test_helper' + +class StatementsTest < Minitest::Test + include Liquid + + def test_true_eql_true + text = ' {% if true == true %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text + end + + def test_true_not_eql_true + text = ' {% if true != true %} true {% else %} false {% endif %} ' + assert_template_result ' false ', text + end + + def test_true_lq_true + text = ' {% if 0 > 0 %} true {% else %} false {% endif %} ' + assert_template_result ' false ', text + end + + def test_one_lq_zero + text = ' {% if 1 > 0 %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text + end + + def test_zero_lq_one + text = ' {% if 0 < 1 %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text + end + + def test_zero_lq_or_equal_one + text = ' {% if 0 <= 0 %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text + end + + def test_zero_lq_or_equal_one_involving_nil + text = ' {% if null <= 0 %} true {% else %} false {% endif %} ' + assert_template_result ' false ', text + + text = ' {% if 0 <= null %} true {% else %} false {% endif %} ' + assert_template_result ' false ', text + end + + def test_zero_lqq_or_equal_one + text = ' {% if 0 >= 0 %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text + end + + def test_strings + text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} " + assert_template_result ' true ', text + end + + def test_strings_not_equal + text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} " + assert_template_result ' false ', text + end + + def test_var_strings_equal + text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => 'hello there!' + end + + def test_var_strings_are_not_equal + text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => 'hello there!' + end + + def test_var_and_long_string_are_equal + text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} " + assert_template_result ' true ', text, 'var' => 'hello there!' + end + + def test_var_and_long_string_are_equal_backwards + text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} " + assert_template_result ' true ', text, 'var' => 'hello there!' + end + + # def test_is_nil + # text = %| {% if var != nil %} true {% else %} false {% end %} | + # @template.assigns = { 'var' => 'hello there!'} + # expected = %| true | + # assert_equal expected, @template.parse(text) + # end + + def test_is_collection_empty + text = ' {% if array == empty %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'array' => [] + end + + def test_is_not_collection_empty + text = ' {% if array == empty %} true {% else %} false {% endif %} ' + assert_template_result ' false ', text, 'array' => [1, 2, 3] + end + + def test_nil + text = ' {% if var == nil %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => nil + + text = ' {% if var == null %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => nil + end + + def test_not_nil + text = ' {% if var != nil %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => 1 + + text = ' {% if var != null %} true {% else %} false {% endif %} ' + assert_template_result ' true ', text, 'var' => 1 + end +end # StatementsTest diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/table_row_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/table_row_test.rb new file mode 100644 index 00000000..d7bc14cf --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/table_row_test.rb @@ -0,0 +1,64 @@ +require 'test_helper' + +class TableRowTest < Minitest::Test + include Liquid + + class ArrayDrop < Liquid::Drop + include Enumerable + + def initialize(array) + @array = array + end + + def each(&block) + @array.each(&block) + end + end + + def test_table_row + assert_template_result("\n 1 2 3 \n 4 5 6 \n", + '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}', + 'numbers' => [1, 2, 3, 4, 5, 6]) + + assert_template_result("\n\n", + '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}', + 'numbers' => []) + end + + def test_table_row_with_different_cols + assert_template_result("\n 1 2 3 4 5 \n 6 \n", + '{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}', + 'numbers' => [1, 2, 3, 4, 5, 6]) + end + + def test_table_col_counter + assert_template_result("\n12\n12\n12\n", + '{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}', + 'numbers' => [1, 2, 3, 4, 5, 6]) + end + + def test_quoted_fragment + assert_template_result("\n 1 2 3 \n 4 5 6 \n", + "{% tablerow n in collections.frontpage cols:3%} {{n}} {% endtablerow %}", + 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] }) + assert_template_result("\n 1 2 3 \n 4 5 6 \n", + "{% tablerow n in collections['frontpage'] cols:3%} {{n}} {% endtablerow %}", + 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] }) + end + + def test_enumerable_drop + assert_template_result("\n 1 2 3 \n 4 5 6 \n", + '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}', + 'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6])) + end + + def test_offset_and_limit + assert_template_result("\n 1 2 3 \n 4 5 6 \n", + '{% tablerow n in numbers cols:3 offset:1 limit:6%} {{n}} {% endtablerow %}', + 'numbers' => [0, 1, 2, 3, 4, 5, 6, 7]) + end + + def test_blank_string_not_iterable + assert_template_result("\n\n", "{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}", 'characters' => '') + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/tags/unless_else_tag_test.rb b/bin/gems/liquid-4.0.4/test/integration/tags/unless_else_tag_test.rb new file mode 100644 index 00000000..c414a715 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/tags/unless_else_tag_test.rb @@ -0,0 +1,26 @@ +require 'test_helper' + +class UnlessElseTagTest < Minitest::Test + include Liquid + + def test_unless + assert_template_result(' ', ' {% unless true %} this text should not go into the output {% endunless %} ') + assert_template_result(' this text should go into the output ', + ' {% unless false %} this text should go into the output {% endunless %} ') + assert_template_result(' you rock ?', '{% unless true %} you suck {% endunless %} {% unless false %} you rock {% endunless %}?') + end + + def test_unless_else + assert_template_result(' YES ', '{% unless true %} NO {% else %} YES {% endunless %}') + assert_template_result(' YES ', '{% unless false %} YES {% else %} NO {% endunless %}') + assert_template_result(' YES ', '{% unless "foo" %} NO {% else %} YES {% endunless %}') + end + + def test_unless_in_loop + assert_template_result '23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false] + end + + def test_unless_else_in_loop + assert_template_result ' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false] + end +end # UnlessElseTest diff --git a/bin/gems/liquid-4.0.4/test/integration/template_test.rb b/bin/gems/liquid-4.0.4/test/integration/template_test.rb new file mode 100644 index 00000000..d10e1c5e --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/template_test.rb @@ -0,0 +1,332 @@ +require 'test_helper' +require 'timeout' + +class TemplateContextDrop < Liquid::Drop + def liquid_method_missing(method) + method + end + + def foo + 'fizzbuzz' + end + + def baz + @context.registers['lulz'] + end +end + +class SomethingWithLength < Liquid::Drop + def length + nil + end +end + +class ErroneousDrop < Liquid::Drop + def bad_method + raise 'ruby error in drop' + end +end + +class DropWithUndefinedMethod < Liquid::Drop + def foo + 'foo' + end +end + +class TemplateTest < Minitest::Test + include Liquid + + def test_instance_assigns_persist_on_same_template_object_between_parses + t = Template.new + assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render! + assert_equal 'from instance assigns', t.parse("{{ foo }}").render! + end + + def test_warnings_is_not_exponential_time + str = "false" + 100.times do + str = "{% if true %}true{% else %}#{str}{% endif %}" + end + + t = Template.parse(str) + assert_equal [], Timeout.timeout(1) { t.warnings } + end + + def test_instance_assigns_persist_on_same_template_parsing_between_renders + t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}") + assert_equal 'foo', t.render! + assert_equal 'foofoo', t.render! + end + + def test_custom_assigns_do_not_persist_on_same_template + t = Template.new + assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns') + assert_equal '', t.parse("{{ foo }}").render! + end + + def test_custom_assigns_squash_instance_assigns + t = Template.new + assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render! + assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns') + end + + def test_persistent_assigns_squash_instance_assigns + t = Template.new + assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render! + t.assigns['foo'] = 'from persistent assigns' + assert_equal 'from persistent assigns', t.parse("{{ foo }}").render! + end + + def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders + t = Template.new + t.assigns['number'] = -> { @global ||= 0; @global += 1 } + assert_equal '1', t.parse("{{number}}").render! + assert_equal '1', t.parse("{{number}}").render! + assert_equal '1', t.render! + @global = nil + end + + def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders + t = Template.new + assigns = { 'number' => -> { @global ||= 0; @global += 1 } } + assert_equal '1', t.parse("{{number}}").render!(assigns) + assert_equal '1', t.parse("{{number}}").render!(assigns) + assert_equal '1', t.render!(assigns) + @global = nil + end + + def test_resource_limits_works_with_custom_length_method + t = Template.parse("{% assign foo = bar %}") + t.resource_limits.render_length_limit = 42 + assert_equal "", t.render!("bar" => SomethingWithLength.new) + end + + def test_resource_limits_render_length + t = Template.parse("0123456789") + t.resource_limits.render_length_limit = 5 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + + t.resource_limits.render_length_limit = 10 + assert_equal "0123456789", t.render! + refute_nil t.resource_limits.render_length + end + + def test_resource_limits_render_score + t = Template.parse("{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}") + t.resource_limits.render_score_limit = 50 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + + t = Template.parse("{% for a in (1..100) %} foo {% endfor %}") + t.resource_limits.render_score_limit = 50 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + + t.resource_limits.render_score_limit = 200 + assert_equal (" foo " * 100), t.render! + refute_nil t.resource_limits.render_score + end + + def test_resource_limits_assign_score + t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}") + t.resource_limits.assign_score_limit = 1 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + + t.resource_limits.assign_score_limit = 2 + assert_equal "", t.render! + refute_nil t.resource_limits.assign_score + end + + def test_resource_limits_assign_score_nested + t = Template.parse("{% assign foo = 'aaaa' | reverse %}") + + t.resource_limits.assign_score_limit = 3 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + + t.resource_limits.assign_score_limit = 5 + assert_equal "", t.render! + end + + def test_resource_limits_aborts_rendering_after_first_error + t = Template.parse("{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}") + t.resource_limits.render_score_limit = 50 + assert_equal "Liquid error: Memory limits exceeded", t.render + assert t.resource_limits.reached? + end + + def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set + t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}") + t.render! + assert t.resource_limits.assign_score > 0 + assert t.resource_limits.render_score > 0 + assert t.resource_limits.render_length > 0 + end + + def test_render_length_persists_between_blocks + t = Template.parse("{% if true %}aaaa{% endif %}") + t.resource_limits.render_length_limit = 7 + assert_equal "Liquid error: Memory limits exceeded", t.render + t.resource_limits.render_length_limit = 8 + assert_equal "aaaa", t.render + + t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}") + t.resource_limits.render_length_limit = 13 + assert_equal "Liquid error: Memory limits exceeded", t.render + t.resource_limits.render_length_limit = 14 + assert_equal "aaaabbb", t.render + + t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}") + t.resource_limits.render_length_limit = 5 + assert_equal "Liquid error: Memory limits exceeded", t.render + t.resource_limits.render_length_limit = 11 + assert_equal "Liquid error: Memory limits exceeded", t.render + t.resource_limits.render_length_limit = 12 + assert_equal "ababab", t.render + end + + def test_default_resource_limits_unaffected_by_render_with_context + context = Context.new + t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}") + t.render!(context) + assert context.resource_limits.assign_score > 0 + assert context.resource_limits.render_score > 0 + assert context.resource_limits.render_length > 0 + end + + def test_can_use_drop_as_context + t = Template.new + t.registers['lulz'] = 'haha' + drop = TemplateContextDrop.new + assert_equal 'fizzbuzz', t.parse('{{foo}}').render!(drop) + assert_equal 'bar', t.parse('{{bar}}').render!(drop) + assert_equal 'haha', t.parse("{{baz}}").render!(drop) + end + + def test_render_bang_force_rethrow_errors_on_passed_context + context = Context.new({ 'drop' => ErroneousDrop.new }) + t = Template.new.parse('{{ drop.bad_method }}') + + e = assert_raises RuntimeError do + t.render!(context) + end + assert_equal 'ruby error in drop', e.message + end + + def test_exception_renderer_that_returns_string + exception = nil + handler = ->(e) { exception = e; '' } + + output = Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: handler) + + assert exception.is_a?(Liquid::ZeroDivisionError) + assert_equal '', output + end + + def test_exception_renderer_that_raises + exception = nil + assert_raises(Liquid::ZeroDivisionError) do + Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) { exception = e; raise }) + end + assert exception.is_a?(Liquid::ZeroDivisionError) + end + + def test_global_filter_option_on_render + global_filter_proc = ->(output) { "#{output} filtered" } + rendered_template = Template.parse("{{name}}").render({ "name" => "bob" }, global_filter: global_filter_proc) + + assert_equal 'bob filtered', rendered_template + end + + def test_global_filter_option_when_native_filters_exist + global_filter_proc = ->(output) { "#{output} filtered" } + rendered_template = Template.parse("{{name | upcase}}").render({ "name" => "bob" }, global_filter: global_filter_proc) + + assert_equal 'BOB filtered', rendered_template + end + + def test_undefined_variables + t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}") + result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true }) + + assert_equal '33 32 ', result + assert_equal 3, t.errors.count + assert_instance_of Liquid::UndefinedVariable, t.errors[0] + assert_equal 'Liquid error: undefined variable y', t.errors[0].message + assert_instance_of Liquid::UndefinedVariable, t.errors[1] + assert_equal 'Liquid error: undefined variable b', t.errors[1].message + assert_instance_of Liquid::UndefinedVariable, t.errors[2] + assert_equal 'Liquid error: undefined variable d', t.errors[2].message + end + + def test_nil_value_does_not_raise + Liquid::Template.error_mode = :strict + t = Template.parse("some{{x}}thing") + result = t.render!({ 'x' => nil }, strict_variables: true) + + assert_equal 0, t.errors.count + assert_equal 'something', result + end + + def test_undefined_variables_raise + t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}") + + assert_raises UndefinedVariable do + t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, { strict_variables: true }) + end + end + + def test_undefined_drop_methods + d = DropWithUndefinedMethod.new + t = Template.new.parse('{{ foo }} {{ woot }}') + result = t.render(d, { strict_variables: true }) + + assert_equal 'foo ', result + assert_equal 1, t.errors.count + assert_instance_of Liquid::UndefinedDropMethod, t.errors[0] + end + + def test_undefined_drop_methods_raise + d = DropWithUndefinedMethod.new + t = Template.new.parse('{{ foo }} {{ woot }}') + + assert_raises UndefinedDropMethod do + t.render!(d, { strict_variables: true }) + end + end + + def test_undefined_filters + t = Template.parse("{{a}} {{x | upcase | somefilter1 | somefilter2 | somefilter3}}") + filters = Module.new do + def somefilter3(v) + "-#{v}-" + end + end + result = t.render({ 'a' => 123, 'x' => 'foo' }, { filters: [filters], strict_filters: true }) + + assert_equal '123 ', result + assert_equal 1, t.errors.count + assert_instance_of Liquid::UndefinedFilter, t.errors[0] + assert_equal 'Liquid error: undefined filter somefilter1', t.errors[0].message + end + + def test_undefined_filters_raise + t = Template.parse("{{x | somefilter1 | upcase | somefilter2}}") + + assert_raises UndefinedFilter do + t.render!({ 'x' => 'foo' }, { strict_filters: true }) + end + end + + def test_using_range_literal_works_as_expected + t = Template.parse("{% assign foo = (x..y) %}{{ foo }}") + result = t.render({ 'x' => 1, 'y' => 5 }) + assert_equal '1..5', result + + t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}") + result = t.render({ 'x' => 1, 'y' => 5 }) + assert_equal '12345', result + end +end diff --git a/bin/gems/liquid-4.0.4/test/integration/trim_mode_test.rb b/bin/gems/liquid-4.0.4/test/integration/trim_mode_test.rb new file mode 100644 index 00000000..52248cff --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/trim_mode_test.rb @@ -0,0 +1,529 @@ +require 'test_helper' + +class TrimModeTest < Minitest::Test + include Liquid + + # Make sure the trim isn't applied to standard output + def test_standard_output + text = <<-END_TEMPLATE +
+

+ {{ 'John' }} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ John +

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_variable_output_with_multiple_blank_lines + text = <<-END_TEMPLATE +
+

+ + + {{- 'John' -}} + + +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

John

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_tag_output_with_multiple_blank_lines + text = <<-END_TEMPLATE +
+

+ + + {%- if true -%} + yes + {%- endif -%} + + +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

yes

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + # Make sure the trim isn't applied to standard tags + def test_standard_tags + whitespace = ' ' + text = <<-END_TEMPLATE +
+

+ {% if true %} + yes + {% endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+#{whitespace} + yes +#{whitespace} +

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {% if false %} + no + {% endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+#{whitespace} +

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + # Make sure the trim isn't too agressive + def test_no_trim_output + text = '

{{- \'John\' -}}

' + expected = '

John

' + assert_template_result(expected, text) + end + + # Make sure the trim isn't too agressive + def test_no_trim_tags + text = '

{%- if true -%}yes{%- endif -%}

' + expected = '

yes

' + assert_template_result(expected, text) + + text = '

{%- if false -%}no{%- endif -%}

' + expected = '

' + assert_template_result(expected, text) + end + + def test_single_line_outer_tag + text = '

{%- if true %} yes {% endif -%}

' + expected = '

yes

' + assert_template_result(expected, text) + + text = '

{%- if false %} no {% endif -%}

' + expected = '

' + assert_template_result(expected, text) + end + + def test_single_line_inner_tag + text = '

{% if true -%} yes {%- endif %}

' + expected = '

yes

' + assert_template_result(expected, text) + + text = '

{% if false -%} no {%- endif %}

' + expected = '

' + assert_template_result(expected, text) + end + + def test_single_line_post_tag + text = '

{% if true -%} yes {% endif -%}

' + expected = '

yes

' + assert_template_result(expected, text) + + text = '

{% if false -%} no {% endif -%}

' + expected = '

' + assert_template_result(expected, text) + end + + def test_single_line_pre_tag + text = '

{%- if true %} yes {%- endif %}

' + expected = '

yes

' + assert_template_result(expected, text) + + text = '

{%- if false %} no {%- endif %}

' + expected = '

' + assert_template_result(expected, text) + end + + def test_pre_trim_output + text = <<-END_TEMPLATE +
+

+ {{- 'John' }} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

John +

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_pre_trim_tags + text = <<-END_TEMPLATE +
+

+ {%- if true %} + yes + {%- endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ yes +

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {%- if false %} + no + {%- endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_post_trim_output + text = <<-END_TEMPLATE +
+

+ {{ 'John' -}} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ John

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_post_trim_tags + text = <<-END_TEMPLATE +
+

+ {% if true -%} + yes + {% endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ yes +

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {% if false -%} + no + {% endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_pre_and_post_trim_tags + text = <<-END_TEMPLATE +
+

+ {%- if true %} + yes + {% endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ yes +

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {%- if false %} + no + {% endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_post_and_pre_trim_tags + text = <<-END_TEMPLATE +
+

+ {% if true -%} + yes + {%- endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+ yes +

+
+ END_EXPECTED + assert_template_result(expected, text) + + whitespace = ' ' + text = <<-END_TEMPLATE +
+

+ {% if false -%} + no + {%- endif %} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+#{whitespace} +

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_trim_output + text = <<-END_TEMPLATE +
+

+ {{- 'John' -}} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

John

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_trim_tags + text = <<-END_TEMPLATE +
+

+ {%- if true -%} + yes + {%- endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

yes

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {%- if false -%} + no + {%- endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_whitespace_trim_output + text = <<-END_TEMPLATE +
+

+ {{- 'John' -}}, + {{- '30' -}} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

John,30

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_whitespace_trim_tags + text = <<-END_TEMPLATE +
+

+ {%- if true -%} + yes + {%- endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

yes

+
+ END_EXPECTED + assert_template_result(expected, text) + + text = <<-END_TEMPLATE +
+

+ {%- if false -%} + no + {%- endif -%} +

+
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

+
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_complex_trim_output + text = <<-END_TEMPLATE +
+

+ {{- 'John' -}} + {{- '30' -}} +

+ + {{ 'John' -}} + {{- '30' }} + + + {{- 'John' }} + {{ '30' -}} + +
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+

John30

+ + John30 + + John + 30 +
+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_complex_trim + text = <<-END_TEMPLATE +
+ {%- if true -%} + {%- if true -%} +

+ {{- 'John' -}} +

+ {%- endif -%} + {%- endif -%} +
+ END_TEMPLATE + expected = <<-END_EXPECTED +

John

+ END_EXPECTED + assert_template_result(expected, text) + end + + def test_right_trim_followed_by_tag + assert_template_result('ab c', '{{ "a" -}}{{ "b" }} c') + end + + def test_raw_output + whitespace = ' ' + text = <<-END_TEMPLATE +
+ {% raw %} + {%- if true -%} +

+ {{- 'John' -}} +

+ {%- endif -%} + {% endraw %} +
+ END_TEMPLATE + expected = <<-END_EXPECTED +
+#{whitespace} + {%- if true -%} +

+ {{- 'John' -}} +

+ {%- endif -%} +#{whitespace} +
+ END_EXPECTED + assert_template_result(expected, text) + end +end # TrimModeTest diff --git a/bin/gems/liquid-4.0.4/test/integration/variable_test.rb b/bin/gems/liquid-4.0.4/test/integration/variable_test.rb new file mode 100644 index 00000000..abd6e70c --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/integration/variable_test.rb @@ -0,0 +1,96 @@ +require 'test_helper' + +class VariableTest < Minitest::Test + include Liquid + + def test_simple_variable + template = Template.parse(%({{test}})) + assert_equal 'worked', template.render!('test' => 'worked') + assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully') + end + + def test_variable_render_calls_to_liquid + assert_template_result 'foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new + end + + def test_simple_with_whitespaces + template = Template.parse(%( {{ test }} )) + assert_equal ' worked ', template.render!('test' => 'worked') + assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully') + end + + def test_ignore_unknown + template = Template.parse(%({{ test }})) + assert_equal '', template.render! + end + + def test_using_blank_as_variable_name + template = Template.parse("{% assign foo = blank %}{{ foo }}") + assert_equal '', template.render! + end + + def test_using_empty_as_variable_name + template = Template.parse("{% assign foo = empty %}{{ foo }}") + assert_equal '', template.render! + end + + def test_hash_scoping + template = Template.parse(%({{ test.test }})) + assert_equal 'worked', template.render!('test' => { 'test' => 'worked' }) + end + + def test_false_renders_as_false + assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false) + assert_equal 'false', Template.parse("{{ false }}").render! + end + + def test_nil_renders_as_empty_string + assert_equal '', Template.parse("{{ nil }}").render! + assert_equal 'cat', Template.parse("{{ nil | append: 'cat' }}").render! + end + + def test_preset_assigns + template = Template.parse(%({{ test }})) + template.assigns['test'] = 'worked' + assert_equal 'worked', template.render! + end + + def test_reuse_parsed_template + template = Template.parse(%({{ greeting }} {{ name }})) + template.assigns['greeting'] = 'Goodbye' + assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi') + assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi') + assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian') + assert_equal 'Goodbye Brian', template.render!('name' => 'Brian') + assert_equal({ 'greeting' => 'Goodbye' }, template.assigns) + end + + def test_assigns_not_polluted_from_template + template = Template.parse(%({{ test }}{% assign test = 'bar' %}{{ test }})) + template.assigns['test'] = 'baz' + assert_equal 'bazbar', template.render! + assert_equal 'bazbar', template.render! + assert_equal 'foobar', template.render!('test' => 'foo') + assert_equal 'bazbar', template.render! + end + + def test_hash_with_default_proc + template = Template.parse(%(Hello {{ test }})) + assigns = Hash.new { |h, k| raise "Unknown variable '#{k}'" } + assigns['test'] = 'Tobi' + assert_equal 'Hello Tobi', template.render!(assigns) + assigns.delete('test') + e = assert_raises(RuntimeError) do + template.render!(assigns) + end + assert_equal "Unknown variable 'test'", e.message + end + + def test_multiline_variable + assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked') + end + + def test_render_symbol + assert_template_result 'bar', '{{ foo }}', 'foo' => :bar + end +end diff --git a/bin/gems/liquid-4.0.4/test/test_helper.rb b/bin/gems/liquid-4.0.4/test/test_helper.rb new file mode 100755 index 00000000..3cee6766 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/test_helper.rb @@ -0,0 +1,108 @@ +#!/usr/bin/env ruby + +ENV["MT_NO_EXPECTATIONS"] = "1" +require 'minitest/autorun' + +$LOAD_PATH.unshift(File.join(File.expand_path(__dir__), '..', 'lib')) +require 'liquid.rb' +require 'liquid/profiler' + +mode = :strict +if env_mode = ENV['LIQUID_PARSER_MODE'] + puts "-- #{env_mode.upcase} ERROR MODE" + mode = env_mode.to_sym +end +Liquid::Template.error_mode = mode + +if ENV['LIQUID-C'] == '1' + puts "-- LIQUID C" + require 'liquid/c' +end + +if Minitest.const_defined?('Test') + # We're on Minitest 5+. Nothing to do here. +else + # Minitest 4 doesn't have Minitest::Test yet. + Minitest::Test = MiniTest::Unit::TestCase +end + +module Minitest + class Test + def fixture(name) + File.join(File.expand_path(__dir__), "fixtures", name) + end + end + + module Assertions + include Liquid + + def assert_template_result(expected, template, assigns = {}, message = nil) + assert_equal expected, Template.parse(template).render!(assigns), message + end + + def assert_template_result_matches(expected, template, assigns = {}, message = nil) + return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp + + assert_match expected, Template.parse(template).render!(assigns), message + end + + def assert_match_syntax_error(match, template, assigns = {}) + exception = assert_raises(Liquid::SyntaxError) do + Template.parse(template).render(assigns) + end + assert_match match, exception.message + end + + def with_global_filter(*globals) + original_global_strainer = Liquid::Strainer.class_variable_get(:@@global_strainer) + Liquid::Strainer.class_variable_set(:@@global_strainer, Class.new(Liquid::Strainer) do + @filter_methods = Set.new + end) + Liquid::Strainer.class_variable_get(:@@strainer_class_cache).clear + + globals.each do |global| + Liquid::Template.register_filter(global) + end + yield + ensure + Liquid::Strainer.class_variable_get(:@@strainer_class_cache).clear + Liquid::Strainer.class_variable_set(:@@global_strainer, original_global_strainer) + end + + def with_error_mode(mode) + old_mode = Liquid::Template.error_mode + Liquid::Template.error_mode = mode + yield + ensure + Liquid::Template.error_mode = old_mode + end + end +end + +class ThingWithToLiquid + def to_liquid + 'foobar' + end +end + +class ErrorDrop < Liquid::Drop + def standard_error + raise Liquid::StandardError, 'standard error' + end + + def argument_error + raise Liquid::ArgumentError, 'argument error' + end + + def syntax_error + raise Liquid::SyntaxError, 'syntax error' + end + + def runtime_error + raise 'runtime error' + end + + def exception + raise Exception, 'exception' + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/block_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/block_unit_test.rb new file mode 100644 index 00000000..6a27a7d4 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/block_unit_test.rb @@ -0,0 +1,58 @@ +require 'test_helper' + +class BlockUnitTest < Minitest::Test + include Liquid + + def test_blankspace + template = Liquid::Template.parse(" ") + assert_equal [" "], template.root.nodelist + end + + def test_variable_beginning + template = Liquid::Template.parse("{{funk}} ") + assert_equal 2, template.root.nodelist.size + assert_equal Variable, template.root.nodelist[0].class + assert_equal String, template.root.nodelist[1].class + end + + def test_variable_end + template = Liquid::Template.parse(" {{funk}}") + assert_equal 2, template.root.nodelist.size + assert_equal String, template.root.nodelist[0].class + assert_equal Variable, template.root.nodelist[1].class + end + + def test_variable_middle + template = Liquid::Template.parse(" {{funk}} ") + assert_equal 3, template.root.nodelist.size + assert_equal String, template.root.nodelist[0].class + assert_equal Variable, template.root.nodelist[1].class + assert_equal String, template.root.nodelist[2].class + end + + def test_variable_many_embedded_fragments + template = Liquid::Template.parse(" {{funk}} {{so}} {{brother}} ") + assert_equal 7, template.root.nodelist.size + assert_equal [String, Variable, String, Variable, String, Variable, String], + block_types(template.root.nodelist) + end + + def test_with_block + template = Liquid::Template.parse(" {% comment %} {% endcomment %} ") + assert_equal [String, Comment, String], block_types(template.root.nodelist) + assert_equal 3, template.root.nodelist.size + end + + def test_with_custom_tag + Liquid::Template.register_tag("testtag", Block) + assert Liquid::Template.parse("{% testtag %} {% endtesttag %}") + ensure + Liquid::Template.tags.delete('testtag') + end + + private + + def block_types(nodelist) + nodelist.collect(&:class) + end +end # VariableTest diff --git a/bin/gems/liquid-4.0.4/test/unit/condition_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/condition_unit_test.rb new file mode 100644 index 00000000..b3b90e88 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/condition_unit_test.rb @@ -0,0 +1,166 @@ +require 'test_helper' + +class ConditionUnitTest < Minitest::Test + include Liquid + + def setup + @context = Liquid::Context.new + end + + def test_basic_condition + assert_equal false, Condition.new(1, '==', 2).evaluate + assert_equal true, Condition.new(1, '==', 1).evaluate + end + + def test_default_operators_evalute_true + assert_evaluates_true 1, '==', 1 + assert_evaluates_true 1, '!=', 2 + assert_evaluates_true 1, '<>', 2 + assert_evaluates_true 1, '<', 2 + assert_evaluates_true 2, '>', 1 + assert_evaluates_true 1, '>=', 1 + assert_evaluates_true 2, '>=', 1 + assert_evaluates_true 1, '<=', 2 + assert_evaluates_true 1, '<=', 1 + # negative numbers + assert_evaluates_true 1, '>', -1 + assert_evaluates_true -1, '<', 1 + assert_evaluates_true 1.0, '>', -1.0 + assert_evaluates_true -1.0, '<', 1.0 + end + + def test_default_operators_evalute_false + assert_evaluates_false 1, '==', 2 + assert_evaluates_false 1, '!=', 1 + assert_evaluates_false 1, '<>', 1 + assert_evaluates_false 1, '<', 0 + assert_evaluates_false 2, '>', 4 + assert_evaluates_false 1, '>=', 3 + assert_evaluates_false 2, '>=', 4 + assert_evaluates_false 1, '<=', 0 + assert_evaluates_false 1, '<=', 0 + end + + def test_contains_works_on_strings + assert_evaluates_true 'bob', 'contains', 'o' + assert_evaluates_true 'bob', 'contains', 'b' + assert_evaluates_true 'bob', 'contains', 'bo' + assert_evaluates_true 'bob', 'contains', 'ob' + assert_evaluates_true 'bob', 'contains', 'bob' + + assert_evaluates_false 'bob', 'contains', 'bob2' + assert_evaluates_false 'bob', 'contains', 'a' + assert_evaluates_false 'bob', 'contains', '---' + end + + def test_invalid_comparation_operator + assert_evaluates_argument_error 1, '~~', 0 + end + + def test_comparation_of_int_and_str + assert_evaluates_argument_error '1', '>', 0 + assert_evaluates_argument_error '1', '<', 0 + assert_evaluates_argument_error '1', '>=', 0 + assert_evaluates_argument_error '1', '<=', 0 + end + + def test_hash_compare_backwards_compatibility + assert_nil Condition.new({}, '>', 2).evaluate + assert_nil Condition.new(2, '>', {}).evaluate + assert_equal false, Condition.new({}, '==', 2).evaluate + assert_equal true, Condition.new({ 'a' => 1 }, '==', { 'a' => 1 }).evaluate + assert_equal true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate + end + + def test_contains_works_on_arrays + @context = Liquid::Context.new + @context['array'] = [1, 2, 3, 4, 5] + array_expr = VariableLookup.new("array") + + assert_evaluates_false array_expr, 'contains', 0 + assert_evaluates_true array_expr, 'contains', 1 + assert_evaluates_true array_expr, 'contains', 2 + assert_evaluates_true array_expr, 'contains', 3 + assert_evaluates_true array_expr, 'contains', 4 + assert_evaluates_true array_expr, 'contains', 5 + assert_evaluates_false array_expr, 'contains', 6 + assert_evaluates_false array_expr, 'contains', "1" + end + + def test_contains_returns_false_for_nil_operands + @context = Liquid::Context.new + assert_evaluates_false VariableLookup.new('not_assigned'), 'contains', '0' + assert_evaluates_false 0, 'contains', VariableLookup.new('not_assigned') + end + + def test_contains_return_false_on_wrong_data_type + assert_evaluates_false 1, 'contains', 0 + end + + def test_contains_with_string_left_operand_coerces_right_operand_to_string + assert_evaluates_true ' 1 ', 'contains', 1 + assert_evaluates_false ' 1 ', 'contains', 2 + end + + def test_or_condition + condition = Condition.new(1, '==', 2) + + assert_equal false, condition.evaluate + + condition.or Condition.new(2, '==', 1) + + assert_equal false, condition.evaluate + + condition.or Condition.new(1, '==', 1) + + assert_equal true, condition.evaluate + end + + def test_and_condition + condition = Condition.new(1, '==', 1) + + assert_equal true, condition.evaluate + + condition.and Condition.new(2, '==', 2) + + assert_equal true, condition.evaluate + + condition.and Condition.new(2, '==', 1) + + assert_equal false, condition.evaluate + end + + def test_should_allow_custom_proc_operator + Condition.operators['starts_with'] = proc { |cond, left, right| left =~ %r{^#{right}} } + + assert_evaluates_true 'bob', 'starts_with', 'b' + assert_evaluates_false 'bob', 'starts_with', 'o' + ensure + Condition.operators.delete 'starts_with' + end + + def test_left_or_right_may_contain_operators + @context = Liquid::Context.new + @context['one'] = @context['another'] = "gnomeslab-and-or-liquid" + + assert_evaluates_true VariableLookup.new("one"), '==', VariableLookup.new("another") + end + + private + + def assert_evaluates_true(left, op, right) + assert Condition.new(left, op, right).evaluate(@context), + "Evaluated false: #{left} #{op} #{right}" + end + + def assert_evaluates_false(left, op, right) + assert !Condition.new(left, op, right).evaluate(@context), + "Evaluated true: #{left} #{op} #{right}" + end + + def assert_evaluates_argument_error(left, op, right) + assert_raises(Liquid::ArgumentError) do + Condition.new(left, op, right).evaluate(@context) + end + end +end # ConditionTest diff --git a/bin/gems/liquid-4.0.4/test/unit/context_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/context_unit_test.rb new file mode 100644 index 00000000..d9bfedb1 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/context_unit_test.rb @@ -0,0 +1,490 @@ +require 'test_helper' + +class HundredCentes + def to_liquid + 100 + end +end + +class CentsDrop < Liquid::Drop + def amount + HundredCentes.new + end + + def non_zero? + true + end +end + +class ContextSensitiveDrop < Liquid::Drop + def test + @context['test'] + end +end + +class Category < Liquid::Drop + attr_accessor :name + + def initialize(name) + @name = name + end + + def to_liquid + CategoryDrop.new(self) + end +end + +class CategoryDrop + attr_accessor :category, :context + def initialize(category) + @category = category + end +end + +class CounterDrop < Liquid::Drop + def count + @count ||= 0 + @count += 1 + end +end + +class ArrayLike + def fetch(index) + end + + def [](index) + @counts ||= [] + @counts[index] ||= 0 + @counts[index] += 1 + end + + def to_liquid + self + end +end + +class ContextUnitTest < Minitest::Test + include Liquid + + def setup + @context = Liquid::Context.new + end + + def test_variables + @context['string'] = 'string' + assert_equal 'string', @context['string'] + + @context['num'] = 5 + assert_equal 5, @context['num'] + + @context['time'] = Time.parse('2006-06-06 12:00:00') + assert_equal Time.parse('2006-06-06 12:00:00'), @context['time'] + + @context['date'] = Date.today + assert_equal Date.today, @context['date'] + + now = DateTime.now + @context['datetime'] = now + assert_equal now, @context['datetime'] + + @context['bool'] = true + assert_equal true, @context['bool'] + + @context['bool'] = false + assert_equal false, @context['bool'] + + @context['nil'] = nil + assert_nil @context['nil'] + assert_nil @context['nil'] + end + + def test_variables_not_existing + assert_nil @context['does_not_exist'] + end + + def test_scoping + @context.push + @context.pop + + assert_raises(Liquid::ContextError) do + @context.pop + end + + assert_raises(Liquid::ContextError) do + @context.push + @context.pop + @context.pop + end + end + + def test_length_query + @context['numbers'] = [1, 2, 3, 4] + + assert_equal 4, @context['numbers.size'] + + @context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4 } + + assert_equal 4, @context['numbers.size'] + + @context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4, 'size' => 1000 } + + assert_equal 1000, @context['numbers.size'] + end + + def test_hyphenated_variable + @context['oh-my'] = 'godz' + assert_equal 'godz', @context['oh-my'] + end + + def test_add_filter + filter = Module.new do + def hi(output) + output + ' hi!' + end + end + + context = Context.new + context.add_filters(filter) + assert_equal 'hi? hi!', context.invoke(:hi, 'hi?') + + context = Context.new + assert_equal 'hi?', context.invoke(:hi, 'hi?') + + context.add_filters(filter) + assert_equal 'hi? hi!', context.invoke(:hi, 'hi?') + end + + def test_only_intended_filters_make_it_there + filter = Module.new do + def hi(output) + output + ' hi!' + end + end + + context = Context.new + assert_equal "Wookie", context.invoke("hi", "Wookie") + + context.add_filters(filter) + assert_equal "Wookie hi!", context.invoke("hi", "Wookie") + end + + def test_add_item_in_outer_scope + @context['test'] = 'test' + @context.push + assert_equal 'test', @context['test'] + @context.pop + assert_equal 'test', @context['test'] + end + + def test_add_item_in_inner_scope + @context.push + @context['test'] = 'test' + assert_equal 'test', @context['test'] + @context.pop + assert_nil @context['test'] + end + + def test_hierachical_data + @context['hash'] = { "name" => 'tobi' } + assert_equal 'tobi', @context['hash.name'] + assert_equal 'tobi', @context['hash["name"]'] + end + + def test_keywords + assert_equal true, @context['true'] + assert_equal false, @context['false'] + end + + def test_digits + assert_equal 100, @context['100'] + assert_equal 100.00, @context['100.00'] + end + + def test_strings + assert_equal "hello!", @context['"hello!"'] + assert_equal "hello!", @context["'hello!'"] + end + + def test_merge + @context.merge({ "test" => "test" }) + assert_equal 'test', @context['test'] + @context.merge({ "test" => "newvalue", "foo" => "bar" }) + assert_equal 'newvalue', @context['test'] + assert_equal 'bar', @context['foo'] + end + + def test_array_notation + @context['test'] = [1, 2, 3, 4, 5] + + assert_equal 1, @context['test[0]'] + assert_equal 2, @context['test[1]'] + assert_equal 3, @context['test[2]'] + assert_equal 4, @context['test[3]'] + assert_equal 5, @context['test[4]'] + end + + def test_recoursive_array_notation + @context['test'] = { 'test' => [1, 2, 3, 4, 5] } + + assert_equal 1, @context['test.test[0]'] + + @context['test'] = [{ 'test' => 'worked' }] + + assert_equal 'worked', @context['test[0].test'] + end + + def test_hash_to_array_transition + @context['colors'] = { + 'Blue' => ['003366', '336699', '6699CC', '99CCFF'], + 'Green' => ['003300', '336633', '669966', '99CC99'], + 'Yellow' => ['CC9900', 'FFCC00', 'FFFF99', 'FFFFCC'], + 'Red' => ['660000', '993333', 'CC6666', 'FF9999'] + } + + assert_equal '003366', @context['colors.Blue[0]'] + assert_equal 'FF9999', @context['colors.Red[3]'] + end + + def test_try_first + @context['test'] = [1, 2, 3, 4, 5] + + assert_equal 1, @context['test.first'] + assert_equal 5, @context['test.last'] + + @context['test'] = { 'test' => [1, 2, 3, 4, 5] } + + assert_equal 1, @context['test.test.first'] + assert_equal 5, @context['test.test.last'] + + @context['test'] = [1] + assert_equal 1, @context['test.first'] + assert_equal 1, @context['test.last'] + end + + def test_access_hashes_with_hash_notation + @context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] } + @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] } + + assert_equal 5, @context['products["count"]'] + assert_equal 'deepsnow', @context['products["tags"][0]'] + assert_equal 'deepsnow', @context['products["tags"].first'] + assert_equal 'draft151cm', @context['product["variants"][0]["title"]'] + assert_equal 'element151cm', @context['product["variants"][1]["title"]'] + assert_equal 'draft151cm', @context['product["variants"][0]["title"]'] + assert_equal 'element151cm', @context['product["variants"].last["title"]'] + end + + def test_access_variable_with_hash_notation + @context['foo'] = 'baz' + @context['bar'] = 'foo' + + assert_equal 'baz', @context['["foo"]'] + assert_equal 'baz', @context['[bar]'] + end + + def test_access_hashes_with_hash_access_variables + @context['var'] = 'tags' + @context['nested'] = { 'var' => 'tags' } + @context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] } + + assert_equal 'deepsnow', @context['products[var].first'] + assert_equal 'freestyle', @context['products[nested.var].last'] + end + + def test_hash_notation_only_for_hash_access + @context['array'] = [1, 2, 3, 4, 5] + @context['hash'] = { 'first' => 'Hello' } + + assert_equal 1, @context['array.first'] + assert_nil @context['array["first"]'] + assert_equal 'Hello', @context['hash["first"]'] + end + + def test_first_can_appear_in_middle_of_callchain + @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] } + + assert_equal 'draft151cm', @context['product.variants[0].title'] + assert_equal 'element151cm', @context['product.variants[1].title'] + assert_equal 'draft151cm', @context['product.variants.first.title'] + assert_equal 'element151cm', @context['product.variants.last.title'] + end + + def test_cents + @context.merge("cents" => HundredCentes.new) + assert_equal 100, @context['cents'] + end + + def test_nested_cents + @context.merge("cents" => { 'amount' => HundredCentes.new }) + assert_equal 100, @context['cents.amount'] + + @context.merge("cents" => { 'cents' => { 'amount' => HundredCentes.new } }) + assert_equal 100, @context['cents.cents.amount'] + end + + def test_cents_through_drop + @context.merge("cents" => CentsDrop.new) + assert_equal 100, @context['cents.amount'] + end + + def test_nested_cents_through_drop + @context.merge("vars" => { "cents" => CentsDrop.new }) + assert_equal 100, @context['vars.cents.amount'] + end + + def test_drop_methods_with_question_marks + @context.merge("cents" => CentsDrop.new) + assert @context['cents.non_zero?'] + end + + def test_context_from_within_drop + @context.merge("test" => '123', "vars" => ContextSensitiveDrop.new) + assert_equal '123', @context['vars.test'] + end + + def test_nested_context_from_within_drop + @context.merge("test" => '123', "vars" => { "local" => ContextSensitiveDrop.new }) + assert_equal '123', @context['vars.local.test'] + end + + def test_ranges + @context.merge("test" => '5') + assert_equal (1..5), @context['(1..5)'] + assert_equal (1..5), @context['(1..test)'] + assert_equal (5..5), @context['(test..test)'] + end + + def test_cents_through_drop_nestedly + @context.merge("cents" => { "cents" => CentsDrop.new }) + assert_equal 100, @context['cents.cents.amount'] + + @context.merge("cents" => { "cents" => { "cents" => CentsDrop.new } }) + assert_equal 100, @context['cents.cents.cents.amount'] + end + + def test_drop_with_variable_called_only_once + @context['counter'] = CounterDrop.new + + assert_equal 1, @context['counter.count'] + assert_equal 2, @context['counter.count'] + assert_equal 3, @context['counter.count'] + end + + def test_drop_with_key_called_only_once + @context['counter'] = CounterDrop.new + + assert_equal 1, @context['counter["count"]'] + assert_equal 2, @context['counter["count"]'] + assert_equal 3, @context['counter["count"]'] + end + + def test_proc_as_variable + @context['dynamic'] = proc { 'Hello' } + + assert_equal 'Hello', @context['dynamic'] + end + + def test_lambda_as_variable + @context['dynamic'] = proc { 'Hello' } + + assert_equal 'Hello', @context['dynamic'] + end + + def test_nested_lambda_as_variable + @context['dynamic'] = { "lambda" => proc { 'Hello' } } + + assert_equal 'Hello', @context['dynamic.lambda'] + end + + def test_array_containing_lambda_as_variable + @context['dynamic'] = [1, 2, proc { 'Hello' }, 4, 5] + + assert_equal 'Hello', @context['dynamic[2]'] + end + + def test_lambda_is_called_once + @context['callcount'] = proc { @global ||= 0; @global += 1; @global.to_s } + + assert_equal '1', @context['callcount'] + assert_equal '1', @context['callcount'] + assert_equal '1', @context['callcount'] + + @global = nil + end + + def test_nested_lambda_is_called_once + @context['callcount'] = { "lambda" => proc { @global ||= 0; @global += 1; @global.to_s } } + + assert_equal '1', @context['callcount.lambda'] + assert_equal '1', @context['callcount.lambda'] + assert_equal '1', @context['callcount.lambda'] + + @global = nil + end + + def test_lambda_in_array_is_called_once + @context['callcount'] = [1, 2, proc { @global ||= 0; @global += 1; @global.to_s }, 4, 5] + + assert_equal '1', @context['callcount[2]'] + assert_equal '1', @context['callcount[2]'] + assert_equal '1', @context['callcount[2]'] + + @global = nil + end + + def test_access_to_context_from_proc + @context.registers[:magic] = 345392 + + @context['magic'] = proc { @context.registers[:magic] } + + assert_equal 345392, @context['magic'] + end + + def test_to_liquid_and_context_at_first_level + @context['category'] = Category.new("foobar") + assert_kind_of CategoryDrop, @context['category'] + assert_equal @context, @context['category'].context + end + + def test_interrupt_avoids_object_allocations + @context.interrupt? # ruby 3.0.0 allocates on the first call + assert_no_object_allocations do + @context.interrupt? + end + end + + def test_context_initialization_with_a_proc_in_environment + contx = Context.new([test: ->(c) { c['poutine'] }], { test: :foo }) + + assert contx + assert_nil contx['poutine'] + end + + def test_apply_global_filter + global_filter_proc = ->(output) { "#{output} filtered" } + + context = Context.new + context.global_filter = global_filter_proc + + assert_equal 'hi filtered', context.apply_global_filter('hi') + end + + def test_apply_global_filter_when_no_global_filter_exist + context = Context.new + assert_equal 'hi', context.apply_global_filter('hi') + end + + private + + def assert_no_object_allocations + unless RUBY_ENGINE == 'ruby' + skip "stackprof needed to count object allocations" + end + require 'stackprof' + + profile = StackProf.run(mode: :object) do + yield + end + assert_equal 0, profile[:samples] + end +end # ContextTest diff --git a/bin/gems/liquid-4.0.4/test/unit/file_system_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/file_system_unit_test.rb new file mode 100644 index 00000000..2c7250ba --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/file_system_unit_test.rb @@ -0,0 +1,35 @@ +require 'test_helper' + +class FileSystemUnitTest < Minitest::Test + include Liquid + + def test_default + assert_raises(FileSystemError) do + BlankFileSystem.new.read_template_file("dummy") + end + end + + def test_local + file_system = Liquid::LocalFileSystem.new("/some/path") + assert_equal "/some/path/_mypartial.liquid", file_system.full_path("mypartial") + assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial") + + assert_raises(FileSystemError) do + file_system.full_path("../dir/mypartial") + end + + assert_raises(FileSystemError) do + file_system.full_path("/dir/../../dir/mypartial") + end + + assert_raises(FileSystemError) do + file_system.full_path("/etc/passwd") + end + end + + def test_custom_template_filename_patterns + file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html") + assert_equal "/some/path/mypartial.html", file_system.full_path("mypartial") + assert_equal "/some/path/dir/mypartial.html", file_system.full_path("dir/mypartial") + end +end # FileSystemTest diff --git a/bin/gems/liquid-4.0.4/test/unit/i18n_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/i18n_unit_test.rb new file mode 100644 index 00000000..b57500e3 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/i18n_unit_test.rb @@ -0,0 +1,37 @@ +require 'test_helper' + +class I18nUnitTest < Minitest::Test + include Liquid + + def setup + @i18n = I18n.new(fixture("en_locale.yml")) + end + + def test_simple_translate_string + assert_equal "less is more", @i18n.translate("simple") + end + + def test_nested_translate_string + assert_equal "something wasn't right", @i18n.translate("errors.syntax.oops") + end + + def test_single_string_interpolation + assert_equal "something different", @i18n.translate("whatever", something: "different") + end + + # def test_raises_translation_error_on_undefined_interpolation_key + # assert_raises I18n::TranslationError do + # @i18n.translate("whatever", :oopstypos => "yes") + # end + # end + + def test_raises_unknown_translation + assert_raises I18n::TranslationError do + @i18n.translate("doesnt_exist") + end + end + + def test_sets_default_path_to_en + assert_equal I18n::DEFAULT_LOCALE, I18n.new.path + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/lexer_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/lexer_unit_test.rb new file mode 100644 index 00000000..5adcf2bd --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/lexer_unit_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class LexerUnitTest < Minitest::Test + include Liquid + + def test_strings + tokens = Lexer.new(%( 'this is a test""' "wat 'lol'")).tokenize + assert_equal [[:string, %('this is a test""')], [:string, %("wat 'lol'")], [:end_of_string]], tokens + end + + def test_integer + tokens = Lexer.new('hi 50').tokenize + assert_equal [[:id, 'hi'], [:number, '50'], [:end_of_string]], tokens + end + + def test_float + tokens = Lexer.new('hi 5.0').tokenize + assert_equal [[:id, 'hi'], [:number, '5.0'], [:end_of_string]], tokens + end + + def test_comparison + tokens = Lexer.new('== <> contains ').tokenize + assert_equal [[:comparison, '=='], [:comparison, '<>'], [:comparison, 'contains'], [:end_of_string]], tokens + end + + def test_specials + tokens = Lexer.new('| .:').tokenize + assert_equal [[:pipe, '|'], [:dot, '.'], [:colon, ':'], [:end_of_string]], tokens + tokens = Lexer.new('[,]').tokenize + assert_equal [[:open_square, '['], [:comma, ','], [:close_square, ']'], [:end_of_string]], tokens + end + + def test_fancy_identifiers + tokens = Lexer.new('hi five?').tokenize + assert_equal [[:id, 'hi'], [:id, 'five?'], [:end_of_string]], tokens + + tokens = Lexer.new('2foo').tokenize + assert_equal [[:number, '2'], [:id, 'foo'], [:end_of_string]], tokens + end + + def test_whitespace + tokens = Lexer.new("five|\n\t ==").tokenize + assert_equal [[:id, 'five'], [:pipe, '|'], [:comparison, '=='], [:end_of_string]], tokens + end + + def test_unexpected_character + assert_raises(SyntaxError) do + Lexer.new("%").tokenize + end + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/parser_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/parser_unit_test.rb new file mode 100644 index 00000000..9f23337a --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/parser_unit_test.rb @@ -0,0 +1,82 @@ +require 'test_helper' + +class ParserUnitTest < Minitest::Test + include Liquid + + def test_consume + p = Parser.new("wat: 7") + assert_equal 'wat', p.consume(:id) + assert_equal ':', p.consume(:colon) + assert_equal '7', p.consume(:number) + end + + def test_jump + p = Parser.new("wat: 7") + p.jump(2) + assert_equal '7', p.consume(:number) + end + + def test_consume? + p = Parser.new("wat: 7") + assert_equal 'wat', p.consume?(:id) + assert_equal false, p.consume?(:dot) + assert_equal ':', p.consume(:colon) + assert_equal '7', p.consume?(:number) + end + + def test_id? + p = Parser.new("wat 6 Peter Hegemon") + assert_equal 'wat', p.id?('wat') + assert_equal false, p.id?('endgame') + assert_equal '6', p.consume(:number) + assert_equal 'Peter', p.id?('Peter') + assert_equal false, p.id?('Achilles') + end + + def test_look + p = Parser.new("wat 6 Peter Hegemon") + assert_equal true, p.look(:id) + assert_equal 'wat', p.consume(:id) + assert_equal false, p.look(:comparison) + assert_equal true, p.look(:number) + assert_equal true, p.look(:id, 1) + assert_equal false, p.look(:number, 1) + end + + def test_expressions + p = Parser.new("hi.there hi?[5].there? hi.there.bob") + assert_equal 'hi.there', p.expression + assert_equal 'hi?[5].there?', p.expression + assert_equal 'hi.there.bob', p.expression + + p = Parser.new("567 6.0 'lol' \"wut\"") + assert_equal '567', p.expression + assert_equal '6.0', p.expression + assert_equal "'lol'", p.expression + assert_equal '"wut"', p.expression + end + + def test_ranges + p = Parser.new("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)") + assert_equal '(5..7)', p.expression + assert_equal '(1.5..9.6)', p.expression + assert_equal '(young..old)', p.expression + assert_equal '(hi[5].wat..old)', p.expression + end + + def test_arguments + p = Parser.new("filter: hi.there[5], keyarg: 7") + assert_equal 'filter', p.consume(:id) + assert_equal ':', p.consume(:colon) + assert_equal 'hi.there[5]', p.argument + assert_equal ',', p.consume(:comma) + assert_equal 'keyarg: 7', p.argument + end + + def test_invalid_expression + assert_raises(SyntaxError) do + p = Parser.new("==") + p.expression + end + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/regexp_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/regexp_unit_test.rb new file mode 100644 index 00000000..0821229f --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/regexp_unit_test.rb @@ -0,0 +1,44 @@ +require 'test_helper' + +class RegexpUnitTest < Minitest::Test + include Liquid + + def test_empty + assert_equal [], ''.scan(QuotedFragment) + end + + def test_quote + assert_equal ['"arg 1"'], '"arg 1"'.scan(QuotedFragment) + end + + def test_words + assert_equal ['arg1', 'arg2'], 'arg1 arg2'.scan(QuotedFragment) + end + + def test_tags + assert_equal ['', ''], ' '.scan(QuotedFragment) + assert_equal [''], ''.scan(QuotedFragment) + assert_equal ['', ''], %().scan(QuotedFragment) + end + + def test_double_quoted_words + assert_equal ['arg1', 'arg2', '"arg 3"'], 'arg1 arg2 "arg 3"'.scan(QuotedFragment) + end + + def test_single_quoted_words + assert_equal ['arg1', 'arg2', "'arg 3'"], 'arg1 arg2 \'arg 3\''.scan(QuotedFragment) + end + + def test_quoted_words_in_the_middle + assert_equal ['arg1', 'arg2', '"arg 3"', 'arg4'], 'arg1 arg2 "arg 3" arg4 '.scan(QuotedFragment) + end + + def test_variable_parser + assert_equal ['var'], 'var'.scan(VariableParser) + assert_equal ['var', 'method'], 'var.method'.scan(VariableParser) + assert_equal ['var', '[method]'], 'var[method]'.scan(VariableParser) + assert_equal ['var', '[method]', '[0]'], 'var[method][0]'.scan(VariableParser) + assert_equal ['var', '["method"]', '[0]'], 'var["method"][0]'.scan(VariableParser) + assert_equal ['var', '[method]', '[0]', 'method'], 'var[method][0].method'.scan(VariableParser) + end +end # RegexpTest diff --git a/bin/gems/liquid-4.0.4/test/unit/strainer_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/strainer_unit_test.rb new file mode 100644 index 00000000..5ce21004 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/strainer_unit_test.rb @@ -0,0 +1,164 @@ +require 'test_helper' + +class StrainerUnitTest < Minitest::Test + include Liquid + + module AccessScopeFilters + def public_filter + "public" + end + + def private_filter + "private" + end + private :private_filter + end + + Strainer.global_filter(AccessScopeFilters) + + def test_strainer + strainer = Strainer.create(nil) + assert_equal 5, strainer.invoke('size', 'input') + assert_equal "public", strainer.invoke("public_filter") + end + + def test_stainer_raises_argument_error + strainer = Strainer.create(nil) + assert_raises(Liquid::ArgumentError) do + strainer.invoke("public_filter", 1) + end + end + + def test_stainer_argument_error_contains_backtrace + strainer = Strainer.create(nil) + begin + strainer.invoke("public_filter", 1) + rescue Liquid::ArgumentError => e + assert_match( + /\ALiquid error: wrong number of arguments \((1 for 0|given 1, expected 0)\)\z/, + e.message) + assert_equal e.backtrace[0].split(':')[0], __FILE__ + end + end + + def test_strainer_only_invokes_public_filter_methods + strainer = Strainer.create(nil) + assert_equal false, strainer.class.invokable?('__test__') + assert_equal false, strainer.class.invokable?('test') + assert_equal false, strainer.class.invokable?('instance_eval') + assert_equal false, strainer.class.invokable?('__send__') + assert_equal true, strainer.class.invokable?('size') # from the standard lib + end + + def test_strainer_returns_nil_if_no_filter_method_found + strainer = Strainer.create(nil) + assert_nil strainer.invoke("private_filter") + assert_nil strainer.invoke("undef_the_filter") + end + + def test_strainer_returns_first_argument_if_no_method_and_arguments_given + strainer = Strainer.create(nil) + assert_equal "password", strainer.invoke("undef_the_method", "password") + end + + def test_strainer_only_allows_methods_defined_in_filters + strainer = Strainer.create(nil) + assert_equal "1 + 1", strainer.invoke("instance_eval", "1 + 1") + assert_equal "puts", strainer.invoke("__send__", "puts", "Hi Mom") + assert_equal "has_method?", strainer.invoke("invoke", "has_method?", "invoke") + end + + def test_strainer_uses_a_class_cache_to_avoid_method_cache_invalidation + a = Module.new + b = Module.new + strainer = Strainer.create(nil, [a, b]) + assert_kind_of Strainer, strainer + assert_kind_of a, strainer + assert_kind_of b, strainer + assert_kind_of Liquid::StandardFilters, strainer + end + + def test_add_filter_when_wrong_filter_class + c = Context.new + s = c.strainer + wrong_filter = ->(v) { v.reverse } + + assert_raises ArgumentError do + s.class.add_filter(wrong_filter) + end + end + + module PrivateMethodOverrideFilter + private + + def public_filter + "overriden as private" + end + end + + def test_add_filter_raises_when_module_privately_overrides_registered_public_methods + strainer = Context.new.strainer + + error = assert_raises(Liquid::MethodOverrideError) do + strainer.class.add_filter(PrivateMethodOverrideFilter) + end + assert_equal 'Liquid error: Filter overrides registered public methods as non public: public_filter', error.message + end + + module ProtectedMethodOverrideFilter + protected + + def public_filter + "overriden as protected" + end + end + + def test_add_filter_raises_when_module_overrides_registered_public_method_as_protected + strainer = Context.new.strainer + + error = assert_raises(Liquid::MethodOverrideError) do + strainer.class.add_filter(ProtectedMethodOverrideFilter) + end + assert_equal 'Liquid error: Filter overrides registered public methods as non public: public_filter', error.message + end + + module PublicMethodOverrideFilter + def public_filter + "public" + end + end + + def test_add_filter_does_not_raise_when_module_overrides_previously_registered_method + strainer = Context.new.strainer + strainer.class.add_filter(PublicMethodOverrideFilter) + assert strainer.class.filter_methods.include?('public_filter') + end + + module LateAddedFilter + def late_added_filter(input) + "filtered" + end + end + + def test_global_filter_clears_cache + assert_equal 'input', Strainer.create(nil).invoke('late_added_filter', 'input') + Strainer.global_filter(LateAddedFilter) + assert_equal 'filtered', Strainer.create(nil).invoke('late_added_filter', 'input') + end + + def test_add_filter_does_not_include_already_included_module + mod = Module.new do + class << self + attr_accessor :include_count + def included(mod) + self.include_count += 1 + end + end + self.include_count = 0 + end + strainer = Context.new.strainer + strainer.class.add_filter(mod) + strainer.class.add_filter(mod) + assert_equal 1, mod.include_count + end +end # StrainerTest diff --git a/bin/gems/liquid-4.0.4/test/unit/tag_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/tag_unit_test.rb new file mode 100644 index 00000000..c4b901b1 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/tag_unit_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class TagUnitTest < Minitest::Test + include Liquid + + def test_tag + tag = Tag.parse('tag', "", Tokenizer.new(""), ParseContext.new) + assert_equal 'liquid::tag', tag.name + assert_equal '', tag.render(Context.new) + end + + def test_return_raw_text_of_tag + tag = Tag.parse("long_tag", "param1, param2, param3", Tokenizer.new(""), ParseContext.new) + assert_equal("long_tag param1, param2, param3", tag.raw) + end + + def test_tag_name_should_return_name_of_the_tag + tag = Tag.parse("some_tag", "", Tokenizer.new(""), ParseContext.new) + assert_equal 'some_tag', tag.tag_name + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/tags/case_tag_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/tags/case_tag_unit_test.rb new file mode 100644 index 00000000..71103081 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/tags/case_tag_unit_test.rb @@ -0,0 +1,10 @@ +require 'test_helper' + +class CaseTagUnitTest < Minitest::Test + include Liquid + + def test_case_nodelist + template = Liquid::Template.parse('{% case var %}{% when true %}WHEN{% else %}ELSE{% endcase %}') + assert_equal ['WHEN', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/tags/for_tag_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/tags/for_tag_unit_test.rb new file mode 100644 index 00000000..b8fc5206 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/tags/for_tag_unit_test.rb @@ -0,0 +1,13 @@ +require 'test_helper' + +class ForTagUnitTest < Minitest::Test + def test_for_nodelist + template = Liquid::Template.parse('{% for item in items %}FOR{% endfor %}') + assert_equal ['FOR'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten + end + + def test_for_else_nodelist + template = Liquid::Template.parse('{% for item in items %}FOR{% else %}ELSE{% endfor %}') + assert_equal ['FOR', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/tags/if_tag_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/tags/if_tag_unit_test.rb new file mode 100644 index 00000000..7ecfc409 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/tags/if_tag_unit_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class IfTagUnitTest < Minitest::Test + def test_if_nodelist + template = Liquid::Template.parse('{% if true %}IF{% else %}ELSE{% endif %}') + assert_equal ['IF', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/template_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/template_unit_test.rb new file mode 100644 index 00000000..6328be53 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/template_unit_test.rb @@ -0,0 +1,78 @@ +require 'test_helper' + +class TemplateUnitTest < Minitest::Test + include Liquid + + def test_sets_default_localization_in_document + t = Template.new + t.parse('{%comment%}{%endcomment%}') + assert_instance_of I18n, t.root.nodelist[0].options[:locale] + end + + def test_sets_default_localization_in_context_with_quick_initialization + t = Template.new + t.parse('{%comment%}{%endcomment%}', locale: I18n.new(fixture("en_locale.yml"))) + + locale = t.root.nodelist[0].options[:locale] + assert_instance_of I18n, locale + assert_equal fixture("en_locale.yml"), locale.path + end + + def test_with_cache_classes_tags_returns_the_same_class + original_cache_setting = Liquid.cache_classes + Liquid.cache_classes = true + + original_klass = Class.new + Object.send(:const_set, :CustomTag, original_klass) + Template.register_tag('custom', CustomTag) + + Object.send(:remove_const, :CustomTag) + + new_klass = Class.new + Object.send(:const_set, :CustomTag, new_klass) + + assert Template.tags['custom'].equal?(original_klass) + ensure + Object.send(:remove_const, :CustomTag) + Template.tags.delete('custom') + Liquid.cache_classes = original_cache_setting + end + + def test_without_cache_classes_tags_reloads_the_class + original_cache_setting = Liquid.cache_classes + Liquid.cache_classes = false + + original_klass = Class.new + Object.send(:const_set, :CustomTag, original_klass) + Template.register_tag('custom', CustomTag) + + Object.send(:remove_const, :CustomTag) + + new_klass = Class.new + Object.send(:const_set, :CustomTag, new_klass) + + assert Template.tags['custom'].equal?(new_klass) + ensure + Object.send(:remove_const, :CustomTag) + Template.tags.delete('custom') + Liquid.cache_classes = original_cache_setting + end + + class FakeTag; end + + def test_tags_delete + Template.register_tag('fake', FakeTag) + assert_equal FakeTag, Template.tags['fake'] + + Template.tags.delete('fake') + assert_nil Template.tags['fake'] + end + + def test_tags_can_be_looped_over + Template.register_tag('fake', FakeTag) + result = Template.tags.map { |name, klass| [name, klass] } + assert result.include?(["fake", "TemplateUnitTest::FakeTag"]) + ensure + Template.tags.delete('fake') + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/tokenizer_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/tokenizer_unit_test.rb new file mode 100644 index 00000000..de84c1fb --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/tokenizer_unit_test.rb @@ -0,0 +1,55 @@ +require 'test_helper' + +class TokenizerTest < Minitest::Test + def test_tokenize_strings + assert_equal [' '], tokenize(' ') + assert_equal ['hello world'], tokenize('hello world') + end + + def test_tokenize_variables + assert_equal ['{{funk}}'], tokenize('{{funk}}') + assert_equal [' ', '{{funk}}', ' '], tokenize(' {{funk}} ') + assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], tokenize(' {{funk}} {{so}} {{brother}} ') + assert_equal [' ', '{{ funk }}', ' '], tokenize(' {{ funk }} ') + end + + def test_tokenize_blocks + assert_equal ['{%comment%}'], tokenize('{%comment%}') + assert_equal [' ', '{%comment%}', ' '], tokenize(' {%comment%} ') + + assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], tokenize(' {%comment%} {%endcomment%} ') + assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], tokenize(" {% comment %} {% endcomment %} ") + end + + def test_calculate_line_numbers_per_token_with_profiling + assert_equal [1], tokenize_line_numbers("{{funk}}") + assert_equal [1, 1, 1], tokenize_line_numbers(" {{funk}} ") + assert_equal [1, 2, 2], tokenize_line_numbers("\n{{funk}}\n") + assert_equal [1, 1, 3], tokenize_line_numbers(" {{\n funk \n}} ") + end + + private + + def tokenize(source) + tokenizer = Liquid::Tokenizer.new(source) + tokens = [] + while t = tokenizer.shift + tokens << t + end + tokens + end + + def tokenize_line_numbers(source) + tokenizer = Liquid::Tokenizer.new(source, true) + line_numbers = [] + loop do + line_number = tokenizer.line_number + if tokenizer.shift + line_numbers << line_number + else + break + end + end + line_numbers + end +end diff --git a/bin/gems/liquid-4.0.4/test/unit/variable_unit_test.rb b/bin/gems/liquid-4.0.4/test/unit/variable_unit_test.rb new file mode 100644 index 00000000..5a21ace8 --- /dev/null +++ b/bin/gems/liquid-4.0.4/test/unit/variable_unit_test.rb @@ -0,0 +1,162 @@ +require 'test_helper' + +class VariableUnitTest < Minitest::Test + include Liquid + + def test_variable + var = create_variable('hello') + assert_equal VariableLookup.new('hello'), var.name + end + + def test_filters + var = create_variable('hello | textileze') + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['textileze', []]], var.filters + + var = create_variable('hello | textileze | paragraph') + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['textileze', []], ['paragraph', []]], var.filters + + var = create_variable(%( hello | strftime: '%Y')) + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['strftime', ['%Y']]], var.filters + + var = create_variable(%( 'typo' | link_to: 'Typo', true )) + assert_equal 'typo', var.name + assert_equal [['link_to', ['Typo', true]]], var.filters + + var = create_variable(%( 'typo' | link_to: 'Typo', false )) + assert_equal 'typo', var.name + assert_equal [['link_to', ['Typo', false]]], var.filters + + var = create_variable(%( 'foo' | repeat: 3 )) + assert_equal 'foo', var.name + assert_equal [['repeat', [3]]], var.filters + + var = create_variable(%( 'foo' | repeat: 3, 3 )) + assert_equal 'foo', var.name + assert_equal [['repeat', [3, 3]]], var.filters + + var = create_variable(%( 'foo' | repeat: 3, 3, 3 )) + assert_equal 'foo', var.name + assert_equal [['repeat', [3, 3, 3]]], var.filters + + var = create_variable(%( hello | strftime: '%Y, okay?')) + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['strftime', ['%Y, okay?']]], var.filters + + var = create_variable(%( hello | things: "%Y, okay?", 'the other one')) + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['things', ['%Y, okay?', 'the other one']]], var.filters + end + + def test_filter_with_date_parameter + var = create_variable(%( '2006-06-06' | date: "%m/%d/%Y")) + assert_equal '2006-06-06', var.name + assert_equal [['date', ['%m/%d/%Y']]], var.filters + end + + def test_filters_without_whitespace + var = create_variable('hello | textileze | paragraph') + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['textileze', []], ['paragraph', []]], var.filters + + var = create_variable('hello|textileze|paragraph') + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['textileze', []], ['paragraph', []]], var.filters + + var = create_variable("hello|replace:'foo','bar'|textileze") + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['replace', ['foo', 'bar']], ['textileze', []]], var.filters + end + + def test_symbol + var = create_variable("http://disney.com/logo.gif | image: 'med' ", error_mode: :lax) + assert_equal VariableLookup.new('http://disney.com/logo.gif'), var.name + assert_equal [['image', ['med']]], var.filters + end + + def test_string_to_filter + var = create_variable("'http://disney.com/logo.gif' | image: 'med' ") + assert_equal 'http://disney.com/logo.gif', var.name + assert_equal [['image', ['med']]], var.filters + end + + def test_string_single_quoted + var = create_variable(%( "hello" )) + assert_equal 'hello', var.name + end + + def test_string_double_quoted + var = create_variable(%( 'hello' )) + assert_equal 'hello', var.name + end + + def test_integer + var = create_variable(%( 1000 )) + assert_equal 1000, var.name + end + + def test_float + var = create_variable(%( 1000.01 )) + assert_equal 1000.01, var.name + end + + def test_dashes + assert_equal VariableLookup.new('foo-bar'), create_variable('foo-bar').name + assert_equal VariableLookup.new('foo-bar-2'), create_variable('foo-bar-2').name + + with_error_mode :strict do + assert_raises(Liquid::SyntaxError) { create_variable('foo - bar') } + assert_raises(Liquid::SyntaxError) { create_variable('-foo') } + assert_raises(Liquid::SyntaxError) { create_variable('2foo') } + end + end + + def test_string_with_special_chars + var = create_variable(%( 'hello! $!@.;"ddasd" ' )) + assert_equal 'hello! $!@.;"ddasd" ', var.name + end + + def test_string_dot + var = create_variable(%( test.test )) + assert_equal VariableLookup.new('test.test'), var.name + end + + def test_filter_with_keyword_arguments + var = create_variable(%( hello | things: greeting: "world", farewell: 'goodbye')) + assert_equal VariableLookup.new('hello'), var.name + assert_equal [['things', [], { 'greeting' => 'world', 'farewell' => 'goodbye' }]], var.filters + end + + def test_lax_filter_argument_parsing + var = create_variable(%( number_of_comments | pluralize: 'comment': 'comments' ), error_mode: :lax) + assert_equal VariableLookup.new('number_of_comments'), var.name + assert_equal [['pluralize', ['comment', 'comments']]], var.filters + end + + def test_strict_filter_argument_parsing + with_error_mode(:strict) do + assert_raises(SyntaxError) do + create_variable(%( number_of_comments | pluralize: 'comment': 'comments' )) + end + end + end + + def test_output_raw_source_of_variable + var = create_variable(%( name_of_variable | upcase )) + assert_equal " name_of_variable | upcase ", var.raw + end + + def test_variable_lookup_interface + lookup = VariableLookup.new('a.b.c') + assert_equal 'a', lookup.name + assert_equal ['b', 'c'], lookup.lookups + end + + private + + def create_variable(markup, options = {}) + Variable.new(markup, ParseContext.new(options)) + end +end diff --git a/bin/gems/listen-3.10.0/CHANGELOG.md b/bin/gems/listen-3.10.0/CHANGELOG.md new file mode 100644 index 00000000..232adbd8 --- /dev/null +++ b/bin/gems/listen-3.10.0/CHANGELOG.md @@ -0,0 +1 @@ +# Moved to [GitHub releases](https://github.com/guard/listen/releases) page. diff --git a/bin/gems/listen-3.10.0/CONTRIBUTING.md b/bin/gems/listen-3.10.0/CONTRIBUTING.md new file mode 100644 index 00000000..7e5b197c --- /dev/null +++ b/bin/gems/listen-3.10.0/CONTRIBUTING.md @@ -0,0 +1,45 @@ +Contribute to Listen +=================== + +File an issue +------------- + +If you haven't already, first see [TROUBLESHOOTING](https://github.com/guard/listen/blob/master/README.md#Issues-and-Troubleshooting) for known issues, solutions and workarounds. + +You can report bugs and feature requests to [GitHub Issues](https://github.com/guard/listen/issues). + +**Please don't ask question in the issue tracker**, instead ask them in our +[Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net). + +Try to figure out where the issue belongs to: Is it an issue with Listen itself or with Guard? + + +**It's most likely that your bug gets resolved faster if you provide as much information as possible!** + +The MOST useful information is debugging output from Listen (`LISTEN_GEM_DEBUGGING=1`) - see [TROUBLESHOOTING](https://github.com/guard/listen/blob/master/README.md#Issues-and-Troubleshooting) for details. + + +Development +----------- + +* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames). +* Source hosted at [GitHub](https://github.com/guard/listen). + +Pull requests are very welcome! Please try to follow these simple rules if applicable: + +* Please create a topic branch for every separate change you make. +* Make sure your patches are well tested. All specs run with `rake spec` must pass. +* Update the [Yard](http://yardoc.org/) documentation. +* Update the [README](https://github.com/guard/listen/blob/master/README.md). +* Please **do not change** the version number. + +The title of your PR will automatically be included in the release notes for the next version of the gem. A maintainer can add one of the following GitHub labels to the PR to automatically categorize it when the release notes are generated: + +- ⚠️ Breaking +- ✨ Feature +- 🐛 Bug Fix +- 📚 Docs +- 🏠 Housekeeping + +For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on +`#guard` (irc.freenode.net). diff --git a/bin/gems/listen-3.10.0/LICENSE.txt b/bin/gems/listen-3.10.0/LICENSE.txt new file mode 100644 index 00000000..b5f71c8b --- /dev/null +++ b/bin/gems/listen-3.10.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Thibaud Guillaume-Gentil + +MIT License + +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/bin/gems/listen-3.10.0/README.md b/bin/gems/listen-3.10.0/README.md new file mode 100644 index 00000000..1ba0e48b --- /dev/null +++ b/bin/gems/listen-3.10.0/README.md @@ -0,0 +1,490 @@ +# Listen + +The `listen` gem listens to file modifications and notifies you about the changes. + +[![Development Status](https://github.com/guard/listen/workflows/Development/badge.svg)](https://github.com/guard/listen/actions?workflow=Development) +[![Gem Version](https://badge.fury.io/rb/listen.svg)](http://badge.fury.io/rb/listen) +[![Code Climate](https://codeclimate.com/github/guard/listen.svg)](https://codeclimate.com/github/guard/listen) +[![Coverage Status](https://coveralls.io/repos/guard/listen/badge.svg?branch=master)](https://coveralls.io/r/guard/listen) + +## Features + +* OS-optimized adapters on MRI for Mac OS X 10.6+, Linux, \*BSD and Windows, [more info](#listen-adapters) below. +* Detects file modification, addition and removal. +* You can watch multiple directories. +* Regexp-patterns for ignoring paths for more accuracy and speed +* Increased change detection accuracy on OS X HFS and VFAT volumes. +* Continuous Integration: tested on selected Ruby environments via [Github Workflows](https://github.com/guard/listen/tree/master/.github/workflows). + +## Issues / limitations + +* Limited support for symlinked directories ([#279](https://github.com/guard/listen/issues/279)): + * Symlinks are always followed ([#25](https://github.com/guard/listen/issues/25)). + * Symlinked directories pointing within a watched directory are not supported ([#273](https://github.com/guard/listen/pull/273). +* No directory/adapter-specific configuration options. +* Support for plugins planned for future. +* TCP functionality was removed in `listen` [3.0.0](https://github.com/guard/listen/releases/tag/v3.0.0) ([#319](https://github.com/guard/listen/issues/319), [#218](https://github.com/guard/listen/issues/218)). There are plans to extract this feature to separate gems ([#258](https://github.com/guard/listen/issues/258)), until this is finished, you can use by locking the `listen` gem to version `'~> 2.10'`. +* Some filesystems won't work without polling (VM/Vagrant Shared folders, NFS, Samba, sshfs, etc.). +* Windows and \*BSD adapter aren't continuously and automatically tested. +* OSX adapter has some performance limitations ([#342](https://github.com/guard/listen/issues/342)). +* Listeners do not notify across forked processes, if you wish for multiple processes to receive change notifications you must [listen inside of each process](https://github.com/guard/listen/issues/398#issuecomment-223957952). + +Pull requests or help is very welcome for these. + +## Install + +The simplest way to install `listen` is to use [Bundler](http://bundler.io). + +```ruby +gem 'listen' +``` + +## Complete Example +Here is a complete example of using the `listen` gem: +```ruby +require 'listen' + +listener = Listen.to('/srv/app') do |modified, added, removed| + puts(modified: modified, added: added, removed: removed) +end +listener.start +sleep +``` +Running the above in the background, you can see the callback block being called in response to each command: +``` +$ cd /srv/app +$ touch a.txt +{:modified=>[], :added=>["/srv/app/a.txt"], :removed=>[]} + +$ echo more >> a.txt +{:modified=>["/srv/app/a.txt"], :added=>[], :removed=>[]} + +$ mv a.txt b.txt +{:modified=>[], :added=>["/srv/app/b.txt"], :removed=>["/srv/app/a.txt"]} + +$ vi b.txt +# add a line to this new file and press ZZ to save and exit +{:modified=>["/srv/app/b.txt"], :added=>[], :removed=>[]} + +$ vi c.txt +# add a line and press ZZ to save and exit +{:modified=>[], :added=>["/srv/app/c.txt"], :removed=>[]} + +$ rm b.txt c.txt +{:modified=>[], :added=>[], :removed=>["/srv/app/b.txt", "/srv/app/c.txt"]} +``` + +## Usage + +Call `Listen.to` with one or more directories and the "changes" callback passed as a block. + +``` ruby +listener = Listen.to('dir/to/listen', 'dir/to/listen2') do |modified, added, removed| + puts "modified absolute path array: #{modified}" + puts "added absolute path array: #{added}" + puts "removed absolute path array: #{removed}" +end +listener.start # starts a listener thread--does not block + +# do whatever you want here...just don't exit the process :) + +sleep +``` +## Changes Callback + +Changes to the listened-to directories are reported by the listener thread in a callback. +The callback receives **three** array parameters: `modified`, `added` and `removed`, in that order. +Each of these three is always an array with 0 or more entries. +Each array entry is an absolute path. + +### Pause / start / stop + +Listeners can also be easily paused and later un-paused with start: + +``` ruby +listener = Listen.to('dir/path/to/listen') { |modified, added, removed| puts 'handle changes here...' } + +listener.start +listener.paused? # => false +listener.processing? # => true + +listener.pause # stops processing changes (but keeps on collecting them) +listener.paused? # => true +listener.processing? # => false + +listener.start # resumes processing changes +listener.stop # stop both listening to changes and processing them +``` + + Note: While paused, `listen` keeps on collecting changes in the background - to clear them, call `stop`. + + Note: You should keep track of all started listeners and `stop` them properly on finish. + +### Ignore / ignore! + +`Listen` ignores some directories and extensions by default (See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer). +You can add ignoring patterns with the `ignore` option/method or overwrite default with `ignore!` option/method. + +``` ruby +listener = Listen.to('dir/path/to/listen', ignore: /\.txt/) { |modified, added, removed| # ... } +listener.start +listener.ignore! /\.pkg/ # overwrite all patterns and only ignore pkg extension. +listener.ignore /\.rb/ # ignore rb extension in addition of pkg. +sleep +``` + +Note: `:ignore` regexp patterns are evaluated against relative paths. + +Note: Ignoring paths does not improve performance, except when Polling ([#274](https://github.com/guard/listen/issues/274)). + +### Only + +`Listen` watches all files (less the ignored ones) by default. If you want to only listen to a specific type of file (i.e., just `.rb` extension), you should use the `only` option/method. + +``` ruby +listener = Listen.to('dir/path/to/listen', only: /\.rb$/) { |modified, added, removed| # ... } +listener.start +listener.only /_spec\.rb$/ # overwrite all existing only patterns. +sleep +``` + +Note: `:only` regexp patterns are evaluated only against relative **file** paths. + + +## Options + +All the following options can be set through the `Listen.to` after the directory path(s) params. + +``` ruby +ignore: [%r{/foo/bar}, /\.pid$/, /\.coffee$/] # Ignore a list of paths + # default: See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer + +ignore!: %r{/foo/bar} # Same as ignore options, but overwrite default ignored paths. + +only: %r{.rb$} # Only listen to specific files + # default: none + +latency: 0.5 # Set the delay (**in seconds**) between checking for changes + # default: 0.25 sec (1.0 sec for polling) + +wait_for_delay: 4 # Set the delay (**in seconds**) between calls to the callback when changes exist + # default: 0.10 sec + +force_polling: true # Force the use of the polling adapter + # default: none + +relative: false # Whether changes should be relative to current dir or not + # default: false + +polling_fallback_message: 'custom message' # Set a custom polling fallback message (or disable it with false) + # default: "Listen will be polling for changes. Learn more at https://github.com/guard/listen#listen-adapters." +``` + +## Logging and Debugging + +`Listen` logs its activity to `Listen.logger`. +This is the primary method of debugging. + +### Custom Logger +You can call `Listen.logger =` to set a custom `listen` logger for the process. For example: +``` ruby +Listen.logger = Rails.logger +``` + +### Default Logger +If no custom logger is set, a default `listen` logger which logs to to `STDERR` will be created and assigned to `Listen.logger`. + +The default logger defaults to the `error` logging level (severity). +You can override the logging level by setting the environment variable `LISTEN_GEM_DEBUGGING=`. +For ``, all standard `::Logger` levels are supported, with any mix of upper-/lower-case: +``` ruby +export LISTEN_GEM_DEBUGGING=debug # or 2 [deprecated] +export LISTEN_GEM_DEBUGGING=info # or 1 or true or yes [deprecated] +export LISTEN_GEM_DEBUGGING=warn +export LISTEN_GEM_DEBUGGING=fatal +export LISTEN_GEM_DEBUGGING=error +``` +The default of `error` will be used if an unsupported value is set. + +Note: The alternate values `1`, `2`, `true` and `yes` shown above are deprecated and will be removed from `listen` v4.0. + +### Disabling Logging +If you want to disable `listen` logging, set +``` ruby +Listen.logger = ::Logger.new('/dev/null') +``` + +### Adapter Warnings +If listen is having trouble with the underlying adapter, it will display warnings with `Kernel#warn` by default, +which in turn writes to STDERR. +Sometimes this is not desirable, for example in an environment where STDERR is ignored. +For these reasons, the behavior can be configured using `Listen.adapter_warn_behavior =`: +``` ruby +Listen.adapter_warn_behavior = :warn # default (true means the same) +Listen.adapter_warn_behavior = :log # send to logger.warn +Listen.adapter_warn_behavior = :silent # suppress all adapter warnings (nil or false mean the same) +``` +Also there are some cases where specific warnings are not helpful. +For example, if you are using the polling adapter--and expect to--you can suppress the warning about it +by providing a callable object like a lambda or proc that determines the behavior based on the `message`: +``` ruby +Listen.adapter_warn_behavior = ->(message) do + case message + when /Listen will be polling for changes/ + :silent + when /directory is already being watched/ + :log + else + :warn + end +end +``` +In cases where the `Listen` gem is embedded inside another service--such as `guard`--the above configuration +can be set in the environment variable `LISTEN_GEM_ADAPTER_WARN_BEHAVIOR=warn|log|silent`. + +## Listen Adapters + +The `Listen` gem has a set of adapters to notify it when there are changes. + +There are 4 OS-specific adapters to support Darwin, Linux, \*BSD and Windows. +These adapters are fast as they use some system-calls to implement the notifying function. + +There is also a polling adapter - although it's much slower than other adapters, +it works on every platform/system and scenario (including network filesystems such as VM shared folders). + +The Darwin and Linux adapters are dependencies of the `listen` gem so they work out of the box. For other adapters a specific gem will have to be added to your Gemfile, please read below. + +The `listen` gem will choose the best adapter automatically, if present. If you +want to force the use of the polling adapter, use the `:force_polling` option +while initializing the listener. + +### On Windows + +If you are on Windows, it's recommended to use the [`wdm`](https://github.com/Maher4Ever/wdm) adapter instead of polling. + +Please add the following to your Gemfile: + +```ruby +gem 'wdm', '>= 0.1.0' +``` + +### On \*BSD + +If you are on \*BSD you can try to use the [`rb-kqueue`](https://github.com/mat813/rb-kqueue) adapter instead of polling. + +Please add the following to your Gemfile: + +```ruby +gem 'rb-kqueue', '>= 0.2' +``` + +### Getting the [polling fallback message](#options)? + +If you see: +``` +Listen will be polling for changes. +``` + +This means the Listen gem can’t find an optimized adapter. Typically this is caused by: + +- You’re on Windows and WDM gem isn’t installed. +- You’re running the app without Bundler or RubyGems. +- Using Sass which includes an ancient (the “dinosaur” type of ancient) version of the Listen gem. + +Possible solutions: + +1. Suppress the message by using the :force_polling option. Or, you could just ignore the message since it’s harmless. +2. Windows users: Install the WDM gem. +3. Upgrade Ruby (use RubyInstaller for Windows or RVM/rbenv for Mac) and RubyGems. +3. Run your apps using Bundler. +4. Sass users: Install the latest version of Listen and try again. + +#### Simplified Bundler and Sass example +Create a Gemfile with these lines: +``` +source 'https://rubygems.org' +gem 'listen' +gem 'sass' +``` +Next, use Bundler to update gems: +``` +$ bundle update +$ bundle exec sass --watch # ... or whatever app is using Listen. +``` + +### Increasing the amount of inotify watchers + +If you are running Debian, RedHat, or another similar Linux distribution, run the following in a terminal: +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf" +$ sudo sysctl -p +``` +If you are running ArchLinux, search the `/etc/sysctl.d/` directory for config files with the setting: +``` +$ grep -H -s "fs.inotify.max_user_watches" /etc/sysctl.d/* +/etc/sysctl.d/40-max_user_watches.conf:fs.inotify.max_user_watches=100000 +``` +Then change the setting in the file you found above to a higher value (see [here](https://www.archlinux.org/news/deprecation-of-etcsysctlconf/) for why): +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 > /etc/sysctl.d/40-max-user-watches.conf" +$ sudo sysctl --system +``` + +#### The technical details +Listen uses `inotify` by default on Linux to monitor directories for changes. +It's not uncommon to encounter a system limit on the number of files you can monitor. +For example, Ubuntu Lucid's (64bit) `inotify` limit is set to 8192. + +You can get your current inotify file watch limit by executing: +``` +$ cat /proc/sys/fs/inotify/max_user_watches +``` +When this limit is not enough to monitor all files inside a directory, the limit must be increased for Listen to work properly. + +You can set a new limit temporarily with: +``` +$ sudo sysctl fs.inotify.max_user_watches=524288 +$ sudo sysctl -p +``` +If you like to make your limit permanent, use: +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf" +$ sudo sysctl -p +``` +You may also need to pay attention to the values of `max_queued_events` and `max_user_instances` if Listen keeps on complaining. + +While 524,288 is the maximum number of files that can be watched. Each file watch [takes up 1,080 bytes](https://stackoverflow.com/a/7091897/1156119) on a 64-bit system, so assuming that all 524,288 watches are consumed, that allocates around 540 MiB. +If you're in an environment that is particularly memory-constrained, consider to specify a lower number. + +#### More info +Man page for [inotify(7)](https://linux.die.net/man/7/inotify). +Blog post: [limit of inotify](https://blog.sorah.jp/2012/01/24/inotify-limitation). + +### Issues and Troubleshooting + +If the gem doesn't work as expected, start by setting `LISTEN_GEM_DEBUGGING=debug` or `LISTEN_GEM_DEBUGGING=info` as described above in [Logging and Debugging](#logging-and-debugging). + +*NOTE: without providing the output after setting the `LISTEN_GEM_DEBUGGING=debug` environment variable, it is usually impossible to guess why `listen` is not working as expected.* + +#### 3 steps before you start diagnosing problems +These 3 steps will: + +- help quickly troubleshoot obscure problems (trust me, most of them are obscure) +- help quickly identify the area of the problem (a full list is below) +- help you get familiar with listen's diagnostic mode (it really comes in handy, trust me) +- help you create relevant output before you submit an issue (so we can respond with answers instead of tons of questions) + +Step 1 - The most important option in Listen +For effective troubleshooting set the `LISTEN_GEM_DEBUGGING=info` variable before starting `listen`. + +Step 2 - Verify polling works +Polling has to work ... or something is really wrong (and we need to know that before anything else). + +(see force_polling option). + +After starting `listen`, you should see something like: +``` +INFO -- : Record.build(): 0.06773114204406738 seconds +``` +Step 3 - Trigger some changes directly without using editors or apps +Make changes e.g. touch foo or echo "a" >> foo (for troubleshooting, avoid using an editor which could generate too many misleading events). + +You should see something like: +``` +INFO -- : listen: raw changes: [[:added, "/home/me/foo"]] +INFO -- : listen: final changes: {:modified=>[], :added=>["/home/me/foo"], :removed=>[]} +``` +"raw changes" contains changes collected during the :wait_for_delay and :latency intervals, while "final changes" is what listen decided are relevant changes (for better editor support). + +## Performance + +If `listen` seems slow or unresponsive, make sure you're not using the Polling adapter (you should see a warning upon startup if you are). + +Also, if the directories you're watching contain many files, make sure you're: + +* not using Polling (ideally) +* using `:ignore` and `:only` options to avoid tracking directories you don't care about (important with Polling and on MacOS) +* running `listen` with the `:latency` and `:wait_for_delay` options not too small or too big (depends on needs) +* not watching directories with log files, database files or other frequently changing files +* not using a version of `listen` prior to 2.7.7 +* not getting silent crashes within `listen` (see `LISTEN_GEM_DEBUGGING=debug`) +* not running multiple instances of `listen` in the background +* using a file system with atime modification disabled (ideally) +* not using a filesystem with inaccurate file modification times (ideally), e.g. HFS, VFAT +* not buffering to a slow terminal (e.g. transparency + fancy font + slow gfx card + lots of output) +* ideally not running a slow encryption stack, e.g. btrfs + ecryptfs + +When in doubt, `LISTEN_GEM_DEBUGGING=debug` can help discover the actual events and time they happened. + +## Tips and Techniques +- Watch only directories you're interested in. +- Set your editor to save quickly (e.g. without backup files, without atomic-save) +- Tweak the `:latency` and `:wait_for_delay` options until you get good results (see [options](#options)). +- Add `:ignore` rules to silence all events you don't care about (reduces a lot of noise, especially if you use it on directories) + +## Development + +* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames). +* Source hosted at [GitHub](https://github.com/guard/listen). + +Pull requests are very welcome! Please try to follow these simple rules if applicable: + +* Please create a topic branch for every separate change you make. +* Make sure your patches are well tested. All specs must pass on [CI](https://github.com/guard/listen/actions?workflow=Development). +* Update the [Yard](http://yardoc.org/) documentation. +* Update the [README](https://github.com/guard/listen/blob/master/README.md). +* Please **do not change** the version number. + +For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on +`#guard` (irc.freenode.net). + +## Releasing + +### Prerequisites + +* You must have commit rights to the GitHub repository. +* You must have push rights for rubygems.org. + +### How to release + +1. Run `bundle install` to make sure that you have all the gems necessary for testing and releasing. +2. **Ensure all tests are passing by running `bundle exec rake`.** +3. Determine which would be the correct next version number according to [semver](http://semver.org/). +4. Update the version in `./lib/listen/version.rb`. +5. Update the version in the Install section of `./README.md` (`gem 'listen', '~> X.Y'`). +6. Commit the version in a single commit, the message should be "Preparing vX.Y.Z" +7. Run `bundle exec rake release:full`; this will tag, push to GitHub, and publish to rubygems.org. +8. Update and publish the release notes on the [GitHub releases page](https://github.com/guard/listen/releases) if necessary + +## Acknowledgments + +* [Michael Kessler (netzpirat)][] for having written the [initial specs](https://github.com/guard/listen/commit/1e457b13b1bb8a25d2240428ce5ed488bafbed1f). +* [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][]. +* [Natalie Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper. +* [Mathieu Arnold (mat813)][] for [rb-kqueue][], a simple kqueue wrapper. +* [Maher Sallam][] for [wdm][], windows support wouldn't exist without him. +* [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration. + +## Author + +[Thibaud Guillaume-Gentil](https://github.com/thibaudgg) ([@thibaudgg](https://twitter.com/thibaudgg)) + +## Contributors + +[https://github.com/guard/listen/graphs/contributors](https://github.com/guard/listen/graphs/contributors) + +[Thibaud Guillaume-Gentil (thibaudgg)]: https://github.com/thibaudgg +[Maher Sallam]: https://github.com/Maher4Ever +[Michael Kessler (netzpirat)]: https://github.com/netzpirat +[Travis Tilley (ttilley)]: https://github.com/ttilley +[fssm]: https://github.com/ttilley/fssm +[rb-fsevent]: https://github.com/thibaudgg/rb-fsevent +[Mathieu Arnold (mat813)]: https://github.com/mat813 +[Natalie Weizenbaum (nex3)]: https://github.com/nex3 +[rb-inotify]: https://github.com/nex3/rb-inotify +[stereobooster]: https://github.com/stereobooster +[rb-fchange]: https://github.com/stereobooster/rb-fchange +[rb-kqueue]: https://github.com/mat813/rb-kqueue +[Yehuda Katz (wycats)]: https://github.com/wycats +[vigilo]: https://github.com/wycats/vigilo +[wdm]: https://github.com/Maher4Ever/wdm diff --git a/bin/gems/listen-3.10.0/bin/listen b/bin/gems/listen-3.10.0/bin/listen new file mode 100755 index 00000000..59ade96d --- /dev/null +++ b/bin/gems/listen-3.10.0/bin/listen @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'listen' +require 'listen/cli' + +if !defined?(JRUBY_VERSION) && Signal.list.keys.include?('INT') + Signal.trap('INT') { Thread.new { Listen.stop } } +end + +Listen::CLI.start diff --git a/bin/gems/listen-3.10.0/lib/listen.rb b/bin/gems/listen-3.10.0/lib/listen.rb new file mode 100644 index 00000000..03857fe4 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'logger' +require 'weakref' +require 'listen/logger' +require 'listen/listener' + +# Won't print anything by default because of level - unless you've set +# LISTEN_GEM_DEBUGGING or provided your own logger with a high enough level +Listen.logger.info "Listen loglevel set to: #{Listen.logger.level}" +Listen.logger.info "Listen version: #{Listen::VERSION}" + +module Listen + @listeners = Queue.new + + class << self + # Listens to file system modifications on a either single directory or + # multiple directories. + # + # @param (see Listen::Listener#new) + # + # @yield [modified, added, removed] the changed files + # @yieldparam [Array] modified the list of modified files + # @yieldparam [Array] added the list of added files + # @yieldparam [Array] removed the list of removed files + # + # @return [Listen::Listener] the listener + # + def to(*args, &block) + Listener.new(*args, &block).tap do |listener| + @listeners.enq(WeakRef.new(listener)) + end + end + + # This is used by the `listen` binary to handle Ctrl-C + # + def stop + while (listener = @listeners.deq(true)) + begin + listener.stop + rescue WeakRef::RefError + end + end + rescue ThreadError + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter.rb b/bin/gems/listen-3.10.0/lib/listen/adapter.rb new file mode 100644 index 00000000..dce86236 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'listen/adapter/base' +require 'listen/adapter/bsd' +require 'listen/adapter/darwin' +require 'listen/adapter/linux' +require 'listen/adapter/polling' +require 'listen/adapter/windows' + +module Listen + module Adapter + OPTIMIZED_ADAPTERS = [Darwin, Linux, BSD, Windows].freeze + POLLING_FALLBACK_MESSAGE = 'Listen will be polling for changes.'\ + 'Learn more at https://github.com/guard/listen#listen-adapters.' + + class << self + def select(options = {}) + Listen.logger.debug 'Adapter: considering polling ...' + return Polling if options[:force_polling] + Listen.logger.debug 'Adapter: considering optimized backend...' + return _usable_adapter_class if _usable_adapter_class + Listen.logger.debug 'Adapter: falling back to polling...' + _warn_polling_fallback(options) + Polling + rescue + Listen.logger.warn format('Adapter: failed: %s:%s', $ERROR_POSITION.inspect, + $ERROR_POSITION * "\n") + raise + end + + private + + def _usable_adapter_class + OPTIMIZED_ADAPTERS.find(&:usable?) + end + + def _warn_polling_fallback(options) + msg = options.fetch(:polling_fallback_message, POLLING_FALLBACK_MESSAGE) + Listen.adapter_warn("[Listen warning]:\n #{msg}") if msg + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/base.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/base.rb new file mode 100644 index 00000000..b7e10390 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/base.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'listen/options' +require 'listen/record' +require 'listen/change' +require 'listen/thread' + +module Listen + module Adapter + class Base + attr_reader :options, :config + + # TODO: only used by tests + DEFAULTS = {}.freeze + + def initialize(config) + @started = false + @config = config + + @configured = nil + + fail 'No directories to watch!' if config.directories.empty? + + defaults = self.class.const_get('DEFAULTS') + @options = Listen::Options.new(config.adapter_options, defaults) + rescue + _log_exception 'adapter config failed: %s:%s called from: %s', caller + raise + end + + # TODO: it's a separate method as a temporary workaround for tests + # rubocop:disable Metrics/MethodLength + def configure + if @configured + Listen.logger.warn('Adapter already configured!') + return + end + + @configured = true + + @callbacks ||= {} + config.directories.each do |dir| + callback = @callbacks[dir] || lambda do |event| + _process_event(dir, event) + end + @callbacks[dir] = callback + _configure(dir, &callback) + end + + @snapshots ||= {} + # TODO: separate config per directory (some day maybe) + change_config = Change::Config.new(config.queue, config.silencer) + config.directories.each do |dir| + record = Record.new(dir, config.silencer) + snapshot = Change.new(change_config, record) + @snapshots[dir] = snapshot + end + end + # rubocop:enable Metrics/MethodLength + + def started? + @started + end + + def start + configure + + if started? + Listen.logger.warn('Adapter already started!') + return + end + + @started = true + + @run_thread = Listen::Thread.new("run_thread") do + @snapshots.each_value do |snapshot| + _timed('Record.build()') { snapshot.record.build } + end + _run + end + end + + def stop + _stop + config.queue.close # this causes queue.pop to return `nil` to the front-end + end + + private + + def _stop + @run_thread&.kill + @run_thread = nil + end + + def _timed(title) + start = MonotonicTime.now + yield + diff = MonotonicTime.now - start + Listen.logger.info format('%s: %.05f seconds', title, diff) + rescue + Listen.logger.warn "#{title} crashed: #{$ERROR_INFO.inspect}" + raise + end + + # TODO: allow backend adapters to pass specific invalidation objects + # e.g. Darwin -> DirRescan, INotify -> MoveScan, etc. + def _queue_change(type, dir, rel_path, options) + @snapshots[dir].invalidate(type, rel_path, options) + end + + def _log_exception(msg, caller_stack) + formatted = format( + msg, + $ERROR_INFO, + $ERROR_POSITION * "\n", + caller_stack * "\n" + ) + + Listen.logger.error(formatted) + end + + class << self + def usable? + const_get('OS_REGEXP') =~ RbConfig::CONFIG['target_os'] + end + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/bsd.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/bsd.rb new file mode 100644 index 00000000..186ded37 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/bsd.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +# Listener implementation for BSD's `kqueue`. +# @see http://www.freebsd.org/cgi/man.cgi?query=kqueue +# @see https://github.com/mat813/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb +# +module Listen + module Adapter + class BSD < Base + OS_REGEXP = /bsd|dragonfly/i + + DEFAULTS = { + events: [ + :delete, + :write, + :extend, + :attrib, + :rename + # :link, :revoke + ] + }.freeze + + BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '') + Please add the following to your Gemfile to avoid polling for changes: + gem 'rb-kqueue', '>= 0.2' + EOS + + def self.usable? + return false unless super + require 'rb-kqueue' + require 'find' + true + rescue LoadError + Listen.adapter_warn(BUNDLER_DECLARE_GEM) + false + end + + private + + def _configure(directory, &callback) + @worker ||= KQueue::Queue.new + @callback = callback + # use Record to make a snapshot of dir, so we + # can detect new files + _find(directory.to_s) { |path| _watch_file(path, @worker) } + end + + def _run + @worker.run + end + + def _process_event(dir, event) + full_path = _event_path(event) + if full_path.directory? + # Force dir content tracking to kick in, or we won't have + # names of added files + _queue_change(:dir, dir, '.', recursive: true) + elsif full_path.exist? + path = full_path.relative_path_from(dir) + _queue_change(:file, dir, path.to_s, change: _change(event.flags)) + end + + # If it is a directory, and it has a write flag, it means a + # file has been added so find out which and deal with it. + # No need to check for removed files, kqueue will forget them + # when the vfs does. + _watch_for_new_file(event) if full_path.directory? + end + + def _change(event_flags) + { modified: [:attrib, :extend], + added: [:write], + removed: [:rename, :delete] }.each do |change, flags| + return change unless (flags & event_flags).empty? + end + nil + end + + def _event_path(event) + Pathname.new(event.watcher.path) + end + + def _watch_for_new_file(event) + queue = event.watcher.queue + _find(_event_path(event).to_s) do |file_path| + unless queue.watchers.find { |_, v| v.path == file_path.to_s } + _watch_file(file_path, queue) + end + end + end + + def _watch_file(path, queue) + queue.watch_file(path, *options.events, &@callback) + rescue Errno::ENOENT => e + Listen.logger.warn "kqueue: watch file failed: #{e.message}" + end + + # Quick rubocop workaround + def _find(*paths, &block) + Find.send(:find, *paths, &block) + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/config.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/config.rb new file mode 100644 index 00000000..5a068a7c --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/config.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'pathname' + +module Listen + module Adapter + class Config + attr_reader :directories, :silencer, :queue, :adapter_options + + def initialize(directories, queue, silencer, adapter_options) + # Default to current directory if no directories are supplied + directories = [Dir.pwd] if directories.to_a.empty? + + # TODO: fix (flatten, array, compact?) + @directories = directories.map do |directory| + Pathname.new(directory.to_s).realpath + end + + @directories.each do |pathname| + unless pathname.directory? + fail ArgumentError, "must be a directory: #{pathname}" + end + end + + @silencer = silencer + @queue = queue + @adapter_options = adapter_options + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/darwin.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/darwin.rb new file mode 100644 index 00000000..07c7a567 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/darwin.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'listen/thread' + +module Listen + module Adapter + # Adapter implementation for Mac OS X `FSEvents`. + # + class Darwin < Base + OS_REGEXP = /darwin(?(1|2)\d+)/i + + # The default delay between checking for changes. + DEFAULTS = { latency: 0.1 }.freeze + + INCOMPATIBLE_GEM_VERSION = <<-EOS.gsub(/^ {8}/, '') + rb-fsevent > 0.9.4 no longer supports OS X 10.6 through 10.8. + + Please add the following to your Gemfile to avoid polling for changes: + require 'rbconfig' + if RbConfig::CONFIG['target_os'] =~ /darwin(1[0-3])/i + gem 'rb-fsevent', '<= 0.9.4' + end + EOS + + def self.usable? + version = RbConfig::CONFIG['target_os'][OS_REGEXP, :major_version] + return false unless version + return true if version.to_i >= 13 # darwin13 is OS X 10.9 + + require 'rb-fsevent' + fsevent_version = Gem::Version.new(FSEvent::VERSION) + return true if fsevent_version <= Gem::Version.new('0.9.4') + Listen.adapter_warn(INCOMPATIBLE_GEM_VERSION) + false + end + + private + + def _configure(dir, &callback) + @callbacks[dir] = callback + end + + def _run + require 'rb-fsevent' + worker = FSEvent.new + dirs_to_watch = @callbacks.keys.map(&:to_s) + Listen.logger.info { "fsevent: watching: #{dirs_to_watch.inspect}" } + worker.watch(dirs_to_watch, { latency: options.latency }, &method(:_process_changes)) + @worker_thread = Listen::Thread.new("worker_thread") { worker.run } + end + + def _process_changes(dirs) + dirs.each do |dir| + dir = Pathname.new(dir.sub(%r{/$}, '')) + + @callbacks.each do |watched_dir, callback| + if watched_dir.eql?(dir) || Listen::Directory.ascendant_of?(watched_dir, dir) + callback.call(dir) + end + end + end + end + + def _process_event(dir, path) + Listen.logger.debug { "fsevent: processing path: #{path.inspect}" } + # TODO: does this preserve symlinks? + rel_path = path.relative_path_from(dir).to_s + _queue_change(:dir, dir, rel_path, recursive: true) + end + + def _stop + @worker_thread&.kill + super + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/linux.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/linux.rb new file mode 100644 index 00000000..5b78ee3d --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/linux.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # @see https://github.com/nex3/rb-inotify + class Linux < Base + OS_REGEXP = /linux/i + + DEFAULTS = { + events: [ + :recursive, + :attrib, + :create, + :modify, + :delete, + :move, + :close_write + ], + wait_for_delay: 0.1 + }.freeze + + private + + README_URL = 'https://github.com/guard/listen'\ + '/blob/master/README.md#increasing-the-amount-of-inotify-watchers' + + def _configure(directory, &callback) + require 'rb-inotify' + @worker ||= ::INotify::Notifier.new + @worker.watch(directory.to_s, *options.events, &callback) + rescue Errno::ENOSPC + raise ::Listen::Error::INotifyMaxWatchesExceeded, <<~EOS + Unable to monitor directories for changes because iNotify max watches exceeded. See #{README_URL} . + EOS + end + + def _run + @worker.run + end + + # rubocop:disable Metrics/MethodLength + def _process_event(dir, event) + # NOTE: avoid using event.absolute_name since new API + # will need to have a custom recursion implemented + # to properly match events to configured directories + path = Pathname.new(event.watcher.path) + event.name + rel_path = path.relative_path_from(dir).to_s + + Listen.logger.debug { "inotify: #{rel_path} (#{event.flags.inspect})" } + + if /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT'] + if (event.flags & [:moved_to, :moved_from]) || _dir_event?(event) + rel_path = path.dirname.relative_path_from(dir).to_s + end + _queue_change(:dir, dir, rel_path, {}) + return + end + + return if _skip_event?(event) + + cookie_params = event.cookie.zero? ? {} : { cookie: event.cookie } + + # NOTE: don't pass options to force rescanning the directory, so we can + # detect moving/deleting a whole tree + if _dir_event?(event) + _queue_change(:dir, dir, rel_path, cookie_params) + return + end + + params = cookie_params.merge(change: _change(event.flags)) + + _queue_change(:file, dir, rel_path, params) + end + # rubocop:enable Metrics/MethodLength + + def _skip_event?(event) + # Event on root directory + return true if event.name == '' + # INotify reports changes to files inside directories as events + # on the directories themselves too. + # + # @see http://linux.die.net/man/7/inotify + _dir_event?(event) && (event.flags & [:close, :modify]).any? + end + + def _change(event_flags) + { modified: [:attrib, :close_write], + moved_to: [:moved_to], + moved_from: [:moved_from], + added: [:create], + removed: [:delete] }.each do |change, flags| + return change unless (flags & event_flags).empty? + end + nil + end + + def _dir_event?(event) + event.flags.include?(:isdir) + end + + def _stop + @worker&.close + + super + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/polling.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/polling.rb new file mode 100644 index 00000000..57cda9c9 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/polling.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # Polling Adapter that works cross-platform and + # has no dependencies. This is the adapter that + # uses the most CPU processing power and has higher + # file IO than the other implementations. + # + class Polling < Base + OS_REGEXP = // # match every OS + + DEFAULTS = { latency: 1.0, wait_for_delay: 0.05 }.freeze + + private + + def _configure(_, &callback) + @polling_callbacks ||= [] + @polling_callbacks << callback + end + + def _run + loop do + start = MonotonicTime.now + @polling_callbacks.each do |callback| + callback.call(nil) + if (nap_time = options.latency - (MonotonicTime.now - start)) > 0 + # TODO: warn if nap_time is negative (polling too slow) + sleep(nap_time) + end + end + end + end + + def _process_event(dir, _) + _queue_change(:dir, dir, '.', recursive: true) + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/adapter/windows.rb b/bin/gems/listen-3.10.0/lib/listen/adapter/windows.rb new file mode 100644 index 00000000..799d4587 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/adapter/windows.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # Adapter implementation for Windows `wdm`. + # + class Windows < Base + OS_REGEXP = /mswin|mingw|cygwin/i + + BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '') + Please add the following to your Gemfile to avoid polling for changes: + gem 'wdm', '>= 0.1.0' + EOS + + def self.usable? + return false unless super + require 'wdm' + true + rescue LoadError + Listen.logger.debug format('wdm - load failed: %s:%s', $ERROR_INFO, + $ERROR_POSITION * "\n") + + Listen.adapter_warn(BUNDLER_DECLARE_GEM) + false + end + + private + + def _configure(dir) + require 'wdm' + Listen.logger.debug 'wdm - starting...' + @worker ||= WDM::Monitor.new + @worker.watch_recursively(dir.to_s, :files) do |change| + yield([:file, change]) + end + + @worker.watch_recursively(dir.to_s, :directories) do |change| + yield([:dir, change]) + end + + @worker.watch_recursively(dir.to_s, :attributes, :last_write) do |change| + yield([:attr, change]) + end + end + + def _run + @worker.run! + end + + # rubocop:disable Metrics/MethodLength + def _process_event(dir, event) + Listen.logger.debug "wdm - callback: #{event.inspect}" + + type, change = event + + full_path = Pathname(change.path) + + rel_path = full_path.relative_path_from(dir).to_s + + options = { change: _change(change.type) } + + case type + when :file + _queue_change(:file, dir, rel_path, options) + when :attr + unless full_path.directory? + _queue_change(:file, dir, rel_path, options) + end + when :dir + case change.type + when :removed + # TODO: check if watched dir? + _queue_change(:dir, dir, Pathname(rel_path).dirname.to_s, {}) + when :added + _queue_change(:dir, dir, rel_path, {}) + # do nothing - changed directory means either: + # - removed subdirs (handled above) + # - added subdirs (handled above) + # - removed files (handled by _file_callback) + # - added files (handled by _file_callback) + # so what's left? + end + end + end + # rubocop:enable Metrics/MethodLength + + def _change(type) + { modified: [:modified, :attrib], # TODO: is attrib really passed? + added: [:added, :renamed_new_file], + removed: [:removed, :renamed_old_file] }.find do |change, types| + types.include?(type) and break change + end + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/backend.rb b/bin/gems/listen-3.10.0/lib/listen/backend.rb new file mode 100644 index 00000000..cab286c1 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/backend.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'listen/adapter' +require 'listen/adapter/base' +require 'listen/adapter/config' + +require 'forwardable' + +# This class just aggregates configuration object to avoid Listener specs +# from exploding with huge test setup blocks +module Listen + class Backend + extend Forwardable + + def initialize(directories, queue, silencer, config) + adapter_select_opts = config.adapter_select_options + + adapter_class = Adapter.select(adapter_select_opts) + + # Use default from adapter if possible + @min_delay_between_events = config.min_delay_between_events + @min_delay_between_events ||= adapter_class::DEFAULTS[:wait_for_delay] + @min_delay_between_events ||= 0.1 + + adapter_opts = config.adapter_instance_options(adapter_class) + + aconfig = Adapter::Config.new(directories, queue, silencer, adapter_opts) + @adapter = adapter_class.new(aconfig) + end + + delegate start: :adapter + delegate stop: :adapter + + attr_reader :min_delay_between_events + + private + + attr_reader :adapter + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/change.rb b/bin/gems/listen-3.10.0/lib/listen/change.rb new file mode 100644 index 00000000..c19b9001 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/change.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'listen/file' +require 'listen/directory' + +module Listen + # TODO: rename to Snapshot + class Change + # TODO: test this class for coverage + class Config + def initialize(queue, silencer) + @queue = queue + @silencer = silencer + end + + def silenced?(path, type) + @silencer.silenced?(Pathname(path), type) + end + + def queue(*args) + @queue << args + end + end + + attr_reader :record + + def initialize(config, record) + @config = config + @record = record + end + + # Invalidate some part of the snapshot/record (dir, file, subtree, etc.) + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity + def invalidate(type, rel_path, options) + watched_dir = Pathname.new(record.root) + + change = options[:change] + cookie = options[:cookie] + + if !cookie && @config.silenced?(rel_path, type) + Listen.logger.debug { "(silenced): #{rel_path.inspect}" } + return + end + + path = watched_dir + rel_path + + Listen.logger.debug do + log_details = options[:silence] && 'recording' || change || 'unknown' + "#{log_details}: #{type}:#{path} (#{options.inspect})" + end + + if change + options = cookie ? { cookie: cookie } : {} + @config.queue(type, change, watched_dir, rel_path, options) + elsif type == :dir + # NOTE: POSSIBLE RECURSION + # TODO: fix - use a queue instead + Directory.scan(self, rel_path, options) + elsif (change = File.change(record, rel_path)) && !options[:silence] + @config.queue(:file, change, watched_dir, rel_path) + end + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/cli.rb b/bin/gems/listen-3.10.0/lib/listen/cli.rb new file mode 100644 index 00000000..e3173133 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/cli.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'thor' +require 'listen' +require 'logger' + +module Listen + class CLI < Thor + default_task :start + + desc 'start', 'Starts Listen' + + class_option :verbose, + type: :boolean, + default: false, + aliases: '-v', + banner: 'Verbose' + + class_option :directory, + type: :array, + default: ['.'], + aliases: '-d', + banner: 'One or more directories to listen to' + + class_option :relative, + type: :boolean, + default: false, + aliases: '-r', + banner: 'Convert paths relative to current directory' + + def start + Listen::Forwarder.new(options).start + end + end + + class Forwarder + attr_reader :logger + + def initialize(options) + @options = options + @logger = ::Logger.new(STDOUT, level: ::Logger::INFO) + @logger.formatter = proc { |_, _, _, msg| "#{msg}\n" } + end + + def start + logger.info 'Starting listen...' + + directory = @options[:directory] + relative = @options[:relative] + callback = proc do |modified, added, removed| + if @options[:verbose] + logger.info "+ #{added}" unless added.empty? + logger.info "- #{removed}" unless removed.empty? + logger.info "> #{modified}" unless modified.empty? + end + end + + listener = Listen.to(*directory, relative: relative, &callback) + + listener.start + + sleep 0.5 while listener.processing? + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/directory.rb b/bin/gems/listen-3.10.0/lib/listen/directory.rb new file mode 100644 index 00000000..19178b3e --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/directory.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'set' + +module Listen + # TODO: refactor (turn it into a normal object, cache the stat, etc) + class Directory + # rubocop:disable Metrics/MethodLength + def self.scan(snapshot, rel_path, options) + record = snapshot.record + dir = Pathname.new(record.root) + previous = record.dir_entries(rel_path) + + record.add_dir(rel_path) + + # TODO: use children(with_directory: false) + path = dir + rel_path + current = Set.new(_children(path)) + + Listen.logger.debug do + format('%s: %s(%s): %s -> %s', + (options[:silence] ? 'Recording' : 'Scanning'), + rel_path, options.inspect, previous.inspect, current.inspect) + end + + begin + current.each do |full_path| + type = ::File.lstat(full_path.to_s).directory? ? :dir : :file + item_rel_path = full_path.relative_path_from(dir).to_s + _change(snapshot, type, item_rel_path, options) + end + rescue Errno::ENOENT + # The directory changed meanwhile, so rescan it + current = Set.new(_children(path)) + retry + end + + # TODO: this is not tested properly + previous = previous.reject { |entry, _| current.include?(path + entry) } + + _async_changes(snapshot, Pathname.new(rel_path), previous, options) + rescue Errno::ENOENT, Errno::EHOSTDOWN + record.unset_path(rel_path) + _async_changes(snapshot, Pathname.new(rel_path), previous, options) + rescue Errno::ENOTDIR + # TODO: path not tested + record.unset_path(rel_path) + _async_changes(snapshot, path, previous, options) + _change(snapshot, :file, rel_path, options) + rescue + Listen.logger.warn { format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n") } + raise + end + # rubocop:enable Metrics/MethodLength + + def self.ascendant_of?(base, other) + other.ascend do |ascendant| + break true if base == ascendant + end + end + + def self._async_changes(snapshot, path, previous, options) + fail "Not a Pathname: #{path.inspect}" unless path.respond_to?(:children) + previous.each do |entry, data| + # TODO: this is a hack with insufficient testing + type = data.key?(:mtime) ? :file : :dir + rel_path_s = (path + entry).to_s + _change(snapshot, type, rel_path_s, options) + end + end + + def self._change(snapshot, type, path, options) + return snapshot.invalidate(type, path, options) if type == :dir + + # Minor param cleanup for tests + # TODO: use a dedicated Event class + opts = options.dup + opts.delete(:recursive) + snapshot.invalidate(type, path, opts) + end + + def self._children(path) + return path.children unless RUBY_ENGINE == 'jruby' + + # JRuby inconsistency workaround, see: + # https://github.com/jruby/jruby/issues/3840 + exists = path.exist? + directory = path.directory? + exists && !directory and raise Errno::ENOTDIR, path.to_s + path.children + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/error.rb b/bin/gems/listen-3.10.0/lib/listen/error.rb new file mode 100644 index 00000000..a5f2dc11 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/error.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Besides programming error exceptions like ArgumentError, +# all public interface exceptions should be declared here and inherit from Listen::Error. +module Listen + class Error < RuntimeError + class NotStarted < Error; end + class SymlinkLoop < Error; end + class INotifyMaxWatchesExceeded < Error; end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/event/config.rb b/bin/gems/listen-3.10.0/lib/listen/event/config.rb new file mode 100644 index 00000000..058a8e5b --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/event/config.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Listen + module Event + class Config + attr_reader :listener, :event_queue, :min_delay_between_events + + def initialize( + listener, + event_queue, + queue_optimizer, + wait_for_delay, + &block + ) + @listener = listener + @event_queue = event_queue + @queue_optimizer = queue_optimizer + @min_delay_between_events = wait_for_delay + @block = block + end + + def sleep(seconds) + Kernel.sleep(seconds) + end + + def call(*args) + @block&.call(*args) + end + + def callable? + @block + end + + def optimize_changes(changes) + @queue_optimizer.smoosh_changes(changes) + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/event/loop.rb b/bin/gems/listen-3.10.0/lib/listen/event/loop.rb new file mode 100644 index 00000000..9275673d --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/event/loop.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'timeout' +require 'listen/event/processor' +require 'listen/thread' +require 'listen/error' + +module Listen + module Event + class Loop + include Listen::FSM + + Error = ::Listen::Error + NotStarted = ::Listen::Error::NotStarted # for backward compatibility + + start_state :pre_start + state :pre_start + state :starting + state :started + state :stopped + + def initialize(config) + @config = config + @wait_thread = nil + @reasons = ::Queue.new + initialize_fsm + end + + def wakeup_on_event + if started? && @wait_thread&.alive? + _wakeup(:event) + end + end + + def started? + state == :started + end + + MAX_STARTUP_SECONDS = 5.0 + + # @raises Error::NotStarted if background thread hasn't started in MAX_STARTUP_SECONDS + def start + # TODO: use a Fiber instead? + return unless state == :pre_start + + transition! :starting + + @wait_thread = Listen::Thread.new("wait_thread") do + _process_changes + end + + Listen.logger.debug("Waiting for processing to start...") + + wait_for_state(:started, timeout: MAX_STARTUP_SECONDS) or + raise Error::NotStarted, "thread didn't start in #{MAX_STARTUP_SECONDS} seconds (in state: #{state.inspect})" + + Listen.logger.debug('Processing started.') + end + + def pause + # TODO: works? + # fail NotImplementedError + end + + def stop + transition! :stopped + + @wait_thread&.join + @wait_thread = nil + end + + def stopped? + state == :stopped + end + + private + + def _process_changes + processor = Event::Processor.new(@config, @reasons) + + transition! :started + + processor.loop_for(@config.min_delay_between_events) + end + + def _wakeup(reason) + @reasons << reason + @wait_thread.wakeup + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/event/processor.rb b/bin/gems/listen-3.10.0/lib/listen/event/processor.rb new file mode 100644 index 00000000..63e207c7 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/event/processor.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require 'listen/monotonic_time' + +module Listen + module Event + class Processor + def initialize(config, reasons) + @config = config + @listener = config.listener + @reasons = reasons + _reset_no_unprocessed_events + end + + # TODO: implement this properly instead of checking the state at arbitrary + # points in time + def loop_for(latency) + @latency = latency + + loop do + event = _wait_until_events + _check_stopped + _wait_until_events_calm_down + _wait_until_no_longer_paused + _process_changes(event) + end + rescue Stopped + Listen.logger.debug('Processing stopped') + end + + private + + class Stopped < RuntimeError + end + + def _wait_until_events_calm_down + loop do + now = MonotonicTime.now + + # Assure there's at least latency between callbacks to allow + # for accumulating changes + diff = _deadline - now + break if diff <= 0 + + # give events a bit of time to accumulate so they can be + # compressed/optimized + _sleep(diff) + end + end + + def _wait_until_no_longer_paused + @listener.wait_for_state(*(Listener.states.keys - [:paused])) + end + + def _check_stopped + if @listener.stopped? + _flush_wakeup_reasons + raise Stopped + end + end + + def _sleep(seconds) + _check_stopped + config.sleep(seconds) + _check_stopped + + _flush_wakeup_reasons do |reason| + if reason == :event && !@listener.paused? + _remember_time_of_first_unprocessed_event + end + end + end + + def _remember_time_of_first_unprocessed_event + @_remember_time_of_first_unprocessed_event ||= MonotonicTime.now + end + + def _reset_no_unprocessed_events + @_remember_time_of_first_unprocessed_event = nil + end + + def _deadline + @_remember_time_of_first_unprocessed_event + @latency + end + + # blocks until event is popped + # returns the event or `nil` when the event_queue is closed + # rubocop:disable Naming/MemoizedInstanceVariableName + def _wait_until_events + config.event_queue.pop.tap do |_event| + @_remember_time_of_first_unprocessed_event ||= MonotonicTime.now + end + end + # rubocop:enable Naming/MemoizedInstanceVariableName + + def _flush_wakeup_reasons + until @reasons.empty? + reason = @reasons.pop + yield reason if block_given? + end + end + + # for easier testing without sleep loop + def _process_changes(event) + _reset_no_unprocessed_events + + changes = [event] + changes << config.event_queue.pop until config.event_queue.empty? + + return unless config.callable? + + hash = config.optimize_changes(changes) + result = [hash[:modified], hash[:added], hash[:removed]] + return if result.all?(&:empty?) + + block_start = MonotonicTime.now + exception_note = " (exception)" + ::Listen::Thread.rescue_and_log('_process_changes') do + config.call(*result) + exception_note = nil + end + Listen.logger.debug "Callback#{exception_note} took #{MonotonicTime.now - block_start} sec" + end + + attr_reader :config + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/event/queue.rb b/bin/gems/listen-3.10.0/lib/listen/event/queue.rb new file mode 100644 index 00000000..0521dddd --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/event/queue.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'forwardable' + +module Listen + module Event + class Queue + extend Forwardable + + class Config + def initialize(relative) + @relative = relative + end + + def relative? + @relative + end + end + + def initialize(config) + @event_queue = ::Queue.new + @config = config + end + + def <<(args) + type, change, dir, path, options = *args + fail "Invalid type: #{type.inspect}" unless [:dir, :file].include? type + fail "Invalid change: #{change.inspect}" unless change.is_a?(Symbol) + fail "Invalid path: #{path.inspect}" unless path.is_a?(String) + + dir = if @config.relative? + _safe_relative_from_cwd(dir) + else + dir + end + @event_queue << [type, change, dir, path, options] + end + + delegate empty?: :@event_queue + delegate pop: :@event_queue + delegate close: :@event_queue + + private + + def _safe_relative_from_cwd(dir) + dir.relative_path_from(Pathname.pwd) + rescue ArgumentError + dir + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/file.rb b/bin/gems/listen-3.10.0/lib/listen/file.rb new file mode 100644 index 00000000..41df6327 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/file.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'digest' + +module Listen + class File + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity + def self.change(record, rel_path) + path = Pathname.new(record.root) + rel_path + lstat = path.lstat + + data = { mtime: lstat.mtime.to_f, mode: lstat.mode, size: lstat.size } + + record_data = record.file_data(rel_path) + + if record_data.empty? + record.update_file(rel_path, data) + return :added + end + + if data[:mode] != record_data[:mode] + record.update_file(rel_path, data) + return :modified + end + + if data[:mtime] != record_data[:mtime] + record.update_file(rel_path, data) + return :modified + end + + if data[:size] != record_data[:size] + record.update_file(rel_path, data) + return :modified + end + + return if /1|true/ =~ ENV['LISTEN_GEM_DISABLE_HASHING'] + return unless inaccurate_mac_time?(lstat) + + # Check if change happened within 1 second (maybe it's even + # too much, e.g. 0.3-0.5 could be sufficient). + # + # With rb-fsevent, there's a (configurable) latency between + # when file was changed and when the event was triggered. + # + # If a file is saved at ???14.998, by the time the event is + # actually received by Listen, the time could already be e.g. + # ???15.7. + # + # And since Darwin adapter uses directory scanning, the file + # mtime may be the same (e.g. file was changed at ???14.001, + # then at ???14.998, but the fstat time would be ???14.0 in + # both cases). + # + # If change happened at ???14.999997, the mtime is 14.0, so for + # an mtime=???14.0 we assume it could even be almost ???15.0 + # + # So if Time.now.to_f is ???15.999998 and stat reports mtime + # at ???14.0, then event was due to that file'd change when: + # + # ???15.999997 - ???14.999998 < 1.0s + # + # So the "2" is "1 + 1" (1s to cover rb-fsevent latency + + # 1s maximum difference between real mtime and that recorded + # in the file system) + # + return if data[:mtime].to_i + 2 <= Time.now.to_f + + sha = Digest::SHA256.file(path).digest + record.update_file(rel_path, data.merge(sha: sha)) + if record_data[:sha] && sha != record_data[:sha] + :modified + end + rescue SystemCallError + record.unset_path(rel_path) + :removed + rescue + Listen.logger.debug "lstat failed for: #{rel_path} (#{$ERROR_INFO})" + raise + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity + + def self.inaccurate_mac_time?(stat) + # 'mac' means Modified/Accessed/Created + + # Since precision depends on mounted FS (e.g. you can have a FAT partiion + # mounted on Linux), check for fields with a remainder to detect this + + [stat.mtime, stat.ctime, stat.atime].map(&:usec).all?(&:zero?) + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/fsm.rb b/bin/gems/listen-3.10.0/lib/listen/fsm.rb new file mode 100644 index 00000000..42354483 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/fsm.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +# Code copied from https://github.com/celluloid/celluloid-fsm + +module Listen + module FSM + # Included hook to extend class methods + def self.included(klass) + klass.send :extend, ClassMethods + end + + module ClassMethods + # Obtain or set the start state + # Passing a state name sets the start state + def start_state(new_start_state = nil) + if new_start_state + new_start_state.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_start_state.inspect})" + @start_state = new_start_state + else + defined?(@start_state) or raise ArgumentError, "`start_state :` must be declared before `new`" + @start_state + end + end + + # The valid states for this FSM, as a hash with state name symbols as keys and State objects as values. + def states + @states ||= {} + end + + # Declare an FSM state and optionally provide a callback block to fire on state entry + # Options: + # * to: a state or array of states this state can transition to + def state(state_name, to: nil, &block) + state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{state_name.inspect})" + states[state_name] = State.new(state_name, to, &block) + end + end + + # NOTE: including classes must call initialize_fsm from their initialize method. + def initialize_fsm + @fsm_initialized = true + @state = self.class.start_state + @mutex = ::Mutex.new + @state_changed = ::ConditionVariable.new + end + + # Current state of the FSM, stored as a symbol + attr_reader :state + + # checks for one of the given states to wait for + # if not already, waits for a state change (up to timeout seconds--`nil` means infinite) + # returns truthy iff the transition to one of the desired state has occurred + def wait_for_state(*wait_for_states, timeout: nil) + wait_for_states.each do |state| + state.is_a?(Symbol) or raise ArgumentError, "states must be symbols (got #{state.inspect})" + end + @mutex.synchronize do + if !wait_for_states.include?(@state) + @state_changed.wait(@mutex, timeout) + end + wait_for_states.include?(@state) + end + end + + private + + def transition(new_state_name) + new_state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_state_name.inspect})" + if (new_state = validate_and_sanitize_new_state(new_state_name)) + transition_with_callbacks!(new_state) + end + end + + # Low-level, immediate state transition with no checks or callbacks. + def transition!(new_state_name) + new_state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_state_name.inspect})" + @fsm_initialized or raise ArgumentError, "FSM not initialized. You must call initialize_fsm from initialize!" + @mutex.synchronize do + yield if block_given? + @state = new_state_name + @state_changed.broadcast + end + end + + def validate_and_sanitize_new_state(new_state_name) + return nil if @state == new_state_name + + if current_state && !current_state.valid_transition?(new_state_name) + valid = current_state.transitions.map(&:to_s).join(', ') + msg = "#{self.class} can't change state from '#{@state}' to '#{new_state_name}', only to: #{valid}" + raise ArgumentError, msg + end + + unless (new_state = self.class.states[new_state_name]) + new_state_name == self.class.start_state or raise ArgumentError, "invalid state for #{self.class}: #{new_state_name}" + end + + new_state + end + + def transition_with_callbacks!(new_state) + transition! new_state.name + new_state.call(self) + end + + def current_state + self.class.states[@state] + end + + class State + attr_reader :name, :transitions + + def initialize(name, transitions, &block) + @name = name + @block = block + @transitions = if transitions + Array(transitions).map(&:to_sym) + end + end + + def call(obj) + obj.instance_eval(&@block) if @block + end + + def valid_transition?(new_state) + # All transitions are allowed if none are expressly declared + !@transitions || @transitions.include?(new_state.to_sym) + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/listener.rb b/bin/gems/listen-3.10.0/lib/listen/listener.rb new file mode 100644 index 00000000..d886fdb4 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/listener.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +require 'English' + +require 'listen/version' + +require 'listen/backend' + +require 'listen/silencer' +require 'listen/silencer/controller' + +require 'listen/queue_optimizer' + +require 'listen/fsm' + +require 'listen/event/loop' +require 'listen/event/queue' +require 'listen/event/config' + +require 'listen/listener/config' + +module Listen + class Listener + include Listen::FSM + + # Initializes the directories listener. + # + # @param [String] directory the directories to listen to + # @param [Hash] options the listen options (see Listen::Listener::Options) + # + # @yield [modified, added, removed] the changed files + # @yieldparam [Array] modified the list of modified files + # @yieldparam [Array] added the list of added files + # @yieldparam [Array] removed the list of removed files + # + # rubocop:disable Metrics/MethodLength + def initialize(*dirs, &block) + options = dirs.last.is_a?(Hash) ? dirs.pop : {} + + @config = Config.new(options) + + eq_config = Event::Queue::Config.new(@config.relative?) + queue = Event::Queue.new(eq_config) + + silencer = Silencer.new + rules = @config.silencer_rules + @silencer_controller = Silencer::Controller.new(silencer, rules) + + @backend = Backend.new(dirs, queue, silencer, @config) + + optimizer_config = QueueOptimizer::Config.new(@backend, silencer) + + pconfig = Event::Config.new( + self, + queue, + QueueOptimizer.new(optimizer_config), + @backend.min_delay_between_events, + &block) + + @processor = Event::Loop.new(pconfig) + + initialize_fsm + end + # rubocop:enable Metrics/MethodLength + + start_state :initializing + + state :initializing, to: [:backend_started, :stopped] + + state :backend_started, to: [:processing_events, :stopped] do + @backend.start + end + + state :processing_events, to: [:paused, :stopped] do + @processor.start + end + + state :paused, to: [:processing_events, :stopped] do + @processor.pause + end + + state :stopped, to: [:backend_started] do + @backend.stop # halt events ASAP + @processor.stop + end + + # Starts processing events and starts adapters + # or resumes invoking callbacks if paused + def start + case state + when :initializing + transition :backend_started + transition :processing_events + when :paused + transition :processing_events + else + raise ArgumentError, "cannot start from state #{state.inspect}" + end + end + + # Stops both listening for events and processing them + def stop + transition :stopped + end + + # Stops invoking callbacks (messages pile up) + def pause + transition :paused + end + + # processing means callbacks are called + def processing? + state == :processing_events + end + + def paused? + state == :paused + end + + def stopped? + state == :stopped + end + + def ignore(regexps) + @silencer_controller.append_ignores(regexps) + end + + def ignore!(regexps) + @silencer_controller.replace_with_bang_ignores(regexps) + end + + def only(regexps) + @silencer_controller.replace_with_only(regexps) + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/listener/config.rb b/bin/gems/listen-3.10.0/lib/listen/listener/config.rb new file mode 100644 index 00000000..56e4b7c9 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/listener/config.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Listen + class Listener + class Config + DEFAULTS = { + # Listener options + debug: false, # TODO: is this broken? + wait_for_delay: nil, # NOTE: should be provided by adapter if possible + relative: false, + + # Backend selecting options + force_polling: false, + polling_fallback_message: nil + }.freeze + + def initialize(opts) + @options = DEFAULTS.merge(opts) + @relative = @options[:relative] + @min_delay_between_events = @options[:wait_for_delay] + @silencer_rules = @options # silencer will extract what it needs + end + + def relative? + @relative + end + + attr_reader :min_delay_between_events, :silencer_rules + + def adapter_instance_options(klass) + valid_keys = klass.const_get('DEFAULTS').keys + Hash[@options.select { |key, _| valid_keys.include?(key) }] + end + + def adapter_select_options + valid_keys = %w[force_polling polling_fallback_message].map(&:to_sym) + Hash[@options.select { |key, _| valid_keys.include?(key) }] + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/logger.rb b/bin/gems/listen-3.10.0/lib/listen/logger.rb new file mode 100644 index 00000000..0bb98067 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/logger.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Listen + @logger = nil + + # Listen.logger will always be present. + # If you don't want logging, set Listen.logger = ::Logger.new('/dev/null', level: ::Logger::UNKNOWN) + + @adapter_warn_behavior = :warn + + class << self + attr_writer :logger + attr_accessor :adapter_warn_behavior + + def logger + @logger ||= default_logger + end + + def adapter_warn(message) + case ENV['LISTEN_GEM_ADAPTER_WARN_BEHAVIOR']&.to_sym || adapter_warn_behavior_callback(message) + when :log + logger.warn(message) + when :silent, nil, false + # do nothing + else # :warn + warn(message) + end + end + + private + + def default_logger + level = + case ENV['LISTEN_GEM_DEBUGGING'].to_s + when /debug|2/i + ::Logger::DEBUG + when /info|true|yes|1/i + ::Logger::INFO + when /warn/i + ::Logger::WARN + when /fatal/i + ::Logger::FATAL + else + ::Logger::ERROR + end + + ::Logger.new(STDERR, level: level) + end + + def adapter_warn_behavior_callback(message) + if adapter_warn_behavior.respond_to?(:call) + case behavior = adapter_warn_behavior.call(message) + when Symbol + behavior + when false, nil + :silent + else + :warn + end + else + adapter_warn_behavior + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/monotonic_time.rb b/bin/gems/listen-3.10.0/lib/listen/monotonic_time.rb new file mode 100644 index 00000000..51b0fc9d --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/monotonic_time.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Listen + module MonotonicTime + class << self + if defined?(Process::CLOCK_MONOTONIC) + + def now + Process.clock_gettime(Process::CLOCK_MONOTONIC) + end + + elsif defined?(Process::CLOCK_MONOTONIC_RAW) + + def now + Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW) + end + + else + + def now + Time.now.to_f + end + + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/options.rb b/bin/gems/listen-3.10.0/lib/listen/options.rb new file mode 100644 index 00000000..65025788 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/options.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Listen + class Options + def initialize(opts, defaults) + @options = {} + given_options = opts.dup + defaults.each_key do |key| + @options[key] = given_options.delete(key) || defaults[key] + end + + given_options.empty? or raise ArgumentError, "Unknown options: #{given_options.inspect}" + end + + def respond_to_missing?(name, *_) + @options.has_key?(name) + end + + def method_missing(name, *_) + respond_to_missing?(name) or raise NameError, "Bad option: #{name.inspect} (valid:#{@options.keys.inspect})" + @options[name] + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/queue_optimizer.rb b/bin/gems/listen-3.10.0/lib/listen/queue_optimizer.rb new file mode 100644 index 00000000..2ccf4cd4 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/queue_optimizer.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module Listen + class QueueOptimizer + class Config + def initialize(adapter_class, silencer) + @adapter_class = adapter_class + @silencer = silencer + end + + def exist?(path) + Pathname(path).exist? + end + + def silenced?(path, type) + @silencer.silenced?(path, type) + end + + def debug(*args, &block) + Listen.logger.debug(*args, &block) + end + end + + def smoosh_changes(changes) + # TODO: adapter could be nil at this point (shutdown) + cookies = changes.group_by do |_, _, _, _, options| + (options || {})[:cookie] + end + _squash_changes(_reinterpret_related_changes(cookies)) + end + + def initialize(config) + @config = config + end + + private + + attr_reader :config + + # groups changes into the expected structure expected by + # clients + def _squash_changes(changes) + # We combine here for backward compatibility + # Newer clients should receive dir and path separately + changes = changes.map { |change, dir, path| [change, dir + path] } + + actions = changes.group_by(&:last).map do |path, action_list| + [_logical_action_for(path, action_list.map(&:first)), path.to_s] + end + + config.debug("listen: raw changes: #{actions.inspect}") + + { modified: [], added: [], removed: [] }.tap do |squashed| + actions.each do |type, path| + squashed[type] << path unless type.nil? + end + config.debug("listen: final changes: #{squashed.inspect}") + end + end + + def _logical_action_for(path, actions) + actions << :added if actions.delete(:moved_to) + actions << :removed if actions.delete(:moved_from) + + modified = actions.find { |x| x == :modified } + _calculate_add_remove_difference(actions, path, modified) + end + + def _calculate_add_remove_difference(actions, path, default_if_exists) + added = actions.count { |x| x == :added } + removed = actions.count { |x| x == :removed } + diff = added - removed + + # TODO: avoid checking if path exists and instead assume the events are + # in order (if last is :removed, it doesn't exist, etc.) + if config.exist?(path) + if diff > 0 + :added + elsif diff.zero? && added > 0 + :modified + else + default_if_exists + end + else + diff < 0 ? :removed : nil + end + end + + # remove extraneous rb-inotify events, keeping them only if it's a possible + # editor rename() call (e.g. Kate and Sublime) + def _reinterpret_related_changes(cookies) + table = { moved_to: :added, moved_from: :removed } + cookies.flat_map do |_, changes| + if (editor_modified = editor_modified?(changes)) + [[:modified, *editor_modified]] + else + not_silenced = changes.reject do |type, _, _, path, _| + config.silenced?(Pathname(path), type) + end + not_silenced.map do |_, change, dir, path, _| + [table.fetch(change, change), dir, path] + end + end + end + end + + def editor_modified?(changes) + return unless changes.size == 2 + + from_type = from = nil + to_type = to_dir = to = nil + + changes.each do |data| + case data[1] + when :moved_from + from_type, _from_change, _, from, = data + when :moved_to + to_type, _to_change, to_dir, to, = data + end + end + + # Expect an ignored moved_from and non-ignored moved_to + # to qualify as an "editor modify" + if from && to && config.silenced?(Pathname(from), from_type) && !config.silenced?(Pathname(to), to_type) + [to_dir, to] + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/record.rb b/bin/gems/listen-3.10.0/lib/listen/record.rb new file mode 100644 index 00000000..362c3806 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/record.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true + +require 'listen/record/entry' +require 'listen/record/symlink_detector' + +module Listen + class Record + # TODO: one Record object per watched directory? + # TODO: deprecate + + attr_reader :root + + def initialize(directory, silencer) + reset_tree + @root = directory.to_s + @silencer = silencer + end + + def add_dir(rel_path) + if !empty_dirname?(rel_path.to_s) + @tree[rel_path.to_s] + end + end + + def update_file(rel_path, data) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + _fast_update_file(dirname, basename, data) + end + + def unset_path(rel_path) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + _fast_unset_path(dirname, basename) + end + + def file_data(rel_path) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + if empty_dirname?(dirname) + @tree[basename].dup + else + @tree[dirname][basename] ||= {} + @tree[dirname][basename].dup + end + end + + def dir_entries(rel_path) + rel_path_s = rel_path.to_s + subtree = if empty_dirname?(rel_path_s) + @tree + else + @tree[rel_path_s] + end + + subtree.each_with_object({}) do |(key, values), result| + # only return data for file entries inside the dir (which will each be sub-hashes) + if values.is_a?(Hash) + result[key] = values.has_key?(:mtime) ? values : {} + end + end + end + + def build + reset_tree + # TODO: test with a file name given + # TODO: test other permissions + # TODO: test with mixed encoding + symlink_detector = SymlinkDetector.new + remaining = ::Queue.new + remaining << Entry.new(root, nil, nil) + _fast_build_dir(remaining, symlink_detector) until remaining.empty? + end + + private + + def empty_dirname?(dirname) + ['.', ''].include?(dirname) + end + + def reset_tree + @tree = Hash.new { |h, k| h[k] = {} } + end + + def _fast_update_file(dirname, basename, data) + if empty_dirname?(dirname.to_s) + @tree[basename] = @tree[basename].merge(data) + else + @tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data) + end + end + + def _fast_unset_path(dirname, basename) + # this may need to be reworked to properly remove + # entries from a tree, without adding non-existing dirs to the record + if empty_dirname?(dirname.to_s) + if @tree.key?(basename) + @tree.delete(basename) + end + elsif @tree.key?(dirname) + @tree[dirname].delete(basename) + end + end + + def _fast_build_dir(remaining, symlink_detector) + entry = remaining.pop + return if @silencer.silenced?(entry.record_dir_key, :dir) + + children = entry.children # NOTE: children() implicitly tests if dir + symlink_detector.verify_unwatched!(entry) + children.each { |child| remaining << child } + add_dir(entry.record_dir_key) + rescue Errno::ENOTDIR + _fast_try_file(entry) + rescue SystemCallError, SymlinkDetector::Error + _fast_unset_path(entry.relative, entry.name) + end + + def _fast_try_file(entry) + _fast_update_file(entry.relative, entry.name, entry.meta) + rescue SystemCallError + _fast_unset_path(entry.relative, entry.name) + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/record/entry.rb b/bin/gems/listen-3.10.0/lib/listen/record/entry.rb new file mode 100644 index 00000000..a01a1592 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/record/entry.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Listen + # @private api + class Record + # Represents a directory entry (dir or file) + class Entry + # file: "/home/me/watched_dir", "app/models", "foo.rb" + # dir, "/home/me/watched_dir", "." + def initialize(root, relative, name = nil) + @root = root + @relative = relative + @name = name + end + + attr_reader :root, :relative, :name + + def children + child_relative = _join + (_entries(sys_path) - %w[. ..]).map do |name| + Entry.new(@root, child_relative, name) + end + end + + def meta + lstat = ::File.lstat(sys_path) + { mtime: lstat.mtime.to_f, mode: lstat.mode, size: lstat.size } + end + + # record hash is e.g. + # if @record["/home/me/watched_dir"]["project/app/models"]["foo.rb"] + # if @record["/home/me/watched_dir"]["project/app"]["models"] + # record_dir_key is "project/app/models" + def record_dir_key + ::File.join(*[@relative, @name].compact) + end + + def sys_path + # Use full path in case someone uses chdir + ::File.join(*[@root, @relative, @name].compact) + end + + def real_path + @real_path ||= ::File.realpath(sys_path) + end + + private + + def _join + args = [@relative, @name].compact + args.empty? ? nil : ::File.join(*args) + end + + def _entries(dir) + return Dir.entries(dir) unless RUBY_ENGINE == 'jruby' + + # JRuby inconsistency workaround, see: + # https://github.com/jruby/jruby/issues/3840 + exists = ::File.exist?(dir) + directory = ::File.directory?(dir) + return Dir.entries(dir) unless exists && !directory + raise Errno::ENOTDIR, dir + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/record/symlink_detector.rb b/bin/gems/listen-3.10.0/lib/listen/record/symlink_detector.rb new file mode 100644 index 00000000..1da60f58 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/record/symlink_detector.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'set' +require 'listen/error' + +module Listen + # @private api + class Record + class SymlinkDetector + README_URL = 'https://github.com/guard/listen/blob/master/README.md' + + SYMLINK_LOOP_ERROR = <<-EOS.freeze + ** ERROR: directory is already being watched! ** + + Directory: %s + + is already being watched through: %s + + MORE INFO: #{README_URL} + EOS + + Error = ::Listen::Error # for backward compatibility + + def initialize + @real_dirs = Set.new + end + + def verify_unwatched!(entry) + real_path = entry.real_path + @real_dirs.add?(real_path) or _fail(entry.sys_path, real_path) + end + + # Leaving this stub here since some warning work-arounds were referring to it. + # Deprecated. Will be removed in Listen v4.0. + def warn(message) + Listen.adapter_warn(message) + end + + private + + def _fail(symlinked, real_path) + warn(format(SYMLINK_LOOP_ERROR, symlinked, real_path)) + raise ::Listen::Error::SymlinkLoop, 'Failed due to looped symlinks' + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/silencer.rb b/bin/gems/listen-3.10.0/lib/listen/silencer.rb new file mode 100644 index 00000000..3cc7936c --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/silencer.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module Listen + class Silencer + # The default list of directories that get ignored. + DEFAULT_IGNORED_FILES = %r{\A(?: + \.git + | \.svn + | \.hg + | \.rbx + | \.bundle + | bundle + | vendor/bundle + | log + | tmp + | vendor/ruby + + # emacs temp files + | \#.+\# + | \.\#.+ + )(/|\z)}x + + # The default list of files that get ignored. + DEFAULT_IGNORED_EXTENSIONS = %r{(?: + # Kate's tmp\/swp files + \..*\d+\.new + | \.kate-swp + + # Gedit tmp files + | \.goutputstream-.{6} + + # Intellij files + | ___jb_bak___ + | ___jb_old___ + + # Vim swap files and write test + | \.sw[px] + | \.swpx + | ^4913 + + # Sed temporary files - but without actual words, like 'sedatives' + | (?:\A + sed + + (?: + [a-zA-Z0-9]{0}[A-Z]{1}[a-zA-Z0-9]{5} | + [a-zA-Z0-9]{1}[A-Z]{1}[a-zA-Z0-9]{4} | + [a-zA-Z0-9]{2}[A-Z]{1}[a-zA-Z0-9]{3} | + [a-zA-Z0-9]{3}[A-Z]{1}[a-zA-Z0-9]{2} | + [a-zA-Z0-9]{4}[A-Z]{1}[a-zA-Z0-9]{1} | + [a-zA-Z0-9]{5}[A-Z]{1}[a-zA-Z0-9]{0} + ) + ) + + # Mutagen sync temporary files + | \.mutagen-temporary.* + + # other files + | \.DS_Store + | \.tmp + | ~ + )\z}x + + # TODO: deprecate these mutators; use attr_reader instead + attr_accessor :only_patterns, :ignore_patterns + + def initialize(**options) + configure(options) + end + + # TODO: deprecate this mutator + def configure(options) + @only_patterns = options[:only] ? Array(options[:only]) : nil + @ignore_patterns = _init_ignores(options[:ignore], options[:ignore!]) + end + + def silenced?(relative_path, type) + path = relative_path.to_s # in case it is a Pathname + + _ignore?(path) || (only_patterns && type == :file && !_only?(path)) + end + + private + + def _ignore?(path) + ignore_patterns.any? { |pattern| path =~ pattern } + end + + def _only?(path) + only_patterns.any? { |pattern| path =~ pattern } + end + + def _init_ignores(ignores, overrides) + patterns = [] + unless overrides + patterns << DEFAULT_IGNORED_FILES + patterns << DEFAULT_IGNORED_EXTENSIONS + end + + patterns << ignores + patterns << overrides + + patterns.compact.flatten + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/silencer/controller.rb b/bin/gems/listen-3.10.0/lib/listen/silencer/controller.rb new file mode 100644 index 00000000..bb94d4bf --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/silencer/controller.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Listen + class Silencer + class Controller + def initialize(silencer, default_options) + @silencer = silencer + + opts = default_options + + @prev_silencer_options = {} + rules = [:only, :ignore, :ignore!].map do |option| + [option, opts[option]] if opts.key? option + end + + _reconfigure_silencer(Hash[rules.compact]) + end + + def append_ignores(*regexps) + prev_ignores = Array(@prev_silencer_options[:ignore]) + _reconfigure_silencer(ignore: [prev_ignores + regexps]) + end + + def replace_with_bang_ignores(regexps) + _reconfigure_silencer(ignore!: regexps) + end + + def replace_with_only(regexps) + _reconfigure_silencer(only: regexps) + end + + private + + def _reconfigure_silencer(extra_options) + opts = extra_options.dup + opts = opts.map do |key, value| + [key, Array(value).flatten.compact] + end + opts = Hash[opts] + + if opts.key?(:ignore) && opts[:ignore].empty? + opts.delete(:ignore) + end + + @prev_silencer_options = opts + @silencer.configure(@prev_silencer_options.dup.freeze) + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/thread.rb b/bin/gems/listen-3.10.0/lib/listen/thread.rb new file mode 100644 index 00000000..a1e6b3b6 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/thread.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'thread' + +require_relative 'logger' + +module Listen + module Thread + class << self + # Creates a new thread with the given name. + # Any exceptions raised by the thread will be logged with the thread name and complete backtrace. + # rubocop:disable Style/MultilineBlockChain + def new(name, &block) + thread_name = "listen-#{name}" + caller_stack = caller + + ::Thread.new do + rescue_and_log(thread_name, caller_stack: caller_stack, &block) + end.tap do |thread| + thread.name = thread_name + end + end + # rubocop:enable Style/MultilineBlockChain + + def rescue_and_log(method_name, *args, caller_stack: nil) + yield(*args) + rescue => exception + _log_exception(exception, method_name, caller_stack: caller_stack) + end + + private + + def _log_exception(exception, thread_name, caller_stack: nil) + complete_backtrace = if caller_stack + [*exception.backtrace, "--- Thread.new ---", *caller_stack] + else + exception.backtrace + end + message = "Exception rescued in #{thread_name}:\n#{_exception_with_causes(exception)}\n#{complete_backtrace * "\n"}" + Listen.logger.error(message) + end + + def _exception_with_causes(exception) + result = +"#{exception.class}: #{exception}" + if exception.cause + result << "\n" + result << "--- Caused by: ---\n" + result << _exception_with_causes(exception.cause) + end + result + end + end + end +end diff --git a/bin/gems/listen-3.10.0/lib/listen/version.rb b/bin/gems/listen-3.10.0/lib/listen/version.rb new file mode 100644 index 00000000..c8bf8413 --- /dev/null +++ b/bin/gems/listen-3.10.0/lib/listen/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Listen + VERSION = '3.10.0' +end diff --git a/bin/gems/listen-3.9.0/CHANGELOG.md b/bin/gems/listen-3.9.0/CHANGELOG.md new file mode 100644 index 00000000..232adbd8 --- /dev/null +++ b/bin/gems/listen-3.9.0/CHANGELOG.md @@ -0,0 +1 @@ +# Moved to [GitHub releases](https://github.com/guard/listen/releases) page. diff --git a/bin/gems/listen-3.9.0/CONTRIBUTING.md b/bin/gems/listen-3.9.0/CONTRIBUTING.md new file mode 100644 index 00000000..7e5b197c --- /dev/null +++ b/bin/gems/listen-3.9.0/CONTRIBUTING.md @@ -0,0 +1,45 @@ +Contribute to Listen +=================== + +File an issue +------------- + +If you haven't already, first see [TROUBLESHOOTING](https://github.com/guard/listen/blob/master/README.md#Issues-and-Troubleshooting) for known issues, solutions and workarounds. + +You can report bugs and feature requests to [GitHub Issues](https://github.com/guard/listen/issues). + +**Please don't ask question in the issue tracker**, instead ask them in our +[Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net). + +Try to figure out where the issue belongs to: Is it an issue with Listen itself or with Guard? + + +**It's most likely that your bug gets resolved faster if you provide as much information as possible!** + +The MOST useful information is debugging output from Listen (`LISTEN_GEM_DEBUGGING=1`) - see [TROUBLESHOOTING](https://github.com/guard/listen/blob/master/README.md#Issues-and-Troubleshooting) for details. + + +Development +----------- + +* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames). +* Source hosted at [GitHub](https://github.com/guard/listen). + +Pull requests are very welcome! Please try to follow these simple rules if applicable: + +* Please create a topic branch for every separate change you make. +* Make sure your patches are well tested. All specs run with `rake spec` must pass. +* Update the [Yard](http://yardoc.org/) documentation. +* Update the [README](https://github.com/guard/listen/blob/master/README.md). +* Please **do not change** the version number. + +The title of your PR will automatically be included in the release notes for the next version of the gem. A maintainer can add one of the following GitHub labels to the PR to automatically categorize it when the release notes are generated: + +- ⚠️ Breaking +- ✨ Feature +- 🐛 Bug Fix +- 📚 Docs +- 🏠 Housekeeping + +For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on +`#guard` (irc.freenode.net). diff --git a/bin/gems/listen-3.9.0/LICENSE.txt b/bin/gems/listen-3.9.0/LICENSE.txt new file mode 100644 index 00000000..b5f71c8b --- /dev/null +++ b/bin/gems/listen-3.9.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Thibaud Guillaume-Gentil + +MIT License + +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/bin/gems/listen-3.9.0/README.md b/bin/gems/listen-3.9.0/README.md new file mode 100644 index 00000000..cc59e02f --- /dev/null +++ b/bin/gems/listen-3.9.0/README.md @@ -0,0 +1,491 @@ +# Listen + +The `listen` gem listens to file modifications and notifies you about the changes. + +[![Development Status](https://github.com/guard/listen/workflows/Development/badge.svg)](https://github.com/guard/listen/actions?workflow=Development) +[![Gem Version](https://badge.fury.io/rb/listen.svg)](http://badge.fury.io/rb/listen) +[![Code Climate](https://codeclimate.com/github/guard/listen.svg)](https://codeclimate.com/github/guard/listen) +[![Coverage Status](https://coveralls.io/repos/guard/listen/badge.svg?branch=master)](https://coveralls.io/r/guard/listen) + +## Features + +* OS-optimized adapters on MRI for Mac OS X 10.6+, Linux, \*BSD and Windows, [more info](#listen-adapters) below. +* Detects file modification, addition and removal. +* You can watch multiple directories. +* Regexp-patterns for ignoring paths for more accuracy and speed +* Increased change detection accuracy on OS X HFS and VFAT volumes. +* Continuous Integration: tested on selected Ruby environments via [Github Workflows](https://github.com/guard/listen/tree/master/.github/workflows). + +## Issues / limitations + +* Limited support for symlinked directories ([#279](https://github.com/guard/listen/issues/279)): + * Symlinks are always followed ([#25](https://github.com/guard/listen/issues/25)). + * Symlinked directories pointing within a watched directory are not supported ([#273](https://github.com/guard/listen/pull/273). +* No directory/adapter-specific configuration options. +* Support for plugins planned for future. +* TCP functionality was removed in `listen` [3.0.0](https://github.com/guard/listen/releases/tag/v3.0.0) ([#319](https://github.com/guard/listen/issues/319), [#218](https://github.com/guard/listen/issues/218)). There are plans to extract this feature to separate gems ([#258](https://github.com/guard/listen/issues/258)), until this is finished, you can use by locking the `listen` gem to version `'~> 2.10'`. +* Some filesystems won't work without polling (VM/Vagrant Shared folders, NFS, Samba, sshfs, etc.). +* Windows and \*BSD adapter aren't continuously and automatically tested. +* OSX adapter has some performance limitations ([#342](https://github.com/guard/listen/issues/342)). +* Listeners do not notify across forked processes, if you wish for multiple processes to receive change notifications you must [listen inside of each process](https://github.com/guard/listen/issues/398#issuecomment-223957952). + +Pull requests or help is very welcome for these. + +## Install + +The simplest way to install `listen` is to use [Bundler](http://bundler.io). + +```ruby +gem 'listen' +``` + +## Complete Example +Here is a complete example of using the `listen` gem: +```ruby +require 'listen' + +listener = Listen.to('/srv/app') do |modified, added, removed| + puts(modified: modified, added: added, removed: removed) +end +listener.start +sleep +``` +Running the above in the background, you can see the callback block being called in response to each command: +``` +$ cd /srv/app +$ touch a.txt +{:modified=>[], :added=>["/srv/app/a.txt"], :removed=>[]} + +$ echo more >> a.txt +{:modified=>["/srv/app/a.txt"], :added=>[], :removed=>[]} + +$ mv a.txt b.txt +{:modified=>[], :added=>["/srv/app/b.txt"], :removed=>["/srv/app/a.txt"]} + +$ vi b.txt +# add a line to this new file and press ZZ to save and exit +{:modified=>["/srv/app/b.txt"], :added=>[], :removed=>[]} + +$ vi c.txt +# add a line and press ZZ to save and exit +{:modified=>[], :added=>["/srv/app/c.txt"], :removed=>[]} + +$ rm b.txt c.txt +{:modified=>[], :added=>[], :removed=>["/srv/app/b.txt", "/srv/app/c.txt"]} +``` + +## Usage + +Call `Listen.to` with one or more directories and the "changes" callback passed as a block. + +``` ruby +listener = Listen.to('dir/to/listen', 'dir/to/listen2') do |modified, added, removed| + puts "modified absolute path array: #{modified}" + puts "added absolute path array: #{added}" + puts "removed absolute path array: #{removed}" +end +listener.start # starts a listener thread--does not block + +# do whatever you want here...just don't exit the process :) + +sleep +``` +## Changes Callback + +Changes to the listened-to directories are reported by the listener thread in a callback. +The callback receives **three** array parameters: `modified`, `added` and `removed`, in that order. +Each of these three is always an array with 0 or more entries. +Each array entry is an absolute path. + +### Pause / start / stop + +Listeners can also be easily paused and later un-paused with start: + +``` ruby +listener = Listen.to('dir/path/to/listen') { |modified, added, removed| puts 'handle changes here...' } + +listener.start +listener.paused? # => false +listener.processing? # => true + +listener.pause # stops processing changes (but keeps on collecting them) +listener.paused? # => true +listener.processing? # => false + +listener.start # resumes processing changes +listener.stop # stop both listening to changes and processing them +``` + + Note: While paused, `listen` keeps on collecting changes in the background - to clear them, call `stop`. + + Note: You should keep track of all started listeners and `stop` them properly on finish. + +### Ignore / ignore! + +`Listen` ignores some directories and extensions by default (See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer). +You can add ignoring patterns with the `ignore` option/method or overwrite default with `ignore!` option/method. + +``` ruby +listener = Listen.to('dir/path/to/listen', ignore: /\.txt/) { |modified, added, removed| # ... } +listener.start +listener.ignore! /\.pkg/ # overwrite all patterns and only ignore pkg extension. +listener.ignore /\.rb/ # ignore rb extension in addition of pkg. +sleep +``` + +Note: `:ignore` regexp patterns are evaluated against relative paths. + +Note: Ignoring paths does not improve performance, except when Polling ([#274](https://github.com/guard/listen/issues/274)). + +### Only + +`Listen` watches all files (less the ignored ones) by default. If you want to only listen to a specific type of file (i.e., just `.rb` extension), you should use the `only` option/method. + +``` ruby +listener = Listen.to('dir/path/to/listen', only: /\.rb$/) { |modified, added, removed| # ... } +listener.start +listener.only /_spec\.rb$/ # overwrite all existing only patterns. +sleep +``` + +Note: `:only` regexp patterns are evaluated only against relative **file** paths. + + +## Options + +All the following options can be set through the `Listen.to` after the directory path(s) params. + +``` ruby +ignore: [%r{/foo/bar}, /\.pid$/, /\.coffee$/] # Ignore a list of paths + # default: See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer + +ignore!: %r{/foo/bar} # Same as ignore options, but overwrite default ignored paths. + +only: %r{.rb$} # Only listen to specific files + # default: none + +latency: 0.5 # Set the delay (**in seconds**) between checking for changes + # default: 0.25 sec (1.0 sec for polling) + +wait_for_delay: 4 # Set the delay (**in seconds**) between calls to the callback when changes exist + # default: 0.10 sec + +force_polling: true # Force the use of the polling adapter + # default: none + +relative: false # Whether changes should be relative to current dir or not + # default: false + +polling_fallback_message: 'custom message' # Set a custom polling fallback message (or disable it with false) + # default: "Listen will be polling for changes. Learn more at https://github.com/guard/listen#listen-adapters." +``` + +## Logging and Debugging + +`Listen` logs its activity to `Listen.logger`. +This is the primary method of debugging. + +### Custom Logger +You can call `Listen.logger =` to set a custom `listen` logger for the process. For example: +``` ruby +Listen.logger = Rails.logger +``` + +### Default Logger +If no custom logger is set, a default `listen` logger which logs to to `STDERR` will be created and assigned to `Listen.logger`. + +The default logger defaults to the `error` logging level (severity). +You can override the logging level by setting the environment variable `LISTEN_GEM_DEBUGGING=`. +For ``, all standard `::Logger` levels are supported, with any mix of upper-/lower-case: +``` ruby +export LISTEN_GEM_DEBUGGING=debug # or 2 [deprecated] +export LISTEN_GEM_DEBUGGING=info # or 1 or true or yes [deprecated] +export LISTEN_GEM_DEBUGGING=warn +export LISTEN_GEM_DEBUGGING=fatal +export LISTEN_GEM_DEBUGGING=error +``` +The default of `error` will be used if an unsupported value is set. + +Note: The alternate values `1`, `2`, `true` and `yes` shown above are deprecated and will be removed from `listen` v4.0. + +### Disabling Logging +If you want to disable `listen` logging, set +``` ruby +Listen.logger = ::Logger.new('/dev/null') +``` + +### Adapter Warnings +If listen is having trouble with the underlying adapter, it will display warnings with `Kernel#warn` by default, +which in turn writes to STDERR. +Sometimes this is not desirable, for example in an environment where STDERR is ignored. +For these reasons, the behavior can be configured using `Listen.adapter_warn_behavior =`: +``` ruby +Listen.adapter_warn_behavior = :warn # default (true means the same) +Listen.adapter_warn_behavior = :log # send to logger.warn +Listen.adapter_warn_behavior = :silent # suppress all adapter warnings (nil or false mean the same) +``` +Also there are some cases where specific warnings are not helpful. +For example, if you are using the polling adapter--and expect to--you can suppress the warning about it +by providing a callable object like a lambda or proc that determines the behavior based on the `message`: +``` ruby +Listen.adapter_warn_behavior = ->(message) do + case message + when /Listen will be polling for changes/ + :silent + when /directory is already being watched/ + :log + else + :warn + end +end +``` +In cases where the `Listen` gem is embedded inside another service--such as `guard`--the above configuration +can be set in the environment variable `LISTEN_GEM_ADAPTER_WARN_BEHAVIOR=warn|log|silent`. + +## Listen Adapters + +The `Listen` gem has a set of adapters to notify it when there are changes. + +There are 4 OS-specific adapters to support Darwin, Linux, \*BSD and Windows. +These adapters are fast as they use some system-calls to implement the notifying function. + +There is also a polling adapter - although it's much slower than other adapters, +it works on every platform/system and scenario (including network filesystems such as VM shared folders). + +The Darwin and Linux adapters are dependencies of the `listen` gem so they work out of the box. For other adapters a specific gem will have to be added to your Gemfile, please read below. + +The `listen` gem will choose the best adapter automatically, if present. If you +want to force the use of the polling adapter, use the `:force_polling` option +while initializing the listener. + +### On Windows + +If you are on Windows, it's recommended to use the [`wdm`](https://github.com/Maher4Ever/wdm) adapter instead of polling. + +Please add the following to your Gemfile: + +```ruby +gem 'wdm', '>= 0.1.0', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +``` + +### On \*BSD + +If you are on \*BSD you can try to use the [`rb-kqueue`](https://github.com/mat813/rb-kqueue) adapter instead of polling. + +Please add the following to your Gemfile: + +```ruby +require 'rbconfig' +if RbConfig::CONFIG['target_os'] =~ /bsd|dragonfly/i + gem 'rb-kqueue', '>= 0.2' +end + +``` + +### Getting the [polling fallback message](#options)? + +If you see: +``` +Listen will be polling for changes. +``` + +This means the Listen gem can’t find an optimized adapter. Typically this is caused by: + +- You’re on Windows and WDM gem isn’t installed. +- You’re running the app without Bundler or RubyGems. +- Using Sass which includes an ancient (the “dinosaur” type of ancient) version of the Listen gem. + +Possible solutions: + +1. Suppress the message by using the :force_polling option. Or, you could just ignore the message since it’s harmless. +2. Windows users: Install the WDM gem. +3. Upgrade Ruby (use RubyInstaller for Windows or RVM/rbenv for Mac) and RubyGems. +3. Run your apps using Bundler. +4. Sass users: Install the latest version of Listen and try again. + +#### Simplified Bundler and Sass example +Create a Gemfile with these lines: +``` +source 'https://rubygems.org' +gem 'listen' +gem 'sass' +``` +Next, use Bundler to update gems: +``` +$ bundle update +$ bundle exec sass --watch # ... or whatever app is using Listen. +``` + +### Increasing the amount of inotify watchers + +If you are running Debian, RedHat, or another similar Linux distribution, run the following in a terminal: +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf" +$ sudo sysctl -p +``` +If you are running ArchLinux, search the `/etc/sysctl.d/` directory for config files with the setting: +``` +$ grep -H -s "fs.inotify.max_user_watches" /etc/sysctl.d/* +/etc/sysctl.d/40-max_user_watches.conf:fs.inotify.max_user_watches=100000 +``` +Then change the setting in the file you found above to a higher value (see [here](https://www.archlinux.org/news/deprecation-of-etcsysctlconf/) for why): +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 > /etc/sysctl.d/40-max-user-watches.conf" +$ sudo sysctl --system +``` + +#### The technical details +Listen uses `inotify` by default on Linux to monitor directories for changes. +It's not uncommon to encounter a system limit on the number of files you can monitor. +For example, Ubuntu Lucid's (64bit) `inotify` limit is set to 8192. + +You can get your current inotify file watch limit by executing: +``` +$ cat /proc/sys/fs/inotify/max_user_watches +``` +When this limit is not enough to monitor all files inside a directory, the limit must be increased for Listen to work properly. + +You can set a new limit temporarily with: +``` +$ sudo sysctl fs.inotify.max_user_watches=524288 +$ sudo sysctl -p +``` +If you like to make your limit permanent, use: +``` +$ sudo sh -c "echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf" +$ sudo sysctl -p +``` +You may also need to pay attention to the values of `max_queued_events` and `max_user_instances` if Listen keeps on complaining. + +#### More info +Man page for [inotify(7)](https://linux.die.net/man/7/inotify). +Blog post: [limit of inotify](https://blog.sorah.jp/2012/01/24/inotify-limitation). + +### Issues and Troubleshooting + +If the gem doesn't work as expected, start by setting `LISTEN_GEM_DEBUGGING=debug` or `LISTEN_GEM_DEBUGGING=info` as described above in [Logging and Debugging](#logging-and-debugging). + +*NOTE: without providing the output after setting the `LISTEN_GEM_DEBUGGING=debug` environment variable, it is usually impossible to guess why `listen` is not working as expected.* + +#### 3 steps before you start diagnosing problems +These 3 steps will: + +- help quickly troubleshoot obscure problems (trust me, most of them are obscure) +- help quickly identify the area of the problem (a full list is below) +- help you get familiar with listen's diagnostic mode (it really comes in handy, trust me) +- help you create relevant output before you submit an issue (so we can respond with answers instead of tons of questions) + +Step 1 - The most important option in Listen +For effective troubleshooting set the `LISTEN_GEM_DEBUGGING=info` variable before starting `listen`. + +Step 2 - Verify polling works +Polling has to work ... or something is really wrong (and we need to know that before anything else). + +(see force_polling option). + +After starting `listen`, you should see something like: +``` +INFO -- : Record.build(): 0.06773114204406738 seconds +``` +Step 3 - Trigger some changes directly without using editors or apps +Make changes e.g. touch foo or echo "a" >> foo (for troubleshooting, avoid using an editor which could generate too many misleading events). + +You should see something like: +``` +INFO -- : listen: raw changes: [[:added, "/home/me/foo"]] +INFO -- : listen: final changes: {:modified=>[], :added=>["/home/me/foo"], :removed=>[]} +``` +"raw changes" contains changes collected during the :wait_for_delay and :latency intervals, while "final changes" is what listen decided are relevant changes (for better editor support). + +## Performance + +If `listen` seems slow or unresponsive, make sure you're not using the Polling adapter (you should see a warning upon startup if you are). + +Also, if the directories you're watching contain many files, make sure you're: + +* not using Polling (ideally) +* using `:ignore` and `:only` options to avoid tracking directories you don't care about (important with Polling and on MacOS) +* running `listen` with the `:latency` and `:wait_for_delay` options not too small or too big (depends on needs) +* not watching directories with log files, database files or other frequently changing files +* not using a version of `listen` prior to 2.7.7 +* not getting silent crashes within `listen` (see `LISTEN_GEM_DEBUGGING=debug`) +* not running multiple instances of `listen` in the background +* using a file system with atime modification disabled (ideally) +* not using a filesystem with inaccurate file modification times (ideally), e.g. HFS, VFAT +* not buffering to a slow terminal (e.g. transparency + fancy font + slow gfx card + lots of output) +* ideally not running a slow encryption stack, e.g. btrfs + ecryptfs + +When in doubt, `LISTEN_GEM_DEBUGGING=debug` can help discover the actual events and time they happened. + +## Tips and Techniques +- Watch only directories you're interested in. +- Set your editor to save quickly (e.g. without backup files, without atomic-save) +- Tweak the `:latency` and `:wait_for_delay` options until you get good results (see [options](#options)). +- Add `:ignore` rules to silence all events you don't care about (reduces a lot of noise, especially if you use it on directories) + +## Development + +* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames). +* Source hosted at [GitHub](https://github.com/guard/listen). + +Pull requests are very welcome! Please try to follow these simple rules if applicable: + +* Please create a topic branch for every separate change you make. +* Make sure your patches are well tested. All specs must pass on [Travis CI](https://travis-ci.org/guard/listen). +* Update the [Yard](http://yardoc.org/) documentation. +* Update the [README](https://github.com/guard/listen/blob/master/README.md). +* Please **do not change** the version number. + +For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on +`#guard` (irc.freenode.net). + +## Releasing + +### Prerequisites + +* You must have commit rights to the GitHub repository. +* You must have push rights for rubygems.org. + +### How to release + +1. Run `bundle install` to make sure that you have all the gems necessary for testing and releasing. +2. **Ensure all tests are passing by running `bundle exec rake`.** +3. Determine which would be the correct next version number according to [semver](http://semver.org/). +4. Update the version in `./lib/listen/version.rb`. +5. Update the version in the Install section of `./README.md` (`gem 'listen', '~> X.Y'`). +6. Commit the version in a single commit, the message should be "Preparing vX.Y.Z" +7. Run `bundle exec rake release:full`; this will tag, push to GitHub, and publish to rubygems.org. +8. Update and publish the release notes on the [GitHub releases page](https://github.com/guard/listen/releases) if necessary + +## Acknowledgments + +* [Michael Kessler (netzpirat)][] for having written the [initial specs](https://github.com/guard/listen/commit/1e457b13b1bb8a25d2240428ce5ed488bafbed1f). +* [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][]. +* [Natalie Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper. +* [Mathieu Arnold (mat813)][] for [rb-kqueue][], a simple kqueue wrapper. +* [Maher Sallam][] for [wdm][], windows support wouldn't exist without him. +* [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration. + +## Author + +[Thibaud Guillaume-Gentil](https://github.com/thibaudgg) ([@thibaudgg](https://twitter.com/thibaudgg)) + +## Contributors + +[https://github.com/guard/listen/graphs/contributors](https://github.com/guard/listen/graphs/contributors) + +[Thibaud Guillaume-Gentil (thibaudgg)]: https://github.com/thibaudgg +[Maher Sallam]: https://github.com/Maher4Ever +[Michael Kessler (netzpirat)]: https://github.com/netzpirat +[Travis Tilley (ttilley)]: https://github.com/ttilley +[fssm]: https://github.com/ttilley/fssm +[rb-fsevent]: https://github.com/thibaudgg/rb-fsevent +[Mathieu Arnold (mat813)]: https://github.com/mat813 +[Natalie Weizenbaum (nex3)]: https://github.com/nex3 +[rb-inotify]: https://github.com/nex3/rb-inotify +[stereobooster]: https://github.com/stereobooster +[rb-fchange]: https://github.com/stereobooster/rb-fchange +[rb-kqueue]: https://github.com/mat813/rb-kqueue +[Yehuda Katz (wycats)]: https://github.com/wycats +[vigilo]: https://github.com/wycats/vigilo +[wdm]: https://github.com/Maher4Ever/wdm diff --git a/bin/gems/listen-3.9.0/bin/listen b/bin/gems/listen-3.9.0/bin/listen new file mode 100755 index 00000000..59ade96d --- /dev/null +++ b/bin/gems/listen-3.9.0/bin/listen @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'listen' +require 'listen/cli' + +if !defined?(JRUBY_VERSION) && Signal.list.keys.include?('INT') + Signal.trap('INT') { Thread.new { Listen.stop } } +end + +Listen::CLI.start diff --git a/bin/gems/listen-3.9.0/lib/listen.rb b/bin/gems/listen-3.9.0/lib/listen.rb new file mode 100644 index 00000000..03857fe4 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'logger' +require 'weakref' +require 'listen/logger' +require 'listen/listener' + +# Won't print anything by default because of level - unless you've set +# LISTEN_GEM_DEBUGGING or provided your own logger with a high enough level +Listen.logger.info "Listen loglevel set to: #{Listen.logger.level}" +Listen.logger.info "Listen version: #{Listen::VERSION}" + +module Listen + @listeners = Queue.new + + class << self + # Listens to file system modifications on a either single directory or + # multiple directories. + # + # @param (see Listen::Listener#new) + # + # @yield [modified, added, removed] the changed files + # @yieldparam [Array] modified the list of modified files + # @yieldparam [Array] added the list of added files + # @yieldparam [Array] removed the list of removed files + # + # @return [Listen::Listener] the listener + # + def to(*args, &block) + Listener.new(*args, &block).tap do |listener| + @listeners.enq(WeakRef.new(listener)) + end + end + + # This is used by the `listen` binary to handle Ctrl-C + # + def stop + while (listener = @listeners.deq(true)) + begin + listener.stop + rescue WeakRef::RefError + end + end + rescue ThreadError + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter.rb b/bin/gems/listen-3.9.0/lib/listen/adapter.rb new file mode 100644 index 00000000..dce86236 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'listen/adapter/base' +require 'listen/adapter/bsd' +require 'listen/adapter/darwin' +require 'listen/adapter/linux' +require 'listen/adapter/polling' +require 'listen/adapter/windows' + +module Listen + module Adapter + OPTIMIZED_ADAPTERS = [Darwin, Linux, BSD, Windows].freeze + POLLING_FALLBACK_MESSAGE = 'Listen will be polling for changes.'\ + 'Learn more at https://github.com/guard/listen#listen-adapters.' + + class << self + def select(options = {}) + Listen.logger.debug 'Adapter: considering polling ...' + return Polling if options[:force_polling] + Listen.logger.debug 'Adapter: considering optimized backend...' + return _usable_adapter_class if _usable_adapter_class + Listen.logger.debug 'Adapter: falling back to polling...' + _warn_polling_fallback(options) + Polling + rescue + Listen.logger.warn format('Adapter: failed: %s:%s', $ERROR_POSITION.inspect, + $ERROR_POSITION * "\n") + raise + end + + private + + def _usable_adapter_class + OPTIMIZED_ADAPTERS.find(&:usable?) + end + + def _warn_polling_fallback(options) + msg = options.fetch(:polling_fallback_message, POLLING_FALLBACK_MESSAGE) + Listen.adapter_warn("[Listen warning]:\n #{msg}") if msg + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/base.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/base.rb new file mode 100644 index 00000000..b7e10390 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/base.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'listen/options' +require 'listen/record' +require 'listen/change' +require 'listen/thread' + +module Listen + module Adapter + class Base + attr_reader :options, :config + + # TODO: only used by tests + DEFAULTS = {}.freeze + + def initialize(config) + @started = false + @config = config + + @configured = nil + + fail 'No directories to watch!' if config.directories.empty? + + defaults = self.class.const_get('DEFAULTS') + @options = Listen::Options.new(config.adapter_options, defaults) + rescue + _log_exception 'adapter config failed: %s:%s called from: %s', caller + raise + end + + # TODO: it's a separate method as a temporary workaround for tests + # rubocop:disable Metrics/MethodLength + def configure + if @configured + Listen.logger.warn('Adapter already configured!') + return + end + + @configured = true + + @callbacks ||= {} + config.directories.each do |dir| + callback = @callbacks[dir] || lambda do |event| + _process_event(dir, event) + end + @callbacks[dir] = callback + _configure(dir, &callback) + end + + @snapshots ||= {} + # TODO: separate config per directory (some day maybe) + change_config = Change::Config.new(config.queue, config.silencer) + config.directories.each do |dir| + record = Record.new(dir, config.silencer) + snapshot = Change.new(change_config, record) + @snapshots[dir] = snapshot + end + end + # rubocop:enable Metrics/MethodLength + + def started? + @started + end + + def start + configure + + if started? + Listen.logger.warn('Adapter already started!') + return + end + + @started = true + + @run_thread = Listen::Thread.new("run_thread") do + @snapshots.each_value do |snapshot| + _timed('Record.build()') { snapshot.record.build } + end + _run + end + end + + def stop + _stop + config.queue.close # this causes queue.pop to return `nil` to the front-end + end + + private + + def _stop + @run_thread&.kill + @run_thread = nil + end + + def _timed(title) + start = MonotonicTime.now + yield + diff = MonotonicTime.now - start + Listen.logger.info format('%s: %.05f seconds', title, diff) + rescue + Listen.logger.warn "#{title} crashed: #{$ERROR_INFO.inspect}" + raise + end + + # TODO: allow backend adapters to pass specific invalidation objects + # e.g. Darwin -> DirRescan, INotify -> MoveScan, etc. + def _queue_change(type, dir, rel_path, options) + @snapshots[dir].invalidate(type, rel_path, options) + end + + def _log_exception(msg, caller_stack) + formatted = format( + msg, + $ERROR_INFO, + $ERROR_POSITION * "\n", + caller_stack * "\n" + ) + + Listen.logger.error(formatted) + end + + class << self + def usable? + const_get('OS_REGEXP') =~ RbConfig::CONFIG['target_os'] + end + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/bsd.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/bsd.rb new file mode 100644 index 00000000..aafa2ceb --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/bsd.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +# Listener implementation for BSD's `kqueue`. +# @see http://www.freebsd.org/cgi/man.cgi?query=kqueue +# @see https://github.com/mat813/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb +# +module Listen + module Adapter + class BSD < Base + OS_REGEXP = /bsd|dragonfly/i.freeze + + DEFAULTS = { + events: [ + :delete, + :write, + :extend, + :attrib, + :rename + # :link, :revoke + ] + }.freeze + + BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '') + Please add the following to your Gemfile to avoid polling for changes: + require 'rbconfig' + if RbConfig::CONFIG['target_os'] =~ /#{OS_REGEXP}/ + gem 'rb-kqueue', '>= 0.2' + end + EOS + + def self.usable? + return false unless super + require 'rb-kqueue' + require 'find' + true + rescue LoadError + Listen.adapter_warn(BUNDLER_DECLARE_GEM) + false + end + + private + + def _configure(directory, &callback) + @worker ||= KQueue::Queue.new + @callback = callback + # use Record to make a snapshot of dir, so we + # can detect new files + _find(directory.to_s) { |path| _watch_file(path, @worker) } + end + + def _run + @worker.run + end + + def _process_event(dir, event) + full_path = _event_path(event) + if full_path.directory? + # Force dir content tracking to kick in, or we won't have + # names of added files + _queue_change(:dir, dir, '.', recursive: true) + elsif full_path.exist? + path = full_path.relative_path_from(dir) + _queue_change(:file, dir, path.to_s, change: _change(event.flags)) + end + + # If it is a directory, and it has a write flag, it means a + # file has been added so find out which and deal with it. + # No need to check for removed files, kqueue will forget them + # when the vfs does. + _watch_for_new_file(event) if full_path.directory? + end + + def _change(event_flags) + { modified: [:attrib, :extend], + added: [:write], + removed: [:rename, :delete] }.each do |change, flags| + return change unless (flags & event_flags).empty? + end + nil + end + + def _event_path(event) + Pathname.new(event.watcher.path) + end + + def _watch_for_new_file(event) + queue = event.watcher.queue + _find(_event_path(event).to_s) do |file_path| + unless queue.watchers.find { |_, v| v.path == file_path.to_s } + _watch_file(file_path, queue) + end + end + end + + def _watch_file(path, queue) + queue.watch_file(path, *options.events, &@callback) + rescue Errno::ENOENT => e + Listen.logger.warn "kqueue: watch file failed: #{e.message}" + end + + # Quick rubocop workaround + def _find(*paths, &block) + Find.send(:find, *paths, &block) + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/config.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/config.rb new file mode 100644 index 00000000..5a068a7c --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/config.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'pathname' + +module Listen + module Adapter + class Config + attr_reader :directories, :silencer, :queue, :adapter_options + + def initialize(directories, queue, silencer, adapter_options) + # Default to current directory if no directories are supplied + directories = [Dir.pwd] if directories.to_a.empty? + + # TODO: fix (flatten, array, compact?) + @directories = directories.map do |directory| + Pathname.new(directory.to_s).realpath + end + + @directories.each do |pathname| + unless pathname.directory? + fail ArgumentError, "must be a directory: #{pathname}" + end + end + + @silencer = silencer + @queue = queue + @adapter_options = adapter_options + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/darwin.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/darwin.rb new file mode 100644 index 00000000..3a610c5d --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/darwin.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'listen/thread' + +module Listen + module Adapter + # Adapter implementation for Mac OS X `FSEvents`. + # + class Darwin < Base + OS_REGEXP = /darwin(?(1|2)\d+)/i.freeze + + # The default delay between checking for changes. + DEFAULTS = { latency: 0.1 }.freeze + + INCOMPATIBLE_GEM_VERSION = <<-EOS.gsub(/^ {8}/, '') + rb-fsevent > 0.9.4 no longer supports OS X 10.6 through 10.8. + + Please add the following to your Gemfile to avoid polling for changes: + require 'rbconfig' + if RbConfig::CONFIG['target_os'] =~ /darwin(1[0-3])/i + gem 'rb-fsevent', '<= 0.9.4' + end + EOS + + def self.usable? + version = RbConfig::CONFIG['target_os'][OS_REGEXP, :major_version] + return false unless version + return true if version.to_i >= 13 # darwin13 is OS X 10.9 + + require 'rb-fsevent' + fsevent_version = Gem::Version.new(FSEvent::VERSION) + return true if fsevent_version <= Gem::Version.new('0.9.4') + Listen.adapter_warn(INCOMPATIBLE_GEM_VERSION) + false + end + + private + + def _configure(dir, &callback) + @callbacks[dir] = callback + end + + def _run + require 'rb-fsevent' + worker = FSEvent.new + dirs_to_watch = @callbacks.keys.map(&:to_s) + Listen.logger.info { "fsevent: watching: #{dirs_to_watch.inspect}" } + worker.watch(dirs_to_watch, { latency: options.latency }, &method(:_process_changes)) + @worker_thread = Listen::Thread.new("worker_thread") { worker.run } + end + + def _process_changes(dirs) + dirs.each do |dir| + dir = Pathname.new(dir.sub(%r{/$}, '')) + + @callbacks.each do |watched_dir, callback| + if watched_dir.eql?(dir) || Listen::Directory.ascendant_of?(watched_dir, dir) + callback.call(dir) + end + end + end + end + + def _process_event(dir, path) + Listen.logger.debug { "fsevent: processing path: #{path.inspect}" } + # TODO: does this preserve symlinks? + rel_path = path.relative_path_from(dir).to_s + _queue_change(:dir, dir, rel_path, recursive: true) + end + + def _stop + @worker_thread&.kill + super + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/linux.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/linux.rb new file mode 100644 index 00000000..32be05f4 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/linux.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # @see https://github.com/nex3/rb-inotify + class Linux < Base + OS_REGEXP = /linux/i.freeze + + DEFAULTS = { + events: [ + :recursive, + :attrib, + :create, + :modify, + :delete, + :move, + :close_write + ], + wait_for_delay: 0.1 + }.freeze + + private + + README_URL = 'https://github.com/guard/listen'\ + '/blob/master/README.md#increasing-the-amount-of-inotify-watchers' + + def _configure(directory, &callback) + require 'rb-inotify' + @worker ||= ::INotify::Notifier.new + @worker.watch(directory.to_s, *options.events, &callback) + rescue Errno::ENOSPC + raise ::Listen::Error::INotifyMaxWatchesExceeded, <<~EOS + Unable to monitor directories for changes because iNotify max watches exceeded. See #{README_URL} . + EOS + end + + def _run + @worker.run + end + + # rubocop:disable Metrics/MethodLength + def _process_event(dir, event) + # NOTE: avoid using event.absolute_name since new API + # will need to have a custom recursion implemented + # to properly match events to configured directories + path = Pathname.new(event.watcher.path) + event.name + rel_path = path.relative_path_from(dir).to_s + + Listen.logger.debug { "inotify: #{rel_path} (#{event.flags.inspect})" } + + if /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT'] + if (event.flags & [:moved_to, :moved_from]) || _dir_event?(event) + rel_path = path.dirname.relative_path_from(dir).to_s + end + _queue_change(:dir, dir, rel_path, {}) + return + end + + return if _skip_event?(event) + + cookie_params = event.cookie.zero? ? {} : { cookie: event.cookie } + + # Note: don't pass options to force rescanning the directory, so we can + # detect moving/deleting a whole tree + if _dir_event?(event) + _queue_change(:dir, dir, rel_path, cookie_params) + return + end + + params = cookie_params.merge(change: _change(event.flags)) + + _queue_change(:file, dir, rel_path, params) + end + # rubocop:enable Metrics/MethodLength + + def _skip_event?(event) + # Event on root directory + return true if event.name == '' + # INotify reports changes to files inside directories as events + # on the directories themselves too. + # + # @see http://linux.die.net/man/7/inotify + _dir_event?(event) && (event.flags & [:close, :modify]).any? + end + + def _change(event_flags) + { modified: [:attrib, :close_write], + moved_to: [:moved_to], + moved_from: [:moved_from], + added: [:create], + removed: [:delete] }.each do |change, flags| + return change unless (flags & event_flags).empty? + end + nil + end + + def _dir_event?(event) + event.flags.include?(:isdir) + end + + def _stop + @worker&.close + + super + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/polling.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/polling.rb new file mode 100644 index 00000000..9d281af6 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/polling.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # Polling Adapter that works cross-platform and + # has no dependencies. This is the adapter that + # uses the most CPU processing power and has higher + # file IO than the other implementations. + # + class Polling < Base + OS_REGEXP = //.freeze # match every OS + + DEFAULTS = { latency: 1.0, wait_for_delay: 0.05 }.freeze + + private + + def _configure(_, &callback) + @polling_callbacks ||= [] + @polling_callbacks << callback + end + + def _run + loop do + start = MonotonicTime.now + @polling_callbacks.each do |callback| + callback.call(nil) + if (nap_time = options.latency - (MonotonicTime.now - start)) > 0 + # TODO: warn if nap_time is negative (polling too slow) + sleep(nap_time) + end + end + end + end + + def _process_event(dir, _) + _queue_change(:dir, dir, '.', recursive: true) + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/adapter/windows.rb b/bin/gems/listen-3.9.0/lib/listen/adapter/windows.rb new file mode 100644 index 00000000..26a64005 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/adapter/windows.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Listen + module Adapter + # Adapter implementation for Windows `wdm`. + # + class Windows < Base + OS_REGEXP = /mswin|mingw|cygwin/i.freeze + + BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '') + Please add the following to your Gemfile to avoid polling for changes: + gem 'wdm', '>= 0.1.0' if Gem.win_platform? + EOS + + def self.usable? + return false unless super + require 'wdm' + true + rescue LoadError + Listen.logger.debug format('wdm - load failed: %s:%s', $ERROR_INFO, + $ERROR_POSITION * "\n") + + Listen.adapter_warn(BUNDLER_DECLARE_GEM) + false + end + + private + + def _configure(dir) + require 'wdm' + Listen.logger.debug 'wdm - starting...' + @worker ||= WDM::Monitor.new + @worker.watch_recursively(dir.to_s, :files) do |change| + yield([:file, change]) + end + + @worker.watch_recursively(dir.to_s, :directories) do |change| + yield([:dir, change]) + end + + @worker.watch_recursively(dir.to_s, :attributes, :last_write) do |change| + yield([:attr, change]) + end + end + + def _run + @worker.run! + end + + # rubocop:disable Metrics/MethodLength + def _process_event(dir, event) + Listen.logger.debug "wdm - callback: #{event.inspect}" + + type, change = event + + full_path = Pathname(change.path) + + rel_path = full_path.relative_path_from(dir).to_s + + options = { change: _change(change.type) } + + case type + when :file + _queue_change(:file, dir, rel_path, options) + when :attr + unless full_path.directory? + _queue_change(:file, dir, rel_path, options) + end + when :dir + case change.type + when :removed + # TODO: check if watched dir? + _queue_change(:dir, dir, Pathname(rel_path).dirname.to_s, {}) + when :added + _queue_change(:dir, dir, rel_path, {}) + # do nothing - changed directory means either: + # - removed subdirs (handled above) + # - added subdirs (handled above) + # - removed files (handled by _file_callback) + # - added files (handled by _file_callback) + # so what's left? + end + end + end + # rubocop:enable Metrics/MethodLength + + def _change(type) + { modified: [:modified, :attrib], # TODO: is attrib really passed? + added: [:added, :renamed_new_file], + removed: [:removed, :renamed_old_file] }.find do |change, types| + types.include?(type) and break change + end + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/backend.rb b/bin/gems/listen-3.9.0/lib/listen/backend.rb new file mode 100644 index 00000000..cab286c1 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/backend.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'listen/adapter' +require 'listen/adapter/base' +require 'listen/adapter/config' + +require 'forwardable' + +# This class just aggregates configuration object to avoid Listener specs +# from exploding with huge test setup blocks +module Listen + class Backend + extend Forwardable + + def initialize(directories, queue, silencer, config) + adapter_select_opts = config.adapter_select_options + + adapter_class = Adapter.select(adapter_select_opts) + + # Use default from adapter if possible + @min_delay_between_events = config.min_delay_between_events + @min_delay_between_events ||= adapter_class::DEFAULTS[:wait_for_delay] + @min_delay_between_events ||= 0.1 + + adapter_opts = config.adapter_instance_options(adapter_class) + + aconfig = Adapter::Config.new(directories, queue, silencer, adapter_opts) + @adapter = adapter_class.new(aconfig) + end + + delegate start: :adapter + delegate stop: :adapter + + attr_reader :min_delay_between_events + + private + + attr_reader :adapter + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/change.rb b/bin/gems/listen-3.9.0/lib/listen/change.rb new file mode 100644 index 00000000..c19b9001 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/change.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'listen/file' +require 'listen/directory' + +module Listen + # TODO: rename to Snapshot + class Change + # TODO: test this class for coverage + class Config + def initialize(queue, silencer) + @queue = queue + @silencer = silencer + end + + def silenced?(path, type) + @silencer.silenced?(Pathname(path), type) + end + + def queue(*args) + @queue << args + end + end + + attr_reader :record + + def initialize(config, record) + @config = config + @record = record + end + + # Invalidate some part of the snapshot/record (dir, file, subtree, etc.) + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity + def invalidate(type, rel_path, options) + watched_dir = Pathname.new(record.root) + + change = options[:change] + cookie = options[:cookie] + + if !cookie && @config.silenced?(rel_path, type) + Listen.logger.debug { "(silenced): #{rel_path.inspect}" } + return + end + + path = watched_dir + rel_path + + Listen.logger.debug do + log_details = options[:silence] && 'recording' || change || 'unknown' + "#{log_details}: #{type}:#{path} (#{options.inspect})" + end + + if change + options = cookie ? { cookie: cookie } : {} + @config.queue(type, change, watched_dir, rel_path, options) + elsif type == :dir + # NOTE: POSSIBLE RECURSION + # TODO: fix - use a queue instead + Directory.scan(self, rel_path, options) + elsif (change = File.change(record, rel_path)) && !options[:silence] + @config.queue(:file, change, watched_dir, rel_path) + end + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/cli.rb b/bin/gems/listen-3.9.0/lib/listen/cli.rb new file mode 100644 index 00000000..e3173133 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/cli.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'thor' +require 'listen' +require 'logger' + +module Listen + class CLI < Thor + default_task :start + + desc 'start', 'Starts Listen' + + class_option :verbose, + type: :boolean, + default: false, + aliases: '-v', + banner: 'Verbose' + + class_option :directory, + type: :array, + default: ['.'], + aliases: '-d', + banner: 'One or more directories to listen to' + + class_option :relative, + type: :boolean, + default: false, + aliases: '-r', + banner: 'Convert paths relative to current directory' + + def start + Listen::Forwarder.new(options).start + end + end + + class Forwarder + attr_reader :logger + + def initialize(options) + @options = options + @logger = ::Logger.new(STDOUT, level: ::Logger::INFO) + @logger.formatter = proc { |_, _, _, msg| "#{msg}\n" } + end + + def start + logger.info 'Starting listen...' + + directory = @options[:directory] + relative = @options[:relative] + callback = proc do |modified, added, removed| + if @options[:verbose] + logger.info "+ #{added}" unless added.empty? + logger.info "- #{removed}" unless removed.empty? + logger.info "> #{modified}" unless modified.empty? + end + end + + listener = Listen.to(*directory, relative: relative, &callback) + + listener.start + + sleep 0.5 while listener.processing? + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/directory.rb b/bin/gems/listen-3.9.0/lib/listen/directory.rb new file mode 100644 index 00000000..19178b3e --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/directory.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'set' + +module Listen + # TODO: refactor (turn it into a normal object, cache the stat, etc) + class Directory + # rubocop:disable Metrics/MethodLength + def self.scan(snapshot, rel_path, options) + record = snapshot.record + dir = Pathname.new(record.root) + previous = record.dir_entries(rel_path) + + record.add_dir(rel_path) + + # TODO: use children(with_directory: false) + path = dir + rel_path + current = Set.new(_children(path)) + + Listen.logger.debug do + format('%s: %s(%s): %s -> %s', + (options[:silence] ? 'Recording' : 'Scanning'), + rel_path, options.inspect, previous.inspect, current.inspect) + end + + begin + current.each do |full_path| + type = ::File.lstat(full_path.to_s).directory? ? :dir : :file + item_rel_path = full_path.relative_path_from(dir).to_s + _change(snapshot, type, item_rel_path, options) + end + rescue Errno::ENOENT + # The directory changed meanwhile, so rescan it + current = Set.new(_children(path)) + retry + end + + # TODO: this is not tested properly + previous = previous.reject { |entry, _| current.include?(path + entry) } + + _async_changes(snapshot, Pathname.new(rel_path), previous, options) + rescue Errno::ENOENT, Errno::EHOSTDOWN + record.unset_path(rel_path) + _async_changes(snapshot, Pathname.new(rel_path), previous, options) + rescue Errno::ENOTDIR + # TODO: path not tested + record.unset_path(rel_path) + _async_changes(snapshot, path, previous, options) + _change(snapshot, :file, rel_path, options) + rescue + Listen.logger.warn { format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n") } + raise + end + # rubocop:enable Metrics/MethodLength + + def self.ascendant_of?(base, other) + other.ascend do |ascendant| + break true if base == ascendant + end + end + + def self._async_changes(snapshot, path, previous, options) + fail "Not a Pathname: #{path.inspect}" unless path.respond_to?(:children) + previous.each do |entry, data| + # TODO: this is a hack with insufficient testing + type = data.key?(:mtime) ? :file : :dir + rel_path_s = (path + entry).to_s + _change(snapshot, type, rel_path_s, options) + end + end + + def self._change(snapshot, type, path, options) + return snapshot.invalidate(type, path, options) if type == :dir + + # Minor param cleanup for tests + # TODO: use a dedicated Event class + opts = options.dup + opts.delete(:recursive) + snapshot.invalidate(type, path, opts) + end + + def self._children(path) + return path.children unless RUBY_ENGINE == 'jruby' + + # JRuby inconsistency workaround, see: + # https://github.com/jruby/jruby/issues/3840 + exists = path.exist? + directory = path.directory? + exists && !directory and raise Errno::ENOTDIR, path.to_s + path.children + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/error.rb b/bin/gems/listen-3.9.0/lib/listen/error.rb new file mode 100644 index 00000000..a5f2dc11 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/error.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Besides programming error exceptions like ArgumentError, +# all public interface exceptions should be declared here and inherit from Listen::Error. +module Listen + class Error < RuntimeError + class NotStarted < Error; end + class SymlinkLoop < Error; end + class INotifyMaxWatchesExceeded < Error; end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/event/config.rb b/bin/gems/listen-3.9.0/lib/listen/event/config.rb new file mode 100644 index 00000000..c83ee37b --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/event/config.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Listen + module Event + class Config + attr_reader :listener, :event_queue, :min_delay_between_events + + def initialize( + listener, + event_queue, + queue_optimizer, + wait_for_delay, + &block + ) + + @listener = listener + @event_queue = event_queue + @queue_optimizer = queue_optimizer + @min_delay_between_events = wait_for_delay + @block = block + end + + def sleep(seconds) + Kernel.sleep(seconds) + end + + def call(*args) + @block&.call(*args) + end + + def callable? + @block + end + + def optimize_changes(changes) + @queue_optimizer.smoosh_changes(changes) + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/event/loop.rb b/bin/gems/listen-3.9.0/lib/listen/event/loop.rb new file mode 100644 index 00000000..dd071f01 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/event/loop.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'thread' + +require 'timeout' +require 'listen/event/processor' +require 'listen/thread' +require 'listen/error' + +module Listen + module Event + class Loop + include Listen::FSM + + Error = ::Listen::Error + NotStarted = ::Listen::Error::NotStarted # for backward compatibility + + start_state :pre_start + state :pre_start + state :starting + state :started + state :stopped + + def initialize(config) + @config = config + @wait_thread = nil + @reasons = ::Queue.new + initialize_fsm + end + + def wakeup_on_event + if started? && @wait_thread&.alive? + _wakeup(:event) + end + end + + def started? + state == :started + end + + MAX_STARTUP_SECONDS = 5.0 + + # @raises Error::NotStarted if background thread hasn't started in MAX_STARTUP_SECONDS + def start + # TODO: use a Fiber instead? + return unless state == :pre_start + + transition! :starting + + @wait_thread = Listen::Thread.new("wait_thread") do + _process_changes + end + + Listen.logger.debug("Waiting for processing to start...") + + wait_for_state(:started, timeout: MAX_STARTUP_SECONDS) or + raise Error::NotStarted, "thread didn't start in #{MAX_STARTUP_SECONDS} seconds (in state: #{state.inspect})" + + Listen.logger.debug('Processing started.') + end + + def pause + # TODO: works? + # fail NotImplementedError + end + + def stop + transition! :stopped + + @wait_thread&.join + @wait_thread = nil + end + + def stopped? + state == :stopped + end + + private + + def _process_changes + processor = Event::Processor.new(@config, @reasons) + + transition! :started + + processor.loop_for(@config.min_delay_between_events) + end + + def _wakeup(reason) + @reasons << reason + @wait_thread.wakeup + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/event/processor.rb b/bin/gems/listen-3.9.0/lib/listen/event/processor.rb new file mode 100644 index 00000000..57656cbe --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/event/processor.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'listen/monotonic_time' + +module Listen + module Event + class Processor + def initialize(config, reasons) + @config = config + @listener = config.listener + @reasons = reasons + _reset_no_unprocessed_events + end + + # TODO: implement this properly instead of checking the state at arbitrary + # points in time + def loop_for(latency) + @latency = latency + + loop do + event = _wait_until_events + _check_stopped + _wait_until_events_calm_down + _wait_until_no_longer_paused + _process_changes(event) + end + rescue Stopped + Listen.logger.debug('Processing stopped') + end + + private + + class Stopped < RuntimeError + end + + def _wait_until_events_calm_down + loop do + now = MonotonicTime.now + + # Assure there's at least latency between callbacks to allow + # for accumulating changes + diff = _deadline - now + break if diff <= 0 + + # give events a bit of time to accumulate so they can be + # compressed/optimized + _sleep(diff) + end + end + + def _wait_until_no_longer_paused + @listener.wait_for_state(*(Listener.states.keys - [:paused])) + end + + def _check_stopped + if @listener.stopped? + _flush_wakeup_reasons + raise Stopped + end + end + + def _sleep(seconds) + _check_stopped + config.sleep(seconds) + _check_stopped + + _flush_wakeup_reasons do |reason| + if reason == :event && !@listener.paused? + _remember_time_of_first_unprocessed_event + end + end + end + + def _remember_time_of_first_unprocessed_event + @_remember_time_of_first_unprocessed_event ||= MonotonicTime.now + end + + def _reset_no_unprocessed_events + @_remember_time_of_first_unprocessed_event = nil + end + + def _deadline + @_remember_time_of_first_unprocessed_event + @latency + end + + # blocks until event is popped + # returns the event or `nil` when the event_queue is closed + def _wait_until_events + config.event_queue.pop.tap do |_event| + @_remember_time_of_first_unprocessed_event ||= MonotonicTime.now + end + end + + def _flush_wakeup_reasons + until @reasons.empty? + reason = @reasons.pop + yield reason if block_given? + end + end + + # for easier testing without sleep loop + def _process_changes(event) + _reset_no_unprocessed_events + + changes = [event] + changes << config.event_queue.pop until config.event_queue.empty? + + return unless config.callable? + + hash = config.optimize_changes(changes) + result = [hash[:modified], hash[:added], hash[:removed]] + return if result.all?(&:empty?) + + block_start = MonotonicTime.now + exception_note = " (exception)" + ::Listen::Thread.rescue_and_log('_process_changes') do + config.call(*result) + exception_note = nil + end + Listen.logger.debug "Callback#{exception_note} took #{MonotonicTime.now - block_start} sec" + end + + attr_reader :config + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/event/queue.rb b/bin/gems/listen-3.9.0/lib/listen/event/queue.rb new file mode 100644 index 00000000..ffcd67c5 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/event/queue.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'thread' + +require 'forwardable' + +module Listen + module Event + class Queue + extend Forwardable + + class Config + def initialize(relative) + @relative = relative + end + + def relative? + @relative + end + end + + def initialize(config) + @event_queue = ::Queue.new + @config = config + end + + def <<(args) + type, change, dir, path, options = *args + fail "Invalid type: #{type.inspect}" unless [:dir, :file].include? type + fail "Invalid change: #{change.inspect}" unless change.is_a?(Symbol) + fail "Invalid path: #{path.inspect}" unless path.is_a?(String) + + dir = if @config.relative? + _safe_relative_from_cwd(dir) + else + dir + end + @event_queue << [type, change, dir, path, options] + end + + delegate empty?: :@event_queue + delegate pop: :@event_queue + delegate close: :@event_queue + + private + + def _safe_relative_from_cwd(dir) + dir.relative_path_from(Pathname.pwd) + rescue ArgumentError + dir + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/file.rb b/bin/gems/listen-3.9.0/lib/listen/file.rb new file mode 100644 index 00000000..41df6327 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/file.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'digest' + +module Listen + class File + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity + def self.change(record, rel_path) + path = Pathname.new(record.root) + rel_path + lstat = path.lstat + + data = { mtime: lstat.mtime.to_f, mode: lstat.mode, size: lstat.size } + + record_data = record.file_data(rel_path) + + if record_data.empty? + record.update_file(rel_path, data) + return :added + end + + if data[:mode] != record_data[:mode] + record.update_file(rel_path, data) + return :modified + end + + if data[:mtime] != record_data[:mtime] + record.update_file(rel_path, data) + return :modified + end + + if data[:size] != record_data[:size] + record.update_file(rel_path, data) + return :modified + end + + return if /1|true/ =~ ENV['LISTEN_GEM_DISABLE_HASHING'] + return unless inaccurate_mac_time?(lstat) + + # Check if change happened within 1 second (maybe it's even + # too much, e.g. 0.3-0.5 could be sufficient). + # + # With rb-fsevent, there's a (configurable) latency between + # when file was changed and when the event was triggered. + # + # If a file is saved at ???14.998, by the time the event is + # actually received by Listen, the time could already be e.g. + # ???15.7. + # + # And since Darwin adapter uses directory scanning, the file + # mtime may be the same (e.g. file was changed at ???14.001, + # then at ???14.998, but the fstat time would be ???14.0 in + # both cases). + # + # If change happened at ???14.999997, the mtime is 14.0, so for + # an mtime=???14.0 we assume it could even be almost ???15.0 + # + # So if Time.now.to_f is ???15.999998 and stat reports mtime + # at ???14.0, then event was due to that file'd change when: + # + # ???15.999997 - ???14.999998 < 1.0s + # + # So the "2" is "1 + 1" (1s to cover rb-fsevent latency + + # 1s maximum difference between real mtime and that recorded + # in the file system) + # + return if data[:mtime].to_i + 2 <= Time.now.to_f + + sha = Digest::SHA256.file(path).digest + record.update_file(rel_path, data.merge(sha: sha)) + if record_data[:sha] && sha != record_data[:sha] + :modified + end + rescue SystemCallError + record.unset_path(rel_path) + :removed + rescue + Listen.logger.debug "lstat failed for: #{rel_path} (#{$ERROR_INFO})" + raise + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity + + def self.inaccurate_mac_time?(stat) + # 'mac' means Modified/Accessed/Created + + # Since precision depends on mounted FS (e.g. you can have a FAT partiion + # mounted on Linux), check for fields with a remainder to detect this + + [stat.mtime, stat.ctime, stat.atime].map(&:usec).all?(&:zero?) + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/fsm.rb b/bin/gems/listen-3.9.0/lib/listen/fsm.rb new file mode 100644 index 00000000..154ad2b3 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/fsm.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +# Code copied from https://github.com/celluloid/celluloid-fsm + +require 'thread' + +module Listen + module FSM + # Included hook to extend class methods + def self.included(klass) + klass.send :extend, ClassMethods + end + + module ClassMethods + # Obtain or set the start state + # Passing a state name sets the start state + def start_state(new_start_state = nil) + if new_start_state + new_start_state.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_start_state.inspect})" + @start_state = new_start_state + else + defined?(@start_state) or raise ArgumentError, "`start_state :` must be declared before `new`" + @start_state + end + end + + # The valid states for this FSM, as a hash with state name symbols as keys and State objects as values. + def states + @states ||= {} + end + + # Declare an FSM state and optionally provide a callback block to fire on state entry + # Options: + # * to: a state or array of states this state can transition to + def state(state_name, to: nil, &block) + state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{state_name.inspect})" + states[state_name] = State.new(state_name, to, &block) + end + end + + # Note: including classes must call initialize_fsm from their initialize method. + def initialize_fsm + @fsm_initialized = true + @state = self.class.start_state + @mutex = ::Mutex.new + @state_changed = ::ConditionVariable.new + end + + # Current state of the FSM, stored as a symbol + attr_reader :state + + # checks for one of the given states to wait for + # if not already, waits for a state change (up to timeout seconds--`nil` means infinite) + # returns truthy iff the transition to one of the desired state has occurred + def wait_for_state(*wait_for_states, timeout: nil) + wait_for_states.each do |state| + state.is_a?(Symbol) or raise ArgumentError, "states must be symbols (got #{state.inspect})" + end + @mutex.synchronize do + if !wait_for_states.include?(@state) + @state_changed.wait(@mutex, timeout) + end + wait_for_states.include?(@state) + end + end + + private + + def transition(new_state_name) + new_state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_state_name.inspect})" + if (new_state = validate_and_sanitize_new_state(new_state_name)) + transition_with_callbacks!(new_state) + end + end + + # Low-level, immediate state transition with no checks or callbacks. + def transition!(new_state_name) + new_state_name.is_a?(Symbol) or raise ArgumentError, "state name must be a Symbol (got #{new_state_name.inspect})" + @fsm_initialized or raise ArgumentError, "FSM not initialized. You must call initialize_fsm from initialize!" + @mutex.synchronize do + yield if block_given? + @state = new_state_name + @state_changed.broadcast + end + end + + def validate_and_sanitize_new_state(new_state_name) + return nil if @state == new_state_name + + if current_state && !current_state.valid_transition?(new_state_name) + valid = current_state.transitions.map(&:to_s).join(', ') + msg = "#{self.class} can't change state from '#{@state}' to '#{new_state_name}', only to: #{valid}" + raise ArgumentError, msg + end + + unless (new_state = self.class.states[new_state_name]) + new_state_name == self.class.start_state or raise ArgumentError, "invalid state for #{self.class}: #{new_state_name}" + end + + new_state + end + + def transition_with_callbacks!(new_state) + transition! new_state.name + new_state.call(self) + end + + def current_state + self.class.states[@state] + end + + class State + attr_reader :name, :transitions + + def initialize(name, transitions, &block) + @name = name + @block = block + @transitions = if transitions + Array(transitions).map(&:to_sym) + end + end + + def call(obj) + obj.instance_eval(&@block) if @block + end + + def valid_transition?(new_state) + # All transitions are allowed if none are expressly declared + !@transitions || @transitions.include?(new_state.to_sym) + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/listener.rb b/bin/gems/listen-3.9.0/lib/listen/listener.rb new file mode 100644 index 00000000..d886fdb4 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/listener.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +require 'English' + +require 'listen/version' + +require 'listen/backend' + +require 'listen/silencer' +require 'listen/silencer/controller' + +require 'listen/queue_optimizer' + +require 'listen/fsm' + +require 'listen/event/loop' +require 'listen/event/queue' +require 'listen/event/config' + +require 'listen/listener/config' + +module Listen + class Listener + include Listen::FSM + + # Initializes the directories listener. + # + # @param [String] directory the directories to listen to + # @param [Hash] options the listen options (see Listen::Listener::Options) + # + # @yield [modified, added, removed] the changed files + # @yieldparam [Array] modified the list of modified files + # @yieldparam [Array] added the list of added files + # @yieldparam [Array] removed the list of removed files + # + # rubocop:disable Metrics/MethodLength + def initialize(*dirs, &block) + options = dirs.last.is_a?(Hash) ? dirs.pop : {} + + @config = Config.new(options) + + eq_config = Event::Queue::Config.new(@config.relative?) + queue = Event::Queue.new(eq_config) + + silencer = Silencer.new + rules = @config.silencer_rules + @silencer_controller = Silencer::Controller.new(silencer, rules) + + @backend = Backend.new(dirs, queue, silencer, @config) + + optimizer_config = QueueOptimizer::Config.new(@backend, silencer) + + pconfig = Event::Config.new( + self, + queue, + QueueOptimizer.new(optimizer_config), + @backend.min_delay_between_events, + &block) + + @processor = Event::Loop.new(pconfig) + + initialize_fsm + end + # rubocop:enable Metrics/MethodLength + + start_state :initializing + + state :initializing, to: [:backend_started, :stopped] + + state :backend_started, to: [:processing_events, :stopped] do + @backend.start + end + + state :processing_events, to: [:paused, :stopped] do + @processor.start + end + + state :paused, to: [:processing_events, :stopped] do + @processor.pause + end + + state :stopped, to: [:backend_started] do + @backend.stop # halt events ASAP + @processor.stop + end + + # Starts processing events and starts adapters + # or resumes invoking callbacks if paused + def start + case state + when :initializing + transition :backend_started + transition :processing_events + when :paused + transition :processing_events + else + raise ArgumentError, "cannot start from state #{state.inspect}" + end + end + + # Stops both listening for events and processing them + def stop + transition :stopped + end + + # Stops invoking callbacks (messages pile up) + def pause + transition :paused + end + + # processing means callbacks are called + def processing? + state == :processing_events + end + + def paused? + state == :paused + end + + def stopped? + state == :stopped + end + + def ignore(regexps) + @silencer_controller.append_ignores(regexps) + end + + def ignore!(regexps) + @silencer_controller.replace_with_bang_ignores(regexps) + end + + def only(regexps) + @silencer_controller.replace_with_only(regexps) + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/listener/config.rb b/bin/gems/listen-3.9.0/lib/listen/listener/config.rb new file mode 100644 index 00000000..56e4b7c9 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/listener/config.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Listen + class Listener + class Config + DEFAULTS = { + # Listener options + debug: false, # TODO: is this broken? + wait_for_delay: nil, # NOTE: should be provided by adapter if possible + relative: false, + + # Backend selecting options + force_polling: false, + polling_fallback_message: nil + }.freeze + + def initialize(opts) + @options = DEFAULTS.merge(opts) + @relative = @options[:relative] + @min_delay_between_events = @options[:wait_for_delay] + @silencer_rules = @options # silencer will extract what it needs + end + + def relative? + @relative + end + + attr_reader :min_delay_between_events, :silencer_rules + + def adapter_instance_options(klass) + valid_keys = klass.const_get('DEFAULTS').keys + Hash[@options.select { |key, _| valid_keys.include?(key) }] + end + + def adapter_select_options + valid_keys = %w[force_polling polling_fallback_message].map(&:to_sym) + Hash[@options.select { |key, _| valid_keys.include?(key) }] + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/logger.rb b/bin/gems/listen-3.9.0/lib/listen/logger.rb new file mode 100644 index 00000000..9689252e --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/logger.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Listen + @logger = nil + + # Listen.logger will always be present. + # If you don't want logging, set Listen.logger = ::Logger.new('/dev/null', level: ::Logger::UNKNOWN) + + @adapter_warn_behavior = :warn + + class << self + attr_writer :logger + attr_accessor :adapter_warn_behavior + + def logger + @logger ||= default_logger + end + + def adapter_warn(message) + case ENV['LISTEN_GEM_ADAPTER_WARN_BEHAVIOR']&.to_sym || adapter_warn_behavior_callback(message) + when :log + logger.warn(message) + when :silent, nil, false + # do nothing + else # :warn + warn(message) + end + end + + private + + def default_logger + level = + case ENV['LISTEN_GEM_DEBUGGING'].to_s + when /debug|2/i + ::Logger::DEBUG + when /info|true|yes|1/i + ::Logger::INFO + when /warn/i + ::Logger::WARN + when /fatal/i + ::Logger::FATAL + else + ::Logger::ERROR + end + + ::Logger.new(STDERR, level: level) + end + + def adapter_warn_behavior_callback(message) + if adapter_warn_behavior.respond_to?(:call) + case behavior = adapter_warn_behavior.call(message) + when Symbol + behavior + when false, nil + :silent + else + :warn + end + else + adapter_warn_behavior + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/monotonic_time.rb b/bin/gems/listen-3.9.0/lib/listen/monotonic_time.rb new file mode 100644 index 00000000..51b0fc9d --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/monotonic_time.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Listen + module MonotonicTime + class << self + if defined?(Process::CLOCK_MONOTONIC) + + def now + Process.clock_gettime(Process::CLOCK_MONOTONIC) + end + + elsif defined?(Process::CLOCK_MONOTONIC_RAW) + + def now + Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW) + end + + else + + def now + Time.now.to_f + end + + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/options.rb b/bin/gems/listen-3.9.0/lib/listen/options.rb new file mode 100644 index 00000000..0f1abb1a --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/options.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Listen + class Options + def initialize(opts, defaults) + @options = {} + given_options = opts.dup + defaults.each_key do |key| + @options[key] = given_options.delete(key) || defaults[key] + end + + given_options.empty? or raise ArgumentError, "Unknown options: #{given_options.inspect}" + end + + # rubocop:disable Lint/MissingSuper + def respond_to_missing?(name, *_) + @options.has_key?(name) + end + + def method_missing(name, *_) + respond_to_missing?(name) or raise NameError, "Bad option: #{name.inspect} (valid:#{@options.keys.inspect})" + @options[name] + end + # rubocop:enable Lint/MissingSuper + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/queue_optimizer.rb b/bin/gems/listen-3.9.0/lib/listen/queue_optimizer.rb new file mode 100644 index 00000000..2ccf4cd4 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/queue_optimizer.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module Listen + class QueueOptimizer + class Config + def initialize(adapter_class, silencer) + @adapter_class = adapter_class + @silencer = silencer + end + + def exist?(path) + Pathname(path).exist? + end + + def silenced?(path, type) + @silencer.silenced?(path, type) + end + + def debug(*args, &block) + Listen.logger.debug(*args, &block) + end + end + + def smoosh_changes(changes) + # TODO: adapter could be nil at this point (shutdown) + cookies = changes.group_by do |_, _, _, _, options| + (options || {})[:cookie] + end + _squash_changes(_reinterpret_related_changes(cookies)) + end + + def initialize(config) + @config = config + end + + private + + attr_reader :config + + # groups changes into the expected structure expected by + # clients + def _squash_changes(changes) + # We combine here for backward compatibility + # Newer clients should receive dir and path separately + changes = changes.map { |change, dir, path| [change, dir + path] } + + actions = changes.group_by(&:last).map do |path, action_list| + [_logical_action_for(path, action_list.map(&:first)), path.to_s] + end + + config.debug("listen: raw changes: #{actions.inspect}") + + { modified: [], added: [], removed: [] }.tap do |squashed| + actions.each do |type, path| + squashed[type] << path unless type.nil? + end + config.debug("listen: final changes: #{squashed.inspect}") + end + end + + def _logical_action_for(path, actions) + actions << :added if actions.delete(:moved_to) + actions << :removed if actions.delete(:moved_from) + + modified = actions.find { |x| x == :modified } + _calculate_add_remove_difference(actions, path, modified) + end + + def _calculate_add_remove_difference(actions, path, default_if_exists) + added = actions.count { |x| x == :added } + removed = actions.count { |x| x == :removed } + diff = added - removed + + # TODO: avoid checking if path exists and instead assume the events are + # in order (if last is :removed, it doesn't exist, etc.) + if config.exist?(path) + if diff > 0 + :added + elsif diff.zero? && added > 0 + :modified + else + default_if_exists + end + else + diff < 0 ? :removed : nil + end + end + + # remove extraneous rb-inotify events, keeping them only if it's a possible + # editor rename() call (e.g. Kate and Sublime) + def _reinterpret_related_changes(cookies) + table = { moved_to: :added, moved_from: :removed } + cookies.flat_map do |_, changes| + if (editor_modified = editor_modified?(changes)) + [[:modified, *editor_modified]] + else + not_silenced = changes.reject do |type, _, _, path, _| + config.silenced?(Pathname(path), type) + end + not_silenced.map do |_, change, dir, path, _| + [table.fetch(change, change), dir, path] + end + end + end + end + + def editor_modified?(changes) + return unless changes.size == 2 + + from_type = from = nil + to_type = to_dir = to = nil + + changes.each do |data| + case data[1] + when :moved_from + from_type, _from_change, _, from, = data + when :moved_to + to_type, _to_change, to_dir, to, = data + end + end + + # Expect an ignored moved_from and non-ignored moved_to + # to qualify as an "editor modify" + if from && to && config.silenced?(Pathname(from), from_type) && !config.silenced?(Pathname(to), to_type) + [to_dir, to] + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/record.rb b/bin/gems/listen-3.9.0/lib/listen/record.rb new file mode 100644 index 00000000..2218149f --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/record.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +require 'thread' +require 'listen/record/entry' +require 'listen/record/symlink_detector' + +module Listen + class Record + # TODO: one Record object per watched directory? + # TODO: deprecate + + attr_reader :root + + def initialize(directory, silencer) + reset_tree + @root = directory.to_s + @silencer = silencer + end + + def add_dir(rel_path) + if !empty_dirname?(rel_path.to_s) + @tree[rel_path.to_s] + end + end + + def update_file(rel_path, data) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + _fast_update_file(dirname, basename, data) + end + + def unset_path(rel_path) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + _fast_unset_path(dirname, basename) + end + + def file_data(rel_path) + dirname, basename = Pathname(rel_path).split.map(&:to_s) + if empty_dirname?(dirname) + @tree[basename].dup + else + @tree[dirname][basename] ||= {} + @tree[dirname][basename].dup + end + end + + def dir_entries(rel_path) + rel_path_s = rel_path.to_s + subtree = if empty_dirname?(rel_path_s) + @tree + else + @tree[rel_path_s] + end + + subtree.each_with_object({}) do |(key, values), result| + # only return data for file entries inside the dir (which will each be sub-hashes) + if values.is_a?(Hash) + result[key] = values.has_key?(:mtime) ? values : {} + end + end + end + + def build + reset_tree + # TODO: test with a file name given + # TODO: test other permissions + # TODO: test with mixed encoding + symlink_detector = SymlinkDetector.new + remaining = ::Queue.new + remaining << Entry.new(root, nil, nil) + _fast_build_dir(remaining, symlink_detector) until remaining.empty? + end + + private + + def empty_dirname?(dirname) + dirname == '.' || dirname == '' + end + + def reset_tree + @tree = Hash.new { |h, k| h[k] = {} } + end + + def _fast_update_file(dirname, basename, data) + if empty_dirname?(dirname.to_s) + @tree[basename] = @tree[basename].merge(data) + else + @tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data) + end + end + + def _fast_unset_path(dirname, basename) + # this may need to be reworked to properly remove + # entries from a tree, without adding non-existing dirs to the record + if empty_dirname?(dirname.to_s) + if @tree.key?(basename) + @tree.delete(basename) + end + elsif @tree.key?(dirname) + @tree[dirname].delete(basename) + end + end + + def _fast_build_dir(remaining, symlink_detector) + entry = remaining.pop + return if @silencer.silenced?(entry.record_dir_key, :dir) + + children = entry.children # NOTE: children() implicitly tests if dir + symlink_detector.verify_unwatched!(entry) + children.each { |child| remaining << child } + add_dir(entry.record_dir_key) + rescue Errno::ENOTDIR + _fast_try_file(entry) + rescue SystemCallError, SymlinkDetector::Error + _fast_unset_path(entry.relative, entry.name) + end + + def _fast_try_file(entry) + _fast_update_file(entry.relative, entry.name, entry.meta) + rescue SystemCallError + _fast_unset_path(entry.relative, entry.name) + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/record/entry.rb b/bin/gems/listen-3.9.0/lib/listen/record/entry.rb new file mode 100644 index 00000000..a01a1592 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/record/entry.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Listen + # @private api + class Record + # Represents a directory entry (dir or file) + class Entry + # file: "/home/me/watched_dir", "app/models", "foo.rb" + # dir, "/home/me/watched_dir", "." + def initialize(root, relative, name = nil) + @root = root + @relative = relative + @name = name + end + + attr_reader :root, :relative, :name + + def children + child_relative = _join + (_entries(sys_path) - %w[. ..]).map do |name| + Entry.new(@root, child_relative, name) + end + end + + def meta + lstat = ::File.lstat(sys_path) + { mtime: lstat.mtime.to_f, mode: lstat.mode, size: lstat.size } + end + + # record hash is e.g. + # if @record["/home/me/watched_dir"]["project/app/models"]["foo.rb"] + # if @record["/home/me/watched_dir"]["project/app"]["models"] + # record_dir_key is "project/app/models" + def record_dir_key + ::File.join(*[@relative, @name].compact) + end + + def sys_path + # Use full path in case someone uses chdir + ::File.join(*[@root, @relative, @name].compact) + end + + def real_path + @real_path ||= ::File.realpath(sys_path) + end + + private + + def _join + args = [@relative, @name].compact + args.empty? ? nil : ::File.join(*args) + end + + def _entries(dir) + return Dir.entries(dir) unless RUBY_ENGINE == 'jruby' + + # JRuby inconsistency workaround, see: + # https://github.com/jruby/jruby/issues/3840 + exists = ::File.exist?(dir) + directory = ::File.directory?(dir) + return Dir.entries(dir) unless exists && !directory + raise Errno::ENOTDIR, dir + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/record/symlink_detector.rb b/bin/gems/listen-3.9.0/lib/listen/record/symlink_detector.rb new file mode 100644 index 00000000..f193043c --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/record/symlink_detector.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'set' +require 'listen/error' + +module Listen + # @private api + class Record + class SymlinkDetector + README_URL = 'https://github.com/guard/listen/blob/master/README.md' + + SYMLINK_LOOP_ERROR = <<-EOS + ** ERROR: directory is already being watched! ** + + Directory: %s + + is already being watched through: %s + + MORE INFO: #{README_URL} + EOS + + Error = ::Listen::Error # for backward compatibility + + def initialize + @real_dirs = Set.new + end + + def verify_unwatched!(entry) + real_path = entry.real_path + @real_dirs.add?(real_path) or _fail(entry.sys_path, real_path) + end + + # Leaving this stub here since some warning work-arounds were referring to it. + # Deprecated. Will be removed in Listen v4.0. + def warn(message) + Listen.adapter_warn(message) + end + + private + + def _fail(symlinked, real_path) + warn(format(SYMLINK_LOOP_ERROR, symlinked, real_path)) + raise ::Listen::Error::SymlinkLoop, 'Failed due to looped symlinks' + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/silencer.rb b/bin/gems/listen-3.9.0/lib/listen/silencer.rb new file mode 100644 index 00000000..7253a8b8 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/silencer.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module Listen + class Silencer + # The default list of directories that get ignored. + DEFAULT_IGNORED_FILES = %r{\A(?: + \.git + | \.svn + | \.hg + | \.rbx + | \.bundle + | bundle + | vendor/bundle + | log + | tmp + | vendor/ruby + + # emacs temp files + | \#.+\# + | \.\#.+ + )(/|\z)}x.freeze + + # The default list of files that get ignored. + DEFAULT_IGNORED_EXTENSIONS = %r{(?: + # Kate's tmp\/swp files + \..*\d+\.new + | \.kate-swp + + # Gedit tmp files + | \.goutputstream-.{6} + + # Intellij files + | ___jb_bak___ + | ___jb_old___ + + # Vim swap files and write test + | \.sw[px] + | \.swpx + | ^4913 + + # Sed temporary files - but without actual words, like 'sedatives' + | (?:\A + sed + + (?: + [a-zA-Z0-9]{0}[A-Z]{1}[a-zA-Z0-9]{5} | + [a-zA-Z0-9]{1}[A-Z]{1}[a-zA-Z0-9]{4} | + [a-zA-Z0-9]{2}[A-Z]{1}[a-zA-Z0-9]{3} | + [a-zA-Z0-9]{3}[A-Z]{1}[a-zA-Z0-9]{2} | + [a-zA-Z0-9]{4}[A-Z]{1}[a-zA-Z0-9]{1} | + [a-zA-Z0-9]{5}[A-Z]{1}[a-zA-Z0-9]{0} + ) + ) + + # Mutagen sync temporary files + | \.mutagen-temporary.* + + # other files + | \.DS_Store + | \.tmp + | ~ + )\z}x.freeze + + # TODO: deprecate these mutators; use attr_reader instead + attr_accessor :only_patterns, :ignore_patterns + + def initialize(**options) + configure(options) + end + + # TODO: deprecate this mutator + def configure(options) + @only_patterns = options[:only] ? Array(options[:only]) : nil + @ignore_patterns = _init_ignores(options[:ignore], options[:ignore!]) + end + + def silenced?(relative_path, type) + path = relative_path.to_s # in case it is a Pathname + + _ignore?(path) || (only_patterns && type == :file && !_only?(path)) + end + + private + + def _ignore?(path) + ignore_patterns.any? { |pattern| path =~ pattern } + end + + def _only?(path) + only_patterns.any? { |pattern| path =~ pattern } + end + + def _init_ignores(ignores, overrides) + patterns = [] + unless overrides + patterns << DEFAULT_IGNORED_FILES + patterns << DEFAULT_IGNORED_EXTENSIONS + end + + patterns << ignores + patterns << overrides + + patterns.compact.flatten + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/silencer/controller.rb b/bin/gems/listen-3.9.0/lib/listen/silencer/controller.rb new file mode 100644 index 00000000..bb94d4bf --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/silencer/controller.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Listen + class Silencer + class Controller + def initialize(silencer, default_options) + @silencer = silencer + + opts = default_options + + @prev_silencer_options = {} + rules = [:only, :ignore, :ignore!].map do |option| + [option, opts[option]] if opts.key? option + end + + _reconfigure_silencer(Hash[rules.compact]) + end + + def append_ignores(*regexps) + prev_ignores = Array(@prev_silencer_options[:ignore]) + _reconfigure_silencer(ignore: [prev_ignores + regexps]) + end + + def replace_with_bang_ignores(regexps) + _reconfigure_silencer(ignore!: regexps) + end + + def replace_with_only(regexps) + _reconfigure_silencer(only: regexps) + end + + private + + def _reconfigure_silencer(extra_options) + opts = extra_options.dup + opts = opts.map do |key, value| + [key, Array(value).flatten.compact] + end + opts = Hash[opts] + + if opts.key?(:ignore) && opts[:ignore].empty? + opts.delete(:ignore) + end + + @prev_silencer_options = opts + @silencer.configure(@prev_silencer_options.dup.freeze) + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/thread.rb b/bin/gems/listen-3.9.0/lib/listen/thread.rb new file mode 100644 index 00000000..a1e6b3b6 --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/thread.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'thread' + +require_relative 'logger' + +module Listen + module Thread + class << self + # Creates a new thread with the given name. + # Any exceptions raised by the thread will be logged with the thread name and complete backtrace. + # rubocop:disable Style/MultilineBlockChain + def new(name, &block) + thread_name = "listen-#{name}" + caller_stack = caller + + ::Thread.new do + rescue_and_log(thread_name, caller_stack: caller_stack, &block) + end.tap do |thread| + thread.name = thread_name + end + end + # rubocop:enable Style/MultilineBlockChain + + def rescue_and_log(method_name, *args, caller_stack: nil) + yield(*args) + rescue => exception + _log_exception(exception, method_name, caller_stack: caller_stack) + end + + private + + def _log_exception(exception, thread_name, caller_stack: nil) + complete_backtrace = if caller_stack + [*exception.backtrace, "--- Thread.new ---", *caller_stack] + else + exception.backtrace + end + message = "Exception rescued in #{thread_name}:\n#{_exception_with_causes(exception)}\n#{complete_backtrace * "\n"}" + Listen.logger.error(message) + end + + def _exception_with_causes(exception) + result = +"#{exception.class}: #{exception}" + if exception.cause + result << "\n" + result << "--- Caused by: ---\n" + result << _exception_with_causes(exception.cause) + end + result + end + end + end +end diff --git a/bin/gems/listen-3.9.0/lib/listen/version.rb b/bin/gems/listen-3.9.0/lib/listen/version.rb new file mode 100644 index 00000000..d235bf9f --- /dev/null +++ b/bin/gems/listen-3.9.0/lib/listen/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Listen + VERSION = '3.9.0' +end diff --git a/bin/gems/mercenary-0.4.0/.gitignore b/bin/gems/mercenary-0.4.0/.gitignore new file mode 100644 index 00000000..a28fccc4 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/.gitignore @@ -0,0 +1,18 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +vendor/bundle diff --git a/bin/gems/mercenary-0.4.0/.rspec b/bin/gems/mercenary-0.4.0/.rspec new file mode 100644 index 00000000..5f164763 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/.rspec @@ -0,0 +1,2 @@ +--color +--format progress diff --git a/bin/gems/mercenary-0.4.0/.rubocop.yml b/bin/gems/mercenary-0.4.0/.rubocop.yml new file mode 100644 index 00000000..f6aff824 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/.rubocop.yml @@ -0,0 +1,10 @@ +inherit_from: .rubocop_todo.yml + +require: rubocop-jekyll +inherit_gem: + rubocop-jekyll: .rubocop.yml + +AllCops: + TargetRubyVersion: 2.4 + Exclude: + - vendor/**/* diff --git a/bin/gems/mercenary-0.4.0/.rubocop_todo.yml b/bin/gems/mercenary-0.4.0/.rubocop_todo.yml new file mode 100644 index 00000000..a7450ae6 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/.rubocop_todo.yml @@ -0,0 +1,79 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2020-01-18 15:09:24 +0100 using RuboCop version 0.71.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +Jekyll/NoPAllowed: + Exclude: + - 'examples/help_dialogue.rb' + +# Offense count: 2 +Jekyll/NoPutsAllowed: + Exclude: + - 'lib/mercenary/command.rb' + +# Offense count: 4 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/mercenary/command.rb' + - 'lib/mercenary/option.rb' + - 'lib/mercenary/presenter.rb' + +# Offense count: 2 +Lint/DuplicateMethods: + Exclude: + - 'lib/mercenary/command.rb' + +# Offense count: 1 +# Configuration parameters: AllowComments. +Lint/HandleExceptions: + Exclude: + - 'lib/mercenary/option.rb' + +# Offense count: 1 +Lint/UselessAssignment: + Exclude: + - 'lib/mercenary/presenter.rb' + +# Offense count: 1 +Metrics/AbcSize: + Max: 25 + +# Offense count: 1 +# Configuration parameters: CountComments, ExcludedMethods. +# ExcludedMethods: refine +Metrics/BlockLength: + Max: 28 + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 319 + +# Offense count: 1 +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/MethodLength: + Max: 24 + +# Offense count: 1 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/mercenary/command.rb' + +# Offense count: 1 +Style/MissingRespondToMissing: + Exclude: + - 'lib/mercenary/presenter.rb' diff --git a/bin/gems/mercenary-0.4.0/.travis.yml b/bin/gems/mercenary-0.4.0/.travis.yml new file mode 100644 index 00000000..688caa61 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/.travis.yml @@ -0,0 +1,15 @@ +language: ruby +cache: bundler +rvm: + - 2.4 + - 2.6 + +before_script: bundle update +script: script/cibuild + +notifications: + email: + recipients: + - mercenary@jekyllrb.com + on_success: change + on_failure: change diff --git a/bin/gems/mercenary-0.4.0/Gemfile b/bin/gems/mercenary-0.4.0/Gemfile new file mode 100644 index 00000000..efaf3a97 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in mercenary.gemspec +gemspec diff --git a/bin/gems/mercenary-0.4.0/History.markdown b/bin/gems/mercenary-0.4.0/History.markdown new file mode 100644 index 00000000..a4f61200 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/History.markdown @@ -0,0 +1,127 @@ +## 0.4.0 / 2020-01-18 + +### Major Enhancements + + * Drop Ruby 2.3 support + +### Minor Enhancements + + * Remove parent command's flags from subcommand usage (#44) + +### Development Fixes + + * Adopt Jekyll's rubocop config for consistency + +### Documentation + + * fixes the readme (#52) + +## 0.3.6 / 2016-04-07 + +### Bug Fixes + + * Presenter: Options should include those from parent command (#42) + +## 0.3.5 / 2014-11-12 + +### Bug Fixes + + * Capture `OptionsParser::InvalidOption` and show a nice error message (#38) + * Absolute paths for requires and autoloads (#39) + +### Development Fixes + + * Bump to RSpec 3 (#40) + +## 0.3.4 / 2014-07-11 + +### Bug Fixes + + * Use option object as key in the command's `@map` hash (#35) + +## 0.3.3 / 2014-05-07 + +### Bug Fixes + + * The `--version` flag should not exit with code 1, but instead code 0. (#33) + +## 0.3.2 / 2014-03-18 + +### Bug Fixes + + * Remove duplicate commands from help output; show aliases w/command names (#29) + +## 0.3.1 / 2014-02-21 + +### Minor Enhancements + + * Add `-t/--trace` to list of options in help message (#19) + +### Bug Fixes + + * `Mercenary::Option` now accepts return values in the form of Class constants (#22) + +## 0.3.0 / 2014-02-20 + +### Major Enhancements + + * Officially drop 1.8.7 support (#14) + * Allow Commands to set their own versions (#17) + * Show subcommands, options and usage in help and attach to all commands (#18) + * Add `-t, --trace` to allow full exception backtrace to print, otherwise print just the error message (#19) + +### Minor Enhancements + + * Logging state is maintained throughout process (#12) + * Tidy up Command#logger output (#21) + +### Development Fixes + + * Added specs for `Program` (#13) + +## 0.2.1 / 2013-12-25 + +### Bug Fixes + + * Added missing comma to fix '-v' and '--version' options (#9) + +## 0.2.0 / 2013-11-30 + +### Major Enhancements + + * Add `Command#default_command` to specify a default command if none is given by the user at runtime (#7) + +### Minor Enhancements + + * Add `Command#execute` to execute the actions of a command (#6) + +### Development Fixes + + * Add standard GitHub bootstrap and cibuild scripts to `script/` (#2) + +## 0.1.0 / 2013-11-08 + +### Major Enhancements + + * It works! + +### Minor Enhancements + + * Add a logger to `Command` + * Add `--version` switch to all programs + +### Bug Fixes + + * Fix `Command#syntax` and `Command#description`'s handing of setting vs getting + * Fix load path problem in `lib/mercenary.rb` + +### Development Fixes + + * Add TomDoc to everything + * Add a couple starter specs + * Add TravisCI badge + * Add Travis configuration + +## 0.0.1 / 2013-11-06 + + * Birthday! diff --git a/bin/gems/mercenary-0.4.0/LICENSE.txt b/bin/gems/mercenary-0.4.0/LICENSE.txt new file mode 100644 index 00000000..cb1130e7 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013-present Parker Moore and the mercenary contributors + +MIT License + +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/bin/gems/mercenary-0.4.0/README.md b/bin/gems/mercenary-0.4.0/README.md new file mode 100644 index 00000000..8150890a --- /dev/null +++ b/bin/gems/mercenary-0.4.0/README.md @@ -0,0 +1,249 @@ +# Mercenary + +Lightweight and flexible library for writing command-line apps in Ruby. + +[![Build Status](https://secure.travis-ci.org/jekyll/mercenary.png)](https://travis-ci.org/jekyll/mercenary) + +## Installation + +Add this line to your application's Gemfile: + + gem 'mercenary' + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install mercenary + +**Note: Mercenary may not work with Ruby < 1.9.3.** + +## Usage + +Creating programs and commands with Mercenary is easy: + +```ruby +Mercenary.program(:jekyll) do |p| + p.version Jekyll::VERSION + p.description 'Jekyll is a blog-aware, static site generator in Ruby' + p.syntax "jekyll [options]" + + p.command(:new) do |c| + c.syntax "new PATH" # do not include the program name or super commands + c.description "Creates a new Jekyll site scaffold in PATH" + c.option 'blank', '--blank', 'Initialize the new site without any content.' + + c.action do |args, options| + Jekyll::Commands::New.process(args, blank: options['blank']) + end + end + + p.command(:build) do |c| + c.syntax "build [options]" + c.description "Builds your Jekyll site" + + c.option 'safe', '--safe', 'Run in safe mode' + c.option 'source', '--source DIR', 'From where to collect the source files' + c.option 'destination', '--dest DIR', 'To where the compiled files should be written' + + c.action do |_, options| + Jekyll::Commands::Build.process(options) + end + end + + # Bring in command bundled in external gem + begin + require "jekyll-import" + JekyllImport.init_with_program(p) + rescue LoadError + end + + p.default_command(:build) +end +``` + +All commands have the following default options: + +- `-h/--help` - show a help message +- `-v/--version` - show the program version +- `-t/--trace` - show the full backtrace when an error occurs + +## API + +### `Mercenary` + +#### `.program` + +Creates and executes a program. Accepts two arguments: + +- `name` - program name as a Symbol +- `block` - the specification for the program, passed the program instance as an + argument. + +Example is above, under the heading [Usage](#usage). + +### `Program` + +`Program` is a subclass of `Command`, so it has all of the methods documented +below as well as those for `Command`. + +#### `#config` + +Fetches the program configuration hash. + +### `Command` + +#### `#new` + +Create a new command. Accepts one argument: + +- `name` - the name of your command, as a symbol + +#### `#version` + +Sets or gets the version of the command. Accepts an optional argument: + +- `version` - (optional) the version to set for the command. If present, this + becomes the new version for the command and persists. + +#### `#syntax` + +Sets or gets the syntax of the command. Built on parent syntaxes if a parent +exists. Accepts one optional argument: + +- `syntax` - (optional) the syntax to set for the command. Will inherit from the + parent commands or program. Usually in the form of + `"command_name [OPTIONS]"` + +When a parent command exists, say `supercommand`, with syntax set as +`supercommand [OPTIONS]`, the syntax of the command in question +will be `supercommand command_name [OPTIONS]` with both +`` and `[OPTIONS]` stripped out. Any text between `<` and `>` or +between `[` and `]` will be stripped from parent command syntaxes. The purpose +of this chaining is to reduce redundancy. + +#### `#description` + +Sets or gets the description of the command. Accepts one optional argument: + +- `desc` - (optional) the description to set for the command. If + provided, will override any previous description set for the command. + +#### `#default_command` + +Sets or gets the default subcommand of the command to execute in the event no +subcommand is passed during execution. Accepts one optional argument: + +- `command_name` - (optional) the `Symbol` name of the subcommand to be + executed. Raises an `ArgumentError` if the subcommand doesn't exist. + Overwrites previously-set default commands. + +#### `#option` + +Adds a new option to the command. Accepts many arguments: + +- `config_key` - the configuration key that the value of this option maps to. +- `*options` - all the options, globbed, to be passed to `OptionParser`, namely the + switches and the option description. Usually in the format + `"-s", "--switch", "Sets the 'switch' flag"`. + +Valid option calls: + +```ruby +cmd.option 'config_key', '-c', 'Sets the "config" flag' +cmd.option 'config_key', '--config', 'Sets the "config" flag' +cmd.option 'config_key', '-c', '--config', 'Sets the "config" flag.' +cmd.option 'config_key', '-c FILE', '--config FILE', 'The config file.' +cmd.option 'config_key', '-c FILE1[,FILE2[,FILE3...]]', '--config FILE1[,FILE2[,FILE3...]]', Array, 'The config files.' +``` + +Notice that you can specify either a short switch, a long switch, or both. If +you want to accept an argument, you have to specify it in the switch strings. +The class of the argument defaults to `String`, but you can optionally set a +different class to create, e.g. `Array`, if you are expecting a particular class +in your code from this option's value. The description is also optional, but +it's highly recommended to include a description. + +#### `#alias` + +Specifies an alias for this command such that the alias may be used in place of +the command during execution. Accepts one argument: + +- `cmd_name` - the alias name for this command as a `Symbol` + +Example: + +```ruby +cmd.alias(:my_alias) +# Now `cmd` is now also executable via "my_alias" +``` + +#### `#action` + +Specifies a block to be executed in the event the command is specified at +runtime. The block is given two arguments: + +- `args` - the non-switch arguments given from the command-line +- `options` - the options hash built via the switches passed + +**Note that actions are additive**, meaning any new call to `#action` will +result in another action to be executed at runtime. Actions will be executed in +the order they are specified in. + +Example: + +```ruby +cmd.action do |args, options| + # do something! +end +``` + +#### `#logger` + +Access the logger for this command. Useful for outputting information to STDOUT. +Accepts one optional argument: + +- `level` - (optional) the severity threshold at which to begin logging. Uses + Ruby's built-in + [`Logger`](http://www.ruby-doc.org/stdlib-2.1.0/libdoc/logger/rdoc/Logger.html) + levels. + +Log level defaults to `Logger::INFO`. + +Examples: + +```ruby +cmd.logger(Logger::DEBUG) +cmd.logger.debug "My debug message." +cmd.logger.info "My informative message." +cmd.logger.warn "ACHTUNG!!" +cmd.logger.error "Something terrible has happened." +cmd.logger.fatal "I can't continue doing what I'm doing." +``` + +#### `#command` + +Creates a new subcommand for the current command. Accepts two arguments: + +- `cmd_name` - the command name, as a Symbol +- `block` - the specification of the subcommand in a block + +Example: + +```ruby +my_command.command(:my_subcommand) do |subcmd| + subcmd.description 'My subcommand' + subcmd.syntax 'my_subcommand [OPTIONS]' + # ... +end +``` + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request diff --git a/bin/gems/mercenary-0.4.0/Rakefile b/bin/gems/mercenary-0.4.0/Rakefile new file mode 100644 index 00000000..5263b583 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/Rakefile @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" diff --git a/bin/gems/mercenary-0.4.0/examples/help_dialogue.rb b/bin/gems/mercenary-0.4.0/examples/help_dialogue.rb new file mode 100755 index 00000000..c99ccc1f --- /dev/null +++ b/bin/gems/mercenary-0.4.0/examples/help_dialogue.rb @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +$LOAD_PATH.unshift File.join(__dir__, "..", "lib") + +require "mercenary" + +# This example sets the logging mode of mercenary to +# debug. Logging messages from "p.logger.debug" will +# be output to STDOUT. + +Mercenary.program(:help_dialogue) do |p| + p.version "2.0.1" + p.description "An example of the help dialogue in Mercenary" + p.syntax "help_dialogue " + + p.command(:some_subcommand) do |c| + c.version "1.4.2" + c.syntax "some_subcommand [options]" + c.description "Some subcommand to do something" + c.option "an_option", "-o", "--option", "Some option" + c.alias(:blah) + + c.command(:yet_another_sub) do |f| + f.syntax "yet_another_sub [options]" + f.description "Do amazing things" + f.option "blah", "-b", "--blah", "Trigger blah flag" + f.option "heh", "-H ARG", "--heh ARG", "Give a heh" + + f.action do |args, options| + print "Args: " + p args + print "Opts: " + p options + end + end + end + + p.command(:another_subcommand) do |c| + c.syntax "another_subcommand [options]" + c.description "Another subcommand to do something different." + c.option "an_option", "-O", "--option", "Some option" + c.option "another_options", "--pluginzzz", "Set where the plugins should be found from" + end +end diff --git a/bin/gems/mercenary-0.4.0/examples/logging.rb b/bin/gems/mercenary-0.4.0/examples/logging.rb new file mode 100755 index 00000000..3a382293 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/examples/logging.rb @@ -0,0 +1,35 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +$LOAD_PATH.unshift File.join(__dir__, "..", "lib") + +require "mercenary" + +# This example sets the logging mode of mercenary to +# debug. Logging messages from "p.logger.debug" will +# be output to STDOUT. + +Mercenary.program(:logger_output) do |p| + p.version "5.2.6" + p.description "An example of turning on logging for Mercenary." + p.syntax "logger_output" + + p.logger.info "The default log level is INFO. So this will output." + p.logger.debug "Since DEBUG is below INFO, this will not output." + + p.logger(Logger::DEBUG) + p.logger.debug "Logger level now set to DEBUG. So everything will output." + + p.logger.debug "Example of DEBUG level message." + p.logger.info "Example of INFO level message." + p.logger.warn "Example of WARN level message." + p.logger.error "Example of ERROR level message." + p.logger.fatal "Example of FATAL level message." + p.logger.unknown "Example of UNKNOWN level message." + + p.action do |_args, _options| + p.logger(Logger::INFO) + p.logger.debug "Logger level back to INFO. This line will not output." + p.logger.info "This INFO message will output." + end +end diff --git a/bin/gems/mercenary-0.4.0/examples/trace.rb b/bin/gems/mercenary-0.4.0/examples/trace.rb new file mode 100755 index 00000000..cca6b6c2 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/examples/trace.rb @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +$LOAD_PATH.unshift File.join(__dir__, "..", "lib") + +require "mercenary" + +# This example sets the logging mode of mercenary to +# debug. Logging messages from "p.logger.debug" will +# be output to STDOUT. + +Mercenary.program(:trace) do |p| + p.version "2.0.1" + p.description "An example of traces in Mercenary" + p.syntax "trace " + + p.action do |_, _| + raise ArgumentError, "YOU DID SOMETHING TERRIBLE YOU BUFFOON" + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary.rb b/bin/gems/mercenary-0.4.0/lib/mercenary.rb new file mode 100644 index 00000000..cd38f78f --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require File.expand_path("mercenary/version", __dir__) +require "optparse" +require "logger" + +module Mercenary + autoload :Command, File.expand_path("mercenary/command", __dir__) + autoload :Option, File.expand_path("mercenary/option", __dir__) + autoload :Presenter, File.expand_path("mercenary/presenter", __dir__) + autoload :Program, File.expand_path("mercenary/program", __dir__) + + # Public: Instantiate a new program and execute. + # + # name - the name of your program + # + # Returns nothing. + def self.program(name) + program = Program.new(name) + yield program + program.go(ARGV) + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary/command.rb b/bin/gems/mercenary-0.4.0/lib/mercenary/command.rb new file mode 100644 index 00000000..08ddf940 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary/command.rb @@ -0,0 +1,281 @@ +# frozen_string_literal: false + +module Mercenary + class Command + attr_reader :name + attr_reader :description + attr_reader :syntax + attr_accessor :options + attr_accessor :commands + attr_accessor :actions + attr_reader :map + attr_accessor :parent + attr_reader :trace + attr_reader :aliases + + # Public: Creates a new Command + # + # name - the name of the command + # parent - (optional) the instancce of Mercenary::Command which you wish to + # be the parent of this command + # + # Returns nothing + def initialize(name, parent = nil) + @name = name + @options = [] + @commands = {} + @actions = [] + @map = {} + @parent = parent + @trace = false + @aliases = [] + end + + # Public: Sets or gets the command version + # + # version - the command version (optional) + # + # Returns the version and sets it if an argument is non-nil + def version(version = nil) + @version = version if version + @version + end + + # Public: Sets or gets the syntax string + # + # syntax - the string which describes this command's usage syntax (optional) + # + # Returns the syntax string and sets it if an argument is present + def syntax(syntax = nil) + @syntax = syntax if syntax + syntax_list = [] + syntax_list << parent.syntax.to_s.gsub(%r!<[\w\s-]+>!, "").gsub(%r!\[[\w\s-]+\]!, "").strip if parent + syntax_list << (@syntax || name.to_s) + syntax_list.join(" ") + end + + # Public: Sets or gets the command description + # + # description - the description of what the command does (optional) + # + # Returns the description and sets it if an argument is present + def description(desc = nil) + @description = desc if desc + @description + end + + # Public: Sets the default command + # + # command_name - the command name to be executed in the event no args are + # present + # + # Returns the default command if there is one, `nil` otherwise + def default_command(command_name = nil) + if command_name + if commands.key?(command_name) + @default_command = commands[command_name] if command_name + @default_command + else + raise ArgumentError, "'#{command_name}' couldn't be found in this command's list of commands." + end + else + @default_command + end + end + + # Public: Adds an option switch + # + # sym - the variable key which is used to identify the value of the switch + # at runtime in the options hash + # + # Returns nothing + def option(sym, *options) + new_option = Option.new(sym, options) + @options << new_option + @map[new_option] = sym + end + + # Public: Adds a subcommand + # + # cmd_name - the name of the command + # block - a block accepting the new instance of Mercenary::Command to be + # modified (optional) + # + # Returns nothing + def command(cmd_name) + cmd = Command.new(cmd_name, self) + yield cmd + @commands[cmd_name] = cmd + end + + # Public: Add an alias for this command's name to be attached to the parent + # + # cmd_name - the name of the alias + # + # Returns nothing + def alias(cmd_name) + logger.debug "adding alias to parent for self: '#{cmd_name}'" + aliases << cmd_name + @parent.commands[cmd_name] = self + end + + # Public: Add an action Proc to be executed at runtime + # + # block - the Proc to be executed at runtime + # + # Returns nothing + def action(&block) + @actions << block + end + + # Public: Fetch a Logger (stdlib) + # + # level - the logger level (a Logger constant, see docs for more info) + # + # Returns the instance of Logger + + def logger(level = nil) + unless @logger + @logger = Logger.new(STDOUT) + @logger.level = level || Logger::INFO + @logger.formatter = proc do |severity, _datetime, _progname, msg| + "#{identity} | " << "#{severity.downcase.capitalize}:".ljust(7) << " #{msg}\n" + end + end + + @logger.level = level unless level.nil? + @logger + end + + # Public: Run the command + # + # argv - an array of string args + # opts - the instance of OptionParser + # config - the output config hash + # + # Returns the command to be executed + def go(argv, opts, config) + opts.banner = "Usage: #{syntax}" + process_options(opts, config) + add_default_options(opts) + + if argv[0] && cmd = commands[argv[0].to_sym] + logger.debug "Found subcommand '#{cmd.name}'" + argv.shift + cmd.go(argv, opts, config) + else + logger.debug "No additional command found, time to exec" + self + end + end + + # Public: Add this command's options to OptionParser and set a default + # action of setting the value of the option to the inputted hash + # + # opts - instance of OptionParser + # config - the Hash in which the option values should be placed + # + # Returns nothing + def process_options(opts, config) + options.each do |option| + opts.on(*option.for_option_parser) do |x| + config[map[option]] = x + end + end + end + + # Public: Add version and help options to the command + # + # opts - instance of OptionParser + # + # Returns nothing + def add_default_options(opts) + option "show_help", "-h", "--help", "Show this message" + option "show_version", "-v", "--version", "Print the name and version" + option "show_backtrace", "-t", "--trace", "Show the full backtrace when an error occurs" + opts.on("-v", "--version", "Print the version") do + puts "#{name} #{version}" + exit(0) + end + + opts.on("-t", "--trace", "Show full backtrace if an error occurs") do + @trace = true + end + + opts.on_tail("-h", "--help", "Show this message") do + puts self + exit + end + end + + # Public: Execute all actions given the inputted args and options + # + # argv - (optional) command-line args (sans opts) + # config - (optional) the Hash configuration of string key to value + # + # Returns nothing + def execute(argv = [], config = {}) + if actions.empty? && !default_command.nil? + default_command.execute + else + actions.each { |a| a.call(argv, config) } + end + end + + # Public: Check if this command has a subcommand + # + # sub_command - the name of the subcommand + # + # Returns true if this command is the parent of a command of name + # 'sub_command' and false otherwise + def has_command?(sub_command) + commands.key?(sub_command) + end + + # Public: Identify this command + # + # Returns a string which identifies this command + def ident + "" + end + + # Public: Get the full identity (name & version) of this command + # + # Returns a string containing the name and version if it exists + def identity + "#{full_name} #{version}".strip + end + + # Public: Get the name of the current command plus that of + # its parent commands + # + # Returns the full name of the command + def full_name + the_name = [] + the_name << parent.full_name if parent&.full_name + the_name << name + the_name.join(" ") + end + + # Public: Return all the names and aliases for this command. + # + # Returns a comma-separated String list of the name followed by its aliases + def names_and_aliases + ([name.to_s] + aliases).compact.join(", ") + end + + # Public: Build a string containing a summary of the command + # + # Returns a one-line summary of the command. + def summarize + " #{names_and_aliases.ljust(20)} #{description}" + end + + # Public: Build a string containing the command name, options and any subcommands + # + # Returns the string identifying this command, its options and its subcommands + def to_s + Presenter.new(self).print_command + end + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary/option.rb b/bin/gems/mercenary-0.4.0/lib/mercenary/option.rb new file mode 100644 index 00000000..dfd21d5b --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary/option.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +module Mercenary + class Option + attr_reader :config_key, :description, :short, :long, :return_type + + # Public: Create a new Option + # + # config_key - the key in the config hash to which the value of this option + # will map + # info - an array containing first the switches, then an optional + # return type (e.g. Array), then a description of the option + # + # Returns nothing + def initialize(config_key, info) + @config_key = config_key + while arg = info.shift + begin + @return_type = Object.const_get(arg.to_s) + next + rescue NameError + end + if arg.start_with?("-") + if arg.start_with?("--") + @long = arg + else + @short = arg + end + next + end + @description = arg + end + end + + # Public: Fetch the array containing the info OptionParser is interested in + # + # Returns the array which OptionParser#on wants + def for_option_parser + [short, long, return_type, description].flatten.reject { |o| o.to_s.empty? } + end + + # Public: Build a string representation of this option including the + # switches and description + # + # Returns a string representation of this option + def to_s + "#{formatted_switches} #{description}" + end + + # Public: Build a beautifully-formatted string representation of the switches + # + # Returns a formatted string representation of the switches + def formatted_switches + [ + switches.first.rjust(10), + switches.last.ljust(13), + ].join(", ").gsub(%r! , !, " ").gsub(%r!, !, " ") + end + + # Public: Hash based on the hash value of instance variables + # + # Returns a Fixnum which is unique to this Option based on the instance variables + def hash + instance_variables.map do |var| + instance_variable_get(var).hash + end.reduce(:^) + end + + # Public: Check equivalence of two Options based on equivalence of their + # instance variables + # + # Returns true if all the instance variables are equal, false otherwise + def eql?(other) + return false unless self.class.eql?(other.class) + + instance_variables.map do |var| + instance_variable_get(var).eql?(other.instance_variable_get(var)) + end.all? + end + + # Public: Fetch an array of switches, including the short and long versions + # + # Returns an array of two strings. An empty string represents no switch in + # that position. + def switches + [short, long].map(&:to_s) + end + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary/presenter.rb b/bin/gems/mercenary-0.4.0/lib/mercenary/presenter.rb new file mode 100644 index 00000000..11685fe4 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary/presenter.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +module Mercenary + class Presenter + attr_accessor :command + + # Public: Make a new Presenter + # + # command - a Mercenary::Command to present + # + # Returns nothing + def initialize(command) + @command = command + end + + # Public: Builds a string representation of the command usage + # + # Returns the string representation of the command usage + def usage_presentation + " #{command.syntax}" + end + + # Public: Builds a string representation of the options + # + # Returns the string representation of the options + def options_presentation + return nil unless command_options_presentation || parent_command_options_presentation + + [command_options_presentation, parent_command_options_presentation].compact.join("\n") + end + + def command_options_presentation + return nil if command.options.empty? + + options = command.options + options -= command.parent.options if command.parent + options.map(&:to_s).join("\n") + end + + # Public: Builds a string representation of the options for parent + # commands + # + # Returns the string representation of the options for parent commands + def parent_command_options_presentation + return nil unless command.parent + + Presenter.new(command.parent).options_presentation + end + + # Public: Builds a string representation of the subcommands + # + # Returns the string representation of the subcommands + def subcommands_presentation + return nil if command.commands.empty? + + command.commands.values.uniq.map(&:summarize).join("\n") + end + + # Public: Builds the command header, including the command identity and description + # + # Returns the command header as a String + def command_header + header = command.identity.to_s + header << " -- #{command.description}" if command.description + header + end + + # Public: Builds a string representation of the whole command + # + # Returns the string representation of the whole command + def command_presentation + msg = [] + msg << command_header + msg << "Usage:" + msg << usage_presentation + + if opts = options_presentation + msg << "Options:\n#{opts}" + end + if subcommands = subcommands_presentation + msg << "Subcommands:\n#{subcommands_presentation}" + end + msg.join("\n\n") + end + + # Public: Turn a print_* into a *_presentation or freak out + # + # meth - the method being called + # args - an array of arguments passed to the missing method + # block - the block passed to the missing method + # + # Returns the value of whatever function is called + def method_missing(meth, *args, &block) + if meth.to_s =~ %r!^print_(.+)$! + send("#{Regexp.last_match(1).downcase}_presentation") + else + # You *must* call super if you don't handle the method, + # otherwise you'll mess up Ruby's method lookup. + super + end + end + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary/program.rb b/bin/gems/mercenary-0.4.0/lib/mercenary/program.rb new file mode 100644 index 00000000..a8d0c521 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary/program.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Mercenary + class Program < Command + attr_reader :optparse + attr_reader :config + + # Public: Creates a new Program + # + # name - the name of the program + # + # Returns nothing + def initialize(name) + @config = {} + super(name) + end + + # Public: Run the program + # + # argv - an array of string args (usually ARGV) + # + # Returns nothing + def go(argv) + logger.debug("Using args passed in: #{argv.inspect}") + + cmd = nil + + @optparse = OptionParser.new do |opts| + cmd = super(argv, opts, @config) + end + + begin + @optparse.parse!(argv) + rescue OptionParser::InvalidOption => e + logger.error "Whoops, we can't understand your command." + logger.error e.message.to_s + logger.error "Run your command again with the --help switch to see available options." + abort + end + + logger.debug("Parsed config: #{@config.inspect}") + + begin + cmd.execute(argv, @config) + rescue StandardError => e + if cmd.trace + raise e + else + logger.error e.message + abort + end + end + end + end +end diff --git a/bin/gems/mercenary-0.4.0/lib/mercenary/version.rb b/bin/gems/mercenary-0.4.0/lib/mercenary/version.rb new file mode 100644 index 00000000..3f3e4754 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/lib/mercenary/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Mercenary + VERSION = "0.4.0" +end diff --git a/bin/gems/mercenary-0.4.0/mercenary.gemspec b/bin/gems/mercenary-0.4.0/mercenary.gemspec new file mode 100644 index 00000000..ff3efa47 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/mercenary.gemspec @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +lib = File.expand_path("lib", __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "mercenary/version" + +Gem::Specification.new do |spec| + spec.name = "mercenary" + spec.version = Mercenary::VERSION + spec.authors = ["Tom Preston-Werner", "Parker Moore"] + spec.email = ["tom@mojombo.com", "parkrmoore@gmail.com"] + spec.description = "Lightweight and flexible library for writing command-line apps in Ruby." + spec.summary = "Lightweight and flexible library for writing command-line apps in Ruby." + spec.homepage = "https://github.com/jekyll/mercenary" + spec.license = "MIT" + + spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR) + spec.executables = spec.files.grep(%r!^bin/!) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r!^(test|spec|features)/!) + spec.require_paths = ["lib"] + + spec.required_ruby_version = ">= 2.4.0" + + spec.add_development_dependency "bundler" + spec.add_development_dependency "rake" + spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "rubocop-jekyll", "~> 0.10.0" +end diff --git a/bin/gems/mercenary-0.4.0/script/bootstrap b/bin/gems/mercenary-0.4.0/script/bootstrap new file mode 100755 index 00000000..a0cf262e --- /dev/null +++ b/bin/gems/mercenary-0.4.0/script/bootstrap @@ -0,0 +1,7 @@ +#! /bin/sh + +set -e + +echo "Time to get set up." +bundle install +echo "Boom." diff --git a/bin/gems/mercenary-0.4.0/script/cibuild b/bin/gems/mercenary-0.4.0/script/cibuild new file mode 100755 index 00000000..43eac1af --- /dev/null +++ b/bin/gems/mercenary-0.4.0/script/cibuild @@ -0,0 +1,7 @@ +#! /bin/sh + +set -ex + +bundle exec rspec +script/fmt +script/examples diff --git a/bin/gems/mercenary-0.4.0/script/console b/bin/gems/mercenary-0.4.0/script/console new file mode 100755 index 00000000..27ed279e --- /dev/null +++ b/bin/gems/mercenary-0.4.0/script/console @@ -0,0 +1,3 @@ +#! /bin/bash + +irb -r./lib/mercenary.rb diff --git a/bin/gems/mercenary-0.4.0/script/examples b/bin/gems/mercenary-0.4.0/script/examples new file mode 100755 index 00000000..a722ab32 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/script/examples @@ -0,0 +1,18 @@ +#! /bin/bash + +set -e + +function run () { + echo "+ ruby ./examples/$@" + ruby -e "puts '=' * 79" + ruby ./examples/$@ + ruby -e "puts '=' * 79" +} + +run logging.rb +run logging.rb -v +run help_dialogue.rb -h +run help_dialogue.rb some_subcommand -h +run help_dialogue.rb another_subcommand -h +run help_dialogue.rb some_subcommand yet_another_sub -h +run help_dialogue.rb some_subcommand yet_another_sub -b diff --git a/bin/gems/mercenary-0.4.0/script/fmt b/bin/gems/mercenary-0.4.0/script/fmt new file mode 100755 index 00000000..74118c50 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/script/fmt @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "Rubocop $(bundle exec rubocop --version)" +bundle exec rubocop -S -D -E $@ diff --git a/bin/gems/mercenary-0.4.0/spec/command_spec.rb b/bin/gems/mercenary-0.4.0/spec/command_spec.rb new file mode 100644 index 00000000..85d766be --- /dev/null +++ b/bin/gems/mercenary-0.4.0/spec/command_spec.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Mercenary::Command) do + context "a basic command" do + let(:command) { Mercenary::Command.new(:my_name) } + let(:parent) { Mercenary::Command.new(:my_parent) } + let(:with_sub) do + c = Mercenary::Command.new(:i_have_subcommand) + add_sub.call(c) + c + end + let(:command_with_parent) do + Mercenary::Command.new( + :i_have_parent, + parent + ) + end + let(:add_sub) do + proc do |c| + c.command(:sub_command) { |p| } + end + end + + it "can be created with just a name" do + expect(command.name).to eql(:my_name) + end + + it "can hold a parent command" do + expect(command_with_parent.parent).to eql(parent) + end + + it "can create subcommands" do + expect(add_sub.call(command)).to be_a(Mercenary::Command) + expect(add_sub.call(command).parent).to eq(command) + end + + it "can set its version" do + version = "1.4.2" + command.version version + expect(command.version).to eq(version) + end + + it "can set its syntax" do + syntax_string = "my_name [options]" + cmd = described_class.new(:my_name) + cmd.syntax syntax_string + expect(cmd.syntax).to eq(syntax_string) + end + + it "can set its description" do + desc = "run all the things" + command.description desc + expect(command.description).to eq(desc) + end + + it "can set its options" do + name = "show_drafts" + opts = ["--drafts", "Render posts in the _drafts folder"] + option = Mercenary::Option.new(name, opts) + command.option name, *opts + expect(command.options).to eql([option]) + expect(command.map.values).to include(name) + end + + it "knows its full name" do + expect(command_with_parent.full_name).to eql("my_parent i_have_parent") + end + + it "knows its identity" do + command_with_parent.version "1.8.7" + expect(command_with_parent.identity).to eql("my_parent i_have_parent 1.8.7") + end + + it "raises an ArgumentError if I specify a default_command that isn't there" do + c = command # some weird NameError with the block below? + expect { c.default_command(:nope) }.to raise_error(ArgumentError) + end + + it "sets the default_command" do + expect(with_sub.default_command(:sub_command).name).to eq(:sub_command) + end + + context "with an alias" do + before(:each) do + command_with_parent.alias(:an_alias) + end + it "shows the alias in the summary" do + expect(command_with_parent.summarize).to eql(" i_have_parent, an_alias ") + end + + it "its names_and_aliases method reports both the name and alias" do + expect(command_with_parent.names_and_aliases).to eql("i_have_parent, an_alias") + end + end + end +end diff --git a/bin/gems/mercenary-0.4.0/spec/option_spec.rb b/bin/gems/mercenary-0.4.0/spec/option_spec.rb new file mode 100644 index 00000000..ce10a624 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/spec/option_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Mercenary::Option) do + let(:config_key) { "largo" } + let(:description) { "This is a description" } + let(:switches) { ["-l", "--largo"] } + let(:option) { described_class.new(config_key, [switches, description].flatten.reject(&:nil?)) } + + it "knows its config key" do + expect(option.config_key).to eql(config_key) + end + + it "knows its description" do + expect(option.description).to eql(description) + end + + it "knows its switches" do + expect(option.switches).to eql(switches) + end + + it "knows how to present itself" do + expect(option.to_s).to eql(" -l, --largo #{description}") + end + + it "has an OptionParser representation" do + expect(option.for_option_parser).to eql([switches, description].flatten) + end + + it "compares itself with other options well" do + new_option = described_class.new(config_key, ["-l", "--largo", description]) + expect(option.eql?(new_option)).to be(true) + expect(option.hash.eql?(new_option.hash)).to be(true) + end + + it "has a custom #hash" do + expect(option.hash.to_s).to match(%r!\d+!) + end + + context "with just the long switch" do + let(:switches) { ["--largo"] } + + it "adds an empty string in place of the short switch" do + expect(option.switches).to eql(["", "--largo"]) + end + + it "sets its description properly" do + expect(option.description).to eql(description) + end + + it "knows how to present the switch" do + expect(option.formatted_switches).to eql(" --largo ") + end + end + + context "with just the short switch" do + let(:switches) { ["-l"] } + + it "adds an empty string in place of the long switch" do + expect(option.switches).to eql(["-l", ""]) + end + + it "sets its description properly" do + expect(option.description).to eql(description) + end + + it "knows how to present the switch" do + expect(option.formatted_switches).to eql(" -l ") + end + end + + context "without a description" do + let(:description) { nil } + + it "knows there is no description" do + expect(option.description).to be(nil) + end + + it "knows both inputs are switches" do + expect(option.switches).to eql(switches) + end + end +end diff --git a/bin/gems/mercenary-0.4.0/spec/presenter_spec.rb b/bin/gems/mercenary-0.4.0/spec/presenter_spec.rb new file mode 100644 index 00000000..b72dbae0 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/spec/presenter_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Mercenary::Presenter) do + let(:supercommand) { Mercenary::Command.new(:script_name) } + let(:command) { Mercenary::Command.new(:subcommand, supercommand) } + let(:presenter) { described_class.new(command) } + + before(:each) do + supercommand.option "version", "-v", "--version", "Show version" + supercommand.option "help", "-h", "--help", "Help!" + + command.version "1.4.2" + command.description "Do all the things." + command.option "help", "-h", "--help", "Help!" + command.option "one", "-1", "--one", "The first option" + command.option "two", "-2", "--two", "The second option" + command.alias :cmd + supercommand.commands[command.name] = command + end + + it "knows how to present the command" do + expect(presenter.command_presentation).to eql("script_name subcommand 1.4.2 -- Do all the things.\n\nUsage:\n\n script_name subcommand\n\nOptions:\n -1, --one The first option\n -2, --two The second option\n -v, --version Show version\n -h, --help Help!") + end + + it "knows how to present the subcommands, without duplicates for aliases" do + expect(described_class.new(supercommand).subcommands_presentation).to eql(" subcommand, cmd Do all the things.") + end + + it "knows how to present the usage" do + expect(presenter.usage_presentation).to eql(" script_name subcommand") + end + + it "knows how to present the options" do + expect(presenter.options_presentation).to eql(" -1, --one The first option\n -2, --two The second option\n -v, --version Show version\n -h, --help Help!") + end + + it "allows you to say print_* instead of *_presentation" do + expect(presenter.print_usage).to eql(presenter.usage_presentation) + expect(presenter.print_subcommands).to eql(presenter.subcommands_presentation) + expect(presenter.print_options).to eql(presenter.options_presentation) + expect(presenter.print_command).to eql(presenter.command_presentation) + end +end diff --git a/bin/gems/mercenary-0.4.0/spec/program_spec.rb b/bin/gems/mercenary-0.4.0/spec/program_spec.rb new file mode 100644 index 00000000..aeb667b9 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/spec/program_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe(Mercenary::Program) do + context "a basic program" do + let(:program) { Mercenary::Program.new(:my_name) } + + it "can be created with just a name" do + expect(program.name).to eql(:my_name) + end + + it "can set its version" do + version = Mercenary::VERSION + program.version version + expect(program.version).to eq(version) + end + end +end diff --git a/bin/gems/mercenary-0.4.0/spec/spec_helper.rb b/bin/gems/mercenary-0.4.0/spec/spec_helper.rb new file mode 100644 index 00000000..42801c74 --- /dev/null +++ b/bin/gems/mercenary-0.4.0/spec/spec_helper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +lib = File.expand_path("../lib", __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "mercenary" + +RSpec.configure do |config| + config.run_all_when_everything_filtered = true + config.filter_run :focus + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = "random" +end diff --git a/bin/gems/method_source-1.1.0/.gemtest b/bin/gems/method_source-1.1.0/.gemtest new file mode 100644 index 00000000..e69de29b diff --git a/bin/gems/method_source-1.1.0/.yardopts b/bin/gems/method_source-1.1.0/.yardopts new file mode 100644 index 00000000..a4e78380 --- /dev/null +++ b/bin/gems/method_source-1.1.0/.yardopts @@ -0,0 +1 @@ +-m markdown diff --git a/bin/gems/method_source-1.1.0/CHANGELOG.md b/bin/gems/method_source-1.1.0/CHANGELOG.md new file mode 100644 index 00000000..08d86025 --- /dev/null +++ b/bin/gems/method_source-1.1.0/CHANGELOG.md @@ -0,0 +1,15 @@ +# method_source changelog + +### master + +### [v1.1.0][v1.1.0] (April 15, 2024) + +- Added `MethodSource.clear_cache` +- Added support for `RUBYOPT="--enable-frozen-string-literal"` + +### [v1.0.0][v1.0.0] (March 19, 2020) + +- Added Ruby 2.7 support + +[v1.0.0]: https://github.com/banister/method_source/releases/tag/v1.0.0 +[v1.1.0]: https://github.com/banister/method_source/releases/tag/v1.1.0 diff --git a/bin/gems/method_source-1.1.0/Gemfile b/bin/gems/method_source-1.1.0/Gemfile new file mode 100644 index 00000000..71d74ff5 --- /dev/null +++ b/bin/gems/method_source-1.1.0/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gemspec + +gem "rake" +gem "rspec" diff --git a/bin/gems/method_source-1.1.0/LICENSE b/bin/gems/method_source-1.1.0/LICENSE new file mode 100644 index 00000000..a0976059 --- /dev/null +++ b/bin/gems/method_source-1.1.0/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2011 John Mair (banisterfiend) + +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/bin/gems/method_source-1.1.0/README.markdown b/bin/gems/method_source-1.1.0/README.markdown new file mode 100644 index 00000000..ccaa690a --- /dev/null +++ b/bin/gems/method_source-1.1.0/README.markdown @@ -0,0 +1,101 @@ +method_source +============= + +[![Circle Build Status](https://circleci.com/gh/banister/method_source.svg?style=shield)](https://circleci.com/gh/banister/method_source) + +(C) John Mair (banisterfiend) 2011 + +_retrieve the sourcecode for a method_ + +*NOTE:* This simply utilizes `Method#source_location`; it + does not access the live AST. + +`method_source` is a utility to return a method's sourcecode as a +Ruby string. Also returns `Proc` and `Lambda` sourcecode. + +Method comments can also be extracted using the `comment` method. + +It is written in pure Ruby (no C). + +* Some Ruby 1.8 support now available. +* Support for MRI, RBX, JRuby, REE + +`method_source` provides the `source` and `comment` methods to the `Method` and +`UnboundMethod` and `Proc` classes. + +* Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source` +* Read the [documentation](https://www.rubydoc.info/github/banister/method_source/master) +* See the [source code](http://github.com/banister/method_source) + +Example: display method source +------------------------------ + + Set.instance_method(:merge).source.display + # => + def merge(enum) + if enum.instance_of?(self.class) + @hash.update(enum.instance_variable_get(:@hash)) + else + do_with_enum(enum) { |o| add(o) } + end + + self + end + +Example: display method comments +-------------------------------- + + Set.instance_method(:merge).comment.display + # => + # Merges the elements of the given enumerable object to the set and + # returns self. + +Example: display module/class comments +-------------------------------------- + + MethodSource::MethodExtensions.method(:included).module_comment + # => + # This module is to be included by `Method` and `UnboundMethod` and + # provides the `#source` functionality + +Limitations: +------------ + +* Occasional strange behaviour in Ruby 1.8 +* Cannot return source for C methods. +* Cannot return source for dynamically defined methods. + +Special Thanks +-------------- + +[Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality. + +[Dmitry Elastic](https://github.com/dmitryelastic) for the brilliant Ruby 1.8 `source_location` hack. + +[Samuel Kadolph](https://github.com/samuelkadolph) for the JRuby 1.8 `source_location`. + +License +------- + +(The MIT License) + +Copyright (c) 2011 John Mair (banisterfiend) + +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/bin/gems/method_source-1.1.0/Rakefile b/bin/gems/method_source-1.1.0/Rakefile new file mode 100644 index 00000000..1648a9f2 --- /dev/null +++ b/bin/gems/method_source-1.1.0/Rakefile @@ -0,0 +1,81 @@ +dlext = RbConfig::CONFIG['DLEXT'] +direc = File.dirname(__FILE__) + +require 'rake/clean' +require 'rubygems/package_task' +require "#{direc}/lib/method_source/version" + +CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o") +CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o", + "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*.rbc", + "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake") + +def apply_spec_defaults(s) + s.name = "method_source" + s.summary = "retrieve the sourcecode for a method" + s.version = MethodSource::VERSION + s.date = Time.now.strftime '%Y-%m-%d' + s.author = "John Mair (banisterfiend)" + s.email = 'jrmair@gmail.com' + s.description = s.summary + s.require_path = 'lib' + s.license = 'MIT' + + s.add_development_dependency("rspec","~>3.6") + s.add_development_dependency("rake", "~>0.9") + s.homepage = "http://banisterfiend.wordpress.com" + s.has_rdoc = 'yard' + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- spec/*`.split("\n") +end + +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new(:spec) do |t| + t.ruby_opts = %w[-w] +end + +desc "reinstall gem" +task :reinstall => :gems do + sh "gem uninstall method_source" rescue nil + sh "gem install #{direc}/pkg/method_source-#{MethodSource::VERSION}.gem" +end + +desc "Set up and run tests" +task :default => [:spec] + +desc "Build the gemspec file" +task :gemspec => "ruby:gemspec" + +namespace :ruby do + spec = Gem::Specification.new do |s| + apply_spec_defaults(s) + s.platform = Gem::Platform::RUBY + end + + Gem::PackageTask.new(spec) do |pkg| + pkg.need_zip = false + pkg.need_tar = false + end + + desc "Generate gemspec file" + task :gemspec do + File.open("#{spec.name}.gemspec", "w") do |f| + f << spec.to_ruby + end + end +end + +desc "build all platform gems at once" +task :gems => [:rmgems, "ruby:gem"] + +desc "remove all platform gems" +task :rmgems => ["ruby:clobber_package"] + +desc "build and push latest gems" +task :pushgems => :gems do + chdir("#{direc}/pkg") do + Dir["*.gem"].each do |gemfile| + sh "gem push #{gemfile}" + end + end +end diff --git a/bin/gems/method_source-1.1.0/lib/method_source.rb b/bin/gems/method_source-1.1.0/lib/method_source.rb new file mode 100644 index 00000000..ffd79ad3 --- /dev/null +++ b/bin/gems/method_source-1.1.0/lib/method_source.rb @@ -0,0 +1,177 @@ +# (C) John Mair (banisterfiend) 2011 +# MIT License + +direc = File.dirname(__FILE__) + +require "#{direc}/method_source/version" +require "#{direc}/method_source/source_location" +require "#{direc}/method_source/code_helpers" + +module MethodSource + extend MethodSource::CodeHelpers + + # An Exception to mark errors that were raised trying to find the source from + # a given source_location. + # + class SourceNotFoundError < StandardError; end + + # Helper method responsible for extracting method body. + # Defined here to avoid polluting `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @param [String] method_name + # @return [String] The method body + def self.source_helper(source_location, name=nil) + raise SourceNotFoundError, "Could not locate source for #{name}!" unless source_location + file, line = *source_location + + expression_at(lines_for(file), line) + rescue SyntaxError => e + raise SourceNotFoundError, "Could not parse source for #{name}: #{e.message}" + end + + # Helper method responsible for opening source file and buffering up + # the comments for a specified method. Defined here to avoid polluting + # `Method` class. + # @param [Array] source_location The array returned by Method#source_location + # @param [String] method_name + # @return [String] The comments up to the point of the method. + def self.comment_helper(source_location, name=nil) + raise SourceNotFoundError, "Could not locate source for #{name}!" unless source_location + file, line = *source_location + + comment_describing(lines_for(file), line) + end + + # Load a memoized copy of the lines in a file. + # + # @param [String] file_name + # @param [String] method_name + # @return [Array] the contents of the file + # @raise [SourceNotFoundError] + def self.lines_for(file_name, name=nil) + @lines_for_file ||= {} + @lines_for_file[file_name] ||= File.readlines(file_name) + rescue Errno::ENOENT => e + raise SourceNotFoundError, "Could not load source for #{name}: #{e.message}" + end + + # Clear cache. + def self.clear_cache + @lines_for_file = {} + end + + # @deprecated — use MethodSource::CodeHelpers#complete_expression? + def self.valid_expression?(str) + complete_expression?(str) + rescue SyntaxError + false + end + + # @deprecated — use MethodSource::CodeHelpers#expression_at + def self.extract_code(source_location) + source_helper(source_location) + end + + # This module is to be included by `Method` and `UnboundMethod` and + # provides the `#source` functionality + module MethodExtensions + + # We use the included hook to patch Method#source on rubinius. + # We need to use the included hook as Rubinius defines a `source` + # on Method so including a module will have no effect (as it's + # higher up the MRO). + # @param [Class] klass The class that includes the module. + def self.included(klass) + if klass.method_defined?(:source) && Object.const_defined?(:RUBY_ENGINE) && + RUBY_ENGINE =~ /rbx/ + + klass.class_eval do + orig_source = instance_method(:source) + + define_method(:source) do + begin + super + rescue + orig_source.bind(self).call + end + end + + end + end + end + + # Return the sourcecode for the method as a string + # @return [String] The method sourcecode as a string + # @raise SourceNotFoundException + # + # @example + # Set.instance_method(:clear).source.display + # => + # def clear + # @hash.clear + # self + # end + def source + MethodSource.source_helper(source_location, defined?(name) ? name : inspect) + end + + # Return the comments associated with the method as a string. + # @return [String] The method's comments as a string + # @raise SourceNotFoundException + # + # @example + # Set.instance_method(:clear).comment.display + # => + # # Removes all elements and returns self. + def comment + MethodSource.comment_helper(source_location, defined?(name) ? name : inspect) + end + + # Return the comments associated with the method class/module. + # @return [String] The method's comments as a string + # @raise SourceNotFoundException + # + # @example + # MethodSource::MethodExtensions.method(:included).module_comment + # => + # # This module is to be included by `Method` and `UnboundMethod` and + # # provides the `#source` functionality + def class_comment + if self.respond_to?(:receiver) + class_inst_or_module = self.receiver + elsif self.respond_to?(:owner) + class_inst_or_module = self.owner + else + return comment + end + + if class_inst_or_module.respond_to?(:name) + const_name = class_inst_or_module.name + else + const_name = class_inst_or_module.class.name + class_inst_or_module = class_inst_or_module.class + end + + location = class_inst_or_module.const_source_location(const_name) + + MethodSource.comment_helper(location, defined?(name) ? name : inspect) + end + alias module_comment class_comment + end +end + +class Method + include MethodSource::SourceLocation::MethodExtensions + include MethodSource::MethodExtensions +end + +class UnboundMethod + include MethodSource::SourceLocation::UnboundMethodExtensions + include MethodSource::MethodExtensions +end + +class Proc + include MethodSource::SourceLocation::ProcExtensions + include MethodSource::MethodExtensions +end + diff --git a/bin/gems/method_source-1.1.0/lib/method_source/code_helpers.rb b/bin/gems/method_source-1.1.0/lib/method_source/code_helpers.rb new file mode 100644 index 00000000..4185c185 --- /dev/null +++ b/bin/gems/method_source-1.1.0/lib/method_source/code_helpers.rb @@ -0,0 +1,154 @@ +module MethodSource + + module CodeHelpers + # Retrieve the first expression starting on the given line of the given file. + # + # This is useful to get module or method source code. + # + # @param [Array, File, String] file The file to parse, either as a File or as + # @param [Integer] line_number The line number at which to look. + # NOTE: The first line in a file is + # line 1! + # @param [Hash] options The optional configuration parameters. + # @option options [Boolean] :strict If set to true, then only completely + # valid expressions are returned. Otherwise heuristics are used to extract + # expressions that may have been valid inside an eval. + # @option options [Integer] :consume A number of lines to automatically + # consume (add to the expression buffer) without checking for validity. + # @return [String] The first complete expression + # @raise [SyntaxError] If the first complete expression can't be identified + def expression_at(file, line_number, options={}) + options = { + :strict => false, + :consume => 0 + }.merge!(options) + + lines = file.is_a?(Array) ? file : file.each_line.to_a + + relevant_lines = lines[(line_number - 1)..-1] || [] + + extract_first_expression(relevant_lines, options[:consume]) + rescue SyntaxError => e + raise if options[:strict] + + begin + extract_first_expression(relevant_lines) do |code| + code.gsub(/\#\{.*?\}/, "temp") + end + rescue SyntaxError + raise e + end + end + + # Retrieve the comment describing the expression on the given line of the given file. + # + # This is useful to get module or method documentation. + # + # @param [Array, File, String] file The file to parse, either as a File or as + # a String or an Array of lines. + # @param [Integer] line_number The line number at which to look. + # NOTE: The first line in a file is line 1! + # @return [String] The comment + def comment_describing(file, line_number) + lines = file.is_a?(Array) ? file : file.each_line.to_a + + extract_last_comment(lines[0..(line_number - 2)]) + end + + # Determine if a string of code is a complete Ruby expression. + # @param [String] code The code to validate. + # @return [Boolean] Whether or not the code is a complete Ruby expression. + # @raise [SyntaxError] Any SyntaxError that does not represent incompleteness. + # @example + # complete_expression?("class Hello") #=> false + # complete_expression?("class Hello; end") #=> true + # complete_expression?("class 123") #=> SyntaxError: unexpected tINTEGER + def complete_expression?(str) + old_verbose = $VERBOSE + $VERBOSE = nil + + catch(:valid) do + eval("BEGIN{throw :valid}\n#{str}") + end + + # Assert that a line which ends with a , or \ is incomplete. + str !~ /[,\\]\s*\z/ + rescue IncompleteExpression + false + ensure + $VERBOSE = old_verbose + end + + private + + # Get the first expression from the input. + # + # @param [Array] lines + # @param [Integer] consume A number of lines to automatically + # consume (add to the expression buffer) without checking for validity. + # @yield a clean-up function to run before checking for complete_expression + # @return [String] a valid ruby expression + # @raise [SyntaxError] + def extract_first_expression(lines, consume=0, &block) + code = consume.zero? ? +"" : lines.slice!(0..(consume - 1)).join + + lines.each do |v| + code << v + return code if complete_expression?(block ? block.call(code) : code) + end + raise SyntaxError, "unexpected $end" + end + + # Get the last comment from the input. + # + # @param [Array] lines + # @return [String] + def extract_last_comment(lines) + buffer = +"" + + lines.each do |line| + # Add any line that is a valid ruby comment, + # but clear as soon as we hit a non comment line. + if (line =~ /^\s*#/) || (line =~ /^\s*$/) + buffer << line.lstrip + else + buffer.clear + end + end + + buffer + end + + # An exception matcher that matches only subsets of SyntaxErrors that can be + # fixed by adding more input to the buffer. + module IncompleteExpression + GENERIC_REGEXPS = [ + /unexpected (\$end|end-of-file|end-of-input|END_OF_FILE)/, # mri, jruby, ruby-2.0, ironruby + /embedded document meets end of file/, # =begin + /unterminated (quoted string|string|regexp|list) meets end of file/, # "quoted string" is ironruby + /can't find string ".*" anywhere before EOF/, # rbx and jruby + /missing 'end' for/, /expecting kWHEN/ # rbx + ] + + RBX_ONLY_REGEXPS = [ + /expecting '[})\]]'(?:$|:)/, /expecting keyword_end/ + ] + + def self.===(ex) + return false unless SyntaxError === ex + case ex.message + when *GENERIC_REGEXPS + true + when *RBX_ONLY_REGEXPS + rbx? + else + false + end + end + + def self.rbx? + RbConfig::CONFIG['ruby_install_name'] == 'rbx' + end + end + end +end diff --git a/bin/gems/method_source-1.1.0/lib/method_source/source_location.rb b/bin/gems/method_source-1.1.0/lib/method_source/source_location.rb new file mode 100644 index 00000000..76298697 --- /dev/null +++ b/bin/gems/method_source-1.1.0/lib/method_source/source_location.rb @@ -0,0 +1,138 @@ +module MethodSource + module ReeSourceLocation + # Ruby enterprise edition provides all the information that's + # needed, in a slightly different way. + def source_location + [__file__, __line__] rescue nil + end + end + + module SourceLocation + module MethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + else + + + def trace_func(event, file, line, id, binding, classname) + return unless event == 'call' + set_trace_func nil + + @file, @line = file, line + raise :found + end + + private :trace_func + + # Return the source location of a method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + if @file.nil? + args =[*(1..(arity<-1 ? -arity-1 : arity ))] + + set_trace_func method(:trace_func).to_proc + call(*args) rescue nil + set_trace_func nil + @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) + end + [@file, @line] if @file + end + end + end + + module ProcExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ + + # Return the source location for a Proc (Rubinius only) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + [block.file.to_s, block.line] + end + else + + # Return the source location for a Proc (in implementations + # without Proc#source_location) + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # proc definition is found. + def source_location + self.to_s =~ /@(.*):(\d+)/ + [$1, $2.to_i] + end + end + end + + module UnboundMethodExtensions + if Proc.method_defined? :__file__ + include ReeSourceLocation + + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ + require 'java' + + # JRuby version source_location hack + # @return [Array] A two element array containing the source location of the method + def source_location + to_java.source_location(Thread.current.to_java.getContext()) + end + + else + + + # Return the source location of an instance method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + klass = case owner + when Class + owner + when Module + method_owner = owner + Class.new { include(method_owner) } + end + + # deal with immediate values + case + when klass == Symbol + return :a.method(name).source_location + when klass == Integer + return 0.method(name).source_location + when klass == TrueClass + return true.method(name).source_location + when klass == FalseClass + return false.method(name).source_location + when klass == NilClass + return nil.method(name).source_location + end + + begin + Object.instance_method(:method).bind(klass.allocate).call(name).source_location + rescue TypeError + + # Assume we are dealing with a Singleton Class: + # 1. Get the instance object + # 2. Forward the source_location lookup to the instance + instance ||= ObjectSpace.each_object(owner).first + Object.instance_method(:method).bind(instance).call(name).source_location + end + end + end + end + end +end diff --git a/bin/gems/method_source-1.1.0/lib/method_source/version.rb b/bin/gems/method_source-1.1.0/lib/method_source/version.rb new file mode 100644 index 00000000..c1d9071e --- /dev/null +++ b/bin/gems/method_source-1.1.0/lib/method_source/version.rb @@ -0,0 +1,3 @@ +module MethodSource + VERSION = '1.1.0'.freeze +end diff --git a/bin/gems/method_source-1.1.0/method_source.gemspec b/bin/gems/method_source-1.1.0/method_source.gemspec new file mode 100644 index 00000000..bad04128 --- /dev/null +++ b/bin/gems/method_source-1.1.0/method_source.gemspec @@ -0,0 +1,19 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "method_source".freeze + s.version = "1.1.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["John Mair (banisterfiend)".freeze] + s.date = "2024-04-15" + s.description = "retrieve the sourcecode for a method".freeze + s.email = "jrmair@gmail.com".freeze + s.files = ["CHANGELOG.md".freeze, ".gemtest".freeze, ".yardopts".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.markdown".freeze, "Rakefile".freeze, "lib/method_source.rb".freeze, "lib/method_source/code_helpers.rb".freeze, "lib/method_source/source_location.rb".freeze, "lib/method_source/version.rb".freeze, "method_source.gemspec".freeze, "spec/method_source/code_helpers_spec.rb".freeze, "spec/method_source_spec.rb".freeze, "spec/spec_helper.rb".freeze] + s.homepage = "http://banisterfiend.wordpress.com".freeze + s.metadata["changelog_uri"] = "https://github.com/banister/method_source/blob/master/CHANGELOG.md".freeze + s.licenses = ["MIT".freeze] + s.summary = "retrieve the sourcecode for a method".freeze + s.test_files = ["spec/method_source/code_helpers_spec.rb".freeze, "spec/method_source_spec.rb".freeze, "spec/spec_helper.rb".freeze] +end diff --git a/bin/gems/method_source-1.1.0/spec/method_source/code_helpers_spec.rb b/bin/gems/method_source-1.1.0/spec/method_source/code_helpers_spec.rb new file mode 100644 index 00000000..287ff893 --- /dev/null +++ b/bin/gems/method_source-1.1.0/spec/method_source/code_helpers_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe MethodSource::CodeHelpers do + before do + @tester = Object.new.extend(MethodSource::CodeHelpers) + end + + [ + ["p = '", "'"], + ["def", "a", "(); end"], + ["p = < error + warn "Unable to load metrics backend: #{backend.inspect}!" + end + end + + return false + end + + # Load the default configuration. + DEFAULT = self.default + end +end diff --git a/bin/gems/metrics-0.12.1/lib/metrics/metric.rb b/bin/gems/metrics-0.12.1/lib/metrics/metric.rb new file mode 100644 index 00000000..2ceb58a7 --- /dev/null +++ b/bin/gems/metrics-0.12.1/lib/metrics/metric.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2022, by Samuel Williams. + +module Metrics + class Metric + def initialize(name, type, description, unit) + @name = name + @type = type + @description = description + @unit = unit + end + + attr :name + attr :type + attr :description + attr :unit + + def emit(value, tags: nil, sample_rate: 1.0) + raise NotImplementedError + end + end +end diff --git a/bin/gems/metrics-0.12.1/lib/metrics/provider.rb b/bin/gems/metrics-0.12.1/lib/metrics/provider.rb new file mode 100644 index 00000000..e7f54414 --- /dev/null +++ b/bin/gems/metrics-0.12.1/lib/metrics/provider.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +require_relative "backend" + +module Metrics + # @returns [Boolean] Whether there is an active backend. + def self.enabled? + Backend.const_defined?(:Interface) + end + + module Provider + end + + # A module which contains tracing specific wrappers. + module Singleton + def metrics_provider + @metrics_provider ||= Module.new + end + end + + private_constant :Singleton + + # Bail out if there is no backend configured. + if self.enabled? + # Extend the specified class in order to emit traces. + def self.Provider(klass, &block) + klass.extend(Singleton) + provider = klass.metrics_provider + klass.prepend(provider) + + provider.module_exec(&block) if block_given? + + return provider + end + + Config::DEFAULT.prepare + else + def self.Provider(klass, &block) + # Metrics disabled. + end + end +end diff --git a/bin/gems/metrics-0.12.1/lib/metrics/tags.rb b/bin/gems/metrics-0.12.1/lib/metrics/tags.rb new file mode 100644 index 00000000..60a3b839 --- /dev/null +++ b/bin/gems/metrics-0.12.1/lib/metrics/tags.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +module Metrics + module Tags + def self.normalize(tags) + return nil unless tags&.any? + + if tags.is_a?(Hash) + tags = tags.map{|key, value| "#{key}:#{value}"} + end + + return Array(tags) + end + end +end diff --git a/bin/gems/metrics-0.12.1/lib/metrics/version.rb b/bin/gems/metrics-0.12.1/lib/metrics/version.rb new file mode 100644 index 00000000..aede04ac --- /dev/null +++ b/bin/gems/metrics-0.12.1/lib/metrics/version.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2024, by Samuel Williams. + +module Metrics + VERSION = "0.12.1" +end diff --git a/bin/gems/metrics-0.12.1/license.md b/bin/gems/metrics-0.12.1/license.md new file mode 100644 index 00000000..48f8857b --- /dev/null +++ b/bin/gems/metrics-0.12.1/license.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright, 2021-2024, by Samuel Williams. + +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/bin/gems/metrics-0.12.1/readme.md b/bin/gems/metrics-0.12.1/readme.md new file mode 100644 index 00000000..7e709376 --- /dev/null +++ b/bin/gems/metrics-0.12.1/readme.md @@ -0,0 +1,51 @@ +# Metrics + +Capture metrics about code execution in a vendor agnostic way. As the author of many libraries which would benefit from metrics, there are few key priorities: (1) zero overhead if metrics are disabled, minimal overhead if enabled, and (2) a small and opinionated interface with standardised semantics. + +[![Development Status](https://github.com/socketry/metrics/workflows/Test/badge.svg)](https://github.com/socketry/metrics/actions?workflow=Test) + +## Features + + - Zero-overhead if tracing is disabled and minimal overhead if enabled. + - Small opinionated interface with standardised semantics. + +## Usage + +Please see the [project documentation](https://socketry.github.io/metrics/) for more details. + + - [Getting Started](https://socketry.github.io/metrics/guides/getting-started/index) - This guide explains how to use `metrics` for capturing run-time metrics. + + - [Capture](https://socketry.github.io/metrics/guides/capture/index) - This guide explains how to use `metrics` for exporting metric definitions from your application. + + - [Testing](https://socketry.github.io/metrics/guides/testing/index) - This guide explains how to write assertions in your test suite to validate `metrics` are being emitted correctly. + +## Releases + +Please see the [project releases](https://socketry.github.io/metrics/releases/index) for all releases. + +### v0.12.1 + + - [Introduce `Metrics::Config` to Expose `prepare` Hook](https://socketry.github.io/metrics/releases/index#introduce-metrics::config-to-expose-prepare-hook) + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +### Developer Certificate of Origin + +In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. + +### Community Guidelines + +This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers. + +## See Also + + - [metrics-backend-datadog](https://github.com/socketry/metrics-backend-datadog) — A Metrics backend for Datadog. + - [traces](https://github.com/socketry/traces) — A code tracing interface which follows a similar pattern. diff --git a/bin/gems/metrics-0.12.1/releases.md b/bin/gems/metrics-0.12.1/releases.md new file mode 100644 index 00000000..8836f5c3 --- /dev/null +++ b/bin/gems/metrics-0.12.1/releases.md @@ -0,0 +1,18 @@ +# Releases + +## v0.12.1 + +### Introduce `Metrics::Config` to Expose `prepare` Hook + +The `metrics` gem uses aspect-oriented programming to wrap existing methods to emit metrics. However, while there are some reasonable defaults for emitting metrics, it can be useful to customize the behavior and level of detail. To that end, the `metrics` gem now optionally loads a `config/metrics.rb` which includes a `prepare` hook that can be used to load additional providers. + +``` ruby +# config/metrics.rb + +def prepare + require 'metrics/provider/async' + require 'metrics/provider/async/http' +end +``` + +The `prepare` method is called immediately after the metrics backend is loaded. You can require any provider you want in this file, or even add your own custom providers. diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/Gemfile b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/Gemfile new file mode 100644 index 00000000..57f16711 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/Gemfile @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +group :development do + # bootstrapping + gem "bundler", "~> 2.3" + gem "rake", "13.2.1" + + # building extensions + gem "rake-compiler", "1.2.8" + gem "rake-compiler-dock", "1.7.0" + + # parser generator + gem "rexical", "1.0.8" + + # tests + gem "minitest", "5.25.4" + gem "minitest-parallel_fork", "2.0.0" + gem "ruby_memcheck", "3.0.0" + gem "rubyzip", "~> 2.3.2" + gem "simplecov", "= 0.21.2" + + # rubocop + gem "standard", "1.43.0" + gem "rubocop-minitest", "0.36.0" + gem "rubocop-packaging", "0.5.2" + gem "rubocop-rake", "0.6.0" +end + +# If Psych doesn't build, you can disable this group locally by running +# `bundle config set --local without rdoc` +# Then re-run `bundle install`. +group :rdoc do + gem "rdoc", "6.10.0" unless RUBY_PLATFORM == "java" || ENV["CI"] +end diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE-DEPENDENCIES.md b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE-DEPENDENCIES.md new file mode 100644 index 00000000..1e950b6e --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE-DEPENDENCIES.md @@ -0,0 +1,2224 @@ +# Vendored Dependency Licenses + +Nokogiri ships with some third party dependencies, which are listed here along with their licenses. + +Note that this document is broken into multiple sections, each of which describes the dependencies of a different "platform release" of Nokogiri. + + + + + +- [Platform Releases](#platform-releases) + * [Default platform release ("ruby")](#default-platform-release-ruby) + * [Native LinuxⓇ platform releases ("x86_64-linux", "aarch64-linux", and "arm-linux")](#native-linux%E2%93%A1-platform-releases-x86_64-linux-aarch64-linux-and-arm-linux) + * [Native Darwin (macOSⓇ) platform releases ("x86_64-darwin" and "arm64-darwin")](#native-darwin-macos%E2%93%A1-platform-releases-x86_64-darwin-and-arm64-darwin) + * [Native WindowsⓇ platform releases ("x64-mingw-ucrt")](#native-windows%E2%93%A1-platform-releases-x64-mingw-ucrt) + * [JavaⓇ (JRuby) platform release ("java")](#java%E2%93%A1-jruby-platform-release-java) +- [Appendix: Dependencies' License Texts](#appendix-dependencies-license-texts) + * [libgumbo](#libgumbo) + * [libxml2](#libxml2) + * [libxslt](#libxslt) + * [zlib](#zlib) + * [libiconv](#libiconv) + * [isorelax:isorelax](#isorelaxisorelax) + * [net.sf.saxon:Saxon-HE](#netsfsaxonsaxon-he) + * [net.sourceforge.htmlunit:neko-htmlunit](#netsourceforgehtmlunitneko-htmlunit) + * [nu.validator:jing](#nuvalidatorjing) + * [org.nokogiri:nekodtd](#orgnokogirinekodtd) + * [xalan:serializer and xalan:xalan](#xalanserializer-and-xalanxalan) + * [xerces:xercesImpl](#xercesxercesimpl) + * [xml-apis:xml-apis](#xml-apisxml-apis) + + + +Anyone consuming this file via license-tracking software should endeavor to understand which gem file you're downloading and using, so as not to misinterpret the contents of this file and the licenses of the software being distributed. + +You can double-check the dependencies in your gem file by examining the output of `nokogiri -v` after installation, which will emit the complete set of libraries in use (for versions `>= 1.11.0.rc4`). + +In particular, I'm sure somebody's lawyer, somewhere, is going to freak out that the LGPL appears in this file; and so I'd like to take special note that the dependency covered by LGPL, `libiconv`, is only being redistributed in the native Windows and native Darwin platform releases. It's not present in default, JavaⓇ, or native LinuxⓇ releases. + + +## Platform Releases + +### Default platform release ("ruby") + +The default platform release distributes the following dependencies in source form: + +* [libxml2](#libxml2) +* [libxslt](#libxslt) +* [libgumbo](#libgumbo) + +This distribution can be identified by inspecting the included Gem::Specification, which will have the value "ruby" for its "platform" attribute. + + +### Native LinuxⓇ platform releases ("x86_64-linux", "aarch64-linux", and "arm-linux") + +The native LinuxⓇ platform release distributes the following dependencies in source form: + +* [libxml2](#libxml2) +* [libxslt](#libxslt) +* [libgumbo](#libgumbo) +* [zlib](#zlib) + +This distribution can be identified by inspecting the included Gem::Specification, which will have a value similar to "x86_64-linux" or "aarch64-linux" for its "platform.cpu" attribute. + + +### Native Darwin (macOSⓇ) platform releases ("x86_64-darwin" and "arm64-darwin") + +The native Darwin platform release distributes the following dependencies in source form: + +* [libxml2](#libxml2) +* [libxslt](#libxslt) +* [libgumbo](#libgumbo) +* [zlib](#zlib) +* [libiconv](#libiconv) + +This distribution can be identified by inspecting the included Gem::Specification, which will have a value similar to "x86_64-darwin" or "arm64-darwin" for its "platform.cpu" attribute. Darwin is also known more familiarly as "OSX" or "macOSⓇ" and is the operating system for many AppleⓇ computers. + + +### Native WindowsⓇ platform releases ("x64-mingw-ucrt") + +The native WindowsⓇ platform release distributes the following dependencies in source form: + +* [libxml2](#libxml2) +* [libxslt](#libxslt) +* [libgumbo](#libgumbo) +* [zlib](#zlib) +* [libiconv](#libiconv) + +This distribution can be identified by inspecting the included Gem::Specification, which will have a value similar to "x64-mingw-ucrt" for its "platform.cpu" attribute. + + +### JavaⓇ (JRuby) platform release ("java") + +The Java platform release distributes the following dependencies as compiled jar files: + +* [isorelax:isorelax](#isorelaxisorelax) +* [net.sf.saxon:Saxon-HE](#netsfsaxonsaxon-he) +* [net.sourceforge.htmlunit:neko-htmlunit](#netsourceforgehtmlunitneko-htmlunit) +* [nu.validator:jing](#nuvalidatorjing) +* [org.nokogiri:nekodtd](#orgnokogirinekodtd) +* [xalan:serializer and xalan:xalan](#xalanserializer-and-xalanxalan) +* [xerces:xercesImpl](#xercesxercesimpl) +* [xml-apis:xml-apis](#xml-apisxml-apis) + +This distribution can be identified by inspecting the included Gem::Specification, which will have the value "java" for its "platform.os" attribute. + + +## Appendix: Dependencies' License Texts + +This section contains a subsection for each potentially-distributed dependency, which includes the name of the license and the license text. + +Please see previous sections to understand which of these potential dependencies is actually distributed in the gem file you're downloading and using. + + +### libgumbo + +Apache 2.0 + +https://github.com/sparklemotion/nokogiri/blob/main/gumbo-parser/src/README.md + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### libxml2 + +MIT + +http://xmlsoft.org/ + + Except where otherwise noted in the source code (e.g. the files hash.c, + list.c and the trio files, which are covered by a similar licence but + with different Copyright notices) all the files are: + + Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. + + 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 fur- + nished 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, FIT- + NESS 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. + + +### libxslt + +MIT + +http://xmlsoft.org/libxslt/ + + Licence for libxslt except libexslt + ---------------------------------------------------------------------- + Copyright (C) 2001-2002 Daniel Veillard. All Rights Reserved. + + 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 fur- + nished 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, FIT- + NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- + NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Daniel Veillard shall not + be used in advertising or otherwise to promote the sale, use or other deal- + ings in this Software without prior written authorization from him. + + ---------------------------------------------------------------------- + + Licence for libexslt + ---------------------------------------------------------------------- + Copyright (C) 2001-2002 Thomas Broyer, Charlie Bozeman and Daniel Veillard. + All Rights Reserved. + + 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 fur- + nished 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, FIT- + NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- + NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the authors shall not + be used in advertising or otherwise to promote the sale, use or other deal- + ings in this Software without prior written authorization from him. + ---------------------------------------------------------------------- + + +### zlib + +zlib license + +http://www.zlib.net/zlib_license.html + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + +### libiconv + +LGPL + +https://www.gnu.org/software/libiconv/ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + Licenses are intended to guarantee your freedom to share and change + free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some + specially designated Free Software Foundation software, and to any + other libraries whose authors decide to use it. You can use it for + your libraries, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if + you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis + or for a fee, you must give the recipients all the rights that we gave + you. You must make sure that they, too, receive or can get the source + code. If you link a program with the library, you must provide + complete object files to the recipients so that they can relink them + with the library, after making changes to the library and recompiling + it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright + the library, and (2) offer you this license which gives you legal + permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain + that everyone understands that there is no warranty for this free + library. If the library is modified by someone else and passed on, we + want its recipients to know that what they have is not the original + version, so that any problems introduced by others will not reflect on + the original authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that companies distributing free + software will individually obtain patent licenses, thus in effect + transforming the program into proprietary software. To prevent this, + we have made it clear that any patent must be licensed for everyone's + free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary + GNU General Public License, which was designed for utility programs. This + license, the GNU Library General Public License, applies to certain + designated libraries. This license is quite different from the ordinary + one; be sure to read it in full, and don't assume that anything in it is + the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that + they blur the distinction we usually make between modifying or adding to a + program and simply using it. Linking a program with a library, without + changing the library, is in some sense simply using the library, and is + analogous to running a utility program or application program. However, in + a textual and legal sense, the linked executable is a combined work, a + derivative of the original library, and the ordinary General Public License + treats it as such. + + Because of this blurred distinction, using the ordinary General + Public License for libraries did not effectively promote software + sharing, because most developers did not use the libraries. We + concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the + users of those programs of all benefit from the free status of the + libraries themselves. This Library General Public License is intended to + permit developers of non-free programs to use free libraries, while + preserving your freedom as a user of such programs to change the free + libraries that are incorporated in them. (We have not seen how to achieve + this as regards changes in header files, but we have achieved it as regards + changes in the actual functions of the Library.) The hope is that this + will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and + modification follow. Pay close attention to the difference between a + "work based on the library" and a "work that uses the library". The + former contains code derived from the library, while the latter only + works together with the library. + + Note that it is possible for a library to be covered by the ordinary + General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which + contains a notice placed by the copyright holder or other authorized + party saying it may be distributed under the terms of this Library + General Public License (also called "this License"). Each licensee is + addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or translated + straightforwardly into another language. (Hereinafter, translation is + included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code means + all the source code for all modules it contains, plus any associated + interface definition files, plus the scripts used to control compilation + and installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running a program using the Library is not restricted, and output from + such a program is covered only if its contents constitute a work based + on the Library (independent of the use of the Library in a tool for + writing it). Whether that is true depends on what the Library does + and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided that + you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep intact + all the notices that refer to this License and to the absence of any + warranty; and distribute a copy of this License along with the + Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange for a + fee. + + 2. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Library, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so + that they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in + these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable form + under the terms of Sections 1 and 2 above provided that you accompany + it with the complete corresponding machine-readable source code, which + must be distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy the + source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being compiled or + linked with it, is called a "work that uses the Library". Such a + work, in isolation, is not a derivative work of the Library, and + therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because it + contains portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. + Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is not. + Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section 6. + Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work + during execution displays copyright notices, you must include the + copyright notice for the Library among them, as well as a reference + directing the user to the copy of this License. Also, you must do one + of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special exception, + the source code distributed need not include anything that is normally + distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on + which the executable runs, unless that component itself accompanies + the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you cannot + use both them and the Library together in an executable that you + distribute. + + 7. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other library + facilities not covered by this License, and distribute such a combined + library, provided that the separate distribution of the work based on + the Library and of the other library facilities is otherwise + permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute + the Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate your + rights under this License. However, parties who have received copies, + or rights, from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Library or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Library (or any work based on the + Library), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent + license would not permit royalty-free redistribution of the Library by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply, + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Library under this License may add + an explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new + versions of the Library General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and + "any later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a + license version number, you may choose any version ever published by + the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free status + of all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGES. + + END OF TERMS AND CONDITIONS + + +### isorelax:isorelax + +MIT + +http://iso-relax.sourceforge.net/ + + Copyright (c) 2001-2002, SourceForge ISO-RELAX Project (ASAMI + Tomoharu, Daisuke Okajima, Kohsuke Kawaguchi, and MURATA Makoto) + + 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. + + +### net.sf.saxon:Saxon-HE + +MPL 2.0 + +http://www.saxonica.com/ + + Mozilla Public License Version 2.0 + ================================== + + 1. Definitions + -------------- + + 1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + + 1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + + 1.3. "Contribution" + means Covered Software of a particular Contributor. + + 1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + + 1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + + 1.6. "Executable Form" + means any form of the work other than Source Code Form. + + 1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + + 1.8. "License" + means this document. + + 1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + + 1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + + 1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + + 1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + + 1.13. "Source Code Form" + means the form of the work preferred for making modifications. + + 1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + + 2. License Grants and Conditions + -------------------------------- + + 2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + (b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + + 2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + + 2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + (a) for any code that a Contributor has removed from Covered Software; + or + + (b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + (c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + + 2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + + 2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights + to grant the rights to its Contributions conveyed by this License. + + 2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + + 2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted + in Section 2.1. + + 3. Responsibilities + ------------------- + + 3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + + 3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + (a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + + (b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + + 3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + + 3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, + or limitations of liability) contained within the Source Code Form of + the Covered Software, except that You may alter any license notices to + the extent required to remedy known factual inaccuracies. + + 3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + + 4. Inability to Comply Due to Statute or Regulation + --------------------------------------------------- + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Software due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description must + be placed in a text file included with all distributions of the Covered + Software under this License. Except to the extent prohibited by statute + or regulation, such description must be sufficiently detailed for a + recipient of ordinary skill to be able to understand it. + + 5. Termination + -------------- + + 5.1. The rights granted under this License will terminate automatically + if You fail to comply with any of its terms. However, if You become + compliant, then the rights granted under this License from a particular + Contributor are reinstated (a) provisionally, unless and until such + Contributor explicitly and finally terminates Your grants, and (b) on an + ongoing basis, if such Contributor fails to notify You of the + non-compliance by some reasonable means prior to 60 days after You have + come back into compliance. Moreover, Your grants from a particular + Contributor are reinstated on an ongoing basis if such Contributor + notifies You of the non-compliance by some reasonable means, this is the + first time You have received notice of non-compliance with this License + from such Contributor, and You become compliant prior to 30 days after + Your receipt of the notice. + + 5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all + end user license agreements (excluding distributors and resellers) which + have been validly granted by You or Your distributors under this License + prior to termination shall survive termination. + + ************************************************************************ + * * + * 6. Disclaimer of Warranty * + * ------------------------- * + * * + * Covered Software is provided under this License on an "as is" * + * basis, without warranty of any kind, either expressed, implied, or * + * statutory, including, without limitation, warranties that the * + * Covered Software is free of defects, merchantable, fit for a * + * particular purpose or non-infringing. The entire risk as to the * + * quality and performance of the Covered Software is with You. * + * Should any Covered Software prove defective in any respect, You * + * (not any Contributor) assume the cost of any necessary servicing, * + * repair, or correction. This disclaimer of warranty constitutes an * + * essential part of this License. No use of any Covered Software is * + * authorized under this License except under this disclaimer. * + * * + ************************************************************************ + + ************************************************************************ + * * + * 7. Limitation of Liability * + * -------------------------- * + * * + * Under no circumstances and under no legal theory, whether tort * + * (including negligence), contract, or otherwise, shall any * + * Contributor, or anyone who distributes Covered Software as * + * permitted above, be liable to You for any direct, indirect, * + * special, incidental, or consequential damages of any character * + * including, without limitation, damages for lost profits, loss of * + * goodwill, work stoppage, computer failure or malfunction, or any * + * and all other commercial damages or losses, even if such party * + * shall have been informed of the possibility of such damages. This * + * limitation of liability shall not apply to liability for death or * + * personal injury resulting from such party's negligence to the * + * extent applicable law prohibits such limitation. Some * + * jurisdictions do not allow the exclusion or limitation of * + * incidental or consequential damages, so this exclusion and * + * limitation may not apply to You. * + * * + ************************************************************************ + + 8. Litigation + ------------- + + Any litigation relating to this License may be brought only in the + courts of a jurisdiction where the defendant maintains its principal + place of business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. + Nothing in this Section shall prevent a party's ability to bring + cross-claims or counter-claims. + + 9. Miscellaneous + ---------------- + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides + that the language of a contract shall be construed against the drafter + shall not be used to construe this License against a Contributor. + + 10. Versions of the License + --------------------------- + + 10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + + 10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + + 10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + + 10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses + + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + + +### net.sourceforge.htmlunit:neko-htmlunit + +Apache 2.0 + +https://github.com/HtmlUnit/htmlunit-neko + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### nu.validator:jing + +BSD-3-Clause + +http://www.thaiopensource.com/relaxng/jing.html + + Copyright (c) 2001-2003 Thai Open Source Software Center Ltd + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the Thai Open Source Software Center Ltd nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + +### org.nokogiri:nekodtd + +Apache 2.0 + +https://github.com/sparklemotion/nekodtd + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### xalan:serializer and xalan:xalan + +Apache 2.0 + +https://xml.apache.org/xalan-j/ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### xerces:xercesImpl + +Apache 2.0 + +https://xerces.apache.org/xerces2-j/ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### xml-apis:xml-apis + +Apache 2.0 + +https://xerces.apache.org/xml-commons/ + + Unless otherwise noted all files in XML Commons are covered under the + Apache License Version 2.0. Please read the LICENSE and NOTICE files. + + XML Commons contains some software and documentation that is covered + under a number of different licenses. This applies particularly to the + xml-commons/java/external/ directory. Most files under + xml-commons/java/external/ are covered under their respective + LICENSE.*.txt files; see the matching README.*.txt files for + descriptions. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE.md b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE.md new file mode 100644 index 00000000..b649dd87 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License + +Copyright 2008 -- 2023 by Mike Dalessio, Aaron Patterson, Yoko Harada, Akinori MUSHA, John Shahid, Karol Bucek, Sam Ruby, Craig Barnes, Stephen Checkoway, Lars Kanis, Sergio Arbeo, Timothy Elliott, Nobuyoshi Nakada, Charles Nutter, Patrick Mahoney. + +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/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/README.md b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/README.md new file mode 100644 index 00000000..df466f4a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/README.md @@ -0,0 +1,293 @@ +
+ +# Nokogiri + +Nokogiri (鋸) makes it easy and painless to work with XML and HTML from Ruby. It provides a sensible, easy-to-understand API for [reading](https://nokogiri.org/tutorials/parsing_an_html_xml_document.html), writing, [modifying](https://nokogiri.org/tutorials/modifying_an_html_xml_document.html), and [querying](https://nokogiri.org/tutorials/searching_a_xml_html_document.html) documents. It is fast and standards-compliant by relying on native parsers like libxml2, libgumbo, and xerces. + +## Guiding Principles + +Some guiding principles Nokogiri tries to follow: + +- be secure-by-default by treating all documents as **untrusted** by default +- be a **thin-as-reasonable layer** on top of the underlying parsers, and don't attempt to fix behavioral differences between the parsers + + +## Features Overview + +- DOM Parser for XML, HTML4, and HTML5 +- SAX Parser for XML and HTML4 +- Push Parser for XML and HTML4 +- Document search via XPath 1.0 +- Document search via CSS3 selectors, with some jquery-like extensions +- XSD Schema validation +- XSLT transformation +- "Builder" DSL for XML and HTML documents + + +## Status + +[![Github Actions CI](https://github.com/sparklemotion/nokogiri/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sparklemotion/nokogiri/actions/workflows/ci.yml) +[![Appveyor CI](https://ci.appveyor.com/api/projects/status/xj2pqwvlxwuwgr06/branch/main?svg=true)](https://ci.appveyor.com/project/flavorjones/nokogiri/branch/main) + +[![Gem Version](https://badge.fury.io/rb/nokogiri.svg)](https://rubygems.org/gems/nokogiri) +[![SemVer compatibility](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nokogiri&package-manager=bundler&previous-version=1.11.7&new-version=1.12.5)](https://docs.github.com/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-dependabot-security-updates#about-compatibility-scores) + +[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5344/badge)](https://bestpractices.coreinfrastructure.org/projects/5344) +[![Tidelift dependencies](https://tidelift.com/badges/package/rubygems/nokogiri)](https://tidelift.com/subscription/pkg/rubygems-nokogiri?utm_source=rubygems-nokogiri&utm_medium=referral&utm_campaign=readme) + + +## Support, Getting Help, and Reporting Issues + +All official documentation is posted at https://nokogiri.org (the source for which is at https://github.com/sparklemotion/nokogiri.org/, and we welcome contributions). + +### Reading + +Your first stops for learning more about Nokogiri should be: + +- [API Documentation](https://nokogiri.org/rdoc/index.html) +- [Tutorials](https://nokogiri.org/tutorials/toc.html) +- An excellent community-maintained [Cheat Sheet](https://github.com/sparklemotion/nokogiri/wiki/Cheat-sheet) + + +### Ask For Help + +There are a few ways to ask exploratory questions: + +- The Nokogiri mailing list is active at https://groups.google.com/group/nokogiri-talk +- Open an issue using the "Help Request" template at https://github.com/sparklemotion/nokogiri/issues +- Open a discussion at https://github.com/sparklemotion/nokogiri/discussions + +Please do not mail the maintainers at their personal addresses. + + +### Report A Bug + +The Nokogiri bug tracker is at https://github.com/sparklemotion/nokogiri/issues + +Please use the "Bug Report" or "Installation Difficulties" templates. + + +### Security and Vulnerability Reporting + +Please report vulnerabilities at https://hackerone.com/nokogiri + +Full information and description of our security policy is in [`SECURITY.md`](SECURITY.md) + + +### Semantic Versioning Policy + +Nokogiri follows [Semantic Versioning](https://semver.org/) (since 2017 or so). [![Dependabot's SemVer compatibility score for Nokogiri](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nokogiri&package-manager=bundler&previous-version=1.11.7&new-version=1.12.5)](https://docs.github.com/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-dependabot-security-updates#about-compatibility-scores) + +We bump `Major.Minor.Patch` versions following this guidance: + +`Major`: (we've never done this) + +- Significant backwards-incompatible changes to the public API that would require rewriting existing application code. +- Some examples of backwards-incompatible changes we might someday consider for a Major release are at [`ROADMAP.md`](ROADMAP.md). + +`Minor`: + +- Features and bugfixes. +- Updating packaged libraries for non-security-related reasons. +- Dropping support for EOLed Ruby versions. [Some folks find this objectionable](https://github.com/sparklemotion/nokogiri/issues/1568), but [SemVer says this is OK if the public API hasn't changed](https://semver.org/#what-should-i-do-if-i-update-my-own-dependencies-without-changing-the-public-api). +- Backwards-incompatible changes to internal or private methods and constants. These are detailed in the "Changes" section of each changelog entry. +- Removal of deprecated methods or parameters, after a generous transition period; usually when those methods or parameters are rarely-used or dangerous to the user. Essentially, removals that do not justify a major version bump. + + +`Patch`: + +- Bugfixes. +- Security updates. +- Updating packaged libraries for security-related reasons. + + +### Sponsorship + +You can help sponsor the maintainers of this software through one of these organizations: + +- [github.com/sponsors/flavorjones](https://github.com/sponsors/flavorjones) +- [opencollective.com/nokogiri](https://opencollective.com/nokogiri) +- [tidelift.com/subscription/pkg/rubygems-nokogiri](https://tidelift.com/subscription/pkg/rubygems-nokogiri?utm_source=rubygems-nokogiri&utm_medium=referral&utm_campaign=readme) + + +## Installation + +Requirements: + +- Ruby >= 3.1 +- JRuby >= 9.4.0.0 + +If you are compiling the native extension against a system version of libxml2: + +- libxml2 >= 2.9.2 (recommended >= 2.12.0) + + +### Native Gems: Faster, more reliable installation + +"Native gems" contain pre-compiled libraries for a specific machine architecture. On supported platforms, this removes the need for compiling the C extension and the packaged libraries, or for system dependencies to exist. This results in **much faster installation** and **more reliable installation**, which as you probably know are the biggest headaches for Nokogiri users. + +### Supported Platforms + +Nokogiri ships pre-compiled, "native" gems for the following platforms: + +- Linux: + - `x86_64-linux-gnu`, `aarch64-linux-gnu`, and `arm-linux-gnu` (req: `glibc >= 2.29`) + - `x86_64-linux-musl`, `aarch64-linux-musl`, and `arm-linux-musl` +- Darwin/MacOS: `x86_64-darwin` and `arm64-darwin` +- Windows: `x64-mingw-ucrt` +- Java: any platform running JRuby 9.4 or higher + +To determine whether your system supports one of these gems, look at the output of `bundle platform` or `ruby -e 'puts Gem::Platform.local.to_s'`. + +If you're on a supported platform, either `gem install` or `bundle install` should install a native gem without any additional action on your part. This installation should only take a few seconds, and your output should look something like: + +``` sh +$ gem install nokogiri +Fetching nokogiri-1.11.0-x86_64-linux.gem +Successfully installed nokogiri-1.11.0-x86_64-linux +1 gem installed +``` + + +### Other Installation Options + +Because Nokogiri is a C extension, it requires that you have a C compiler toolchain, Ruby development header files, and some system dependencies installed. + +The following may work for you if you have an appropriately-configured system: + +``` bash +gem install nokogiri +``` + +If you have any issues, please visit [Installing Nokogiri](https://nokogiri.org/tutorials/installing_nokogiri.html) for more complete instructions and troubleshooting. + + +## How To Use Nokogiri + +Nokogiri is a large library, and so it's challenging to briefly summarize it. We've tried to provide long, real-world examples at [Tutorials](https://nokogiri.org/tutorials/toc.html). + +### Parsing and Querying + +Here is example usage for parsing and querying a document: + +```ruby +#! /usr/bin/env ruby + +require 'nokogiri' +require 'open-uri' + +# Fetch and parse HTML document +doc = Nokogiri::HTML(URI.open('https://nokogiri.org/tutorials/installing_nokogiri.html')) + +# Search for nodes by css +doc.css('nav ul.menu li a', 'article h2').each do |link| + puts link.content +end + +# Search for nodes by xpath +doc.xpath('//nav//ul//li/a', '//article//h2').each do |link| + puts link.content +end + +# Or mix and match +doc.search('nav ul.menu li a', '//article//h2').each do |link| + puts link.content +end +``` + + +### Encoding + +Strings are always stored as UTF-8 internally. Methods that return +text values will always return UTF-8 encoded strings. Methods that +return a string containing markup (like `to_xml`, `to_html` and +`inner_html`) will return a string encoded like the source document. + +__WARNING__ + +Some documents declare one encoding, but actually use a different +one. In these cases, which encoding should the parser choose? + +Data is just a stream of bytes. Humans add meaning to that stream. Any +particular set of bytes could be valid characters in multiple +encodings, so detecting encoding with 100% accuracy is not +possible. `libxml2` does its best, but it can't be right all the time. + +If you want Nokogiri to handle the document encoding properly, your +best bet is to explicitly set the encoding. Here is an example of +explicitly setting the encoding to EUC-JP on the parser: + +```ruby + doc = Nokogiri.XML('', nil, 'EUC-JP') +``` + + +## Technical Overview + +### Guiding Principles + +As noted above, two guiding principles of the software are: + +- be secure-by-default by treating all documents as **untrusted** by default +- be a **thin-as-reasonable layer** on top of the underlying parsers, and don't attempt to fix behavioral differences between the parsers + +Notably, despite all parsers being standards-compliant, there are behavioral inconsistencies between the parsers used in the CRuby and JRuby implementations, and Nokogiri does not and should not attempt to remove these inconsistencies. Instead, we surface these differences in the test suite when they are important/semantic; or we intentionally write tests to depend only on the important/semantic bits (omitting whitespace from regex matchers on results, for example). + + +### CRuby + +The Ruby (a.k.a., CRuby, MRI, YARV) implementation is a C extension that depends on libxml2 and libxslt (which in turn depend on zlib and possibly libiconv). + +These dependencies are met by default by Nokogiri's packaged versions of the libxml2 and libxslt source code, but a configuration option `--use-system-libraries` is provided to allow specification of alternative library locations. See [Installing Nokogiri](https://nokogiri.org/tutorials/installing_nokogiri.html) for full documentation. + +We provide native gems by pre-compiling libxml2 and libxslt (and potentially zlib and libiconv) and packaging them into the gem file. In this case, no compilation is necessary at installation time, which leads to faster and more reliable installation. + +See [`LICENSE-DEPENDENCIES.md`](LICENSE-DEPENDENCIES.md) for more information on which dependencies are provided in which native and source gems. + + +### JRuby + +The Java (a.k.a. JRuby) implementation is a Java extension that depends primarily on Xerces and NekoHTML for parsing, though additional dependencies are on `isorelax`, `nekodtd`, `jing`, `serializer`, `xalan-j`, and `xml-apis`. + +These dependencies are provided by pre-compiled jar files packaged in the `java` platform gem. + +See [`LICENSE-DEPENDENCIES.md`](LICENSE-DEPENDENCIES.md) for more information on which dependencies are provided in which native and source gems. + + +## Contributing + +See [`CONTRIBUTING.md`](CONTRIBUTING.md) for an intro guide to developing Nokogiri. + + +## Code of Conduct + +We've adopted the Contributor Covenant code of conduct, which you can read in full in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md). + + +## License + +This project is licensed under the terms of the MIT license. + +See this license at [`LICENSE.md`](LICENSE.md). + + +### Dependencies + +Some additional libraries may be distributed with your version of Nokogiri. Please see [`LICENSE-DEPENDENCIES.md`](LICENSE-DEPENDENCIES.md) for a discussion of the variations as well as the licenses thereof. + + +## Authors + +- Mike Dalessio +- Aaron Patterson +- Yoko Harada +- Akinori MUSHA +- John Shahid +- Karol Bucek +- Sam Ruby +- Craig Barnes +- Stephen Checkoway +- Lars Kanis +- Sergio Arbeo +- Timothy Elliott +- Nobuyoshi Nakada diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/bin/nokogiri b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/bin/nokogiri new file mode 100755 index 00000000..04a5ceae --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/bin/nokogiri @@ -0,0 +1,131 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "optparse" +require "open-uri" +require "uri" +require "rubygems" +require "nokogiri" +autoload :IRB, "irb" + +parse_class = Nokogiri +encoding = nil + +# This module provides some tunables with the nokogiri CLI for use in +# your ~/.nokogirirc. +module Nokogiri + module CLI + class << self + # Specify the console engine, defaulted to IRB. + # + # call-seq: + # require 'pry' + # Nokogiri::CLI.console = Pry + attr_writer :console + + def console + case @console + when Symbol + Kernel.const_get(@console) + else + @console + end + end + + attr_accessor :rcfile + end + + self.rcfile = File.expand_path("~/.nokogirirc") + self.console = :IRB + end +end + +def safe_read(uri_or_path) + uri = URI.parse(uri_or_path) + case uri + when URI::HTTP + uri.read + when URI::File + File.read(uri.path) + else + File.read(uri_or_path) + end +end + +opts = OptionParser.new do |opts| + opts.banner = "Nokogiri: an HTML, XML, SAX, and Reader parser" + opts.define_head("Usage: nokogiri [options]") + opts.separator("") + opts.separator("Examples:") + opts.separator(" nokogiri https://www.ruby-lang.org/") + opts.separator(" nokogiri ./public/index.html") + opts.separator(" curl -s http://www.nokogiri.org | nokogiri -e'p $_.css(\"h1\").length'") + opts.separator("") + opts.separator("Options:") + + opts.on("--type type", "Parse as type: xml or html (default: auto)", [:xml, :html]) do |v| + parse_class = { xml: Nokogiri::XML, html: Nokogiri::HTML }[v] + end + + opts.on("-C file", "Specifies initialization file to load (default #{Nokogiri::CLI.rcfile})") do |v| + Nokogiri::CLI.rcfile = v + end + + opts.on("-E", "--encoding encoding", "Read as encoding (default: #{encoding || "none"})") do |v| + encoding = v + end + + opts.on("-e command", "Specifies script from command-line.") do |v| + @script = v + end + + opts.on("--rng ", "Validate using this rng file.") do |v| + @rng = Nokogiri::XML::RelaxNG(safe_read(v)) + end + + opts.on_tail("-?", "--help", "Show this message") do + puts opts + exit + end + + opts.on_tail("-v", "--version", "Show version") do + puts Nokogiri::VersionInfo.instance.to_markdown + exit + end +end +opts.parse! + +url = ARGV.shift + +if url.to_s.strip.empty? && $stdin.tty? + puts opts + exit 1 +end + +if File.file?(Nokogiri::CLI.rcfile) + load Nokogiri::CLI.rcfile +end + +@doc = if url || $stdin.tty? + parse_class.parse(safe_read(url), url, encoding) +else + parse_class.parse($stdin, nil, encoding) +end + +$_ = @doc + +if @rng + @rng.validate(@doc).each do |error| + puts error.message + end +elsif @script + begin + eval(@script, binding, "
") # rubocop:disable Security/Eval + rescue Exception => e # rubocop:disable Lint/RescueException + warn("ERROR: Exception raised while evaluating '#{@script}'") + raise e + end +else + puts "Your document is stored in @doc..." + Nokogiri::CLI.console.start +end diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/dependencies.yml b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/dependencies.yml new file mode 100644 index 00000000..22ef327a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/dependencies.yml @@ -0,0 +1,42 @@ +--- +libxml2: + version: "2.13.6" + sha256: "f453480307524968f7a04ec65e64f2a83a825973bcd260a2e7691be82ae70c96" + # sha-256 hash provided in https://download.gnome.org/sources/libxml2/2.13/libxml2-2.13.6.sha256sum + +libxslt: + version: "1.1.42" + sha256: "85ca62cac0d41fc77d3f6033da9df6fd73d20ea2fc18b0a3609ffb4110e1baeb" + # sha-256 hash provided in https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.42.sha256sum + +zlib: + version: "1.3.1" + sha256: "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23" + # SHA-256 hash provided on http://zlib.net/ + +libiconv: + version: "1.17" + sha256: "8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313" + # signature verified by following this path: + # - release announced at https://savannah.gnu.org/forum/forum.php?forum_id=10175 + # - which links to https://savannah.gnu.org/users/haible as the releaser + # - which links to https://savannah.gnu.org/people/viewgpg.php?user_id=1871 as the gpg key + # + # So: + # - wget -q -O - https://savannah.gnu.org/people/viewgpg.php?user_id=1871 | gpg --import + # gpg: key F5BE8B267C6A406D: 1 signature not checked due to a missing key + # gpg: key F5BE8B267C6A406D: public key "Bruno Haible (Open Source Development) " imported + # gpg: Total number processed: 1 + # gpg: imported: 1 + # gpg: marginals needed: 3 completes needed: 1 trust model: pgp + # gpg: depth: 0 valid: 4 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 4u + # gpg: next trustdb check due at 2024-05-09 + # - gpg --verify libiconv-1.17.tar.gz.sig ports/archives/libiconv-1.17.tar.gz + # gpg: Signature made Sun 15 May 2022 11:26:42 AM EDT + # gpg: using RSA key 9001B85AF9E1B83DF1BDA942F5BE8B267C6A406D + # gpg: Good signature from "Bruno Haible (Open Source Development) " [unknown] + # gpg: WARNING: This key is not certified with a trusted signature! + # gpg: There is no indication that the signature belongs to the owner. + # Primary key fingerprint: 9001 B85A F9E1 B83D F1BD A942 F5BE 8B26 7C6A 406D + # + # And this sha256sum is calculated from that verified tarball. diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/depend b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/depend new file mode 100644 index 00000000..24f59088 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/depend @@ -0,0 +1,38 @@ +# -*-makefile-*- +# DO NOT DELETE + +gumbo.o: $(srcdir)/nokogiri.h +html_document.o: $(srcdir)/nokogiri.h +html_element_description.o: $(srcdir)/nokogiri.h +html_entity_lookup.o: $(srcdir)/nokogiri.h +html_sax_parser_context.o: $(srcdir)/nokogiri.h +html_sax_push_parser.o: $(srcdir)/nokogiri.h +libxml2_backwards_compat.o: $(srcdir)/nokogiri.h +nokogiri.o: $(srcdir)/nokogiri.h +test_global_handlers.o: $(srcdir)/nokogiri.h +xml_attr.o: $(srcdir)/nokogiri.h +xml_attribute_decl.o: $(srcdir)/nokogiri.h +xml_cdata.o: $(srcdir)/nokogiri.h +xml_comment.o: $(srcdir)/nokogiri.h +xml_document.o: $(srcdir)/nokogiri.h +xml_document_fragment.o: $(srcdir)/nokogiri.h +xml_dtd.o: $(srcdir)/nokogiri.h +xml_element_content.o: $(srcdir)/nokogiri.h +xml_element_decl.o: $(srcdir)/nokogiri.h +xml_encoding_handler.o: $(srcdir)/nokogiri.h +xml_entity_decl.o: $(srcdir)/nokogiri.h +xml_entity_reference.o: $(srcdir)/nokogiri.h +xml_namespace.o: $(srcdir)/nokogiri.h +xml_node.o: $(srcdir)/nokogiri.h +xml_node_set.o: $(srcdir)/nokogiri.h +xml_processing_instruction.o: $(srcdir)/nokogiri.h +xml_reader.o: $(srcdir)/nokogiri.h +xml_relax_ng.o: $(srcdir)/nokogiri.h +xml_sax_parser.o: $(srcdir)/nokogiri.h +xml_sax_parser_context.o: $(srcdir)/nokogiri.h +xml_sax_push_parser.o: $(srcdir)/nokogiri.h +xml_schema.o: $(srcdir)/nokogiri.h +xml_syntax_error.o: $(srcdir)/nokogiri.h +xml_text.o: $(srcdir)/nokogiri.h +xml_xpath_context.o: $(srcdir)/nokogiri.h +xslt_stylesheet.o: $(srcdir)/nokogiri.h diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/extconf.rb b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/extconf.rb new file mode 100644 index 00000000..70e2fe0c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/extconf.rb @@ -0,0 +1,1173 @@ +# frozen_string_literal: true + +# rubocop:disable Style/GlobalVars + +ENV["RC_ARCHS"] = "" if RUBY_PLATFORM.include?("darwin") + +require "mkmf" +require "rbconfig" +require "fileutils" +require "shellwords" +require "pathname" + +# helpful constants +PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", "..")) +REQUIRED_LIBXML_VERSION = "2.9.2" +RECOMMENDED_LIBXML_VERSION = "2.12.0" + +REQUIRED_MINI_PORTILE_VERSION = "~> 2.8.2" # keep this version in sync with the one in the gemspec +REQUIRED_PKG_CONFIG_VERSION = "~> 1.1" + +# Keep track of what versions of what libraries we build against +OTHER_LIBRARY_VERSIONS = {} + +NOKOGIRI_HELP_MESSAGE = <<~HELP + USAGE: ruby #{$PROGRAM_NAME} [options] + + Flags that are always valid: + + --use-system-libraries + --enable-system-libraries + Use system libraries instead of building and using the packaged libraries. + + --disable-system-libraries + Use the packaged libraries, and ignore the system libraries. This is the default on most + platforms, and overrides `--use-system-libraries` and the environment variable + `NOKOGIRI_USE_SYSTEM_LIBRARIES`. + + --disable-clean + Do not clean out intermediate files after successful build. + + --prevent-strip + Take steps to prevent stripping the symbol table and debugging info from the shared + library, potentially overriding RbConfig's CFLAGS/LDFLAGS/DLDFLAGS. + + + Flags only used when using system libraries: + + General: + + --with-opt-dir=DIRECTORY + Look for headers and libraries in DIRECTORY. + + --with-opt-lib=DIRECTORY + Look for libraries in DIRECTORY. + + --with-opt-include=DIRECTORY + Look for headers in DIRECTORY. + + + Related to libxml2: + + --with-xml2-dir=DIRECTORY + Look for xml2 headers and library in DIRECTORY. + + --with-xml2-lib=DIRECTORY + Look for xml2 library in DIRECTORY. + + --with-xml2-include=DIRECTORY + Look for xml2 headers in DIRECTORY. + + --with-xml2-source-dir=DIRECTORY + (dev only) Build libxml2 from the source code in DIRECTORY + + --disable-xml2-legacy + Do not build libxml2 with zlib, liblzma, or HTTP support. This will become the default + in a future version of Nokogiri. + + + Related to libxslt: + + --with-xslt-dir=DIRECTORY + Look for xslt headers and library in DIRECTORY. + + --with-xslt-lib=DIRECTORY + Look for xslt library in DIRECTORY. + + --with-xslt-include=DIRECTORY + Look for xslt headers in DIRECTORY. + + --with-xslt-source-dir=DIRECTORY + (dev only) Build libxslt from the source code in DIRECTORY + + + Related to libexslt: + + --with-exslt-dir=DIRECTORY + Look for exslt headers and library in DIRECTORY. + + --with-exslt-lib=DIRECTORY + Look for exslt library in DIRECTORY. + + --with-exslt-include=DIRECTORY + Look for exslt headers in DIRECTORY. + + + Related to iconv: + + --with-iconv-dir=DIRECTORY + Look for iconv headers and library in DIRECTORY. + + --with-iconv-lib=DIRECTORY + Look for iconv library in DIRECTORY. + + --with-iconv-include=DIRECTORY + Look for iconv headers in DIRECTORY. + + + Related to zlib (ignored if `--disable-xml2-legacy` is used): + + --with-zlib-dir=DIRECTORY + Look for zlib headers and library in DIRECTORY. + + --with-zlib-lib=DIRECTORY + Look for zlib library in DIRECTORY. + + --with-zlib-include=DIRECTORY + Look for zlib headers in DIRECTORY. + + + Flags only used when building and using the packaged libraries: + + --disable-static + Do not statically link packaged libraries, instead use shared libraries. + + --enable-cross-build + Enable cross-build mode. (You probably do not want to set this manually.) + + + Environment variables used: + + NOKOGIRI_USE_SYSTEM_LIBRARIES + Equivalent to `--enable-system-libraries` when set, even if nil or blank. + + AR + Use this path to invoke the library archiver instead of `RbConfig::CONFIG['AR']` + + CC + Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']` + + CPPFLAGS + If this string is accepted by the C preprocessor, add it to the flags passed to the C preprocessor + + CFLAGS + If this string is accepted by the compiler, add it to the flags passed to the compiler + + LD + Use this path to invoke the linker instead of `RbConfig::CONFIG['LD']` + + LDFLAGS + If this string is accepted by the linker, add it to the flags passed to the linker + + LIBS + Add this string to the flags passed to the linker +HELP + +# +# utility functions +# +def config_clean? + enable_config("clean", true) +end + +def config_static? + default_static = !truffle? + enable_config("static", default_static) +end + +def config_cross_build? + enable_config("cross-build") +end + +def config_system_libraries? + enable_config("system-libraries", ENV.key?("NOKOGIRI_USE_SYSTEM_LIBRARIES")) do |_, default| + arg_config("--use-system-libraries", default) + end +end + +def config_with_xml2_legacy? + enable_config("xml2-legacy", true) +end + +def windows? + RbConfig::CONFIG["target_os"].match?(/mingw|mswin/) +end + +def solaris? + RbConfig::CONFIG["target_os"].include?("solaris") +end + +def darwin? + RbConfig::CONFIG["target_os"].include?("darwin") +end + +def openbsd? + RbConfig::CONFIG["target_os"].include?("openbsd") +end + +def aix? + RbConfig::CONFIG["target_os"].include?("aix") +end + +def unix? + !(windows? || solaris? || darwin?) +end + +def nix? + ENV.key?("NIX_CC") +end + +def truffle? + RUBY_ENGINE == "truffleruby" +end + +def concat_flags(*args) + args.compact.join(" ") +end + +def local_have_library(lib, func = nil, headers = nil) + have_library(lib, func, headers) || have_library("lib#{lib}", func, headers) +end + +def zlib_source(version_string) + # As of 2022-12, I'm starting to see failed downloads often enough from zlib.net that I want to + # change the default to github. + if ENV["NOKOGIRI_USE_CANONICAL_ZLIB_SOURCE"] + "https://zlib.net/fossils/zlib-#{version_string}.tar.gz" + else + "https://github.com/madler/zlib/releases/download/v#{version_string}/zlib-#{version_string}.tar.gz" + end +end + +def gnome_source + # As of 2022-02-20, some mirrors have expired SSL certificates. I'm able to retrieve from my home, + # but whatever host is resolved on the github actions workers see an expired cert. + # + # See https://github.com/sparklemotion/nokogiri/runs/5266206403?check_suite_focus=true + if ENV["NOKOGIRI_USE_CANONICAL_GNOME_SOURCE"] + "https://download.gnome.org" + else + "https://muug.ca/mirror/gnome" # old reliable + end +end + +LOCAL_PACKAGE_RESPONSE = Object.new +def LOCAL_PACKAGE_RESPONSE.%(package) + package ? "yes: #{package}" : "no" +end + +# wrapper around MakeMakefil#pkg_config and the PKGConfig gem +def try_package_configuration(pc) + unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG_GEM") + # try MakeMakefile#pkg_config, which uses the system utility `pkg-config`. + return if checking_for("#{pc} using `pkg_config`", LOCAL_PACKAGE_RESPONSE) do + pkg_config(pc) + end + end + + # `pkg-config` probably isn't installed, which appears to be the case for lots of freebsd systems. + # let's fall back to the pkg-config gem, which knows how to parse .pc files, and wrap it with the + # same logic as MakeMakefile#pkg_config + begin + require "rubygems" + gem("pkg-config", REQUIRED_PKG_CONFIG_VERSION) + require "pkg-config" + + checking_for("#{pc} using pkg-config gem version #{PKGConfig::VERSION}", LOCAL_PACKAGE_RESPONSE) do + if PKGConfig.have_package(pc) + cflags = PKGConfig.cflags(pc) + ldflags = PKGConfig.libs_only_L(pc) + libs = PKGConfig.libs_only_l(pc) + + Logging.message("pkg-config gem found package configuration for %s\n", pc) + Logging.message("cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs) + + [cflags, ldflags, libs] + end + end + rescue LoadError + message("Please install either the `pkg-config` utility or the `pkg-config` rubygem.\n") + end +end + +# set up mkmf to link against the library if we can find it +def have_package_configuration(opt: nil, pc: nil, lib:, func:, headers:) + if opt + dir_config(opt) + dir_config("opt") + end + + # see if we have enough path info to do this without trying any harder + unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG") + return true if local_have_library(lib, func, headers) + end + + try_package_configuration(pc) if pc + + # verify that we can compile and link against the library + local_have_library(lib, func, headers) +end + +def ensure_package_configuration(opt: nil, pc: nil, lib:, func:, headers:) + have_package_configuration(opt: opt, pc: pc, lib: lib, func: func, headers: headers) || + abort_could_not_find_library(lib) +end + +def ensure_func(func, headers = nil) + have_func(func, headers) || abort_could_not_find_library(func) +end + +def preserving_globals + values = [$arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs].map(&:dup) + yield +ensure + $arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs = values +end + +def abort_could_not_find_library(lib) + callers = caller(1..2).join("\n") + abort("-----\n#{callers}\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----") +end + +def chdir_for_build(&block) + # When using rake-compiler-dock on Windows, the underlying Virtualbox shared + # folders don't support symlinks, but libiconv expects it for a build on + # Linux. We work around this limitation by using the temp dir for cooking. + build_dir = /mingw|mswin|cygwin/.match?(ENV["RCD_HOST_RUBY_PLATFORM"].to_s) ? "/tmp" : "." + Dir.chdir(build_dir, &block) +end + +def sh_export_path(path) + # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":" + # as a $PATH separator, we need to convert windows paths from + # + # C:/path/to/foo + # + # to + # + # /C/path/to/foo + # + # which is sh-compatible, in order to find things properly during + # configuration + return path unless windows? + + match = Regexp.new("^([A-Z]):(/.*)").match(path) + if match && match.length == 3 + return File.join("/", match[1], match[2]) + end + + path +end + +def libflag_to_filename(ldflag) + case ldflag + when /\A-l(.+)/ + "lib#{Regexp.last_match(1)}.#{$LIBEXT}" + end +end + +def have_libxml_headers?(version = nil) + source = if version.nil? + <<~SRC + #include + SRC + else + version_int = format("%d%2.2d%2.2d", *version.split(".")) + <<~SRC + #include + #if LIBXML_VERSION < #{version_int} + # error libxml2 is older than #{version} + #endif + SRC + end + + try_cpp(source) +end + +def try_link_iconv(using = nil) + checking_for(using ? "iconv using #{using}" : "iconv") do + ["", "-liconv"].any? do |opt| + preserving_globals do + yield if block_given? + + try_link(<<~SRC, opt) + #include + #include + int main(void) + { + iconv_t cd = iconv_open("", ""); + iconv(cd, NULL, NULL, NULL, NULL); + return EXIT_SUCCESS; + } + SRC + end + end + end +end + +def iconv_configure_flags + # give --with-iconv-dir and --with-opt-dir first priority + ["iconv", "opt"].each do |target| + config = preserving_globals { dir_config(target) } + next unless config.any? && try_link_iconv("--with-#{target}-* flags") { dir_config(target) } + + idirs, ldirs = config.map do |dirs| + Array(dirs).flat_map do |dir| + dir.split(File::PATH_SEPARATOR) + end if dirs + end + + return [ + "--with-iconv=yes", + *("CPPFLAGS=#{idirs.map { |dir| "-I" + dir }.join(" ")}" if idirs), + *("LDFLAGS=#{ldirs.map { |dir| "-L" + dir }.join(" ")}" if ldirs), + ] + end + + if try_link_iconv + return ["--with-iconv=yes"] + end + + config = preserving_globals { pkg_config("libiconv") } + if config && try_link_iconv("pkg-config libiconv") { pkg_config("libiconv") } + cflags, ldflags, libs = config + + return [ + "--with-iconv=yes", + "CPPFLAGS=#{cflags}", + "LDFLAGS=#{ldflags}", + "LIBS=#{libs}", + ] + end + + abort_could_not_find_library("libiconv") +end + +def process_recipe(name, version, static_p, cross_p, cacheable_p = true) + require "rubygems" + gem("mini_portile2", REQUIRED_MINI_PORTILE_VERSION) # gemspec is not respected at install time + require "mini_portile2" + message("Using mini_portile version #{MiniPortile::VERSION}\n") + + unless ["libxml2", "libxslt"].include?(name) + OTHER_LIBRARY_VERSIONS[name] = version + end + + MiniPortile.new(name, version).tap do |recipe| + def recipe.port_path + "#{@target}/#{RUBY_PLATFORM}/#{@name}/#{@version}" + end + + # We use 'host' to set compiler prefix for cross-compiling. Prefer host_alias over host. And + # prefer i686 (what external dev tools use) to i386 (what ruby's configure.ac emits). + recipe.host = RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"] + recipe.host = recipe.host.gsub("i386", "i686") + + recipe.target = File.join(PACKAGE_ROOT_DIR, "ports") if cacheable_p + recipe.configure_options << "--libdir=#{File.join(recipe.path, "lib")}" + + yield recipe + + env = Hash.new do |hash, key| + hash[key] = (ENV[key]).to_s + end + + recipe.configure_options.flatten! + + recipe.configure_options.delete_if do |option| + case option + when /\A(\w+)=(.*)\z/ + env[Regexp.last_match(1)] = if env.key?(Regexp.last_match(1)) + concat_flags(env[Regexp.last_match(1)], Regexp.last_match(2)) + else + Regexp.last_match(2) + end + true + else + false + end + end + + if static_p + recipe.configure_options += [ + "--disable-shared", + "--enable-static", + ] + env["CFLAGS"] = concat_flags(env["CFLAGS"], "-fPIC") + else + recipe.configure_options += [ + "--enable-shared", + "--disable-static", + ] + end + + if cross_p + recipe.configure_options += [ + "--target=#{recipe.host}", + "--host=#{recipe.host}", + ] + end + + if RbConfig::CONFIG["target_cpu"] == "universal" + ["CFLAGS", "LDFLAGS"].each do |key| + unless env[key].include?("-arch") + env[key] = concat_flags(env[key], RbConfig::CONFIG["ARCH_FLAG"]) + end + end + end + + recipe.configure_options += env.map do |key, value| + "#{key}=#{value.strip}" + end + + checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{RUBY_PLATFORM}.installed" + if File.exist?(checkpoint) && !recipe.source_directory + message("Building Nokogiri with a packaged version of #{name}-#{version}.\n") + else + message(<<~EOM) + ---------- IMPORTANT NOTICE ---------- + Building Nokogiri with a packaged version of #{name}-#{version}. + Configuration options: #{recipe.configure_options.shelljoin} + EOM + + unless recipe.patch_files.empty? + message("The following patches are being applied:\n") + + recipe.patch_files.each do |patch| + message(format(" - %s\n", File.basename(patch))) + end + end + + message(<<~EOM) if name != "libgumbo" + + The Nokogiri maintainers intend to provide timely security updates, but if + this is a concern for you and want to use your OS/distro system library + instead, then abort this installation process and install nokogiri as + instructed at: + + https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries + + EOM + + message(<<~EOM) if name == "libxml2" + Note, however, that nokogiri cannot guarantee compatibility with every + version of libxml2 that may be provided by OS/package vendors. + + EOM + + chdir_for_build { recipe.cook } + FileUtils.touch(checkpoint) + end + recipe.activate + end +end + +def copy_packaged_libraries_headers(to_path:, from_recipes:) + FileUtils.rm_rf(to_path, secure: true) + FileUtils.mkdir(to_path) + from_recipes.each do |recipe| + FileUtils.cp_r(Dir[File.join(recipe.path, "include/*")], to_path) + end +end + +def do_help + print(NOKOGIRI_HELP_MESSAGE) + exit!(0) +end + +def do_clean + root = Pathname(PACKAGE_ROOT_DIR) + pwd = Pathname(Dir.pwd) + + # Skip if this is a development work tree + unless (root + ".git").exist? + message("Cleaning files only used during build.\n") + + # (root + 'tmp') cannot be removed at this stage because + # nokogiri.so is yet to be copied to lib. + + # clean the ports build directory + Pathname.glob(pwd.join("tmp", "*", "ports")) do |dir| + FileUtils.rm_rf(dir, verbose: true) + end + + if config_static? + # ports installation can be safely removed if statically linked. + FileUtils.rm_rf(root + "ports", verbose: true) + else + FileUtils.rm_rf(root + "ports" + "archives", verbose: true) + end + end + + exit!(0) +end + +# In ruby 3.2, symbol resolution changed on Darwin, to introduce the `-bundle_loader` flag to +# resolve symbols against the ruby binary. +# +# This makes it challenging to build a single extension that works with both a ruby with +# `--enable-shared` and one with `--disable-shared. To work around that, we choose to add +# `-flat_namespace` to the link line (later in this file). +# +# The `-flat_namespace` line introduces its own behavior change, which is that (similar to on +# Linux), any symbols in the extension that are exported may now be resolved by shared libraries +# loaded by the Ruby process. Specifically, that means that libxml2 and libxslt, which are +# statically linked into the nokogiri bundle, will resolve (at runtime) to a system libxml2 loaded +# by Ruby on Darwin. And it appears that often Ruby on Darwin does indeed load the system libxml2, +# and that messes with our assumptions about whether we're running with a patched libxml2 or a +# vanilla libxml2. +# +# We choose to use `-load_hidden` in this case to prevent exporting those symbols from libxml2 and +# libxslt, which ensures that they will be resolved to the static libraries in the bundle. In other +# words, when we use `load_hidden`, what happens in the extension stays in the extension. +# +# See https://github.com/rake-compiler/rake-compiler-dock/issues/87 for more info. +# +# Anyway, this method is the logical bit to tell us when to turn on these workarounds. +def needs_darwin_linker_hack + config_cross_build? && + darwin? && + Gem::Requirement.new("~> 3.2").satisfied_by?(Gem::Version.new(RbConfig::CONFIG["ruby_version"].split("+").first)) +end + +# +# main +# +do_help if arg_config("--help") +do_clean if arg_config("--clean") + +if openbsd? && !config_system_libraries? + unless %x(#{ENV["CC"] || "/usr/bin/cc"} -v 2>&1).include?("clang") + (ENV["CC"] ||= find_executable("egcc")) || + abort("Please install gcc 4.9+ from ports using `pkg_add -v gcc`") + end + append_cppflags "-I/usr/local/include" +end + +if ENV["AR"] + RbConfig::CONFIG["AR"] = RbConfig::MAKEFILE_CONFIG["AR"] = ENV["AR"] +end + +if ENV["CC"] + RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] +end + +if ENV["LD"] + RbConfig::CONFIG["LD"] = RbConfig::MAKEFILE_CONFIG["LD"] = ENV["LD"] +end + +# use same toolchain for libxml and libxslt +ENV["AR"] = RbConfig::CONFIG["AR"] +ENV["CC"] = RbConfig::CONFIG["CC"] +ENV["LD"] = RbConfig::CONFIG["LD"] + +if arg_config("--prevent-strip") + old_cflags = $CFLAGS.split.join(" ") + old_ldflags = $LDFLAGS.split.join(" ") + old_dldflags = $DLDFLAGS.split.join(" ") + $CFLAGS = $CFLAGS.split.reject { |flag| flag == "-s" }.join(" ") + $LDFLAGS = $LDFLAGS.split.reject { |flag| flag == "-s" }.join(" ") + $DLDFLAGS = $DLDFLAGS.split.reject { |flag| flag == "-s" }.join(" ") + puts "Prevent stripping by removing '-s' from $CFLAGS" if old_cflags != $CFLAGS + puts "Prevent stripping by removing '-s' from $LDFLAGS" if old_ldflags != $LDFLAGS + puts "Prevent stripping by removing '-s' from $DLDFLAGS" if old_dldflags != $DLDFLAGS +end + +# adopt environment config +append_cflags(ENV["CFLAGS"]) unless ENV["CFLAGS"].nil? +append_cppflags(ENV["CPPFLAGS"]) unless ENV["CPPFLAGS"].nil? +append_ldflags(ENV["LDFLAGS"]) unless ENV["LDFLAGS"].nil? +$LIBS = concat_flags($LIBS, ENV["LIBS"]) + +# libgumbo uses C90/C99 features, see #2302 +append_cflags(["-std=c99", "-Wno-declaration-after-statement"]) + +# gumbo html5 serialization is slower with O3, let's make sure we use O2 +append_cflags("-O2") + +# always include debugging information +append_cflags("-g") + +# we use at least one inline function in the C extension +append_cflags("-Winline") + +# good to have no matter what Ruby was compiled with +append_cflags("-Wmissing-noreturn") + +# check integer loss of precision. this flag won't generally work until Ruby 3.4. +# see https://bugs.ruby-lang.org/issues/20507 +append_cflags("-Wconversion") + +# handle clang variations, see #1101 +if darwin? + append_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future") + append_cflags("-Wno-unknown-warning-option") +end + +# these tend to be noisy, but on occasion useful during development +# append_cflags(["-Wcast-qual", "-Wwrite-strings"]) + +# Add SDK-specific include path for macOS and brew versions before v2.2.12 (2020-04-08) [#1851, #1801] +macos_mojave_sdk_include_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2" +if config_system_libraries? && darwin? && Dir.exist?(macos_mojave_sdk_include_path) && !nix? + append_cppflags("-I#{macos_mojave_sdk_include_path}") +end + +# Work around a character escaping bug in MSYS by passing an arbitrary double-quoted parameter to gcc. +# See https://sourceforge.net/p/mingw/bugs/2142 +append_cppflags(' "-Idummypath"') if windows? + +if config_system_libraries? + message "Building nokogiri using system libraries.\n" + if config_with_xml2_legacy? + ensure_package_configuration( + opt: "zlib", + pc: "zlib", + lib: "z", + headers: "zlib.h", + func: "gzdopen", + ) + end + ensure_package_configuration( + opt: "xml2", + pc: "libxml-2.0", + lib: "xml2", + headers: "libxml/parser.h", + func: "xmlParseDoc", + ) + ensure_package_configuration( + opt: "xslt", + pc: "libxslt", + lib: "xslt", + headers: "libxslt/xslt.h", + func: "xsltParseStylesheetDoc", + ) + ensure_package_configuration( + opt: "exslt", + pc: "libexslt", + lib: "exslt", + headers: "libexslt/exslt.h", + func: "exsltFuncRegister", + ) + + have_libxml_headers?(REQUIRED_LIBXML_VERSION) || + abort("ERROR: libxml2 version #{REQUIRED_LIBXML_VERSION} or later is required!") + have_libxml_headers?(RECOMMENDED_LIBXML_VERSION) || + warn("WARNING: libxml2 version #{RECOMMENDED_LIBXML_VERSION} or later is highly recommended, but proceeding anyway.") + +else + message "Building nokogiri using packaged libraries.\n" + + static_p = config_static? + message "Static linking is #{static_p ? "enabled" : "disabled"}.\n" + + cross_build_p = config_cross_build? + message "Cross build is #{cross_build_p ? "enabled" : "disabled"}.\n" + + if needs_darwin_linker_hack + append_ldflags("-Wl,-flat_namespace") + end + + require "yaml" + dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml")) + + dir_config("zlib") if config_with_xml2_legacy? + + if cross_build_p || windows? + if config_with_xml2_legacy? + zlib_recipe = process_recipe("zlib", dependencies["zlib"]["version"], static_p, cross_build_p) do |recipe| + recipe.files = [{ + url: zlib_source(recipe.version), + sha256: dependencies["zlib"]["sha256"], + }] + if windows? + class << recipe + attr_accessor :cross_build_p + + def configure + Dir.chdir(work_path) do + mk = File.read("win32/Makefile.gcc") + File.open("win32/Makefile.gcc", "wb") do |f| + f.puts "BINARY_PATH = #{path}/bin" + f.puts "LIBRARY_PATH = #{path}/lib" + f.puts "INCLUDE_PATH = #{path}/include" + mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p + f.puts mk + end + end + end + + def configured? + Dir.chdir(work_path) do + !!(File.read("win32/Makefile.gcc") =~ /^BINARY_PATH/) + end + end + + def compile + execute("compile", "make -f win32/Makefile.gcc") + end + + def install + execute("install", "make -f win32/Makefile.gcc install") + end + end + recipe.cross_build_p = cross_build_p + else + class << recipe + def configure + env = {} + env["CFLAGS"] = concat_flags(ENV["CFLAGS"], "-fPIC", "-g") + env["CHOST"] = host + execute("configure", ["./configure", "--static", configure_prefix], { env: env }) + if darwin? + # needed as of zlib 1.2.13 + Dir.chdir(work_path) do + makefile = File.read("Makefile").gsub(/^AR=.*$/, "AR=#{host}-libtool") + File.open("Makefile", "w") { |m| m.write(makefile) } + end + end + end + end + end + end + end + + unless unix? + libiconv_recipe = process_recipe( + "libiconv", + dependencies["libiconv"]["version"], + static_p, + cross_build_p, + ) do |recipe| + recipe.files = [{ + url: "https://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz", + sha256: dependencies["libiconv"]["sha256"], + }] + + # The libiconv configure script doesn't accept "arm64" host string but "aarch64" + recipe.host = recipe.host.gsub("arm64-apple-darwin", "aarch64-apple-darwin") + + cflags = concat_flags(ENV["CFLAGS"], "-O2", "-g") + + recipe.configure_options += [ + "--disable-dependency-tracking", + "CPPFLAGS=-Wall", + "CFLAGS=#{cflags}", + "CXXFLAGS=#{cflags}", + "LDFLAGS=", + ] + end + end + elsif darwin? && !have_header("iconv.h") + abort(<<~EOM.chomp) + ----- + The file "iconv.h" is missing in your build environment, + which means you haven't installed Xcode Command Line Tools properly. + + To install Command Line Tools, try running `xcode-select --install` on + terminal and follow the instructions. If it fails, open Xcode.app, + select from the menu "Xcode" - "Open Developer Tool" - "More Developer + Tools" to open the developer site, download the installer for your OS + version and run it. + ----- + EOM + end + + if zlib_recipe + append_cppflags("-I#{zlib_recipe.path}/include") + $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH + ensure_package_configuration( + opt: "zlib", + pc: "zlib", + lib: "z", + headers: "zlib.h", + func: "gzdopen", + ) + end + + if libiconv_recipe + append_cppflags("-I#{libiconv_recipe.path}/include") + $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH + ensure_package_configuration( + opt: "iconv", + pc: "iconv", + lib: "iconv", + headers: "iconv.h", + func: "iconv_open", + ) + end + + libxml2_recipe = process_recipe("libxml2", dependencies["libxml2"]["version"], static_p, cross_build_p) do |recipe| + source_dir = arg_config("--with-xml2-source-dir") + if source_dir + recipe.source_directory = source_dir + else + minor_version = Gem::Version.new(recipe.version).segments.take(2).join(".") + recipe.files = [{ + url: "#{gnome_source}/sources/libxml2/#{minor_version}/#{recipe.name}-#{recipe.version}.tar.xz", + sha256: dependencies["libxml2"]["sha256"], + }] + recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", "libxml2", "*.patch")].sort + end + + cppflags = concat_flags(ENV["CPPFLAGS"]) + cflags = concat_flags(ENV["CFLAGS"], "-O2", "-g") + + if cross_build_p + cppflags = concat_flags(cppflags, "-DNOKOGIRI_PRECOMPILED_LIBRARIES") + end + + if config_with_xml2_legacy? + recipe.configure_options << "--with-legacy" + end + + if zlib_recipe + recipe.configure_options << "--with-zlib=#{zlib_recipe.path}" + end + + if libiconv_recipe + recipe.configure_options << "--with-iconv=#{libiconv_recipe.path}" + else + recipe.configure_options += iconv_configure_flags + end + + if darwin? && !cross_build_p + recipe.configure_options << "RANLIB=/usr/bin/ranlib" unless ENV.key?("RANLIB") + recipe.configure_options << "AR=/usr/bin/ar" unless ENV.key?("AR") + end + + if windows? + cflags = concat_flags(cflags, "-ULIBXML_STATIC", "-DIN_LIBXML") + end + + recipe.configure_options << if source_dir + "--config-cache" + else + "--disable-dependency-tracking" + end + + recipe.configure_options += [ + "--without-python", + "--without-readline", + "--with-c14n", + "--with-debug", + "--with-threads", + "CPPFLAGS=#{cppflags}", + "CFLAGS=#{cflags}", + ] + end + + libxslt_recipe = process_recipe("libxslt", dependencies["libxslt"]["version"], static_p, cross_build_p) do |recipe| + source_dir = arg_config("--with-xslt-source-dir") + if source_dir + recipe.source_directory = source_dir + else + minor_version = Gem::Version.new(recipe.version).segments.take(2).join(".") + recipe.files = [{ + url: "#{gnome_source}/sources/libxslt/#{minor_version}/#{recipe.name}-#{recipe.version}.tar.xz", + sha256: dependencies["libxslt"]["sha256"], + }] + recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", "libxslt", "*.patch")].sort + end + + cflags = concat_flags(ENV["CFLAGS"], "-O2", "-g") + + if darwin? && !cross_build_p + recipe.configure_options << "RANLIB=/usr/bin/ranlib" unless ENV.key?("RANLIB") + recipe.configure_options << "AR=/usr/bin/ar" unless ENV.key?("AR") + end + + if windows? + cflags = concat_flags(cflags, "-ULIBXSLT_STATIC", "-DIN_LIBXSLT") + cflags = concat_flags(cflags, "-ULIBEXSLT_STATIC", "-DIN_LIBEXSLT") + end + + recipe.configure_options << if source_dir + "--config-cache" + else + "--disable-dependency-tracking" + end + + recipe.configure_options += [ + "--without-python", + "--without-crypto", + "--with-debug", + "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}", + "CFLAGS=#{cflags}", + ] + end + + append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES") + append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p + + $libs = $libs.shellsplit.tap do |libs| + [libxml2_recipe, libxslt_recipe].each do |recipe| + libname = recipe.name[/\Alib(.+)\z/, 1] + config_basename = "#{libname}-config" + File.join(recipe.path, "bin", config_basename).tap do |config| + # call config scripts explicit with 'sh' for compat with Windows + cflags = %x(sh #{config} --cflags).strip + message("#{config_basename} cflags: #{cflags}\n") + $CPPFLAGS = concat_flags(cflags, $CPPFLAGS) # prepend + + %x(sh #{config} --libs).strip.shellsplit.each do |arg| + case arg + when /\A-L(.+)\z/ + # Prioritize ports' directories + $LIBPATH = if Regexp.last_match(1).start_with?(PACKAGE_ROOT_DIR + "/") + [Regexp.last_match(1)] | $LIBPATH + else + $LIBPATH | [Regexp.last_match(1)] + end + when /\A-l./ + libs.unshift(arg) + else + $LDFLAGS << " " << arg.shellescape + end + end + end + + patches_string = recipe.patch_files.map { |path| File.basename(path) }.join(" ") + append_cppflags(%[-DNOKOGIRI_#{recipe.name.upcase}_PATCHES="\\"#{patches_string}\\""]) + + case libname + when "xml2" + # xslt-config --libs or pkg-config libxslt --libs does not include + # -llzma, so we need to add it manually when linking statically. + if static_p && preserving_globals { local_have_library("lzma") } + # Add it at the end; GH #988 + libs << "-llzma" + end + when "xslt" + # xslt-config does not have a flag to emit options including + # -lexslt, so add it manually. + libs.unshift("-lexslt") + end + end + end.shelljoin + + if static_p + static_archive_ld_flag = needs_darwin_linker_hack ? ["-load_hidden"] : [] + $libs = $libs.shellsplit.map do |arg| + case arg + when "-lxml2" + static_archive_ld_flag + [File.join(libxml2_recipe.path, "lib", libflag_to_filename(arg))] + when "-lxslt", "-lexslt" + static_archive_ld_flag + [File.join(libxslt_recipe.path, "lib", libflag_to_filename(arg))] + else + arg + end + end.flatten.shelljoin + end + + ensure_func("xmlParseDoc", "libxml/parser.h") + ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h") + ensure_func("exsltFuncRegister", "libexslt/exslt.h") +end + +if arg_config("--gumbo-dev") + message("DEV MODE ENABLED: build libgumbo as packaged source") + ext_dir = File.dirname(__FILE__) + Dir.chdir(ext_dir) do + $srcs = Dir["*.c", "../../gumbo-parser/src/*.c"] + $hdrs = Dir["*.h", "../../gumbo-parser/src/*.h"] + end + $INCFLAGS << " -I$(srcdir)/../../gumbo-parser/src" + $VPATH << "$(srcdir)/../../gumbo-parser/src" + find_header("nokogiri_gumbo.h") || abort("nokogiri_gumbo.h not found") +else + libgumbo_recipe = process_recipe("libgumbo", "1.0.0-nokogiri", static_p, cross_build_p, false) do |recipe| + recipe.configure_options = [] + + class << recipe + def downloaded? + true + end + + def extract + target = File.join(tmp_path, "gumbo-parser") + output("Copying gumbo-parser files into #{target}...") + FileUtils.mkdir_p(target) + FileUtils.cp(Dir.glob(File.join(PACKAGE_ROOT_DIR, "gumbo-parser/src/*")), target) + end + + def configured? + true + end + + def install + lib_dir = File.join(port_path, "lib") + inc_dir = File.join(port_path, "include") + FileUtils.mkdir_p([lib_dir, inc_dir]) + FileUtils.cp(File.join(work_path, "libgumbo.a"), lib_dir) + FileUtils.cp(Dir.glob(File.join(work_path, "*.h")), inc_dir) + end + + def compile + cflags = concat_flags(ENV["CFLAGS"], "-fPIC", "-O2", "-g") + + env = { "CC" => gcc_cmd, "CFLAGS" => cflags } + if config_cross_build? + if host.include?("darwin") + env["AR"] = "#{host}-libtool" + env["ARFLAGS"] = "-o" + else + env["AR"] = "#{host}-ar" + end + env["RANLIB"] = "#{host}-ranlib" + if windows? + concat_flags(env["CFLAGS"], "-D_RUBY_UCRT") + end + end + + execute("compile", make_cmd, { env: env }) + end + end + end + append_cppflags("-I#{File.join(libgumbo_recipe.path, "include")}") + $libs = $libs + " " + File.join(libgumbo_recipe.path, "lib", "libgumbo.a") + $LIBPATH = $LIBPATH | [File.join(libgumbo_recipe.path, "lib")] + ensure_func("gumbo_parse_with_options", "nokogiri_gumbo.h") +end + +have_func("xmlCtxtSetOptions") # introduced in libxml2 2.13.0 +have_func("xmlCtxtGetOptions") # introduced in libxml2 2.14.0 +have_func("xmlSwitchEncodingName") # introduced in libxml2 2.13.0 +have_func("rb_category_warning") # introduced in Ruby 3.0 but had trouble resolving this symbol in truffleruby + +other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",") +append_cppflags(%[-DNOKOGIRI_OTHER_LIBRARY_VERSIONS="\\"#{other_library_versions_string}\\""]) + +unless config_system_libraries? + if cross_build_p + # When precompiling native gems, copy packaged libraries' headers to ext/nokogiri/include + # These are packaged up by the cross-compiling callback in the ExtensionTask + copy_packaged_libraries_headers( + to_path: File.join(PACKAGE_ROOT_DIR, "ext/nokogiri/include"), + from_recipes: [libxml2_recipe, libxslt_recipe], + ) + else + # When compiling during installation, install packaged libraries' header files into ext/nokogiri/include + copy_packaged_libraries_headers( + to_path: "include", + from_recipes: [libxml2_recipe, libxslt_recipe], + ) + $INSTALLFILES << ["include/**/*.h", "$(rubylibdir)"] + end +end + +create_makefile("nokogiri/nokogiri") + +if config_clean? + # Do not clean if run in a development work tree. + File.open("Makefile", "at") do |mk| + mk.print(<<~EOF) + + all: clean-ports + clean-ports: $(TARGET_SO) + \t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? "enable" : "disable"}-static + EOF + end +end + +# rubocop:enable Style/GlobalVars diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/gumbo.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/gumbo.c new file mode 100644 index 00000000..fd938f3c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/gumbo.c @@ -0,0 +1,610 @@ +// +// Copyright 2013-2021 Sam Ruby, Stephen Checkoway +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// nokogumbo.c defines the following: +// +// class Nokogumbo +// def parse(utf8_string) # returns Nokogiri::HTML5::Document +// end +// +// Processing starts by calling gumbo_parse_with_options. The resulting document tree +// is then walked, a parallel libxml2 tree is constructed, and the final document is +// then wrapped using noko_xml_document_wrap. This approach reduces memory and CPU +// requirements as Ruby objects are only built when necessary. +// + +#include + +#include "nokogiri_gumbo.h" + +VALUE cNokogiriHtml5Document; + +// Interned symbols +static ID internal_subset; +static ID parent; + +#include +#include +#include + +// URI = system id +// external id = public id +static xmlDocPtr +new_html_doc(const char *dtd_name, const char *system, const char *public) +{ + // These two libxml2 functions take the public and system ids in + // opposite orders. + htmlDocPtr doc = htmlNewDocNoDtD(/* URI */ NULL, /* ExternalID */NULL); + assert(doc); + if (dtd_name) { + xmlCreateIntSubset(doc, (const xmlChar *)dtd_name, (const xmlChar *)public, (const xmlChar *)system); + } + return doc; +} + +static xmlNodePtr +get_parent(xmlNodePtr node) +{ + return node->parent; +} + +static GumboOutput * +perform_parse(const GumboOptions *options, VALUE input) +{ + assert(RTEST(input)); + Check_Type(input, T_STRING); + GumboOutput *output = gumbo_parse_with_options( + options, + RSTRING_PTR(input), + (size_t)RSTRING_LEN(input) + ); + + const char *status_string = gumbo_status_to_string(output->status); + switch (output->status) { + case GUMBO_STATUS_OK: + break; + case GUMBO_STATUS_TOO_MANY_ATTRIBUTES: + case GUMBO_STATUS_TREE_TOO_DEEP: + gumbo_destroy_output(output); + rb_raise(rb_eArgError, "%s", status_string); + case GUMBO_STATUS_OUT_OF_MEMORY: + gumbo_destroy_output(output); + rb_raise(rb_eNoMemError, "%s", status_string); + } + return output; +} + +static xmlNsPtr +lookup_or_add_ns( + xmlDocPtr doc, + xmlNodePtr root, + const char *href, + const char *prefix +) +{ + xmlNsPtr ns = xmlSearchNs(doc, root, (const xmlChar *)prefix); + if (ns) { + return ns; + } + return xmlNewNs(root, (const xmlChar *)href, (const xmlChar *)prefix); +} + +static void +set_line(xmlNodePtr node, size_t line) +{ + // libxml2 uses 65535 to mean look elsewhere for the line number on some + // nodes. + if (line < 65535) { + node->line = (unsigned short)line; + } +} + +// Construct an XML tree rooted at xml_output_node from the Gumbo tree rooted +// at gumbo_node. +static void +build_tree( + xmlDocPtr doc, + xmlNodePtr xml_output_node, + const GumboNode *gumbo_node +) +{ + xmlNodePtr xml_root = NULL; + xmlNodePtr xml_node = xml_output_node; + size_t child_index = 0; + + while (true) { + assert(gumbo_node != NULL); + const GumboVector *children = gumbo_node->type == GUMBO_NODE_DOCUMENT ? + &gumbo_node->v.document.children : &gumbo_node->v.element.children; + if (child_index >= children->length) { + // Move up the tree and to the next child. + if (xml_node == xml_output_node) { + // We've built as much of the tree as we can. + return; + } + child_index = gumbo_node->index_within_parent + 1; + gumbo_node = gumbo_node->parent; + xml_node = get_parent(xml_node); + // Children of fragments don't share the same root, so reset it and + // it'll be set below. In the non-fragment case, this will only happen + // after the html element has been finished at which point there are no + // further elements. + if (xml_node == xml_output_node) { + xml_root = NULL; + } + continue; + } + const GumboNode *gumbo_child = children->data[child_index++]; + xmlNodePtr xml_child; + + switch (gumbo_child->type) { + case GUMBO_NODE_DOCUMENT: + abort(); // Bug in Gumbo. + + case GUMBO_NODE_TEXT: + case GUMBO_NODE_WHITESPACE: + xml_child = xmlNewDocText(doc, (const xmlChar *)gumbo_child->v.text.text); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); + break; + + case GUMBO_NODE_CDATA: + xml_child = xmlNewCDataBlock(doc, (const xmlChar *)gumbo_child->v.text.text, + (int) strlen(gumbo_child->v.text.text)); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); + break; + + case GUMBO_NODE_COMMENT: + xml_child = xmlNewDocComment(doc, (const xmlChar *)gumbo_child->v.text.text); + set_line(xml_child, gumbo_child->v.text.start_pos.line); + xmlAddChild(xml_node, xml_child); + break; + + case GUMBO_NODE_TEMPLATE: + // XXX: Should create a template element and a new DocumentFragment + case GUMBO_NODE_ELEMENT: { + xml_child = xmlNewDocNode(doc, NULL, (const xmlChar *)gumbo_child->v.element.name, NULL); + set_line(xml_child, gumbo_child->v.element.start_pos.line); + if (xml_root == NULL) { + xml_root = xml_child; + } + xmlNsPtr ns = NULL; + switch (gumbo_child->v.element.tag_namespace) { + case GUMBO_NAMESPACE_HTML: + break; + case GUMBO_NAMESPACE_SVG: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/svg", "svg"); + break; + case GUMBO_NAMESPACE_MATHML: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1998/Math/MathML", "math"); + break; + } + if (ns != NULL) { + xmlSetNs(xml_child, ns); + } + xmlAddChild(xml_node, xml_child); + + // Add the attributes. + const GumboVector *attrs = &gumbo_child->v.element.attributes; + for (size_t i = 0; i < attrs->length; i++) { + const GumboAttribute *attr = attrs->data[i]; + + switch (attr->attr_namespace) { + case GUMBO_ATTR_NAMESPACE_XLINK: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/1999/xlink", "xlink"); + break; + + case GUMBO_ATTR_NAMESPACE_XML: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/XML/1998/namespace", "xml"); + break; + + case GUMBO_ATTR_NAMESPACE_XMLNS: + ns = lookup_or_add_ns(doc, xml_root, "http://www.w3.org/2000/xmlns/", "xmlns"); + break; + + default: + ns = NULL; + } + xmlNewNsProp(xml_child, ns, (const xmlChar *)attr->name, (const xmlChar *)attr->value); + } + + // Add children for this element. + child_index = 0; + gumbo_node = gumbo_child; + xml_node = xml_child; + } + } + } +} + +static void +add_errors(const GumboOutput *output, VALUE rdoc, VALUE input, VALUE url) +{ + const char *input_str = RSTRING_PTR(input); + size_t input_len = (size_t)RSTRING_LEN(input); + + // Add parse errors to rdoc. + if (output->errors.length) { + const GumboVector *errors = &output->errors; + VALUE rerrors = rb_ary_new2(errors->length); + + for (size_t i = 0; i < errors->length; i++) { + GumboError *err = errors->data[i]; + GumboSourcePosition position = gumbo_error_position(err); + char *msg; + size_t size = gumbo_caret_diagnostic_to_string(err, input_str, input_len, &msg); + VALUE err_str = rb_utf8_str_new(msg, (int)size); + free(msg); + VALUE syntax_error = rb_class_new_instance(1, &err_str, cNokogiriXmlSyntaxError); + const char *error_code = gumbo_error_code(err); + VALUE str1 = error_code ? rb_utf8_str_new_static(error_code, (int)strlen(error_code)) : Qnil; + rb_iv_set(syntax_error, "@domain", INT2NUM(1)); // XML_FROM_PARSER + rb_iv_set(syntax_error, "@code", INT2NUM(1)); // XML_ERR_INTERNAL_ERROR + rb_iv_set(syntax_error, "@level", INT2NUM(2)); // XML_ERR_ERROR + rb_iv_set(syntax_error, "@file", url); + rb_iv_set(syntax_error, "@line", SIZET2NUM(position.line)); + rb_iv_set(syntax_error, "@str1", str1); + rb_iv_set(syntax_error, "@str2", Qnil); + rb_iv_set(syntax_error, "@str3", Qnil); + rb_iv_set(syntax_error, "@int1", INT2NUM(0)); + rb_iv_set(syntax_error, "@column", SIZET2NUM(position.column)); + rb_ary_push(rerrors, syntax_error); + } + rb_iv_set(rdoc, "@errors", rerrors); + } +} + +typedef struct { + GumboOutput *output; + VALUE input; + VALUE url_or_frag; + VALUE klass; + xmlDocPtr doc; +} ParseArgs; + +static VALUE +parse_cleanup(VALUE parse_args) +{ + ParseArgs *args = (ParseArgs *)parse_args; + gumbo_destroy_output(args->output); + // Make sure garbage collection doesn't mark the objects as being live based + // on references from the ParseArgs. This may be unnecessary. + args->input = Qnil; + args->url_or_frag = Qnil; + if (args->doc != NULL) { + xmlFreeDoc(args->doc); + } + return Qnil; +} + +// Scan the keyword arguments for options common to the document and fragment +// parse. +static GumboOptions +common_options(VALUE kwargs) +{ + // The order of the keywords determines the order of the values below. + // If this order is changed, then setting the options below must change as + // well. + ID keywords[] = { + // Required keywords. + rb_intern_const("max_attributes"), + rb_intern_const("max_errors"), + rb_intern_const("max_tree_depth"), + + // Optional keywords. + rb_intern_const("parse_noscript_content_as_text"), + }; + VALUE values[sizeof keywords / sizeof keywords[0]]; + + // Extract the values coresponding to the required keywords. Raise an error + // if required arguments are missing. + rb_get_kwargs(kwargs, keywords, 3, 1, values); + + GumboOptions options = kGumboDefaultOptions; + options.max_attributes = NUM2INT(values[0]); + options.max_errors = NUM2INT(values[1]); + + // handle negative values + int depth = NUM2INT(values[2]); + options.max_tree_depth = depth < 0 ? UINT_MAX : (unsigned int)depth; + + options.parse_noscript_content_as_text = values[3] != Qundef && RTEST(values[3]); + + return options; +} + +static VALUE parse_continue(VALUE parse_args); + +/* + * @!visibility protected + */ +static VALUE +noko_gumbo_s_parse(int argc, VALUE *argv, VALUE _self) +{ + VALUE input, url, klass, kwargs; + + rb_scan_args(argc, argv, "3:", &input, &url, &klass, &kwargs); + if (NIL_P(kwargs)) { + kwargs = rb_hash_new(); + } + + GumboOptions options = common_options(kwargs); + + GumboOutput *output = perform_parse(&options, input); + ParseArgs args = { + .output = output, + .input = input, + .url_or_frag = url, + .klass = klass, + .doc = NULL, + }; + + return rb_ensure(parse_continue, (VALUE)(&args), parse_cleanup, (VALUE)(&args)); +} + +static VALUE +parse_continue(VALUE parse_args) +{ + ParseArgs *args = (ParseArgs *)parse_args; + GumboOutput *output = args->output; + xmlDocPtr doc; + if (output->document->v.document.has_doctype) { + const char *name = output->document->v.document.name; + const char *public = output->document->v.document.public_identifier; + const char *system = output->document->v.document.system_identifier; + public = public[0] ? public : NULL; + system = system[0] ? system : NULL; + doc = new_html_doc(name, system, public); + } else { + doc = new_html_doc(NULL, NULL, NULL); + } + args->doc = doc; // Make sure doc gets cleaned up if an error is thrown. + build_tree(doc, (xmlNodePtr)doc, output->document); + VALUE rdoc = noko_xml_document_wrap(args->klass, doc); + rb_iv_set(rdoc, "@url", args->url_or_frag); + rb_iv_set(rdoc, "@quirks_mode", INT2NUM(output->document->v.document.doc_type_quirks_mode)); + args->doc = NULL; // The Ruby runtime now owns doc so don't delete it. + add_errors(output, rdoc, args->input, args->url_or_frag); + return rdoc; +} + +static int +lookup_namespace(VALUE node, bool require_known_ns) +{ + ID namespace, href; + CONST_ID(namespace, "namespace"); + CONST_ID(href, "href"); + VALUE ns = rb_funcall(node, namespace, 0); + + if (NIL_P(ns)) { + return GUMBO_NAMESPACE_HTML; + } + ns = rb_funcall(ns, href, 0); + assert(RTEST(ns)); + Check_Type(ns, T_STRING); + + const char *href_ptr = RSTRING_PTR(ns); + size_t href_len = (size_t)RSTRING_LEN(ns); +#define NAMESPACE_P(uri) (href_len == sizeof uri - 1 && !memcmp(href_ptr, uri, href_len)) + if (NAMESPACE_P("http://www.w3.org/1999/xhtml")) { + return GUMBO_NAMESPACE_HTML; + } + if (NAMESPACE_P("http://www.w3.org/1998/Math/MathML")) { + return GUMBO_NAMESPACE_MATHML; + } + if (NAMESPACE_P("http://www.w3.org/2000/svg")) { + return GUMBO_NAMESPACE_SVG; + } +#undef NAMESPACE_P + if (require_known_ns) { + rb_raise(rb_eArgError, "Unexpected namespace URI \"%*s\"", (int)href_len, href_ptr); + } + return -1; +} + +static xmlNodePtr +extract_xml_node(VALUE node) +{ + xmlNodePtr xml_node; + Noko_Node_Get_Struct(node, xmlNode, xml_node); + return xml_node; +} + +static VALUE fragment_continue(VALUE parse_args); + +/* + * @!visibility protected + */ +static VALUE +noko_gumbo_s_fragment(int argc, VALUE *argv, VALUE _self) +{ + VALUE doc_fragment; + VALUE tags; + VALUE ctx; + VALUE kwargs; + ID name = rb_intern_const("name"); + const char *ctx_tag; + GumboNamespaceEnum ctx_ns; + GumboQuirksModeEnum quirks_mode; + bool form = false; + const char *encoding = NULL; + + rb_scan_args(argc, argv, "3:", &doc_fragment, &tags, &ctx, &kwargs); + if (NIL_P(kwargs)) { + kwargs = rb_hash_new(); + } + + GumboOptions options = common_options(kwargs); + + if (NIL_P(ctx)) { + ctx_tag = "body"; + ctx_ns = GUMBO_NAMESPACE_HTML; + } else if (TYPE(ctx) == T_STRING) { + ctx_tag = StringValueCStr(ctx); + ctx_ns = GUMBO_NAMESPACE_HTML; + size_t len = (size_t)RSTRING_LEN(ctx); + const char *colon = memchr(ctx_tag, ':', len); + if (colon) { + switch (colon - ctx_tag) { + case 3: + if (st_strncasecmp(ctx_tag, "svg", 3) != 0) { + goto error; + } + ctx_ns = GUMBO_NAMESPACE_SVG; + break; + case 4: + if (st_strncasecmp(ctx_tag, "html", 4) == 0) { + ctx_ns = GUMBO_NAMESPACE_HTML; + } else if (st_strncasecmp(ctx_tag, "math", 4) == 0) { + ctx_ns = GUMBO_NAMESPACE_MATHML; + } else { + goto error; + } + break; + default: +error: + rb_raise(rb_eArgError, "Invalid context namespace '%*s'", (int)(colon - ctx_tag), ctx_tag); + } + ctx_tag = colon + 1; + } else { + // For convenience, put 'svg' and 'math' in their namespaces. + if (len == 3 && st_strncasecmp(ctx_tag, "svg", 3) == 0) { + ctx_ns = GUMBO_NAMESPACE_SVG; + } else if (len == 4 && st_strncasecmp(ctx_tag, "math", 4) == 0) { + ctx_ns = GUMBO_NAMESPACE_MATHML; + } + } + + // Check if it's a form. + form = ctx_ns == GUMBO_NAMESPACE_HTML && st_strcasecmp(ctx_tag, "form") == 0; + } else { + ID element_ = rb_intern_const("element?"); + + // Context fragment name. + VALUE tag_name = rb_funcall(ctx, name, 0); + assert(RTEST(tag_name)); + Check_Type(tag_name, T_STRING); + ctx_tag = StringValueCStr(tag_name); + + // Context fragment namespace. + ctx_ns = lookup_namespace(ctx, true); + + // Check for a form ancestor, including self. + for (VALUE node = ctx; + !NIL_P(node); + node = rb_respond_to(node, parent) ? rb_funcall(node, parent, 0) : Qnil) { + if (!RTEST(rb_funcall(node, element_, 0))) { + continue; + } + VALUE element_name = rb_funcall(node, name, 0); + if (RSTRING_LEN(element_name) == 4 + && !st_strcasecmp(RSTRING_PTR(element_name), "form") + && lookup_namespace(node, false) == GUMBO_NAMESPACE_HTML) { + form = true; + break; + } + } + + // Encoding. + if (ctx_ns == GUMBO_NAMESPACE_MATHML + && RSTRING_LEN(tag_name) == 14 + && !st_strcasecmp(ctx_tag, "annotation-xml")) { + VALUE enc = rb_funcall(ctx, rb_intern_const("[]"), + 1, + rb_utf8_str_new_static("encoding", 8)); + if (RTEST(enc)) { + Check_Type(enc, T_STRING); + encoding = StringValueCStr(enc); + } + } + } + + // Quirks mode. + VALUE doc = rb_funcall(doc_fragment, rb_intern_const("document"), 0); + VALUE dtd = rb_funcall(doc, internal_subset, 0); + VALUE doc_quirks_mode = rb_iv_get(doc, "@quirks_mode"); + if (NIL_P(ctx) || (TYPE(ctx) == T_STRING) || NIL_P(doc_quirks_mode)) { + quirks_mode = GUMBO_DOCTYPE_NO_QUIRKS; + } else if (NIL_P(dtd)) { + quirks_mode = GUMBO_DOCTYPE_QUIRKS; + } else { + VALUE dtd_name = rb_funcall(dtd, name, 0); + VALUE pubid = rb_funcall(dtd, rb_intern_const("external_id"), 0); + VALUE sysid = rb_funcall(dtd, rb_intern_const("system_id"), 0); + quirks_mode = gumbo_compute_quirks_mode( + NIL_P(dtd_name) ? NULL : StringValueCStr(dtd_name), + NIL_P(pubid) ? NULL : StringValueCStr(pubid), + NIL_P(sysid) ? NULL : StringValueCStr(sysid) + ); + } + + // Perform a fragment parse. + options.fragment_context = ctx_tag; + options.fragment_namespace = ctx_ns; + options.fragment_encoding = encoding; + options.quirks_mode = quirks_mode; + options.fragment_context_has_form_ancestor = form; + + // Add one to the max tree depth to account for the HTML element. + if (options.max_tree_depth < UINT_MAX) { options.max_tree_depth++; } + + GumboOutput *output = perform_parse(&options, tags); + ParseArgs args = { + .output = output, + .input = tags, + .url_or_frag = doc_fragment, + .doc = (xmlDocPtr)extract_xml_node(doc), + }; + rb_ensure(fragment_continue, (VALUE)(&args), parse_cleanup, (VALUE)(&args)); + return Qnil; +} + +static VALUE +fragment_continue(VALUE parse_args) +{ + ParseArgs *args = (ParseArgs *)parse_args; + GumboOutput *output = args->output; + VALUE doc_fragment = args->url_or_frag; + xmlDocPtr xml_doc = args->doc; + + args->doc = NULL; // The Ruby runtime owns doc so make sure we don't delete it. + xmlNodePtr xml_frag = extract_xml_node(doc_fragment); + build_tree(xml_doc, xml_frag, output->root); + rb_iv_set(doc_fragment, "@quirks_mode", INT2NUM(output->document->v.document.doc_type_quirks_mode)); + add_errors(output, doc_fragment, args->input, rb_utf8_str_new_static("#fragment", 9)); + return Qnil; +} + +// Initialize the Nokogumbo class and fetch constants we will use later. +void +noko_init_gumbo(void) +{ + // Class constants. + cNokogiriHtml5Document = rb_define_class_under(mNokogiriHtml5, "Document", cNokogiriHtml4Document); + rb_gc_register_mark_object(cNokogiriHtml5Document); + + // Interned symbols. + internal_subset = rb_intern_const("internal_subset"); + parent = rb_intern_const("parent"); + + // Define Nokogumbo module with parse and fragment methods. + rb_define_singleton_method(mNokogiriGumbo, "parse", noko_gumbo_s_parse, -1); + rb_define_singleton_method(mNokogiriGumbo, "fragment", noko_gumbo_s_fragment, -1); +} + +// vim: set shiftwidth=2 softtabstop=2 tabstop=8 expandtab: diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_document.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_document.c new file mode 100644 index 00000000..e3e0ee08 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_document.c @@ -0,0 +1,171 @@ +#include + +VALUE cNokogiriHtml4Document ; + +static ID id_encoding_found; +static ID id_to_s; + +/* + * call-seq: + * new(uri=nil, external_id=nil) → HTML4::Document + * + * Create a new empty document with base URI +uri+ and external ID +external_id+. + */ +static VALUE +rb_html_document_s_new(int argc, VALUE *argv, VALUE klass) +{ + VALUE uri, external_id, rest, rb_doc; + htmlDocPtr doc; + + rb_scan_args(argc, argv, "0*", &rest); + uri = rb_ary_entry(rest, (long)0); + external_id = rb_ary_entry(rest, (long)1); + + doc = htmlNewDoc( + RTEST(uri) ? (const xmlChar *)StringValueCStr(uri) : NULL, + RTEST(external_id) ? (const xmlChar *)StringValueCStr(external_id) : NULL + ); + rb_doc = noko_xml_document_wrap_with_init_args(klass, doc, argc, argv); + return rb_doc ; +} + +/* + * call-seq: + * read_io(io, url, encoding, options) + * + * Read the HTML document from +io+ with given +url+, +encoding+, + * and +options+. See Nokogiri::HTML4.parse + */ +static VALUE +rb_html_document_s_read_io(VALUE klass, VALUE rb_io, VALUE rb_url, VALUE rb_encoding, VALUE rb_options) +{ + VALUE rb_doc; + VALUE rb_error_list = rb_ary_new(); + htmlDocPtr c_doc; + const char *c_url = NIL_P(rb_url) ? NULL : StringValueCStr(rb_url); + const char *c_encoding = NIL_P(rb_encoding) ? NULL : StringValueCStr(rb_encoding); + int options = NUM2INT(rb_options); + + xmlSetStructuredErrorFunc((void *)rb_error_list, noko__error_array_pusher); + + c_doc = htmlReadIO(noko_io_read, noko_io_close, (void *)rb_io, c_url, c_encoding, options); + + xmlSetStructuredErrorFunc(NULL, NULL); + + /* + * If EncodingFound has occurred in EncodingReader, make sure to do + * a cleanup and propagate the error. + */ + if (rb_respond_to(rb_io, id_encoding_found)) { + VALUE encoding_found = rb_funcall(rb_io, id_encoding_found, 0); + if (!NIL_P(encoding_found)) { + xmlFreeDoc(c_doc); + rb_exc_raise(encoding_found); + } + } + + if ((c_doc == NULL) || (!(options & XML_PARSE_RECOVER) && (RARRAY_LEN(rb_error_list) > 0))) { + VALUE rb_error ; + + xmlFreeDoc(c_doc); + + rb_error = rb_ary_entry(rb_error_list, 0); + if (rb_error == Qnil) { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } else { + VALUE exception_message = rb_funcall(rb_error, id_to_s, 0); + exception_message = rb_str_concat(rb_str_new2("Parser without recover option encountered error or warning: "), + exception_message); + rb_exc_raise(rb_class_new_instance(1, &exception_message, cNokogiriXmlSyntaxError)); + } + + return Qnil; + } + + rb_doc = noko_xml_document_wrap(klass, c_doc); + rb_iv_set(rb_doc, "@errors", rb_error_list); + return rb_doc; +} + +/* + * call-seq: + * read_memory(string, url, encoding, options) + * + * Read the HTML document contained in +string+ with given +url+, +encoding+, + * and +options+. See Nokogiri::HTML4.parse + */ +static VALUE +rb_html_document_s_read_memory(VALUE klass, VALUE rb_html, VALUE rb_url, VALUE rb_encoding, VALUE rb_options) +{ + VALUE rb_doc; + VALUE rb_error_list = rb_ary_new(); + htmlDocPtr c_doc; + const char *c_buffer = StringValuePtr(rb_html); + const char *c_url = NIL_P(rb_url) ? NULL : StringValueCStr(rb_url); + const char *c_encoding = NIL_P(rb_encoding) ? NULL : StringValueCStr(rb_encoding); + int html_len = (int)RSTRING_LEN(rb_html); + int options = NUM2INT(rb_options); + + xmlSetStructuredErrorFunc((void *)rb_error_list, noko__error_array_pusher); + + c_doc = htmlReadMemory(c_buffer, html_len, c_url, c_encoding, options); + + xmlSetStructuredErrorFunc(NULL, NULL); + + if ((c_doc == NULL) || (!(options & XML_PARSE_RECOVER) && (RARRAY_LEN(rb_error_list) > 0))) { + VALUE rb_error ; + + xmlFreeDoc(c_doc); + + rb_error = rb_ary_entry(rb_error_list, 0); + if (rb_error == Qnil) { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } else { + VALUE exception_message = rb_funcall(rb_error, id_to_s, 0); + exception_message = rb_str_concat(rb_str_new2("Parser without recover option encountered error or warning: "), + exception_message); + rb_exc_raise(rb_class_new_instance(1, &exception_message, cNokogiriXmlSyntaxError)); + } + + return Qnil; + } + + rb_doc = noko_xml_document_wrap(klass, c_doc); + rb_iv_set(rb_doc, "@errors", rb_error_list); + return rb_doc; +} + +/* + * call-seq: + * type + * + * The type for this document + */ +static VALUE +rb_html_document_type(VALUE self) +{ + htmlDocPtr doc = noko_xml_document_unwrap(self); + return INT2NUM(doc->type); +} + +void +noko_init_html_document(void) +{ + /* this is here so that rdoc doesn't ignore this file. */ + /* + mNokogiri = rb_define_module("Nokogiri"); + mNokogiriHtml4 = rb_define_module_under(mNokogiri, "HTML4"); + */ + + assert(cNokogiriXmlDocument); + cNokogiriHtml4Document = rb_define_class_under(mNokogiriHtml4, "Document", cNokogiriXmlDocument); + + rb_define_singleton_method(cNokogiriHtml4Document, "read_memory", rb_html_document_s_read_memory, 4); + rb_define_singleton_method(cNokogiriHtml4Document, "read_io", rb_html_document_s_read_io, 4); + rb_define_singleton_method(cNokogiriHtml4Document, "new", rb_html_document_s_new, -1); + + rb_define_method(cNokogiriHtml4Document, "type", rb_html_document_type, 0); + + id_encoding_found = rb_intern("encoding_found"); + id_to_s = rb_intern("to_s"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_element_description.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_element_description.c new file mode 100644 index 00000000..bd345d1a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_element_description.c @@ -0,0 +1,299 @@ +#include + +static const rb_data_type_t html_elem_desc_type = { + .wrap_struct_name = "htmlElemDesc", + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +VALUE cNokogiriHtml4ElementDescription ; + +/* + * call-seq: + * required_attributes + * + * A list of required attributes for this element + */ +static VALUE +required_attributes(VALUE self) +{ + const htmlElemDesc *description; + VALUE list; + int i; + + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + list = rb_ary_new(); + + if (NULL == description->attrs_req) { return list; } + + for (i = 0; description->attrs_depr[i]; i++) { + rb_ary_push(list, NOKOGIRI_STR_NEW2(description->attrs_req[i])); + } + + return list; +} + +/* + * call-seq: + * deprecated_attributes + * + * A list of deprecated attributes for this element + */ +static VALUE +deprecated_attributes(VALUE self) +{ + const htmlElemDesc *description; + VALUE list; + int i; + + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + list = rb_ary_new(); + + if (NULL == description->attrs_depr) { return list; } + + for (i = 0; description->attrs_depr[i]; i++) { + rb_ary_push(list, NOKOGIRI_STR_NEW2(description->attrs_depr[i])); + } + + return list; +} + +/* + * call-seq: + * optional_attributes + * + * A list of optional attributes for this element + */ +static VALUE +optional_attributes(VALUE self) +{ + const htmlElemDesc *description; + VALUE list; + int i; + + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + list = rb_ary_new(); + + if (NULL == description->attrs_opt) { return list; } + + for (i = 0; description->attrs_opt[i]; i++) { + rb_ary_push(list, NOKOGIRI_STR_NEW2(description->attrs_opt[i])); + } + + return list; +} + +/* + * call-seq: + * default_sub_element + * + * The default sub element for this element + */ +static VALUE +default_sub_element(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->defaultsubelt) { + return NOKOGIRI_STR_NEW2(description->defaultsubelt); + } + + return Qnil; +} + +/* + * call-seq: + * sub_elements + * + * A list of allowed sub elements for this element. + */ +static VALUE +sub_elements(VALUE self) +{ + const htmlElemDesc *description; + VALUE list; + int i; + + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + list = rb_ary_new(); + + if (NULL == description->subelts) { return list; } + + for (i = 0; description->subelts[i]; i++) { + rb_ary_push(list, NOKOGIRI_STR_NEW2(description->subelts[i])); + } + + return list; +} + +/* + * call-seq: + * description + * + * The description for this element + */ +static VALUE +description(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + return NOKOGIRI_STR_NEW2(description->desc); +} + +/* + * call-seq: + * inline? + * + * Is this element an inline element? + */ +static VALUE +inline_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->isinline) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * deprecated? + * + * Is this element deprecated? + */ +static VALUE +deprecated_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->depr) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * empty? + * + * Is this an empty element? + */ +static VALUE +empty_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->empty) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * save_end_tag? + * + * Should the end tag be saved? + */ +static VALUE +save_end_tag_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->saveEndTag) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * implied_end_tag? + * + * Can the end tag be implied for this tag? + */ +static VALUE +implied_end_tag_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->endTag) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * implied_start_tag? + * + * Can the start tag be implied for this tag? + */ +static VALUE +implied_start_tag_eh(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (description->startTag) { return Qtrue; } + return Qfalse; +} + +/* + * call-seq: + * name + * + * Get the tag name for this ElementDescription + */ +static VALUE +name(VALUE self) +{ + const htmlElemDesc *description; + TypedData_Get_Struct(self, htmlElemDesc, &html_elem_desc_type, description); + + if (NULL == description->name) { return Qnil; } + return NOKOGIRI_STR_NEW2(description->name); +} + +/* + * call-seq: + * [](tag_name) + * + * Get ElementDescription for +tag_name+ + */ +static VALUE +get_description(VALUE klass, VALUE tag_name) +{ + const htmlElemDesc *description = htmlTagLookup( + (const xmlChar *)StringValueCStr(tag_name) + ); + + if (NULL == description) { return Qnil; } + return TypedData_Wrap_Struct(klass, &html_elem_desc_type, DISCARD_CONST_QUAL(void *, description)); +} + +void +noko_init_html_element_description(void) +{ + cNokogiriHtml4ElementDescription = rb_define_class_under(mNokogiriHtml4, "ElementDescription", rb_cObject); + + rb_undef_alloc_func(cNokogiriHtml4ElementDescription); + + rb_define_singleton_method(cNokogiriHtml4ElementDescription, "[]", get_description, 1); + + rb_define_method(cNokogiriHtml4ElementDescription, "name", name, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "implied_start_tag?", implied_start_tag_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "implied_end_tag?", implied_end_tag_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "save_end_tag?", save_end_tag_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "empty?", empty_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "deprecated?", deprecated_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "inline?", inline_eh, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "description", description, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "sub_elements", sub_elements, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "default_sub_element", default_sub_element, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "optional_attributes", optional_attributes, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "deprecated_attributes", deprecated_attributes, 0); + rb_define_method(cNokogiriHtml4ElementDescription, "required_attributes", required_attributes, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_entity_lookup.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_entity_lookup.c new file mode 100644 index 00000000..85ad3842 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_entity_lookup.c @@ -0,0 +1,37 @@ +#include + +static VALUE cNokogiriHtml4EntityLookup; + +/* + * call-seq: + * get(key) + * + * Get the HTML4::EntityDescription for +key+ + */ +static VALUE +get(VALUE _, VALUE rb_entity_name) +{ + VALUE cNokogiriHtml4EntityDescription; + const htmlEntityDesc *c_entity_desc; + VALUE rb_constructor_args[3]; + + c_entity_desc = htmlEntityLookup((const xmlChar *)StringValueCStr(rb_entity_name)); + if (NULL == c_entity_desc) { + return Qnil; + } + + rb_constructor_args[0] = UINT2NUM(c_entity_desc->value); + rb_constructor_args[1] = NOKOGIRI_STR_NEW2(c_entity_desc->name); + rb_constructor_args[2] = NOKOGIRI_STR_NEW2(c_entity_desc->desc); + + cNokogiriHtml4EntityDescription = rb_const_get_at(mNokogiriHtml4, rb_intern("EntityDescription")); + return rb_class_new_instance(3, rb_constructor_args, cNokogiriHtml4EntityDescription); +} + +void +noko_init_html_entity_lookup(void) +{ + cNokogiriHtml4EntityLookup = rb_define_class_under(mNokogiriHtml4, "EntityLookup", rb_cObject); + + rb_define_method(cNokogiriHtml4EntityLookup, "get", get, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser.c new file mode 100644 index 00000000..2316ec2b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser.c @@ -0,0 +1,40 @@ +#include + +VALUE cNokogiriHtml4SaxParser; + +static ID id_start_document; + +static void +noko_html4_sax_parser_start_document(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + xmlSAX2StartDocument(ctx); + + rb_funcall(doc, id_start_document, 0); +} + +static VALUE +noko_html4_sax_parser_initialize(VALUE self) +{ + xmlSAXHandlerPtr handler = noko_xml_sax_parser_unwrap(self); + + rb_call_super(0, NULL); + + handler->startDocument = noko_html4_sax_parser_start_document; + + return self; +} + +void +noko_init_html4_sax_parser(void) +{ + cNokogiriHtml4SaxParser = rb_define_class_under(mNokogiriHtml4Sax, "Parser", cNokogiriXmlSaxParser); + + rb_define_private_method(cNokogiriHtml4SaxParser, "initialize_native", + noko_html4_sax_parser_initialize, 0); + + id_start_document = rb_intern("start_document"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser_context.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser_context.c new file mode 100644 index 00000000..6f971d1f --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_parser_context.c @@ -0,0 +1,98 @@ +#include + +VALUE cNokogiriHtml4SaxParserContext ; + +/* :nodoc: */ +static VALUE +noko_html4_sax_parser_context_s_native_memory(VALUE rb_class, VALUE rb_input, VALUE rb_encoding) +{ + Check_Type(rb_input, T_STRING); + if (!(int)RSTRING_LEN(rb_input)) { + rb_raise(rb_eRuntimeError, "input string cannot be empty"); + } + + if (!NIL_P(rb_encoding) && !rb_obj_is_kind_of(rb_encoding, rb_cEncoding)) { + rb_raise(rb_eTypeError, "argument must be an Encoding object"); + } + + htmlParserCtxtPtr c_context = + htmlCreateMemoryParserCtxt(StringValuePtr(rb_input), (int)RSTRING_LEN(rb_input)); + if (!c_context) { + rb_raise(rb_eRuntimeError, "failed to create xml sax parser context"); + } + + noko_xml_sax_parser_context_set_encoding(c_context, rb_encoding); + + if (c_context->sax) { + xmlFree(c_context->sax); + c_context->sax = NULL; + } + + return noko_xml_sax_parser_context_wrap(rb_class, c_context); +} + +/* :nodoc: */ +static VALUE +noko_html4_sax_parser_context_s_native_file(VALUE rb_class, VALUE rb_filename, VALUE rb_encoding) +{ + if (!NIL_P(rb_encoding) && !rb_obj_is_kind_of(rb_encoding, rb_cEncoding)) { + rb_raise(rb_eTypeError, "argument must be an Encoding object"); + } + + htmlParserCtxtPtr c_context = htmlCreateFileParserCtxt(StringValueCStr(rb_filename), NULL); + if (!c_context) { + rb_raise(rb_eRuntimeError, "failed to create xml sax parser context"); + } + + noko_xml_sax_parser_context_set_encoding(c_context, rb_encoding); + + if (c_context->sax) { + xmlFree(c_context->sax); + c_context->sax = NULL; + } + + return noko_xml_sax_parser_context_wrap(rb_class, c_context); +} + +static VALUE +noko_html4_sax_parser_context__parse_with(VALUE rb_context, VALUE rb_sax_parser) +{ + htmlParserCtxtPtr ctxt; + htmlSAXHandlerPtr sax; + + if (!rb_obj_is_kind_of(rb_sax_parser, cNokogiriXmlSaxParser)) { + rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::SAX::Parser"); + } + + ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + sax = noko_xml_sax_parser_unwrap(rb_sax_parser); + + ctxt->sax = sax; + ctxt->userData = ctxt; /* so we can use libxml2/SAX2.c handlers if we want to */ + ctxt->_private = (void *)rb_sax_parser; + + xmlSetStructuredErrorFunc(NULL, NULL); + + /* although we're calling back into Ruby here, we don't need to worry about exceptions, because we + * don't have any cleanup to do. The only memory we need to free is handled by + * xml_sax_parser_context_type_free */ + htmlParseDocument(ctxt); + + return Qnil; +} + +void +noko_init_html_sax_parser_context(void) +{ + assert(cNokogiriXmlSaxParserContext); + cNokogiriHtml4SaxParserContext = rb_define_class_under(mNokogiriHtml4Sax, "ParserContext", + cNokogiriXmlSaxParserContext); + + rb_define_singleton_method(cNokogiriHtml4SaxParserContext, "native_memory", + noko_html4_sax_parser_context_s_native_memory, 2); + rb_define_singleton_method(cNokogiriHtml4SaxParserContext, "native_file", + noko_html4_sax_parser_context_s_native_file, 2); + + rb_define_method(cNokogiriHtml4SaxParserContext, "parse_with", + noko_html4_sax_parser_context__parse_with, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_push_parser.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_push_parser.c new file mode 100644 index 00000000..845baf0b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/html4_sax_push_parser.c @@ -0,0 +1,96 @@ +#include + +VALUE cNokogiriHtml4SaxPushParser; + +/* + * Write +chunk+ to PushParser. +last_chunk+ triggers the end_document handle + */ +static VALUE +noko_html4_sax_push_parser__native_write(VALUE self, VALUE rb_chunk, VALUE rb_last_chunk) +{ + xmlParserCtxtPtr ctx; + const char *chunk = NULL; + int size = 0; + int status = 0; + libxmlStructuredErrorHandlerState handler_state; + + ctx = noko_xml_sax_push_parser_unwrap(self); + + if (Qnil != rb_chunk) { + chunk = StringValuePtr(rb_chunk); + size = (int)RSTRING_LEN(rb_chunk); + } + + noko__structured_error_func_save_and_set(&handler_state, NULL, NULL); + + status = htmlParseChunk(ctx, chunk, size, Qtrue == rb_last_chunk ? 1 : 0); + + noko__structured_error_func_restore(&handler_state); + + if ((status != 0) && !(xmlCtxtGetOptions(ctx) & XML_PARSE_RECOVER)) { + // TODO: there appear to be no tests for this block + xmlErrorConstPtr e = xmlCtxtGetLastError(ctx); + noko__error_raise(NULL, e); + } + + return self; +} + +/* + * Initialize the push parser with +xml_sax+ using +filename+ + */ +static VALUE +noko_html4_sax_push_parser__initialize_native( + VALUE self, + VALUE rb_xml_sax, + VALUE rb_filename, + VALUE encoding +) +{ + htmlSAXHandlerPtr sax; + const char *filename = NULL; + htmlParserCtxtPtr ctx; + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + + sax = noko_xml_sax_parser_unwrap(rb_xml_sax); + + if (rb_filename != Qnil) { filename = StringValueCStr(rb_filename); } + + if (!NIL_P(encoding)) { + enc = xmlParseCharEncoding(StringValueCStr(encoding)); + if (enc == XML_CHAR_ENCODING_ERROR) { + rb_raise(rb_eArgError, "Unsupported Encoding"); + } + } + + ctx = htmlCreatePushParserCtxt( + sax, + NULL, + NULL, + 0, + filename, + enc + ); + if (ctx == NULL) { + rb_raise(rb_eRuntimeError, "Could not create a parser context"); + } + + ctx->userData = ctx; + ctx->_private = (void *)rb_xml_sax; + + DATA_PTR(self) = ctx; + return self; +} + +void +noko_init_html_sax_push_parser(void) +{ + assert(cNokogiriXmlSaxPushParser); + cNokogiriHtml4SaxPushParser = + rb_define_class_under(mNokogiriHtml4Sax, "PushParser", cNokogiriXmlSaxPushParser); + + rb_define_private_method(cNokogiriHtml4SaxPushParser, "initialize_native", + noko_html4_sax_push_parser__initialize_native, 3); + rb_define_private_method(cNokogiriHtml4SaxPushParser, "native_write", + noko_html4_sax_push_parser__native_write, 2); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exslt.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exslt.h new file mode 100644 index 00000000..dfbd09be --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exslt.h @@ -0,0 +1,108 @@ +/* + * Summary: main header file + * + * Copy: See Copyright for the status of this software. + */ + + +#ifndef __EXSLT_H__ +#define __EXSLT_H__ + +#include +#include +#include "exsltexports.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXSLTPUBVAR const char *exsltLibraryVersion; +EXSLTPUBVAR const int exsltLibexsltVersion; +EXSLTPUBVAR const int exsltLibxsltVersion; +EXSLTPUBVAR const int exsltLibxmlVersion; + +/** + * EXSLT_COMMON_NAMESPACE: + * + * Namespace for EXSLT common functions + */ +#define EXSLT_COMMON_NAMESPACE ((const xmlChar *) "http://exslt.org/common") +/** + * EXSLT_CRYPTO_NAMESPACE: + * + * Namespace for EXSLT crypto functions + */ +#define EXSLT_CRYPTO_NAMESPACE ((const xmlChar *) "http://exslt.org/crypto") +/** + * EXSLT_MATH_NAMESPACE: + * + * Namespace for EXSLT math functions + */ +#define EXSLT_MATH_NAMESPACE ((const xmlChar *) "http://exslt.org/math") +/** + * EXSLT_SETS_NAMESPACE: + * + * Namespace for EXSLT set functions + */ +#define EXSLT_SETS_NAMESPACE ((const xmlChar *) "http://exslt.org/sets") +/** + * EXSLT_FUNCTIONS_NAMESPACE: + * + * Namespace for EXSLT functions extension functions + */ +#define EXSLT_FUNCTIONS_NAMESPACE ((const xmlChar *) "http://exslt.org/functions") +/** + * EXSLT_STRINGS_NAMESPACE: + * + * Namespace for EXSLT strings functions + */ +#define EXSLT_STRINGS_NAMESPACE ((const xmlChar *) "http://exslt.org/strings") +/** + * EXSLT_DATE_NAMESPACE: + * + * Namespace for EXSLT date functions + */ +#define EXSLT_DATE_NAMESPACE ((const xmlChar *) "http://exslt.org/dates-and-times") +/** + * EXSLT_DYNAMIC_NAMESPACE: + * + * Namespace for EXSLT dynamic functions + */ +#define EXSLT_DYNAMIC_NAMESPACE ((const xmlChar *) "http://exslt.org/dynamic") + +/** + * SAXON_NAMESPACE: + * + * Namespace for SAXON extensions functions + */ +#define SAXON_NAMESPACE ((const xmlChar *) "http://icl.com/saxon") + +EXSLTPUBFUN void EXSLTCALL exsltCommonRegister (void); +#ifdef EXSLT_CRYPTO_ENABLED +EXSLTPUBFUN void EXSLTCALL exsltCryptoRegister (void); +#endif +EXSLTPUBFUN void EXSLTCALL exsltMathRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltSetsRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltFuncRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltStrRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltDateRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltSaxonRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltDynRegister(void); + +EXSLTPUBFUN void EXSLTCALL exsltRegisterAll (void); + +EXSLTPUBFUN int EXSLTCALL exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); + +#ifdef __cplusplus +} +#endif +#endif /* __EXSLT_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltconfig.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltconfig.h new file mode 100644 index 00000000..62aa98cb --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltconfig.h @@ -0,0 +1,70 @@ +/* + * exsltconfig.h: compile-time version information for the EXSLT library + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#ifndef __XML_EXSLTCONFIG_H__ +#define __XML_EXSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBEXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBEXSLT_DOTTED_VERSION "0.8.23" + +/** + * LIBEXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBEXSLT_VERSION 823 + +/** + * LIBEXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBEXSLT_VERSION_STRING "823" + +/** + * LIBEXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBEXSLT_VERSION_EXTRA "" + +/** + * WITH_CRYPTO: + * + * Whether crypto support is configured into exslt + */ +#if 0 +#define EXSLT_CRYPTO_ENABLED +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * This macro is used to flag unused function parameters to GCC + */ +#ifdef __GNUC__ +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_EXSLTCONFIG_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltexports.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltexports.h new file mode 100644 index 00000000..ee79ec7a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libexslt/exsltexports.h @@ -0,0 +1,63 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __EXSLT_EXPORTS_H__ +#define __EXSLT_EXPORTS_H__ + +#if defined(_WIN32) || defined(__CYGWIN__) +/** DOC_DISABLE */ + +#ifdef LIBEXSLT_STATIC + #define EXSLTPUBLIC +#elif defined(IN_LIBEXSLT) + #define EXSLTPUBLIC __declspec(dllexport) +#else + #define EXSLTPUBLIC __declspec(dllimport) +#endif + +#define EXSLTCALL __cdecl + +/** DOC_ENABLE */ +#else /* not Windows */ + +/** + * EXSLTPUBLIC: + * + * Macro which declares a public symbol + */ +#define EXSLTPUBLIC + +/** + * EXSLTCALL: + * + * Macro which declares the calling convention for exported functions + */ +#define EXSLTCALL + +#endif /* platform switch */ + +/* + * EXSLTPUBFUN: + * + * Macro which declares an exportable function + */ +#define EXSLTPUBFUN EXSLTPUBLIC + +/** + * EXSLTPUBVAR: + * + * Macro which declares an exportable variable + */ +#define EXSLTPUBVAR EXSLTPUBLIC extern + +/* Compatibility */ +#if !defined(LIBEXSLT_PUBLIC) +#define LIBEXSLT_PUBLIC EXSLTPUBVAR +#endif + +#endif /* __EXSLT_EXPORTS_H__ */ + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLparser.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLparser.h new file mode 100644 index 00000000..7be3d2b8 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLparser.h @@ -0,0 +1,336 @@ +/* + * Summary: interface for an HTML 4.0 non-verifying parser + * Description: this module implements an HTML 4.0 non-verifying parser + * with API compatible with the XML parser ones. It should + * be able to parse "real world" HTML, even if severely + * broken from a specification point of view. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_PARSER_H__ +#define __HTML_PARSER_H__ +#include +#include + +#ifdef LIBXML_HTML_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Most of the back-end structures from XML and HTML are shared. + */ +typedef xmlParserCtxt htmlParserCtxt; +typedef xmlParserCtxtPtr htmlParserCtxtPtr; +typedef xmlParserNodeInfo htmlParserNodeInfo; +typedef xmlSAXHandler htmlSAXHandler; +typedef xmlSAXHandlerPtr htmlSAXHandlerPtr; +typedef xmlParserInput htmlParserInput; +typedef xmlParserInputPtr htmlParserInputPtr; +typedef xmlDocPtr htmlDocPtr; +typedef xmlNodePtr htmlNodePtr; + +/* + * Internal description of an HTML element, representing HTML 4.01 + * and XHTML 1.0 (which share the same structure). + */ +typedef struct _htmlElemDesc htmlElemDesc; +typedef htmlElemDesc *htmlElemDescPtr; +struct _htmlElemDesc { + const char *name; /* The tag name */ + char startTag; /* Whether the start tag can be implied */ + char endTag; /* Whether the end tag can be implied */ + char saveEndTag; /* Whether the end tag should be saved */ + char empty; /* Is this an empty element ? */ + char depr; /* Is this a deprecated element ? */ + char dtd; /* 1: only in Loose DTD, 2: only Frameset one */ + char isinline; /* is this a block 0 or inline 1 element */ + const char *desc; /* the description */ + +/* NRK Jan.2003 + * New fields encapsulating HTML structure + * + * Bugs: + * This is a very limited representation. It fails to tell us when + * an element *requires* subelements (we only have whether they're + * allowed or not), and it doesn't tell us where CDATA and PCDATA + * are allowed. Some element relationships are not fully represented: + * these are flagged with the word MODIFIER + */ + const char** subelts; /* allowed sub-elements of this element */ + const char* defaultsubelt; /* subelement for suggested auto-repair + if necessary or NULL */ + const char** attrs_opt; /* Optional Attributes */ + const char** attrs_depr; /* Additional deprecated attributes */ + const char** attrs_req; /* Required attributes */ +}; + +/* + * Internal description of an HTML entity. + */ +typedef struct _htmlEntityDesc htmlEntityDesc; +typedef htmlEntityDesc *htmlEntityDescPtr; +struct _htmlEntityDesc { + unsigned int value; /* the UNICODE value for the character */ + const char *name; /* The entity name */ + const char *desc; /* the description */ +}; + +#ifdef LIBXML_SAX1_ENABLED + +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 htmlDefaultSAXHandler; + +#ifdef LIBXML_THREAD_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__htmlDefaultSAXHandler(void); +#endif + +#endif /* LIBXML_SAX1_ENABLED */ + +/* + * There is only few public functions. + */ +XML_DEPRECATED +XMLPUBFUN void + htmlInitAutoClose (void); +XMLPUBFUN const htmlElemDesc * + htmlTagLookup (const xmlChar *tag); +XMLPUBFUN const htmlEntityDesc * + htmlEntityLookup(const xmlChar *name); +XMLPUBFUN const htmlEntityDesc * + htmlEntityValueLookup(unsigned int value); + +XMLPUBFUN int + htmlIsAutoClosed(htmlDocPtr doc, + htmlNodePtr elem); +XMLPUBFUN int + htmlAutoCloseTag(htmlDocPtr doc, + const xmlChar *name, + htmlNodePtr elem); +XML_DEPRECATED +XMLPUBFUN const htmlEntityDesc * + htmlParseEntityRef(htmlParserCtxtPtr ctxt, + const xmlChar **str); +XML_DEPRECATED +XMLPUBFUN int + htmlParseCharRef(htmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + htmlParseElement(htmlParserCtxtPtr ctxt); + +XMLPUBFUN htmlParserCtxtPtr + htmlNewParserCtxt(void); +XMLPUBFUN htmlParserCtxtPtr + htmlNewSAXParserCtxt(const htmlSAXHandler *sax, + void *userData); + +XMLPUBFUN htmlParserCtxtPtr + htmlCreateMemoryParserCtxt(const char *buffer, + int size); + +XMLPUBFUN int + htmlParseDocument(htmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN htmlDocPtr + htmlSAXParseDoc (const xmlChar *cur, + const char *encoding, + htmlSAXHandlerPtr sax, + void *userData); +XMLPUBFUN htmlDocPtr + htmlParseDoc (const xmlChar *cur, + const char *encoding); +XMLPUBFUN htmlParserCtxtPtr + htmlCreateFileParserCtxt(const char *filename, + const char *encoding); +XML_DEPRECATED +XMLPUBFUN htmlDocPtr + htmlSAXParseFile(const char *filename, + const char *encoding, + htmlSAXHandlerPtr sax, + void *userData); +XMLPUBFUN htmlDocPtr + htmlParseFile (const char *filename, + const char *encoding); +XMLPUBFUN int + UTF8ToHtml (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +XMLPUBFUN int + htmlEncodeEntities(unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen, int quoteChar); +XMLPUBFUN int + htmlIsScriptAttribute(const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN int + htmlHandleOmittedElem(int val); + +#ifdef LIBXML_PUSH_ENABLED +/** + * Interfaces for the Push mode. + */ +XMLPUBFUN htmlParserCtxtPtr + htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename, + xmlCharEncoding enc); +XMLPUBFUN int + htmlParseChunk (htmlParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +#endif /* LIBXML_PUSH_ENABLED */ + +XMLPUBFUN void + htmlFreeParserCtxt (htmlParserCtxtPtr ctxt); + +/* + * New set of simpler/more flexible APIs + */ +/** + * xmlParserOption: + * + * This is the set of XML parser options that can be passed down + * to the xmlReadDoc() and similar calls. + */ +typedef enum { + HTML_PARSE_RECOVER = 1<<0, /* Relaxed parsing */ + HTML_PARSE_NODEFDTD = 1<<2, /* do not default a doctype if not found */ + HTML_PARSE_NOERROR = 1<<5, /* suppress error reports */ + HTML_PARSE_NOWARNING= 1<<6, /* suppress warning reports */ + HTML_PARSE_PEDANTIC = 1<<7, /* pedantic error reporting */ + HTML_PARSE_NOBLANKS = 1<<8, /* remove blank nodes */ + HTML_PARSE_NONET = 1<<11,/* Forbid network access */ + HTML_PARSE_NOIMPLIED= 1<<13,/* Do not add implied html/body... elements */ + HTML_PARSE_COMPACT = 1<<16,/* compact small text nodes */ + HTML_PARSE_IGNORE_ENC=1<<21 /* ignore internal document encoding hint */ +} htmlParserOption; + +XMLPUBFUN void + htmlCtxtReset (htmlParserCtxtPtr ctxt); +XMLPUBFUN int + htmlCtxtUseOptions (htmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN htmlDocPtr + htmlReadDoc (const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlReadFile (const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlReadMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlReadFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlReadIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlCtxtParseDocument (htmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN htmlDocPtr + htmlCtxtReadDoc (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlCtxtReadFile (xmlParserCtxtPtr ctxt, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlCtxtReadMemory (xmlParserCtxtPtr ctxt, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlCtxtReadFd (xmlParserCtxtPtr ctxt, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr + htmlCtxtReadIO (xmlParserCtxtPtr ctxt, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +/* NRK/Jan2003: further knowledge of HTML structure + */ +typedef enum { + HTML_NA = 0 , /* something we don't check at all */ + HTML_INVALID = 0x1 , + HTML_DEPRECATED = 0x2 , + HTML_VALID = 0x4 , + HTML_REQUIRED = 0xc /* VALID bit set so ( & HTML_VALID ) is TRUE */ +} htmlStatus ; + +/* Using htmlElemDesc rather than name here, to emphasise the fact + that otherwise there's a lookup overhead +*/ +XMLPUBFUN htmlStatus htmlAttrAllowed(const htmlElemDesc*, const xmlChar*, int) ; +XMLPUBFUN int htmlElementAllowedHere(const htmlElemDesc*, const xmlChar*) ; +XMLPUBFUN htmlStatus htmlElementStatusHere(const htmlElemDesc*, const htmlElemDesc*) ; +XMLPUBFUN htmlStatus htmlNodeStatus(htmlNodePtr, int) ; +/** + * htmlDefaultSubelement: + * @elt: HTML element + * + * Returns the default subelement for this element + */ +#define htmlDefaultSubelement(elt) elt->defaultsubelt +/** + * htmlElementAllowedHereDesc: + * @parent: HTML parent element + * @elt: HTML element + * + * Checks whether an HTML element description may be a + * direct child of the specified element. + * + * Returns 1 if allowed; 0 otherwise. + */ +#define htmlElementAllowedHereDesc(parent,elt) \ + htmlElementAllowedHere((parent), (elt)->name) +/** + * htmlRequiredAttrs: + * @elt: HTML element + * + * Returns the attributes required for the specified element. + */ +#define htmlRequiredAttrs(elt) (elt)->attrs_req + + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTML_ENABLED */ +#endif /* __HTML_PARSER_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLtree.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLtree.h new file mode 100644 index 00000000..8e1ba90e --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/HTMLtree.h @@ -0,0 +1,147 @@ +/* + * Summary: specific APIs to process HTML tree, especially serialization + * Description: this module implements a few function needed to process + * tree in an HTML specific way. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_TREE_H__ +#define __HTML_TREE_H__ + +#include +#include +#include +#include + +#ifdef LIBXML_HTML_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * HTML_TEXT_NODE: + * + * Macro. A text node in a HTML document is really implemented + * the same way as a text node in an XML document. + */ +#define HTML_TEXT_NODE XML_TEXT_NODE +/** + * HTML_ENTITY_REF_NODE: + * + * Macro. An entity reference in a HTML document is really implemented + * the same way as an entity reference in an XML document. + */ +#define HTML_ENTITY_REF_NODE XML_ENTITY_REF_NODE +/** + * HTML_COMMENT_NODE: + * + * Macro. A comment in a HTML document is really implemented + * the same way as a comment in an XML document. + */ +#define HTML_COMMENT_NODE XML_COMMENT_NODE +/** + * HTML_PRESERVE_NODE: + * + * Macro. A preserved node in a HTML document is really implemented + * the same way as a CDATA section in an XML document. + */ +#define HTML_PRESERVE_NODE XML_CDATA_SECTION_NODE +/** + * HTML_PI_NODE: + * + * Macro. A processing instruction in a HTML document is really implemented + * the same way as a processing instruction in an XML document. + */ +#define HTML_PI_NODE XML_PI_NODE + +XMLPUBFUN htmlDocPtr + htmlNewDoc (const xmlChar *URI, + const xmlChar *ExternalID); +XMLPUBFUN htmlDocPtr + htmlNewDocNoDtD (const xmlChar *URI, + const xmlChar *ExternalID); +XMLPUBFUN const xmlChar * + htmlGetMetaEncoding (htmlDocPtr doc); +XMLPUBFUN int + htmlSetMetaEncoding (htmlDocPtr doc, + const xmlChar *encoding); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + htmlDocDumpMemory (xmlDocPtr cur, + xmlChar **mem, + int *size); +XMLPUBFUN void + htmlDocDumpMemoryFormat (xmlDocPtr cur, + xmlChar **mem, + int *size, + int format); +XMLPUBFUN int + htmlDocDump (FILE *f, + xmlDocPtr cur); +XMLPUBFUN int + htmlSaveFile (const char *filename, + xmlDocPtr cur); +XMLPUBFUN int + htmlNodeDump (xmlBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN void + htmlNodeDumpFile (FILE *out, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN int + htmlNodeDumpFileFormat (FILE *out, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding, + int format); +XMLPUBFUN int + htmlSaveFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN int + htmlSaveFileFormat (const char *filename, + xmlDocPtr cur, + const char *encoding, + int format); + +XMLPUBFUN void + htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding, + int format); +XMLPUBFUN void + htmlDocContentDumpOutput(xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN void + htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding, + int format); +XMLPUBFUN void + htmlNodeDumpOutput (xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding); + +#endif /* LIBXML_OUTPUT_ENABLED */ + +XMLPUBFUN int + htmlIsBooleanAttr (const xmlChar *name); + + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTML_ENABLED */ + +#endif /* __HTML_TREE_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX.h new file mode 100644 index 00000000..eea1057b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX.h @@ -0,0 +1,202 @@ +/* + * Summary: Old SAX version 1 handler, deprecated + * Description: DEPRECATED set of SAX version 1 interfaces used to + * build the DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX_H__ +#define __XML_SAX_H__ + +#include +#include + +#ifdef LIBXML_LEGACY_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif +XML_DEPRECATED +XMLPUBFUN const xmlChar * + getPublicId (void *ctx); +XML_DEPRECATED +XMLPUBFUN const xmlChar * + getSystemId (void *ctx); +XML_DEPRECATED +XMLPUBFUN void + setDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XML_DEPRECATED +XMLPUBFUN int + getLineNumber (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + getColumnNumber (void *ctx); + +XML_DEPRECATED +XMLPUBFUN int + isStandalone (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + hasInternalSubset (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + hasExternalSubset (void *ctx); + +XML_DEPRECATED +XMLPUBFUN void + internalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XML_DEPRECATED +XMLPUBFUN void + externalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XML_DEPRECATED +XMLPUBFUN xmlEntityPtr + getEntity (void *ctx, + const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN xmlEntityPtr + getParameterEntity (void *ctx, + const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN xmlParserInputPtr + resolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XML_DEPRECATED +XMLPUBFUN void + entityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XML_DEPRECATED +XMLPUBFUN void + attributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XML_DEPRECATED +XMLPUBFUN void + elementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XML_DEPRECATED +XMLPUBFUN void + notationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XML_DEPRECATED +XMLPUBFUN void + unparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XML_DEPRECATED +XMLPUBFUN void + startDocument (void *ctx); +XML_DEPRECATED +XMLPUBFUN void + endDocument (void *ctx); +XML_DEPRECATED +XMLPUBFUN void + attribute (void *ctx, + const xmlChar *fullname, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN void + startElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XML_DEPRECATED +XMLPUBFUN void + endElement (void *ctx, + const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN void + reference (void *ctx, + const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN void + characters (void *ctx, + const xmlChar *ch, + int len); +XML_DEPRECATED +XMLPUBFUN void + ignorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XML_DEPRECATED +XMLPUBFUN void + processingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XML_DEPRECATED +XMLPUBFUN void + globalNamespace (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XML_DEPRECATED +XMLPUBFUN void + setNamespace (void *ctx, + const xmlChar *name); +XML_DEPRECATED +XMLPUBFUN xmlNsPtr + getNamespace (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + checkNamespace (void *ctx, + xmlChar *nameSpace); +XML_DEPRECATED +XMLPUBFUN void + namespaceDecl (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XML_DEPRECATED +XMLPUBFUN void + comment (void *ctx, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN void + cdataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN void + initxmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr, + int warning); +#ifdef LIBXML_HTML_ENABLED +XML_DEPRECATED +XMLPUBFUN void + inithtmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr); +#endif +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_LEGACY_ENABLED */ + +#endif /* __XML_SAX_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX2.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX2.h new file mode 100644 index 00000000..4c4ecce8 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/SAX2.h @@ -0,0 +1,171 @@ +/* + * Summary: SAX2 parser interface used to build the DOM tree + * Description: those are the default SAX2 interfaces used by + * the library when building DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX2_H__ +#define __XML_SAX2_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN const xmlChar * + xmlSAX2GetPublicId (void *ctx); +XMLPUBFUN const xmlChar * + xmlSAX2GetSystemId (void *ctx); +XMLPUBFUN void + xmlSAX2SetDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XMLPUBFUN int + xmlSAX2GetLineNumber (void *ctx); +XMLPUBFUN int + xmlSAX2GetColumnNumber (void *ctx); + +XMLPUBFUN int + xmlSAX2IsStandalone (void *ctx); +XMLPUBFUN int + xmlSAX2HasInternalSubset (void *ctx); +XMLPUBFUN int + xmlSAX2HasExternalSubset (void *ctx); + +XMLPUBFUN void + xmlSAX2InternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN void + xmlSAX2ExternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlEntityPtr + xmlSAX2GetEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr + xmlSAX2GetParameterEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlParserInputPtr + xmlSAX2ResolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XMLPUBFUN void + xmlSAX2EntityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XMLPUBFUN void + xmlSAX2AttributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XMLPUBFUN void + xmlSAX2ElementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XMLPUBFUN void + xmlSAX2NotationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XMLPUBFUN void + xmlSAX2UnparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XMLPUBFUN void + xmlSAX2StartDocument (void *ctx); +XMLPUBFUN void + xmlSAX2EndDocument (void *ctx); +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED) +XMLPUBFUN void + xmlSAX2StartElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XMLPUBFUN void + xmlSAX2EndElement (void *ctx, + const xmlChar *name); +#endif /* LIBXML_SAX1_ENABLED or LIBXML_HTML_ENABLED or LIBXML_LEGACY_ENABLED */ +XMLPUBFUN void + xmlSAX2StartElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); +XMLPUBFUN void + xmlSAX2EndElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); +XMLPUBFUN void + xmlSAX2Reference (void *ctx, + const xmlChar *name); +XMLPUBFUN void + xmlSAX2Characters (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void + xmlSAX2IgnorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void + xmlSAX2ProcessingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XMLPUBFUN void + xmlSAX2Comment (void *ctx, + const xmlChar *value); +XMLPUBFUN void + xmlSAX2CDataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN int + xmlSAXDefaultVersion (int version); +#endif /* LIBXML_SAX1_ENABLED */ + +XMLPUBFUN int + xmlSAXVersion (xmlSAXHandler *hdlr, + int version); +XMLPUBFUN void + xmlSAX2InitDefaultSAXHandler (xmlSAXHandler *hdlr, + int warning); +#ifdef LIBXML_HTML_ENABLED +XMLPUBFUN void + xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr); +XML_DEPRECATED +XMLPUBFUN void + htmlDefaultSAXHandlerInit (void); +#endif +XML_DEPRECATED +XMLPUBFUN void + xmlDefaultSAXHandlerInit (void); +#ifdef __cplusplus +} +#endif +#endif /* __XML_SAX2_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/c14n.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/c14n.h new file mode 100644 index 00000000..8ccd1cef --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/c14n.h @@ -0,0 +1,115 @@ +/* + * Summary: Provide Canonical XML and Exclusive XML Canonicalization + * Description: the c14n modules provides a + * + * "Canonical XML" implementation + * http://www.w3.org/TR/xml-c14n + * + * and an + * + * "Exclusive XML Canonicalization" implementation + * http://www.w3.org/TR/xml-exc-c14n + + * Copy: See Copyright for the status of this software. + * + * Author: Aleksey Sanin + */ +#ifndef __XML_C14N_H__ +#define __XML_C14N_H__ + +#include + +#ifdef LIBXML_C14N_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * XML Canonicalization + * http://www.w3.org/TR/xml-c14n + * + * Exclusive XML Canonicalization + * http://www.w3.org/TR/xml-exc-c14n + * + * Canonical form of an XML document could be created if and only if + * a) default attributes (if any) are added to all nodes + * b) all character and parsed entity references are resolved + * In order to achieve this in libxml2 the document MUST be loaded with + * following options: XML_PARSE_DTDATTR | XML_PARSE_NOENT + */ + +/* + * xmlC14NMode: + * + * Predefined values for C14N modes + * + */ +typedef enum { + XML_C14N_1_0 = 0, /* Original C14N 1.0 spec */ + XML_C14N_EXCLUSIVE_1_0 = 1, /* Exclusive C14N 1.0 spec */ + XML_C14N_1_1 = 2 /* C14N 1.1 spec */ +} xmlC14NMode; + +XMLPUBFUN int + xmlC14NDocSaveTo (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +XMLPUBFUN int + xmlC14NDocDumpMemory (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlChar **doc_txt_ptr); + +XMLPUBFUN int + xmlC14NDocSave (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + const char* filename, + int compression); + + +/** + * This is the core C14N function + */ +/** + * xmlC14NIsVisibleCallback: + * @user_data: user data + * @node: the current node + * @parent: the parent node + * + * Signature for a C14N callback on visible nodes + * + * Returns 1 if the node should be included + */ +typedef int (*xmlC14NIsVisibleCallback) (void* user_data, + xmlNodePtr node, + xmlNodePtr parent); + +XMLPUBFUN int + xmlC14NExecute (xmlDocPtr doc, + xmlC14NIsVisibleCallback is_visible_callback, + void* user_data, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBXML_C14N_ENABLED */ +#endif /* __XML_C14N_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/catalog.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/catalog.h new file mode 100644 index 00000000..02fa7ab2 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/catalog.h @@ -0,0 +1,182 @@ +/** + * Summary: interfaces to the Catalog handling system + * Description: the catalog module implements the support for + * XML Catalogs and SGML catalogs + * + * SGML Open Technical Resolution TR9401:1997. + * http://www.jclark.com/sp/catalog.htm + * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CATALOG_H__ +#define __XML_CATALOG_H__ + +#include + +#include +#include +#include + +#ifdef LIBXML_CATALOG_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_CATALOGS_NAMESPACE: + * + * The namespace for the XML Catalogs elements. + */ +#define XML_CATALOGS_NAMESPACE \ + (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog" +/** + * XML_CATALOG_PI: + * + * The specific XML Catalog Processing Instruction name. + */ +#define XML_CATALOG_PI \ + (const xmlChar *) "oasis-xml-catalog" + +/* + * The API is voluntarily limited to general cataloging. + */ +typedef enum { + XML_CATA_PREFER_NONE = 0, + XML_CATA_PREFER_PUBLIC = 1, + XML_CATA_PREFER_SYSTEM +} xmlCatalogPrefer; + +typedef enum { + XML_CATA_ALLOW_NONE = 0, + XML_CATA_ALLOW_GLOBAL = 1, + XML_CATA_ALLOW_DOCUMENT = 2, + XML_CATA_ALLOW_ALL = 3 +} xmlCatalogAllow; + +typedef struct _xmlCatalog xmlCatalog; +typedef xmlCatalog *xmlCatalogPtr; + +/* + * Operations on a given catalog. + */ +XMLPUBFUN xmlCatalogPtr + xmlNewCatalog (int sgml); +XMLPUBFUN xmlCatalogPtr + xmlLoadACatalog (const char *filename); +XMLPUBFUN xmlCatalogPtr + xmlLoadSGMLSuperCatalog (const char *filename); +XMLPUBFUN int + xmlConvertSGMLCatalog (xmlCatalogPtr catal); +XMLPUBFUN int + xmlACatalogAdd (xmlCatalogPtr catal, + const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int + xmlACatalogRemove (xmlCatalogPtr catal, + const xmlChar *value); +XMLPUBFUN xmlChar * + xmlACatalogResolve (xmlCatalogPtr catal, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * + xmlACatalogResolveSystem(xmlCatalogPtr catal, + const xmlChar *sysID); +XMLPUBFUN xmlChar * + xmlACatalogResolvePublic(xmlCatalogPtr catal, + const xmlChar *pubID); +XMLPUBFUN xmlChar * + xmlACatalogResolveURI (xmlCatalogPtr catal, + const xmlChar *URI); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlACatalogDump (xmlCatalogPtr catal, + FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN void + xmlFreeCatalog (xmlCatalogPtr catal); +XMLPUBFUN int + xmlCatalogIsEmpty (xmlCatalogPtr catal); + +/* + * Global operations. + */ +XMLPUBFUN void + xmlInitializeCatalog (void); +XMLPUBFUN int + xmlLoadCatalog (const char *filename); +XMLPUBFUN void + xmlLoadCatalogs (const char *paths); +XMLPUBFUN void + xmlCatalogCleanup (void); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlCatalogDump (FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN xmlChar * + xmlCatalogResolve (const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * + xmlCatalogResolveSystem (const xmlChar *sysID); +XMLPUBFUN xmlChar * + xmlCatalogResolvePublic (const xmlChar *pubID); +XMLPUBFUN xmlChar * + xmlCatalogResolveURI (const xmlChar *URI); +XMLPUBFUN int + xmlCatalogAdd (const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int + xmlCatalogRemove (const xmlChar *value); +XMLPUBFUN xmlDocPtr + xmlParseCatalogFile (const char *filename); +XMLPUBFUN int + xmlCatalogConvert (void); + +/* + * Strictly minimal interfaces for per-document catalogs used + * by the parser. + */ +XMLPUBFUN void + xmlCatalogFreeLocal (void *catalogs); +XMLPUBFUN void * + xmlCatalogAddLocal (void *catalogs, + const xmlChar *URL); +XMLPUBFUN xmlChar * + xmlCatalogLocalResolve (void *catalogs, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * + xmlCatalogLocalResolveURI(void *catalogs, + const xmlChar *URI); +/* + * Preference settings. + */ +XMLPUBFUN int + xmlCatalogSetDebug (int level); +XMLPUBFUN xmlCatalogPrefer + xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer); +XMLPUBFUN void + xmlCatalogSetDefaults (xmlCatalogAllow allow); +XMLPUBFUN xmlCatalogAllow + xmlCatalogGetDefaults (void); + + +/* DEPRECATED interfaces */ +XMLPUBFUN const xmlChar * + xmlCatalogGetSystem (const xmlChar *sysID); +XMLPUBFUN const xmlChar * + xmlCatalogGetPublic (const xmlChar *pubID); + +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_CATALOG_ENABLED */ +#endif /* __XML_CATALOG_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/chvalid.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/chvalid.h new file mode 100644 index 00000000..8225c95e --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/chvalid.h @@ -0,0 +1,230 @@ +/* + * Summary: Unicode character range checking + * Description: this module exports interfaces for the character + * range validation APIs + * + * This file is automatically generated from the cvs source + * definition files using the genChRanges.py Python script + * + * Generation date: Mon Mar 27 11:09:48 2006 + * Sources: chvalid.def + * Author: William Brack + */ + +#ifndef __XML_CHVALID_H__ +#define __XML_CHVALID_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Define our typedefs and structures + * + */ +typedef struct _xmlChSRange xmlChSRange; +typedef xmlChSRange *xmlChSRangePtr; +struct _xmlChSRange { + unsigned short low; + unsigned short high; +}; + +typedef struct _xmlChLRange xmlChLRange; +typedef xmlChLRange *xmlChLRangePtr; +struct _xmlChLRange { + unsigned int low; + unsigned int high; +}; + +typedef struct _xmlChRangeGroup xmlChRangeGroup; +typedef xmlChRangeGroup *xmlChRangeGroupPtr; +struct _xmlChRangeGroup { + int nbShortRange; + int nbLongRange; + const xmlChSRange *shortRange; /* points to an array of ranges */ + const xmlChLRange *longRange; +}; + +/** + * Range checking routine + */ +XMLPUBFUN int + xmlCharInRange(unsigned int val, const xmlChRangeGroup *group); + + +/** + * xmlIsBaseChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseChar_ch(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a)) || \ + ((0xc0 <= (c)) && ((c) <= 0xd6)) || \ + ((0xd8 <= (c)) && ((c) <= 0xf6)) || \ + (0xf8 <= (c))) + +/** + * xmlIsBaseCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseCharQ(c) (((c) < 0x100) ? \ + xmlIsBaseChar_ch((c)) : \ + xmlCharInRange((c), &xmlIsBaseCharGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsBaseCharGroup; + +/** + * xmlIsBlank_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlank_ch(c) (((c) == 0x20) || \ + ((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd)) + +/** + * xmlIsBlankQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlankQ(c) (((c) < 0x100) ? \ + xmlIsBlank_ch((c)) : 0) + + +/** + * xmlIsChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsChar_ch(c) (((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd) || \ + (0x20 <= (c))) + +/** + * xmlIsCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCharQ(c) (((c) < 0x100) ? \ + xmlIsChar_ch((c)) :\ + (((0x100 <= (c)) && ((c) <= 0xd7ff)) || \ + ((0xe000 <= (c)) && ((c) <= 0xfffd)) || \ + ((0x10000 <= (c)) && ((c) <= 0x10ffff)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsCharGroup; + +/** + * xmlIsCombiningQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCombiningQ(c) (((c) < 0x100) ? \ + 0 : \ + xmlCharInRange((c), &xmlIsCombiningGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsCombiningGroup; + +/** + * xmlIsDigit_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigit_ch(c) (((0x30 <= (c)) && ((c) <= 0x39))) + +/** + * xmlIsDigitQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigitQ(c) (((c) < 0x100) ? \ + xmlIsDigit_ch((c)) : \ + xmlCharInRange((c), &xmlIsDigitGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsDigitGroup; + +/** + * xmlIsExtender_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtender_ch(c) (((c) == 0xb7)) + +/** + * xmlIsExtenderQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtenderQ(c) (((c) < 0x100) ? \ + xmlIsExtender_ch((c)) : \ + xmlCharInRange((c), &xmlIsExtenderGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsExtenderGroup; + +/** + * xmlIsIdeographicQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsIdeographicQ(c) (((c) < 0x100) ? \ + 0 :\ + (((0x4e00 <= (c)) && ((c) <= 0x9fa5)) || \ + ((c) == 0x3007) || \ + ((0x3021 <= (c)) && ((c) <= 0x3029)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsIdeographicGroup; +XMLPUBVAR const unsigned char xmlIsPubidChar_tab[256]; + +/** + * xmlIsPubidChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidChar_ch(c) (xmlIsPubidChar_tab[(c)]) + +/** + * xmlIsPubidCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidCharQ(c) (((c) < 0x100) ? \ + xmlIsPubidChar_ch((c)) : 0) + +XMLPUBFUN int + xmlIsBaseChar(unsigned int ch); +XMLPUBFUN int + xmlIsBlank(unsigned int ch); +XMLPUBFUN int + xmlIsChar(unsigned int ch); +XMLPUBFUN int + xmlIsCombining(unsigned int ch); +XMLPUBFUN int + xmlIsDigit(unsigned int ch); +XMLPUBFUN int + xmlIsExtender(unsigned int ch); +XMLPUBFUN int + xmlIsIdeographic(unsigned int ch); +XMLPUBFUN int + xmlIsPubidChar(unsigned int ch); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_CHVALID_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/debugXML.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/debugXML.h new file mode 100644 index 00000000..1332dd73 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/debugXML.h @@ -0,0 +1,217 @@ +/* + * Summary: Tree debugging APIs + * Description: Interfaces to a set of routines used for debugging the tree + * produced by the XML parser. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __DEBUG_XML__ +#define __DEBUG_XML__ +#include +#include +#include + +#ifdef LIBXML_DEBUG_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The standard Dump routines. + */ +XMLPUBFUN void + xmlDebugDumpString (FILE *output, + const xmlChar *str); +XMLPUBFUN void + xmlDebugDumpAttr (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void + xmlDebugDumpAttrList (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void + xmlDebugDumpOneNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void + xmlDebugDumpNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void + xmlDebugDumpNodeList (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void + xmlDebugDumpDocumentHead(FILE *output, + xmlDocPtr doc); +XMLPUBFUN void + xmlDebugDumpDocument (FILE *output, + xmlDocPtr doc); +XMLPUBFUN void + xmlDebugDumpDTD (FILE *output, + xmlDtdPtr dtd); +XMLPUBFUN void + xmlDebugDumpEntities (FILE *output, + xmlDocPtr doc); + +/**************************************************************** + * * + * Checking routines * + * * + ****************************************************************/ + +XMLPUBFUN int + xmlDebugCheckDocument (FILE * output, + xmlDocPtr doc); + +/**************************************************************** + * * + * XML shell helpers * + * * + ****************************************************************/ + +XMLPUBFUN void + xmlLsOneNode (FILE *output, xmlNodePtr node); +XMLPUBFUN int + xmlLsCountNode (xmlNodePtr node); + +XMLPUBFUN const char * + xmlBoolToText (int boolval); + +/**************************************************************** + * * + * The XML shell related structures and functions * + * * + ****************************************************************/ + +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlShellReadlineFunc: + * @prompt: a string prompt + * + * This is a generic signature for the XML shell input function. + * + * Returns a string which will be freed by the Shell. + */ +typedef char * (* xmlShellReadlineFunc)(char *prompt); + +/** + * xmlShellCtxt: + * + * A debugging shell context. + * TODO: add the defined function tables. + */ +typedef struct _xmlShellCtxt xmlShellCtxt; +typedef xmlShellCtxt *xmlShellCtxtPtr; +struct _xmlShellCtxt { + char *filename; + xmlDocPtr doc; + xmlNodePtr node; + xmlXPathContextPtr pctxt; + int loaded; + FILE *output; + xmlShellReadlineFunc input; +}; + +/** + * xmlShellCmd: + * @ctxt: a shell context + * @arg: a string argument + * @node: a first node + * @node2: a second node + * + * This is a generic signature for the XML shell functions. + * + * Returns an int, negative returns indicating errors. + */ +typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); + +XMLPUBFUN void + xmlShellPrintXPathError (int errorType, + const char *arg); +XMLPUBFUN void + xmlShellPrintXPathResult(xmlXPathObjectPtr list); +XMLPUBFUN int + xmlShellList (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellBase (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellDir (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellLoad (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlShellPrintNode (xmlNodePtr node); +XMLPUBFUN int + xmlShellCat (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellWrite (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellSave (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED +XMLPUBFUN int + xmlShellValidate (xmlShellCtxtPtr ctxt, + char *dtd, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_VALID_ENABLED */ +XMLPUBFUN int + xmlShellDu (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr tree, + xmlNodePtr node2); +XMLPUBFUN int + xmlShellPwd (xmlShellCtxtPtr ctxt, + char *buffer, + xmlNodePtr node, + xmlNodePtr node2); + +/* + * The Shell interface. + */ +XMLPUBFUN void + xmlShell (xmlDocPtr doc, + const char *filename, + xmlShellReadlineFunc input, + FILE *output); + +#endif /* LIBXML_XPATH_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_DEBUG_ENABLED */ +#endif /* __DEBUG_XML__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/dict.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/dict.h new file mode 100644 index 00000000..22aa3d9d --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/dict.h @@ -0,0 +1,82 @@ +/* + * Summary: string dictionary + * Description: dictionary of reusable strings, just used to avoid allocation + * and freeing operations. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_DICT_H__ +#define __XML_DICT_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The dictionary. + */ +typedef struct _xmlDict xmlDict; +typedef xmlDict *xmlDictPtr; + +/* + * Initializer + */ +XML_DEPRECATED +XMLPUBFUN int xmlInitializeDict(void); + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlDictPtr + xmlDictCreate (void); +XMLPUBFUN size_t + xmlDictSetLimit (xmlDictPtr dict, + size_t limit); +XMLPUBFUN size_t + xmlDictGetUsage (xmlDictPtr dict); +XMLPUBFUN xmlDictPtr + xmlDictCreateSub(xmlDictPtr sub); +XMLPUBFUN int + xmlDictReference(xmlDictPtr dict); +XMLPUBFUN void + xmlDictFree (xmlDictPtr dict); + +/* + * Lookup of entry in the dictionary. + */ +XMLPUBFUN const xmlChar * + xmlDictLookup (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * + xmlDictExists (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * + xmlDictQLookup (xmlDictPtr dict, + const xmlChar *prefix, + const xmlChar *name); +XMLPUBFUN int + xmlDictOwns (xmlDictPtr dict, + const xmlChar *str); +XMLPUBFUN int + xmlDictSize (xmlDictPtr dict); + +/* + * Cleanup function + */ +XML_DEPRECATED +XMLPUBFUN void + xmlDictCleanup (void); + +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_DICT_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/encoding.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/encoding.h new file mode 100644 index 00000000..599a03e1 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/encoding.h @@ -0,0 +1,244 @@ +/* + * Summary: interface for the encoding conversion functions + * Description: interface for the encoding conversion functions needed for + * XML basic encoding and iconv() support. + * + * Related specs are + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CHAR_ENCODING_H__ +#define __XML_CHAR_ENCODING_H__ + +#include + +#ifdef LIBXML_ICONV_ENABLED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_ENC_ERR_SUCCESS = 0, + XML_ENC_ERR_SPACE = -1, + XML_ENC_ERR_INPUT = -2, + XML_ENC_ERR_PARTIAL = -3, + XML_ENC_ERR_INTERNAL = -4, + XML_ENC_ERR_MEMORY = -5 +} xmlCharEncError; + +/* + * xmlCharEncoding: + * + * Predefined values for some standard encodings. + * Libxml does not do beforehand translation on UTF8 and ISOLatinX. + * It also supports ASCII, ISO-8859-1, and UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC. A + * converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the current form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable iconv and to provide iconv libs for the encoding + * support needed. + * + * Note that the generic "UTF-16" is not a predefined value. Instead, only + * the specific UTF-16LE and UTF-16BE are present. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @out: a pointer to an array of bytes to store the UTF-8 result + * @outlen: the length of @out + * @in: a pointer to an array of chars in the original encoding + * @inlen: the length of @in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to another + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets produced. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there are two extra fields. + */ +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +#ifdef LIBXML_ICU_ENABLED + struct _uconv_t *uconv_in; + struct _uconv_t *uconv_out; +#endif /* LIBXML_ICU_ENABLED */ +}; + +/* + * Interfaces for encoding handlers. + */ +XML_DEPRECATED +XMLPUBFUN void + xmlInitCharEncodingHandlers (void); +XML_DEPRECATED +XMLPUBFUN void + xmlCleanupCharEncodingHandlers (void); +XMLPUBFUN void + xmlRegisterCharEncodingHandler (xmlCharEncodingHandlerPtr handler); +XMLPUBFUN int + xmlLookupCharEncodingHandler (xmlCharEncoding enc, + xmlCharEncodingHandlerPtr *out); +XMLPUBFUN int + xmlOpenCharEncodingHandler (const char *name, + int output, + xmlCharEncodingHandlerPtr *out); +XMLPUBFUN xmlCharEncodingHandlerPtr + xmlGetCharEncodingHandler (xmlCharEncoding enc); +XMLPUBFUN xmlCharEncodingHandlerPtr + xmlFindCharEncodingHandler (const char *name); +XMLPUBFUN xmlCharEncodingHandlerPtr + xmlNewCharEncodingHandler (const char *name, + xmlCharEncodingInputFunc input, + xmlCharEncodingOutputFunc output); + +/* + * Interfaces for encoding names and aliases. + */ +XMLPUBFUN int + xmlAddEncodingAlias (const char *name, + const char *alias); +XMLPUBFUN int + xmlDelEncodingAlias (const char *alias); +XMLPUBFUN const char * + xmlGetEncodingAlias (const char *alias); +XMLPUBFUN void + xmlCleanupEncodingAliases (void); +XMLPUBFUN xmlCharEncoding + xmlParseCharEncoding (const char *name); +XMLPUBFUN const char * + xmlGetCharEncodingName (xmlCharEncoding enc); + +/* + * Interfaces directly used by the parsers. + */ +XMLPUBFUN xmlCharEncoding + xmlDetectCharEncoding (const unsigned char *in, + int len); + +/** DOC_DISABLE */ +struct _xmlBuffer; +/** DOC_ENABLE */ +XMLPUBFUN int + xmlCharEncOutFunc (xmlCharEncodingHandler *handler, + struct _xmlBuffer *out, + struct _xmlBuffer *in); + +XMLPUBFUN int + xmlCharEncInFunc (xmlCharEncodingHandler *handler, + struct _xmlBuffer *out, + struct _xmlBuffer *in); +XML_DEPRECATED +XMLPUBFUN int + xmlCharEncFirstLine (xmlCharEncodingHandler *handler, + struct _xmlBuffer *out, + struct _xmlBuffer *in); +XMLPUBFUN int + xmlCharEncCloseFunc (xmlCharEncodingHandler *handler); + +/* + * Export a few useful functions + */ +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN int + UTF8Toisolat1 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN int + isolat1ToUTF8 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_CHAR_ENCODING_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/entities.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/entities.h new file mode 100644 index 00000000..a0cfca81 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/entities.h @@ -0,0 +1,166 @@ +/* + * Summary: interface for the XML entities handling + * Description: this module provides some of the entity API needed + * for the parser and applications. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_ENTITIES_H__ +#define __XML_ENTITIES_H__ + +/** DOC_DISABLE */ +#include +#define XML_TREE_INTERNALS +#include +#undef XML_TREE_INTERNALS +/** DOC_ENABLE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The different valid entity types. + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +struct _xmlEntity { + void *_private; /* application data */ + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Entity name */ + struct _xmlNode *children; /* First child link */ + struct _xmlNode *last; /* Last child link */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ + int owner; /* unused */ + int flags; /* various flags */ + unsigned long expandedSize; /* expanded size */ +}; + +/* + * All entities are stored in an hash table. + * There is 2 separate hash tables for global and parameter entities. + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions: + */ + +#ifdef LIBXML_LEGACY_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlInitializePredefinedEntities (void); +#endif /* LIBXML_LEGACY_ENABLED */ + +XMLPUBFUN xmlEntityPtr + xmlNewEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN void + xmlFreeEntity (xmlEntityPtr entity); +XMLPUBFUN int + xmlAddEntity (xmlDocPtr doc, + int extSubset, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content, + xmlEntityPtr *out); +XMLPUBFUN xmlEntityPtr + xmlAddDocEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr + xmlAddDtdEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr + xmlGetPredefinedEntity (const xmlChar *name); +XMLPUBFUN xmlEntityPtr + xmlGetDocEntity (const xmlDoc *doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr + xmlGetDtdEntity (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr + xmlGetParameterEntity (xmlDocPtr doc, + const xmlChar *name); +#ifdef LIBXML_LEGACY_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlEncodeEntities (xmlDocPtr doc, + const xmlChar *input); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlChar * + xmlEncodeEntitiesReentrant(xmlDocPtr doc, + const xmlChar *input); +XMLPUBFUN xmlChar * + xmlEncodeSpecialChars (const xmlDoc *doc, + const xmlChar *input); +XMLPUBFUN xmlEntitiesTablePtr + xmlCreateEntitiesTable (void); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEntitiesTablePtr + xmlCopyEntitiesTable (xmlEntitiesTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void + xmlFreeEntitiesTable (xmlEntitiesTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlDumpEntitiesTable (xmlBufferPtr buf, + xmlEntitiesTablePtr table); +XMLPUBFUN void + xmlDumpEntityDecl (xmlBufferPtr buf, + xmlEntityPtr ent); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN void + xmlCleanupPredefinedEntities(void); +#endif /* LIBXML_LEGACY_ENABLED */ + + +#ifdef __cplusplus +} +#endif + +# endif /* __XML_ENTITIES_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/globals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/globals.h new file mode 100644 index 00000000..92f41312 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/globals.h @@ -0,0 +1,41 @@ +/* + * Summary: interface for all global variables of the library + * Description: Deprecated, don't use + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __XML_GLOBALS_H +#define __XML_GLOBALS_H + +#include + +/* + * This file was required to access global variables until version v2.12.0. + * + * These includes are for backward compatibility. + */ +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlGlobalState xmlGlobalState; +typedef xmlGlobalState *xmlGlobalStatePtr; + +XML_DEPRECATED XMLPUBFUN void +xmlInitializeGlobalState(xmlGlobalStatePtr gs); +XML_DEPRECATED XMLPUBFUN +xmlGlobalStatePtr xmlGetGlobalState(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_GLOBALS_H */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/hash.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/hash.h new file mode 100644 index 00000000..135b6966 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/hash.h @@ -0,0 +1,251 @@ +/* + * Summary: Chained hash tables + * Description: This module implements the hash table support used in + * various places in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Bjorn Reese + */ + +#ifndef __XML_HASH_H__ +#define __XML_HASH_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The hash table. + */ +typedef struct _xmlHashTable xmlHashTable; +typedef xmlHashTable *xmlHashTablePtr; + +/* + * Recent version of gcc produce a warning when a function pointer is assigned + * to an object pointer, or vice versa. The following macro is a dirty hack + * to allow suppression of the warning. If your architecture has function + * pointers which are a different size than a void pointer, there may be some + * serious trouble within the library. + */ +/** + * XML_CAST_FPTR: + * @fptr: pointer to a function + * + * Macro to do a casting from an object pointer to a + * function pointer without encountering a warning from + * gcc + * + * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) + * This macro violated ISO C aliasing rules (gcc4 on s390 broke) + * so it is disabled now + */ + +#define XML_CAST_FPTR(fptr) fptr + +/* + * function types: + */ +/** + * xmlHashDeallocator: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to free data from a hash. + */ +typedef void (*xmlHashDeallocator)(void *payload, const xmlChar *name); +/** + * xmlHashCopier: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to copy data from a hash. + * + * Returns a copy of the data or NULL in case of error. + */ +typedef void *(*xmlHashCopier)(void *payload, const xmlChar *name); +/** + * xmlHashScanner: + * @payload: the data in the hash + * @data: extra scanner data + * @name: the name associated + * + * Callback when scanning data in a hash with the simple scanner. + */ +typedef void (*xmlHashScanner)(void *payload, void *data, const xmlChar *name); +/** + * xmlHashScannerFull: + * @payload: the data in the hash + * @data: extra scanner data + * @name: the name associated + * @name2: the second name associated + * @name3: the third name associated + * + * Callback when scanning data in a hash with the full scanner. + */ +typedef void (*xmlHashScannerFull)(void *payload, void *data, + const xmlChar *name, const xmlChar *name2, + const xmlChar *name3); + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlHashTablePtr + xmlHashCreate (int size); +XMLPUBFUN xmlHashTablePtr + xmlHashCreateDict (int size, + xmlDictPtr dict); +XMLPUBFUN void + xmlHashFree (xmlHashTablePtr hash, + xmlHashDeallocator dealloc); +XMLPUBFUN void + xmlHashDefaultDeallocator(void *entry, + const xmlChar *name); + +/* + * Add a new entry to the hash table. + */ +XMLPUBFUN int + xmlHashAdd (xmlHashTablePtr hash, + const xmlChar *name, + void *userdata); +XMLPUBFUN int + xmlHashAddEntry (xmlHashTablePtr hash, + const xmlChar *name, + void *userdata); +XMLPUBFUN int + xmlHashUpdateEntry (xmlHashTablePtr hash, + const xmlChar *name, + void *userdata, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + void *userdata); +XMLPUBFUN int + xmlHashAddEntry2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + void *userdata); +XMLPUBFUN int + xmlHashUpdateEntry2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + void *userdata, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); +XMLPUBFUN int + xmlHashAddEntry3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); +XMLPUBFUN int + xmlHashUpdateEntry3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata, + xmlHashDeallocator dealloc); + +/* + * Remove an entry from the hash table. + */ +XMLPUBFUN int + xmlHashRemoveEntry (xmlHashTablePtr hash, + const xmlChar *name, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashRemoveEntry2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashRemoveEntry3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashDeallocator dealloc); + +/* + * Retrieve the payload. + */ +XMLPUBFUN void * + xmlHashLookup (xmlHashTablePtr hash, + const xmlChar *name); +XMLPUBFUN void * + xmlHashLookup2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2); +XMLPUBFUN void * + xmlHashLookup3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3); +XMLPUBFUN void * + xmlHashQLookup (xmlHashTablePtr hash, + const xmlChar *prefix, + const xmlChar *name); +XMLPUBFUN void * + xmlHashQLookup2 (xmlHashTablePtr hash, + const xmlChar *prefix, + const xmlChar *name, + const xmlChar *prefix2, + const xmlChar *name2); +XMLPUBFUN void * + xmlHashQLookup3 (xmlHashTablePtr hash, + const xmlChar *prefix, + const xmlChar *name, + const xmlChar *prefix2, + const xmlChar *name2, + const xmlChar *prefix3, + const xmlChar *name3); + +/* + * Helpers. + */ +XMLPUBFUN xmlHashTablePtr + xmlHashCopySafe (xmlHashTablePtr hash, + xmlHashCopier copy, + xmlHashDeallocator dealloc); +XMLPUBFUN xmlHashTablePtr + xmlHashCopy (xmlHashTablePtr hash, + xmlHashCopier copy); +XMLPUBFUN int + xmlHashSize (xmlHashTablePtr hash); +XMLPUBFUN void + xmlHashScan (xmlHashTablePtr hash, + xmlHashScanner scan, + void *data); +XMLPUBFUN void + xmlHashScan3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScanner scan, + void *data); +XMLPUBFUN void + xmlHashScanFull (xmlHashTablePtr hash, + xmlHashScannerFull scan, + void *data); +XMLPUBFUN void + xmlHashScanFull3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScannerFull scan, + void *data); +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_HASH_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/list.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/list.h new file mode 100644 index 00000000..1fa76aff --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/list.h @@ -0,0 +1,137 @@ +/* + * Summary: lists interfaces + * Description: this module implement the list support used in + * various place in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Gary Pennington + */ + +#ifndef __XML_LINK_INCLUDE__ +#define __XML_LINK_INCLUDE__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +/** + * xmlListDeallocator: + * @lk: the data to deallocate + * + * Callback function used to free data from a list. + */ +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +/** + * xmlListDataCompare: + * @data0: the first data + * @data1: the second data + * + * Callback function used to compare 2 data. + * + * Returns 0 is equality, -1 or 1 otherwise depending on the ordering. + */ +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +/** + * xmlListWalker: + * @data: the data found in the list + * @user: extra user provided data to the walker + * + * Callback function used when walking a list with xmlListWalk(). + * + * Returns 0 to stop walking the list, 1 otherwise. + */ +typedef int (*xmlListWalker) (const void *data, void *user); + +/* Creation/Deletion */ +XMLPUBFUN xmlListPtr + xmlListCreate (xmlListDeallocator deallocator, + xmlListDataCompare compare); +XMLPUBFUN void + xmlListDelete (xmlListPtr l); + +/* Basic Operators */ +XMLPUBFUN void * + xmlListSearch (xmlListPtr l, + void *data); +XMLPUBFUN void * + xmlListReverseSearch (xmlListPtr l, + void *data); +XMLPUBFUN int + xmlListInsert (xmlListPtr l, + void *data) ; +XMLPUBFUN int + xmlListAppend (xmlListPtr l, + void *data) ; +XMLPUBFUN int + xmlListRemoveFirst (xmlListPtr l, + void *data); +XMLPUBFUN int + xmlListRemoveLast (xmlListPtr l, + void *data); +XMLPUBFUN int + xmlListRemoveAll (xmlListPtr l, + void *data); +XMLPUBFUN void + xmlListClear (xmlListPtr l); +XMLPUBFUN int + xmlListEmpty (xmlListPtr l); +XMLPUBFUN xmlLinkPtr + xmlListFront (xmlListPtr l); +XMLPUBFUN xmlLinkPtr + xmlListEnd (xmlListPtr l); +XMLPUBFUN int + xmlListSize (xmlListPtr l); + +XMLPUBFUN void + xmlListPopFront (xmlListPtr l); +XMLPUBFUN void + xmlListPopBack (xmlListPtr l); +XMLPUBFUN int + xmlListPushFront (xmlListPtr l, + void *data); +XMLPUBFUN int + xmlListPushBack (xmlListPtr l, + void *data); + +/* Advanced Operators */ +XMLPUBFUN void + xmlListReverse (xmlListPtr l); +XMLPUBFUN void + xmlListSort (xmlListPtr l); +XMLPUBFUN void + xmlListWalk (xmlListPtr l, + xmlListWalker walker, + void *user); +XMLPUBFUN void + xmlListReverseWalk (xmlListPtr l, + xmlListWalker walker, + void *user); +XMLPUBFUN void + xmlListMerge (xmlListPtr l1, + xmlListPtr l2); +XMLPUBFUN xmlListPtr + xmlListDup (xmlListPtr old); +XMLPUBFUN int + xmlListCopy (xmlListPtr cur, + xmlListPtr old); +/* Link operators */ +XMLPUBFUN void * + xmlLinkGetData (xmlLinkPtr lk); + +/* xmlListUnique() */ +/* xmlListSwap */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_LINK_INCLUDE__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanoftp.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanoftp.h new file mode 100644 index 00000000..ed3ac4f1 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanoftp.h @@ -0,0 +1,186 @@ +/* + * Summary: minimal FTP implementation + * Description: minimal FTP implementation allowing to fetch resources + * like external subset. This module is DEPRECATED, do not + * use any of its functions. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __NANO_FTP_H__ +#define __NANO_FTP_H__ + +#include + +#if defined(LIBXML_FTP_ENABLED) + +/* Needed for portability to Windows 64 bits */ +#if defined(_WIN32) +#include +#else +/** + * SOCKET: + * + * macro used to provide portability of code to windows sockets + */ +#define SOCKET int +/** + * INVALID_SOCKET: + * + * macro used to provide portability of code to windows sockets + * the value to be used when the socket is not valid + */ +#undef INVALID_SOCKET +#define INVALID_SOCKET (-1) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * ftpListCallback: + * @userData: user provided data for the callback + * @filename: the file name (including "->" when links are shown) + * @attrib: the attribute string + * @owner: the owner string + * @group: the group string + * @size: the file size + * @links: the link count + * @year: the year + * @month: the month + * @day: the day + * @hour: the hour + * @minute: the minute + * + * A callback for the xmlNanoFTPList command. + * Note that only one of year and day:minute are specified. + */ +typedef void (*ftpListCallback) (void *userData, + const char *filename, const char *attrib, + const char *owner, const char *group, + unsigned long size, int links, int year, + const char *month, int day, int hour, + int minute); +/** + * ftpDataCallback: + * @userData: the user provided context + * @data: the data received + * @len: its size in bytes + * + * A callback for the xmlNanoFTPGet command. + */ +typedef void (*ftpDataCallback) (void *userData, + const char *data, + int len); + +/* + * Init + */ +XML_DEPRECATED +XMLPUBFUN void + xmlNanoFTPInit (void); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoFTPCleanup (void); + +/* + * Creating/freeing contexts. + */ +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoFTPNewCtxt (const char *URL); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoFTPFreeCtxt (void * ctx); +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoFTPConnectTo (const char *server, + int port); +/* + * Opening/closing session connections. + */ +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoFTPOpen (const char *URL); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPConnect (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPClose (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPQuit (void *ctx); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoFTPScanProxy (const char *URL); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoFTPProxy (const char *host, + int port, + const char *user, + const char *passwd, + int type); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPUpdateURL (void *ctx, + const char *URL); + +/* + * Rather internal commands. + */ +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPGetResponse (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPCheckResponse (void *ctx); + +/* + * CD/DIR/GET handlers. + */ +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPCwd (void *ctx, + const char *directory); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPDele (void *ctx, + const char *file); + +XML_DEPRECATED +XMLPUBFUN SOCKET + xmlNanoFTPGetConnection (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPCloseConnection(void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPList (void *ctx, + ftpListCallback callback, + void *userData, + const char *filename); +XML_DEPRECATED +XMLPUBFUN SOCKET + xmlNanoFTPGetSocket (void *ctx, + const char *filename); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPGet (void *ctx, + ftpDataCallback callback, + void *userData, + const char *filename); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoFTPRead (void *ctx, + void *dest, + int len); + +#ifdef __cplusplus +} +#endif +#endif /* defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */ +#endif /* __NANO_FTP_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanohttp.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanohttp.h new file mode 100644 index 00000000..c70d1c26 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/nanohttp.h @@ -0,0 +1,98 @@ +/* + * Summary: minimal HTTP implementation + * Description: minimal HTTP implementation allowing to fetch resources + * like external subset. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __NANO_HTTP_H__ +#define __NANO_HTTP_H__ + +#include + +#ifdef LIBXML_HTTP_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif +XML_DEPRECATED +XMLPUBFUN void + xmlNanoHTTPInit (void); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoHTTPCleanup (void); +XML_DEPRECATED +XMLPUBFUN void + xmlNanoHTTPScanProxy (const char *URL); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoHTTPFetch (const char *URL, + const char *filename, + char **contentType); +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoHTTPMethod (const char *URL, + const char *method, + const char *input, + char **contentType, + const char *headers, + int ilen); +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoHTTPMethodRedir (const char *URL, + const char *method, + const char *input, + char **contentType, + char **redir, + const char *headers, + int ilen); +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoHTTPOpen (const char *URL, + char **contentType); +XML_DEPRECATED +XMLPUBFUN void * + xmlNanoHTTPOpenRedir (const char *URL, + char **contentType, + char **redir); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoHTTPReturnCode (void *ctx); +XML_DEPRECATED +XMLPUBFUN const char * + xmlNanoHTTPAuthHeader (void *ctx); +XML_DEPRECATED +XMLPUBFUN const char * + xmlNanoHTTPRedir (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoHTTPContentLength( void * ctx ); +XML_DEPRECATED +XMLPUBFUN const char * + xmlNanoHTTPEncoding (void *ctx); +XML_DEPRECATED +XMLPUBFUN const char * + xmlNanoHTTPMimeType (void *ctx); +XML_DEPRECATED +XMLPUBFUN int + xmlNanoHTTPRead (void *ctx, + void *dest, + int len); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN int + xmlNanoHTTPSave (void *ctxt, + const char *filename); +#endif /* LIBXML_OUTPUT_ENABLED */ +XML_DEPRECATED +XMLPUBFUN void + xmlNanoHTTPClose (void *ctx); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTTP_ENABLED */ +#endif /* __NANO_HTTP_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parser.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parser.h new file mode 100644 index 00000000..78d29cad --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parser.h @@ -0,0 +1,1390 @@ +/* + * Summary: the core parser module + * Description: Interfaces, constants and types related to the XML parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_H__ +#define __XML_PARSER_H__ + +/** DOC_DISABLE */ +#include +#define XML_TREE_INTERNALS +#include +#undef XML_TREE_INTERNALS +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* for compatibility */ +#include +#include +/** DOC_ENABLE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_DEFAULT_VERSION: + * + * The default version of XML used: 1.0 + */ +#define XML_DEFAULT_VERSION "1.0" + +/** + * xmlParserInput: + * + * An xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +/** + * xmlParserInputDeallocate: + * @str: the string to deallocate + * + * Callback for freeing some parser input allocations. + */ +typedef void (* xmlParserInputDeallocate)(xmlChar *str); + +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* unused */ + const xmlChar *base; /* Base of the array to parse */ + const xmlChar *cur; /* Current char being parsed */ + const xmlChar *end; /* end of the array to parse */ + int length; /* unused */ + int line; /* Current line */ + int col; /* Current column */ + unsigned long consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* unused */ + const xmlChar *version; /* the version string for entity */ + int flags; /* Flags */ + int id; /* an unique identifier for the entity */ + unsigned long parentConsumed; /* unused */ + xmlEntityPtr entity; /* entity, if any */ +}; + +/** + * xmlParserNodeInfo: + * + * The parser can be asked to collect Node information, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/** + * xmlParserInputState: + * + * The parser is now working also as a state based parser. + * The recursive one use the state info for entities processing. + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Within a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE, /* within an IGNORED section */ + XML_PARSER_PUBLIC_LITERAL, /* within a PUBLIC value */ + XML_PARSER_XML_DECL /* before XML decl (but after BOM) */ +} xmlParserInputState; + +/** DOC_DISABLE */ +/* + * Internal bits in the 'loadsubset' context member + */ +#define XML_DETECT_IDS 2 +#define XML_COMPLETE_ATTRS 4 +#define XML_SKIP_IDS 8 +/** DOC_ENABLE */ + +/** + * xmlParserMode: + * + * A parser can operate in various modes + */ +typedef enum { + XML_PARSE_UNKNOWN = 0, + XML_PARSE_DOM = 1, + XML_PARSE_SAX = 2, + XML_PARSE_PUSH_DOM = 3, + XML_PARSE_PUSH_SAX = 4, + XML_PARSE_READER = 5 +} xmlParserMode; + +typedef struct _xmlStartTag xmlStartTag; +typedef struct _xmlParserNsData xmlParserNsData; +typedef struct _xmlAttrHashBucket xmlAttrHashBucket; + +/** + * xmlParserCtxt: + * + * The parser context. + * NOTE This doesn't completely define the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1) document + * 3 is HTML after + * 10 is HTML after + */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* unused */ + + int valid; /* is the document valid */ + int validate; /* shall we try to validate ? */ + xmlValidCtxt vctxt; /* The validity context */ + + xmlParserInputState instate; /* push parser state */ + int token; /* unused */ + + char *directory; /* unused */ + + /* Node name stack */ + const xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + const xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* unused */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + const xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* unused */ + int charset; /* unused */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ + int linenumbers; /* set line number in element content */ + void *catalogs; /* document's own catalog */ + int recovery; /* run in recovery mode */ + int progressive; /* unused */ + xmlDictPtr dict; /* dictionary for the parser */ + const xmlChar * *atts; /* array for the attributes callbacks */ + int maxatts; /* the size of the array */ + int docdict; /* unused */ + + /* + * pre-interned strings + */ + const xmlChar *str_xml; + const xmlChar *str_xmlns; + const xmlChar *str_xml_ns; + + /* + * Everything below is used only by the new SAX mode + */ + int sax2; /* operating in the new SAX mode */ + int nsNr; /* the number of inherited namespaces */ + int nsMax; /* the size of the arrays */ + const xmlChar * *nsTab; /* the array of prefix/namespace name */ + unsigned *attallocs; /* which attribute were allocated */ + xmlStartTag *pushTab; /* array of data for push */ + xmlHashTablePtr attsDefault; /* defaulted attributes if any */ + xmlHashTablePtr attsSpecial; /* non-CDATA attributes if any */ + int nsWellFormed; /* is the document XML Namespace okay */ + int options; /* Extra options */ + + /* + * Those fields are needed only for streaming parsing so far + */ + int dictNames; /* Use dictionary names for the tree */ + int freeElemsNr; /* number of freed element nodes */ + xmlNodePtr freeElems; /* List of freed element nodes */ + int freeAttrsNr; /* number of freed attributes nodes */ + xmlAttrPtr freeAttrs; /* List of freed attributes nodes */ + + /* + * the complete error information for the last error. + */ + xmlError lastError; + xmlParserMode parseMode; /* the parser mode */ + unsigned long nbentities; /* unused */ + unsigned long sizeentities; /* size of external entities */ + + /* for use by HTML non-recursive parser */ + xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ + int nodeInfoNr; /* Depth of the parsing stack */ + int nodeInfoMax; /* Max depth of the parsing stack */ + xmlParserNodeInfo *nodeInfoTab; /* array of nodeInfos */ + + int input_id; /* we need to label inputs */ + unsigned long sizeentcopy; /* volume of entity copy */ + + int endCheckState; /* quote state for push parser */ + unsigned short nbErrors; /* number of errors */ + unsigned short nbWarnings; /* number of warnings */ + unsigned maxAmpl; /* maximum amplification factor */ + + xmlParserNsData *nsdb; /* namespace database */ + unsigned attrHashMax; /* allocated size */ + xmlAttrHashBucket *attrHash; /* atttribute hash table */ + + xmlStructuredErrorFunc errorHandler; + void *errorCtxt; +}; + +/** + * xmlSAXLocator: + * + * A SAX Locator. + */ +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/** + * xmlSAXHandler: + * + * A SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure information. + */ + +/** + * resolveEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * Callback: + * The entity loader, to control the loading of external entities, + * the application can either: + * - override this resolveEntity() callback in the SAX block + * - or better use the xmlSetExternalEntityLoader() function to + * set up it's own entity resolution routine + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * internalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on internal subset declaration. + */ +typedef void (*internalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * externalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on external subset declaration. + */ +typedef void (*externalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * getEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get an entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * getParameterEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get a parameter entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * entityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed. + */ +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +/** + * notationDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +typedef void (*notationDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * attributeDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @elem: the name of the element + * @fullname: the attribute name + * @type: the attribute type + * @def: the type of default value + * @defaultValue: the attribute default value + * @tree: the tree of enumerated value set + * + * An attribute definition has been parsed. + */ +typedef void (*attributeDeclSAXFunc)(void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +/** + * elementDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the element name + * @type: the element type + * @content: the element value tree + * + * An element definition has been parsed. + */ +typedef void (*elementDeclSAXFunc)(void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +/** + * unparsedEntityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed. + */ +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); +/** + * setDocumentLocatorSAXFunc: + * @ctx: the user data (XML parser context) + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator. + * Everything is available on the context, so this is useless in our case. + */ +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +/** + * startDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document start being processed. + */ +typedef void (*startDocumentSAXFunc) (void *ctx); +/** + * endDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document end has been detected. + */ +typedef void (*endDocumentSAXFunc) (void *ctx); +/** + * startElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name, including namespace prefix + * @atts: An array of name/value attributes pairs, NULL terminated + * + * Called when an opening tag has been processed. + */ +typedef void (*startElementSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar **atts); +/** + * endElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name + * + * Called when the end of an element has been detected. + */ +typedef void (*endElementSAXFunc) (void *ctx, + const xmlChar *name); +/** + * attributeSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The attribute name, including namespace prefix + * @value: The attribute value + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +typedef void (*attributeSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *value); +/** + * referenceSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Called when an entity reference is detected. + */ +typedef void (*referenceSAXFunc) (void *ctx, + const xmlChar *name); +/** + * charactersSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some chars from the parser. + */ +typedef void (*charactersSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * ignorableWhitespaceSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some ignorable whitespaces from the parser. + * UNUSED: by default the DOM building will use characters. + */ +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * processingInstructionSAXFunc: + * @ctx: the user data (XML parser context) + * @target: the target name + * @data: the PI data's + * + * A processing instruction has been parsed. + */ +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, + const xmlChar *data); +/** + * commentSAXFunc: + * @ctx: the user data (XML parser context) + * @value: the comment content + * + * A comment has been parsed. + */ +typedef void (*commentSAXFunc) (void *ctx, + const xmlChar *value); +/** + * cdataBlockSAXFunc: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * Called when a pcdata block has been parsed. + */ +typedef void (*cdataBlockSAXFunc) ( + void *ctx, + const xmlChar *value, + int len); +/** + * warningSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a warning messages, callback. + */ +typedef void (*warningSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * errorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an error messages, callback. + */ +typedef void (*errorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * fatalErrorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format fatal error messages, callback. + * Note: so far fatalError() SAX callbacks are not used, error() + * get all the callbacks for errors. + */ +typedef void (*fatalErrorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * isStandaloneSAXFunc: + * @ctx: the user data (XML parser context) + * + * Is this document tagged standalone? + * + * Returns 1 if true + */ +typedef int (*isStandaloneSAXFunc) (void *ctx); +/** + * hasInternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an internal subset. + * + * Returns 1 if true + */ +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); + +/** + * hasExternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an external subset? + * + * Returns 1 if true + */ +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +/************************************************************************ + * * + * The SAX version 2 API extensions * + * * + ************************************************************************/ +/** + * XML_SAX2_MAGIC: + * + * Special constant found in SAX2 blocks initialized fields + */ +#define XML_SAX2_MAGIC 0xDEEDBEAF + +/** + * startElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * @nb_defaulted: the number of defaulted attributes. The defaulted + * ones are at the end of the array + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * SAX2 callback when an element start has been detected by the parser. + * It provides the namespace information for the element, as well as + * the new namespace declarations on the element. + */ + +typedef void (*startElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); + +/** + * endElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * SAX2 callback when an element end has been detected by the parser. + * It provides the namespace information for the element. + */ + +typedef void (*endElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); + + +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + /* + * `startElement` and `endElement` are only used by the legacy SAX1 + * interface and should not be used in new software. If you really + * have to enable SAX1, the preferred way is set the `initialized` + * member to 1 instead of XML_SAX2_MAGIC. + * + * For backward compatibility, it's also possible to set the + * `startElementNs` and `endElementNs` handlers to NULL. + * + * You can also set the XML_PARSE_SAX1 parser option, but versions + * older than 2.12.0 will probably crash if this option is provided + * together with custom SAX callbacks. + */ + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + /* + * `initialized` should always be set to XML_SAX2_MAGIC to enable the + * modern SAX2 interface. + */ + unsigned int initialized; + /* + * The following members are only used by the SAX2 interface. + */ + void *_private; + startElementNsSAX2Func startElementNs; + endElementNsSAX2Func endElementNs; + xmlStructuredErrorFunc serror; +}; + +/* + * SAX Version 1 + */ +typedef struct _xmlSAXHandlerV1 xmlSAXHandlerV1; +typedef xmlSAXHandlerV1 *xmlSAXHandlerV1Ptr; +struct _xmlSAXHandlerV1 { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + unsigned int initialized; +}; + + +/** + * xmlExternalEntityLoader: + * @URL: The System ID of the resource requested + * @ID: The Public ID of the resource requested + * @context: the XML parser context + * + * External entity loaders types. + * + * Returns the entity input parser. + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +/* + * Variables + */ + +XMLPUBVAR const char *const xmlParserVersion; +XML_DEPRECATED +XMLPUBVAR const int oldXMLWDcompatibility; +XML_DEPRECATED +XMLPUBVAR const int xmlParserDebugEntities; +XML_DEPRECATED +XMLPUBVAR const xmlSAXLocator xmlDefaultSAXLocator; +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 xmlDefaultSAXHandler; +#endif + +#ifdef LIBXML_THREAD_ENABLED +/* backward compatibility */ +XMLPUBFUN const char *const *__xmlParserVersion(void); +XML_DEPRECATED +XMLPUBFUN const int *__oldXMLWDcompatibility(void); +XML_DEPRECATED +XMLPUBFUN const int *__xmlParserDebugEntities(void); +XML_DEPRECATED +XMLPUBFUN const xmlSAXLocator *__xmlDefaultSAXLocator(void); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__xmlDefaultSAXHandler(void); +#endif +#endif + +/** DOC_DISABLE */ +#define XML_GLOBALS_PARSER_CORE \ + XML_OP(xmlDoValidityCheckingDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlGetWarningsDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlKeepBlanksDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlLineNumbersDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlLoadExtDtdDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlPedanticParserDefaultValue, int, XML_DEPRECATED) \ + XML_OP(xmlSubstituteEntitiesDefaultValue, int, XML_DEPRECATED) + +#ifdef LIBXML_OUTPUT_ENABLED + #define XML_GLOBALS_PARSER_OUTPUT \ + XML_OP(xmlIndentTreeOutput, int, XML_NO_ATTR) \ + XML_OP(xmlTreeIndentString, const char *, XML_NO_ATTR) \ + XML_OP(xmlSaveNoEmptyTags, int, XML_NO_ATTR) +#else + #define XML_GLOBALS_PARSER_OUTPUT +#endif + +#define XML_GLOBALS_PARSER \ + XML_GLOBALS_PARSER_CORE \ + XML_GLOBALS_PARSER_OUTPUT + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_PARSER +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlDoValidityCheckingDefaultValue \ + XML_GLOBAL_MACRO(xmlDoValidityCheckingDefaultValue) + #define xmlGetWarningsDefaultValue \ + XML_GLOBAL_MACRO(xmlGetWarningsDefaultValue) + #define xmlKeepBlanksDefaultValue XML_GLOBAL_MACRO(xmlKeepBlanksDefaultValue) + #define xmlLineNumbersDefaultValue \ + XML_GLOBAL_MACRO(xmlLineNumbersDefaultValue) + #define xmlLoadExtDtdDefaultValue XML_GLOBAL_MACRO(xmlLoadExtDtdDefaultValue) + #define xmlPedanticParserDefaultValue \ + XML_GLOBAL_MACRO(xmlPedanticParserDefaultValue) + #define xmlSubstituteEntitiesDefaultValue \ + XML_GLOBAL_MACRO(xmlSubstituteEntitiesDefaultValue) + #ifdef LIBXML_OUTPUT_ENABLED + #define xmlIndentTreeOutput XML_GLOBAL_MACRO(xmlIndentTreeOutput) + #define xmlTreeIndentString XML_GLOBAL_MACRO(xmlTreeIndentString) + #define xmlSaveNoEmptyTags XML_GLOBAL_MACRO(xmlSaveNoEmptyTags) + #endif +#endif +/** DOC_ENABLE */ + +/* + * Init/Cleanup + */ +XMLPUBFUN void + xmlInitParser (void); +XMLPUBFUN void + xmlCleanupParser (void); +XML_DEPRECATED +XMLPUBFUN void + xmlInitGlobals (void); +XML_DEPRECATED +XMLPUBFUN void + xmlCleanupGlobals (void); + +/* + * Input functions + */ +XML_DEPRECATED +XMLPUBFUN int + xmlParserInputRead (xmlParserInputPtr in, + int len); +XML_DEPRECATED +XMLPUBFUN int + xmlParserInputGrow (xmlParserInputPtr in, + int len); + +/* + * Basic parsing Interfaces + */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN xmlDocPtr + xmlParseDoc (const xmlChar *cur); +XMLPUBFUN xmlDocPtr + xmlParseFile (const char *filename); +XMLPUBFUN xmlDocPtr + xmlParseMemory (const char *buffer, + int size); +#endif /* LIBXML_SAX1_ENABLED */ +XML_DEPRECATED XMLPUBFUN int + xmlSubstituteEntitiesDefault(int val); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefSubstituteEntitiesDefaultValue(int v); +XMLPUBFUN int + xmlKeepBlanksDefault (int val); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefKeepBlanksDefaultValue(int v); +XMLPUBFUN void + xmlStopParser (xmlParserCtxtPtr ctxt); +XML_DEPRECATED XMLPUBFUN int + xmlPedanticParserDefault(int val); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefPedanticParserDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlLineNumbersDefault (int val); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefLineNumbersDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefDoValidityCheckingDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefGetWarningsDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefLoadExtDtdDefaultValue(int v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefParserDebugEntities(int v); + +#ifdef LIBXML_SAX1_ENABLED +/* + * Recovery mode + */ +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlRecoverDoc (const xmlChar *cur); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlRecoverMemory (const char *buffer, + int size); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlRecoverFile (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +/* + * Less common routines and SAX interfaces + */ +XMLPUBFUN int + xmlParseDocument (xmlParserCtxtPtr ctxt); +XMLPUBFUN int + xmlParseExtParsedEnt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN int + xmlSAXUserParseFile (xmlSAXHandlerPtr sax, + void *user_data, + const char *filename); +XML_DEPRECATED +XMLPUBFUN int + xmlSAXUserParseMemory (xmlSAXHandlerPtr sax, + void *user_data, + const char *buffer, + int size); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseDoc (xmlSAXHandlerPtr sax, + const xmlChar *cur, + int recovery); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseMemory (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseMemoryWithData (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery, + void *data); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseFile (xmlSAXHandlerPtr sax, + const char *filename, + int recovery); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseFileWithData (xmlSAXHandlerPtr sax, + const char *filename, + int recovery, + void *data); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlSAXParseEntity (xmlSAXHandlerPtr sax, + const char *filename); +XML_DEPRECATED +XMLPUBFUN xmlDocPtr + xmlParseEntity (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +XML_DEPRECATED +XMLPUBFUN xmlDtdPtr + xmlSAXParseDTD (xmlSAXHandlerPtr sax, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr + xmlParseDTD (const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr + xmlIOParseDTD (xmlSAXHandlerPtr sax, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); +#endif /* LIBXML_VALID_ENABLE */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int + xmlParseBalancedChunkMemory(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserErrors + xmlParseInNodeContext (xmlNodePtr node, + const char *data, + int datalen, + int options, + xmlNodePtr *lst); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int + xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst, + int recover); +XML_DEPRECATED +XMLPUBFUN int + xmlParseExternalEntity (xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN int + xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); + +/* + * Parser contexts handling. + */ +XMLPUBFUN xmlParserCtxtPtr + xmlNewParserCtxt (void); +XMLPUBFUN xmlParserCtxtPtr + xmlNewSAXParserCtxt (const xmlSAXHandler *sax, + void *userData); +XMLPUBFUN int + xmlInitParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void + xmlClearParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void + xmlFreeParserCtxt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlSetupParserForBuffer (xmlParserCtxtPtr ctxt, + const xmlChar* buffer, + const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserCtxtPtr + xmlCreateDocParserCtxt (const xmlChar *cur); + +#ifdef LIBXML_LEGACY_ENABLED +/* + * Reading/setting optional parsing features. + */ +XML_DEPRECATED +XMLPUBFUN int + xmlGetFeaturesList (int *len, + const char **result); +XML_DEPRECATED +XMLPUBFUN int + xmlGetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *result); +XML_DEPRECATED +XMLPUBFUN int + xmlSetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *value); +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef LIBXML_PUSH_ENABLED +/* + * Interfaces for the Push mode. + */ +XMLPUBFUN xmlParserCtxtPtr + xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename); +XMLPUBFUN int + xmlParseChunk (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +#endif /* LIBXML_PUSH_ENABLED */ + +/* + * Special I/O mode. + */ + +XMLPUBFUN xmlParserCtxtPtr + xmlCreateIOParserCtxt (xmlSAXHandlerPtr sax, + void *user_data, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputPtr + xmlNewIOInputStream (xmlParserCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); + +/* + * Node infos. + */ +XMLPUBFUN const xmlParserNodeInfo* + xmlParserFindNodeInfo (xmlParserCtxtPtr ctxt, + xmlNodePtr node); +XMLPUBFUN void + xmlInitNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN void + xmlClearNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN unsigned long + xmlParserFindNodeInfoIndex(xmlParserNodeInfoSeqPtr seq, + xmlNodePtr node); +XMLPUBFUN void + xmlParserAddNodeInfo (xmlParserCtxtPtr ctxt, + xmlParserNodeInfoPtr info); + +/* + * External entities handling actually implemented in xmlIO. + */ + +XMLPUBFUN void + xmlSetExternalEntityLoader(xmlExternalEntityLoader f); +XMLPUBFUN xmlExternalEntityLoader + xmlGetExternalEntityLoader(void); +XMLPUBFUN xmlParserInputPtr + xmlLoadExternalEntity (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +/* + * Index lookup, actually implemented in the encoding module + */ +XMLPUBFUN long + xmlByteConsumed (xmlParserCtxtPtr ctxt); + +/* + * New set of simpler/more flexible APIs + */ +/** + * xmlParserOption: + * + * This is the set of XML parser options that can be passed down + * to the xmlReadDoc() and similar calls. + */ +typedef enum { + XML_PARSE_RECOVER = 1<<0, /* recover on errors */ + XML_PARSE_NOENT = 1<<1, /* substitute entities */ + XML_PARSE_DTDLOAD = 1<<2, /* load the external subset */ + XML_PARSE_DTDATTR = 1<<3, /* default DTD attributes */ + XML_PARSE_DTDVALID = 1<<4, /* validate with the DTD */ + XML_PARSE_NOERROR = 1<<5, /* suppress error reports */ + XML_PARSE_NOWARNING = 1<<6, /* suppress warning reports */ + XML_PARSE_PEDANTIC = 1<<7, /* pedantic error reporting */ + XML_PARSE_NOBLANKS = 1<<8, /* remove blank nodes */ + XML_PARSE_SAX1 = 1<<9, /* use the SAX1 interface internally */ + XML_PARSE_XINCLUDE = 1<<10,/* Implement XInclude substitution */ + XML_PARSE_NONET = 1<<11,/* Forbid network access */ + XML_PARSE_NODICT = 1<<12,/* Do not reuse the context dictionary */ + XML_PARSE_NSCLEAN = 1<<13,/* remove redundant namespaces declarations */ + XML_PARSE_NOCDATA = 1<<14,/* merge CDATA as text nodes */ + XML_PARSE_NOXINCNODE= 1<<15,/* do not generate XINCLUDE START/END nodes */ + XML_PARSE_COMPACT = 1<<16,/* compact small text nodes; no modification of + the tree allowed afterwards (will possibly + crash if you try to modify the tree) */ + XML_PARSE_OLD10 = 1<<17,/* parse using XML-1.0 before update 5 */ + XML_PARSE_NOBASEFIX = 1<<18,/* do not fixup XINCLUDE xml:base uris */ + XML_PARSE_HUGE = 1<<19,/* relax any hardcoded limit from the parser */ + XML_PARSE_OLDSAX = 1<<20,/* parse using SAX2 interface before 2.7.0 */ + XML_PARSE_IGNORE_ENC= 1<<21,/* ignore internal document encoding hint */ + XML_PARSE_BIG_LINES = 1<<22,/* Store big lines numbers in text PSVI field */ + XML_PARSE_NO_XXE = 1<<23 /* disable loading of external content */ +} xmlParserOption; + +XMLPUBFUN void + xmlCtxtReset (xmlParserCtxtPtr ctxt); +XMLPUBFUN int + xmlCtxtResetPush (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + const char *filename, + const char *encoding); +XMLPUBFUN int + xmlCtxtSetOptions (xmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN int + xmlCtxtUseOptions (xmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN void + xmlCtxtSetErrorHandler (xmlParserCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); +XMLPUBFUN void + xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, + unsigned maxAmpl); +XMLPUBFUN xmlDocPtr + xmlReadDoc (const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlReadFile (const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlReadMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlReadFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlReadIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlCtxtParseDocument (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN xmlDocPtr + xmlCtxtReadDoc (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlCtxtReadFile (xmlParserCtxtPtr ctxt, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlCtxtReadMemory (xmlParserCtxtPtr ctxt, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlCtxtReadFd (xmlParserCtxtPtr ctxt, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr + xmlCtxtReadIO (xmlParserCtxtPtr ctxt, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +/* + * Library wide options + */ +/** + * xmlFeature: + * + * Used to examine the existence of features that can be enabled + * or disabled at compile-time. + * They used to be called XML_FEATURE_xxx but this clashed with Expat + */ +typedef enum { + XML_WITH_THREAD = 1, + XML_WITH_TREE = 2, + XML_WITH_OUTPUT = 3, + XML_WITH_PUSH = 4, + XML_WITH_READER = 5, + XML_WITH_PATTERN = 6, + XML_WITH_WRITER = 7, + XML_WITH_SAX1 = 8, + XML_WITH_FTP = 9, + XML_WITH_HTTP = 10, + XML_WITH_VALID = 11, + XML_WITH_HTML = 12, + XML_WITH_LEGACY = 13, + XML_WITH_C14N = 14, + XML_WITH_CATALOG = 15, + XML_WITH_XPATH = 16, + XML_WITH_XPTR = 17, + XML_WITH_XINCLUDE = 18, + XML_WITH_ICONV = 19, + XML_WITH_ISO8859X = 20, + XML_WITH_UNICODE = 21, + XML_WITH_REGEXP = 22, + XML_WITH_AUTOMATA = 23, + XML_WITH_EXPR = 24, + XML_WITH_SCHEMAS = 25, + XML_WITH_SCHEMATRON = 26, + XML_WITH_MODULES = 27, + XML_WITH_DEBUG = 28, + XML_WITH_DEBUG_MEM = 29, + XML_WITH_DEBUG_RUN = 30, /* unused */ + XML_WITH_ZLIB = 31, + XML_WITH_ICU = 32, + XML_WITH_LZMA = 33, + XML_WITH_NONE = 99999 /* just to be sure of allocation size */ +} xmlFeature; + +XMLPUBFUN int + xmlHasFeature (xmlFeature feature); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parserInternals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parserInternals.h new file mode 100644 index 00000000..c4d4363b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/parserInternals.h @@ -0,0 +1,671 @@ +/* + * Summary: internals routines and limits exported by the parser. + * Description: this module exports a number of internal parsing routines + * they are not really all intended for applications but + * can prove useful doing low level processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_INTERNALS_H__ +#define __XML_PARSER_INTERNALS_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserMaxDepth: + * + * DEPRECATED: has no effect + * + * arbitrary depth limit for the XML documents that we allow to + * process. This is not a limitation of the parser but a safety + * boundary feature, use XML_PARSE_HUGE option to override it. + */ +XML_DEPRECATED +XMLPUBVAR const unsigned int xmlParserMaxDepth; + +/** + * XML_MAX_TEXT_LENGTH: + * + * Maximum size allowed for a single text node when building a tree. + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Introduced in 2.9.0 + */ +#define XML_MAX_TEXT_LENGTH 10000000 + +/** + * XML_MAX_HUGE_LENGTH: + * + * Maximum size allowed when XML_PARSE_HUGE is set. + */ +#define XML_MAX_HUGE_LENGTH 1000000000 + +/** + * XML_MAX_NAME_LENGTH: + * + * Maximum size allowed for a markup identifier. + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Note that with the use of parsing dictionaries overriding the limit + * may result in more runtime memory usage in face of "unfriendly' content + * Introduced in 2.9.0 + */ +#define XML_MAX_NAME_LENGTH 50000 + +/** + * XML_MAX_DICTIONARY_LIMIT: + * + * Maximum size allowed by the parser for a dictionary by default + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Introduced in 2.9.0 + */ +#define XML_MAX_DICTIONARY_LIMIT 10000000 + +/** + * XML_MAX_LOOKUP_LIMIT: + * + * Maximum size allowed by the parser for ahead lookup + * This is an upper boundary enforced by the parser to avoid bad + * behaviour on "unfriendly' content + * Introduced in 2.9.0 + */ +#define XML_MAX_LOOKUP_LIMIT 10000000 + +/** + * XML_MAX_NAMELEN: + * + * Identifiers can be longer, but this will be more costly + * at runtime. + */ +#define XML_MAX_NAMELEN 100 + +/** + * INPUT_CHUNK: + * + * The parser tries to always have that amount of input ready. + * One of the point is providing context when reporting errors. + */ +#define INPUT_CHUNK 250 + +/************************************************************************ + * * + * UNICODE version of the macros. * + * * + ************************************************************************/ +/** + * IS_BYTE_CHAR: + * @c: an byte value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20...] + * any byte character in the accepted range + */ +#define IS_BYTE_CHAR(c) xmlIsChar_ch(c) + +/** + * IS_CHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] + * | [#x10000-#x10FFFF] + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + */ +#define IS_CHAR(c) xmlIsCharQ(c) + +/** + * IS_CHAR_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Behaves like IS_CHAR on single-byte value + */ +#define IS_CHAR_CH(c) xmlIsChar_ch(c) + +/** + * IS_BLANK: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [3] S ::= (#x20 | #x9 | #xD | #xA)+ + */ +#define IS_BLANK(c) xmlIsBlankQ(c) + +/** + * IS_BLANK_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Behaviour same as IS_BLANK + */ +#define IS_BLANK_CH(c) xmlIsBlank_ch(c) + +/** + * IS_BASECHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [85] BaseChar ::= ... long list see REC ... + */ +#define IS_BASECHAR(c) xmlIsBaseCharQ(c) + +/** + * IS_DIGIT: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [88] Digit ::= ... long list see REC ... + */ +#define IS_DIGIT(c) xmlIsDigitQ(c) + +/** + * IS_DIGIT_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_DIGIT but with a single byte argument + */ +#define IS_DIGIT_CH(c) xmlIsDigit_ch(c) + +/** + * IS_COMBINING: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [87] CombiningChar ::= ... long list see REC ... + */ +#define IS_COMBINING(c) xmlIsCombiningQ(c) + +/** + * IS_COMBINING_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Always false (all combining chars > 0xff) + */ +#define IS_COMBINING_CH(c) 0 + +/** + * IS_EXTENDER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | + * #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] | + * [#x309D-#x309E] | [#x30FC-#x30FE] + */ +#define IS_EXTENDER(c) xmlIsExtenderQ(c) + +/** + * IS_EXTENDER_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_EXTENDER but with a single-byte argument + */ +#define IS_EXTENDER_CH(c) xmlIsExtender_ch(c) + +/** + * IS_IDEOGRAPHIC: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029] + */ +#define IS_IDEOGRAPHIC(c) xmlIsIdeographicQ(c) + +/** + * IS_LETTER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [84] Letter ::= BaseChar | Ideographic + */ +#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c)) + +/** + * IS_LETTER_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Macro behaves like IS_LETTER, but only check base chars + * + */ +#define IS_LETTER_CH(c) xmlIsBaseChar_ch(c) + +/** + * IS_ASCII_LETTER: + * @c: an xmlChar value + * + * Macro to check [a-zA-Z] + * + */ +#define IS_ASCII_LETTER(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a))) + +/** + * IS_ASCII_DIGIT: + * @c: an xmlChar value + * + * Macro to check [0-9] + * + */ +#define IS_ASCII_DIGIT(c) ((0x30 <= (c)) && ((c) <= 0x39)) + +/** + * IS_PUBIDCHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + */ +#define IS_PUBIDCHAR(c) xmlIsPubidCharQ(c) + +/** + * IS_PUBIDCHAR_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Same as IS_PUBIDCHAR but for single-byte value + */ +#define IS_PUBIDCHAR_CH(c) xmlIsPubidChar_ch(c) + +/** + * Global variables used for predefined strings. + */ +XMLPUBVAR const xmlChar xmlStringText[]; +XMLPUBVAR const xmlChar xmlStringTextNoenc[]; +XMLPUBVAR const xmlChar xmlStringComment[]; + +/* + * Function to finish the work of the macros where needed. + */ +XMLPUBFUN int xmlIsLetter (int c); + +/** + * Parser context. + */ +XMLPUBFUN xmlParserCtxtPtr + xmlCreateFileParserCtxt (const char *filename); +XMLPUBFUN xmlParserCtxtPtr + xmlCreateURLParserCtxt (const char *filename, + int options); +XMLPUBFUN xmlParserCtxtPtr + xmlCreateMemoryParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlParserCtxtPtr + xmlCreateEntityParserCtxt(const xmlChar *URL, + const xmlChar *ID, + const xmlChar *base); +XMLPUBFUN void + xmlCtxtErrMemory (xmlParserCtxtPtr ctxt); +XMLPUBFUN int + xmlSwitchEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncoding enc); +XMLPUBFUN int + xmlSwitchEncodingName (xmlParserCtxtPtr ctxt, + const char *encoding); +XMLPUBFUN int + xmlSwitchToEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncodingHandlerPtr handler); +XML_DEPRECATED +XMLPUBFUN int + xmlSwitchInputEncoding (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input, + xmlCharEncodingHandlerPtr handler); + +/** + * Input Streams. + */ +XMLPUBFUN xmlParserInputPtr + xmlNewStringInputStream (xmlParserCtxtPtr ctxt, + const xmlChar *buffer); +XML_DEPRECATED +XMLPUBFUN xmlParserInputPtr + xmlNewEntityInputStream (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); +XMLPUBFUN int + xmlPushInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN xmlChar + xmlPopInput (xmlParserCtxtPtr ctxt); +XMLPUBFUN void + xmlFreeInputStream (xmlParserInputPtr input); +XMLPUBFUN xmlParserInputPtr + xmlNewInputFromFile (xmlParserCtxtPtr ctxt, + const char *filename); +XMLPUBFUN xmlParserInputPtr + xmlNewInputStream (xmlParserCtxtPtr ctxt); + +/** + * Namespaces. + */ +XMLPUBFUN xmlChar * + xmlSplitQName (xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlChar **prefix); + +/** + * Generic production rules. + */ +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlParseName (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseNmtoken (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseEntityValue (xmlParserCtxtPtr ctxt, + xmlChar **orig); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseAttValue (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseSystemLiteral (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParsePubidLiteral (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseCharData (xmlParserCtxtPtr ctxt, + int cdata); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseExternalID (xmlParserCtxtPtr ctxt, + xmlChar **publicID, + int strict); +XML_DEPRECATED +XMLPUBFUN void + xmlParseComment (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlParsePITarget (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParsePI (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseNotationDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseEntityDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int + xmlParseDefaultDecl (xmlParserCtxtPtr ctxt, + xmlChar **value); +XML_DEPRECATED +XMLPUBFUN xmlEnumerationPtr + xmlParseNotationType (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlEnumerationPtr + xmlParseEnumerationType (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int + xmlParseEnumeratedType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XML_DEPRECATED +XMLPUBFUN int + xmlParseAttributeType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XML_DEPRECATED +XMLPUBFUN void + xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlElementContentPtr + xmlParseElementMixedContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XML_DEPRECATED +XMLPUBFUN xmlElementContentPtr + xmlParseElementChildrenContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XML_DEPRECATED +XMLPUBFUN int + xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlElementContentPtr *result); +XML_DEPRECATED +XMLPUBFUN int + xmlParseElementDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseMarkupDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int + xmlParseCharRef (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlEntityPtr + xmlParseEntityRef (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseReference (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParsePEReference (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseDocTypeDecl (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlParseAttribute (xmlParserCtxtPtr ctxt, + xmlChar **value); +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlParseStartTag (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseEndTag (xmlParserCtxtPtr ctxt); +#endif /* LIBXML_SAX1_ENABLED */ +XML_DEPRECATED +XMLPUBFUN void + xmlParseCDSect (xmlParserCtxtPtr ctxt); +XMLPUBFUN void + xmlParseContent (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseElement (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseVersionNum (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseVersionInfo (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseEncName (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN const xmlChar * + xmlParseEncodingDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int + xmlParseSDDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseXMLDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseTextDecl (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseMisc (xmlParserCtxtPtr ctxt); +XMLPUBFUN void + xmlParseExternalSubset (xmlParserCtxtPtr ctxt, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * XML_SUBSTITUTE_NONE: + * + * If no entities need to be substituted. + */ +#define XML_SUBSTITUTE_NONE 0 +/** + * XML_SUBSTITUTE_REF: + * + * Whether general entities need to be substituted. + */ +#define XML_SUBSTITUTE_REF 1 +/** + * XML_SUBSTITUTE_PEREF: + * + * Whether parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_PEREF 2 +/** + * XML_SUBSTITUTE_BOTH: + * + * Both general and parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_BOTH 3 + +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlStringDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlStringLenDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); + +/* + * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP. + */ +XML_DEPRECATED +XMLPUBFUN int nodePush (xmlParserCtxtPtr ctxt, + xmlNodePtr value); +XML_DEPRECATED +XMLPUBFUN xmlNodePtr nodePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int inputPush (xmlParserCtxtPtr ctxt, + xmlParserInputPtr value); +XMLPUBFUN xmlParserInputPtr inputPop (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN const xmlChar * namePop (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int namePush (xmlParserCtxtPtr ctxt, + const xmlChar *value); + +/* + * other commodities shared between parser.c and parserInternals. + */ +XML_DEPRECATED +XMLPUBFUN int xmlSkipBlankChars (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int xmlStringCurrentChar (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + int *len); +XML_DEPRECATED +XMLPUBFUN void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN int xmlCheckLanguageID (const xmlChar *lang); + +/* + * Really core function shared with HTML parser. + */ +XML_DEPRECATED +XMLPUBFUN int xmlCurrentChar (xmlParserCtxtPtr ctxt, + int *len); +XMLPUBFUN int xmlCopyCharMultiByte (xmlChar *out, + int val); +XMLPUBFUN int xmlCopyChar (int len, + xmlChar *out, + int val); +XML_DEPRECATED +XMLPUBFUN void xmlNextChar (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void xmlParserInputShrink (xmlParserInputPtr in); + +/* + * Specific function to keep track of entities references + * and used by the XSLT debugger. + */ +#ifdef LIBXML_LEGACY_ENABLED +/** + * xmlEntityReferenceFunc: + * @ent: the entity + * @firstNode: the fist node in the chunk + * @lastNode: the last nod in the chunk + * + * Callback function used when one needs to be able to track back the + * provenance of a chunk of nodes inherited from an entity replacement. + */ +typedef void (*xmlEntityReferenceFunc) (xmlEntityPtr ent, + xmlNodePtr firstNode, + xmlNodePtr lastNode); + +XML_DEPRECATED +XMLPUBFUN void xmlSetEntityReferenceFunc (xmlEntityReferenceFunc func); + +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlParseQuotedString (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void + xmlParseNamespace (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlNamespaceParseNSDef (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlScanName (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlNamespaceParseNCName (xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN void xmlParserHandleReference(xmlParserCtxtPtr ctxt); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlNamespaceParseQName (xmlParserCtxtPtr ctxt, + xmlChar **prefix); +/** + * Entities + */ +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlDecodeEntities (xmlParserCtxtPtr ctxt, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XML_DEPRECATED +XMLPUBFUN void + xmlHandleEntity (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); + +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_INTERNALS_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/pattern.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/pattern.h new file mode 100644 index 00000000..947f0900 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/pattern.h @@ -0,0 +1,106 @@ +/* + * Summary: pattern expression handling + * Description: allows to compile and test pattern expressions for nodes + * either in a tree or based on a parser state. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PATTERN_H__ +#define __XML_PATTERN_H__ + +#include +#include +#include + +#ifdef LIBXML_PATTERN_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlPattern: + * + * A compiled (XPath based) pattern to select nodes + */ +typedef struct _xmlPattern xmlPattern; +typedef xmlPattern *xmlPatternPtr; + +/** + * xmlPatternFlags: + * + * This is the set of options affecting the behaviour of pattern + * matching with this module + * + */ +typedef enum { + XML_PATTERN_DEFAULT = 0, /* simple pattern match */ + XML_PATTERN_XPATH = 1<<0, /* standard XPath pattern */ + XML_PATTERN_XSSEL = 1<<1, /* XPath subset for schema selector */ + XML_PATTERN_XSFIELD = 1<<2 /* XPath subset for schema field */ +} xmlPatternFlags; + +XMLPUBFUN void + xmlFreePattern (xmlPatternPtr comp); + +XMLPUBFUN void + xmlFreePatternList (xmlPatternPtr comp); + +XMLPUBFUN xmlPatternPtr + xmlPatterncompile (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces); +XMLPUBFUN int + xmlPatternCompileSafe (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces, + xmlPatternPtr *patternOut); +XMLPUBFUN int + xmlPatternMatch (xmlPatternPtr comp, + xmlNodePtr node); + +/* streaming interfaces */ +typedef struct _xmlStreamCtxt xmlStreamCtxt; +typedef xmlStreamCtxt *xmlStreamCtxtPtr; + +XMLPUBFUN int + xmlPatternStreamable (xmlPatternPtr comp); +XMLPUBFUN int + xmlPatternMaxDepth (xmlPatternPtr comp); +XMLPUBFUN int + xmlPatternMinDepth (xmlPatternPtr comp); +XMLPUBFUN int + xmlPatternFromRoot (xmlPatternPtr comp); +XMLPUBFUN xmlStreamCtxtPtr + xmlPatternGetStreamCtxt (xmlPatternPtr comp); +XMLPUBFUN void + xmlFreeStreamCtxt (xmlStreamCtxtPtr stream); +XMLPUBFUN int + xmlStreamPushNode (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns, + int nodeType); +XMLPUBFUN int + xmlStreamPush (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int + xmlStreamPushAttr (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int + xmlStreamPop (xmlStreamCtxtPtr stream); +XMLPUBFUN int + xmlStreamWantsAnyNode (xmlStreamCtxtPtr stream); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_PATTERN_ENABLED */ + +#endif /* __XML_PATTERN_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/relaxng.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/relaxng.h new file mode 100644 index 00000000..079b7f12 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/relaxng.h @@ -0,0 +1,219 @@ +/* + * Summary: implementation of the Relax-NG validation + * Description: implementation of the Relax-NG validation + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_RELAX_NG__ +#define __XML_RELAX_NG__ + +#include +#include +#include +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlRelaxNG xmlRelaxNG; +typedef xmlRelaxNG *xmlRelaxNGPtr; + + +/** + * xmlRelaxNGValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Relax-NG validation + */ +typedef void (*xmlRelaxNGValidityErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlRelaxNGValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Relax-NG validation + */ +typedef void (*xmlRelaxNGValidityWarningFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlRelaxNGParserCtxt xmlRelaxNGParserCtxt; +typedef xmlRelaxNGParserCtxt *xmlRelaxNGParserCtxtPtr; + +typedef struct _xmlRelaxNGValidCtxt xmlRelaxNGValidCtxt; +typedef xmlRelaxNGValidCtxt *xmlRelaxNGValidCtxtPtr; + +/* + * xmlRelaxNGValidErr: + * + * List of possible Relax NG validation errors + */ +typedef enum { + XML_RELAXNG_OK = 0, + XML_RELAXNG_ERR_MEMORY, + XML_RELAXNG_ERR_TYPE, + XML_RELAXNG_ERR_TYPEVAL, + XML_RELAXNG_ERR_DUPID, + XML_RELAXNG_ERR_TYPECMP, + XML_RELAXNG_ERR_NOSTATE, + XML_RELAXNG_ERR_NODEFINE, + XML_RELAXNG_ERR_LISTEXTRA, + XML_RELAXNG_ERR_LISTEMPTY, + XML_RELAXNG_ERR_INTERNODATA, + XML_RELAXNG_ERR_INTERSEQ, + XML_RELAXNG_ERR_INTEREXTRA, + XML_RELAXNG_ERR_ELEMNAME, + XML_RELAXNG_ERR_ATTRNAME, + XML_RELAXNG_ERR_ELEMNONS, + XML_RELAXNG_ERR_ATTRNONS, + XML_RELAXNG_ERR_ELEMWRONGNS, + XML_RELAXNG_ERR_ATTRWRONGNS, + XML_RELAXNG_ERR_ELEMEXTRANS, + XML_RELAXNG_ERR_ATTREXTRANS, + XML_RELAXNG_ERR_ELEMNOTEMPTY, + XML_RELAXNG_ERR_NOELEM, + XML_RELAXNG_ERR_NOTELEM, + XML_RELAXNG_ERR_ATTRVALID, + XML_RELAXNG_ERR_CONTENTVALID, + XML_RELAXNG_ERR_EXTRACONTENT, + XML_RELAXNG_ERR_INVALIDATTR, + XML_RELAXNG_ERR_DATAELEM, + XML_RELAXNG_ERR_VALELEM, + XML_RELAXNG_ERR_LISTELEM, + XML_RELAXNG_ERR_DATATYPE, + XML_RELAXNG_ERR_VALUE, + XML_RELAXNG_ERR_LIST, + XML_RELAXNG_ERR_NOGRAMMAR, + XML_RELAXNG_ERR_EXTRADATA, + XML_RELAXNG_ERR_LACKDATA, + XML_RELAXNG_ERR_INTERNAL, + XML_RELAXNG_ERR_ELEMWRONG, + XML_RELAXNG_ERR_TEXTWRONG +} xmlRelaxNGValidErr; + +/* + * xmlRelaxNGParserFlags: + * + * List of possible Relax NG Parser flags + */ +typedef enum { + XML_RELAXNGP_NONE = 0, + XML_RELAXNGP_FREE_DOC = 1, + XML_RELAXNGP_CRNG = 2 +} xmlRelaxNGParserFlag; + +XMLPUBFUN int + xmlRelaxNGInitTypes (void); +XML_DEPRECATED +XMLPUBFUN void + xmlRelaxNGCleanupTypes (void); + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlRelaxNGParserCtxtPtr + xmlRelaxNGNewParserCtxt (const char *URL); +XMLPUBFUN xmlRelaxNGParserCtxtPtr + xmlRelaxNGNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlRelaxNGParserCtxtPtr + xmlRelaxNGNewDocParserCtxt (xmlDocPtr doc); + +XMLPUBFUN int + xmlRelaxParserSetFlag (xmlRelaxNGParserCtxtPtr ctxt, + int flag); + +XMLPUBFUN void + xmlRelaxNGFreeParserCtxt (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void + xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int + xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void + xmlRelaxNGSetParserStructuredErrors( + xmlRelaxNGParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN xmlRelaxNGPtr + xmlRelaxNGParse (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void + xmlRelaxNGFree (xmlRelaxNGPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlRelaxNGDump (FILE *output, + xmlRelaxNGPtr schema); +XMLPUBFUN void + xmlRelaxNGDumpTree (FILE * output, + xmlRelaxNGPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void + xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int + xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void + xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx); +XMLPUBFUN xmlRelaxNGValidCtxtPtr + xmlRelaxNGNewValidCtxt (xmlRelaxNGPtr schema); +XMLPUBFUN void + xmlRelaxNGFreeValidCtxt (xmlRelaxNGValidCtxtPtr ctxt); +XMLPUBFUN int + xmlRelaxNGValidateDoc (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc); +/* + * Interfaces for progressive validation when possible + */ +XMLPUBFUN int + xmlRelaxNGValidatePushElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int + xmlRelaxNGValidatePushCData (xmlRelaxNGValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XMLPUBFUN int + xmlRelaxNGValidatePopElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int + xmlRelaxNGValidateFullElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ + +#endif /* __XML_RELAX_NG__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schemasInternals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schemasInternals.h new file mode 100644 index 00000000..e9d3b3c7 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schemasInternals.h @@ -0,0 +1,959 @@ +/* + * Summary: internal interfaces for XML Schemas + * Description: internal interfaces for the XML Schemas handling + * and schema validity checking + * The Schemas development is a Work In Progress. + * Some of those interfaces are not guaranteed to be API or ABI stable ! + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_INTERNALS_H__ +#define __XML_SCHEMA_INTERNALS_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMAS_UNKNOWN = 0, + XML_SCHEMAS_STRING = 1, + XML_SCHEMAS_NORMSTRING = 2, + XML_SCHEMAS_DECIMAL = 3, + XML_SCHEMAS_TIME = 4, + XML_SCHEMAS_GDAY = 5, + XML_SCHEMAS_GMONTH = 6, + XML_SCHEMAS_GMONTHDAY = 7, + XML_SCHEMAS_GYEAR = 8, + XML_SCHEMAS_GYEARMONTH = 9, + XML_SCHEMAS_DATE = 10, + XML_SCHEMAS_DATETIME = 11, + XML_SCHEMAS_DURATION = 12, + XML_SCHEMAS_FLOAT = 13, + XML_SCHEMAS_DOUBLE = 14, + XML_SCHEMAS_BOOLEAN = 15, + XML_SCHEMAS_TOKEN = 16, + XML_SCHEMAS_LANGUAGE = 17, + XML_SCHEMAS_NMTOKEN = 18, + XML_SCHEMAS_NMTOKENS = 19, + XML_SCHEMAS_NAME = 20, + XML_SCHEMAS_QNAME = 21, + XML_SCHEMAS_NCNAME = 22, + XML_SCHEMAS_ID = 23, + XML_SCHEMAS_IDREF = 24, + XML_SCHEMAS_IDREFS = 25, + XML_SCHEMAS_ENTITY = 26, + XML_SCHEMAS_ENTITIES = 27, + XML_SCHEMAS_NOTATION = 28, + XML_SCHEMAS_ANYURI = 29, + XML_SCHEMAS_INTEGER = 30, + XML_SCHEMAS_NPINTEGER = 31, + XML_SCHEMAS_NINTEGER = 32, + XML_SCHEMAS_NNINTEGER = 33, + XML_SCHEMAS_PINTEGER = 34, + XML_SCHEMAS_INT = 35, + XML_SCHEMAS_UINT = 36, + XML_SCHEMAS_LONG = 37, + XML_SCHEMAS_ULONG = 38, + XML_SCHEMAS_SHORT = 39, + XML_SCHEMAS_USHORT = 40, + XML_SCHEMAS_BYTE = 41, + XML_SCHEMAS_UBYTE = 42, + XML_SCHEMAS_HEXBINARY = 43, + XML_SCHEMAS_BASE64BINARY = 44, + XML_SCHEMAS_ANYTYPE = 45, + XML_SCHEMAS_ANYSIMPLETYPE = 46 +} xmlSchemaValType; + +/* + * XML Schemas defines multiple type of types. + */ +typedef enum { + XML_SCHEMA_TYPE_BASIC = 1, /* A built-in datatype */ + XML_SCHEMA_TYPE_ANY, + XML_SCHEMA_TYPE_FACET, + XML_SCHEMA_TYPE_SIMPLE, + XML_SCHEMA_TYPE_COMPLEX, + XML_SCHEMA_TYPE_SEQUENCE = 6, + XML_SCHEMA_TYPE_CHOICE, + XML_SCHEMA_TYPE_ALL, + XML_SCHEMA_TYPE_SIMPLE_CONTENT, + XML_SCHEMA_TYPE_COMPLEX_CONTENT, + XML_SCHEMA_TYPE_UR, + XML_SCHEMA_TYPE_RESTRICTION, + XML_SCHEMA_TYPE_EXTENSION, + XML_SCHEMA_TYPE_ELEMENT, + XML_SCHEMA_TYPE_ATTRIBUTE, + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, + XML_SCHEMA_TYPE_GROUP, + XML_SCHEMA_TYPE_NOTATION, + XML_SCHEMA_TYPE_LIST, + XML_SCHEMA_TYPE_UNION, + XML_SCHEMA_TYPE_ANY_ATTRIBUTE, + XML_SCHEMA_TYPE_IDC_UNIQUE, + XML_SCHEMA_TYPE_IDC_KEY, + XML_SCHEMA_TYPE_IDC_KEYREF, + XML_SCHEMA_TYPE_PARTICLE = 25, + XML_SCHEMA_TYPE_ATTRIBUTE_USE, + XML_SCHEMA_FACET_MININCLUSIVE = 1000, + XML_SCHEMA_FACET_MINEXCLUSIVE, + XML_SCHEMA_FACET_MAXINCLUSIVE, + XML_SCHEMA_FACET_MAXEXCLUSIVE, + XML_SCHEMA_FACET_TOTALDIGITS, + XML_SCHEMA_FACET_FRACTIONDIGITS, + XML_SCHEMA_FACET_PATTERN, + XML_SCHEMA_FACET_ENUMERATION, + XML_SCHEMA_FACET_WHITESPACE, + XML_SCHEMA_FACET_LENGTH, + XML_SCHEMA_FACET_MAXLENGTH, + XML_SCHEMA_FACET_MINLENGTH, + XML_SCHEMA_EXTRA_QNAMEREF = 2000, + XML_SCHEMA_EXTRA_ATTR_USE_PROHIB +} xmlSchemaTypeType; + +typedef enum { + XML_SCHEMA_CONTENT_UNKNOWN = 0, + XML_SCHEMA_CONTENT_EMPTY = 1, + XML_SCHEMA_CONTENT_ELEMENTS, + XML_SCHEMA_CONTENT_MIXED, + XML_SCHEMA_CONTENT_SIMPLE, + XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS, /* Obsolete */ + XML_SCHEMA_CONTENT_BASIC, + XML_SCHEMA_CONTENT_ANY +} xmlSchemaContentType; + +typedef struct _xmlSchemaVal xmlSchemaVal; +typedef xmlSchemaVal *xmlSchemaValPtr; + +typedef struct _xmlSchemaType xmlSchemaType; +typedef xmlSchemaType *xmlSchemaTypePtr; + +typedef struct _xmlSchemaFacet xmlSchemaFacet; +typedef xmlSchemaFacet *xmlSchemaFacetPtr; + +/** + * Annotation + */ +typedef struct _xmlSchemaAnnot xmlSchemaAnnot; +typedef xmlSchemaAnnot *xmlSchemaAnnotPtr; +struct _xmlSchemaAnnot { + struct _xmlSchemaAnnot *next; + xmlNodePtr content; /* the annotation */ +}; + +/** + * XML_SCHEMAS_ANYATTR_SKIP: + * + * Skip unknown attribute from validation + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_SKIP 1 +/** + * XML_SCHEMAS_ANYATTR_LAX: + * + * Ignore validation non definition on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_LAX 2 +/** + * XML_SCHEMAS_ANYATTR_STRICT: + * + * Apply strict validation rules on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_STRICT 3 +/** + * XML_SCHEMAS_ANY_SKIP: + * + * Skip unknown attribute from validation + */ +#define XML_SCHEMAS_ANY_SKIP 1 +/** + * XML_SCHEMAS_ANY_LAX: + * + * Used by wildcards. + * Validate if type found, don't worry if not found + */ +#define XML_SCHEMAS_ANY_LAX 2 +/** + * XML_SCHEMAS_ANY_STRICT: + * + * Used by wildcards. + * Apply strict validation rules + */ +#define XML_SCHEMAS_ANY_STRICT 3 +/** + * XML_SCHEMAS_ATTR_USE_PROHIBITED: + * + * Used by wildcards. + * The attribute is prohibited. + */ +#define XML_SCHEMAS_ATTR_USE_PROHIBITED 0 +/** + * XML_SCHEMAS_ATTR_USE_REQUIRED: + * + * The attribute is required. + */ +#define XML_SCHEMAS_ATTR_USE_REQUIRED 1 +/** + * XML_SCHEMAS_ATTR_USE_OPTIONAL: + * + * The attribute is optional. + */ +#define XML_SCHEMAS_ATTR_USE_OPTIONAL 2 +/** + * XML_SCHEMAS_ATTR_GLOBAL: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_GLOBAL 1 << 0 +/** + * XML_SCHEMAS_ATTR_NSDEFAULT: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ATTR_INTERNAL_RESOLVED: + * + * this is set when the "type" and "ref" references + * have been resolved. + */ +#define XML_SCHEMAS_ATTR_INTERNAL_RESOLVED 1 << 8 +/** + * XML_SCHEMAS_ATTR_FIXED: + * + * the attribute has a fixed value + */ +#define XML_SCHEMAS_ATTR_FIXED 1 << 9 + +/** + * xmlSchemaAttribute: + * An attribute definition. + */ + +typedef struct _xmlSchemaAttribute xmlSchemaAttribute; +typedef xmlSchemaAttribute *xmlSchemaAttributePtr; +struct _xmlSchemaAttribute { + xmlSchemaTypeType type; + struct _xmlSchemaAttribute *next; /* the next attribute (not used?) */ + const xmlChar *name; /* the name of the declaration */ + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + const xmlChar *typeName; /* the local name of the type definition */ + const xmlChar *typeNs; /* the ns URI of the type definition */ + xmlSchemaAnnotPtr annot; + + xmlSchemaTypePtr base; /* Deprecated; not used */ + int occurs; /* Deprecated; not used */ + const xmlChar *defValue; /* The initial value of the value constraint */ + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlNodePtr node; + const xmlChar *targetNamespace; + int flags; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value constraint */ + xmlSchemaAttributePtr refDecl; /* Deprecated; not used */ +}; + +/** + * xmlSchemaAttributeLink: + * Used to build a list of attribute uses on complexType definitions. + * WARNING: Deprecated; not used. + */ +typedef struct _xmlSchemaAttributeLink xmlSchemaAttributeLink; +typedef xmlSchemaAttributeLink *xmlSchemaAttributeLinkPtr; +struct _xmlSchemaAttributeLink { + struct _xmlSchemaAttributeLink *next;/* the next attribute link ... */ + struct _xmlSchemaAttribute *attr;/* the linked attribute */ +}; + +/** + * XML_SCHEMAS_WILDCARD_COMPLETE: + * + * If the wildcard is complete. + */ +#define XML_SCHEMAS_WILDCARD_COMPLETE 1 << 0 + +/** + * xmlSchemaCharValueLink: + * Used to build a list of namespaces on wildcards. + */ +typedef struct _xmlSchemaWildcardNs xmlSchemaWildcardNs; +typedef xmlSchemaWildcardNs *xmlSchemaWildcardNsPtr; +struct _xmlSchemaWildcardNs { + struct _xmlSchemaWildcardNs *next;/* the next constraint link ... */ + const xmlChar *value;/* the value */ +}; + +/** + * xmlSchemaWildcard. + * A wildcard. + */ +typedef struct _xmlSchemaWildcard xmlSchemaWildcard; +typedef xmlSchemaWildcard *xmlSchemaWildcardPtr; +struct _xmlSchemaWildcard { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *id; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + int processContents; + int any; /* Indicates if the ns constraint is of ##any */ + xmlSchemaWildcardNsPtr nsSet; /* The list of allowed namespaces */ + xmlSchemaWildcardNsPtr negNsSet; /* The negated namespace */ + int flags; +}; + +/** + * XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED: + * + * The attribute wildcard has been built. + */ +#define XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED 1 << 0 +/** + * XML_SCHEMAS_ATTRGROUP_GLOBAL: + * + * The attribute group has been defined. + */ +#define XML_SCHEMAS_ATTRGROUP_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ATTRGROUP_MARKED: + * + * Marks the attr group as marked; used for circular checks. + */ +#define XML_SCHEMAS_ATTRGROUP_MARKED 1 << 2 + +/** + * XML_SCHEMAS_ATTRGROUP_REDEFINED: + * + * The attr group was redefined. + */ +#define XML_SCHEMAS_ATTRGROUP_REDEFINED 1 << 3 +/** + * XML_SCHEMAS_ATTRGROUP_HAS_REFS: + * + * Whether this attr. group contains attr. group references. + */ +#define XML_SCHEMAS_ATTRGROUP_HAS_REFS 1 << 4 + +/** + * An attribute group definition. + * + * xmlSchemaAttribute and xmlSchemaAttributeGroup start of structures + * must be kept similar + */ +typedef struct _xmlSchemaAttributeGroup xmlSchemaAttributeGroup; +typedef xmlSchemaAttributeGroup *xmlSchemaAttributeGroupPtr; +struct _xmlSchemaAttributeGroup { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaAttribute *next;/* the next attribute if in a group ... */ + const xmlChar *name; + const xmlChar *id; + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int flags; + xmlSchemaWildcardPtr attributeWildcard; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaAttributeGroupPtr refItem; /* Deprecated; not used */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/** + * xmlSchemaTypeLink: + * Used to build a list of types (e.g. member types of + * simpleType with variety "union"). + */ +typedef struct _xmlSchemaTypeLink xmlSchemaTypeLink; +typedef xmlSchemaTypeLink *xmlSchemaTypeLinkPtr; +struct _xmlSchemaTypeLink { + struct _xmlSchemaTypeLink *next;/* the next type link ... */ + xmlSchemaTypePtr type;/* the linked type */ +}; + +/** + * xmlSchemaFacetLink: + * Used to build a list of facets. + */ +typedef struct _xmlSchemaFacetLink xmlSchemaFacetLink; +typedef xmlSchemaFacetLink *xmlSchemaFacetLinkPtr; +struct _xmlSchemaFacetLink { + struct _xmlSchemaFacetLink *next;/* the next facet link ... */ + xmlSchemaFacetPtr facet;/* the linked facet */ +}; + +/** + * XML_SCHEMAS_TYPE_MIXED: + * + * the element content type is mixed + */ +#define XML_SCHEMAS_TYPE_MIXED 1 << 0 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION: + * + * the simple or complex type has a derivation method of "extension". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION 1 << 1 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION: + * + * the simple or complex type has a derivation method of "restriction". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION 1 << 2 +/** + * XML_SCHEMAS_TYPE_GLOBAL: + * + * the type is global + */ +#define XML_SCHEMAS_TYPE_GLOBAL 1 << 3 +/** + * XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD: + * + * the complexType owns an attribute wildcard, i.e. + * it can be freed by the complexType + */ +#define XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD 1 << 4 /* Obsolete. */ +/** + * XML_SCHEMAS_TYPE_VARIETY_ABSENT: + * + * the simpleType has a variety of "absent". + * TODO: Actually not necessary :-/, since if + * none of the variety flags occur then it's + * automatically absent. + */ +#define XML_SCHEMAS_TYPE_VARIETY_ABSENT 1 << 5 +/** + * XML_SCHEMAS_TYPE_VARIETY_LIST: + * + * the simpleType has a variety of "list". + */ +#define XML_SCHEMAS_TYPE_VARIETY_LIST 1 << 6 +/** + * XML_SCHEMAS_TYPE_VARIETY_UNION: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_UNION 1 << 7 +/** + * XML_SCHEMAS_TYPE_VARIETY_ATOMIC: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_ATOMIC 1 << 8 +/** + * XML_SCHEMAS_TYPE_FINAL_EXTENSION: + * + * the complexType has a final of "extension". + */ +#define XML_SCHEMAS_TYPE_FINAL_EXTENSION 1 << 9 +/** + * XML_SCHEMAS_TYPE_FINAL_RESTRICTION: + * + * the simpleType/complexType has a final of "restriction". + */ +#define XML_SCHEMAS_TYPE_FINAL_RESTRICTION 1 << 10 +/** + * XML_SCHEMAS_TYPE_FINAL_LIST: + * + * the simpleType has a final of "list". + */ +#define XML_SCHEMAS_TYPE_FINAL_LIST 1 << 11 +/** + * XML_SCHEMAS_TYPE_FINAL_UNION: + * + * the simpleType has a final of "union". + */ +#define XML_SCHEMAS_TYPE_FINAL_UNION 1 << 12 +/** + * XML_SCHEMAS_TYPE_FINAL_DEFAULT: + * + * the simpleType has a final of "default". + */ +#define XML_SCHEMAS_TYPE_FINAL_DEFAULT 1 << 13 +/** + * XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE: + * + * Marks the item as a builtin primitive. + */ +#define XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE 1 << 14 +/** + * XML_SCHEMAS_TYPE_MARKED: + * + * Marks the item as marked; used for circular checks. + */ +#define XML_SCHEMAS_TYPE_MARKED 1 << 16 +/** + * XML_SCHEMAS_TYPE_BLOCK_DEFAULT: + * + * the complexType did not specify 'block' so use the default of the + * item. + */ +#define XML_SCHEMAS_TYPE_BLOCK_DEFAULT 1 << 17 +/** + * XML_SCHEMAS_TYPE_BLOCK_EXTENSION: + * + * the complexType has a 'block' of "extension". + */ +#define XML_SCHEMAS_TYPE_BLOCK_EXTENSION 1 << 18 +/** + * XML_SCHEMAS_TYPE_BLOCK_RESTRICTION: + * + * the complexType has a 'block' of "restriction". + */ +#define XML_SCHEMAS_TYPE_BLOCK_RESTRICTION 1 << 19 +/** + * XML_SCHEMAS_TYPE_ABSTRACT: + * + * the simple/complexType is abstract. + */ +#define XML_SCHEMAS_TYPE_ABSTRACT 1 << 20 +/** + * XML_SCHEMAS_TYPE_FACETSNEEDVALUE: + * + * indicates if the facets need a computed value + */ +#define XML_SCHEMAS_TYPE_FACETSNEEDVALUE 1 << 21 +/** + * XML_SCHEMAS_TYPE_INTERNAL_RESOLVED: + * + * indicates that the type was typefixed + */ +#define XML_SCHEMAS_TYPE_INTERNAL_RESOLVED 1 << 22 +/** + * XML_SCHEMAS_TYPE_INTERNAL_INVALID: + * + * indicates that the type is invalid + */ +#define XML_SCHEMAS_TYPE_INTERNAL_INVALID 1 << 23 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE: + * + * a whitespace-facet value of "preserve" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE 1 << 24 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_REPLACE: + * + * a whitespace-facet value of "replace" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_REPLACE 1 << 25 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE: + * + * a whitespace-facet value of "collapse" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE 1 << 26 +/** + * XML_SCHEMAS_TYPE_HAS_FACETS: + * + * has facets + */ +#define XML_SCHEMAS_TYPE_HAS_FACETS 1 << 27 +/** + * XML_SCHEMAS_TYPE_NORMVALUENEEDED: + * + * indicates if the facets (pattern) need a normalized value + */ +#define XML_SCHEMAS_TYPE_NORMVALUENEEDED 1 << 28 + +/** + * XML_SCHEMAS_TYPE_FIXUP_1: + * + * First stage of fixup was done. + */ +#define XML_SCHEMAS_TYPE_FIXUP_1 1 << 29 + +/** + * XML_SCHEMAS_TYPE_REDEFINED: + * + * The type was redefined. + */ +#define XML_SCHEMAS_TYPE_REDEFINED 1 << 30 +/** + * XML_SCHEMAS_TYPE_REDEFINING: + * + * The type redefines an other type. + */ +/* #define XML_SCHEMAS_TYPE_REDEFINING 1 << 31 */ + +/** + * _xmlSchemaType: + * + * Schemas type definition. + */ +struct _xmlSchemaType { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* the next type if in a sequence ... */ + const xmlChar *name; + const xmlChar *id ; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + xmlSchemaContentType contentType; + const xmlChar *base; /* Base type's local name */ + const xmlChar *baseNs; /* Base type's target namespace */ + xmlSchemaTypePtr baseType; /* The base type component */ + xmlSchemaFacetPtr facets; /* Local facets */ + struct _xmlSchemaType *redef; /* Deprecated; not used */ + int recurse; /* Obsolete */ + xmlSchemaAttributeLinkPtr *attributeUses; /* Deprecated; not used */ + xmlSchemaWildcardPtr attributeWildcard; + int builtInType; /* Type of built-in types. */ + xmlSchemaTypeLinkPtr memberTypes; /* member-types if a union type. */ + xmlSchemaFacetLinkPtr facetSet; /* All facets (incl. inherited) */ + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaTypePtr contentTypeDef; /* Used for the simple content of complex types. + Could we use @subtypes for this? */ + xmlRegexpPtr contModel; /* Holds the automaton of the content model */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/* + * xmlSchemaElement: + * An element definition. + * + * xmlSchemaType, xmlSchemaFacet and xmlSchemaElement start of + * structures must be kept similar + */ +/** + * XML_SCHEMAS_ELEM_NILLABLE: + * + * the element is nillable + */ +#define XML_SCHEMAS_ELEM_NILLABLE 1 << 0 +/** + * XML_SCHEMAS_ELEM_GLOBAL: + * + * the element is global + */ +#define XML_SCHEMAS_ELEM_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ELEM_DEFAULT: + * + * the element has a default value + */ +#define XML_SCHEMAS_ELEM_DEFAULT 1 << 2 +/** + * XML_SCHEMAS_ELEM_FIXED: + * + * the element has a fixed value + */ +#define XML_SCHEMAS_ELEM_FIXED 1 << 3 +/** + * XML_SCHEMAS_ELEM_ABSTRACT: + * + * the element is abstract + */ +#define XML_SCHEMAS_ELEM_ABSTRACT 1 << 4 +/** + * XML_SCHEMAS_ELEM_TOPLEVEL: + * + * the element is top level + * obsolete: use XML_SCHEMAS_ELEM_GLOBAL instead + */ +#define XML_SCHEMAS_ELEM_TOPLEVEL 1 << 5 +/** + * XML_SCHEMAS_ELEM_REF: + * + * the element is a reference to a type + */ +#define XML_SCHEMAS_ELEM_REF 1 << 6 +/** + * XML_SCHEMAS_ELEM_NSDEFAULT: + * + * allow elements in no namespace + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ELEM_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ELEM_INTERNAL_RESOLVED: + * + * this is set when "type", "ref", "substitutionGroup" + * references have been resolved. + */ +#define XML_SCHEMAS_ELEM_INTERNAL_RESOLVED 1 << 8 + /** + * XML_SCHEMAS_ELEM_CIRCULAR: + * + * a helper flag for the search of circular references. + */ +#define XML_SCHEMAS_ELEM_CIRCULAR 1 << 9 +/** + * XML_SCHEMAS_ELEM_BLOCK_ABSENT: + * + * the "block" attribute is absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_ABSENT 1 << 10 +/** + * XML_SCHEMAS_ELEM_BLOCK_EXTENSION: + * + * disallowed substitutions are absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_EXTENSION 1 << 11 +/** + * XML_SCHEMAS_ELEM_BLOCK_RESTRICTION: + * + * disallowed substitutions: "restriction" + */ +#define XML_SCHEMAS_ELEM_BLOCK_RESTRICTION 1 << 12 +/** + * XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION: + * + * disallowed substitutions: "substitution" + */ +#define XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION 1 << 13 +/** + * XML_SCHEMAS_ELEM_FINAL_ABSENT: + * + * substitution group exclusions are absent + */ +#define XML_SCHEMAS_ELEM_FINAL_ABSENT 1 << 14 +/** + * XML_SCHEMAS_ELEM_FINAL_EXTENSION: + * + * substitution group exclusions: "extension" + */ +#define XML_SCHEMAS_ELEM_FINAL_EXTENSION 1 << 15 +/** + * XML_SCHEMAS_ELEM_FINAL_RESTRICTION: + * + * substitution group exclusions: "restriction" + */ +#define XML_SCHEMAS_ELEM_FINAL_RESTRICTION 1 << 16 +/** + * XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD: + * + * the declaration is a substitution group head + */ +#define XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD 1 << 17 +/** + * XML_SCHEMAS_ELEM_INTERNAL_CHECKED: + * + * this is set when the elem decl has been checked against + * all constraints + */ +#define XML_SCHEMAS_ELEM_INTERNAL_CHECKED 1 << 18 + +typedef struct _xmlSchemaElement xmlSchemaElement; +typedef xmlSchemaElement *xmlSchemaElementPtr; +struct _xmlSchemaElement { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* Not used? */ + const xmlChar *name; + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlSchemaAttributePtr attributes; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + const xmlChar *targetNamespace; + const xmlChar *namedType; + const xmlChar *namedTypeNs; + const xmlChar *substGroup; + const xmlChar *substGroupNs; + const xmlChar *scope; + const xmlChar *value; /* The original value of the value constraint. */ + struct _xmlSchemaElement *refDecl; /* This will now be used for the + substitution group affiliation */ + xmlRegexpPtr contModel; /* Obsolete for WXS, maybe used for RelaxNG */ + xmlSchemaContentType contentType; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value constraint. */ + void *idcs; /* The identity-constraint defs */ +}; + +/* + * XML_SCHEMAS_FACET_UNKNOWN: + * + * unknown facet handling + */ +#define XML_SCHEMAS_FACET_UNKNOWN 0 +/* + * XML_SCHEMAS_FACET_PRESERVE: + * + * preserve the type of the facet + */ +#define XML_SCHEMAS_FACET_PRESERVE 1 +/* + * XML_SCHEMAS_FACET_REPLACE: + * + * replace the type of the facet + */ +#define XML_SCHEMAS_FACET_REPLACE 2 +/* + * XML_SCHEMAS_FACET_COLLAPSE: + * + * collapse the types of the facet + */ +#define XML_SCHEMAS_FACET_COLLAPSE 3 +/** + * A facet definition. + */ +struct _xmlSchemaFacet { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaFacet *next;/* the next type if in a sequence ... */ + const xmlChar *value; /* The original value */ + const xmlChar *id; /* Obsolete */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int fixed; /* XML_SCHEMAS_FACET_PRESERVE, etc. */ + int whitespace; + xmlSchemaValPtr val; /* The compiled value */ + xmlRegexpPtr regexp; /* The regex for patterns */ +}; + +/** + * A notation definition. + */ +typedef struct _xmlSchemaNotation xmlSchemaNotation; +typedef xmlSchemaNotation *xmlSchemaNotationPtr; +struct _xmlSchemaNotation { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *name; + xmlSchemaAnnotPtr annot; + const xmlChar *identifier; + const xmlChar *targetNamespace; +}; + +/* +* TODO: Actually all those flags used for the schema should sit +* on the schema parser context, since they are used only +* during parsing an XML schema document, and not available +* on the component level as per spec. +*/ +/** + * XML_SCHEMAS_QUALIF_ELEM: + * + * Reflects elementFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ELEM 1 << 0 +/** + * XML_SCHEMAS_QUALIF_ATTR: + * + * Reflects attributeFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ATTR 1 << 1 +/** + * XML_SCHEMAS_FINAL_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_EXTENSION 1 << 2 +/** + * XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION 1 << 3 +/** + * XML_SCHEMAS_FINAL_DEFAULT_LIST: + * + * the schema has "list" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_LIST 1 << 4 +/** + * XML_SCHEMAS_FINAL_DEFAULT_UNION: + * + * the schema has "union" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_UNION 1 << 5 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION 1 << 6 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION 1 << 7 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION: + * + * the schema has "substitution" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION 1 << 8 +/** + * XML_SCHEMAS_INCLUDING_CONVERT_NS: + * + * the schema is currently including an other schema with + * no target namespace. + */ +#define XML_SCHEMAS_INCLUDING_CONVERT_NS 1 << 9 +/** + * _xmlSchema: + * + * A Schemas definition + */ +struct _xmlSchema { + const xmlChar *name; /* schema name */ + const xmlChar *targetNamespace; /* the target namespace */ + const xmlChar *version; + const xmlChar *id; /* Obsolete */ + xmlDocPtr doc; + xmlSchemaAnnotPtr annot; + int flags; + + xmlHashTablePtr typeDecl; + xmlHashTablePtr attrDecl; + xmlHashTablePtr attrgrpDecl; + xmlHashTablePtr elemDecl; + xmlHashTablePtr notaDecl; + + xmlHashTablePtr schemasImports; + + void *_private; /* unused by the library for users or bindings */ + xmlHashTablePtr groupDecl; + xmlDictPtr dict; + void *includes; /* the includes, this is opaque for now */ + int preserve; /* whether to free the document */ + int counter; /* used to give anonymous components unique names */ + xmlHashTablePtr idcDef; /* All identity-constraint defs. */ + void *volatiles; /* Obsolete */ +}; + +XMLPUBFUN void xmlSchemaFreeType (xmlSchemaTypePtr type); +XMLPUBFUN void xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_INTERNALS_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schematron.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schematron.h new file mode 100644 index 00000000..8dd8d25c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/schematron.h @@ -0,0 +1,143 @@ +/* + * Summary: XML Schematron implementation + * Description: interface to the XML Schematron validity checking. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMATRON_H__ +#define __XML_SCHEMATRON_H__ + +#include + +#ifdef LIBXML_SCHEMATRON_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMATRON_OUT_QUIET = 1 << 0, /* quiet no report */ + XML_SCHEMATRON_OUT_TEXT = 1 << 1, /* build a textual report */ + XML_SCHEMATRON_OUT_XML = 1 << 2, /* output SVRL */ + XML_SCHEMATRON_OUT_ERROR = 1 << 3, /* output via xmlStructuredErrorFunc */ + XML_SCHEMATRON_OUT_FILE = 1 << 8, /* output to a file descriptor */ + XML_SCHEMATRON_OUT_BUFFER = 1 << 9, /* output to a buffer */ + XML_SCHEMATRON_OUT_IO = 1 << 10 /* output to I/O mechanism */ +} xmlSchematronValidOptions; + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchematron xmlSchematron; +typedef xmlSchematron *xmlSchematronPtr; + +/** + * xmlSchematronValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityErrorFunc) (void *ctx, const char *msg, ...); + +/** + * xmlSchematronValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityWarningFunc) (void *ctx, const char *msg, ...); + +/** + * A schemas validation context + */ +typedef struct _xmlSchematronParserCtxt xmlSchematronParserCtxt; +typedef xmlSchematronParserCtxt *xmlSchematronParserCtxtPtr; + +typedef struct _xmlSchematronValidCtxt xmlSchematronValidCtxt; +typedef xmlSchematronValidCtxt *xmlSchematronValidCtxtPtr; + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchematronParserCtxtPtr + xmlSchematronNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchematronParserCtxtPtr + xmlSchematronNewMemParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlSchematronParserCtxtPtr + xmlSchematronNewDocParserCtxt(xmlDocPtr doc); +XMLPUBFUN void + xmlSchematronFreeParserCtxt (xmlSchematronParserCtxtPtr ctxt); +/***** +XMLPUBFUN void + xmlSchematronSetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int + xmlSchematronGetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc * err, + xmlSchematronValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int + xmlSchematronIsValid (xmlSchematronValidCtxtPtr ctxt); + *****/ +XMLPUBFUN xmlSchematronPtr + xmlSchematronParse (xmlSchematronParserCtxtPtr ctxt); +XMLPUBFUN void + xmlSchematronFree (xmlSchematronPtr schema); +/* + * Interfaces for validating + */ +XMLPUBFUN void + xmlSchematronSetValidStructuredErrors( + xmlSchematronValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +/****** +XMLPUBFUN void + xmlSchematronSetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int + xmlSchematronGetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc *err, + xmlSchematronValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int + xmlSchematronSetValidOptions(xmlSchematronValidCtxtPtr ctxt, + int options); +XMLPUBFUN int + xmlSchematronValidCtxtGetOptions(xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int + xmlSchematronValidateOneElement (xmlSchematronValidCtxtPtr ctxt, + xmlNodePtr elem); + *******/ + +XMLPUBFUN xmlSchematronValidCtxtPtr + xmlSchematronNewValidCtxt (xmlSchematronPtr schema, + int options); +XMLPUBFUN void + xmlSchematronFreeValidCtxt (xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int + xmlSchematronValidateDoc (xmlSchematronValidCtxtPtr ctxt, + xmlDocPtr instance); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMATRON_ENABLED */ +#endif /* __XML_SCHEMATRON_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/threads.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/threads.h new file mode 100644 index 00000000..8f4b6e17 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/threads.h @@ -0,0 +1,87 @@ +/** + * Summary: interfaces for thread handling + * Description: set of generic threading related routines + * should work with pthreads, Windows native or TLS threads + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_THREADS_H__ +#define __XML_THREADS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlMutex are a simple mutual exception locks. + */ +typedef struct _xmlMutex xmlMutex; +typedef xmlMutex *xmlMutexPtr; + +/* + * xmlRMutex are reentrant mutual exception locks. + */ +typedef struct _xmlRMutex xmlRMutex; +typedef xmlRMutex *xmlRMutexPtr; + +XMLPUBFUN int + xmlCheckThreadLocalStorage(void); + +XMLPUBFUN xmlMutexPtr + xmlNewMutex (void); +XMLPUBFUN void + xmlMutexLock (xmlMutexPtr tok); +XMLPUBFUN void + xmlMutexUnlock (xmlMutexPtr tok); +XMLPUBFUN void + xmlFreeMutex (xmlMutexPtr tok); + +XMLPUBFUN xmlRMutexPtr + xmlNewRMutex (void); +XMLPUBFUN void + xmlRMutexLock (xmlRMutexPtr tok); +XMLPUBFUN void + xmlRMutexUnlock (xmlRMutexPtr tok); +XMLPUBFUN void + xmlFreeRMutex (xmlRMutexPtr tok); + +/* + * Library wide APIs. + */ +XML_DEPRECATED +XMLPUBFUN void + xmlInitThreads (void); +XMLPUBFUN void + xmlLockLibrary (void); +XMLPUBFUN void + xmlUnlockLibrary(void); +XML_DEPRECATED +XMLPUBFUN int + xmlGetThreadId (void); +XML_DEPRECATED +XMLPUBFUN int + xmlIsMainThread (void); +XML_DEPRECATED +XMLPUBFUN void + xmlCleanupThreads(void); + +/** DOC_DISABLE */ +#if defined(LIBXML_THREAD_ENABLED) && defined(_WIN32) && \ + defined(LIBXML_STATIC_FOR_DLL) +int +xmlDllMain(void *hinstDLL, unsigned long fdwReason, + void *lpvReserved); +#endif +/** DOC_ENABLE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __XML_THREADS_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/tree.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/tree.h new file mode 100644 index 00000000..4070375b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/tree.h @@ -0,0 +1,1382 @@ +/* + * Summary: interfaces for tree manipulation + * Description: this module describes the structures found in an tree resulting + * from an XML or HTML parsing, as well as the API provided for + * various processing on that tree + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef XML_TREE_INTERNALS + +/* + * Emulate circular dependency for backward compatibility + */ +#include + +#else /* XML_TREE_INTERNALS */ + +#ifndef __XML_TREE_H__ +#define __XML_TREE_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Some of the basic types pointer to structures: + */ +/* xmlIO.h */ +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; + +/* parser.h */ +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; + +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; + +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; + +/* entities.h */ +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; + +/** + * BASE_BUFFER_SIZE: + * + * default buffer size 4000. + */ +#define BASE_BUFFER_SIZE 4096 + +/** + * LIBXML_NAMESPACE_DICT: + * + * Defines experimental behaviour: + * 1) xmlNs gets an additional field @context (a xmlDoc) + * 2) when creating a tree, xmlNs->href is stored in the dict of xmlDoc. + */ +/* #define LIBXML_NAMESPACE_DICT */ + +/** + * xmlBufferAllocationScheme: + * + * A buffer allocation scheme can be defined to either match exactly the + * need or double it's allocated size each time it is found too small. + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, /* double each time one need to grow */ + XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */ + XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer, deprecated */ + XML_BUFFER_ALLOC_IO, /* special allocation scheme used for I/O */ + XML_BUFFER_ALLOC_HYBRID, /* exact up to a threshold, and doubleit thereafter */ + XML_BUFFER_ALLOC_BOUNDED /* limit the upper size of the buffer */ +} xmlBufferAllocationScheme; + +/** + * xmlBuffer: + * + * A buffer structure, this old construct is limited to 2GB and + * is being deprecated, use API with xmlBuf instead + */ +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ + xmlChar *contentIO; /* in IO mode we may have a different base */ +}; + +/** + * xmlBuf: + * + * A buffer structure, new one, the actual structure internals are not public + */ + +typedef struct _xmlBuf xmlBuf; + +/** + * xmlBufPtr: + * + * A pointer to a buffer structure, the actual structure internals are not + * public + */ + +typedef xmlBuf *xmlBufPtr; + +/* + * A few public routines for xmlBuf. As those are expected to be used + * mostly internally the bulk of the routines are internal in buf.h + */ +XMLPUBFUN xmlChar* xmlBufContent (const xmlBuf* buf); +XMLPUBFUN xmlChar* xmlBufEnd (xmlBufPtr buf); +XMLPUBFUN size_t xmlBufUse (const xmlBufPtr buf); +XMLPUBFUN size_t xmlBufShrink (xmlBufPtr buf, size_t len); + +/* + * LIBXML2_NEW_BUFFER: + * + * Macro used to express that the API use the new buffers for + * xmlParserInputBuffer and xmlOutputBuffer. The change was + * introduced in 2.9.0. + */ +#define LIBXML2_NEW_BUFFER + +/** + * XML_XML_NAMESPACE: + * + * This is the namespace for the special xml: prefix predefined in the + * XML Namespace specification. + */ +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/** + * XML_XML_ID: + * + * This is the name for the special xml:id attribute + */ +#define XML_XML_ID (const xmlChar *) "xml:id" + +/* + * The different element types carried by an XML tree. + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, /* unused */ + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, /* unused */ + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, /* unused */ + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 + /* XML_DOCB_DOCUMENT_NODE= 21 */ /* removed */ +} xmlElementType; + +/** DOC_DISABLE */ +/* For backward compatibility */ +#define XML_DOCB_DOCUMENT_NODE 21 +/** DOC_ENABLE */ + +/** + * xmlNotation: + * + * A DTD Notation definition. + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/** + * xmlAttributeType: + * + * A DTD Attribute type definition. + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +/** + * xmlAttributeDefault: + * + * A DTD Attribute default definition. + */ + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +/** + * xmlEnumeration: + * + * List structure used when there is an enumeration in DTDs. + */ + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +/** + * xmlAttribute: + * + * An Attribute declaration in a DTD. + */ + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/** + * xmlElementContentType: + * + * Possible definitions of element content types. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +/** + * xmlElementContentOccur: + * + * Possible definitions of element content occurrences. + */ +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +/** + * xmlElementContent: + * + * An XML Element content as stored after parsing an element definition + * in a DTD. + */ + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ + const xmlChar *prefix; /* Namespace prefix */ +}; + +/** + * xmlElementTypeVal: + * + * The different possibilities for an element content type. + */ + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +/** + * xmlElement: + * + * An XML Element declaration from a DTD. + */ + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { + void *_private; /* application data */ + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +#ifdef LIBXML_REGEXP_ENABLED + xmlRegexpPtr contModel; /* the validating regexp */ +#else + void *contModel; +#endif +}; + + +/** + * XML_LOCAL_NAMESPACE: + * + * A namespace declaration node. + */ +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +/** + * xmlNs: + * + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overridden). + * + * xmlNsType is unified with xmlElementType. + */ + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ + void *_private; /* application data */ + struct _xmlDoc *context; /* normally an xmlDoc */ +}; + +/** + * xmlDtd: + * + * An XML DTD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/** + * xmlAttr: + * + * An attribute on an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ + void *psvi; /* for type/PSVI information */ + struct _xmlID *id; /* the ID struct */ +}; + +/** + * xmlID: + * + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ + struct _xmlDoc *doc; /* The document holding the ID */ +}; + +/** + * xmlRef: + * + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ +}; + +/** + * xmlNode: + * + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { + void *_private; /* application data */ + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlChar *content; /* the content */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ + void *psvi; /* for type/PSVI information */ + unsigned short line; /* line number */ + unsigned short extra; /* extra data for XPath/XSLT */ +}; + +/** + * XML_GET_CONTENT: + * + * Macro to extract the content pointer of a node. + */ +#define XML_GET_CONTENT(n) \ + ((n)->type == XML_ELEMENT_NODE ? NULL : (n)->content) + +/** + * XML_GET_LINE: + * + * Macro to extract the line number of an element node. + */ +#define XML_GET_LINE(n) \ + (xmlGetLineNo(n)) + +/** + * xmlDocProperty + * + * Set of properties of the document as found by the parser + * Some of them are linked to similarly named xmlParserOption + */ +typedef enum { + XML_DOC_WELLFORMED = 1<<0, /* document is XML well formed */ + XML_DOC_NSVALID = 1<<1, /* document is Namespace valid */ + XML_DOC_OLD10 = 1<<2, /* parsed with old XML-1.0 parser */ + XML_DOC_DTDVALID = 1<<3, /* DTD validation was successful */ + XML_DOC_XINCLUDE = 1<<4, /* XInclude substitution was done */ + XML_DOC_USERBUILT = 1<<5, /* Document was built using the API + and not by parsing an instance */ + XML_DOC_INTERNAL = 1<<6, /* built for internal processing */ + XML_DOC_HTML = 1<<7 /* parsed or built HTML document */ +} xmlDocProperties; + +/** + * xmlDoc: + * + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { + void *_private; /* application data */ + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) + 1 if standalone="yes" + 0 if standalone="no" + -1 if there is no XML declaration + -2 if there is an XML declaration, but no + standalone attribute was specified */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* actual encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* unused */ + struct _xmlDict *dict; /* dict used to allocate names or NULL */ + void *psvi; /* for type/PSVI information */ + int parseFlags; /* set of xmlParserOption used to parse the + document */ + int properties; /* set of xmlDocProperties for this document + set at the end of parsing */ +}; + + +typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt; +typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr; + +/** + * xmlDOMWrapAcquireNsFunction: + * @ctxt: a DOM wrapper context + * @node: the context node (element or attribute) + * @nsName: the requested namespace name + * @nsPrefix: the requested namespace prefix + * + * A function called to acquire namespaces (xmlNs) from the wrapper. + * + * Returns an xmlNsPtr or NULL in case of an error. + */ +typedef xmlNsPtr (*xmlDOMWrapAcquireNsFunction) (xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr node, + const xmlChar *nsName, + const xmlChar *nsPrefix); + +/** + * xmlDOMWrapCtxt: + * + * Context for DOM wrapper-operations. + */ +struct _xmlDOMWrapCtxt { + void * _private; + /* + * The type of this context, just in case we need specialized + * contexts in the future. + */ + int type; + /* + * Internal namespace map used for various operations. + */ + void * namespaceMap; + /* + * Use this one to acquire an xmlNsPtr intended for node->ns. + * (Note that this is not intended for elem->nsDef). + */ + xmlDOMWrapAcquireNsFunction getNsForNodeFunc; +}; + +/** + * xmlRegisterNodeFunc: + * @node: the current node + * + * Signature for the registration callback of a created node + */ +typedef void (*xmlRegisterNodeFunc) (xmlNodePtr node); + +/** + * xmlDeregisterNodeFunc: + * @node: the current node + * + * Signature for the deregistration callback of a discarded node + */ +typedef void (*xmlDeregisterNodeFunc) (xmlNodePtr node); + +/** + * xmlChildrenNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children." + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#endif + +/** + * xmlRootNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children". + */ +#ifndef xmlRootNode +#define xmlRootNode children +#endif + +/* + * Variables. + */ + +/** DOC_DISABLE */ +#define XML_GLOBALS_TREE \ + XML_OP(xmlBufferAllocScheme, xmlBufferAllocationScheme, XML_DEPRECATED) \ + XML_OP(xmlDefaultBufferSize, int, XML_DEPRECATED) \ + XML_OP(xmlRegisterNodeDefaultValue, xmlRegisterNodeFunc, XML_DEPRECATED) \ + XML_OP(xmlDeregisterNodeDefaultValue, xmlDeregisterNodeFunc, \ + XML_DEPRECATED) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_TREE +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlBufferAllocScheme XML_GLOBAL_MACRO(xmlBufferAllocScheme) + #define xmlDefaultBufferSize XML_GLOBAL_MACRO(xmlDefaultBufferSize) + #define xmlRegisterNodeDefaultValue \ + XML_GLOBAL_MACRO(xmlRegisterNodeDefaultValue) + #define xmlDeregisterNodeDefaultValue \ + XML_GLOBAL_MACRO(xmlDeregisterNodeDefaultValue) +#endif +/** DOC_ENABLE */ + +/* + * Some helper functions + */ +XMLPUBFUN int + xmlValidateNCName (const xmlChar *value, + int space); + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int + xmlValidateQName (const xmlChar *value, + int space); +XMLPUBFUN int + xmlValidateName (const xmlChar *value, + int space); +XMLPUBFUN int + xmlValidateNMToken (const xmlChar *value, + int space); +#endif + +XMLPUBFUN xmlChar * + xmlBuildQName (const xmlChar *ncname, + const xmlChar *prefix, + xmlChar *memory, + int len); +XMLPUBFUN xmlChar * + xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); +XMLPUBFUN const xmlChar * + xmlSplitQName3 (const xmlChar *name, + int *len); + +/* + * Handling Buffers, the old ones see @xmlBuf for the new ones. + */ + +XMLPUBFUN void + xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme); +XMLPUBFUN xmlBufferAllocationScheme + xmlGetBufferAllocationScheme(void); + +XMLPUBFUN xmlBufferPtr + xmlBufferCreate (void); +XMLPUBFUN xmlBufferPtr + xmlBufferCreateSize (size_t size); +XMLPUBFUN xmlBufferPtr + xmlBufferCreateStatic (void *mem, + size_t size); +XMLPUBFUN int + xmlBufferResize (xmlBufferPtr buf, + unsigned int size); +XMLPUBFUN void + xmlBufferFree (xmlBufferPtr buf); +XMLPUBFUN int + xmlBufferDump (FILE *file, + xmlBufferPtr buf); +XMLPUBFUN int + xmlBufferAdd (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int + xmlBufferAddHead (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int + xmlBufferCat (xmlBufferPtr buf, + const xmlChar *str); +XMLPUBFUN int + xmlBufferCCat (xmlBufferPtr buf, + const char *str); +XMLPUBFUN int + xmlBufferShrink (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN int + xmlBufferGrow (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN void + xmlBufferEmpty (xmlBufferPtr buf); +XMLPUBFUN const xmlChar* + xmlBufferContent (const xmlBuffer *buf); +XMLPUBFUN xmlChar* + xmlBufferDetach (xmlBufferPtr buf); +XMLPUBFUN void + xmlBufferSetAllocationScheme(xmlBufferPtr buf, + xmlBufferAllocationScheme scheme); +XMLPUBFUN int + xmlBufferLength (const xmlBuffer *buf); + +/* + * Creating/freeing new structures. + */ +XMLPUBFUN xmlDtdPtr + xmlCreateIntSubset (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr + xmlNewDtd (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr + xmlGetIntSubset (const xmlDoc *doc); +XMLPUBFUN void + xmlFreeDtd (xmlDtdPtr cur); +#ifdef LIBXML_LEGACY_ENABLED +XML_DEPRECATED +XMLPUBFUN xmlNsPtr + xmlNewGlobalNs (xmlDocPtr doc, + const xmlChar *href, + const xmlChar *prefix); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlNsPtr + xmlNewNs (xmlNodePtr node, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void + xmlFreeNs (xmlNsPtr cur); +XMLPUBFUN void + xmlFreeNsList (xmlNsPtr cur); +XMLPUBFUN xmlDocPtr + xmlNewDoc (const xmlChar *version); +XMLPUBFUN void + xmlFreeDoc (xmlDocPtr cur); +XMLPUBFUN xmlAttrPtr + xmlNewDocProp (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *value); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlAttrPtr + xmlNewProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +#endif +XMLPUBFUN xmlAttrPtr + xmlNewNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr + xmlNewNsPropEatName (xmlNodePtr node, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *value); +XMLPUBFUN void + xmlFreePropList (xmlAttrPtr cur); +XMLPUBFUN void + xmlFreeProp (xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr + xmlCopyProp (xmlNodePtr target, + xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr + xmlCopyPropList (xmlNodePtr target, + xmlAttrPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlDtdPtr + xmlCopyDtd (xmlDtdPtr dtd); +#endif /* LIBXML_TREE_ENABLED */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlDocPtr + xmlCopyDoc (xmlDocPtr doc, + int recursive); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ +/* + * Creating new nodes. + */ +XMLPUBFUN xmlNodePtr + xmlNewDocNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewDocNodeEatName (xmlDocPtr doc, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewNode (xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN xmlNodePtr + xmlNewNodeEatName (xmlNsPtr ns, + xmlChar *name); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNodePtr + xmlNewChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +#endif +XMLPUBFUN xmlNodePtr + xmlNewDocText (const xmlDoc *doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewText (const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewDocPI (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewPI (const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewDocTextLen (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr + xmlNewTextLen (const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr + xmlNewDocComment (xmlDocPtr doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewComment (const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewCDataBlock (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr + xmlNewCharRef (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr + xmlNewReference (const xmlDoc *doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr + xmlCopyNode (xmlNodePtr node, + int recursive); +XMLPUBFUN xmlNodePtr + xmlDocCopyNode (xmlNodePtr node, + xmlDocPtr doc, + int recursive); +XMLPUBFUN xmlNodePtr + xmlDocCopyNodeList (xmlDocPtr doc, + xmlNodePtr node); +XMLPUBFUN xmlNodePtr + xmlCopyNodeList (xmlNodePtr node); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNodePtr + xmlNewTextChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewDocRawNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr + xmlNewDocFragment (xmlDocPtr doc); +#endif /* LIBXML_TREE_ENABLED */ + +/* + * Navigating. + */ +XMLPUBFUN long + xmlGetLineNo (const xmlNode *node); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +XMLPUBFUN xmlChar * + xmlGetNodePath (const xmlNode *node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) */ +XMLPUBFUN xmlNodePtr + xmlDocGetRootElement (const xmlDoc *doc); +XMLPUBFUN xmlNodePtr + xmlGetLastChild (const xmlNode *parent); +XMLPUBFUN int + xmlNodeIsText (const xmlNode *node); +XMLPUBFUN int + xmlIsBlankNode (const xmlNode *node); + +/* + * Changing the structure. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr + xmlDocSetRootElement (xmlDocPtr doc, + xmlNodePtr root); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void + xmlNodeSetName (xmlNodePtr cur, + const xmlChar *name); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN xmlNodePtr + xmlAddChild (xmlNodePtr parent, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr + xmlAddChildList (xmlNodePtr parent, + xmlNodePtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr + xmlReplaceNode (xmlNodePtr old, + xmlNodePtr cur); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +XMLPUBFUN xmlNodePtr + xmlAddPrevSibling (xmlNodePtr cur, + xmlNodePtr elem); +#endif /* LIBXML_TREE_ENABLED || LIBXML_HTML_ENABLED || LIBXML_SCHEMAS_ENABLED */ +XMLPUBFUN xmlNodePtr + xmlAddSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN xmlNodePtr + xmlAddNextSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN void + xmlUnlinkNode (xmlNodePtr cur); +XMLPUBFUN xmlNodePtr + xmlTextMerge (xmlNodePtr first, + xmlNodePtr second); +XMLPUBFUN int + xmlTextConcat (xmlNodePtr node, + const xmlChar *content, + int len); +XMLPUBFUN void + xmlFreeNodeList (xmlNodePtr cur); +XMLPUBFUN void + xmlFreeNode (xmlNodePtr cur); +XMLPUBFUN int + xmlSetTreeDoc (xmlNodePtr tree, + xmlDocPtr doc); +XMLPUBFUN int + xmlSetListDoc (xmlNodePtr list, + xmlDocPtr doc); +/* + * Namespaces. + */ +XMLPUBFUN xmlNsPtr + xmlSearchNs (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *nameSpace); +XMLPUBFUN xmlNsPtr + xmlSearchNsByHref (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *href); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int + xmlGetNsListSafe (const xmlDoc *doc, + const xmlNode *node, + xmlNsPtr **out); +XMLPUBFUN xmlNsPtr * + xmlGetNsList (const xmlDoc *doc, + const xmlNode *node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) */ + +XMLPUBFUN void + xmlSetNs (xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN xmlNsPtr + xmlCopyNamespace (xmlNsPtr cur); +XMLPUBFUN xmlNsPtr + xmlCopyNamespaceList (xmlNsPtr cur); + +/* + * Changing the content. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) +XMLPUBFUN xmlAttrPtr + xmlSetProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr + xmlSetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) */ +XMLPUBFUN int + xmlNodeGetAttrValue (const xmlNode *node, + const xmlChar *name, + const xmlChar *nsUri, + xmlChar **out); +XMLPUBFUN xmlChar * + xmlGetNoNsProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlChar * + xmlGetProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr + xmlHasProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr + xmlHasNsProp (const xmlNode *node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlChar * + xmlGetNsProp (const xmlNode *node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlNodePtr + xmlStringGetNodeList (const xmlDoc *doc, + const xmlChar *value); +XMLPUBFUN xmlNodePtr + xmlStringLenGetNodeList (const xmlDoc *doc, + const xmlChar *value, + int len); +XMLPUBFUN xmlChar * + xmlNodeListGetString (xmlDocPtr doc, + const xmlNode *list, + int inLine); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlChar * + xmlNodeListGetRawString (const xmlDoc *doc, + const xmlNode *list, + int inLine); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN int + xmlNodeSetContent (xmlNodePtr cur, + const xmlChar *content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN int + xmlNodeSetContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN int + xmlNodeAddContent (xmlNodePtr cur, + const xmlChar *content); +XMLPUBFUN int + xmlNodeAddContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +XMLPUBFUN xmlChar * + xmlNodeGetContent (const xmlNode *cur); + +XMLPUBFUN int + xmlNodeBufGetContent (xmlBufferPtr buffer, + const xmlNode *cur); +XMLPUBFUN int + xmlBufGetNodeContent (xmlBufPtr buf, + const xmlNode *cur); + +XMLPUBFUN xmlChar * + xmlNodeGetLang (const xmlNode *cur); +XMLPUBFUN int + xmlNodeGetSpacePreserve (const xmlNode *cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN int + xmlNodeSetLang (xmlNodePtr cur, + const xmlChar *lang); +XMLPUBFUN int + xmlNodeSetSpacePreserve (xmlNodePtr cur, + int val); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN int + xmlNodeGetBaseSafe (const xmlDoc *doc, + const xmlNode *cur, + xmlChar **baseOut); +XMLPUBFUN xmlChar * + xmlNodeGetBase (const xmlDoc *doc, + const xmlNode *cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +XMLPUBFUN int + xmlNodeSetBase (xmlNodePtr cur, + const xmlChar *uri); +#endif + +/* + * Removing content. + */ +XMLPUBFUN int + xmlRemoveProp (xmlAttrPtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int + xmlUnsetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN int + xmlUnsetProp (xmlNodePtr node, + const xmlChar *name); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ + +/* + * Internal, don't use. + */ +XMLPUBFUN void + xmlBufferWriteCHAR (xmlBufferPtr buf, + const xmlChar *string); +XMLPUBFUN void + xmlBufferWriteChar (xmlBufferPtr buf, + const char *string); +XMLPUBFUN void + xmlBufferWriteQuotedString(xmlBufferPtr buf, + const xmlChar *string); + +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void xmlAttrSerializeTxtContent(xmlBufferPtr buf, + xmlDocPtr doc, + xmlAttrPtr attr, + const xmlChar *string); +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_TREE_ENABLED +/* + * Namespace handling. + */ +XMLPUBFUN int + xmlReconciliateNs (xmlDocPtr doc, + xmlNodePtr tree); +#endif + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Saving. + */ +XMLPUBFUN void + xmlDocDumpFormatMemory (xmlDocPtr cur, + xmlChar **mem, + int *size, + int format); +XMLPUBFUN void + xmlDocDumpMemory (xmlDocPtr cur, + xmlChar **mem, + int *size); +XMLPUBFUN void + xmlDocDumpMemoryEnc (xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding); +XMLPUBFUN void + xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding, + int format); +XMLPUBFUN int + xmlDocFormatDump (FILE *f, + xmlDocPtr cur, + int format); +XMLPUBFUN int + xmlDocDump (FILE *f, + xmlDocPtr cur); +XMLPUBFUN void + xmlElemDump (FILE *f, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN int + xmlSaveFile (const char *filename, + xmlDocPtr cur); +XMLPUBFUN int + xmlSaveFormatFile (const char *filename, + xmlDocPtr cur, + int format); +XMLPUBFUN size_t + xmlBufNodeDump (xmlBufPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format); +XMLPUBFUN int + xmlNodeDump (xmlBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format); + +XMLPUBFUN int + xmlSaveFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN int + xmlSaveFormatFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding, + int format); +XMLPUBFUN void + xmlNodeDumpOutput (xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format, + const char *encoding); + +XMLPUBFUN int + xmlSaveFormatFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding, + int format); + +XMLPUBFUN int + xmlSaveFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding); + +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * XHTML + */ +XMLPUBFUN int + xmlIsXHTML (const xmlChar *systemID, + const xmlChar *publicID); + +/* + * Compression. + */ +XMLPUBFUN int + xmlGetDocCompressMode (const xmlDoc *doc); +XMLPUBFUN void + xmlSetDocCompressMode (xmlDocPtr doc, + int mode); +XML_DEPRECATED +XMLPUBFUN int + xmlGetCompressMode (void); +XML_DEPRECATED +XMLPUBFUN void + xmlSetCompressMode (int mode); + +/* +* DOM-wrapper helper functions. +*/ +XMLPUBFUN xmlDOMWrapCtxtPtr + xmlDOMWrapNewCtxt (void); +XMLPUBFUN void + xmlDOMWrapFreeCtxt (xmlDOMWrapCtxtPtr ctxt); +XMLPUBFUN int + xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr elem, + int options); +XMLPUBFUN int + xmlDOMWrapAdoptNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options); +XMLPUBFUN int + xmlDOMWrapRemoveNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr node, + int options); +XMLPUBFUN int + xmlDOMWrapCloneNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlNodePtr *clonedNode, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int deep, + int options); + +#ifdef LIBXML_TREE_ENABLED +/* + * 5 interfaces from DOM ElementTraversal, but different in entities + * traversal. + */ +XMLPUBFUN unsigned long + xmlChildElementCount (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr + xmlNextElementSibling (xmlNodePtr node); +XMLPUBFUN xmlNodePtr + xmlFirstElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr + xmlLastElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr + xmlPreviousElementSibling (xmlNodePtr node); +#endif + +XML_DEPRECATED +XMLPUBFUN xmlRegisterNodeFunc + xmlRegisterNodeDefault (xmlRegisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlDeregisterNodeFunc + xmlDeregisterNodeDefault (xmlDeregisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlRegisterNodeFunc + xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); +XML_DEPRECATED +XMLPUBFUN xmlDeregisterNodeFunc + xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func); + +XML_DEPRECATED XMLPUBFUN xmlBufferAllocationScheme + xmlThrDefBufferAllocScheme (xmlBufferAllocationScheme v); +XML_DEPRECATED XMLPUBFUN int + xmlThrDefDefaultBufferSize (int v); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_TREE_H__ */ + +#endif /* XML_TREE_INTERNALS */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/uri.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/uri.h new file mode 100644 index 00000000..19980b71 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/uri.h @@ -0,0 +1,106 @@ +/** + * Summary: library of generic URI related routines + * Description: library of generic URI related routines + * Implements RFC 2396 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_URI_H__ +#define __XML_URI_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlURI: + * + * A parsed URI reference. This is a struct containing the various fields + * as described in RFC 2396 but separated for further processing. + * + * Note: query is a deprecated field which is incorrectly unescaped. + * query_raw takes precedence over query if the former is set. + * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00127 + */ +typedef struct _xmlURI xmlURI; +typedef xmlURI *xmlURIPtr; +struct _xmlURI { + char *scheme; /* the URI scheme */ + char *opaque; /* opaque part */ + char *authority; /* the authority part */ + char *server; /* the server part */ + char *user; /* the user part */ + int port; /* the port number */ + char *path; /* the path string */ + char *query; /* the query string (deprecated - use with caution) */ + char *fragment; /* the fragment identifier */ + int cleanup; /* parsing potentially unclean URI */ + char *query_raw; /* the query string (as it appears in the URI) */ +}; + +/* + * This function is in tree.h: + * xmlChar * xmlNodeGetBase (xmlDocPtr doc, + * xmlNodePtr cur); + */ +XMLPUBFUN xmlURIPtr + xmlCreateURI (void); +XMLPUBFUN int + xmlBuildURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); +XMLPUBFUN xmlChar * + xmlBuildURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN int + xmlBuildRelativeURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); +XMLPUBFUN xmlChar * + xmlBuildRelativeURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN xmlURIPtr + xmlParseURI (const char *str); +XMLPUBFUN int + xmlParseURISafe (const char *str, + xmlURIPtr *uri); +XMLPUBFUN xmlURIPtr + xmlParseURIRaw (const char *str, + int raw); +XMLPUBFUN int + xmlParseURIReference (xmlURIPtr uri, + const char *str); +XMLPUBFUN xmlChar * + xmlSaveUri (xmlURIPtr uri); +XMLPUBFUN void + xmlPrintURI (FILE *stream, + xmlURIPtr uri); +XMLPUBFUN xmlChar * + xmlURIEscapeStr (const xmlChar *str, + const xmlChar *list); +XMLPUBFUN char * + xmlURIUnescapeString (const char *str, + int len, + char *target); +XMLPUBFUN int + xmlNormalizeURIPath (char *path); +XMLPUBFUN xmlChar * + xmlURIEscape (const xmlChar *str); +XMLPUBFUN void + xmlFreeURI (xmlURIPtr uri); +XMLPUBFUN xmlChar* + xmlCanonicPath (const xmlChar *path); +XMLPUBFUN xmlChar* + xmlPathToURI (const xmlChar *path); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_URI_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/valid.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/valid.h new file mode 100644 index 00000000..e1698d7a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/valid.h @@ -0,0 +1,477 @@ +/* + * Summary: The DTD validation + * Description: API for the DTD handling and the validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_VALID_H__ +#define __XML_VALID_H__ + +/** DOC_DISABLE */ +#include +#include +#define XML_TREE_INTERNALS +#include +#undef XML_TREE_INTERNALS +#include +#include +#include +/** DOC_ENABLE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Validation state added for non-determinist content model. + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * xmlValidityErrorFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity error is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (*xmlValidityErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlValidityWarningFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity warning is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (*xmlValidityWarningFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/* + * xmlValidCtxt: + * An xmlValidCtxt is used for error reporting when validating. + */ +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + unsigned int flags; /* internal flags */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ + +#ifdef LIBXML_REGEXP_ENABLED + xmlAutomataPtr am; /* the automata */ + xmlAutomataStatePtr state; /* used to build the automata */ +#else + void *am; + void *state; +#endif +}; + +/* + * ALL notation declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALL element declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALL attribute declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALL IDs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALL Refs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* Notation */ +XMLPUBFUN xmlNotationPtr + xmlAddNotationDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *PublicID, + const xmlChar *SystemID); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNotationTablePtr + xmlCopyNotationTable (xmlNotationTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void + xmlFreeNotationTable (xmlNotationTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlDumpNotationDecl (xmlBufferPtr buf, + xmlNotationPtr nota); +/* XML_DEPRECATED, still used in lxml */ +XMLPUBFUN void + xmlDumpNotationTable (xmlBufferPtr buf, + xmlNotationTablePtr table); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Element Content */ +/* the non Doc version are being deprecated */ +XMLPUBFUN xmlElementContentPtr + xmlNewElementContent (const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr + xmlCopyElementContent (xmlElementContentPtr content); +XMLPUBFUN void + xmlFreeElementContent (xmlElementContentPtr cur); +/* the new versions with doc argument */ +XMLPUBFUN xmlElementContentPtr + xmlNewDocElementContent (xmlDocPtr doc, + const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr + xmlCopyDocElementContent(xmlDocPtr doc, + xmlElementContentPtr content); +XMLPUBFUN void + xmlFreeDocElementContent(xmlDocPtr doc, + xmlElementContentPtr cur); +XMLPUBFUN void + xmlSnprintfElementContent(char *buf, + int size, + xmlElementContentPtr content, + int englob); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlSprintfElementContent(char *buf, + xmlElementContentPtr content, + int englob); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Element */ +XMLPUBFUN xmlElementPtr + xmlAddElementDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + xmlElementTypeVal type, + xmlElementContentPtr content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlElementTablePtr + xmlCopyElementTable (xmlElementTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void + xmlFreeElementTable (xmlElementTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlDumpElementTable (xmlBufferPtr buf, + xmlElementTablePtr table); +XML_DEPRECATED +XMLPUBFUN void + xmlDumpElementDecl (xmlBufferPtr buf, + xmlElementPtr elem); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Enumeration */ +XMLPUBFUN xmlEnumerationPtr + xmlCreateEnumeration (const xmlChar *name); +XMLPUBFUN void + xmlFreeEnumeration (xmlEnumerationPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEnumerationPtr + xmlCopyEnumeration (xmlEnumerationPtr cur); +#endif /* LIBXML_TREE_ENABLED */ + +/* Attribute */ +XMLPUBFUN xmlAttributePtr + xmlAddAttributeDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *ns, + xmlAttributeType type, + xmlAttributeDefault def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlAttributeTablePtr + xmlCopyAttributeTable (xmlAttributeTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void + xmlFreeAttributeTable (xmlAttributeTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN void + xmlDumpAttributeTable (xmlBufferPtr buf, + xmlAttributeTablePtr table); +XML_DEPRECATED +XMLPUBFUN void + xmlDumpAttributeDecl (xmlBufferPtr buf, + xmlAttributePtr attr); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* IDs */ +XMLPUBFUN int + xmlAddIDSafe (xmlAttrPtr attr, + const xmlChar *value); +XMLPUBFUN xmlIDPtr + xmlAddID (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XMLPUBFUN void + xmlFreeIDTable (xmlIDTablePtr table); +XMLPUBFUN xmlAttrPtr + xmlGetID (xmlDocPtr doc, + const xmlChar *ID); +XMLPUBFUN int + xmlIsID (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XMLPUBFUN int + xmlRemoveID (xmlDocPtr doc, + xmlAttrPtr attr); + +/* IDREFs */ +XML_DEPRECATED +XMLPUBFUN xmlRefPtr + xmlAddRef (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XML_DEPRECATED +XMLPUBFUN void + xmlFreeRefTable (xmlRefTablePtr table); +XML_DEPRECATED +XMLPUBFUN int + xmlIsRef (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XML_DEPRECATED +XMLPUBFUN int + xmlRemoveRef (xmlDocPtr doc, + xmlAttrPtr attr); +XML_DEPRECATED +XMLPUBFUN xmlListPtr + xmlGetRefs (xmlDocPtr doc, + const xmlChar *ID); + +/** + * The public function calls related to validity checking. + */ +#ifdef LIBXML_VALID_ENABLED +/* Allocate/Release Validation Contexts */ +XMLPUBFUN xmlValidCtxtPtr + xmlNewValidCtxt(void); +XMLPUBFUN void + xmlFreeValidCtxt(xmlValidCtxtPtr); + +XML_DEPRECATED +XMLPUBFUN int + xmlValidateRoot (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateElementDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlElementPtr elem); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlValidNormalizeAttributeValue(xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlAttributePtr attr); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateAttributeValue(xmlAttributeType type, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateNotationDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNotationPtr nota); +XMLPUBFUN int + xmlValidateDtd (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlDtdPtr dtd); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateDtdFinal (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int + xmlValidateDocument (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int + xmlValidateElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateOneElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateOneNamespace (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *prefix, + xmlNsPtr ns, + const xmlChar *value); +XML_DEPRECATED +XMLPUBFUN int + xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +#endif /* LIBXML_VALID_ENABLED */ + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XML_DEPRECATED +XMLPUBFUN int + xmlValidateNotationUse (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *notationName); +#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +XMLPUBFUN int + xmlIsMixedElement (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr + xmlGetDtdAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr + xmlGetDtdQAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlNotationPtr + xmlGetDtdNotationDesc (xmlDtdPtr dtd, + const xmlChar *name); +XMLPUBFUN xmlElementPtr + xmlGetDtdQElementDesc (xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlElementPtr + xmlGetDtdElementDesc (xmlDtdPtr dtd, + const xmlChar *name); + +#ifdef LIBXML_VALID_ENABLED + +XMLPUBFUN int + xmlValidGetPotentialChildren(xmlElementContent *ctree, + const xmlChar **names, + int *len, + int max); + +XMLPUBFUN int + xmlValidGetValidElements(xmlNode *prev, + xmlNode *next, + const xmlChar **names, + int max); +XMLPUBFUN int + xmlValidateNameValue (const xmlChar *value); +XMLPUBFUN int + xmlValidateNamesValue (const xmlChar *value); +XMLPUBFUN int + xmlValidateNmtokenValue (const xmlChar *value); +XMLPUBFUN int + xmlValidateNmtokensValue(const xmlChar *value); + +#ifdef LIBXML_REGEXP_ENABLED +/* + * Validation based on the regexp support + */ +XML_DEPRECATED +XMLPUBFUN int + xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, + xmlElementPtr elem); + +XML_DEPRECATED +XMLPUBFUN int + xmlValidatePushElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +XML_DEPRECATED +XMLPUBFUN int + xmlValidatePushCData (xmlValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XML_DEPRECATED +XMLPUBFUN int + xmlValidatePopElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +#endif /* LIBXML_REGEXP_ENABLED */ +#endif /* LIBXML_VALID_ENABLED */ +#ifdef __cplusplus +} +#endif +#endif /* __XML_VALID_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xinclude.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xinclude.h new file mode 100644 index 00000000..71fa4c20 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xinclude.h @@ -0,0 +1,136 @@ +/* + * Summary: implementation of XInclude + * Description: API to handle XInclude processing, + * implements the + * World Wide Web Consortium Last Call Working Draft 10 November 2003 + * http://www.w3.org/TR/2003/WD-xinclude-20031110 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XINCLUDE_H__ +#define __XML_XINCLUDE_H__ + +#include +#include +#include + +#ifdef LIBXML_XINCLUDE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XINCLUDE_NS: + * + * Macro defining the Xinclude namespace: http://www.w3.org/2003/XInclude + */ +#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2003/XInclude" +/** + * XINCLUDE_OLD_NS: + * + * Macro defining the draft Xinclude namespace: http://www.w3.org/2001/XInclude + */ +#define XINCLUDE_OLD_NS (const xmlChar *) "http://www.w3.org/2001/XInclude" +/** + * XINCLUDE_NODE: + * + * Macro defining "include" + */ +#define XINCLUDE_NODE (const xmlChar *) "include" +/** + * XINCLUDE_FALLBACK: + * + * Macro defining "fallback" + */ +#define XINCLUDE_FALLBACK (const xmlChar *) "fallback" +/** + * XINCLUDE_HREF: + * + * Macro defining "href" + */ +#define XINCLUDE_HREF (const xmlChar *) "href" +/** + * XINCLUDE_PARSE: + * + * Macro defining "parse" + */ +#define XINCLUDE_PARSE (const xmlChar *) "parse" +/** + * XINCLUDE_PARSE_XML: + * + * Macro defining "xml" + */ +#define XINCLUDE_PARSE_XML (const xmlChar *) "xml" +/** + * XINCLUDE_PARSE_TEXT: + * + * Macro defining "text" + */ +#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text" +/** + * XINCLUDE_PARSE_ENCODING: + * + * Macro defining "encoding" + */ +#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding" +/** + * XINCLUDE_PARSE_XPOINTER: + * + * Macro defining "xpointer" + */ +#define XINCLUDE_PARSE_XPOINTER (const xmlChar *) "xpointer" + +typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt; +typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr; + +/* + * standalone processing + */ +XMLPUBFUN int + xmlXIncludeProcess (xmlDocPtr doc); +XMLPUBFUN int + xmlXIncludeProcessFlags (xmlDocPtr doc, + int flags); +XMLPUBFUN int + xmlXIncludeProcessFlagsData(xmlDocPtr doc, + int flags, + void *data); +XMLPUBFUN int + xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, + int flags, + void *data); +XMLPUBFUN int + xmlXIncludeProcessTree (xmlNodePtr tree); +XMLPUBFUN int + xmlXIncludeProcessTreeFlags(xmlNodePtr tree, + int flags); +/* + * contextual processing + */ +XMLPUBFUN xmlXIncludeCtxtPtr + xmlXIncludeNewContext (xmlDocPtr doc); +XMLPUBFUN int + xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, + int flags); +XMLPUBFUN void + xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); +XMLPUBFUN int + xmlXIncludeGetLastError (xmlXIncludeCtxtPtr ctxt); +XMLPUBFUN void + xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); +XMLPUBFUN int + xmlXIncludeProcessNode (xmlXIncludeCtxtPtr ctxt, + xmlNodePtr tree); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XINCLUDE_ENABLED */ + +#endif /* __XML_XINCLUDE_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xlink.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xlink.h new file mode 100644 index 00000000..10657366 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xlink.h @@ -0,0 +1,189 @@ +/* + * Summary: unfinished XLink detection module + * Description: unfinished XLink detection module + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XLINK_H__ +#define __XML_XLINK_H__ + +#include +#include + +#ifdef LIBXML_XPTR_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Various defines for the various Link properties. + * + * NOTE: the link detection layer will try to resolve QName expansion + * of namespaces. If "foo" is the prefix for "http://foo.com/" + * then the link detection layer will expand role="foo:myrole" + * to "http://foo.com/:myrole". + * NOTE: the link detection layer will expand URI-References found on + * href attributes by using the base mechanism if found. + */ +typedef xmlChar *xlinkHRef; +typedef xmlChar *xlinkRole; +typedef xmlChar *xlinkTitle; + +typedef enum { + XLINK_TYPE_NONE = 0, + XLINK_TYPE_SIMPLE, + XLINK_TYPE_EXTENDED, + XLINK_TYPE_EXTENDED_SET +} xlinkType; + +typedef enum { + XLINK_SHOW_NONE = 0, + XLINK_SHOW_NEW, + XLINK_SHOW_EMBED, + XLINK_SHOW_REPLACE +} xlinkShow; + +typedef enum { + XLINK_ACTUATE_NONE = 0, + XLINK_ACTUATE_AUTO, + XLINK_ACTUATE_ONREQUEST +} xlinkActuate; + +/** + * xlinkNodeDetectFunc: + * @ctx: user data pointer + * @node: the node to check + * + * This is the prototype for the link detection routine. + * It calls the default link detection callbacks upon link detection. + */ +typedef void (*xlinkNodeDetectFunc) (void *ctx, xmlNodePtr node); + +/* + * The link detection module interact with the upper layers using + * a set of callback registered at parsing time. + */ + +/** + * xlinkSimpleLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @href: the target of the link + * @role: the role string + * @title: the link title + * + * This is the prototype for a simple link detection callback. + */ +typedef void +(*xlinkSimpleLinkFunk) (void *ctx, + xmlNodePtr node, + const xlinkHRef href, + const xlinkRole role, + const xlinkTitle title); + +/** + * xlinkExtendedLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbArcs: the number of arcs detected on the link + * @from: pointer to the array of source roles found on the arcs + * @to: pointer to the array of target roles found on the arcs + * @show: array of values for the show attributes found on the arcs + * @actuate: array of values for the actuate attributes found on the arcs + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link detection callback. + */ +typedef void +(*xlinkExtendedLinkFunk)(void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbArcs, + const xlinkRole *from, + const xlinkRole *to, + xlinkShow *show, + xlinkActuate *actuate, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * xlinkExtendedLinkSetFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link set detection callback. + */ +typedef void +(*xlinkExtendedLinkSetFunk) (void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * This is the structure containing a set of Links detection callbacks. + * + * There is no default xlink callbacks, if one want to get link + * recognition activated, those call backs must be provided before parsing. + */ +typedef struct _xlinkHandler xlinkHandler; +typedef xlinkHandler *xlinkHandlerPtr; +struct _xlinkHandler { + xlinkSimpleLinkFunk simple; + xlinkExtendedLinkFunk extended; + xlinkExtendedLinkSetFunk set; +}; + +/* + * The default detection routine, can be overridden, they call the default + * detection callbacks. + */ + +XMLPUBFUN xlinkNodeDetectFunc + xlinkGetDefaultDetect (void); +XMLPUBFUN void + xlinkSetDefaultDetect (xlinkNodeDetectFunc func); + +/* + * Routines to set/get the default handlers. + */ +XMLPUBFUN xlinkHandlerPtr + xlinkGetDefaultHandler (void); +XMLPUBFUN void + xlinkSetDefaultHandler (xlinkHandlerPtr handler); + +/* + * Link detection module itself. + */ +XMLPUBFUN xlinkType + xlinkIsLink (xmlDocPtr doc, + xmlNodePtr node); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ + +#endif /* __XML_XLINK_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlIO.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlIO.h new file mode 100644 index 00000000..5a35dc64 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlIO.h @@ -0,0 +1,438 @@ +/* + * Summary: interface for the I/O interfaces used by the parser + * Description: interface for the I/O interfaces used by the parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_IO_H__ +#define __XML_IO_H__ + +/** DOC_DISABLE */ +#include +#include +#include +#define XML_TREE_INTERNALS +#include +#undef XML_TREE_INTERNALS +/** DOC_ENABLE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Those are the functions and datatypes for the parser input + * I/O structures. + */ + +/** + * xmlInputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to detect if the current handler + * can provide input functionality for this resource. + * + * Returns 1 if yes and 0 if another Input module should be used + */ +typedef int (*xmlInputMatchCallback) (char const *filename); +/** + * xmlInputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to open the resource + * + * Returns an Input context or NULL in case or error + */ +typedef void * (*xmlInputOpenCallback) (char const *filename); +/** + * xmlInputReadCallback: + * @context: an Input context + * @buffer: the buffer to store data read + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Input API to read the resource + * + * Returns the number of bytes read or -1 in case of error + */ +typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); +/** + * xmlInputCloseCallback: + * @context: an Input context + * + * Callback used in the I/O Input API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (*xmlInputCloseCallback) (void * context); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +/** + * xmlOutputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to detect if the current handler + * can provide output functionality for this resource. + * + * Returns 1 if yes and 0 if another Output module should be used + */ +typedef int (*xmlOutputMatchCallback) (char const *filename); +/** + * xmlOutputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to open the resource + * + * Returns an Output context or NULL in case or error + */ +typedef void * (*xmlOutputOpenCallback) (char const *filename); +/** + * xmlOutputWriteCallback: + * @context: an Output context + * @buffer: the buffer of data to write + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Output API to write to the resource + * + * Returns the number of bytes written or -1 in case of error + */ +typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +/** + * xmlOutputCloseCallback: + * @context: an Output context + * + * Callback used in the I/O Output API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (*xmlOutputCloseCallback) (void * context); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateFilenameFunc: + * @URI: the URI to read from + * @enc: the requested source encoding + * + * Signature for the function doing the lookup for a suitable input method + * corresponding to an URI. + * + * Returns the new xmlParserInputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlParserInputBufferPtr +(*xmlParserInputBufferCreateFilenameFunc)(const char *URI, xmlCharEncoding enc); + +/** + * xmlOutputBufferCreateFilenameFunc: + * @URI: the URI to write to + * @enc: the requested target encoding + * + * Signature for the function doing the lookup for a suitable output method + * corresponding to an URI. + * + * Returns the new xmlOutputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlOutputBufferPtr +(*xmlOutputBufferCreateFilenameFunc)(const char *URI, + xmlCharEncodingHandlerPtr encoder, int compression); + +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufPtr raw; /* if encoder != NULL buffer for raw input */ + int compressed; /* -1=unknown, 0=not compressed, 1=compressed */ + int error; + unsigned long rawconsumed;/* amount consumed from raw */ +}; + + +#ifdef LIBXML_OUTPUT_ENABLED +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ + int error; +}; +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** DOC_DISABLE */ +#define XML_GLOBALS_IO \ + XML_OP(xmlParserInputBufferCreateFilenameValue, \ + xmlParserInputBufferCreateFilenameFunc, XML_DEPRECATED) \ + XML_OP(xmlOutputBufferCreateFilenameValue, \ + xmlOutputBufferCreateFilenameFunc, XML_DEPRECATED) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_IO +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlParserInputBufferCreateFilenameValue \ + XML_GLOBAL_MACRO(xmlParserInputBufferCreateFilenameValue) + #define xmlOutputBufferCreateFilenameValue \ + XML_GLOBAL_MACRO(xmlOutputBufferCreateFilenameValue) +#endif +/** DOC_ENABLE */ + +/* + * Interfaces for input + */ +XMLPUBFUN void + xmlCleanupInputCallbacks (void); + +XMLPUBFUN int + xmlPopInputCallbacks (void); + +XMLPUBFUN void + xmlRegisterDefaultInputCallbacks (void); +XMLPUBFUN xmlParserInputBufferPtr + xmlAllocParserInputBuffer (xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateFilename (const char *URI, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateFile (FILE *file, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateFd (int fd, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateMem (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateStatic (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr + xmlParserInputBufferCreateIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); +XMLPUBFUN int + xmlParserInputBufferRead (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int + xmlParserInputBufferGrow (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int + xmlParserInputBufferPush (xmlParserInputBufferPtr in, + int len, + const char *buf); +XMLPUBFUN void + xmlFreeParserInputBuffer (xmlParserInputBufferPtr in); +XMLPUBFUN char * + xmlParserGetDirectory (const char *filename); + +XMLPUBFUN int + xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, + xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc); + +xmlParserInputBufferPtr + __xmlParserInputBufferCreateFilename(const char *URI, + xmlCharEncoding enc); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Interfaces for output + */ +XMLPUBFUN void + xmlCleanupOutputCallbacks (void); +XMLPUBFUN int + xmlPopOutputCallbacks (void); +XMLPUBFUN void + xmlRegisterDefaultOutputCallbacks(void); +XMLPUBFUN xmlOutputBufferPtr + xmlAllocOutputBuffer (xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr + xmlOutputBufferCreateFilename (const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +XMLPUBFUN xmlOutputBufferPtr + xmlOutputBufferCreateFile (FILE *file, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr + xmlOutputBufferCreateBuffer (xmlBufferPtr buffer, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr + xmlOutputBufferCreateFd (int fd, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr + xmlOutputBufferCreateIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + xmlCharEncodingHandlerPtr encoder); + +/* Couple of APIs to get the output without digging into the buffers */ +XMLPUBFUN const xmlChar * + xmlOutputBufferGetContent (xmlOutputBufferPtr out); +XMLPUBFUN size_t + xmlOutputBufferGetSize (xmlOutputBufferPtr out); + +XMLPUBFUN int + xmlOutputBufferWrite (xmlOutputBufferPtr out, + int len, + const char *buf); +XMLPUBFUN int + xmlOutputBufferWriteString (xmlOutputBufferPtr out, + const char *str); +XMLPUBFUN int + xmlOutputBufferWriteEscape (xmlOutputBufferPtr out, + const xmlChar *str, + xmlCharEncodingOutputFunc escaping); + +XMLPUBFUN int + xmlOutputBufferFlush (xmlOutputBufferPtr out); +XMLPUBFUN int + xmlOutputBufferClose (xmlOutputBufferPtr out); + +XMLPUBFUN int + xmlRegisterOutputCallbacks (xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, + xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc); + +xmlOutputBufferPtr + __xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +#ifdef LIBXML_HTTP_ENABLED +/* This function only exists if HTTP support built into the library */ +XML_DEPRECATED +XMLPUBFUN void + xmlRegisterHTTPPostCallbacks (void ); +#endif /* LIBXML_HTTP_ENABLED */ + +#endif /* LIBXML_OUTPUT_ENABLED */ + +XML_DEPRECATED +XMLPUBFUN xmlParserInputPtr + xmlCheckHTTPInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr ret); + +/* + * A predefined entity loader disabling network accesses + */ +XMLPUBFUN xmlParserInputPtr + xmlNoNetExternalEntityLoader (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +XML_DEPRECATED +XMLPUBFUN xmlChar * + xmlNormalizeWindowsPath (const xmlChar *path); + +XML_DEPRECATED +XMLPUBFUN int + xmlCheckFilename (const char *path); +/** + * Default 'file://' protocol callbacks + */ +XML_DEPRECATED +XMLPUBFUN int + xmlFileMatch (const char *filename); +XML_DEPRECATED +XMLPUBFUN void * + xmlFileOpen (const char *filename); +XML_DEPRECATED +XMLPUBFUN int + xmlFileRead (void * context, + char * buffer, + int len); +XML_DEPRECATED +XMLPUBFUN int + xmlFileClose (void * context); + +/** + * Default 'http://' protocol callbacks + */ +#ifdef LIBXML_HTTP_ENABLED +XML_DEPRECATED +XMLPUBFUN int + xmlIOHTTPMatch (const char *filename); +XML_DEPRECATED +XMLPUBFUN void * + xmlIOHTTPOpen (const char *filename); +#ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED +XMLPUBFUN void * + xmlIOHTTPOpenW (const char * post_uri, + int compression ); +#endif /* LIBXML_OUTPUT_ENABLED */ +XML_DEPRECATED +XMLPUBFUN int + xmlIOHTTPRead (void * context, + char * buffer, + int len); +XML_DEPRECATED +XMLPUBFUN int + xmlIOHTTPClose (void * context); +#endif /* LIBXML_HTTP_ENABLED */ + +/** + * Default 'ftp://' protocol callbacks + */ +#if defined(LIBXML_FTP_ENABLED) +XML_DEPRECATED +XMLPUBFUN int + xmlIOFTPMatch (const char *filename); +XML_DEPRECATED +XMLPUBFUN void * + xmlIOFTPOpen (const char *filename); +XML_DEPRECATED +XMLPUBFUN int + xmlIOFTPRead (void * context, + char * buffer, + int len); +XML_DEPRECATED +XMLPUBFUN int + xmlIOFTPClose (void * context); +#endif /* defined(LIBXML_FTP_ENABLED) */ + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc + xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func); +XMLPUBFUN xmlOutputBufferCreateFilenameFunc + xmlOutputBufferCreateFilenameDefault( + xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED +XMLPUBFUN xmlOutputBufferCreateFilenameFunc + xmlThrDefOutputBufferCreateFilenameDefault( + xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc + xmlThrDefParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_IO_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlautomata.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlautomata.h new file mode 100644 index 00000000..ea38eb37 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlautomata.h @@ -0,0 +1,146 @@ +/* + * Summary: API to build regexp automata + * Description: the API to build regexp automata + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_AUTOMATA_H__ +#define __XML_AUTOMATA_H__ + +#include + +#ifdef LIBXML_REGEXP_ENABLED +#ifdef LIBXML_AUTOMATA_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlAutomataPtr: + * + * A libxml automata description, It can be compiled into a regexp + */ +typedef struct _xmlAutomata xmlAutomata; +typedef xmlAutomata *xmlAutomataPtr; + +/** + * xmlAutomataStatePtr: + * + * A state int the automata description, + */ +typedef struct _xmlAutomataState xmlAutomataState; +typedef xmlAutomataState *xmlAutomataStatePtr; + +/* + * Building API + */ +XMLPUBFUN xmlAutomataPtr + xmlNewAutomata (void); +XMLPUBFUN void + xmlFreeAutomata (xmlAutomataPtr am); + +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataGetInitState (xmlAutomataPtr am); +XMLPUBFUN int + xmlAutomataSetFinalState (xmlAutomataPtr am, + xmlAutomataStatePtr state); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewState (xmlAutomataPtr am); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewTransition (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewTransition2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewNegTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); + +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewCountTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewCountTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewOnceTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewOnceTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewAllTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int lax); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewEpsilon (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewCountedTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN xmlAutomataStatePtr + xmlAutomataNewCounterTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN int + xmlAutomataNewCounter (xmlAutomataPtr am, + int min, + int max); + +XMLPUBFUN struct _xmlRegexp * + xmlAutomataCompile (xmlAutomataPtr am); +XMLPUBFUN int + xmlAutomataIsDeterminist (xmlAutomataPtr am); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_AUTOMATA_ENABLED */ +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /* __XML_AUTOMATA_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlerror.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlerror.h new file mode 100644 index 00000000..36381bec --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlerror.h @@ -0,0 +1,962 @@ +/* + * Summary: error handling + * Description: the API used to report errors + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_ERROR_H__ +#define __XML_ERROR_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlErrorLevel: + * + * Indicates the level of an error + */ +typedef enum { + XML_ERR_NONE = 0, + XML_ERR_WARNING = 1, /* A simple warning */ + XML_ERR_ERROR = 2, /* A recoverable error */ + XML_ERR_FATAL = 3 /* A fatal error */ +} xmlErrorLevel; + +/** + * xmlErrorDomain: + * + * Indicates where an error may have come from + */ +typedef enum { + XML_FROM_NONE = 0, + XML_FROM_PARSER, /* The XML parser */ + XML_FROM_TREE, /* The tree module */ + XML_FROM_NAMESPACE, /* The XML Namespace module */ + XML_FROM_DTD, /* The XML DTD validation with parser context*/ + XML_FROM_HTML, /* The HTML parser */ + XML_FROM_MEMORY, /* The memory allocator */ + XML_FROM_OUTPUT, /* The serialization code */ + XML_FROM_IO, /* The Input/Output stack */ + XML_FROM_FTP, /* The FTP module */ + XML_FROM_HTTP, /* The HTTP module */ + XML_FROM_XINCLUDE, /* The XInclude processing */ + XML_FROM_XPATH, /* The XPath module */ + XML_FROM_XPOINTER, /* The XPointer module */ + XML_FROM_REGEXP, /* The regular expressions module */ + XML_FROM_DATATYPE, /* The W3C XML Schemas Datatype module */ + XML_FROM_SCHEMASP, /* The W3C XML Schemas parser module */ + XML_FROM_SCHEMASV, /* The W3C XML Schemas validation module */ + XML_FROM_RELAXNGP, /* The Relax-NG parser module */ + XML_FROM_RELAXNGV, /* The Relax-NG validator module */ + XML_FROM_CATALOG, /* The Catalog module */ + XML_FROM_C14N, /* The Canonicalization module */ + XML_FROM_XSLT, /* The XSLT engine from libxslt */ + XML_FROM_VALID, /* The XML DTD validation with valid context */ + XML_FROM_CHECK, /* The error checking module */ + XML_FROM_WRITER, /* The xmlwriter module */ + XML_FROM_MODULE, /* The dynamically loaded module module*/ + XML_FROM_I18N, /* The module handling character conversion */ + XML_FROM_SCHEMATRONV,/* The Schematron validator module */ + XML_FROM_BUFFER, /* The buffers module */ + XML_FROM_URI /* The URI module */ +} xmlErrorDomain; + +/** + * xmlError: + * + * An XML Error instance. + */ + +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; +struct _xmlError { + int domain; /* What part of the library raised this error */ + int code; /* The error code, e.g. an xmlParserError */ + char *message;/* human-readable informative error message */ + xmlErrorLevel level;/* how consequent is the error */ + char *file; /* the filename */ + int line; /* the line number if available */ + char *str1; /* extra string information */ + char *str2; /* extra string information */ + char *str3; /* extra string information */ + int int1; /* extra number information */ + int int2; /* error column # or 0 if N/A (todo: rename field when we would brk ABI) */ + void *ctxt; /* the parser context if available */ + void *node; /* the node in the tree */ +}; + +/** + * xmlParserError: + * + * This is an error that the XML (or HTML) parser can generate + */ +typedef enum { + XML_ERR_OK = 0, + XML_ERR_INTERNAL_ERROR, /* 1 */ + XML_ERR_NO_MEMORY, /* 2 */ + XML_ERR_DOCUMENT_START, /* 3 */ + XML_ERR_DOCUMENT_EMPTY, /* 4 */ + XML_ERR_DOCUMENT_END, /* 5 */ + XML_ERR_INVALID_HEX_CHARREF, /* 6 */ + XML_ERR_INVALID_DEC_CHARREF, /* 7 */ + XML_ERR_INVALID_CHARREF, /* 8 */ + XML_ERR_INVALID_CHAR, /* 9 */ + XML_ERR_CHARREF_AT_EOF, /* 10 */ + XML_ERR_CHARREF_IN_PROLOG, /* 11 */ + XML_ERR_CHARREF_IN_EPILOG, /* 12 */ + XML_ERR_CHARREF_IN_DTD, /* 13 */ + XML_ERR_ENTITYREF_AT_EOF, /* 14 */ + XML_ERR_ENTITYREF_IN_PROLOG, /* 15 */ + XML_ERR_ENTITYREF_IN_EPILOG, /* 16 */ + XML_ERR_ENTITYREF_IN_DTD, /* 17 */ + XML_ERR_PEREF_AT_EOF, /* 18 */ + XML_ERR_PEREF_IN_PROLOG, /* 19 */ + XML_ERR_PEREF_IN_EPILOG, /* 20 */ + XML_ERR_PEREF_IN_INT_SUBSET, /* 21 */ + XML_ERR_ENTITYREF_NO_NAME, /* 22 */ + XML_ERR_ENTITYREF_SEMICOL_MISSING, /* 23 */ + XML_ERR_PEREF_NO_NAME, /* 24 */ + XML_ERR_PEREF_SEMICOL_MISSING, /* 25 */ + XML_ERR_UNDECLARED_ENTITY, /* 26 */ + XML_WAR_UNDECLARED_ENTITY, /* 27 */ + XML_ERR_UNPARSED_ENTITY, /* 28 */ + XML_ERR_ENTITY_IS_EXTERNAL, /* 29 */ + XML_ERR_ENTITY_IS_PARAMETER, /* 30 */ + XML_ERR_UNKNOWN_ENCODING, /* 31 */ + XML_ERR_UNSUPPORTED_ENCODING, /* 32 */ + XML_ERR_STRING_NOT_STARTED, /* 33 */ + XML_ERR_STRING_NOT_CLOSED, /* 34 */ + XML_ERR_NS_DECL_ERROR, /* 35 */ + XML_ERR_ENTITY_NOT_STARTED, /* 36 */ + XML_ERR_ENTITY_NOT_FINISHED, /* 37 */ + XML_ERR_LT_IN_ATTRIBUTE, /* 38 */ + XML_ERR_ATTRIBUTE_NOT_STARTED, /* 39 */ + XML_ERR_ATTRIBUTE_NOT_FINISHED, /* 40 */ + XML_ERR_ATTRIBUTE_WITHOUT_VALUE, /* 41 */ + XML_ERR_ATTRIBUTE_REDEFINED, /* 42 */ + XML_ERR_LITERAL_NOT_STARTED, /* 43 */ + XML_ERR_LITERAL_NOT_FINISHED, /* 44 */ + XML_ERR_COMMENT_NOT_FINISHED, /* 45 */ + XML_ERR_PI_NOT_STARTED, /* 46 */ + XML_ERR_PI_NOT_FINISHED, /* 47 */ + XML_ERR_NOTATION_NOT_STARTED, /* 48 */ + XML_ERR_NOTATION_NOT_FINISHED, /* 49 */ + XML_ERR_ATTLIST_NOT_STARTED, /* 50 */ + XML_ERR_ATTLIST_NOT_FINISHED, /* 51 */ + XML_ERR_MIXED_NOT_STARTED, /* 52 */ + XML_ERR_MIXED_NOT_FINISHED, /* 53 */ + XML_ERR_ELEMCONTENT_NOT_STARTED, /* 54 */ + XML_ERR_ELEMCONTENT_NOT_FINISHED, /* 55 */ + XML_ERR_XMLDECL_NOT_STARTED, /* 56 */ + XML_ERR_XMLDECL_NOT_FINISHED, /* 57 */ + XML_ERR_CONDSEC_NOT_STARTED, /* 58 */ + XML_ERR_CONDSEC_NOT_FINISHED, /* 59 */ + XML_ERR_EXT_SUBSET_NOT_FINISHED, /* 60 */ + XML_ERR_DOCTYPE_NOT_FINISHED, /* 61 */ + XML_ERR_MISPLACED_CDATA_END, /* 62 */ + XML_ERR_CDATA_NOT_FINISHED, /* 63 */ + XML_ERR_RESERVED_XML_NAME, /* 64 */ + XML_ERR_SPACE_REQUIRED, /* 65 */ + XML_ERR_SEPARATOR_REQUIRED, /* 66 */ + XML_ERR_NMTOKEN_REQUIRED, /* 67 */ + XML_ERR_NAME_REQUIRED, /* 68 */ + XML_ERR_PCDATA_REQUIRED, /* 69 */ + XML_ERR_URI_REQUIRED, /* 70 */ + XML_ERR_PUBID_REQUIRED, /* 71 */ + XML_ERR_LT_REQUIRED, /* 72 */ + XML_ERR_GT_REQUIRED, /* 73 */ + XML_ERR_LTSLASH_REQUIRED, /* 74 */ + XML_ERR_EQUAL_REQUIRED, /* 75 */ + XML_ERR_TAG_NAME_MISMATCH, /* 76 */ + XML_ERR_TAG_NOT_FINISHED, /* 77 */ + XML_ERR_STANDALONE_VALUE, /* 78 */ + XML_ERR_ENCODING_NAME, /* 79 */ + XML_ERR_HYPHEN_IN_COMMENT, /* 80 */ + XML_ERR_INVALID_ENCODING, /* 81 */ + XML_ERR_EXT_ENTITY_STANDALONE, /* 82 */ + XML_ERR_CONDSEC_INVALID, /* 83 */ + XML_ERR_VALUE_REQUIRED, /* 84 */ + XML_ERR_NOT_WELL_BALANCED, /* 85 */ + XML_ERR_EXTRA_CONTENT, /* 86 */ + XML_ERR_ENTITY_CHAR_ERROR, /* 87 */ + XML_ERR_ENTITY_PE_INTERNAL, /* 88 */ + XML_ERR_ENTITY_LOOP, /* 89 */ + XML_ERR_ENTITY_BOUNDARY, /* 90 */ + XML_ERR_INVALID_URI, /* 91 */ + XML_ERR_URI_FRAGMENT, /* 92 */ + XML_WAR_CATALOG_PI, /* 93 */ + XML_ERR_NO_DTD, /* 94 */ + XML_ERR_CONDSEC_INVALID_KEYWORD, /* 95 */ + XML_ERR_VERSION_MISSING, /* 96 */ + XML_WAR_UNKNOWN_VERSION, /* 97 */ + XML_WAR_LANG_VALUE, /* 98 */ + XML_WAR_NS_URI, /* 99 */ + XML_WAR_NS_URI_RELATIVE, /* 100 */ + XML_ERR_MISSING_ENCODING, /* 101 */ + XML_WAR_SPACE_VALUE, /* 102 */ + XML_ERR_NOT_STANDALONE, /* 103 */ + XML_ERR_ENTITY_PROCESSING, /* 104 */ + XML_ERR_NOTATION_PROCESSING, /* 105 */ + XML_WAR_NS_COLUMN, /* 106 */ + XML_WAR_ENTITY_REDEFINED, /* 107 */ + XML_ERR_UNKNOWN_VERSION, /* 108 */ + XML_ERR_VERSION_MISMATCH, /* 109 */ + XML_ERR_NAME_TOO_LONG, /* 110 */ + XML_ERR_USER_STOP, /* 111 */ + XML_ERR_COMMENT_ABRUPTLY_ENDED, /* 112 */ + XML_WAR_ENCODING_MISMATCH, /* 113 */ + XML_ERR_RESOURCE_LIMIT, /* 114 */ + XML_ERR_ARGUMENT, /* 115 */ + XML_ERR_SYSTEM, /* 116 */ + XML_ERR_REDECL_PREDEF_ENTITY, /* 117 */ + XML_ERR_INT_SUBSET_NOT_FINISHED, /* 118 */ + XML_NS_ERR_XML_NAMESPACE = 200, + XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */ + XML_NS_ERR_QNAME, /* 202 */ + XML_NS_ERR_ATTRIBUTE_REDEFINED, /* 203 */ + XML_NS_ERR_EMPTY, /* 204 */ + XML_NS_ERR_COLON, /* 205 */ + XML_DTD_ATTRIBUTE_DEFAULT = 500, + XML_DTD_ATTRIBUTE_REDEFINED, /* 501 */ + XML_DTD_ATTRIBUTE_VALUE, /* 502 */ + XML_DTD_CONTENT_ERROR, /* 503 */ + XML_DTD_CONTENT_MODEL, /* 504 */ + XML_DTD_CONTENT_NOT_DETERMINIST, /* 505 */ + XML_DTD_DIFFERENT_PREFIX, /* 506 */ + XML_DTD_ELEM_DEFAULT_NAMESPACE, /* 507 */ + XML_DTD_ELEM_NAMESPACE, /* 508 */ + XML_DTD_ELEM_REDEFINED, /* 509 */ + XML_DTD_EMPTY_NOTATION, /* 510 */ + XML_DTD_ENTITY_TYPE, /* 511 */ + XML_DTD_ID_FIXED, /* 512 */ + XML_DTD_ID_REDEFINED, /* 513 */ + XML_DTD_ID_SUBSET, /* 514 */ + XML_DTD_INVALID_CHILD, /* 515 */ + XML_DTD_INVALID_DEFAULT, /* 516 */ + XML_DTD_LOAD_ERROR, /* 517 */ + XML_DTD_MISSING_ATTRIBUTE, /* 518 */ + XML_DTD_MIXED_CORRUPT, /* 519 */ + XML_DTD_MULTIPLE_ID, /* 520 */ + XML_DTD_NO_DOC, /* 521 */ + XML_DTD_NO_DTD, /* 522 */ + XML_DTD_NO_ELEM_NAME, /* 523 */ + XML_DTD_NO_PREFIX, /* 524 */ + XML_DTD_NO_ROOT, /* 525 */ + XML_DTD_NOTATION_REDEFINED, /* 526 */ + XML_DTD_NOTATION_VALUE, /* 527 */ + XML_DTD_NOT_EMPTY, /* 528 */ + XML_DTD_NOT_PCDATA, /* 529 */ + XML_DTD_NOT_STANDALONE, /* 530 */ + XML_DTD_ROOT_NAME, /* 531 */ + XML_DTD_STANDALONE_WHITE_SPACE, /* 532 */ + XML_DTD_UNKNOWN_ATTRIBUTE, /* 533 */ + XML_DTD_UNKNOWN_ELEM, /* 534 */ + XML_DTD_UNKNOWN_ENTITY, /* 535 */ + XML_DTD_UNKNOWN_ID, /* 536 */ + XML_DTD_UNKNOWN_NOTATION, /* 537 */ + XML_DTD_STANDALONE_DEFAULTED, /* 538 */ + XML_DTD_XMLID_VALUE, /* 539 */ + XML_DTD_XMLID_TYPE, /* 540 */ + XML_DTD_DUP_TOKEN, /* 541 */ + XML_HTML_STRUCURE_ERROR = 800, + XML_HTML_UNKNOWN_TAG, /* 801 */ + XML_HTML_INCORRECTLY_OPENED_COMMENT, /* 802 */ + XML_RNGP_ANYNAME_ATTR_ANCESTOR = 1000, + XML_RNGP_ATTR_CONFLICT, /* 1001 */ + XML_RNGP_ATTRIBUTE_CHILDREN, /* 1002 */ + XML_RNGP_ATTRIBUTE_CONTENT, /* 1003 */ + XML_RNGP_ATTRIBUTE_EMPTY, /* 1004 */ + XML_RNGP_ATTRIBUTE_NOOP, /* 1005 */ + XML_RNGP_CHOICE_CONTENT, /* 1006 */ + XML_RNGP_CHOICE_EMPTY, /* 1007 */ + XML_RNGP_CREATE_FAILURE, /* 1008 */ + XML_RNGP_DATA_CONTENT, /* 1009 */ + XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, /* 1010 */ + XML_RNGP_DEFINE_CREATE_FAILED, /* 1011 */ + XML_RNGP_DEFINE_EMPTY, /* 1012 */ + XML_RNGP_DEFINE_MISSING, /* 1013 */ + XML_RNGP_DEFINE_NAME_MISSING, /* 1014 */ + XML_RNGP_ELEM_CONTENT_EMPTY, /* 1015 */ + XML_RNGP_ELEM_CONTENT_ERROR, /* 1016 */ + XML_RNGP_ELEMENT_EMPTY, /* 1017 */ + XML_RNGP_ELEMENT_CONTENT, /* 1018 */ + XML_RNGP_ELEMENT_NAME, /* 1019 */ + XML_RNGP_ELEMENT_NO_CONTENT, /* 1020 */ + XML_RNGP_ELEM_TEXT_CONFLICT, /* 1021 */ + XML_RNGP_EMPTY, /* 1022 */ + XML_RNGP_EMPTY_CONSTRUCT, /* 1023 */ + XML_RNGP_EMPTY_CONTENT, /* 1024 */ + XML_RNGP_EMPTY_NOT_EMPTY, /* 1025 */ + XML_RNGP_ERROR_TYPE_LIB, /* 1026 */ + XML_RNGP_EXCEPT_EMPTY, /* 1027 */ + XML_RNGP_EXCEPT_MISSING, /* 1028 */ + XML_RNGP_EXCEPT_MULTIPLE, /* 1029 */ + XML_RNGP_EXCEPT_NO_CONTENT, /* 1030 */ + XML_RNGP_EXTERNALREF_EMTPY, /* 1031 */ + XML_RNGP_EXTERNAL_REF_FAILURE, /* 1032 */ + XML_RNGP_EXTERNALREF_RECURSE, /* 1033 */ + XML_RNGP_FORBIDDEN_ATTRIBUTE, /* 1034 */ + XML_RNGP_FOREIGN_ELEMENT, /* 1035 */ + XML_RNGP_GRAMMAR_CONTENT, /* 1036 */ + XML_RNGP_GRAMMAR_EMPTY, /* 1037 */ + XML_RNGP_GRAMMAR_MISSING, /* 1038 */ + XML_RNGP_GRAMMAR_NO_START, /* 1039 */ + XML_RNGP_GROUP_ATTR_CONFLICT, /* 1040 */ + XML_RNGP_HREF_ERROR, /* 1041 */ + XML_RNGP_INCLUDE_EMPTY, /* 1042 */ + XML_RNGP_INCLUDE_FAILURE, /* 1043 */ + XML_RNGP_INCLUDE_RECURSE, /* 1044 */ + XML_RNGP_INTERLEAVE_ADD, /* 1045 */ + XML_RNGP_INTERLEAVE_CREATE_FAILED, /* 1046 */ + XML_RNGP_INTERLEAVE_EMPTY, /* 1047 */ + XML_RNGP_INTERLEAVE_NO_CONTENT, /* 1048 */ + XML_RNGP_INVALID_DEFINE_NAME, /* 1049 */ + XML_RNGP_INVALID_URI, /* 1050 */ + XML_RNGP_INVALID_VALUE, /* 1051 */ + XML_RNGP_MISSING_HREF, /* 1052 */ + XML_RNGP_NAME_MISSING, /* 1053 */ + XML_RNGP_NEED_COMBINE, /* 1054 */ + XML_RNGP_NOTALLOWED_NOT_EMPTY, /* 1055 */ + XML_RNGP_NSNAME_ATTR_ANCESTOR, /* 1056 */ + XML_RNGP_NSNAME_NO_NS, /* 1057 */ + XML_RNGP_PARAM_FORBIDDEN, /* 1058 */ + XML_RNGP_PARAM_NAME_MISSING, /* 1059 */ + XML_RNGP_PARENTREF_CREATE_FAILED, /* 1060 */ + XML_RNGP_PARENTREF_NAME_INVALID, /* 1061 */ + XML_RNGP_PARENTREF_NO_NAME, /* 1062 */ + XML_RNGP_PARENTREF_NO_PARENT, /* 1063 */ + XML_RNGP_PARENTREF_NOT_EMPTY, /* 1064 */ + XML_RNGP_PARSE_ERROR, /* 1065 */ + XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, /* 1066 */ + XML_RNGP_PAT_ATTR_ATTR, /* 1067 */ + XML_RNGP_PAT_ATTR_ELEM, /* 1068 */ + XML_RNGP_PAT_DATA_EXCEPT_ATTR, /* 1069 */ + XML_RNGP_PAT_DATA_EXCEPT_ELEM, /* 1070 */ + XML_RNGP_PAT_DATA_EXCEPT_EMPTY, /* 1071 */ + XML_RNGP_PAT_DATA_EXCEPT_GROUP, /* 1072 */ + XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, /* 1073 */ + XML_RNGP_PAT_DATA_EXCEPT_LIST, /* 1074 */ + XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, /* 1075 */ + XML_RNGP_PAT_DATA_EXCEPT_REF, /* 1076 */ + XML_RNGP_PAT_DATA_EXCEPT_TEXT, /* 1077 */ + XML_RNGP_PAT_LIST_ATTR, /* 1078 */ + XML_RNGP_PAT_LIST_ELEM, /* 1079 */ + XML_RNGP_PAT_LIST_INTERLEAVE, /* 1080 */ + XML_RNGP_PAT_LIST_LIST, /* 1081 */ + XML_RNGP_PAT_LIST_REF, /* 1082 */ + XML_RNGP_PAT_LIST_TEXT, /* 1083 */ + XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, /* 1084 */ + XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, /* 1085 */ + XML_RNGP_PAT_ONEMORE_GROUP_ATTR, /* 1086 */ + XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, /* 1087 */ + XML_RNGP_PAT_START_ATTR, /* 1088 */ + XML_RNGP_PAT_START_DATA, /* 1089 */ + XML_RNGP_PAT_START_EMPTY, /* 1090 */ + XML_RNGP_PAT_START_GROUP, /* 1091 */ + XML_RNGP_PAT_START_INTERLEAVE, /* 1092 */ + XML_RNGP_PAT_START_LIST, /* 1093 */ + XML_RNGP_PAT_START_ONEMORE, /* 1094 */ + XML_RNGP_PAT_START_TEXT, /* 1095 */ + XML_RNGP_PAT_START_VALUE, /* 1096 */ + XML_RNGP_PREFIX_UNDEFINED, /* 1097 */ + XML_RNGP_REF_CREATE_FAILED, /* 1098 */ + XML_RNGP_REF_CYCLE, /* 1099 */ + XML_RNGP_REF_NAME_INVALID, /* 1100 */ + XML_RNGP_REF_NO_DEF, /* 1101 */ + XML_RNGP_REF_NO_NAME, /* 1102 */ + XML_RNGP_REF_NOT_EMPTY, /* 1103 */ + XML_RNGP_START_CHOICE_AND_INTERLEAVE, /* 1104 */ + XML_RNGP_START_CONTENT, /* 1105 */ + XML_RNGP_START_EMPTY, /* 1106 */ + XML_RNGP_START_MISSING, /* 1107 */ + XML_RNGP_TEXT_EXPECTED, /* 1108 */ + XML_RNGP_TEXT_HAS_CHILD, /* 1109 */ + XML_RNGP_TYPE_MISSING, /* 1110 */ + XML_RNGP_TYPE_NOT_FOUND, /* 1111 */ + XML_RNGP_TYPE_VALUE, /* 1112 */ + XML_RNGP_UNKNOWN_ATTRIBUTE, /* 1113 */ + XML_RNGP_UNKNOWN_COMBINE, /* 1114 */ + XML_RNGP_UNKNOWN_CONSTRUCT, /* 1115 */ + XML_RNGP_UNKNOWN_TYPE_LIB, /* 1116 */ + XML_RNGP_URI_FRAGMENT, /* 1117 */ + XML_RNGP_URI_NOT_ABSOLUTE, /* 1118 */ + XML_RNGP_VALUE_EMPTY, /* 1119 */ + XML_RNGP_VALUE_NO_CONTENT, /* 1120 */ + XML_RNGP_XMLNS_NAME, /* 1121 */ + XML_RNGP_XML_NS, /* 1122 */ + XML_XPATH_EXPRESSION_OK = 1200, + XML_XPATH_NUMBER_ERROR, /* 1201 */ + XML_XPATH_UNFINISHED_LITERAL_ERROR, /* 1202 */ + XML_XPATH_START_LITERAL_ERROR, /* 1203 */ + XML_XPATH_VARIABLE_REF_ERROR, /* 1204 */ + XML_XPATH_UNDEF_VARIABLE_ERROR, /* 1205 */ + XML_XPATH_INVALID_PREDICATE_ERROR, /* 1206 */ + XML_XPATH_EXPR_ERROR, /* 1207 */ + XML_XPATH_UNCLOSED_ERROR, /* 1208 */ + XML_XPATH_UNKNOWN_FUNC_ERROR, /* 1209 */ + XML_XPATH_INVALID_OPERAND, /* 1210 */ + XML_XPATH_INVALID_TYPE, /* 1211 */ + XML_XPATH_INVALID_ARITY, /* 1212 */ + XML_XPATH_INVALID_CTXT_SIZE, /* 1213 */ + XML_XPATH_INVALID_CTXT_POSITION, /* 1214 */ + XML_XPATH_MEMORY_ERROR, /* 1215 */ + XML_XPTR_SYNTAX_ERROR, /* 1216 */ + XML_XPTR_RESOURCE_ERROR, /* 1217 */ + XML_XPTR_SUB_RESOURCE_ERROR, /* 1218 */ + XML_XPATH_UNDEF_PREFIX_ERROR, /* 1219 */ + XML_XPATH_ENCODING_ERROR, /* 1220 */ + XML_XPATH_INVALID_CHAR_ERROR, /* 1221 */ + XML_TREE_INVALID_HEX = 1300, + XML_TREE_INVALID_DEC, /* 1301 */ + XML_TREE_UNTERMINATED_ENTITY, /* 1302 */ + XML_TREE_NOT_UTF8, /* 1303 */ + XML_SAVE_NOT_UTF8 = 1400, + XML_SAVE_CHAR_INVALID, /* 1401 */ + XML_SAVE_NO_DOCTYPE, /* 1402 */ + XML_SAVE_UNKNOWN_ENCODING, /* 1403 */ + XML_REGEXP_COMPILE_ERROR = 1450, + XML_IO_UNKNOWN = 1500, + XML_IO_EACCES, /* 1501 */ + XML_IO_EAGAIN, /* 1502 */ + XML_IO_EBADF, /* 1503 */ + XML_IO_EBADMSG, /* 1504 */ + XML_IO_EBUSY, /* 1505 */ + XML_IO_ECANCELED, /* 1506 */ + XML_IO_ECHILD, /* 1507 */ + XML_IO_EDEADLK, /* 1508 */ + XML_IO_EDOM, /* 1509 */ + XML_IO_EEXIST, /* 1510 */ + XML_IO_EFAULT, /* 1511 */ + XML_IO_EFBIG, /* 1512 */ + XML_IO_EINPROGRESS, /* 1513 */ + XML_IO_EINTR, /* 1514 */ + XML_IO_EINVAL, /* 1515 */ + XML_IO_EIO, /* 1516 */ + XML_IO_EISDIR, /* 1517 */ + XML_IO_EMFILE, /* 1518 */ + XML_IO_EMLINK, /* 1519 */ + XML_IO_EMSGSIZE, /* 1520 */ + XML_IO_ENAMETOOLONG, /* 1521 */ + XML_IO_ENFILE, /* 1522 */ + XML_IO_ENODEV, /* 1523 */ + XML_IO_ENOENT, /* 1524 */ + XML_IO_ENOEXEC, /* 1525 */ + XML_IO_ENOLCK, /* 1526 */ + XML_IO_ENOMEM, /* 1527 */ + XML_IO_ENOSPC, /* 1528 */ + XML_IO_ENOSYS, /* 1529 */ + XML_IO_ENOTDIR, /* 1530 */ + XML_IO_ENOTEMPTY, /* 1531 */ + XML_IO_ENOTSUP, /* 1532 */ + XML_IO_ENOTTY, /* 1533 */ + XML_IO_ENXIO, /* 1534 */ + XML_IO_EPERM, /* 1535 */ + XML_IO_EPIPE, /* 1536 */ + XML_IO_ERANGE, /* 1537 */ + XML_IO_EROFS, /* 1538 */ + XML_IO_ESPIPE, /* 1539 */ + XML_IO_ESRCH, /* 1540 */ + XML_IO_ETIMEDOUT, /* 1541 */ + XML_IO_EXDEV, /* 1542 */ + XML_IO_NETWORK_ATTEMPT, /* 1543 */ + XML_IO_ENCODER, /* 1544 */ + XML_IO_FLUSH, /* 1545 */ + XML_IO_WRITE, /* 1546 */ + XML_IO_NO_INPUT, /* 1547 */ + XML_IO_BUFFER_FULL, /* 1548 */ + XML_IO_LOAD_ERROR, /* 1549 */ + XML_IO_ENOTSOCK, /* 1550 */ + XML_IO_EISCONN, /* 1551 */ + XML_IO_ECONNREFUSED, /* 1552 */ + XML_IO_ENETUNREACH, /* 1553 */ + XML_IO_EADDRINUSE, /* 1554 */ + XML_IO_EALREADY, /* 1555 */ + XML_IO_EAFNOSUPPORT, /* 1556 */ + XML_IO_UNSUPPORTED_PROTOCOL, /* 1557 */ + XML_XINCLUDE_RECURSION=1600, + XML_XINCLUDE_PARSE_VALUE, /* 1601 */ + XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */ + XML_XINCLUDE_NO_HREF, /* 1603 */ + XML_XINCLUDE_NO_FALLBACK, /* 1604 */ + XML_XINCLUDE_HREF_URI, /* 1605 */ + XML_XINCLUDE_TEXT_FRAGMENT, /* 1606 */ + XML_XINCLUDE_TEXT_DOCUMENT, /* 1607 */ + XML_XINCLUDE_INVALID_CHAR, /* 1608 */ + XML_XINCLUDE_BUILD_FAILED, /* 1609 */ + XML_XINCLUDE_UNKNOWN_ENCODING, /* 1610 */ + XML_XINCLUDE_MULTIPLE_ROOT, /* 1611 */ + XML_XINCLUDE_XPTR_FAILED, /* 1612 */ + XML_XINCLUDE_XPTR_RESULT, /* 1613 */ + XML_XINCLUDE_INCLUDE_IN_INCLUDE, /* 1614 */ + XML_XINCLUDE_FALLBACKS_IN_INCLUDE, /* 1615 */ + XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, /* 1616 */ + XML_XINCLUDE_DEPRECATED_NS, /* 1617 */ + XML_XINCLUDE_FRAGMENT_ID, /* 1618 */ + XML_CATALOG_MISSING_ATTR = 1650, + XML_CATALOG_ENTRY_BROKEN, /* 1651 */ + XML_CATALOG_PREFER_VALUE, /* 1652 */ + XML_CATALOG_NOT_CATALOG, /* 1653 */ + XML_CATALOG_RECURSION, /* 1654 */ + XML_SCHEMAP_PREFIX_UNDEFINED = 1700, + XML_SCHEMAP_ATTRFORMDEFAULT_VALUE, /* 1701 */ + XML_SCHEMAP_ATTRGRP_NONAME_NOREF, /* 1702 */ + XML_SCHEMAP_ATTR_NONAME_NOREF, /* 1703 */ + XML_SCHEMAP_COMPLEXTYPE_NONAME_NOREF, /* 1704 */ + XML_SCHEMAP_ELEMFORMDEFAULT_VALUE, /* 1705 */ + XML_SCHEMAP_ELEM_NONAME_NOREF, /* 1706 */ + XML_SCHEMAP_EXTENSION_NO_BASE, /* 1707 */ + XML_SCHEMAP_FACET_NO_VALUE, /* 1708 */ + XML_SCHEMAP_FAILED_BUILD_IMPORT, /* 1709 */ + XML_SCHEMAP_GROUP_NONAME_NOREF, /* 1710 */ + XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI, /* 1711 */ + XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, /* 1712 */ + XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI, /* 1713 */ + XML_SCHEMAP_INVALID_BOOLEAN, /* 1714 */ + XML_SCHEMAP_INVALID_ENUM, /* 1715 */ + XML_SCHEMAP_INVALID_FACET, /* 1716 */ + XML_SCHEMAP_INVALID_FACET_VALUE, /* 1717 */ + XML_SCHEMAP_INVALID_MAXOCCURS, /* 1718 */ + XML_SCHEMAP_INVALID_MINOCCURS, /* 1719 */ + XML_SCHEMAP_INVALID_REF_AND_SUBTYPE, /* 1720 */ + XML_SCHEMAP_INVALID_WHITE_SPACE, /* 1721 */ + XML_SCHEMAP_NOATTR_NOREF, /* 1722 */ + XML_SCHEMAP_NOTATION_NO_NAME, /* 1723 */ + XML_SCHEMAP_NOTYPE_NOREF, /* 1724 */ + XML_SCHEMAP_REF_AND_SUBTYPE, /* 1725 */ + XML_SCHEMAP_RESTRICTION_NONAME_NOREF, /* 1726 */ + XML_SCHEMAP_SIMPLETYPE_NONAME, /* 1727 */ + XML_SCHEMAP_TYPE_AND_SUBTYPE, /* 1728 */ + XML_SCHEMAP_UNKNOWN_ALL_CHILD, /* 1729 */ + XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, /* 1730 */ + XML_SCHEMAP_UNKNOWN_ATTR_CHILD, /* 1731 */ + XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, /* 1732 */ + XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP, /* 1733 */ + XML_SCHEMAP_UNKNOWN_BASE_TYPE, /* 1734 */ + XML_SCHEMAP_UNKNOWN_CHOICE_CHILD, /* 1735 */ + XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD, /* 1736 */ + XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD, /* 1737 */ + XML_SCHEMAP_UNKNOWN_ELEM_CHILD, /* 1738 */ + XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD, /* 1739 */ + XML_SCHEMAP_UNKNOWN_FACET_CHILD, /* 1740 */ + XML_SCHEMAP_UNKNOWN_FACET_TYPE, /* 1741 */ + XML_SCHEMAP_UNKNOWN_GROUP_CHILD, /* 1742 */ + XML_SCHEMAP_UNKNOWN_IMPORT_CHILD, /* 1743 */ + XML_SCHEMAP_UNKNOWN_LIST_CHILD, /* 1744 */ + XML_SCHEMAP_UNKNOWN_NOTATION_CHILD, /* 1745 */ + XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, /* 1746 */ + XML_SCHEMAP_UNKNOWN_REF, /* 1747 */ + XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, /* 1748 */ + XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD, /* 1749 */ + XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, /* 1750 */ + XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD, /* 1751 */ + XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, /* 1752 */ + XML_SCHEMAP_UNKNOWN_TYPE, /* 1753 */ + XML_SCHEMAP_UNKNOWN_UNION_CHILD, /* 1754 */ + XML_SCHEMAP_ELEM_DEFAULT_FIXED, /* 1755 */ + XML_SCHEMAP_REGEXP_INVALID, /* 1756 */ + XML_SCHEMAP_FAILED_LOAD, /* 1757 */ + XML_SCHEMAP_NOTHING_TO_PARSE, /* 1758 */ + XML_SCHEMAP_NOROOT, /* 1759 */ + XML_SCHEMAP_REDEFINED_GROUP, /* 1760 */ + XML_SCHEMAP_REDEFINED_TYPE, /* 1761 */ + XML_SCHEMAP_REDEFINED_ELEMENT, /* 1762 */ + XML_SCHEMAP_REDEFINED_ATTRGROUP, /* 1763 */ + XML_SCHEMAP_REDEFINED_ATTR, /* 1764 */ + XML_SCHEMAP_REDEFINED_NOTATION, /* 1765 */ + XML_SCHEMAP_FAILED_PARSE, /* 1766 */ + XML_SCHEMAP_UNKNOWN_PREFIX, /* 1767 */ + XML_SCHEMAP_DEF_AND_PREFIX, /* 1768 */ + XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD, /* 1769 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI, /* 1770 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI, /* 1771 */ + XML_SCHEMAP_NOT_SCHEMA, /* 1772 */ + XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, /* 1773 */ + XML_SCHEMAP_INVALID_ATTR_USE, /* 1774 */ + XML_SCHEMAP_RECURSIVE, /* 1775 */ + XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE, /* 1776 */ + XML_SCHEMAP_INVALID_ATTR_COMBINATION, /* 1777 */ + XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION, /* 1778 */ + XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD, /* 1779 */ + XML_SCHEMAP_INVALID_ATTR_NAME, /* 1780 */ + XML_SCHEMAP_REF_AND_CONTENT, /* 1781 */ + XML_SCHEMAP_CT_PROPS_CORRECT_1, /* 1782 */ + XML_SCHEMAP_CT_PROPS_CORRECT_2, /* 1783 */ + XML_SCHEMAP_CT_PROPS_CORRECT_3, /* 1784 */ + XML_SCHEMAP_CT_PROPS_CORRECT_4, /* 1785 */ + XML_SCHEMAP_CT_PROPS_CORRECT_5, /* 1786 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, /* 1787 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1, /* 1788 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2, /* 1789 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2, /* 1790 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3, /* 1791 */ + XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER, /* 1792 */ + XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE, /* 1793 */ + XML_SCHEMAP_UNION_NOT_EXPRESSIBLE, /* 1794 */ + XML_SCHEMAP_SRC_IMPORT_3_1, /* 1795 */ + XML_SCHEMAP_SRC_IMPORT_3_2, /* 1796 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1, /* 1797 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2, /* 1798 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3, /* 1799 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_3, /* 1800 */ + XML_SCHEMAV_NOROOT = 1801, + XML_SCHEMAV_UNDECLAREDELEM, /* 1802 */ + XML_SCHEMAV_NOTTOPLEVEL, /* 1803 */ + XML_SCHEMAV_MISSING, /* 1804 */ + XML_SCHEMAV_WRONGELEM, /* 1805 */ + XML_SCHEMAV_NOTYPE, /* 1806 */ + XML_SCHEMAV_NOROLLBACK, /* 1807 */ + XML_SCHEMAV_ISABSTRACT, /* 1808 */ + XML_SCHEMAV_NOTEMPTY, /* 1809 */ + XML_SCHEMAV_ELEMCONT, /* 1810 */ + XML_SCHEMAV_HAVEDEFAULT, /* 1811 */ + XML_SCHEMAV_NOTNILLABLE, /* 1812 */ + XML_SCHEMAV_EXTRACONTENT, /* 1813 */ + XML_SCHEMAV_INVALIDATTR, /* 1814 */ + XML_SCHEMAV_INVALIDELEM, /* 1815 */ + XML_SCHEMAV_NOTDETERMINIST, /* 1816 */ + XML_SCHEMAV_CONSTRUCT, /* 1817 */ + XML_SCHEMAV_INTERNAL, /* 1818 */ + XML_SCHEMAV_NOTSIMPLE, /* 1819 */ + XML_SCHEMAV_ATTRUNKNOWN, /* 1820 */ + XML_SCHEMAV_ATTRINVALID, /* 1821 */ + XML_SCHEMAV_VALUE, /* 1822 */ + XML_SCHEMAV_FACET, /* 1823 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, /* 1824 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2, /* 1825 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3, /* 1826 */ + XML_SCHEMAV_CVC_TYPE_3_1_1, /* 1827 */ + XML_SCHEMAV_CVC_TYPE_3_1_2, /* 1828 */ + XML_SCHEMAV_CVC_FACET_VALID, /* 1829 */ + XML_SCHEMAV_CVC_LENGTH_VALID, /* 1830 */ + XML_SCHEMAV_CVC_MINLENGTH_VALID, /* 1831 */ + XML_SCHEMAV_CVC_MAXLENGTH_VALID, /* 1832 */ + XML_SCHEMAV_CVC_MININCLUSIVE_VALID, /* 1833 */ + XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID, /* 1834 */ + XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID, /* 1835 */ + XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID, /* 1836 */ + XML_SCHEMAV_CVC_TOTALDIGITS_VALID, /* 1837 */ + XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID, /* 1838 */ + XML_SCHEMAV_CVC_PATTERN_VALID, /* 1839 */ + XML_SCHEMAV_CVC_ENUMERATION_VALID, /* 1840 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, /* 1841 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, /* 1842 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, /* 1843 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_4, /* 1844 */ + XML_SCHEMAV_CVC_ELT_1, /* 1845 */ + XML_SCHEMAV_CVC_ELT_2, /* 1846 */ + XML_SCHEMAV_CVC_ELT_3_1, /* 1847 */ + XML_SCHEMAV_CVC_ELT_3_2_1, /* 1848 */ + XML_SCHEMAV_CVC_ELT_3_2_2, /* 1849 */ + XML_SCHEMAV_CVC_ELT_4_1, /* 1850 */ + XML_SCHEMAV_CVC_ELT_4_2, /* 1851 */ + XML_SCHEMAV_CVC_ELT_4_3, /* 1852 */ + XML_SCHEMAV_CVC_ELT_5_1_1, /* 1853 */ + XML_SCHEMAV_CVC_ELT_5_1_2, /* 1854 */ + XML_SCHEMAV_CVC_ELT_5_2_1, /* 1855 */ + XML_SCHEMAV_CVC_ELT_5_2_2_1, /* 1856 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_1, /* 1857 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_2, /* 1858 */ + XML_SCHEMAV_CVC_ELT_6, /* 1859 */ + XML_SCHEMAV_CVC_ELT_7, /* 1860 */ + XML_SCHEMAV_CVC_ATTRIBUTE_1, /* 1861 */ + XML_SCHEMAV_CVC_ATTRIBUTE_2, /* 1862 */ + XML_SCHEMAV_CVC_ATTRIBUTE_3, /* 1863 */ + XML_SCHEMAV_CVC_ATTRIBUTE_4, /* 1864 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_1, /* 1865 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1, /* 1866 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2, /* 1867 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_4, /* 1868 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_1, /* 1869 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_2, /* 1870 */ + XML_SCHEMAV_ELEMENT_CONTENT, /* 1871 */ + XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING, /* 1872 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_1, /* 1873 */ + XML_SCHEMAV_CVC_AU, /* 1874 */ + XML_SCHEMAV_CVC_TYPE_1, /* 1875 */ + XML_SCHEMAV_CVC_TYPE_2, /* 1876 */ + XML_SCHEMAV_CVC_IDC, /* 1877 */ + XML_SCHEMAV_CVC_WILDCARD, /* 1878 */ + XML_SCHEMAV_MISC, /* 1879 */ + XML_XPTR_UNKNOWN_SCHEME = 1900, + XML_XPTR_CHILDSEQ_START, /* 1901 */ + XML_XPTR_EVAL_FAILED, /* 1902 */ + XML_XPTR_EXTRA_OBJECTS, /* 1903 */ + XML_C14N_CREATE_CTXT = 1950, + XML_C14N_REQUIRES_UTF8, /* 1951 */ + XML_C14N_CREATE_STACK, /* 1952 */ + XML_C14N_INVALID_NODE, /* 1953 */ + XML_C14N_UNKNOW_NODE, /* 1954 */ + XML_C14N_RELATIVE_NAMESPACE, /* 1955 */ + XML_FTP_PASV_ANSWER = 2000, + XML_FTP_EPSV_ANSWER, /* 2001 */ + XML_FTP_ACCNT, /* 2002 */ + XML_FTP_URL_SYNTAX, /* 2003 */ + XML_HTTP_URL_SYNTAX = 2020, + XML_HTTP_USE_IP, /* 2021 */ + XML_HTTP_UNKNOWN_HOST, /* 2022 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_1 = 3000, + XML_SCHEMAP_SRC_SIMPLE_TYPE_2, /* 3001 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_3, /* 3002 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_4, /* 3003 */ + XML_SCHEMAP_SRC_RESOLVE, /* 3004 */ + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, /* 3005 */ + XML_SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE, /* 3006 */ + XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES, /* 3007 */ + XML_SCHEMAP_ST_PROPS_CORRECT_1, /* 3008 */ + XML_SCHEMAP_ST_PROPS_CORRECT_2, /* 3009 */ + XML_SCHEMAP_ST_PROPS_CORRECT_3, /* 3010 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_1, /* 3011 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_2, /* 3012 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1, /* 3013 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_2, /* 3014 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, /* 3015 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1, /* 3016 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2, /* 3017 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1, /* 3018 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2, /* 3019 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3, /* 3020 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4, /* 3021 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_5, /* 3022 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_1, /* 3023 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1, /* 3024 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2, /* 3025 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2, /* 3026 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1, /* 3027 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3, /* 3028 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4, /* 3029 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_5, /* 3030 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_1, /* 3031 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_2, /* 3032 */ + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, /* 3033 */ + XML_SCHEMAP_S4S_ELEM_MISSING, /* 3034 */ + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, /* 3035 */ + XML_SCHEMAP_S4S_ATTR_MISSING, /* 3036 */ + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, /* 3037 */ + XML_SCHEMAP_SRC_ELEMENT_1, /* 3038 */ + XML_SCHEMAP_SRC_ELEMENT_2_1, /* 3039 */ + XML_SCHEMAP_SRC_ELEMENT_2_2, /* 3040 */ + XML_SCHEMAP_SRC_ELEMENT_3, /* 3041 */ + XML_SCHEMAP_P_PROPS_CORRECT_1, /* 3042 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_1, /* 3043 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_2, /* 3044 */ + XML_SCHEMAP_E_PROPS_CORRECT_2, /* 3045 */ + XML_SCHEMAP_E_PROPS_CORRECT_3, /* 3046 */ + XML_SCHEMAP_E_PROPS_CORRECT_4, /* 3047 */ + XML_SCHEMAP_E_PROPS_CORRECT_5, /* 3048 */ + XML_SCHEMAP_E_PROPS_CORRECT_6, /* 3049 */ + XML_SCHEMAP_SRC_INCLUDE, /* 3050 */ + XML_SCHEMAP_SRC_ATTRIBUTE_1, /* 3051 */ + XML_SCHEMAP_SRC_ATTRIBUTE_2, /* 3052 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_1, /* 3053 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_2, /* 3054 */ + XML_SCHEMAP_SRC_ATTRIBUTE_4, /* 3055 */ + XML_SCHEMAP_NO_XMLNS, /* 3056 */ + XML_SCHEMAP_NO_XSI, /* 3057 */ + XML_SCHEMAP_COS_VALID_DEFAULT_1, /* 3058 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_1, /* 3059 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_1, /* 3060 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_2, /* 3061 */ + XML_SCHEMAP_CVC_SIMPLE_TYPE, /* 3062 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_1, /* 3063 */ + XML_SCHEMAP_SRC_IMPORT_1_1, /* 3064 */ + XML_SCHEMAP_SRC_IMPORT_1_2, /* 3065 */ + XML_SCHEMAP_SRC_IMPORT_2, /* 3066 */ + XML_SCHEMAP_SRC_IMPORT_2_1, /* 3067 */ + XML_SCHEMAP_SRC_IMPORT_2_2, /* 3068 */ + XML_SCHEMAP_INTERNAL, /* 3069 non-W3C */ + XML_SCHEMAP_NOT_DETERMINISTIC, /* 3070 non-W3C */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_1, /* 3071 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_2, /* 3072 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3, /* 3073 */ + XML_SCHEMAP_MG_PROPS_CORRECT_1, /* 3074 */ + XML_SCHEMAP_MG_PROPS_CORRECT_2, /* 3075 */ + XML_SCHEMAP_SRC_CT_1, /* 3076 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3, /* 3077 */ + XML_SCHEMAP_AU_PROPS_CORRECT_2, /* 3078 */ + XML_SCHEMAP_A_PROPS_CORRECT_2, /* 3079 */ + XML_SCHEMAP_C_PROPS_CORRECT, /* 3080 */ + XML_SCHEMAP_SRC_REDEFINE, /* 3081 */ + XML_SCHEMAP_SRC_IMPORT, /* 3082 */ + XML_SCHEMAP_WARN_SKIP_SCHEMA, /* 3083 */ + XML_SCHEMAP_WARN_UNLOCATED_SCHEMA, /* 3084 */ + XML_SCHEMAP_WARN_ATTR_REDECL_PROH, /* 3085 */ + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, /* 3085 */ + XML_SCHEMAP_AG_PROPS_CORRECT, /* 3086 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_2, /* 3087 */ + XML_SCHEMAP_AU_PROPS_CORRECT, /* 3088 */ + XML_SCHEMAP_A_PROPS_CORRECT_3, /* 3089 */ + XML_SCHEMAP_COS_ALL_LIMITED, /* 3090 */ + XML_SCHEMATRONV_ASSERT = 4000, /* 4000 */ + XML_SCHEMATRONV_REPORT, + XML_MODULE_OPEN = 4900, /* 4900 */ + XML_MODULE_CLOSE, /* 4901 */ + XML_CHECK_FOUND_ELEMENT = 5000, + XML_CHECK_FOUND_ATTRIBUTE, /* 5001 */ + XML_CHECK_FOUND_TEXT, /* 5002 */ + XML_CHECK_FOUND_CDATA, /* 5003 */ + XML_CHECK_FOUND_ENTITYREF, /* 5004 */ + XML_CHECK_FOUND_ENTITY, /* 5005 */ + XML_CHECK_FOUND_PI, /* 5006 */ + XML_CHECK_FOUND_COMMENT, /* 5007 */ + XML_CHECK_FOUND_DOCTYPE, /* 5008 */ + XML_CHECK_FOUND_FRAGMENT, /* 5009 */ + XML_CHECK_FOUND_NOTATION, /* 5010 */ + XML_CHECK_UNKNOWN_NODE, /* 5011 */ + XML_CHECK_ENTITY_TYPE, /* 5012 */ + XML_CHECK_NO_PARENT, /* 5013 */ + XML_CHECK_NO_DOC, /* 5014 */ + XML_CHECK_NO_NAME, /* 5015 */ + XML_CHECK_NO_ELEM, /* 5016 */ + XML_CHECK_WRONG_DOC, /* 5017 */ + XML_CHECK_NO_PREV, /* 5018 */ + XML_CHECK_WRONG_PREV, /* 5019 */ + XML_CHECK_NO_NEXT, /* 5020 */ + XML_CHECK_WRONG_NEXT, /* 5021 */ + XML_CHECK_NOT_DTD, /* 5022 */ + XML_CHECK_NOT_ATTR, /* 5023 */ + XML_CHECK_NOT_ATTR_DECL, /* 5024 */ + XML_CHECK_NOT_ELEM_DECL, /* 5025 */ + XML_CHECK_NOT_ENTITY_DECL, /* 5026 */ + XML_CHECK_NOT_NS_DECL, /* 5027 */ + XML_CHECK_NO_HREF, /* 5028 */ + XML_CHECK_WRONG_PARENT,/* 5029 */ + XML_CHECK_NS_SCOPE, /* 5030 */ + XML_CHECK_NS_ANCESTOR, /* 5031 */ + XML_CHECK_NOT_UTF8, /* 5032 */ + XML_CHECK_NO_DICT, /* 5033 */ + XML_CHECK_NOT_NCNAME, /* 5034 */ + XML_CHECK_OUTSIDE_DICT, /* 5035 */ + XML_CHECK_WRONG_NAME, /* 5036 */ + XML_CHECK_NAME_NOT_NULL, /* 5037 */ + XML_I18N_NO_NAME = 6000, + XML_I18N_NO_HANDLER, /* 6001 */ + XML_I18N_EXCESS_HANDLER, /* 6002 */ + XML_I18N_CONV_FAILED, /* 6003 */ + XML_I18N_NO_OUTPUT, /* 6004 */ + XML_BUF_OVERFLOW = 7000 +} xmlParserErrors; + +/** + * xmlGenericErrorFunc: + * @ctx: a parsing context + * @msg: the message + * @...: the extra arguments of the varargs to format the message + * + * Signature of the function to use when there is an error and + * no parsing or validity context available . + */ +typedef void (*xmlGenericErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +/** + * xmlStructuredErrorFunc: + * @userData: user provided data for the error callback + * @error: the error being raised. + * + * Signature of the function to use when there is an error and + * the module handles the new error reporting mechanism. + */ +typedef void (*xmlStructuredErrorFunc) (void *userData, const xmlError *error); + +/** DOC_DISABLE */ +#define XML_GLOBALS_ERROR \ + XML_OP(xmlLastError, xmlError, XML_DEPRECATED) \ + XML_OP(xmlGenericError, xmlGenericErrorFunc, XML_NO_ATTR) \ + XML_OP(xmlGenericErrorContext, void *, XML_NO_ATTR) \ + XML_OP(xmlStructuredError, xmlStructuredErrorFunc, XML_NO_ATTR) \ + XML_OP(xmlStructuredErrorContext, void *, XML_NO_ATTR) + +#define XML_OP XML_DECLARE_GLOBAL +XML_GLOBALS_ERROR +#undef XML_OP + +#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlLastError XML_GLOBAL_MACRO(xmlLastError) + #define xmlGenericError XML_GLOBAL_MACRO(xmlGenericError) + #define xmlGenericErrorContext XML_GLOBAL_MACRO(xmlGenericErrorContext) + #define xmlStructuredError XML_GLOBAL_MACRO(xmlStructuredError) + #define xmlStructuredErrorContext XML_GLOBAL_MACRO(xmlStructuredErrorContext) +#endif +/** DOC_ENABLE */ + +/* + * Use the following function to reset the two global variables + * xmlGenericError and xmlGenericErrorContext. + */ +XMLPUBFUN void + xmlSetGenericErrorFunc (void *ctx, + xmlGenericErrorFunc handler); +XML_DEPRECATED +XMLPUBFUN void + xmlThrDefSetGenericErrorFunc(void *ctx, + xmlGenericErrorFunc handler); +XML_DEPRECATED +XMLPUBFUN void + initGenericErrorDefaultFunc (xmlGenericErrorFunc *handler); + +XMLPUBFUN void + xmlSetStructuredErrorFunc (void *ctx, + xmlStructuredErrorFunc handler); +XML_DEPRECATED +XMLPUBFUN void + xmlThrDefSetStructuredErrorFunc(void *ctx, + xmlStructuredErrorFunc handler); +/* + * Default message routines used by SAX and Valid context for error + * and warning reporting. + */ +XMLPUBFUN void + xmlParserError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void + xmlParserWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void + xmlParserValidityError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void + xmlParserValidityWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +/** DOC_DISABLE */ +struct _xmlParserInput; +/** DOC_ENABLE */ +XMLPUBFUN void + xmlParserPrintFileInfo (struct _xmlParserInput *input); +XMLPUBFUN void + xmlParserPrintFileContext (struct _xmlParserInput *input); +XMLPUBFUN void +xmlFormatError (const xmlError *err, + xmlGenericErrorFunc channel, + void *data); + +/* + * Extended error information routines + */ +XMLPUBFUN const xmlError * + xmlGetLastError (void); +XMLPUBFUN void + xmlResetLastError (void); +XMLPUBFUN const xmlError * + xmlCtxtGetLastError (void *ctx); +XMLPUBFUN void + xmlCtxtResetLastError (void *ctx); +XMLPUBFUN void + xmlResetError (xmlErrorPtr err); +XMLPUBFUN int + xmlCopyError (const xmlError *from, + xmlErrorPtr to); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_ERROR_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlexports.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlexports.h new file mode 100644 index 00000000..3c1d83f4 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlexports.h @@ -0,0 +1,146 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * Description: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __XML_EXPORTS_H__ +#define __XML_EXPORTS_H__ + +/** DOC_DISABLE */ + +/* + * Symbol visibility + */ + +#if defined(_WIN32) || defined(__CYGWIN__) + #ifdef LIBXML_STATIC + #define XMLPUBLIC + #elif defined(IN_LIBXML) + #define XMLPUBLIC __declspec(dllexport) + #else + #define XMLPUBLIC __declspec(dllimport) + #endif +#else /* not Windows */ + #define XMLPUBLIC +#endif /* platform switch */ + +#define XMLPUBFUN XMLPUBLIC + +#define XMLPUBVAR XMLPUBLIC extern + +/* Compatibility */ +#define XMLCALL +#define XMLCDECL +#ifndef LIBXML_DLL_IMPORT + #define LIBXML_DLL_IMPORT XMLPUBVAR +#endif + +/* + * Attributes + */ + +#ifndef ATTRIBUTE_UNUSED + #if __GNUC__ * 100 + __GNUC_MINOR__ >= 207 || defined(__clang__) + #define ATTRIBUTE_UNUSED __attribute__((unused)) + #else + #define ATTRIBUTE_UNUSED + #endif +#endif + +#if !defined(__clang__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) + #define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) +#else + #define LIBXML_ATTR_ALLOC_SIZE(x) +#endif + +#if __GNUC__ * 100 + __GNUC_MINOR__ >= 303 + #define LIBXML_ATTR_FORMAT(fmt,args) \ + __attribute__((__format__(__printf__,fmt,args))) +#else + #define LIBXML_ATTR_FORMAT(fmt,args) +#endif + +#ifndef XML_DEPRECATED + #if defined(IN_LIBXML) + #define XML_DEPRECATED + #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 301 + #define XML_DEPRECATED __attribute__((deprecated)) + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + /* Available since Visual Studio 2005 */ + #define XML_DEPRECATED __declspec(deprecated) + #else + #define XML_DEPRECATED + #endif +#endif + +/* + * Warnings pragmas, should be moved from public headers + */ + +#if defined(__LCC__) + + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS \ + _Pragma("diag_default 1215") + +#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) + + #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800) + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"") + #else + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + #endif + #define XML_POP_WARNINGS \ + _Pragma("GCC diagnostic pop") + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + + #define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push)) + #define XML_POP_WARNINGS __pragma(warning(pop)) + +#else + + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS + +#endif + +/* + * Accessors for globals + */ + +#define XML_NO_ATTR + +#ifdef LIBXML_THREAD_ENABLED + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBFUN type *__##name(void); + #define XML_GLOBAL_MACRO(name) (*__##name()) +#else + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBVAR type name; +#endif + +/* + * Originally declared in xmlversion.h which is generated + */ + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void xmlCheckVersion(int version); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_EXPORTS_H__ */ + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmemory.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmemory.h new file mode 100644 index 00000000..1de3e9fc --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmemory.h @@ -0,0 +1,188 @@ +/* + * Summary: interface for the memory allocator + * Description: provides interfaces for the memory allocator, + * including debugging capabilities. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __DEBUG_MEMORY_ALLOC__ +#define __DEBUG_MEMORY_ALLOC__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The XML memory wrapper support 4 basic overloadable functions. + */ +/** + * xmlFreeFunc: + * @mem: an already allocated block of memory + * + * Signature for a free() implementation. + */ +typedef void (*xmlFreeFunc)(void *mem); +/** + * xmlMallocFunc: + * @size: the size requested in bytes + * + * Signature for a malloc() implementation. + * + * Returns a pointer to the newly allocated block or NULL in case of error. + */ +typedef void *(LIBXML_ATTR_ALLOC_SIZE(1) *xmlMallocFunc)(size_t size); + +/** + * xmlReallocFunc: + * @mem: an already allocated block of memory + * @size: the new size requested in bytes + * + * Signature for a realloc() implementation. + * + * Returns a pointer to the newly reallocated block or NULL in case of error. + */ +typedef void *(*xmlReallocFunc)(void *mem, size_t size); + +/** + * xmlStrdupFunc: + * @str: a zero terminated string + * + * Signature for an strdup() implementation. + * + * Returns the copy of the string or NULL in case of error. + */ +typedef char *(*xmlStrdupFunc)(const char *str); + +/* + * In general the memory allocation entry points are not kept + * thread specific but this can be overridden by LIBXML_THREAD_ALLOC_ENABLED + * - xmlMalloc + * - xmlMallocAtomic + * - xmlRealloc + * - xmlMemStrdup + * - xmlFree + */ +/** DOC_DISABLE */ +#ifdef LIBXML_THREAD_ALLOC_ENABLED + #define XML_GLOBALS_ALLOC \ + XML_OP(xmlMalloc, xmlMallocFunc, XML_NO_ATTR) \ + XML_OP(xmlMallocAtomic, xmlMallocFunc, XML_NO_ATTR) \ + XML_OP(xmlRealloc, xmlReallocFunc, XML_NO_ATTR) \ + XML_OP(xmlFree, xmlFreeFunc, XML_NO_ATTR) \ + XML_OP(xmlMemStrdup, xmlStrdupFunc, XML_NO_ATTR) + #define XML_OP XML_DECLARE_GLOBAL + XML_GLOBALS_ALLOC + #undef XML_OP + #if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) + #define xmlMalloc XML_GLOBAL_MACRO(xmlMalloc) + #define xmlMallocAtomic XML_GLOBAL_MACRO(xmlMallocAtomic) + #define xmlRealloc XML_GLOBAL_MACRO(xmlRealloc) + #define xmlFree XML_GLOBAL_MACRO(xmlFree) + #define xmlMemStrdup XML_GLOBAL_MACRO(xmlMemStrdup) + #endif +#else + #define XML_GLOBALS_ALLOC +/** DOC_ENABLE */ + XMLPUBVAR xmlMallocFunc xmlMalloc; + XMLPUBVAR xmlMallocFunc xmlMallocAtomic; + XMLPUBVAR xmlReallocFunc xmlRealloc; + XMLPUBVAR xmlFreeFunc xmlFree; + XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif + +/* + * The way to overload the existing functions. + * The xmlGc function have an extra entry for atomic block + * allocations useful for garbage collected memory allocators + */ +XMLPUBFUN int + xmlMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int + xmlMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); +XMLPUBFUN int + xmlGcMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlMallocFunc mallocAtomicFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int + xmlGcMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlMallocFunc *mallocAtomicFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); + +/* + * Initialization of the memory layer. + */ +XML_DEPRECATED +XMLPUBFUN int + xmlInitMemory (void); + +/* + * Cleanup of the memory layer. + */ +XML_DEPRECATED +XMLPUBFUN void + xmlCleanupMemory (void); +/* + * These are specific to the XML debug memory wrapper. + */ +XMLPUBFUN size_t + xmlMemSize (void *ptr); +XMLPUBFUN int + xmlMemUsed (void); +XMLPUBFUN int + xmlMemBlocks (void); +XML_DEPRECATED +XMLPUBFUN void + xmlMemDisplay (FILE *fp); +XML_DEPRECATED +XMLPUBFUN void + xmlMemDisplayLast(FILE *fp, long nbBytes); +XML_DEPRECATED +XMLPUBFUN void + xmlMemShow (FILE *fp, int nr); +XML_DEPRECATED +XMLPUBFUN void + xmlMemoryDump (void); +XMLPUBFUN void * + xmlMemMalloc (size_t size) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN void * + xmlMemRealloc (void *ptr,size_t size); +XMLPUBFUN void + xmlMemFree (void *ptr); +XMLPUBFUN char * + xmlMemoryStrdup (const char *str); +XML_DEPRECATED +XMLPUBFUN void * + xmlMallocLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XML_DEPRECATED +XMLPUBFUN void * + xmlReallocLoc (void *ptr, size_t size, const char *file, int line); +XML_DEPRECATED +XMLPUBFUN void * + xmlMallocAtomicLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XML_DEPRECATED +XMLPUBFUN char * + xmlMemStrdupLoc (const char *str, const char *file, int line); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DEBUG_MEMORY_ALLOC__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmodule.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmodule.h new file mode 100644 index 00000000..279986c1 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlmodule.h @@ -0,0 +1,57 @@ +/* + * Summary: dynamic module loading + * Description: basic API for dynamic module loading, used by + * libexslt added in 2.6.17 + * + * Copy: See Copyright for the status of this software. + * + * Author: Joel W. Reed + */ + +#ifndef __XML_MODULE_H__ +#define __XML_MODULE_H__ + +#include + +#ifdef LIBXML_MODULES_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlModulePtr: + * + * A handle to a dynamically loaded module + */ +typedef struct _xmlModule xmlModule; +typedef xmlModule *xmlModulePtr; + +/** + * xmlModuleOption: + * + * enumeration of options that can be passed down to xmlModuleOpen() + */ +typedef enum { + XML_MODULE_LAZY = 1, /* lazy binding */ + XML_MODULE_LOCAL= 2 /* local binding */ +} xmlModuleOption; + +XMLPUBFUN xmlModulePtr xmlModuleOpen (const char *filename, + int options); + +XMLPUBFUN int xmlModuleSymbol (xmlModulePtr module, + const char* name, + void **result); + +XMLPUBFUN int xmlModuleClose (xmlModulePtr module); + +XMLPUBFUN int xmlModuleFree (xmlModulePtr module); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_MODULES_ENABLED */ + +#endif /*__XML_MODULE_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlreader.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlreader.h new file mode 100644 index 00000000..5d4fc5d5 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlreader.h @@ -0,0 +1,436 @@ +/* + * Summary: the XMLReader implementation + * Description: API of the XML streaming API based on C# interfaces. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLREADER_H__ +#define __XML_XMLREADER_H__ + +#include +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif +/* for compatibility */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserSeverities: + * + * How severe an error callback is when the per-reader error callback API + * is used. + */ +typedef enum { + XML_PARSER_SEVERITY_VALIDITY_WARNING = 1, + XML_PARSER_SEVERITY_VALIDITY_ERROR = 2, + XML_PARSER_SEVERITY_WARNING = 3, + XML_PARSER_SEVERITY_ERROR = 4 +} xmlParserSeverities; + +#ifdef LIBXML_READER_ENABLED + +/** + * xmlTextReaderMode: + * + * Internal state values for the reader. + */ +typedef enum { + XML_TEXTREADER_MODE_INITIAL = 0, + XML_TEXTREADER_MODE_INTERACTIVE = 1, + XML_TEXTREADER_MODE_ERROR = 2, + XML_TEXTREADER_MODE_EOF =3, + XML_TEXTREADER_MODE_CLOSED = 4, + XML_TEXTREADER_MODE_READING = 5 +} xmlTextReaderMode; + +/** + * xmlParserProperties: + * + * Some common options to use with xmlTextReaderSetParserProp, but it + * is better to use xmlParserOption and the xmlReaderNewxxx and + * xmlReaderForxxx APIs now. + */ +typedef enum { + XML_PARSER_LOADDTD = 1, + XML_PARSER_DEFAULTATTRS = 2, + XML_PARSER_VALIDATE = 3, + XML_PARSER_SUBST_ENTITIES = 4 +} xmlParserProperties; + +/** + * xmlReaderTypes: + * + * Predefined constants for the different types of nodes. + */ +typedef enum { + XML_READER_TYPE_NONE = 0, + XML_READER_TYPE_ELEMENT = 1, + XML_READER_TYPE_ATTRIBUTE = 2, + XML_READER_TYPE_TEXT = 3, + XML_READER_TYPE_CDATA = 4, + XML_READER_TYPE_ENTITY_REFERENCE = 5, + XML_READER_TYPE_ENTITY = 6, + XML_READER_TYPE_PROCESSING_INSTRUCTION = 7, + XML_READER_TYPE_COMMENT = 8, + XML_READER_TYPE_DOCUMENT = 9, + XML_READER_TYPE_DOCUMENT_TYPE = 10, + XML_READER_TYPE_DOCUMENT_FRAGMENT = 11, + XML_READER_TYPE_NOTATION = 12, + XML_READER_TYPE_WHITESPACE = 13, + XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14, + XML_READER_TYPE_END_ELEMENT = 15, + XML_READER_TYPE_END_ENTITY = 16, + XML_READER_TYPE_XML_DECLARATION = 17 +} xmlReaderTypes; + +/** + * xmlTextReader: + * + * Structure for an xmlReader context. + */ +typedef struct _xmlTextReader xmlTextReader; + +/** + * xmlTextReaderPtr: + * + * Pointer to an xmlReader context. + */ +typedef xmlTextReader *xmlTextReaderPtr; + +/* + * Constructors & Destructor + */ +XMLPUBFUN xmlTextReaderPtr + xmlNewTextReader (xmlParserInputBufferPtr input, + const char *URI); +XMLPUBFUN xmlTextReaderPtr + xmlNewTextReaderFilename(const char *URI); + +XMLPUBFUN void + xmlFreeTextReader (xmlTextReaderPtr reader); + +XMLPUBFUN int + xmlTextReaderSetup(xmlTextReaderPtr reader, + xmlParserInputBufferPtr input, const char *URL, + const char *encoding, int options); +XMLPUBFUN void + xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, + unsigned maxAmpl); +XMLPUBFUN const xmlError * + xmlTextReaderGetLastError(xmlTextReaderPtr reader); + +/* + * Iterators + */ +XMLPUBFUN int + xmlTextReaderRead (xmlTextReaderPtr reader); + +#ifdef LIBXML_WRITER_ENABLED +XMLPUBFUN xmlChar * + xmlTextReaderReadInnerXml(xmlTextReaderPtr reader); + +XMLPUBFUN xmlChar * + xmlTextReaderReadOuterXml(xmlTextReaderPtr reader); +#endif + +XMLPUBFUN xmlChar * + xmlTextReaderReadString (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader); + +/* + * Attributes of the node + */ +XMLPUBFUN int + xmlTextReaderAttributeCount(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderDepth (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderHasAttributes(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderHasValue(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderIsDefault (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderNodeType (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderQuoteChar (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderReadState (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader); + +XMLPUBFUN const xmlChar * + xmlTextReaderConstBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstLocalName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstPrefix (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstString (xmlTextReaderPtr reader, + const xmlChar *str); +XMLPUBFUN const xmlChar * + xmlTextReaderConstValue (xmlTextReaderPtr reader); + +/* + * use the Const version of the routine for + * better performance and simpler code + */ +XMLPUBFUN xmlChar * + xmlTextReaderBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderLocalName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderPrefix (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderValue (xmlTextReaderPtr reader); + +/* + * Methods of the XmlTextReader + */ +XMLPUBFUN int + xmlTextReaderClose (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderGetAttributeNo (xmlTextReaderPtr reader, + int no); +XMLPUBFUN xmlChar * + xmlTextReaderGetAttribute (xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN xmlChar * + xmlTextReaderGetAttributeNs (xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN xmlParserInputBufferPtr + xmlTextReaderGetRemainder (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * + xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, + const xmlChar *prefix); +XMLPUBFUN int + xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, + int no); +XMLPUBFUN int + xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN int + xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN int + xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderMoveToElement (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderNormalization (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * + xmlTextReaderConstEncoding (xmlTextReaderPtr reader); + +/* + * Extensions + */ +XMLPUBFUN int + xmlTextReaderSetParserProp (xmlTextReaderPtr reader, + int prop, + int value); +XMLPUBFUN int + xmlTextReaderGetParserProp (xmlTextReaderPtr reader, + int prop); +XMLPUBFUN xmlNodePtr + xmlTextReaderCurrentNode (xmlTextReaderPtr reader); + +XMLPUBFUN int + xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader); + +XMLPUBFUN int + xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader); + +XMLPUBFUN xmlNodePtr + xmlTextReaderPreserve (xmlTextReaderPtr reader); +#ifdef LIBXML_PATTERN_ENABLED +XMLPUBFUN int + xmlTextReaderPreservePattern(xmlTextReaderPtr reader, + const xmlChar *pattern, + const xmlChar **namespaces); +#endif /* LIBXML_PATTERN_ENABLED */ +XMLPUBFUN xmlDocPtr + xmlTextReaderCurrentDoc (xmlTextReaderPtr reader); +XMLPUBFUN xmlNodePtr + xmlTextReaderExpand (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderNext (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderNextSibling (xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderIsValid (xmlTextReaderPtr reader); +#ifdef LIBXML_SCHEMAS_ENABLED +XMLPUBFUN int + xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, + const char *rng); +XMLPUBFUN int + xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader, + xmlRelaxNGValidCtxtPtr ctxt, + int options); + +XMLPUBFUN int + xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, + xmlRelaxNGPtr schema); +XMLPUBFUN int + xmlTextReaderSchemaValidate (xmlTextReaderPtr reader, + const char *xsd); +XMLPUBFUN int + xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader, + xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN int + xmlTextReaderSetSchema (xmlTextReaderPtr reader, + xmlSchemaPtr schema); +#endif +XMLPUBFUN const xmlChar * + xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader); +XMLPUBFUN int + xmlTextReaderStandalone (xmlTextReaderPtr reader); + + +/* + * Index lookup + */ +XMLPUBFUN long + xmlTextReaderByteConsumed (xmlTextReaderPtr reader); + +/* + * New more complete APIs for simpler creation and reuse of readers + */ +XMLPUBFUN xmlTextReaderPtr + xmlReaderWalker (xmlDocPtr doc); +XMLPUBFUN xmlTextReaderPtr + xmlReaderForDoc (const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr + xmlReaderForFile (const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr + xmlReaderForMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr + xmlReaderForFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr + xmlReaderForIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +XMLPUBFUN int + xmlReaderNewWalker (xmlTextReaderPtr reader, + xmlDocPtr doc); +XMLPUBFUN int + xmlReaderNewDoc (xmlTextReaderPtr reader, + const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int + xmlReaderNewFile (xmlTextReaderPtr reader, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN int + xmlReaderNewMemory (xmlTextReaderPtr reader, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int + xmlReaderNewFd (xmlTextReaderPtr reader, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int + xmlReaderNewIO (xmlTextReaderPtr reader, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +/* + * Error handling extensions + */ +typedef void * xmlTextReaderLocatorPtr; + +/** + * xmlTextReaderErrorFunc: + * @arg: the user argument + * @msg: the message + * @severity: the severity of the error + * @locator: a locator indicating where the error occurred + * + * Signature of an error callback from a reader parser + */ +typedef void (*xmlTextReaderErrorFunc)(void *arg, + const char *msg, + xmlParserSeverities severity, + xmlTextReaderLocatorPtr locator); +XMLPUBFUN int + xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator); +XMLPUBFUN xmlChar * + xmlTextReaderLocatorBaseURI (xmlTextReaderLocatorPtr locator); +XMLPUBFUN void + xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc f, + void *arg); +XMLPUBFUN void + xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, + xmlStructuredErrorFunc f, + void *arg); +XMLPUBFUN void + xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc *f, + void **arg); + +#endif /* LIBXML_READER_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XMLREADER_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlregexp.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlregexp.h new file mode 100644 index 00000000..2d66437a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlregexp.h @@ -0,0 +1,215 @@ +/* + * Summary: regular expressions handling + * Description: basic API for libxml regular expressions handling used + * for XML Schemas and validation. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_REGEXP_H__ +#define __XML_REGEXP_H__ + +#include +#include +#include + +#ifdef LIBXML_REGEXP_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlRegexpPtr: + * + * A libxml regular expression, they can actually be far more complex + * thank the POSIX regex expressions. + */ +typedef struct _xmlRegexp xmlRegexp; +typedef xmlRegexp *xmlRegexpPtr; + +/** + * xmlRegExecCtxtPtr: + * + * A libxml progressive regular expression evaluation context + */ +typedef struct _xmlRegExecCtxt xmlRegExecCtxt; +typedef xmlRegExecCtxt *xmlRegExecCtxtPtr; + +/* + * The POSIX like API + */ +XMLPUBFUN xmlRegexpPtr + xmlRegexpCompile (const xmlChar *regexp); +XMLPUBFUN void xmlRegFreeRegexp(xmlRegexpPtr regexp); +XMLPUBFUN int + xmlRegexpExec (xmlRegexpPtr comp, + const xmlChar *value); +XMLPUBFUN void + xmlRegexpPrint (FILE *output, + xmlRegexpPtr regexp); +XMLPUBFUN int + xmlRegexpIsDeterminist(xmlRegexpPtr comp); + +/** + * xmlRegExecCallbacks: + * @exec: the regular expression context + * @token: the current token string + * @transdata: transition data + * @inputdata: input data + * + * Callback function when doing a transition in the automata + */ +typedef void (*xmlRegExecCallbacks) (xmlRegExecCtxtPtr exec, + const xmlChar *token, + void *transdata, + void *inputdata); + +/* + * The progressive API + */ +XMLPUBFUN xmlRegExecCtxtPtr + xmlRegNewExecCtxt (xmlRegexpPtr comp, + xmlRegExecCallbacks callback, + void *data); +XMLPUBFUN void + xmlRegFreeExecCtxt (xmlRegExecCtxtPtr exec); +XMLPUBFUN int + xmlRegExecPushString(xmlRegExecCtxtPtr exec, + const xmlChar *value, + void *data); +XMLPUBFUN int + xmlRegExecPushString2(xmlRegExecCtxtPtr exec, + const xmlChar *value, + const xmlChar *value2, + void *data); + +XMLPUBFUN int + xmlRegExecNextValues(xmlRegExecCtxtPtr exec, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +XMLPUBFUN int + xmlRegExecErrInfo (xmlRegExecCtxtPtr exec, + const xmlChar **string, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +#ifdef LIBXML_EXPR_ENABLED +/* + * Formal regular expression handling + * Its goal is to do some formal work on content models + */ + +/* expressions are used within a context */ +typedef struct _xmlExpCtxt xmlExpCtxt; +typedef xmlExpCtxt *xmlExpCtxtPtr; + +XMLPUBFUN void + xmlExpFreeCtxt (xmlExpCtxtPtr ctxt); +XMLPUBFUN xmlExpCtxtPtr + xmlExpNewCtxt (int maxNodes, + xmlDictPtr dict); + +XMLPUBFUN int + xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt); +XMLPUBFUN int + xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt); + +/* Expressions are trees but the tree is opaque */ +typedef struct _xmlExpNode xmlExpNode; +typedef xmlExpNode *xmlExpNodePtr; + +typedef enum { + XML_EXP_EMPTY = 0, + XML_EXP_FORBID = 1, + XML_EXP_ATOM = 2, + XML_EXP_SEQ = 3, + XML_EXP_OR = 4, + XML_EXP_COUNT = 5 +} xmlExpNodeType; + +/* + * 2 core expressions shared by all for the empty language set + * and for the set with just the empty token + */ +XMLPUBVAR xmlExpNodePtr forbiddenExp; +XMLPUBVAR xmlExpNodePtr emptyExp; + +/* + * Expressions are reference counted internally + */ +XMLPUBFUN void + xmlExpFree (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr); +XMLPUBFUN void + xmlExpRef (xmlExpNodePtr expr); + +/* + * constructors can be either manual or from a string + */ +XMLPUBFUN xmlExpNodePtr + xmlExpParse (xmlExpCtxtPtr ctxt, + const char *expr); +XMLPUBFUN xmlExpNodePtr + xmlExpNewAtom (xmlExpCtxtPtr ctxt, + const xmlChar *name, + int len); +XMLPUBFUN xmlExpNodePtr + xmlExpNewOr (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr + xmlExpNewSeq (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr + xmlExpNewRange (xmlExpCtxtPtr ctxt, + xmlExpNodePtr subset, + int min, + int max); +/* + * The really interesting APIs + */ +XMLPUBFUN int + xmlExpIsNillable(xmlExpNodePtr expr); +XMLPUBFUN int + xmlExpMaxToken (xmlExpNodePtr expr); +XMLPUBFUN int + xmlExpGetLanguage(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**langList, + int len); +XMLPUBFUN int + xmlExpGetStart (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**tokList, + int len); +XMLPUBFUN xmlExpNodePtr + xmlExpStringDerive(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar *str, + int len); +XMLPUBFUN xmlExpNodePtr + xmlExpExpDerive (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN int + xmlExpSubsume (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN void + xmlExpDump (xmlBufferPtr buf, + xmlExpNodePtr expr); +#endif /* LIBXML_EXPR_ENABLED */ +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /*__XML_REGEXP_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlsave.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlsave.h new file mode 100644 index 00000000..e266e467 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlsave.h @@ -0,0 +1,102 @@ +/* + * Summary: the XML document serializer + * Description: API to save document or subtree of document + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLSAVE_H__ +#define __XML_XMLSAVE_H__ + +#include +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlSaveOption: + * + * This is the set of XML save options that can be passed down + * to the xmlSaveToFd() and similar calls. + */ +typedef enum { + XML_SAVE_FORMAT = 1<<0, /* format save output */ + XML_SAVE_NO_DECL = 1<<1, /* drop the xml declaration */ + XML_SAVE_NO_EMPTY = 1<<2, /* no empty tags */ + XML_SAVE_NO_XHTML = 1<<3, /* disable XHTML1 specific rules */ + XML_SAVE_XHTML = 1<<4, /* force XHTML1 specific rules */ + XML_SAVE_AS_XML = 1<<5, /* force XML serialization on HTML doc */ + XML_SAVE_AS_HTML = 1<<6, /* force HTML serialization on XML doc */ + XML_SAVE_WSNONSIG = 1<<7 /* format with non-significant whitespace */ +} xmlSaveOption; + + +typedef struct _xmlSaveCtxt xmlSaveCtxt; +typedef xmlSaveCtxt *xmlSaveCtxtPtr; + +XMLPUBFUN xmlSaveCtxtPtr + xmlSaveToFd (int fd, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr + xmlSaveToFilename (const char *filename, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr + xmlSaveToBuffer (xmlBufferPtr buffer, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr + xmlSaveToIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + const char *encoding, + int options); + +XMLPUBFUN long + xmlSaveDoc (xmlSaveCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN long + xmlSaveTree (xmlSaveCtxtPtr ctxt, + xmlNodePtr node); + +XMLPUBFUN int + xmlSaveFlush (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int + xmlSaveClose (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int + xmlSaveFinish (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int + xmlSaveSetEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); +XMLPUBFUN int + xmlSaveSetAttrEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); + +XML_DEPRECATED +XMLPUBFUN int + xmlThrDefIndentTreeOutput(int v); +XML_DEPRECATED +XMLPUBFUN const char * + xmlThrDefTreeIndentString(const char * v); +XML_DEPRECATED +XMLPUBFUN int + xmlThrDefSaveNoEmptyTags(int v); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* __XML_XMLSAVE_H__ */ + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemas.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemas.h new file mode 100644 index 00000000..c2af3d70 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemas.h @@ -0,0 +1,249 @@ +/* + * Summary: incomplete XML Schemas structure implementation + * Description: interface to the XML Schemas handling and schema validity + * checking, it is incomplete right now. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_H__ +#define __XML_SCHEMA_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This error codes are obsolete; not used any more. + */ +typedef enum { + XML_SCHEMAS_ERR_OK = 0, + XML_SCHEMAS_ERR_NOROOT = 1, + XML_SCHEMAS_ERR_UNDECLAREDELEM, + XML_SCHEMAS_ERR_NOTTOPLEVEL, + XML_SCHEMAS_ERR_MISSING, + XML_SCHEMAS_ERR_WRONGELEM, + XML_SCHEMAS_ERR_NOTYPE, + XML_SCHEMAS_ERR_NOROLLBACK, + XML_SCHEMAS_ERR_ISABSTRACT, + XML_SCHEMAS_ERR_NOTEMPTY, + XML_SCHEMAS_ERR_ELEMCONT, + XML_SCHEMAS_ERR_HAVEDEFAULT, + XML_SCHEMAS_ERR_NOTNILLABLE, + XML_SCHEMAS_ERR_EXTRACONTENT, + XML_SCHEMAS_ERR_INVALIDATTR, + XML_SCHEMAS_ERR_INVALIDELEM, + XML_SCHEMAS_ERR_NOTDETERMINIST, + XML_SCHEMAS_ERR_CONSTRUCT, + XML_SCHEMAS_ERR_INTERNAL, + XML_SCHEMAS_ERR_NOTSIMPLE, + XML_SCHEMAS_ERR_ATTRUNKNOWN, + XML_SCHEMAS_ERR_ATTRINVALID, + XML_SCHEMAS_ERR_VALUE, + XML_SCHEMAS_ERR_FACET, + XML_SCHEMAS_ERR_, + XML_SCHEMAS_ERR_XXX +} xmlSchemaValidError; + +/* +* ATTENTION: Change xmlSchemaSetValidOptions's check +* for invalid values, if adding to the validation +* options below. +*/ +/** + * xmlSchemaValidOption: + * + * This is the set of XML Schema validation options. + */ +typedef enum { + XML_SCHEMA_VAL_VC_I_CREATE = 1<<0 + /* Default/fixed: create an attribute node + * or an element's text node on the instance. + */ +} xmlSchemaValidOption; + +/* + XML_SCHEMA_VAL_XSI_ASSEMBLE = 1<<1, + * assemble schemata using + * xsi:schemaLocation and + * xsi:noNamespaceSchemaLocation +*/ + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchema xmlSchema; +typedef xmlSchema *xmlSchemaPtr; + +/** + * xmlSchemaValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from an XSD validation + */ +typedef void (*xmlSchemaValidityErrorFunc) + (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlSchemaValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from an XSD validation + */ +typedef void (*xmlSchemaValidityWarningFunc) + (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlSchemaParserCtxt xmlSchemaParserCtxt; +typedef xmlSchemaParserCtxt *xmlSchemaParserCtxtPtr; + +typedef struct _xmlSchemaValidCtxt xmlSchemaValidCtxt; +typedef xmlSchemaValidCtxt *xmlSchemaValidCtxtPtr; + +/** + * xmlSchemaValidityLocatorFunc: + * @ctx: user provided context + * @file: returned file information + * @line: returned line information + * + * A schemas validation locator, a callback called by the validator. + * This is used when file or node information are not available + * to find out what file and line number are affected + * + * Returns: 0 in case of success and -1 in case of error + */ + +typedef int (*xmlSchemaValidityLocatorFunc) (void *ctx, + const char **file, unsigned long *line); + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchemaParserCtxtPtr + xmlSchemaNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchemaParserCtxtPtr + xmlSchemaNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlSchemaParserCtxtPtr + xmlSchemaNewDocParserCtxt (xmlDocPtr doc); +XMLPUBFUN void + xmlSchemaFreeParserCtxt (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void + xmlSchemaSetParserErrors (xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void + xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int + xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc * err, + xmlSchemaValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int + xmlSchemaIsValid (xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaPtr + xmlSchemaParse (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void + xmlSchemaFree (xmlSchemaPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void + xmlSchemaDump (FILE *output, + xmlSchemaPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void + xmlSchemaSetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void + xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int + xmlSchemaGetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc *err, + xmlSchemaValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int + xmlSchemaSetValidOptions (xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN void + xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt, + const char *filename); +XMLPUBFUN int + xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaValidCtxtPtr + xmlSchemaNewValidCtxt (xmlSchemaPtr schema); +XMLPUBFUN void + xmlSchemaFreeValidCtxt (xmlSchemaValidCtxtPtr ctxt); +XMLPUBFUN int + xmlSchemaValidateDoc (xmlSchemaValidCtxtPtr ctxt, + xmlDocPtr instance); +XMLPUBFUN int + xmlSchemaValidateOneElement (xmlSchemaValidCtxtPtr ctxt, + xmlNodePtr elem); +XMLPUBFUN int + xmlSchemaValidateStream (xmlSchemaValidCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc, + xmlSAXHandlerPtr sax, + void *user_data); +XMLPUBFUN int + xmlSchemaValidateFile (xmlSchemaValidCtxtPtr ctxt, + const char * filename, + int options); + +XMLPUBFUN xmlParserCtxtPtr + xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt); + +/* + * Interface to insert Schemas SAX validation in a SAX stream + */ +typedef struct _xmlSchemaSAXPlug xmlSchemaSAXPlugStruct; +typedef xmlSchemaSAXPlugStruct *xmlSchemaSAXPlugPtr; + +XMLPUBFUN xmlSchemaSAXPlugPtr + xmlSchemaSAXPlug (xmlSchemaValidCtxtPtr ctxt, + xmlSAXHandlerPtr *sax, + void **user_data); +XMLPUBFUN int + xmlSchemaSAXUnplug (xmlSchemaSAXPlugPtr plug); + + +XMLPUBFUN void + xmlSchemaValidateSetLocator (xmlSchemaValidCtxtPtr vctxt, + xmlSchemaValidityLocatorFunc f, + void *ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemastypes.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemastypes.h new file mode 100644 index 00000000..e2cde357 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlschemastypes.h @@ -0,0 +1,152 @@ +/* + * Summary: implementation of XML Schema Datatypes + * Description: module providing the XML Schema Datatypes implementation + * both definition and validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_TYPES_H__ +#define __XML_SCHEMA_TYPES_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMA_WHITESPACE_UNKNOWN = 0, + XML_SCHEMA_WHITESPACE_PRESERVE = 1, + XML_SCHEMA_WHITESPACE_REPLACE = 2, + XML_SCHEMA_WHITESPACE_COLLAPSE = 3 +} xmlSchemaWhitespaceValueType; + +XMLPUBFUN int + xmlSchemaInitTypes (void); +XML_DEPRECATED +XMLPUBFUN void + xmlSchemaCleanupTypes (void); +XMLPUBFUN xmlSchemaTypePtr + xmlSchemaGetPredefinedType (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int + xmlSchemaValidatePredefinedType (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val); +XMLPUBFUN int + xmlSchemaValPredefTypeNode (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int + xmlSchemaValidateFacet (xmlSchemaTypePtr base, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val); +XMLPUBFUN int + xmlSchemaValidateFacetWhtsp (xmlSchemaFacetPtr facet, + xmlSchemaWhitespaceValueType fws, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN void + xmlSchemaFreeValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaFacetPtr + xmlSchemaNewFacet (void); +XMLPUBFUN int + xmlSchemaCheckFacet (xmlSchemaFacetPtr facet, + xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr ctxt, + const xmlChar *name); +XMLPUBFUN void + xmlSchemaFreeFacet (xmlSchemaFacetPtr facet); +XMLPUBFUN int + xmlSchemaCompareValues (xmlSchemaValPtr x, + xmlSchemaValPtr y); +XMLPUBFUN xmlSchemaTypePtr + xmlSchemaGetBuiltInListSimpleTypeItemType (xmlSchemaTypePtr type); +XMLPUBFUN int + xmlSchemaValidateListSimpleTypeFacet (xmlSchemaFacetPtr facet, + const xmlChar *value, + unsigned long actualLen, + unsigned long *expectedLen); +XMLPUBFUN xmlSchemaTypePtr + xmlSchemaGetBuiltInType (xmlSchemaValType type); +XMLPUBFUN int + xmlSchemaIsBuiltInTypeFacet (xmlSchemaTypePtr type, + int facetType); +XMLPUBFUN xmlChar * + xmlSchemaCollapseString (const xmlChar *value); +XMLPUBFUN xmlChar * + xmlSchemaWhiteSpaceReplace (const xmlChar *value); +XMLPUBFUN unsigned long + xmlSchemaGetFacetValueAsULong (xmlSchemaFacetPtr facet); +XMLPUBFUN int + xmlSchemaValidateLengthFacet (xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length); +XMLPUBFUN int + xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int + xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int + xmlSchemaGetCanonValue (xmlSchemaValPtr val, + const xmlChar **retValue); +XMLPUBFUN int + xmlSchemaGetCanonValueWhtsp (xmlSchemaValPtr val, + const xmlChar **retValue, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int + xmlSchemaValueAppend (xmlSchemaValPtr prev, + xmlSchemaValPtr cur); +XMLPUBFUN xmlSchemaValPtr + xmlSchemaValueGetNext (xmlSchemaValPtr cur); +XMLPUBFUN const xmlChar * + xmlSchemaValueGetAsString (xmlSchemaValPtr val); +XMLPUBFUN int + xmlSchemaValueGetAsBoolean (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValPtr + xmlSchemaNewStringValue (xmlSchemaValType type, + const xmlChar *value); +XMLPUBFUN xmlSchemaValPtr + xmlSchemaNewNOTATIONValue (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN xmlSchemaValPtr + xmlSchemaNewQNameValue (const xmlChar *namespaceName, + const xmlChar *localName); +XMLPUBFUN int + xmlSchemaCompareValuesWhtsp (xmlSchemaValPtr x, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValPtr y, + xmlSchemaWhitespaceValueType yws); +XMLPUBFUN xmlSchemaValPtr + xmlSchemaCopyValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValType + xmlSchemaGetValType (xmlSchemaValPtr val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_TYPES_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlstring.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlstring.h new file mode 100644 index 00000000..db11a0b0 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlstring.h @@ -0,0 +1,140 @@ +/* + * Summary: set of routines to process strings + * Description: type and interfaces needed for the internal string handling + * of the library, especially UTF8 processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_STRING_H__ +#define __XML_STRING_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlChar: + * + * This is a basic byte in an UTF-8 encoded string. + * It's unsigned allowing to pinpoint case where char * are assigned + * to xmlChar * (possibly making serialization back impossible). + */ +typedef unsigned char xmlChar; + +/** + * BAD_CAST: + * + * Macro to cast a string to an xmlChar * when one know its safe. + */ +#define BAD_CAST (xmlChar *) + +/* + * xmlChar handling + */ +XMLPUBFUN xmlChar * + xmlStrdup (const xmlChar *cur); +XMLPUBFUN xmlChar * + xmlStrndup (const xmlChar *cur, + int len); +XMLPUBFUN xmlChar * + xmlCharStrndup (const char *cur, + int len); +XMLPUBFUN xmlChar * + xmlCharStrdup (const char *cur); +XMLPUBFUN xmlChar * + xmlStrsub (const xmlChar *str, + int start, + int len); +XMLPUBFUN const xmlChar * + xmlStrchr (const xmlChar *str, + xmlChar val); +XMLPUBFUN const xmlChar * + xmlStrstr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN const xmlChar * + xmlStrcasestr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN int + xmlStrcmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int + xmlStrncmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int + xmlStrcasecmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int + xmlStrncasecmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int + xmlStrEqual (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int + xmlStrQEqual (const xmlChar *pref, + const xmlChar *name, + const xmlChar *str); +XMLPUBFUN int + xmlStrlen (const xmlChar *str); +XMLPUBFUN xmlChar * + xmlStrcat (xmlChar *cur, + const xmlChar *add); +XMLPUBFUN xmlChar * + xmlStrncat (xmlChar *cur, + const xmlChar *add, + int len); +XMLPUBFUN xmlChar * + xmlStrncatNew (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int + xmlStrPrintf (xmlChar *buf, + int len, + const char *msg, + ...) LIBXML_ATTR_FORMAT(3,4); +XMLPUBFUN int + xmlStrVPrintf (xmlChar *buf, + int len, + const char *msg, + va_list ap) LIBXML_ATTR_FORMAT(3,0); + +XMLPUBFUN int + xmlGetUTF8Char (const unsigned char *utf, + int *len); +XMLPUBFUN int + xmlCheckUTF8 (const unsigned char *utf); +XMLPUBFUN int + xmlUTF8Strsize (const xmlChar *utf, + int len); +XMLPUBFUN xmlChar * + xmlUTF8Strndup (const xmlChar *utf, + int len); +XMLPUBFUN const xmlChar * + xmlUTF8Strpos (const xmlChar *utf, + int pos); +XMLPUBFUN int + xmlUTF8Strloc (const xmlChar *utf, + const xmlChar *utfchar); +XMLPUBFUN xmlChar * + xmlUTF8Strsub (const xmlChar *utf, + int start, + int len); +XMLPUBFUN int + xmlUTF8Strlen (const xmlChar *utf); +XMLPUBFUN int + xmlUTF8Size (const xmlChar *utf); +XMLPUBFUN int + xmlUTF8Charcmp (const xmlChar *utf1, + const xmlChar *utf2); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_STRING_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlunicode.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlunicode.h new file mode 100644 index 00000000..b6d795b2 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlunicode.h @@ -0,0 +1,366 @@ +/* + * Summary: Unicode character APIs + * Description: API for the Unicode character APIs + * + * This file is automatically generated from the + * UCS description files of the Unicode Character Database + * http://www.unicode.org/Public/4.0-Update1/UCD-4.0.1.html + * using the genUnicode.py Python script. + * + * Generation date: Tue Apr 30 17:30:38 2024 + * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt + * Author: Daniel Veillard + */ + +#ifndef __XML_UNICODE_H__ +#define __XML_UNICODE_H__ + +#include + +#ifdef LIBXML_UNICODE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsAegeanNumbers (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsAlphabeticPresentationForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabicPresentationFormsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArabicPresentationFormsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArmenian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsArrows (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBasicLatin (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBengali (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBlockElements (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBopomofo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBopomofoExtended (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBoxDrawing (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBraillePatterns (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsBuhid (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsByzantineMusicalSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibility (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKRadicalsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKSymbolsandPunctuation (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCherokee (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarks (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarksforSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningHalfMarks (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCombiningMarksforSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsControlPictures (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCurrencySymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCypriotSyllabary (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCyrillic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCyrillicSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDeseret (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDevanagari (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsDingbats (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEnclosedAlphanumerics (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEnclosedCJKLettersandMonths (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsEthiopic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeneralPunctuation (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeometricShapes (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGeorgian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGothic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreek (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreekExtended (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGreekandCoptic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGujarati (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsGurmukhi (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHalfwidthandFullwidthForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulCompatibilityJamo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulJamo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHangulSyllables (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHanunoo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHebrew (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHighPrivateUseSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHighSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsHiragana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsIPAExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsIdeographicDescriptionCharacters (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKanbun (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKangxiRadicals (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKannada (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKatakana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKatakanaPhoneticExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKhmer (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsKhmerSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLao (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatin1Supplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLatinExtendedAdditional (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLetterlikeSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLimbu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLinearBIdeograms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLinearBSyllabary (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsLowSurrogates (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMalayalam (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMathematicalAlphanumericSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMathematicalOperators (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousSymbolsandArrows (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMiscellaneousTechnical (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMongolian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMusicalSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsMyanmar (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsNumberForms (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOgham (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOldItalic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOpticalCharacterRecognition (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOriya (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsOsmanya (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPhoneticExtensions (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPrivateUse (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsPrivateUseArea (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsRunic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsShavian (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSinhala (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSmallFormVariants (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSpacingModifierLetters (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSpecials (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSuperscriptsandSubscripts (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalArrowsA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalArrowsB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementalMathematicalOperators (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaA (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaB (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsSyriac (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTagalog (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTagbanwa (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTags (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTaiLe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTaiXuanJingSymbols (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTamil (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTelugu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsThaana (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsThai (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsTibetan (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsUgaritic (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsUnifiedCanadianAboriginalSyllabics (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsVariationSelectors (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsVariationSelectorsSupplement (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYiRadicals (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYiSyllables (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsYijingHexagramSymbols (int code); + +XMLPUBFUN int xmlUCSIsBlock (int code, const char *block); + +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatC (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCf (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatCs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatL (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLm (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLt (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatLu (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatM (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatMn (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatN (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNd (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatNo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatP (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPd (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPe (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPf (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPi (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatPs (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatS (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSc (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSk (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSm (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatSo (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZ (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZl (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZp (int code); +XML_DEPRECATED +XMLPUBFUN int xmlUCSIsCatZs (int code); + +XMLPUBFUN int xmlUCSIsCat (int code, const char *cat); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_UNICODE_ENABLED */ + +#endif /* __XML_UNICODE_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlversion.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlversion.h new file mode 100644 index 00000000..75102322 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlversion.h @@ -0,0 +1,347 @@ +/* + * Summary: compile-time version information + * Description: compile-time version information for the XML library + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.13.6" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXML_VERSION 21306 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXML_VERSION_STRING "21306" + +/** + * LIBXML_VERSION_EXTRA: + * + * extra version information, used to show a git commit description + */ +#define LIBXML_VERSION_EXTRA "" + +/** + * LIBXML_TEST_VERSION: + * + * Macro to check that the libxml version in use is compatible with + * the version the software has been compiled against + */ +#define LIBXML_TEST_VERSION xmlCheckVersion(21306); + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 1 +#define LIBXML_THREAD_ENABLED +#endif + +/** + * LIBXML_THREAD_ALLOC_ENABLED: + * + * Whether the allocation hooks are per-thread + */ +#if 0 +#define LIBXML_THREAD_ALLOC_ENABLED +#endif + +/** + * LIBXML_TREE_ENABLED: + * + * Whether the DOM like tree manipulation API support is configured in + */ +#if 1 +#define LIBXML_TREE_ENABLED +#endif + +/** + * LIBXML_OUTPUT_ENABLED: + * + * Whether the serialization/saving support is configured in + */ +#if 1 +#define LIBXML_OUTPUT_ENABLED +#endif + +/** + * LIBXML_PUSH_ENABLED: + * + * Whether the push parsing interfaces are configured in + */ +#if 1 +#define LIBXML_PUSH_ENABLED +#endif + +/** + * LIBXML_READER_ENABLED: + * + * Whether the xmlReader parsing interface is configured in + */ +#if 1 +#define LIBXML_READER_ENABLED +#endif + +/** + * LIBXML_PATTERN_ENABLED: + * + * Whether the xmlPattern node selection interface is configured in + */ +#if 1 +#define LIBXML_PATTERN_ENABLED +#endif + +/** + * LIBXML_WRITER_ENABLED: + * + * Whether the xmlWriter saving interface is configured in + */ +#if 1 +#define LIBXML_WRITER_ENABLED +#endif + +/** + * LIBXML_SAX1_ENABLED: + * + * Whether the older SAX1 interface is configured in + */ +#if 1 +#define LIBXML_SAX1_ENABLED +#endif + +/** + * LIBXML_FTP_ENABLED: + * + * Whether the FTP support is configured in + */ +#if 0 +#define LIBXML_FTP_ENABLED +#endif + +/** + * LIBXML_HTTP_ENABLED: + * + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#endif + +/** + * LIBXML_VALID_ENABLED: + * + * Whether the DTD validation support is configured in + */ +#if 1 +#define LIBXML_VALID_ENABLED +#endif + +/** + * LIBXML_HTML_ENABLED: + * + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#endif + +/** + * LIBXML_LEGACY_ENABLED: + * + * Whether the deprecated APIs are compiled in for compatibility + */ +#if 1 +#define LIBXML_LEGACY_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 1 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 1 +#define LIBXML_CATALOG_ENABLED +#endif + +/** + * LIBXML_XPATH_ENABLED: + * + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#endif + +/** + * LIBXML_XPTR_ENABLED: + * + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#endif + +/** + * LIBXML_XPTR_LOCS_ENABLED: + * + * Whether support for XPointer locations is configured in + */ +#if 0 +#define LIBXML_XPTR_LOCS_ENABLED +#endif + +/** + * LIBXML_XINCLUDE_ENABLED: + * + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#endif + +/** + * LIBXML_ICONV_ENABLED: + * + * Whether iconv support is available + */ +#if 1 +#define LIBXML_ICONV_ENABLED +#endif + +/** + * LIBXML_ICU_ENABLED: + * + * Whether icu support is available + */ +#if 0 +#define LIBXML_ICU_ENABLED +#endif + +/** + * LIBXML_ISO8859X_ENABLED: + * + * Whether ISO-8859-* support is made available in case iconv is not + */ +#if 1 +#define LIBXML_ISO8859X_ENABLED +#endif + +/** + * LIBXML_DEBUG_ENABLED: + * + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#endif + +/** + * LIBXML_UNICODE_ENABLED: + * + * Whether the Unicode related interfaces are compiled in + */ +#if 1 +#define LIBXML_UNICODE_ENABLED +#endif + +/** + * LIBXML_REGEXP_ENABLED: + * + * Whether the regular expressions interfaces are compiled in + */ +#if 1 +#define LIBXML_REGEXP_ENABLED +#endif + +/** + * LIBXML_AUTOMATA_ENABLED: + * + * Whether the automata interfaces are compiled in + */ +#if 1 +#define LIBXML_AUTOMATA_ENABLED +#endif + +/** + * LIBXML_SCHEMAS_ENABLED: + * + * Whether the Schemas validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMAS_ENABLED +#endif + +/** + * LIBXML_SCHEMATRON_ENABLED: + * + * Whether the Schematron validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMATRON_ENABLED +#endif + +/** + * LIBXML_MODULES_ENABLED: + * + * Whether the module interfaces are compiled in + */ +#if 1 +#define LIBXML_MODULES_ENABLED +/** + * LIBXML_MODULE_EXTENSION: + * + * the string suffix used by dynamic modules (usually shared libraries) + */ +#define LIBXML_MODULE_EXTENSION ".so" +#endif + +/** + * LIBXML_ZLIB_ENABLED: + * + * Whether the Zlib support is compiled in + */ +#if 1 +#define LIBXML_ZLIB_ENABLED +#endif + +/** + * LIBXML_LZMA_ENABLED: + * + * Whether the Lzma support is compiled in + */ +#if 0 +#define LIBXML_LZMA_ENABLED +#endif + +#include + +#endif + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlwriter.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlwriter.h new file mode 100644 index 00000000..55f88bc7 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xmlwriter.h @@ -0,0 +1,489 @@ +/* + * Summary: text writing API for XML + * Description: text writing API for XML + * + * Copy: See Copyright for the status of this software. + * + * Author: Alfred Mickautsch + */ + +#ifndef __XML_XMLWRITER_H__ +#define __XML_XMLWRITER_H__ + +#include + +#ifdef LIBXML_WRITER_ENABLED + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _xmlTextWriter xmlTextWriter; + typedef xmlTextWriter *xmlTextWriterPtr; + +/* + * Constructors & Destructor + */ + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriter(xmlOutputBufferPtr out); + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriterFilename(const char *uri, int compression); + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriterMemory(xmlBufferPtr buf, int compression); + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, int compression); + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriterDoc(xmlDocPtr * doc, int compression); + XMLPUBFUN xmlTextWriterPtr + xmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, + int compression); + XMLPUBFUN void xmlFreeTextWriter(xmlTextWriterPtr writer); + +/* + * Functions + */ + + +/* + * Document + */ + XMLPUBFUN int + xmlTextWriterStartDocument(xmlTextWriterPtr writer, + const char *version, + const char *encoding, + const char *standalone); + XMLPUBFUN int xmlTextWriterEndDocument(xmlTextWriterPtr + writer); + +/* + * Comments + */ + XMLPUBFUN int xmlTextWriterStartComment(xmlTextWriterPtr + writer); + XMLPUBFUN int xmlTextWriterEndComment(xmlTextWriterPtr writer); + XMLPUBFUN int + xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int + xmlTextWriterWriteVFormatComment(xmlTextWriterPtr writer, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int xmlTextWriterWriteComment(xmlTextWriterPtr + writer, + const xmlChar * + content); + +/* + * Elements + */ + XMLPUBFUN int + xmlTextWriterStartElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int xmlTextWriterStartElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI); + XMLPUBFUN int xmlTextWriterEndElement(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterFullEndElement(xmlTextWriterPtr + writer); + +/* + * Elements conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int + xmlTextWriterWriteVFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int xmlTextWriterWriteElement(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int + xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int + xmlTextWriterWriteVFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int xmlTextWriterWriteElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * Text + */ + XMLPUBFUN int + xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int + xmlTextWriterWriteVFormatRaw(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int + xmlTextWriterWriteRawLen(xmlTextWriterPtr writer, + const xmlChar * content, int len); + XMLPUBFUN int + xmlTextWriterWriteRaw(xmlTextWriterPtr writer, + const xmlChar * content); + XMLPUBFUN int xmlTextWriterWriteFormatString(xmlTextWriterPtr + writer, + const char + *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int xmlTextWriterWriteVFormatString(xmlTextWriterPtr + writer, + const char + *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int xmlTextWriterWriteString(xmlTextWriterPtr writer, + const xmlChar * + content); + XMLPUBFUN int xmlTextWriterWriteBase64(xmlTextWriterPtr writer, + const char *data, + int start, int len); + XMLPUBFUN int xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, + const char *data, + int start, int len); + +/* + * Attributes + */ + XMLPUBFUN int + xmlTextWriterStartAttribute(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int xmlTextWriterStartAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI); + XMLPUBFUN int xmlTextWriterEndAttribute(xmlTextWriterPtr + writer); + +/* + * Attributes conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int + xmlTextWriterWriteVFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int xmlTextWriterWriteAttribute(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int + xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int + xmlTextWriterWriteVFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int xmlTextWriterWriteAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * PI's + */ + XMLPUBFUN int + xmlTextWriterStartPI(xmlTextWriterPtr writer, + const xmlChar * target); + XMLPUBFUN int xmlTextWriterEndPI(xmlTextWriterPtr writer); + +/* + * PI conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int + xmlTextWriterWriteVFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int + xmlTextWriterWritePI(xmlTextWriterPtr writer, + const xmlChar * target, + const xmlChar * content); + +/** + * xmlTextWriterWriteProcessingInstruction: + * + * This macro maps to xmlTextWriterWritePI + */ +#define xmlTextWriterWriteProcessingInstruction xmlTextWriterWritePI + +/* + * CDATA + */ + XMLPUBFUN int xmlTextWriterStartCDATA(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterEndCDATA(xmlTextWriterPtr writer); + +/* + * CDATA conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int + xmlTextWriterWriteVFormatCDATA(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int + xmlTextWriterWriteCDATA(xmlTextWriterPtr writer, + const xmlChar * content); + +/* + * DTD + */ + XMLPUBFUN int + xmlTextWriterStartDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + XMLPUBFUN int xmlTextWriterEndDTD(xmlTextWriterPtr writer); + +/* + * DTD conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int + xmlTextWriterWriteVFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int + xmlTextWriterWriteDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * subset); + +/** + * xmlTextWriterWriteDocType: + * + * this macro maps to xmlTextWriterWriteDTD + */ +#define xmlTextWriterWriteDocType xmlTextWriterWriteDTD + +/* + * DTD element definition + */ + XMLPUBFUN int + xmlTextWriterStartDTDElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int xmlTextWriterEndDTDElement(xmlTextWriterPtr + writer); + +/* + * DTD element definition conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int + xmlTextWriterWriteVFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int xmlTextWriterWriteDTDElement(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD attribute list definition + */ + XMLPUBFUN int + xmlTextWriterStartDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int xmlTextWriterEndDTDAttlist(xmlTextWriterPtr + writer); + +/* + * DTD attribute list definition conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int + xmlTextWriterWriteVFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD entity definition + */ + XMLPUBFUN int + xmlTextWriterStartDTDEntity(xmlTextWriterPtr writer, + int pe, const xmlChar * name); + XMLPUBFUN int xmlTextWriterEndDTDEntity(xmlTextWriterPtr + writer); + +/* + * DTD entity definition conveniency functions + */ + XMLPUBFUN int + xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(4,5); + XMLPUBFUN int + xmlTextWriterWriteVFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(4,0); + XMLPUBFUN int + xmlTextWriterWriteDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * content); + XMLPUBFUN int + xmlTextWriterWriteDTDExternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid); + XMLPUBFUN int + xmlTextWriterWriteDTDExternalEntityContents(xmlTextWriterPtr + writer, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * + ndataid); + XMLPUBFUN int xmlTextWriterWriteDTDEntity(xmlTextWriterPtr + writer, int pe, + const xmlChar * name, + const xmlChar * + pubid, + const xmlChar * + sysid, + const xmlChar * + ndataid, + const xmlChar * + content); + +/* + * DTD notation definition + */ + XMLPUBFUN int + xmlTextWriterWriteDTDNotation(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + +/* + * Indentation + */ + XMLPUBFUN int + xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent); + XMLPUBFUN int + xmlTextWriterSetIndentString(xmlTextWriterPtr writer, + const xmlChar * str); + + XMLPUBFUN int + xmlTextWriterSetQuoteChar(xmlTextWriterPtr writer, xmlChar quotechar); + + +/* + * misc + */ + XMLPUBFUN int xmlTextWriterFlush(xmlTextWriterPtr writer); + XMLPUBFUN int xmlTextWriterClose(xmlTextWriterPtr writer); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_WRITER_ENABLED */ + +#endif /* __XML_XMLWRITER_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpath.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpath.h new file mode 100644 index 00000000..b89e105c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpath.h @@ -0,0 +1,579 @@ +/* + * Summary: XML Path Language implementation + * Description: API for the XML Path Language implementation + * + * XML Path Language implementation + * XPath is a language for addressing parts of an XML document, + * designed to be used by both XSLT and XPointer + * http://www.w3.org/TR/xpath + * + * Implements + * W3C Recommendation 16 November 1999 + * http://www.w3.org/TR/1999/REC-xpath-19991116 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_H__ +#define __XML_XPATH_H__ + +#include + +#ifdef LIBXML_XPATH_ENABLED + +#include +#include +#include +#endif /* LIBXML_XPATH_ENABLED */ + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef __cplusplus +extern "C" { +#endif +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +#ifdef LIBXML_XPATH_ENABLED + +typedef struct _xmlXPathContext xmlXPathContext; +typedef xmlXPathContext *xmlXPathContextPtr; +typedef struct _xmlXPathParserContext xmlXPathParserContext; +typedef xmlXPathParserContext *xmlXPathParserContextPtr; + +/** + * The set of XPath error codes. + */ + +typedef enum { + XPATH_EXPRESSION_OK = 0, + XPATH_NUMBER_ERROR, + XPATH_UNFINISHED_LITERAL_ERROR, + XPATH_START_LITERAL_ERROR, + XPATH_VARIABLE_REF_ERROR, + XPATH_UNDEF_VARIABLE_ERROR, + XPATH_INVALID_PREDICATE_ERROR, + XPATH_EXPR_ERROR, + XPATH_UNCLOSED_ERROR, + XPATH_UNKNOWN_FUNC_ERROR, + XPATH_INVALID_OPERAND, + XPATH_INVALID_TYPE, + XPATH_INVALID_ARITY, + XPATH_INVALID_CTXT_SIZE, + XPATH_INVALID_CTXT_POSITION, + XPATH_MEMORY_ERROR, + XPTR_SYNTAX_ERROR, + XPTR_RESOURCE_ERROR, + XPTR_SUB_RESOURCE_ERROR, + XPATH_UNDEF_PREFIX_ERROR, + XPATH_ENCODING_ERROR, + XPATH_INVALID_CHAR_ERROR, + XPATH_INVALID_CTXT, + XPATH_STACK_ERROR, + XPATH_FORBID_VARIABLE_ERROR, + XPATH_OP_LIMIT_EXCEEDED, + XPATH_RECURSION_LIMIT_EXCEEDED +} xmlXPathError; + +/* + * A node-set (an unordered collection of nodes without duplicates). + */ +typedef struct _xmlNodeSet xmlNodeSet; +typedef xmlNodeSet *xmlNodeSetPtr; +struct _xmlNodeSet { + int nodeNr; /* number of nodes in the set */ + int nodeMax; /* size of the array as allocated */ + xmlNodePtr *nodeTab; /* array of nodes in no particular order */ + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ +}; + +/* + * An expression is evaluated to yield an object, which + * has one of the following four basic types: + * - node-set + * - boolean + * - number + * - string + * + * @@ XPointer will add more types ! + */ + +typedef enum { + XPATH_UNDEFINED = 0, + XPATH_NODESET = 1, + XPATH_BOOLEAN = 2, + XPATH_NUMBER = 3, + XPATH_STRING = 4, +#ifdef LIBXML_XPTR_LOCS_ENABLED + XPATH_POINT = 5, + XPATH_RANGE = 6, + XPATH_LOCATIONSET = 7, +#endif + XPATH_USERS = 8, + XPATH_XSLT_TREE = 9 /* An XSLT value tree, non modifiable */ +} xmlXPathObjectType; + +#ifndef LIBXML_XPTR_LOCS_ENABLED +/** DOC_DISABLE */ +#define XPATH_POINT 5 +#define XPATH_RANGE 6 +#define XPATH_LOCATIONSET 7 +/** DOC_ENABLE */ +#endif + +typedef struct _xmlXPathObject xmlXPathObject; +typedef xmlXPathObject *xmlXPathObjectPtr; +struct _xmlXPathObject { + xmlXPathObjectType type; + xmlNodeSetPtr nodesetval; + int boolval; + double floatval; + xmlChar *stringval; + void *user; + int index; + void *user2; + int index2; +}; + +/** + * xmlXPathConvertFunc: + * @obj: an XPath object + * @type: the number of the target type + * + * A conversion function is associated to a type and used to cast + * the new type to primitive values. + * + * Returns -1 in case of error, 0 otherwise + */ +typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type); + +/* + * Extra type: a name and a conversion function. + */ + +typedef struct _xmlXPathType xmlXPathType; +typedef xmlXPathType *xmlXPathTypePtr; +struct _xmlXPathType { + const xmlChar *name; /* the type name */ + xmlXPathConvertFunc func; /* the conversion function */ +}; + +/* + * Extra variable: a name and a value. + */ + +typedef struct _xmlXPathVariable xmlXPathVariable; +typedef xmlXPathVariable *xmlXPathVariablePtr; +struct _xmlXPathVariable { + const xmlChar *name; /* the variable name */ + xmlXPathObjectPtr value; /* the value */ +}; + +/** + * xmlXPathEvalFunc: + * @ctxt: an XPath parser context + * @nargs: the number of arguments passed to the function + * + * An XPath evaluation function, the parameters are on the XPath context stack. + */ + +typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, + int nargs); + +/* + * Extra function: a name and a evaluation function. + */ + +typedef struct _xmlXPathFunct xmlXPathFunct; +typedef xmlXPathFunct *xmlXPathFuncPtr; +struct _xmlXPathFunct { + const xmlChar *name; /* the function name */ + xmlXPathEvalFunc func; /* the evaluation function */ +}; + +/** + * xmlXPathAxisFunc: + * @ctxt: the XPath interpreter context + * @cur: the previous node being explored on that axis + * + * An axis traversal function. To traverse an axis, the engine calls + * the first time with cur == NULL and repeat until the function returns + * NULL indicating the end of the axis traversal. + * + * Returns the next node in that axis or NULL if at the end of the axis. + */ + +typedef xmlXPathObjectPtr (*xmlXPathAxisFunc) (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr cur); + +/* + * Extra axis: a name and an axis function. + */ + +typedef struct _xmlXPathAxis xmlXPathAxis; +typedef xmlXPathAxis *xmlXPathAxisPtr; +struct _xmlXPathAxis { + const xmlChar *name; /* the axis name */ + xmlXPathAxisFunc func; /* the search function */ +}; + +/** + * xmlXPathFunction: + * @ctxt: the XPath interprestation context + * @nargs: the number of arguments + * + * An XPath function. + * The arguments (if any) are popped out from the context stack + * and the result is pushed on the stack. + */ + +typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); + +/* + * Function and Variable Lookup. + */ + +/** + * xmlXPathVariableLookupFunc: + * @ctxt: an XPath context + * @name: name of the variable + * @ns_uri: the namespace name hosting this variable + * + * Prototype for callbacks used to plug variable lookup in the XPath + * engine. + * + * Returns the XPath object value or NULL if not found. + */ +typedef xmlXPathObjectPtr (*xmlXPathVariableLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFuncLookupFunc: + * @ctxt: an XPath context + * @name: name of the function + * @ns_uri: the namespace name hosting this function + * + * Prototype for callbacks used to plug function lookup in the XPath + * engine. + * + * Returns the XPath function or NULL if not found. + */ +typedef xmlXPathFunction (*xmlXPathFuncLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFlags: + * Flags for XPath engine compilation and runtime + */ +/** + * XML_XPATH_CHECKNS: + * + * check namespaces at compilation + */ +#define XML_XPATH_CHECKNS (1<<0) +/** + * XML_XPATH_NOVAR: + * + * forbid variables in expression + */ +#define XML_XPATH_NOVAR (1<<1) + +/** + * xmlXPathContext: + * + * Expression evaluation occurs with respect to a context. + * he context consists of: + * - a node (the context node) + * - a node list (the context node list) + * - a set of variable bindings + * - a function library + * - the set of namespace declarations in scope for the expression + * Following the switch to hash tables, this need to be trimmed up at + * the next binary incompatible release. + * The node may be modified when the context is passed to libxml2 + * for an XPath evaluation so you may need to initialize it again + * before the next call. + */ + +struct _xmlXPathContext { + xmlDocPtr doc; /* The current document */ + xmlNodePtr node; /* The current node */ + + int nb_variables_unused; /* unused (hash table) */ + int max_variables_unused; /* unused (hash table) */ + xmlHashTablePtr varHash; /* Hash table of defined variables */ + + int nb_types; /* number of defined types */ + int max_types; /* max number of types */ + xmlXPathTypePtr types; /* Array of defined types */ + + int nb_funcs_unused; /* unused (hash table) */ + int max_funcs_unused; /* unused (hash table) */ + xmlHashTablePtr funcHash; /* Hash table of defined funcs */ + + int nb_axis; /* number of defined axis */ + int max_axis; /* max number of axis */ + xmlXPathAxisPtr axis; /* Array of defined axis */ + + /* the namespace nodes of the context node */ + xmlNsPtr *namespaces; /* Array of namespaces */ + int nsNr; /* number of namespace in scope */ + void *user; /* function to free */ + + /* extra variables */ + int contextSize; /* the context size */ + int proximityPosition; /* the proximity position */ + + /* extra stuff for XPointer */ + int xptr; /* is this an XPointer context? */ + xmlNodePtr here; /* for here() */ + xmlNodePtr origin; /* for origin() */ + + /* the set of namespace declarations in scope for the expression */ + xmlHashTablePtr nsHash; /* The namespaces hash table */ + xmlXPathVariableLookupFunc varLookupFunc;/* variable lookup func */ + void *varLookupData; /* variable lookup data */ + + /* Possibility to link in an extra item */ + void *extra; /* needed for XSLT */ + + /* The function name and URI when calling a function */ + const xmlChar *function; + const xmlChar *functionURI; + + /* function lookup function and data */ + xmlXPathFuncLookupFunc funcLookupFunc;/* function lookup func */ + void *funcLookupData; /* function lookup data */ + + /* temporary namespace lists kept for walking the namespace axis */ + xmlNsPtr *tmpNsList; /* Array of namespaces */ + int tmpNsNr; /* number of namespaces in scope */ + + /* error reporting mechanism */ + void *userData; /* user specific data block */ + xmlStructuredErrorFunc error; /* the callback in case of errors */ + xmlError lastError; /* the last error */ + xmlNodePtr debugNode; /* the source node XSLT */ + + /* dictionary */ + xmlDictPtr dict; /* dictionary if any */ + + int flags; /* flags to control compilation */ + + /* Cache for reusal of XPath objects */ + void *cache; + + /* Resource limits */ + unsigned long opLimit; + unsigned long opCount; + int depth; +}; + +/* + * The structure of a compiled expression form is not public. + */ + +typedef struct _xmlXPathCompExpr xmlXPathCompExpr; +typedef xmlXPathCompExpr *xmlXPathCompExprPtr; + +/** + * xmlXPathParserContext: + * + * An XPath parser context. It contains pure parsing information, + * an xmlXPathContext, and the stack of objects. + */ +struct _xmlXPathParserContext { + const xmlChar *cur; /* the current char being parsed */ + const xmlChar *base; /* the full expression */ + + int error; /* error code */ + + xmlXPathContextPtr context; /* the evaluation context */ + xmlXPathObjectPtr value; /* the current value */ + int valueNr; /* number of values stacked */ + int valueMax; /* max number of values stacked */ + xmlXPathObjectPtr *valueTab; /* stack of values */ + + xmlXPathCompExprPtr comp; /* the precompiled expression */ + int xptr; /* it this an XPointer expression */ + xmlNodePtr ancestor; /* used for walking preceding axis */ + + int valueFrame; /* always zero for compatibility */ +}; + +/************************************************************************ + * * + * Public API * + * * + ************************************************************************/ + +/** + * Objects and Nodesets handling + */ + +XMLPUBVAR double xmlXPathNAN; +XMLPUBVAR double xmlXPathPINF; +XMLPUBVAR double xmlXPathNINF; + +/* These macros may later turn into functions */ +/** + * xmlXPathNodeSetGetLength: + * @ns: a node-set + * + * Implement a functionality similar to the DOM NodeList.length. + * + * Returns the number of nodes in the node-set. + */ +#define xmlXPathNodeSetGetLength(ns) ((ns) ? (ns)->nodeNr : 0) +/** + * xmlXPathNodeSetItem: + * @ns: a node-set + * @index: index of a node in the set + * + * Implements a functionality similar to the DOM NodeList.item(). + * + * Returns the xmlNodePtr at the given @index in @ns or NULL if + * @index is out of range (0 to length-1) + */ +#define xmlXPathNodeSetItem(ns, index) \ + ((((ns) != NULL) && \ + ((index) >= 0) && ((index) < (ns)->nodeNr)) ? \ + (ns)->nodeTab[(index)] \ + : NULL) +/** + * xmlXPathNodeSetIsEmpty: + * @ns: a node-set + * + * Checks whether @ns is empty or not. + * + * Returns %TRUE if @ns is an empty node-set. + */ +#define xmlXPathNodeSetIsEmpty(ns) \ + (((ns) == NULL) || ((ns)->nodeNr == 0) || ((ns)->nodeTab == NULL)) + + +XMLPUBFUN void + xmlXPathFreeObject (xmlXPathObjectPtr obj); +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeSetCreate (xmlNodePtr val); +XMLPUBFUN void + xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); +XMLPUBFUN void + xmlXPathFreeNodeSet (xmlNodeSetPtr obj); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathObjectCopy (xmlXPathObjectPtr val); +XMLPUBFUN int + xmlXPathCmpNodes (xmlNodePtr node1, + xmlNodePtr node2); +/** + * Conversion functions to basic types. + */ +XMLPUBFUN int + xmlXPathCastNumberToBoolean (double val); +XMLPUBFUN int + xmlXPathCastStringToBoolean (const xmlChar * val); +XMLPUBFUN int + xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns); +XMLPUBFUN int + xmlXPathCastToBoolean (xmlXPathObjectPtr val); + +XMLPUBFUN double + xmlXPathCastBooleanToNumber (int val); +XMLPUBFUN double + xmlXPathCastStringToNumber (const xmlChar * val); +XMLPUBFUN double + xmlXPathCastNodeToNumber (xmlNodePtr node); +XMLPUBFUN double + xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns); +XMLPUBFUN double + xmlXPathCastToNumber (xmlXPathObjectPtr val); + +XMLPUBFUN xmlChar * + xmlXPathCastBooleanToString (int val); +XMLPUBFUN xmlChar * + xmlXPathCastNumberToString (double val); +XMLPUBFUN xmlChar * + xmlXPathCastNodeToString (xmlNodePtr node); +XMLPUBFUN xmlChar * + xmlXPathCastNodeSetToString (xmlNodeSetPtr ns); +XMLPUBFUN xmlChar * + xmlXPathCastToString (xmlXPathObjectPtr val); + +XMLPUBFUN xmlXPathObjectPtr + xmlXPathConvertBoolean (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathConvertNumber (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathConvertString (xmlXPathObjectPtr val); + +/** + * Context handling. + */ +XMLPUBFUN xmlXPathContextPtr + xmlXPathNewContext (xmlDocPtr doc); +XMLPUBFUN void + xmlXPathFreeContext (xmlXPathContextPtr ctxt); +XMLPUBFUN void + xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt, + xmlStructuredErrorFunc handler, + void *context); +XMLPUBFUN int + xmlXPathContextSetCache(xmlXPathContextPtr ctxt, + int active, + int value, + int options); +/** + * Evaluation functions. + */ +XMLPUBFUN long + xmlXPathOrderDocElems (xmlDocPtr doc); +XMLPUBFUN int + xmlXPathSetContextNode (xmlNodePtr node, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNodeEval (xmlNodePtr node, + const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathEval (const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathEvalExpression (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN int + xmlXPathEvalPredicate (xmlXPathContextPtr ctxt, + xmlXPathObjectPtr res); +/** + * Separate compilation/evaluation entry points. + */ +XMLPUBFUN xmlXPathCompExprPtr + xmlXPathCompile (const xmlChar *str); +XMLPUBFUN xmlXPathCompExprPtr + xmlXPathCtxtCompile (xmlXPathContextPtr ctxt, + const xmlChar *str); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathCompiledEval (xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctx); +XMLPUBFUN int + xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctxt); +XMLPUBFUN void + xmlXPathFreeCompExpr (xmlXPathCompExprPtr comp); +#endif /* LIBXML_XPATH_ENABLED */ +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XML_DEPRECATED +XMLPUBFUN void + xmlXPathInit (void); +XMLPUBFUN int + xmlXPathIsNaN (double val); +XMLPUBFUN int + xmlXPathIsInf (double val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED*/ +#endif /* ! __XML_XPATH_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpathInternals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpathInternals.h new file mode 100644 index 00000000..d1c90dff --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpathInternals.h @@ -0,0 +1,633 @@ +/* + * Summary: internal interfaces for XML Path Language implementation + * Description: internal interfaces for XML Path Language implementation + * used to build new modules on top of XPath like XPointer and + * XSLT + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_INTERNALS_H__ +#define __XML_XPATH_INTERNALS_H__ + +#include +#include +#include + +#ifdef LIBXML_XPATH_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************ + * * + * Helpers * + * * + ************************************************************************/ + +/* + * Many of these macros may later turn into functions. They + * shouldn't be used in #ifdef's preprocessor instructions. + */ +/** + * xmlXPathSetError: + * @ctxt: an XPath parser context + * @err: an xmlXPathError code + * + * Raises an error. + */ +#define xmlXPathSetError(ctxt, err) \ + { xmlXPatherror((ctxt), __FILE__, __LINE__, (err)); \ + if ((ctxt) != NULL) (ctxt)->error = (err); } + +/** + * xmlXPathSetArityError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_ARITY error. + */ +#define xmlXPathSetArityError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_ARITY) + +/** + * xmlXPathSetTypeError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_TYPE error. + */ +#define xmlXPathSetTypeError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_TYPE) + +/** + * xmlXPathGetError: + * @ctxt: an XPath parser context + * + * Get the error code of an XPath context. + * + * Returns the context error. + */ +#define xmlXPathGetError(ctxt) ((ctxt)->error) + +/** + * xmlXPathCheckError: + * @ctxt: an XPath parser context + * + * Check if an XPath error was raised. + * + * Returns true if an error has been raised, false otherwise. + */ +#define xmlXPathCheckError(ctxt) ((ctxt)->error != XPATH_EXPRESSION_OK) + +/** + * xmlXPathGetDocument: + * @ctxt: an XPath parser context + * + * Get the document of an XPath context. + * + * Returns the context document. + */ +#define xmlXPathGetDocument(ctxt) ((ctxt)->context->doc) + +/** + * xmlXPathGetContextNode: + * @ctxt: an XPath parser context + * + * Get the context node of an XPath context. + * + * Returns the context node. + */ +#define xmlXPathGetContextNode(ctxt) ((ctxt)->context->node) + +XMLPUBFUN int + xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt); +XMLPUBFUN double + xmlXPathPopNumber (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * + xmlXPathPopString (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr + xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void * + xmlXPathPopExternal (xmlXPathParserContextPtr ctxt); + +/** + * xmlXPathReturnBoolean: + * @ctxt: an XPath parser context + * @val: a boolean + * + * Pushes the boolean @val on the context stack. + */ +#define xmlXPathReturnBoolean(ctxt, val) \ + valuePush((ctxt), xmlXPathNewBoolean(val)) + +/** + * xmlXPathReturnTrue: + * @ctxt: an XPath parser context + * + * Pushes true on the context stack. + */ +#define xmlXPathReturnTrue(ctxt) xmlXPathReturnBoolean((ctxt), 1) + +/** + * xmlXPathReturnFalse: + * @ctxt: an XPath parser context + * + * Pushes false on the context stack. + */ +#define xmlXPathReturnFalse(ctxt) xmlXPathReturnBoolean((ctxt), 0) + +/** + * xmlXPathReturnNumber: + * @ctxt: an XPath parser context + * @val: a double + * + * Pushes the double @val on the context stack. + */ +#define xmlXPathReturnNumber(ctxt, val) \ + valuePush((ctxt), xmlXPathNewFloat(val)) + +/** + * xmlXPathReturnString: + * @ctxt: an XPath parser context + * @str: a string + * + * Pushes the string @str on the context stack. + */ +#define xmlXPathReturnString(ctxt, str) \ + valuePush((ctxt), xmlXPathWrapString(str)) + +/** + * xmlXPathReturnEmptyString: + * @ctxt: an XPath parser context + * + * Pushes an empty string on the stack. + */ +#define xmlXPathReturnEmptyString(ctxt) \ + valuePush((ctxt), xmlXPathNewCString("")) + +/** + * xmlXPathReturnNodeSet: + * @ctxt: an XPath parser context + * @ns: a node-set + * + * Pushes the node-set @ns on the context stack. + */ +#define xmlXPathReturnNodeSet(ctxt, ns) \ + valuePush((ctxt), xmlXPathWrapNodeSet(ns)) + +/** + * xmlXPathReturnEmptyNodeSet: + * @ctxt: an XPath parser context + * + * Pushes an empty node-set on the context stack. + */ +#define xmlXPathReturnEmptyNodeSet(ctxt) \ + valuePush((ctxt), xmlXPathNewNodeSet(NULL)) + +/** + * xmlXPathReturnExternal: + * @ctxt: an XPath parser context + * @val: user data + * + * Pushes user data on the context stack. + */ +#define xmlXPathReturnExternal(ctxt, val) \ + valuePush((ctxt), xmlXPathWrapExternal(val)) + +/** + * xmlXPathStackIsNodeSet: + * @ctxt: an XPath parser context + * + * Check if the current value on the XPath stack is a node set or + * an XSLT value tree. + * + * Returns true if the current object on the stack is a node-set. + */ +#define xmlXPathStackIsNodeSet(ctxt) \ + (((ctxt)->value != NULL) \ + && (((ctxt)->value->type == XPATH_NODESET) \ + || ((ctxt)->value->type == XPATH_XSLT_TREE))) + +/** + * xmlXPathStackIsExternal: + * @ctxt: an XPath parser context + * + * Checks if the current value on the XPath stack is an external + * object. + * + * Returns true if the current object on the stack is an external + * object. + */ +#define xmlXPathStackIsExternal(ctxt) \ + ((ctxt->value != NULL) && (ctxt->value->type == XPATH_USERS)) + +/** + * xmlXPathEmptyNodeSet: + * @ns: a node-set + * + * Empties a node-set. + */ +#define xmlXPathEmptyNodeSet(ns) \ + { while ((ns)->nodeNr > 0) (ns)->nodeTab[--(ns)->nodeNr] = NULL; } + +/** + * CHECK_ERROR: + * + * Macro to return from the function if an XPath error was detected. + */ +#define CHECK_ERROR \ + if (ctxt->error != XPATH_EXPRESSION_OK) return + +/** + * CHECK_ERROR0: + * + * Macro to return 0 from the function if an XPath error was detected. + */ +#define CHECK_ERROR0 \ + if (ctxt->error != XPATH_EXPRESSION_OK) return(0) + +/** + * XP_ERROR: + * @X: the error code + * + * Macro to raise an XPath error and return. + */ +#define XP_ERROR(X) \ + { xmlXPathErr(ctxt, X); return; } + +/** + * XP_ERROR0: + * @X: the error code + * + * Macro to raise an XPath error and return 0. + */ +#define XP_ERROR0(X) \ + { xmlXPathErr(ctxt, X); return(0); } + +/** + * CHECK_TYPE: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. + */ +#define CHECK_TYPE(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR(XPATH_INVALID_TYPE) + +/** + * CHECK_TYPE0: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. Return(0) in case of failure + */ +#define CHECK_TYPE0(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR0(XPATH_INVALID_TYPE) + +/** + * CHECK_ARITY: + * @x: the number of expected args + * + * Macro to check that the number of args passed to an XPath function matches. + */ +#define CHECK_ARITY(x) \ + if (ctxt == NULL) return; \ + if (nargs != (x)) \ + XP_ERROR(XPATH_INVALID_ARITY); \ + if (ctxt->valueNr < (x)) \ + XP_ERROR(XPATH_STACK_ERROR); + +/** + * CAST_TO_STRING: + * + * Macro to try to cast the value on the top of the XPath stack to a string. + */ +#define CAST_TO_STRING \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \ + xmlXPathStringFunction(ctxt, 1); + +/** + * CAST_TO_NUMBER: + * + * Macro to try to cast the value on the top of the XPath stack to a number. + */ +#define CAST_TO_NUMBER \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \ + xmlXPathNumberFunction(ctxt, 1); + +/** + * CAST_TO_BOOLEAN: + * + * Macro to try to cast the value on the top of the XPath stack to a boolean. + */ +#define CAST_TO_BOOLEAN \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \ + xmlXPathBooleanFunction(ctxt, 1); + +/* + * Variable Lookup forwarding. + */ + +XMLPUBFUN void + xmlXPathRegisterVariableLookup (xmlXPathContextPtr ctxt, + xmlXPathVariableLookupFunc f, + void *data); + +/* + * Function Lookup forwarding. + */ + +XMLPUBFUN void + xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, + xmlXPathFuncLookupFunc f, + void *funcCtxt); + +/* + * Error reporting. + */ +XMLPUBFUN void + xmlXPatherror (xmlXPathParserContextPtr ctxt, + const char *file, + int line, + int no); + +XMLPUBFUN void + xmlXPathErr (xmlXPathParserContextPtr ctxt, + int error); + +#ifdef LIBXML_DEBUG_ENABLED +XMLPUBFUN void + xmlXPathDebugDumpObject (FILE *output, + xmlXPathObjectPtr cur, + int depth); +XMLPUBFUN void + xmlXPathDebugDumpCompExpr(FILE *output, + xmlXPathCompExprPtr comp, + int depth); +#endif +/** + * NodeSet handling. + */ +XMLPUBFUN int + xmlXPathNodeSetContains (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN xmlNodeSetPtr + xmlXPathDifference (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr + xmlXPathIntersection (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr + xmlXPathDistinctSorted (xmlNodeSetPtr nodes); +XMLPUBFUN xmlNodeSetPtr + xmlXPathDistinct (xmlNodeSetPtr nodes); + +XMLPUBFUN int + xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr + xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeLeading (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr + xmlXPathLeading (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr + xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeTrailing (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr + xmlXPathTrailing (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + + +/** + * Extending a context. + */ + +XMLPUBFUN int + xmlXPathRegisterNs (xmlXPathContextPtr ctxt, + const xmlChar *prefix, + const xmlChar *ns_uri); +XMLPUBFUN const xmlChar * + xmlXPathNsLookup (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +XMLPUBFUN void + xmlXPathRegisteredNsCleanup (xmlXPathContextPtr ctxt); + +XMLPUBFUN int + xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathFunction f); +XMLPUBFUN int + xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathFunction f); +XMLPUBFUN int + xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathObjectPtr value); +XMLPUBFUN int + xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathObjectPtr value); +XMLPUBFUN xmlXPathFunction + xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathFunction + xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void + xmlXPathRegisteredFuncsCleanup (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathVariableLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void + xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); + +/** + * Utilities to extend XPath. + */ +XMLPUBFUN xmlXPathParserContextPtr + xmlXPathNewParserContext (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN void + xmlXPathFreeParserContext (xmlXPathParserContextPtr ctxt); + +/* TODO: remap to xmlXPathValuePop and Push. */ +XMLPUBFUN xmlXPathObjectPtr + valuePop (xmlXPathParserContextPtr ctxt); +XMLPUBFUN int + valuePush (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr value); + +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewString (const xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewCString (const char *val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathWrapString (xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathWrapCString (char * val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewFloat (double val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewBoolean (int val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewNodeSet (xmlNodePtr val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewValueTree (xmlNodePtr val); +XMLPUBFUN int + xmlXPathNodeSetAdd (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN int + xmlXPathNodeSetAddUnique (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN int + xmlXPathNodeSetAddNs (xmlNodeSetPtr cur, + xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN void + xmlXPathNodeSetSort (xmlNodeSetPtr set); + +XMLPUBFUN void + xmlXPathRoot (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void + xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * + xmlXPathParseName (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * + xmlXPathParseNCName (xmlXPathParserContextPtr ctxt); + +/* + * Existing functions. + */ +XMLPUBFUN double + xmlXPathStringEvalNumber (const xmlChar *str); +XMLPUBFUN int + xmlXPathEvaluatePredicateResult (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res); +XMLPUBFUN void + xmlXPathRegisterAllFunctions (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr + xmlXPathNodeSetMerge (xmlNodeSetPtr val1, + xmlNodeSetPtr val2); +XMLPUBFUN void + xmlXPathNodeSetDel (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN void + xmlXPathNodeSetRemove (xmlNodeSetPtr cur, + int val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathNewNodeSetList (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathWrapNodeSet (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr + xmlXPathWrapExternal (void *val); + +XMLPUBFUN int xmlXPathEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict); +XMLPUBFUN void xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathAddValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathSubValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathMultValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathDivValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void xmlXPathModValues(xmlXPathParserContextPtr ctxt); + +XMLPUBFUN int xmlXPathIsNodeType(const xmlChar *name); + +/* + * Some of the axis navigation routines. + */ +XMLPUBFUN xmlNodePtr xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextChild(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextParent(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +/* + * The official core of XPath functions. + */ +XMLPUBFUN void xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); + +/** + * Really internal functions + */ +XMLPUBFUN void xmlXPathNodeSetFreeNs(xmlNsPtr ns); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED */ +#endif /* ! __XML_XPATH_INTERNALS_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpointer.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpointer.h new file mode 100644 index 00000000..a5260008 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxml2/libxml/xpointer.h @@ -0,0 +1,138 @@ +/* + * Summary: API to handle XML Pointers + * Description: API to handle XML Pointers + * Base implementation was made accordingly to + * W3C Candidate Recommendation 7 June 2000 + * http://www.w3.org/TR/2000/CR-xptr-20000607 + * + * Added support for the element() scheme described in: + * W3C Proposed Recommendation 13 November 2002 + * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPTR_H__ +#define __XML_XPTR_H__ + +#include + +#ifdef LIBXML_XPTR_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(LIBXML_XPTR_LOCS_ENABLED) +/* + * A Location Set + */ +typedef struct _xmlLocationSet xmlLocationSet; +typedef xmlLocationSet *xmlLocationSetPtr; +struct _xmlLocationSet { + int locNr; /* number of locations in the set */ + int locMax; /* size of the array as allocated */ + xmlXPathObjectPtr *locTab;/* array of locations */ +}; + +/* + * Handling of location sets. + */ + +XML_DEPRECATED +XMLPUBFUN xmlLocationSetPtr + xmlXPtrLocationSetCreate (xmlXPathObjectPtr val); +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); +XML_DEPRECATED +XMLPUBFUN xmlLocationSetPtr + xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, + xmlLocationSetPtr val2); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRange (xmlNodePtr start, + int startindex, + xmlNodePtr end, + int endindex); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRangePoints (xmlXPathObjectPtr start, + xmlXPathObjectPtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRangeNodePoint (xmlNodePtr start, + xmlXPathObjectPtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRangePointNode (xmlXPathObjectPtr start, + xmlNodePtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRangeNodes (xmlNodePtr start, + xmlNodePtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewLocationSetNodes (xmlNodePtr start, + xmlNodePtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewRangeNodeObject (xmlNodePtr start, + xmlXPathObjectPtr end); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrNewCollapsedRange (xmlNodePtr start); +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrLocationSetAdd (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XML_DEPRECATED +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrWrapLocationSet (xmlLocationSetPtr val); +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrLocationSetDel (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrLocationSetRemove (xmlLocationSetPtr cur, + int val); +#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) */ + +/* + * Functions. + */ +XMLPUBFUN xmlXPathContextPtr + xmlXPtrNewContext (xmlDocPtr doc, + xmlNodePtr here, + xmlNodePtr origin); +XMLPUBFUN xmlXPathObjectPtr + xmlXPtrEval (const xmlChar *str, + xmlXPathContextPtr ctx); + +#if defined(LIBXML_XPTR_LOCS_ENABLED) +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XML_DEPRECATED +XMLPUBFUN xmlNodePtr + xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); +XML_DEPRECATED +XMLPUBFUN void + xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); +#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) */ +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ +#endif /* __XML_XPTR_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/attributes.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/attributes.h new file mode 100644 index 00000000..d9b99a74 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/attributes.h @@ -0,0 +1,39 @@ +/* + * Summary: interface for the XSLT attribute handling + * Description: this module handles the specificities of attribute + * and attribute groups processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_ATTRIBUTES_H__ +#define __XML_XSLT_ATTRIBUTES_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetAttributeSet (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltFreeAttributeSetsHashes (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltApplyAttributeSet (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + const xmlChar *attributes); +XSLTPUBFUN void XSLTCALL + xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_ATTRIBUTES_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/documents.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/documents.h new file mode 100644 index 00000000..ae7c0ca2 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/documents.h @@ -0,0 +1,93 @@ +/* + * Summary: interface for the document handling + * Description: implements document loading and cache (multiple + * document() reference for the same resources must + * be equal. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_DOCUMENTS_H__ +#define __XML_XSLT_DOCUMENTS_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltNewDocument (xsltTransformContextPtr ctxt, + xmlDocPtr doc); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltLoadDocument (xsltTransformContextPtr ctxt, + const xmlChar *URI); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltFindDocument (xsltTransformContextPtr ctxt, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeDocuments (xsltTransformContextPtr ctxt); + +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltLoadStyleDocument (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltNewStyleDocument (xsltStylesheetPtr style, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeStyleDocuments (xsltStylesheetPtr style); + +/* + * Hooks for document loading + */ + +/** + * xsltLoadType: + * + * Enum defining the kind of loader requirement. + */ +typedef enum { + XSLT_LOAD_START = 0, /* loading for a top stylesheet */ + XSLT_LOAD_STYLESHEET = 1, /* loading for a stylesheet include/import */ + XSLT_LOAD_DOCUMENT = 2 /* loading document at transformation time */ +} xsltLoadType; + +/** + * xsltDocLoaderFunc: + * @URI: the URI of the document to load + * @dict: the dictionary to use when parsing that document + * @options: parsing options, a set of xmlParserOption + * @ctxt: the context, either a stylesheet or a transformation context + * @type: the xsltLoadType indicating the kind of loading required + * + * An xsltDocLoaderFunc is a signature for a function which can be + * registered to load document not provided by the compilation or + * transformation API themselve, for example when an xsl:import, + * xsl:include is found at compilation time or when a document() + * call is made at runtime. + * + * Returns the pointer to the document (which will be modified and + * freed by the engine later), or NULL in case of error. + */ +typedef xmlDocPtr (*xsltDocLoaderFunc) (const xmlChar *URI, + xmlDictPtr dict, + int options, + void *ctxt, + xsltLoadType type); + +XSLTPUBFUN void XSLTCALL + xsltSetLoaderFunc (xsltDocLoaderFunc f); + +/* the loader may be needed by extension libraries so it is exported */ +XSLTPUBVAR xsltDocLoaderFunc xsltDocDefaultLoader; + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_DOCUMENTS_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extensions.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extensions.h new file mode 100644 index 00000000..84d6aa44 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extensions.h @@ -0,0 +1,262 @@ +/* + * Summary: interface for the extension support + * Description: This provide the API needed for simple and module + * extension support. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_EXTENSION_H__ +#define __XML_XSLT_EXTENSION_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Extension Modules API. + */ + +/** + * xsltInitGlobals: + * + * Initialize the global variables for extensions + * + */ + +XSLTPUBFUN void XSLTCALL + xsltInitGlobals (void); + +/** + * xsltStyleExtInitFunction: + * @ctxt: an XSLT stylesheet + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module. + * + * Returns a pointer to the module specific data for this transformation. + */ +typedef void * (*xsltStyleExtInitFunction) (xsltStylesheetPtr style, + const xmlChar *URI); + +/** + * xsltStyleExtShutdownFunction: + * @ctxt: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module. + */ +typedef void (*xsltStyleExtShutdownFunction) (xsltStylesheetPtr style, + const xmlChar *URI, + void *data); + +/** + * xsltExtInitFunction: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module. + * + * Returns a pointer to the module specific data for this transformation. + */ +typedef void * (*xsltExtInitFunction) (xsltTransformContextPtr ctxt, + const xmlChar *URI); + +/** + * xsltExtShutdownFunction: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module. + */ +typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt, + const xmlChar *URI, + void *data); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModule (const xmlChar *URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc); +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleFull + (const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc); + +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModule (const xmlChar * URI); + +XSLTPUBFUN void * XSLTCALL + xsltGetExtData (xsltTransformContextPtr ctxt, + const xmlChar *URI); + +XSLTPUBFUN void * XSLTCALL + xsltStyleGetExtData (xsltStylesheetPtr style, + const xmlChar *URI); +#ifdef XSLT_REFACTORED +XSLTPUBFUN void * XSLTCALL + xsltStyleStylesheetLevelGetExtData( + xsltStylesheetPtr style, + const xmlChar * URI); +#endif +XSLTPUBFUN void XSLTCALL + xsltShutdownCtxtExts (xsltTransformContextPtr ctxt); + +XSLTPUBFUN void XSLTCALL + xsltShutdownExts (xsltStylesheetPtr style); + +XSLTPUBFUN xsltTransformContextPtr XSLTCALL + xsltXPathGetTransformContext + (xmlXPathParserContextPtr ctxt); + +/* + * extension functions +*/ +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleFunction + (const xmlChar *name, + const xmlChar *URI, + xmlXPathFunction function); +XSLTPUBFUN xmlXPathFunction XSLTCALL + xsltExtModuleFunctionLookup (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleFunction + (const xmlChar *name, + const xmlChar *URI); + +/* + * extension elements + */ +typedef xsltElemPreCompPtr (*xsltPreComputeFunction) + (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltNewElemPreComp (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); +XSLTPUBFUN void XSLTCALL + xsltInitElemPreComp (xsltElemPreCompPtr comp, + xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function, + xsltElemPreCompDeallocator freeFunc); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleElement + (const xmlChar *name, + const xmlChar *URI, + xsltPreComputeFunction precomp, + xsltTransformFunction transform); +XSLTPUBFUN xsltTransformFunction XSLTCALL + xsltExtElementLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN xsltTransformFunction XSLTCALL + xsltExtModuleElementLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN xsltPreComputeFunction XSLTCALL + xsltExtModuleElementPreComputeLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleElement + (const xmlChar *name, + const xmlChar *URI); + +/* + * top-level elements + */ +typedef void (*xsltTopLevelFunction) (xsltStylesheetPtr style, + xmlNodePtr inst); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleTopLevel + (const xmlChar *name, + const xmlChar *URI, + xsltTopLevelFunction function); +XSLTPUBFUN xsltTopLevelFunction XSLTCALL + xsltExtModuleTopLevelLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleTopLevel + (const xmlChar *name, + const xmlChar *URI); + + +/* These 2 functions are deprecated for use within modules. */ +XSLTPUBFUN int XSLTCALL + xsltRegisterExtFunction (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI, + xmlXPathFunction function); +XSLTPUBFUN int XSLTCALL + xsltRegisterExtElement (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI, + xsltTransformFunction function); + +/* + * Extension Prefix handling API. + * Those are used by the XSLT (pre)processor. + */ + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtPrefix (xsltStylesheetPtr style, + const xmlChar *prefix, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltCheckExtPrefix (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltCheckExtURI (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltInitCtxtExts (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltFreeCtxtExts (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltFreeExts (xsltStylesheetPtr style); + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltPreComputeExtModuleElement + (xsltStylesheetPtr style, + xmlNodePtr inst); +/* + * Extension Infos access. + * Used by exslt initialisation + */ + +XSLTPUBFUN xmlHashTablePtr XSLTCALL + xsltGetExtInfo (xsltStylesheetPtr style, + const xmlChar *URI); + +/** + * Test of the extension module API + */ +XSLTPUBFUN void XSLTCALL + xsltRegisterTestModule (void); +XSLTPUBFUN void XSLTCALL + xsltDebugDumpExtensions (FILE * output); + + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_EXTENSION_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extra.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extra.h new file mode 100644 index 00000000..e512fd03 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/extra.h @@ -0,0 +1,72 @@ +/* + * Summary: interface for the non-standard features + * Description: implement some extension outside the XSLT namespace + * but not EXSLT with is in a different library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_EXTRA_H__ +#define __XML_XSLT_EXTRA_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_LIBXSLT_NAMESPACE: + * + * This is the libxslt namespace for specific extensions. + */ +#define XSLT_LIBXSLT_NAMESPACE ((xmlChar *) "http://xmlsoft.org/XSLT/namespace") + +/** + * XSLT_SAXON_NAMESPACE: + * + * This is Michael Kay's Saxon processor namespace for extensions. + */ +#define XSLT_SAXON_NAMESPACE ((xmlChar *) "http://icl.com/saxon") + +/** + * XSLT_XT_NAMESPACE: + * + * This is James Clark's XT processor namespace for extensions. + */ +#define XSLT_XT_NAMESPACE ((xmlChar *) "http://www.jclark.com/xt") + +/** + * XSLT_XALAN_NAMESPACE: + * + * This is the Apache project XALAN processor namespace for extensions. + */ +#define XSLT_XALAN_NAMESPACE ((xmlChar *) \ + "org.apache.xalan.xslt.extensions.Redirect") + + +XSLTPUBFUN void XSLTCALL + xsltFunctionNodeSet (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltDebug (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); + + +XSLTPUBFUN void XSLTCALL + xsltRegisterExtras (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltRegisterAllExtras (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_EXTRA_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/functions.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/functions.h new file mode 100644 index 00000000..5455b7f4 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/functions.h @@ -0,0 +1,78 @@ +/* + * Summary: interface for the XSLT functions not from XPath + * Description: a set of extra functions coming from XSLT but not in XPath + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard and Bjorn Reese + */ + +#ifndef __XML_XSLT_FUNCTIONS_H__ +#define __XML_XSLT_FUNCTIONS_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_REGISTER_FUNCTION_LOOKUP: + * + * Registering macro, not general purpose at all but used in different modules. + */ +#define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt) \ + xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt, \ + xsltXPathFunctionLookup, \ + (void *)(ctxt->xpathCtxt)); + +XSLTPUBFUN xmlXPathFunction XSLTCALL + xsltXPathFunctionLookup (void *vctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/* + * Interfaces for the functions implementations. + */ + +XSLTPUBFUN void XSLTCALL + xsltDocumentFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltKeyFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltUnparsedEntityURIFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltFormatNumberFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltGenerateIdFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltSystemPropertyFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltElementAvailableFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltFunctionAvailableFunction (xmlXPathParserContextPtr ctxt, + int nargs); + +/* + * And the registration + */ + +XSLTPUBFUN void XSLTCALL + xsltRegisterAllFunctions (xmlXPathContextPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_FUNCTIONS_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/imports.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/imports.h new file mode 100644 index 00000000..95e44e51 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/imports.h @@ -0,0 +1,75 @@ +/* + * Summary: interface for the XSLT import support + * Description: macros and fuctions needed to implement and + * access the import tree + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_IMPORTS_H__ +#define __XML_XSLT_IMPORTS_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_GET_IMPORT_PTR: + * + * A macro to import pointers from the stylesheet cascading order. + */ +#define XSLT_GET_IMPORT_PTR(res, style, name) { \ + xsltStylesheetPtr st = style; \ + res = NULL; \ + while (st != NULL) { \ + if (st->name != NULL) { res = st->name; break; } \ + st = xsltNextImport(st); \ + }} + +/** + * XSLT_GET_IMPORT_INT: + * + * A macro to import intergers from the stylesheet cascading order. + */ +#define XSLT_GET_IMPORT_INT(res, style, name) { \ + xsltStylesheetPtr st = style; \ + res = -1; \ + while (st != NULL) { \ + if (st->name != -1) { res = st->name; break; } \ + st = xsltNextImport(st); \ + }} + +/* + * Module interfaces + */ +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetImport(xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetInclude + (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltNextImport (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xsltTemplatePtr XSLTCALL + xsltFindTemplate (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *nameURI); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_IMPORTS_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/keys.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/keys.h new file mode 100644 index 00000000..757d1224 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/keys.h @@ -0,0 +1,53 @@ +/* + * Summary: interface for the key matching used in key() and template matches. + * Description: implementation of the key mechanims. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_KEY_H__ +#define __XML_XSLT_KEY_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * NODE_IS_KEYED: + * + * check for bit 15 set + */ +#define NODE_IS_KEYED (1 >> 15) + +XSLTPUBFUN int XSLTCALL + xsltAddKey (xsltStylesheetPtr style, + const xmlChar *name, + const xmlChar *nameURI, + const xmlChar *match, + const xmlChar *use, + xmlNodePtr inst); +XSLTPUBFUN xmlNodeSetPtr XSLTCALL + xsltGetKey (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *nameURI, + const xmlChar *value); +XSLTPUBFUN void XSLTCALL + xsltInitCtxtKeys (xsltTransformContextPtr ctxt, + xsltDocumentPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeKeys (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltFreeDocumentKeys (xsltDocumentPtr doc); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/namespaces.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/namespaces.h new file mode 100644 index 00000000..fa2d3b4c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/namespaces.h @@ -0,0 +1,68 @@ +/* + * Summary: interface for the XSLT namespace handling + * Description: set of function easing the processing and generation + * of namespace nodes in XSLT. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_NAMESPACES_H__ +#define __XML_XSLT_NAMESPACES_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Used within nsAliases hashtable when the default namespace is required + * but it's not been explicitly defined + */ +/** + * UNDEFINED_DEFAULT_NS: + * + * Special value for undefined namespace, internal + */ +#define UNDEFINED_DEFAULT_NS (const xmlChar *) -1L + +XSLTPUBFUN void XSLTCALL + xsltNamespaceAlias (xsltStylesheetPtr style, + xmlNodePtr node); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + xmlNsPtr ns, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetPlainNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + xmlNsPtr ns, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetSpecialNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + const xmlChar *URI, + const xmlChar *prefix, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltCopyNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr elem, + xmlNsPtr ns); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltCopyNamespaceList (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNsPtr cur); +XSLTPUBFUN void XSLTCALL + xsltFreeNamespaceAliasHashes + (xsltStylesheetPtr style); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_NAMESPACES_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/numbersInternals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/numbersInternals.h new file mode 100644 index 00000000..85245928 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/numbersInternals.h @@ -0,0 +1,73 @@ +/* + * Summary: Implementation of the XSLT number functions + * Description: Implementation of the XSLT number functions + * + * Copy: See Copyright for the status of this software. + * + * Author: Bjorn Reese and Daniel Veillard + */ + +#ifndef __XML_XSLT_NUMBERSINTERNALS_H__ +#define __XML_XSLT_NUMBERSINTERNALS_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _xsltCompMatch; + +/** + * xsltNumberData: + * + * This data structure is just a wrapper to pass xsl:number data in. + */ +typedef struct _xsltNumberData xsltNumberData; +typedef xsltNumberData *xsltNumberDataPtr; + +struct _xsltNumberData { + const xmlChar *level; + const xmlChar *count; + const xmlChar *from; + const xmlChar *value; + const xmlChar *format; + int has_format; + int digitsPerGroup; + int groupingCharacter; + int groupingCharacterLen; + xmlDocPtr doc; + xmlNodePtr node; + struct _xsltCompMatch *countPat; + struct _xsltCompMatch *fromPat; + + /* + * accelerators + */ +}; + +/** + * xsltFormatNumberInfo,: + * + * This data structure lists the various parameters needed to format numbers. + */ +typedef struct _xsltFormatNumberInfo xsltFormatNumberInfo; +typedef xsltFormatNumberInfo *xsltFormatNumberInfoPtr; + +struct _xsltFormatNumberInfo { + int integer_hash; /* Number of '#' in integer part */ + int integer_digits; /* Number of '0' in integer part */ + int frac_digits; /* Number of '0' in fractional part */ + int frac_hash; /* Number of '#' in fractional part */ + int group; /* Number of chars per display 'group' */ + int multiplier; /* Scaling for percent or permille */ + char add_decimal; /* Flag for whether decimal point appears in pattern */ + char is_multiplier_set; /* Flag to catch multiple occurences of percent/permille */ + char is_negative_pattern;/* Flag for processing -ve prefix/suffix */ +}; + +#ifdef __cplusplus +} +#endif +#endif /* __XML_XSLT_NUMBERSINTERNALS_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/pattern.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/pattern.h new file mode 100644 index 00000000..a0991c0c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/pattern.h @@ -0,0 +1,84 @@ +/* + * Summary: interface for the pattern matching used in template matches. + * Description: the implementation of the lookup of the right template + * for a given node must be really fast in order to keep + * decent performances. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_PATTERN_H__ +#define __XML_XSLT_PATTERN_H__ + +#include "xsltInternals.h" +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xsltCompMatch: + * + * Data structure used for the implementation of patterns. + * It is kept private (in pattern.c). + */ +typedef struct _xsltCompMatch xsltCompMatch; +typedef xsltCompMatch *xsltCompMatchPtr; + +/* + * Pattern related interfaces. + */ + +XSLTPUBFUN xsltCompMatchPtr XSLTCALL + xsltCompilePattern (const xmlChar *pattern, + xmlDocPtr doc, + xmlNodePtr node, + xsltStylesheetPtr style, + xsltTransformContextPtr runtime); +XSLTPUBFUN void XSLTCALL + xsltFreeCompMatchList (xsltCompMatchPtr comp); +XSLTPUBFUN int XSLTCALL + xsltTestCompMatchList (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltCompMatchPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCompMatchClearCache (xsltTransformContextPtr ctxt, + xsltCompMatchPtr comp); +XSLTPUBFUN void XSLTCALL + xsltNormalizeCompSteps (void *payload, + void *data, + const xmlChar *name); + +/* + * Template related interfaces. + */ +XSLTPUBFUN int XSLTCALL + xsltAddTemplate (xsltStylesheetPtr style, + xsltTemplatePtr cur, + const xmlChar *mode, + const xmlChar *modeURI); +XSLTPUBFUN xsltTemplatePtr XSLTCALL + xsltGetTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltFreeTemplateHashes (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltCleanupTemplates (xsltStylesheetPtr style); + +#if 0 +int xsltMatchPattern (xsltTransformContextPtr ctxt, + xmlNodePtr node, + const xmlChar *pattern, + xmlDocPtr ctxtdoc, + xmlNodePtr ctxtnode); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_PATTERN_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/preproc.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/preproc.h new file mode 100644 index 00000000..2a2fc7e4 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/preproc.h @@ -0,0 +1,43 @@ +/* + * Summary: precomputing stylesheets + * Description: this is the compilation phase, where most of the + * stylesheet is "compiled" into faster to use data. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_PRECOMP_H__ +#define __XML_XSLT_PRECOMP_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces + */ +XSLTPUBVAR const xmlChar *xsltExtMarker; + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltDocumentComp (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); + +XSLTPUBFUN void XSLTCALL + xsltStylePreCompute (xsltStylesheetPtr style, + xmlNodePtr inst); +XSLTPUBFUN void XSLTCALL + xsltFreeStylePreComps (xsltStylesheetPtr style); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_PRECOMP_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/security.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/security.h new file mode 100644 index 00000000..bab5c8c6 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/security.h @@ -0,0 +1,104 @@ +/* + * Summary: interface for the libxslt security framework + * Description: the libxslt security framework allow to restrict + * the access to new resources (file or URL) from + * the stylesheet at runtime. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_SECURITY_H__ +#define __XML_XSLT_SECURITY_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xsltSecurityPref: + * + * structure to indicate the preferences for security in the XSLT + * transformation. + */ +typedef struct _xsltSecurityPrefs xsltSecurityPrefs; +typedef xsltSecurityPrefs *xsltSecurityPrefsPtr; + +/** + * xsltSecurityOption: + * + * the set of option that can be configured + */ +typedef enum { + XSLT_SECPREF_READ_FILE = 1, + XSLT_SECPREF_WRITE_FILE, + XSLT_SECPREF_CREATE_DIRECTORY, + XSLT_SECPREF_READ_NETWORK, + XSLT_SECPREF_WRITE_NETWORK +} xsltSecurityOption; + +/** + * xsltSecurityCheck: + * + * User provided function to check the value of a string like a file + * path or an URL ... + */ +typedef int (*xsltSecurityCheck) (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); + +/* + * Module interfaces + */ +XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL + xsltNewSecurityPrefs (void); +XSLTPUBFUN void XSLTCALL + xsltFreeSecurityPrefs (xsltSecurityPrefsPtr sec); +XSLTPUBFUN int XSLTCALL + xsltSetSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltSecurityOption option, + xsltSecurityCheck func); +XSLTPUBFUN xsltSecurityCheck XSLTCALL + xsltGetSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltSecurityOption option); + +XSLTPUBFUN void XSLTCALL + xsltSetDefaultSecurityPrefs (xsltSecurityPrefsPtr sec); +XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL + xsltGetDefaultSecurityPrefs (void); + +XSLTPUBFUN int XSLTCALL + xsltSetCtxtSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt); + +XSLTPUBFUN int XSLTCALL + xsltSecurityAllow (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); +XSLTPUBFUN int XSLTCALL + xsltSecurityForbid (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); +/* + * internal interfaces + */ +XSLTPUBFUN int XSLTCALL + xsltCheckWrite (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const xmlChar *URL); +XSLTPUBFUN int XSLTCALL + xsltCheckRead (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const xmlChar *URL); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_SECURITY_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/templates.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/templates.h new file mode 100644 index 00000000..84a9de4d --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/templates.h @@ -0,0 +1,77 @@ +/* + * Summary: interface for the template processing + * Description: This set of routine encapsulates XPath calls + * and Attribute Value Templates evaluation. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_TEMPLATES_H__ +#define __XML_XSLT_TEMPLATES_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN int XSLTCALL + xsltEvalXPathPredicate (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp, + xmlNsPtr *nsList, + int nsNr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalTemplateString (xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr inst); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *ns); +XSLTPUBFUN const xmlChar * XSLTCALL + xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *ns, + int *found); + +/* TODO: this is obviously broken ... the namespaces should be passed too ! */ +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalXPathString (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalXPathStringNs (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp, + int nsNr, + xmlNsPtr *nsList); + +XSLTPUBFUN xmlNodePtr * XSLTCALL + xsltTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xmlAttrPtr XSLTCALL + xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr cur); +XSLTPUBFUN xmlAttrPtr XSLTCALL + xsltAttrTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt, + const xmlChar* attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt, + const xmlChar* str, + xmlNodePtr node); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_TEMPLATES_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/transform.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/transform.h new file mode 100644 index 00000000..5a6f7959 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/transform.h @@ -0,0 +1,207 @@ +/* + * Summary: the XSLT engine transformation part. + * Description: This module implements the bulk of the actual + * transformation processing. Most of the xsl: element + * constructs are implemented in this module. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_TRANSFORM_H__ +#define __XML_XSLT_TRANSFORM_H__ + +#include +#include +#include "xsltexports.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XInclude default processing. + */ +XSLTPUBFUN void XSLTCALL + xsltSetXIncludeDefault (int xinclude); +XSLTPUBFUN int XSLTCALL + xsltGetXIncludeDefault (void); + +/** + * Export context to users. + */ +XSLTPUBFUN xsltTransformContextPtr XSLTCALL + xsltNewTransformContext (xsltStylesheetPtr style, + xmlDocPtr doc); + +XSLTPUBFUN void XSLTCALL + xsltFreeTransformContext(xsltTransformContextPtr ctxt); + +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltApplyStylesheetUser (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + FILE * profile, + xsltTransformContextPtr userCtxt); +XSLTPUBFUN void XSLTCALL + xsltProcessOneNode (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltStackElemPtr params); +/** + * Private Interfaces. + */ +XSLTPUBFUN void XSLTCALL + xsltApplyStripSpaces (xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltApplyStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params); +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltProfileStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + FILE * output); +XSLTPUBFUN int XSLTCALL + xsltRunStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + xmlSAXHandlerPtr SAX, + xmlOutputBufferPtr IObuf); +XSLTPUBFUN int XSLTCALL + xsltRunStylesheetUser (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + xmlSAXHandlerPtr SAX, + xmlOutputBufferPtr IObuf, + FILE * profile, + xsltTransformContextPtr userCtxt); +XSLTPUBFUN void XSLTCALL + xsltApplyOneTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr list, + xsltTemplatePtr templ, + xsltStackElemPtr params); +XSLTPUBFUN void XSLTCALL + xsltDocumentElem (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltSort (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCopy (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltText (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltElement (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltComment (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltAttribute (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltProcessingInstruction(xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCopyOf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltValueOf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltNumber (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltApplyImports (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCallTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltApplyTemplates (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltChoose (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltIf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltForEach (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltRegisterAllElement (xsltTransformContextPtr ctxt); + +XSLTPUBFUN xmlNodePtr XSLTCALL + xsltCopyTextString (xsltTransformContextPtr ctxt, + xmlNodePtr target, + const xmlChar *string, + int noescape); + +/* Following 2 functions needed for libexslt/functions.c */ +XSLTPUBFUN void XSLTCALL + xsltLocalVariablePop (xsltTransformContextPtr ctxt, + int limitNr, + int level); +XSLTPUBFUN int XSLTCALL + xsltLocalVariablePush (xsltTransformContextPtr ctxt, + xsltStackElemPtr variable, + int level); +/* + * Hook for the debugger if activated. + */ +XSLTPUBFUN void XSLTCALL + xslHandleDebugger (xmlNodePtr cur, + xmlNodePtr node, + xsltTemplatePtr templ, + xsltTransformContextPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_TRANSFORM_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/variables.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/variables.h new file mode 100644 index 00000000..e2adee0f --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/variables.h @@ -0,0 +1,118 @@ +/* + * Summary: interface for the variable matching and lookup. + * Description: interface for the variable matching and lookup. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_VARIABLES_H__ +#define __XML_XSLT_VARIABLES_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" +#include "functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * XSLT_REGISTER_VARIABLE_LOOKUP: + * + * Registering macro, not general purpose at all but used in different modules. + */ + +#define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt) \ + xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt, \ + xsltXPathVariableLookup, (void *)(ctxt)); \ + xsltRegisterAllFunctions((ctxt)->xpathCtxt); \ + xsltRegisterAllElement(ctxt); \ + (ctxt)->xpathCtxt->extra = ctxt + +/* + * Flags for memory management of RVTs + */ + +/** + * XSLT_RVT_LOCAL: + * + * RVT is destroyed after the current instructions ends. + */ +#define XSLT_RVT_LOCAL 1 + +/** + * XSLT_RVT_FUNC_RESULT: + * + * RVT is part of results returned with func:result. The RVT won't be + * destroyed after exiting a template and will be reset to XSLT_RVT_LOCAL or + * XSLT_RVT_VARIABLE in the template that receives the return value. + */ +#define XSLT_RVT_FUNC_RESULT 2 + +/** + * XSLT_RVT_GLOBAL: + * + * RVT is part of a global variable. + */ +#define XSLT_RVT_GLOBAL 3 + +/* + * Interfaces for the variable module. + */ + +XSLTPUBFUN int XSLTCALL + xsltEvalGlobalVariables (xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltEvalUserParams (xsltTransformContextPtr ctxt, + const char **params); +XSLTPUBFUN int XSLTCALL + xsltQuoteUserParams (xsltTransformContextPtr ctxt, + const char **params); +XSLTPUBFUN int XSLTCALL + xsltEvalOneUserParam (xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value); +XSLTPUBFUN int XSLTCALL + xsltQuoteOneUserParam (xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value); + +XSLTPUBFUN void XSLTCALL + xsltParseGlobalVariable (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseGlobalParam (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetVariable (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetParam (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN xsltStackElemPtr XSLTCALL + xsltParseStylesheetCallerParam (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN int XSLTCALL + xsltAddStackElemList (xsltTransformContextPtr ctxt, + xsltStackElemPtr elems); +XSLTPUBFUN void XSLTCALL + xsltFreeGlobalVariables (xsltTransformContextPtr ctxt); +XSLTPUBFUN xmlXPathObjectPtr XSLTCALL + xsltVariableLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XSLTPUBFUN xmlXPathObjectPtr XSLTCALL + xsltXPathVariableLookup (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_VARIABLES_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xslt.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xslt.h new file mode 100644 index 00000000..02f491a5 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xslt.h @@ -0,0 +1,110 @@ +/* + * Summary: Interfaces, constants and types related to the XSLT engine + * Description: Interfaces, constants and types related to the XSLT engine + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_H__ +#define __XML_XSLT_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_DEFAULT_VERSION: + * + * The default version of XSLT supported. + */ +#define XSLT_DEFAULT_VERSION "1.0" + +/** + * XSLT_DEFAULT_VENDOR: + * + * The XSLT "vendor" string for this processor. + */ +#define XSLT_DEFAULT_VENDOR "libxslt" + +/** + * XSLT_DEFAULT_URL: + * + * The XSLT "vendor" URL for this processor. + */ +#define XSLT_DEFAULT_URL "http://xmlsoft.org/XSLT/" + +/** + * XSLT_NAMESPACE: + * + * The XSLT specification namespace. + */ +#define XSLT_NAMESPACE ((const xmlChar *)"http://www.w3.org/1999/XSL/Transform") + +/** + * XSLT_PARSE_OPTIONS: + * + * The set of options to pass to an xmlReadxxx when loading files for + * XSLT consumption. + */ +#define XSLT_PARSE_OPTIONS \ + XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR | XML_PARSE_NOCDATA + +/** + * xsltMaxDepth: + * + * This value is used to detect templates loops. + */ +XSLTPUBVAR int xsltMaxDepth; + +/** + * * xsltMaxVars: + * * + * * This value is used to detect templates loops. + * */ +XSLTPUBVAR int xsltMaxVars; + +/** + * xsltEngineVersion: + * + * The version string for libxslt. + */ +XSLTPUBVAR const char *xsltEngineVersion; + +/** + * xsltLibxsltVersion: + * + * The version of libxslt compiled. + */ +XSLTPUBVAR const int xsltLibxsltVersion; + +/** + * xsltLibxmlVersion: + * + * The version of libxml libxslt was compiled against. + */ +XSLTPUBVAR const int xsltLibxmlVersion; + +/* + * Global initialization function. + */ + +XSLTPUBFUN void XSLTCALL + xsltInit (void); + +/* + * Global cleanup function. + */ +XSLTPUBFUN void XSLTCALL + xsltCleanupGlobals (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltInternals.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltInternals.h new file mode 100644 index 00000000..6faa07db --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltInternals.h @@ -0,0 +1,1995 @@ +/* + * Summary: internal data structures, constants and functions + * Description: Internal data structures, constants and functions used + * by the XSLT engine. + * They are not part of the API or ABI, i.e. they can change + * without prior notice, use carefully. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_INTERNALS_H__ +#define __XML_XSLT_INTERNALS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "xsltexports.h" +#include "numbersInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define XSLT_DEBUG_PROFILE_CACHE */ + +/** + * XSLT_IS_TEXT_NODE: + * + * check if the argument is a text node + */ +#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \ + (((n)->type == XML_TEXT_NODE) || \ + ((n)->type == XML_CDATA_SECTION_NODE))) + + +/** + * XSLT_MARK_RES_TREE_FRAG: + * + * internal macro to set up tree fragments + */ +#define XSLT_MARK_RES_TREE_FRAG(n) \ + (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); + +/** + * XSLT_IS_RES_TREE_FRAG: + * + * internal macro to test tree fragments + */ +#define XSLT_IS_RES_TREE_FRAG(n) \ + ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \ + ((n)->name != NULL) && ((n)->name[0] == ' ')) + +/** + * XSLT_REFACTORED_KEYCOMP: + * + * Internal define to enable on-demand xsl:key computation. + * That's the only mode now but the define is kept for compatibility + */ +#define XSLT_REFACTORED_KEYCOMP + +/** + * XSLT_FAST_IF: + * + * Internal define to enable usage of xmlXPathCompiledEvalToBoolean() + * for XSLT "tests"; e.g. in + */ +#define XSLT_FAST_IF + +/** + * XSLT_REFACTORED: + * + * Internal define to enable the refactored parts of Libxslt. + */ +/* #define XSLT_REFACTORED */ +/* ==================================================================== */ + +/** + * XSLT_REFACTORED_VARS: + * + * Internal define to enable the refactored variable part of libxslt + */ +#define XSLT_REFACTORED_VARS + +#ifdef XSLT_REFACTORED + +extern const xmlChar *xsltXSLTAttrMarker; + + +/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */ + +/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */ + +/** + * XSLT_REFACTORED_XSLT_NSCOMP + * + * Internal define to enable the pointer-comparison of + * namespaces of XSLT elements. + */ +/* #define XSLT_REFACTORED_XSLT_NSCOMP */ + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + +extern const xmlChar *xsltConstNamespaceNameXSLT; + +/** + * IS_XSLT_ELEM_FAST: + * + * quick test to detect XSLT elements + */ +#define IS_XSLT_ELEM_FAST(n) \ + (((n) != NULL) && ((n)->ns != NULL) && \ + ((n)->ns->href == xsltConstNamespaceNameXSLT)) + +/** + * IS_XSLT_ATTR_FAST: + * + * quick test to detect XSLT attributes + */ +#define IS_XSLT_ATTR_FAST(a) \ + (((a) != NULL) && ((a)->ns != NULL) && \ + ((a)->ns->href == xsltConstNamespaceNameXSLT)) + +/** + * XSLT_HAS_INTERNAL_NSMAP: + * + * check for namespace mapping + */ +#define XSLT_HAS_INTERNAL_NSMAP(s) \ + (((s) != NULL) && ((s)->principal) && \ + ((s)->principal->principalData) && \ + ((s)->principal->principalData->nsMap)) + +/** + * XSLT_GET_INTERNAL_NSMAP: + * + * get pointer to namespace map + */ +#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap) + +#else /* XSLT_REFACTORED_XSLT_NSCOMP */ + +/** + * IS_XSLT_ELEM_FAST: + * + * quick check whether this is an xslt element + */ +#define IS_XSLT_ELEM_FAST(n) \ + (((n) != NULL) && ((n)->ns != NULL) && \ + (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) + +/** + * IS_XSLT_ATTR_FAST: + * + * quick check for xslt namespace attribute + */ +#define IS_XSLT_ATTR_FAST(a) \ + (((a) != NULL) && ((a)->ns != NULL) && \ + (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE))) + + +#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ + + +/** + * XSLT_REFACTORED_MANDATORY_VERSION: + * + * TODO: Currently disabled to surpress regression test failures, since + * the old behaviour was that a missing version attribute + * produced a only a warning and not an error, which was incerrect. + * So the regression tests need to be fixed if this is enabled. + */ +/* #define XSLT_REFACTORED_MANDATORY_VERSION */ + +/** + * xsltPointerList: + * + * Pointer-list for various purposes. + */ +typedef struct _xsltPointerList xsltPointerList; +typedef xsltPointerList *xsltPointerListPtr; +struct _xsltPointerList { + void **items; + int number; + int size; +}; + +#endif + +/** + * XSLT_REFACTORED_PARSING: + * + * Internal define to enable the refactored parts of Libxslt + * related to parsing. + */ +/* #define XSLT_REFACTORED_PARSING */ + +/** + * XSLT_MAX_SORT: + * + * Max number of specified xsl:sort on an element. + */ +#define XSLT_MAX_SORT 15 + +/** + * XSLT_PAT_NO_PRIORITY: + * + * Specific value for pattern without priority expressed. + */ +#define XSLT_PAT_NO_PRIORITY -12345789 + +/** + * xsltRuntimeExtra: + * + * Extra information added to the transformation context. + */ +typedef struct _xsltRuntimeExtra xsltRuntimeExtra; +typedef xsltRuntimeExtra *xsltRuntimeExtraPtr; +struct _xsltRuntimeExtra { + void *info; /* pointer to the extra data */ + xmlFreeFunc deallocate; /* pointer to the deallocation routine */ + union { /* dual-purpose field */ + void *ptr; /* data not needing deallocation */ + int ival; /* integer value storage */ + } val; +}; + +/** + * XSLT_RUNTIME_EXTRA_LST: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to access extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info +/** + * XSLT_RUNTIME_EXTRA_FREE: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to free extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate +/** + * XSLT_RUNTIME_EXTRA: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to define extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ + +/** + * xsltTemplate: + * + * The in-memory structure corresponding to an XSLT Template. + */ +typedef struct _xsltTemplate xsltTemplate; +typedef xsltTemplate *xsltTemplatePtr; +struct _xsltTemplate { + struct _xsltTemplate *next;/* chained list sorted by priority */ + struct _xsltStylesheet *style;/* the containing stylesheet */ + xmlChar *match; /* the matching string */ + float priority; /* as given from the stylesheet, not computed */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *mode;/* the local part of the mode QName */ + const xmlChar *modeURI;/* the URI part of the mode QName */ + xmlNodePtr content; /* the template replacement value */ + xmlNodePtr elem; /* the source element */ + + /* + * TODO: @inheritedNsNr and @inheritedNs won't be used in the + * refactored code. + */ + int inheritedNsNr; /* number of inherited namespaces */ + xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */ + + /* Profiling information */ + int nbCalls; /* the number of time the template was called */ + unsigned long time; /* the time spent in this template */ + void *params; /* xsl:param instructions */ + + int templNr; /* Nb of templates in the stack */ + int templMax; /* Size of the templtes stack */ + xsltTemplatePtr *templCalledTab; /* templates called */ + int *templCountTab; /* .. and how often */ + + /* Conflict resolution */ + int position; +}; + +/** + * xsltDecimalFormat: + * + * Data structure of decimal-format. + */ +typedef struct _xsltDecimalFormat xsltDecimalFormat; +typedef xsltDecimalFormat *xsltDecimalFormatPtr; +struct _xsltDecimalFormat { + struct _xsltDecimalFormat *next; /* chained list */ + xmlChar *name; + /* Used for interpretation of pattern */ + xmlChar *digit; + xmlChar *patternSeparator; + /* May appear in result */ + xmlChar *minusSign; + xmlChar *infinity; + xmlChar *noNumber; /* Not-a-number */ + /* Used for interpretation of pattern and may appear in result */ + xmlChar *decimalPoint; + xmlChar *grouping; + xmlChar *percent; + xmlChar *permille; + xmlChar *zeroDigit; + const xmlChar *nsUri; +}; + +/** + * xsltDocument: + * + * Data structure associated to a parsed document. + */ +typedef struct _xsltDocument xsltDocument; +typedef xsltDocument *xsltDocumentPtr; +struct _xsltDocument { + struct _xsltDocument *next; /* documents are kept in a chained list */ + int main; /* is this the main document */ + xmlDocPtr doc; /* the parsed document */ + void *keys; /* key tables storage */ + struct _xsltDocument *includes; /* subsidiary includes */ + int preproc; /* pre-processing already done */ + int nbKeysComputed; +}; + +/** + * xsltKeyDef: + * + * Representation of an xsl:key. + */ +typedef struct _xsltKeyDef xsltKeyDef; +typedef xsltKeyDef *xsltKeyDefPtr; +struct _xsltKeyDef { + struct _xsltKeyDef *next; + xmlNodePtr inst; + xmlChar *name; + xmlChar *nameURI; + xmlChar *match; + xmlChar *use; + xmlXPathCompExprPtr comp; + xmlXPathCompExprPtr usecomp; + xmlNsPtr *nsList; /* the namespaces in scope */ + int nsNr; /* the number of namespaces in scope */ +}; + +/** + * xsltKeyTable: + * + * Holds the computed keys for key definitions of the same QName. + * Is owned by an xsltDocument. + */ +typedef struct _xsltKeyTable xsltKeyTable; +typedef xsltKeyTable *xsltKeyTablePtr; +struct _xsltKeyTable { + struct _xsltKeyTable *next; + xmlChar *name; + xmlChar *nameURI; + xmlHashTablePtr keys; +}; + +/* + * The in-memory structure corresponding to an XSLT Stylesheet. + * NOTE: most of the content is simply linked from the doc tree + * structure, no specific allocation is made. + */ +typedef struct _xsltStylesheet xsltStylesheet; +typedef xsltStylesheet *xsltStylesheetPtr; + +typedef struct _xsltTransformContext xsltTransformContext; +typedef xsltTransformContext *xsltTransformContextPtr; + +/** + * xsltElemPreComp: + * + * The in-memory structure corresponding to element precomputed data, + * designed to be extended by extension implementors. + */ +typedef struct _xsltElemPreComp xsltElemPreComp; +typedef xsltElemPreComp *xsltElemPreCompPtr; + +/** + * xsltTransformFunction: + * @ctxt: the XSLT transformation context + * @node: the input node + * @inst: the stylesheet node + * @comp: the compiled information from the stylesheet + * + * Signature of the function associated to elements part of the + * stylesheet language like xsl:if or xsl:apply-templates. + */ +typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); + +/** + * xsltSortFunc: + * @ctxt: a transformation context + * @sorts: the node-set to sort + * @nbsorts: the number of sorts + * + * Signature of the function to use during sorting + */ +typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts, + int nbsorts); + +typedef enum { + XSLT_FUNC_COPY=1, + XSLT_FUNC_SORT, + XSLT_FUNC_TEXT, + XSLT_FUNC_ELEMENT, + XSLT_FUNC_ATTRIBUTE, + XSLT_FUNC_COMMENT, + XSLT_FUNC_PI, + XSLT_FUNC_COPYOF, + XSLT_FUNC_VALUEOF, + XSLT_FUNC_NUMBER, + XSLT_FUNC_APPLYIMPORTS, + XSLT_FUNC_CALLTEMPLATE, + XSLT_FUNC_APPLYTEMPLATES, + XSLT_FUNC_CHOOSE, + XSLT_FUNC_IF, + XSLT_FUNC_FOREACH, + XSLT_FUNC_DOCUMENT, + XSLT_FUNC_WITHPARAM, + XSLT_FUNC_PARAM, + XSLT_FUNC_VARIABLE, + XSLT_FUNC_WHEN, + XSLT_FUNC_EXTENSION +#ifdef XSLT_REFACTORED + , + XSLT_FUNC_OTHERWISE, + XSLT_FUNC_FALLBACK, + XSLT_FUNC_MESSAGE, + XSLT_FUNC_INCLUDE, + XSLT_FUNC_ATTRSET, + XSLT_FUNC_LITERAL_RESULT_ELEMENT, + XSLT_FUNC_UNKOWN_FORWARDS_COMPAT +#endif +} xsltStyleType; + +/** + * xsltElemPreCompDeallocator: + * @comp: the #xsltElemPreComp to free up + * + * Deallocates an #xsltElemPreComp structure. + */ +typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp); + +/** + * xsltElemPreComp: + * + * The basic structure for compiled items of the AST of the XSLT processor. + * This structure is also intended to be extended by extension implementors. + * TODO: This is somehow not nice, since it has a "free" field, which + * derived stylesheet-structs do not have. + */ +struct _xsltElemPreComp { + xsltElemPreCompPtr next; /* next item in the global chained + list held by xsltStylesheet. */ + xsltStyleType type; /* type of the element */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the node in the stylesheet's tree + corresponding to this item */ + + /* end of common part */ + xsltElemPreCompDeallocator free; /* the deallocator */ +}; + +/** + * xsltStylePreComp: + * + * The abstract basic structure for items of the XSLT processor. + * This includes: + * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.) + * 2) compiled forms of literal result elements + * 3) compiled forms of extension elements + */ +typedef struct _xsltStylePreComp xsltStylePreComp; +typedef xsltStylePreComp *xsltStylePreCompPtr; + +#ifdef XSLT_REFACTORED + +/* +* Some pointer-list utility functions. +*/ +XSLTPUBFUN xsltPointerListPtr XSLTCALL + xsltPointerListCreate (int initialSize); +XSLTPUBFUN void XSLTCALL + xsltPointerListFree (xsltPointerListPtr list); +XSLTPUBFUN void XSLTCALL + xsltPointerListClear (xsltPointerListPtr list); +XSLTPUBFUN int XSLTCALL + xsltPointerListAddSize (xsltPointerListPtr list, + void *item, + int initialSize); + +/************************************************************************ + * * + * Refactored structures * + * * + ************************************************************************/ + +typedef struct _xsltNsListContainer xsltNsListContainer; +typedef xsltNsListContainer *xsltNsListContainerPtr; +struct _xsltNsListContainer { + xmlNsPtr *list; + int totalNumber; + int xpathNumber; +}; + +/** + * XSLT_ITEM_COMPATIBILITY_FIELDS: + * + * Fields for API compatibility to the structure + * _xsltElemPreComp which is used for extension functions. + * Note that @next is used for storage; it does not reflect a next + * sibling in the tree. + * TODO: Evaluate if we really need such a compatibility. + */ +#define XSLT_ITEM_COMPATIBILITY_FIELDS \ + xsltElemPreCompPtr next;\ + xsltStyleType type;\ + xsltTransformFunction func;\ + xmlNodePtr inst; + +/** + * XSLT_ITEM_NAVIGATION_FIELDS: + * + * Currently empty. + * TODO: It is intended to hold navigational fields in the future. + */ +#define XSLT_ITEM_NAVIGATION_FIELDS +/* + xsltStylePreCompPtr parent;\ + xsltStylePreCompPtr children;\ + xsltStylePreCompPtr nextItem; +*/ + +/** + * XSLT_ITEM_NSINSCOPE_FIELDS: + * + * The in-scope namespaces. + */ +#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs; + +/** + * XSLT_ITEM_COMMON_FIELDS: + * + * Common fields used for all items. + */ +#define XSLT_ITEM_COMMON_FIELDS \ + XSLT_ITEM_COMPATIBILITY_FIELDS \ + XSLT_ITEM_NAVIGATION_FIELDS \ + XSLT_ITEM_NSINSCOPE_FIELDS + +/** + * _xsltStylePreComp: + * + * The abstract basic structure for items of the XSLT processor. + * This includes: + * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.) + * 2) compiled forms of literal result elements + * 3) various properties for XSLT instructions (e.g. xsl:when, + * xsl:with-param) + * + * REVISIT TODO: Keep this structure equal to the fields + * defined by XSLT_ITEM_COMMON_FIELDS + */ +struct _xsltStylePreComp { + xsltElemPreCompPtr next; /* next item in the global chained + list held by xsltStylesheet */ + xsltStyleType type; /* type of the item */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the node in the stylesheet's tree + corresponding to this item. */ + /* Currently no navigational fields. */ + xsltNsListContainerPtr inScopeNs; +}; + +/** + * xsltStyleBasicEmptyItem: + * + * Abstract structure only used as a short-cut for + * XSLT items with no extra fields. + * NOTE that it is intended that this structure looks the same as + * _xsltStylePreComp. + */ +typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem; +typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr; + +struct _xsltStyleBasicEmptyItem { + XSLT_ITEM_COMMON_FIELDS +}; + +/** + * xsltStyleBasicExpressionItem: + * + * Abstract structure only used as a short-cut for + * XSLT items with just an expression. + */ +typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem; +typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr; + +struct _xsltStyleBasicExpressionItem { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; /* TODO: Change this to "expression". */ + xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */ +}; + +/************************************************************************ + * * + * XSLT-instructions/declarations * + * * + ************************************************************************/ + +/** + * xsltStyleItemElement: + * + * + * + * + * + */ +typedef struct _xsltStyleItemElement xsltStyleItemElement; +typedef xsltStyleItemElement *xsltStyleItemElementPtr; + +struct _xsltStyleItemElement { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *use; + int has_use; + const xmlChar *name; + int has_name; + const xmlChar *ns; + const xmlChar *nsPrefix; + int has_ns; +}; + +/** + * xsltStyleItemAttribute: + * + * + * + * + * + */ +typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute; +typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr; + +struct _xsltStyleItemAttribute { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *name; + int has_name; + const xmlChar *ns; + const xmlChar *nsPrefix; + int has_ns; +}; + +/** + * xsltStyleItemText: + * + * + * + * + * + */ +typedef struct _xsltStyleItemText xsltStyleItemText; +typedef xsltStyleItemText *xsltStyleItemTextPtr; + +struct _xsltStyleItemText { + XSLT_ITEM_COMMON_FIELDS + int noescape; /* text */ +}; + +/** + * xsltStyleItemComment: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemComment; +typedef xsltStyleItemComment *xsltStyleItemCommentPtr; + +/** + * xsltStyleItemPI: + * + * + * + * + * + */ +typedef struct _xsltStyleItemPI xsltStyleItemPI; +typedef xsltStyleItemPI *xsltStyleItemPIPtr; + +struct _xsltStyleItemPI { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *name; + int has_name; +}; + +/** + * xsltStyleItemApplyImports: + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports; +typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr; + +/** + * xsltStyleItemApplyTemplates: + * + * + * + * + * + */ +typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates; +typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr; + +struct _xsltStyleItemApplyTemplates { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *mode; /* apply-templates */ + const xmlChar *modeURI; /* apply-templates */ + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + /* TODO: with-params */ +}; + +/** + * xsltStyleItemCallTemplate: + * + * + * + * + * + */ +typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate; +typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr; + +struct _xsltStyleItemCallTemplate { + XSLT_ITEM_COMMON_FIELDS + + xsltTemplatePtr templ; /* call-template */ + const xmlChar *name; /* element, attribute, pi */ + int has_name; /* element, attribute, pi */ + const xmlChar *ns; /* element */ + int has_ns; /* element */ + /* TODO: with-params */ +}; + +/** + * xsltStyleItemCopy: + * + * + * + * + * + */ +typedef struct _xsltStyleItemCopy xsltStyleItemCopy; +typedef xsltStyleItemCopy *xsltStyleItemCopyPtr; + +struct _xsltStyleItemCopy { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *use; /* copy, element */ + int has_use; /* copy, element */ +}; + +/** + * xsltStyleItemIf: + * + * + * + * + * + */ +typedef struct _xsltStyleItemIf xsltStyleItemIf; +typedef xsltStyleItemIf *xsltStyleItemIfPtr; + +struct _xsltStyleItemIf { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *test; /* if */ + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ +}; + + +/** + * xsltStyleItemCopyOf: + * + * + * + */ +typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf; +typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr; + +/** + * xsltStyleItemValueOf: + * + * + * + */ +typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf; +typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr; + +struct _xsltStyleItemValueOf { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + int noescape; +}; + +/** + * xsltStyleItemNumber: + * + * + * + */ +typedef struct _xsltStyleItemNumber xsltStyleItemNumber; +typedef xsltStyleItemNumber *xsltStyleItemNumberPtr; + +struct _xsltStyleItemNumber { + XSLT_ITEM_COMMON_FIELDS + xsltNumberData numdata; /* number */ +}; + +/** + * xsltStyleItemChoose: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemChoose; +typedef xsltStyleItemChoose *xsltStyleItemChoosePtr; + +/** + * xsltStyleItemFallback: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemFallback; +typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr; + +/** + * xsltStyleItemForEach: + * + * + * + * + * + */ +typedef xsltStyleBasicExpressionItem xsltStyleItemForEach; +typedef xsltStyleItemForEach *xsltStyleItemForEachPtr; + +/** + * xsltStyleItemMessage: + * + * + * + * + * + */ +typedef struct _xsltStyleItemMessage xsltStyleItemMessage; +typedef xsltStyleItemMessage *xsltStyleItemMessagePtr; + +struct _xsltStyleItemMessage { + XSLT_ITEM_COMMON_FIELDS + int terminate; +}; + +/** + * xsltStyleItemDocument: + * + * NOTE: This is not an instruction of XSLT 1.0. + */ +typedef struct _xsltStyleItemDocument xsltStyleItemDocument; +typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr; + +struct _xsltStyleItemDocument { + XSLT_ITEM_COMMON_FIELDS + int ver11; /* assigned: in xsltDocumentComp; + read: nowhere; + TODO: Check if we need. */ + const xmlChar *filename; /* document URL */ + int has_filename; +}; + +/************************************************************************ + * * + * Non-instructions (actually properties of instructions/declarations) * + * * + ************************************************************************/ + +/** + * xsltStyleBasicItemVariable: + * + * Basic struct for xsl:variable, xsl:param and xsl:with-param. + * It's currently important to have equal fields, since + * xsltParseStylesheetCallerParam() is used with xsl:with-param from + * the xslt side and with xsl:param from the exslt side (in + * exsltFuncFunctionFunction()). + * + * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param + * have additional different fields. + */ +typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable; +typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr; + +struct _xsltStyleBasicItemVariable { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; + + const xmlChar *name; + int has_name; + const xmlChar *ns; + int has_ns; +}; + +/** + * xsltStyleItemVariable: + * + * + * + * + * + */ +typedef xsltStyleBasicItemVariable xsltStyleItemVariable; +typedef xsltStyleItemVariable *xsltStyleItemVariablePtr; + +/** + * xsltStyleItemParam: + * + * + * + * + * + */ +typedef struct _xsltStyleItemParam xsltStyleItemParam; +typedef xsltStyleItemParam *xsltStyleItemParamPtr; + +struct _xsltStyleItemParam { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; + + const xmlChar *name; + int has_name; + const xmlChar *ns; + int has_ns; +}; + +/** + * xsltStyleItemWithParam: + * + * + * + * + */ +typedef xsltStyleBasicItemVariable xsltStyleItemWithParam; +typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr; + +/** + * xsltStyleItemSort: + * + * Reflects the XSLT xsl:sort item. + * Allowed parents: xsl:apply-templates, xsl:for-each + * + */ +typedef struct _xsltStyleItemSort xsltStyleItemSort; +typedef xsltStyleItemSort *xsltStyleItemSortPtr; + +struct _xsltStyleItemSort { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *stype; /* sort */ + int has_stype; /* sort */ + int number; /* sort */ + const xmlChar *order; /* sort */ + int has_order; /* sort */ + int descending; /* sort */ + const xmlChar *lang; /* sort */ + int has_lang; /* sort */ + const xmlChar *case_order; /* sort */ + int lower_first; /* sort */ + + const xmlChar *use; + int has_use; + + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ +}; + + +/** + * xsltStyleItemWhen: + * + * + * + * + * Allowed parent: xsl:choose + */ +typedef struct _xsltStyleItemWhen xsltStyleItemWhen; +typedef xsltStyleItemWhen *xsltStyleItemWhenPtr; + +struct _xsltStyleItemWhen { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *test; + xmlXPathCompExprPtr comp; +}; + +/** + * xsltStyleItemOtherwise: + * + * Allowed parent: xsl:choose + * + * + * + */ +typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise; +typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr; + +struct _xsltStyleItemOtherwise { + XSLT_ITEM_COMMON_FIELDS +}; + +typedef struct _xsltStyleItemInclude xsltStyleItemInclude; +typedef xsltStyleItemInclude *xsltStyleItemIncludePtr; + +struct _xsltStyleItemInclude { + XSLT_ITEM_COMMON_FIELDS + xsltDocumentPtr include; +}; + +/************************************************************************ + * * + * XSLT elements in forwards-compatible mode * + * * + ************************************************************************/ + +typedef struct _xsltStyleItemUknown xsltStyleItemUknown; +typedef xsltStyleItemUknown *xsltStyleItemUknownPtr; +struct _xsltStyleItemUknown { + XSLT_ITEM_COMMON_FIELDS +}; + + +/************************************************************************ + * * + * Extension elements * + * * + ************************************************************************/ + +/* + * xsltStyleItemExtElement: + * + * Reflects extension elements. + * + * NOTE: Due to the fact that the structure xsltElemPreComp is most + * probably already heavily in use out there by users, so we cannot + * easily change it, we'll create an intermediate structure which will + * hold an xsltElemPreCompPtr. + * BIG NOTE: The only problem I see here is that the user processes the + * content of the stylesheet tree, possibly he'll lookup the node->psvi + * fields in order to find subsequent extension functions. + * In this case, the user's code will break, since the node->psvi + * field will hold now the xsltStyleItemExtElementPtr and not + * the xsltElemPreCompPtr. + * However the place where the structure is anchored in the node-tree, + * namely node->psvi, has beed already once been moved from node->_private + * to node->psvi, so we have a precedent here, which, I think, should allow + * us to change such semantics without headaches. + */ +typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement; +typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr; +struct _xsltStyleItemExtElement { + XSLT_ITEM_COMMON_FIELDS + xsltElemPreCompPtr item; +}; + +/************************************************************************ + * * + * Literal result elements * + * * + ************************************************************************/ + +typedef struct _xsltEffectiveNs xsltEffectiveNs; +typedef xsltEffectiveNs *xsltEffectiveNsPtr; +struct _xsltEffectiveNs { + xsltEffectiveNsPtr nextInStore; /* storage next */ + xsltEffectiveNsPtr next; /* next item in the list */ + const xmlChar *prefix; + const xmlChar *nsName; + /* + * Indicates if eclared on the literal result element; dunno if really + * needed. + */ + int holdByElem; +}; + +/* + * Info for literal result elements. + * This will be set on the elem->psvi field and will be + * shared by literal result elements, which have the same + * excluded result namespaces; i.e., this *won't* be created uniquely + * for every literal result element. + */ +typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo; +typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr; +struct _xsltStyleItemLRElementInfo { + XSLT_ITEM_COMMON_FIELDS + /* + * @effectiveNs is the set of effective ns-nodes + * on the literal result element, which will be added to the result + * element if not already existing in the result tree. + * This means that excluded namespaces (via exclude-result-prefixes, + * extension-element-prefixes and the XSLT namespace) not added + * to the set. + * Namespace-aliasing was applied on the @effectiveNs. + */ + xsltEffectiveNsPtr effectiveNs; + +}; + +#ifdef XSLT_REFACTORED + +typedef struct _xsltNsAlias xsltNsAlias; +typedef xsltNsAlias *xsltNsAliasPtr; +struct _xsltNsAlias { + xsltNsAliasPtr next; /* next in the list */ + xmlNsPtr literalNs; + xmlNsPtr targetNs; + xmlDocPtr docOfTargetNs; +}; +#endif + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + +typedef struct _xsltNsMap xsltNsMap; +typedef xsltNsMap *xsltNsMapPtr; +struct _xsltNsMap { + xsltNsMapPtr next; /* next in the list */ + xmlDocPtr doc; + xmlNodePtr elem; /* the element holding the ns-decl */ + xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */ + const xmlChar *origNsName; /* the original XML namespace name */ + const xmlChar *newNsName; /* the mapped XML namespace name */ +}; +#endif + +/************************************************************************ + * * + * Compile-time structures for *internal* use only * + * * + ************************************************************************/ + +typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData; +typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr; + +typedef struct _xsltNsList xsltNsList; +typedef xsltNsList *xsltNsListPtr; +struct _xsltNsList { + xsltNsListPtr next; /* next in the list */ + xmlNsPtr ns; +}; + +/* +* xsltVarInfo: +* +* Used at compilation time for parameters and variables. +*/ +typedef struct _xsltVarInfo xsltVarInfo; +typedef xsltVarInfo *xsltVarInfoPtr; +struct _xsltVarInfo { + xsltVarInfoPtr next; /* next in the list */ + xsltVarInfoPtr prev; + int depth; /* the depth in the tree */ + const xmlChar *name; + const xmlChar *nsName; +}; + +/** + * xsltCompilerNodeInfo: + * + * Per-node information during compile-time. + */ +typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo; +typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr; +struct _xsltCompilerNodeInfo { + xsltCompilerNodeInfoPtr next; + xsltCompilerNodeInfoPtr prev; + xmlNodePtr node; + int depth; + xsltTemplatePtr templ; /* The owning template */ + int category; /* XSLT element, LR-element or + extension element */ + xsltStyleType type; + xsltElemPreCompPtr item; /* The compiled information */ + /* The current in-scope namespaces */ + xsltNsListContainerPtr inScopeNs; + /* The current excluded result namespaces */ + xsltPointerListPtr exclResultNs; + /* The current extension instruction namespaces */ + xsltPointerListPtr extElemNs; + + /* The current info for literal result elements. */ + xsltStyleItemLRElementInfoPtr litResElemInfo; + /* + * Set to 1 if in-scope namespaces changed, + * or excluded result namespaces changed, + * or extension element namespaces changed. + * This will trigger creation of new infos + * for literal result elements. + */ + int nsChanged; + int preserveWhitespace; + int stripWhitespace; + int isRoot; /* whether this is the stylesheet's root node */ + int forwardsCompat; /* whether forwards-compatible mode is enabled */ + /* whether the content of an extension element was processed */ + int extContentHandled; + /* the type of the current child */ + xsltStyleType curChildType; +}; + +/** + * XSLT_CCTXT: + * + * get pointer to compiler context + */ +#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) + +typedef enum { + XSLT_ERROR_SEVERITY_ERROR = 0, + XSLT_ERROR_SEVERITY_WARNING +} xsltErrorSeverityType; + +typedef struct _xsltCompilerCtxt xsltCompilerCtxt; +typedef xsltCompilerCtxt *xsltCompilerCtxtPtr; +struct _xsltCompilerCtxt { + void *errorCtxt; /* user specific error context */ + /* + * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */ + xsltErrorSeverityType errSeverity; + int warnings; /* TODO: number of warnings found at + compilation */ + int errors; /* TODO: number of errors found at + compilation */ + xmlDictPtr dict; + xsltStylesheetPtr style; + int simplified; /* whether this is a simplified stylesheet */ + /* TODO: structured/unstructured error contexts. */ + int depth; /* Current depth of processing */ + + xsltCompilerNodeInfoPtr inode; + xsltCompilerNodeInfoPtr inodeList; + xsltCompilerNodeInfoPtr inodeLast; + xsltPointerListPtr tmpList; /* Used for various purposes */ + /* + * The XSLT version as specified by the stylesheet's root element. + */ + int isInclude; + int hasForwardsCompat; /* whether forwards-compatible mode was used + in a parsing episode */ + int maxNodeInfos; /* TEMP TODO: just for the interest */ + int maxLREs; /* TEMP TODO: just for the interest */ + /* + * In order to keep the old behaviour, applying strict rules of + * the spec can be turned off. This has effect only on special + * mechanisms like whitespace-stripping in the stylesheet. + */ + int strict; + xsltPrincipalStylesheetDataPtr psData; + xsltStyleItemUknownPtr unknownItem; + int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */ + xsltNsAliasPtr nsAliases; + xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */ + xsltVarInfoPtr ivar; /* topmost local variable/param. */ +}; + +#else /* XSLT_REFACTORED */ +/* +* The old structures before refactoring. +*/ + +/** + * _xsltStylePreComp: + * + * The in-memory structure corresponding to XSLT stylesheet constructs + * precomputed data. + */ +struct _xsltStylePreComp { + xsltElemPreCompPtr next; /* chained list */ + xsltStyleType type; /* type of the element */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the instruction */ + + /* + * Pre computed values. + */ + + const xmlChar *stype; /* sort */ + int has_stype; /* sort */ + int number; /* sort */ + const xmlChar *order; /* sort */ + int has_order; /* sort */ + int descending; /* sort */ + const xmlChar *lang; /* sort */ + int has_lang; /* sort */ + const xmlChar *case_order; /* sort */ + int lower_first; /* sort */ + + const xmlChar *use; /* copy, element */ + int has_use; /* copy, element */ + + int noescape; /* text */ + + const xmlChar *name; /* element, attribute, pi */ + int has_name; /* element, attribute, pi */ + const xmlChar *ns; /* element */ + int has_ns; /* element */ + + const xmlChar *mode; /* apply-templates */ + const xmlChar *modeURI; /* apply-templates */ + + const xmlChar *test; /* if */ + + xsltTemplatePtr templ; /* call-template */ + + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + + int ver11; /* document */ + const xmlChar *filename; /* document URL */ + int has_filename; /* document */ + + xsltNumberData numdata; /* number */ + + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + xmlNsPtr *nsList; /* the namespaces in scope */ + int nsNr; /* the number of namespaces in scope */ +}; + +#endif /* XSLT_REFACTORED */ + + +/* + * The in-memory structure corresponding to an XSLT Variable + * or Param. + */ +typedef struct _xsltStackElem xsltStackElem; +typedef xsltStackElem *xsltStackElemPtr; +struct _xsltStackElem { + struct _xsltStackElem *next;/* chained list */ + xsltStylePreCompPtr comp; /* the compiled form */ + int computed; /* was the evaluation done */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *select; /* the eval string */ + xmlNodePtr tree; /* the sequence constructor if no eval + string or the location */ + xmlXPathObjectPtr value; /* The value if computed */ + xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) + which are bound to the variable's lifetime. */ + int level; /* the depth in the tree; + -1 if persistent (e.g. a given xsl:with-param) */ + xsltTransformContextPtr context; /* The transformation context; needed to cache + the variables */ + int flags; +}; + +#ifdef XSLT_REFACTORED + +struct _xsltPrincipalStylesheetData { + /* + * Namespace dictionary for ns-prefixes and ns-names: + * TODO: Shared between stylesheets, and XPath mechanisms. + * Not used yet. + */ + xmlDictPtr namespaceDict; + /* + * Global list of in-scope namespaces. + */ + xsltPointerListPtr inScopeNamespaces; + /* + * Global list of information for [xsl:]excluded-result-prefixes. + */ + xsltPointerListPtr exclResultNamespaces; + /* + * Global list of information for [xsl:]extension-element-prefixes. + */ + xsltPointerListPtr extElemNamespaces; + xsltEffectiveNsPtr effectiveNs; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + /* + * Namespace name map to get rid of string comparison of namespace names. + */ + xsltNsMapPtr nsMap; +#endif +}; + + +#endif +/* + * Note that we added a @compCtxt field to anchor an stylesheet compilation + * context, since, due to historical reasons, various compile-time function + * take only the stylesheet as argument and not a compilation context. + */ +struct _xsltStylesheet { + /* + * The stylesheet import relation is kept as a tree. + */ + struct _xsltStylesheet *parent; + struct _xsltStylesheet *next; + struct _xsltStylesheet *imports; + + xsltDocumentPtr docList; /* the include document list */ + + /* + * General data on the style sheet document. + */ + xmlDocPtr doc; /* the parsed XML stylesheet */ + xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and + preserve space elements */ + int stripAll; /* strip-space * (1) preserve-space * (-1) */ + xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */ + + /* + * Global variable or parameters. + */ + xsltStackElemPtr variables; /* linked list of param and variables */ + + /* + * Template descriptions. + */ + xsltTemplatePtr templates; /* the ordered list of templates */ + xmlHashTablePtr templatesHash; /* hash table or wherever compiled + templates information is stored */ + struct _xsltCompMatch *rootMatch; /* template based on / */ + struct _xsltCompMatch *keyMatch; /* template based on key() */ + struct _xsltCompMatch *elemMatch; /* template based on * */ + struct _xsltCompMatch *attrMatch; /* template based on @* */ + struct _xsltCompMatch *parentMatch; /* template based on .. */ + struct _xsltCompMatch *textMatch; /* template based on text() */ + struct _xsltCompMatch *piMatch; /* template based on + processing-instruction() */ + struct _xsltCompMatch *commentMatch; /* template based on comment() */ + + /* + * Namespace aliases. + * NOTE: Not used in the refactored code. + */ + xmlHashTablePtr nsAliases; /* the namespace alias hash tables */ + + /* + * Attribute sets. + */ + xmlHashTablePtr attributeSets;/* the attribute sets hash tables */ + + /* + * Namespaces. + * TODO: Eliminate this. + */ + xmlHashTablePtr nsHash; /* the set of namespaces in use: + ATTENTION: This is used for + execution of XPath expressions; unfortunately + it restricts the stylesheet to have distinct + prefixes. + TODO: We need to get rid of this. + */ + void *nsDefs; /* ATTENTION TODO: This is currently used to store + xsltExtDefPtr (in extensions.c) and + *not* xmlNsPtr. + */ + + /* + * Key definitions. + */ + void *keys; /* key definitions */ + + /* + * Output related stuff. + */ + xmlChar *method; /* the output method */ + xmlChar *methodURI; /* associated namespace if any */ + xmlChar *version; /* version string */ + xmlChar *encoding; /* encoding string */ + int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */ + + /* + * Number formatting. + */ + xsltDecimalFormatPtr decimalFormat; + int standalone; /* standalone = "yes" | "no" */ + xmlChar *doctypePublic; /* doctype-public string */ + xmlChar *doctypeSystem; /* doctype-system string */ + int indent; /* should output being indented */ + xmlChar *mediaType; /* media-type string */ + + /* + * Precomputed blocks. + */ + xsltElemPreCompPtr preComps;/* list of precomputed blocks */ + int warnings; /* number of warnings found at compilation */ + int errors; /* number of errors found at compilation */ + + xmlChar *exclPrefix; /* last excluded prefixes */ + xmlChar **exclPrefixTab; /* array of excluded prefixes */ + int exclPrefixNr; /* number of excluded prefixes in scope */ + int exclPrefixMax; /* size of the array */ + + void *_private; /* user defined data */ + + /* + * Extensions. + */ + xmlHashTablePtr extInfos; /* the extension data */ + int extrasNr; /* the number of extras required */ + + /* + * For keeping track of nested includes + */ + xsltDocumentPtr includes; /* points to last nested include */ + + /* + * dictionary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; + /* + * precompiled attribute value templates. + */ + void *attVTs; + /* + * if namespace-alias has an alias for the default stylesheet prefix + * NOTE: Not used in the refactored code. + */ + const xmlChar *defaultAlias; + /* + * bypass pre-processing (already done) (used in imports) + */ + int nopreproc; + /* + * all document text strings were internalized + */ + int internalized; + /* + * Literal Result Element as Stylesheet c.f. section 2.3 + */ + int literal_result; + /* + * The principal stylesheet + */ + xsltStylesheetPtr principal; +#ifdef XSLT_REFACTORED + /* + * Compilation context used during compile-time. + */ + xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */ + + xsltPrincipalStylesheetDataPtr principalData; +#endif + /* + * Forwards-compatible processing + */ + int forwards_compatible; + + xmlHashTablePtr namedTemplates; /* hash table of named templates */ + + xmlXPathContextPtr xpathCtxt; + + unsigned long opLimit; + unsigned long opCount; +}; + +typedef struct _xsltTransformCache xsltTransformCache; +typedef xsltTransformCache *xsltTransformCachePtr; +struct _xsltTransformCache { + xmlDocPtr RVT; + int nbRVT; + xsltStackElemPtr stackItems; + int nbStackItems; +#ifdef XSLT_DEBUG_PROFILE_CACHE + int dbgCachedRVTs; + int dbgReusedRVTs; + int dbgCachedVars; + int dbgReusedVars; +#endif +}; + +/* + * The in-memory structure corresponding to an XSLT Transformation. + */ +typedef enum { + XSLT_OUTPUT_XML = 0, + XSLT_OUTPUT_HTML, + XSLT_OUTPUT_TEXT +} xsltOutputType; + +typedef void * +(*xsltNewLocaleFunc)(const xmlChar *lang, int lowerFirst); +typedef void +(*xsltFreeLocaleFunc)(void *locale); +typedef xmlChar * +(*xsltGenSortKeyFunc)(void *locale, const xmlChar *lang); + +typedef enum { + XSLT_STATE_OK = 0, + XSLT_STATE_ERROR, + XSLT_STATE_STOPPED +} xsltTransformState; + +struct _xsltTransformContext { + xsltStylesheetPtr style; /* the stylesheet used */ + xsltOutputType type; /* the type of output */ + + xsltTemplatePtr templ; /* the current template */ + int templNr; /* Nb of templates in the stack */ + int templMax; /* Size of the templtes stack */ + xsltTemplatePtr *templTab; /* the template stack */ + + xsltStackElemPtr vars; /* the current variable list */ + int varsNr; /* Nb of variable list in the stack */ + int varsMax; /* Size of the variable list stack */ + xsltStackElemPtr *varsTab; /* the variable list stack */ + int varsBase; /* the var base for current templ */ + + /* + * Extensions + */ + xmlHashTablePtr extFunctions; /* the extension functions */ + xmlHashTablePtr extElements; /* the extension elements */ + xmlHashTablePtr extInfos; /* the extension data */ + + const xmlChar *mode; /* the current mode */ + const xmlChar *modeURI; /* the current mode URI */ + + xsltDocumentPtr docList; /* the document list */ + + xsltDocumentPtr document; /* the current source document; can be NULL if an RTF */ + xmlNodePtr node; /* the current node being processed */ + xmlNodeSetPtr nodeList; /* the current node list */ + /* xmlNodePtr current; the node */ + + xmlDocPtr output; /* the resulting document */ + xmlNodePtr insert; /* the insertion node */ + + xmlXPathContextPtr xpathCtxt; /* the XPath context */ + xsltTransformState state; /* the current state */ + + /* + * Global variables + */ + xmlHashTablePtr globalVars; /* the global variables and params */ + + xmlNodePtr inst; /* the instruction in the stylesheet */ + + int xinclude; /* should XInclude be processed */ + + const char * outputFile; /* the output URI if known */ + + int profile; /* is this run profiled */ + long prof; /* the current profiled value */ + int profNr; /* Nb of templates in the stack */ + int profMax; /* Size of the templtaes stack */ + long *profTab; /* the profile template stack */ + + void *_private; /* user defined data */ + + int extrasNr; /* the number of extras used */ + int extrasMax; /* the number of extras allocated */ + xsltRuntimeExtraPtr extras; /* extra per runtime information */ + + xsltDocumentPtr styleList; /* the stylesheet docs list */ + void * sec; /* the security preferences if any */ + + xmlGenericErrorFunc error; /* a specific error handler */ + void * errctx; /* context for the error handler */ + + xsltSortFunc sortfunc; /* a ctxt specific sort routine */ + + /* + * handling of temporary Result Value Tree + * (XSLT 1.0 term: "Result Tree Fragment") + */ + xmlDocPtr tmpRVT; /* list of RVT without persistance */ + xmlDocPtr persistRVT; /* list of persistant RVTs */ + int ctxtflags; /* context processing flags */ + + /* + * Speed optimization when coalescing text nodes + */ + const xmlChar *lasttext; /* last text node content */ + int lasttsize; /* last text node size */ + int lasttuse; /* last text node use */ + /* + * Per Context Debugging + */ + int debugStatus; /* the context level debug status */ + unsigned long* traceCode; /* pointer to the variable holding the mask */ + + int parserOptions; /* parser options xmlParserOption */ + + /* + * dictionary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; + xmlDocPtr tmpDoc; /* Obsolete; not used in the library. */ + /* + * all document text strings are internalized + */ + int internalized; + int nbKeys; + int hasTemplKeyPatterns; + xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */ + xmlNodePtr initialContextNode; + xmlDocPtr initialContextDoc; + xsltTransformCachePtr cache; + void *contextVariable; /* the current variable item */ + xmlDocPtr localRVT; /* list of local tree fragments; will be freed when + the instruction which created the fragment + exits */ + xmlDocPtr localRVTBase; /* Obsolete */ + int keyInitLevel; /* Needed to catch recursive keys issues */ + int depth; /* Needed to catch recursions */ + int maxTemplateDepth; + int maxTemplateVars; + unsigned long opLimit; + unsigned long opCount; + int sourceDocDirty; + unsigned long currentId; /* For generate-id() */ + + xsltNewLocaleFunc newLocale; + xsltFreeLocaleFunc freeLocale; + xsltGenSortKeyFunc genSortKey; +}; + +/** + * CHECK_STOPPED: + * + * Macro to check if the XSLT processing should be stopped. + * Will return from the function. + */ +#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return; + +/** + * CHECK_STOPPEDE: + * + * Macro to check if the XSLT processing should be stopped. + * Will goto the error: label. + */ +#define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error; + +/** + * CHECK_STOPPED0: + * + * Macro to check if the XSLT processing should be stopped. + * Will return from the function with a 0 value. + */ +#define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0); + +/* + * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about + * possible incompatibilities between function pointers and object + * pointers. It is defined in libxml/hash.h within recent versions + * of libxml2, but is put here for compatibility. + */ +#ifndef XML_CAST_FPTR +/** + * XML_CAST_FPTR: + * @fptr: pointer to a function + * + * Macro to do a casting from an object pointer to a + * function pointer without encountering a warning from + * gcc + * + * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) + * This macro violated ISO C aliasing rules (gcc4 on s390 broke) + * so it is disabled now + */ + +#define XML_CAST_FPTR(fptr) fptr +#endif +/* + * Functions associated to the internal types +xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, + xmlChar *name); + */ +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltNewStylesheet (void); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetFile (const xmlChar* filename); +XSLTPUBFUN void XSLTCALL + xsltFreeStylesheet (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltIsBlank (xmlChar *str); +XSLTPUBFUN void XSLTCALL + xsltFreeStackElemList (xsltStackElemPtr elem); +XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL + xsltDecimalFormatGetByName(xsltStylesheetPtr style, + xmlChar *name); +XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL + xsltDecimalFormatGetByQName(xsltStylesheetPtr style, + const xmlChar *nsUri, + const xmlChar *name); + +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetProcess(xsltStylesheetPtr ret, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetOutput(xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetDoc (xmlDocPtr doc); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetImportedDoc(xmlDocPtr doc, + xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetUser(xsltStylesheetPtr style, + xmlDocPtr doc); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltLoadStylesheetPI (xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltNumberFormat (xsltTransformContextPtr ctxt, + xsltNumberDataPtr data, + xmlNodePtr node); +XSLTPUBFUN xmlXPathError XSLTCALL + xsltFormatNumberConversion(xsltDecimalFormatPtr self, + xmlChar *format, + double number, + xmlChar **result); + +XSLTPUBFUN void XSLTCALL + xsltParseTemplateContent(xsltStylesheetPtr style, + xmlNodePtr templ); +XSLTPUBFUN int XSLTCALL + xsltAllocateExtra (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt); +/* + * Extra functions for Result Value Trees + */ +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltCreateRVT (xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltRegisterTmpRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltRegisterLocalRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltRegisterPersistRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltExtensionInstructionResultRegister( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj); +XSLTPUBFUN int XSLTCALL + xsltExtensionInstructionResultFinalize( + xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, + int val); +XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltReleaseRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +/* + * Extra functions for Attribute Value Templates + */ +XSLTPUBFUN void XSLTCALL + xsltCompileAttr (xsltStylesheetPtr style, + xmlAttrPtr attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalAVT (xsltTransformContextPtr ctxt, + void *avt, + xmlNodePtr node); +XSLTPUBFUN void XSLTCALL + xsltFreeAVTList (void *avt); + +/* + * Extra function for successful xsltCleanupGlobals / xsltInit sequence. + */ + +XSLTPUBFUN void XSLTCALL + xsltUninit (void); + +/************************************************************************ + * * + * Compile-time functions for *internal* use only * + * * + ************************************************************************/ + +#ifdef XSLT_REFACTORED +XSLTPUBFUN void XSLTCALL + xsltParseSequenceConstructor( + xsltCompilerCtxtPtr cctxt, + xmlNodePtr start); +XSLTPUBFUN int XSLTCALL + xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt, + xmlNodePtr elem); +#ifdef XSLT_REFACTORED_XSLT_NSCOMP +XSLTPUBFUN int XSLTCALL + xsltRestoreDocumentNamespaces( + xsltNsMapPtr ns, + xmlDocPtr doc); +#endif +#endif /* XSLT_REFACTORED */ + +/************************************************************************ + * * + * Transformation-time functions for *internal* use only * + * * + ************************************************************************/ +XSLTPUBFUN int XSLTCALL + xsltInitCtxtKey (xsltTransformContextPtr ctxt, + xsltDocumentPtr doc, + xsltKeyDefPtr keyd); +XSLTPUBFUN int XSLTCALL + xsltInitAllDocKeys (xsltTransformContextPtr ctxt); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltconfig.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltconfig.h new file mode 100644 index 00000000..0e573be2 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltconfig.h @@ -0,0 +1,146 @@ +/* + * Summary: compile-time version information for the XSLT engine + * Description: compile-time version information for the XSLT engine + * this module is autogenerated. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLTCONFIG_H__ +#define __XML_XSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXSLT_DOTTED_VERSION "1.1.42" + +/** + * LIBXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXSLT_VERSION 10142 + +/** + * LIBXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXSLT_VERSION_STRING "10142" + +/** + * LIBXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBXSLT_VERSION_EXTRA "" + +/** + * WITH_XSLT_DEBUG: + * + * Activate the compilation of the debug reporting. Speed penalty + * is insignifiant and being able to run xsltpoc -v is useful. On + * by default unless --without-debug is passed to configure + */ +#if 1 +#define WITH_XSLT_DEBUG +#endif + +/** + * XSLT_NEED_TRIO: + * + * should be activated if the existing libc library lacks some of the + * string formatting function, in that case reuse the Trio ones already + * compiled in the libxml2 library. + */ + +#if 0 +#define XSLT_NEED_TRIO +#endif +#ifdef __VMS +#define HAVE_SYS_STAT_H 1 +#ifndef XSLT_NEED_TRIO +#define XSLT_NEED_TRIO +#endif +#endif + +#ifdef XSLT_NEED_TRIO +#define TRIO_REPLACE_STDIO +#endif + +/** + * WITH_XSLT_DEBUGGER: + * + * Activate the compilation of the debugger support. Speed penalty + * is insignifiant. + * On by default unless --without-debugger is passed to configure + */ +#if 1 +#ifndef WITH_DEBUGGER +#define WITH_DEBUGGER +#endif +#endif + +/** + * WITH_PROFILER: + * + * Activate the compilation of the profiler. Speed penalty + * is insignifiant. + * On by default unless --without-profiler is passed to configure + */ +#if 1 +#ifndef WITH_PROFILER +#define WITH_PROFILER +#endif +#endif + +/** + * WITH_MODULES: + * + * Whether module support is configured into libxslt + * Note: no default module path for win32 platforms + */ +#if 0 +#ifndef WITH_MODULES +#define WITH_MODULES +#endif +#define LIBXSLT_DEFAULT_PLUGINS_PATH() "/home/flavorjones/code/oss/nokogiri/ports/x86_64-linux-gnu/libxslt/1.1.42/lib/libxslt-plugins" +#endif + +/** + * LIBXSLT_ATTR_FORMAT: + * + * This macro is used to indicate to GCC the parameters are printf-like + */ +#ifdef __GNUC__ +#define LIBXSLT_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) +#else +#define LIBXSLT_ATTR_FORMAT(fmt,args) +#endif + +/** + * LIBXSLT_PUBLIC: + * + * This macro is used to declare PUBLIC variables for Cygwin and for MSC on Windows + */ +#if !defined LIBXSLT_PUBLIC +#if (defined(__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC +#define LIBXSLT_PUBLIC __declspec(dllimport) +#else +#define LIBXSLT_PUBLIC +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTCONFIG_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltexports.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltexports.h new file mode 100644 index 00000000..95c352fe --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltexports.h @@ -0,0 +1,64 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * Description: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __XSLT_EXPORTS_H__ +#define __XSLT_EXPORTS_H__ + +#if defined(_WIN32) || defined(__CYGWIN__) +/** DOC_DISABLE */ + +#ifdef LIBXSLT_STATIC + #define XSLTPUBLIC +#elif defined(IN_LIBXSLT) + #define XSLTPUBLIC __declspec(dllexport) +#else + #define XSLTPUBLIC __declspec(dllimport) +#endif + +#define XSLTCALL __cdecl + +/** DOC_ENABLE */ +#else /* not Windows */ + +/** + * XSLTPUBLIC: + * + * Macro which declares a public symbol + */ +#define XSLTPUBLIC + +/** + * XSLTCALL: + * + * Macro which declares the calling convention for exported functions + */ +#define XSLTCALL + +#endif /* platform switch */ + +/* + * XSLTPUBFUN: + * + * Macro which declares an exportable function + */ +#define XSLTPUBFUN XSLTPUBLIC + +/** + * XSLTPUBVAR: + * + * Macro which declares an exportable variable + */ +#define XSLTPUBVAR XSLTPUBLIC extern + +/* Compatibility */ +#if !defined(LIBXSLT_PUBLIC) +#define LIBXSLT_PUBLIC XSLTPUBVAR +#endif + +#endif /* __XSLT_EXPORTS_H__ */ + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltlocale.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltlocale.h new file mode 100644 index 00000000..c8be58d3 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltlocale.h @@ -0,0 +1,44 @@ +/* + * Summary: Locale handling + * Description: Interfaces for locale handling. Needed for language dependent + * sorting. + * + * Copy: See Copyright for the status of this software. + * + * Author: Nick Wellnhofer + */ + +#ifndef __XML_XSLTLOCALE_H__ +#define __XML_XSLTLOCALE_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN void * XSLTCALL + xsltNewLocale (const xmlChar *langName, + int lowerFirst); +XSLTPUBFUN void XSLTCALL + xsltFreeLocale (void *locale); +XSLTPUBFUN xmlChar * XSLTCALL + xsltStrxfrm (void *locale, + const xmlChar *string); +XSLTPUBFUN void XSLTCALL + xsltFreeLocales (void); + +/* Backward compatibility */ +typedef void *xsltLocale; +typedef xmlChar xsltLocaleChar; +XSLTPUBFUN int XSLTCALL + xsltLocaleStrcmp (void *locale, + const xmlChar *str1, + const xmlChar *str2); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTLOCALE_H__ */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltutils.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltutils.h new file mode 100644 index 00000000..2514774b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/include/libxslt/xsltutils.h @@ -0,0 +1,343 @@ +/* + * Summary: set of utilities for the XSLT engine + * Description: interfaces for the utilities module of the XSLT engine. + * things like message handling, profiling, and other + * generally useful routines. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLTUTILS_H__ +#define __XML_XSLTUTILS_H__ + +#include +#include +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_TODO: + * + * Macro to flag unimplemented blocks. + */ +#define XSLT_TODO \ + xsltGenericError(xsltGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +/** + * XSLT_STRANGE: + * + * Macro to flag that a problem was detected internally. + */ +#define XSLT_STRANGE \ + xsltGenericError(xsltGenericErrorContext, \ + "Internal error at %s:%d\n", \ + __FILE__, __LINE__); + +/** + * IS_XSLT_ELEM: + * + * Checks that the element pertains to XSLT namespace. + */ +#define IS_XSLT_ELEM(n) \ + (((n) != NULL) && ((n)->type == XML_ELEMENT_NODE) && \ + ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) + +/** + * IS_XSLT_NAME: + * + * Checks the value of an element in XSLT namespace. + */ +#define IS_XSLT_NAME(n, val) \ + (xmlStrEqual((n)->name, (const xmlChar *) (val))) + +/** + * IS_XSLT_REAL_NODE: + * + * Check that a node is a 'real' one: document, element, text or attribute. + */ +#define IS_XSLT_REAL_NODE(n) \ + (((n) != NULL) && \ + (((n)->type == XML_ELEMENT_NODE) || \ + ((n)->type == XML_TEXT_NODE) || \ + ((n)->type == XML_CDATA_SECTION_NODE) || \ + ((n)->type == XML_ATTRIBUTE_NODE) || \ + ((n)->type == XML_DOCUMENT_NODE) || \ + ((n)->type == XML_HTML_DOCUMENT_NODE) || \ + ((n)->type == XML_COMMENT_NODE) || \ + ((n)->type == XML_PI_NODE))) + +/* + * Our own version of namespaced attributes lookup. + */ +XSLTPUBFUN xmlChar * XSLTCALL + xsltGetNsProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XSLTPUBFUN const xmlChar * XSLTCALL + xsltGetCNsProp (xsltStylesheetPtr style, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XSLTPUBFUN int XSLTCALL + xsltGetUTF8Char (const unsigned char *utf, + int *len); +#ifdef IN_LIBXSLT +/** DOC_DISABLE */ +XSLTPUBFUN int XSLTCALL + xsltGetUTF8CharZ (const unsigned char *utf, + int *len); +/** DOC_ENABLE */ +#endif + +/* + * XSLT Debug Tracing Tracing Types + */ +typedef enum { + XSLT_TRACE_ALL = -1, + XSLT_TRACE_NONE = 0, + XSLT_TRACE_COPY_TEXT = 1<<0, + XSLT_TRACE_PROCESS_NODE = 1<<1, + XSLT_TRACE_APPLY_TEMPLATE = 1<<2, + XSLT_TRACE_COPY = 1<<3, + XSLT_TRACE_COMMENT = 1<<4, + XSLT_TRACE_PI = 1<<5, + XSLT_TRACE_COPY_OF = 1<<6, + XSLT_TRACE_VALUE_OF = 1<<7, + XSLT_TRACE_CALL_TEMPLATE = 1<<8, + XSLT_TRACE_APPLY_TEMPLATES = 1<<9, + XSLT_TRACE_CHOOSE = 1<<10, + XSLT_TRACE_IF = 1<<11, + XSLT_TRACE_FOR_EACH = 1<<12, + XSLT_TRACE_STRIP_SPACES = 1<<13, + XSLT_TRACE_TEMPLATES = 1<<14, + XSLT_TRACE_KEYS = 1<<15, + XSLT_TRACE_VARIABLES = 1<<16 +} xsltDebugTraceCodes; + +/** + * XSLT_TRACE: + * + * Control the type of xsl debugtrace messages emitted. + */ +#define XSLT_TRACE(ctxt,code,call) \ + if (ctxt->traceCode && (*(ctxt->traceCode) & code)) \ + call + +XSLTPUBFUN void XSLTCALL + xsltDebugSetDefaultTrace(xsltDebugTraceCodes val); +XSLTPUBFUN xsltDebugTraceCodes XSLTCALL + xsltDebugGetDefaultTrace(void); + +/* + * XSLT specific error and debug reporting functions. + */ +XSLTPUBVAR xmlGenericErrorFunc xsltGenericError; +XSLTPUBVAR void *xsltGenericErrorContext; +XSLTPUBVAR xmlGenericErrorFunc xsltGenericDebug; +XSLTPUBVAR void *xsltGenericDebugContext; + +XSLTPUBFUN void XSLTCALL + xsltPrintErrorContext (xsltTransformContextPtr ctxt, + xsltStylesheetPtr style, + xmlNodePtr node); +XSLTPUBFUN void XSLTCALL + xsltMessage (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst); +XSLTPUBFUN void XSLTCALL + xsltSetGenericErrorFunc (void *ctx, + xmlGenericErrorFunc handler); +XSLTPUBFUN void XSLTCALL + xsltSetGenericDebugFunc (void *ctx, + xmlGenericErrorFunc handler); +XSLTPUBFUN void XSLTCALL + xsltSetTransformErrorFunc (xsltTransformContextPtr ctxt, + void *ctx, + xmlGenericErrorFunc handler); +XSLTPUBFUN void XSLTCALL + xsltTransformError (xsltTransformContextPtr ctxt, + xsltStylesheetPtr style, + xmlNodePtr node, + const char *msg, + ...) LIBXSLT_ATTR_FORMAT(4,5); + +XSLTPUBFUN int XSLTCALL + xsltSetCtxtParseOptions (xsltTransformContextPtr ctxt, + int options); +/* + * Sorting. + */ + +XSLTPUBFUN void XSLTCALL + xsltDocumentSortFunction (xmlNodeSetPtr list); +XSLTPUBFUN void XSLTCALL + xsltSetSortFunc (xsltSortFunc handler); +XSLTPUBFUN void XSLTCALL + xsltSetCtxtSortFunc (xsltTransformContextPtr ctxt, + xsltSortFunc handler); +XSLTPUBFUN void XSLTCALL + xsltSetCtxtLocaleHandlers (xsltTransformContextPtr ctxt, + xsltNewLocaleFunc newLocale, + xsltFreeLocaleFunc freeLocale, + xsltGenSortKeyFunc genSortKey); +XSLTPUBFUN void XSLTCALL + xsltDefaultSortFunction (xsltTransformContextPtr ctxt, + xmlNodePtr *sorts, + int nbsorts); +XSLTPUBFUN void XSLTCALL + xsltDoSortFunction (xsltTransformContextPtr ctxt, + xmlNodePtr * sorts, + int nbsorts); +XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL + xsltComputeSortResult (xsltTransformContextPtr ctxt, + xmlNodePtr sort); + +/* + * QNames handling. + */ + +XSLTPUBFUN const xmlChar * XSLTCALL + xsltSplitQName (xmlDictPtr dict, + const xmlChar *name, + const xmlChar **prefix); +XSLTPUBFUN const xmlChar * XSLTCALL + xsltGetQNameURI (xmlNodePtr node, + xmlChar **name); + +XSLTPUBFUN const xmlChar * XSLTCALL + xsltGetQNameURI2 (xsltStylesheetPtr style, + xmlNodePtr node, + const xmlChar **name); + +/* + * Output, reuse libxml I/O buffers. + */ +XSLTPUBFUN int XSLTCALL + xsltSaveResultTo (xmlOutputBufferPtr buf, + xmlDocPtr result, + xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltSaveResultToFilename (const char *URI, + xmlDocPtr result, + xsltStylesheetPtr style, + int compression); +XSLTPUBFUN int XSLTCALL + xsltSaveResultToFile (FILE *file, + xmlDocPtr result, + xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltSaveResultToFd (int fd, + xmlDocPtr result, + xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltSaveResultToString (xmlChar **doc_txt_ptr, + int * doc_txt_len, + xmlDocPtr result, + xsltStylesheetPtr style); + +/* + * XPath interface + */ +XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + xsltXPathCompile (xsltStylesheetPtr style, + const xmlChar *str); +XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL + xsltXPathCompileFlags (xsltStylesheetPtr style, + const xmlChar *str, + int flags); + +#ifdef IN_LIBXSLT +/** DOC_DISABLE */ +#define XSLT_SOURCE_NODE_MASK 15u +#define XSLT_SOURCE_NODE_HAS_KEY 1u +#define XSLT_SOURCE_NODE_HAS_ID 2u +int +xsltGetSourceNodeFlags(xmlNodePtr node); +int +xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node, + int flags); +int +xsltClearSourceNodeFlags(xmlNodePtr node, int flags); +void ** +xsltGetPSVIPtr(xmlNodePtr cur); +/** DOC_ENABLE */ +#endif + +#ifdef WITH_PROFILER +/* + * Profiling. + */ +XSLTPUBFUN void XSLTCALL + xsltSaveProfiling (xsltTransformContextPtr ctxt, + FILE *output); +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltGetProfileInformation (xsltTransformContextPtr ctxt); + +XSLTPUBFUN long XSLTCALL + xsltTimestamp (void); +XSLTPUBFUN void XSLTCALL + xsltCalibrateAdjust (long delta); +#endif + +/** + * XSLT_TIMESTAMP_TICS_PER_SEC: + * + * Sampling precision for profiling + */ +#define XSLT_TIMESTAMP_TICS_PER_SEC 100000l + +/* + * Hooks for the debugger. + */ + +typedef enum { + XSLT_DEBUG_NONE = 0, /* no debugging allowed */ + XSLT_DEBUG_INIT, + XSLT_DEBUG_STEP, + XSLT_DEBUG_STEPOUT, + XSLT_DEBUG_NEXT, + XSLT_DEBUG_STOP, + XSLT_DEBUG_CONT, + XSLT_DEBUG_RUN, + XSLT_DEBUG_RUN_RESTART, + XSLT_DEBUG_QUIT +} xsltDebugStatusCodes; + +XSLTPUBVAR int xslDebugStatus; + +typedef void (*xsltHandleDebuggerCallback) (xmlNodePtr cur, xmlNodePtr node, + xsltTemplatePtr templ, xsltTransformContextPtr ctxt); +typedef int (*xsltAddCallCallback) (xsltTemplatePtr templ, xmlNodePtr source); +typedef void (*xsltDropCallCallback) (void); + +XSLTPUBFUN int XSLTCALL + xsltGetDebuggerStatus (void); +#ifdef WITH_DEBUGGER +XSLTPUBFUN void XSLTCALL + xsltSetDebuggerStatus (int value); +XSLTPUBFUN int XSLTCALL + xsltSetDebuggerCallbacks (int no, void *block); +XSLTPUBFUN int XSLTCALL + xslAddCall (xsltTemplatePtr templ, + xmlNodePtr source); +XSLTPUBFUN void XSLTCALL + xslDropCall (void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTUTILS_H__ */ + + diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/libxml2_polyfill.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/libxml2_polyfill.c new file mode 100644 index 00000000..750b1b52 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/libxml2_polyfill.c @@ -0,0 +1,114 @@ +#include + +#ifndef HAVE_XMLCTXTSETOPTIONS +/* based on libxml2-2.14.0-dev (1d8bd126) parser.c xmlCtxtSetInternalOptions */ +int +xmlCtxtSetOptions(xmlParserCtxtPtr ctxt, int options) +{ + int keepMask = 0; + int allMask; + + if (ctxt == NULL) { + return (-1); + } + + /* + * XInclude options aren't handled by the parser. + * + * XML_PARSE_XINCLUDE + * XML_PARSE_NOXINCNODE + * XML_PARSE_NOBASEFIX + */ + allMask = XML_PARSE_RECOVER | + XML_PARSE_NOENT | + XML_PARSE_DTDLOAD | + XML_PARSE_DTDATTR | + XML_PARSE_DTDVALID | + XML_PARSE_NOERROR | + XML_PARSE_NOWARNING | + XML_PARSE_PEDANTIC | + XML_PARSE_NOBLANKS | +#ifdef LIBXML_SAX1_ENABLED + XML_PARSE_SAX1 | +#endif + XML_PARSE_NONET | + XML_PARSE_NODICT | + XML_PARSE_NSCLEAN | + XML_PARSE_NOCDATA | + XML_PARSE_COMPACT | + XML_PARSE_OLD10 | + XML_PARSE_HUGE | + XML_PARSE_OLDSAX | + XML_PARSE_IGNORE_ENC | + XML_PARSE_BIG_LINES; + + ctxt->options = (ctxt->options & keepMask) | (options & allMask); + + /* + * For some options, struct members are historically the source + * of truth. The values are initalized from global variables and + * old code could also modify them directly. Several older API + * functions that don't take an options argument rely on these + * deprecated mechanisms. + * + * Once public access to struct members and the globals are + * disabled, we can use the options bitmask as source of + * truth, making all these struct members obsolete. + * + * The XML_DETECT_IDS flags is misnamed. It simply enables + * loading of the external subset. + */ + ctxt->recovery = (options & XML_PARSE_RECOVER) ? 1 : 0; + ctxt->replaceEntities = (options & XML_PARSE_NOENT) ? 1 : 0; + ctxt->loadsubset = (options & XML_PARSE_DTDLOAD) ? XML_DETECT_IDS : 0; + ctxt->loadsubset |= (options & XML_PARSE_DTDATTR) ? XML_COMPLETE_ATTRS : 0; + ctxt->validate = (options & XML_PARSE_DTDVALID) ? 1 : 0; + ctxt->pedantic = (options & XML_PARSE_PEDANTIC) ? 1 : 0; + ctxt->keepBlanks = (options & XML_PARSE_NOBLANKS) ? 0 : 1; + ctxt->dictNames = (options & XML_PARSE_NODICT) ? 0 : 1; + + /* + * Changing SAX callbacks is a bad idea. This should be fixed. + */ + if (options & XML_PARSE_NOBLANKS) { + ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + } + if (options & XML_PARSE_NOCDATA) { + ctxt->sax->cdataBlock = NULL; + } + if (options & XML_PARSE_HUGE) { + if (ctxt->dict != NULL) { + xmlDictSetLimit(ctxt->dict, 0); + } + } + + ctxt->linenumbers = 1; + + return (options & ~allMask); +} +#endif + +#ifndef HAVE_XMLCTXTGETOPTIONS +int +xmlCtxtGetOptions(xmlParserCtxtPtr ctxt) +{ + return (ctxt->options); +} +#endif + +#ifndef HAVE_XMLSWITCHENCODINGNAME +int +xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding) +{ + if (ctxt == NULL) { + return (-1); + } + + xmlCharEncodingHandlerPtr handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) { + return (-1); + } + + return (xmlSwitchToEncoding(ctxt, handler)); +} +#endif diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.c new file mode 100644 index 00000000..a43813b9 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.c @@ -0,0 +1,294 @@ +#include + +VALUE mNokogiri ; +VALUE mNokogiriGumbo ; +VALUE mNokogiriHtml4 ; +VALUE mNokogiriHtml4Sax ; +VALUE mNokogiriHtml5 ; +VALUE mNokogiriXml ; +VALUE mNokogiriXmlSax ; +VALUE mNokogiriXmlXpath ; +VALUE mNokogiriXslt ; + +VALUE cNokogiriSyntaxError; +VALUE cNokogiriXmlCharacterData; +VALUE cNokogiriXmlElement; +VALUE cNokogiriXmlXpathSyntaxError; + +void noko_init_xml_attr(void); +void noko_init_xml_attribute_decl(void); +void noko_init_xml_cdata(void); +void noko_init_xml_comment(void); +void noko_init_xml_document(void); +void noko_init_xml_document_fragment(void); +void noko_init_xml_dtd(void); +void noko_init_xml_element_content(void); +void noko_init_xml_element_decl(void); +void noko_init_xml_encoding_handler(void); +void noko_init_xml_entity_decl(void); +void noko_init_xml_entity_reference(void); +void noko_init_xml_namespace(void); +void noko_init_xml_node(void); +void noko_init_xml_node_set(void); +void noko_init_xml_processing_instruction(void); +void noko_init_xml_reader(void); +void noko_init_xml_relax_ng(void); +void noko_init_xml_sax_parser(void); +void noko_init_xml_sax_parser_context(void); +void noko_init_xml_sax_push_parser(void); +void noko_init_xml_schema(void); +void noko_init_xml_syntax_error(void); +void noko_init_xml_text(void); +void noko_init_xml_xpath_context(void); +void noko_init_xslt_stylesheet(void); +void noko_init_html_document(void); +void noko_init_html_element_description(void); +void noko_init_html_entity_lookup(void); +void noko_init_html_sax_parser_context(void); +void noko_init_html_sax_push_parser(void); +void noko_init_html4_sax_parser(void); +void noko_init_gumbo(void); +void noko_init_test_global_handlers(void); + +static ID id_read, id_write, id_external_encoding; + + +static VALUE +noko_io_read_check(VALUE val) +{ + VALUE *args = (VALUE *)val; + return rb_funcall(args[0], id_read, 1, args[1]); +} + + +static VALUE +noko_io_read_failed(VALUE arg, VALUE exc) +{ + return Qundef; +} + + +int +noko_io_read(void *io, char *c_buffer, int c_buffer_len) +{ + VALUE rb_io = (VALUE)io; + VALUE rb_read_string, rb_args[2]; + size_t n_bytes_read, safe_len; + + rb_args[0] = rb_io; + rb_args[1] = INT2NUM(c_buffer_len); + + rb_read_string = rb_rescue(noko_io_read_check, (VALUE)rb_args, noko_io_read_failed, 0); + + if (NIL_P(rb_read_string)) { return 0; } + if (rb_read_string == Qundef) { return -1; } + if (TYPE(rb_read_string) != T_STRING) { return -1; } + + n_bytes_read = (size_t)RSTRING_LEN(rb_read_string); + safe_len = (n_bytes_read > (size_t)c_buffer_len) ? (size_t)c_buffer_len : n_bytes_read; + memcpy(c_buffer, StringValuePtr(rb_read_string), safe_len); + + return (int)safe_len; +} + + +static VALUE +noko_io_write_check(VALUE rb_args) +{ + VALUE rb_io = ((VALUE *)rb_args)[0]; + VALUE rb_output = ((VALUE *)rb_args)[1]; + return rb_funcall(rb_io, id_write, 1, rb_output); +} + + +static VALUE +noko_io_write_failed(VALUE arg, VALUE exc) +{ + return Qundef; +} + + +int +noko_io_write(void *io, char *c_buffer, int c_buffer_len) +{ + VALUE rb_args[2], rb_n_bytes_written; + VALUE rb_io = (VALUE)io; + VALUE rb_enc = Qnil; + rb_encoding *io_encoding; + + if (rb_respond_to(rb_io, id_external_encoding)) { + rb_enc = rb_funcall(rb_io, id_external_encoding, 0); + } + io_encoding = RB_NIL_P(rb_enc) ? rb_ascii8bit_encoding() : rb_to_encoding(rb_enc); + + rb_args[0] = rb_io; + rb_args[1] = rb_enc_str_new(c_buffer, (long)c_buffer_len, io_encoding); + + rb_n_bytes_written = rb_rescue(noko_io_write_check, (VALUE)rb_args, noko_io_write_failed, 0); + if (rb_n_bytes_written == Qundef) { return -1; } + + return NUM2INT(rb_n_bytes_written); +} + + +int +noko_io_close(void *io) +{ + return 0; +} + + +#if defined(_WIN32) && !defined(NOKOGIRI_PACKAGED_LIBRARIES) +# define NOKOGIRI_WINDOWS_DLLS 1 +#else +# define NOKOGIRI_WINDOWS_DLLS 0 +#endif + +// +// | dlls || true | false | +// | nlmm || | | +// |-----------++---------+---------| +// | NULL || default | ruby | +// | "random" || default | ruby | +// | "ruby" || ruby | ruby | +// | "default" || default | default | +// +// We choose *not* to use Ruby's memory management functions with windows DLLs because of this +// issue: https://github.com/sparklemotion/nokogiri/issues/2241 +// +static void +set_libxml_memory_management(void) +{ + const char *nlmm = getenv("NOKOGIRI_LIBXML_MEMORY_MANAGEMENT"); + if (nlmm) { + if (strcmp(nlmm, "default") == 0) { + goto libxml_uses_default_memory_management; + } else if (strcmp(nlmm, "ruby") == 0) { + goto libxml_uses_ruby_memory_management; + } + } + if (NOKOGIRI_WINDOWS_DLLS) { +libxml_uses_default_memory_management: + rb_const_set(mNokogiri, rb_intern("LIBXML_MEMORY_MANAGEMENT"), NOKOGIRI_STR_NEW2("default")); + return; + } else { +libxml_uses_ruby_memory_management: + rb_const_set(mNokogiri, rb_intern("LIBXML_MEMORY_MANAGEMENT"), NOKOGIRI_STR_NEW2("ruby")); + xmlMemSetup((xmlFreeFunc)ruby_xfree, (xmlMallocFunc)ruby_xmalloc, (xmlReallocFunc)ruby_xrealloc, ruby_strdup); + return; + } +} + + +void +Init_nokogiri(void) +{ + mNokogiri = rb_define_module("Nokogiri"); + mNokogiriGumbo = rb_define_module_under(mNokogiri, "Gumbo"); + mNokogiriHtml4 = rb_define_module_under(mNokogiri, "HTML4"); + mNokogiriHtml4Sax = rb_define_module_under(mNokogiriHtml4, "SAX"); + mNokogiriHtml5 = rb_define_module_under(mNokogiri, "HTML5"); + mNokogiriXml = rb_define_module_under(mNokogiri, "XML"); + mNokogiriXmlSax = rb_define_module_under(mNokogiriXml, "SAX"); + mNokogiriXmlXpath = rb_define_module_under(mNokogiriXml, "XPath"); + mNokogiriXslt = rb_define_module_under(mNokogiri, "XSLT"); + + set_libxml_memory_management(); /* must be before any function calls that might invoke xmlInitParser() */ + xmlInitParser(); + exsltRegisterAll(); + + rb_const_set(mNokogiri, rb_intern("LIBXML_COMPILED_VERSION"), NOKOGIRI_STR_NEW2(LIBXML_DOTTED_VERSION)); + rb_const_set(mNokogiri, rb_intern("LIBXML_LOADED_VERSION"), NOKOGIRI_STR_NEW2(xmlParserVersion)); + + rb_const_set(mNokogiri, rb_intern("LIBXSLT_COMPILED_VERSION"), NOKOGIRI_STR_NEW2(LIBXSLT_DOTTED_VERSION)); + rb_const_set(mNokogiri, rb_intern("LIBXSLT_LOADED_VERSION"), NOKOGIRI_STR_NEW2(xsltEngineVersion)); + + rb_const_set(mNokogiri, rb_intern("LIBXML_ZLIB_ENABLED"), + xmlHasFeature(XML_WITH_ZLIB) == 1 ? Qtrue : Qfalse); + +#ifdef NOKOGIRI_PACKAGED_LIBRARIES + rb_const_set(mNokogiri, rb_intern("PACKAGED_LIBRARIES"), Qtrue); +# ifdef NOKOGIRI_PRECOMPILED_LIBRARIES + rb_const_set(mNokogiri, rb_intern("PRECOMPILED_LIBRARIES"), Qtrue); +# else + rb_const_set(mNokogiri, rb_intern("PRECOMPILED_LIBRARIES"), Qfalse); +# endif + rb_const_set(mNokogiri, rb_intern("LIBXML2_PATCHES"), rb_str_split(NOKOGIRI_STR_NEW2(NOKOGIRI_LIBXML2_PATCHES), " ")); + rb_const_set(mNokogiri, rb_intern("LIBXSLT_PATCHES"), rb_str_split(NOKOGIRI_STR_NEW2(NOKOGIRI_LIBXSLT_PATCHES), " ")); +#else + rb_const_set(mNokogiri, rb_intern("PACKAGED_LIBRARIES"), Qfalse); + rb_const_set(mNokogiri, rb_intern("PRECOMPILED_LIBRARIES"), Qfalse); + rb_const_set(mNokogiri, rb_intern("LIBXML2_PATCHES"), Qnil); + rb_const_set(mNokogiri, rb_intern("LIBXSLT_PATCHES"), Qnil); +#endif + +#ifdef LIBXML_ICONV_ENABLED + rb_const_set(mNokogiri, rb_intern("LIBXML_ICONV_ENABLED"), Qtrue); +#else + rb_const_set(mNokogiri, rb_intern("LIBXML_ICONV_ENABLED"), Qfalse); +#endif + +#ifdef NOKOGIRI_OTHER_LIBRARY_VERSIONS + rb_const_set(mNokogiri, rb_intern("OTHER_LIBRARY_VERSIONS"), NOKOGIRI_STR_NEW2(NOKOGIRI_OTHER_LIBRARY_VERSIONS)); +#endif + + if (xsltExtModuleFunctionLookup((const xmlChar *)"date-time", EXSLT_DATE_NAMESPACE)) { + rb_const_set(mNokogiri, rb_intern("LIBXSLT_DATETIME_ENABLED"), Qtrue); + } else { + rb_const_set(mNokogiri, rb_intern("LIBXSLT_DATETIME_ENABLED"), Qfalse); + } + + cNokogiriSyntaxError = rb_define_class_under(mNokogiri, "SyntaxError", rb_eStandardError); + noko_init_xml_syntax_error(); + assert(cNokogiriXmlSyntaxError); + cNokogiriXmlXpathSyntaxError = rb_define_class_under(mNokogiriXmlXpath, "SyntaxError", cNokogiriXmlSyntaxError); + + noko_init_xml_element_content(); + noko_init_xml_encoding_handler(); + noko_init_xml_namespace(); + noko_init_xml_node_set(); + noko_init_xml_reader(); + + noko_init_xml_sax_parser(); + noko_init_html4_sax_parser(); + + noko_init_xml_xpath_context(); + noko_init_xslt_stylesheet(); + noko_init_html_element_description(); + noko_init_html_entity_lookup(); + + noko_init_xml_schema(); + noko_init_xml_relax_ng(); + + noko_init_xml_sax_parser_context(); + noko_init_html_sax_parser_context(); + + noko_init_xml_sax_push_parser(); + noko_init_html_sax_push_parser(); + + noko_init_xml_node(); + noko_init_xml_attr(); + noko_init_xml_attribute_decl(); + noko_init_xml_dtd(); + noko_init_xml_element_decl(); + noko_init_xml_entity_decl(); + noko_init_xml_entity_reference(); + noko_init_xml_processing_instruction(); + assert(cNokogiriXmlNode); + cNokogiriXmlElement = rb_define_class_under(mNokogiriXml, "Element", cNokogiriXmlNode); + cNokogiriXmlCharacterData = rb_define_class_under(mNokogiriXml, "CharacterData", cNokogiriXmlNode); + noko_init_xml_comment(); + noko_init_xml_text(); + noko_init_xml_cdata(); + + noko_init_xml_document_fragment(); + noko_init_xml_document(); + noko_init_html_document(); + noko_init_gumbo(); + + noko_init_test_global_handlers(); + + id_read = rb_intern("read"); + id_write = rb_intern("write"); + id_external_encoding = rb_intern("external_encoding"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.h b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.h new file mode 100644 index 00000000..b75ebc47 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/nokogiri.h @@ -0,0 +1,238 @@ +#ifndef NOKOGIRI_NATIVE +#define NOKOGIRI_NATIVE + +#include // https://github.com/sparklemotion/nokogiri/issues/2696 + +#ifdef _MSC_VER +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif /* WIN32_LEAN_AND_MEAN */ + +# ifndef WIN32 +# define WIN32 +# endif /* WIN32 */ + +# include +# include +# include +#endif + +#ifdef _WIN32 +# define NOKOPUBFUN __declspec(dllexport) +# define NOKOPUBVAR __declspec(dllexport) extern +#else +# define NOKOPUBFUN +# define NOKOPUBVAR extern +#endif + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* libxml2_polyfill.c */ +#ifndef HAVE_XMLCTXTSETOPTIONS +int xmlCtxtSetOptions(xmlParserCtxtPtr ctxt, int options); +#endif +#ifndef HAVE_XMLCTXTGETOPTIONS +int xmlCtxtGetOptions(xmlParserCtxtPtr ctxt); +#endif +#ifndef HAVE_XMLSWITCHENCODINGNAME +int xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding); +#endif + +#define XMLNS_PREFIX "xmlns" +#define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */ + +#ifndef xmlErrorConstPtr +# if LIBXML_VERSION >= 21200 +# define xmlErrorConstPtr const xmlError * +# else +# define xmlErrorConstPtr xmlError * +# endif +#endif + +#include +#include +#include +#include +#include + +#define NOKOGIRI_STR_NEW2(str) NOKOGIRI_STR_NEW(str, strlen((const char *)(str))) +#define NOKOGIRI_STR_NEW(str, len) rb_external_str_new_with_enc((const char *)(str), (long)(len), rb_utf8_encoding()) +#define RBSTR_OR_QNIL(_str) (_str ? NOKOGIRI_STR_NEW2(_str) : Qnil) + +#ifndef NORETURN_DECL +# if defined(__GNUC__) +# define NORETURN_DECL __attribute__ ((noreturn)) +# else +# define NORETURN_DECL +# endif +#endif + +#ifndef PRINTFLIKE_DECL +# if defined(__GNUC__) +# define PRINTFLIKE_DECL(stringidx, argidx) __attribute__ ((format(printf,stringidx,argidx))) +# else +# define PRINTFLIKE_DECL(stringidx, argidx) +# endif +#endif + +#if defined(TRUFFLERUBY) && !defined(NOKOGIRI_PACKAGED_LIBRARIES) +# define TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES +#endif + +NOKOPUBVAR VALUE mNokogiri ; +NOKOPUBVAR VALUE mNokogiriGumbo ; +NOKOPUBVAR VALUE mNokogiriHtml4 ; +NOKOPUBVAR VALUE mNokogiriHtml4Sax ; +NOKOPUBVAR VALUE mNokogiriHtml5 ; +NOKOPUBVAR VALUE mNokogiriXml ; +NOKOPUBVAR VALUE mNokogiriXmlSax ; +NOKOPUBVAR VALUE mNokogiriXmlXpath ; +NOKOPUBVAR VALUE mNokogiriXslt ; + +NOKOPUBVAR VALUE cNokogiriEncodingHandler; +NOKOPUBVAR VALUE cNokogiriSyntaxError; +NOKOPUBVAR VALUE cNokogiriXmlAttr; +NOKOPUBVAR VALUE cNokogiriXmlAttributeDecl; +NOKOPUBVAR VALUE cNokogiriXmlCData; +NOKOPUBVAR VALUE cNokogiriXmlCharacterData; +NOKOPUBVAR VALUE cNokogiriXmlComment; +NOKOPUBVAR VALUE cNokogiriXmlDocument ; +NOKOPUBVAR VALUE cNokogiriXmlDocumentFragment; +NOKOPUBVAR VALUE cNokogiriXmlDtd; +NOKOPUBVAR VALUE cNokogiriXmlElement ; +NOKOPUBVAR VALUE cNokogiriXmlElementContent; +NOKOPUBVAR VALUE cNokogiriXmlElementDecl; +NOKOPUBVAR VALUE cNokogiriXmlEntityDecl; +NOKOPUBVAR VALUE cNokogiriXmlEntityReference; +NOKOPUBVAR VALUE cNokogiriXmlNamespace ; +NOKOPUBVAR VALUE cNokogiriXmlNode ; +NOKOPUBVAR VALUE cNokogiriXmlNodeSet ; +NOKOPUBVAR VALUE cNokogiriXmlProcessingInstruction; +NOKOPUBVAR VALUE cNokogiriXmlReader; +NOKOPUBVAR VALUE cNokogiriXmlRelaxNG; +NOKOPUBVAR VALUE cNokogiriXmlSaxParser ; +NOKOPUBVAR VALUE cNokogiriXmlSaxParserContext; +NOKOPUBVAR VALUE cNokogiriXmlSaxPushParser ; +NOKOPUBVAR VALUE cNokogiriXmlSchema; +NOKOPUBVAR VALUE cNokogiriXmlSyntaxError; +NOKOPUBVAR VALUE cNokogiriXmlText ; +NOKOPUBVAR VALUE cNokogiriXmlXpathContext; +NOKOPUBVAR VALUE cNokogiriXmlXpathSyntaxError; +NOKOPUBVAR VALUE cNokogiriXsltStylesheet ; + +NOKOPUBVAR VALUE cNokogiriHtml4Document ; +NOKOPUBVAR VALUE cNokogiriHtml4SaxPushParser ; +NOKOPUBVAR VALUE cNokogiriHtml4ElementDescription ; +NOKOPUBVAR VALUE cNokogiriHtml4SaxParser; +NOKOPUBVAR VALUE cNokogiriHtml4SaxParserContext; +NOKOPUBVAR VALUE cNokogiriHtml5Document ; + +typedef struct _nokogiriTuple { + VALUE doc; + st_table *unlinkedNodes; + VALUE node_cache; +} nokogiriTuple; +typedef nokogiriTuple *nokogiriTuplePtr; + +typedef struct _libxmlStructuredErrorHandlerState { + void *user_data; + xmlStructuredErrorFunc handler; +} libxmlStructuredErrorHandlerState ; + +typedef struct _nokogiriXsltStylesheetTuple { + xsltStylesheetPtr ss; + VALUE func_instances; +} nokogiriXsltStylesheetTuple; + +void noko_xml_document_pin_node(xmlNodePtr); +void noko_xml_document_pin_namespace(xmlNsPtr, xmlDocPtr); +int noko_xml_document_has_wrapped_blank_nodes_p(xmlDocPtr c_document); + +int noko_io_read(void *ctx, char *buffer, int len); +int noko_io_write(void *ctx, char *buffer, int len); +int noko_io_close(void *ctx); + +#define Noko_Node_Get_Struct(obj,type,sval) ((sval) = (type*)DATA_PTR(obj)) +#define Noko_Namespace_Get_Struct(obj,type,sval) ((sval) = (type*)DATA_PTR(obj)) + +VALUE noko_xml_node_wrap(VALUE klass, xmlNodePtr node) ; +VALUE noko_xml_node_wrap_node_set_result(xmlNodePtr node, VALUE node_set) ; +VALUE noko_xml_node_attrs(xmlNodePtr node) ; + +VALUE noko_xml_namespace_wrap(xmlNsPtr node, xmlDocPtr doc); +VALUE noko_xml_namespace_wrap_xpath_copy(xmlNsPtr node); + +VALUE noko_xml_element_content_wrap(VALUE doc, xmlElementContentPtr element); + +VALUE noko_xml_node_set_wrap(xmlNodeSetPtr node_set, VALUE document) ; +xmlNodeSetPtr noko_xml_node_set_unwrap(VALUE rb_node_set) ; + +VALUE noko_xml_document_wrap_with_init_args(VALUE klass, xmlDocPtr doc, int argc, VALUE *argv); +VALUE noko_xml_document_wrap(VALUE klass, xmlDocPtr doc); +xmlDocPtr noko_xml_document_unwrap(VALUE rb_document); +NOKOPUBFUN VALUE Nokogiri_wrap_xml_document(VALUE klass, + xmlDocPtr doc); /* deprecated. use noko_xml_document_wrap() instead. */ + +xmlSAXHandlerPtr noko_xml_sax_parser_unwrap(VALUE rb_sax_handler); + +xmlParserCtxtPtr noko_xml_sax_push_parser_unwrap(VALUE rb_parser); + +VALUE noko_xml_sax_parser_context_wrap(VALUE klass, xmlParserCtxtPtr c_context); +xmlParserCtxtPtr noko_xml_sax_parser_context_unwrap(VALUE rb_context); +void noko_xml_sax_parser_context_set_encoding(xmlParserCtxtPtr c_context, VALUE rb_encoding); + +#define DOC_RUBY_OBJECT_TEST(x) ((nokogiriTuplePtr)(x->_private)) +#define DOC_RUBY_OBJECT(x) (((nokogiriTuplePtr)(x->_private))->doc) +#define DOC_UNLINKED_NODE_HASH(x) (((nokogiriTuplePtr)(x->_private))->unlinkedNodes) +#define DOC_NODE_CACHE(x) (((nokogiriTuplePtr)(x->_private))->node_cache) +#define NOKOGIRI_NAMESPACE_EH(node) ((node)->type == XML_NAMESPACE_DECL) + +#define DISCARD_CONST_QUAL(t, v) ((t)(uintptr_t)(v)) +#define DISCARD_CONST_QUAL_XMLCHAR(v) DISCARD_CONST_QUAL(xmlChar *, v) + +#if HAVE_RB_CATEGORY_WARNING +# define NOKO_WARN_DEPRECATION(message...) rb_category_warning(RB_WARN_CATEGORY_DEPRECATED, message) +#else +# define NOKO_WARN_DEPRECATION(message...) rb_warning(message) +#endif + +void noko__structured_error_func_save(libxmlStructuredErrorHandlerState *handler_state); +void noko__structured_error_func_save_and_set(libxmlStructuredErrorHandlerState *handler_state, void *user_data, + xmlStructuredErrorFunc handler); +void noko__structured_error_func_restore(libxmlStructuredErrorHandlerState *handler_state); +VALUE noko_xml_syntax_error__wrap(xmlErrorConstPtr error); +void noko__error_array_pusher(void *ctx, xmlErrorConstPtr error); +NORETURN_DECL void noko__error_raise(void *ctx, xmlErrorConstPtr error); +void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, + const char *function_name) ; + +#endif /* NOKOGIRI_NATIVE */ diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/test_global_handlers.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/test_global_handlers.c new file mode 100644 index 00000000..cec0915f --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/test_global_handlers.c @@ -0,0 +1,40 @@ +#include + +static VALUE foreign_error_handler_block = Qnil; + +static void +foreign_error_handler(void *user_data, xmlErrorConstPtr c_error) +{ + rb_funcall(foreign_error_handler_block, rb_intern("call"), 0); +} + +/* + * call-seq: + * __foreign_error_handler { ... } -> nil + * + * Override libxml2's global error handlers to call the block. This method thus has very little + * value except to test that Nokogiri is properly setting error handlers elsewhere in the code. See + * test/helper.rb for how this is being used. + */ +static VALUE +rb_foreign_error_handler(VALUE klass) +{ + rb_need_block(); + foreign_error_handler_block = rb_block_proc(); + xmlSetStructuredErrorFunc(NULL, foreign_error_handler); + return Qnil; +} + +/* + * Document-module: Nokogiri::Test + * + * The Nokogiri::Test module should only be used for testing Nokogiri. + * Do NOT use this outside of the Nokogiri test suite. + */ +void +noko_init_test_global_handlers(void) +{ + VALUE mNokogiriTest = rb_define_module_under(mNokogiri, "Test"); + + rb_define_singleton_method(mNokogiriTest, "__foreign_error_handler", rb_foreign_error_handler, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attr.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attr.c new file mode 100644 index 00000000..90eea3c7 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attr.c @@ -0,0 +1,103 @@ +#include + +VALUE cNokogiriXmlAttr; + +/* + * call-seq: + * value=(content) + * + * Set the value for this Attr to +content+. Use +nil+ to remove the value + * (e.g., a HTML boolean attribute). + */ +static VALUE +set_value(VALUE self, VALUE content) +{ + xmlAttrPtr attr; + xmlChar *value; + xmlNode *cur; + + Noko_Node_Get_Struct(self, xmlAttr, attr); + + if (attr->children) { + xmlFreeNodeList(attr->children); + } + attr->children = attr->last = NULL; + + if (content == Qnil) { + return content; + } + + value = xmlEncodeEntitiesReentrant(attr->doc, (unsigned char *)StringValueCStr(content)); + if (xmlStrlen(value) == 0) { + attr->children = xmlNewDocText(attr->doc, value); + } else { + attr->children = xmlStringGetNodeList(attr->doc, value); + } + xmlFree(value); + + for (cur = attr->children; cur; cur = cur->next) { + cur->parent = (xmlNode *)attr; + cur->doc = attr->doc; + if (cur->next == NULL) { + attr->last = cur; + } + } + + return content; +} + +/* + * call-seq: + * new(document, name) + * + * Create a new Attr element on the +document+ with +name+ + */ +static VALUE +new (int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr xml_doc; + VALUE document; + VALUE name; + VALUE rest; + xmlAttrPtr node; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &document, &name, &rest); + + if (! rb_obj_is_kind_of(document, cNokogiriXmlDocument)) { + rb_raise(rb_eArgError, "parameter must be a Nokogiri::XML::Document"); + } + + xml_doc = noko_xml_document_unwrap(document); + + node = xmlNewDocProp( + xml_doc, + (const xmlChar *)StringValueCStr(name), + NULL + ); + + noko_xml_document_pin_node((xmlNodePtr)node); + + rb_node = noko_xml_node_wrap(klass, (xmlNodePtr)node); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { + rb_yield(rb_node); + } + + return rb_node; +} + +void +noko_init_xml_attr(void) +{ + assert(cNokogiriXmlNode); + /* + * Attr represents a Attr node in an xml document. + */ + cNokogiriXmlAttr = rb_define_class_under(mNokogiriXml, "Attr", cNokogiriXmlNode); + + rb_define_singleton_method(cNokogiriXmlAttr, "new", new, -1); + + rb_define_method(cNokogiriXmlAttr, "value=", set_value, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attribute_decl.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attribute_decl.c new file mode 100644 index 00000000..3f9bebc8 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_attribute_decl.c @@ -0,0 +1,70 @@ +#include + +VALUE cNokogiriXmlAttributeDecl; + +/* + * call-seq: + * attribute_type + * + * The attribute_type for this AttributeDecl + */ +static VALUE +attribute_type(VALUE self) +{ + xmlAttributePtr node; + Noko_Node_Get_Struct(self, xmlAttribute, node); + return INT2NUM(node->atype); +} + +/* + * call-seq: + * default + * + * The default value + */ +static VALUE +default_value(VALUE self) +{ + xmlAttributePtr node; + Noko_Node_Get_Struct(self, xmlAttribute, node); + + if (node->defaultValue) { return NOKOGIRI_STR_NEW2(node->defaultValue); } + return Qnil; +} + +/* + * call-seq: + * enumeration + * + * An enumeration of possible values + */ +static VALUE +enumeration(VALUE self) +{ + xmlAttributePtr node; + xmlEnumerationPtr enm; + VALUE list; + + Noko_Node_Get_Struct(self, xmlAttribute, node); + + list = rb_ary_new(); + enm = node->tree; + + while (enm) { + rb_ary_push(list, NOKOGIRI_STR_NEW2(enm->name)); + enm = enm->next; + } + + return list; +} + +void +noko_init_xml_attribute_decl(void) +{ + assert(cNokogiriXmlNode); + cNokogiriXmlAttributeDecl = rb_define_class_under(mNokogiriXml, "AttributeDecl", cNokogiriXmlNode); + + rb_define_method(cNokogiriXmlAttributeDecl, "attribute_type", attribute_type, 0); + rb_define_method(cNokogiriXmlAttributeDecl, "default", default_value, 0); + rb_define_method(cNokogiriXmlAttributeDecl, "enumeration", enumeration, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_cdata.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_cdata.c new file mode 100644 index 00000000..4431d200 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_cdata.c @@ -0,0 +1,62 @@ +#include + +VALUE cNokogiriXmlCData; + +/* + * call-seq: + * new(document, content) + * + * Create a new CDATA element on the +document+ with +content+ + * + * If +content+ cannot be implicitly converted to a string, this method will + * raise a TypeError exception. + */ +static VALUE +rb_xml_cdata_s_new(int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr c_document; + xmlNodePtr c_node; + VALUE rb_document; + VALUE rb_content; + VALUE rb_rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &rb_document, &rb_content, &rb_rest); + + Check_Type(rb_content, T_STRING); + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) { + rb_raise(rb_eTypeError, + "expected first parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE, + rb_obj_class(rb_document)); + } + + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) { + xmlNodePtr deprecated_node_type_arg; + NOKO_WARN_DEPRECATION("Passing a Node as the first parameter to CDATA.new is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0 + Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg); + c_document = deprecated_node_type_arg->doc; + } else { + c_document = noko_xml_document_unwrap(rb_document); + } + + c_node = xmlNewCDataBlock(c_document, (xmlChar *)StringValueCStr(rb_content), RSTRING_LENINT(rb_content)); + noko_xml_document_pin_node(c_node); + rb_node = noko_xml_node_wrap(klass, c_node); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +void +noko_init_xml_cdata(void) +{ + assert(cNokogiriXmlText); + /* + * CData represents a CData node in an xml document. + */ + cNokogiriXmlCData = rb_define_class_under(mNokogiriXml, "CDATA", cNokogiriXmlText); + + rb_define_singleton_method(cNokogiriXmlCData, "new", rb_xml_cdata_s_new, -1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_comment.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_comment.c new file mode 100644 index 00000000..211761c9 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_comment.c @@ -0,0 +1,57 @@ +#include + +VALUE cNokogiriXmlComment; + +static ID document_id ; + +/* + * call-seq: + * new(document_or_node, content) + * + * Create a new Comment element on the +document+ with +content+. + * Alternatively, if a +node+ is passed, the +node+'s document is used. + */ +static VALUE +new (int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr xml_doc; + xmlNodePtr node; + VALUE document; + VALUE content; + VALUE rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &document, &content, &rest); + + Check_Type(content, T_STRING); + if (rb_obj_is_kind_of(document, cNokogiriXmlNode)) { + document = rb_funcall(document, document_id, 0); + } else if (!rb_obj_is_kind_of(document, cNokogiriXmlDocument) + && !rb_obj_is_kind_of(document, cNokogiriXmlDocumentFragment)) { + rb_raise(rb_eArgError, "first argument must be a XML::Document or XML::Node"); + } + xml_doc = noko_xml_document_unwrap(document); + + node = xmlNewDocComment(xml_doc, (const xmlChar *)StringValueCStr(content)); + noko_xml_document_pin_node(node); + rb_node = noko_xml_node_wrap(klass, node); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +void +noko_init_xml_comment(void) +{ + assert(cNokogiriXmlCharacterData); + /* + * Comment represents a comment node in an xml document. + */ + cNokogiriXmlComment = rb_define_class_under(mNokogiriXml, "Comment", cNokogiriXmlCharacterData); + + rb_define_singleton_method(cNokogiriXmlComment, "new", new, -1); + + document_id = rb_intern("document"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document.c new file mode 100644 index 00000000..74081930 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document.c @@ -0,0 +1,784 @@ +#include + +VALUE cNokogiriXmlDocument ; + +static int +dealloc_node_i2(xmlNodePtr key, xmlNodePtr node, xmlDocPtr doc) +{ + switch (node->type) { + case XML_ATTRIBUTE_NODE: + xmlFreePropList((xmlAttrPtr)node); + break; + case XML_NAMESPACE_DECL: + xmlFreeNs((xmlNsPtr)node); + break; + case XML_DTD_NODE: + xmlFreeDtd((xmlDtdPtr)node); + break; + default: + if (node->parent == NULL) { + node->next = NULL; + node->prev = NULL; + xmlAddChild((xmlNodePtr)doc, node); + } + } + return ST_CONTINUE; +} + +static int +dealloc_node_i(st_data_t key, st_data_t node, st_data_t doc) +{ + return dealloc_node_i2((xmlNodePtr)key, (xmlNodePtr)node, (xmlDocPtr)doc); +} + +static void +remove_private(xmlNodePtr node) +{ + xmlNodePtr child; + + for (child = node->children; child; child = child->next) { + remove_private(child); + } + + if ((node->type == XML_ELEMENT_NODE || + node->type == XML_XINCLUDE_START || + node->type == XML_XINCLUDE_END) && + node->properties) { + for (child = (xmlNodePtr)node->properties; child; child = child->next) { + remove_private(child); + } + } + + node->_private = NULL; +} + +static void +mark(void *data) +{ + xmlDocPtr doc = (xmlDocPtr)data; + nokogiriTuplePtr tuple = (nokogiriTuplePtr)doc->_private; + if (tuple) { + rb_gc_mark(tuple->doc); + rb_gc_mark(tuple->node_cache); + } +} + +static void +dealloc(void *data) +{ + xmlDocPtr doc = (xmlDocPtr)data; + st_table *node_hash; + + node_hash = DOC_UNLINKED_NODE_HASH(doc); + + st_foreach(node_hash, dealloc_node_i, (st_data_t)doc); + st_free_table(node_hash); + + ruby_xfree(doc->_private); + +#if defined(__GNUC__) && __GNUC__ >= 5 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // xmlDeregisterNodeDefault is deprecated as of libxml2 2.11.0 +#endif + /* + * libxml-ruby < 3.0.0 uses xmlDeregisterNodeDefault. If the user is using one of those older + * versions, the registered callback from libxml-ruby will access the _private pointers set by + * nokogiri, which will result in segfaults. + * + * To avoid this, we need to clear the _private pointers from all nodes in this document tree + * before that callback gets invoked. + * + * libxml-ruby 3.0.0 was released in 2017-02, so at some point we can probably safely remove this + * safeguard (though probably pairing with a runtime check on the libxml-ruby version). + */ + if (xmlDeregisterNodeDefaultValue) { + remove_private((xmlNodePtr)doc); + } +#if defined(__GNUC__) && __GNUC__ >= 5 +#pragma GCC diagnostic pop +#endif + + xmlFreeDoc(doc); +} + +static size_t +memsize_node(const xmlNodePtr node) +{ + /* note we don't count namespace definitions, just going for a good-enough number here */ + xmlNodePtr child; + xmlAttrPtr property; + size_t memsize = 0; + + memsize += (size_t)xmlStrlen(node->name); + + if (node->type == XML_ELEMENT_NODE) { + for (property = node->properties; property; property = property->next) { + memsize += sizeof(xmlAttr) + memsize_node((xmlNodePtr)property); + } + } + if (node->type == XML_TEXT_NODE) { + memsize += (size_t)xmlStrlen(node->content); + } + for (child = node->children; child; child = child->next) { + memsize += sizeof(xmlNode) + memsize_node(child); + } + return memsize; +} + +static size_t +memsize(const void *data) +{ + xmlDocPtr doc = (const xmlDocPtr)data; + size_t memsize = sizeof(xmlDoc); + /* This may not account for all memory use */ + memsize += memsize_node((xmlNodePtr)doc); + return memsize; +} + +static const rb_data_type_t xml_doc_type = { + .wrap_struct_name = "xmlDoc", + .function = { + .dmark = mark, + .dfree = dealloc, + .dsize = memsize, + }, + // .flags = RUBY_TYPED_FREE_IMMEDIATELY, // TODO see https://github.com/sparklemotion/nokogiri/issues/2822 +}; + +static VALUE +_xml_document_alloc(VALUE klass) +{ + return TypedData_Wrap_Struct(klass, &xml_doc_type, NULL); +} + +static void +_xml_document_data_ptr_set(VALUE rb_document, xmlDocPtr c_document) +{ + nokogiriTuplePtr tuple; + + assert(DATA_PTR(rb_document) == NULL); + assert(c_document->_private == NULL); + + DATA_PTR(rb_document) = c_document; + + tuple = (nokogiriTuplePtr)ruby_xmalloc(sizeof(nokogiriTuple)); + tuple->doc = rb_document; + tuple->unlinkedNodes = st_init_numtable_with_size(128); + tuple->node_cache = rb_ary_new(); + + c_document->_private = tuple ; + + rb_iv_set(rb_document, "@node_cache", tuple->node_cache); + + return; +} + +/* :nodoc: */ +static VALUE +rb_xml_document_initialize_copy_with_args(VALUE rb_self, VALUE rb_other, VALUE rb_level) +{ + xmlDocPtr c_other, c_self; + int c_level; + + c_other = noko_xml_document_unwrap(rb_other); + c_level = (int)NUM2INT(rb_level); + + c_self = xmlCopyDoc(c_other, c_level); + if (c_self == NULL) { return Qnil; } + + c_self->type = c_other->type; + _xml_document_data_ptr_set(rb_self, c_self); + + return rb_self ; +} + +static void +recursively_remove_namespaces_from_node(xmlNodePtr node) +{ + xmlNodePtr child ; + xmlAttrPtr property ; + + xmlSetNs(node, NULL); + + for (child = node->children ; child ; child = child->next) { + recursively_remove_namespaces_from_node(child); + } + + if (((node->type == XML_ELEMENT_NODE) || + (node->type == XML_XINCLUDE_START) || + (node->type == XML_XINCLUDE_END)) && + node->nsDef) { + xmlNsPtr curr = node->nsDef; + while (curr) { + noko_xml_document_pin_namespace(curr, node->doc); + curr = curr->next; + } + node->nsDef = NULL; + } + + if (node->type == XML_ELEMENT_NODE && node->properties != NULL) { + property = node->properties ; + while (property != NULL) { + if (property->ns) { property->ns = NULL ; } + property = property->next ; + } + } +} + +/* + * call-seq: + * url + * + * Get the url name for this document. + */ +static VALUE +url(VALUE self) +{ + xmlDocPtr doc = noko_xml_document_unwrap(self); + + if (doc->URL) { return NOKOGIRI_STR_NEW2(doc->URL); } + + return Qnil; +} + +/* + * call-seq: + * root= + * + * Set the root element on this document + */ +static VALUE +rb_xml_document_root_set(VALUE self, VALUE rb_new_root) +{ + xmlDocPtr c_document; + xmlNodePtr c_new_root = NULL, c_current_root; + + c_document = noko_xml_document_unwrap(self); + + c_current_root = xmlDocGetRootElement(c_document); + if (c_current_root) { + xmlUnlinkNode(c_current_root); + noko_xml_document_pin_node(c_current_root); + } + + if (!NIL_P(rb_new_root)) { + if (!rb_obj_is_kind_of(rb_new_root, cNokogiriXmlNode)) { + rb_raise(rb_eArgError, + "expected Nokogiri::XML::Node but received %"PRIsVALUE, + rb_obj_class(rb_new_root)); + } + + Noko_Node_Get_Struct(rb_new_root, xmlNode, c_new_root); + + /* If the new root's document is not the same as the current document, + * then we need to dup the node in to this document. */ + if (c_new_root->doc != c_document) { + c_new_root = xmlDocCopyNode(c_new_root, c_document, 1); + if (!c_new_root) { + rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)"); + } + } + } + + xmlDocSetRootElement(c_document, c_new_root); + + return rb_new_root; +} + +/* + * call-seq: + * root + * + * Get the root node for this document. + */ +static VALUE +rb_xml_document_root(VALUE self) +{ + xmlDocPtr c_document; + xmlNodePtr c_root; + + c_document = noko_xml_document_unwrap(self); + + c_root = xmlDocGetRootElement(c_document); + if (!c_root) { + return Qnil; + } + + return noko_xml_node_wrap(Qnil, c_root) ; +} + +/* + * call-seq: + * encoding= encoding + * + * Set the encoding string for this Document + */ +static VALUE +set_encoding(VALUE self, VALUE encoding) +{ + xmlDocPtr doc = noko_xml_document_unwrap(self); + + if (doc->encoding) { + xmlFree(DISCARD_CONST_QUAL_XMLCHAR(doc->encoding)); + } + + doc->encoding = xmlStrdup((xmlChar *)StringValueCStr(encoding)); + + return encoding; +} + +/* + * call-seq: + * encoding + * + * Get the encoding for this Document + */ +static VALUE +encoding(VALUE self) +{ + xmlDocPtr doc = noko_xml_document_unwrap(self); + + if (!doc->encoding) { return Qnil; } + return NOKOGIRI_STR_NEW2(doc->encoding); +} + +/* + * call-seq: + * version + * + * Get the XML version for this Document + */ +static VALUE +version(VALUE self) +{ + xmlDocPtr doc = noko_xml_document_unwrap(self); + + if (!doc->version) { return Qnil; } + return NOKOGIRI_STR_NEW2(doc->version); +} + +/* + * call-seq: + * read_io(io, url, encoding, options) + * + * Create a new document from an IO object + */ +static VALUE +noko_xml_document_s_read_io(VALUE rb_class, + VALUE rb_io, + VALUE rb_url, + VALUE rb_encoding, + VALUE rb_options) +{ + /* TODO: deprecate this method, parse should be the preferred entry point. then we can make this + private. */ + libxmlStructuredErrorHandlerState handler_state; + VALUE rb_errors = rb_ary_new(); + + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + const char *c_url = NIL_P(rb_url) ? NULL : StringValueCStr(rb_url); + const char *c_enc = NIL_P(rb_encoding) ? NULL : StringValueCStr(rb_encoding); + xmlDocPtr c_document = xmlReadIO( + (xmlInputReadCallback)noko_io_read, + (xmlInputCloseCallback)noko_io_close, + (void *)rb_io, + c_url, + c_enc, + (int)NUM2INT(rb_options) + ); + + noko__structured_error_func_restore(&handler_state); + + if (c_document == NULL) { + xmlFreeDoc(c_document); + + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } + } + + VALUE rb_document = noko_xml_document_wrap(rb_class, c_document); + rb_iv_set(rb_document, "@errors", rb_errors); + return rb_document; +} + +/* + * call-seq: + * read_memory(string, url, encoding, options) + * + * Create a new document from a String + */ +static VALUE +noko_xml_document_s_read_memory(VALUE rb_class, + VALUE rb_input, + VALUE rb_url, + VALUE rb_encoding, + VALUE rb_options) +{ + /* TODO: deprecate this method, parse should be the preferred entry point. then we can make this + private. */ + VALUE rb_errors = rb_ary_new(); + xmlSetStructuredErrorFunc((void *)rb_errors, noko__error_array_pusher); + + const char *c_buffer = StringValuePtr(rb_input); + const char *c_url = NIL_P(rb_url) ? NULL : StringValueCStr(rb_url); + const char *c_enc = NIL_P(rb_encoding) ? NULL : StringValueCStr(rb_encoding); + int c_buffer_len = (int)RSTRING_LEN(rb_input); + xmlDocPtr c_document = xmlReadMemory(c_buffer, c_buffer_len, c_url, c_enc, (int)NUM2INT(rb_options)); + + xmlSetStructuredErrorFunc(NULL, NULL); + + if (c_document == NULL) { + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } + } + + VALUE document = noko_xml_document_wrap(rb_class, c_document); + rb_iv_set(document, "@errors", rb_errors); + return document; +} + +/* + * call-seq: + * new(version = "1.0") + * + * Create a new empty document declaring XML version +version+. + */ +static VALUE +new (int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr doc; + VALUE version, rest, rb_doc ; + + rb_scan_args(argc, argv, "0*", &rest); + version = rb_ary_entry(rest, (long)0); + if (NIL_P(version)) { version = rb_str_new2("1.0"); } + + doc = xmlNewDoc((xmlChar *)StringValueCStr(version)); + rb_doc = noko_xml_document_wrap_with_init_args(klass, doc, argc, argv); + return rb_doc ; +} + +/* + * call-seq: + * remove_namespaces! + * + * Remove all namespaces from all nodes in the document. + * + * This could be useful for developers who either don't understand namespaces + * or don't care about them. + * + * The following example shows a use case, and you can decide for yourself + * whether this is a good thing or not: + * + * doc = Nokogiri::XML <<-EOXML + * + * + * Michelin Model XGV + * + * + * I'm a bicycle tire! + * + * + * EOXML + * + * doc.xpath("//tire").to_s # => "" + * doc.xpath("//part:tire", "part" => "http://general-motors.com/").to_s # => "Michelin Model XGV" + * doc.xpath("//part:tire", "part" => "http://schwinn.com/").to_s # => "I'm a bicycle tire!" + * + * doc.remove_namespaces! + * + * doc.xpath("//tire").to_s # => "Michelin Model XGVI'm a bicycle tire!" + * doc.xpath("//part:tire", "part" => "http://general-motors.com/").to_s # => "" + * doc.xpath("//part:tire", "part" => "http://schwinn.com/").to_s # => "" + * + * For more information on why this probably is *not* a good thing in general, + * please direct your browser to + * http://tenderlovemaking.com/2009/04/23/namespaces-in-xml.html + */ +static VALUE +remove_namespaces_bang(VALUE self) +{ + xmlDocPtr doc = noko_xml_document_unwrap(self); + + recursively_remove_namespaces_from_node((xmlNodePtr)doc); + return self; +} + +/* call-seq: + * doc.create_entity(name, type, external_id, system_id, content) + * + * Create a new entity named +name+. + * + * +type+ is an integer representing the type of entity to be created, and it defaults to + * +Nokogiri::XML::EntityDecl::INTERNAL_GENERAL+. See the constants on Nokogiri::XML::EntityDecl for + * more information. + * + * +external_id+, +system_id+, and +content+ set the External ID, System ID, + * and content respectively. All of these parameters are optional. + */ +static VALUE +noko_xml_document__create_entity(int argc, VALUE *argv, VALUE rb_document) +{ + VALUE rb_name; + VALUE rb_type; + VALUE rb_ext_id; + VALUE rb_sys_id; + VALUE rb_content; + + rb_scan_args(argc, argv, "14", + &rb_name, + &rb_type, &rb_ext_id, &rb_sys_id, &rb_content); + + xmlDocPtr c_document = noko_xml_document_unwrap(rb_document); + + libxmlStructuredErrorHandlerState handler_state; + VALUE rb_errors = rb_ary_new(); + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + xmlEntityPtr c_entity = xmlAddDocEntity( + c_document, + (xmlChar *)(NIL_P(rb_name) ? NULL : StringValueCStr(rb_name)), + (int)(NIL_P(rb_type) ? XML_INTERNAL_GENERAL_ENTITY : NUM2INT(rb_type)), + (xmlChar *)(NIL_P(rb_ext_id) ? NULL : StringValueCStr(rb_ext_id)), + (xmlChar *)(NIL_P(rb_sys_id) ? NULL : StringValueCStr(rb_sys_id)), + (xmlChar *)(NIL_P(rb_content) ? NULL : StringValueCStr(rb_content)) + ); + + noko__structured_error_func_restore(&handler_state); + + if (NULL == c_entity) { + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not create entity"); + } + } + + return noko_xml_node_wrap(cNokogiriXmlEntityDecl, (xmlNodePtr)c_entity); +} + +static int +block_caller(void *ctx, xmlNodePtr c_node, xmlNodePtr c_parent_node) +{ + VALUE block = (VALUE)ctx; + VALUE rb_node; + VALUE rb_parent_node; + VALUE ret; + + if (c_node->type == XML_NAMESPACE_DECL) { + rb_node = noko_xml_namespace_wrap((xmlNsPtr)c_node, c_parent_node->doc); + } else { + rb_node = noko_xml_node_wrap(Qnil, c_node); + } + rb_parent_node = c_parent_node ? noko_xml_node_wrap(Qnil, c_parent_node) : Qnil; + + ret = rb_funcall(block, rb_intern("call"), 2, rb_node, rb_parent_node); + + return (Qfalse == ret || Qnil == ret) ? 0 : 1; +} + +/* call-seq: + * doc.canonicalize(mode=XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false) + * doc.canonicalize { |obj, parent| ... } + * + * Canonicalize a document and return the results. Takes an optional block + * that takes two parameters: the +obj+ and that node's +parent+. + * The +obj+ will be either a Nokogiri::XML::Node, or a Nokogiri::XML::Namespace + * The block must return a non-nil, non-false value if the +obj+ passed in + * should be included in the canonicalized document. + */ +static VALUE +rb_xml_document_canonicalize(int argc, VALUE *argv, VALUE self) +{ + VALUE rb_mode; + VALUE rb_namespaces; + VALUE rb_comments_p; + int c_mode = 0; + xmlChar **c_namespaces; + + xmlDocPtr c_doc; + xmlOutputBufferPtr c_obuf; + xmlC14NIsVisibleCallback c_callback_wrapper = NULL; + void *rb_callback = NULL; + + VALUE rb_cStringIO; + VALUE rb_io; + + rb_scan_args(argc, argv, "03", &rb_mode, &rb_namespaces, &rb_comments_p); + if (!NIL_P(rb_mode)) { + Check_Type(rb_mode, T_FIXNUM); + c_mode = NUM2INT(rb_mode); + } + if (!NIL_P(rb_namespaces)) { + Check_Type(rb_namespaces, T_ARRAY); + if (c_mode == XML_C14N_1_0 || c_mode == XML_C14N_1_1) { + rb_raise(rb_eRuntimeError, "This canonicalizer does not support this operation"); + } + } + + c_doc = noko_xml_document_unwrap(self); + + rb_cStringIO = rb_const_get_at(rb_cObject, rb_intern("StringIO")); + rb_io = rb_class_new_instance(0, 0, rb_cStringIO); + c_obuf = xmlAllocOutputBuffer(NULL); + + c_obuf->writecallback = (xmlOutputWriteCallback)noko_io_write; + c_obuf->closecallback = (xmlOutputCloseCallback)noko_io_close; + c_obuf->context = (void *)rb_io; + + if (rb_block_given_p()) { + c_callback_wrapper = block_caller; + rb_callback = (void *)rb_block_proc(); + } + + if (NIL_P(rb_namespaces)) { + c_namespaces = NULL; + } else { + long ns_len = RARRAY_LEN(rb_namespaces); + c_namespaces = ruby_xcalloc((size_t)ns_len + 1, sizeof(xmlChar *)); + for (int j = 0 ; j < ns_len ; j++) { + VALUE entry = rb_ary_entry(rb_namespaces, j); + c_namespaces[j] = (xmlChar *)StringValueCStr(entry); + } + } + + xmlC14NExecute(c_doc, c_callback_wrapper, rb_callback, + c_mode, + c_namespaces, + (int)RTEST(rb_comments_p), + c_obuf); + + ruby_xfree(c_namespaces); + xmlOutputBufferClose(c_obuf); + + return rb_funcall(rb_io, rb_intern("string"), 0); +} + +VALUE +noko_xml_document_wrap_with_init_args(VALUE klass, xmlDocPtr c_document, int argc, VALUE *argv) +{ + VALUE rb_document; + + if (!klass) { + klass = cNokogiriXmlDocument; + } + + rb_document = _xml_document_alloc(klass); + _xml_document_data_ptr_set(rb_document, c_document); + + rb_iv_set(rb_document, "@decorators", Qnil); + rb_iv_set(rb_document, "@errors", Qnil); + + rb_obj_call_init(rb_document, argc, argv); + + return rb_document ; +} + + +/* deprecated. use noko_xml_document_wrap() instead. */ +VALUE +Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc) +{ + /* TODO: deprecate this method in v2.0 */ + return noko_xml_document_wrap_with_init_args(klass, doc, 0, NULL); +} + +VALUE +noko_xml_document_wrap(VALUE klass, xmlDocPtr doc) +{ + return noko_xml_document_wrap_with_init_args(klass, doc, 0, NULL); +} + +xmlDocPtr +noko_xml_document_unwrap(VALUE rb_document) +{ + xmlDocPtr c_document; + TypedData_Get_Struct(rb_document, xmlDoc, &xml_doc_type, c_document); + return c_document; +} + +/* Schema creation will remove and deallocate "blank" nodes. + * If those blank nodes have been exposed to Ruby, they could get freed + * out from under the VALUE pointer. This function checks to see if any of + * those nodes have been exposed to Ruby, and if so we should raise an exception. + */ +int +noko_xml_document_has_wrapped_blank_nodes_p(xmlDocPtr c_document) +{ + VALUE cache = DOC_NODE_CACHE(c_document); + + if (NIL_P(cache)) { + return 0; + } + + for (long jnode = 0; jnode < RARRAY_LEN(cache); jnode++) { + xmlNodePtr node; + VALUE element = rb_ary_entry(cache, jnode); + + Noko_Node_Get_Struct(element, xmlNode, node); + if (xmlIsBlankNode(node)) { + return 1; + } + } + + return 0; +} + +void +noko_xml_document_pin_node(xmlNodePtr node) +{ + xmlDocPtr doc; + nokogiriTuplePtr tuple; + + doc = node->doc; + tuple = (nokogiriTuplePtr)doc->_private; + st_insert(tuple->unlinkedNodes, (st_data_t)node, (st_data_t)node); +} + + +void +noko_xml_document_pin_namespace(xmlNsPtr ns, xmlDocPtr doc) +{ + nokogiriTuplePtr tuple; + + tuple = (nokogiriTuplePtr)doc->_private; + st_insert(tuple->unlinkedNodes, (st_data_t)ns, (st_data_t)ns); +} + + +void +noko_init_xml_document(void) +{ + assert(cNokogiriXmlNode); + + cNokogiriXmlDocument = rb_define_class_under(mNokogiriXml, "Document", cNokogiriXmlNode); + + rb_define_alloc_func(cNokogiriXmlDocument, _xml_document_alloc); + + rb_define_singleton_method(cNokogiriXmlDocument, "read_memory", noko_xml_document_s_read_memory, 4); + rb_define_singleton_method(cNokogiriXmlDocument, "read_io", noko_xml_document_s_read_io, 4); + rb_define_singleton_method(cNokogiriXmlDocument, "new", new, -1); + + rb_define_method(cNokogiriXmlDocument, "root", rb_xml_document_root, 0); + rb_define_method(cNokogiriXmlDocument, "root=", rb_xml_document_root_set, 1); + rb_define_method(cNokogiriXmlDocument, "encoding", encoding, 0); + rb_define_method(cNokogiriXmlDocument, "encoding=", set_encoding, 1); + rb_define_method(cNokogiriXmlDocument, "version", version, 0); + rb_define_method(cNokogiriXmlDocument, "canonicalize", rb_xml_document_canonicalize, -1); + rb_define_method(cNokogiriXmlDocument, "url", url, 0); + rb_define_method(cNokogiriXmlDocument, "create_entity", noko_xml_document__create_entity, -1); + rb_define_method(cNokogiriXmlDocument, "remove_namespaces!", remove_namespaces_bang, 0); + + rb_define_protected_method(cNokogiriXmlDocument, "initialize_copy_with_args", rb_xml_document_initialize_copy_with_args, + 2); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document_fragment.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document_fragment.c new file mode 100644 index 00000000..3f28d28d --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_document_fragment.c @@ -0,0 +1,29 @@ +#include + +VALUE cNokogiriXmlDocumentFragment; + +/* :nodoc: */ +static VALUE +noko_xml_document_fragment_s_native_new(VALUE klass, VALUE rb_doc) +{ + xmlDocPtr c_doc; + xmlNodePtr c_node; + VALUE rb_node; + + c_doc = noko_xml_document_unwrap(rb_doc); + c_node = xmlNewDocFragment(c_doc->doc); + noko_xml_document_pin_node(c_node); + rb_node = noko_xml_node_wrap(klass, c_node); + + return rb_node; +} + +void +noko_init_xml_document_fragment(void) +{ + assert(cNokogiriXmlNode); + + cNokogiriXmlDocumentFragment = rb_define_class_under(mNokogiriXml, "DocumentFragment", cNokogiriXmlNode); + + rb_define_singleton_method(cNokogiriXmlDocumentFragment, "native_new", noko_xml_document_fragment_s_native_new, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_dtd.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_dtd.c new file mode 100644 index 00000000..d3610205 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_dtd.c @@ -0,0 +1,208 @@ +#include + +VALUE cNokogiriXmlDtd; + +static void +notation_copier(void *c_notation_ptr, void *rb_hash_ptr, const xmlChar *name) +{ + VALUE rb_hash = (VALUE)rb_hash_ptr; + xmlNotationPtr c_notation = (xmlNotationPtr)c_notation_ptr; + VALUE rb_notation; + VALUE cNokogiriXmlNotation; + VALUE rb_constructor_args[3]; + + rb_constructor_args[0] = (c_notation->name ? NOKOGIRI_STR_NEW2(c_notation->name) : Qnil); + rb_constructor_args[1] = (c_notation->PublicID ? NOKOGIRI_STR_NEW2(c_notation->PublicID) : Qnil); + rb_constructor_args[2] = (c_notation->SystemID ? NOKOGIRI_STR_NEW2(c_notation->SystemID) : Qnil); + + cNokogiriXmlNotation = rb_const_get_at(mNokogiriXml, rb_intern("Notation")); + rb_notation = rb_class_new_instance(3, rb_constructor_args, cNokogiriXmlNotation); + + rb_hash_aset(rb_hash, NOKOGIRI_STR_NEW2(name), rb_notation); +} + +static void +element_copier(void *c_node_ptr, void *rb_hash_ptr, const xmlChar *c_name) +{ + VALUE rb_hash = (VALUE)rb_hash_ptr; + xmlNodePtr c_node = (xmlNodePtr)c_node_ptr; + + VALUE rb_node = noko_xml_node_wrap(Qnil, c_node); + + rb_hash_aset(rb_hash, NOKOGIRI_STR_NEW2(c_name), rb_node); +} + +/* + * call-seq: + * entities + * + * Get a hash of the elements for this DTD. + */ +static VALUE +entities(VALUE self) +{ + xmlDtdPtr dtd; + VALUE hash; + + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + if (!dtd->entities) { return Qnil; } + + hash = rb_hash_new(); + + xmlHashScan((xmlHashTablePtr)dtd->entities, element_copier, (void *)hash); + + return hash; +} + +/* + * call-seq: + * notations() → Hash + * + * [Returns] All the notations for this DTD in a Hash of Notation +name+ to Notation. + */ +static VALUE +notations(VALUE self) +{ + xmlDtdPtr dtd; + VALUE hash; + + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + if (!dtd->notations) { return Qnil; } + + hash = rb_hash_new(); + + xmlHashScan((xmlHashTablePtr)dtd->notations, notation_copier, (void *)hash); + + return hash; +} + +/* + * call-seq: + * attributes + * + * Get a hash of the attributes for this DTD. + */ +static VALUE +attributes(VALUE self) +{ + xmlDtdPtr dtd; + VALUE hash; + + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + hash = rb_hash_new(); + + if (!dtd->attributes) { return hash; } + + xmlHashScan((xmlHashTablePtr)dtd->attributes, element_copier, (void *)hash); + + return hash; +} + +/* + * call-seq: + * elements + * + * Get a hash of the elements for this DTD. + */ +static VALUE +elements(VALUE self) +{ + xmlDtdPtr dtd; + VALUE hash; + + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + if (!dtd->elements) { return Qnil; } + + hash = rb_hash_new(); + + xmlHashScan((xmlHashTablePtr)dtd->elements, element_copier, (void *)hash); + + return hash; +} + +/* + * call-seq: + * validate(document) + * + * Validate +document+ returning a list of errors + */ +static VALUE +validate(VALUE self, VALUE document) +{ + xmlDocPtr doc; + xmlDtdPtr dtd; + xmlValidCtxtPtr ctxt; + VALUE error_list; + + Noko_Node_Get_Struct(self, xmlDtd, dtd); + doc = noko_xml_document_unwrap(document); + error_list = rb_ary_new(); + + ctxt = xmlNewValidCtxt(); + + xmlSetStructuredErrorFunc((void *)error_list, noko__error_array_pusher); + + xmlValidateDtd(ctxt, doc, dtd); + + xmlSetStructuredErrorFunc(NULL, NULL); + + xmlFreeValidCtxt(ctxt); + + return error_list; +} + +/* + * call-seq: + * system_id + * + * Get the System ID for this DTD + */ +static VALUE +system_id(VALUE self) +{ + xmlDtdPtr dtd; + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + if (!dtd->SystemID) { return Qnil; } + + return NOKOGIRI_STR_NEW2(dtd->SystemID); +} + +/* + * call-seq: + * external_id + * + * Get the External ID for this DTD + */ +static VALUE +external_id(VALUE self) +{ + xmlDtdPtr dtd; + Noko_Node_Get_Struct(self, xmlDtd, dtd); + + if (!dtd->ExternalID) { return Qnil; } + + return NOKOGIRI_STR_NEW2(dtd->ExternalID); +} + +void +noko_init_xml_dtd(void) +{ + assert(cNokogiriXmlNode); + /* + * Nokogiri::XML::DTD wraps DTD nodes in an XML document + */ + cNokogiriXmlDtd = rb_define_class_under(mNokogiriXml, "DTD", cNokogiriXmlNode); + + rb_define_method(cNokogiriXmlDtd, "notations", notations, 0); + rb_define_method(cNokogiriXmlDtd, "elements", elements, 0); + rb_define_method(cNokogiriXmlDtd, "entities", entities, 0); + rb_define_method(cNokogiriXmlDtd, "validate", validate, 1); + rb_define_method(cNokogiriXmlDtd, "attributes", attributes, 0); + rb_define_method(cNokogiriXmlDtd, "system_id", system_id, 0); + rb_define_method(cNokogiriXmlDtd, "external_id", external_id, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_content.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_content.c new file mode 100644 index 00000000..b4fa884a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_content.c @@ -0,0 +1,131 @@ +#include + +VALUE cNokogiriXmlElementContent; + +static const rb_data_type_t xml_element_content_type = { + .wrap_struct_name = "xmlElementContent", + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * call-seq: + * name → String + * + * [Returns] The content element's +name+ + */ +static VALUE +get_name(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + if (!elem->name) { return Qnil; } + return NOKOGIRI_STR_NEW2(elem->name); +} + +/* + * call-seq: + * type → Integer + * + * [Returns] The content element's +type+. Possible values are +PCDATA+, +ELEMENT+, +SEQ+, or +OR+. + */ +static VALUE +get_type(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + return INT2NUM(elem->type); +} + +/* + * Get the first child. + */ +static VALUE +get_c1(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + if (!elem->c1) { return Qnil; } + return noko_xml_element_content_wrap(rb_iv_get(self, "@document"), elem->c1); +} + +/* + * Get the second child. + */ +static VALUE +get_c2(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + if (!elem->c2) { return Qnil; } + return noko_xml_element_content_wrap(rb_iv_get(self, "@document"), elem->c2); +} + +/* + * call-seq: + * occur → Integer + * + * [Returns] The content element's +occur+ flag. Possible values are +ONCE+, +OPT+, +MULT+ or +PLUS+. + */ +static VALUE +get_occur(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + return INT2NUM(elem->ocur); +} + +/* + * call-seq: + * prefix → String + * + * [Returns] The content element's namespace +prefix+. + */ +static VALUE +get_prefix(VALUE self) +{ + xmlElementContentPtr elem; + TypedData_Get_Struct(self, xmlElementContent, &xml_element_content_type, elem); + + if (!elem->prefix) { return Qnil; } + + return NOKOGIRI_STR_NEW2(elem->prefix); +} + +/* + * create a Nokogiri::XML::ElementContent object around an +element+. + */ +VALUE +noko_xml_element_content_wrap(VALUE rb_document, xmlElementContentPtr c_element_content) +{ + VALUE elem = TypedData_Wrap_Struct( + cNokogiriXmlElementContent, + &xml_element_content_type, + c_element_content + ); + + /* keep a handle on the document for GC marking */ + rb_iv_set(elem, "@document", rb_document); + + return elem; +} + +void +noko_init_xml_element_content(void) +{ + cNokogiriXmlElementContent = rb_define_class_under(mNokogiriXml, "ElementContent", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlElementContent); + + rb_define_method(cNokogiriXmlElementContent, "name", get_name, 0); + rb_define_method(cNokogiriXmlElementContent, "type", get_type, 0); + rb_define_method(cNokogiriXmlElementContent, "occur", get_occur, 0); + rb_define_method(cNokogiriXmlElementContent, "prefix", get_prefix, 0); + + rb_define_private_method(cNokogiriXmlElementContent, "c1", get_c1, 0); + rb_define_private_method(cNokogiriXmlElementContent, "c2", get_c2, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_decl.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_decl.c new file mode 100644 index 00000000..58981d35 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_element_decl.c @@ -0,0 +1,69 @@ +#include + +VALUE cNokogiriXmlElementDecl; + +static ID id_document; + +/* + * call-seq: + * element_type → Integer + * + * The element_type + */ +static VALUE +element_type(VALUE self) +{ + xmlElementPtr node; + Noko_Node_Get_Struct(self, xmlElement, node); + return INT2NUM(node->etype); +} + +/* + * call-seq: + * content → Nokogiri::XML::ElementContent + * + * [Returns] The root of this element declaration's content tree. + */ +static VALUE +content(VALUE self) +{ + xmlElementPtr node; + Noko_Node_Get_Struct(self, xmlElement, node); + + if (!node->content) { return Qnil; } + + return noko_xml_element_content_wrap( + rb_funcall(self, id_document, 0), + node->content + ); +} + +/* + * call-seq: + * prefix → String + * + * [Returns] The namespace +prefix+ for this element declaration. + */ +static VALUE +prefix(VALUE self) +{ + xmlElementPtr node; + Noko_Node_Get_Struct(self, xmlElement, node); + + if (!node->prefix) { return Qnil; } + + return NOKOGIRI_STR_NEW2(node->prefix); +} + +void +noko_init_xml_element_decl(void) +{ + assert(cNokogiriXmlNode); + cNokogiriXmlElementDecl = rb_define_class_under(mNokogiriXml, "ElementDecl", cNokogiriXmlNode); + + rb_define_method(cNokogiriXmlElementDecl, "element_type", element_type, 0); + rb_define_method(cNokogiriXmlElementDecl, "content", content, 0); + rb_define_method(cNokogiriXmlElementDecl, "prefix", prefix, 0); + + id_document = rb_intern("document"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_encoding_handler.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_encoding_handler.c new file mode 100644 index 00000000..09927877 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_encoding_handler.c @@ -0,0 +1,112 @@ +#include + +VALUE cNokogiriEncodingHandler; + +static void +xml_encoding_handler_dealloc(void *data) +{ + /* make sure iconv handlers are cleaned up and freed */ + xmlCharEncodingHandlerPtr c_handler = data; + xmlCharEncCloseFunc(c_handler); +} + +static const rb_data_type_t xml_char_encoding_handler_type = { + .wrap_struct_name = "xmlCharEncodingHandler", + .function = { + .dfree = xml_encoding_handler_dealloc, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + + +/* + * call-seq: Nokogiri::EncodingHandler.[](name) + * + * Get the encoding handler for +name+ + */ +static VALUE +rb_xml_encoding_handler_s_get(VALUE klass, VALUE key) +{ + xmlCharEncodingHandlerPtr handler; + + handler = xmlFindCharEncodingHandler(StringValueCStr(key)); + if (handler) { + return TypedData_Wrap_Struct(klass, &xml_char_encoding_handler_type, handler); + } + + return Qnil; +} + + +/* + * call-seq: Nokogiri::EncodingHandler.delete(name) + * + * Delete the encoding alias named +name+ + */ +static VALUE +rb_xml_encoding_handler_s_delete(VALUE klass, VALUE name) +{ + if (xmlDelEncodingAlias(StringValueCStr(name))) { return Qnil; } + + return Qtrue; +} + + +/* + * call-seq: Nokogiri::EncodingHandler.alias(real_name, alias_name) + * + * Alias encoding handler with name +real_name+ to name +alias_name+ + */ +static VALUE +rb_xml_encoding_handler_s_alias(VALUE klass, VALUE from, VALUE to) +{ + xmlAddEncodingAlias(StringValueCStr(from), StringValueCStr(to)); + + return to; +} + + +/* + * call-seq: Nokogiri::EncodingHandler.clear_aliases! + * + * Remove all encoding aliases. + */ +static VALUE +rb_xml_encoding_handler_s_clear_aliases(VALUE klass) +{ + xmlCleanupEncodingAliases(); + + return klass; +} + + +/* + * call-seq: name + * + * Get the name of this EncodingHandler + */ +static VALUE +rb_xml_encoding_handler_name(VALUE self) +{ + xmlCharEncodingHandlerPtr handler; + + TypedData_Get_Struct(self, xmlCharEncodingHandler, &xml_char_encoding_handler_type, handler); + + return NOKOGIRI_STR_NEW2(handler->name); +} + + +void +noko_init_xml_encoding_handler(void) +{ + cNokogiriEncodingHandler = rb_define_class_under(mNokogiri, "EncodingHandler", rb_cObject); + + rb_undef_alloc_func(cNokogiriEncodingHandler); + + rb_define_singleton_method(cNokogiriEncodingHandler, "[]", rb_xml_encoding_handler_s_get, 1); + rb_define_singleton_method(cNokogiriEncodingHandler, "delete", rb_xml_encoding_handler_s_delete, 1); + rb_define_singleton_method(cNokogiriEncodingHandler, "alias", rb_xml_encoding_handler_s_alias, 2); + rb_define_singleton_method(cNokogiriEncodingHandler, "clear_aliases!", rb_xml_encoding_handler_s_clear_aliases, 0); + + rb_define_method(cNokogiriEncodingHandler, "name", rb_xml_encoding_handler_name, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_decl.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_decl.c new file mode 100644 index 00000000..4b7f4078 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_decl.c @@ -0,0 +1,112 @@ +#include + +VALUE cNokogiriXmlEntityDecl; + +/* + * call-seq: + * original_content + * + * Get the original_content before ref substitution + */ +static VALUE +original_content(VALUE self) +{ + xmlEntityPtr node; + Noko_Node_Get_Struct(self, xmlEntity, node); + + if (!node->orig) { return Qnil; } + + return NOKOGIRI_STR_NEW2(node->orig); +} + +/* + * call-seq: + * content + * + * Get the content + */ +static VALUE +get_content(VALUE self) +{ + xmlEntityPtr node; + Noko_Node_Get_Struct(self, xmlEntity, node); + + if (!node->content) { return Qnil; } + + return NOKOGIRI_STR_NEW(node->content, node->length); +} + +/* + * call-seq: + * entity_type + * + * Get the entity type + */ +static VALUE +entity_type(VALUE self) +{ + xmlEntityPtr node; + Noko_Node_Get_Struct(self, xmlEntity, node); + + return INT2NUM((int)node->etype); +} + +/* + * call-seq: + * external_id + * + * Get the external identifier for PUBLIC + */ +static VALUE +external_id(VALUE self) +{ + xmlEntityPtr node; + Noko_Node_Get_Struct(self, xmlEntity, node); + + if (!node->ExternalID) { return Qnil; } + + return NOKOGIRI_STR_NEW2(node->ExternalID); +} + +/* + * call-seq: + * system_id + * + * Get the URI for a SYSTEM or PUBLIC Entity + */ +static VALUE +system_id(VALUE self) +{ + xmlEntityPtr node; + Noko_Node_Get_Struct(self, xmlEntity, node); + + if (!node->SystemID) { return Qnil; } + + return NOKOGIRI_STR_NEW2(node->SystemID); +} + +void +noko_init_xml_entity_decl(void) +{ + assert(cNokogiriXmlNode); + cNokogiriXmlEntityDecl = rb_define_class_under(mNokogiriXml, "EntityDecl", cNokogiriXmlNode); + + rb_define_method(cNokogiriXmlEntityDecl, "original_content", original_content, 0); + rb_define_method(cNokogiriXmlEntityDecl, "content", get_content, 0); + rb_define_method(cNokogiriXmlEntityDecl, "entity_type", entity_type, 0); + rb_define_method(cNokogiriXmlEntityDecl, "external_id", external_id, 0); + rb_define_method(cNokogiriXmlEntityDecl, "system_id", system_id, 0); + + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("INTERNAL_GENERAL"), + INT2NUM(XML_INTERNAL_GENERAL_ENTITY)); + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("EXTERNAL_GENERAL_PARSED"), + INT2NUM(XML_EXTERNAL_GENERAL_PARSED_ENTITY)); + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("EXTERNAL_GENERAL_UNPARSED"), + INT2NUM(XML_EXTERNAL_GENERAL_UNPARSED_ENTITY)); + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("INTERNAL_PARAMETER"), + INT2NUM(XML_INTERNAL_PARAMETER_ENTITY)); + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("EXTERNAL_PARAMETER"), + INT2NUM(XML_EXTERNAL_PARAMETER_ENTITY)); + rb_const_set(cNokogiriXmlEntityDecl, rb_intern("INTERNAL_PREDEFINED"), + INT2NUM(XML_INTERNAL_PREDEFINED_ENTITY)); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_reference.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_reference.c new file mode 100644 index 00000000..3fcc3e54 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_entity_reference.c @@ -0,0 +1,50 @@ +#include + +VALUE cNokogiriXmlEntityReference; + +/* + * call-seq: + * new(document, content) + * + * Create a new EntityReference element on the +document+ with +name+ + */ +static VALUE +new (int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr xml_doc; + xmlNodePtr node; + VALUE document; + VALUE name; + VALUE rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &document, &name, &rest); + + xml_doc = noko_xml_document_unwrap(document); + + node = xmlNewReference( + xml_doc, + (const xmlChar *)StringValueCStr(name) + ); + + noko_xml_document_pin_node(node); + + rb_node = noko_xml_node_wrap(klass, node); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +void +noko_init_xml_entity_reference(void) +{ + assert(cNokogiriXmlNode); + /* + * EntityReference represents an EntityReference node in an xml document. + */ + cNokogiriXmlEntityReference = rb_define_class_under(mNokogiriXml, "EntityReference", cNokogiriXmlNode); + + rb_define_singleton_method(cNokogiriXmlEntityReference, "new", new, -1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_namespace.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_namespace.c new file mode 100644 index 00000000..b16ad455 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_namespace.c @@ -0,0 +1,181 @@ +#include + +/* + * The lifecycle of a Namespace node is more complicated than other Nodes, for two reasons: + * + * 1. the underlying C structure has a different layout than all the other node structs, with the + * `_private` member where we store a pointer to Ruby object data not being in first position. + * 2. xmlNs structures returned in an xmlNodeset from an XPath query are copies of the document's + * namespaces, and so do not share the same memory lifecycle as everything else in a document. + * + * As a result of 1, you may see special handling of XML_NAMESPACE_DECL node types throughout the + * Nokogiri C code, though I intend to wrap up that logic in ruby_object_{get,set} functions + * shortly. + * + * As a result of 2, you will see we have special handling in this file and in xml_node_set.c to + * carefully manage the memory lifecycle of xmlNs structs to match the Ruby object's GC + * lifecycle. In xml_node_set.c we have local versions of xmlXPathNodeSetDel() and + * xmlXPathFreeNodeSet() that avoid freeing xmlNs structs in the node set. In this file, we decide + * whether or not to call dealloc_namespace() depending on whether the xmlNs struct appears to be + * in an xmlNodeSet (and thus the result of an XPath query) or not. + * + * Yes, this is madness. + */ + +VALUE cNokogiriXmlNamespace ; + +static void +_xml_namespace_dealloc(void *ptr) +{ + /* + * this deallocator is only used for namespace nodes that are part of an xpath + * node set. see noko_xml_namespace_wrap(). + */ + xmlNsPtr ns = ptr; + + if (ns->href) { + xmlFree(DISCARD_CONST_QUAL_XMLCHAR(ns->href)); + } + if (ns->prefix) { + xmlFree(DISCARD_CONST_QUAL_XMLCHAR(ns->prefix)); + } + xmlFree(ns); +} + +static void +_xml_namespace_update_references(void *ptr) +{ + xmlNsPtr ns = ptr; + if (ns->_private) { + ns->_private = (void *)rb_gc_location((VALUE)ns->_private); + } +} + +static const rb_data_type_t xml_ns_type_with_free = { + .wrap_struct_name = "xmlNs (with free)", + .function = { + .dfree = _xml_namespace_dealloc, + .dcompact = _xml_namespace_update_references, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static const rb_data_type_t xml_ns_type_without_free = { + .wrap_struct_name = "xmlNs (without free)", + .function = { + .dcompact = _xml_namespace_update_references, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* + * :call-seq: + * prefix() → String or nil + * + * Return the prefix for this Namespace, or +nil+ if there is no prefix (e.g., default namespace). + * + * *Example* + * + * doc = Nokogiri::XML.parse(<<~XML) + * + * + * + * + * + * XML + * + * doc.root.elements.first.namespace.prefix + * # => nil + * + * doc.root.elements.last.namespace.prefix + * # => "noko" + */ +static VALUE +prefix(VALUE self) +{ + xmlNsPtr ns; + + Noko_Namespace_Get_Struct(self, xmlNs, ns); + if (!ns->prefix) { return Qnil; } + + return NOKOGIRI_STR_NEW2(ns->prefix); +} + +/* + * :call-seq: + * href() → String + * + * Returns the URI reference for this Namespace. + * + * *Example* + * + * doc = Nokogiri::XML.parse(<<~XML) + * + * + * + * + * + * XML + * + * doc.root.elements.first.namespace.href + * # => "http://nokogiri.org/ns/default" + * + * doc.root.elements.last.namespace.href + * # => "http://nokogiri.org/ns/noko" + */ +static VALUE +href(VALUE self) +{ + xmlNsPtr ns; + + Noko_Namespace_Get_Struct(self, xmlNs, ns); + if (!ns->href) { return Qnil; } + + return NOKOGIRI_STR_NEW2(ns->href); +} + +VALUE +noko_xml_namespace_wrap(xmlNsPtr c_namespace, xmlDocPtr c_document) +{ + VALUE rb_namespace; + + if (c_namespace->_private) { + return (VALUE)c_namespace->_private; + } + + if (c_document) { + rb_namespace = TypedData_Wrap_Struct(cNokogiriXmlNamespace, + &xml_ns_type_without_free, + c_namespace); + + if (DOC_RUBY_OBJECT_TEST(c_document)) { + rb_iv_set(rb_namespace, "@document", DOC_RUBY_OBJECT(c_document)); + rb_ary_push(DOC_NODE_CACHE(c_document), rb_namespace); + } + } else { + rb_namespace = TypedData_Wrap_Struct(cNokogiriXmlNamespace, + &xml_ns_type_with_free, + c_namespace); + } + + c_namespace->_private = (void *)rb_namespace; + + return rb_namespace; +} + +VALUE +noko_xml_namespace_wrap_xpath_copy(xmlNsPtr c_namespace) +{ + return noko_xml_namespace_wrap(c_namespace, NULL); +} + +void +noko_init_xml_namespace(void) +{ + cNokogiriXmlNamespace = rb_define_class_under(mNokogiriXml, "Namespace", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlNamespace); + + rb_define_method(cNokogiriXmlNamespace, "prefix", prefix, 0); + rb_define_method(cNokogiriXmlNamespace, "href", href, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node.c new file mode 100644 index 00000000..111e8f7e --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node.c @@ -0,0 +1,2459 @@ +#include + +#include + +// :stopdoc: + +VALUE cNokogiriXmlNode ; +static ID id_decorate, id_decorate_bang; + +typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr); + +static void +_xml_node_mark(void *ptr) +{ + xmlNodePtr node = ptr; + + if (!DOC_RUBY_OBJECT_TEST(node->doc)) { + return; + } + + xmlDocPtr doc = node->doc; + if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) { + if (DOC_RUBY_OBJECT_TEST(doc)) { + rb_gc_mark(DOC_RUBY_OBJECT(doc)); + } + } else if (node->doc->_private) { + rb_gc_mark((VALUE)doc->_private); + } +} + +static void +_xml_node_update_references(void *ptr) +{ + xmlNodePtr node = ptr; + + if (node->_private) { + node->_private = (void *)rb_gc_location((VALUE)node->_private); + } +} + +static const rb_data_type_t xml_node_type = { + .wrap_struct_name = "xmlNode", + .function = { + .dmark = _xml_node_mark, + .dcompact = _xml_node_update_references, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static VALUE +_xml_node_alloc(VALUE klass) +{ + return TypedData_Wrap_Struct(klass, &xml_node_type, NULL); +} + +static void +_xml_node_data_ptr_set(VALUE rb_node, xmlNodePtr c_node) +{ + assert(DATA_PTR(rb_node) == NULL); + assert(c_node->_private == NULL); + + DATA_PTR(rb_node) = c_node; + c_node->_private = (void *)rb_node; + + return; +} + +static void +relink_namespace(xmlNodePtr reparented) +{ + xmlNodePtr child; + xmlAttrPtr attr; + + if (reparented->type != XML_ATTRIBUTE_NODE && + reparented->type != XML_ELEMENT_NODE) { return; } + + if (reparented->ns == NULL || reparented->ns->prefix == NULL) { + xmlNsPtr ns = NULL; + xmlChar *name = NULL, *prefix = NULL; + + name = xmlSplitQName2(reparented->name, &prefix); + + if (reparented->type == XML_ATTRIBUTE_NODE) { + if (prefix == NULL || strcmp((char *)prefix, XMLNS_PREFIX) == 0) { + xmlFree(name); + xmlFree(prefix); + return; + } + } + + ns = xmlSearchNs(reparented->doc, reparented, prefix); + + if (ns != NULL) { + xmlNodeSetName(reparented, name); + xmlSetNs(reparented, ns); + } + + xmlFree(name); + xmlFree(prefix); + } + + /* Avoid segv when relinking against unlinked nodes. */ + if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; } + + /* Make sure that our reparented node has the correct namespaces */ + if (!reparented->ns && + (reparented->doc != (xmlDocPtr)reparented->parent) && + (rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) { + xmlSetNs(reparented, reparented->parent->ns); + } + + /* Search our parents for an existing definition */ + if (reparented->nsDef) { + xmlNsPtr curr = reparented->nsDef; + xmlNsPtr prev = NULL; + + while (curr) { + xmlNsPtr ns = xmlSearchNsByHref( + reparented->doc, + reparented->parent, + curr->href + ); + /* If we find the namespace is already declared, remove it from this + * definition list. */ + if (ns && ns != curr && xmlStrEqual(ns->prefix, curr->prefix)) { + if (prev) { + prev->next = curr->next; + } else { + reparented->nsDef = curr->next; + } + noko_xml_document_pin_namespace(curr, reparented->doc); + } else { + prev = curr; + } + curr = curr->next; + } + } + + /* + * Search our parents for an existing definition of current namespace, + * because the definition it's pointing to may have just been removed nsDef. + * + * And although that would technically probably be OK, I'd feel better if we + * referred to a namespace that's still present in a node's nsDef somewhere + * in the doc. + */ + if (reparented->ns) { + xmlNsPtr ns = xmlSearchNs(reparented->doc, reparented, reparented->ns->prefix); + if (ns + && ns != reparented->ns + && xmlStrEqual(ns->prefix, reparented->ns->prefix) + && xmlStrEqual(ns->href, reparented->ns->href) + ) { + xmlSetNs(reparented, ns); + } + } + + /* Only walk all children if there actually is a namespace we need to */ + /* reparent. */ + if (NULL == reparented->ns) { return; } + + /* When a node gets reparented, walk its children to make sure that */ + /* their namespaces are reparented as well. */ + child = reparented->children; + while (NULL != child) { + relink_namespace(child); + child = child->next; + } + + if (reparented->type == XML_ELEMENT_NODE) { + attr = reparented->properties; + while (NULL != attr) { + relink_namespace((xmlNodePtr)attr); + attr = attr->next; + } + } +} + + +/* internal function meant to wrap xmlReplaceNode + and fix some issues we have with libxml2 merging nodes */ +static xmlNodePtr +xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node) +{ + xmlNodePtr retval ; + + retval = xmlReplaceNode(pivot, new_node) ; + + if (retval == pivot) { + retval = new_node ; /* return semantics for reparent_node_with */ + } + + /* work around libxml2 issue: https://bugzilla.gnome.org/show_bug.cgi?id=615612 */ + if (retval && retval->type == XML_TEXT_NODE) { + if (retval->prev && retval->prev->type == XML_TEXT_NODE) { + retval = xmlTextMerge(retval->prev, retval); + } + if (retval->next && retval->next->type == XML_TEXT_NODE) { + retval = xmlTextMerge(retval, retval->next); + } + } + + return retval ; +} + + +static void +raise_if_ancestor_of_self(xmlNodePtr self) +{ + for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) { + if (self == ancestor) { + rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name); + } + } +} + + +static VALUE +reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf) +{ + VALUE reparented_obj ; + xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ; + int original_ns_prefix_is_default = 0 ; + + if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) { + rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node"); + } + if (rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) { + rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node"); + } + + Noko_Node_Get_Struct(reparentee_obj, xmlNode, reparentee); + Noko_Node_Get_Struct(pivot_obj, xmlNode, pivot); + + /* + * Check if nodes given are appropriate to have a parent-child + * relationship, based on the DOM specification. + * + * cf. http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-1590626202 + */ + if (prf == xmlAddChild) { + parent = pivot; + } else { + parent = pivot->parent; + } + + if (parent) { + switch (parent->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + switch (reparentee->type) { + case XML_ELEMENT_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + /* + * The DOM specification says no to adding text-like nodes + * directly to a document, but we allow it for compatibility. + */ + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } + break; + case XML_DOCUMENT_FRAG_NODE: + case XML_ENTITY_REF_NODE: + case XML_ELEMENT_NODE: + switch (reparentee->type) { + case XML_ELEMENT_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } + break; + case XML_ATTRIBUTE_NODE: + switch (reparentee->type) { + case XML_TEXT_NODE: + case XML_ENTITY_REF_NODE: + goto ok; + default: + break; + } + break; + case XML_TEXT_NODE: + /* + * xmlAddChild() breaks the DOM specification in that it allows + * adding a text node to another, in which case text nodes are + * coalesced, but since our JRuby version does not support such + * operation, we should inhibit it. + */ + break; + default: + break; + } + + rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj)); + } + +ok: + original_reparentee = reparentee; + + if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) { + /* + * if the reparentee is a text node, there's a very good chance it will be + * merged with an adjacent text node after being reparented, and in that case + * libxml will free the underlying C struct. + * + * since we clearly have a ruby object which references the underlying + * memory, we can't let the C struct get freed. let's pickle the original + * reparentee by rooting it; and then we'll reparent a duplicate of the + * node that we don't care about preserving. + * + * alternatively, if the reparentee is from a different document than the + * pivot node, libxml2 is going to get confused about which document's + * "dictionary" the node's strings belong to (this is an otherwise + * uninteresting libxml2 implementation detail). as a result, we cannot + * reparent the actual reparentee, so we reparent a duplicate. + */ + if (reparentee->type == XML_TEXT_NODE && reparentee->_private) { + /* + * additionally, since we know this C struct isn't going to be related to + * a Ruby object anymore, let's break the relationship on this end as + * well. + * + * this is not absolutely necessary unless libxml-ruby is also in effect, + * in which case its global callback `rxml_node_deregisterNode` will try + * to do things to our data. + * + * for more details on this particular (and particularly nasty) edge + * case, see: + * + * https://github.com/sparklemotion/nokogiri/issues/1426 + */ + reparentee->_private = NULL ; + } + + if (reparentee->ns != NULL && reparentee->ns->prefix == NULL) { + original_ns_prefix_is_default = 1; + } + + noko_xml_document_pin_node(reparentee); + + if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) { + rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)"); + } + + if (original_ns_prefix_is_default && reparentee->ns != NULL && reparentee->ns->prefix != NULL) { + /* + * issue #391, where new node's prefix may become the string "default" + * see libxml2 tree.c xmlNewReconciliedNs which implements this behavior. + */ + xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix)); + reparentee->ns->prefix = NULL; + } + } + + xmlUnlinkNode(original_reparentee); + + if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling && prf != xmlAddChild + && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) { + /* + * libxml merges text nodes in a right-to-left fashion, meaning that if + * there are two text nodes who would be adjacent, the right (or following, + * or next) node will be merged into the left (or preceding, or previous) + * node. + * + * and by "merged" I mean the string contents will be concatenated onto the + * left node's contents, and then the node will be freed. + * + * which means that if we have a ruby object wrapped around the right node, + * its memory would be freed out from under it. + * + * so, we detect this edge case and unlink-and-root the text node before it gets + * merged. then we dup the node and insert that duplicate back into the + * document where the real node was. + * + * yes, this is totally lame. + */ + next_text = pivot->next ; + new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ; + + xmlUnlinkNode(next_text); + noko_xml_document_pin_node(next_text); + + xmlAddNextSibling(pivot, new_next_text); + } + + if (!(reparented = (*prf)(pivot, reparentee))) { + rb_raise(rb_eRuntimeError, "Could not reparent node"); + } + + /* + * make sure the ruby object is pointed at the just-reparented node, which + * might be a duplicate (see above) or might be the result of merging + * adjacent text nodes. + */ + DATA_PTR(reparentee_obj) = reparented ; + reparented_obj = noko_xml_node_wrap(Qnil, reparented); + + rb_funcall(reparented_obj, id_decorate_bang, 0); + + /* if we've created a cycle, raise an exception */ + raise_if_ancestor_of_self(reparented); + + relink_namespace(reparented); + + return reparented_obj ; +} + +// :startdoc: + +/* + * :call-seq: + * add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace + * add_namespace(prefix, href) → Nokogiri::XML::Namespace + * + * :category: Manipulating Document Structure + * + * Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had + * included an attribute "xmlns:prefix=href". + * + * A default namespace definition for this node can be added by passing +nil+ for +prefix+. + * + * [Parameters] + * - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl] + * - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces] + * + * [Returns] The new Nokogiri::XML::Namespace + * + * *Example:* adding a non-default namespace definition + * + * doc = Nokogiri::XML("") + * inventory = doc.at_css("inventory") + * inventory.add_namespace_definition("automobile", "http://alices-autos.com/") + * inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/") + * inventory.add_child("Michelin model XGV, size 75R") + * doc.to_xml + * # => "\n" + + * # "\n" + + * # " \n" + + * # " Michelin model XGV, size 75R\n" + + * # " \n" + + * # "\n" + * + * *Example:* adding a default namespace definition + * + * doc = Nokogiri::XML("Michelin model XGV, size 75R") + * doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/") + * doc.to_xml + * # => "\n" + + * # "\n" + + * # " \n" + + * # " Michelin model XGV, size 75R\n" + + * # " \n" + + * # "\n" + * + */ +static VALUE +rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href) +{ + xmlNodePtr c_node, element; + xmlNsPtr c_namespace; + const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix)); + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + element = c_node ; + + c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix); + + if (!c_namespace) { + if (c_node->type != XML_ELEMENT_NODE) { + element = c_node->parent; + } + c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix); + } + + if (!c_namespace) { + return Qnil ; + } + + if (NIL_P(rb_prefix) || c_node != element) { + xmlSetNs(c_node, c_namespace); + } + + return noko_xml_namespace_wrap(c_namespace, c_node->doc); +} + + +/* + * :call-seq: attribute(name) → Nokogiri::XML::Attr + * + * :category: Working With Node Attributes + * + * [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+. + * + * ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is + * used to find a matching attribute. In case of a simple name collision, only one of the matching + * attributes will be returned. In this case, you will need to use #attribute_with_ns. + * + * *Example:* + * + * doc = Nokogiri::XML("") + * child = doc.at_css("child") + * child.attribute("size") # => # + * child.attribute("class") # => # + * + * *Example* showing that namespaced attributes will not be returned: + * + * ⚠ Note that only one of the two matching attributes is returned. + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * EOF + * doc.at_css("child").attribute("size") + * # => #(Attr:0x550 { + * # name = "size", + * # namespace = #(Namespace:0x564 { + * # prefix = "width", + * # href = "http://example.com/widths" + * # }), + * # value = "broad" + * # }) + */ +static VALUE +rb_xml_node_attribute(VALUE self, VALUE name) +{ + xmlNodePtr node; + xmlAttrPtr prop; + Noko_Node_Get_Struct(self, xmlNode, node); + prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name)); + + if (! prop) { return Qnil; } + return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop); +} + + +/* + * :call-seq: attribute_nodes() → Array + * + * :category: Working With Node Attributes + * + * [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node. + * + * Note that this is the preferred alternative to #attributes when the simple + * (non-namespace-prefixed) attribute names may collide. + * + * *Example:* + * + * Contrast this with the colliding-name example from #attributes. + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * EOF + * doc.at_css("child").attribute_nodes + * # => [#(Attr:0x550 { + * # name = "size", + * # namespace = #(Namespace:0x564 { + * # prefix = "width", + * # href = "http://example.com/widths" + * # }), + * # value = "broad" + * # }), + * # #(Attr:0x578 { + * # name = "size", + * # namespace = #(Namespace:0x58c { + * # prefix = "height", + * # href = "http://example.com/heights" + * # }), + * # value = "tall" + * # })] + */ +static VALUE +rb_xml_node_attribute_nodes(VALUE rb_node) +{ + xmlNodePtr c_node; + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + return noko_xml_node_attrs(c_node); +} + + +/* + * :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr + * + * :category: Working With Node Attributes + * + * [Returns] + * Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+. + * + * [Parameters] + * - +name+ (String): the simple (non-namespace-prefixed) name of the attribute + * - +namespace+ (String): the URI of the attribute's namespace + * + * See related: #attribute + * + * *Example:* + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * EOF + * doc.at_css("child").attribute_with_ns("size", "http://example.com/widths") + * # => #(Attr:0x550 { + * # name = "size", + * # namespace = #(Namespace:0x564 { + * # prefix = "width", + * # href = "http://example.com/widths" + * # }), + * # value = "broad" + * # }) + * doc.at_css("child").attribute_with_ns("size", "http://example.com/heights") + * # => #(Attr:0x578 { + * # name = "size", + * # namespace = #(Namespace:0x58c { + * # prefix = "height", + * # href = "http://example.com/heights" + * # }), + * # value = "tall" + * # }) + */ +static VALUE +rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace) +{ + xmlNodePtr node; + xmlAttrPtr prop; + Noko_Node_Get_Struct(self, xmlNode, node); + prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name), + NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace)); + + if (! prop) { return Qnil; } + return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop); +} + + + +/* + * call-seq: blank? → Boolean + * + * [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+. + * + * *Example:* + * + * Nokogiri("").root.child.blank? # => false + * Nokogiri("\t \n").root.child.blank? # => true + * Nokogiri("").root.child.blank? # => true + * Nokogiri("not-blank").root.child + * .tap { |n| n.content = "" }.blank # => true + */ +static VALUE +rb_xml_node_blank_eh(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ; +} + + +/* + * :call-seq: child() → Nokogiri::XML::Node + * + * :category: Traversing Document Structure + * + * [Returns] First of this node's children, or +nil+ if there are no children + * + * This is a convenience method and is equivalent to: + * + * node.children.first + * + * See related: #children + */ +static VALUE +rb_xml_node_child(VALUE self) +{ + xmlNodePtr node, child; + Noko_Node_Get_Struct(self, xmlNode, node); + + child = node->children; + if (!child) { return Qnil; } + + return noko_xml_node_wrap(Qnil, child); +} + + +/* + * :call-seq: children() → Nokogiri::XML::NodeSet + * + * :category: Traversing Document Structure + * + * [Returns] Nokogiri::XML::NodeSet containing this node's children. + */ +static VALUE +rb_xml_node_children(VALUE self) +{ + xmlNodePtr node; + xmlNodePtr child; + xmlNodeSetPtr set; + VALUE document; + VALUE node_set; + + Noko_Node_Get_Struct(self, xmlNode, node); + + child = node->children; + set = xmlXPathNodeSetCreate(child); + + document = DOC_RUBY_OBJECT(node->doc); + + if (!child) { return noko_xml_node_set_wrap(set, document); } + + child = child->next; + while (NULL != child) { + xmlXPathNodeSetAddUnique(set, child); + child = child->next; + } + + node_set = noko_xml_node_set_wrap(set, document); + + return node_set; +} + + +/* + * :call-seq: + * content() → String + * inner_text() → String + * text() → String + * to_str() → String + * + * [Returns] + * Contents of all the text nodes in this node's subtree, concatenated together into a single + * String. + * + * ⚠ Note that entities will _always_ be expanded in the returned String. + * + * See related: #inner_html + * + * *Example* of how entities are handled: + * + * Note that < becomes < in the returned String. + * + * doc = Nokogiri::XML.fragment("a < b") + * doc.at_css("child").content + * # => "a < b" + * + * *Example* of how a subtree is handled: + * + * Note that the tags are omitted and only the text node contents are returned, + * concatenated into a single string. + * + * doc = Nokogiri::XML.fragment("first second") + * doc.at_css("child").content + * # => "first second" + */ +static VALUE +rb_xml_node_content(VALUE self) +{ + xmlNodePtr node; + xmlChar *content; + + Noko_Node_Get_Struct(self, xmlNode, node); + + content = xmlNodeGetContent(node); + if (content) { + VALUE rval = NOKOGIRI_STR_NEW2(content); + xmlFree(content); + return rval; + } + return Qnil; +} + + +/* + * :call-seq: document() → Nokogiri::XML::Document + * + * :category: Traversing Document Structure + * + * [Returns] Parent Nokogiri::XML::Document for this node + */ +static VALUE +rb_xml_node_document(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + return DOC_RUBY_OBJECT(node->doc); +} + +/* + * :call-seq: pointer_id() → Integer + * + * [Returns] + * A unique id for this node based on the internal memory structures. This method is used by #== + * to determine node identity. + */ +static VALUE +rb_xml_node_pointer_id(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + + return rb_uint2inum((uintptr_t)(node)); +} + +/* + * :call-seq: encode_special_chars(string) → String + * + * Encode any special characters in +string+ + */ +static VALUE +encode_special_chars(VALUE self, VALUE string) +{ + xmlNodePtr node; + xmlChar *encoded; + VALUE encoded_str; + + Noko_Node_Get_Struct(self, xmlNode, node); + encoded = xmlEncodeSpecialChars( + node->doc, + (const xmlChar *)StringValueCStr(string) + ); + + encoded_str = NOKOGIRI_STR_NEW2(encoded); + xmlFree(encoded); + + return encoded_str; +} + +/* + * :call-seq: + * create_internal_subset(name, external_id, system_id) + * + * Create the internal subset of a document. + * + * doc.create_internal_subset("chapter", "-//OASIS//DTD DocBook XML//EN", "chapter.dtd") + * # => + * + * doc.create_internal_subset("chapter", nil, "chapter.dtd") + * # => + */ +static VALUE +create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id) +{ + xmlNodePtr node; + xmlDocPtr doc; + xmlDtdPtr dtd; + + Noko_Node_Get_Struct(self, xmlNode, node); + + doc = node->doc; + + if (xmlGetIntSubset(doc)) { + rb_raise(rb_eRuntimeError, "Document already has an internal subset"); + } + + dtd = xmlCreateIntSubset( + doc, + NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name), + NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id), + NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id) + ); + + if (!dtd) { return Qnil; } + + return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd); +} + +/* + * :call-seq: + * create_external_subset(name, external_id, system_id) + * + * Create an external subset + */ +static VALUE +create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id) +{ + xmlNodePtr node; + xmlDocPtr doc; + xmlDtdPtr dtd; + + Noko_Node_Get_Struct(self, xmlNode, node); + + doc = node->doc; + + if (doc->extSubset) { + rb_raise(rb_eRuntimeError, "Document already has an external subset"); + } + + dtd = xmlNewDtd( + doc, + NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name), + NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id), + NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id) + ); + + if (!dtd) { return Qnil; } + + return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd); +} + +/* + * :call-seq: + * external_subset() + * + * Get the external subset + */ +static VALUE +external_subset(VALUE self) +{ + xmlNodePtr node; + xmlDocPtr doc; + xmlDtdPtr dtd; + + Noko_Node_Get_Struct(self, xmlNode, node); + + if (!node->doc) { return Qnil; } + + doc = node->doc; + dtd = doc->extSubset; + + if (!dtd) { return Qnil; } + + return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd); +} + +/* + * :call-seq: + * internal_subset() + * + * Get the internal subset + */ +static VALUE +internal_subset(VALUE self) +{ + xmlNodePtr node; + xmlDocPtr doc; + xmlDtdPtr dtd; + + Noko_Node_Get_Struct(self, xmlNode, node); + + if (!node->doc) { return Qnil; } + + doc = node->doc; + dtd = xmlGetIntSubset(doc); + + if (!dtd) { return Qnil; } + + return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd); +} + +/* :nodoc: */ +static VALUE +rb_xml_node_initialize_copy_with_args(VALUE rb_self, VALUE rb_other, VALUE rb_level, VALUE rb_new_parent_doc) +{ + xmlNodePtr c_self, c_other; + int c_level; + xmlDocPtr c_new_parent_doc; + VALUE rb_node_cache; + + Noko_Node_Get_Struct(rb_other, xmlNode, c_other); + c_level = (int)NUM2INT(rb_level); + c_new_parent_doc = noko_xml_document_unwrap(rb_new_parent_doc); + + c_self = xmlDocCopyNode(c_other, c_new_parent_doc, c_level); + if (c_self == NULL) { return Qnil; } + + _xml_node_data_ptr_set(rb_self, c_self); + noko_xml_document_pin_node(c_self); + + rb_node_cache = DOC_NODE_CACHE(c_new_parent_doc); + rb_ary_push(rb_node_cache, rb_self); + rb_funcall(rb_new_parent_doc, id_decorate, 1, rb_self); + + return rb_self; +} + +/* + * :call-seq: + * unlink() → self + * + * Unlink this node from its current context. + */ +static VALUE +unlink_node(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + xmlUnlinkNode(node); + noko_xml_document_pin_node(node); + return self; +} + + +/* + * call-seq: + * next_sibling + * + * Returns the next sibling node + */ +static VALUE +next_sibling(VALUE self) +{ + xmlNodePtr node, sibling; + Noko_Node_Get_Struct(self, xmlNode, node); + + sibling = node->next; + if (!sibling) { return Qnil; } + + return noko_xml_node_wrap(Qnil, sibling) ; +} + +/* + * call-seq: + * previous_sibling + * + * Returns the previous sibling node + */ +static VALUE +previous_sibling(VALUE self) +{ + xmlNodePtr node, sibling; + Noko_Node_Get_Struct(self, xmlNode, node); + + sibling = node->prev; + if (!sibling) { return Qnil; } + + return noko_xml_node_wrap(Qnil, sibling); +} + +/* + * call-seq: + * next_element + * + * Returns the next Nokogiri::XML::Element type sibling node. + */ +static VALUE +next_element(VALUE self) +{ + xmlNodePtr node, sibling; + Noko_Node_Get_Struct(self, xmlNode, node); + + sibling = xmlNextElementSibling(node); + if (!sibling) { return Qnil; } + + return noko_xml_node_wrap(Qnil, sibling); +} + +/* + * call-seq: + * previous_element + * + * Returns the previous Nokogiri::XML::Element type sibling node. + */ +static VALUE +previous_element(VALUE self) +{ + xmlNodePtr node, sibling; + Noko_Node_Get_Struct(self, xmlNode, node); + + sibling = xmlPreviousElementSibling(node); + if (!sibling) { return Qnil; } + + return noko_xml_node_wrap(Qnil, sibling); +} + +/* :nodoc: */ +static VALUE +replace(VALUE self, VALUE new_node) +{ + VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper); + + xmlNodePtr pivot; + Noko_Node_Get_Struct(self, xmlNode, pivot); + noko_xml_document_pin_node(pivot); + + return reparent; +} + +/* + * :call-seq: + * element_children() → NodeSet + * elements() → NodeSet + * + * [Returns] + * The node's child elements as a NodeSet. Only children that are elements will be returned, which + * notably excludes Text nodes. + * + * *Example:* + * + * Note that #children returns the Text node "hello" while #element_children does not. + * + * div = Nokogiri::HTML5("
helloworld").at_css("div") + * div.element_children + * # => [#]>] + * div.children + * # => [#, + * # #]>] + */ +static VALUE +rb_xml_node_element_children(VALUE self) +{ + xmlNodePtr node; + xmlNodePtr child; + xmlNodeSetPtr set; + VALUE document; + VALUE node_set; + + Noko_Node_Get_Struct(self, xmlNode, node); + + child = xmlFirstElementChild(node); + set = xmlXPathNodeSetCreate(child); + + document = DOC_RUBY_OBJECT(node->doc); + + if (!child) { return noko_xml_node_set_wrap(set, document); } + + child = xmlNextElementSibling(child); + while (NULL != child) { + xmlXPathNodeSetAddUnique(set, child); + child = xmlNextElementSibling(child); + } + + node_set = noko_xml_node_set_wrap(set, document); + + return node_set; +} + +/* + * :call-seq: + * first_element_child() → Node + * + * [Returns] The first child Node that is an element. + * + * *Example:* + * + * Note that the "hello" child, which is a Text node, is skipped and the element is + * returned. + * + * div = Nokogiri::HTML5("
helloworld").at_css("div") + * div.first_element_child + * # => #(Element:0x3c { name = "span", children = [ #(Text "world")] }) + */ +static VALUE +rb_xml_node_first_element_child(VALUE self) +{ + xmlNodePtr node, child; + Noko_Node_Get_Struct(self, xmlNode, node); + + child = xmlFirstElementChild(node); + if (!child) { return Qnil; } + + return noko_xml_node_wrap(Qnil, child); +} + +/* + * :call-seq: + * last_element_child() → Node + * + * [Returns] The last child Node that is an element. + * + * *Example:* + * + * Note that the "hello" child, which is a Text node, is skipped and the yes + * element is returned. + * + * div = Nokogiri::HTML5("
noyesskip
").at_css("div") + * div.last_element_child + * # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] }) + */ +static VALUE +rb_xml_node_last_element_child(VALUE self) +{ + xmlNodePtr node, child; + Noko_Node_Get_Struct(self, xmlNode, node); + + child = xmlLastElementChild(node); + if (!child) { return Qnil; } + + return noko_xml_node_wrap(Qnil, child); +} + +/* + * call-seq: + * key?(attribute) + * + * Returns true if +attribute+ is set + */ +static VALUE +key_eh(VALUE self, VALUE attribute) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + if (xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) { + return Qtrue; + } + return Qfalse; +} + +/* + * call-seq: + * namespaced_key?(attribute, namespace) + * + * Returns true if +attribute+ is set with +namespace+ + */ +static VALUE +namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + if (xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute), + NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) { + return Qtrue; + } + return Qfalse; +} + +/* + * call-seq: + * []=(property, value) + * + * Set the +property+ to +value+ + */ +static VALUE +set(VALUE self, VALUE property, VALUE value) +{ + xmlNodePtr node, cur; + xmlAttrPtr prop; + Noko_Node_Get_Struct(self, xmlNode, node); + + /* If a matching attribute node already exists, then xmlSetProp will destroy + * the existing node's children. However, if Nokogiri has a node object + * pointing to one of those children, we are left with a broken reference. + * + * We can avoid this by unlinking these nodes first. + */ + if (node->type != XML_ELEMENT_NODE) { + return (Qnil); + } + prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property)); + if (prop && prop->children) { + for (cur = prop->children; cur; cur = cur->next) { + if (cur->_private) { + noko_xml_document_pin_node(cur); + xmlUnlinkNode(cur); + } + } + } + + xmlSetProp(node, (xmlChar *)StringValueCStr(property), + (xmlChar *)StringValueCStr(value)); + + return value; +} + +/* + * call-seq: + * get(attribute) + * + * Get the value for +attribute+ + */ +static VALUE +get(VALUE self, VALUE rattribute) +{ + xmlNodePtr node; + xmlChar *value = 0; + VALUE rvalue; + xmlChar *colon; + xmlChar *attribute, *attr_name, *prefix; + xmlNsPtr ns; + + if (NIL_P(rattribute)) { return Qnil; } + + Noko_Node_Get_Struct(self, xmlNode, node); + attribute = xmlCharStrdup(StringValueCStr(rattribute)); + + colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':')); + if (colon) { + /* split the attribute string into separate prefix and name by + * null-terminating the prefix at the colon */ + prefix = attribute; + attr_name = colon + 1; + (*colon) = 0; + + ns = xmlSearchNs(node->doc, node, prefix); + if (ns) { + value = xmlGetNsProp(node, attr_name, ns->href); + } else { + value = xmlGetProp(node, (xmlChar *)StringValueCStr(rattribute)); + } + } else { + value = xmlGetNoNsProp(node, attribute); + } + + xmlFree((void *)attribute); + if (!value) { return Qnil; } + + rvalue = NOKOGIRI_STR_NEW2(value); + xmlFree((void *)value); + + return rvalue ; +} + +/* + * call-seq: + * set_namespace(namespace) + * + * Set the namespace to +namespace+ + */ +static VALUE +set_namespace(VALUE self, VALUE namespace) +{ + xmlNodePtr node; + xmlNsPtr ns = NULL; + + Noko_Node_Get_Struct(self, xmlNode, node); + + if (!NIL_P(namespace)) { + Noko_Namespace_Get_Struct(namespace, xmlNs, ns); + } + + xmlSetNs(node, ns); + + return self; +} + +/* + * :call-seq: + * namespace() → Namespace + * + * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace. + * + * *Example:* + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * + * + * EOF + * doc.at_xpath("//first").namespace + * # => nil + * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace + * # => #(Namespace:0x3c { href = "http://example.com/child" }) + * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace + * # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" }) + */ +static VALUE +rb_xml_node_namespace(VALUE rb_node) +{ + xmlNodePtr c_node ; + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + if (c_node->ns) { + return noko_xml_namespace_wrap(c_node->ns, c_node->doc); + } + + return Qnil ; +} + +/* + * :call-seq: + * namespace_definitions() → Array + * + * [Returns] + * Namespaces that are defined directly on this node, as an Array of Namespace objects. The array + * will be empty if no namespaces are defined on this node. + * + * *Example:* + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * + * + * EOF + * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions + * # => [] + * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions + * # => [#(Namespace:0x3c { href = "http://example.com/child" }), + * # #(Namespace:0x50 { + * # prefix = "unused", + * # href = "http://example.com/unused" + * # })] + * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions + * # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })] + */ +static VALUE +namespace_definitions(VALUE rb_node) +{ + /* this code in the mode of xmlHasProp() */ + xmlNodePtr c_node ; + xmlNsPtr c_namespace; + VALUE definitions = rb_ary_new(); + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + c_namespace = c_node->nsDef; + if (!c_namespace) { + return definitions; + } + + while (c_namespace != NULL) { + rb_ary_push(definitions, noko_xml_namespace_wrap(c_namespace, c_node->doc)); + c_namespace = c_namespace->next; + } + + return definitions; +} + +/* + * :call-seq: + * namespace_scopes() → Array + * + * [Returns] Array of all the Namespaces on this node and its ancestors. + * + * See also #namespaces + * + * *Example:* + * + * doc = Nokogiri::XML(<<~EOF) + * + * + * + * + * + * EOF + * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes + * # => [#(Namespace:0x3c { href = "http://example.com/root" }), + * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })] + * doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes + * # => [#(Namespace:0x64 { href = "http://example.com/child" }), + * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })] + * doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes + * # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }), + * # #(Namespace:0x3c { href = "http://example.com/root" }), + * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })] + */ +static VALUE +rb_xml_node_namespace_scopes(VALUE rb_node) +{ + xmlNodePtr c_node ; + xmlNsPtr *namespaces; + VALUE scopes = rb_ary_new(); + int j; + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + namespaces = xmlGetNsList(c_node->doc, c_node); + if (!namespaces) { + return scopes; + } + + for (j = 0 ; namespaces[j] != NULL ; ++j) { + rb_ary_push(scopes, noko_xml_namespace_wrap(namespaces[j], c_node->doc)); + } + + xmlFree(namespaces); + return scopes; +} + +/* + * call-seq: + * node_type + * + * Get the type for this Node + */ +static VALUE +node_type(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + return INT2NUM(node->type); +} + +/* + * call-seq: + * native_content=(input) + * + * Set the content of this node to +input+. + * + * [Parameters] + * - +input+ (String) The new content for this node. + * + * ⚠ This method behaves differently depending on the node type. For Text, CDATA, Comment, and + * ProcessingInstruction nodes, it treats the input as raw content, which means that the final DOM + * will contain the entity-escaped version of the input (see example below). For Element and Attr + * nodes, it treats the input as parsed content and expects it to be valid markup that is already + * entity-escaped. + * + * 💡 Use Node#content= for a more consistent API across node types. + * + * [Example] + * Note the behavior differences of this method between Text and Element nodes: + * + * doc = Nokogiri::HTML::Document.parse(<<~HTML) + * + * + *
asdf
+ *
asdf
+ * HTML + * + * text_node = doc.at_css("div#first").children.first + * div_node = doc.at_css("div#second") + * + * value = "You & Me" + * + * text_node.native_content = value + * div_node.native_content = value + * + * doc.css("div").to_html + * # => "
You &amp; Me
+ * #
You & Me
" + * + * See also: #content= + */ +static VALUE +set_native_content(VALUE self, VALUE content) +{ + xmlNodePtr node, child, next ; + Noko_Node_Get_Struct(self, xmlNode, node); + + child = node->children; + while (NULL != child) { + next = child->next ; + xmlUnlinkNode(child) ; + noko_xml_document_pin_node(child); + child = next ; + } + + xmlNodeSetContent(node, (xmlChar *)StringValueCStr(content)); + return content; +} + +/* + * call-seq: + * lang= + * + * Set the language of a node, i.e. the values of the xml:lang attribute. + */ +static VALUE +set_lang(VALUE self_rb, VALUE lang_rb) +{ + xmlNodePtr self ; + xmlChar *lang ; + + Noko_Node_Get_Struct(self_rb, xmlNode, self); + lang = (xmlChar *)StringValueCStr(lang_rb); + + xmlNodeSetLang(self, lang); + + return Qnil ; +} + +/* + * call-seq: + * lang + * + * Searches the language of a node, i.e. the values of the xml:lang attribute or + * the one carried by the nearest ancestor. + */ +static VALUE +get_lang(VALUE self_rb) +{ + xmlNodePtr self ; + xmlChar *lang ; + VALUE lang_rb ; + + Noko_Node_Get_Struct(self_rb, xmlNode, self); + + lang = xmlNodeGetLang(self); + if (lang) { + lang_rb = NOKOGIRI_STR_NEW2(lang); + xmlFree(lang); + return lang_rb ; + } + + return Qnil ; +} + +/* :nodoc: */ +static VALUE +add_child(VALUE self, VALUE new_child) +{ + return reparent_node_with(self, new_child, xmlAddChild); +} + +/* + * call-seq: + * parent + * + * Get the parent Node for this Node + */ +static VALUE +get_parent(VALUE self) +{ + xmlNodePtr node, parent; + Noko_Node_Get_Struct(self, xmlNode, node); + + parent = node->parent; + if (!parent) { return Qnil; } + + return noko_xml_node_wrap(Qnil, parent) ; +} + +/* + * call-seq: + * name=(new_name) + * + * Set the name for this Node + */ +static VALUE +set_name(VALUE self, VALUE new_name) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + xmlNodeSetName(node, (xmlChar *)StringValueCStr(new_name)); + return new_name; +} + +/* + * call-seq: + * name + * + * Returns the name for this Node + */ +static VALUE +get_name(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + if (node->name) { + return NOKOGIRI_STR_NEW2(node->name); + } + return Qnil; +} + +/* + * call-seq: + * path + * + * Returns the path associated with this Node + */ +static VALUE +rb_xml_node_path(VALUE rb_node) +{ + xmlNodePtr c_node; + xmlChar *c_path ; + VALUE rval; + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + c_path = xmlGetNodePath(c_node); + if (c_path == NULL) { + // see https://github.com/sparklemotion/nokogiri/issues/2250 + // this behavior is clearly undesirable, but is what libxml <= 2.9.10 returned, and so we + // do this for now to preserve the behavior across libxml2 versions. + rval = NOKOGIRI_STR_NEW2("?"); + } else { + rval = NOKOGIRI_STR_NEW2(c_path); + xmlFree(c_path); + } + + return rval ; +} + +/* :nodoc: */ +static VALUE +add_next_sibling(VALUE self, VALUE new_sibling) +{ + return reparent_node_with(self, new_sibling, xmlAddNextSibling) ; +} + +/* :nodoc: */ +static VALUE +add_previous_sibling(VALUE self, VALUE new_sibling) +{ + return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ; +} + +/* + * call-seq: + * native_write_to(io, encoding, options) + * + * Write this Node to +io+ with +encoding+ and +options+ + */ +static VALUE +native_write_to( + VALUE self, + VALUE io, + VALUE encoding, + VALUE indent_string, + VALUE options +) +{ + xmlNodePtr node; + const char *before_indent; + xmlSaveCtxtPtr savectx; + + Noko_Node_Get_Struct(self, xmlNode, node); + + xmlIndentTreeOutput = 1; + + before_indent = xmlTreeIndentString; + + xmlTreeIndentString = StringValueCStr(indent_string); + + savectx = xmlSaveToIO( + (xmlOutputWriteCallback)noko_io_write, + (xmlOutputCloseCallback)noko_io_close, + (void *)io, + RTEST(encoding) ? StringValueCStr(encoding) : NULL, + (int)NUM2INT(options) + ); + + xmlSaveTree(savectx, node); + xmlSaveClose(savectx); + + xmlTreeIndentString = before_indent; + return io; +} + + +static inline void +output_partial_string(VALUE out, char const *str, size_t length) +{ + if (length) { + rb_enc_str_buf_cat(out, str, (long)length, rb_utf8_encoding()); + } +} + +static inline void +output_char(VALUE out, char ch) +{ + output_partial_string(out, &ch, 1); +} + +static inline void +output_string(VALUE out, char const *str) +{ + output_partial_string(out, str, strlen(str)); +} + +static inline void +output_tagname(VALUE out, xmlNodePtr elem) +{ + // Elements in the HTML, MathML, and SVG namespaces do not use a namespace + // prefix in the HTML syntax. + char const *name = (char const *)elem->name; + xmlNsPtr ns = elem->ns; + if (ns && ns->href && ns->prefix + && strcmp((char const *)ns->href, "http://www.w3.org/1999/xhtml") + && strcmp((char const *)ns->href, "http://www.w3.org/1998/Math/MathML") + && strcmp((char const *)ns->href, "http://www.w3.org/2000/svg")) { + output_string(out, (char const *)elem->ns->prefix); + output_char(out, ':'); + char const *colon = strchr(name, ':'); + if (colon) { + name = colon + 1; + } + } + output_string(out, name); +} + +static inline void +output_attr_name(VALUE out, xmlAttrPtr attr) +{ + xmlNsPtr ns = attr->ns; + char const *name = (char const *)attr->name; + if (ns && ns->href) { + char const *uri = (char const *)ns->href; + char const *localname = strchr(name, ':'); + if (localname) { + ++localname; + } else { + localname = name; + } + + if (!strcmp(uri, "http://www.w3.org/XML/1998/namespace")) { + output_string(out, "xml:"); + name = localname; + } else if (!strcmp(uri, "http://www.w3.org/2000/xmlns/")) { + // xmlns:xmlns -> xmlns + // xmlns:foo -> xmlns:foo + if (strcmp(localname, "xmlns")) { + output_string(out, "xmlns:"); + } + name = localname; + } else if (!strcmp(uri, "http://www.w3.org/1999/xlink")) { + output_string(out, "xlink:"); + name = localname; + } else if (ns->prefix) { + output_string(out, (char const *)ns->prefix); + output_char(out, ':'); + name = localname; + } + } + output_string(out, name); +} + +static void +output_escaped_string(VALUE out, xmlChar const *start, bool attr) +{ + xmlChar const *next = start; + int ch; + + while ((ch = *next) != 0) { + char const *replacement = NULL; + size_t replaced_bytes = 1; + if (ch == '&') { + replacement = "&"; + } else if (ch == 0xC2 && next[1] == 0xA0) { + // U+00A0 NO-BREAK SPACE has the UTF-8 encoding C2 A0. + replacement = " "; + replaced_bytes = 2; + } else if (attr && ch == '"') { + replacement = """; + } else if (!attr && ch == '<') { + replacement = "<"; + } else if (!attr && ch == '>') { + replacement = ">"; + } else { + ++next; + continue; + } + output_partial_string(out, (char const *)start, (size_t)(next - start)); + output_string(out, replacement); + next += replaced_bytes; + start = next; + } + output_partial_string(out, (char const *)start, (size_t)(next - start)); +} + +static bool +should_prepend_newline(xmlNodePtr node) +{ + char const *name = (char const *)node->name; + xmlNodePtr child = node->children; + + if (!name || !child || (strcmp(name, "pre") && strcmp(name, "textarea") && strcmp(name, "listing"))) { + return false; + } + + return child->type == XML_TEXT_NODE && child->content && child->content[0] == '\n'; +} + +static VALUE +rb_prepend_newline(VALUE self) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + return should_prepend_newline(node) ? Qtrue : Qfalse; +} + +static bool +is_one_of(xmlNodePtr node, char const *const *tagnames, size_t num_tagnames) +{ + char const *name = (char const *)node->name; + if (name == NULL) { // fragments don't have a name + return false; + } + + if (node->ns != NULL) { + // if the node has a namespace, it's in a foreign context and is not one of the HTML tags we're + // matching against. + return false; + } + + for (size_t idx = 0; idx < num_tagnames; ++idx) { + if (!strcmp(name, tagnames[idx])) { + return true; + } + } + return false; +} + +static void +output_node( + VALUE out, + xmlNodePtr node, + bool preserve_newline +) +{ + static char const *const VOID_ELEMENTS[] = { + "area", "base", "basefont", "bgsound", "br", "col", "embed", "frame", "hr", + "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr", + }; + + static char const *const UNESCAPED_TEXT_ELEMENTS[] = { + "style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript", + }; + + switch (node->type) { + case XML_ELEMENT_NODE: + // Serialize the start tag. + output_char(out, '<'); + output_tagname(out, node); + + // Add attributes. + for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) { + output_char(out, ' '); + output_node(out, (xmlNodePtr)attr, preserve_newline); + } + output_char(out, '>'); + + // Add children and end tag if element is not void. + if (!is_one_of(node, VOID_ELEMENTS, sizeof VOID_ELEMENTS / sizeof VOID_ELEMENTS[0])) { + if (preserve_newline && should_prepend_newline(node)) { + output_char(out, '\n'); + } + for (xmlNodePtr child = node->children; child; child = child->next) { + output_node(out, child, preserve_newline); + } + output_string(out, "'); + } + break; + + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr attr = (xmlAttrPtr)node; + output_attr_name(out, attr); + if (attr->children) { + output_string(out, "=\""); + xmlChar *value = xmlNodeListGetString(attr->doc, attr->children, 1); + output_escaped_string(out, value, true); + xmlFree(value); + output_char(out, '"'); + } else { + // Output name="" + output_string(out, "=\"\""); + } + } + break; + + case XML_TEXT_NODE: + if (node->parent + && is_one_of(node->parent, UNESCAPED_TEXT_ELEMENTS, + sizeof UNESCAPED_TEXT_ELEMENTS / sizeof UNESCAPED_TEXT_ELEMENTS[0])) { + output_string(out, (char const *)node->content); + } else { + output_escaped_string(out, node->content, false); + } + break; + + case XML_CDATA_SECTION_NODE: + output_string(out, "content); + output_string(out, "]]>"); + break; + + case XML_COMMENT_NODE: + output_string(out, ""); + break; + + case XML_PI_NODE: + output_string(out, "content); + output_char(out, '>'); + break; + + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + output_string(out, "name); + output_string(out, ">"); + break; + + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: + for (xmlNodePtr child = node->children; child; child = child->next) { + output_node(out, child, preserve_newline); + } + break; + + default: + rb_raise(rb_eRuntimeError, "Unsupported document node (%d); this is a bug in Nokogiri", node->type); + break; + } +} + +static VALUE +html_standard_serialize( + VALUE self, + VALUE preserve_newline +) +{ + xmlNodePtr node; + Noko_Node_Get_Struct(self, xmlNode, node); + VALUE output = rb_str_buf_new(4096); + output_node(output, node, RTEST(preserve_newline)); + return output; +} + +/* + * :call-seq: + * line() → Integer + * + * [Returns] The line number of this Node. + * + * --- + * + * ⚠ The CRuby and JRuby implementations differ in important ways! + * + * Semantic differences: + * - The CRuby method reflects the node's line number in the parsed string + * - The JRuby method reflects the node's line number in the final DOM structure after + * corrections have been applied + * + * Performance differences: + * - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time] + * (constant time) + * - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear + * time, where n is the number of nodes before/above the element in the DOM) + * + * If you'd like to help improve the JRuby implementation, please review these issues and reach out + * to the maintainers: + * - https://github.com/sparklemotion/nokogiri/issues/1223 + * - https://github.com/sparklemotion/nokogiri/pull/2177 + * - https://github.com/sparklemotion/nokogiri/issues/2380 + */ +static VALUE +rb_xml_node_line(VALUE rb_node) +{ + xmlNodePtr c_node; + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + return LONG2NUM(xmlGetLineNo(c_node)); +} + +/* + * call-seq: + * line=(num) + * + * Sets the line for this Node. num must be less than 65535. + */ +static VALUE +rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number) +{ + xmlNodePtr c_node; + int line_number = NUM2INT(rb_line_number); + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + // libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes. + // search for "psvi" in SAX2.c and tree.c to learn more. + if (line_number < 65535) { + c_node->line = (short unsigned)line_number; + } else { + c_node->line = 65535; + if (c_node->type == XML_TEXT_NODE) { + c_node->psvi = (void *)(ptrdiff_t)line_number; + } + } + + return rb_line_number; +} + +/* :nodoc: documented in lib/nokogiri/xml/node.rb */ +static VALUE +rb_xml_node_new(int argc, VALUE *argv, VALUE klass) +{ + xmlNodePtr c_document_node; + xmlNodePtr c_node; + VALUE rb_name; + VALUE rb_document_node; + VALUE rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest); + + if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) { + rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node"); + } + if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) { + NOKO_WARN_DEPRECATION("Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.13.0, remove in v1.17.0 + } + Noko_Node_Get_Struct(rb_document_node, xmlNode, c_document_node); + + c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name)); + c_node->doc = c_document_node->doc; + noko_xml_document_pin_node(c_node); + + rb_node = noko_xml_node_wrap( + klass == cNokogiriXmlNode ? (VALUE)NULL : klass, + c_node + ); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +/* + * call-seq: + * dump_html + * + * Returns the Node as html. + */ +static VALUE +dump_html(VALUE self) +{ + xmlBufferPtr buf ; + xmlNodePtr node ; + VALUE html; + + Noko_Node_Get_Struct(self, xmlNode, node); + + buf = xmlBufferCreate() ; + htmlNodeDump(buf, node->doc, node); + html = NOKOGIRI_STR_NEW2(xmlBufferContent(buf)); + xmlBufferFree(buf); + return html ; +} + +/* + * call-seq: + * compare(other) + * + * Compare this Node to +other+ with respect to their Document + */ +static VALUE +compare(VALUE self, VALUE _other) +{ + xmlNodePtr node, other; + Noko_Node_Get_Struct(self, xmlNode, node); + Noko_Node_Get_Struct(_other, xmlNode, other); + + return INT2NUM(xmlXPathCmpNodes(other, node)); +} + + +/* + * call-seq: + * process_xincludes(flags) + * + * Loads and substitutes all xinclude elements below the node. The + * parser context will be initialized with +flags+. + */ +static VALUE +noko_xml_node__process_xincludes(VALUE rb_node, VALUE rb_flags) +{ + int status ; + xmlNodePtr c_node; + VALUE rb_errors = rb_ary_new(); + libxmlStructuredErrorHandlerState handler_state; + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + status = xmlXIncludeProcessTreeFlags(c_node, (int)NUM2INT(rb_flags)); + + noko__structured_error_func_restore(&handler_state); + + if (status < 0) { + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution"); + } + } + + return rb_node; +} + + +/* TODO: DOCUMENT ME */ +static VALUE +in_context(VALUE self, VALUE _str, VALUE _options) +{ + xmlNodePtr node, list = 0, tmp, child_iter, node_children, doc_children; + xmlNodeSetPtr set; + xmlParserErrors error; + VALUE doc, err; + int doc_is_empty; + + Noko_Node_Get_Struct(self, xmlNode, node); + + doc = DOC_RUBY_OBJECT(node->doc); + err = rb_iv_get(doc, "@errors"); + doc_is_empty = (node->doc->children == NULL) ? 1 : 0; + node_children = node->children; + doc_children = node->doc->children; + + xmlSetStructuredErrorFunc((void *)err, noko__error_array_pusher); + + /* This function adds a fake node to the child of +node+. If the parser + * does not exit cleanly with XML_ERR_OK, the list is freed. This can + * leave the child pointers in a bad state if they were originally empty. + * + * http://git.gnome.org/browse/libxml2/tree/parser.c#n13177 + * */ + error = xmlParseInNodeContext(node, StringValuePtr(_str), + (int)RSTRING_LEN(_str), + (int)NUM2INT(_options), &list); + + /* xmlParseInNodeContext should not mutate the original document or node, + * so reassigning these pointers should be OK. The reason we're reassigning + * is because if there were errors, it's possible for the child pointers + * to be manipulated. */ + if (error != XML_ERR_OK) { + node->doc->children = doc_children; + node->children = node_children; + } + + /* make sure parent/child pointers are coherent so an unlink will work + * properly (#331) + */ + child_iter = node->doc->children ; + while (child_iter) { + child_iter->parent = (xmlNodePtr)node->doc; + child_iter = child_iter->next; + } + + xmlSetStructuredErrorFunc(NULL, NULL); + + /* + * Workaround for a libxml2 bug where a parsing error may leave a broken + * node reference in node->doc->children. + * + * https://bugzilla.gnome.org/show_bug.cgi?id=668155 + * + * This workaround is limited to when a parse error occurs, the document + * went from having no children to having children, and the context node is + * part of a document fragment. + * + * TODO: This was fixed in libxml 2.8.0 by 71a243d + */ + if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) { + child_iter = node; + while (child_iter->parent) { + child_iter = child_iter->parent; + } + + if (child_iter->type == XML_DOCUMENT_FRAG_NODE) { + node->doc->children = NULL; + } + } + + /* FIXME: This probably needs to handle more constants... */ + switch (error) { + case XML_ERR_INTERNAL_ERROR: + case XML_ERR_NO_MEMORY: + rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error); + break; + default: + break; + } + + set = xmlXPathNodeSetCreate(NULL); + + while (list) { + tmp = list->next; + list->next = NULL; + xmlXPathNodeSetAddUnique(set, list); + noko_xml_document_pin_node(list); + list = tmp; + } + + return noko_xml_node_set_wrap(set, doc); +} + +/* :nodoc: */ +VALUE +rb_xml_node_data_ptr_eh(VALUE self) +{ + xmlNodePtr c_node; + Noko_Node_Get_Struct(self, xmlNode, c_node); + return c_node ? Qtrue : Qfalse; +} + +VALUE +noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node) +{ + VALUE rb_document, rb_node_cache, rb_node; + nokogiriTuplePtr node_has_a_document; + xmlDocPtr c_doc; + + assert(c_node); + + if (c_node->type == XML_DOCUMENT_NODE || c_node->type == XML_HTML_DOCUMENT_NODE) { + return DOC_RUBY_OBJECT(c_node->doc); + } + + c_doc = c_node->doc; + + // Nodes yielded from XML::Reader don't have a fully-realized Document + node_has_a_document = DOC_RUBY_OBJECT_TEST(c_doc); + + if (c_node->_private && node_has_a_document) { + return (VALUE)c_node->_private; + } + + if (!RTEST(rb_class)) { + switch (c_node->type) { + case XML_ELEMENT_NODE: + rb_class = cNokogiriXmlElement; + break; + case XML_TEXT_NODE: + rb_class = cNokogiriXmlText; + break; + case XML_ATTRIBUTE_NODE: + rb_class = cNokogiriXmlAttr; + break; + case XML_ENTITY_REF_NODE: + rb_class = cNokogiriXmlEntityReference; + break; + case XML_COMMENT_NODE: + rb_class = cNokogiriXmlComment; + break; + case XML_DOCUMENT_FRAG_NODE: + rb_class = cNokogiriXmlDocumentFragment; + break; + case XML_PI_NODE: + rb_class = cNokogiriXmlProcessingInstruction; + break; + case XML_ENTITY_DECL: + rb_class = cNokogiriXmlEntityDecl; + break; + case XML_CDATA_SECTION_NODE: + rb_class = cNokogiriXmlCData; + break; + case XML_DTD_NODE: + rb_class = cNokogiriXmlDtd; + break; + case XML_ATTRIBUTE_DECL: + rb_class = cNokogiriXmlAttributeDecl; + break; + case XML_ELEMENT_DECL: + rb_class = cNokogiriXmlElementDecl; + break; + default: + rb_class = cNokogiriXmlNode; + } + } + + rb_node = _xml_node_alloc(rb_class); + _xml_node_data_ptr_set(rb_node, c_node); + + if (node_has_a_document) { + rb_document = DOC_RUBY_OBJECT(c_doc); + rb_node_cache = DOC_NODE_CACHE(c_doc); + rb_ary_push(rb_node_cache, rb_node); + rb_funcall(rb_document, id_decorate, 1, rb_node); + } + + return rb_node ; +} + + +/* + * return Array containing the node's attributes + */ +VALUE +noko_xml_node_attrs(xmlNodePtr c_node) +{ + VALUE rb_properties = rb_ary_new(); + xmlAttrPtr c_property; + + c_property = c_node->properties ; + while (c_property != NULL) { + rb_ary_push(rb_properties, noko_xml_node_wrap(Qnil, (xmlNodePtr)c_property)); + c_property = c_property->next ; + } + + return rb_properties; +} + +void +noko_init_xml_node(void) +{ + cNokogiriXmlNode = rb_define_class_under(mNokogiriXml, "Node", rb_cObject); + + rb_define_alloc_func(cNokogiriXmlNode, _xml_node_alloc); + + rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1); + + rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2); + rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1); + rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0); + rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2); + rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0); + rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0); + rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0); + rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0); + rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3); + rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3); + rb_define_method(cNokogiriXmlNode, "data_ptr?", rb_xml_node_data_ptr_eh, 0); + rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0); + rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0); + rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1); + rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0); + rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0); + rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0); + rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1); + rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0); + rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1); + rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0); + rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0); + rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1); + rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0); + rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0); + rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0); + rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2); + rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1); + rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0); + rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0); + rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0); + rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1); + rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0); + rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0); + rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0); + rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0); + rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0); + rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0); + rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0); + + rb_define_protected_method(cNokogiriXmlNode, "initialize_copy_with_args", rb_xml_node_initialize_copy_with_args, 3); + + rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1); + rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1); + rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1); + rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1); + rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0); + rb_define_private_method(cNokogiriXmlNode, "get", get, 1); + rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2); + rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4); + rb_define_private_method(cNokogiriXmlNode, "prepend_newline?", rb_prepend_newline, 0); + rb_define_private_method(cNokogiriXmlNode, "html_standard_serialize", html_standard_serialize, 1); + rb_define_private_method(cNokogiriXmlNode, "process_xincludes", noko_xml_node__process_xincludes, 1); + rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1); + rb_define_private_method(cNokogiriXmlNode, "set", set, 2); + rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1); + + id_decorate = rb_intern("decorate"); + id_decorate_bang = rb_intern("decorate!"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node_set.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node_set.c new file mode 100644 index 00000000..de1beeb5 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_node_set.c @@ -0,0 +1,518 @@ +#include + +VALUE cNokogiriXmlNodeSet ; + +static ID decorate ; + +static void +Check_Node_Set_Node_Type(VALUE node) +{ + if (!(rb_obj_is_kind_of(node, cNokogiriXmlNode) || + rb_obj_is_kind_of(node, cNokogiriXmlNamespace))) { + rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node or Nokogiri::XML::Namespace"); + } +} + + +static +VALUE +ruby_object_get(xmlNodePtr c_node) +{ + /* see xmlElementType in libxml2 tree.h */ + switch (c_node->type) { + case XML_NAMESPACE_DECL: + /* _private is later in the namespace struct */ + return (VALUE)(((xmlNsPtr)c_node)->_private); + + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + /* in documents we use _private to store a tuple */ + if (DOC_RUBY_OBJECT_TEST(((xmlDocPtr)c_node))) { + return DOC_RUBY_OBJECT((xmlDocPtr)c_node); + } + return (VALUE)NULL; + + default: + return (VALUE)(c_node->_private); + } +} + + +static void +xml_node_set_mark(void *data) +{ + xmlNodeSetPtr node_set = data; + VALUE rb_node; + int jnode; + + for (jnode = 0; jnode < node_set->nodeNr; jnode++) { + rb_node = ruby_object_get(node_set->nodeTab[jnode]); + if (rb_node) { + rb_gc_mark(rb_node); + } + } +} + +static void +xml_node_set_deallocate(void *data) +{ + xmlNodeSetPtr node_set = data; + /* + * For reasons outlined in xml_namespace.c, here we reproduce xmlXPathFreeNodeSet() except for the + * offending call to xmlXPathNodeSetFreeNs(). + */ + if (node_set->nodeTab != NULL) { + xmlFree(node_set->nodeTab); + } + + xmlFree(node_set); +} + +static const rb_data_type_t xml_node_set_type = { + .wrap_struct_name = "xmlNodeSet", + .function = { + .dmark = xml_node_set_mark, + .dfree = xml_node_set_deallocate, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY, +}; + +static VALUE +xml_node_set_allocate(VALUE klass) +{ + return TypedData_Wrap_Struct(klass, &xml_node_set_type, xmlXPathNodeSetCreate(NULL)); +} + +/* :nodoc: */ +static VALUE +rb_xml_node_set_initialize_copy(VALUE rb_self, VALUE rb_other) +{ + xmlNodeSetPtr c_self, c_other; + VALUE rb_document; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); + + xmlXPathNodeSetMerge(c_self, c_other); + + rb_document = rb_iv_get(rb_other, "@document"); + if (!NIL_P(rb_document)) { + rb_iv_set(rb_self, "@document", rb_document); + rb_funcall(rb_document, decorate, 1, rb_self); + } + + return rb_self; +} + +static void +xpath_node_set_del(xmlNodeSetPtr cur, xmlNodePtr val) +{ + /* + * For reasons outlined in xml_namespace.c, here we reproduce xmlXPathNodeSetDel() except for the + * offending call to xmlXPathNodeSetFreeNs(). + */ + int i; + + if (cur == NULL) { return; } + if (val == NULL) { return; } + + /* + * find node in nodeTab + */ + for (i = 0; i < cur->nodeNr; i++) + if (cur->nodeTab[i] == val) { break; } + + if (i >= cur->nodeNr) { /* not found */ + return; + } + cur->nodeNr--; + for (; i < cur->nodeNr; i++) { + cur->nodeTab[i] = cur->nodeTab[i + 1]; + } + cur->nodeTab[cur->nodeNr] = NULL; +} + +/* + * call-seq: + * length + * + * Get the length of the node set + */ +static VALUE +length(VALUE rb_self) +{ + xmlNodeSetPtr c_self; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + return c_self ? INT2NUM(c_self->nodeNr) : INT2NUM(0); +} + +/* + * call-seq: + * push(node) + * + * Append +node+ to the NodeSet. + */ +static VALUE +push(VALUE rb_self, VALUE rb_node) +{ + xmlNodeSetPtr c_self; + xmlNodePtr node; + + Check_Node_Set_Node_Type(rb_node); + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + Noko_Node_Get_Struct(rb_node, xmlNode, node); + + xmlXPathNodeSetAdd(c_self, node); + + return rb_self; +} + +/* + * call-seq: + * delete(node) + * + * Delete +node+ from the Nodeset, if it is a member. Returns the deleted node + * if found, otherwise returns nil. + */ +static VALUE +delete (VALUE rb_self, VALUE rb_node) +{ + xmlNodeSetPtr c_self; + xmlNodePtr node; + + Check_Node_Set_Node_Type(rb_node); + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + Noko_Node_Get_Struct(rb_node, xmlNode, node); + + if (xmlXPathNodeSetContains(c_self, node)) { + xpath_node_set_del(c_self, node); + return rb_node; + } + return Qnil ; +} + + +/* + * call-seq: + * &(node_set) + * + * Set Intersection — Returns a new NodeSet containing nodes common to the two NodeSets. + */ +static VALUE +intersection(VALUE rb_self, VALUE rb_other) +{ + xmlNodeSetPtr c_self, c_other ; + xmlNodeSetPtr intersection; + + if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { + rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); + } + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); + + intersection = xmlXPathIntersection(c_self, c_other); + return noko_xml_node_set_wrap(intersection, rb_iv_get(rb_self, "@document")); +} + + +/* + * call-seq: + * include?(node) + * + * Returns true if any member of node set equals +node+. + */ +static VALUE +include_eh(VALUE rb_self, VALUE rb_node) +{ + xmlNodeSetPtr c_self; + xmlNodePtr node; + + Check_Node_Set_Node_Type(rb_node); + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + Noko_Node_Get_Struct(rb_node, xmlNode, node); + + return (xmlXPathNodeSetContains(c_self, node) ? Qtrue : Qfalse); +} + + +/* + * call-seq: + * |(node_set) + * + * Returns a new set built by merging the set and the elements of the given + * set. + */ +static VALUE +rb_xml_node_set_union(VALUE rb_self, VALUE rb_other) +{ + xmlNodeSetPtr c_self, c_other; + xmlNodeSetPtr c_new_node_set; + + if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { + rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); + } + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); + + c_new_node_set = xmlXPathNodeSetMerge(NULL, c_self); + c_new_node_set = xmlXPathNodeSetMerge(c_new_node_set, c_other); + + return noko_xml_node_set_wrap(c_new_node_set, rb_iv_get(rb_self, "@document")); +} + +/* + * call-seq: + * -(node_set) + * + * Difference - returns a new NodeSet that is a copy of this NodeSet, removing + * each item that also appears in +node_set+ + */ +static VALUE +minus(VALUE rb_self, VALUE rb_other) +{ + xmlNodeSetPtr c_self, c_other; + xmlNodeSetPtr new; + int j ; + + if (!rb_obj_is_kind_of(rb_other, cNokogiriXmlNodeSet)) { + rb_raise(rb_eArgError, "node_set must be a Nokogiri::XML::NodeSet"); + } + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + TypedData_Get_Struct(rb_other, xmlNodeSet, &xml_node_set_type, c_other); + + new = xmlXPathNodeSetMerge(NULL, c_self); + for (j = 0 ; j < c_other->nodeNr ; ++j) { + xpath_node_set_del(new, c_other->nodeTab[j]); + } + + return noko_xml_node_set_wrap(new, rb_iv_get(rb_self, "@document")); +} + + +static VALUE +index_at(VALUE rb_self, long offset) +{ + xmlNodeSetPtr c_self; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + if (offset >= c_self->nodeNr || abs((int)offset) > c_self->nodeNr) { + return Qnil; + } + + if (offset < 0) { offset += c_self->nodeNr ; } + + return noko_xml_node_wrap_node_set_result(c_self->nodeTab[offset], rb_self); +} + +static VALUE +subseq(VALUE rb_self, long beg, long len) +{ + long j; + xmlNodeSetPtr c_self; + xmlNodeSetPtr new_set ; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + if (beg > c_self->nodeNr) { return Qnil ; } + if (beg < 0 || len < 0) { return Qnil ; } + + if ((beg + len) > c_self->nodeNr) { + len = c_self->nodeNr - beg ; + } + + new_set = xmlXPathNodeSetCreate(NULL); + for (j = beg ; j < beg + len ; ++j) { + xmlXPathNodeSetAddUnique(new_set, c_self->nodeTab[j]); + } + return noko_xml_node_set_wrap(new_set, rb_iv_get(rb_self, "@document")); +} + +/* + * call-seq: + * [index] -> Node or nil + * [start, length] -> NodeSet or nil + * [range] -> NodeSet or nil + * slice(index) -> Node or nil + * slice(start, length) -> NodeSet or nil + * slice(range) -> NodeSet or nil + * + * Element reference - returns the node at +index+, or returns a NodeSet + * containing nodes starting at +start+ and continuing for +length+ elements, or + * returns a NodeSet containing nodes specified by +range+. Negative +indices+ + * count backward from the end of the +node_set+ (-1 is the last node). Returns + * nil if the +index+ (or +start+) are out of range. + */ +static VALUE +slice(int argc, VALUE *argv, VALUE rb_self) +{ + VALUE arg ; + long beg, len ; + xmlNodeSetPtr c_self; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + if (argc == 2) { + beg = NUM2LONG(argv[0]); + len = NUM2LONG(argv[1]); + if (beg < 0) { + beg += c_self->nodeNr ; + } + return subseq(rb_self, beg, len); + } + + if (argc != 1) { + rb_scan_args(argc, argv, "11", NULL, NULL); + } + arg = argv[0]; + + if (FIXNUM_P(arg)) { + return index_at(rb_self, FIX2LONG(arg)); + } + + /* if arg is Range */ + switch (rb_range_beg_len(arg, &beg, &len, (long)c_self->nodeNr, 0)) { + case Qfalse: + break; + case Qnil: + return Qnil; + default: + return subseq(rb_self, beg, len); + } + + return index_at(rb_self, NUM2LONG(arg)); +} + + +/* + * call-seq: + * to_a + * + * Return this list as an Array + */ +static VALUE +to_array(VALUE rb_self) +{ + xmlNodeSetPtr c_self ; + VALUE list; + int i; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + list = rb_ary_new2(c_self->nodeNr); + for (i = 0; i < c_self->nodeNr; i++) { + VALUE elt = noko_xml_node_wrap_node_set_result(c_self->nodeTab[i], rb_self); + rb_ary_push(list, elt); + } + + return list; +} + +/* + * call-seq: + * unlink + * + * Unlink this NodeSet and all Node objects it contains from their current context. + */ +static VALUE +unlink_nodeset(VALUE rb_self) +{ + xmlNodeSetPtr c_self; + int j, nodeNr ; + + TypedData_Get_Struct(rb_self, xmlNodeSet, &xml_node_set_type, c_self); + + nodeNr = c_self->nodeNr ; + for (j = 0 ; j < nodeNr ; j++) { + if (! NOKOGIRI_NAMESPACE_EH(c_self->nodeTab[j])) { + VALUE node ; + xmlNodePtr node_ptr; + node = noko_xml_node_wrap(Qnil, c_self->nodeTab[j]); + rb_funcall(node, rb_intern("unlink"), 0); /* modifies the C struct out from under the object */ + Noko_Node_Get_Struct(node, xmlNode, node_ptr); + c_self->nodeTab[j] = node_ptr ; + } + } + return rb_self ; +} + + +VALUE +noko_xml_node_set_wrap(xmlNodeSetPtr c_node_set, VALUE document) +{ + int j; + VALUE rb_node_set ; + + if (c_node_set == NULL) { + rb_node_set = xml_node_set_allocate(cNokogiriXmlNodeSet); + } else { + rb_node_set = TypedData_Wrap_Struct(cNokogiriXmlNodeSet, &xml_node_set_type, c_node_set); + } + + if (!NIL_P(document)) { + rb_iv_set(rb_node_set, "@document", document); + rb_funcall(document, decorate, 1, rb_node_set); + } + + if (c_node_set) { + /* create ruby objects for all the results, so they'll be marked during the GC mark phase */ + for (j = 0 ; j < c_node_set->nodeNr ; j++) { + noko_xml_node_wrap_node_set_result(c_node_set->nodeTab[j], rb_node_set); + } + } + + return rb_node_set ; +} + + +VALUE +noko_xml_node_wrap_node_set_result(xmlNodePtr node, VALUE node_set) +{ + if (NOKOGIRI_NAMESPACE_EH(node)) { + return noko_xml_namespace_wrap_xpath_copy((xmlNsPtr)node); + } else { + return noko_xml_node_wrap(Qnil, node); + } +} + + +xmlNodeSetPtr +noko_xml_node_set_unwrap(VALUE rb_node_set) +{ + xmlNodeSetPtr c_node_set; + TypedData_Get_Struct(rb_node_set, xmlNodeSet, &xml_node_set_type, c_node_set); + return c_node_set; +} + + +void +noko_init_xml_node_set(void) +{ + cNokogiriXmlNodeSet = rb_define_class_under(mNokogiriXml, "NodeSet", rb_cObject); + + rb_define_alloc_func(cNokogiriXmlNodeSet, xml_node_set_allocate); + + rb_define_method(cNokogiriXmlNodeSet, "&", intersection, 1); + rb_define_method(cNokogiriXmlNodeSet, "-", minus, 1); + rb_define_method(cNokogiriXmlNodeSet, "[]", slice, -1); + rb_define_method(cNokogiriXmlNodeSet, "delete", delete, 1); + rb_define_method(cNokogiriXmlNodeSet, "include?", include_eh, 1); + rb_define_method(cNokogiriXmlNodeSet, "length", length, 0); + rb_define_method(cNokogiriXmlNodeSet, "push", push, 1); + rb_define_method(cNokogiriXmlNodeSet, "slice", slice, -1); + rb_define_method(cNokogiriXmlNodeSet, "to_a", to_array, 0); + rb_define_method(cNokogiriXmlNodeSet, "unlink", unlink_nodeset, 0); + rb_define_method(cNokogiriXmlNodeSet, "|", rb_xml_node_set_union, 1); + + rb_define_private_method(cNokogiriXmlNodeSet, "initialize_copy", rb_xml_node_set_initialize_copy, 1); + + decorate = rb_intern("decorate"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_processing_instruction.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_processing_instruction.c new file mode 100644 index 00000000..6bcf15f1 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_processing_instruction.c @@ -0,0 +1,54 @@ +#include + +VALUE cNokogiriXmlProcessingInstruction; + +/* + * call-seq: + * new(document, name, content) + * + * Create a new ProcessingInstruction element on the +document+ with +name+ + * and +content+ + */ +static VALUE +new (int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr xml_doc; + xmlNodePtr node; + VALUE document; + VALUE name; + VALUE content; + VALUE rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "3*", &document, &name, &content, &rest); + + xml_doc = noko_xml_document_unwrap(document); + + node = xmlNewDocPI( + xml_doc, + (const xmlChar *)StringValueCStr(name), + (const xmlChar *)StringValueCStr(content) + ); + + noko_xml_document_pin_node(node); + + rb_node = noko_xml_node_wrap(klass, node); + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +void +noko_init_xml_processing_instruction(void) +{ + assert(cNokogiriXmlNode); + /* + * ProcessingInstruction represents a ProcessingInstruction node in an xml + * document. + */ + cNokogiriXmlProcessingInstruction = rb_define_class_under(mNokogiriXml, "ProcessingInstruction", cNokogiriXmlNode); + + rb_define_singleton_method(cNokogiriXmlProcessingInstruction, "new", new, -1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_reader.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_reader.c new file mode 100644 index 00000000..aa857493 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_reader.c @@ -0,0 +1,777 @@ +#include + +VALUE cNokogiriXmlReader; + +static void +xml_reader_deallocate(void *data) +{ + // free the document separately because we _may_ have triggered preservation by calling + // xmlTextReaderCurrentDoc during a read_more. + xmlTextReaderPtr reader = data; + xmlDocPtr doc = xmlTextReaderCurrentDoc(reader); + xmlFreeTextReader(reader); + if (doc) { + xmlFreeDoc(doc); + } +} + +static const rb_data_type_t xml_text_reader_type = { + .wrap_struct_name = "xmlTextReader", + .function = { + .dfree = xml_reader_deallocate, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static int +has_attributes(xmlTextReaderPtr reader) +{ + /* + * this implementation of xmlTextReaderHasAttributes explicitly includes + * namespaces and properties, because some earlier versions ignore + * namespaces. + */ + xmlNodePtr node ; + node = xmlTextReaderCurrentNode(reader); + if (node == NULL) { + return (0); + } + + if ((node->type == XML_ELEMENT_NODE) && + ((node->properties != NULL) || (node->nsDef != NULL))) { + return (1); + } + return (0); +} + +// TODO: merge this function into the `namespaces` method implementation +static void +Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash) +{ + xmlNsPtr ns; + VALUE key; + + if (node->type != XML_ELEMENT_NODE) { return ; } + + ns = node->nsDef; + while (ns != NULL) { + + key = rb_enc_str_new_cstr(XMLNS_PREFIX, rb_utf8_encoding()); + if (ns->prefix) { + rb_str_cat_cstr(key, ":"); + rb_str_cat_cstr(key, (const char *)ns->prefix); + } + + key = rb_str_conv_enc(key, rb_utf8_encoding(), rb_default_internal_encoding()); + rb_hash_aset(attr_hash, + key, + (ns->href ? NOKOGIRI_STR_NEW2(ns->href) : Qnil) + ); + ns = ns->next ; + } +} + + +/* + * call-seq: + * default? + * + * Was an attribute generated from the default value in the DTD or schema? + */ +static VALUE +default_eh(VALUE self) +{ + xmlTextReaderPtr reader; + int eh; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + eh = xmlTextReaderIsDefault(reader); + if (eh == 0) { return Qfalse; } + if (eh == 1) { return Qtrue; } + + return Qnil; +} + +/* + * call-seq: + * value? + * + * Does this node have a text value? + */ +static VALUE +value_eh(VALUE self) +{ + xmlTextReaderPtr reader; + int eh; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + eh = xmlTextReaderHasValue(reader); + if (eh == 0) { return Qfalse; } + if (eh == 1) { return Qtrue; } + + return Qnil; +} + +/* + * call-seq: + * attributes? + * + * Does this node have attributes? + */ +static VALUE +attributes_eh(VALUE self) +{ + xmlTextReaderPtr reader; + int eh; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + eh = has_attributes(reader); + if (eh == 0) { return Qfalse; } + if (eh == 1) { return Qtrue; } + + return Qnil; +} + +/* + * call-seq: + * namespaces + * + * Get a hash of namespaces for this Node + */ +static VALUE +rb_xml_reader_namespaces(VALUE rb_reader) +{ + VALUE rb_namespaces = rb_hash_new() ; + xmlTextReaderPtr c_reader; + xmlNodePtr c_node; + VALUE rb_errors; + + TypedData_Get_Struct(rb_reader, xmlTextReader, &xml_text_reader_type, c_reader); + + if (! has_attributes(c_reader)) { + return rb_namespaces ; + } + + rb_errors = rb_funcall(rb_reader, rb_intern("errors"), 0); + + xmlSetStructuredErrorFunc((void *)rb_errors, noko__error_array_pusher); + c_node = xmlTextReaderExpand(c_reader); + xmlSetStructuredErrorFunc(NULL, NULL); + + if (c_node == NULL) { + if (RARRAY_LEN(rb_errors) > 0) { + VALUE rb_error = rb_ary_entry(rb_errors, 0); + VALUE exception_message = rb_funcall(rb_error, rb_intern("to_s"), 0); + rb_exc_raise(rb_class_new_instance(1, &exception_message, cNokogiriXmlSyntaxError)); + } + return Qnil; + } + + Nokogiri_xml_node_namespaces(c_node, rb_namespaces); + + return rb_namespaces ; +} + +/* + :call-seq: attribute_hash() → Hash + + Get the attributes of the current node as a Hash of names and values. + + See related: #attributes and #namespaces + */ +static VALUE +rb_xml_reader_attribute_hash(VALUE rb_reader) +{ + VALUE rb_attributes = rb_hash_new(); + xmlTextReaderPtr c_reader; + xmlNodePtr c_node; + xmlAttrPtr c_property; + VALUE rb_errors; + + TypedData_Get_Struct(rb_reader, xmlTextReader, &xml_text_reader_type, c_reader); + + if (!has_attributes(c_reader)) { + return rb_attributes; + } + + rb_errors = rb_funcall(rb_reader, rb_intern("errors"), 0); + + xmlSetStructuredErrorFunc((void *)rb_errors, noko__error_array_pusher); + c_node = xmlTextReaderExpand(c_reader); + xmlSetStructuredErrorFunc(NULL, NULL); + + if (c_node == NULL) { + if (RARRAY_LEN(rb_errors) > 0) { + VALUE rb_error = rb_ary_entry(rb_errors, 0); + VALUE exception_message = rb_funcall(rb_error, rb_intern("to_s"), 0); + rb_exc_raise(rb_class_new_instance(1, &exception_message, cNokogiriXmlSyntaxError)); + } + return Qnil; + } + + c_property = c_node->properties; + while (c_property != NULL) { + VALUE rb_name = NOKOGIRI_STR_NEW2(c_property->name); + VALUE rb_value = Qnil; + xmlChar *c_value = xmlNodeGetContent((xmlNode *)c_property); + + if (c_value) { + rb_value = NOKOGIRI_STR_NEW2(c_value); + xmlFree(c_value); + } + + rb_hash_aset(rb_attributes, rb_name, rb_value); + + c_property = c_property->next; + } + + return rb_attributes; +} + +/* + * call-seq: + * attribute_at(index) + * + * Get the value of attribute at +index+ + */ +static VALUE +attribute_at(VALUE self, VALUE index) +{ + xmlTextReaderPtr reader; + xmlChar *value; + VALUE rb_value; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + + if (NIL_P(index)) { return Qnil; } + index = rb_Integer(index); + + value = xmlTextReaderGetAttributeNo( + reader, + (int)NUM2INT(index) + ); + if (value == NULL) { return Qnil; } + + rb_value = NOKOGIRI_STR_NEW2(value); + xmlFree(value); + return rb_value; +} + +/* + * call-seq: + * attribute(name) + * + * Get the value of attribute named +name+ + */ +static VALUE +reader_attribute(VALUE self, VALUE name) +{ + xmlTextReaderPtr reader; + xmlChar *value ; + VALUE rb_value; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + + if (NIL_P(name)) { return Qnil; } + name = StringValue(name) ; + + value = xmlTextReaderGetAttribute(reader, (xmlChar *)StringValueCStr(name)); + if (value == NULL) { return Qnil; } + + rb_value = NOKOGIRI_STR_NEW2(value); + xmlFree(value); + return rb_value; +} + +/* + * call-seq: + * attribute_count + * + * Get the number of attributes for the current node + */ +static VALUE +attribute_count(VALUE self) +{ + xmlTextReaderPtr reader; + int count; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + count = xmlTextReaderAttributeCount(reader); + if (count == -1) { return Qnil; } + + return INT2NUM(count); +} + +/* + * call-seq: + * depth + * + * Get the depth of the node + */ +static VALUE +depth(VALUE self) +{ + xmlTextReaderPtr reader; + int depth; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + depth = xmlTextReaderDepth(reader); + if (depth == -1) { return Qnil; } + + return INT2NUM(depth); +} + +/* + * call-seq: + * xml_version + * + * Get the XML version of the document being read + */ +static VALUE +xml_version(VALUE self) +{ + xmlTextReaderPtr reader; + const char *version; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + version = (const char *)xmlTextReaderConstXmlVersion(reader); + if (version == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(version); +} + +/* + * call-seq: + * lang + * + * Get the xml:lang scope within which the node resides. + */ +static VALUE +lang(VALUE self) +{ + xmlTextReaderPtr reader; + const char *lang; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + lang = (const char *)xmlTextReaderConstXmlLang(reader); + if (lang == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(lang); +} + +/* + * call-seq: + * value + * + * Get the text value of the node if present. Returns a utf-8 encoded string. + */ +static VALUE +value(VALUE self) +{ + xmlTextReaderPtr reader; + const char *value; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + value = (const char *)xmlTextReaderConstValue(reader); + if (value == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(value); +} + +/* + * call-seq: + * prefix + * + * Get the shorthand reference to the namespace associated with the node. + */ +static VALUE +prefix(VALUE self) +{ + xmlTextReaderPtr reader; + const char *prefix; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + prefix = (const char *)xmlTextReaderConstPrefix(reader); + if (prefix == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(prefix); +} + +/* + * call-seq: + * namespace_uri + * + * Get the URI defining the namespace associated with the node + */ +static VALUE +namespace_uri(VALUE self) +{ + xmlTextReaderPtr reader; + const char *uri; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + uri = (const char *)xmlTextReaderConstNamespaceUri(reader); + if (uri == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(uri); +} + +/* + * call-seq: + * local_name + * + * Get the local name of the node + */ +static VALUE +local_name(VALUE self) +{ + xmlTextReaderPtr reader; + const char *name; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + name = (const char *)xmlTextReaderConstLocalName(reader); + if (name == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(name); +} + +/* + * call-seq: + * name + * + * Get the name of the node. Returns a utf-8 encoded string. + */ +static VALUE +name(VALUE self) +{ + xmlTextReaderPtr reader; + const char *name; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + name = (const char *)xmlTextReaderConstName(reader); + if (name == NULL) { return Qnil; } + + return NOKOGIRI_STR_NEW2(name); +} + +/* + * call-seq: + * base_uri + * + * Get the xml:base of the node + */ +static VALUE +rb_xml_reader_base_uri(VALUE rb_reader) +{ + VALUE rb_base_uri; + xmlTextReaderPtr c_reader; + xmlChar *c_base_uri; + + TypedData_Get_Struct(rb_reader, xmlTextReader, &xml_text_reader_type, c_reader); + + c_base_uri = xmlTextReaderBaseUri(c_reader); + if (c_base_uri == NULL) { + return Qnil; + } + + rb_base_uri = NOKOGIRI_STR_NEW2(c_base_uri); + xmlFree(c_base_uri); + + return rb_base_uri; +} + +/* + * call-seq: + * state + * + * Get the state of the reader + */ +static VALUE +state(VALUE self) +{ + xmlTextReaderPtr reader; + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + return INT2NUM(xmlTextReaderReadState(reader)); +} + +/* + * call-seq: + * node_type + * + * Get the type of readers current node + */ +static VALUE +node_type(VALUE self) +{ + xmlTextReaderPtr reader; + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + return INT2NUM(xmlTextReaderNodeType(reader)); +} + +/* + * call-seq: + * read + * + * Move the Reader forward through the XML document. + */ +static VALUE +read_more(VALUE rb_reader) +{ + xmlTextReaderPtr c_reader; + libxmlStructuredErrorHandlerState handler_state; + + TypedData_Get_Struct(rb_reader, xmlTextReader, &xml_text_reader_type, c_reader); + + VALUE rb_errors = rb_funcall(rb_reader, rb_intern("errors"), 0); + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + int status = xmlTextReaderRead(c_reader); + + noko__structured_error_func_restore(&handler_state); + + xmlDocPtr c_document = xmlTextReaderCurrentDoc(c_reader); + if (c_document && c_document->encoding == NULL) { + VALUE constructor_encoding = rb_iv_get(rb_reader, "@encoding"); + if (RTEST(constructor_encoding)) { + c_document->encoding = xmlStrdup(BAD_CAST StringValueCStr(constructor_encoding)); + } else { + rb_iv_set(rb_reader, "@encoding", NOKOGIRI_STR_NEW2("UTF-8")); + c_document->encoding = xmlStrdup(BAD_CAST "UTF-8"); + } + } + + if (status == 1) { return rb_reader; } + if (status == 0) { return Qnil; } + + /* if we're here, there was an error */ + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Error pulling: %d", status); + } +} + +/* + * call-seq: + * inner_xml + * + * Read the contents of the current node, including child nodes and markup. + * Returns a utf-8 encoded string. + */ +static VALUE +inner_xml(VALUE self) +{ + xmlTextReaderPtr reader; + xmlChar *value; + VALUE str; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + + value = xmlTextReaderReadInnerXml(reader); + + str = Qnil; + if (value) { + str = NOKOGIRI_STR_NEW2((char *)value); + xmlFree(value); + } + + return str; +} + +/* + * call-seq: + * outer_xml + * + * Read the current node and its contents, including child nodes and markup. + * Returns a utf-8 encoded string. + */ +static VALUE +outer_xml(VALUE self) +{ + xmlTextReaderPtr reader; + xmlChar *value; + VALUE str = Qnil; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + + value = xmlTextReaderReadOuterXml(reader); + + if (value) { + str = NOKOGIRI_STR_NEW2((char *)value); + xmlFree(value); + } + return str; +} + +/* + * call-seq: + * from_memory(string, url = nil, encoding = nil, options = 0) + * + * Create a new Reader to parse a String. + */ +static VALUE +from_memory(int argc, VALUE *argv, VALUE klass) +{ + /* TODO: deprecate this method, since Reader.new can handle both memory and IO. It can then + * become private. */ + VALUE rb_buffer, rb_url, encoding, rb_options; + xmlTextReaderPtr reader; + const char *c_url = NULL; + const char *c_encoding = NULL; + int c_options = 0; + VALUE rb_reader, args[3]; + + rb_scan_args(argc, argv, "13", &rb_buffer, &rb_url, &encoding, &rb_options); + + if (!RTEST(rb_buffer)) { rb_raise(rb_eArgError, "string cannot be nil"); } + if (RTEST(rb_url)) { c_url = StringValueCStr(rb_url); } + if (RTEST(encoding)) { c_encoding = StringValueCStr(encoding); } + if (RTEST(rb_options)) { c_options = (int)NUM2INT(rb_options); } + + reader = xmlReaderForMemory( + StringValuePtr(rb_buffer), + (int)RSTRING_LEN(rb_buffer), + c_url, + c_encoding, + c_options + ); + + if (reader == NULL) { + xmlFreeTextReader(reader); + rb_raise(rb_eRuntimeError, "couldn't create a parser"); + } + + rb_reader = TypedData_Wrap_Struct(klass, &xml_text_reader_type, reader); + args[0] = rb_buffer; + args[1] = rb_url; + args[2] = encoding; + rb_obj_call_init(rb_reader, 3, args); + + return rb_reader; +} + +/* + * call-seq: + * from_io(io, url = nil, encoding = nil, options = 0) + * + * Create a new Reader to parse an IO stream. + */ +static VALUE +from_io(int argc, VALUE *argv, VALUE klass) +{ + /* TODO: deprecate this method, since Reader.new can handle both memory and IO. It can then + * become private. */ + VALUE rb_io, rb_url, encoding, rb_options; + xmlTextReaderPtr reader; + const char *c_url = NULL; + const char *c_encoding = NULL; + int c_options = 0; + VALUE rb_reader, args[3]; + + rb_scan_args(argc, argv, "13", &rb_io, &rb_url, &encoding, &rb_options); + + if (!RTEST(rb_io)) { rb_raise(rb_eArgError, "io cannot be nil"); } + if (RTEST(rb_url)) { c_url = StringValueCStr(rb_url); } + if (RTEST(encoding)) { c_encoding = StringValueCStr(encoding); } + if (RTEST(rb_options)) { c_options = (int)NUM2INT(rb_options); } + + reader = xmlReaderForIO( + (xmlInputReadCallback)noko_io_read, + (xmlInputCloseCallback)noko_io_close, + (void *)rb_io, + c_url, + c_encoding, + c_options + ); + + if (reader == NULL) { + xmlFreeTextReader(reader); + rb_raise(rb_eRuntimeError, "couldn't create a parser"); + } + + rb_reader = TypedData_Wrap_Struct(klass, &xml_text_reader_type, reader); + args[0] = rb_io; + args[1] = rb_url; + args[2] = encoding; + rb_obj_call_init(rb_reader, 3, args); + + return rb_reader; +} + +/* + * call-seq: + * reader.empty_element? # => true or false + * + * Returns true if the current node is empty, otherwise false. + */ +static VALUE +empty_element_p(VALUE self) +{ + xmlTextReaderPtr reader; + + TypedData_Get_Struct(self, xmlTextReader, &xml_text_reader_type, reader); + + if (xmlTextReaderIsEmptyElement(reader)) { + return Qtrue; + } + + return Qfalse; +} + +static VALUE +rb_xml_reader_encoding(VALUE rb_reader) +{ + xmlTextReaderPtr c_reader; + const char *parser_encoding; + VALUE constructor_encoding; + + TypedData_Get_Struct(rb_reader, xmlTextReader, &xml_text_reader_type, c_reader); + parser_encoding = (const char *)xmlTextReaderConstEncoding(c_reader); + if (parser_encoding) { + return NOKOGIRI_STR_NEW2(parser_encoding); + } + + constructor_encoding = rb_iv_get(rb_reader, "@encoding"); + if (RTEST(constructor_encoding)) { + return constructor_encoding; + } + + return Qnil; +} + +void +noko_init_xml_reader(void) +{ + cNokogiriXmlReader = rb_define_class_under(mNokogiriXml, "Reader", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlReader); + + rb_define_singleton_method(cNokogiriXmlReader, "from_memory", from_memory, -1); + rb_define_singleton_method(cNokogiriXmlReader, "from_io", from_io, -1); + + rb_define_method(cNokogiriXmlReader, "attribute", reader_attribute, 1); + rb_define_method(cNokogiriXmlReader, "attribute_at", attribute_at, 1); + rb_define_method(cNokogiriXmlReader, "attribute_count", attribute_count, 0); + rb_define_method(cNokogiriXmlReader, "attribute_hash", rb_xml_reader_attribute_hash, 0); + rb_define_method(cNokogiriXmlReader, "attributes?", attributes_eh, 0); + rb_define_method(cNokogiriXmlReader, "base_uri", rb_xml_reader_base_uri, 0); + rb_define_method(cNokogiriXmlReader, "default?", default_eh, 0); + rb_define_method(cNokogiriXmlReader, "depth", depth, 0); + rb_define_method(cNokogiriXmlReader, "empty_element?", empty_element_p, 0); + rb_define_method(cNokogiriXmlReader, "encoding", rb_xml_reader_encoding, 0); + rb_define_method(cNokogiriXmlReader, "inner_xml", inner_xml, 0); + rb_define_method(cNokogiriXmlReader, "lang", lang, 0); + rb_define_method(cNokogiriXmlReader, "local_name", local_name, 0); + rb_define_method(cNokogiriXmlReader, "name", name, 0); + rb_define_method(cNokogiriXmlReader, "namespace_uri", namespace_uri, 0); + rb_define_method(cNokogiriXmlReader, "namespaces", rb_xml_reader_namespaces, 0); + rb_define_method(cNokogiriXmlReader, "node_type", node_type, 0); + rb_define_method(cNokogiriXmlReader, "outer_xml", outer_xml, 0); + rb_define_method(cNokogiriXmlReader, "prefix", prefix, 0); + rb_define_method(cNokogiriXmlReader, "read", read_more, 0); + rb_define_method(cNokogiriXmlReader, "state", state, 0); + rb_define_method(cNokogiriXmlReader, "value", value, 0); + rb_define_method(cNokogiriXmlReader, "value?", value_eh, 0); + rb_define_method(cNokogiriXmlReader, "xml_version", xml_version, 0); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_relax_ng.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_relax_ng.c new file mode 100644 index 00000000..07b0567a --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_relax_ng.c @@ -0,0 +1,149 @@ +#include + +VALUE cNokogiriXmlRelaxNG; + +static void +_noko_xml_relax_ng_deallocate(void *data) +{ + xmlRelaxNGPtr schema = data; + xmlRelaxNGFree(schema); +} + +static const rb_data_type_t xml_relax_ng_type = { + .wrap_struct_name = "xmlRelaxNG", + .function = { + .dfree = _noko_xml_relax_ng_deallocate, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +noko_xml_relax_ng__validate_document(VALUE self, VALUE document) +{ + xmlDocPtr doc; + xmlRelaxNGPtr schema; + VALUE errors; + xmlRelaxNGValidCtxtPtr valid_ctxt; + + TypedData_Get_Struct(self, xmlRelaxNG, &xml_relax_ng_type, schema); + doc = noko_xml_document_unwrap(document); + + errors = rb_ary_new(); + + valid_ctxt = xmlRelaxNGNewValidCtxt(schema); + + if (NULL == valid_ctxt) { + /* we have a problem */ + rb_raise(rb_eRuntimeError, "Could not create a validation context"); + } + + xmlRelaxNGSetValidStructuredErrors( + valid_ctxt, + noko__error_array_pusher, + (void *)errors + ); + + xmlRelaxNGValidateDoc(valid_ctxt, doc); + + xmlRelaxNGFreeValidCtxt(valid_ctxt); + + return errors; +} + +static VALUE +_noko_xml_relax_ng_parse_schema( + VALUE rb_class, + xmlRelaxNGParserCtxtPtr c_parser_context, + VALUE rb_parse_options +) +{ + VALUE rb_errors; + VALUE rb_schema; + xmlRelaxNGPtr c_schema; + libxmlStructuredErrorHandlerState handler_state; + + if (NIL_P(rb_parse_options)) { + rb_parse_options = rb_const_get_at( + rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), + rb_intern("DEFAULT_SCHEMA") + ); + } + + rb_errors = rb_ary_new(); + + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + xmlRelaxNGSetParserStructuredErrors( + c_parser_context, + noko__error_array_pusher, + (void *)rb_errors + ); + + c_schema = xmlRelaxNGParse(c_parser_context); + + xmlRelaxNGFreeParserCtxt(c_parser_context); + noko__structured_error_func_restore(&handler_state); + + if (NULL == c_schema) { + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } + } + + rb_schema = TypedData_Wrap_Struct(rb_class, &xml_relax_ng_type, c_schema); + rb_iv_set(rb_schema, "@errors", rb_errors); + rb_iv_set(rb_schema, "@parse_options", rb_parse_options); + + return rb_schema; +} + +/* + * :call-seq: + * from_document(document) → Nokogiri::XML::RelaxNG + * from_document(document, parse_options) → Nokogiri::XML::RelaxNG + * + * Parse a RELAX NG schema definition from a Document to create a new Nokogiri::XML::RelaxNG. + * + * [Parameters] + * - +document+ (XML::Document) A document containing the RELAX NG schema definition + * - +parse_options+ (Nokogiri::XML::ParseOptions) + * Defaults to ParseOptions::DEFAULT_SCHEMA ⚠ Unused + * + * [Returns] Nokogiri::XML::RelaxNG + * + * ⚠ +parse_options+ is currently unused by this method and is present only as a placeholder for + * future functionality. + */ +static VALUE +noko_xml_relax_ng_s_from_document(int argc, VALUE *argv, VALUE rb_class) +{ + /* TODO: deprecate this method and put file-or-string logic into .new so that becomes the + * preferred entry point, and this can become a private method */ + VALUE rb_document; + VALUE rb_parse_options; + xmlDocPtr c_document; + xmlRelaxNGParserCtxtPtr c_parser_context; + + rb_scan_args(argc, argv, "11", &rb_document, &rb_parse_options); + + c_document = noko_xml_document_unwrap(rb_document); + c_document = c_document->doc; /* In case someone passes us a node. ugh. */ + + c_parser_context = xmlRelaxNGNewDocParserCtxt(c_document); + + return _noko_xml_relax_ng_parse_schema(rb_class, c_parser_context, rb_parse_options); +} + +void +noko_init_xml_relax_ng(void) +{ + assert(cNokogiriXmlSchema); + cNokogiriXmlRelaxNG = rb_define_class_under(mNokogiriXml, "RelaxNG", cNokogiriXmlSchema); + + rb_define_singleton_method(cNokogiriXmlRelaxNG, "from_document", noko_xml_relax_ng_s_from_document, -1); + + rb_define_private_method(cNokogiriXmlRelaxNG, "validate_document", noko_xml_relax_ng__validate_document, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser.c new file mode 100644 index 00000000..ec2d2ade --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser.c @@ -0,0 +1,403 @@ +#include + +VALUE cNokogiriXmlSaxParser ; + +static ID id_start_document; +static ID id_end_document; +static ID id_start_element; +static ID id_end_element; +static ID id_start_element_namespace; +static ID id_end_element_namespace; +static ID id_comment; +static ID id_characters; +static ID id_xmldecl; +static ID id_error; +static ID id_warning; +static ID id_cdata_block; +static ID id_processing_instruction; +static ID id_reference; + +static size_t +xml_sax_parser_memsize(const void *data) +{ + return sizeof(xmlSAXHandler); +} + +/* Used by Nokogiri::XML::SAX::Parser and Nokogiri::HTML::SAX::Parser */ +static const rb_data_type_t xml_sax_parser_type = { + .wrap_struct_name = "xmlSAXHandler", + .function = { + .dfree = RUBY_TYPED_DEFAULT_FREE, + .dsize = xml_sax_parser_memsize + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED +}; + +static void +noko_xml_sax_parser_start_document_callback(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + xmlSAX2StartDocument(ctx); + + if (ctxt->standalone != -1) { /* -1 means there was no declaration */ + VALUE encoding = Qnil ; + VALUE standalone = Qnil; + VALUE version; + + if (ctxt->encoding) { + encoding = NOKOGIRI_STR_NEW2(ctxt->encoding) ; + } else if (ctxt->input && ctxt->input->encoding) { // unnecessary after v2.12.0 / gnome/libxml2@ec7be506 + encoding = NOKOGIRI_STR_NEW2(ctxt->input->encoding) ; + } + + version = ctxt->version ? NOKOGIRI_STR_NEW2(ctxt->version) : Qnil; + + /* TODO try using xmlSAX2IsStandalone */ + switch (ctxt->standalone) { + case 0: + standalone = NOKOGIRI_STR_NEW2("no"); + break; + case 1: + standalone = NOKOGIRI_STR_NEW2("yes"); + break; + } + + rb_funcall(doc, id_xmldecl, 3, version, encoding, standalone); + } + + rb_funcall(doc, id_start_document, 0); +} + +static void +noko_xml_sax_parser_end_document_callback(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + rb_funcall(doc, id_end_document, 0); +} + +static void +noko_xml_sax_parser_start_element_callback(void *ctx, const xmlChar *name, const xmlChar **atts) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE attributes = rb_ary_new(); + const xmlChar *attr; + int i = 0; + if (atts) { + while ((attr = atts[i]) != NULL) { + const xmlChar *val = atts[i + 1]; + VALUE value = val != NULL ? NOKOGIRI_STR_NEW2(val) : Qnil; + rb_ary_push(attributes, rb_ary_new3(2, NOKOGIRI_STR_NEW2(attr), value)); + i += 2; + } + } + + rb_funcall(doc, + id_start_element, + 2, + NOKOGIRI_STR_NEW2(name), + attributes + ); +} + +static void +noko_xml_sax_parser_end_element_callback(void *ctx, const xmlChar *name) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + rb_funcall(doc, id_end_element, 1, NOKOGIRI_STR_NEW2(name)); +} + +static VALUE +xml_sax_parser_marshal_attributes(int attributes_len, const xmlChar **c_attributes) +{ + VALUE rb_array = rb_ary_new2((long)attributes_len); + VALUE cNokogiriXmlSaxParserAttribute; + + cNokogiriXmlSaxParserAttribute = rb_const_get_at(cNokogiriXmlSaxParser, rb_intern("Attribute")); + if (c_attributes) { + /* Each attribute is an array of [localname, prefix, URI, value, end] */ + int i; + for (i = 0; i < attributes_len * 5; i += 5) { + VALUE rb_constructor_args[4], rb_attribute; + + rb_constructor_args[0] = RBSTR_OR_QNIL(c_attributes[i + 0]); /* localname */ + rb_constructor_args[1] = RBSTR_OR_QNIL(c_attributes[i + 1]); /* prefix */ + rb_constructor_args[2] = RBSTR_OR_QNIL(c_attributes[i + 2]); /* URI */ + + /* value */ + rb_constructor_args[3] = NOKOGIRI_STR_NEW((const char *)c_attributes[i + 3], + (c_attributes[i + 4] - c_attributes[i + 3])); + + rb_attribute = rb_class_new_instance(4, rb_constructor_args, cNokogiriXmlSaxParserAttribute); + rb_ary_push(rb_array, rb_attribute); + } + } + + return rb_array; +} + +static void +noko_xml_sax_parser_start_element_ns_callback( + void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *uri, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE attribute_ary = xml_sax_parser_marshal_attributes(nb_attributes, attributes); + + VALUE ns_list = rb_ary_new2((long)nb_namespaces); + + if (namespaces) { + int i; + for (i = 0; i < nb_namespaces * 2; i += 2) { + rb_ary_push(ns_list, + rb_ary_new3((long)2, + RBSTR_OR_QNIL(namespaces[i + 0]), + RBSTR_OR_QNIL(namespaces[i + 1]) + ) + ); + } + } + + rb_funcall(doc, + id_start_element_namespace, + 5, + NOKOGIRI_STR_NEW2(localname), + attribute_ary, + RBSTR_OR_QNIL(prefix), + RBSTR_OR_QNIL(uri), + ns_list + ); +} + +/** + * end_element_ns was borrowed heavily from libxml-ruby. + */ +static void +noko_xml_sax_parser_end_element_ns_callback( + void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *uri) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + rb_funcall(doc, id_end_element_namespace, 3, + NOKOGIRI_STR_NEW2(localname), + RBSTR_OR_QNIL(prefix), + RBSTR_OR_QNIL(uri) + ); +} + +static void +noko_xml_sax_parser_characters_callback(void *ctx, const xmlChar *ch, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE str = NOKOGIRI_STR_NEW(ch, len); + rb_funcall(doc, id_characters, 1, str); +} + +static void +noko_xml_sax_parser_comment_callback(void *ctx, const xmlChar *value) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE str = NOKOGIRI_STR_NEW2(value); + rb_funcall(doc, id_comment, 1, str); +} + +PRINTFLIKE_DECL(2, 3) +static void +noko_xml_sax_parser_warning_callback(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE rb_message; + +#ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES + /* It is not currently possible to pass var args from native + functions to sulong, so we work around the issue here. */ + rb_message = rb_sprintf("warning_func: %s", msg); +#else + va_list args; + va_start(args, msg); + rb_message = rb_vsprintf(msg, args); + va_end(args); +#endif + + rb_funcall(doc, id_warning, 1, rb_message); +} + +PRINTFLIKE_DECL(2, 3) +static void +noko_xml_sax_parser_error_callback(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE rb_message; + +#ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES + /* It is not currently possible to pass var args from native + functions to sulong, so we work around the issue here. */ + rb_message = rb_sprintf("error_func: %s", msg); +#else + va_list args; + va_start(args, msg); + rb_message = rb_vsprintf(msg, args); + va_end(args); +#endif + + rb_funcall(doc, id_error, 1, rb_message); +} + +static void +noko_xml_sax_parser_cdata_block_callback(void *ctx, const xmlChar *value, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE string = NOKOGIRI_STR_NEW(value, len); + rb_funcall(doc, id_cdata_block, 1, string); +} + +static void +noko_xml_sax_parser_processing_instruction_callback(void *ctx, const xmlChar *name, const xmlChar *content) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + VALUE rb_content = content ? NOKOGIRI_STR_NEW2(content) : Qnil; + + rb_funcall(doc, + id_processing_instruction, + 2, + NOKOGIRI_STR_NEW2(name), + rb_content + ); +} + +static void +noko_xml_sax_parser_reference_callback(void *ctx, const xmlChar *name) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx; + xmlEntityPtr entity = xmlSAX2GetEntity(ctxt, name); + + VALUE self = (VALUE)ctxt->_private; + VALUE doc = rb_iv_get(self, "@document"); + + if (entity && entity->content) { + rb_funcall(doc, id_reference, 2, NOKOGIRI_STR_NEW2(entity->name), NOKOGIRI_STR_NEW2(entity->content)); + } else { + rb_funcall(doc, id_reference, 2, NOKOGIRI_STR_NEW2(name), Qnil); + } +} + +static VALUE +noko_xml_sax_parser__initialize_native(VALUE self) +{ + xmlSAXHandlerPtr handler = noko_xml_sax_parser_unwrap(self); + + handler->startDocument = noko_xml_sax_parser_start_document_callback; + handler->endDocument = noko_xml_sax_parser_end_document_callback; + handler->startElement = noko_xml_sax_parser_start_element_callback; + handler->endElement = noko_xml_sax_parser_end_element_callback; + handler->startElementNs = noko_xml_sax_parser_start_element_ns_callback; + handler->endElementNs = noko_xml_sax_parser_end_element_ns_callback; + handler->characters = noko_xml_sax_parser_characters_callback; + handler->comment = noko_xml_sax_parser_comment_callback; + handler->warning = noko_xml_sax_parser_warning_callback; + handler->error = noko_xml_sax_parser_error_callback; + handler->cdataBlock = noko_xml_sax_parser_cdata_block_callback; + handler->processingInstruction = noko_xml_sax_parser_processing_instruction_callback; + handler->reference = noko_xml_sax_parser_reference_callback; + + /* use some of libxml2's default callbacks to managed DTDs and entities */ + handler->getEntity = xmlSAX2GetEntity; + handler->internalSubset = xmlSAX2InternalSubset; + handler->externalSubset = xmlSAX2ExternalSubset; + handler->isStandalone = xmlSAX2IsStandalone; + handler->hasInternalSubset = xmlSAX2HasInternalSubset; + handler->hasExternalSubset = xmlSAX2HasExternalSubset; + handler->resolveEntity = xmlSAX2ResolveEntity; + handler->getParameterEntity = xmlSAX2GetParameterEntity; + handler->entityDecl = xmlSAX2EntityDecl; + handler->unparsedEntityDecl = xmlSAX2UnparsedEntityDecl; + + handler->initialized = XML_SAX2_MAGIC; + + return self; +} + +static VALUE +noko_xml_sax_parser_allocate(VALUE klass) +{ + xmlSAXHandlerPtr handler; + return TypedData_Make_Struct(klass, xmlSAXHandler, &xml_sax_parser_type, handler); +} + +xmlSAXHandlerPtr +noko_xml_sax_parser_unwrap(VALUE rb_sax_handler) +{ + xmlSAXHandlerPtr c_sax_handler; + TypedData_Get_Struct(rb_sax_handler, xmlSAXHandler, &xml_sax_parser_type, c_sax_handler); + return c_sax_handler; +} + +void +noko_init_xml_sax_parser(void) +{ + cNokogiriXmlSaxParser = rb_define_class_under(mNokogiriXmlSax, "Parser", rb_cObject); + + rb_define_alloc_func(cNokogiriXmlSaxParser, noko_xml_sax_parser_allocate); + + rb_define_private_method(cNokogiriXmlSaxParser, "initialize_native", + noko_xml_sax_parser__initialize_native, 0); + + id_start_document = rb_intern("start_document"); + id_end_document = rb_intern("end_document"); + id_start_element = rb_intern("start_element"); + id_end_element = rb_intern("end_element"); + id_comment = rb_intern("comment"); + id_characters = rb_intern("characters"); + id_xmldecl = rb_intern("xmldecl"); + id_error = rb_intern("error"); + id_warning = rb_intern("warning"); + id_cdata_block = rb_intern("cdata_block"); + id_start_element_namespace = rb_intern("start_element_namespace"); + id_end_element_namespace = rb_intern("end_element_namespace"); + id_processing_instruction = rb_intern("processing_instruction"); + id_reference = rb_intern("reference"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser_context.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser_context.c new file mode 100644 index 00000000..0d2b65b5 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_parser_context.c @@ -0,0 +1,396 @@ +#include + +VALUE cNokogiriXmlSaxParserContext ; + +static ID id_read; + +static void +xml_sax_parser_context_type_free(void *data) +{ + xmlParserCtxtPtr ctxt = data; + ctxt->sax = NULL; + if (ctxt->myDoc) { + xmlFreeDoc(ctxt->myDoc); + } + if (ctxt) { + xmlFreeParserCtxt(ctxt); + } +} + +/* + * note that htmlParserCtxtPtr == xmlParserCtxtPtr and xmlFreeParserCtxt() == htmlFreeParserCtxt() + * so we use this type for both XML::SAX::ParserContext and HTML::SAX::ParserContext + */ +static const rb_data_type_t xml_sax_parser_context_type = { + .wrap_struct_name = "xmlParserCtxt", + .function = { + .dfree = xml_sax_parser_context_type_free, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +xmlParserCtxtPtr +noko_xml_sax_parser_context_unwrap(VALUE rb_context) +{ + xmlParserCtxtPtr c_context; + TypedData_Get_Struct(rb_context, xmlParserCtxt, &xml_sax_parser_context_type, c_context); + return c_context; +} + +VALUE +noko_xml_sax_parser_context_wrap(VALUE klass, xmlParserCtxtPtr c_context) +{ + return TypedData_Wrap_Struct(klass, &xml_sax_parser_context_type, c_context); +} + +void +noko_xml_sax_parser_context_set_encoding(xmlParserCtxtPtr c_context, VALUE rb_encoding) +{ + if (!NIL_P(rb_encoding)) { + VALUE rb_encoding_name = rb_funcall(rb_encoding, rb_intern("name"), 0); + + char *encoding_name = StringValueCStr(rb_encoding_name); + if (encoding_name) { + libxmlStructuredErrorHandlerState handler_state; + VALUE rb_errors = rb_ary_new(); + + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + int result = xmlSwitchEncodingName(c_context, encoding_name); + + noko__structured_error_func_restore(&handler_state); + + if (result != 0) { + xmlFreeParserCtxt(c_context); + + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (!NIL_P(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "could not set encoding"); + } + } + } + } +} + +/* :nodoc: */ +static VALUE +noko_xml_sax_parser_context_s_native_io(VALUE rb_class, VALUE rb_io, VALUE rb_encoding) +{ + if (!rb_respond_to(rb_io, id_read)) { + rb_raise(rb_eTypeError, "argument expected to respond to :read"); + } + + if (!NIL_P(rb_encoding) && !rb_obj_is_kind_of(rb_encoding, rb_cEncoding)) { + rb_raise(rb_eTypeError, "argument must be an Encoding object"); + } + + xmlParserCtxtPtr c_context = + xmlCreateIOParserCtxt(NULL, NULL, + (xmlInputReadCallback)noko_io_read, + (xmlInputCloseCallback)noko_io_close, + (void *)rb_io, XML_CHAR_ENCODING_NONE); + if (!c_context) { + rb_raise(rb_eRuntimeError, "failed to create xml sax parser context"); + } + + noko_xml_sax_parser_context_set_encoding(c_context, rb_encoding); + + if (c_context->sax) { + xmlFree(c_context->sax); + c_context->sax = NULL; + } + + VALUE rb_context = noko_xml_sax_parser_context_wrap(rb_class, c_context); + rb_iv_set(rb_context, "@input", rb_io); + + return rb_context; +} + +/* :nodoc: */ +static VALUE +noko_xml_sax_parser_context_s_native_file(VALUE rb_class, VALUE rb_path, VALUE rb_encoding) +{ + if (!NIL_P(rb_encoding) && !rb_obj_is_kind_of(rb_encoding, rb_cEncoding)) { + rb_raise(rb_eTypeError, "argument must be an Encoding object"); + } + + xmlParserCtxtPtr c_context = xmlCreateFileParserCtxt(StringValueCStr(rb_path)); + if (!c_context) { + rb_raise(rb_eRuntimeError, "failed to create xml sax parser context"); + } + + noko_xml_sax_parser_context_set_encoding(c_context, rb_encoding); + + if (c_context->sax) { + xmlFree(c_context->sax); + c_context->sax = NULL; + } + + return noko_xml_sax_parser_context_wrap(rb_class, c_context); +} + +/* :nodoc: */ +static VALUE +noko_xml_sax_parser_context_s_native_memory(VALUE rb_class, VALUE rb_input, VALUE rb_encoding) +{ + Check_Type(rb_input, T_STRING); + if (!(int)RSTRING_LEN(rb_input)) { + rb_raise(rb_eRuntimeError, "input string cannot be empty"); + } + + if (!NIL_P(rb_encoding) && !rb_obj_is_kind_of(rb_encoding, rb_cEncoding)) { + rb_raise(rb_eTypeError, "argument must be an Encoding object"); + } + + xmlParserCtxtPtr c_context = + xmlCreateMemoryParserCtxt(StringValuePtr(rb_input), (int)RSTRING_LEN(rb_input)); + if (!c_context) { + rb_raise(rb_eRuntimeError, "failed to create xml sax parser context"); + } + + noko_xml_sax_parser_context_set_encoding(c_context, rb_encoding); + + if (c_context->sax) { + xmlFree(c_context->sax); + c_context->sax = NULL; + } + + VALUE rb_context = noko_xml_sax_parser_context_wrap(rb_class, c_context); + rb_iv_set(rb_context, "@input", rb_input); + + return rb_context; +} + +/* + * call-seq: + * parse_with(sax_handler) + * + * Use +sax_handler+ and parse the current document + * + * 💡 Calling this method directly is discouraged. Use Nokogiri::XML::SAX::Parser methods which are + * more convenient for most use cases. + */ +static VALUE +noko_xml_sax_parser_context__parse_with(VALUE rb_context, VALUE rb_sax_parser) +{ + xmlParserCtxtPtr c_context; + xmlSAXHandlerPtr sax; + + if (!rb_obj_is_kind_of(rb_sax_parser, cNokogiriXmlSaxParser)) { + rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::SAX::Parser"); + } + + c_context = noko_xml_sax_parser_context_unwrap(rb_context); + sax = noko_xml_sax_parser_unwrap(rb_sax_parser); + + c_context->sax = sax; + c_context->userData = c_context; /* so we can use libxml2/SAX2.c handlers if we want to */ + c_context->_private = (void *)rb_sax_parser; + + xmlSetStructuredErrorFunc(NULL, NULL); + + /* although we're calling back into Ruby here, we don't need to worry about exceptions, because we + * don't have any cleanup to do. The only memory we need to free is handled by + * xml_sax_parser_context_type_free */ + xmlParseDocument(c_context); + + return Qnil; +} + +/* + * call-seq: + * replace_entities=(value) + * + * See Document@Entity+Handling for an explanation of the behavior controlled by this flag. + * + * [Parameters] + * - +value+ (Boolean) Whether external parsed entities will be resolved. + * + * ⚠ It is UNSAFE to set this option to +true+ when parsing untrusted documents. The option + * defaults to +false+ for this reason. + * + * This option is perhaps misnamed by the libxml2 author, since it controls resolution and not + * replacement. + * + * [Example] + * Because this class is generally not instantiated directly, you would typically set this option + * via the block argument to Nokogiri::XML::SAX::Parser.parse et al: + * + * parser = Nokogiri::XML::SAX::Parser.new(document_handler) + * parser.parse(xml) do |ctx| + * ctx.replace_entities = true # this is UNSAFE for untrusted documents! + * end + */ +static VALUE +noko_xml_sax_parser_context__replace_entities_set(VALUE rb_context, VALUE rb_value) +{ + int error; + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + + if (RB_TEST(rb_value)) { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) | XML_PARSE_NOENT); + } else { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) & ~XML_PARSE_NOENT); + } + + if (error) { + rb_raise(rb_eRuntimeError, "failed to set parser context options (%x)", error); + } + + return rb_value; +} + +/* + * call-seq: + * replace_entities + * + * See Document@Entity+Handling for an explanation of the behavior controlled by this flag. + * + * [Returns] (Boolean) Value of the parse option. (Default +false+) + * + * This option is perhaps misnamed by the libxml2 author, since it controls resolution and not + * replacement. + */ +static VALUE +noko_xml_sax_parser_context__replace_entities_get(VALUE rb_context) +{ + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + + if (xmlCtxtGetOptions(ctxt) & XML_PARSE_NOENT) { + return Qtrue; + } else { + return Qfalse; + } +} + +/* + * call-seq: line + * + * [Returns] (Integer) the line number of the line being currently parsed. + */ +static VALUE +noko_xml_sax_parser_context__line(VALUE rb_context) +{ + xmlParserInputPtr io; + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + + io = ctxt->input; + if (io) { + return INT2NUM(io->line); + } + + return Qnil; +} + +/* + * call-seq: column + * + * [Returns] (Integer) the column number of the column being currently parsed. + */ +static VALUE +noko_xml_sax_parser_context__column(VALUE rb_context) +{ + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + xmlParserInputPtr io; + + io = ctxt->input; + if (io) { + return INT2NUM(io->col); + } + + return Qnil; +} + +/* + * call-seq: + * recovery=(value) + * + * Controls whether this parser will recover from parsing errors. If set to +true+, the parser will + * invoke the SAX::Document#error callback and continue processing the file. If set to +false+, the + * parser will stop processing the file on the first parsing error. + * + * [Parameters] + * - +value+ (Boolean) Recover from parsing errors. (Default is +false+ for XML and +true+ for HTML.) + * + * [Returns] (Boolean) The passed +value+. + * + * [Example] + * Because this class is generally not instantiated directly, you would typically set this option + * via the block argument to Nokogiri::XML::SAX::Parser.parse et al: + * + * parser = Nokogiri::XML::SAX::Parser.new(document_handler) + * parser.parse(xml) do |ctx| + * ctx.recovery = true + * end + */ +static VALUE +noko_xml_sax_parser_context__recovery_set(VALUE rb_context, VALUE rb_value) +{ + int error; + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + + if (RB_TEST(rb_value)) { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) | XML_PARSE_RECOVER); + } else { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) & ~XML_PARSE_RECOVER); + } + + if (error) { + rb_raise(rb_eRuntimeError, "failed to set parser context options (%x)", error); + } + + return rb_value; +} + +/* + * call-seq: + * recovery + * + * Inspect whether this parser will recover from parsing errors. If set to +true+, the parser will + * invoke the SAX::Document#error callback and continue processing the file. If set to +false+, the + * parser will stop processing the file on the first parsing error. + * + * [Returns] (Boolean) Whether this parser will recover from parsing errors. + * + * Default is +false+ for XML and +true+ for HTML. + */ +static VALUE +noko_xml_sax_parser_context__recovery_get(VALUE rb_context) +{ + xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(rb_context); + + if (xmlCtxtGetOptions(ctxt) & XML_PARSE_RECOVER) { + return Qtrue; + } else { + return Qfalse; + } +} + +void +noko_init_xml_sax_parser_context(void) +{ + cNokogiriXmlSaxParserContext = rb_define_class_under(mNokogiriXmlSax, "ParserContext", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlSaxParserContext); + + rb_define_singleton_method(cNokogiriXmlSaxParserContext, "native_io", + noko_xml_sax_parser_context_s_native_io, 2); + rb_define_singleton_method(cNokogiriXmlSaxParserContext, "native_memory", + noko_xml_sax_parser_context_s_native_memory, 2); + rb_define_singleton_method(cNokogiriXmlSaxParserContext, "native_file", + noko_xml_sax_parser_context_s_native_file, 2); + + rb_define_method(cNokogiriXmlSaxParserContext, "parse_with", noko_xml_sax_parser_context__parse_with, 1); + rb_define_method(cNokogiriXmlSaxParserContext, "replace_entities=", + noko_xml_sax_parser_context__replace_entities_set, 1); + rb_define_method(cNokogiriXmlSaxParserContext, "replace_entities", + noko_xml_sax_parser_context__replace_entities_get, 0); + rb_define_method(cNokogiriXmlSaxParserContext, "recovery=", noko_xml_sax_parser_context__recovery_set, 1); + rb_define_method(cNokogiriXmlSaxParserContext, "recovery", noko_xml_sax_parser_context__recovery_get, 0); + rb_define_method(cNokogiriXmlSaxParserContext, "line", noko_xml_sax_parser_context__line, 0); + rb_define_method(cNokogiriXmlSaxParserContext, "column", noko_xml_sax_parser_context__column, 0); + + id_read = rb_intern("read"); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_push_parser.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_push_parser.c new file mode 100644 index 00000000..e6bffbfe --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_sax_push_parser.c @@ -0,0 +1,206 @@ +#include + +VALUE cNokogiriXmlSaxPushParser ; + +static void +xml_sax_push_parser_free(void *data) +{ + xmlParserCtxtPtr ctx = data; + if (ctx->myDoc) { + xmlFreeDoc(ctx->myDoc); + } + if (ctx) { + xmlFreeParserCtxt(ctx); + } +} + +static const rb_data_type_t xml_sax_push_parser_type = { + .wrap_struct_name = "xmlParserCtxt", + .function = { + .dfree = xml_sax_push_parser_free, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +xml_sax_push_parser_allocate(VALUE klass) +{ + return TypedData_Wrap_Struct(klass, &xml_sax_push_parser_type, NULL); +} + +xmlParserCtxtPtr +noko_xml_sax_push_parser_unwrap(VALUE rb_parser) +{ + xmlParserCtxtPtr c_parser; + TypedData_Get_Struct(rb_parser, xmlParserCtxt, &xml_sax_push_parser_type, c_parser); + return c_parser; +} + +/* + * Write +chunk+ to PushParser. +last_chunk+ triggers the end_document handle + */ +static VALUE +noko_xml_sax_push_parser__native_write(VALUE self, VALUE _chunk, VALUE _last_chunk) +{ + xmlParserCtxtPtr ctx; + const char *chunk = NULL; + int size = 0; + + ctx = noko_xml_sax_push_parser_unwrap(self); + + if (Qnil != _chunk) { + chunk = StringValuePtr(_chunk); + size = (int)RSTRING_LEN(_chunk); + } + + xmlSetStructuredErrorFunc(NULL, NULL); + + if (xmlParseChunk(ctx, chunk, size, Qtrue == _last_chunk ? 1 : 0)) { + if (!(xmlCtxtGetOptions(ctx) & XML_PARSE_RECOVER)) { + xmlErrorConstPtr e = xmlCtxtGetLastError(ctx); + noko__error_raise(NULL, e); + } + } + + return self; +} + +/* + * call-seq: + * initialize_native(xml_sax, filename) + * + * Initialize the push parser with +xml_sax+ using +filename+ + */ +static VALUE +noko_xml_sax_push_parser__initialize_native(VALUE self, VALUE _xml_sax, VALUE _filename) +{ + xmlSAXHandlerPtr sax; + const char *filename = NULL; + xmlParserCtxtPtr ctx; + + sax = noko_xml_sax_parser_unwrap(_xml_sax); + + if (_filename != Qnil) { filename = StringValueCStr(_filename); } + + ctx = xmlCreatePushParserCtxt( + sax, + NULL, + NULL, + 0, + filename + ); + if (ctx == NULL) { + rb_raise(rb_eRuntimeError, "Could not create a parser context"); + } + + ctx->userData = ctx; + ctx->_private = (void *)_xml_sax; + + DATA_PTR(self) = ctx; + return self; +} + +static VALUE +noko_xml_sax_push_parser__options_get(VALUE self) +{ + xmlParserCtxtPtr ctx; + + ctx = noko_xml_sax_push_parser_unwrap(self); + + return INT2NUM(xmlCtxtGetOptions(ctx)); +} + +static VALUE +noko_xml_sax_push_parser__options_set(VALUE self, VALUE options) +{ + int error; + xmlParserCtxtPtr ctx; + + ctx = noko_xml_sax_push_parser_unwrap(self); + + error = xmlCtxtSetOptions(ctx, (int)NUM2INT(options)); + if (error) { + rb_raise(rb_eRuntimeError, "Cannot set XML parser context options (%x)", error); + } + + return Qnil; +} + +/* + * call-seq: + * replace_entities + * + * See Document@Entity+Handling for an explanation of the behavior controlled by this flag. + * + * [Returns] (Boolean) Value of the parse option. (Default +false+) + * + * This option is perhaps misnamed by the libxml2 author, since it controls resolution and not + * replacement. + */ +static VALUE +noko_xml_sax_push_parser__replace_entities_get(VALUE self) +{ + xmlParserCtxtPtr ctxt = noko_xml_sax_push_parser_unwrap(self); + + if (xmlCtxtGetOptions(ctxt) & XML_PARSE_NOENT) { + return Qtrue; + } else { + return Qfalse; + } +} + +/* + * call-seq: + * replace_entities=(value) + * + * See Document@Entity+Handling for an explanation of the behavior controlled by this flag. + * + * [Parameters] + * - +value+ (Boolean) Whether external parsed entities will be resolved. + * + * ⚠ It is UNSAFE to set this option to +true+ when parsing untrusted documents. The option + * defaults to +false+ for this reason. + * + * This option is perhaps misnamed by the libxml2 author, since it controls resolution and not + * replacement. + */ +static VALUE +noko_xml_sax_push_parser__replace_entities_set(VALUE self, VALUE value) +{ + int error; + xmlParserCtxtPtr ctxt = noko_xml_sax_push_parser_unwrap(self); + + if (RB_TEST(value)) { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) | XML_PARSE_NOENT); + } else { + error = xmlCtxtSetOptions(ctxt, xmlCtxtGetOptions(ctxt) & ~XML_PARSE_NOENT); + } + + if (error) { + rb_raise(rb_eRuntimeError, "failed to set parser context options (%x)", error); + } + + return value; +} + +void +noko_init_xml_sax_push_parser(void) +{ + cNokogiriXmlSaxPushParser = rb_define_class_under(mNokogiriXmlSax, "PushParser", rb_cObject); + + rb_define_alloc_func(cNokogiriXmlSaxPushParser, xml_sax_push_parser_allocate); + + rb_define_method(cNokogiriXmlSaxPushParser, "options", + noko_xml_sax_push_parser__options_get, 0); + rb_define_method(cNokogiriXmlSaxPushParser, "options=", + noko_xml_sax_push_parser__options_set, 1); + rb_define_method(cNokogiriXmlSaxPushParser, "replace_entities", + noko_xml_sax_push_parser__replace_entities_get, 0); + rb_define_method(cNokogiriXmlSaxPushParser, "replace_entities=", + noko_xml_sax_push_parser__replace_entities_set, 1); + + rb_define_private_method(cNokogiriXmlSaxPushParser, "initialize_native", + noko_xml_sax_push_parser__initialize_native, 2); + rb_define_private_method(cNokogiriXmlSaxPushParser, "native_write", + noko_xml_sax_push_parser__native_write, 2); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_schema.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_schema.c new file mode 100644 index 00000000..b2bded98 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_schema.c @@ -0,0 +1,226 @@ +#include + +VALUE cNokogiriXmlSchema; + +static void +xml_schema_deallocate(void *data) +{ + xmlSchemaPtr schema = data; + xmlSchemaFree(schema); +} + +static const rb_data_type_t xml_schema_type = { + .wrap_struct_name = "xmlSchema", + .function = { + .dfree = xml_schema_deallocate, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +static VALUE +noko_xml_schema__validate_document(VALUE self, VALUE document) +{ + xmlDocPtr doc; + xmlSchemaPtr schema; + xmlSchemaValidCtxtPtr valid_ctxt; + VALUE errors; + + TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema); + doc = noko_xml_document_unwrap(document); + + errors = rb_ary_new(); + + valid_ctxt = xmlSchemaNewValidCtxt(schema); + + if (NULL == valid_ctxt) { + /* we have a problem */ + rb_raise(rb_eRuntimeError, "Could not create a validation context"); + } + + xmlSchemaSetValidStructuredErrors( + valid_ctxt, + noko__error_array_pusher, + (void *)errors + ); + + int status = xmlSchemaValidateDoc(valid_ctxt, doc); + + xmlSchemaFreeValidCtxt(valid_ctxt); + + if (status != 0) { + if (RARRAY_LEN(errors) == 0) { + rb_ary_push(errors, rb_str_new2("Could not validate document")); + } + } + + return errors; +} + +static VALUE +noko_xml_schema__validate_file(VALUE self, VALUE rb_filename) +{ + xmlSchemaPtr schema; + xmlSchemaValidCtxtPtr valid_ctxt; + const char *filename ; + VALUE errors; + + TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema); + filename = (const char *)StringValueCStr(rb_filename) ; + + errors = rb_ary_new(); + + valid_ctxt = xmlSchemaNewValidCtxt(schema); + + if (NULL == valid_ctxt) { + /* we have a problem */ + rb_raise(rb_eRuntimeError, "Could not create a validation context"); + } + + xmlSchemaSetValidStructuredErrors( + valid_ctxt, + noko__error_array_pusher, + (void *)errors + ); + + int status = xmlSchemaValidateFile(valid_ctxt, filename, 0); + + xmlSchemaFreeValidCtxt(valid_ctxt); + + if (status != 0) { + if (RARRAY_LEN(errors) == 0) { + rb_ary_push(errors, rb_str_new2("Could not validate file.")); + } + } + + return errors; +} + +static VALUE +xml_schema_parse_schema( + VALUE rb_class, + xmlSchemaParserCtxtPtr c_parser_context, + VALUE rb_parse_options +) +{ + xmlExternalEntityLoader saved_loader = 0; + libxmlStructuredErrorHandlerState handler_state; + + if (NIL_P(rb_parse_options)) { + rb_parse_options = rb_const_get_at( + rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), + rb_intern("DEFAULT_SCHEMA") + ); + } + int c_parse_options = (int)NUM2INT(rb_funcall(rb_parse_options, rb_intern("to_i"), 0)); + + VALUE rb_errors = rb_ary_new(); + noko__structured_error_func_save_and_set(&handler_state, (void *)rb_errors, noko__error_array_pusher); + + xmlSchemaSetParserStructuredErrors( + c_parser_context, + noko__error_array_pusher, + (void *)rb_errors + ); + + if (c_parse_options & XML_PARSE_NONET) { + saved_loader = xmlGetExternalEntityLoader(); + xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader); + } + + xmlSchemaPtr c_schema = xmlSchemaParse(c_parser_context); + + if (saved_loader) { + xmlSetExternalEntityLoader(saved_loader); + } + + xmlSchemaFreeParserCtxt(c_parser_context); + noko__structured_error_func_restore(&handler_state); + + if (NULL == c_schema) { + VALUE exception = rb_funcall(cNokogiriXmlSyntaxError, rb_intern("aggregate"), 1, rb_errors); + if (RB_TEST(exception)) { + rb_exc_raise(exception); + } else { + rb_raise(rb_eRuntimeError, "Could not parse document"); + } + } + + VALUE rb_schema = TypedData_Wrap_Struct(rb_class, &xml_schema_type, c_schema); + rb_iv_set(rb_schema, "@errors", rb_errors); + rb_iv_set(rb_schema, "@parse_options", rb_parse_options); + + return rb_schema; +} + +/* + * :call-seq: + * from_document(input) → Nokogiri::XML::Schema + * from_document(input, parse_options) → Nokogiri::XML::Schema + * + * Parse an \XSD schema definition from a Document to create a new Nokogiri::XML::Schema + * + * [Parameters] + * - +input+ (XML::Document) A document containing the \XSD schema definition + * - +parse_options+ (Nokogiri::XML::ParseOptions) + * Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA + * + * [Returns] Nokogiri::XML::Schema + */ +static VALUE +noko_xml_schema_s_from_document(int argc, VALUE *argv, VALUE rb_class) +{ + /* TODO: deprecate this method and put file-or-string logic into .new so that becomes the + * preferred entry point, and this can become a private method */ + VALUE rb_document; + VALUE rb_parse_options; + VALUE rb_schema; + xmlDocPtr c_document; + xmlSchemaParserCtxtPtr c_parser_context; + int defensive_copy_p = 0; + + rb_scan_args(argc, argv, "11", &rb_document, &rb_parse_options); + + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) { + rb_raise(rb_eTypeError, + "expected parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE, + rb_obj_class(rb_document)); + } + + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) { + xmlNodePtr deprecated_node_type_arg; + NOKO_WARN_DEPRECATION("Passing a Node as the first parameter to Schema.from_document is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0 + Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg); + c_document = deprecated_node_type_arg->doc; + } else { + c_document = noko_xml_document_unwrap(rb_document); + } + + if (noko_xml_document_has_wrapped_blank_nodes_p(c_document)) { + // see https://github.com/sparklemotion/nokogiri/pull/2001 + c_document = xmlCopyDoc(c_document, 1); + defensive_copy_p = 1; + } + + c_parser_context = xmlSchemaNewDocParserCtxt(c_document); + rb_schema = xml_schema_parse_schema(rb_class, c_parser_context, rb_parse_options); + + if (defensive_copy_p) { + xmlFreeDoc(c_document); + c_document = NULL; + } + + return rb_schema; +} + +void +noko_init_xml_schema(void) +{ + cNokogiriXmlSchema = rb_define_class_under(mNokogiriXml, "Schema", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlSchema); + + rb_define_singleton_method(cNokogiriXmlSchema, "from_document", noko_xml_schema_s_from_document, -1); + + rb_define_private_method(cNokogiriXmlSchema, "validate_document", noko_xml_schema__validate_document, 1); + rb_define_private_method(cNokogiriXmlSchema, "validate_file", noko_xml_schema__validate_file, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_syntax_error.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_syntax_error.c new file mode 100644 index 00000000..d0a3bf8d --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_syntax_error.c @@ -0,0 +1,93 @@ +#include + +VALUE cNokogiriXmlSyntaxError; + +void +noko__structured_error_func_save(libxmlStructuredErrorHandlerState *handler_state) +{ + /* this method is tightly coupled to the implementation of xmlSetStructuredErrorFunc */ + handler_state->user_data = xmlStructuredErrorContext; + handler_state->handler = xmlStructuredError; +} + +void +noko__structured_error_func_save_and_set( + libxmlStructuredErrorHandlerState *handler_state, + void *user_data, + xmlStructuredErrorFunc handler +) +{ + noko__structured_error_func_save(handler_state); + xmlSetStructuredErrorFunc(user_data, handler); +} + +void +noko__structured_error_func_restore(libxmlStructuredErrorHandlerState *handler_state) +{ + xmlSetStructuredErrorFunc(handler_state->user_data, handler_state->handler); +} + +void +noko__error_array_pusher(void *ctx, xmlErrorConstPtr error) +{ + VALUE list = (VALUE)ctx; + Check_Type(list, T_ARRAY); + rb_ary_push(list, noko_xml_syntax_error__wrap(error)); +} + +void +noko__error_raise(void *ctx, xmlErrorConstPtr error) +{ + rb_exc_raise(noko_xml_syntax_error__wrap(error)); +} + +VALUE +noko_xml_syntax_error__wrap(xmlErrorConstPtr error) +{ + xmlChar *c_path ; + VALUE msg, e, klass; + + klass = cNokogiriXmlSyntaxError; + + if (error && error->domain == XML_FROM_XPATH) { + klass = cNokogiriXmlXpathSyntaxError; + } + + msg = (error && error->message) ? NOKOGIRI_STR_NEW2(error->message) : Qnil; + + e = rb_class_new_instance( + 1, + &msg, + klass + ); + + if (error) { + c_path = xmlGetNodePath(error->node); + + rb_iv_set(e, "@domain", INT2NUM(error->domain)); + rb_iv_set(e, "@code", INT2NUM(error->code)); + rb_iv_set(e, "@level", INT2NUM((short)error->level)); + rb_iv_set(e, "@file", RBSTR_OR_QNIL(error->file)); + rb_iv_set(e, "@line", INT2NUM(error->line)); + rb_iv_set(e, "@path", RBSTR_OR_QNIL(c_path)); + rb_iv_set(e, "@str1", RBSTR_OR_QNIL(error->str1)); + rb_iv_set(e, "@str2", RBSTR_OR_QNIL(error->str2)); + rb_iv_set(e, "@str3", RBSTR_OR_QNIL(error->str3)); + rb_iv_set(e, "@int1", INT2NUM(error->int1)); + rb_iv_set(e, "@column", INT2NUM(error->int2)); + + xmlFree(c_path); + } + + return e; +} + +void +noko_init_xml_syntax_error(void) +{ + assert(cNokogiriSyntaxError); + /* + * The XML::SyntaxError is raised on parse errors + */ + cNokogiriXmlSyntaxError = rb_define_class_under(mNokogiriXml, "SyntaxError", cNokogiriSyntaxError); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_text.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_text.c new file mode 100644 index 00000000..e15de27f --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_text.c @@ -0,0 +1,59 @@ +#include + +VALUE cNokogiriXmlText ; + +/* + * call-seq: + * new(content, document) + * + * Create a new Text element on the +document+ with +content+ + */ +static VALUE +rb_xml_text_s_new(int argc, VALUE *argv, VALUE klass) +{ + xmlDocPtr c_document; + xmlNodePtr c_node; + VALUE rb_string; + VALUE rb_document; + VALUE rb_rest; + VALUE rb_node; + + rb_scan_args(argc, argv, "2*", &rb_string, &rb_document, &rb_rest); + + Check_Type(rb_string, T_STRING); + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) { + rb_raise(rb_eTypeError, + "expected second parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE, + rb_obj_class(rb_document)); + } + + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) { + xmlNodePtr deprecated_node_type_arg; + NOKO_WARN_DEPRECATION("Passing a Node as the second parameter to Text.new is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0 + Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg); + c_document = deprecated_node_type_arg->doc; + } else { + c_document = noko_xml_document_unwrap(rb_document); + } + + c_node = xmlNewDocText(c_document, (xmlChar *)StringValueCStr(rb_string)); + noko_xml_document_pin_node(c_node); + rb_node = noko_xml_node_wrap(klass, c_node) ; + rb_obj_call_init(rb_node, argc, argv); + + if (rb_block_given_p()) { rb_yield(rb_node); } + + return rb_node; +} + +void +noko_init_xml_text(void) +{ + assert(cNokogiriXmlCharacterData); + /* + * Wraps Text nodes. + */ + cNokogiriXmlText = rb_define_class_under(mNokogiriXml, "Text", cNokogiriXmlCharacterData); + + rb_define_singleton_method(cNokogiriXmlText, "new", rb_xml_text_s_new, -1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_xpath_context.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_xpath_context.c new file mode 100644 index 00000000..8f71c2e3 --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xml_xpath_context.c @@ -0,0 +1,486 @@ +#include + +VALUE cNokogiriXmlXpathContext; + +/* + * these constants have matching declarations in + * ext/java/nokogiri/internals/NokogiriNamespaceContext.java + */ +static const xmlChar *NOKOGIRI_PREFIX = (const xmlChar *)"nokogiri"; +static const xmlChar *NOKOGIRI_URI = (const xmlChar *)"http://www.nokogiri.org/default_ns/ruby/extensions_functions"; +static const xmlChar *NOKOGIRI_BUILTIN_PREFIX = (const xmlChar *)"nokogiri-builtin"; +static const xmlChar *NOKOGIRI_BUILTIN_URI = (const xmlChar *)"https://www.nokogiri.org/default_ns/ruby/builtins"; + +static void +_noko_xml_xpath_context_dfree(void *data) +{ + xmlXPathContextPtr c_context = data; + xmlXPathFreeContext(c_context); +} + +static const rb_data_type_t _noko_xml_xpath_context_type = { + .wrap_struct_name = "xmlXPathContext", + .function = { + .dfree = _noko_xml_xpath_context_dfree, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + +/* find a CSS class in an HTML element's `class` attribute */ +static const xmlChar * +_noko_xml_xpath_context__css_class(const xmlChar *str, const xmlChar *val) +{ + int val_len; + + if (str == NULL) { return (NULL); } + if (val == NULL) { return (NULL); } + + val_len = xmlStrlen(val); + if (val_len == 0) { return (str); } + + while (*str != 0) { + if ((*str == *val) && !xmlStrncmp(str, val, val_len)) { + const xmlChar *next_byte = str + val_len; + + /* only match if the next byte is whitespace or end of string */ + if ((*next_byte == 0) || (IS_BLANK_CH(*next_byte))) { + return ((const xmlChar *)str); + } + } + + /* advance str to whitespace */ + while ((*str != 0) && !IS_BLANK_CH(*str)) { + str++; + } + + /* advance str to start of next word or end of string */ + while ((*str != 0) && IS_BLANK_CH(*str)) { + str++; + } + } + + return (NULL); +} + +/* xmlXPathFunction to wrap _noko_xml_xpath_context__css_class() */ +static void +noko_xml_xpath_context_xpath_func_css_class(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr hay, needle; + + CHECK_ARITY(2); + + CAST_TO_STRING; + needle = valuePop(ctxt); + if ((needle == NULL) || (needle->type != XPATH_STRING)) { + xmlXPathFreeObject(needle); + XP_ERROR(XPATH_INVALID_TYPE); + } + + CAST_TO_STRING; + hay = valuePop(ctxt); + if ((hay == NULL) || (hay->type != XPATH_STRING)) { + xmlXPathFreeObject(hay); + xmlXPathFreeObject(needle); + XP_ERROR(XPATH_INVALID_TYPE); + } + + if (_noko_xml_xpath_context__css_class(hay->stringval, needle->stringval)) { + valuePush(ctxt, xmlXPathNewBoolean(1)); + } else { + valuePush(ctxt, xmlXPathNewBoolean(0)); + } + + xmlXPathFreeObject(hay); + xmlXPathFreeObject(needle); +} + + +/* xmlXPathFunction to select nodes whose local name matches, for HTML5 CSS queries that should + * ignore namespaces */ +static void +noko_xml_xpath_context_xpath_func_local_name_is(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr element_name; + + assert(ctxt->context->node); + + CHECK_ARITY(1); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + element_name = valuePop(ctxt); + + valuePush( + ctxt, + xmlXPathNewBoolean(xmlStrEqual(ctxt->context->node->name, element_name->stringval)) + ); + + xmlXPathFreeObject(element_name); +} + + +/* + * call-seq: + * register_ns(prefix, uri) → Nokogiri::XML::XPathContext + * + * Register the namespace with +prefix+ and +uri+ for use in future queries. + * Passing a uri of +nil+ will unregister the namespace. + * + * [Returns] +self+ + */ +static VALUE +noko_xml_xpath_context_register_ns(VALUE rb_context, VALUE prefix, VALUE uri) +{ + xmlXPathContextPtr c_context; + const xmlChar *ns_uri; + + TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context); + + if (NIL_P(uri)) { + ns_uri = NULL; + } else { + ns_uri = (const xmlChar *)StringValueCStr(uri); + } + + xmlXPathRegisterNs(c_context, (const xmlChar *)StringValueCStr(prefix), ns_uri); + + return rb_context; +} + +/* + * call-seq: + * register_variable(name, value) → Nokogiri::XML::XPathContext + * + * Register the variable +name+ with +value+ for use in future queries. + * Passing a value of +nil+ will unregister the variable. + * + * [Returns] +self+ + */ +static VALUE +noko_xml_xpath_context_register_variable(VALUE rb_context, VALUE name, VALUE value) +{ + xmlXPathContextPtr c_context; + xmlXPathObjectPtr xmlValue; + + TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context); + + if (NIL_P(value)) { + xmlValue = NULL; + } else { + xmlValue = xmlXPathNewCString(StringValueCStr(value)); + } + + xmlXPathRegisterVariable(c_context, (const xmlChar *)StringValueCStr(name), xmlValue); + + return rb_context; +} + + +/* + * convert an XPath object into a Ruby object of the appropriate type. + * returns Qundef if no conversion was possible. + */ +static VALUE +_noko_xml_xpath_context__xpath2ruby(xmlXPathObjectPtr c_xpath_object, xmlXPathContextPtr c_context) +{ + VALUE rb_retval; + + assert(c_context->doc); + assert(DOC_RUBY_OBJECT_TEST(c_context->doc)); + + switch (c_xpath_object->type) { + case XPATH_STRING: + rb_retval = NOKOGIRI_STR_NEW2(c_xpath_object->stringval); + xmlFree(c_xpath_object->stringval); + return rb_retval; + + case XPATH_NODESET: + return noko_xml_node_set_wrap( + c_xpath_object->nodesetval, + DOC_RUBY_OBJECT(c_context->doc) + ); + + case XPATH_NUMBER: + return rb_float_new(c_xpath_object->floatval); + + case XPATH_BOOLEAN: + return (c_xpath_object->boolval == 1) ? Qtrue : Qfalse; + + default: + return Qundef; + } +} + +void +Nokogiri_marshal_xpath_funcall_and_return_values( + xmlXPathParserContextPtr ctxt, + int argc, + VALUE rb_xpath_handler, + const char *method_name +) +{ + VALUE rb_retval; + VALUE *argv; + VALUE rb_node_set = Qnil; + xmlNodeSetPtr c_node_set = NULL; + xmlXPathObjectPtr c_xpath_object; + + assert(ctxt->context->doc); + assert(DOC_RUBY_OBJECT_TEST(ctxt->context->doc)); + + argv = (VALUE *)ruby_xcalloc((size_t)argc, sizeof(VALUE)); + for (int j = 0 ; j < argc ; ++j) { + rb_gc_register_address(&argv[j]); + } + + for (int j = argc - 1 ; j >= 0 ; --j) { + c_xpath_object = valuePop(ctxt); + argv[j] = _noko_xml_xpath_context__xpath2ruby(c_xpath_object, ctxt->context); + if (argv[j] == Qundef) { + argv[j] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(c_xpath_object)); + } + xmlXPathFreeNodeSetList(c_xpath_object); + } + + rb_retval = rb_funcall2( + rb_xpath_handler, + rb_intern((const char *)method_name), + argc, + argv + ); + + for (int j = 0 ; j < argc ; ++j) { + rb_gc_unregister_address(&argv[j]); + } + ruby_xfree(argv); + + switch (TYPE(rb_retval)) { + case T_FLOAT: + case T_BIGNUM: + case T_FIXNUM: + xmlXPathReturnNumber(ctxt, NUM2DBL(rb_retval)); + break; + case T_STRING: + xmlXPathReturnString(ctxt, xmlCharStrdup(StringValueCStr(rb_retval))); + break; + case T_TRUE: + xmlXPathReturnTrue(ctxt); + break; + case T_FALSE: + xmlXPathReturnFalse(ctxt); + break; + case T_NIL: + break; + case T_ARRAY: { + VALUE construct_args[2] = { DOC_RUBY_OBJECT(ctxt->context->doc), rb_retval }; + rb_node_set = rb_class_new_instance(2, construct_args, cNokogiriXmlNodeSet); + c_node_set = noko_xml_node_set_unwrap(rb_node_set); + xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set)); + } + break; + case T_DATA: + if (rb_obj_is_kind_of(rb_retval, cNokogiriXmlNodeSet)) { + c_node_set = noko_xml_node_set_unwrap(rb_retval); + /* Copy the node set, otherwise it will get GC'd. */ + xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set)); + break; + } + default: + rb_raise(rb_eRuntimeError, "Invalid return type"); + } +} + +static void +_noko_xml_xpath_context__handler_invoker(xmlXPathParserContextPtr ctxt, int argc) +{ + VALUE rb_xpath_handler = Qnil; + const char *method_name = NULL ; + + assert(ctxt); + assert(ctxt->context); + assert(ctxt->context->userData); + assert(ctxt->context->function); + + rb_xpath_handler = (VALUE)(ctxt->context->userData); + method_name = (const char *)(ctxt->context->function); + + Nokogiri_marshal_xpath_funcall_and_return_values( + ctxt, + argc, + rb_xpath_handler, + method_name + ); +} + +static xmlXPathFunction +_noko_xml_xpath_context_handler_lookup(void *data, const xmlChar *c_name, const xmlChar *c_ns_uri) +{ + VALUE rb_handler = (VALUE)data; + if (rb_respond_to(rb_handler, rb_intern((const char *)c_name))) { + if (c_ns_uri == NULL) { + NOKO_WARN_DEPRECATION("A custom XPath or CSS handler function named '%s' is being invoked without a namespace. Please update your query to reference this function as 'nokogiri:%s'. Invoking custom handler functions without a namespace is deprecated and will become an error in Nokogiri v1.17.0.", + c_name, c_name); // TODO deprecated in v1.15.0, remove in v1.19.0 + } + return _noko_xml_xpath_context__handler_invoker; + } + + return NULL; +} + +PRINTFLIKE_DECL(2, 3) +static void +_noko_xml_xpath_context__generic_exception_pusher(void *data, const char *msg, ...) +{ + VALUE rb_errors = (VALUE)data; + VALUE rb_message; + VALUE rb_exception; + + Check_Type(rb_errors, T_ARRAY); + +#ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES + /* It is not currently possible to pass var args from native + functions to sulong, so we work around the issue here. */ + rb_message = rb_sprintf("_noko_xml_xpath_context__generic_exception_pusher: %s", msg); +#else + va_list args; + va_start(args, msg); + rb_message = rb_vsprintf(msg, args); + va_end(args); +#endif + + rb_exception = rb_exc_new_str(cNokogiriXmlXpathSyntaxError, rb_message); + rb_ary_push(rb_errors, rb_exception); +} + +/* + * call-seq: + * evaluate(search_path, handler = nil) → Object + * + * Evaluate the +search_path+ query. + * + * [Returns] an object of the appropriate type for the query, which could be +NodeSet+, a +String+, + * a +Float+, or a boolean. + */ +static VALUE +noko_xml_xpath_context_evaluate(int argc, VALUE *argv, VALUE rb_context) +{ + xmlXPathContextPtr c_context; + VALUE rb_expression = Qnil; + VALUE rb_function_lookup_handler = Qnil; + xmlChar *c_expression_str = NULL; + VALUE rb_errors = rb_ary_new(); + xmlXPathObjectPtr c_xpath_object; + VALUE rb_xpath_object = Qnil; + + TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context); + + rb_scan_args(argc, argv, "11", &rb_expression, &rb_function_lookup_handler); + + c_expression_str = (xmlChar *)StringValueCStr(rb_expression); + + if (Qnil != rb_function_lookup_handler) { + /* FIXME: not sure if this is the correct place to shove private data. */ + c_context->userData = (void *)rb_function_lookup_handler; + xmlXPathRegisterFuncLookup( + c_context, + _noko_xml_xpath_context_handler_lookup, + (void *)rb_function_lookup_handler + ); + } + + /* TODO: use xmlXPathSetErrorHandler (as of 2.13.0) */ + xmlSetStructuredErrorFunc((void *)rb_errors, noko__error_array_pusher); + xmlSetGenericErrorFunc((void *)rb_errors, _noko_xml_xpath_context__generic_exception_pusher); + + c_xpath_object = xmlXPathEvalExpression(c_expression_str, c_context); + + xmlSetStructuredErrorFunc(NULL, NULL); + xmlSetGenericErrorFunc(NULL, NULL); + + xmlXPathRegisterFuncLookup(c_context, NULL, NULL); + + if (c_xpath_object == NULL) { + rb_exc_raise(rb_ary_entry(rb_errors, 0)); + } + + rb_xpath_object = _noko_xml_xpath_context__xpath2ruby(c_xpath_object, c_context); + if (rb_xpath_object == Qundef) { + rb_xpath_object = noko_xml_node_set_wrap(NULL, DOC_RUBY_OBJECT(c_context->doc)); + } + + xmlXPathFreeNodeSetList(c_xpath_object); + + return rb_xpath_object; +} + +/* + * call-seq: + * new(node) + * + * Create a new XPathContext with +node+ as the context node. + */ +static VALUE +noko_xml_xpath_context_new(VALUE klass, VALUE rb_node) +{ + xmlNodePtr c_node; + xmlXPathContextPtr c_context; + VALUE rb_context; + + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + +#if LIBXML_VERSION < 21000 + xmlXPathInit(); /* deprecated in 40483d0 */ +#endif + + c_context = xmlXPathNewContext(c_node->doc); + c_context->node = c_node; + + xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI); + xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI); + + xmlXPathRegisterFuncNS(c_context, + (const xmlChar *)"css-class", NOKOGIRI_BUILTIN_URI, + noko_xml_xpath_context_xpath_func_css_class); + xmlXPathRegisterFuncNS(c_context, + (const xmlChar *)"local-name-is", NOKOGIRI_BUILTIN_URI, + noko_xml_xpath_context_xpath_func_local_name_is); + + rb_context = TypedData_Wrap_Struct(klass, &_noko_xml_xpath_context_type, c_context); + + return rb_context; +} + + +/* :nodoc: */ +static VALUE +noko_xml_xpath_context_set_node(VALUE rb_context, VALUE rb_node) +{ + xmlNodePtr c_node; + xmlXPathContextPtr c_context; + + TypedData_Get_Struct(rb_context, xmlXPathContext, &_noko_xml_xpath_context_type, c_context); + Noko_Node_Get_Struct(rb_node, xmlNode, c_node); + + c_context->doc = c_node->doc; + c_context->node = c_node; + + return rb_node; +} + +void +noko_init_xml_xpath_context(void) +{ + /* + * XPathContext is the entry point for searching a +Document+ by using XPath. + */ + cNokogiriXmlXpathContext = rb_define_class_under(mNokogiriXml, "XPathContext", rb_cObject); + + rb_undef_alloc_func(cNokogiriXmlXpathContext); + + rb_define_singleton_method(cNokogiriXmlXpathContext, "new", noko_xml_xpath_context_new, 1); + + rb_define_method(cNokogiriXmlXpathContext, "evaluate", noko_xml_xpath_context_evaluate, -1); + rb_define_method(cNokogiriXmlXpathContext, "register_variable", noko_xml_xpath_context_register_variable, 2); + rb_define_method(cNokogiriXmlXpathContext, "register_ns", noko_xml_xpath_context_register_ns, 2); + rb_define_method(cNokogiriXmlXpathContext, "node=", noko_xml_xpath_context_set_node, 1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xslt_stylesheet.c b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xslt_stylesheet.c new file mode 100644 index 00000000..903f729c --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/ext/nokogiri/xslt_stylesheet.c @@ -0,0 +1,421 @@ +#include + +VALUE cNokogiriXsltStylesheet; + +static void +mark(void *data) +{ + nokogiriXsltStylesheetTuple *wrapper = (nokogiriXsltStylesheetTuple *)data; + rb_gc_mark(wrapper->func_instances); +} + +static void +dealloc(void *data) +{ + nokogiriXsltStylesheetTuple *wrapper = (nokogiriXsltStylesheetTuple *)data; + xsltStylesheetPtr doc = wrapper->ss; + xsltFreeStylesheet(doc); + ruby_xfree(wrapper); +} + +static const rb_data_type_t nokogiri_xslt_stylesheet_tuple_type = { + .wrap_struct_name = "nokogiriXsltStylesheetTuple", + .function = { + .dmark = mark, + .dfree = dealloc, + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY +}; + +PRINTFLIKE_DECL(2, 3) +static void +xslt_generic_error_handler(void *ctx, const char *msg, ...) +{ + VALUE message; + +#ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES + /* It is not currently possible to pass var args from native + functions to sulong, so we work around the issue here. */ + message = rb_sprintf("xslt_generic_error_handler: %s", msg); +#else + va_list args; + va_start(args, msg); + message = rb_vsprintf(msg, args); + va_end(args); +#endif + + rb_str_concat((VALUE)ctx, message); +} + +VALUE +Nokogiri_wrap_xslt_stylesheet(xsltStylesheetPtr ss) +{ + VALUE self; + nokogiriXsltStylesheetTuple *wrapper; + + self = TypedData_Make_Struct( + cNokogiriXsltStylesheet, + nokogiriXsltStylesheetTuple, + &nokogiri_xslt_stylesheet_tuple_type, + wrapper + ); + + ss->_private = (void *)self; + wrapper->ss = ss; + wrapper->func_instances = rb_ary_new(); + + return self; +} + +/* + * call-seq: + * parse_stylesheet_doc(document) + * + * Parse an XSLT::Stylesheet from +document+. + * + * [Parameters] + * - +document+ (Nokogiri::XML::Document) the document to be parsed. + * + * [Returns] Nokogiri::XSLT::Stylesheet + */ +static VALUE +parse_stylesheet_doc(VALUE klass, VALUE xmldocobj) +{ + xmlDocPtr xml, xml_cpy; + VALUE errstr, exception; + xsltStylesheetPtr ss ; + + xml = noko_xml_document_unwrap(xmldocobj); + + errstr = rb_str_new(0, 0); + xsltSetGenericErrorFunc((void *)errstr, xslt_generic_error_handler); + + xml_cpy = xmlCopyDoc(xml, 1); /* 1 => recursive */ + ss = xsltParseStylesheetDoc(xml_cpy); + + xsltSetGenericErrorFunc(NULL, NULL); + + if (!ss) { + xmlFreeDoc(xml_cpy); + exception = rb_exc_new3(rb_eRuntimeError, errstr); + rb_exc_raise(exception); + } + + return Nokogiri_wrap_xslt_stylesheet(ss); +} + + +/* + * call-seq: + * serialize(document) + * + * Serialize +document+ to an xml string, as specified by the +method+ parameter in the Stylesheet. + */ +static VALUE +rb_xslt_stylesheet_serialize(VALUE self, VALUE xmlobj) +{ + xmlDocPtr xml ; + nokogiriXsltStylesheetTuple *wrapper; + xmlChar *doc_ptr ; + int doc_len ; + VALUE rval ; + + xml = noko_xml_document_unwrap(xmlobj); + TypedData_Get_Struct( + self, + nokogiriXsltStylesheetTuple, + &nokogiri_xslt_stylesheet_tuple_type, + wrapper + ); + xsltSaveResultToString(&doc_ptr, &doc_len, xml, wrapper->ss); + rval = NOKOGIRI_STR_NEW(doc_ptr, doc_len); + xmlFree(doc_ptr); + return rval ; +} + +/* + * call-seq: + * transform(document) + * transform(document, params = {}) + * + * Transform an XML::Document as defined by an XSLT::Stylesheet. + * + * [Parameters] + * - +document+ (Nokogiri::XML::Document) the document to be transformed. + * - +params+ (Hash, Array) strings used as XSLT parameters. + * + * [Returns] Nokogiri::XML::Document + * + * *Example* of basic transformation: + * + * xslt = <<~XSLT + * + * + * + * + * + * + * + *

+ *
    + * + *
  1. + *
    + *
+ * + * + *
+ * XSLT + * + * xml = <<~XML + * + * + * + * EMP0001 + * Accountant + * + * + * EMP0002 + * Developer + * + * + * XML + * + * doc = Nokogiri::XML::Document.parse(xml) + * stylesheet = Nokogiri::XSLT.parse(xslt) + * + * ⚠ Note that the +h1+ element is empty because no param has been provided! + * + * stylesheet.transform(doc).to_xml + * # => "\n" + + * # "

\n" + + * # "
    \n" + + * # "
  1. EMP0001
  2. \n" + + * # "
  3. EMP0002
  4. \n" + + * # "
\n" + + * # "\n" + * + * *Example* of using an input parameter hash: + * + * ⚠ The title is populated, but note how we need to quote-escape the value. + * + * stylesheet.transform(doc, { "title" => "'Employee List'" }).to_xml + * # => "\n" + + * # "

Employee List

\n" + + * # "
    \n" + + * # "
  1. EMP0001
  2. \n" + + * # "
  3. EMP0002
  4. \n" + + * # "
\n" + + * # "\n" + * + * *Example* using the XSLT.quote_params helper method to safely quote-escape strings: + * + * stylesheet.transform(doc, Nokogiri::XSLT.quote_params({ "title" => "Aaron's List" })).to_xml + * # => "\n" + + * # "

Aaron's List

\n" + + * # "
    \n" + + * # "
  1. EMP0001
  2. \n" + + * # "
  3. EMP0002
  4. \n" + + * # "
\n" + + * # "\n" + * + * *Example* using an array of XSLT parameters + * + * You can also use an array if you want to. + * + * stylesheet.transform(doc, ["title", "'Employee List'"]).to_xml + * # => "\n" + + * # "

Employee List

\n" + + * # "
    \n" + + * # "
  1. EMP0001
  2. \n" + + * # "
  3. EMP0002
  4. \n" + + * # "
\n" + + * # "\n" + * + * Or pass an array to XSLT.quote_params: + * + * stylesheet.transform(doc, Nokogiri::XSLT.quote_params(["title", "Aaron's List"])).to_xml + * # => "\n" + + * # "

Aaron's List

\n" + + * # "
    \n" + + * # "
  1. EMP0001
  2. \n" + + * # "
  3. EMP0002
  4. \n" + + * # "
\n" + + * # "\n" + * + * See: Nokogiri::XSLT.quote_params + */ +static VALUE +rb_xslt_stylesheet_transform(int argc, VALUE *argv, VALUE self) +{ + VALUE rb_document, rb_param, rb_error_str; + xmlDocPtr c_document ; + xmlDocPtr c_result_document ; + nokogiriXsltStylesheetTuple *wrapper; + const char **params ; + long param_len, j ; + int parse_error_occurred ; + int defensive_copy_p = 0; + + rb_scan_args(argc, argv, "11", &rb_document, &rb_param); + if (NIL_P(rb_param)) { rb_param = rb_ary_new2(0L) ; } + if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) { + rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::Document"); + } + + /* handle hashes as arguments. */ + if (T_HASH == TYPE(rb_param)) { + rb_param = rb_funcall(rb_param, rb_intern("to_a"), 0); + rb_param = rb_funcall(rb_param, rb_intern("flatten"), 0); + } + + Check_Type(rb_param, T_ARRAY); + + c_document = noko_xml_document_unwrap(rb_document); + TypedData_Get_Struct(self, nokogiriXsltStylesheetTuple, &nokogiri_xslt_stylesheet_tuple_type, wrapper); + + param_len = RARRAY_LEN(rb_param); + params = ruby_xcalloc((size_t)param_len + 1, sizeof(char *)); + for (j = 0 ; j < param_len ; j++) { + VALUE entry = rb_ary_entry(rb_param, j); + const char *ptr = StringValueCStr(entry); + params[j] = ptr; + } + params[param_len] = 0 ; + + xsltTransformContextPtr c_transform_context = xsltNewTransformContext(wrapper->ss, c_document); + if (xsltNeedElemSpaceHandling(c_transform_context) && + noko_xml_document_has_wrapped_blank_nodes_p(c_document)) { + // see https://github.com/sparklemotion/nokogiri/issues/2800 + c_document = xmlCopyDoc(c_document, 1); + defensive_copy_p = 1; + } + xsltFreeTransformContext(c_transform_context); + + rb_error_str = rb_str_new(0, 0); + xsltSetGenericErrorFunc((void *)rb_error_str, xslt_generic_error_handler); + xmlSetGenericErrorFunc((void *)rb_error_str, xslt_generic_error_handler); + + c_result_document = xsltApplyStylesheet(wrapper->ss, c_document, params); + + ruby_xfree(params); + if (defensive_copy_p) { + xmlFreeDoc(c_document); + c_document = NULL; + } + + xsltSetGenericErrorFunc(NULL, NULL); + xmlSetGenericErrorFunc(NULL, NULL); + + parse_error_occurred = (Qfalse == rb_funcall(rb_error_str, rb_intern("empty?"), 0)); + + if (parse_error_occurred) { + rb_exc_raise(rb_exc_new3(rb_eRuntimeError, rb_error_str)); + } + + return noko_xml_document_wrap((VALUE)0, c_result_document) ; +} + +static void +method_caller(xmlXPathParserContextPtr ctxt, int nargs) +{ + VALUE handler; + const char *function_name; + xsltTransformContextPtr transform; + const xmlChar *functionURI; + + transform = xsltXPathGetTransformContext(ctxt); + functionURI = ctxt->context->functionURI; + handler = (VALUE)xsltGetExtData(transform, functionURI); + function_name = (const char *)(ctxt->context->function); + + Nokogiri_marshal_xpath_funcall_and_return_values( + ctxt, + nargs, + handler, + (const char *)function_name + ); +} + +static void * +initFunc(xsltTransformContextPtr ctxt, const xmlChar *uri) +{ + VALUE modules = rb_iv_get(mNokogiriXslt, "@modules"); + VALUE obj = rb_hash_aref(modules, rb_str_new2((const char *)uri)); + VALUE args = { Qfalse }; + VALUE methods = rb_funcall(obj, rb_intern("instance_methods"), 1, args); + VALUE inst; + nokogiriXsltStylesheetTuple *wrapper; + int i; + + for (i = 0; i < RARRAY_LEN(methods); i++) { + VALUE method_name = rb_obj_as_string(rb_ary_entry(methods, i)); + xsltRegisterExtFunction( + ctxt, + (unsigned char *)StringValueCStr(method_name), + uri, + method_caller + ); + } + + TypedData_Get_Struct( + (VALUE)ctxt->style->_private, + nokogiriXsltStylesheetTuple, + &nokogiri_xslt_stylesheet_tuple_type, + wrapper + ); + inst = rb_class_new_instance(0, NULL, obj); + rb_ary_push(wrapper->func_instances, inst); + + return (void *)inst; +} + +static void +shutdownFunc(xsltTransformContextPtr ctxt, + const xmlChar *uri, void *data) +{ + nokogiriXsltStylesheetTuple *wrapper; + + TypedData_Get_Struct( + (VALUE)ctxt->style->_private, + nokogiriXsltStylesheetTuple, + &nokogiri_xslt_stylesheet_tuple_type, + wrapper + ); + + rb_ary_clear(wrapper->func_instances); +} + +/* docstring is in lib/nokogiri/xslt.rb */ +static VALUE +rb_xslt_s_register(VALUE self, VALUE uri, VALUE obj) +{ + VALUE modules = rb_iv_get(self, "@modules"); + if (NIL_P(modules)) { + rb_raise(rb_eRuntimeError, "internal error: @modules not set"); + } + + rb_hash_aset(modules, uri, obj); + xsltRegisterExtModule( + (unsigned char *)StringValueCStr(uri), + initFunc, + shutdownFunc + ); + return self; +} + +void +noko_init_xslt_stylesheet(void) +{ + rb_define_singleton_method(mNokogiriXslt, "register", rb_xslt_s_register, 2); + rb_iv_set(mNokogiriXslt, "@modules", rb_hash_new()); + + cNokogiriXsltStylesheet = rb_define_class_under(mNokogiriXslt, "Stylesheet", rb_cObject); + + rb_undef_alloc_func(cNokogiriXsltStylesheet); + + rb_define_singleton_method(cNokogiriXsltStylesheet, "parse_stylesheet_doc", parse_stylesheet_doc, 1); + rb_define_method(cNokogiriXsltStylesheet, "serialize", rb_xslt_stylesheet_serialize, 1); + rb_define_method(cNokogiriXsltStylesheet, "transform", rb_xslt_stylesheet_transform, -1); +} diff --git a/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/gumbo-parser/CHANGES.md b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/gumbo-parser/CHANGES.md new file mode 100644 index 00000000..277b3a2b --- /dev/null +++ b/bin/gems/nokogiri-1.18.3-x86_64-linux-gnu/gumbo-parser/CHANGES.md @@ -0,0 +1,63 @@ +## Gumbo 0.10.1 (2015-04-30) + +Same as 0.10.0, but with the version number bumped because the last version-number commit to v0.9.4 makes GitHub think that v0.9.4 is the latest version and so it's not highlighted on the webpage. + +## Gumbo 0.10.0 (2015-04-30) + +* Full support for `